aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CREDITS42
-rw-r--r--Documentation/CodingStyle34
-rw-r--r--Documentation/DMA-mapping.txt4
-rw-r--r--Documentation/DocBook/kernel-api.tmpl84
-rw-r--r--Documentation/DocBook/libata.tmpl4
-rw-r--r--Documentation/DocBook/usb.tmpl128
-rw-r--r--Documentation/DocBook/writing_usb_driver.tmpl7
-rw-r--r--Documentation/HOWTO40
-rw-r--r--Documentation/IPMI.txt23
-rw-r--r--Documentation/MSI-HOWTO.txt65
-rw-r--r--Documentation/RCU/checklist.txt38
-rw-r--r--Documentation/RCU/rcu.txt3
-rw-r--r--Documentation/RCU/torture.txt33
-rw-r--r--Documentation/RCU/whatisRCU.txt7
-rw-r--r--Documentation/SubmitChecklist5
-rw-r--r--Documentation/SubmittingDrivers21
-rw-r--r--Documentation/SubmittingPatches39
-rw-r--r--Documentation/accounting/getdelays.c7
-rw-r--r--Documentation/accounting/taskstats-struct.txt161
-rw-r--r--Documentation/aoe/todo.txt2
-rw-r--r--Documentation/arm/SA1100/serial_UART4
-rw-r--r--Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt2
-rw-r--r--Documentation/arm/Samsung-S3C24XX/GPIO.txt2
-rw-r--r--Documentation/arm/Samsung-S3C24XX/Overview.txt2
-rw-r--r--Documentation/arm/Samsung-S3C24XX/S3C2412.txt2
-rw-r--r--Documentation/block/as-iosched.txt4
-rw-r--r--Documentation/block/barrier.txt6
-rw-r--r--Documentation/block/biodoc.txt10
-rw-r--r--Documentation/block/deadline-iosched.txt4
-rw-r--r--Documentation/cciss.txt4
-rw-r--r--Documentation/computone.txt70
-rw-r--r--Documentation/cpu-freq/cpufreq-stats.txt10
-rw-r--r--Documentation/cpu-freq/governors.txt12
-rw-r--r--Documentation/cpu-hotplug.txt148
-rw-r--r--Documentation/cpusets.txt10
-rw-r--r--Documentation/cputopology.txt2
-rw-r--r--Documentation/dell_rbu.txt22
-rw-r--r--Documentation/devices.txt11
-rw-r--r--Documentation/driver-model/class.txt2
-rw-r--r--Documentation/driver-model/driver.txt2
-rw-r--r--Documentation/driver-model/overview.txt2
-rw-r--r--Documentation/dvb/avermedia.txt4
-rw-r--r--Documentation/dvb/cards.txt2
-rw-r--r--Documentation/dvb/ci.txt4
-rw-r--r--Documentation/dvb/faq.txt6
-rw-r--r--Documentation/ecryptfs.txt77
-rw-r--r--Documentation/eisa.txt4
-rw-r--r--Documentation/exception.txt2
-rw-r--r--Documentation/fb/fbcon.txt2
-rw-r--r--Documentation/fb/intel810.txt148
-rw-r--r--Documentation/fb/intelfb.txt21
-rw-r--r--Documentation/fb/sisfb.txt2
-rw-r--r--Documentation/fb/sstfb.txt42
-rw-r--r--Documentation/feature-removal-schedule.txt105
-rw-r--r--Documentation/filesystems/00-INDEX4
-rw-r--r--Documentation/filesystems/Locking5
-rw-r--r--Documentation/filesystems/befs.txt8
-rw-r--r--Documentation/filesystems/configfs/configfs.txt8
-rw-r--r--Documentation/filesystems/directory-locking2
-rw-r--r--Documentation/filesystems/dlmfs.txt2
-rw-r--r--Documentation/filesystems/ext2.txt2
-rw-r--r--Documentation/filesystems/ext4.txt236
-rw-r--r--Documentation/filesystems/files.txt2
-rw-r--r--Documentation/filesystems/gfs2.txt43
-rw-r--r--Documentation/filesystems/ntfs.txt10
-rw-r--r--Documentation/filesystems/proc.txt28
-rw-r--r--Documentation/filesystems/spufs.txt6
-rw-r--r--Documentation/filesystems/sysfs.txt2
-rw-r--r--Documentation/filesystems/tmpfs.txt4
-rw-r--r--Documentation/filesystems/vfat.txt2
-rw-r--r--Documentation/filesystems/vfs.txt6
-rw-r--r--Documentation/fujitsu/frv/mmu-layout.txt2
-rw-r--r--Documentation/highuid.txt2
-rw-r--r--Documentation/hrtimers.txt12
-rw-r--r--Documentation/hwmon/adm92402
-rw-r--r--Documentation/hwmon/f71805f2
-rw-r--r--Documentation/hwmon/it8761
-rw-r--r--Documentation/hwmon/k8temp55
-rw-r--r--Documentation/hwmon/smsc47m14
-rw-r--r--Documentation/hwmon/vt1211206
-rw-r--r--Documentation/hwmon/w83627ehf85
-rw-r--r--Documentation/hwmon/w83791d69
-rw-r--r--Documentation/i2c/busses/i2c-viapro7
-rw-r--r--Documentation/i2c/i2c-stub15
-rw-r--r--Documentation/ia64/efirtc.txt2
-rw-r--r--Documentation/ia64/fsys.txt2
-rw-r--r--Documentation/ia64/mca.txt4
-rw-r--r--Documentation/ia64/serial.txt7
-rw-r--r--Documentation/ibm-acpi.txt77
-rw-r--r--Documentation/ide.txt2
-rw-r--r--Documentation/input/amijoy.txt4
-rw-r--r--Documentation/input/atarikbd.txt10
-rw-r--r--Documentation/input/cs461x.txt2
-rw-r--r--Documentation/input/ff.txt114
-rw-r--r--Documentation/input/gameport-programming.txt4
-rw-r--r--Documentation/input/input.txt31
-rw-r--r--Documentation/input/joystick-parport.txt8
-rw-r--r--Documentation/input/joystick.txt2
-rw-r--r--Documentation/input/xpad.txt115
-rw-r--r--Documentation/input/yealink.txt4
-rw-r--r--Documentation/ioctl/hdio.txt2
-rw-r--r--Documentation/isdn/INTERFACE.fax2
-rw-r--r--Documentation/isdn/README.hysdn2
-rw-r--r--Documentation/java.txt2
-rw-r--r--Documentation/kbuild/kconfig-language.txt6
-rw-r--r--Documentation/kbuild/makefiles.txt2
-rw-r--r--Documentation/kbuild/modules.txt9
-rw-r--r--Documentation/kdump/kdump.txt2
-rw-r--r--Documentation/kernel-docs.txt11
-rw-r--r--Documentation/kernel-parameters.txt58
-rw-r--r--Documentation/keys.txt6
-rw-r--r--Documentation/kobject.txt2
-rw-r--r--Documentation/kprobes.txt89
-rw-r--r--Documentation/laptop-mode.txt2
-rw-r--r--Documentation/lockdep-design.txt30
-rw-r--r--Documentation/m68k/kernel-options.txt2
-rw-r--r--Documentation/mca.txt2
-rw-r--r--Documentation/md.txt42
-rw-r--r--Documentation/memory-barriers.txt6
-rw-r--r--Documentation/mono.txt2
-rw-r--r--Documentation/networking/3c509.txt2
-rw-r--r--Documentation/networking/NAPI_HOWTO.txt2
-rw-r--r--Documentation/networking/arcnet-hardware.txt2
-rw-r--r--Documentation/networking/bonding.txt61
-rw-r--r--Documentation/networking/cs89x0.txt6
-rw-r--r--Documentation/networking/cxgb.txt4
-rw-r--r--Documentation/networking/decnet.txt2
-rw-r--r--Documentation/networking/dl2k.txt4
-rw-r--r--Documentation/networking/dmfe.txt2
-rw-r--r--Documentation/networking/driver.txt2
-rw-r--r--Documentation/networking/e1000.txt2
-rw-r--r--Documentation/networking/fib_trie.txt2
-rw-r--r--Documentation/networking/gen_stats.txt8
-rw-r--r--Documentation/networking/ip-sysctl.txt4
-rw-r--r--Documentation/networking/netconsole.txt2
-rw-r--r--Documentation/networking/netif-msg.txt2
-rw-r--r--Documentation/networking/operstates.txt2
-rw-r--r--Documentation/networking/packet_mmap.txt24
-rw-r--r--Documentation/networking/pktgen.txt24
-rw-r--r--Documentation/networking/s2io.txt2
-rw-r--r--Documentation/networking/sk98lin.txt16
-rw-r--r--Documentation/networking/skfp.txt4
-rw-r--r--Documentation/networking/slicecom.txt8
-rw-r--r--Documentation/networking/smctr.txt2
-rw-r--r--Documentation/networking/tcp.txt2
-rw-r--r--Documentation/networking/tms380tr.txt2
-rw-r--r--Documentation/networking/vortex.txt4
-rw-r--r--Documentation/networking/wan-router.txt16
-rw-r--r--Documentation/nfsroot.txt2
-rw-r--r--Documentation/nommu-mmap.txt46
-rw-r--r--Documentation/pci-error-recovery.txt2
-rw-r--r--Documentation/pcieaer-howto.txt253
-rw-r--r--Documentation/pi-futex.txt2
-rw-r--r--Documentation/pm.txt6
-rw-r--r--Documentation/pnp.txt2
-rw-r--r--Documentation/power/pci.txt2
-rw-r--r--Documentation/power/swsusp.txt8
-rw-r--r--Documentation/power/tricks.txt2
-rw-r--r--Documentation/power/userland-swsusp.txt2
-rw-r--r--Documentation/power/video.txt2
-rw-r--r--Documentation/powerpc/booting-without-of.txt295
-rw-r--r--Documentation/powerpc/eeh-pci-error-recovery.txt4
-rw-r--r--Documentation/powerpc/hvcs.txt2
-rw-r--r--Documentation/prio_tree.txt2
-rw-r--r--Documentation/rocket.txt6
-rw-r--r--Documentation/rpc-cache.txt4
-rw-r--r--Documentation/rt-mutex-design.txt14
-rw-r--r--Documentation/s390/3270.txt4
-rw-r--r--Documentation/s390/CommonIO2
-rw-r--r--Documentation/s390/Debugging390.txt93
-rw-r--r--Documentation/s390/cds.txt62
-rw-r--r--Documentation/s390/crypto/crypto-API.txt4
-rw-r--r--Documentation/s390/driver-model.txt7
-rw-r--r--Documentation/s390/monreader.txt2
-rw-r--r--Documentation/s390/s390dbf.txt12
-rw-r--r--Documentation/sched-coding.txt2
-rw-r--r--Documentation/sched-design.txt4
-rw-r--r--Documentation/scsi/ChangeLog.1992-19972
-rw-r--r--Documentation/scsi/ChangeLog.megaraid_sas45
-rw-r--r--Documentation/scsi/NinjaSCSI.txt18
-rw-r--r--Documentation/scsi/aacraid.txt2
-rw-r--r--Documentation/scsi/aic79xx.txt4
-rw-r--r--Documentation/scsi/aic7xxx.txt2
-rw-r--r--Documentation/scsi/aic7xxx_old.txt6
-rw-r--r--Documentation/scsi/dc395x.txt2
-rw-r--r--Documentation/scsi/dpti.txt2
-rw-r--r--Documentation/scsi/ibmmca.txt36
-rw-r--r--Documentation/scsi/megaraid.txt4
-rw-r--r--Documentation/scsi/ncr53c8xx.txt20
-rw-r--r--Documentation/scsi/osst.txt3
-rw-r--r--Documentation/scsi/ppa.txt2
-rw-r--r--Documentation/scsi/scsi-changer.txt2
-rw-r--r--Documentation/scsi/scsi_eh.txt4
-rw-r--r--Documentation/scsi/st.txt4
-rw-r--r--Documentation/scsi/sym53c8xx_2.txt4
-rw-r--r--Documentation/scsi/tmscsim.txt4
-rw-r--r--Documentation/seclvl.txt97
-rw-r--r--Documentation/sh/kgdb.txt2
-rw-r--r--Documentation/sh/new-machine.txt128
-rw-r--r--Documentation/sh/register-banks.txt33
-rw-r--r--Documentation/sound/alsa/ALSA-Configuration.txt26
-rw-r--r--Documentation/sound/alsa/Audiophile-Usb.txt2
-rw-r--r--Documentation/sound/alsa/CMIPCI.txt6
-rw-r--r--Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl2
-rw-r--r--Documentation/sound/alsa/MIXART.txt6
-rw-r--r--Documentation/sound/alsa/Procfile.txt10
-rw-r--r--Documentation/sound/oss/AWE3276
-rw-r--r--Documentation/sound/oss/CMI833885
-rw-r--r--Documentation/sound/oss/INSTALL.awe134
-rw-r--r--Documentation/sound/oss/MAD1656
-rw-r--r--Documentation/sound/oss/Maestro123
-rw-r--r--Documentation/sound/oss/Maestro392
-rw-r--r--Documentation/sound/oss/NEWS42
-rw-r--r--Documentation/sound/oss/OPL3-SA52
-rw-r--r--Documentation/sound/oss/README.awe218
-rw-r--r--Documentation/sound/oss/Wavefront339
-rw-r--r--Documentation/sound/oss/es137070
-rw-r--r--Documentation/sound/oss/rme96xx767
-rw-r--r--Documentation/sound/oss/solo170
-rw-r--r--Documentation/sound/oss/sonicvibes81
-rw-r--r--Documentation/sound/oss/ultrasound2
-rw-r--r--Documentation/sound/oss/vwsnd2
-rw-r--r--Documentation/sparc/sbus_drivers.txt6
-rw-r--r--Documentation/spi/pxa2xx6
-rw-r--r--Documentation/spi/spi-summary4
-rw-r--r--Documentation/stable_kernel_rules.txt4
-rw-r--r--Documentation/sysctl/kernel.txt5
-rw-r--r--Documentation/uml/UserModeLinux-HOWTO.txt66
-rw-r--r--Documentation/unshare.txt2
-rw-r--r--Documentation/usb/URB.txt2
-rw-r--r--Documentation/usb/acm.txt14
-rw-r--r--Documentation/usb/error-codes.txt15
-rw-r--r--Documentation/usb/hiddev.txt2
-rw-r--r--Documentation/usb/mtouchusb.txt6
-rw-r--r--Documentation/usb/usb-serial.txt16
-rw-r--r--Documentation/video4linux/CARDLIST.cx8812
-rw-r--r--Documentation/video4linux/CARDLIST.saa71349
-rw-r--r--Documentation/video4linux/README.pvrusb22
-rw-r--r--Documentation/video4linux/Zoran2
-rw-r--r--Documentation/video4linux/bttv/Insmod-options6
-rw-r--r--Documentation/video4linux/cx2341x/README.hm12116
-rw-r--r--Documentation/video4linux/cx2341x/README.vbi45
-rw-r--r--Documentation/video4linux/cx2341x/fw-decoder-api.txt2
-rw-r--r--Documentation/video4linux/cx2341x/fw-encoder-api.txt2
-rw-r--r--Documentation/video4linux/cx2341x/fw-osd-api.txt2
-rw-r--r--Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt2
-rw-r--r--Documentation/video4linux/et61x251.txt4
-rw-r--r--Documentation/video4linux/hauppauge-wintv-cx88-ir.txt2
-rw-r--r--Documentation/video4linux/meye.txt2
-rw-r--r--Documentation/video4linux/sn9c102.txt4
-rw-r--r--Documentation/video4linux/w9968cf.txt2
-rw-r--r--Documentation/video4linux/zr36120.txt4
-rw-r--r--Documentation/vm/numa2
-rw-r--r--Documentation/watchdog/watchdog-api.txt8
-rw-r--r--Documentation/x86_64/boot-options.txt7
-rw-r--r--MAINTAINERS208
-rw-r--r--Makefile23
-rw-r--r--arch/alpha/Kconfig2
-rw-r--r--arch/alpha/kernel/alpha_ksyms.c100
-rw-r--r--arch/alpha/kernel/core_apecs.c5
-rw-r--r--arch/alpha/kernel/core_cia.c5
-rw-r--r--arch/alpha/kernel/core_irongate.c2
-rw-r--r--arch/alpha/kernel/core_lca.c6
-rw-r--r--arch/alpha/kernel/core_mcpcia.c5
-rw-r--r--arch/alpha/kernel/core_polaris.c5
-rw-r--r--arch/alpha/kernel/core_t2.c5
-rw-r--r--arch/alpha/kernel/core_tsunami.c5
-rw-r--r--arch/alpha/kernel/core_wildfire.c5
-rw-r--r--arch/alpha/kernel/entry.S10
-rw-r--r--arch/alpha/kernel/err_ev6.c5
-rw-r--r--arch/alpha/kernel/err_ev7.c2
-rw-r--r--arch/alpha/kernel/err_impl.h10
-rw-r--r--arch/alpha/kernel/err_marvel.c4
-rw-r--r--arch/alpha/kernel/err_titan.c14
-rw-r--r--arch/alpha/kernel/head.S2
-rw-r--r--arch/alpha/kernel/irq.c4
-rw-r--r--arch/alpha/kernel/irq_alpha.c25
-rw-r--r--arch/alpha/kernel/irq_i8259.c8
-rw-r--r--arch/alpha/kernel/irq_impl.h10
-rw-r--r--arch/alpha/kernel/irq_pyxis.c6
-rw-r--r--arch/alpha/kernel/irq_srm.c4
-rw-r--r--arch/alpha/kernel/machvec_impl.h2
-rw-r--r--arch/alpha/kernel/osf_sys.c34
-rw-r--r--arch/alpha/kernel/pci-noop.c1
-rw-r--r--arch/alpha/kernel/pci_iommu.c17
-rw-r--r--arch/alpha/kernel/process.c5
-rw-r--r--arch/alpha/kernel/proto.h44
-rw-r--r--arch/alpha/kernel/setup.c7
-rw-r--r--arch/alpha/kernel/smp.c14
-rw-r--r--arch/alpha/kernel/srmcons.c2
-rw-r--r--arch/alpha/kernel/sys_alcor.c6
-rw-r--r--arch/alpha/kernel/sys_cabriolet.c16
-rw-r--r--arch/alpha/kernel/sys_dp264.c14
-rw-r--r--arch/alpha/kernel/sys_eb64p.c6
-rw-r--r--arch/alpha/kernel/sys_eiger.c16
-rw-r--r--arch/alpha/kernel/sys_jensen.c8
-rw-r--r--arch/alpha/kernel/sys_marvel.c4
-rw-r--r--arch/alpha/kernel/sys_miata.c4
-rw-r--r--arch/alpha/kernel/sys_mikasa.c11
-rw-r--r--arch/alpha/kernel/sys_nautilus.c7
-rw-r--r--arch/alpha/kernel/sys_noritake.c15
-rw-r--r--arch/alpha/kernel/sys_rawhide.c4
-rw-r--r--arch/alpha/kernel/sys_rx164.c6
-rw-r--r--arch/alpha/kernel/sys_sable.c4
-rw-r--r--arch/alpha/kernel/sys_takara.c16
-rw-r--r--arch/alpha/kernel/sys_titan.c12
-rw-r--r--arch/alpha/kernel/sys_wildfire.c4
-rw-r--r--arch/alpha/kernel/systbls.S1
-rw-r--r--arch/alpha/kernel/time.c24
-rw-r--r--arch/alpha/lib/dbg_stackcheck.S2
-rw-r--r--arch/alpha/lib/dbg_stackkill.S2
-rw-r--r--arch/alpha/lib/memset.S2
-rw-r--r--arch/alpha/mm/Makefile2
-rw-r--r--arch/alpha/mm/fault.c2
-rw-r--r--arch/alpha/mm/numa.c2
-rw-r--r--arch/alpha/mm/remap.c86
-rw-r--r--arch/arm/Kconfig52
-rw-r--r--arch/arm/Kconfig-nommu8
-rw-r--r--arch/arm/Makefile9
-rw-r--r--arch/arm/boot/compressed/Makefile4
-rw-r--r--arch/arm/boot/compressed/head-clps7500.S2
-rw-r--r--arch/arm/boot/compressed/head.S25
-rw-r--r--arch/arm/boot/compressed/misc.c21
-rw-r--r--arch/arm/common/icst307.c4
-rw-r--r--arch/arm/common/icst525.c4
-rw-r--r--arch/arm/common/locomo.c86
-rw-r--r--arch/arm/common/sa1111.c10
-rw-r--r--arch/arm/common/sharpsl_pm.c10
-rw-r--r--arch/arm/common/time-acorn.c4
-rw-r--r--arch/arm/configs/at91rm9200dk_defconfig6
-rw-r--r--arch/arm/configs/at91rm9200ek_defconfig6
-rw-r--r--arch/arm/configs/ateb9200_defconfig6
-rw-r--r--arch/arm/configs/carmeva_defconfig4
-rw-r--r--arch/arm/configs/csb337_defconfig6
-rw-r--r--arch/arm/configs/csb637_defconfig6
-rw-r--r--arch/arm/configs/ep93xx_defconfig1
-rw-r--r--arch/arm/configs/iop32x_defconfig (renamed from arch/arm/configs/ep80219_defconfig)602
-rw-r--r--arch/arm/configs/iop33x_defconfig (renamed from arch/arm/configs/iq80332_defconfig)473
-rw-r--r--arch/arm/configs/iq31244_defconfig922
-rw-r--r--arch/arm/configs/iq80321_defconfig843
-rw-r--r--arch/arm/configs/kafa_defconfig6
-rw-r--r--arch/arm/configs/kb9202_defconfig4
-rw-r--r--arch/arm/configs/onearm_defconfig6
-rw-r--r--arch/arm/configs/s3c2410_defconfig46
-rw-r--r--arch/arm/kernel/apm.c33
-rw-r--r--arch/arm/kernel/armksyms.c6
-rw-r--r--arch/arm/kernel/crunch.c1
-rw-r--r--arch/arm/kernel/debug.S35
-rw-r--r--arch/arm/kernel/ecard.c10
-rw-r--r--arch/arm/kernel/entry-armv.S13
-rw-r--r--arch/arm/kernel/head-nommu.S12
-rw-r--r--arch/arm/kernel/head.S18
-rw-r--r--arch/arm/kernel/irq.c4
-rw-r--r--arch/arm/kernel/iwmmxt-notifier.c1
-rw-r--r--arch/arm/kernel/module.c8
-rw-r--r--arch/arm/kernel/process.c22
-rw-r--r--arch/arm/kernel/setup.c2
-rw-r--r--arch/arm/kernel/smp.c2
-rw-r--r--arch/arm/kernel/sys_arm.c4
-rw-r--r--arch/arm/kernel/time.c24
-rw-r--r--arch/arm/kernel/traps.c2
-rw-r--r--arch/arm/mach-aaec2000/core.c4
-rw-r--r--arch/arm/mach-at91rm9200/at91rm9200.c250
-rw-r--r--arch/arm/mach-at91rm9200/at91rm9200_time.c4
-rw-r--r--arch/arm/mach-at91rm9200/board-1arm.c21
-rw-r--r--arch/arm/mach-at91rm9200/board-carmeva.c22
-rw-r--r--arch/arm/mach-at91rm9200/board-csb337.c20
-rw-r--r--arch/arm/mach-at91rm9200/board-csb637.c20
-rw-r--r--arch/arm/mach-at91rm9200/board-dk.c45
-rw-r--r--arch/arm/mach-at91rm9200/board-eb9200.c21
-rw-r--r--arch/arm/mach-at91rm9200/board-ek.c20
-rw-r--r--arch/arm/mach-at91rm9200/board-kafa.c21
-rw-r--r--arch/arm/mach-at91rm9200/board-kb9202.c46
-rw-r--r--arch/arm/mach-at91rm9200/clock.c324
-rw-r--r--arch/arm/mach-at91rm9200/clock.h30
-rw-r--r--arch/arm/mach-at91rm9200/devices.c107
-rw-r--r--arch/arm/mach-at91rm9200/generic.h20
-rw-r--r--arch/arm/mach-at91rm9200/gpio.c93
-rw-r--r--arch/arm/mach-at91rm9200/irq.c6
-rw-r--r--arch/arm/mach-at91rm9200/pm.c14
-rw-r--r--arch/arm/mach-clps711x/time.c4
-rw-r--r--arch/arm/mach-clps7500/core.c4
-rw-r--r--arch/arm/mach-ebsa110/core.c4
-rw-r--r--arch/arm/mach-ep93xx/Kconfig6
-rw-r--r--arch/arm/mach-ep93xx/Makefile1
-rw-r--r--arch/arm/mach-ep93xx/core.c10
-rw-r--r--arch/arm/mach-ep93xx/edb9302.c1
-rw-r--r--arch/arm/mach-ep93xx/edb9312.c62
-rw-r--r--arch/arm/mach-ep93xx/edb9315.c1
-rw-r--r--arch/arm/mach-ep93xx/edb9315a.c31
-rw-r--r--arch/arm/mach-ep93xx/gesbc9312.c27
-rw-r--r--arch/arm/mach-ep93xx/ts72xx.c30
-rw-r--r--arch/arm/mach-footbridge/dc21285-timer.c4
-rw-r--r--arch/arm/mach-footbridge/dc21285.c40
-rw-r--r--arch/arm/mach-footbridge/isa-irq.c6
-rw-r--r--arch/arm/mach-footbridge/isa-timer.c4
-rw-r--r--arch/arm/mach-h720x/common.c29
-rw-r--r--arch/arm/mach-h720x/cpu-h7201.c4
-rw-r--r--arch/arm/mach-h720x/cpu-h7202.c11
-rw-r--r--arch/arm/mach-imx/dma.c12
-rw-r--r--arch/arm/mach-imx/irq.c24
-rw-r--r--arch/arm/mach-imx/leds.c2
-rw-r--r--arch/arm/mach-imx/leds.h2
-rw-r--r--arch/arm/mach-imx/time.c4
-rw-r--r--arch/arm/mach-integrator/core.c6
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c6
-rw-r--r--arch/arm/mach-integrator/pci_v3.c3
-rw-r--r--arch/arm/mach-integrator/time.c3
-rw-r--r--arch/arm/mach-iop32x/Kconfig35
-rw-r--r--arch/arm/mach-iop32x/Makefile13
-rw-r--r--arch/arm/mach-iop32x/Makefile.boot3
-rw-r--r--arch/arm/mach-iop32x/glantank.c195
-rw-r--r--arch/arm/mach-iop32x/iq31244.c293
-rw-r--r--arch/arm/mach-iop32x/iq80321.c193
-rw-r--r--arch/arm/mach-iop32x/irq.c76
-rw-r--r--arch/arm/mach-iop32x/n2100.c251
-rw-r--r--arch/arm/mach-iop33x/Kconfig21
-rw-r--r--arch/arm/mach-iop33x/Makefile11
-rw-r--r--arch/arm/mach-iop33x/Makefile.boot3
-rw-r--r--arch/arm/mach-iop33x/iq80331.c148
-rw-r--r--arch/arm/mach-iop33x/iq80332.c148
-rw-r--r--arch/arm/mach-iop33x/irq.c127
-rw-r--r--arch/arm/mach-iop33x/uart.c105
-rw-r--r--arch/arm/mach-iop3xx/Kconfig66
-rw-r--r--arch/arm/mach-iop3xx/Makefile23
-rw-r--r--arch/arm/mach-iop3xx/Makefile.boot9
-rw-r--r--arch/arm/mach-iop3xx/common.c72
-rw-r--r--arch/arm/mach-iop3xx/iop321-irq.c97
-rw-r--r--arch/arm/mach-iop3xx/iop321-pci.c220
-rw-r--r--arch/arm/mach-iop3xx/iop321-setup.c173
-rw-r--r--arch/arm/mach-iop3xx/iop321-time.c108
-rw-r--r--arch/arm/mach-iop3xx/iop331-irq.c129
-rw-r--r--arch/arm/mach-iop3xx/iop331-pci.c222
-rw-r--r--arch/arm/mach-iop3xx/iop331-setup.c221
-rw-r--r--arch/arm/mach-iop3xx/iop331-time.c106
-rw-r--r--arch/arm/mach-iop3xx/iq31244-mm.c45
-rw-r--r--arch/arm/mach-iop3xx/iq31244-pci.c129
-rw-r--r--arch/arm/mach-iop3xx/iq80321-mm.c45
-rw-r--r--arch/arm/mach-iop3xx/iq80321-pci.c123
-rw-r--r--arch/arm/mach-iop3xx/iq80331-mm.c35
-rw-r--r--arch/arm/mach-iop3xx/iq80331-pci.c119
-rw-r--r--arch/arm/mach-iop3xx/iq80332-mm.c35
-rw-r--r--arch/arm/mach-iop3xx/iq80332-pci.c125
-rw-r--r--arch/arm/mach-ixp2000/core.c12
-rw-r--r--arch/arm/mach-ixp2000/ixdp2400.c6
-rw-r--r--arch/arm/mach-ixp2000/ixdp2800.c6
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c11
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x01.c4
-rw-r--r--arch/arm/mach-ixp23xx/core.c8
-rw-r--r--arch/arm/mach-ixp23xx/ixdp2351.c8
-rw-r--r--arch/arm/mach-ixp4xx/common.c42
-rw-r--r--arch/arm/mach-ixp4xx/coyote-pci.c2
-rw-r--r--arch/arm/mach-ixp4xx/ixdpg425-pci.c2
-rw-r--r--arch/arm/mach-ixp4xx/nas100d-power.c2
-rw-r--r--arch/arm/mach-ixp4xx/nslu2-power.c4
-rw-r--r--arch/arm/mach-ixp4xx/nslu2-setup.c2
-rw-r--r--arch/arm/mach-lh7a40x/arch-kev7a400.c5
-rw-r--r--arch/arm/mach-lh7a40x/arch-lpd7a40x.c5
-rw-r--r--arch/arm/mach-lh7a40x/clcd.c2
-rw-r--r--arch/arm/mach-lh7a40x/clocks.c1
-rw-r--r--arch/arm/mach-lh7a40x/common.h2
-rw-r--r--arch/arm/mach-lh7a40x/irq-kev7a400.c5
-rw-r--r--arch/arm/mach-lh7a40x/irq-lpd7a40x.c3
-rw-r--r--arch/arm/mach-lh7a40x/time.c4
-rw-r--r--arch/arm/mach-netx/generic.c5
-rw-r--r--arch/arm/mach-netx/time.c4
-rw-r--r--arch/arm/mach-omap1/board-fsample.c8
-rw-r--r--arch/arm/mach-omap1/board-h2.c11
-rw-r--r--arch/arm/mach-omap1/board-h3.c11
-rw-r--r--arch/arm/mach-omap1/board-innovator.c8
-rw-r--r--arch/arm/mach-omap1/board-nokia770.c8
-rw-r--r--arch/arm/mach-omap1/board-osk.c10
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c9
-rw-r--r--arch/arm/mach-omap1/clock.c107
-rw-r--r--arch/arm/mach-omap1/clock.h14
-rw-r--r--arch/arm/mach-omap1/fpga.c5
-rw-r--r--arch/arm/mach-omap1/mux.c11
-rw-r--r--arch/arm/mach-omap1/pm.c3
-rw-r--r--arch/arm/mach-omap1/serial.c5
-rw-r--r--arch/arm/mach-omap1/time.c8
-rw-r--r--arch/arm/mach-omap2/board-apollon.c11
-rw-r--r--arch/arm/mach-omap2/board-generic.c2
-rw-r--r--arch/arm/mach-omap2/board-h4.c3
-rw-r--r--arch/arm/mach-omap2/clock.c146
-rw-r--r--arch/arm/mach-omap2/clock.h20
-rw-r--r--arch/arm/mach-omap2/gpmc.c180
-rw-r--r--arch/arm/mach-omap2/irq.c14
-rw-r--r--arch/arm/mach-omap2/mux.c14
-rw-r--r--arch/arm/mach-omap2/pm-domain.c1
-rw-r--r--arch/arm/mach-omap2/prcm-regs.h2
-rw-r--r--arch/arm/mach-omap2/prcm.c10
-rw-r--r--arch/arm/mach-omap2/serial.c2
-rw-r--r--arch/arm/mach-omap2/sram-fn.S2
-rw-r--r--arch/arm/mach-omap2/timer-gp.c5
-rw-r--r--arch/arm/mach-pnx4008/clock.c11
-rw-r--r--arch/arm/mach-pnx4008/dma.c10
-rw-r--r--arch/arm/mach-pnx4008/gpio.c1
-rw-r--r--arch/arm/mach-pnx4008/sleep.S1
-rw-r--r--arch/arm/mach-pnx4008/time.c6
-rw-r--r--arch/arm/mach-pxa/corgi.c17
-rw-r--r--arch/arm/mach-pxa/corgi_lcd.c6
-rw-r--r--arch/arm/mach-pxa/dma.c8
-rw-r--r--arch/arm/mach-pxa/generic.c13
-rw-r--r--arch/arm/mach-pxa/idp.c11
-rw-r--r--arch/arm/mach-pxa/irq.c11
-rw-r--r--arch/arm/mach-pxa/leds-trizeps4.c1
-rw-r--r--arch/arm/mach-pxa/leds.h2
-rw-r--r--arch/arm/mach-pxa/lpd270.c47
-rw-r--r--arch/arm/mach-pxa/lubbock.c22
-rw-r--r--arch/arm/mach-pxa/mainstone.c24
-rw-r--r--arch/arm/mach-pxa/poodle.c14
-rw-r--r--arch/arm/mach-pxa/spitz.c53
-rw-r--r--arch/arm/mach-pxa/ssp.c2
-rw-r--r--arch/arm/mach-pxa/time.c8
-rw-r--r--arch/arm/mach-pxa/tosa.c2
-rw-r--r--arch/arm/mach-pxa/trizeps4.c9
-rw-r--r--arch/arm/mach-realview/core.c6
-rw-r--r--arch/arm/mach-rpc/dma.c2
-rw-r--r--arch/arm/mach-s3c2410/Kconfig40
-rw-r--r--arch/arm/mach-s3c2410/Makefile16
-rw-r--r--arch/arm/mach-s3c2410/bast-irq.c9
-rw-r--r--arch/arm/mach-s3c2410/cpu.c9
-rw-r--r--arch/arm/mach-s3c2410/devs.h5
-rw-r--r--arch/arm/mach-s3c2410/dma.c243
-rw-r--r--arch/arm/mach-s3c2410/dma.h45
-rw-r--r--arch/arm/mach-s3c2410/gpio.c16
-rw-r--r--arch/arm/mach-s3c2410/irq.c196
-rw-r--r--arch/arm/mach-s3c2410/mach-amlm5900.c266
-rw-r--r--arch/arm/mach-s3c2410/mach-anubis.c6
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2440.c9
-rw-r--r--arch/arm/mach-s3c2410/mach-vstms.c168
-rw-r--r--arch/arm/mach-s3c2410/pm-simtec.c3
-rw-r--r--arch/arm/mach-s3c2410/pm.c72
-rw-r--r--arch/arm/mach-s3c2410/pm.h16
-rw-r--r--arch/arm/mach-s3c2410/s3c2400-gpio.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-clock.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-dma.c158
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-gpio.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-irq.c48
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-pm.c120
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-sleep.S68
-rw-r--r--arch/arm/mach-s3c2410/s3c2410.c11
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-dma.c160
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-irq.c3
-rw-r--r--arch/arm/mach-s3c2410/s3c2412-pm.c128
-rw-r--r--arch/arm/mach-s3c2410/s3c2412.c61
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-dma.c164
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-dsc.c5
-rw-r--r--arch/arm/mach-s3c2410/s3c2440-irq.c9
-rw-r--r--arch/arm/mach-s3c2410/s3c2442.c2
-rw-r--r--arch/arm/mach-s3c2410/s3c244x-irq.c18
-rw-r--r--arch/arm/mach-s3c2410/s3c244x.h2
-rw-r--r--arch/arm/mach-s3c2410/sleep.S54
-rw-r--r--arch/arm/mach-s3c2410/time.c4
-rw-r--r--arch/arm/mach-s3c2410/usb-simtec.c8
-rw-r--r--arch/arm/mach-s3c2410/usb-simtec.h2
-rw-r--r--arch/arm/mach-sa1100/collie.c23
-rw-r--r--arch/arm/mach-sa1100/cpu-sa1110.c10
-rw-r--r--arch/arm/mach-sa1100/dma.c4
-rw-r--r--arch/arm/mach-sa1100/h3600.c6
-rw-r--r--arch/arm/mach-sa1100/irq.c5
-rw-r--r--arch/arm/mach-sa1100/neponset.c8
-rw-r--r--arch/arm/mach-sa1100/ssp.c2
-rw-r--r--arch/arm/mach-sa1100/time.c8
-rw-r--r--arch/arm/mach-shark/core.c4
-rw-r--r--arch/arm/mach-shark/irq.c2
-rw-r--r--arch/arm/mach-shark/leds.c2
-rw-r--r--arch/arm/mach-versatile/core.c14
-rw-r--r--arch/arm/mach-versatile/pci.c33
-rw-r--r--arch/arm/mm/Kconfig154
-rw-r--r--arch/arm/mm/Makefile10
-rw-r--r--arch/arm/mm/abort-lv4t.S7
-rw-r--r--arch/arm/mm/abort-nommu.S19
-rw-r--r--arch/arm/mm/alignment.c2
-rw-r--r--arch/arm/mm/cache-v4.S10
-rw-r--r--arch/arm/mm/context.c45
-rw-r--r--arch/arm/mm/copypage-v4mc.c4
-rw-r--r--arch/arm/mm/copypage-v6.c4
-rw-r--r--arch/arm/mm/copypage-xscale.c4
-rw-r--r--arch/arm/mm/fault.c19
-rw-r--r--arch/arm/mm/fault.h5
-rw-r--r--arch/arm/mm/flush.c6
-rw-r--r--arch/arm/mm/init.c224
-rw-r--r--arch/arm/mm/ioremap.c6
-rw-r--r--arch/arm/mm/mm-armv.c663
-rw-r--r--arch/arm/mm/mm.h22
-rw-r--r--arch/arm/mm/mmap.c22
-rw-r--r--arch/arm/mm/mmu.c768
-rw-r--r--arch/arm/mm/nommu.c43
-rw-r--r--arch/arm/mm/pgd.c101
-rw-r--r--arch/arm/mm/proc-arm740.S174
-rw-r--r--arch/arm/mm/proc-arm7tdmi.S249
-rw-r--r--arch/arm/mm/proc-arm940.S369
-rw-r--r--arch/arm/mm/proc-arm946.S424
-rw-r--r--arch/arm/mm/proc-arm9tdmi.S134
-rw-r--r--arch/arm/mm/proc-xscale.S58
-rw-r--r--arch/arm/oprofile/op_model_xscale.c20
-rw-r--r--arch/arm/plat-iop/Makefile8
-rw-r--r--arch/arm/plat-iop/gpio.c48
-rw-r--r--arch/arm/plat-iop/i2c.c81
-rw-r--r--arch/arm/plat-iop/pci.c247
-rw-r--r--arch/arm/plat-iop/setup.c38
-rw-r--r--arch/arm/plat-iop/time.c98
-rw-r--r--arch/arm/plat-omap/clock.c26
-rw-r--r--arch/arm/plat-omap/devices.c20
-rw-r--r--arch/arm/plat-omap/dma.c104
-rw-r--r--arch/arm/plat-omap/dmtimer.c76
-rw-r--r--arch/arm/plat-omap/gpio.c50
-rw-r--r--arch/arm/plat-omap/mcbsp.c13
-rw-r--r--arch/arm/plat-omap/pm.c670
-rw-r--r--arch/arm/plat-omap/sram-fn.S2
-rw-r--r--arch/arm/plat-omap/sram.c5
-rw-r--r--arch/arm/plat-omap/timer32k.c37
-rw-r--r--arch/arm/plat-omap/usb.c2
-rw-r--r--arch/arm/tools/gen-mach-types1
-rw-r--r--arch/arm/tools/mach-types90
-rw-r--r--arch/arm/vfp/vfp.h15
-rw-r--r--arch/arm/vfp/vfpdouble.c95
-rw-r--r--arch/arm/vfp/vfpinstr.h8
-rw-r--r--arch/arm/vfp/vfpmodule.c42
-rw-r--r--arch/arm/vfp/vfpsingle.c97
-rw-r--r--arch/arm26/kernel/armksyms.c8
-rw-r--r--arch/arm26/kernel/setup.c2
-rw-r--r--arch/arm26/kernel/sys_arm.c4
-rw-r--r--arch/arm26/kernel/time.c14
-rw-r--r--arch/arm26/lib/ecard.S1
-rw-r--r--arch/arm26/lib/io-acorn.S1
-rw-r--r--arch/arm26/mm/fault.c4
-rw-r--r--arch/avr32/boards/atstk1000/atstk1002.c16
-rw-r--r--arch/avr32/configs/atstk1002_defconfig6
-rw-r--r--arch/avr32/kernel/setup.c1
-rw-r--r--arch/avr32/kernel/sys_avr32.c14
-rw-r--r--arch/avr32/kernel/time.c12
-rw-r--r--arch/avr32/mach-at32ap/at32ap.c3
-rw-r--r--arch/avr32/mach-at32ap/at32ap7000.c87
-rw-r--r--arch/avr32/mach-at32ap/extint.c5
-rw-r--r--arch/avr32/mach-at32ap/intc.c7
-rw-r--r--arch/avr32/mm/ioremap.c120
-rw-r--r--arch/avr32/mm/tlb.c6
-rw-r--r--arch/cris/arch-v10/drivers/Kconfig4
-rw-r--r--arch/cris/arch-v10/kernel/time.c2
-rw-r--r--arch/cris/arch-v32/Kconfig2
-rw-r--r--arch/cris/arch-v32/kernel/smp.c1
-rw-r--r--arch/cris/arch-v32/kernel/time.c2
-rw-r--r--arch/cris/kernel/setup.c2
-rw-r--r--arch/cris/kernel/time.c7
-rw-r--r--arch/cris/mm/ioremap.c88
-rw-r--r--arch/frv/Kconfig8
-rw-r--r--arch/frv/kernel/Makefile2
-rw-r--r--arch/frv/kernel/dma.c5
-rw-r--r--arch/frv/kernel/irq-mb93091.c4
-rw-r--r--arch/frv/kernel/irq-mb93093.c4
-rw-r--r--arch/frv/kernel/irq-mb93493.c4
-rw-r--r--arch/frv/kernel/irq.c2
-rw-r--r--arch/frv/kernel/kernel_execve.S33
-rw-r--r--arch/frv/kernel/setup.c1
-rw-r--r--arch/frv/kernel/time.c11
-rw-r--r--arch/h8300/kernel/ints.c2
-rw-r--r--arch/h8300/kernel/sys_h8300.c24
-rw-r--r--arch/h8300/kernel/time.c3
-rw-r--r--arch/i386/Kconfig18
-rw-r--r--arch/i386/Kconfig.cpu3
-rw-r--r--arch/i386/Makefile8
-rw-r--r--arch/i386/boot/video.S2
-rw-r--r--arch/i386/defconfig56
-rw-r--r--arch/i386/kernel/acpi/boot.c19
-rw-r--r--arch/i386/kernel/acpi/cstate.c122
-rw-r--r--arch/i386/kernel/alternative.c4
-rw-r--r--arch/i386/kernel/apic.c18
-rw-r--r--arch/i386/kernel/apm.c73
-rw-r--r--arch/i386/kernel/cpu/common.c12
-rw-r--r--arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c7
-rw-r--r--arch/i386/kernel/cpu/cpufreq/longhaul.c56
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c2
-rw-r--r--arch/i386/kernel/cpu/mcheck/therm_throt.c21
-rw-r--r--arch/i386/kernel/crash.c10
-rw-r--r--arch/i386/kernel/efi.c7
-rw-r--r--arch/i386/kernel/head.S2
-rw-r--r--arch/i386/kernel/i8237.c5
-rw-r--r--arch/i386/kernel/i8253.c2
-rw-r--r--arch/i386/kernel/i8259.c50
-rw-r--r--arch/i386/kernel/io_apic.c504
-rw-r--r--arch/i386/kernel/irq.c19
-rw-r--r--arch/i386/kernel/kprobes.c41
-rw-r--r--arch/i386/kernel/ldt.c2
-rw-r--r--arch/i386/kernel/microcode.c778
-rw-r--r--arch/i386/kernel/nmi.c14
-rw-r--r--arch/i386/kernel/process.c33
-rw-r--r--arch/i386/kernel/setup.c35
-rw-r--r--arch/i386/kernel/smp.c33
-rw-r--r--arch/i386/kernel/smpboot.c6
-rw-r--r--arch/i386/kernel/srat.c104
-rw-r--r--arch/i386/kernel/sys_i386.c42
-rw-r--r--arch/i386/kernel/syscall_table.S1
-rw-r--r--arch/i386/kernel/time.c13
-rw-r--r--arch/i386/kernel/time_hpet.c4
-rw-r--r--arch/i386/kernel/traps.c15
-rw-r--r--arch/i386/kernel/tsc.c6
-rw-r--r--arch/i386/kernel/vm86.c2
-rw-r--r--arch/i386/lib/delay.c1
-rw-r--r--arch/i386/lib/semaphore.S4
-rw-r--r--arch/i386/lib/usercopy.c7
-rw-r--r--arch/i386/mach-visws/visws_apic.c6
-rw-r--r--arch/i386/mach-voyager/voyager_basic.c8
-rw-r--r--arch/i386/mach-voyager/voyager_smp.c77
-rw-r--r--arch/i386/mm/discontig.c73
-rw-r--r--arch/i386/mm/fault.c4
-rw-r--r--arch/i386/mm/highmem.c18
-rw-r--r--arch/i386/mm/init.c4
-rw-r--r--arch/i386/mm/ioremap.c84
-rw-r--r--arch/i386/oprofile/op_model_ppro.c20
-rw-r--r--arch/i386/pci/common.c59
-rw-r--r--arch/i386/pci/direct.c2
-rw-r--r--arch/i386/pci/fixup.c47
-rw-r--r--arch/i386/pci/init.c4
-rw-r--r--arch/i386/pci/irq.c38
-rw-r--r--arch/i386/pci/mmconfig.c5
-rw-r--r--arch/i386/pci/pci.h7
-rw-r--r--arch/ia64/Kconfig13
-rw-r--r--arch/ia64/configs/sn2_defconfig219
-rw-r--r--arch/ia64/hp/sim/simeth.c10
-rw-r--r--arch/ia64/hp/sim/simscsi.c2
-rw-r--r--arch/ia64/hp/sim/simserial.c22
-rw-r--r--arch/ia64/ia32/sys_ia32.c25
-rw-r--r--arch/ia64/kernel/Makefile6
-rw-r--r--arch/ia64/kernel/acpi-processor.c2
-rw-r--r--arch/ia64/kernel/acpi.c9
-rw-r--r--arch/ia64/kernel/entry.S10
-rw-r--r--arch/ia64/kernel/esi.c205
-rw-r--r--arch/ia64/kernel/esi_stub.S96
-rw-r--r--arch/ia64/kernel/ia64_ksyms.c4
-rw-r--r--arch/ia64/kernel/irq.c5
-rw-r--r--arch/ia64/kernel/irq_ia64.c53
-rw-r--r--arch/ia64/kernel/kprobes.c157
-rw-r--r--arch/ia64/kernel/machvec.c2
-rw-r--r--arch/ia64/kernel/mca.c268
-rw-r--r--arch/ia64/kernel/mca_asm.S9
-rw-r--r--arch/ia64/kernel/mca_drv.c54
-rw-r--r--arch/ia64/kernel/mca_drv.h4
-rw-r--r--arch/ia64/kernel/msi_ia64.c143
-rw-r--r--arch/ia64/kernel/numa.c1
-rw-r--r--arch/ia64/kernel/pal.S58
-rw-r--r--arch/ia64/kernel/perfmon.c116
-rw-r--r--arch/ia64/kernel/process.c2
-rw-r--r--arch/ia64/kernel/salinfo.c4
-rw-r--r--arch/ia64/kernel/setup.c42
-rw-r--r--arch/ia64/kernel/smpboot.c24
-rw-r--r--arch/ia64/kernel/time.c18
-rw-r--r--arch/ia64/kernel/topology.c2
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S8
-rw-r--r--arch/ia64/mm/contig.c85
-rw-r--r--arch/ia64/mm/discontig.c73
-rw-r--r--arch/ia64/mm/fault.c8
-rw-r--r--arch/ia64/mm/init.c12
-rw-r--r--arch/ia64/mm/numa.c18
-rw-r--r--arch/ia64/pci/pci.c12
-rw-r--r--arch/ia64/sn/kernel/Makefile1
-rw-r--r--arch/ia64/sn/kernel/bte.c3
-rw-r--r--arch/ia64/sn/kernel/huberror.c4
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c (renamed from drivers/pci/msi-altix.c)108
-rw-r--r--arch/ia64/sn/kernel/setup.c12
-rw-r--r--arch/ia64/sn/kernel/sn2/sn_hwperf.c2
-rw-r--r--arch/ia64/sn/kernel/sn2/timer_interrupt.c2
-rw-r--r--arch/ia64/sn/kernel/xpc_main.c7
-rw-r--r--arch/ia64/sn/kernel/xpnet.c2
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_ate.c4
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_dma.c2
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_provider.c4
-rw-r--r--arch/ia64/sn/pci/tioca_provider.c3
-rw-r--r--arch/ia64/sn/pci/tioce_provider.c45
-rw-r--r--arch/m32r/kernel/irq.c5
-rw-r--r--arch/m32r/kernel/setup.c8
-rw-r--r--arch/m32r/kernel/setup_mappi.c16
-rw-r--r--arch/m32r/kernel/signal.c6
-rw-r--r--arch/m32r/kernel/smp.c15
-rw-r--r--arch/m32r/kernel/sys_m32r.c28
-rw-r--r--arch/m32r/kernel/time.c23
-rw-r--r--arch/m32r/kernel/traps.c2
-rw-r--r--arch/m32r/mm/fault.c2
-rw-r--r--arch/m32r/mm/ioremap.c93
-rw-r--r--arch/m32r/mm/mmu.S1
-rw-r--r--arch/m68k/Kconfig2
-rw-r--r--arch/m68k/amiga/amiints.c40
-rw-r--r--arch/m68k/amiga/cia.c4
-rw-r--r--arch/m68k/amiga/config.c5
-rw-r--r--arch/m68k/apollo/config.c14
-rw-r--r--arch/m68k/apollo/dma.c50
-rw-r--r--arch/m68k/apollo/dn_ints.c2
-rw-r--r--arch/m68k/atari/ataints.c9
-rw-r--r--arch/m68k/atari/config.c2
-rw-r--r--arch/m68k/atari/stdma.c11
-rw-r--r--arch/m68k/atari/time.c11
-rw-r--r--arch/m68k/bvme6000/config.c12
-rw-r--r--arch/m68k/hp300/time.c8
-rw-r--r--arch/m68k/hp300/time.h2
-rw-r--r--arch/m68k/kernel/Makefile3
-rw-r--r--arch/m68k/kernel/dma.c4
-rw-r--r--arch/m68k/kernel/entry.S33
-rw-r--r--arch/m68k/kernel/ints.c21
-rw-r--r--arch/m68k/kernel/m68k_ksyms.c55
-rw-r--r--arch/m68k/kernel/process.c11
-rw-r--r--arch/m68k/kernel/setup.c17
-rw-r--r--arch/m68k/kernel/sys_m68k.c16
-rw-r--r--arch/m68k/kernel/time.c26
-rw-r--r--arch/m68k/kernel/traps.c6
-rw-r--r--arch/m68k/lib/string.c15
-rw-r--r--arch/m68k/lib/uaccess.c2
-rw-r--r--arch/m68k/mac/baboon.c6
-rw-r--r--arch/m68k/mac/config.c4
-rw-r--r--arch/m68k/mac/iop.c22
-rw-r--r--arch/m68k/mac/macints.c16
-rw-r--r--arch/m68k/mac/oss.c16
-rw-r--r--arch/m68k/mac/psc.c6
-rw-r--r--arch/m68k/mac/via.c24
-rw-r--r--arch/m68k/mm/fault.c4
-rw-r--r--arch/m68k/mm/kmap.c4
-rw-r--r--arch/m68k/mm/memory.c8
-rw-r--r--arch/m68k/mm/motorola.c2
-rw-r--r--arch/m68k/mm/sun3kmap.c11
-rw-r--r--arch/m68k/mvme147/config.c10
-rw-r--r--arch/m68k/mvme16x/config.c12
-rw-r--r--arch/m68k/q40/config.c2
-rw-r--r--arch/m68k/q40/q40ints.c16
-rw-r--r--arch/m68k/sun3/Makefile2
-rw-r--r--arch/m68k/sun3/config.c4
-rw-r--r--arch/m68k/sun3/idprom.c3
-rw-r--r--arch/m68k/sun3/sun3_ksyms.c13
-rw-r--r--arch/m68k/sun3/sun3dvma.c8
-rw-r--r--arch/m68k/sun3/sun3ints.c13
-rw-r--r--arch/m68k/sun3x/time.c2
-rw-r--r--arch/m68k/sun3x/time.h2
-rw-r--r--arch/m68knommu/Kconfig6
-rw-r--r--arch/m68knommu/kernel/sys_m68k.c15
-rw-r--r--arch/m68knommu/kernel/syscalltable.S37
-rw-r--r--arch/m68knommu/kernel/time.c9
-rw-r--r--arch/m68knommu/platform/532x/config.c1
-rw-r--r--arch/m68knommu/platform/68328/head-pilot.S2
-rw-r--r--arch/m68knommu/platform/68328/romvec.S2
-rw-r--r--arch/mips/Kconfig131
-rw-r--r--arch/mips/Makefile34
-rw-r--r--arch/mips/au1000/common/Makefile1
-rw-r--r--arch/mips/au1000/common/dbdma.c2
-rw-r--r--arch/mips/au1000/common/dma.c2
-rw-r--r--arch/mips/au1000/common/irq.c52
-rw-r--r--arch/mips/au1000/common/time.c20
-rw-r--r--arch/mips/au1000/common/usbdev.c1555
-rw-r--r--arch/mips/au1000/db1x00/Makefile1
-rw-r--r--arch/mips/au1000/db1x00/board_setup.c5
-rw-r--r--arch/mips/au1000/db1x00/mirage_ts.c260
-rw-r--r--arch/mips/au1000/mtx-1/board_setup.c8
-rw-r--r--arch/mips/au1000/pb1000/board_setup.c10
-rw-r--r--arch/mips/au1000/pb1100/board_setup.c6
-rw-r--r--arch/mips/au1000/pb1200/irqmap.c5
-rw-r--r--arch/mips/au1000/pb1500/board_setup.c9
-rw-r--r--arch/mips/basler/excite/excite_dbg_io.c2
-rw-r--r--arch/mips/basler/excite/excite_device.c16
-rw-r--r--arch/mips/basler/excite/excite_flashtest.c294
-rw-r--r--arch/mips/basler/excite/excite_iodev.c14
-rw-r--r--arch/mips/basler/excite/excite_irq.c18
-rw-r--r--arch/mips/cobalt/irq.c52
-rw-r--r--arch/mips/cobalt/setup.c5
-rw-r--r--arch/mips/configs/atlas_defconfig6
-rw-r--r--arch/mips/configs/bigsur_defconfig106
-rw-r--r--arch/mips/configs/capcella_defconfig4
-rw-r--r--arch/mips/configs/cobalt_defconfig6
-rw-r--r--arch/mips/configs/db1000_defconfig4
-rw-r--r--arch/mips/configs/db1100_defconfig4
-rw-r--r--arch/mips/configs/db1200_defconfig4
-rw-r--r--arch/mips/configs/db1500_defconfig4
-rw-r--r--arch/mips/configs/db1550_defconfig4
-rw-r--r--arch/mips/configs/ddb5477_defconfig4
-rw-r--r--arch/mips/configs/decstation_defconfig150
-rw-r--r--arch/mips/configs/e55_defconfig13
-rw-r--r--arch/mips/configs/emma2rh_defconfig4
-rw-r--r--arch/mips/configs/ev64120_defconfig4
-rw-r--r--arch/mips/configs/excite_defconfig4
-rw-r--r--arch/mips/configs/ip22_defconfig6
-rw-r--r--arch/mips/configs/ip27_defconfig6
-rw-r--r--arch/mips/configs/ip32_defconfig4
-rw-r--r--arch/mips/configs/jaguar-atx_defconfig6
-rw-r--r--arch/mips/configs/jazz_defconfig1404
-rw-r--r--arch/mips/configs/jmr3927_defconfig4
-rw-r--r--arch/mips/configs/lasat200_defconfig6
-rw-r--r--arch/mips/configs/malta_defconfig104
-rw-r--r--arch/mips/configs/mipssim_defconfig4
-rw-r--r--arch/mips/configs/mpc30x_defconfig15
-rw-r--r--arch/mips/configs/ocelot_3_defconfig4
-rw-r--r--arch/mips/configs/ocelot_c_defconfig6
-rw-r--r--arch/mips/configs/ocelot_defconfig6
-rw-r--r--arch/mips/configs/ocelot_g_defconfig6
-rw-r--r--arch/mips/configs/pb1100_defconfig5
-rw-r--r--arch/mips/configs/pb1500_defconfig5
-rw-r--r--arch/mips/configs/pb1550_defconfig4
-rw-r--r--arch/mips/configs/pnx8550-jbs_defconfig388
-rw-r--r--arch/mips/configs/pnx8550-v2pci_defconfig445
-rw-r--r--arch/mips/configs/qemu_defconfig6
-rw-r--r--arch/mips/configs/rbhma4500_defconfig4
-rw-r--r--arch/mips/configs/rm200_defconfig6
-rw-r--r--arch/mips/configs/sb1250-swarm_defconfig4
-rw-r--r--arch/mips/configs/sead_defconfig4
-rw-r--r--arch/mips/configs/tb0226_defconfig4
-rw-r--r--arch/mips/configs/tb0229_defconfig4
-rw-r--r--arch/mips/configs/tb0287_defconfig186
-rw-r--r--arch/mips/configs/workpad_defconfig13
-rw-r--r--arch/mips/configs/wrppmc_defconfig4
-rw-r--r--arch/mips/configs/yosemite_defconfig4
-rw-r--r--arch/mips/ddb5xxx/ddb5477/irq.c19
-rw-r--r--arch/mips/dec/boot/Makefile12
-rw-r--r--arch/mips/dec/boot/decstation.c84
-rw-r--r--arch/mips/dec/boot/ld.ecoff43
-rw-r--r--arch/mips/dec/ecc-berr.c5
-rw-r--r--arch/mips/dec/int-handler.S13
-rw-r--r--arch/mips/dec/kn01-berr.c4
-rw-r--r--arch/mips/dec/kn02xa-berr.c6
-rw-r--r--arch/mips/dec/prom/call_o32.S2
-rw-r--r--arch/mips/dec/reset.c3
-rw-r--r--arch/mips/dec/setup.c2
-rw-r--r--arch/mips/dec/time.c2
-rw-r--r--arch/mips/defconfig8
-rw-r--r--arch/mips/emma2rh/common/irq.c12
-rw-r--r--arch/mips/emma2rh/markeins/irq.c14
-rw-r--r--arch/mips/galileo-boards/ev96100/Makefile9
-rw-r--r--arch/mips/galileo-boards/ev96100/init.c173
-rw-r--r--arch/mips/galileo-boards/ev96100/irq.c77
-rw-r--r--arch/mips/galileo-boards/ev96100/puts.c138
-rw-r--r--arch/mips/galileo-boards/ev96100/reset.c70
-rw-r--r--arch/mips/galileo-boards/ev96100/setup.c159
-rw-r--r--arch/mips/galileo-boards/ev96100/time.c88
-rw-r--r--arch/mips/gt64120/common/time.c10
-rw-r--r--arch/mips/gt64120/ev64120/irq.c14
-rw-r--r--arch/mips/gt64120/ev64120/setup.c1
-rw-r--r--arch/mips/gt64120/momenco_ocelot/irq.c22
-rw-r--r--arch/mips/gt64120/momenco_ocelot/setup.c1
-rw-r--r--arch/mips/gt64120/wrppmc/irq.c10
-rw-r--r--arch/mips/ite-boards/Kconfig8
-rw-r--r--arch/mips/ite-boards/generic/Makefile15
-rw-r--r--arch/mips/ite-boards/generic/dbg_io.c124
-rw-r--r--arch/mips/ite-boards/generic/irq.c308
-rw-r--r--arch/mips/ite-boards/generic/it8172_cir.c170
-rw-r--r--arch/mips/ite-boards/generic/it8172_setup.c352
-rw-r--r--arch/mips/ite-boards/generic/lpc.c144
-rw-r--r--arch/mips/ite-boards/generic/pmon_prom.c135
-rw-r--r--arch/mips/ite-boards/generic/puts.c139
-rw-r--r--arch/mips/ite-boards/generic/reset.c60
-rw-r--r--arch/mips/ite-boards/generic/time.c249
-rw-r--r--arch/mips/ite-boards/ivr/Makefile10
-rw-r--r--arch/mips/ite-boards/ivr/README3
-rw-r--r--arch/mips/ite-boards/ivr/init.c81
-rw-r--r--arch/mips/ite-boards/qed-4n-s01b/Makefile10
-rw-r--r--arch/mips/ite-boards/qed-4n-s01b/README2
-rw-r--r--arch/mips/ite-boards/qed-4n-s01b/init.c82
-rw-r--r--arch/mips/jazz/irq.c30
-rw-r--r--arch/mips/jazz/setup.c31
-rw-r--r--arch/mips/jmr3927/rbhma3100/irq.c106
-rw-r--r--arch/mips/kernel/Makefile1
-rw-r--r--arch/mips/kernel/asm-offsets.c3
-rw-r--r--arch/mips/kernel/cpu-probe.c71
-rw-r--r--arch/mips/kernel/entry.S15
-rw-r--r--arch/mips/kernel/genex.S15
-rw-r--r--arch/mips/kernel/i8259.c4
-rw-r--r--arch/mips/kernel/irixsig.c63
-rw-r--r--arch/mips/kernel/irq-msc01.c13
-rw-r--r--arch/mips/kernel/irq-mv6434x.c9
-rw-r--r--arch/mips/kernel/irq.c6
-rw-r--r--arch/mips/kernel/linux32.c18
-rw-r--r--arch/mips/kernel/proc.c12
-rw-r--r--arch/mips/kernel/process.c284
-rw-r--r--arch/mips/kernel/ptrace.c18
-rw-r--r--arch/mips/kernel/ptrace32.c3
-rw-r--r--arch/mips/kernel/rtlx.c6
-rw-r--r--arch/mips/kernel/scall32-o32.S16
-rw-r--r--arch/mips/kernel/scall64-64.S5
-rw-r--r--arch/mips/kernel/scall64-n32.S11
-rw-r--r--arch/mips/kernel/scall64-o32.S9
-rw-r--r--arch/mips/kernel/setup.c439
-rw-r--r--arch/mips/kernel/signal.c8
-rw-r--r--arch/mips/kernel/signal32.c7
-rw-r--r--arch/mips/kernel/smp-mt.c18
-rw-r--r--arch/mips/kernel/smp.c16
-rw-r--r--arch/mips/kernel/smtc-asm.S11
-rw-r--r--arch/mips/kernel/smtc.c26
-rw-r--r--arch/mips/kernel/stacktrace.c85
-rw-r--r--arch/mips/kernel/syscall.c60
-rw-r--r--arch/mips/kernel/sysirix.c22
-rw-r--r--arch/mips/kernel/time.c111
-rw-r--r--arch/mips/kernel/traps.c132
-rw-r--r--arch/mips/kernel/vpe.c6
-rw-r--r--arch/mips/lasat/interrupt.c6
-rw-r--r--arch/mips/lasat/setup.c1
-rw-r--r--arch/mips/math-emu/cp1emu.c7
-rw-r--r--arch/mips/mips-boards/atlas/atlas_int.c117
-rw-r--r--arch/mips/mips-boards/atlas/atlas_setup.c2
-rw-r--r--arch/mips/mips-boards/generic/time.c81
-rw-r--r--arch/mips/mips-boards/malta/malta_int.c39
-rw-r--r--arch/mips/mips-boards/sead/sead_int.c4
-rw-r--r--arch/mips/mips-boards/sim/sim_int.c11
-rw-r--r--arch/mips/mips-boards/sim/sim_time.c15
-rw-r--r--arch/mips/mm/c-r3k.c21
-rw-r--r--arch/mips/mm/c-r4k.c101
-rw-r--r--arch/mips/mm/c-sb1.c105
-rw-r--r--arch/mips/mm/c-tx39.c29
-rw-r--r--arch/mips/mm/cache.c17
-rw-r--r--arch/mips/mm/fault.c4
-rw-r--r--arch/mips/mm/init.c4
-rw-r--r--arch/mips/mm/ioremap.c2
-rw-r--r--arch/mips/mm/tlb-r4k.c21
-rw-r--r--arch/mips/mm/tlbex-fault.S4
-rw-r--r--arch/mips/mm/tlbex.c2
-rw-r--r--arch/mips/momentum/jaguar_atx/irq.c20
-rw-r--r--arch/mips/momentum/jaguar_atx/setup.c1
-rw-r--r--arch/mips/momentum/ocelot_3/irq.c22
-rw-r--r--arch/mips/momentum/ocelot_3/setup.c1
-rw-r--r--arch/mips/momentum/ocelot_c/cpci-irq.c5
-rw-r--r--arch/mips/momentum/ocelot_c/irq.c24
-rw-r--r--arch/mips/momentum/ocelot_c/setup.c1
-rw-r--r--arch/mips/momentum/ocelot_c/uart-irq.c5
-rw-r--r--arch/mips/momentum/ocelot_g/gt-irq.c7
-rw-r--r--arch/mips/momentum/ocelot_g/irq.c24
-rw-r--r--arch/mips/momentum/ocelot_g/setup.c1
-rw-r--r--arch/mips/oprofile/op_impl.h6
-rw-r--r--arch/mips/oprofile/op_model_mipsxx.c7
-rw-r--r--arch/mips/oprofile/op_model_rm9000.c3
-rw-r--r--arch/mips/pci/Makefile7
-rw-r--r--arch/mips/pci/fixup-atlas.c20
-rw-r--r--arch/mips/pci/fixup-ev96100.c48
-rw-r--r--arch/mips/pci/fixup-ite8172g.c80
-rw-r--r--arch/mips/pci/fixup-ivr.c75
-rw-r--r--arch/mips/pci/fixup-sb1250.c23
-rw-r--r--arch/mips/pci/fixup-vr4133.c2
-rw-r--r--arch/mips/pci/ops-au1000.c2
-rw-r--r--arch/mips/pci/ops-gt96100.c169
-rw-r--r--arch/mips/pci/ops-it8172.c213
-rw-r--r--arch/mips/pci/pci-ev96100.c63
-rw-r--r--arch/mips/pci/pci-ip27.c2
-rw-r--r--arch/mips/pci/pci-ip32.c2
-rw-r--r--arch/mips/philips/pnx8550/common/int.c32
-rw-r--r--arch/mips/philips/pnx8550/common/platform.c16
-rw-r--r--arch/mips/philips/pnx8550/common/prom.c4
-rw-r--r--arch/mips/philips/pnx8550/common/setup.c6
-rw-r--r--arch/mips/pmc-sierra/yosemite/irq.c54
-rw-r--r--arch/mips/pmc-sierra/yosemite/setup.c1
-rw-r--r--arch/mips/pmc-sierra/yosemite/smp.c2
-rw-r--r--arch/mips/qemu/q-irq.c6
-rw-r--r--arch/mips/sgi-ip22/ip22-berr.c4
-rw-r--r--arch/mips/sgi-ip22/ip22-eisa.c5
-rw-r--r--arch/mips/sgi-ip22/ip22-int.c32
-rw-r--r--arch/mips/sgi-ip22/ip22-reset.c5
-rw-r--r--arch/mips/sgi-ip22/ip22-time.c6
-rw-r--r--arch/mips/sgi-ip27/ip27-irq.c27
-rw-r--r--arch/mips/sgi-ip27/ip27-klnuma.c2
-rw-r--r--arch/mips/sgi-ip27/ip27-timer.c8
-rw-r--r--arch/mips/sgi-ip32/crime.c7
-rw-r--r--arch/mips/sgi-ip32/ip32-irq.c48
-rw-r--r--arch/mips/sgi-ip32/ip32-reset.c4
-rw-r--r--arch/mips/sibyte/bcm1480/irq.c45
-rw-r--r--arch/mips/sibyte/bcm1480/smp.c8
-rw-r--r--arch/mips/sibyte/bcm1480/time.c9
-rw-r--r--arch/mips/sibyte/sb1250/bcm1250_tbprof.c4
-rw-r--r--arch/mips/sibyte/sb1250/bus_watcher.c2
-rw-r--r--arch/mips/sibyte/sb1250/irq.c47
-rw-r--r--arch/mips/sibyte/sb1250/smp.c2
-rw-r--r--arch/mips/sibyte/sb1250/time.c7
-rw-r--r--arch/mips/sni/irq.c34
-rw-r--r--arch/mips/sni/setup.c1
-rw-r--r--arch/mips/tx4927/common/tx4927_irq.c14
-rw-r--r--arch/mips/tx4927/common/tx4927_setup.c10
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c2
-rw-r--r--arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c7
-rw-r--r--arch/mips/tx4938/common/irq.c49
-rw-r--r--arch/mips/tx4938/common/setup.c19
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/irq.c2
-rw-r--r--arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c3
-rw-r--r--arch/mips/vr41xx/common/icu.c2
-rw-r--r--arch/mips/vr41xx/common/irq.c32
-rw-r--r--arch/parisc/Kconfig2
-rw-r--r--arch/parisc/hpux/fs.c10
-rw-r--r--arch/parisc/hpux/sys_hpux.c37
-rw-r--r--arch/parisc/kernel/binfmt_elf32.c24
-rw-r--r--arch/parisc/kernel/cache.c48
-rw-r--r--arch/parisc/kernel/drivers.c11
-rw-r--r--arch/parisc/kernel/entry.S25
-rw-r--r--arch/parisc/kernel/firmware.c257
-rw-r--r--arch/parisc/kernel/hardware.c3
-rw-r--r--arch/parisc/kernel/head.S2
-rw-r--r--arch/parisc/kernel/irq.c158
-rw-r--r--arch/parisc/kernel/module.c32
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c4
-rw-r--r--arch/parisc/kernel/pci.c2
-rw-r--r--arch/parisc/kernel/process.c9
-rw-r--r--arch/parisc/kernel/processor.c5
-rw-r--r--arch/parisc/kernel/signal.c5
-rw-r--r--arch/parisc/kernel/smp.c22
-rw-r--r--arch/parisc/kernel/sys_parisc.c32
-rw-r--r--arch/parisc/kernel/sys_parisc32.c44
-rw-r--r--arch/parisc/kernel/syscall.S1
-rw-r--r--arch/parisc/kernel/syscall_table.S4
-rw-r--r--arch/parisc/kernel/time.c242
-rw-r--r--arch/parisc/kernel/traps.c10
-rw-r--r--arch/parisc/mm/init.c23
-rw-r--r--arch/parisc/mm/ioremap.c2
-rw-r--r--arch/powerpc/Kconfig43
-rw-r--r--arch/powerpc/Makefile6
-rw-r--r--arch/powerpc/boot/Makefile224
-rw-r--r--arch/powerpc/boot/dts/mpc8272ads.dts223
-rw-r--r--arch/powerpc/boot/dts/mpc8349emitx.dts246
-rw-r--r--arch/powerpc/boot/dts/mpc8360emds.dts375
-rw-r--r--arch/powerpc/boot/dts/mpc8560ads.dts302
-rw-r--r--arch/powerpc/boot/of.c5
-rwxr-xr-xarch/powerpc/boot/wrapper204
-rw-r--r--arch/powerpc/boot/zImage.coff.lds.S (renamed from arch/powerpc/boot/zImage.coff.lds)1
-rw-r--r--arch/powerpc/boot/zImage.lds.S (renamed from arch/powerpc/boot/zImage.lds)0
-rw-r--r--arch/powerpc/configs/cell_defconfig60
-rw-r--r--arch/powerpc/configs/chrp32_defconfig2
-rw-r--r--arch/powerpc/configs/g5_defconfig28
-rw-r--r--arch/powerpc/configs/iseries_defconfig86
-rw-r--r--arch/powerpc/configs/maple_defconfig56
-rw-r--r--arch/powerpc/configs/mpc7448_hpc2_defconfig28
-rw-r--r--arch/powerpc/configs/mpc834x_itx_defconfig55
-rw-r--r--arch/powerpc/configs/mpc8360emds_defconfig (renamed from arch/arm/configs/iq80331_defconfig)796
-rw-r--r--arch/powerpc/configs/mpc8560_ads_defconfig (renamed from arch/mips/configs/ivr_defconfig)536
-rw-r--r--arch/powerpc/configs/pmac32_defconfig4
-rw-r--r--arch/powerpc/configs/ppc64_defconfig28
-rw-r--r--arch/powerpc/configs/pseries_defconfig3
-rw-r--r--arch/powerpc/kernel/cputable.c17
-rw-r--r--arch/powerpc/kernel/entry_64.S18
-rw-r--r--arch/powerpc/kernel/head_64.S28
-rw-r--r--arch/powerpc/kernel/ibmebus.c2
-rw-r--r--arch/powerpc/kernel/iommu.c2
-rw-r--r--arch/powerpc/kernel/irq.c31
-rw-r--r--arch/powerpc/kernel/kprobes.c33
-rw-r--r--arch/powerpc/kernel/misc_32.S2
-rw-r--r--arch/powerpc/kernel/misc_64.S54
-rw-r--r--arch/powerpc/kernel/pci_32.c12
-rw-r--r--arch/powerpc/kernel/pci_64.c68
-rw-r--r--arch/powerpc/kernel/perfmon_fsl_booke.c2
-rw-r--r--arch/powerpc/kernel/process.c12
-rw-r--r--arch/powerpc/kernel/prom.c2
-rw-r--r--arch/powerpc/kernel/ptrace.c13
-rw-r--r--arch/powerpc/kernel/setup-common.c25
-rw-r--r--arch/powerpc/kernel/setup_32.c12
-rw-r--r--arch/powerpc/kernel/setup_64.c19
-rw-r--r--arch/powerpc/kernel/smp.c6
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c17
-rw-r--r--arch/powerpc/kernel/syscalls.c14
-rw-r--r--arch/powerpc/kernel/sysfs.c4
-rw-r--r--arch/powerpc/kernel/time.c59
-rw-r--r--arch/powerpc/kernel/traps.c3
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S8
-rw-r--r--arch/powerpc/lib/Makefile6
-rw-r--r--arch/powerpc/lib/rheap.c24
-rw-r--r--arch/powerpc/math-emu/Makefile3
-rw-r--r--arch/powerpc/mm/fault.c4
-rw-r--r--arch/powerpc/mm/mem.c52
-rw-r--r--arch/powerpc/mm/numa.c159
-rw-r--r--arch/powerpc/mm/pgtable_64.c29
-rw-r--r--arch/powerpc/mm/slb_low.S3
-rw-r--r--arch/powerpc/oprofile/backtrace.c11
-rw-r--r--arch/powerpc/oprofile/op_model_7450.c2
-rw-r--r--arch/powerpc/oprofile/op_model_fsl_booke.c2
-rw-r--r--arch/powerpc/platforms/82xx/Kconfig21
-rw-r--r--arch/powerpc/platforms/82xx/Makefile5
-rw-r--r--arch/powerpc/platforms/82xx/m82xx_pci.h19
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx.c110
-rw-r--r--arch/powerpc/platforms/82xx/mpc82xx_ads.c658
-rw-r--r--arch/powerpc/platforms/82xx/pq2ads.h65
-rw-r--r--arch/powerpc/platforms/83xx/Kconfig26
-rw-r--r--arch/powerpc/platforms/83xx/Makefile2
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c215
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.h19
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_itx.c5
-rw-r--r--arch/powerpc/platforms/83xx/mpc834x_sys.h2
-rw-r--r--arch/powerpc/platforms/83xx/mpc8360e_pb.c238
-rw-r--r--arch/powerpc/platforms/85xx/Kconfig21
-rw-r--r--arch/powerpc/platforms/85xx/Makefile1
-rw-r--r--arch/powerpc/platforms/85xx/mpc8540_ads.h2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx.h2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.c119
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_ads.h60
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.c10
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_cds.h2
-rw-r--r--arch/powerpc/platforms/86xx/mpc86xx_hpcn.c7
-rw-r--r--arch/powerpc/platforms/cell/Kconfig5
-rw-r--r--arch/powerpc/platforms/cell/cbe_regs.c2
-rw-r--r--arch/powerpc/platforms/cell/interrupt.c244
-rw-r--r--arch/powerpc/platforms/cell/interrupt.h97
-rw-r--r--arch/powerpc/platforms/cell/iommu.c8
-rw-r--r--arch/powerpc/platforms/cell/ras.c1
-rw-r--r--arch/powerpc/platforms/cell/spider-pic.c20
-rw-r--r--arch/powerpc/platforms/cell/spu_base.c212
-rw-r--r--arch/powerpc/platforms/cell/spufs/Makefile2
-rw-r--r--arch/powerpc/platforms/cell/spufs/context.c6
-rw-r--r--arch/powerpc/platforms/cell/spufs/file.c357
-rw-r--r--arch/powerpc/platforms/cell/spufs/gang.c81
-rw-r--r--arch/powerpc/platforms/cell/spufs/hw_ops.c4
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c235
-rw-r--r--arch/powerpc/platforms/cell/spufs/run.c48
-rw-r--r--arch/powerpc/platforms/cell/spufs/sched.c450
-rw-r--r--arch/powerpc/platforms/cell/spufs/spufs.h29
-rw-r--r--arch/powerpc/platforms/cell/spufs/switch.c9
-rw-r--r--arch/powerpc/platforms/cell/spufs/syscalls.c9
-rw-r--r--arch/powerpc/platforms/chrp/setup.c9
-rw-r--r--arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c6
-rw-r--r--arch/powerpc/platforms/iseries/irq.c17
-rw-r--r--arch/powerpc/platforms/iseries/irq.h2
-rw-r--r--arch/powerpc/platforms/iseries/lpevents.c4
-rw-r--r--arch/powerpc/platforms/iseries/mf.c6
-rw-r--r--arch/powerpc/platforms/iseries/pci.c8
-rw-r--r--arch/powerpc/platforms/iseries/setup.c16
-rw-r--r--arch/powerpc/platforms/iseries/smp.c6
-rw-r--r--arch/powerpc/platforms/iseries/smp.h6
-rw-r--r--arch/powerpc/platforms/iseries/viopath.c2
-rw-r--r--arch/powerpc/platforms/maple/pci.c247
-rw-r--r--arch/powerpc/platforms/pasemi/pci.c26
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c1
-rw-r--r--arch/powerpc/platforms/pasemi/time.c1
-rw-r--r--arch/powerpc/platforms/powermac/cpufreq_64.c2
-rw-r--r--arch/powerpc/platforms/powermac/low_i2c.c2
-rw-r--r--arch/powerpc/platforms/powermac/nvram.c4
-rw-r--r--arch/powerpc/platforms/powermac/pfunc_base.c2
-rw-r--r--arch/powerpc/platforms/powermac/pic.c19
-rw-r--r--arch/powerpc/platforms/powermac/pic.h4
-rw-r--r--arch/powerpc/platforms/powermac/smp.c15
-rw-r--r--arch/powerpc/platforms/powermac/udbg_scc.c14
-rw-r--r--arch/powerpc/platforms/pseries/eeh.c7
-rw-r--r--arch/powerpc/platforms/pseries/hvCall_inst.c2
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c3
-rw-r--r--arch/powerpc/platforms/pseries/ras.c16
-rw-r--r--arch/powerpc/platforms/pseries/setup.c35
-rw-r--r--arch/powerpc/platforms/pseries/xics.c22
-rw-r--r--arch/powerpc/platforms/pseries/xics.h3
-rw-r--r--arch/powerpc/sysdev/Makefile6
-rw-r--r--arch/powerpc/sysdev/cpm2_common.c309
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.c256
-rw-r--r--arch/powerpc/sysdev/cpm2_pic.h10
-rw-r--r--arch/powerpc/sysdev/fsl_soc.c330
-rw-r--r--arch/powerpc/sysdev/fsl_soc.h2
-rw-r--r--arch/powerpc/sysdev/i8259.c2
-rw-r--r--arch/powerpc/sysdev/ipic.c4
-rw-r--r--arch/powerpc/sysdev/mpic.c14
-rw-r--r--arch/powerpc/sysdev/qe_lib/Kconfig30
-rw-r--r--arch/powerpc/sysdev/qe_lib/Makefile8
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe.c353
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c553
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.h106
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_io.c225
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc.c251
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc_fast.c396
-rw-r--r--arch/powerpc/sysdev/qe_lib/ucc_slow.c404
-rw-r--r--arch/powerpc/sysdev/tsi108_dev.c1
-rw-r--r--arch/powerpc/sysdev/tsi108_pci.c5
-rw-r--r--arch/powerpc/xmon/xmon.c47
-rw-r--r--arch/ppc/4xx_io/serial_sicc.c12
-rw-r--r--arch/ppc/8260_io/enet.c4
-rw-r--r--arch/ppc/8260_io/fcc_enet.c6
-rw-r--r--arch/ppc/8xx_io/commproc.c19
-rw-r--r--arch/ppc/8xx_io/cs4218_tdm.c4
-rw-r--r--arch/ppc/8xx_io/enet.c4
-rw-r--r--arch/ppc/8xx_io/fec.c7
-rw-r--r--arch/ppc/Kconfig7
-rw-r--r--arch/ppc/amiga/time.c1
-rw-r--r--arch/ppc/boot/include/mpsc_defs.h2
-rw-r--r--arch/ppc/boot/utils/mkbugboot.c208
-rw-r--r--arch/ppc/boot/utils/mkprep.c416
-rw-r--r--arch/ppc/kernel/misc.S18
-rw-r--r--arch/ppc/kernel/setup.c4
-rw-r--r--arch/ppc/kernel/smp.c4
-rw-r--r--arch/ppc/kernel/time.c19
-rw-r--r--arch/ppc/kernel/traps.c2
-rw-r--r--arch/ppc/mm/fault.c4
-rw-r--r--arch/ppc/mm/init.c24
-rw-r--r--arch/ppc/platforms/4xx/cpci405.h1
-rw-r--r--arch/ppc/platforms/4xx/xparameters/xparameters.h2
-rw-r--r--arch/ppc/platforms/85xx/Kconfig14
-rw-r--r--arch/ppc/platforms/85xx/mpc8560_ads.c6
-rw-r--r--arch/ppc/platforms/85xx/mpc85xx_cds_common.c6
-rw-r--r--arch/ppc/platforms/85xx/stx_gp3.c6
-rw-r--r--arch/ppc/platforms/85xx/tqm85xx.c6
-rw-r--r--arch/ppc/platforms/apus_setup.c2
-rw-r--r--arch/ppc/platforms/hdpu.c22
-rw-r--r--arch/ppc/platforms/lopec.h2
-rw-r--r--arch/ppc/platforms/mpc8272ads_setup.c14
-rw-r--r--arch/ppc/platforms/mpc866ads_setup.c12
-rw-r--r--arch/ppc/platforms/mpc885ads_setup.c16
-rw-r--r--arch/ppc/platforms/mvme5100.h2
-rw-r--r--arch/ppc/platforms/powerpmc250.h2
-rw-r--r--arch/ppc/platforms/prpmc750.h2
-rw-r--r--arch/ppc/platforms/prpmc800.h2
-rw-r--r--arch/ppc/platforms/radstone_ppc7d.c10
-rw-r--r--arch/ppc/platforms/sbc82xx.c4
-rw-r--r--arch/ppc/platforms/spruce.h2
-rw-r--r--arch/ppc/syslib/cpc700.h2
-rw-r--r--arch/ppc/syslib/cpc700_pic.c2
-rw-r--r--arch/ppc/syslib/cpm2_pic.c2
-rw-r--r--arch/ppc/syslib/cpm2_pic.h2
-rw-r--r--arch/ppc/syslib/gt64260_pic.c9
-rw-r--r--arch/ppc/syslib/i8259.c2
-rw-r--r--arch/ppc/syslib/ibm440gx_common.c2
-rw-r--r--arch/ppc/syslib/ipic.c2
-rw-r--r--arch/ppc/syslib/m82xx_pci.c4
-rw-r--r--arch/ppc/syslib/m8xx_setup.c2
-rw-r--r--arch/ppc/syslib/m8xx_wdt.c4
-rw-r--r--arch/ppc/syslib/mpc52xx_pic.c2
-rw-r--r--arch/ppc/syslib/mv64360_pic.c22
-rw-r--r--arch/ppc/syslib/open_pic.c14
-rw-r--r--arch/ppc/syslib/open_pic2.c2
-rw-r--r--arch/ppc/syslib/ppc403_pic.c2
-rw-r--r--arch/ppc/syslib/ppc4xx_pic.c8
-rw-r--r--arch/ppc/syslib/ppc85xx_rio.c9
-rw-r--r--arch/ppc/syslib/ppc8xx_pic.c4
-rw-r--r--arch/ppc/syslib/xilinx_pic.c2
-rw-r--r--arch/s390/Kconfig18
-rw-r--r--arch/s390/Makefile1
-rw-r--r--arch/s390/appldata/appldata_base.c8
-rw-r--r--arch/s390/crypto/crypt_s390.h204
-rw-r--r--arch/s390/defconfig58
-rw-r--r--arch/s390/hypfs/hypfs_diag.c26
-rw-r--r--arch/s390/hypfs/inode.c24
-rw-r--r--arch/s390/kernel/compat_linux.c14
-rw-r--r--arch/s390/kernel/compat_wrapper.S449
-rw-r--r--arch/s390/kernel/cpcmd.c83
-rw-r--r--arch/s390/kernel/debug.c2
-rw-r--r--arch/s390/kernel/entry.S469
-rw-r--r--arch/s390/kernel/entry64.S443
-rw-r--r--arch/s390/kernel/head.S624
-rw-r--r--arch/s390/kernel/head31.S11
-rw-r--r--arch/s390/kernel/head64.S443
-rw-r--r--arch/s390/kernel/ipl.c21
-rw-r--r--arch/s390/kernel/kprobes.c10
-rw-r--r--arch/s390/kernel/process.c5
-rw-r--r--arch/s390/kernel/reipl.S75
-rw-r--r--arch/s390/kernel/reipl64.S93
-rw-r--r--arch/s390/kernel/relocate_kernel.S74
-rw-r--r--arch/s390/kernel/relocate_kernel64.S82
-rw-r--r--arch/s390/kernel/s390_ext.c9
-rw-r--r--arch/s390/kernel/s390_ksyms.c1
-rw-r--r--arch/s390/kernel/semaphore.c22
-rw-r--r--arch/s390/kernel/setup.c57
-rw-r--r--arch/s390/kernel/signal.c17
-rw-r--r--arch/s390/kernel/smp.c75
-rw-r--r--arch/s390/kernel/stacktrace.c17
-rw-r--r--arch/s390/kernel/sys_s390.c20
-rw-r--r--arch/s390/kernel/syscalls.S3
-rw-r--r--arch/s390/kernel/time.c125
-rw-r--r--arch/s390/kernel/traps.c15
-rw-r--r--arch/s390/kernel/vtime.c11
-rw-r--r--arch/s390/lib/Makefile1
-rw-r--r--arch/s390/lib/delay.c11
-rw-r--r--arch/s390/lib/div64.c151
-rw-r--r--arch/s390/lib/spinlock.c62
-rw-r--r--arch/s390/lib/uaccess_mvcos.c22
-rw-r--r--arch/s390/lib/uaccess_std.c36
-rw-r--r--arch/s390/math-emu/math.c126
-rw-r--r--arch/s390/math-emu/sfp-util.h73
-rw-r--r--arch/s390/mm/extmem.c16
-rw-r--r--arch/s390/mm/fault.c39
-rw-r--r--arch/s390/mm/init.c86
-rw-r--r--arch/sh/Kconfig177
-rw-r--r--arch/sh/Kconfig.debug36
-rw-r--r--arch/sh/Makefile40
-rw-r--r--arch/sh/boards/adx/Makefile6
-rw-r--r--arch/sh/boards/adx/irq.c31
-rw-r--r--arch/sh/boards/adx/setup.c56
-rw-r--r--arch/sh/boards/bigsur/io.c2
-rw-r--r--arch/sh/boards/bigsur/irq.c47
-rw-r--r--arch/sh/boards/bigsur/led.c2
-rw-r--r--arch/sh/boards/bigsur/setup.c47
-rw-r--r--arch/sh/boards/cat68701/Makefile6
-rw-r--r--arch/sh/boards/cat68701/irq.c28
-rw-r--r--arch/sh/boards/cat68701/setup.c85
-rw-r--r--arch/sh/boards/cqreek/Makefile6
-rw-r--r--arch/sh/boards/cqreek/irq.c128
-rw-r--r--arch/sh/boards/cqreek/setup.c100
-rw-r--r--arch/sh/boards/dmida/Makefile7
-rw-r--r--arch/sh/boards/dmida/mach.c59
-rw-r--r--arch/sh/boards/dreamcast/irq.c15
-rw-r--r--arch/sh/boards/dreamcast/rtc.c22
-rw-r--r--arch/sh/boards/dreamcast/setup.c40
-rw-r--r--arch/sh/boards/ec3104/io.c2
-rw-r--r--arch/sh/boards/ec3104/setup.c49
-rw-r--r--arch/sh/boards/harp/Makefile8
-rw-r--r--arch/sh/boards/harp/irq.c147
-rw-r--r--arch/sh/boards/harp/led.c51
-rw-r--r--arch/sh/boards/harp/mach.c62
-rw-r--r--arch/sh/boards/harp/pcidma.c42
-rw-r--r--arch/sh/boards/harp/setup.c90
-rw-r--r--arch/sh/boards/hp6xx/Makefile5
-rw-r--r--arch/sh/boards/hp6xx/hp6xx_apm.c122
-rw-r--r--arch/sh/boards/hp6xx/pm.c87
-rw-r--r--arch/sh/boards/hp6xx/pm_wakeup.S58
-rw-r--r--arch/sh/boards/hp6xx/setup.c64
-rw-r--r--arch/sh/boards/landisk/Makefile5
-rw-r--r--arch/sh/boards/landisk/io.c250
-rw-r--r--arch/sh/boards/landisk/irq.c97
-rw-r--r--arch/sh/boards/landisk/landisk_pwb.c346
-rw-r--r--arch/sh/boards/landisk/rtc.c91
-rw-r--r--arch/sh/boards/landisk/setup.c176
-rw-r--r--arch/sh/boards/mpc1211/led.c2
-rw-r--r--arch/sh/boards/mpc1211/rtc.c4
-rw-r--r--arch/sh/boards/mpc1211/setup.c78
-rw-r--r--arch/sh/boards/overdrive/Makefile8
-rw-r--r--arch/sh/boards/overdrive/fpga.c133
-rw-r--r--arch/sh/boards/overdrive/galileo.c587
-rw-r--r--arch/sh/boards/overdrive/io.c172
-rw-r--r--arch/sh/boards/overdrive/irq.c191
-rw-r--r--arch/sh/boards/overdrive/led.c58
-rw-r--r--arch/sh/boards/overdrive/mach.c62
-rw-r--r--arch/sh/boards/overdrive/pcidma.c46
-rw-r--r--arch/sh/boards/overdrive/setup.c36
-rw-r--r--arch/sh/boards/renesas/edosk7705/Makefile4
-rw-r--r--arch/sh/boards/renesas/edosk7705/setup.c29
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/Kconfig12
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/Makefile6
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/io.c254
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/irq.c6
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/led.c26
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/mach.c54
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/pci.c2
-rw-r--r--arch/sh/boards/renesas/hs7751rvoip/setup.c94
-rw-r--r--arch/sh/boards/renesas/r7780rp/Kconfig14
-rw-r--r--arch/sh/boards/renesas/r7780rp/Makefile6
-rw-r--r--arch/sh/boards/renesas/r7780rp/io.c301
-rw-r--r--arch/sh/boards/renesas/r7780rp/irq.c54
-rw-r--r--arch/sh/boards/renesas/r7780rp/led.c43
-rw-r--r--arch/sh/boards/renesas/r7780rp/setup.c163
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/Kconfig12
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/Makefile8
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/io.c191
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/irq.c6
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/led.c13
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/mach.c69
-rw-r--r--arch/sh/boards/renesas/rts7751r2d/setup.c139
-rw-r--r--arch/sh/boards/renesas/sh7710voipgw/Makefile1
-rw-r--r--arch/sh/boards/renesas/sh7710voipgw/setup.c109
-rw-r--r--arch/sh/boards/renesas/systemh/io.c165
-rw-r--r--arch/sh/boards/renesas/systemh/irq.c12
-rw-r--r--arch/sh/boards/renesas/systemh/setup.c32
-rw-r--r--arch/sh/boards/saturn/setup.c14
-rw-r--r--arch/sh/boards/se/7300/io.c8
-rw-r--r--arch/sh/boards/se/7300/irq.c2
-rw-r--r--arch/sh/boards/se/7300/led.c18
-rw-r--r--arch/sh/boards/se/7300/setup.c20
-rw-r--r--arch/sh/boards/se/73180/io.c6
-rw-r--r--arch/sh/boards/se/73180/irq.c9
-rw-r--r--arch/sh/boards/se/73180/led.c15
-rw-r--r--arch/sh/boards/se/73180/setup.c22
-rw-r--r--arch/sh/boards/se/7343/Makefile7
-rw-r--r--arch/sh/boards/se/7343/io.c273
-rw-r--r--arch/sh/boards/se/7343/irq.c191
-rw-r--r--arch/sh/boards/se/7343/led.c44
-rw-r--r--arch/sh/boards/se/7343/setup.c83
-rw-r--r--arch/sh/boards/se/770x/Makefile4
-rw-r--r--arch/sh/boards/se/770x/io.c61
-rw-r--r--arch/sh/boards/se/770x/irq.c2
-rw-r--r--arch/sh/boards/se/770x/led.c19
-rw-r--r--arch/sh/boards/se/770x/mach.c67
-rw-r--r--arch/sh/boards/se/770x/setup.c68
-rw-r--r--arch/sh/boards/se/7751/Makefile4
-rw-r--r--arch/sh/boards/se/7751/io.c171
-rw-r--r--arch/sh/boards/se/7751/irq.c2
-rw-r--r--arch/sh/boards/se/7751/led.c20
-rw-r--r--arch/sh/boards/se/7751/mach.c54
-rw-r--r--arch/sh/boards/se/7751/pci.c2
-rw-r--r--arch/sh/boards/se/7751/setup.c113
-rw-r--r--arch/sh/boards/sh03/rtc.c9
-rw-r--r--arch/sh/boards/sh03/setup.c50
-rw-r--r--arch/sh/boards/sh2000/Makefile6
-rw-r--r--arch/sh/boards/sh2000/setup.c70
-rw-r--r--arch/sh/boards/shmin/Makefile5
-rw-r--r--arch/sh/boards/shmin/setup.c41
-rw-r--r--arch/sh/boards/snapgear/io.c145
-rw-r--r--arch/sh/boards/snapgear/rtc.c34
-rw-r--r--arch/sh/boards/snapgear/setup.c117
-rw-r--r--arch/sh/boards/superh/microdev/io.c2
-rw-r--r--arch/sh/boards/superh/microdev/irq.c39
-rw-r--r--arch/sh/boards/superh/microdev/led.c2
-rw-r--r--arch/sh/boards/superh/microdev/setup.c113
-rw-r--r--arch/sh/boards/titan/Makefile5
-rw-r--r--arch/sh/boards/titan/io.c126
-rw-r--r--arch/sh/boards/titan/setup.c48
-rw-r--r--arch/sh/boards/unknown/setup.c13
-rw-r--r--arch/sh/boot/.gitignore1
-rw-r--r--arch/sh/boot/compressed/Makefile11
-rw-r--r--arch/sh/cchips/Kconfig6
-rw-r--r--arch/sh/cchips/hd6446x/hd64461/io.c20
-rw-r--r--arch/sh/cchips/hd6446x/hd64461/setup.c12
-rw-r--r--arch/sh/cchips/hd6446x/hd64465/gpio.c2
-rw-r--r--arch/sh/cchips/hd6446x/hd64465/setup.c8
-rw-r--r--arch/sh/cchips/voyagergx/irq.c22
-rw-r--r--arch/sh/cchips/voyagergx/setup.c2
-rw-r--r--arch/sh/configs/adx_defconfig539
-rw-r--r--arch/sh/configs/cqreek_defconfig533
-rw-r--r--arch/sh/configs/dreamcast_defconfig572
-rw-r--r--arch/sh/configs/hp6xx_defconfig201
-rw-r--r--arch/sh/configs/hs7751rvoip_defconfig (renamed from arch/mips/configs/ev96100_defconfig)610
-rw-r--r--arch/sh/configs/landisk_defconfig1450
-rw-r--r--arch/sh/configs/microdev_defconfig167
-rw-r--r--arch/sh/configs/r7780rp_defconfig1221
-rw-r--r--arch/sh/configs/rts7751r2d_defconfig568
-rw-r--r--arch/sh/configs/se7300_defconfig357
-rw-r--r--arch/sh/configs/se73180_defconfig348
-rw-r--r--arch/sh/configs/se7343_defconfig (renamed from arch/mips/configs/it8172_defconfig)712
-rw-r--r--arch/sh/configs/se7705_defconfig531
-rw-r--r--arch/sh/configs/se7750_defconfig532
-rw-r--r--arch/sh/configs/se7751_defconfig626
-rw-r--r--arch/sh/configs/sh03_defconfig568
-rw-r--r--arch/sh/configs/sh7710voipgw_defconfig955
-rw-r--r--arch/sh/configs/shmin_defconfig862
-rw-r--r--arch/sh/configs/snapgear_defconfig527
-rw-r--r--arch/sh/configs/systemh_defconfig370
-rw-r--r--arch/sh/configs/titan_defconfig1654
-rw-r--r--arch/sh/drivers/dma/Kconfig3
-rw-r--r--arch/sh/drivers/dma/dma-g2.c56
-rw-r--r--arch/sh/drivers/dma/dma-pvr2.c9
-rw-r--r--arch/sh/drivers/dma/dma-sh.c25
-rw-r--r--arch/sh/drivers/dma/dma-sysfs.c8
-rw-r--r--arch/sh/drivers/pci/Makefile6
-rw-r--r--arch/sh/drivers/pci/dma-dreamcast.c2
-rw-r--r--arch/sh/drivers/pci/fixups-dreamcast.c40
-rw-r--r--arch/sh/drivers/pci/fixups-r7780rp.c45
-rw-r--r--arch/sh/drivers/pci/fixups-rts7751r2d.c24
-rw-r--r--arch/sh/drivers/pci/fixups-sh03.c38
-rw-r--r--arch/sh/drivers/pci/ops-bigsur.c20
-rw-r--r--arch/sh/drivers/pci/ops-dreamcast.c2
-rw-r--r--arch/sh/drivers/pci/ops-landisk.c67
-rw-r--r--arch/sh/drivers/pci/ops-r7780rp.c73
-rw-r--r--arch/sh/drivers/pci/ops-rts7751r2d.c15
-rw-r--r--arch/sh/drivers/pci/ops-sh03.c4
-rw-r--r--arch/sh/drivers/pci/ops-sh4.c164
-rw-r--r--arch/sh/drivers/pci/ops-snapgear.c21
-rw-r--r--arch/sh/drivers/pci/ops-titan.c81
-rw-r--r--arch/sh/drivers/pci/pci-auto.c48
-rw-r--r--arch/sh/drivers/pci/pci-sh4.h180
-rw-r--r--arch/sh/drivers/pci/pci-sh7751.c326
-rw-r--r--arch/sh/drivers/pci/pci-sh7751.h174
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.c137
-rw-r--r--arch/sh/drivers/pci/pci-sh7780.h94
-rw-r--r--arch/sh/drivers/pci/pci-st40.c21
-rw-r--r--arch/sh/drivers/pci/pci.c105
-rw-r--r--arch/sh/kernel/Makefile5
-rw-r--r--arch/sh/kernel/apm.c538
-rw-r--r--arch/sh/kernel/cf-enabler.c12
-rw-r--r--arch/sh/kernel/cpu/Makefile1
-rw-r--r--arch/sh/kernel/cpu/clock.c19
-rw-r--r--arch/sh/kernel/cpu/init.c21
-rw-r--r--arch/sh/kernel/cpu/irq/Makefile5
-rw-r--r--arch/sh/kernel/cpu/irq/intc2.c144
-rw-r--r--arch/sh/kernel/cpu/irq/ipr.c110
-rw-r--r--arch/sh/kernel/cpu/irq/maskreg.c (renamed from arch/sh/boards/adx/irq_maskreg.c)61
-rw-r--r--arch/sh/kernel/cpu/irq/pint.c8
-rw-r--r--arch/sh/kernel/cpu/rtc.c128
-rw-r--r--arch/sh/kernel/cpu/sh3/Makefile13
-rw-r--r--arch/sh/kernel/cpu/sh3/clock-sh7706.c84
-rw-r--r--arch/sh/kernel/cpu/sh3/ex.S147
-rw-r--r--arch/sh/kernel/cpu/sh3/probe.c6
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7300.c43
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7705.c48
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7708.c43
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7709.c53
-rw-r--r--arch/sh/kernel/cpu/sh3/setup-sh7710.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/Makefile10
-rw-r--r--arch/sh/kernel/cpu/sh4/ex.S328
-rw-r--r--arch/sh/kernel/cpu/sh4/probe.c138
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh4-202.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh73180.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7343.c43
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7750.c48
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7760.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7770.c53
-rw-r--r--arch/sh/kernel/cpu/sh4/setup-sh7780.c79
-rw-r--r--arch/sh/kernel/cpu/sh4/sq.c543
-rw-r--r--arch/sh/kernel/cpu/ubc.S2
-rw-r--r--arch/sh/kernel/early_printk.c106
-rw-r--r--arch/sh/kernel/entry.S382
-rw-r--r--arch/sh/kernel/head.S43
-rw-r--r--arch/sh/kernel/io.c67
-rw-r--r--arch/sh/kernel/irq.c200
-rw-r--r--arch/sh/kernel/kgdb_stub.c33
-rw-r--r--arch/sh/kernel/machine_kexec.c6
-rw-r--r--arch/sh/kernel/pm.c88
-rw-r--r--arch/sh/kernel/process.c58
-rw-r--r--arch/sh/kernel/ptrace.c1
-rw-r--r--arch/sh/kernel/semaphore.c2
-rw-r--r--arch/sh/kernel/setup.c123
-rw-r--r--arch/sh/kernel/sh_ksyms.c33
-rw-r--r--arch/sh/kernel/signal.c158
-rw-r--r--arch/sh/kernel/smp.c1
-rw-r--r--arch/sh/kernel/sys_sh.c75
-rw-r--r--arch/sh/kernel/syscalls.S353
-rw-r--r--arch/sh/kernel/time.c89
-rw-r--r--arch/sh/kernel/timers/timer-tmu.c81
-rw-r--r--arch/sh/kernel/traps.c184
-rw-r--r--arch/sh/kernel/vmlinux.lds.S17
-rw-r--r--arch/sh/kernel/vsyscall/.gitignore1
-rw-r--r--arch/sh/kernel/vsyscall/Makefile36
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-note.S25
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-sigreturn.S39
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-syscall.S10
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall-trapa.S42
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall.c150
-rw-r--r--arch/sh/kernel/vsyscall/vsyscall.lds.S74
-rw-r--r--arch/sh/lib/checksum.S3
-rw-r--r--arch/sh/lib/memcpy-sh4.S4
-rw-r--r--arch/sh/lib/memset.S1
-rw-r--r--arch/sh/math-emu/Makefile1
-rw-r--r--arch/sh/math-emu/math.c623
-rw-r--r--arch/sh/math-emu/sfp-util.h72
-rw-r--r--arch/sh/mm/Kconfig78
-rw-r--r--arch/sh/mm/Makefile16
-rw-r--r--arch/sh/mm/cache-debugfs.c147
-rw-r--r--arch/sh/mm/cache-sh4.c685
-rw-r--r--arch/sh/mm/cache-sh7705.c19
-rw-r--r--arch/sh/mm/clear_page.S99
-rw-r--r--arch/sh/mm/consistent.c3
-rw-r--r--arch/sh/mm/fault.c211
-rw-r--r--arch/sh/mm/hugetlbpage.c52
-rw-r--r--arch/sh/mm/init.c32
-rw-r--r--arch/sh/mm/ioremap.c17
-rw-r--r--arch/sh/mm/pg-nommu.c17
-rw-r--r--arch/sh/mm/pg-sh4.c24
-rw-r--r--arch/sh/mm/pmb.c400
-rw-r--r--arch/sh/mm/tlb-flush.c134
-rw-r--r--arch/sh/mm/tlb-sh4.c8
-rw-r--r--arch/sh/oprofile/Makefile4
-rw-r--r--arch/sh/tools/gen-mach-types2
-rw-r--r--arch/sh/tools/mach-types10
-rw-r--r--arch/sh64/boot/compressed/misc.c2
-rw-r--r--arch/sh64/configs/cayman_defconfig456
-rw-r--r--arch/sh64/kernel/alphanum.c2
-rw-r--r--arch/sh64/kernel/process.c270
-rw-r--r--arch/sh64/kernel/sys_sh64.c21
-rw-r--r--arch/sh64/kernel/time.c14
-rw-r--r--arch/sh64/lib/c-checksum.c2
-rw-r--r--arch/sh64/mach-cayman/led.c2
-rw-r--r--arch/sh64/mm/fault.c6
-rw-r--r--arch/sh64/oprofile/op_model_null.c2
-rw-r--r--arch/sparc/Kconfig7
-rw-r--r--arch/sparc/Makefile2
-rw-r--r--arch/sparc/kernel/ioport.c1
-rw-r--r--arch/sparc/kernel/irq.c23
-rw-r--r--arch/sparc/kernel/of_device.c1
-rw-r--r--arch/sparc/kernel/pcic.c23
-rw-r--r--arch/sparc/kernel/prom.c7
-rw-r--r--arch/sparc/kernel/setup.c12
-rw-r--r--arch/sparc/kernel/sparc_ksyms.c4
-rw-r--r--arch/sparc/kernel/sun4c_irq.c2
-rw-r--r--arch/sparc/kernel/sun4d_irq.c12
-rw-r--r--arch/sparc/kernel/sun4d_smp.c6
-rw-r--r--arch/sparc/kernel/sun4m_irq.c2
-rw-r--r--arch/sparc/kernel/sun4m_smp.c7
-rw-r--r--arch/sparc/kernel/sys_solaris.c2
-rw-r--r--arch/sparc/kernel/sys_sparc.c27
-rw-r--r--arch/sparc/kernel/sys_sunos.c31
-rw-r--r--arch/sparc/kernel/tick14.c2
-rw-r--r--arch/sparc/kernel/time.c29
-rw-r--r--arch/sparc/kernel/vmlinux.lds.S4
-rw-r--r--arch/sparc/lib/copy_user.S4
-rw-r--r--arch/sparc/lib/locks.S20
-rw-r--r--arch/sparc/mm/srmmu.c2
-rw-r--r--arch/sparc/oprofile/Kconfig17
-rw-r--r--arch/sparc/oprofile/Makefile9
-rw-r--r--arch/sparc/oprofile/init.c23
-rw-r--r--arch/sparc64/Kconfig2
-rw-r--r--arch/sparc64/defconfig85
-rw-r--r--arch/sparc64/kernel/auxio.c1
-rw-r--r--arch/sparc64/kernel/ebus.c2
-rw-r--r--arch/sparc64/kernel/irq.c12
-rw-r--r--arch/sparc64/kernel/of_device.c10
-rw-r--r--arch/sparc64/kernel/pci_common.c29
-rw-r--r--arch/sparc64/kernel/pci_psycho.c6
-rw-r--r--arch/sparc64/kernel/pci_sabre.c29
-rw-r--r--arch/sparc64/kernel/pci_schizo.c8
-rw-r--r--arch/sparc64/kernel/power.c7
-rw-r--r--arch/sparc64/kernel/prom.c1
-rw-r--r--arch/sparc64/kernel/sbus.c6
-rw-r--r--arch/sparc64/kernel/setup.c12
-rw-r--r--arch/sparc64/kernel/signal32.c1
-rw-r--r--arch/sparc64/kernel/smp.c6
-rw-r--r--arch/sparc64/kernel/sys_sparc.c25
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c8
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c23
-rw-r--r--arch/sparc64/kernel/time.c13
-rw-r--r--arch/sparc64/mm/init.c3
-rw-r--r--arch/sparc64/solaris/fs.c7
-rw-r--r--arch/sparc64/solaris/misc.c9
-rw-r--r--arch/um/Kconfig43
-rw-r--r--arch/um/Kconfig.char5
-rw-r--r--arch/um/Kconfig.i38649
-rw-r--r--arch/um/Makefile2
-rw-r--r--arch/um/Makefile-x86_649
-rw-r--r--arch/um/drivers/chan_kern.c16
-rw-r--r--arch/um/drivers/cow_sys.h1
-rw-r--r--arch/um/drivers/daemon.h2
-rw-r--r--arch/um/drivers/daemon_kern.c2
-rw-r--r--arch/um/drivers/daemon_user.c3
-rw-r--r--arch/um/drivers/fd.c5
-rw-r--r--arch/um/drivers/hostaudio_kern.c5
-rw-r--r--arch/um/drivers/line.c21
-rw-r--r--arch/um/drivers/mcast.h2
-rw-r--r--arch/um/drivers/mcast_kern.c2
-rw-r--r--arch/um/drivers/mcast_user.c3
-rw-r--r--arch/um/drivers/mconsole_kern.c29
-rw-r--r--arch/um/drivers/mconsole_user.c4
-rw-r--r--arch/um/drivers/mmapper_kern.c3
-rw-r--r--arch/um/drivers/net_kern.c126
-rw-r--r--arch/um/drivers/net_user.c2
-rw-r--r--arch/um/drivers/null.c5
-rw-r--r--arch/um/drivers/pcap_kern.c2
-rw-r--r--arch/um/drivers/pcap_user.c3
-rw-r--r--arch/um/drivers/pcap_user.h2
-rw-r--r--arch/um/drivers/port_kern.c4
-rw-r--r--arch/um/drivers/port_user.c5
-rw-r--r--arch/um/drivers/pty.c7
-rw-r--r--arch/um/drivers/random.c6
-rw-r--r--arch/um/drivers/slip.h2
-rw-r--r--arch/um/drivers/slip_kern.c3
-rw-r--r--arch/um/drivers/slip_user.c3
-rw-r--r--arch/um/drivers/slirp.h2
-rw-r--r--arch/um/drivers/slirp_kern.c2
-rw-r--r--arch/um/drivers/slirp_user.c2
-rw-r--r--arch/um/drivers/ssl.c5
-rw-r--r--arch/um/drivers/stderr_console.c2
-rw-r--r--arch/um/drivers/stdio_console.c4
-rw-r--r--arch/um/drivers/tty.c5
-rw-r--r--arch/um/drivers/ubd_kern.c14
-rw-r--r--arch/um/drivers/xterm.c6
-rw-r--r--arch/um/drivers/xterm_kern.c2
-rw-r--r--arch/um/include/chan_kern.h6
-rw-r--r--arch/um/include/chan_user.h6
-rw-r--r--arch/um/include/common-offsets.h11
-rw-r--r--arch/um/include/irq_kern.h5
-rw-r--r--arch/um/include/kern_util.h3
-rw-r--r--arch/um/include/line.h11
-rw-r--r--arch/um/include/longjmp.h3
-rw-r--r--arch/um/include/mconsole_kern.h1
-rw-r--r--arch/um/include/mode_kern.h2
-rw-r--r--arch/um/include/net_kern.h18
-rw-r--r--arch/um/include/net_user.h18
-rw-r--r--arch/um/include/os.h14
-rw-r--r--arch/um/include/skas/mmu-skas.h1
-rw-r--r--arch/um/include/skas/skas.h3
-rw-r--r--arch/um/include/sysdep-i386/archsetjmp.h3
-rw-r--r--arch/um/include/sysdep-i386/kernel-offsets.h5
-rw-r--r--arch/um/include/sysdep-ppc/ptrace.h1
-rw-r--r--arch/um/include/sysdep-x86_64/archsetjmp.h3
-rw-r--r--arch/um/include/sysdep-x86_64/kernel-offsets.h5
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace.h43
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace_user.h2
-rw-r--r--arch/um/include/sysdep-x86_64/sc.h2
-rw-r--r--arch/um/include/um_malloc.h17
-rw-r--r--arch/um/include/um_uaccess.h1
-rw-r--r--arch/um/include/user.h6
-rw-r--r--arch/um/include/user_util.h1
-rw-r--r--arch/um/kernel/Makefile2
-rw-r--r--arch/um/kernel/exitcode.c8
-rw-r--r--arch/um/kernel/gmon_syms.c13
-rw-r--r--arch/um/kernel/init_task.c1
-rw-r--r--arch/um/kernel/irq.c17
-rw-r--r--arch/um/kernel/ksyms.c4
-rw-r--r--arch/um/kernel/mem.c3
-rw-r--r--arch/um/kernel/process.c (renamed from arch/um/kernel/process_kern.c)34
-rw-r--r--arch/um/kernel/sigio.c2
-rw-r--r--arch/um/kernel/signal.c1
-rw-r--r--arch/um/kernel/skas/Makefile3
-rw-r--r--arch/um/kernel/skas/exec.c30
-rw-r--r--arch/um/kernel/skas/exec_kern.c41
-rw-r--r--arch/um/kernel/skas/mem.c1
-rw-r--r--arch/um/kernel/skas/mmu.c4
-rw-r--r--arch/um/kernel/skas/process.c (renamed from arch/um/kernel/skas/process_kern.c)40
-rw-r--r--arch/um/kernel/skas/tlb.c1
-rw-r--r--arch/um/kernel/smp.c1
-rw-r--r--arch/um/kernel/syscall.c35
-rw-r--r--arch/um/kernel/sysrq.c1
-rw-r--r--arch/um/kernel/time.c6
-rw-r--r--arch/um/kernel/trap.c20
-rw-r--r--arch/um/kernel/tt/gdb_kern.c1
-rw-r--r--arch/um/kernel/tt/mem.c1
-rw-r--r--arch/um/kernel/tt/uaccess_user.c6
-rw-r--r--arch/um/kernel/um_arch.c9
-rw-r--r--arch/um/os-Linux/Makefile8
-rw-r--r--arch/um/os-Linux/drivers/etap.h2
-rw-r--r--arch/um/os-Linux/drivers/ethertap_kern.c2
-rw-r--r--arch/um/os-Linux/drivers/ethertap_user.c3
-rw-r--r--arch/um/os-Linux/drivers/tuntap.h2
-rw-r--r--arch/um/os-Linux/drivers/tuntap_kern.c2
-rw-r--r--arch/um/os-Linux/drivers/tuntap_user.c2
-rw-r--r--arch/um/os-Linux/helper.c54
-rw-r--r--arch/um/os-Linux/irq.c1
-rw-r--r--arch/um/os-Linux/main.c1
-rw-r--r--arch/um/os-Linux/mem.c6
-rw-r--r--arch/um/os-Linux/process.c5
-rw-r--r--arch/um/os-Linux/sigio.c1
-rw-r--r--arch/um/os-Linux/skas/process.c68
-rw-r--r--arch/um/os-Linux/sys-i386/tls.c5
-rw-r--r--arch/um/os-Linux/time.c3
-rw-r--r--arch/um/os-Linux/tls.c8
-rw-r--r--arch/um/os-Linux/tt.c1
-rw-r--r--arch/um/os-Linux/util.c9
-rw-r--r--arch/um/sys-i386/ldt.c1
-rw-r--r--arch/um/sys-i386/sysrq.c1
-rw-r--r--arch/um/sys-i386/tls.c1
-rw-r--r--arch/um/sys-i386/unmap.c11
-rw-r--r--arch/um/sys-x86_64/ksyms.c3
-rw-r--r--arch/um/sys-x86_64/stub_segv.c1
-rw-r--r--arch/um/sys-x86_64/syscalls.c2
-rw-r--r--arch/um/sys-x86_64/sysrq.c2
-rw-r--r--arch/um/sys-x86_64/unmap.c11
-rw-r--r--arch/v850/kernel/entry.S2
-rw-r--r--arch/v850/kernel/memcons.c4
-rw-r--r--arch/v850/kernel/rte_cb_leds.c2
-rw-r--r--arch/v850/kernel/rte_mb_a_pci.c12
-rw-r--r--arch/v850/kernel/simcons.c2
-rw-r--r--arch/v850/kernel/syscalls.c20
-rw-r--r--arch/v850/kernel/time.c3
-rw-r--r--arch/x86_64/Kconfig17
-rw-r--r--arch/x86_64/Makefile4
-rw-r--r--arch/x86_64/boot/video.S2
-rw-r--r--arch/x86_64/defconfig59
-rw-r--r--arch/x86_64/ia32/ia32_binfmt.c1
-rw-r--r--arch/x86_64/ia32/ptrace32.c4
-rw-r--r--arch/x86_64/ia32/sys_ia32.c47
-rw-r--r--arch/x86_64/kernel/apic.c67
-rw-r--r--arch/x86_64/kernel/e820.c139
-rw-r--r--arch/x86_64/kernel/early-quirks.c9
-rw-r--r--arch/x86_64/kernel/entry.S6
-rw-r--r--arch/x86_64/kernel/genapic_cluster.c8
-rw-r--r--arch/x86_64/kernel/genapic_flat.c26
-rw-r--r--arch/x86_64/kernel/i8259.c109
-rw-r--r--arch/x86_64/kernel/io_apic.c731
-rw-r--r--arch/x86_64/kernel/irq.c27
-rw-r--r--arch/x86_64/kernel/kprobes.c48
-rw-r--r--arch/x86_64/kernel/mpparse.c79
-rw-r--r--arch/x86_64/kernel/nmi.c4
-rw-r--r--arch/x86_64/kernel/pci-calgary.c37
-rw-r--r--arch/x86_64/kernel/pci-dma.c93
-rw-r--r--arch/x86_64/kernel/pci-swiotlb.c3
-rw-r--r--arch/x86_64/kernel/process.c35
-rw-r--r--arch/x86_64/kernel/setup.c18
-rw-r--r--arch/x86_64/kernel/sys_x86_64.c2
-rw-r--r--arch/x86_64/kernel/tce.c1
-rw-r--r--arch/x86_64/kernel/time.c40
-rw-r--r--arch/x86_64/kernel/traps.c2
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S20
-rw-r--r--arch/x86_64/kernel/vsmp.c1
-rw-r--r--arch/x86_64/kernel/vsyscall.c11
-rw-r--r--arch/x86_64/kernel/x8664_ksyms.c1
-rw-r--r--arch/x86_64/lib/copy_page.S3
-rw-r--r--arch/x86_64/lib/delay.c1
-rw-r--r--arch/x86_64/lib/memcpy.S3
-rw-r--r--arch/x86_64/lib/memset.S1
-rw-r--r--arch/x86_64/lib/thunk.S1
-rw-r--r--arch/x86_64/mm/fault.c6
-rw-r--r--arch/x86_64/mm/init.c108
-rw-r--r--arch/x86_64/mm/ioremap.c111
-rw-r--r--arch/x86_64/mm/k8topology.c3
-rw-r--r--arch/x86_64/mm/numa.c23
-rw-r--r--arch/x86_64/mm/srat.c83
-rw-r--r--arch/x86_64/pci/Makefile2
-rw-r--r--arch/xtensa/Kconfig4
-rw-r--r--arch/xtensa/kernel/module.c2
-rw-r--r--arch/xtensa/kernel/pci-dma.c2
-rw-r--r--arch/xtensa/kernel/pci.c2
-rw-r--r--arch/xtensa/kernel/setup.c2
-rw-r--r--arch/xtensa/kernel/syscalls.c24
-rw-r--r--arch/xtensa/kernel/time.c15
-rw-r--r--arch/xtensa/lib/pci-auto.c2
-rw-r--r--arch/xtensa/lib/usercopy.S4
-rw-r--r--arch/xtensa/mm/fault.c2
-rw-r--r--arch/xtensa/mm/pgtable.c2
-rw-r--r--arch/xtensa/mm/tlb.c2
-rw-r--r--arch/xtensa/platform-iss/console.c2
-rw-r--r--arch/xtensa/platform-iss/network.c2
-rw-r--r--block/Kconfig20
-rw-r--r--block/Kconfig.iosched3
-rw-r--r--block/Makefile2
-rw-r--r--block/as-iosched.c674
-rw-r--r--block/blktrace.c34
-rw-r--r--block/cfq-iosched.c867
-rw-r--r--block/deadline-iosched.c464
-rw-r--r--block/elevator.c332
-rw-r--r--block/genhd.c9
-rw-r--r--block/ioctl.c5
-rw-r--r--block/ll_rw_blk.c329
-rw-r--r--block/noop-iosched.c2
-rw-r--r--block/scsi_ioctl.c6
-rw-r--r--crypto/Kconfig4
-rw-r--r--crypto/api.c15
-rw-r--r--crypto/serpent.c16
-rw-r--r--drivers/Kconfig6
-rw-r--r--drivers/acorn/block/mfmhd.c4
-rw-r--r--drivers/acorn/char/i2c.c1
-rw-r--r--drivers/acpi/Kconfig6
-rw-r--r--drivers/acpi/acpi_memhotplug.c18
-rw-r--r--drivers/acpi/asus_acpi.c67
-rw-r--r--drivers/acpi/battery.c14
-rw-r--r--drivers/acpi/cm_sbs.c4
-rw-r--r--drivers/acpi/ec.c1096
-rw-r--r--drivers/acpi/events/evmisc.c14
-rw-r--r--drivers/acpi/events/evrgnini.c13
-rw-r--r--drivers/acpi/hardware/hwregs.c2
-rw-r--r--drivers/acpi/i2c_ec.c2
-rw-r--r--drivers/acpi/ibm_acpi.c2
-rw-r--r--drivers/acpi/motherboard.c6
-rw-r--r--drivers/acpi/osl.c38
-rw-r--r--drivers/acpi/pci_link.c2
-rw-r--r--drivers/acpi/power.c9
-rw-r--r--drivers/acpi/processor_core.c2
-rw-r--r--drivers/acpi/processor_idle.c149
-rw-r--r--drivers/acpi/sbs.c20
-rw-r--r--drivers/acpi/tables/tbget.c2
-rw-r--r--drivers/acpi/tables/tbrsdt.c2
-rw-r--r--drivers/ata/Kconfig3
-rw-r--r--drivers/ata/ahci.c94
-rw-r--r--drivers/ata/ata_generic.c2
-rw-r--r--drivers/ata/ata_piix.c8
-rw-r--r--drivers/ata/libata-core.c26
-rw-r--r--drivers/ata/libata-eh.c6
-rw-r--r--drivers/ata/libata-scsi.c60
-rw-r--r--drivers/ata/libata-sff.c50
-rw-r--r--drivers/ata/pata_ali.c21
-rw-r--r--drivers/ata/pata_amd.c75
-rw-r--r--drivers/ata/pata_artop.c39
-rw-r--r--drivers/ata/pata_atiixp.c26
-rw-r--r--drivers/ata/pata_cmd64x.c23
-rw-r--r--drivers/ata/pata_cs5520.c12
-rw-r--r--drivers/ata/pata_cs5530.c13
-rw-r--r--drivers/ata/pata_cs5535.c11
-rw-r--r--drivers/ata/pata_cypress.c15
-rw-r--r--drivers/ata/pata_efar.c16
-rw-r--r--drivers/ata/pata_hpt366.c13
-rw-r--r--drivers/ata/pata_hpt37x.c27
-rw-r--r--drivers/ata/pata_hpt3x2n.c19
-rw-r--r--drivers/ata/pata_hpt3x3.c11
-rw-r--r--drivers/ata/pata_isapnp.c2
-rw-r--r--drivers/ata/pata_it821x.c17
-rw-r--r--drivers/ata/pata_jmicron.c16
-rw-r--r--drivers/ata/pata_legacy.c14
-rw-r--r--drivers/ata/pata_mpiix.c20
-rw-r--r--drivers/ata/pata_netcell.c6
-rw-r--r--drivers/ata/pata_ns87410.c18
-rw-r--r--drivers/ata/pata_oldpiix.c13
-rw-r--r--drivers/ata/pata_opti.c22
-rw-r--r--drivers/ata/pata_optidma.c23
-rw-r--r--drivers/ata/pata_pcmcia.c6
-rw-r--r--drivers/ata/pata_pdc2027x.c23
-rw-r--r--drivers/ata/pata_pdc202xx_old.c19
-rw-r--r--drivers/ata/pata_qdi.c6
-rw-r--r--drivers/ata/pata_radisys.c6
-rw-r--r--drivers/ata/pata_rz1000.c14
-rw-r--r--drivers/ata/pata_sc1200.c13
-rw-r--r--drivers/ata/pata_serverworks.c29
-rw-r--r--drivers/ata/pata_sil680.c11
-rw-r--r--drivers/ata/pata_sis.c26
-rw-r--r--drivers/ata/pata_sl82c105.c20
-rw-r--r--drivers/ata/pata_triflex.c25
-rw-r--r--drivers/ata/pata_via.c28
-rw-r--r--drivers/ata/pdc_adma.c8
-rw-r--r--drivers/ata/sata_mv.c34
-rw-r--r--drivers/ata/sata_nv.c71
-rw-r--r--drivers/ata/sata_promise.c62
-rw-r--r--drivers/ata/sata_qstor.c7
-rw-r--r--drivers/ata/sata_sil.c23
-rw-r--r--drivers/ata/sata_sil24.c15
-rw-r--r--drivers/ata/sata_sis.c8
-rw-r--r--drivers/ata/sata_svw.c19
-rw-r--r--drivers/ata/sata_sx4.c9
-rw-r--r--drivers/ata/sata_uli.c8
-rw-r--r--drivers/ata/sata_via.c6
-rw-r--r--drivers/ata/sata_vsc.c9
-rw-r--r--drivers/atm/adummy.c6
-rw-r--r--drivers/atm/ambassador.c15
-rw-r--r--drivers/atm/eni.c2
-rw-r--r--drivers/atm/firestream.c14
-rw-r--r--drivers/atm/fore200e.c2
-rw-r--r--drivers/atm/he.c8
-rw-r--r--drivers/atm/horizon.c17
-rw-r--r--drivers/atm/idt77252.c25
-rw-r--r--drivers/atm/iphase.c2
-rw-r--r--drivers/atm/lanai.c14
-rw-r--r--drivers/atm/nicstar.c4
-rw-r--r--drivers/atm/zatm.c9
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/bus.c108
-rw-r--r--drivers/base/class.c13
-rw-r--r--drivers/base/core.c26
-rw-r--r--drivers/base/dd.c4
-rw-r--r--drivers/base/dmapool.c13
-rw-r--r--drivers/base/firmware_class.c14
-rw-r--r--drivers/base/topology.c3
-rw-r--r--drivers/block/DAC960.c42
-rw-r--r--drivers/block/DAC960.h20
-rw-r--r--drivers/block/Kconfig9
-rw-r--r--drivers/block/acsi.c4
-rw-r--r--drivers/block/acsi_slm.c4
-rw-r--r--drivers/block/amiflop.c17
-rw-r--r--drivers/block/aoe/aoe.h30
-rw-r--r--drivers/block/aoe/aoeblk.c44
-rw-r--r--drivers/block/aoe/aoechr.c18
-rw-r--r--drivers/block/aoe/aoecmd.c303
-rw-r--r--drivers/block/aoe/aoedev.c52
-rw-r--r--drivers/block/aoe/aoemain.c10
-rw-r--r--drivers/block/aoe/aoenet.c9
-rw-r--r--drivers/block/ataflop.c4
-rw-r--r--drivers/block/cciss.c255
-rw-r--r--drivers/block/cciss.h3
-rw-r--r--drivers/block/cciss_cmd.h33
-rw-r--r--drivers/block/cciss_scsi.c2
-rw-r--r--drivers/block/cpqarray.c6
-rw-r--r--drivers/block/floppy.c8
-rw-r--r--drivers/block/loop.c253
-rw-r--r--drivers/block/nbd.c8
-rw-r--r--drivers/block/paride/pd.c8
-rw-r--r--drivers/block/pktcdvd.c142
-rw-r--r--drivers/block/ps2esdi.c6
-rw-r--r--drivers/block/rd.c12
-rw-r--r--drivers/block/swim3.c16
-rw-r--r--drivers/block/swim_iop.c8
-rw-r--r--drivers/block/sx8.c2
-rw-r--r--drivers/block/ub.c44
-rw-r--r--drivers/block/umem.c5
-rw-r--r--drivers/block/xd.c7
-rw-r--r--drivers/block/xd.h3
-rw-r--r--drivers/block/z2ram.c28
-rw-r--r--drivers/bluetooth/bcm203x.c19
-rw-r--r--drivers/bluetooth/bfusb.c324
-rw-r--r--drivers/bluetooth/bluecard_cs.c2
-rw-r--r--drivers/bluetooth/bpa10x.c2
-rw-r--r--drivers/bluetooth/bt3c_cs.c2
-rw-r--r--drivers/bluetooth/btuart_cs.c2
-rw-r--r--drivers/bluetooth/dtl1_cs.c3
-rw-r--r--drivers/bluetooth/hci_ldisc.c13
-rw-r--r--drivers/bluetooth/hci_usb.c14
-rw-r--r--drivers/bluetooth/hci_vhci.c99
-rw-r--r--drivers/cdrom/Kconfig2
-rw-r--r--drivers/cdrom/cdrom.c10
-rw-r--r--drivers/cdrom/cdu31a.c6
-rw-r--r--drivers/cdrom/cm206.c2
-rw-r--r--drivers/cdrom/mcdx.c6
-rw-r--r--drivers/cdrom/sonycd535.c2
-rw-r--r--drivers/char/.gitignore1
-rw-r--r--drivers/char/Kconfig51
-rw-r--r--drivers/char/Makefile8
-rw-r--r--drivers/char/agp/Kconfig10
-rw-r--r--drivers/char/agp/Makefile1
-rw-r--r--drivers/char/agp/parisc-agp.c416
-rw-r--r--drivers/char/amiserial.c38
-rw-r--r--drivers/char/applicom.c4
-rw-r--r--drivers/char/briq_panel.c1
-rw-r--r--drivers/char/cyclades.c34
-rw-r--r--drivers/char/drm/Kconfig9
-rw-r--r--drivers/char/drm/Makefile6
-rw-r--r--drivers/char/drm/drmP.h68
-rw-r--r--drivers/char/drm/drm_auth.c64
-rw-r--r--drivers/char/drm/drm_bufs.c74
-rw-r--r--drivers/char/drm/drm_drv.c12
-rw-r--r--drivers/char/drm/drm_fops.c10
-rw-r--r--drivers/char/drm/drm_hashtab.c190
-rw-r--r--drivers/char/drm/drm_hashtab.h67
-rw-r--r--drivers/char/drm/drm_ioc32.c2
-rw-r--r--drivers/char/drm/drm_ioctl.c34
-rw-r--r--drivers/char/drm/drm_irq.c12
-rw-r--r--drivers/char/drm/drm_mm.c201
-rw-r--r--drivers/char/drm/drm_os_linux.h2
-rw-r--r--drivers/char/drm/drm_pciids.h187
-rw-r--r--drivers/char/drm/drm_proc.c2
-rw-r--r--drivers/char/drm/drm_sman.c352
-rw-r--r--drivers/char/drm/drm_sman.h176
-rw-r--r--drivers/char/drm/drm_stub.c12
-rw-r--r--drivers/char/drm/drm_vm.c45
-rw-r--r--drivers/char/drm/i810_dma.c10
-rw-r--r--drivers/char/drm/i830_dma.c4
-rw-r--r--drivers/char/drm/i915_dma.c45
-rw-r--r--drivers/char/drm/i915_drm.h6
-rw-r--r--drivers/char/drm/i915_drv.h10
-rw-r--r--drivers/char/drm/i915_irq.c16
-rw-r--r--drivers/char/drm/radeon_cp.c72
-rw-r--r--drivers/char/drm/radeon_drv.c2
-rw-r--r--drivers/char/drm/radeon_drv.h36
-rw-r--r--drivers/char/drm/radeon_state.c48
-rw-r--r--drivers/char/drm/sis_drv.c39
-rw-r--r--drivers/char/drm/sis_drv.h34
-rw-r--r--drivers/char/drm/sis_ds.c299
-rw-r--r--drivers/char/drm/sis_ds.h146
-rw-r--r--drivers/char/drm/sis_mm.c504
-rw-r--r--drivers/char/drm/via_dmablit.c68
-rw-r--r--drivers/char/drm/via_drm.h8
-rw-r--r--drivers/char/drm/via_drv.c3
-rw-r--r--drivers/char/drm/via_drv.h16
-rw-r--r--drivers/char/drm/via_ds.c273
-rw-r--r--drivers/char/drm/via_ds.h104
-rw-r--r--drivers/char/drm/via_map.c9
-rw-r--r--drivers/char/drm/via_mm.c375
-rw-r--r--drivers/char/ds1286.c15
-rw-r--r--drivers/char/ec3104_keyb.c2
-rw-r--r--drivers/char/epca.c51
-rw-r--r--drivers/char/epca.h1
-rw-r--r--drivers/char/esp.c5
-rw-r--r--drivers/char/ftape/lowlevel/fdc-io.c3
-rw-r--r--drivers/char/ftape/zftape/zftape-rw.c1
-rw-r--r--drivers/char/ftape/zftape/zftape-rw.h1
-rw-r--r--drivers/char/generic_serial.c30
-rw-r--r--drivers/char/hangcheck-timer.c2
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/hvc_console.c6
-rw-r--r--drivers/char/hvc_iseries.c15
-rw-r--r--drivers/char/hvc_vio.c4
-rw-r--r--drivers/char/hvcs.c8
-rw-r--r--drivers/char/hvsi.c8
-rw-r--r--drivers/char/hw_random/intel-rng.c186
-rw-r--r--drivers/char/hw_random/ixp4xx-rng.c3
-rw-r--r--drivers/char/hw_random/omap-rng.c2
-rw-r--r--drivers/char/ip2/i2lib.c11
-rw-r--r--drivers/char/ip2/i2lib.h2
-rw-r--r--drivers/char/ip2/ip2main.c27
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c34
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c197
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c36
-rw-r--r--drivers/char/ipmi/ipmi_watchdog.c2
-rw-r--r--drivers/char/isicom.c39
-rw-r--r--drivers/char/istallion.c80
-rw-r--r--drivers/char/ite_gpio.c419
-rw-r--r--drivers/char/keyboard.c160
-rw-r--r--drivers/char/lp.c4
-rw-r--r--drivers/char/mbcs.c10
-rw-r--r--drivers/char/mem.c52
-rw-r--r--drivers/char/mmtimer.c3
-rw-r--r--drivers/char/moxa.c91
-rw-r--r--drivers/char/mspec.c420
-rw-r--r--drivers/char/mwave/README5
-rw-r--r--drivers/char/mwave/mwavedd.c4
-rw-r--r--drivers/char/mwave/tp3780i.c4
-rw-r--r--drivers/char/mxser.c72
-rw-r--r--drivers/char/nsc_gpio.c1
-rw-r--r--drivers/char/nwbutton.c7
-rw-r--r--drivers/char/nwbutton.h2
-rw-r--r--drivers/char/pc8736x_gpio.c10
-rw-r--r--drivers/char/pcmcia/synclink_cs.c9
-rw-r--r--drivers/char/ppdev.c2
-rw-r--r--drivers/char/pty.c2
-rw-r--r--drivers/char/qtronix.c605
-rw-r--r--drivers/char/qtronixmap.c_shipped265
-rw-r--r--drivers/char/qtronixmap.map287
-rw-r--r--drivers/char/random.c9
-rw-r--r--drivers/char/raw.c50
-rw-r--r--drivers/char/rio/func.h2
-rw-r--r--drivers/char/rio/host.h1
-rw-r--r--drivers/char/rio/rio_linux.c19
-rw-r--r--drivers/char/rio/rioctrl.c4
-rw-r--r--drivers/char/rio/riointr.c2
-rw-r--r--drivers/char/riscom8.c43
-rw-r--r--drivers/char/rocket.c2
-rw-r--r--drivers/char/rtc.c16
-rw-r--r--drivers/char/s3c2410-rtc.c591
-rw-r--r--drivers/char/scx200_gpio.c4
-rw-r--r--drivers/char/selection.c2
-rw-r--r--drivers/char/ser_a2232.c6
-rw-r--r--drivers/char/serial167.c102
-rw-r--r--drivers/char/snsc.c2
-rw-r--r--drivers/char/snsc_event.c4
-rw-r--r--drivers/char/sonypi.c2
-rw-r--r--drivers/char/specialix.c50
-rw-r--r--drivers/char/stallion.c7
-rw-r--r--drivers/char/sx.c10
-rw-r--r--drivers/char/synclink.c11
-rw-r--r--drivers/char/synclink_gt.c101
-rw-r--r--drivers/char/synclinkmp.c5
-rw-r--r--drivers/char/sysrq.c66
-rw-r--r--drivers/char/tipar.c6
-rw-r--r--drivers/char/tlclk.c4
-rw-r--r--drivers/char/tpm/tpm.c9
-rw-r--r--drivers/char/tpm/tpm_atmel.c10
-rw-r--r--drivers/char/tpm/tpm_nsc.c6
-rw-r--r--drivers/char/tpm/tpm_tis.c4
-rw-r--r--drivers/char/tty_io.c107
-rw-r--r--drivers/char/tty_ioctl.c35
-rw-r--r--drivers/char/vc_screen.c5
-rw-r--r--drivers/char/viocons.c4
-rw-r--r--drivers/char/vme_scc.c22
-rw-r--r--drivers/char/vr41xx_giu.c2
-rw-r--r--drivers/char/vt.c146
-rw-r--r--drivers/char/vt_ioctl.c34
-rw-r--r--drivers/char/watchdog/Kconfig47
-rw-r--r--drivers/char/watchdog/Makefile3
-rw-r--r--drivers/char/watchdog/acquirewdt.c2
-rw-r--r--drivers/char/watchdog/advantechwdt.c2
-rw-r--r--drivers/char/watchdog/alim1535_wdt.c12
-rw-r--r--drivers/char/watchdog/alim7101_wdt.c30
-rw-r--r--drivers/char/watchdog/at91_wdt.c2
-rw-r--r--drivers/char/watchdog/booke_wdt.c2
-rw-r--r--drivers/char/watchdog/cpu5wdt.c2
-rw-r--r--drivers/char/watchdog/ep93xx_wdt.c2
-rw-r--r--drivers/char/watchdog/eurotechwdt.c4
-rw-r--r--drivers/char/watchdog/i6300esb.c2
-rw-r--r--drivers/char/watchdog/i8xx_tco.c35
-rw-r--r--drivers/char/watchdog/iTCO_wdt.c734
-rw-r--r--drivers/char/watchdog/ib700wdt.c2
-rw-r--r--drivers/char/watchdog/ibmasr.c2
-rw-r--r--drivers/char/watchdog/indydog.c2
-rw-r--r--drivers/char/watchdog/ixp2000_wdt.c4
-rw-r--r--drivers/char/watchdog/ixp4xx_wdt.c4
-rw-r--r--drivers/char/watchdog/machzwd.c5
-rw-r--r--drivers/char/watchdog/mixcomwd.c2
-rw-r--r--drivers/char/watchdog/mpc83xx_wdt.c2
-rw-r--r--drivers/char/watchdog/mpc8xx_wdt.c2
-rw-r--r--drivers/char/watchdog/mpcore_wdt.c6
-rw-r--r--drivers/char/watchdog/mv64x60_wdt.c2
-rw-r--r--drivers/char/watchdog/omap_wdt.c390
-rw-r--r--drivers/char/watchdog/omap_wdt.h64
-rw-r--r--drivers/char/watchdog/pcwd.c3
-rw-r--r--drivers/char/watchdog/pcwd_pci.c3
-rw-r--r--drivers/char/watchdog/pcwd_usb.c4
-rw-r--r--drivers/char/watchdog/pnx4008_wdt.c361
-rw-r--r--drivers/char/watchdog/s3c2410_wdt.c15
-rw-r--r--drivers/char/watchdog/sa1100_wdt.c2
-rw-r--r--drivers/char/watchdog/sbc60xxwdt.c2
-rw-r--r--drivers/char/watchdog/sbc_epx_c3.c2
-rw-r--r--drivers/char/watchdog/sc1200wdt.c2
-rw-r--r--drivers/char/watchdog/sc520_wdt.c2
-rw-r--r--drivers/char/watchdog/scx200_wdt.c2
-rw-r--r--drivers/char/watchdog/shwdt.c112
-rw-r--r--drivers/char/watchdog/softdog.c2
-rw-r--r--drivers/char/watchdog/w83627hf_wdt.c2
-rw-r--r--drivers/char/watchdog/w83877f_wdt.c2
-rw-r--r--drivers/char/watchdog/w83977f_wdt.c2
-rw-r--r--drivers/char/watchdog/wafer5823wdt.c2
-rw-r--r--drivers/char/watchdog/wdrtas.c2
-rw-r--r--drivers/char/watchdog/wdt.c5
-rw-r--r--drivers/char/watchdog/wdt285.c4
-rw-r--r--drivers/char/watchdog/wdt977.c2
-rw-r--r--drivers/char/watchdog/wdt_pci.c5
-rw-r--r--drivers/clocksource/acpi_pm.c6
-rw-r--r--drivers/clocksource/scx200_hrt.c4
-rw-r--r--drivers/cpufreq/cpufreq.c22
-rw-r--r--drivers/dma/ioatdma.c6
-rw-r--r--drivers/dma/ioatdma.h4
-rw-r--r--drivers/eisa/eisa-bus.c43
-rw-r--r--drivers/fc4/fc.c1
-rw-r--r--drivers/fc4/soc.c2
-rw-r--r--drivers/fc4/socal.c2
-rw-r--r--drivers/firmware/Kconfig2
-rw-r--r--drivers/firmware/dcdbas.c9
-rw-r--r--drivers/firmware/dell_rbu.c25
-rw-r--r--drivers/firmware/dmi_scan.c43
-rw-r--r--drivers/firmware/edd.c2
-rw-r--r--drivers/firmware/efivars.c7
-rw-r--r--drivers/hwmon/Kconfig57
-rw-r--r--drivers/hwmon/Makefile2
-rw-r--r--drivers/hwmon/abituguru.c30
-rw-r--r--drivers/hwmon/adm1021.c31
-rw-r--r--drivers/hwmon/adm1025.c94
-rw-r--r--drivers/hwmon/adm1026.c286
-rw-r--r--drivers/hwmon/adm1031.c114
-rw-r--r--drivers/hwmon/adm9240.c109
-rw-r--r--drivers/hwmon/asb100.c122
-rw-r--r--drivers/hwmon/atxp1.c28
-rw-r--r--drivers/hwmon/ds1621.c28
-rw-r--r--drivers/hwmon/f71805f.c336
-rw-r--r--drivers/hwmon/fscher.c106
-rw-r--r--drivers/hwmon/fscpos.c75
-rw-r--r--drivers/hwmon/gl518sm.c74
-rw-r--r--drivers/hwmon/gl520sm.c128
-rw-r--r--drivers/hwmon/hdaps.c7
-rw-r--r--drivers/hwmon/it87.c470
-rw-r--r--drivers/hwmon/k8temp.c294
-rw-r--r--drivers/hwmon/lm63.c96
-rw-r--r--drivers/hwmon/lm75.c24
-rw-r--r--drivers/hwmon/lm77.c33
-rw-r--r--drivers/hwmon/lm78.c101
-rw-r--r--drivers/hwmon/lm80.c85
-rw-r--r--drivers/hwmon/lm83.c128
-rw-r--r--drivers/hwmon/lm85.c173
-rw-r--r--drivers/hwmon/lm87.c191
-rw-r--r--drivers/hwmon/lm90.c90
-rw-r--r--drivers/hwmon/lm92.c34
-rw-r--r--drivers/hwmon/max1619.c33
-rw-r--r--drivers/hwmon/pc87360.c231
-rw-r--r--drivers/hwmon/sis5595.c102
-rw-r--r--drivers/hwmon/smsc47b397.c40
-rw-r--r--drivers/hwmon/smsc47m1.c93
-rw-r--r--drivers/hwmon/smsc47m192.c150
-rw-r--r--drivers/hwmon/via686a.c84
-rw-r--r--drivers/hwmon/vt1211.c1355
-rw-r--r--drivers/hwmon/vt8231.c187
-rw-r--r--drivers/hwmon/w83627ehf.c495
-rw-r--r--drivers/hwmon/w83627hf.c233
-rw-r--r--drivers/hwmon/w83781d.c298
-rw-r--r--drivers/hwmon/w83791d.c93
-rw-r--r--drivers/hwmon/w83792d.c554
-rw-r--r--drivers/hwmon/w83l785ts.c28
-rw-r--r--drivers/i2c/Kconfig2
-rw-r--r--drivers/i2c/algos/Kconfig6
-rw-r--r--drivers/i2c/algos/Makefile1
-rw-r--r--drivers/i2c/algos/i2c-algo-bit.c23
-rw-r--r--drivers/i2c/algos/i2c-algo-pca.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-pcf.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-sgi.c2
-rw-r--r--drivers/i2c/algos/i2c-algo-sibyte.c215
-rw-r--r--drivers/i2c/busses/Kconfig40
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-ali1535.c2
-rw-r--r--drivers/i2c/busses/i2c-ali1563.c2
-rw-r--r--drivers/i2c/busses/i2c-ali15x3.c2
-rw-r--r--drivers/i2c/busses/i2c-amd756.c2
-rw-r--r--drivers/i2c/busses/i2c-amd8111.c2
-rw-r--r--drivers/i2c/busses/i2c-au1550.c21
-rw-r--r--drivers/i2c/busses/i2c-elektor.c3
-rw-r--r--drivers/i2c/busses/i2c-hydra.c1
-rw-r--r--drivers/i2c/busses/i2c-i801.c2
-rw-r--r--drivers/i2c/busses/i2c-i810.c2
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.c6
-rw-r--r--drivers/i2c/busses/i2c-ibm_iic.h2
-rw-r--r--drivers/i2c/busses/i2c-iop3xx.c20
-rw-r--r--drivers/i2c/busses/i2c-isa.c42
-rw-r--r--drivers/i2c/busses/i2c-ite.c5
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c1
-rw-r--r--drivers/i2c/busses/i2c-ixp4xx.c3
-rw-r--r--drivers/i2c/busses/i2c-mpc.c4
-rw-r--r--drivers/i2c/busses/i2c-mv64xxx.c4
-rw-r--r--drivers/i2c/busses/i2c-nforce2.c2
-rw-r--r--drivers/i2c/busses/i2c-ocores.c5
-rw-r--r--drivers/i2c/busses/i2c-omap.c676
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c1
-rw-r--r--drivers/i2c/busses/i2c-parport.c1
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c2
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-powermac.c30
-rw-r--r--drivers/i2c/busses/i2c-prosavage.c1
-rw-r--r--drivers/i2c/busses/i2c-pxa.c4
-rw-r--r--drivers/i2c/busses/i2c-rpx.c4
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c5
-rw-r--r--drivers/i2c/busses/i2c-savage4.c1
-rw-r--r--drivers/i2c/busses/i2c-sibyte.c160
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/busses/i2c-sis630.c2
-rw-r--r--drivers/i2c/busses/i2c-sis96x.c2
-rw-r--r--drivers/i2c/busses/i2c-stub.c21
-rw-r--r--drivers/i2c/busses/i2c-via.c1
-rw-r--r--drivers/i2c/busses/i2c-viapro.c10
-rw-r--r--drivers/i2c/busses/i2c-voodoo3.c2
-rw-r--r--drivers/i2c/busses/scx200_acb.c2
-rw-r--r--drivers/i2c/busses/scx200_i2c.c14
-rw-r--r--drivers/i2c/chips/eeprom.c8
-rw-r--r--drivers/i2c/chips/isp1301_omap.c6
-rw-r--r--drivers/i2c/chips/max6875.c25
-rw-r--r--drivers/i2c/chips/pca9539.c11
-rw-r--r--drivers/i2c/chips/pcf8574.c22
-rw-r--r--drivers/i2c/chips/pcf8591.c58
-rw-r--r--drivers/i2c/chips/tps65010.c4
-rw-r--r--drivers/i2c/i2c-core.c87
-rw-r--r--drivers/i2c/i2c-dev.c109
-rw-r--r--drivers/ide/Kconfig21
-rw-r--r--drivers/ide/h8300/ide-h8300.c2
-rw-r--r--drivers/ide/ide-cd.c70
-rw-r--r--drivers/ide/ide-disk.c5
-rw-r--r--drivers/ide/ide-dma.c64
-rw-r--r--drivers/ide/ide-floppy.c17
-rw-r--r--drivers/ide/ide-io.c84
-rw-r--r--drivers/ide/ide-iops.c4
-rw-r--r--drivers/ide/ide-lib.c130
-rw-r--r--drivers/ide/ide-probe.c25
-rw-r--r--drivers/ide/ide-proc.c22
-rw-r--r--drivers/ide/ide-tape.c16
-rw-r--r--drivers/ide/ide-taskfile.c21
-rw-r--r--drivers/ide/ide.c35
-rw-r--r--drivers/ide/legacy/hd.c4
-rw-r--r--drivers/ide/legacy/ide-cs.c7
-rw-r--r--drivers/ide/legacy/macide.c2
-rw-r--r--drivers/ide/mips/swarm.c2
-rw-r--r--drivers/ide/pci/Makefile2
-rw-r--r--drivers/ide/pci/atiixp.c21
-rw-r--r--drivers/ide/pci/cs5530.c13
-rw-r--r--drivers/ide/pci/cy82c693.c5
-rw-r--r--drivers/ide/pci/generic.c19
-rw-r--r--drivers/ide/pci/it8172.c307
-rw-r--r--drivers/ide/pci/jmicron.c268
-rw-r--r--drivers/ide/pci/pdc202xx_old.c22
-rw-r--r--drivers/ide/pci/piix.c33
-rw-r--r--drivers/ide/pci/rz1000.c1
-rw-r--r--drivers/ide/pci/sc1200.c4
-rw-r--r--drivers/ide/pci/serverworks.c8
-rw-r--r--drivers/ide/pci/sgiioc4.c22
-rw-r--r--drivers/ide/pci/siimage.c1
-rw-r--r--drivers/ide/pci/sis5513.c3
-rw-r--r--drivers/ide/pci/via82cxxx.c5
-rw-r--r--drivers/ide/ppc/pmac.c2
-rw-r--r--drivers/ide/setup-pci.c20
-rw-r--r--drivers/ieee1394/Kconfig13
-rw-r--r--drivers/ieee1394/csr.c31
-rw-r--r--drivers/ieee1394/csr.h109
-rw-r--r--drivers/ieee1394/dma.c7
-rw-r--r--drivers/ieee1394/dma.h90
-rw-r--r--drivers/ieee1394/dv1394-private.h6
-rw-r--r--drivers/ieee1394/dv1394.c47
-rw-r--r--drivers/ieee1394/eth1394.c12
-rw-r--r--drivers/ieee1394/highlevel.h201
-rw-r--r--drivers/ieee1394/hosts.c23
-rw-r--r--drivers/ieee1394/hosts.h51
-rw-r--r--drivers/ieee1394/ieee1394-ioctl.h9
-rw-r--r--drivers/ieee1394/ieee1394.h316
-rw-r--r--drivers/ieee1394/ieee1394_core.c9
-rw-r--r--drivers/ieee1394/ieee1394_core.h28
-rw-r--r--drivers/ieee1394/ieee1394_hotplug.h30
-rw-r--r--drivers/ieee1394/ieee1394_transactions.c114
-rw-r--r--drivers/ieee1394/ieee1394_transactions.h41
-rw-r--r--drivers/ieee1394/ieee1394_types.h68
-rw-r--r--drivers/ieee1394/iso.c5
-rw-r--r--drivers/ieee1394/iso.h87
-rw-r--r--drivers/ieee1394/nodemgr.c227
-rw-r--r--drivers/ieee1394/nodemgr.h27
-rw-r--r--drivers/ieee1394/ohci1394.c76
-rw-r--r--drivers/ieee1394/pcilynx.c4
-rw-r--r--drivers/ieee1394/raw1394-private.h3
-rw-r--r--drivers/ieee1394/raw1394.c138
-rw-r--r--drivers/ieee1394/sbp2.c481
-rw-r--r--drivers/ieee1394/sbp2.h37
-rw-r--r--drivers/ieee1394/video1394.c52
-rw-r--r--drivers/infiniband/core/addr.c4
-rw-r--r--drivers/infiniband/core/cm.c84
-rw-r--r--drivers/infiniband/core/cma.c47
-rw-r--r--drivers/infiniband/core/mad.c5
-rw-r--r--drivers/infiniband/hw/amso1100/c2.c6
-rw-r--r--drivers/infiniband/hw/amso1100/c2_ae.c4
-rw-r--r--drivers/infiniband/hw/amso1100/c2_alloc.c2
-rw-r--r--drivers/infiniband/hw/amso1100/c2_cm.c15
-rw-r--r--drivers/infiniband/hw/amso1100/c2_provider.c8
-rw-r--r--drivers/infiniband/hw/amso1100/c2_qp.c16
-rw-r--r--drivers/infiniband/hw/amso1100/c2_rnic.c8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.h4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_main.c36
-rw-r--r--drivers/infiniband/hw/ehca/ehca_tools.h2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_common.h54
-rw-r--r--drivers/infiniband/hw/ipath/ipath_cq.c48
-rw-r--r--drivers/infiniband/hw/ipath/ipath_diag.c65
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c369
-rw-r--r--drivers/infiniband/hw/ipath/ipath_eeprom.c17
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c974
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c26
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6110.c137
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba6120.c263
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c56
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c282
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h121
-rw-r--r--drivers/infiniband/hw/ipath/ipath_keys.c12
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mad.c16
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mmap.c1
-rw-r--r--drivers/infiniband/hw/ipath/ipath_mr.c3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_qp.c16
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c136
-rw-r--r--drivers/infiniband/hw/ipath/ipath_registers.h40
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c14
-rw-r--r--drivers/infiniband/hw/ipath/ipath_srq.c23
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sysfs.c21
-rw-r--r--drivers/infiniband/hw/ipath/ipath_uc.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ud.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_user_pages.c56
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c45
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.h18
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_ppc64.c20
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_x86_64.c13
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c7
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c10
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c2
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c19
-rw-r--r--drivers/infiniband/hw/mthca/mthca_srq.c14
-rw-r--r--drivers/infiniband/ulp/ipoib/Kconfig2
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_fs.c4
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c5
-rw-r--r--drivers/infiniband/ulp/iser/Kconfig13
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c2
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h9
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c60
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c42
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c8
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c27
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h2
-rw-r--r--drivers/input/Kconfig14
-rw-r--r--drivers/input/Makefile6
-rw-r--r--drivers/input/evbug.c11
-rw-r--r--drivers/input/evdev.c42
-rw-r--r--drivers/input/ff-core.c367
-rw-r--r--drivers/input/ff-memless.c515
-rw-r--r--drivers/input/fixp-arith.h (renamed from drivers/usb/input/fixp-arith.h)0
-rw-r--r--drivers/input/gameport/fm801-gp.c22
-rw-r--r--drivers/input/gameport/gameport.c18
-rw-r--r--drivers/input/input.c46
-rw-r--r--drivers/input/joydev.c12
-rw-r--r--drivers/input/joystick/Kconfig2
-rw-r--r--drivers/input/joystick/amijoy.c4
-rw-r--r--drivers/input/joystick/iforce/iforce-ff.c118
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c226
-rw-r--r--drivers/input/joystick/iforce/iforce-packets.c21
-rw-r--r--drivers/input/joystick/iforce/iforce-serio.c4
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c8
-rw-r--r--drivers/input/joystick/iforce/iforce.h28
-rw-r--r--drivers/input/joystick/magellan.c8
-rw-r--r--drivers/input/joystick/spaceball.c8
-rw-r--r--drivers/input/joystick/spaceorb.c8
-rw-r--r--drivers/input/joystick/stinger.c8
-rw-r--r--drivers/input/joystick/twidjoy.c8
-rw-r--r--drivers/input/joystick/warrior.c10
-rw-r--r--drivers/input/keyboard/Kconfig26
-rw-r--r--drivers/input/keyboard/Makefile2
-rw-r--r--drivers/input/keyboard/amikbd.c4
-rw-r--r--drivers/input/keyboard/atkbd.c62
-rw-r--r--drivers/input/keyboard/corgikbd.c11
-rw-r--r--drivers/input/keyboard/hil_kbd.c4
-rw-r--r--drivers/input/keyboard/hilkbd.c2
-rw-r--r--drivers/input/keyboard/lkkbd.c5
-rw-r--r--drivers/input/keyboard/locomokbd.c10
-rw-r--r--drivers/input/keyboard/newtonkbd.c3
-rw-r--r--drivers/input/keyboard/omap-keypad.c491
-rw-r--r--drivers/input/keyboard/spitzkbd.c12
-rw-r--r--drivers/input/keyboard/stowaway.c186
-rw-r--r--drivers/input/keyboard/sunkbd.c3
-rw-r--r--drivers/input/keyboard/xtkbd.c3
-rw-r--r--drivers/input/misc/Kconfig2
-rw-r--r--drivers/input/misc/hp_sdc_rtc.c8
-rw-r--r--drivers/input/misc/ixp4xx-beeper.c2
-rw-r--r--drivers/input/misc/uinput.c67
-rw-r--r--drivers/input/misc/wistron_btns.c20
-rw-r--r--drivers/input/mouse/Kconfig2
-rw-r--r--drivers/input/mouse/alps.c18
-rw-r--r--drivers/input/mouse/alps.h2
-rw-r--r--drivers/input/mouse/amimouse.c4
-rw-r--r--drivers/input/mouse/hil_ptr.c4
-rw-r--r--drivers/input/mouse/inport.c4
-rw-r--r--drivers/input/mouse/lifebook.c12
-rw-r--r--drivers/input/mouse/logibm.c3
-rw-r--r--drivers/input/mouse/logips2pp.c27
-rw-r--r--drivers/input/mouse/pc110pad.c9
-rw-r--r--drivers/input/mouse/psmouse-base.c58
-rw-r--r--drivers/input/mouse/psmouse.h2
-rw-r--r--drivers/input/mouse/rpcmouse.c4
-rw-r--r--drivers/input/mouse/sermouse.c16
-rw-r--r--drivers/input/mouse/synaptics.c25
-rw-r--r--drivers/input/mouse/vsxxxaa.c22
-rw-r--r--drivers/input/mousedev.c28
-rw-r--r--drivers/input/power.c7
-rw-r--r--drivers/input/serio/Kconfig6
-rw-r--r--drivers/input/serio/ambakmi.c4
-rw-r--r--drivers/input/serio/ct82c710.c4
-rw-r--r--drivers/input/serio/gscps2.c10
-rw-r--r--drivers/input/serio/hil_mlc.c50
-rw-r--r--drivers/input/serio/hp_sdc.c8
-rw-r--r--drivers/input/serio/i8042-io.h15
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h14
-rw-r--r--drivers/input/serio/i8042.c762
-rw-r--r--drivers/input/serio/i8042.h9
-rw-r--r--drivers/input/serio/libps2.c39
-rw-r--r--drivers/input/serio/maceps2.c5
-rw-r--r--drivers/input/serio/parkbd.c4
-rw-r--r--drivers/input/serio/pcips2.c4
-rw-r--r--drivers/input/serio/q40kbd.c4
-rw-r--r--drivers/input/serio/rpckbd.c6
-rw-r--r--drivers/input/serio/sa1111ps2.c6
-rw-r--r--drivers/input/serio/serio.c26
-rw-r--r--drivers/input/serio/serio_raw.c2
-rw-r--r--drivers/input/serio/serport.c5
-rw-r--r--drivers/input/touchscreen/Kconfig36
-rw-r--r--drivers/input/touchscreen/Makefile3
-rw-r--r--drivers/input/touchscreen/ads7846.c2
-rw-r--r--drivers/input/touchscreen/corgi_ts.c17
-rw-r--r--drivers/input/touchscreen/elo.c178
-rw-r--r--drivers/input/touchscreen/gunze.c7
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c14
-rw-r--r--drivers/input/touchscreen/hp680_ts_input.c16
-rw-r--r--drivers/input/touchscreen/mk712.c3
-rw-r--r--drivers/input/touchscreen/mtouch.c11
-rw-r--r--drivers/input/touchscreen/penmount.c184
-rw-r--r--drivers/input/touchscreen/touchright.c195
-rw-r--r--drivers/input/touchscreen/touchwin.c202
-rw-r--r--drivers/input/tsdev.c12
-rw-r--r--drivers/isdn/act2000/act2000_isa.c24
-rw-r--r--drivers/isdn/capi/capi.c2
-rw-r--r--drivers/isdn/capi/capidrv.c3
-rw-r--r--drivers/isdn/capi/capifs.c2
-rw-r--r--drivers/isdn/gigaset/bas-gigaset.c14
-rw-r--r--drivers/isdn/gigaset/interface.c2
-rw-r--r--drivers/isdn/gigaset/proc.c3
-rw-r--r--drivers/isdn/gigaset/usb-gigaset.c4
-rw-r--r--drivers/isdn/hardware/avm/avmcard.h4
-rw-r--r--drivers/isdn/hardware/avm/b1.c2
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c2
-rw-r--r--drivers/isdn/hardware/avm/c4.c2
-rw-r--r--drivers/isdn/hardware/avm/t1isa.c2
-rw-r--r--drivers/isdn/hardware/eicon/Kconfig2
-rw-r--r--drivers/isdn/hardware/eicon/diva.c4
-rw-r--r--drivers/isdn/hardware/eicon/divasmain.c3
-rw-r--r--drivers/isdn/hardware/eicon/dsp_defs.h3
-rw-r--r--drivers/isdn/hisax/Kconfig2
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c2
-rw-r--r--drivers/isdn/hisax/amd7930_fn.h2
-rw-r--r--drivers/isdn/hisax/asuscom.c4
-rw-r--r--drivers/isdn/hisax/avm_a1.c2
-rw-r--r--drivers/isdn/hisax/avm_a1p.c2
-rw-r--r--drivers/isdn/hisax/avm_pci.c2
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c2
-rw-r--r--drivers/isdn/hisax/bkm_a8.c2
-rw-r--r--drivers/isdn/hisax/config.c12
-rw-r--r--drivers/isdn/hisax/diva.c34
-rw-r--r--drivers/isdn/hisax/elsa.c4
-rw-r--r--drivers/isdn/hisax/enternow_pci.c2
-rw-r--r--drivers/isdn/hisax/gazel.c4
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c9
-rw-r--r--drivers/isdn/hisax/hfc_pci.c2
-rw-r--r--drivers/isdn/hisax/hfc_sx.c6
-rw-r--r--drivers/isdn/hisax/hfc_usb.c12
-rw-r--r--drivers/isdn/hisax/hfc_usb.h6
-rw-r--r--drivers/isdn/hisax/hfcscard.c2
-rw-r--r--drivers/isdn/hisax/hisax.h15
-rw-r--r--drivers/isdn/hisax/hisax_fcpcipnp.c21
-rw-r--r--drivers/isdn/hisax/icc.c2
-rw-r--r--drivers/isdn/hisax/isac.c2
-rw-r--r--drivers/isdn/hisax/isurf.c2
-rw-r--r--drivers/isdn/hisax/ix1_micro.c2
-rw-r--r--drivers/isdn/hisax/mic.c2
-rw-r--r--drivers/isdn/hisax/netjet.h2
-rw-r--r--drivers/isdn/hisax/niccy.c222
-rw-r--r--drivers/isdn/hisax/nj_s.c2
-rw-r--r--drivers/isdn/hisax/nj_u.c2
-rw-r--r--drivers/isdn/hisax/s0box.c2
-rw-r--r--drivers/isdn/hisax/saphir.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c6
-rw-r--r--drivers/isdn/hisax/sportster.c2
-rw-r--r--drivers/isdn/hisax/st5481_b.c10
-rw-r--r--drivers/isdn/hisax/st5481_d.c6
-rw-r--r--drivers/isdn/hisax/st5481_usb.c6
-rw-r--r--drivers/isdn/hisax/teleint.c2
-rw-r--r--drivers/isdn/hisax/teles0.c2
-rw-r--r--drivers/isdn/hisax/teles3.c2
-rw-r--r--drivers/isdn/hisax/telespci.c2
-rw-r--r--drivers/isdn/hisax/w6692.c4
-rw-r--r--drivers/isdn/hysdn/boardergo.c36
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h2
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c17
-rw-r--r--drivers/isdn/hysdn/hysdn_sched.c9
-rw-r--r--drivers/isdn/i4l/isdn_common.c9
-rw-r--r--drivers/isdn/i4l/isdn_net.c4
-rw-r--r--drivers/isdn/i4l/isdn_tty.c2
-rw-r--r--drivers/isdn/icn/icn.c3
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c73
-rw-r--r--drivers/isdn/isdnloop/isdnloop.h1
-rw-r--r--drivers/isdn/pcbit/drv.c16
-rw-r--r--drivers/isdn/pcbit/layer2.c3
-rw-r--r--drivers/isdn/pcbit/layer2.h2
-rw-r--r--drivers/isdn/sc/command.c22
-rw-r--r--drivers/isdn/sc/event.c2
-rw-r--r--drivers/isdn/sc/init.c25
-rw-r--r--drivers/isdn/sc/interrupt.c4
-rw-r--r--drivers/isdn/sc/packet.c14
-rw-r--r--drivers/isdn/sc/shmem.c2
-rw-r--r--drivers/isdn/sc/timer.c2
-rw-r--r--drivers/leds/led-class.c28
-rw-r--r--drivers/leds/led-triggers.c1
-rw-r--r--drivers/leds/leds-ams-delta.c1
-rw-r--r--drivers/leds/leds-locomo.c2
-rw-r--r--drivers/leds/leds-net48xx.c9
-rw-r--r--drivers/leds/ledtrig-timer.c16
-rw-r--r--drivers/macintosh/Kconfig2
-rw-r--r--drivers/macintosh/adb-iop.c10
-rw-r--r--drivers/macintosh/adb.c10
-rw-r--r--drivers/macintosh/adbhid.c22
-rw-r--r--drivers/macintosh/macio-adb.c9
-rw-r--r--drivers/macintosh/smu.c10
-rw-r--r--drivers/macintosh/via-cuda.c14
-rw-r--r--drivers/macintosh/via-macii.c9
-rw-r--r--drivers/macintosh/via-maciisi.c14
-rw-r--r--drivers/macintosh/via-pmu-backlight.c2
-rw-r--r--drivers/macintosh/via-pmu.c53
-rw-r--r--drivers/macintosh/via-pmu68k.c25
-rw-r--r--drivers/macintosh/windfarm_pm112.c18
-rw-r--r--drivers/macintosh/windfarm_pm81.c24
-rw-r--r--drivers/macintosh/windfarm_pm91.c24
-rw-r--r--drivers/macintosh/windfarm_smu_controls.c2
-rw-r--r--drivers/macintosh/windfarm_smu_sat.c7
-rw-r--r--drivers/macintosh/windfarm_smu_sensors.c2
-rw-r--r--drivers/mca/mca-bus.c28
-rw-r--r--drivers/md/Kconfig21
-rw-r--r--drivers/md/bitmap.c29
-rw-r--r--drivers/md/dm-crypt.c507
-rw-r--r--drivers/md/dm-emc.c3
-rw-r--r--drivers/md/dm-exception-store.c176
-rw-r--r--drivers/md/dm-linear.c19
-rw-r--r--drivers/md/dm-mpath.c83
-rw-r--r--drivers/md/dm-raid1.c4
-rw-r--r--drivers/md/dm-snap.c351
-rw-r--r--drivers/md/dm-snap.h17
-rw-r--r--drivers/md/dm-table.c109
-rw-r--r--drivers/md/dm.c113
-rw-r--r--drivers/md/dm.h7
-rw-r--r--drivers/md/linear.c15
-rw-r--r--drivers/md/md.c293
-rw-r--r--drivers/md/multipath.c29
-rw-r--r--drivers/md/raid0.c17
-rw-r--r--drivers/md/raid1.c247
-rw-r--r--drivers/md/raid10.c263
-rw-r--r--drivers/md/raid5.c76
-rw-r--r--drivers/media/Kconfig1
-rw-r--r--drivers/media/common/Kconfig1
-rw-r--r--drivers/media/common/ir-keymaps.c79
-rw-r--r--drivers/media/common/saa7146_core.c2
-rw-r--r--drivers/media/common/saa7146_fops.c1
-rw-r--r--drivers/media/dvb/b2c2/Kconfig14
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c24
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c2
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig14
-rw-r--r--drivers/media/dvb/bt8xx/bt878.c2
-rw-r--r--drivers/media/dvb/bt8xx/dst.c9
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c11
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h3
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c41
-rw-r--r--drivers/media/dvb/cinergyT2/Kconfig2
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c4
-rw-r--r--drivers/media/dvb/dvb-core/Kconfig13
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c52
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h8
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ringbuffer.c1
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.h22
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig57
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile5
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c52
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c258
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h49
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c279
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c212
-rw-r--r--drivers/media/dvb/dvb-usb/dib07x0.h21
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c242
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c202
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c79
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h18
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c139
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c162
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-common.h41
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c176
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-firmware.c10
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c49
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h139
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c165
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c7
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-urb.c269
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h280
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c32
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c48
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c38
-rw-r--r--drivers/media/dvb/dvb-usb/usb-urb.c243
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x-fe.c39
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c204
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.h2
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c40
-rw-r--r--drivers/media/dvb/frontends/Kconfig71
-rw-r--r--drivers/media/dvb/frontends/Makefile8
-rw-r--r--drivers/media/dvb/frontends/bcm3510.h9
-rw-r--r--drivers/media/dvb/frontends/cx22700.h9
-rw-r--r--drivers/media/dvb/frontends/cx22702.c4
-rw-r--r--drivers/media/dvb/frontends/cx22702.h9
-rw-r--r--drivers/media/dvb/frontends/cx24110.c17
-rw-r--r--drivers/media/dvb/frontends/cx24110.h19
-rw-r--r--drivers/media/dvb/frontends/cx24123.c102
-rw-r--r--drivers/media/dvb/frontends/cx24123.h12
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.c83
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.h135
-rw-r--r--drivers/media/dvb/frontends/dib3000.h11
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c76
-rw-r--r--drivers/media/dvb/frontends/dib3000mb_priv.h93
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c1408
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.h61
-rw-r--r--drivers/media/dvb/frontends/dib3000mc_priv.h428
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c152
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.h166
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c11
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h4
-rw-r--r--drivers/media/dvb/frontends/isl6421.c30
-rw-r--r--drivers/media/dvb/frontends/isl6421.h11
-rw-r--r--drivers/media/dvb/frontends/l64781.h10
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.h9
-rw-r--r--drivers/media/dvb/frontends/lnbp21.c30
-rw-r--r--drivers/media/dvb/frontends/lnbp21.h12
-rw-r--r--drivers/media/dvb/frontends/mt2060.c370
-rw-r--r--drivers/media/dvb/frontends/mt2060.h35
-rw-r--r--drivers/media/dvb/frontends/mt2060_priv.h105
-rw-r--r--drivers/media/dvb/frontends/mt312.h10
-rw-r--r--drivers/media/dvb/frontends/mt352.c16
-rw-r--r--drivers/media/dvb/frontends/mt352.h16
-rw-r--r--drivers/media/dvb/frontends/nxt200x.h9
-rw-r--r--drivers/media/dvb/frontends/nxt6000.h9
-rw-r--r--drivers/media/dvb/frontends/or51132.h9
-rw-r--r--drivers/media/dvb/frontends/or51211.h9
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h9
-rw-r--r--drivers/media/dvb/frontends/sp8870.h9
-rw-r--r--drivers/media/dvb/frontends/sp887x.h9
-rw-r--r--drivers/media/dvb/frontends/stv0297.h9
-rw-r--r--drivers/media/dvb/frontends/stv0299.c9
-rw-r--r--drivers/media/dvb/frontends/stv0299.h19
-rw-r--r--drivers/media/dvb/frontends/tda10021.c63
-rw-r--r--drivers/media/dvb/frontends/tda10021.h19
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c10
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h25
-rw-r--r--drivers/media/dvb/frontends/tda10086.c740
-rw-r--r--drivers/media/dvb/frontends/tda10086.h50
-rw-r--r--drivers/media/dvb/frontends/tda8083.h9
-rw-r--r--drivers/media/dvb/frontends/tda826x.c173
-rw-r--r--drivers/media/dvb/frontends/tda826x.h53
-rw-r--r--drivers/media/dvb/frontends/tua6100.c205
-rw-r--r--drivers/media/dvb/frontends/tua6100.h47
-rw-r--r--drivers/media/dvb/frontends/ves1820.h9
-rw-r--r--drivers/media/dvb/frontends/ves1x93.h9
-rw-r--r--drivers/media/dvb/frontends/zl10353.c11
-rw-r--r--drivers/media/dvb/frontends/zl10353.h14
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c2
-rw-r--r--drivers/media/dvb/ttpci/Kconfig57
-rw-r--r--drivers/media/dvb/ttpci/av7110.c58
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c3
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c184
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c32
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c17
-rw-r--r--drivers/media/dvb/ttpci/budget.c53
-rw-r--r--drivers/media/dvb/ttusb-budget/Kconfig14
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c30
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c12
-rw-r--r--drivers/media/radio/Kconfig33
-rw-r--r--drivers/media/radio/dsbr100.c198
-rw-r--r--drivers/media/radio/radio-aimslab.c151
-rw-r--r--drivers/media/radio/radio-aztech.c166
-rw-r--r--drivers/media/radio/radio-cadet.c250
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c172
-rw-r--r--drivers/media/radio/radio-gemtek.c165
-rw-r--r--drivers/media/radio/radio-maestro.c197
-rw-r--r--drivers/media/radio/radio-maxiradio.c166
-rw-r--r--drivers/media/radio/radio-rtrack2.c163
-rw-r--r--drivers/media/radio/radio-sf16fmi.c158
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c223
-rw-r--r--drivers/media/radio/radio-terratec.c154
-rw-r--r--drivers/media/radio/radio-trust.c188
-rw-r--r--drivers/media/radio/radio-typhoon.c171
-rw-r--r--drivers/media/radio/radio-zoltrix.c183
-rw-r--r--drivers/media/video/Kconfig478
-rw-r--r--drivers/media/video/Makefile45
-rw-r--r--drivers/media/video/arv.c2
-rw-r--r--drivers/media/video/bt866.c2
-rw-r--r--drivers/media/video/bt8xx/Kconfig5
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c4
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c14
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c17
-rw-r--r--drivers/media/video/compat_ioctl32.c59
-rw-r--r--drivers/media/video/cpia2/cpia2.h4
-rw-r--r--drivers/media/video/cpia2/cpia2_usb.c4
-rw-r--r--drivers/media/video/cpia_usb.c2
-rw-r--r--drivers/media/video/cx2341x.c25
-rw-r--r--drivers/media/video/cx25840/Kconfig2
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c29
-rw-r--r--drivers/media/video/cx88/Kconfig111
-rw-r--r--drivers/media/video/cx88/Makefile7
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c2
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c6
-rw-r--r--drivers/media/video/cx88/cx88-cards.c261
-rw-r--r--drivers/media/video/cx88/cx88-core.c22
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c349
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c18
-rw-r--r--drivers/media/video/cx88/cx88-input.c21
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c15
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c9
-rw-r--r--drivers/media/video/cx88/cx88-video.c12
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c1
-rw-r--r--drivers/media/video/cx88/cx88.h22
-rw-r--r--drivers/media/video/dabusb.c2
-rw-r--r--drivers/media/video/em28xx/Kconfig3
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c6
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c39
-rw-r--r--drivers/media/video/ir-kbd-i2c.c19
-rw-r--r--drivers/media/video/ks0127.c3
-rw-r--r--drivers/media/video/meye.c2
-rw-r--r--drivers/media/video/msp3400-driver.c2
-rw-r--r--drivers/media/video/msp3400-driver.h1
-rw-r--r--drivers/media/video/msp3400-kthreads.c5
-rw-r--r--drivers/media/video/ov511.c67
-rw-r--r--drivers/media/video/planb.c4
-rw-r--r--drivers/media/video/pvrusb2/Kconfig27
-rw-r--r--drivers/media/video/pvrusb2/Makefile6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c21
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h31
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c125
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h8
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c8
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c3
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c161
-rw-r--r--drivers/media/video/pwc/philips.txt4
-rw-r--r--drivers/media/video/pwc/pwc-if.c45
-rw-r--r--drivers/media/video/saa5246a.c1
-rw-r--r--drivers/media/video/saa5249.c1
-rw-r--r--drivers/media/video/saa7115.c1252
-rw-r--r--drivers/media/video/saa711x_regs.h549
-rw-r--r--drivers/media/video/saa7134/Kconfig50
-rw-r--r--drivers/media/video/saa7134/Makefile3
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c10
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c198
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c242
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c7
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c94
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c66
-rw-r--r--drivers/media/video/saa7134/saa7134.h6
-rw-r--r--drivers/media/video/se401.c4
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c73
-rw-r--r--drivers/media/video/stradis.c2
-rw-r--r--drivers/media/video/stv680.c55
-rw-r--r--drivers/media/video/tda9887.c2
-rw-r--r--drivers/media/video/tuner-simple.c6
-rw-r--r--drivers/media/video/tuner-types.c2
-rw-r--r--drivers/media/video/tvaudio.c42
-rw-r--r--drivers/media/video/tveeprom.c6
-rw-r--r--drivers/media/video/tvp5150.c7
-rw-r--r--drivers/media/video/usbvideo/konicawc.c11
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c4
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c2
-rw-r--r--drivers/media/video/usbvideo/vicam.c4
-rw-r--r--drivers/media/video/v4l1-compat.c12
-rw-r--r--drivers/media/video/v4l2-common.c1
-rw-r--r--drivers/media/video/video-buf-dvb.c2
-rw-r--r--drivers/media/video/video-buf.c7
-rw-r--r--drivers/media/video/videodev.c44
-rw-r--r--drivers/media/video/vino.c3
-rw-r--r--drivers/media/video/vivi.c17
-rw-r--r--drivers/media/video/vpx3220.c2
-rw-r--r--drivers/media/video/w9968cf.c11
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c2
-rw-r--r--drivers/media/video/zoran_card.c17
-rw-r--r--drivers/media/video/zoran_device.c5
-rw-r--r--drivers/media/video/zoran_device.h4
-rw-r--r--drivers/media/video/zoran_driver.c7
-rw-r--r--drivers/media/video/zr36120.c31
-rw-r--r--drivers/message/fusion/linux_compat.h9
-rw-r--r--drivers/message/fusion/mptbase.c5
-rw-r--r--drivers/message/i2o/Kconfig2
-rw-r--r--drivers/message/i2o/bus-osm.c12
-rw-r--r--drivers/message/i2o/exec-osm.c19
-rw-r--r--drivers/message/i2o/i2o_block.c7
-rw-r--r--drivers/message/i2o/pci.c10
-rw-r--r--drivers/mfd/ucb1x00-core.c2
-rw-r--r--drivers/mfd/ucb1x00-ts.c45
-rw-r--r--drivers/misc/Kconfig62
-rw-r--r--drivers/misc/Makefile7
-rw-r--r--drivers/misc/ibmasm/ibmasm.h4
-rw-r--r--drivers/misc/ibmasm/ibmasmfs.c17
-rw-r--r--drivers/misc/ibmasm/lowlevel.c4
-rw-r--r--drivers/misc/ibmasm/remote.c14
-rw-r--r--drivers/misc/ioc4.c (renamed from drivers/sn/ioc4.c)47
-rw-r--r--drivers/misc/lkdtm.c341
-rw-r--r--drivers/misc/msi-laptop.c395
-rw-r--r--drivers/misc/tifm_7xx1.c438
-rw-r--r--drivers/misc/tifm_core.c272
-rw-r--r--drivers/mmc/Kconfig18
-rw-r--r--drivers/mmc/Makefile4
-rw-r--r--drivers/mmc/at91_mci.c9
-rw-r--r--drivers/mmc/au1xmmc.c2
-rw-r--r--drivers/mmc/imxmmc.c6
-rw-r--r--drivers/mmc/mmc.c7
-rw-r--r--drivers/mmc/mmc.h4
-rw-r--r--drivers/mmc/mmc_block.c180
-rw-r--r--drivers/mmc/mmc_queue.c6
-rw-r--r--drivers/mmc/mmc_sysfs.c35
-rw-r--r--drivers/mmc/mmci.c17
-rw-r--r--drivers/mmc/omap.c11
-rw-r--r--drivers/mmc/pxamci.c6
-rw-r--r--drivers/mmc/sdhci.c34
-rw-r--r--drivers/mmc/sdhci.h5
-rw-r--r--drivers/mmc/tifm_sd.c933
-rw-r--r--drivers/mmc/wbsd.c9
-rw-r--r--drivers/mmc/wbsd.h5
-rw-r--r--drivers/mtd/Kconfig12
-rw-r--r--drivers/mtd/chips/Kconfig2
-rw-r--r--drivers/mtd/devices/Kconfig2
-rw-r--r--drivers/mtd/maps/arctic-mtd.c6
-rw-r--r--drivers/mtd/maps/bast-flash.c2
-rw-r--r--drivers/mtd/maps/beech-mtd.c6
-rw-r--r--drivers/mtd/maps/cstm_mips_ixx.c8
-rw-r--r--drivers/mtd/maps/dmv182.c2
-rw-r--r--drivers/mtd/maps/nettel.c2
-rw-r--r--drivers/mtd/maps/physmap.c2
-rw-r--r--drivers/mtd/maps/redwood.c2
-rw-r--r--drivers/mtd/mtd_blkdevs.c4
-rw-r--r--drivers/mtd/nand/Kconfig2
-rw-r--r--drivers/mtd/nand/cs553x_nand.c2
-rw-r--r--drivers/mtd/nand/edb7312.c2
-rw-r--r--drivers/mtd/nand/nand_base.c172
-rw-r--r--drivers/mtd/nand/nand_bbt.c2
-rw-r--r--drivers/mtd/nftlcore.c4
-rw-r--r--drivers/mtd/onenand/Kconfig8
-rw-r--r--drivers/mtd/onenand/onenand_base.c154
-rw-r--r--drivers/net/3c501.c3
-rw-r--r--drivers/net/3c501.h2
-rw-r--r--drivers/net/3c505.c2
-rw-r--r--drivers/net/3c507.c4
-rw-r--r--drivers/net/3c509.c14
-rw-r--r--drivers/net/3c515.c6
-rw-r--r--drivers/net/3c523.c11
-rw-r--r--drivers/net/3c527.c9
-rw-r--r--drivers/net/3c59x.c15
-rw-r--r--drivers/net/7990.c4
-rw-r--r--drivers/net/8139cp.c5
-rw-r--r--drivers/net/8139too.c8
-rw-r--r--drivers/net/82596.c8
-rw-r--r--drivers/net/8390.c19
-rw-r--r--drivers/net/8390.h2
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/Space.c2
-rw-r--r--drivers/net/a2065.c3
-rw-r--r--drivers/net/acenic.c6
-rw-r--r--drivers/net/acenic.h2
-rw-r--r--drivers/net/amd8111e.c4
-rw-r--r--drivers/net/apne.c6
-rw-r--r--drivers/net/appletalk/cops.c4
-rw-r--r--drivers/net/appletalk/ipddp.c5
-rw-r--r--drivers/net/appletalk/ltpc.c2
-rw-r--r--drivers/net/arcnet/arcnet.c2
-rw-r--r--drivers/net/ariadne.c4
-rw-r--r--drivers/net/arm/am79c961a.c4
-rw-r--r--drivers/net/arm/am79c961a.h2
-rw-r--r--drivers/net/arm/at91_ether.c6
-rw-r--r--drivers/net/arm/ep93xx_eth.c3
-rw-r--r--drivers/net/arm/ether1.c4
-rw-r--r--drivers/net/arm/ether3.c4
-rw-r--r--drivers/net/at1700.c5
-rw-r--r--drivers/net/atari_bionet.c2
-rw-r--r--drivers/net/atari_pamsnet.c3
-rw-r--r--drivers/net/atarilance.c4
-rw-r--r--drivers/net/atp.c11
-rw-r--r--drivers/net/au1000_eth.c4
-rw-r--r--drivers/net/b44.c13
-rw-r--r--drivers/net/bmac.c14
-rw-r--r--drivers/net/bnx2.c38
-rw-r--r--drivers/net/bonding/bond_3ad.c70
-rw-r--r--drivers/net/bonding/bond_alb.c4
-rw-r--r--drivers/net/bonding/bond_main.c230
-rw-r--r--drivers/net/bonding/bond_sysfs.c56
-rw-r--r--drivers/net/bonding/bonding.h34
-rw-r--r--drivers/net/cassini.c8
-rw-r--r--drivers/net/chelsio/cpl5_cmd.h6
-rw-r--r--drivers/net/chelsio/cxgb2.c2
-rw-r--r--drivers/net/chelsio/sge.c6
-rw-r--r--drivers/net/chelsio/sge.h9
-rw-r--r--drivers/net/cris/eth_v10.c8
-rw-r--r--drivers/net/cs89x0.c6
-rw-r--r--drivers/net/de600.c8
-rw-r--r--drivers/net/de600.h2
-rw-r--r--drivers/net/de620.c4
-rw-r--r--drivers/net/declance.c10
-rw-r--r--drivers/net/defxx.c6
-rw-r--r--drivers/net/depca.c4
-rw-r--r--drivers/net/dgrs.c7
-rw-r--r--drivers/net/dl2k.c4
-rw-r--r--drivers/net/dm9000.c6
-rw-r--r--drivers/net/e100.c98
-rw-r--r--drivers/net/e1000/LICENSE339
-rw-r--r--drivers/net/e1000/Makefile35
-rw-r--r--drivers/net/e1000/e1000.h59
-rw-r--r--drivers/net/e1000/e1000_ethtool.c153
-rw-r--r--drivers/net/e1000/e1000_hw.c1074
-rw-r--r--drivers/net/e1000/e1000_hw.h90
-rw-r--r--drivers/net/e1000/e1000_main.c278
-rw-r--r--drivers/net/e1000/e1000_osdep.h35
-rw-r--r--drivers/net/e1000/e1000_param.c47
-rw-r--r--drivers/net/eepro.c26
-rw-r--r--drivers/net/eepro100.c6
-rw-r--r--drivers/net/eexpress.c11
-rw-r--r--drivers/net/ehea/ehea.h13
-rw-r--r--drivers/net/ehea/ehea_main.c18
-rw-r--r--drivers/net/ehea/ehea_phyp.c573
-rw-r--r--drivers/net/epic100.c4
-rw-r--r--drivers/net/eth16i.c6
-rw-r--r--drivers/net/ewrk3.c4
-rw-r--r--drivers/net/fealnx.c4
-rw-r--r--drivers/net/fec.c10
-rw-r--r--drivers/net/fec_8xx/fec_main.c6
-rw-r--r--drivers/net/forcedeth.c59
-rw-r--r--drivers/net/fs_enet/fs_enet-main.c9
-rw-r--r--drivers/net/fs_enet/fs_enet.h3
-rw-r--r--drivers/net/fs_enet/mii-fec.c2
-rw-r--r--drivers/net/gianfar.c22
-rw-r--r--drivers/net/gianfar.h2
-rw-r--r--drivers/net/gt64240eth.h402
-rw-r--r--drivers/net/hamachi.c4
-rw-r--r--drivers/net/hamradio/baycom_epp.c2
-rw-r--r--drivers/net/hamradio/baycom_par.c2
-rw-r--r--drivers/net/hamradio/baycom_ser_fdx.c2
-rw-r--r--drivers/net/hamradio/baycom_ser_hdx.c2
-rw-r--r--drivers/net/hamradio/dmascc.c4
-rw-r--r--drivers/net/hamradio/scc.c4
-rw-r--r--drivers/net/hamradio/yam.c2
-rw-r--r--drivers/net/hp100.c13
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c4
-rw-r--r--drivers/net/ibm_emac/ibm_emac_debug.c3
-rw-r--r--drivers/net/ibm_emac/ibm_emac_debug.h2
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.c10
-rw-r--r--drivers/net/ibm_emac/ibm_emac_rgmii.h2
-rw-r--r--drivers/net/ibmlana.c2
-rw-r--r--drivers/net/ibmveth.c72
-rw-r--r--drivers/net/ifb.c4
-rw-r--r--drivers/net/ioc3-eth.c2
-rw-r--r--drivers/net/irda/Kconfig1
-rw-r--r--drivers/net/irda/ali-ircc.c13
-rw-r--r--drivers/net/irda/au1k_ir.c4
-rw-r--r--drivers/net/irda/donauboe.c35
-rw-r--r--drivers/net/irda/irda-usb.c30
-rw-r--r--drivers/net/irda/irport.c16
-rw-r--r--drivers/net/irda/irport.h2
-rw-r--r--drivers/net/irda/mcs7780.c4
-rw-r--r--drivers/net/irda/mcs7780.h4
-rw-r--r--drivers/net/irda/nsc-ircc.c14
-rw-r--r--drivers/net/irda/pxaficp_ir.c8
-rw-r--r--drivers/net/irda/sa1100_ir.c2
-rw-r--r--drivers/net/irda/smsc-ircc2.c44
-rw-r--r--drivers/net/irda/stir4200.c17
-rw-r--r--drivers/net/irda/via-ircc.c15
-rw-r--r--drivers/net/irda/vlsi_ir.c3
-rw-r--r--drivers/net/irda/vlsi_ir.h2
-rw-r--r--drivers/net/irda/w83977af_ir.c12
-rw-r--r--drivers/net/isa-skeleton.c4
-rw-r--r--drivers/net/iseries_veth.c2
-rw-r--r--drivers/net/ixgb/Makefile38
-rw-r--r--drivers/net/ixgb/ixgb.h38
-rw-r--r--drivers/net/ixgb/ixgb_ee.c36
-rw-r--r--drivers/net/ixgb/ixgb_ee.h36
-rw-r--r--drivers/net/ixgb/ixgb_ethtool.c36
-rw-r--r--drivers/net/ixgb/ixgb_hw.c36
-rw-r--r--drivers/net/ixgb/ixgb_hw.h36
-rw-r--r--drivers/net/ixgb/ixgb_ids.h36
-rw-r--r--drivers/net/ixgb/ixgb_main.c53
-rw-r--r--drivers/net/ixgb/ixgb_osdep.h36
-rw-r--r--drivers/net/ixgb/ixgb_param.c36
-rw-r--r--drivers/net/ixp2000/ixpdev.c2
-rw-r--r--drivers/net/lance.c10
-rw-r--r--drivers/net/lasi_82596.c8
-rw-r--r--drivers/net/loopback.c70
-rw-r--r--drivers/net/lp486e.c4
-rw-r--r--drivers/net/mac89x0.c4
-rw-r--r--drivers/net/mace.c12
-rw-r--r--drivers/net/macmace.c8
-rw-r--r--drivers/net/meth.c4
-rw-r--r--drivers/net/mipsnet.c3
-rw-r--r--drivers/net/mv643xx_eth.c9
-rw-r--r--drivers/net/myri10ge/myri10ge.c2
-rw-r--r--drivers/net/myri_code.h8
-rw-r--r--drivers/net/myri_sbus.c6
-rw-r--r--drivers/net/natsemi.c6
-rw-r--r--drivers/net/ne3210.c1
-rw-r--r--drivers/net/netx-eth.c2
-rw-r--r--drivers/net/ni5010.c4
-rw-r--r--drivers/net/ni52.c4
-rw-r--r--drivers/net/ni65.c4
-rw-r--r--drivers/net/ns83820.c2
-rw-r--r--drivers/net/pci-skeleton.c6
-rw-r--r--drivers/net/pcmcia/3c574_cs.c6
-rw-r--r--drivers/net/pcmcia/3c589_cs.c6
-rw-r--r--drivers/net/pcmcia/axnet_cs.c20
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c4
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c4
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c8
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c6
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c4
-rw-r--r--drivers/net/pcnet32.c15
-rw-r--r--drivers/net/phy/fixed.c7
-rw-r--r--drivers/net/phy/phy.c2
-rw-r--r--drivers/net/phy/phy_device.c10
-rw-r--r--drivers/net/plip.c11
-rw-r--r--drivers/net/pppoe.c1
-rw-r--r--drivers/net/qla3xxx.c2
-rw-r--r--drivers/net/r8169.c7
-rw-r--r--drivers/net/rrunner.c2
-rw-r--r--drivers/net/rrunner.h2
-rw-r--r--drivers/net/s2io.c22
-rw-r--r--drivers/net/s2io.h330
-rw-r--r--drivers/net/saa9730.c5
-rw-r--r--drivers/net/sb1000.c12
-rw-r--r--drivers/net/sb1250-mac.c4
-rw-r--r--drivers/net/seeq8005.c4
-rw-r--r--drivers/net/sgiseeq.c2
-rw-r--r--drivers/net/sis190.c4
-rw-r--r--drivers/net/sis900.c6
-rw-r--r--drivers/net/sk98lin/skge.c10
-rw-r--r--drivers/net/sk_mca.c2
-rw-r--r--drivers/net/skfp/skfddi.c12
-rw-r--r--drivers/net/skge.c509
-rw-r--r--drivers/net/skge.h58
-rw-r--r--drivers/net/sky2.c683
-rw-r--r--drivers/net/sky2.h32
-rw-r--r--drivers/net/smc-ultra.c2
-rw-r--r--drivers/net/smc911x.c6
-rw-r--r--drivers/net/smc9194.c4
-rw-r--r--drivers/net/smc91x.c4
-rw-r--r--drivers/net/smc91x.h39
-rw-r--r--drivers/net/sonic.c9
-rw-r--r--drivers/net/sonic.h2
-rw-r--r--drivers/net/spider_net.c256
-rw-r--r--drivers/net/spider_net.h35
-rw-r--r--drivers/net/spider_net_ethtool.c6
-rw-r--r--drivers/net/starfire.c4
-rw-r--r--drivers/net/stnic.c2
-rw-r--r--drivers/net/sun3_82586.c6
-rw-r--r--drivers/net/sun3lance.c10
-rw-r--r--drivers/net/sunbmac.c4
-rw-r--r--drivers/net/sundance.c4
-rw-r--r--drivers/net/sungem.c4
-rw-r--r--drivers/net/sunhme.c8
-rw-r--r--drivers/net/sunlance.c4
-rw-r--r--drivers/net/sunqe.c4
-rw-r--r--drivers/net/tc35815.c4
-rw-r--r--drivers/net/tg3.c510
-rw-r--r--drivers/net/tg3.h48
-rw-r--r--drivers/net/tlan.c7
-rw-r--r--drivers/net/tokenring/3c359.c4
-rw-r--r--drivers/net/tokenring/ibmtr.c6
-rw-r--r--drivers/net/tokenring/lanstreamer.c64
-rw-r--r--drivers/net/tokenring/lanstreamer.h12
-rw-r--r--drivers/net/tokenring/madgemc.c6
-rw-r--r--drivers/net/tokenring/olympic.c4
-rw-r--r--drivers/net/tokenring/smctr.c11
-rw-r--r--drivers/net/tokenring/tms380tr.c7
-rw-r--r--drivers/net/tokenring/tms380tr.h2
-rw-r--r--drivers/net/tokenring/tmspci.c3
-rw-r--r--drivers/net/tulip/de2104x.c10
-rw-r--r--drivers/net/tulip/de4x5.c11
-rw-r--r--drivers/net/tulip/dmfe.c6
-rw-r--r--drivers/net/tulip/interrupt.c2
-rw-r--r--drivers/net/tulip/tulip.h2
-rw-r--r--drivers/net/tulip/tulip_core.c2
-rw-r--r--drivers/net/tulip/uli526x.c4
-rw-r--r--drivers/net/tulip/winbond-840.c4
-rw-r--r--drivers/net/tulip/xircom_cb.c6
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c4
-rw-r--r--drivers/net/tun.c39
-rw-r--r--drivers/net/typhoon.c6
-rw-r--r--drivers/net/ucc_geth.c5
-rw-r--r--drivers/net/ucc_geth_phy.c1
-rw-r--r--drivers/net/via-rhine.c6
-rw-r--r--drivers/net/via-velocity.c5
-rw-r--r--drivers/net/wan/Kconfig12
-rw-r--r--drivers/net/wan/Makefile19
-rw-r--r--drivers/net/wan/cosa.c4
-rw-r--r--drivers/net/wan/cycx_main.c8
-rw-r--r--drivers/net/wan/dscc4.c4
-rw-r--r--drivers/net/wan/farsync.c2
-rw-r--r--drivers/net/wan/hd6457x.c2
-rw-r--r--drivers/net/wan/hdlc.c (renamed from drivers/net/wan/hdlc_generic.c)169
-rw-r--r--drivers/net/wan/hdlc_cisco.c200
-rw-r--r--drivers/net/wan/hdlc_fr.c389
-rw-r--r--drivers/net/wan/hdlc_ppp.c77
-rw-r--r--drivers/net/wan/hdlc_raw.c50
-rw-r--r--drivers/net/wan/hdlc_raw_eth.c49
-rw-r--r--drivers/net/wan/hdlc_x25.c54
-rw-r--r--drivers/net/wan/lmc/lmc_main.c4
-rw-r--r--drivers/net/wan/pc300.h1
-rw-r--r--drivers/net/wan/pc300_drv.c34
-rw-r--r--drivers/net/wan/sbni.c4
-rw-r--r--drivers/net/wan/sdla.c10
-rw-r--r--drivers/net/wan/syncppp.c4
-rw-r--r--drivers/net/wan/wanxl.c2
-rw-r--r--drivers/net/wan/z85230.c2
-rw-r--r--drivers/net/wan/z85230.h2
-rw-r--r--drivers/net/wireless/Kconfig2
-rw-r--r--drivers/net/wireless/airo.c47
-rw-r--r--drivers/net/wireless/arlan-main.c4
-rw-r--r--drivers/net/wireless/atmel.c20
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx.h1
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_main.c14
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_phy.c15
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_wx.c2
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_xmit.c5
-rw-r--r--drivers/net/wireless/hostap/hostap_hw.c2
-rw-r--r--drivers/net/wireless/hostap/hostap_ioctl.c10
-rw-r--r--drivers/net/wireless/ipw2100.c38
-rw-r--r--drivers/net/wireless/ipw2200.c18
-rw-r--r--drivers/net/wireless/netwave_cs.c6
-rw-r--r--drivers/net/wireless/orinoco.c14
-rw-r--r--drivers/net/wireless/orinoco.h2
-rw-r--r--drivers/net/wireless/prism54/isl_ioctl.c16
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.c2
-rw-r--r--drivers/net/wireless/prism54/islpci_dev.h2
-rw-r--r--drivers/net/wireless/ray_cs.c6
-rw-r--r--drivers/net/wireless/strip.c4
-rw-r--r--drivers/net/wireless/wavelan.c2
-rw-r--r--drivers/net/wireless/wavelan.p.h3
-rw-r--r--drivers/net/wireless/wavelan_cs.c14
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h3
-rw-r--r--drivers/net/wireless/wl3501_cs.c24
-rw-r--r--drivers/net/wireless/zd1201.c12
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.c137
-rw-r--r--drivers/net/wireless/zd1211rw/zd_chip.h23
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.c50
-rw-r--r--drivers/net/wireless/zd1211rw/zd_mac.h5
-rw-r--r--drivers/net/wireless/zd1211rw/zd_netdev.c2
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.c16
-rw-r--r--drivers/net/wireless/zd1211rw/zd_usb.h2
-rw-r--r--drivers/net/yellowfin.c11
-rw-r--r--drivers/net/znet.c9
-rw-r--r--drivers/oprofile/oprofilefs.c11
-rw-r--r--drivers/parisc/dino.c5
-rw-r--r--drivers/parisc/eisa.c6
-rw-r--r--drivers/parisc/gsc.c4
-rw-r--r--drivers/parisc/gsc.h2
-rw-r--r--drivers/parisc/iosapic.c5
-rw-r--r--drivers/parisc/lba_pci.c122
-rw-r--r--drivers/parisc/led.c2
-rw-r--r--drivers/parisc/power.c7
-rw-r--r--drivers/parisc/sba_iommu.c267
-rw-r--r--drivers/parisc/superio.c4
-rw-r--r--drivers/parport/daisy.c214
-rw-r--r--drivers/parport/ieee1284.c2
-rw-r--r--drivers/parport/parport_amiga.c4
-rw-r--r--drivers/parport/parport_atari.c4
-rw-r--r--drivers/parport/parport_ax88796.c4
-rw-r--r--drivers/parport/parport_gsc.c4
-rw-r--r--drivers/parport/parport_ip32.c11
-rw-r--r--drivers/parport/parport_mfc3.c4
-rw-r--r--drivers/parport/parport_pc.c4
-rw-r--r--drivers/parport/parport_serial.c4
-rw-r--r--drivers/parport/parport_sunbpp.c4
-rw-r--r--drivers/parport/share.c2
-rw-r--r--drivers/pci/Kconfig8
-rw-r--r--drivers/pci/Makefile11
-rw-r--r--drivers/pci/bus.c22
-rw-r--r--drivers/pci/hotplug/Kconfig2
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c2
-rw-r--r--drivers/pci/hotplug/acpiphp.h7
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c2
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c129
-rw-r--r--drivers/pci/hotplug/acpiphp_ibm.c1
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c4
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_pci.c2
-rw-r--r--drivers/pci/hotplug/cpcihp_generic.c4
-rw-r--r--drivers/pci/hotplug/cpqphp.h3
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c1
-rw-r--r--drivers/pci/hotplug/cpqphp_ctrl.c3
-rw-r--r--drivers/pci/hotplug/cpqphp_nvram.c1
-rw-r--r--drivers/pci/hotplug/cpqphp_pci.c1
-rw-r--r--drivers/pci/hotplug/cpqphp_sysfs.c3
-rw-r--r--drivers/pci/hotplug/fakephp.c31
-rw-r--r--drivers/pci/hotplug/ibmphp.h2
-rw-r--r--drivers/pci/hotplug/pci_hotplug_core.c168
-rw-r--r--drivers/pci/hotplug/pciehp.h11
-rw-r--r--drivers/pci/hotplug/pciehp_core.c6
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c116
-rw-r--r--drivers/pci/hotplug/pciehp_hpc.c8
-rw-r--r--drivers/pci/hotplug/pcihp_skeleton.c11
-rw-r--r--drivers/pci/hotplug/rpadlpar_sysfs.c2
-rw-r--r--drivers/pci/hotplug/rpaphp.h2
-rw-r--r--drivers/pci/hotplug/rpaphp_core.c2
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c2
-rw-r--r--drivers/pci/hotplug/shpchp.h6
-rw-r--r--drivers/pci/hotplug/shpchp_core.c6
-rw-r--r--drivers/pci/hotplug/shpchp_hpc.c88
-rw-r--r--drivers/pci/hotplug/shpchp_sysfs.c4
-rw-r--r--drivers/pci/htirq.c190
-rw-r--r--drivers/pci/msi-apic.c101
-rw-r--r--drivers/pci/msi.c1007
-rw-r--r--drivers/pci/msi.h110
-rw-r--r--drivers/pci/pci-driver.c11
-rw-r--r--drivers/pci/pci-sysfs.c153
-rw-r--r--drivers/pci/pci.c50
-rw-r--r--drivers/pci/pci.h2
-rw-r--r--drivers/pci/pcie/Kconfig1
-rw-r--r--drivers/pci/pcie/Makefile3
-rw-r--r--drivers/pci/pcie/aer/Kconfig12
-rw-r--r--drivers/pci/pcie/aer/Makefile8
-rw-r--r--drivers/pci/pcie/aer/aerdrv.c345
-rw-r--r--drivers/pci/pcie/aer/aerdrv.h125
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c68
-rw-r--r--drivers/pci/pcie/aer/aerdrv_core.c758
-rw-r--r--drivers/pci/pcie/aer/aerdrv_errprint.c248
-rw-r--r--drivers/pci/pcie/portdrv.h4
-rw-r--r--drivers/pci/pcie/portdrv_bus.c1
-rw-r--r--drivers/pci/pcie/portdrv_core.c10
-rw-r--r--drivers/pci/pcie/portdrv_pci.c211
-rw-r--r--drivers/pci/probe.c108
-rw-r--r--drivers/pci/quirks.c216
-rw-r--r--drivers/pci/remove.c37
-rw-r--r--drivers/pci/rom.c5
-rw-r--r--drivers/pci/search.c72
-rw-r--r--drivers/pci/setup-bus.c11
-rw-r--r--drivers/pcmcia/at91_cf.c4
-rw-r--r--drivers/pcmcia/cardbus.c5
-rw-r--r--drivers/pcmcia/hd64465_ss.c9
-rw-r--r--drivers/pcmcia/i82092.c2
-rw-r--r--drivers/pcmcia/i82092aa.h2
-rw-r--r--drivers/pcmcia/i82365.c9
-rw-r--r--drivers/pcmcia/m32r_cfc.c7
-rw-r--r--drivers/pcmcia/m32r_pcc.c6
-rw-r--r--drivers/pcmcia/m8xx_pcmcia.c4
-rw-r--r--drivers/pcmcia/omap_cf.c27
-rw-r--r--drivers/pcmcia/pcmcia_resource.c2
-rw-r--r--drivers/pcmcia/pd6729.c6
-rw-r--r--drivers/pcmcia/soc_common.c2
-rw-r--r--drivers/pcmcia/socket_sysfs.c27
-rw-r--r--drivers/pcmcia/tcic.c10
-rw-r--r--drivers/pcmcia/vrc4171_card.c2
-rw-r--r--drivers/pcmcia/vrc4173_cardu.c2
-rw-r--r--drivers/pcmcia/yenta_socket.c6
-rw-r--r--drivers/pnp/isapnp/core.c4
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c41
-rw-r--r--drivers/pnp/pnpbios/core.c8
-rw-r--r--drivers/pnp/resource.c2
-rw-r--r--drivers/rapidio/Kconfig2
-rw-r--r--drivers/rtc/Kconfig38
-rw-r--r--drivers/rtc/Makefile5
-rw-r--r--drivers/rtc/class.c6
-rw-r--r--drivers/rtc/rtc-at91.c27
-rw-r--r--drivers/rtc/rtc-dev.c7
-rw-r--r--drivers/rtc/rtc-ds1307.c8
-rw-r--r--drivers/rtc/rtc-ds1553.c13
-rw-r--r--drivers/rtc/rtc-ds1672.c6
-rw-r--r--drivers/rtc/rtc-ds1742.c12
-rw-r--r--drivers/rtc/rtc-ep93xx.c2
-rw-r--r--drivers/rtc/rtc-isl1208.c2
-rw-r--r--drivers/rtc/rtc-lib.c8
-rw-r--r--drivers/rtc/rtc-m48t86.c2
-rw-r--r--drivers/rtc/rtc-max6902.c7
-rw-r--r--drivers/rtc/rtc-pcf8563.c6
-rw-r--r--drivers/rtc/rtc-pcf8583.c2
-rw-r--r--drivers/rtc/rtc-pl031.c4
-rw-r--r--drivers/rtc/rtc-proc.c6
-rw-r--r--drivers/rtc/rtc-rs5c348.c11
-rw-r--r--drivers/rtc/rtc-rs5c372.c6
-rw-r--r--drivers/rtc/rtc-s3c.c6
-rw-r--r--drivers/rtc/rtc-sa1100.c8
-rw-r--r--drivers/rtc/rtc-sh.c467
-rw-r--r--drivers/rtc/rtc-sysfs.c2
-rw-r--r--drivers/rtc/rtc-test.c2
-rw-r--r--drivers/rtc/rtc-v3020.c9
-rw-r--r--drivers/rtc/rtc-vr41xx.c6
-rw-r--r--drivers/rtc/rtc-x1205.c2
-rw-r--r--drivers/s390/block/Kconfig2
-rw-r--r--drivers/s390/block/dasd.c1
-rw-r--r--drivers/s390/block/dasd_diag.c38
-rw-r--r--drivers/s390/block/dasd_eckd.c2
-rw-r--r--drivers/s390/block/dasd_fba.c2
-rw-r--r--drivers/s390/block/xpram.c54
-rw-r--r--drivers/s390/char/con3215.c2
-rw-r--r--drivers/s390/char/ctrlchar.c2
-rw-r--r--drivers/s390/char/fs3270.c12
-rw-r--r--drivers/s390/char/keyboard.c2
-rw-r--r--drivers/s390/char/monwriter.c24
-rw-r--r--drivers/s390/char/sclp.c35
-rw-r--r--drivers/s390/char/sclp_tty.c2
-rw-r--r--drivers/s390/char/sclp_vt220.c2
-rw-r--r--drivers/s390/char/tty3270.c3
-rw-r--r--drivers/s390/char/vmwatchdog.c52
-rw-r--r--drivers/s390/cio/chsc.c48
-rw-r--r--drivers/s390/cio/cio.c10
-rw-r--r--drivers/s390/cio/css.c2
-rw-r--r--drivers/s390/cio/css.h7
-rw-r--r--drivers/s390/cio/device.c48
-rw-r--r--drivers/s390/cio/device.h1
-rw-r--r--drivers/s390/cio/device_fsm.c119
-rw-r--r--drivers/s390/cio/device_id.c52
-rw-r--r--drivers/s390/cio/device_ops.c20
-rw-r--r--drivers/s390/cio/device_pgid.c31
-rw-r--r--drivers/s390/cio/device_status.c7
-rw-r--r--drivers/s390/cio/ioasm.h220
-rw-r--r--drivers/s390/cio/qdio.c12
-rw-r--r--drivers/s390/cio/qdio.h192
-rw-r--r--drivers/s390/crypto/ap_bus.c25
-rw-r--r--drivers/s390/net/iucv.c43
-rw-r--r--drivers/s390/net/qeth_main.c2
-rw-r--r--drivers/s390/s390mach.c95
-rw-r--r--drivers/s390/scsi/zfcp_erp.c2
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c2
-rw-r--r--drivers/sbus/char/aurora.c6
-rw-r--r--drivers/sbus/char/bbc_envctrl.c9
-rw-r--r--drivers/sbus/char/bbc_i2c.c2
-rw-r--r--drivers/sbus/char/cpwatchdog.c6
-rw-r--r--drivers/sbus/char/envctrl.c15
-rw-r--r--drivers/sbus/char/openprom.c2
-rw-r--r--drivers/sbus/char/uctrl.c4
-rw-r--r--drivers/scsi/3w-9xxx.c4
-rw-r--r--drivers/scsi/3w-xxxx.c5
-rw-r--r--drivers/scsi/3w-xxxx.h2
-rw-r--r--drivers/scsi/53c700.c4
-rw-r--r--drivers/scsi/53c700.h2
-rw-r--r--drivers/scsi/53c7xx.c6
-rw-r--r--drivers/scsi/BusLogic.c13
-rw-r--r--drivers/scsi/BusLogic.h7
-rw-r--r--drivers/scsi/Kconfig15
-rw-r--r--drivers/scsi/Makefile1
-rw-r--r--drivers/scsi/NCR5380.c6
-rw-r--r--drivers/scsi/NCR5380.h2
-rw-r--r--drivers/scsi/NCR53C9x.c6
-rw-r--r--drivers/scsi/NCR53C9x.h2
-rw-r--r--drivers/scsi/NCR53c406a.c13
-rw-r--r--drivers/scsi/NCR_D700.c4
-rw-r--r--drivers/scsi/NCR_Q720.c4
-rw-r--r--drivers/scsi/a100u2w.c4
-rw-r--r--drivers/scsi/a2091.c2
-rw-r--r--drivers/scsi/a3000.c2
-rw-r--r--drivers/scsi/aacraid/rx.c4
-rw-r--r--drivers/scsi/aacraid/sa.c2
-rw-r--r--drivers/scsi/advansys.c10
-rw-r--r--drivers/scsi/aha152x.c15
-rw-r--r--drivers/scsi/aha1542.c12
-rw-r--r--drivers/scsi/aha1740.c4
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic79xx4
-rw-r--r--drivers/scsi/aic7xxx/Kconfig.aic7xxx4
-rw-r--r--drivers/scsi/aic7xxx/aic7770_osm.c3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_inline.h3
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c6
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.h2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm_pci.c2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_inline.h3
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c4
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm_pci.c3
-rw-r--r--drivers/scsi/aic7xxx_old.c316
-rw-r--r--drivers/scsi/aic94xx/Kconfig1
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c3
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c42
-rw-r--r--drivers/scsi/amiga7xx.h2
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c3
-rw-r--r--drivers/scsi/arm/acornscsi.c53
-rw-r--r--drivers/scsi/arm/acornscsi.h4
-rw-r--r--drivers/scsi/arm/arxescsi.c2
-rw-r--r--drivers/scsi/arm/cumana_2.c3
-rw-r--r--drivers/scsi/arm/eesox.c3
-rw-r--r--drivers/scsi/arm/fas216.c50
-rw-r--r--drivers/scsi/arm/fas216.h36
-rw-r--r--drivers/scsi/arm/powertec.c4
-rw-r--r--drivers/scsi/arm/queue.c37
-rw-r--r--drivers/scsi/arm/queue.h28
-rw-r--r--drivers/scsi/arm/scsi.h2
-rw-r--r--drivers/scsi/atari_NCR5380.c2
-rw-r--r--drivers/scsi/atari_dma_emul.c4
-rw-r--r--drivers/scsi/atari_scsi.c10
-rw-r--r--drivers/scsi/atp870u.c2
-rw-r--r--drivers/scsi/bvme6000.h2
-rw-r--r--drivers/scsi/dc395x.c9
-rw-r--r--drivers/scsi/dec_esp.c12
-rw-r--r--drivers/scsi/dmx3191d.c2
-rw-r--r--drivers/scsi/dpt/dpti_i2o.h10
-rw-r--r--drivers/scsi/dpt_i2o.c4
-rw-r--r--drivers/scsi/dpti.h4
-rw-r--r--drivers/scsi/dtc.c2
-rw-r--r--drivers/scsi/eata.c5
-rw-r--r--drivers/scsi/eata_pio.c9
-rw-r--r--drivers/scsi/esp.c4
-rw-r--r--drivers/scsi/fd_mcs.c4
-rw-r--r--drivers/scsi/fdomain.c17
-rw-r--r--drivers/scsi/gdth.c10
-rw-r--r--drivers/scsi/gdth.h10
-rw-r--r--drivers/scsi/gvp11.c2
-rw-r--r--drivers/scsi/hosts.h2
-rw-r--r--drivers/scsi/hptiop.c2
-rw-r--r--drivers/scsi/ibmmca.c3
-rw-r--r--drivers/scsi/ibmvscsi/rpa_vscsi.c5
-rw-r--r--drivers/scsi/ide-scsi.c16
-rw-r--r--drivers/scsi/imm.h1
-rw-r--r--drivers/scsi/in2000.c2
-rw-r--r--drivers/scsi/initio.c21
-rw-r--r--drivers/scsi/ipr.c690
-rw-r--r--drivers/scsi/ipr.h18
-rw-r--r--drivers/scsi/ips.c95
-rw-r--r--drivers/scsi/ips.h16
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c2
-rw-r--r--drivers/scsi/lpfc/lpfc_crtn.h2
-rw-r--r--drivers/scsi/lpfc/lpfc_ct.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_init.c6
-rw-r--r--drivers/scsi/lpfc/lpfc_sli.c2
-rw-r--r--drivers/scsi/mac53c94.c10
-rw-r--r--drivers/scsi/mac_esp.c14
-rw-r--r--drivers/scsi/megaraid.c6
-rw-r--r--drivers/scsi/megaraid.h4
-rw-r--r--drivers/scsi/megaraid/mega_common.h2
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c6
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c368
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h22
-rw-r--r--drivers/scsi/mesh.c12
-rw-r--r--drivers/scsi/mvme147.c2
-rw-r--r--drivers/scsi/mvme16x.h2
-rw-r--r--drivers/scsi/ncr53c8xx.c2
-rw-r--r--drivers/scsi/ncr53c8xx.h2
-rw-r--r--drivers/scsi/nsp32.c6
-rw-r--r--drivers/scsi/nsp32.h42
-rw-r--r--drivers/scsi/osst.c134
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c3
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.h2
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c2
-rw-r--r--drivers/scsi/pluto.c6
-rw-r--r--drivers/scsi/ppa.h1
-rw-r--r--drivers/scsi/psi240i.c7
-rw-r--r--drivers/scsi/qla1280.c12
-rw-r--r--drivers/scsi/qla2xxx/qla_attr.c57
-rw-r--r--drivers/scsi/qla2xxx/qla_dbg.h14
-rw-r--r--drivers/scsi/qla2xxx/qla_def.h42
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h17
-rw-r--r--drivers/scsi/qla2xxx/qla_gs.c228
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c86
-rw-r--r--drivers/scsi/qla2xxx/qla_inline.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_isr.c13
-rw-r--r--drivers/scsi/qla2xxx/qla_mbx.c86
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c56
-rw-r--r--drivers/scsi/qla2xxx/qla_version.h2
-rw-r--r--drivers/scsi/qla4xxx/Kconfig7
-rw-r--r--drivers/scsi/qla4xxx/Makefile5
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.c197
-rw-r--r--drivers/scsi/qla4xxx/ql4_dbg.h55
-rw-r--r--drivers/scsi/qla4xxx/ql4_def.h586
-rw-r--r--drivers/scsi/qla4xxx/ql4_fw.h843
-rw-r--r--drivers/scsi/qla4xxx/ql4_glbl.h78
-rw-r--r--drivers/scsi/qla4xxx/ql4_init.c1340
-rw-r--r--drivers/scsi/qla4xxx/ql4_inline.h84
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c368
-rw-r--r--drivers/scsi/qla4xxx/ql4_isr.c796
-rw-r--r--drivers/scsi/qla4xxx/ql4_mbx.c930
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.c224
-rw-r--r--drivers/scsi/qla4xxx/ql4_nvram.h256
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c1755
-rw-r--r--drivers/scsi/qla4xxx/ql4_version.h13
-rw-r--r--drivers/scsi/qlogicfas408.c8
-rw-r--r--drivers/scsi/qlogicfas408.h2
-rw-r--r--drivers/scsi/qlogicpti.c6
-rw-r--r--drivers/scsi/qlogicpti_asm.c4
-rw-r--r--drivers/scsi/raid_class.c20
-rw-r--r--drivers/scsi/scsi.c15
-rw-r--r--drivers/scsi/scsi_devinfo.c16
-rw-r--r--drivers/scsi/scsi_error.c2
-rw-r--r--drivers/scsi/scsi_lib.c39
-rw-r--r--drivers/scsi/sd.c28
-rw-r--r--drivers/scsi/seagate.c37
-rw-r--r--drivers/scsi/seagate.h19
-rw-r--r--drivers/scsi/sg.c53
-rw-r--r--drivers/scsi/sgiwd93.c2
-rw-r--r--drivers/scsi/sim710.c1
-rw-r--r--drivers/scsi/st.c115
-rw-r--r--drivers/scsi/stex.c199
-rw-r--r--drivers/scsi/sun3_NCR5380.c4
-rw-r--r--drivers/scsi/sun3_scsi.c8
-rw-r--r--drivers/scsi/sun3_scsi_vme.c8
-rw-r--r--drivers/scsi/sym53c416.c3
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c2
-rw-r--r--drivers/scsi/t128.c2
-rw-r--r--drivers/scsi/tmscsim.c20
-rw-r--r--drivers/scsi/u14-34f.c5
-rw-r--r--drivers/scsi/ultrastor.c13
-rw-r--r--drivers/scsi/wd7000.c4
-rw-r--r--drivers/serial/21285.c6
-rw-r--r--drivers/serial/68328serial.c11
-rw-r--r--drivers/serial/68360serial.c6
-rw-r--r--drivers/serial/8250.c53
-rw-r--r--drivers/serial/8250_acorn.c9
-rw-r--r--drivers/serial/8250_gsc.c5
-rw-r--r--drivers/serial/8250_pci.c4
-rw-r--r--drivers/serial/8250_pnp.c13
-rw-r--r--drivers/serial/Kconfig76
-rw-r--r--drivers/serial/Makefile2
-rw-r--r--drivers/serial/amba-pl010.c15
-rw-r--r--drivers/serial/amba-pl011.c15
-rw-r--r--drivers/serial/at91_serial.c980
-rw-r--r--drivers/serial/atmel_serial.c992
-rw-r--r--drivers/serial/atmel_serial.h123
-rw-r--r--drivers/serial/clps711x.c6
-rw-r--r--drivers/serial/cpm_uart/cpm_uart.h1
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_core.c40
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.h2
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.c143
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm2.h4
-rw-r--r--drivers/serial/crisv10.c8
-rw-r--r--drivers/serial/dz.c2
-rw-r--r--drivers/serial/icom.c3
-rw-r--r--drivers/serial/imx.c8
-rw-r--r--drivers/serial/ioc3_serial.c10
-rw-r--r--drivers/serial/ioc4_serial.c8
-rw-r--r--drivers/serial/ip22zilog.c34
-rw-r--r--drivers/serial/jsm/jsm.h2
-rw-r--r--drivers/serial/jsm/jsm_neo.c4
-rw-r--r--drivers/serial/m32r_sio.c21
-rw-r--r--drivers/serial/mcfserial.c4
-rw-r--r--drivers/serial/mpc52xx_uart.c31
-rw-r--r--drivers/serial/mpsc.c20
-rw-r--r--drivers/serial/mux.c4
-rw-r--r--drivers/serial/netx-serial.c12
-rw-r--r--drivers/serial/pmac_zilog.c17
-rw-r--r--drivers/serial/pxa.c12
-rw-r--r--drivers/serial/s3c2410.c6
-rw-r--r--drivers/serial/sa1100.c8
-rw-r--r--drivers/serial/serial_core.c20
-rw-r--r--drivers/serial/serial_cs.c292
-rw-r--r--drivers/serial/serial_lh7a40x.c16
-rw-r--r--drivers/serial/serial_txx9.c10
-rw-r--r--drivers/serial/sh-sci.c1174
-rw-r--r--drivers/serial/sh-sci.h89
-rw-r--r--drivers/serial/sn_console.c13
-rw-r--r--drivers/serial/sunhv.c10
-rw-r--r--drivers/serial/sunsab.c13
-rw-r--r--drivers/serial/sunsu.c22
-rw-r--r--drivers/serial/sunzilog.c41
-rw-r--r--drivers/serial/v850e_uart.c4
-rw-r--r--drivers/serial/vr41xx_siu.c9
-rw-r--r--drivers/sn/Kconfig13
-rw-r--r--drivers/sn/Makefile1
-rw-r--r--drivers/sn/ioc3.c14
-rw-r--r--drivers/spi/pxa2xx_spi.c6
-rw-r--r--drivers/spi/spi_mpc83xx.c3
-rw-r--r--drivers/spi/spi_s3c24xx.c3
-rw-r--r--drivers/spi/spi_s3c24xx_gpio.c1
-rw-r--r--drivers/tc/zs.c10
-rw-r--r--drivers/telephony/ixj.c11
-rw-r--r--drivers/usb/Kconfig1
-rw-r--r--drivers/usb/Makefile12
-rw-r--r--drivers/usb/atm/Kconfig2
-rw-r--r--drivers/usb/atm/cxacru.c5
-rw-r--r--drivers/usb/atm/speedtch.c95
-rw-r--r--drivers/usb/atm/ueagle-atm.c135
-rw-r--r--drivers/usb/atm/usbatm.c7
-rw-r--r--drivers/usb/class/cdc-acm.c37
-rw-r--r--drivers/usb/class/usblp.c98
-rw-r--r--drivers/usb/core/Makefile2
-rw-r--r--drivers/usb/core/buffer.c4
-rw-r--r--drivers/usb/core/config.c4
-rw-r--r--drivers/usb/core/devices.c6
-rw-r--r--drivers/usb/core/devio.c94
-rw-r--r--drivers/usb/core/driver.c1012
-rw-r--r--drivers/usb/core/endpoint.c42
-rw-r--r--drivers/usb/core/file.c4
-rw-r--r--drivers/usb/core/generic.c207
-rw-r--r--drivers/usb/core/hcd-pci.c16
-rw-r--r--drivers/usb/core/hcd.c269
-rw-r--r--drivers/usb/core/hcd.h65
-rw-r--r--drivers/usb/core/hub.c557
-rw-r--r--drivers/usb/core/hub.h3
-rw-r--r--drivers/usb/core/inode.c26
-rw-r--r--drivers/usb/core/message.c152
-rw-r--r--drivers/usb/core/notify.c3
-rw-r--r--drivers/usb/core/sysfs.c60
-rw-r--r--drivers/usb/core/urb.c15
-rw-r--r--drivers/usb/core/usb.c571
-rw-r--r--drivers/usb/core/usb.h95
-rw-r--r--drivers/usb/gadget/Kconfig18
-rw-r--r--drivers/usb/gadget/Makefile2
-rw-r--r--drivers/usb/gadget/at91_udc.c12
-rw-r--r--drivers/usb/gadget/dummy_hcd.c43
-rw-r--r--drivers/usb/gadget/ether.c11
-rw-r--r--drivers/usb/gadget/file_storage.c37
-rw-r--r--drivers/usb/gadget/gmidi.c1336
-rw-r--r--drivers/usb/gadget/goku_udc.c2
-rw-r--r--drivers/usb/gadget/inode.c149
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c2
-rw-r--r--drivers/usb/gadget/net2280.c182
-rw-r--r--drivers/usb/gadget/omap_udc.c15
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c79
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h24
-rw-r--r--drivers/usb/gadget/serial.c7
-rw-r--r--drivers/usb/gadget/zero.c2
-rw-r--r--drivers/usb/host/Kconfig29
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-au1xxx.c2
-rw-r--r--drivers/usb/host/ehci-dbg.c27
-rw-r--r--drivers/usb/host/ehci-fsl.c2
-rw-r--r--drivers/usb/host/ehci-hcd.c47
-rw-r--r--drivers/usb/host/ehci-hub.c14
-rw-r--r--drivers/usb/host/ehci-mem.c14
-rw-r--r--drivers/usb/host/ehci-pci.c4
-rw-r--r--drivers/usb/host/ehci-q.c41
-rw-r--r--drivers/usb/host/ehci-sched.c47
-rw-r--r--drivers/usb/host/ehci.h37
-rw-r--r--drivers/usb/host/hc_crisv10.c12
-rw-r--r--drivers/usb/host/isp116x-hcd.c20
-rw-r--r--drivers/usb/host/isp116x.h2
-rw-r--r--drivers/usb/host/ohci-at91.c7
-rw-r--r--drivers/usb/host/ohci-au1xxx.c7
-rw-r--r--drivers/usb/host/ohci-dbg.c18
-rw-r--r--drivers/usb/host/ohci-ep93xx.c3
-rw-r--r--drivers/usb/host/ohci-hcd.c78
-rw-r--r--drivers/usb/host/ohci-hub.c281
-rw-r--r--drivers/usb/host/ohci-lh7a404.c7
-rw-r--r--drivers/usb/host/ohci-mem.c1
-rw-r--r--drivers/usb/host/ohci-omap.c120
-rw-r--r--drivers/usb/host/ohci-pci.c11
-rw-r--r--drivers/usb/host/ohci-pnx4008.c479
-rw-r--r--drivers/usb/host/ohci-ppc-soc.c3
-rw-r--r--drivers/usb/host/ohci-pxa27x.c3
-rw-r--r--drivers/usb/host/ohci-q.c16
-rw-r--r--drivers/usb/host/ohci-s3c2410.c5
-rw-r--r--drivers/usb/host/ohci-sa1111.c5
-rw-r--r--drivers/usb/host/ohci.h5
-rw-r--r--drivers/usb/host/sl811-hcd.c25
-rw-r--r--drivers/usb/host/u132-hcd.c3294
-rw-r--r--drivers/usb/host/uhci-debug.c6
-rw-r--r--drivers/usb/host/uhci-hcd.c60
-rw-r--r--drivers/usb/host/uhci-hub.c14
-rw-r--r--drivers/usb/host/uhci-q.c15
-rw-r--r--drivers/usb/image/mdc800.c10
-rw-r--r--drivers/usb/image/microtek.c28
-rw-r--r--drivers/usb/image/microtek.h4
-rw-r--r--drivers/usb/input/Kconfig38
-rw-r--r--drivers/usb/input/Makefile6
-rw-r--r--drivers/usb/input/acecad.c7
-rw-r--r--drivers/usb/input/aiptek.c13
-rw-r--r--drivers/usb/input/appletouch.c7
-rw-r--r--drivers/usb/input/ati_remote.c25
-rw-r--r--drivers/usb/input/ati_remote2.c14
-rw-r--r--drivers/usb/input/hid-core.c90
-rw-r--r--drivers/usb/input/hid-ff.c49
-rw-r--r--drivers/usb/input/hid-input.c27
-rw-r--r--drivers/usb/input/hid-lgff.c523
-rw-r--r--drivers/usb/input/hid-pidff.c1330
-rw-r--r--drivers/usb/input/hid-tmff.c399
-rw-r--r--drivers/usb/input/hid-zpff.c110
-rw-r--r--drivers/usb/input/hid.h36
-rw-r--r--drivers/usb/input/hiddev.c4
-rw-r--r--drivers/usb/input/itmtouch.c16
-rw-r--r--drivers/usb/input/kbtab.c2
-rw-r--r--drivers/usb/input/keyspan_remote.c10
-rw-r--r--drivers/usb/input/mtouchusb.c5
-rw-r--r--drivers/usb/input/pid.c295
-rw-r--r--drivers/usb/input/pid.h62
-rw-r--r--drivers/usb/input/powermate.c11
-rw-r--r--drivers/usb/input/touchkitusb.c17
-rw-r--r--drivers/usb/input/usbkbd.c6
-rw-r--r--drivers/usb/input/usbmouse.c6
-rw-r--r--drivers/usb/input/usbtouchscreen.c295
-rw-r--r--drivers/usb/input/wacom.c1003
-rw-r--r--drivers/usb/input/wacom.h132
-rw-r--r--drivers/usb/input/wacom_sys.c312
-rw-r--r--drivers/usb/input/wacom_wac.c648
-rw-r--r--drivers/usb/input/wacom_wac.h48
-rw-r--r--drivers/usb/input/xpad.c147
-rw-r--r--drivers/usb/input/yealink.c11
-rw-r--r--drivers/usb/misc/Kconfig71
-rw-r--r--drivers/usb/misc/Makefile6
-rw-r--r--drivers/usb/misc/adutux.c901
-rw-r--r--drivers/usb/misc/appledisplay.c3
-rw-r--r--drivers/usb/misc/auerswald.c36
-rw-r--r--drivers/usb/misc/cypress_cy7c63.c19
-rw-r--r--drivers/usb/misc/cytherm.c35
-rw-r--r--drivers/usb/misc/ftdi-elan.c2794
-rw-r--r--drivers/usb/misc/idmouse.c2
-rw-r--r--drivers/usb/misc/ldusb.c14
-rw-r--r--drivers/usb/misc/legousbtower.c10
-rw-r--r--drivers/usb/misc/phidget.c43
-rw-r--r--drivers/usb/misc/phidget.h12
-rw-r--r--drivers/usb/misc/phidgetkit.c374
-rw-r--r--drivers/usb/misc/phidgetmotorcontrol.c466
-rw-r--r--drivers/usb/misc/phidgetservo.c117
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb.c7
-rw-r--r--drivers/usb/misc/sisusbvga/sisusb_con.c1
-rw-r--r--drivers/usb/misc/trancevibrator.c159
-rw-r--r--drivers/usb/misc/usb_u132.h97
-rw-r--r--drivers/usb/misc/usblcd.c12
-rw-r--r--drivers/usb/misc/usbled.c20
-rw-r--r--drivers/usb/misc/usbtest.c8
-rw-r--r--drivers/usb/misc/uss720.c4
-rw-r--r--drivers/usb/mon/mon_main.c7
-rw-r--r--drivers/usb/mon/mon_stat.c4
-rw-r--r--drivers/usb/mon/mon_text.c19
-rw-r--r--drivers/usb/mon/usb_mon.h5
-rw-r--r--drivers/usb/net/Kconfig8
-rw-r--r--drivers/usb/net/Makefile1
-rw-r--r--drivers/usb/net/asix.c999
-rw-r--r--drivers/usb/net/catc.c8
-rw-r--r--drivers/usb/net/cdc_ether.c2
-rw-r--r--drivers/usb/net/gl620a.c2
-rw-r--r--drivers/usb/net/kaweth.c215
-rw-r--r--drivers/usb/net/mcs7830.c534
-rw-r--r--drivers/usb/net/net1080.c17
-rw-r--r--drivers/usb/net/pegasus.c34
-rw-r--r--drivers/usb/net/rtl8150.c14
-rw-r--r--drivers/usb/net/usbnet.c109
-rw-r--r--drivers/usb/net/usbnet.h6
-rw-r--r--drivers/usb/serial/Kconfig38
-rw-r--r--drivers/usb/serial/Makefile3
-rw-r--r--drivers/usb/serial/aircable.c625
-rw-r--r--drivers/usb/serial/airprime.c260
-rw-r--r--drivers/usb/serial/ark3116.c233
-rw-r--r--drivers/usb/serial/belkin_sa.c4
-rw-r--r--drivers/usb/serial/cp2101.c1
-rw-r--r--drivers/usb/serial/cyberjack.c18
-rw-r--r--drivers/usb/serial/cypress_m8.c137
-rw-r--r--drivers/usb/serial/digi_acceleport.c8
-rw-r--r--drivers/usb/serial/empeg.c8
-rw-r--r--drivers/usb/serial/ftdi_sio.c296
-rw-r--r--drivers/usb/serial/ftdi_sio.h10
-rw-r--r--drivers/usb/serial/garmin_gps.c225
-rw-r--r--drivers/usb/serial/generic.c10
-rw-r--r--drivers/usb/serial/io_edgeport.c16
-rw-r--r--drivers/usb/serial/io_ti.c6
-rw-r--r--drivers/usb/serial/ipaq.c47
-rw-r--r--drivers/usb/serial/ipw.c10
-rw-r--r--drivers/usb/serial/ir-usb.c14
-rw-r--r--drivers/usb/serial/keyspan.c52
-rw-r--r--drivers/usb/serial/keyspan_pda.c10
-rw-r--r--drivers/usb/serial/kl5kusb105.c8
-rw-r--r--drivers/usb/serial/kobil_sct.c8
-rw-r--r--drivers/usb/serial/mct_u232.c4
-rw-r--r--drivers/usb/serial/mos7720.c1683
-rw-r--r--drivers/usb/serial/mos7840.c2948
-rw-r--r--drivers/usb/serial/navman.c2
-rw-r--r--drivers/usb/serial/omninet.c14
-rw-r--r--drivers/usb/serial/option.c10
-rw-r--r--drivers/usb/serial/pl2303.c828
-rw-r--r--drivers/usb/serial/pl2303.h8
-rw-r--r--drivers/usb/serial/safe_serial.c8
-rw-r--r--drivers/usb/serial/sierra.c697
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c12
-rw-r--r--drivers/usb/serial/usb-serial.c30
-rw-r--r--drivers/usb/serial/visor.c12
-rw-r--r--drivers/usb/serial/whiteheat.c16
-rw-r--r--drivers/usb/storage/Kconfig19
-rw-r--r--drivers/usb/storage/Makefile1
-rw-r--r--drivers/usb/storage/initializers.c73
-rw-r--r--drivers/usb/storage/initializers.h1
-rw-r--r--drivers/usb/storage/karma.c155
-rw-r--r--drivers/usb/storage/karma.h7
-rw-r--r--drivers/usb/storage/libusual.c10
-rw-r--r--drivers/usb/storage/onetouch.c11
-rw-r--r--drivers/usb/storage/scsiglue.c15
-rw-r--r--drivers/usb/storage/transport.c7
-rw-r--r--drivers/usb/storage/unusual_devs.h56
-rw-r--r--drivers/usb/storage/usb.c11
-rw-r--r--drivers/usb/usb-skeleton.c103
-rw-r--r--drivers/video/Kconfig48
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/amifb.c4
-rw-r--r--drivers/video/arcfb.c3
-rw-r--r--drivers/video/atafb.c2
-rw-r--r--drivers/video/aty/atyfb.h6
-rw-r--r--drivers/video/aty/atyfb_base.c13
-rw-r--r--drivers/video/aty/mach64_ct.c2
-rw-r--r--drivers/video/aty/radeon_i2c.c106
-rw-r--r--drivers/video/aty/radeon_pm.c3
-rw-r--r--drivers/video/au1100fb.c30
-rw-r--r--drivers/video/au1200fb.c2
-rw-r--r--drivers/video/backlight/hp680_bl.c4
-rw-r--r--drivers/video/backlight/locomolcd.c30
-rw-r--r--drivers/video/console/Kconfig2
-rw-r--r--drivers/video/console/fbcon.c58
-rw-r--r--drivers/video/console/fbcon.h2
-rw-r--r--drivers/video/console/fbcon_ccw.c2
-rw-r--r--drivers/video/console/fbcon_cw.c2
-rw-r--r--drivers/video/console/fbcon_ud.c2
-rw-r--r--drivers/video/console/softcursor.c31
-rw-r--r--drivers/video/controlfb.c8
-rw-r--r--drivers/video/fb_ddc.c116
-rw-r--r--drivers/video/fbmem.c3
-rw-r--r--drivers/video/fbsysfs.c35
-rw-r--r--drivers/video/hitfb.c229
-rw-r--r--drivers/video/i810/i810-i2c.c43
-rw-r--r--drivers/video/i810/i810_main.c6
-rw-r--r--drivers/video/igafb.c7
-rw-r--r--drivers/video/intelfb/Makefile4
-rw-r--r--drivers/video/intelfb/intelfb.h79
-rw-r--r--drivers/video/intelfb/intelfb_i2c.c199
-rw-r--r--drivers/video/intelfb/intelfbdrv.c64
-rw-r--r--drivers/video/intelfb/intelfbhw.c136
-rw-r--r--drivers/video/intelfb/intelfbhw.h25
-rw-r--r--drivers/video/matrox/i2c-matroxfb.c12
-rw-r--r--drivers/video/matrox/matroxfb_base.c14
-rw-r--r--drivers/video/mbx/mbxfb.c21
-rw-r--r--drivers/video/nvidia/nvidia.c16
-rw-r--r--drivers/video/platinumfb.c5
-rw-r--r--drivers/video/pvr2fb.c26
-rw-r--r--drivers/video/pxafb.c108
-rw-r--r--drivers/video/pxafb.h4
-rw-r--r--drivers/video/riva/fbdev.c10
-rw-r--r--drivers/video/riva/rivafb-i2c.c44
-rw-r--r--drivers/video/s3c2410fb.c2
-rw-r--r--drivers/video/s3c2410fb.h2
-rw-r--r--drivers/video/sa1100fb.c2
-rw-r--r--drivers/video/savage/savagefb-i2c.c50
-rw-r--r--drivers/video/sis/init.h7
-rw-r--r--drivers/video/sis/init301.h7
-rw-r--r--drivers/video/sis/initextlfb.c4
-rw-r--r--drivers/video/sis/osdef.h4
-rw-r--r--drivers/video/sis/sis_accel.c26
-rw-r--r--drivers/video/sis/sis_accel.h14
-rw-r--r--drivers/video/sis/sis_main.c232
-rw-r--r--drivers/video/sis/sis_main.h65
-rw-r--r--drivers/video/sis/vgatypes.h2
-rw-r--r--drivers/video/sstfb.c170
-rw-r--r--drivers/video/valkyriefb.c4
-rw-r--r--drivers/w1/Kconfig3
-rw-r--r--fs/9p/v9fs.c6
-rw-r--r--fs/9p/vfs_inode.c6
-rw-r--r--fs/Kconfig208
-rw-r--r--fs/Makefile20
-rw-r--r--fs/adfs/file.c6
-rw-r--r--fs/adfs/inode.c1
-rw-r--r--fs/adfs/super.c6
-rw-r--r--fs/affs/file.c6
-rw-r--r--fs/affs/super.c6
-rw-r--r--fs/afs/dir.c12
-rw-r--r--fs/afs/file.c2
-rw-r--r--fs/afs/inode.c1
-rw-r--r--fs/afs/proc.c2
-rw-r--r--fs/afs/vlocation.c3
-rw-r--r--fs/afs/volume.c3
-rw-r--r--fs/aio.c170
-rw-r--r--fs/autofs/autofs_i.h1
-rw-r--r--fs/autofs/dirhash.c1
-rw-r--r--fs/autofs/init.c2
-rw-r--r--fs/autofs/inode.c10
-rw-r--r--fs/autofs/root.c4
-rw-r--r--fs/autofs/symlink.c2
-rw-r--r--fs/autofs4/autofs_i.h3
-rw-r--r--fs/autofs4/init.c2
-rw-r--r--fs/autofs4/inode.c23
-rw-r--r--fs/autofs4/root.c54
-rw-r--r--fs/autofs4/waitq.c1
-rw-r--r--fs/bad_inode.c2
-rw-r--r--fs/befs/befs.h6
-rw-r--r--fs/befs/befs_fs_types.h114
-rw-r--r--fs/befs/btree.c29
-rw-r--r--fs/befs/datastream.c11
-rw-r--r--fs/befs/debug.c12
-rw-r--r--fs/befs/endian.h57
-rw-r--r--fs/befs/inode.c1
-rw-r--r--fs/befs/linuxvfs.c6
-rw-r--r--fs/befs/super.c1
-rw-r--r--fs/bfs/dir.c13
-rw-r--r--fs/bfs/file.c6
-rw-r--r--fs/bfs/inode.c10
-rw-r--r--fs/binfmt_aout.c14
-rw-r--r--fs/binfmt_elf.c91
-rw-r--r--fs/binfmt_elf_fdpic.c7
-rw-r--r--fs/binfmt_misc.c15
-rw-r--r--fs/binfmt_som.c18
-rw-r--r--fs/bio.c13
-rw-r--r--fs/block_dev.c83
-rw-r--r--fs/buffer.c213
-rw-r--r--fs/char_dev.c108
-rw-r--r--fs/cifs/README6
-rw-r--r--fs/cifs/cifsacl.h4
-rw-r--r--fs/cifs/cifsencrypt.h2
-rw-r--r--fs/cifs/cifsfs.c70
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h15
-rw-r--r--fs/cifs/cifspdu.h12
-rw-r--r--fs/cifs/cifsproto.h12
-rw-r--r--fs/cifs/cifssmb.c102
-rw-r--r--fs/cifs/connect.c53
-rw-r--r--fs/cifs/file.c1
-rw-r--r--fs/cifs/inode.c27
-rw-r--r--fs/cifs/ioctl.c7
-rw-r--r--fs/cifs/link.c6
-rw-r--r--fs/cifs/md5.c8
-rw-r--r--fs/cifs/md5.h8
-rw-r--r--fs/cifs/misc.c44
-rw-r--r--fs/cifs/netmisc.c58
-rw-r--r--fs/cifs/readdir.c32
-rw-r--r--fs/cifs/sess.c29
-rw-r--r--fs/cifs/smbdes.c6
-rw-r--r--fs/cifs/smbencrypt.c11
-rw-r--r--fs/coda/coda_linux.c2
-rw-r--r--fs/coda/dir.c8
-rw-r--r--fs/coda/inode.c3
-rw-r--r--fs/compat.c74
-rw-r--r--fs/compat_ioctl.c416
-rw-r--r--fs/configfs/dir.c4
-rw-r--r--fs/configfs/file.c21
-rw-r--r--fs/configfs/inode.c4
-rw-r--r--fs/configfs/item.c2
-rw-r--r--fs/configfs/mount.c2
-rw-r--r--fs/cramfs/inode.c15
-rw-r--r--fs/cramfs/uncompress.c3
-rw-r--r--fs/dcache.c280
-rw-r--r--fs/debugfs/file.c4
-rw-r--r--fs/debugfs/inode.c11
-rw-r--r--fs/devpts/inode.c6
-rw-r--r--fs/dlm/Kconfig20
-rw-r--r--fs/dlm/Makefile19
-rw-r--r--fs/dlm/ast.c173
-rw-r--r--fs/dlm/ast.h26
-rw-r--r--fs/dlm/config.c789
-rw-r--r--fs/dlm/config.h42
-rw-r--r--fs/dlm/debug_fs.c387
-rw-r--r--fs/dlm/dir.c423
-rw-r--r--fs/dlm/dir.h30
-rw-r--r--fs/dlm/dlm_internal.h543
-rw-r--r--fs/dlm/lock.c3871
-rw-r--r--fs/dlm/lock.h62
-rw-r--r--fs/dlm/lockspace.c717
-rw-r--r--fs/dlm/lockspace.h25
-rw-r--r--fs/dlm/lowcomms.c1239
-rw-r--r--fs/dlm/lowcomms.h26
-rw-r--r--fs/dlm/lvb_table.h18
-rw-r--r--fs/dlm/main.c97
-rw-r--r--fs/dlm/member.c327
-rw-r--r--fs/dlm/member.h24
-rw-r--r--fs/dlm/memory.c116
-rw-r--r--fs/dlm/memory.h29
-rw-r--r--fs/dlm/midcomms.c140
-rw-r--r--fs/dlm/midcomms.h21
-rw-r--r--fs/dlm/rcom.c472
-rw-r--r--fs/dlm/rcom.h24
-rw-r--r--fs/dlm/recover.c765
-rw-r--r--fs/dlm/recover.h34
-rw-r--r--fs/dlm/recoverd.c290
-rw-r--r--fs/dlm/recoverd.h24
-rw-r--r--fs/dlm/requestqueue.c184
-rw-r--r--fs/dlm/requestqueue.h22
-rw-r--r--fs/dlm/user.c788
-rw-r--r--fs/dlm/user.h16
-rw-r--r--fs/dlm/util.c161
-rw-r--r--fs/dlm/util.h22
-rw-r--r--fs/dnotify.c2
-rw-r--r--fs/dquot.c5
-rw-r--r--fs/ecryptfs/Makefile7
-rw-r--r--fs/ecryptfs/crypto.c1659
-rw-r--r--fs/ecryptfs/debug.c123
-rw-r--r--fs/ecryptfs/dentry.c87
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h482
-rw-r--r--fs/ecryptfs/file.c440
-rw-r--r--fs/ecryptfs/inode.c1079
-rw-r--r--fs/ecryptfs/keystore.c1061
-rw-r--r--fs/ecryptfs/main.c828
-rw-r--r--fs/ecryptfs/mmap.c788
-rw-r--r--fs/ecryptfs/super.c198
-rw-r--r--fs/efs/super.c6
-rw-r--r--fs/eventpoll.c62
-rw-r--r--fs/exec.c83
-rw-r--r--fs/exportfs/expfs.c2
-rw-r--r--fs/ext2/acl.c4
-rw-r--r--fs/ext2/dir.c3
-rw-r--r--fs/ext2/ext2.h1
-rw-r--r--fs/ext2/file.c12
-rw-r--r--fs/ext2/ialloc.c1
-rw-r--r--fs/ext2/inode.c1
-rw-r--r--fs/ext2/ioctl.c32
-rw-r--r--fs/ext2/namei.c2
-rw-r--r--fs/ext2/super.c54
-rw-r--r--fs/ext2/xattr.c3
-rw-r--r--fs/ext3/acl.c6
-rw-r--r--fs/ext3/balloc.c350
-rw-r--r--fs/ext3/bitmap.c2
-rw-r--r--fs/ext3/dir.c22
-rw-r--r--fs/ext3/file.c12
-rw-r--r--fs/ext3/fsync.c6
-rw-r--r--fs/ext3/hash.c8
-rw-r--r--fs/ext3/ialloc.c55
-rw-r--r--fs/ext3/inode.c82
-rw-r--r--fs/ext3/ioctl.c55
-rw-r--r--fs/ext3/namei.c75
-rw-r--r--fs/ext3/resize.c42
-rw-r--r--fs/ext3/super.c112
-rw-r--r--fs/ext3/xattr.c16
-rw-r--r--fs/ext4/Makefile12
-rw-r--r--fs/ext4/acl.c551
-rw-r--r--fs/ext4/acl.h81
-rw-r--r--fs/ext4/balloc.c1833
-rw-r--r--fs/ext4/bitmap.c32
-rw-r--r--fs/ext4/dir.c518
-rw-r--r--fs/ext4/extents.c2152
-rw-r--r--fs/ext4/file.c139
-rw-r--r--fs/ext4/fsync.c88
-rw-r--r--fs/ext4/hash.c152
-rw-r--r--fs/ext4/ialloc.c772
-rw-r--r--fs/ext4/inode.c3233
-rw-r--r--fs/ext4/ioctl.c306
-rw-r--r--fs/ext4/namei.c2395
-rw-r--r--fs/ext4/namei.h8
-rw-r--r--fs/ext4/resize.c1045
-rw-r--r--fs/ext4/super.c2829
-rw-r--r--fs/ext4/symlink.c54
-rw-r--r--fs/ext4/xattr.c1317
-rw-r--r--fs/ext4/xattr.h145
-rw-r--r--fs/ext4/xattr_security.c77
-rw-r--r--fs/ext4/xattr_trusted.c62
-rw-r--r--fs/ext4/xattr_user.c64
-rw-r--r--fs/fat/cache.c3
-rw-r--r--fs/fat/dir.c58
-rw-r--r--fs/fat/file.c16
-rw-r--r--fs/fat/inode.c99
-rw-r--r--fs/fcntl.c79
-rw-r--r--fs/file.c84
-rw-r--r--fs/file_table.c3
-rw-r--r--fs/filesystems.c2
-rw-r--r--fs/freevxfs/vxfs.h2
-rw-r--r--fs/freevxfs/vxfs_inode.c5
-rw-r--r--fs/freevxfs/vxfs_super.c11
-rw-r--r--fs/fs-writeback.c9
-rw-r--r--fs/fuse/control.c8
-rw-r--r--fs/fuse/dev.c39
-rw-r--r--fs/fuse/dir.c113
-rw-r--r--fs/fuse/file.c18
-rw-r--r--fs/fuse/fuse_i.h3
-rw-r--r--fs/fuse/inode.c17
-rw-r--r--fs/generic_acl.c197
-rw-r--r--fs/gfs2/Kconfig44
-rw-r--r--fs/gfs2/Makefile10
-rw-r--r--fs/gfs2/acl.c309
-rw-r--r--fs/gfs2/acl.h39
-rw-r--r--fs/gfs2/bmap.c1222
-rw-r--r--fs/gfs2/bmap.h31
-rw-r--r--fs/gfs2/daemon.c196
-rw-r--r--fs/gfs2/daemon.h19
-rw-r--r--fs/gfs2/dir.c1957
-rw-r--r--fs/gfs2/dir.h79
-rw-r--r--fs/gfs2/eaops.c230
-rw-r--r--fs/gfs2/eaops.h30
-rw-r--r--fs/gfs2/eattr.c1501
-rw-r--r--fs/gfs2/eattr.h100
-rw-r--r--fs/gfs2/gfs2.h31
-rw-r--r--fs/gfs2/glock.c2231
-rw-r--r--fs/gfs2/glock.h153
-rw-r--r--fs/gfs2/glops.c615
-rw-r--r--fs/gfs2/glops.h25
-rw-r--r--fs/gfs2/incore.h634
-rw-r--r--fs/gfs2/inode.c1379
-rw-r--r--fs/gfs2/inode.h56
-rw-r--r--fs/gfs2/lm.c217
-rw-r--r--fs/gfs2/lm.h42
-rw-r--r--fs/gfs2/locking.c184
-rw-r--r--fs/gfs2/locking/dlm/Makefile3
-rw-r--r--fs/gfs2/locking/dlm/lock.c524
-rw-r--r--fs/gfs2/locking/dlm/lock_dlm.h187
-rw-r--r--fs/gfs2/locking/dlm/main.c64
-rw-r--r--fs/gfs2/locking/dlm/mount.c255
-rw-r--r--fs/gfs2/locking/dlm/plock.c301
-rw-r--r--fs/gfs2/locking/dlm/sysfs.c226
-rw-r--r--fs/gfs2/locking/dlm/thread.c359
-rw-r--r--fs/gfs2/locking/nolock/Makefile3
-rw-r--r--fs/gfs2/locking/nolock/main.c246
-rw-r--r--fs/gfs2/log.c688
-rw-r--r--fs/gfs2/log.h65
-rw-r--r--fs/gfs2/lops.c809
-rw-r--r--fs/gfs2/lops.h99
-rw-r--r--fs/gfs2/main.c150
-rw-r--r--fs/gfs2/meta_io.c590
-rw-r--r--fs/gfs2/meta_io.h78
-rw-r--r--fs/gfs2/mount.c214
-rw-r--r--fs/gfs2/mount.h17
-rw-r--r--fs/gfs2/ondisk.c308
-rw-r--r--fs/gfs2/ops_address.c793
-rw-r--r--fs/gfs2/ops_address.h22
-rw-r--r--fs/gfs2/ops_dentry.c119
-rw-r--r--fs/gfs2/ops_dentry.h17
-rw-r--r--fs/gfs2/ops_export.c298
-rw-r--r--fs/gfs2/ops_export.h22
-rw-r--r--fs/gfs2/ops_file.c661
-rw-r--r--fs/gfs2/ops_file.h24
-rw-r--r--fs/gfs2/ops_fstype.c925
-rw-r--r--fs/gfs2/ops_fstype.h18
-rw-r--r--fs/gfs2/ops_inode.c1151
-rw-r--r--fs/gfs2/ops_inode.h20
-rw-r--r--fs/gfs2/ops_super.c468
-rw-r--r--fs/gfs2/ops_super.h17
-rw-r--r--fs/gfs2/ops_vm.c184
-rw-r--r--fs/gfs2/ops_vm.h18
-rw-r--r--fs/gfs2/quota.c1228
-rw-r--r--fs/gfs2/quota.h35
-rw-r--r--fs/gfs2/recovery.c571
-rw-r--r--fs/gfs2/recovery.h34
-rw-r--r--fs/gfs2/rgrp.c1513
-rw-r--r--fs/gfs2/rgrp.h69
-rw-r--r--fs/gfs2/super.c976
-rw-r--r--fs/gfs2/super.h55
-rw-r--r--fs/gfs2/sys.c583
-rw-r--r--fs/gfs2/sys.h27
-rw-r--r--fs/gfs2/trans.c184
-rw-r--r--fs/gfs2/trans.h39
-rw-r--r--fs/gfs2/util.c245
-rw-r--r--fs/gfs2/util.h170
-rw-r--r--fs/hfs/bnode.c3
-rw-r--r--fs/hfs/btree.c3
-rw-r--r--fs/hfs/dir.c4
-rw-r--r--fs/hfs/inode.c8
-rw-r--r--fs/hfs/super.c6
-rw-r--r--fs/hfsplus/bnode.c3
-rw-r--r--fs/hfsplus/btree.c3
-rw-r--r--fs/hfsplus/dir.c8
-rw-r--r--fs/hfsplus/hfsplus_fs.h8
-rw-r--r--fs/hfsplus/inode.c8
-rw-r--r--fs/hfsplus/ioctl.c17
-rw-r--r--fs/hfsplus/part_tbl.c2
-rw-r--r--fs/hfsplus/super.c3
-rw-r--r--fs/hostfs/hostfs_kern.c7
-rw-r--r--fs/hpfs/buffer.c2
-rw-r--r--fs/hpfs/file.c6
-rw-r--r--fs/hpfs/inode.c12
-rw-r--r--fs/hpfs/namei.c14
-rw-r--r--fs/hpfs/super.c6
-rw-r--r--fs/hppfs/hppfs_kern.c3
-rw-r--r--fs/hugetlbfs/inode.c9
-rw-r--r--fs/inode.c78
-rw-r--r--fs/internal.h55
-rw-r--r--fs/ioprio.c24
-rw-r--r--fs/isofs/inode.c58
-rw-r--r--fs/isofs/joliet.c10
-rw-r--r--fs/isofs/namei.c1
-rw-r--r--fs/jbd/checkpoint.c33
-rw-r--r--fs/jbd/commit.c2
-rw-r--r--fs/jbd/journal.c98
-rw-r--r--fs/jbd/recovery.c58
-rw-r--r--fs/jbd/revoke.c70
-rw-r--r--fs/jbd/transaction.c139
-rw-r--r--fs/jbd2/Makefile7
-rw-r--r--fs/jbd2/checkpoint.c697
-rw-r--r--fs/jbd2/commit.c920
-rw-r--r--fs/jbd2/journal.c2084
-rw-r--r--fs/jbd2/recovery.c609
-rw-r--r--fs/jbd2/revoke.c712
-rw-r--r--fs/jbd2/transaction.c2081
-rw-r--r--fs/jffs/inode-v23.c53
-rw-r--r--fs/jffs/intrep.c11
-rw-r--r--fs/jffs/jffs_fm.c6
-rw-r--r--fs/jffs2/dir.c12
-rw-r--r--fs/jffs2/file.c6
-rw-r--r--fs/jffs2/fs.c8
-rw-r--r--fs/jffs2/super.c11
-rw-r--r--fs/jfs/acl.c8
-rw-r--r--fs/jfs/endian24.h2
-rw-r--r--fs/jfs/file.c14
-rw-r--r--fs/jfs/inode.c10
-rw-r--r--fs/jfs/ioctl.c15
-rw-r--r--fs/jfs/jfs_acl.h8
-rw-r--r--fs/jfs/jfs_btree.h6
-rw-r--r--fs/jfs/jfs_debug.c6
-rw-r--r--fs/jfs/jfs_dinode.h8
-rw-r--r--fs/jfs/jfs_dmap.c192
-rw-r--r--fs/jfs/jfs_dmap.h28
-rw-r--r--fs/jfs/jfs_dtree.c18
-rw-r--r--fs/jfs/jfs_dtree.h10
-rw-r--r--fs/jfs/jfs_extent.c58
-rw-r--r--fs/jfs/jfs_extent.h12
-rw-r--r--fs/jfs/jfs_filsys.h24
-rw-r--r--fs/jfs/jfs_imap.c243
-rw-r--r--fs/jfs/jfs_imap.h18
-rw-r--r--fs/jfs/jfs_incore.h8
-rw-r--r--fs/jfs/jfs_inode.c16
-rw-r--r--fs/jfs/jfs_inode.h6
-rw-r--r--fs/jfs/jfs_lock.h10
-rw-r--r--fs/jfs/jfs_logmgr.c38
-rw-r--r--fs/jfs/jfs_logmgr.h76
-rw-r--r--fs/jfs/jfs_metapage.c14
-rw-r--r--fs/jfs/jfs_metapage.h12
-rw-r--r--fs/jfs/jfs_mount.c34
-rw-r--r--fs/jfs/jfs_superblock.h22
-rw-r--r--fs/jfs/jfs_txnmgr.c28
-rw-r--r--fs/jfs/jfs_txnmgr.h12
-rw-r--r--fs/jfs/jfs_types.h4
-rw-r--r--fs/jfs/jfs_umount.c24
-rw-r--r--fs/jfs/jfs_unicode.c12
-rw-r--r--fs/jfs/jfs_unicode.h10
-rw-r--r--fs/jfs/jfs_uniupr.c8
-rw-r--r--fs/jfs/jfs_xattr.h2
-rw-r--r--fs/jfs/jfs_xtree.c14
-rw-r--r--fs/jfs/jfs_xtree.h8
-rw-r--r--fs/jfs/namei.c89
-rw-r--r--fs/jfs/resize.c6
-rw-r--r--fs/jfs/super.c12
-rw-r--r--fs/jfs/symlink.c6
-rw-r--r--fs/jfs/xattr.c48
-rw-r--r--fs/libfs.c28
-rw-r--r--fs/lockd/clntlock.c60
-rw-r--r--fs/lockd/clntproc.c23
-rw-r--r--fs/lockd/host.c325
-rw-r--r--fs/lockd/mon.c79
-rw-r--r--fs/lockd/svc.c93
-rw-r--r--fs/lockd/svc4proc.c85
-rw-r--r--fs/lockd/svclock.c209
-rw-r--r--fs/lockd/svcproc.c89
-rw-r--r--fs/lockd/svcshare.c24
-rw-r--r--fs/lockd/svcsubs.c186
-rw-r--r--fs/lockd/xdr.c78
-rw-r--r--fs/lockd/xdr4.c80
-rw-r--r--fs/locks.c14
-rw-r--r--fs/mbcache.c1
-rw-r--r--fs/minix/bitmap.c2
-rw-r--r--fs/minix/file.c6
-rw-r--r--fs/minix/inode.c21
-rw-r--r--fs/minix/namei.c2
-rw-r--r--fs/mpage.c2
-rw-r--r--fs/msdos/namei.c28
-rw-r--r--fs/namei.c259
-rw-r--r--fs/namespace.c37
-rw-r--r--fs/ncpfs/dir.c3
-rw-r--r--fs/ncpfs/file.c3
-rw-r--r--fs/ncpfs/inode.c7
-rw-r--r--fs/ncpfs/ioctl.c239
-rw-r--r--fs/ncpfs/symlink.c4
-rw-r--r--fs/nfs/callback.c7
-rw-r--r--fs/nfs/callback.h10
-rw-r--r--fs/nfs/callback_proc.c6
-rw-r--r--fs/nfs/callback_xdr.c106
-rw-r--r--fs/nfs/client.c55
-rw-r--r--fs/nfs/delegation.c7
-rw-r--r--fs/nfs/dir.c37
-rw-r--r--fs/nfs/direct.c54
-rw-r--r--fs/nfs/file.c34
-rw-r--r--fs/nfs/getroot.c1
-rw-r--r--fs/nfs/inode.c39
-rw-r--r--fs/nfs/internal.h6
-rw-r--r--fs/nfs/mount_clnt.c6
-rw-r--r--fs/nfs/namespace.c14
-rw-r--r--fs/nfs/nfs2xdr.c78
-rw-r--r--fs/nfs/nfs3proc.c4
-rw-r--r--fs/nfs/nfs3xdr.c118
-rw-r--r--fs/nfs/nfs4_fs.h2
-rw-r--r--fs/nfs/nfs4namespace.c2
-rw-r--r--fs/nfs/nfs4proc.c16
-rw-r--r--fs/nfs/nfs4xdr.c360
-rw-r--r--fs/nfs/nfsroot.c3
-rw-r--r--fs/nfs/pagelist.c3
-rw-r--r--fs/nfs/proc.c2
-rw-r--r--fs/nfs/read.c3
-rw-r--r--fs/nfs/super.c3
-rw-r--r--fs/nfs/write.c12
-rw-r--r--fs/nfs_common/nfsacl.c4
-rw-r--r--fs/nfsd/export.c165
-rw-r--r--fs/nfsd/lockd.c16
-rw-r--r--fs/nfsd/nfs2acl.c39
-rw-r--r--fs/nfsd/nfs3acl.c23
-rw-r--r--fs/nfsd/nfs3proc.c108
-rw-r--r--fs/nfsd/nfs3xdr.c182
-rw-r--r--fs/nfsd/nfs4acl.c711
-rw-r--r--fs/nfsd/nfs4callback.c28
-rw-r--r--fs/nfsd/nfs4idmap.c3
-rw-r--r--fs/nfsd/nfs4proc.c142
-rw-r--r--fs/nfsd/nfs4recover.c16
-rw-r--r--fs/nfsd/nfs4state.c127
-rw-r--r--fs/nfsd/nfs4xdr.c457
-rw-r--r--fs/nfsd/nfscache.c8
-rw-r--r--fs/nfsd/nfsctl.c189
-rw-r--r--fs/nfsd/nfsfh.c10
-rw-r--r--fs/nfsd/nfsproc.c91
-rw-r--r--fs/nfsd/nfssvc.c345
-rw-r--r--fs/nfsd/nfsxdr.c117
-rw-r--r--fs/nfsd/vfs.c389
-rw-r--r--fs/nls/nls_ascii.c2
-rw-r--r--fs/nls/nls_base.c4
-rw-r--r--fs/nls/nls_cp1250.c2
-rw-r--r--fs/nls/nls_cp1251.c2
-rw-r--r--fs/nls/nls_cp1255.c2
-rw-r--r--fs/nls/nls_cp437.c2
-rw-r--r--fs/nls/nls_cp737.c2
-rw-r--r--fs/nls/nls_cp775.c2
-rw-r--r--fs/nls/nls_cp850.c2
-rw-r--r--fs/nls/nls_cp852.c2
-rw-r--r--fs/nls/nls_cp855.c2
-rw-r--r--fs/nls/nls_cp857.c2
-rw-r--r--fs/nls/nls_cp860.c2
-rw-r--r--fs/nls/nls_cp861.c2
-rw-r--r--fs/nls/nls_cp862.c2
-rw-r--r--fs/nls/nls_cp863.c2
-rw-r--r--fs/nls/nls_cp864.c2
-rw-r--r--fs/nls/nls_cp865.c2
-rw-r--r--fs/nls/nls_cp866.c2
-rw-r--r--fs/nls/nls_cp869.c2
-rw-r--r--fs/nls/nls_cp874.c2
-rw-r--r--fs/nls/nls_cp932.c2
-rw-r--r--fs/nls/nls_cp936.c2
-rw-r--r--fs/nls/nls_cp949.c2
-rw-r--r--fs/nls/nls_cp950.c2
-rw-r--r--fs/nls/nls_euc-jp.c2
-rw-r--r--fs/nls/nls_iso8859-1.c2
-rw-r--r--fs/nls/nls_iso8859-13.c2
-rw-r--r--fs/nls/nls_iso8859-14.c2
-rw-r--r--fs/nls/nls_iso8859-15.c2
-rw-r--r--fs/nls/nls_iso8859-2.c2
-rw-r--r--fs/nls/nls_iso8859-3.c2
-rw-r--r--fs/nls/nls_iso8859-4.c2
-rw-r--r--fs/nls/nls_iso8859-5.c2
-rw-r--r--fs/nls/nls_iso8859-6.c2
-rw-r--r--fs/nls/nls_iso8859-7.c2
-rw-r--r--fs/nls/nls_iso8859-9.c2
-rw-r--r--fs/nls/nls_koi8-r.c2
-rw-r--r--fs/nls/nls_koi8-ru.c2
-rw-r--r--fs/nls/nls_koi8-u.c2
-rw-r--r--fs/no-block.c22
-rw-r--r--fs/ntfs/aops.c30
-rw-r--r--fs/ntfs/aops.h2
-rw-r--r--fs/ntfs/attrib.c54
-rw-r--r--fs/ntfs/attrib.h8
-rw-r--r--fs/ntfs/bitmap.c8
-rw-r--r--fs/ntfs/bitmap.h4
-rw-r--r--fs/ntfs/collate.h8
-rw-r--r--fs/ntfs/compress.c4
-rw-r--r--fs/ntfs/dir.c5
-rw-r--r--fs/ntfs/file.c46
-rw-r--r--fs/ntfs/index.c4
-rw-r--r--fs/ntfs/index.h12
-rw-r--r--fs/ntfs/inode.c16
-rw-r--r--fs/ntfs/layout.h6
-rw-r--r--fs/ntfs/lcnalloc.c20
-rw-r--r--fs/ntfs/lcnalloc.h8
-rw-r--r--fs/ntfs/logfile.c108
-rw-r--r--fs/ntfs/logfile.h6
-rw-r--r--fs/ntfs/mft.c67
-rw-r--r--fs/ntfs/mft.h2
-rw-r--r--fs/ntfs/ntfs.h2
-rw-r--r--fs/ntfs/quota.c12
-rw-r--r--fs/ntfs/quota.h2
-rw-r--r--fs/ntfs/runlist.c54
-rw-r--r--fs/ntfs/super.c206
-rw-r--r--fs/ntfs/types.h5
-rw-r--r--fs/ntfs/unistr.c12
-rw-r--r--fs/ntfs/usnjrnl.c8
-rw-r--r--fs/ntfs/usnjrnl.h2
-rw-r--r--fs/ocfs2/cluster/nodemanager.c10
-rw-r--r--fs/ocfs2/dlm/dlmfs.c12
-rw-r--r--fs/ocfs2/dlmglue.c2
-rw-r--r--fs/ocfs2/file.c79
-rw-r--r--fs/ocfs2/inode.c4
-rw-r--r--fs/ocfs2/namei.c59
-rw-r--r--fs/ocfs2/super.c2
-rw-r--r--fs/open.c213
-rw-r--r--fs/partitions/Makefile2
-rw-r--r--fs/partitions/check.c50
-rw-r--r--fs/partitions/efi.c9
-rw-r--r--fs/partitions/ldm.c267
-rw-r--r--fs/partitions/msdos.c37
-rw-r--r--fs/pipe.c215
-rw-r--r--fs/posix_acl.c6
-rw-r--r--fs/proc/array.c88
-rw-r--r--fs/proc/base.c1768
-rw-r--r--fs/proc/internal.h1
-rw-r--r--fs/proc/kcore.c10
-rw-r--r--fs/proc/nommu.c20
-rw-r--r--fs/proc/proc_misc.c16
-rw-r--r--fs/proc/root.c12
-rw-r--r--fs/proc/task_mmu.c5
-rw-r--r--fs/proc/task_nommu.c74
-rw-r--r--fs/qnx4/file.c6
-rw-r--r--fs/qnx4/inode.c8
-rw-r--r--fs/qnx4/namei.c8
-rw-r--r--fs/quota.c44
-rw-r--r--fs/ramfs/file-mmu.c6
-rw-r--r--fs/ramfs/file-nommu.c6
-rw-r--r--fs/ramfs/inode.c5
-rw-r--r--fs/read_write.c253
-rw-r--r--fs/read_write.h14
-rw-r--r--fs/readdir.c18
-rw-r--r--fs/reiserfs/Makefile2
-rw-r--r--fs/reiserfs/bitmap.c216
-rw-r--r--fs/reiserfs/dir.c3
-rw-r--r--fs/reiserfs/file.c16
-rw-r--r--fs/reiserfs/inode.c20
-rw-r--r--fs/reiserfs/ioctl.c35
-rw-r--r--fs/reiserfs/item_ops.c12
-rw-r--r--fs/reiserfs/journal.c106
-rw-r--r--fs/reiserfs/namei.c25
-rw-r--r--fs/reiserfs/resize.c71
-rw-r--r--fs/reiserfs/stree.c4
-rw-r--r--fs/reiserfs/super.c217
-rw-r--r--fs/reiserfs/xattr.c6
-rw-r--r--fs/romfs/inode.c3
-rw-r--r--fs/select.c8
-rw-r--r--fs/smbfs/file.c24
-rw-r--r--fs/smbfs/inode.c5
-rw-r--r--fs/smbfs/proc.c1
-rw-r--r--fs/smbfs/request.c3
-rw-r--r--fs/splice.c113
-rw-r--r--fs/stat.c9
-rw-r--r--fs/super.c49
-rw-r--r--fs/sync.c113
-rw-r--r--fs/sysfs/dir.c4
-rw-r--r--fs/sysfs/file.c11
-rw-r--r--fs/sysfs/inode.c1
-rw-r--r--fs/sysfs/mount.c2
-rw-r--r--fs/sysv/file.c6
-rw-r--r--fs/sysv/ialloc.c2
-rw-r--r--fs/sysv/inode.c2
-rw-r--r--fs/sysv/namei.c2
-rw-r--r--fs/sysv/super.c21
-rw-r--r--fs/udf/file.c16
-rw-r--r--fs/udf/ialloc.c7
-rw-r--r--fs/udf/inode.c4
-rw-r--r--fs/udf/namei.c26
-rw-r--r--fs/udf/super.c8
-rw-r--r--fs/ufs/file.c6
-rw-r--r--fs/ufs/ialloc.c1
-rw-r--r--fs/ufs/inode.c1
-rw-r--r--fs/ufs/namei.c2
-rw-r--r--fs/ufs/super.c6
-rw-r--r--fs/ufs/util.c14
-rw-r--r--fs/utimes.c137
-rw-r--r--fs/vfat/namei.c17
-rw-r--r--fs/xattr.c33
-rw-r--r--fs/xfs/Kconfig1
-rw-r--r--fs/xfs/Makefile-linux-2.61
-rw-r--r--fs/xfs/linux-2.6/kmem.c34
-rw-r--r--fs/xfs/linux-2.6/kmem.h10
-rw-r--r--fs/xfs/linux-2.6/sema.h2
-rw-r--r--fs/xfs/linux-2.6/sv.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c9
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c54
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.h7
-rw-r--r--fs/xfs/linux-2.6/xfs_file.c142
-rw-r--r--fs/xfs/linux-2.6/xfs_globals.c2
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c19
-rw-r--r--fs/xfs/linux-2.6/xfs_iops.c29
-rw-r--r--fs/xfs/linux-2.6/xfs_linux.h14
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c14
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_vfs.h2
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.c1
-rw-r--r--fs/xfs/linux-2.6/xfs_vnode.h2
-rw-r--r--fs/xfs/quota/xfs_dquot_item.c26
-rw-r--r--fs/xfs/quota/xfs_qm.c14
-rw-r--r--fs/xfs/quota/xfs_qm.h6
-rw-r--r--fs/xfs/quota/xfs_quota_priv.h2
-rw-r--r--fs/xfs/support/debug.c6
-rw-r--r--fs/xfs/support/ktrace.c2
-rw-r--r--fs/xfs/xfs_ag.h2
-rw-r--r--fs/xfs/xfs_alloc.c10
-rw-r--r--fs/xfs/xfs_alloc_btree.c132
-rw-r--r--fs/xfs/xfs_attr.c181
-rw-r--r--fs/xfs/xfs_attr.h8
-rw-r--r--fs/xfs/xfs_attr_leaf.c351
-rw-r--r--fs/xfs/xfs_attr_leaf.h41
-rw-r--r--fs/xfs/xfs_behavior.c20
-rw-r--r--fs/xfs/xfs_behavior.h2
-rw-r--r--fs/xfs/xfs_bmap.c90
-rw-r--r--fs/xfs/xfs_bmap_btree.c113
-rw-r--r--fs/xfs/xfs_bmap_btree.h11
-rw-r--r--fs/xfs/xfs_btree.c8
-rw-r--r--fs/xfs/xfs_btree.h5
-rw-r--r--fs/xfs/xfs_buf_item.c22
-rw-r--r--fs/xfs/xfs_da_btree.c33
-rw-r--r--fs/xfs/xfs_error.h9
-rw-r--r--fs/xfs/xfs_extfree_item.c69
-rw-r--r--fs/xfs/xfs_extfree_item.h50
-rw-r--r--fs/xfs/xfs_fs.h8
-rw-r--r--fs/xfs/xfs_ialloc.c11
-rw-r--r--fs/xfs/xfs_ialloc_btree.c62
-rw-r--r--fs/xfs/xfs_ialloc_btree.h19
-rw-r--r--fs/xfs/xfs_iget.c44
-rw-r--r--fs/xfs/xfs_inode.c30
-rw-r--r--fs/xfs/xfs_inode.h12
-rw-r--r--fs/xfs/xfs_inode_item.c16
-rw-r--r--fs/xfs/xfs_inode_item.h66
-rw-r--r--fs/xfs/xfs_iomap.c89
-rw-r--r--fs/xfs/xfs_itable.c184
-rw-r--r--fs/xfs/xfs_itable.h16
-rw-r--r--fs/xfs/xfs_log.c19
-rw-r--r--fs/xfs/xfs_log.h8
-rw-r--r--fs/xfs/xfs_log_priv.h10
-rw-r--r--fs/xfs/xfs_mount.h5
-rw-r--r--fs/xfs/xfs_quota.h2
-rw-r--r--fs/xfs/xfs_rtalloc.c38
-rw-r--r--fs/xfs/xfs_sb.h22
-rw-r--r--fs/xfs/xfs_trans.h2
-rw-r--r--fs/xfs/xfs_trans_ail.c4
-rw-r--r--fs/xfs/xfs_trans_priv.h12
-rw-r--r--fs/xfs/xfs_vfsops.c2
-rw-r--r--fs/xfs/xfs_vnodeops.c26
-rw-r--r--include/acpi/aclocal.h2
-rw-r--r--include/acpi/pdc_intel.h9
-rw-r--r--include/acpi/processor.h18
-rw-r--r--include/asm-alpha/io.h13
-rw-r--r--include/asm-alpha/irq_regs.h1
-rw-r--r--include/asm-alpha/machvec.h5
-rw-r--r--include/asm-alpha/spinlock.h4
-rw-r--r--include/asm-alpha/unistd.h69
-rw-r--r--include/asm-arm/arch-at91rm9200/at91rm9200.h118
-rw-r--r--include/asm-arm/arch-at91rm9200/at91rm9200_sys.h3
-rw-r--r--include/asm-arm/arch-at91rm9200/at91rm9200_twi.h57
-rw-r--r--include/asm-arm/arch-at91rm9200/at91rm9200_usart.h123
-rw-r--r--include/asm-arm/arch-at91rm9200/board.h5
-rw-r--r--include/asm-arm/arch-at91rm9200/gpio.h18
-rw-r--r--include/asm-arm/arch-at91rm9200/hardware.h30
-rw-r--r--include/asm-arm/arch-at91rm9200/irqs.h2
-rw-r--r--include/asm-arm/arch-clps711x/entry-macro.S2
-rw-r--r--include/asm-arm/arch-clps711x/time.h5
-rw-r--r--include/asm-arm/arch-ebsa285/entry-macro.S2
-rw-r--r--include/asm-arm/arch-h720x/system.h2
-rw-r--r--include/asm-arm/arch-imx/imx-dma.h8
-rw-r--r--include/asm-arm/arch-iop32x/debug-macro.S20
-rw-r--r--include/asm-arm/arch-iop32x/dma.h (renamed from include/asm-arm/arch-iop3xx/dma.h)4
-rw-r--r--include/asm-arm/arch-iop32x/entry-macro.S21
-rw-r--r--include/asm-arm/arch-iop32x/glantank.h13
-rw-r--r--include/asm-arm/arch-iop32x/hardware.h44
-rw-r--r--include/asm-arm/arch-iop32x/io.h (renamed from include/asm-arm/arch-iop3xx/io.h)11
-rw-r--r--include/asm-arm/arch-iop32x/iop32x.h28
-rw-r--r--include/asm-arm/arch-iop32x/iq31244.h (renamed from include/asm-arm/arch-iop3xx/iq31244.h)15
-rw-r--r--include/asm-arm/arch-iop32x/iq80321.h (renamed from include/asm-arm/arch-iop3xx/iq80321.h)15
-rw-r--r--include/asm-arm/arch-iop32x/irqs.h50
-rw-r--r--include/asm-arm/arch-iop32x/memory.h26
-rw-r--r--include/asm-arm/arch-iop32x/n2100.h19
-rw-r--r--include/asm-arm/arch-iop32x/system.h33
-rw-r--r--include/asm-arm/arch-iop32x/timex.h9
-rw-r--r--include/asm-arm/arch-iop32x/uncompress.h39
-rw-r--r--include/asm-arm/arch-iop32x/vmalloc.h5
-rw-r--r--include/asm-arm/arch-iop33x/debug-macro.S24
-rw-r--r--include/asm-arm/arch-iop33x/dma.h9
-rw-r--r--include/asm-arm/arch-iop33x/entry-macro.S22
-rw-r--r--include/asm-arm/arch-iop33x/hardware.h46
-rw-r--r--include/asm-arm/arch-iop33x/io.h21
-rw-r--r--include/asm-arm/arch-iop33x/iop33x.h33
-rw-r--r--include/asm-arm/arch-iop33x/iq80331.h (renamed from include/asm-arm/arch-iop3xx/iq80331.h)15
-rw-r--r--include/asm-arm/arch-iop33x/iq80332.h (renamed from include/asm-arm/arch-iop3xx/iq80332.h)15
-rw-r--r--include/asm-arm/arch-iop33x/irqs.h60
-rw-r--r--include/asm-arm/arch-iop33x/memory.h26
-rw-r--r--include/asm-arm/arch-iop33x/system.h22
-rw-r--r--include/asm-arm/arch-iop33x/timex.h9
-rw-r--r--include/asm-arm/arch-iop33x/uncompress.h37
-rw-r--r--include/asm-arm/arch-iop33x/vmalloc.h5
-rw-r--r--include/asm-arm/arch-iop3xx/debug-macro.S35
-rw-r--r--include/asm-arm/arch-iop3xx/entry-macro.S57
-rw-r--r--include/asm-arm/arch-iop3xx/hardware.h57
-rw-r--r--include/asm-arm/arch-iop3xx/iop321-irqs.h100
-rw-r--r--include/asm-arm/arch-iop3xx/iop321.h345
-rw-r--r--include/asm-arm/arch-iop3xx/iop331-irqs.h132
-rw-r--r--include/asm-arm/arch-iop3xx/iop331.h363
-rw-r--r--include/asm-arm/arch-iop3xx/irqs.h21
-rw-r--r--include/asm-arm/arch-iop3xx/memory.h38
-rw-r--r--include/asm-arm/arch-iop3xx/system.h35
-rw-r--r--include/asm-arm/arch-iop3xx/timex.h20
-rw-r--r--include/asm-arm/arch-iop3xx/uncompress.h48
-rw-r--r--include/asm-arm/arch-iop3xx/vmalloc.h16
-rw-r--r--include/asm-arm/arch-ixp4xx/platform.h5
-rw-r--r--include/asm-arm/arch-ixp4xx/system.h2
-rw-r--r--include/asm-arm/arch-l7200/io.h8
-rw-r--r--include/asm-arm/arch-l7200/time.h5
-rw-r--r--include/asm-arm/arch-lh7a40x/clocks.h2
-rw-r--r--include/asm-arm/arch-omap/board-ams-delta.h11
-rw-r--r--include/asm-arm/arch-omap/clock.h1
-rw-r--r--include/asm-arm/arch-omap/dma.h16
-rw-r--r--include/asm-arm/arch-omap/dmtimer.h4
-rw-r--r--include/asm-arm/arch-omap/gpmc.h4
-rw-r--r--include/asm-arm/arch-omap/irqs.h2
-rw-r--r--include/asm-arm/arch-omap/keypad.h3
-rw-r--r--include/asm-arm/arch-omap/mcbsp.h2
-rw-r--r--include/asm-arm/arch-omap/mux.h25
-rw-r--r--include/asm-arm/arch-omap/pm.h2
-rw-r--r--include/asm-arm/arch-pnx4008/clock.h1
-rw-r--r--include/asm-arm/arch-pnx4008/dma.h2
-rw-r--r--include/asm-arm/arch-pnx4008/platform.h2
-rw-r--r--include/asm-arm/arch-pxa/dma.h2
-rw-r--r--include/asm-arm/arch-pxa/mmc.h2
-rw-r--r--include/asm-arm/arch-pxa/pxa-regs.h1
-rw-r--r--include/asm-arm/arch-pxa/pxafb.h14
-rw-r--r--include/asm-arm/arch-pxa/spitz.h4
-rw-r--r--include/asm-arm/arch-pxa/udc.h8
-rw-r--r--include/asm-arm/arch-s3c2410/dma.h66
-rw-r--r--include/asm-arm/arch-s3c2410/fb.h2
-rw-r--r--include/asm-arm/arch-s3c2410/map.h5
-rw-r--r--include/asm-arm/arch-s3c2410/osiris-map.h18
-rw-r--r--include/asm-arm/arch-s3c2410/regs-ac97.h23
-rw-r--r--include/asm-arm/arch-s3c2410/regs-adc.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-clock.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-dsc.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-gpio.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-gpioj.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-iis.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-irq.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-lcd.h32
-rw-r--r--include/asm-arm/arch-s3c2410/regs-rtc.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-sdi.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-timer.h2
-rw-r--r--include/asm-arm/arch-s3c2410/regs-udc.h2
-rw-r--r--include/asm-arm/arch-s3c2410/spi-gpio.h2
-rw-r--r--include/asm-arm/arch-sa1100/jornada720.h14
-rw-r--r--include/asm-arm/arch-sa1100/neponset.h2
-rw-r--r--include/asm-arm/arch-sa1100/uncompress.h2
-rw-r--r--include/asm-arm/arch-shark/vmalloc.h2
-rw-r--r--include/asm-arm/arch-versatile/hardware.h4
-rw-r--r--include/asm-arm/atomic.h16
-rw-r--r--include/asm-arm/bitops.h24
-rw-r--r--include/asm-arm/cacheflush.h22
-rw-r--r--include/asm-arm/flat.h16
-rw-r--r--include/asm-arm/hardware/debug-8250.S2
-rw-r--r--include/asm-arm/hardware/debug-pl01x.S2
-rw-r--r--include/asm-arm/hardware/entry-macro-iomd.S2
-rw-r--r--include/asm-arm/hardware/iop3xx.h301
-rw-r--r--include/asm-arm/hardware/locomo.h33
-rw-r--r--include/asm-arm/hardware/sa1111.h2
-rw-r--r--include/asm-arm/hardware/sharpsl_pm.h7
-rw-r--r--include/asm-arm/hw_irq.h2
-rw-r--r--include/asm-arm/io.h23
-rw-r--r--include/asm-arm/irq_regs.h1
-rw-r--r--include/asm-arm/irqflags.h132
-rw-r--r--include/asm-arm/mach/irq.h9
-rw-r--r--include/asm-arm/mach/pci.h10
-rw-r--r--include/asm-arm/mach/serial_at91.h8
-rw-r--r--include/asm-arm/mach/time.h6
-rw-r--r--include/asm-arm/page.h3
-rw-r--r--include/asm-arm/pgtable-nommu.h1
-rw-r--r--include/asm-arm/pgtable.h7
-rw-r--r--include/asm-arm/proc-fns.h40
-rw-r--r--include/asm-arm/setup.h12
-rw-r--r--include/asm-arm/spinlock.h4
-rw-r--r--include/asm-arm/system.h137
-rw-r--r--include/asm-arm/tlbflush.h76
-rw-r--r--include/asm-arm/uaccess.h2
-rw-r--r--include/asm-arm/unaligned.h62
-rw-r--r--include/asm-arm/unistd.h27
-rw-r--r--include/asm-arm26/assembler.h2
-rw-r--r--include/asm-arm26/namei.h2
-rw-r--r--include/asm-arm26/semaphore.h2
-rw-r--r--include/asm-arm26/unistd.h27
-rw-r--r--include/asm-avr32/arch-at32ap/at91rm9200_usart.h123
-rw-r--r--include/asm-avr32/arch-at32ap/board.h10
-rw-r--r--include/asm-avr32/arch-at32ap/init.h1
-rw-r--r--include/asm-avr32/irq_regs.h1
-rw-r--r--include/asm-avr32/mach/serial_at91.h8
-rw-r--r--include/asm-avr32/unistd.h80
-rw-r--r--include/asm-cris/arch-v32/spinlock.h4
-rw-r--r--include/asm-cris/unistd.h61
-rw-r--r--include/asm-frv/dma.h5
-rw-r--r--include/asm-frv/highmem.h27
-rw-r--r--include/asm-frv/io.h21
-rw-r--r--include/asm-frv/irq_regs.h27
-rw-r--r--include/asm-frv/namei.h2
-rw-r--r--include/asm-frv/pgtable.h2
-rw-r--r--include/asm-frv/ptrace.h1
-rw-r--r--include/asm-frv/timex.h5
-rw-r--r--include/asm-frv/unistd.h28
-rw-r--r--include/asm-generic/bitops/sched.h2
-rw-r--r--include/asm-generic/bug.h39
-rw-r--r--include/asm-generic/irq_regs.h37
-rw-r--r--include/asm-generic/mutex-dec.h2
-rw-r--r--include/asm-generic/mutex-null.h2
-rw-r--r--include/asm-generic/mutex-xchg.h2
-rw-r--r--include/asm-generic/percpu.h2
-rw-r--r--include/asm-generic/pgtable.h37
-rw-r--r--include/asm-generic/rtc.h2
-rw-r--r--include/asm-generic/tlb.h2
-rw-r--r--include/asm-generic/vmlinux.lds.h22
-rw-r--r--include/asm-h8300/keyboard.h8
-rw-r--r--include/asm-h8300/unistd.h57
-rw-r--r--include/asm-i386/alternative-asm.i2
-rw-r--r--include/asm-i386/apic.h4
-rw-r--r--include/asm-i386/arch_hooks.h2
-rw-r--r--include/asm-i386/bugs.h2
-rw-r--r--include/asm-i386/dma-mapping.h12
-rw-r--r--include/asm-i386/elf.h2
-rw-r--r--include/asm-i386/floppy.h6
-rw-r--r--include/asm-i386/frame.i1
-rw-r--r--include/asm-i386/hpet.h2
-rw-r--r--include/asm-i386/hw_irq.h8
-rw-r--r--include/asm-i386/hypertransport.h42
-rw-r--r--include/asm-i386/io.h27
-rw-r--r--include/asm-i386/io_apic.h42
-rw-r--r--include/asm-i386/irq_regs.h1
-rw-r--r--include/asm-i386/mach-default/do_timer.h10
-rw-r--r--include/asm-i386/mach-default/irq_vectors_limits.h5
-rw-r--r--include/asm-i386/mach-summit/mach_apic.h2
-rw-r--r--include/asm-i386/mach-visws/do_timer.h10
-rw-r--r--include/asm-i386/mach-voyager/do_timer.h8
-rw-r--r--include/asm-i386/mca_dma.h3
-rw-r--r--include/asm-i386/msi.h23
-rw-r--r--include/asm-i386/msidef.h47
-rw-r--r--include/asm-i386/nmi.h6
-rw-r--r--include/asm-i386/pgtable-2level.h1
-rw-r--r--include/asm-i386/pgtable-3level.h16
-rw-r--r--include/asm-i386/pgtable.h80
-rw-r--r--include/asm-i386/processor.h2
-rw-r--r--include/asm-i386/ptrace.h3
-rw-r--r--include/asm-i386/semaphore.h4
-rw-r--r--include/asm-i386/smp.h5
-rw-r--r--include/asm-i386/spinlock.h4
-rw-r--r--include/asm-i386/topology.h1
-rw-r--r--include/asm-i386/uaccess.h67
-rw-r--r--include/asm-i386/unistd.h47
-rw-r--r--include/asm-i386/vic.h2
-rw-r--r--include/asm-i386/voyager.h164
-rw-r--r--include/asm-ia64/esi.h30
-rw-r--r--include/asm-ia64/futex.h122
-rw-r--r--include/asm-ia64/io.h4
-rw-r--r--include/asm-ia64/irq_regs.h1
-rw-r--r--include/asm-ia64/kprobes.h9
-rw-r--r--include/asm-ia64/machvec.h25
-rw-r--r--include/asm-ia64/machvec_sn2.h9
-rw-r--r--include/asm-ia64/mca_asm.h2
-rw-r--r--include/asm-ia64/meminit.h1
-rw-r--r--include/asm-ia64/msi.h29
-rw-r--r--include/asm-ia64/numa.h2
-rw-r--r--include/asm-ia64/pal.h27
-rw-r--r--include/asm-ia64/processor.h13
-rw-r--r--include/asm-ia64/ptrace.h3
-rw-r--r--include/asm-ia64/smp.h1
-rw-r--r--include/asm-ia64/sn/pcibr_provider.h2
-rw-r--r--include/asm-ia64/sn/tioca_provider.h4
-rw-r--r--include/asm-ia64/sn/tioce_provider.h2
-rw-r--r--include/asm-ia64/sn/xpc.h2
-rw-r--r--include/asm-ia64/spinlock.h4
-rw-r--r--include/asm-ia64/topology.h2
-rw-r--r--include/asm-ia64/unistd.h75
-rw-r--r--include/asm-m32r/io.h32
-rw-r--r--include/asm-m32r/irq_regs.h1
-rw-r--r--include/asm-m32r/m32104ut/m32104ut_pld.h2
-rw-r--r--include/asm-m32r/m32700ut/m32700ut_lan.h2
-rw-r--r--include/asm-m32r/m32700ut/m32700ut_lcd.h2
-rw-r--r--include/asm-m32r/m32700ut/m32700ut_pld.h2
-rw-r--r--include/asm-m32r/mappi2/mappi2_pld.h2
-rw-r--r--include/asm-m32r/mappi3/mappi3_pld.h2
-rw-r--r--include/asm-m32r/opsput/opsput_lan.h2
-rw-r--r--include/asm-m32r/opsput/opsput_lcd.h2
-rw-r--r--include/asm-m32r/opsput/opsput_pld.h2
-rw-r--r--include/asm-m32r/pgtable-2level.h2
-rw-r--r--include/asm-m32r/spinlock.h13
-rw-r--r--include/asm-m32r/system.h4
-rw-r--r--include/asm-m32r/timex.h3
-rw-r--r--include/asm-m32r/unistd.h42
-rw-r--r--include/asm-m68k/atari_stdma.h3
-rw-r--r--include/asm-m68k/dma-mapping.h7
-rw-r--r--include/asm-m68k/floppy.h10
-rw-r--r--include/asm-m68k/ide.h2
-rw-r--r--include/asm-m68k/irq.h11
-rw-r--r--include/asm-m68k/irq_regs.h1
-rw-r--r--include/asm-m68k/mac_iop.h6
-rw-r--r--include/asm-m68k/machdep.h2
-rw-r--r--include/asm-m68k/rtc.h2
-rw-r--r--include/asm-m68k/signal.h1
-rw-r--r--include/asm-m68k/string.h198
-rw-r--r--include/asm-m68k/sun3mmu.h3
-rw-r--r--include/asm-m68k/sun3xflop.h7
-rw-r--r--include/asm-m68k/system.h6
-rw-r--r--include/asm-m68k/uaccess.h16
-rw-r--r--include/asm-m68k/unistd.h42
-rw-r--r--include/asm-m68k/user.h2
-rw-r--r--include/asm-m68knommu/processor.h2
-rw-r--r--include/asm-m68knommu/unistd.h95
-rw-r--r--include/asm-mips/Kbuild2
-rw-r--r--include/asm-mips/bootinfo.h15
-rw-r--r--include/asm-mips/cacheflush.h12
-rw-r--r--include/asm-mips/dec/ecc.h3
-rw-r--r--include/asm-mips/dec/kn01.h3
-rw-r--r--include/asm-mips/dec/kn02xa.h3
-rw-r--r--include/asm-mips/fcntl.h2
-rw-r--r--include/asm-mips/fpu.h6
-rw-r--r--include/asm-mips/galileo-boards/ev96100.h55
-rw-r--r--include/asm-mips/galileo-boards/ev96100int.h12
-rw-r--r--include/asm-mips/galileo-boards/gt96100.h427
-rw-r--r--include/asm-mips/hazards.h360
-rw-r--r--include/asm-mips/io.h30
-rw-r--r--include/asm-mips/irq.h14
-rw-r--r--include/asm-mips/irq_regs.h21
-rw-r--r--include/asm-mips/irqflags.h25
-rw-r--r--include/asm-mips/it8172/it8172.h348
-rw-r--r--include/asm-mips/it8172/it8172_cir.h140
-rw-r--r--include/asm-mips/it8172/it8172_dbg.h38
-rw-r--r--include/asm-mips/it8172/it8172_int.h144
-rw-r--r--include/asm-mips/it8172/it8172_pci.h108
-rw-r--r--include/asm-mips/it8712.h28
-rw-r--r--include/asm-mips/jmr3927/irq.h4
-rw-r--r--include/asm-mips/mach-atlas/mc146818rtc.h4
-rw-r--r--include/asm-mips/mach-au1x00/au1000_dma.h3
-rw-r--r--include/asm-mips/mach-au1x00/au1000_usbdev.h73
-rw-r--r--include/asm-mips/mach-ev64120/mach-gt64120.h1
-rw-r--r--include/asm-mips/mach-ev96100/mach-gt64120.h46
-rw-r--r--include/asm-mips/mach-excite/excite.h2
-rw-r--r--include/asm-mips/mach-excite/excite_fpga.h (renamed from arch/mips/basler/excite/excite_fpga.h)0
-rw-r--r--include/asm-mips/mach-ip27/topology.h1
-rw-r--r--include/asm-mips/mach-pnx8550/uart.h14
-rw-r--r--include/asm-mips/mach-qemu/cpu-feature-overrides.h2
-rw-r--r--include/asm-mips/marvell.h2
-rw-r--r--include/asm-mips/mips-boards/atlasint.h124
-rw-r--r--include/asm-mips/mmu_context.h8
-rw-r--r--include/asm-mips/msc01_ic.h2
-rw-r--r--include/asm-mips/page.h11
-rw-r--r--include/asm-mips/pgtable-64.h6
-rw-r--r--include/asm-mips/ptrace.h6
-rw-r--r--include/asm-mips/serial.h55
-rw-r--r--include/asm-mips/sibyte/sb1250_defs.h6
-rw-r--r--include/asm-mips/sibyte/sb1250_scd.h2
-rw-r--r--include/asm-mips/signal.h11
-rw-r--r--include/asm-mips/spinlock.h51
-rw-r--r--include/asm-mips/stackframe.h64
-rw-r--r--include/asm-mips/stacktrace.h44
-rw-r--r--include/asm-mips/termbits.h12
-rw-r--r--include/asm-mips/thread_info.h1
-rw-r--r--include/asm-mips/time.h8
-rw-r--r--include/asm-mips/timex.h4
-rw-r--r--include/asm-mips/tx4938/tx4938_mips.h2
-rw-r--r--include/asm-mips/unistd.h66
-rw-r--r--include/asm-mips/user.h4
-rw-r--r--include/asm-mips/vr41xx/vr41xx.h2
-rw-r--r--include/asm-parisc/agp.h25
-rw-r--r--include/asm-parisc/assembly.h6
-rw-r--r--include/asm-parisc/cacheflush.h30
-rw-r--r--include/asm-parisc/compat.h4
-rw-r--r--include/asm-parisc/dma.h7
-rw-r--r--include/asm-parisc/futex.h71
-rw-r--r--include/asm-parisc/io.h2
-rw-r--r--include/asm-parisc/iosapic.h53
-rw-r--r--include/asm-parisc/irq.h6
-rw-r--r--include/asm-parisc/irq_regs.h1
-rw-r--r--include/asm-parisc/mckinley.h9
-rw-r--r--include/asm-parisc/page.h22
-rw-r--r--include/asm-parisc/param.h10
-rw-r--r--include/asm-parisc/parisc-device.h5
-rw-r--r--include/asm-parisc/pci.h5
-rw-r--r--include/asm-parisc/pdc.h2
-rw-r--r--include/asm-parisc/prefetch.h39
-rw-r--r--include/asm-parisc/processor.h39
-rw-r--r--include/asm-parisc/ropes.h322
-rw-r--r--include/asm-parisc/rtc.h2
-rw-r--r--include/asm-parisc/serial.h16
-rw-r--r--include/asm-parisc/spinlock.h119
-rw-r--r--include/asm-parisc/unistd.h86
-rw-r--r--include/asm-powerpc/bug.h12
-rw-r--r--include/asm-powerpc/firmware.h67
-rw-r--r--include/asm-powerpc/fs_pd.h45
-rw-r--r--include/asm-powerpc/i8259.h4
-rw-r--r--include/asm-powerpc/ibmebus.h2
-rw-r--r--include/asm-powerpc/immap_qe.h477
-rw-r--r--include/asm-powerpc/io.h27
-rw-r--r--include/asm-powerpc/ipic.h6
-rw-r--r--include/asm-powerpc/irq.h3
-rw-r--r--include/asm-powerpc/irq_regs.h2
-rw-r--r--include/asm-powerpc/iseries/hv_lp_event.h2
-rw-r--r--include/asm-powerpc/iseries/it_lp_queue.h2
-rw-r--r--include/asm-powerpc/kprobes.h22
-rw-r--r--include/asm-powerpc/machdep.h2
-rw-r--r--include/asm-powerpc/mpc85xx.h53
-rw-r--r--include/asm-powerpc/mpic.h4
-rw-r--r--include/asm-powerpc/pci-bridge.h1
-rw-r--r--include/asm-powerpc/ptrace.h2
-rw-r--r--include/asm-powerpc/qe.h457
-rw-r--r--include/asm-powerpc/qe_ic.h64
-rw-r--r--include/asm-powerpc/reg.h2
-rw-r--r--include/asm-powerpc/smp.h3
-rw-r--r--include/asm-powerpc/spinlock.h4
-rw-r--r--include/asm-powerpc/spu.h36
-rw-r--r--include/asm-powerpc/system.h4
-rw-r--r--include/asm-powerpc/time.h6
-rw-r--r--include/asm-powerpc/topology.h1
-rw-r--r--include/asm-powerpc/ucc.h84
-rw-r--r--include/asm-powerpc/ucc_fast.h243
-rw-r--r--include/asm-powerpc/ucc_slow.h289
-rw-r--r--include/asm-powerpc/unistd.h7
-rw-r--r--include/asm-powerpc/xmon.h26
-rw-r--r--include/asm-ppc/commproc.h3
-rw-r--r--include/asm-ppc/cpm2.h63
-rw-r--r--include/asm-ppc/floppy.h6
-rw-r--r--include/asm-ppc/fs_pd.h36
-rw-r--r--include/asm-ppc/gt64260.h2
-rw-r--r--include/asm-ppc/io.h16
-rw-r--r--include/asm-ppc/machdep.h2
-rw-r--r--include/asm-ppc/mpc52xx.h2
-rw-r--r--include/asm-ppc/mv64x60.h4
-rw-r--r--include/asm-ppc/mv64x60_defs.h2
-rw-r--r--include/asm-ppc/open_pic.h6
-rw-r--r--include/asm-ppc/rheap.h6
-rw-r--r--include/asm-ppc/rtc.h2
-rw-r--r--include/asm-ppc/smp.h2
-rw-r--r--include/asm-ppc/spinlock.h4
-rw-r--r--include/asm-s390/appldata.h2
-rw-r--r--include/asm-s390/atomic.h120
-rw-r--r--include/asm-s390/bitops.h626
-rw-r--r--include/asm-s390/byteorder.h50
-rw-r--r--include/asm-s390/checksum.h176
-rw-r--r--include/asm-s390/cio.h6
-rw-r--r--include/asm-s390/div64.h48
-rw-r--r--include/asm-s390/ebcdic.h20
-rw-r--r--include/asm-s390/hardirq.h2
-rw-r--r--include/asm-s390/io.h19
-rw-r--r--include/asm-s390/irq.h3
-rw-r--r--include/asm-s390/irq_regs.h1
-rw-r--r--include/asm-s390/irqflags.h110
-rw-r--r--include/asm-s390/lowcore.h2
-rw-r--r--include/asm-s390/page.h112
-rw-r--r--include/asm-s390/percpu.h4
-rw-r--r--include/asm-s390/pgalloc.h2
-rw-r--r--include/asm-s390/pgtable.h144
-rw-r--r--include/asm-s390/processor.h130
-rw-r--r--include/asm-s390/ptrace.h3
-rw-r--r--include/asm-s390/qdio.h2
-rw-r--r--include/asm-s390/rwsem.h238
-rw-r--r--include/asm-s390/s390_ext.h2
-rw-r--r--include/asm-s390/semaphore.h16
-rw-r--r--include/asm-s390/setup.h1
-rw-r--r--include/asm-s390/sfp-machine.h64
-rw-r--r--include/asm-s390/sigp.h65
-rw-r--r--include/asm-s390/smp.h2
-rw-r--r--include/asm-s390/spinlock.h62
-rw-r--r--include/asm-s390/spinlock_types.h6
-rw-r--r--include/asm-s390/string.h56
-rw-r--r--include/asm-s390/system.h342
-rw-r--r--include/asm-s390/timer.h2
-rw-r--r--include/asm-s390/timex.h19
-rw-r--r--include/asm-s390/tlbflush.h32
-rw-r--r--include/asm-s390/uaccess.h13
-rw-r--r--include/asm-s390/unistd.h318
-rw-r--r--include/asm-sh/.gitignore3
-rw-r--r--include/asm-sh/addrspace.h8
-rw-r--r--include/asm-sh/adx/io.h86
-rw-r--r--include/asm-sh/apm.h46
-rw-r--r--include/asm-sh/atomic.h106
-rw-r--r--include/asm-sh/auxvec.h14
-rw-r--r--include/asm-sh/bigsur/io.h2
-rw-r--r--include/asm-sh/bigsur/serial.h2
-rw-r--r--include/asm-sh/bitops.h16
-rw-r--r--include/asm-sh/bugs.h6
-rw-r--r--include/asm-sh/cache.h30
-rw-r--r--include/asm-sh/cacheflush.h3
-rw-r--r--include/asm-sh/cat68701/io.h22
-rw-r--r--include/asm-sh/checksum.h2
-rw-r--r--include/asm-sh/cpu-features.h24
-rw-r--r--include/asm-sh/cpu-sh2/shmparam.h16
-rw-r--r--include/asm-sh/cpu-sh3/cache.h4
-rw-r--r--include/asm-sh/cpu-sh3/cacheflush.h52
-rw-r--r--include/asm-sh/cpu-sh3/freq.h4
-rw-r--r--include/asm-sh/cpu-sh3/mmu_context.h8
-rw-r--r--include/asm-sh/cpu-sh3/rtc.h25
-rw-r--r--include/asm-sh/cpu-sh3/shmparam.h16
-rw-r--r--include/asm-sh/cpu-sh3/timer.h8
-rw-r--r--include/asm-sh/cpu-sh3/ubc.h15
-rw-r--r--include/asm-sh/cpu-sh4/addrspace.h3
-rw-r--r--include/asm-sh/cpu-sh4/cache.h2
-rw-r--r--include/asm-sh/cpu-sh4/cacheflush.h36
-rw-r--r--include/asm-sh/cpu-sh4/dma-sh7780.h39
-rw-r--r--include/asm-sh/cpu-sh4/dma.h11
-rw-r--r--include/asm-sh/cpu-sh4/rtc.h25
-rw-r--r--include/asm-sh/cpu-sh4/shmparam.h19
-rw-r--r--include/asm-sh/cpu-sh4/sq.h23
-rw-r--r--include/asm-sh/cpu-sh4/ubc.h37
-rw-r--r--include/asm-sh/cqreek/cqreek.h27
-rw-r--r--include/asm-sh/dma-mapping.h42
-rw-r--r--include/asm-sh/dma.h1
-rw-r--r--include/asm-sh/dmida/io.h10
-rw-r--r--include/asm-sh/dreamcast/sysasic.h2
-rw-r--r--include/asm-sh/ec3104/keyboard.h2
-rw-r--r--include/asm-sh/elf.h29
-rw-r--r--include/asm-sh/fixmap.h2
-rw-r--r--include/asm-sh/flat.h2
-rw-r--r--include/asm-sh/harp/harp.h43
-rw-r--r--include/asm-sh/harp/io.h10
-rw-r--r--include/asm-sh/hd64461.h (renamed from include/asm-sh/hd64461/hd64461.h)56
-rw-r--r--include/asm-sh/hd64461/io.h43
-rw-r--r--include/asm-sh/hd64465/io.h2
-rw-r--r--include/asm-sh/hp6xx/hp6xx.h53
-rw-r--r--include/asm-sh/hp6xx/io.h2
-rw-r--r--include/asm-sh/hs7751rvoip/hs7751rvoip.h11
-rw-r--r--include/asm-sh/hs7751rvoip/io.h39
-rw-r--r--include/asm-sh/hw_irq.h4
-rw-r--r--include/asm-sh/io.h32
-rw-r--r--include/asm-sh/irq-sh73180.h2
-rw-r--r--include/asm-sh/irq-sh7343.h317
-rw-r--r--include/asm-sh/irq-sh7780.h5
-rw-r--r--include/asm-sh/irq.h151
-rw-r--r--include/asm-sh/irq_regs.h1
-rw-r--r--include/asm-sh/kexec.h9
-rw-r--r--include/asm-sh/kgdb.h15
-rw-r--r--include/asm-sh/landisk/gio.h45
-rw-r--r--include/asm-sh/landisk/ide.h14
-rw-r--r--include/asm-sh/landisk/iodata_landisk.h79
-rw-r--r--include/asm-sh/machvec.h7
-rw-r--r--include/asm-sh/mc146818rtc.h169
-rw-r--r--include/asm-sh/mmu.h77
-rw-r--r--include/asm-sh/mmu_context.h15
-rw-r--r--include/asm-sh/mpc1211/io.h2
-rw-r--r--include/asm-sh/mpc1211/keyboard.h4
-rw-r--r--include/asm-sh/overdrive/fpga.h15
-rw-r--r--include/asm-sh/overdrive/gt64111.h109
-rw-r--r--include/asm-sh/overdrive/io.h39
-rw-r--r--include/asm-sh/overdrive/overdrive.h88
-rw-r--r--include/asm-sh/page.h33
-rw-r--r--include/asm-sh/pci.h44
-rw-r--r--include/asm-sh/pgalloc.h37
-rw-r--r--include/asm-sh/pgtable.h154
-rw-r--r--include/asm-sh/pm.h17
-rw-r--r--include/asm-sh/processor.h52
-rw-r--r--include/asm-sh/r7780rp/ide.h8
-rw-r--r--include/asm-sh/r7780rp/r7780rp.h177
-rw-r--r--include/asm-sh/rtc.h25
-rw-r--r--include/asm-sh/rts7751r2d/io.h37
-rw-r--r--include/asm-sh/rts7751r2d/rts7751r2d.h5
-rw-r--r--include/asm-sh/scatterlist.h9
-rw-r--r--include/asm-sh/sci.h34
-rw-r--r--include/asm-sh/se.h (renamed from include/asm-sh/se/se.h)3
-rw-r--r--include/asm-sh/se/io.h35
-rw-r--r--include/asm-sh/se7300.h (renamed from include/asm-sh/se7300/se7300.h)3
-rw-r--r--include/asm-sh/se7300/io.h29
-rw-r--r--include/asm-sh/se73180.h (renamed from include/asm-sh/se73180/se73180.h)3
-rw-r--r--include/asm-sh/se73180/io.h32
-rw-r--r--include/asm-sh/se7343.h82
-rw-r--r--include/asm-sh/se7751.h (renamed from include/asm-sh/se7751/se7751.h)3
-rw-r--r--include/asm-sh/se7751/io.h42
-rw-r--r--include/asm-sh/setup.h2
-rw-r--r--include/asm-sh/sfp-machine.h84
-rw-r--r--include/asm-sh/sh03/io.h10
-rw-r--r--include/asm-sh/sh2000/sh2000.h8
-rw-r--r--include/asm-sh/shmin/shmin.h9
-rw-r--r--include/asm-sh/shmparam.h20
-rw-r--r--include/asm-sh/smc37c93x.h (renamed from include/asm-sh/se/smc37c93x.h)0
-rw-r--r--include/asm-sh/smp.h5
-rw-r--r--include/asm-sh/snapgear.h (renamed from include/asm-sh/snapgear/io.h)31
-rw-r--r--include/asm-sh/spinlock.h13
-rw-r--r--include/asm-sh/string.h15
-rw-r--r--include/asm-sh/system.h199
-rw-r--r--include/asm-sh/systemh/io.h43
-rw-r--r--include/asm-sh/systemh7751.h (renamed from include/asm-sh/systemh/7751systemh.h)3
-rw-r--r--include/asm-sh/thread_info.h43
-rw-r--r--include/asm-sh/timer.h15
-rw-r--r--include/asm-sh/titan.h43
-rw-r--r--include/asm-sh/uaccess.h79
-rw-r--r--include/asm-sh/unistd.h121
-rw-r--r--include/asm-sh/voyagergx.h (renamed from include/asm-sh/rts7751r2d/voyagergx_reg.h)2
-rw-r--r--include/asm-sh/watchdog.h3
-rw-r--r--include/asm-sh64/io.h16
-rw-r--r--include/asm-sh64/keyboard.h4
-rw-r--r--include/asm-sh64/serial.h2
-rw-r--r--include/asm-sh64/timex.h3
-rw-r--r--include/asm-sh64/unistd.h47
-rw-r--r--include/asm-sparc/elf.h41
-rw-r--r--include/asm-sparc/floppy.h2
-rw-r--r--include/asm-sparc/irq.h6
-rw-r--r--include/asm-sparc/irq_regs.h1
-rw-r--r--include/asm-sparc/reg.h2
-rw-r--r--include/asm-sparc/spinlock.h32
-rw-r--r--include/asm-sparc/unistd.h47
-rw-r--r--include/asm-sparc64/compat_signal.h29
-rw-r--r--include/asm-sparc64/floppy.h8
-rw-r--r--include/asm-sparc64/io.h15
-rw-r--r--include/asm-sparc64/irq_regs.h1
-rw-r--r--include/asm-sparc64/signal.h42
-rw-r--r--include/asm-sparc64/spinlock.h4
-rw-r--r--include/asm-sparc64/unistd.h42
-rw-r--r--include/asm-um/archparam-ppc.h9
-rw-r--r--include/asm-um/irq_regs.h1
-rw-r--r--include/asm-um/pgtable.h6
-rw-r--r--include/asm-um/processor-generic.h6
-rw-r--r--include/asm-um/ptrace-x86_64.h3
-rw-r--r--include/asm-um/unistd.h28
-rw-r--r--include/asm-v850/unistd.h56
-rw-r--r--include/asm-x86_64/alternative-asm.i2
-rw-r--r--include/asm-x86_64/apic.h2
-rw-r--r--include/asm-x86_64/cache.h2
-rw-r--r--include/asm-x86_64/dma-mapping.h7
-rw-r--r--include/asm-x86_64/e820.h5
-rw-r--r--include/asm-x86_64/floppy.h6
-rw-r--r--include/asm-x86_64/genapic.h1
-rw-r--r--include/asm-x86_64/hardirq.h3
-rw-r--r--include/asm-x86_64/hw_irq.h8
-rw-r--r--include/asm-x86_64/hypertransport.h42
-rw-r--r--include/asm-x86_64/io.h27
-rw-r--r--include/asm-x86_64/io_apic.h43
-rw-r--r--include/asm-x86_64/irq.h7
-rw-r--r--include/asm-x86_64/irq_regs.h1
-rw-r--r--include/asm-x86_64/mach_apic.h1
-rw-r--r--include/asm-x86_64/msi.h24
-rw-r--r--include/asm-x86_64/msidef.h47
-rw-r--r--include/asm-x86_64/nmi.h7
-rw-r--r--include/asm-x86_64/percpu.h6
-rw-r--r--include/asm-x86_64/pgtable.h1
-rw-r--r--include/asm-x86_64/processor.h2
-rw-r--r--include/asm-x86_64/proto.h8
-rw-r--r--include/asm-x86_64/ptrace.h2
-rw-r--r--include/asm-x86_64/semaphore.h4
-rw-r--r--include/asm-x86_64/spinlock.h5
-rw-r--r--include/asm-x86_64/topology.h1
-rw-r--r--include/asm-x86_64/uaccess.h7
-rw-r--r--include/asm-x86_64/unistd.h98
-rw-r--r--include/asm-x86_64/vsyscall.h3
-rw-r--r--include/asm-xtensa/a.out.h2
-rw-r--r--include/asm-xtensa/cache.h2
-rw-r--r--include/asm-xtensa/coprocessor.h2
-rw-r--r--include/asm-xtensa/dma-mapping.h2
-rw-r--r--include/asm-xtensa/ioctls.h2
-rw-r--r--include/asm-xtensa/pgtable.h2
-rw-r--r--include/asm-xtensa/siginfo.h2
-rw-r--r--include/asm-xtensa/timex.h3
-rw-r--r--include/asm-xtensa/unistd.h5
-rw-r--r--include/linux/Kbuild13
-rw-r--r--include/linux/ac97_codec.h5
-rw-r--r--include/linux/acct.h4
-rw-r--r--include/linux/acpi.h3
-rw-r--r--include/linux/adb.h4
-rw-r--r--include/linux/aer.h24
-rw-r--r--include/linux/aio.h12
-rw-r--r--include/linux/aio_abi.h4
-rw-r--r--include/linux/arcdevice.h2
-rw-r--r--include/linux/atalk.h40
-rw-r--r--include/linux/atmlec.h119
-rw-r--r--include/linux/audit.h8
-rw-r--r--include/linux/awe_voice.h2
-rw-r--r--include/linux/backing-dev.h7
-rw-r--r--include/linux/bio.h5
-rw-r--r--include/linux/bitmap.h13
-rw-r--r--include/linux/blkdev.h368
-rw-r--r--include/linux/blktrace_api.h3
-rw-r--r--include/linux/buffer_head.h21
-rw-r--r--include/linux/carta_random32.h29
-rw-r--r--include/linux/cdev.h2
-rw-r--r--include/linux/cdrom.h28
-rw-r--r--include/linux/compat.h4
-rw-r--r--include/linux/compat_ioctl.h47
-rw-r--r--include/linux/compiler.h12
-rw-r--r--include/linux/config.h8
-rw-r--r--include/linux/console.h3
-rw-r--r--include/linux/console_struct.h2
-rw-r--r--include/linux/consolemap.h1
-rw-r--r--include/linux/cpumask.h14
-rw-r--r--include/linux/cpuset.h4
-rw-r--r--include/linux/cramfs_fs.h2
-rw-r--r--include/linux/dcache.h1
-rw-r--r--include/linux/dccp.h2
-rw-r--r--include/linux/debug_locks.h2
-rw-r--r--include/linux/device-mapper.h14
-rw-r--r--include/linux/dlm.h302
-rw-r--r--include/linux/dlm_device.h86
-rw-r--r--include/linux/dm-ioctl.h4
-rw-r--r--include/linux/dma-mapping.h7
-rw-r--r--include/linux/dmi.h5
-rw-r--r--include/linux/eisa.h8
-rw-r--r--include/linux/elevator.h69
-rw-r--r--include/linux/err.h4
-rw-r--r--include/linux/errqueue.h2
-rw-r--r--include/linux/ext2_fs.h64
-rw-r--r--include/linux/ext3_fs.h30
-rw-r--r--include/linux/ext3_fs_i.h2
-rw-r--r--include/linux/ext3_jbd.h10
-rw-r--r--include/linux/ext4_fs.h994
-rw-r--r--include/linux/ext4_fs_extents.h198
-rw-r--r--include/linux/ext4_fs_i.h158
-rw-r--r--include/linux/ext4_fs_sb.h94
-rw-r--r--include/linux/ext4_jbd2.h273
-rw-r--r--include/linux/fb.h3
-rw-r--r--include/linux/file.h1
-rw-r--r--include/linux/fs.h165
-rw-r--r--include/linux/fs_enet_pd.h47
-rw-r--r--include/linux/fs_uart_pd.h14
-rw-r--r--include/linux/fsl_devices.h65
-rw-r--r--include/linux/genalloc.h1
-rw-r--r--include/linux/generic_acl.h36
-rw-r--r--include/linux/genhd.h4
-rw-r--r--include/linux/getcpu.h12
-rw-r--r--include/linux/gfp.h5
-rw-r--r--include/linux/gfs2_ondisk.h443
-rw-r--r--include/linux/hardirq.h7
-rw-r--r--include/linux/harrier_defs.h2
-rw-r--r--include/linux/hdlc.h201
-rw-r--r--include/linux/hdlc/ioctl.h33
-rw-r--r--include/linux/hiddev.h4
-rw-r--r--include/linux/hrtimer.h1
-rw-r--r--include/linux/htirq.h15
-rw-r--r--include/linux/hugetlb.h1
-rw-r--r--include/linux/i2c-algo-bit.h1
-rw-r--r--include/linux/i2c-algo-pcf.h1
-rw-r--r--include/linux/i2c-algo-sibyte.h33
-rw-r--r--include/linux/i2c-id.h1
-rw-r--r--include/linux/i2c.h14
-rw-r--r--include/linux/icmp.h12
-rw-r--r--include/linux/ide.h14
-rw-r--r--include/linux/if.h132
-rw-r--r--include/linux/if_arp.h6
-rw-r--r--include/linux/if_link.h136
-rw-r--r--include/linux/if_vlan.h2
-rw-r--r--include/linux/igmp.h38
-rw-r--r--include/linux/in.h13
-rw-r--r--include/linux/in6.h6
-rw-r--r--include/linux/inet_diag.h10
-rw-r--r--include/linux/inetdevice.h24
-rw-r--r--include/linux/init.h1
-rw-r--r--include/linux/init_task.h12
-rw-r--r--include/linux/input.h279
-rw-r--r--include/linux/interrupt.h25
-rw-r--r--include/linux/io.h32
-rw-r--r--include/linux/ioc3.h2
-rw-r--r--include/linux/ioc4.h2
-rw-r--r--include/linux/ip.h23
-rw-r--r--include/linux/ipc.h55
-rw-r--r--include/linux/ipmi.h48
-rw-r--r--include/linux/ipsec.h3
-rw-r--r--include/linux/ipv6.h16
-rw-r--r--include/linux/irq.h140
-rw-r--r--include/linux/istallion.h4
-rw-r--r--include/linux/ite_gpio.h66
-rw-r--r--include/linux/jbd.h71
-rw-r--r--include/linux/jbd2.h1107
-rw-r--r--include/linux/kallsyms.h11
-rw-r--r--include/linux/kernel.h13
-rw-r--r--include/linux/kmod.h4
-rw-r--r--include/linux/kprobes.h8
-rw-r--r--include/linux/latency.h25
-rw-r--r--include/linux/leds.h3
-rw-r--r--include/linux/libata.h13
-rw-r--r--include/linux/libps2.h1
-rw-r--r--include/linux/list.h15
-rw-r--r--include/linux/lm_interface.h273
-rw-r--r--include/linux/lock_dlm_plock.h41
-rw-r--r--include/linux/lockd/bind.h7
-rw-r--r--include/linux/lockd/lockd.h75
-rw-r--r--include/linux/lockd/share.h7
-rw-r--r--include/linux/lockd/sm_inter.h5
-rw-r--r--include/linux/lockd/xdr.h30
-rw-r--r--include/linux/lockd/xdr4.h28
-rw-r--r--include/linux/lockdep.h21
-rw-r--r--include/linux/loop.h5
-rw-r--r--include/linux/magic.h1
-rw-r--r--include/linux/memory.h4
-rw-r--r--include/linux/memory_hotplug.h2
-rw-r--r--include/linux/mempolicy.h2
-rw-r--r--include/linux/mm.h144
-rw-r--r--include/linux/mm_types.h67
-rw-r--r--include/linux/mmc/host.h2
-rw-r--r--include/linux/mmc/mmc.h1
-rw-r--r--include/linux/mmc/protocol.h1
-rw-r--r--include/linux/mmzone.h23
-rw-r--r--include/linux/mod_devicetable.h12
-rw-r--r--include/linux/module.h7
-rw-r--r--include/linux/mpage.h7
-rw-r--r--include/linux/mroute.h14
-rw-r--r--include/linux/msdos_fs.h3
-rw-r--r--include/linux/msi.h49
-rw-r--r--include/linux/mtd/nand.h25
-rw-r--r--include/linux/mtd/onenand.h6
-rw-r--r--include/linux/mtd/onenand_regs.h4
-rw-r--r--include/linux/mtd/plat-ram.h2
-rw-r--r--include/linux/namei.h2
-rw-r--r--include/linux/namespace.h6
-rw-r--r--include/linux/nbd.h2
-rw-r--r--include/linux/ncp_fs.h1
-rw-r--r--include/linux/net.h7
-rw-r--r--include/linux/netdevice.h10
-rw-r--r--include/linux/netfilter_arp/arp_tables.h6
-rw-r--r--include/linux/netfilter_bridge/ebt_mark_t.h12
-rw-r--r--include/linux/netfilter_ipv4.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_h323.h6
-rw-r--r--include/linux/netfilter_ipv4/ip_conntrack_tuple.h16
-rw-r--r--include/linux/netfilter_ipv4/ip_nat.h2
-rw-r--r--include/linux/netfilter_ipv4/ip_queue.h2
-rw-r--r--include/linux/netfilter_ipv4/ipt_iprange.h2
-rw-r--r--include/linux/nfs_fs.h17
-rw-r--r--include/linux/nfs_xdr.h10
-rw-r--r--include/linux/nfsd/cache.h6
-rw-r--r--include/linux/nfsd/const.h20
-rw-r--r--include/linux/nfsd/export.h25
-rw-r--r--include/linux/nfsd/nfsd.h53
-rw-r--r--include/linux/nfsd/nfsfh.h29
-rw-r--r--include/linux/nfsd/state.h12
-rw-r--r--include/linux/nfsd/stats.h2
-rw-r--r--include/linux/nfsd/syscall.h17
-rw-r--r--include/linux/nfsd/xdr.h54
-rw-r--r--include/linux/nfsd/xdr3.h116
-rw-r--r--include/linux/nfsd/xdr4.h56
-rw-r--r--include/linux/nmi.h3
-rw-r--r--include/linux/nodemask.h16
-rw-r--r--include/linux/notifier.h43
-rw-r--r--include/linux/nsproxy.h52
-rw-r--r--include/linux/oom.h10
-rw-r--r--include/linux/page-flags.h11
-rw-r--r--include/linux/parport.h16
-rw-r--r--include/linux/pci.h34
-rw-r--r--include/linux/pci_hotplug.h (renamed from drivers/pci/hotplug/pci_hotplug.h)6
-rw-r--r--include/linux/pci_ids.h17
-rw-r--r--include/linux/pci_regs.h23
-rw-r--r--include/linux/pcieport_if.h6
-rw-r--r--include/linux/percpu.h4
-rw-r--r--include/linux/personality.h7
-rw-r--r--include/linux/pid.h51
-rw-r--r--include/linux/posix-timers.h4
-rw-r--r--include/linux/ppdev.h2
-rw-r--r--include/linux/proc_fs.h12
-rw-r--r--include/linux/profile.h2
-rw-r--r--include/linux/pspace.h23
-rw-r--r--include/linux/ptrace.h4
-rw-r--r--include/linux/raid/bitmap.h22
-rw-r--r--include/linux/raid/md.h4
-rw-r--r--include/linux/raid/md_k.h14
-rw-r--r--include/linux/raid/md_p.h56
-rw-r--r--include/linux/raid/md_u.h2
-rw-r--r--include/linux/raid/raid1.h1
-rw-r--r--include/linux/raid/raid10.h1
-rw-r--r--include/linux/raid/raid5.h7
-rw-r--r--include/linux/raid_class.h5
-rw-r--r--include/linux/ramfs.h1
-rw-r--r--include/linux/random.h3
-rw-r--r--include/linux/rbtree.h2
-rw-r--r--include/linux/rcupdate.h7
-rw-r--r--include/linux/reiserfs_acl.h17
-rw-r--r--include/linux/reiserfs_fs.h41
-rw-r--r--include/linux/reiserfs_fs_i.h5
-rw-r--r--include/linux/reiserfs_fs_sb.h2
-rw-r--r--include/linux/reiserfs_xattr.h8
-rw-r--r--include/linux/rtc.h6
-rw-r--r--include/linux/rtnetlink.h2
-rw-r--r--include/linux/sched.h97
-rw-r--r--include/linux/scx200.h2
-rw-r--r--include/linux/scx200_gpio.h1
-rw-r--r--include/linux/security.h25
-rw-r--r--include/linux/serial_core.h12
-rw-r--r--include/linux/serio.h9
-rw-r--r--include/linux/shmem_fs.h24
-rw-r--r--include/linux/slab.h32
-rw-r--r--include/linux/smb.h1
-rw-r--r--include/linux/smb_fs.h12
-rw-r--r--include/linux/sound.h2
-rw-r--r--include/linux/spinlock.h14
-rw-r--r--include/linux/spinlock_api_smp.h50
-rw-r--r--include/linux/srcu.h53
-rw-r--r--include/linux/stat.h2
-rw-r--r--include/linux/stddef.h6
-rw-r--r--include/linux/string.h1
-rw-r--r--include/linux/sunrpc/auth.h19
-rw-r--r--include/linux/sunrpc/auth_gss.h2
-rw-r--r--include/linux/sunrpc/cache.h11
-rw-r--r--include/linux/sunrpc/gss_api.h2
-rw-r--r--include/linux/sunrpc/msg_prot.h48
-rw-r--r--include/linux/sunrpc/svc.h218
-rw-r--r--include/linux/sunrpc/svcauth.h5
-rw-r--r--include/linux/sunrpc/svcauth_gss.h2
-rw-r--r--include/linux/sunrpc/svcsock.h18
-rw-r--r--include/linux/sunrpc/xdr.h39
-rw-r--r--include/linux/sunrpc/xprt.h20
-rw-r--r--include/linux/synclink.h4
-rw-r--r--include/linux/syscalls.h10
-rw-r--r--include/linux/sysrq.h10
-rw-r--r--include/linux/taskstats.h64
-rw-r--r--include/linux/tcp.h25
-rw-r--r--include/linux/tifm.h159
-rw-r--r--include/linux/timex.h61
-rw-r--r--include/linux/tipc.h1
-rw-r--r--include/linux/topology.h46
-rw-r--r--include/linux/trdevice.h2
-rw-r--r--include/linux/tsacct_kern.h34
-rw-r--r--include/linux/tty.h6
-rw-r--r--include/linux/tty_driver.h3
-rw-r--r--include/linux/types.h8
-rw-r--r--include/linux/uaccess.h22
-rw-r--r--include/linux/udp.h8
-rw-r--r--include/linux/ufs_fs.h10
-rw-r--r--include/linux/uinput.h35
-rw-r--r--include/linux/unistd.h6
-rw-r--r--include/linux/unwind.h4
-rw-r--r--include/linux/usb.h159
-rw-r--r--include/linux/usb/audio.h53
-rw-r--r--include/linux/usb/midi.h112
-rw-r--r--include/linux/usb/otg.h (renamed from include/linux/usb_otg.h)4
-rw-r--r--include/linux/usb/serial.h12
-rw-r--r--include/linux/usb_usual.h3
-rw-r--r--include/linux/utime.h2
-rw-r--r--include/linux/utsname.h62
-rw-r--r--include/linux/videodev2.h87
-rw-r--r--include/linux/vmalloc.h1
-rw-r--r--include/linux/vmstat.h1
-rw-r--r--include/linux/vt_kern.h10
-rw-r--r--include/linux/wavefront.h675
-rw-r--r--include/linux/wireless.h24
-rw-r--r--include/linux/writeback.h6
-rw-r--r--include/linux/xattr.h1
-rw-r--r--include/linux/xfrm.h19
-rw-r--r--include/media/audiochip.h4
-rw-r--r--include/media/ir-common.h2
-rw-r--r--include/media/tuner-types.h3
-rw-r--r--include/media/tuner.h1
-rw-r--r--include/media/v4l2-common.h16
-rw-r--r--include/media/v4l2-dev.h10
-rw-r--r--include/mtd/Kbuild3
-rw-r--r--include/mtd/mtd-abi.h6
-rw-r--r--include/net/arp.h8
-rw-r--r--include/net/bluetooth/hci.h11
-rw-r--r--include/net/bluetooth/hci_core.h35
-rw-r--r--include/net/cipso_ipv4.h5
-rw-r--r--include/net/dst.h2
-rw-r--r--include/net/flow.h12
-rw-r--r--include/net/genetlink.h18
-rw-r--r--include/net/icmp.h2
-rw-r--r--include/net/inet_connection_sock.h6
-rw-r--r--include/net/inet_hashtables.h56
-rw-r--r--include/net/inet_sock.h34
-rw-r--r--include/net/inet_timewait_sock.h11
-rw-r--r--include/net/inetpeer.h26
-rw-r--r--include/net/ip.h10
-rw-r--r--include/net/ip6_route.h7
-rw-r--r--include/net/ip_fib.h31
-rw-r--r--include/net/ip_mp_alg.h4
-rw-r--r--include/net/ip_vs.h68
-rw-r--r--include/net/ipv6.h6
-rw-r--r--include/net/irda/irlan_common.h10
-rw-r--r--include/net/irda/irlap_frame.h31
-rw-r--r--include/net/irda/irlmp.h2
-rw-r--r--include/net/netdma.h1
-rw-r--r--include/net/netlabel.h70
-rw-r--r--include/net/netlink.h12
-rw-r--r--include/net/route.h24
-rw-r--r--include/net/sctp/sctp.h14
-rw-r--r--include/net/sctp/ulpevent.h1
-rw-r--r--include/net/sock.h1
-rw-r--r--include/net/timewait_sock.h7
-rw-r--r--include/net/xfrm.h29
-rw-r--r--include/scsi/scsi_device.h4
-rw-r--r--include/scsi/scsi_tcq.h25
-rw-r--r--include/scsi/sg.h61
-rw-r--r--include/sound/core.h4
-rw-r--r--include/sound/cs4231.h2
-rw-r--r--include/sound/emu10k1.h2
-rw-r--r--include/sound/gus.h2
-rw-r--r--include/sound/initval.h2
-rw-r--r--include/sound/mpu401.h6
-rw-r--r--include/sound/pcm.h1
-rw-r--r--include/sound/sb.h6
-rw-r--r--include/sound/version.h6
-rw-r--r--include/sound/vx_core.h2
-rw-r--r--include/video/s1d13xxxfb.h2
-rw-r--r--include/video/sstfb.h4
-rw-r--r--init/Kconfig64
-rw-r--r--init/do_mounts.c13
-rw-r--r--init/do_mounts.h1
-rw-r--r--init/do_mounts_initrd.c3
-rw-r--r--init/do_mounts_md.c8
-rw-r--r--init/main.c27
-rw-r--r--init/version.c23
-rw-r--r--ipc/mqueue.c39
-rw-r--r--ipc/msg.c157
-rw-r--r--ipc/msgutil.c2
-rw-r--r--ipc/sem.c206
-rw-r--r--ipc/shm.c254
-rw-r--r--ipc/util.c132
-rw-r--r--ipc/util.h24
-rw-r--r--kernel/Makefile5
-rw-r--r--kernel/acct.c36
-rw-r--r--kernel/audit.c3
-rw-r--r--kernel/auditfilter.c9
-rw-r--r--kernel/auditsc.c33
-rw-r--r--kernel/capability.c2
-rw-r--r--kernel/compat.c33
-rw-r--r--kernel/cpu.c24
-rw-r--r--kernel/cpuset.c115
-rw-r--r--kernel/dma.c10
-rw-r--r--kernel/exit.c52
-rw-r--r--kernel/fork.c101
-rw-r--r--kernel/futex.c27
-rw-r--r--kernel/futex_compat.c12
-rw-r--r--kernel/hrtimer.c20
-rw-r--r--kernel/irq/chip.c146
-rw-r--r--kernel/irq/handle.c19
-rw-r--r--kernel/irq/manage.c4
-rw-r--r--kernel/irq/migration.c34
-rw-r--r--kernel/irq/proc.c2
-rw-r--r--kernel/irq/resend.c2
-rw-r--r--kernel/irq/spurious.c10
-rw-r--r--kernel/kallsyms.c124
-rw-r--r--kernel/kexec.c8
-rw-r--r--kernel/kfifo.c28
-rw-r--r--kernel/kmod.c74
-rw-r--r--kernel/kprobes.c53
-rw-r--r--kernel/latency.c279
-rw-r--r--kernel/lockdep.c40
-rw-r--r--kernel/module.c92
-rw-r--r--kernel/mutex-debug.c2
-rw-r--r--kernel/nsproxy.c137
-rw-r--r--kernel/panic.c1
-rw-r--r--kernel/params.c15
-rw-r--r--kernel/pid.c123
-rw-r--r--kernel/posix-cpu-timers.c128
-rw-r--r--kernel/posix-timers.c23
-rw-r--r--kernel/power/disk.c8
-rw-r--r--kernel/power/poweroff.c3
-rw-r--r--kernel/power/snapshot.c10
-rw-r--r--kernel/power/swap.c3
-rw-r--r--kernel/power/user.c10
-rw-r--r--kernel/printk.c11
-rw-r--r--kernel/profile.c7
-rw-r--r--kernel/ptrace.c55
-rw-r--r--kernel/rcupdate.c11
-rw-r--r--kernel/rcutorture.c327
-rw-r--r--kernel/relay.c79
-rw-r--r--kernel/resource.c115
-rw-r--r--kernel/rtmutex-debug.c1
-rw-r--r--kernel/rtmutex-tester.c1
-rw-r--r--kernel/rtmutex.c51
-rw-r--r--kernel/sched.c424
-rw-r--r--kernel/signal.c76
-rw-r--r--kernel/softirq.c4
-rw-r--r--kernel/softlockup.c3
-rw-r--r--kernel/spinlock.c15
-rw-r--r--kernel/srcu.c258
-rw-r--r--kernel/stop_machine.c3
-rw-r--r--kernel/sys.c236
-rw-r--r--kernel/sys_ni.c6
-rw-r--r--kernel/sysctl.c482
-rw-r--r--kernel/taskstats.c10
-rw-r--r--kernel/time.c173
-rw-r--r--kernel/time/Makefile2
-rw-r--r--kernel/time/jiffies.c2
-rw-r--r--kernel/time/ntp.c350
-rw-r--r--kernel/timer.c283
-rw-r--r--kernel/tsacct.c124
-rw-r--r--kernel/unwind.c322
-rw-r--r--kernel/utsname.c95
-rw-r--r--kernel/workqueue.c9
-rw-r--r--lib/Kconfig.debug43
-rw-r--r--lib/Makefile8
-rw-r--r--lib/bitmap.c54
-rw-r--r--lib/errno.c7
-rw-r--r--lib/genalloc.c63
-rw-r--r--lib/ioremap.c92
-rw-r--r--lib/irq_regs.c17
-rw-r--r--lib/kobject.c1
-rw-r--r--lib/list_debug.c76
-rw-r--r--lib/radix-tree.c6
-rw-r--r--lib/random32.c142
-rw-r--r--lib/rbtree.c6
-rw-r--r--lib/reed_solomon/reed_solomon.c2
-rw-r--r--lib/rwsem-spinlock.c2
-rw-r--r--lib/rwsem.c4
-rw-r--r--lib/sort.c10
-rw-r--r--lib/spinlock_debug.c19
-rw-r--r--lib/ts_fsm.c10
-rw-r--r--mm/Kconfig11
-rw-r--r--mm/Makefile7
-rw-r--r--mm/backing-dev.c69
-rw-r--r--mm/bounce.c302
-rw-r--r--mm/filemap.c281
-rw-r--r--mm/filemap.h1
-rw-r--r--mm/fremap.c2
-rw-r--r--mm/highmem.c281
-rw-r--r--mm/hugetlb.c30
-rw-r--r--mm/memory.c148
-rw-r--r--mm/memory_hotplug.c71
-rw-r--r--mm/mempolicy.c9
-rw-r--r--mm/migrate.c4
-rw-r--r--mm/mmap.c21
-rw-r--r--mm/mprotect.c2
-rw-r--r--mm/mremap.c2
-rw-r--r--mm/nommu.c250
-rw-r--r--mm/oom_kill.c54
-rw-r--r--mm/page-writeback.c179
-rw-r--r--mm/page_alloc.c780
-rw-r--r--mm/readahead.c1
-rw-r--r--mm/rmap.c41
-rw-r--r--mm/shmem.c205
-rw-r--r--mm/shmem_acl.c197
-rw-r--r--mm/slab.c202
-rw-r--r--mm/slob.c3
-rw-r--r--mm/swapfile.c7
-rw-r--r--mm/truncate.c85
-rw-r--r--mm/util.c22
-rw-r--r--mm/vmalloc.c43
-rw-r--r--mm/vmscan.c42
-rw-r--r--mm/vmstat.c4
-rw-r--r--net/802/tr.c12
-rw-r--r--net/8021q/vlan_dev.c2
-rw-r--r--net/Kconfig2
-rw-r--r--net/appletalk/ddp.c79
-rw-r--r--net/atm/lec.c3161
-rw-r--r--net/atm/lec.h171
-rw-r--r--net/atm/lec_arpc.h146
-rw-r--r--net/atm/mpc.c13
-rw-r--r--net/atm/mpoa_caches.c12
-rw-r--r--net/bluetooth/af_bluetooth.c40
-rw-r--r--net/bluetooth/bnep/core.c24
-rw-r--r--net/bluetooth/bnep/sock.c69
-rw-r--r--net/bluetooth/cmtp/sock.c35
-rw-r--r--net/bluetooth/hci_conn.c45
-rw-r--r--net/bluetooth/hci_core.c3
-rw-r--r--net/bluetooth/hci_event.c41
-rw-r--r--net/bluetooth/hci_sock.c2
-rw-r--r--net/bluetooth/hci_sysfs.c148
-rw-r--r--net/bluetooth/hidp/core.c31
-rw-r--r--net/bluetooth/hidp/sock.c80
-rw-r--r--net/bluetooth/l2cap.c5
-rw-r--r--net/bluetooth/rfcomm/core.c5
-rw-r--r--net/bluetooth/rfcomm/sock.c6
-rw-r--r--net/bluetooth/rfcomm/tty.c24
-rw-r--r--net/bluetooth/sco.c6
-rw-r--r--net/bridge/br_fdb.c7
-rw-r--r--net/bridge/br_if.c4
-rw-r--r--net/bridge/br_private.h2
-rw-r--r--net/bridge/br_stp_if.c2
-rw-r--r--net/bridge/netfilter/ebt_arpreply.c2
-rw-r--r--net/bridge/netfilter/ebt_mark.c21
-rw-r--r--net/compat.c3
-rw-r--r--net/core/dev.c16
-rw-r--r--net/core/ethtool.c32
-rw-r--r--net/core/fib_rules.c1
-rw-r--r--net/core/flow.c42
-rw-r--r--net/core/neighbour.c14
-rw-r--r--net/core/net-sysfs.c5
-rw-r--r--net/core/netpoll.c8
-rw-r--r--net/core/pktgen.c321
-rw-r--r--net/core/rtnetlink.c4
-rw-r--r--net/core/scm.c3
-rw-r--r--net/core/skbuff.c3
-rw-r--r--net/core/sock.c2
-rw-r--r--net/core/utils.c118
-rw-r--r--net/core/wireless.c67
-rw-r--r--net/dccp/ipv4.c8
-rw-r--r--net/dccp/ipv6.c6
-rw-r--r--net/decnet/af_decnet.c4
-rw-r--r--net/decnet/dn_route.c14
-rw-r--r--net/ethernet/eth.c2
-rw-r--r--net/ieee80211/softmac/ieee80211softmac_wx.c8
-rw-r--r--net/ipv4/Kconfig15
-rw-r--r--net/ipv4/Makefile1
-rw-r--r--net/ipv4/af_inet.c8
-rw-r--r--net/ipv4/arp.c42
-rw-r--r--net/ipv4/cipso_ipv4.c48
-rw-r--r--net/ipv4/datagram.c2
-rw-r--r--net/ipv4/devinet.c42
-rw-r--r--net/ipv4/esp4.c26
-rw-r--r--net/ipv4/fib_frontend.c40
-rw-r--r--net/ipv4/fib_hash.c22
-rw-r--r--net/ipv4/fib_lookup.h6
-rw-r--r--net/ipv4/fib_rules.c24
-rw-r--r--net/ipv4/fib_semantics.c33
-rw-r--r--net/ipv4/fib_trie.c12
-rw-r--r--net/ipv4/icmp.c10
-rw-r--r--net/ipv4/igmp.c68
-rw-r--r--net/ipv4/inet_connection_sock.c12
-rw-r--r--net/ipv4/inet_diag.c12
-rw-r--r--net/ipv4/inet_hashtables.c12
-rw-r--r--net/ipv4/inetpeer.c33
-rw-r--r--net/ipv4/ip_fragment.c15
-rw-r--r--net/ipv4/ip_gre.c4
-rw-r--r--net/ipv4/ip_options.c26
-rw-r--r--net/ipv4/ip_output.c6
-rw-r--r--net/ipv4/ip_sockglue.c4
-rw-r--r--net/ipv4/ipcomp.c7
-rw-r--r--net/ipv4/ipconfig.c16
-rw-r--r--net/ipv4/ipmr.c4
-rw-r--r--net/ipv4/ipvs/Kconfig4
-rw-r--r--net/ipv4/ipvs/ip_vs_conn.c24
-rw-r--r--net/ipv4/ipvs/ip_vs_core.c24
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c26
-rw-r--r--net/ipv4/ipvs/ip_vs_dh.c4
-rw-r--r--net/ipv4/ipvs/ip_vs_ftp.c29
-rw-r--r--net/ipv4/ipvs/ip_vs_lblc.c8
-rw-r--r--net/ipv4/ipvs/ip_vs_lblcr.c8
-rw-r--r--net/ipv4/ipvs/ip_vs_proto.c2
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_tcp.c10
-rw-r--r--net/ipv4/ipvs/ip_vs_proto_udp.c14
-rw-r--r--net/ipv4/ipvs/ip_vs_sh.c4
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c20
-rw-r--r--net/ipv4/ipvs/ip_vs_xmit.c2
-rw-r--r--net/ipv4/multipath_wrandom.c14
-rw-r--r--net/ipv4/netfilter.c13
-rw-r--r--net/ipv4/netfilter/Kconfig2
-rw-r--r--net/ipv4/netfilter/arp_tables.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_amanda.c6
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c12
-rw-r--r--net/ipv4/netfilter/ip_conntrack_ftp.c6
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_h323.c84
-rw-r--r--net/ipv4/netfilter/ip_conntrack_helper_pptp.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_irc.c5
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netbios_ns.c12
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c154
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_icmp.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_sctp.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_proto_tcp.c6
-rw-r--r--net/ipv4/netfilter/ip_conntrack_sip.c16
-rw-r--r--net/ipv4/netfilter/ip_conntrack_tftp.c8
-rw-r--r--net/ipv4/netfilter/ip_nat_core.c14
-rw-r--r--net/ipv4/netfilter/ip_nat_ftp.c10
-rw-r--r--net/ipv4/netfilter/ip_nat_helper.c39
-rw-r--r--net/ipv4/netfilter/ip_nat_helper_h323.c16
-rw-r--r--net/ipv4/netfilter/ip_nat_helper_pptp.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_proto_icmp.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_proto_tcp.c10
-rw-r--r--net/ipv4/netfilter/ip_nat_proto_udp.c10
-rw-r--r--net/ipv4/netfilter/ip_nat_rule.c6
-rw-r--r--net/ipv4/netfilter/ip_nat_sip.c8
-rw-r--r--net/ipv4/netfilter/ip_nat_snmp_basic.c2
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c5
-rw-r--r--net/ipv4/netfilter/ip_tables.c3
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c14
-rw-r--r--net/ipv4/netfilter/ipt_ECN.c12
-rw-r--r--net/ipv4/netfilter/ipt_MASQUERADE.c2
-rw-r--r--net/ipv4/netfilter/ipt_NETMAP.c2
-rw-r--r--net/ipv4/netfilter/ipt_REDIRECT.c2
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c101
-rw-r--r--net/ipv4/netfilter/ipt_SAME.c3
-rw-r--r--net/ipv4/netfilter/ipt_TCPMSS.c17
-rw-r--r--net/ipv4/netfilter/ipt_TOS.c4
-rw-r--r--net/ipv4/netfilter/ipt_TTL.c4
-rw-r--r--net/ipv4/netfilter/ipt_addrtype.c2
-rw-r--r--net/ipv4/netfilter/ipt_hashlimit.c16
-rw-r--r--net/ipv4/netfilter/ipt_recent.c15
-rw-r--r--net/ipv4/netfilter/iptable_mangle.c5
-rw-r--r--net/ipv4/raw.c4
-rw-r--r--net/ipv4/route.c111
-rw-r--r--net/ipv4/tcp_input.c32
-rw-r--r--net/ipv4/tcp_ipv4.c28
-rw-r--r--net/ipv4/tcp_lp.c4
-rw-r--r--net/ipv4/tcp_output.c63
-rw-r--r--net/ipv4/tcp_probe.c6
-rw-r--r--net/ipv4/udp.c34
-rw-r--r--net/ipv4/xfrm4_input.c4
-rw-r--r--net/ipv4/xfrm4_mode_beet.c139
-rw-r--r--net/ipv4/xfrm4_policy.c8
-rw-r--r--net/ipv4/xfrm4_state.c4
-rw-r--r--net/ipv6/Kconfig39
-rw-r--r--net/ipv6/Makefile4
-rw-r--r--net/ipv6/addrconf.c22
-rw-r--r--net/ipv6/af_inet6.c4
-rw-r--r--net/ipv6/fib6_rules.c12
-rw-r--r--net/ipv6/inet6_hashtables.c8
-rw-r--r--net/ipv6/ipcomp6.c9
-rw-r--r--net/ipv6/ipv6_sockglue.c3
-rw-r--r--net/ipv6/mip6.c1
-rw-r--r--net/ipv6/ndisc.c2
-rw-r--r--net/ipv6/route.c66
-rw-r--r--net/ipv6/sit.c4
-rw-r--r--net/ipv6/tcp_ipv6.c15
-rw-r--r--net/ipv6/udp.c64
-rw-r--r--net/ipv6/xfrm6_input.c4
-rw-r--r--net/ipv6/xfrm6_mode_beet.c107
-rw-r--r--net/ipv6/xfrm6_policy.c14
-rw-r--r--net/ipv6/xfrm6_state.c4
-rw-r--r--net/ipv6/xfrm6_tunnel.c2
-rw-r--r--net/irda/af_irda.c12
-rw-r--r--net/irda/ircomm/ircomm_lmp.c4
-rw-r--r--net/irda/ircomm/ircomm_tty.c2
-rw-r--r--net/irda/iriap.c9
-rw-r--r--net/irda/iriap_event.c2
-rw-r--r--net/irda/irias_object.c2
-rw-r--r--net/irda/irlan/irlan_common.c46
-rw-r--r--net/irda/irlan/irlan_provider.c12
-rw-r--r--net/irda/irlap_frame.c59
-rw-r--r--net/irda/irlmp.c2
-rw-r--r--net/irda/irttp.c14
-rw-r--r--net/key/af_key.c13
-rw-r--r--net/netfilter/Kconfig6
-rw-r--r--net/netfilter/nf_conntrack_netlink.c72
-rw-r--r--net/netfilter/xt_NFQUEUE.c2
-rw-r--r--net/netfilter/xt_connmark.c2
-rw-r--r--net/netlabel/netlabel_cipso_v4.c59
-rw-r--r--net/netlabel/netlabel_domainhash.c56
-rw-r--r--net/netlabel/netlabel_domainhash.h8
-rw-r--r--net/netlabel/netlabel_kapi.c2
-rw-r--r--net/netlabel/netlabel_mgmt.c25
-rw-r--r--net/netlabel/netlabel_unlabeled.c48
-rw-r--r--net/netlabel/netlabel_user.c41
-rw-r--r--net/netlabel/netlabel_user.h18
-rw-r--r--net/rxrpc/transport.c3
-rw-r--r--net/sched/cls_api.c4
-rw-r--r--net/sched/cls_basic.c2
-rw-r--r--net/sched/estimator.c196
-rw-r--r--net/sched/sch_api.c16
-rw-r--r--net/sched/sch_generic.c66
-rw-r--r--net/sched/sch_htb.c5
-rw-r--r--net/sctp/input.c8
-rw-r--r--net/sctp/ipv6.c10
-rw-r--r--net/sctp/output.c10
-rw-r--r--net/sctp/outqueue.c3
-rw-r--r--net/sctp/proc.c2
-rw-r--r--net/sctp/sm_make_chunk.c10
-rw-r--r--net/sctp/socket.c28
-rw-r--r--net/sctp/ulpevent.c25
-rw-r--r--net/sctp/ulpqueue.c2
-rw-r--r--net/socket.c87
-rw-r--r--net/sunrpc/auth.c12
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c35
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c4
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c148
-rw-r--r--net/sunrpc/auth_null.c8
-rw-r--r--net/sunrpc/auth_unix.c10
-rw-r--r--net/sunrpc/clnt.c27
-rw-r--r--net/sunrpc/pmap_clnt.c20
-rw-r--r--net/sunrpc/rpc_pipe.c10
-rw-r--r--net/sunrpc/sched.c8
-rw-r--r--net/sunrpc/sunrpc_syms.c2
-rw-r--r--net/sunrpc/svc.c604
-rw-r--r--net/sunrpc/svcauth.c4
-rw-r--r--net/sunrpc/svcauth_unix.c90
-rw-r--r--net/sunrpc/svcsock.c468
-rw-r--r--net/sunrpc/xdr.c54
-rw-r--r--net/sunrpc/xprt.c4
-rw-r--r--net/sunrpc/xprtsock.c5
-rw-r--r--net/tipc/bearer.c8
-rw-r--r--net/tipc/config.c5
-rw-r--r--net/tipc/core.c4
-rw-r--r--net/tipc/core.h30
-rw-r--r--net/tipc/dbg.c136
-rw-r--r--net/tipc/dbg.h15
-rw-r--r--net/tipc/discover.c39
-rw-r--r--net/tipc/link.c13
-rw-r--r--net/tipc/name_distr.c2
-rw-r--r--net/tipc/node.c2
-rw-r--r--net/tipc/port.c7
-rw-r--r--net/tipc/socket.c19
-rw-r--r--net/tipc/subscr.c99
-rw-r--r--net/xfrm/xfrm_hash.h11
-rw-r--r--net/xfrm/xfrm_input.c8
-rw-r--r--net/xfrm/xfrm_policy.c108
-rw-r--r--net/xfrm/xfrm_state.c70
-rw-r--r--net/xfrm/xfrm_user.c10
-rw-r--r--scripts/.gitignore1
-rw-r--r--scripts/Makefile2
-rw-r--r--scripts/Makefile.headersinst4
-rw-r--r--scripts/Makefile.modpost13
-rw-r--r--scripts/basic/docproc.c1
-rw-r--r--scripts/kconfig/Makefile31
-rw-r--r--scripts/kconfig/confdata.c2
-rw-r--r--scripts/kconfig/lxdialog/Makefile21
-rw-r--r--scripts/kconfig/lxdialog/checklist.c183
-rw-r--r--scripts/kconfig/lxdialog/colors.h154
-rw-r--r--scripts/kconfig/lxdialog/dialog.h145
-rw-r--r--scripts/kconfig/lxdialog/inputbox.c48
-rw-r--r--scripts/kconfig/lxdialog/lxdialog.c204
-rw-r--r--scripts/kconfig/lxdialog/menubox.c166
-rw-r--r--scripts/kconfig/lxdialog/msgbox.c71
-rw-r--r--scripts/kconfig/lxdialog/textbox.c416
-rw-r--r--scripts/kconfig/lxdialog/util.c502
-rw-r--r--scripts/kconfig/lxdialog/yesno.c26
-rw-r--r--scripts/kconfig/mconf.c511
-rwxr-xr-xscripts/kernel-doc19
-rw-r--r--scripts/mod/file2alias.c12
-rw-r--r--security/Kconfig12
-rw-r--r--security/Makefile1
-rw-r--r--security/commoncap.c2
-rw-r--r--security/dummy.c3
-rw-r--r--security/inode.c13
-rw-r--r--security/seclvl.c671
-rw-r--r--security/selinux/Kconfig4
-rw-r--r--security/selinux/hooks.c39
-rw-r--r--security/selinux/include/xfrm.h3
-rw-r--r--security/selinux/selinuxfs.c5
-rw-r--r--security/selinux/ss/ebitmap.c8
-rw-r--r--security/selinux/ss/mls.c17
-rw-r--r--security/selinux/ss/policydb.c2
-rw-r--r--security/selinux/ss/services.c82
-rw-r--r--security/selinux/xfrm.c53
-rw-r--r--sound/Makefile3
-rw-r--r--sound/aoa/core/snd-aoa-gpio-feature.c4
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-core.c5
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus-pcm.c4
-rw-r--r--sound/aoa/soundbus/i2sbus/i2sbus.h4
-rw-r--r--sound/aoa/soundbus/sysfs.c1
-rw-r--r--sound/arm/aaci.c2
-rw-r--r--sound/arm/pxa2xx-ac97.c2
-rw-r--r--sound/arm/pxa2xx-pcm.c2
-rw-r--r--sound/core/hwdep.c3
-rw-r--r--sound/core/hwdep_compat.c2
-rw-r--r--sound/core/info_oss.c10
-rw-r--r--sound/core/init.c92
-rw-r--r--sound/core/memory.c1
-rw-r--r--sound/core/pcm.c3
-rw-r--r--sound/core/pcm_native.c63
-rw-r--r--sound/drivers/mpu401/mpu401_uart.c8
-rw-r--r--sound/drivers/mtpav.c2
-rw-r--r--sound/drivers/mts64.c2
-rw-r--r--sound/drivers/serial-u16550.c2
-rw-r--r--sound/drivers/vx/vx_core.c2
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c2
-rw-r--r--sound/isa/ad1848/ad1848_lib.c2
-rw-r--r--sound/isa/cs423x/cs4231_lib.c2
-rw-r--r--sound/isa/es1688/es1688_lib.c2
-rw-r--r--sound/isa/es18xx.c5
-rw-r--r--sound/isa/gus/gus_irq.c2
-rw-r--r--sound/isa/gus/gusmax.c8
-rw-r--r--sound/isa/gus/interwave.c8
-rw-r--r--sound/isa/opl3sa2.c6
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c2
-rw-r--r--sound/isa/sb/es968.c3
-rw-r--r--sound/isa/sb/sb16_main.c4
-rw-r--r--sound/isa/sb/sb8.c2
-rw-r--r--sound/isa/sb/sb_common.c2
-rw-r--r--sound/isa/sgalaxy.c2
-rw-r--r--sound/isa/wavefront/wavefront.c4
-rw-r--r--sound/mips/au1x00.c4
-rw-r--r--sound/oss/COPYING339
-rw-r--r--sound/oss/Kconfig6
-rw-r--r--sound/oss/Makefile58
-rw-r--r--sound/oss/ac97.c20
-rw-r--r--sound/oss/ac97.h3
-rw-r--r--sound/oss/ac97_codec.c89
-rw-r--r--sound/oss/ac97_plugin_ad1980.c126
-rw-r--r--sound/oss/ad1816.c2
-rw-r--r--sound/oss/ad1848.c6
-rw-r--r--sound/oss/ad1848.h1
-rw-r--r--sound/oss/ad1848_mixer.h2
-rw-r--r--sound/oss/ad1889.c2
-rw-r--r--sound/oss/adlib_card.c2
-rw-r--r--sound/oss/ali5455.c3735
-rw-r--r--sound/oss/au1000.c2216
-rw-r--r--sound/oss/audio.c2
-rw-r--r--sound/oss/audio_syms.c16
-rw-r--r--sound/oss/awe_hw.h99
-rw-r--r--sound/oss/awe_wave.c6149
-rw-r--r--sound/oss/awe_wave.h77
-rw-r--r--sound/oss/btaudio.c2
-rw-r--r--sound/oss/cmpci.c3381
-rw-r--r--sound/oss/cs4281/Makefile6
-rw-r--r--sound/oss/cs4281/cs4281_hwdefs.h1234
-rw-r--r--sound/oss/cs4281/cs4281_wrapper-24.c41
-rw-r--r--sound/oss/cs4281/cs4281m.c4487
-rw-r--r--sound/oss/cs4281/cs4281pm-24.c45
-rw-r--r--sound/oss/cs4281/cs4281pm.h74
-rw-r--r--sound/oss/cs46xx.c17
-rw-r--r--sound/oss/cs46xxpm-24.h48
-rw-r--r--sound/oss/dev_table.c46
-rw-r--r--sound/oss/dev_table.h17
-rw-r--r--sound/oss/dm.h79
-rw-r--r--sound/oss/dmabuf.c42
-rw-r--r--sound/oss/dmasound/dmasound_atari.c4
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c18
-rw-r--r--sound/oss/dmasound/dmasound_paula.c4
-rw-r--r--sound/oss/dmasound/dmasound_q40.c8
-rw-r--r--sound/oss/emu10k1/irqmgr.c2
-rw-r--r--sound/oss/emu10k1/main.c2
-rw-r--r--sound/oss/es1370.c2819
-rw-r--r--sound/oss/es1371.c4
-rw-r--r--sound/oss/esssolo1.c2516
-rw-r--r--sound/oss/forte.c2139
-rw-r--r--sound/oss/gus.h24
-rw-r--r--sound/oss/gus_card.c293
-rw-r--r--sound/oss/gus_hw.h50
-rw-r--r--sound/oss/gus_linearvol.h18
-rw-r--r--sound/oss/gus_midi.c256
-rw-r--r--sound/oss/gus_vol.c153
-rw-r--r--sound/oss/gus_wave.c3464
-rw-r--r--sound/oss/hal2.c4
-rw-r--r--sound/oss/harmony.c1330
-rw-r--r--sound/oss/i810_audio.c4
-rw-r--r--sound/oss/ics2101.c247
-rw-r--r--sound/oss/ite8172.c2261
-rw-r--r--sound/oss/iwmem.h36
-rw-r--r--sound/oss/mad16.c1113
-rw-r--r--sound/oss/maestro.c3686
-rw-r--r--sound/oss/maestro.h60
-rw-r--r--sound/oss/maestro3.c2969
-rw-r--r--sound/oss/maestro3.h821
-rw-r--r--sound/oss/maui.c478
-rw-r--r--sound/oss/midi_syms.c29
-rw-r--r--sound/oss/midi_synth.c23
-rw-r--r--sound/oss/midibuf.c13
-rw-r--r--sound/oss/mpu401.c17
-rw-r--r--sound/oss/mpu401.h5
-rw-r--r--sound/oss/msnd_pinnacle.c2
-rw-r--r--sound/oss/nec_vrc5477.c2
-rw-r--r--sound/oss/nm256.h2
-rw-r--r--sound/oss/nm256_audio.c8
-rw-r--r--sound/oss/opl3.c2
-rw-r--r--sound/oss/opl3sa.c329
-rw-r--r--sound/oss/opl3sa2.c2
-rw-r--r--sound/oss/pas2_card.c4
-rw-r--r--sound/oss/pas2_midi.c2
-rw-r--r--sound/oss/pas2_mixer.c2
-rw-r--r--sound/oss/pss.c2
-rw-r--r--sound/oss/rme96xx.c1857
-rw-r--r--sound/oss/rme96xx.h78
-rw-r--r--sound/oss/sb_audio.c2
-rw-r--r--sound/oss/sb_common.c6
-rw-r--r--sound/oss/sb_midi.c2
-rw-r--r--sound/oss/sb_mixer.c2
-rw-r--r--sound/oss/sb_mixer.h2
-rw-r--r--sound/oss/sequencer.c17
-rw-r--r--sound/oss/sequencer_syms.c29
-rw-r--r--sound/oss/sgalaxy.c207
-rw-r--r--sound/oss/sh_dac_audio.c62
-rw-r--r--sound/oss/sonicvibes.c2792
-rw-r--r--sound/oss/sound_calls.h3
-rw-r--r--sound/oss/sound_syms.c50
-rw-r--r--sound/oss/sound_timer.c6
-rw-r--r--sound/oss/soundcard.c18
-rw-r--r--sound/oss/sscape.c2
-rw-r--r--sound/oss/swarm_cs4297a.c4
-rw-r--r--sound/oss/sys_timer.c2
-rw-r--r--sound/oss/trident.c72
-rw-r--r--sound/oss/trix.c2
-rw-r--r--sound/oss/tuning.h10
-rw-r--r--sound/oss/uart401.c4
-rw-r--r--sound/oss/uart6850.c4
-rw-r--r--sound/oss/v_midi.c2
-rw-r--r--sound/oss/via82cxxx_audio.c12
-rw-r--r--sound/oss/vidc.c2
-rw-r--r--sound/oss/vidc.h2
-rw-r--r--sound/oss/vwsnd.c6
-rw-r--r--sound/oss/waveartist.c4
-rw-r--r--sound/oss/waveartist.h2
-rw-r--r--sound/oss/wavfront.c3554
-rw-r--r--sound/oss/wf_midi.c880
-rw-r--r--sound/oss/ymfpci.c2692
-rw-r--r--sound/oss/ymfpci.h361
-rw-r--r--sound/oss/ymfpci_image.h1565
-rw-r--r--sound/oss/yss225.c319
-rw-r--r--sound/oss/yss225.h24
-rw-r--r--sound/parisc/harmony.c2
-rw-r--r--sound/pci/ac97/ac97_patch.c7
-rw-r--r--sound/pci/ad1889.c4
-rw-r--r--sound/pci/ali5451/ali5451.c4
-rw-r--r--sound/pci/als300.c6
-rw-r--r--sound/pci/als4000.c4
-rw-r--r--sound/pci/atiixp.c2
-rw-r--r--sound/pci/atiixp_modem.c2
-rw-r--r--sound/pci/au88x0/au88x0.c1
-rw-r--r--sound/pci/au88x0/au88x0.h3
-rw-r--r--sound/pci/au88x0/au88x0_core.c4
-rw-r--r--sound/pci/azt3328.c4
-rw-r--r--sound/pci/bt87x.c2
-rw-r--r--sound/pci/ca0106/ca0106_main.c3
-rw-r--r--sound/pci/cmipci.c4
-rw-r--r--sound/pci/cs4281.c4
-rw-r--r--sound/pci/cs46xx/cs46xx_lib.c2
-rw-r--r--sound/pci/cs5535audio/cs5535audio.c3
-rw-r--r--sound/pci/echoaudio/echoaudio.c3
-rw-r--r--sound/pci/echoaudio/layla24_dsp.c4
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c4
-rw-r--r--sound/pci/emu10k1/emu10k1x.c3
-rw-r--r--sound/pci/emu10k1/irq.c2
-rw-r--r--sound/pci/ens1370.c4
-rw-r--r--sound/pci/es1938.c6
-rw-r--r--sound/pci/es1968.c6
-rw-r--r--sound/pci/fm801.c4
-rw-r--r--sound/pci/hda/hda_intel.c3
-rw-r--r--sound/pci/hda/patch_realtek.c4
-rw-r--r--sound/pci/hda/patch_si3054.c5
-rw-r--r--sound/pci/ice1712/ice1712.c6
-rw-r--r--sound/pci/ice1712/ice1724.c4
-rw-r--r--sound/pci/intel8x0.c2
-rw-r--r--sound/pci/intel8x0m.c2
-rw-r--r--sound/pci/korg1212/korg1212.c6
-rw-r--r--sound/pci/maestro3.c3
-rw-r--r--sound/pci/mixart/mixart_core.c2
-rw-r--r--sound/pci/mixart/mixart_core.h2
-rw-r--r--sound/pci/nm256/nm256.c6
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c2
-rw-r--r--sound/pci/pcxhr/pcxhr_core.h2
-rw-r--r--sound/pci/riptide/riptide.c5
-rw-r--r--sound/pci/rme32.c3
-rw-r--r--sound/pci/rme96.c3
-rw-r--r--sound/pci/rme9652/hdsp.c2
-rw-r--r--sound/pci/rme9652/hdspm.c3
-rw-r--r--sound/pci/rme9652/rme9652.c2
-rw-r--r--sound/pci/sonicvibes.c4
-rw-r--r--sound/pci/trident/trident_main.c7
-rw-r--r--sound/pci/via82xx.c6
-rw-r--r--sound/pci/via82xx_modem.c2
-rw-r--r--sound/pci/ymfpci/ymfpci_main.c4
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.h2
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_irq.c5
-rw-r--r--sound/ppc/pmac.c6
-rw-r--r--sound/ppc/tumbler.c2
-rw-r--r--sound/sound_core.c38
-rw-r--r--sound/sound_firmware.c6
-rw-r--r--sound/sparc/amd7930.c2
-rw-r--r--sound/sparc/cs4231.c2
-rw-r--r--sound/sparc/dbri.c7
-rw-r--r--sound/usb/usbaudio.c15
-rw-r--r--sound/usb/usbmidi.c13
-rw-r--r--sound/usb/usbmixer.c5
-rw-r--r--sound/usb/usx2y/usbusx2y.c4
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c28
-rw-r--r--sound/usb/usx2y/usx2yhwdeppcm.c23
6239 files changed, 262491 insertions, 174231 deletions
diff --git a/CREDITS b/CREDITS
index cc3453a55fb9..5329ead9c672 100644
--- a/CREDITS
+++ b/CREDITS
@@ -34,6 +34,7 @@ E: magrawal@nortelnetworks.com
D: Basic Interphase 5575 driver with UBR and ABR support.
S: 75 Donald St, Apt 42
S: Weymouth, MA 02188
+S: USA
N: Dave Airlie
E: airlied@linux.ie
@@ -202,6 +203,7 @@ S: MS42
S: Hewlett-Packard
S: 3404 E Harmony Rd
S: Fort Collins, CO 80525
+S: USA
N: Arindam Banerji
E: axb@cse.nd.edu
@@ -444,6 +446,7 @@ E: rbradetich@uswest.net
D: Linux/PA-RISC hacker
S: 1200 Goldenrod Dr.
S: Nampa, Idaho 83686
+S: USA
N: Derrick J. Brashear
E: shadow@dementia.org
@@ -633,6 +636,7 @@ E: scole@lanl.gov
E: elenstev@mesatop.com
D: Various build fixes and kernel documentation.
S: Los Alamos, New Mexico
+S: USA
N: Hamish Coleman
E: hamish@zot.apana.org.au
@@ -951,6 +955,12 @@ S: Brevia 1043
S: S-114 79 Stockholm
S: Sweden
+N: Pekka Enberg
+E: penberg@cs.helsinki.fi
+W: http://www.cs.helsinki.fi/u/penberg/
+D: Various kernel hacks, fixes, and cleanups.
+S: Finland
+
N: David Engebretsen
E: engebret@us.ibm.com
D: Linux port to 64-bit PowerPC architecture
@@ -1620,7 +1630,8 @@ D: fbdev hacking
N: Jesper Juhl
E: jesper.juhl@gmail.com
-D: Various fixes, cleanups and minor features.
+D: Various fixes, cleanups and minor features all over the tree.
+D: Wrote initial version of the hdaps driver (since passed on to others).
S: Lemnosvej 1, 3.tv
S: 2300 Copenhagen S.
S: Denmark
@@ -2002,6 +2013,7 @@ W: http://www.mathematik.uni-stuttgart.de/~floeff
D: Busmaster driver for HP 10/100 Mbit Network Adapters
S: University of Stuttgart, Germany and
S: Ecole Nationale Superieure des Telecommunications, Paris
+S: France
N: Jamie Lokier
E: jamie@shareable.org
@@ -2171,6 +2183,7 @@ S: Hewlett Packard
S: MS 42
S: 3404 E. Harmony Road
S: Fort Collins, CO 80528
+S: USA
N: Torben Mathiasen
E: torben.mathiasen@compaq.com
@@ -2227,6 +2240,12 @@ D: tc: HFSC scheduler
S: Freiburg
S: Germany
+N: Paul E. McKenney
+E: paulmck@us.ibm.com
+W: http://www.rdrop.com/users/paulmck/
+D: RCU and variants
+D: rcutorture module
+
N: Mike McLagan
E: mike.mclagan@linux.org
W: http://www.invlogic.com/~mmclagan
@@ -2477,7 +2496,8 @@ S: Derbyshire DE4 3RL
S: United Kingdom
N: Ian S. Nelson
-E: ian.nelson@echostar.com
+E: nelsonis@earthlink.net
+P: 1024D/00D3D983 3EFD 7B86 B888 D7E2 29B6 9E97 576F 1B97 00D3 D983
D: Minor mmap and ide hacks
S: 1370 Atlantis Ave.
S: Lafayette CO, 80026
@@ -2967,6 +2987,10 @@ S: 69 rue Dunois
S: 75013 Paris
S: France
+N: Dipankar Sarma
+E: dipankar@in.ibm.com
+D: RCU
+
N: Hannu Savolainen
E: hannu@opensound.com
D: Maintainer of the sound drivers until 2.1.x days.
@@ -3279,6 +3303,12 @@ S: 3 Ballow Crescent
S: MacGregor A.C.T 2615
S: Australia
+N: Josh Triplett
+E: josh@freedesktop.org
+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
E: winni@xpilot.org
W: http://www.shop.de/~winni/
@@ -3548,11 +3578,11 @@ S: Fargo, North Dakota 58122
S: USA
N: Steven Whitehouse
-E: SteveW@ACM.org
+E: steve@chygwyn.com
W: http://www.chygwyn.com/~steve
-D: Linux DECnet project: http://www.sucs.swan.ac.uk/~rohan/DECnet/index.html
+D: Linux DECnet project
D: Minor debugging of other networking protocols.
-D: Misc bug fixes and filesystem development
+D: Misc bug fixes and GFS2 filesystem development
N: Hans-Joachim Widmaier
E: hjw@zvw.de
@@ -3650,7 +3680,7 @@ S: Portland, OR
S: USA
N: Michal Wronski
-E: Michal.Wronski@motorola.com
+E: michal.wronski@gmail.com
D: POSIX message queues fs (with K. Benedyczak)
S: Krakow
S: Poland
diff --git a/Documentation/CodingStyle b/Documentation/CodingStyle
index 6d2412ec91ed..29c18966b050 100644
--- a/Documentation/CodingStyle
+++ b/Documentation/CodingStyle
@@ -532,6 +532,40 @@ appears outweighs the potential value of the hint that tells gcc to do
something it would have done anyway.
+ Chapter 16: Function return values and names
+
+Functions can return values of many different kinds, and one of the
+most common is a value indicating whether the function succeeded or
+failed. Such a value can be represented as an error-code integer
+(-Exxx = failure, 0 = success) or a "succeeded" boolean (0 = failure,
+non-zero = success).
+
+Mixing up these two sorts of representations is a fertile source of
+difficult-to-find bugs. If the C language included a strong distinction
+between integers and booleans then the compiler would find these mistakes
+for us... but it doesn't. To help prevent such bugs, always follow this
+convention:
+
+ If the name of a function is an action or an imperative command,
+ the function should return an error-code integer. If the name
+ is a predicate, the function should return a "succeeded" boolean.
+
+For example, "add work" is a command, and the add_work() function returns 0
+for success or -EBUSY for failure. In the same way, "PCI device present" is
+a predicate, and the pci_dev_present() function returns 1 if it succeeds in
+finding a matching device or 0 if it doesn't.
+
+All EXPORTed functions must respect this convention, and so should all
+public functions. Private (static) functions need not, but it is
+recommended that they do.
+
+Functions whose return value is the actual result of a computation, rather
+than an indication of whether the computation succeeded, are not subject to
+this rule. Generally they indicate failure by returning some out-of-range
+result. Typical examples would be functions that return pointers; they use
+NULL or the ERR_PTR mechanism to report failure.
+
+
Appendix I: References
diff --git a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt
index 63392c9132b4..028614cdd062 100644
--- a/Documentation/DMA-mapping.txt
+++ b/Documentation/DMA-mapping.txt
@@ -107,7 +107,7 @@ The query is performed via a call to pci_set_dma_mask():
int pci_set_dma_mask(struct pci_dev *pdev, u64 device_mask);
-The query for consistent allocations is performed via a a call to
+The query for consistent allocations is performed via a call to
pci_set_consistent_dma_mask():
int pci_set_consistent_dma_mask(struct pci_dev *pdev, u64 device_mask);
@@ -117,7 +117,7 @@ device_mask is a bit mask describing which bits of a PCI address your
device supports. It returns zero if your card can perform DMA
properly on the machine given the address mask you provided.
-If it returns non-zero, your device can not perform DMA properly on
+If it returns non-zero, your device cannot perform DMA properly on
this platform, and attempting to do so will result in undefined
behavior. You must either use a different mask, or not use DMA.
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index f8fe882e33dc..2b5ac604948c 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -158,6 +158,7 @@ X!Ilib/string.c
!Emm/filemap.c
!Emm/memory.c
!Emm/vmalloc.c
+!Imm/page_alloc.c
!Emm/mempool.c
!Emm/page-writeback.c
!Emm/truncate.c
@@ -181,27 +182,6 @@ X!Ilib/string.c
</sect1>
</chapter>
- <chapter id="proc">
- <title>The proc filesystem</title>
-
- <sect1><title>sysctl interface</title>
-!Ekernel/sysctl.c
- </sect1>
-
- <sect1><title>proc filesystem interface</title>
-!Ifs/proc/base.c
- </sect1>
- </chapter>
-
- <chapter id="debugfs">
- <title>The debugfs filesystem</title>
-
- <sect1><title>debugfs interface</title>
-!Efs/debugfs/inode.c
-!Efs/debugfs/file.c
- </sect1>
- </chapter>
-
<chapter id="vfs">
<title>The Linux VFS</title>
<sect1><title>The Filesystem types</title>
@@ -234,6 +214,50 @@ X!Ilib/string.c
</sect1>
</chapter>
+ <chapter id="proc">
+ <title>The proc filesystem</title>
+
+ <sect1><title>sysctl interface</title>
+!Ekernel/sysctl.c
+ </sect1>
+
+ <sect1><title>proc filesystem interface</title>
+!Ifs/proc/base.c
+ </sect1>
+ </chapter>
+
+ <chapter id="sysfs">
+ <title>The Filesystem for Exporting Kernel Objects</title>
+!Efs/sysfs/file.c
+!Efs/sysfs/symlink.c
+!Efs/sysfs/bin.c
+ </chapter>
+
+ <chapter id="debugfs">
+ <title>The debugfs filesystem</title>
+
+ <sect1><title>debugfs interface</title>
+!Efs/debugfs/inode.c
+!Efs/debugfs/file.c
+ </sect1>
+ </chapter>
+
+ <chapter id="relayfs">
+ <title>relay interface support</title>
+
+ <para>
+ Relay interface support
+ is designed to provide an efficient mechanism for tools and
+ facilities to relay large amounts of data from kernel space to
+ user space.
+ </para>
+
+ <sect1><title>relay interface</title>
+!Ekernel/relay.c
+!Ikernel/relay.c
+ </sect1>
+ </chapter>
+
<chapter id="netcore">
<title>Linux Networking</title>
<sect1><title>Networking Base Types</title>
@@ -302,8 +326,13 @@ X!Ekernel/module.c
!Ekernel/irq/manage.c
</sect1>
+ <sect1><title>DMA Channels</title>
+!Ekernel/dma.c
+ </sect1>
+
<sect1><title>Resources Management</title>
!Ikernel/resource.c
+!Ekernel/resource.c
</sect1>
<sect1><title>MTRR Handling</title>
@@ -349,13 +378,6 @@ X!Earch/i386/kernel/mca.c
</sect1>
</chapter>
- <chapter id="sysfs">
- <title>The Filesystem for Exporting Kernel Objects</title>
-!Efs/sysfs/file.c
-!Efs/sysfs/symlink.c
-!Efs/sysfs/bin.c
- </chapter>
-
<chapter id="security">
<title>Security Framework</title>
!Esecurity/security.c
@@ -386,6 +408,7 @@ X!Iinclude/linux/device.h
-->
!Edrivers/base/driver.c
!Edrivers/base/core.c
+!Edrivers/base/class.c
!Edrivers/base/firmware_class.c
!Edrivers/base/transport_class.c
!Edrivers/base/dmapool.c
@@ -437,6 +460,11 @@ X!Edrivers/pnp/system.c
!Eblock/ll_rw_blk.c
</chapter>
+ <chapter id="chrdev">
+ <title>Char devices</title>
+!Efs/char_dev.c
+ </chapter>
+
<chapter id="miscdev">
<title>Miscellaneous Devices</title>
!Edrivers/char/misc.c
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index 065e8dc23e3a..07a635590b36 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -14,7 +14,7 @@
</authorgroup>
<copyright>
- <year>2003-2005</year>
+ <year>2003-2006</year>
<holder>Jeff Garzik</holder>
</copyright>
@@ -1400,7 +1400,7 @@ and other resources, etc.
<listitem>
<para>
When it's known that HBA is in ready state but ATA/ATAPI
- device in in unknown state, reset only device.
+ device is in unknown state, reset only device.
</para>
</listitem>
diff --git a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl
index 320af25de3a2..143e5ff7deb8 100644
--- a/Documentation/DocBook/usb.tmpl
+++ b/Documentation/DocBook/usb.tmpl
@@ -43,59 +43,52 @@
<para>A Universal Serial Bus (USB) is used to connect a host,
such as a PC or workstation, to a number of peripheral
- devices. USB uses a tree structure, with the host at the
+ devices. USB uses a tree structure, with the host as the
root (the system's master), hubs as interior nodes, and
- peripheral devices as leaves (and slaves).
+ peripherals as leaves (and slaves).
Modern PCs support several such trees of USB devices, usually
one USB 2.0 tree (480 Mbit/sec each) with
a few USB 1.1 trees (12 Mbit/sec each) that are used when you
connect a USB 1.1 device directly to the machine's "root hub".
</para>
- <para>That master/slave asymmetry was designed in part for
- ease of use. It is not physically possible to assemble
- (legal) USB cables incorrectly: all upstream "to-the-host"
- connectors are the rectangular type, matching the sockets on
- root hubs, and the downstream type are the squarish type
- (or they are built in to the peripheral).
- Software doesn't need to deal with distributed autoconfiguration
- since the pre-designated master node manages all that.
- At the electrical level, bus protocol overhead is reduced by
- eliminating arbitration and moving scheduling into host software.
+ <para>That master/slave asymmetry was designed-in for a number of
+ reasons, one being ease of use. It is not physically possible to
+ assemble (legal) USB cables incorrectly: all upstream "to the host"
+ connectors are the rectangular type (matching the sockets on
+ root hubs), and all downstream connectors are the squarish type
+ (or they are built into the peripheral).
+ Also, the host software doesn't need to deal with distributed
+ auto-configuration since the pre-designated master node manages all that.
+ And finally, at the electrical level, bus protocol overhead is reduced by
+ eliminating arbitration and moving scheduling into the host software.
</para>
- <para>USB 1.0 was announced in January 1996, and was revised
+ <para>USB 1.0 was announced in January 1996 and was revised
as USB 1.1 (with improvements in hub specification and
support for interrupt-out transfers) in September 1998.
- USB 2.0 was released in April 2000, including high speed
- transfers and transaction translating hubs (used for USB 1.1
+ USB 2.0 was released in April 2000, adding high-speed
+ transfers and transaction-translating hubs (used for USB 1.1
and 1.0 backward compatibility).
</para>
- <para>USB support was added to Linux early in the 2.2 kernel series
- shortly before the 2.3 development forked off. Updates
- from 2.3 were regularly folded back into 2.2 releases, bringing
- new features such as <filename>/sbin/hotplug</filename> support,
- more drivers, and more robustness.
- The 2.5 kernel series continued such improvements, and also
- worked on USB 2.0 support,
- higher performance,
- better consistency between host controller drivers,
- API simplification (to make bugs less likely),
- and providing internal "kerneldoc" documentation.
+ <para>Kernel developers added USB support to Linux early in the 2.2 kernel
+ series, shortly before 2.3 development forked. Updates from 2.3 were
+ regularly folded back into 2.2 releases, which improved reliability and
+ brought <filename>/sbin/hotplug</filename> support as well more drivers.
+ Such improvements were continued in the 2.5 kernel series, where they added
+ USB 2.0 support, improved performance, and made the host controller drivers
+ (HCDs) more consistent. They also simplified the API (to make bugs less
+ likely) and added internal "kerneldoc" documentation.
</para>
<para>Linux can run inside USB devices as well as on
the hosts that control the devices.
- Because the Linux 2.x USB support evolved to support mass market
- platforms such as Apple Macintosh or PC-compatible systems,
- it didn't address design concerns for those types of USB systems.
- So it can't be used inside mass-market PDAs, or other peripherals.
- USB device drivers running inside those Linux peripherals
+ But USB device drivers running inside those peripherals
don't do the same things as the ones running inside hosts,
- and so they've been given a different name:
- they're called <emphasis>gadget drivers</emphasis>.
- This document does not present gadget drivers.
+ so they've been given a different name:
+ <emphasis>gadget drivers</emphasis>.
+ This document does not cover gadget drivers.
</para>
</chapter>
@@ -103,17 +96,14 @@
<chapter id="host">
<title>USB Host-Side API Model</title>
- <para>Within the kernel,
- host-side drivers for USB devices talk to the "usbcore" APIs.
- There are two types of public "usbcore" APIs, targetted at two different
- layers of USB driver. Those are
- <emphasis>general purpose</emphasis> drivers, exposed through
- driver frameworks such as block, character, or network devices;
- and drivers that are <emphasis>part of the core</emphasis>,
- which are involved in managing a USB bus.
- Such core drivers include the <emphasis>hub</emphasis> driver,
- which manages trees of USB devices, and several different kinds
- of <emphasis>host controller driver (HCD)</emphasis>,
+ <para>Host-side drivers for USB devices talk to the "usbcore" APIs.
+ There are two. One is intended for
+ <emphasis>general-purpose</emphasis> drivers (exposed through
+ driver frameworks), and the other is for drivers that are
+ <emphasis>part of the core</emphasis>.
+ Such core drivers include the <emphasis>hub</emphasis> driver
+ (which manages trees of USB devices) and several different kinds
+ of <emphasis>host controller drivers</emphasis>,
which control individual busses.
</para>
@@ -122,21 +112,21 @@
<itemizedlist>
- <listitem><para>USB supports four kinds of data transfer
- (control, bulk, interrupt, and isochronous). Two transfer
- types use bandwidth as it's available (control and bulk),
- while the other two types of transfer (interrupt and isochronous)
+ <listitem><para>USB supports four kinds of data transfers
+ (control, bulk, interrupt, and isochronous). Two of them (control
+ and bulk) use bandwidth as it's available,
+ while the other two (interrupt and isochronous)
are scheduled to provide guaranteed bandwidth.
</para></listitem>
<listitem><para>The device description model includes one or more
"configurations" per device, only one of which is active at a time.
- Devices that are capable of high speed operation must also support
- full speed configurations, along with a way to ask about the
- "other speed" configurations that might be used.
+ Devices that are capable of high-speed operation must also support
+ full-speed configurations, along with a way to ask about the
+ "other speed" configurations which might be used.
</para></listitem>
- <listitem><para>Configurations have one or more "interface", each
+ <listitem><para>Configurations have one or more "interfaces", each
of which may have "alternate settings". Interfaces may be
standardized by USB "Class" specifications, or may be specific to
a vendor or device.</para>
@@ -162,7 +152,7 @@
</para></listitem>
<listitem><para>The Linux USB API supports synchronous calls for
- control and bulk messaging.
+ control and bulk messages.
It also supports asynchnous calls for all kinds of data transfer,
using request structures called "URBs" (USB Request Blocks).
</para></listitem>
@@ -324,8 +314,7 @@
<emphasis>usbdevfs</emphasis> although it wasn't solving what
<emphasis>devfs</emphasis> was.
Every USB device will appear in usbfs, regardless of whether or
- not it has a kernel driver; but only devices with kernel drivers
- show up in devfs.
+ not it has a kernel driver.
</para>
<sect1>
@@ -463,14 +452,25 @@
file in your Linux kernel sources.
</para>
- <para>Otherwise the main use for this file from programs
- is to poll() it to get notifications of usb devices
- as they're plugged or unplugged.
- To see what changed, you'd need to read the file and
- compare "before" and "after" contents, scan the filesystem,
- or see its hotplug event.
+ <para>This file, in combination with the poll() system call, can
+ also be used to detect when devices are added or removed:
+<programlisting>int fd;
+struct pollfd pfd;
+
+fd = open("/proc/bus/usb/devices", O_RDONLY);
+pfd = { fd, POLLIN, 0 };
+for (;;) {
+ /* The first time through, this call will return immediately. */
+ poll(&amp;pfd, 1, -1);
+
+ /* To see what's changed, compare the file's previous and current
+ contents or scan the filesystem. (Scanning is more precise.) */
+}</programlisting>
+ Note that this behavior is intended to be used for informational
+ and debug purposes. It would be more appropriate to use programs
+ such as udev or HAL to initialize a device or start a user-mode
+ helper program, for instance.
</para>
-
</sect1>
<sect1>
@@ -740,7 +740,7 @@ usbdev_ioctl (int fd, int ifno, unsigned request, void *param)
<title>Synchronous I/O Support</title>
<para>Synchronous requests involve the kernel blocking
- until until the user mode request completes, either by
+ until the user mode request completes, either by
finishing successfully or by reporting an error.
In most cases this is the simplest way to use usbfs,
although as noted above it does prevent performing I/O
diff --git a/Documentation/DocBook/writing_usb_driver.tmpl b/Documentation/DocBook/writing_usb_driver.tmpl
index 008a341234d0..07cd34c1940b 100644
--- a/Documentation/DocBook/writing_usb_driver.tmpl
+++ b/Documentation/DocBook/writing_usb_driver.tmpl
@@ -224,13 +224,8 @@ static int skel_probe(struct usb_interface *interface,
Conversely, when the device is removed from the USB bus, the disconnect
function is called with the device pointer. The driver needs to clean any
private data that has been allocated at this time and to shut down any
- pending urbs that are in the USB system. The driver also unregisters
- itself from the devfs subsystem with the call:
+ pending urbs that are in the USB system.
</para>
- <programlisting>
-/* remove our devfs node */
-devfs_unregister(skel->devfs);
- </programlisting>
<para>
Now that the device is plugged into the system and the driver is bound to
the device, any of the functions in the file_operations structure that
diff --git a/Documentation/HOWTO b/Documentation/HOWTO
index 1d6560413cc5..8d51c148f721 100644
--- a/Documentation/HOWTO
+++ b/Documentation/HOWTO
@@ -375,6 +375,46 @@ of information is needed by the kernel developers to help track down the
problem.
+Managing bug reports
+--------------------
+
+One of the best ways to put into practice your hacking skills is by fixing
+bugs reported by other people. Not only you will help to make the kernel
+more stable, you'll learn to fix real world problems and you will improve
+your skills, and other developers will be aware of your presence. Fixing
+bugs is one of the best ways to earn merit amongst the developers, because
+not many people like wasting time fixing other people's bugs.
+
+To work in the already reported bug reports, go to http://bugzilla.kernel.org.
+If you want to be advised of the future bug reports, you can subscribe to the
+bugme-new mailing list (only new bug reports are mailed here) or to the
+bugme-janitor mailing list (every change in the bugzilla is mailed here)
+
+ http://lists.osdl.org/mailman/listinfo/bugme-new
+ http://lists.osdl.org/mailman/listinfo/bugme-janitors
+
+
+
+Managing bug reports
+--------------------
+
+One of the best ways to put into practice your hacking skills is by fixing
+bugs reported by other people. Not only you will help to make the kernel
+more stable, you'll learn to fix real world problems and you will improve
+your skills, and other developers will be aware of your presence. Fixing
+bugs is one of the best ways to get merits among other developers, because
+not many people like wasting time fixing other people's bugs.
+
+To work in the already reported bug reports, go to http://bugzilla.kernel.org.
+If you want to be advised of the future bug reports, you can subscribe to the
+bugme-new mailing list (only new bug reports are mailed here) or to the
+bugme-janitor mailing list (every change in the bugzilla is mailed here)
+
+ http://lists.osdl.org/mailman/listinfo/bugme-new
+ http://lists.osdl.org/mailman/listinfo/bugme-janitors
+
+
+
Mailing lists
-------------
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 0256805b548f..0e3924ecd76b 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -326,9 +326,12 @@ for events, they will all receive all events that come in.
For receiving commands, you have to individually register commands you
want to receive. Call ipmi_register_for_cmd() and supply the netfn
-and command name for each command you want to receive. Only one user
-may be registered for each netfn/cmd, but different users may register
-for different commands.
+and command name for each command you want to receive. You also
+specify a bitmask of the channels you want to receive the command from
+(or use IPMI_CHAN_ALL for all channels if you don't care). Only one
+user may be registered for each netfn/cmd/channel, but different users
+may register for different commands, or the same command if the
+channel bitmasks do not overlap.
From userland, equivalent IOCTLs are provided to do these functions.
@@ -361,6 +364,7 @@ You can change this at module load time (for a module) with:
regspacings=<sp1>,<sp2>,... regsizes=<size1>,<size2>,...
regshifts=<shift1>,<shift2>,...
slave_addrs=<addr1>,<addr2>,...
+ force_kipmid=<enable1>,<enable2>,...
Each of these except si_trydefaults is a list, the first item for the
first interface, second item for the second interface, etc.
@@ -406,7 +410,13 @@ The slave_addrs specifies the IPMI address of the local BMC. This is
usually 0x20 and the driver defaults to that, but in case it's not, it
can be specified when the driver starts up.
-When compiled into the kernel, the addresses can be specified on the
+The force_ipmid parameter forcefully enables (if set to 1) or disables
+(if set to 0) the kernel IPMI daemon. Normally this is auto-detected
+by the driver, but systems with broken interrupts might need an enable,
+or users that don't want the daemon (don't need the performance, don't
+want the CPU hit) can disable it.
+
+When compiled into the kernel, the parameters can be specified on the
kernel command line as:
ipmi_si.type=<type1>,<type2>...
@@ -416,6 +426,7 @@ kernel command line as:
ipmi_si.regsizes=<size1>,<size2>,...
ipmi_si.regshifts=<shift1>,<shift2>,...
ipmi_si.slave_addrs=<addr1>,<addr2>,...
+ ipmi_si.force_kipmid=<enable1>,<enable2>,...
It works the same as the module parameters of the same names.
@@ -457,12 +468,12 @@ BMCs specified on the smb_addr line will be detected.
Setting smb_dbg_probe to 1 will enable debugging of the probing and
detection process for BMCs on the SMBusses.
-Discovering the IPMI compilant BMC on the SMBus can cause devices
+Discovering the IPMI compliant BMC on the SMBus can cause devices
on the I2C bus to fail. The SMBus driver writes a "Get Device ID" IPMI
message as a block write to the I2C bus and waits for a response.
This action can be detrimental to some I2C devices. It is highly recommended
that the known I2c address be given to the SMBus driver in the smb_addr
-parameter. The default adrress range will not be used when a smb_addr
+parameter. The default address range will not be used when a smb_addr
parameter is provided.
When compiled into the kernel, the addresses can be specified on the
diff --git a/Documentation/MSI-HOWTO.txt b/Documentation/MSI-HOWTO.txt
index 3ec6c720b016..5c34910665d1 100644
--- a/Documentation/MSI-HOWTO.txt
+++ b/Documentation/MSI-HOWTO.txt
@@ -267,7 +267,7 @@ y = The number of MSI capable devices populated in the system.
vector reserved to avoid the case where some MSI-X capable
drivers may attempt to claim all available vector resources.
-z = The number of MSI-X capable devices pupulated in the system.
+z = The number of MSI-X capable devices populated in the system.
This policy ensures that maximum (x - y) is distributed
evenly among MSI-X capable devices.
@@ -470,7 +470,68 @@ LOC: 324553 325068
ERR: 0
MIS: 0
-6. FAQ
+6. MSI quirks
+
+Several PCI chipsets or devices are known to not support MSI.
+The PCI stack provides 3 possible levels of MSI disabling:
+* on a single device
+* on all devices behind a specific bridge
+* globally
+
+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()
+or all, or setting the pci_dev->no_msi flag before (most of the time
+in a quirk).
+
+6.2. Disabling MSI below a bridge
+
+The vast majority of MSI quirks are required by PCI bridges not
+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
+MSI on a device, pci_msi_supported() takes care of checking the NO_MSI
+flag in all parent busses of the device.
+
+Some bridges actually support dynamic MSI support enabling/disabling
+by changing some bits in their PCI configuration space (especially
+the Hypertransport chipsets such as the nVidia nForce and Serverworks
+HT2000). It may then be required to update the NO_MSI flag on the
+corresponding devices in the sysfs hierarchy. To enable MSI support
+on device "0000:00:0e", do:
+
+ echo 1 > /sys/bus/pci/devices/0000:00:0e/msi_bus
+
+To disable MSI support, echo 0 instead of 1. Note that it should be
+used with caution since changing this value might break interrupts.
+
+6.3. Disabling MSI globally
+
+Some extreme cases may require to disable MSI globally on the system.
+For now, the only known case is a Serverworks PCI-X chipsets (MSI are
+not supported on several busses that are not all connected to the
+chipset in the Linux PCI hierarchy). In the vast majority of other
+cases, disabling only behind a specific bridge is enough.
+
+For debugging purpose, the user may also pass pci=nomsi on the kernel
+command-line to explicitly disable MSI globally. But, once the appro-
+priate quirks are added to the kernel, this option should not be
+required anymore.
+
+6.4. Finding why MSI cannot be enabled on a device
+
+Assuming that MSI are not enabled on a device, you should look at
+dmesg to find messages that quirks may output when disabling MSI
+on some devices, some bridges or even globally.
+Then, lspci -t gives the list of bridges above a device. Reading
+/sys/bus/pci/devices/0000:00:0e/msi_bus will tell you whether MSI
+are enabled (1) or disabled (0). In 0 is found in a single bridge
+msi_bus file above the device, MSI cannot be enabled.
+
+7. FAQ
Q1. Are there any limitations on using the MSI?
diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
index 1d50cf0c905e..f4dffadbcb00 100644
--- a/Documentation/RCU/checklist.txt
+++ b/Documentation/RCU/checklist.txt
@@ -221,3 +221,41 @@ over a rather long period of time, but improvements are always welcome!
disable irq on a given acquisition of that lock will result in
deadlock as soon as the RCU callback happens to interrupt that
acquisition's critical section.
+
+13. SRCU (srcu_read_lock(), srcu_read_unlock(), and synchronize_srcu())
+ may only be invoked from process context. Unlike other forms of
+ RCU, it -is- permissible to block in an SRCU read-side critical
+ section (demarked by srcu_read_lock() and srcu_read_unlock()),
+ hence the "SRCU": "sleepable RCU". Please note that if you
+ don't need to sleep in read-side critical sections, you should
+ be using RCU rather than SRCU, because RCU is almost always
+ faster and easier to use than is SRCU.
+
+ Also unlike other forms of RCU, explicit initialization
+ and cleanup is required via init_srcu_struct() and
+ cleanup_srcu_struct(). These are passed a "struct srcu_struct"
+ that defines the scope of a given SRCU domain. Once initialized,
+ the srcu_struct is passed to srcu_read_lock(), srcu_read_unlock()
+ and synchronize_srcu(). A given synchronize_srcu() waits only
+ for SRCU read-side critical sections governed by srcu_read_lock()
+ and srcu_read_unlock() calls that have been passd the same
+ srcu_struct. This property is what makes sleeping read-side
+ critical sections tolerable -- a given subsystem delays only
+ its own updates, not those of other subsystems using SRCU.
+ Therefore, SRCU is less prone to OOM the system than RCU would
+ be if RCU's read-side critical sections were permitted to
+ sleep.
+
+ The ability to sleep in read-side critical sections does not
+ come for free. First, corresponding srcu_read_lock() and
+ srcu_read_unlock() calls must be passed the same srcu_struct.
+ Second, grace-period-detection overhead is amortized only
+ over those updates sharing a given srcu_struct, rather than
+ being globally amortized as they are for other forms of RCU.
+ Therefore, SRCU should be used in preference to rw_semaphore
+ only in extremely read-intensive situations, or in situations
+ requiring SRCU's read-side deadlock immunity or low read-side
+ realtime latency.
+
+ Note that, rcu_assign_pointer() and rcu_dereference() relate to
+ SRCU just as they do to other forms of RCU.
diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt
index 02e27bf1d365..f84407cba816 100644
--- a/Documentation/RCU/rcu.txt
+++ b/Documentation/RCU/rcu.txt
@@ -45,7 +45,8 @@ o How can I see where RCU is currently used in the Linux kernel?
Search for "rcu_read_lock", "rcu_read_unlock", "call_rcu",
"rcu_read_lock_bh", "rcu_read_unlock_bh", "call_rcu_bh",
- "synchronize_rcu", and "synchronize_net".
+ "srcu_read_lock", "srcu_read_unlock", "synchronize_rcu",
+ "synchronize_net", and "synchronize_srcu".
o What guidelines should I follow when writing code that uses RCU?
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
index a4948591607d..25a3c3f7d378 100644
--- a/Documentation/RCU/torture.txt
+++ b/Documentation/RCU/torture.txt
@@ -28,6 +28,15 @@ nreaders This is the number of RCU reading threads supported.
To properly exercise RCU implementations with preemptible
read-side critical sections.
+nfakewriters This is the number of RCU fake writer threads to run. Fake
+ writer threads repeatedly use the synchronous "wait for
+ current readers" function of the interface selected by
+ torture_type, with a delay between calls to allow for various
+ different numbers of writers running in parallel.
+ nfakewriters defaults to 4, which provides enough parallelism
+ to trigger special cases caused by multiple writers, such as
+ the synchronize_srcu() early return optimization.
+
stat_interval The number of seconds between output of torture
statistics (via printk()). Regardless of the interval,
statistics are printed when the module is unloaded.
@@ -44,9 +53,12 @@ test_no_idle_hz Whether or not to test the ability of RCU to operate in
a kernel that disables the scheduling-clock interrupt to
idle CPUs. Boolean parameter, "1" to test, "0" otherwise.
-torture_type The type of RCU to test: "rcu" for the rcu_read_lock()
- API, "rcu_bh" for the rcu_read_lock_bh() API, and "srcu"
- for the "srcu_read_lock()" API.
+torture_type The type of RCU to test: "rcu" for the rcu_read_lock() API,
+ "rcu_sync" for rcu_read_lock() with synchronous reclamation,
+ "rcu_bh" for the rcu_read_lock_bh() API, "rcu_bh_sync" for
+ rcu_read_lock_bh() with synchronous reclamation, "srcu" for
+ the "srcu_read_lock()" API, and "sched" for the use of
+ preempt_disable() together with synchronize_sched().
verbose Enable debug printk()s. Default is disabled.
@@ -118,6 +130,21 @@ o "Free-Block Circulation": Shows the number of torture structures
as it is only incremented if a torture structure's counter
somehow gets incremented farther than it should.
+Different implementations of RCU can provide implementation-specific
+additional information. For example, SRCU provides the following:
+
+ srcu-torture: rtc: f8cf46a8 ver: 355 tfle: 0 rta: 356 rtaf: 0 rtf: 346 rtmbe: 0
+ srcu-torture: Reader Pipe: 559738 939 0 0 0 0 0 0 0 0 0
+ srcu-torture: Reader Batch: 560434 243 0 0 0 0 0 0 0 0
+ srcu-torture: Free-Block Circulation: 355 354 353 352 351 350 349 348 347 346 0
+ srcu-torture: per-CPU(idx=1): 0(0,1) 1(0,1) 2(0,0) 3(0,1)
+
+The first four lines are similar to those for RCU. The last line shows
+the per-CPU counter state. The numbers in parentheses are the values
+of the "old" and "current" counters for the corresponding CPU. The
+"idx" value maps the "old" and "current" values to the underlying array,
+and is useful for debugging.
+
USAGE
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index 318df44259b3..e0d6d99b8f9b 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -582,7 +582,7 @@ The rcu_read_lock() and rcu_read_unlock() primitive read-acquire
and release a global reader-writer lock. The synchronize_rcu()
primitive write-acquires this same lock, then immediately releases
it. This means that once synchronize_rcu() exits, all RCU read-side
-critical sections that were in progress before synchonize_rcu() was
+critical sections that were in progress before synchronize_rcu() was
called are guaranteed to have completed -- there is no way that
synchronize_rcu() would have been able to write-acquire the lock
otherwise.
@@ -750,7 +750,7 @@ Or, for those who prefer a side-by-side listing:
Either way, the differences are quite small. Read-side locking moves
to rcu_read_lock() and rcu_read_unlock, update-side locking moves from
-from a reader-writer lock to a simple spinlock, and a synchronize_rcu()
+a reader-writer lock to a simple spinlock, and a synchronize_rcu()
precedes the kfree().
However, there is one potential catch: the read-side and update-side
@@ -778,6 +778,8 @@ Markers for RCU read-side critical sections:
rcu_read_unlock
rcu_read_lock_bh
rcu_read_unlock_bh
+ srcu_read_lock
+ srcu_read_unlock
RCU pointer/list traversal:
@@ -804,6 +806,7 @@ RCU grace period:
synchronize_net
synchronize_sched
synchronize_rcu
+ synchronize_srcu
call_rcu
call_rcu_bh
diff --git a/Documentation/SubmitChecklist b/Documentation/SubmitChecklist
index a10bfb6ecd9f..7ac61f60037a 100644
--- a/Documentation/SubmitChecklist
+++ b/Documentation/SubmitChecklist
@@ -61,3 +61,8 @@ kernel patches.
Documentation/kernel-parameters.txt.
18: All new module parameters are documented with MODULE_PARM_DESC()
+
+19: All new userspace interfaces are documented in Documentation/ABI/.
+ See Documentation/ABI/README for more information.
+
+20: Check that it all passes `make headers_check'.
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index 6bd30fdd0786..58bead05eabb 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -59,11 +59,11 @@ Copyright: The copyright owner must agree to use of GPL.
are the same person/entity. If not, the name of
the person/entity authorizing use of GPL should be
listed in case it's necessary to verify the will of
- the copright owner.
+ the copyright owner.
Interfaces: If your driver uses existing interfaces and behaves like
other drivers in the same class it will be much more likely
- to be accepted than if it invents gratuitous new ones.
+ to be accepted than if it invents gratuitous new ones.
If you need to implement a common API over Linux and NT
drivers do it in userspace.
@@ -88,7 +88,7 @@ Clarity: It helps if anyone can see how to fix the driver. It helps
it will go in the bitbucket.
Control: In general if there is active maintainance of a driver by
- the author then patches will be redirected to them unless
+ the author then patches will be redirected to them unless
they are totally obvious and without need of checking.
If you want to be the contact and update point for the
driver it is a good idea to state this in the comments,
@@ -100,7 +100,7 @@ What Criteria Do Not Determine Acceptance
Vendor: Being the hardware vendor and maintaining the driver is
often a good thing. If there is a stable working driver from
other people already in the tree don't expect 'we are the
- vendor' to get your driver chosen. Ideally work with the
+ vendor' to get your driver chosen. Ideally work with the
existing driver author to build a single perfect driver.
Author: It doesn't matter if a large Linux company wrote the driver,
@@ -116,17 +116,13 @@ Linux kernel master tree:
ftp.??.kernel.org:/pub/linux/kernel/...
?? == your country code, such as "us", "uk", "fr", etc.
-Linux kernel mailing list:
+Linux kernel mailing list:
linux-kernel@vger.kernel.org
[mail majordomo@vger.kernel.org to subscribe]
Linux Device Drivers, Third Edition (covers 2.6.10):
http://lwn.net/Kernel/LDD3/ (free version)
-Kernel traffic:
- Weekly summary of kernel list activity (much easier to read)
- http://www.kerneltraffic.org/kernel-traffic/
-
LWN.net:
Weekly summary of kernel development activity - http://lwn.net/
2.6 API changes:
@@ -145,11 +141,8 @@ KernelNewbies:
Linux USB project:
http://www.linux-usb.org/
-How to NOT write kernel driver by arjanv@redhat.com
- http://people.redhat.com/arjanv/olspaper.pdf
+How to NOT write kernel driver by Arjan van de Ven:
+ http://www.fenrus.org/how-to-not-write-a-device-driver-paper.pdf
Kernel Janitor:
http://janitor.kernelnewbies.org/
-
---
-Last updated on 17 Nov 2005.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index d42ab4c9e893..302d148c2e18 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -173,15 +173,15 @@ For small patches you may want to CC the Trivial Patch Monkey
trivial@kernel.org managed by Adrian Bunk; which collects "trivial"
patches. Trivial patches must qualify for one of the following rules:
Spelling fixes in documentation
- Spelling fixes which could break grep(1).
+ Spelling fixes which could break grep(1)
Warning fixes (cluttering with useless warnings is bad)
Compilation fixes (only if they are actually correct)
Runtime fixes (only if they actually fix things)
- Removing use of deprecated functions/macros (eg. check_region).
+ Removing use of deprecated functions/macros (eg. check_region)
Contact detail and documentation fixes
Non-portable code replaced by portable code (even in arch-specific,
since people copy, as long as it's trivial)
- Any fix by the author/maintainer of the file. (ie. patch monkey
+ Any fix by the author/maintainer of the file (ie. patch monkey
in re-transmission mode)
URL: <http://www.kernel.org/pub/linux/kernel/people/bunk/trivial/>
@@ -209,6 +209,19 @@ Exception: If your mailer is mangling patches then someone may ask
you to re-send them using MIME.
+WARNING: Some mailers like Mozilla send your messages with
+---- message header ----
+Content-Type: text/plain; charset=us-ascii; format=flowed
+---- message header ----
+The problem is that "format=flowed" makes some of the mailers
+on receiving side to replace TABs with spaces and do similar
+changes. Thus the patches from you can look corrupted.
+
+To fix this just make your mozilla defaults/pref/mailnews.js file to look like:
+pref("mailnews.send_plaintext_flowed", false); // RFC 2646=======
+pref("mailnews.display.disable_format_flowed_support", true);
+
+
7) E-mail size.
@@ -245,13 +258,13 @@ updated change.
It is quite common for Linus to "drop" your patch without comment.
That's the nature of the system. If he drops your patch, it could be
due to
-* Your patch did not apply cleanly to the latest kernel version
+* Your patch did not apply cleanly to the latest kernel version.
* Your patch was not sufficiently discussed on linux-kernel.
-* A style issue (see section 2),
-* An e-mail formatting issue (re-read this section)
-* A technical problem with your change
-* He gets tons of e-mail, and yours got lost in the shuffle
-* You are being annoying (See Figure 1)
+* A style issue (see section 2).
+* An e-mail formatting issue (re-read this section).
+* A technical problem with your change.
+* He gets tons of e-mail, and yours got lost in the shuffle.
+* You are being annoying.
When in doubt, solicit comments on linux-kernel mailing list.
@@ -476,10 +489,10 @@ SECTION 3 - REFERENCES
Andrew Morton, "The perfect patch" (tpp).
<http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
-Jeff Garzik, "Linux kernel patch submission format."
+Jeff Garzik, "Linux kernel patch submission format".
<http://linux.yyz.us/patch-format.html>
-Greg Kroah-Hartman "How to piss off a kernel subsystem maintainer".
+Greg Kroah-Hartman, "How to piss off a kernel subsystem maintainer".
<http://www.kroah.com/log/2005/03/31/>
<http://www.kroah.com/log/2005/07/08/>
<http://www.kroah.com/log/2005/10/19/>
@@ -488,9 +501,9 @@ Greg Kroah-Hartman "How to piss off a kernel subsystem maintainer".
NO!!!! No more huge patch bombs to linux-kernel@vger.kernel.org people!
<http://marc.theaimsgroup.com/?l=linux-kernel&m=112112749912944&w=2>
-Kernel Documentation/CodingStyle
+Kernel Documentation/CodingStyle:
<http://sosdg.org/~coywolf/lxr/source/Documentation/CodingStyle>
-Linus Torvald's mail on the canonical patch format:
+Linus Torvalds's mail on the canonical patch format:
<http://lkml.org/lkml/2005/4/7/183>
--
diff --git a/Documentation/accounting/getdelays.c b/Documentation/accounting/getdelays.c
index 795ca3911cc5..b11792abd6b6 100644
--- a/Documentation/accounting/getdelays.c
+++ b/Documentation/accounting/getdelays.c
@@ -285,7 +285,7 @@ int main(int argc, char *argv[])
if (maskset) {
rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
- &cpumask, sizeof(cpumask));
+ &cpumask, strlen(cpumask) + 1);
PRINTF("Sent register cpumask, retval %d\n", rc);
if (rc < 0) {
printf("error sending register cpumask\n");
@@ -315,7 +315,8 @@ int main(int argc, char *argv[])
}
if (msg.n.nlmsg_type == NLMSG_ERROR ||
!NLMSG_OK((&msg.n), rep_len)) {
- printf("fatal reply error, errno %d\n", errno);
+ struct nlmsgerr *err = NLMSG_DATA(&msg);
+ printf("fatal reply error, errno %d\n", err->error);
goto done;
}
@@ -383,7 +384,7 @@ done:
if (maskset) {
rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
- &cpumask, sizeof(cpumask));
+ &cpumask, strlen(cpumask) + 1);
printf("Sent deregister mask, retval %d\n", rc);
if (rc < 0)
err(rc, "error sending deregister cpumask\n");
diff --git a/Documentation/accounting/taskstats-struct.txt b/Documentation/accounting/taskstats-struct.txt
new file mode 100644
index 000000000000..661c797eaf79
--- /dev/null
+++ b/Documentation/accounting/taskstats-struct.txt
@@ -0,0 +1,161 @@
+The struct taskstats
+--------------------
+
+This document contains an explanation of the struct taskstats fields.
+
+There are three different groups of fields in the struct taskstats:
+
+1) Common and basic accounting fields
+ If CONFIG_TASKSTATS is set, the taskstats inteface is enabled and
+ the common fields and basic accounting fields are collected for
+ delivery at do_exit() of a task.
+2) Delay accounting fields
+ These fields are placed between
+ /* Delay accounting fields start */
+ and
+ /* Delay accounting fields end */
+ Their values are collected if CONFIG_TASK_DELAY_ACCT is set.
+3) Extended accounting fields
+ These fields are placed between
+ /* Extended accounting fields start */
+ and
+ /* Extended accounting fields end */
+ Their values are collected if CONFIG_TASK_XACCT is set.
+
+Future extension should add fields to the end of the taskstats struct, and
+should not change the relative position of each field within the struct.
+
+
+struct taskstats {
+
+1) Common and basic accounting fields:
+ /* The version number of this struct. This field is always set to
+ * TAKSTATS_VERSION, which is defined in <linux/taskstats.h>.
+ * Each time the struct is changed, the value should be incremented.
+ */
+ __u16 version;
+
+ /* The exit code of a task. */
+ __u32 ac_exitcode; /* Exit status */
+
+ /* The accounting flags of a task as defined in <linux/acct.h>
+ * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG.
+ */
+ __u8 ac_flag; /* Record flags */
+
+ /* The value of task_nice() of a task. */
+ __u8 ac_nice; /* task_nice */
+
+ /* The name of the command that started this task. */
+ char ac_comm[TS_COMM_LEN]; /* Command name */
+
+ /* The scheduling discipline as set in task->policy field. */
+ __u8 ac_sched; /* Scheduling discipline */
+
+ __u8 ac_pad[3];
+ __u32 ac_uid; /* User ID */
+ __u32 ac_gid; /* Group ID */
+ __u32 ac_pid; /* Process ID */
+ __u32 ac_ppid; /* Parent process ID */
+
+ /* The time when a task begins, in [secs] since 1970. */
+ __u32 ac_btime; /* Begin time [sec since 1970] */
+
+ /* The elapsed time of a task, in [usec]. */
+ __u64 ac_etime; /* Elapsed time [usec] */
+
+ /* The user CPU time of a task, in [usec]. */
+ __u64 ac_utime; /* User CPU time [usec] */
+
+ /* The system CPU time of a task, in [usec]. */
+ __u64 ac_stime; /* System CPU time [usec] */
+
+ /* The minor page fault count of a task, as set in task->min_flt. */
+ __u64 ac_minflt; /* Minor Page Fault Count */
+
+ /* The major page fault count of a task, as set in task->maj_flt. */
+ __u64 ac_majflt; /* Major Page Fault Count */
+
+
+2) Delay accounting fields:
+ /* Delay accounting fields start
+ *
+ * All values, until the comment "Delay accounting fields end" are
+ * available only if delay accounting is enabled, even though the last
+ * few fields are not delays
+ *
+ * xxx_count is the number of delay values recorded
+ * xxx_delay_total is the corresponding cumulative delay in nanoseconds
+ *
+ * xxx_delay_total wraps around to zero on overflow
+ * xxx_count incremented regardless of overflow
+ */
+
+ /* Delay waiting for cpu, while runnable
+ * count, delay_total NOT updated atomically
+ */
+ __u64 cpu_count;
+ __u64 cpu_delay_total;
+
+ /* Following four fields atomically updated using task->delays->lock */
+
+ /* Delay waiting for synchronous block I/O to complete
+ * does not account for delays in I/O submission
+ */
+ __u64 blkio_count;
+ __u64 blkio_delay_total;
+
+ /* Delay waiting for page fault I/O (swap in only) */
+ __u64 swapin_count;
+ __u64 swapin_delay_total;
+
+ /* cpu "wall-clock" running time
+ * On some architectures, value will adjust for cpu time stolen
+ * from the kernel in involuntary waits due to virtualization.
+ * Value is cumulative, in nanoseconds, without a corresponding count
+ * and wraps around to zero silently on overflow
+ */
+ __u64 cpu_run_real_total;
+
+ /* cpu "virtual" running time
+ * Uses time intervals seen by the kernel i.e. no adjustment
+ * for kernel's involuntary waits due to virtualization.
+ * Value is cumulative, in nanoseconds, without a corresponding count
+ * and wraps around to zero silently on overflow
+ */
+ __u64 cpu_run_virtual_total;
+ /* Delay accounting fields end */
+ /* version 1 ends here */
+
+
+3) Extended accounting fields
+ /* Extended accounting fields start */
+
+ /* Accumulated RSS usage in duration of a task, in MBytes-usecs.
+ * The current rss usage is added to this counter every time
+ * a tick is charged to a task's system time. So, at the end we
+ * will have memory usage multiplied by system time. Thus an
+ * average usage per system time unit can be calculated.
+ */
+ __u64 coremem; /* accumulated RSS usage in MB-usec */
+
+ /* Accumulated virtual memory usage in duration of a task.
+ * Same as acct_rss_mem1 above except that we keep track of VM usage.
+ */
+ __u64 virtmem; /* accumulated VM usage in MB-usec */
+
+ /* High watermark of RSS usage in duration of a task, in KBytes. */
+ __u64 hiwater_rss; /* High-watermark of RSS usage */
+
+ /* High watermark of VM usage in duration of a task, in KBytes. */
+ __u64 hiwater_vm; /* High-water virtual memory usage */
+
+ /* The following four fields are I/O statistics of a task. */
+ __u64 read_char; /* bytes read */
+ __u64 write_char; /* bytes written */
+ __u64 read_syscalls; /* read syscalls */
+ __u64 write_syscalls; /* write syscalls */
+
+ /* Extended accounting fields end */
+
+}
diff --git a/Documentation/aoe/todo.txt b/Documentation/aoe/todo.txt
index 7fee1e1165bc..c09dfad4aed8 100644
--- a/Documentation/aoe/todo.txt
+++ b/Documentation/aoe/todo.txt
@@ -7,7 +7,7 @@ not been observed, but it would be nice to eliminate any potential for
deadlock under memory pressure.
Because ATA over Ethernet is not fragmented by the kernel's IP code,
-the destructore member of the struct sk_buff is available to the aoe
+the destructor member of the struct sk_buff is available to the aoe
driver. By using a mempool for allocating all but the first few
sk_buffs, and by registering a destructor, we should be able to
efficiently allocate sk_buffs without introducing any potential for
diff --git a/Documentation/arm/SA1100/serial_UART b/Documentation/arm/SA1100/serial_UART
index aea2e91ca0ef..a63966f1d083 100644
--- a/Documentation/arm/SA1100/serial_UART
+++ b/Documentation/arm/SA1100/serial_UART
@@ -24,8 +24,8 @@ The SA1100 serial port had its major/minor numbers officially assigned:
> 7 = /dev/cusa2 Callout device for ttySA2
>
-If you're not using devfs, you must create those inodes in /dev
-on the root filesystem used by your SA1100-based device:
+You must create those inodes in /dev on the root filesystem used
+by your SA1100-based device:
mknod ttySA0 c 204 5
mknod ttySA1 c 204 6
diff --git a/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt b/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
index 000e3d7a78b2..26422f0f9080 100644
--- a/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
+++ b/Documentation/arm/Samsung-S3C24XX/EB2410ITX.txt
@@ -38,7 +38,7 @@ MTD
---
The NAND and NOR support has been merged from the linux-mtd project.
- Any prolbems, see http://www.linux-mtd.infradead.org/ for more
+ Any problems, see http://www.linux-mtd.infradead.org/ for more
information or up-to-date versions of linux-mtd.
diff --git a/Documentation/arm/Samsung-S3C24XX/GPIO.txt b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
index 0822764ec270..8caea8c237ee 100644
--- a/Documentation/arm/Samsung-S3C24XX/GPIO.txt
+++ b/Documentation/arm/Samsung-S3C24XX/GPIO.txt
@@ -24,7 +24,7 @@ Headers
header include/asm-arm/arch-s3c2410/hardware.h which can be
included by #include <asm/arch/hardware.h>
- A useful ammount of documentation can be found in the hardware
+ A useful amount of documentation can be found in the hardware
header on how the GPIO functions (and others) work.
Whilst a number of these functions do make some checks on what
diff --git a/Documentation/arm/Samsung-S3C24XX/Overview.txt b/Documentation/arm/Samsung-S3C24XX/Overview.txt
index 3e46d2a31158..dda7ecdde87b 100644
--- a/Documentation/arm/Samsung-S3C24XX/Overview.txt
+++ b/Documentation/arm/Samsung-S3C24XX/Overview.txt
@@ -80,7 +80,7 @@ Machines
Adding New Machines
-------------------
- The archicture has been designed to support as many machines as can
+ The architecture has been designed to support as many machines as can
be configured for it in one kernel build, and any future additions
should keep this in mind before altering items outside of their own
machine files.
diff --git a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
index cb82a7fc7901..295d971a15ed 100644
--- a/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
+++ b/Documentation/arm/Samsung-S3C24XX/S3C2412.txt
@@ -80,7 +80,7 @@ RTC
Watchdog
--------
- The watchdog harware is the same as the S3C2410, and is supported by
+ The watchdog hardware is the same as the S3C2410, and is supported by
the s3c2410_wdt driver.
diff --git a/Documentation/block/as-iosched.txt b/Documentation/block/as-iosched.txt
index 6f47332c883d..e2a66f8143c5 100644
--- a/Documentation/block/as-iosched.txt
+++ b/Documentation/block/as-iosched.txt
@@ -99,8 +99,8 @@ contrast, many write requests may be dispatched to the disk controller
at a time during a write batch. It is this characteristic that can make
the anticipatory scheduler perform anomalously with controllers supporting
TCQ, or with hardware striped RAID devices. Setting the antic_expire
-queue paramter (see below) to zero disables this behavior, and the anticipatory
-scheduler behaves essentially like the deadline scheduler.
+queue parameter (see below) to zero disables this behavior, and the
+anticipatory scheduler behaves essentially like the deadline scheduler.
When read anticipation is enabled (antic_expire is not zero), reads
are dispatched to the disk controller one at a time.
diff --git a/Documentation/block/barrier.txt b/Documentation/block/barrier.txt
index 03971518b222..a272c3db8094 100644
--- a/Documentation/block/barrier.txt
+++ b/Documentation/block/barrier.txt
@@ -25,7 +25,7 @@ of the following three ways.
i. For devices which have queue depth greater than 1 (TCQ devices) and
support ordered tags, block layer can just issue the barrier as an
ordered request and the lower level driver, controller and drive
-itself are responsible for making sure that the ordering contraint is
+itself are responsible for making sure that the ordering constraint is
met. Most modern SCSI controllers/drives should support this.
NOTE: SCSI ordered tag isn't currently used due to limitation in the
@@ -42,7 +42,7 @@ iii. Devices which have queue depth of 1. This is a degenerate case
of ii. Just keeping issue order suffices. Ancient SCSI
controllers/drives and IDE drives are in this category.
-2. Forced flushing to physcial medium
+2. Forced flushing to physical medium
Again, if you're not gonna do synchronization with disk drives (dang,
it sounds even more appealing now!), the reason you use I/O barriers
@@ -56,7 +56,7 @@ There are four cases,
i. No write-back cache. Keeping requests ordered is enough.
ii. Write-back cache but no flush operation. There's no way to
-gurantee physical-medium commit order. This kind of devices can't to
+guarantee physical-medium commit order. This kind of devices can't to
I/O barriers.
iii. Write-back cache and flush operation but no FUA (forced unit
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index f989a9e839b4..34bf8f60d8f8 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -135,7 +135,7 @@ Some new queue property settings:
Sets two variables that limit the size of the request.
- The request queue's max_sectors, which is a soft size in
- in units of 512 byte sectors, and could be dynamically varied
+ units of 512 byte sectors, and could be dynamically varied
by the core kernel.
- The request queue's max_hw_sectors, which is a hard limit
@@ -783,7 +783,7 @@ all the outstanding requests. There's a third helper to do that:
blk_queue_invalidate_tags(request_queue_t *q)
- Clear the internal block tag queue and readd all the pending requests
+ Clear the internal block tag queue and re-add all the pending requests
to the request queue. The driver will receive them again on the
next request_fn run, just like it did the first time it encountered
them.
@@ -890,7 +890,7 @@ Aside:
Kvec i/o:
- Ben LaHaise's aio code uses a slighly different structure instead
+ Ben LaHaise's aio code uses a slightly different structure instead
of kiobufs, called a kvec_cb. This contains an array of <page, offset, len>
tuples (very much like the networking code), together with a callback function
and data pointer. This is embedded into a brw_cb structure when passed
@@ -988,7 +988,7 @@ elevator_exit_fn Allocate and free any elevator specific storage
for a queue.
4.2 Request flows seen by I/O schedulers
-All requests seens by I/O schedulers strictly follow one of the following three
+All requests seen by I/O schedulers strictly follow one of the following three
flows.
set_req_fn ->
@@ -1203,6 +1203,6 @@ temporarily map a bio into the virtual address space.
and Linus' comments - Jan 2001)
9.2 Discussions about kiobuf and bh design on lkml between sct, linus, alan
et al - Feb-March 2001 (many of the initial thoughts that led to bio were
-brought up in this discusion thread)
+brought up in this discussion thread)
9.3 Discussions on mempool on lkml - Dec 2001.
diff --git a/Documentation/block/deadline-iosched.txt b/Documentation/block/deadline-iosched.txt
index c918b3a6022d..be08ffd1e9b8 100644
--- a/Documentation/block/deadline-iosched.txt
+++ b/Documentation/block/deadline-iosched.txt
@@ -23,11 +23,11 @@ you can do so by typing:
read_expire (in ms)
-----------
-The goal of the deadline io scheduler is to attempt to guarentee a start
+The goal of the deadline io scheduler is to attempt to guarantee a start
service time for a request. As we focus mainly on read latencies, this is
tunable. When a read request first enters the io scheduler, it is assigned
a deadline that is the current time + the read_expire value in units of
-miliseconds.
+milliseconds.
write_expire (in ms)
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
index 9c629ffa0e58..f74affe5c829 100644
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -80,7 +80,7 @@ the /proc filesystem entry which the "block" side of the driver creates as
the SCSI core may not yet be initialized (because the driver is a block
driver) and attempting to register it with the SCSI core in such a case
would cause a hang. This is best done via an initialization script
-(typically in /etc/init.d, but could vary depending on distibution).
+(typically in /etc/init.d, but could vary depending on distribution).
For example:
for x in /proc/driver/cciss/cciss[0-9]*
@@ -152,7 +152,7 @@ side during the SCSI error recovery process, the cciss driver only
implements the first two of these actions, aborting the command, and
resetting the device. Additionally, most tape drives will not oblige
in aborting commands, and sometimes it appears they will not even
-obey a reset coommand, though in most circumstances they will. In
+obey a reset command, though in most circumstances they will. In
the case that the command cannot be aborted and the device cannot be
reset, the device will be set offline.
diff --git a/Documentation/computone.txt b/Documentation/computone.txt
index b1cf59b84d97..5e2a0c76bfa0 100644
--- a/Documentation/computone.txt
+++ b/Documentation/computone.txt
@@ -199,30 +199,6 @@ boxes this will leave gaps in the sequence of device names. ip2mkdev uses
Linux tty naming conventions: ttyF0 - ttyF255 for normal devices, and
cuf0 - cuf255 for callout devices.
-If you are using devfs, existing devices are automatically created within
-the devfs name space. Normal devices will be tts/F0 - tts/F255 and callout
-devices will be cua/F0 - cua/F255. With devfs installed, ip2mkdev will
-create symbolic links in /dev from the old conventional names to the newer
-devfs names as follows:
-
- /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3
- /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3
- /dev/ttyF[n] -> /dev/tts/F[n] n = 0 - 255
- /dev/cuf[n] -> /dev/cua/F[n] n = 0 - 255
-
-Only devices for existing ports and boards will be created.
-
-IMPORTANT NOTE: The naming convention used for devfs by this driver
-was changed from 1.2.12 to 1.2.13. The old naming convention was to
-use ttf/%d for the tty device and cuf/%d for the cua device. That
-has been changed to conform to an agreed-upon standard of placing
-all the tty devices under tts. The device names are now tts/F%d for
-the tty device and cua/F%d for the cua devices. If you were using
-the older devfs names, you must update for the newer convention.
-
-You do not need to run ip2mkdev if you are using devfs and only want to
-use the devfs native device names.
-
4. USING THE DRIVERS
@@ -256,57 +232,15 @@ cut out and run as "ip2mkdev" to create the necessary device files. To
use the ip2mkdev script, you must have procfs enabled and the proc file
system mounted on /proc.
-You do not need to run ip2mkdev if you are using devfs and only want to
-use the devfs native device names.
-
-
-6. DEVFS
-
-DEVFS is the DEVice File System available as an add on package for the
-2.2.x kernels and available as a configuration option in 2.3.46 and higher.
-Devfs allows for the automatic creation and management of device names
-under control of the device drivers themselves. The Devfs namespace is
-hierarchical and reduces the clutter present in the normal flat /dev
-namespace. Devfs names and conventional device names may be intermixed.
-A userspace daemon, devfsd, exists to allow for automatic creation and
-management of symbolic links from the devfs name space to the conventional
-names. More details on devfs can be found on the DEVFS home site at
-<http://www.atnf.csiro.au/~rgooch/linux/> or in the file kernel
-documentation files, .../linux/Documentation/filesystems/devfs/README.
-
-If you are using devfs, existing devices are automatically created within
-the devfs name space. Normal devices will be tts/F0 - tts/F255 and callout
-devices will be cua/F0 - cua/F255. With devfs installed, ip2mkdev will
-create symbolic links in /dev from the old conventional names to the newer
-devfs names as follows:
-
- /dev/ip2ipl[n] -> /dev/ip2/ipl[n] n = 0 - 3
- /dev/ip2stat[n] -> /dev/ip2/stat[n] n = 0 - 3
- /dev/ttyF[n] -> /dev/tts/F[n] n = 0 - 255
- /dev/cuf[n] -> /dev/cua/F[n] n = 0 - 255
-
-Only devices for existing ports and boards will be created.
-
-IMPORTANT NOTE: The naming convention used for devfs by this driver
-was changed from 1.2.12 to 1.2.13. The old naming convention was to
-use ttf/%d for the tty device and cuf/%d for the cua device. That
-has been changed to conform to an agreed-upon standard of placing
-all the tty devices under tts. The device names are now tts/F%d for
-the tty device and cua/F%d for the cua devices. If you were using
-the older devfs names, you must update for the newer convention.
-
-You do not need to run ip2mkdev if you are using devfs and only want to
-use the devfs native device names.
-
-7. NOTES
+6. NOTES
This is a release version of the driver, but it is impossible to test it
in all configurations of Linux. If there is any anomalous behaviour that
does not match the standard serial port's behaviour please let us know.
-8. ip2mkdev shell script
+7. ip2mkdev shell script
Previously, this script was simply attached here. It is now attached as a
shar archive to make it easier to extract the script from the documentation.
diff --git a/Documentation/cpu-freq/cpufreq-stats.txt b/Documentation/cpu-freq/cpufreq-stats.txt
index 6a82948ff4bd..53d62c1e1c94 100644
--- a/Documentation/cpu-freq/cpufreq-stats.txt
+++ b/Documentation/cpu-freq/cpufreq-stats.txt
@@ -1,5 +1,5 @@
- CPU frequency and voltage scaling statictics in the Linux(TM) kernel
+ CPU frequency and voltage scaling statistics in the Linux(TM) kernel
L i n u x c p u f r e q - s t a t s d r i v e r
@@ -18,8 +18,8 @@ Contents
1. Introduction
cpufreq-stats is a driver that provices CPU frequency statistics for each CPU.
-This statistics is provided in /sysfs as a bunch of read_only interfaces. This
-interface (when configured) will appear in a seperate directory under cpufreq
+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.
Various statistics will form read_only files under this directory.
@@ -53,7 +53,7 @@ drwxr-xr-x 3 root root 0 May 14 15:58 ..
This gives the amount of time spent in each of the frequencies supported by
this CPU. The cat output will have "<frequency> <time>" pair in each line, which
will mean this CPU spent <time> usertime units of time at <frequency>. Output
-will have one line for each of the supported freuencies. usertime units here
+will have one line for each of the supported frequencies. usertime units here
is 10mS (similar to other time exported in /proc).
--------------------------------------------------------------------------------
@@ -115,7 +115,7 @@ basic statistics which includes time_in_state and total_trans.
"CPU frequency translation statistics details" (CONFIG_CPU_FREQ_STAT_DETAILS)
provides fine grained cpufreq stats by trans_table. The reason for having a
-seperate config option for trans_table is:
+separate config option for trans_table is:
- trans_table goes against the traditional /sysfs rule of one value per
interface. It provides a whole bunch of value in a 2 dimensional matrix
form.
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index f4b8dc4237e6..6a9c55bd556b 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -57,7 +57,7 @@ selected for each specific use.
Basically, it's the following flow graph:
-CPU can be set to switch independetly | CPU can only be set
+CPU can be set to switch independently | CPU can only be set
within specific "limits" | to specific frequencies
"CPUfreq policy"
@@ -109,7 +109,7 @@ directory.
2.4 Ondemand
------------
-The CPUfreq govenor "ondemand" sets the CPU depending on the
+The CPUfreq governor "ondemand" sets the CPU depending on the
current usage. To do this the CPU must have the capability to
switch the frequency very quickly. There are a number of sysfs file
accessible parameters:
@@ -137,11 +137,11 @@ have to be made in a row before the CPU frequency is actually lower.
If set to '1' then the frequency decreases as quickly as it increases,
if set to '2' it decreases at half the rate of the increase.
-ignore_nice_load: this parameter takes a value of '0' or '1', when set
-to '0' (its default) then all processes are counted towards towards the
-'cpu utilisation' value. When set to '1' then processes that are
+ignore_nice_load: this parameter takes a value of '0' or '1'. When
+set to '0' (its default), all processes are counted towards the
+'cpu utilisation' value. When set to '1', the processes that are
run with a 'nice' value will not count (and thus be ignored) in the
-overal usage calculation. This is useful if you are running a CPU
+overall usage calculation. This is useful if you are running a CPU
intensive calculation on your laptop that you do not care how long it
takes to complete as you can 'nice' it and prevent it from taking part
in the deciding process of whether to increase your CPU frequency.
diff --git a/Documentation/cpu-hotplug.txt b/Documentation/cpu-hotplug.txt
index bc107cb157a8..4868c34f7509 100644
--- a/Documentation/cpu-hotplug.txt
+++ b/Documentation/cpu-hotplug.txt
@@ -46,7 +46,7 @@ maxcpus=n Restrict boot time cpus to n. Say if you have 4 cpus, using
maxcpus=2 will only boot 2. You can choose to bring the
other cpus later online, read FAQ's for more info.
-additional_cpus*=n Use this to limit hotpluggable cpus. This option sets
+additional_cpus=n (*) Use this to limit hotpluggable cpus. This option sets
cpu_possible_map = cpu_present_map + additional_cpus
(*) Option valid only for following architectures
@@ -101,15 +101,15 @@ cpu_possible_map/for_each_possible_cpu() to iterate.
Never use anything other than cpumask_t to represent bitmap of CPUs.
-#include <linux/cpumask.h>
+ #include <linux/cpumask.h>
-for_each_possible_cpu - Iterate over cpu_possible_map
-for_each_online_cpu - Iterate over cpu_online_map
-for_each_present_cpu - Iterate over cpu_present_map
-for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
+ for_each_possible_cpu - Iterate over cpu_possible_map
+ for_each_online_cpu - Iterate over cpu_online_map
+ for_each_present_cpu - Iterate over cpu_present_map
+ for_each_cpu_mask(x,mask) - Iterate over some random collection of cpu mask.
-#include <linux/cpu.h>
-lock_cpu_hotplug() and unlock_cpu_hotplug():
+ #include <linux/cpu.h>
+ lock_cpu_hotplug() and unlock_cpu_hotplug():
The above calls are used to inhibit cpu hotplug operations. While holding the
cpucontrol mutex, cpu_online_map will not change. If you merely need to avoid
@@ -120,7 +120,7 @@ will work as long as stop_machine_run() is used to take a cpu down.
CPU Hotplug - Frequently Asked Questions.
-Q: How to i enable my kernel to support CPU hotplug?
+Q: How to enable my kernel to support CPU hotplug?
A: When doing make defconfig, Enable CPU hotplug support
"Processor type and Features" -> Support for Hotpluggable CPUs
@@ -141,39 +141,39 @@ A: You should now notice an entry in sysfs.
Check if sysfs is mounted, using the "mount" command. You should notice
an entry as shown below in the output.
-....
-none on /sys type sysfs (rw)
-....
+ ....
+ none on /sys type sysfs (rw)
+ ....
-if this is not mounted, do the following.
+If this is not mounted, do the following.
-#mkdir /sysfs
-#mount -t sysfs sys /sys
+ #mkdir /sysfs
+ #mount -t sysfs sys /sys
-now you should see entries for all present cpu, the following is an example
+Now you should see entries for all present cpu, the following is an example
in a 8-way system.
-#pwd
-#/sys/devices/system/cpu
-#ls -l
-total 0
-drwxr-xr-x 10 root root 0 Sep 19 07:44 .
-drwxr-xr-x 13 root root 0 Sep 19 07:45 ..
-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0
-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1
-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2
-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3
-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4
-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5
-drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6
-drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7
+ #pwd
+ #/sys/devices/system/cpu
+ #ls -l
+ total 0
+ drwxr-xr-x 10 root root 0 Sep 19 07:44 .
+ drwxr-xr-x 13 root root 0 Sep 19 07:45 ..
+ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu0
+ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu1
+ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu2
+ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu3
+ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu4
+ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu5
+ drwxr-xr-x 3 root root 0 Sep 19 07:44 cpu6
+ drwxr-xr-x 3 root root 0 Sep 19 07:48 cpu7
Under each directory you would find an "online" file which is the control
file to logically online/offline a processor.
Q: Does hot-add/hot-remove refer to physical add/remove of cpus?
A: The usage of hot-add/remove may not be very consistently used in the code.
-CONFIG_CPU_HOTPLUG enables logical online/offline capability in the kernel.
+CONFIG_HOTPLUG_CPU enables logical online/offline capability in the kernel.
To support physical addition/removal, one would need some BIOS hooks and
the platform should have something like an attention button in PCI hotplug.
CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs.
@@ -181,17 +181,17 @@ CONFIG_ACPI_HOTPLUG_CPU enables ACPI support for physical add/remove of CPUs.
Q: How do i logically offline a CPU?
A: Do the following.
-#echo 0 > /sys/devices/system/cpu/cpuX/online
+ #echo 0 > /sys/devices/system/cpu/cpuX/online
-once the logical offline is successful, check
+Once the logical offline is successful, check
-#cat /proc/interrupts
+ #cat /proc/interrupts
-you should now not see the CPU that you removed. Also online file will report
+You should now not see the CPU that you removed. Also online file will report
the state as 0 when a cpu if offline and 1 when its online.
-#To display the current cpu state.
-#cat /sys/devices/system/cpu/cpuX/online
+ #To display the current cpu state.
+ #cat /sys/devices/system/cpu/cpuX/online
Q: Why cant i remove CPU0 on some systems?
A: Some architectures may have some special dependency on a certain CPU.
@@ -234,8 +234,8 @@ Q: If i have some kernel code that needs to be aware of CPU arrival and
departure, how to i arrange for proper notification?
A: This is what you would need in your kernel code to receive notifications.
- #include <linux/cpu.h>
- static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb,
+ #include <linux/cpu.h>
+ static int __cpuinit foobar_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
@@ -279,10 +279,10 @@ Q: I don't see my action being called for all CPUs already up and running?
A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined.
If you need to perform some action for each cpu already in the system, then
- for_each_online_cpu(i) {
+ for_each_online_cpu(i) {
foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);
- foobar_cpu_callback(&foobar-cpu_notifier, CPU_ONLINE, i);
- }
+ foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i);
+ }
Q: If i would like to develop cpu hotplug support for a new architecture,
what do i need at a minimum?
@@ -307,38 +307,38 @@ Q: I need to ensure that a particular cpu is not removed when there is some
work specific to this cpu is in progress.
A: First switch the current thread context to preferred cpu
- int my_func_on_cpu(int cpu)
- {
- cpumask_t saved_mask, new_mask = CPU_MASK_NONE;
- int curr_cpu, err = 0;
-
- saved_mask = current->cpus_allowed;
- cpu_set(cpu, new_mask);
- err = set_cpus_allowed(current, new_mask);
-
- if (err)
- return err;
-
- /*
- * If we got scheduled out just after the return from
- * set_cpus_allowed() before running the work, this ensures
- * we stay locked.
- */
- curr_cpu = get_cpu();
-
- if (curr_cpu != cpu) {
- err = -EAGAIN;
- goto ret;
- } else {
- /*
- * Do work : But cant sleep, since get_cpu() disables preempt
- */
- }
- ret:
- put_cpu();
- set_cpus_allowed(current, saved_mask);
- return err;
- }
+ int my_func_on_cpu(int cpu)
+ {
+ cpumask_t saved_mask, new_mask = CPU_MASK_NONE;
+ int curr_cpu, err = 0;
+
+ saved_mask = current->cpus_allowed;
+ cpu_set(cpu, new_mask);
+ err = set_cpus_allowed(current, new_mask);
+
+ if (err)
+ return err;
+
+ /*
+ * If we got scheduled out just after the return from
+ * set_cpus_allowed() before running the work, this ensures
+ * we stay locked.
+ */
+ curr_cpu = get_cpu();
+
+ if (curr_cpu != cpu) {
+ err = -EAGAIN;
+ goto ret;
+ } else {
+ /*
+ * Do work : But cant sleep, since get_cpu() disables preempt
+ */
+ }
+ ret:
+ put_cpu();
+ set_cpus_allowed(current, saved_mask);
+ return err;
+ }
Q: How do we determine how many CPUs are available for hotplug.
diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt
index 76b44290c154..842f0d1ab216 100644
--- a/Documentation/cpusets.txt
+++ b/Documentation/cpusets.txt
@@ -217,11 +217,11 @@ exclusive cpuset. Also, the use of a Linux virtual file system (vfs)
to represent the cpuset hierarchy provides for a familiar permission
and name space for cpusets, with a minimum of additional kernel code.
-The cpus file in the root (top_cpuset) cpuset is read-only.
-It automatically tracks the value of cpu_online_map, using a CPU
-hotplug notifier. If and when memory nodes can be hotplugged,
-we expect to make the mems file in the root cpuset read-only
-as well, and have it track the value of node_online_map.
+The cpus and mems files in the root (top_cpuset) cpuset are
+read-only. The cpus file automatically tracks the value of
+cpu_online_map using a CPU hotplug notifier, and the mems file
+automatically tracks the value of node_online_map using the
+cpuset_track_online_nodes() hook.
1.4 What are exclusive cpusets ?
diff --git a/Documentation/cputopology.txt b/Documentation/cputopology.txt
index 2b28e9ec4e3a..b61cb9564023 100644
--- a/Documentation/cputopology.txt
+++ b/Documentation/cputopology.txt
@@ -26,7 +26,7 @@ The type of **_id is int.
The type of siblings is cpumask_t.
To be consistent on all architectures, the 4 attributes should have
-deafult values if their values are unavailable. Below is the rule.
+default values if their values are unavailable. Below is the rule.
1) physical_package_id: If cpu has no physical package id, -1 is the
default value.
2) core_id: If cpu doesn't support multi-core, its core id is 0.
diff --git a/Documentation/dell_rbu.txt b/Documentation/dell_rbu.txt
index 941343a7a265..2c0d631de0cf 100644
--- a/Documentation/dell_rbu.txt
+++ b/Documentation/dell_rbu.txt
@@ -4,7 +4,7 @@ for updating BIOS images on Dell servers and desktops.
Scope:
This document discusses the functionality of the rbu driver only.
-It does not cover the support needed from aplications to enable the BIOS to
+It does not cover the support needed from applications to enable the BIOS to
update itself with the image downloaded in to the memory.
Overview:
@@ -16,8 +16,8 @@ OpenManage and Dell Update packages (DUP).
Libsmbios can also be used to update BIOS on Dell systems go to
http://linux.dell.com/libsmbios/ for details.
-Dell_RBU driver supports BIOS update using the monilothic image and packetized
-image methods. In case of moniolithic the driver allocates a contiguous chunk
+Dell_RBU driver supports BIOS update using the monolithic image and packetized
+image methods. In case of monolithic the driver allocates a contiguous chunk
of physical pages having the BIOS image. In case of packetized the app
using the driver breaks the image in to packets of fixed sizes and the driver
would place each packet in contiguous physical memory. The driver also
@@ -41,7 +41,7 @@ The driver supports two types of update mechanism; monolithic and packetized.
These update mechanism depends upon the BIOS currently running on the system.
Most of the Dell systems support a monolithic update where the BIOS image is
copied to a single contiguous block of physical memory.
-In case of packet mechanism the single memory can be broken in smaller chuks
+In case of packet mechanism the single memory can be broken in smaller chunks
of contiguous memory and the BIOS image is scattered in these packets.
By default the driver uses monolithic memory for the update type. This can be
@@ -52,11 +52,11 @@ echo packet > /sys/devices/platform/dell_rbu/image_type
In packet update mode the packet size has to be given before any packets can
be downloaded. It is done as below
echo XXXX > /sys/devices/platform/dell_rbu/packet_size
-In the packet update mechanism, the user neesd to create a new file having
+In the packet update mechanism, the user needs to create a new file having
packets of data arranged back to back. It can be done as follows
The user creates packets header, gets the chunk of the BIOS image and
-placs it next to the packetheader; now, the packetheader + BIOS image chunk
-added to geather should match the specified packet_size. This makes one
+places it next to the packetheader; now, the packetheader + BIOS image chunk
+added together should match the specified packet_size. This makes one
packet, the user needs to create more such packets out of the entire BIOS
image file and then arrange all these packets back to back in to one single
file.
@@ -93,8 +93,8 @@ read back the image downloaded.
NOTE:
This driver requires a patch for firmware_class.c which has the modified
request_firmware_nowait function.
-Also after updating the BIOS image an user mdoe application neeeds to execute
-code which message the BIOS update request to the BIOS. So on the next reboot
-the BIOS knows about the new image downloaded and it updates it self.
-Also don't unload the rbu drive if the image has to be updated.
+Also after updating the BIOS image a user mode application needs to execute
+code which sends the BIOS update request to the BIOS. So on the next reboot
+the BIOS knows about the new image downloaded and it updates itself.
+Also don't unload the rbu driver if the image has to be updated.
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index 66c725f530f3..28c4f79662c2 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -2005,7 +2005,7 @@ Your cooperation is appreciated.
116 char Advanced Linux Sound Driver (ALSA)
116 block MicroMemory battery backed RAM adapter (NVRAM)
- Supports 16 boards, 15 paritions each.
+ Supports 16 boards, 15 partitions each.
Requested by neilb at cse.unsw.edu.au.
0 = /dev/umem/d0 Whole of first board
@@ -2543,6 +2543,9 @@ Your cooperation is appreciated.
64 = /dev/usb/rio500 Diamond Rio 500
65 = /dev/usb/usblcd USBLCD Interface (info@usblcd.de)
66 = /dev/usb/cpad0 Synaptics cPad (mouse/LCD)
+ 67 = /dev/usb/adutux0 1st Ontrak ADU device
+ ...
+ 76 = /dev/usb/adutux10 10th Ontrak ADU device
96 = /dev/usb/hiddev0 1st USB HID device
...
111 = /dev/usb/hiddev15 16th USB HID device
@@ -3091,7 +3094,7 @@ Your cooperation is appreciated.
This major is reserved to assist the expansion to a
larger number space. No device nodes with this major
should ever be created on the filesystem.
- (This is probaly not true anymore, but I'll leave it
+ (This is probably not true anymore, but I'll leave it
for now /Torben)
---LARGE MAJORS!!!!!---
@@ -3202,7 +3205,7 @@ for a session; this includes virtual consoles, serial ports, and
pseudoterminals (PTYs).
All terminal devices share a common set of capabilities known as line
-diciplines; these include the common terminal line dicipline as well
+disciplines; these include the common terminal line discipline as well
as SLIP and PPP modes.
All terminal devices are named similarly; this section explains the
@@ -3282,7 +3285,7 @@ port TTY, for which no alternate device would exist.
Pseudoterminals (PTYs)
Pseudoterminals, or PTYs, are used to create login sessions or provide
-other capabilities requiring a TTY line dicipline (including SLIP or
+other capabilities requiring a TTY line discipline (including SLIP or
PPP capability) to arbitrary data-generation processes. Each PTY has
a master side, named /dev/pty[p-za-e][0-9a-f], and a slave side, named
/dev/tty[p-za-e][0-9a-f]. The kernel arbitrates the use of PTYs by
diff --git a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt
index 2d1d893a5e5d..548505f14aa4 100644
--- a/Documentation/driver-model/class.txt
+++ b/Documentation/driver-model/class.txt
@@ -12,7 +12,7 @@ device. The following device classes have been identified:
Each device class defines a set of semantics and a programming interface
that devices of that class adhere to. Device drivers are the
-implemention of that programming interface for a particular device on
+implementation of that programming interface for a particular device on
a particular bus.
Device classes are agnostic with respect to what bus a device resides
diff --git a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt
index 59806c9761f7..82132169d47a 100644
--- a/Documentation/driver-model/driver.txt
+++ b/Documentation/driver-model/driver.txt
@@ -178,7 +178,7 @@ the driver to that device.
A driver's probe() may return a negative errno value to indicate that
the driver did not bind to this device, in which case it should have
-released all reasources it allocated.
+released all resources it allocated.
int (*remove) (struct device * dev);
diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt
index 2050c9ffc629..07236ed968da 100644
--- a/Documentation/driver-model/overview.txt
+++ b/Documentation/driver-model/overview.txt
@@ -57,7 +57,7 @@ the two.
The PCI bus layer freely accesses the fields of struct device. It knows about
the structure of struct pci_dev, and it should know the structure of struct
-device. Individual PCI device drivers that have been converted the the current
+device. Individual PCI device drivers that have been converted to the current
driver model generally do not and should not touch the fields of struct device,
unless there is a strong compelling reason to do so.
diff --git a/Documentation/dvb/avermedia.txt b/Documentation/dvb/avermedia.txt
index 8bab8461a4af..e44c009ac6c5 100644
--- a/Documentation/dvb/avermedia.txt
+++ b/Documentation/dvb/avermedia.txt
@@ -45,9 +45,9 @@ Assumptions and Introduction
by circuitry on the card and is often presented uncompressed.
For a PAL TV signal encoded at a resolution of 768x576 24-bit
color pixels over 25 frames per second - a fair amount of data
- is generated and must be proceesed by the PC before it can be
+ is generated and must be processed by the PC before it can be
displayed on the video monitor screen. Some Analogue TV cards
- for PC's have onboard MPEG2 encoders which permit the raw
+ for PCs have onboard MPEG2 encoders which permit the raw
digital data stream to be presented to the PC in an encoded
and compressed form - similar to the form that is used in
Digital TV.
diff --git a/Documentation/dvb/cards.txt b/Documentation/dvb/cards.txt
index 9e10092440e1..ca58e339d85f 100644
--- a/Documentation/dvb/cards.txt
+++ b/Documentation/dvb/cards.txt
@@ -5,7 +5,7 @@ Hardware supported by the linuxtv.org DVB drivers
frontends (i.e. tuner / demodulator units) used, usually without
changing the product name, revision number or specs. Some cards
are also available in versions with different frontends for
- DVB-S/DVB-C/DVB-T. Thus the frontend drivers are listed seperately.
+ DVB-S/DVB-C/DVB-T. Thus the frontend drivers are listed separately.
Note 1: There is no guarantee that every frontend driver works
out of the box with every card, because of different wiring.
diff --git a/Documentation/dvb/ci.txt b/Documentation/dvb/ci.txt
index 95f0e73b2135..531239b29082 100644
--- a/Documentation/dvb/ci.txt
+++ b/Documentation/dvb/ci.txt
@@ -32,7 +32,7 @@ This application requires the following to function properly as of now.
descrambler to function,
eg: $ ca_zap channels.conf "TMC"
- (d) Hopeflly Enjoy your favourite subscribed channel as you do with
+ (d) Hopefully enjoy your favourite subscribed channel as you do with
a FTA card.
(3) Currently ca_zap, and dst_test, both are meant for demonstration
@@ -65,7 +65,7 @@ Modules that have been tested by this driver at present are
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With the High Level CI approach any new card with almost any random
architecture can be implemented with this style, the definitions
-insidethe switch statement can be easily adapted for any card, thereby
+inside the switch statement can be easily adapted for any card, thereby
eliminating the need for any additional ioctls.
The disadvantage is that the driver/hardware has to manage the rest. For
diff --git a/Documentation/dvb/faq.txt b/Documentation/dvb/faq.txt
index a42132d60dc8..dbcedf5833ee 100644
--- a/Documentation/dvb/faq.txt
+++ b/Documentation/dvb/faq.txt
@@ -5,7 +5,7 @@ Some very frequently asked questions about linuxtv-dvb
It's not a bug, it's a feature. Because the frontends have
significant power requirements (and hence get very hot), they
are powered down if they are unused (i.e. if the frontend device
- is closed). The dvb-core.o module paramter "dvb_shutdown_timeout"
+ is closed). The dvb-core.o module parameter "dvb_shutdown_timeout"
allow you to change the timeout (default 5 seconds). Setting the
timeout to 0 disables the timeout feature.
@@ -138,7 +138,7 @@ Some very frequently asked questions about linuxtv-dvb
- v4l2-common: common functions for Video4Linux-2 drivers
- - v4l1-compat: backward compatiblity layer for Video4Linux-1 legacy
+ - v4l1-compat: backward compatibility layer for Video4Linux-1 legacy
applications
- dvb-core: DVB core module. This provides you with the
@@ -153,7 +153,7 @@ Some very frequently asked questions about linuxtv-dvb
- video-buf: capture helper module for the saa7146_vv driver. This
one is responsible to handle capture buffers.
- - dvb-ttpci: The main driver for AV7110 based, full-featued
+ - dvb-ttpci: The main driver for AV7110 based, full-featured
DVB-S/C/T cards
eof
diff --git a/Documentation/ecryptfs.txt b/Documentation/ecryptfs.txt
new file mode 100644
index 000000000000..01d8a08351ac
--- /dev/null
+++ b/Documentation/ecryptfs.txt
@@ -0,0 +1,77 @@
+eCryptfs: A stacked cryptographic filesystem for Linux
+
+eCryptfs is free software. Please see the file COPYING for details.
+For documentation, please see the files in the doc/ subdirectory. For
+building and installation instructions please see the INSTALL file.
+
+Maintainer: Phillip Hellewell
+Lead developer: Michael A. Halcrow <mhalcrow@us.ibm.com>
+Developers: Michael C. Thompson
+ Kent Yoder
+Web Site: http://ecryptfs.sf.net
+
+This software is currently undergoing development. Make sure to
+maintain a backup copy of any data you write into eCryptfs.
+
+eCryptfs requires the userspace tools downloadable from the
+SourceForge site:
+
+http://sourceforge.net/projects/ecryptfs/
+
+Userspace requirements include:
+ - David Howells' userspace keyring headers and libraries (version
+ 1.0 or higher), obtainable from
+ http://people.redhat.com/~dhowells/keyutils/
+ - Libgcrypt
+
+
+NOTES
+
+In the beta/experimental releases of eCryptfs, when you upgrade
+eCryptfs, you should copy the files to an unencrypted location and
+then copy the files back into the new eCryptfs mount to migrate the
+files.
+
+
+MOUNT-WIDE PASSPHRASE
+
+Create a new directory into which eCryptfs will write its encrypted
+files (i.e., /root/crypt). Then, create the mount point directory
+(i.e., /mnt/crypt). Now it's time to mount eCryptfs:
+
+mount -t ecryptfs /root/crypt /mnt/crypt
+
+You should be prompted for a passphrase and a salt (the salt may be
+blank).
+
+Try writing a new file:
+
+echo "Hello, World" > /mnt/crypt/hello.txt
+
+The operation will complete. Notice that there is a new file in
+/root/crypt that is at least 12288 bytes in size (depending on your
+host page size). This is the encrypted underlying file for what you
+just wrote. To test reading, from start to finish, you need to clear
+the user session keyring:
+
+keyctl clear @u
+
+Then umount /mnt/crypt and mount again per the instructions given
+above.
+
+cat /mnt/crypt/hello.txt
+
+
+NOTES
+
+eCryptfs version 0.1 should only be mounted on (1) empty directories
+or (2) directories containing files only created by eCryptfs. If you
+mount a directory that has pre-existing files not created by eCryptfs,
+then behavior is undefined. Do not run eCryptfs in higher verbosity
+levels unless you are doing so for the sole purpose of debugging or
+development, since secret values will be written out to the system log
+in that case.
+
+
+Mike Halcrow
+mhalcrow@us.ibm.com
diff --git a/Documentation/eisa.txt b/Documentation/eisa.txt
index 8c8388da868a..6a099edadd62 100644
--- a/Documentation/eisa.txt
+++ b/Documentation/eisa.txt
@@ -18,7 +18,7 @@ The EISA infrastructure is made up of three parts :
- The bus code implements most of the generic code. It is shared
among all the architectures that the EISA code runs on. It
- implements bus probing (detecting EISA cards avaible on the bus),
+ implements bus probing (detecting EISA cards available on the bus),
allocates I/O resources, allows fancy naming through sysfs, and
offers interfaces for driver to register.
@@ -84,7 +84,7 @@ struct eisa_driver {
id_table : an array of NULL terminated EISA id strings,
followed by an empty string. Each string can
- optionnaly be paired with a driver-dependant value
+ optionally be paired with a driver-dependant value
(driver_data).
driver : a generic driver, such as described in
diff --git a/Documentation/exception.txt b/Documentation/exception.txt
index 3cb39ade290e..2d5aded64247 100644
--- a/Documentation/exception.txt
+++ b/Documentation/exception.txt
@@ -10,7 +10,7 @@ int verify_area(int type, const void * addr, unsigned long size)
function (which has since been replaced by access_ok()).
This function verified that the memory area starting at address
-addr and of size size was accessible for the operation specified
+'addr' and of size 'size' was accessible for the operation specified
in type (read or write). To do this, verify_read had to look up the
virtual memory area (vma) that contained the address addr. In the
normal case (correctly working program), this test was successful.
diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt
index f373df12ed4c..99ea58e65eff 100644
--- a/Documentation/fb/fbcon.txt
+++ b/Documentation/fb/fbcon.txt
@@ -163,7 +163,7 @@ from the console layer before unloading the driver. The VGA driver cannot be
unloaded if it is still bound to the console layer. (See
Documentation/console/console.txt for more information).
-This is more complicated in the case of the the framebuffer console (fbcon),
+This is more complicated in the case of the framebuffer console (fbcon),
because fbcon is an intermediate layer between the console and the drivers:
console ---> fbcon ---> fbdev drivers ---> hardware
diff --git a/Documentation/fb/intel810.txt b/Documentation/fb/intel810.txt
index 4f0d6bc789ef..be3e7836abef 100644
--- a/Documentation/fb/intel810.txt
+++ b/Documentation/fb/intel810.txt
@@ -9,8 +9,9 @@ Intel 810/815 Framebuffer driver
================================================================
A. Introduction
+
This is a framebuffer driver for various Intel 810/815 compatible
-graphics devices. These would include:
+ graphics devices. These include:
Intel 810
Intel 810E
@@ -21,136 +22,136 @@ graphics devices. These would include:
B. Features
- - Choice of using Discrete Video Timings, VESA Generalized Timing
+ - Choice of using Discrete Video Timings, VESA Generalized Timing
Formula, or a framebuffer specific database to set the video mode
- - Supports a variable range of horizontal and vertical resolution, and
- vertical refresh rates if the VESA Generalized Timing Formula is
+ - Supports a variable range of horizontal and vertical resolution and
+ vertical refresh rates if the VESA Generalized Timing Formula is
enabled.
- - Supports color depths of 8, 16, 24 and 32 bits per pixel
+ - Supports color depths of 8, 16, 24 and 32 bits per pixel
- Supports pseudocolor, directcolor, or truecolor visuals
- - Full and optimized hardware acceleration at 8, 16 and 24 bpp
+ - Full and optimized hardware acceleration at 8, 16 and 24 bpp
- Robust video state save and restore
- - MTRR support
+ - MTRR support
- Utilizes user-entered monitor specifications to automatically
calculate required video mode parameters.
- - Can concurrently run with xfree86 running with native i810 drivers
+ - Can concurrently run with xfree86 running with native i810 drivers
- Hardware Cursor Support
- Supports EDID probing either by DDC/I2C or through the BIOS
C. List of available options
-
- a. "video=i810fb"
+
+ a. "video=i810fb"
enables the i810 driver
Recommendation: required
-
- b. "xres:<value>"
+
+ b. "xres:<value>"
select horizontal resolution in pixels. (This parameter will be
ignored if 'mode_option' is specified. See 'o' below).
- Recommendation: user preference
+ Recommendation: user preference
(default = 640)
c. "yres:<value>"
select vertical resolution in scanlines. If Discrete Video Timings
is enabled, this will be ignored and computed as 3*xres/4. (This
parameter will be ignored if 'mode_option' is specified. See 'o'
- below)
+ below)
Recommendation: user preference
(default = 480)
-
- d. "vyres:<value>"
+
+ d. "vyres:<value>"
select virtual vertical resolution in scanlines. If (0) or none
- is specified, this will be computed against maximum available memory.
+ is specified, this will be computed against maximum available memory.
Recommendation: do not set
(default = 480)
e. "vram:<value>"
- select amount of system RAM in MB to allocate for the video memory
+ select amount of system RAM in MB to allocate for the video memory
Recommendation: 1 - 4 MB.
(default = 4)
- f. "bpp:<value>"
- select desired pixel depth
+ f. "bpp:<value>"
+ select desired pixel depth
Recommendation: 8
(default = 8)
- g. "hsync1/hsync2:<value>"
- select the minimum and maximum Horizontal Sync Frequency of the
- monitor in KHz. If a using a fixed frequency monitor, hsync1 must
+ g. "hsync1/hsync2:<value>"
+ select the minimum and maximum Horizontal Sync Frequency of the
+ monitor in kHz. If using a fixed frequency monitor, hsync1 must
be equal to hsync2. If EDID probing is successful, these will be
ignored and values will be taken from the EDID block.
Recommendation: check monitor manual for correct values
- default (29/30)
+ (default = 29/30)
- h. "vsync1/vsync2:<value>"
+ h. "vsync1/vsync2:<value>"
select the minimum and maximum Vertical Sync Frequency of the monitor
- in Hz. You can also use this option to lock your monitor's refresh
+ in Hz. You can also use this option to lock your monitor's refresh
rate. If EDID probing is successful, these will be ignored and values
will be taken from the EDID block.
Recommendation: check monitor manual for correct values
(default = 60/60)
- IMPORTANT: If you need to clamp your timings, try to give some
- leeway for computational errors (over/underflows). Example: if
+ IMPORTANT: If you need to clamp your timings, try to give some
+ leeway for computational errors (over/underflows). Example: if
using vsync1/vsync2 = 60/60, make sure hsync1/hsync2 has at least
a 1 unit difference, and vice versa.
- i. "voffset:<value>"
- select at what offset in MB of the logical memory to allocate the
+ i. "voffset:<value>"
+ select at what offset in MB of the logical memory to allocate the
framebuffer memory. The intent is to avoid the memory blocks
used by standard graphics applications (XFree86). The default
- offset (16 MB for a 64MB aperture, 8 MB for a 32MB aperture) will
- avoid XFree86's usage and allows up to 7MB/15MB of framebuffer
- memory. Depending on your usage, adjust the value up or down,
- (0 for maximum usage, 31/63 MB for the least amount). Note, an
+ offset (16 MB for a 64 MB aperture, 8 MB for a 32 MB aperture) will
+ avoid XFree86's usage and allows up to 7 MB/15 MB of framebuffer
+ memory. Depending on your usage, adjust the value up or down
+ (0 for maximum usage, 31/63 MB for the least amount). Note, an
arbitrary setting may conflict with XFree86.
Recommendation: do not set
(default = 8 or 16 MB)
-
- j. "accel"
- enable text acceleration. This can be enabled/reenabled anytime
- by using 'fbset -accel true/false'.
+
+ j. "accel"
+ enable text acceleration. This can be enabled/reenabled anytime
+ by using 'fbset -accel true/false'.
Recommendation: enable
- (default = not set)
+ (default = not set)
- k. "mtrr"
+ k. "mtrr"
enable MTRR. This allows data transfers to the framebuffer memory
to occur in bursts which can significantly increase performance.
- Not very helpful with the i810/i815 because of 'shared memory'.
+ Not very helpful with the i810/i815 because of 'shared memory'.
Recommendation: do not set
- (default = not set)
+ (default = not set)
l. "extvga"
if specified, secondary/external VGA output will always be enabled.
Useful if the BIOS turns off the VGA port when no monitor is attached.
- The external VGA monitor can then be attached without rebooting.
+ The external VGA monitor can then be attached without rebooting.
Recommendation: do not set
(default = not set)
-
- m. "sync"
+
+ m. "sync"
Forces the hardware engine to do a "sync" or wait for the hardware
- to finish before starting another instruction. This will produce a
+ to finish before starting another instruction. This will produce a
more stable setup, but will be slower.
Recommendation: do not set
@@ -162,6 +163,7 @@ C. List of available options
Recommendation: do not set
(default = not set)
+
o. <xres>x<yres>[-<bpp>][@<refresh>]
The driver will now accept specification of boot mode option. If this
is specified, the options 'xres' and 'yres' will be ignored. See
@@ -183,8 +185,8 @@ append="video=i810fb:vram:2,xres:1024,yres:768,bpp:8,hsync1:30,hsync2:55, \
vsync1:50,vsync2:85,accel,mtrr"
This will initialize the framebuffer to 1024x768 at 8bpp. The framebuffer
-will use 2 MB of System RAM. MTRR support will be enabled. The refresh rate
-will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
+will use 2 MB of System RAM. MTRR support will be enabled. The refresh rate
+will be computed based on the hsync1/hsync2 and vsync1/vsync2 values.
IMPORTANT:
You must include hsync1, hsync2, vsync1 and vsync2 to enable video modes
@@ -194,10 +196,10 @@ vsync1 and vsync2 parameters. These parameters will be taken from the EDID
block.
E. Module options
-
- The module parameters are essentially similar to the kernel
-parameters. The main difference is that you need to include a Boolean value
-(1 for TRUE, and 0 for FALSE) for those options which don't need a value.
+
+The module parameters are essentially similar to the kernel
+parameters. The main difference is that you need to include a Boolean value
+(1 for TRUE, and 0 for FALSE) for those options which don't need a value.
Example, to enable MTRR, include "mtrr=1".
@@ -214,62 +216,62 @@ Or just add the following to /etc/modprobe.conf
options i810fb vram=2 xres=1024 bpp=16 hsync1=30 hsync2=55 vsync1=50 \
vsync2=85 accel=1 mtrr=1
-and just do a
+and just do a
modprobe i810fb
F. Setup
- a. Do your usual method of configuring the kernel.
-
+ a. Do your usual method of configuring the kernel.
+
make menuconfig/xconfig/config
- b. Under "Code Maturity Options", enable "Prompt for experimental/
- incomplete code/drivers".
+ b. Under "Code maturity level options" enable "Prompt for development
+ and/or incomplete code/drivers".
c. Enable agpgart support for the Intel 810/815 on-board graphics.
- This is required. The option is under "Character Devices"
+ This is required. The option is under "Character Devices".
d. Under "Graphics Support", select "Intel 810/815" either statically
or as a module. Choose "use VESA Generalized Timing Formula" if
- you need to maximize the capability of your display. To be on the
- safe side, you can leave this unselected.
-
+ you need to maximize the capability of your display. To be on the
+ safe side, you can leave this unselected.
+
e. If you want support for DDC/I2C probing (Plug and Play Displays),
set 'Enable DDC Support' to 'y'. To make this option appear, set
'use VESA Generalized Timing Formula' to 'y'.
- f. If you want a framebuffer console, enable it under "Console
- Drivers"
+ f. If you want a framebuffer console, enable it under "Console
+ Drivers".
+
+ g. Compile your kernel.
+
+ h. Load the driver as described in sections D and E.
- g. Compile your kernel.
-
- h. Load the driver as described in section D and E.
-
i. Try the DirectFB (http://www.directfb.org) + the i810 gfxdriver
patch to see the chipset in action (or inaction :-).
G. Acknowledgment:
-
+
1. Geert Uytterhoeven - his excellent howto and the virtual
- framebuffer driver code made this possible.
+ framebuffer driver code made this possible.
- 2. Jeff Hartmann for his agpgart code.
+ 2. Jeff Hartmann for his agpgart code.
3. The X developers. Insights were provided just by reading the
XFree86 source code.
4. Intel(c). For this value-oriented chipset driver and for
- providing documentation.
+ providing documentation.
5. Matt Sottek. His inputs and ideas helped in making some
- optimizations possible.
+ optimizations possible.
H. Home Page:
A more complete, and probably updated information is provided at
-http://i810fb.sourceforge.net.
+ http://i810fb.sourceforge.net.
###########################
Tony
diff --git a/Documentation/fb/intelfb.txt b/Documentation/fb/intelfb.txt
index c12d39a23c3d..da5ee74219e8 100644
--- a/Documentation/fb/intelfb.txt
+++ b/Documentation/fb/intelfb.txt
@@ -1,16 +1,19 @@
-Intel 830M/845G/852GM/855GM/865G/915G Framebuffer driver
+Intel 830M/845G/852GM/855GM/865G/915G/945G Framebuffer driver
================================================================
A. Introduction
- This is a framebuffer driver for various Intel 810/815 compatible
+ This is a framebuffer driver for various Intel 8xx/9xx compatible
graphics devices. These would include:
Intel 830M
- Intel 810E845G
+ Intel 845G
Intel 852GM
Intel 855GM
Intel 865G
Intel 915G
+ Intel 915GM
+ Intel 945G
+ Intel 945GM
B. List of available options
@@ -78,19 +81,27 @@ C. Kernel booting
Separate each option/option-pair by commas (,) and the option from its value
with an equals sign (=) as in the following:
-video=i810fb:option1,option2=value2
+video=intelfb:option1,option2=value2
Sample Usage
------------
In /etc/lilo.conf, add the line:
-append="video=intelfb:800x600-32@75,accel,hwcursor,vram=8"
+append="video=intelfb:mode=800x600-32@75,accel,hwcursor,vram=8"
This will initialize the framebuffer to 800x600 at 32bpp and 75Hz. The
framebuffer will use 8 MB of System RAM. hw acceleration of text and cursor
will be enabled.
+Remarks
+-------
+
+If setting this parameter doesn't work (you stay in a 80x25 text-mode),
+you might need to set the "vga=<mode>" parameter too - see vesafb.txt
+in this directory.
+
+
D. Module options
The module parameters are essentially similar to the kernel
diff --git a/Documentation/fb/sisfb.txt b/Documentation/fb/sisfb.txt
index 3b50c517a08d..2e68e503e72f 100644
--- a/Documentation/fb/sisfb.txt
+++ b/Documentation/fb/sisfb.txt
@@ -72,7 +72,7 @@ information. Additionally, "modinfo sisfb" gives an overview over all
supported options including some explanation.
The desired display mode can be specified using the keyword "mode" with
-a parameter in one of the follwing formats:
+a parameter in one of the following formats:
- XxYxDepth or
- XxY-Depth or
- XxY-Depth@Rate or
diff --git a/Documentation/fb/sstfb.txt b/Documentation/fb/sstfb.txt
index 628d7ffa8769..df27f5bf15db 100644
--- a/Documentation/fb/sstfb.txt
+++ b/Documentation/fb/sstfb.txt
@@ -48,12 +48,12 @@ Module Usage
Module insertion:
# insmod sstfb.o
- you should see some strange output frome the board:
+ you should see some strange output from the board:
a big blue square, a green and a red small squares and a vertical
- white rectangle. why ? the function's name is self explanatory :
+ white rectangle. why? the function's name is self-explanatory:
"sstfb_test()"...
(if you don't have a second monitor, you'll have to plug your monitor
- directely to the 2D videocard to see what you're typing)
+ directly to the 2D videocard to see what you're typing)
# con2fb /dev/fbx /dev/ttyx
bind a tty to the new frame buffer. if you already have a frame
buffer driver, the voodoo fb will likely be /dev/fb1. if not,
@@ -72,12 +72,12 @@ Module Usage
Kernel/Modules Options
- You can pass some otions to sstfb module, and via the kernel command
- line when the driver is compiled in :
+ You can pass some options to the sstfb module, and via the kernel
+ command line when the driver is compiled in:
for module : insmod sstfb.o option1=value1 option2=value2 ...
in kernel : video=sstfb:option1,option2:value2,option3 ...
- sstfb supports the folowing options :
+ sstfb supports the following options :
Module Kernel Description
@@ -95,11 +95,11 @@ inverse=1 inverse Supposed to enable inverse console.
clipping=1 clipping Enable or disable clipping.
clipping=0 noclipping With clipping enabled, all offscreen
- reads and writes are disgarded.
+ reads and writes are discarded.
Default: enable clipping.
gfxclk=x gfxclk:x Force graphic clock frequency (in MHz).
- Be carefull with this option, it may be
+ Be careful with this option, it may be
DANGEROUS.
Default: auto
50Mhz for Voodoo 1,
@@ -137,23 +137,23 @@ Bugs
- The driver is 16 bpp only, 24/32 won't work.
- The driver is not your_favorite_toy-safe. this includes SMP...
[Actually from inspection it seems to be safe - Alan]
- - when using XFree86 FBdev (X over fbdev) you may see strange color
+ - When using XFree86 FBdev (X over fbdev) you may see strange color
patterns at the border of your windows (the pixels lose the lowest
- byte -> basicaly the blue component nd some of the green) . I'm unable
+ byte -> basically the blue component and some of the green). I'm unable
to reproduce this with XFree86-3.3, but one of the testers has this
- problem with XFree86-4. apparently recent Xfree86-4.x solve this
+ problem with XFree86-4. Apparently recent Xfree86-4.x solve this
problem.
- I didn't really test changing the palette, so you may find some weird
things when playing with that.
- - Sometimes the driver will not recognise the DAC , and the
- initialisation will fail. this is specificaly true for
- voodoo 2 boards , but it should be solved in recent versions. please
- contact me .
- - the 24/32 is not likely to work anytime soon , knowing that the
- hardware does ... unusual thigs in 24/32 bpp
- - When used with anther video board, current limitations of linux
- console subsystem can cause some troubles, specificaly, you should
- disable software scrollback , as it can oops badly ...
+ - Sometimes the driver will not recognise the DAC, and the
+ initialisation will fail. This is specifically true for
+ voodoo 2 boards, but it should be solved in recent versions. Please
+ contact me.
+ - The 24/32 is not likely to work anytime soon, knowing that the
+ hardware does ... unusual things in 24/32 bpp.
+ - When used with another video board, current limitations of the linux
+ console subsystem can cause some troubles, specifically, you should
+ disable software scrollback, as it can oops badly ...
Todo
@@ -161,7 +161,7 @@ Todo
- Buy more coffee.
- test/port to other arch.
- try to add panning using tweeks with front and back buffer .
- - try to implement accel on voodoo2 , this board can actualy do a
+ - try to implement accel on voodoo2, this board can actually do a
lot in 2D even if it was sold as a 3D only board ...
ghoz.
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 611acc32fdf5..1ac3c74646e3 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -29,14 +29,6 @@ Who: Adrian Bunk <bunk@stusta.de>
---------------------------
-What: drivers that were depending on OBSOLETE_OSS_DRIVER
- (config options already removed)
-When: before 2.6.19
-Why: OSS drivers with ALSA replacements
-Who: Adrian Bunk <bunk@stusta.de>
-
----------------------------
-
What: raw1394: requests of type RAW1394_REQ_ISO_SEND, RAW1394_REQ_ISO_LISTEN
When: November 2006
Why: Deprecated in favour of the new ioctl-based rawiso interface, which is
@@ -46,17 +38,8 @@ Who: Jody McIntyre <scjody@modernduck.com>
---------------------------
-What: sbp2: module parameter "force_inquiry_hack"
-When: July 2006
-Why: Superceded by parameter "workarounds". Both parameters are meant to be
- used ad-hoc and for single devices only, i.e. not in modprobe.conf,
- therefore the impact of this feature replacement should be low.
-Who: Stefan Richter <stefanr@s5r6.in-berlin.de>
-
----------------------------
-
What: Video4Linux API 1 ioctls and video_decoder.h from Video devices.
-When: July 2006
+When: December 2006
Why: V4L1 AP1 was replaced by V4L2 API. during migration from 2.4 to 2.6
series. The old API have lots of drawbacks and don't provide enough
means to work with all video and audio standards. The newer API is
@@ -70,6 +53,18 @@ Who: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
---------------------------
+What: sys_sysctl
+When: January 2007
+Why: The same information is available through /proc/sys and that is the
+ interface user space prefers to use. And there do not appear to be
+ any existing user in user space of sys_sysctl. The additional
+ maintenance overhead of keeping a set of binary names gets
+ in the way of doing a good job of maintaining this interface.
+
+Who: Eric Biederman <ebiederm@xmission.com>
+
+---------------------------
+
What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
When: November 2005
Files: drivers/pcmcia/: pcmcia_ioctl.c
@@ -119,15 +114,6 @@ Who: Arjan van de Ven
---------------------------
-What: START_ARRAY ioctl for md
-When: July 2006
-Files: drivers/md/md.c
-Why: Not reliable by design - can fail when most needed.
- Alternatives exist
-Who: NeilBrown <neilb@suse.de>
-
----------------------------
-
What: eepro100 network driver
When: January 2007
Why: replaced by the e100 driver
@@ -190,7 +176,7 @@ Who: Greg Kroah-Hartman <gregkh@suse.de>
---------------------------
What: USB driver API moves to EXPORT_SYMBOL_GPL
-When: Febuary 2008
+When: February 2008
Files: include/linux/usb.h, drivers/usb/core/driver.c
Why: The USB subsystem has changed a lot over time, and it has been
possible to create userspace USB drivers using usbfs/libusb/gadgetfs
@@ -217,50 +203,6 @@ Who: Nick Piggin <npiggin@suse.de>
---------------------------
-What: Support for the MIPS EV96100 evaluation board
-When: September 2006
-Why: Does no longer build since at least November 15, 2003, apparently
- no userbase left.
-Who: Ralf Baechle <ralf@linux-mips.org>
-
----------------------------
-
-What: Support for the Momentum / PMC-Sierra Jaguar ATX evaluation board
-When: September 2006
-Why: Does no longer build since quite some time, and was never popular,
- due to the platform being replaced by successor models. Apparently
- no user base left. It also is one of the last users of
- WANT_PAGE_VIRTUAL.
-Who: Ralf Baechle <ralf@linux-mips.org>
-
----------------------------
-
-What: Support for the Momentum Ocelot, Ocelot 3, Ocelot C and Ocelot G
-When: September 2006
-Why: Some do no longer build and apparently there is no user base left
- for these platforms.
-Who: Ralf Baechle <ralf@linux-mips.org>
-
----------------------------
-
-What: Support for MIPS Technologies' Altas and SEAD evaluation board
-When: September 2006
-Why: Some do no longer build and apparently there is no user base left
- for these platforms. Hardware out of production since several years.
-Who: Ralf Baechle <ralf@linux-mips.org>
-
----------------------------
-
-What: Support for the IT8172-based platforms, ITE 8172G and Globespan IVR
-When: September 2006
-Why: Code does no longer build since at least 2.6.0, apparently there is
- no user base left for these platforms. Hardware out of production
- since several years and hardly a trace of the manufacturer left on
- the net.
-Who: Ralf Baechle <ralf@linux-mips.org>
-
----------------------------
-
What: Interrupt only SA_* flags
When: Januar 2007
Why: The interrupt related SA_* flags are replaced by IRQF_* to move them
@@ -313,7 +255,7 @@ Who: Stephen Hemminger <shemminger@osdl.org>
What: PHYSDEVPATH, PHYSDEVBUS, PHYSDEVDRIVER in the uevent environment
-When: Oktober 2008
+When: October 2008
Why: The stacking of class devices makes these values misleading and
inconsistent.
Class devices should not carry any of these properties, and bus
@@ -321,3 +263,20 @@ Why: The stacking of class devices makes these values misleading and
Who: Kay Sievers <kay.sievers@suse.de>
---------------------------
+
+What: i2c-isa
+When: December 2006
+Why: i2c-isa is a non-sense and doesn't fit in the device driver
+ model. Drivers relying on it are better implemented as platform
+ drivers.
+Who: Jean Delvare <khali@linux-fr.org>
+
+---------------------------
+
+What: ftape
+When: 2.6.20
+Why: Orphaned for ages. SMP bugs long unfixed. Few users left
+ in the world.
+Who: Jeff Garzik <jeff@garzik.org>
+
+---------------------------
diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX
index 16dec61d7671..4dc28cc93503 100644
--- a/Documentation/filesystems/00-INDEX
+++ b/Documentation/filesystems/00-INDEX
@@ -26,8 +26,6 @@ cramfs.txt
- info on the cram filesystem for small storage (ROMs etc).
dentry-locking.txt
- info on the RCU-based dcache locking model.
-devfs/
- - directory containing devfs documentation.
directory-locking
- info about the locking scheme used for directory operations.
dlmfs.txt
@@ -36,6 +34,8 @@ ext2.txt
- info, mount options and specifications for the Ext2 filesystem.
ext3.txt
- info, mount options and specifications for the Ext3 filesystem.
+ext4.txt
+ - info, mount options and specifications for the Ext4 filesystem.
files.txt
- info on file management in the Linux kernel.
fuse.txt
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 247d7f619aa2..eb1a6cad21e6 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -356,10 +356,9 @@ The last two are called only from check_disk_change().
prototypes:
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
- ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t,
- loff_t);
+ ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int,
diff --git a/Documentation/filesystems/befs.txt b/Documentation/filesystems/befs.txt
index 877a7b1d46ec..67391a15949a 100644
--- a/Documentation/filesystems/befs.txt
+++ b/Documentation/filesystems/befs.txt
@@ -7,7 +7,7 @@ WARNING
Make sure you understand that this is alpha software. This means that the
implementation is neither complete nor well-tested.
-I DISCLAIM ALL RESPONSIBILTY FOR ANY POSSIBLE BAD EFFECTS OF THIS CODE!
+I DISCLAIM ALL RESPONSIBILITY FOR ANY POSSIBLE BAD EFFECTS OF THIS CODE!
LICENSE
=====
@@ -22,7 +22,7 @@ He has been working on the code since Aug 13, 2001. See the changelog for
details.
Original Author: Makoto Kato <m_kato@ga2.so-net.ne.jp>
-His orriginal code can still be found at:
+His original code can still be found at:
<http://hp.vector.co.jp/authors/VA008030/bfs/>
Does anyone know of a more current email address for Makoto? He doesn't
respond to the address given above...
@@ -39,7 +39,7 @@ Which is it, BFS or BEFS?
================
Be, Inc said, "BeOS Filesystem is officially called BFS, not BeFS".
But Unixware Boot Filesystem is called bfs, too. And they are already in
-the kernel. Because of this nameing conflict, on Linux the BeOS
+the kernel. Because of this naming conflict, on Linux the BeOS
filesystem is called befs.
HOW TO INSTALL
@@ -57,7 +57,7 @@ if the patching step fails (i.e. there are rejected hunks), you can try to
figure it out yourself (it shouldn't be hard), or mail the maintainer
(Will Dyson <will_dyson@pobox.com>) for help.
-step 2. Configuretion & make kernel
+step 2. Configuration & make kernel
The linux kernel has many compile-time options. Most of them are beyond the
scope of this document. I suggest the Kernel-HOWTO document as a good general
diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt
index c4ff96b7c4e0..c3a7afb5eabf 100644
--- a/Documentation/filesystems/configfs/configfs.txt
+++ b/Documentation/filesystems/configfs/configfs.txt
@@ -1,5 +1,5 @@
-configfs - Userspace-driven kernel object configuation.
+configfs - Userspace-driven kernel object configuration.
Joel Becker <joel.becker@oracle.com>
@@ -254,7 +254,7 @@ using the group _init() functions on the group.
Finally, when userspace calls rmdir(2) on the item or group,
ct_group_ops->drop_item() is called. As a config_group is also a
-config_item, it is not necessary for a seperate drop_group() method.
+config_item, it is not necessary for a separate drop_group() method.
The subsystem must config_item_put() the reference that was initialized
upon item allocation. If a subsystem has no work to do, it may omit
the ct_group_ops->drop_item() method, and configfs will call
@@ -406,7 +406,7 @@ that condition is met.
Far better would be an explicit action notifying the subsystem that the
config_item is ready to go. More importantly, an explicit action allows
-the subsystem to provide feedback as to whether the attibutes are
+the subsystem to provide feedback as to whether the attributes are
initialized in a way that makes sense. configfs provides this as
committable items.
@@ -422,7 +422,7 @@ support mkdir(2) or rmdir(2) either. It only allows rename(2). The
"pending" directory does allow mkdir(2) and rmdir(2). An item is
created in the "pending" directory. Its attributes can be modified at
will. Userspace commits the item by renaming it into the "live"
-directory. At this point, the subsystem recieves the ->commit_item()
+directory. At this point, the subsystem receives the ->commit_item()
callback. If all required attributes are filled to satisfaction, the
method returns zero and the item is moved to the "live" directory.
diff --git a/Documentation/filesystems/directory-locking b/Documentation/filesystems/directory-locking
index 34380d4fbce3..d7099a9266fb 100644
--- a/Documentation/filesystems/directory-locking
+++ b/Documentation/filesystems/directory-locking
@@ -82,7 +82,7 @@ own descendent. Moreover, there is exactly one cross-directory rename
Consider the object blocking the cross-directory rename. One
of its descendents is locked by cross-directory rename (otherwise we
-would again have an infinite set of of contended objects). But that
+would again have an infinite set of contended objects). But that
means that cross-directory rename is taking locks out of order. Due
to (2) the order hadn't changed since we had acquired filesystem lock.
But locking rules for cross-directory rename guarantee that we do not
diff --git a/Documentation/filesystems/dlmfs.txt b/Documentation/filesystems/dlmfs.txt
index 9afab845a906..c50bbb2d52b4 100644
--- a/Documentation/filesystems/dlmfs.txt
+++ b/Documentation/filesystems/dlmfs.txt
@@ -68,7 +68,7 @@ request for an already acquired lock will not generate another DLM
call. Userspace programs are assumed to handle their own local
locking.
-Two levels of locks are supported - Shared Read, and Exlcusive.
+Two levels of locks are supported - Shared Read, and Exclusive.
Also supported is a Trylock operation.
For information on the libo2dlm interface, please see o2dlm.h,
diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
index 3dd2872416a1..4333e836c495 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -205,7 +205,7 @@ Reserved Space
In ext2, there is a mechanism for reserving a certain number of blocks
for a particular user (normally the super-user). This is intended to
-allow for the system to continue functioning even if non-priveleged users
+allow for the system to continue functioning even if non-privileged users
fill up all the space available to them (this is independent of filesystem
quotas). It also keeps the filesystem from filling up entirely which
helps combat fragmentation.
diff --git a/Documentation/filesystems/ext4.txt b/Documentation/filesystems/ext4.txt
new file mode 100644
index 000000000000..6a4adcae9f9a
--- /dev/null
+++ b/Documentation/filesystems/ext4.txt
@@ -0,0 +1,236 @@
+
+Ext4 Filesystem
+===============
+
+This is a development version of the ext4 filesystem, an advanced level
+of the ext3 filesystem which incorporates scalability and reliability
+enhancements for supporting large filesystems (64 bit) in keeping with
+increasing disk capacities and state-of-the-art feature requirements.
+
+Mailing list: linux-ext4@vger.kernel.org
+
+
+1. Quick usage instructions:
+===========================
+
+ - Grab updated e2fsprogs from
+ ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs-interim/
+ This is a patchset on top of e2fsprogs-1.39, which can be found at
+ ftp://ftp.kernel.org/pub/linux/kernel/people/tytso/e2fsprogs/
+
+ - It's still mke2fs -j /dev/hda1
+
+ - mount /dev/hda1 /wherever -t ext4dev
+
+ - To enable extents,
+
+ mount /dev/hda1 /wherever -t ext4dev -o extents
+
+ - The filesystem is compatible with the ext3 driver until you add a file
+ which has extents (ie: `mount -o extents', then create a file).
+
+ NOTE: The "extents" mount flag is temporary. It will soon go away and
+ extents will be enabled by the "-o extents" flag to mke2fs or tune2fs
+
+ - When comparing performance with other filesystems, remember that
+ ext3/4 by default offers higher data integrity guarantees than most. So
+ when comparing with a metadata-only journalling filesystem, use `mount -o
+ data=writeback'. And you might as well use `mount -o nobh' too along
+ with it. Making the journal larger than the mke2fs default often helps
+ performance with metadata-intensive workloads.
+
+2. Features
+===========
+
+2.1 Currently available
+
+* ability to use filesystems > 16TB
+* extent format reduces metadata overhead (RAM, IO for access, transactions)
+* extent format more robust in face of on-disk corruption due to magics,
+* internal redunancy in tree
+
+2.1 Previously available, soon to be enabled by default by "mkefs.ext4":
+
+* dir_index and resize inode will be on by default
+* large inodes will be used by default for fast EAs, nsec timestamps, etc
+
+2.2 Candidate features for future inclusion
+
+There are several under discussion, whether they all make it in is
+partly a function of how much time everyone has to work on them:
+
+* improved file allocation (multi-block alloc, delayed alloc; basically done)
+* fix 32000 subdirectory limit (patch exists, needs some e2fsck work)
+* nsec timestamps for mtime, atime, ctime, create time (patch exists,
+ needs some e2fsck work)
+* inode version field on disk (NFSv4, Lustre; prototype exists)
+* reduced mke2fs/e2fsck time via uninitialized groups (prototype exists)
+* journal checksumming for robustness, performance (prototype exists)
+* persistent file preallocation (e.g for streaming media, databases)
+
+Features like metadata checksumming have been discussed and planned for
+a bit but no patches exist yet so I'm not sure they're in the near-term
+roadmap.
+
+The big performance win will come with mballoc and delalloc. CFS has
+been using mballoc for a few years already with Lustre, and IBM + Bull
+did a lot of benchmarking on it. The reason it isn't in the first set of
+patches is partly a manageability issue, and partly because it doesn't
+directly affect the on-disk format (outside of much better allocation)
+so it isn't critical to get into the first round of changes. I believe
+Alex is working on a new set of patches right now.
+
+3. Options
+==========
+
+When mounting an ext4 filesystem, the following option are accepted:
+(*) == default
+
+extents ext4 will use extents to address file data. The
+ file system will no longer be mountable by ext3.
+
+journal=update Update the ext4 file system's journal to the current
+ format.
+
+journal=inum When a journal already exists, this option is ignored.
+ Otherwise, it specifies the number of the inode which
+ will represent the ext4 file system's journal file.
+
+journal_dev=devnum When the external journal device's major/minor numbers
+ have changed, this option allows the user to specify
+ the new journal location. The journal device is
+ identified through its new major/minor numbers encoded
+ in devnum.
+
+noload Don't load the journal on mounting.
+
+data=journal All data are committed into the journal prior to being
+ written into the main file system.
+
+data=ordered (*) All data are forced directly out to the main file
+ system prior to its metadata being committed to the
+ journal.
+
+data=writeback Data ordering is not preserved, data may be written
+ into the main file system after its metadata has been
+ committed to the journal.
+
+commit=nrsec (*) Ext4 can be told to sync all its data and metadata
+ every 'nrsec' seconds. The default value is 5 seconds.
+ This means that if you lose your power, you will lose
+ as much as the latest 5 seconds of work (your
+ filesystem will not be damaged though, thanks to the
+ journaling). This default value (or any low value)
+ will hurt performance, but it's good for data-safety.
+ Setting it to 0 will have the same effect as leaving
+ it at the default (5 seconds).
+ Setting it to very large values will improve
+ performance.
+
+barrier=1 This enables/disables barriers. barrier=0 disables
+ it, barrier=1 enables it.
+
+orlov (*) This enables the new Orlov block allocator. It is
+ enabled by default.
+
+oldalloc This disables the Orlov block allocator and enables
+ the old block allocator. Orlov should have better
+ performance - we'd like to get some feedback if it's
+ the contrary for you.
+
+user_xattr Enables Extended User Attributes. Additionally, you
+ need to have extended attribute support enabled in the
+ kernel configuration (CONFIG_EXT4_FS_XATTR). See the
+ attr(5) manual page and http://acl.bestbits.at/ to
+ learn more about extended attributes.
+
+nouser_xattr Disables Extended User Attributes.
+
+acl Enables POSIX Access Control Lists support.
+ Additionally, you need to have ACL support enabled in
+ the kernel configuration (CONFIG_EXT4_FS_POSIX_ACL).
+ See the acl(5) manual page and http://acl.bestbits.at/
+ for more information.
+
+noacl This option disables POSIX Access Control List
+ support.
+
+reservation
+
+noreservation
+
+bsddf (*) Make 'df' act like BSD.
+minixdf Make 'df' act like Minix.
+
+check=none Don't do extra checking of bitmaps on mount.
+nocheck
+
+debug Extra debugging information is sent to syslog.
+
+errors=remount-ro(*) Remount the filesystem read-only on an error.
+errors=continue Keep going on a filesystem error.
+errors=panic Panic and halt the machine if an error occurs.
+
+grpid Give objects the same group ID as their creator.
+bsdgroups
+
+nogrpid (*) New objects have the group ID of their creator.
+sysvgroups
+
+resgid=n The group ID which may use the reserved blocks.
+
+resuid=n The user ID which may use the reserved blocks.
+
+sb=n Use alternate superblock at this location.
+
+quota
+noquota
+grpquota
+usrquota
+
+bh (*) ext4 associates buffer heads to data pages to
+nobh (a) cache disk block mapping information
+ (b) link pages into transaction to provide
+ ordering guarantees.
+ "bh" option forces use of buffer heads.
+ "nobh" option tries to avoid associating buffer
+ heads (supported only for "writeback" mode).
+
+
+Data Mode
+---------
+There are 3 different data modes:
+
+* writeback mode
+In data=writeback mode, ext4 does not journal data at all. This mode provides
+a similar level of journaling as that of XFS, JFS, and ReiserFS in its default
+mode - metadata journaling. A crash+recovery can cause incorrect data to
+appear in files which were written shortly before the crash. This mode will
+typically provide the best ext4 performance.
+
+* ordered mode
+In data=ordered mode, ext4 only officially journals metadata, but it logically
+groups metadata and data blocks into a single unit called a transaction. When
+it's time to write the new metadata out to disk, the associated data blocks
+are written first. In general, this mode performs slightly slower than
+writeback but significantly faster than journal mode.
+
+* journal mode
+data=journal mode provides full data and metadata journaling. All new data is
+written to the journal first, and then to its final location.
+In the event of a crash, the journal can be replayed, bringing both data and
+metadata into a consistent state. This mode is the slowest except when data
+needs to be read from and written to disk at the same time where it
+outperforms all others modes.
+
+References
+==========
+
+kernel source: <file:fs/ext4/>
+ <file:fs/jbd2/>
+
+programs: http://e2fsprogs.sourceforge.net/
+ http://ext2resize.sourceforge.net
+
+useful links: http://fedoraproject.org/wiki/ext3-devel
+ http://www.bullopensource.org/ext4/
diff --git a/Documentation/filesystems/files.txt b/Documentation/filesystems/files.txt
index 8c206f4e0250..133e213ebb72 100644
--- a/Documentation/filesystems/files.txt
+++ b/Documentation/filesystems/files.txt
@@ -55,7 +55,7 @@ the fdtable structure -
2. Reading of the fdtable as described above must be protected
by rcu_read_lock()/rcu_read_unlock().
-3. For any update to the the fd table, files->file_lock must
+3. For any update to the fd table, files->file_lock must
be held.
4. To look up the file structure given an fd, a reader
diff --git a/Documentation/filesystems/gfs2.txt b/Documentation/filesystems/gfs2.txt
new file mode 100644
index 000000000000..593004b6bbab
--- /dev/null
+++ b/Documentation/filesystems/gfs2.txt
@@ -0,0 +1,43 @@
+Global File System
+------------------
+
+http://sources.redhat.com/cluster/
+
+GFS is a cluster file system. It allows a cluster of computers to
+simultaneously use a block device that is shared between them (with FC,
+iSCSI, NBD, etc). GFS reads and writes to the block device like a local
+file system, but also uses a lock module to allow the computers coordinate
+their I/O so file system consistency is maintained. One of the nifty
+features of GFS is perfect consistency -- changes made to the file system
+on one machine show up immediately on all other machines in the cluster.
+
+GFS uses interchangable inter-node locking mechanisms. Different lock
+modules can plug into GFS and each file system selects the appropriate
+lock module at mount time. Lock modules include:
+
+ lock_nolock -- allows gfs to be used as a local file system
+
+ lock_dlm -- uses a distributed lock manager (dlm) for inter-node locking
+ The dlm is found at linux/fs/dlm/
+
+In addition to interfacing with an external locking manager, a gfs lock
+module is responsible for interacting with external cluster management
+systems. Lock_dlm depends on user space cluster management systems found
+at the URL above.
+
+To use gfs as a local file system, no external clustering systems are
+needed, simply:
+
+ $ mkfs -t gfs2 -p lock_nolock -j 1 /dev/block_device
+ $ mount -t gfs2 /dev/block_device /dir
+
+GFS2 is not on-disk compatible with previous versions of GFS.
+
+The following man pages can be found at the URL above:
+ gfs2_fsck to repair a filesystem
+ gfs2_grow to expand a filesystem online
+ gfs2_jadd to add journals to a filesystem online
+ gfs2_tool to manipulate, examine and tune a filesystem
+ gfs2_quota to examine and change quota values in a filesystem
+ mount.gfs2 to help mount(8) mount a filesystem
+ mkfs.gfs2 to make a filesystem
diff --git a/Documentation/filesystems/ntfs.txt b/Documentation/filesystems/ntfs.txt
index 638cbd3d2b00..35f105b29e3e 100644
--- a/Documentation/filesystems/ntfs.txt
+++ b/Documentation/filesystems/ntfs.txt
@@ -13,7 +13,7 @@ Table of contents
- Using NTFS volume and stripe sets
- The Device-Mapper driver
- The Software RAID / MD driver
- - Limitiations when using the MD driver
+ - Limitations when using the MD driver
- ChangeLog
@@ -43,7 +43,7 @@ There is plenty of additional information on the linux-ntfs web site
at http://linux-ntfs.sourceforge.net/
The web site has a lot of additional information, such as a comprehensive
-FAQ, documentation on the NTFS on-disk format, informaiton on the Linux-NTFS
+FAQ, documentation on the NTFS on-disk format, information on the Linux-NTFS
userspace utilities, etc.
@@ -383,14 +383,14 @@ Software RAID / MD driver. For which you need to set up your /etc/raidtab
appropriately (see man 5 raidtab).
Linear volume sets, i.e. linear raid, as well as stripe sets, i.e. raid level
-0, have been tested and work fine (though see section "Limitiations when using
+0, have been tested and work fine (though see section "Limitations when using
the MD driver with NTFS volumes" especially if you want to use linear raid).
Even though untested, there is no reason why mirrors, i.e. raid level 1, and
stripes with parity, i.e. raid level 5, should not work, too.
You have to use the "persistent-superblock 0" option for each raid-disk in the
NTFS volume/stripe you are configuring in /etc/raidtab as the persistent
-superblock used by the MD driver would damange the NTFS volume.
+superblock used by the MD driver would damage the NTFS volume.
Windows by default uses a stripe chunk size of 64k, so you probably want the
"chunk-size 64k" option for each raid-disk, too.
@@ -435,7 +435,7 @@ setup correctly to avoid the possibility of causing damage to the data on the
ntfs volume.
-Limitiations when using the Software RAID / MD driver
+Limitations when using the Software RAID / MD driver
-----------------------------------------------------
Using the md driver will not work properly if any of your NTFS partitions have
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 7db71d6fba82..3355e6920105 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -39,6 +39,8 @@ Table of Contents
2.9 Appletalk
2.10 IPX
2.11 /proc/sys/fs/mqueue - POSIX message queues filesystem
+ 2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
+ 2.13 /proc/<pid>/oom_score - Display current oom-killer score
------------------------------------------------------------------------------
Preface
@@ -408,7 +410,7 @@ VmallocChunk: 111088 kB
this memory, making it slower to access than lowmem.
LowTotal:
LowFree: Lowmem is memory which can be used for everything that
- highmem can be used for, but it is also availble for the
+ highmem can be used for, but it is also available for the
kernel's use for its own data structures. Among many
other things, it is where everything from the Slab is
allocated. Bad things happen when you're out of lowmem.
@@ -1253,7 +1255,7 @@ to allocate (but not use) more memory than is actually available.
address space are refused. Used for a typical system. It
ensures a seriously wild allocation fails while allowing
overcommit to reduce swap usage. root is allowed to
- allocate slighly more memory in this mode. This is the
+ allocate slightly more memory in this mode. This is the
default.
1 - Always overcommit. Appropriate for some scientific
@@ -1586,7 +1588,7 @@ Enable the strict RFC793 interpretation of the TCP urgent pointer field. The
default is to use the BSD compatible interpretation of the urgent pointer
pointing to the first byte after the urgent data. The RFC793 interpretation is
to have it point to the last byte of urgent data. Enabling this option may
-lead to interoperatibility problems. Disabled by default.
+lead to interoperability problems. Disabled by default.
tcp_syncookies
--------------
@@ -1731,7 +1733,7 @@ error_burst and error_cost
These parameters are used to limit how many ICMP destination unreachable to
send from the host in question. ICMP destination unreachable messages are
-sent when we can not reach the next hop, while trying to transmit a packet.
+sent when we cannot reach the next hop while trying to transmit a packet.
It will also print some error messages to kernel logs if someone is ignoring
our ICMP redirects. The higher the error_cost factor is, the fewer
destination unreachable and error messages will be let through. Error_burst
@@ -1855,7 +1857,7 @@ proxy_qlen
Maximum queue length of the delayed proxy arp timer. (see proxy_delay).
-app_solcit
+app_solicit
----------
Determines the number of requests to send to the user level ARP daemon. Use 0
@@ -1962,6 +1964,22 @@ a queue must be less or equal then msg_max.
maximum message size value (it is every message queue's attribute set during
its creation).
+2.12 /proc/<pid>/oom_adj - Adjust the oom-killer score
+------------------------------------------------------
+
+This file can be used to adjust the score used to select which processes
+should be killed in an out-of-memory situation. Giving it a high score will
+increase the likelihood of this process being killed by the oom-killer. Valid
+values are in the range -16 to +15, plus the special value -17, which disables
+oom-killing altogether for this process.
+
+2.13 /proc/<pid>/oom_score - Display current oom-killer score
+-------------------------------------------------------------
+
+------------------------------------------------------------------------------
+This file can be used to check the current score used by the oom-killer is for
+any given <pid>. Use it together with /proc/<pid>/oom_adj to tune which
+process should be killed in an out-of-memory situation.
------------------------------------------------------------------------------
Summary
diff --git a/Documentation/filesystems/spufs.txt b/Documentation/filesystems/spufs.txt
index 8edc3952eff4..982645a1981d 100644
--- a/Documentation/filesystems/spufs.txt
+++ b/Documentation/filesystems/spufs.txt
@@ -84,7 +84,7 @@ FILES
/ibox
The second SPU to CPU communication mailbox. This file is similar to
the first mailbox file, but can be read in blocking I/O mode, and the
- poll familiy of system calls can be used to wait for it. The possible
+ poll family of system calls can be used to wait for it. The possible
operations on an open ibox file are:
read(2)
@@ -105,7 +105,7 @@ FILES
/wbox
- The CPU to SPU communation mailbox. It is write-only can can be written
+ The CPU to SPU communation mailbox. It is write-only and can be written
in units of 32 bits. If the mailbox is full, write() will block and
poll can be used to wait for it becoming empty again. The possible
operations on an open wbox file are: write(2) If a count smaller than
@@ -359,7 +359,7 @@ ERRORS
EFAULT npc is not a valid pointer or status is neither NULL nor a valid
pointer.
- EINTR A signal occured while spu_run was in progress. The npc value
+ EINTR A signal occurred while spu_run was in progress. The npc value
has been updated to the new program counter value if necessary.
EINVAL fd is not a file descriptor returned from spu_create(2).
diff --git a/Documentation/filesystems/sysfs.txt b/Documentation/filesystems/sysfs.txt
index 89b1d196ca80..4b5ca26e5048 100644
--- a/Documentation/filesystems/sysfs.txt
+++ b/Documentation/filesystems/sysfs.txt
@@ -238,7 +238,7 @@ Top Level Directory Layout
The sysfs directory arrangement exposes the relationship of kernel
data structures.
-The top level sysfs diretory looks like:
+The top level sysfs directory looks like:
block/
bus/
diff --git a/Documentation/filesystems/tmpfs.txt b/Documentation/filesystems/tmpfs.txt
index 1773106976a2..6dd050878a20 100644
--- a/Documentation/filesystems/tmpfs.txt
+++ b/Documentation/filesystems/tmpfs.txt
@@ -39,7 +39,7 @@ tmpfs has the following uses:
tmpfs /dev/shm tmpfs defaults 0 0
Remember to create the directory that you intend to mount tmpfs on
- if necessary (/dev/shm is automagically created if you use devfs).
+ if necessary.
This mount is _not_ needed for SYSV shared memory. The internal
mount is used for that. (In the 2.3 kernel versions it was
@@ -63,7 +63,7 @@ size: The limit of allocated bytes for this tmpfs instance. The
nr_blocks: The same as size, but in blocks of PAGE_CACHE_SIZE.
nr_inodes: The maximum number of inodes for this instance. The default
is half of the number of your physical RAM pages, or (on a
- a machine with highmem) the number of lowmem RAM pages,
+ machine with highmem) the number of lowmem RAM pages,
whichever is the lower.
These parameters accept a suffix k, m or g for kilo, mega and giga and
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt
index 2001abbc60e6..069cb1094300 100644
--- a/Documentation/filesystems/vfat.txt
+++ b/Documentation/filesystems/vfat.txt
@@ -35,7 +35,7 @@ iocharset=name -- Character set to use for converting between the
you should consider the following option instead.
utf8=<bool> -- UTF-8 is the filesystem safe version of Unicode that
- is used by the console. It can be be enabled for the
+ is used by the console. It can be enabled for the
filesystem with this option. If 'uni_xlate' gets set,
UTF-8 gets disabled.
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 1cb7e8be927a..7737bfd03cf8 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -410,7 +410,7 @@ otherwise noted.
put_link: called by the VFS to release resources allocated by
follow_link(). The cookie returned by follow_link() is passed
- to to this method as the last parameter. It is used by
+ to this method as the last parameter. It is used by
filesystems such as NFS where page cache is not stable
(i.e. page that was installed when the symbolic link walk
started might not be in the page cache at the end of the
@@ -699,9 +699,9 @@ This describes how the VFS can manipulate an open file. As of kernel
struct file_operations {
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
- ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
+ ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
diff --git a/Documentation/fujitsu/frv/mmu-layout.txt b/Documentation/fujitsu/frv/mmu-layout.txt
index 11dcc5679887..db10250df6be 100644
--- a/Documentation/fujitsu/frv/mmu-layout.txt
+++ b/Documentation/fujitsu/frv/mmu-layout.txt
@@ -233,7 +233,7 @@ related kernel services:
(*) __debug_mmu.iamr[]
(*) __debug_mmu.damr[]
- These receive the current IAMR and DAMR contents. These can be viewed with with the _amr
+ These receive the current IAMR and DAMR contents. These can be viewed with the _amr
GDB macro:
(gdb) _amr
diff --git a/Documentation/highuid.txt b/Documentation/highuid.txt
index 2c33926b9099..76034d9dbfc0 100644
--- a/Documentation/highuid.txt
+++ b/Documentation/highuid.txt
@@ -57,7 +57,7 @@ What's left to be done for 32-bit UIDs on all Linux architectures:
Other filesystems have not been checked yet.
-- The ncpfs and smpfs filesystems can not presently use 32-bit UIDs in
+- The ncpfs and smpfs filesystems cannot presently use 32-bit UIDs in
all ioctl()s. Some new ioctl()s have been added with 32-bit UIDs, but
more are needed. (as well as new user<->kernel data structures)
diff --git a/Documentation/hrtimers.txt b/Documentation/hrtimers.txt
index 7620ff735faf..ce31f65e12e7 100644
--- a/Documentation/hrtimers.txt
+++ b/Documentation/hrtimers.txt
@@ -10,7 +10,7 @@ back and forth trying to integrate high-resolution and high-precision
features into the existing timer framework, and after testing various
such high-resolution timer implementations in practice, we came to the
conclusion that the timer wheel code is fundamentally not suitable for
-such an approach. We initially didnt believe this ('there must be a way
+such an approach. We initially didn't believe this ('there must be a way
to solve this'), and spent a considerable effort trying to integrate
things into the timer wheel, but we failed. In hindsight, there are
several reasons why such integration is hard/impossible:
@@ -27,7 +27,7 @@ several reasons why such integration is hard/impossible:
high-res timers.
- the unpredictable [O(N)] overhead of cascading leads to delays which
- necessiate a more complex handling of high resolution timers, which
+ necessitate a more complex handling of high resolution timers, which
in turn decreases robustness. Such a design still led to rather large
timing inaccuracies. Cascading is a fundamental property of the timer
wheel concept, it cannot be 'designed out' without unevitably
@@ -58,7 +58,7 @@ several reasons why such integration is hard/impossible:
The primary users of precision timers are user-space applications that
utilize nanosleep, posix-timers and itimer interfaces. Also, in-kernel
users like drivers and subsystems which require precise timed events
-(e.g. multimedia) can benefit from the availability of a seperate
+(e.g. multimedia) can benefit from the availability of a separate
high-resolution timer subsystem as well.
While this subsystem does not offer high-resolution clock sources just
@@ -68,7 +68,7 @@ The increasing demand for realtime and multimedia applications along
with other potential users for precise timers gives another reason to
separate the "timeout" and "precise timer" subsystems.
-Another potential benefit is that such a seperation allows even more
+Another potential benefit is that such a separation allows even more
special-purpose optimization of the existing timer wheel for the low
resolution and low precision use cases - once the precision-sensitive
APIs are separated from the timer wheel and are migrated over to
@@ -96,8 +96,8 @@ file systems. The rbtree is solely used for time sorted ordering, while
a separate list is used to give the expiry code fast access to the
queued timers, without having to walk the rbtree.
-(This seperate list is also useful for later when we'll introduce
-high-resolution clocks, where we need seperate pending and expired
+(This separate list is also useful for later when we'll introduce
+high-resolution clocks, where we need separate pending and expired
queues while keeping the time-order intact.)
Time-ordered enqueueing is not purely for the purposes of
diff --git a/Documentation/hwmon/adm9240 b/Documentation/hwmon/adm9240
index 35f618f32896..2c6f1fed4618 100644
--- a/Documentation/hwmon/adm9240
+++ b/Documentation/hwmon/adm9240
@@ -24,7 +24,7 @@ Authors:
Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>,
Michiel Rook <michiel@grendelproject.nl>,
- Grant Coady <gcoady@gmail.com> with guidance
+ Grant Coady <gcoady.lk@gmail.com> with guidance
from Jean Delvare <khali@linux-fr.org>
Interface
diff --git a/Documentation/hwmon/f71805f b/Documentation/hwmon/f71805f
index 28c5b7d1eb90..2ca69df669c3 100644
--- a/Documentation/hwmon/f71805f
+++ b/Documentation/hwmon/f71805f
@@ -17,7 +17,7 @@ Thanks to Kris Chen from Fintek for answering technical questions and
providing additional documentation.
Thanks to Chris Lin from Jetway for providing wiring schematics and
-anwsering technical questions.
+answering technical questions.
Description
diff --git a/Documentation/hwmon/it87 b/Documentation/hwmon/it87
index 9555be1ed999..e783fd62e308 100644
--- a/Documentation/hwmon/it87
+++ b/Documentation/hwmon/it87
@@ -13,12 +13,25 @@ Supported chips:
from Super I/O config space (8 I/O ports)
Datasheet: Publicly available at the ITE website
http://www.ite.com.tw/
+ * IT8716F
+ Prefix: 'it8716'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+ Datasheet: Publicly available at the ITE website
+ http://www.ite.com.tw/product_info/file/pc/IT8716F_V0.3.ZIP
+ * IT8718F
+ Prefix: 'it8718'
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+ Datasheet: Publicly available at the ITE website
+ http://www.ite.com.tw/product_info/file/pc/IT8718F_V0.2.zip
+ http://www.ite.com.tw/product_info/file/pc/IT8718F_V0%203_(for%20C%20version).zip
* SiS950 [clone of IT8705F]
Prefix: 'it87'
Addresses scanned: from Super I/O config space (8 I/O ports)
Datasheet: No longer be available
-Author: Christophe Gauthron <chrisg@0-in.com>
+Authors:
+ Christophe Gauthron <chrisg@0-in.com>
+ Jean Delvare <khali@linux-fr.org>
Module Parameters
@@ -43,26 +56,46 @@ Module Parameters
Description
-----------
-This driver implements support for the IT8705F, IT8712F and SiS950 chips.
-
-This driver also supports IT8712F, which adds SMBus access, and a VID
-input, used to report the Vcore voltage of the Pentium processor.
-The IT8712F additionally features VID inputs.
+This driver implements support for the IT8705F, IT8712F, IT8716F,
+IT8718F and SiS950 chips.
These chips are 'Super I/O chips', supporting floppy disks, infrared ports,
joysticks and other miscellaneous stuff. For hardware monitoring, they
include an 'environment controller' with 3 temperature sensors, 3 fan
rotation speed sensors, 8 voltage sensors, and associated alarms.
+The IT8712F and IT8716F additionally feature VID inputs, used to report
+the Vcore voltage of the processor. The early IT8712F have 5 VID pins,
+the IT8716F and late IT8712F have 6. They are shared with other functions
+though, so the functionality may not be available on a given system.
+The driver dumbly assume it is there.
+
+The IT8718F also features VID inputs (up to 8 pins) but the value is
+stored in the Super-I/O configuration space. Due to technical limitations,
+this value can currently only be read once at initialization time, so
+the driver won't notice and report changes in the VID value. The two
+upper VID bits share their pins with voltage inputs (in5 and in6) so you
+can't have both on a given board.
+
+The IT8716F, IT8718F and later IT8712F revisions have support for
+2 additional fans. They are not yet supported by the driver.
+
+The IT8716F and IT8718F, and late IT8712F and IT8705F also have optional
+16-bit tachometer counters for fans 1 to 3. This is better (no more fan
+clock divider mess) but not compatible with the older chips and
+revisions. For now, the driver only uses the 16-bit mode on the
+IT8716F and IT8718F.
+
Temperatures are measured in degrees Celsius. An alarm is triggered once
when the Overtemperature Shutdown limit is crossed.
Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
-triggered if the rotation speed has dropped below a programmable limit. Fan
-readings can be divided by a programmable divider (1, 2, 4 or 8) to give the
-readings more range or accuracy. Not all RPM values can accurately be
-represented, so some rounding is done. With a divider of 2, the lowest
-representable value is around 2600 RPM.
+triggered if the rotation speed has dropped below a programmable limit. When
+16-bit tachometer counters aren't used, fan readings can be divided by
+a programmable divider (1, 2, 4 or 8) to give the readings more range or
+accuracy. With a divider of 2, the lowest representable value is around
+2600 RPM. Not all RPM values can accurately be represented, so some rounding
+is done.
Voltage sensors (also known as IN sensors) report their values in volts. An
alarm is triggered if the voltage has crossed a programmable minimum or
@@ -71,9 +104,9 @@ zero'; this is important for negative voltage measurements. All voltage
inputs can measure voltages between 0 and 4.08 volts, with a resolution of
0.016 volt. The battery voltage in8 does not have limit registers.
-The VID lines (IT8712F only) encode the core voltage value: the voltage
-level your processor should work with. This is hardcoded by the mainboard
-and/or processor itself. It is a value in volts.
+The VID lines (IT8712F/IT8716F/IT8718F) encode the core voltage value:
+the voltage level your processor should work with. This is hardcoded by
+the mainboard and/or processor itself. It is a value in volts.
If an alarm triggers, it will remain triggered until the hardware register
is read at least once. This means that the cause for the alarm may already
diff --git a/Documentation/hwmon/k8temp b/Documentation/hwmon/k8temp
new file mode 100644
index 000000000000..30d123b8d920
--- /dev/null
+++ b/Documentation/hwmon/k8temp
@@ -0,0 +1,55 @@
+Kernel driver k8temp
+====================
+
+Supported chips:
+ * AMD Athlon64/FX or Opteron CPUs
+ Prefix: 'k8temp'
+ Addresses scanned: PCI space
+ Datasheet: http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/32559.pdf
+
+Author: Rudolf Marek
+Contact: Rudolf Marek <r.marek@sh.cvut.cz>
+
+Description
+-----------
+
+This driver permits reading temperature sensor(s) embedded inside AMD K8
+family CPUs (Athlon64/FX, Opteron). Official documentation says that it works
+from revision F of K8 core, but in fact it seems to be implemented for all
+revisions of K8 except the first two revisions (SH-B0 and SH-B3).
+
+Please note that you will need at least lm-sensors 2.10.1 for proper userspace
+support.
+
+There can be up to four temperature sensors inside single CPU. The driver
+will auto-detect the sensors and will display only temperatures from
+implemented sensors.
+
+Mapping of /sys files is as follows:
+
+temp1_input - temperature of Core 0 and "place" 0
+temp2_input - temperature of Core 0 and "place" 1
+temp3_input - temperature of Core 1 and "place" 0
+temp4_input - temperature of Core 1 and "place" 1
+
+Temperatures are measured in degrees Celsius and measurement resolution is
+1 degree C. It is expected that future CPU will have better resolution. The
+temperature is updated once a second. Valid temperatures are from -49 to
+206 degrees C.
+
+Temperature known as TCaseMax was specified for processors up to revision E.
+This temperature is defined as temperature between heat-spreader and CPU
+case, so the internal CPU temperature supplied by this driver can be higher.
+There is no easy way how to measure the temperature which will correlate
+with TCaseMax temperature.
+
+For newer revisions of CPU (rev F, socket AM2) there is a mathematically
+computed temperature called TControl, which must be lower than TControlMax.
+
+The relationship is following:
+
+temp1_input - TjOffset*2 < TControlMax,
+
+TjOffset is not yet exported by the driver, TControlMax is usually
+70 degrees C. The rule of the thumb -> CPU temperature should not cross
+60 degrees C too much.
diff --git a/Documentation/hwmon/smsc47m1 b/Documentation/hwmon/smsc47m1
index c15bbe68264e..04a11124f667 100644
--- a/Documentation/hwmon/smsc47m1
+++ b/Documentation/hwmon/smsc47m1
@@ -2,12 +2,14 @@ Kernel driver smsc47m1
======================
Supported chips:
- * SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x and LPC47M192
+ * SMSC LPC47B27x, LPC47M112, LPC47M10x, LPC47M13x, LPC47M14x,
+ LPC47M15x and LPC47M192
Addresses scanned: none, address read from Super I/O config space
Prefix: 'smsc47m1'
Datasheets:
http://www.smsc.com/main/datasheets/47b27x.pdf
http://www.smsc.com/main/datasheets/47m10x.pdf
+ http://www.smsc.com/main/datasheets/47m112.pdf
http://www.smsc.com/main/tools/discontinued/47m13x.pdf
http://www.smsc.com/main/datasheets/47m14x.pdf
http://www.smsc.com/main/tools/discontinued/47m15x.pdf
diff --git a/Documentation/hwmon/vt1211 b/Documentation/hwmon/vt1211
new file mode 100644
index 000000000000..77fa633b97a8
--- /dev/null
+++ b/Documentation/hwmon/vt1211
@@ -0,0 +1,206 @@
+Kernel driver vt1211
+====================
+
+Supported chips:
+ * VIA VT1211
+ Prefix: 'vt1211'
+ Addresses scanned: none, address read from Super-I/O config space
+ Datasheet: Provided by VIA upon request and under NDA
+
+Authors: Juerg Haefliger <juergh@gmail.com>
+
+This driver is based on the driver for kernel 2.4 by Mark D. Studebaker and
+its port to kernel 2.6 by Lars Ekman.
+
+Thanks to Joseph Chan and Fiona Gatt from VIA for providing documentation and
+technical support.
+
+
+Module Parameters
+-----------------
+
+* uch_config: int Override the BIOS default universal channel (UCH)
+ configuration for channels 1-5.
+ Legal values are in the range of 0-31. Bit 0 maps to
+ UCH1, bit 1 maps to UCH2 and so on. Setting a bit to 1
+ enables the thermal input of that particular UCH and
+ setting a bit to 0 enables the voltage input.
+
+* int_mode: int Override the BIOS default temperature interrupt mode.
+ The only possible value is 0 which forces interrupt
+ mode 0. In this mode, any pending interrupt is cleared
+ when the status register is read but is regenerated as
+ long as the temperature stays above the hysteresis
+ limit.
+
+Be aware that overriding BIOS defaults might cause some unwanted side effects!
+
+
+Description
+-----------
+
+The VIA VT1211 Super-I/O chip includes complete hardware monitoring
+capabilities. It monitors 2 dedicated temperature sensor inputs (temp1 and
+temp2), 1 dedicated voltage (in5) and 2 fans. Additionally, the chip
+implements 5 universal input channels (UCH1-5) that can be individually
+programmed to either monitor a voltage or a temperature.
+
+This chip also provides manual and automatic control of fan speeds (according
+to the datasheet). The driver only supports automatic control since the manual
+mode doesn't seem to work as advertised in the datasheet. In fact I couldn't
+get manual mode to work at all! Be aware that automatic mode hasn't been
+tested very well (due to the fact that my EPIA M10000 doesn't have the fans
+connected to the PWM outputs of the VT1211 :-().
+
+The following table shows the relationship between the vt1211 inputs and the
+sysfs nodes.
+
+Sensor Voltage Mode Temp Mode Default Use (from the datasheet)
+------ ------------ --------- --------------------------------
+Reading 1 temp1 Intel thermal diode
+Reading 3 temp2 Internal thermal diode
+UCH1/Reading2 in0 temp3 NTC type thermistor
+UCH2 in1 temp4 +2.5V
+UCH3 in2 temp5 VccP (processor core)
+UCH4 in3 temp6 +5V
+UCH5 in4 temp7 +12V
++3.3V in5 Internal VCC (+3.3V)
+
+
+Voltage Monitoring
+------------------
+
+Voltages are sampled by an 8-bit ADC with a LSB of ~10mV. The supported input
+range is thus from 0 to 2.60V. Voltage values outside of this range need
+external scaling resistors. This external scaling needs to be compensated for
+via compute lines in sensors.conf, like:
+
+compute inx @*(1+R1/R2), @/(1+R1/R2)
+
+The board level scaling resistors according to VIA's recommendation are as
+follows. And this is of course totally dependent on the actual board
+implementation :-) You will have to find documentation for your own
+motherboard and edit sensors.conf accordingly.
+
+ Expected
+Voltage R1 R2 Divider Raw Value
+-----------------------------------------------
++2.5V 2K 10K 1.2 2083 mV
+VccP --- --- 1.0 1400 mV (1)
++5V 14K 10K 2.4 2083 mV
++12V 47K 10K 5.7 2105 mV
++3.3V (int) 2K 3.4K 1.588 3300 mV (2)
++3.3V (ext) 6.8K 10K 1.68 1964 mV
+
+(1) Depending on the CPU (1.4V is for a VIA C3 Nehemiah).
+(2) R1 and R2 for 3.3V (int) are internal to the VT1211 chip and the driver
+ performs the scaling and returns the properly scaled voltage value.
+
+Each measured voltage has an associated low and high limit which triggers an
+alarm when crossed.
+
+
+Temperature Monitoring
+----------------------
+
+Temperatures are reported in millidegree Celsius. Each measured temperature
+has a high limit which triggers an alarm if crossed. There is an associated
+hysteresis value with each temperature below which the temperature has to drop
+before the alarm is cleared (this is only true for interrupt mode 0). The
+interrupt mode can be forced to 0 in case the BIOS doesn't do it
+automatically. See the 'Module Parameters' section for details.
+
+All temperature channels except temp2 are external. Temp2 is the VT1211
+internal thermal diode and the driver does all the scaling for temp2 and
+returns the temperature in millidegree Celsius. For the external channels
+temp1 and temp3-temp7, scaling depends on the board implementation and needs
+to be performed in userspace via sensors.conf.
+
+Temp1 is an Intel-type thermal diode which requires the following formula to
+convert between sysfs readings and real temperatures:
+
+compute temp1 (@-Offset)/Gain, (@*Gain)+Offset
+
+According to the VIA VT1211 BIOS porting guide, the following gain and offset
+values should be used:
+
+Diode Type Offset Gain
+---------- ------ ----
+Intel CPU 88.638 0.9528
+ 65.000 0.9686 *)
+VIA C3 Ezra 83.869 0.9528
+VIA C3 Ezra-T 73.869 0.9528
+
+*) This is the formula from the lm_sensors 2.10.0 sensors.conf file. I don't
+know where it comes from or how it was derived, it's just listed here for
+completeness.
+
+Temp3-temp7 support NTC thermistors. For these channels, the driver returns
+the voltages as seen at the individual pins of UCH1-UCH5. The voltage at the
+pin (Vpin) is formed by a voltage divider made of the thermistor (Rth) and a
+scaling resistor (Rs):
+
+Vpin = 2200 * Rth / (Rs + Rth) (2200 is the ADC max limit of 2200 mV)
+
+The equation for the thermistor is as follows (google it if you want to know
+more about it):
+
+Rth = Ro * exp(B * (1 / T - 1 / To)) (To is 298.15K (25C) and Ro is the
+ nominal resistance at 25C)
+
+Mingling the above two equations and assuming Rs = Ro and B = 3435 yields the
+following formula for sensors.conf:
+
+compute tempx 1 / (1 / 298.15 - (` (2200 / @ - 1)) / 3435) - 273.15,
+ 2200 / (1 + (^ (3435 / 298.15 - 3435 / (273.15 + @))))
+
+
+Fan Speed Control
+-----------------
+
+The VT1211 provides 2 programmable PWM outputs to control the speeds of 2
+fans. Writing a 2 to any of the two pwm[1-2]_enable sysfs nodes will put the
+PWM controller in automatic mode. There is only a single controller that
+controls both PWM outputs but each PWM output can be individually enabled and
+disabled.
+
+Each PWM has 4 associated distinct output duty-cycles: full, high, low and
+off. Full and off are internally hard-wired to 255 (100%) and 0 (0%),
+respectively. High and low can be programmed via
+pwm[1-2]_auto_point[2-3]_pwm. Each PWM output can be associated with a
+different thermal input but - and here's the weird part - only one set of
+thermal thresholds exist that controls both PWMs output duty-cycles. The
+thermal thresholds are accessible via pwm[1-2]_auto_point[1-4]_temp. Note
+that even though there are 2 sets of 4 auto points each, they map to the same
+registers in the VT1211 and programming one set is sufficient (actually only
+the first set pwm1_auto_point[1-4]_temp is writable, the second set is
+read-only).
+
+PWM Auto Point PWM Output Duty-Cycle
+------------------------------------------------
+pwm[1-2]_auto_point4_pwm full speed duty-cycle (hard-wired to 255)
+pwm[1-2]_auto_point3_pwm high speed duty-cycle
+pwm[1-2]_auto_point2_pwm low speed duty-cycle
+pwm[1-2]_auto_point1_pwm off duty-cycle (hard-wired to 0)
+
+Temp Auto Point Thermal Threshold
+---------------------------------------------
+pwm[1-2]_auto_point4_temp full speed temp
+pwm[1-2]_auto_point3_temp high speed temp
+pwm[1-2]_auto_point2_temp low speed temp
+pwm[1-2]_auto_point1_temp off temp
+
+Long story short, the controller implements the following algorithm to set the
+PWM output duty-cycle based on the input temperature:
+
+Thermal Threshold Output Duty-Cycle
+ (Rising Temp) (Falling Temp)
+----------------------------------------------------------
+ full speed duty-cycle full speed duty-cycle
+full speed temp
+ high speed duty-cycle full speed duty-cycle
+high speed temp
+ low speed duty-cycle high speed duty-cycle
+low speed temp
+ off duty-cycle low speed duty-cycle
+off temp
diff --git a/Documentation/hwmon/w83627ehf b/Documentation/hwmon/w83627ehf
new file mode 100644
index 000000000000..caa610a297e8
--- /dev/null
+++ b/Documentation/hwmon/w83627ehf
@@ -0,0 +1,85 @@
+Kernel driver w83627ehf
+=======================
+
+Supported chips:
+ * Winbond W83627EHF/EHG (ISA access ONLY)
+ Prefix: 'w83627ehf'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83627EHF_%20W83627EHGb.pdf
+
+Authors:
+ Jean Delvare <khali@linux-fr.org>
+ Yuan Mu (Winbond)
+ Rudolf Marek <r.marek@sh.cvut.cz>
+
+Description
+-----------
+
+This driver implements support for the Winbond W83627EHF and W83627EHG
+super I/O chips. We will refer to them collectively as Winbond chips.
+
+The chips implement three temperature sensors, five fan rotation
+speed sensors, ten analog voltage sensors, alarms with beep warnings (control
+unimplemented), and some automatic fan regulation strategies (plus manual
+fan control mode).
+
+Temperatures are measured in degrees Celsius and measurement resolution is 1
+degC for temp1 and 0.5 degC for temp2 and temp3. An alarm is triggered when
+the temperature gets higher than high limit; it stays on until the temperature
+falls below the hysteresis value.
+
+Fan rotation speeds are reported in RPM (rotations per minute). An alarm is
+triggered if the rotation speed has dropped below a programmable limit. Fan
+readings can be divided by a programmable divider (1, 2, 4, 8, 16, 32, 64 or
+128) to give the readings more range or accuracy. The driver sets the most
+suitable fan divisor itself. Some fans might not be present because they
+share pins with other functions.
+
+Voltage sensors (also known as IN sensors) report their values in millivolts.
+An alarm is triggered if the voltage has crossed a programmable minimum
+or maximum limit.
+
+The driver supports automatic fan control mode known as Thermal Cruise.
+In this mode, the chip attempts to keep the measured temperature in a
+predefined temperature range. If the temperature goes out of range, fan
+is driven slower/faster to reach the predefined range again.
+
+The mode works for fan1-fan4. Mapping of temperatures to pwm outputs is as
+follows:
+
+temp1 -> pwm1
+temp2 -> pwm2
+temp3 -> pwm3
+prog -> pwm4 (the programmable setting is not supported by the driver)
+
+/sys files
+----------
+
+pwm[1-4] - this file stores PWM duty cycle or DC value (fan speed) in range:
+ 0 (stop) to 255 (full)
+
+pwm[1-4]_enable - this file controls mode of fan/temperature control:
+ * 1 Manual Mode, write to pwm file any value 0-255 (full speed)
+ * 2 Thermal Cruise
+
+Thermal Cruise mode
+-------------------
+
+If the temperature is in the range defined by:
+
+pwm[1-4]_target - set target temperature, unit millidegree Celsius
+ (range 0 - 127000)
+pwm[1-4]_tolerance - tolerance, unit millidegree Celsius (range 0 - 15000)
+
+there are no changes to fan speed. Once the temperature leaves the interval,
+fan speed increases (temp is higher) or decreases if lower than desired.
+There are defined steps and times, but not exported by the driver yet.
+
+pwm[1-4]_min_output - minimum fan speed (range 1 - 255), when the temperature
+ is below defined range.
+pwm[1-4]_stop_time - how many milliseconds [ms] must elapse to switch
+ corresponding fan off. (when the temperature was below
+ defined range).
+
+Note: last two functions are influenced by other control bits, not yet exported
+ by the driver, so a change might not have any effect.
diff --git a/Documentation/hwmon/w83791d b/Documentation/hwmon/w83791d
index 83a3836289c2..19b2ed739fa1 100644
--- a/Documentation/hwmon/w83791d
+++ b/Documentation/hwmon/w83791d
@@ -5,7 +5,7 @@ Supported chips:
* Winbond W83791D
Prefix: 'w83791d'
Addresses scanned: I2C 0x2c - 0x2f
- Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791Da.pdf
+ Datasheet: http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83791D_W83791Gb.pdf
Author: Charles Spirakis <bezaur@gmail.com>
@@ -20,6 +20,9 @@ Credits:
Chunhao Huang <DZShen@Winbond.com.tw>,
Rudolf Marek <r.marek@sh.cvut.cz>
+Additional contributors:
+ Sven Anders <anders@anduras.de>
+
Module Parameters
-----------------
@@ -46,7 +49,8 @@ Module Parameters
Description
-----------
-This driver implements support for the Winbond W83791D chip.
+This driver implements support for the Winbond W83791D chip. The W83791G
+chip appears to be the same as the W83791D but is lead free.
Detection of the chip can sometimes be foiled because it can be in an
internal state that allows no clean access (Bank with ID register is not
@@ -71,34 +75,36 @@ Voltage sensors (also known as IN sensors) report their values in millivolts.
An alarm is triggered if the voltage has crossed a programmable minimum
or maximum limit.
-Alarms are provided as output from a "realtime status register". The
-following bits are defined:
-
-bit - alarm on:
-0 - Vcore
-1 - VINR0
-2 - +3.3VIN
-3 - 5VDD
-4 - temp1
-5 - temp2
-6 - fan1
-7 - fan2
-8 - +12VIN
-9 - -12VIN
-10 - -5VIN
-11 - fan3
-12 - chassis
-13 - temp3
-14 - VINR1
-15 - reserved
-16 - tart1
-17 - tart2
-18 - tart3
-19 - VSB
-20 - VBAT
-21 - fan4
-22 - fan5
-23 - reserved
+The bit ordering for the alarm "realtime status register" and the
+"beep enable registers" are different.
+
+in0 (VCORE) : alarms: 0x000001 beep_enable: 0x000001
+in1 (VINR0) : alarms: 0x000002 beep_enable: 0x002000 <== mismatch
+in2 (+3.3VIN): alarms: 0x000004 beep_enable: 0x000004
+in3 (5VDD) : alarms: 0x000008 beep_enable: 0x000008
+in4 (+12VIN) : alarms: 0x000100 beep_enable: 0x000100
+in5 (-12VIN) : alarms: 0x000200 beep_enable: 0x000200
+in6 (-5VIN) : alarms: 0x000400 beep_enable: 0x000400
+in7 (VSB) : alarms: 0x080000 beep_enable: 0x010000 <== mismatch
+in8 (VBAT) : alarms: 0x100000 beep_enable: 0x020000 <== mismatch
+in9 (VINR1) : alarms: 0x004000 beep_enable: 0x004000
+temp1 : alarms: 0x000010 beep_enable: 0x000010
+temp2 : alarms: 0x000020 beep_enable: 0x000020
+temp3 : alarms: 0x002000 beep_enable: 0x000002 <== mismatch
+fan1 : alarms: 0x000040 beep_enable: 0x000040
+fan2 : alarms: 0x000080 beep_enable: 0x000080
+fan3 : alarms: 0x000800 beep_enable: 0x000800
+fan4 : alarms: 0x200000 beep_enable: 0x200000
+fan5 : alarms: 0x400000 beep_enable: 0x400000
+tart1 : alarms: 0x010000 beep_enable: 0x040000 <== mismatch
+tart2 : alarms: 0x020000 beep_enable: 0x080000 <== mismatch
+tart3 : alarms: 0x040000 beep_enable: 0x100000 <== mismatch
+case_open : alarms: 0x001000 beep_enable: 0x001000
+user_enable : alarms: -------- beep_enable: 0x800000
+
+*** NOTE: It is the responsibility of user-space code to handle the fact
+that the beep enable and alarm bits are in different positions when using that
+feature of the chip.
When an alarm goes off, you can be warned by a beeping signal through your
computer speaker. It is possible to enable all beeping globally, or only
@@ -109,5 +115,6 @@ often will do no harm, but will return 'old' values.
W83791D TODO:
---------------
-Provide a patch for per-file alarms as discussed on the mailing list
+Provide a patch for per-file alarms and beep enables as defined in the hwmon
+ documentation (Documentation/hwmon/sysfs-interface)
Provide a patch for smart-fan control (still need appropriate motherboard/fans)
diff --git a/Documentation/i2c/busses/i2c-viapro b/Documentation/i2c/busses/i2c-viapro
index 16775663b9f5..25680346e0ac 100644
--- a/Documentation/i2c/busses/i2c-viapro
+++ b/Documentation/i2c/busses/i2c-viapro
@@ -7,9 +7,12 @@ Supported adapters:
* VIA Technologies, Inc. VT82C686A/B
Datasheet: Sometimes available at the VIA website
- * VIA Technologies, Inc. VT8231, VT8233, VT8233A, VT8235, VT8237R
+ * VIA Technologies, Inc. VT8231, VT8233, VT8233A
Datasheet: available on request from VIA
+ * VIA Technologies, Inc. VT8235, VT8237R, VT8237A, VT8251
+ Datasheet: available on request and under NDA from VIA
+
Authors:
Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark D. Studebaker <mdsxyz123@yahoo.com>,
@@ -39,6 +42,8 @@ Your lspci -n listing must show one of these :
device 1106:8235 (VT8231 function 4)
device 1106:3177 (VT8235)
device 1106:3227 (VT8237R)
+ device 1106:3337 (VT8237A)
+ device 1106:3287 (VT8251)
If none of these show up, you should look in the BIOS for settings like
enable ACPI / SMBus or even USB.
diff --git a/Documentation/i2c/i2c-stub b/Documentation/i2c/i2c-stub
index d6dcb138abf5..9cc081e69764 100644
--- a/Documentation/i2c/i2c-stub
+++ b/Documentation/i2c/i2c-stub
@@ -6,9 +6,12 @@ This module is a very simple fake I2C/SMBus driver. It implements four
types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
(r/w) word data.
+You need to provide a chip address as a module parameter when loading
+this driver, which will then only react to SMBus commands to this address.
+
No hardware is needed nor associated with this module. It will accept write
-quick commands to all addresses; it will respond to the other commands (also
-to all addresses) by reading from or writing to an array in memory. It will
+quick commands to one address; it will respond to the other commands (also
+to one address) by reading from or writing to an array in memory. It will
also spam the kernel logs for every command it handles.
A pointer register with auto-increment is implemented for all byte
@@ -21,6 +24,11 @@ The typical use-case is like this:
3. load the target sensors chip driver module
4. observe its behavior in the kernel log
+PARAMETERS:
+
+int chip_addr:
+ The SMBus address to emulate a chip at.
+
CAVEATS:
There are independent arrays for byte/data and word/data commands. Depending
@@ -33,6 +41,9 @@ If the hardware for your driver has banked registers (e.g. Winbond sensors
chips) this module will not work well - although it could be extended to
support that pretty easily.
+Only one chip address is supported - although this module could be
+extended to support more.
+
If you spam it hard enough, printk can be lossy. This module really wants
something like relayfs.
diff --git a/Documentation/ia64/efirtc.txt b/Documentation/ia64/efirtc.txt
index ede2c1e51cd7..057e6bebda8f 100644
--- a/Documentation/ia64/efirtc.txt
+++ b/Documentation/ia64/efirtc.txt
@@ -26,7 +26,7 @@ to initialize the system view of the time during boot.
Because we wanted to minimize the impact on existing user-level apps using
the CMOS clock, we decided to expose an API that was very similar to the one
used today with the legacy RTC driver (driver/char/rtc.c). However, because
-EFI provides a simpler services, not all all ioctl() are available. Also
+EFI provides a simpler services, not all ioctl() are available. Also
new ioctl()s have been introduced for things that EFI provides but not the
legacy.
diff --git a/Documentation/ia64/fsys.txt b/Documentation/ia64/fsys.txt
index 28da181f9966..59dd689d9b86 100644
--- a/Documentation/ia64/fsys.txt
+++ b/Documentation/ia64/fsys.txt
@@ -165,7 +165,7 @@ complicated cases.
* Signal handling
The delivery of (asynchronous) signals must be delayed until fsys-mode
-is exited. This is acomplished with the help of the lower-privilege
+is exited. This is accomplished with the help of the lower-privilege
transfer trap: arch/ia64/kernel/process.c:do_notify_resume_user()
checks whether the interrupted task was in fsys-mode and, if so, sets
PSR.lp and returns immediately. When fsys-mode is exited via the
diff --git a/Documentation/ia64/mca.txt b/Documentation/ia64/mca.txt
index a71cc6a67ef7..f097c60cba1b 100644
--- a/Documentation/ia64/mca.txt
+++ b/Documentation/ia64/mca.txt
@@ -12,7 +12,7 @@ by locks is indeterminate, including linked lists.
---
The complicated ia64 MCA process. All of this is mandated by Intel's
-specification for ia64 SAL, error recovery and and unwind, it is not as
+specification for ia64 SAL, error recovery and unwind, it is not as
if we have a choice here.
* MCA occurs on one cpu, usually due to a double bit memory error.
@@ -94,7 +94,7 @@ if we have a choice here.
INIT is less complicated than MCA. Pressing the nmi button or using
the equivalent command on the management console sends INIT to all
-cpus. SAL picks one one of the cpus as the monarch and the rest are
+cpus. SAL picks one of the cpus as the monarch and the rest are
slaves. All the OS INIT handlers are entered at approximately the same
time. The OS monarch prints the state of all tasks and returns, after
which the slaves return and the system resumes.
diff --git a/Documentation/ia64/serial.txt b/Documentation/ia64/serial.txt
index f51eb4bc2ff1..040b9773209f 100644
--- a/Documentation/ia64/serial.txt
+++ b/Documentation/ia64/serial.txt
@@ -124,6 +124,13 @@ TROUBLESHOOTING SERIAL CONSOLE PROBLEMS
- Add entry to /etc/securetty for console tty.
+ No ACPI serial devices found in 2.6.17 or later:
+
+ - Turn on CONFIG_PNP and CONFIG_PNPACPI. Prior to 2.6.17, ACPI
+ serial devices were discovered by 8250_acpi. In 2.6.17,
+ 8250_acpi was replaced by the combination of 8250_pnp and
+ CONFIG_PNPACPI.
+
[1] http://www.dig64.org/specifications/DIG64_PCDPv20.pdf
diff --git a/Documentation/ibm-acpi.txt b/Documentation/ibm-acpi.txt
index 8b3fd82b2ce7..e50595bfd8ea 100644
--- a/Documentation/ibm-acpi.txt
+++ b/Documentation/ibm-acpi.txt
@@ -30,9 +30,10 @@ detailed description):
- ACPI sounds
- temperature sensors
- Experimental: embedded controller register dump
- - Experimental: LCD brightness control
- - Experimental: volume control
+ - LCD brightness control
+ - Volume control
- Experimental: fan speed, fan enable/disable
+ - Experimental: WAN enable and disable
A compatibility table by model and feature is maintained on the web
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
@@ -52,40 +53,7 @@ Installation
If you are compiling this driver as included in the Linux kernel
sources, simply enable the CONFIG_ACPI_IBM option (Power Management /
-ACPI / IBM ThinkPad Laptop Extras). The rest of this section describes
-how to install this driver when downloaded from the web site.
-
-First, you need to get a kernel with ACPI support up and running.
-Please refer to http://acpi.sourceforge.net/ for help with this
-step. How successful you will be depends a lot on you ThinkPad model,
-the kernel you are using and any additional patches applied. The
-kernel provided with your distribution may not be good enough. I
-needed to compile a 2.6.7 kernel with the 20040715 ACPI patch to get
-ACPI working reliably on my ThinkPad X40. Old ThinkPad models may not
-be supported at all.
-
-Assuming you have the basic ACPI support working (e.g. you can see the
-/proc/acpi directory), follow the following steps to install this
-driver:
-
- - unpack the archive:
-
- tar xzvf ibm-acpi-x.y.tar.gz; cd ibm-acpi-x.y
-
- - compile the driver:
-
- make
-
- - install the module in your kernel modules directory:
-
- make install
-
- - load the module:
-
- modprobe ibm_acpi
-
-After loading the module, check the "dmesg" output for any error messages.
-
+ACPI / IBM ThinkPad Laptop Extras).
Features
--------
@@ -450,7 +418,7 @@ his laptop (the location of sensors may vary on other models):
No commands can be written to this file.
-EXPERIMENTAL: Embedded controller reigster dump -- /proc/acpi/ibm/ecdump
+EXPERIMENTAL: Embedded controller register dump -- /proc/acpi/ibm/ecdump
------------------------------------------------------------------------
This feature is marked EXPERIMENTAL because the implementation
@@ -523,13 +491,8 @@ registers contain the current battery capacity, etc. If you experiment
with this, do send me your results (including some complete dumps with
a description of the conditions when they were taken.)
-EXPERIMENTAL: LCD brightness control -- /proc/acpi/ibm/brightness
------------------------------------------------------------------
-
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+LCD brightness control -- /proc/acpi/ibm/brightness
+---------------------------------------------------
This feature allows software control of the LCD brightness on ThinkPad
models which don't have a hardware brightness slider. The available
@@ -542,13 +505,8 @@ commands are:
The <level> number range is 0 to 7, although not all of them may be
distinct. The current brightness level is shown in the file.
-EXPERIMENTAL: Volume control -- /proc/acpi/ibm/volume
------------------------------------------------------
-
-This feature is marked EXPERIMENTAL because the implementation
-directly accesses hardware registers and may not work as expected. USE
-WITH CAUTION! To use this feature, you need to supply the
-experimental=1 parameter when loading the module.
+Volume control -- /proc/acpi/ibm/volume
+---------------------------------------
This feature allows volume control on ThinkPad models which don't have
a hardware volume knob. The available commands are:
@@ -611,6 +569,23 @@ with the following command:
echo 'level <level>' > /proc/acpi/ibm/thermal
+EXPERIMENTAL: WAN -- /proc/acpi/ibm/wan
+---------------------------------------
+
+This feature is marked EXPERIMENTAL because the implementation
+directly accesses hardware registers and may not work as expected. USE
+WITH CAUTION! To use this feature, you need to supply the
+experimental=1 parameter when loading the module.
+
+This feature shows the presence and current state of a WAN (Sierra
+Wireless EV-DO) device. If WAN is installed, the following commands can
+be used:
+
+ echo enable > /proc/acpi/ibm/wan
+ echo disable > /proc/acpi/ibm/wan
+
+It was tested on a Lenovo Thinkpad X60. It should probably work on other
+Thinkpad models which come with this module installed.
Multiple Commands, Module Parameters
------------------------------------
diff --git a/Documentation/ide.txt b/Documentation/ide.txt
index 29866fbfb229..0bf38baa2db9 100644
--- a/Documentation/ide.txt
+++ b/Documentation/ide.txt
@@ -281,7 +281,7 @@ Summary of ide driver parameters for kernel command line
"idex=serialize" : do not overlap operations on idex. Please note
that you will have to specify this option for
- both the respecitve primary and secondary channel
+ both the respective primary and secondary channel
to take effect.
"idex=four" : four drives on idex and ide(x^1) share same ports
diff --git a/Documentation/input/amijoy.txt b/Documentation/input/amijoy.txt
index 3b8b2d43a68e..4f0e89df5c51 100644
--- a/Documentation/input/amijoy.txt
+++ b/Documentation/input/amijoy.txt
@@ -79,10 +79,10 @@ JOY0DAT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 X7 X6 X5 X4 X3 X2 X1 X0
JOY1DAT Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 X7 X6 X5 X4 X3 X2 X1 X0
0=LEFT CONTROLLER PAIR, 1=RIGHT CONTROLLER PAIR.
- (4 counters total).The bit usage for both left and right
+ (4 counters total). The bit usage for both left and right
addresses is shown below. Each 6 bit counter (Y7-Y2,X7-X2) is
clocked by 2 of the signals input from the mouse serial
- stream. Starting with first bit recived:
+ stream. Starting with first bit received:
+-------------------+-----------------------------------------+
| Serial | Bit Name | Description |
diff --git a/Documentation/input/atarikbd.txt b/Documentation/input/atarikbd.txt
index 8fb896c74114..1e7e5853ba4c 100644
--- a/Documentation/input/atarikbd.txt
+++ b/Documentation/input/atarikbd.txt
@@ -10,7 +10,7 @@ provides a convenient connection point for a mouse and switch-type joysticks.
The ikbd processor also maintains a time-of-day clock with one second
resolution.
The ikbd has been designed to be general enough that it can be used with a
-ariety of new computer products. Product variations in a number of
+variety of new computer products. Product variations in a number of
keyswitches, mouse resolution, etc. can be accommodated.
The ikbd communicates with the main processor over a high speed bi-directional
serial interface. It can function in a variety of modes to facilitate
@@ -30,7 +30,7 @@ is obtained by ORing 0x80 with the make code.
The special codes 0xF6 through 0xFF are reserved for use as follows:
0xF6 status report
0xF7 absolute mouse position record
- 0xF8-0xFB relative mouse position records(lsbs determind by
+ 0xF8-0xFB relative mouse position records (lsbs determined by
mouse button states)
0xFC time-of-day
0xFD joystick report (both sticks)
@@ -84,7 +84,7 @@ selected.
4.2 Absolute Position reporting
The ikbd can also maintain absolute mouse position. Commands exist for
-reseting the mouse position, setting X/Y scaling, and interrogating the
+resetting the mouse position, setting X/Y scaling, and interrogating the
current mouse position.
4.3 Mouse Cursor Key Mode
@@ -406,7 +406,7 @@ INTERROGATION MODE.
9.18 SET JOYSTICK MONITORING
0x17
- rate ; time between samples in hundreths of a second
+ rate ; time between samples in hundredths of a second
Returns: (in packets of two as long as in mode)
%000000xy ; where y is JOYSTICK1 Fire button
; and x is JOYSTICK0 Fire button
@@ -522,7 +522,7 @@ controller memory. The time between data bytes must be less than 20ms.
0x20 ; memory access
{ data } ; 6 data bytes starting at ADR
-This comand permits the host to read from the ikbd controller memory.
+This command permits the host to read from the ikbd controller memory.
9.26 CONTROLLER EXECUTE
diff --git a/Documentation/input/cs461x.txt b/Documentation/input/cs461x.txt
index 6181747a14d8..afe0d6543e09 100644
--- a/Documentation/input/cs461x.txt
+++ b/Documentation/input/cs461x.txt
@@ -27,7 +27,7 @@ This driver have the basic support for PCI devices only; there is no
ISA or PnP ISA cards supported. AFAIK the ns558 have support for Crystal
ISA and PnP ISA series.
-The driver works witn ALSA drivers simultaneously. For exmple, the xracer
+The driver works with ALSA drivers simultaneously. For example, the xracer
uses joystick as input device and PCM device as sound output in one time.
There are no sound or input collisions detected. The source code have
comments about them; but I've found the joystick can be initialized
diff --git a/Documentation/input/ff.txt b/Documentation/input/ff.txt
index c7e10eaff203..085eb15b45b7 100644
--- a/Documentation/input/ff.txt
+++ b/Documentation/input/ff.txt
@@ -1,78 +1,48 @@
Force feedback for Linux.
By Johann Deneux <deneux@ifrance.com> on 2001/04/22.
+Updated by Anssi Hannula <anssi.hannula@gmail.com> on 2006/04/09.
You may redistribute this file. Please remember to include shape.fig and
interactive.fig as well.
----------------------------------------------------------------------------
-0. Introduction
+1. Introduction
~~~~~~~~~~~~~~~
This document describes how to use force feedback devices under Linux. The
goal is not to support these devices as if they were simple input-only devices
(as it is already the case), but to really enable the rendering of force
effects.
-At the moment, only I-Force devices are supported, and not officially. That
-means I had to find out how the protocol works on my own. Of course, the
-information I managed to grasp is far from being complete, and I can not
-guarranty that this driver will work for you.
-This document only describes the force feedback part of the driver for I-Force
-devices. Please read joystick.txt before reading further this document.
+This document only describes the force feedback part of the Linux input
+interface. Please read joystick.txt and input.txt before reading further this
+document.
2. Instructions to the user
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Here are instructions on how to compile and use the driver. In fact, this
-driver is the normal iforce, input and evdev drivers written by Vojtech
-Pavlik, plus additions to support force feedback.
+To enable force feedback, you have to:
+
+1. have your kernel configured with evdev and a driver that supports your
+ device.
+2. make sure evdev module is loaded and /dev/input/event* device files are
+ created.
Before you start, let me WARN you that some devices shake violently during the
initialisation phase. This happens for example with my "AVB Top Shot Pegasus".
To stop this annoying behaviour, move you joystick to its limits. Anyway, you
-should keep a hand on your device, in order to avoid it to brake down if
+should keep a hand on your device, in order to avoid it to break down if
something goes wrong.
-At the kernel's compilation:
- - Enable IForce/Serial
- - Enable Event interface
-
-Compile the modules, install them.
-
-You also need inputattach.
-
-You then need to insert the modules into the following order:
-% modprobe joydev
-% modprobe serport # Only for serial
-% modprobe iforce
-% modprobe evdev
-% ./inputattach -ifor $2 & # Only for serial
-If you are using USB, you don't need the inputattach step.
-
-Please check that you have all the /dev/input entries needed:
-cd /dev
-rm js*
-mkdir input
-mknod input/js0 c 13 0
-mknod input/js1 c 13 1
-mknod input/js2 c 13 2
-mknod input/js3 c 13 3
-ln -s input/js0 js0
-ln -s input/js1 js1
-ln -s input/js2 js2
-ln -s input/js3 js3
-
-mknod input/event0 c 13 64
-mknod input/event1 c 13 65
-mknod input/event2 c 13 66
-mknod input/event3 c 13 67
+If you have a serial iforce device, you need to start inputattach. See
+joystick.txt for details.
2.1 Does it work ?
~~~~~~~~~~~~~~~~~~
There is an utility called fftest that will allow you to test the driver.
% fftest /dev/input/eventXX
-3. Instructions to the developper
+3. Instructions to the developer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- All interactions are done using the event API. That is, you can use ioctl()
+All interactions are done using the event API. That is, you can use ioctl()
and write() on /dev/input/eventXX.
- This information is subject to change.
+This information is subject to change.
3.1 Querying device capabilities
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -86,18 +56,29 @@ int ioctl(int file_descriptor, int request, unsigned long *features);
Returns the features supported by the device. features is a bitfield with the
following bits:
-- FF_X has an X axis (usually joysticks)
-- FF_Y has an Y axis (usually joysticks)
-- FF_WHEEL has a wheel (usually sterring wheels)
- FF_CONSTANT can render constant force effects
-- FF_PERIODIC can render periodic effects (sine, triangle, square...)
+- FF_PERIODIC can render periodic effects with the following waveforms:
+ - FF_SQUARE square waveform
+ - FF_TRIANGLE triangle waveform
+ - FF_SINE sine waveform
+ - FF_SAW_UP sawtooth up waveform
+ - FF_SAW_DOWN sawtooth down waveform
+ - FF_CUSTOM custom waveform
- FF_RAMP can render ramp effects
- FF_SPRING can simulate the presence of a spring
-- FF_FRICTION can simulate friction
+- FF_FRICTION can simulate friction
- FF_DAMPER can simulate damper effects
-- FF_RUMBLE rumble effects (normally the only effect supported by rumble
- pads)
+- FF_RUMBLE rumble effects
- FF_INERTIA can simulate inertia
+- FF_GAIN gain is adjustable
+- FF_AUTOCENTER autocenter is adjustable
+
+Note: In most cases you should use FF_PERIODIC instead of FF_RUMBLE. All
+ devices that support FF_RUMBLE support FF_PERIODIC (square, triangle,
+ sine) and the other way around.
+
+Note: The exact syntax FF_CUSTOM is undefined for the time being as no driver
+ supports it yet.
int ioctl(int fd, EVIOCGEFFECTS, int *n);
@@ -108,7 +89,7 @@ Returns the number of effects the device can keep in its memory.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <linux/input.h>
#include <sys/ioctl.h>
-
+
int ioctl(int file_descriptor, int request, struct ff_effect *effect);
"request" must be EVIOCSFF.
@@ -120,6 +101,9 @@ to the unique id assigned by the driver. This data is required for performing
some operations (removing an effect, controlling the playback).
This if field must be set to -1 by the user in order to tell the driver to
allocate a new effect.
+
+Effects are file descriptor specific.
+
See <linux/input.h> for a description of the ff_effect struct. You should also
find help in a few sketches, contained in files shape.fig and interactive.fig.
You need xfig to visualize these files.
@@ -128,8 +112,8 @@ You need xfig to visualize these files.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int ioctl(int fd, EVIOCRMFF, effect.id);
-This makes room for new effects in the device's memory. Please note this won't
-stop the effect if it was playing.
+This makes room for new effects in the device's memory. Note that this also
+stops the effect if it was playing.
3.4 Controlling the playback of effects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -149,22 +133,21 @@ Control of playing is done with write(). Below is an example:
play.type = EV_FF;
play.code = effect.id;
play.value = 3;
-
+
write(fd, (const void*) &play, sizeof(play));
...
/* Stop an effect */
stop.type = EV_FF;
stop.code = effect.id;
stop.value = 0;
-
+
write(fd, (const void*) &play, sizeof(stop));
3.5 Setting the gain
~~~~~~~~~~~~~~~~~~~~
Not all devices have the same strength. Therefore, users should set a gain
factor depending on how strong they want effects to be. This setting is
-persistent across access to the driver, so you should not care about it if
-you are writing games, as another utility probably already set this for you.
+persistent across access to the driver.
/* Set the gain of the device
int gain; /* between 0 and 100 */
@@ -204,11 +187,14 @@ type of device, not all parameters can be dynamically updated. For example,
the direction of an effect cannot be updated with iforce devices. In this
case, the driver stops the effect, up-load it, and restart it.
+Therefore it is recommended to dynamically change direction while the effect
+is playing only when it is ok to restart the effect with a replay count of 1.
3.8 Information about the status of effects
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Every time the status of an effect is changed, an event is sent. The values
and meanings of the fields of the event are as follows:
+
struct input_event {
/* When the status of the effect changed */
struct timeval time;
@@ -225,3 +211,9 @@ struct input_event {
FF_STATUS_STOPPED The effect stopped playing
FF_STATUS_PLAYING The effect started to play
+
+NOTE: Status feedback is only supported by iforce driver. If you have
+ a really good reason to use this, please contact
+ linux-joystick@atrey.karlin.mff.cuni.cz or anssi.hannula@gmail.com
+ so that support for it can be added to the rest of the drivers.
+
diff --git a/Documentation/input/gameport-programming.txt b/Documentation/input/gameport-programming.txt
index 1ba3d322e0ac..14e0a8b70225 100644
--- a/Documentation/input/gameport-programming.txt
+++ b/Documentation/input/gameport-programming.txt
@@ -18,8 +18,8 @@ Make sure struct gameport is initialized to 0 in all other fields. The
gameport generic code will take care of the rest.
If your hardware supports more than one io address, and your driver can
-choose which one program the hardware to, starting from the more exotic
-addresses is preferred, because the likelyhood of clashing with the standard
+choose which one to program the hardware to, starting from the more exotic
+addresses is preferred, because the likelihood of clashing with the standard
0x201 address is smaller.
Eg. if your driver supports addresses 0x200, 0x208, 0x210 and 0x218, then
diff --git a/Documentation/input/input.txt b/Documentation/input/input.txt
index 47137e75fdb8..ff8cea0225f9 100644
--- a/Documentation/input/input.txt
+++ b/Documentation/input/input.txt
@@ -68,8 +68,8 @@ will be available as a character device on major 13, minor 63:
crw-r--r-- 1 root root 13, 63 Mar 28 22:45 mice
- This device has to be created, unless you use devfs, in which case it's
-created automatically. The commands to do create it by hand are:
+ This device has to be created.
+ The commands to create it by hand are:
cd /dev
mkdir input
@@ -154,7 +154,7 @@ about it.
3.2 Event handlers
~~~~~~~~~~~~~~~~~~
- Event handlers distrubite the events from the devices to userland and
+ Event handlers distribute the events from the devices to userland and
kernel, as needed.
3.2.1 keybdev
@@ -230,7 +230,7 @@ generated in the kernel straight to the program, with timestamps. The
API is still evolving, but should be useable now. It's described in
section 5.
- This should be the way for GPM and X to get keyboard and mouse mouse
+ This should be the way for GPM and X to get keyboard and mouse
events. It allows for multihead in X without any specific multihead
kernel support. The event codes are the same on all architectures and
are hardware independent.
@@ -279,7 +279,7 @@ struct input_event {
};
'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+Type is for example EV_REL for relative moment, REL_KEY for a keypress or
release. More types are defined in include/linux/input.h.
'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
@@ -289,24 +289,3 @@ list is in include/linux/input.h.
EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
release, 1 for keypress and 2 for autorepeat.
-6. Contacts
-~~~~~~~~~~~
- This effort has its home page at:
-
- http://www.suse.cz/development/input/
-
-You'll find both the latest HID driver and the complete Input driver
-there as well as information how to access the CVS repository for
-latest revisions of the drivers.
-
- There is also a mailing list for this:
-
- majordomo@atrey.karlin.mff.cuni.cz
-
-Send "subscribe linux-input" to subscribe to it.
-
-The input changes are also being worked on as part of the LinuxConsole
-project, see:
-
- http://sourceforge.net/projects/linuxconsole/
-
diff --git a/Documentation/input/joystick-parport.txt b/Documentation/input/joystick-parport.txt
index d537c48cc6d0..ede5f33daad3 100644
--- a/Documentation/input/joystick-parport.txt
+++ b/Documentation/input/joystick-parport.txt
@@ -456,8 +456,8 @@ uses the following kernel/module command line:
8 | Sony PSX DDR controller
9 | SNES mouse
- The exact type of the PSX controller type is autoprobed when used so
-hot swapping should work (but is not recomended).
+ The exact type of the PSX controller type is autoprobed when used, so
+hot swapping should work (but is not recommended).
Should you want to use more than one of parallel ports at once, you can use
gamecon.map2 and gamecon.map3 as additional command line parameters for two
@@ -465,8 +465,8 @@ more parallel ports.
There are two options specific to PSX driver portion. gamecon.psx_delay sets
the command delay when talking to the controllers. The default of 25 should
-work but you can try lowering it for better performace. If your pads don't
-respond try raising it untill they work. Setting the type to 8 allows the
+work but you can try lowering it for better performance. If your pads don't
+respond try raising it until they work. Setting the type to 8 allows the
driver to be used with Dance Dance Revolution or similar games. Arrow keys are
registered as key presses instead of X and Y axes.
diff --git a/Documentation/input/joystick.txt b/Documentation/input/joystick.txt
index 841c353297e6..389de9bd9878 100644
--- a/Documentation/input/joystick.txt
+++ b/Documentation/input/joystick.txt
@@ -60,7 +60,7 @@ and install it before going on.
2.2 Device nodes
~~~~~~~~~~~~~~~~
-For applications to be able to use the joysticks, in you don't use devfs,
+For applications to be able to use the joysticks,
you'll have to manually create these nodes in /dev:
cd /dev
diff --git a/Documentation/input/xpad.txt b/Documentation/input/xpad.txt
index b9111a703ce0..5427bdf225ed 100644
--- a/Documentation/input/xpad.txt
+++ b/Documentation/input/xpad.txt
@@ -3,20 +3,37 @@ xpad - Linux USB driver for X-Box gamepads
This is the very first release of a driver for X-Box gamepads.
Basically, this was hacked away in just a few hours, so don't expect
miracles.
+
In particular, there is currently NO support for the rumble pack.
You won't find many ff-aware linux applications anyway.
-0. Status
----------
+0. Notes
+--------
+
+Driver updated for kernel 2.6.17.11. (Based on a patch for 2.6.11.4.)
-For now, this driver has only been tested on just one Linux-Box.
-This one is running a 2.4.18 kernel with usb-uhci on an amd athlon 600.
+The number of buttons/axes reported varies based on 3 things:
+- if you are using a known controller
+- if you are using a known dance pad
+- if using an unknown device (one not listed below), what you set in the
+ module configuration for "Map D-PAD to buttons rather than axes for unknown
+ pads" (module option dpad_to_buttons)
-The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) reports
-8 axes and 10 buttons.
+If you set dpad_to_buttons to 0 and you are using an unknown device (one
+not listed below), the driver will map the directional pad to axes (X/Y),
+if you said N it will map the d-pad to buttons, which is needed for dance
+style games to function correctly. The default is Y.
+
+dpad_to_buttons has no effect for known pads.
+
+0.1 Normal Controllers
+----------------------
+With a normal controller, the directional pad is mapped to its own X/Y axes.
+The jstest-program from joystick-1.2.15 (jstest-version 2.1.0) will report 8
+axes and 10 buttons.
-Alls 8 axes work, though they all have the same range (-32768..32767)
+All 8 axes work, though they all have the same range (-32768..32767)
and the zero-setting is not correct for the triggers (I don't know if that
is some limitation of jstest, since the input device setup should be fine. I
didn't have a look at jstest itself yet).
@@ -30,16 +47,50 @@ in game functionality were OK. However, I find it rather difficult to
play first person shooters with a pad. Your mileage may vary.
+0.2 Xbox Dance Pads
+-------------------
+When using a known dance pad, jstest will report 6 axes and 14 buttons.
+
+For dance style pads (like the redoctane pad) several changes
+have been made. The old driver would map the d-pad to axes, resulting
+in the driver being unable to report when the user was pressing both
+left+right or up+down, making DDR style games unplayable.
+
+Known dance pads automatically map the d-pad to buttons and will work
+correctly out of the box.
+
+If your dance pad is recognized by the driver but is using axes instead
+of buttons, see section 0.3 - Unknown Controllers
+
+I've tested this with Stepmania, and it works quite well.
+
+
+0.3 Unkown Controllers
+----------------------
+If you have an unkown 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
+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
+box in the future.
+
+
1. USB adapter
--------------
Before you can actually use the driver, you need to get yourself an
-adapter cable to connect the X-Box controller to your Linux-Box.
+adapter cable to connect the X-Box controller to your Linux-Box. You
+can buy these online fairly cheap, or build your own.
-Such a cable is pretty easy to build. The Controller itself is a USB compound
-device (a hub with three ports for two expansion slots and the controller
-device) with the only difference in a nonstandard connector (5 pins vs. 4 on
-standard USB connector).
+Such a cable is pretty easy to build. The Controller itself is a USB
+compound device (a hub with three ports for two expansion slots and
+the controller device) with the only difference in a nonstandard connector
+(5 pins vs. 4 on standard USB connector).
You just need to solder a USB connector onto the cable and keep the
yellow wire unconnected. The other pins have the same order on both
@@ -51,36 +102,36 @@ original one. You can buy an extension cable and cut that instead. That way,
you can still use the controller with your X-Box, if you have one ;)
-2. driver installation
+2. Driver Installation
----------------------
Once you have the adapter cable and the controller is connected, you need
to load your USB subsystem and should cat /proc/bus/usb/devices.
There should be an entry like the one at the end [4].
-Currently (as of version 0.0.4), the following three devices are included:
+Currently (as of version 0.0.6), the following devices are included:
original Microsoft XBOX controller (US), vendor=0x045e, product=0x0202
+ smaller Microsoft XBOX controller (US), vendor=0x045e, product=0x0289
original Microsoft XBOX controller (Japan), vendor=0x045e, product=0x0285
InterAct PowerPad Pro (Germany), vendor=0x05fd, product=0x107a
+ RedOctane Xbox Dance Pad (US), vendor=0x0c12, product=0x8809
-If you have another controller that is not listed above and is not recognized
-by the driver, please drop me a line with the appropriate info (that is, include
-the name, vendor and product ID, as well as the country where you bought it;
-sending the whole dump out of /proc/bus/usb/devices along would be even better).
+The driver should work with xbox pads not listed above as well, however
+you will need to do something extra for dance pads to work.
-In theory, the driver should work with other controllers than mine
-(InterAct PowerPad pro, bought in Germany) just fine, but I cannot test this
-for I only have this one controller.
+If you have a controller not listed above, see 0.3 - Unknown Controllers
If you compiled and installed the driver, test the functionality:
> modprobe xpad
> modprobe joydev
> jstest /dev/js0
-There should be a single line showing 18 inputs (8 axes, 10 buttons), and
-it's values should change if you move the sticks and push the buttons.
+If you're using a normal controller, there should be a single line showing
+18 inputs (8 axes, 10 buttons), and its values should change if you move
+the sticks and push the buttons. If you're using a dance pad, it should
+show 20 inputs (6 axes, 14 buttons).
-It works? Voila, your done ;)
+It works? Voila, you're done ;)
3. Thanks
@@ -111,6 +162,22 @@ I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=(none)
E: Ad=81(I) Atr=03(Int.) MxPS= 32 Ivl= 10ms
E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl= 10ms
+5. /proc/bus/usb/devices - dump from Redoctane Xbox Dance Pad (US):
+
+T: Bus=01 Lev=02 Prnt=09 Port=00 Cnt=01 Dev#= 10 Spd=12 MxCh= 0
+D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
+P: Vendor=0c12 ProdID=8809 Rev= 0.01
+S: Product=XBOX DDR
+C:* #Ifs= 1 Cfg#= 1 Atr=80 MxPwr=100mA
+I: If#= 0 Alt= 0 #EPs= 2 Cls=58(unk. ) Sub=42 Prot=00 Driver=xpad
+E: Ad=82(I) Atr=03(Int.) MxPS= 32 Ivl=4ms
+E: Ad=02(O) Atr=03(Int.) MxPS= 32 Ivl=4ms
+
--
Marko Friedemann <mfr@bmx-chemnitz.de>
2002-07-16
+ - original doc
+
+Dominic Cerquetti <binary1230@yahoo.com>
+2005-03-19
+ - added stuff for dance pads, new d-pad->axes mappings
diff --git a/Documentation/input/yealink.txt b/Documentation/input/yealink.txt
index 0962c5c948be..0a8c97e87d47 100644
--- a/Documentation/input/yealink.txt
+++ b/Documentation/input/yealink.txt
@@ -87,13 +87,13 @@ Line 3 Format : 888888888888
Format description:
- From a user space perspective the world is seperated in "digits" and "icons".
+ From a userspace perspective the world is separated into "digits" and "icons".
A digit can have a character set, an icon can only be ON or OFF.
Format specifier
'8' : Generic 7 segment digit with individual addressable segments
- Reduced capabillity 7 segm digit, when segments are hard wired together.
+ Reduced capability 7 segm digit, when segments are hard wired together.
'1' : 2 segments digit only able to produce a 1.
'e' : Most significant day of the month digit,
able to produce at least 1 2 3.
diff --git a/Documentation/ioctl/hdio.txt b/Documentation/ioctl/hdio.txt
index 11c9be49f37c..c19efdeace2c 100644
--- a/Documentation/ioctl/hdio.txt
+++ b/Documentation/ioctl/hdio.txt
@@ -203,7 +203,7 @@ HDIO_SET_MULTCOUNT change IDE blockmode
Source code comments read:
- This is tightly woven into the driver->do_special can not
+ This is tightly woven into the driver->do_special cannot
touch. DON'T do it again until a total personality rewrite
is committed.
diff --git a/Documentation/isdn/INTERFACE.fax b/Documentation/isdn/INTERFACE.fax
index 7e5731319e30..9c8c6d914ec7 100644
--- a/Documentation/isdn/INTERFACE.fax
+++ b/Documentation/isdn/INTERFACE.fax
@@ -26,7 +26,7 @@ Structure T30_s description:
If the HL-driver receives ISDN_CMD_FAXCMD, all needed information
is in this struct set by the LL.
To signal information to the LL, the HL-driver has to set the
- the parameters and use ISDN_STAT_FAXIND.
+ parameters and use ISDN_STAT_FAXIND.
(Please refer to INTERFACE)
Structure T30_s:
diff --git a/Documentation/isdn/README.hysdn b/Documentation/isdn/README.hysdn
index 56cc59df1fb7..eeca11f00ccd 100644
--- a/Documentation/isdn/README.hysdn
+++ b/Documentation/isdn/README.hysdn
@@ -1,6 +1,6 @@
$Id: README.hysdn,v 1.3.6.1 2001/02/10 14:41:19 kai Exp $
The hysdn driver has been written by
-by Werner Cornelius (werner@isdn4linux.de or werner@titro.de)
+Werner Cornelius (werner@isdn4linux.de or werner@titro.de)
for Hypercope GmbH Aachen Germany. Hypercope agreed to publish this driver
under the GNU General Public License.
diff --git a/Documentation/java.txt b/Documentation/java.txt
index e4814c213301..c768dc63b34e 100644
--- a/Documentation/java.txt
+++ b/Documentation/java.txt
@@ -22,7 +22,7 @@ other program after you have done the following:
the kernel (CONFIG_BINFMT_MISC) and set it up properly.
If you choose to compile it as a module, you will have
to insert it manually with modprobe/insmod, as kmod
- can not easily be supported with binfmt_misc.
+ cannot easily be supported with binfmt_misc.
Read the file 'binfmt_misc.txt' in this directory to know
more about the configuration process.
diff --git a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
index 003fccc14d24..125093c3ef76 100644
--- a/Documentation/kbuild/kconfig-language.txt
+++ b/Documentation/kbuild/kconfig-language.txt
@@ -1,7 +1,7 @@
Introduction
------------
-The configuration database is collection of configuration options
+The configuration database is a collection of configuration options
organized in a tree structure:
+- Code maturity level options
@@ -110,7 +110,7 @@ applicable everywhere (see syntax).
the indentation level, this means it ends at the first line which has
a smaller indentation than the first line of the help text.
"---help---" and "help" do not differ in behaviour, "---help---" is
- used to help visually seperate configuration logic from help within
+ used to help visually separate configuration logic from help within
the file as an aid to developers.
@@ -226,7 +226,7 @@ menuconfig:
"menuconfig" <symbol>
<config options>
-This is similiar to the simple config entry above, but it also gives a
+This is similar to the simple config entry above, but it also gives a
hint to front ends, that all suboptions should be displayed as a
separate list of options.
diff --git a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt
index e2cbd59cf2d0..50f4eddf899c 100644
--- a/Documentation/kbuild/makefiles.txt
+++ b/Documentation/kbuild/makefiles.txt
@@ -390,7 +390,7 @@ more details, with real examples.
The kernel may be built with several different versions of
$(CC), each supporting a unique set of features and options.
kbuild provide basic support to check for valid options for $(CC).
- $(CC) is useally the gcc compiler, but other alternatives are
+ $(CC) is usually the gcc compiler, but other alternatives are
available.
as-option
diff --git a/Documentation/kbuild/modules.txt b/Documentation/kbuild/modules.txt
index 2e7702e94a78..769ee05ee4d1 100644
--- a/Documentation/kbuild/modules.txt
+++ b/Documentation/kbuild/modules.txt
@@ -43,7 +43,7 @@ are not planned to be included in the kernel tree.
What is covered within this file is mainly information to authors
of modules. The author of an external module should supply
a makefile that hides most of the complexity, so one only has to type
-'make' to build the module. A complete example will be present in
+'make' to build the module. A complete example will be presented in
chapter 4, "Creating a kbuild file for an external module".
@@ -61,6 +61,7 @@ when building an external module.
make -C <path-to-kernel> M=`pwd`
For the running kernel use:
+
make -C /lib/modules/`uname -r`/build M=`pwd`
For the above command to succeed, the kernel must have been
@@ -130,10 +131,10 @@ when building an external module.
To make sure the kernel contains the information required to
build external modules the target 'modules_prepare' must be used.
- 'module_prepare' exists solely as a simple way to prepare
+ 'modules_prepare' exists solely as a simple way to prepare
a kernel source tree for building external modules.
Note: modules_prepare will not build Module.symvers even if
- CONFIG_MODULEVERSIONING is set. Therefore a full kernel build
+ CONFIG_MODVERSIONS is set. Therefore a full kernel build
needs to be executed to make module versioning work.
--- 2.5 Building separate files for a module
@@ -450,7 +451,7 @@ kernel refuses to load the module.
Module.symvers contains a list of all exported symbols from a kernel build.
---- 7.1 Symbols fron the kernel (vmlinux + modules)
+--- 7.1 Symbols from the kernel (vmlinux + modules)
During a kernel build, a file named Module.symvers will be generated.
Module.symvers contains all exported symbols from the kernel and
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index 08bafa8c1caa..99f2d4d4bf7d 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -249,7 +249,7 @@ If die() is called, and it happens to be a thread with pid 0 or 1, or die()
is called inside interrupt context or die() is called and panic_on_oops is set,
the system will boot into the dump-capture kernel.
-On powererpc systems when a soft-reset is generated, die() is called by all cpus and the system system will boot into the dump-capture kernel.
+On powererpc systems when a soft-reset is generated, die() is called by all cpus and the system will boot into the dump-capture kernel.
For testing purposes, you can trigger a crash by using "ALT-SysRq-c",
"echo c > /proc/sysrq-trigger or write a module to force the panic.
diff --git a/Documentation/kernel-docs.txt b/Documentation/kernel-docs.txt
index 99d24f2943ee..b53bccbd9727 100644
--- a/Documentation/kernel-docs.txt
+++ b/Documentation/kernel-docs.txt
@@ -290,17 +290,6 @@
Description: Very nice 92 pages GPL book on the topic of modules
programming. Lots of examples.
- * Title: "Device File System (devfs) Overview"
- Author: Richard Gooch.
- URL: http://www.atnf.csiro.au/people/rgooch/linux/docs/devfs.html
- Keywords: filesystem, /dev, devfs, dynamic devices, major/minor
- allocation, device management.
- Description: Document describing Richard Gooch's controversial
- devfs, which allows for dynamic devices, only shows present
- devices in /dev, gets rid of major/minor numbers allocation
- problems, and allows for hundreds of identical devices (which some
- USB systems might demand soon).
-
* Title: "I/O Event Handling Under Linux"
Author: Richard Gooch.
URL: http://www.atnf.csiro.au/~rgooch/linux/docs/io-events.html
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index c918cc3f65fb..dd00fd556a60 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -110,6 +110,13 @@ be entered as an environment variable, whereas its absence indicates that
it will appear as a kernel argument readable via /proc/cmdline by programs
running once the system is up.
+The number of kernel parameters is not limited, but the length of the
+complete command line (parameters including spaces etc.) is limited to
+a fixed number of characters. This limit depends on the architecture
+and is between 256 and 4096 characters. It is defined in the file
+./include/asm/setup.h as COMMAND_LINE_SIZE.
+
+
53c7xx= [HW,SCSI] Amiga SCSI controllers
See header of drivers/scsi/53c7xx.c.
See also Documentation/scsi/ncr53c7xx.txt.
@@ -282,9 +289,6 @@ running once the system is up.
autotest [IA64]
- awe= [HW,OSS] AWE32/SB32/AWE64 wave table synth
- Format: <io>,<memsize>,<isapnp>
-
aztcd= [HW,CD] Aztech CD268 CDROM driver
Format: <io>,0x79 (?)
@@ -348,9 +352,9 @@ running once the system is up.
clock= [BUGS=IA-32, HW] gettimeofday clocksource override.
[Deprecated]
- Forces specified clocksource (if avaliable) to be used
+ Forces specified clocksource (if available) to be used
when calculating gettimeofday(). If specified
- clocksource is not avalible, it defaults to PIT.
+ clocksource is not available, it defaults to PIT.
Format: { pit | tsc | cyclone | pmtmr }
disable_8254_timer
@@ -529,10 +533,6 @@ running once the system is up.
Default value is 0.
Value can be changed at runtime via /selinux/enforce.
- es1370= [HW,OSS]
- Format: <lineout>[,<micbias>]
- See also header of sound/oss/es1370.c.
-
es1371= [HW,OSS]
Format: <spdif>,[<nomix>,[<amplifier>]]
See also header of sound/oss/es1371.c.
@@ -573,11 +573,6 @@ running once the system is up.
gscd= [HW,CD]
Format: <io>
- gt96100eth= [NET] MIPS GT96100 Advanced Communication Controller
-
- gus= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma16>
-
gvp11= [HW,SCSI]
hashdist= [KNL,NUMA] Large hashes allocated during boot
@@ -606,8 +601,8 @@ running once the system is up.
noirqbalance [IA-32,SMP,KNL] Disable kernel irq balancing
i8042.direct [HW] Put keyboard port into non-translated mode
- i8042.dumbkbd [HW] Pretend that controlled can only read data from
- keyboard and can not control its state
+ i8042.dumbkbd [HW] Pretend that controller can only read data from
+ keyboard and cannot control its state
(Don't attempt to blink the leds)
i8042.noaux [HW] Don't check for auxiliary (== mouse) port
i8042.nokbd [HW] Don't check/create keyboard port
@@ -836,12 +831,6 @@ running once the system is up.
(machvec) in a generic kernel.
Example: machvec=hpzx1_swiotlb
- mad16= [HW,OSS] Format:
- <io>,<irq>,<dma>,<dma16>,<mpu_io>,<mpu_irq>,<joystick>
-
- maui= [HW,OSS]
- Format: <io>,<irq>
-
max_loop= [LOOP] Maximum number of loopback devices that can
be mounted
Format: <1-256>
@@ -1109,9 +1098,6 @@ running once the system is up.
opl3= [HW,OSS]
Format: <io>
- opl3sa= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma2>,<mpu_io>,<mpu_irq>
-
opl3sa2= [HW,OSS] Format:
<io>,<irq>,<dma>,<dma2>,<mss_io>,<mpu_io>,<ymode>,<loopback>[,<isapnp>,<multiple]
@@ -1245,6 +1231,11 @@ running once the system is up.
machine check when some devices' config space
is read. But various workarounds are disabled
and some IOMMU drivers will not work.
+ bfsort Sort PCI devices into breadth-first order.
+ This sorting is done to get a device
+ order compatible with older (<= 2.4) kernels.
+ nobfsort Don't sort PCI devices into breadth-first order.
+
pcmv= [HW,PCMCIA] BadgePAD 4
pd. [PARIDE]
@@ -1326,7 +1317,7 @@ running once the system is up.
pt. [PARIDE]
See Documentation/paride.txt.
- quiet= [KNL] Disable log messages
+ quiet [KNL] Disable most log messages
r128= [HW,DRM]
@@ -1352,10 +1343,6 @@ running once the system is up.
rcu.qlowmark= [KNL,BOOT] Set threshold of queued
RCU callbacks below which batch limiting is re-enabled.
- rcu.rsinterval= [KNL,BOOT,SMP] Set the number of additional
- RCU callbacks to queued before forcing reschedule
- on all cpus.
-
rdinit= [KNL]
Format: <full_path>
Run specified binary instead of /init from the ramdisk,
@@ -1363,7 +1350,7 @@ running once the system is up.
reboot= [BUGS=IA-32,BUGS=ARM,BUGS=IA-64] Rebooting mode
Format: <reboot_mode>[,<reboot_mode2>[,...]]
- See arch/*/kernel/reboot.c.
+ See arch/*/kernel/reboot.c or arch/*/kernel/process.c
reserve= [KNL,BUGS] Force the kernel to ignore some iomem area
@@ -1372,6 +1359,9 @@ running once the system is up.
Reserves a hole at the top of the kernel virtual
address space.
+ reset_devices [KNL] Force drivers to reset the underlying device
+ during initialization.
+
resume= [SWSUSP]
Specify the partition device for software suspend
@@ -1447,9 +1437,6 @@ running once the system is up.
sg_def_reserved_size= [SCSI]
- sgalaxy= [HW,OSS]
- Format: <io>,<irq>,<dma>,<dma2>,<sgbase>
-
shapers= [NET]
Maximal number of shapers.
@@ -1590,9 +1577,6 @@ running once the system is up.
snd-ymfpci= [HW,ALSA]
- sonicvibes= [HW,OSS]
- Format: <reverb>
-
sonycd535= [HW,CD]
Format: <io>[,<irq>]
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index e373f0212843..3da586bc7859 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -671,7 +671,7 @@ The keyctl syscall functions are:
Note that this setting is inherited across fork/exec.
- [1] The default default is: the thread keyring if there is one, otherwise
+ [1] The default is: the thread keyring if there is one, otherwise
the process keyring if there is one, otherwise the session keyring if
there is one, otherwise the user default session keyring.
@@ -708,14 +708,14 @@ The keyctl syscall functions are:
If the specified key is 0, then any assumed authority will be divested.
- The assumed authorititive key is inherited across fork and exec.
+ The assumed authoritative key is inherited across fork and exec.
===============
KERNEL SERVICES
===============
-The kernel services for key managment are fairly simple to deal with. They can
+The kernel services for key management are fairly simple to deal with. They can
be broken down into two areas: keys and key types.
Dealing with keys is fairly straightforward. Firstly, the kernel service
diff --git a/Documentation/kobject.txt b/Documentation/kobject.txt
index 949f7b5a2053..e44855513b3d 100644
--- a/Documentation/kobject.txt
+++ b/Documentation/kobject.txt
@@ -51,7 +51,7 @@ more complex object types. It provides a set of basic fields that
almost all complex data types share. kobjects are intended to be
embedded in larger data structures and replace fields they duplicate.
-1.2 Defintion
+1.2 Definition
struct kobject {
char name[KOBJ_NAME_LEN];
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt
index 2c3b1eae4280..ba26201d5023 100644
--- a/Documentation/kprobes.txt
+++ b/Documentation/kprobes.txt
@@ -151,9 +151,9 @@ So that you can load and unload Kprobes-based instrumentation modules,
make sure "Loadable module support" (CONFIG_MODULES) and "Module
unloading" (CONFIG_MODULE_UNLOAD) are set to "y".
-You may also want to ensure that CONFIG_KALLSYMS and perhaps even
-CONFIG_KALLSYMS_ALL are set to "y", since kallsyms_lookup_name()
-is a handy, version-independent way to find a function's address.
+Also make sure that CONFIG_KALLSYMS and perhaps even CONFIG_KALLSYMS_ALL
+are set to "y", since kallsyms_lookup_name() is used by the in-kernel
+kprobe address resolution code.
If you need to insert a probe in the middle of a function, you may find
it useful to "Compile the kernel with debug info" (CONFIG_DEBUG_INFO),
@@ -179,6 +179,27 @@ occurs during execution of kp->pre_handler or kp->post_handler,
or during single-stepping of the probed instruction, Kprobes calls
kp->fault_handler. Any or all handlers can be NULL.
+NOTE:
+1. With the introduction of the "symbol_name" field to struct kprobe,
+the probepoint address resolution will now be taken care of by the kernel.
+The following will now work:
+
+ kp.symbol_name = "symbol_name";
+
+(64-bit powerpc intricacies such as function descriptors are handled
+transparently)
+
+2. Use the "offset" field of struct kprobe if the offset into the symbol
+to install a probepoint is known. This field is used to calculate the
+probepoint.
+
+3. Specify either the kprobe "symbol_name" OR the "addr". If both are
+specified, kprobe registration will fail with -EINVAL.
+
+4. With CISC architectures (such as i386 and x86_64), the kprobes code
+does not validate if the kprobe.addr is at an instruction boundary.
+Use "offset" with caution.
+
register_kprobe() returns 0 on success, or a negative errno otherwise.
User's pre-handler (kp->pre_handler):
@@ -225,6 +246,12 @@ control to Kprobes.) If the probed function is declared asmlinkage,
fastcall, or anything else that affects how args are passed, the
handler's declaration must match.
+NOTE: A macro JPROBE_ENTRY is provided to handle architecture-specific
+aliasing of jp->entry. In the interest of portability, it is advised
+to use:
+
+ jp->entry = JPROBE_ENTRY(handler);
+
register_jprobe() returns 0 on success, or a negative errno otherwise.
4.3 register_kretprobe
@@ -251,6 +278,11 @@ of interest:
- ret_addr: the return address
- rp: points to the corresponding kretprobe object
- task: points to the corresponding task struct
+
+The regs_return_value(regs) macro provides a simple abstraction to
+extract the return value from the appropriate register as defined by
+the architecture's ABI.
+
The handler's return value is currently ignored.
4.4 unregister_*probe
@@ -369,7 +401,6 @@ stack trace and selected i386 registers when do_fork() is called.
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
-#include <linux/kallsyms.h>
#include <linux/sched.h>
/*For each probe you need to allocate a kprobe structure*/
@@ -403,18 +434,14 @@ int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr)
return 0;
}
-int init_module(void)
+static int __init kprobe_init(void)
{
int ret;
kp.pre_handler = handler_pre;
kp.post_handler = handler_post;
kp.fault_handler = handler_fault;
- kp.addr = (kprobe_opcode_t*) kallsyms_lookup_name("do_fork");
- /* register the kprobe now */
- if (!kp.addr) {
- printk("Couldn't find %s to plant kprobe\n", "do_fork");
- return -1;
- }
+ kp.symbol_name = "do_fork";
+
if ((ret = register_kprobe(&kp) < 0)) {
printk("register_kprobe failed, returned %d\n", ret);
return -1;
@@ -423,12 +450,14 @@ int init_module(void)
return 0;
}
-void cleanup_module(void)
+static void __exit kprobe_exit(void)
{
unregister_kprobe(&kp);
printk("kprobe unregistered\n");
}
+module_init(kprobe_init)
+module_exit(kprobe_exit)
MODULE_LICENSE("GPL");
----- cut here -----
@@ -463,7 +492,6 @@ the arguments of do_fork().
#include <linux/fs.h>
#include <linux/uio.h>
#include <linux/kprobes.h>
-#include <linux/kallsyms.h>
/*
* Jumper probe for do_fork.
@@ -485,17 +513,13 @@ long jdo_fork(unsigned long clone_flags, unsigned long stack_start,
}
static struct jprobe my_jprobe = {
- .entry = (kprobe_opcode_t *) jdo_fork
+ .entry = JPROBE_ENTRY(jdo_fork)
};
-int init_module(void)
+static int __init jprobe_init(void)
{
int ret;
- my_jprobe.kp.addr = (kprobe_opcode_t *) kallsyms_lookup_name("do_fork");
- if (!my_jprobe.kp.addr) {
- printk("Couldn't find %s to plant jprobe\n", "do_fork");
- return -1;
- }
+ my_jprobe.kp.symbol_name = "do_fork";
if ((ret = register_jprobe(&my_jprobe)) <0) {
printk("register_jprobe failed, returned %d\n", ret);
@@ -506,12 +530,14 @@ int init_module(void)
return 0;
}
-void cleanup_module(void)
+static void __exit jprobe_exit(void)
{
unregister_jprobe(&my_jprobe);
printk("jprobe unregistered\n");
}
+module_init(jprobe_init)
+module_exit(jprobe_exit)
MODULE_LICENSE("GPL");
----- cut here -----
@@ -530,16 +556,13 @@ report failed calls to sys_open().
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/kprobes.h>
-#include <linux/kallsyms.h>
static const char *probed_func = "sys_open";
/* Return-probe handler: If the probed function fails, log the return value. */
static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs)
{
- // Substitute the appropriate register name for your architecture --
- // e.g., regs->rax for x86_64, regs->gpr[3] for ppc64.
- int retval = (int) regs->eax;
+ int retval = regs_return_value(regs);
if (retval < 0) {
printk("%s returns %d\n", probed_func, retval);
}
@@ -552,15 +575,11 @@ static struct kretprobe my_kretprobe = {
.maxactive = 20
};
-int init_module(void)
+static int __init kretprobe_init(void)
{
int ret;
- my_kretprobe.kp.addr =
- (kprobe_opcode_t *) kallsyms_lookup_name(probed_func);
- if (!my_kretprobe.kp.addr) {
- printk("Couldn't find %s to plant return probe\n", probed_func);
- return -1;
- }
+ my_kretprobe.kp.symbol_name = (char *)probed_func;
+
if ((ret = register_kretprobe(&my_kretprobe)) < 0) {
printk("register_kretprobe failed, returned %d\n", ret);
return -1;
@@ -569,7 +588,7 @@ int init_module(void)
return 0;
}
-void cleanup_module(void)
+static void __exit kretprobe_exit(void)
{
unregister_kretprobe(&my_kretprobe);
printk("kretprobe unregistered\n");
@@ -578,6 +597,8 @@ void cleanup_module(void)
my_kretprobe.nmissed, probed_func);
}
+module_init(kretprobe_init)
+module_exit(kretprobe_exit)
MODULE_LICENSE("GPL");
----- cut here -----
@@ -590,3 +611,5 @@ messages.)
For additional information on Kprobes, refer to the following URLs:
http://www-106.ibm.com/developerworks/library/l-kprobes.html?ca=dgr-lnxw42Kprobe
http://www.redhat.com/magazine/005mar05/features/kprobes/
+http://www-users.cs.umn.edu/~boutcher/kprobes/
+http://www.linuxsymposium.org/2006/linuxsymposium_procv2.pdf (pages 101-115)
diff --git a/Documentation/laptop-mode.txt b/Documentation/laptop-mode.txt
index 5696e879449b..c487186eb2b9 100644
--- a/Documentation/laptop-mode.txt
+++ b/Documentation/laptop-mode.txt
@@ -152,7 +152,7 @@ loaded on demand while the application executes) and sequentially accessed data
DO_REMOUNTS:
The control script automatically remounts any mounted journaled filesystems
-with approriate commit interval options. When this option is set to 0, this
+with appropriate commit interval options. When this option is set to 0, this
feature is disabled.
DO_REMOUNT_NOATIME:
diff --git a/Documentation/lockdep-design.txt b/Documentation/lockdep-design.txt
index 00d93605bfd3..488773018152 100644
--- a/Documentation/lockdep-design.txt
+++ b/Documentation/lockdep-design.txt
@@ -36,6 +36,28 @@ The validator tracks lock-class usage history into 5 separate state bits:
- 'ever used' [ == !unused ]
+When locking rules are violated, these 4 state bits are presented in the
+locking error messages, inside curlies. A contrived example:
+
+ modprobe/2287 is trying to acquire lock:
+ (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
+
+ but task is already holding lock:
+ (&sio_locks[i].lock){--..}, at: [<c02867fd>] mutex_lock+0x21/0x24
+
+
+The bit position indicates hardirq, softirq, hardirq-read,
+softirq-read respectively, and the character displayed in each
+indicates:
+
+ '.' acquired while irqs disabled
+ '+' acquired in irq context
+ '-' acquired with irqs enabled
+ '?' read acquired in irq context with irqs enabled.
+
+Unused mutexes cannot be part of the cause of an error.
+
+
Single-lock state rules:
------------------------
@@ -111,7 +133,7 @@ cases there is an inherent "natural" ordering between the two objects
(defined by the properties of the hierarchy), and the kernel grabs the
locks in this fixed order on each of the objects.
-An example of such an object hieararchy that results in "nested locking"
+An example of such an object hierarchy that results in "nested locking"
is that of a "whole disk" block-dev object and a "partition" block-dev
object; the partition is "part of" the whole device and as long as one
always takes the whole disk lock as a higher lock than the partition
@@ -136,11 +158,11 @@ enum bdev_bd_mutex_lock_class
In this case the locking is done on a bdev object that is known to be a
partition.
-The validator treats a lock that is taken in such a nested fasion as a
+The validator treats a lock that is taken in such a nested fashion as a
separate (sub)class for the purposes of validation.
Note: When changing code to use the _nested() primitives, be careful and
-check really thoroughly that the hiearchy is correctly mapped; otherwise
+check really thoroughly that the hierarchy is correctly mapped; otherwise
you can get false positives or false negatives.
Proof of 100% correctness:
@@ -148,7 +170,7 @@ Proof of 100% correctness:
The validator achieves perfect, mathematical 'closure' (proof of locking
correctness) in the sense that for every simple, standalone single-task
-locking sequence that occured at least once during the lifetime of the
+locking sequence that occurred at least once during the lifetime of the
kernel, the validator proves it with a 100% certainty that no
combination and timing of these locking sequences can cause any class of
lock related deadlock. [*]
diff --git a/Documentation/m68k/kernel-options.txt b/Documentation/m68k/kernel-options.txt
index d5d3f064f552..1c41db21d3c1 100644
--- a/Documentation/m68k/kernel-options.txt
+++ b/Documentation/m68k/kernel-options.txt
@@ -415,7 +415,7 @@ switch to another mode once Linux has started.
The first 3 parameters of this sub-option should be obvious: <xres>,
<yres> and <depth> give the dimensions of the screen and the number of
-planes (depth). The depth is is the logarithm to base 2 of the number
+planes (depth). The depth is the logarithm to base 2 of the number
of colors possible. (Or, the other way round: The number of colors is
2^depth).
diff --git a/Documentation/mca.txt b/Documentation/mca.txt
index 60913354cb7d..aabce4ad90f9 100644
--- a/Documentation/mca.txt
+++ b/Documentation/mca.txt
@@ -177,7 +177,7 @@ Currently, there are a number of MCA-specific device drivers.
with clones that have a different adapter id than the original
NE/2.
-6) Future Domain MCS-600/700, OEM'd IBM Fast SCSI Aapter/A and
+6) Future Domain MCS-600/700, OEM'd IBM Fast SCSI Adapter/A and
Reply Sound Blaster/SCSI (SCSI part)
Better support for these cards than the driver for ISA.
Supports multiple cards with IRQ sharing.
diff --git a/Documentation/md.txt b/Documentation/md.txt
index 0668f9dc9d29..2202f5dc8ac2 100644
--- a/Documentation/md.txt
+++ b/Documentation/md.txt
@@ -62,7 +62,7 @@ be reconstructed (due to no parity).
For this reason, md will normally refuse to start such an array. This
requires the sysadmin to take action to explicitly start the array
-desipite possible corruption. This is normally done with
+despite possible corruption. This is normally done with
mdadm --assemble --force ....
This option is not really available if the array has the root
@@ -154,11 +154,12 @@ contains further md-specific information about the device.
All md devices contain:
level
- a text file indicating the 'raid level'. This may be a standard
- numerical level prefixed by "RAID-" - e.g. "RAID-5", or some
- other name such as "linear" or "multipath".
+ a text file indicating the 'raid level'. e.g. raid0, raid1,
+ raid5, linear, multipath, faulty.
If no raid level has been set yet (array is still being
- assembled), this file will be empty.
+ assembled), the value will reflect whatever has been written
+ to it, which may be a name like the above, or may be a number
+ such as '0', '5', etc.
raid_disks
a text file with a simple number indicating the number of devices
@@ -174,7 +175,7 @@ All md devices contain:
raid levels that involve striping (1,4,5,6,10). The address space
of the array is conceptually divided into chunks and consecutive
chunks are striped onto neighbouring devices.
- The size should be atleast PAGE_SIZE (4k) and should be a power
+ 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
component_size
@@ -192,14 +193,6 @@ All md devices contain:
1.2 (newer format in varying locations) or "none" indicating that
the kernel isn't managing metadata at all.
- level
- The raid 'level' for this array. The name will often (but not
- always) be the same as the name of the module that implements the
- level. To be auto-loaded the module must have an alias
- md-$LEVEL e.g. md-raid5
- This can be written only while the array is being assembled, not
- after it is started.
-
layout
The "layout" for the array for the particular level. This is
simply a number that is interpretted differently by different
@@ -221,8 +214,8 @@ All md devices contain:
safe_mode_delay
When an md array has seen no write requests for a certain period
of time, it will be marked as 'clean'. When another write
- request arrive, the array is marked as 'dirty' before the write
- commenses. This is known as 'safe_mode'.
+ request arrives, the array is marked as 'dirty' before the write
+ commences. This is known as 'safe_mode'.
The 'certain period' is controlled by this file which stores the
period as a number of seconds. The default is 200msec (0.200).
Writing a value of 0 disables safemode.
@@ -314,8 +307,8 @@ Each directory contains:
This applies only to raid1 arrays.
spare - device is working, but not a full member.
This includes spares that are in the process
- of being recoverred to
- This list make grow in future.
+ of being recovered to
+ This list may grow in future.
This can be written to.
Writing "faulty" simulates a failure on the device.
Writing "remove" removes the device from the array.
@@ -337,7 +330,7 @@ Each directory contains:
This gives the role that the device has in the array. It will
either be 'none' if the device is not active in the array
(i.e. is a spare or has failed) or an integer less than the
- 'raid_disks' number for the array indicating which possition
+ 'raid_disks' number for the array indicating which position
it currently fills. This can only be set while assembling an
array. A device for which this is set is assumed to be working.
@@ -360,7 +353,7 @@ in the array. These are named
rdNN
-where 'NN' is the possition in the array, starting from 0.
+where 'NN' is the position in the array, starting from 0.
So for a 3 drive array there will be rd0, rd1, rd2.
These are symbolic links to the appropriate 'dev-XXX' entry.
Thus, for example,
@@ -410,6 +403,15 @@ also have
than sectors, this my be larger than the number of actual errors
by a factor of the number of sectors in a page.
+ bitmap_set_bits
+ If the array has a write-intent bitmap, then writing to this
+ attribute can set bits in the bitmap, indicating that a resync
+ would need to check the corresponding blocks. Either individual
+ numbers or start-end pairs can be written. Multiple numbers
+ can be separated by a space.
+ Note that the numbers are 'bit' numbers, not 'block' numbers.
+ They should be scaled by the bitmap_chunksize.
+
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
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 46b9b389df35..7f790f66ec68 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -670,7 +670,7 @@ effectively random order, despite the write barrier issued by CPU 1:
In the above example, CPU 2 perceives that B is 7, despite the load of *C
-(which would be B) coming after the the LOAD of C.
+(which would be B) coming after the LOAD of C.
If, however, a data dependency barrier were to be placed between the load of C
and the load of *C (ie: B) on CPU 2:
@@ -1898,7 +1898,7 @@ queue before processing any further requests:
smp_wmb();
<A:modify v=2> <C:busy>
<C:queue v=2>
- p = &b; q = p;
+ p = &v; q = p;
<D:request p>
<B:modify p=&v> <D:commit p=&v>
<D:read p>
@@ -1915,7 +1915,7 @@ Whilst most CPUs do imply a data dependency barrier on the read when a memory
access depends on a read, not all do, so it may not be relied on.
Other CPUs may also have split caches, but must coordinate between the various
-cachelets for normal memory accesss. The semantics of the Alpha removes the
+cachelets for normal memory accesses. The semantics of the Alpha removes the
need for coordination in absence of memory barriers.
diff --git a/Documentation/mono.txt b/Documentation/mono.txt
index 807a0c7b4737..e8e1758e87da 100644
--- a/Documentation/mono.txt
+++ b/Documentation/mono.txt
@@ -26,7 +26,7 @@ other program after you have done the following:
the kernel (CONFIG_BINFMT_MISC) and set it up properly.
If you choose to compile it as a module, you will have
to insert it manually with modprobe/insmod, as kmod
- can not be easily supported with binfmt_misc.
+ cannot be easily supported with binfmt_misc.
Read the file 'binfmt_misc.txt' in this directory to know
more about the configuration process.
diff --git a/Documentation/networking/3c509.txt b/Documentation/networking/3c509.txt
index 867a99f88c68..0643e3b7168c 100644
--- a/Documentation/networking/3c509.txt
+++ b/Documentation/networking/3c509.txt
@@ -126,7 +126,7 @@ packets faster than they can be removed from the card. This should be rare
or impossible in normal operation. Possible causes of this error report are:
- a "green" mode enabled that slows the processor down when there is no
- keyboard activitiy.
+ keyboard activity.
- some other device or device driver hogging the bus or disabling interrupts.
Check /proc/interrupts for excessive interrupt counts. The timer tick
diff --git a/Documentation/networking/NAPI_HOWTO.txt b/Documentation/networking/NAPI_HOWTO.txt
index 54376e8249c1..93af3e87c65b 100644
--- a/Documentation/networking/NAPI_HOWTO.txt
+++ b/Documentation/networking/NAPI_HOWTO.txt
@@ -35,7 +35,7 @@ Legend:
packets out of the rx ring. Note from this that the lower the
load the more we could clean up the rxring
"Ndone" == is the converse of "Done". Note again, that the higher
-the load the more times we couldnt clean up the rxring.
+the load the more times we couldn't clean up the rxring.
Observe that:
when the NIC receives 890Kpackets/sec only 17 rx interrupts are generated.
diff --git a/Documentation/networking/arcnet-hardware.txt b/Documentation/networking/arcnet-hardware.txt
index 30a5f01403d3..731de411513c 100644
--- a/Documentation/networking/arcnet-hardware.txt
+++ b/Documentation/networking/arcnet-hardware.txt
@@ -139,7 +139,7 @@ And now to the cabling. What you can connect together:
5. An active hub to passive hub.
-Remember, that you can not connect two passive hubs together. The power loss
+Remember that you cannot connect two passive hubs together. The power loss
implied by such a connection is too high for the net to operate reliably.
An example of a typical ARCnet network:
diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt
index afac780445cd..de809e58092f 100644
--- a/Documentation/networking/bonding.txt
+++ b/Documentation/networking/bonding.txt
@@ -192,6 +192,17 @@ or, for backwards compatibility, the option value. E.g.,
arp_interval
Specifies the ARP link monitoring frequency in milliseconds.
+
+ The ARP monitor works by periodically checking the slave
+ devices to determine whether they have sent or received
+ traffic recently (the precise criteria depends upon the
+ bonding mode, and the state of the slave). Regular traffic is
+ generated via ARP probes issued for the addresses specified by
+ the arp_ip_target option.
+
+ This behavior can be modified by the arp_validate option,
+ below.
+
If ARP monitoring is used in an etherchannel compatible mode
(modes 0 and 2), the switch should be configured in a mode
that evenly distributes packets across all links. If the
@@ -213,6 +224,54 @@ arp_ip_target
maximum number of targets that can be specified is 16. The
default value is no IP addresses.
+arp_validate
+
+ Specifies whether or not ARP probes and replies should be
+ validated in the active-backup mode. This causes the ARP
+ monitor to examine the incoming ARP requests and replies, and
+ only consider a slave to be up if it is receiving the
+ appropriate ARP traffic.
+
+ Possible values are:
+
+ none or 0
+
+ No validation is performed. This is the default.
+
+ active or 1
+
+ Validation is performed only for the active slave.
+
+ backup or 2
+
+ Validation is performed only for backup slaves.
+
+ all or 3
+
+ Validation is performed for all slaves.
+
+ For the active slave, the validation checks ARP replies to
+ confirm that they were generated by an arp_ip_target. Since
+ backup slaves do not typically receive these replies, the
+ validation performed for backup slaves is on the ARP request
+ sent out via the active slave. It is possible that some
+ switch or network configurations may result in situations
+ wherein the backup slaves do not receive the ARP requests; in
+ such a situation, validation of backup slaves must be
+ disabled.
+
+ This option is useful in network configurations in which
+ multiple bonding hosts are concurrently issuing ARPs to one or
+ more targets beyond a common switch. Should the link between
+ the switch and target fail (but not the switch itself), the
+ probe traffic generated by the multiple bonding instances will
+ fool the standard ARP monitor into considering the links as
+ still up. Use of the arp_validate option can resolve this, as
+ the ARP monitor will only consider ARP requests and replies
+ associated with its own instance of bonding.
+
+ This option was added in bonding version 3.1.0.
+
downdelay
Specifies the time, in milliseconds, to wait before disabling
@@ -964,7 +1023,7 @@ Changing a Bond's Configuration
files located in /sys/class/net/<bond name>/bonding
The names of these files correspond directly with the command-
-line parameters described elsewhere in in this file, and, with the
+line parameters described elsewhere in this file, and, with the
exception of arp_ip_target, they accept the same values. To see the
current setting, simply cat the appropriate file.
diff --git a/Documentation/networking/cs89x0.txt b/Documentation/networking/cs89x0.txt
index 188beb7d6a17..64896470e279 100644
--- a/Documentation/networking/cs89x0.txt
+++ b/Documentation/networking/cs89x0.txt
@@ -227,7 +227,7 @@ configuration options are available on the command line:
* media=rj45 - specify media type
or media=bnc
or media=aui
- or medai=auto
+ or media=auto
* duplex=full - specify forced half/full/autonegotiate duplex
or duplex=half
or duplex=auto
@@ -584,7 +584,7 @@ of four ways after installing and or configuring the CS8900/20-based adapter:
1.) The system does not boot properly (or at all).
- 2.) The driver can not communicate with the adapter, reporting an "Adapter
+ 2.) The driver cannot communicate with the adapter, reporting an "Adapter
not found" error message.
3.) You cannot connect to the network or the driver will not load.
@@ -684,7 +684,7 @@ ethernet@crystal.cirrus.com) and request that you be registered for automatic
software-update notification.
Cirrus Logic maintains a web page at http://www.cirrus.com with the
-the latest drivers and technical publications.
+latest drivers and technical publications.
6.4 Current maintainer
diff --git a/Documentation/networking/cxgb.txt b/Documentation/networking/cxgb.txt
index 76324638626b..20a887615c4a 100644
--- a/Documentation/networking/cxgb.txt
+++ b/Documentation/networking/cxgb.txt
@@ -56,7 +56,7 @@ FEATURES
ethtool -C eth0 rx-usecs 100
- You may also provide a timer latency value while disabling adpative-rx:
+ You may also provide a timer latency value while disabling adaptive-rx:
ethtool -C <interface> adaptive-rx off rx-usecs <microseconds>
@@ -172,7 +172,7 @@ PERFORMANCE
smaller window prevents congestion and facilitates better pacing,
especially if/when MAC level flow control does not work well or when it is
not supported on the machine. Experimentation may be necessary to attain
- the correct value. This method is provided as a starting point fot the
+ the correct value. This method is provided as a starting point for the
correct receive buffer size.
Setting the min, max, and default receive buffer (RX_WINDOW) size is
performed in the same manner as single connection.
diff --git a/Documentation/networking/decnet.txt b/Documentation/networking/decnet.txt
index e6c39c5831f5..badb7480ea62 100644
--- a/Documentation/networking/decnet.txt
+++ b/Documentation/networking/decnet.txt
@@ -82,7 +82,7 @@ ethernet address of your ethernet card has to be set according to the DECnet
address of the node in order for it to be autoconfigured (and then appear in
/proc/net/decnet_dev). There is a utility available at the above
FTP sites called dn2ethaddr which can compute the correct ethernet
-address to use. The address can be set by ifconfig either before at
+address to use. The address can be set by ifconfig either before or
at the time the device is brought up. If you are using RedHat you can
add the line:
diff --git a/Documentation/networking/dl2k.txt b/Documentation/networking/dl2k.txt
index d460492037ef..10e8490fa406 100644
--- a/Documentation/networking/dl2k.txt
+++ b/Documentation/networking/dl2k.txt
@@ -173,7 +173,7 @@ Installing the Driver
Parameter Description
=====================
-You can install this driver without any addtional parameter. However, if you
+You can install this driver without any additional parameter. However, if you
are going to have extensive functions then it is necessary to set extra
parameter. Below is a list of the command line parameters supported by the
Linux device
@@ -222,7 +222,7 @@ rx_timeout=n - Rx DMA wait time for an interrupt.
reach timeout of n * 640 nano seconds.
Set proper rx_coalesce and rx_timeout can
reduce congestion collapse and overload which
- has been a bottlenect for high speed network.
+ has been a bottleneck for high speed network.
For example, rx_coalesce=10 rx_timeout=800.
that is, hardware assert only 1 interrupt
diff --git a/Documentation/networking/dmfe.txt b/Documentation/networking/dmfe.txt
index 046363552d09..b1b7499dd9d3 100644
--- a/Documentation/networking/dmfe.txt
+++ b/Documentation/networking/dmfe.txt
@@ -34,7 +34,7 @@ Next you should configure your network interface with a command similar to :
ifconfig eth0 172.22.3.18
^^^^^^^^^^^
- Your IP Adress
+ Your IP Address
Then you may have to modify the default routing table with command :
diff --git a/Documentation/networking/driver.txt b/Documentation/networking/driver.txt
index a9ad58b49cc5..4f7da5a2bf4f 100644
--- a/Documentation/networking/driver.txt
+++ b/Documentation/networking/driver.txt
@@ -37,7 +37,7 @@ Transmit path guidelines:
...
}
- And then at the end of your TX reclaimation event handling:
+ And then at the end of your TX reclamation event handling:
if (netif_queue_stopped(dp->dev) &&
TX_BUFFS_AVAIL(dp) > (MAX_SKB_FRAGS + 1))
diff --git a/Documentation/networking/e1000.txt b/Documentation/networking/e1000.txt
index 71fe15af356c..5c0a5cc03998 100644
--- a/Documentation/networking/e1000.txt
+++ b/Documentation/networking/e1000.txt
@@ -350,7 +350,7 @@ Additional Configurations
As an example, if you install the e1000 driver for two PRO/1000 adapters
(eth0 and eth1) and set the speed and duplex to 10full and 100half, add
- the following to modules.conf or or modprobe.conf:
+ the following to modules.conf or modprobe.conf:
alias eth0 e1000
alias eth1 e1000
diff --git a/Documentation/networking/fib_trie.txt b/Documentation/networking/fib_trie.txt
index f50d0c673c57..0723db7f8495 100644
--- a/Documentation/networking/fib_trie.txt
+++ b/Documentation/networking/fib_trie.txt
@@ -79,7 +79,7 @@ trie_rebalance()
resize()
Analyzes a tnode and optimizes the child array size by either inflating
- or shrinking it repeatedly until it fullfills the criteria for optimal
+ or shrinking it repeatedly until it fulfills the criteria for optimal
level compression. This part follows the original paper pretty closely
and there may be some room for experimentation here.
diff --git a/Documentation/networking/gen_stats.txt b/Documentation/networking/gen_stats.txt
index c3297f79c137..70e6275b757a 100644
--- a/Documentation/networking/gen_stats.txt
+++ b/Documentation/networking/gen_stats.txt
@@ -79,8 +79,8 @@ Rate Estimator:
0) Prepare an estimator attribute. Most likely this would be in user
space. The value of this TLV should contain a tc_estimator structure.
- As usual, such a TLV nees to be 32 bit aligned and therefore the
- length needs to be appropriately set etc. The estimator interval
+ As usual, such a TLV needs to be 32 bit aligned and therefore the
+ length needs to be appropriately set, etc. The estimator interval
and ewma log need to be converted to the appropriate values.
tc_estimator.c::tc_setup_estimator() is advisable to be used as the
conversion routine. It does a few clever things. It takes a time
@@ -103,8 +103,8 @@ In the kernel when setting up:
else
failed
-From now on, everytime you dump my_rate_est_stats it will contain
-uptodate info.
+From now on, every time you dump my_rate_est_stats it will contain
+up-to-date info.
Once you are done, call gen_kill_estimator(my_basicstats,
my_rate_est_stats) Make sure that my_basicstats and my_rate_est_stats
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 935e298f674a..fd3c0c012351 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -495,7 +495,7 @@ icmp_errors_use_inbound_ifaddr - BOOLEAN
Note that if no primary address exists for the interface selected,
then the primary address of the first non-loopback interface that
- has one will be used regarldess of this setting.
+ has one will be used regardless of this setting.
Default: 0
@@ -787,7 +787,7 @@ accept_ra_defrtr - BOOLEAN
disabled if accept_ra is disabled.
accept_ra_pinfo - BOOLEAN
- Learn Prefix Inforamtion in Router Advertisement.
+ Learn Prefix Information in Router Advertisement.
Functional default: enabled if accept_ra is enabled.
disabled if accept_ra is disabled.
diff --git a/Documentation/networking/netconsole.txt b/Documentation/networking/netconsole.txt
index 53618fb1a717..1caa6c734691 100644
--- a/Documentation/networking/netconsole.txt
+++ b/Documentation/networking/netconsole.txt
@@ -52,6 +52,6 @@ messages is high, but should have no other impact.
Netconsole was designed to be as instantaneous as possible, to
enable the logging of even the most critical kernel bugs. It works
from IRQ contexts as well, and does not enable interrupts while
-sending packets. Due to these unique needs, configuration can not
+sending packets. Due to these unique needs, configuration cannot
be more automatic, and some fundamental limitations will remain:
only IP networks, UDP packets and ethernet devices are supported.
diff --git a/Documentation/networking/netif-msg.txt b/Documentation/networking/netif-msg.txt
index 18ad4cea6259..c967ddb90d0b 100644
--- a/Documentation/networking/netif-msg.txt
+++ b/Documentation/networking/netif-msg.txt
@@ -40,7 +40,7 @@ History
Per-interface rather than per-driver message level setting.
More selective control over the type of messages emitted.
- The netif_msg recommandation adds these features with only a minor
+ The netif_msg recommendation adds these features with only a minor
complexity and code size increase.
The recommendation is the following points
diff --git a/Documentation/networking/operstates.txt b/Documentation/networking/operstates.txt
index 4a21d9bb836b..c9074f9b78bb 100644
--- a/Documentation/networking/operstates.txt
+++ b/Documentation/networking/operstates.txt
@@ -2,7 +2,7 @@
1. Introduction
Linux distinguishes between administrative and operational state of an
-interface. Admininstrative state is the result of "ip link set dev
+interface. Administrative state is the result of "ip link set dev
<dev> up or down" and reflects whether the administrator wants to use
the device for traffic.
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt
index aaf99d5f0dad..12a008a5c221 100644
--- a/Documentation/networking/packet_mmap.txt
+++ b/Documentation/networking/packet_mmap.txt
@@ -66,7 +66,7 @@ the following process:
[setup] socket() -------> creation of the capture socket
setsockopt() ---> allocation of the circular buffer (ring)
- mmap() ---------> maping of the allocated buffer to the
+ mmap() ---------> mapping of the allocated buffer to the
user process
[capture] poll() ---------> to wait for incoming packets
@@ -93,7 +93,7 @@ The destruction of the socket and all associated resources
is done by a simple call to close(fd).
Next I will describe PACKET_MMAP settings and it's constraints,
-also the maping of the circular buffer in the user process and
+also the mapping of the circular buffer in the user process and
the use of this buffer.
--------------------------------------------------------------------------------
@@ -153,8 +153,8 @@ we will get the following buffer structure:
A frame can be of any size with the only condition it can fit in a block. A block
can only hold an integer number of frames, or in other words, a frame cannot
-be spawn accross two blocks so there are some datails you have to take into
-account when choosing the frame_size. See "Maping and use of the circular
+be spawned accross two blocks, so there are some details you have to take into
+account when choosing the frame_size. See "Mapping and use of the circular
buffer (ring)".
@@ -215,8 +215,8 @@ called pg_vec, its size limits the number of blocks that can be allocated.
block #1
-kmalloc allocates any number of bytes of phisically contiguous memory from
-a pool of pre-determined sizes. This pool of memory is mantained by the slab
+kmalloc allocates any number of bytes of physically contiguous memory from
+a pool of pre-determined sizes. This pool of memory is maintained by the slab
allocator which is at the end the responsible for doing the allocation and
hence which imposes the maximum memory that kmalloc can allocate.
@@ -262,7 +262,7 @@ i386 architecture:
<pagesize> = 4096 bytes
<max-order> = 11
-and a value for <frame size> of 2048 byteas. These parameters will yield
+and a value for <frame size> of 2048 bytes. These parameters will yield
<block number> = 131072/4 = 32768 blocks
<block size> = 4096 << 11 = 8 MiB.
@@ -278,7 +278,7 @@ an i386 kernel's memory size is limited to 1GiB.
All memory allocations are not freed until the socket is closed. The memory
allocations are done with GFP_KERNEL priority, this basically means that
the allocation can wait and swap other process' memory in order to allocate
-the nececessary memory, so normally limits can be reached.
+the necessary memory, so normally limits can be reached.
Other constraints
-------------------
@@ -296,7 +296,7 @@ the following (from include/linux/if_packet.h):
- struct tpacket_hdr
- pad to TPACKET_ALIGNMENT=16
- struct sockaddr_ll
- - Gap, chosen so that packet data (Start+tp_net) alignes to
+ - Gap, chosen so that packet data (Start+tp_net) aligns to
TPACKET_ALIGNMENT=16
- Start+tp_mac: [ Optional MAC header ]
- Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16.
@@ -311,14 +311,14 @@ the following (from include/linux/if_packet.h):
tp_frame_size must be a multiple of TPACKET_ALIGNMENT
tp_frame_nr must be exactly frames_per_block*tp_block_nr
-Note that tp_block_size should be choosed to be a power of two or there will
+Note that tp_block_size should be chosen to be a power of two or there will
be a waste of memory.
--------------------------------------------------------------------------------
-+ Maping and use of the circular buffer (ring)
++ Mapping and use of the circular buffer (ring)
--------------------------------------------------------------------------------
-The maping of the buffer in the user process is done with the conventional
+The mapping of the buffer in the user process is done with the conventional
mmap function. Even the circular buffer is compound of several physically
discontiguous blocks of memory, they are contiguous to the user space, hence
just one call to mmap is needed:
diff --git a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt
index 44f2f769e865..c8eee23be8c0 100644
--- a/Documentation/networking/pktgen.txt
+++ b/Documentation/networking/pktgen.txt
@@ -7,7 +7,7 @@ Date: 041221
Enable CONFIG_NET_PKTGEN to compile and build pktgen.o either in kernel
or as module. Module is preferred. insmod pktgen if needed. Once running
-pktgen creates a thread on each CPU where each thread has affinty it's CPU.
+pktgen creates a thread on each CPU where each thread has affinity to its CPU.
Monitoring and controlling is done via /proc. Easiest to select a suitable
a sample script and configure.
@@ -18,7 +18,7 @@ root 129 0.3 0.0 0 0 ? SW 2003 523:20 [pktgen/0]
root 130 0.3 0.0 0 0 ? SW 2003 509:50 [pktgen/1]
-For montoring and control pktgen creates:
+For monitoring and control pktgen creates:
/proc/net/pktgen/pgctrl
/proc/net/pktgen/kpktgend_X
/proc/net/pktgen/ethX
@@ -32,7 +32,7 @@ Running:
Stopped: eth1
Result: OK: max_before_softirq=10000
-Most important the devices assigend to thread. Note! A device can only belong
+Most important the devices assigned to thread. Note! A device can only belong
to one thread.
@@ -100,6 +100,7 @@ Examples:
are: IPSRC_RND #IP Source is random (between min/max),
IPDST_RND, UDPSRC_RND,
UDPDST_RND, MACSRC_RND, MACDST_RND
+ MPLS_RND, VID_RND, SVID_RND
pgset "udp_src_min 9" set UDP source port min, If < udp_src_max, then
cycle through the port range.
@@ -125,13 +126,28 @@ Examples:
pgset "mpls 0" turn off mpls (or any invalid argument works too!)
+ pgset "vlan_id 77" set VLAN ID 0-4095
+ pgset "vlan_p 3" set priority bit 0-7 (default 0)
+ pgset "vlan_cfi 0" set canonical format identifier 0-1 (default 0)
+
+ pgset "svlan_id 22" set SVLAN ID 0-4095
+ pgset "svlan_p 3" set priority bit 0-7 (default 0)
+ pgset "svlan_cfi 0" set canonical format identifier 0-1 (default 0)
+
+ pgset "vlan_id 9999" > 4095 remove vlan and svlan tags
+ pgset "svlan 9999" > 4095 remove svlan tag
+
+
+ pgset "tos XX" set former IPv4 TOS field (e.g. "tos 28" for AF11 no ECN, default 00)
+ pgset "traffic_class XX" set former IPv6 TRAFFIC CLASS (e.g. "traffic_class B8" for EF no ECN, default 00)
+
pgset stop aborts injection. Also, ^C aborts generator.
Example scripts
===============
-A collection of small tutorial scripts for pktgen is in expamples dir.
+A collection of small tutorial scripts for pktgen is in examples dir.
pktgen.conf-1-1 # 1 CPU 1 dev
pktgen.conf-1-2 # 1 CPU 2 dev
diff --git a/Documentation/networking/s2io.txt b/Documentation/networking/s2io.txt
index bd528ffbeb4b..4bde53e85f3f 100644
--- a/Documentation/networking/s2io.txt
+++ b/Documentation/networking/s2io.txt
@@ -126,7 +126,7 @@ However, you may want to set PCI latency timer to 248.
#setpci -d 17d5:* LATENCY_TIMER=f8
For detailed description of the PCI registers, please see Xframe User Guide.
b. Use 2-buffer mode. This results in large performance boost on
-on certain platforms(eg. SGI Altix, IBM xSeries).
+certain platforms(eg. SGI Altix, IBM xSeries).
c. Ensure Receive Checksum offload is enabled. Use "ethtool -K ethX" command to
set/verify this option.
d. Enable NAPI feature(in kernel configuration Device Drivers ---> Network
diff --git a/Documentation/networking/sk98lin.txt b/Documentation/networking/sk98lin.txt
index 7837c53fd5fe..4e1cc745ec63 100644
--- a/Documentation/networking/sk98lin.txt
+++ b/Documentation/networking/sk98lin.txt
@@ -180,7 +180,7 @@ To set the driver parameters in this file, proceed as follows:
1. Insert a line of the form :
options sk98lin ...
For "...", the same syntax is required as described for the command
- line paramaters of modprobe below.
+ line parameters of modprobe below.
2. To activate the new parameters, either reboot your computer
or
unload and reload the driver.
@@ -320,7 +320,7 @@ Parameter: Moderation
Values: None, Static, Dynamic
Default: None
-Interrupt moderation is employed to limit the maxmimum number of interrupts
+Interrupt moderation is employed to limit the maximum number of interrupts
the driver has to serve. That is, one or more interrupts (which indicate any
transmit or receive packet to be processed) are queued until the driver
processes them. When queued interrupts are to be served, is determined by the
@@ -364,9 +364,9 @@ Parameter: IntsPerSec
Values: 30...40000 (interrupts per second)
Default: 2000
-This parameter is only used, if either static or dynamic interrupt moderation
-is used on a network adapter card. Using this paramter if no moderation is
-applied, will lead to no action performed.
+This parameter is only used if either static or dynamic interrupt moderation
+is used on a network adapter card. Using this parameter if no moderation is
+applied will lead to no action performed.
This parameter determines the length of any interrupt moderation interval.
Assuming that static interrupt moderation is to be used, an 'IntsPerSec'
@@ -484,7 +484,7 @@ If any problems occur during the installation process, check the
following list:
-Problem: The SK-98xx adapter can not be found by the driver.
+Problem: The SK-98xx adapter cannot be found by the driver.
Solution: In /proc/pci search for the following entry:
'Ethernet controller: SysKonnect SK-98xx ...'
If this entry exists, the SK-98xx or SK-98xx V2.0 adapter has
@@ -497,12 +497,12 @@ Solution: In /proc/pci search for the following entry:
www.syskonnect.com
Some COMPAQ machines have problems dealing with PCI under Linux.
- Linux. This problem is described in the 'PCI howto' document
+ This problem is described in the 'PCI howto' document
(included in some distributions or available from the
web, e.g. at 'www.linux.org').
-Problem: Programs such as 'ifconfig' or 'route' can not be found or the
+Problem: Programs such as 'ifconfig' or 'route' cannot be found or the
error message 'Operation not permitted' is displayed.
Reason: You are not logged in as user 'root'.
Solution: Logout and login as 'root' or change to 'root' via 'su'.
diff --git a/Documentation/networking/skfp.txt b/Documentation/networking/skfp.txt
index 3a419ed42f81..abfddf81e34a 100644
--- a/Documentation/networking/skfp.txt
+++ b/Documentation/networking/skfp.txt
@@ -81,7 +81,7 @@ Makes my life much easier :-)
If you run into problems during installation, check those items:
-Problem: The FDDI adapter can not be found by the driver.
+Problem: The FDDI adapter cannot be found by the driver.
Reason: Look in /proc/pci for the following entry:
'FDDI network controller: SysKonnect SK-FDDI-PCI ...'
If this entry exists, then the FDDI adapter has been
@@ -99,7 +99,7 @@ Reason: Look in /proc/pci for the following entry:
Problem: You want to use your computer as a router between
multiple IP subnetworks (using multiple adapters), but
- you can not reach computers in other subnetworks.
+ you cannot reach computers in other subnetworks.
Reason: Either the router's kernel is not configured for IP
forwarding or there is a problem with the routing table
and gateway configuration in at least one of the
diff --git a/Documentation/networking/slicecom.txt b/Documentation/networking/slicecom.txt
index 59cfd95121fb..2f04c9267f89 100644
--- a/Documentation/networking/slicecom.txt
+++ b/Documentation/networking/slicecom.txt
@@ -89,7 +89,7 @@ red: green: meaning:
- - no frame-sync, no signal received, or signal SNAFU.
- on "Everything is OK"
-on on Recepion is ok, but the remote end sends Remote Alarm
+on on Reception is ok, but the remote end sends Remote Alarm
on - The interface is unconfigured
-----------------------------------------------------------------
@@ -257,12 +257,12 @@ which begin with '//' are the comments.
// No alarms - Everything OK
//
// LOS - Loss Of Signal - No signal sensed on the input
-// AIS - Alarm Indication Signal - The remot side sends '11111111'-s,
+// AIS - Alarm Indication Signal - The remote side sends '11111111'-s,
// it tells, that there's an error condition, or it's not
// initialised.
// AUXP - Auxiliary Pattern Indication - 01010101.. received.
// LFA - Loss of Frame Alignment - no frame sync received.
-// RRA - Receive Remote Alarm - the remote end's OK, but singnals error cond.
+// RRA - Receive Remote Alarm - the remote end's OK, but signals error cond.
// LMFA - Loss of CRC4 Multiframe Alignment - no CRC4 multiframe sync.
// NMF - No Multiframe alignment Found after 400 msec - no such alarm using
// no-crc4 or crc4 framing, see below.
@@ -364,6 +364,6 @@ Treat them very carefully, these can cause much trouble!
# echo >lbireg 0x1d 0x21
- - Swithing the loop off:
+ - Switching the loop off:
# echo >lbireg 0x1d 0x00
diff --git a/Documentation/networking/smctr.txt b/Documentation/networking/smctr.txt
index 4c866f5a0ee4..9af25b810c1f 100644
--- a/Documentation/networking/smctr.txt
+++ b/Documentation/networking/smctr.txt
@@ -11,7 +11,7 @@ This driver is rather simple to use. Select Y to Token Ring adapter support
in the kernel configuration. A choice for SMC Token Ring adapters will
appear. This drives supports all SMC ISA/MCA adapters. Choose this
option. I personally recommend compiling the driver as a module (M), but if you
-you would like to compile it staticly answer Y instead.
+you would like to compile it statically answer Y instead.
This driver supports multiple adapters without the need to load multiple copies
of the driver. You should be able to load up to 7 adapters without any kernel
diff --git a/Documentation/networking/tcp.txt b/Documentation/networking/tcp.txt
index 0fa300425575..0121edc3ba06 100644
--- a/Documentation/networking/tcp.txt
+++ b/Documentation/networking/tcp.txt
@@ -62,7 +62,7 @@ if needed and you will get the expected protocol. If you ask for an
unknown congestion method, then the sysctl attempt will fail.
If you remove a tcp congestion control module, then you will get the next
-available one. Since reno can not be built as a module, and can not be
+available one. Since reno cannot be built as a module, and cannot be
deleted, it will always be available.
How the new TCP output machine [nyi] works.
diff --git a/Documentation/networking/tms380tr.txt b/Documentation/networking/tms380tr.txt
index 179e527b9da1..c169a57bc925 100644
--- a/Documentation/networking/tms380tr.txt
+++ b/Documentation/networking/tms380tr.txt
@@ -24,7 +24,7 @@ This driver is rather simple to use. Select Y to Token Ring adapter support
in the kernel configuration. A choice for SysKonnect Token Ring adapters will
appear. This drives supports all SysKonnect ISA and PCI adapters. Choose this
option. I personally recommend compiling the driver as a module (M), but if you
-you would like to compile it staticly answer Y instead.
+you would like to compile it statically answer Y instead.
This driver supports multiple adapters without the need to load multiple copies
of the driver. You should be able to load up to 7 adapters without any kernel
diff --git a/Documentation/networking/vortex.txt b/Documentation/networking/vortex.txt
index 6091e5f6794f..6356d3faed36 100644
--- a/Documentation/networking/vortex.txt
+++ b/Documentation/networking/vortex.txt
@@ -359,13 +359,13 @@ steps you should take:
Eliminate some variables: try different cards, different
computers, different cables, different ports on the switch/hub,
- different versions of the kernel or ofthe driver, etc.
+ different versions of the kernel or of the driver, etc.
- OK, it's a driver problem.
You need to generate a report. Typically this is an email to the
maintainer and/or linux-net@vger.kernel.org. The maintainer's
- email address will be inthe driver source or in the MAINTAINERS file.
+ email address will be in the driver source or in the MAINTAINERS file.
- The contents of your report will vary a lot depending upon the
problem. If it's a kernel crash then you should refer to the
diff --git a/Documentation/networking/wan-router.txt b/Documentation/networking/wan-router.txt
index c96897aa08b6..0cf654147634 100644
--- a/Documentation/networking/wan-router.txt
+++ b/Documentation/networking/wan-router.txt
@@ -148,7 +148,7 @@ NEW IN THIS RELEASE
for async connections.
o Added the PPPCONFIG utility
- Used to configure the PPPD dameon for the
+ Used to configure the PPPD daemon for the
WANPIPE Async PPP and standard serial port.
The wancfg calls the pppconfig to configure
the pppd.
@@ -214,7 +214,7 @@ PRODUCT COMPONENTS AND RELATED FILES
/usr/local/wanrouter/patches/kdrivers:
Sources of the latest WANPIPE device drivers.
These are used to UPGRADE the linux kernel to the newest
- version if the kernel source has already been pathced with
+ version if the kernel source has already been patched with
WANPIPE drivers.
/usr/local/wanrouter/samples:
@@ -350,7 +350,7 @@ REVISION HISTORY
Available as a patch.
2.0.6 Aug 17, 1999 Increased debugging in statup scripts
- Fixed insallation bugs from 2.0.5
+ Fixed installation bugs from 2.0.5
Kernel patch works for both 2.2.10 and 2.2.11 kernels.
There is no functional difference between the two packages
@@ -434,11 +434,11 @@ beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix.
change.
beta1-2.1.5 Nov 15 2000
- o Fixed the MulitPort PPP Support for kernels 2.2.16 and above.
+ o Fixed the MultiPort PPP Support for kernels 2.2.16 and above.
2.2.X kernels only
o Secured the driver UDP debugging calls
- - All illegal netowrk debugging calls are reported to
+ - All illegal network debugging calls are reported to
the log.
- Defined a set of allowed commands, all other denied.
@@ -451,7 +451,7 @@ beta1-2.1.5 Nov 15 2000
o Keyboard Led Monitor/Debugger
- A new utilty /usr/sbin/wpkbdmon uses keyboard leds
- to convey operatinal statistic information of the
+ to convey operational statistic information of the
Sangoma WANPIPE cards.
NUM_LOCK = Line State (On=connected, Off=disconnected)
CAPS_LOCK = Tx data (On=transmitting, Off=no tx data)
@@ -470,7 +470,7 @@ beta1-2.1.5 Nov 15 2000
o Fixed the Frame Relay and Chdlc network interfaces so they are
compatible with libpcap libraries. Meaning, tcpdump, snort,
ethereal, and all other packet sniffers and debuggers work on
- all WANPIPE netowrk interfaces.
+ all WANPIPE network interfaces.
- Set the network interface encoding type to ARPHRD_PPP.
This tell the sniffers that data obtained from the
network interface is in pure IP format.
@@ -570,7 +570,7 @@ bata1-2.2.1 Feb 09 2001
Option to COMPILE WANPIPE modules against the currently
running kernel, thus no need for manual kernel and module
- re-compilatin.
+ re-compilation.
o Updates and Bug Fixes to wancfg utility.
diff --git a/Documentation/nfsroot.txt b/Documentation/nfsroot.txt
index 3cc953cb288f..719f9a9d60c0 100644
--- a/Documentation/nfsroot.txt
+++ b/Documentation/nfsroot.txt
@@ -11,7 +11,7 @@ Updated 2006 by Horms <horms@verge.net.au>
In order to use a diskless system, such as an X-terminal or printer server
for example, it is necessary for the root filesystem to be present on a
non-disk device. This may be an initramfs (see Documentation/filesystems/
-ramfs-rootfs-initramfs.txt), a ramdisk (see Documenation/initrd.txt) or a
+ramfs-rootfs-initramfs.txt), a ramdisk (see Documentation/initrd.txt) or a
filesystem mounted via NFS. The following text describes on how to use NFS
for the root filesystem. For the rest of this text 'client' means the
diskless system, and 'server' means the NFS server.
diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt
index b88ebe4d808c..7714f57caad5 100644
--- a/Documentation/nommu-mmap.txt
+++ b/Documentation/nommu-mmap.txt
@@ -116,6 +116,9 @@ FURTHER NOTES ON NO-MMU MMAP
(*) A list of all the mappings on the system is visible through /proc/maps in
no-MMU mode.
+ (*) A list of all the mappings in use by a process is visible through
+ /proc/<pid>/maps in no-MMU mode.
+
(*) Supplying MAP_FIXED or a requesting a particular mapping address will
result in an error.
@@ -125,6 +128,49 @@ FURTHER NOTES ON NO-MMU MMAP
error will result if they don't. This is most likely to be encountered
with character device files, pipes, fifos and sockets.
+
+==========================
+INTERPROCESS SHARED MEMORY
+==========================
+
+Both SYSV IPC SHM shared memory and POSIX shared memory is supported in NOMMU
+mode. The former through the usual mechanism, the latter through files created
+on ramfs or tmpfs mounts.
+
+
+=======
+FUTEXES
+=======
+
+Futexes are supported in NOMMU mode if the arch supports them. An error will
+be given if an address passed to the futex system call lies outside the
+mappings made by a process or if the mapping in which the address lies does not
+support futexes (such as an I/O chardev mapping).
+
+
+=============
+NO-MMU MREMAP
+=============
+
+The mremap() function is partially supported. It may change the size of a
+mapping, and may move it[*] if MREMAP_MAYMOVE is specified and if the new size
+of the mapping exceeds the size of the slab object currently occupied by the
+memory to which the mapping refers, or if a smaller slab object could be used.
+
+MREMAP_FIXED is not supported, though it is ignored if there's no change of
+address and the object does not need to be moved.
+
+Shared mappings may not be moved. Shareable mappings may not be moved either,
+even if they are not currently shared.
+
+The mremap() function must be given an exact match for base address and size of
+a previously mapped object. It may not be used to create holes in existing
+mappings, move parts of existing mappings or resize parts of mappings. It must
+act on a complete mapping.
+
+[*] Not currently supported.
+
+
============================================
PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT
============================================
diff --git a/Documentation/pci-error-recovery.txt b/Documentation/pci-error-recovery.txt
index 634d3e5b5756..6650af432523 100644
--- a/Documentation/pci-error-recovery.txt
+++ b/Documentation/pci-error-recovery.txt
@@ -172,7 +172,7 @@ is STEP 6 (Permanent Failure).
>>> a value of 0xff on read, and writes will be dropped. If the device
>>> driver attempts more than 10K I/O's to a frozen adapter, it will
>>> assume that the device driver has gone into an infinite loop, and
->>> it will panic the the kernel. There doesn't seem to be any other
+>>> it will panic the kernel. There doesn't seem to be any other
>>> way of stopping a device driver that insists on spinning on I/O.
STEP 2: MMIO Enabled
diff --git a/Documentation/pcieaer-howto.txt b/Documentation/pcieaer-howto.txt
new file mode 100644
index 000000000000..16c251230c82
--- /dev/null
+++ b/Documentation/pcieaer-howto.txt
@@ -0,0 +1,253 @@
+ The PCI Express Advanced Error Reporting Driver Guide HOWTO
+ T. Long Nguyen <tom.l.nguyen@intel.com>
+ Yanmin Zhang <yanmin.zhang@intel.com>
+ 07/29/2006
+
+
+1. Overview
+
+1.1 About this guide
+
+This guide describes the basics of the PCI Express Advanced Error
+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.3 What is the PCI Express AER Driver?
+
+PCI Express error signaling can occur on the PCI Express link itself
+or on behalf of transactions initiated on the link. PCI Express
+defines two error reporting paradigms: the baseline capability and
+the Advanced Error Reporting capability. The baseline capability is
+required of all PCI Express components providing a minimum defined
+set of error reporting requirements. Advanced Error Reporting
+capability is implemented with a PCI Express advanced error reporting
+extended capability structure providing more robust error reporting.
+
+The PCI Express AER driver provides the infrastructure to support PCI
+Express Advanced Error Reporting capability. The PCI Express AER
+driver provides three basic functions:
+
+- Gathers the comprehensive error information if errors occurred.
+- Reports error to the users.
+- Performs error recovery actions.
+
+AER driver only attaches root ports which support PCI-Express AER
+capability.
+
+
+2. User Guide
+
+2.1 Include the PCI Express AER Root Driver into the Linux Kernel
+
+The PCI Express AER Root driver is a Root Port service driver attached
+to the PCI Express Port Bus driver. If a user wants to use it, the driver
+has to be compiled. Option CONFIG_PCIEAER supports this capability. It
+depends on CONFIG_PCIEPORTBUS, so pls. set CONFIG_PCIEPORTBUS=y and
+CONFIG_PCIEAER = y.
+
+2.2 Load PCI Express AER Root Driver
+There is a case where a system has AER support in BIOS. Enabling the AER
+Root driver and having AER support in BIOS may result unpredictable
+behavior. To avoid this conflict, a successful load of the AER Root driver
+requires ACPI _OSC support in the BIOS to allow the AER Root driver to
+request for native control of AER. See the PCI FW 3.0 Specification for
+details regarding OSC usage. Currently, lots of firmwares don't provide
+_OSC support while they use PCI Express. To support such firmwares,
+forceload, a parameter of type bool, could enable AER to continue to
+be initiated although firmwares have no _OSC support. To enable the
+walkaround, pls. add aerdriver.forceload=y to kernel boot parameter line
+when booting kernel. Note that forceload=n by default.
+
+2.3 AER error output
+When a PCI-E AER error is captured, an error message will be outputed to
+console. If it's a correctable error, it is outputed as a warning.
+Otherwise, it is printed as an error. So users could choose different
+log level to filter out correctable error messages.
+
+Below shows an example.
++------ PCI-Express Device Error -----+
+Error Severity : Uncorrected (Fatal)
+PCIE Bus Error type : Transaction Layer
+Unsupported Request : First
+Requester ID : 0500
+VendorID=8086h, DeviceID=0329h, Bus=05h, Device=00h, Function=00h
+TLB Header:
+04000001 00200a03 05010000 00050100
+
+In the example, 'Requester ID' means the ID of the device who sends
+the error message to root port. Pls. refer to pci express specs for
+other fields.
+
+
+3. Developer Guide
+
+To enable AER aware support requires a software driver to configure
+the AER capability structure within its device and to provide callbacks.
+
+To support AER better, developers need understand how AER does work
+firstly.
+
+PCI Express errors are classified into two types: correctable errors
+and uncorrectable errors. This classification is based on the impacts
+of those errors, which may result in degraded performance or function
+failure.
+
+Correctable errors pose no impacts on the functionality of the
+interface. The PCI Express protocol can recover without any software
+intervention or any loss of data. These errors are detected and
+corrected by hardware. Unlike correctable errors, uncorrectable
+errors impact functionality of the interface. Uncorrectable errors
+can cause a particular transaction or a particular PCI Express link
+to be unreliable. Depending on those error conditions, uncorrectable
+errors are further classified into non-fatal errors and fatal errors.
+Non-fatal errors cause the particular transaction to be unreliable,
+but the PCI Express link itself is fully functional. Fatal errors, on
+the other hand, cause the link to be unreliable.
+
+When AER is enabled, a PCI Express device will automatically send an
+error message to the PCIE root port above it when the device captures
+an error. The Root Port, upon receiving an error reporting message,
+internally processes and logs the error message in its PCI Express
+capability structure. Error information being logged includes storing
+the error reporting agent's requestor ID into the Error Source
+Identification Registers and setting the error bits of the Root Error
+Status Register accordingly. If AER error reporting is enabled in Root
+Error Command Register, the Root Port generates an interrupt if an
+error is detected.
+
+Note that the errors as described above are related to the PCI Express
+hierarchy and links. These errors do not include any device specific
+errors because device specific errors will still get sent directly to
+the device driver.
+
+3.1 Configure the AER capability structure
+
+AER aware drivers of PCI Express component need change the device
+control registers to enable AER. They also could change AER registers,
+including mask and severity registers. Helper function
+pci_enable_pcie_error_reporting could be used to enable AER. See
+section 3.3.
+
+3.2. Provide callbacks
+
+3.2.1 callback reset_link to reset pci express link
+
+This callback is used to reset the pci express physical link when a
+fatal error happens. The root port aer service driver provides a
+default reset_link function, but different upstream ports might
+have different specifications to reset pci express link, so all
+upstream ports should provide their own reset_link functions.
+
+In struct pcie_port_service_driver, a new pointer, reset_link, is
+added.
+
+pci_ers_result_t (*reset_link) (struct pci_dev *dev);
+
+Section 3.2.2.2 provides more detailed info on when to call
+reset_link.
+
+3.2.2 PCI error-recovery callbacks
+
+The PCI Express AER Root driver uses error callbacks to coordinate
+with downstream device drivers associated with a hierarchy in question
+when performing error recovery actions.
+
+Data struct pci_driver has a pointer, err_handler, to point to
+pci_error_handlers who consists of a couple of callback function
+pointers. AER driver follows the rules defined in
+pci-error-recovery.txt except pci express specific parts (e.g.
+reset_link). Pls. refer to pci-error-recovery.txt for detailed
+definitions of the callbacks.
+
+Below sections specify when to call the error callback functions.
+
+3.2.2.1 Correctable errors
+
+Correctable errors pose no impacts on the functionality of
+the interface. The PCI Express protocol can recover without any
+software intervention or any loss of data. These errors do not
+require any recovery actions. The AER driver clears the device's
+correctable error status register accordingly and logs these errors.
+
+3.2.2.2 Non-correctable (non-fatal and fatal) errors
+
+If an error message indicates a non-fatal error, performing link reset
+at upstream is not required. The AER driver calls error_detected(dev,
+pci_channel_io_normal) to all drivers associated within a hierarchy in
+question. for example,
+EndPoint<==>DownstreamPort B<==>UpstreamPort A<==>RootPort.
+If Upstream port A captures an AER error, the hierarchy consists of
+Downstream port B and EndPoint.
+
+A driver may return PCI_ERS_RESULT_CAN_RECOVER,
+PCI_ERS_RESULT_DISCONNECT, or PCI_ERS_RESULT_NEED_RESET, depending on
+whether it can recover or the AER driver calls mmio_enabled as next.
+
+If an error message indicates a fatal error, kernel will broadcast
+error_detected(dev, pci_channel_io_frozen) to all drivers within
+a hierarchy in question. Then, performing link reset at upstream is
+necessary. As different kinds of devices might use different approaches
+to reset link, AER port service driver is required to provide the
+function to reset link. Firstly, kernel looks for if the upstream
+component has an aer driver. If it has, kernel uses the reset_link
+callback of the aer driver. If the upstream component has no aer driver
+and the port is downstream port, we will use the aer driver of the
+root port who reports the AER error. As for upstream ports,
+they should provide their own aer service drivers with reset_link
+function. If error_detected returns PCI_ERS_RESULT_CAN_RECOVER and
+reset_link returns PCI_ERS_RESULT_RECOVERED, the error handling goes
+to mmio_enabled.
+
+3.3 helper functions
+
+3.3.1 int pci_find_aer_capability(struct pci_dev *dev);
+pci_find_aer_capability locates the PCI Express AER capability
+in the device configuration space. If the device doesn't support
+PCI-Express AER, the function returns 0.
+
+3.3.2 int pci_enable_pcie_error_reporting(struct pci_dev *dev);
+pci_enable_pcie_error_reporting enables the device to send error
+messages to root port when an error is detected. Note that devices
+don't enable the error reporting by default, so device drivers need
+call this function to enable it.
+
+3.3.3 int pci_disable_pcie_error_reporting(struct pci_dev *dev);
+pci_disable_pcie_error_reporting disables the device to send error
+messages to root port when an error is detected.
+
+3.3.4 int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
+pci_cleanup_aer_uncorrect_error_status cleanups the uncorrectable
+error status register.
+
+3.4 Frequent Asked Questions
+
+Q: What happens if a PCI Express device driver does not provide an
+error recovery handler (pci_driver->err_handler is equal to NULL)?
+
+A: The devices attached with the driver won't be recovered. If the
+error is fatal, kernel will print out warning messages. Please refer
+to section 3 for more information.
+
+Q: What happens if an upstream port service driver does not provide
+callback reset_link?
+
+A: Fatal error recovery will fail if the errors are reported by the
+upstream ports who are attached by the service driver.
+
+Q: How does this infrastructure deal with driver that is not PCI
+Express aware?
+
+A: This infrastructure calls the error callback functions of the
+driver when an error happens. But if the driver is not aware of
+PCI Express, the device might not report its own errors to root
+port.
+
+Q: What modifications will that driver need to make it compatible
+with the PCI Express AER Root driver?
+
+A: It could call the helper functions to enable AER in devices and
+cleanup uncorrectable status register. Pls. refer to section 3.3.
+
diff --git a/Documentation/pi-futex.txt b/Documentation/pi-futex.txt
index 5d61dacd21f6..9a5bc8651c29 100644
--- a/Documentation/pi-futex.txt
+++ b/Documentation/pi-futex.txt
@@ -118,4 +118,4 @@ properties of futexes, and all four combinations are possible: futex,
robust-futex, PI-futex, robust+PI-futex.
More details about priority inheritance can be found in
-Documentation/rtmutex.txt.
+Documentation/rt-mutex.txt.
diff --git a/Documentation/pm.txt b/Documentation/pm.txt
index 79c0f32a760e..da8589a0e07d 100644
--- a/Documentation/pm.txt
+++ b/Documentation/pm.txt
@@ -18,10 +18,10 @@ enabled by default). If a working ACPI implementation is found, the
ACPI driver will override and disable APM, otherwise the APM driver
will be used.
-No sorry, you can not have both ACPI and APM enabled and running at
+No, sorry, you cannot have both ACPI and APM enabled and running at
once. Some people with broken ACPI or broken APM implementations
would like to use both to get a full set of working features, but you
-simply can not mix and match the two. Only one power management
+simply cannot mix and match the two. Only one power management
interface can be in control of the machine at once. Think about it..
User-space Daemons
@@ -106,7 +106,7 @@ void pm_unregister_all(pm_callback cback);
*
* Returns: 0 if the request is successful
* EINVAL if the request is not supported
- * EBUSY if the device is now busy and can not handle the request
+ * EBUSY if the device is now busy and cannot handle the request
* ENOMEM if the device was unable to handle the request due to memory
*
* Details: The device request callback will be called before the
diff --git a/Documentation/pnp.txt b/Documentation/pnp.txt
index 9529c9c9fd59..9ff966bf76e6 100644
--- a/Documentation/pnp.txt
+++ b/Documentation/pnp.txt
@@ -222,7 +222,7 @@ static struct pnp_driver serial_pnp_driver = {
.remove = serial_pnp_remove,
};
-* name and id_table can not be NULL.
+* name and id_table cannot be NULL.
4.) register the driver
ex:
diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt
index 73fc87e5dc38..24edf25b3bb7 100644
--- a/Documentation/power/pci.txt
+++ b/Documentation/power/pci.txt
@@ -326,7 +326,7 @@ A reference implementation
This is a typical implementation. Drivers can slightly change the order
of the operations in the implementation, ignore some operations or add
-more deriver specific operations in it, but drivers should do something like
+more driver specific operations in it, but drivers should do something like
this on the whole.
5. Resources
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index 823b2cf6e3dc..9ea2208b43b5 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -156,7 +156,7 @@ instead set the PF_NOFREEZE process flag when creating the thread (and
be very carefull).
-Q: What is the difference between between "platform", "shutdown" and
+Q: What is the difference between "platform", "shutdown" and
"firmware" in /sys/power/disk?
A:
@@ -175,8 +175,8 @@ reliable.
Q: I do not understand why you have such strong objections to idea of
selective suspend.
-A: Do selective suspend during runtime power managment, that's okay. But
-its useless for suspend-to-disk. (And I do not see how you could use
+A: Do selective suspend during runtime power management, that's okay. But
+it's useless for suspend-to-disk. (And I do not see how you could use
it for suspend-to-ram, I hope you do not want that).
Lets see, so you suggest to
@@ -211,7 +211,7 @@ slowness may not matter to you. It can always be fixed later.
For devices like disk it does matter, you do not want to spindown for
FREEZE.
-Q: After resuming, system is paging heavilly, leading to very bad interactivity.
+Q: After resuming, system is paging heavily, leading to very bad interactivity.
A: Try running
diff --git a/Documentation/power/tricks.txt b/Documentation/power/tricks.txt
index c6d58d3da133..3b26bb502a4a 100644
--- a/Documentation/power/tricks.txt
+++ b/Documentation/power/tricks.txt
@@ -9,7 +9,7 @@ If you want to trick swsusp/S3 into working, you might want to try:
* turn off APIC and preempt
-* use ext2. At least it has working fsck. [If something seemes to go
+* use ext2. At least it has working fsck. [If something seems to go
wrong, force fsck when you have a chance]
* turn off modules
diff --git a/Documentation/power/userland-swsusp.txt b/Documentation/power/userland-swsusp.txt
index 94058220aaf0..64755e9285db 100644
--- a/Documentation/power/userland-swsusp.txt
+++ b/Documentation/power/userland-swsusp.txt
@@ -91,7 +91,7 @@ unfreeze user space processes frozen by SNAPSHOT_UNFREEZE if they are
still frozen when the device is being closed).
Currently it is assumed that the userland utilities reading/writing the
-snapshot image from/to the kernel will use a swap parition, called the resume
+snapshot image from/to the kernel will use a swap partition, called the resume
partition, as storage space. However, this is not really required, as they
can use, for example, a special (blank) suspend partition or a file on a partition
that is unmounted before SNAPSHOT_ATOMIC_SNAPSHOT and mounted afterwards.
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index d859faa3a463..2b358498d095 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -16,7 +16,7 @@ problem for S1 standby, because hardware should retain its state over
that.
We either have to run video BIOS during early resume, or interpret it
-using vbetool later, or maybe nothing is neccessary on particular
+using vbetool later, or maybe nothing is necessary on particular
system because video state is preserved. Unfortunately different
methods work on different systems, and no known method suits all of
them.
diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index 5c0ba235f5a5..27b457c09729 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -145,7 +145,7 @@ it with special cases.
in case you are entering the kernel with MMU enabled
and a non-1:1 mapping.
- r5 : NULL (as to differenciate with method a)
+ r5 : NULL (as to differentiate with method a)
Note about SMP entry: Either your firmware puts your other
CPUs in some sleep loop or spin loop in ROM where you can get
@@ -245,7 +245,7 @@ the block to RAM before passing it to the kernel.
---------
The kernel is entered with r3 pointing to an area of memory that is
- roughtly described in include/asm-powerpc/prom.h by the structure
+ roughly described in include/asm-powerpc/prom.h by the structure
boot_param_header:
struct boot_param_header {
@@ -335,7 +335,7 @@ struct boot_param_header {
"compact" format for the tree itself that is however not backward
compatible. You should always generate a structure of the highest
version defined at the time of your implementation. Currently
- that is version 16, unless you explicitely aim at being backward
+ that is version 16, unless you explicitly aim at being backward
compatible.
- last_comp_version
@@ -418,9 +418,9 @@ zero terminated string and is mandatory for version 1 to 3 of the
format definition (as it is in Open Firmware). Version 0x10 makes it
optional as it can generate it from the unit name defined below.
-There is also a "unit name" that is used to differenciate nodes with
+There is also a "unit name" that is used to differentiate nodes with
the same name at the same level, it is usually made of the node
-name's, the "@" sign, and a "unit address", which definition is
+names, the "@" sign, and a "unit address", which definition is
specific to the bus type the node sits on.
The unit name doesn't exist as a property per-se but is included in
@@ -550,11 +550,11 @@ Here's the basic structure of a single node:
* [child nodes if any]
* token OF_DT_END_NODE (that is 0x00000002)
-So the node content can be summmarised as a start token, a full path,
-a list of properties, a list of child node and an end token. Every
+So the node content can be summarised as a start token, a full path,
+a list of properties, a list of child nodes, and an end token. Every
child node is a full node structure itself as defined above.
-4) Device tree 'strings" block
+4) Device tree "strings" block
In order to save space, property names, which are generally redundant,
are stored separately in the "strings" block. This block is simply the
@@ -573,7 +573,7 @@ implementation of Open Firmware or an implementation compatible with
the Open Firmware client interface, those properties will be created
by the trampoline code in the kernel's prom_init() file. For example,
that's where you'll have to add code to detect your board model and
-set the platform number. However, when using the flatenned device-tree
+set the platform number. However, when using the flattened device-tree
entry point, there is no prom_init() pass, and thus you have to
provide those properties yourself.
@@ -630,12 +630,11 @@ like address space bits, you'll have to add a bus translator to the
prom_parse.c file of the recent kernels for your bus type.
The "reg" property only defines addresses and sizes (if #size-cells
-is
-non-0) within a given bus. In order to translate addresses upward
+is non-0) within a given bus. In order to translate addresses upward
(that is into parent bus addresses, and possibly into cpu physical
addresses), all busses must contain a "ranges" property. If the
"ranges" property is missing at a given level, it's assumed that
-translation isn't possible. The format of the "ranges" proprety for a
+translation isn't possible. The format of the "ranges" property for a
bus is a list of:
bus address, parent bus address, size
@@ -689,7 +688,7 @@ is present).
4) Note about node and property names and character set
-------------------------------------------------------
-While open firmware provides more flexibe usage of 8859-1, this
+While open firmware provides more flexible usage of 8859-1, this
specification enforces more strict rules. Nodes and properties should
be comprised only of ASCII characters 'a' to 'z', '0' to
'9', ',', '.', '_', '+', '#', '?', and '-'. Node names additionally
@@ -732,12 +731,12 @@ address which can extend beyond that limit.
that typically get driven by the same platform code in the
kernel, you would use a different "model" property but put a
value in "compatible". The kernel doesn't directly use that
- value (see /chosen/linux,platform for how the kernel choses a
+ value (see /chosen/linux,platform for how the kernel chooses a
platform type) but it is generally useful.
The root node is also generally where you add additional properties
specific to your board like the serial number if any, that sort of
- thing. it is recommended that if you add any "custom" property whose
+ thing. It is recommended that if you add any "custom" property whose
name may clash with standard defined ones, you prefix them with your
vendor name and a comma.
@@ -817,7 +816,7 @@ address which can extend beyond that limit.
your board. It's a list of addresses/sizes concatenated
together, with the number of cells of each defined by the
#address-cells and #size-cells of the root node. For example,
- with both of these properties beeing 2 like in the example given
+ with both of these properties being 2 like in the example given
earlier, a 970 based machine with 6Gb of RAM could typically
have a "reg" property here that looks like:
@@ -970,7 +969,7 @@ device-tree in another format. The currently supported formats are:
- "asm": assembly language file. This is a file that can be
sourced by gas to generate a device-tree "blob". That file can
then simply be added to your Makefile. Additionally, the
- assembly file exports some symbols that can be use
+ assembly file exports some symbols that can be used.
The syntax of the dtc tool is
@@ -984,10 +983,10 @@ generated. Supported versions are 1,2,3 and 16. The default is
currently version 3 but that may change in the future to version 16.
Additionally, dtc performs various sanity checks on the tree, like the
-uniqueness of linux,phandle properties, validity of strings, etc...
+uniqueness of linux, phandle properties, validity of strings, etc...
The format of the .dts "source" file is "C" like, supports C and C++
-style commments.
+style comments.
/ {
}
@@ -1069,13 +1068,13 @@ while all this has been defined and implemented.
around. It contains no internal offsets or pointers for this
purpose.
- - An example of code for iterating nodes & retreiving properties
+ - An example of code for iterating nodes & retrieving properties
directly from the flattened tree format can be found in the kernel
file arch/ppc64/kernel/prom.c, look at scan_flat_dt() function,
- it's usage in early_init_devtree(), and the corresponding various
+ its usage in early_init_devtree(), and the corresponding various
early_init_dt_scan_*() callbacks. That code can be re-used in a
GPL bootloader, and as the author of that code, I would be happy
- do discuss possible free licencing to any vendor who wishes to
+ to discuss possible free licencing to any vendor who wishes to
integrate all or part of this code into a non-GPL bootloader.
@@ -1441,6 +1440,258 @@ platforms are moved over to use the flattened-device-tree model.
descriptor-types-mask = <012b0ebf>;
};
+ h) Board Control and Status (BCSR)
+
+ Required properties:
+
+ - device_type : Should be "board-control"
+ - reg : Offset and length of the register set for the device
+
+ Example:
+
+ bcsr@f8000000 {
+ device_type = "board-control";
+ reg = <f8000000 8000>;
+ };
+
+ i) Freescale QUICC Engine module (QE)
+ This represents qe module that is installed on PowerQUICC II Pro.
+ Hopefully it will merge backward compatibility with CPM/CPM2.
+ 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
+ more nodes and properties would be extended in the future.
+
+ i) Root QE device
+
+ Required properties:
+ - device_type : should be "qe";
+ - model : precise model of the QE, Can be "QE", "CPM", or "CPM2"
+ - reg : offset and length of the device registers.
+ - bus-frequency : the clock frequency for QUICC Engine.
+
+ Recommended properties
+ - brg-frequency : the internal clock source frequency for baud-rate
+ generators in Hz.
+
+ Example:
+ qe@e0100000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "qe";
+ model = "QE";
+ ranges = <0 e0100000 00100000>;
+ reg = <e0100000 480>;
+ brg-frequency = <0>;
+ bus-frequency = <179A7B00>;
+ }
+
+
+ ii) SPI (Serial Peripheral Interface)
+
+ Required properties:
+ - device_type : should be "spi".
+ - compatible : should be "fsl_spi".
+ - mode : the spi operation mode, it can be "cpu" or "qe".
+ - reg : Offset and length of the register set for the device
+ - interrupts : <a b> where a is the interrupt number and b is a
+ field that represents an encoding of the sense and level
+ information for the interrupt. This should be encoded based on
+ the information in section 2) depending on the type of interrupt
+ controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+
+ Example:
+ spi@4c0 {
+ device_type = "spi";
+ compatible = "fsl_spi";
+ reg = <4c0 40>;
+ interrupts = <82 0>;
+ interrupt-parent = <700>;
+ mode = "cpu";
+ };
+
+
+ iii) USB (Universal Serial Bus Controller)
+
+ Required properties:
+ - device_type : should be "usb".
+ - compatible : could be "qe_udc" or "fhci-hcd".
+ - mode : the could be "host" or "slave".
+ - reg : Offset and length of the register set for the device
+ - interrupts : <a b> where a is the interrupt number and b is a
+ field that represents an encoding of the sense and level
+ information for the interrupt. This should be encoded based on
+ the information in section 2) depending on the type of interrupt
+ controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+
+ Example(slave):
+ usb@6c0 {
+ device_type = "usb";
+ compatible = "qe_udc";
+ reg = <6c0 40>;
+ interrupts = <8b 0>;
+ interrupt-parent = <700>;
+ mode = "slave";
+ };
+
+
+ iv) UCC (Unified Communications Controllers)
+
+ Required properties:
+ - device_type : should be "network", "hldc", "uart", "transparent"
+ "bisync" or "atm".
+ - compatible : could be "ucc_geth" or "fsl_atm" and so on.
+ - model : should be "UCC".
+ - device-id : the ucc number(1-8), corresponding to UCCx in UM.
+ - reg : Offset and length of the register set for the device
+ - interrupts : <a b> where a is the interrupt number and b is a
+ field that represents an encoding of the sense and level
+ information for the interrupt. This should be encoded based on
+ the information in section 2) depending on the type of interrupt
+ controller you have.
+ - interrupt-parent : the phandle for the interrupt controller that
+ services interrupts for this device.
+ - pio-handle : The phandle for the Parallel I/O port configuration.
+ - rx-clock : represents the UCC receive clock source.
+ 0x00 : clock source is disabled;
+ 0x1~0x10 : clock source is BRG1~BRG16 respectively;
+ 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+ - tx-clock: represents the UCC transmit clock source;
+ 0x00 : clock source is disabled;
+ 0x1~0x10 : clock source is BRG1~BRG16 respectively;
+ 0x11~0x28: clock source is QE_CLK1~QE_CLK24 respectively.
+
+ Required properties for network device_type:
+ - mac-address : list of bytes representing the ethernet address.
+ - phy-handle : The phandle for the PHY connected to this controller.
+
+ Example:
+ ucc@2000 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <1>;
+ reg = <2000 200>;
+ interrupts = <a0 0>;
+ interrupt-parent = <700>;
+ mac-address = [ 00 04 9f 00 23 23 ];
+ rx-clock = "none";
+ tx-clock = "clk9";
+ phy-handle = <212000>;
+ pio-handle = <140001>;
+ };
+
+
+ v) Parallel I/O Ports
+
+ This node configures Parallel I/O ports for CPUs with QE support.
+ The node should reside in the "soc" node of the tree. For each
+ device that using parallel I/O ports, a child node should be created.
+ See the definition of the Pin configuration nodes below for more
+ information.
+
+ Required properties:
+ - device_type : should be "par_io".
+ - reg : offset to the register set and its length.
+ - num-ports : number of Parallel I/O ports
+
+ Example:
+ par_io@1400 {
+ reg = <1400 100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "par_io";
+ num-ports = <7>;
+ ucc_pin@01 {
+ ......
+ };
+
+
+ vi) Pin configuration nodes
+
+ Required properties:
+ - linux,phandle : phandle of this node; likely referenced by a QE
+ device.
+ - pio-map : array of pin configurations. Each pin is defined by 6
+ integers. The six numbers are respectively: port, pin, dir,
+ open_drain, assignment, has_irq.
+ - port : port number of the pin; 0-6 represent port A-G in UM.
+ - pin : pin number in the port.
+ - dir : direction of the pin, should encode as follows:
+
+ 0 = The pin is disabled
+ 1 = The pin is an output
+ 2 = The pin is an input
+ 3 = The pin is I/O
+
+ - open_drain : indicates the pin is normal or wired-OR:
+
+ 0 = The pin is actively driven as an output
+ 1 = The pin is an open-drain driver. As an output, the pin is
+ driven active-low, otherwise it is three-stated.
+
+ - 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
+ interrupts.
+
+ Example:
+ ucc_pin@01 {
+ linux,phandle = <140001>;
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0 3 1 0 1 0 /* TxD0 */
+ 0 4 1 0 1 0 /* TxD1 */
+ 0 5 1 0 1 0 /* TxD2 */
+ 0 6 1 0 1 0 /* TxD3 */
+ 1 6 1 0 3 0 /* TxD4 */
+ 1 7 1 0 1 0 /* TxD5 */
+ 1 9 1 0 2 0 /* TxD6 */
+ 1 a 1 0 2 0 /* TxD7 */
+ 0 9 2 0 1 0 /* RxD0 */
+ 0 a 2 0 1 0 /* RxD1 */
+ 0 b 2 0 1 0 /* RxD2 */
+ 0 c 2 0 1 0 /* RxD3 */
+ 0 d 2 0 1 0 /* RxD4 */
+ 1 1 2 0 2 0 /* RxD5 */
+ 1 0 2 0 2 0 /* RxD6 */
+ 1 4 2 0 2 0 /* RxD7 */
+ 0 7 1 0 1 0 /* TX_EN */
+ 0 8 1 0 1 0 /* TX_ER */
+ 0 f 2 0 1 0 /* RX_DV */
+ 0 10 2 0 1 0 /* RX_ER */
+ 0 0 2 0 1 0 /* RX_CLK */
+ 2 9 1 0 3 0 /* GTX_CLK - CLK10 */
+ 2 8 2 0 1 0>; /* GTX125 - CLK9 */
+ };
+
+ vii) Multi-User RAM (MURAM)
+
+ Required properties:
+ - device_type : should be "muram".
+ - mode : the could be "host" or "slave".
+ - ranges : Should be defined as specified in 1) to describe the
+ translation of MURAM addresses.
+ - data-only : sub-node which defines the address area under MURAM
+ bus that can be allocated as data/parameter
+
+ Example:
+
+ muram@10000 {
+ device_type = "muram";
+ ranges = <0 00010000 0000c000>;
+
+ data-only@0{
+ reg = <0 c000>;
+ };
+ };
More devices will be defined as this spec matures.
diff --git a/Documentation/powerpc/eeh-pci-error-recovery.txt b/Documentation/powerpc/eeh-pci-error-recovery.txt
index 3764dd4b12cb..4530d1bf0286 100644
--- a/Documentation/powerpc/eeh-pci-error-recovery.txt
+++ b/Documentation/powerpc/eeh-pci-error-recovery.txt
@@ -90,7 +90,7 @@ EEH-isolated, there is a firmware call it can make to determine if
this is the case. If so, then the device driver should put itself
into a consistent state (given that it won't be able to complete any
pending work) and start recovery of the card. Recovery normally
-would consist of reseting the PCI device (holding the PCI #RST
+would consist of resetting the PCI device (holding the PCI #RST
line high for two seconds), followed by setting up the device
config space (the base address registers (BAR's), latency timer,
cache line size, interrupt line, and so on). This is followed by a
@@ -116,7 +116,7 @@ At this time, a generic EEH recovery mechanism has been implemented,
so that individual device drivers do not need to be modified to support
EEH recovery. This generic mechanism piggy-backs on the PCI hotplug
infrastructure, and percolates events up through the userspace/udev
-infrastructure. Followiing is a detailed description of how this is
+infrastructure. Following is a detailed description of how this is
accomplished.
EEH must be enabled in the PHB's very early during the boot process,
diff --git a/Documentation/powerpc/hvcs.txt b/Documentation/powerpc/hvcs.txt
index 1e38166f4e54..f93462c5db25 100644
--- a/Documentation/powerpc/hvcs.txt
+++ b/Documentation/powerpc/hvcs.txt
@@ -259,7 +259,7 @@ This index of '2' means that in order to connect to vty-server adapter
It should be noted that due to the system hotplug I/O capabilities of a
system the /dev/hvcs* entry that interacts with a particular vty-server
-adapter is not guarenteed to remain the same across system reboots. Look
+adapter is not guaranteed to remain the same across system reboots. Look
in the Q & A section for more on this issue.
---------------------------------------------------------------------------
diff --git a/Documentation/prio_tree.txt b/Documentation/prio_tree.txt
index 2fbb0c49bc5b..3aa68f9a117b 100644
--- a/Documentation/prio_tree.txt
+++ b/Documentation/prio_tree.txt
@@ -88,7 +88,7 @@ path which is not desirable. Hence, we do not optimize the height of the
heap-and-size indexed overflow-sub-trees using prio_tree->index_bits.
Instead the overflow sub-trees are indexed using full BITS_PER_LONG bits
of size_index. This may lead to skewed sub-trees because most of the
-higher significant bits of the size_index are likely to be be 0 (zero). In
+higher significant bits of the size_index are likely to be 0 (zero). In
the example above, all 3 overflow-sub-trees are skewed. This may marginally
affect the performance. However, processes rarely map many vmas with the
same start_vm_pgoff but different end_vm_pgoffs. Therefore, we normally
diff --git a/Documentation/rocket.txt b/Documentation/rocket.txt
index a10678004451..1d8582990435 100644
--- a/Documentation/rocket.txt
+++ b/Documentation/rocket.txt
@@ -97,7 +97,7 @@ a range of I/O addresses for it to use. The first RocketPort card
requires a 68-byte contiguous block of I/O addresses, starting at one
of the following: 0x100h, 0x140h, 0x180h, 0x200h, 0x240h, 0x280h,
0x300h, 0x340h, 0x380h. This I/O address must be reflected in the DIP
-switiches of *all* of the Rocketport cards.
+switches of *all* of the Rocketport cards.
The second, third, and fourth RocketPort cards require a 64-byte
contiguous block of I/O addresses, starting at one of the following
@@ -107,7 +107,7 @@ second, third, and fourth Rocketport cards (if present) are set via
software control. The DIP switch settings for the I/O address must be
set to the value of the first Rocketport cards.
-In order to destinguish each of the card from the others, each card
+In order to distinguish each of the card from the others, each card
must have a unique board ID set on the dip switches. The first
Rocketport board must be set with the DIP switches corresponding to
the first board, the second board must be set with the DIP switches
@@ -120,7 +120,7 @@ conflict with any other cards in the system, including other
RocketPort cards. Below, you will find a list of commonly used I/O
address ranges which may be in use by other devices in your system.
On a Linux system, "cat /proc/ioports" will also be helpful in
-identifying what I/O addresses are being used by devics on your
+identifying what I/O addresses are being used by devices on your
system.
Remember, the FIRST RocketPort uses 68 I/O addresses. So, if you set it
diff --git a/Documentation/rpc-cache.txt b/Documentation/rpc-cache.txt
index 5f757c8cf979..8a382bea6808 100644
--- a/Documentation/rpc-cache.txt
+++ b/Documentation/rpc-cache.txt
@@ -24,7 +24,7 @@ The common code handles such things as:
- general cache lookup with correct locking
- supporting 'NEGATIVE' as well as positive entries
- allowing an EXPIRED time on cache items, and removing
- items after they expire, and are no longe in-use.
+ items after they expire, and are no longer in-use.
- making requests to user-space to fill in cache entries
- allowing user-space to directly set entries in the cache
- delaying RPC requests that depend on as-yet incomplete
@@ -53,7 +53,7 @@ Creating a Cache
structure
void cache_put(struct kref *)
This is called when the last reference to an item is
- is dropped. The pointer passed is to the 'ref' field
+ dropped. The pointer passed is to the 'ref' field
in the cache_head. cache_put should release any
references create by 'cache_init' and, if CACHE_VALID
is set, any references created by cache_update.
diff --git a/Documentation/rt-mutex-design.txt b/Documentation/rt-mutex-design.txt
index c472ffacc2f6..4b736d24da7a 100644
--- a/Documentation/rt-mutex-design.txt
+++ b/Documentation/rt-mutex-design.txt
@@ -333,11 +333,11 @@ cmpxchg is basically the following function performed atomically:
unsigned long _cmpxchg(unsigned long *A, unsigned long *B, unsigned long *C)
{
- unsigned long T = *A;
- if (*A == *B) {
- *A = *C;
- }
- return T;
+ unsigned long T = *A;
+ if (*A == *B) {
+ *A = *C;
+ }
+ return T;
}
#define cmpxchg(a,b,c) _cmpxchg(&a,&b,&c)
@@ -582,7 +582,7 @@ contention).
try_to_take_rt_mutex is used every time the task tries to grab a mutex in the
slow path. The first thing that is done here is an atomic setting of
the "Has Waiters" flag of the mutex's owner field. Yes, this could really
-be false, because if the the mutex has no owner, there are no waiters and
+be false, because if the mutex has no owner, there are no waiters and
the current task also won't have any waiters. But we don't have the lock
yet, so we assume we are going to be a waiter. The reason for this is to
play nice for those architectures that do have CMPXCHG. By setting this flag
@@ -735,7 +735,7 @@ do have CMPXCHG, that check is done in the fast path, but it is still needed
in the slow path too. If a waiter of a mutex woke up because of a signal
or timeout between the time the owner failed the fast path CMPXCHG check and
the grabbing of the wait_lock, the mutex may not have any waiters, thus the
-owner still needs to make this check. If there are no waiters than the mutex
+owner still needs to make this check. If there are no waiters then the mutex
owner field is set to NULL, the wait_lock is released and nothing more is
needed.
diff --git a/Documentation/s390/3270.txt b/Documentation/s390/3270.txt
index 0a044e647d2d..7a5c73a7ed7f 100644
--- a/Documentation/s390/3270.txt
+++ b/Documentation/s390/3270.txt
@@ -111,9 +111,7 @@ Here are the installation steps in detail:
config3270.sh. Inspect the output script it produces,
/tmp/mkdev3270, and then run that script. This will create the
necessary character special device files and make the necessary
- changes to /etc/inittab. If you have selected DEVFS, the driver
- itself creates the device files, and /tmp/mkdev3270 only changes
- /etc/inittab.
+ changes to /etc/inittab.
Then notify /sbin/init that /etc/inittab has changed, by issuing
the telinit command with the q operand:
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
index 59d1166d41ee..d684a6ac69a8 100644
--- a/Documentation/s390/CommonIO
+++ b/Documentation/s390/CommonIO
@@ -66,7 +66,7 @@ Command line parameters
When a device is un-ignored, device recognition and sensing is performed and
the device driver will be notified if possible, so the device will become
- available to the system.
+ available to the system. Note that un-ignoring is performed asynchronously.
You can also add ranges of devices to be ignored by piping to
/proc/cio_ignore; "add <device range>, <device range>, ..." will ignore the
diff --git a/Documentation/s390/Debugging390.txt b/Documentation/s390/Debugging390.txt
index 844c03fe7921..4dd25ee549e9 100644
--- a/Documentation/s390/Debugging390.txt
+++ b/Documentation/s390/Debugging390.txt
@@ -8,8 +8,8 @@
Overview of Document:
=====================
This document is intended to give an good overview of how to debug
-Linux for s/390 & z/Architecture it isn't intended as a complete reference & not a
-tutorial on the fundamentals of C & assembly, it dosen't go into
+Linux for s/390 & z/Architecture. It isn't intended as a complete reference & not a
+tutorial on the fundamentals of C & assembly. It doesn't go into
390 IO in any detail. It is intended to complement the documents in the
reference section below & any other worthwhile references you get.
@@ -88,7 +88,7 @@ s/390 z/Architecture
0 0 Reserved ( must be 0 ) otherwise specification exception occurs.
1 1 Program Event Recording 1 PER enabled,
- PER is used to facilititate debugging e.g. single stepping.
+ PER is used to facilitate debugging e.g. single stepping.
2-4 2-4 Reserved ( must be 0 ).
@@ -163,7 +163,7 @@ s/390 z/Architecture
1 1 64 bit
32 1=31 bit addressing mode 0=24 bit addressing mode (for backward
- compatibility ), linux always runs with this bit set to 1
+ compatibility), linux always runs with this bit set to 1
33-64 Instruction address.
33-63 Reserved must be 0
@@ -188,7 +188,7 @@ Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Arch
are used by the processor itself for holding such information as exception indications &
entry points for exceptions.
Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture
-( there is a gap on z/Architecure too currently between 0xc00 & 1000 which linux uses ).
+( there is a gap on z/Architecture too currently between 0xc00 & 1000 which linux uses ).
The closest thing to this on traditional architectures is the interrupt
vector table. This is a good thing & does simplify some of the kernel coding
however it means that we now cannot catch stray NULL pointers in the
@@ -239,7 +239,7 @@ they go to 64 Bit.
On 390 our limitations & strengths make us slightly different.
For backward compatibility we are only allowed use 31 bits (2GB)
-of our 32 bit addresses,however, we use entirely separate address
+of our 32 bit addresses, however, we use entirely separate address
spaces for the user & kernel.
This means we can support 2GB of non Extended RAM on s/390, & more
@@ -317,9 +317,9 @@ Each process/thread under Linux for S390 has its own kernel task_struct
defined in linux/include/linux/sched.h
The S390 on initialisation & resuming of a process on a cpu sets
the __LC_KERNEL_STACK variable in the spare prefix area for this cpu
-( which we use for per processor globals).
+(which we use for per-processor globals).
-The kernel stack pointer is intimately tied with the task stucture for
+The kernel stack pointer is intimately tied with the task structure for
each processor as follows.
s/390
@@ -354,7 +354,7 @@ static inline struct task_struct * get_current(void)
}
i.e. just anding the current kernel stack pointer with the mask -8192.
-Thankfully because Linux dosen't have support for nested IO interrupts
+Thankfully because Linux doesn't have support for nested IO interrupts
& our devices have large buffers can survive interrupts being shut for
short amounts of time we don't need a separate stack for interrupts.
@@ -366,8 +366,8 @@ Register Usage & Stackframes on Linux for s/390 & z/Architecture
Overview:
---------
This is the code that gcc produces at the top & the bottom of
-each function, it usually is fairly consistent & similar from
-function to function & if you know its layout you can probalby
+each function. It usually is fairly consistent & similar from
+function to function & if you know its layout you can probably
make some headway in finding the ultimate cause of a problem
after a crash without a source level debugger.
@@ -394,7 +394,7 @@ i.e they aren't in registers & they aren't static.
back-chain:
This is a pointer to the stack pointer before entering a
framed functions ( see frameless function ) prologue got by
-deferencing the address of the current stack pointer,
+dereferencing the address of the current stack pointer,
i.e. got by accessing the 32 bit value at the stack pointers
current location.
@@ -724,7 +724,7 @@ This is useful for debugging because
1) You can double check whether the files you expect to be included are the ones
that are being included ( e.g. double check that you aren't going to the i386 asm directory ).
2) Check that macro definitions aren't clashing with typedefs,
-3) Check that definitons aren't being used before they are being included.
+3) Check that definitions aren't being used before they are being included.
4) Helps put the line emitting the error under the microscope if it contains macros.
For convenience the Linux kernel's makefile will do preprocessing automatically for you
@@ -840,12 +840,11 @@ using the strip command to make it a more reasonable size to boot it.
A source/assembly mixed dump of the kernel can be done with the line
objdump --source vmlinux > vmlinux.lst
-Also if the file isn't compiled -g this will output as much debugging information
-as it can ( e.g. function names ), however, this is very slow as it spends lots
-of time searching for debugging info, the following self explanitory line should be used
-instead if the code isn't compiled -g.
+Also, if the file isn't compiled -g, this will output as much debugging information
+as it can (e.g. function names). This is very slow as it spends lots
+of time searching for debugging info. The following self explanatory line should be used
+instead if the code isn't compiled -g, as it is much faster:
objdump --disassemble-all --syms vmlinux > vmlinux.lst
-as it is much faster
As hard drive space is valuble most of us use the following approach.
1) Look at the emitted psw on the console to find the crash address in the kernel.
@@ -861,7 +860,7 @@ Linux source tree.
6) rm /arch/s390/kernel/signal.o
7) make /arch/s390/kernel/signal.o
8) watch the gcc command line emitted
-9) type it in again or alernatively cut & paste it on the console adding the -g option.
+9) type it in again or alternatively cut & paste it on the console adding the -g option.
10) objdump --source arch/s390/kernel/signal.o > signal.lst
This will output the source & the assembly intermixed, as the snippet below shows
This will unfortunately output addresses which aren't the same
@@ -913,8 +912,8 @@ If you wanted to know does ping work but didn't have the source
strace ping -c 1 127.0.0.1
& then look at the man pages for each of the syscalls below,
( In fact this is sometimes easier than looking at some spagetti
-source which conditionally compiles for several architectures )
-Not everything that it throws out needs to make sense immeadiately
+source which conditionally compiles for several architectures ).
+Not everything that it throws out needs to make sense immediately.
Just looking quickly you can see that it is making up a RAW socket
for the ICMP protocol.
@@ -974,8 +973,9 @@ through the pipe for each line containing the string open.
Example 3
---------
-Getting sophistocated
-telnetd crashes on & I don't know why
+Getting sophisticated
+telnetd crashes & I don't know why
+
Steps
-----
1) Replace the following line in /etc/inetd.conf
@@ -1085,8 +1085,7 @@ Notes
-----
Addresses & values in the VM debugger are always hex never decimal
Address ranges are of the format <HexValue1>-<HexValue2> or <HexValue1>.<HexValue2>
-e.g. The address range 0x2000 to 0x3000 can be described described as
-2000-3000 or 2000.1000
+e.g. The address range 0x2000 to 0x3000 can be described as 2000-3000 or 2000.1000
The VM Debugger is case insensitive.
@@ -1311,7 +1310,7 @@ for finding out when a particular variable changes.
An alternative way of finding the STD of a currently running process
is to do the following, ( this method is more complex but
-could be quite convient if you aren't updating the kernel much &
+could be quite convenient if you aren't updating the kernel much &
so your kernel structures will stay constant for a reasonable period of
time ).
@@ -1413,7 +1412,7 @@ SMP Specific commands
To find out how many cpus you have
Q CPUS displays all the CPU's available to your virtual machine
To find the cpu that the current cpu VM debugger commands are being directed at do
-Q CPU to change the current cpu cpu VM debugger commands are being directed at do
+Q CPU to change the current cpu VM debugger commands are being directed at do
CPU <desired cpu no>
On a SMP guest issue a command to all CPUs try prefixing the command with cpu all.
@@ -1674,8 +1673,8 @@ channel is idle & the second for device end ( secondary status ) sometimes you g
concurrently, you check how the IO went on by issuing a TEST SUBCHANNEL at each interrupt,
from which you receive an Interruption response block (IRB). If you get channel & device end
status in the IRB without channel checks etc. your IO probably went okay. If you didn't you
-probably need a doctorto examine the IRB & extended status word etc.
-If an error occurs more sophistocated control units have a facitity known as
+probably need a doctor to examine the IRB & extended status word etc.
+If an error occurs, more sophistocated control units have a facitity known as
concurrent sense this means that if an error occurs Extended sense information will
be presented in the Extended status word in the IRB if not you have to issue a
subsequent SENSE CCW command after the test subchannel.
@@ -1704,7 +1703,7 @@ concentrate on data processing.
IOP's can use one or more links ( known as channel paths ) to talk to each
IO device. It first checks for path availability & chooses an available one,
then starts ( & sometimes terminates IO ).
-There are two types of channel path ESCON & the Paralell IO interface.
+There are two types of channel path: ESCON & the Parallel IO interface.
IO devices are attached to control units, control units provide the
logic to interface the channel paths & channel path IO protocols to
@@ -1743,11 +1742,11 @@ controllers or a control unit which connects to 1000 3270 terminals ).
The 390 IO systems come in 2 flavours the current 390 machines support both
-The Older 360 & 370 Interface,sometimes called the paralell I/O interface,
+The Older 360 & 370 Interface,sometimes called the Parallel I/O interface,
sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers
Interface (OEMI).
-This byte wide paralell channel path/bus has parity & data on the "Bus" cable
+This byte wide Parallel channel path/bus has parity & data on the "Bus" cable
& control lines on the "Tag" cable. These can operate in byte multiplex mode for
sharing between several slow devices or burst mode & monopolize the channel for the
whole burst. Upto 256 devices can be addressed on one of these cables. These cables are
@@ -1777,7 +1776,7 @@ Consoles 3270 & 3215 ( a teletype emulated under linux for a line mode console )
DASD's direct access storage devices ( otherwise known as hard disks ).
Tape Drives.
CTC ( Channel to Channel Adapters ),
-ESCON or Paralell Cables used as a very high speed serial link
+ESCON or Parallel Cables used as a very high speed serial link
between 2 machines. We use 2 cables under linux to do a bi-directional serial link.
@@ -1803,8 +1802,8 @@ OSA 7C09 ON OSA 7C09 SUBCHANNEL = 0001
OSA 7C14 ON OSA 7C14 SUBCHANNEL = 0002
OSA 7C15 ON OSA 7C15 SUBCHANNEL = 0003
-If you have a guest with certain priviliges you may be able to see devices
-which don't belong to you to avoid this do add the option V.
+If you have a guest with certain privileges you may be able to see devices
+which don't belong to you. To avoid this, add the option V.
e.g.
Q V OSA
@@ -1837,7 +1836,7 @@ RDRLIST
RECEIVE / LOG TXT A1 ( replace
8)
filel & press F11 to look at it
-You should see someting like.
+You should see something like:
00020942' SSCH B2334000 0048813C CC 0 SCH 0000 DEV 7C08
CPA 000FFDF0 PARM 00E2C9C4 KEY 0 FPI C0 LPM 80
@@ -1916,7 +1915,7 @@ Assembly
--------
info registers: displays registers other than floating point.
info all-registers: displays floating points as well.
-disassemble: dissassembles
+disassemble: disassembles
e.g.
disassemble without parameters will disassemble the current function
disassemble $pc $pc+10
@@ -1935,7 +1934,7 @@ undisplay : undo's display's
info breakpoints: shows all current breakpoints
-info stack: shows stack back trace ( if this dosent work too well, I'll show you the
+info stack: shows stack back trace ( if this doesn't work too well, I'll show you the
stacktrace by hand below ).
info locals: displays local variables.
@@ -2045,13 +2044,13 @@ what gdb does when the victim receives certain signals.
list:
e.g.
list lists current function source
-list 1,10 list first 10 lines of curret file.
+list 1,10 list first 10 lines of current file.
list test.c:1,10
directory:
Adds directories to be searched for source if gdb cannot find the source.
-(note it is a bit sensititive about slashes )
+(note it is a bit sensititive about slashes)
e.g. To add the root of the filesystem to the searchpath do
directory //
@@ -2123,9 +2122,9 @@ p/x (*(**$sp+56))&0x7fffffff
Disassembling instructions without debug info
---------------------------------------------
-gdb typically compains if there is a lack of debugging
-symbols in the disassemble command with
-"No function contains specified address." to get around
+gdb typically complains if there is a lack of debugging
+symbols in the disassemble command with
+"No function contains specified address." To get around
this do
x/<number lines to disassemble>xi <address>
e.g.
@@ -2184,7 +2183,7 @@ ps -aux | grep gdb
kill -SIGSEGV <gdb's pid>
or alternatively use killall -SIGSEGV gdb if you have the killall command.
Now look at the core dump.
-./gdb ./gdb core
+./gdb core
Displays the following
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
@@ -2316,7 +2315,7 @@ Showing us the shared libraries init uses where they are in memory
/proc/1/mem is the current running processes memory which you
can read & write to like a file.
strace uses this sometimes as it is a bit faster than the
-rather inefficent ptrace interface for peeking at DATA.
+rather inefficient ptrace interface for peeking at DATA.
cat status
@@ -2446,7 +2445,7 @@ displays the following lines as it executes them.
+ RELSTATUS=release
+ MACHTYPE=i586-pc-linux-gnu
-perl -d <scriptname> runs the perlscript in a fully intercative debugger
+perl -d <scriptname> runs the perlscript in a fully interactive debugger
<like gdb>.
Type 'h' in the debugger for help.
@@ -2477,7 +2476,7 @@ Lcrash is a perfectly normal program,however, it requires 2
additional files, Kerntypes which is built using a patch to the
linux kernel sources in the linux root directory & the System.map.
-Kerntypes is an an objectfile whose sole purpose in life
+Kerntypes is an objectfile whose sole purpose in life
is to provide stabs debug info to lcrash, to do this
Kerntypes is built from kerntypes.c which just includes the most commonly
referenced header files used when debugging, lcrash can then read the
diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt
index f0be389c7116..32a96cc39215 100644
--- a/Documentation/s390/cds.txt
+++ b/Documentation/s390/cds.txt
@@ -133,7 +133,7 @@ determine the device driver owning the device that raised the interrupt.
In order not to introduce a new I/O concept to the common Linux code,
Linux/390 preserves the IRQ concept and semantically maps the ESA/390
subchannels to Linux as IRQs. This allows Linux/390 to support up to 64k
-different IRQs, uniquely representig a single device each.
+different IRQs, uniquely representing a single device each.
Up to kernel 2.4, Linux/390 used to provide interfaces via the IRQ (subchannel).
For internal use of the common I/O layer, these are still there. However,
@@ -143,7 +143,7 @@ During its startup the Linux/390 system checks for peripheral devices. Each
of those devices is uniquely defined by a so called subchannel by the ESA/390
channel subsystem. While the subchannel numbers are system generated, each
subchannel also takes a user defined attribute, the so called device number.
-Both subchannel number and device number can not exceed 65535. During driverfs
+Both subchannel number and device number cannot exceed 65535. During driverfs
initialisation, the information about control unit type and device types that
imply specific I/O commands (channel command words - CCWs) in order to operate
the device are gathered. Device drivers can retrieve this set of hardware
@@ -174,14 +174,10 @@ read_dev_chars() - Read Device Characteristics
This routine returns the characteristics for the device specified.
-The function is meant to be called with an irq handler in place; that is,
+The function is meant to be called with the device already enabled; that is,
at earliest during set_online() processing.
-While the request is procesed synchronously, the device interrupt
-handler is called for final ending status. In case of error situations the
-interrupt handler may recover appropriately. The device irq handler can
-recognize the corresponding interrupts by the interruption parameter be
-0x00524443.The ccw_device must not be locked prior to calling read_dev_chars().
+The ccw_device must not be locked prior to calling read_dev_chars().
The function may be called enabled or disabled.
@@ -325,7 +321,7 @@ with the following CCW flags values defined :
CCW_FLAG_DC - data chaining
CCW_FLAG_CC - command chaining
-CCW_FLAG_SLI - suppress incorrct length
+CCW_FLAG_SLI - suppress incorrect length
CCW_FLAG_SKIP - skip
CCW_FLAG_PCI - PCI
CCW_FLAG_IDA - indirect addressing
@@ -348,7 +344,7 @@ The ccw_device_start() function returns :
not online.
When the I/O request completes, the CDS first level interrupt handler will
-accumalate the status in a struct irb and then call the device interrupt handler.
+accumulate the status in a struct irb and then call the device interrupt handler.
The intparm field will contain the value the device driver has associated with a
particular I/O request. If a pending device status was recognized,
intparm will be set to 0 (zero). This may happen during I/O initiation or delayed
@@ -410,30 +406,11 @@ individual flag meanings.
Usage Notes :
-Prior to call ccw_device_start() the device driver must assure disabled state,
-i.e. the I/O mask value in the PSW must be disabled. This can be accomplished
-by calling local_save_flags( flags). The current PSW flags are preserved and
-can be restored by local_irq_restore( flags) at a later time.
-
-If the device driver violates this rule while running in a uni-processor
-environment an interrupt might be presented prior to the ccw_device_start()
-routine returning to the device driver main path. In this case we will end in a
-deadlock situation as the interrupt handler will try to obtain the irq
-lock the device driver still owns (see below) !
-
-The driver must assure to hold the device specific lock. This can be
-accomplished by
-
-(i) spin_lock(get_ccwdev_lock(cdev)), or
-(ii) spin_lock_irqsave(get_ccwdev_lock(cdev), flags)
-
-Option (i) should be used if the calling routine is running disabled for
-I/O interrupts (see above) already. Option (ii) obtains the device gate und
-puts the CPU into I/O disabled state by preserving the current PSW flags.
+ccw_device_start() must be called disabled and with the ccw device lock held.
The device driver is allowed to issue the next ccw_device_start() call from
within its interrupt handler already. It is not required to schedule a
-bottom-half, unless an non deterministicly long running error recovery procedure
+bottom-half, unless an non deterministically long running error recovery procedure
or similar needs to be scheduled. During I/O processing the Linux/390 generic
I/O device driver support has already obtained the IRQ lock, i.e. the handler
must not try to obtain it again when calling ccw_device_start() or we end in a
@@ -488,7 +465,7 @@ int ccw_device_resume(struct ccw_device *cdev);
cdev - ccw_device the resume operation is requested for
-The resume_IO() function returns:
+The ccw_device_resume() function returns:
0 - suspended channel program is resumed
-EBUSY - status pending
@@ -507,6 +484,8 @@ a long-running channel program or the device might require to initially issue
a halt subchannel (HSCH) I/O command. For those purposes the ccw_device_halt()
command is provided.
+ccw_device_halt() must be called disabled and with the ccw device lock held.
+
int ccw_device_halt(struct ccw_device *cdev,
unsigned long intparm);
@@ -517,7 +496,7 @@ intparm : interruption parameter; value is only used if no I/O
The ccw_device_halt() function returns :
- 0 - successful completion or request successfully initiated
+ 0 - request successfully initiated
-EBUSY - the device is currently busy, or status pending.
-ENODEV - cdev invalid.
-EINVAL - The device is not operational or the ccw device is not online.
@@ -533,6 +512,23 @@ can then perform an appropriate action. Prior to interrupt of an outstanding
read to a network device (with or without PCI flag) a ccw_device_halt()
is required to end the pending operation.
+ccw_device_clear() - Terminage I/O Request Processing
+
+In order to terminate all I/O processing at the subchannel, the clear subchannel
+(CSCH) command is used. It can be issued via ccw_device_clear().
+
+ccw_device_clear() must be called disabled and with the ccw device lock held.
+
+int ccw_device_clear(struct ccw_device *cdev, unsigned long intparm);
+
+cdev: ccw_device the clear operation is requested for
+intparm: interruption parameter (see ccw_device_halt())
+
+The ccw_device_clear() function returns:
+
+ 0 - request successfully initiated
+-ENODEV - cdev invalid
+-EINVAL - The device is not operational or the ccw device is not online.
Miscellaneous Support Routines
diff --git a/Documentation/s390/crypto/crypto-API.txt b/Documentation/s390/crypto/crypto-API.txt
index 78a77624a716..29dee792c887 100644
--- a/Documentation/s390/crypto/crypto-API.txt
+++ b/Documentation/s390/crypto/crypto-API.txt
@@ -61,9 +61,9 @@ Example: z990 crypto instruction for SHA1 algorithm is available
-> when the sha1 algorithm is requested through the crypto API
(which has a module autoloader) the z990 module will be loaded.
-TBD: a userspace module probin mechanism
+TBD: a userspace module probing mechanism
something like 'probe sha1 sha1_z990 sha1' in modprobe.conf
- -> try module sha1_z990, if it fails to load load standard module sha1
+ -> try module sha1_z990, if it fails to load standard module sha1
the 'probe' statement is currently not supported in modprobe.conf
diff --git a/Documentation/s390/driver-model.txt b/Documentation/s390/driver-model.txt
index efb674eda4d4..77bf450ec39b 100644
--- a/Documentation/s390/driver-model.txt
+++ b/Documentation/s390/driver-model.txt
@@ -157,7 +157,7 @@ notify: This function is called by the common I/O layer for some state changes
* In online state, device detached (CIO_GONE) or last path gone
(CIO_NO_PATH). The driver must return !0 to keep the device; for
return code 0, the device will be deleted as usual (also when no
- notify function is registerd). If the driver wants to keep the
+ notify function is registered). If the driver wants to keep the
device, it is moved into disconnected state.
* In disconnected state, device operational again (CIO_OPER). The
common I/O layer performs some sanity checks on device number and
@@ -239,6 +239,9 @@ status - Can be 'online' or 'offline'.
type - The physical type of the channel path.
+shared - Whether the channel path is shared.
+
+cmg - The channel measurement group.
3. System devices
-----------------
@@ -262,7 +265,7 @@ attribute 'online' which can be 0 or 1.
-----------
The netiucv driver creates an attribute 'connection' under
-bus/iucv/drivers/netiucv. Piping to this attibute creates a new netiucv
+bus/iucv/drivers/netiucv. Piping to this attribute creates a new netiucv
connection to the specified host.
Netiucv connections show up under devices/iucv/ as "netiucv<ifnum>". The interface
diff --git a/Documentation/s390/monreader.txt b/Documentation/s390/monreader.txt
index d843bb04906e..beeaa4b24427 100644
--- a/Documentation/s390/monreader.txt
+++ b/Documentation/s390/monreader.txt
@@ -83,7 +83,7 @@ This loads the module and sets the DCSS name to "MYDCSS".
NOTE:
-----
-This API provides no interface to control the *MONITOR service, e.g. specifiy
+This API provides no interface to control the *MONITOR service, e.g. specify
which data should be collected. This can be done by the CP command MONITOR
(Class E privileged), see "CP Command and Utility Reference".
diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt
index e321a8ed2a2d..000230cd26db 100644
--- a/Documentation/s390/s390dbf.txt
+++ b/Documentation/s390/s390dbf.txt
@@ -11,7 +11,7 @@ where log records can be stored efficiently in memory, where each component
(e.g. device drivers) can have one separate debug log.
One purpose of this is to inspect the debug logs after a production system crash
in order to analyze the reason for the crash.
-If the system still runs but only a subcomponent which uses dbf failes,
+If the system still runs but only a subcomponent which uses dbf fails,
it is possible to look at the debug logs on a live system via the Linux
debugfs filesystem.
The debug feature may also very useful for kernel and driver development.
@@ -65,7 +65,7 @@ Predefined views for hex/ascii, sprintf and raw binary data are provided.
It is also possible to define other views. The content of
a view can be inspected simply by reading the corresponding debugfs file.
-All debug logs have an an actual debug level (range from 0 to 6).
+All debug logs have an actual debug level (range from 0 to 6).
The default level is 3. Event and Exception functions have a 'level'
parameter. Only debug entries with a level that is lower or equal
than the actual level are written to the log. This means, when
@@ -83,8 +83,8 @@ Example:
It is also possible to deactivate the debug feature globally for every
debug log. You can change the behavior using 2 sysctl parameters in
/proc/sys/s390dbf:
-There are currently 2 possible triggers, which stop the debug feature
-globally. The first possbility is to use the "debug_active" sysctl. If
+There are currently 2 possible triggers, which stop the debug feature
+globally. The first possibility is to use the "debug_active" sysctl. If
set to 1 the debug feature is running. If "debug_active" is set to 0 the
debug feature is turned off.
The second trigger which stops the debug feature is an kernel oops.
@@ -468,7 +468,7 @@ The hex_ascii view shows the data field in hex and ascii representation
The raw view returns a bytestream as the debug areas are stored in memory.
The sprintf view formats the debug entries in the same way as the sprintf
-function would do. The sprintf event/expection functions write to the
+function would do. The sprintf event/exception functions write to the
debug entry a pointer to the format string (size = sizeof(long))
and for each vararg a long value. So e.g. for a debug entry with a format
string plus two varargs one would need to allocate a (3 * sizeof(long))
@@ -556,7 +556,7 @@ The input_proc can be used to implement functionality when it is written to
the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level).
For header_proc there can be used the default function
-debug_dflt_header_fn() which is defined in in debug.h.
+debug_dflt_header_fn() which is defined in debug.h.
and which produces the same header output as the predefined views.
E.g:
00 00964419409:440761 2 - 00 88023ec
diff --git a/Documentation/sched-coding.txt b/Documentation/sched-coding.txt
index 2b75ef67c9fe..cbd8db752acf 100644
--- a/Documentation/sched-coding.txt
+++ b/Documentation/sched-coding.txt
@@ -15,7 +15,7 @@ Main Scheduling Methods
void load_balance(runqueue_t *this_rq, int idle)
Attempts to pull tasks from one cpu to another to balance cpu usage,
if needed. This method is called explicitly if the runqueues are
- inbalanced or periodically by the timer tick. Prior to calling,
+ imbalanced or periodically by the timer tick. Prior to calling,
the current runqueue must be locked and interrupts disabled.
void schedule()
diff --git a/Documentation/sched-design.txt b/Documentation/sched-design.txt
index 9d04e7bbf45f..1605bf0cba8b 100644
--- a/Documentation/sched-design.txt
+++ b/Documentation/sched-design.txt
@@ -93,9 +93,9 @@ and the goal is also to add a few new things:
Design
======
-the core of the new scheduler are the following mechanizms:
+The core of the new scheduler contains the following mechanisms:
- - *two*, priority-ordered 'priority arrays' per CPU. There is an 'active'
+ - *two* priority-ordered 'priority arrays' per CPU. There is an 'active'
array and an 'expired' array. The active array contains all tasks that
are affine to this CPU and have timeslices left. The expired array
contains all tasks which have used up their timeslices - but this array
diff --git a/Documentation/scsi/ChangeLog.1992-1997 b/Documentation/scsi/ChangeLog.1992-1997
index dc88ee2ab73d..6faad7e6417c 100644
--- a/Documentation/scsi/ChangeLog.1992-1997
+++ b/Documentation/scsi/ChangeLog.1992-1997
@@ -1214,7 +1214,7 @@ Thu Jul 21 10:37:39 1994 Eric Youngdale (eric@esp22)
* sr.c(sr_open): Do not allow opens with write access.
-Mon Jul 18 09:51:22 1994 1994 Eric Youngdale (eric@esp22)
+Mon Jul 18 09:51:22 1994 Eric Youngdale (eric@esp22)
* Linux 1.1.31 released.
diff --git a/Documentation/scsi/ChangeLog.megaraid_sas b/Documentation/scsi/ChangeLog.megaraid_sas
index d9e5960dafd5..5eb927544990 100644
--- a/Documentation/scsi/ChangeLog.megaraid_sas
+++ b/Documentation/scsi/ChangeLog.megaraid_sas
@@ -1,4 +1,49 @@
+1 Release Date : Mon Oct 02 11:21:32 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.05
+3 Older Version : 00.00.03.04
+
+i. PCI_DEVICE macro used
+
+ Convert the pci_device_id-table of the megaraid_sas-driver to the PCI_DEVICE-macro, to safe some lines.
+
+ - Henrik Kretzschmar <henne@nachtwindheim.de>
+ii. All compiler warnings removed
+iii. megasas_ctrl_info struct reverted to 3.02 release
+iv. Default value of megasas_dbg_lvl set to 0
+v. Removing in megasas_exit the sysfs entry created for megasas_dbg_lvl
+vi. In megasas_teardown_frame_pool(), cmd->frame was passed instead of
+ cmd->sense to pci_pool_free. Fixed. Bug was pointed out by
+ Eric Sesterhenn
+
+1 Release Date : Wed Sep 13 14:22:51 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.04
+3 Older Version : 00.00.03.03
+
+i. Added Reboot notify
+ii. Reduced by 1 max cmds sent to FW from Driver to make the reply_q_sz same
+ as Max Cmds FW can support
+
+1 Release Date : Tue Aug 22 16:33:14 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.03
+3 Older Version : 00.00.03.02
+
+i. Send stop adapter to FW & Dump pending FW cmds before declaring adapter dead.
+ New varible added to set dbg level.
+ii. Disable interrupt made as fn pointer as they are different for 1068 / 1078
+iii. Frame count optimization. Main frame can contain 2 SGE for 64 bit SGLs and
+ 3 SGE for 32 bit SGL
+iv. Tasklet added for cmd completion
+v. If FW in operational state before firing INIT, now we send RESET Flag to FW instead of just READY. This is used to do soft reset.
+vi. megasas_ctrl_prop structure updated (based on FW struct)
+vii. Added print : FW now in Ready State during initialization
+
+1 Release Date : Sun Aug 06 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
+2 Current Version : 00.00.03.02
+3 Older Version : 00.00.03.01
+
+i. Added FW tranistion state for Hotplug scenario
+
1 Release Date : Sun May 14 22:49:52 PDT 2006 - Sumant Patro <Sumant.Patro@lsil.com>
2 Current Version : 00.00.03.01
3 Older Version : 00.00.02.04
diff --git a/Documentation/scsi/NinjaSCSI.txt b/Documentation/scsi/NinjaSCSI.txt
index 041780f428ac..3229b64cf24e 100644
--- a/Documentation/scsi/NinjaSCSI.txt
+++ b/Documentation/scsi/NinjaSCSI.txt
@@ -24,7 +24,7 @@ SCSI device: I-O data CDPS-PX24 (CD-ROM drive)
You can also use "cardctl" program (this program is in pcmcia-cs source
code) to get more info.
-# cat /var/log/messgaes
+# cat /var/log/messages
...
Jan 2 03:45:06 lindberg cardmgr[78]: unsupported card in socket 1
Jan 2 03:45:06 lindberg cardmgr[78]: product info: "WBT", "NinjaSCSI-3", "R1.0"
@@ -36,18 +36,18 @@ Socket 1:
product info: "IO DATA", "CBSC16 ", "1"
-[2] Get Linux kernel source, and extract it to /usr/src.
- Because NinjaSCSI driver requiers some SCSI header files in Linux kernel
- source.
- I recomend rebuilding your kernel. This eliminate some versioning problem.
+[2] Get the Linux kernel source, and extract it to /usr/src.
+ Because the NinjaSCSI driver requires some SCSI header files in Linux
+ kernel source, I recommend rebuilding your kernel; this eliminates
+ some versioning problems.
$ cd /usr/src
$ tar -zxvf linux-x.x.x.tar.gz
$ cd linux
$ make config
...
-[3] If you use this driver with Kernel 2.2, Unpack pcmcia-cs in some directory
- and make & install. This driver requies pcmcia-cs header file.
+[3] If you use this driver with Kernel 2.2, unpack pcmcia-cs in some directory
+ and make & install. This driver requires the pcmcia-cs header file.
$ cd /usr/src
$ tar zxvf cs-pcmcia-cs-3.x.x.tar.gz
...
@@ -59,10 +59,10 @@ $ emacs Makefile
...
$ make
-[5] Copy nsp_cs.o to suitable plase, like /lib/modules/<Kernel version>/pcmcia/ .
+[5] Copy nsp_cs.ko to suitable place, like /lib/modules/<Kernel version>/pcmcia/ .
[6] Add these lines to /etc/pcmcia/config .
- If you yse pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file.
+ If you use pcmcia-cs-3.1.8 or later, we can use "nsp_cs.conf" file.
So, you don't need to edit file. Just copy to /etc/pcmcia/ .
-------------------------------------
diff --git a/Documentation/scsi/aacraid.txt b/Documentation/scsi/aacraid.txt
index ee03678c8029..3367130e64f6 100644
--- a/Documentation/scsi/aacraid.txt
+++ b/Documentation/scsi/aacraid.txt
@@ -4,7 +4,7 @@ Introduction
-------------------------
The aacraid driver adds support for Adaptec (http://www.adaptec.com)
RAID controllers. This is a major rewrite from the original
-Adaptec supplied driver. It has signficantly cleaned up both the code
+Adaptec supplied driver. It has significantly cleaned up both the code
and the running binary size (the module is less than half the size of
the original).
diff --git a/Documentation/scsi/aic79xx.txt b/Documentation/scsi/aic79xx.txt
index 382b439b439e..904d49e90ef2 100644
--- a/Documentation/scsi/aic79xx.txt
+++ b/Documentation/scsi/aic79xx.txt
@@ -81,7 +81,7 @@ The following information is available in this file:
an SDTR with an offset of 0 to be sure the target
knows we are async. This works around a firmware defect
in the Quantum Atlas 10K.
- - Implement controller susupend and resume.
+ - Implement controller suspend and resume.
- Clear PCI error state during driver attach so that we
don't disable memory mapped I/O due to a stray write
by some other driver probe that occurred before we
@@ -94,7 +94,7 @@ The following information is available in this file:
- Add support for scsi_report_device_reset() found in
2.5.X kernels.
- Add 7901B support.
- - Simplify handling of the packtized lun Rev A workaround.
+ - Simplify handling of the packetized lun Rev A workaround.
- Correct and simplify handling of the ignore wide residue
message. The previous code would fail to report a residual
if the transaction data length was even and we received
diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
index 3481fcded4c2..9b894f116d95 100644
--- a/Documentation/scsi/aic7xxx.txt
+++ b/Documentation/scsi/aic7xxx.txt
@@ -160,7 +160,7 @@ The following information is available in this file:
6.2.34 (May 5th, 2003)
- Fix locking regression instroduced in 6.2.29 that
- could cuase a lock order reversal between the io_request_lock
+ could cause a lock order reversal between the io_request_lock
and our per-softc lock. This was only possible on RH9,
SuSE, and kernel.org 2.4.X kernels.
diff --git a/Documentation/scsi/aic7xxx_old.txt b/Documentation/scsi/aic7xxx_old.txt
index 79e5ac6cb6ff..c92f4473193b 100644
--- a/Documentation/scsi/aic7xxx_old.txt
+++ b/Documentation/scsi/aic7xxx_old.txt
@@ -102,7 +102,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
The hardware RAID devices sold by Adaptec are *NOT* supported by this
driver (and will people please stop emailing me about them, they are
a totally separate beast from the bare SCSI controllers and this driver
- can not be retrofitted in any sane manner to support the hardware RAID
+ cannot be retrofitted in any sane manner to support the hardware RAID
features on those cards - Doug Ledford).
@@ -241,7 +241,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
that instead of dumping the register contents on the card, this
option dumps the contents of the sequencer program RAM. This gives
the ability to verify that the instructions downloaded to the
- card's sequencer are indeed what they are suppossed to be. Again,
+ card's sequencer are indeed what they are supposed to be. Again,
unless you have documentation to tell you how to interpret these
numbers, then it is totally useless.
@@ -317,7 +317,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
initial DEVCONFIG values for each of your aic7xxx controllers as
they are listed, and also record what the machine is detecting as
the proper termination on your controllers. NOTE: the order in
- which the initial DEVCONFIG values are printed out is not gauranteed
+ which the initial DEVCONFIG values are printed out is not guaranteed
to be the same order as the SCSI controllers are registered. The
above option and this option both work on the order of the SCSI
controllers as they are registered, so make sure you match the right
diff --git a/Documentation/scsi/dc395x.txt b/Documentation/scsi/dc395x.txt
index ae3b79a2d275..88219f96633d 100644
--- a/Documentation/scsi/dc395x.txt
+++ b/Documentation/scsi/dc395x.txt
@@ -20,7 +20,7 @@ Parameters
----------
The driver uses the settings from the EEPROM set in the SCSI BIOS
setup. If there is no EEPROM, the driver uses default values.
-Both can be overriden by command line parameters (module or kernel
+Both can be overridden by command line parameters (module or kernel
parameters).
The following parameters are available:
diff --git a/Documentation/scsi/dpti.txt b/Documentation/scsi/dpti.txt
index 6e45e70243e5..f36dc0e7c8da 100644
--- a/Documentation/scsi/dpti.txt
+++ b/Documentation/scsi/dpti.txt
@@ -48,7 +48,7 @@
* Implemented suggestions from Alan Cox
* Added calculation of resid for sg layer
* Better error handling
- * Added checking underflow condtions
+ * Added checking underflow conditions
* Added DATAPROTECT checking
* Changed error return codes
* Fixed pointer bug in bus reset routine
diff --git a/Documentation/scsi/ibmmca.txt b/Documentation/scsi/ibmmca.txt
index d16ce5b540f4..35f6b8ed2295 100644
--- a/Documentation/scsi/ibmmca.txt
+++ b/Documentation/scsi/ibmmca.txt
@@ -229,7 +229,7 @@
In a second step of the driver development, the following improvement has
been applied: The first approach limited the number of devices to 7, far
- fewer than the 15 that it could usem then it just maped ldn ->
+ fewer than the 15 that it could use, then it just mapped ldn ->
(ldn/8,ldn%8) for pun,lun. We ended up with a real mishmash of puns
and luns, but it all seemed to work.
@@ -254,12 +254,12 @@
device to be existant, but it has no ldn assigned, it gets a ldn out of 7
to 14. The numbers are assigned in cyclic order. Therefore it takes 8
dynamical reassignments on the SCSI-devices, until a certain device
- loses its ldn again. This assures, that dynamical remapping is avoided
+ loses its ldn again. This assures that dynamical remapping is avoided
during intense I/O between up to 15 SCSI-devices (means pun,lun
- combinations). A further advantage of this method is, that people who
+ combinations). A further advantage of this method is that people who
build their kernel without probing on all luns will get what they expect,
because the driver just won't assign everything with lun>0 when
- multpile lun probing is inactive.
+ multiple lun probing is inactive.
2.4 SCSI-Device Order
---------------------
@@ -309,9 +309,9 @@
2.6 Abort & Reset Commands
--------------------------
These are implemented with busy waiting for interrupt to arrive.
- ibmmca_reset() and ibmmca_abort() do not work sufficently well
- up to now and need still a lot of development work. But, this seems
- to be even a problem with other SCSI-low level drivers, too. However,
+ ibmmca_reset() and ibmmca_abort() do not work sufficiently well
+ up to now and need still a lot of development work. This seems
+ to be a problem with other low-level SCSI drivers too, however
this should be no excuse.
2.7 Disk Geometry
@@ -684,8 +684,8 @@
not like sending commands to non-existing SCSI-devices and will react
with a command error as a sign of protest. While this error is not
present on IBM SCSI Adapter w/cache, it appears on IBM Integrated SCSI
- Adapters. Therefore, I implemented a workarround to forgive those
- adapters their protests, but it is marked up in the statisctis, so
+ Adapters. Therefore, I implemented a workaround to forgive those
+ adapters their protests, but it is marked up in the statistics, so
after a successful boot, you can see in /proc/scsi/ibmmca/<host_number>
how often the command errors have been forgiven to the SCSI-subsystem.
If the number is bigger than 0, you have a SCSI subsystem of older
@@ -778,15 +778,15 @@
not accept this, as they stick quite near to ANSI-SCSI and report
a COMMAND_ERROR message which causes the driver to panic. The main
problem was located around the INQUIRY command. Now, for all the
- mentioned commands, the buffersize, sent to the adapter is at
+ mentioned commands, the buffersize sent to the adapter is at
maximum 255 which seems to be a quite reasonable solution.
- TEST_UNIT_READY gets a buffersize of 0 to make sure, that no
+ TEST_UNIT_READY gets a buffersize of 0 to make sure that no
data is transferred in order to avoid any possible command failure.
- 2) On unsuccessful TEST_UNIT_READY, the midlevel-driver has to send
- a REQUEST_SENSE in order to see, where the problem is located. This
+ 2) On unsuccessful TEST_UNIT_READY, the mid-level driver has to send
+ a REQUEST_SENSE in order to see where the problem is located. This
REQUEST_SENSE may have various length in its answer-buffer. IBM
- SCSI-subsystems report a command failure, if the returned buffersize
- is different from the sent buffersize, but this can be supressed by
+ SCSI-subsystems report a command failure if the returned buffersize
+ is different from the sent buffersize, but this can be suppressed by
a special bit, which is now done and problems seem to be solved.
2) Code adaption to all kernel-releases. Now, the 3.2 code compiles on
2.0.x, 2.1.x, 2.2.x and 2.3.x kernel releases without any code-changes.
@@ -1086,7 +1086,7 @@
Q: "Reset SCSI-devices at boottime" halts the system at boottime, why?
A: This is only tested with the IBM SCSI Adapter w/cache. It is not
- yet prooved to run on other adapters, however you may be lucky.
+ yet proven to run on other adapters, however you may be lucky.
In version 3.1d this has been hugely improved and should work better,
now. Normally you really won't need to activate this flag in the
kernel configuration, as all post 1989 SCSI-devices should accept
@@ -1104,7 +1104,7 @@
The parameter 'normal' sets the new industry standard, starting
from pun 0, scanning up to pun 6. This allows you to change your
opinion still after having already compiled the kernel.
- Q: Why I cannot find the IBM MCA SCSI support in the config menue?
+ Q: Why can't I find IBM MCA SCSI support in the config menu?
A: You have to activate MCA bus support, first.
Q: Where can I find the latest info about this driver?
A: See the file MAINTAINERS for the current WWW-address, which offers
@@ -1156,7 +1156,7 @@
Guide) what has to be done for reset, we still share the bad shape of
the reset functions with all other low level SCSI-drivers.
Astonishingly, reset works in most cases quite ok, but the harddisks
- won't run in synchonous mode anymore after a reset, until you reboot.
+ won't run in synchronous mode anymore after a reset, until you reboot.
Q: Why does my XXX w/Cache adapter not use read-prefetch?
A: Ok, that is not completely possible. If a cache is present, the
adapter tries to use it internally. Explicitly, one can use the cache
diff --git a/Documentation/scsi/megaraid.txt b/Documentation/scsi/megaraid.txt
index ff864c0f494c..3c7cea51e687 100644
--- a/Documentation/scsi/megaraid.txt
+++ b/Documentation/scsi/megaraid.txt
@@ -4,11 +4,11 @@
Overview:
--------
-Different classes of controllers from LSI Logic, accept and respond to the
+Different classes of controllers from LSI Logic accept and respond to the
user applications in a similar way. They understand the same firmware control
commands. Furthermore, the applications also can treat different classes of
the controllers uniformly. Hence it is logical to have a single module that
-interefaces with the applications on one side and all the low level drivers
+interfaces with the applications on one side and all the low level drivers
on the other.
The advantages, though obvious, are listed for completeness:
diff --git a/Documentation/scsi/ncr53c8xx.txt b/Documentation/scsi/ncr53c8xx.txt
index 822d2aca3700..58ad8db333d9 100644
--- a/Documentation/scsi/ncr53c8xx.txt
+++ b/Documentation/scsi/ncr53c8xx.txt
@@ -70,7 +70,7 @@ Written by Gerard Roudier <groudier@free.fr>
15. SCSI problem troubleshooting
15.1 Problem tracking
15.2 Understanding hardware error reports
-16. Synchonous transfer negotiation tables
+16. Synchronous transfer negotiation tables
16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
16.2 Synchronous timings for fast SCSI-2 53C8XX controllers
17. Serial NVRAM support (by Richard Waltham)
@@ -96,10 +96,10 @@ The original driver has been written for 386bsd and FreeBSD by:
It is now available as a bundle of 2 drivers:
- ncr53c8xx generic driver that supports all the SYM53C8XX family including
- the ealiest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and
+ the earliest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and
the new 895A (1 channel LVD SCSI controller).
- sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest
- chips in order to gain advantage of new features, as LOAD/STORE intructions
+ chips in order to gain advantage of new features, as LOAD/STORE instructions
available since the 810A and hardware phase mismatch available with the
896 and the 895A.
@@ -207,7 +207,7 @@ The 896 and the 895A allows handling of the phase mismatch context from
SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor
until the C code has saved the context of the transfer).
Implementing this without using LOAD/STORE instructions would be painfull
-and I did'nt even want to try it.
+and I didn't even want to try it.
The 896 chip supports 64 bit PCI transactions and addressing, while the
895A supports 32 bit PCI transactions and 64 bit addressing.
@@ -631,8 +631,8 @@ string variable using 'insmod'.
A boot setup command for the ncr53c8xx (sym53c8xx) driver begins with the
driver name "ncr53c8xx="(sym53c8xx). The kernel syntax parser then expects
-an optionnal list of integers separated with comma followed by an optional
-list of comma-separated strings. Example of boot setup command under lilo
+an optional list of integers separated with comma followed by an optional
+list of comma-separated strings. Example of boot setup command under lilo
prompt:
lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200
@@ -778,7 +778,7 @@ port address 0x1400.
Some scsi boards use a 875 (ultra wide) and only supply narrow connectors.
If you have connected a wide device with a 50 pins to 68 pins cable
converter, any accepted wide negotiation will break further data transfers.
- In such a case, using "wide:0" in the bootup command will be helpfull.
+ In such a case, using "wide:0" in the bootup command will be helpful.
10.2.14 Differential mode
diff:0 never set up diff mode
@@ -899,7 +899,7 @@ boot setup can be:
ncr53c8xx=safe:y,mpar:y
ncr53c8xx=safe:y
-My personnal system works flawlessly with the following equivalent setup:
+My personal system works flawlessly with the following equivalent setup:
ncr53c8xx=mpar:y,spar:y,disc:y,specf:1,fsn:n,ultra:2,fsn:n,revprob:n,verb:1\
tags:32,sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0
@@ -1151,7 +1151,7 @@ Driver files:
New driver versions are made available separately in order to allow testing
changes and new features prior to including them into the linux kernel
-distribution. The following URL provides informations on latest avalaible
+distribution. The following URL provides information on latest available
patches:
ftp://ftp.tux.org/pub/people/gerard-roudier/README
@@ -1382,7 +1382,7 @@ SCSI standards, chip cores functionnals and internal driver data structures.
You are not required to decode and understand them, unless you want to help
maintain the driver code.
-16. Synchonous transfer negotiation tables
+16. Synchronous transfer negotiation tables
Tables below have been created by calling the routine the driver uses
for synchronisation negotiation timing calculation and chip setting.
diff --git a/Documentation/scsi/osst.txt b/Documentation/scsi/osst.txt
index ce574e7791ab..f536907e241d 100644
--- a/Documentation/scsi/osst.txt
+++ b/Documentation/scsi/osst.txt
@@ -56,8 +56,7 @@ Compile your kernel and install the modules.
Now, your osst driver is inside the kernel or available as a module,
depending on your choice during kernel config. You may still need to create
-the device nodes by calling the Makedevs.sh script (see below) manually,
-unless you use a devfs kernel, where this won't be needed.
+the device nodes by calling the Makedevs.sh script (see below) manually.
To load your module, you may use the command
modprobe osst
diff --git a/Documentation/scsi/ppa.txt b/Documentation/scsi/ppa.txt
index 5d9223bc1bd5..067ac394e0b2 100644
--- a/Documentation/scsi/ppa.txt
+++ b/Documentation/scsi/ppa.txt
@@ -3,7 +3,7 @@
General Iomega ZIP drive page for Linux:
http://www.torque.net/~campbell/
-Driver achive for old drivers:
+Driver archive for old drivers:
http://www.torque.net/~campbell/ppa/
Linux Parport page (parallel port)
diff --git a/Documentation/scsi/scsi-changer.txt b/Documentation/scsi/scsi-changer.txt
index c132687b017a..d74bbd29eb3a 100644
--- a/Documentation/scsi/scsi-changer.txt
+++ b/Documentation/scsi/scsi-changer.txt
@@ -31,7 +31,7 @@ changers. But it allows to handle nearly all possible cases. It knows
media transport - this one shuffles around the media, i.e. the
transport arm. Also known as "picker".
storage - a slot which can hold a media.
- import/export - the same as above, but is accessable from outside,
+ import/export - the same as above, but is accessible from outside,
i.e. there the operator (you !) can use this to
fill in and remove media from the changer.
Sometimes named "mailslot".
diff --git a/Documentation/scsi/scsi_eh.txt b/Documentation/scsi/scsi_eh.txt
index ce767b90bb0d..b964eef2f62f 100644
--- a/Documentation/scsi/scsi_eh.txt
+++ b/Documentation/scsi/scsi_eh.txt
@@ -160,7 +160,7 @@ ways.
- Fine-grained EH callbacks
LLDD can implement fine-grained EH callbacks and let SCSI
midlayer drive error handling and call appropriate callbacks.
- This will be dicussed further in [2-1].
+ This will be discussed further in [2-1].
- eh_strategy_handler() callback
This is one big callback which should perform whole error
@@ -194,7 +194,7 @@ lower layers and lower layers are ready to process or fail the scmd
again.
To achieve these goals, EH performs recovery actions with increasing
-severity. Some actions are performed by issueing SCSI commands and
+severity. Some actions are performed by issuing SCSI commands and
others are performed by invoking one of the following fine-grained
hostt EH callbacks. Callbacks may be omitted and omitted ones are
considered to fail always.
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
index 20e30cf31877..5ff65b184265 100644
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -249,7 +249,7 @@ BOOT TIME CONFIGURATION
If the driver is compiled into the kernel, the same parameters can be
also set using, e.g., the LILO command line. The preferred syntax is
-is to use the same keyword used when loading as module but prepended
+to use the same keyword used when loading as module but prepended
with 'st.'. For instance, to set the maximum number of scatter/gather
segments, the parameter 'st.max_sg_segs=xx' should be used (xx is the
number of scatter/gather segments).
@@ -369,7 +369,7 @@ MTSETDRVBUFFER
the device dependent address. It is recommended to set
this flag unless there are tapes using the device
dependent (from the old times) (global)
- MT_ST_SYSV sets the SYSV sematics (mode)
+ MT_ST_SYSV sets the SYSV semantics (mode)
MT_ST_NOWAIT enables immediate mode (i.e., don't wait for
the command to finish) for some commands (e.g., rewind)
MT_ST_DEBUGGING debugging (global; debugging must be
diff --git a/Documentation/scsi/sym53c8xx_2.txt b/Documentation/scsi/sym53c8xx_2.txt
index 7f516cdcd262..26c8a08ca3ea 100644
--- a/Documentation/scsi/sym53c8xx_2.txt
+++ b/Documentation/scsi/sym53c8xx_2.txt
@@ -67,7 +67,7 @@ under Linux is contained in 2 files named sym_glue.h and sym_glue.c.
Other drivers files are intended not to depend on the Operating System
on which the driver is used.
-The history of this driver can be summerized as follows:
+The history of this driver can be summarized as follows:
1993: ncr driver written for 386bsd and FreeBSD by:
Wolfgang Stanglmeier <wolf@cologne.de>
@@ -684,7 +684,7 @@ Field H : SCNTL3 Scsi Control Register 3
Contains the setting of timing values for both asynchronous and
synchronous data transfers.
Field I : SCNTL4 Scsi Control Register 4
- Only meaninful for 53C1010 Ultra3 controllers.
+ Only meaningful for 53C1010 Ultra3 controllers.
Understanding Fields J, K, L and dumps requires to have good knowledge of
SCSI standards, chip cores functionnals and internal driver data structures.
diff --git a/Documentation/scsi/tmscsim.txt b/Documentation/scsi/tmscsim.txt
index df7a02bfb5bf..8b2168aa4fc7 100644
--- a/Documentation/scsi/tmscsim.txt
+++ b/Documentation/scsi/tmscsim.txt
@@ -27,7 +27,7 @@ Tekram DC390(T) adapter. This is where the name comes from: tm = Tekram
scsi = SCSI driver, m = AMD (?) as opposed to w for the DC390W/U/F
(NCR53c8X5, X=2/7) driver. Yes, there was also a driver for the latter,
tmscsiw, which supported DC390W/U/F adapters. It's not maintained any more,
-as the ncr53c8xx is perfectly supporting these adpaters since some time.
+as the ncr53c8xx is perfectly supporting these adapters since some time.
The driver first appeared in April 1996, exclusively supported the DC390
and has been enhanced since then in various steps. In May 1998 support for
@@ -381,7 +381,7 @@ Please see http://www.garloff.de/kurt/linux/dc390/problems.html
replaced by the dev index of your scanner). You may try to reset your SCSI
bus afterwards (echo "RESET" >/proc/scsi/tmscsim/?).
The problem seems to be solved as of 2.0d18, thanks to Andreas Rick.
-* If there is a valid partition table, the driver will use it for determing
+* If there is a valid partition table, the driver will use it for determining
the mapping. If there's none, a reasonable mapping (Symbios-like) will be
assumed. Other operating systems may not like this mapping, though
it's consistent with the BIOS' behaviour. Old DC390 drivers ignored the
diff --git a/Documentation/seclvl.txt b/Documentation/seclvl.txt
deleted file mode 100644
index 97274d122d0e..000000000000
--- a/Documentation/seclvl.txt
+++ /dev/null
@@ -1,97 +0,0 @@
-BSD Secure Levels Linux Security Module
-Michael A. Halcrow <mike@halcrow.us>
-
-
-Introduction
-
-Under the BSD Secure Levels security model, sets of policies are
-associated with levels. Levels range from -1 to 2, with -1 being the
-weakest and 2 being the strongest. These security policies are
-enforced at the kernel level, so not even the superuser is able to
-disable or circumvent them. This hardens the machine against attackers
-who gain root access to the system.
-
-
-Levels and Policies
-
-Level -1 (Permanently Insecure):
- - Cannot increase the secure level
-
-Level 0 (Insecure):
- - Cannot ptrace the init process
-
-Level 1 (Default):
- - /dev/mem and /dev/kmem are read-only
- - IMMUTABLE and APPEND extended attributes, if set, may not be unset
- - Cannot load or unload kernel modules
- - Cannot write directly to a mounted block device
- - Cannot perform raw I/O operations
- - Cannot perform network administrative tasks
- - Cannot setuid any file
-
-Level 2 (Secure):
- - Cannot decrement the system time
- - Cannot write to any block device, whether mounted or not
- - Cannot unmount any mounted filesystems
-
-
-Compilation
-
-To compile the BSD Secure Levels LSM, seclvl.ko, enable the
-SECURITY_SECLVL configuration option. This is found under Security
-options -> BSD Secure Levels in the kernel configuration menu.
-
-
-Basic Usage
-
-Once the machine is in a running state, with all the necessary modules
-loaded and all the filesystems mounted, you can load the seclvl.ko
-module:
-
-# insmod seclvl.ko
-
-The module defaults to secure level 1, except when compiled directly
-into the kernel, in which case it defaults to secure level 0. To raise
-the secure level to 2, the administrator writes ``2'' to the
-seclvl/seclvl file under the sysfs mount point (assumed to be /sys in
-these examples):
-
-# echo -n "2" > /sys/seclvl/seclvl
-
-Alternatively, you can initialize the module at secure level 2 with
-the initlvl module parameter:
-
-# insmod seclvl.ko initlvl=2
-
-At this point, it is impossible to remove the module or reduce the
-secure level. If the administrator wishes to have the option of doing
-so, he must provide a module parameter, sha1_passwd, that specifies
-the SHA1 hash of the password that can be used to reduce the secure
-level to 0.
-
-To generate this SHA1 hash, the administrator can use OpenSSL:
-
-# echo -n "boogabooga" | openssl sha1
-abeda4e0f33defa51741217592bf595efb8d289c
-
-In order to use password-instigated secure level reduction, the SHA1
-crypto module must be loaded or compiled into the kernel:
-
-# insmod sha1.ko
-
-The administrator can then insmod the seclvl module, including the
-SHA1 hash of the password:
-
-# insmod seclvl.ko
- sha1_passwd=abeda4e0f33defa51741217592bf595efb8d289c
-
-To reduce the secure level, write the password to seclvl/passwd under
-your sysfs mount point:
-
-# echo -n "boogabooga" > /sys/seclvl/passwd
-
-The September 2004 edition of Sys Admin Magazine has an article about
-the BSD Secure Levels LSM. I encourage you to refer to that article
-for a more in-depth treatment of this security module:
-
-http://www.samag.com/documents/s=9304/sam0409a/0409a.htm
diff --git a/Documentation/sh/kgdb.txt b/Documentation/sh/kgdb.txt
index 5b04f7f306fc..05b4ba89d28c 100644
--- a/Documentation/sh/kgdb.txt
+++ b/Documentation/sh/kgdb.txt
@@ -69,7 +69,7 @@ might specify the halt option:
kgdb=halt
-Boot the TARGET machinem, which will appear to hang.
+Boot the TARGET machine, which will appear to hang.
On your DEVELOPMENT machine, cd to the source directory and run the gdb
program. (This is likely to be a cross GDB which runs on your host but
diff --git a/Documentation/sh/new-machine.txt b/Documentation/sh/new-machine.txt
index eb2dd2e6993b..73988e0d112b 100644
--- a/Documentation/sh/new-machine.txt
+++ b/Documentation/sh/new-machine.txt
@@ -41,11 +41,6 @@ Board-specific code:
|
.. more boards here ...
-It should also be noted that each board is required to have some certain
-headers. At the time of this writing, io.h is the only thing that needs
-to be provided for each board, and can generally just reference generic
-functions (with the exception of isa_port2addr).
-
Next, for companion chips:
.
`-- arch
@@ -104,12 +99,13 @@ and then populate that with sub-directories for each member of the family.
Both the Solution Engine and the hp6xx boards are an example of this.
After you have setup your new arch/sh/boards/ directory, remember that you
-also must add a directory in include/asm-sh for headers localized to this
-board. In order to interoperate seamlessly with the build system, it's best
-to have this directory the same as the arch/sh/boards/ directory name,
-though if your board is again part of a family, the build system has ways
-of dealing with this, and you can feel free to name the directory after
-the family member itself.
+should also add a directory in include/asm-sh for headers localized to this
+board (if there are going to be more than one). In order to interoperate
+seamlessly with the build system, it's best to have this directory the same
+as the arch/sh/boards/ directory name, though if your board is again part of
+a family, the build system has ways of dealing with this (via incdir-y
+overloading), and you can feel free to name the directory after the family
+member itself.
There are a few things that each board is required to have, both in the
arch/sh/boards and the include/asm-sh/ heirarchy. In order to better
@@ -122,6 +118,7 @@ might look something like:
* arch/sh/boards/vapor/setup.c - Setup code for imaginary board
*/
#include <linux/init.h>
+#include <asm/rtc.h> /* for board_time_init() */
const char *get_system_type(void)
{
@@ -152,79 +149,57 @@ int __init platform_setup(void)
}
Our new imaginary board will also have to tie into the machvec in order for it
-to be of any use. Currently the machvec is slowly on its way out, but is still
-required for the time being. As such, let us take a look at what needs to be
-done for the machvec assignment.
+to be of any use.
machvec functions fall into a number of categories:
- I/O functions to IO memory (inb etc) and PCI/main memory (readb etc).
- - I/O remapping functions (ioremap etc)
- - some initialisation functions
- - a 'heartbeat' function
- - some miscellaneous flags
-
-The tree can be built in two ways:
- - as a fully generic build. All drivers are linked in, and all functions
- go through the machvec
- - as a machine specific build. In this case only the required drivers
- will be linked in, and some macros may be redefined to not go through
- the machvec where performance is important (in particular IO functions).
-
-There are three ways in which IO can be performed:
- - none at all. This is really only useful for the 'unknown' machine type,
- which us designed to run on a machine about which we know nothing, and
- so all all IO instructions do nothing.
- - fully custom. In this case all IO functions go to a machine specific
- set of functions which can do what they like
- - a generic set of functions. These will cope with most situations,
- and rely on a single function, mv_port2addr, which is called through the
- machine vector, and converts an IO address into a memory address, which
- can be read from/written to directly.
-
-Thus adding a new machine involves the following steps (I will assume I am
-adding a machine called vapor):
-
- - add a new file include/asm-sh/vapor/io.h which contains prototypes for
+ - I/O mapping functions (ioport_map, ioport_unmap, etc).
+ - a 'heartbeat' function.
+ - PCI and IRQ initialization routines.
+ - Consistent allocators (for boards that need special allocators,
+ particularly for allocating out of some board-specific SRAM for DMA
+ handles).
+
+There are machvec functions added and removed over time, so always be sure to
+consult include/asm-sh/machvec.h for the current state of the machvec.
+
+The kernel will automatically wrap in generic routines for undefined function
+pointers in the machvec at boot time, as machvec functions are referenced
+unconditionally throughout most of the tree. Some boards have incredibly
+sparse machvecs (such as the dreamcast and sh03), whereas others must define
+virtually everything (rts7751r2d).
+
+Adding a new machine is relatively trivial (using vapor as an example):
+
+If the board-specific definitions are quite minimalistic, as is the case for
+the vast majority of boards, simply having a single board-specific header is
+sufficient.
+
+ - add a new file include/asm-sh/vapor.h which contains prototypes for
any machine specific IO functions prefixed with the machine name, for
example vapor_inb. These will be needed when filling out the machine
vector.
- This is the minimum that is required, however there are ample
- opportunities to optimise this. In particular, by making the prototypes
- inline function definitions, it is possible to inline the function when
- building machine specific versions. Note that the machine vector
- functions will still be needed, so that a module built for a generic
- setup can be loaded.
-
- - add a new file arch/sh/boards/vapor/mach.c. This contains the definition
- of the machine vector. When building the machine specific version, this
- will be the real machine vector (via an alias), while in the generic
- version is used to initialise the machine vector, and then freed, by
- making it initdata. This should be defined as:
-
- struct sh_machine_vector mv_vapor __initmv = {
- .mv_name = "vapor",
- }
- ALIAS_MV(vapor)
-
- - finally add a file arch/sh/boards/vapor/io.c, which contains
- definitions of the machine specific io functions.
-
-A note about initialisation functions. Three initialisation functions are
-provided in the machine vector:
- - mv_arch_init - called very early on from setup_arch
- - mv_init_irq - called from init_IRQ, after the generic SH interrupt
- initialisation
- - mv_init_pci - currently not used
-
-Any other remaining functions which need to be called at start up can be
-added to the list using the __initcalls macro (or module_init if the code
-can be built as a module). Many generic drivers probe to see if the device
-they are targeting is present, however this may not always be appropriate,
-so a flag can be added to the machine vector which will be set on those
-machines which have the hardware in question, reducing the probe to a
-single conditional.
+ Note that these prototypes are generated automatically by setting
+ __IO_PREFIX to something sensible. A typical example would be:
+
+ #define __IO_PREFIX vapor
+ #include <asm/io_generic.h>
+
+ somewhere in the board-specific header. Any boards being ported that still
+ have a legacy io.h should remove it entirely and switch to the new model.
+
+ - Add machine vector definitions to the board's setup.c. At a bare minimum,
+ this must be defined as something like:
+
+ struct sh_machine_vector mv_vapor __initmv = {
+ .mv_name = "vapor",
+ };
+ ALIAS_MV(vapor)
+
+ - finally add a file arch/sh/boards/vapor/io.c, which contains definitions of
+ the machine specific io functions (if there are enough to warrant it).
3. Hooking into the Build System
================================
@@ -303,4 +278,3 @@ which will in turn copy the defconfig for this board, run it through
oldconfig (prompting you for any new options since the time of creation),
and start you on your way to having a functional kernel for your new
board.
-
diff --git a/Documentation/sh/register-banks.txt b/Documentation/sh/register-banks.txt
new file mode 100644
index 000000000000..a6719f2f6594
--- /dev/null
+++ b/Documentation/sh/register-banks.txt
@@ -0,0 +1,33 @@
+ Notes on register bank usage in the kernel
+ ==========================================
+
+Introduction
+------------
+
+The SH-3 and SH-4 CPU families traditionally include a single partial register
+bank (selected by SR.RB, only r0 ... r7 are banked), whereas other families
+may have more full-featured banking or simply no such capabilities at all.
+
+SR.RB banking
+-------------
+
+In the case of this type of banking, banked registers are mapped directly to
+r0 ... r7 if SR.RB is set to the bank we are interested in, otherwise ldc/stc
+can still be used to reference the banked registers (as r0_bank ... r7_bank)
+when in the context of another bank. The developer must keep the SR.RB value
+in mind when writing code that utilizes these banked registers, for obvious
+reasons. Userspace is also not able to poke at the bank1 values, so these can
+be used rather effectively as scratch registers by the kernel.
+
+Presently the kernel uses several of these registers.
+
+ - r0_bank, r1_bank (referenced as k0 and k1, used for scratch
+ registers when doing exception handling).
+ - r2_bank (used to track the EXPEVT/INTEVT code)
+ - Used by do_IRQ() and friends for doing irq mapping based off
+ of the interrupt exception vector jump table offset
+ - r6_bank (global interrupt mask)
+ - The SR.IMASK interrupt handler makes use of this to set the
+ interrupt priority level (used by local_irq_enable())
+ - r7_bank (current)
+
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt
index e6b57dd46a4f..138673a907f5 100644
--- a/Documentation/sound/alsa/ALSA-Configuration.txt
+++ b/Documentation/sound/alsa/ALSA-Configuration.txt
@@ -57,11 +57,6 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
- Default: 1
- For auto-loading more than one card, specify this
option together with snd-card-X aliases.
- device_mode
- - permission mask for dynamic sound device filesystem
- - This is available only when DEVFS is enabled
- - Default: 0666
- - E.g.: device_mode=0660
Module snd-pcm-oss
@@ -1268,8 +1263,8 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
Note: on some notebooks the buffer address cannot be detected
automatically, or causes hang-up during initialization.
- In such a case, specify the buffer top address explicity via
- buffer_top option.
+ In such a case, specify the buffer top address explicitly via
+ the buffer_top option.
For example,
Sony F250: buffer_top=0x25a800
Sony F270: buffer_top=0x272800
@@ -1887,7 +1882,7 @@ options snd-ens1371 index=1
# OSS/Free portion
alias sound-slot-0 snd-interwave
alias sound-slot-1 snd-ens1371
------ /etc/moprobe.conf
+----- /etc/modprobe.conf
In this example, the interwave card is always loaded as the first card
(index 0) and ens1371 as the second (index 1).
@@ -1915,21 +1910,6 @@ Please note that the device mapping above may be varied via the module
options of snd-pcm-oss module.
-DEVFS support
-=============
-
-The ALSA driver fully supports the devfs extension.
-You should add lines below to your devfsd.conf file:
-
-LOOKUP snd MODLOAD ACTION snd
-REGISTER ^sound/.* PERMISSIONS root.audio 660
-REGISTER ^snd/.* PERMISSIONS root.audio 660
-
-Warning: These lines assume that you have the audio group in your system.
- Otherwise replace audio word with another group name (root for
- example).
-
-
Proc interfaces (/proc/asound)
==============================
diff --git a/Documentation/sound/alsa/Audiophile-Usb.txt b/Documentation/sound/alsa/Audiophile-Usb.txt
index b535c2a198f8..e40cce83327c 100644
--- a/Documentation/sound/alsa/Audiophile-Usb.txt
+++ b/Documentation/sound/alsa/Audiophile-Usb.txt
@@ -126,7 +126,7 @@ Here is a list of supported device_setup values for this device:
- Alsa driver default mode
- maintains backward compatibility with setups that do not use this
parameter by not introducing any change
- - results sometimes in corrupted sound as decribed earlier
+ - results sometimes in corrupted sound as described earlier
* device_setup=0x01
- 16bits 48kHz mode with Di disabled
- Ai,Ao,Do can be used at the same time
diff --git a/Documentation/sound/alsa/CMIPCI.txt b/Documentation/sound/alsa/CMIPCI.txt
index 1872e24442a4..4b2b15387056 100644
--- a/Documentation/sound/alsa/CMIPCI.txt
+++ b/Documentation/sound/alsa/CMIPCI.txt
@@ -16,11 +16,11 @@ As default, ALSA driver assigns the first PCM device (i.e. hw:0,0 for
card#0) for front and 4/6ch playbacks, while the second PCM device
(hw:0,1) is assigned to the second DAC for rear playback.
-There are slight difference between two DACs.
+There are slight differences between the two DACs:
- The first DAC supports U8 and S16LE formats, while the second DAC
supports only S16LE.
-- The seconde DAC supports only two channel stereo.
+- The second DAC supports only two channel stereo.
Please note that the CM8x38 DAC doesn't support continuous playback
rate but only fixed rates: 5512, 8000, 11025, 16000, 22050, 32000,
@@ -76,7 +76,7 @@ in alsa-lib. For example, you can play a WAV file with 6 channels like
% aplay -Dsurround51 sixchannels.wav
-For programmin the 4/6 channel playback, you need to specify the PCM
+For programming the 4/6 channel playback, you need to specify the PCM
channels as you like and set the format S16LE. For example, for playback
with 4 channels,
diff --git a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
index 4807ef79a94d..077fbe25ebf4 100644
--- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl
@@ -5486,7 +5486,7 @@ struct _snd_pcm_runtime {
<chapter id="power-management">
<title>Power Management</title>
<para>
- If the chip is supposed to work with with suspend/resume
+ If the chip is supposed to work with suspend/resume
functions, you need to add the power-management codes to the
driver. The additional codes for the power-management should be
<function>ifdef</function>'ed with
diff --git a/Documentation/sound/alsa/MIXART.txt b/Documentation/sound/alsa/MIXART.txt
index 5cb970612870..ef42c44fa1f2 100644
--- a/Documentation/sound/alsa/MIXART.txt
+++ b/Documentation/sound/alsa/MIXART.txt
@@ -31,7 +31,7 @@ With a miXart8AES/EBU there is in addition 1 stereo digital input
Formats
-------
U8, S16_LE, S16_BE, S24_3LE, S24_3BE, FLOAT_LE, FLOAT_BE
-Sample rates : 8000 - 48000 Hz continously
+Sample rates : 8000 - 48000 Hz continuously
Playback
--------
@@ -39,7 +39,7 @@ For instance the playback devices are configured to have max. 4
substreams performing hardware mixing. This could be changed to a
maximum of 24 substreams if wished.
Mono files will be played on the left and right channel. Each channel
-can be muted for each stream to use 8 analog/digital outputs seperately.
+can be muted for each stream to use 8 analog/digital outputs separately.
Capture
-------
@@ -97,4 +97,4 @@ COPYRIGHT
=========
Copyright (c) 2003 Digigram SA <alsa@digigram.com>
-Distributalbe under GPL.
+Distributable under GPL.
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
index 1fe48846d78f..f738b296440a 100644
--- a/Documentation/sound/alsa/Procfile.txt
+++ b/Documentation/sound/alsa/Procfile.txt
@@ -71,7 +71,7 @@ The status of MIDI I/O is found in midi* files. It shows the device
name and the received/transmitted bytes through the MIDI device.
When the card is equipped with AC97 codecs, there are codec97#*
-subdirectories (desribed later).
+subdirectories (described later).
When the OSS mixer emulation is enabled (and the module is loaded),
oss_mixer file appears here, too. This shows the current mapping of
@@ -161,12 +161,12 @@ seq/drivers
Lists the currently available ALSA sequencer drivers.
seq/clients
- Shows the list of currently available sequencer clinets and
+ Shows the list of currently available sequencer clients and
ports. The connection status and the running status are shown
in this file, too.
seq/queues
- Lists the currently allocated/running sequener queues.
+ Lists the currently allocated/running sequencer queues.
seq/timer
Lists the currently allocated/running sequencer timers.
@@ -182,10 +182,10 @@ When the problem is related with PCM, first try to turn on xrun_debug
mode. This will give you the kernel messages when and where xrun
happened.
-If it's really a bug, report it with the following information
+If it's really a bug, report it with the following information:
- the name of the driver/card, show in /proc/asound/cards
- - the reigster dump, if available (e.g. card*/cmipci)
+ - the register dump, if available (e.g. card*/cmipci)
when it's a PCM problem,
diff --git a/Documentation/sound/oss/AWE32 b/Documentation/sound/oss/AWE32
deleted file mode 100644
index cb179bfeb522..000000000000
--- a/Documentation/sound/oss/AWE32
+++ /dev/null
@@ -1,76 +0,0 @@
- Installing and using Creative AWE midi sound under Linux.
-
-This documentation is devoted to the Creative Sound Blaster AWE32, AWE64 and
-SB32.
-
-1) Make sure you have an ORIGINAL Creative SB32, AWE32 or AWE64 card. This
- is important, because the driver works only with real Creative cards.
-
-2) The first thing you need to do is re-compile your kernel with support for
- your sound card. Run your favourite tool to configure the kernel and when
- you get to the "Sound" menu you should enable support for the following:
-
- Sound card support,
- OSS sound modules,
- 100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support,
- AWE32 synth
-
- If your card is "Plug and Play" you will also need to enable these two
- options, found under the "Plug and Play configuration" menu:
-
- Plug and Play support
- ISA Plug and Play support
-
- Now compile and install the kernel in normal fashion. If you don't know
- how to do this you can find instructions for this in the README file
- located in the root directory of the kernel source.
-
-3) Before you can start playing midi files you will have to load a sound
- bank file. The utility needed for doing this is called "sfxload", and it
- is one of the utilities found in a package called "awesfx". If this
- package is not available in your distribution you can download the AWE
- snapshot from Creative Labs Open Source website:
-
- http://www.opensource.creative.com/snapshot.html
-
- Once you have unpacked the AWE snapshot you will see a "awesfx"
- directory. Follow the instructions in awesfx/docs/INSTALL to install the
- utilities in this package. After doing this, sfxload should be installed
- as:
-
- /usr/local/bin/sfxload
-
- To enable AWE general midi synthesis you should also get the sound bank
- file for general midi from:
-
- http://members.xoom.com/yar/synthgm.sbk.gz
-
- Copy it to a directory of your choice, and unpack it there.
-
-4) Edit /etc/modprobe.conf, and insert the following lines at the end of the
- file:
-
- alias sound-slot-0 sb
- alias sound-service-0-1 awe_wave
- install awe_wave /sbin/modprobe --first-time -i awe_wave && /usr/local/bin/sfxload PATH_TO_SOUND_BANK_FILE
-
- You will of course have to change "PATH_TO_SOUND_BANK_FILE" to the full
- path of of the sound bank file. That will enable the Sound Blaster and AWE
- wave synthesis. To play midi files you should get one of these programs if
- you don't already have them:
-
- Playmidi: http://playmidi.openprojects.net
-
- AWEMidi Player (drvmidi) Included in the previously mentioned AWE
- snapshot.
-
- You will probably have to pass the "-e" switch to playmidi to have it use
- your midi device. drvmidi should work without switches.
-
- If something goes wrong please e-mail me. All comments and suggestions are
- welcome.
-
- Yaroslav Rosomakho (alons55@dialup.ptt.ru)
- http://www.yar.opennet.ru
-
-Last Updated: Feb 3 2001
diff --git a/Documentation/sound/oss/CMI8338 b/Documentation/sound/oss/CMI8338
deleted file mode 100644
index 387d058c3f95..000000000000
--- a/Documentation/sound/oss/CMI8338
+++ /dev/null
@@ -1,85 +0,0 @@
-Audio driver for CM8338/CM8738 chips by Chen-Li Tien
-
-
-HARDWARE SUPPORTED
-================================================================================
-C-Media CMI8338
-C-Media CMI8738
-On-board C-Media chips
-
-
-STEPS TO BUILD DRIVER
-================================================================================
-
- 1. Backup the Config.in and Makefile in the sound driver directory
- (/usr/src/linux/driver/sound).
- The Configure.help provide help when you config driver in step
- 4, please backup the original one (/usr/src/linux/Document) and
- copy this file.
- The cmpci is document for the driver in detail, please copy it
- to /usr/src/linux/Document/sound so you can refer it. Backup if
- there is already one.
-
- 2. Extract the tar file by 'tar xvzf cmpci-xx.tar.gz' in the above
- directory.
-
- 3. Change directory to /usr/src/linux
-
- 4. Config cm8338 driver by 'make menuconfig', 'make config' or
- 'make xconfig' command.
-
- 5. Please select Sound Card (CONFIG_SOUND=m) support and CMPCI
- driver (CONFIG_SOUND_CMPCI=m) as modules. Resident mode not tested.
- For driver option, please refer 'DRIVER PARAMETER'
-
- 6. Compile the kernel if necessary.
-
- 7. Compile the modules by 'make modules'.
-
- 8. Install the modules by 'make modules_install'
-
-
-INSTALL DRIVER
-================================================================================
-
- 1. Before first time to run the driver, create module dependency by
- 'depmod -a'
-
- 2. To install the driver manually, enter 'modprobe cmpci'.
-
- 3. Driver installation for various distributions:
-
- a. Slackware 4.0
- Add the 'modprobe cmpci' command in your /etc/rc.d/rc.modules
- file.so you can start the driver automatically each time booting.
-
- b. Caldera OpenLinux 2.2
- Use LISA to load the cmpci module.
-
- c. RedHat 6.0 and S.u.S.E. 6.1
- Add following command in /etc/conf.modules:
-
- alias sound cmpci
-
- also visit http://www.cmedia.com.tw for installation instruction.
-
-DRIVER PARAMETER
-================================================================================
-
- Some functions for the cm8738 can be configured in Kernel Configuration
- or modules parameters. Set these parameters to 1 to enable.
-
- mpuio: I/O ports base for MPU-401, 0 if disabled.
- fmio: I/O ports base for OPL-3, 0 if disabled.
- spdif_inverse:Inverse the S/PDIF-in signal, this depends on your
- CD-ROM or DVD-ROM.
- spdif_loop: Enable S/PDIF loop, this route S/PDIF-in to S/PDIF-out
- directly.
- speakers: Number of speakers used.
- use_line_as_rear:Enable this if you want to use line-in as
- rear-out.
- use_line_as_bass:Enable this if you want to use line-in as
- bass-out.
- joystick: Enable joystick. You will need to install Linux joystick
- driver.
-
diff --git a/Documentation/sound/oss/INSTALL.awe b/Documentation/sound/oss/INSTALL.awe
deleted file mode 100644
index 310f42ca1e83..000000000000
--- a/Documentation/sound/oss/INSTALL.awe
+++ /dev/null
@@ -1,134 +0,0 @@
-================================================================
- INSTALLATION OF AWE32 SOUND DRIVER FOR LINUX
- Takashi Iwai <iwai@ww.uni-erlangen.de>
-================================================================
-
-----------------------------------------------------------------
-* Attention to SB-PnP Card Users
-
-If you're using PnP cards, the initialization of PnP is required
-before loading this driver. You have now three options:
- 1. Use isapnptools.
- 2. Use in-kernel isapnp support.
- 3. Initialize PnP on DOS/Windows, then boot linux by loadlin.
-In this document, only the case 1 case is treated.
-
-----------------------------------------------------------------
-* Installation on Red Hat 5.0 Sound Driver
-
-Please use install-rh.sh under RedHat5.0 directory.
-DO NOT USE install.sh below.
-See INSTALL.RH for more details.
-
-----------------------------------------------------------------
-* Installation/Update by Shell Script
-
- 1. Become root
-
- % su
-
- 2. If you have never configured the kernel tree yet, run make config
- once (to make dependencies and symlinks).
-
- # cd /usr/src/linux
- # make xconfig
-
- 3. Run install.sh script
-
- # sh ./install.sh
-
- 4. Configure your kernel
-
- (for Linux 2.[01].x user)
- # cd /usr/src/linux
- # make xconfig (or make menuconfig)
-
- (for Linux 1.2.x user)
- # cd /usr/src/linux
- # make config
-
- Answer YES to both "lowlevel drivers" and "AWE32 wave synth" items
- in Sound menu. ("lowlevel drivers" will appear only in 2.x
- kernel.)
-
- 5. Make your kernel (and modules), and install them as usual.
-
- 5a. make kernel image
- # make zImage
-
- 5b. make modules and install them
- # make modules && make modules_install
-
- 5c. If you're using lilo, copy the kernel image and run lilo.
- Otherwise, copy the kernel image to suitable directory or
- media for your system.
-
- 6. Reboot the kernel if necessary.
- - If you updated only the modules, you don't have to reboot
- the system. Just remove the old sound modules here.
- in
- # rmmod sound.o (linux-2.0 or OSS/Free)
- # rmmod awe_wave.o (linux-2.1)
-
- 7. If your AWE card is a PnP and not initialized yet, you'll have to
- do it by isapnp tools. Otherwise, skip to 8.
-
- This section described only a brief explanation. For more
- details, please see the AWE64-Mini-HOWTO or isapnp tools FAQ.
-
- 7a. If you have no isapnp.conf file, generate it by pnpdump.
- Otherwise, skip to 7d.
- # pnpdump > /etc/isapnp.conf
-
- 7b. Edit isapnp.conf file. Comment out the appropriate
- lines containing desirable I/O ports, DMA and IRQs.
- Don't forget to enable (ACT Y) line.
-
- 7c. Add two i/o ports (0xA20 and 0xE20) in WaveTable part.
- ex)
- (CONFIGURE CTL0048/58128 (LD 2
- # ANSI string -->WaveTable<--
- (IO 0 (BASE 0x0620))
- (IO 1 (BASE 0x0A20))
- (IO 2 (BASE 0x0E20))
- (ACT Y)
- ))
-
- 7d. Load the config file.
- CAUTION: This will reset all PnP cards!
-
- # isapnp /etc/isapnp.conf
-
- 8. Load the sound module (if you configured it as a module):
-
- for 2.0 kernel or OSS/Free monolithic module:
-
- # modprobe sound.o
-
- for 2.1 kernel:
-
- # modprobe sound
- # insmod uart401
- # insmod sb io=0x220 irq=5 dma=1 dma16=5 mpu_io=0x330
- (These values depend on your settings.)
- # insmod awe_wave
- (Be sure to load awe_wave after sb!)
-
- See Documentation/sound/oss/AWE32 for
- more details.
-
- 9. (only for obsolete systems) If you don't have /dev/sequencer
- device file, make it according to Readme.linux file on
- /usr/src/linux/drivers/sound. (Run a shell script included in
- that file). <-- This file no longer exists in the recent kernels!
-
- 10. OK, load your own soundfont file, and enjoy MIDI!
-
- % sfxload synthgm.sbk
- % drvmidi foo.mid
-
- 11. For more advanced use (eg. dynamic loading, virtual bank and
- etc.), please read the awedrv FAQ or the instructions in awesfx
- and awemidi packages.
-
-Good luck!
diff --git a/Documentation/sound/oss/MAD16 b/Documentation/sound/oss/MAD16
deleted file mode 100644
index 865dbd848742..000000000000
--- a/Documentation/sound/oss/MAD16
+++ /dev/null
@@ -1,56 +0,0 @@
-(This recipe has been edited to update the configuration symbols,
- and change over to modprobe.conf for 2.6)
-
-From: Shaw Carruthers <shaw@shawc.demon.co.uk>
-
-I have been using mad16 sound for some time now with no problems, current
-kernel 2.1.89
-
-lsmod shows:
-
-mad16 5176 0
-sb 22044 0 [mad16]
-uart401 5576 0 [mad16 sb]
-ad1848 14176 1 [mad16]
-sound 61928 0 [mad16 sb uart401 ad1848]
-
-.config has:
-
-CONFIG_SOUND=m
-CONFIG_SOUND_ADLIB=m
-CONFIG_SOUND_MAD16=m
-CONFIG_SOUND_YM3812=m
-
-modprobe.conf has:
-
-alias char-major-14-* mad16
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-
-To get the built in mixer to work this needs to be:
-
-options adlib_card io=0x388 # FM synthesizer
-options sb mad16=1
-options mad16 io=0x530 irq=7 dma=0 dma16=1 mpu_io=816 mpu_irq=5 && /usr/local/bin/aumix -w 15 -p 20 -m 0 -1 0 -2 0 -3 0 -i 0
-
-The addition of the "mpu_io=816 mpu_irq=5" to the mad16 options line is
-
-------------------------------------------------------------------------
-The mad16 module in addition supports the following options:
-
-option: meaning: default:
-joystick=0,1 disabled, enabled disabled
-cdtype=0x00,0x02,0x04, disabled, Sony CDU31A, disabled
- 0x06,0x08,0x0a Mitsumi, Panasonic,
- Secondary IDE, Primary IDE
-cdport=0x340,0x320, 0x340
- 0x330,0x360
-cdirq=0,3,5,7,9,10,11 disabled, IRQ3, ... disabled
-cddma=0,5,6,7 disabled, DMA5, ... DMA5 for Mitsumi or IDE
-cddma=0,1,2,3 disabled, DMA1, ... DMA3 for Sony or Panasonic
-opl4=0,1 OPL3, OPL4 OPL3
-
-for more details see linux/drivers/sound/mad16.c
-
-Rui Sousa
diff --git a/Documentation/sound/oss/Maestro b/Documentation/sound/oss/Maestro
deleted file mode 100644
index 4a80eb3f8e00..000000000000
--- a/Documentation/sound/oss/Maestro
+++ /dev/null
@@ -1,123 +0,0 @@
- An OSS/Lite Driver for the ESS Maestro family of sound cards
-
- Zach Brown, December 1999
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
- http://www.zabbo.net/maestro/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-ESS Maestro Chip Family
------------------------
-
-There are 3 main variants of the ESS Maestro PCI sound chip. The first
-is the Maestro 1. It was originally produced by Platform Tech as the
-'AGOGO'. It can be recognized by Platform Tech's PCI ID 0x1285 with
-0x0100 as the device ID. It was put on some sound boards and a few laptops.
-ESS bought the design and cleaned it up as the Maestro 2. This starts
-their marking with the ESS vendor ID 0x125D and the 'year' device IDs.
-The Maestro 2 claims 0x1968 while the Maestro 2e has 0x1978.
-
-The various families of Maestro are mostly identical as far as this
-driver is concerned. It doesn't touch the DSP parts that differ (though
-it could for FM synthesis).
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec. This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves almost as expected. Playback is
-supported in all the various lovely formats. 8/16bit stereo/mono from
-8khz to 48khz, and mmap()ing for playback behaves. Capture/recording
-is limited due to oddities with the Maestro hardware. One can only
-record in 16bit stereo. For recording the maestro uses non interleaved
-stereo buffers so that mmap()ing the incoming data does not result in
-a ring buffer of LRLR data. mmap()ing of the read buffers is therefore
-disallowed until this can be cleaned up.
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro. It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro. Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them.
-
-The driver doesn't support MIDI or FM playback at the moment. Typically
-the Maestro is wired to an MPU MIDI chip, but some hardware implementations
-don't. We need to assemble a white list of hardware implementations that
-have MIDI wired properly before we can claim to support it safely.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers. Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO variable
-in the config system.
-
-It may be modular or statically linked. If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere. 'alias sound maestro'
-should also be added to your module configs (typically /etc/conf.modules)
-if you're using modular OSS/Lite sound and want to default to using a
-maestro chip.
-
-As this is a PCI device, the module does not need to be informed of
-any IO or IRQ resources it should use, it devines these from the
-system. Sometimes, on sucky PCs, the BIOS fails to allocated resources
-for the maestro. This will result in a message like:
- maestro: PCI subsystem reports IRQ 0, this might not be correct.
-from the kernel. Should this happen the sound chip most likely will
-not operate correctly. To solve this one has to dig through their BIOS
-(typically entered by hitting a hot key at boot time) and figure out
-what magic needs to happen so that the BIOS will reward the maestro with
-an IRQ. This operation is incredibly system specific, so you're on your
-own. Sometimes the magic lies in 'PNP Capable Operating System' settings.
-
-There are very few options to the driver. One is 'debug' which will
-tell the driver to print minimal debugging information as it runs. This
-can be collected with 'dmesg' or through the klogd daemon.
-
-The other, more interesting option, is 'dsps_order'. Typically at
-install time the driver will only register one available /dev/dsp device
-for its use. The 'dsps_order' module parameter allows for more devices
-to be allocated, as a power of two. Up to 4 devices can be registered
-( dsps_order=2 ). These devices act as fully distinct units and use
-separate channels in the maestro.
-
-Power Management
-----------------
-
-As of version 0.14, this driver has a minimal understanding of PCI
-Power Management. If it finds a valid power management capability
-on the PCI device it will attempt to use the power management
-functions of the maestro. It will only do this on Maestro 2Es and
-only on machines that are known to function well. You can
-force the use of power management by setting the 'use_pm' module
-option to 1, or can disable it entirely by setting it to 0.
-
-When using power management, the driver does a few things
-differently. It will keep the chip in a lower power mode
-when the module is inserted but /dev/dsp is not open. This
-allows the mixer to function but turns off the clocks
-on other parts of the chip. When /dev/dsp is opened the chip
-is brought into full power mode, and brought back down
-when it is closed. It also powers down the chip entirely
-when the module is removed or the machine is shutdown. This
-can have nonobvious consequences. CD audio may not work
-after a power managing driver is removed. Also, software that
-doesn't understand power management may not be able to talk
-to the powered down chip until the machine goes through a hard
-reboot to bring it back.
-
-.. more details ..
-------------------
-
-drivers/sound/maestro.c contains comments that hopefully explain
-the maestro implementation.
diff --git a/Documentation/sound/oss/Maestro3 b/Documentation/sound/oss/Maestro3
deleted file mode 100644
index a113718e8034..000000000000
--- a/Documentation/sound/oss/Maestro3
+++ /dev/null
@@ -1,92 +0,0 @@
- An OSS/Lite Driver for the ESS Maestro3 family of sound chips
-
- Zach Brown, January 2001
-
-Driver Status and Availability
-------------------------------
-
-The most recent version of this driver will hopefully always be available at
- http://www.zabbo.net/maestro3/
-
-I will try and maintain the most recent stable version of the driver
-in both the stable and development kernel lines.
-
-Historically I've sucked pretty hard at actually doing that, however.
-
-ESS Maestro3 Chip Family
------------------------
-
-The 'Maestro3' is much like the Maestro2 chip. The noted improvement
-is the removal of the silicon in the '2' that did PCM mixing. All that
-work is now done through a custom DSP called the ASSP, the Asynchronus
-Specific Signal Processor.
-
-The 'Allegro' is a baby version of the Maestro3. I'm not entirely clear
-on the extent of the differences, but the driver supports them both :)
-
-The 'Allegro' shows up as PCI ID 0x1988 and the Maestro3 as 0x1998,
-both under ESS's vendor ID of 0x125D. The Maestro3 can also show up as
-0x199a when hardware strapping is used.
-
-The chip can also act as a multi function device. The modem IDs follow
-the audio multimedia device IDs. (so the modem part of an Allegro shows
-up as 0x1989)
-
-Driver OSS Behavior
---------------------
-
-This OSS driver exports /dev/mixer and /dev/dsp to applications, which
-mostly adhere to the OSS spec. This driver doesn't register itself
-with /dev/sndstat, so don't expect information to appear there.
-
-The /dev/dsp device exported behaves as expected. Playback is
-supported in all the various lovely formats. 8/16bit stereo/mono from
-8khz to 48khz, with both read()/write(), and mmap().
-
-/dev/mixer is an interface to the AC'97 codec on the Maestro3. It is
-worth noting that there are a variety of AC'97s that can be wired to
-the Maestro3. Which is used is entirely up to the hardware implementor.
-This should only be visible to the user by the presence, or lack, of
-'Bass' and 'Treble' sliders in the mixer. Not all AC'97s have them.
-The Allegro has an onchip AC'97.
-
-The driver doesn't support MIDI or FM playback at the moment.
-
-Compiling and Installing
-------------------------
-
-With the drivers inclusion into the kernel, compiling and installing
-is the same as most OSS/Lite modular sound drivers. Compilation
-of the driver is enabled through the CONFIG_SOUND_MAESTRO3 variable
-in the config system.
-
-It may be modular or statically linked. If it is modular it should be
-installed with the rest of the modules for the kernel on the system.
-Typically this will be in /lib/modules/ somewhere. 'alias sound-slot-0
-maestro3' should also be added to your module configs (typically
-/etc/modprobe.conf) if you're using modular OSS/Lite sound and want to
-default to using a maestro3 chip.
-
-There are very few options to the driver. One is 'debug' which will
-tell the driver to print minimal debugging information as it runs. This
-can be collected with 'dmesg' or through the klogd daemon.
-
-One is 'external_amp', which tells the driver to attempt to enable
-an external amplifier. This defaults to '1', you can tell the driver
-not to bother enabling such an amplifier by setting it to '0'.
-
-And the last is 'gpio_pin', which tells the driver which GPIO pin number
-the external amp uses (0-15), The Allegro uses 8 by default, all others 1.
-If everything loads correctly and seems to be working but you get no sound,
-try tweaking this value.
-
-Systems known to need a different value
- Panasonic ToughBook CF-72: gpio_pin=13
-
-Power Management
-----------------
-
-This driver has a minimal understanding of PCI Power Management. It will
-try and power down the chip when the system is suspended, and power
-it up with it is resumed. It will also try and power down the chip
-when the machine is shut down.
diff --git a/Documentation/sound/oss/NEWS b/Documentation/sound/oss/NEWS
deleted file mode 100644
index a81e0ef72ae9..000000000000
--- a/Documentation/sound/oss/NEWS
+++ /dev/null
@@ -1,42 +0,0 @@
-Linux 2.4 Sound Changes
-2000-September-25
-Christoph Hellwig, <hch@infradead.org>
-
-
-
-=== isapnp support
-
-The Linux 2.4 Kernel does have reliable in-kernel isapnp support.
-Some drivers (sb.o, ad1816.o awe_wave.o) do now support automatically
-detecting and configuring isapnp devices.
-If you have a not yet supported isapnp soundcard, mail me the content
-of '/proc/isapnp' on your system and some information about your card
-and its driver(s) so I can try to get isapnp working for it.
-
-
-
-=== soundcard resources on kernel commandline
-
-Before Linux 2.4 you had to specify the resources for sounddrivers
-statically linked into the kernel at compile time
-(in make config/menuconfig/xconfig). In Linux 2.4 the resources are
-now specified at the boot-time kernel commandline (e.g. the lilo
-'append=' line or everything that's after the kernel name in grub).
-Read the Configure.help entry for your card for the parameters.
-
-
-=== softoss is gone
-
-In Linux 2.4 the softoss in-kernel software synthesizer is no more aviable.
-Use a user space software synthesizer like timidity instead.
-
-
-
-=== /dev/sndstat and /proc/sound are gone
-
-In older Linux versions those files exported some information about the
-OSS/Free configuration to userspace. In Linux 2.3 they were removed because
-they did not support the growing number of pci soundcards and there were
-some general problems with this interface.
-
-
diff --git a/Documentation/sound/oss/OPL3-SA b/Documentation/sound/oss/OPL3-SA
deleted file mode 100644
index 66a91835d918..000000000000
--- a/Documentation/sound/oss/OPL3-SA
+++ /dev/null
@@ -1,52 +0,0 @@
-OPL3-SA1 sound driver (opl3sa.o)
-
----
-Note: This howto only describes how to setup the OPL3-SA1 chip; this info
-does not apply to the SA2, SA3, or SA4.
----
-
-The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and
-it's a decent little chip offering a WSS mode, a SB Pro emulation mode, MPU401
-and OPL3 FM Synth capabilities.
-
-You can enable inclusion of the driver via CONFIG_SOUND_OPL3SA1=m, or
-CONFIG_SOUND_OPL3SA1=y through 'make config/xconfig/menuconfig'.
-
-You'll need to know all of the relevant info (irq, dma, and io port) for the
-chip's WSS mode, since that is the mode the kernel sound driver uses, and of
-course you'll also need to know about where the MPU401 and OPL3 ports and
-IRQs are if you want to use those.
-
-Here's the skinny on how to load it as a module:
-
- modprobe opl3sa io=0x530 irq=11 dma=0 dma2=1 mpu_io=0x330 mpu_irq=5
-
-Module options in detail:
-
- io: This is the WSS's port base.
- irq: This is the WSS's IRQ.
- dma: This is the WSS's DMA line. In my BIOS setup screen this was
- listed as "WSS Play DMA"
- dma2: This is the WSS's secondary DMA line. My BIOS calls it the
- "WSS capture DMA"
-
- mpu_io: This is the MPU401's port base.
- mpu_irq: This is the MPU401's IRQ.
-
-If you'd like to use the OPL3 FM Synthesizer, make sure you enable
-CONFIG_SOUND_YM3812 (in 'make config'). That'll build the opl3.o module.
-
-Then a simple 'insmod opl3 io=0x388', and you now have FM Synth.
-
-You can also use the SoftOSS software synthesizer instead of the builtin OPL3.
-Here's how:
-
-Say 'y' or 'm' to "SoftOSS software wave table engine" in make config.
-
-If you said yes, the software synth is available once you boot your new
-kernel.
-
-If you chose to build it as a module, just insmod the resulting softoss2.o
-
-Questions? Comments?
-<stiker@northlink.com>
diff --git a/Documentation/sound/oss/README.awe b/Documentation/sound/oss/README.awe
deleted file mode 100644
index 80054cd8fcde..000000000000
--- a/Documentation/sound/oss/README.awe
+++ /dev/null
@@ -1,218 +0,0 @@
-================================================================
- AWE32 Sound Driver for Linux / FreeBSD
- version 0.4.3; Nov. 1, 1998
-
- Takashi Iwai <iwai@ww.uni-erlangen.de>
-================================================================
-
-* GENERAL NOTES
-
-This is a sound driver extension for SoundBlaster AWE32 and other
-compatible cards (AWE32-PnP, SB32, SB32-PnP, AWE64 & etc) to enable
-the wave synth operations. The driver is provided for Linux 1.2.x
-and 2.[012].x kernels, as well as FreeBSD, on Intel x86 and DEC
-Alpha systems.
-
-This driver was written by Takashi Iwai <iwai@ww.uni-erlangen.de>,
-and provided "as is". The original source (awedrv-0.4.3.tar.gz) and
-binary packages are available on the following URL:
- http://bahamut.mm.t.u-tokyo.ac.jp/~iwai/awedrv/
-Note that since the author is apart from this web site, the update is
-not frequent now.
-
-
-* NOTE TO LINUX USERS
-
-To enable this driver on linux-2.[01].x kernels, you need turn on
-"AWE32 synth" options in sound menu when configure your linux kernel
-and modules. The precise installation procedure is described in the
-AWE64-Mini-HOWTO and linux-kernel/Documetation/sound/AWE32.
-
-If you're using PnP cards, the card must be initialized before loading
-the sound driver. There're several options to do this:
- - Initialize the card via ISA PnP tools, and load the sound module.
- - Initialize the card on DOS, and load linux by loadlin.exe
- - Use PnP kernel driver (for Linux-2.x.x)
-The detailed instruction for the solution using isapnp tools is found
-in many documents like above. A brief instruction is also included in
-the installation document of this package.
-For PnP driver project, please refer to the following URL:
- http://www-jcr.lmh.ox.ac.uk/~pnp/
-
-
-* USING THE DRIVER
-
-The awedrv has several different playing modes to realize easy channel
-allocation for MIDI songs. To hear the exact sound quality, you need
-to obtain the extended sequencer program, drvmidi or playmidi-2.5.
-
-For playing MIDI files, you *MUST* load the soundfont file on the
-driver previously by sfxload utility. Otherwise you'll here no sounds
-at all! All the utilities and driver source packages are found in the
-above URL. The sfxload program is included in the package
-awesfx-0.4.3.tgz. Binary packages are available there, too. See the
-instruction in each package for installation.
-
-Loading a soundfont file is very simple. Just execute the command
-
- % sfxload synthgm.sbk
-
-Then, sfxload transfers the file "synthgm.sbk" to the driver.
-Both SF1 and SF2 formats are accepted.
-
-Now you can hear midi musics by a midi player.
-
- % drvmidi foo.mid
-
-If you run MIDI player after MOD player, you need to load soundfont
-files again, since MOD player programs clear the previous loaded
-samples by their own data.
-
-If you have only 512kb on the sound card, I recommend to use dynamic
-sample loading via -L option of drvmidi. 2MB GM/GS soundfont file is
-available in most midi files.
-
- % sfxload synthgm
- % drvmidi -L 2mbgmgs foo.mid
-
-This makes a big difference (believe me)! For more details, please
-refer to the FAQ list which is available on the URL above.
-
-The current chorus, reverb and equalizer status can be changed by
-aweset utility program (included in awesfx package). Note that
-some awedrv-native programs (like drvmidi and xmp) will change the
-current settings by themselves. The aweset program is effective
-only for other programs like playmidi.
-
-Enjoy.
-
-
-* COMPILE FLAGS
-
-Compile conditions are defined in awe_config.h.
-
-[Compatibility Conditions]
-The following flags are defined automatically when using installation
-shell script.
-
-- AWE_MODULE_SUPPORT
- indicates your Linux kernel supports module for each sound card
- (in recent 2.1 or 2.2 kernels and unofficial patched 2.0 kernels
- as distributed in the RH5.0 package).
- This flag is automatically set when you're using 2.1.x kernels.
- You can pass the base address and memory size via the following
- module options,
- io = base I/O port address (eg. 0x620)
- memsize = DRAM size in kilobytes (eg. 512)
- As default, AWE driver probes these values automatically.
-
-
-[Hardware Conditions]
-You DON'T have to define the following two values.
-Define them only when the driver couldn't detect the card properly.
-
-- AWE_DEFAULT_BASE_ADDR (default: not defined)
- specifies the base port address of your AWE32 card.
- 0 means to autodetect the address.
-
-- AWE_DEFAULT_MEM_SIZE (default: not defined)
- specifies the memory size of your AWE32 card in kilobytes.
- -1 means to autodetect its size.
-
-
-[Sample Table Size]
-From ver.0.4.0, sample tables are allocated dynamically (except
-Linux-1.2.x system), so you need NOT to touch these parameters.
-Linux-1.2.x users may need to increase these values to appropriate size
-if the sound card is equipped with more DRAM.
-
-- AWE_MAX_SF_LISTS, AWE_MAX_SAMPLES, AWE_MAX_INFOS
-
-
-[Other Conditions]
-
-- AWE_ALWAYS_INIT_FM (default: not defined)
- indicates the AWE driver always initialize FM passthrough even
- without DRAM on board. Emu8000 chip has a restriction for playing
- samples on DRAM that at least two channels must be occupied as
- passthrough channels.
-
-- AWE_DEBUG_ON (default: defined)
- turns on debugging messages if defined.
-
-- AWE_HAS_GUS_COMPATIBILITY (default: defined)
- Enables GUS compatibility mode if defined, reading GUS patches and
- GUS control commands. Define this option to use GMOD or other
- GUS module players.
-
-- CONFIG_AWE32_MIDIEMU (default: defined)
- Adds a MIDI emulation device by Emu8000 wavetable. The emulation
- device can be accessed as an external MIDI, and sends the MIDI
- control codes directly. XG and GS sysex/NRPN are accepted.
- No MIDI input is supported.
-
-- CONFIG_AWE32_MIXER (default: not defined)
- Adds a mixer device for AWE32 bass/treble equalizer control.
- You can access this device using /dev/mixer?? (usually mixer01).
-
-- AWE_USE_NEW_VOLUME_CALC (default: defined)
- Use the new method to calculate the volume change as compatible
- with DOS/Win drivers. This option can be toggled via aweset
- program, or drvmidi player.
-
-- AWE_CHECK_VTARGET (default: defined)
- Check the current volume target value when searching for an
- empty channel to allocate a new voice. This is experimentally
- implemented in this version. (probably, this option doesn't
- affect the sound quality severely...)
-
-- AWE_ALLOW_SAMPLE_SHARING (default: defined)
- Allow sample sharing for differently loaded patches.
- This function is available only together with awesfx-0.4.3p3.
- Note that this is still an experimental option.
-
-- DEF_FM_CHORUS_DEPTH (default: 0x10)
- The default strength to be sent to the chorus effect engine.
- From 0 to 0xff. Larger numbers may often cause weird sounds.
-
-- DEF_FM_REVERB_DEPTH (default: 0x10)
- The default strength to be sent to the reverb effect engine.
- From 0 to 0xff. Larger numbers may often cause weird sounds.
-
-
-* ACKNOWLEDGMENTS
-
-Thanks to Witold Jachimczyk (witek@xfactor.wpi.edu) for much advice
-on programming of AWE32. Much code is brought from his AWE32-native
-MOD player, ALMP.
-The port of awedrv to FreeBSD is done by Randall Hopper
-(rhh@ct.picker.com).
-The new volume calculation routine was derived from Mark Weaver's
-ADIP compatible routines.
-I also thank linux-awe-ml members for their efforts
-to reboot their system many times :-)
-
-
-* TODO'S
-
-- Complete DOS/Win compatibility
-- DSP-like output
-
-
-* COPYRIGHT
-
-Copyright (C) 1996-1998 Takashi Iwai
-
-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., 675 Mass Ave, Cambridge, MA 02139, USA.
diff --git a/Documentation/sound/oss/Wavefront b/Documentation/sound/oss/Wavefront
deleted file mode 100644
index 16f57ea43052..000000000000
--- a/Documentation/sound/oss/Wavefront
+++ /dev/null
@@ -1,339 +0,0 @@
- An OSS/Free Driver for WaveFront soundcards
- (Turtle Beach Maui, Tropez, Tropez Plus)
-
- Paul Barton-Davis, July 1998
-
- VERSION 0.2.5
-
-Driver Status
--------------
-
-Requires: Kernel 2.1.106 or later (the driver is included with kernels
-2.1.109 and above)
-
-As of 7/22/1998, this driver is currently in *BETA* state. This means
-that it compiles and runs, and that I use it on my system (Linux
-2.1.106) with some reasonably demanding applications and uses. I
-believe the code is approaching an initial "finished" state that
-provides bug-free support for the Tropez Plus.
-
-Please note that to date, the driver has ONLY been tested on a Tropez
-Plus. I would very much like to hear (and help out) people with Tropez
-and Maui cards, since I think the driver can support those cards as
-well.
-
-Finally, the driver has not been tested (or even compiled) as a static
-(non-modular) part of the kernel. Alan Cox's good work in modularizing
-OSS/Free for Linux makes this rather unnecessary.
-
-Some Questions
---------------
-
-**********************************************************************
-0) What does this driver do that the maui driver did not ?
-**********************************************************************
-
-* can fully initialize a WaveFront card from cold boot - no DOS
- utilities needed
-* working patch/sample/program loading and unloading (the maui
- driver didn't document how to make this work, and assumed
- user-level preparation of the patch data for writing
- to the board. ick.)
-* full user-level access to all WaveFront commands
-* for the Tropez Plus, (primitive) control of the YSS225 FX processor
-* Virtual MIDI mode supported - 2 MIDI devices accessible via the
- WaveFront's MPU401/UART emulation. One
- accesses the WaveFront synth, the other accesses the
- external MIDI connector. Full MIDI read/write semantics
- for both devices.
-* OSS-compliant /dev/sequencer interface for the WaveFront synth,
- including native and GUS-format patch downloading.
-* semi-intelligent patch management (prototypical at this point)
-
-**********************************************************************
-1) What to do about MIDI interfaces ?
-**********************************************************************
-
-The Tropez Plus (and perhaps other WF cards) can in theory support up
-to 2 physical MIDI interfaces. One of these is connected to the
-ICS2115 chip (the WaveFront synth itself) and is controlled by
-MPU/UART-401 emulation code running as part of the WaveFront OS. The
-other is controlled by the CS4232 chip present on the board. However,
-physical access to the CS4232 connector is difficult, and it is
-unlikely (though not impossible) that you will want to use it.
-
-An older version of this driver introduced an additional kernel config
-variable which controlled whether or not the CS4232 MIDI interface was
-configured. Because of Alan Cox's work on modularizing the sound
-drivers, and now backporting them to 2.0.34 kernels, there seems to be
-little reason to support "static" configuration variables, and so this
-has been abandoned in favor of *only* module parameters. Specifying
-"mpuio" and "mpuirq" for the cs4232 parameter will result in the
-CS4232 MIDI interface being configured; leaving them unspecified will
-leave it unconfigured (and thus unusable).
-
-BTW, I have heard from one Tropez+ user that the CS4232 interface is
-more reliable than the ICS2115 one. I have had no problems with the
-latter, and I don't have the right cable to test the former one
-out. Reports welcome.
-
-**********************************************************************
-2) Why does line XXX of the code look like this .... ?
-**********************************************************************
-
-Either because it's not finished yet, or because you're a better coder
-than I am, or because you don't understand some aspect of how the card
-or the code works.
-
-I absolutely welcome comments, criticisms and suggestions about the
-design and implementation of the driver.
-
-**********************************************************************
-3) What files are included ?
-**********************************************************************
-
- drivers/sound/README.wavefront -- this file
-
- drivers/sound/wavefront.patch -- patches for the 2.1.106 sound drivers
- needed to make the rest of this work
- DO NOT USE IF YOU'VE APPLIED THEM
- BEFORE, OR HAVE 2.1.109 OR ABOVE
-
- drivers/sound/wavfront.c -- the driver
- drivers/sound/ys225.h -- data declarations for FX config
- drivers/sound/ys225.c -- data definitions for FX config
- drivers/sound/wf_midi.c -- the "uart401" driver
- to support virtual MIDI mode.
- include/wavefront.h -- the header file
- Documentation/sound/oss/Tropez+ -- short docs on configuration
-
-**********************************************************************
-4) How do I compile/install/use it ?
-**********************************************************************
-
-PART ONE: install the source code into your sound driver directory
-
- cd <top-of-your-2.1.106-code-base-e.g.-/usr/src/linux>
- tar -zxvf <where-you-put/wavefront.tar.gz>
-
-PART TWO: apply the patches
-
- DO THIS ONLY IF YOU HAVE A KERNEL VERSION BELOW 2.1.109
- AND HAVE NOT ALREADY INSTALLED THE PATCH(ES).
-
- cd drivers/sound
- patch < wavefront.patch
-
-PART THREE: configure your kernel
-
- cd <top of your kernel tree>
- make xconfig (or whichever config option you use)
-
- - choose YES for Sound Support
- - choose MODULE (M) for OSS Sound Modules
- - choose MODULE(M) to YM3812/OPL3 support
- - choose MODULE(M) for WaveFront support
- - choose MODULE(M) for CS4232 support
-
- - choose "N" for everything else (unless you have other
- soundcards you want support for)
-
-
- make boot
- .
- .
- .
- <whatever you normally do for a kernel install>
- make modules
- .
- .
- .
- make modules_install
-
-Here's my autoconf.h SOUND section:
-
-/*
- * Sound
- */
-#define CONFIG_SOUND 1
-#undef CONFIG_SOUND_OSS
-#define CONFIG_SOUND_OSS_MODULE 1
-#undef CONFIG_SOUND_PAS
-#undef CONFIG_SOUND_SB
-#undef CONFIG_SOUND_ADLIB
-#undef CONFIG_SOUND_GUS
-#undef CONFIG_SOUND_MPU401
-#undef CONFIG_SOUND_PSS
-#undef CONFIG_SOUND_MSS
-#undef CONFIG_SOUND_SSCAPE
-#undef CONFIG_SOUND_TRIX
-#undef CONFIG_SOUND_MAD16
-#undef CONFIG_SOUND_WAVEFRONT
-#define CONFIG_SOUND_WAVEFRONT_MODULE 1
-#undef CONFIG_SOUND_CS4232
-#define CONFIG_SOUND_CS4232_MODULE 1
-#undef CONFIG_SOUND_MAUI
-#undef CONFIG_SOUND_SGALAXY
-#undef CONFIG_SOUND_OPL3SA1
-#undef CONFIG_SOUND_SOFTOSS
-#undef CONFIG_SOUND_YM3812
-#define CONFIG_SOUND_YM3812_MODULE 1
-#undef CONFIG_SOUND_VMIDI
-#undef CONFIG_SOUND_UART6850
-/*
- * Additional low level sound drivers
- */
-#undef CONFIG_LOWLEVEL_SOUND
-
-************************************************************
-6) How do I configure my card ?
-************************************************************
-
-You need to edit /etc/modprobe.conf. Here's mine (edited to show the
-relevant details):
-
- # Sound system
- alias char-major-14-* wavefront
- alias synth0 wavefront
- alias mixer0 cs4232
- alias audio0 cs4232
- install wavefront /sbin/modprobe cs4232 && /sbin/modprobe -i wavefront && /sbin/modprobe opl3
- options wavefront io=0x200 irq=9
- options cs4232 synthirq=9 synthio=0x200 io=0x530 irq=5 dma=1 dma2=0
- options opl3 io=0x388
-
-Things to note:
-
- the wavefront options "io" and "irq" ***MUST*** match the "synthio"
- and "synthirq" cs4232 options.
-
- you can do without the opl3 module if you don't
- want to use the OPL/[34] FM synth on the soundcard
-
- the opl3 io parameter is conventionally not adjustable.
- In theory, any not-in-use IO port address would work, but
- just use 0x388 and stick with the crowd.
-
-**********************************************************************
-7) What about firmware ?
-**********************************************************************
-
-Turtle Beach have not given me permission to distribute their firmware
-for the ICS2115. However, if you have a WaveFront card, then you
-almost certainly have the firmware, and if not, its freely available
-on their website, at:
-
- http://www.tbeach.com/tbs/downloads/scardsdown.htm#tropezplus
-
-The file is called WFOS2001.MOT (for the Tropez+).
-
-This driver, however, doesn't use the pure firmware as distributed,
-but instead relies on a somewhat processed form of it. You can
-generate this very easily. Following an idea from Andrew Veliath's
-Pinnacle driver, the following flex program will generate the
-processed version:
-
----- cut here -------------------------
-%option main
-%%
-^S[28].*\r$ printf ("%c%.*s", yyleng-1,yyleng-1,yytext);
-<<EOF>> { fputc ('\0', stdout); return; }
-\n {}
-. {}
----- cut here -------------------------
-
-To use it, put the above in file (say, ws.l) compile it like this:
-
- shell> flex -ows.c ws.l
- shell> cc -o ws ws.c
-
-and then use it like this:
-
- ws < my-copy-of-the-oswf.mot-file > /etc/sound/wavefront.os
-
-If you put it somewhere else, you'll always have to use the wf_ospath
-module parameter (see below) or alter the source code.
-
-**********************************************************************
-7) How do I get it working ?
-**********************************************************************
-
-Optionally, you can reboot with the "new" kernel (even though the only
-changes have really been made to a module).
-
-Then, as root do:
-
- modprobe wavefront
-
-You should get something like this in /var/log/messages:
-
- WaveFront: firmware 1.20 already loaded.
-
-or
-
- WaveFront: no response to firmware probe, assume raw.
-
-then:
-
- WaveFront: waiting for memory configuration ...
- WaveFront: hardware version 1.64
- WaveFront: available DRAM 8191k
- WaveFront: 332 samples used (266 real, 13 aliases, 53 multi), 180 empty
- WaveFront: 128 programs slots in use
- WaveFront: 256 patch slots filled, 142 in use
-
-The whole process takes about 16 seconds, the longest waits being
-after reporting the hardware version (during the firmware download),
-and after reporting program status (during patch status inquiry). Its
-shorter (about 10 secs) if the firmware is already loaded (i.e. only
-warm reboots since the last firmware load).
-
-The "available DRAM" line will vary depending on how much added RAM
-your card has. Mine has 8MB.
-
-To check basically functionality, use play(1) or splay(1) to send a
-.WAV or other audio file through the audio portion. Then use playmidi
-to play a General MIDI file. Try the "-D 0" to hear the
-difference between sending MIDI to the WaveFront and using the OPL/3,
-which is the default (I think ...). If you have an external synth(s)
-hooked to the soundcard, you can use "-e" to route to the
-external synth(s) (in theory, -D 1 should work as well, but I think
-there is a bug in playmidi which prevents this from doing what it
-should).
-
-**********************************************************************
-8) What are the module parameters ?
-**********************************************************************
-
-Its best to read wavefront.c for this, but here is a summary:
-
-integers:
- wf_raw - if set, ignore apparent presence of firmware
- loaded onto the ICS2115, reset the whole
- board, and initialize it from scratch. (default = 0)
-
- fx_raw - if set, always initialize the YSS225 processor
- on the Tropez plus. (default = 1)
-
- < The next 4 are basically for kernel hackers to allow
- tweaking the driver for testing purposes. >
-
- wait_usecs - loop timer used when waiting for
- status conditions on the board.
- The default is 150.
-
- debug_default - debugging flags. See sound/wavefront.h
- for WF_DEBUG_* values. Default is zero.
- Setting this allows you to debug the
- driver during module installation.
-strings:
- ospath - path to get to the pre-processed OS firmware.
- (default: /etc/sound/wavefront.os)
-
-**********************************************************************
-9) Who should I contact if I have problems?
-**********************************************************************
-
-Just me: Paul Barton-Davis <pbd@op.net>
-
-
diff --git a/Documentation/sound/oss/es1370 b/Documentation/sound/oss/es1370
deleted file mode 100644
index 7b38b1a096a3..000000000000
--- a/Documentation/sound/oss/es1370
+++ /dev/null
@@ -1,70 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-This soundcard does not have any hardware MIDI synthesizer;
-MIDI synthesis has to be done in software. To allow this
-the driver/soundcard supports two PCM (/dev/dsp) interfaces.
-The second one goes to the mixer "synth" setting and supports
-only a limited set of sampling rates (44100, 22050, 11025, 5512).
-By setting lineout to 1 on the driver command line
-(eg. insmod es1370 lineout=1) it is even possible on some
-cards to convert the LINEIN jack into a second LINEOUT jack, thus
-making it possible to output four independent audio channels!
-
-There is a freely available software package that allows
-MIDI file playback on this soundcard called Timidity.
-See http://www.cgs.fi/~tt/timidity/.
-
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/Documentation/sound/oss/rme96xx b/Documentation/sound/oss/rme96xx
deleted file mode 100644
index 87d7b7b65fa1..000000000000
--- a/Documentation/sound/oss/rme96xx
+++ /dev/null
@@ -1,767 +0,0 @@
-Beta release of the rme96xx (driver for RME 96XX cards like the
-"Hammerfall" and the "Hammerfall light")
-
-Important: The driver module has to be installed on a freshly rebooted system,
-otherwise the driver might not be able to acquire its buffers.
-
-features:
-
- - OSS programming interface (i.e. runs with standard OSS soundsoftware)
- - OSS/Multichannel interface (OSS multichannel is done by just aquiring
- more than 2 channels). The driver does not use more than one device
- ( yet .. this feature may be implemented later )
- - more than one RME card supported
-
-The driver uses a specific multichannel interface, which I will document
-when the driver gets stable. (take a look at the defines in rme96xx.h,
-which adds blocked multichannel formats i.e instead of
-lrlrlrlr --> llllrrrr etc.
-
-Use the "rmectrl" programm to look at the status of the card ..
-or use xrmectrl, a GUI interface for the ctrl program.
-
-What you can do with the rmectrl program is to set the stereo device for
-OSS emulation (e.g. if you use SPDIF out).
-
-You do:
-
-./ctrl offset 24 24
-
-which makes the stereo device use channels 25 and 26.
-
-Guenter Geiger <geiger@epy.co.at>
-
-copy the first part of the attached source code into rmectrl.c
-and the second part into xrmectrl (or get the program from
-http://gige.xdv.org/pages/soft/pages/rme)
-
-to compile: gcc -o rmectrl rmectrl.c
------------------------------- snip ------------------------------------
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <linux/soundcard.h>
-#include <math.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include "rme96xx.h"
-
-/*
- remctrl.c
- (C) 2000 Guenter Geiger <geiger@debian.org>
- HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-*/
-
-/* # define DEVICE_NAME "/dev/mixer" */
-# define DEVICE_NAME "/dev/mixer1"
-
-
-void usage(void)
-{
- fprintf(stderr,"usage: rmectrl [/dev/mixer<n>] [command [options]]\n\n");
- fprintf(stderr,"where command is one of:\n");
- fprintf(stderr," help show this help\n");
- fprintf(stderr," status show status bits\n");
- fprintf(stderr," control show control bits\n");
- fprintf(stderr," mix show mixer/offset status\n");
- fprintf(stderr," master <n> set sync master\n");
- fprintf(stderr," pro <n> set spdif out pro\n");
- fprintf(stderr," emphasis <n> set spdif out emphasis\n");
- fprintf(stderr," dolby <n> set spdif out no audio\n");
- fprintf(stderr," optout <n> set spdif out optical\n");
- fprintf(stderr," wordclock <n> set sync wordclock\n");
- fprintf(stderr," spdifin <n> set spdif in (0=optical,1=coax,2=intern)\n");
- fprintf(stderr," syncref <n> set sync source (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n");
- fprintf(stderr," adat1cd <n> set ADAT1 on internal CD\n");
- fprintf(stderr," offset <devnr> <in> <out> set dev (0..3) offset (0..25)\n");
- exit(-1);
-}
-
-
-int main(int argc, char* argv[])
-{
- int cards;
- int ret;
- int i;
- double ft;
- int fd, fdwr;
- int param,orig;
- rme_status_t stat;
- rme_ctrl_t ctrl;
- char *device;
- int argidx;
-
- if (argc < 2)
- usage();
-
- if (*argv[1]=='/') {
- device = argv[1];
- argidx = 2;
- }
- else {
- device = DEVICE_NAME;
- argidx = 1;
- }
-
- fprintf(stdout,"mixer device %s\n",device);
- if ((fd = open(device,O_RDONLY)) < 0) {
- fprintf(stdout,"opening device failed\n");
- exit(-1);
- }
-
- if ((fdwr = open(device,O_WRONLY)) < 0) {
- fprintf(stdout,"opening device failed\n");
- exit(-1);
- }
-
- if (argc < argidx+1)
- usage();
-
- if (!strcmp(argv[argidx],"help"))
- usage();
- if (!strcmp(argv[argidx],"-h"))
- usage();
- if (!strcmp(argv[argidx],"--help"))
- usage();
-
- if (!strcmp(argv[argidx],"status")) {
- ioctl(fd,SOUND_MIXER_PRIVATE2,&stat);
- fprintf(stdout,"stat.irq %d\n",stat.irq);
- fprintf(stdout,"stat.lockmask %d\n",stat.lockmask);
- fprintf(stdout,"stat.sr48 %d\n",stat.sr48);
- fprintf(stdout,"stat.wclock %d\n",stat.wclock);
- fprintf(stdout,"stat.bufpoint %d\n",stat.bufpoint);
- fprintf(stdout,"stat.syncmask %d\n",stat.syncmask);
- fprintf(stdout,"stat.doublespeed %d\n",stat.doublespeed);
- fprintf(stdout,"stat.tc_busy %d\n",stat.tc_busy);
- fprintf(stdout,"stat.tc_out %d\n",stat.tc_out);
- fprintf(stdout,"stat.crystalrate %d (0=64k 3=96k 4=88.2k 5=48k 6=44.1k 7=32k)\n",stat.crystalrate);
- fprintf(stdout,"stat.spdif_error %d\n",stat.spdif_error);
- fprintf(stdout,"stat.bufid %d\n",stat.bufid);
- fprintf(stdout,"stat.tc_valid %d\n",stat.tc_valid);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"control")) {
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- fprintf(stdout,"ctrl.start %d\n",ctrl.start);
- fprintf(stdout,"ctrl.latency %d (0=64 .. 7=8192)\n",ctrl.latency);
- fprintf(stdout,"ctrl.master %d\n",ctrl.master);
- fprintf(stdout,"ctrl.ie %d\n",ctrl.ie);
- fprintf(stdout,"ctrl.sr48 %d\n",ctrl.sr48);
- fprintf(stdout,"ctrl.spare %d\n",ctrl.spare);
- fprintf(stdout,"ctrl.doublespeed %d\n",ctrl.doublespeed);
- fprintf(stdout,"ctrl.pro %d\n",ctrl.pro);
- fprintf(stdout,"ctrl.emphasis %d\n",ctrl.emphasis);
- fprintf(stdout,"ctrl.dolby %d\n",ctrl.dolby);
- fprintf(stdout,"ctrl.opt_out %d\n",ctrl.opt_out);
- fprintf(stdout,"ctrl.wordclock %d\n",ctrl.wordclock);
- fprintf(stdout,"ctrl.spdif_in %d (0=optical,1=coax,2=intern)\n",ctrl.spdif_in);
- fprintf(stdout,"ctrl.sync_ref %d (0=ADAT1,1=ADAT2,2=ADAT3,3=SPDIF)\n",ctrl.sync_ref);
- fprintf(stdout,"ctrl.spdif_reset %d\n",ctrl.spdif_reset);
- fprintf(stdout,"ctrl.spdif_select %d\n",ctrl.spdif_select);
- fprintf(stdout,"ctrl.spdif_clock %d\n",ctrl.spdif_clock);
- fprintf(stdout,"ctrl.spdif_write %d\n",ctrl.spdif_write);
- fprintf(stdout,"ctrl.adat1_cd %d\n",ctrl.adat1_cd);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"mix")) {
- rme_mixer mix;
- int i;
-
- for (i=0; i<4; i++) {
- mix.devnr = i;
- ioctl(fd,SOUND_MIXER_PRIVATE1,&mix);
- if (mix.devnr == i) {
- fprintf(stdout,"devnr %d\n",mix.devnr);
- fprintf(stdout,"mix.i_offset %2d (0-25)\n",mix.i_offset);
- fprintf(stdout,"mix.o_offset %2d (0-25)\n",mix.o_offset);
- }
- }
- exit (0);
- }
-
-/* the control flags */
-
- if (argc < argidx+2)
- usage();
-
- if (!strcmp(argv[argidx],"master")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("master = %d\n",val);
- ctrl.master = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"pro")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("pro = %d\n",val);
- ctrl.pro = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"emphasis")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("emphasis = %d\n",val);
- ctrl.emphasis = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"dolby")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("dolby = %d\n",val);
- ctrl.dolby = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"optout")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("optout = %d\n",val);
- ctrl.opt_out = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"wordclock")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("wordclock = %d\n",val);
- ctrl.wordclock = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"spdifin")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("spdifin = %d\n",val);
- ctrl.spdif_in = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"syncref")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("syncref = %d\n",val);
- ctrl.sync_ref = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
- if (!strcmp(argv[argidx],"adat1cd")) {
- int val = atoi(argv[argidx+1]);
- ioctl(fd,SOUND_MIXER_PRIVATE3,&ctrl);
- printf("adat1cd = %d\n",val);
- ctrl.adat1_cd = val;
- ioctl(fdwr,SOUND_MIXER_PRIVATE3,&ctrl);
- exit (0);
- }
-
-/* setting offset */
-
- if (argc < argidx+4)
- usage();
-
- if (!strcmp(argv[argidx],"offset")) {
- rme_mixer mix;
-
- mix.devnr = atoi(argv[argidx+1]);
-
- mix.i_offset = atoi(argv[argidx+2]);
- mix.o_offset = atoi(argv[argidx+3]);
- ioctl(fdwr,SOUND_MIXER_PRIVATE1,&mix);
- fprintf(stdout,"devnr %d\n",mix.devnr);
- fprintf(stdout,"mix.i_offset to %d\n",mix.i_offset);
- fprintf(stdout,"mix.o_offset to %d\n",mix.o_offset);
- exit (0);
- }
-
- usage();
- exit (0); /* to avoid warning */
-}
-
-
----------------------------- <snip> --------------------------------
-#!/usr/bin/wish
-
-# xrmectrl
-# (C) 2000 Guenter Geiger <geiger@debian.org>
-# HP20020201 - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
-
-#set defaults "-relief ridged"
-set CTRLPROG "./rmectrl"
-if {$argc} {
- set CTRLPROG "$CTRLPROG $argv"
-}
-puts "CTRLPROG $CTRLPROG"
-
-frame .butts
-button .butts.exit -text "Exit" -command "exit" -relief ridge
-#button .butts.state -text "State" -command "get_all"
-
-pack .butts.exit -side left
-pack .butts -side bottom
-
-
-#
-# STATUS
-#
-
-frame .status
-
-# Sampling Rate
-
-frame .status.sr
-label .status.sr.text -text "Sampling Rate" -justify left
-radiobutton .status.sr.441 -selectcolor red -text "44.1 kHz" -width 10 -anchor nw -variable srate -value 44100 -font times
-radiobutton .status.sr.480 -selectcolor red -text "48 kHz" -width 10 -anchor nw -variable srate -value 48000 -font times
-radiobutton .status.sr.882 -selectcolor red -text "88.2 kHz" -width 10 -anchor nw -variable srate -value 88200 -font times
-radiobutton .status.sr.960 -selectcolor red -text "96 kHz" -width 10 -anchor nw -variable srate -value 96000 -font times
-
-pack .status.sr.text .status.sr.441 .status.sr.480 .status.sr.882 .status.sr.960 -side top -padx 3
-
-# Lock
-
-frame .status.lock
-label .status.lock.text -text "Lock" -justify left
-checkbutton .status.lock.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatlock1 -font times
-checkbutton .status.lock.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatlock2 -font times
-checkbutton .status.lock.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatlock3 -font times
-
-pack .status.lock.text .status.lock.adat1 .status.lock.adat2 .status.lock.adat3 -side top -padx 3
-
-# Sync
-
-frame .status.sync
-label .status.sync.text -text "Sync" -justify left
-checkbutton .status.sync.adat1 -selectcolor red -text "ADAT1" -anchor nw -width 10 -variable adatsync1 -font times
-checkbutton .status.sync.adat2 -selectcolor red -text "ADAT2" -anchor nw -width 10 -variable adatsync2 -font times
-checkbutton .status.sync.adat3 -selectcolor red -text "ADAT3" -anchor nw -width 10 -variable adatsync3 -font times
-
-pack .status.sync.text .status.sync.adat1 .status.sync.adat2 .status.sync.adat3 -side top -padx 3
-
-# Timecode
-
-frame .status.tc
-label .status.tc.text -text "Timecode" -justify left
-checkbutton .status.tc.busy -selectcolor red -text "busy" -anchor nw -width 10 -variable tcbusy -font times
-checkbutton .status.tc.out -selectcolor red -text "out" -anchor nw -width 10 -variable tcout -font times
-checkbutton .status.tc.valid -selectcolor red -text "valid" -anchor nw -width 10 -variable tcvalid -font times
-
-pack .status.tc.text .status.tc.busy .status.tc.out .status.tc.valid -side top -padx 3
-
-# SPDIF In
-
-frame .status.spdif
-label .status.spdif.text -text "SPDIF In" -justify left
-label .status.spdif.sr -text "--.- kHz" -anchor n -width 10 -font times
-checkbutton .status.spdif.error -selectcolor red -text "Input Lock" -anchor nw -width 10 -variable spdiferr -font times
-
-pack .status.spdif.text .status.spdif.sr .status.spdif.error -side top -padx 3
-
-pack .status.sr .status.lock .status.sync .status.tc .status.spdif -side left -fill x -anchor n -expand 1
-
-
-#
-# CONTROL
-#
-
-proc setprof {} {
- global CTRLPROG
- global spprof
- exec $CTRLPROG pro $spprof
-}
-
-proc setemph {} {
- global CTRLPROG
- global spemph
- exec $CTRLPROG emphasis $spemph
-}
-
-proc setnoaud {} {
- global CTRLPROG
- global spnoaud
- exec $CTRLPROG dolby $spnoaud
-}
-
-proc setoptical {} {
- global CTRLPROG
- global spoptical
- exec $CTRLPROG optout $spoptical
-}
-
-proc setspdifin {} {
- global CTRLPROG
- global spdifin
- exec $CTRLPROG spdifin [expr $spdifin - 1]
-}
-
-proc setsyncsource {} {
- global CTRLPROG
- global syncsource
- exec $CTRLPROG syncref [expr $syncsource -1]
-}
-
-
-proc setmaster {} {
- global CTRLPROG
- global master
- exec $CTRLPROG master $master
-}
-
-proc setwordclock {} {
- global CTRLPROG
- global wordclock
- exec $CTRLPROG wordclock $wordclock
-}
-
-proc setadat1cd {} {
- global CTRLPROG
- global adat1cd
- exec $CTRLPROG adat1cd $adat1cd
-}
-
-
-frame .control
-
-# SPDIF In & SPDIF Out
-
-
-frame .control.spdif
-
-frame .control.spdif.in
-label .control.spdif.in.text -text "SPDIF In" -justify left
-radiobutton .control.spdif.in.input1 -text "Optical" -anchor nw -width 13 -variable spdifin -value 1 -command setspdifin -selectcolor blue -font times
-radiobutton .control.spdif.in.input2 -text "Coaxial" -anchor nw -width 13 -variable spdifin -value 2 -command setspdifin -selectcolor blue -font times
-radiobutton .control.spdif.in.input3 -text "Intern " -anchor nw -width 13 -variable spdifin -command setspdifin -value 3 -selectcolor blue -font times
-
-checkbutton .control.spdif.in.adat1cd -text "ADAT1 Intern" -anchor nw -width 13 -variable adat1cd -command setadat1cd -selectcolor blue -font times
-
-pack .control.spdif.in.text .control.spdif.in.input1 .control.spdif.in.input2 .control.spdif.in.input3 .control.spdif.in.adat1cd
-
-label .control.spdif.space
-
-frame .control.spdif.out
-label .control.spdif.out.text -text "SPDIF Out" -justify left
-checkbutton .control.spdif.out.pro -text "Professional" -anchor nw -width 13 -variable spprof -command setprof -selectcolor blue -font times
-checkbutton .control.spdif.out.emphasis -text "Emphasis" -anchor nw -width 13 -variable spemph -command setemph -selectcolor blue -font times
-checkbutton .control.spdif.out.dolby -text "NoAudio" -anchor nw -width 13 -variable spnoaud -command setnoaud -selectcolor blue -font times
-checkbutton .control.spdif.out.optout -text "Optical Out" -anchor nw -width 13 -variable spoptical -command setoptical -selectcolor blue -font times
-
-pack .control.spdif.out.optout .control.spdif.out.dolby .control.spdif.out.emphasis .control.spdif.out.pro .control.spdif.out.text -side bottom
-
-pack .control.spdif.in .control.spdif.space .control.spdif.out -side top -fill y -padx 3 -expand 1
-
-# Sync Mode & Sync Source
-
-frame .control.sync
-frame .control.sync.mode
-label .control.sync.mode.text -text "Sync Mode" -justify left
-checkbutton .control.sync.mode.master -text "Master" -anchor nw -width 13 -variable master -command setmaster -selectcolor blue -font times
-checkbutton .control.sync.mode.wc -text "Wordclock" -anchor nw -width 13 -variable wordclock -command setwordclock -selectcolor blue -font times
-
-pack .control.sync.mode.text .control.sync.mode.master .control.sync.mode.wc
-
-label .control.sync.space
-
-frame .control.sync.src
-label .control.sync.src.text -text "Sync Source" -justify left
-radiobutton .control.sync.src.input1 -text "ADAT1" -anchor nw -width 13 -variable syncsource -value 1 -command setsyncsource -selectcolor blue -font times
-radiobutton .control.sync.src.input2 -text "ADAT2" -anchor nw -width 13 -variable syncsource -value 2 -command setsyncsource -selectcolor blue -font times
-radiobutton .control.sync.src.input3 -text "ADAT3" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 3 -selectcolor blue -font times
-radiobutton .control.sync.src.input4 -text "SPDIF" -anchor nw -width 13 -variable syncsource -command setsyncsource -value 4 -selectcolor blue -font times
-
-pack .control.sync.src.input4 .control.sync.src.input3 .control.sync.src.input2 .control.sync.src.input1 .control.sync.src.text -side bottom
-
-pack .control.sync.mode .control.sync.space .control.sync.src -side top -fill y -padx 3 -expand 1
-
-label .control.space -text "" -width 10
-
-# Buffer Size
-
-frame .control.buf
-label .control.buf.text -text "Buffer Size (Latency)" -justify left
-radiobutton .control.buf.b1 -selectcolor red -text "64 (1.5 ms)" -width 13 -anchor nw -variable ssrate -value 1 -font times
-radiobutton .control.buf.b2 -selectcolor red -text "128 (3 ms)" -width 13 -anchor nw -variable ssrate -value 2 -font times
-radiobutton .control.buf.b3 -selectcolor red -text "256 (6 ms)" -width 13 -anchor nw -variable ssrate -value 3 -font times
-radiobutton .control.buf.b4 -selectcolor red -text "512 (12 ms)" -width 13 -anchor nw -variable ssrate -value 4 -font times
-radiobutton .control.buf.b5 -selectcolor red -text "1024 (23 ms)" -width 13 -anchor nw -variable ssrate -value 5 -font times
-radiobutton .control.buf.b6 -selectcolor red -text "2048 (46 ms)" -width 13 -anchor nw -variable ssrate -value 6 -font times
-radiobutton .control.buf.b7 -selectcolor red -text "4096 (93 ms)" -width 13 -anchor nw -variable ssrate -value 7 -font times
-radiobutton .control.buf.b8 -selectcolor red -text "8192 (186 ms)" -width 13 -anchor nw -variable ssrate -value 8 -font times
-
-pack .control.buf.text .control.buf.b1 .control.buf.b2 .control.buf.b3 .control.buf.b4 .control.buf.b5 .control.buf.b6 .control.buf.b7 .control.buf.b8 -side top -padx 3
-
-# Offset
-
-frame .control.offset
-
-frame .control.offset.in
-label .control.offset.in.text -text "Offset In" -justify left
-label .control.offset.in.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
-label .control.offset.in.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
-label .control.offset.in.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
-label .control.offset.in.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
-
-pack .control.offset.in.text .control.offset.in.off0 .control.offset.in.off1 .control.offset.in.off2 .control.offset.in.off3
-
-label .control.offset.space
-
-frame .control.offset.out
-label .control.offset.out.text -text "Offset Out" -justify left
-label .control.offset.out.off0 -text "dev\#0: -" -anchor nw -width 10 -font times
-label .control.offset.out.off1 -text "dev\#1: -" -anchor nw -width 10 -font times
-label .control.offset.out.off2 -text "dev\#2: -" -anchor nw -width 10 -font times
-label .control.offset.out.off3 -text "dev\#3: -" -anchor nw -width 10 -font times
-
-pack .control.offset.out.off3 .control.offset.out.off2 .control.offset.out.off1 .control.offset.out.off0 .control.offset.out.text -side bottom
-
-pack .control.offset.in .control.offset.space .control.offset.out -side top -fill y -padx 3 -expand 1
-
-
-pack .control.spdif .control.sync .control.space .control.buf .control.offset -side left -fill both -anchor n -expand 1
-
-
-label .statustext -text Status -justify center -relief ridge
-label .controltext -text Control -justify center -relief ridge
-
-label .statusspace
-label .controlspace
-
-pack .statustext .status .statusspace .controltext .control .controlspace -side top -anchor nw -fill both -expand 1
-
-
-proc get_bit {output sstr} {
- set idx1 [string last [concat $sstr 1] $output]
- set idx1 [expr $idx1 != -1]
- return $idx1
-}
-
-proc get_val {output sstr} {
- set val [string wordend $output [string last $sstr $output]]
- set val [string range $output $val [expr $val+1]]
- return $val
-}
-
-proc get_val2 {output sstr} {
- set val [string wordend $output [string first $sstr $output]]
- set val [string range $output $val [expr $val+2]]
- return $val
-}
-
-proc get_control {} {
- global spprof
- global spemph
- global spnoaud
- global spoptical
- global spdifin
- global ssrate
- global master
- global wordclock
- global syncsource
- global CTRLPROG
-
- set f [open "| $CTRLPROG control" r+]
- set ooo [read $f 1000]
- close $f
-# puts $ooo
-
- set spprof [ get_bit $ooo "pro"]
- set spemph [ get_bit $ooo "emphasis"]
- set spnoaud [ get_bit $ooo "dolby"]
- set spoptical [ get_bit $ooo "opt_out"]
- set spdifin [ expr [ get_val $ooo "spdif_in"] + 1]
- set ssrate [ expr [ get_val $ooo "latency"] + 1]
- set master [ expr [ get_val $ooo "master"]]
- set wordclock [ expr [ get_val $ooo "wordclock"]]
- set syncsource [ expr [ get_val $ooo "sync_ref"] + 1]
-}
-
-proc get_status {} {
- global srate
- global ctrlcom
-
- global adatlock1
- global adatlock2
- global adatlock3
-
- global adatsync1
- global adatsync2
- global adatsync3
-
- global tcbusy
- global tcout
- global tcvalid
-
- global spdiferr
- global crystal
- global .status.spdif.text
- global CTRLPROG
-
-
- set f [open "| $CTRLPROG status" r+]
- set ooo [read $f 1000]
- close $f
-# puts $ooo
-
-# samplerate
-
- set idx1 [string last "sr48 1" $ooo]
- set idx2 [string last "doublespeed 1" $ooo]
- if {$idx1 >= 0} {
- set fact1 48000
- } else {
- set fact1 44100
- }
-
- if {$idx2 >= 0} {
- set fact2 2
- } else {
- set fact2 1
- }
- set srate [expr $fact1 * $fact2]
-# ADAT lock
-
- set val [get_val $ooo lockmask]
- set adatlock1 0
- set adatlock2 0
- set adatlock3 0
- if {[expr $val & 1]} {
- set adatlock3 1
- }
- if {[expr $val & 2]} {
- set adatlock2 1
- }
- if {[expr $val & 4]} {
- set adatlock1 1
- }
-
-# ADAT sync
- set val [get_val $ooo syncmask]
- set adatsync1 0
- set adatsync2 0
- set adatsync3 0
-
- if {[expr $val & 1]} {
- set adatsync3 1
- }
- if {[expr $val & 2]} {
- set adatsync2 1
- }
- if {[expr $val & 4]} {
- set adatsync1 1
- }
-
-# TC busy
-
- set tcbusy [get_bit $ooo "busy"]
- set tcout [get_bit $ooo "out"]
- set tcvalid [get_bit $ooo "valid"]
- set spdiferr [expr [get_bit $ooo "spdif_error"] == 0]
-
-# 000=64kHz, 100=88.2kHz, 011=96kHz
-# 111=32kHz, 110=44.1kHz, 101=48kHz
-
- set val [get_val $ooo crystalrate]
-
- set crystal "--.- kHz"
- if {$val == 0} {
- set crystal "64 kHz"
- }
- if {$val == 4} {
- set crystal "88.2 kHz"
- }
- if {$val == 3} {
- set crystal "96 kHz"
- }
- if {$val == 7} {
- set crystal "32 kHz"
- }
- if {$val == 6} {
- set crystal "44.1 kHz"
- }
- if {$val == 5} {
- set crystal "48 kHz"
- }
- .status.spdif.sr configure -text $crystal
-}
-
-proc get_offset {} {
- global inoffset
- global outoffset
- global CTRLPROG
-
- set f [open "| $CTRLPROG mix" r+]
- set ooo [read $f 1000]
- close $f
-# puts $ooo
-
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off0 configure -text "dev\#0: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off0 configure -text "dev\#0: $val"
- } else {
- .control.offset.in.off0 configure -text "dev\#0: -"
- .control.offset.out.off0 configure -text "dev\#0: -"
- }
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off1 configure -text "dev\#1: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off1 configure -text "dev\#1: $val"
- } else {
- .control.offset.in.off1 configure -text "dev\#1: -"
- .control.offset.out.off1 configure -text "dev\#1: -"
- }
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off2 configure -text "dev\#2: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off2 configure -text "dev\#2: $val"
- } else {
- .control.offset.in.off2 configure -text "dev\#2: -"
- .control.offset.out.off2 configure -text "dev\#2: -"
- }
- if { [string match "*devnr*" $ooo] } {
- set ooo [string range $ooo [string wordend $ooo [string first devnr $ooo]] end]
- set val [get_val2 $ooo i_offset]
- .control.offset.in.off3 configure -text "dev\#3: $val"
- set val [get_val2 $ooo o_offset]
- .control.offset.out.off3 configure -text "dev\#3: $val"
- } else {
- .control.offset.in.off3 configure -text "dev\#3: -"
- .control.offset.out.off3 configure -text "dev\#3: -"
- }
-}
-
-
-proc get_all {} {
-get_status
-get_control
-get_offset
-}
-
-# main
-while {1} {
- after 200
- get_all
- update
-}
diff --git a/Documentation/sound/oss/solo1 b/Documentation/sound/oss/solo1
deleted file mode 100644
index 6f53d407d027..000000000000
--- a/Documentation/sound/oss/solo1
+++ /dev/null
@@ -1,70 +0,0 @@
-Recording
----------
-
-Recording does not work on the author's card, but there
-is at least one report of it working on later silicon.
-The chip behaves differently than described in the data sheet,
-likely due to a chip bug. Working around this would require
-the help of ESS (for example by publishing an errata sheet),
-but ESS has not done so so far.
-
-Also, the chip only supports 24 bit addresses for recording,
-which means it cannot work on some Alpha mainboards.
-
-
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (or later, available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card has an OPL compatible FM synthesizer.
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/Documentation/sound/oss/sonicvibes b/Documentation/sound/oss/sonicvibes
deleted file mode 100644
index 84dee2e0b37d..000000000000
--- a/Documentation/sound/oss/sonicvibes
+++ /dev/null
@@ -1,81 +0,0 @@
-/proc/sound, /dev/sndstat
--------------------------
-
-/proc/sound and /dev/sndstat is not supported by the
-driver. To find out whether the driver succeeded loading,
-check the kernel log (dmesg).
-
-
-ALaw/uLaw sample formats
-------------------------
-
-This driver does not support the ALaw/uLaw sample formats.
-ALaw is the default mode when opening a sound device
-using OSS/Free. The reason for the lack of support is
-that the hardware does not support these formats, and adding
-conversion routines to the kernel would lead to very ugly
-code in the presence of the mmap interface to the driver.
-And since xquake uses mmap, mmap is considered important :-)
-and no sane application uses ALaw/uLaw these days anyway.
-In short, playing a Sun .au file as follows:
-
-cat my_file.au > /dev/dsp
-
-does not work. Instead, you may use the play script from
-Chris Bagwell's sox-12.14 package (available from the URL
-below) to play many different audio file formats.
-The script automatically determines the audio format
-and does do audio conversions if necessary.
-http://home.sprynet.com/sprynet/cbagwell/projects.html
-
-
-Blocking vs. nonblocking IO
----------------------------
-
-Unlike OSS/Free this driver honours the O_NONBLOCK file flag
-not only during open, but also during read and write.
-This is an effort to make the sound driver interface more
-regular. Timidity has problems with this; a patch
-is available from http://www.ife.ee.ethz.ch/~sailer/linux/pciaudio.html.
-(Timidity patched will also run on OSS/Free).
-
-
-MIDI UART
----------
-
-The driver supports a simple MIDI UART interface, with
-no ioctl's supported.
-
-
-MIDI synthesizer
-----------------
-
-The card both has an OPL compatible FM synthesizer as well as
-a wavetable synthesizer.
-
-I haven't managed so far to get the OPL synth running.
-
-Using the wavetable synthesizer requires allocating
-1-4MB of physically contiguous memory, which isn't possible
-currently on Linux without ugly hacks like the bigphysarea
-patch. Therefore, the driver doesn't support wavetable
-synthesis.
-
-
-No support from S3
-------------------
-
-I do not get any support from S3. Therefore, the driver
-still has many problems. For example, although the manual
-states that the chip should be able to access the sample
-buffer anywhere in 32bit address space, I haven't managed to
-get it working with buffers above 16M. Therefore, the card
-has the same disadvantages as ISA soundcards.
-
-Given that the card is also very noisy, and if you haven't
-already bought it, you should strongly opt for one of the
-comparatively priced Ensoniq products.
-
-
-Thomas Sailer
-t.sailer@alumni.ethz.ch
diff --git a/Documentation/sound/oss/ultrasound b/Documentation/sound/oss/ultrasound
index 32cd50478b36..eed331c738a3 100644
--- a/Documentation/sound/oss/ultrasound
+++ b/Documentation/sound/oss/ultrasound
@@ -19,7 +19,7 @@ db16 ???
no_wave_dma option
This option defaults to a value of 0, which allows the Ultrasound wavetable
-DSP to use DMA for for playback and downloading samples. This is the same
+DSP to use DMA for playback and downloading samples. This is the same
as the old behaviour. If set to 1, no DMA is needed for downloading samples,
and allows owners of a GUS MAX to make use of simultaneous digital audio
(/dev/dsp), MIDI, and wavetable playback.
diff --git a/Documentation/sound/oss/vwsnd b/Documentation/sound/oss/vwsnd
index a6ea0a1df9e4..4c6cbdb3c548 100644
--- a/Documentation/sound/oss/vwsnd
+++ b/Documentation/sound/oss/vwsnd
@@ -12,7 +12,7 @@ boxes.
The Visual Workstation has an Analog Devices AD1843 "SoundComm" audio
codec chip. The AD1843 is accessed through the Cobalt I/O ASIC, also
-known as Lithium. This driver programs both both chips.
+known as Lithium. This driver programs both chips.
==============================================================================
QUICK CONFIGURATION
diff --git a/Documentation/sparc/sbus_drivers.txt b/Documentation/sparc/sbus_drivers.txt
index 4b9351624f13..8418d35484fc 100644
--- a/Documentation/sparc/sbus_drivers.txt
+++ b/Documentation/sparc/sbus_drivers.txt
@@ -25,8 +25,8 @@ the bits necessary to run your device. The most commonly
used members of this structure, and their typical usage,
will be detailed below.
- Here is a piece of skeleton code for perofming a device
-probe in an SBUS driverunder Linux:
+ Here is a piece of skeleton code for performing a device
+probe in an SBUS driver under Linux:
static int __devinit mydevice_probe_one(struct sbus_dev *sdev)
{
@@ -98,7 +98,7 @@ in your .remove method.
Any memory allocated, registers mapped, IRQs registered,
etc. must be undone by your .remove method so that all resources
-of your device are relased by the time it returns.
+of your device are released by the time it returns.
You should _NOT_ use the for_each_sbus(), for_each_sbusdev(),
and for_all_sbusdev() interfaces. They are deprecated, will be
diff --git a/Documentation/spi/pxa2xx b/Documentation/spi/pxa2xx
index 9c45f3df2e18..a1e0ee20f595 100644
--- a/Documentation/spi/pxa2xx
+++ b/Documentation/spi/pxa2xx
@@ -124,12 +124,12 @@ use a value of 8.
The "pxa2xx_spi_chip.timeout_microsecs" fields is used to efficiently handle
trailing bytes in the SSP receiver fifo. The correct value for this field is
dependent on the SPI bus speed ("spi_board_info.max_speed_hz") and the specific
-slave device. Please note the the PXA2xx SSP 1 does not support trailing byte
+slave device. Please note that the PXA2xx SSP 1 does not support trailing byte
timeouts and must busy-wait any trailing bytes.
The "pxa2xx_spi_chip.enable_loopback" field is used to place the SSP porting
into internal loopback mode. In this mode the SSP controller internally
-connects the SSPTX pin the the SSPRX pin. This is useful for initial setup
+connects the SSPTX pin to the SSPRX pin. This is useful for initial setup
testing.
The "pxa2xx_spi_chip.cs_control" field is used to point to a board specific
@@ -208,7 +208,7 @@ DMA and PIO I/O Support
-----------------------
The pxa2xx_spi driver support both DMA and interrupt driven PIO message
transfers. The driver defaults to PIO mode and DMA transfers must enabled by
-setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and and
+setting the "enable_dma" flag in the "pxa2xx_spi_master" structure and
ensuring that the "pxa2xx_spi_chip.dma_burst_size" field is non-zero. The DMA
mode support both coherent and stream based DMA mappings.
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index 068732d32276..72795796b13d 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -262,7 +262,7 @@ NON-STATIC CONFIGURATIONS
Developer boards often play by different rules than product boards, and one
example is the potential need to hotplug SPI devices and/or controllers.
-For those cases you might need to use use spi_busnum_to_master() to look
+For those cases you might need to use spi_busnum_to_master() to look
up the spi bus master, and will likely need spi_new_device() to provide the
board info based on the board that was hotplugged. Of course, you'd later
call at least spi_unregister_device() when that board is removed.
@@ -322,7 +322,7 @@ As soon as it enters probe(), the driver may issue I/O requests to
the SPI device using "struct spi_message". When remove() returns,
the driver guarantees that it won't submit any more such messages.
- - An spi_message is a sequence of of protocol operations, executed
+ - An spi_message is a sequence of protocol operations, executed
as one atomic sequence. SPI driver controls include:
+ when bidirectional reads and writes start ... by how its
diff --git a/Documentation/stable_kernel_rules.txt b/Documentation/stable_kernel_rules.txt
index e409e5d07486..02a481225b0d 100644
--- a/Documentation/stable_kernel_rules.txt
+++ b/Documentation/stable_kernel_rules.txt
@@ -4,7 +4,7 @@ Rules on what kind of patches are accepted, and which ones are not, into the
"-stable" tree:
- It must be obviously correct and tested.
- - It can not be bigger than 100 lines, with context.
+ - It cannot be bigger than 100 lines, with context.
- It must fix only one thing.
- It must fix a real bug that bothers people (not a, "This could be a
problem..." type thing).
@@ -14,7 +14,7 @@ Rules on what kind of patches are accepted, and which ones are not, into the
critical.
- No "theoretical race condition" issues, unless an explanation of how the
race can be exploited is also provided.
- - It can not contain any "trivial" fixes in it (spelling changes,
+ - It cannot contain any "trivial" fixes in it (spelling changes,
whitespace cleanups, etc).
- It must be accepted by the relevant subsystem maintainer.
- It must follow the Documentation/SubmittingPatches rules.
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 89bf8c20a586..0bc7f1e3c9e6 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -86,7 +86,7 @@ valid for 30 seconds.
core_pattern:
core_pattern is used to specify a core dumpfile pattern name.
-. max length 64 characters; default value is "core"
+. max length 128 characters; default value is "core"
. core_pattern is used as a pattern template for the output filename;
certain string patterns (beginning with '%') are substituted with
their actual values.
@@ -105,6 +105,9 @@ core_pattern is used to specify a core dumpfile pattern name.
%h hostname
%e executable filename
%<OTHER> both are dropped
+. If the first character of the pattern is a '|', the kernel will treat
+ the rest of the pattern as a command to run. The core dump will be
+ written to the standard input of that program instead of to a file.
==============================================================
diff --git a/Documentation/uml/UserModeLinux-HOWTO.txt b/Documentation/uml/UserModeLinux-HOWTO.txt
index 544430e39980..b60590eca18f 100644
--- a/Documentation/uml/UserModeLinux-HOWTO.txt
+++ b/Documentation/uml/UserModeLinux-HOWTO.txt
@@ -157,7 +157,7 @@
13. What to do when UML doesn't work
13.1 Strange compilation errors when you build from source
- 13.2 UML hangs on boot after mounting devfs
+ 13.2 (obsolete)
13.3 A variety of panics and hangs with /tmp on a reiserfs filesystem
13.4 The compile fails with errors about conflicting types for 'open', 'dup', and 'waitpid'
13.5 UML doesn't work when /tmp is an NFS filesystem
@@ -379,31 +379,6 @@
bug fixes and enhancements that have gone into subsequent releases.
- If you build your own kernel, and want to boot it from one of the
- filesystems distributed from this site, then, in nearly all cases,
- devfs must be compiled into the kernel and mounted at boot time. The
- exception is the SuSE filesystem. For this, devfs must either not be
- in the kernel at all, or "devfs=nomount" must be on the kernel command
- line. Any disagreement between the kernel and the filesystem being
- booted about whether devfs is being used will result in the boot
- getting no further than single-user mode.
-
-
- If you don't want to use devfs, you can remove the need for it from a
- filesystem by copying /dev from someplace, making a bunch of /dev/ubd
- devices:
-
-
- UML# for i in 0 1 2 3 4 5 6 7; do mknod ubd$i b 98 $i; done
-
-
-
-
- and changing /etc/fstab and /etc/inittab to refer to the non-devfs
- devices.
-
-
-
22..22.. CCoommppiilliinngg aanndd iinnssttaalllliinngg kkeerrnneell mmoodduulleess
UML modules are built in the same way as the native kernel (with the
@@ -839,9 +814,7 @@
+o None - device=none
- This causes the device to disappear. If you are using devfs, the
- device will not appear in /dev. If not, then attempts to open it
- will return -ENODEV.
+ This causes the device to disappear.
@@ -1047,7 +1020,7 @@
Note that the IP address you assign to the host end of the tap device
must be different than the IP you assign to the eth device inside UML.
- If you are short on IPs and don't want to comsume two per UML, then
+ If you are short on IPs and don't want to consume two per UML, then
you can reuse the host's eth IP address for the host ends of the tap
devices. Internally, the UMLs must still get unique IPs for their eth
devices. You can also give the UMLs non-routable IPs (192.168.x.x or
@@ -2058,7 +2031,7 @@
there are multiple COWs associated with a backing file, a -d merge of
one of them will invalidate all of the others. However, it is
convenient if you're short of disk space, and it should also be
- noticably faster than a non-destructive merge.
+ noticeably faster than a non-destructive merge.
@@ -3898,29 +3871,6 @@
- 1133..22.. UUMMLL hhaannggss oonn bboooott aafftteerr mmoouunnttiinngg ddeevvffss
-
- The boot looks like this:
-
-
- VFS: Mounted root (ext2 filesystem) readonly.
- Mounted devfs on /dev
-
-
-
-
- You're probably running a recent distribution on an old machine. I
- saw this with the RH7.1 filesystem running on a Pentium. The shared
- library loader, ld.so, was executing an instruction (cmove) which the
- Pentium didn't support. That instruction was apparently added later.
- If you run UML under the debugger, you'll see the hang caused by one
- instruction causing an infinite SIGILL stream.
-
-
- The fix is to boot UML on an older filesystem.
-
-
-
1133..33.. AA vvaarriieettyy ooff ppaanniiccss aanndd hhaannggss wwiitthh //ttmmpp oonn aa rreeiisseerrffss ffiilleessyyss--
tteemm
@@ -3953,9 +3903,9 @@
1133..55.. UUMMLL ddooeessnn''tt wwoorrkk wwhheenn //ttmmpp iiss aann NNFFSS ffiilleessyysstteemm
- This seems to be a similar situation with the resierfs problem above.
+ This seems to be a similar situation with the ReiserFS problem above.
Some versions of NFS seems not to handle mmap correctly, which UML
- depends on. The workaround is have /tmp be non-NFS directory.
+ depends on. The workaround is have /tmp be a non-NFS directory.
1133..66.. UUMMLL hhaannggss oonn bboooott wwhheenn ccoommppiilleedd wwiitthh ggpprrooff ssuuppppoorrtt
@@ -4022,7 +3972,7 @@
nneett
If you can connect to the host, and the host can connect to UML, but
- you can not connect to any other machines, then you may need to enable
+ you cannot connect to any other machines, then you may need to enable
IP Masquerading on the host. Usually this is only experienced when
using private IP addresses (192.168.x.x or 10.x.x.x) for host/UML
networking, rather than the public address space that your host is
@@ -4671,7 +4621,7 @@
Chris Reahard built a specialized root filesystem for running a DNS
server jailed inside UML. It's available from the download
<http://user-mode-linux.sourceforge.net/dl-sf.html> page in the Jail
- Filesysems section.
+ Filesystems section.
diff --git a/Documentation/unshare.txt b/Documentation/unshare.txt
index 90a5e9e5bef1..a8643513a5f6 100644
--- a/Documentation/unshare.txt
+++ b/Documentation/unshare.txt
@@ -260,7 +260,7 @@ items:
a pointer to it.
7.4) Appropriately modify architecture specific code to register the
- the new system call.
+ new system call.
8) Test Specification
---------------------
diff --git a/Documentation/usb/URB.txt b/Documentation/usb/URB.txt
index a49e5f2c2b46..8ffce746d496 100644
--- a/Documentation/usb/URB.txt
+++ b/Documentation/usb/URB.txt
@@ -184,7 +184,7 @@ you can pass information to the completion handler.
Note that even when an error (or unlink) is reported, data may have been
transferred. That's because USB transfers are packetized; it might take
sixteen packets to transfer your 1KByte buffer, and ten of them might
-have transferred succesfully before the completion was called.
+have transferred successfully before the completion was called.
NOTE: ***** WARNING *****
diff --git a/Documentation/usb/acm.txt b/Documentation/usb/acm.txt
index 8ef45ea8f691..737d6104c3f3 100644
--- a/Documentation/usb/acm.txt
+++ b/Documentation/usb/acm.txt
@@ -49,20 +49,6 @@ Abstract Control Model (USB CDC ACM) specification.
Unfortunately many modems and most ISDN TAs use proprietary interfaces and
thus won't work with this drivers. Check for ACM compliance before buying.
- The driver (with devfs) creates these devices in /dev/usb/acm:
-
- crw-r--r-- 1 root root 166, 0 Apr 1 10:49 0
- crw-r--r-- 1 root root 166, 1 Apr 1 10:49 1
- crw-r--r-- 1 root root 166, 2 Apr 1 10:49 2
-
- And so on, up to 31, with the limit being possible to change in acm.c to up
-to 256, so you can use up to 256 USB modems with one computer (you'll need
-three USB cards for that, though).
-
- If you don't use devfs, then you can create device nodes with the same
-minor/major numbers anywhere you want, but either the above location or
-/dev/usb/ttyACM0 is preferred.
-
To use the modems you need these modules loaded:
usbcore.ko
diff --git a/Documentation/usb/error-codes.txt b/Documentation/usb/error-codes.txt
index 867f4c38f356..9cf83e8c27b8 100644
--- a/Documentation/usb/error-codes.txt
+++ b/Documentation/usb/error-codes.txt
@@ -98,13 +98,13 @@ one or more packets could finish before an error stops further endpoint I/O.
error, a failure to respond (often caused by
device disconnect), or some other fault.
--ETIMEDOUT (**) No response packet received within the prescribed
+-ETIME (**) No response packet received within the prescribed
bus turn-around time. This error may instead be
reported as -EPROTO or -EILSEQ.
- Note that the synchronous USB message functions
- also use this code to indicate timeout expired
- before the transfer completed.
+-ETIMEDOUT Synchronous USB message functions use this code
+ to indicate timeout expired before the transfer
+ completed, and no other error was reported by HC.
-EPIPE (**) Endpoint stalled. For non-control endpoints,
reset this status with usb_clear_halt().
@@ -126,7 +126,7 @@ one or more packets could finish before an error stops further endpoint I/O.
urb->transfer_flags.
-ENODEV Device was removed. Often preceded by a burst of
- other errors, since the hub driver does't detect
+ other errors, since the hub driver doesn't detect
device removal events immediately.
-EXDEV ISO transfer only partially completed
@@ -145,7 +145,7 @@ one or more packets could finish before an error stops further endpoint I/O.
hardware problems such as bad devices (including firmware) or cables.
(**) This is also one of several codes that different kinds of host
-controller use to to indicate a transfer has failed because of device
+controller use to indicate a transfer has failed because of device
disconnect. In the interval before the hub driver starts disconnect
processing, devices may receive such fault reports for every request.
@@ -163,6 +163,3 @@ usb_get_*/usb_set_*():
usb_control_msg():
usb_bulk_msg():
-ETIMEDOUT Timeout expired before the transfer completed.
- In the future this code may change to -ETIME,
- whose definition is a closer match to this sort
- of error.
diff --git a/Documentation/usb/hiddev.txt b/Documentation/usb/hiddev.txt
index cd6fb4b58e1f..6a790754e963 100644
--- a/Documentation/usb/hiddev.txt
+++ b/Documentation/usb/hiddev.txt
@@ -118,7 +118,7 @@ index, the ioctl returns -1 and sets errno to -EINVAL.
HIDIOCGDEVINFO - struct hiddev_devinfo (read)
Gets a hiddev_devinfo structure which describes the device.
-HIDIOCGSTRING - struct struct hiddev_string_descriptor (read/write)
+HIDIOCGSTRING - struct hiddev_string_descriptor (read/write)
Gets a string descriptor from the device. The caller must fill in the
"index" field to indicate which descriptor should be returned.
diff --git a/Documentation/usb/mtouchusb.txt b/Documentation/usb/mtouchusb.txt
index cd806bfc8b81..e43cfffaa100 100644
--- a/Documentation/usb/mtouchusb.txt
+++ b/Documentation/usb/mtouchusb.txt
@@ -11,7 +11,7 @@ CHANGES
Changed reset from standard USB dev reset to vendor reset
Changed data sent to host from compensated to raw coordinates
Eliminated vendor/product module params
- Performed multiple successfull tests with an EXII-5010UC
+ Performed multiple successful tests with an EXII-5010UC
SUPPORTED HARDWARE:
@@ -38,7 +38,7 @@ This driver appears to be one of possible 2 Linux USB Input Touchscreen
drivers. Although 3M produces a binary only driver available for
download, I persist in updating this driver since I would like to use the
touchscreen for embedded apps using QTEmbedded, DirectFB, etc. So I feel the
-logical choice is to use Linux Imput.
+logical choice is to use Linux Input.
Currently there is no way to calibrate the device via this driver. Even if
the device could be calibrated, the driver pulls to raw coordinate data from
@@ -63,7 +63,7 @@ TODO:
Implement a control urb again to handle requests to and from the device
such as calibration, etc once/if it becomes available.
-DISCLAMER:
+DISCLAIMER:
I am not a MicroTouch/3M employee, nor have I ever been. 3M does not support
this driver! If you want touch drivers only supported within X, please go to:
diff --git a/Documentation/usb/usb-serial.txt b/Documentation/usb/usb-serial.txt
index 02b0f7beb6d1..8dc2bacc8f1f 100644
--- a/Documentation/usb/usb-serial.txt
+++ b/Documentation/usb/usb-serial.txt
@@ -13,7 +13,6 @@ CONFIGURATION
Currently the driver can handle up to 256 different serial interfaces at
one time.
- If you are not using devfs:
The major number that the driver uses is 188 so to use the driver,
create the following nodes:
mknod /dev/ttyUSB0 c 188 0
@@ -26,10 +25,6 @@ CONFIGURATION
mknod /dev/ttyUSB254 c 188 254
mknod /dev/ttyUSB255 c 188 255
- If you are using devfs:
- The devices supported by this driver will show up as
- /dev/usb/tts/{0,1,...}
-
When the device is connected and recognized by the driver, the driver
will print to the system log, which node(s) the device has been bound
to.
@@ -228,7 +223,7 @@ Cypress M8 CY4601 Family Serial Driver
-Cypress HID->COM RS232 adapter
Note: Cypress Semiconductor claims no affiliation with the
- the hid->com device.
+ hid->com device.
Most devices using chipsets under the CY4601 family should
work with the driver. As long as they stay true to the CY4601
@@ -277,7 +272,7 @@ Digi AccelePort Driver
work under SMP with the uhci driver.
The driver is generally working, though we still have a few more ioctls
- to implement and final testing and debugging to do. The paralled port
+ to implement and final testing and debugging to do. The parallel port
on the USB 2 is supported as a serial to parallel converter; in other
words, it appears as another USB serial port on Linux, even though
physically it is really a parallel port. The Digi Acceleport USB 8
@@ -427,12 +422,17 @@ Options supported:
debug - extra verbose debugging info
(default: 0; nonzero enables)
use_lowlatency - use low_latency flag to speed up tty layer
- when reading from from the device.
+ when reading from the device.
(default: 0; nonzero enables)
See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
information on this driver.
+AIRcable USB Dongle Bluetooth driver
+ If there is the cdc_acm driver loaded in the system, you will find that the
+ cdc_acm claims the device before AIRcable can. This is simply corrected
+ by unloading both modules and then loading the aircable module before
+ cdc_acm module
Generic Serial driver
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index 00d9a1f2a54c..8755b3e7b09e 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -7,16 +7,16 @@
6 -> AverTV Studio 303 (M126) [1461:000b]
7 -> MSI TV-@nywhere Master [1462:8606]
8 -> Leadtek Winfast DV2000 [107d:6620]
- 9 -> Leadtek PVR 2000 [107d:663b,107d:663C]
+ 9 -> Leadtek PVR 2000 [107d:663b,107d:663c,107d:6632]
10 -> IODATA GV-VCP3/PCI [10fc:d003]
11 -> Prolink PlayTV PVR
- 12 -> ASUS PVR-416 [1043:4823]
+ 12 -> ASUS PVR-416 [1043:4823,1461:c111]
13 -> MSI TV-@nywhere
14 -> KWorld/VStream XPert DVB-T [17de:08a6]
15 -> DViCO FusionHDTV DVB-T1 [18ac:db00]
16 -> KWorld LTV883RF
17 -> DViCO FusionHDTV 3 Gold-Q [18ac:d810,18ac:d800]
- 18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001]
+ 18 -> Hauppauge Nova-T DVB-T [0070:9002,0070:9001,0070:9000]
19 -> Conexant DVB-T reference design [14f1:0187]
20 -> Provideo PV259 [1540:2580]
21 -> DViCO FusionHDTV DVB-T Plus [18ac:db10,18ac:db11]
@@ -41,7 +41,7 @@
40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid [0070:9400,0070:9402]
41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile) [0070:9800,0070:9802]
42 -> digitalnow DNTV Live! DVB-T Pro [1822:0025,1822:0019]
- 43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1]
+ 43 -> KWorld/VStream XPert DVB-T with cx22702 [17de:08a1,12ab:2300]
44 -> DViCO FusionHDTV DVB-T Dual Digital [18ac:db50,18ac:db54]
45 -> KWorld HardwareMpegTV XPert [17de:0840]
46 -> DViCO FusionHDTV DVB-T Hybrid [18ac:db40,18ac:db44]
@@ -51,3 +51,7 @@
50 -> NPG Tech Real TV FM Top 10 [14f1:0842]
51 -> WinFast DTV2000 H [107d:665e]
52 -> Geniatech DVB-S [14f1:0084]
+ 53 -> Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T [0070:1404,0070:1400,0070:1401,0070:1402]
+ 54 -> Norwood Micro TV Tuner
+ 55 -> Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM [c180:c980]
+ 56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 9068b669f5ee..53ce6a39083c 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -58,7 +58,7 @@
57 -> Avermedia AVerTV GO 007 FM [1461:f31f]
58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0351,1421:0370,1421:1370]
59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
- 60 -> LifeView/Typhoon FlyDVB-T Duo Cardbus [5168:0502,4e42:0502]
+ 60 -> LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus [5168:0502,4e42:0502,1489:0502]
61 -> Philips TOUGH DVB-T reference design [1131:2004]
62 -> Compro VideoMate TV Gold+II
63 -> Kworld Xpert TV PVR7134
@@ -83,7 +83,7 @@
82 -> MSI TV@Anywhere plus [1462:6231]
83 -> Terratec Cinergy 250 PCI TV [153b:1160]
84 -> LifeView FlyDVB Trio [5168:0319]
- 85 -> AverTV DVB-T 777 [1461:2c05]
+ 85 -> AverTV DVB-T 777 [1461:2c05,1461:2c05]
86 -> LifeView FlyDVB-T / Genius VideoWonder DVB-T [5168:0301,1489:0301]
87 -> ADS Instant TV Duo Cardbus PTV331 [0331:1421]
88 -> Tevion/KWorld DVB-T 220RF [17de:7201]
@@ -94,3 +94,8 @@
93 -> Medion 7134 Bridge #2 [16be:0005]
94 -> LifeView FlyDVB-T Hybrid Cardbus [5168:3306,5168:3502]
95 -> LifeView FlyVIDEO3000 (NTSC) [5169:0138]
+ 96 -> Medion Md8800 Quadro [16be:0007,16be:0008]
+ 97 -> LifeView FlyDVB-S /Acorp TV134DS [5168:0300,4e42:0300]
+ 98 -> Proteus Pro 2309 [0919:2003]
+ 99 -> AVerMedia TV Hybrid A16AR [1461:2c00]
+100 -> Asus Europa2 OEM [1043:4860]
diff --git a/Documentation/video4linux/README.pvrusb2 b/Documentation/video4linux/README.pvrusb2
index c73a32c34528..a4b7ae800866 100644
--- a/Documentation/video4linux/README.pvrusb2
+++ b/Documentation/video4linux/README.pvrusb2
@@ -155,7 +155,7 @@ Source file list / functional overview:
pvrusb2-i2c-core.[ch] - This module provides an implementation of a
kernel-friendly I2C adaptor driver, through which other external
I2C client drivers (e.g. msp3400, tuner, lirc) may connect and
- operate corresponding chips within the the pvrusb2 device. It is
+ operate corresponding chips within the pvrusb2 device. It is
through here that other V4L modules can reach into this driver to
operate specific pieces (and those modules are in turn driven by
glue logic which is coordinated by pvrusb2-hdw, doled out by
diff --git a/Documentation/video4linux/Zoran b/Documentation/video4linux/Zoran
index 040a2c841ae9..deb218f77adb 100644
--- a/Documentation/video4linux/Zoran
+++ b/Documentation/video4linux/Zoran
@@ -144,7 +144,7 @@ tv broadcast formats all aver the world.
The CCIR defines parameters needed for broadcasting the signal.
The CCIR has defined different standards: A,B,D,E,F,G,D,H,I,K,K1,L,M,N,...
-The CCIR says not much about about the colorsystem used !!!
+The CCIR says not much about the colorsystem used !!!
And talking about a colorsystem says not to much about how it is broadcast.
The CCIR standards A,E,F are not used any more.
diff --git a/Documentation/video4linux/bttv/Insmod-options b/Documentation/video4linux/bttv/Insmod-options
index fc94ff235ffa..bb7c2cac7917 100644
--- a/Documentation/video4linux/bttv/Insmod-options
+++ b/Documentation/video4linux/bttv/Insmod-options
@@ -54,6 +54,12 @@ bttv.o
dropouts.
chroma_agc=0/1 AGC of chroma signal, off by default.
adc_crush=0/1 Luminance ADC crush, on by default.
+ i2c_udelay= Allow reduce I2C speed. Default is 5 usecs
+ (meaning 66,67 Kbps). The default is the
+ maximum supported speed by kernel bitbang
+ algoritm. You may use lower numbers, if I2C
+ messages are lost (16 is known to work on
+ all supported cards).
bttv_gpio=0/1
gpiomask=
diff --git a/Documentation/video4linux/cx2341x/README.hm12 b/Documentation/video4linux/cx2341x/README.hm12
new file mode 100644
index 000000000000..0e213ed095e6
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/README.hm12
@@ -0,0 +1,116 @@
+The cx23416 can produce (and the cx23415 can also read) raw YUV output. The
+format of a YUV frame is specific to this chip and is called HM12. 'HM' stands
+for 'Hauppauge Macroblock', which is a misnomer as 'Conexant Macroblock' would
+be more accurate.
+
+The format is YUV 4:2:0 which uses 1 Y byte per pixel and 1 U and V byte per
+four pixels.
+
+The data is encoded as two macroblock planes, the first containing the Y
+values, the second containing UV macroblocks.
+
+The Y plane is divided into blocks of 16x16 pixels from left to right
+and from top to bottom. Each block is transmitted in turn, line-by-line.
+
+So the first 16 bytes are the first line of the top-left block, the
+second 16 bytes are the second line of the top-left block, etc. After
+transmitting this block the first line of the block on the right to the
+first block is transmitted, etc.
+
+The UV plane is divided into blocks of 16x8 UV values going from left
+to right, top to bottom. Each block is transmitted in turn, line-by-line.
+
+So the first 16 bytes are the first line of the top-left block and
+contain 8 UV value pairs (16 bytes in total). The second 16 bytes are the
+second line of 8 UV pairs of the top-left block, etc. After transmitting
+this block the first line of the block on the right to the first block is
+transmitted, etc.
+
+The code below is given as an example on how to convert HM12 to separate
+Y, U and V planes. This code assumes frames of 720x576 (PAL) pixels.
+
+The width of a frame is always 720 pixels, regardless of the actual specified
+width.
+
+--------------------------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static unsigned char frame[576*720*3/2];
+static unsigned char framey[576*720];
+static unsigned char frameu[576*720 / 4];
+static unsigned char framev[576*720 / 4];
+
+static void de_macro_y(unsigned char* dst, unsigned char *src, int dstride, int w, int h)
+{
+ unsigned int y, x, i;
+
+ // descramble Y plane
+ // dstride = 720 = w
+ // The Y plane is divided into blocks of 16x16 pixels
+ // Each block in transmitted in turn, line-by-line.
+ for (y = 0; y < h; y += 16) {
+ for (x = 0; x < w; x += 16) {
+ for (i = 0; i < 16; i++) {
+ memcpy(dst + x + (y + i) * dstride, src, 16);
+ src += 16;
+ }
+ }
+ }
+}
+
+static void de_macro_uv(unsigned char *dstu, unsigned char *dstv, unsigned char *src, int dstride, int w, int h)
+{
+ unsigned int y, x, i;
+
+ // descramble U/V plane
+ // dstride = 720 / 2 = w
+ // The U/V values are interlaced (UVUV...).
+ // Again, the UV plane is divided into blocks of 16x16 UV values.
+ // Each block in transmitted in turn, line-by-line.
+ for (y = 0; y < h; y += 16) {
+ for (x = 0; x < w; x += 8) {
+ for (i = 0; i < 16; i++) {
+ int idx = x + (y + i) * dstride;
+
+ dstu[idx+0] = src[0]; dstv[idx+0] = src[1];
+ dstu[idx+1] = src[2]; dstv[idx+1] = src[3];
+ dstu[idx+2] = src[4]; dstv[idx+2] = src[5];
+ dstu[idx+3] = src[6]; dstv[idx+3] = src[7];
+ dstu[idx+4] = src[8]; dstv[idx+4] = src[9];
+ dstu[idx+5] = src[10]; dstv[idx+5] = src[11];
+ dstu[idx+6] = src[12]; dstv[idx+6] = src[13];
+ dstu[idx+7] = src[14]; dstv[idx+7] = src[15];
+ src += 16;
+ }
+ }
+ }
+}
+
+/*************************************************************************/
+int main(int argc, char **argv)
+{
+ FILE *fin;
+ int i;
+
+ if (argc == 1) fin = stdin;
+ else fin = fopen(argv[1], "r");
+
+ if (fin == NULL) {
+ fprintf(stderr, "cannot open input\n");
+ exit(-1);
+ }
+ while (fread(frame, sizeof(frame), 1, fin) == 1) {
+ de_macro_y(framey, frame, 720, 720, 576);
+ de_macro_uv(frameu, framev, frame + 720 * 576, 720 / 2, 720 / 2, 576 / 2);
+ fwrite(framey, sizeof(framey), 1, stdout);
+ fwrite(framev, sizeof(framev), 1, stdout);
+ fwrite(frameu, sizeof(frameu), 1, stdout);
+ }
+ fclose(fin);
+ return 0;
+}
+
+--------------------------------------------------------------------------
diff --git a/Documentation/video4linux/cx2341x/README.vbi b/Documentation/video4linux/cx2341x/README.vbi
new file mode 100644
index 000000000000..5807cf156173
--- /dev/null
+++ b/Documentation/video4linux/cx2341x/README.vbi
@@ -0,0 +1,45 @@
+
+Format of embedded V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data
+=========================================================
+
+This document describes the V4L2_MPEG_STREAM_VBI_FMT_IVTV format of the VBI data
+embedded in an MPEG-2 program stream. This format is in part dictated by some
+hardware limitations of the ivtv driver (the driver for the Conexant cx23415/6
+chips), in particular a maximum size for the VBI data. Anything longer is cut
+off when the MPEG stream is played back through the cx23415.
+
+The advantage of this format is it is very compact and that all VBI data for
+all lines can be stored while still fitting within the maximum allowed size.
+
+The stream ID of the VBI data is 0xBD. The maximum size of the embedded data is
+4 + 43 * 36, which is 4 bytes for a header and 2 * 18 VBI lines with a 1 byte
+header and a 42 bytes payload each. Anything beyond this limit is cut off by
+the cx23415/6 firmware. Besides the data for the VBI lines we also need 36 bits
+for a bitmask determining which lines are captured and 4 bytes for a magic cookie,
+signifying that this data package contains V4L2_MPEG_STREAM_VBI_FMT_IVTV VBI data.
+If all lines are used, then there is no longer room for the bitmask. To solve this
+two different magic numbers were introduced:
+
+'itv0': After this magic number two unsigned longs follow. Bits 0-17 of the first
+unsigned long denote which lines of the first field are captured. Bits 18-31 of
+the first unsigned long and bits 0-3 of the second unsigned long are used for the
+second field.
+
+'ITV0': This magic number assumes all VBI lines are captured, i.e. it implicitly
+implies that the bitmasks are 0xffffffff and 0xf.
+
+After these magic cookies (and the 8 byte bitmask in case of cookie 'itv0') the
+captured VBI lines start:
+
+For each line the least significant 4 bits of the first byte contain the data type.
+Possible values are shown in the table below. The payload is in the following 42
+bytes.
+
+Here is the list of possible data types:
+
+#define IVTV_SLICED_TYPE_TELETEXT 0x1 // Teletext (uses lines 6-22 for PAL)
+#define IVTV_SLICED_TYPE_CC 0x4 // Closed Captions (line 21 NTSC)
+#define IVTV_SLICED_TYPE_WSS 0x5 // Wide Screen Signal (line 23 PAL)
+#define IVTV_SLICED_TYPE_VPS 0x7 // Video Programming System (PAL) (line 16)
+
+Hans Verkuil <hverkuil@xs4all.nl>
diff --git a/Documentation/video4linux/cx2341x/fw-decoder-api.txt b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
index 9df4fb3ea0f2..78bf5f21e513 100644
--- a/Documentation/video4linux/cx2341x/fw-decoder-api.txt
+++ b/Documentation/video4linux/cx2341x/fw-decoder-api.txt
@@ -102,7 +102,7 @@ Param[0]
Name CX2341X_DEC_GET_XFER_INFO
Enum 9/0x09
Description
- This API call may be used to detect an end of stream condtion.
+ This API call may be used to detect an end of stream condition.
Result[0]
Stream type
Result[1]
diff --git a/Documentation/video4linux/cx2341x/fw-encoder-api.txt b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
index 001c68644b08..15df0df57ddd 100644
--- a/Documentation/video4linux/cx2341x/fw-encoder-api.txt
+++ b/Documentation/video4linux/cx2341x/fw-encoder-api.txt
@@ -280,7 +280,7 @@ Param[0]
Param[1]
Unknown, but leaving this to 0 seems to work best. Indications are that
this might have to do with USB support, although passing anything but 0
- onl breaks things.
+ only breaks things.
-------------------------------------------------------------------------------
diff --git a/Documentation/video4linux/cx2341x/fw-osd-api.txt b/Documentation/video4linux/cx2341x/fw-osd-api.txt
index da98ae30a37a..0a602f3e601b 100644
--- a/Documentation/video4linux/cx2341x/fw-osd-api.txt
+++ b/Documentation/video4linux/cx2341x/fw-osd-api.txt
@@ -97,7 +97,7 @@ Result[0]
Result[1]
top left vertical offset
Result[2]
- bottom right hotizontal offset
+ bottom right horizontal offset
Result[3]
bottom right vertical offset
diff --git a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
index 93fec32a1188..faccee68f603 100644
--- a/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
+++ b/Documentation/video4linux/cx88/hauppauge-wintv-cx88-ir.txt
@@ -30,7 +30,7 @@ provide for a handler)
GP_SAMPLE register is at 0x35C058
Bits are then right shifted into the GP_SAMPLE register at the specified
-rate; you get an interrupt when a full DWORD is recieved.
+rate; you get an interrupt when a full DWORD is received.
You need to recover the actual RC5 bits out of the (oversampled) IR sensor
bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data) An
actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
diff --git a/Documentation/video4linux/et61x251.txt b/Documentation/video4linux/et61x251.txt
index cd584f20a997..1bdee8f85b9a 100644
--- a/Documentation/video4linux/et61x251.txt
+++ b/Documentation/video4linux/et61x251.txt
@@ -80,7 +80,7 @@ Some of the features of the driver are:
high compression quality (see also "Notes for V4L2 application developers"
paragraph);
- full support for the capabilities of every possible image sensors that can
- be connected to the ET61X[12]51 bridges, including, for istance, red, green,
+ be connected to the ET61X[12]51 bridges, including, for instance, red, green,
blue and global gain adjustments and exposure control (see "Supported
devices" paragraph for details);
- use of default color settings for sunlight conditions;
@@ -222,7 +222,7 @@ identifier - of the camera registered as "/dev/video0":
[root@localhost #] echo 1 > i2c_reg
[root@localhost #] cat i2c_val
-Note that if the sensor registers can not be read, "cat" will fail.
+Note that if the sensor registers cannot be read, "cat" will fail.
To avoid race conditions, all the I/O accesses to the files are serialized.
diff --git a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
index 93fec32a1188..faccee68f603 100644
--- a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
+++ b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
@@ -30,7 +30,7 @@ provide for a handler)
GP_SAMPLE register is at 0x35C058
Bits are then right shifted into the GP_SAMPLE register at the specified
-rate; you get an interrupt when a full DWORD is recieved.
+rate; you get an interrupt when a full DWORD is received.
You need to recover the actual RC5 bits out of the (oversampled) IR sensor
bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data) An
actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
diff --git a/Documentation/video4linux/meye.txt b/Documentation/video4linux/meye.txt
index 2137da97552f..ecb34160e61d 100644
--- a/Documentation/video4linux/meye.txt
+++ b/Documentation/video4linux/meye.txt
@@ -29,7 +29,7 @@ driver (PCI vendor/device is 0x136b/0xff01)
The third one, present in recent (more or less last year) Picturebooks
(C1M* models), is not supported. The manufacturer has given the specs
-to the developers under a NDA (which allows the develoment of a GPL
+to the developers under a NDA (which allows the development of a GPL
driver however), but things are not moving very fast (see
http://r-engine.sourceforge.net/) (PCI vendor/device is 0x10cf/0x2011).
diff --git a/Documentation/video4linux/sn9c102.txt b/Documentation/video4linux/sn9c102.txt
index 1d20895b4354..8cda472db36d 100644
--- a/Documentation/video4linux/sn9c102.txt
+++ b/Documentation/video4linux/sn9c102.txt
@@ -60,7 +60,7 @@ It's worth to note that SONiX has never collaborated with the author during the
development of this project, despite several requests for enough detailed
specifications of the register tables, compression engine and video data format
of the above chips. Nevertheless, these informations are no longer necessary,
-becouse all the aspects related to these chips are known and have been
+because all the aspects related to these chips are known and have been
described in detail in this documentation.
The driver relies on the Video4Linux2 and USB core modules. It has been
@@ -85,7 +85,7 @@ Some of the features of the driver are:
high compression quality (see also "Notes for V4L2 application developers"
and "Video frame formats" paragraphs);
- full support for the capabilities of many of the possible image sensors that
- can be connected to the SN9C10x bridges, including, for istance, red, green,
+ can be connected to the SN9C10x bridges, including, for instance, red, green,
blue and global gain adjustments and exposure (see "Supported devices"
paragraph for details);
- use of default color settings for sunlight conditions;
diff --git a/Documentation/video4linux/w9968cf.txt b/Documentation/video4linux/w9968cf.txt
index 0d53ce774b01..e0bba8393c77 100644
--- a/Documentation/video4linux/w9968cf.txt
+++ b/Documentation/video4linux/w9968cf.txt
@@ -15,7 +15,7 @@ Index
5. Supported devices
6. Module dependencies
7. Module loading
-8. Module paramaters
+8. Module parameters
9. Contact information
10. Credits
diff --git a/Documentation/video4linux/zr36120.txt b/Documentation/video4linux/zr36120.txt
index ac6d92d01944..1a1c2d03a5c8 100644
--- a/Documentation/video4linux/zr36120.txt
+++ b/Documentation/video4linux/zr36120.txt
@@ -118,9 +118,9 @@ card is not there, please try if any other card gives some
response, and mail me if you got a working tvcard addition.
PS. <TVCard editors behold!)
- Dont forget to set video_input to the number of inputs
+ Don't forget to set video_input to the number of inputs
you defined in the video_mux part of the tvcard definition.
- Its a common error to add a channel but not incrementing
+ It's a common error to add a channel but not incrementing
video_input and getting angry with me/v4l/linux/linus :(
You are now ready to test the framegrabber with your favorite
diff --git a/Documentation/vm/numa b/Documentation/vm/numa
index 4b8db1bd3b78..e93ad9425e2a 100644
--- a/Documentation/vm/numa
+++ b/Documentation/vm/numa
@@ -22,7 +22,7 @@ The initial port includes NUMAizing the bootmem allocator code by
encapsulating all the pieces of information into a bootmem_data_t
structure. Node specific calls have been added to the allocator.
In theory, any platform which uses the bootmem allocator should
-be able to to put the bootmem and mem_map data structures anywhere
+be able to put the bootmem and mem_map data structures anywhere
it deems best.
Each node's page allocation data structures have also been encapsulated
diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt
index 958ff3d48be3..7e8ae83e9847 100644
--- a/Documentation/watchdog/watchdog-api.txt
+++ b/Documentation/watchdog/watchdog-api.txt
@@ -45,7 +45,7 @@ daemon and it crashes the system will not reboot. Because of this,
some of the drivers support the configuration option "Disable watchdog
shutdown on close", CONFIG_WATCHDOG_NOWAYOUT. If it is set to Y when
compiling the kernel, there is no way of disabling the watchdog once
-it has been started. So, if the watchdog dameon crashes, the system
+it has been started. So, if the watchdog daemon crashes, the system
will reboot after the timeout has passed.
Some other drivers will not disable the watchdog, unless a specific
@@ -207,7 +207,7 @@ Note that not all devices support these two calls, and some only
support the GETBOOTSTATUS call.
Some drivers can measure the temperature using the GETTEMP ioctl. The
-returned value is the temperature in degrees farenheit.
+returned value is the temperature in degrees fahrenheit.
int temperature;
ioctl(fd, WDIOC_GETTEMP, &temperature);
@@ -258,13 +258,13 @@ booke_wdt.c -- PowerPC BookE Watchdog Timer
Timeout default varies according to frequency, supports
SETTIMEOUT
- Watchdog can not be turned off, CONFIG_WATCHDOG_NOWAYOUT
+ Watchdog cannot be turned off, CONFIG_WATCHDOG_NOWAYOUT
does not make sense
GETSUPPORT returns the watchdog_info struct, and
GETSTATUS returns the supported options. GETBOOTSTATUS
returns a 1 if the last reset was caused by the
- watchdog and a 0 otherwise. This watchdog can not be
+ watchdog and a 0 otherwise. This watchdog cannot be
disabled once it has been started. The wdt_period kernel
parameter selects which bit of the time base changing
from 0->1 will trigger the watchdog exception. Changing
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index 4303e0c12476..f3c57f43ba64 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -109,7 +109,7 @@ Idle loop
Rebooting
reboot=b[ios] | t[riple] | k[bd] [, [w]arm | [c]old]
- bios Use the CPU reboto vector for warm reset
+ bios Use the CPU reboot vector for warm reset
warm Don't set the cold reboot flag
cold Set the cold reboot flag
triple Force a triple fault (init)
@@ -199,6 +199,11 @@ IOMMU
allowed overwrite iommu off workarounds for specific chipsets.
soft Use software bounce buffering (default for Intel machines)
noaperture Don't touch the aperture for AGP.
+ allowdac Allow DMA >4GB
+ When off all DMA over >4GB is forced through an IOMMU or bounce
+ buffering.
+ nodac Forbid DMA >4GB
+ panic Always panic when IOMMU overflows
swiotlb=pages[,force]
diff --git a/MAINTAINERS b/MAINTAINERS
index 767a43434ae8..d708702aba2f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -144,11 +144,9 @@ L: netdev@vger.kernel.org
S: Maintained
8250/16?50 (AND CLONE UARTS) SERIAL DRIVER
-P: Russell King
-M: rmk+serial@arm.linux.org.uk
L: linux-serial@vger.kernel.org
W: http://serial.sourceforge.net
-S: Maintained
+S: Orphan
8390 NETWORK DRIVERS [WD80x3/SMC-ELITE, SMC-ULTRA, NE2000, 3C503, etc.]
P: Paul Gortmaker
@@ -501,7 +499,7 @@ S: Maintained
BLOCK LAYER
P: Jens Axboe
-M: axboe@suse.de
+M: axboe@kernel.dk
L: linux-kernel@vger.kernel.org
T: git kernel.org:/pub/scm/linux/kernel/git/axboe/linux-2.6-block.git
S: Maintained
@@ -643,7 +641,7 @@ CALGARY x86-64 IOMMU
P: Muli Ben-Yehuda
M: muli@il.ibm.com
P: Jon D. Mason
-M: jdmason@us.ibm.com
+M: jdmason@kudzu.us
L: linux-kernel@vger.kernel.org
L: discuss@x86-64.org
S: Maintained
@@ -851,7 +849,7 @@ P: Doug Warzecha
M: Douglas_Warzecha@dell.com
S: Maintained
-DEVICE-MAPPER
+DEVICE-MAPPER (LVM)
P: Alasdair Kergon
L: dm-devel@redhat.com
W: http://sources.redhat.com/dm
@@ -900,6 +898,17 @@ M: jack@suse.cz
L: linux-kernel@vger.kernel.org
S: Maintained
+DISTRIBUTED LOCK MANAGER
+P: Patrick Caulfield
+M: pcaulfie@redhat.com
+P: David Teigland
+M: teigland@redhat.com
+L: cluster-devel@redhat.com
+W: http://sources.redhat.com/cluster/
+T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git
+T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git
+S: Supported
+
DAVICOM FAST ETHERNET (DMFE) NETWORK DRIVER
P: Tobias Ringstrom
M: tori@unhappy.mine.nu
@@ -979,6 +988,13 @@ L: ebtables-devel@lists.sourceforge.net
W: http://ebtables.sourceforge.net/
S: Maintained
+ECRYPT FILE SYSTEM
+P: Mike Halcrow, Phillip Hellewell
+M: mhalcrow@us.ibm.com, phillip@hellewell.homeip.net
+L: ecryptfs-devel@lists.sourceforge.net
+W: http://ecryptfs.sourceforge.net/
+S: Supported
+
EDAC-CORE
P: Doug Thompson
M: norsk5@xmission.com
@@ -1168,6 +1184,15 @@ M: khc@pm.waw.pl
W: http://www.kernel.org/pub/linux/utils/net/hdlc/
S: Maintained
+GFS2 FILE SYSTEM
+P: Steven Whitehouse
+M: swhiteho@redhat.com
+L: cluster-devel@redhat.com
+W: http://sources.redhat.com/cluster/
+T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-fixes.git
+T: git kernel.org:/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw.git
+S: Supported
+
GIGASET ISDN DRIVERS
P: Hansjoerg Lipp
M: hjlipp@web.de
@@ -1380,7 +1405,7 @@ S: Maintained
IDE/ATAPI CDROM DRIVER
P: Jens Axboe
-M: axboe@suse.de
+M: axboe@kernel.dk
L: linux-kernel@vger.kernel.org
W: http://www.kernel.dk
S: Maintained
@@ -1398,36 +1423,29 @@ M: Gadi Oxman <gadio@netvision.net.il>
L: linux-kernel@vger.kernel.org
S: Maintained
-IEEE 1394 ETHERNET (eth1394)
-L: linux1394-devel@lists.sourceforge.net
-W: http://www.linux1394.org/
-S: Orphan
-
IEEE 1394 SUBSYSTEM
P: Ben Collins
M: bcollins@debian.org
-P: Jody McIntyre
-M: scjody@modernduck.com
+P: Stefan Richter
+M: stefanr@s5r6.in-berlin.de
L: linux1394-devel@lists.sourceforge.net
W: http://www.linux1394.org/
-T: git kernel.org:/pub/scm/linux/kernel/git/scjody/ieee1394.git
+T: git kernel.org:/pub/scm/linux/kernel/git/ieee1394/linux1394-2.6.git
S: Maintained
-IEEE 1394 OHCI DRIVER
-P: Ben Collins
-M: bcollins@debian.org
-P: Jody McIntyre
-M: scjody@modernduck.com
+IEEE 1394 IPV4 DRIVER (eth1394)
+P: Stefan Richter
+M: stefanr@s5r6.in-berlin.de
L: linux1394-devel@lists.sourceforge.net
-W: http://www.linux1394.org/
-S: Maintained
+S: Odd Fixes
IEEE 1394 PCILYNX DRIVER
P: Jody McIntyre
M: scjody@modernduck.com
+P: Stefan Richter
+M: stefanr@s5r6.in-berlin.de
L: linux1394-devel@lists.sourceforge.net
-W: http://www.linux1394.org/
-S: Maintained
+S: Odd Fixes
IEEE 1394 RAW I/O DRIVER
P: Ben Collins
@@ -1435,16 +1453,6 @@ M: bcollins@debian.org
P: Dan Dennedy
M: dan@dennedy.org
L: linux1394-devel@lists.sourceforge.net
-W: http://www.linux1394.org/
-S: Maintained
-
-IEEE 1394 SBP2
-P: Ben Collins
-M: bcollins@debian.org
-P: Stefan Richter
-M: stefanr@s5r6.in-berlin.de
-L: linux1394-devel@lists.sourceforge.net
-W: http://www.linux1394.org/
S: Maintained
IMS TWINTURBO FRAMEBUFFER DRIVER
@@ -1660,6 +1668,12 @@ M: sct@redhat.com, akpm@osdl.org
L: ext2-devel@lists.sourceforge.net
S: Maintained
+K8TEMP HARDWARE MONITORING DRIVER
+P: Rudolf Marek
+M: r.marek@assembler.cz
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
KCONFIG
P: Roman Zippel
M: zippel@linux-m68k.org
@@ -1912,11 +1926,6 @@ M: rroesler@syskonnect.de
W: http://www.syskonnect.com
S: Supported
-MAESTRO PCI SOUND DRIVERS
-P: Zach Brown
-M: zab@zabbo.net
-S: Odd Fixes
-
MAN-PAGES: MANUAL PAGES FOR LINUX -- Sections 2, 3, 4, 5, and 7
P: Michael Kerrisk
M: mtk-manpages@gmx.net
@@ -1995,6 +2004,13 @@ M: rubini@ipvvis.unipv.it
L: linux-kernel@vger.kernel.org
S: Maintained
+MSI LAPTOP SUPPORT
+P: Lennart Poettering
+M: mzxreary@0pointer.de
+L: https://tango.0pointer.de/mailman/listinfo/s270-linux
+W: http://0pointer.de/lennart/tchibo.html
+S: Maintained
+
MTRR AND SIMILAR SUPPORT [i386]
P: Richard Gooch
M: rgooch@atnf.csiro.au
@@ -2002,9 +2018,10 @@ L: linux-kernel@vger.kernel.org
W: http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html
S: Maintained
-MULTIMEDIA CARD (MMC) SUBSYSTEM
-P: Russell King
-M: rmk+mmc@arm.linux.org.uk
+MULTIMEDIA CARD (MMC) AND SECURE DIGITAL (SD) SUBSYSTEM
+P: Pierre Ossman
+M: drzeus-mmc@drzeus.cx
+L: linux-kernel@vger.kernel.org
S: Maintained
MULTISOUND SOUND DRIVER
@@ -2041,11 +2058,13 @@ P: Marc Boucher
P: James Morris
P: Harald Welte
P: Jozsef Kadlecsik
-M: coreteam@netfilter.org
+P: Patrick McHardy
+M: kaber@trash.net
+L: netfilter-devel@lists.netfilter.org
+L: netfilter@lists.netfilter.org
+L: coreteam@netfilter.org
W: http://www.netfilter.org/
W: http://www.iptables.org/
-L: netfilter@lists.netfilter.org
-L: netfilter-devel@lists.netfilter.org
S: Supported
NETLABEL
@@ -2062,7 +2081,7 @@ L: linux-hams@vger.kernel.org
W: http://www.linux-ax25.org/
S: Maintained
-NETWORK BLOCK DEVICE
+NETWORK BLOCK DEVICE (NBD)
P: Paul Clements
M: Paul.Clements@steeleye.com
S: Maintained
@@ -2262,6 +2281,17 @@ T: git kernel.org:/pub/scm/linux/kernel/git/kyle/parisc-2.6.git
T: cvs cvs.parisc-linux.org:/var/cvs/linux-2.6
S: Maintained
+PC87360 HARDWARE MONITORING DRIVER
+P: Jim Cromie
+M: jim.cromie@gmail.com
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
+PC8736x GPIO DRIVER
+P: Jim Cromie
+M: jim.cromie@gmail.com
+S: Maintained
+
PCI ERROR RECOVERY
P: Linas Vepstas
M: linas@austin.ibm.com
@@ -2285,8 +2315,8 @@ T: quilt kernel.org/pub/linux/kernel/people/gregkh/gregkh-2.6/
S: Supported
PCI HOTPLUG CORE
-P: Greg Kroah-Hartman
-M: gregkh@suse.de
+P: Kristen Carlson Accardi
+M: kristen.c.accardi@intel.com
S: Supported
PCI HOTPLUG COMPAQ DRIVER
@@ -2455,6 +2485,19 @@ M: mporter@kernel.crashing.org
L: linux-kernel@vger.kernel.org
S: Maintained
+READ-COPY UPDATE (RCU)
+P: Dipankar Sarma
+M: dipankar@in.ibm.com
+W: http://www.rdrop.com/users/paulmck/rclock/
+L: linux-kernel@vger.kernel.org
+S: Supported
+
+RCUTORTURE MODULE
+P: Josh Triplett
+M: josh@freedesktop.org
+L: linux-kernel@vger.kernel.org
+S: Maintained
+
REAL TIME CLOCK DRIVER
P: Paul Gortmaker
M: p_gortmaker@yahoo.com
@@ -2548,7 +2591,7 @@ S: Maintained
SCSI CDROM DRIVER
P: Jens Axboe
-M: axboe@suse.de
+M: axboe@kernel.dk
L: linux-scsi@vger.kernel.org
W: http://www.kernel.dk
S: Maintained
@@ -2580,10 +2623,19 @@ L: lksctp-developers@lists.sourceforge.net
S: Supported
SCx200 CPU SUPPORT
-P: Christer Weinigel
-M: christer@weinigel.se
-W: http://www.weinigel.se
-S: Supported
+P: Jim Cromie
+M: jim.cromie@gmail.com
+S: Odd Fixes
+
+SCx200 GPIO DRIVER
+P: Jim Cromie
+M: jim.cromie@gmail.com
+S: Maintained
+
+SCx200 HRT CLOCKSOURCE DRIVER
+P: Jim Cromie
+M: jim.cromie@gmail.com
+S: Maintained
SECURITY CONTACT
P: Security Officers
@@ -2679,7 +2731,6 @@ M: josejx@gentoo.org
P: Daniel Drake
M: dsd@gentoo.org
W: http://softmac.sipsolutions.net/
-L: softmac-dev@sipsolutions.net
L: netdev@vger.kernel.org
S: Maintained
@@ -2729,14 +2780,6 @@ M: chrisw@sous-sol.org
L: stable@kernel.org
S: Maintained
-STABLE BRANCH:
-P: Greg Kroah-Hartman
-M: greg@kroah.com
-P: Chris Wright
-M: chrisw@sous-sol.org
-L: stable@kernel.org
-S: Maintained
-
TPM DEVICE DRIVER
P: Kylene Hall
M: kjhall@us.ibm.com
@@ -2757,14 +2800,7 @@ S: Maintained
UltraSPARC (sparc64):
P: David S. Miller
M: davem@davemloft.net
-P: Eddie C. Dost
-M: ecd@brainaid.de
-P: Jakub Jelinek
-M: jj@sunsite.ms.mff.cuni.cz
-P: Anton Blanchard
-M: anton@samba.org
L: sparclinux@vger.kernel.org
-L: ultralinux@vger.kernel.org
T: git kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6.git
S: Maintained
@@ -2811,6 +2847,12 @@ M: R.E.Wolff@BitWizard.nl
L: linux-kernel@vger.kernel.org ?
S: Supported
+SPIDERNET NETWORK DRIVER for CELL
+P: Jim Lewis
+M: jim@jklewis.com
+L: netdev@vger.kernel.org
+S: Supported
+
SRM (Alpha) environment access
P: Jan-Benedict Glaw
M: jbglaw@lug-owl.de
@@ -2835,22 +2877,15 @@ S: Maintained
SUPERH (sh)
P: Paul Mundt
M: lethal@linux-sh.org
-P: Kazumoto Kojima
-M: kkojima@rr.iij4u.or.jp
-L: linuxsh-dev@lists.sourceforge.net
+L: linuxsh-dev@lists.sourceforge.net (subscribers-only)
W: http://www.linux-sh.org
-W: http://www.m17n.org/linux-sh/
-W: http://www.rr.iij4u.or.jp/~kkojima/linux-sh4.html
S: Maintained
SUPERH64 (sh64)
P: Paul Mundt
M: lethal@linux-sh.org
-P: Richard Curnow
-M: rc@rc0.org.uk
L: linuxsh-shmedia-dev@lists.sourceforge.net
W: http://www.linux-sh.org
-W: http://www.rc0.org.uk/sh64
S: Maintained
SUN3/3X
@@ -2885,6 +2920,11 @@ M: hlhung3i@gmail.com
W: http://tcp-lp-mod.sourceforge.net/
S: Maintained
+TI FLASH MEDIA INTERFACE DRIVER
+P: Alex Dubov
+M: oakad@yahoo.com
+S: Maintained
+
TI OMAP RANDOM NUMBER GENERATOR SUPPORT
P: Deepak Saxena
M: dsaxena@plexity.net
@@ -2991,7 +3031,7 @@ S: Maintained
UNIFORM CDROM DRIVER
P: Jens Axboe
-M: axboe@suse.de
+M: axboe@kernel.dk
L: linux-kernel@vger.kernel.org
W: http://www.kernel.dk
S: Maintained
@@ -3310,6 +3350,12 @@ W: http://linuxtv.org
T: git kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb.git
S: Maintained
+VT1211 HARDWARE MONITOR DRIVER
+P: Juerg Haefliger
+M: juergh@gmail.com
+L: lm-sensors@lm-sensors.org
+S: Maintained
+
VT8231 HARDWARE MONITOR DRIVER
P: Roger Lucas
M: roger@planbit.co.uk
@@ -3402,12 +3448,6 @@ M: Henk.Vergonet@gmail.com
L: usbb2k-api-dev@nongnu.org
S: Maintained
-YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
-P: Pete Zaitcev
-M: zaitcev@yahoo.com
-L: linux-kernel@vger.kernel.org
-S: Obsolete
-
Z8530 DRIVER FOR AX.25
P: Joerg Reuter
M: jreuter@yaina.de
diff --git a/Makefile b/Makefile
index 80dac0245d66..389ff0cca9a7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
-SUBLEVEL = 18
-EXTRAVERSION =
+SUBLEVEL = 19
+EXTRAVERSION =-rc2
NAME=Avast! A bilge rat!
# *DOCUMENTATION*
@@ -499,6 +499,7 @@ endif
ifdef CONFIG_UNWIND_INFO
CFLAGS += -fasynchronous-unwind-tables
+LDFLAGS_vmlinux += --eh-frame-hdr
endif
ifdef CONFIG_DEBUG_INFO
@@ -741,6 +742,9 @@ endif # ifdef CONFIG_KALLSYMS
# vmlinux image - including updated kernel symbols
vmlinux: $(vmlinux-lds) $(vmlinux-init) $(vmlinux-main) $(kallsyms.o) FORCE
+ifdef CONFIG_HEADERS_CHECK
+ $(Q)$(MAKE) -f $(srctree)/Makefile headers_check
+endif
$(call if_changed_rule,vmlinux__)
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost $@
$(Q)rm -f .old_version
@@ -932,7 +936,7 @@ headers_install_all: include/linux/version.h scripts_basic FORCE
PHONY += headers_install
headers_install: include/linux/version.h scripts_basic FORCE
- @if [ ! -r include/asm-$(ARCH)/Kbuild ]; then \
+ @if [ ! -r $(srctree)/include/asm-$(ARCH)/Kbuild ]; then \
echo '*** Error: Headers not exportable for this architecture ($(ARCH))'; \
exit 1 ; fi
$(Q)$(MAKE) $(build)=scripts scripts/unifdef
@@ -1316,12 +1320,13 @@ define xtags
$(all-sources) | xargs $1 -a \
-I __initdata,__exitdata,__acquires,__releases \
-I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \
- --extra=+f --c-kinds=+px; \
+ --extra=+f --c-kinds=+px \
+ --regex-asm='/ENTRY\(([^)]*)\).*/\1/'; \
$(all-kconfigs) | xargs $1 -a \
--langdef=kconfig \
--language-force=kconfig \
--regex-kconfig='/^[[:blank:]]*config[[:blank:]]+([[:alnum:]_]+)/\1/'; \
- $(all-defconfigs) | xargs $1 -a \
+ $(all-defconfigs) | xargs -r $1 -a \
--langdef=dotconfig \
--language-force=dotconfig \
--regex-dotconfig='/^#?[[:blank:]]*(CONFIG_[[:alnum:]_]+)/\1/'; \
@@ -1329,7 +1334,7 @@ define xtags
$(all-sources) | xargs $1 -a; \
$(all-kconfigs) | xargs $1 -a \
--regex='/^[ \t]*config[ \t]+\([a-zA-Z0-9_]+\)/\1/'; \
- $(all-defconfigs) | xargs $1 -a \
+ $(all-defconfigs) | xargs -r $1 -a \
--regex='/^#?[ \t]?\(CONFIG_[a-zA-Z0-9_]+\)/\1/'; \
else \
$(all-sources) | xargs $1 -a; \
@@ -1385,9 +1390,13 @@ endif #ifeq ($(config-targets),1)
endif #ifeq ($(mixed-targets),1)
PHONY += checkstack kernelrelease kernelversion
+
+# Use $(SUBARCH) here instead of $(ARCH) so that this works for UML.
+# In the UML case, $(SUBARCH) is the name of the underlying
+# architecture, while for all other arches, it is the same as $(ARCH).
checkstack:
$(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \
- $(PERL) $(src)/scripts/checkstack.pl $(ARCH)
+ $(PERL) $(src)/scripts/checkstack.pl $(SUBARCH)
kernelrelease:
$(if $(wildcard include/config/kernel.release), $(Q)echo $(KERNELRELEASE), \
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index 2b36afd8e969..7e55ea66c6d4 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -534,7 +534,7 @@ config ARCH_DISCONTIGMEM_ENABLE
bool "Discontiguous Memory Support (EXPERIMENTAL)"
depends on EXPERIMENTAL
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.
diff --git a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
index f042cc42b00f..e9762a33b043 100644
--- a/arch/alpha/kernel/alpha_ksyms.c
+++ b/arch/alpha/kernel/alpha_ksyms.c
@@ -1,46 +1,18 @@
/*
- * linux/arch/alpha/kernel/ksyms.c
+ * linux/arch/alpha/kernel/alpha_ksyms.c
*
* Export the alpha-specific functions that are needed for loadable
* modules.
*/
#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/socket.h>
-#include <linux/syscalls.h>
-#include <linux/in.h>
-#include <linux/in6.h>
-#include <linux/pci.h>
-#include <linux/screen_info.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
#include <asm/console.h>
-#include <asm/hwrpb.h>
#include <asm/uaccess.h>
-#include <asm/processor.h>
#include <asm/checksum.h>
-#include <linux/interrupt.h>
#include <asm/fpu.h>
-#include <asm/irq.h>
#include <asm/machvec.h>
-#include <asm/pgalloc.h>
-#include <asm/semaphore.h>
-#include <asm/tlbflush.h>
-#include <asm/cacheflush.h>
-#include <asm/vga.h>
-#define __KERNEL_SYSCALLS__
-#include <asm/unistd.h>
-
-extern struct hwrpb_struct *hwrpb;
-extern spinlock_t rtc_lock;
+#include <linux/syscalls.h>
/* these are C runtime functions with special calling conventions: */
extern void __divl (void);
@@ -53,14 +25,9 @@ extern void __divqu (void);
extern void __remqu (void);
EXPORT_SYMBOL(alpha_mv);
-EXPORT_SYMBOL(screen_info);
-EXPORT_SYMBOL(perf_irq);
EXPORT_SYMBOL(callback_getenv);
EXPORT_SYMBOL(callback_setenv);
EXPORT_SYMBOL(callback_save_env);
-#ifdef CONFIG_ALPHA_GENERIC
-EXPORT_SYMBOL(alpha_using_srm);
-#endif /* CONFIG_ALPHA_GENERIC */
/* platform dependent support */
EXPORT_SYMBOL(strcat);
@@ -78,47 +45,14 @@ EXPORT_SYMBOL(__constant_c_memset);
EXPORT_SYMBOL(copy_page);
EXPORT_SYMBOL(clear_page);
-EXPORT_SYMBOL(__direct_map_base);
-EXPORT_SYMBOL(__direct_map_size);
-
-#ifdef CONFIG_PCI
-EXPORT_SYMBOL(pci_alloc_consistent);
-EXPORT_SYMBOL(pci_free_consistent);
-EXPORT_SYMBOL(pci_map_single);
-EXPORT_SYMBOL(pci_map_page);
-EXPORT_SYMBOL(pci_unmap_single);
-EXPORT_SYMBOL(pci_unmap_page);
-EXPORT_SYMBOL(pci_map_sg);
-EXPORT_SYMBOL(pci_unmap_sg);
-EXPORT_SYMBOL(pci_dma_supported);
-EXPORT_SYMBOL(pci_dac_dma_supported);
-EXPORT_SYMBOL(pci_dac_page_to_dma);
-EXPORT_SYMBOL(pci_dac_dma_to_page);
-EXPORT_SYMBOL(pci_dac_dma_to_offset);
-EXPORT_SYMBOL(alpha_gendev_to_pci);
-#endif
-EXPORT_SYMBOL(dma_set_mask);
-
-EXPORT_SYMBOL(dump_thread);
-EXPORT_SYMBOL(dump_elf_thread);
-EXPORT_SYMBOL(dump_elf_task);
-EXPORT_SYMBOL(dump_elf_task_fp);
-EXPORT_SYMBOL(hwrpb);
-EXPORT_SYMBOL(start_thread);
EXPORT_SYMBOL(alpha_read_fp_reg);
EXPORT_SYMBOL(alpha_read_fp_reg_s);
EXPORT_SYMBOL(alpha_write_fp_reg);
EXPORT_SYMBOL(alpha_write_fp_reg_s);
-/* In-kernel system calls. */
+/* entry.S */
EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(sys_dup);
-EXPORT_SYMBOL(sys_exit);
-EXPORT_SYMBOL(sys_write);
-EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(execve);
-EXPORT_SYMBOL(sys_setsid);
-EXPORT_SYMBOL(sys_wait4);
+EXPORT_SYMBOL(kernel_execve);
/* Networking helper routines. */
EXPORT_SYMBOL(csum_tcpudp_magic);
@@ -135,10 +69,6 @@ EXPORT_SYMBOL(alpha_fp_emul_imprecise);
EXPORT_SYMBOL(alpha_fp_emul);
#endif
-#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
-EXPORT_SYMBOL(__min_ipl);
-#endif
-
/*
* The following are specially called from the uaccess assembly stubs.
*/
@@ -161,27 +91,10 @@ EXPORT_SYMBOL(up);
*/
#ifdef CONFIG_SMP
-EXPORT_SYMBOL(flush_tlb_mm);
-EXPORT_SYMBOL(flush_tlb_range);
-EXPORT_SYMBOL(flush_tlb_page);
-EXPORT_SYMBOL(smp_imb);
-EXPORT_SYMBOL(cpu_data);
-EXPORT_SYMBOL(smp_num_cpus);
-EXPORT_SYMBOL(smp_call_function);
-EXPORT_SYMBOL(smp_call_function_on_cpu);
EXPORT_SYMBOL(_atomic_dec_and_lock);
#endif /* CONFIG_SMP */
/*
- * NUMA specific symbols
- */
-#ifdef CONFIG_DISCONTIGMEM
-EXPORT_SYMBOL(node_data);
-#endif /* CONFIG_DISCONTIGMEM */
-
-EXPORT_SYMBOL(rtc_lock);
-
-/*
* The following are special because they're not called
* explicitly (the C compiler or assembler generates them in
* response to division operations). Fortunately, their
@@ -201,8 +114,3 @@ EXPORT_SYMBOL(__remqu);
EXPORT_SYMBOL(memcpy);
EXPORT_SYMBOL(memset);
EXPORT_SYMBOL(memchr);
-
-#ifdef CONFIG_ALPHA_IRONGATE
-EXPORT_SYMBOL(irongate_ioremap);
-EXPORT_SYMBOL(irongate_iounmap);
-#endif
diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c
index a27ba12ba35e..ca46b2c24457 100644
--- a/arch/alpha/kernel/core_apecs.c
+++ b/arch/alpha/kernel/core_apecs.c
@@ -387,8 +387,7 @@ apecs_pci_clr_err(void)
}
void
-apecs_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+apecs_machine_check(unsigned long vector, unsigned long la_ptr)
{
struct el_common *mchk_header;
struct el_apecs_procdata *mchk_procdata;
@@ -412,7 +411,7 @@ apecs_machine_check(unsigned long vector, unsigned long la_ptr,
wrmces(0x7); /* reset machine check pending flag */
mb();
- process_mcheck_info(vector, la_ptr, regs, "APECS",
+ process_mcheck_info(vector, la_ptr, "APECS",
(mcheck_expected(0)
&& (mchk_sysdata->epic_dcsr & 0x0c00UL)));
}
diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c
index fd563064363c..1d6ee6c985f9 100644
--- a/arch/alpha/kernel/core_cia.c
+++ b/arch/alpha/kernel/core_cia.c
@@ -1192,8 +1192,7 @@ cia_decode_mchk(unsigned long la_ptr)
}
void
-cia_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+cia_machine_check(unsigned long vector, unsigned long la_ptr)
{
int expected;
@@ -1208,5 +1207,5 @@ cia_machine_check(unsigned long vector, unsigned long la_ptr,
expected = mcheck_expected(0);
if (!expected && vector == 0x660)
expected = cia_decode_mchk(la_ptr);
- process_mcheck_info(vector, la_ptr, regs, "CIA", expected);
+ process_mcheck_info(vector, la_ptr, "CIA", expected);
}
diff --git a/arch/alpha/kernel/core_irongate.c b/arch/alpha/kernel/core_irongate.c
index 138d497d1cca..e4a0bcf1d28b 100644
--- a/arch/alpha/kernel/core_irongate.c
+++ b/arch/alpha/kernel/core_irongate.c
@@ -404,6 +404,7 @@ irongate_ioremap(unsigned long addr, unsigned long size)
#endif
return (void __iomem *)vaddr;
}
+EXPORT_SYMBOL(irongate_ioremap);
void
irongate_iounmap(volatile void __iomem *xaddr)
@@ -414,3 +415,4 @@ irongate_iounmap(volatile void __iomem *xaddr)
if (addr)
return vfree((void *)(PAGE_MASK & addr));
}
+EXPORT_SYMBOL(irongate_iounmap);
diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c
index 6a5a9145c676..4843f6ec9f3a 100644
--- a/arch/alpha/kernel/core_lca.c
+++ b/arch/alpha/kernel/core_lca.c
@@ -19,6 +19,7 @@
#include <linux/tty.h>
#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
#include <asm/smp.h>
#include "proto.h"
@@ -386,8 +387,7 @@ ioc_error(__u32 stat0, __u32 stat1)
}
void
-lca_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs *regs)
+lca_machine_check(unsigned long vector, unsigned long la_ptr)
{
const char * reason;
union el_lca el;
@@ -397,7 +397,7 @@ lca_machine_check(unsigned long vector, unsigned long la_ptr,
wrmces(rdmces()); /* reset machine check pending flag */
printk(KERN_CRIT "LCA machine check: vector=%#lx pc=%#lx code=%#x\n",
- vector, regs->pc, (unsigned int) el.c->code);
+ vector, get_irq_regs()->pc, (unsigned int) el.c->code);
/*
* The first quadword after the common header always seems to
diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c
index 28849c894153..8d019071190a 100644
--- a/arch/alpha/kernel/core_mcpcia.c
+++ b/arch/alpha/kernel/core_mcpcia.c
@@ -572,8 +572,7 @@ mcpcia_print_system_area(unsigned long la_ptr)
}
void
-mcpcia_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+mcpcia_machine_check(unsigned long vector, unsigned long la_ptr)
{
struct el_common *mchk_header;
struct el_MCPCIA_uncorrected_frame_mcheck *mchk_logout;
@@ -610,7 +609,7 @@ mcpcia_machine_check(unsigned long vector, unsigned long la_ptr,
wrmces(0x7);
mb();
- process_mcheck_info(vector, la_ptr, regs, "MCPCIA", expected != 0);
+ process_mcheck_info(vector, la_ptr, "MCPCIA", expected != 0);
if (!expected && vector != 0x620 && vector != 0x630) {
mcpcia_print_uncorrectable(mchk_logout);
mcpcia_print_system_area(la_ptr);
diff --git a/arch/alpha/kernel/core_polaris.c b/arch/alpha/kernel/core_polaris.c
index 277674a500ff..c5a271d37abd 100644
--- a/arch/alpha/kernel/core_polaris.c
+++ b/arch/alpha/kernel/core_polaris.c
@@ -187,8 +187,7 @@ polaris_pci_clr_err(void)
}
void
-polaris_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+polaris_machine_check(unsigned long vector, unsigned long la_ptr)
{
/* Clear the error before any reporting. */
mb();
@@ -198,6 +197,6 @@ polaris_machine_check(unsigned long vector, unsigned long la_ptr,
wrmces(0x7);
mb();
- process_mcheck_info(vector, la_ptr, regs, "POLARIS",
+ process_mcheck_info(vector, la_ptr, "POLARIS",
mcheck_expected(0));
}
diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c
index ecce09e3626a..f5ca5255eb06 100644
--- a/arch/alpha/kernel/core_t2.c
+++ b/arch/alpha/kernel/core_t2.c
@@ -551,8 +551,7 @@ t2_clear_errors(int cpu)
* Hence all the taken/expected/any_expected/last_taken stuff...
*/
void
-t2_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+t2_machine_check(unsigned long vector, unsigned long la_ptr)
{
int cpu = smp_processor_id();
#ifdef CONFIG_VERBOSE_MCHECK
@@ -618,5 +617,5 @@ t2_machine_check(unsigned long vector, unsigned long la_ptr,
}
#endif
- process_mcheck_info(vector, la_ptr, regs, "T2", mcheck_expected(cpu));
+ process_mcheck_info(vector, la_ptr, "T2", mcheck_expected(cpu));
}
diff --git a/arch/alpha/kernel/core_tsunami.c b/arch/alpha/kernel/core_tsunami.c
index 8aa305bd6a2c..ce623c6e55e1 100644
--- a/arch/alpha/kernel/core_tsunami.c
+++ b/arch/alpha/kernel/core_tsunami.c
@@ -443,8 +443,7 @@ tsunami_pci_clr_err(void)
}
void
-tsunami_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+tsunami_machine_check(unsigned long vector, unsigned long la_ptr)
{
/* Clear error before any reporting. */
mb();
@@ -454,6 +453,6 @@ tsunami_machine_check(unsigned long vector, unsigned long la_ptr,
wrmces(0x7);
mb();
- process_mcheck_info(vector, la_ptr, regs, "TSUNAMI",
+ process_mcheck_info(vector, la_ptr, "TSUNAMI",
mcheck_expected(smp_processor_id()));
}
diff --git a/arch/alpha/kernel/core_wildfire.c b/arch/alpha/kernel/core_wildfire.c
index 2b767a1bad96..7e072443d7fd 100644
--- a/arch/alpha/kernel/core_wildfire.c
+++ b/arch/alpha/kernel/core_wildfire.c
@@ -322,8 +322,7 @@ wildfire_init_arch(void)
}
void
-wildfire_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+wildfire_machine_check(unsigned long vector, unsigned long la_ptr)
{
mb();
mb(); /* magic */
@@ -332,7 +331,7 @@ wildfire_machine_check(unsigned long vector, unsigned long la_ptr,
wrmces(0x7);
mb();
- process_mcheck_info(vector, la_ptr, regs, "WILDFIRE",
+ process_mcheck_info(vector, la_ptr, "WILDFIRE",
mcheck_expected(smp_processor_id()));
}
diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
index 01ecd09d4a64..c95e95e1ab04 100644
--- a/arch/alpha/kernel/entry.S
+++ b/arch/alpha/kernel/entry.S
@@ -655,12 +655,12 @@ kernel_thread:
.end kernel_thread
/*
- * execve(path, argv, envp)
+ * kernel_execve(path, argv, envp)
*/
.align 4
- .globl execve
- .ent execve
-execve:
+ .globl kernel_execve
+ .ent kernel_execve
+kernel_execve:
/* We can be called from a module. */
ldgp $gp, 0($27)
lda $sp, -(32+SIZEOF_PT_REGS+8)($sp)
@@ -704,7 +704,7 @@ execve:
1: lda $sp, 32+SIZEOF_PT_REGS+8($sp)
ret
-.end execve
+.end kernel_execve
/*
diff --git a/arch/alpha/kernel/err_ev6.c b/arch/alpha/kernel/err_ev6.c
index 64f59f2fcf5c..69b5f4ea7355 100644
--- a/arch/alpha/kernel/err_ev6.c
+++ b/arch/alpha/kernel/err_ev6.c
@@ -11,6 +11,7 @@
#include <linux/sched.h>
#include <asm/io.h>
+#include <asm/irq_regs.h>
#include <asm/hwrpb.h>
#include <asm/smp.h>
#include <asm/err_common.h>
@@ -229,7 +230,7 @@ ev6_process_logout_frame(struct el_common *mchk_header, int print)
}
void
-ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+ev6_machine_check(u64 vector, u64 la_ptr)
{
struct el_common *mchk_header = (struct el_common *)la_ptr;
@@ -260,7 +261,7 @@ ev6_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
(unsigned int)vector, (int)smp_processor_id());
ev6_process_logout_frame(mchk_header, 1);
- dik_show_regs(regs, NULL);
+ dik_show_regs(get_irq_regs(), NULL);
err_print_prefix = saved_err_prefix;
}
diff --git a/arch/alpha/kernel/err_ev7.c b/arch/alpha/kernel/err_ev7.c
index fed6b3d1b803..95463ab1cf35 100644
--- a/arch/alpha/kernel/err_ev7.c
+++ b/arch/alpha/kernel/err_ev7.c
@@ -118,7 +118,7 @@ ev7_collect_logout_frame_subpackets(struct el_subpacket *el_ptr,
}
void
-ev7_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+ev7_machine_check(u64 vector, u64 la_ptr)
{
struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
char *saved_err_prefix = err_print_prefix;
diff --git a/arch/alpha/kernel/err_impl.h b/arch/alpha/kernel/err_impl.h
index 64e9b73809fa..3c12258158e6 100644
--- a/arch/alpha/kernel/err_impl.h
+++ b/arch/alpha/kernel/err_impl.h
@@ -60,26 +60,26 @@ extern struct ev7_lf_subpackets *
ev7_collect_logout_frame_subpackets(struct el_subpacket *,
struct ev7_lf_subpackets *);
extern void ev7_register_error_handlers(void);
-extern void ev7_machine_check(u64, u64, struct pt_regs *);
+extern void ev7_machine_check(u64, u64);
/*
* err_ev6.c
*/
extern void ev6_register_error_handlers(void);
extern int ev6_process_logout_frame(struct el_common *, int);
-extern void ev6_machine_check(u64, u64, struct pt_regs *);
+extern void ev6_machine_check(u64, u64);
/*
* err_marvel.c
*/
-extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_machine_check(u64, u64);
extern void marvel_register_error_handlers(void);
/*
* err_titan.c
*/
extern int titan_process_logout_frame(struct el_common *, int);
-extern void titan_machine_check(u64, u64, struct pt_regs *);
+extern void titan_machine_check(u64, u64);
extern void titan_register_error_handlers(void);
extern int privateer_process_logout_frame(struct el_common *, int);
-extern void privateer_machine_check(u64, u64, struct pt_regs *);
+extern void privateer_machine_check(u64, u64);
diff --git a/arch/alpha/kernel/err_marvel.c b/arch/alpha/kernel/err_marvel.c
index 70b38b1d2af3..f2956ac8dccc 100644
--- a/arch/alpha/kernel/err_marvel.c
+++ b/arch/alpha/kernel/err_marvel.c
@@ -1042,7 +1042,7 @@ marvel_process_logout_frame(struct ev7_lf_subpackets *lf_subpackets, int print)
}
void
-marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+marvel_machine_check(u64 vector, u64 la_ptr)
{
struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr;
int (*process_frame)(struct ev7_lf_subpackets *, int) = NULL;
@@ -1077,7 +1077,7 @@ marvel_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
default:
/* Don't know it - pass it up. */
- ev7_machine_check(vector, la_ptr, regs);
+ ev7_machine_check(vector, la_ptr);
return;
}
diff --git a/arch/alpha/kernel/err_titan.c b/arch/alpha/kernel/err_titan.c
index 7e6720d45f02..febe71c6869f 100644
--- a/arch/alpha/kernel/err_titan.c
+++ b/arch/alpha/kernel/err_titan.c
@@ -379,7 +379,7 @@ titan_process_logout_frame(struct el_common *mchk_header, int print)
}
void
-titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+titan_machine_check(u64 vector, u64 la_ptr)
{
struct el_common *mchk_header = (struct el_common *)la_ptr;
struct el_TITAN_sysdata_mcheck *tmchk =
@@ -408,7 +408,7 @@ titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
* Only handle system errors here
*/
if ((vector != SCB_Q_SYSMCHK) && (vector != SCB_Q_SYSERR)) {
- ev6_machine_check(vector, la_ptr, regs);
+ ev6_machine_check(vector, la_ptr);
return;
}
@@ -442,7 +442,7 @@ titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
#ifdef CONFIG_VERBOSE_MCHECK
titan_process_logout_frame(mchk_header, alpha_verbose_mcheck);
if (alpha_verbose_mcheck)
- dik_show_regs(regs, NULL);
+ dik_show_regs(get_irq_regs(), NULL);
#endif /* CONFIG_VERBOSE_MCHECK */
err_print_prefix = saved_err_prefix;
@@ -452,7 +452,7 @@ titan_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
* machine checks to interrupts
*/
irqmask = tmchk->c_dirx & TITAN_MCHECK_INTERRUPT_MASK;
- titan_dispatch_irqs(irqmask, regs);
+ titan_dispatch_irqs(irqmask);
}
@@ -701,7 +701,7 @@ privateer_process_logout_frame(struct el_common *mchk_header, int print)
}
void
-privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
+privateer_machine_check(u64 vector, u64 la_ptr)
{
struct el_common *mchk_header = (struct el_common *)la_ptr;
struct el_TITAN_sysdata_mcheck *tmchk =
@@ -723,7 +723,7 @@ privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
* Only handle system events here.
*/
if (vector != SCB_Q_SYSEVENT)
- return titan_machine_check(vector, la_ptr, regs);
+ return titan_machine_check(vector, la_ptr);
/*
* Report the event - System Events should be reported even if no
@@ -746,7 +746,7 @@ privateer_machine_check(u64 vector, u64 la_ptr, struct pt_regs *regs)
/*
* Dispatch the interrupt(s).
*/
- titan_dispatch_irqs(irqmask, regs);
+ titan_dispatch_irqs(irqmask);
/*
* Release the logout frame.
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index 1e2a62a1f75f..e27d23c74ba8 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -1,5 +1,5 @@
/*
- * alpha/boot/head.S
+ * arch/alpha/kernel/head.S
*
* initial boot stuff.. At this point, the bootloader has already
* switched into OSF/1 PAL-code, and loaded us at the correct address
diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
index 729c475d2269..facf82a5499a 100644
--- a/arch/alpha/kernel/irq.c
+++ b/arch/alpha/kernel/irq.c
@@ -127,7 +127,7 @@ unlock:
#define MAX_ILLEGAL_IRQS 16
void
-handle_irq(int irq, struct pt_regs * regs)
+handle_irq(int irq)
{
/*
* We ack quickly, we don't want the irq controller
@@ -157,6 +157,6 @@ handle_irq(int irq, struct pt_regs * regs)
* at IPL 0.
*/
local_irq_disable();
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
irq_exit();
}
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index ddf5cf8dcb0b..e16aeb6e79ef 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -6,6 +6,7 @@
#include <linux/sched.h>
#include <linux/irq.h>
#include <linux/kernel_stat.h>
+#include <linux/module.h>
#include <asm/machvec.h>
#include <asm/dma.h>
@@ -16,6 +17,7 @@
/* Hack minimum IPL during interrupt processing for broken hardware. */
#ifdef CONFIG_ALPHA_BROKEN_IRQ_MASK
int __min_ipl;
+EXPORT_SYMBOL(__min_ipl);
#endif
/*
@@ -30,6 +32,7 @@ dummy_perf(unsigned long vector, struct pt_regs *regs)
}
void (*perf_irq)(unsigned long, struct pt_regs *) = dummy_perf;
+EXPORT_SYMBOL(perf_irq);
/*
* The main interrupt entry point.
@@ -39,6 +42,7 @@ asmlinkage void
do_entInt(unsigned long type, unsigned long vector,
unsigned long la_ptr, struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
switch (type) {
case 0:
#ifdef CONFIG_SMP
@@ -51,6 +55,7 @@ do_entInt(unsigned long type, unsigned long vector,
#endif
break;
case 1:
+ old_regs = set_irq_regs(regs);
#ifdef CONFIG_SMP
{
long cpu;
@@ -61,18 +66,23 @@ do_entInt(unsigned long type, unsigned long vector,
if (cpu != boot_cpuid) {
kstat_cpu(cpu).irqs[RTC_IRQ]++;
} else {
- handle_irq(RTC_IRQ, regs);
+ handle_irq(RTC_IRQ);
}
}
#else
- handle_irq(RTC_IRQ, regs);
+ handle_irq(RTC_IRQ);
#endif
+ set_irq_regs(old_regs);
return;
case 2:
- alpha_mv.machine_check(vector, la_ptr, regs);
+ old_regs = set_irq_regs(regs);
+ alpha_mv.machine_check(vector, la_ptr);
+ set_irq_regs(old_regs);
return;
case 3:
- alpha_mv.device_interrupt(vector, regs);
+ old_regs = set_irq_regs(regs);
+ alpha_mv.device_interrupt(vector);
+ set_irq_regs(old_regs);
return;
case 4:
perf_irq(la_ptr, regs);
@@ -120,8 +130,7 @@ struct mcheck_info __mcheck_info;
void
process_mcheck_info(unsigned long vector, unsigned long la_ptr,
- struct pt_regs *regs, const char *machine,
- int expected)
+ const char *machine, int expected)
{
struct el_common *mchk_header;
const char *reason;
@@ -148,7 +157,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
mchk_header = (struct el_common *)la_ptr;
printk(KERN_CRIT "%s machine check: vector=0x%lx pc=0x%lx code=0x%x\n",
- machine, vector, regs->pc, mchk_header->code);
+ machine, vector, get_irq_regs()->pc, mchk_header->code);
switch (mchk_header->code) {
/* Machine check reasons. Defined according to PALcode sources. */
@@ -189,7 +198,7 @@ process_mcheck_info(unsigned long vector, unsigned long la_ptr,
printk(KERN_CRIT "machine check type: %s%s\n",
reason, mchk_header->retry ? " (retryable)" : "");
- dik_show_regs(regs, NULL);
+ dik_show_regs(get_irq_regs(), NULL);
#ifdef CONFIG_VERBOSE_MCHECK
if (alpha_verbose_mcheck > 1) {
diff --git a/arch/alpha/kernel/irq_i8259.c b/arch/alpha/kernel/irq_i8259.c
index ebbadbc0c36a..9405bee9894e 100644
--- a/arch/alpha/kernel/irq_i8259.c
+++ b/arch/alpha/kernel/irq_i8259.c
@@ -137,7 +137,7 @@ init_i8259a_irqs(void)
#if defined(IACK_SC)
void
-isa_device_interrupt(unsigned long vector, struct pt_regs *regs)
+isa_device_interrupt(unsigned long vector)
{
/*
* Generate a PCI interrupt acknowledge cycle. The PIC will
@@ -147,13 +147,13 @@ isa_device_interrupt(unsigned long vector, struct pt_regs *regs)
*/
int j = *(vuip) IACK_SC;
j &= 0xff;
- handle_irq(j, regs);
+ handle_irq(j);
}
#endif
#if defined(CONFIG_ALPHA_GENERIC) || !defined(IACK_SC)
void
-isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs)
+isa_no_iack_sc_device_interrupt(unsigned long vector)
{
unsigned long pic;
@@ -176,7 +176,7 @@ isa_no_iack_sc_device_interrupt(unsigned long vector, struct pt_regs *regs)
while (pic) {
int j = ffz(~pic);
pic &= pic - 1;
- handle_irq(j, regs);
+ handle_irq(j);
}
}
#endif
diff --git a/arch/alpha/kernel/irq_impl.h b/arch/alpha/kernel/irq_impl.h
index f201d8ffc0d9..cc9a8a7aa279 100644
--- a/arch/alpha/kernel/irq_impl.h
+++ b/arch/alpha/kernel/irq_impl.h
@@ -15,10 +15,10 @@
#define RTC_IRQ 8
-extern void isa_device_interrupt(unsigned long, struct pt_regs *);
-extern void isa_no_iack_sc_device_interrupt(unsigned long, struct pt_regs *);
-extern void srm_device_interrupt(unsigned long, struct pt_regs *);
-extern void pyxis_device_interrupt(unsigned long, struct pt_regs *);
+extern void isa_device_interrupt(unsigned long);
+extern void isa_no_iack_sc_device_interrupt(unsigned long);
+extern void srm_device_interrupt(unsigned long);
+extern void pyxis_device_interrupt(unsigned long);
extern struct irqaction timer_irqaction;
extern struct irqaction isa_cascade_irqaction;
@@ -39,4 +39,4 @@ extern void i8259a_end_irq(unsigned int);
extern struct hw_interrupt_type i8259a_irq_type;
extern void init_i8259a_irqs(void);
-extern void handle_irq(int irq, struct pt_regs * regs);
+extern void handle_irq(int irq);
diff --git a/arch/alpha/kernel/irq_pyxis.c b/arch/alpha/kernel/irq_pyxis.c
index 3b581415bab0..d53edbccbfe5 100644
--- a/arch/alpha/kernel/irq_pyxis.c
+++ b/arch/alpha/kernel/irq_pyxis.c
@@ -81,7 +81,7 @@ static struct hw_interrupt_type pyxis_irq_type = {
};
void
-pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
+pyxis_device_interrupt(unsigned long vector)
{
unsigned long pld;
unsigned int i;
@@ -98,9 +98,9 @@ pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i == 7)
- isa_device_interrupt(vector, regs);
+ isa_device_interrupt(vector);
else
- handle_irq(16+i, regs);
+ handle_irq(16+i);
}
}
diff --git a/arch/alpha/kernel/irq_srm.c b/arch/alpha/kernel/irq_srm.c
index 8e4d121f84cc..32212014fbe9 100644
--- a/arch/alpha/kernel/irq_srm.c
+++ b/arch/alpha/kernel/irq_srm.c
@@ -72,8 +72,8 @@ init_srm_irqs(long max, unsigned long ignore_mask)
}
void
-srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+srm_device_interrupt(unsigned long vector)
{
int irq = (vector - 0x800) >> 4;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
diff --git a/arch/alpha/kernel/machvec_impl.h b/arch/alpha/kernel/machvec_impl.h
index 08b8302e64ca..0caa45aa128d 100644
--- a/arch/alpha/kernel/machvec_impl.h
+++ b/arch/alpha/kernel/machvec_impl.h
@@ -1,5 +1,5 @@
/*
- * linux/arch/alpha/kernel/machvec.h
+ * linux/arch/alpha/kernel/machvec_impl.h
*
* Copyright (C) 1997, 1998 Richard Henderson
*
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 73c7622b5297..ad6173651995 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -111,22 +111,26 @@ struct osf_dirent_callback {
static int
osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
- ino_t ino, unsigned int d_type)
+ u64 ino, unsigned int d_type)
{
struct osf_dirent __user *dirent;
struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1);
+ unsigned int d_ino;
buf->error = -EINVAL; /* only used if we fail */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
if (buf->basep) {
if (put_user(offset, buf->basep))
return -EFAULT;
buf->basep = NULL;
}
dirent = buf->dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(namlen, &dirent->d_namlen);
put_user(reclen, &dirent->d_reclen);
if (copy_to_user(dirent->d_name, name, namlen) ||
@@ -402,15 +406,15 @@ osf_utsname(char __user *name)
down_read(&uts_sem);
error = -EFAULT;
- if (copy_to_user(name + 0, system_utsname.sysname, 32))
+ if (copy_to_user(name + 0, utsname()->sysname, 32))
goto out;
- if (copy_to_user(name + 32, system_utsname.nodename, 32))
+ if (copy_to_user(name + 32, utsname()->nodename, 32))
goto out;
- if (copy_to_user(name + 64, system_utsname.release, 32))
+ if (copy_to_user(name + 64, utsname()->release, 32))
goto out;
- if (copy_to_user(name + 96, system_utsname.version, 32))
+ if (copy_to_user(name + 96, utsname()->version, 32))
goto out;
- if (copy_to_user(name + 128, system_utsname.machine, 32))
+ if (copy_to_user(name + 128, utsname()->machine, 32))
goto out;
error = 0;
@@ -449,8 +453,8 @@ osf_getdomainname(char __user *name, int namelen)
down_read(&uts_sem);
for (i = 0; i < len; ++i) {
- __put_user(system_utsname.domainname[i], name + i);
- if (system_utsname.domainname[i] == '\0')
+ __put_user(utsname()->domainname[i], name + i);
+ if (utsname()->domainname[i] == '\0')
break;
}
up_read(&uts_sem);
@@ -607,12 +611,12 @@ osf_sigstack(struct sigstack __user *uss, struct sigstack __user *uoss)
asmlinkage long
osf_sysinfo(int command, char __user *buf, long count)
{
- static char * sysinfo_table[] = {
- system_utsname.sysname,
- system_utsname.nodename,
- system_utsname.release,
- system_utsname.version,
- system_utsname.machine,
+ char *sysinfo_table[] = {
+ utsname()->sysname,
+ utsname()->nodename,
+ utsname()->release,
+ utsname()->version,
+ utsname()->machine,
"alpha", /* instruction set architecture */
"dummy", /* hardware serial number */
"dummy", /* hardware manufacturer */
diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c
index fff5cf93e816..174b729c504b 100644
--- a/arch/alpha/kernel/pci-noop.c
+++ b/arch/alpha/kernel/pci-noop.c
@@ -201,6 +201,7 @@ dma_set_mask(struct device *dev, u64 mask)
return 0;
}
+EXPORT_SYMBOL(dma_set_mask);
void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
{
diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c
index c468e312e5f8..6e7d1fe6e935 100644
--- a/arch/alpha/kernel/pci_iommu.c
+++ b/arch/alpha/kernel/pci_iommu.c
@@ -300,6 +300,7 @@ pci_map_single(struct pci_dev *pdev, void *cpu_addr, size_t size, int dir)
dac_allowed = pdev ? pci_dac_dma_supported(pdev, pdev->dma_mask) : 0;
return pci_map_single_1(pdev, cpu_addr, size, dac_allowed);
}
+EXPORT_SYMBOL(pci_map_single);
dma_addr_t
pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset,
@@ -314,6 +315,7 @@ pci_map_page(struct pci_dev *pdev, struct page *page, unsigned long offset,
return pci_map_single_1(pdev, (char *)page_address(page) + offset,
size, dac_allowed);
}
+EXPORT_SYMBOL(pci_map_page);
/* Unmap a single streaming mode DMA translation. The DMA_ADDR and
SIZE must match what was provided for in a previous pci_map_single
@@ -379,6 +381,7 @@ pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, size_t size,
DBGA2("pci_unmap_single: sg [%lx,%lx] np %ld from %p\n",
dma_addr, size, npages, __builtin_return_address(0));
}
+EXPORT_SYMBOL(pci_unmap_single);
void
pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr,
@@ -386,6 +389,7 @@ pci_unmap_page(struct pci_dev *pdev, dma_addr_t dma_addr,
{
pci_unmap_single(pdev, dma_addr, size, direction);
}
+EXPORT_SYMBOL(pci_unmap_page);
/* Allocate and map kernel buffer using consistent mode DMA for PCI
device. Returns non-NULL cpu-view pointer to the buffer if
@@ -427,6 +431,7 @@ try_again:
return cpu_addr;
}
+EXPORT_SYMBOL(pci_alloc_consistent);
/* Free and unmap a consistent DMA buffer. CPU_ADDR and DMA_ADDR must
be values that were returned from pci_alloc_consistent. SIZE must
@@ -444,7 +449,7 @@ pci_free_consistent(struct pci_dev *pdev, size_t size, void *cpu_addr,
DBGA2("pci_free_consistent: [%x,%lx] from %p\n",
dma_addr, size, __builtin_return_address(0));
}
-
+EXPORT_SYMBOL(pci_free_consistent);
/* Classify the elements of the scatterlist. Write dma_address
of each element with:
@@ -672,6 +677,7 @@ pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
pci_unmap_sg(pdev, start, out - start, direction);
return 0;
}
+EXPORT_SYMBOL(pci_map_sg);
/* Unmap a set of streaming mode DMA translations. Again, cpu read
rules concerning calls here are the same as for pci_unmap_single()
@@ -752,6 +758,7 @@ pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
DBGA("pci_unmap_sg: %ld entries\n", nents - (end - sg));
}
+EXPORT_SYMBOL(pci_unmap_sg);
/* Return whether the given PCI device DMA address mask can be
@@ -786,6 +793,7 @@ pci_dma_supported(struct pci_dev *pdev, u64 mask)
return 0;
}
+EXPORT_SYMBOL(pci_dma_supported);
/*
@@ -908,6 +916,7 @@ pci_dac_dma_supported(struct pci_dev *dev, u64 mask)
return ok;
}
+EXPORT_SYMBOL(pci_dac_dma_supported);
dma64_addr_t
pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page,
@@ -917,6 +926,7 @@ pci_dac_page_to_dma(struct pci_dev *pdev, struct page *page,
+ __pa(page_address(page))
+ (dma64_addr_t) offset);
}
+EXPORT_SYMBOL(pci_dac_page_to_dma);
struct page *
pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
@@ -924,13 +934,14 @@ pci_dac_dma_to_page(struct pci_dev *pdev, dma64_addr_t dma_addr)
unsigned long paddr = (dma_addr & PAGE_MASK) - alpha_mv.pci_dac_offset;
return virt_to_page(__va(paddr));
}
+EXPORT_SYMBOL(pci_dac_dma_to_page);
unsigned long
pci_dac_dma_to_offset(struct pci_dev *pdev, dma64_addr_t dma_addr)
{
return (dma_addr & ~PAGE_MASK);
}
-
+EXPORT_SYMBOL(pci_dac_dma_to_offset);
/* Helper for generic DMA-mapping functions. */
@@ -957,6 +968,7 @@ alpha_gendev_to_pci(struct device *dev)
/* This assumes ISA bus master with dma_mask 0xffffff. */
return NULL;
}
+EXPORT_SYMBOL(alpha_gendev_to_pci);
int
dma_set_mask(struct device *dev, u64 mask)
@@ -969,3 +981,4 @@ dma_set_mask(struct device *dev, u64 mask)
return 0;
}
+EXPORT_SYMBOL(dma_set_mask);
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
index b3a8a2980365..3370e6faeae0 100644
--- a/arch/alpha/kernel/process.c
+++ b/arch/alpha/kernel/process.c
@@ -205,6 +205,7 @@ start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
regs->ps = 8;
wrusp(sp);
}
+EXPORT_SYMBOL(start_thread);
/*
* Free current thread data structures etc..
@@ -376,6 +377,7 @@ dump_thread(struct pt_regs * pt, struct user * dump)
dump->regs[EF_A2] = pt->r18;
memcpy((char *)dump->regs + EF_SIZE, sw->fp, 32 * 8);
}
+EXPORT_SYMBOL(dump_thread);
/*
* Fill in the user structure for a ELF core dump.
@@ -424,6 +426,7 @@ dump_elf_thread(elf_greg_t *dest, struct pt_regs *pt, struct thread_info *ti)
useful value of the thread's UNIQUE field. */
dest[32] = ti->pcb.unique;
}
+EXPORT_SYMBOL(dump_elf_thread);
int
dump_elf_task(elf_greg_t *dest, struct task_struct *task)
@@ -431,6 +434,7 @@ dump_elf_task(elf_greg_t *dest, struct task_struct *task)
dump_elf_thread(dest, task_pt_regs(task), task_thread_info(task));
return 1;
}
+EXPORT_SYMBOL(dump_elf_task);
int
dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
@@ -439,6 +443,7 @@ dump_elf_task_fp(elf_fpreg_t *dest, struct task_struct *task)
memcpy(dest, sw->fp, 32 * 8);
return 1;
}
+EXPORT_SYMBOL(dump_elf_task_fp);
/*
* sys_execve() executes a new program.
diff --git a/arch/alpha/kernel/proto.h b/arch/alpha/kernel/proto.h
index 2a6e3da8144f..95912ecc65e1 100644
--- a/arch/alpha/kernel/proto.h
+++ b/arch/alpha/kernel/proto.h
@@ -1,5 +1,7 @@
#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/pgtable.h>
/* Prototypes of functions used across modules here in this directory. */
@@ -18,7 +20,7 @@ struct pci_controller;
extern struct pci_ops apecs_pci_ops;
extern void apecs_init_arch(void);
extern void apecs_pci_clr_err(void);
-extern void apecs_machine_check(u64, u64, struct pt_regs *);
+extern void apecs_machine_check(u64, u64);
extern void apecs_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
/* core_cia.c */
@@ -27,27 +29,27 @@ extern void cia_init_pci(void);
extern void cia_init_arch(void);
extern void pyxis_init_arch(void);
extern void cia_kill_arch(int);
-extern void cia_machine_check(u64, u64, struct pt_regs *);
+extern void cia_machine_check(u64, u64);
extern void cia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
/* core_irongate.c */
extern struct pci_ops irongate_pci_ops;
extern int irongate_pci_clr_err(void);
extern void irongate_init_arch(void);
-extern void irongate_machine_check(u64, u64, struct pt_regs *);
+extern void irongate_machine_check(u64, u64);
#define irongate_pci_tbi ((void *)0)
/* core_lca.c */
extern struct pci_ops lca_pci_ops;
extern void lca_init_arch(void);
-extern void lca_machine_check(u64, u64, struct pt_regs *);
+extern void lca_machine_check(u64, u64);
extern void lca_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
/* core_marvel.c */
extern struct pci_ops marvel_pci_ops;
extern void marvel_init_arch(void);
extern void marvel_kill_arch(int);
-extern void marvel_machine_check(u64, u64, struct pt_regs *);
+extern void marvel_machine_check(u64, u64);
extern void marvel_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
extern int marvel_pa_to_nid(unsigned long);
extern int marvel_cpuid_to_nid(int);
@@ -62,7 +64,7 @@ void io7_clear_errors(struct io7 *io7);
extern struct pci_ops mcpcia_pci_ops;
extern void mcpcia_init_arch(void);
extern void mcpcia_init_hoses(void);
-extern void mcpcia_machine_check(u64, u64, struct pt_regs *);
+extern void mcpcia_machine_check(u64, u64);
extern void mcpcia_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
/* core_polaris.c */
@@ -70,21 +72,21 @@ extern struct pci_ops polaris_pci_ops;
extern int polaris_read_config_dword(struct pci_dev *, int, u32 *);
extern int polaris_write_config_dword(struct pci_dev *, int, u32);
extern void polaris_init_arch(void);
-extern void polaris_machine_check(u64, u64, struct pt_regs *);
+extern void polaris_machine_check(u64, u64);
#define polaris_pci_tbi ((void *)0)
/* core_t2.c */
extern struct pci_ops t2_pci_ops;
extern void t2_init_arch(void);
extern void t2_kill_arch(int);
-extern void t2_machine_check(u64, u64, struct pt_regs *);
+extern void t2_machine_check(u64, u64);
extern void t2_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
/* core_titan.c */
extern struct pci_ops titan_pci_ops;
extern void titan_init_arch(void);
extern void titan_kill_arch(int);
-extern void titan_machine_check(u64, u64, struct pt_regs *);
+extern void titan_machine_check(u64, u64);
extern void titan_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
extern struct _alpha_agp_info *titan_agp_info(void);
@@ -92,14 +94,14 @@ extern struct _alpha_agp_info *titan_agp_info(void);
extern struct pci_ops tsunami_pci_ops;
extern void tsunami_init_arch(void);
extern void tsunami_kill_arch(int);
-extern void tsunami_machine_check(u64, u64, struct pt_regs *);
+extern void tsunami_machine_check(u64, u64);
extern void tsunami_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
/* core_wildfire.c */
extern struct pci_ops wildfire_pci_ops;
extern void wildfire_init_arch(void);
extern void wildfire_kill_arch(int);
-extern void wildfire_machine_check(u64, u64, struct pt_regs *);
+extern void wildfire_machine_check(u64, u64);
extern void wildfire_pci_tbi(struct pci_controller *, dma_addr_t, dma_addr_t);
extern int wildfire_pa_to_nid(unsigned long);
extern int wildfire_cpuid_to_nid(int);
@@ -131,7 +133,7 @@ extern void smp_percpu_timer_interrupt(struct pt_regs *);
/* extern void reset_for_srm(void); */
/* time.c */
-extern irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs);
+extern irqreturn_t timer_interrupt(int irq, void *dev);
extern void common_init_rtc(void);
extern unsigned long est_cycle_freq;
@@ -175,15 +177,22 @@ extern void dik_show_regs(struct pt_regs *regs, unsigned long *r9_15);
extern void die_if_kernel(char *, struct pt_regs *, long, unsigned long *);
/* sys_titan.c */
-extern void titan_dispatch_irqs(u64, struct pt_regs *);
+extern void titan_dispatch_irqs(u64);
/* ../mm/init.c */
extern void switch_to_system_map(void);
extern void srm_paging_stop(void);
-/* ../mm/remap.c */
-extern int __alpha_remap_area_pages(unsigned long, unsigned long,
- unsigned long, unsigned long);
+static inline int
+__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
+ unsigned long size, unsigned long flags)
+{
+ pgprot_t prot;
+
+ prot = __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE
+ | _PAGE_KWE | flags);
+ return ioremap_page_range(address, address + size, phys_addr, prot);
+}
/* irq.c */
@@ -205,5 +214,4 @@ extern struct mcheck_info
#endif
extern void process_mcheck_info(unsigned long vector, unsigned long la_ptr,
- struct pt_regs *regs, const char *machine,
- int expected);
+ const char *machine, int expected);
diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c
index fd4a8fa0c93d..1aea7c7c683c 100644
--- a/arch/alpha/kernel/setup.c
+++ b/arch/alpha/kernel/setup.c
@@ -21,7 +21,6 @@
#include <linux/a.out.h>
#include <linux/screen_info.h>
#include <linux/delay.h>
-#include <linux/config.h> /* CONFIG_ALPHA_LCA etc */
#include <linux/mc146818rtc.h>
#include <linux/console.h>
#include <linux/cpu.h>
@@ -67,6 +66,7 @@ static struct notifier_block alpha_panic_block = {
struct hwrpb_struct *hwrpb;
+EXPORT_SYMBOL(hwrpb);
unsigned long srm_hae;
int alpha_l1i_cacheshape;
@@ -112,6 +112,7 @@ unsigned long alpha_agpgart_size = DEFAULT_AGP_APER_SIZE;
#ifdef CONFIG_ALPHA_GENERIC
struct alpha_machine_vector alpha_mv;
int alpha_using_srm;
+EXPORT_SYMBOL(alpha_using_srm);
#endif
static struct alpha_machine_vector *get_sysvec(unsigned long, unsigned long,
@@ -138,6 +139,8 @@ struct screen_info screen_info = {
.orig_video_points = 16
};
+EXPORT_SYMBOL(screen_info);
+
/*
* The direct map I/O window, if any. This should be the same
* for all busses, since it's used by virt_to_bus.
@@ -145,6 +148,8 @@ struct screen_info screen_info = {
unsigned long __direct_map_base;
unsigned long __direct_map_size;
+EXPORT_SYMBOL(__direct_map_base);
+EXPORT_SYMBOL(__direct_map_size);
/*
* Declare all of the machine vectors.
diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
index 4dc273e537fd..d1ec4f51df1a 100644
--- a/arch/alpha/kernel/smp.c
+++ b/arch/alpha/kernel/smp.c
@@ -52,6 +52,7 @@
/* A collection of per-processor data. */
struct cpuinfo_alpha cpu_data[NR_CPUS];
+EXPORT_SYMBOL(cpu_data);
/* A collection of single bit ipi messages. */
static struct {
@@ -74,6 +75,7 @@ EXPORT_SYMBOL(cpu_online_map);
int smp_num_probed; /* Internal processor count */
int smp_num_cpus = 1; /* Number that came online. */
+EXPORT_SYMBOL(smp_num_cpus);
extern void calibrate_delay(void);
@@ -515,12 +517,15 @@ smp_cpus_done(unsigned int max_cpus)
void
smp_percpu_timer_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
int cpu = smp_processor_id();
unsigned long user = user_mode(regs);
struct cpuinfo_alpha *data = &cpu_data[cpu];
+ old_regs = set_irq_regs(regs);
+
/* Record kernel PC. */
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
if (!--data->prof_counter) {
/* We need to make like a normal interrupt -- otherwise
@@ -534,6 +539,7 @@ smp_percpu_timer_interrupt(struct pt_regs *regs)
irq_exit();
}
+ set_irq_regs(old_regs);
}
int __init
@@ -786,6 +792,7 @@ smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry,
return 0;
}
+EXPORT_SYMBOL(smp_call_function_on_cpu);
int
smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
@@ -793,6 +800,7 @@ smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
return smp_call_function_on_cpu (func, info, retry, wait,
cpu_online_map);
}
+EXPORT_SYMBOL(smp_call_function);
static void
ipi_imb(void *ignored)
@@ -807,6 +815,7 @@ smp_imb(void)
if (on_each_cpu(ipi_imb, NULL, 1, 1))
printk(KERN_CRIT "smp_imb: timed out\n");
}
+EXPORT_SYMBOL(smp_imb);
static void
ipi_flush_tlb_all(void *ignored)
@@ -862,6 +871,7 @@ flush_tlb_mm(struct mm_struct *mm)
preempt_enable();
}
+EXPORT_SYMBOL(flush_tlb_mm);
struct flush_tlb_page_struct {
struct vm_area_struct *vma;
@@ -914,6 +924,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long addr)
preempt_enable();
}
+EXPORT_SYMBOL(flush_tlb_page);
void
flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
@@ -921,6 +932,7 @@ flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long e
/* On the Alpha we always flush the whole user tlb. */
flush_tlb_mm(vma->vm_mm);
}
+EXPORT_SYMBOL(flush_tlb_range);
static void
ipi_flush_icache_page(void *x)
diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c
index 9d7dff27f815..756923203860 100644
--- a/arch/alpha/kernel/srmcons.c
+++ b/arch/alpha/kernel/srmcons.c
@@ -229,7 +229,7 @@ srmcons_close(struct tty_struct *tty, struct file *filp)
static struct tty_driver *srmcons_driver;
-static struct tty_operations srmcons_ops = {
+static const struct tty_operations srmcons_ops = {
.open = srmcons_open,
.close = srmcons_close,
.write = srmcons_write,
diff --git a/arch/alpha/kernel/sys_alcor.c b/arch/alpha/kernel/sys_alcor.c
index d6926b7b1e99..49bedfbbd31b 100644
--- a/arch/alpha/kernel/sys_alcor.c
+++ b/arch/alpha/kernel/sys_alcor.c
@@ -100,7 +100,7 @@ static struct hw_interrupt_type alcor_irq_type = {
};
static void
-alcor_device_interrupt(unsigned long vector, struct pt_regs *regs)
+alcor_device_interrupt(unsigned long vector)
{
unsigned long pld;
unsigned int i;
@@ -116,9 +116,9 @@ alcor_device_interrupt(unsigned long vector, struct pt_regs *regs)
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i == 31) {
- isa_device_interrupt(vector, regs);
+ isa_device_interrupt(vector);
} else {
- handle_irq(16 + i, regs);
+ handle_irq(16 + i);
}
}
}
diff --git a/arch/alpha/kernel/sys_cabriolet.c b/arch/alpha/kernel/sys_cabriolet.c
index 25a215067da8..ace475c124f6 100644
--- a/arch/alpha/kernel/sys_cabriolet.c
+++ b/arch/alpha/kernel/sys_cabriolet.c
@@ -82,7 +82,7 @@ static struct hw_interrupt_type cabriolet_irq_type = {
};
static void
-cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
+cabriolet_device_interrupt(unsigned long v)
{
unsigned long pld;
unsigned int i;
@@ -98,15 +98,15 @@ cabriolet_device_interrupt(unsigned long v, struct pt_regs *r)
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i == 4) {
- isa_device_interrupt(v, r);
+ isa_device_interrupt(v);
} else {
- handle_irq(16 + i, r);
+ handle_irq(16 + i);
}
}
}
static void __init
-common_init_irq(void (*srm_dev_int)(unsigned long v, struct pt_regs *r))
+common_init_irq(void (*srm_dev_int)(unsigned long v))
{
init_i8259a_irqs();
@@ -154,18 +154,18 @@ cabriolet_init_irq(void)
too invasive though. */
static void
-pc164_srm_device_interrupt(unsigned long v, struct pt_regs *r)
+pc164_srm_device_interrupt(unsigned long v)
{
__min_ipl = getipl();
- srm_device_interrupt(v, r);
+ srm_device_interrupt(v);
__min_ipl = 0;
}
static void
-pc164_device_interrupt(unsigned long v, struct pt_regs *r)
+pc164_device_interrupt(unsigned long v)
{
__min_ipl = getipl();
- cabriolet_device_interrupt(v, r);
+ cabriolet_device_interrupt(v);
__min_ipl = 0;
}
diff --git a/arch/alpha/kernel/sys_dp264.c b/arch/alpha/kernel/sys_dp264.c
index dd6103b867e7..85d2f933dd07 100644
--- a/arch/alpha/kernel/sys_dp264.c
+++ b/arch/alpha/kernel/sys_dp264.c
@@ -217,7 +217,7 @@ static struct hw_interrupt_type clipper_irq_type = {
};
static void
-dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
+dp264_device_interrupt(unsigned long vector)
{
#if 1
printk("dp264_device_interrupt: NOT IMPLEMENTED YET!! \n");
@@ -236,9 +236,9 @@ dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i == 55)
- isa_device_interrupt(vector, regs);
+ isa_device_interrupt(vector);
else
- handle_irq(16 + i, 16 + i, regs);
+ handle_irq(16 + i);
#if 0
TSUNAMI_cchip->dir0.csr = 1UL << i; mb();
tmp = TSUNAMI_cchip->dir0.csr;
@@ -248,7 +248,7 @@ dp264_device_interrupt(unsigned long vector, struct pt_regs * regs)
}
static void
-dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+dp264_srm_device_interrupt(unsigned long vector)
{
int irq;
@@ -268,11 +268,11 @@ dp264_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
if (irq >= 32)
irq -= 16;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void
-clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+clipper_srm_device_interrupt(unsigned long vector)
{
int irq;
@@ -290,7 +290,7 @@ clipper_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
*
* Eg IRQ 24 is DRIR bit 8, etc, etc
*/
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
diff --git a/arch/alpha/kernel/sys_eb64p.c b/arch/alpha/kernel/sys_eb64p.c
index ed108b66ec09..9c5a306dc0ee 100644
--- a/arch/alpha/kernel/sys_eb64p.c
+++ b/arch/alpha/kernel/sys_eb64p.c
@@ -80,7 +80,7 @@ static struct hw_interrupt_type eb64p_irq_type = {
};
static void
-eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
+eb64p_device_interrupt(unsigned long vector)
{
unsigned long pld;
unsigned int i;
@@ -97,9 +97,9 @@ eb64p_device_interrupt(unsigned long vector, struct pt_regs *regs)
pld &= pld - 1; /* clear least bit set */
if (i == 5) {
- isa_device_interrupt(vector, regs);
+ isa_device_interrupt(vector);
} else {
- handle_irq(16 + i, regs);
+ handle_irq(16 + i);
}
}
}
diff --git a/arch/alpha/kernel/sys_eiger.c b/arch/alpha/kernel/sys_eiger.c
index 64a785baf53a..7ef3b6fb3700 100644
--- a/arch/alpha/kernel/sys_eiger.c
+++ b/arch/alpha/kernel/sys_eiger.c
@@ -91,7 +91,7 @@ static struct hw_interrupt_type eiger_irq_type = {
};
static void
-eiger_device_interrupt(unsigned long vector, struct pt_regs * regs)
+eiger_device_interrupt(unsigned long vector)
{
unsigned intstatus;
@@ -118,20 +118,20 @@ eiger_device_interrupt(unsigned long vector, struct pt_regs * regs)
* despatch an interrupt if it's set.
*/
- if (intstatus & 8) handle_irq(16+3, regs);
- if (intstatus & 4) handle_irq(16+2, regs);
- if (intstatus & 2) handle_irq(16+1, regs);
- if (intstatus & 1) handle_irq(16+0, regs);
+ if (intstatus & 8) handle_irq(16+3);
+ if (intstatus & 4) handle_irq(16+2);
+ if (intstatus & 2) handle_irq(16+1);
+ if (intstatus & 1) handle_irq(16+0);
} else {
- isa_device_interrupt(vector, regs);
+ isa_device_interrupt(vector);
}
}
static void
-eiger_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+eiger_srm_device_interrupt(unsigned long vector)
{
int irq = (vector - 0x800) >> 4;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
diff --git a/arch/alpha/kernel/sys_jensen.c b/arch/alpha/kernel/sys_jensen.c
index 4ac2b328b8de..2c3de97de46c 100644
--- a/arch/alpha/kernel/sys_jensen.c
+++ b/arch/alpha/kernel/sys_jensen.c
@@ -129,7 +129,7 @@ static struct hw_interrupt_type jensen_local_irq_type = {
};
static void
-jensen_device_interrupt(unsigned long vector, struct pt_regs * regs)
+jensen_device_interrupt(unsigned long vector)
{
int irq;
@@ -189,7 +189,7 @@ jensen_device_interrupt(unsigned long vector, struct pt_regs * regs)
if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) ||
irq != last_irq) {
printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n",
- irq, count, cc-last_cc, regs->pc);
+ irq, count, cc-last_cc, get_irq_regs()->pc);
count = 0;
last_msg = cc;
last_irq = irq;
@@ -198,7 +198,7 @@ jensen_device_interrupt(unsigned long vector, struct pt_regs * regs)
}
#endif
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
@@ -244,7 +244,7 @@ jensen_init_arch(void)
}
static void
-jensen_machine_check (u64 vector, u64 la, struct pt_regs *regs)
+jensen_machine_check (u64 vector, u64 la)
{
printk(KERN_CRIT "Machine check\n");
}
diff --git a/arch/alpha/kernel/sys_marvel.c b/arch/alpha/kernel/sys_marvel.c
index 36d215954376..e349f03b830e 100644
--- a/arch/alpha/kernel/sys_marvel.c
+++ b/arch/alpha/kernel/sys_marvel.c
@@ -38,7 +38,7 @@
* Interrupt handling.
*/
static void
-io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
+io7_device_interrupt(unsigned long vector)
{
unsigned int pid;
unsigned int irq;
@@ -64,7 +64,7 @@ io7_device_interrupt(unsigned long vector, struct pt_regs * regs)
irq &= MARVEL_IRQ_VEC_IRQ_MASK; /* not too many bits */
irq |= pid << MARVEL_IRQ_VEC_PE_SHIFT; /* merge the pid */
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static volatile unsigned long *
diff --git a/arch/alpha/kernel/sys_miata.c b/arch/alpha/kernel/sys_miata.c
index 61ac56f8eeea..b8b817feb1ee 100644
--- a/arch/alpha/kernel/sys_miata.c
+++ b/arch/alpha/kernel/sys_miata.c
@@ -33,7 +33,7 @@
static void
-miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+miata_srm_device_interrupt(unsigned long vector)
{
int irq;
@@ -56,7 +56,7 @@ miata_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
if (irq >= 16)
irq = irq + 8;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
diff --git a/arch/alpha/kernel/sys_mikasa.c b/arch/alpha/kernel/sys_mikasa.c
index cc4c58111366..8d3e9429c5ee 100644
--- a/arch/alpha/kernel/sys_mikasa.c
+++ b/arch/alpha/kernel/sys_mikasa.c
@@ -79,7 +79,7 @@ static struct hw_interrupt_type mikasa_irq_type = {
};
static void
-mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
+mikasa_device_interrupt(unsigned long vector)
{
unsigned long pld;
unsigned int i;
@@ -97,9 +97,9 @@ mikasa_device_interrupt(unsigned long vector, struct pt_regs *regs)
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i < 16) {
- isa_device_interrupt(vector, regs);
+ isa_device_interrupt(vector);
} else {
- handle_irq(i, regs);
+ handle_irq(i);
}
}
}
@@ -182,8 +182,7 @@ mikasa_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
static void
-mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr)
{
#define MCHK_NO_DEVSEL 0x205U
#define MCHK_NO_TABT 0x204U
@@ -202,7 +201,7 @@ mikasa_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
mb();
code = mchk_header->code;
- process_mcheck_info(vector, la_ptr, regs, "MIKASA APECS",
+ process_mcheck_info(vector, la_ptr, "MIKASA APECS",
(mcheck_expected(0)
&& (code == MCHK_NO_DEVSEL
|| code == MCHK_NO_TABT)));
diff --git a/arch/alpha/kernel/sys_nautilus.c b/arch/alpha/kernel/sys_nautilus.c
index c0d696efec5b..93744bab73fb 100644
--- a/arch/alpha/kernel/sys_nautilus.c
+++ b/arch/alpha/kernel/sys_nautilus.c
@@ -124,8 +124,7 @@ naut_sys_machine_check(unsigned long vector, unsigned long la_ptr,
in the system. They are analysed separately but all starts here. */
void
-nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs *regs)
+nautilus_machine_check(unsigned long vector, unsigned long la_ptr)
{
char *mchk_class;
@@ -165,7 +164,7 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
else if (vector == SCB_Q_SYSMCHK)
mchk_class = "Fatal";
else {
- ev6_machine_check(vector, la_ptr, regs);
+ ev6_machine_check(vector, la_ptr);
return;
}
@@ -173,7 +172,7 @@ nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
"[%s System Machine Check (NMI)]\n",
vector, mchk_class);
- naut_sys_machine_check(vector, la_ptr, regs);
+ naut_sys_machine_check(vector, la_ptr, get_irq_regs());
/* Tell the PALcode to clear the machine check */
draina();
diff --git a/arch/alpha/kernel/sys_noritake.c b/arch/alpha/kernel/sys_noritake.c
index 2d3cff7e8c5f..de6ba3432e8a 100644
--- a/arch/alpha/kernel/sys_noritake.c
+++ b/arch/alpha/kernel/sys_noritake.c
@@ -77,7 +77,7 @@ static struct hw_interrupt_type noritake_irq_type = {
};
static void
-noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
+noritake_device_interrupt(unsigned long vector)
{
unsigned long pld;
unsigned int i;
@@ -96,15 +96,15 @@ noritake_device_interrupt(unsigned long vector, struct pt_regs *regs)
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i < 16) {
- isa_device_interrupt(vector, regs);
+ isa_device_interrupt(vector);
} else {
- handle_irq(i, regs);
+ handle_irq(i);
}
}
}
static void
-noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+noritake_srm_device_interrupt(unsigned long vector)
{
int irq;
@@ -122,7 +122,7 @@ noritake_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
if (irq >= 16)
irq = irq + 1;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
@@ -264,8 +264,7 @@ noritake_swizzle(struct pci_dev *dev, u8 *pinp)
#if defined(CONFIG_ALPHA_GENERIC) || !defined(CONFIG_ALPHA_PRIMO)
static void
-noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
- struct pt_regs * regs)
+noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr)
{
#define MCHK_NO_DEVSEL 0x205U
#define MCHK_NO_TABT 0x204U
@@ -284,7 +283,7 @@ noritake_apecs_machine_check(unsigned long vector, unsigned long la_ptr,
mb();
code = mchk_header->code;
- process_mcheck_info(vector, la_ptr, regs, "NORITAKE APECS",
+ process_mcheck_info(vector, la_ptr, "NORITAKE APECS",
(mcheck_expected(0)
&& (code == MCHK_NO_DEVSEL
|| code == MCHK_NO_TABT)));
diff --git a/arch/alpha/kernel/sys_rawhide.c b/arch/alpha/kernel/sys_rawhide.c
index 949607e3d6fb..581d08c70b92 100644
--- a/arch/alpha/kernel/sys_rawhide.c
+++ b/arch/alpha/kernel/sys_rawhide.c
@@ -134,7 +134,7 @@ static struct hw_interrupt_type rawhide_irq_type = {
};
static void
-rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+rawhide_srm_device_interrupt(unsigned long vector)
{
int irq;
@@ -158,7 +158,7 @@ rawhide_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
/* Adjust by which hose it is from. */
irq -= ((irq + 16) >> 2) & 0x38;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
diff --git a/arch/alpha/kernel/sys_rx164.c b/arch/alpha/kernel/sys_rx164.c
index 6ae506052635..ce1faa6f1df1 100644
--- a/arch/alpha/kernel/sys_rx164.c
+++ b/arch/alpha/kernel/sys_rx164.c
@@ -83,7 +83,7 @@ static struct hw_interrupt_type rx164_irq_type = {
};
static void
-rx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
+rx164_device_interrupt(unsigned long vector)
{
unsigned long pld;
volatile unsigned int *dirr;
@@ -102,9 +102,9 @@ rx164_device_interrupt(unsigned long vector, struct pt_regs *regs)
i = ffz(~pld);
pld &= pld - 1; /* clear least bit set */
if (i == 20) {
- isa_no_iack_sc_device_interrupt(vector, regs);
+ isa_no_iack_sc_device_interrupt(vector);
} else {
- handle_irq(16+i, regs);
+ handle_irq(16+i);
}
}
}
diff --git a/arch/alpha/kernel/sys_sable.c b/arch/alpha/kernel/sys_sable.c
index a7a14647b50e..906019cfa681 100644
--- a/arch/alpha/kernel/sys_sable.c
+++ b/arch/alpha/kernel/sys_sable.c
@@ -512,7 +512,7 @@ static struct hw_interrupt_type sable_lynx_irq_type = {
};
static void
-sable_lynx_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+sable_lynx_srm_device_interrupt(unsigned long vector)
{
/* Note that the vector reported by the SRM PALcode corresponds
to the interrupt mask bits, but we have to manage via the
@@ -526,7 +526,7 @@ sable_lynx_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
printk("%s: vector 0x%lx bit 0x%x irq 0x%x\n",
__FUNCTION__, vector, bit, irq);
#endif
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
diff --git a/arch/alpha/kernel/sys_takara.c b/arch/alpha/kernel/sys_takara.c
index 2c75cd1fd81a..9bd9a31450c6 100644
--- a/arch/alpha/kernel/sys_takara.c
+++ b/arch/alpha/kernel/sys_takara.c
@@ -85,7 +85,7 @@ static struct hw_interrupt_type takara_irq_type = {
};
static void
-takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
+takara_device_interrupt(unsigned long vector)
{
unsigned intstatus;
@@ -112,20 +112,20 @@ takara_device_interrupt(unsigned long vector, struct pt_regs *regs)
* despatch an interrupt if it's set.
*/
- if (intstatus & 8) handle_irq(16+3, regs);
- if (intstatus & 4) handle_irq(16+2, regs);
- if (intstatus & 2) handle_irq(16+1, regs);
- if (intstatus & 1) handle_irq(16+0, regs);
+ if (intstatus & 8) handle_irq(16+3);
+ if (intstatus & 4) handle_irq(16+2);
+ if (intstatus & 2) handle_irq(16+1);
+ if (intstatus & 1) handle_irq(16+0);
} else {
- isa_device_interrupt (vector, regs);
+ isa_device_interrupt (vector);
}
}
static void
-takara_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+takara_srm_device_interrupt(unsigned long vector)
{
int irq = (vector - 0x800) >> 4;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
static void __init
diff --git a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
index 302aab38d95f..29ab7db81c30 100644
--- a/arch/alpha/kernel/sys_titan.c
+++ b/arch/alpha/kernel/sys_titan.c
@@ -167,18 +167,18 @@ titan_set_irq_affinity(unsigned int irq, cpumask_t affinity)
}
static void
-titan_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_device_interrupt(unsigned long vector)
{
printk("titan_device_interrupt: NOT IMPLEMENTED YET!! \n");
}
static void
-titan_srm_device_interrupt(unsigned long vector, struct pt_regs * regs)
+titan_srm_device_interrupt(unsigned long vector)
{
int irq;
irq = (vector - 0x800) >> 4;
- handle_irq(irq, regs);
+ handle_irq(irq);
}
@@ -204,7 +204,7 @@ static struct hw_interrupt_type titan_irq_type = {
};
static irqreturn_t
-titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs)
+titan_intr_nop(int irq, void *dev_id)
{
/*
* This is a NOP interrupt handler for the purposes of
@@ -243,7 +243,7 @@ titan_legacy_init_irq(void)
}
void
-titan_dispatch_irqs(u64 mask, struct pt_regs *regs)
+titan_dispatch_irqs(u64 mask)
{
unsigned long vector;
@@ -263,7 +263,7 @@ titan_dispatch_irqs(u64 mask, struct pt_regs *regs)
vector = 0x900 + (vector << 4); /* convert to SRM vector */
/* dispatch it */
- alpha_mv.device_interrupt(vector, regs);
+ alpha_mv.device_interrupt(vector);
}
}
diff --git a/arch/alpha/kernel/sys_wildfire.c b/arch/alpha/kernel/sys_wildfire.c
index 22c5798fe083..42c3eede4d09 100644
--- a/arch/alpha/kernel/sys_wildfire.c
+++ b/arch/alpha/kernel/sys_wildfire.c
@@ -234,7 +234,7 @@ wildfire_init_irq(void)
}
static void
-wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs)
+wildfire_device_interrupt(unsigned long vector)
{
int irq;
@@ -246,7 +246,7 @@ wildfire_device_interrupt(unsigned long vector, struct pt_regs * regs)
* bits 5-0: irq in PCA
*/
- handle_irq(irq, regs);
+ handle_irq(irq);
return;
}
diff --git a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S
index 4342cea1a926..f6cfe8ce3f96 100644
--- a/arch/alpha/kernel/systbls.S
+++ b/arch/alpha/kernel/systbls.S
@@ -4,7 +4,6 @@
* The system call table.
*/
-#include <linux/config.h> /* CONFIG_OSF4_COMPAT */
#include <asm/unistd.h>
.data
diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c
index b191cc759737..d7053eb4ffcf 100644
--- a/arch/alpha/kernel/time.c
+++ b/arch/alpha/kernel/time.c
@@ -54,11 +54,10 @@
#include "proto.h"
#include "irq_impl.h"
-extern unsigned long wall_jiffies; /* kernel/timer.c */
-
static int set_rtc_mmss(unsigned long);
DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL(rtc_lock);
#define TICK_SIZE (tick_nsec / 1000)
@@ -106,7 +105,7 @@ unsigned long long sched_clock(void)
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs)
+irqreturn_t timer_interrupt(int irq, void *dev)
{
unsigned long delta;
__u32 now;
@@ -114,7 +113,7 @@ irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs)
#ifndef CONFIG_SMP
/* Not SMP, do kernel PC profiling here. */
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#endif
write_seqlock(&xtime_lock);
@@ -132,9 +131,9 @@ irqreturn_t timer_interrupt(int irq, void *dev, struct pt_regs * regs)
nticks = delta >> FIX_SHIFT;
while (nticks > 0) {
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
nticks--;
}
@@ -413,7 +412,7 @@ void
do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
- unsigned long sec, usec, lost, seq;
+ unsigned long sec, usec, seq;
unsigned long delta_cycles, delta_usec, partial_tick;
do {
@@ -423,14 +422,13 @@ do_gettimeofday(struct timeval *tv)
sec = xtime.tv_sec;
usec = (xtime.tv_nsec / 1000);
partial_tick = state.partial_tick;
- lost = jiffies - wall_jiffies;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
#ifdef CONFIG_SMP
/* Until and unless we figure out how to get cpu cycle counters
in sync and keep them there, we can't use the rpcc tricks. */
- delta_usec = lost * (1000000 / HZ);
+ delta_usec = 0;
#else
/*
* usec = cycles * ticks_per_cycle * 2**48 * 1e6 / (2**48 * ticks)
@@ -446,8 +444,7 @@ do_gettimeofday(struct timeval *tv)
*/
delta_usec = (delta_cycles * state.scaled_ticks_per_cycle
- + partial_tick
- + (lost << FIX_SHIFT)) * 15625;
+ + partial_tick) * 15625;
delta_usec = ((delta_usec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
#endif
@@ -480,12 +477,11 @@ do_settimeofday(struct timespec *tv)
time. Without this, a full-tick error is possible. */
#ifdef CONFIG_SMP
- delta_nsec = (jiffies - wall_jiffies) * (NSEC_PER_SEC / HZ);
+ delta_nsec = 0;
#else
delta_nsec = rpcc() - state.last_time;
delta_nsec = (delta_nsec * state.scaled_ticks_per_cycle
- + state.partial_tick
- + ((jiffies - wall_jiffies) << FIX_SHIFT)) * 15625;
+ + state.partial_tick) * 15625;
delta_nsec = ((delta_nsec / ((1UL << (FIX_SHIFT-6-1)) * HZ)) + 1) / 2;
delta_nsec *= 1000;
#endif
diff --git a/arch/alpha/lib/dbg_stackcheck.S b/arch/alpha/lib/dbg_stackcheck.S
index 3c1f3e6522e5..78f6b924ad8f 100644
--- a/arch/alpha/lib/dbg_stackcheck.S
+++ b/arch/alpha/lib/dbg_stackcheck.S
@@ -1,5 +1,5 @@
/*
- * arch/alpha/lib/stackcheck.S
+ * arch/alpha/lib/dbg_stackcheck.S
* Contributed by Richard Henderson (rth@tamu.edu)
*
* Verify that we have not overflowed the stack. Oops if we have.
diff --git a/arch/alpha/lib/dbg_stackkill.S b/arch/alpha/lib/dbg_stackkill.S
index e9f6a9dcf2b7..c1e40a1a43d5 100644
--- a/arch/alpha/lib/dbg_stackkill.S
+++ b/arch/alpha/lib/dbg_stackkill.S
@@ -1,5 +1,5 @@
/*
- * arch/alpha/lib/killstack.S
+ * arch/alpha/lib/dbg_stackkill.S
* Contributed by Richard Henderson (rth@cygnus.com)
*
* Clobber the balance of the kernel stack, hoping to catch
diff --git a/arch/alpha/lib/memset.S b/arch/alpha/lib/memset.S
index 8ff6e7e1773e..311b8cfc6914 100644
--- a/arch/alpha/lib/memset.S
+++ b/arch/alpha/lib/memset.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/alpha/memset.S
+ * linux/arch/alpha/lib/memset.S
*
* This is an efficient (and small) implementation of the C library "memset()"
* function for the alpha.
diff --git a/arch/alpha/mm/Makefile b/arch/alpha/mm/Makefile
index 6edd9a09ea4f..09399c5386cb 100644
--- a/arch/alpha/mm/Makefile
+++ b/arch/alpha/mm/Makefile
@@ -4,6 +4,6 @@
EXTRA_CFLAGS := -Werror
-obj-y := init.o fault.o extable.o remap.o
+obj-y := init.o fault.o extable.o
obj-$(CONFIG_DISCONTIGMEM) += numa.o
diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c
index 622dabd84680..8871529a34e2 100644
--- a/arch/alpha/mm/fault.c
+++ b/arch/alpha/mm/fault.c
@@ -193,7 +193,7 @@ do_page_fault(unsigned long address, unsigned long mmcsr,
/* We ran out of memory, or some other thing happened to us that
made us unable to handle the page fault gracefully. */
out_of_memory:
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/alpha/mm/numa.c b/arch/alpha/mm/numa.c
index b826f58c6e72..e3e3806a6f25 100644
--- a/arch/alpha/mm/numa.c
+++ b/arch/alpha/mm/numa.c
@@ -13,12 +13,14 @@
#include <linux/swap.h>
#include <linux/initrd.h>
#include <linux/pfn.h>
+#include <linux/module.h>
#include <asm/hwrpb.h>
#include <asm/pgalloc.h>
pg_data_t node_data[MAX_NUMNODES];
bootmem_data_t node_bdata[MAX_NUMNODES];
+EXPORT_SYMBOL(node_data);
#undef DEBUG_DISCONTIG
#ifdef DEBUG_DISCONTIG
diff --git a/arch/alpha/mm/remap.c b/arch/alpha/mm/remap.c
deleted file mode 100644
index a78356c3ead5..000000000000
--- a/arch/alpha/mm/remap.c
+++ /dev/null
@@ -1,86 +0,0 @@
-#include <linux/vmalloc.h>
-#include <asm/pgalloc.h>
-#include <asm/cacheflush.h>
-
-static inline void
-remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
- unsigned long pfn;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
- set_pte(pte, pfn_pte(pfn,
- __pgprot(_PAGE_VALID | _PAGE_ASM |
- _PAGE_KRE | _PAGE_KWE | flags)));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int
-remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address,
- address + phys_addr, flags);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-int
-__alpha_remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, unsigned long flags)
-{
- pgd_t * dir;
- int error = 0;
- unsigned long end = address + size;
-
- phys_addr -= address;
- dir = pgd_offset(&init_mm, address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pmd_t *pmd;
- pmd = pmd_alloc(&init_mm, dir, address);
- error = -ENOMEM;
- if (!pmd)
- break;
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- return error;
-}
-
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f81a62380add..adb05de40e24 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -17,6 +17,10 @@ config ARM
Europe. There is an ARM Linux project with a web page at
<http://www.arm.linux.org.uk/>.
+config GENERIC_TIME
+ bool
+ default n
+
config MMU
bool
default y
@@ -51,6 +55,10 @@ config GENERIC_HARDIRQS
bool
default y
+config TRACE_IRQFLAGS_SUPPORT
+ bool
+ default y
+
config HARDIRQS_SW_RESEND
bool
default y
@@ -91,7 +99,7 @@ config ARCH_MTD_XIP
config VECTORS_BASE
hex
- default 0xffff0000 if MMU
+ default 0xffff0000 if MMU || CPU_HIGH_VECTOR
default DRAM_BASE if REMAP_VECTORS_TO_RAM
default 0x00000000
help
@@ -198,16 +206,27 @@ config ARCH_IMX
help
Support for Motorola's i.MX family of processors (MX1, MXL).
-config ARCH_IOP3XX
- bool "IOP3xx-based"
+config ARCH_IOP32X
+ bool "IOP32x-based"
+ depends on MMU
+ select PLAT_IOP
+ select PCI
+ help
+ Support for Intel's 80219 and IOP32X (XScale) family of
+ processors.
+
+config ARCH_IOP33X
+ bool "IOP33x-based"
depends on MMU
+ select PLAT_IOP
select PCI
help
- Support for Intel's IOP3XX (XScale) family of processors.
+ Support for Intel's IOP33X (XScale) family of processors.
config ARCH_IXP4XX
bool "IXP4xx-based"
depends on MMU
+ select GENERIC_TIME
help
Support for Intel's IXP4XX (XScale) family of processors.
@@ -308,7 +327,9 @@ source "arch/arm/mach-footbridge/Kconfig"
source "arch/arm/mach-integrator/Kconfig"
-source "arch/arm/mach-iop3xx/Kconfig"
+source "arch/arm/mach-iop32x/Kconfig"
+
+source "arch/arm/mach-iop33x/Kconfig"
source "arch/arm/mach-ixp4xx/Kconfig"
@@ -348,6 +369,9 @@ source "arch/arm/mach-netx/Kconfig"
config ARCH_ACORN
bool
+config PLAT_IOP
+ bool
+
source arch/arm/mm/Kconfig
# bool 'Use XScale PMU as timer source' CONFIG_XSCALE_PMU_TIMER
@@ -602,9 +626,10 @@ config LEDS_CPU
config ALIGNMENT_TRAP
bool
+ depends on CPU_CP15_MMU
default y if !ARCH_EBSA110
help
- ARM processors can not fetch/store information which is not
+ ARM processors cannot fetch/store information which is not
naturally aligned on the bus, i.e., a 4 byte fetch must start at an
address divisible by 4. On 32-bit ARM processors, these non-aligned
fetch/store instructions will be emulated in software if you say
@@ -633,11 +658,12 @@ config ZBOOT_ROM_BSS
hex "Compressed ROM boot loader BSS address"
default "0"
help
- The base address of 64KiB of read/write memory in the target
- for the ROM-able zImage, which must be available while the
- decompressor is running. Platforms which normally make use of
- ROM-able zImage formats normally set this to a suitable
- value in their defconfig file.
+ The base address of an area of read/write memory in the target
+ for the ROM-able zImage which must be available while the
+ decompressor is running. It must be large enough to hold the
+ entire decompressed kernel plus an additional 128 KiB.
+ Platforms which normally make use of ROM-able zImage formats
+ normally set this to a suitable value in their defconfig file.
If ZBOOT_ROM is not enabled, this has no effect.
@@ -832,7 +858,7 @@ source "drivers/base/Kconfig"
source "drivers/connector/Kconfig"
-if ALIGNMENT_TRAP
+if ALIGNMENT_TRAP || !CPU_CP15_MMU
source "drivers/mtd/Kconfig"
endif
@@ -844,7 +870,7 @@ source "drivers/block/Kconfig"
source "drivers/acorn/block/Kconfig"
-if PCMCIA || ARCH_CLPS7500 || ARCH_IOP3XX || ARCH_IXP4XX \
+if PCMCIA || ARCH_CLPS7500 || ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX \
|| ARCH_L7200 || ARCH_LH7A40X || ARCH_PXA || ARCH_RPC \
|| ARCH_S3C2410 || ARCH_SA1100 || ARCH_SHARK || FOOTBRIDGE \
|| ARCH_IXP23XX
diff --git a/arch/arm/Kconfig-nommu b/arch/arm/Kconfig-nommu
index e1574be2ded6..f087376748d1 100644
--- a/arch/arm/Kconfig-nommu
+++ b/arch/arm/Kconfig-nommu
@@ -25,6 +25,14 @@ config FLASH_SIZE
hex 'FLASH Size' if SET_MEM_PARAM
default 0x00400000
+config PROCESSOR_ID
+ hex
+ default 0x00007700
+ depends on !CPU_CP15
+ help
+ If processor has no CP15 register, this processor ID is
+ used instead of the auto-probing which utilizes the register.
+
config REMAP_VECTORS_TO_RAM
bool 'Install vectors to the begining of RAM' if DRAM_BASE
depends on DRAM_BASE
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 92873cdee31f..2a0b2c8a1fe0 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -55,7 +55,12 @@ arch-$(CONFIG_CPU_32v3) :=-D__LINUX_ARM_ARCH__=3 -march=armv3
# This selects how we optimise for the processor.
tune-$(CONFIG_CPU_ARM610) :=-mtune=arm610
tune-$(CONFIG_CPU_ARM710) :=-mtune=arm710
+tune-$(CONFIG_CPU_ARM7TDMI) :=-mtune=arm7tdmi
tune-$(CONFIG_CPU_ARM720T) :=-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM740T) :=-mtune=arm7tdmi
+tune-$(CONFIG_CPU_ARM9TDMI) :=-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM940T) :=-mtune=arm9tdmi
+tune-$(CONFIG_CPU_ARM946T) :=$(call cc-option,-mtune=arm9e,-mtune=arm9tdmi)
tune-$(CONFIG_CPU_ARM920T) :=-mtune=arm9tdmi
tune-$(CONFIG_CPU_ARM922T) :=-mtune=arm9tdmi
tune-$(CONFIG_CPU_ARM925T) :=-mtune=arm9tdmi
@@ -101,7 +106,8 @@ endif
machine-$(CONFIG_ARCH_INTEGRATOR) := integrator
textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000
machine-$(CONFIG_ARCH_CLPS711X) := clps711x
- machine-$(CONFIG_ARCH_IOP3XX) := iop3xx
+ machine-$(CONFIG_ARCH_IOP32X) := iop32x
+ machine-$(CONFIG_ARCH_IOP33X) := iop33x
machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx
machine-$(CONFIG_ARCH_IXP2000) := ixp2000
machine-$(CONFIG_ARCH_IXP23XX) := ixp23xx
@@ -157,6 +163,7 @@ core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
core-$(CONFIG_VFP) += arch/arm/vfp/
# If we have a common platform directory, then include it in the build.
+core-$(CONFIG_PLAT_IOP) += arch/arm/plat-iop/
core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
diff --git a/arch/arm/boot/compressed/Makefile b/arch/arm/boot/compressed/Makefile
index 2adc1527e0eb..adddc7131685 100644
--- a/arch/arm/boot/compressed/Makefile
+++ b/arch/arm/boot/compressed/Makefile
@@ -51,7 +51,11 @@ OBJS += head-at91rm9200.o
endif
ifeq ($(CONFIG_CPU_BIG_ENDIAN),y)
+ifeq ($(CONFIG_CPU_CP15),y)
OBJS += big-endian.o
+else
+# The endian should be set by h/w design.
+endif
endif
#
diff --git a/arch/arm/boot/compressed/head-clps7500.S b/arch/arm/boot/compressed/head-clps7500.S
index 941c5f5cbacf..4f3c78ac30a0 100644
--- a/arch/arm/boot/compressed/head-clps7500.S
+++ b/arch/arm/boot/compressed/head-clps7500.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/boot/compressed/head.S
+ * linux/arch/arm/boot/compressed/head-clps7500.S
*
* Copyright (C) 1999, 2000, 2001 Nexus Electronics Ltd
*/
diff --git a/arch/arm/boot/compressed/head.S b/arch/arm/boot/compressed/head.S
index 14a9ff9c68df..2568d311be21 100644
--- a/arch/arm/boot/compressed/head.S
+++ b/arch/arm/boot/compressed/head.S
@@ -20,11 +20,21 @@
#ifdef DEBUG
#if defined(CONFIG_DEBUG_ICEDCC)
+
+#ifdef CONFIG_CPU_V6
+ .macro loadsp, rb
+ .endm
+ .macro writeb, ch, rb
+ mcr p14, 0, \ch, c0, c5, 0
+ .endm
+#else
.macro loadsp, rb
.endm
.macro writeb, ch, rb
mcr p14, 0, \ch, c0, c1, 0
.endm
+#endif
+
#else
#include <asm/arch/debug-macro.S>
@@ -42,12 +52,6 @@
add \rb, \rb, #0x00010000 @ Ser1
#endif
.endm
-#elif defined(CONFIG_ARCH_IOP331)
- .macro loadsp, rb
- mov \rb, #0xff000000
- orr \rb, \rb, #0x00ff0000
- orr \rb, \rb, #0x0000f700 @ location of the UART
- .endm
#elif defined(CONFIG_ARCH_S3C2410)
.macro loadsp, rb
mov \rb, #0x50000000
@@ -78,9 +82,11 @@
kphex r6, 8 /* processor id */
kputc #':'
kphex r7, 8 /* architecture id */
+#ifdef CONFIG_CPU_CP15
kputc #':'
mrc p15, 0, r0, c1, c0
kphex r0, 8 /* control reg */
+#endif
kputc #'\n'
kphex r5, 8 /* decompressed kernel start */
kputc #'-'
@@ -231,7 +237,8 @@ not_relocated: mov r0, #0
*/
cmp r4, r2
bhs wont_overwrite
- add r0, r4, #4096*1024 @ 4MB largest kernel size
+ sub r3, sp, r5 @ > compressed kernel size
+ add r0, r4, r3, lsl #2 @ allow for 4x expansion
cmp r0, r5
bls wont_overwrite
@@ -503,7 +510,11 @@ call_kernel: bl cache_clean_flush
*/
call_cache_fn: adr r12, proc_types
+#ifdef CONFIG_CPU_CP15
mrc p15, 0, r6, c0, c0 @ get processor ID
+#else
+ ldr r6, =CONFIG_PROCESSOR_ID
+#endif
1: ldr r1, [r12, #0] @ get value
ldr r2, [r12, #4] @ get mask
eor r1, r1, r6 @ (real ^ match)
diff --git a/arch/arm/boot/compressed/misc.c b/arch/arm/boot/compressed/misc.c
index ace3fb5835d9..283891c736c4 100644
--- a/arch/arm/boot/compressed/misc.c
+++ b/arch/arm/boot/compressed/misc.c
@@ -30,6 +30,25 @@ static void putstr(const char *ptr);
#include <asm/arch/uncompress.h>
#ifdef CONFIG_DEBUG_ICEDCC
+
+#ifdef CONFIG_CPU_V6
+
+static void icedcc_putc(int ch)
+{
+ int status, i = 0x4000000;
+
+ do {
+ if (--i < 0)
+ return;
+
+ asm volatile ("mrc p14, 0, %0, c0, c1, 0" : "=r" (status));
+ } while (status & (1 << 29));
+
+ asm("mcr p14, 0, %0, c0, c5, 0" : : "r" (ch));
+}
+
+#else
+
static void icedcc_putc(int ch)
{
int status, i = 0x4000000;
@@ -44,6 +63,8 @@ static void icedcc_putc(int ch)
asm("mcr p14, 0, %0, c1, c0, 0" : : "r" (ch));
}
+#endif
+
#define putc(ch) icedcc_putc(ch)
#define flush() do { } while (0)
#endif
diff --git a/arch/arm/common/icst307.c b/arch/arm/common/icst307.c
index bafe8b19be82..6d094c157540 100644
--- a/arch/arm/common/icst307.c
+++ b/arch/arm/common/icst307.c
@@ -57,7 +57,7 @@ icst307_khz_to_vco(const struct icst307_params *p, unsigned long freq)
break;
} while (i < ARRAY_SIZE(idx2s));
- if (i > ARRAY_SIZE(idx2s))
+ if (i >= ARRAY_SIZE(idx2s))
return vco;
vco.s = idx2s[i];
@@ -119,7 +119,7 @@ icst307_ps_to_vco(const struct icst307_params *p, unsigned long period)
break;
} while (i < ARRAY_SIZE(idx2s));
- if (i > ARRAY_SIZE(idx2s))
+ if (i >= ARRAY_SIZE(idx2s))
return vco;
vco.s = idx2s[i];
diff --git a/arch/arm/common/icst525.c b/arch/arm/common/icst525.c
index 943ef88c0379..3d377c5bdef6 100644
--- a/arch/arm/common/icst525.c
+++ b/arch/arm/common/icst525.c
@@ -55,7 +55,7 @@ icst525_khz_to_vco(const struct icst525_params *p, unsigned long freq)
break;
} while (i < ARRAY_SIZE(idx2s));
- if (i > ARRAY_SIZE(idx2s))
+ if (i >= ARRAY_SIZE(idx2s))
return vco;
vco.s = idx2s[i];
@@ -118,7 +118,7 @@ icst525_ps_to_vco(const struct icst525_params *p, unsigned long period)
break;
} while (i < ARRAY_SIZE(idx2s));
- if (i > ARRAY_SIZE(idx2s))
+ if (i >= ARRAY_SIZE(idx2s))
return vco;
vco.s = idx2s[i];
diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c
index 4e0dcaef6eb2..80a72c75214f 100644
--- a/arch/arm/common/locomo.c
+++ b/arch/arm/common/locomo.c
@@ -121,6 +121,13 @@ static struct locomo_dev_info locomo_devices[] = {
.offset = 0,
.length = 0,
},
+ {
+ .devid = LOCOMO_DEVID_SPI,
+ .irq = {},
+ .name = "locomo-spi",
+ .offset = LOCOMO_SPI,
+ .length = 0x30,
+ },
};
@@ -156,8 +163,7 @@ static struct locomo_dev_info locomo_devices[] = {
#define LOCOMO_IRQ_LT_START (IRQ_LOCOMO_LT)
#define LOCOMO_IRQ_SPI_START (IRQ_LOCOMO_SPI_RFR)
-static void locomo_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void locomo_handler(unsigned int irq, struct irqdesc *desc)
{
int req, i;
struct irqdesc *d;
@@ -175,7 +181,7 @@ static void locomo_handler(unsigned int irq, struct irqdesc *desc,
d = irq_desc + irq;
for (i = 0; i <= 3; i++, d++, irq++) {
if (req & (0x0100 << i)) {
- desc_handle_irq(irq, d, regs);
+ desc_handle_irq(irq, d);
}
}
@@ -211,15 +217,14 @@ static struct irq_chip locomo_chip = {
.unmask = locomo_unmask_irq,
};
-static void locomo_key_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void locomo_key_handler(unsigned int irq, struct irqdesc *desc)
{
struct irqdesc *d;
void __iomem *mapbase = get_irq_chipdata(irq);
if (locomo_readl(mapbase + LOCOMO_KEYBOARD + LOCOMO_KIC) & 0x0001) {
d = irq_desc + LOCOMO_IRQ_KEY_START;
- desc_handle_irq(LOCOMO_IRQ_KEY_START, d, regs);
+ desc_handle_irq(LOCOMO_IRQ_KEY_START, d);
}
}
@@ -257,8 +262,7 @@ static struct irq_chip locomo_key_chip = {
.unmask = locomo_key_unmask_irq,
};
-static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc)
{
int req, i;
struct irqdesc *d;
@@ -273,7 +277,7 @@ static void locomo_gpio_handler(unsigned int irq, struct irqdesc *desc,
d = irq_desc + LOCOMO_IRQ_GPIO_START;
for (i = 0; i <= 15; i++, irq++, d++) {
if (req & (0x0001 << i)) {
- desc_handle_irq(irq, d, regs);
+ desc_handle_irq(irq, d);
}
}
}
@@ -321,15 +325,14 @@ static struct irq_chip locomo_gpio_chip = {
.unmask = locomo_gpio_unmask_irq,
};
-static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void locomo_lt_handler(unsigned int irq, struct irqdesc *desc)
{
struct irqdesc *d;
void __iomem *mapbase = get_irq_chipdata(irq);
if (locomo_readl(mapbase + LOCOMO_LTINT) & 0x0001) {
d = irq_desc + LOCOMO_IRQ_LT_START;
- desc_handle_irq(LOCOMO_IRQ_LT_START, d, regs);
+ desc_handle_irq(LOCOMO_IRQ_LT_START, d);
}
}
@@ -367,21 +370,20 @@ static struct irq_chip locomo_lt_chip = {
.unmask = locomo_lt_unmask_irq,
};
-static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void locomo_spi_handler(unsigned int irq, struct irqdesc *desc)
{
int req, i;
struct irqdesc *d;
void __iomem *mapbase = get_irq_chipdata(irq);
- req = locomo_readl(mapbase + LOCOMO_SPIIR) & 0x000F;
+ req = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIR) & 0x000F;
if (req) {
irq = LOCOMO_IRQ_SPI_START;
d = irq_desc + irq;
for (i = 0; i <= 3; i++, irq++, d++) {
if (req & (0x0001 << i)) {
- desc_handle_irq(irq, d, regs);
+ desc_handle_irq(irq, d);
}
}
}
@@ -391,35 +393,35 @@ static void locomo_spi_ack_irq(unsigned int irq)
{
void __iomem *mapbase = get_irq_chipdata(irq);
unsigned int r;
- r = locomo_readl(mapbase + LOCOMO_SPIWE);
+ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START));
- locomo_writel(r, mapbase + LOCOMO_SPIWE);
+ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
- r = locomo_readl(mapbase + LOCOMO_SPIIS);
+ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIS);
r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
- locomo_writel(r, mapbase + LOCOMO_SPIIS);
+ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIIS);
- r = locomo_readl(mapbase + LOCOMO_SPIWE);
+ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
- locomo_writel(r, mapbase + LOCOMO_SPIWE);
+ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIWE);
}
static void locomo_spi_mask_irq(unsigned int irq)
{
void __iomem *mapbase = get_irq_chipdata(irq);
unsigned int r;
- r = locomo_readl(mapbase + LOCOMO_SPIIE);
+ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
r &= ~(0x0001 << (irq - LOCOMO_IRQ_SPI_START));
- locomo_writel(r, mapbase + LOCOMO_SPIIE);
+ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
}
static void locomo_spi_unmask_irq(unsigned int irq)
{
void __iomem *mapbase = get_irq_chipdata(irq);
unsigned int r;
- r = locomo_readl(mapbase + LOCOMO_SPIIE);
+ r = locomo_readl(mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
r |= (0x0001 << (irq - LOCOMO_IRQ_SPI_START));
- locomo_writel(r, mapbase + LOCOMO_SPIIE);
+ locomo_writel(r, mapbase + LOCOMO_SPI + LOCOMO_SPIIE);
}
static struct irq_chip locomo_spi_chip = {
@@ -814,12 +816,15 @@ static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev)
return (struct locomo *)dev_get_drvdata(ldev->dev.parent);
}
-void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir)
+void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir)
{
- struct locomo *lchip = locomo_chip_driver(ldev);
+ struct locomo *lchip = dev_get_drvdata(dev);
unsigned long flags;
unsigned int r;
+ if (!lchip)
+ return;
+
spin_lock_irqsave(&lchip->lock, flags);
r = locomo_readl(lchip->base + LOCOMO_GPD);
@@ -836,12 +841,15 @@ void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned in
spin_unlock_irqrestore(&lchip->lock, flags);
}
-unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits)
+int locomo_gpio_read_level(struct device *dev, unsigned int bits)
{
- struct locomo *lchip = locomo_chip_driver(ldev);
+ struct locomo *lchip = dev_get_drvdata(dev);
unsigned long flags;
unsigned int ret;
+ if (!lchip)
+ return -ENODEV;
+
spin_lock_irqsave(&lchip->lock, flags);
ret = locomo_readl(lchip->base + LOCOMO_GPL);
spin_unlock_irqrestore(&lchip->lock, flags);
@@ -850,12 +858,15 @@ unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits)
return ret;
}
-unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits)
+int locomo_gpio_read_output(struct device *dev, unsigned int bits)
{
- struct locomo *lchip = locomo_chip_driver(ldev);
+ struct locomo *lchip = dev_get_drvdata(dev);
unsigned long flags;
unsigned int ret;
+ if (!lchip)
+ return -ENODEV;
+
spin_lock_irqsave(&lchip->lock, flags);
ret = locomo_readl(lchip->base + LOCOMO_GPO);
spin_unlock_irqrestore(&lchip->lock, flags);
@@ -864,12 +875,15 @@ unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits)
return ret;
}
-void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set)
+void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set)
{
- struct locomo *lchip = locomo_chip_driver(ldev);
+ struct locomo *lchip = dev_get_drvdata(dev);
unsigned long flags;
unsigned int r;
+ if (!lchip)
+ return;
+
spin_lock_irqsave(&lchip->lock, flags);
r = locomo_readl(lchip->base + LOCOMO_GPO);
@@ -1058,9 +1072,9 @@ void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf)
struct locomo *lchip = locomo_chip_driver(dev);
if (vr)
- locomo_gpio_write(dev, LOCOMO_GPIO_FL_VR, 1);
+ locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 1);
else
- locomo_gpio_write(dev, LOCOMO_GPIO_FL_VR, 0);
+ locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
spin_lock_irqsave(&lchip->lock, flags);
locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS);
diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
index 29818bd3248f..d5f72010a6f3 100644
--- a/arch/arm/common/sa1111.c
+++ b/arch/arm/common/sa1111.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-sa1100/sa1111.c
+ * linux/arch/arm/common/sa1111.c
*
* SA1111 support
*
@@ -147,7 +147,7 @@ void __init sa1111_adjust_zones(int node, unsigned long *size, unsigned long *ho
* will call us again if there are more interrupts to process.
*/
static void
-sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+sa1111_irq_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned int stat0, stat1, i;
void __iomem *base = get_irq_data(irq);
@@ -162,17 +162,17 @@ sa1111_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
sa1111_writel(stat1, base + SA1111_INTSTATCLR1);
if (stat0 == 0 && stat1 == 0) {
- do_bad_IRQ(irq, desc, regs);
+ do_bad_IRQ(irq, desc);
return;
}
for (i = IRQ_SA1111_START; stat0; i++, stat0 >>= 1)
if (stat0 & 1)
- handle_edge_irq(i, irq_desc + i, regs);
+ handle_edge_irq(i, irq_desc + i);
for (i = IRQ_SA1111_START + 32; stat1; i++, stat1 >>= 1)
if (stat1 & 1)
- handle_edge_irq(i, irq_desc + i, regs);
+ handle_edge_irq(i, irq_desc + i);
/* For level-based interrupts */
desc->chip->unmask(irq);
diff --git a/arch/arm/common/sharpsl_pm.c b/arch/arm/common/sharpsl_pm.c
index 59b5ddec480f..605dedf96790 100644
--- a/arch/arm/common/sharpsl_pm.c
+++ b/arch/arm/common/sharpsl_pm.c
@@ -40,6 +40,7 @@
#define SHARPSL_CHARGE_FINISH_TIME (msecs_to_jiffies(10*60*1000)) /* 10 min */
#define SHARPSL_BATCHK_TIME (msecs_to_jiffies(15*1000)) /* 15 sec */
#define SHARPSL_BATCHK_TIME_SUSPEND (60*10) /* 10 min */
+
#define SHARPSL_WAIT_CO_TIME 15 /* 15 sec */
#define SHARPSL_WAIT_DISCHARGE_ON 100 /* 100 msec */
#define SHARPSL_CHECK_BATTERY_WAIT_TIME_TEMP 10 /* 10 msec */
@@ -257,7 +258,7 @@ static void sharpsl_ac_timer(unsigned long data)
}
-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp)
+irqreturn_t sharpsl_ac_isr(int irq, void *dev_id)
{
/* Delay the event slightly to debounce */
/* Must be a smaller delay than the chrg_full_isr below */
@@ -292,7 +293,7 @@ static void sharpsl_chrg_full_timer(unsigned long data)
/* Charging Finished Interrupt (Not present on Corgi) */
/* Can trigger at the same time as an AC staus change so
delay until after that has been processed */
-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp)
+irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id)
{
if (sharpsl_pm.flags & SHARPSL_SUSPENDED)
return IRQ_HANDLED;
@@ -303,7 +304,7 @@ irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp)
return IRQ_HANDLED;
}
-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp)
+irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id)
{
int is_fatal = 0;
@@ -575,6 +576,9 @@ static int corgi_pxa_pm_enter(suspend_state_t state)
while (corgi_enter_suspend(alarm_time,alarm_status,state))
{}
+ if (sharpsl_pm.machinfo->earlyresume)
+ sharpsl_pm.machinfo->earlyresume();
+
dev_dbg(sharpsl_pm.dev, "SharpSL resuming...\n");
return 0;
diff --git a/arch/arm/common/time-acorn.c b/arch/arm/common/time-acorn.c
index 3f60dd9aca80..34038eccbba9 100644
--- a/arch/arm/common/time-acorn.c
+++ b/arch/arm/common/time-acorn.c
@@ -67,10 +67,10 @@ void __init ioctime_init(void)
}
static irqreturn_t
-ioc_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ioc_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig
index 4f3d8d37741e..c82e4667f45e 100644
--- a/arch/arm/configs/at91rm9200dk_defconfig
+++ b/arch/arm/configs/at91rm9200dk_defconfig
@@ -553,9 +553,9 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig
index 08b5dc38876f..b983fc59aa42 100644
--- a/arch/arm/configs/at91rm9200ek_defconfig
+++ b/arch/arm/configs/at91rm9200ek_defconfig
@@ -534,9 +534,9 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/ateb9200_defconfig b/arch/arm/configs/ateb9200_defconfig
index bee7813d040e..15e6b0bbbde8 100644
--- a/arch/arm/configs/ateb9200_defconfig
+++ b/arch/arm/configs/ateb9200_defconfig
@@ -656,9 +656,9 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/carmeva_defconfig b/arch/arm/configs/carmeva_defconfig
index 8a075c8ecc63..d24ae8777c35 100644
--- a/arch/arm/configs/carmeva_defconfig
+++ b/arch/arm/configs/carmeva_defconfig
@@ -455,8 +455,8 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig
index cf3fa5cb26e4..a2d6fd398f16 100644
--- a/arch/arm/configs/csb337_defconfig
+++ b/arch/arm/configs/csb337_defconfig
@@ -591,9 +591,9 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig
index 640d70c1f066..2a1ac6c60abc 100644
--- a/arch/arm/configs/csb637_defconfig
+++ b/arch/arm/configs/csb637_defconfig
@@ -591,9 +591,9 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/ep93xx_defconfig b/arch/arm/configs/ep93xx_defconfig
index 2948b4589a8b..3b4802a849e4 100644
--- a/arch/arm/configs/ep93xx_defconfig
+++ b/arch/arm/configs/ep93xx_defconfig
@@ -126,6 +126,7 @@ CONFIG_CRUNCH=y
# EP93xx Platforms
#
CONFIG_MACH_EDB9302=y
+CONFIG_MACH_EDB9312=y
CONFIG_MACH_EDB9315=y
CONFIG_MACH_EDB9315A=y
CONFIG_MACH_GESBC9312=y
diff --git a/arch/arm/configs/ep80219_defconfig b/arch/arm/configs/iop32x_defconfig
index 3c73b707c2f3..0d67f66e78c2 100644
--- a/arch/arm/configs/ep80219_defconfig
+++ b/arch/arm/configs/iop32x_defconfig
@@ -1,50 +1,63 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 22:34:12 2005
+# Linux kernel version: 2.6.18-rc7
+# Tue Sep 19 00:30:18 2006
#
CONFIG_ARM=y
CONFIG_MMU=y
-CONFIG_UID16=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
+CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -52,24 +65,52 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
# System Type
#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS7500 is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-CONFIG_ARCH_IOP3XX=y
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+CONFIG_ARCH_IOP32X=y
+# CONFIG_ARCH_IOP33X is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
@@ -77,28 +118,19 @@ CONFIG_ARCH_IOP3XX=y
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
#
-# IOP3xx Implementation Options
+# IOP32x Implementation Options
#
#
-# IOP3xx Platform Types
+# IOP32x Platform Types
#
-# CONFIG_ARCH_IQ80321 is not set
+CONFIG_MACH_GLANTANK=y
+CONFIG_ARCH_IQ80321=y
CONFIG_ARCH_IQ31244=y
-# CONFIG_ARCH_IQ80331 is not set
-# CONFIG_MACH_IQ80332 is not set
-CONFIG_ARCH_EP80219=y
-CONFIG_ARCH_IOP321=y
-# CONFIG_ARCH_IOP331 is not set
-
-#
-# IOP3xx Chipset Features
-#
+CONFIG_MACH_N2100=y
+CONFIG_PLAT_IOP=y
#
# Processor Type
@@ -109,7 +141,6 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
#
# Processor Features
@@ -121,8 +152,7 @@ CONFIG_XSCALE_PMU=y
# Bus support
#
CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -133,6 +163,19 @@ CONFIG_PCI_NAMES=y
# Kernel Features
#
# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
CONFIG_ALIGNMENT_TRAP=y
#
@@ -140,7 +183,7 @@ CONFIG_ALIGNMENT_TRAP=y
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp"
# CONFIG_XIP_KERNEL is not set
#
@@ -166,6 +209,93 @@ CONFIG_BINFMT_AOUT=y
# Power management options
#
# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -177,6 +307,13 @@ CONFIG_BINFMT_AOUT=y
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -200,6 +337,7 @@ CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
#
# RAM/ROM/Flash chip drivers
@@ -225,18 +363,18 @@ CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0xf0000000
-CONFIG_MTD_PHYSMAP_LEN=0x00800000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+CONFIG_MTD_PHYSMAP_START=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=1
# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -245,7 +383,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
@@ -261,6 +398,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# CONFIG_MTD_NAND is not set
#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
# Parallel port support
#
# CONFIG_PARPORT is not set
@@ -272,7 +414,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -284,17 +425,9 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -305,6 +438,7 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
CONFIG_SCSI_PROC_FS=y
@@ -316,6 +450,7 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -330,10 +465,12 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -344,25 +481,19 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
@@ -377,8 +508,7 @@ CONFIG_BLK_DEV_MD=y
CONFIG_MD_RAID0=y
CONFIG_MD_RAID1=y
# CONFIG_MD_RAID10 is not set
-CONFIG_MD_RAID5=y
-# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_RAID456 is not set
# CONFIG_MD_MULTIPATH is not set
# CONFIG_MD_FAULTY is not set
CONFIG_BLK_DEV_DM=y
@@ -392,6 +522,9 @@ CONFIG_BLK_DEV_DM=y
# Fusion MPT device support
#
# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
@@ -404,71 +537,8 @@ CONFIG_BLK_DEV_DM=y
# CONFIG_I2O is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
+# Network device support
#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -481,14 +551,21 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
#
# Tulip family network device support
@@ -526,16 +603,23 @@ CONFIG_E1000_NAPI=y
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
+CONFIG_R8169=y
+# CONFIG_R8169_NAPI is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -558,6 +642,8 @@ CONFIG_E1000_NAPI=y
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -595,7 +681,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -603,6 +688,7 @@ CONFIG_SOUND_GAMEPORT=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -610,7 +696,9 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
@@ -618,6 +706,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -631,8 +720,8 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -647,6 +736,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# TPM devices
#
# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -671,14 +761,13 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
CONFIG_I2C_IOP3XX=y
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
@@ -689,15 +778,45 @@ CONFIG_I2C_IOP3XX=y
# CONFIG_I2C_PCA_ISA is not set
#
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
#
-# CONFIG_I2C_SENSOR is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
# CONFIG_SENSORS_GL518SM is not set
@@ -712,36 +831,45 @@ CONFIG_I2C_IOP3XX=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
-# Other I2C Chip support
+# Misc devices
#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
#
-# Misc devices
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
#
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -751,6 +879,7 @@ CONFIG_I2C_IOP3XX=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
@@ -758,6 +887,7 @@ CONFIG_I2C_IOP3XX=y
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -769,7 +899,125 @@ CONFIG_DUMMY_CONSOLE=y
#
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_SPLIT_ISO=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+CONFIG_USB_EHCI_TT_NEWSCHED=y
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
#
# USB Gadget Support
@@ -782,10 +1030,17 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -795,22 +1050,22 @@ CONFIG_JBD=y
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
CONFIG_XFS_FS=y
-CONFIG_XFS_EXPORT=y
-# CONFIG_XFS_RT is not set
# CONFIG_XFS_QUOTA is not set
CONFIG_XFS_SECURITY=y
CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -830,12 +1085,10 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -850,8 +1103,9 @@ CONFIG_RAMFS=y
# CONFIG_JFFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_RTIME=y
@@ -868,16 +1122,19 @@ CONFIG_JFFS2_RTIME=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
# CONFIG_NFSD_TCP is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -886,6 +1143,7 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -905,6 +1163,7 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
#
@@ -921,11 +1180,34 @@ CONFIG_MSDOS_PARTITION=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS 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 is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
#
# Security options
@@ -946,7 +1228,9 @@ CONFIG_DEBUG_USER=y
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/iq80332_defconfig b/arch/arm/configs/iop33x_defconfig
index 11959b705d82..2a8fc153969d 100644
--- a/arch/arm/configs/iq80332_defconfig
+++ b/arch/arm/configs/iop33x_defconfig
@@ -1,50 +1,63 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 17:33:39 2005
+# Linux kernel version: 2.6.18-rc7
+# Tue Sep 19 00:30:42 2006
#
CONFIG_ARM=y
CONFIG_MMU=y
-CONFIG_UID16=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_UID16=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_EMBEDDED is not set
CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
+CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -52,24 +65,52 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
+# Block layer
+#
+# CONFIG_BLK_DEV_IO_TRACE is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
# System Type
#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS7500 is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-CONFIG_ARCH_IOP3XX=y
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+CONFIG_ARCH_IOP33X=y
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
# CONFIG_ARCH_PXA is not set
# CONFIG_ARCH_RPC is not set
# CONFIG_ARCH_SA1100 is not set
@@ -77,28 +118,17 @@ CONFIG_ARCH_IOP3XX=y
# CONFIG_ARCH_SHARK is not set
# CONFIG_ARCH_LH7A40X is not set
# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
#
-# IOP3xx Implementation Options
+# IOP33x Implementation Options
#
#
-# IOP3xx Platform Types
+# IOP33x Platform Types
#
-# CONFIG_ARCH_IQ80321 is not set
-# CONFIG_ARCH_IQ31244 is not set
-# CONFIG_ARCH_IQ80331 is not set
+CONFIG_ARCH_IQ80331=y
CONFIG_MACH_IQ80332=y
-# CONFIG_ARCH_EP80219 is not set
-CONFIG_ARCH_IOP331=y
-
-#
-# IOP3xx Chipset Features
-#
-# CONFIG_IOP331_STEPD is not set
+CONFIG_PLAT_IOP=y
#
# Processor Type
@@ -109,7 +139,6 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
#
# Processor Features
@@ -121,8 +150,7 @@ CONFIG_XSCALE_PMU=y
# Bus support
#
CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -133,6 +161,19 @@ CONFIG_PCI_NAMES=y
# Kernel Features
#
# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
CONFIG_ALIGNMENT_TRAP=y
#
@@ -140,7 +181,7 @@ CONFIG_ALIGNMENT_TRAP=y
#
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
+CONFIG_CMDLINE="console=ttyS0,115200 root=/dev/nfs ip=bootp"
# CONFIG_XIP_KERNEL is not set
#
@@ -166,6 +207,93 @@ CONFIG_BINFMT_AOUT=y
# Power management options
#
# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -177,6 +305,13 @@ CONFIG_BINFMT_AOUT=y
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -200,6 +335,7 @@ CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
#
# RAM/ROM/Flash chip drivers
@@ -222,6 +358,7 @@ CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
CONFIG_MTD_CFI_INTELEXT=y
# CONFIG_MTD_CFI_AMDSTD is not set
# CONFIG_MTD_CFI_STAA is not set
@@ -229,18 +366,18 @@ CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0xc0000000
-CONFIG_MTD_PHYSMAP_LEN=0x00800000
+CONFIG_MTD_PHYSMAP_START=0x0
+CONFIG_MTD_PHYSMAP_LEN=0x0
CONFIG_MTD_PHYSMAP_BANKWIDTH=1
# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -249,7 +386,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
@@ -265,6 +401,11 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
# CONFIG_MTD_NAND is not set
#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
# Parallel port support
#
# CONFIG_PARPORT is not set
@@ -276,7 +417,6 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -288,17 +428,9 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -309,6 +441,7 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
CONFIG_SCSI_PROC_FS=y
@@ -320,6 +453,7 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -334,10 +468,12 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -348,25 +484,19 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
@@ -381,8 +511,7 @@ CONFIG_MD_LINEAR=y
CONFIG_MD_RAID0=y
CONFIG_MD_RAID1=y
# CONFIG_MD_RAID10 is not set
-CONFIG_MD_RAID5=y
-# CONFIG_MD_RAID6 is not set
+# CONFIG_MD_RAID456 is not set
# CONFIG_MD_MULTIPATH is not set
# CONFIG_MD_FAULTY is not set
CONFIG_BLK_DEV_DM=y
@@ -396,6 +525,9 @@ CONFIG_BLK_DEV_DM=y
# Fusion MPT device support
#
# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
@@ -408,71 +540,8 @@ CONFIG_BLK_DEV_DM=y
# CONFIG_I2O is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
+# Network device support
#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -485,6 +554,10 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+
+#
# Ethernet (10 or 100Mbit)
#
# CONFIG_NET_ETHERNET is not set
@@ -501,14 +574,20 @@ CONFIG_E1000_NAPI=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -531,6 +610,8 @@ CONFIG_E1000_NAPI=y
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -568,7 +649,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -576,6 +656,7 @@ CONFIG_SOUND_GAMEPORT=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -583,7 +664,9 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
@@ -591,6 +674,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -604,8 +688,8 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -620,6 +704,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# TPM devices
#
# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -644,14 +729,13 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
CONFIG_I2C_IOP3XX=y
-# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
@@ -662,15 +746,45 @@ CONFIG_I2C_IOP3XX=y
# CONFIG_I2C_PCA_ISA is not set
#
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
#
-# CONFIG_I2C_SENSOR is not set
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
# CONFIG_SENSORS_GL518SM is not set
@@ -685,36 +799,45 @@ CONFIG_I2C_IOP3XX=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
-# Other I2C Chip support
+# Misc devices
#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
#
-# Misc devices
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
#
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -724,6 +847,7 @@ CONFIG_I2C_IOP3XX=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
@@ -731,6 +855,7 @@ CONFIG_I2C_IOP3XX=y
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -742,9 +867,14 @@ CONFIG_DUMMY_CONSOLE=y
#
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_USB is not set
#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -755,10 +885,17 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -768,22 +905,22 @@ CONFIG_JBD=y
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
CONFIG_XFS_FS=y
-CONFIG_XFS_EXPORT=y
-# CONFIG_XFS_RT is not set
# CONFIG_XFS_QUOTA is not set
CONFIG_XFS_SECURITY=y
CONFIG_XFS_POSIX_ACL=y
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -803,12 +940,10 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -834,16 +969,19 @@ CONFIG_RAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
# CONFIG_NFSD_TCP is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -852,6 +990,7 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -871,6 +1010,7 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
#
@@ -887,11 +1027,34 @@ CONFIG_MSDOS_PARTITION=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS 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 is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
#
# Security options
@@ -912,5 +1075,7 @@ CONFIG_DEBUG_USER=y
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
# CONFIG_CRC32 is not set
# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
diff --git a/arch/arm/configs/iq31244_defconfig b/arch/arm/configs/iq31244_defconfig
deleted file mode 100644
index 32467160a6df..000000000000
--- a/arch/arm/configs/iq31244_defconfig
+++ /dev/null
@@ -1,922 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 02:10:38 2005
-#
-CONFIG_ARM=y
-CONFIG_MMU=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# System Type
-#
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-CONFIG_ARCH_IOP3XX=y
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-
-#
-# IOP3xx Implementation Options
-#
-
-#
-# IOP3xx Platform Types
-#
-# CONFIG_ARCH_IQ80321 is not set
-CONFIG_ARCH_IQ31244=y
-# CONFIG_ARCH_IQ80331 is not set
-# CONFIG_MACH_IQ80332 is not set
-# CONFIG_ARCH_EP80219 is not set
-CONFIG_ARCH_IOP321=y
-# CONFIG_ARCH_IOP331 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_XSCALE=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
-
-#
-# Processor Features
-#
-# CONFIG_ARM_THUMB is not set
-CONFIG_XSCALE_PMU=y
-
-#
-# Bus support
-#
-CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Kernel Features
-#
-# CONFIG_PREEMPT is not set
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-# CONFIG_XIP_KERNEL is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
-# CONFIG_FPE_FASTFPE is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
-
-#
-# Power management options
-#
-# CONFIG_PM is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-# CONFIG_MTD_CMDLINE_PARTS is not set
-# CONFIG_MTD_AFS_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0xf0000000
-CONFIG_MTD_PHYSMAP_LEN=0x00800000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-CONFIG_SCSI=y
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_CHR_DEV_OSST is not set
-# CONFIG_BLK_DEV_SR is not set
-CONFIG_CHR_DEV_SG=y
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-# CONFIG_SCSI_MULTI_LUN is not set
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-
-#
-# SCSI Transport Attributes
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-
-#
-# SCSI low-level drivers
-#
-# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_3W_9XXX is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AACRAID is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_AIC7XXX_OLD is not set
-# CONFIG_SCSI_AIC79XX is not set
-# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_MEGARAID_NEWGEN is not set
-# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_IPS is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_DC395x is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_NSP32 is not set
-# CONFIG_SCSI_DEBUG is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=y
-# CONFIG_MD_LINEAR is not set
-CONFIG_MD_RAID0=y
-CONFIG_MD_RAID1=y
-# CONFIG_MD_RAID10 is not set
-CONFIG_MD_RAID5=y
-# CONFIG_MD_RAID6 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_MD_FAULTY is not set
-CONFIG_BLK_DEV_DM=y
-# CONFIG_DM_CRYPT is not set
-# CONFIG_DM_SNAPSHOT is not set
-# CONFIG_DM_MIRROR is not set
-# CONFIG_DM_ZERO is not set
-# CONFIG_DM_MULTIPATH is not set
-
-#
-# Fusion MPT device support
-#
-# CONFIG_FUSION is not set
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=y
-CONFIG_E1000_NAPI=y
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_FC is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-CONFIG_I2C_IOP3XX=y
-# CONFIG_I2C_ISA is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
-
-#
-# Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
-CONFIG_XFS_FS=y
-CONFIG_XFS_EXPORT=y
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_QUOTA is not set
-CONFIG_XFS_SECURITY=y
-CONFIG_XFS_POSIX_ACL=y
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_RTIME=y
-# CONFIG_JFFS2_RUBIN is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V4 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/iq80321_defconfig b/arch/arm/configs/iq80321_defconfig
deleted file mode 100644
index b000da753c41..000000000000
--- a/arch/arm/configs/iq80321_defconfig
+++ /dev/null
@@ -1,843 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 13:24:10 2005
-#
-CONFIG_ARM=y
-CONFIG_MMU=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
-# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# System Type
-#
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-CONFIG_ARCH_IOP3XX=y
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-
-#
-# IOP3xx Implementation Options
-#
-
-#
-# IOP3xx Platform Types
-#
-CONFIG_ARCH_IQ80321=y
-# CONFIG_ARCH_IQ31244 is not set
-# CONFIG_ARCH_IQ80331 is not set
-# CONFIG_MACH_IQ80332 is not set
-# CONFIG_ARCH_EP80219 is not set
-CONFIG_ARCH_IOP321=y
-# CONFIG_ARCH_IOP331 is not set
-
-#
-# IOP3xx Chipset Features
-#
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_XSCALE=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
-
-#
-# Processor Features
-#
-# CONFIG_ARM_THUMB is not set
-CONFIG_XSCALE_PMU=y
-
-#
-# Bus support
-#
-CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# Kernel Features
-#
-# CONFIG_PREEMPT is not set
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-# CONFIG_XIP_KERNEL is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
-# CONFIG_FPE_FASTFPE is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
-
-#
-# Power management options
-#
-# CONFIG_PM is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-# CONFIG_MTD_CMDLINE_PARTS is not set
-# CONFIG_MTD_AFS_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=y
-# CONFIG_MTD_CFI_ADV_OPTIONS is not set
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0xf0000000
-CONFIG_MTD_PHYSMAP_LEN=0x00800000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=1
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-# CONFIG_IDE is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-# CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
-CONFIG_NETDEVICES=y
-# CONFIG_DUMMY is not set
-# CONFIG_BONDING is not set
-# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
-
-#
-# ARCnet devices
-#
-# CONFIG_ARCNET is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
-# CONFIG_NET_ETHERNET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-CONFIG_E1000=y
-CONFIG_E1000_NAPI=y
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
-
-#
-# Ethernet (10000 Mbit)
-#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-# CONFIG_NET_RADIO is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input Device Drivers
-#
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Hardware I/O ports
-#
-# CONFIG_SERIO is not set
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
-
-#
-# Non-8250 serial port support
-#
-CONFIG_SERIAL_CORE=y
-CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-
-#
-# I2C Algorithms
-#
-# CONFIG_I2C_ALGOBIT is not set
-# CONFIG_I2C_ALGOPCF is not set
-# CONFIG_I2C_ALGOPCA is not set
-
-#
-# I2C Hardware Bus support
-#
-# CONFIG_I2C_ALI1535 is not set
-# CONFIG_I2C_ALI1563 is not set
-# CONFIG_I2C_ALI15X3 is not set
-# CONFIG_I2C_AMD756 is not set
-# CONFIG_I2C_AMD8111 is not set
-# CONFIG_I2C_I801 is not set
-# CONFIG_I2C_I810 is not set
-CONFIG_I2C_IOP3XX=y
-# CONFIG_I2C_ISA is not set
-# CONFIG_I2C_NFORCE2 is not set
-# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
-# CONFIG_I2C_PROSAVAGE is not set
-# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
-# CONFIG_I2C_SIS5595 is not set
-# CONFIG_I2C_SIS630 is not set
-# CONFIG_I2C_SIS96X is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_VIA is not set
-# CONFIG_I2C_VIAPRO is not set
-# CONFIG_I2C_VOODOO3 is not set
-# CONFIG_I2C_PCA_ISA is not set
-
-#
-# Hardware Sensors Chip support
-#
-# CONFIG_I2C_SENSOR is not set
-# CONFIG_SENSORS_ADM1021 is not set
-# CONFIG_SENSORS_ADM1025 is not set
-# CONFIG_SENSORS_ADM1026 is not set
-# CONFIG_SENSORS_ADM1031 is not set
-# CONFIG_SENSORS_ASB100 is not set
-# CONFIG_SENSORS_DS1621 is not set
-# CONFIG_SENSORS_FSCHER is not set
-# CONFIG_SENSORS_FSCPOS is not set
-# CONFIG_SENSORS_GL518SM is not set
-# CONFIG_SENSORS_GL520SM is not set
-# CONFIG_SENSORS_IT87 is not set
-# CONFIG_SENSORS_LM63 is not set
-# CONFIG_SENSORS_LM75 is not set
-# CONFIG_SENSORS_LM77 is not set
-# CONFIG_SENSORS_LM78 is not set
-# CONFIG_SENSORS_LM80 is not set
-# CONFIG_SENSORS_LM83 is not set
-# CONFIG_SENSORS_LM85 is not set
-# CONFIG_SENSORS_LM87 is not set
-# CONFIG_SENSORS_LM90 is not set
-# CONFIG_SENSORS_MAX1619 is not set
-# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
-# CONFIG_SENSORS_SIS5595 is not set
-# CONFIG_SENSORS_SMSC47M1 is not set
-# CONFIG_SENSORS_VIA686A is not set
-# CONFIG_SENSORS_W83781D is not set
-# CONFIG_SENSORS_W83L785TS is not set
-# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-CONFIG_EXT3_FS=y
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
-CONFIG_JBD=y
-# CONFIG_JBD_DEBUG is not set
-CONFIG_FS_MBCACHE=y
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
-CONFIG_XFS_FS=y
-CONFIG_XFS_EXPORT=y
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_QUOTA is not set
-CONFIG_XFS_SECURITY=y
-CONFIG_XFS_POSIX_ACL=y
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-CONFIG_JFFS2_FS=y
-CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
-# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
-CONFIG_JFFS2_ZLIB=y
-CONFIG_JFFS2_RTIME=y
-# CONFIG_JFFS2_RUBIN is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Network File Systems
-#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V4 is not set
-# CONFIG_NFSD_TCP is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-# CONFIG_SMB_FS is not set
-# CONFIG_CIFS is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
-
-#
-# Partition Types
-#
-CONFIG_PARTITION_ADVANCED=y
-# CONFIG_ACORN_PARTITION is not set
-# CONFIG_OSF_PARTITION is not set
-# CONFIG_AMIGA_PARTITION is not set
-# CONFIG_ATARI_PARTITION is not set
-# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
-# CONFIG_LDM_PARTITION is not set
-# CONFIG_SGI_PARTITION is not set
-# CONFIG_ULTRIX_PARTITION is not set
-# CONFIG_SUN_PARTITION is not set
-# CONFIG_EFI_PARTITION is not set
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
-CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/arm/configs/kafa_defconfig b/arch/arm/configs/kafa_defconfig
index 1db633e2c940..54fcd75779da 100644
--- a/arch/arm/configs/kafa_defconfig
+++ b/arch/arm/configs/kafa_defconfig
@@ -536,9 +536,9 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/kb9202_defconfig b/arch/arm/configs/kb9202_defconfig
index 45396e087196..b4cd4b414836 100644
--- a/arch/arm/configs/kb9202_defconfig
+++ b/arch/arm/configs/kb9202_defconfig
@@ -418,8 +418,8 @@ CONFIG_HW_CONSOLE=y
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/onearm_defconfig b/arch/arm/configs/onearm_defconfig
index 6a93e3aae106..cb1d94f9049e 100644
--- a/arch/arm/configs/onearm_defconfig
+++ b/arch/arm/configs/onearm_defconfig
@@ -583,9 +583,9 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index f20814e6f497..a83222641045 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -1,14 +1,19 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17-git9
-# Sun Jun 25 23:56:32 2006
+# Linux kernel version: 2.6.18
+# Wed Sep 20 20:27:31 2006
#
CONFIG_ARM=y
CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
@@ -26,14 +31,15 @@ CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -46,6 +52,8 @@ CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -84,7 +92,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_REALVIEW is not set
# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_AT91 is not set
# CONFIG_ARCH_CLPS7500 is not set
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
@@ -94,7 +102,8 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_NETX is not set
# CONFIG_ARCH_H720X is not set
# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
# CONFIG_ARCH_IXP4XX is not set
# CONFIG_ARCH_IXP2000 is not set
# CONFIG_ARCH_IXP23XX is not set
@@ -122,13 +131,18 @@ CONFIG_ARCH_SMDK2410=y
CONFIG_ARCH_S3C2440=y
CONFIG_SMDK2440_CPU2440=y
CONFIG_SMDK2440_CPU2442=y
+CONFIG_MACH_S3C2413=y
CONFIG_MACH_SMDK2413=y
CONFIG_MACH_VR1000=y
CONFIG_MACH_RX3715=y
CONFIG_MACH_OTOM=y
CONFIG_MACH_NEXCODER_2440=y
+CONFIG_MACH_VSTMS=y
CONFIG_S3C2410_CLOCK=y
+CONFIG_S3C2410_PM=y
+CONFIG_CPU_S3C2410_DMA=y
CONFIG_CPU_S3C2410=y
+CONFIG_S3C2412_PM=y
CONFIG_CPU_S3C2412=y
CONFIG_CPU_S3C244X=y
CONFIG_CPU_S3C2440=y
@@ -156,7 +170,7 @@ CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
CONFIG_CPU_32=y
CONFIG_CPU_ARM920T=y
CONFIG_CPU_ARM926T=y
-CONFIG_CPU_32v4=y
+CONFIG_CPU_32v4T=y
CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV4T=y
CONFIG_CPU_ABRT_EV5TJ=y
@@ -200,6 +214,7 @@ CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
CONFIG_ALIGNMENT_TRAP=y
#
@@ -304,7 +319,6 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -460,6 +474,7 @@ 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
CONFIG_ATA_OVER_ETH=m
@@ -640,6 +655,7 @@ CONFIG_SERIO_LIBPS2=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_COMPUTONE is not set
# CONFIG_ROCKETPORT is not set
@@ -716,6 +732,7 @@ CONFIG_S3C2410_WATCHDOG=y
# USB-based Watchdog Cards
#
# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=y
# CONFIG_NVRAM is not set
CONFIG_S3C2410_RTC=y
# CONFIG_DTLK is not set
@@ -857,12 +874,12 @@ CONFIG_VIDEO_V4L2=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_MACMODES is not set
-CONFIG_FB_FIRMWARE_EDID=y
# CONFIG_FB_BACKLIGHT is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
@@ -995,7 +1012,7 @@ CONFIG_USB_MON=y
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
-# CONFIG_USB_CY7C63 is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
@@ -1095,6 +1112,7 @@ CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
CONFIG_JFFS2_FS_WRITEBUFFER=y
# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_RTIME=y
@@ -1202,14 +1220,19 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# CONFIG_PRINTK_TIME is not set
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_MUTEXES=y
+# 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 is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
CONFIG_DEBUG_INFO=y
@@ -1251,3 +1274,4 @@ CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/arm/kernel/apm.c b/arch/arm/kernel/apm.c
index 33c55689f999..ecf4f9472d94 100644
--- a/arch/arm/kernel/apm.c
+++ b/arch/arm/kernel/apm.c
@@ -25,6 +25,7 @@
#include <linux/list.h>
#include <linux/init.h>
#include <linux/completion.h>
+#include <linux/kthread.h>
#include <asm/apm.h> /* apm_power_info */
#include <asm/system.h>
@@ -80,7 +81,7 @@ struct apm_user {
*/
static int suspends_pending;
static int apm_disabled;
-static int arm_apm_active;
+static struct task_struct *kapmd_tsk;
static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
@@ -97,7 +98,6 @@ static LIST_HEAD(apm_user_list);
* to be suspending the system.
*/
static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
-static DECLARE_COMPLETION(kapmd_exit);
static DEFINE_SPINLOCK(kapmd_queue_lock);
static struct apm_queue kapmd_queue;
@@ -468,16 +468,13 @@ static int apm_get_info(char *buf, char **start, off_t fpos, int length)
static int kapmd(void *arg)
{
- daemonize("kapmd");
- current->flags |= PF_NOFREEZE;
-
do {
apm_event_t event;
wait_event_interruptible(kapmd_wait,
- !queue_empty(&kapmd_queue) || !arm_apm_active);
+ !queue_empty(&kapmd_queue) || kthread_should_stop());
- if (!arm_apm_active)
+ if (kthread_should_stop())
break;
spin_lock_irq(&kapmd_queue_lock);
@@ -508,7 +505,7 @@ static int kapmd(void *arg)
}
} while (1);
- complete_and_exit(&kapmd_exit, 0);
+ return 0;
}
static int __init apm_init(void)
@@ -520,13 +517,14 @@ static int __init apm_init(void)
return -ENODEV;
}
- arm_apm_active = 1;
-
- ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
- if (ret < 0) {
- arm_apm_active = 0;
+ kapmd_tsk = kthread_create(kapmd, NULL, "kapmd");
+ if (IS_ERR(kapmd_tsk)) {
+ ret = PTR_ERR(kapmd_tsk);
+ kapmd_tsk = NULL;
return ret;
}
+ kapmd_tsk->flags |= PF_NOFREEZE;
+ wake_up_process(kapmd_tsk);
#ifdef CONFIG_PROC_FS
create_proc_info_entry("apm", 0, NULL, apm_get_info);
@@ -535,10 +533,7 @@ static int __init apm_init(void)
ret = misc_register(&apm_device);
if (ret != 0) {
remove_proc_entry("apm", NULL);
-
- arm_apm_active = 0;
- wake_up(&kapmd_wait);
- wait_for_completion(&kapmd_exit);
+ kthread_stop(kapmd_tsk);
}
return ret;
@@ -549,9 +544,7 @@ static void __exit apm_exit(void)
misc_deregister(&apm_device);
remove_proc_entry("apm", NULL);
- arm_apm_active = 0;
- wake_up(&kapmd_wait);
- wait_for_completion(&kapmd_exit);
+ kthread_stop(kapmd_tsk);
}
module_init(apm_init);
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index da69e660574b..4779f474f911 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -178,9 +178,3 @@ EXPORT_SYMBOL(_find_next_zero_bit_be);
EXPORT_SYMBOL(_find_first_bit_be);
EXPORT_SYMBOL(_find_next_bit_be);
#endif
-
- /* syscalls */
-EXPORT_SYMBOL(sys_write);
-EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_exit);
-EXPORT_SYMBOL(sys_wait4);
diff --git a/arch/arm/kernel/crunch.c b/arch/arm/kernel/crunch.c
index 748175921f9b..cec83783206e 100644
--- a/arch/arm/kernel/crunch.c
+++ b/arch/arm/kernel/crunch.c
@@ -10,7 +10,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/signal.h>
diff --git a/arch/arm/kernel/debug.S b/arch/arm/kernel/debug.S
index a5747e58a9dc..5617566477b4 100644
--- a/arch/arm/kernel/debug.S
+++ b/arch/arm/kernel/debug.S
@@ -21,6 +21,36 @@
#if defined(CONFIG_DEBUG_ICEDCC)
@@ debug using ARM EmbeddedICE DCC channel
+
+#if defined(CONFIG_CPU_V6)
+
+ .macro addruart, rx
+ .endm
+
+ .macro senduart, rd, rx
+ mcr p14, 0, \rd, c0, c5, 0
+ .endm
+
+ .macro busyuart, rd, rx
+1001:
+ mrc p14, 0, \rx, c0, c1, 0
+ tst \rx, #0x20000000
+ beq 1001b
+ .endm
+
+ .macro waituart, rd, rx
+ mov \rd, #0x2000000
+1001:
+ subs \rd, \rd, #1
+ bmi 1002f
+ mrc p14, 0, \rx, c0, c1, 0
+ tst \rx, #0x20000000
+ bne 1001b
+1002:
+ .endm
+
+#else
+
.macro addruart, rx
.endm
@@ -46,9 +76,12 @@
bne 1001b
1002:
.endm
+
+#endif /* CONFIG_CPU_V6 */
+
#else
#include <asm/arch/debug-macro.S>
-#endif
+#endif /* CONFIG_DEBUG_ICEDCC */
/*
* Useful debugging routines
diff --git a/arch/arm/kernel/ecard.c b/arch/arm/kernel/ecard.c
index eca248d9eba4..b27513a0f11e 100644
--- a/arch/arm/kernel/ecard.c
+++ b/arch/arm/kernel/ecard.c
@@ -295,7 +295,7 @@ ecard_task(void * unused)
*/
static void ecard_call(struct ecard_request *req)
{
- DECLARE_COMPLETION(completion);
+ DECLARE_COMPLETION_ONSTACK(completion);
req->complete = &completion;
@@ -567,7 +567,7 @@ static void ecard_check_lockup(struct irqdesc *desc)
}
static void
-ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+ecard_irq_handler(unsigned int irq, struct irqdesc *desc)
{
ecard_t *ec;
int called = 0;
@@ -586,7 +586,7 @@ ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
if (pending) {
struct irqdesc *d = irq_desc + ec->irq;
- desc_handle_irq(ec->irq, d, regs);
+ desc_handle_irq(ec->irq, d);
called ++;
}
}
@@ -609,7 +609,7 @@ static unsigned char first_set[] =
};
static void
-ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc)
{
const unsigned int statusmask = 15;
unsigned int status;
@@ -633,7 +633,7 @@ ecard_irqexp_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
* Serial cards should go in 0/1, ethernet/scsi in 2/3
* otherwise you will lose serial data at high speeds!
*/
- desc_handle_irq(ec->irq, d, regs);
+ desc_handle_irq(ec->irq, d);
} else {
printk(KERN_WARNING "card%d: interrupt from unclaimed "
"card???\n", slot);
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index de4e33137901..bd623b73445f 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -191,6 +191,9 @@ __dabt_svc:
__irq_svc:
svc_entry
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl trace_hardirqs_off
+#endif
#ifdef CONFIG_PREEMPT
get_thread_info tsk
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
@@ -211,6 +214,10 @@ preempt_return:
#endif
ldr r0, [sp, #S_PSR] @ irqs are already disabled
msr spsr_cxsf, r0
+#ifdef CONFIG_TRACE_IRQFLAGS
+ tst r0, #PSR_I_BIT
+ bleq trace_hardirqs_on
+#endif
ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr
.ltorg
@@ -398,6 +405,9 @@ __dabt_usr:
__irq_usr:
usr_entry
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl trace_hardirqs_off
+#endif
get_thread_info tsk
#ifdef CONFIG_PREEMPT
ldr r8, [tsk, #TI_PREEMPT] @ get preempt count
@@ -412,6 +422,9 @@ __irq_usr:
teq r0, r7
strne r0, [r0, -r0]
#endif
+#ifdef CONFIG_TRACE_IRQFLAGS
+ bl trace_hardirqs_on
+#endif
mov why, #0
b ret_to_user
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index ac9eb3d30518..f359a189dcf2 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -9,7 +9,6 @@
* published by the Free Software Foundation.
*
* Common kernel startup code (non-paged MM)
- * for 32-bit CPUs which has a process ID register(CP15).
*
*/
#include <linux/linkage.h>
@@ -40,7 +39,11 @@
ENTRY(stext)
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
@ and irqs disabled
+#ifndef CONFIG_CPU_CP15
+ ldr r9, =CONFIG_PROCESSOR_ID
+#else
mrc p15, 0, r9, c0, c0 @ get processor id
+#endif
bl __lookup_processor_type @ r5=procinfo r9=cpuid
movs r10, r5 @ invalid processor (r5=0)?
beq __error_p @ yes, error 'p'
@@ -58,6 +61,7 @@ ENTRY(stext)
*/
.type __after_proc_init, %function
__after_proc_init:
+#ifdef CONFIG_CPU_CP15
mrc p15, 0, r0, c1, c0, 0 @ read control reg
#ifdef CONFIG_ALIGNMENT_TRAP
orr r0, r0, #CR_A
@@ -73,7 +77,13 @@ __after_proc_init:
#ifdef CONFIG_CPU_ICACHE_DISABLE
bic r0, r0, #CR_I
#endif
+#ifdef CONFIG_CPU_HIGH_VECTOR
+ orr r0, r0, #CR_V
+#else
+ bic r0, r0, #CR_V
+#endif
mcr p15, 0, r0, c1, c0, 0 @ write control reg
+#endif /* CONFIG_CPU_CP15 */
mov pc, r13 @ clear the BSS and jump
@ to start_kernel
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 5365d4e5949e..ebc3e74a7947 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -234,18 +234,18 @@ __create_page_tables:
/*
* Now setup the pagetables for our kernel direct
- * mapped region. We round TEXTADDR down to the
- * nearest megabyte boundary. It is assumed that
- * the kernel fits within 4 contigous 1MB sections.
+ * mapped region.
*/
add r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
str r3, [r0, #(TEXTADDR & 0x00f00000) >> 18]!
- add r3, r3, #1 << 20
- str r3, [r0, #4]! @ KERNEL + 1MB
- add r3, r3, #1 << 20
- str r3, [r0, #4]! @ KERNEL + 2MB
- add r3, r3, #1 << 20
- str r3, [r0, #4] @ KERNEL + 3MB
+
+ ldr r6, =(_end - PAGE_OFFSET - 1) @ r6 = number of sections
+ mov r6, r6, lsr #20 @ needed for kernel minus 1
+
+1: add r3, r3, #1 << 20
+ str r3, [r0, #4]!
+ subs r6, r6, #1
+ bgt 1b
/*
* Then map first 1MB of ram in case it contains our boot params.
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 2e1bf830fe11..2c4ff1cbe334 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -111,6 +111,7 @@ static struct irq_desc bad_irq_desc = {
*/
asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
struct irqdesc *desc = irq_desc + irq;
/*
@@ -122,12 +123,13 @@ asmlinkage void asm_do_IRQ(unsigned int irq, struct pt_regs *regs)
irq_enter();
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
/* AT91 specific workaround */
irq_finish(irq);
irq_exit();
+ set_irq_regs(old_regs);
}
void set_irq_flags(unsigned int irq, unsigned int iflags)
diff --git a/arch/arm/kernel/iwmmxt-notifier.c b/arch/arm/kernel/iwmmxt-notifier.c
index 44a86c33796e..0d1a1db40062 100644
--- a/arch/arm/kernel/iwmmxt-notifier.c
+++ b/arch/arm/kernel/iwmmxt-notifier.c
@@ -15,7 +15,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/signal.h>
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 298363d97047..1b061583408e 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -2,6 +2,7 @@
* linux/arch/arm/kernel/module.c
*
* Copyright (C) 2002 Russell King.
+ * Modified for nommu by Hyok S. Choi
*
* 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
@@ -32,6 +33,7 @@ extern void _etext;
#define MODULE_START (((unsigned long)&_etext + ~PGDIR_MASK) & PGDIR_MASK)
#endif
+#ifdef CONFIG_MMU
void *module_alloc(unsigned long size)
{
struct vm_struct *area;
@@ -46,6 +48,12 @@ void *module_alloc(unsigned long size)
return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL);
}
+#else /* CONFIG_MMU */
+void *module_alloc(unsigned long size)
+{
+ return size == 0 ? NULL : vmalloc(size);
+}
+#endif /* !CONFIG_MMU */
void module_free(struct module *module, void *region)
{
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 3079535afccd..bf35c178a877 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -221,16 +221,26 @@ void __show_regs(struct pt_regs *regs)
processor_modes[processor_mode(regs)],
thumb_mode(regs) ? " (T)" : "",
get_fs() == get_ds() ? "kernel" : "user");
+#if CONFIG_CPU_CP15
{
- unsigned int ctrl, transbase, dac;
+ unsigned int ctrl;
__asm__ (
" mrc p15, 0, %0, c1, c0\n"
- " mrc p15, 0, %1, c2, c0\n"
- " mrc p15, 0, %2, c3, c0\n"
- : "=r" (ctrl), "=r" (transbase), "=r" (dac));
- printk("Control: %04X Table: %08X DAC: %08X\n",
- ctrl, transbase, dac);
+ : "=r" (ctrl));
+ printk("Control: %04X\n", ctrl);
}
+#ifdef CONFIG_CPU_CP15_MMU
+ {
+ unsigned int transbase, dac;
+ __asm__ (
+ " mrc p15, 0, %0, c2, c0\n"
+ " mrc p15, 0, %1, c3, c0\n"
+ : "=r" (transbase), "=r" (dac));
+ printk("Table: %08X DAC: %08X\n",
+ transbase, dac);
+ }
+#endif
+#endif
}
void show_regs(struct pt_regs * regs)
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 0a722e77c143..6bbd93dd186a 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -348,7 +348,7 @@ static void __init setup_processor(void)
cpu_name, processor_id, (int)processor_id & 15,
proc_arch[cpu_architecture()], cr_alignment);
- sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
+ sprintf(init_utsname()->machine, "%s%c", list->arch_name, ENDIANNESS);
sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
elf_hwcap = list->elf_hwcap;
#ifndef CONFIG_ARM_THUMB
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 68e9634d260a..421329f5e18e 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -36,7 +36,9 @@
* The online bitmask indicates that the CPU is up and running.
*/
cpumask_t cpu_possible_map;
+EXPORT_SYMBOL(cpu_possible_map);
cpumask_t cpu_online_map;
+EXPORT_SYMBOL(cpu_online_map);
/*
* as from 2.5, kernels no longer have an init_tasks structure
diff --git a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
index 8170af471439..00c18d35913c 100644
--- a/arch/arm/kernel/sys_arm.c
+++ b/arch/arm/kernel/sys_arm.c
@@ -279,7 +279,7 @@ out:
return error;
}
-long execve(const char *filename, char **argv, char **envp)
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
{
struct pt_regs regs;
int ret;
@@ -317,7 +317,7 @@ long execve(const char *filename, char **argv, char **envp)
out:
return ret;
}
-EXPORT_SYMBOL(execve);
+EXPORT_SYMBOL(kernel_execve);
/*
* Since loff_t is a 64 bit type we avoid a lot of ABI hastle
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index 09a67d771857..c03cab5c4c79 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -27,6 +27,7 @@
#include <linux/profile.h>
#include <linux/sysdev.h>
#include <linux/timer.h>
+#include <linux/irq.h>
#include <asm/leds.h>
#include <asm/thread_info.h>
@@ -37,8 +38,6 @@
*/
struct sys_timer *system_timer;
-extern unsigned long wall_jiffies;
-
/* this needs a better home */
DEFINE_SPINLOCK(rtc_lock);
@@ -69,10 +68,12 @@ EXPORT_SYMBOL(profile_pc);
*/
int (*set_rtc)(void);
+#ifndef CONFIG_GENERIC_TIME
static unsigned long dummy_gettimeoffset(void)
{
return 0;
}
+#endif
/*
* Scheduler clock - returns current time in nanosec units.
@@ -230,20 +231,16 @@ static inline void do_leds(void)
#define do_leds()
#endif
+#ifndef CONFIG_GENERIC_TIME
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long seq;
- unsigned long usec, sec, lost;
+ unsigned long usec, sec;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = system_timer->offset();
-
- lost = jiffies - wall_jiffies;
- if (lost)
- usec += lost * USECS_PER_JIFFY;
-
sec = xtime.tv_sec;
usec += xtime.tv_nsec / 1000;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
@@ -276,7 +273,6 @@ int do_settimeofday(struct timespec *tv)
* done, and then undo it!
*/
nsec -= system_timer->offset() * NSEC_PER_USEC;
- nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -291,6 +287,7 @@ int do_settimeofday(struct timespec *tv)
}
EXPORT_SYMBOL(do_settimeofday);
+#endif /* !CONFIG_GENERIC_TIME */
/**
* save_time_delta - Save the offset between system time and RTC time
@@ -328,12 +325,13 @@ EXPORT_SYMBOL(restore_time_delta);
/*
* Kernel system timer support.
*/
-void timer_tick(struct pt_regs *regs)
+void timer_tick(void)
{
- profile_tick(CPU_PROFILING, regs);
+ struct pt_regs *regs = get_irq_regs();
+ profile_tick(CPU_PROFILING);
do_leds();
do_set_rtc();
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
@@ -500,8 +498,10 @@ device_initcall(timer_init_sysfs);
void __init time_init(void)
{
+#ifndef CONFIG_GENERIC_TIME
if (system_timer->offset == NULL)
system_timer->offset = dummy_gettimeoffset;
+#endif
system_timer->init();
#ifdef CONFIG_NO_IDLE_HZ
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index aeeed806f991..bede380c07a9 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -191,7 +191,7 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
if (tsk != current)
fp = thread_saved_fp(tsk);
else
- asm("mov%? %0, fp" : "=r" (fp));
+ asm("mov %0, fp" : "=r" (fp) : : "cc");
c_backtrace(fp, 0x10);
barrier();
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
index baa997c857dc..fe3d297d682d 100644
--- a/arch/arm/mach-aaec2000/core.c
+++ b/arch/arm/mach-aaec2000/core.c
@@ -127,12 +127,12 @@ static unsigned long aaec2000_gettimeoffset(void)
/* We enter here with IRQs enabled */
static irqreturn_t
-aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+aaec2000_timer_interrupt(int irq, void *dev_id)
{
/* TODO: Check timer accuracy */
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
TIMER1_CLEAR = 1;
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-at91rm9200/at91rm9200.c b/arch/arm/mach-at91rm9200/at91rm9200.c
index 0985b1c42c7c..dcf6136fedf9 100644
--- a/arch/arm/mach-at91rm9200/at91rm9200.c
+++ b/arch/arm/mach-at91rm9200/at91rm9200.c
@@ -17,6 +17,7 @@
#include <asm/hardware.h>
#include "generic.h"
+#include "clock.h"
static struct map_desc at91rm9200_io_desc[] __initdata = {
{
@@ -26,87 +27,224 @@ static struct map_desc at91rm9200_io_desc[] __initdata = {
.type = MT_DEVICE,
}, {
.virtual = AT91_VA_BASE_SPI,
- .pfn = __phys_to_pfn(AT91_BASE_SPI),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_SSC2,
- .pfn = __phys_to_pfn(AT91_BASE_SSC2),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_SSC1,
- .pfn = __phys_to_pfn(AT91_BASE_SSC1),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_SSC0,
- .pfn = __phys_to_pfn(AT91_BASE_SSC0),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_US3,
- .pfn = __phys_to_pfn(AT91_BASE_US3),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_US2,
- .pfn = __phys_to_pfn(AT91_BASE_US2),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_US1,
- .pfn = __phys_to_pfn(AT91_BASE_US1),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_US0,
- .pfn = __phys_to_pfn(AT91_BASE_US0),
+ .pfn = __phys_to_pfn(AT91RM9200_BASE_SPI),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = AT91_VA_BASE_EMAC,
- .pfn = __phys_to_pfn(AT91_BASE_EMAC),
+ .pfn = __phys_to_pfn(AT91RM9200_BASE_EMAC),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = AT91_VA_BASE_TWI,
- .pfn = __phys_to_pfn(AT91_BASE_TWI),
+ .pfn = __phys_to_pfn(AT91RM9200_BASE_TWI),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = AT91_VA_BASE_MCI,
- .pfn = __phys_to_pfn(AT91_BASE_MCI),
+ .pfn = __phys_to_pfn(AT91RM9200_BASE_MCI),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = AT91_VA_BASE_UDP,
- .pfn = __phys_to_pfn(AT91_BASE_UDP),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_TCB1,
- .pfn = __phys_to_pfn(AT91_BASE_TCB1),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = AT91_VA_BASE_TCB0,
- .pfn = __phys_to_pfn(AT91_BASE_TCB0),
+ .pfn = __phys_to_pfn(AT91RM9200_BASE_UDP),
.length = SZ_16K,
.type = MT_DEVICE,
}, {
.virtual = AT91_SRAM_VIRT_BASE,
- .pfn = __phys_to_pfn(AT91_SRAM_BASE),
- .length = AT91_SRAM_SIZE,
+ .pfn = __phys_to_pfn(AT91RM9200_SRAM_BASE),
+ .length = AT91RM9200_SRAM_SIZE,
.type = MT_DEVICE,
},
};
-void __init at91rm9200_map_io(void)
+/* --------------------------------------------------------------------
+ * Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk udc_clk = {
+ .name = "udc_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_UDP,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ohci_clk = {
+ .name = "ohci_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_UHP,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ether_clk = {
+ .name = "ether_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_EMAC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc_clk = {
+ .name = "mci_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_MCI,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi_clk = {
+ .name = "twi_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_TWI,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+ .name = "usart0_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_US0,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+ .name = "usart1_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_US1,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+ .name = "usart2_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_US2,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart3_clk = {
+ .name = "usart3_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_US3,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi_clk = {
+ .name = "spi_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_SPI,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioA_clk = {
+ .name = "pioA_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_PIOA,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+ .name = "pioB_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_PIOB,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioC_clk = {
+ .name = "pioC_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_PIOC,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioD_clk = {
+ .name = "pioD_clk",
+ .pmc_mask = 1 << AT91RM9200_ID_PIOD,
+ .type = CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+ &pioA_clk,
+ &pioB_clk,
+ &pioC_clk,
+ &pioD_clk,
+ &usart0_clk,
+ &usart1_clk,
+ &usart2_clk,
+ &usart3_clk,
+ &mmc_clk,
+ &udc_clk,
+ &twi_clk,
+ &spi_clk,
+ // ssc 0 .. ssc2
+ // tc0 .. tc5
+ &ohci_clk,
+ &ether_clk,
+ // irq0 .. irq6
+};
+
+/*
+ * The four programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+ .name = "pck0",
+ .pmc_mask = AT91_PMC_PCK0,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 0,
+};
+static struct clk pck1 = {
+ .name = "pck1",
+ .pmc_mask = AT91_PMC_PCK1,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 1,
+};
+static struct clk pck2 = {
+ .name = "pck2",
+ .pmc_mask = AT91_PMC_PCK2,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 2,
+};
+static struct clk pck3 = {
+ .name = "pck3",
+ .pmc_mask = AT91_PMC_PCK3,
+ .type = CLK_TYPE_PROGRAMMABLE,
+ .id = 3,
+};
+
+static void __init at91rm9200_register_clocks(void)
{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+ clk_register(periph_clocks[i]);
+
+ clk_register(&pck0);
+ clk_register(&pck1);
+ clk_register(&pck2);
+ clk_register(&pck3);
+}
+
+/* --------------------------------------------------------------------
+ * GPIO
+ * -------------------------------------------------------------------- */
+
+static struct at91_gpio_bank at91rm9200_gpio[] = {
+ {
+ .id = AT91RM9200_ID_PIOA,
+ .offset = AT91_PIOA,
+ .clock = &pioA_clk,
+ }, {
+ .id = AT91RM9200_ID_PIOB,
+ .offset = AT91_PIOB,
+ .clock = &pioB_clk,
+ }, {
+ .id = AT91RM9200_ID_PIOC,
+ .offset = AT91_PIOC,
+ .clock = &pioC_clk,
+ }, {
+ .id = AT91RM9200_ID_PIOD,
+ .offset = AT91_PIOD,
+ .clock = &pioD_clk,
+ }
+};
+
+/* --------------------------------------------------------------------
+ * AT91RM9200 processor initialization
+ * -------------------------------------------------------------------- */
+void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks)
+{
+ /* Map peripherals */
iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
+
+ /* Init clock subsystem */
+ at91_clock_init(main_clock);
+
+ /* Register the processor-specific clocks */
+ at91rm9200_register_clocks();
+
+ /* Initialize GPIO subsystem */
+ at91_gpio_init(at91rm9200_gpio, banks);
}
+
+/* --------------------------------------------------------------------
+ * Interrupt initialization
+ * -------------------------------------------------------------------- */
+
/*
* The default interrupt priority levels (0 = lowest, 7 = highest).
*/
@@ -145,10 +283,14 @@ static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
0 /* Advanced Interrupt Controller (IRQ6) */
};
-void __init at91rm9200_init_irq(unsigned int priority[NR_AIC_IRQS])
+void __init at91rm9200_init_interrupts(unsigned int priority[NR_AIC_IRQS])
{
if (!priority)
priority = at91rm9200_default_irq_priority;
+ /* Initialize the AIC interrupt controller */
at91_aic_init(priority);
+
+ /* Enable GPIO interrupts */
+ at91_gpio_irq_setup();
}
diff --git a/arch/arm/mach-at91rm9200/at91rm9200_time.c b/arch/arm/mach-at91rm9200/at91rm9200_time.c
index a92a8622c78a..07c9cea8961d 100644
--- a/arch/arm/mach-at91rm9200/at91rm9200_time.c
+++ b/arch/arm/mach-at91rm9200/at91rm9200_time.c
@@ -65,13 +65,13 @@ static unsigned long at91rm9200_gettimeoffset(void)
/*
* IRQ handler for the timer.
*/
-static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t at91rm9200_timer_interrupt(int irq, void *dev_id)
{
if (at91_sys_read(AT91_ST_SR) & AT91_ST_PITS) { /* This is a shared interrupt */
write_seqlock(&xtime_lock);
while (((read_CRTR() - last_crtr) & AT91_ST_ALMV) >= LATCH) {
- timer_tick(regs);
+ timer_tick();
last_crtr = (last_crtr + LATCH) & AT91_ST_ALMV;
}
diff --git a/arch/arm/mach-at91rm9200/board-1arm.c b/arch/arm/mach-at91rm9200/board-1arm.c
index dc79e0992af7..971c3e2d8e36 100644
--- a/arch/arm/mach-at91rm9200/board-1arm.c
+++ b/arch/arm/mach-at91rm9200/board-1arm.c
@@ -18,7 +18,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
@@ -34,20 +33,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init onearm_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(PQFP_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -62,15 +52,18 @@ static struct at91_uart_config __initdata onearm_uart_config = {
static void __init onearm_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 18.432 MHz crystal */
- at91_clock_init(18432000);
+ /* Initialize processor: 18.432 MHz crystal */
+ at91rm9200_initialize(18432000, AT91RM9200_PQFP);
/* Setup the serial ports and console */
at91_init_serial(&onearm_uart_config);
}
+static void __init onearm_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata onearm_eth_data = {
.phy_irq_pin = AT91_PIN_PC4,
.is_rmii = 1,
diff --git a/arch/arm/mach-at91rm9200/board-carmeva.c b/arch/arm/mach-at91rm9200/board-carmeva.c
index 2c138b542ebe..98208740e7c5 100644
--- a/arch/arm/mach-at91rm9200/board-carmeva.c
+++ b/arch/arm/mach-at91rm9200/board-carmeva.c
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
@@ -35,20 +34,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init carmeva_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(BGA_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -63,15 +53,19 @@ static struct at91_uart_config __initdata carmeva_uart_config = {
static void __init carmeva_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 20.000 MHz crystal */
- at91_clock_init(20000000);
+ /* Initialize processor: 20.000 MHz crystal */
+ at91rm9200_initialize(20000000, AT91RM9200_BGA);
/* Setup the serial ports and console */
at91_init_serial(&carmeva_uart_config);
}
+static void __init carmeva_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
+
static struct at91_eth_data __initdata carmeva_eth_data = {
.phy_irq_pin = AT91_PIN_PC4,
.is_rmii = 1,
diff --git a/arch/arm/mach-at91rm9200/board-csb337.c b/arch/arm/mach-at91rm9200/board-csb337.c
index 794d3fbb449b..8eeae491ce71 100644
--- a/arch/arm/mach-at91rm9200/board-csb337.c
+++ b/arch/arm/mach-at91rm9200/board-csb337.c
@@ -34,20 +34,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init csb337_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(BGA_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -62,10 +53,8 @@ static struct at91_uart_config __initdata csb337_uart_config = {
static void __init csb337_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 3.6864 MHz crystal */
- at91_clock_init(3686400);
+ /* Initialize processor: 3.6864 MHz crystal */
+ at91rm9200_initialize(3686400, AT91RM9200_BGA);
/* Setup the LEDs */
at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
@@ -74,6 +63,11 @@ static void __init csb337_map_io(void)
at91_init_serial(&csb337_uart_config);
}
+static void __init csb337_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata csb337_eth_data = {
.phy_irq_pin = AT91_PIN_PC2,
.is_rmii = 0,
diff --git a/arch/arm/mach-at91rm9200/board-csb637.c b/arch/arm/mach-at91rm9200/board-csb637.c
index c8b6f334246a..a29fa0e822ce 100644
--- a/arch/arm/mach-at91rm9200/board-csb637.c
+++ b/arch/arm/mach-at91rm9200/board-csb637.c
@@ -33,20 +33,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init csb637_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(BGA_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -61,10 +52,8 @@ static struct at91_uart_config __initdata csb637_uart_config = {
static void __init csb637_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 3.6864 MHz crystal */
- at91_clock_init(3686400);
+ /* Initialize processor: 3.6864 MHz crystal */
+ at91rm9200_initialize(3686400, AT91RM9200_BGA);
/* Setup the LEDs */
at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
@@ -73,6 +62,11 @@ static void __init csb637_map_io(void)
at91_init_serial(&csb637_uart_config);
}
+static void __init csb637_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata csb637_eth_data = {
.phy_irq_pin = AT91_PIN_PC0,
.is_rmii = 0,
diff --git a/arch/arm/mach-at91rm9200/board-dk.c b/arch/arm/mach-at91rm9200/board-dk.c
index 65873037e02a..c699f3984d4b 100644
--- a/arch/arm/mach-at91rm9200/board-dk.c
+++ b/arch/arm/mach-at91rm9200/board-dk.c
@@ -37,20 +37,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init dk_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(BGA_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -65,10 +56,8 @@ static struct at91_uart_config __initdata dk_uart_config = {
static void __init dk_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 18.432 MHz crystal */
- at91_clock_init(18432000);
+ /* Initialize processor: 18.432 MHz crystal */
+ at91rm9200_initialize(18432000, AT91RM9200_BGA);
/* Setup the LEDs */
at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
@@ -77,6 +66,11 @@ static void __init dk_map_io(void)
at91_init_serial(&dk_uart_config);
}
+static void __init dk_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata dk_eth_data = {
.phy_irq_pin = AT91_PIN_PC4,
.is_rmii = 1,
@@ -128,6 +122,29 @@ static struct spi_board_info dk_spi_devices[] = {
#endif
};
+static struct mtd_partition __initdata dk_nand_partition[] = {
+ {
+ .name = "NAND Partition 1",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+{
+ *num_partitions = ARRAY_SIZE(dk_nand_partition);
+ return dk_nand_partition;
+}
+
+static struct at91_nand_data __initdata dk_nand_data = {
+ .ale = 22,
+ .cle = 21,
+ .det_pin = AT91_PIN_PB1,
+ .rdy_pin = AT91_PIN_PC2,
+ // .enable_pin = ... not there
+ .partition_info = nand_partitions,
+};
+
static void __init dk_board_init(void)
{
/* Serial */
@@ -153,6 +170,8 @@ static void __init dk_board_init(void)
at91_set_gpio_output(AT91_PIN_PB7, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
at91_add_device_mmc(&dk_mmc_data);
#endif
+ /* NAND */
+ at91_add_device_nand(&dk_nand_data);
/* VGA */
// dk_add_device_video();
}
diff --git a/arch/arm/mach-at91rm9200/board-eb9200.c b/arch/arm/mach-at91rm9200/board-eb9200.c
index a3e2df968a66..65e867ba2df3 100644
--- a/arch/arm/mach-at91rm9200/board-eb9200.c
+++ b/arch/arm/mach-at91rm9200/board-eb9200.c
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
@@ -35,20 +34,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init eb9200_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(BGA_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -63,15 +53,18 @@ static struct at91_uart_config __initdata eb9200_uart_config = {
static void __init eb9200_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 18.432 MHz crystal */
- at91_clock_init(18432000);
+ /* Initialize processor: 18.432 MHz crystal */
+ at91rm9200_initialize(18432000, AT91RM9200_BGA);
/* Setup the serial ports and console */
at91_init_serial(&eb9200_uart_config);
}
+static void __init eb9200_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata eb9200_eth_data = {
.phy_irq_pin = AT91_PIN_PC4,
.is_rmii = 1,
diff --git a/arch/arm/mach-at91rm9200/board-ek.c b/arch/arm/mach-at91rm9200/board-ek.c
index 868192351dda..830eb7932178 100644
--- a/arch/arm/mach-at91rm9200/board-ek.c
+++ b/arch/arm/mach-at91rm9200/board-ek.c
@@ -37,20 +37,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init ek_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(BGA_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -65,10 +56,8 @@ static struct at91_uart_config __initdata ek_uart_config = {
static void __init ek_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 18.432 MHz crystal */
- at91_clock_init(18432000);
+ /* Initialize processor: 18.432 MHz crystal */
+ at91rm9200_initialize(18432000, AT91RM9200_BGA);
/* Setup the LEDs */
at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
@@ -77,6 +66,11 @@ static void __init ek_map_io(void)
at91_init_serial(&ek_uart_config);
}
+static void __init ek_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata ek_eth_data = {
.phy_irq_pin = AT91_PIN_PC4,
.is_rmii = 1,
diff --git a/arch/arm/mach-at91rm9200/board-kafa.c b/arch/arm/mach-at91rm9200/board-kafa.c
index bf760c5e0c46..6ef3c4879829 100644
--- a/arch/arm/mach-at91rm9200/board-kafa.c
+++ b/arch/arm/mach-at91rm9200/board-kafa.c
@@ -18,7 +18,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
@@ -34,20 +33,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init kafa_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(PQFP_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -62,10 +52,8 @@ static struct at91_uart_config __initdata kafa_uart_config = {
static void __init kafa_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 18.432 MHz crystal */
- at91_clock_init(18432000);
+ /* Initialize processor: 18.432 MHz crystal */
+ at91rm9200_initialize(18432000, AT91RM9200_PQFP);
/* Set up the LEDs */
at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
@@ -74,6 +62,11 @@ static void __init kafa_map_io(void)
at91_init_serial(&kafa_uart_config);
}
+static void __init kafa_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata kafa_eth_data = {
.phy_irq_pin = AT91_PIN_PC4,
.is_rmii = 0,
diff --git a/arch/arm/mach-at91rm9200/board-kb9202.c b/arch/arm/mach-at91rm9200/board-kb9202.c
index f06d2b54cc9a..35a954a44b1b 100644
--- a/arch/arm/mach-at91rm9200/board-kb9202.c
+++ b/arch/arm/mach-at91rm9200/board-kb9202.c
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/mm.h>
@@ -35,20 +34,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include <asm/hardware.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include "generic.h"
-static void __init kb9202_init_irq(void)
-{
- /* Initialize AIC controller */
- at91rm9200_init_irq(NULL);
-
- /* Set up the GPIO interrupts */
- at91_gpio_irq_setup(PQFP_GPIO_BANKS);
-}
/*
* Serial port configuration.
@@ -63,10 +53,8 @@ static struct at91_uart_config __initdata kb9202_uart_config = {
static void __init kb9202_map_io(void)
{
- at91rm9200_map_io();
-
- /* Initialize clocks: 10 MHz crystal */
- at91_clock_init(10000000);
+ /* Initialize processor: 10 MHz crystal */
+ at91rm9200_initialize(10000000, AT91RM9200_PQFP);
/* Set up the LEDs */
at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
@@ -75,6 +63,11 @@ static void __init kb9202_map_io(void)
at91_init_serial(&kb9202_uart_config);
}
+static void __init kb9202_init_irq(void)
+{
+ at91rm9200_init_interrupts(NULL);
+}
+
static struct at91_eth_data __initdata kb9202_eth_data = {
.phy_irq_pin = AT91_PIN_PB29,
.is_rmii = 0,
@@ -95,6 +88,29 @@ static struct at91_mmc_data __initdata kb9202_mmc_data = {
.wire4 = 1,
};
+static struct mtd_partition __initdata kb9202_nand_partition[] = {
+ {
+ .name = "nand_fs",
+ .offset = 0,
+ .size = MTDPART_SIZ_FULL,
+ },
+};
+
+static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+{
+ *num_partitions = ARRAY_SIZE(kb9202_nand_partition);
+ return kb9202_nand_partition;
+}
+
+static struct at91_nand_data __initdata kb9202_nand_data = {
+ .ale = 22,
+ .cle = 21,
+ // .det_pin = ... not there
+ .rdy_pin = AT91_PIN_PC29,
+ .enable_pin = AT91_PIN_PC28,
+ .partition_info = nand_partitions,
+};
+
static void __init kb9202_board_init(void)
{
/* Serial */
@@ -111,6 +127,8 @@ static void __init kb9202_board_init(void)
at91_add_device_i2c();
/* SPI */
at91_add_device_spi(NULL, 0);
+ /* NAND */
+ at91_add_device_nand(&kb9202_nand_data);
}
MACHINE_START(KB9200, "KB920x")
diff --git a/arch/arm/mach-at91rm9200/clock.c b/arch/arm/mach-at91rm9200/clock.c
index edc2cc837ae6..a43b061a7c85 100644
--- a/arch/arm/mach-at91rm9200/clock.c
+++ b/arch/arm/mach-at91rm9200/clock.c
@@ -29,7 +29,7 @@
#include <asm/hardware.h>
-#include "generic.h"
+#include "clock.h"
/*
@@ -38,23 +38,15 @@
* PLLB be used at other rates (on boards that don't need USB), etc.
*/
-struct clk {
- const char *name; /* unique clock name */
- const char *function; /* function of the clock */
- struct device *dev; /* device associated with function */
- unsigned long rate_hz;
- struct clk *parent;
- u32 pmc_mask;
- void (*mode)(struct clk *, int);
- unsigned id:2; /* PCK0..3, or 32k/main/a/b */
- unsigned primary:1;
- unsigned pll:1;
- unsigned programmable:1;
- u16 users;
-};
+#define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY)
+#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE)
+#define clk_is_peripheral(x) ((x)->type & CLK_TYPE_PERIPHERAL)
+
+
+static LIST_HEAD(clocks);
+static DEFINE_SPINLOCK(clk_lock);
-static spinlock_t clk_lock;
-static u32 at91_pllb_usb_init;
+static u32 at91_pllb_usb_init;
/*
* Four primary clock sources: two crystal oscillators (32K, main), and
@@ -67,21 +59,20 @@ static struct clk clk32k = {
.rate_hz = AT91_SLOW_CLOCK,
.users = 1, /* always on */
.id = 0,
- .primary = 1,
+ .type = CLK_TYPE_PRIMARY,
};
static struct clk main_clk = {
.name = "main",
.pmc_mask = AT91_PMC_MOSCS, /* in PMC_SR */
.id = 1,
- .primary = 1,
+ .type = CLK_TYPE_PRIMARY,
};
static struct clk plla = {
.name = "plla",
.parent = &main_clk,
.pmc_mask = AT91_PMC_LOCKA, /* in PMC_SR */
.id = 2,
- .primary = 1,
- .pll = 1,
+ .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
};
static void pllb_mode(struct clk *clk, int is_on)
@@ -94,6 +85,7 @@ static void pllb_mode(struct clk *clk, int is_on)
} else
value = 0;
+ // REVISIT: Add work-around for AT91RM9200 Errata #26 ?
at91_sys_write(AT91_CKGR_PLLBR, value);
do {
@@ -107,8 +99,7 @@ static struct clk pllb = {
.pmc_mask = AT91_PMC_LOCKB, /* in PMC_SR */
.mode = pllb_mode,
.id = 3,
- .primary = 1,
- .pll = 1,
+ .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
};
static void pmc_sys_mode(struct clk *clk, int is_on)
@@ -133,41 +124,6 @@ static struct clk uhpck = {
.mode = pmc_sys_mode,
};
-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
-/*
- * The four programmable clocks can be parented by any primary clock.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .mode = pmc_sys_mode,
- .programmable = 1,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .mode = pmc_sys_mode,
- .programmable = 1,
- .id = 1,
-};
-static struct clk pck2 = {
- .name = "pck2",
- .pmc_mask = AT91_PMC_PCK2,
- .mode = pmc_sys_mode,
- .programmable = 1,
- .id = 2,
-};
-static struct clk pck3 = {
- .name = "pck3",
- .pmc_mask = AT91_PMC_PCK3,
- .mode = pmc_sys_mode,
- .programmable = 1,
- .id = 3,
-};
-#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
-
/*
* The master clock is divided from the CPU clock (by 1-4). It's used for
@@ -187,131 +143,21 @@ static void pmc_periph_mode(struct clk *clk, int is_on)
at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);
}
-static struct clk udc_clk = {
- .name = "udc_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_UDP,
- .mode = pmc_periph_mode,
-};
-static struct clk ohci_clk = {
- .name = "ohci_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_UHP,
- .mode = pmc_periph_mode,
-};
-static struct clk ether_clk = {
- .name = "ether_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_EMAC,
- .mode = pmc_periph_mode,
-};
-static struct clk mmc_clk = {
- .name = "mci_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_MCI,
- .mode = pmc_periph_mode,
-};
-static struct clk twi_clk = {
- .name = "twi_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_TWI,
- .mode = pmc_periph_mode,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_US0,
- .mode = pmc_periph_mode,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_US1,
- .mode = pmc_periph_mode,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_US2,
- .mode = pmc_periph_mode,
-};
-static struct clk usart3_clk = {
- .name = "usart3_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_US3,
- .mode = pmc_periph_mode,
-};
-static struct clk spi_clk = {
- .name = "spi0_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_SPI,
- .mode = pmc_periph_mode,
-};
-static struct clk pioA_clk = {
- .name = "pioA_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_PIOA,
- .mode = pmc_periph_mode,
-};
-static struct clk pioB_clk = {
- .name = "pioB_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_PIOB,
- .mode = pmc_periph_mode,
-};
-static struct clk pioC_clk = {
- .name = "pioC_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_PIOC,
- .mode = pmc_periph_mode,
-};
-static struct clk pioD_clk = {
- .name = "pioD_clk",
- .parent = &mck,
- .pmc_mask = 1 << AT91_ID_PIOD,
- .mode = pmc_periph_mode,
-};
-
-static struct clk *const clock_list[] = {
- /* four primary clocks -- MUST BE FIRST! */
- &clk32k,
- &main_clk,
- &plla,
- &pllb,
-
- /* PLLB children (USB) */
- &udpck,
- &uhpck,
-
-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
- /* programmable clocks */
- &pck0,
- &pck1,
- &pck2,
- &pck3,
-#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
-
- /* MCK and peripherals */
- &mck,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &usart3_clk,
- &mmc_clk,
- &udc_clk,
- &twi_clk,
- &spi_clk,
- &pioA_clk,
- &pioB_clk,
- &pioC_clk,
- &pioD_clk,
- // ssc0..ssc2
- // tc0..tc5
- // irq0..irq6
- &ohci_clk,
- &ether_clk,
-};
+static struct clk __init *at91_css_to_clk(unsigned long css)
+{
+ switch (css) {
+ case AT91_PMC_CSS_SLOW:
+ return &clk32k;
+ case AT91_PMC_CSS_MAIN:
+ return &main_clk;
+ case AT91_PMC_CSS_PLLA:
+ return &plla;
+ case AT91_PMC_CSS_PLLB:
+ return &pllb;
+ }
+ return NULL;
+}
/*
* Associate a particular clock with a function (eg, "uart") and device.
@@ -329,14 +175,12 @@ void __init at91_clock_associate(const char *id, struct device *dev, const char
clk->dev = dev;
}
-/* clocks are all static for now; no refcounting necessary */
+/* clocks cannot be de-registered no refcounting necessary */
struct clk *clk_get(struct device *dev, const char *id)
{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
- struct clk *clk = clock_list[i];
+ struct clk *clk;
+ list_for_each_entry(clk, &clocks, node) {
if (strcmp(id, clk->name) == 0)
return clk;
if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0)
@@ -424,7 +268,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
unsigned prescale;
unsigned long actual;
- if (!clk->programmable)
+ if (!clk_is_programmable(clk))
return -EINVAL;
spin_lock_irqsave(&clk_lock, flags);
@@ -446,7 +290,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
unsigned prescale;
unsigned long actual;
- if (!clk->programmable)
+ if (!clk_is_programmable(clk))
return -EINVAL;
if (clk->users)
return -EBUSY;
@@ -484,7 +328,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
if (clk->users)
return -EBUSY;
- if (!parent->primary || !clk->programmable)
+ if (!clk_is_primary(parent) || !clk_is_programmable(clk))
return -EINVAL;
spin_lock_irqsave(&clk_lock, flags);
@@ -497,6 +341,18 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
}
EXPORT_SYMBOL(clk_set_parent);
+/* establish PCK0..PCK3 parentage and rate */
+static void init_programmable_clock(struct clk *clk)
+{
+ struct clk *parent;
+ u32 pckr;
+
+ pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
+ parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
+ clk->parent = parent;
+ clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));
+}
+
#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
/*------------------------------------------------------------------------*/
@@ -506,6 +362,7 @@ EXPORT_SYMBOL(clk_set_parent);
static int at91_clk_show(struct seq_file *s, void *unused)
{
u32 scsr, pcsr, sr;
+ struct clk *clk;
unsigned i;
seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR));
@@ -523,9 +380,8 @@ static int at91_clk_show(struct seq_file *s, void *unused)
seq_printf(s, "\n");
- for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
- char *state;
- struct clk *clk = clock_list[i];
+ list_for_each_entry(clk, &clocks, node) {
+ char *state;
if (clk->mode == pmc_sys_mode)
state = (scsr & clk->pmc_mask) ? "on" : "off";
@@ -570,6 +426,28 @@ postcore_initcall(at91_clk_debugfs_init);
/*------------------------------------------------------------------------*/
+/* Register a new clock */
+int __init clk_register(struct clk *clk)
+{
+ if (clk_is_peripheral(clk)) {
+ clk->parent = &mck;
+ clk->mode = pmc_periph_mode;
+ list_add_tail(&clk->node, &clocks);
+ }
+#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+ else if (clk_is_programmable(clk)) {
+ clk->mode = pmc_sys_mode;
+ init_programmable_clock(clk);
+ list_add_tail(&clk->node, &clocks);
+ }
+#endif
+
+ return 0;
+}
+
+
+/*------------------------------------------------------------------------*/
+
static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
{
unsigned mul, div;
@@ -640,20 +518,17 @@ fail:
return 0;
}
-
/*
* Several unused clocks may be active. Turn them off.
*/
-static void at91_periphclk_reset(void)
+static void __init at91_periphclk_reset(void)
{
unsigned long reg;
- int i;
+ struct clk *clk;
reg = at91_sys_read(AT91_PMC_PCSR);
- for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
- struct clk *clk = clock_list[i];
-
+ list_for_each_entry(clk, &clocks, node) {
if (clk->mode != pmc_periph_mode)
continue;
@@ -664,11 +539,25 @@ static void at91_periphclk_reset(void)
at91_sys_write(AT91_PMC_PCDR, reg);
}
+static struct clk *const standard_pmc_clocks[] __initdata = {
+ /* four primary clocks */
+ &clk32k,
+ &main_clk,
+ &plla,
+ &pllb,
+
+ /* PLLB children (USB) */
+ &udpck,
+ &uhpck,
+
+ /* MCK */
+ &mck
+};
+
int __init at91_clock_init(unsigned long main_clock)
{
unsigned tmp, freq, mckr;
-
- spin_lock_init(&clk_lock);
+ int i;
/*
* When the bootloader initialized the main oscillator correctly,
@@ -709,11 +598,15 @@ int __init at91_clock_init(unsigned long main_clock)
* For now, assume this parentage won't change.
*/
mckr = at91_sys_read(AT91_PMC_MCKR);
- mck.parent = clock_list[mckr & AT91_PMC_CSS];
+ mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
freq = mck.parent->rate_hz;
freq /= (1 << ((mckr >> 2) & 3)); /* prescale */
mck.rate_hz = freq / (1 + ((mckr >> 8) & 3)); /* mdiv */
+ /* Register the PMC's standard clocks */
+ for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
+ list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
+
/* MCK and CPU clock are "always on" */
clk_enable(&mck);
@@ -722,35 +615,8 @@ int __init at91_clock_init(unsigned long main_clock)
(unsigned) main_clock / 1000000,
((unsigned) main_clock % 1000000) / 1000);
-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
- /* establish PCK0..PCK3 parentage */
- for (tmp = 0; tmp < ARRAY_SIZE(clock_list); tmp++) {
- struct clk *clk = clock_list[tmp], *parent;
- u32 pckr;
-
- if (!clk->programmable)
- continue;
-
- pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
- parent = clock_list[pckr & AT91_PMC_CSS];
- clk->parent = parent;
- clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));
-
- if (clk->users == 0) {
- /* not being used, so switch it off */
- at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask);
- }
- }
-#else
/* disable all programmable clocks */
at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK0 | AT91_PMC_PCK1 | AT91_PMC_PCK2 | AT91_PMC_PCK3);
-#endif
-
- /* enable the PIO clocks */
- clk_enable(&pioA_clk);
- clk_enable(&pioB_clk);
- clk_enable(&pioC_clk);
- clk_enable(&pioD_clk);
/* disable all other unused peripheral clocks */
at91_periphclk_reset();
diff --git a/arch/arm/mach-at91rm9200/clock.h b/arch/arm/mach-at91rm9200/clock.h
new file mode 100644
index 000000000000..0592e662ab37
--- /dev/null
+++ b/arch/arm/mach-at91rm9200/clock.h
@@ -0,0 +1,30 @@
+/*
+ * linux/arch/arm/mach-at91rm9200/clock.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
+ * published by the Free Software Foundation.
+ */
+
+#define CLK_TYPE_PRIMARY 0x1
+#define CLK_TYPE_PLL 0x2
+#define CLK_TYPE_PROGRAMMABLE 0x4
+#define CLK_TYPE_PERIPHERAL 0x8
+
+
+struct clk {
+ struct list_head node;
+ const char *name; /* unique clock name */
+ const char *function; /* function of the clock */
+ struct device *dev; /* device associated with function */
+ unsigned long rate_hz;
+ struct clk *parent;
+ u32 pmc_mask;
+ void (*mode)(struct clk *, int);
+ unsigned id:2; /* PCK0..3, or 32k/main/a/b */
+ unsigned type; /* clock type */
+ u16 users;
+};
+
+
+extern int __init clk_register(struct clk *clk);
diff --git a/arch/arm/mach-at91rm9200/devices.c b/arch/arm/mach-at91rm9200/devices.c
index 4352acb88178..059824376629 100644
--- a/arch/arm/mach-at91rm9200/devices.c
+++ b/arch/arm/mach-at91rm9200/devices.c
@@ -35,13 +35,13 @@ static struct at91_usbh_data usbh_data;
static struct resource at91_usbh_resources[] = {
[0] = {
- .start = AT91_UHP_BASE,
- .end = AT91_UHP_BASE + SZ_1M - 1,
+ .start = AT91RM9200_UHP_BASE,
+ .end = AT91RM9200_UHP_BASE + SZ_1M - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_UHP,
- .end = AT91_ID_UHP,
+ .start = AT91RM9200_ID_UHP,
+ .end = AT91RM9200_ID_UHP,
.flags = IORESOURCE_IRQ,
},
};
@@ -80,13 +80,13 @@ static struct at91_udc_data udc_data;
static struct resource at91_udc_resources[] = {
[0] = {
- .start = AT91_BASE_UDP,
- .end = AT91_BASE_UDP + SZ_16K - 1,
+ .start = AT91RM9200_BASE_UDP,
+ .end = AT91RM9200_BASE_UDP + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_UDP,
- .end = AT91_ID_UDP,
+ .start = AT91RM9200_ID_UDP,
+ .end = AT91RM9200_ID_UDP,
.flags = IORESOURCE_IRQ,
},
};
@@ -131,13 +131,13 @@ static struct at91_eth_data eth_data;
static struct resource at91_eth_resources[] = {
[0] = {
- .start = AT91_BASE_EMAC,
- .end = AT91_BASE_EMAC + SZ_16K - 1,
+ .start = AT91_VA_BASE_EMAC,
+ .end = AT91_VA_BASE_EMAC + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_EMAC,
- .end = AT91_ID_EMAC,
+ .start = AT91RM9200_ID_EMAC,
+ .end = AT91RM9200_ID_EMAC,
.flags = IORESOURCE_IRQ,
},
};
@@ -263,13 +263,13 @@ static struct at91_mmc_data mmc_data;
static struct resource at91_mmc_resources[] = {
[0] = {
- .start = AT91_BASE_MCI,
- .end = AT91_BASE_MCI + SZ_16K - 1,
+ .start = AT91RM9200_BASE_MCI,
+ .end = AT91RM9200_BASE_MCI + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_MCI,
- .end = AT91_ID_MCI,
+ .start = AT91RM9200_ID_MCI,
+ .end = AT91RM9200_ID_MCI,
.flags = IORESOURCE_IRQ,
},
};
@@ -423,13 +423,13 @@ static u64 spi_dmamask = 0xffffffffUL;
static struct resource at91_spi_resources[] = {
[0] = {
- .start = AT91_BASE_SPI,
- .end = AT91_BASE_SPI + SZ_16K - 1,
+ .start = AT91RM9200_BASE_SPI,
+ .end = AT91RM9200_BASE_SPI + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_SPI,
- .end = AT91_ID_SPI,
+ .start = AT91RM9200_ID_SPI,
+ .end = AT91RM9200_ID_SPI,
.flags = IORESOURCE_IRQ,
},
};
@@ -544,7 +544,7 @@ void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
* UART
* -------------------------------------------------------------------- */
-#if defined(CONFIG_SERIAL_AT91)
+#if defined(CONFIG_SERIAL_ATMEL)
static struct resource dbgu_resources[] = {
[0] = {
.start = AT91_VA_BASE_SYS + AT91_DBGU,
@@ -558,13 +558,14 @@ static struct resource dbgu_resources[] = {
},
};
-static struct at91_uart_data dbgu_data = {
+static struct atmel_uart_data dbgu_data = {
.use_dma_tx = 0,
.use_dma_rx = 0, /* DBGU not capable of receive DMA */
+ .regs = (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
};
static struct platform_device at91rm9200_dbgu_device = {
- .name = "at91_usart",
+ .name = "atmel_usart",
.id = 0,
.dev = {
.platform_data = &dbgu_data,
@@ -582,24 +583,24 @@ static inline void configure_dbgu_pins(void)
static struct resource uart0_resources[] = {
[0] = {
- .start = AT91_BASE_US0,
- .end = AT91_BASE_US0 + SZ_16K - 1,
+ .start = AT91RM9200_BASE_US0,
+ .end = AT91RM9200_BASE_US0 + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_US0,
- .end = AT91_ID_US0,
+ .start = AT91RM9200_ID_US0,
+ .end = AT91RM9200_ID_US0,
.flags = IORESOURCE_IRQ,
},
};
-static struct at91_uart_data uart0_data = {
+static struct atmel_uart_data uart0_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
};
static struct platform_device at91rm9200_uart0_device = {
- .name = "at91_usart",
+ .name = "atmel_usart",
.id = 1,
.dev = {
.platform_data = &uart0_data,
@@ -624,24 +625,24 @@ static inline void configure_usart0_pins(void)
static struct resource uart1_resources[] = {
[0] = {
- .start = AT91_BASE_US1,
- .end = AT91_BASE_US1 + SZ_16K - 1,
+ .start = AT91RM9200_BASE_US1,
+ .end = AT91RM9200_BASE_US1 + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_US1,
- .end = AT91_ID_US1,
+ .start = AT91RM9200_ID_US1,
+ .end = AT91RM9200_ID_US1,
.flags = IORESOURCE_IRQ,
},
};
-static struct at91_uart_data uart1_data = {
+static struct atmel_uart_data uart1_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
};
static struct platform_device at91rm9200_uart1_device = {
- .name = "at91_usart",
+ .name = "atmel_usart",
.id = 2,
.dev = {
.platform_data = &uart1_data,
@@ -665,24 +666,24 @@ static inline void configure_usart1_pins(void)
static struct resource uart2_resources[] = {
[0] = {
- .start = AT91_BASE_US2,
- .end = AT91_BASE_US2 + SZ_16K - 1,
+ .start = AT91RM9200_BASE_US2,
+ .end = AT91RM9200_BASE_US2 + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_US2,
- .end = AT91_ID_US2,
+ .start = AT91RM9200_ID_US2,
+ .end = AT91RM9200_ID_US2,
.flags = IORESOURCE_IRQ,
},
};
-static struct at91_uart_data uart2_data = {
+static struct atmel_uart_data uart2_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
};
static struct platform_device at91rm9200_uart2_device = {
- .name = "at91_usart",
+ .name = "atmel_usart",
.id = 3,
.dev = {
.platform_data = &uart2_data,
@@ -700,24 +701,24 @@ static inline void configure_usart2_pins(void)
static struct resource uart3_resources[] = {
[0] = {
- .start = AT91_BASE_US3,
- .end = AT91_BASE_US3 + SZ_16K - 1,
+ .start = AT91RM9200_BASE_US3,
+ .end = AT91RM9200_BASE_US3 + SZ_16K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
- .start = AT91_ID_US3,
- .end = AT91_ID_US3,
+ .start = AT91RM9200_ID_US3,
+ .end = AT91RM9200_ID_US3,
.flags = IORESOURCE_IRQ,
},
};
-static struct at91_uart_data uart3_data = {
+static struct atmel_uart_data uart3_data = {
.use_dma_tx = 1,
.use_dma_rx = 1,
};
static struct platform_device at91rm9200_uart3_device = {
- .name = "at91_usart",
+ .name = "atmel_usart",
.id = 4,
.dev = {
.platform_data = &uart3_data,
@@ -733,8 +734,8 @@ static inline void configure_usart3_pins(void)
at91_set_B_periph(AT91_PIN_PA6, 0); /* RXD3 */
}
-struct platform_device *at91_uarts[AT91_NR_UART]; /* the UARTs to use */
-struct platform_device *at91_default_console_device; /* the serial console device */
+struct platform_device *at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
+struct platform_device *atmel_default_console_device; /* the serial console device */
void __init at91_init_serial(struct at91_uart_config *config)
{
@@ -775,9 +776,9 @@ void __init at91_init_serial(struct at91_uart_config *config)
}
/* Set serial console device */
- if (config->console_tty < AT91_NR_UART)
- at91_default_console_device = at91_uarts[config->console_tty];
- if (!at91_default_console_device)
+ if (config->console_tty < ATMEL_MAX_UART)
+ atmel_default_console_device = at91_uarts[config->console_tty];
+ if (!atmel_default_console_device)
printk(KERN_INFO "AT91: No default serial console defined.\n");
}
@@ -785,7 +786,7 @@ void __init at91_add_device_serial(void)
{
int i;
- for (i = 0; i < AT91_NR_UART; i++) {
+ for (i = 0; i < ATMEL_MAX_UART; i++) {
if (at91_uarts[i])
platform_device_register(at91_uarts[i]);
}
diff --git a/arch/arm/mach-at91rm9200/generic.h b/arch/arm/mach-at91rm9200/generic.h
index 7979d8ab7e07..694e411e285f 100644
--- a/arch/arm/mach-at91rm9200/generic.h
+++ b/arch/arm/mach-at91rm9200/generic.h
@@ -8,18 +8,17 @@
* published by the Free Software Foundation.
*/
+ /* Processors */
+extern void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks);
+
/* Interrupts */
-extern void __init at91rm9200_init_irq(unsigned int priority[]);
+extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
extern void __init at91_aic_init(unsigned int priority[]);
-extern void __init at91_gpio_irq_setup(unsigned banks);
/* Timer */
struct sys_timer;
extern struct sys_timer at91rm9200_timer;
- /* Memory Map */
-extern void __init at91rm9200_map_io(void);
-
/* Clocks */
extern int __init at91_clock_init(unsigned long main_clock);
struct device;
@@ -29,3 +28,14 @@ extern void __init at91_clock_associate(const char *id, struct device *dev, cons
extern void at91_irq_suspend(void);
extern void at91_irq_resume(void);
+ /* GPIO */
+#define AT91RM9200_PQFP 3 /* AT91RM9200 PQFP package has 3 banks */
+#define AT91RM9200_BGA 4 /* AT91RM9200 BGA package has 4 banks */
+
+struct at91_gpio_bank {
+ unsigned short id; /* peripheral ID */
+ unsigned long offset; /* offset from system peripheral base */
+ struct clk *clock; /* associated clock */
+};
+extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
+extern void __init at91_gpio_irq_setup(void);
diff --git a/arch/arm/mach-at91rm9200/gpio.c b/arch/arm/mach-at91rm9200/gpio.c
index cec199fd6721..7467d644f0a3 100644
--- a/arch/arm/mach-at91rm9200/gpio.c
+++ b/arch/arm/mach-at91rm9200/gpio.c
@@ -9,6 +9,7 @@
* (at your option) any later version.
*/
+#include <linux/clk.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@@ -20,12 +21,12 @@
#include <asm/hardware.h>
#include <asm/arch/gpio.h>
-static const u32 pio_controller_offset[4] = {
- AT91_PIOA,
- AT91_PIOB,
- AT91_PIOC,
- AT91_PIOD,
-};
+#include "generic.h"
+
+
+static struct at91_gpio_bank *gpio;
+static int gpio_banks;
+
static inline void __iomem *pin_to_controller(unsigned pin)
{
@@ -33,8 +34,8 @@ static inline void __iomem *pin_to_controller(unsigned pin)
pin -= PIN_BASE;
pin /= 32;
- if (likely(pin < BGA_GPIO_BANKS))
- return sys_base + pio_controller_offset[pin];
+ if (likely(pin < gpio_banks))
+ return sys_base + gpio[pin].offset;
return NULL;
}
@@ -179,7 +180,6 @@ EXPORT_SYMBOL(at91_set_multi_drive);
/*--------------------------------------------------------------------------*/
-
/*
* assuming the pin is muxed as a gpio output, set its value.
*/
@@ -216,8 +216,8 @@ EXPORT_SYMBOL(at91_get_gpio_value);
#ifdef CONFIG_PM
-static u32 wakeups[BGA_GPIO_BANKS];
-static u32 backups[BGA_GPIO_BANKS];
+static u32 wakeups[MAX_GPIO_BANKS];
+static u32 backups[MAX_GPIO_BANKS];
static int gpio_irq_set_wake(unsigned pin, unsigned state)
{
@@ -226,7 +226,7 @@ static int gpio_irq_set_wake(unsigned pin, unsigned state)
pin -= PIN_BASE;
pin /= 32;
- if (unlikely(pin >= BGA_GPIO_BANKS))
+ if (unlikely(pin >= MAX_GPIO_BANKS))
return -EINVAL;
if (state)
@@ -241,8 +241,8 @@ void at91_gpio_suspend(void)
{
int i;
- for (i = 0; i < BGA_GPIO_BANKS; i++) {
- u32 pio = pio_controller_offset[i];
+ for (i = 0; i < gpio_banks; i++) {
+ u32 pio = gpio[i].offset;
/*
* Note: drivers should have disabled GPIO interrupts that
@@ -257,14 +257,14 @@ void at91_gpio_suspend(void)
* first place!
*/
backups[i] = at91_sys_read(pio + PIO_IMR);
- at91_sys_write(pio_controller_offset[i] + PIO_IDR, backups[i]);
- at91_sys_write(pio_controller_offset[i] + PIO_IER, wakeups[i]);
+ at91_sys_write(pio + PIO_IDR, backups[i]);
+ at91_sys_write(pio + PIO_IER, wakeups[i]);
if (!wakeups[i]) {
- disable_irq_wake(AT91_ID_PIOA + i);
- at91_sys_write(AT91_PMC_PCDR, 1 << (AT91_ID_PIOA + i));
+ disable_irq_wake(gpio[i].id);
+ at91_sys_write(AT91_PMC_PCDR, 1 << gpio[i].id);
} else {
- enable_irq_wake(AT91_ID_PIOA + i);
+ enable_irq_wake(gpio[i].id);
#ifdef CONFIG_PM_DEBUG
printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", "ABCD"[i], wakeups[i]);
#endif
@@ -276,16 +276,13 @@ void at91_gpio_resume(void)
{
int i;
- for (i = 0; i < BGA_GPIO_BANKS; i++) {
- at91_sys_write(pio_controller_offset[i] + PIO_IDR, wakeups[i]);
- at91_sys_write(pio_controller_offset[i] + PIO_IER, backups[i]);
- }
+ for (i = 0; i < gpio_banks; i++) {
+ u32 pio = gpio[i].offset;
- at91_sys_write(AT91_PMC_PCER,
- (1 << AT91_ID_PIOA)
- | (1 << AT91_ID_PIOB)
- | (1 << AT91_ID_PIOC)
- | (1 << AT91_ID_PIOD));
+ at91_sys_write(pio + PIO_IDR, wakeups[i]);
+ at91_sys_write(pio + PIO_IER, backups[i]);
+ at91_sys_write(AT91_PMC_PCER, 1 << gpio[i].id);
+ }
}
#else
@@ -335,7 +332,7 @@ static struct irq_chip gpio_irqchip = {
.set_wake = gpio_irq_set_wake,
};
-static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs)
+static void gpio_irq_handler(unsigned irq, struct irqdesc *desc)
{
unsigned pin;
struct irqdesc *gpio;
@@ -366,7 +363,7 @@ static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs
gpio_irq_mask(pin);
}
else
- desc_handle_irq(pin, gpio, regs);
+ desc_handle_irq(pin, gpio);
}
pin++;
gpio++;
@@ -377,20 +374,25 @@ static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs
/* now it may re-trigger */
}
-/* call this from board-specific init_irq */
-void __init at91_gpio_irq_setup(unsigned banks)
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Called from the processor-specific init to enable GPIO interrupt support.
+ */
+void __init at91_gpio_irq_setup(void)
{
- unsigned pioc, pin, id;
+ unsigned pioc, pin;
- if (banks > 4)
- banks = 4;
- for (pioc = 0, pin = PIN_BASE, id = AT91_ID_PIOA;
- pioc < banks;
- pioc++, id++) {
+ for (pioc = 0, pin = PIN_BASE;
+ pioc < gpio_banks;
+ pioc++) {
void __iomem *controller;
+ unsigned id = gpio[pioc].id;
unsigned i;
- controller = (void __iomem *) AT91_VA_BASE_SYS + pio_controller_offset[pioc];
+ clk_enable(gpio[pioc].clock); /* enable PIO controller's clock */
+
+ controller = (void __iomem *) AT91_VA_BASE_SYS + gpio[pioc].offset;
__raw_writel(~0, controller + PIO_IDR);
set_irq_data(id, (void *) pin);
@@ -408,5 +410,16 @@ void __init at91_gpio_irq_setup(unsigned banks)
set_irq_chained_handler(id, gpio_irq_handler);
}
- pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, banks);
+ pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, gpio_banks);
+}
+
+/*
+ * Called from the processor-specific init to enable GPIO pin support.
+ */
+void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
+{
+ BUG_ON(nr_banks > MAX_GPIO_BANKS);
+
+ gpio = data;
+ gpio_banks = nr_banks;
}
diff --git a/arch/arm/mach-at91rm9200/irq.c b/arch/arm/mach-at91rm9200/irq.c
index c3a5e777f9f8..3e488117ca91 100644
--- a/arch/arm/mach-at91rm9200/irq.c
+++ b/arch/arm/mach-at91rm9200/irq.c
@@ -34,8 +34,6 @@
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
-#include "generic.h"
-
static void at91_aic_mask_irq(unsigned int irq)
{
@@ -61,12 +59,12 @@ static int at91_aic_set_type(unsigned irq, unsigned type)
srctype = AT91_AIC_SRCTYPE_RISING;
break;
case IRQT_LOW:
- if ((irq > AT91_ID_FIQ) && (irq < AT91_ID_IRQ0)) /* only supported on external interrupts */
+ if ((irq > AT91_ID_FIQ) && (irq < AT91RM9200_ID_IRQ0)) /* only supported on external interrupts */
return -EINVAL;
srctype = AT91_AIC_SRCTYPE_LOW;
break;
case IRQT_FALLING:
- if ((irq > AT91_ID_FIQ) && (irq < AT91_ID_IRQ0)) /* only supported on external interrupts */
+ if ((irq > AT91_ID_FIQ) && (irq < AT91RM9200_ID_IRQ0)) /* only supported on external interrupts */
return -EINVAL;
srctype = AT91_AIC_SRCTYPE_FALLING;
break;
diff --git a/arch/arm/mach-at91rm9200/pm.c b/arch/arm/mach-at91rm9200/pm.c
index 47e5480feb7e..32c95d8eaacf 100644
--- a/arch/arm/mach-at91rm9200/pm.c
+++ b/arch/arm/mach-at91rm9200/pm.c
@@ -123,13 +123,13 @@ static int at91_pm_enter(suspend_state_t state)
(at91_sys_read(AT91_PMC_PCSR)
| (1 << AT91_ID_FIQ)
| (1 << AT91_ID_SYS)
- | (1 << AT91_ID_IRQ0)
- | (1 << AT91_ID_IRQ1)
- | (1 << AT91_ID_IRQ2)
- | (1 << AT91_ID_IRQ3)
- | (1 << AT91_ID_IRQ4)
- | (1 << AT91_ID_IRQ5)
- | (1 << AT91_ID_IRQ6))
+ | (1 << AT91RM9200_ID_IRQ0)
+ | (1 << AT91RM9200_ID_IRQ1)
+ | (1 << AT91RM9200_ID_IRQ2)
+ | (1 << AT91RM9200_ID_IRQ3)
+ | (1 << AT91RM9200_ID_IRQ4)
+ | (1 << AT91RM9200_ID_IRQ5)
+ | (1 << AT91RM9200_ID_IRQ6))
& at91_sys_read(AT91_AIC_IMR),
state);
diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
index a071eac4a30a..428493dd4687 100644
--- a/arch/arm/mach-clps711x/time.c
+++ b/arch/arm/mach-clps711x/time.c
@@ -48,10 +48,10 @@ static unsigned long clps711x_gettimeoffset(void)
* IRQ handler for the timer
*/
static irqreturn_t
-p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+p720t_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index 92eaebdd5606..fb10cf252588 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -292,11 +292,11 @@ extern void ioctime_init(void);
extern unsigned long ioc_timer_gettimeoffset(void);
static irqreturn_t
-clps7500_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+clps7500_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
/* Why not using do_leds interface?? */
{
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index 70dd12ef3c40..90103ab373a6 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -174,7 +174,7 @@ static unsigned long ebsa110_gettimeoffset(void)
}
static irqreturn_t
-ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ebsa110_timer_interrupt(int irq, void *dev_id)
{
u32 count;
@@ -190,7 +190,7 @@ ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
__raw_writeb(count & 0xff, PIT_T1);
__raw_writeb(count >> 8, PIT_T1);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-ep93xx/Kconfig b/arch/arm/mach-ep93xx/Kconfig
index f1b740083aee..e346b03cd921 100644
--- a/arch/arm/mach-ep93xx/Kconfig
+++ b/arch/arm/mach-ep93xx/Kconfig
@@ -15,6 +15,12 @@ config MACH_EDB9302
Say 'Y' here if you want your kernel to support the Cirrus
Logic EDB9302 Evaluation Board.
+config MACH_EDB9312
+ bool "Support Cirrus Logic EDB9312"
+ help
+ Say 'Y' here if you want your kernel to support the Cirrus
+ Logic EDB9312 Evaluation Board.
+
config MACH_EDB9315
bool "Support Cirrus Logic EDB9315"
help
diff --git a/arch/arm/mach-ep93xx/Makefile b/arch/arm/mach-ep93xx/Makefile
index 1f5a6b0487ee..c2eb18b530c2 100644
--- a/arch/arm/mach-ep93xx/Makefile
+++ b/arch/arm/mach-ep93xx/Makefile
@@ -7,6 +7,7 @@ obj-n :=
obj- :=
obj-$(CONFIG_MACH_EDB9302) += edb9302.o
+obj-$(CONFIG_MACH_EDB9312) += edb9312.o
obj-$(CONFIG_MACH_EDB9315) += edb9315.o
obj-$(CONFIG_MACH_EDB9315A) += edb9315a.o
obj-$(CONFIG_MACH_GESBC9312) += gesbc9312.o
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index a87a784b9201..e3fd1ab6adcc 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -97,7 +97,7 @@ static unsigned int last_jiffy_time;
#define TIMER4_TICKS_PER_JIFFY ((CLOCK_TICK_RATE + (HZ/2)) / HZ)
-static int ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static int ep93xx_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
@@ -106,7 +106,7 @@ static int ep93xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
(__raw_readl(EP93XX_TIMER4_VALUE_LOW) - last_jiffy_time)
>= TIMER4_TICKS_PER_JIFFY) {
last_jiffy_time += TIMER4_TICKS_PER_JIFFY;
- timer_tick(regs);
+ timer_tick();
}
write_sequnlock(&xtime_lock);
@@ -245,7 +245,7 @@ EXPORT_SYMBOL(gpio_line_set);
* EP93xx IRQ handling
*************************************************************************/
static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
- struct irqdesc *desc, struct pt_regs *regs)
+ struct irqdesc *desc)
{
unsigned char status;
int i;
@@ -254,7 +254,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
for (i = 0; i < 8; i++) {
if (status & (1 << i)) {
desc = irq_desc + IRQ_EP93XX_GPIO(0) + i;
- desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc, regs);
+ desc_handle_irq(IRQ_EP93XX_GPIO(0) + i, desc);
}
}
@@ -262,7 +262,7 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq,
for (i = 0; i < 8; i++) {
if (status & (1 << i)) {
desc = irq_desc + IRQ_EP93XX_GPIO(8) + i;
- desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc, regs);
+ desc_handle_irq(IRQ_EP93XX_GPIO(8) + i, desc);
}
}
}
diff --git a/arch/arm/mach-ep93xx/edb9302.c b/arch/arm/mach-ep93xx/edb9302.c
index 62a8efd23256..0315615b74da 100644
--- a/arch/arm/mach-ep93xx/edb9302.c
+++ b/arch/arm/mach-ep93xx/edb9302.c
@@ -10,7 +10,6 @@
* your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
diff --git a/arch/arm/mach-ep93xx/edb9312.c b/arch/arm/mach-ep93xx/edb9312.c
new file mode 100644
index 000000000000..e310e4d72990
--- /dev/null
+++ b/arch/arm/mach-ep93xx/edb9312.c
@@ -0,0 +1,62 @@
+/*
+ * arch/arm/mach-ep93xx/edb9312.c
+ * Cirrus Logic EDB9312 support.
+ *
+ * Copyright (C) 2006 Infosys Technologies Limited
+ * Toufeeq Hussain <toufeeq_hussain@infosys.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/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+static struct physmap_flash_data edb9312_flash_data = {
+ .width = 4,
+};
+
+static struct resource edb9312_flash_resource = {
+ .start = 0x60000000,
+ .end = 0x61ffffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device edb9312_flash = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &edb9312_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &edb9312_flash_resource,
+};
+
+static void __init edb9312_init_machine(void)
+{
+ ep93xx_init_devices();
+ platform_device_register(&edb9312_flash);
+}
+
+MACHINE_START(EDB9312, "Cirrus Logic EDB9312 Evaluation Board")
+ /* Maintainer: Toufeeq Hussain <toufeeq_hussain@infosys.com> */
+ .phys_io = EP93XX_APB_PHYS_BASE,
+ .io_pg_offst = ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = ep93xx_map_io,
+ .init_irq = ep93xx_init_irq,
+ .timer = &ep93xx_timer,
+ .init_machine = edb9312_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-ep93xx/edb9315.c b/arch/arm/mach-ep93xx/edb9315.c
index ef7482faad81..249ca9e57bc6 100644
--- a/arch/arm/mach-ep93xx/edb9315.c
+++ b/arch/arm/mach-ep93xx/edb9315.c
@@ -10,7 +10,6 @@
* your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
diff --git a/arch/arm/mach-ep93xx/edb9315a.c b/arch/arm/mach-ep93xx/edb9315a.c
index bfefdaa8f794..7ca0e6170a41 100644
--- a/arch/arm/mach-ep93xx/edb9315a.c
+++ b/arch/arm/mach-ep93xx/edb9315a.c
@@ -10,7 +10,6 @@
* your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/mm.h>
@@ -44,10 +43,40 @@ static struct platform_device edb9315a_flash = {
.resource = &edb9315a_flash_resource,
};
+static struct ep93xx_eth_data edb9315a_eth_data = {
+ .phy_id = 1,
+};
+
+static struct resource edb9315a_eth_resource[] = {
+ {
+ .start = EP93XX_ETHERNET_PHYS_BASE,
+ .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_EP93XX_ETHERNET,
+ .end = IRQ_EP93XX_ETHERNET,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device edb9315a_eth_device = {
+ .name = "ep93xx-eth",
+ .id = -1,
+ .dev = {
+ .platform_data = &edb9315a_eth_data,
+ },
+ .num_resources = 2,
+ .resource = edb9315a_eth_resource,
+};
+
static void __init edb9315a_init_machine(void)
{
ep93xx_init_devices();
platform_device_register(&edb9315a_flash);
+
+ memcpy(edb9315a_eth_data.dev_addr,
+ (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
+ platform_device_register(&edb9315a_eth_device);
}
MACHINE_START(EDB9315A, "Cirrus Logic EDB9315A Evaluation Board")
diff --git a/arch/arm/mach-ep93xx/gesbc9312.c b/arch/arm/mach-ep93xx/gesbc9312.c
index e760fd4f3655..694590a451c1 100644
--- a/arch/arm/mach-ep93xx/gesbc9312.c
+++ b/arch/arm/mach-ep93xx/gesbc9312.c
@@ -43,10 +43,37 @@ static struct platform_device gesbc9312_flash = {
.resource = &gesbc9312_flash_resource,
};
+static struct ep93xx_eth_data gesbc9312_eth_data = {
+ .phy_id = 1,
+};
+
+static struct resource gesbc9312_eth_resource[] = {
+ {
+ .start = EP93XX_ETHERNET_PHYS_BASE,
+ .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_EP93XX_ETHERNET,
+ .end = IRQ_EP93XX_ETHERNET,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device gesbc9312_eth_device = {
+ .name = "ep93xx-eth",
+ .id = -1,
+ .dev = {
+ .platform_data = &gesbc9312_eth_data,
+ },
+ .num_resources = 2,
+ .resource = gesbc9312_eth_resource,
+};
+
static void __init gesbc9312_init_machine(void)
{
ep93xx_init_devices();
platform_device_register(&gesbc9312_flash);
+ platform_device_register(&gesbc9312_eth_device);
}
MACHINE_START(GESBC9312, "Glomation GESBC-9312-sx")
diff --git a/arch/arm/mach-ep93xx/ts72xx.c b/arch/arm/mach-ep93xx/ts72xx.c
index df315f2e9beb..3a4bf90ba832 100644
--- a/arch/arm/mach-ep93xx/ts72xx.c
+++ b/arch/arm/mach-ep93xx/ts72xx.c
@@ -157,12 +157,42 @@ static struct platform_device ts72xx_rtc_device = {
.num_resources = 0,
};
+static struct ep93xx_eth_data ts72xx_eth_data = {
+ .phy_id = 1,
+};
+
+static struct resource ts72xx_eth_resource[] = {
+ {
+ .start = EP93XX_ETHERNET_PHYS_BASE,
+ .end = EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+ .flags = IORESOURCE_MEM,
+ }, {
+ .start = IRQ_EP93XX_ETHERNET,
+ .end = IRQ_EP93XX_ETHERNET,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+static struct platform_device ts72xx_eth_device = {
+ .name = "ep93xx-eth",
+ .id = -1,
+ .dev = {
+ .platform_data = &ts72xx_eth_data,
+ },
+ .num_resources = 2,
+ .resource = ts72xx_eth_resource,
+};
+
static void __init ts72xx_init_machine(void)
{
ep93xx_init_devices();
if (board_is_ts7200())
platform_device_register(&ts72xx_flash);
platform_device_register(&ts72xx_rtc_device);
+
+ memcpy(ts72xx_eth_data.dev_addr,
+ (void *)(EP93XX_ETHERNET_BASE + 0x50), 6);
+ platform_device_register(&ts72xx_eth_device);
}
MACHINE_START(TS72XX, "Technologic Systems TS-72xx SBC")
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index 2af610811ca4..fa6be870c6c2 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -28,13 +28,13 @@ static unsigned long timer1_gettimeoffset (void)
}
static irqreturn_t
-timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+timer1_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
*CSR_TIMER1_CLR = 0;
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
index 823e25d4547e..1463330ed8ee 100644
--- a/arch/arm/mach-footbridge/dc21285.c
+++ b/arch/arm/mach-footbridge/dc21285.c
@@ -16,6 +16,7 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/ioport.h>
+#include <linux/irq.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -69,16 +70,16 @@ dc21285_read_config(struct pci_bus *bus, unsigned int devfn, int where,
if (addr)
switch (size) {
case 1:
- asm("ldr%?b %0, [%1, %2]"
- : "=r" (v) : "r" (addr), "r" (where));
+ asm("ldrb %0, [%1, %2]"
+ : "=r" (v) : "r" (addr), "r" (where) : "cc");
break;
case 2:
- asm("ldr%?h %0, [%1, %2]"
- : "=r" (v) : "r" (addr), "r" (where));
+ asm("ldrh %0, [%1, %2]"
+ : "=r" (v) : "r" (addr), "r" (where) : "cc");
break;
case 4:
- asm("ldr%? %0, [%1, %2]"
- : "=r" (v) : "r" (addr), "r" (where));
+ asm("ldr %0, [%1, %2]"
+ : "=r" (v) : "r" (addr), "r" (where) : "cc");
break;
}
@@ -103,16 +104,19 @@ dc21285_write_config(struct pci_bus *bus, unsigned int devfn, int where,
if (addr)
switch (size) {
case 1:
- asm("str%?b %0, [%1, %2]"
- : : "r" (value), "r" (addr), "r" (where));
+ asm("strb %0, [%1, %2]"
+ : : "r" (value), "r" (addr), "r" (where)
+ : "cc");
break;
case 2:
- asm("str%?h %0, [%1, %2]"
- : : "r" (value), "r" (addr), "r" (where));
+ asm("strh %0, [%1, %2]"
+ : : "r" (value), "r" (addr), "r" (where)
+ : "cc");
break;
case 4:
- asm("str%? %0, [%1, %2]"
- : : "r" (value), "r" (addr), "r" (where));
+ asm("str %0, [%1, %2]"
+ : : "r" (value), "r" (addr), "r" (where)
+ : "cc");
break;
}
@@ -151,7 +155,7 @@ static void dc21285_enable_error(unsigned long __data)
/*
* Warn on PCI errors.
*/
-static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_abort_irq(int irq, void *dev_id)
{
unsigned int cmd;
unsigned int status;
@@ -162,7 +166,7 @@ static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs
if (status & PCI_STATUS_REC_MASTER_ABORT) {
printk(KERN_DEBUG "PCI: master abort, pc=0x%08lx\n",
- instruction_pointer(regs));
+ instruction_pointer(get_irq_regs()));
cmd |= PCI_STATUS_REC_MASTER_ABORT << 16;
}
@@ -181,7 +185,7 @@ static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs
return IRQ_HANDLED;
}
-static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_serr_irq(int irq, void *dev_id)
{
struct timer_list *timer = dev_id;
unsigned int cntl;
@@ -203,7 +207,7 @@ static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_discard_irq(int irq, void *dev_id)
{
printk(KERN_DEBUG "PCI: discard timer expired\n");
*CSR_SA110_CNTL &= 0xffffde07;
@@ -211,7 +215,7 @@ static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *re
return IRQ_HANDLED;
}
-static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id)
{
unsigned int cmd;
@@ -225,7 +229,7 @@ static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *re
return IRQ_HANDLED;
}
-static irqreturn_t dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_parity_irq(int irq, void *dev_id)
{
struct timer_list *timer = dev_id;
unsigned int cmd;
diff --git a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c
index 87448c2d6baa..888dedd501b9 100644
--- a/arch/arm/mach-footbridge/isa-irq.c
+++ b/arch/arm/mach-footbridge/isa-irq.c
@@ -85,17 +85,17 @@ static struct irqchip isa_hi_chip = {
};
static void
-isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+isa_irq_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned int isa_irq = *(unsigned char *)PCIIACK_BASE;
if (isa_irq < _ISA_IRQ(0) || isa_irq >= _ISA_IRQ(16)) {
- do_bad_IRQ(isa_irq, desc, regs);
+ do_bad_IRQ(isa_irq, desc);
return;
}
desc = irq_desc + isa_irq;
- desc_handle_irq(isa_irq, desc, regs);
+ desc_handle_irq(isa_irq, desc);
}
static struct irqaction irq_cascade = {
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index c4810a40c8e1..d884a3954fb4 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -62,10 +62,10 @@ static unsigned long isa_gettimeoffset(void)
}
static irqreturn_t
-isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+isa_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-h720x/common.c b/arch/arm/mach-h720x/common.c
index c096b4569308..4719229a1a78 100644
--- a/arch/arm/mach-h720x/common.c
+++ b/arch/arm/mach-h720x/common.c
@@ -101,14 +101,14 @@ static void inline unmask_gpio_irq(u32 irq)
static void
h720x_gpio_handler(unsigned int mask, unsigned int irq,
- struct irqdesc *desc, struct pt_regs *regs)
+ struct irqdesc *desc)
{
IRQDBG("%s irq: %d\n",__FUNCTION__,irq);
desc = irq_desc + irq;
while (mask) {
if (mask & 1) {
IRQDBG("handling irq %d\n", irq);
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
}
irq++;
desc++;
@@ -117,63 +117,58 @@ h720x_gpio_handler(unsigned int mask, unsigned int irq,
}
static void
-h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+h720x_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = CPU_REG(GPIO_A_VIRT,GPIO_STAT);
irq = IRQ_CHAINED_GPIOA(0);
IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
- h720x_gpio_handler(mask, irq, desc, regs);
+ h720x_gpio_handler(mask, irq, desc);
}
static void
-h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+h720x_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = CPU_REG(GPIO_B_VIRT,GPIO_STAT);
irq = IRQ_CHAINED_GPIOB(0);
IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
- h720x_gpio_handler(mask, irq, desc, regs);
+ h720x_gpio_handler(mask, irq, desc);
}
static void
-h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+h720x_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = CPU_REG(GPIO_C_VIRT,GPIO_STAT);
irq = IRQ_CHAINED_GPIOC(0);
IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
- h720x_gpio_handler(mask, irq, desc, regs);
+ h720x_gpio_handler(mask, irq, desc);
}
static void
-h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+h720x_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = CPU_REG(GPIO_D_VIRT,GPIO_STAT);
irq = IRQ_CHAINED_GPIOD(0);
IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
- h720x_gpio_handler(mask, irq, desc, regs);
+ h720x_gpio_handler(mask, irq, desc);
}
#ifdef CONFIG_CPU_H7202
static void
-h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+h720x_gpioe_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = CPU_REG(GPIO_E_VIRT,GPIO_STAT);
irq = IRQ_CHAINED_GPIOE(0);
IRQDBG("%s mask: 0x%08x irq: %d\n",__FUNCTION__,mask,irq);
- h720x_gpio_handler(mask, irq, desc, regs);
+ h720x_gpio_handler(mask, irq, desc);
}
#endif
diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
index a9a8255a3a03..13f76bdb3d9d 100644
--- a/arch/arm/mach-h720x/cpu-h7201.c
+++ b/arch/arm/mach-h720x/cpu-h7201.c
@@ -27,12 +27,12 @@
* Timer interrupt handler
*/
static irqreturn_t
-h7201_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+h7201_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
CPU_REG (TIMER_VIRT, TIMER_TOPSTAT);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index da678d163fd9..06fecaefd8dc 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -106,8 +106,7 @@ static struct platform_device *devices[] __initdata = {
* we have to handle all timer interrupts in one place.
*/
static void
-h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
@@ -115,7 +114,7 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
if ( mask & TSTAT_T0INT ) {
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
if( mask == TSTAT_T0INT )
return;
@@ -126,7 +125,7 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
desc = irq_desc + irq;
while (mask) {
if (mask & 1)
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
irq++;
desc++;
mask >>= 1;
@@ -137,9 +136,9 @@ h7202_timerx_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
* Timer interrupt handler
*/
static irqreturn_t
-h7202_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+h7202_timer_interrupt(int irq, void *dev_id)
{
- h7202_timerx_demux_handler(0, NULL, regs);
+ h7202_timerx_demux_handler(0, NULL);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-imx/dma.c b/arch/arm/mach-imx/dma.c
index 36578871ecc8..6d50d85a618c 100644
--- a/arch/arm/mach-imx/dma.c
+++ b/arch/arm/mach-imx/dma.c
@@ -279,8 +279,8 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
*/
int
imx_dma_setup_handlers(imx_dmach_t dma_ch,
- void (*irq_handler) (int, void *, struct pt_regs *),
- void (*err_handler) (int, void *, struct pt_regs *, int),
+ void (*irq_handler) (int, void *),
+ void (*err_handler) (int, void *, int),
void *data)
{
struct imx_dma_channel *imxdma = &imx_dma_channels[dma_ch];
@@ -461,7 +461,7 @@ imx_dma_request_by_prio(imx_dmach_t * pdma_ch, const char *name,
return -ENODEV;
}
-static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_err_handler(int irq, void *dev_id)
{
int i, disr = DISR;
struct imx_dma_channel *channel;
@@ -500,7 +500,7 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
/*imx_dma_channels[i].sg = NULL;*/
if (channel->name && channel->err_handler) {
- channel->err_handler(i, channel->data, regs, errcode);
+ channel->err_handler(i, channel->data, errcode);
continue;
}
@@ -517,7 +517,7 @@ static irqreturn_t dma_err_handler(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
int i, disr = DISR;
@@ -536,7 +536,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
} else {
if (channel->irq_handler)
channel->irq_handler(i,
- channel->data, regs);
+ channel->data);
}
} else {
/*
diff --git a/arch/arm/mach-imx/irq.c b/arch/arm/mach-imx/irq.c
index 2688bd82c2a2..368b13b058ab 100644
--- a/arch/arm/mach-imx/irq.c
+++ b/arch/arm/mach-imx/irq.c
@@ -146,13 +146,13 @@ imx_gpio_unmask_irq(unsigned int irq)
static void
imx_gpio_handler(unsigned int mask, unsigned int irq,
- struct irqdesc *desc, struct pt_regs *regs)
+ struct irqdesc *desc)
{
desc = irq_desc + irq;
while (mask) {
if (mask & 1) {
DEBUG_IRQ("handling irq %d\n", irq);
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
}
irq++;
desc++;
@@ -161,47 +161,43 @@ imx_gpio_handler(unsigned int mask, unsigned int irq,
}
static void
-imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = ISR(0);
irq = IRQ_GPIOA(0);
- imx_gpio_handler(mask, irq, desc, regs);
+ imx_gpio_handler(mask, irq, desc);
}
static void
-imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = ISR(1);
irq = IRQ_GPIOB(0);
- imx_gpio_handler(mask, irq, desc, regs);
+ imx_gpio_handler(mask, irq, desc);
}
static void
-imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = ISR(2);
irq = IRQ_GPIOC(0);
- imx_gpio_handler(mask, irq, desc, regs);
+ imx_gpio_handler(mask, irq, desc);
}
static void
-imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int mask, irq;
mask = ISR(3);
irq = IRQ_GPIOD(0);
- imx_gpio_handler(mask, irq, desc, regs);
+ imx_gpio_handler(mask, irq, desc);
}
static struct irq_chip imx_internal_chip = {
diff --git a/arch/arm/mach-imx/leds.c b/arch/arm/mach-imx/leds.c
index 471c1db7c57f..cf30803e019b 100644
--- a/arch/arm/mach-imx/leds.c
+++ b/arch/arm/mach-imx/leds.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-imx/leds.h
+ * linux/arch/arm/mach-imx/leds.c
*
* Copyright (C) 2004 Sascha Hauer <sascha@saschahauer.de>
*
diff --git a/arch/arm/mach-imx/leds.h b/arch/arm/mach-imx/leds.h
index 83fa21e795a9..49dc1c1da338 100644
--- a/arch/arm/mach-imx/leds.h
+++ b/arch/arm/mach-imx/leds.h
@@ -1,5 +1,5 @@
/*
- * include/asm-arm/arch-imx/leds.h
+ * arch/arm/mach-imx/leds.h
*
* Copyright (c) 2004 Sascha Hauer <sascha@saschahauer.de>
*
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 6ed7523c65bb..8ae4a2c5066f 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -56,7 +56,7 @@ static unsigned long imx_gettimeoffset(void)
* IRQ handler for the timer
*/
static irqreturn_t
-imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+imx_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
@@ -64,7 +64,7 @@ imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (IMX_TSTAT(TIMER_BASE))
IMX_TSTAT(TIMER_BASE) = 0;
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index 42021fdfa0c6..8d880cb9ba39 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -248,7 +248,7 @@ unsigned long integrator_gettimeoffset(void)
* IRQ handler for the timer
*/
static irqreturn_t
-integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+integrator_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
@@ -262,7 +262,7 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* primary CPU
*/
if (hard_smp_processor_id() == 0) {
- timer_tick(regs);
+ timer_tick();
#ifdef CONFIG_SMP
smp_send_timer();
#endif
@@ -272,7 +272,7 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*
* this is the ARM equivalent of the APIC timer interrupt
*/
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif /* CONFIG_SMP */
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index 678b6ba2b463..771b65bffe69 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -202,12 +202,12 @@ static struct irq_chip sic_chip = {
};
static void
-sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+sic_handle_irq(unsigned int irq, struct irqdesc *desc)
{
unsigned long status = sic_readl(INTCP_VA_SIC_BASE + IRQ_STATUS);
if (status == 0) {
- do_bad_IRQ(irq, desc, regs);
+ do_bad_IRQ(irq, desc);
return;
}
@@ -218,7 +218,7 @@ sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
irq += IRQ_SIC_START;
desc = irq_desc + irq;
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
} while (status);
}
diff --git a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c
index 4418f6d7572d..fb8c6d97b22b 100644
--- a/arch/arm/mach-integrator/pci_v3.c
+++ b/arch/arm/mach-integrator/pci_v3.c
@@ -440,9 +440,10 @@ v3_pci_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
return 1;
}
-static irqreturn_t v3_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t v3_irq(int irq, void *devid)
{
#ifdef CONFIG_DEBUG_LL
+ struct pt_regs *regs = get_irq_regs();
unsigned long pc = instruction_pointer(regs);
unsigned long instr = *(unsigned long *)pc;
char buf[128];
diff --git a/arch/arm/mach-integrator/time.c b/arch/arm/mach-integrator/time.c
index ee49cf790dab..5278f589fcee 100644
--- a/arch/arm/mach-integrator/time.c
+++ b/arch/arm/mach-integrator/time.c
@@ -96,8 +96,7 @@ static struct rtc_ops rtc_ops = {
.set_alarm = integrator_rtc_set_alarm,
};
-static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id)
{
writel(0, rtc_base + RTC_EOI);
return IRQ_HANDLED;
diff --git a/arch/arm/mach-iop32x/Kconfig b/arch/arm/mach-iop32x/Kconfig
new file mode 100644
index 000000000000..c072d94070da
--- /dev/null
+++ b/arch/arm/mach-iop32x/Kconfig
@@ -0,0 +1,35 @@
+if ARCH_IOP32X
+
+menu "IOP32x Implementation Options"
+
+comment "IOP32x Platform Types"
+
+config MACH_GLANTANK
+ bool "Enable support for the IO-Data GLAN Tank"
+ help
+ Say Y here if you want to run your kernel on the GLAN Tank
+ NAS appliance or machines from IO-Data's HDL-Gxxx, HDL-GWxxx
+ and HDL-GZxxx series.
+
+config ARCH_IQ80321
+ bool "Enable support for IQ80321"
+ help
+ Say Y here if you want to run your kernel on the Intel IQ80321
+ evaluation kit for the IOP321 processor.
+
+config ARCH_IQ31244
+ bool "Enable support for EP80219/IQ31244"
+ help
+ Say Y here if you want to run your kernel on the Intel EP80219
+ evaluation kit for the Intel 80219 processor (a IOP321 variant)
+ or the IQ31244 evaluation kit for the IOP321 processor.
+
+config MACH_N2100
+ bool "Enable support for the Thecus n2100"
+ help
+ Say Y here if you want to run your kernel on the Thecus n2100
+ NAS appliance.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-iop32x/Makefile b/arch/arm/mach-iop32x/Makefile
new file mode 100644
index 000000000000..7b05b37e1f94
--- /dev/null
+++ b/arch/arm/mach-iop32x/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y := irq.o
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_MACH_GLANTANK) += glantank.o
+obj-$(CONFIG_ARCH_IQ80321) += iq80321.o
+obj-$(CONFIG_ARCH_IQ31244) += iq31244.o
+obj-$(CONFIG_MACH_N2100) += n2100.o
diff --git a/arch/arm/mach-iop32x/Makefile.boot b/arch/arm/mach-iop32x/Makefile.boot
new file mode 100644
index 000000000000..47000dccd61f
--- /dev/null
+++ b/arch/arm/mach-iop32x/Makefile.boot
@@ -0,0 +1,3 @@
+ zreladdr-y := 0xa0008000
+params_phys-y := 0xa0000100
+initrd_phys-y := 0xa0800000
diff --git a/arch/arm/mach-iop32x/glantank.c b/arch/arm/mach-iop32x/glantank.c
new file mode 100644
index 000000000000..b9b765057dbe
--- /dev/null
+++ b/arch/arm/mach-iop32x/glantank.c
@@ -0,0 +1,195 @@
+/*
+ * arch/arm/mach-iop32x/glantank.c
+ *
+ * Board support code for the GLAN Tank.
+ *
+ * Copyright (C) 2006 Martin Michlmayr <tbm@cyrius.com>
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+
+/*
+ * GLAN Tank timer tick configuration.
+ */
+static void __init glantank_timer_init(void)
+{
+ /* 33.333 MHz crystal. */
+ iop3xx_init_time(200000000);
+}
+
+static struct sys_timer glantank_timer = {
+ .init = glantank_timer_init,
+ .offset = iop3xx_gettimeoffset,
+};
+
+
+/*
+ * GLAN Tank I/O.
+ */
+static struct map_desc glantank_io_desc[] __initdata = {
+ { /* on-board devices */
+ .virtual = GLANTANK_UART,
+ .pfn = __phys_to_pfn(GLANTANK_UART),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ },
+};
+
+void __init glantank_map_io(void)
+{
+ iop3xx_map_io();
+ iotable_init(glantank_io_desc, ARRAY_SIZE(glantank_io_desc));
+}
+
+
+/*
+ * GLAN Tank PCI.
+ */
+#define INTA IRQ_IOP32X_XINT0
+#define INTB IRQ_IOP32X_XINT1
+#define INTC IRQ_IOP32X_XINT2
+#define INTD IRQ_IOP32X_XINT3
+
+static inline int __init
+glantank_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ static int pci_irq_table[][4] = {
+ /*
+ * PCI IDSEL/INTPIN->INTLINE
+ * A B C D
+ */
+ {INTD, INTD, INTD, INTD}, /* UART (8250) */
+ {INTA, INTA, INTA, INTA}, /* Ethernet (E1000) */
+ {INTB, INTB, INTB, INTB}, /* IDE (AEC6280R) */
+ {INTC, INTC, INTC, INTC}, /* USB (NEC) */
+ };
+
+ BUG_ON(pin < 1 || pin > 4);
+
+ return pci_irq_table[slot % 4][pin - 1];
+}
+
+static struct hw_pci glantank_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = glantank_pci_map_irq,
+};
+
+static int __init glantank_pci_init(void)
+{
+ if (machine_is_glantank())
+ pci_common_init(&glantank_pci);
+
+ return 0;
+}
+
+subsys_initcall(glantank_pci_init);
+
+
+/*
+ * GLAN Tank machine initialization.
+ */
+static struct physmap_flash_data glantank_flash_data = {
+ .width = 1,
+};
+
+static struct resource glantank_flash_resource = {
+ .start = 0xf0000000,
+ .end = 0xf007ffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device glantank_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &glantank_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &glantank_flash_resource,
+};
+
+static struct plat_serial8250_port glantank_serial_port[] = {
+ {
+ .mapbase = GLANTANK_UART,
+ .membase = (char *)GLANTANK_UART,
+ .irq = IRQ_IOP32X_XINT3,
+ .flags = UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = 1843200,
+ },
+ { },
+};
+
+static struct resource glantank_uart_resource = {
+ .start = GLANTANK_UART,
+ .end = GLANTANK_UART + 7,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device glantank_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = glantank_serial_port,
+ },
+ .num_resources = 1,
+ .resource = &glantank_uart_resource,
+};
+
+static void glantank_power_off(void)
+{
+ __raw_writeb(0x01, 0xfe8d0004);
+
+ while (1)
+ ;
+}
+
+static void __init glantank_init_machine(void)
+{
+ platform_device_register(&iop3xx_i2c0_device);
+ platform_device_register(&iop3xx_i2c1_device);
+ platform_device_register(&glantank_flash_device);
+ platform_device_register(&glantank_serial_device);
+
+ pm_power_off = glantank_power_off;
+}
+
+MACHINE_START(GLANTANK, "GLAN Tank")
+ /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+ .phys_io = GLANTANK_UART,
+ .io_pg_offst = ((GLANTANK_UART) >> 18) & 0xfffc,
+ .boot_params = 0xa0000100,
+ .map_io = glantank_map_io,
+ .init_irq = iop32x_init_irq,
+ .timer = &glantank_timer,
+ .init_machine = glantank_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-iop32x/iq31244.c b/arch/arm/mach-iop32x/iq31244.c
new file mode 100644
index 000000000000..be4aedfa0de6
--- /dev/null
+++ b/arch/arm/mach-iop32x/iq31244.c
@@ -0,0 +1,293 @@
+/*
+ * arch/arm/mach-iop32x/iq31244.c
+ *
+ * Board support code for the Intel EP80219 and IQ31244 platforms.
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ * Copyright 2003 (c) MontaVista, Software, Inc.
+ * Copyright (C) 2004 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+
+/*
+ * The EP80219 and IQ31244 use the same machine ID. To find out
+ * which of the two we're running on, we look at the processor ID.
+ */
+static int is_80219(void)
+{
+ extern int processor_id;
+ return !!((processor_id & 0xffffffe0) == 0x69052e20);
+}
+
+
+/*
+ * EP80219/IQ31244 timer tick configuration.
+ */
+static void __init iq31244_timer_init(void)
+{
+ if (is_80219()) {
+ /* 33.333 MHz crystal. */
+ iop3xx_init_time(200000000);
+ } else {
+ /* 33.000 MHz crystal. */
+ iop3xx_init_time(198000000);
+ }
+}
+
+static struct sys_timer iq31244_timer = {
+ .init = iq31244_timer_init,
+ .offset = iop3xx_gettimeoffset,
+};
+
+
+/*
+ * IQ31244 I/O.
+ */
+static struct map_desc iq31244_io_desc[] __initdata = {
+ { /* on-board devices */
+ .virtual = IQ31244_UART,
+ .pfn = __phys_to_pfn(IQ31244_UART),
+ .length = 0x00100000,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init iq31244_map_io(void)
+{
+ iop3xx_map_io();
+ iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc));
+}
+
+
+/*
+ * EP80219/IQ31244 PCI.
+ */
+static inline int __init
+ep80219_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+
+ if (slot == 0) {
+ /* CFlash */
+ irq = IRQ_IOP32X_XINT1;
+ } else if (slot == 1) {
+ /* 82551 Pro 100 */
+ irq = IRQ_IOP32X_XINT0;
+ } else if (slot == 2) {
+ /* PCI-X Slot */
+ irq = IRQ_IOP32X_XINT3;
+ } else if (slot == 3) {
+ /* SATA */
+ irq = IRQ_IOP32X_XINT2;
+ } else {
+ printk(KERN_ERR "ep80219_pci_map_irq() called for unknown "
+ "device PCI:%d:%d:%d\n", dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ irq = -1;
+ }
+
+ return irq;
+}
+
+static struct hw_pci ep80219_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = ep80219_pci_map_irq,
+};
+
+static inline int __init
+iq31244_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+
+ if (slot == 0) {
+ /* CFlash */
+ irq = IRQ_IOP32X_XINT1;
+ } else if (slot == 1) {
+ /* SATA */
+ irq = IRQ_IOP32X_XINT2;
+ } else if (slot == 2) {
+ /* PCI-X Slot */
+ irq = IRQ_IOP32X_XINT3;
+ } else if (slot == 3) {
+ /* 82546 GigE */
+ irq = IRQ_IOP32X_XINT0;
+ } else {
+ printk(KERN_ERR "iq31244_pci_map_irq called for unknown "
+ "device PCI:%d:%d:%d\n", dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ irq = -1;
+ }
+
+ return irq;
+}
+
+static struct hw_pci iq31244_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = iq31244_pci_map_irq,
+};
+
+static int __init iq31244_pci_init(void)
+{
+ if (machine_is_iq31244()) {
+ if (is_80219()) {
+ pci_common_init(&ep80219_pci);
+ } else {
+ pci_common_init(&iq31244_pci);
+ }
+ }
+
+ return 0;
+}
+
+subsys_initcall(iq31244_pci_init);
+
+
+/*
+ * IQ31244 machine initialisation.
+ */
+static struct physmap_flash_data iq31244_flash_data = {
+ .width = 2,
+};
+
+static struct resource iq31244_flash_resource = {
+ .start = 0xf0000000,
+ .end = 0xf07fffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device iq31244_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &iq31244_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &iq31244_flash_resource,
+};
+
+static struct plat_serial8250_port iq31244_serial_port[] = {
+ {
+ .mapbase = IQ31244_UART,
+ .membase = (char *)IQ31244_UART,
+ .irq = IRQ_IOP32X_XINT1,
+ .flags = UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = 1843200,
+ },
+ { },
+};
+
+static struct resource iq31244_uart_resource = {
+ .start = IQ31244_UART,
+ .end = IQ31244_UART + 7,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device iq31244_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = iq31244_serial_port,
+ },
+ .num_resources = 1,
+ .resource = &iq31244_uart_resource,
+};
+
+/*
+ * This function will send a SHUTDOWN_COMPLETE message to the PIC
+ * controller over I2C. We are not using the i2c subsystem since
+ * we are going to power off and it may be removed
+ */
+void ep80219_power_off(void)
+{
+ /*
+ * Send the Address byte w/ the start condition
+ */
+ *IOP3XX_IDBR1 = 0x60;
+ *IOP3XX_ICR1 = 0xE9;
+ mdelay(1);
+
+ /*
+ * Send the START_MSG byte w/ no start or stop condition
+ */
+ *IOP3XX_IDBR1 = 0x0F;
+ *IOP3XX_ICR1 = 0xE8;
+ mdelay(1);
+
+ /*
+ * Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or
+ * stop condition
+ */
+ *IOP3XX_IDBR1 = 0x03;
+ *IOP3XX_ICR1 = 0xE8;
+ mdelay(1);
+
+ /*
+ * Send an ignored byte w/ stop condition
+ */
+ *IOP3XX_IDBR1 = 0x00;
+ *IOP3XX_ICR1 = 0xEA;
+
+ while (1)
+ ;
+}
+
+static void __init iq31244_init_machine(void)
+{
+ platform_device_register(&iop3xx_i2c0_device);
+ platform_device_register(&iop3xx_i2c1_device);
+ platform_device_register(&iq31244_flash_device);
+ platform_device_register(&iq31244_serial_device);
+
+ if (is_80219())
+ pm_power_off = ep80219_power_off;
+}
+
+MACHINE_START(IQ31244, "Intel IQ31244")
+ /* Maintainer: Intel Corp. */
+ .phys_io = IQ31244_UART,
+ .io_pg_offst = ((IQ31244_UART) >> 18) & 0xfffc,
+ .boot_params = 0xa0000100,
+ .map_io = iq31244_map_io,
+ .init_irq = iop32x_init_irq,
+ .timer = &iq31244_timer,
+ .init_machine = iq31244_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-iop32x/iq80321.c b/arch/arm/mach-iop32x/iq80321.c
new file mode 100644
index 000000000000..1f37b5501888
--- /dev/null
+++ b/arch/arm/mach-iop32x/iq80321.c
@@ -0,0 +1,193 @@
+/*
+ * arch/arm/mach-iop32x/iq80321.c
+ *
+ * Board support code for the Intel IQ80321 platform.
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ * Copyright (C) 2004 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+/*
+ * IQ80321 timer tick configuration.
+ */
+static void __init iq80321_timer_init(void)
+{
+ /* 33.333 MHz crystal. */
+ iop3xx_init_time(200000000);
+}
+
+static struct sys_timer iq80321_timer = {
+ .init = iq80321_timer_init,
+ .offset = iop3xx_gettimeoffset,
+};
+
+
+/*
+ * IQ80321 I/O.
+ */
+static struct map_desc iq80321_io_desc[] __initdata = {
+ { /* on-board devices */
+ .virtual = IQ80321_UART,
+ .pfn = __phys_to_pfn(IQ80321_UART),
+ .length = 0x00100000,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init iq80321_map_io(void)
+{
+ iop3xx_map_io();
+ iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc));
+}
+
+
+/*
+ * IQ80321 PCI.
+ */
+static inline int __init
+iq80321_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+
+ if ((slot == 2 || slot == 6) && pin == 1) {
+ /* PCI-X Slot INTA */
+ irq = IRQ_IOP32X_XINT2;
+ } else if ((slot == 2 || slot == 6) && pin == 2) {
+ /* PCI-X Slot INTA */
+ irq = IRQ_IOP32X_XINT3;
+ } else if ((slot == 2 || slot == 6) && pin == 3) {
+ /* PCI-X Slot INTA */
+ irq = IRQ_IOP32X_XINT0;
+ } else if ((slot == 2 || slot == 6) && pin == 4) {
+ /* PCI-X Slot INTA */
+ irq = IRQ_IOP32X_XINT1;
+ } else if (slot == 4 || slot == 8) {
+ /* Gig-E */
+ irq = IRQ_IOP32X_XINT0;
+ } else {
+ printk(KERN_ERR "iq80321_pci_map_irq() called for unknown "
+ "device PCI:%d:%d:%d\n", dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ irq = -1;
+ }
+
+ return irq;
+}
+
+static struct hw_pci iq80321_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = iq80321_pci_map_irq,
+};
+
+static int __init iq80321_pci_init(void)
+{
+ if (machine_is_iq80321())
+ pci_common_init(&iq80321_pci);
+
+ return 0;
+}
+
+subsys_initcall(iq80321_pci_init);
+
+
+/*
+ * IQ80321 machine initialisation.
+ */
+static struct physmap_flash_data iq80321_flash_data = {
+ .width = 1,
+};
+
+static struct resource iq80321_flash_resource = {
+ .start = 0xf0000000,
+ .end = 0xf07fffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device iq80321_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &iq80321_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &iq80321_flash_resource,
+};
+
+static struct plat_serial8250_port iq80321_serial_port[] = {
+ {
+ .mapbase = IQ80321_UART,
+ .membase = (char *)IQ80321_UART,
+ .irq = IRQ_IOP32X_XINT1,
+ .flags = UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = 1843200,
+ },
+ { },
+};
+
+static struct resource iq80321_uart_resource = {
+ .start = IQ80321_UART,
+ .end = IQ80321_UART + 7,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device iq80321_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = iq80321_serial_port,
+ },
+ .num_resources = 1,
+ .resource = &iq80321_uart_resource,
+};
+
+static void __init iq80321_init_machine(void)
+{
+ platform_device_register(&iop3xx_i2c0_device);
+ platform_device_register(&iop3xx_i2c1_device);
+ platform_device_register(&iq80321_flash_device);
+ platform_device_register(&iq80321_serial_device);
+}
+
+MACHINE_START(IQ80321, "Intel IQ80321")
+ /* Maintainer: Intel Corp. */
+ .phys_io = IQ80321_UART,
+ .io_pg_offst = ((IQ80321_UART) >> 18) & 0xfffc,
+ .boot_params = 0xa0000100,
+ .map_io = iq80321_map_io,
+ .init_irq = iop32x_init_irq,
+ .timer = &iq80321_timer,
+ .init_machine = iq80321_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-iop32x/irq.c b/arch/arm/mach-iop32x/irq.c
new file mode 100644
index 000000000000..69d6302f40cf
--- /dev/null
+++ b/arch/arm/mach-iop32x/irq.c
@@ -0,0 +1,76 @@
+/*
+ * arch/arm/mach-iop32x/irq.c
+ *
+ * Generic IOP32X IRQ handling functionality
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ *
+ * 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/interrupt.h>
+#include <linux/list.h>
+#include <asm/mach/irq.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+static u32 iop32x_mask;
+
+static inline void intctl_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c0, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static inline void intstr_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c4, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static void
+iop32x_irq_mask(unsigned int irq)
+{
+ iop32x_mask &= ~(1 << irq);
+ intctl_write(iop32x_mask);
+}
+
+static void
+iop32x_irq_unmask(unsigned int irq)
+{
+ iop32x_mask |= 1 << irq;
+ intctl_write(iop32x_mask);
+}
+
+struct irq_chip ext_chip = {
+ .name = "IOP32x",
+ .ack = iop32x_irq_mask,
+ .mask = iop32x_irq_mask,
+ .unmask = iop32x_irq_unmask,
+};
+
+void __init iop32x_init_irq(void)
+{
+ int i;
+
+ intctl_write(0);
+ intstr_write(0);
+ if (machine_is_glantank() ||
+ machine_is_iq80321() ||
+ machine_is_iq31244() ||
+ machine_is_n2100())
+ *IOP3XX_PCIIRSR = 0x0f;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ set_irq_chip(i, &ext_chip);
+ set_irq_handler(i, do_level_IRQ);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+}
diff --git a/arch/arm/mach-iop32x/n2100.c b/arch/arm/mach-iop32x/n2100.c
new file mode 100644
index 000000000000..a2c94a47b2b2
--- /dev/null
+++ b/arch/arm/mach-iop32x/n2100.c
@@ -0,0 +1,251 @@
+/*
+ * arch/arm/mach-iop32x/n2100.c
+ *
+ * Board support code for the Thecus N2100 platform.
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ * Copyright 2003 (c) MontaVista, Software, Inc.
+ * Copyright (C) 2004 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+/*
+ * N2100 timer tick configuration.
+ */
+static void __init n2100_timer_init(void)
+{
+ /* 33.000 MHz crystal. */
+ iop3xx_init_time(198000000);
+}
+
+static struct sys_timer n2100_timer = {
+ .init = n2100_timer_init,
+ .offset = iop3xx_gettimeoffset,
+};
+
+
+/*
+ * N2100 I/O.
+ */
+static struct map_desc n2100_io_desc[] __initdata = {
+ { /* on-board devices */
+ .virtual = N2100_UART,
+ .pfn = __phys_to_pfn(N2100_UART),
+ .length = 0x00100000,
+ .type = MT_DEVICE
+ },
+};
+
+void __init n2100_map_io(void)
+{
+ iop3xx_map_io();
+ iotable_init(n2100_io_desc, ARRAY_SIZE(n2100_io_desc));
+}
+
+
+/*
+ * N2100 PCI.
+ */
+static inline int __init
+n2100_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+
+ if (PCI_SLOT(dev->devfn) == 1) {
+ /* RTL8110SB #1 */
+ irq = IRQ_IOP32X_XINT0;
+ } else if (PCI_SLOT(dev->devfn) == 2) {
+ /* RTL8110SB #2 */
+ irq = IRQ_IOP32X_XINT1;
+ } else if (PCI_SLOT(dev->devfn) == 3) {
+ /* Sil3512 */
+ irq = IRQ_IOP32X_XINT2;
+ } else if (PCI_SLOT(dev->devfn) == 4 && pin == 1) {
+ /* VT6212 INTA */
+ irq = IRQ_IOP32X_XINT1;
+ } else if (PCI_SLOT(dev->devfn) == 4 && pin == 2) {
+ /* VT6212 INTB */
+ irq = IRQ_IOP32X_XINT0;
+ } else if (PCI_SLOT(dev->devfn) == 4 && pin == 3) {
+ /* VT6212 INTC */
+ irq = IRQ_IOP32X_XINT2;
+ } else if (PCI_SLOT(dev->devfn) == 5) {
+ /* Mini-PCI slot */
+ irq = IRQ_IOP32X_XINT3;
+ } else {
+ printk(KERN_ERR "n2100_pci_map_irq() called for unknown "
+ "device PCI:%d:%d:%d\n", dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ irq = -1;
+ }
+
+ return irq;
+}
+
+static struct hw_pci n2100_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = n2100_pci_map_irq,
+};
+
+static int __init n2100_pci_init(void)
+{
+ if (machine_is_n2100())
+ pci_common_init(&n2100_pci);
+
+ return 0;
+}
+
+subsys_initcall(n2100_pci_init);
+
+
+/*
+ * N2100 machine initialisation.
+ */
+static struct physmap_flash_data n2100_flash_data = {
+ .width = 2,
+};
+
+static struct resource n2100_flash_resource = {
+ .start = 0xf0000000,
+ .end = 0xf0ffffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device n2100_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &n2100_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &n2100_flash_resource,
+};
+
+
+static struct plat_serial8250_port n2100_serial_port[] = {
+ {
+ .mapbase = N2100_UART,
+ .membase = (char *)N2100_UART,
+ .irq = 0,
+ .flags = UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 0,
+ .uartclk = 1843200,
+ },
+ { },
+};
+
+static struct resource n2100_uart_resource = {
+ .start = N2100_UART,
+ .end = N2100_UART + 7,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device n2100_serial_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = n2100_serial_port,
+ },
+ .num_resources = 1,
+ .resource = &n2100_uart_resource,
+};
+
+
+/*
+ * Pull PCA9532 GPIO #8 low to power off the machine.
+ */
+static void n2100_power_off(void)
+{
+ local_irq_disable();
+
+ /* Start condition, I2C address of PCA9532, write transaction. */
+ *IOP3XX_IDBR0 = 0xc0;
+ *IOP3XX_ICR0 = 0xe9;
+ mdelay(1);
+
+ /* Write address 0x08. */
+ *IOP3XX_IDBR0 = 0x08;
+ *IOP3XX_ICR0 = 0xe8;
+ mdelay(1);
+
+ /* Write data 0x01, stop condition. */
+ *IOP3XX_IDBR0 = 0x01;
+ *IOP3XX_ICR0 = 0xea;
+
+ while (1)
+ ;
+}
+
+
+static struct timer_list power_button_poll_timer;
+
+static void power_button_poll(unsigned long dummy)
+{
+ if (gpio_line_get(N2100_POWER_BUTTON) == 0) {
+ ctrl_alt_del();
+ return;
+ }
+
+ power_button_poll_timer.expires = jiffies + (HZ / 10);
+ add_timer(&power_button_poll_timer);
+}
+
+
+static void __init n2100_init_machine(void)
+{
+ platform_device_register(&iop3xx_i2c0_device);
+ platform_device_register(&n2100_flash_device);
+ platform_device_register(&n2100_serial_device);
+
+ pm_power_off = n2100_power_off;
+
+ init_timer(&power_button_poll_timer);
+ power_button_poll_timer.function = power_button_poll;
+ power_button_poll_timer.expires = jiffies + (HZ / 10);
+ add_timer(&power_button_poll_timer);
+}
+
+MACHINE_START(N2100, "Thecus N2100")
+ /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+ .phys_io = N2100_UART,
+ .io_pg_offst = ((N2100_UART) >> 18) & 0xfffc,
+ .boot_params = 0xa0000100,
+ .map_io = n2100_map_io,
+ .init_irq = iop32x_init_irq,
+ .timer = &n2100_timer,
+ .init_machine = n2100_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-iop33x/Kconfig b/arch/arm/mach-iop33x/Kconfig
new file mode 100644
index 000000000000..9aa016bb18f9
--- /dev/null
+++ b/arch/arm/mach-iop33x/Kconfig
@@ -0,0 +1,21 @@
+if ARCH_IOP33X
+
+menu "IOP33x Implementation Options"
+
+comment "IOP33x Platform Types"
+
+config ARCH_IQ80331
+ bool "Enable support for IQ80331"
+ help
+ Say Y here if you want to run your kernel on the Intel IQ80331
+ evaluation kit for the IOP331 chipset.
+
+config MACH_IQ80332
+ bool "Enable support for IQ80332"
+ help
+ Say Y here if you want to run your kernel on the Intel IQ80332
+ evaluation kit for the IOP332 chipset.
+
+endmenu
+
+endif
diff --git a/arch/arm/mach-iop33x/Makefile b/arch/arm/mach-iop33x/Makefile
new file mode 100644
index 000000000000..90081d8c9d16
--- /dev/null
+++ b/arch/arm/mach-iop33x/Makefile
@@ -0,0 +1,11 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y := irq.o uart.o
+obj-m :=
+obj-n :=
+obj- :=
+
+obj-$(CONFIG_ARCH_IQ80331) += iq80331.o
+obj-$(CONFIG_MACH_IQ80332) += iq80332.o
diff --git a/arch/arm/mach-iop33x/Makefile.boot b/arch/arm/mach-iop33x/Makefile.boot
new file mode 100644
index 000000000000..67039c3e0c48
--- /dev/null
+++ b/arch/arm/mach-iop33x/Makefile.boot
@@ -0,0 +1,3 @@
+ zreladdr-y := 0x00008000
+params_phys-y := 0x00000100
+initrd_phys-y := 0x00800000
diff --git a/arch/arm/mach-iop33x/iq80331.c b/arch/arm/mach-iop33x/iq80331.c
new file mode 100644
index 000000000000..97a7b7488264
--- /dev/null
+++ b/arch/arm/mach-iop33x/iq80331.c
@@ -0,0 +1,148 @@
+/*
+ * arch/arm/mach-iop33x/iq80331.c
+ *
+ * Board support code for the Intel IQ80331 platform.
+ *
+ * Author: Dave Jiang <dave.jiang@intel.com>
+ * Copyright (C) 2003 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+/*
+ * IQ80331 timer tick configuration.
+ */
+static void __init iq80331_timer_init(void)
+{
+ /* D-Step parts run at a higher internal bus frequency */
+ if (*IOP3XX_ATURID >= 0xa)
+ iop3xx_init_time(333000000);
+ else
+ iop3xx_init_time(266000000);
+}
+
+static struct sys_timer iq80331_timer = {
+ .init = iq80331_timer_init,
+ .offset = iop3xx_gettimeoffset,
+};
+
+
+/*
+ * IQ80331 PCI.
+ */
+static inline int __init
+iq80331_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+
+ if (slot == 1 && pin == 1) {
+ /* PCI-X Slot INTA */
+ irq = IRQ_IOP33X_XINT1;
+ } else if (slot == 1 && pin == 2) {
+ /* PCI-X Slot INTB */
+ irq = IRQ_IOP33X_XINT2;
+ } else if (slot == 1 && pin == 3) {
+ /* PCI-X Slot INTC */
+ irq = IRQ_IOP33X_XINT3;
+ } else if (slot == 1 && pin == 4) {
+ /* PCI-X Slot INTD */
+ irq = IRQ_IOP33X_XINT0;
+ } else if (slot == 2) {
+ /* GigE */
+ irq = IRQ_IOP33X_XINT2;
+ } else {
+ printk(KERN_ERR "iq80331_pci_map_irq() called for unknown "
+ "device PCI:%d:%d:%d\n", dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ irq = -1;
+ }
+
+ return irq;
+}
+
+static struct hw_pci iq80331_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = iq80331_pci_map_irq,
+};
+
+static int __init iq80331_pci_init(void)
+{
+ if (machine_is_iq80331())
+ pci_common_init(&iq80331_pci);
+
+ return 0;
+}
+
+subsys_initcall(iq80331_pci_init);
+
+
+/*
+ * IQ80331 machine initialisation.
+ */
+static struct physmap_flash_data iq80331_flash_data = {
+ .width = 1,
+};
+
+static struct resource iq80331_flash_resource = {
+ .start = 0xc0000000,
+ .end = 0xc07fffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device iq80331_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &iq80331_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &iq80331_flash_resource,
+};
+
+static void __init iq80331_init_machine(void)
+{
+ platform_device_register(&iop3xx_i2c0_device);
+ platform_device_register(&iop3xx_i2c1_device);
+ platform_device_register(&iop33x_uart0_device);
+ platform_device_register(&iop33x_uart1_device);
+ platform_device_register(&iq80331_flash_device);
+}
+
+MACHINE_START(IQ80331, "Intel IQ80331")
+ /* Maintainer: Intel Corp. */
+ .phys_io = 0xfefff000,
+ .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = iop3xx_map_io,
+ .init_irq = iop33x_init_irq,
+ .timer = &iq80331_timer,
+ .init_machine = iq80331_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-iop33x/iq80332.c b/arch/arm/mach-iop33x/iq80332.c
new file mode 100644
index 000000000000..9887bfc1c078
--- /dev/null
+++ b/arch/arm/mach-iop33x/iq80332.c
@@ -0,0 +1,148 @@
+/*
+ * arch/arm/mach-iop33x/iq80332.c
+ *
+ * Board support code for the Intel IQ80332 platform.
+ *
+ * Author: Dave Jiang <dave.jiang@intel.com>
+ * Copyright (C) 2004 Intel Corp.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/pci.h>
+#include <asm/mach/time.h>
+#include <asm/mach-types.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+/*
+ * IQ80332 timer tick configuration.
+ */
+static void __init iq80332_timer_init(void)
+{
+ /* D-Step parts and the iop333 run at a higher internal bus frequency */
+ if (*IOP3XX_ATURID >= 0xa || *IOP3XX_ATUDID == 0x374)
+ iop3xx_init_time(333000000);
+ else
+ iop3xx_init_time(266000000);
+}
+
+static struct sys_timer iq80332_timer = {
+ .init = iq80332_timer_init,
+ .offset = iop3xx_gettimeoffset,
+};
+
+
+/*
+ * IQ80332 PCI.
+ */
+static inline int __init
+iq80332_pci_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
+{
+ int irq;
+
+ if (slot == 4 && pin == 1) {
+ /* PCI-X Slot INTA */
+ irq = IRQ_IOP33X_XINT0;
+ } else if (slot == 4 && pin == 2) {
+ /* PCI-X Slot INTB */
+ irq = IRQ_IOP33X_XINT1;
+ } else if (slot == 4 && pin == 3) {
+ /* PCI-X Slot INTC */
+ irq = IRQ_IOP33X_XINT2;
+ } else if (slot == 4 && pin == 4) {
+ /* PCI-X Slot INTD */
+ irq = IRQ_IOP33X_XINT3;
+ } else if (slot == 6) {
+ /* GigE */
+ irq = IRQ_IOP33X_XINT2;
+ } else {
+ printk(KERN_ERR "iq80332_pci_map_irq() called for unknown "
+ "device PCI:%d:%d:%d\n", dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+ irq = -1;
+ }
+
+ return irq;
+}
+
+static struct hw_pci iq80332_pci __initdata = {
+ .swizzle = pci_std_swizzle,
+ .nr_controllers = 1,
+ .setup = iop3xx_pci_setup,
+ .preinit = iop3xx_pci_preinit,
+ .scan = iop3xx_pci_scan_bus,
+ .map_irq = iq80332_pci_map_irq,
+};
+
+static int __init iq80332_pci_init(void)
+{
+ if (machine_is_iq80332())
+ pci_common_init(&iq80332_pci);
+
+ return 0;
+}
+
+subsys_initcall(iq80332_pci_init);
+
+
+/*
+ * IQ80332 machine initialisation.
+ */
+static struct physmap_flash_data iq80332_flash_data = {
+ .width = 1,
+};
+
+static struct resource iq80332_flash_resource = {
+ .start = 0xc0000000,
+ .end = 0xc07fffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device iq80332_flash_device = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &iq80332_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &iq80332_flash_resource,
+};
+
+static void __init iq80332_init_machine(void)
+{
+ platform_device_register(&iop3xx_i2c0_device);
+ platform_device_register(&iop3xx_i2c1_device);
+ platform_device_register(&iop33x_uart0_device);
+ platform_device_register(&iop33x_uart1_device);
+ platform_device_register(&iq80332_flash_device);
+}
+
+MACHINE_START(IQ80332, "Intel IQ80332")
+ /* Maintainer: Intel Corp. */
+ .phys_io = 0xfefff000,
+ .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = iop3xx_map_io,
+ .init_irq = iop33x_init_irq,
+ .timer = &iq80332_timer,
+ .init_machine = iq80332_init_machine,
+MACHINE_END
diff --git a/arch/arm/mach-iop33x/irq.c b/arch/arm/mach-iop33x/irq.c
new file mode 100644
index 000000000000..63304b3d0d76
--- /dev/null
+++ b/arch/arm/mach-iop33x/irq.c
@@ -0,0 +1,127 @@
+/*
+ * arch/arm/mach-iop33x/irq.c
+ *
+ * Generic IOP331 IRQ handling functionality
+ *
+ * Author: Dave Jiang <dave.jiang@intel.com>
+ * Copyright (C) 2003 Intel Corp.
+ *
+ * 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/interrupt.h>
+#include <linux/list.h>
+#include <asm/mach/irq.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+
+static u32 iop33x_mask0;
+static u32 iop33x_mask1;
+
+static inline void intctl0_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c0, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static inline void intctl1_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c1, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static inline void intstr0_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c2, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static inline void intstr1_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c3, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static inline void intbase_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c12, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static inline void intsize_write(u32 val)
+{
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c13, c0, 0" : : "r" (val));
+ iop3xx_cp6_disable();
+}
+
+static void
+iop33x_irq_mask1 (unsigned int irq)
+{
+ iop33x_mask0 &= ~(1 << irq);
+ intctl0_write(iop33x_mask0);
+}
+
+static void
+iop33x_irq_mask2 (unsigned int irq)
+{
+ iop33x_mask1 &= ~(1 << (irq - 32));
+ intctl1_write(iop33x_mask1);
+}
+
+static void
+iop33x_irq_unmask1(unsigned int irq)
+{
+ iop33x_mask0 |= 1 << irq;
+ intctl0_write(iop33x_mask0);
+}
+
+static void
+iop33x_irq_unmask2(unsigned int irq)
+{
+ iop33x_mask1 |= (1 << (irq - 32));
+ intctl1_write(iop33x_mask1);
+}
+
+struct irq_chip iop33x_irqchip1 = {
+ .name = "IOP33x-1",
+ .ack = iop33x_irq_mask1,
+ .mask = iop33x_irq_mask1,
+ .unmask = iop33x_irq_unmask1,
+};
+
+struct irq_chip iop33x_irqchip2 = {
+ .name = "IOP33x-2",
+ .ack = iop33x_irq_mask2,
+ .mask = iop33x_irq_mask2,
+ .unmask = iop33x_irq_unmask2,
+};
+
+void __init iop33x_init_irq(void)
+{
+ int i;
+
+ intctl0_write(0);
+ intctl1_write(0);
+ intstr0_write(0);
+ intstr1_write(0);
+ intbase_write(0);
+ intsize_write(1);
+ if (machine_is_iq80331())
+ *IOP3XX_PCIIRSR = 0x0f;
+
+ for (i = 0; i < NR_IRQS; i++) {
+ set_irq_chip(i, (i < 32) ? &iop33x_irqchip1 : &iop33x_irqchip2);
+ set_irq_handler(i, do_level_IRQ);
+ set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
+ }
+}
diff --git a/arch/arm/mach-iop33x/uart.c b/arch/arm/mach-iop33x/uart.c
new file mode 100644
index 000000000000..ac297cd0276c
--- /dev/null
+++ b/arch/arm/mach-iop33x/uart.c
@@ -0,0 +1,105 @@
+/*
+ * arch/arm/mach-iop33x/uart.c
+ *
+ * Author: Dave Jiang (dave.jiang@intel.com)
+ * Copyright (C) 2004 Intel 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.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/hardware/iop3xx.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#define IOP33X_UART_XTAL 33334000
+
+static struct plat_serial8250_port iop33x_uart0_data[] = {
+ {
+ .membase = (char *)IOP33X_UART0_VIRT,
+ .mapbase = IOP33X_UART0_PHYS,
+ .irq = IRQ_IOP33X_UART0,
+ .uartclk = IOP33X_UART_XTAL,
+ .regshift = 2,
+ .iotype = UPIO_MEM,
+ .flags = UPF_SKIP_TEST,
+ },
+ { },
+};
+
+static struct resource iop33x_uart0_resources[] = {
+ [0] = {
+ .start = IOP33X_UART0_PHYS,
+ .end = IOP33X_UART0_PHYS + 0x3f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_IOP33X_UART0,
+ .end = IRQ_IOP33X_UART0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device iop33x_uart0_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM,
+ .dev = {
+ .platform_data = iop33x_uart0_data,
+ },
+ .num_resources = 2,
+ .resource = iop33x_uart0_resources,
+};
+
+
+static struct resource iop33x_uart1_resources[] = {
+ [0] = {
+ .start = IOP33X_UART1_PHYS,
+ .end = IOP33X_UART1_PHYS + 0x3f,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_IOP33X_UART1,
+ .end = IRQ_IOP33X_UART1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct plat_serial8250_port iop33x_uart1_data[] = {
+ {
+ .membase = (char *)IOP33X_UART1_VIRT,
+ .mapbase = IOP33X_UART1_PHYS,
+ .irq = IRQ_IOP33X_UART1,
+ .uartclk = IOP33X_UART_XTAL,
+ .regshift = 2,
+ .iotype = UPIO_MEM,
+ .flags = UPF_SKIP_TEST,
+ },
+ { },
+};
+
+struct platform_device iop33x_uart1_device = {
+ .name = "serial8250",
+ .id = PLAT8250_DEV_PLATFORM1,
+ .dev = {
+ .platform_data = iop33x_uart1_data,
+ },
+ .num_resources = 2,
+ .resource = iop33x_uart1_resources,
+};
diff --git a/arch/arm/mach-iop3xx/Kconfig b/arch/arm/mach-iop3xx/Kconfig
deleted file mode 100644
index 4422f2388607..000000000000
--- a/arch/arm/mach-iop3xx/Kconfig
+++ /dev/null
@@ -1,66 +0,0 @@
-if ARCH_IOP3XX
-
-menu "IOP3xx Implementation Options"
-
-comment "IOP3xx Platform Types"
-
-config ARCH_IQ80321
- bool "Enable support for IQ80321"
- select ARCH_IOP321
- help
- Say Y here if you want to run your kernel on the Intel IQ80321
- evaluation kit for the IOP321 chipset.
-
-config ARCH_IQ31244
- bool "Enable support for IQ31244"
- select ARCH_IOP321
- help
- Say Y here if you want to run your kernel on the Intel IQ31244
- evaluation kit for the IOP321 chipset.
-
-config ARCH_IQ80331
- bool "Enable support for IQ80331"
- select ARCH_IOP331
- help
- Say Y here if you want to run your kernel on the Intel IQ80331
- evaluation kit for the IOP331 chipset.
-
-config MACH_IQ80332
- bool "Enable support for IQ80332"
- select ARCH_IOP331
- help
- Say Y here if you want to run your kernel on the Intel IQ80332
- evaluation kit for the IOP332 chipset.
-
-config ARCH_EP80219
- bool "Enable support for EP80219"
- select ARCH_IOP321
- select ARCH_IQ31244
- help
- Say Y here if you want to run your kernel on the Intel EP80219
- evaluation kit for the Intel 80219 chipset (a IOP321 variant).
-
-# Which IOP variant are we running?
-config ARCH_IOP321
- bool
- help
- The IQ80321 uses the IOP321 variant.
- The IQ31244 and EP80219 uses the IOP321 variant.
-
-config ARCH_IOP331
- bool
- default ARCH_IQ80331
- help
- The IQ80331, IQ80332, and IQ80333 uses the IOP331 variant.
-
-comment "IOP3xx Chipset Features"
-
-config IOP331_STEPD
- bool "Chip stepping D of the IOP80331 processor or IOP80333"
- depends on (ARCH_IOP331)
- help
- Say Y here if you have StepD of the IOP80331 or IOP8033
- based platforms.
-
-endmenu
-endif
diff --git a/arch/arm/mach-iop3xx/Makefile b/arch/arm/mach-iop3xx/Makefile
deleted file mode 100644
index b17eb1f46102..000000000000
--- a/arch/arm/mach-iop3xx/Makefile
+++ /dev/null
@@ -1,23 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Object file lists.
-
-obj-y := common.o
-
-obj-m :=
-obj-n :=
-obj- :=
-
-obj-$(CONFIG_ARCH_IOP321) += iop321-setup.o iop321-irq.o iop321-pci.o iop321-time.o
-
-obj-$(CONFIG_ARCH_IOP331) += iop331-setup.o iop331-irq.o iop331-pci.o iop331-time.o
-
-obj-$(CONFIG_ARCH_IQ80321) += iq80321-mm.o iq80321-pci.o
-
-obj-$(CONFIG_ARCH_IQ31244) += iq31244-mm.o iq31244-pci.o
-
-obj-$(CONFIG_ARCH_IQ80331) += iq80331-mm.o iq80331-pci.o
-
-obj-$(CONFIG_MACH_IQ80332) += iq80332-mm.o iq80332-pci.o
diff --git a/arch/arm/mach-iop3xx/Makefile.boot b/arch/arm/mach-iop3xx/Makefile.boot
deleted file mode 100644
index 6387aa20461b..000000000000
--- a/arch/arm/mach-iop3xx/Makefile.boot
+++ /dev/null
@@ -1,9 +0,0 @@
- zreladdr-y := 0xa0008000
-params_phys-y := 0xa0000100
-initrd_phys-y := 0xa0800000
-ifeq ($(CONFIG_ARCH_IOP331),y)
- zreladdr-y := 0x00008000
-params_phys-y := 0x00000100
-initrd_phys-y := 0x00800000
-endif
-
diff --git a/arch/arm/mach-iop3xx/common.c b/arch/arm/mach-iop3xx/common.c
deleted file mode 100644
index d7f50e57e753..000000000000
--- a/arch/arm/mach-iop3xx/common.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/common.c
- *
- * Common routines shared across all IOP3xx implementations
- *
- * Author: Deepak Saxena <dsaxena@mvista.com>
- *
- * Copyright 2003 (c) MontaVista, Software, Inc.
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/delay.h>
-#include <asm/hardware.h>
-
-/*
- * Shared variables
- */
-unsigned long iop3xx_pcibios_min_io = 0;
-unsigned long iop3xx_pcibios_min_mem = 0;
-
-#ifdef CONFIG_ARCH_EP80219
-#include <linux/kernel.h>
-/*
- * Default power-off for EP80219
- */
-
-static inline void ep80219_send_to_pic(__u8 c) {
-}
-
-void ep80219_power_off(void)
-{
- /*
- * This function will send a SHUTDOWN_COMPLETE message to the PIC controller
- * over I2C. We are not using the i2c subsystem since we are going to power
- * off and it may be removed
- */
-
- /* Send the Address byte w/ the start condition */
- *IOP321_IDBR1 = 0x60;
- *IOP321_ICR1 = 0xE9;
- mdelay(1);
-
- /* Send the START_MSG byte w/ no start or stop condition */
- *IOP321_IDBR1 = 0x0F;
- *IOP321_ICR1 = 0xE8;
- mdelay(1);
-
- /* Send the SHUTDOWN_COMPLETE Message ID byte w/ no start or stop condition */
- *IOP321_IDBR1 = 0x03;
- *IOP321_ICR1 = 0xE8;
- mdelay(1);
-
- /* Send an ignored byte w/ stop condition */
- *IOP321_IDBR1 = 0x00;
- *IOP321_ICR1 = 0xEA;
-
- while (1) ;
-}
-
-#include <linux/init.h>
-#include <linux/pm.h>
-
-static int __init ep80219_init(void)
-{
- pm_power_off = ep80219_power_off;
- return 0;
-}
-arch_initcall(ep80219_init);
-#endif
diff --git a/arch/arm/mach-iop3xx/iop321-irq.c b/arch/arm/mach-iop3xx/iop321-irq.c
deleted file mode 100644
index 88ac333472c8..000000000000
--- a/arch/arm/mach-iop3xx/iop321-irq.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/iop321-irq.c
- *
- * Generic IOP321 IRQ handling functionality
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright (C) 2002 Rory Bolt
- *
- * 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.
- *
- * Added IOP3XX chipset and IQ80321 board masking code.
- *
- */
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/list.h>
-
-#include <asm/mach/irq.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
-
-#include <asm/mach-types.h>
-
-static u32 iop321_mask /* = 0 */;
-
-static inline void intctl_write(u32 val)
-{
- asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val));
-}
-
-static inline void intstr_write(u32 val)
-{
- asm volatile("mcr p6,0,%0,c4,c0,0"::"r" (val));
-}
-
-static void
-iop321_irq_mask (unsigned int irq)
-{
-
- iop321_mask &= ~(1 << (irq - IOP321_IRQ_OFS));
-
- intctl_write(iop321_mask);
-}
-
-static void
-iop321_irq_unmask (unsigned int irq)
-{
- iop321_mask |= (1 << (irq - IOP321_IRQ_OFS));
-
- intctl_write(iop321_mask);
-}
-
-struct irq_chip ext_chip = {
- .name = "IOP",
- .ack = iop321_irq_mask,
- .mask = iop321_irq_mask,
- .unmask = iop321_irq_unmask,
-};
-
-void __init iop321_init_irq(void)
-{
- unsigned int i, tmp;
-
- /* Enable access to coprocessor 6 for dealing with IRQs.
- * From RMK:
- * Basically, the Intel documentation here is poor. It appears that
- * you need to set the bit to be able to access the coprocessor from
- * SVC mode. Whether that allows access from user space or not is
- * unclear.
- */
- asm volatile (
- "mrc p15, 0, %0, c15, c1, 0\n\t"
- "orr %0, %0, %1\n\t"
- "mcr p15, 0, %0, c15, c1, 0\n\t"
- /* The action is delayed, so we have to do this: */
- "mrc p15, 0, %0, c15, c1, 0\n\t"
- "mov %0, %0\n\t"
- "sub pc, pc, #4"
- : "=r" (tmp) : "i" (1 << 6) );
-
- intctl_write(0); // disable all interrupts
- intstr_write(0); // treat all as IRQ
- if(machine_is_iq80321() ||
- machine_is_iq31244()) // all interrupts are inputs to chip
- *IOP321_PCIIRSR = 0x0f;
-
- for(i = IOP321_IRQ_OFS; i < NR_IOP321_IRQS; i++)
- {
- set_irq_chip(i, &ext_chip);
- set_irq_handler(i, do_level_IRQ);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
-
- }
-}
-
diff --git a/arch/arm/mach-iop3xx/iop321-pci.c b/arch/arm/mach-iop3xx/iop321-pci.c
deleted file mode 100644
index 8ba6a0e23134..000000000000
--- a/arch/arm/mach-iop3xx/iop321-pci.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iop321-pci.c
- *
- * PCI support for the Intel IOP321 chipset
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright (C) 2002 Rory Bolt
- *
- * 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/hardware.h>
-#include <asm/mach/pci.h>
-
-#include <asm/arch/iop321.h>
-
-// #define DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
-
-/*
- * This routine builds either a type0 or type1 configuration command. If the
- * bus is on the 80321 then a type0 made, else a type1 is created.
- */
-static u32 iop321_cfg_address(struct pci_bus *bus, int devfn, int where)
-{
- struct pci_sys_data *sys = bus->sysdata;
- u32 addr;
-
- if (sys->busnr == bus->number)
- addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
- else
- addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
-
- addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
-
- return addr;
-}
-
-/*
- * This routine checks the status of the last configuration cycle. If an error
- * was detected it returns a 1, else it returns a 0. The errors being checked
- * are parity, master abort, target abort (master and target). These types of
- * errors occure during a config cycle where there is no device, like during
- * the discovery stage.
- */
-static int iop321_pci_status(void)
-{
- unsigned int status;
- int ret = 0;
-
- /*
- * Check the status registers.
- */
- status = *IOP321_ATUSR;
- if (status & 0xf900)
- {
- DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
- *IOP321_ATUSR = status & 0xf900;
- ret = 1;
- }
- status = *IOP321_ATUISR;
- if (status & 0x679f)
- {
- DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
- *IOP321_ATUISR = status & 0x679f;
- ret = 1;
- }
- return ret;
-}
-
-/*
- * Simply write the address register and read the configuration
- * data. Note that the 4 nop's ensure that we are able to handle
- * a delayed abort (in theory.)
- */
-static inline u32 iop321_read(unsigned long addr)
-{
- u32 val;
-
- __asm__ __volatile__(
- "str %1, [%2]\n\t"
- "ldr %0, [%3]\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- : "=r" (val)
- : "r" (addr), "r" (IOP321_OCCAR), "r" (IOP321_OCCDR));
-
- return val;
-}
-
-/*
- * The read routines must check the error status of the last configuration
- * cycle. If there was an error, the routine returns all hex f's.
- */
-static int
-iop321_read_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 *value)
-{
- unsigned long addr = iop321_cfg_address(bus, devfn, where);
- u32 val = iop321_read(addr) >> ((where & 3) * 8);
-
- if( iop321_pci_status() )
- val = 0xffffffff;
-
- *value = val;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-iop321_write_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 value)
-{
- unsigned long addr = iop321_cfg_address(bus, devfn, where);
- u32 val;
-
- if (size != 4) {
- val = iop321_read(addr);
- if (!iop321_pci_status() == 0)
- return PCIBIOS_SUCCESSFUL;
-
- where = (where & 3) * 8;
-
- if (size == 1)
- val &= ~(0xff << where);
- else
- val &= ~(0xffff << where);
-
- *IOP321_OCCDR = val | value << where;
- } else {
- asm volatile(
- "str %1, [%2]\n\t"
- "str %0, [%3]\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- :
- : "r" (value), "r" (addr),
- "r" (IOP321_OCCAR), "r" (IOP321_OCCDR));
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops iop321_ops = {
- .read = iop321_read_config,
- .write = iop321_write_config,
-};
-
-/*
- * When a PCI device does not exist during config cycles, the 80200 gets a
- * bus error instead of returning 0xffffffff. This handler simply returns.
- */
-int
-iop321_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
-{
- DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
- addr, fsr, regs->ARM_pc, regs->ARM_lr);
-
- /*
- * If it was an imprecise abort, then we need to correct the
- * return address to be _after_ the instruction.
- */
- if (fsr & (1 << 10))
- regs->ARM_pc += 4;
-
- return 0;
-}
-
-/*
- * Scan an IOP321 PCI bus. sys->bus defines which bus we scan.
- */
-struct pci_bus *iop321_scan_bus(int nr, struct pci_sys_data *sys)
-{
- return pci_scan_bus(sys->busnr, &iop321_ops, sys);
-}
-
-void iop321_init(void)
-{
- DBG("PCI: Intel 80321 PCI init code.\n");
- DBG("ATU: IOP321_ATUCMD=0x%04x\n", *IOP321_ATUCMD);
- DBG("ATU: IOP321_OMWTVR0=0x%04x, IOP321_OIOWTVR=0x%04x\n",
- *IOP321_OMWTVR0,
- *IOP321_OIOWTVR);
- DBG("ATU: IOP321_ATUCR=0x%08x\n", *IOP321_ATUCR);
- DBG("ATU: IOP321_IABAR0=0x%08x IOP321_IALR0=0x%08x IOP321_IATVR0=%08x\n",
- *IOP321_IABAR0, *IOP321_IALR0, *IOP321_IATVR0);
- DBG("ATU: IOP321_OMWTVR0=0x%08x\n", *IOP321_OMWTVR0);
- DBG("ATU: IOP321_IABAR1=0x%08x IOP321_IALR1=0x%08x\n",
- *IOP321_IABAR1, *IOP321_IALR1);
- DBG("ATU: IOP321_ERBAR=0x%08x IOP321_ERLR=0x%08x IOP321_ERTVR=%08x\n",
- *IOP321_ERBAR, *IOP321_ERLR, *IOP321_ERTVR);
- DBG("ATU: IOP321_IABAR2=0x%08x IOP321_IALR2=0x%08x IOP321_IATVR2=%08x\n",
- *IOP321_IABAR2, *IOP321_IALR2, *IOP321_IATVR2);
- DBG("ATU: IOP321_IABAR3=0x%08x IOP321_IALR3=0x%08x IOP321_IATVR3=%08x\n",
- *IOP321_IABAR3, *IOP321_IALR3, *IOP321_IATVR3);
-
- hook_fault_code(16+6, iop321_pci_abort, SIGBUS, "imprecise external abort");
-}
-
diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c
deleted file mode 100644
index b6d096903c4a..000000000000
--- a/arch/arm/mach-iop3xx/iop321-setup.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/iop321-setup.c
- *
- * Author: Nicolas Pitre <nico@cam.org>
- * Copyright (C) 2001 MontaVista Software, Inc.
- * Copyright (C) 2004 Intel 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.
- *
- */
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/platform_device.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_core.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/mach/map.h>
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/memory.h>
-#include <asm/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#define IOP321_UART_XTAL 1843200
-
-/*
- * Standard IO mapping for all IOP321 based systems
- */
-static struct map_desc iop321_std_desc[] __initdata = {
- { /* mem mapped registers */
- .virtual = IOP321_VIRT_MEM_BASE,
- .pfn = __phys_to_pfn(IOP321_PHYS_MEM_BASE),
- .length = 0x00002000,
- .type = MT_DEVICE
- }, { /* PCI IO space */
- .virtual = IOP321_PCI_LOWER_IO_VA,
- .pfn = __phys_to_pfn(IOP321_PCI_LOWER_IO_PA),
- .length = IOP321_PCI_IO_WINDOW_SIZE,
- .type = MT_DEVICE
- }
-};
-
-#ifdef CONFIG_ARCH_IQ80321
-#define UARTBASE IQ80321_UART
-#define IRQ_UART IRQ_IQ80321_UART
-#endif
-
-#ifdef CONFIG_ARCH_IQ31244
-#define UARTBASE IQ31244_UART
-#define IRQ_UART IRQ_IQ31244_UART
-#endif
-
-static struct uart_port iop321_serial_ports[] = {
- {
- .membase = (char*)(UARTBASE),
- .mapbase = (UARTBASE),
- .irq = IRQ_UART,
- .flags = UPF_SKIP_TEST,
- .iotype = UPIO_MEM,
- .regshift = 0,
- .uartclk = IOP321_UART_XTAL,
- .line = 0,
- .type = PORT_16550A,
- .fifosize = 16
- }
-};
-
-static struct resource iop32x_i2c_0_resources[] = {
- [0] = {
- .start = 0xfffff680,
- .end = 0xfffff698,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_IOP321_I2C_0,
- .end = IRQ_IOP321_I2C_0,
- .flags = IORESOURCE_IRQ
- }
-};
-
-static struct resource iop32x_i2c_1_resources[] = {
- [0] = {
- .start = 0xfffff6a0,
- .end = 0xfffff6b8,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_IOP321_I2C_1,
- .end = IRQ_IOP321_I2C_1,
- .flags = IORESOURCE_IRQ
- }
-};
-
-static struct platform_device iop32x_i2c_0_controller = {
- .name = "IOP3xx-I2C",
- .id = 0,
- .num_resources = 2,
- .resource = iop32x_i2c_0_resources
-};
-
-static struct platform_device iop32x_i2c_1_controller = {
- .name = "IOP3xx-I2C",
- .id = 1,
- .num_resources = 2,
- .resource = iop32x_i2c_1_resources
-};
-
-static struct platform_device *iop32x_devices[] __initdata = {
- &iop32x_i2c_0_controller,
- &iop32x_i2c_1_controller
-};
-
-void __init iop32x_init(void)
-{
- if(iop_is_321())
- {
- platform_add_devices(iop32x_devices,
- ARRAY_SIZE(iop32x_devices));
- }
-}
-
-void __init iop321_map_io(void)
-{
- iotable_init(iop321_std_desc, ARRAY_SIZE(iop321_std_desc));
- early_serial_setup(&iop321_serial_ports[0]);
-}
-
-#ifdef CONFIG_ARCH_IQ80321
-extern void iq80321_map_io(void);
-extern struct sys_timer iop321_timer;
-extern void iop321_init_time(void);
-#endif
-
-#ifdef CONFIG_ARCH_IQ31244
-extern void iq31244_map_io(void);
-extern struct sys_timer iop321_timer;
-extern void iop321_init_time(void);
-#endif
-
-#if defined(CONFIG_ARCH_IQ80321)
-MACHINE_START(IQ80321, "Intel IQ80321")
- /* Maintainer: Intel Corporation */
- .phys_io = IQ80321_UART,
- .io_pg_offst = ((IQ80321_UART) >> 18) & 0xfffc,
- .map_io = iq80321_map_io,
- .init_irq = iop321_init_irq,
- .timer = &iop321_timer,
- .boot_params = 0xa0000100,
- .init_machine = iop32x_init,
-MACHINE_END
-#elif defined(CONFIG_ARCH_IQ31244)
-MACHINE_START(IQ31244, "Intel IQ31244")
- /* Maintainer: Intel Corp. */
- .phys_io = IQ31244_UART,
- .io_pg_offst = ((IQ31244_UART) >> 18) & 0xfffc,
- .map_io = iq31244_map_io,
- .init_irq = iop321_init_irq,
- .timer = &iop321_timer,
- .boot_params = 0xa0000100,
- .init_machine = iop32x_init,
-MACHINE_END
-#else
-#error No machine descriptor defined for this IOP3XX implementation
-#endif
diff --git a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c
deleted file mode 100644
index 04b1a6f7ebae..000000000000
--- a/arch/arm/mach-iop3xx/iop321-time.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iop321-time.c
- *
- * Timer code for IOP321 based systems
- *
- * Author: Deepak Saxena <dsaxena@mvista.com>
- *
- * Copyright 2002-2003 MontaVista Software Inc.
- *
- * 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/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-
-#define IOP321_TIME_SYNC 0
-
-static inline unsigned long get_elapsed(void)
-{
- return LATCH - *IOP321_TU_TCR0;
-}
-
-static unsigned long iop321_gettimeoffset(void)
-{
- unsigned long elapsed, usec;
- u32 tisr1, tisr2;
-
- /*
- * If an interrupt was pending before we read the timer,
- * we've already wrapped. Factor this into the time.
- * If an interrupt was pending after we read the timer,
- * it may have wrapped between checking the interrupt
- * status and reading the timer. Re-read the timer to
- * be sure its value is after the wrap.
- */
-
- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
- elapsed = get_elapsed();
- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
-
- if(tisr1 & 1)
- elapsed += LATCH;
- else if (tisr2 & 1)
- elapsed = LATCH + get_elapsed();
-
- /*
- * Now convert them to usec.
- */
- usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
-
- return usec;
-}
-
-static irqreturn_t
-iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- u32 tisr;
-
- write_seqlock(&xtime_lock);
-
- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
- tisr |= 1;
- asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
-
- timer_tick(regs);
-
- write_sequnlock(&xtime_lock);
-
- return IRQ_HANDLED;
-}
-
-static struct irqaction iop321_timer_irq = {
- .name = "IOP321 Timer Tick",
- .handler = iop321_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
-};
-
-static void __init iop321_timer_init(void)
-{
- u32 timer_ctl;
-
- setup_irq(IRQ_IOP321_TIMER0, &iop321_timer_irq);
-
- timer_ctl = IOP321_TMR_EN | IOP321_TMR_PRIVILEGED | IOP321_TMR_RELOAD |
- IOP321_TMR_RATIO_1_1;
-
- asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH));
-
- asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
-}
-
-struct sys_timer iop321_timer = {
- .init = &iop321_timer_init,
- .offset = iop321_gettimeoffset,
-};
diff --git a/arch/arm/mach-iop3xx/iop331-irq.c b/arch/arm/mach-iop3xx/iop331-irq.c
deleted file mode 100644
index cab11722ced2..000000000000
--- a/arch/arm/mach-iop3xx/iop331-irq.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/iop331-irq.c
- *
- * Generic IOP331 IRQ handling functionality
- *
- * Author: Dave Jiang <dave.jiang@intel.com>
- * Copyright (C) 2003 Intel Corp.
- *
- * 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/interrupt.h>
-#include <linux/list.h>
-
-#include <asm/mach/irq.h>
-#include <asm/irq.h>
-#include <asm/hardware.h>
-
-#include <asm/mach-types.h>
-
-static u32 iop331_mask0 = 0;
-static u32 iop331_mask1 = 0;
-
-static inline void intctl_write0(u32 val)
-{
- // INTCTL0
- asm volatile("mcr p6,0,%0,c0,c0,0"::"r" (val));
-}
-
-static inline void intctl_write1(u32 val)
-{
- // INTCTL1
- asm volatile("mcr p6,0,%0,c1,c0,0"::"r" (val));
-}
-
-static inline void intstr_write0(u32 val)
-{
- // INTSTR0
- asm volatile("mcr p6,0,%0,c2,c0,0"::"r" (val));
-}
-
-static inline void intstr_write1(u32 val)
-{
- // INTSTR1
- asm volatile("mcr p6,0,%0,c3,c0,0"::"r" (val));
-}
-
-static void
-iop331_irq_mask1 (unsigned int irq)
-{
- iop331_mask0 &= ~(1 << (irq - IOP331_IRQ_OFS));
- intctl_write0(iop331_mask0);
-}
-
-static void
-iop331_irq_mask2 (unsigned int irq)
-{
- iop331_mask1 &= ~(1 << (irq - IOP331_IRQ_OFS - 32));
- intctl_write1(iop331_mask1);
-}
-
-static void
-iop331_irq_unmask1(unsigned int irq)
-{
- iop331_mask0 |= (1 << (irq - IOP331_IRQ_OFS));
- intctl_write0(iop331_mask0);
-}
-
-static void
-iop331_irq_unmask2(unsigned int irq)
-{
- iop331_mask1 |= (1 << (irq - IOP331_IRQ_OFS - 32));
- intctl_write1(iop331_mask1);
-}
-
-struct irq_chip iop331_irqchip1 = {
- .name = "IOP-1",
- .ack = iop331_irq_mask1,
- .mask = iop331_irq_mask1,
- .unmask = iop331_irq_unmask1,
-};
-
-struct irq_chip iop331_irqchip2 = {
- .name = "IOP-2",
- .ack = iop331_irq_mask2,
- .mask = iop331_irq_mask2,
- .unmask = iop331_irq_unmask2,
-};
-
-void __init iop331_init_irq(void)
-{
- unsigned int i, tmp;
-
- /* Enable access to coprocessor 6 for dealing with IRQs.
- * From RMK:
- * Basically, the Intel documentation here is poor. It appears that
- * you need to set the bit to be able to access the coprocessor from
- * SVC mode. Whether that allows access from user space or not is
- * unclear.
- */
- asm volatile (
- "mrc p15, 0, %0, c15, c1, 0\n\t"
- "orr %0, %0, %1\n\t"
- "mcr p15, 0, %0, c15, c1, 0\n\t"
- /* The action is delayed, so we have to do this: */
- "mrc p15, 0, %0, c15, c1, 0\n\t"
- "mov %0, %0\n\t"
- "sub pc, pc, #4"
- : "=r" (tmp) : "i" (1 << 6) );
-
- intctl_write0(0); // disable all interrupts
- intctl_write1(0);
- intstr_write0(0); // treat all as IRQ
- intstr_write1(0);
- if(machine_is_iq80331()) // all interrupts are inputs to chip
- *IOP331_PCIIRSR = 0x0f;
-
- for(i = IOP331_IRQ_OFS; i < NR_IOP331_IRQS; i++)
- {
- set_irq_chip(i, (i < 32) ? &iop331_irqchip1 : &iop331_irqchip2);
- set_irq_handler(i, do_level_IRQ);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
-}
-
diff --git a/arch/arm/mach-iop3xx/iop331-pci.c b/arch/arm/mach-iop3xx/iop331-pci.c
deleted file mode 100644
index 44dd213b48a3..000000000000
--- a/arch/arm/mach-iop3xx/iop331-pci.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iop331-pci.c
- *
- * PCI support for the Intel IOP331 chipset
- *
- * Author: Dave Jiang (dave.jiang@intel.com)
- * Copyright (C) 2003, 2004 Intel Corp.
- *
- * 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/hardware.h>
-#include <asm/mach/pci.h>
-
-#include <asm/arch/iop331.h>
-
-#undef DEBUG
-#undef DEBUG1
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...) do { } while (0)
-#endif
-
-#ifdef DEBUG1
-#define DBG1(x...) printk(x)
-#else
-#define DBG1(x...) do { } while (0)
-#endif
-
-/*
- * This routine builds either a type0 or type1 configuration command. If the
- * bus is on the 80331 then a type0 made, else a type1 is created.
- */
-static u32 iop331_cfg_address(struct pci_bus *bus, int devfn, int where)
-{
- struct pci_sys_data *sys = bus->sysdata;
- u32 addr;
-
- if (sys->busnr == bus->number)
- addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
- else
- addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
-
- addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
-
- return addr;
-}
-
-/*
- * This routine checks the status of the last configuration cycle. If an error
- * was detected it returns a 1, else it returns a 0. The errors being checked
- * are parity, master abort, target abort (master and target). These types of
- * errors occure during a config cycle where there is no device, like during
- * the discovery stage.
- */
-static int iop331_pci_status(void)
-{
- unsigned int status;
- int ret = 0;
-
- /*
- * Check the status registers.
- */
- status = *IOP331_ATUSR;
- if (status & 0xf900)
- {
- DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
- *IOP331_ATUSR = status & 0xf900;
- ret = 1;
- }
- status = *IOP331_ATUISR;
- if (status & 0x679f)
- {
- DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
- *IOP331_ATUISR = status & 0x679f;
- ret = 1;
- }
- return ret;
-}
-
-/*
- * Simply write the address register and read the configuration
- * data. Note that the 4 nop's ensure that we are able to handle
- * a delayed abort (in theory.)
- */
-static inline u32 iop331_read(unsigned long addr)
-{
- u32 val;
-
- __asm__ __volatile__(
- "str %1, [%2]\n\t"
- "ldr %0, [%3]\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- : "=r" (val)
- : "r" (addr), "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
-
- return val;
-}
-
-/*
- * The read routines must check the error status of the last configuration
- * cycle. If there was an error, the routine returns all hex f's.
- */
-static int
-iop331_read_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 *value)
-{
- unsigned long addr = iop331_cfg_address(bus, devfn, where);
- u32 val = iop331_read(addr) >> ((where & 3) * 8);
-
- if( iop331_pci_status() )
- val = 0xffffffff;
-
- *value = val;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-iop331_write_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 value)
-{
- unsigned long addr = iop331_cfg_address(bus, devfn, where);
- u32 val;
-
- if (size != 4) {
- val = iop331_read(addr);
- if (!iop331_pci_status() == 0)
- return PCIBIOS_SUCCESSFUL;
-
- where = (where & 3) * 8;
-
- if (size == 1)
- val &= ~(0xff << where);
- else
- val &= ~(0xffff << where);
-
- *IOP331_OCCDR = val | value << where;
- } else {
- asm volatile(
- "str %1, [%2]\n\t"
- "str %0, [%3]\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- :
- : "r" (value), "r" (addr),
- "r" (IOP331_OCCAR), "r" (IOP331_OCCDR));
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops iop331_ops = {
- .read = iop331_read_config,
- .write = iop331_write_config,
-};
-
-/*
- * When a PCI device does not exist during config cycles, the XScale gets a
- * bus error instead of returning 0xffffffff. This handler simply returns.
- */
-int
-iop331_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
-{
- DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
- addr, fsr, regs->ARM_pc, regs->ARM_lr);
-
- /*
- * If it was an imprecise abort, then we need to correct the
- * return address to be _after_ the instruction.
- */
- if (fsr & (1 << 10))
- regs->ARM_pc += 4;
-
- return 0;
-}
-
-/*
- * Scan an IOP331 PCI bus. sys->bus defines which bus we scan.
- */
-struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *sys)
-{
- return pci_scan_bus(sys->busnr, &iop331_ops, sys);
-}
-
-void iop331_init(void)
-{
- DBG1("PCI: Intel 80331 PCI init code.\n");
- DBG1("\tATU: IOP331_ATUCMD=0x%04x\n", *IOP331_ATUCMD);
- DBG1("\tATU: IOP331_OMWTVR0=0x%04x, IOP331_OIOWTVR=0x%04x\n",
- *IOP331_OMWTVR0,
- *IOP331_OIOWTVR);
- DBG1("\tATU: IOP331_OMWTVR1=0x%04x\n", *IOP331_OMWTVR1);
- DBG1("\tATU: IOP331_ATUCR=0x%08x\n", *IOP331_ATUCR);
- DBG1("\tATU: IOP331_IABAR0=0x%08x IOP331_IALR0=0x%08x IOP331_IATVR0=%08x\n", *IOP331_IABAR0, *IOP331_IALR0, *IOP331_IATVR0);
- DBG1("\tATU: IOP31_IABAR1=0x%08x IOP331_IALR1=0x%08x\n", *IOP331_IABAR1, *IOP331_IALR1);
- DBG1("\tATU: IOP331_ERBAR=0x%08x IOP331_ERLR=0x%08x IOP331_ERTVR=%08x\n", *IOP331_ERBAR, *IOP331_ERLR, *IOP331_ERTVR);
- DBG1("\tATU: IOP331_IABAR2=0x%08x IOP331_IALR2=0x%08x IOP331_IATVR2=%08x\n", *IOP331_IABAR2, *IOP331_IALR2, *IOP331_IATVR2);
- DBG1("\tATU: IOP331_IABAR3=0x%08x IOP331_IALR3=0x%08x IOP331_IATVR3=%08x\n", *IOP331_IABAR3, *IOP331_IALR3, *IOP331_IATVR3);
-
- hook_fault_code(16+6, iop331_pci_abort, SIGBUS, "imprecise external abort");
-}
-
diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c
deleted file mode 100644
index 3cc98d892ad4..000000000000
--- a/arch/arm/mach-iop3xx/iop331-setup.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/iop331-setup.c
- *
- * Author: Dave Jiang (dave.jiang@intel.com)
- * Copyright (C) 2004 Intel 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.
- *
- */
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/major.h>
-#include <linux/fs.h>
-#include <linux/platform_device.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <asm/mach/map.h>
-#include <asm/setup.h>
-#include <asm/system.h>
-#include <asm/memory.h>
-#include <asm/hardware.h>
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#define IOP331_UART_XTAL 33334000
-
-/*
- * Standard IO mapping for all IOP331 based systems
- */
-static struct map_desc iop331_std_desc[] __initdata = {
- { /* mem mapped registers */
- .virtual = IOP331_VIRT_MEM_BASE,
- .pfn = __phys_to_pfn(IOP331_PHYS_MEM_BASE),
- .length = 0x00002000,
- .type = MT_DEVICE
- }, { /* PCI IO space */
- .virtual = IOP331_PCI_LOWER_IO_VA,
- .pfn = __phys_to_pfn(IOP331_PCI_LOWER_IO_PA),
- .length = IOP331_PCI_IO_WINDOW_SIZE,
- .type = MT_DEVICE
- }
-};
-
-static struct resource iop33x_uart0_resources[] = {
- [0] = {
- .start = IOP331_UART0_PHYS,
- .end = IOP331_UART0_PHYS + 0x3f,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_IOP331_UART0,
- .end = IRQ_IOP331_UART0,
- .flags = IORESOURCE_IRQ
- }
-};
-
-static struct resource iop33x_uart1_resources[] = {
- [0] = {
- .start = IOP331_UART1_PHYS,
- .end = IOP331_UART1_PHYS + 0x3f,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_IOP331_UART1,
- .end = IRQ_IOP331_UART1,
- .flags = IORESOURCE_IRQ
- }
-};
-
-static struct plat_serial8250_port iop33x_uart0_data[] = {
- {
- .membase = (char*)(IOP331_UART0_VIRT),
- .mapbase = (IOP331_UART0_PHYS),
- .irq = IRQ_IOP331_UART0,
- .uartclk = IOP331_UART_XTAL,
- .regshift = 2,
- .iotype = UPIO_MEM,
- .flags = UPF_SKIP_TEST,
- },
- { },
-};
-
-static struct plat_serial8250_port iop33x_uart1_data[] = {
- {
- .membase = (char*)(IOP331_UART1_VIRT),
- .mapbase = (IOP331_UART1_PHYS),
- .irq = IRQ_IOP331_UART1,
- .uartclk = IOP331_UART_XTAL,
- .regshift = 2,
- .iotype = UPIO_MEM,
- .flags = UPF_SKIP_TEST,
- },
- { },
-};
-
-static struct platform_device iop33x_uart0 = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM,
- .dev.platform_data = iop33x_uart0_data,
- .num_resources = 2,
- .resource = iop33x_uart0_resources,
-};
-
-static struct platform_device iop33x_uart1 = {
- .name = "serial8250",
- .id = PLAT8250_DEV_PLATFORM1,
- .dev.platform_data = iop33x_uart1_data,
- .num_resources = 2,
- .resource = iop33x_uart1_resources,
-};
-
-static struct resource iop33x_i2c_0_resources[] = {
- [0] = {
- .start = 0xfffff680,
- .end = 0xfffff698,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_IOP331_I2C_0,
- .end = IRQ_IOP331_I2C_0,
- .flags = IORESOURCE_IRQ
- }
-};
-
-static struct resource iop33x_i2c_1_resources[] = {
- [0] = {
- .start = 0xfffff6a0,
- .end = 0xfffff6b8,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_IOP331_I2C_1,
- .end = IRQ_IOP331_I2C_1,
- .flags = IORESOURCE_IRQ
- }
-};
-
-static struct platform_device iop33x_i2c_0_controller = {
- .name = "IOP3xx-I2C",
- .id = 0,
- .num_resources = 2,
- .resource = iop33x_i2c_0_resources
-};
-
-static struct platform_device iop33x_i2c_1_controller = {
- .name = "IOP3xx-I2C",
- .id = 1,
- .num_resources = 2,
- .resource = iop33x_i2c_1_resources
-};
-
-static struct platform_device *iop33x_devices[] __initdata = {
- &iop33x_uart0,
- &iop33x_uart1,
- &iop33x_i2c_0_controller,
- &iop33x_i2c_1_controller
-};
-
-void __init iop33x_init(void)
-{
- if(iop_is_331())
- {
- platform_add_devices(iop33x_devices,
- ARRAY_SIZE(iop33x_devices));
- }
-}
-
-void __init iop331_map_io(void)
-{
- iotable_init(iop331_std_desc, ARRAY_SIZE(iop331_std_desc));
-}
-
-#ifdef CONFIG_ARCH_IOP331
-extern void iop331_init_irq(void);
-extern struct sys_timer iop331_timer;
-#endif
-
-#ifdef CONFIG_ARCH_IQ80331
-extern void iq80331_map_io(void);
-#endif
-
-#ifdef CONFIG_MACH_IQ80332
-extern void iq80332_map_io(void);
-#endif
-
-#if defined(CONFIG_ARCH_IQ80331)
-MACHINE_START(IQ80331, "Intel IQ80331")
- /* Maintainer: Intel Corp. */
- .phys_io = 0xfefff000,
- .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
- .map_io = iq80331_map_io,
- .init_irq = iop331_init_irq,
- .timer = &iop331_timer,
- .boot_params = 0x0100,
- .init_machine = iop33x_init,
-MACHINE_END
-
-#elif defined(CONFIG_MACH_IQ80332)
-MACHINE_START(IQ80332, "Intel IQ80332")
- /* Maintainer: Intel Corp. */
- .phys_io = 0xfefff000,
- .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
- .map_io = iq80332_map_io,
- .init_irq = iop331_init_irq,
- .timer = &iop331_timer,
- .boot_params = 0x0100,
- .init_machine = iop33x_init,
-MACHINE_END
-
-#else
-#error No machine descriptor defined for this IOP3XX implementation
-#endif
-
-
diff --git a/arch/arm/mach-iop3xx/iop331-time.c b/arch/arm/mach-iop3xx/iop331-time.c
deleted file mode 100644
index 0c09e74c5740..000000000000
--- a/arch/arm/mach-iop3xx/iop331-time.c
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iop331-time.c
- *
- * Timer code for IOP331 based systems
- *
- * Author: Dave Jiang <dave.jiang@intel.com>
- *
- * Copyright 2003 Intel Corp.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/time.h>
-#include <linux/init.h>
-#include <linux/timex.h>
-
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/time.h>
-
-static inline unsigned long get_elapsed(void)
-{
- return LATCH - *IOP331_TU_TCR0;
-}
-
-static unsigned long iop331_gettimeoffset(void)
-{
- unsigned long elapsed, usec;
- u32 tisr1, tisr2;
-
- /*
- * If an interrupt was pending before we read the timer,
- * we've already wrapped. Factor this into the time.
- * If an interrupt was pending after we read the timer,
- * it may have wrapped between checking the interrupt
- * status and reading the timer. Re-read the timer to
- * be sure its value is after the wrap.
- */
-
- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr1));
- elapsed = get_elapsed();
- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr2));
-
- if(tisr1 & 1)
- elapsed += LATCH;
- else if (tisr2 & 1)
- elapsed = LATCH + get_elapsed();
-
- /*
- * Now convert them to usec.
- */
- usec = (unsigned long)(elapsed / (CLOCK_TICK_RATE/1000000));
-
- return usec;
-}
-
-static irqreturn_t
-iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- u32 tisr;
-
- write_seqlock(&xtime_lock);
-
- asm volatile("mrc p6, 0, %0, c6, c1, 0" : "=r" (tisr));
- tisr |= 1;
- asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (tisr));
-
- timer_tick(regs);
-
- write_sequnlock(&xtime_lock);
- return IRQ_HANDLED;
-}
-
-static struct irqaction iop331_timer_irq = {
- .name = "IOP331 Timer Tick",
- .handler = iop331_timer_interrupt,
- .flags = IRQF_DISABLED | IRQF_TIMER,
-};
-
-static void __init iop331_timer_init(void)
-{
- u32 timer_ctl;
-
- setup_irq(IRQ_IOP331_TIMER0, &iop331_timer_irq);
-
- timer_ctl = IOP331_TMR_EN | IOP331_TMR_PRIVILEGED | IOP331_TMR_RELOAD |
- IOP331_TMR_RATIO_1_1;
-
- asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (LATCH));
-
- asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
-
-}
-
-struct sys_timer iop331_timer = {
- .init = iop331_timer_init,
- .offset = iop331_gettimeoffset,
-};
diff --git a/arch/arm/mach-iop3xx/iq31244-mm.c b/arch/arm/mach-iop3xx/iq31244-mm.c
deleted file mode 100644
index e874b54eefe3..000000000000
--- a/arch/arm/mach-iop3xx/iq31244-mm.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/mm.c
- *
- * Low level memory initialization for iq80321 platform
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright (C) 2002 Rory Bolt
- *
- * 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/mm.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
-
-
-/*
- * IQ80321 specific IO mappings
- *
- * We use RedBoot's setup for the onboard devices.
- */
-static struct map_desc iq31244_io_desc[] __initdata = {
- { /* on-board devices */
- .virtual = IQ31244_UART,
- .pfn = __phys_to_pfn(IQ31244_UART),
- .length = 0x00100000,
- .type = MT_DEVICE
- }
-};
-
-void __init iq31244_map_io(void)
-{
- iop321_map_io();
-
- iotable_init(iq31244_io_desc, ARRAY_SIZE(iq31244_io_desc));
-}
diff --git a/arch/arm/mach-iop3xx/iq31244-pci.c b/arch/arm/mach-iop3xx/iq31244-pci.c
deleted file mode 100644
index f3c6413fa5bd..000000000000
--- a/arch/arm/mach-iop3xx/iq31244-pci.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iq80321-pci.c
- *
- * PCI support for the Intel IQ80321 reference board
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright (C) 2002 Rory Bolt
- * Copyright (C) 2004 Intel Corp.
- *
- * 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach/pci.h>
-#include <asm/mach-types.h>
-
-/*
- * The following macro is used to lookup irqs in a standard table
- * format for those systems that do not already have PCI
- * interrupts properly routed. We assume 1 <= pin <= 4
- */
-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
-({ int _ctl_ = -1; \
- unsigned int _idsel = idsel - minid; \
- if (_idsel <= maxid) \
- _ctl_ = pci_irq_table[_idsel][pin-1]; \
- _ctl_; })
-
-#define INTA IRQ_IQ31244_INTA
-#define INTB IRQ_IQ31244_INTB
-#define INTC IRQ_IQ31244_INTC
-#define INTD IRQ_IQ31244_INTD
-
-#define INTE IRQ_IQ31244_I82546
-
-static inline int __init
-iq31244_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
-{
- static int pci_irq_table[][4] = {
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
-#ifdef CONFIG_ARCH_EP80219
- {INTB, INTB, INTB, INTB}, /* CFlash */
- {INTE, INTE, INTE, INTE}, /* 82551 Pro 100 */
- {INTD, INTD, INTD, INTD}, /* PCI-X Slot */
- {INTC, INTC, INTC, INTC}, /* SATA */
-#else
- {INTB, INTB, INTB, INTB}, /* CFlash */
- {INTC, INTC, INTC, INTC}, /* SATA */
- {INTD, INTD, INTD, INTD}, /* PCI-X Slot */
- {INTE, INTE, INTE, INTE}, /* 82546 GigE */
-#endif // CONFIG_ARCH_EP80219
- };
-
- BUG_ON(pin < 1 || pin > 4);
-
- return PCI_IRQ_TABLE_LOOKUP(0, 7);
-}
-
-static int iq31244_setup(int nr, struct pci_sys_data *sys)
-{
- struct resource *res;
-
- if(nr != 0)
- return 0;
-
- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
- if (!res)
- panic("PCI: unable to alloc resources");
-
- res[0].start = IOP321_PCI_LOWER_IO_VA;
- res[0].end = IOP321_PCI_UPPER_IO_VA;
- res[0].name = "IQ31244 PCI I/O Space";
- res[0].flags = IORESOURCE_IO;
-
- res[1].start = IOP321_PCI_LOWER_MEM_PA;
- res[1].end = IOP321_PCI_UPPER_MEM_PA;
- res[1].name = "IQ31244 PCI Memory Space";
- res[1].flags = IORESOURCE_MEM;
-
- request_resource(&ioport_resource, &res[0]);
- request_resource(&iomem_resource, &res[1]);
-
- sys->mem_offset = IOP321_PCI_MEM_OFFSET;
- sys->io_offset = IOP321_PCI_IO_OFFSET;
-
- sys->resource[0] = &res[0];
- sys->resource[1] = &res[1];
- sys->resource[2] = NULL;
-
- return 1;
-}
-
-static void iq31244_preinit(void)
-{
- iop321_init();
-}
-
-static struct hw_pci iq31244_pci __initdata = {
- .swizzle = pci_std_swizzle,
- .nr_controllers = 1,
- .setup = iq31244_setup,
- .scan = iop321_scan_bus,
- .preinit = iq31244_preinit,
- .map_irq = iq31244_map_irq
-};
-
-static int __init iq31244_pci_init(void)
-{
- if (machine_is_iq31244())
- pci_common_init(&iq31244_pci);
- return 0;
-}
-
-subsys_initcall(iq31244_pci_init);
-
-
-
-
diff --git a/arch/arm/mach-iop3xx/iq80321-mm.c b/arch/arm/mach-iop3xx/iq80321-mm.c
deleted file mode 100644
index d9cac5e1fc3d..000000000000
--- a/arch/arm/mach-iop3xx/iq80321-mm.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/mm.c
- *
- * Low level memory initialization for iq80321 platform
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright (C) 2002 Rory Bolt
- *
- * 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/mm.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
-
-
-/*
- * IQ80321 specific IO mappings
- *
- * We use RedBoot's setup for the onboard devices.
- */
-static struct map_desc iq80321_io_desc[] __initdata = {
- { /* on-board devices */
- .virtual = IQ80321_UART,
- .pfn = __phys_to_pfn(IQ80321_UART),
- .length = 0x00100000,
- .type = MT_DEVICE
- }
-};
-
-void __init iq80321_map_io(void)
-{
- iop321_map_io();
-
- iotable_init(iq80321_io_desc, ARRAY_SIZE(iq80321_io_desc));
-}
diff --git a/arch/arm/mach-iop3xx/iq80321-pci.c b/arch/arm/mach-iop3xx/iq80321-pci.c
deleted file mode 100644
index d9758d3f6e7f..000000000000
--- a/arch/arm/mach-iop3xx/iq80321-pci.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iq80321-pci.c
- *
- * PCI support for the Intel IQ80321 reference board
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright (C) 2002 Rory Bolt
- * Copyright (C) 2004 Intel Corp.
- *
- * 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach/pci.h>
-#include <asm/mach-types.h>
-
-/*
- * The following macro is used to lookup irqs in a standard table
- * format for those systems that do not already have PCI
- * interrupts properly routed. We assume 1 <= pin <= 4
- */
-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
-({ int _ctl_ = -1; \
- unsigned int _idsel = idsel - minid; \
- if (_idsel <= maxid) \
- _ctl_ = pci_irq_table[_idsel][pin-1]; \
- _ctl_; })
-
-#define INTA IRQ_IQ80321_INTA
-#define INTB IRQ_IQ80321_INTB
-#define INTC IRQ_IQ80321_INTC
-#define INTD IRQ_IQ80321_INTD
-
-#define INTE IRQ_IQ80321_I82544
-
-static inline int __init
-iq80321_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
-{
- static int pci_irq_table[][4] = {
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {INTE, INTE, INTE, INTE}, /* Gig-E */
- {-1, -1, -1, -1}, /* Unused */
- {INTC, INTD, INTA, INTB}, /* PCI-X Slot */
- {-1, -1, -1, -1},
- };
-
- BUG_ON(pin < 1 || pin > 4);
-
-// return PCI_IRQ_TABLE_LOOKUP(4, 7);
- return pci_irq_table[idsel%4][pin-1];
-}
-
-static int iq80321_setup(int nr, struct pci_sys_data *sys)
-{
- struct resource *res;
-
- if(nr != 0)
- return 0;
-
- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
- if (!res)
- panic("PCI: unable to alloc resources");
-
- res[0].start = IOP321_PCI_LOWER_IO_VA;
- res[0].end = IOP321_PCI_UPPER_IO_VA;
- res[0].name = "IQ80321 PCI I/O Space";
- res[0].flags = IORESOURCE_IO;
-
- res[1].start = IOP321_PCI_LOWER_MEM_PA;
- res[1].end = IOP321_PCI_UPPER_MEM_PA;
- res[1].name = "IQ80321 PCI Memory Space";
- res[1].flags = IORESOURCE_MEM;
-
- request_resource(&ioport_resource, &res[0]);
- request_resource(&iomem_resource, &res[1]);
-
- sys->mem_offset = IOP321_PCI_MEM_OFFSET;
- sys->io_offset = IOP321_PCI_IO_OFFSET;
-
- sys->resource[0] = &res[0];
- sys->resource[1] = &res[1];
- sys->resource[2] = NULL;
-
- return 1;
-}
-
-static void iq80321_preinit(void)
-{
- iop321_init();
-}
-
-static struct hw_pci iq80321_pci __initdata = {
- .swizzle = pci_std_swizzle,
- .nr_controllers = 1,
- .setup = iq80321_setup,
- .scan = iop321_scan_bus,
- .preinit = iq80321_preinit,
- .map_irq = iq80321_map_irq
-};
-
-static int __init iq80321_pci_init(void)
-{
- if (machine_is_iq80321())
- pci_common_init(&iq80321_pci);
- return 0;
-}
-
-subsys_initcall(iq80321_pci_init);
-
-
-
-
diff --git a/arch/arm/mach-iop3xx/iq80331-mm.c b/arch/arm/mach-iop3xx/iq80331-mm.c
deleted file mode 100644
index 129eb49b0670..000000000000
--- a/arch/arm/mach-iop3xx/iq80331-mm.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/mm.c
- *
- * Low level memory initialization for iq80331 platform
- *
- * Author: Dave Jiang <dave.jiang@intel.com>
- * Copyright (C) 2003 Intel Corp.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
-
-
-/*
- * IQ80331 specific IO mappings
- *
- * We use RedBoot's setup for the onboard devices.
- */
-
-void __init iq80331_map_io(void)
-{
- iop331_map_io();
-}
diff --git a/arch/arm/mach-iop3xx/iq80331-pci.c b/arch/arm/mach-iop3xx/iq80331-pci.c
deleted file mode 100644
index 40d861002492..000000000000
--- a/arch/arm/mach-iop3xx/iq80331-pci.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iq80331-pci.c
- *
- * PCI support for the Intel IQ80331 reference board
- *
- * Author: Dave Jiang <dave.jiang@intel.com>
- * Copyright (C) 2003, 2004 Intel Corp.
- *
- * 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach/pci.h>
-#include <asm/mach-types.h>
-
-/*
- * The following macro is used to lookup irqs in a standard table
- * format for those systems that do not already have PCI
- * interrupts properly routed. We assume 1 <= pin <= 4
- */
-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
-({ int _ctl_ = -1; \
- unsigned int _idsel = idsel - minid; \
- if (_idsel <= maxid) \
- _ctl_ = pci_irq_table[_idsel][pin-1]; \
- _ctl_; })
-
-#define INTA IRQ_IQ80331_INTA
-#define INTB IRQ_IQ80331_INTB
-#define INTC IRQ_IQ80331_INTC
-#define INTD IRQ_IQ80331_INTD
-
-//#define INTE IRQ_IQ80331_I82544
-
-static inline int __init
-iq80331_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
-{
- static int pci_irq_table[][4] = {
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {INTB, INTC, INTD, INTA}, /* PCI-X Slot */
- {INTC, INTC, INTC, INTC}, /* GigE */
- };
-
- BUG_ON(pin < 1 || pin > 4);
-
- return PCI_IRQ_TABLE_LOOKUP(1, 7);
-}
-
-static int iq80331_setup(int nr, struct pci_sys_data *sys)
-{
- struct resource *res;
-
- if(nr != 0)
- return 0;
-
- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
- if (!res)
- panic("PCI: unable to alloc resources");
-
- res[0].start = IOP331_PCI_LOWER_IO_VA;
- res[0].end = IOP331_PCI_UPPER_IO_VA;
- res[0].name = "IQ80331 PCI I/O Space";
- res[0].flags = IORESOURCE_IO;
-
- res[1].start = IOP331_PCI_LOWER_MEM_PA;
- res[1].end = IOP331_PCI_UPPER_MEM_PA;
- res[1].name = "IQ80331 PCI Memory Space";
- res[1].flags = IORESOURCE_MEM;
-
- request_resource(&ioport_resource, &res[0]);
- request_resource(&iomem_resource, &res[1]);
-
- sys->mem_offset = IOP331_PCI_MEM_OFFSET;
- sys->io_offset = IOP331_PCI_IO_OFFSET;
-
- sys->resource[0] = &res[0];
- sys->resource[1] = &res[1];
- sys->resource[2] = NULL;
-
- return 1;
-}
-
-static void iq80331_preinit(void)
-{
- iop331_init();
-}
-
-static struct hw_pci iq80331_pci __initdata = {
- .swizzle = pci_std_swizzle,
- .nr_controllers = 1,
- .setup = iq80331_setup,
- .scan = iop331_scan_bus,
- .preinit = iq80331_preinit,
- .map_irq = iq80331_map_irq
-};
-
-static int __init iq80331_pci_init(void)
-{
- if (machine_is_iq80331())
- pci_common_init(&iq80331_pci);
- return 0;
-}
-
-subsys_initcall(iq80331_pci_init);
-
-
-
-
diff --git a/arch/arm/mach-iop3xx/iq80332-mm.c b/arch/arm/mach-iop3xx/iq80332-mm.c
deleted file mode 100644
index 2feaf7591f53..000000000000
--- a/arch/arm/mach-iop3xx/iq80332-mm.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * linux/arch/arm/mach-iop3xx/mm.c
- *
- * Low level memory initialization for iq80332 platform
- *
- * Author: Dave Jiang <dave.jiang@intel.com>
- * Copyright (C) 2004 Intel Corp.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/mm.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-
-#include <asm/mach/map.h>
-
-
-/*
- * IQ80332 specific IO mappings
- *
- * We use RedBoot's setup for the onboard devices.
- */
-
-void __init iq80332_map_io(void)
-{
- iop331_map_io();
-}
diff --git a/arch/arm/mach-iop3xx/iq80332-pci.c b/arch/arm/mach-iop3xx/iq80332-pci.c
deleted file mode 100644
index afc0676318e4..000000000000
--- a/arch/arm/mach-iop3xx/iq80332-pci.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * arch/arm/mach-iop3xx/iq80332-pci.c
- *
- * PCI support for the Intel IQ80332 reference board
- *
- * Author: Dave Jiang <dave.jiang@intel.com>
- * Copyright (C) 2004 Intel Corp.
- *
- * 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/kernel.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include <asm/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach/pci.h>
-#include <asm/mach-types.h>
-
-/*
- * The following macro is used to lookup irqs in a standard table
- * format for those systems that do not already have PCI
- * interrupts properly routed. We assume 1 <= pin <= 4
- */
-#define PCI_IRQ_TABLE_LOOKUP(minid,maxid) \
-({ int _ctl_ = -1; \
- unsigned int _idsel = idsel - minid; \
- if (_idsel <= maxid) \
- _ctl_ = pci_irq_table[_idsel][pin-1]; \
- _ctl_; })
-
-#define INTA IRQ_IQ80332_INTA
-#define INTB IRQ_IQ80332_INTB
-#define INTC IRQ_IQ80332_INTC
-#define INTD IRQ_IQ80332_INTD
-
-//#define INTE IRQ_IQ80332_I82544
-
-static inline int __init
-iq80332_map_irq(struct pci_dev *dev, u8 idsel, u8 pin)
-{
- static int pci_irq_table[][8] = {
- /*
- * PCI IDSEL/INTPIN->INTLINE
- * A B C D
- */
- {-1, -1, -1, -1},
- {-1, -1, -1, -1},
- {-1, -1, -1, -1},
- {INTA, INTB, INTC, INTD}, /* PCI-X Slot */
- {-1, -1, -1, -1},
- {INTC, INTC, INTC, INTC}, /* GigE */
- {-1, -1, -1, -1},
- {-1, -1, -1, -1},
- };
-
- BUG_ON(pin < 1 || pin > 4);
-
- return PCI_IRQ_TABLE_LOOKUP(1, 7);
-}
-
-static int iq80332_setup(int nr, struct pci_sys_data *sys)
-{
- struct resource *res;
-
- if(nr != 0)
- return 0;
-
- res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
- if (!res)
- panic("PCI: unable to alloc resources");
-
- res[0].start = IOP331_PCI_LOWER_IO_VA;
- res[0].end = IOP331_PCI_UPPER_IO_VA;
- res[0].name = "IQ80332 PCI I/O Space";
- res[0].flags = IORESOURCE_IO;
-
- res[1].start = IOP331_PCI_LOWER_MEM_PA;
- res[1].end = IOP331_PCI_UPPER_MEM_PA;
- res[1].name = "IQ80332 PCI Memory Space";
- res[1].flags = IORESOURCE_MEM;
-
- request_resource(&ioport_resource, &res[0]);
- request_resource(&iomem_resource, &res[1]);
-
- sys->mem_offset = IOP331_PCI_MEM_OFFSET;
- sys->io_offset = IOP331_PCI_IO_OFFSET;
-
- sys->resource[0] = &res[0];
- sys->resource[1] = &res[1];
- sys->resource[2] = NULL;
-
- return 1;
-}
-
-static void iq80332_preinit(void)
-{
- iop331_init();
-}
-
-static struct hw_pci iq80332_pci __initdata = {
- .swizzle = pci_std_swizzle,
- .nr_controllers = 1,
- .setup = iq80332_setup,
- .scan = iop331_scan_bus,
- .preinit = iq80332_preinit,
- .map_irq = iq80332_map_irq
-};
-
-static int __init iq80332_pci_init(void)
-{
- if (machine_is_iq80332())
- pci_common_init(&iq80332_pci);
- return 0;
-}
-
-subsys_initcall(iq80332_pci_init);
-
-
-
-
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index 7f91f689a041..22c98e9dad28 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -204,7 +204,7 @@ unsigned long ixp2000_gettimeoffset (void)
return offset / ticks_per_usec;
}
-static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static int ixp2000_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
@@ -213,7 +213,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
while ((signed long)(next_jiffy_time - *missing_jiffy_timer_csr)
>= ticks_per_jiffy) {
- timer_tick(regs);
+ timer_tick();
next_jiffy_time -= ticks_per_jiffy;
}
@@ -308,7 +308,7 @@ EXPORT_SYMBOL(gpio_line_config);
/*************************************************************************
* IRQ handling IXP2000
*************************************************************************/
-static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc)
{
int i;
unsigned long status = *IXP2000_GPIO_INST;
@@ -316,7 +316,7 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str
for (i = 0; i <= 7; i++) {
if (status & (1<<i)) {
desc = irq_desc + i + IRQ_IXP2000_GPIO0;
- desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc, regs);
+ desc_handle_irq(i + IRQ_IXP2000_GPIO0, desc);
}
}
}
@@ -401,7 +401,7 @@ static void ixp2000_pci_irq_unmask(unsigned int irq)
/*
* Error interrupts. These are used extensively by the microengine drivers
*/
-static void ixp2000_err_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void ixp2000_err_irq_handler(unsigned int irq, struct irqdesc *desc)
{
int i;
unsigned long status = *IXP2000_IRQ_ERR_STATUS;
@@ -409,7 +409,7 @@ static void ixp2000_err_irq_handler(unsigned int irq, struct irqdesc *desc, str
for(i = 31; i >= 0; i--) {
if(status & (1 << i)) {
desc = irq_desc + IRQ_IXP2000_DRAM0_MIN_ERR + i;
- desc_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc, regs);
+ desc_handle_irq(IRQ_IXP2000_DRAM0_MIN_ERR + i, desc);
}
}
}
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
index a6f14801872d..9ee63834e603 100644
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ b/arch/arm/mach-ixp2000/ixdp2400.c
@@ -133,11 +133,13 @@ static void ixdp2400_pci_postinit(void)
struct pci_dev *dev;
if (ixdp2x00_master_npu()) {
- dev = pci_find_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
+ dev = pci_get_bus_and_slot(1, IXDP2400_SLAVE_ENET_DEVFN);
pci_remove_bus_device(dev);
+ pci_dev_put(dev)
} else {
- dev = pci_find_slot(1, IXDP2400_MASTER_ENET_DEVFN);
+ dev = pci_get_bus_and_slot(1, IXDP2400_MASTER_ENET_DEVFN);
pci_remove_bus_device(dev);
+ pci_dev_put(dev)
ixdp2x00_slave_pci_postinit();
}
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index 91d36d91dac0..70d247f09a7e 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -261,14 +261,16 @@ int __init ixdp2800_pci_init(void)
pci_common_init(&ixdp2800_pci);
if (ixdp2x00_master_npu()) {
- dev = pci_find_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
+ dev = pci_get_bus_and_slot(1, IXDP2800_SLAVE_ENET_DEVFN);
pci_remove_bus_device(dev);
+ pci_dev_put(dev);
ixdp2800_master_enable_slave();
ixdp2800_master_wait_for_slave_bus_scan();
} else {
- dev = pci_find_slot(1, IXDP2800_MASTER_ENET_DEVFN);
+ dev = pci_get_bus_and_slot(1, IXDP2800_MASTER_ENET_DEVFN);
pci_remove_bus_device(dev);
+ pci_dev_put(dev);
}
}
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 40eef8b36740..aa2655092d2d 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -106,7 +106,7 @@ static void ixdp2x00_irq_unmask(unsigned int irq)
ixp2000_release_slowport(&old_cfg);
}
-static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc)
{
volatile u32 ex_interrupt = 0;
static struct slowport_cfg old_cfg;
@@ -132,7 +132,7 @@ static void ixdp2x00_irq_handler(unsigned int irq, struct irqdesc *desc, struct
struct irqdesc *cpld_desc;
int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
cpld_desc = irq_desc + cpld_irq;
- desc_handle_irq(cpld_irq, cpld_desc, regs);
+ desc_handle_irq(cpld_irq, cpld_desc);
}
}
@@ -241,11 +241,14 @@ void ixdp2x00_slave_pci_postinit(void)
/*
* Remove PMC device is there is one
*/
- if((dev = pci_find_slot(1, IXDP2X00_PMC_DEVFN)))
+ if((dev = pci_get_bus_and_slot(1, IXDP2X00_PMC_DEVFN))) {
pci_remove_bus_device(dev);
+ pci_dev_put(dev);
+ }
- dev = pci_find_slot(0, IXDP2X00_21555_DEVFN);
+ dev = pci_get_bus_and_slot(0, IXDP2X00_21555_DEVFN);
pci_remove_bus_device(dev);
+ pci_dev_put(dev);
}
/**************************************************************************
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index 7f42366f60d1..9ccae9e63f70 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -63,7 +63,7 @@ static void ixdp2x01_irq_unmask(unsigned int irq)
static u32 valid_irq_mask;
-static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc)
{
u32 ex_interrupt;
int i;
@@ -82,7 +82,7 @@ static void ixdp2x01_irq_handler(unsigned int irq, struct irqdesc *desc, struct
struct irqdesc *cpld_desc;
int cpld_irq = IXP2000_BOARD_IRQ(0) + i;
cpld_desc = irq_desc + cpld_irq;
- desc_handle_irq(cpld_irq, cpld_desc, regs);
+ desc_handle_irq(cpld_irq, cpld_desc);
}
}
diff --git a/arch/arm/mach-ixp23xx/core.c b/arch/arm/mach-ixp23xx/core.c
index 566a07821c77..a704a1820048 100644
--- a/arch/arm/mach-ixp23xx/core.c
+++ b/arch/arm/mach-ixp23xx/core.c
@@ -251,7 +251,7 @@ static void ixp23xx_pci_irq_unmask(unsigned int irq)
/*
* TODO: Should this just be done at ASM level?
*/
-static void pci_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void pci_handler(unsigned int irq, struct irqdesc *desc)
{
u32 pci_interrupt;
unsigned int irqno;
@@ -271,7 +271,7 @@ static void pci_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *
}
int_desc = irq_desc + irqno;
- desc_handle_irq(irqno, int_desc, regs);
+ desc_handle_irq(irqno, int_desc);
desc->chip->unmask(irq);
}
@@ -348,12 +348,12 @@ ixp23xx_gettimeoffset(void)
}
static irqreturn_t
-ixp23xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ixp23xx_timer_interrupt(int irq, void *dev_id)
{
/* Clear Pending Interrupt by writing '1' to it */
*IXP23XX_TIMER_STATUS = IXP23XX_TIMER1_INT_PEND;
while ((signed long)(*IXP23XX_TIMER_CONT - next_jiffy_time) >= LATCH) {
- timer_tick(regs);
+ timer_tick();
next_jiffy_time += LATCH;
}
diff --git a/arch/arm/mach-ixp23xx/ixdp2351.c b/arch/arm/mach-ixp23xx/ixdp2351.c
index 37a32e6bcca2..b6ab0e8bb5e8 100644
--- a/arch/arm/mach-ixp23xx/ixdp2351.c
+++ b/arch/arm/mach-ixp23xx/ixdp2351.c
@@ -60,7 +60,7 @@ static void ixdp2351_inta_unmask(unsigned int irq)
*IXDP2351_CPLD_INTA_MASK_CLR_REG = IXDP2351_INTA_IRQ_MASK(irq);
}
-static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc)
{
u16 ex_interrupt =
*IXDP2351_CPLD_INTA_STAT_REG & IXDP2351_INTA_IRQ_VALID;
@@ -74,7 +74,7 @@ static void ixdp2351_inta_handler(unsigned int irq, struct irqdesc *desc, struct
int cpld_irq =
IXP23XX_MACH_IRQ(IXDP2351_INTA_IRQ_BASE + i);
cpld_desc = irq_desc + cpld_irq;
- desc_handle_irq(cpld_irq, cpld_desc, regs);
+ desc_handle_irq(cpld_irq, cpld_desc);
}
}
@@ -97,7 +97,7 @@ static void ixdp2351_intb_unmask(unsigned int irq)
*IXDP2351_CPLD_INTB_MASK_CLR_REG = IXDP2351_INTB_IRQ_MASK(irq);
}
-static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc)
{
u16 ex_interrupt =
*IXDP2351_CPLD_INTB_STAT_REG & IXDP2351_INTB_IRQ_VALID;
@@ -111,7 +111,7 @@ static void ixdp2351_intb_handler(unsigned int irq, struct irqdesc *desc, struct
int cpld_irq =
IXP23XX_MACH_IRQ(IXDP2351_INTB_IRQ_BASE + i);
cpld_desc = irq_desc + cpld_irq;
- desc_handle_irq(cpld_irq, cpld_desc, regs);
+ desc_handle_irq(cpld_irq, cpld_desc);
}
}
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 7c25dbd5a181..c7513f6eb50c 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -26,6 +26,7 @@
#include <linux/bitops.h>
#include <linux/time.h>
#include <linux/timex.h>
+#include <linux/clocksource.h>
#include <asm/hardware.h>
#include <asm/uaccess.h>
@@ -255,17 +256,7 @@ static unsigned volatile last_jiffy_time;
#define CLOCK_TICKS_PER_USEC ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
-/* IRQs are disabled before entering here from do_gettimeofday() */
-static unsigned long ixp4xx_gettimeoffset(void)
-{
- u32 elapsed;
-
- elapsed = *IXP4XX_OSTS - last_jiffy_time;
-
- return elapsed / CLOCK_TICKS_PER_USEC;
-}
-
-static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
@@ -276,7 +267,7 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs
* Catch up with the real idea of time
*/
while ((signed long)(*IXP4XX_OSTS - last_jiffy_time) >= LATCH) {
- timer_tick(regs);
+ timer_tick();
last_jiffy_time += LATCH;
}
@@ -309,7 +300,6 @@ static void __init ixp4xx_timer_init(void)
struct sys_timer ixp4xx_timer = {
.init = ixp4xx_timer_init,
- .offset = ixp4xx_gettimeoffset,
};
static struct resource ixp46x_i2c_resources[] = {
@@ -365,3 +355,29 @@ void __init ixp4xx_sys_init(void)
ixp4xx_exp_bus_size >> 20);
}
+cycle_t ixp4xx_get_cycles(void)
+{
+ return *IXP4XX_OSTS;
+}
+
+static struct clocksource clocksource_ixp4xx = {
+ .name = "OSTS",
+ .rating = 200,
+ .read = ixp4xx_get_cycles,
+ .mask = CLOCKSOURCE_MASK(32),
+ .shift = 20,
+ .is_continuous = 1,
+};
+
+unsigned long ixp4xx_timer_freq = FREQ;
+static int __init ixp4xx_clocksource_init(void)
+{
+ clocksource_ixp4xx.mult =
+ clocksource_hz2mult(ixp4xx_timer_freq,
+ clocksource_ixp4xx.shift);
+ clocksource_register(&clocksource_ixp4xx);
+
+ return 0;
+}
+
+device_initcall(ixp4xx_clocksource_init);
diff --git a/arch/arm/mach-ixp4xx/coyote-pci.c b/arch/arm/mach-ixp4xx/coyote-pci.c
index 2cebb2878895..7bc94f3def1c 100644
--- a/arch/arm/mach-ixp4xx/coyote-pci.c
+++ b/arch/arm/mach-ixp4xx/coyote-pci.c
@@ -1,5 +1,5 @@
/*
- * arch/arch/mach-ixp4xx/coyote-pci.c
+ * arch/arm/mach-ixp4xx/coyote-pci.c
*
* PCI setup routines for ADI Engineering Coyote platform
*
diff --git a/arch/arm/mach-ixp4xx/ixdpg425-pci.c b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
index ed5270800217..509a95a692a4 100644
--- a/arch/arm/mach-ixp4xx/ixdpg425-pci.c
+++ b/arch/arm/mach-ixp4xx/ixdpg425-pci.c
@@ -1,5 +1,5 @@
/*
- * arch/arch/mach-ixp4xx/ixdpg425-pci.c
+ * arch/arm/mach-ixp4xx/ixdpg425-pci.c
*
* PCI setup routines for Intel IXDPG425 Platform
*
diff --git a/arch/arm/mach-ixp4xx/nas100d-power.c b/arch/arm/mach-ixp4xx/nas100d-power.c
index 81ffcae1f56e..29aa98d3a7fa 100644
--- a/arch/arm/mach-ixp4xx/nas100d-power.c
+++ b/arch/arm/mach-ixp4xx/nas100d-power.c
@@ -24,7 +24,7 @@
#include <asm/mach-types.h>
-static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t nas100d_reset_handler(int irq, void *dev_id)
{
/* Signal init to do the ctrlaltdel action, this will bypass init if
* it hasn't started and do a kernel_restart.
diff --git a/arch/arm/mach-ixp4xx/nslu2-power.c b/arch/arm/mach-ixp4xx/nslu2-power.c
index a29b3b2b61b6..acd71e9c38a7 100644
--- a/arch/arm/mach-ixp4xx/nslu2-power.c
+++ b/arch/arm/mach-ixp4xx/nslu2-power.c
@@ -25,7 +25,7 @@
#include <asm/mach-types.h>
-static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t nslu2_power_handler(int irq, void *dev_id)
{
/* Signal init to do the ctrlaltdel action, this will bypass init if
* it hasn't started and do a kernel_restart.
@@ -35,7 +35,7 @@ static irqreturn_t nslu2_power_handler(int irq, void *dev_id, struct pt_regs *re
return IRQ_HANDLED;
}
-static irqreturn_t nslu2_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t nslu2_reset_handler(int irq, void *dev_id)
{
/* This is the paper-clip reset, it shuts the machine down directly.
*/
diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c
index 749a337494d3..162c266e5f8f 100644
--- a/arch/arm/mach-ixp4xx/nslu2-setup.c
+++ b/arch/arm/mach-ixp4xx/nslu2-setup.c
@@ -159,6 +159,8 @@ static void nslu2_power_off(void)
static void __init nslu2_init(void)
{
+ ixp4xx_timer_freq = NSLU2_FREQ;
+
ixp4xx_sys_init();
nslu2_flash_resource.start = IXP4XX_EXP_BUS_BASE(0);
diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
index 4f2ab48800a5..15fbcc911fe7 100644
--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
@@ -71,14 +71,13 @@ static struct irq_chip kev7a400_cpld_chip = {
};
-static void kev7a400_cpld_handler (unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void kev7a400_cpld_handler (unsigned int irq, struct irqdesc *desc)
{
u32 mask = CPLD_LATCHED_INTS;
irq = IRQ_KEV7A400_CPLD;
for (; mask; mask >>= 1, ++irq) {
if (mask & 1)
- desc[irq].handle (irq, desc, regs);
+ desc[irq].handle (irq, desc);
}
}
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
index a6910114b24c..8441e0a156cb 100644
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
@@ -164,7 +164,7 @@ static void lh7a40x_ack_cpld_irq (u32 irq)
/* CPLD doesn't have ack capability, but some devices may */
#if defined (CPLD_INTMASK_TOUCH)
- /* The touch control *must* mask the the interrupt because the
+ /* The touch control *must* mask the interrupt because the
* interrupt bit is read by the driver to determine if the pen
* is still down. */
if (irq == IRQ_TOUCH)
@@ -207,8 +207,7 @@ static struct irq_chip lpd7a40x_cpld_chip = {
.unmask = lh7a40x_unmask_cpld_irq,
};
-static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void lpd7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc)
{
unsigned int mask = CPLD_INTERRUPTS;
diff --git a/arch/arm/mach-lh7a40x/clcd.c b/arch/arm/mach-lh7a40x/clcd.c
index 93751fee793d..1992db4c2523 100644
--- a/arch/arm/mach-lh7a40x/clcd.c
+++ b/arch/arm/mach-lh7a40x/clcd.c
@@ -8,7 +8,7 @@
* version 2 as published by the Free Software Foundation.
*
*/
-#include <linux/config.h>
+
#include <linux/init.h>
#include <linux/device.h>
#include <linux/dma-mapping.h>
diff --git a/arch/arm/mach-lh7a40x/clocks.c b/arch/arm/mach-lh7a40x/clocks.c
index 2291afe9f23e..7530a95c15a6 100644
--- a/arch/arm/mach-lh7a40x/clocks.c
+++ b/arch/arm/mach-lh7a40x/clocks.c
@@ -8,7 +8,6 @@
*
*/
-#include <linux/config.h>
#include <linux/cpufreq.h>
#include <asm/hardware.h>
#include <asm/arch/clocks.h>
diff --git a/arch/arm/mach-lh7a40x/common.h b/arch/arm/mach-lh7a40x/common.h
index 18e8bb4eb202..0ca20c6c83b7 100644
--- a/arch/arm/mach-lh7a40x/common.h
+++ b/arch/arm/mach-lh7a40x/common.h
@@ -15,4 +15,4 @@ extern void lh7a404_init_irq (void);
extern void lh7a40x_clcd_init (void);
extern void lh7a40x_init_board_irq (void);
-#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq), regs)
+#define IRQ_DISPATCH(irq) desc_handle_irq((irq),(irq_desc + irq))
diff --git a/arch/arm/mach-lh7a40x/irq-kev7a400.c b/arch/arm/mach-lh7a40x/irq-kev7a400.c
index f9b3fe9174a5..646071334b8f 100644
--- a/arch/arm/mach-lh7a40x/irq-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/irq-kev7a400.c
@@ -51,14 +51,13 @@ irq_chip lh7a400_cpld_chip = {
};
static void
-lh7a400_cpld_handler (unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+lh7a400_cpld_handler (unsigned int irq, struct irqdesc *desc)
{
u32 mask = CPLD_LATCHED_INTS;
irq = IRQ_KEV_7A400_CPLD;
for (; mask; mask >>= 1, ++irq) {
if (mask & 1)
- desc[irq].handle (irq, desc, regs);
+ desc[irq].handle (irq, desc);
}
}
diff --git a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
index d6055dde6468..b20376804bbb 100644
--- a/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/irq-lpd7a40x.c
@@ -57,8 +57,7 @@ static struct irq_chip lh7a40x_cpld_chip = {
.unmask = lh7a40x_unmask_cpld_irq,
};
-static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void lh7a40x_cpld_handler (unsigned int irq, struct irqdesc *desc)
{
unsigned int mask = CPLD_INTERRUPTS;
diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
index ad5652e01507..bef3c4b68d3b 100644
--- a/arch/arm/mach-lh7a40x/time.c
+++ b/arch/arm/mach-lh7a40x/time.c
@@ -39,12 +39,12 @@
#endif
static irqreturn_t
-lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+lh7a40x_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
TIMER_EOI = 0;
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-netx/generic.c b/arch/arm/mach-netx/generic.c
index af0b13534cfd..edbbbdc3b06b 100644
--- a/arch/arm/mach-netx/generic.c
+++ b/arch/arm/mach-netx/generic.c
@@ -69,8 +69,7 @@ static struct platform_device *devices[] __initdata = {
#endif
static void
-netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
- struct pt_regs *regs)
+netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc)
{
unsigned int irq = NETX_IRQ_HIF_CHAINED(0);
unsigned int stat;
@@ -83,7 +82,7 @@ netx_hif_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
while (stat) {
if (stat & 1) {
DEBUG_IRQ("handling irq %d\n", irq);
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
}
irq++;
desc++;
diff --git a/arch/arm/mach-netx/time.c b/arch/arm/mach-netx/time.c
index 6d72c81b7d9f..0993336c0b55 100644
--- a/arch/arm/mach-netx/time.c
+++ b/arch/arm/mach-netx/time.c
@@ -38,11 +38,11 @@ static unsigned long netx_gettimeoffset(void)
* IRQ handler for the timer
*/
static irqreturn_t
-netx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+netx_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
/* acknowledge interrupt */
diff --git a/arch/arm/mach-omap1/board-fsample.c b/arch/arm/mach-omap1/board-fsample.c
index c753a3c5aadd..62e42c7a628e 100644
--- a/arch/arm/mach-omap1/board-fsample.c
+++ b/arch/arm/mach-omap1/board-fsample.c
@@ -172,9 +172,11 @@ static struct resource kp_resources[] = {
};
static struct omap_kp_platform_data kp_data = {
- .rows = 8,
- .cols = 8,
- .keymap = fsample_keymap,
+ .rows = 8,
+ .cols = 8,
+ .keymap = fsample_keymap,
+ .keymapsize = ARRAY_SIZE(fsample_keymap),
+ .delay = 4,
};
static struct platform_device kp_device = {
diff --git a/arch/arm/mach-omap1/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index cd3a06dfc0a8..6e113078f7ab 100644
--- a/arch/arm/mach-omap1/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -167,10 +167,13 @@ static struct resource h2_kp_resources[] = {
};
static struct omap_kp_platform_data h2_kp_data = {
- .rows = 8,
- .cols = 8,
- .keymap = h2_keymap,
- .rep = 1,
+ .rows = 8,
+ .cols = 8,
+ .keymap = h2_keymap,
+ .keymapsize = ARRAY_SIZE(h2_keymap),
+ .rep = 1,
+ .delay = 9,
+ .dbounce = 1,
};
static struct platform_device h2_kp_device = {
diff --git a/arch/arm/mach-omap1/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 7b206116cd03..f225a083dee1 100644
--- a/arch/arm/mach-omap1/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -247,10 +247,13 @@ static struct resource h3_kp_resources[] = {
};
static struct omap_kp_platform_data h3_kp_data = {
- .rows = 8,
- .cols = 8,
- .keymap = h3_keymap,
- .rep = 1,
+ .rows = 8,
+ .cols = 8,
+ .keymap = h3_keymap,
+ .keymapsize = ARRAY_SIZE(h3_keymap),
+ .rep = 1,
+ .delay = 9,
+ .dbounce = 1,
};
static struct platform_device h3_kp_device = {
diff --git a/arch/arm/mach-omap1/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index 4cbc62db5b5d..cb00530ad279 100644
--- a/arch/arm/mach-omap1/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -159,9 +159,11 @@ static struct resource innovator_kp_resources[] = {
};
static struct omap_kp_platform_data innovator_kp_data = {
- .rows = 8,
- .cols = 8,
- .keymap = innovator_keymap,
+ .rows = 8,
+ .cols = 8,
+ .keymap = innovator_keymap,
+ .keymapsize = ARRAY_SIZE(innovator_keymap),
+ .delay = 4,
};
static struct platform_device innovator_kp_device = {
diff --git a/arch/arm/mach-omap1/board-nokia770.c b/arch/arm/mach-omap1/board-nokia770.c
index 02b980d77b12..dbc555d209ff 100644
--- a/arch/arm/mach-omap1/board-nokia770.c
+++ b/arch/arm/mach-omap1/board-nokia770.c
@@ -71,9 +71,11 @@ static struct resource nokia770_kp_resources[] = {
};
static struct omap_kp_platform_data nokia770_kp_data = {
- .rows = 8,
- .cols = 8,
- .keymap = nokia770_keymap
+ .rows = 8,
+ .cols = 8,
+ .keymap = nokia770_keymap,
+ .keymapsize = ARRAY_SIZE(nokia770_keymap)
+ .delay = 4,
};
static struct platform_device nokia770_kp_device = {
diff --git a/arch/arm/mach-omap1/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index b742261c97ad..3a622801d7b0 100644
--- a/arch/arm/mach-omap1/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -266,9 +266,11 @@ static const int osk_keymap[] = {
};
static struct omap_kp_platform_data osk_kp_data = {
- .rows = 8,
- .cols = 8,
- .keymap = (int *) osk_keymap,
+ .rows = 8,
+ .cols = 8,
+ .keymap = (int *) osk_keymap,
+ .keymapsize = ARRAY_SIZE(osk_keymap),
+ .delay = 9,
};
static struct resource osk5912_kp_resources[] = {
@@ -325,7 +327,7 @@ static struct spi_board_info __initdata mistral_boardinfo[] = { {
#ifdef CONFIG_PM
static irqreturn_t
-osk_mistral_wake_interrupt(int irq, void *ignored, struct pt_regs *regs)
+osk_mistral_wake_interrupt(int irq, void *ignored)
{
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-omap1/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 64b45d8ae357..fa4be962df67 100644
--- a/arch/arm/mach-omap1/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -171,9 +171,12 @@ static struct resource kp_resources[] = {
};
static struct omap_kp_platform_data kp_data = {
- .rows = 8,
- .cols = 8,
- .keymap = p2_keymap,
+ .rows = 8,
+ .cols = 8,
+ .keymap = p2_keymap,
+ .keymapsize = ARRAY_SIZE(p2_keymap),
+ .delay = 4,
+ .dbounce = 1,
};
static struct platform_device kp_device = {
diff --git a/arch/arm/mach-omap1/clock.c b/arch/arm/mach-omap1/clock.c
index f1958e882e86..638490e62d5f 100644
--- a/arch/arm/mach-omap1/clock.c
+++ b/arch/arm/mach-omap1/clock.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <asm/io.h>
+#include <asm/mach-types.h>
#include <asm/arch/cpu.h>
#include <asm/arch/usb.h>
@@ -586,77 +587,53 @@ static int omap1_clk_set_rate(struct clk *clk, unsigned long rate)
*-------------------------------------------------------------------------*/
#ifdef CONFIG_OMAP_RESET_CLOCKS
-/*
- * Resets some clocks that may be left on from bootloader,
- * but leaves serial clocks on. See also omap_late_clk_reset().
- */
-static inline void omap1_early_clk_reset(void)
-{
- //omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
-}
-static int __init omap1_late_clk_reset(void)
+static void __init omap1_clk_disable_unused(struct clk *clk)
{
- /* Turn off all unused clocks */
- struct clk *p;
__u32 regval32;
- /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
- regval32 = omap_readw(SOFT_REQ_REG) & (1 << 4);
- omap_writew(regval32, SOFT_REQ_REG);
- omap_writew(0, SOFT_REQ_REG2);
-
- list_for_each_entry(p, &clocks, node) {
- if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
- p->enable_reg == 0)
- continue;
-
- /* Clocks in the DSP domain need api_ck. Just assume bootloader
- * has not enabled any DSP clocks */
- if ((u32)p->enable_reg == DSP_IDLECT2) {
- printk(KERN_INFO "Skipping reset check for DSP domain "
- "clock \"%s\"\n", p->name);
- continue;
- }
+ /* Clocks in the DSP domain need api_ck. Just assume bootloader
+ * has not enabled any DSP clocks */
+ if ((u32)clk->enable_reg == DSP_IDLECT2) {
+ printk(KERN_INFO "Skipping reset check for DSP domain "
+ "clock \"%s\"\n", clk->name);
+ return;
+ }
- /* Is the clock already disabled? */
- if (p->flags & ENABLE_REG_32BIT) {
- if (p->flags & VIRTUAL_IO_ADDRESS)
- regval32 = __raw_readl(p->enable_reg);
- else
- regval32 = omap_readl(p->enable_reg);
- } else {
- if (p->flags & VIRTUAL_IO_ADDRESS)
- regval32 = __raw_readw(p->enable_reg);
+ /* Is the clock already disabled? */
+ if (clk->flags & ENABLE_REG_32BIT) {
+ if (clk->flags & VIRTUAL_IO_ADDRESS)
+ regval32 = __raw_readl(clk->enable_reg);
else
- regval32 = omap_readw(p->enable_reg);
- }
-
- if ((regval32 & (1 << p->enable_bit)) == 0)
- continue;
+ regval32 = omap_readl(clk->enable_reg);
+ } else {
+ if (clk->flags & VIRTUAL_IO_ADDRESS)
+ regval32 = __raw_readw(clk->enable_reg);
+ else
+ regval32 = omap_readw(clk->enable_reg);
+ }
- /* FIXME: This clock seems to be necessary but no-one
- * has asked for its activation. */
- if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera
- || p == &ck_dpll1out.clk // FIX: SoSSI, SSR
- || p == &arm_gpio_ck // FIX: GPIO code for 1510
- ) {
- printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
- p->name);
- continue;
- }
+ if ((regval32 & (1 << clk->enable_bit)) == 0)
+ return;
- printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
- p->disable(p);
- printk(" done\n");
+ /* FIXME: This clock seems to be necessary but no-one
+ * has asked for its activation. */
+ if (clk == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera
+ || clk == &ck_dpll1out.clk // FIX: SoSSI, SSR
+ || clk == &arm_gpio_ck // FIX: GPIO code for 1510
+ ) {
+ printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+ clk->name);
+ return;
}
- return 0;
+ printk(KERN_INFO "Disabling unused clock \"%s\"... ", clk->name);
+ clk->disable(clk);
+ printk(" done\n");
}
-late_initcall(omap1_late_clk_reset);
#else
-#define omap1_early_clk_reset() {}
+#define omap1_clk_disable_unused NULL
#endif
static struct clk_functions omap1_clk_functions = {
@@ -664,6 +641,7 @@ static struct clk_functions omap1_clk_functions = {
.clk_disable = omap1_clk_disable,
.clk_round_rate = omap1_clk_round_rate,
.clk_set_rate = omap1_clk_set_rate,
+ .clk_disable_unused = omap1_clk_disable_unused,
};
int __init omap1_clk_init(void)
@@ -671,8 +649,13 @@ int __init omap1_clk_init(void)
struct clk ** clkp;
const struct omap_clock_config *info;
int crystal_type = 0; /* Default 12 MHz */
+ u32 reg;
+
+ /* USB_REQ_EN will be disabled later if necessary (usb_dc_ck) */
+ reg = omap_readw(SOFT_REQ_REG) & (1 << 4);
+ omap_writew(reg, SOFT_REQ_REG);
+ omap_writew(0, SOFT_REQ_REG2);
- omap1_early_clk_reset();
clk_init(&omap1_clk_functions);
/* By default all idlect1 clocks are allowed to idle */
@@ -772,6 +755,12 @@ int __init omap1_clk_init(void)
omap_writew(omap_readw(OMAP730_PCC_UPLD_CTRL) & ~0x1, OMAP730_PCC_UPLD_CTRL);
#endif
+ /* Amstrad Delta wants BCLK high when inactive */
+ if (machine_is_ams_delta())
+ omap_writel(omap_readl(ULPD_CLOCK_CTRL) |
+ (1 << SDW_MCLK_INV_BIT),
+ ULPD_CLOCK_CTRL);
+
/* Turn off DSP and ARM_TIMXO. Make sure ARM_INTHCK is not divided */
/* (on 730, bit 13 must not be cleared) */
if (cpu_is_omap730())
diff --git a/arch/arm/mach-omap1/clock.h b/arch/arm/mach-omap1/clock.h
index b7c68819c4e7..f7df00205c4a 100644
--- a/arch/arm/mach-omap1/clock.h
+++ b/arch/arm/mach-omap1/clock.h
@@ -89,6 +89,7 @@ struct arm_idlect1_clk {
#define EN_DSPTIMCK 5
/* Various register defines for clock controls scattered around OMAP chip */
+#define SDW_MCLK_INV_BIT 2 /* In ULPD_CLKC_CTRL */
#define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */
#define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */
#define SWD_ULPD_PLL_CLK_REQ 1 /* In SWD_CLK_DIV_CTRL_SEL */
@@ -741,6 +742,18 @@ static struct clk i2c_fck = {
.disable = &omap1_clk_disable_generic,
};
+static struct clk i2c_ick = {
+ .name = "i2c_ick",
+ .id = 1,
+ .flags = CLOCK_IN_OMAP16XX |
+ VIRTUAL_CLOCK | CLOCK_NO_IDLE_PARENT |
+ ALWAYS_ENABLED,
+ .parent = &armper_ck.clk,
+ .recalc = &followparent_recalc,
+ .enable = &omap1_clk_enable_generic,
+ .disable = &omap1_clk_disable_generic,
+};
+
static struct clk * onchip_clks[] = {
/* non-ULPD clocks */
&ck_ref,
@@ -790,6 +803,7 @@ static struct clk * onchip_clks[] = {
/* Virtual clocks */
&virtual_ck_mpu,
&i2c_fck,
+ &i2c_ick,
};
#endif
diff --git a/arch/arm/mach-omap1/fpga.c b/arch/arm/mach-omap1/fpga.c
index efe9bfc6e55f..8e40208b10bb 100644
--- a/arch/arm/mach-omap1/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
@@ -84,8 +84,7 @@ static void fpga_mask_ack_irq(unsigned int irq)
fpga_ack_irq(irq);
}
-void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc)
{
struct irqdesc *d;
u32 stat;
@@ -101,7 +100,7 @@ void innovator_fpga_IRQ_demux(unsigned int irq, struct irqdesc *desc,
fpga_irq++, stat >>= 1) {
if (stat & 1) {
d = irq_desc + fpga_irq;
- desc_handle_irq(fpga_irq, d, regs);
+ desc_handle_irq(fpga_irq, d);
}
}
}
diff --git a/arch/arm/mach-omap1/mux.c b/arch/arm/mach-omap1/mux.c
index fa74ef7af15f..5432335bc493 100644
--- a/arch/arm/mach-omap1/mux.c
+++ b/arch/arm/mach-omap1/mux.c
@@ -199,6 +199,17 @@ MUX_CFG("N14_1610_UWIRE_CS0", 8, 9, 1, 1, 21, 0, 1, 1, 1)
MUX_CFG("P15_1610_UWIRE_CS3", 8, 12, 1, 1, 22, 0, 1, 1, 1)
MUX_CFG("N15_1610_UWIRE_CS1", 7, 18, 2, 1, 14, 0, NA, 0, 1)
+/* OMAP-1610 SPI */
+MUX_CFG("U19_1610_SPIF_SCK", 7, 21, 6, 1, 15, 0, 1, 1, 1)
+MUX_CFG("U18_1610_SPIF_DIN", 8, 0, 6, 1, 18, 1, 1, 0, 1)
+MUX_CFG("P20_1610_SPIF_DIN", 6, 27, 4, 1, 7, 1, 1, 0, 1)
+MUX_CFG("W21_1610_SPIF_DOUT", 8, 3, 6, 1, 19, 0, 1, 0, 1)
+MUX_CFG("R18_1610_SPIF_DOUT", 7, 9, 3, 1, 11, 0, 1, 0, 1)
+MUX_CFG("N14_1610_SPIF_CS0", 8, 9, 6, 1, 21, 0, 1, 1, 1)
+MUX_CFG("N15_1610_SPIF_CS1", 7, 18, 6, 1, 14, 0, 1, 1, 1)
+MUX_CFG("T19_1610_SPIF_CS2", 7, 15, 4, 1, 13, 0, 1, 1, 1)
+MUX_CFG("P15_1610_SPIF_CS3", 8, 12, 3, 1, 22, 0, 1, 1, 1)
+
/* OMAP-1610 Flash */
MUX_CFG("L3_1610_FLASH_CS2B_OE",10, 6, 1, NA, 0, 0, NA, 0, 1)
MUX_CFG("M8_1610_FLASH_CS2B_WE",10, 3, 1, NA, 0, 0, NA, 0, 1)
diff --git a/arch/arm/mach-omap1/pm.c b/arch/arm/mach-omap1/pm.c
index cd76185bab74..4834758d340c 100644
--- a/arch/arm/mach-omap1/pm.c
+++ b/arch/arm/mach-omap1/pm.c
@@ -682,8 +682,7 @@ static int omap_pm_finish(suspend_state_t state)
}
-static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
- struct pt_regs * regs)
+static irqreturn_t omap_wakeup_interrupt(int irq, void *dev)
{
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
index 976edfb882e2..4cc98a578e4b 100644
--- a/arch/arm/mach-omap1/serial.c
+++ b/arch/arm/mach-omap1/serial.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap1/id.c
+ * linux/arch/arm/mach-omap1/serial.c
*
* OMAP1 CPU identification code
*
@@ -204,8 +204,7 @@ void __init omap_serial_init(void)
#ifdef CONFIG_OMAP_SERIAL_WAKE
-static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t omap_serial_wake_interrupt(int irq, void *dev_id)
{
/* Need to do something with serial port right after wake-up? */
return IRQ_HANDLED;
diff --git a/arch/arm/mach-omap1/time.c b/arch/arm/mach-omap1/time.c
index 4d91b9f51084..1b7e4a506c26 100644
--- a/arch/arm/mach-omap1/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -160,8 +160,7 @@ static unsigned long omap_mpu_timer_gettimeoffset(void)
* Latency during the interrupt is calculated using timer1.
* Both timer0 and timer1 are counting at 6MHz (P2 6.5MHz).
*/
-static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id)
{
unsigned long now, latency;
@@ -169,7 +168,7 @@ static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id,
now = 0 - omap_mpu_timer_read(0);
latency = MPU_TICKS_PER_SEC / HZ - omap_mpu_timer_read(1);
omap_mpu_timer_last = now - latency;
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
@@ -182,8 +181,7 @@ static struct irqaction omap_mpu_timer_irq = {
};
static unsigned long omap_mpu_timer1_overflows;
-static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id)
{
omap_mpu_timer1_overflows++;
return IRQ_HANDLED;
diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c
index 7993b7bae2bd..03d6905ba490 100644
--- a/arch/arm/mach-omap2/board-apollon.c
+++ b/arch/arm/mach-omap2/board-apollon.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/omap2/board-apollon.c
+ * linux/arch/arm/mach-omap2/board-apollon.c
*
* Copyright (C) 2005,2006 Samsung Electronics
* Author: Kyungmin Park <kyungmin.park@samsung.com>
@@ -166,8 +166,8 @@ static struct omap_uart_config apollon_uart_config __initdata = {
static struct omap_mmc_config apollon_mmc_config __initdata = {
.mmc [0] = {
- .enabled = 0,
- .wire4 = 0,
+ .enabled = 1,
+ .wire4 = 1,
.wp_pin = -1,
.power_pin = -1,
.switch_pin = -1,
@@ -203,7 +203,7 @@ static void __init apollon_led_init(void)
omap_set_gpio_dataout(LED2_GPIO15, 0);
}
-static irqreturn_t apollon_sw_interrupt(int irq, void *ignored, struct pt_regs *regs)
+static irqreturn_t apollon_sw_interrupt(int irq, void *ignored)
{
static unsigned int led0, led1, led2;
@@ -257,6 +257,9 @@ static void __init omap_apollon_init(void)
/* REVISIT: where's the correct place */
omap_cfg_reg(W19_24XX_SYS_NIRQ);
+ /* Use Interal loop-back in MMC/SDIO Module Input Clock selection */
+ CONTROL_DEVCONF |= (1 << 24);
+
/*
* Make sure the serial ports are muxed on at this point.
* You have to mux them off in device drivers later on
diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c
index eaecbf422d8c..90938151bcf1 100644
--- a/arch/arm/mach-omap2/board-generic.c
+++ b/arch/arm/mach-omap2/board-generic.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/omap2/board-generic.c
+ * linux/arch/arm/mach-omap2/board-generic.c
*
* Copyright (C) 2005 Nokia Corporation
* Author: Paul Mundt <paul.mundt@nokia.com>
diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c
index 4933fce766c8..26a95a642ad7 100644
--- a/arch/arm/mach-omap2/board-h4.c
+++ b/arch/arm/mach-omap2/board-h4.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/omap2/board-h4.c
+ * linux/arch/arm/mach-omap2/board-h4.c
*
* Copyright (C) 2005 Nokia Corporation
* Author: Paul Mundt <paul.mundt@nokia.com>
@@ -245,6 +245,7 @@ static struct omap_kp_platform_data h4_kp_data = {
.rows = 6,
.cols = 7,
.keymap = h4_keymap,
+ .keymapsize = ARRAY_SIZE(h4_keymap),
.rep = 1,
.row_gpios = row_gpios,
.col_gpios = col_gpios,
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index d1b648a4efbf..0de201c3d50b 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -32,10 +32,14 @@
#include "memory.h"
#include "clock.h"
+#undef DEBUG
+
//#define DOWN_VARIABLE_DPLL 1 /* Experimental */
static struct prcm_config *curr_prcm_set;
static u32 curr_perf_level = PRCM_FULL_SPEED;
+static struct clk *vclk;
+static struct clk *sclk;
/*-------------------------------------------------------------------------
* Omap2 specific clock functions
@@ -79,6 +83,14 @@ static void omap2_propagate_rate(struct clk * clk)
propagate_rate(clk);
}
+static void omap2_set_osc_ck(int enable)
+{
+ if (enable)
+ PRCM_CLKSRC_CTRL &= ~(0x3 << 3);
+ else
+ PRCM_CLKSRC_CTRL |= 0x3 << 3;
+}
+
/* Enable an APLL if off */
static void omap2_clk_fixed_enable(struct clk *clk)
{
@@ -101,12 +113,54 @@ static void omap2_clk_fixed_enable(struct clk *clk)
else if (clk == &apll54_ck)
cval = (1 << 6);
- while (!CM_IDLEST_CKGEN & cval) { /* Wait for lock */
+ while (!(CM_IDLEST_CKGEN & cval)) { /* Wait for lock */
++i;
udelay(1);
- if (i == 100000)
+ if (i == 100000) {
+ printk(KERN_ERR "Clock %s didn't lock\n", clk->name);
+ break;
+ }
+ }
+}
+
+static void omap2_clk_wait_ready(struct clk *clk)
+{
+ unsigned long reg, other_reg, st_reg;
+ u32 bit;
+ int i;
+
+ reg = (unsigned long) clk->enable_reg;
+ if (reg == (unsigned long) &CM_FCLKEN1_CORE ||
+ reg == (unsigned long) &CM_FCLKEN2_CORE)
+ other_reg = (reg & ~0xf0) | 0x10;
+ else if (reg == (unsigned long) &CM_ICLKEN1_CORE ||
+ reg == (unsigned long) &CM_ICLKEN2_CORE)
+ other_reg = (reg & ~0xf0) | 0x00;
+ else
+ return;
+
+ /* No check for DSS or cam clocks */
+ if ((reg & 0x0f) == 0) {
+ if (clk->enable_bit <= 1 || clk->enable_bit == 31)
+ return;
+ }
+
+ /* Check if both functional and interface clocks
+ * are running. */
+ bit = 1 << clk->enable_bit;
+ if (!(__raw_readl(other_reg) & bit))
+ return;
+ st_reg = (other_reg & ~0xf0) | 0x20;
+ i = 0;
+ while (!(__raw_readl(st_reg) & bit)) {
+ i++;
+ if (i == 100000) {
+ printk(KERN_ERR "Timeout enabling clock %s\n", clk->name);
break;
+ }
}
+ if (i)
+ pr_debug("Clock %s stable after %d loops\n", clk->name, i);
}
/* Enables clock without considering parent dependencies or use count
@@ -119,6 +173,11 @@ static int _omap2_clk_enable(struct clk * clk)
if (clk->flags & ALWAYS_ENABLED)
return 0;
+ if (unlikely(clk == &osc_ck)) {
+ omap2_set_osc_ck(1);
+ return 0;
+ }
+
if (unlikely(clk->enable_reg == 0)) {
printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
clk->name);
@@ -133,6 +192,9 @@ static int _omap2_clk_enable(struct clk * clk)
regval32 = __raw_readl(clk->enable_reg);
regval32 |= (1 << clk->enable_bit);
__raw_writel(regval32, clk->enable_reg);
+ wmb();
+
+ omap2_clk_wait_ready(clk);
return 0;
}
@@ -155,6 +217,11 @@ static void _omap2_clk_disable(struct clk *clk)
{
u32 regval32;
+ if (unlikely(clk == &osc_ck)) {
+ omap2_set_osc_ck(0);
+ return;
+ }
+
if (clk->enable_reg == 0)
return;
@@ -166,6 +233,7 @@ static void _omap2_clk_disable(struct clk *clk)
regval32 = __raw_readl(clk->enable_reg);
regval32 &= ~(1 << clk->enable_bit);
__raw_writel(regval32, clk->enable_reg);
+ wmb();
}
static int omap2_clk_enable(struct clk *clk)
@@ -695,12 +763,14 @@ static int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
reg_val = __raw_readl(reg);
reg_val &= ~(field_mask << div_off);
reg_val |= (field_val << div_off);
-
__raw_writel(reg_val, reg);
+ wmb();
clk->rate = clk->parent->rate / field_val;
- if (clk->flags & DELAYED_APP)
+ if (clk->flags & DELAYED_APP) {
__raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
+ wmb();
+ }
ret = 0;
} else if (clk->set_rate != 0)
ret = clk->set_rate(clk, rate);
@@ -836,10 +906,12 @@ static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
reg_val = __raw_readl(reg) & ~(field_mask << src_off);
reg_val |= (field_val << src_off);
__raw_writel(reg_val, reg);
+ wmb();
- if (clk->flags & DELAYED_APP)
+ if (clk->flags & DELAYED_APP) {
__raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
-
+ wmb();
+ }
if (clk->usecount > 0)
_omap2_clk_enable(clk);
@@ -953,12 +1025,29 @@ static int omap2_select_table_rate(struct clk * clk, unsigned long rate)
* Omap2 clock reset and init functions
*-------------------------------------------------------------------------*/
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+static void __init omap2_clk_disable_unused(struct clk *clk)
+{
+ u32 regval32;
+
+ regval32 = __raw_readl(clk->enable_reg);
+ if ((regval32 & (1 << clk->enable_bit)) == 0)
+ return;
+
+ printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
+ _omap2_clk_disable(clk);
+}
+#else
+#define omap2_clk_disable_unused NULL
+#endif
+
static struct clk_functions omap2_clk_functions = {
.clk_enable = omap2_clk_enable,
.clk_disable = omap2_clk_disable,
.clk_round_rate = omap2_clk_round_rate,
.clk_set_rate = omap2_clk_set_rate,
.clk_set_parent = omap2_clk_set_parent,
+ .clk_disable_unused = omap2_clk_disable_unused,
};
static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
@@ -984,27 +1073,19 @@ static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
sys->rate = sclk;
}
-#ifdef CONFIG_OMAP_RESET_CLOCKS
-static void __init omap2_disable_unused_clocks(void)
+/*
+ * Set clocks for bypass mode for reboot to work.
+ */
+void omap2_clk_prepare_for_reboot(void)
{
- struct clk *ck;
- u32 regval32;
+ u32 rate;
- list_for_each_entry(ck, &clocks, node) {
- if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
- ck->enable_reg == 0)
- continue;
-
- regval32 = __raw_readl(ck->enable_reg);
- if ((regval32 & (1 << ck->enable_bit)) == 0)
- continue;
+ if (vclk == NULL || sclk == NULL)
+ return;
- printk(KERN_INFO "Disabling unused clock \"%s\"\n", ck->name);
- _omap2_clk_disable(ck);
- }
+ rate = clk_get_rate(sclk);
+ clk_set_rate(vclk, rate);
}
-late_initcall(omap2_disable_unused_clocks);
-#endif
/*
* Switch the MPU rate if specified on cmdline.
@@ -1077,8 +1158,27 @@ int __init omap2_clk_init(void)
*/
clk_enable(&sync_32k_ick);
clk_enable(&omapctrl_ick);
+
+ /* Force the APLLs active during bootup to avoid disabling and
+ * enabling them unnecessarily. */
+ clk_enable(&apll96_ck);
+ clk_enable(&apll54_ck);
+
if (cpu_is_omap2430())
clk_enable(&sdrc_ick);
+ /* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
+ vclk = clk_get(NULL, "virt_prcm_set");
+ sclk = clk_get(NULL, "sys_ck");
+
+ return 0;
+}
+
+static int __init omap2_disable_aplls(void)
+{
+ clk_disable(&apll96_ck);
+ clk_disable(&apll54_ck);
+
return 0;
}
+late_initcall(omap2_disable_aplls);
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 2781dfbc5164..8816f5a33a28 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -560,7 +560,7 @@ static struct clk osc_ck = { /* (*12, *13, 19.2, *26, 38.4)MHz */
.name = "osc_ck",
.rate = 26000000, /* fixed up in clock init */
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X |
- RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+ RATE_FIXED | RATE_PROPAGATES,
};
/* With out modem likely 12MHz, with modem likely 13MHz */
@@ -1368,7 +1368,8 @@ static struct clk mcbsp5_fck = {
};
static struct clk mcspi1_ick = {
- .name = "mcspi1_ick",
+ .name = "mcspi_ick",
+ .id = 1,
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
@@ -1377,7 +1378,8 @@ static struct clk mcspi1_ick = {
};
static struct clk mcspi1_fck = {
- .name = "mcspi1_fck",
+ .name = "mcspi_fck",
+ .id = 1,
.parent = &func_48m_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
@@ -1386,7 +1388,8 @@ static struct clk mcspi1_fck = {
};
static struct clk mcspi2_ick = {
- .name = "mcspi2_ick",
+ .name = "mcspi_ick",
+ .id = 2,
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_ICLKEN1_CORE,
@@ -1395,7 +1398,8 @@ static struct clk mcspi2_ick = {
};
static struct clk mcspi2_fck = {
- .name = "mcspi2_fck",
+ .name = "mcspi_fck",
+ .id = 2,
.parent = &func_48m_ck,
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_FCLKEN1_CORE,
@@ -1404,7 +1408,8 @@ static struct clk mcspi2_fck = {
};
static struct clk mcspi3_ick = {
- .name = "mcspi3_ick",
+ .name = "mcspi_ick",
+ .id = 3,
.parent = &l4_ck,
.flags = CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_ICLKEN2_CORE,
@@ -1413,7 +1418,8 @@ static struct clk mcspi3_ick = {
};
static struct clk mcspi3_fck = {
- .name = "mcspi3_fck",
+ .name = "mcspi_fck",
+ .id = 3,
.parent = &func_48m_ck,
.flags = CLOCK_IN_OMAP243X,
.enable_reg = (void __iomem *)&CM_FCLKEN2_CORE,
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index c7a48f921fef..f4f04d87df32 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -13,6 +13,8 @@
#include <linux/init.h>
#include <linux/err.h>
#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/arch/gpmc.h>
@@ -41,6 +43,19 @@
#define GPMC_CS0 0x60
#define GPMC_CS_SIZE 0x30
+#define GPMC_CS_NUM 8
+#define GPMC_MEM_START 0x00000000
+#define GPMC_MEM_END 0x3FFFFFFF
+#define BOOT_ROM_SPACE 0x100000 /* 1MB */
+
+#define GPMC_CHUNK_SHIFT 24 /* 16 MB */
+#define GPMC_SECTION_SHIFT 28 /* 128 MB */
+
+static struct resource gpmc_mem_root;
+static struct resource gpmc_cs_mem[GPMC_CS_NUM];
+static spinlock_t gpmc_mem_lock = SPIN_LOCK_UNLOCKED;
+static unsigned gpmc_cs_map;
+
static void __iomem *gpmc_base =
(void __iomem *) IO_ADDRESS(GPMC_BASE);
static void __iomem *gpmc_cs_base =
@@ -187,9 +202,168 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
return 0;
}
-unsigned long gpmc_cs_get_base_addr(int cs)
+static void gpmc_cs_enable_mem(int cs, u32 base, u32 size)
+{
+ u32 l;
+ u32 mask;
+
+ mask = (1 << GPMC_SECTION_SHIFT) - size;
+ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+ l &= ~0x3f;
+ l = (base >> GPMC_CHUNK_SHIFT) & 0x3f;
+ l &= ~(0x0f << 8);
+ l |= ((mask >> GPMC_CHUNK_SHIFT) & 0x0f) << 8;
+ l |= 1 << 6; /* CSVALID */
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+}
+
+static void gpmc_cs_disable_mem(int cs)
+{
+ u32 l;
+
+ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+ l &= ~(1 << 6); /* CSVALID */
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+}
+
+static void gpmc_cs_get_memconf(int cs, u32 *base, u32 *size)
+{
+ u32 l;
+ u32 mask;
+
+ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+ *base = (l & 0x3f) << GPMC_CHUNK_SHIFT;
+ mask = (l >> 8) & 0x0f;
+ *size = (1 << GPMC_SECTION_SHIFT) - (mask << GPMC_CHUNK_SHIFT);
+}
+
+static int gpmc_cs_mem_enabled(int cs)
+{
+ u32 l;
+
+ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+ return l & (1 << 6);
+}
+
+static void gpmc_cs_set_reserved(int cs, int reserved)
{
- return (gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7) & 0x1f) << 24;
+ gpmc_cs_map &= ~(1 << cs);
+ gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+}
+
+static int gpmc_cs_reserved(int cs)
+{
+ return gpmc_cs_map & (1 << cs);
+}
+
+static unsigned long gpmc_mem_align(unsigned long size)
+{
+ int order;
+
+ size = (size - 1) >> (GPMC_CHUNK_SHIFT - 1);
+ order = GPMC_CHUNK_SHIFT - 1;
+ do {
+ size >>= 1;
+ order++;
+ } while (size);
+ size = 1 << order;
+ return size;
+}
+
+static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
+{
+ struct resource *res = &gpmc_cs_mem[cs];
+ int r;
+
+ size = gpmc_mem_align(size);
+ spin_lock(&gpmc_mem_lock);
+ res->start = base;
+ res->end = base + size - 1;
+ r = request_resource(&gpmc_mem_root, res);
+ spin_unlock(&gpmc_mem_lock);
+
+ return r;
+}
+
+int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
+{
+ struct resource *res = &gpmc_cs_mem[cs];
+ int r = -1;
+
+ if (cs > GPMC_CS_NUM)
+ return -ENODEV;
+
+ size = gpmc_mem_align(size);
+ if (size > (1 << GPMC_SECTION_SHIFT))
+ return -ENOMEM;
+
+ spin_lock(&gpmc_mem_lock);
+ if (gpmc_cs_reserved(cs)) {
+ r = -EBUSY;
+ goto out;
+ }
+ if (gpmc_cs_mem_enabled(cs))
+ r = adjust_resource(res, res->start & ~(size - 1), size);
+ if (r < 0)
+ r = allocate_resource(&gpmc_mem_root, res, size, 0, ~0,
+ size, NULL, NULL);
+ if (r < 0)
+ goto out;
+
+ gpmc_cs_enable_mem(cs, res->start, res->end - res->start + 1);
+ *base = res->start;
+ gpmc_cs_set_reserved(cs, 1);
+out:
+ spin_unlock(&gpmc_mem_lock);
+ return r;
+}
+
+void gpmc_cs_free(int cs)
+{
+ spin_lock(&gpmc_mem_lock);
+ if (cs >= GPMC_CS_NUM || !gpmc_cs_reserved(cs)) {
+ printk(KERN_ERR "Trying to free non-reserved GPMC CS%d\n", cs);
+ BUG();
+ spin_unlock(&gpmc_mem_lock);
+ return;
+ }
+ gpmc_cs_disable_mem(cs);
+ release_resource(&gpmc_cs_mem[cs]);
+ gpmc_cs_set_reserved(cs, 0);
+ spin_unlock(&gpmc_mem_lock);
+}
+
+void __init gpmc_mem_init(void)
+{
+ int cs;
+ unsigned long boot_rom_space = 0;
+
+ if (cpu_is_omap242x()) {
+ u32 l;
+ l = omap_readl(OMAP242X_CONTROL_STATUS);
+ /* In case of internal boot the 1st MB is redirected to the
+ * boot ROM memory space.
+ */
+ if (l & (1 << 3))
+ boot_rom_space = BOOT_ROM_SPACE;
+ } else
+ /* We assume internal boot if the mode can't be
+ * determined.
+ */
+ boot_rom_space = BOOT_ROM_SPACE;
+ gpmc_mem_root.start = GPMC_MEM_START + boot_rom_space;
+ gpmc_mem_root.end = GPMC_MEM_END;
+
+ /* Reserve all regions that has been set up by bootloader */
+ for (cs = 0; cs < GPMC_CS_NUM; cs++) {
+ u32 base, size;
+
+ if (!gpmc_cs_mem_enabled(cs))
+ continue;
+ gpmc_cs_get_memconf(cs, &base, &size);
+ if (gpmc_cs_insert_mem(cs, base, size) < 0)
+ BUG();
+ }
}
void __init gpmc_init(void)
@@ -206,4 +380,6 @@ void __init gpmc_init(void)
l &= 0x03 << 3;
l |= (0x02 << 3) | (1 << 0);
gpmc_write_reg(GPMC_SYSCONFIG, l);
+
+ gpmc_mem_init();
}
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index dfc3b35cc1ff..11870093d7a1 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/omap2/irq.c
+ * linux/arch/arm/mach-omap2/irq.c
*
* Interrupt handler for OMAP2 boards.
*
@@ -41,18 +41,6 @@ static struct omap_irq_bank {
.nr_irqs = 96,
}, {
/* XXX: DSP INTC */
-
-#if 0
- /*
- * Commented out for now until we fix the IVA clocking
- */
-#ifdef CONFIG_ARCH_OMAP2420
- }, {
- /* IVA INTC (2420 only) */
- .base_reg = OMAP24XX_IVA_INTC_BASE,
- .nr_irqs = 16, /* Actually 32, but only 16 are used */
-#endif
-#endif
}
};
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 60ef084faffd..f538d0fdb13c 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -104,6 +104,20 @@ MUX_CFG_24XX("P20_24XX_TSC_IRQ", 0x108, 0, 0, 0, 1)
MUX_CFG_24XX("K15_24XX_UART3_TX", 0x118, 0, 0, 0, 1)
MUX_CFG_24XX("K14_24XX_UART3_RX", 0x119, 0, 0, 0, 1)
+/* MMC/SDIO */
+MUX_CFG_24XX("G19_24XX_MMC_CLKO", 0x0f3, 0, 0, 0, 1)
+MUX_CFG_24XX("H18_24XX_MMC_CMD", 0x0f4, 0, 0, 0, 1)
+MUX_CFG_24XX("F20_24XX_MMC_DAT0", 0x0f5, 0, 0, 0, 1)
+MUX_CFG_24XX("H14_24XX_MMC_DAT1", 0x0f6, 0, 0, 0, 1)
+MUX_CFG_24XX("E19_24XX_MMC_DAT2", 0x0f7, 0, 0, 0, 1)
+MUX_CFG_24XX("D19_24XX_MMC_DAT3", 0x0f8, 0, 0, 0, 1)
+MUX_CFG_24XX("F19_24XX_MMC_DAT_DIR0", 0x0f9, 0, 0, 0, 1)
+MUX_CFG_24XX("E20_24XX_MMC_DAT_DIR1", 0x0fa, 0, 0, 0, 1)
+MUX_CFG_24XX("F18_24XX_MMC_DAT_DIR2", 0x0fb, 0, 0, 0, 1)
+MUX_CFG_24XX("E18_24XX_MMC_DAT_DIR3", 0x0fc, 0, 0, 0, 1)
+MUX_CFG_24XX("G18_24XX_MMC_CMD_DIR", 0x0fd, 0, 0, 0, 1)
+MUX_CFG_24XX("H15_24XX_MMC_CLKI", 0x0fe, 0, 0, 0, 1)
+
/* Keypad GPIO*/
MUX_CFG_24XX("T19_24XX_KBR0", 0x106, 3, 1, 1, 1)
MUX_CFG_24XX("R19_24XX_KBR1", 0x107, 3, 1, 1, 1)
diff --git a/arch/arm/mach-omap2/pm-domain.c b/arch/arm/mach-omap2/pm-domain.c
index 5e20e740cde5..2494091a078b 100644
--- a/arch/arm/mach-omap2/pm-domain.c
+++ b/arch/arm/mach-omap2/pm-domain.c
@@ -15,7 +15,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/clk.h>
diff --git a/arch/arm/mach-omap2/prcm-regs.h b/arch/arm/mach-omap2/prcm-regs.h
index 22ac7be4f782..5e1c4b53ee9d 100644
--- a/arch/arm/mach-omap2/prcm-regs.h
+++ b/arch/arm/mach-omap2/prcm-regs.h
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap2/prcm-reg.h
+ * linux/arch/arm/mach-omap2/prcm-regs.h
*
* OMAP24XX Power Reset and Clock Management (PRCM) registers
*
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index c2bf57ef6825..90f530540c65 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -19,6 +19,8 @@
#include "prcm-regs.h"
+extern void omap2_clk_prepare_for_reboot(void);
+
u32 omap_prcm_get_reset_sources(void)
{
return RM_RSTST_WKUP & 0x7f;
@@ -28,12 +30,6 @@ EXPORT_SYMBOL(omap_prcm_get_reset_sources);
/* Resets clock rates and reboots the system. Only called from system.h */
void omap_prcm_arch_reset(char mode)
{
- u32 rate;
- struct clk *vclk, *sclk;
-
- vclk = clk_get(NULL, "virt_prcm_set");
- sclk = clk_get(NULL, "sys_ck");
- rate = clk_get_rate(sclk);
- clk_set_rate(vclk, rate); /* go to bypass for OMAP limitation */
+ omap2_clk_prepare_for_reboot();
RM_RSTCTRL_WKUP |= 2;
}
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 0884bc7c23b7..aaa5589e8169 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-omap/omap2/serial.c
+ * arch/arm/mach-omap2/serial.c
*
* OMAP2 serial support.
*
diff --git a/arch/arm/mach-omap2/sram-fn.S b/arch/arm/mach-omap2/sram-fn.S
index a5ef7f611da9..b27576690f8d 100644
--- a/arch/arm/mach-omap2/sram-fn.S
+++ b/arch/arm/mach-omap2/sram-fn.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap2/sram.S
+ * linux/arch/arm/mach-omap2/sram-fn.S
*
* Omap2 specific functions that need to be run in internal SRAM
*
diff --git a/arch/arm/mach-omap2/timer-gp.c b/arch/arm/mach-omap2/timer-gp.c
index fe5fd6d42dea..973189cd9766 100644
--- a/arch/arm/mach-omap2/timer-gp.c
+++ b/arch/arm/mach-omap2/timer-gp.c
@@ -37,13 +37,12 @@ static inline void omap2_gp_timer_start(unsigned long load_val)
omap_dm_timer_start(gptimer);
}
-static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t omap2_gp_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-pnx4008/clock.c b/arch/arm/mach-pnx4008/clock.c
index f582ed2ec43c..daa8d3d98eff 100644
--- a/arch/arm/mach-pnx4008/clock.c
+++ b/arch/arm/mach-pnx4008/clock.c
@@ -735,6 +735,16 @@ static struct clk uart6_ck = {
.enable_reg = UARTCLKCTRL_REG,
};
+static struct clk wdt_ck = {
+ .name = "wdt_ck",
+ .parent = &per_ck,
+ .flags = NEEDS_INITIALIZATION,
+ .round_rate = &on_off_round_rate,
+ .set_rate = &on_off_set_rate,
+ .enable_shift = 0,
+ .enable_reg = TIMCLKCTRL_REG,
+};
+
/* These clocks are visible outside this module
* and can be initialized
*/
@@ -765,6 +775,7 @@ static struct clk *onchip_clks[] = {
&uart4_ck,
&uart5_ck,
&uart6_ck,
+ &wdt_ck,
};
static int local_clk_enable(struct clk *clk)
diff --git a/arch/arm/mach-pnx4008/dma.c b/arch/arm/mach-pnx4008/dma.c
index ec01574f88ac..d6a279e4b524 100644
--- a/arch/arm/mach-pnx4008/dma.c
+++ b/arch/arm/mach-pnx4008/dma.c
@@ -32,7 +32,7 @@
static struct dma_channel {
char *name;
- void (*irq_handler) (int, int, void *, struct pt_regs *);
+ void (*irq_handler) (int, int, void *);
void *data;
struct pnx4008_dma_ll *ll;
u32 ll_dma;
@@ -150,8 +150,7 @@ static inline void pnx4008_dma_unlock(void)
#define VALID_CHANNEL(c) (((c) >= 0) && ((c) < MAX_DMA_CHANNELS))
int pnx4008_request_channel(char *name, int ch,
- void (*irq_handler) (int, int, void *,
- struct pt_regs *), void *data)
+ void (*irq_handler) (int, int, void *), void *data)
{
int i, found = 0;
@@ -1033,7 +1032,7 @@ int pnx4008_dma_ch_enabled(int ch)
EXPORT_SYMBOL_GPL(pnx4008_dma_ch_enabled);
-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
int i;
unsigned long dint = __raw_readl(DMAC_INT_STAT);
@@ -1053,8 +1052,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
cause |= DMA_ERR_INT;
if (tcint & i_bit)
cause |= DMA_TC_INT;
- channel->irq_handler(i, cause, channel->data,
- regs);
+ channel->irq_handler(i, cause, channel->data);
} else {
/*
* IRQ for an unregistered DMA channel
diff --git a/arch/arm/mach-pnx4008/gpio.c b/arch/arm/mach-pnx4008/gpio.c
index e1ce050d8fe0..1ab84ced7b5a 100644
--- a/arch/arm/mach-pnx4008/gpio.c
+++ b/arch/arm/mach-pnx4008/gpio.c
@@ -14,7 +14,6 @@
* or implied.
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/arch/arm/mach-pnx4008/sleep.S b/arch/arm/mach-pnx4008/sleep.S
index 93c802bac269..fea1e17a3650 100644
--- a/arch/arm/mach-pnx4008/sleep.S
+++ b/arch/arm/mach-pnx4008/sleep.S
@@ -11,7 +11,6 @@
* or implied.
*/
-#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-pnx4008/time.c b/arch/arm/mach-pnx4008/time.c
index 756228ddd035..8621c206ac84 100644
--- a/arch/arm/mach-pnx4008/time.c
+++ b/arch/arm/mach-pnx4008/time.c
@@ -11,7 +11,6 @@
* or implied.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
@@ -48,15 +47,14 @@ static unsigned long pnx4008_gettimeoffset(void)
/*!
* IRQ handler for the timer
*/
-static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t pnx4008_timer_interrupt(int irq, void *dev_id)
{
if (__raw_readl(HSTIM_INT) & MATCH0_INT) {
write_seqlock(&xtime_lock);
do {
- timer_tick(regs);
+ timer_tick();
/*
* this algorithm takes care of possible delay
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index cce26576999e..a1a900d16665 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -212,7 +212,7 @@ static struct platform_device corgits_device = {
*/
static struct pxamci_platform_data corgi_mci_platform_data;
-static int corgi_mci_init(struct device *dev, irqreturn_t (*corgi_detect_int)(int, void *, struct pt_regs *), void *data)
+static int corgi_mci_init(struct device *dev, irq_handler_t corgi_detect_int, void *data)
{
int err;
@@ -284,21 +284,9 @@ static struct pxaficp_platform_data corgi_ficp_platform_data = {
/*
* USB Device Controller
*/
-static void corgi_udc_command(int cmd)
-{
- switch(cmd) {
- case PXA2XX_UDC_CMD_CONNECT:
- GPSR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
- break;
- case PXA2XX_UDC_CMD_DISCONNECT:
- GPCR(CORGI_GPIO_USB_PULLUP) = GPIO_bit(CORGI_GPIO_USB_PULLUP);
- break;
- }
-}
-
static struct pxa2xx_udc_mach_info udc_info __initdata = {
/* no connect GPIO; corgi can't tell connection status */
- .udc_command = corgi_udc_command,
+ .gpio_pullup = CORGI_GPIO_USB_PULLUP,
};
@@ -350,7 +338,6 @@ static void __init corgi_init(void)
corgi_ssp_set_machinfo(&corgi_ssp_machinfo);
pxa_gpio_mode(CORGI_GPIO_IR_ON | GPIO_OUT);
- pxa_gpio_mode(CORGI_GPIO_USB_PULLUP | GPIO_OUT);
pxa_gpio_mode(CORGI_GPIO_HSYNC | GPIO_IN);
pxa_set_udc_info(&udc_info);
diff --git a/arch/arm/mach-pxa/corgi_lcd.c b/arch/arm/mach-pxa/corgi_lcd.c
index 6dbcaf114ad7..a72476c24621 100644
--- a/arch/arm/mach-pxa/corgi_lcd.c
+++ b/arch/arm/mach-pxa/corgi_lcd.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/video/w100fb.c
+ * linux/arch/arm/mach-pxa/corgi_lcd.c
*
* Corgi/Spitz LCD Specific Code
*
@@ -431,10 +431,10 @@ struct platform_device corgifb_device = {
#include <asm/arch/pxafb.h>
-void spitz_lcd_power(int on)
+void spitz_lcd_power(int on, struct fb_var_screeninfo *var)
{
if (on)
- lcdtg_hw_init(480);
+ lcdtg_hw_init(var->xres);
else
lcdtg_suspend();
}
diff --git a/arch/arm/mach-pxa/dma.c b/arch/arm/mach-pxa/dma.c
index 7d8c85486c66..4440babe7b97 100644
--- a/arch/arm/mach-pxa/dma.c
+++ b/arch/arm/mach-pxa/dma.c
@@ -27,13 +27,13 @@
static struct dma_channel {
char *name;
- void (*irq_handler)(int, void *, struct pt_regs *);
+ void (*irq_handler)(int, void *);
void *data;
} dma_channels[PXA_DMA_CHANNELS];
int pxa_request_dma (char *name, pxa_dma_prio prio,
- void (*irq_handler)(int, void *, struct pt_regs *),
+ void (*irq_handler)(int, void *),
void *data)
{
unsigned long flags;
@@ -87,7 +87,7 @@ void pxa_free_dma (int dma_ch)
local_irq_restore(flags);
}
-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
int i, dint = DINT;
@@ -95,7 +95,7 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
if (dint & (1 << i)) {
struct dma_channel *channel = &dma_channels[i];
if (channel->name && channel->irq_handler) {
- channel->irq_handler(i, channel->data, regs);
+ channel->irq_handler(i, channel->data);
} else {
/*
* IRQ for an unregistered DMA channel:
diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
index 5efa84749f37..45fb2c3bcf82 100644
--- a/arch/arm/mach-pxa/generic.c
+++ b/arch/arm/mach-pxa/generic.c
@@ -204,13 +204,6 @@ static struct platform_device udc_device = {
}
};
-static struct pxafb_mach_info pxa_fb_info;
-
-void __init set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info)
-{
- memcpy(&pxa_fb_info,hard_pxa_fb_info,sizeof(struct pxafb_mach_info));
-}
-
static struct resource pxafb_resources[] = {
[0] = {
.start = 0x44000000,
@@ -230,7 +223,6 @@ static struct platform_device pxafb_device = {
.name = "pxa2xx-fb",
.id = -1,
.dev = {
- .platform_data = &pxa_fb_info,
.dma_mask = &fb_dma_mask,
.coherent_dma_mask = 0xffffffff,
},
@@ -238,6 +230,11 @@ static struct platform_device pxafb_device = {
.resource = pxafb_resources,
};
+void __init set_pxa_fb_info(struct pxafb_mach_info *info)
+{
+ pxafb_device.dev.platform_data = info;
+}
+
void __init set_pxa_fb_parent(struct device *parent_dev)
{
pxafb_device.dev.parent = parent_dev;
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index 6914d22bc20f..64df44043a65 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -82,7 +82,7 @@ static void idp_vlcd(int on)
}
}
-static void idp_lcd_power(int on)
+static void idp_lcd_power(int on, struct fb_var_screeninfo *var)
{
if (on) {
IDP_CPLD_LCD |= (1<<0);
@@ -99,7 +99,7 @@ static void idp_lcd_power(int on)
idp_vlcd(on);
}
-static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+static struct pxafb_mode_info sharp_lm8v31_mode = {
.pixclock = 270000,
.xres = 640,
.yres = 480,
@@ -112,6 +112,11 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = {
.lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info sharp_lm8v31 = {
+ .modes = &sharp_lm8v31_mode,
+ .num_modes = 1,
.cmap_inverse = 0,
.cmap_static = 0,
.lccr0 = LCCR0_SDS,
@@ -120,7 +125,7 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = {
.pxafb_lcd_power = &idp_lcd_power
};
-static int idp_mci_init(struct device *dev, irqreturn_t (*idp_detect_int)(int, void *, struct pt_regs *), void *data)
+static int idp_mci_init(struct device *dev, irq_handler_t idp_detect_int, void *data)
{
/* setup GPIO for PXA25x MMC controller */
pxa_gpio_mode(GPIO6_MMCCLK_MD);
diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
index 12141e2a50cc..ab1a16025d51 100644
--- a/arch/arm/mach-pxa/irq.c
+++ b/arch/arm/mach-pxa/irq.c
@@ -143,8 +143,7 @@ static struct irq_chip pxa_low_gpio_chip = {
* Demux handler for GPIO>=2 edge detect interrupts
*/
-static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned int mask;
int loop;
@@ -160,7 +159,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
mask >>= 2;
do {
if (mask & 1)
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
irq++;
desc++;
mask >>= 1;
@@ -175,7 +174,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
desc = irq_desc + irq;
do {
if (mask & 1)
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
irq++;
desc++;
mask >>= 1;
@@ -190,7 +189,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
desc = irq_desc + irq;
do {
if (mask & 1)
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
irq++;
desc++;
mask >>= 1;
@@ -206,7 +205,7 @@ static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc,
desc = irq_desc + irq;
do {
if (mask & 1)
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
irq++;
desc++;
mask >>= 1;
diff --git a/arch/arm/mach-pxa/leds-trizeps4.c b/arch/arm/mach-pxa/leds-trizeps4.c
index 14cfc85e44b5..2271d20ffeda 100644
--- a/arch/arm/mach-pxa/leds-trizeps4.c
+++ b/arch/arm/mach-pxa/leds-trizeps4.c
@@ -10,7 +10,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/init.h>
#include <asm/hardware.h>
diff --git a/arch/arm/mach-pxa/leds.h b/arch/arm/mach-pxa/leds.h
index 4f829b8c39dd..7f0dfe01345a 100644
--- a/arch/arm/mach-pxa/leds.h
+++ b/arch/arm/mach-pxa/leds.h
@@ -1,5 +1,5 @@
/*
- * include/asm-arm/arch-pxa/leds.h
+ * arch/arm/mach-pxa/leds.h
*
* Copyright (c) 2001 Jeff Sutherland, Accelent Systems Inc.
*
diff --git a/arch/arm/mach-pxa/lpd270.c b/arch/arm/mach-pxa/lpd270.c
index 12479ae26db2..5749f6b72e12 100644
--- a/arch/arm/mach-pxa/lpd270.c
+++ b/arch/arm/mach-pxa/lpd270.c
@@ -75,8 +75,7 @@ static struct irq_chip lpd270_irq_chip = {
.unmask = lpd270_unmask_irq,
};
-static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned long pending;
@@ -86,7 +85,7 @@ static void lpd270_irq_handler(unsigned int irq, struct irqdesc *desc,
if (likely(pending)) {
irq = LPD270_IRQ(0) + __ffs(pending);
desc = irq_desc + irq;
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
pending = __raw_readw(LPD270_INT_STATUS) &
lpd270_irq_enabled;
@@ -248,7 +247,7 @@ static void lpd270_backlight_power(int on)
}
/* 5.7" TFT QVGA (LoLo display number 1) */
-static struct pxafb_mach_info sharp_lq057q3dc02 __initdata = {
+static struct pxafb_mode_info sharp_lq057q3dc02_mode = {
.pixclock = 150000,
.xres = 320,
.yres = 240,
@@ -260,13 +259,18 @@ static struct pxafb_mach_info sharp_lq057q3dc02 __initdata = {
.upper_margin = 0x08,
.lower_margin = 0x14,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq057q3dc02 = {
+ .modes = &sharp_lq057q3dc02_mode,
+ .num_modes = 1,
.lccr0 = 0x07800080,
.lccr3 = 0x00400000,
.pxafb_backlight_power = lpd270_backlight_power,
};
/* 12.1" TFT SVGA (LoLo display number 2) */
-static struct pxafb_mach_info sharp_lq121s1dg31 __initdata = {
+static struct pxafb_mode_info sharp_lq121s1dg31_mode = {
.pixclock = 50000,
.xres = 800,
.yres = 600,
@@ -278,13 +282,18 @@ static struct pxafb_mach_info sharp_lq121s1dg31 __initdata = {
.upper_margin = 0x14,
.lower_margin = 0x0a,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq121s1dg31 = {
+ .modes = &sharp_lq121s1dg31_mode,
+ .num_modes = 1,
.lccr0 = 0x07800080,
.lccr3 = 0x00400000,
.pxafb_backlight_power = lpd270_backlight_power,
};
/* 3.6" TFT QVGA (LoLo display number 3) */
-static struct pxafb_mach_info sharp_lq036q1da01 __initdata = {
+static struct pxafb_mode_info sharp_lq036q1da01_mode = {
.pixclock = 150000,
.xres = 320,
.yres = 240,
@@ -296,13 +305,18 @@ static struct pxafb_mach_info sharp_lq036q1da01 __initdata = {
.upper_margin = 0x03,
.lower_margin = 0x03,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq036q1da01 = {
+ .modes = &sharp_lq036q1da01_mode,
+ .num_modes = 1,
.lccr0 = 0x07800080,
.lccr3 = 0x00400000,
.pxafb_backlight_power = lpd270_backlight_power,
};
/* 6.4" TFT VGA (LoLo display number 5) */
-static struct pxafb_mach_info sharp_lq64d343 __initdata = {
+static struct pxafb_mode_info sharp_lq64d343_mode = {
.pixclock = 25000,
.xres = 640,
.yres = 480,
@@ -314,13 +328,18 @@ static struct pxafb_mach_info sharp_lq64d343 __initdata = {
.upper_margin = 0x22,
.lower_margin = 0x00,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq64d343 = {
+ .modes = &sharp_lq64d343_mode,
+ .num_modes = 1,
.lccr0 = 0x07800080,
.lccr3 = 0x00400000,
.pxafb_backlight_power = lpd270_backlight_power,
};
/* 10.4" TFT VGA (LoLo display number 7) */
-static struct pxafb_mach_info sharp_lq10d368 __initdata = {
+static struct pxafb_mode_info sharp_lq10d368_mode = {
.pixclock = 25000,
.xres = 640,
.yres = 480,
@@ -332,13 +351,18 @@ static struct pxafb_mach_info sharp_lq10d368 __initdata = {
.upper_margin = 0x22,
.lower_margin = 0x00,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq10d368 = {
+ .modes = &sharp_lq10d368_mode,
+ .num_modes = 1,
.lccr0 = 0x07800080,
.lccr3 = 0x00400000,
.pxafb_backlight_power = lpd270_backlight_power,
};
/* 3.5" TFT QVGA (LoLo display number 8) */
-static struct pxafb_mach_info sharp_lq035q7db02_20 __initdata = {
+static struct pxafb_mode_info sharp_lq035q7db02_20_mode = {
.pixclock = 150000,
.xres = 240,
.yres = 320,
@@ -350,6 +374,11 @@ static struct pxafb_mach_info sharp_lq035q7db02_20 __initdata = {
.upper_margin = 0x05,
.lower_margin = 0x14,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info sharp_lq035q7db02_20 = {
+ .modes = &sharp_lq035q7db02_20_mode,
+ .num_modes = 1,
.lccr0 = 0x07800080,
.lccr3 = 0x00400000,
.pxafb_backlight_power = lpd270_backlight_power,
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index 83ff5cee64d9..142c33c3dff5 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -85,8 +85,7 @@ static struct irq_chip lubbock_irq_chip = {
.unmask = lubbock_unmask_irq,
};
-static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
do {
@@ -94,7 +93,7 @@ static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc,
if (likely(pending)) {
irq = LUBBOCK_IRQ(0) + __ffs(pending);
desc = irq_desc + irq;
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
}
pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
} while (pending);
@@ -352,7 +351,7 @@ static struct platform_device *devices[] __initdata = {
&pxa_ssp,
};
-static struct pxafb_mach_info sharp_lm8v31 __initdata = {
+static struct pxafb_mode_info sharp_lm8v31_mode = {
.pixclock = 270000,
.xres = 640,
.yres = 480,
@@ -365,6 +364,11 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = {
.lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info sharp_lm8v31 = {
+ .modes = &sharp_lm8v31_mode,
+ .num_modes = 1,
.cmap_inverse = 0,
.cmap_static = 0,
.lccr0 = LCCR0_SDS,
@@ -374,7 +378,7 @@ static struct pxafb_mach_info sharp_lm8v31 __initdata = {
#define MMC_POLL_RATE msecs_to_jiffies(1000)
static void lubbock_mmc_poll(unsigned long);
-static irqreturn_t (*mmc_detect_int)(int, void *, struct pt_regs *);
+static irq_handler_t mmc_detect_int;
static struct timer_list mmc_timer = {
.function = lubbock_mmc_poll,
@@ -393,22 +397,22 @@ static void lubbock_mmc_poll(unsigned long data)
if (LUB_IRQ_SET_CLR & (1 << 0))
mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
else {
- (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data, NULL);
+ (void) mmc_detect_int(LUBBOCK_SD_IRQ, (void *)data);
enable_irq(LUBBOCK_SD_IRQ);
}
}
-static irqreturn_t lubbock_detect_int(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t lubbock_detect_int(int irq, void *data)
{
/* IRQ is level triggered; disable, and poll for removal */
disable_irq(irq);
mod_timer(&mmc_timer, jiffies + MMC_POLL_RATE);
- return mmc_detect_int(irq, data, regs);
+ return mmc_detect_int(irq, data);
}
static int lubbock_mci_init(struct device *dev,
- irqreturn_t (*detect_int)(int, void *, struct pt_regs *),
+ irq_handler_t detect_int,
void *data)
{
/* setup GPIO for PXA25x MMC controller */
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index a7e9b96f258a..49c34d94a9fe 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -71,8 +71,7 @@ static struct irq_chip mainstone_irq_chip = {
.unmask = mainstone_unmask_irq,
};
-static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned long pending = MST_INTSETCLR & mainstone_irq_enabled;
do {
@@ -80,7 +79,7 @@ static void mainstone_irq_handler(unsigned int irq, struct irqdesc *desc,
if (likely(pending)) {
irq = MAINSTONE_IRQ(0) + __ffs(pending);
desc = irq_desc + irq;
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
}
pending = MST_INTSETCLR & mainstone_irq_enabled;
} while (pending);
@@ -279,7 +278,7 @@ static void mainstone_backlight_power(int on)
}
}
-static struct pxafb_mach_info toshiba_ltm04c380k __initdata = {
+static struct pxafb_mode_info toshiba_ltm04c380k_mode = {
.pixclock = 50000,
.xres = 640,
.yres = 480,
@@ -291,12 +290,9 @@ static struct pxafb_mach_info toshiba_ltm04c380k __initdata = {
.upper_margin = 0,
.lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
- .lccr0 = LCCR0_Act,
- .lccr3 = LCCR3_PCP,
- .pxafb_backlight_power = mainstone_backlight_power,
};
-static struct pxafb_mach_info toshiba_ltm035a776c __initdata = {
+static struct pxafb_mode_info toshiba_ltm035a776c_mode = {
.pixclock = 110000,
.xres = 240,
.yres = 320,
@@ -308,12 +304,16 @@ static struct pxafb_mach_info toshiba_ltm035a776c __initdata = {
.upper_margin = 1,
.lower_margin = 10,
.sync = FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT,
+};
+
+static struct pxafb_mach_info mainstone_pxafb_info = {
+ .num_modes = 1,
.lccr0 = LCCR0_Act,
.lccr3 = LCCR3_PCP,
.pxafb_backlight_power = mainstone_backlight_power,
};
-static int mainstone_mci_init(struct device *dev, irqreturn_t (*mstone_detect_int)(int, void *, struct pt_regs *), void *data)
+static int mainstone_mci_init(struct device *dev, irq_handler_t mstone_detect_int, void *data)
{
int err;
@@ -448,9 +448,11 @@ static void __init mainstone_init(void)
/* reading Mainstone's "Virtual Configuration Register"
might be handy to select LCD type here */
if (0)
- set_pxa_fb_info(&toshiba_ltm04c380k);
+ mainstone_pxafb_info.modes = &toshiba_ltm04c380k_mode;
else
- set_pxa_fb_info(&toshiba_ltm035a776c);
+ mainstone_pxafb_info.modes = &toshiba_ltm035a776c_mode;
+
+ set_pxa_fb_info(&mainstone_pxafb_info);
pxa_set_mci_info(&mainstone_mci_platform_data);
pxa_set_ficp_info(&mainstone_ficp_platform_data);
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 6dbff6d94801..34fb80b37023 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -197,7 +197,7 @@ static struct platform_device poodle_ts_device = {
*/
static struct pxamci_platform_data poodle_mci_platform_data;
-static int poodle_mci_init(struct device *dev, irqreturn_t (*poodle_detect_int)(int, void *, struct pt_regs *), void *data)
+static int poodle_mci_init(struct device *dev, irq_handler_t poodle_detect_int, void *data)
{
int err;
@@ -296,27 +296,25 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
/* PXAFB device */
-static struct pxafb_mach_info poodle_fb_info __initdata = {
+static struct pxafb_mode_info poodle_fb_mode = {
.pixclock = 144700,
-
.xres = 320,
.yres = 240,
.bpp = 16,
-
.hsync_len = 7,
.left_margin = 11,
.right_margin = 30,
-
.vsync_len = 2,
.upper_margin = 2,
.lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+};
+static struct pxafb_mach_info poodle_fb_info = {
+ .modes = &poodle_fb_mode,
+ .num_modes = 1,
.lccr0 = LCCR0_Act | LCCR0_Sngl | LCCR0_Color,
.lccr3 = 0,
-
- .pxafb_backlight_power = NULL,
- .pxafb_lcd_power = NULL,
};
static struct platform_device *devices[] __initdata = {
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 1c32a9310dc2..3cbac63bed3c 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -291,7 +291,7 @@ static struct platform_device spitzts_device = {
static struct pxamci_platform_data spitz_mci_platform_data;
-static int spitz_mci_init(struct device *dev, irqreturn_t (*spitz_detect_int)(int, void *, struct pt_regs *), void *data)
+static int spitz_mci_init(struct device *dev, irq_handler_t spitz_detect_int, void *data)
{
int err;
@@ -407,21 +407,42 @@ static struct pxaficp_platform_data spitz_ficp_platform_data = {
/*
* Spitz PXA Framebuffer
*/
-static struct pxafb_mach_info spitz_pxafb_info __initdata = {
- .pixclock = 19231,
- .xres = 480,
- .yres = 640,
- .bpp = 16,
- .hsync_len = 40,
- .left_margin = 46,
- .right_margin = 125,
- .vsync_len = 3,
- .upper_margin = 1,
- .lower_margin = 0,
- .sync = 0,
- .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
- .lccr3 = LCCR3_PixRsEdg | LCCR3_OutEnH,
- .pxafb_lcd_power = spitz_lcd_power,
+
+static struct pxafb_mode_info spitz_pxafb_modes[] = {
+{
+ .pixclock = 19231,
+ .xres = 480,
+ .yres = 640,
+ .bpp = 16,
+ .hsync_len = 40,
+ .left_margin = 46,
+ .right_margin = 125,
+ .vsync_len = 3,
+ .upper_margin = 1,
+ .lower_margin = 0,
+ .sync = 0,
+},{
+ .pixclock = 134617,
+ .xres = 240,
+ .yres = 320,
+ .bpp = 16,
+ .hsync_len = 20,
+ .left_margin = 20,
+ .right_margin = 46,
+ .vsync_len = 2,
+ .upper_margin = 1,
+ .lower_margin = 0,
+ .sync = 0,
+},
+};
+
+static struct pxafb_mach_info spitz_pxafb_info = {
+ .modes = &spitz_pxafb_modes[0],
+ .num_modes = 2,
+ .fixed_modes = 1,
+ .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act | LCCR0_LDDALT | LCCR0_OUC | LCCR0_CMDIM | LCCR0_RDSTM,
+ .lccr3 = LCCR3_PixRsEdg | LCCR3_OutEnH,
+ .pxafb_lcd_power = spitz_lcd_power,
};
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 1fddfeaa630d..6cc202755fb4 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -65,7 +65,7 @@ static const struct ssp_info_ ssp_info[PXA_SSP_PORTS] = {
static DEFINE_MUTEX(mutex);
static int use_count[PXA_SSP_PORTS] = {0, 0, 0};
-static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ssp_interrupt(int irq, void *dev_id)
{
struct ssp_dev *dev = (struct ssp_dev*) dev_id;
unsigned int status = SSSR_P(dev->port);
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 5dbd191c57c4..3ac268fa419b 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -75,7 +75,7 @@ static int match_posponed;
#endif
static irqreturn_t
-pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+pxa_timer_interrupt(int irq, void *dev_id)
{
int next_match;
@@ -105,7 +105,7 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* exactly one tick period which should be a pretty rare event.
*/
do {
- timer_tick(regs);
+ timer_tick();
OSSR = OSSR_M0; /* Clear match on timer 0 */
next_match = (OSMR0 += LATCH);
} while( (signed long)(next_match - OSCR) <= 8 );
@@ -157,13 +157,13 @@ static void pxa_dyn_tick_reprogram(unsigned long ticks)
}
static irqreturn_t
-pxa_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+pxa_dyn_tick_handler(int irq, void *dev_id)
{
if (match_posponed) {
match_posponed = 0;
OSMR0 = initial_match;
if ( (signed long)(initial_match - OSCR) <= 8 )
- return pxa_timer_interrupt(irq, dev_id, regs);
+ return pxa_timer_interrupt(irq, dev_id);
}
return IRQ_NONE;
}
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index 249353616aba..7915a5a22865 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -174,7 +174,7 @@ static struct pxa2xx_udc_mach_info udc_info __initdata = {
*/
static struct pxamci_platform_data tosa_mci_platform_data;
-static int tosa_mci_init(struct device *dev, irqreturn_t (*tosa_detect_int)(int, void *, struct pt_regs *), void *data)
+static int tosa_mci_init(struct device *dev, irq_handler_t tosa_detect_int, void *data)
{
int err;
diff --git a/arch/arm/mach-pxa/trizeps4.c b/arch/arm/mach-pxa/trizeps4.c
index 7c3007df1bd6..c1827d021ba8 100644
--- a/arch/arm/mach-pxa/trizeps4.c
+++ b/arch/arm/mach-pxa/trizeps4.c
@@ -270,7 +270,7 @@ void board_pcmcia_power(int power) {;}
#endif /* CONFIG_MACH_TRIZEPS4_CONXS */
EXPORT_SYMBOL(board_pcmcia_power);
-static int trizeps4_mci_init(struct device *dev, irqreturn_t (*mci_detect_int)(int, void *, struct pt_regs *), void *data)
+static int trizeps4_mci_init(struct device *dev, irq_handler_t mci_detect_int, void *data)
{
int err;
/* setup GPIO for PXA27x MMC controller */
@@ -368,7 +368,7 @@ static struct map_desc trizeps4_io_desc[] __initdata = {
}
};
-static struct pxafb_mach_info sharp_lcd __initdata = {
+static struct pxafb_mode_info sharp_lcd_mode = {
.pixclock = 78000,
.xres = 640,
.yres = 480,
@@ -381,6 +381,11 @@ static struct pxafb_mach_info sharp_lcd __initdata = {
.lower_margin = 0,
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.cmap_greyscale = 0,
+};
+
+static struct pxafb_mach_info sharp_lcd = {
+ .modes = &sharp_lcd_mode,
+ .num_modes = 1,
.cmap_inverse = 0,
.cmap_static = 0,
.lccr0 = LCCR0_Color | LCCR0_Pas | LCCR0_Dual,
diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c
index da0286973823..68c67053f479 100644
--- a/arch/arm/mach-realview/core.c
+++ b/arch/arm/mach-realview/core.c
@@ -515,18 +515,18 @@ static unsigned long realview_gettimeoffset(void)
/*
* IRQ handler for the timer
*/
-static irqreturn_t realview_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t realview_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
// ...clear the interrupt
writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
- timer_tick(regs);
+ timer_tick();
#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS)
smp_send_timer();
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
index ac511d41d4d7..596379a4cf82 100644
--- a/arch/arm/mach-rpc/dma.c
+++ b/arch/arm/mach-rpc/dma.c
@@ -83,7 +83,7 @@ static void iomd_get_next_sg(struct scatterlist *sg, dma_t *dma)
sg->length |= flags;
}
-static irqreturn_t iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t iomd_dma_handle(int irq, void *dev_id)
{
dma_t *dma = (dma_t *)dev_id;
unsigned long base = dma->dma_base;
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index bbd138be6a70..63965c78de8c 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -2,11 +2,18 @@ if ARCH_S3C2410
menu "S3C24XX Implementations"
+config MACH_AML_M5900
+ bool "AML M5900 Series"
+ select CPU_S3C2410
+ help
+ Say Y here if you are using the American Microsystems M5900 Series
+ <http://www.amltd.com>
+
config MACH_ANUBIS
bool "Simtec Electronics ANUBIS"
select CPU_S3C2440
help
- Say Y gere if you are using the Simtec Electronics ANUBIS
+ Say Y here if you are using the Simtec Electronics ANUBIS
development system
config MACH_OSIRIS
@@ -126,6 +133,12 @@ config MACH_NEXCODER_2440
help
Say Y here if you are using the Nex Vision NEXCODER 2440 Light Board
+config MACH_VSTMS
+ bool "VMSTMS"
+ select CPU_S3C2412
+ help
+ Say Y here if you are using an VSTMS board
+
endmenu
config S3C2410_CLOCK
@@ -133,10 +146,24 @@ config S3C2410_CLOCK
help
Clock code for the S3C2410, and similar processors
+config S3C2410_PM
+ bool
+ depends on CONFIG_PM
+ help
+ Power Management code common to S3C2410 and better
+
+config CPU_S3C2410_DMA
+ bool
+ depends on S3C2410_DMA && (CPU_S3C2410 || CPU_S3C2442)
+ default y if CPU_S3C2410 || CPU_S3C2442
+ help
+ DMA device selection for S3C2410 and compatible CPUs
+
config CPU_S3C2410
bool
depends on ARCH_S3C2410
select S3C2410_CLOCK
+ select S3C2410_PM
help
Support for S3C2410 and S3C2410A family from the S3C24XX line
of Samsung Mobile CPUs.
@@ -149,6 +176,13 @@ config CPU_S3C2412_ONLY
!CPU_S3C2440 && !CPU_S3C2442 && CPU_S3C2412
default y if CPU_S3C2412
+config S3C2412_PM
+ bool
+ default y if PM
+ depends on CPU_S3C2412
+ help
+ Internal config node to apply S3C2412 power management
+
config CPU_S3C2412
bool
depends on ARCH_S3C2410
@@ -165,6 +199,7 @@ config CPU_S3C2440
bool
depends on ARCH_S3C2410
select S3C2410_CLOCK
+ select S3C2410_PM
select CPU_S3C244X
help
Support for S3C2440 Samsung Mobile CPU based systems.
@@ -173,6 +208,7 @@ config CPU_S3C2442
bool
depends on ARCH_S3C2420
select S3C2410_CLOCK
+ select S3C2410_PM
select CPU_S3C244X
help
Support for S3C2442 Samsung Mobile CPU based systems.
@@ -256,7 +292,7 @@ config S3C2410_PM_CHECK_CHUNKSIZE
config PM_SIMTEC
bool
- depends on PM && (ARCH_BAST || MACH_VR1000)
+ depends on PM && (ARCH_BAST || MACH_VR1000 || MACH_AML_M5900)
default y
config S3C2410_LOWLEVEL_UART_PORT
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 0eadec916214..d66013365b6b 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -9,6 +9,8 @@ obj-y := cpu.o irq.o time.o gpio.o clock.o devs.o
obj-m :=
obj-n :=
obj- :=
+obj-dma-y :=
+obj-dma-n :=
# DMA
obj-$(CONFIG_S3C2410_DMA) += dma.o
@@ -20,6 +22,10 @@ obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpio.o
obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
obj-$(CONFIG_CPU_S3C2410) += s3c2410-gpio.o
+obj-$(CONFIG_CPU_S3C2410) += s3c2410-irq.o
+
+obj-$(CONFIG_S3C2410_PM) += s3c2410-pm.o s3c2410-sleep.o
+obj-$(CONFIG_CPU_S3C2410_DMA) += s3c2410-dma.o
# Power Management support
@@ -30,6 +36,9 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
obj-$(CONFIG_CPU_S3C2412) += s3c2412.o
obj-$(CONFIG_CPU_S3C2412) += s3c2412-irq.o
obj-$(CONFIG_CPU_S3C2412) += s3c2412-clock.o
+obj-dma-$(CONFIG_CPU_S3C2412) += s3c2412-dma.o
+
+obj-$(CONFIG_S3C2412_PM) += s3c2412-pm.o
#
# S3C244X support
@@ -47,6 +56,7 @@ obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o
+obj-dma-$(CONFIG_CPU_S3C2440) += s3c2440-dma.o
# S3C2442 support
@@ -57,8 +67,13 @@ obj-$(CONFIG_CPU_S3C2442) += s3c2442-clock.o
obj-$(CONFIG_BAST_PC104_IRQ) += bast-irq.o
+# merge in dma objects
+
+obj-y += $(obj-dma-y)
+
# machine specific support
+obj-$(CONFIG_MACH_AML_M5900) += mach-amlm5900.o
obj-$(CONFIG_MACH_ANUBIS) += mach-anubis.o
obj-$(CONFIG_MACH_OSIRIS) += mach-osiris.o
obj-$(CONFIG_ARCH_BAST) += mach-bast.o usb-simtec.o
@@ -71,5 +86,6 @@ obj-$(CONFIG_MACH_VR1000) += mach-vr1000.o usb-simtec.o
obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
obj-$(CONFIG_MACH_OTOM) += mach-otom.o
obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
+obj-$(CONFIG_MACH_VSTMS) += mach-vstms.o
obj-$(CONFIG_MACH_SMDK) += common-smdk.o \ No newline at end of file
diff --git a/arch/arm/mach-s3c2410/bast-irq.c b/arch/arm/mach-s3c2410/bast-irq.c
index def4441d2442..23d5beea5568 100644
--- a/arch/arm/mach-s3c2410/bast-irq.c
+++ b/arch/arm/mach-s3c2410/bast-irq.c
@@ -18,10 +18,6 @@
* 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
- *
- * Modifications:
- * 08-Jan-2003 BJD Moved from central IRQ code
- * 21-Aug-2005 BJD Fixed missing code and compile errors
*/
@@ -116,8 +112,7 @@ static struct irqchip bast_pc104_chip = {
static void
bast_irq_pc104_demux(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+ struct irqdesc *desc)
{
unsigned int stat;
unsigned int irqno;
@@ -137,7 +132,7 @@ bast_irq_pc104_demux(unsigned int irq,
if (stat & 1) {
irqno = bast_pc104_irqs[i];
desc = irq_desc + irqno;
- desc_handle_irq(irqno, desc, regs);
+ desc_handle_irq(irqno, desc);
}
}
}
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
index 1c3c6adae6c4..9d4899eddf1f 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -124,6 +124,15 @@ static struct cpu_table cpu_ids[] __initdata = {
.init = s3c2412_init,
.name = name_s3c2412,
},
+ { /* a newer version of the s3c2412 */
+ .idcode = 0x32412003,
+ .idmask = 0xffffffff,
+ .map_io = s3c2412_map_io,
+ .init_clocks = s3c2412_init_clocks,
+ .init_uarts = s3c2412_init_uarts,
+ .init = s3c2412_init,
+ .name = name_s3c2412,
+ },
{
.idcode = 0x0, /* S3C2400 doesn't have an idcode */
.idmask = 0xffffffff,
diff --git a/arch/arm/mach-s3c2410/devs.h b/arch/arm/mach-s3c2410/devs.h
index 726e2eaf8797..14fb0bade716 100644
--- a/arch/arm/mach-s3c2410/devs.h
+++ b/arch/arm/mach-s3c2410/devs.h
@@ -8,11 +8,6 @@
* 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.
- *
- * Modifications:
- * 18-Aug-2004 BJD Created initial version
- * 27-Aug-2004 BJD Added timers 0 through 3
- * 10-Feb-2005 BJD Added camera from guillaume.gourat@nexvision.tv
*/
#include <linux/platform_device.h>
diff --git a/arch/arm/mach-s3c2410/dma.c b/arch/arm/mach-s3c2410/dma.c
index cc92a7b2db88..3d211dc2f2f9 100644
--- a/arch/arm/mach-s3c2410/dma.c
+++ b/arch/arm/mach-s3c2410/dma.c
@@ -1,35 +1,16 @@
-/* linux/arch/arm/mach-bast/dma.c
+/* linux/arch/arm/mach-s3c2410/dma.c
*
- * (c) 2003-2005 Simtec Electronics
+ * (c) 2003-2005,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
* S3C2410 DMA core
*
- * http://www.simtec.co.uk/products/EB2410ITX/
+ * http://armlinux.simtec.co.uk/
*
* 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.
- *
- * Changelog:
- * 27-Feb-2005 BJD Added kmem cache for dma descriptors
- * 18-Nov-2004 BJD Removed error for loading onto stopped channel
- * 10-Nov-2004 BJD Ensure all external symbols exported for modules
- * 10-Nov-2004 BJD Use sys_device and sysdev_class for power management
- * 08-Aug-2004 BJD Apply rmk's suggestions
- * 21-Jul-2004 BJD Ported to linux 2.6
- * 12-Jul-2004 BJD Finished re-write and change of API
- * 06-Jul-2004 BJD Rewrote dma code to try and cope with various problems
- * 23-May-2003 BJD Created file
- * 19-Aug-2003 BJD Cleanup, header fix, added URL
- *
- * This file is based on the Sangwook Lee/Samsung patches, re-written due
- * to various ommisions from the code (such as flexible dma configuration)
- * for use with the BAST system board.
- *
- * The re-write is pretty much complete, and should be good enough for any
- * possible DMA function
- */
+*/
#ifdef CONFIG_S3C2410_DMA_DEBUG
@@ -55,10 +36,14 @@
#include <asm/mach/dma.h>
#include <asm/arch/map.h>
+#include "dma.h"
+
/* io map for dma */
static void __iomem *dma_base;
static kmem_cache_t *dma_kmem;
+struct s3c24xx_dma_selection dma_sel;
+
/* dma channel state information */
struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
@@ -79,7 +64,6 @@ dma_wrreg(struct s3c2410_dma_chan *chan, int reg, unsigned long val)
pr_debug("writing %08x to register %08x\n",(unsigned int)val,reg);
writel(val, dma_regaddr(chan, reg));
}
-
#endif
#define dma_rdreg(chan, reg) readl((chan)->regs + (reg))
@@ -151,12 +135,20 @@ dmadbg_showregs(const char *fname, int line, struct s3c2410_dma_chan *chan)
#define dbg_showchan(chan) do { } while(0)
#endif /* CONFIG_S3C2410_DMA_DEBUG */
-#define check_channel(chan) \
- do { if ((chan) >= S3C2410_DMA_CHANNELS) { \
- printk(KERN_ERR "%s: invalid channel %d\n", __FUNCTION__, (chan)); \
- return -EINVAL; \
- } } while(0)
+static struct s3c2410_dma_chan *dma_chan_map[DMACH_MAX];
+/* lookup_dma_channel
+ *
+ * change the dma channel number given into a real dma channel id
+*/
+
+static struct s3c2410_dma_chan *lookup_dma_channel(unsigned int channel)
+{
+ if (channel & DMACH_LOW_LEVEL)
+ return &s3c2410_chans[channel & ~DMACH_LOW_LEVEL];
+ else
+ return dma_chan_map[channel];
+}
/* s3c2410_dma_stats_timeout
*
@@ -321,8 +313,10 @@ static inline void
s3c2410_dma_buffdone(struct s3c2410_dma_chan *chan, struct s3c2410_dma_buf *buf,
enum s3c2410_dma_buffresult result)
{
+#if 0
pr_debug("callback_fn=%p, buf=%p, id=%p, size=%d, result=%d\n",
chan->callback_fn, buf, buf->id, buf->size, result);
+#endif
if (chan->callback_fn != NULL) {
(chan->callback_fn)(chan, buf->id, buf->size, result);
@@ -439,7 +433,6 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
return 0;
}
-
/* s3c2410_dma_enqueue
*
* queue an given buffer for dma transfer.
@@ -460,11 +453,12 @@ s3c2410_dma_canload(struct s3c2410_dma_chan *chan)
int s3c2410_dma_enqueue(unsigned int channel, void *id,
dma_addr_t data, int size)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
struct s3c2410_dma_buf *buf;
unsigned long flags;
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
pr_debug("%s: id=%p, data=%08x, size=%d\n",
__FUNCTION__, id, (unsigned int)data, size);
@@ -562,8 +556,10 @@ s3c2410_dma_freebuf(struct s3c2410_dma_buf *buf)
static inline void
s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
{
+#if 0
pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
chan->number, chan->load_state);
+#endif
switch (chan->load_state) {
case S3C2410_DMALOAD_NONE:
@@ -599,7 +595,7 @@ s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
#define dmadbg2(x...)
static irqreturn_t
-s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
+s3c2410_dma_irq(int irq, void *devpw)
{
struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
struct s3c2410_dma_buf *buf;
@@ -718,7 +714,8 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
if (chan->load_state == S3C2410_DMALOAD_NONE) {
pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
chan->number, jiffies);
- s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
+ s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
+ S3C2410_DMAOP_STOP);
}
}
@@ -726,37 +723,34 @@ s3c2410_dma_irq(int irq, void *devpw, struct pt_regs *regs)
return IRQ_HANDLED;
}
+static struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel);
+
/* s3c2410_request_dma
*
* get control of an dma channel
*/
-int s3c2410_dma_request(unsigned int channel, struct s3c2410_dma_client *client,
+int s3c2410_dma_request(unsigned int channel,
+ struct s3c2410_dma_client *client,
void *dev)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan;
unsigned long flags;
int err;
pr_debug("dma%d: s3c2410_request_dma: client=%s, dev=%p\n",
channel, client->name, dev);
- check_channel(channel);
-
local_irq_save(flags);
- dbg_showchan(chan);
-
- if (chan->in_use) {
- if (client != chan->client) {
- printk(KERN_ERR "dma%d: already in use\n", channel);
- local_irq_restore(flags);
- return -EBUSY;
- } else {
- printk(KERN_ERR "dma%d: client already has channel\n", channel);
- }
+ chan = s3c2410_dma_map_channel(channel);
+ if (chan == NULL) {
+ local_irq_restore(flags);
+ return -EBUSY;
}
+ dbg_showchan(chan);
+
chan->client = client;
chan->in_use = 1;
@@ -809,14 +803,14 @@ EXPORT_SYMBOL(s3c2410_dma_request);
int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
unsigned long flags;
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
local_irq_save(flags);
-
if (chan->client != client) {
printk(KERN_WARNING "dma%d: possible free from different client (channel %p, passed %p)\n",
channel, chan->client, client);
@@ -837,8 +831,12 @@ int s3c2410_dma_free(dmach_t channel, struct s3c2410_dma_client *client)
if (chan->irq_claimed)
free_irq(chan->irq, (void *)chan);
+
chan->irq_claimed = 0;
+ if (!(channel & DMACH_LOW_LEVEL))
+ dma_chan_map[channel] = NULL;
+
local_irq_restore(flags);
return 0;
@@ -848,8 +846,8 @@ EXPORT_SYMBOL(s3c2410_dma_free);
static int s3c2410_dma_dostop(struct s3c2410_dma_chan *chan)
{
- unsigned long tmp;
unsigned long flags;
+ unsigned long tmp;
pr_debug("%s:\n", __FUNCTION__);
@@ -997,9 +995,10 @@ s3c2410_dma_started(struct s3c2410_dma_chan *chan)
int
s3c2410_dma_ctrl(dmach_t channel, enum s3c2410_chan_op op)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
switch (op) {
case S3C2410_DMAOP_START:
@@ -1046,12 +1045,19 @@ int s3c2410_dma_config(dmach_t channel,
int xferunit,
int dcon)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n",
__FUNCTION__, channel, xferunit, dcon);
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
+
+ printk("Initial dcon is %08x\n", dcon);
+
+ dcon |= chan->dcon & dma_sel.dcon_mask;
+
+ printk("New dcon is %08x\n", dcon);
switch (xferunit) {
case 1:
@@ -1086,9 +1092,10 @@ EXPORT_SYMBOL(s3c2410_dma_config);
int s3c2410_dma_setflags(dmach_t channel, unsigned int flags)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
pr_debug("%s: chan=%p, flags=%08x\n", __FUNCTION__, chan, flags);
@@ -1106,9 +1113,10 @@ EXPORT_SYMBOL(s3c2410_dma_setflags);
int s3c2410_dma_set_opfn(dmach_t channel, s3c2410_dma_opfn_t rtn)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
pr_debug("%s: chan=%p, op rtn=%p\n", __FUNCTION__, chan, rtn);
@@ -1121,9 +1129,10 @@ EXPORT_SYMBOL(s3c2410_dma_set_opfn);
int s3c2410_dma_set_buffdone_fn(dmach_t channel, s3c2410_dma_cbfn_t rtn)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
pr_debug("%s: chan=%p, callback rtn=%p\n", __FUNCTION__, chan, rtn);
@@ -1153,9 +1162,10 @@ int s3c2410_dma_devconfig(int channel,
int hwcfg,
unsigned long devaddr)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
pr_debug("%s: source=%d, hwcfg=%08x, devaddr=%08lx\n",
__FUNCTION__, (int)source, hwcfg, devaddr);
@@ -1200,9 +1210,10 @@ EXPORT_SYMBOL(s3c2410_dma_devconfig);
int s3c2410_dma_getposition(dmach_t channel, dma_addr_t *src, dma_addr_t *dst)
{
- struct s3c2410_dma_chan *chan = &s3c2410_chans[channel];
+ struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
- check_channel(channel);
+ if (chan == NULL)
+ return -EINVAL;
if (src != NULL)
*src = dma_rdreg(chan, S3C2410_DMA_DCSRC);
@@ -1252,7 +1263,7 @@ static int s3c2410_dma_resume(struct sys_device *dev)
#define s3c2410_dma_resume NULL
#endif /* CONFIG_PM */
-static struct sysdev_class dma_sysclass = {
+struct sysdev_class dma_sysclass = {
set_kset_name("s3c24xx-dma"),
.suspend = s3c2410_dma_suspend,
.resume = s3c2410_dma_resume,
@@ -1265,7 +1276,6 @@ static void s3c2410_dma_cache_ctor(void *p, kmem_cache_t *c, unsigned long f)
memset(p, 0, sizeof(struct s3c2410_dma_buf));
}
-
/* initialisation code */
static int __init s3c2410_init_dma(void)
@@ -1274,7 +1284,7 @@ static int __init s3c2410_init_dma(void)
int channel;
int ret;
- printk("S3C2410 DMA Driver, (c) 2003-2004 Simtec Electronics\n");
+ printk("S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics\n");
dma_base = ioremap(S3C24XX_PA_DMA, 0x200);
if (dma_base == NULL) {
@@ -1282,6 +1292,8 @@ static int __init s3c2410_init_dma(void)
return -ENOMEM;
}
+ printk("Registering sysclass\n");
+
ret = sysdev_class_register(&dma_sysclass);
if (ret != 0) {
printk(KERN_ERR "dma sysclass registration failed\n");
@@ -1335,4 +1347,95 @@ static int __init s3c2410_init_dma(void)
return ret;
}
-__initcall(s3c2410_init_dma);
+core_initcall(s3c2410_init_dma);
+
+static inline int is_channel_valid(unsigned int channel)
+{
+ return (channel & DMA_CH_VALID);
+}
+
+/* s3c2410_dma_map_channel()
+ *
+ * turn the virtual channel number into a real, and un-used hardware
+ * channel.
+ *
+ * currently this code uses first-free channel from the specified harware
+ * map, not taking into account anything that the board setup code may
+ * have to say about the likely peripheral set to be in use.
+*/
+
+struct s3c2410_dma_chan *s3c2410_dma_map_channel(int channel)
+{
+ struct s3c24xx_dma_map *ch_map;
+ struct s3c2410_dma_chan *dmach;
+ int ch;
+
+ if (dma_sel.map == NULL || channel > dma_sel.map_size)
+ return NULL;
+
+ ch_map = dma_sel.map + channel;
+
+ for (ch = 0; ch < S3C2410_DMA_CHANNELS; ch++) {
+ if (!is_channel_valid(ch_map->channels[ch]))
+ continue;
+
+ if (s3c2410_chans[ch].in_use == 0) {
+ printk("mapped channel %d to %d\n", channel, ch);
+ break;
+ }
+ }
+
+ if (ch >= S3C2410_DMA_CHANNELS)
+ return NULL;
+
+ /* update our channel mapping */
+
+ dmach = &s3c2410_chans[ch];
+ dma_chan_map[channel] = dmach;
+
+ /* select the channel */
+
+ (dma_sel.select)(dmach, ch_map);
+
+ return dmach;
+}
+
+static void s3c24xx_dma_show_ch(struct s3c24xx_dma_map *map, int ch)
+{
+ /* show the channel configuration */
+
+ printk("%2d: %20s, channels %c%c%c%c\n", ch, map->name,
+ (is_channel_valid(map->channels[0]) ? '0' : '-'),
+ (is_channel_valid(map->channels[1]) ? '1' : '-'),
+ (is_channel_valid(map->channels[2]) ? '2' : '-'),
+ (is_channel_valid(map->channels[3]) ? '3' : '-'));
+}
+
+static int s3c24xx_dma_check_entry(struct s3c24xx_dma_map *map, int ch)
+{
+ if (1)
+ s3c24xx_dma_show_ch(map, ch);
+
+ return 0;
+}
+
+int __init s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel)
+{
+ struct s3c24xx_dma_map *nmap;
+ size_t map_sz = sizeof(*nmap) * sel->map_size;
+ int ptr;
+
+ nmap = kmalloc(map_sz, GFP_KERNEL);
+ if (nmap == NULL)
+ return -ENOMEM;
+
+ memcpy(nmap, sel->map, map_sz);
+ memcpy(&dma_sel, sel, sizeof(*sel));
+
+ dma_sel.map = nmap;
+
+ for (ptr = 0; ptr < sel->map_size; ptr++)
+ s3c24xx_dma_check_entry(nmap+ptr, ptr);
+
+ return 0;
+}
diff --git a/arch/arm/mach-s3c2410/dma.h b/arch/arm/mach-s3c2410/dma.h
new file mode 100644
index 000000000000..0ebfe0aab80b
--- /dev/null
+++ b/arch/arm/mach-s3c2410/dma.h
@@ -0,0 +1,45 @@
+/* arch/arm/mach-s3c2410/dma.h
+ *
+ * Copyright (C) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Samsung S3C24XX DMA support
+ *
+ * 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.
+*/
+
+extern struct sysdev_class dma_sysclass;
+extern struct s3c2410_dma_chan s3c2410_chans[S3C2410_DMA_CHANNELS];
+
+#define DMA_CH_VALID (1<<31)
+
+struct s3c24xx_dma_addr {
+ unsigned long from;
+ unsigned long to;
+};
+
+/* struct s3c24xx_dma_map
+ *
+ * this holds the mapping information for the channel selected
+ * to be connected to the specified device
+*/
+
+struct s3c24xx_dma_map {
+ const char *name;
+ struct s3c24xx_dma_addr hw_addr;
+
+ unsigned long channels[S3C2410_DMA_CHANNELS];
+};
+
+struct s3c24xx_dma_selection {
+ struct s3c24xx_dma_map *map;
+ unsigned long map_size;
+ unsigned long dcon_mask;
+
+ void (*select)(struct s3c2410_dma_chan *chan,
+ struct s3c24xx_dma_map *map);
+};
+
+extern int s3c24xx_dma_init_map(struct s3c24xx_dma_selection *sel);
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index cd39e8684584..db6393c99860 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -18,21 +18,7 @@
* 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
- *
- * Changelog
- * 13-Sep-2004 BJD Implemented change of MISCCR
- * 14-Sep-2004 BJD Added getpin call
- * 14-Sep-2004 BJD Fixed bug in setpin() call
- * 30-Sep-2004 BJD Fixed cfgpin() mask bug
- * 01-Oct-2004 BJD Added getcfg() to get pin configuration
- * 01-Oct-2004 BJD Fixed mask bug in pullup() call
- * 01-Oct-2004 BJD Added getirq() to turn pin into irqno
- * 04-Oct-2004 BJD Added irq filter controls for GPIO
- * 05-Nov-2004 BJD EXPORT_SYMBOL() added for all code
- * 13-Mar-2005 BJD Updates for __iomem
- * 26-Oct-2005 BJD Added generic configuration types
- * 15-Jan-2006 LCVR Added support for the S3C2400
- */
+*/
#include <linux/kernel.h>
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index cd6139b35999..683b3491ba3c 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -181,17 +181,19 @@ s3c_irq_unmask(unsigned int irqno)
}
struct irqchip s3c_irq_level_chip = {
- .ack = s3c_irq_maskack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake
+ .name = "s3c-level",
+ .ack = s3c_irq_maskack,
+ .mask = s3c_irq_mask,
+ .unmask = s3c_irq_unmask,
+ .set_wake = s3c_irq_wake
};
static struct irqchip s3c_irq_chip = {
- .ack = s3c_irq_ack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake
+ .name = "s3c",
+ .ack = s3c_irq_ack,
+ .mask = s3c_irq_mask,
+ .unmask = s3c_irq_unmask,
+ .set_wake = s3c_irq_wake
};
static void
@@ -343,19 +345,21 @@ s3c_irqext_type(unsigned int irq, unsigned int type)
}
static struct irqchip s3c_irqext_chip = {
- .mask = s3c_irqext_mask,
- .unmask = s3c_irqext_unmask,
- .ack = s3c_irqext_ack,
- .set_type = s3c_irqext_type,
- .set_wake = s3c_irqext_wake
+ .name = "s3c-ext",
+ .mask = s3c_irqext_mask,
+ .unmask = s3c_irqext_unmask,
+ .ack = s3c_irqext_ack,
+ .set_type = s3c_irqext_type,
+ .set_wake = s3c_irqext_wake
};
static struct irqchip s3c_irq_eint0t4 = {
- .ack = s3c_irq_ack,
- .mask = s3c_irq_mask,
- .unmask = s3c_irq_unmask,
- .set_wake = s3c_irq_wake,
- .set_type = s3c_irqext_type,
+ .name = "s3c-ext0",
+ .ack = s3c_irq_ack,
+ .mask = s3c_irq_mask,
+ .unmask = s3c_irq_unmask,
+ .set_wake = s3c_irq_wake,
+ .set_type = s3c_irqext_type,
};
/* mask values for the parent registers for each of the interrupt types */
@@ -387,9 +391,10 @@ s3c_irq_uart0_ack(unsigned int irqno)
}
static struct irqchip s3c_irq_uart0 = {
- .mask = s3c_irq_uart0_mask,
- .unmask = s3c_irq_uart0_unmask,
- .ack = s3c_irq_uart0_ack,
+ .name = "s3c-uart0",
+ .mask = s3c_irq_uart0_mask,
+ .unmask = s3c_irq_uart0_unmask,
+ .ack = s3c_irq_uart0_ack,
};
/* UART1 */
@@ -413,9 +418,10 @@ s3c_irq_uart1_ack(unsigned int irqno)
}
static struct irqchip s3c_irq_uart1 = {
- .mask = s3c_irq_uart1_mask,
- .unmask = s3c_irq_uart1_unmask,
- .ack = s3c_irq_uart1_ack,
+ .name = "s3c-uart1",
+ .mask = s3c_irq_uart1_mask,
+ .unmask = s3c_irq_uart1_unmask,
+ .ack = s3c_irq_uart1_ack,
};
/* UART2 */
@@ -439,9 +445,10 @@ s3c_irq_uart2_ack(unsigned int irqno)
}
static struct irqchip s3c_irq_uart2 = {
- .mask = s3c_irq_uart2_mask,
- .unmask = s3c_irq_uart2_unmask,
- .ack = s3c_irq_uart2_ack,
+ .name = "s3c-uart2",
+ .mask = s3c_irq_uart2_mask,
+ .unmask = s3c_irq_uart2_unmask,
+ .ack = s3c_irq_uart2_ack,
};
/* ADC and Touchscreen */
@@ -465,15 +472,15 @@ s3c_irq_adc_ack(unsigned int irqno)
}
static struct irqchip s3c_irq_adc = {
- .mask = s3c_irq_adc_mask,
- .unmask = s3c_irq_adc_unmask,
- .ack = s3c_irq_adc_ack,
+ .name = "s3c-adc",
+ .mask = s3c_irq_adc_mask,
+ .unmask = s3c_irq_adc_unmask,
+ .ack = s3c_irq_adc_ack,
};
/* irq demux for adc */
static void s3c_irq_demux_adc(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+ struct irqdesc *desc)
{
unsigned int subsrc, submsk;
unsigned int offset = 9;
@@ -492,17 +499,16 @@ static void s3c_irq_demux_adc(unsigned int irq,
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_TC;
- desc_handle_irq(IRQ_TC, mydesc, regs);
+ desc_handle_irq(IRQ_TC, mydesc);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_ADC;
- desc_handle_irq(IRQ_ADC, mydesc, regs);
+ desc_handle_irq(IRQ_ADC, mydesc);
}
}
}
-static void s3c_irq_demux_uart(unsigned int start,
- struct pt_regs *regs)
+static void s3c_irq_demux_uart(unsigned int start)
{
unsigned int subsrc, submsk;
unsigned int offset = start - IRQ_S3CUART_RX0;
@@ -525,17 +531,17 @@ static void s3c_irq_demux_uart(unsigned int start,
desc = irq_desc + start;
if (subsrc & 1)
- desc_handle_irq(start, desc, regs);
+ desc_handle_irq(start, desc);
desc++;
if (subsrc & 2)
- desc_handle_irq(start+1, desc, regs);
+ desc_handle_irq(start+1, desc);
desc++;
if (subsrc & 4)
- desc_handle_irq(start+2, desc, regs);
+ desc_handle_irq(start+2, desc);
}
}
@@ -543,49 +549,125 @@ static void s3c_irq_demux_uart(unsigned int start,
static void
s3c_irq_demux_uart0(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+ struct irqdesc *desc)
{
irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX0, regs);
+ s3c_irq_demux_uart(IRQ_S3CUART_RX0);
}
static void
s3c_irq_demux_uart1(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+ struct irqdesc *desc)
{
irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX1, regs);
+ s3c_irq_demux_uart(IRQ_S3CUART_RX1);
}
static void
s3c_irq_demux_uart2(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+ struct irqdesc *desc)
{
irq = irq;
- s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
+ s3c_irq_demux_uart(IRQ_S3CUART_RX2);
}
static void
-s3c_irq_demux_extint(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+s3c_irq_demux_extint8(unsigned int irq,
+ struct irqdesc *desc)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
+ eintpnd &= ~0xff; /* ignore lower irqs */
- if (eintpnd) {
- irq = fls(eintpnd);
- irq += (IRQ_EINT4 - (4 + 1));
+ /* we may as well handle all the pending IRQs here */
- desc_handle_irq(irq, irq_desc + irq, regs);
+ while (eintpnd) {
+ irq = __ffs(eintpnd);
+ eintpnd &= ~(1<<irq);
+
+ irq += (IRQ_EINT4 - 4);
+ desc_handle_irq(irq, irq_desc + irq);
}
+
}
+static void
+s3c_irq_demux_extint4t7(unsigned int irq,
+ struct irqdesc *desc)
+{
+ unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
+ unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
+
+ eintpnd &= ~eintmsk;
+ eintpnd &= 0xff; /* only lower irqs */
+
+ /* we may as well handle all the pending IRQs here */
+
+ while (eintpnd) {
+ irq = __ffs(eintpnd);
+ eintpnd &= ~(1<<irq);
+
+ irq += (IRQ_EINT4 - 4);
+
+ desc_handle_irq(irq, irq_desc + irq);
+ }
+}
+
+#ifdef CONFIG_PM
+
+static struct sleep_save irq_save[] = {
+ SAVE_ITEM(S3C2410_INTMSK),
+ SAVE_ITEM(S3C2410_INTSUBMSK),
+};
+
+/* the extint values move between the s3c2410/s3c2440 and the s3c2412
+ * so we use an array to hold them, and to calculate the address of
+ * the register at run-time
+*/
+
+static unsigned long save_extint[3];
+static unsigned long save_eintflt[4];
+static unsigned long save_eintmask;
+
+int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(save_extint); i++)
+ save_extint[i] = __raw_readl(S3C24XX_EXTINT0 + (i*4));
+
+ for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
+ save_eintflt[i] = __raw_readl(S3C24XX_EINFLT0 + (i*4));
+
+ s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
+ save_eintmask = __raw_readl(S3C24XX_EINTMASK);
+
+ return 0;
+}
+
+int s3c24xx_irq_resume(struct sys_device *dev)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(save_extint); i++)
+ __raw_writel(save_extint[i], S3C24XX_EXTINT0 + (i*4));
+
+ for (i = 0; i < ARRAY_SIZE(save_eintflt); i++)
+ __raw_writel(save_eintflt[i], S3C24XX_EINFLT0 + (i*4));
+
+ s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
+ __raw_writel(save_eintmask, S3C24XX_EINTMASK);
+
+ return 0;
+}
+
+#else
+#define s3c24xx_irq_suspend NULL
+#define s3c24xx_irq_resume NULL
+#endif
+
/* s3c24xx_init_irq
*
* Initialise S3C2410 IRQ system
@@ -674,8 +756,8 @@ void __init s3c24xx_init_irq(void)
/* setup the cascade irq handlers */
- set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint);
- set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint);
+ set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
+ set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
diff --git a/arch/arm/mach-s3c2410/mach-amlm5900.c b/arch/arm/mach-s3c2410/mach-amlm5900.c
new file mode 100644
index 000000000000..817e2c684410
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-amlm5900.c
@@ -0,0 +1,266 @@
+/***********************************************************************
+ *
+ * linux/arch/arm/mach-s3c2410/mach-amlm5900.c
+ *
+ * Copyright (c) 2006 American Microsystems Limited
+ * David Anders <danders@amltd.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
+ *
+ * @History:
+ * derived from linux/arch/arm/mach-s3c2410/mach-bast.c, written by
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ ***********************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/proc_fs.h>
+
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/flash.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+#include <asm/arch/fb.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "devs.h"
+#include "cpu.h"
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/physmap.h>
+
+static struct resource amlm5900_nor_resource = {
+ .start = 0x00000000,
+ .end = 0x01000000 - 1,
+ .flags = IORESOURCE_MEM,
+};
+
+
+
+static struct mtd_partition amlm5900_mtd_partitions[] = {
+ {
+ .name = "System",
+ .size = 0x240000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE, /* force read-only */
+ }, {
+ .name = "Kernel",
+ .size = 0x100000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "Ramdisk",
+ .size = 0x300000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "JFFS2",
+ .size = 0x9A0000,
+ .offset = MTDPART_OFS_APPEND,
+ }, {
+ .name = "Settings",
+ .size = MTDPART_SIZ_FULL,
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+static struct physmap_flash_data amlm5900_flash_data = {
+ .width = 2,
+ .parts = amlm5900_mtd_partitions,
+ .nr_parts = ARRAY_SIZE(amlm5900_mtd_partitions),
+};
+
+static struct platform_device amlm5900_device_nor = {
+ .name = "physmap-flash",
+ .id = 0,
+ .dev = {
+ .platform_data = &amlm5900_flash_data,
+ },
+ .num_resources = 1,
+ .resource = &amlm5900_nor_resource,
+};
+#endif
+
+static struct map_desc amlm5900_iodesc[] __initdata = {
+ {
+ .virtual = (u32)S3C24XX_VA_SPI,
+ .pfn = __phys_to_pfn(S3C2410_PA_SPI),
+ .length = SZ_1M,
+ .type = MT_DEVICE
+ }
+};
+
+#define UCON S3C2410_UCON_DEFAULT
+#define ULCON S3C2410_LCON_CS8 | S3C2410_LCON_PNONE | S3C2410_LCON_STOPB
+#define UFCON S3C2410_UFCON_RXTRIG8 | S3C2410_UFCON_FIFOMODE
+
+static struct s3c2410_uartcfg amlm5900_uartcfgs[] = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ },
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = UCON,
+ .ulcon = ULCON,
+ .ufcon = UFCON,
+ }
+};
+
+
+static struct platform_device *amlm5900_devices[] __initdata = {
+#ifdef CONFIG_FB_S3C2410
+ &s3c_device_lcd,
+#endif
+ &s3c_device_adc,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_usb,
+ &s3c_device_rtc,
+ &s3c_device_usbgadget,
+ &s3c_device_sdi,
+#ifdef CONFIG_MTD_PARTITIONS
+ &amlm5900_device_nor,
+#endif
+};
+
+static struct s3c24xx_board amlm5900_board __initdata = {
+ .devices = amlm5900_devices,
+ .devices_count = ARRAY_SIZE(amlm5900_devices)
+};
+
+void __init amlm5900_map_io(void)
+{
+ s3c24xx_init_io(amlm5900_iodesc, ARRAY_SIZE(amlm5900_iodesc));
+ s3c24xx_init_clocks(0);
+ s3c24xx_init_uarts(amlm5900_uartcfgs, ARRAY_SIZE(amlm5900_uartcfgs));
+ s3c24xx_set_board(&amlm5900_board);
+}
+
+#ifdef CONFIG_FB_S3C2410
+static struct s3c2410fb_mach_info __initdata amlm5900_lcd_info = {
+ .width = 160,
+ .height = 160,
+
+/* commented out until stn patch is submitted
+* .type = S3C2410_LCDCON1_STN4,
+*/
+ .gpccon = 0xaaaaaaaa,
+ .gpccon_mask = 0xffffffff,
+ .gpcup = 0x0000ffff,
+ .gpcup_mask = 0xffffffff,
+
+ .gpdcon = 0xaaaaaaaa,
+ .gpdcon_mask = 0xffffffff,
+ .gpdup = 0x0000ffff,
+ .gpdup_mask = 0xffffffff,
+
+ .xres = {
+ .min = 160,
+ .max = 160,
+ .defval = 160,
+ },
+
+ .yres = {
+ .min = 160,
+ .max = 160,
+ .defval = 160,
+ },
+
+ .bpp = {
+ .min = 4,
+ .max = 4,
+ .defval = 4,
+ },
+
+ .regs = {
+ .lcdcon1 = 0x00008225,
+ .lcdcon2 = 0x0027c000,
+ .lcdcon3 = 0x00182708,
+ .lcdcon4 = 0x00000002,
+ .lcdcon5 = 0x00000001,
+ }
+};
+#endif
+
+static irqreturn_t
+amlm5900_wake_interrupt(int irq, void *ignored)
+{
+ return IRQ_HANDLED;
+}
+
+static void amlm5900_init_pm(void)
+{
+ int ret = 0;
+
+ ret = request_irq(IRQ_EINT9, &amlm5900_wake_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_SHARED,
+ "amlm5900_wakeup", &amlm5900_wake_interrupt);
+ if (ret != 0) {
+ printk(KERN_ERR "AML-M5900: no wakeup irq, %d?\n", ret);
+ } else {
+ enable_irq_wake(IRQ_EINT9);
+ /* configure the suspend/resume status pin */
+ s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_OUTP);
+ s3c2410_gpio_pullup(S3C2410_GPF2, 0);
+ }
+}
+static void __init amlm5900_init(void)
+{
+ amlm5900_init_pm();
+#ifdef CONFIG_FB_S3C2410
+ s3c24xx_fb_set_platdata(&amlm5900_lcd_info);
+#endif
+}
+
+MACHINE_START(AML_M5900, "AML_M5900")
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = amlm5900_map_io,
+ .init_irq = s3c24xx_init_irq,
+ .init_machine = amlm5900_init,
+ .timer = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-anubis.c b/arch/arm/mach-s3c2410/mach-anubis.c
index 60641d452db3..e94cdcd96591 100644
--- a/arch/arm/mach-s3c2410/mach-anubis.c
+++ b/arch/arm/mach-s3c2410/mach-anubis.c
@@ -4,15 +4,9 @@
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
- *
- *
* 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.
- *
- * Modifications:
- * 02-May-2005 BJD Copied from mach-bast.c
- * 20-Sep-2005 BJD Added static to non-exported items
*/
#include <linux/kernel.h>
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
index d661c6b7ff56..e2205ff1b0ee 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -11,15 +11,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * Modifications:
- * 01-Nov-2004 BJD Initial version
- * 12-Nov-2004 BJD Updated for release
- * 04-Jan-2005 BJD Fixes for pre-release
- * 22-Feb-2005 BJD Updated for 2.6.11-rc5 relesa
- * 10-Mar-2005 LCVR Replaced S3C2410_VA by S3C24XX_VA
- * 14-Mar-2005 BJD void __iomem fixes
- * 20-Sep-2005 BJD Added static to non-exported items
- * 26-Oct-2005 BJD Added framebuffer data
*/
#include <linux/kernel.h>
diff --git a/arch/arm/mach-s3c2410/mach-vstms.c b/arch/arm/mach-s3c2410/mach-vstms.c
new file mode 100644
index 000000000000..ea554e7c006e
--- /dev/null
+++ b/arch/arm/mach-s3c2410/mach-vstms.c
@@ -0,0 +1,168 @@
+/* linux/arch/arm/mach-s3c2410/mach-vstms.c
+ *
+ * (C) 2006 Thomas Gleixner <tglx@linutronix.de>
+ *
+ * Derived from mach-smdk2413.c - (C) 2006 Simtec Electronics
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/hardware.h>
+#include <asm/hardware/iomd.h>
+#include <asm/setup.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-lcd.h>
+
+#include <asm/arch/idle.h>
+#include <asm/arch/fb.h>
+
+#include <asm/arch/nand.h>
+
+#include "s3c2410.h"
+#include "s3c2412.h"
+#include "clock.h"
+#include "devs.h"
+#include "cpu.h"
+
+
+static struct map_desc vstms_iodesc[] __initdata = {
+};
+
+static struct s3c2410_uartcfg vstms_uartcfgs[] __initdata = {
+ [0] = {
+ .hwport = 0,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ [1] = {
+ .hwport = 1,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ },
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+ .ucon = 0x3c5,
+ .ulcon = 0x03,
+ .ufcon = 0x51,
+ }
+};
+
+static struct mtd_partition vstms_nand_part[] = {
+ [0] = {
+ .name = "Boot Agent",
+ .size = 0x7C000,
+ .offset = 0,
+ },
+ [1] = {
+ .name = "UBoot Config",
+ .offset = 0x7C000,
+ .size = 0x4000,
+ },
+ [2] = {
+ .name = "Kernel",
+ .offset = 0x80000,
+ .size = 0x200000,
+ },
+ [3] = {
+ .name = "RFS",
+ .offset = 0x280000,
+ .size = 0x3d80000,
+ },
+};
+
+static struct s3c2410_nand_set vstms_nand_sets[] = {
+ [0] = {
+ .name = "NAND",
+ .nr_chips = 1,
+ .nr_partitions = ARRAY_SIZE(vstms_nand_part),
+ .partitions = vstms_nand_part,
+ },
+};
+
+/* choose a set of timings which should suit most 512Mbit
+ * chips and beyond.
+*/
+
+static struct s3c2410_platform_nand vstms_nand_info = {
+ .tacls = 20,
+ .twrph0 = 60,
+ .twrph1 = 20,
+ .nr_sets = ARRAY_SIZE(vstms_nand_sets),
+ .sets = vstms_nand_sets,
+};
+
+static struct platform_device *vstms_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+ &s3c_device_rtc,
+ &s3c_device_nand,
+};
+
+static struct s3c24xx_board vstms_board __initdata = {
+ .devices = vstms_devices,
+ .devices_count = ARRAY_SIZE(vstms_devices)
+};
+
+static void __init vstms_fixup(struct machine_desc *desc,
+ struct tag *tags, char **cmdline,
+ struct meminfo *mi)
+{
+ if (tags != phys_to_virt(S3C2410_SDRAM_PA + 0x100)) {
+ mi->nr_banks=1;
+ mi->bank[0].start = 0x30000000;
+ mi->bank[0].size = SZ_64M;
+ mi->bank[0].node = 0;
+ }
+}
+
+static void __init vstms_map_io(void)
+{
+ s3c_device_nand.dev.platform_data = &vstms_nand_info;
+
+ s3c24xx_init_io(vstms_iodesc, ARRAY_SIZE(vstms_iodesc));
+ s3c24xx_init_clocks(12000000);
+ s3c24xx_init_uarts(vstms_uartcfgs, ARRAY_SIZE(vstms_uartcfgs));
+ s3c24xx_set_board(&vstms_board);
+}
+
+MACHINE_START(VSTMS, "VSTMS")
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+
+ .fixup = vstms_fixup,
+ .init_irq = s3c24xx_init_irq,
+ .map_io = vstms_map_io,
+ .timer = &s3c24xx_timer,
+MACHINE_END
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
index 7b244566a436..42cd05e298f8 100644
--- a/arch/arm/mach-s3c2410/pm-simtec.c
+++ b/arch/arm/mach-s3c2410/pm-simtec.c
@@ -49,7 +49,8 @@ static __init int pm_simtec_init(void)
/* check which machine we are running on */
if (!machine_is_bast() && !machine_is_vr1000() &&
- !machine_is_anubis() && !machine_is_osiris())
+ !machine_is_anubis() && !machine_is_osiris() &&
+ !machine_is_aml_m5900())
return 0;
printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
diff --git a/arch/arm/mach-s3c2410/pm.c b/arch/arm/mach-s3c2410/pm.c
index a589fe76d915..b49a0b3b72b3 100644
--- a/arch/arm/mach-s3c2410/pm.c
+++ b/arch/arm/mach-s3c2410/pm.c
@@ -1,9 +1,9 @@
/* linux/arch/arm/mach-s3c2410/pm.c
*
- * Copyright (c) 2004 Simtec Electronics
+ * Copyright (c) 2004,2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
*
- * S3C2410 Power Manager (Suspend-To-RAM) support
+ * S3C24XX Power Manager (Suspend-To-RAM) support
*
* See Documentation/arm/Samsung-S3C24XX/Suspend.txt for more information
*
@@ -24,9 +24,6 @@
* Parts based on arch/arm/mach-pxa/pm.c
*
* Thanks to Dimitry Andric for debugging
- *
- * Modifications:
- * 10-Mar-2005 LCVR Changed S3C2410_VA_UART to S3C24XX_VA_UART
*/
#include <linux/init.h>
@@ -38,6 +35,7 @@
#include <linux/ioport.h>
#include <linux/delay.h>
+#include <asm/cacheflush.h>
#include <asm/hardware.h>
#include <asm/io.h>
@@ -55,14 +53,6 @@
unsigned long s3c_pm_flags;
-/* cache functions from arch/arm/mm/proc-arm920.S */
-
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
-extern void arm920_flush_kern_cache_all(void);
-#else
-static void arm920_flush_kern_cache_all(void) { }
-#endif
-
#define PFX "s3c24xx-pm: "
static struct sleep_save core_save[] = {
@@ -92,19 +82,6 @@ static struct sleep_save core_save[] = {
SAVE_ITEM(S3C2410_REFRESH),
};
-/* this lot should be really saved by the IRQ code */
-static struct sleep_save irq_save[] = {
- SAVE_ITEM(S3C2410_EXTINT0),
- SAVE_ITEM(S3C2410_EXTINT1),
- SAVE_ITEM(S3C2410_EXTINT2),
- SAVE_ITEM(S3C2410_EINFLT0),
- SAVE_ITEM(S3C2410_EINFLT1),
- SAVE_ITEM(S3C2410_EINFLT2),
- SAVE_ITEM(S3C2410_EINFLT3),
- SAVE_ITEM(S3C2410_EINTMASK),
- SAVE_ITEM(S3C2410_INTMSK)
-};
-
static struct sleep_save gpio_save[] = {
SAVE_ITEM(S3C2410_GPACON),
SAVE_ITEM(S3C2410_GPADAT),
@@ -165,7 +142,7 @@ static struct sleep_save uart_save[] = {
extern void printascii(const char *);
-static void pm_dbg(const char *fmt, ...)
+void pm_dbg(const char *fmt, ...)
{
va_list va;
char buff[256];
@@ -509,6 +486,9 @@ static void s3c2410_pm_configure_extint(void)
}
}
+void (*pm_cpu_prep)(void);
+void (*pm_cpu_sleep)(void);
+
#define any_allowed(mask, allow) (((mask) & (allow)) != (allow))
/* s3c2410_pm_enter
@@ -519,7 +499,6 @@ static void s3c2410_pm_configure_extint(void)
static int s3c2410_pm_enter(suspend_state_t state)
{
unsigned long regs_save[16];
- unsigned long tmp;
/* ensure the debug is initialised (if enabled) */
@@ -527,6 +506,11 @@ static int s3c2410_pm_enter(suspend_state_t state)
DBG("s3c2410_pm_enter(%d)\n", state);
+ if (pm_cpu_prep == NULL || pm_cpu_sleep == NULL) {
+ printk(KERN_ERR PFX "error: no cpu sleep functions set\n");
+ return -EINVAL;
+ }
+
if (state != PM_SUSPEND_MEM) {
printk(KERN_ERR PFX "error: only PM_SUSPEND_MEM supported\n");
return -EINVAL;
@@ -554,17 +538,9 @@ static int s3c2410_pm_enter(suspend_state_t state)
DBG("s3c2410_sleep_save_phys=0x%08lx\n", s3c2410_sleep_save_phys);
- /* ensure at least GESTATUS3 has the resume address */
-
- __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
-
- DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
- DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
-
/* save all necessary core registers not covered by the drivers */
s3c2410_pm_do_save(gpio_save, ARRAY_SIZE(gpio_save));
- s3c2410_pm_do_save(irq_save, ARRAY_SIZE(irq_save));
s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
@@ -581,10 +557,16 @@ static int s3c2410_pm_enter(suspend_state_t state)
/* ack any outstanding external interrupts before we go to sleep */
__raw_writel(__raw_readl(S3C2410_EINTPEND), S3C2410_EINTPEND);
+ __raw_writel(__raw_readl(S3C2410_INTPND), S3C2410_INTPND);
+ __raw_writel(__raw_readl(S3C2410_SRCPND), S3C2410_SRCPND);
+
+ /* call cpu specific preperation */
+
+ pm_cpu_prep();
/* flush cache back to ram */
- arm920_flush_kern_cache_all();
+ flush_cache_all();
s3c2410_pm_check_store();
@@ -592,23 +574,23 @@ static int s3c2410_pm_enter(suspend_state_t state)
__raw_writel(0x00, S3C2410_CLKCON); /* turn off clocks over sleep */
- s3c2410_cpu_suspend(regs_save);
+ /* s3c2410_cpu_save will also act as our return point from when
+ * we resume as it saves its own register state, so use the return
+ * code to differentiate return from save and return from sleep */
+
+ if (s3c2410_cpu_save(regs_save) == 0) {
+ flush_cache_all();
+ pm_cpu_sleep();
+ }
/* restore the cpu state */
cpu_init();
- /* unset the return-from-sleep flag, to ensure reset */
-
- tmp = __raw_readl(S3C2410_GSTATUS2);
- tmp &= S3C2410_GSTATUS2_OFFRESET;
- __raw_writel(tmp, S3C2410_GSTATUS2);
-
/* restore the system state */
s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
s3c2410_pm_do_restore(gpio_save, ARRAY_SIZE(gpio_save));
- s3c2410_pm_do_restore(irq_save, ARRAY_SIZE(irq_save));
s3c2410_pm_do_restore(uart_save, ARRAY_SIZE(uart_save));
s3c2410_pm_debug_init();
diff --git a/arch/arm/mach-s3c2410/pm.h b/arch/arm/mach-s3c2410/pm.h
index 7a5e714c7386..ffe197a119fb 100644
--- a/arch/arm/mach-s3c2410/pm.h
+++ b/arch/arm/mach-s3c2410/pm.h
@@ -34,13 +34,19 @@ extern unsigned long s3c_irqwake_eintmask;
extern unsigned long s3c_irqwake_intallow;
extern unsigned long s3c_irqwake_eintallow;
+/* per-cpu sleep functions */
+
+extern void (*pm_cpu_prep)(void);
+extern void (*pm_cpu_sleep)(void);
+
/* Flags for PM Control */
extern unsigned long s3c_pm_flags;
/* from sleep.S */
-extern void s3c2410_cpu_suspend(unsigned long *saveblk);
+extern int s3c2410_cpu_save(unsigned long *saveblk);
+extern void s3c2410_cpu_suspend(void);
extern void s3c2410_cpu_resume(void);
extern unsigned long s3c2410_sleep_save_phys;
@@ -57,3 +63,11 @@ struct sleep_save {
extern void s3c2410_pm_do_save(struct sleep_save *ptr, int count);
extern void s3c2410_pm_do_restore(struct sleep_save *ptr, int count);
+
+#ifdef CONFIG_PM
+extern int s3c24xx_irq_suspend(struct sys_device *dev, pm_message_t state);
+extern int s3c24xx_irq_resume(struct sys_device *dev);
+#else
+#define s3c24xx_irq_suspend NULL
+#define s3c24xx_irq_resume NULL
+#endif
diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2410/s3c2400-gpio.c
index f2a78175a70a..1576d01d5f82 100644
--- a/arch/arm/mach-s3c2410/s3c2400-gpio.c
+++ b/arch/arm/mach-s3c2410/s3c2400-gpio.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/gpio.c
+/* linux/arch/arm/mach-s3c2410/s3c2400-gpio.c
*
* Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org>
*
diff --git a/arch/arm/mach-s3c2410/s3c2410-clock.c b/arch/arm/mach-s3c2410/s3c2410-clock.c
index 99718663318e..00abe199a08e 100644
--- a/arch/arm/mach-s3c2410/s3c2410-clock.c
+++ b/arch/arm/mach-s3c2410/s3c2410-clock.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/clock.c
+/* linux/arch/arm/mach-s3c2410/s3c2410-clock.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2410-dma.c b/arch/arm/mach-s3c2410/s3c2410-dma.c
new file mode 100644
index 000000000000..51e5098b32e8
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410-dma.c
@@ -0,0 +1,158 @@
+/* linux/arch/arm/mach-s3c2410/s3c2410-dma.c
+ *
+ * (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+#include "dma.h"
+
+#include "cpu.h"
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-sdi.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-spi.h>
+
+static struct s3c24xx_dma_map __initdata s3c2410_dma_mappings[] = {
+ [DMACH_XD0] = {
+ .name = "xdreq0",
+ .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
+ },
+ [DMACH_XD1] = {
+ .name = "xdreq1",
+ .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
+ },
+ [DMACH_SDI] = {
+ .name = "sdi",
+ .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
+ .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_SPI0] = {
+ .name = "spi0",
+ .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
+ },
+ [DMACH_SPI1] = {
+ .name = "spi1",
+ .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
+ },
+ [DMACH_UART0] = {
+ .name = "uart0",
+ .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
+ },
+ [DMACH_UART1] = {
+ .name = "uart1",
+ .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
+ },
+ [DMACH_UART2] = {
+ .name = "uart2",
+ .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
+ },
+ [DMACH_TIMER] = {
+ .name = "timer",
+ .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
+ .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
+ },
+ [DMACH_I2S_IN] = {
+ .name = "i2s-sdi",
+ .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_I2S_OUT] = {
+ .name = "i2s-sdo",
+ .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_USB_EP1] = {
+ .name = "usb-ep1",
+ .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP2] = {
+ .name = "usb-ep2",
+ .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP3] = {
+ .name = "usb-ep3",
+ .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP4] = {
+ .name = "usb-ep4",
+ .channels[3] =S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
+ },
+};
+
+static void s3c2410_dma_select(struct s3c2410_dma_chan *chan,
+ struct s3c24xx_dma_map *map)
+{
+ chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2410_dma_sel = {
+ .select = s3c2410_dma_select,
+ .dcon_mask = 7 << 24,
+ .map = s3c2410_dma_mappings,
+ .map_size = ARRAY_SIZE(s3c2410_dma_mappings),
+};
+
+static int s3c2410_dma_add(struct sys_device *sysdev)
+{
+ return s3c24xx_dma_init_map(&s3c2410_dma_sel);
+}
+
+static struct sysdev_driver s3c2410_dma_driver = {
+ .add = s3c2410_dma_add,
+};
+
+static int __init s3c2410_dma_init(void)
+{
+ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_dma_driver);
+}
+
+arch_initcall(s3c2410_dma_init);
+
+/* S3C2442 DMA contains the same selection table as the S3C2410 */
+
+static struct sysdev_driver s3c2442_dma_driver = {
+ .add = s3c2410_dma_add,
+};
+
+static int __init s3c2442_dma_init(void)
+{
+ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_dma_driver);
+}
+
+arch_initcall(s3c2442_dma_init);
+
+
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
index 471a71490010..a2098f692d83 100644
--- a/arch/arm/mach-s3c2410/s3c2410-gpio.c
+++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/gpio.c
+/* linux/arch/arm/mach-s3c2410/s3c2410-gpio.c
*
* Copyright (c) 2004-2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c2410-irq.c b/arch/arm/mach-s3c2410/s3c2410-irq.c
new file mode 100644
index 000000000000..c796c9c76e78
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410-irq.c
@@ -0,0 +1,48 @@
+/* linux/arch/arm/mach-s3c2410/s3c2410-irq.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include "cpu.h"
+#include "pm.h"
+
+static int s3c2410_irq_add(struct sys_device *sysdev)
+{
+ return 0;
+}
+
+static struct sysdev_driver s3c2410_irq_driver = {
+ .add = s3c2410_irq_add,
+ .suspend = s3c24xx_irq_suspend,
+ .resume = s3c24xx_irq_resume,
+};
+
+static int s3c2410_irq_init(void)
+{
+ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_irq_driver);
+}
+
+arch_initcall(s3c2410_irq_init);
diff --git a/arch/arm/mach-s3c2410/s3c2410-pm.c b/arch/arm/mach-s3c2410/s3c2410-pm.c
new file mode 100644
index 000000000000..e51d76669512
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410-pm.c
@@ -0,0 +1,120 @@
+/* linux/arch/arm/mach-s3c2410/s3c2410-pm.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 (and compatible) Power Manager (Suspend-To-RAM) support
+ *
+ * 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/init.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/mach-types.h>
+
+#include <asm/arch/regs-gpio.h>
+
+#include "cpu.h"
+#include "pm.h"
+
+#ifdef CONFIG_S3C2410_PM_DEBUG
+extern void pm_dbg(const char *fmt, ...);
+#define DBG(fmt...) pm_dbg(fmt)
+#else
+#define DBG(fmt...) printk(KERN_DEBUG fmt)
+#endif
+
+static void s3c2410_pm_prepare(void)
+{
+ /* ensure at least GSTATUS3 has the resume address */
+
+ __raw_writel(virt_to_phys(s3c2410_cpu_resume), S3C2410_GSTATUS3);
+
+ DBG("GSTATUS3 0x%08x\n", __raw_readl(S3C2410_GSTATUS3));
+ DBG("GSTATUS4 0x%08x\n", __raw_readl(S3C2410_GSTATUS4));
+
+ if ( machine_is_aml_m5900() )
+ s3c2410_gpio_setpin(S3C2410_GPF2, 1);
+
+}
+
+int s3c2410_pm_resume(struct sys_device *dev)
+{
+ unsigned long tmp;
+
+ /* unset the return-from-sleep flag, to ensure reset */
+
+ tmp = __raw_readl(S3C2410_GSTATUS2);
+ tmp &= S3C2410_GSTATUS2_OFFRESET;
+ __raw_writel(tmp, S3C2410_GSTATUS2);
+
+ if ( machine_is_aml_m5900() )
+ s3c2410_gpio_setpin(S3C2410_GPF2, 0);
+
+ return 0;
+}
+
+static int s3c2410_pm_add(struct sys_device *dev)
+{
+ pm_cpu_prep = s3c2410_pm_prepare;
+ pm_cpu_sleep = s3c2410_cpu_suspend;
+
+ return 0;
+}
+
+static struct sysdev_driver s3c2410_pm_driver = {
+ .add = s3c2410_pm_add,
+ .resume = s3c2410_pm_resume,
+};
+
+/* register ourselves */
+
+static int __init s3c2410_pm_drvinit(void)
+{
+ return sysdev_driver_register(&s3c2410_sysclass, &s3c2410_pm_driver);
+}
+
+arch_initcall(s3c2410_pm_drvinit);
+
+static struct sysdev_driver s3c2440_pm_driver = {
+ .add = s3c2410_pm_add,
+ .resume = s3c2410_pm_resume,
+};
+
+static int __init s3c2440_pm_drvinit(void)
+{
+ return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_pm_driver);
+}
+
+arch_initcall(s3c2440_pm_drvinit);
+
+static struct sysdev_driver s3c2442_pm_driver = {
+ .add = s3c2410_pm_add,
+ .resume = s3c2410_pm_resume,
+};
+
+static int __init s3c2442_pm_drvinit(void)
+{
+ return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_pm_driver);
+}
+
+arch_initcall(s3c2442_pm_drvinit);
diff --git a/arch/arm/mach-s3c2410/s3c2410-sleep.S b/arch/arm/mach-s3c2410/s3c2410-sleep.S
new file mode 100644
index 000000000000..9179a1024588
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410-sleep.S
@@ -0,0 +1,68 @@
+/* linux/arch/arm/mach-s3c2410/s3c2410-sleep.S
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 Power Manager (Suspend-To-RAM) support
+ *
+ * Based on PXA/SA1100 sleep code by:
+ * Nicolas Pitre, (c) 2002 Monta Vista Software Inc
+ * Cliff Brake, (c) 2001
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+#include <asm/arch/map.h>
+
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-serial.h>
+
+ /* s3c2410_cpu_suspend
+ *
+ * put the cpu into sleep mode
+ */
+
+ENTRY(s3c2410_cpu_suspend)
+ @@ prepare cpu to sleep
+
+ ldr r4, =S3C2410_REFRESH
+ ldr r5, =S3C24XX_MISCCR
+ ldr r6, =S3C2410_CLKCON
+ ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
+ ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
+ ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
+
+ orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
+ orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
+ orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
+
+ teq pc, #0 @ first as a trial-run to load cache
+ bl s3c2410_do_sleep
+ teq r0, r0 @ now do it for real
+ b s3c2410_do_sleep @
+
+ @@ align next bit of code to cache line
+ .align 8
+s3c2410_do_sleep:
+ streq r7, [ r4 ] @ SDRAM sleep command
+ streq r8, [ r5 ] @ SDRAM power-down config
+ streq r9, [ r6 ] @ CPU sleep
+1: beq 1b
+ mov pc, r14
diff --git a/arch/arm/mach-s3c2410/s3c2410.c b/arch/arm/mach-s3c2410/s3c2410.c
index a110cff9cf6b..183e4033ce61 100644
--- a/arch/arm/mach-s3c2410/s3c2410.c
+++ b/arch/arm/mach-s3c2410/s3c2410.c
@@ -8,17 +8,6 @@
* 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.
- *
- * Modifications:
- * 16-May-2003 BJD Created initial version
- * 16-Aug-2003 BJD Fixed header files and copyright, added URL
- * 05-Sep-2003 BJD Moved to kernel v2.6
- * 18-Jan-2004 BJD Added serial port configuration
- * 21-Aug-2004 BJD Added new struct s3c2410_board handler
- * 28-Sep-2004 BJD Updates for new serial port bits
- * 04-Nov-2004 BJD Updated UART configuration process
- * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
- * 13-Aug-2005 DA Removed UART from initial I/O mappings
*/
#include <linux/kernel.h>
diff --git a/arch/arm/mach-s3c2410/s3c2412-dma.c b/arch/arm/mach-s3c2410/s3c2412-dma.c
new file mode 100644
index 000000000000..171f3706d36d
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412-dma.c
@@ -0,0 +1,160 @@
+/* linux/arch/arm/mach-s3c2410/s3c2412-dma.c
+ *
+ * (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2412 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+#include <asm/io.h>
+
+#include "dma.h"
+#include "cpu.h"
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-sdi.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-spi.h>
+
+#define MAP(x) { (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID, (x)| DMA_CH_VALID }
+
+static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
+ [DMACH_XD0] = {
+ .name = "xdreq0",
+ .channels = MAP(S3C2412_DMAREQSEL_XDREQ0),
+ },
+ [DMACH_XD1] = {
+ .name = "xdreq1",
+ .channels = MAP(S3C2412_DMAREQSEL_XDREQ1),
+ },
+ [DMACH_SDI] = {
+ .name = "sdi",
+ .channels = MAP(S3C2412_DMAREQSEL_SDI),
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_SPI0] = {
+ .name = "spi0",
+ .channels = MAP(S3C2412_DMAREQSEL_SPI0TX),
+ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
+ },
+ [DMACH_SPI1] = {
+ .name = "spi1",
+ .channels = MAP(S3C2412_DMAREQSEL_SPI1TX),
+ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
+ },
+ [DMACH_UART0] = {
+ .name = "uart0",
+ .channels = MAP(S3C2412_DMAREQSEL_UART0_0),
+ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
+ },
+ [DMACH_UART1] = {
+ .name = "uart1",
+ .channels = MAP(S3C2412_DMAREQSEL_UART1_0),
+ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
+ },
+ [DMACH_UART2] = {
+ .name = "uart2",
+ .channels = MAP(S3C2412_DMAREQSEL_UART2_0),
+ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
+ },
+ [DMACH_UART0_SRC2] = {
+ .name = "uart0",
+ .channels = MAP(S3C2412_DMAREQSEL_UART0_1),
+ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
+ },
+ [DMACH_UART1_SRC2] = {
+ .name = "uart1",
+ .channels = MAP(S3C2412_DMAREQSEL_UART1_1),
+ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
+ },
+ [DMACH_UART2_SRC2] = {
+ .name = "uart2",
+ .channels = MAP(S3C2412_DMAREQSEL_UART2_1),
+ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
+ },
+ [DMACH_TIMER] = {
+ .name = "timer",
+ .channels = MAP(S3C2412_DMAREQSEL_TIMER),
+ },
+ [DMACH_I2S_IN] = {
+ .name = "i2s-sdi",
+ .channels = MAP(S3C2412_DMAREQSEL_I2SRX),
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_I2S_OUT] = {
+ .name = "i2s-sdo",
+ .channels = MAP(S3C2412_DMAREQSEL_I2STX),
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_USB_EP1] = {
+ .name = "usb-ep1",
+ .channels = MAP(S3C2412_DMAREQSEL_USBEP1),
+ },
+ [DMACH_USB_EP2] = {
+ .name = "usb-ep2",
+ .channels = MAP(S3C2412_DMAREQSEL_USBEP2),
+ },
+ [DMACH_USB_EP3] = {
+ .name = "usb-ep3",
+ .channels = MAP(S3C2412_DMAREQSEL_USBEP3),
+ },
+ [DMACH_USB_EP4] = {
+ .name = "usb-ep4",
+ .channels = MAP(S3C2412_DMAREQSEL_USBEP4),
+ },
+};
+
+static void s3c2412_dma_select(struct s3c2410_dma_chan *chan,
+ struct s3c24xx_dma_map *map)
+{
+ writel(chan->regs + S3C2412_DMA_DMAREQSEL,
+ map->channels[0] | S3C2412_DMAREQSEL_HW);
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2412_dma_sel = {
+ .select = s3c2412_dma_select,
+ .dcon_mask = 0,
+ .map = s3c2412_dma_mappings,
+ .map_size = ARRAY_SIZE(s3c2412_dma_mappings),
+};
+
+static int s3c2412_dma_add(struct sys_device *sysdev)
+{
+ return s3c24xx_dma_init_map(&s3c2412_dma_sel);
+}
+
+static struct sysdev_driver s3c2412_dma_driver = {
+ .add = s3c2412_dma_add,
+};
+
+static int __init s3c2412_dma_init(void)
+{
+ return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_dma_driver);
+}
+
+arch_initcall(s3c2412_dma_init);
diff --git a/arch/arm/mach-s3c2410/s3c2412-irq.c b/arch/arm/mach-s3c2410/s3c2412-irq.c
index c80ec93dfea9..7f741547658f 100644
--- a/arch/arm/mach-s3c2410/s3c2412-irq.c
+++ b/arch/arm/mach-s3c2410/s3c2412-irq.c
@@ -37,6 +37,7 @@
#include "cpu.h"
#include "irq.h"
+#include "pm.h"
/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
* having them turn up in both the INT* and the EINT* registers. Whilst
@@ -120,6 +121,8 @@ static int s3c2412_irq_add(struct sys_device *sysdev)
static struct sysdev_driver s3c2412_irq_driver = {
.add = s3c2412_irq_add,
+ .suspend = s3c24xx_irq_suspend,
+ .resume = s3c24xx_irq_resume,
};
static int s3c2412_irq_init(void)
diff --git a/arch/arm/mach-s3c2410/s3c2412-pm.c b/arch/arm/mach-s3c2410/s3c2412-pm.c
new file mode 100644
index 000000000000..19b63322d259
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412-pm.c
@@ -0,0 +1,128 @@
+/* linux/arch/arm/mach-s3c2410/s3c2412-pm.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/.
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+#include <linux/platform_device.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <asm/arch/regs-power.h>
+#include <asm/arch/regs-gpioj.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-dsc.h>
+
+#include "cpu.h"
+#include "pm.h"
+
+#include "s3c2412.h"
+
+static void s3c2412_cpu_suspend(void)
+{
+ unsigned long tmp;
+
+ /* set our standby method to sleep */
+
+ tmp = __raw_readl(S3C2412_PWRCFG);
+ tmp |= S3C2412_PWRCFG_STANDBYWFI_SLEEP;
+ __raw_writel(tmp, S3C2412_PWRCFG);
+
+ /* issue the standby signal into the pm unit. Note, we
+ * issue a write-buffer drain just in case */
+
+ tmp = 0;
+
+ asm("b 1f\n\t"
+ ".align 5\n\t"
+ "1:\n\t"
+ "mcr p15, 0, %0, c7, c10, 4\n\t"
+ "mcr p15, 0, %0, c7, c0, 4" :: "r" (tmp));
+
+ /* we should never get past here */
+
+ panic("sleep resumed to originator?");
+}
+
+static void s3c2412_pm_prepare(void)
+{
+}
+
+static int s3c2412_pm_add(struct sys_device *sysdev)
+{
+ pm_cpu_prep = s3c2412_pm_prepare;
+ pm_cpu_sleep = s3c2412_cpu_suspend;
+
+ return 0;
+}
+
+static struct sleep_save s3c2412_sleep[] = {
+ SAVE_ITEM(S3C2412_DSC0),
+ SAVE_ITEM(S3C2412_DSC1),
+ SAVE_ITEM(S3C2413_GPJDAT),
+ SAVE_ITEM(S3C2413_GPJCON),
+ SAVE_ITEM(S3C2413_GPJUP),
+
+ /* save the PWRCFG to get back to original sleep method */
+
+ SAVE_ITEM(S3C2412_PWRCFG),
+
+ /* save the sleep configuration anyway, just in case these
+ * get damaged during wakeup */
+
+ SAVE_ITEM(S3C2412_GPBSLPCON),
+ SAVE_ITEM(S3C2412_GPCSLPCON),
+ SAVE_ITEM(S3C2412_GPDSLPCON),
+ SAVE_ITEM(S3C2412_GPESLPCON),
+ SAVE_ITEM(S3C2412_GPFSLPCON),
+ SAVE_ITEM(S3C2412_GPGSLPCON),
+ SAVE_ITEM(S3C2412_GPHSLPCON),
+ SAVE_ITEM(S3C2413_GPJSLPCON),
+};
+
+static int s3c2412_pm_suspend(struct sys_device *dev, pm_message_t state)
+{
+ s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+ return 0;
+}
+
+static int s3c2412_pm_resume(struct sys_device *dev)
+{
+ unsigned long tmp;
+
+ tmp = __raw_readl(S3C2412_PWRCFG);
+ tmp &= ~S3C2412_PWRCFG_STANDBYWFI_MASK;
+ tmp |= S3C2412_PWRCFG_STANDBYWFI_IDLE;
+ __raw_writel(tmp, S3C2412_PWRCFG);
+
+ s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
+ return 0;
+}
+
+static struct sysdev_driver s3c2412_pm_driver = {
+ .add = s3c2412_pm_add,
+ .suspend = s3c2412_pm_suspend,
+ .resume = s3c2412_pm_resume,
+};
+
+static __init int s3c2412_pm_init(void)
+{
+ return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_pm_driver);
+}
+
+arch_initcall(s3c2412_pm_init);
diff --git a/arch/arm/mach-s3c2410/s3c2412.c b/arch/arm/mach-s3c2410/s3c2412.c
index 2d163f7600be..e76431c41461 100644
--- a/arch/arm/mach-s3c2410/s3c2412.c
+++ b/arch/arm/mach-s3c2410/s3c2412.c
@@ -8,17 +8,6 @@
* 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.
- *
- * Modifications:
- * 16-May-2003 BJD Created initial version
- * 16-Aug-2003 BJD Fixed header files and copyright, added URL
- * 05-Sep-2003 BJD Moved to kernel v2.6
- * 18-Jan-2004 BJD Added serial port configuration
- * 21-Aug-2004 BJD Added new struct s3c2410_board handler
- * 28-Sep-2004 BJD Updates for new serial port bits
- * 04-Nov-2004 BJD Updated UART configuration process
- * 10-Jan-2005 BJD Removed s3c2410_clock_tick_rate
- * 13-Aug-2005 DA Removed UART from initial I/O mappings
*/
#include <linux/kernel.h>
@@ -56,6 +45,13 @@
#ifndef CONFIG_CPU_S3C2412_ONLY
void __iomem *s3c24xx_va_gpio2 = S3C24XX_VA_GPIO;
+
+static inline void s3c2412_init_gpio2(void)
+{
+ s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
+}
+#else
+#define s3c2412_init_gpio2() do { } while(0)
#endif
/* Initial IO mappings */
@@ -76,6 +72,7 @@ void __init s3c2412_init_uarts(struct s3c2410_uartcfg *cfg, int no)
/* rename devices that are s3c2412/s3c2413 specific */
s3c_device_sdi.name = "s3c2412-sdi";
+ s3c_device_lcd.name = "s3c2412-lcd";
s3c_device_nand.name = "s3c2412-nand";
}
@@ -110,7 +107,7 @@ void __init s3c2412_map_io(struct map_desc *mach_desc, int mach_size)
{
/* move base of IO */
- s3c24xx_va_gpio2 = S3C24XX_VA_GPIO + 0x10;
+ s3c2412_init_gpio2();
/* set our idle function */
@@ -161,48 +158,8 @@ void __init s3c2412_init_clocks(int xtal)
* as a driver which may support both 2410 and 2440 may try and use it.
*/
-#ifdef CONFIG_PM
-static struct sleep_save s3c2412_sleep[] = {
- SAVE_ITEM(S3C2412_DSC0),
- SAVE_ITEM(S3C2412_DSC1),
- SAVE_ITEM(S3C2413_GPJDAT),
- SAVE_ITEM(S3C2413_GPJCON),
- SAVE_ITEM(S3C2413_GPJUP),
-
- /* save the sleep configuration anyway, just in case these
- * get damaged during wakeup */
-
- SAVE_ITEM(S3C2412_GPBSLPCON),
- SAVE_ITEM(S3C2412_GPCSLPCON),
- SAVE_ITEM(S3C2412_GPDSLPCON),
- SAVE_ITEM(S3C2412_GPESLPCON),
- SAVE_ITEM(S3C2412_GPFSLPCON),
- SAVE_ITEM(S3C2412_GPGSLPCON),
- SAVE_ITEM(S3C2412_GPHSLPCON),
- SAVE_ITEM(S3C2413_GPJSLPCON),
-};
-
-static int s3c2412_suspend(struct sys_device *dev, pm_message_t state)
-{
- s3c2410_pm_do_save(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
- return 0;
-}
-
-static int s3c2412_resume(struct sys_device *dev)
-{
- s3c2410_pm_do_restore(s3c2412_sleep, ARRAY_SIZE(s3c2412_sleep));
- return 0;
-}
-
-#else
-#define s3c2412_suspend NULL
-#define s3c2412_resume NULL
-#endif
-
struct sysdev_class s3c2412_sysclass = {
set_kset_name("s3c2412-core"),
- .suspend = s3c2412_suspend,
- .resume = s3c2412_resume
};
static int __init s3c2412_core_init(void)
diff --git a/arch/arm/mach-s3c2410/s3c2440-dma.c b/arch/arm/mach-s3c2410/s3c2440-dma.c
new file mode 100644
index 000000000000..11e109c84a15
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2440-dma.c
@@ -0,0 +1,164 @@
+/* linux/arch/arm/mach-s3c2410/s3c2440-dma.c
+ *
+ * (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2440 DMA selection
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/sysdev.h>
+
+#include <asm/dma.h>
+#include <asm/arch/dma.h>
+#include "dma.h"
+
+#include "cpu.h"
+
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-ac97.h>
+#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
+#include <asm/arch/regs-sdi.h>
+#include <asm/arch/regs-iis.h>
+#include <asm/arch/regs-spi.h>
+
+static struct s3c24xx_dma_map __initdata s3c2440_dma_mappings[] = {
+ [DMACH_XD0] = {
+ .name = "xdreq0",
+ .channels[0] = S3C2410_DCON_CH0_XDREQ0 | DMA_CH_VALID,
+ },
+ [DMACH_XD1] = {
+ .name = "xdreq1",
+ .channels[1] = S3C2410_DCON_CH1_XDREQ1 | DMA_CH_VALID,
+ },
+ [DMACH_SDI] = {
+ .name = "sdi",
+ .channels[0] = S3C2410_DCON_CH0_SDI | DMA_CH_VALID,
+ .channels[1] = S3C2440_DCON_CH1_SDI | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_SDI | DMA_CH_VALID,
+ .channels[3] = S3C2410_DCON_CH3_SDI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_SPI0] = {
+ .name = "spi0",
+ .channels[1] = S3C2410_DCON_CH1_SPI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_SPI + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + S3C2410_SPRDAT,
+ },
+ [DMACH_SPI1] = {
+ .name = "spi1",
+ .channels[3] = S3C2410_DCON_CH3_SPI | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_SPI + 0x20 + S3C2410_SPTDAT,
+ .hw_addr.from = S3C2410_PA_SPI + 0x20 + S3C2410_SPRDAT,
+ },
+ [DMACH_UART0] = {
+ .name = "uart0",
+ .channels[0] = S3C2410_DCON_CH0_UART0 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART0 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART0 + S3C2410_URXH,
+ },
+ [DMACH_UART1] = {
+ .name = "uart1",
+ .channels[1] = S3C2410_DCON_CH1_UART1 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART1 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART1 + S3C2410_URXH,
+ },
+ [DMACH_UART2] = {
+ .name = "uart2",
+ .channels[3] = S3C2410_DCON_CH3_UART2 | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_UART2 + S3C2410_UTXH,
+ .hw_addr.from = S3C2410_PA_UART2 + S3C2410_URXH,
+ },
+ [DMACH_TIMER] = {
+ .name = "timer",
+ .channels[0] = S3C2410_DCON_CH0_TIMER | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_TIMER | DMA_CH_VALID,
+ .channels[3] = S3C2410_DCON_CH3_TIMER | DMA_CH_VALID,
+ },
+ [DMACH_I2S_IN] = {
+ .name = "i2s-sdi",
+ .channels[1] = S3C2410_DCON_CH1_I2SSDI | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_I2SSDI | DMA_CH_VALID,
+ .hw_addr.from = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_I2S_OUT] = {
+ .name = "i2s-sdo",
+ .channels[0] = S3C2440_DCON_CH0_I2SSDO | DMA_CH_VALID,
+ .channels[2] = S3C2410_DCON_CH2_I2SSDO | DMA_CH_VALID,
+ .hw_addr.to = S3C2410_PA_IIS + S3C2410_IISFIFO,
+ },
+ [DMACH_PCM_IN] = {
+ .name = "pcm-in",
+ .channels[0] = S3C2440_DCON_CH0_PCMIN | DMA_CH_VALID,
+ .channels[2] = S3C2440_DCON_CH2_PCMIN | DMA_CH_VALID,
+ .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+ },
+ [DMACH_PCM_OUT] = {
+ .name = "pcm-out",
+ .channels[1] = S3C2440_DCON_CH1_PCMOUT | DMA_CH_VALID,
+ .channels[3] = S3C2440_DCON_CH3_PCMOUT | DMA_CH_VALID,
+ .hw_addr.to = S3C2440_PA_AC97 + S3C_AC97_PCM_DATA,
+ },
+ [DMACH_MIC_IN] = {
+ .name = "mic-in",
+ .channels[2] = S3C2440_DCON_CH2_MICIN | DMA_CH_VALID,
+ .channels[3] = S3C2440_DCON_CH3_MICIN | DMA_CH_VALID,
+ .hw_addr.from = S3C2440_PA_AC97 + S3C_AC97_MIC_DATA,
+ },
+ [DMACH_USB_EP1] = {
+ .name = "usb-ep1",
+ .channels[0] = S3C2410_DCON_CH0_USBEP1 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP2] = {
+ .name = "usb-ep2",
+ .channels[1] = S3C2410_DCON_CH1_USBEP2 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP3] = {
+ .name = "usb-ep3",
+ .channels[2] = S3C2410_DCON_CH2_USBEP3 | DMA_CH_VALID,
+ },
+ [DMACH_USB_EP4] = {
+ .name = "usb-ep4",
+ .channels[3] = S3C2410_DCON_CH3_USBEP4 | DMA_CH_VALID,
+ },
+};
+
+static void s3c2440_dma_select(struct s3c2410_dma_chan *chan,
+ struct s3c24xx_dma_map *map)
+{
+ chan->dcon = map->channels[chan->number] & ~DMA_CH_VALID;
+}
+
+static struct s3c24xx_dma_selection __initdata s3c2440_dma_sel = {
+ .select = s3c2440_dma_select,
+ .dcon_mask = 7 << 24,
+ .map = s3c2440_dma_mappings,
+ .map_size = ARRAY_SIZE(s3c2440_dma_mappings),
+};
+
+static int s3c2440_dma_add(struct sys_device *sysdev)
+{
+ return s3c24xx_dma_init_map(&s3c2440_dma_sel);
+}
+
+static struct sysdev_driver s3c2440_dma_driver = {
+ .add = s3c2440_dma_add,
+};
+
+static int __init s3c2440_dma_init(void)
+{
+ return sysdev_driver_register(&s3c2440_sysclass, &s3c2440_dma_driver);
+}
+
+arch_initcall(s3c2440_dma_init);
+
diff --git a/arch/arm/mach-s3c2410/s3c2440-dsc.c b/arch/arm/mach-s3c2410/s3c2440-dsc.c
index 16fa2a3b38fa..c92ea66ba45e 100644
--- a/arch/arm/mach-s3c2410/s3c2440-dsc.c
+++ b/arch/arm/mach-s3c2410/s3c2440-dsc.c
@@ -8,11 +8,6 @@
* 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.
- *
- * Modifications:
- * 29-Aug-2004 BJD Start of drive-strength control
- * 09-Nov-2004 BJD Added symbol export
- * 11-Jan-2005 BJD Include fix
*/
#include <linux/kernel.h>
diff --git a/arch/arm/mach-s3c2410/s3c2440-irq.c b/arch/arm/mach-s3c2410/s3c2440-irq.c
index 1667ba1fa43d..39db0752d53b 100644
--- a/arch/arm/mach-s3c2410/s3c2440-irq.c
+++ b/arch/arm/mach-s3c2410/s3c2440-irq.c
@@ -42,8 +42,7 @@
/* WDT/AC97 */
static void s3c_irq_demux_wdtac97(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+ struct irqdesc *desc)
{
unsigned int subsrc, submsk;
struct irqdesc *mydesc;
@@ -61,11 +60,11 @@ static void s3c_irq_demux_wdtac97(unsigned int irq,
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_S3C2440_WDT;
- desc_handle_irq(IRQ_S3C2440_WDT, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_WDT, mydesc);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_S3C2440_AC97;
- desc_handle_irq(IRQ_S3C2440_AC97, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_AC97, mydesc);
}
}
}
@@ -119,7 +118,7 @@ static int s3c2440_irq_add(struct sys_device *sysdev)
}
static struct sysdev_driver s3c2440_irq_driver = {
- .add = s3c2440_irq_add,
+ .add = s3c2440_irq_add,
};
static int s3c2440_irq_init(void)
diff --git a/arch/arm/mach-s3c2410/s3c2442.c b/arch/arm/mach-s3c2410/s3c2442.c
index debae2430557..581667efd13c 100644
--- a/arch/arm/mach-s3c2410/s3c2442.c
+++ b/arch/arm/mach-s3c2410/s3c2442.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2440.c
+/* linux/arch/arm/mach-s3c2410/s3c2442.c
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/s3c244x-irq.c b/arch/arm/mach-s3c2410/s3c244x-irq.c
index 44c5affa9b89..146f2109dd90 100644
--- a/arch/arm/mach-s3c2410/s3c244x-irq.c
+++ b/arch/arm/mach-s3c2410/s3c244x-irq.c
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/s3c2440-irq.c
+/* linux/arch/arm/mach-s3c2410/s3c244x-irq.c
*
* Copyright (c) 2003,2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
@@ -42,8 +42,7 @@
/* camera irq */
static void s3c_irq_demux_cam(unsigned int irq,
- struct irqdesc *desc,
- struct pt_regs *regs)
+ struct irqdesc *desc)
{
unsigned int subsrc, submsk;
struct irqdesc *mydesc;
@@ -61,11 +60,11 @@ static void s3c_irq_demux_cam(unsigned int irq,
if (subsrc != 0) {
if (subsrc & 1) {
mydesc = irq_desc + IRQ_S3C2440_CAM_C;
- desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_CAM_C, mydesc);
}
if (subsrc & 2) {
mydesc = irq_desc + IRQ_S3C2440_CAM_P;
- desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc, regs);
+ desc_handle_irq(IRQ_S3C2440_CAM_P, mydesc);
}
}
}
@@ -120,7 +119,9 @@ static int s3c244x_irq_add(struct sys_device *sysdev)
}
static struct sysdev_driver s3c2440_irq_driver = {
- .add = s3c244x_irq_add,
+ .add = s3c244x_irq_add,
+ .suspend = s3c24xx_irq_suspend,
+ .resume = s3c24xx_irq_resume,
};
static int s3c2440_irq_init(void)
@@ -131,9 +132,12 @@ static int s3c2440_irq_init(void)
arch_initcall(s3c2440_irq_init);
static struct sysdev_driver s3c2442_irq_driver = {
- .add = s3c244x_irq_add,
+ .add = s3c244x_irq_add,
+ .suspend = s3c24xx_irq_suspend,
+ .resume = s3c24xx_irq_resume,
};
+
static int s3c2442_irq_init(void)
{
return sysdev_driver_register(&s3c2442_sysclass, &s3c2442_irq_driver);
diff --git a/arch/arm/mach-s3c2410/s3c244x.h b/arch/arm/mach-s3c2410/s3c244x.h
index 3e7f5f75134d..1488c1eb37e6 100644
--- a/arch/arm/mach-s3c2410/s3c244x.h
+++ b/arch/arm/mach-s3c2410/s3c244x.h
@@ -1,4 +1,4 @@
-/* arch/arm/mach-s3c2410/s3c2440.h
+/* arch/arm/mach-s3c2410/s3c244x.h
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
index a7561a79fc82..2018c2e1dcc5 100644
--- a/arch/arm/mach-s3c2410/sleep.S
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -41,15 +41,25 @@
.text
- /* s3c2410_cpu_suspend
+ /* s3c2410_cpu_save
*
- * put the cpu into sleep mode
+ * save enough of the CPU state to allow us to re-start
+ * pm.c code. as we store items like the sp/lr, we will
+ * end up returning from this function when the cpu resumes
+ * so the return value is set to mark this.
+ *
+ * This arangement means we avoid having to flush the cache
+ * from this code.
*
* entry:
- * r0 = sleep save block
+ * r0 = pointer to save block
+ *
+ * exit:
+ * r0 = 0 => we stored everything
+ * 1 => resumed from sleep
*/
-ENTRY(s3c2410_cpu_suspend)
+ENTRY(s3c2410_cpu_save)
stmfd sp!, { r4 - r12, lr }
@@ store co-processor registers
@@ -62,44 +72,14 @@ ENTRY(s3c2410_cpu_suspend)
stmia r0, { r4 - r13 }
- @@ flush the caches to ensure everything is back out to
- @@ SDRAM before the core powers down
-
-#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
- bl arm920_flush_kern_cache_all
-#endif
-
- @@ prepare cpu to sleep
-
- ldr r4, =S3C2410_REFRESH
- ldr r5, =S3C24XX_MISCCR
- ldr r6, =S3C2410_CLKCON
- ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
- ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
- ldr r9, [ r6 ] @ get CLKCON (and ensure in TLB)
-
- orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
- orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
- orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
-
- teq pc, #0 @ first as a trial-run to load cache
- bl s3c2410_do_sleep
- teq r0, r0 @ now do it for real
- b s3c2410_do_sleep @
-
- @@ align next bit of code to cache line
- .align 8
-s3c2410_do_sleep:
- streq r7, [ r4 ] @ SDRAM sleep command
- streq r8, [ r5 ] @ SDRAM power-down config
- streq r9, [ r6 ] @ CPU sleep
-1: beq 1b
- mov pc, r14
+ mov r0, #0
+ ldmfd sp, { r4 - r12, pc }
@@ return to the caller, after having the MMU
@@ turned on, this restores the last bits from the
@@ stack
resume_with_mmu:
+ mov r0, #1
ldmfd sp!, { r4 - r12, pc }
.ltorg
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c
index 00d1cfca9712..9910bf0f2cea 100644
--- a/arch/arm/mach-s3c2410/time.c
+++ b/arch/arm/mach-s3c2410/time.c
@@ -128,10 +128,10 @@ static unsigned long s3c2410_gettimeoffset (void)
* IRQ handler for the timer
*/
static irqreturn_t
-s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+s3c2410_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-s3c2410/usb-simtec.c b/arch/arm/mach-s3c2410/usb-simtec.c
index 6b22d8f0a00d..22b0e1cdd4bf 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.c
+++ b/arch/arm/mach-s3c2410/usb-simtec.c
@@ -10,12 +10,6 @@
* 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.
- *
- * Modifications:
- * 14-Sep-2004 BJD Created
- * 18-Oct-2004 BJD Cleanups, and added code to report OC cleared
- * 09-Aug-2005 BJD Renamed s3c2410_report_oc to s3c2410_usb_report_oc
- * 09-Aug-2005 BJD Ports powered only if both are enabled
*/
#define DEBUG
@@ -64,7 +58,7 @@ usb_simtec_powercontrol(int port, int to)
}
static irqreturn_t
-usb_simtec_ocirq(int irq, void *pw, struct pt_regs *regs)
+usb_simtec_ocirq(int irq, void *pw)
{
struct s3c2410_hcd_info *info = (struct s3c2410_hcd_info *)pw;
diff --git a/arch/arm/mach-s3c2410/usb-simtec.h b/arch/arm/mach-s3c2410/usb-simtec.h
index 92c0cc83aeec..d8aa6127dedb 100644
--- a/arch/arm/mach-s3c2410/usb-simtec.h
+++ b/arch/arm/mach-s3c2410/usb-simtec.h
@@ -1,4 +1,4 @@
-/* linux/arch/arm/mach-s3c2410/usb-simtec.c
+/* linux/arch/arm/mach-s3c2410/usb-simtec.h
*
* Copyright (c) 2004 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index a0dfa390e34b..6496eb645cee 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -91,30 +91,29 @@ static struct mcp_plat_data collie_mcp_data = {
/*
* low-level UART features.
*/
-static struct locomo_dev *uart_dev = NULL;
+struct platform_device collie_locomo_device;
static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl)
{
- if (!uart_dev) return;
-
if (mctrl & TIOCM_RTS)
- locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 0);
+ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 0);
else
- locomo_gpio_write(uart_dev, LOCOMO_GPIO_RTS, 1);
+ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 1);
if (mctrl & TIOCM_DTR)
- locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 0);
+ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 0);
else
- locomo_gpio_write(uart_dev, LOCOMO_GPIO_DTR, 1);
+ locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 1);
}
static u_int collie_uart_get_mctrl(struct uart_port *port)
{
int ret = TIOCM_CD;
unsigned int r;
- if (!uart_dev) return ret;
- r = locomo_gpio_read_output(uart_dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
+ r = locomo_gpio_read_output(&collie_locomo_device.dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR);
+ if (r == -ENODEV)
+ return ret;
if (r & LOCOMO_GPIO_CTS)
ret |= TIOCM_CTS;
if (r & LOCOMO_GPIO_DSR)
@@ -130,13 +129,11 @@ static struct sa1100_port_fns collie_port_fns __initdata = {
static int collie_uart_probe(struct locomo_dev *dev)
{
- uart_dev = dev;
return 0;
}
static int collie_uart_remove(struct locomo_dev *dev)
{
- uart_dev = NULL;
return 0;
}
@@ -170,7 +167,7 @@ static struct resource locomo_resources[] = {
},
};
-static struct platform_device locomo_device = {
+struct platform_device collie_locomo_device = {
.name = "locomo",
.id = 0,
.num_resources = ARRAY_SIZE(locomo_resources),
@@ -178,7 +175,7 @@ static struct platform_device locomo_device = {
};
static struct platform_device *devices[] __initdata = {
- &locomo_device,
+ &collie_locomo_device,
&colliescoop_device,
};
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
index 639597729932..90a4130114a6 100644
--- a/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -82,6 +82,14 @@ static struct sdram_params sdram_tbl[] __initdata = {
.twr = 9,
.refresh = 64000,
.cas_latency = 3,
+ }, { /* Samsung K4S281632B-1H */
+ .name = "K4S281632b-1H",
+ .rows = 12,
+ .tck = 10,
+ .trp = 20,
+ .twr = 10,
+ .refresh = 64000,
+ .cas_latency = 3,
}, { /* Samsung KM416S4030CT */
.name = "KM416S4030CT",
.rows = 13,
@@ -366,6 +374,8 @@ static int __init sa1110_clk_init(void)
if (machine_is_h3100())
name = "KM416S4030CT";
+ if (machine_is_jornada720())
+ name = "K4S281632B-1H";
}
sdram = sa1110_find_sdram(name);
diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
index 3c6441d4bc59..1fbe053e8b59 100644
--- a/arch/arm/mach-sa1100/dma.c
+++ b/arch/arm/mach-sa1100/dma.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/kernel/dma-sa1100.c
+ * arch/arm/mach-sa1100/dma.c
*
* Support functions for the SA11x0 internal DMA channels.
*
@@ -42,7 +42,7 @@ static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
static spinlock_t dma_list_lock;
-static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_irq_handler(int irq, void *dev_id)
{
dma_regs_t *dma_regs = dev_id;
sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7);
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index 7364478cec12..fa6dc71bd6ad 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -702,7 +702,7 @@ static u32 gpio_irq_mask[] = {
GPIO2_SD_CON_SLT,
};
-static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc)
{
int i;
@@ -719,14 +719,14 @@ static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_re
if (0) printk("%s KPIO 0x%08X\n", __FUNCTION__, irq);
for (j = 0; j < H3800_KPIO_IRQ_COUNT; j++)
if (irq & kpio_irq_mask[j])
- do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j, regs);
+ do_edge_IRQ(H3800_KPIO_IRQ_COUNT + j, irq_desc + H3800_KPIO_IRQ_COUNT + j);
/* GPIO2 */
irq = H3800_ASIC2_GPIINTFLAG;
if (0) printk("%s GPIO 0x%08X\n", __FUNCTION__, irq);
for (j = 0; j < H3800_GPIO_IRQ_COUNT; j++)
if (irq & gpio_irq_mask[j])
- do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j , regs);
+ do_edge_IRQ(H3800_GPIO_IRQ_COUNT + j, irq_desc + H3800_GPIO_IRQ_COUNT + j);
}
if (i >= MAX_ASIC_ISR_LOOPS)
diff --git a/arch/arm/mach-sa1100/irq.c b/arch/arm/mach-sa1100/irq.c
index b55b90a2e8fe..f4c6322ca33e 100644
--- a/arch/arm/mach-sa1100/irq.c
+++ b/arch/arm/mach-sa1100/irq.c
@@ -110,8 +110,7 @@ static struct irq_chip sa1100_low_gpio_chip = {
* and call the handler.
*/
static void
-sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned int mask;
@@ -128,7 +127,7 @@ sa1100_high_gpio_handler(unsigned int irq, struct irqdesc *desc,
mask >>= 11;
do {
if (mask & 1)
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
mask >>= 1;
irq++;
desc++;
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index af6d2775cf82..354d5e91da59 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -29,7 +29,7 @@
* is rather unfortunate.
*/
static void
-neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+neponset_irq_handler(unsigned int irq, struct irqdesc *desc)
{
unsigned int irr;
@@ -69,12 +69,12 @@ neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
if (irr & IRR_ETHERNET) {
d = irq_desc + IRQ_NEPONSET_SMC9196;
- desc_handle_irq(IRQ_NEPONSET_SMC9196, d, regs);
+ desc_handle_irq(IRQ_NEPONSET_SMC9196, d);
}
if (irr & IRR_USAR) {
d = irq_desc + IRQ_NEPONSET_USAR;
- desc_handle_irq(IRQ_NEPONSET_USAR, d, regs);
+ desc_handle_irq(IRQ_NEPONSET_USAR, d);
}
desc->chip->unmask(irq);
@@ -82,7 +82,7 @@ neponset_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *reg
if (irr & IRR_SA1111) {
d = irq_desc + IRQ_NEPONSET_SA1111;
- desc_handle_irq(IRQ_NEPONSET_SA1111, d, regs);
+ desc_handle_irq(IRQ_NEPONSET_SA1111, d);
}
}
}
diff --git a/arch/arm/mach-sa1100/ssp.c b/arch/arm/mach-sa1100/ssp.c
index 5eba5fbbb561..59703c6fb29b 100644
--- a/arch/arm/mach-sa1100/ssp.c
+++ b/arch/arm/mach-sa1100/ssp.c
@@ -25,7 +25,7 @@
#define TIMEOUT 100000
-static irqreturn_t ssp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ssp_interrupt(int irq, void *dev_id)
{
unsigned int status = Ser4SSSR;
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 49ae716e16c2..4284bd6f7a1f 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -77,7 +77,7 @@ static int match_posponed;
#endif
static irqreturn_t
-sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+sa1100_timer_interrupt(int irq, void *dev_id)
{
unsigned int next_match;
@@ -99,7 +99,7 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* handlers.
*/
do {
- timer_tick(regs);
+ timer_tick();
OSSR = OSSR_M0; /* Clear match on timer 0 */
next_match = (OSMR0 += LATCH);
} while ((signed long)(next_match - OSCR) <= 0);
@@ -151,13 +151,13 @@ static void sa1100_dyn_tick_reprogram(unsigned long ticks)
}
static irqreturn_t
-sa1100_dyn_tick_handler(int irq, void *dev_id, struct pt_regs *regs)
+sa1100_dyn_tick_handler(int irq, void *dev_id)
{
if (match_posponed) {
match_posponed = 0;
OSMR0 = initial_match;
if ((signed long)(initial_match - OSCR) <= 0)
- return sa1100_timer_interrupt(irq, dev_id, regs);
+ return sa1100_timer_interrupt(irq, dev_id);
}
return IRQ_NONE;
}
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index 1095df34fec0..0e480fae8ec5 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -80,10 +80,10 @@ static void __init shark_map_io(void)
#define HZ_TIME ((1193180 + HZ/2) / HZ)
static irqreturn_t
-shark_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+shark_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
}
diff --git a/arch/arm/mach-shark/irq.c b/arch/arm/mach-shark/irq.c
index b227052296cf..297ecf130650 100644
--- a/arch/arm/mach-shark/irq.c
+++ b/arch/arm/mach-shark/irq.c
@@ -61,7 +61,7 @@ static void shark_enable_8259A_irq(unsigned int irq)
static void shark_ack_8259A_irq(unsigned int irq){}
-static irqreturn_t bogus_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bogus_int(int irq, void *dev_id)
{
printk("Got interrupt %i!\n",irq);
return IRQ_NONE;
diff --git a/arch/arm/mach-shark/leds.c b/arch/arm/mach-shark/leds.c
index 7cd86d357a3c..5386a81f796a 100644
--- a/arch/arm/mach-shark/leds.c
+++ b/arch/arm/mach-shark/leds.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/kernel/leds-shark.c
+ * arch/arm/mach-shark/leds.c
* by Alexander Schulz
*
* derived from:
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index f2bbef07b1e4..3b8576111c16 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -77,12 +77,12 @@ static struct irq_chip sic_chip = {
};
static void
-sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
+sic_handle_irq(unsigned int irq, struct irqdesc *desc)
{
unsigned long status = readl(VA_SIC_BASE + SIC_IRQ_STATUS);
if (status == 0) {
- do_bad_IRQ(irq, desc, regs);
+ do_bad_IRQ(irq, desc);
return;
}
@@ -93,7 +93,7 @@ sic_handle_irq(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
irq += IRQ_SIC_START;
desc = irq_desc + irq;
- desc_handle_irq(irq, desc, regs);
+ desc_handle_irq(irq, desc);
} while (status);
}
@@ -188,12 +188,12 @@ static struct map_desc versatile_io_desc[] __initdata = {
.length = SZ_4K,
.type = MT_DEVICE
}, {
- .virtual = VERSATILE_PCI_VIRT_BASE,
+ .virtual = (unsigned long)VERSATILE_PCI_VIRT_BASE,
.pfn = __phys_to_pfn(VERSATILE_PCI_BASE),
.length = VERSATILE_PCI_BASE_SIZE,
.type = MT_DEVICE
}, {
- .virtual = VERSATILE_PCI_CFG_VIRT_BASE,
+ .virtual = (unsigned long)VERSATILE_PCI_CFG_VIRT_BASE,
.pfn = __phys_to_pfn(VERSATILE_PCI_CFG_BASE),
.length = VERSATILE_PCI_CFG_BASE_SIZE,
.type = MT_DEVICE
@@ -851,14 +851,14 @@ static unsigned long versatile_gettimeoffset(void)
/*
* IRQ handler for the timer
*/
-static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id)
{
write_seqlock(&xtime_lock);
// ...clear the interrupt
writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
- timer_tick(regs);
+ timer_tick();
write_sequnlock(&xtime_lock);
diff --git a/arch/arm/mach-versatile/pci.c b/arch/arm/mach-versatile/pci.c
index 41b370090b60..5cd0b5d9e7eb 100644
--- a/arch/arm/mach-versatile/pci.c
+++ b/arch/arm/mach-versatile/pci.c
@@ -40,14 +40,15 @@
* Cfg 42000000 - 42FFFFFF PCI config
*
*/
-#define SYS_PCICTL IO_ADDRESS(VERSATILE_SYS_PCICTL)
-#define PCI_IMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
-#define PCI_IMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
-#define PCI_IMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
-#define PCI_SMAP0 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
-#define PCI_SMAP1 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
-#define PCI_SMAP2 IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
-#define PCI_SELFID IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
+#define __IO_ADDRESS(n) ((void __iomem *)(unsigned long)IO_ADDRESS(n))
+#define SYS_PCICTL __IO_ADDRESS(VERSATILE_SYS_PCICTL)
+#define PCI_IMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x0)
+#define PCI_IMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x4)
+#define PCI_IMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x8)
+#define PCI_SMAP0 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x10)
+#define PCI_SMAP1 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x14)
+#define PCI_SMAP2 __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0x18)
+#define PCI_SELFID __IO_ADDRESS(VERSATILE_PCI_CORE_BASE+0xc)
#define DEVICE_ID_OFFSET 0x00
#define CSR_OFFSET 0x04
@@ -76,7 +77,7 @@ static int __init versatile_pci_slot_ignore(char *str)
__setup("pci_slot_ignore=", versatile_pci_slot_ignore);
-static unsigned long __pci_addr(struct pci_bus *bus,
+static void __iomem *__pci_addr(struct pci_bus *bus,
unsigned int devfn, int offset)
{
unsigned int busnr = bus->number;
@@ -91,14 +92,14 @@ static unsigned long __pci_addr(struct pci_bus *bus,
if (devfn > 255)
BUG();
- return (VERSATILE_PCI_CFG_VIRT_BASE | (busnr << 16) |
+ return VERSATILE_PCI_CFG_VIRT_BASE + ((busnr << 16) |
(PCI_SLOT(devfn) << 11) | (PCI_FUNC(devfn) << 8) | offset);
}
static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 *val)
{
- unsigned long addr = __pci_addr(bus, devfn, where);
+ void __iomem *addr = __pci_addr(bus, devfn, where & ~3);
u32 v;
int slot = PCI_SLOT(devfn);
@@ -117,18 +118,16 @@ static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int wh
} else {
switch (size) {
case 1:
- addr &= ~3;
v = __raw_readb(addr);
break;
case 2:
- v = __raw_readl(addr & ~3);
- if (addr & 2) v >>= 16;
+ v = __raw_readl(addr);
+ if (where & 2) v >>= 16;
v &= 0xffff;
break;
default:
- addr &= ~3;
v = __raw_readl(addr);
break;
}
@@ -141,7 +140,7 @@ static int versatile_read_config(struct pci_bus *bus, unsigned int devfn, int wh
static int versatile_write_config(struct pci_bus *bus, unsigned int devfn, int where,
int size, u32 val)
{
- unsigned long addr = __pci_addr(bus, devfn, where);
+ void __iomem *addr = __pci_addr(bus, devfn, where);
int slot = PCI_SLOT(devfn);
if (pci_slot_ignore & (1 << slot)) {
@@ -280,7 +279,7 @@ int __init pci_versatile_setup(int nr, struct pci_sys_data *sys)
printk("PCI core found (slot %d)\n",myslot);
__raw_writel(myslot, PCI_SELFID);
- local_pci_cfg_base = (void *) VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
+ local_pci_cfg_base = VERSATILE_PCI_CFG_VIRT_BASE + (myslot << 11);
val = __raw_readl(local_pci_cfg_base + CSR_OFFSET);
val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index b4f220dd5eb8..c0bfb8212b77 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -15,6 +15,7 @@ config CPU_ARM610
select CPU_32v3
select CPU_CACHE_V3
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V3 if MMU
select CPU_TLB_V3 if MMU
help
@@ -24,6 +25,20 @@ config CPU_ARM610
Say Y if you want support for the ARM610 processor.
Otherwise, say N.
+# ARM7TDMI
+config CPU_ARM7TDMI
+ bool "Support ARM7TDMI processor"
+ depends on !MMU
+ select CPU_32v4T
+ select CPU_ABRT_LV4T
+ select CPU_CACHE_V4
+ help
+ A 32-bit RISC microprocessor based on the ARM7 processor core
+ which has no memory control unit and cache.
+
+ Say Y if you want support for the ARM7TDMI processor.
+ Otherwise, say N.
+
# ARM710
config CPU_ARM710
bool "Support ARM710 processor" if !ARCH_CLPS7500 && ARCH_RPC
@@ -31,6 +46,7 @@ config CPU_ARM710
select CPU_32v3
select CPU_CACHE_V3
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V3 if MMU
select CPU_TLB_V3 if MMU
help
@@ -50,6 +66,7 @@ config CPU_ARM720T
select CPU_ABRT_LV4T
select CPU_CACHE_V4
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WT if MMU
select CPU_TLB_V4WT if MMU
help
@@ -59,6 +76,36 @@ config CPU_ARM720T
Say Y if you want support for the ARM720T processor.
Otherwise, say N.
+# ARM740T
+config CPU_ARM740T
+ bool "Support ARM740T processor" if ARCH_INTEGRATOR
+ depends on !MMU
+ select CPU_32v4T
+ select CPU_ABRT_LV4T
+ select CPU_CACHE_V3 # although the core is v4t
+ select CPU_CP15_MPU
+ help
+ A 32-bit RISC processor with 8KB cache or 4KB variants,
+ write buffer and MPU(Protection Unit) built around
+ an ARM7TDMI core.
+
+ Say Y if you want support for the ARM740T processor.
+ Otherwise, say N.
+
+# ARM9TDMI
+config CPU_ARM9TDMI
+ bool "Support ARM9TDMI processor"
+ depends on !MMU
+ select CPU_32v4T
+ select CPU_ABRT_NOMMU
+ select CPU_CACHE_V4
+ help
+ A 32-bit RISC microprocessor based on the ARM9 processor core
+ which has no memory control unit and cache.
+
+ Say Y if you want support for the ARM9TDMI processor.
+ Otherwise, say N.
+
# ARM920T
config CPU_ARM920T
bool "Support ARM920T processor"
@@ -68,6 +115,7 @@ config CPU_ARM920T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI if MMU
help
@@ -89,6 +137,7 @@ config CPU_ARM922T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI if MMU
help
@@ -108,6 +157,7 @@ config CPU_ARM925T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI if MMU
help
@@ -126,6 +176,7 @@ config CPU_ARM926T
select CPU_32v5
select CPU_ABRT_EV5TJ
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI if MMU
help
@@ -136,6 +187,39 @@ config CPU_ARM926T
Say Y if you want support for the ARM926T processor.
Otherwise, say N.
+# ARM940T
+config CPU_ARM940T
+ bool "Support ARM940T processor" if ARCH_INTEGRATOR
+ depends on !MMU
+ select CPU_32v4T
+ select CPU_ABRT_NOMMU
+ select CPU_CACHE_VIVT
+ select CPU_CP15_MPU
+ help
+ ARM940T is a member of the ARM9TDMI family of general-
+ purpose microprocessors with MPU and seperate 4KB
+ instruction and 4KB data cases, each with a 4-word line
+ length.
+
+ Say Y if you want support for the ARM940T processor.
+ Otherwise, say N.
+
+# ARM946E-S
+config CPU_ARM946E
+ bool "Support ARM946E-S processor" if ARCH_INTEGRATOR
+ depends on !MMU
+ select CPU_32v5
+ select CPU_ABRT_NOMMU
+ select CPU_CACHE_VIVT
+ select CPU_CP15_MPU
+ help
+ ARM946E-S is a member of the ARM9E-S family of high-
+ performance, 32-bit system-on-chip processor solutions.
+ The TCM and ARMv5TE 32-bit instruction set is supported.
+
+ Say Y if you want support for the ARM946E-S processor.
+ Otherwise, say N.
+
# ARM1020 - needs validating
config CPU_ARM1020
bool "Support ARM1020T (rev 0) processor"
@@ -144,6 +228,7 @@ config CPU_ARM1020
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI if MMU
help
@@ -161,6 +246,7 @@ config CPU_ARM1020E
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WBI if MMU
depends on n
@@ -172,6 +258,7 @@ config CPU_ARM1022
select CPU_32v5
select CPU_ABRT_EV4T
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU # can probably do better
select CPU_TLB_V4WBI if MMU
help
@@ -189,6 +276,7 @@ config CPU_ARM1026
select CPU_32v5
select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU # can probably do better
select CPU_TLB_V4WBI if MMU
help
@@ -207,6 +295,7 @@ config CPU_SA110
select CPU_ABRT_EV4
select CPU_CACHE_V4WB
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_COPY_V4WB if MMU
select CPU_TLB_V4WB if MMU
help
@@ -227,16 +316,18 @@ config CPU_SA1100
select CPU_ABRT_EV4
select CPU_CACHE_V4WB
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_TLB_V4WB if MMU
# XScale
config CPU_XSCALE
bool
- depends on ARCH_IOP3XX || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000
+ depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_PXA || ARCH_IXP4XX || ARCH_IXP2000
default y
select CPU_32v5
select CPU_ABRT_EV5T
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_TLB_V4WBI if MMU
# XScale Core Version 3
@@ -247,6 +338,7 @@ config CPU_XSC3
select CPU_32v5
select CPU_ABRT_EV5T
select CPU_CACHE_VIVT
+ select CPU_CP15_MMU
select CPU_TLB_V4WBI if MMU
select IO_36
@@ -258,6 +350,7 @@ config CPU_V6
select CPU_ABRT_EV6
select CPU_CACHE_V6
select CPU_CACHE_VIPT
+ select CPU_CP15_MMU
select CPU_COPY_V6 if MMU
select CPU_TLB_V6 if MMU
@@ -299,6 +392,9 @@ config CPU_32v6
bool
# The abort model
+config CPU_ABRT_NOMMU
+ bool
+
config CPU_ABRT_EV4
bool
@@ -380,6 +476,23 @@ config CPU_TLB_V6
endif
+config CPU_CP15
+ bool
+ help
+ Processor has the CP15 register.
+
+config CPU_CP15_MMU
+ bool
+ select CPU_CP15
+ help
+ Processor has the CP15 register, which has MMU related registers.
+
+config CPU_CP15_MPU
+ bool
+ select CPU_CP15
+ help
+ Processor has the CP15 register, which has MPU related registers.
+
#
# CPU supports 36-bit I/O
#
@@ -390,7 +503,7 @@ comment "Processor Features"
config ARM_THUMB
bool "Support Thumb user binaries"
- depends on CPU_ARM720T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || 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
default y
help
Say Y if you want to include kernel support for running user space
@@ -411,23 +524,48 @@ config CPU_BIG_ENDIAN
port must properly enable any big-endian related features
of your chipset/board/processor.
+config CPU_HIGH_VECTOR
+ depends !MMU && CPU_CP15 && !CPU_ARM740T
+ bool "Select the High exception vector"
+ default n
+ help
+ Say Y here to select high exception vector(0xFFFF0000~).
+ The exception vector can be vary depending on the platform
+ design in nommu mode. If your platform needs to select
+ high exception vector, say Y.
+ Otherwise or if you are unsure, say N, and the low exception
+ vector (0x00000000~) will be used.
+
config CPU_ICACHE_DISABLE
- bool "Disable I-Cache"
- depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6
+ bool "Disable I-Cache (I-bit)"
+ depends on CPU_CP15 && !(CPU_ARM610 || CPU_ARM710 || CPU_ARM720T || CPU_ARM740T || CPU_XSCALE || CPU_XSC3)
help
Say Y here to disable the processor instruction cache. Unless
you have a reason not to or are unsure, say N.
config CPU_DCACHE_DISABLE
- bool "Disable D-Cache"
- depends on CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6
+ bool "Disable D-Cache (C-bit)"
+ depends on CPU_CP15
help
Say Y here to disable the processor data cache. Unless
you have a reason not to or are unsure, say N.
+config CPU_DCACHE_SIZE
+ hex
+ depends on CPU_ARM740T || CPU_ARM946E
+ default 0x00001000 if CPU_ARM740T
+ default 0x00002000 # default size for ARM946E-S
+ help
+ Some cores are synthesizable to have various sized cache. For
+ ARM946E-S case, it can vary from 0KB to 1MB.
+ To support such cache operations, it is efficient to know the size
+ before compile time.
+ If your SoC is configured to have a different size, define the value
+ here with proper conditions.
+
config CPU_DCACHE_WRITETHROUGH
bool "Force write through D-cache"
- depends on (CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE
+ depends on (CPU_ARM740T || CPU_ARM920T || CPU_ARM922T || CPU_ARM925T || CPU_ARM926T || CPU_ARM940T || CPU_ARM946E || CPU_ARM1020 || CPU_V6) && !CPU_DCACHE_DISABLE
default y if CPU_ARM925T
help
Say Y here to use the data cache in writethrough mode. Unless you
@@ -435,7 +573,7 @@ config CPU_DCACHE_WRITETHROUGH
config CPU_CACHE_ROUND_ROBIN
bool "Round robin I and D cache replacement algorithm"
- depends on (CPU_ARM926T || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE)
+ depends on (CPU_ARM926T || CPU_ARM946E || CPU_ARM1020) && (!CPU_ICACHE_DISABLE || !CPU_DCACHE_DISABLE)
help
Say Y here to use the predictable round-robin cache replacement
policy. Unless you specifically require this or are unsure, say N.
diff --git a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
index 21a2770226ee..d2f5672ecf62 100644
--- a/arch/arm/mm/Makefile
+++ b/arch/arm/mm/Makefile
@@ -6,7 +6,7 @@ obj-y := consistent.o extable.o fault.o init.o \
iomap.o
obj-$(CONFIG_MMU) += fault-armv.o flush.o ioremap.o mmap.o \
- mm-armv.o
+ pgd.o mmu.o
ifneq ($(CONFIG_MMU),y)
obj-y += nommu.o
@@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += proc-syms.o
obj-$(CONFIG_ALIGNMENT_TRAP) += alignment.o
obj-$(CONFIG_DISCONTIGMEM) += discontig.o
+obj-$(CONFIG_CPU_ABRT_NOMMU) += abort-nommu.o
obj-$(CONFIG_CPU_ABRT_EV4) += abort-ev4.o
obj-$(CONFIG_CPU_ABRT_EV4T) += abort-ev4t.o
obj-$(CONFIG_CPU_ABRT_LV4T) += abort-lv4t.o
@@ -33,7 +34,7 @@ obj-$(CONFIG_CPU_CACHE_V6) += cache-v6.o
obj-$(CONFIG_CPU_COPY_V3) += copypage-v3.o
obj-$(CONFIG_CPU_COPY_V4WT) += copypage-v4wt.o
obj-$(CONFIG_CPU_COPY_V4WB) += copypage-v4wb.o
-obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o mmu.o
+obj-$(CONFIG_CPU_COPY_V6) += copypage-v6.o context.o
obj-$(CONFIG_CPU_SA1100) += copypage-v4mc.o
obj-$(CONFIG_CPU_XSCALE) += copypage-xscale.o
obj-$(CONFIG_CPU_XSC3) += copypage-xsc3.o
@@ -46,11 +47,16 @@ obj-$(CONFIG_CPU_TLB_V6) += tlb-v6.o
obj-$(CONFIG_CPU_ARM610) += proc-arm6_7.o
obj-$(CONFIG_CPU_ARM710) += proc-arm6_7.o
+obj-$(CONFIG_CPU_ARM7TDMI) += proc-arm7tdmi.o
obj-$(CONFIG_CPU_ARM720T) += proc-arm720.o
+obj-$(CONFIG_CPU_ARM740T) += proc-arm740.o
+obj-$(CONFIG_CPU_ARM9TDMI) += proc-arm9tdmi.o
obj-$(CONFIG_CPU_ARM920T) += proc-arm920.o
obj-$(CONFIG_CPU_ARM922T) += proc-arm922.o
obj-$(CONFIG_CPU_ARM925T) += proc-arm925.o
obj-$(CONFIG_CPU_ARM926T) += proc-arm926.o
+obj-$(CONFIG_CPU_ARM940T) += proc-arm940.o
+obj-$(CONFIG_CPU_ARM946E) += proc-arm946.o
obj-$(CONFIG_CPU_ARM1020) += proc-arm1020.o
obj-$(CONFIG_CPU_ARM1020E) += proc-arm1020e.o
obj-$(CONFIG_CPU_ARM1022) += proc-arm1022.o
diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S
index db743e510214..9fb7b0e25ea1 100644
--- a/arch/arm/mm/abort-lv4t.S
+++ b/arch/arm/mm/abort-lv4t.S
@@ -19,11 +19,16 @@
*/
ENTRY(v4t_late_abort)
tst r3, #PSR_T_BIT @ check for thumb mode
+#ifdef CONFIG_CPU_CP15_MMU
mrc p15, 0, r1, c5, c0, 0 @ get FSR
mrc p15, 0, r0, c6, c0, 0 @ get FAR
+ bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
+#else
+ mov r0, #0 @ clear r0, r1 (no FSR/FAR)
+ mov r1, #0
+#endif
bne .data_thumb_abort
ldr r8, [r2] @ read arm instruction
- bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR
tst r8, #1 << 20 @ L = 1 -> write?
orreq r1, r1, #1 << 11 @ yes.
and r7, r8, #15 << 24
diff --git a/arch/arm/mm/abort-nommu.S b/arch/arm/mm/abort-nommu.S
new file mode 100644
index 000000000000..a7cc7f9ee45d
--- /dev/null
+++ b/arch/arm/mm/abort-nommu.S
@@ -0,0 +1,19 @@
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+/*
+ * Function: nommu_early_abort
+ *
+ * Params : r2 = address of aborted instruction
+ * : r3 = saved SPSR
+ *
+ * Returns : r0 = 0 (abort address)
+ * : r1 = 0 (FSR)
+ *
+ * Note: There is no FSR/FAR on !CPU_CP15_MMU cores.
+ * Just fill zero into the registers.
+ */
+ .align 5
+ENTRY(nommu_early_abort)
+ mov r0, #0 @ clear r0, r1 (no FSR/FAR)
+ mov r1, #0
+ mov pc, lr
diff --git a/arch/arm/mm/alignment.c b/arch/arm/mm/alignment.c
index e0d21bbbe7d7..aa109f074dd9 100644
--- a/arch/arm/mm/alignment.c
+++ b/arch/arm/mm/alignment.c
@@ -735,7 +735,7 @@ do_alignment(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
/*
* We got a fault - fix it up, or die.
*/
- do_bad_area(current, current->mm, addr, fsr, regs);
+ do_bad_area(addr, fsr, regs);
return 0;
swp:
diff --git a/arch/arm/mm/cache-v4.S b/arch/arm/mm/cache-v4.S
index b8ad5d58ebe2..b2908063ed6a 100644
--- a/arch/arm/mm/cache-v4.S
+++ b/arch/arm/mm/cache-v4.S
@@ -29,9 +29,13 @@ ENTRY(v4_flush_user_cache_all)
* Clean and invalidate the entire cache.
*/
ENTRY(v4_flush_kern_cache_all)
+#ifdef CPU_CP15
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
mov pc, lr
+#else
+ /* FALLTHROUGH */
+#endif
/*
* flush_user_cache_range(start, end, flags)
@@ -44,9 +48,13 @@ ENTRY(v4_flush_kern_cache_all)
* - flags - vma_area_struct flags describing address space
*/
ENTRY(v4_flush_user_cache_range)
+#ifdef CPU_CP15
mov ip, #0
mcreq p15, 0, ip, c7, c7, 0 @ flush ID cache
mov pc, lr
+#else
+ /* FALLTHROUGH */
+#endif
/*
* coherent_kern_range(start, end)
@@ -108,8 +116,10 @@ ENTRY(v4_dma_inv_range)
* - end - virtual end address
*/
ENTRY(v4_dma_flush_range)
+#ifdef CPU_CP15
mov r0, #0
mcr p15, 0, r0, c7, c7, 0 @ flush ID cache
+#endif
/* FALLTHROUGH */
/*
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
new file mode 100644
index 000000000000..79e800202424
--- /dev/null
+++ b/arch/arm/mm/context.c
@@ -0,0 +1,45 @@
+/*
+ * linux/arch/arm/mm/context.c
+ *
+ * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
+ *
+ * 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/sched.h>
+#include <linux/mm.h>
+
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+
+unsigned int cpu_last_asid = { 1 << ASID_BITS };
+
+/*
+ * We fork()ed a process, and we need a new context for the child
+ * to run in. We reserve version 0 for initial tasks so we will
+ * always allocate an ASID.
+ */
+void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ mm->context.id = 0;
+}
+
+void __new_context(struct mm_struct *mm)
+{
+ unsigned int asid;
+
+ asid = ++cpu_last_asid;
+ if (asid == 0)
+ asid = cpu_last_asid = 1 << ASID_BITS;
+
+ /*
+ * If we've used up all our ASIDs, we need
+ * to start a new version and flush the TLB.
+ */
+ if ((asid & ~ASID_MASK) == 0)
+ flush_tlb_all();
+
+ mm->context.id = asid;
+}
diff --git a/arch/arm/mm/copypage-v4mc.c b/arch/arm/mm/copypage-v4mc.c
index fc69dccdace1..df1645e14b4c 100644
--- a/arch/arm/mm/copypage-v4mc.c
+++ b/arch/arm/mm/copypage-v4mc.c
@@ -20,6 +20,8 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#include "mm.h"
+
/*
* 0xffff8000 to 0xffffffff is reserved for any ARM architecture
* specific hacks for copying pages efficiently.
@@ -27,8 +29,6 @@
#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
L_PTE_CACHEABLE)
-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
-
static DEFINE_SPINLOCK(minicache_lock);
/*
diff --git a/arch/arm/mm/copypage-v6.c b/arch/arm/mm/copypage-v6.c
index 269ce6913ee9..3d0d3a963d20 100644
--- a/arch/arm/mm/copypage-v6.c
+++ b/arch/arm/mm/copypage-v6.c
@@ -17,6 +17,8 @@
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
+#include "mm.h"
+
#if SHMLBA > 16384
#error FIX ME
#endif
@@ -24,8 +26,6 @@
#define from_address (0xffff8000)
#define to_address (0xffffc000)
-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
-
static DEFINE_SPINLOCK(v6_lock);
/*
diff --git a/arch/arm/mm/copypage-xscale.c b/arch/arm/mm/copypage-xscale.c
index 42a6ee255ce0..84ebe0aa379e 100644
--- a/arch/arm/mm/copypage-xscale.c
+++ b/arch/arm/mm/copypage-xscale.c
@@ -20,6 +20,8 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
+#include "mm.h"
+
/*
* 0xffff8000 to 0xffffffff is reserved for any ARM architecture
* specific hacks for copying pages efficiently.
@@ -29,8 +31,6 @@
#define minicache_pgprot __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | \
L_PTE_CACHEABLE)
-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
-
static DEFINE_SPINLOCK(minicache_lock);
/*
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index c5e0622c7765..5e658a874498 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -131,10 +131,11 @@ __do_user_fault(struct task_struct *tsk, unsigned long addr,
force_sig_info(sig, &si, tsk);
}
-void
-do_bad_area(struct task_struct *tsk, struct mm_struct *mm, unsigned long addr,
- unsigned int fsr, struct pt_regs *regs)
+void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->active_mm;
+
/*
* If we are in kernel mode at this point, we
* have no context to handle this fault with.
@@ -170,7 +171,7 @@ good_area:
if (fsr & (1 << 11)) /* write? */
mask = VM_WRITE;
else
- mask = VM_READ|VM_EXEC;
+ mask = VM_READ|VM_EXEC|VM_WRITE;
fault = VM_FAULT_BADACCESS;
if (!(vma->vm_flags & mask))
@@ -197,7 +198,7 @@ survive:
return fault;
}
- if (tsk->pid != 1)
+ if (!is_init(tsk))
goto out;
/*
@@ -319,7 +320,6 @@ static int
do_translation_fault(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
- struct task_struct *tsk;
unsigned int index;
pgd_t *pgd, *pgd_k;
pmd_t *pmd, *pmd_k;
@@ -351,9 +351,7 @@ do_translation_fault(unsigned long addr, unsigned int fsr,
return 0;
bad_area:
- tsk = current;
-
- do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
+ do_bad_area(addr, fsr, regs);
return 0;
}
@@ -364,8 +362,7 @@ bad_area:
static int
do_sect_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
- struct task_struct *tsk = current;
- do_bad_area(tsk, tsk->active_mm, addr, fsr, regs);
+ do_bad_area(addr, fsr, regs);
return 0;
}
diff --git a/arch/arm/mm/fault.h b/arch/arm/mm/fault.h
index 73b59e83227f..49e9e3804de4 100644
--- a/arch/arm/mm/fault.h
+++ b/arch/arm/mm/fault.h
@@ -1,6 +1,3 @@
-void do_bad_area(struct task_struct *tsk, struct mm_struct *mm,
- unsigned long addr, unsigned int fsr, struct pt_regs *regs);
-
-void show_pte(struct mm_struct *mm, unsigned long addr);
+void do_bad_area(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
unsigned long search_exception_table(unsigned long addr);
diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c
index d438ce41cdd5..454205b789d5 100644
--- a/arch/arm/mm/flush.c
+++ b/arch/arm/mm/flush.c
@@ -15,12 +15,12 @@
#include <asm/system.h>
#include <asm/tlbflush.h>
+#include "mm.h"
+
#ifdef CONFIG_CPU_CACHE_VIPT
#define ALIAS_FLUSH_START 0xffff4000
-#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
-
static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr)
{
unsigned long to = ALIAS_FLUSH_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT);
@@ -107,7 +107,7 @@ void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
/* VIPT non-aliasing cache */
if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask) &&
- vma->vm_flags | VM_EXEC) {
+ vma->vm_flags & VM_EXEC) {
unsigned long addr = (unsigned long)kaddr;
/* only flushing the kernel mapping on non-aliasing VIPT */
__cpuc_coherent_kern_range(addr, addr + len);
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index fe3f7f625008..22217fe2650b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -25,10 +25,9 @@
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
-DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+#include "mm.h"
-extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
-extern void _stext, _text, _etext, __data_start, _end, __init_begin, __init_end;
+extern void _text, _etext, __data_start, _end, __init_begin, __init_end;
extern unsigned long phys_initrd_start;
extern unsigned long phys_initrd_size;
@@ -38,12 +37,6 @@ extern unsigned long phys_initrd_size;
*/
static struct meminfo meminfo __initdata = { 0, };
-/*
- * empty_zero_page is a special page that is used for
- * zero-initialized data and COW.
- */
-struct page *empty_zero_page;
-
void show_mem(void)
{
int free = 0, total = 0, reserved = 0;
@@ -83,16 +76,6 @@ void show_mem(void)
printk("%d pages swap cached\n", cached);
}
-static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
-{
- return pmd_offset(pgd, virt);
-}
-
-static inline pmd_t *pmd_off_k(unsigned long virt)
-{
- return pmd_off(pgd_offset_k(virt), virt);
-}
-
#define for_each_nodebank(iter,mi,no) \
for (iter = 0; iter < mi->nr_banks; iter++) \
if (mi->bank[iter].node == no)
@@ -176,62 +159,20 @@ static int __init check_initrd(struct meminfo *mi)
return initrd_node;
}
-/*
- * Reserve the various regions of node 0
- */
-static __init void reserve_node_zero(pg_data_t *pgdat)
+static inline void map_memory_bank(struct membank *bank)
{
- unsigned long res_size = 0;
-
- /*
- * Register the kernel text and data with bootmem.
- * Note that this can only be in node 0.
- */
-#ifdef CONFIG_XIP_KERNEL
- reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
-#else
- reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
-#endif
-
- /*
- * Reserve the page tables. These are already in use,
- * and can only be in node 0.
- */
- reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
- PTRS_PER_PGD * sizeof(pgd_t));
-
- /*
- * Hmm... This should go elsewhere, but we really really need to
- * stop things allocating the low memory; ideally we need a better
- * implementation of GFP_DMA which does not assume that DMA-able
- * memory starts at zero.
- */
- if (machine_is_integrator() || machine_is_cintegrator())
- res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
+#ifdef CONFIG_MMU
+ struct map_desc map;
- /*
- * These should likewise go elsewhere. They pre-reserve the
- * screen memory region at the start of main system memory.
- */
- if (machine_is_edb7211())
- res_size = 0x00020000;
- if (machine_is_p720t())
- res_size = 0x00014000;
+ map.pfn = __phys_to_pfn(bank->start);
+ map.virtual = __phys_to_virt(bank->start);
+ map.length = bank->size;
+ map.type = MT_MEMORY;
-#ifdef CONFIG_SA1111
- /*
- * Because of the SA1111 DMA bug, we want to preserve our
- * precious DMA-able memory...
- */
- res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
+ create_mapping(&map);
#endif
- if (res_size)
- reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
}
-void __init build_mem_type_table(void);
-void __init create_mapping(struct map_desc *md);
-
static unsigned long __init
bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
{
@@ -248,23 +189,18 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
* Calculate the pfn range, and map the memory banks for this node.
*/
for_each_nodebank(i, mi, node) {
+ struct membank *bank = &mi->bank[i];
unsigned long start, end;
- struct map_desc map;
- start = mi->bank[i].start >> PAGE_SHIFT;
- end = (mi->bank[i].start + mi->bank[i].size) >> PAGE_SHIFT;
+ start = bank->start >> PAGE_SHIFT;
+ end = (bank->start + bank->size) >> PAGE_SHIFT;
if (start_pfn > start)
start_pfn = start;
if (end_pfn < end)
end_pfn = end;
- map.pfn = __phys_to_pfn(mi->bank[i].start);
- map.virtual = __phys_to_virt(mi->bank[i].start);
- map.length = mi->bank[i].size;
- map.type = MT_MEMORY;
-
- create_mapping(&map);
+ map_memory_bank(bank);
}
/*
@@ -346,9 +282,9 @@ bootmem_init_node(int node, int initrd_node, struct meminfo *mi)
return end_pfn;
}
-static void __init bootmem_init(struct meminfo *mi)
+void __init bootmem_init(struct meminfo *mi)
{
- unsigned long addr, memend_pfn = 0;
+ unsigned long memend_pfn = 0;
int node, initrd_node, i;
/*
@@ -361,26 +297,6 @@ static void __init bootmem_init(struct meminfo *mi)
memcpy(&meminfo, mi, sizeof(meminfo));
/*
- * Clear out all the mappings below the kernel image.
- */
- for (addr = 0; addr < MODULE_START; addr += PGDIR_SIZE)
- pmd_clear(pmd_off_k(addr));
-#ifdef CONFIG_XIP_KERNEL
- /* The XIP kernel is mapped in the module area -- skip over it */
- addr = ((unsigned long)&_etext + PGDIR_SIZE - 1) & PGDIR_MASK;
-#endif
- for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
- pmd_clear(pmd_off_k(addr));
-
- /*
- * Clear out all the kernel space mappings, except for the first
- * memory bank, up to the end of the vmalloc region.
- */
- for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size);
- addr < VMALLOC_END; addr += PGDIR_SIZE)
- pmd_clear(pmd_off_k(addr));
-
- /*
* Locate which node contains the ramdisk image, if any.
*/
initrd_node = check_initrd(mi);
@@ -413,114 +329,6 @@ static void __init bootmem_init(struct meminfo *mi)
max_pfn = max_low_pfn = memend_pfn - PHYS_PFN_OFFSET;
}
-/*
- * Set up device the mappings. Since we clear out the page tables for all
- * mappings above VMALLOC_END, we will remove any debug device mappings.
- * This means you have to be careful how you debug this function, or any
- * called function. This means you can't use any function or debugging
- * method which may touch any device, otherwise the kernel _will_ crash.
- */
-static void __init devicemaps_init(struct machine_desc *mdesc)
-{
- struct map_desc map;
- unsigned long addr;
- void *vectors;
-
- /*
- * Allocate the vector page early.
- */
- vectors = alloc_bootmem_low_pages(PAGE_SIZE);
- BUG_ON(!vectors);
-
- for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
- pmd_clear(pmd_off_k(addr));
-
- /*
- * Map the kernel if it is XIP.
- * It is always first in the modulearea.
- */
-#ifdef CONFIG_XIP_KERNEL
- map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & PGDIR_MASK);
- map.virtual = MODULE_START;
- map.length = ((unsigned long)&_etext - map.virtual + ~PGDIR_MASK) & PGDIR_MASK;
- map.type = MT_ROM;
- create_mapping(&map);
-#endif
-
- /*
- * Map the cache flushing regions.
- */
-#ifdef FLUSH_BASE
- map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS);
- map.virtual = FLUSH_BASE;
- map.length = SZ_1M;
- map.type = MT_CACHECLEAN;
- create_mapping(&map);
-#endif
-#ifdef FLUSH_BASE_MINICACHE
- map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M);
- map.virtual = FLUSH_BASE_MINICACHE;
- map.length = SZ_1M;
- map.type = MT_MINICLEAN;
- create_mapping(&map);
-#endif
-
- /*
- * Create a mapping for the machine vectors at the high-vectors
- * location (0xffff0000). If we aren't using high-vectors, also
- * create a mapping at the low-vectors virtual address.
- */
- map.pfn = __phys_to_pfn(virt_to_phys(vectors));
- map.virtual = 0xffff0000;
- map.length = PAGE_SIZE;
- map.type = MT_HIGH_VECTORS;
- create_mapping(&map);
-
- if (!vectors_high()) {
- map.virtual = 0;
- map.type = MT_LOW_VECTORS;
- create_mapping(&map);
- }
-
- /*
- * Ask the machine support to map in the statically mapped devices.
- */
- if (mdesc->map_io)
- mdesc->map_io();
-
- /*
- * Finally flush the caches and tlb to ensure that we're in a
- * consistent state wrt the writebuffer. This also ensures that
- * any write-allocated cache lines in the vector page are written
- * back. After this point, we can start to touch devices again.
- */
- local_flush_tlb_all();
- flush_cache_all();
-}
-
-/*
- * paging_init() sets up the page tables, initialises the zone memory
- * maps, and sets up the zero page, bad page and bad page tables.
- */
-void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
-{
- void *zero_page;
-
- build_mem_type_table();
- bootmem_init(mi);
- devicemaps_init(mdesc);
-
- top_pmd = pmd_off_k(0xffff0000);
-
- /*
- * allocate the zero page. Note that we count on this going ok.
- */
- zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
- memzero(zero_page, PAGE_SIZE);
- empty_zero_page = virt_to_page(zero_page);
- flush_dcache_page(empty_zero_page);
-}
-
static inline void free_area(unsigned long addr, unsigned long end, char *s)
{
unsigned int size = (end - addr) >> 10;
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 591fc3187c7f..465440592791 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -361,14 +361,14 @@ __ioremap(unsigned long phys_addr, size_t size, unsigned long flags)
}
EXPORT_SYMBOL(__ioremap);
-void __iounmap(void __iomem *addr)
+void __iounmap(volatile void __iomem *addr)
{
#ifndef CONFIG_SMP
struct vm_struct **p, *tmp;
#endif
unsigned int section_mapping = 0;
- addr = (void __iomem *)(PAGE_MASK & (unsigned long)addr);
+ addr = (volatile void __iomem *)(PAGE_MASK & (unsigned long)addr);
#ifndef CONFIG_SMP
/*
@@ -395,6 +395,6 @@ void __iounmap(void __iomem *addr)
#endif
if (!section_mapping)
- vunmap(addr);
+ vunmap((void __force *)addr);
}
EXPORT_SYMBOL(__iounmap);
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
deleted file mode 100644
index 38769f5862bc..000000000000
--- a/arch/arm/mm/mm-armv.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/*
- * linux/arch/arm/mm/mm-armv.c
- *
- * Copyright (C) 1998-2005 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Page table sludge for ARM v3 and v4 processor architectures.
- */
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/highmem.h>
-#include <linux/nodemask.h>
-
-#include <asm/pgalloc.h>
-#include <asm/page.h>
-#include <asm/setup.h>
-#include <asm/tlbflush.h>
-
-#include <asm/mach/map.h>
-
-#define CPOLICY_UNCACHED 0
-#define CPOLICY_BUFFERED 1
-#define CPOLICY_WRITETHROUGH 2
-#define CPOLICY_WRITEBACK 3
-#define CPOLICY_WRITEALLOC 4
-
-static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
-static unsigned int ecc_mask __initdata = 0;
-pgprot_t pgprot_kernel;
-
-EXPORT_SYMBOL(pgprot_kernel);
-
-pmd_t *top_pmd;
-
-struct cachepolicy {
- const char policy[16];
- unsigned int cr_mask;
- unsigned int pmd;
- unsigned int pte;
-};
-
-static struct cachepolicy cache_policies[] __initdata = {
- {
- .policy = "uncached",
- .cr_mask = CR_W|CR_C,
- .pmd = PMD_SECT_UNCACHED,
- .pte = 0,
- }, {
- .policy = "buffered",
- .cr_mask = CR_C,
- .pmd = PMD_SECT_BUFFERED,
- .pte = PTE_BUFFERABLE,
- }, {
- .policy = "writethrough",
- .cr_mask = 0,
- .pmd = PMD_SECT_WT,
- .pte = PTE_CACHEABLE,
- }, {
- .policy = "writeback",
- .cr_mask = 0,
- .pmd = PMD_SECT_WB,
- .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
- }, {
- .policy = "writealloc",
- .cr_mask = 0,
- .pmd = PMD_SECT_WBWA,
- .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
- }
-};
-
-/*
- * These are useful for identifing cache coherency
- * problems by allowing the cache or the cache and
- * writebuffer to be turned off. (Note: the write
- * buffer should not be on and the cache off).
- */
-static void __init early_cachepolicy(char **p)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
- int len = strlen(cache_policies[i].policy);
-
- if (memcmp(*p, cache_policies[i].policy, len) == 0) {
- cachepolicy = i;
- cr_alignment &= ~cache_policies[i].cr_mask;
- cr_no_alignment &= ~cache_policies[i].cr_mask;
- *p += len;
- break;
- }
- }
- if (i == ARRAY_SIZE(cache_policies))
- printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
- flush_cache_all();
- set_cr(cr_alignment);
-}
-
-static void __init early_nocache(char **__unused)
-{
- char *p = "buffered";
- printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
- early_cachepolicy(&p);
-}
-
-static void __init early_nowrite(char **__unused)
-{
- char *p = "uncached";
- printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
- early_cachepolicy(&p);
-}
-
-static void __init early_ecc(char **p)
-{
- if (memcmp(*p, "on", 2) == 0) {
- ecc_mask = PMD_PROTECTION;
- *p += 2;
- } else if (memcmp(*p, "off", 3) == 0) {
- ecc_mask = 0;
- *p += 3;
- }
-}
-
-__early_param("nocache", early_nocache);
-__early_param("nowb", early_nowrite);
-__early_param("cachepolicy=", early_cachepolicy);
-__early_param("ecc=", early_ecc);
-
-static int __init noalign_setup(char *__unused)
-{
- cr_alignment &= ~CR_A;
- cr_no_alignment &= ~CR_A;
- set_cr(cr_alignment);
- return 1;
-}
-
-__setup("noalign", noalign_setup);
-
-#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
-
-static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
-{
- return pmd_offset(pgd, virt);
-}
-
-static inline pmd_t *pmd_off_k(unsigned long virt)
-{
- return pmd_off(pgd_offset_k(virt), virt);
-}
-
-/*
- * need to get a 16k page for level 1
- */
-pgd_t *get_pgd_slow(struct mm_struct *mm)
-{
- pgd_t *new_pgd, *init_pgd;
- pmd_t *new_pmd, *init_pmd;
- pte_t *new_pte, *init_pte;
-
- new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
- if (!new_pgd)
- goto no_pgd;
-
- memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
-
- /*
- * Copy over the kernel and IO PGD entries
- */
- init_pgd = pgd_offset_k(0);
- memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
- (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
-
- clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
-
- if (!vectors_high()) {
- /*
- * On ARM, first page must always be allocated since it
- * contains the machine vectors.
- */
- new_pmd = pmd_alloc(mm, new_pgd, 0);
- if (!new_pmd)
- goto no_pmd;
-
- new_pte = pte_alloc_map(mm, new_pmd, 0);
- if (!new_pte)
- goto no_pte;
-
- init_pmd = pmd_offset(init_pgd, 0);
- init_pte = pte_offset_map_nested(init_pmd, 0);
- set_pte(new_pte, *init_pte);
- pte_unmap_nested(init_pte);
- pte_unmap(new_pte);
- }
-
- return new_pgd;
-
-no_pte:
- pmd_free(new_pmd);
-no_pmd:
- free_pages((unsigned long)new_pgd, 2);
-no_pgd:
- return NULL;
-}
-
-void free_pgd_slow(pgd_t *pgd)
-{
- pmd_t *pmd;
- struct page *pte;
-
- if (!pgd)
- return;
-
- /* pgd is always present and good */
- pmd = pmd_off(pgd, 0);
- if (pmd_none(*pmd))
- goto free;
- if (pmd_bad(*pmd)) {
- pmd_ERROR(*pmd);
- pmd_clear(pmd);
- goto free;
- }
-
- pte = pmd_page(*pmd);
- pmd_clear(pmd);
- dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
- pte_lock_deinit(pte);
- pte_free(pte);
- pmd_free(pmd);
-free:
- free_pages((unsigned long) pgd, 2);
-}
-
-/*
- * Create a SECTION PGD between VIRT and PHYS in domain
- * DOMAIN with protection PROT. This operates on half-
- * pgdir entry increments.
- */
-static inline void
-alloc_init_section(unsigned long virt, unsigned long phys, int prot)
-{
- pmd_t *pmdp = pmd_off_k(virt);
-
- if (virt & (1 << 20))
- pmdp++;
-
- *pmdp = __pmd(phys | prot);
- flush_pmd_entry(pmdp);
-}
-
-/*
- * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT
- */
-static inline void
-alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
-{
- int i;
-
- for (i = 0; i < 16; i += 1) {
- alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
-
- virt += (PGDIR_SIZE / 2);
- }
-}
-
-/*
- * Add a PAGE mapping between VIRT and PHYS in domain
- * DOMAIN with protection PROT. Note that due to the
- * way we map the PTEs, we must allocate two PTE_SIZE'd
- * blocks - one for the Linux pte table, and one for
- * the hardware pte table.
- */
-static inline void
-alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
-{
- pmd_t *pmdp = pmd_off_k(virt);
- pte_t *ptep;
-
- if (pmd_none(*pmdp)) {
- ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
- sizeof(pte_t));
-
- __pmd_populate(pmdp, __pa(ptep) | prot_l1);
- }
- ptep = pte_offset_kernel(pmdp, virt);
-
- set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
-}
-
-struct mem_types {
- unsigned int prot_pte;
- unsigned int prot_l1;
- unsigned int prot_sect;
- unsigned int domain;
-};
-
-static struct mem_types mem_types[] __initdata = {
- [MT_DEVICE] = {
- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
- L_PTE_WRITE,
- .prot_l1 = PMD_TYPE_TABLE,
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
- PMD_SECT_AP_WRITE,
- .domain = DOMAIN_IO,
- },
- [MT_CACHECLEAN] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
- .domain = DOMAIN_KERNEL,
- },
- [MT_MINICLEAN] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE,
- .domain = DOMAIN_KERNEL,
- },
- [MT_LOW_VECTORS] = {
- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
- L_PTE_EXEC,
- .prot_l1 = PMD_TYPE_TABLE,
- .domain = DOMAIN_USER,
- },
- [MT_HIGH_VECTORS] = {
- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
- L_PTE_USER | L_PTE_EXEC,
- .prot_l1 = PMD_TYPE_TABLE,
- .domain = DOMAIN_USER,
- },
- [MT_MEMORY] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE,
- .domain = DOMAIN_KERNEL,
- },
- [MT_ROM] = {
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
- .domain = DOMAIN_KERNEL,
- },
- [MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */
- .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
- L_PTE_WRITE,
- .prot_l1 = PMD_TYPE_TABLE,
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
- PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
- PMD_SECT_TEX(1),
- .domain = DOMAIN_IO,
- },
- [MT_NONSHARED_DEVICE] = {
- .prot_l1 = PMD_TYPE_TABLE,
- .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_NONSHARED_DEV |
- PMD_SECT_AP_WRITE,
- .domain = DOMAIN_IO,
- }
-};
-
-/*
- * Adjust the PMD section entries according to the CPU in use.
- */
-void __init build_mem_type_table(void)
-{
- struct cachepolicy *cp;
- unsigned int cr = get_cr();
- unsigned int user_pgprot, kern_pgprot;
- int cpu_arch = cpu_architecture();
- int i;
-
-#if defined(CONFIG_CPU_DCACHE_DISABLE)
- if (cachepolicy > CPOLICY_BUFFERED)
- cachepolicy = CPOLICY_BUFFERED;
-#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
- if (cachepolicy > CPOLICY_WRITETHROUGH)
- cachepolicy = CPOLICY_WRITETHROUGH;
-#endif
- if (cpu_arch < CPU_ARCH_ARMv5) {
- if (cachepolicy >= CPOLICY_WRITEALLOC)
- cachepolicy = CPOLICY_WRITEBACK;
- ecc_mask = 0;
- }
-
- /*
- * Xscale must not have PMD bit 4 set for section mappings.
- */
- if (cpu_is_xscale())
- for (i = 0; i < ARRAY_SIZE(mem_types); i++)
- mem_types[i].prot_sect &= ~PMD_BIT4;
-
- /*
- * ARMv5 and lower, excluding Xscale, bit 4 must be set for
- * page tables.
- */
- if (cpu_arch < CPU_ARCH_ARMv6 && !cpu_is_xscale())
- for (i = 0; i < ARRAY_SIZE(mem_types); i++)
- if (mem_types[i].prot_l1)
- mem_types[i].prot_l1 |= PMD_BIT4;
-
- cp = &cache_policies[cachepolicy];
- kern_pgprot = user_pgprot = cp->pte;
-
- /*
- * Enable CPU-specific coherency if supported.
- * (Only available on XSC3 at the moment.)
- */
- if (arch_is_coherent()) {
- if (cpu_is_xsc3()) {
- mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
- mem_types[MT_MEMORY].prot_pte |= L_PTE_COHERENT;
- }
- }
-
- /*
- * ARMv6 and above have extended page tables.
- */
- if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
- /*
- * bit 4 becomes XN which we must clear for the
- * kernel memory mapping.
- */
- mem_types[MT_MEMORY].prot_sect &= ~PMD_SECT_XN;
- mem_types[MT_ROM].prot_sect &= ~PMD_SECT_XN;
-
- /*
- * Mark cache clean areas and XIP ROM read only
- * from SVC mode and no access from userspace.
- */
- mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
- mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
- mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
-
- /*
- * Mark the device area as "shared device"
- */
- mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE;
- mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED;
-
- /*
- * User pages need to be mapped with the ASID
- * (iow, non-global)
- */
- user_pgprot |= L_PTE_ASID;
-
-#ifdef CONFIG_SMP
- /*
- * Mark memory with the "shared" attribute for SMP systems
- */
- user_pgprot |= L_PTE_SHARED;
- kern_pgprot |= L_PTE_SHARED;
- mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
-#endif
- }
-
- for (i = 0; i < 16; i++) {
- unsigned long v = pgprot_val(protection_map[i]);
- v = (v & ~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)) | user_pgprot;
- protection_map[i] = __pgprot(v);
- }
-
- mem_types[MT_LOW_VECTORS].prot_pte |= kern_pgprot;
- mem_types[MT_HIGH_VECTORS].prot_pte |= kern_pgprot;
-
- if (cpu_arch >= CPU_ARCH_ARMv5) {
-#ifndef CONFIG_SMP
- /*
- * Only use write-through for non-SMP systems
- */
- mem_types[MT_LOW_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
- mem_types[MT_HIGH_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
-#endif
- } else {
- mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1);
- }
-
- pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
- L_PTE_DIRTY | L_PTE_WRITE |
- L_PTE_EXEC | kern_pgprot);
-
- mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
- mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
- mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd;
- mem_types[MT_ROM].prot_sect |= cp->pmd;
-
- switch (cp->pmd) {
- case PMD_SECT_WT:
- mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT;
- break;
- case PMD_SECT_WB:
- case PMD_SECT_WBWA:
- mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB;
- break;
- }
- printk("Memory policy: ECC %sabled, Data cache %s\n",
- ecc_mask ? "en" : "dis", cp->policy);
-}
-
-#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
-
-/*
- * Create the page directory entries and any necessary
- * page tables for the mapping specified by `md'. We
- * are able to cope here with varying sizes and address
- * offsets, and we take full advantage of sections and
- * supersections.
- */
-void __init create_mapping(struct map_desc *md)
-{
- unsigned long virt, length;
- int prot_sect, prot_l1, domain;
- pgprot_t prot_pte;
- unsigned long off = (u32)__pfn_to_phys(md->pfn);
-
- if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
- printk(KERN_WARNING "BUG: not creating mapping for "
- "0x%08llx at 0x%08lx in user region\n",
- __pfn_to_phys((u64)md->pfn), md->virtual);
- return;
- }
-
- if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
- md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
- printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
- "overlaps vmalloc space\n",
- __pfn_to_phys((u64)md->pfn), md->virtual);
- }
-
- domain = mem_types[md->type].domain;
- prot_pte = __pgprot(mem_types[md->type].prot_pte);
- prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
- prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
-
- /*
- * Catch 36-bit addresses
- */
- if(md->pfn >= 0x100000) {
- if(domain) {
- printk(KERN_ERR "MM: invalid domain in supersection "
- "mapping for 0x%08llx at 0x%08lx\n",
- __pfn_to_phys((u64)md->pfn), md->virtual);
- return;
- }
- if((md->virtual | md->length | __pfn_to_phys(md->pfn))
- & ~SUPERSECTION_MASK) {
- printk(KERN_ERR "MM: cannot create mapping for "
- "0x%08llx at 0x%08lx invalid alignment\n",
- __pfn_to_phys((u64)md->pfn), md->virtual);
- return;
- }
-
- /*
- * Shift bits [35:32] of address into bits [23:20] of PMD
- * (See ARMv6 spec).
- */
- off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
- }
-
- virt = md->virtual;
- off -= virt;
- length = md->length;
-
- if (mem_types[md->type].prot_l1 == 0 &&
- (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
- printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
- "be mapped using pages, ignoring.\n",
- __pfn_to_phys(md->pfn), md->virtual);
- return;
- }
-
- while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
- alloc_init_page(virt, virt + off, prot_l1, prot_pte);
-
- virt += PAGE_SIZE;
- length -= PAGE_SIZE;
- }
-
- /* N.B. ARMv6 supersections are only defined to work with domain 0.
- * Since domain assignments can in fact be arbitrary, the
- * 'domain == 0' check below is required to insure that ARMv6
- * supersections are only allocated for domain 0 regardless
- * of the actual domain assignments in use.
- */
- if ((cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())
- && domain == 0) {
- /*
- * Align to supersection boundary if !high pages.
- * High pages have already been checked for proper
- * alignment above and they will fail the SUPSERSECTION_MASK
- * check because of the way the address is encoded into
- * offset.
- */
- if (md->pfn <= 0x100000) {
- while ((virt & ~SUPERSECTION_MASK ||
- (virt + off) & ~SUPERSECTION_MASK) &&
- length >= (PGDIR_SIZE / 2)) {
- alloc_init_section(virt, virt + off, prot_sect);
-
- virt += (PGDIR_SIZE / 2);
- length -= (PGDIR_SIZE / 2);
- }
- }
-
- while (length >= SUPERSECTION_SIZE) {
- alloc_init_supersection(virt, virt + off, prot_sect);
-
- virt += SUPERSECTION_SIZE;
- length -= SUPERSECTION_SIZE;
- }
- }
-
- /*
- * A section mapping covers half a "pgdir" entry.
- */
- while (length >= (PGDIR_SIZE / 2)) {
- alloc_init_section(virt, virt + off, prot_sect);
-
- virt += (PGDIR_SIZE / 2);
- length -= (PGDIR_SIZE / 2);
- }
-
- while (length >= PAGE_SIZE) {
- alloc_init_page(virt, virt + off, prot_l1, prot_pte);
-
- virt += PAGE_SIZE;
- length -= PAGE_SIZE;
- }
-}
-
-/*
- * In order to soft-boot, we need to insert a 1:1 mapping in place of
- * the user-mode pages. This will then ensure that we have predictable
- * results when turning the mmu off
- */
-void setup_mm_for_reboot(char mode)
-{
- unsigned long base_pmdval;
- pgd_t *pgd;
- int i;
-
- if (current->mm && current->mm->pgd)
- pgd = current->mm->pgd;
- else
- pgd = init_mm.pgd;
-
- base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
- if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
- base_pmdval |= PMD_BIT4;
-
- for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
- unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
- pmd_t *pmd;
-
- pmd = pmd_off(pgd, i << PGDIR_SHIFT);
- pmd[0] = __pmd(pmdval);
- pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
- flush_pmd_entry(pmd);
- }
-}
-
-/*
- * Create the architecture specific mappings
- */
-void __init iotable_init(struct map_desc *io_desc, int nr)
-{
- int i;
-
- for (i = 0; i < nr; i++)
- create_mapping(io_desc + i);
-}
diff --git a/arch/arm/mm/mm.h b/arch/arm/mm/mm.h
new file mode 100644
index 000000000000..bb2bc9ab6bd3
--- /dev/null
+++ b/arch/arm/mm/mm.h
@@ -0,0 +1,22 @@
+/* the upper-most page table pointer */
+extern pmd_t *top_pmd;
+
+#define TOP_PTE(x) pte_offset_kernel(top_pmd, x)
+
+static inline pmd_t *pmd_off(pgd_t *pgd, unsigned long virt)
+{
+ return pmd_offset(pgd, virt);
+}
+
+static inline pmd_t *pmd_off_k(unsigned long virt)
+{
+ return pmd_off(pgd_offset_k(virt), virt);
+}
+
+struct map_desc;
+struct meminfo;
+struct pglist_data;
+
+void __init create_mapping(struct map_desc *md);
+void __init bootmem_init(struct meminfo *mi);
+void reserve_node_zero(struct pglist_data *pgdat);
diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
index 29e54807c5bc..b0b5f4694070 100644
--- a/arch/arm/mm/mmap.c
+++ b/arch/arm/mm/mmap.c
@@ -114,3 +114,25 @@ full_search:
}
}
+
+/*
+ * You really shouldn't be using read() or write() on /dev/mem. This
+ * might go away in the future.
+ */
+int valid_phys_addr_range(unsigned long addr, size_t size)
+{
+ if (addr + size > __pa(high_memory))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * We don't use supersection mappings for mmap() on /dev/mem, which
+ * means that we can't map the memory area above the 4G barrier into
+ * userspace.
+ */
+int valid_mmap_phys_addr_range(unsigned long pfn, size_t size)
+{
+ return !(pfn + (size >> PAGE_SHIFT) > 0x00100000);
+}
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 0d90227a0a32..f866bf6b97d4 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -1,45 +1,771 @@
/*
* linux/arch/arm/mm/mmu.c
*
- * Copyright (C) 2002-2003 Deep Blue Solutions Ltd, all rights reserved.
+ * Copyright (C) 1995-2005 Russell King
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
+#include <linux/bootmem.h>
+#include <linux/mman.h>
+#include <linux/nodemask.h>
-#include <asm/mmu_context.h>
-#include <asm/tlbflush.h>
+#include <asm/mach-types.h>
+#include <asm/setup.h>
+#include <asm/sizes.h>
+#include <asm/tlb.h>
-unsigned int cpu_last_asid = { 1 << ASID_BITS };
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include "mm.h"
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+
+extern void _stext, _etext, __data_start, _end;
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+
+/*
+ * empty_zero_page is a special page that is used for
+ * zero-initialized data and COW.
+ */
+struct page *empty_zero_page;
/*
- * We fork()ed a process, and we need a new context for the child
- * to run in. We reserve version 0 for initial tasks so we will
- * always allocate an ASID.
+ * The pmd table for the upper-most set of pages.
*/
-void __init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+pmd_t *top_pmd;
+
+#define CPOLICY_UNCACHED 0
+#define CPOLICY_BUFFERED 1
+#define CPOLICY_WRITETHROUGH 2
+#define CPOLICY_WRITEBACK 3
+#define CPOLICY_WRITEALLOC 4
+
+static unsigned int cachepolicy __initdata = CPOLICY_WRITEBACK;
+static unsigned int ecc_mask __initdata = 0;
+pgprot_t pgprot_kernel;
+
+EXPORT_SYMBOL(pgprot_kernel);
+
+struct cachepolicy {
+ const char policy[16];
+ unsigned int cr_mask;
+ unsigned int pmd;
+ unsigned int pte;
+};
+
+static struct cachepolicy cache_policies[] __initdata = {
+ {
+ .policy = "uncached",
+ .cr_mask = CR_W|CR_C,
+ .pmd = PMD_SECT_UNCACHED,
+ .pte = 0,
+ }, {
+ .policy = "buffered",
+ .cr_mask = CR_C,
+ .pmd = PMD_SECT_BUFFERED,
+ .pte = PTE_BUFFERABLE,
+ }, {
+ .policy = "writethrough",
+ .cr_mask = 0,
+ .pmd = PMD_SECT_WT,
+ .pte = PTE_CACHEABLE,
+ }, {
+ .policy = "writeback",
+ .cr_mask = 0,
+ .pmd = PMD_SECT_WB,
+ .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
+ }, {
+ .policy = "writealloc",
+ .cr_mask = 0,
+ .pmd = PMD_SECT_WBWA,
+ .pte = PTE_BUFFERABLE|PTE_CACHEABLE,
+ }
+};
+
+/*
+ * These are useful for identifing cache coherency
+ * problems by allowing the cache or the cache and
+ * writebuffer to be turned off. (Note: the write
+ * buffer should not be on and the cache off).
+ */
+static void __init early_cachepolicy(char **p)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cache_policies); i++) {
+ int len = strlen(cache_policies[i].policy);
+
+ if (memcmp(*p, cache_policies[i].policy, len) == 0) {
+ cachepolicy = i;
+ cr_alignment &= ~cache_policies[i].cr_mask;
+ cr_no_alignment &= ~cache_policies[i].cr_mask;
+ *p += len;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(cache_policies))
+ printk(KERN_ERR "ERROR: unknown or unsupported cache policy\n");
+ flush_cache_all();
+ set_cr(cr_alignment);
+}
+__early_param("cachepolicy=", early_cachepolicy);
+
+static void __init early_nocache(char **__unused)
+{
+ char *p = "buffered";
+ printk(KERN_WARNING "nocache is deprecated; use cachepolicy=%s\n", p);
+ early_cachepolicy(&p);
+}
+__early_param("nocache", early_nocache);
+
+static void __init early_nowrite(char **__unused)
+{
+ char *p = "uncached";
+ printk(KERN_WARNING "nowb is deprecated; use cachepolicy=%s\n", p);
+ early_cachepolicy(&p);
+}
+__early_param("nowb", early_nowrite);
+
+static void __init early_ecc(char **p)
+{
+ if (memcmp(*p, "on", 2) == 0) {
+ ecc_mask = PMD_PROTECTION;
+ *p += 2;
+ } else if (memcmp(*p, "off", 3) == 0) {
+ ecc_mask = 0;
+ *p += 3;
+ }
+}
+__early_param("ecc=", early_ecc);
+
+static int __init noalign_setup(char *__unused)
{
- mm->context.id = 0;
+ cr_alignment &= ~CR_A;
+ cr_no_alignment &= ~CR_A;
+ set_cr(cr_alignment);
+ return 1;
}
+__setup("noalign", noalign_setup);
+
+struct mem_types {
+ unsigned int prot_pte;
+ unsigned int prot_l1;
+ unsigned int prot_sect;
+ unsigned int domain;
+};
-void __new_context(struct mm_struct *mm)
+static struct mem_types mem_types[] __initdata = {
+ [MT_DEVICE] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_WRITE,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
+ PMD_SECT_AP_WRITE,
+ .domain = DOMAIN_IO,
+ },
+ [MT_CACHECLEAN] = {
+ .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+ .domain = DOMAIN_KERNEL,
+ },
+ [MT_MINICLEAN] = {
+ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_MINICACHE,
+ .domain = DOMAIN_KERNEL,
+ },
+ [MT_LOW_VECTORS] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_EXEC,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .domain = DOMAIN_USER,
+ },
+ [MT_HIGH_VECTORS] = {
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_USER | L_PTE_EXEC,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .domain = DOMAIN_USER,
+ },
+ [MT_MEMORY] = {
+ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE,
+ .domain = DOMAIN_KERNEL,
+ },
+ [MT_ROM] = {
+ .prot_sect = PMD_TYPE_SECT | PMD_BIT4,
+ .domain = DOMAIN_KERNEL,
+ },
+ [MT_IXP2000_DEVICE] = { /* IXP2400 requires XCB=101 for on-chip I/O */
+ .prot_pte = L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY |
+ L_PTE_WRITE,
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_UNCACHED |
+ PMD_SECT_AP_WRITE | PMD_SECT_BUFFERABLE |
+ PMD_SECT_TEX(1),
+ .domain = DOMAIN_IO,
+ },
+ [MT_NONSHARED_DEVICE] = {
+ .prot_l1 = PMD_TYPE_TABLE,
+ .prot_sect = PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_NONSHARED_DEV |
+ PMD_SECT_AP_WRITE,
+ .domain = DOMAIN_IO,
+ }
+};
+
+/*
+ * Adjust the PMD section entries according to the CPU in use.
+ */
+static void __init build_mem_type_table(void)
{
- unsigned int asid;
+ struct cachepolicy *cp;
+ unsigned int cr = get_cr();
+ unsigned int user_pgprot, kern_pgprot;
+ int cpu_arch = cpu_architecture();
+ int i;
- asid = ++cpu_last_asid;
- if (asid == 0)
- asid = cpu_last_asid = 1 << ASID_BITS;
+#if defined(CONFIG_CPU_DCACHE_DISABLE)
+ if (cachepolicy > CPOLICY_BUFFERED)
+ cachepolicy = CPOLICY_BUFFERED;
+#elif defined(CONFIG_CPU_DCACHE_WRITETHROUGH)
+ if (cachepolicy > CPOLICY_WRITETHROUGH)
+ cachepolicy = CPOLICY_WRITETHROUGH;
+#endif
+ if (cpu_arch < CPU_ARCH_ARMv5) {
+ if (cachepolicy >= CPOLICY_WRITEALLOC)
+ cachepolicy = CPOLICY_WRITEBACK;
+ ecc_mask = 0;
+ }
+
+ /*
+ * Xscale must not have PMD bit 4 set for section mappings.
+ */
+ if (cpu_is_xscale())
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++)
+ mem_types[i].prot_sect &= ~PMD_BIT4;
/*
- * If we've used up all our ASIDs, we need
- * to start a new version and flush the TLB.
+ * ARMv5 and lower, excluding Xscale, bit 4 must be set for
+ * page tables.
*/
- if ((asid & ~ASID_MASK) == 0)
- flush_tlb_all();
+ if (cpu_arch < CPU_ARCH_ARMv6 && !cpu_is_xscale())
+ for (i = 0; i < ARRAY_SIZE(mem_types); i++)
+ if (mem_types[i].prot_l1)
+ mem_types[i].prot_l1 |= PMD_BIT4;
+
+ cp = &cache_policies[cachepolicy];
+ kern_pgprot = user_pgprot = cp->pte;
+
+ /*
+ * Enable CPU-specific coherency if supported.
+ * (Only available on XSC3 at the moment.)
+ */
+ if (arch_is_coherent()) {
+ if (cpu_is_xsc3()) {
+ mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+ mem_types[MT_MEMORY].prot_pte |= L_PTE_COHERENT;
+ }
+ }
+
+ /*
+ * ARMv6 and above have extended page tables.
+ */
+ if (cpu_arch >= CPU_ARCH_ARMv6 && (cr & CR_XP)) {
+ /*
+ * bit 4 becomes XN which we must clear for the
+ * kernel memory mapping.
+ */
+ mem_types[MT_MEMORY].prot_sect &= ~PMD_SECT_XN;
+ mem_types[MT_ROM].prot_sect &= ~PMD_SECT_XN;
+
+ /*
+ * Mark cache clean areas and XIP ROM read only
+ * from SVC mode and no access from userspace.
+ */
+ mem_types[MT_ROM].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+ mem_types[MT_MINICLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+ mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_APX|PMD_SECT_AP_WRITE;
+
+ /*
+ * Mark the device area as "shared device"
+ */
+ mem_types[MT_DEVICE].prot_pte |= L_PTE_BUFFERABLE;
+ mem_types[MT_DEVICE].prot_sect |= PMD_SECT_BUFFERED;
+
+ /*
+ * User pages need to be mapped with the ASID
+ * (iow, non-global)
+ */
+ user_pgprot |= L_PTE_ASID;
+
+#ifdef CONFIG_SMP
+ /*
+ * Mark memory with the "shared" attribute for SMP systems
+ */
+ user_pgprot |= L_PTE_SHARED;
+ kern_pgprot |= L_PTE_SHARED;
+ mem_types[MT_MEMORY].prot_sect |= PMD_SECT_S;
+#endif
+ }
+
+ for (i = 0; i < 16; i++) {
+ unsigned long v = pgprot_val(protection_map[i]);
+ v = (v & ~(L_PTE_BUFFERABLE|L_PTE_CACHEABLE)) | user_pgprot;
+ protection_map[i] = __pgprot(v);
+ }
+
+ mem_types[MT_LOW_VECTORS].prot_pte |= kern_pgprot;
+ mem_types[MT_HIGH_VECTORS].prot_pte |= kern_pgprot;
+
+ if (cpu_arch >= CPU_ARCH_ARMv5) {
+#ifndef CONFIG_SMP
+ /*
+ * Only use write-through for non-SMP systems
+ */
+ mem_types[MT_LOW_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
+ mem_types[MT_HIGH_VECTORS].prot_pte &= ~L_PTE_BUFFERABLE;
+#endif
+ } else {
+ mem_types[MT_MINICLEAN].prot_sect &= ~PMD_SECT_TEX(1);
+ }
+
+ pgprot_kernel = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG |
+ L_PTE_DIRTY | L_PTE_WRITE |
+ L_PTE_EXEC | kern_pgprot);
+
+ mem_types[MT_LOW_VECTORS].prot_l1 |= ecc_mask;
+ mem_types[MT_HIGH_VECTORS].prot_l1 |= ecc_mask;
+ mem_types[MT_MEMORY].prot_sect |= ecc_mask | cp->pmd;
+ mem_types[MT_ROM].prot_sect |= cp->pmd;
+
+ switch (cp->pmd) {
+ case PMD_SECT_WT:
+ mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WT;
+ break;
+ case PMD_SECT_WB:
+ case PMD_SECT_WBWA:
+ mem_types[MT_CACHECLEAN].prot_sect |= PMD_SECT_WB;
+ break;
+ }
+ printk("Memory policy: ECC %sabled, Data cache %s\n",
+ ecc_mask ? "en" : "dis", cp->policy);
+}
+
+#define vectors_base() (vectors_high() ? 0xffff0000 : 0)
+
+/*
+ * Create a SECTION PGD between VIRT and PHYS in domain
+ * DOMAIN with protection PROT. This operates on half-
+ * pgdir entry increments.
+ */
+static inline void
+alloc_init_section(unsigned long virt, unsigned long phys, int prot)
+{
+ pmd_t *pmdp = pmd_off_k(virt);
+
+ if (virt & (1 << 20))
+ pmdp++;
+
+ *pmdp = __pmd(phys | prot);
+ flush_pmd_entry(pmdp);
+}
+
+/*
+ * Create a SUPER SECTION PGD between VIRT and PHYS with protection PROT
+ */
+static inline void
+alloc_init_supersection(unsigned long virt, unsigned long phys, int prot)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 1) {
+ alloc_init_section(virt, phys, prot | PMD_SECT_SUPER);
+
+ virt += (PGDIR_SIZE / 2);
+ }
+}
+
+/*
+ * Add a PAGE mapping between VIRT and PHYS in domain
+ * DOMAIN with protection PROT. Note that due to the
+ * way we map the PTEs, we must allocate two PTE_SIZE'd
+ * blocks - one for the Linux pte table, and one for
+ * the hardware pte table.
+ */
+static inline void
+alloc_init_page(unsigned long virt, unsigned long phys, unsigned int prot_l1, pgprot_t prot)
+{
+ pmd_t *pmdp = pmd_off_k(virt);
+ pte_t *ptep;
+
+ if (pmd_none(*pmdp)) {
+ ptep = alloc_bootmem_low_pages(2 * PTRS_PER_PTE *
+ sizeof(pte_t));
+
+ __pmd_populate(pmdp, __pa(ptep) | prot_l1);
+ }
+ ptep = pte_offset_kernel(pmdp, virt);
+
+ set_pte(ptep, pfn_pte(phys >> PAGE_SHIFT, prot));
+}
+
+/*
+ * Create the page directory entries and any necessary
+ * page tables for the mapping specified by `md'. We
+ * are able to cope here with varying sizes and address
+ * offsets, and we take full advantage of sections and
+ * supersections.
+ */
+void __init create_mapping(struct map_desc *md)
+{
+ unsigned long virt, length;
+ int prot_sect, prot_l1, domain;
+ pgprot_t prot_pte;
+ unsigned long off = (u32)__pfn_to_phys(md->pfn);
+
+ if (md->virtual != vectors_base() && md->virtual < TASK_SIZE) {
+ printk(KERN_WARNING "BUG: not creating mapping for "
+ "0x%08llx at 0x%08lx in user region\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+
+ if ((md->type == MT_DEVICE || md->type == MT_ROM) &&
+ md->virtual >= PAGE_OFFSET && md->virtual < VMALLOC_END) {
+ printk(KERN_WARNING "BUG: mapping for 0x%08llx at 0x%08lx "
+ "overlaps vmalloc space\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ }
+
+ domain = mem_types[md->type].domain;
+ prot_pte = __pgprot(mem_types[md->type].prot_pte);
+ prot_l1 = mem_types[md->type].prot_l1 | PMD_DOMAIN(domain);
+ prot_sect = mem_types[md->type].prot_sect | PMD_DOMAIN(domain);
+
+ /*
+ * Catch 36-bit addresses
+ */
+ if(md->pfn >= 0x100000) {
+ if(domain) {
+ printk(KERN_ERR "MM: invalid domain in supersection "
+ "mapping for 0x%08llx at 0x%08lx\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+ if((md->virtual | md->length | __pfn_to_phys(md->pfn))
+ & ~SUPERSECTION_MASK) {
+ printk(KERN_ERR "MM: cannot create mapping for "
+ "0x%08llx at 0x%08lx invalid alignment\n",
+ __pfn_to_phys((u64)md->pfn), md->virtual);
+ return;
+ }
+
+ /*
+ * Shift bits [35:32] of address into bits [23:20] of PMD
+ * (See ARMv6 spec).
+ */
+ off |= (((md->pfn >> (32 - PAGE_SHIFT)) & 0xF) << 20);
+ }
+
+ virt = md->virtual;
+ off -= virt;
+ length = md->length;
+
+ if (mem_types[md->type].prot_l1 == 0 &&
+ (virt & 0xfffff || (virt + off) & 0xfffff || (virt + length) & 0xfffff)) {
+ printk(KERN_WARNING "BUG: map for 0x%08lx at 0x%08lx can not "
+ "be mapped using pages, ignoring.\n",
+ __pfn_to_phys(md->pfn), md->virtual);
+ return;
+ }
+
+ while ((virt & 0xfffff || (virt + off) & 0xfffff) && length >= PAGE_SIZE) {
+ alloc_init_page(virt, virt + off, prot_l1, prot_pte);
+
+ virt += PAGE_SIZE;
+ length -= PAGE_SIZE;
+ }
+
+ /* N.B. ARMv6 supersections are only defined to work with domain 0.
+ * Since domain assignments can in fact be arbitrary, the
+ * 'domain == 0' check below is required to insure that ARMv6
+ * supersections are only allocated for domain 0 regardless
+ * of the actual domain assignments in use.
+ */
+ if ((cpu_architecture() >= CPU_ARCH_ARMv6 || cpu_is_xsc3())
+ && domain == 0) {
+ /*
+ * Align to supersection boundary if !high pages.
+ * High pages have already been checked for proper
+ * alignment above and they will fail the SUPSERSECTION_MASK
+ * check because of the way the address is encoded into
+ * offset.
+ */
+ if (md->pfn <= 0x100000) {
+ while ((virt & ~SUPERSECTION_MASK ||
+ (virt + off) & ~SUPERSECTION_MASK) &&
+ length >= (PGDIR_SIZE / 2)) {
+ alloc_init_section(virt, virt + off, prot_sect);
+
+ virt += (PGDIR_SIZE / 2);
+ length -= (PGDIR_SIZE / 2);
+ }
+ }
+
+ while (length >= SUPERSECTION_SIZE) {
+ alloc_init_supersection(virt, virt + off, prot_sect);
+
+ virt += SUPERSECTION_SIZE;
+ length -= SUPERSECTION_SIZE;
+ }
+ }
+
+ /*
+ * A section mapping covers half a "pgdir" entry.
+ */
+ while (length >= (PGDIR_SIZE / 2)) {
+ alloc_init_section(virt, virt + off, prot_sect);
+
+ virt += (PGDIR_SIZE / 2);
+ length -= (PGDIR_SIZE / 2);
+ }
+
+ while (length >= PAGE_SIZE) {
+ alloc_init_page(virt, virt + off, prot_l1, prot_pte);
+
+ virt += PAGE_SIZE;
+ length -= PAGE_SIZE;
+ }
+}
+
+/*
+ * Create the architecture specific mappings
+ */
+void __init iotable_init(struct map_desc *io_desc, int nr)
+{
+ int i;
+
+ for (i = 0; i < nr; i++)
+ create_mapping(io_desc + i);
+}
+
+static inline void prepare_page_table(struct meminfo *mi)
+{
+ unsigned long addr;
+
+ /*
+ * Clear out all the mappings below the kernel image.
+ */
+ for (addr = 0; addr < MODULE_START; addr += PGDIR_SIZE)
+ pmd_clear(pmd_off_k(addr));
+
+#ifdef CONFIG_XIP_KERNEL
+ /* The XIP kernel is mapped in the module area -- skip over it */
+ addr = ((unsigned long)&_etext + PGDIR_SIZE - 1) & PGDIR_MASK;
+#endif
+ for ( ; addr < PAGE_OFFSET; addr += PGDIR_SIZE)
+ pmd_clear(pmd_off_k(addr));
+
+ /*
+ * Clear out all the kernel space mappings, except for the first
+ * memory bank, up to the end of the vmalloc region.
+ */
+ for (addr = __phys_to_virt(mi->bank[0].start + mi->bank[0].size);
+ addr < VMALLOC_END; addr += PGDIR_SIZE)
+ pmd_clear(pmd_off_k(addr));
+}
+
+/*
+ * Reserve the various regions of node 0
+ */
+void __init reserve_node_zero(pg_data_t *pgdat)
+{
+ unsigned long res_size = 0;
+
+ /*
+ * Register the kernel text and data with bootmem.
+ * Note that this can only be in node 0.
+ */
+#ifdef CONFIG_XIP_KERNEL
+ reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
+#else
+ reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
+#endif
+
+ /*
+ * Reserve the page tables. These are already in use,
+ * and can only be in node 0.
+ */
+ reserve_bootmem_node(pgdat, __pa(swapper_pg_dir),
+ PTRS_PER_PGD * sizeof(pgd_t));
+
+ /*
+ * Hmm... This should go elsewhere, but we really really need to
+ * stop things allocating the low memory; ideally we need a better
+ * implementation of GFP_DMA which does not assume that DMA-able
+ * memory starts at zero.
+ */
+ if (machine_is_integrator() || machine_is_cintegrator())
+ res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
+
+ /*
+ * These should likewise go elsewhere. They pre-reserve the
+ * screen memory region at the start of main system memory.
+ */
+ if (machine_is_edb7211())
+ res_size = 0x00020000;
+ if (machine_is_p720t())
+ res_size = 0x00014000;
+
+#ifdef CONFIG_SA1111
+ /*
+ * Because of the SA1111 DMA bug, we want to preserve our
+ * precious DMA-able memory...
+ */
+ res_size = __pa(swapper_pg_dir) - PHYS_OFFSET;
+#endif
+ if (res_size)
+ reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
+}
+
+/*
+ * Set up device the mappings. Since we clear out the page tables for all
+ * mappings above VMALLOC_END, we will remove any debug device mappings.
+ * This means you have to be careful how you debug this function, or any
+ * called function. This means you can't use any function or debugging
+ * method which may touch any device, otherwise the kernel _will_ crash.
+ */
+static void __init devicemaps_init(struct machine_desc *mdesc)
+{
+ struct map_desc map;
+ unsigned long addr;
+ void *vectors;
+
+ /*
+ * Allocate the vector page early.
+ */
+ vectors = alloc_bootmem_low_pages(PAGE_SIZE);
+ BUG_ON(!vectors);
+
+ for (addr = VMALLOC_END; addr; addr += PGDIR_SIZE)
+ pmd_clear(pmd_off_k(addr));
+
+ /*
+ * Map the kernel if it is XIP.
+ * It is always first in the modulearea.
+ */
+#ifdef CONFIG_XIP_KERNEL
+ map.pfn = __phys_to_pfn(CONFIG_XIP_PHYS_ADDR & SECTION_MASK);
+ map.virtual = MODULE_START;
+ map.length = ((unsigned long)&_etext - map.virtual + ~SECTION_MASK) & SECTION_MASK;
+ map.type = MT_ROM;
+ create_mapping(&map);
+#endif
+
+ /*
+ * Map the cache flushing regions.
+ */
+#ifdef FLUSH_BASE
+ map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS);
+ map.virtual = FLUSH_BASE;
+ map.length = SZ_1M;
+ map.type = MT_CACHECLEAN;
+ create_mapping(&map);
+#endif
+#ifdef FLUSH_BASE_MINICACHE
+ map.pfn = __phys_to_pfn(FLUSH_BASE_PHYS + SZ_1M);
+ map.virtual = FLUSH_BASE_MINICACHE;
+ map.length = SZ_1M;
+ map.type = MT_MINICLEAN;
+ create_mapping(&map);
+#endif
+
+ /*
+ * Create a mapping for the machine vectors at the high-vectors
+ * location (0xffff0000). If we aren't using high-vectors, also
+ * create a mapping at the low-vectors virtual address.
+ */
+ map.pfn = __phys_to_pfn(virt_to_phys(vectors));
+ map.virtual = 0xffff0000;
+ map.length = PAGE_SIZE;
+ map.type = MT_HIGH_VECTORS;
+ create_mapping(&map);
+
+ if (!vectors_high()) {
+ map.virtual = 0;
+ map.type = MT_LOW_VECTORS;
+ create_mapping(&map);
+ }
+
+ /*
+ * Ask the machine support to map in the statically mapped devices.
+ */
+ if (mdesc->map_io)
+ mdesc->map_io();
+
+ /*
+ * Finally flush the caches and tlb to ensure that we're in a
+ * consistent state wrt the writebuffer. This also ensures that
+ * any write-allocated cache lines in the vector page are written
+ * back. After this point, we can start to touch devices again.
+ */
+ local_flush_tlb_all();
+ flush_cache_all();
+}
+
+/*
+ * paging_init() sets up the page tables, initialises the zone memory
+ * maps, and sets up the zero page, bad page and bad page tables.
+ */
+void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
+{
+ void *zero_page;
+
+ build_mem_type_table();
+ prepare_page_table(mi);
+ bootmem_init(mi);
+ devicemaps_init(mdesc);
+
+ top_pmd = pmd_off_k(0xffff0000);
+
+ /*
+ * allocate the zero page. Note that we count on this going ok.
+ */
+ zero_page = alloc_bootmem_low_pages(PAGE_SIZE);
+ memzero(zero_page, PAGE_SIZE);
+ empty_zero_page = virt_to_page(zero_page);
+ flush_dcache_page(empty_zero_page);
+}
+
+/*
+ * In order to soft-boot, we need to insert a 1:1 mapping in place of
+ * the user-mode pages. This will then ensure that we have predictable
+ * results when turning the mmu off
+ */
+void setup_mm_for_reboot(char mode)
+{
+ unsigned long base_pmdval;
+ pgd_t *pgd;
+ int i;
+
+ if (current->mm && current->mm->pgd)
+ pgd = current->mm->pgd;
+ else
+ pgd = init_mm.pgd;
+
+ base_pmdval = PMD_SECT_AP_WRITE | PMD_SECT_AP_READ | PMD_TYPE_SECT;
+ if (cpu_architecture() <= CPU_ARCH_ARMv5TEJ && !cpu_is_xscale())
+ base_pmdval |= PMD_BIT4;
+
+ for (i = 0; i < FIRST_USER_PGD_NR + USER_PTRS_PER_PGD; i++, pgd++) {
+ unsigned long pmdval = (i << PGDIR_SHIFT) | base_pmdval;
+ pmd_t *pmd;
- mm->context.id = asid;
+ pmd = pmd_off(pgd, i << PGDIR_SHIFT);
+ pmd[0] = __pmd(pmdval);
+ pmd[1] = __pmd(pmdval + (1 << (PGDIR_SHIFT - 1)));
+ flush_pmd_entry(pmd);
+ }
}
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c
index 1464ed817b5d..d0e66424a597 100644
--- a/arch/arm/mm/nommu.c
+++ b/arch/arm/mm/nommu.c
@@ -11,6 +11,49 @@
#include <asm/io.h>
#include <asm/page.h>
+#include "mm.h"
+
+extern void _stext, __data_start, _end;
+
+/*
+ * Reserve the various regions of node 0
+ */
+void __init reserve_node_zero(pg_data_t *pgdat)
+{
+ /*
+ * Register the kernel text and data with bootmem.
+ * Note that this can only be in node 0.
+ */
+#ifdef CONFIG_XIP_KERNEL
+ reserve_bootmem_node(pgdat, __pa(&__data_start), &_end - &__data_start);
+#else
+ reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext);
+#endif
+
+ /*
+ * Register the exception vector page.
+ * some architectures which the DRAM is the exception vector to trap,
+ * alloc_page breaks with error, although it is not NULL, but "0."
+ */
+ reserve_bootmem_node(pgdat, CONFIG_VECTORS_BASE, PAGE_SIZE);
+}
+
+/*
+ * paging_init() sets up the page tables, initialises the zone memory
+ * maps, and sets up the zero page, bad page and bad page tables.
+ */
+void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
+{
+ bootmem_init(mi);
+}
+
+/*
+ * We don't need to do anything here for nommu machines.
+ */
+void setup_mm_for_reboot(char mode)
+{
+}
+
void flush_dcache_page(struct page *page)
{
__cpuc_flush_dcache_page(page_address(page));
diff --git a/arch/arm/mm/pgd.c b/arch/arm/mm/pgd.c
new file mode 100644
index 000000000000..20c1b0df75f2
--- /dev/null
+++ b/arch/arm/mm/pgd.c
@@ -0,0 +1,101 @@
+/*
+ * linux/arch/arm/mm/pgd.c
+ *
+ * Copyright (C) 1998-2005 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/mm.h>
+#include <linux/highmem.h>
+
+#include <asm/pgalloc.h>
+#include <asm/page.h>
+#include <asm/tlbflush.h>
+
+#include "mm.h"
+
+#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD)
+
+/*
+ * need to get a 16k page for level 1
+ */
+pgd_t *get_pgd_slow(struct mm_struct *mm)
+{
+ pgd_t *new_pgd, *init_pgd;
+ pmd_t *new_pmd, *init_pmd;
+ pte_t *new_pte, *init_pte;
+
+ new_pgd = (pgd_t *)__get_free_pages(GFP_KERNEL, 2);
+ if (!new_pgd)
+ goto no_pgd;
+
+ memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
+
+ /*
+ * Copy over the kernel and IO PGD entries
+ */
+ init_pgd = pgd_offset_k(0);
+ memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+ (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
+
+ clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
+
+ if (!vectors_high()) {
+ /*
+ * On ARM, first page must always be allocated since it
+ * contains the machine vectors.
+ */
+ new_pmd = pmd_alloc(mm, new_pgd, 0);
+ if (!new_pmd)
+ goto no_pmd;
+
+ new_pte = pte_alloc_map(mm, new_pmd, 0);
+ if (!new_pte)
+ goto no_pte;
+
+ init_pmd = pmd_offset(init_pgd, 0);
+ init_pte = pte_offset_map_nested(init_pmd, 0);
+ set_pte(new_pte, *init_pte);
+ pte_unmap_nested(init_pte);
+ pte_unmap(new_pte);
+ }
+
+ return new_pgd;
+
+no_pte:
+ pmd_free(new_pmd);
+no_pmd:
+ free_pages((unsigned long)new_pgd, 2);
+no_pgd:
+ return NULL;
+}
+
+void free_pgd_slow(pgd_t *pgd)
+{
+ pmd_t *pmd;
+ struct page *pte;
+
+ if (!pgd)
+ return;
+
+ /* pgd is always present and good */
+ pmd = pmd_off(pgd, 0);
+ if (pmd_none(*pmd))
+ goto free;
+ if (pmd_bad(*pmd)) {
+ pmd_ERROR(*pmd);
+ pmd_clear(pmd);
+ goto free;
+ }
+
+ pte = pmd_page(*pmd);
+ pmd_clear(pmd);
+ dec_zone_page_state(virt_to_page((unsigned long *)pgd), NR_PAGETABLE);
+ pte_lock_deinit(pte);
+ pte_free(pte);
+ pmd_free(pmd);
+free:
+ free_pages((unsigned long) pgd, 2);
+}
diff --git a/arch/arm/mm/proc-arm740.S b/arch/arm/mm/proc-arm740.S
new file mode 100644
index 000000000000..40713818a87b
--- /dev/null
+++ b/arch/arm/mm/proc-arm740.S
@@ -0,0 +1,174 @@
+/*
+ * linux/arch/arm/mm/arm740.S: utility functions for ARM740
+ *
+ * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi@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.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+#include <asm/procinfo.h>
+#include <asm/ptrace.h>
+
+ .text
+/*
+ * cpu_arm740_proc_init()
+ * cpu_arm740_do_idle()
+ * cpu_arm740_dcache_clean_area()
+ * cpu_arm740_switch_mm()
+ *
+ * These are not required.
+ */
+ENTRY(cpu_arm740_proc_init)
+ENTRY(cpu_arm740_do_idle)
+ENTRY(cpu_arm740_dcache_clean_area)
+ENTRY(cpu_arm740_switch_mm)
+ mov pc, lr
+
+/*
+ * cpu_arm740_proc_fin()
+ */
+ENTRY(cpu_arm740_proc_fin)
+ stmfd sp!, {lr}
+ mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+ msr cpsr_c, ip
+ mrc p15, 0, r0, c1, c0, 0
+ bic r0, r0, #0x3f000000 @ bank/f/lock/s
+ bic r0, r0, #0x0000000c @ w-buffer/cache
+ mcr p15, 0, r0, c1, c0, 0 @ disable caches
+ mcr p15, 0, r0, c7, c0, 0 @ invalidate cache
+ ldmfd sp!, {pc}
+
+/*
+ * cpu_arm740_reset(loc)
+ * Params : r0 = address to jump to
+ * Notes : This sets up everything for a reset
+ */
+ENTRY(cpu_arm740_reset)
+ mov ip, #0
+ mcr p15, 0, ip, c7, c0, 0 @ invalidate cache
+ mrc p15, 0, ip, c1, c0, 0 @ get ctrl register
+ bic ip, ip, #0x0000000c @ ............wc..
+ mcr p15, 0, ip, c1, c0, 0 @ ctrl register
+ mov pc, r0
+
+ __INIT
+
+ .type __arm740_setup, #function
+__arm740_setup:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c0, 0 @ invalidate caches
+
+ mcr p15, 0, r0, c6, c3 @ disable area 3~7
+ mcr p15, 0, r0, c6, c4
+ mcr p15, 0, r0, c6, c5
+ mcr p15, 0, r0, c6, c6
+ mcr p15, 0, r0, c6, c7
+
+ mov r0, #0x0000003F @ base = 0, size = 4GB
+ mcr p15, 0, r0, c6, c0 @ set area 0, default
+
+ ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
+ ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
+ mov r2, #10 @ 11 is the minimum (4KB)
+1: add r2, r2, #1 @ area size *= 2
+ mov r1, r1, lsr #1
+ bne 1b @ count not zero r-shift
+ orr r0, r0, r2, lsl #1 @ the area register value
+ orr r0, r0, #1 @ set enable bit
+ mcr p15, 0, r0, c6, c1 @ set area 1, RAM
+
+ ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
+ ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
+ mov r2, #10 @ 11 is the minimum (4KB)
+1: add r2, r2, #1 @ area size *= 2
+ mov r1, r1, lsr #1
+ bne 1b @ count not zero r-shift
+ orr r0, r0, r2, lsl #1 @ the area register value
+ orr r0, r0, #1 @ set enable bit
+ mcr p15, 0, r0, c6, c2 @ set area 2, ROM/FLASH
+
+ mov r0, #0x06
+ mcr p15, 0, r0, c2, c0 @ Region 1&2 cacheable
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mov r0, #0x00 @ disable whole write buffer
+#else
+ mov r0, #0x02 @ Region 1 write bufferred
+#endif
+ mcr p15, 0, r0, c3, c0
+
+ mov r0, #0x10000
+ sub r0, r0, #1 @ r0 = 0xffff
+ mcr p15, 0, r0, c5, c0 @ all read/write access
+
+ mrc p15, 0, r0, c1, c0 @ get control register
+ bic r0, r0, #0x3F000000 @ set to standard caching mode
+ @ need some benchmark
+ orr r0, r0, #0x0000000d @ MPU/Cache/WB
+
+ mov pc, lr
+
+ .size __arm740_setup, . - __arm740_setup
+
+ __INITDATA
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ * come through these
+ */
+ .type arm740_processor_functions, #object
+ENTRY(arm740_processor_functions)
+ .word v4t_late_abort
+ .word cpu_arm740_proc_init
+ .word cpu_arm740_proc_fin
+ .word cpu_arm740_reset
+ .word cpu_arm740_do_idle
+ .word cpu_arm740_dcache_clean_area
+ .word cpu_arm740_switch_mm
+ .word 0 @ cpu_*_set_pte
+ .size arm740_processor_functions, . - arm740_processor_functions
+
+ .section ".rodata"
+
+ .type cpu_arch_name, #object
+cpu_arch_name:
+ .asciz "armv4"
+ .size cpu_arch_name, . - cpu_arch_name
+
+ .type cpu_elf_name, #object
+cpu_elf_name:
+ .asciz "v4"
+ .size cpu_elf_name, . - cpu_elf_name
+
+ .type cpu_arm740_name, #object
+cpu_arm740_name:
+ .ascii "ARM740T"
+ .size cpu_arm740_name, . - cpu_arm740_name
+
+ .align
+
+ .section ".proc.info.init", #alloc, #execinstr
+ .type __arm740_proc_info,#object
+__arm740_proc_info:
+ .long 0x41807400
+ .long 0xfffffff0
+ .long 0
+ b __arm740_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_HALF | HWCAP_26BIT
+ .long cpu_arm740_name
+ .long arm740_processor_functions
+ .long 0
+ .long 0
+ .long v3_cache_fns @ cache model
+ .size __arm740_proc_info, . - __arm740_proc_info
+
+
diff --git a/arch/arm/mm/proc-arm7tdmi.S b/arch/arm/mm/proc-arm7tdmi.S
new file mode 100644
index 000000000000..22d7e3100ea6
--- /dev/null
+++ b/arch/arm/mm/proc-arm7tdmi.S
@@ -0,0 +1,249 @@
+/*
+ * linux/arch/arm/mm/proc-arm7tdmi.S: utility functions for ARM7TDMI
+ *
+ * Copyright (C) 2003-2006 Hyok S. Choi <hyok.choi@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.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+#include <asm/procinfo.h>
+#include <asm/ptrace.h>
+
+ .text
+/*
+ * cpu_arm7tdmi_proc_init()
+ * cpu_arm7tdmi_do_idle()
+ * cpu_arm7tdmi_dcache_clean_area()
+ * cpu_arm7tdmi_switch_mm()
+ *
+ * These are not required.
+ */
+ENTRY(cpu_arm7tdmi_proc_init)
+ENTRY(cpu_arm7tdmi_do_idle)
+ENTRY(cpu_arm7tdmi_dcache_clean_area)
+ENTRY(cpu_arm7tdmi_switch_mm)
+ mov pc, lr
+
+/*
+ * cpu_arm7tdmi_proc_fin()
+ */
+ENTRY(cpu_arm7tdmi_proc_fin)
+ mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+ msr cpsr_c, r0
+ mov pc, lr
+
+/*
+ * Function: cpu_arm7tdmi_reset(loc)
+ * Params : loc(r0) address to jump to
+ * Purpose : Sets up everything for a reset and jump to the location for soft reset.
+ */
+ENTRY(cpu_arm7tdmi_reset)
+ mov pc, r0
+
+ __INIT
+
+ .type __arm7tdmi_setup, #function
+__arm7tdmi_setup:
+ mov pc, lr
+ .size __arm7tdmi_setup, . - __arm7tdmi_setup
+
+ __INITDATA
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ * come through these
+ */
+ .type arm7tdmi_processor_functions, #object
+ENTRY(arm7tdmi_processor_functions)
+ .word v4t_late_abort
+ .word cpu_arm7tdmi_proc_init
+ .word cpu_arm7tdmi_proc_fin
+ .word cpu_arm7tdmi_reset
+ .word cpu_arm7tdmi_do_idle
+ .word cpu_arm7tdmi_dcache_clean_area
+ .word cpu_arm7tdmi_switch_mm
+ .word 0 @ cpu_*_set_pte
+ .size arm7tdmi_processor_functions, . - arm7tdmi_processor_functions
+
+ .section ".rodata"
+
+ .type cpu_arch_name, #object
+cpu_arch_name:
+ .asciz "armv4t"
+ .size cpu_arch_name, . - cpu_arch_name
+
+ .type cpu_elf_name, #object
+cpu_elf_name:
+ .asciz "v4"
+ .size cpu_elf_name, . - cpu_elf_name
+
+ .type cpu_arm7tdmi_name, #object
+cpu_arm7tdmi_name:
+ .asciz "ARM7TDMI"
+ .size cpu_arm7tdmi_name, . - cpu_arm7tdmi_name
+
+ .type cpu_triscenda7_name, #object
+cpu_triscenda7_name:
+ .asciz "Triscend-A7x"
+ .size cpu_triscenda7_name, . - cpu_triscenda7_name
+
+ .type cpu_at91_name, #object
+cpu_at91_name:
+ .asciz "Atmel-AT91M40xxx"
+ .size cpu_at91_name, . - cpu_at91_name
+
+ .type cpu_s3c3410_name, #object
+cpu_s3c3410_name:
+ .asciz "Samsung-S3C3410"
+ .size cpu_s3c3410_name, . - cpu_s3c3410_name
+
+ .type cpu_s3c44b0x_name, #object
+cpu_s3c44b0x_name:
+ .asciz "Samsung-S3C44B0x"
+ .size cpu_s3c44b0x_name, . - cpu_s3c44b0x_name
+
+ .type cpu_s3c4510b, #object
+cpu_s3c4510b_name:
+ .asciz "Samsung-S3C4510B"
+ .size cpu_s3c4510b_name, . - cpu_s3c4510b_name
+
+ .type cpu_s3c4530_name, #object
+cpu_s3c4530_name:
+ .asciz "Samsung-S3C4530"
+ .size cpu_s3c4530_name, . - cpu_s3c4530_name
+
+ .type cpu_netarm_name, #object
+cpu_netarm_name:
+ .asciz "NETARM"
+ .size cpu_netarm_name, . - cpu_netarm_name
+
+ .align
+
+ .section ".proc.info.init", #alloc, #execinstr
+
+ .type __arm7tdmi_proc_info, #object
+__arm7tdmi_proc_info:
+ .long 0x41007700
+ .long 0xfff8ff00
+ .long 0
+ .long 0
+ b __arm7tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_26BIT
+ .long cpu_arm7tdmi_name
+ .long arm7tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __arm7tdmi_proc_info, . - __arm7dmi_proc_info
+
+ .type __triscenda7_proc_info, #object
+__triscenda7_proc_info:
+ .long 0x0001d2ff
+ .long 0x0001ffff
+ .long 0
+ .long 0
+ b __arm7tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_triscenda7_name
+ .long arm7tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __triscenda7_proc_info, . - __triscenda7_proc_info
+
+ .type __at91_proc_info, #object
+__at91_proc_info:
+ .long 0x14000040
+ .long 0xfff000e0
+ .long 0
+ .long 0
+ b __arm7tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_at91_name
+ .long arm7tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __at91_proc_info, . - __at91_proc_info
+
+ .type __s3c4510b_proc_info, #object
+__s3c4510b_proc_info:
+ .long 0x36365000
+ .long 0xfffff000
+ .long 0
+ .long 0
+ b __arm7tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_s3c4510b_name
+ .long arm7tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __s3c4510b_proc_info, . - __s3c4510b_proc_info
+
+ .type __s3c4530_proc_info, #object
+__s3c4530_proc_info:
+ .long 0x4c000000
+ .long 0xfff000e0
+ .long 0
+ .long 0
+ b __arm7tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_s3c4530_name
+ .long arm7tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __s3c4530_proc_info, . - __s3c4530_proc_info
+
+ .type __s3c3410_proc_info, #object
+__s3c3410_proc_info:
+ .long 0x34100000
+ .long 0xffff0000
+ .long 0
+ .long 0
+ b __arm7tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_s3c3410_name
+ .long arm7tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __s3c3410_proc_info, . - __s3c3410_proc_info
+
+ .type __s3c44b0x_proc_info, #object
+__s3c44b0x_proc_info:
+ .long 0x44b00000
+ .long 0xffff0000
+ .long 0
+ .long 0
+ b __arm7tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_s3c44b0x_name
+ .long arm7tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __s3c44b0x_proc_info, . - __s3c44b0x_proc_info
diff --git a/arch/arm/mm/proc-arm940.S b/arch/arm/mm/proc-arm940.S
new file mode 100644
index 000000000000..2397f4b6e151
--- /dev/null
+++ b/arch/arm/mm/proc-arm940.S
@@ -0,0 +1,369 @@
+/*
+ * linux/arch/arm/mm/arm940.S: utility functions for ARM940T
+ *
+ * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi@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.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+#include <asm/procinfo.h>
+#include <asm/ptrace.h>
+
+/* ARM940T has a 4KB DCache comprising 256 lines of 4 words */
+#define CACHE_DLINESIZE 16
+#define CACHE_DSEGMENTS 4
+#define CACHE_DENTRIES 64
+
+ .text
+/*
+ * cpu_arm940_proc_init()
+ * cpu_arm940_switch_mm()
+ *
+ * These are not required.
+ */
+ENTRY(cpu_arm940_proc_init)
+ENTRY(cpu_arm940_switch_mm)
+ mov pc, lr
+
+/*
+ * cpu_arm940_proc_fin()
+ */
+ENTRY(cpu_arm940_proc_fin)
+ stmfd sp!, {lr}
+ mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+ msr cpsr_c, ip
+ bl arm940_flush_kern_cache_all
+ mrc p15, 0, r0, c1, c0, 0 @ ctrl register
+ bic r0, r0, #0x00001000 @ i-cache
+ bic r0, r0, #0x00000004 @ d-cache
+ mcr p15, 0, r0, c1, c0, 0 @ disable caches
+ ldmfd sp!, {pc}
+
+/*
+ * cpu_arm940_reset(loc)
+ * Params : r0 = address to jump to
+ * Notes : This sets up everything for a reset
+ */
+ENTRY(cpu_arm940_reset)
+ mov ip, #0
+ mcr p15, 0, ip, c7, c5, 0 @ flush I cache
+ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
+ mcr p15, 0, ip, c7, c10, 4 @ drain WB
+ mrc p15, 0, ip, c1, c0, 0 @ ctrl register
+ bic ip, ip, #0x00000005 @ .............c.p
+ bic ip, ip, #0x00001000 @ i-cache
+ mcr p15, 0, ip, c1, c0, 0 @ ctrl register
+ mov pc, r0
+
+/*
+ * cpu_arm940_do_idle()
+ */
+ .align 5
+ENTRY(cpu_arm940_do_idle)
+ mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
+ mov pc, lr
+
+/*
+ * flush_user_cache_all()
+ */
+ENTRY(arm940_flush_user_cache_all)
+ /* FALLTHROUGH */
+
+/*
+ * flush_kern_cache_all()
+ *
+ * Clean and invalidate the entire cache.
+ */
+ENTRY(arm940_flush_kern_cache_all)
+ mov r2, #VM_EXEC
+ /* FALLTHROUGH */
+
+/*
+ * flush_user_cache_range(start, end, flags)
+ *
+ * There is no efficient way to flush a range of cache entries
+ * in the specified address range. Thus, flushes all.
+ *
+ * - start - start address (inclusive)
+ * - end - end address (exclusive)
+ * - flags - vm_flags describing address space
+ */
+ENTRY(arm940_flush_user_cache_range)
+ mov ip, #0
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
+#else
+ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
+1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
+2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index
+ subs r3, r3, #1 << 26
+ bcs 2b @ entries 63 to 0
+ subs r1, r1, #1 << 4
+ bcs 1b @ segments 3 to 0
+#endif
+ tst r2, #VM_EXEC
+ mcrne p15, 0, ip, c7, c5, 0 @ invalidate I cache
+ mcrne p15, 0, ip, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * coherent_kern_range(start, end)
+ *
+ * Ensure coherency between the Icache and the Dcache in the
+ * region described by start, end. If you have non-snooping
+ * Harvard caches, you need to implement this function.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(arm940_coherent_kern_range)
+ /* FALLTHROUGH */
+
+/*
+ * coherent_user_range(start, end)
+ *
+ * Ensure coherency between the Icache and the Dcache in the
+ * region described by start, end. If you have non-snooping
+ * Harvard caches, you need to implement this function.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(arm940_coherent_user_range)
+ /* FALLTHROUGH */
+
+/*
+ * flush_kern_dcache_page(void *page)
+ *
+ * Ensure no D cache aliasing occurs, either with itself or
+ * the I cache
+ *
+ * - addr - page aligned address
+ */
+ENTRY(arm940_flush_kern_dcache_page)
+ mov ip, #0
+ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
+1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
+2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index
+ subs r3, r3, #1 << 26
+ bcs 2b @ entries 63 to 0
+ subs r1, r1, #1 << 4
+ bcs 1b @ segments 7 to 0
+ mcr p15, 0, ip, c7, c5, 0 @ invalidate I cache
+ mcr p15, 0, ip, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * dma_inv_range(start, end)
+ *
+ * There is no efficient way to invalidate a specifid virtual
+ * address range. Thus, invalidates all.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(arm940_dma_inv_range)
+ mov ip, #0
+ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
+1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
+2: mcr p15, 0, r3, c7, c6, 2 @ flush D entry
+ subs r3, r3, #1 << 26
+ bcs 2b @ entries 63 to 0
+ subs r1, r1, #1 << 4
+ bcs 1b @ segments 7 to 0
+ mcr p15, 0, ip, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * dma_clean_range(start, end)
+ *
+ * There is no efficient way to clean a specifid virtual
+ * address range. Thus, cleans all.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(arm940_dma_clean_range)
+ENTRY(cpu_arm940_dcache_clean_area)
+ mov ip, #0
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
+1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
+2: mcr p15, 0, r3, c7, c10, 2 @ clean D entry
+ subs r3, r3, #1 << 26
+ bcs 2b @ entries 63 to 0
+ subs r1, r1, #1 << 4
+ bcs 1b @ segments 7 to 0
+#endif
+ mcr p15, 0, ip, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * dma_flush_range(start, end)
+ *
+ * There is no efficient way to clean and invalidate a specifid
+ * virtual address range.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(arm940_dma_flush_range)
+ mov ip, #0
+ mov r1, #(CACHE_DSEGMENTS - 1) << 4 @ 4 segments
+1: orr r3, r1, #(CACHE_DENTRIES - 1) << 26 @ 64 entries
+2:
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mcr p15, 0, r3, c7, c14, 2 @ clean/flush D entry
+#else
+ mcr p15, 0, r3, c7, c10, 2 @ clean D entry
+#endif
+ subs r3, r3, #1 << 26
+ bcs 2b @ entries 63 to 0
+ subs r1, r1, #1 << 4
+ bcs 1b @ segments 7 to 0
+ mcr p15, 0, ip, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+ENTRY(arm940_cache_fns)
+ .long arm940_flush_kern_cache_all
+ .long arm940_flush_user_cache_all
+ .long arm940_flush_user_cache_range
+ .long arm940_coherent_kern_range
+ .long arm940_coherent_user_range
+ .long arm940_flush_kern_dcache_page
+ .long arm940_dma_inv_range
+ .long arm940_dma_clean_range
+ .long arm940_dma_flush_range
+
+ __INIT
+
+ .type __arm940_setup, #function
+__arm940_setup:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
+ mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+
+ mcr p15, 0, r0, c6, c3, 0 @ disable data area 3~7
+ mcr p15, 0, r0, c6, c4, 0
+ mcr p15, 0, r0, c6, c5, 0
+ mcr p15, 0, r0, c6, c6, 0
+ mcr p15, 0, r0, c6, c7, 0
+
+ mcr p15, 0, r0, c6, c3, 1 @ disable instruction area 3~7
+ mcr p15, 0, r0, c6, c4, 1
+ mcr p15, 0, r0, c6, c5, 1
+ mcr p15, 0, r0, c6, c6, 1
+ mcr p15, 0, r0, c6, c7, 1
+
+ mov r0, #0x0000003F @ base = 0, size = 4GB
+ mcr p15, 0, r0, c6, c0, 0 @ set area 0, default
+ mcr p15, 0, r0, c6, c0, 1
+
+ ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
+ ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
+ mov r2, #10 @ 11 is the minimum (4KB)
+1: add r2, r2, #1 @ area size *= 2
+ mov r1, r1, lsr #1
+ bne 1b @ count not zero r-shift
+ orr r0, r0, r2, lsl #1 @ the area register value
+ orr r0, r0, #1 @ set enable bit
+ mcr p15, 0, r0, c6, c1, 0 @ set area 1, RAM
+ mcr p15, 0, r0, c6, c1, 1
+
+ ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
+ ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
+ mov r2, #10 @ 11 is the minimum (4KB)
+1: add r2, r2, #1 @ area size *= 2
+ mov r1, r1, lsr #1
+ bne 1b @ count not zero r-shift
+ orr r0, r0, r2, lsl #1 @ the area register value
+ orr r0, r0, #1 @ set enable bit
+ mcr p15, 0, r0, c6, c2, 0 @ set area 2, ROM/FLASH
+ mcr p15, 0, r0, c6, c2, 1
+
+ mov r0, #0x06
+ mcr p15, 0, r0, c2, c0, 0 @ Region 1&2 cacheable
+ mcr p15, 0, r0, c2, c0, 1
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mov r0, #0x00 @ disable whole write buffer
+#else
+ mov r0, #0x02 @ Region 1 write bufferred
+#endif
+ mcr p15, 0, r0, c3, c0, 0
+
+ mov r0, #0x10000
+ sub r0, r0, #1 @ r0 = 0xffff
+ mcr p15, 0, r0, c5, c0, 0 @ all read/write access
+ mcr p15, 0, r0, c5, c0, 1
+
+ mrc p15, 0, r0, c1, c0 @ get control register
+ orr r0, r0, #0x00001000 @ I-cache
+ orr r0, r0, #0x00000005 @ MPU/D-cache
+
+ mov pc, lr
+
+ .size __arm940_setup, . - __arm940_setup
+
+ __INITDATA
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ * come through these
+ */
+ .type arm940_processor_functions, #object
+ENTRY(arm940_processor_functions)
+ .word nommu_early_abort
+ .word cpu_arm940_proc_init
+ .word cpu_arm940_proc_fin
+ .word cpu_arm940_reset
+ .word cpu_arm940_do_idle
+ .word cpu_arm940_dcache_clean_area
+ .word cpu_arm940_switch_mm
+ .word 0 @ cpu_*_set_pte
+ .size arm940_processor_functions, . - arm940_processor_functions
+
+ .section ".rodata"
+
+.type cpu_arch_name, #object
+cpu_arch_name:
+ .asciz "armv4t"
+ .size cpu_arch_name, . - cpu_arch_name
+
+ .type cpu_elf_name, #object
+cpu_elf_name:
+ .asciz "v4"
+ .size cpu_elf_name, . - cpu_elf_name
+
+ .type cpu_arm940_name, #object
+cpu_arm940_name:
+ .ascii "ARM940T"
+ .size cpu_arm940_name, . - cpu_arm940_name
+
+ .align
+
+ .section ".proc.info.init", #alloc, #execinstr
+
+ .type __arm940_proc_info,#object
+__arm940_proc_info:
+ .long 0x41009400
+ .long 0xff00fff0
+ .long 0
+ b __arm940_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
+ .long cpu_arm940_name
+ .long arm940_processor_functions
+ .long 0
+ .long 0
+ .long arm940_cache_fns
+ .size __arm940_proc_info, . - __arm940_proc_info
+
diff --git a/arch/arm/mm/proc-arm946.S b/arch/arm/mm/proc-arm946.S
new file mode 100644
index 000000000000..e18617564421
--- /dev/null
+++ b/arch/arm/mm/proc-arm946.S
@@ -0,0 +1,424 @@
+/*
+ * linux/arch/arm/mm/arm946.S: utility functions for ARM946E-S
+ *
+ * Copyright (C) 2004-2006 Hyok S. Choi (hyok.choi@samsung.com)
+ *
+ * (Many of cache codes are from proc-arm926.S)
+ *
+ * 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/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+#include <asm/procinfo.h>
+#include <asm/ptrace.h>
+
+/*
+ * ARM946E-S is synthesizable to have 0KB to 1MB sized D-Cache,
+ * comprising 256 lines of 32 bytes (8 words).
+ */
+#define CACHE_DSIZE (CONFIG_CPU_DCACHE_SIZE) /* typically 8KB. */
+#define CACHE_DLINESIZE 32 /* fixed */
+#define CACHE_DSEGMENTS 4 /* fixed */
+#define CACHE_DENTRIES (CACHE_DSIZE / CACHE_DSEGMENTS / CACHE_DLINESIZE)
+#define CACHE_DLIMIT (CACHE_DSIZE * 4) /* benchmark needed */
+
+ .text
+/*
+ * cpu_arm946_proc_init()
+ * cpu_arm946_switch_mm()
+ *
+ * These are not required.
+ */
+ENTRY(cpu_arm946_proc_init)
+ENTRY(cpu_arm946_switch_mm)
+ mov pc, lr
+
+/*
+ * cpu_arm946_proc_fin()
+ */
+ENTRY(cpu_arm946_proc_fin)
+ stmfd sp!, {lr}
+ mov ip, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+ msr cpsr_c, ip
+ bl arm946_flush_kern_cache_all
+ mrc p15, 0, r0, c1, c0, 0 @ ctrl register
+ bic r0, r0, #0x00001000 @ i-cache
+ bic r0, r0, #0x00000004 @ d-cache
+ mcr p15, 0, r0, c1, c0, 0 @ disable caches
+ ldmfd sp!, {pc}
+
+/*
+ * cpu_arm946_reset(loc)
+ * Params : r0 = address to jump to
+ * Notes : This sets up everything for a reset
+ */
+ENTRY(cpu_arm946_reset)
+ mov ip, #0
+ mcr p15, 0, ip, c7, c5, 0 @ flush I cache
+ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
+ mcr p15, 0, ip, c7, c10, 4 @ drain WB
+ mrc p15, 0, ip, c1, c0, 0 @ ctrl register
+ bic ip, ip, #0x00000005 @ .............c.p
+ bic ip, ip, #0x00001000 @ i-cache
+ mcr p15, 0, ip, c1, c0, 0 @ ctrl register
+ mov pc, r0
+
+/*
+ * cpu_arm946_do_idle()
+ */
+ .align 5
+ENTRY(cpu_arm946_do_idle)
+ mcr p15, 0, r0, c7, c0, 4 @ Wait for interrupt
+ mov pc, lr
+
+/*
+ * flush_user_cache_all()
+ */
+ENTRY(arm946_flush_user_cache_all)
+ /* FALLTHROUGH */
+
+/*
+ * flush_kern_cache_all()
+ *
+ * Clean and invalidate the entire cache.
+ */
+ENTRY(arm946_flush_kern_cache_all)
+ mov r2, #VM_EXEC
+ mov ip, #0
+__flush_whole_cache:
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mcr p15, 0, ip, c7, c6, 0 @ flush D cache
+#else
+ mov r1, #(CACHE_DSEGMENTS - 1) << 29 @ 4 segments
+1: orr r3, r1, #(CACHE_DENTRIES - 1) << 4 @ n entries
+2: mcr p15, 0, r3, c7, c14, 2 @ clean/flush D index
+ subs r3, r3, #1 << 4
+ bcs 2b @ entries n to 0
+ subs r1, r1, #1 << 29
+ bcs 1b @ segments 3 to 0
+#endif
+ tst r2, #VM_EXEC
+ mcrne p15, 0, ip, c7, c5, 0 @ flush I cache
+ mcrne p15, 0, ip, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * flush_user_cache_range(start, end, flags)
+ *
+ * Clean and invalidate a range of cache entries in the
+ * specified address range.
+ *
+ * - start - start address (inclusive)
+ * - end - end address (exclusive)
+ * - flags - vm_flags describing address space
+ * (same as arm926)
+ */
+ENTRY(arm946_flush_user_cache_range)
+ mov ip, #0
+ sub r3, r1, r0 @ calculate total size
+ cmp r3, #CACHE_DLIMIT
+ bhs __flush_whole_cache
+
+1: tst r2, #VM_EXEC
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
+ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
+ add r0, r0, #CACHE_DLINESIZE
+ mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
+ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
+ add r0, r0, #CACHE_DLINESIZE
+#else
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
+ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
+ add r0, r0, #CACHE_DLINESIZE
+ mcr p15, 0, r0, c7, c14, 1 @ clean and invalidate D entry
+ mcrne p15, 0, r0, c7, c5, 1 @ invalidate I entry
+ add r0, r0, #CACHE_DLINESIZE
+#endif
+ cmp r0, r1
+ blo 1b
+ tst r2, #VM_EXEC
+ mcrne p15, 0, ip, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * coherent_kern_range(start, end)
+ *
+ * Ensure coherency between the Icache and the Dcache in the
+ * region described by start, end. If you have non-snooping
+ * Harvard caches, you need to implement this function.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ */
+ENTRY(arm946_coherent_kern_range)
+ /* FALLTHROUGH */
+
+/*
+ * coherent_user_range(start, end)
+ *
+ * Ensure coherency between the Icache and the Dcache in the
+ * region described by start, end. If you have non-snooping
+ * Harvard caches, you need to implement this function.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ * (same as arm926)
+ */
+ENTRY(arm946_coherent_user_range)
+ bic r0, r0, #CACHE_DLINESIZE - 1
+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+ mcr p15, 0, r0, c7, c5, 1 @ invalidate I entry
+ add r0, r0, #CACHE_DLINESIZE
+ cmp r0, r1
+ blo 1b
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * flush_kern_dcache_page(void *page)
+ *
+ * Ensure no D cache aliasing occurs, either with itself or
+ * the I cache
+ *
+ * - addr - page aligned address
+ * (same as arm926)
+ */
+ENTRY(arm946_flush_kern_dcache_page)
+ add r1, r0, #PAGE_SZ
+1: mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
+ add r0, r0, #CACHE_DLINESIZE
+ cmp r0, r1
+ blo 1b
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * dma_inv_range(start, end)
+ *
+ * Invalidate (discard) the specified virtual address range.
+ * May not write back any entries. If 'start' or 'end'
+ * are not cache line aligned, those lines must be written
+ * back.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ * (same as arm926)
+ */
+ENTRY(arm946_dma_inv_range)
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ tst r0, #CACHE_DLINESIZE - 1
+ mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
+ tst r1, #CACHE_DLINESIZE - 1
+ mcrne p15, 0, r1, c7, c10, 1 @ clean D entry
+#endif
+ bic r0, r0, #CACHE_DLINESIZE - 1
+1: mcr p15, 0, r0, c7, c6, 1 @ invalidate D entry
+ add r0, r0, #CACHE_DLINESIZE
+ cmp r0, r1
+ blo 1b
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * dma_clean_range(start, end)
+ *
+ * Clean the specified virtual address range.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ *
+ * (same as arm926)
+ */
+ENTRY(arm946_dma_clean_range)
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ bic r0, r0, #CACHE_DLINESIZE - 1
+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+ add r0, r0, #CACHE_DLINESIZE
+ cmp r0, r1
+ blo 1b
+#endif
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+/*
+ * dma_flush_range(start, end)
+ *
+ * Clean and invalidate the specified virtual address range.
+ *
+ * - start - virtual start address
+ * - end - virtual end address
+ *
+ * (same as arm926)
+ */
+ENTRY(arm946_dma_flush_range)
+ bic r0, r0, #CACHE_DLINESIZE - 1
+1:
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mcr p15, 0, r0, c7, c14, 1 @ clean+invalidate D entry
+#else
+ mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+#endif
+ add r0, r0, #CACHE_DLINESIZE
+ cmp r0, r1
+ blo 1b
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+ENTRY(arm946_cache_fns)
+ .long arm946_flush_kern_cache_all
+ .long arm946_flush_user_cache_all
+ .long arm946_flush_user_cache_range
+ .long arm946_coherent_kern_range
+ .long arm946_coherent_user_range
+ .long arm946_flush_kern_dcache_page
+ .long arm946_dma_inv_range
+ .long arm946_dma_clean_range
+ .long arm946_dma_flush_range
+
+
+ENTRY(cpu_arm946_dcache_clean_area)
+#ifndef CONFIG_CPU_DCACHE_WRITETHROUGH
+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+ add r0, r0, #CACHE_DLINESIZE
+ subs r1, r1, #CACHE_DLINESIZE
+ bhi 1b
+#endif
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+ mov pc, lr
+
+ __INIT
+
+ .type __arm946_setup, #function
+__arm946_setup:
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0 @ invalidate I cache
+ mcr p15, 0, r0, c7, c6, 0 @ invalidate D cache
+ mcr p15, 0, r0, c7, c10, 4 @ drain WB
+
+ mcr p15, 0, r0, c6, c3, 0 @ disable memory region 3~7
+ mcr p15, 0, r0, c6, c4, 0
+ mcr p15, 0, r0, c6, c5, 0
+ mcr p15, 0, r0, c6, c6, 0
+ mcr p15, 0, r0, c6, c7, 0
+
+ mov r0, #0x0000003F @ base = 0, size = 4GB
+ mcr p15, 0, r0, c6, c0, 0 @ set region 0, default
+
+ ldr r0, =(CONFIG_DRAM_BASE & 0xFFFFF000) @ base[31:12] of RAM
+ ldr r1, =(CONFIG_DRAM_SIZE >> 12) @ size of RAM (must be >= 4KB)
+ mov r2, #10 @ 11 is the minimum (4KB)
+1: add r2, r2, #1 @ area size *= 2
+ mov r1, r1, lsr #1
+ bne 1b @ count not zero r-shift
+ orr r0, r0, r2, lsl #1 @ the region register value
+ orr r0, r0, #1 @ set enable bit
+ mcr p15, 0, r0, c6, c1, 0 @ set region 1, RAM
+
+ ldr r0, =(CONFIG_FLASH_MEM_BASE & 0xFFFFF000) @ base[31:12] of FLASH
+ ldr r1, =(CONFIG_FLASH_SIZE >> 12) @ size of FLASH (must be >= 4KB)
+ mov r2, #10 @ 11 is the minimum (4KB)
+1: add r2, r2, #1 @ area size *= 2
+ mov r1, r1, lsr #1
+ bne 1b @ count not zero r-shift
+ orr r0, r0, r2, lsl #1 @ the region register value
+ orr r0, r0, #1 @ set enable bit
+ mcr p15, 0, r0, c6, c2, 0 @ set region 2, ROM/FLASH
+
+ mov r0, #0x06
+ mcr p15, 0, r0, c2, c0, 0 @ region 1,2 d-cacheable
+ mcr p15, 0, r0, c2, c0, 1 @ region 1,2 i-cacheable
+#ifdef CONFIG_CPU_DCACHE_WRITETHROUGH
+ mov r0, #0x00 @ disable whole write buffer
+#else
+ mov r0, #0x02 @ region 1 write bufferred
+#endif
+ mcr p15, 0, r0, c3, c0, 0
+
+/*
+ * Access Permission Settings for future permission control by PU.
+ *
+ * priv. user
+ * region 0 (whole) rw -- : b0001
+ * region 1 (RAM) rw rw : b0011
+ * region 2 (FLASH) rw r- : b0010
+ * region 3~7 (none) -- -- : b0000
+ */
+ mov r0, #0x00000031
+ orr r0, r0, #0x00000200
+ mcr p15, 0, r0, c5, c0, 2 @ set data access permission
+ mcr p15, 0, r0, c5, c0, 3 @ set inst. access permission
+
+ mrc p15, 0, r0, c1, c0 @ get control register
+ orr r0, r0, #0x00001000 @ I-cache
+ orr r0, r0, #0x00000005 @ MPU/D-cache
+#ifdef CONFIG_CPU_CACHE_ROUND_ROBIN
+ orr r0, r0, #0x00004000 @ .1.. .... .... ....
+#endif
+ mov pc, lr
+
+ .size __arm946_setup, . - __arm946_setup
+
+ __INITDATA
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ * come through these
+ */
+ .type arm946_processor_functions, #object
+ENTRY(arm946_processor_functions)
+ .word nommu_early_abort
+ .word cpu_arm946_proc_init
+ .word cpu_arm946_proc_fin
+ .word cpu_arm946_reset
+ .word cpu_arm946_do_idle
+
+ .word cpu_arm946_dcache_clean_area
+ .word cpu_arm946_switch_mm
+ .word 0 @ cpu_*_set_pte
+ .size arm946_processor_functions, . - arm946_processor_functions
+
+ .section ".rodata"
+
+ .type cpu_arch_name, #object
+cpu_arch_name:
+ .asciz "armv5te"
+ .size cpu_arch_name, . - cpu_arch_name
+
+ .type cpu_elf_name, #object
+cpu_elf_name:
+ .asciz "v5t"
+ .size cpu_elf_name, . - cpu_elf_name
+
+ .type cpu_arm946_name, #object
+cpu_arm946_name:
+ .ascii "ARM946E-S"
+ .size cpu_arm946_name, . - cpu_arm946_name
+
+ .align
+
+ .section ".proc.info.init", #alloc, #execinstr
+ .type __arm946_proc_info,#object
+__arm946_proc_info:
+ .long 0x41009460
+ .long 0xff00fff0
+ .long 0
+ b __arm946_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_HALF | HWCAP_THUMB
+ .long cpu_arm946_name
+ .long arm946_processor_functions
+ .long 0
+ .long 0
+ .long arm940_cache_fns
+ .size __arm946_proc_info, . - __arm946_proc_info
+
diff --git a/arch/arm/mm/proc-arm9tdmi.S b/arch/arm/mm/proc-arm9tdmi.S
new file mode 100644
index 000000000000..918ebf65d4f6
--- /dev/null
+++ b/arch/arm/mm/proc-arm9tdmi.S
@@ -0,0 +1,134 @@
+/*
+ * linux/arch/arm/mm/proc-arm9tdmi.S: utility functions for ARM9TDMI
+ *
+ * Copyright (C) 2003-2006 Hyok S. Choi <hyok.choi@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.
+ *
+ */
+#include <linux/linkage.h>
+#include <linux/init.h>
+#include <asm/assembler.h>
+#include <asm/asm-offsets.h>
+#include <asm/pgtable-hwdef.h>
+#include <asm/pgtable.h>
+#include <asm/procinfo.h>
+#include <asm/ptrace.h>
+
+ .text
+/*
+ * cpu_arm9tdmi_proc_init()
+ * cpu_arm9tdmi_do_idle()
+ * cpu_arm9tdmi_dcache_clean_area()
+ * cpu_arm9tdmi_switch_mm()
+ *
+ * These are not required.
+ */
+ENTRY(cpu_arm9tdmi_proc_init)
+ENTRY(cpu_arm9tdmi_do_idle)
+ENTRY(cpu_arm9tdmi_dcache_clean_area)
+ENTRY(cpu_arm9tdmi_switch_mm)
+ mov pc, lr
+
+/*
+ * cpu_arm9tdmi_proc_fin()
+ */
+ENTRY(cpu_arm9tdmi_proc_fin)
+ mov r0, #PSR_F_BIT | PSR_I_BIT | SVC_MODE
+ msr cpsr_c, r0
+ mov pc, lr
+
+/*
+ * Function: cpu_arm9tdmi_reset(loc)
+ * Params : loc(r0) address to jump to
+ * Purpose : Sets up everything for a reset and jump to the location for soft reset.
+ */
+ENTRY(cpu_arm9tdmi_reset)
+ mov pc, r0
+
+ __INIT
+
+ .type __arm9tdmi_setup, #function
+__arm9tdmi_setup:
+ mov pc, lr
+ .size __arm9tdmi_setup, . - __arm9tdmi_setup
+
+ __INITDATA
+
+/*
+ * Purpose : Function pointers used to access above functions - all calls
+ * come through these
+ */
+ .type arm9tdmi_processor_functions, #object
+ENTRY(arm9tdmi_processor_functions)
+ .word nommu_early_abort
+ .word cpu_arm9tdmi_proc_init
+ .word cpu_arm9tdmi_proc_fin
+ .word cpu_arm9tdmi_reset
+ .word cpu_arm9tdmi_do_idle
+ .word cpu_arm9tdmi_dcache_clean_area
+ .word cpu_arm9tdmi_switch_mm
+ .word 0 @ cpu_*_set_pte
+ .size arm9tdmi_processor_functions, . - arm9tdmi_processor_functions
+
+ .section ".rodata"
+
+ .type cpu_arch_name, #object
+cpu_arch_name:
+ .asciz "armv4t"
+ .size cpu_arch_name, . - cpu_arch_name
+
+ .type cpu_elf_name, #object
+cpu_elf_name:
+ .asciz "v4"
+ .size cpu_elf_name, . - cpu_elf_name
+
+ .type cpu_arm9tdmi_name, #object
+cpu_arm9tdmi_name:
+ .asciz "ARM9TDMI"
+ .size cpu_arm9tdmi_name, . - cpu_arm9tdmi_name
+
+ .type cpu_p2001_name, #object
+cpu_p2001_name:
+ .asciz "P2001"
+ .size cpu_p2001_name, . - cpu_p2001_name
+
+ .align
+
+ .section ".proc.info.init", #alloc, #execinstr
+
+ .type __arm9tdmi_proc_info, #object
+__arm9tdmi_proc_info:
+ .long 0x41009900
+ .long 0xfff8ff00
+ .long 0
+ .long 0
+ b __arm9tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_arm9tdmi_name
+ .long arm9tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __arm9tdmi_proc_info, . - __arm9dmi_proc_info
+
+ .type __p2001_proc_info, #object
+__p2001_proc_info:
+ .long 0x41029000
+ .long 0xffffffff
+ .long 0
+ .long 0
+ b __arm9tdmi_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP | HWCAP_THUMB | HWCAP_26BIT
+ .long cpu_p2001_name
+ .long arm9tdmi_processor_functions
+ .long 0
+ .long 0
+ .long v4_cache_fns
+ .size __p2001_proc_info, . - __p2001_proc_info
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 3ca0c92e98a2..e8b377d637f6 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -311,12 +311,6 @@ ENTRY(xscale_flush_kern_dcache_page)
* - end - virtual end address
*/
ENTRY(xscale_dma_inv_range)
- mrc p15, 0, r2, c0, c0, 0 @ read ID
- eor r2, r2, #0x69000000
- eor r2, r2, #0x00052000
- bics r2, r2, #1
- beq xscale_dma_flush_range
-
tst r0, #CACHELINESIZE - 1
bic r0, r0, #CACHELINESIZE - 1
mcrne p15, 0, r0, c7, c10, 1 @ clean D entry
@@ -375,6 +369,30 @@ ENTRY(xscale_cache_fns)
.long xscale_dma_clean_range
.long xscale_dma_flush_range
+/*
+ * On stepping A0/A1 of the 80200, invalidating D-cache by line doesn't
+ * clear the dirty bits, which means that if we invalidate a dirty line,
+ * the dirty data can still be written back to external memory later on.
+ *
+ * The recommended workaround is to always do a clean D-cache line before
+ * doing an invalidate D-cache line, so on the affected processors,
+ * dma_inv_range() is implemented as dma_flush_range().
+ *
+ * See erratum #25 of "Intel 80200 Processor Specification Update",
+ * revision January 22, 2003, available at:
+ * http://www.intel.com/design/iio/specupdt/273415.htm
+ */
+ENTRY(xscale_80200_A0_A1_cache_fns)
+ .long xscale_flush_kern_cache_all
+ .long xscale_flush_user_cache_all
+ .long xscale_flush_user_cache_range
+ .long xscale_coherent_kern_range
+ .long xscale_coherent_user_range
+ .long xscale_flush_kern_dcache_page
+ .long xscale_dma_flush_range
+ .long xscale_dma_clean_range
+ .long xscale_dma_flush_range
+
ENTRY(cpu_xscale_dcache_clean_area)
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
add r0, r0, #CACHELINESIZE
@@ -531,6 +549,11 @@ cpu_elf_name:
.asciz "v5"
.size cpu_elf_name, . - cpu_elf_name
+ .type cpu_80200_A0_A1_name, #object
+cpu_80200_A0_A1_name:
+ .asciz "XScale-80200 A0/A1"
+ .size cpu_80200_A0_A1_name, . - cpu_80200_A0_A1_name
+
.type cpu_80200_name, #object
cpu_80200_name:
.asciz "XScale-80200"
@@ -595,6 +618,29 @@ cpu_pxa270_name:
.section ".proc.info.init", #alloc, #execinstr
+ .type __80200_A0_A1_proc_info,#object
+__80200_A0_A1_proc_info:
+ .long 0x69052000
+ .long 0xfffffffe
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_BUFFERABLE | \
+ PMD_SECT_CACHEABLE | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ
+ .long PMD_TYPE_SECT | \
+ PMD_SECT_AP_WRITE | \
+ PMD_SECT_AP_READ
+ b __xscale_setup
+ .long cpu_arch_name
+ .long cpu_elf_name
+ .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP
+ .long cpu_80200_name
+ .long xscale_processor_functions
+ .long v4wbi_tlb_fns
+ .long xscale_mc_user_fns
+ .long xscale_80200_A0_A1_cache_fns
+ .size __80200_A0_A1_proc_info, . - __80200_A0_A1_proc_info
+
.type __80200_proc_info,#object
__80200_proc_info:
.long 0x69052000
diff --git a/arch/arm/oprofile/op_model_xscale.c b/arch/arm/oprofile/op_model_xscale.c
index 34fdc733743b..7c3289c2acd7 100644
--- a/arch/arm/oprofile/op_model_xscale.c
+++ b/arch/arm/oprofile/op_model_xscale.c
@@ -20,7 +20,8 @@
#include <linux/sched.h>
#include <linux/oprofile.h>
#include <linux/interrupt.h>
-#include <asm/irq.h>
+#include <linux/irq.h>
+
#include <asm/system.h>
#include "op_counter.h"
@@ -33,14 +34,11 @@
#define PMU_CNT64 0x008 /* Make CCNT count every 64th cycle */
/* TODO do runtime detection */
-#ifdef CONFIG_ARCH_IOP310
-#define XSCALE_PMU_IRQ IRQ_XS80200_PMU
-#endif
-#ifdef CONFIG_ARCH_IOP321
-#define XSCALE_PMU_IRQ IRQ_IOP321_CORE_PMU
+#ifdef CONFIG_ARCH_IOP32X
+#define XSCALE_PMU_IRQ IRQ_IOP32X_CORE_PMU
#endif
-#ifdef CONFIG_ARCH_IOP331
-#define XSCALE_PMU_IRQ IRQ_IOP331_CORE_PMU
+#ifdef CONFIG_ARCH_IOP33X
+#define XSCALE_PMU_IRQ IRQ_IOP33X_CORE_PMU
#endif
#ifdef CONFIG_ARCH_PXA
#define XSCALE_PMU_IRQ IRQ_PMU
@@ -88,7 +86,7 @@ static struct pmu_counter results[MAX_COUNTERS];
/*
* There are two versions of the PMU in current XScale processors
* with differing register layouts and number of performance counters.
- * e.g. IOP321 is xsc1 whilst IOP331 is xsc2.
+ * e.g. IOP32x is xsc1 whilst IOP33x is xsc2.
* We detect which register layout to use in xscale_detect_pmu()
*/
enum { PMU_XSC1, PMU_XSC2 };
@@ -344,7 +342,7 @@ static void inline __xsc2_check_ctrs(void)
__asm__ __volatile__ ("mcr p14, 0, %0, c5, c1, 0" : : "r" (flag));
}
-static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t xscale_pmu_interrupt(int irq, void *arg)
{
int i;
u32 pmnc;
@@ -359,7 +357,7 @@ static irqreturn_t xscale_pmu_interrupt(int irq, void *arg, struct pt_regs *regs
continue;
write_counter(i, -(u32)results[i].reset_counter);
- oprofile_add_sample(regs, i);
+ oprofile_add_sample(get_irq_regs(), i);
results[i].ovf--;
}
diff --git a/arch/arm/plat-iop/Makefile b/arch/arm/plat-iop/Makefile
new file mode 100644
index 000000000000..23da00b11517
--- /dev/null
+++ b/arch/arm/plat-iop/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y := gpio.o i2c.o pci.o setup.o time.o
+obj-m :=
+obj-n :=
+obj- :=
diff --git a/arch/arm/plat-iop/gpio.c b/arch/arm/plat-iop/gpio.c
new file mode 100644
index 000000000000..eda436083417
--- /dev/null
+++ b/arch/arm/plat-iop/gpio.c
@@ -0,0 +1,48 @@
+/*
+ * arch/arm/plat-iop/gpio.c
+ * GPIO handling for Intel IOP3xx processors.
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.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.
+ */
+
+#include <linux/device.h>
+#include <asm/hardware/iop3xx.h>
+
+void gpio_line_config(int line, int direction)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (direction == GPIO_IN) {
+ *IOP3XX_GPOE |= 1 << line;
+ } else if (direction == GPIO_OUT) {
+ *IOP3XX_GPOE &= ~(1 << line);
+ }
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_line_config);
+
+int gpio_line_get(int line)
+{
+ return !!(*IOP3XX_GPID & (1 << line));
+}
+EXPORT_SYMBOL(gpio_line_get);
+
+void gpio_line_set(int line, int value)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (value == GPIO_LOW) {
+ *IOP3XX_GPOD &= ~(1 << line);
+ } else if (value == GPIO_HIGH) {
+ *IOP3XX_GPOD |= 1 << line;
+ }
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(gpio_line_set);
diff --git a/arch/arm/plat-iop/i2c.c b/arch/arm/plat-iop/i2c.c
new file mode 100644
index 000000000000..e99909bdba71
--- /dev/null
+++ b/arch/arm/plat-iop/i2c.c
@@ -0,0 +1,81 @@
+/*
+ * arch/arm/plat-iop/i2c.c
+ *
+ * Author: Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 2001 MontaVista Software, Inc.
+ * Copyright (C) 2004 Intel 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.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/platform_device.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_core.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/mach/map.h>
+#include <asm/setup.h>
+#include <asm/system.h>
+#include <asm/memory.h>
+#include <asm/hardware.h>
+#include <asm/hardware/iop3xx.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#ifdef CONFIG_ARCH_IOP32X
+#define IRQ_IOP3XX_I2C_0 IRQ_IOP32X_I2C_0
+#define IRQ_IOP3XX_I2C_1 IRQ_IOP32X_I2C_1
+#endif
+#ifdef CONFIG_ARCH_IOP33X
+#define IRQ_IOP3XX_I2C_0 IRQ_IOP33X_I2C_0
+#define IRQ_IOP3XX_I2C_1 IRQ_IOP33X_I2C_1
+#endif
+
+static struct resource iop3xx_i2c0_resources[] = {
+ [0] = {
+ .start = 0xfffff680,
+ .end = 0xfffff697,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_IOP3XX_I2C_0,
+ .end = IRQ_IOP3XX_I2C_0,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device iop3xx_i2c0_device = {
+ .name = "IOP3xx-I2C",
+ .id = 0,
+ .num_resources = 2,
+ .resource = iop3xx_i2c0_resources,
+};
+
+
+static struct resource iop3xx_i2c1_resources[] = {
+ [0] = {
+ .start = 0xfffff6a0,
+ .end = 0xfffff6b7,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_IOP3XX_I2C_1,
+ .end = IRQ_IOP3XX_I2C_1,
+ .flags = IORESOURCE_IRQ,
+ }
+};
+
+struct platform_device iop3xx_i2c1_device = {
+ .name = "IOP3xx-I2C",
+ .id = 1,
+ .num_resources = 2,
+ .resource = iop3xx_i2c1_resources,
+};
diff --git a/arch/arm/plat-iop/pci.c b/arch/arm/plat-iop/pci.c
new file mode 100644
index 000000000000..e647812654f2
--- /dev/null
+++ b/arch/arm/plat-iop/pci.c
@@ -0,0 +1,247 @@
+/*
+ * arch/arm/plat-iop/pci.c
+ *
+ * PCI support for the Intel IOP32X and IOP33X processors
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ *
+ * 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/kernel.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <asm/mach/pci.h>
+#include <asm/hardware/iop3xx.h>
+
+// #define DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...) do { } while (0)
+#endif
+
+/*
+ * This routine builds either a type0 or type1 configuration command. If the
+ * bus is on the 803xx then a type0 made, else a type1 is created.
+ */
+static u32 iop3xx_cfg_address(struct pci_bus *bus, int devfn, int where)
+{
+ struct pci_sys_data *sys = bus->sysdata;
+ u32 addr;
+
+ if (sys->busnr == bus->number)
+ addr = 1 << (PCI_SLOT(devfn) + 16) | (PCI_SLOT(devfn) << 11);
+ else
+ addr = bus->number << 16 | PCI_SLOT(devfn) << 11 | 1;
+
+ addr |= PCI_FUNC(devfn) << 8 | (where & ~3);
+
+ return addr;
+}
+
+/*
+ * This routine checks the status of the last configuration cycle. If an error
+ * was detected it returns a 1, else it returns a 0. The errors being checked
+ * are parity, master abort, target abort (master and target). These types of
+ * errors occure during a config cycle where there is no device, like during
+ * the discovery stage.
+ */
+static int iop3xx_pci_status(void)
+{
+ unsigned int status;
+ int ret = 0;
+
+ /*
+ * Check the status registers.
+ */
+ status = *IOP3XX_ATUSR;
+ if (status & 0xf900) {
+ DBG("\t\t\tPCI: P0 - status = 0x%08x\n", status);
+ *IOP3XX_ATUSR = status & 0xf900;
+ ret = 1;
+ }
+
+ status = *IOP3XX_ATUISR;
+ if (status & 0x679f) {
+ DBG("\t\t\tPCI: P1 - status = 0x%08x\n", status);
+ *IOP3XX_ATUISR = status & 0x679f;
+ ret = 1;
+ }
+
+ return ret;
+}
+
+/*
+ * Simply write the address register and read the configuration
+ * data. Note that the 4 nop's ensure that we are able to handle
+ * a delayed abort (in theory.)
+ */
+static inline u32 iop3xx_read(unsigned long addr)
+{
+ u32 val;
+
+ __asm__ __volatile__(
+ "str %1, [%2]\n\t"
+ "ldr %0, [%3]\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ : "=r" (val)
+ : "r" (addr), "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR));
+
+ return val;
+}
+
+/*
+ * The read routines must check the error status of the last configuration
+ * cycle. If there was an error, the routine returns all hex f's.
+ */
+static int
+iop3xx_read_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 *value)
+{
+ unsigned long addr = iop3xx_cfg_address(bus, devfn, where);
+ u32 val = iop3xx_read(addr) >> ((where & 3) * 8);
+
+ if (iop3xx_pci_status())
+ val = 0xffffffff;
+
+ *value = val;
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+iop3xx_write_config(struct pci_bus *bus, unsigned int devfn, int where,
+ int size, u32 value)
+{
+ unsigned long addr = iop3xx_cfg_address(bus, devfn, where);
+ u32 val;
+
+ if (size != 4) {
+ val = iop3xx_read(addr);
+ if (iop3xx_pci_status())
+ return PCIBIOS_SUCCESSFUL;
+
+ where = (where & 3) * 8;
+
+ if (size == 1)
+ val &= ~(0xff << where);
+ else
+ val &= ~(0xffff << where);
+
+ *IOP3XX_OCCDR = val | value << where;
+ } else {
+ asm volatile(
+ "str %1, [%2]\n\t"
+ "str %0, [%3]\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ "nop\n\t"
+ :
+ : "r" (value), "r" (addr),
+ "r" (IOP3XX_OCCAR), "r" (IOP3XX_OCCDR));
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops iop3xx_ops = {
+ .read = iop3xx_read_config,
+ .write = iop3xx_write_config,
+};
+
+/*
+ * When a PCI device does not exist during config cycles, the 80200 gets a
+ * bus error instead of returning 0xffffffff. This handler simply returns.
+ */
+static int
+iop3xx_pci_abort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
+{
+ DBG("PCI abort: address = 0x%08lx fsr = 0x%03x PC = 0x%08lx LR = 0x%08lx\n",
+ addr, fsr, regs->ARM_pc, regs->ARM_lr);
+
+ /*
+ * If it was an imprecise abort, then we need to correct the
+ * return address to be _after_ the instruction.
+ */
+ if (fsr & (1 << 10))
+ regs->ARM_pc += 4;
+
+ return 0;
+}
+
+int iop3xx_pci_setup(int nr, struct pci_sys_data *sys)
+{
+ struct resource *res;
+
+ if (nr != 0)
+ return 0;
+
+ res = kzalloc(2 * sizeof(struct resource), GFP_KERNEL);
+ if (!res)
+ panic("PCI: unable to alloc resources");
+
+ res[0].start = IOP3XX_PCI_LOWER_IO_VA;
+ res[0].end = IOP3XX_PCI_LOWER_IO_VA + IOP3XX_PCI_IO_WINDOW_SIZE - 1;
+ res[0].name = "IOP3XX PCI I/O Space";
+ res[0].flags = IORESOURCE_IO;
+ request_resource(&ioport_resource, &res[0]);
+
+ res[1].start = IOP3XX_PCI_LOWER_MEM_PA;
+ res[1].end = IOP3XX_PCI_LOWER_MEM_PA + IOP3XX_PCI_MEM_WINDOW_SIZE - 1;
+ res[1].name = "IOP3XX PCI Memory Space";
+ res[1].flags = IORESOURCE_MEM;
+ request_resource(&iomem_resource, &res[1]);
+
+ sys->mem_offset = IOP3XX_PCI_LOWER_MEM_PA - IOP3XX_PCI_LOWER_MEM_BA;
+ sys->io_offset = IOP3XX_PCI_LOWER_IO_VA - IOP3XX_PCI_LOWER_IO_BA;
+
+ sys->resource[0] = &res[0];
+ sys->resource[1] = &res[1];
+ sys->resource[2] = NULL;
+
+ return 1;
+}
+
+struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *sys)
+{
+ return pci_scan_bus(sys->busnr, &iop3xx_ops, sys);
+}
+
+void iop3xx_pci_preinit(void)
+{
+ DBG("PCI: Intel 803xx PCI init code.\n");
+ DBG("ATU: IOP3XX_ATUCMD=0x%04x\n", *IOP3XX_ATUCMD);
+ DBG("ATU: IOP3XX_OMWTVR0=0x%04x, IOP3XX_OIOWTVR=0x%04x\n",
+ *IOP3XX_OMWTVR0,
+ *IOP3XX_OIOWTVR);
+ DBG("ATU: IOP3XX_ATUCR=0x%08x\n", *IOP3XX_ATUCR);
+ DBG("ATU: IOP3XX_IABAR0=0x%08x IOP3XX_IALR0=0x%08x IOP3XX_IATVR0=%08x\n",
+ *IOP3XX_IABAR0, *IOP3XX_IALR0, *IOP3XX_IATVR0);
+ DBG("ATU: IOP3XX_OMWTVR0=0x%08x\n", *IOP3XX_OMWTVR0);
+ DBG("ATU: IOP3XX_IABAR1=0x%08x IOP3XX_IALR1=0x%08x\n",
+ *IOP3XX_IABAR1, *IOP3XX_IALR1);
+ DBG("ATU: IOP3XX_ERBAR=0x%08x IOP3XX_ERLR=0x%08x IOP3XX_ERTVR=%08x\n",
+ *IOP3XX_ERBAR, *IOP3XX_ERLR, *IOP3XX_ERTVR);
+ DBG("ATU: IOP3XX_IABAR2=0x%08x IOP3XX_IALR2=0x%08x IOP3XX_IATVR2=%08x\n",
+ *IOP3XX_IABAR2, *IOP3XX_IALR2, *IOP3XX_IATVR2);
+ DBG("ATU: IOP3XX_IABAR3=0x%08x IOP3XX_IALR3=0x%08x IOP3XX_IATVR3=%08x\n",
+ *IOP3XX_IABAR3, *IOP3XX_IALR3, *IOP3XX_IATVR3);
+
+ hook_fault_code(16+6, iop3xx_pci_abort, SIGBUS, "imprecise external abort");
+}
diff --git a/arch/arm/plat-iop/setup.c b/arch/arm/plat-iop/setup.c
new file mode 100644
index 000000000000..4689db638e95
--- /dev/null
+++ b/arch/arm/plat-iop/setup.c
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/plat-iop/setup.c
+ *
+ * Author: Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 2001 MontaVista Software, Inc.
+ * Copyright (C) 2004 Intel 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.
+ */
+
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/iop3xx.h>
+
+/*
+ * Standard IO mapping for all IOP3xx based systems
+ */
+static struct map_desc iop3xx_std_desc[] __initdata = {
+ { /* mem mapped registers */
+ .virtual = IOP3XX_PERIPHERAL_VIRT_BASE,
+ .pfn = __phys_to_pfn(IOP3XX_PERIPHERAL_PHYS_BASE),
+ .length = IOP3XX_PERIPHERAL_SIZE,
+ .type = MT_DEVICE,
+ }, { /* PCI IO space */
+ .virtual = IOP3XX_PCI_LOWER_IO_VA,
+ .pfn = __phys_to_pfn(IOP3XX_PCI_LOWER_IO_PA),
+ .length = IOP3XX_PCI_IO_WINDOW_SIZE,
+ .type = MT_DEVICE,
+ },
+};
+
+void __init iop3xx_map_io(void)
+{
+ iotable_init(iop3xx_std_desc, ARRAY_SIZE(iop3xx_std_desc));
+}
diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c
new file mode 100644
index 000000000000..f530abdaa7a1
--- /dev/null
+++ b/arch/arm/plat-iop/time.c
@@ -0,0 +1,98 @@
+/*
+ * arch/arm/plat-iop/time.c
+ *
+ * Timer code for IOP32x and IOP33x based systems
+ *
+ * Author: Deepak Saxena <dsaxena@mvista.com>
+ *
+ * Copyright 2002-2003 MontaVista Software Inc.
+ *
+ * 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/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/time.h>
+#include <linux/init.h>
+#include <linux/timex.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
+
+#ifdef CONFIG_ARCH_IOP32X
+#define IRQ_IOP3XX_TIMER0 IRQ_IOP32X_TIMER0
+#else
+#ifdef CONFIG_ARCH_IOP33X
+#define IRQ_IOP3XX_TIMER0 IRQ_IOP33X_TIMER0
+#endif
+#endif
+
+static unsigned long ticks_per_jiffy;
+static unsigned long ticks_per_usec;
+static unsigned long next_jiffy_time;
+
+unsigned long iop3xx_gettimeoffset(void)
+{
+ unsigned long offset;
+
+ offset = next_jiffy_time - *IOP3XX_TU_TCR1;
+
+ return offset / ticks_per_usec;
+}
+
+static irqreturn_t
+iop3xx_timer_interrupt(int irq, void *dev_id)
+{
+ write_seqlock(&xtime_lock);
+
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c6, c1, 0" : : "r" (1));
+ iop3xx_cp6_disable();
+
+ while ((signed long)(next_jiffy_time - *IOP3XX_TU_TCR1)
+ >= ticks_per_jiffy) {
+ timer_tick();
+ next_jiffy_time -= ticks_per_jiffy;
+ }
+
+ write_sequnlock(&xtime_lock);
+
+ return IRQ_HANDLED;
+}
+
+static struct irqaction iop3xx_timer_irq = {
+ .name = "IOP3XX Timer Tick",
+ .handler = iop3xx_timer_interrupt,
+ .flags = IRQF_DISABLED | IRQF_TIMER,
+};
+
+void __init iop3xx_init_time(unsigned long tick_rate)
+{
+ u32 timer_ctl;
+
+ ticks_per_jiffy = (tick_rate + HZ/2) / HZ;
+ ticks_per_usec = tick_rate / 1000000;
+ next_jiffy_time = 0xffffffff;
+
+ timer_ctl = IOP3XX_TMR_EN | IOP3XX_TMR_PRIVILEGED |
+ IOP3XX_TMR_RELOAD | IOP3XX_TMR_RATIO_1_1;
+
+ /*
+ * We use timer 0 for our timer interrupt, and timer 1 as
+ * monotonic counter for tracking missed jiffies.
+ */
+ iop3xx_cp6_enable();
+ asm volatile("mcr p6, 0, %0, c4, c1, 0" : : "r" (ticks_per_jiffy - 1));
+ asm volatile("mcr p6, 0, %0, c0, c1, 0" : : "r" (timer_ctl));
+ asm volatile("mcr p6, 0, %0, c5, c1, 0" : : "r" (0xffffffff));
+ asm volatile("mcr p6, 0, %0, c1, c1, 0" : : "r" (timer_ctl));
+ iop3xx_cp6_disable();
+
+ setup_irq(IRQ_IOP3XX_TIMER0, &iop3xx_timer_irq);
+}
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 7f45c7c3e673..f1179ad4be1b 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -100,6 +100,7 @@ void clk_disable(struct clk *clk)
return;
spin_lock_irqsave(&clockfw_lock, flags);
+ BUG_ON(clk->usecount == 0);
if (arch_clock->clk_disable)
arch_clock->clk_disable(clk);
spin_unlock_irqrestore(&clockfw_lock, flags);
@@ -322,6 +323,31 @@ EXPORT_SYMBOL(clk_allow_idle);
/*-------------------------------------------------------------------------*/
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+/*
+ * Disable any unused clocks left on by the bootloader
+ */
+static int __init clk_disable_unused(void)
+{
+ struct clk *ck;
+ unsigned long flags;
+
+ list_for_each_entry(ck, &clocks, node) {
+ if (ck->usecount > 0 || (ck->flags & ALWAYS_ENABLED) ||
+ ck->enable_reg == 0)
+ continue;
+
+ spin_lock_irqsave(&clockfw_lock, flags);
+ if (arch_clock->clk_disable_unused)
+ arch_clock->clk_disable_unused(ck);
+ spin_unlock_irqrestore(&clockfw_lock, flags);
+ }
+
+ return 0;
+}
+late_initcall(clk_disable_unused);
+#endif
+
int __init clk_init(struct clk_functions * custom_clocks)
{
if (!custom_clocks) {
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index 1812f237d12f..dbc3f44e07a6 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -148,7 +148,7 @@ static inline void omap_init_kp(void) {}
#ifdef CONFIG_ARCH_OMAP24XX
#define OMAP_MMC1_BASE 0x4809c000
-#define OMAP_MMC1_INT 83
+#define OMAP_MMC1_INT INT_24XX_MMC_IRQ
#else
#define OMAP_MMC1_BASE 0xfffb7800
#define OMAP_MMC1_INT INT_MMC
@@ -225,7 +225,14 @@ static void __init omap_init_mmc(void)
/* block 1 is always available and has just one pinout option */
mmc = &mmc_conf->mmc[0];
if (mmc->enabled) {
- if (!cpu_is_omap24xx()) {
+ if (cpu_is_omap24xx()) {
+ omap_cfg_reg(H18_24XX_MMC_CMD);
+ omap_cfg_reg(H15_24XX_MMC_CLKI);
+ omap_cfg_reg(G19_24XX_MMC_CLKO);
+ omap_cfg_reg(F20_24XX_MMC_DAT0);
+ omap_cfg_reg(F19_24XX_MMC_DAT_DIR0);
+ omap_cfg_reg(G18_24XX_MMC_CMD_DIR);
+ } else {
omap_cfg_reg(MMC_CMD);
omap_cfg_reg(MMC_CLK);
omap_cfg_reg(MMC_DAT0);
@@ -236,7 +243,14 @@ static void __init omap_init_mmc(void)
}
}
if (mmc->wire4) {
- if (!cpu_is_omap24xx()) {
+ if (cpu_is_omap24xx()) {
+ omap_cfg_reg(H14_24XX_MMC_DAT1);
+ omap_cfg_reg(E19_24XX_MMC_DAT2);
+ omap_cfg_reg(D19_24XX_MMC_DAT3);
+ omap_cfg_reg(E20_24XX_MMC_DAT_DIR1);
+ omap_cfg_reg(F18_24XX_MMC_DAT_DIR2);
+ omap_cfg_reg(E18_24XX_MMC_DAT_DIR3);
+ } else {
omap_cfg_reg(MMC_DAT1);
/* NOTE: DAT2 can be on W10 (here) or M15 */
if (!mmc->nomux)
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index 9eddc9507147..bb045e5ddbd8 100644
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -119,32 +119,41 @@ static void clear_lch_regs(int lch)
omap_writew(0, lch_base + i);
}
-void omap_set_dma_priority(int dst_port, int priority)
+void omap_set_dma_priority(int lch, int dst_port, int priority)
{
unsigned long reg;
u32 l;
- switch (dst_port) {
- case OMAP_DMA_PORT_OCP_T1: /* FFFECC00 */
- reg = OMAP_TC_OCPT1_PRIOR;
- break;
- case OMAP_DMA_PORT_OCP_T2: /* FFFECCD0 */
- reg = OMAP_TC_OCPT2_PRIOR;
- break;
- case OMAP_DMA_PORT_EMIFF: /* FFFECC08 */
- reg = OMAP_TC_EMIFF_PRIOR;
- break;
- case OMAP_DMA_PORT_EMIFS: /* FFFECC04 */
- reg = OMAP_TC_EMIFS_PRIOR;
- break;
- default:
- BUG();
- return;
+ if (cpu_class_is_omap1()) {
+ switch (dst_port) {
+ case OMAP_DMA_PORT_OCP_T1: /* FFFECC00 */
+ reg = OMAP_TC_OCPT1_PRIOR;
+ break;
+ case OMAP_DMA_PORT_OCP_T2: /* FFFECCD0 */
+ reg = OMAP_TC_OCPT2_PRIOR;
+ break;
+ case OMAP_DMA_PORT_EMIFF: /* FFFECC08 */
+ reg = OMAP_TC_EMIFF_PRIOR;
+ break;
+ case OMAP_DMA_PORT_EMIFS: /* FFFECC04 */
+ reg = OMAP_TC_EMIFS_PRIOR;
+ break;
+ default:
+ BUG();
+ return;
+ }
+ l = omap_readl(reg);
+ l &= ~(0xf << 8);
+ l |= (priority & 0xf) << 8;
+ omap_writel(l, reg);
+ }
+
+ if (cpu_is_omap24xx()) {
+ if (priority)
+ OMAP_DMA_CCR_REG(lch) |= (1 << 6);
+ else
+ OMAP_DMA_CCR_REG(lch) &= ~(1 << 6);
}
- l = omap_readl(reg);
- l &= ~(0xf << 8);
- l |= (priority & 0xf) << 8;
- omap_writel(l, reg);
}
void omap_set_dma_transfer_params(int lch, int data_type, int elem_count,
@@ -234,6 +243,14 @@ void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
OMAP1_DMA_LCH_CTRL_REG(lch) = w;
}
+void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode)
+{
+ if (cpu_is_omap24xx()) {
+ OMAP_DMA_CSDP_REG(lch) &= ~(0x3 << 16);
+ OMAP_DMA_CSDP_REG(lch) |= (mode << 16);
+ }
+}
+
/* Note that src_port is only for omap1 */
void omap_set_dma_src_params(int lch, int src_port, int src_amode,
unsigned long src_start,
@@ -698,6 +715,32 @@ void omap_stop_dma(int lch)
}
/*
+ * Allows changing the DMA callback function or data. This may be needed if
+ * the driver shares a single DMA channel for multiple dma triggers.
+ */
+int omap_set_dma_callback(int lch,
+ void (* callback)(int lch, u16 ch_status, void *data),
+ void *data)
+{
+ unsigned long flags;
+
+ if (lch < 0)
+ return -ENODEV;
+
+ spin_lock_irqsave(&dma_chan_lock, flags);
+ if (dma_chan[lch].dev_id == -1) {
+ printk(KERN_ERR "DMA callback for not set for free channel\n");
+ spin_unlock_irqrestore(&dma_chan_lock, flags);
+ return -EINVAL;
+ }
+ dma_chan[lch].callback = callback;
+ dma_chan[lch].data = data;
+ spin_unlock_irqrestore(&dma_chan_lock, flags);
+
+ return 0;
+}
+
+/*
* Returns current physical source address for the given DMA channel.
* If the channel is running the caller must disable interrupts prior calling
* this function and process the returned value before re-enabling interrupt to
@@ -856,8 +899,7 @@ static int omap1_dma_handle_ch(int ch)
return 1;
}
-static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t omap1_dma_irq_handler(int irq, void *dev_id)
{
int ch = ((int) dev_id) - 1;
int handled = 0;
@@ -919,8 +961,7 @@ static int omap2_dma_handle_ch(int ch)
}
/* STATUS register count is from 1-32 while our is 0-31 */
-static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t omap2_dma_irq_handler(int irq, void *dev_id)
{
u32 val;
int i;
@@ -1177,8 +1218,7 @@ static void set_b1_regs(void)
omap_writew(fi, OMAP1610_DMA_LCD_SRC_FI_B1_L);
}
-static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t lcd_dma_irq_handler(int irq, void *dev_id)
{
u16 w;
@@ -1339,6 +1379,14 @@ static int __init omap_init_dma(void)
dma_chan_count = 16;
} else
dma_chan_count = 9;
+ if (cpu_is_omap16xx()) {
+ u16 w;
+
+ /* this would prevent OMAP sleep */
+ w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+ w &= ~(1 << 8);
+ omap_writew(w, OMAP1610_DMA_LCD_CTRL);
+ }
} else if (cpu_is_omap24xx()) {
u8 revision = omap_readb(OMAP_DMA4_REVISION);
printk(KERN_INFO "OMAP DMA hardware revision %d.%d\n",
@@ -1414,11 +1462,13 @@ EXPORT_SYMBOL(omap_request_dma);
EXPORT_SYMBOL(omap_free_dma);
EXPORT_SYMBOL(omap_start_dma);
EXPORT_SYMBOL(omap_stop_dma);
+EXPORT_SYMBOL(omap_set_dma_callback);
EXPORT_SYMBOL(omap_enable_dma_irq);
EXPORT_SYMBOL(omap_disable_dma_irq);
EXPORT_SYMBOL(omap_set_dma_transfer_params);
EXPORT_SYMBOL(omap_set_dma_color_mode);
+EXPORT_SYMBOL(omap_set_dma_write_mode);
EXPORT_SYMBOL(omap_set_dma_src_params);
EXPORT_SYMBOL(omap_set_dma_src_index);
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index 50524436de63..bcbb8d7392be 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -75,10 +75,14 @@ struct omap_dm_timer {
#endif
void __iomem *io_base;
unsigned reserved:1;
+ unsigned enabled:1;
};
#ifdef CONFIG_ARCH_OMAP1
+#define omap_dm_clk_enable(x)
+#define omap_dm_clk_disable(x)
+
static struct omap_dm_timer dm_timers[] = {
{ .phys_base = 0xfffb1400, .irq = INT_1610_GPTIMER1 },
{ .phys_base = 0xfffb1c00, .irq = INT_1610_GPTIMER2 },
@@ -92,6 +96,9 @@ static struct omap_dm_timer dm_timers[] = {
#elif defined(CONFIG_ARCH_OMAP2)
+#define omap_dm_clk_enable(x) clk_enable(x)
+#define omap_dm_clk_disable(x) clk_disable(x)
+
static struct omap_dm_timer dm_timers[] = {
{ .phys_base = 0x48028000, .irq = INT_24XX_GPTIMER1 },
{ .phys_base = 0x4802a000, .irq = INT_24XX_GPTIMER2 },
@@ -154,24 +161,28 @@ static void omap_dm_timer_reset(struct omap_dm_timer *timer)
{
u32 l;
- if (timer != &dm_timers[0]) {
+ if (!cpu_class_is_omap2() || timer != &dm_timers[0]) {
omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0x06);
omap_dm_timer_wait_for_reset(timer);
}
- omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_SYS_CLK);
+ omap_dm_timer_set_source(timer, OMAP_TIMER_SRC_32_KHZ);
/* Set to smart-idle mode */
l = omap_dm_timer_read_reg(timer, OMAP_TIMER_OCP_CFG_REG);
l |= 0x02 << 3;
+
+ if (cpu_class_is_omap2() && timer == &dm_timers[0]) {
+ /* Enable wake-up only for GPT1 on OMAP2 CPUs*/
+ l |= 1 << 2;
+ /* Non-posted mode */
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_IF_CTRL_REG, 0);
+ }
omap_dm_timer_write_reg(timer, OMAP_TIMER_OCP_CFG_REG, l);
}
static void omap_dm_timer_prepare(struct omap_dm_timer *timer)
{
-#ifdef CONFIG_ARCH_OMAP2
- clk_enable(timer->iclk);
- clk_enable(timer->fclk);
-#endif
+ omap_dm_timer_enable(timer);
omap_dm_timer_reset(timer);
}
@@ -223,15 +234,36 @@ struct omap_dm_timer *omap_dm_timer_request_specific(int id)
void omap_dm_timer_free(struct omap_dm_timer *timer)
{
+ omap_dm_timer_enable(timer);
omap_dm_timer_reset(timer);
-#ifdef CONFIG_ARCH_OMAP2
- clk_disable(timer->iclk);
- clk_disable(timer->fclk);
-#endif
+ omap_dm_timer_disable(timer);
+
WARN_ON(!timer->reserved);
timer->reserved = 0;
}
+void omap_dm_timer_enable(struct omap_dm_timer *timer)
+{
+ if (timer->enabled)
+ return;
+
+ omap_dm_clk_enable(timer->fclk);
+ omap_dm_clk_enable(timer->iclk);
+
+ timer->enabled = 1;
+}
+
+void omap_dm_timer_disable(struct omap_dm_timer *timer)
+{
+ if (!timer->enabled)
+ return;
+
+ omap_dm_clk_disable(timer->iclk);
+ omap_dm_clk_disable(timer->fclk);
+
+ timer->enabled = 0;
+}
+
int omap_dm_timer_get_irq(struct omap_dm_timer *timer)
{
return timer->irq;
@@ -276,7 +308,7 @@ __u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
struct clk *omap_dm_timer_get_fclk(struct omap_dm_timer *timer)
{
- return timer->fclk;
+ return timer->fclk;
}
__u32 omap_dm_timer_modify_idlect_mask(__u32 inputmask)
@@ -406,11 +438,16 @@ void omap_dm_timer_set_int_enable(struct omap_dm_timer *timer,
unsigned int value)
{
omap_dm_timer_write_reg(timer, OMAP_TIMER_INT_EN_REG, value);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_WAKEUP_EN_REG, value);
}
unsigned int omap_dm_timer_read_status(struct omap_dm_timer *timer)
{
- return omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+ unsigned int l;
+
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_STAT_REG);
+
+ return l;
}
void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
@@ -420,12 +457,16 @@ void omap_dm_timer_write_status(struct omap_dm_timer *timer, unsigned int value)
unsigned int omap_dm_timer_read_counter(struct omap_dm_timer *timer)
{
- return omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
+ unsigned int l;
+
+ l = omap_dm_timer_read_reg(timer, OMAP_TIMER_COUNTER_REG);
+
+ return l;
}
void omap_dm_timer_write_counter(struct omap_dm_timer *timer, unsigned int value)
{
- return omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
+ omap_dm_timer_write_reg(timer, OMAP_TIMER_COUNTER_REG, value);
}
int omap_dm_timers_active(void)
@@ -436,9 +477,14 @@ int omap_dm_timers_active(void)
struct omap_dm_timer *timer;
timer = &dm_timers[i];
+
+ if (!timer->enabled)
+ continue;
+
if (omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG) &
- OMAP_TIMER_CTRL_ST)
+ OMAP_TIMER_CTRL_ST) {
return 1;
+ }
}
return 0;
}
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index cd7f973fb286..8162eed8b500 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -94,6 +94,8 @@
#define OMAP24XX_GPIO_SYSCONFIG 0x0010
#define OMAP24XX_GPIO_SYSSTATUS 0x0014
#define OMAP24XX_GPIO_IRQSTATUS1 0x0018
+#define OMAP24XX_GPIO_IRQSTATUS2 0x0028
+#define OMAP24XX_GPIO_IRQENABLE2 0x002c
#define OMAP24XX_GPIO_IRQENABLE1 0x001c
#define OMAP24XX_GPIO_CTRL 0x0030
#define OMAP24XX_GPIO_OE 0x0034
@@ -110,8 +112,6 @@
#define OMAP24XX_GPIO_CLEARDATAOUT 0x0090
#define OMAP24XX_GPIO_SETDATAOUT 0x0094
-#define OMAP_MPUIO_MASK (~OMAP_MAX_GPIO_LINES & 0xff)
-
struct gpio_bank {
void __iomem *base;
u16 irq;
@@ -216,11 +216,13 @@ static inline int gpio_valid(int gpio)
{
if (gpio < 0)
return -1;
+#ifndef CONFIG_ARCH_OMAP24XX
if (OMAP_GPIO_IS_MPUIO(gpio)) {
- if ((gpio & OMAP_MPUIO_MASK) > 16)
+ if (gpio >= OMAP_MAX_GPIO_LINES + 16)
return -1;
return 0;
}
+#endif
#ifdef CONFIG_ARCH_OMAP15XX
if (cpu_is_omap15xx() && gpio < 16)
return 0;
@@ -529,6 +531,10 @@ static void _clear_gpio_irqbank(struct gpio_bank *bank, int gpio_mask)
return;
}
__raw_writel(gpio_mask, reg);
+
+ /* Workaround for clearing DSP GPIO interrupts to allow retention */
+ if (cpu_is_omap2420())
+ __raw_writel(gpio_mask, bank->base + OMAP24XX_GPIO_IRQSTATUS2);
}
static inline void _clear_gpio_irqstatus(struct gpio_bank *bank, int gpio)
@@ -662,6 +668,14 @@ static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
}
}
+static void _reset_gpio(struct gpio_bank *bank, int gpio)
+{
+ _set_gpio_direction(bank, get_gpio_index(gpio), 1);
+ _set_gpio_irqenable(bank, gpio, 0);
+ _clear_gpio_irqstatus(bank, gpio);
+ _set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
+}
+
/* Use disable_irq_wake() and enable_irq_wake() functions from drivers */
static int gpio_wake_enable(unsigned int irq, unsigned int enable)
{
@@ -672,9 +686,7 @@ static int gpio_wake_enable(unsigned int irq, unsigned int enable)
if (check_gpio(gpio) < 0)
return -ENODEV;
bank = get_gpio_bank(gpio);
- spin_lock(&bank->lock);
retval = _set_gpio_wakeup(bank, get_gpio_index(gpio), enable);
- spin_unlock(&bank->lock);
return retval;
}
@@ -696,7 +708,9 @@ int omap_request_gpio(int gpio)
}
bank->reserved_map |= (1 << get_gpio_index(gpio));
- /* Set trigger to none. You need to enable the trigger after request_irq */
+ /* Set trigger to none. You need to enable the desired trigger with
+ * request_irq() or set_irq_type().
+ */
_set_gpio_triggering(bank, get_gpio_index(gpio), IRQT_NOEDGE);
#ifdef CONFIG_ARCH_OMAP15XX
@@ -756,9 +770,7 @@ void omap_free_gpio(int gpio)
}
#endif
bank->reserved_map &= ~(1 << get_gpio_index(gpio));
- _set_gpio_direction(bank, get_gpio_index(gpio), 1);
- _set_gpio_irqenable(bank, gpio, 0);
- _clear_gpio_irqstatus(bank, gpio);
+ _reset_gpio(bank, gpio);
spin_unlock(&bank->lock);
}
@@ -771,8 +783,7 @@ void omap_free_gpio(int gpio)
* line's interrupt handler has been run, we may miss some nested
* interrupts.
*/
-static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
- struct pt_regs *regs)
+static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc)
{
void __iomem *isr_reg = NULL;
u32 isr;
@@ -870,7 +881,7 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
continue;
}
- desc_handle_irq(gpio_irq, d, regs);
+ desc_handle_irq(gpio_irq, d);
if (unlikely((d->status & IRQ_PENDING) && !d->depth)) {
irq_mask = 1 <<
@@ -898,6 +909,14 @@ static void gpio_irq_handler(unsigned int irq, struct irqdesc *desc,
}
+static void gpio_irq_shutdown(unsigned int irq)
+{
+ unsigned int gpio = irq - IH_GPIO_BASE;
+ struct gpio_bank *bank = get_gpio_bank(gpio);
+
+ _reset_gpio(bank, gpio);
+}
+
static void gpio_ack_irq(unsigned int irq)
{
unsigned int gpio = irq - IH_GPIO_BASE;
@@ -946,6 +965,7 @@ static void mpuio_unmask_irq(unsigned int irq)
static struct irq_chip gpio_irq_chip = {
.name = "GPIO",
+ .shutdown = gpio_irq_shutdown,
.ack = gpio_ack_irq,
.mask = gpio_mask_irq,
.unmask = gpio_unmask_irq,
@@ -985,7 +1005,7 @@ static int __init _omap_gpio_init(void)
else
clk_enable(gpio_ick);
gpio_fck = clk_get(NULL, "gpios_fck");
- if (IS_ERR(gpio_ick))
+ if (IS_ERR(gpio_fck))
printk("Could not get gpios_fck\n");
else
clk_enable(gpio_fck);
@@ -1144,8 +1164,8 @@ static int omap_gpio_resume(struct sys_device *dev)
wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
break;
case METHOD_GPIO_24XX:
- wake_clear = bank->base + OMAP1610_GPIO_CLEAR_WAKEUPENA;
- wake_set = bank->base + OMAP1610_GPIO_SET_WAKEUPENA;
+ wake_clear = bank->base + OMAP24XX_GPIO_CLEARWKUENA;
+ wake_set = bank->base + OMAP24XX_GPIO_SETWKUENA;
break;
default:
continue;
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 196aac3ac329..ec50008a2df6 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -75,8 +75,6 @@ static struct clk *mcbsp1_ick = 0;
static struct clk *mcbsp1_fck = 0;
static struct clk *mcbsp2_ick = 0;
static struct clk *mcbsp2_fck = 0;
-static struct clk *sys_ck = 0;
-static struct clk *sys_clkout = 0;
#endif
static void omap_mcbsp_dump_reg(u8 id)
@@ -98,7 +96,7 @@ static void omap_mcbsp_dump_reg(u8 id)
DBG("***********************\n");
}
-static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
{
struct omap_mcbsp * mcbsp_tx = (struct omap_mcbsp *)(dev_id);
@@ -108,7 +106,7 @@ static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id, struct pt_re
return IRQ_HANDLED;
}
-static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
{
struct omap_mcbsp * mcbsp_rx = (struct omap_mcbsp *)(dev_id);
@@ -232,7 +230,6 @@ static void omap2_mcbsp2_mux_setup(void)
omap_cfg_reg(W15_24XX_MCBSP2_DR);
omap_cfg_reg(V15_24XX_MCBSP2_DX);
omap_cfg_reg(V14_24XX_GPIO117);
- omap_cfg_reg(W14_24XX_SYS_CLKOUT);
}
#endif
@@ -984,13 +981,7 @@ static int __init omap_mcbsp_init(void)
if (cpu_is_omap24xx()) {
mcbsp_info = mcbsp_24xx;
mcbsp_count = ARRAY_SIZE(mcbsp_24xx);
-
- /* REVISIT: where's the right place? */
omap2_mcbsp2_mux_setup();
- sys_ck = clk_get(0, "sys_ck");
- sys_clkout = clk_get(0, "sys_clkout");
- clk_set_parent(sys_clkout, sys_ck);
- clk_enable(sys_clkout);
}
#endif
for (i = 0; i < OMAP_MAX_MCBSP_COUNT ; i++) {
diff --git a/arch/arm/plat-omap/pm.c b/arch/arm/plat-omap/pm.c
deleted file mode 100644
index 04b4102727a8..000000000000
--- a/arch/arm/plat-omap/pm.c
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * linux/arch/arm/plat-omap/pm.c
- *
- * OMAP Power Management Routines
- *
- * Original code for the SA11x0:
- * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
- *
- * Modified for the PXA250 by Nicolas Pitre:
- * Copyright (c) 2002 Monta Vista Software, Inc.
- *
- * Modified for the OMAP1510 by David Singleton:
- * Copyright (c) 2002 Monta Vista Software, Inc.
- *
- * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/pm.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/pm.h>
-#include <linux/interrupt.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/mach/time.h>
-#include <asm/mach/irq.h>
-
-#include <asm/mach-types.h>
-#include <asm/arch/irqs.h>
-#include <asm/arch/tc.h>
-#include <asm/arch/pm.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/tps65010.h>
-#include <asm/arch/dsp_common.h>
-
-#include <asm/arch/clock.h>
-#include <asm/arch/sram.h>
-
-static unsigned int arm_sleep_save[ARM_SLEEP_SAVE_SIZE];
-static unsigned short ulpd_sleep_save[ULPD_SLEEP_SAVE_SIZE];
-static unsigned int mpui730_sleep_save[MPUI730_SLEEP_SAVE_SIZE];
-static unsigned int mpui1510_sleep_save[MPUI1510_SLEEP_SAVE_SIZE];
-static unsigned int mpui1610_sleep_save[MPUI1610_SLEEP_SAVE_SIZE];
-
-static void (*omap_sram_idle)(void) = NULL;
-static void (*omap_sram_suspend)(unsigned long r0, unsigned long r1) = NULL;
-
-/*
- * Let's power down on idle, but only if we are really
- * idle, because once we start down the path of
- * going idle we continue to do idle even if we get
- * a clock tick interrupt . .
- */
-void omap_pm_idle(void)
-{
- unsigned int mask32 = 0;
-
- /*
- * If the DSP is being used let's just idle the CPU, the overhead
- * to wake up from Big Sleep is big, milliseconds versus micro
- * seconds for wait for interrupt.
- */
-
- local_irq_disable();
- local_fiq_disable();
- if (need_resched()) {
- local_fiq_enable();
- local_irq_enable();
- return;
- }
- mask32 = omap_readl(ARM_SYSST);
-
- /*
- * Prevent the ULPD from entering low power state by setting
- * POWER_CTRL_REG:4 = 0
- */
- omap_writew(omap_readw(ULPD_POWER_CTRL) &
- ~ULPD_DEEP_SLEEP_TRANSITION_EN, ULPD_POWER_CTRL);
-
- /*
- * Since an interrupt may set up a timer, we don't want to
- * reprogram the hardware timer with interrupts enabled.
- * Re-enable interrupts only after returning from idle.
- */
- timer_dyn_reprogram();
-
- if ((mask32 & DSP_IDLE) == 0) {
- __asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
- } else
- omap_sram_idle();
-
- local_fiq_enable();
- local_irq_enable();
-}
-
-/*
- * Configuration of the wakeup event is board specific. For the
- * moment we put it into this helper function. Later it may move
- * to board specific files.
- */
-static void omap_pm_wakeup_setup(void)
-{
- u32 level1_wake = 0;
- u32 level2_wake = OMAP_IRQ_BIT(INT_UART2);
-
- /*
- * Turn off all interrupts except GPIO bank 1, L1-2nd level cascade,
- * and the L2 wakeup interrupts: keypad and UART2. Note that the
- * drivers must still separately call omap_set_gpio_wakeup() to
- * wake up to a GPIO interrupt.
- */
- if (cpu_is_omap730())
- level1_wake = OMAP_IRQ_BIT(INT_730_GPIO_BANK1) |
- OMAP_IRQ_BIT(INT_730_IH2_IRQ);
- else if (cpu_is_omap1510())
- level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
- OMAP_IRQ_BIT(INT_1510_IH2_IRQ);
- else if (cpu_is_omap16xx())
- level1_wake = OMAP_IRQ_BIT(INT_GPIO_BANK1) |
- OMAP_IRQ_BIT(INT_1610_IH2_IRQ);
-
- omap_writel(~level1_wake, OMAP_IH1_MIR);
-
- if (cpu_is_omap730()) {
- omap_writel(~level2_wake, OMAP_IH2_0_MIR);
- omap_writel(~(OMAP_IRQ_BIT(INT_730_WAKE_UP_REQ) | OMAP_IRQ_BIT(INT_730_MPUIO_KEYPAD)), OMAP_IH2_1_MIR);
- } else if (cpu_is_omap1510()) {
- level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
- omap_writel(~level2_wake, OMAP_IH2_MIR);
- } else if (cpu_is_omap16xx()) {
- level2_wake |= OMAP_IRQ_BIT(INT_KEYBOARD);
- omap_writel(~level2_wake, OMAP_IH2_0_MIR);
-
- /* INT_1610_WAKE_UP_REQ is needed for GPIO wakeup... */
- omap_writel(~OMAP_IRQ_BIT(INT_1610_WAKE_UP_REQ), OMAP_IH2_1_MIR);
- omap_writel(~0x0, OMAP_IH2_2_MIR);
- omap_writel(~0x0, OMAP_IH2_3_MIR);
- }
-
- /* New IRQ agreement, recalculate in cascade order */
- omap_writel(1, OMAP_IH2_CONTROL);
- omap_writel(1, OMAP_IH1_CONTROL);
-}
-
-void omap_pm_suspend(void)
-{
- unsigned long arg0 = 0, arg1 = 0;
-
- printk("PM: OMAP%x is trying to enter deep sleep...\n", system_rev);
-
- omap_serial_wake_trigger(1);
-
- if (machine_is_omap_osk()) {
- /* Stop LED1 (D9) blink */
- tps65010_set_led(LED1, OFF);
- }
-
- omap_writew(0xffff, ULPD_SOFT_DISABLE_REQ_REG);
-
- /*
- * Step 1: turn off interrupts (FIXME: NOTE: already disabled)
- */
-
- local_irq_disable();
- local_fiq_disable();
-
- /*
- * Step 2: save registers
- *
- * The omap is a strange/beautiful device. The caches, memory
- * and register state are preserved across power saves.
- * We have to save and restore very little register state to
- * idle the omap.
- *
- * Save interrupt, MPUI, ARM and UPLD control registers.
- */
-
- if (cpu_is_omap730()) {
- MPUI730_SAVE(OMAP_IH1_MIR);
- MPUI730_SAVE(OMAP_IH2_0_MIR);
- MPUI730_SAVE(OMAP_IH2_1_MIR);
- MPUI730_SAVE(MPUI_CTRL);
- MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI730_SAVE(MPUI_DSP_API_CONFIG);
- MPUI730_SAVE(EMIFS_CONFIG);
- MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
-
- } else if (cpu_is_omap1510()) {
- MPUI1510_SAVE(OMAP_IH1_MIR);
- MPUI1510_SAVE(OMAP_IH2_MIR);
- MPUI1510_SAVE(MPUI_CTRL);
- MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
- MPUI1510_SAVE(EMIFS_CONFIG);
- MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
- } else if (cpu_is_omap16xx()) {
- MPUI1610_SAVE(OMAP_IH1_MIR);
- MPUI1610_SAVE(OMAP_IH2_0_MIR);
- MPUI1610_SAVE(OMAP_IH2_1_MIR);
- MPUI1610_SAVE(OMAP_IH2_2_MIR);
- MPUI1610_SAVE(OMAP_IH2_3_MIR);
- MPUI1610_SAVE(MPUI_CTRL);
- MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
- MPUI1610_SAVE(EMIFS_CONFIG);
- MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
- }
-
- ARM_SAVE(ARM_CKCTL);
- ARM_SAVE(ARM_IDLECT1);
- ARM_SAVE(ARM_IDLECT2);
- if (!(cpu_is_omap1510()))
- ARM_SAVE(ARM_IDLECT3);
- ARM_SAVE(ARM_EWUPCT);
- ARM_SAVE(ARM_RSTCT1);
- ARM_SAVE(ARM_RSTCT2);
- ARM_SAVE(ARM_SYSST);
- ULPD_SAVE(ULPD_CLOCK_CTRL);
- ULPD_SAVE(ULPD_STATUS_REQ);
-
- /* (Step 3 removed - we now allow deep sleep by default) */
-
- /*
- * Step 4: OMAP DSP Shutdown
- */
-
-
- /*
- * Step 5: Wakeup Event Setup
- */
-
- omap_pm_wakeup_setup();
-
- /*
- * Step 6: ARM and Traffic controller shutdown
- */
-
- /* disable ARM watchdog */
- omap_writel(0x00F5, OMAP_WDT_TIMER_MODE);
- omap_writel(0x00A0, OMAP_WDT_TIMER_MODE);
-
- /*
- * Step 6b: ARM and Traffic controller shutdown
- *
- * Step 6 continues here. Prepare jump to power management
- * assembly code in internal SRAM.
- *
- * Since the omap_cpu_suspend routine has been copied to
- * SRAM, we'll do an indirect procedure call to it and pass the
- * contents of arm_idlect1 and arm_idlect2 so it can restore
- * them when it wakes up and it will return.
- */
-
- arg0 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT1];
- arg1 = arm_sleep_save[ARM_SLEEP_SAVE_ARM_IDLECT2];
-
- /*
- * Step 6c: ARM and Traffic controller shutdown
- *
- * Jump to assembly code. The processor will stay there
- * until wake up.
- */
- omap_sram_suspend(arg0, arg1);
-
- /*
- * If we are here, processor is woken up!
- */
-
- /*
- * Restore ARM state, except ARM_IDLECT1/2 which omap_cpu_suspend did
- */
-
- if (!(cpu_is_omap1510()))
- ARM_RESTORE(ARM_IDLECT3);
- ARM_RESTORE(ARM_CKCTL);
- ARM_RESTORE(ARM_EWUPCT);
- ARM_RESTORE(ARM_RSTCT1);
- ARM_RESTORE(ARM_RSTCT2);
- ARM_RESTORE(ARM_SYSST);
- ULPD_RESTORE(ULPD_CLOCK_CTRL);
- ULPD_RESTORE(ULPD_STATUS_REQ);
-
- if (cpu_is_omap730()) {
- MPUI730_RESTORE(EMIFS_CONFIG);
- MPUI730_RESTORE(EMIFF_SDRAM_CONFIG);
- MPUI730_RESTORE(OMAP_IH1_MIR);
- MPUI730_RESTORE(OMAP_IH2_0_MIR);
- MPUI730_RESTORE(OMAP_IH2_1_MIR);
- } else if (cpu_is_omap1510()) {
- MPUI1510_RESTORE(MPUI_CTRL);
- MPUI1510_RESTORE(MPUI_DSP_BOOT_CONFIG);
- MPUI1510_RESTORE(MPUI_DSP_API_CONFIG);
- MPUI1510_RESTORE(EMIFS_CONFIG);
- MPUI1510_RESTORE(EMIFF_SDRAM_CONFIG);
- MPUI1510_RESTORE(OMAP_IH1_MIR);
- MPUI1510_RESTORE(OMAP_IH2_MIR);
- } else if (cpu_is_omap16xx()) {
- MPUI1610_RESTORE(MPUI_CTRL);
- MPUI1610_RESTORE(MPUI_DSP_BOOT_CONFIG);
- MPUI1610_RESTORE(MPUI_DSP_API_CONFIG);
- MPUI1610_RESTORE(EMIFS_CONFIG);
- MPUI1610_RESTORE(EMIFF_SDRAM_CONFIG);
-
- MPUI1610_RESTORE(OMAP_IH1_MIR);
- MPUI1610_RESTORE(OMAP_IH2_0_MIR);
- MPUI1610_RESTORE(OMAP_IH2_1_MIR);
- MPUI1610_RESTORE(OMAP_IH2_2_MIR);
- MPUI1610_RESTORE(OMAP_IH2_3_MIR);
- }
-
- omap_writew(0, ULPD_SOFT_DISABLE_REQ_REG);
-
- /*
- * Reenable interrupts
- */
-
- local_irq_enable();
- local_fiq_enable();
-
- omap_serial_wake_trigger(0);
-
- printk("PM: OMAP%x is re-starting from deep sleep...\n", system_rev);
-
- if (machine_is_omap_osk()) {
- /* Let LED1 (D9) blink again */
- tps65010_set_led(LED1, BLINK);
- }
-}
-
-#if defined(DEBUG) && defined(CONFIG_PROC_FS)
-static int g_read_completed;
-
-/*
- * Read system PM registers for debugging
- */
-static int omap_pm_read_proc(
- char *page_buffer,
- char **my_first_byte,
- off_t virtual_start,
- int length,
- int *eof,
- void *data)
-{
- int my_buffer_offset = 0;
- char * const my_base = page_buffer;
-
- ARM_SAVE(ARM_CKCTL);
- ARM_SAVE(ARM_IDLECT1);
- ARM_SAVE(ARM_IDLECT2);
- if (!(cpu_is_omap1510()))
- ARM_SAVE(ARM_IDLECT3);
- ARM_SAVE(ARM_EWUPCT);
- ARM_SAVE(ARM_RSTCT1);
- ARM_SAVE(ARM_RSTCT2);
- ARM_SAVE(ARM_SYSST);
-
- ULPD_SAVE(ULPD_IT_STATUS);
- ULPD_SAVE(ULPD_CLOCK_CTRL);
- ULPD_SAVE(ULPD_SOFT_REQ);
- ULPD_SAVE(ULPD_STATUS_REQ);
- ULPD_SAVE(ULPD_DPLL_CTRL);
- ULPD_SAVE(ULPD_POWER_CTRL);
-
- if (cpu_is_omap730()) {
- MPUI730_SAVE(MPUI_CTRL);
- MPUI730_SAVE(MPUI_DSP_STATUS);
- MPUI730_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI730_SAVE(MPUI_DSP_API_CONFIG);
- MPUI730_SAVE(EMIFF_SDRAM_CONFIG);
- MPUI730_SAVE(EMIFS_CONFIG);
- } else if (cpu_is_omap1510()) {
- MPUI1510_SAVE(MPUI_CTRL);
- MPUI1510_SAVE(MPUI_DSP_STATUS);
- MPUI1510_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI1510_SAVE(MPUI_DSP_API_CONFIG);
- MPUI1510_SAVE(EMIFF_SDRAM_CONFIG);
- MPUI1510_SAVE(EMIFS_CONFIG);
- } else if (cpu_is_omap16xx()) {
- MPUI1610_SAVE(MPUI_CTRL);
- MPUI1610_SAVE(MPUI_DSP_STATUS);
- MPUI1610_SAVE(MPUI_DSP_BOOT_CONFIG);
- MPUI1610_SAVE(MPUI_DSP_API_CONFIG);
- MPUI1610_SAVE(EMIFF_SDRAM_CONFIG);
- MPUI1610_SAVE(EMIFS_CONFIG);
- }
-
- if (virtual_start == 0) {
- g_read_completed = 0;
-
- my_buffer_offset += sprintf(my_base + my_buffer_offset,
- "ARM_CKCTL_REG: 0x%-8x \n"
- "ARM_IDLECT1_REG: 0x%-8x \n"
- "ARM_IDLECT2_REG: 0x%-8x \n"
- "ARM_IDLECT3_REG: 0x%-8x \n"
- "ARM_EWUPCT_REG: 0x%-8x \n"
- "ARM_RSTCT1_REG: 0x%-8x \n"
- "ARM_RSTCT2_REG: 0x%-8x \n"
- "ARM_SYSST_REG: 0x%-8x \n"
- "ULPD_IT_STATUS_REG: 0x%-4x \n"
- "ULPD_CLOCK_CTRL_REG: 0x%-4x \n"
- "ULPD_SOFT_REQ_REG: 0x%-4x \n"
- "ULPD_DPLL_CTRL_REG: 0x%-4x \n"
- "ULPD_STATUS_REQ_REG: 0x%-4x \n"
- "ULPD_POWER_CTRL_REG: 0x%-4x \n",
- ARM_SHOW(ARM_CKCTL),
- ARM_SHOW(ARM_IDLECT1),
- ARM_SHOW(ARM_IDLECT2),
- ARM_SHOW(ARM_IDLECT3),
- ARM_SHOW(ARM_EWUPCT),
- ARM_SHOW(ARM_RSTCT1),
- ARM_SHOW(ARM_RSTCT2),
- ARM_SHOW(ARM_SYSST),
- ULPD_SHOW(ULPD_IT_STATUS),
- ULPD_SHOW(ULPD_CLOCK_CTRL),
- ULPD_SHOW(ULPD_SOFT_REQ),
- ULPD_SHOW(ULPD_DPLL_CTRL),
- ULPD_SHOW(ULPD_STATUS_REQ),
- ULPD_SHOW(ULPD_POWER_CTRL));
-
- if (cpu_is_omap730()) {
- my_buffer_offset += sprintf(my_base + my_buffer_offset,
- "MPUI730_CTRL_REG 0x%-8x \n"
- "MPUI730_DSP_STATUS_REG: 0x%-8x \n"
- "MPUI730_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
- "MPUI730_DSP_API_CONFIG_REG: 0x%-8x \n"
- "MPUI730_SDRAM_CONFIG_REG: 0x%-8x \n"
- "MPUI730_EMIFS_CONFIG_REG: 0x%-8x \n",
- MPUI730_SHOW(MPUI_CTRL),
- MPUI730_SHOW(MPUI_DSP_STATUS),
- MPUI730_SHOW(MPUI_DSP_BOOT_CONFIG),
- MPUI730_SHOW(MPUI_DSP_API_CONFIG),
- MPUI730_SHOW(EMIFF_SDRAM_CONFIG),
- MPUI730_SHOW(EMIFS_CONFIG));
- } else if (cpu_is_omap1510()) {
- my_buffer_offset += sprintf(my_base + my_buffer_offset,
- "MPUI1510_CTRL_REG 0x%-8x \n"
- "MPUI1510_DSP_STATUS_REG: 0x%-8x \n"
- "MPUI1510_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
- "MPUI1510_DSP_API_CONFIG_REG: 0x%-8x \n"
- "MPUI1510_SDRAM_CONFIG_REG: 0x%-8x \n"
- "MPUI1510_EMIFS_CONFIG_REG: 0x%-8x \n",
- MPUI1510_SHOW(MPUI_CTRL),
- MPUI1510_SHOW(MPUI_DSP_STATUS),
- MPUI1510_SHOW(MPUI_DSP_BOOT_CONFIG),
- MPUI1510_SHOW(MPUI_DSP_API_CONFIG),
- MPUI1510_SHOW(EMIFF_SDRAM_CONFIG),
- MPUI1510_SHOW(EMIFS_CONFIG));
- } else if (cpu_is_omap16xx()) {
- my_buffer_offset += sprintf(my_base + my_buffer_offset,
- "MPUI1610_CTRL_REG 0x%-8x \n"
- "MPUI1610_DSP_STATUS_REG: 0x%-8x \n"
- "MPUI1610_DSP_BOOT_CONFIG_REG: 0x%-8x \n"
- "MPUI1610_DSP_API_CONFIG_REG: 0x%-8x \n"
- "MPUI1610_SDRAM_CONFIG_REG: 0x%-8x \n"
- "MPUI1610_EMIFS_CONFIG_REG: 0x%-8x \n",
- MPUI1610_SHOW(MPUI_CTRL),
- MPUI1610_SHOW(MPUI_DSP_STATUS),
- MPUI1610_SHOW(MPUI_DSP_BOOT_CONFIG),
- MPUI1610_SHOW(MPUI_DSP_API_CONFIG),
- MPUI1610_SHOW(EMIFF_SDRAM_CONFIG),
- MPUI1610_SHOW(EMIFS_CONFIG));
- }
-
- g_read_completed++;
- } else if (g_read_completed >= 1) {
- *eof = 1;
- return 0;
- }
- g_read_completed++;
-
- *my_first_byte = page_buffer;
- return my_buffer_offset;
-}
-
-static void omap_pm_init_proc(void)
-{
- struct proc_dir_entry *entry;
-
- entry = create_proc_read_entry("driver/omap_pm",
- S_IWUSR | S_IRUGO, NULL,
- omap_pm_read_proc, NULL);
-}
-
-#endif /* DEBUG && CONFIG_PROC_FS */
-
-/*
- * omap_pm_prepare - Do preliminary suspend work.
- * @state: suspend state we're entering.
- *
- */
-//#include <asm/hardware.h>
-
-static int omap_pm_prepare(suspend_state_t state)
-{
- int error = 0;
-
- switch (state)
- {
- case PM_SUSPEND_STANDBY:
- case PM_SUSPEND_MEM:
- break;
-
- case PM_SUSPEND_DISK:
- return -ENOTSUPP;
-
- default:
- return -EINVAL;
- }
-
- return error;
-}
-
-
-/*
- * omap_pm_enter - Actually enter a sleep state.
- * @state: State we're entering.
- *
- */
-
-static int omap_pm_enter(suspend_state_t state)
-{
- switch (state)
- {
- case PM_SUSPEND_STANDBY:
- case PM_SUSPEND_MEM:
- omap_pm_suspend();
- break;
-
- case PM_SUSPEND_DISK:
- return -ENOTSUPP;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-
-/**
- * omap_pm_finish - Finish up suspend sequence.
- * @state: State we're coming out of.
- *
- * This is called after we wake back up (or if entering the sleep state
- * failed).
- */
-
-static int omap_pm_finish(suspend_state_t state)
-{
- return 0;
-}
-
-
-static irqreturn_t omap_wakeup_interrupt(int irq, void * dev,
- struct pt_regs * regs)
-{
- return IRQ_HANDLED;
-}
-
-static struct irqaction omap_wakeup_irq = {
- .name = "peripheral wakeup",
- .flags = IRQF_DISABLED,
- .handler = omap_wakeup_interrupt
-};
-
-
-
-static struct pm_ops omap_pm_ops ={
- .pm_disk_mode = 0,
- .prepare = omap_pm_prepare,
- .enter = omap_pm_enter,
- .finish = omap_pm_finish,
-};
-
-static int __init omap_pm_init(void)
-{
- printk("Power Management for TI OMAP.\n");
- /*
- * We copy the assembler sleep/wakeup routines to SRAM.
- * These routines need to be in SRAM as that's the only
- * memory the MPU can see when it wakes up.
- */
- if (cpu_is_omap730()) {
- omap_sram_idle = omap_sram_push(omap730_idle_loop_suspend,
- omap730_idle_loop_suspend_sz);
- omap_sram_suspend = omap_sram_push(omap730_cpu_suspend,
- omap730_cpu_suspend_sz);
- } else if (cpu_is_omap1510()) {
- omap_sram_idle = omap_sram_push(omap1510_idle_loop_suspend,
- omap1510_idle_loop_suspend_sz);
- omap_sram_suspend = omap_sram_push(omap1510_cpu_suspend,
- omap1510_cpu_suspend_sz);
- } else if (cpu_is_omap16xx()) {
- omap_sram_idle = omap_sram_push(omap1610_idle_loop_suspend,
- omap1610_idle_loop_suspend_sz);
- omap_sram_suspend = omap_sram_push(omap1610_cpu_suspend,
- omap1610_cpu_suspend_sz);
- }
-
- if (omap_sram_idle == NULL || omap_sram_suspend == NULL) {
- printk(KERN_ERR "PM not initialized: Missing SRAM support\n");
- return -ENODEV;
- }
-
- pm_idle = omap_pm_idle;
-
- if (cpu_is_omap730())
- setup_irq(INT_730_WAKE_UP_REQ, &omap_wakeup_irq);
- else if (cpu_is_omap16xx())
- setup_irq(INT_1610_WAKE_UP_REQ, &omap_wakeup_irq);
-
-#if 0
- /* --- BEGIN BOARD-DEPENDENT CODE --- */
- /* Sleepx mask direction */
- omap_writew((omap_readw(0xfffb5008) & ~2), 0xfffb5008);
- /* Unmask sleepx signal */
- omap_writew((omap_readw(0xfffb5004) & ~2), 0xfffb5004);
- /* --- END BOARD-DEPENDENT CODE --- */
-#endif
-
- /* Program new power ramp-up time
- * (0 for most boards since we don't lower voltage when in deep sleep)
- */
- omap_writew(ULPD_SETUP_ANALOG_CELL_3_VAL, ULPD_SETUP_ANALOG_CELL_3);
-
- /* Setup ULPD POWER_CTRL_REG - enter deep sleep whenever possible */
- omap_writew(ULPD_POWER_CTRL_REG_VAL, ULPD_POWER_CTRL);
-
- /* Configure IDLECT3 */
- if (cpu_is_omap730())
- omap_writel(OMAP730_IDLECT3_VAL, OMAP730_IDLECT3);
- else if (cpu_is_omap16xx())
- omap_writel(OMAP1610_IDLECT3_VAL, OMAP1610_IDLECT3);
-
- pm_set_ops(&omap_pm_ops);
-
-#if defined(DEBUG) && defined(CONFIG_PROC_FS)
- omap_pm_init_proc();
-#endif
-
- if (cpu_is_omap16xx()) {
- /* configure LOW_PWR pin */
- omap_cfg_reg(T20_1610_LOW_PWR);
- }
-
- return 0;
-}
-__initcall(omap_pm_init);
-
diff --git a/arch/arm/plat-omap/sram-fn.S b/arch/arm/plat-omap/sram-fn.S
index 85cffe2c6266..9e1813c77e05 100644
--- a/arch/arm/plat-omap/sram-fn.S
+++ b/arch/arm/plat-omap/sram-fn.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/plat-omap/sram.S
+ * linux/arch/arm/plat-omap/sram-fn.S
*
* Functions that need to be run in internal SRAM
*
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index e75718301b0f..19014b2ff4c6 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -174,10 +174,7 @@ void __init omap_map_sram(void)
if (cpu_is_omap24xx()) {
omap_sram_io_desc[0].virtual = OMAP2_SRAM_VA;
- if (is_sram_locked())
- base = OMAP2_SRAM_PUB_PA;
- else
- base = OMAP2_SRAM_PA;
+ base = OMAP2_SRAM_PA;
base = ROUND_DOWN(base, PAGE_SIZE);
omap_sram_io_desc[0].pfn = __phys_to_pfn(base);
}
diff --git a/arch/arm/plat-omap/timer32k.c b/arch/arm/plat-omap/timer32k.c
index 281ecc7fcdfc..265310601161 100644
--- a/arch/arm/plat-omap/timer32k.c
+++ b/arch/arm/plat-omap/timer32k.c
@@ -105,6 +105,8 @@ static inline unsigned long omap_32k_timer_read(int reg)
static inline void omap_32k_timer_start(unsigned long load_val)
{
+ if (!load_val)
+ load_val = 1;
omap_32k_timer_write(load_val, OMAP1_32K_TIMER_TVR);
omap_32k_timer_write(0x0f, OMAP1_32K_TIMER_CR);
}
@@ -192,21 +194,17 @@ unsigned long long sched_clock(void)
* issues with dynamic tick. In the dynamic tick case, we need to lock
* with irqsave.
*/
-static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static inline irqreturn_t _omap_32k_timer_interrupt(int irq, void *dev_id)
{
- unsigned long flags;
unsigned long now;
- write_seqlock_irqsave(&xtime_lock, flags);
-
omap_32k_timer_ack_irq();
now = omap_32k_sync_timer_read();
while ((signed long)(now - omap_32k_last_tick)
>= OMAP_32K_TICKS_PER_HZ) {
omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
- timer_tick(regs);
+ timer_tick();
}
/* Restart timer so we don't drift off due to modulo or dynamic tick.
@@ -215,6 +213,21 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
* continuous timer can be overridden from pm_idle to be longer.
*/
omap_32k_timer_start(omap_32k_last_tick + OMAP_32K_TICKS_PER_HZ - now);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t omap_32k_timer_handler(int irq, void *dev_id)
+{
+ return _omap_32k_timer_interrupt(irq, dev_id);
+}
+
+static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id)
+{
+ unsigned long flags;
+
+ write_seqlock_irqsave(&xtime_lock, flags);
+ _omap_32k_timer_interrupt(irq, dev_id);
write_sequnlock_irqrestore(&xtime_lock, flags);
return IRQ_HANDLED;
@@ -230,7 +243,15 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
*/
void omap_32k_timer_reprogram(unsigned long next_tick)
{
- omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
+ unsigned long ticks = JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1;
+ unsigned long now = omap_32k_sync_timer_read();
+ unsigned long idled = now - omap_32k_last_tick;
+
+ if (idled + 1 < ticks)
+ ticks -= idled;
+ else
+ ticks = 1;
+ omap_32k_timer_start(ticks);
}
static struct irqaction omap_32k_timer_irq;
@@ -252,7 +273,7 @@ static struct dyn_tick_timer omap_dyn_tick_timer = {
.enable = omap_32k_timer_enable_dyn_tick,
.disable = omap_32k_timer_disable_dyn_tick,
.reprogram = omap_32k_timer_reprogram,
- .handler = omap_32k_timer_interrupt,
+ .handler = omap_32k_timer_handler,
};
#endif /* CONFIG_NO_IDLE_HZ */
diff --git a/arch/arm/plat-omap/usb.c b/arch/arm/plat-omap/usb.c
index 9b815327b6a5..7e8096809be2 100644
--- a/arch/arm/plat-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -26,7 +26,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/platform_device.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
#include <asm/io.h>
#include <asm/irq.h>
diff --git a/arch/arm/tools/gen-mach-types b/arch/arm/tools/gen-mach-types
index 2f9c9b5dd260..ce319ef64bc1 100644
--- a/arch/arm/tools/gen-mach-types
+++ b/arch/arm/tools/gen-mach-types
@@ -28,7 +28,6 @@ END {
printf(" */\n\n");
printf("#ifndef __ASM_ARM_MACH_TYPE_H\n");
printf("#define __ASM_ARM_MACH_TYPE_H\n\n");
- printf("#include <linux/config.h>\n\n");
printf("#ifndef __ASSEMBLY__\n");
printf("/* The type of machine we're running on */\n");
printf("extern unsigned int __machine_arch_type;\n");
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index e1372a25311d..579c69ae9ff7 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -4,7 +4,7 @@
#
# Up to date versions of this file can be obtained from:
#
-# http://www.arm.linux.org.uk/developer/machines/?action=download
+# http://www.arm.linux.org.uk/developer/machines/download.php
#
# Please do not send patches to this file; it is automatically generated!
# To add an entry into this database, please see Documentation/arm/README,
@@ -12,7 +12,7 @@
#
# http://www.arm.linux.org.uk/developer/machines/?action=new
#
-# Last update: Mon Jun 26 22:26:08 2006
+# Last update: Mon Oct 16 21:13:36 2006
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
@@ -329,7 +329,7 @@ nimbra29x ARCH_NIMBRA29X NIMBRA29X 311
nimbra210 ARCH_NIMBRA210 NIMBRA210 312
hhp_d95xx ARCH_HHP_D95XX HHP_D95XX 313
labarm ARCH_LABARM LABARM 314
-comcerto ARCH_M825XX M825XX 315
+m825xx ARCH_M825XX M825XX 315
m7100 SA1100_M7100 M7100 316
nipc2 ARCH_NIPC2 NIPC2 317
fu7202 ARCH_FU7202 FU7202 318
@@ -857,12 +857,12 @@ osiris MACH_OSIRIS OSIRIS 842
maestro MACH_MAESTRO MAESTRO 843
tunge2 MACH_TUNGE2 TUNGE2 844
ixbbm MACH_IXBBM IXBBM 845
-mx27ads MACH_MX27 MX27 846
+mx27ads MACH_MX27ADS MX27ADS 846
ax8004 MACH_AX8004 AX8004 847
at91sam9261ek MACH_AT91SAM9261EK AT91SAM9261EK 848
loft MACH_LOFT LOFT 849
magpie MACH_MAGPIE MAGPIE 850
-mx21ads MACH_MX21 MX21 851
+mx21ads MACH_MX21ADS MX21ADS 851
mb87m3400 MACH_MB87M3400 MB87M3400 852
mguard_delta MACH_MGUARD_DELTA MGUARD_DELTA 853
davinci_dvdp MACH_DAVINCI_DVDP DAVINCI_DVDP 854
@@ -1058,7 +1058,7 @@ akai9307 MACH_AKAI9307 AKAI9307 1044
fontaine MACH_FONTAINE FONTAINE 1045
wombat MACH_WOMBAT WOMBAT 1046
acq300 MACH_ACQ300 ACQ300 1047
-mod_270 MACH_MOD_270 MOD_270 1048
+mod272 MACH_MOD_270 MOD_270 1048
vmc_vc0820 MACH_VC0820 VC0820 1049
ani_aim MACH_ANI_AIM ANI_AIM 1050
jellyfish MACH_JELLYFISH JELLYFISH 1051
@@ -1093,3 +1093,81 @@ msm6100 MACH_MSM6100 MSM6100 1079
eti_b1 MACH_ETI_B1 ETI_B1 1080
za9l_series MACH_ZILOG_ZA9L ZILOG_ZA9L 1081
bit2440 MACH_BIT2440 BIT2440 1082
+nbi MACH_NBI NBI 1083
+smdk2443 MACH_SMDK2443 SMDK2443 1084
+vdavinci MACH_VDAVINCI VDAVINCI 1085
+atc6 MACH_ATC6 ATC6 1086
+multmdw MACH_MULTMDW MULTMDW 1087
+mba2440 MACH_MBA2440 MBA2440 1088
+ecsd MACH_ECSD ECSD 1089
+zire31 MACH_ZIRE31 ZIRE31 1090
+fsg MACH_FSG FSG 1091
+razor101 MACH_RAZOR101 RAZOR101 1092
+opera_tdm MACH_OPERA_TDM OPERA_TDM 1093
+comcerto MACH_COMCERTO COMCERTO 1094
+tb0319 MACH_TB0319 TB0319 1095
+kws8000 MACH_KWS8000 KWS8000 1096
+b2 MACH_B2 B2 1097
+lcl54 MACH_LCL54 LCL54 1098
+at91sam9260ek MACH_AT91SAM9260EK AT91SAM9260EK 1099
+glantank MACH_GLANTANK GLANTANK 1100
+n2100 MACH_N2100 N2100 1101
+n4100 MACH_N4100 N4100 1102
+rsc4 MACH_VERTICAL_RSC4 VERTICAL_RSC4 1103
+sg8100 MACH_SG8100 SG8100 1104
+im42xx MACH_IM42XX IM42XX 1105
+ftxx MACH_FTXX FTXX 1106
+lwfusion MACH_LWFUSION LWFUSION 1107
+qt2410 MACH_QT2410 QT2410 1108
+kixrp435 MACH_KIXRP435 KIXRP435 1109
+ccw9c MACH_CCW9C CCW9C 1110
+dabhs MACH_DABHS DABHS 1111
+gzmx MACH_GZMX GZMX 1112
+ipnw100ap MACH_IPNW100AP IPNW100AP 1113
+cc9p9360dev MACH_CC9P9360DEV CC9P9360DEV 1114
+cc9p9750dev MACH_CC9P9750DEV CC9P9750DEV 1115
+cc9p9360val MACH_CC9P9360VAL CC9P9360VAL 1116
+cc9p9750val MACH_CC9P9750VAL CC9P9750VAL 1117
+nx70v MACH_NX70V NX70V 1118
+at91rm9200df MACH_AT91RM9200DF AT91RM9200DF 1119
+se_pilot2 MACH_SE_PILOT2 SE_PILOT2 1120
+mtcn_t800 MACH_MTCN_T800 MTCN_T800 1121
+vcmx212 MACH_VCMX212 VCMX212 1122
+lynx MACH_LYNX LYNX 1123
+at91sam9260id MACH_AT91SAM9260ID AT91SAM9260ID 1124
+hw86052 MACH_HW86052 HW86052 1125
+pilz_pmi3 MACH_PILZ_PMI3 PILZ_PMI3 1126
+edb9302a MACH_EDB9302A EDB9302A 1127
+edb9307a MACH_EDB9307A EDB9307A 1128
+ct_dfs MACH_CT_DFS CT_DFS 1129
+pilz_pmi4 MACH_PILZ_PMI4 PILZ_PMI4 1130
+xceednp_ixp MACH_XCEEDNP_IXP XCEEDNP_IXP 1131
+smdk2442b MACH_SMDK2442B SMDK2442B 1132
+xnode MACH_XNODE XNODE 1133
+aidx270 MACH_AIDX270 AIDX270 1134
+rema MACH_REMA REMA 1135
+bps1000 MACH_BPS1000 BPS1000 1136
+hw90350 MACH_HW90350 HW90350 1137
+omap_sdp3430 MACH_OMAP_SDP3430 OMAP_SDP3430 1138
+bluetouch MACH_BLUETOUCH BLUETOUCH 1139
+vstms MACH_VSTMS VSTMS 1140
+xsbase270 MACH_XSBASE270 XSBASE270 1141
+at91sam9260ek_cn MACH_AT91SAM9260EK_CN AT91SAM9260EK_CN 1142
+adsturboxb MACH_ADSTURBOXB ADSTURBOXB 1143
+oti4110 MACH_OTI4110 OTI4110 1144
+hme_pxa MACH_HME_PXA HME_PXA 1145
+deisterdca MACH_DEISTERDCA DEISTERDCA 1146
+ces_ssem2 MACH_CES_SSEM2 CES_SSEM2 1147
+ces_mtr MACH_CES_MTR CES_MTR 1148
+tds_avng_sbc MACH_TDS_AVNG_SBC TDS_AVNG_SBC 1149
+everest MACH_EVEREST EVEREST 1150
+pnx4010 MACH_PNX4010 PNX4010 1151
+oxnas MACH_OXNAS OXNAS 1152
+fiori MACH_FIORI FIORI 1153
+ml1200 MACH_ML1200 ML1200 1154
+cactus MACH_CACTUS CACTUS 1155
+nb2xxx MACH_NB2XXX NB2XXX 1156
+hw6900 MACH_HW6900 HW6900 1157
+cdcs_quoll MACH_CDCS_QUOLL CDCS_QUOLL 1158
+quicksilver MACH_QUICKSILVER QUICKSILVER 1159
+uplat926 MACH_UPLAT926 UPLAT926 1160
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index 96fdf30f6a3b..f2797896e6d5 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -355,3 +355,18 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand);
* we check for an error.
*/
#define VFP_EXCEPTION_ERROR ((u32)-1 & ~VFP_NAN_FLAG)
+
+/*
+ * A flag to tell vfp instruction type.
+ * OP_SCALAR - this operation always operates in scalar mode
+ * OP_SD - the instruction exceptionally writes to a single precision result.
+ * OP_DD - the instruction exceptionally writes to a double precision result.
+ */
+#define OP_SCALAR (1 << 0)
+#define OP_SD (1 << 1)
+#define OP_DD (1 << 1)
+
+struct op {
+ u32 (* const fn)(int dd, int dn, int dm, u32 fpscr);
+ u32 flags;
+};
diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c
index add48e36c2dc..4fc05ee0a2ef 100644
--- a/arch/arm/vfp/vfpdouble.c
+++ b/arch/arm/vfp/vfpdouble.c
@@ -659,22 +659,22 @@ static u32 vfp_double_ftosiz(int dd, int unused, int dm, u32 fpscr)
}
-static u32 (* const fop_extfns[32])(int dd, int unused, int dm, u32 fpscr) = {
- [FEXT_TO_IDX(FEXT_FCPY)] = vfp_double_fcpy,
- [FEXT_TO_IDX(FEXT_FABS)] = vfp_double_fabs,
- [FEXT_TO_IDX(FEXT_FNEG)] = vfp_double_fneg,
- [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_double_fsqrt,
- [FEXT_TO_IDX(FEXT_FCMP)] = vfp_double_fcmp,
- [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_double_fcmpe,
- [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_double_fcmpz,
- [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_double_fcmpez,
- [FEXT_TO_IDX(FEXT_FCVT)] = vfp_double_fcvts,
- [FEXT_TO_IDX(FEXT_FUITO)] = vfp_double_fuito,
- [FEXT_TO_IDX(FEXT_FSITO)] = vfp_double_fsito,
- [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_double_ftoui,
- [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_double_ftouiz,
- [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_double_ftosi,
- [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_double_ftosiz,
+static struct op fops_ext[32] = {
+ [FEXT_TO_IDX(FEXT_FCPY)] = { vfp_double_fcpy, 0 },
+ [FEXT_TO_IDX(FEXT_FABS)] = { vfp_double_fabs, 0 },
+ [FEXT_TO_IDX(FEXT_FNEG)] = { vfp_double_fneg, 0 },
+ [FEXT_TO_IDX(FEXT_FSQRT)] = { vfp_double_fsqrt, 0 },
+ [FEXT_TO_IDX(FEXT_FCMP)] = { vfp_double_fcmp, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCMPE)] = { vfp_double_fcmpe, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCMPZ)] = { vfp_double_fcmpz, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCMPEZ)] = { vfp_double_fcmpez, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCVT)] = { vfp_double_fcvts, OP_SCALAR|OP_SD },
+ [FEXT_TO_IDX(FEXT_FUITO)] = { vfp_double_fuito, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FSITO)] = { vfp_double_fsito, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FTOUI)] = { vfp_double_ftoui, OP_SCALAR|OP_SD },
+ [FEXT_TO_IDX(FEXT_FTOUIZ)] = { vfp_double_ftouiz, OP_SCALAR|OP_SD },
+ [FEXT_TO_IDX(FEXT_FTOSI)] = { vfp_double_ftosi, OP_SCALAR|OP_SD },
+ [FEXT_TO_IDX(FEXT_FTOSIZ)] = { vfp_double_ftosiz, OP_SCALAR|OP_SD },
};
@@ -1108,16 +1108,16 @@ static u32 vfp_double_fdiv(int dd, int dn, int dm, u32 fpscr)
return FPSCR_IOC;
}
-static u32 (* const fop_fns[16])(int dd, int dn, int dm, u32 fpscr) = {
- [FOP_TO_IDX(FOP_FMAC)] = vfp_double_fmac,
- [FOP_TO_IDX(FOP_FNMAC)] = vfp_double_fnmac,
- [FOP_TO_IDX(FOP_FMSC)] = vfp_double_fmsc,
- [FOP_TO_IDX(FOP_FNMSC)] = vfp_double_fnmsc,
- [FOP_TO_IDX(FOP_FMUL)] = vfp_double_fmul,
- [FOP_TO_IDX(FOP_FNMUL)] = vfp_double_fnmul,
- [FOP_TO_IDX(FOP_FADD)] = vfp_double_fadd,
- [FOP_TO_IDX(FOP_FSUB)] = vfp_double_fsub,
- [FOP_TO_IDX(FOP_FDIV)] = vfp_double_fdiv,
+static struct op fops[16] = {
+ [FOP_TO_IDX(FOP_FMAC)] = { vfp_double_fmac, 0 },
+ [FOP_TO_IDX(FOP_FNMAC)] = { vfp_double_fnmac, 0 },
+ [FOP_TO_IDX(FOP_FMSC)] = { vfp_double_fmsc, 0 },
+ [FOP_TO_IDX(FOP_FNMSC)] = { vfp_double_fnmsc, 0 },
+ [FOP_TO_IDX(FOP_FMUL)] = { vfp_double_fmul, 0 },
+ [FOP_TO_IDX(FOP_FNMUL)] = { vfp_double_fnmul, 0 },
+ [FOP_TO_IDX(FOP_FADD)] = { vfp_double_fadd, 0 },
+ [FOP_TO_IDX(FOP_FSUB)] = { vfp_double_fsub, 0 },
+ [FOP_TO_IDX(FOP_FDIV)] = { vfp_double_fdiv, 0 },
};
#define FREG_BANK(x) ((x) & 0x0c)
@@ -1131,69 +1131,60 @@ u32 vfp_double_cpdo(u32 inst, u32 fpscr)
unsigned int dn = vfp_get_dn(inst);
unsigned int dm = vfp_get_dm(inst);
unsigned int vecitr, veclen, vecstride;
- u32 (*fop)(int, int, s32, u32);
+ struct op *fop;
- veclen = fpscr & FPSCR_LENGTH_MASK;
vecstride = (1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK)) * 2;
+ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
+
/*
* fcvtds takes an sN register number as destination, not dN.
* It also always operates on scalars.
*/
- if ((inst & FEXT_MASK) == FEXT_FCVT) {
- veclen = 0;
+ if (fop->flags & OP_SD)
dest = vfp_get_sd(inst);
- } else
+ else
dest = vfp_get_dd(inst);
/*
* If destination bank is zero, vector length is always '1'.
* ARM DDI0100F C5.1.3, C5.3.2.
*/
- if (FREG_BANK(dest) == 0)
+ if ((fop->flags & OP_SCALAR) || (FREG_BANK(dest) == 0))
veclen = 0;
+ else
+ veclen = fpscr & FPSCR_LENGTH_MASK;
pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
(veclen >> FPSCR_LENGTH_BIT) + 1);
- fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)];
- if (!fop)
+ if (!fop->fn)
goto invalid;
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
u32 except;
+ char type;
- if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT)
- pr_debug("VFP: itr%d (s%u) = op[%u] (d%u)\n",
- vecitr >> FPSCR_LENGTH_BIT,
- dest, dn, dm);
- else if (op == FOP_EXT)
- pr_debug("VFP: itr%d (d%u) = op[%u] (d%u)\n",
+ type = fop->flags & OP_SD ? 's' : 'd';
+ if (op == FOP_EXT)
+ pr_debug("VFP: itr%d (%c%u) = op[%u] (d%u)\n",
vecitr >> FPSCR_LENGTH_BIT,
- dest, dn, dm);
+ type, dest, dn, dm);
else
- pr_debug("VFP: itr%d (d%u) = (d%u) op[%u] (d%u)\n",
+ pr_debug("VFP: itr%d (%c%u) = (d%u) op[%u] (d%u)\n",
vecitr >> FPSCR_LENGTH_BIT,
- dest, dn, FOP_TO_IDX(op), dm);
+ type, dest, dn, FOP_TO_IDX(op), dm);
- except = fop(dest, dn, dm, fpscr);
+ except = fop->fn(dest, dn, dm, fpscr);
pr_debug("VFP: itr%d: exceptions=%08x\n",
vecitr >> FPSCR_LENGTH_BIT, except);
exceptions |= except;
/*
- * This ensures that comparisons only operate on scalars;
- * comparisons always return with one FPSCR status bit set.
- */
- if (except & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
- break;
-
- /*
* CHECK: It appears to be undefined whether we stop when
* we encounter an exception. We continue.
*/
-
dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 6);
dn = FREG_BANK(dn) + ((FREG_IDX(dn) + vecstride) & 6);
if (FREG_BANK(dm) != 0)
diff --git a/arch/arm/vfp/vfpinstr.h b/arch/arm/vfp/vfpinstr.h
index 6c819aeae006..7f343a4beca0 100644
--- a/arch/arm/vfp/vfpinstr.h
+++ b/arch/arm/vfp/vfpinstr.h
@@ -73,14 +73,14 @@
#define fmrx(_vfp_) ({ \
u32 __v; \
- asm("mrc%? p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmrx %0, " #_vfp_ \
- : "=r" (__v)); \
+ asm("mrc p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmrx %0, " #_vfp_ \
+ : "=r" (__v) : : "cc"); \
__v; \
})
#define fmxr(_vfp_,_var_) \
- asm("mcr%? p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \
- : : "r" (_var_))
+ asm("mcr p10, 7, %0, " vfpreg(_vfp_) ", cr0, 0 @ fmxr " #_vfp_ ", %0" \
+ : : "r" (_var_) : "cc")
u32 vfp_single_cpdo(u32 inst, u32 fpscr);
u32 vfp_single_cprt(u32 inst, u32 fpscr, struct pt_regs *regs);
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 4178f6cc3d37..a657a28f08db 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -40,10 +40,19 @@ unsigned int VFP_arch;
static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
{
struct thread_info *thread = v;
- union vfp_state *vfp = &thread->vfpstate;
+ union vfp_state *vfp;
- switch (cmd) {
- case THREAD_NOTIFY_FLUSH:
+ if (likely(cmd == THREAD_NOTIFY_SWITCH)) {
+ /*
+ * Always disable VFP so we can lazily save/restore the
+ * old state.
+ */
+ fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
+ return NOTIFY_DONE;
+ }
+
+ vfp = &thread->vfpstate;
+ if (cmd == THREAD_NOTIFY_FLUSH) {
/*
* Per-thread VFP initialisation.
*/
@@ -56,29 +65,12 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v)
* Disable VFP to ensure we initialise it first.
*/
fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
-
- /*
- * FALLTHROUGH: Ensure we don't try to overwrite our newly
- * initialised state information on the first fault.
- */
-
- case THREAD_NOTIFY_RELEASE:
- /*
- * Per-thread VFP cleanup.
- */
- if (last_VFP_context == vfp)
- last_VFP_context = NULL;
- break;
-
- case THREAD_NOTIFY_SWITCH:
- /*
- * Always disable VFP so we can lazily save/restore the
- * old state.
- */
- fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_ENABLE);
- break;
}
+ /* flush and release case: Per-thread VFP cleanup. */
+ if (last_VFP_context == vfp)
+ last_VFP_context = NULL;
+
return NOTIFY_DONE;
}
@@ -98,7 +90,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
info.si_signo = SIGFPE;
info.si_code = sicode;
- info.si_addr = (void *)(instruction_pointer(regs) - 4);
+ info.si_addr = (void __user *)(instruction_pointer(regs) - 4);
/*
* This is the same as NWFPE, because it's not clear what
diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c
index 8f6c179cafbe..0221ba3bc799 100644
--- a/arch/arm/vfp/vfpsingle.c
+++ b/arch/arm/vfp/vfpsingle.c
@@ -198,8 +198,10 @@ u32 vfp_single_normaliseround(int sd, struct vfp_single *vs, u32 fpscr, u32 exce
vfp_single_dump("pack: final", vs);
{
s32 d = vfp_single_pack(vs);
+#ifdef DEBUG
pr_debug("VFP: %s: d(s%d)=%08x exceptions=%08x\n", func,
sd, d, exceptions);
+#endif
vfp_put_float(d, sd);
}
@@ -702,22 +704,22 @@ static u32 vfp_single_ftosiz(int sd, int unused, s32 m, u32 fpscr)
return vfp_single_ftosi(sd, unused, m, FPSCR_ROUND_TOZERO);
}
-static u32 (* const fop_extfns[32])(int sd, int unused, s32 m, u32 fpscr) = {
- [FEXT_TO_IDX(FEXT_FCPY)] = vfp_single_fcpy,
- [FEXT_TO_IDX(FEXT_FABS)] = vfp_single_fabs,
- [FEXT_TO_IDX(FEXT_FNEG)] = vfp_single_fneg,
- [FEXT_TO_IDX(FEXT_FSQRT)] = vfp_single_fsqrt,
- [FEXT_TO_IDX(FEXT_FCMP)] = vfp_single_fcmp,
- [FEXT_TO_IDX(FEXT_FCMPE)] = vfp_single_fcmpe,
- [FEXT_TO_IDX(FEXT_FCMPZ)] = vfp_single_fcmpz,
- [FEXT_TO_IDX(FEXT_FCMPEZ)] = vfp_single_fcmpez,
- [FEXT_TO_IDX(FEXT_FCVT)] = vfp_single_fcvtd,
- [FEXT_TO_IDX(FEXT_FUITO)] = vfp_single_fuito,
- [FEXT_TO_IDX(FEXT_FSITO)] = vfp_single_fsito,
- [FEXT_TO_IDX(FEXT_FTOUI)] = vfp_single_ftoui,
- [FEXT_TO_IDX(FEXT_FTOUIZ)] = vfp_single_ftouiz,
- [FEXT_TO_IDX(FEXT_FTOSI)] = vfp_single_ftosi,
- [FEXT_TO_IDX(FEXT_FTOSIZ)] = vfp_single_ftosiz,
+static struct op fops_ext[32] = {
+ [FEXT_TO_IDX(FEXT_FCPY)] = { vfp_single_fcpy, 0 },
+ [FEXT_TO_IDX(FEXT_FABS)] = { vfp_single_fabs, 0 },
+ [FEXT_TO_IDX(FEXT_FNEG)] = { vfp_single_fneg, 0 },
+ [FEXT_TO_IDX(FEXT_FSQRT)] = { vfp_single_fsqrt, 0 },
+ [FEXT_TO_IDX(FEXT_FCMP)] = { vfp_single_fcmp, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCMPE)] = { vfp_single_fcmpe, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCMPZ)] = { vfp_single_fcmpz, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCMPEZ)] = { vfp_single_fcmpez, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FCVT)] = { vfp_single_fcvtd, OP_SCALAR|OP_DD },
+ [FEXT_TO_IDX(FEXT_FUITO)] = { vfp_single_fuito, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FSITO)] = { vfp_single_fsito, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FTOUI)] = { vfp_single_ftoui, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FTOUIZ)] = { vfp_single_ftouiz, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FTOSI)] = { vfp_single_ftosi, OP_SCALAR },
+ [FEXT_TO_IDX(FEXT_FTOSIZ)] = { vfp_single_ftosiz, OP_SCALAR },
};
@@ -1151,16 +1153,16 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
return FPSCR_IOC;
}
-static u32 (* const fop_fns[16])(int sd, int sn, s32 m, u32 fpscr) = {
- [FOP_TO_IDX(FOP_FMAC)] = vfp_single_fmac,
- [FOP_TO_IDX(FOP_FNMAC)] = vfp_single_fnmac,
- [FOP_TO_IDX(FOP_FMSC)] = vfp_single_fmsc,
- [FOP_TO_IDX(FOP_FNMSC)] = vfp_single_fnmsc,
- [FOP_TO_IDX(FOP_FMUL)] = vfp_single_fmul,
- [FOP_TO_IDX(FOP_FNMUL)] = vfp_single_fnmul,
- [FOP_TO_IDX(FOP_FADD)] = vfp_single_fadd,
- [FOP_TO_IDX(FOP_FSUB)] = vfp_single_fsub,
- [FOP_TO_IDX(FOP_FDIV)] = vfp_single_fdiv,
+static struct op fops[16] = {
+ [FOP_TO_IDX(FOP_FMAC)] = { vfp_single_fmac, 0 },
+ [FOP_TO_IDX(FOP_FNMAC)] = { vfp_single_fnmac, 0 },
+ [FOP_TO_IDX(FOP_FMSC)] = { vfp_single_fmsc, 0 },
+ [FOP_TO_IDX(FOP_FNMSC)] = { vfp_single_fnmsc, 0 },
+ [FOP_TO_IDX(FOP_FMUL)] = { vfp_single_fmul, 0 },
+ [FOP_TO_IDX(FOP_FNMUL)] = { vfp_single_fnmul, 0 },
+ [FOP_TO_IDX(FOP_FADD)] = { vfp_single_fadd, 0 },
+ [FOP_TO_IDX(FOP_FSUB)] = { vfp_single_fsub, 0 },
+ [FOP_TO_IDX(FOP_FDIV)] = { vfp_single_fdiv, 0 },
};
#define FREG_BANK(x) ((x) & 0x18)
@@ -1174,70 +1176,63 @@ u32 vfp_single_cpdo(u32 inst, u32 fpscr)
unsigned int sn = vfp_get_sn(inst);
unsigned int sm = vfp_get_sm(inst);
unsigned int vecitr, veclen, vecstride;
- u32 (*fop)(int, int, s32, u32);
+ struct op *fop;
- veclen = fpscr & FPSCR_LENGTH_MASK;
vecstride = 1 + ((fpscr & FPSCR_STRIDE_MASK) == FPSCR_STRIDE_MASK);
+ fop = (op == FOP_EXT) ? &fops_ext[FEXT_TO_IDX(inst)] : &fops[FOP_TO_IDX(op)];
+
/*
* fcvtsd takes a dN register number as destination, not sN.
* Technically, if bit 0 of dd is set, this is an invalid
* instruction. However, we ignore this for efficiency.
* It also only operates on scalars.
*/
- if ((inst & FEXT_MASK) == FEXT_FCVT) {
- veclen = 0;
+ if (fop->flags & OP_DD)
dest = vfp_get_dd(inst);
- } else
+ else
dest = vfp_get_sd(inst);
/*
* If destination bank is zero, vector length is always '1'.
* ARM DDI0100F C5.1.3, C5.3.2.
*/
- if (FREG_BANK(dest) == 0)
+ if ((fop->flags & OP_SCALAR) || FREG_BANK(dest) == 0)
veclen = 0;
+ else
+ veclen = fpscr & FPSCR_LENGTH_MASK;
pr_debug("VFP: vecstride=%u veclen=%u\n", vecstride,
(veclen >> FPSCR_LENGTH_BIT) + 1);
- fop = (op == FOP_EXT) ? fop_extfns[FEXT_TO_IDX(inst)] : fop_fns[FOP_TO_IDX(op)];
- if (!fop)
+ if (!fop->fn)
goto invalid;
for (vecitr = 0; vecitr <= veclen; vecitr += 1 << FPSCR_LENGTH_BIT) {
s32 m = vfp_get_float(sm);
u32 except;
+ char type;
- if (op == FOP_EXT && (inst & FEXT_MASK) == FEXT_FCVT)
- pr_debug("VFP: itr%d (d%u) = op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m);
- else if (op == FOP_EXT)
- pr_debug("VFP: itr%d (s%u) = op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, dest, sn, sm, m);
+ type = fop->flags & OP_DD ? 'd' : 's';
+ if (op == FOP_EXT)
+ pr_debug("VFP: itr%d (%c%u) = op[%u] (s%u=%08x)\n",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
+ sm, m);
else
- pr_debug("VFP: itr%d (s%u) = (s%u) op[%u] (s%u=%08x)\n",
- vecitr >> FPSCR_LENGTH_BIT, dest, sn,
+ pr_debug("VFP: itr%d (%c%u) = (s%u) op[%u] (s%u=%08x)\n",
+ vecitr >> FPSCR_LENGTH_BIT, type, dest, sn,
FOP_TO_IDX(op), sm, m);
- except = fop(dest, sn, m, fpscr);
+ except = fop->fn(dest, sn, m, fpscr);
pr_debug("VFP: itr%d: exceptions=%08x\n",
vecitr >> FPSCR_LENGTH_BIT, except);
exceptions |= except;
/*
- * This ensures that comparisons only operate on scalars;
- * comparisons always return with one FPSCR status bit set.
- */
- if (except & (FPSCR_N|FPSCR_Z|FPSCR_C|FPSCR_V))
- break;
-
- /*
* CHECK: It appears to be undefined whether we stop when
* we encounter an exception. We continue.
*/
-
dest = FREG_BANK(dest) + ((FREG_IDX(dest) + vecstride) & 7);
sn = FREG_BANK(sn) + ((FREG_IDX(sn) + vecstride) & 7);
if (FREG_BANK(sm) != 0)
diff --git a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c
index 07907b6ecb63..93293d04b303 100644
--- a/arch/arm26/kernel/armksyms.c
+++ b/arch/arm26/kernel/armksyms.c
@@ -202,14 +202,6 @@ EXPORT_SYMBOL(_find_next_zero_bit_le);
EXPORT_SYMBOL(elf_platform);
EXPORT_SYMBOL(elf_hwcap);
- /* syscalls */
-EXPORT_SYMBOL(sys_write);
-EXPORT_SYMBOL(sys_read);
-EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_open);
-EXPORT_SYMBOL(sys_exit);
-EXPORT_SYMBOL(sys_wait4);
-
#ifdef CONFIG_PREEMPT
EXPORT_SYMBOL(kernel_flag);
#endif
diff --git a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c
index e7eb070f794f..466ddb54b44f 100644
--- a/arch/arm26/kernel/setup.c
+++ b/arch/arm26/kernel/setup.c
@@ -143,7 +143,7 @@ static void __init setup_processor(void)
dump_cpu_info();
- sprintf(system_utsname.machine, "%s", list->arch_name);
+ sprintf(init_utsname()->machine, "%s", list->arch_name);
sprintf(elf_platform, "%s", list->elf_name);
elf_hwcap = list->elf_hwcap;
diff --git a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c
index 85457897b8a9..dc05aba58baf 100644
--- a/arch/arm26/kernel/sys_arm.c
+++ b/arch/arm26/kernel/sys_arm.c
@@ -283,7 +283,7 @@ out:
}
/* FIXME - see if this is correct for arm26 */
-long execve(const char *filename, char **argv, char **envp)
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
{
struct pt_regs regs;
int ret;
@@ -320,4 +320,4 @@ long execve(const char *filename, char **argv, char **envp)
return ret;
}
-EXPORT_SYMBOL(execve);
+EXPORT_SYMBOL(kernel_execve);
diff --git a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c
index db63d75d0715..1206469b2b86 100644
--- a/arch/arm26/kernel/time.c
+++ b/arch/arm26/kernel/time.c
@@ -33,8 +33,6 @@
#include <asm/irq.h>
#include <asm/ioc.h>
-extern unsigned long wall_jiffies;
-
/* this needs a better home */
DEFINE_SPINLOCK(rtc_lock);
@@ -136,16 +134,11 @@ void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long seq;
- unsigned long usec, sec, lost;
+ unsigned long usec, sec;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = gettimeoffset();
-
- lost = jiffies - wall_jiffies;
- if (lost)
- usec += lost * USECS_PER_JIFFY;
-
sec = xtime.tv_sec;
usec += xtime.tv_nsec / 1000;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
@@ -174,8 +167,7 @@ int do_settimeofday(struct timespec *tv)
* wall time. Discover what correction gettimeofday() would have
* done, and then undo it!
*/
- tv->tv_nsec -= 1000 * (gettimeoffset() +
- (jiffies - wall_jiffies) * USECS_PER_JIFFY);
+ tv->tv_nsec -= 1000 * gettimeoffset();
while (tv->tv_nsec < 0) {
tv->tv_nsec += NSEC_PER_SEC;
@@ -194,7 +186,7 @@ EXPORT_SYMBOL(do_settimeofday);
static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
diff --git a/arch/arm26/lib/ecard.S b/arch/arm26/lib/ecard.S
index b4633150f01c..658bc4529c9d 100644
--- a/arch/arm26/lib/ecard.S
+++ b/arch/arm26/lib/ecard.S
@@ -7,7 +7,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/config.h> /* for CONFIG_CPU_nn */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/hardware.h>
diff --git a/arch/arm26/lib/io-acorn.S b/arch/arm26/lib/io-acorn.S
index f6c3e30b1b4f..5f62ade5be39 100644
--- a/arch/arm26/lib/io-acorn.S
+++ b/arch/arm26/lib/io-acorn.S
@@ -7,7 +7,6 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
-#include <linux/config.h> /* for CONFIG_CPU_nn */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/hardware.h>
diff --git a/arch/arm26/mm/fault.c b/arch/arm26/mm/fault.c
index 761938b56679..a1f6d8a9cc32 100644
--- a/arch/arm26/mm/fault.c
+++ b/arch/arm26/mm/fault.c
@@ -155,7 +155,7 @@ __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr,
*/
good_area:
if (READ_FAULT(fsr)) /* read? */
- mask = VM_READ|VM_EXEC;
+ mask = VM_READ|VM_EXEC|VM_WRITE;
else
mask = VM_WRITE;
@@ -185,7 +185,7 @@ survive:
}
fault = -3; /* out of memory */
- if (tsk->pid != 1)
+ if (!is_init(tsk))
goto out;
/*
diff --git a/arch/avr32/boards/atstk1000/atstk1002.c b/arch/avr32/boards/atstk1000/atstk1002.c
index 49164e9aadd6..cced73c58115 100644
--- a/arch/avr32/boards/atstk1000/atstk1002.c
+++ b/arch/avr32/boards/atstk1000/atstk1002.c
@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <asm/arch/board.h>
+#include <asm/arch/init.h>
struct eth_platform_data __initdata eth0_data = {
.valid = 1,
@@ -20,13 +21,22 @@ struct eth_platform_data __initdata eth0_data = {
extern struct lcdc_platform_data atstk1000_fb0_data;
+void __init setup_board(void)
+{
+ at32_map_usart(1, 0); /* /dev/ttyS0 */
+ at32_map_usart(2, 1); /* /dev/ttyS1 */
+ at32_map_usart(3, 2); /* /dev/ttyS2 */
+
+ at32_setup_serial_console(0);
+}
+
static int __init atstk1002_init(void)
{
at32_add_system_devices();
- at32_add_device_usart(1); /* /dev/ttyS0 */
- at32_add_device_usart(2); /* /dev/ttyS1 */
- at32_add_device_usart(3); /* /dev/ttyS2 */
+ at32_add_device_usart(0);
+ at32_add_device_usart(1);
+ at32_add_device_usart(2);
at32_add_device_eth(0, &eth0_data);
at32_add_device_spi(0);
diff --git a/arch/avr32/configs/atstk1002_defconfig b/arch/avr32/configs/atstk1002_defconfig
index 1d22255009fd..6c2c5e00dfc7 100644
--- a/arch/avr32/configs/atstk1002_defconfig
+++ b/arch/avr32/configs/atstk1002_defconfig
@@ -385,9 +385,9 @@ CONFIG_PPP_DEFLATE=m
#
# Non-8250 serial port support
#
-CONFIG_SERIAL_AT91=y
-CONFIG_SERIAL_AT91_CONSOLE=y
-# CONFIG_SERIAL_AT91_TTYAT is not set
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c
index 5d68f3c6990b..ea2d1ffee478 100644
--- a/arch/avr32/kernel/setup.c
+++ b/arch/avr32/kernel/setup.c
@@ -292,6 +292,7 @@ void __init setup_arch (char **cmdline_p)
setup_processor();
setup_platform();
+ setup_board();
cpu_clk = clk_get(NULL, "cpu");
if (IS_ERR(cpu_clk)) {
diff --git a/arch/avr32/kernel/sys_avr32.c b/arch/avr32/kernel/sys_avr32.c
index 6ec5693da448..8deb6003ee62 100644
--- a/arch/avr32/kernel/sys_avr32.c
+++ b/arch/avr32/kernel/sys_avr32.c
@@ -49,3 +49,17 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
fput(file);
return error;
}
+
+int kernel_execve(const char *file, char **argv, char **envp)
+{
+ register long scno asm("r8") = __NR_execve;
+ register long sc1 asm("r12") = (long)file;
+ register long sc2 asm("r11") = (long)argv;
+ register long sc3 asm("r10") = (long)envp;
+
+ asm volatile("scall"
+ : "=r"(sc1)
+ : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3)
+ : "cc", "memory");
+ return sc1;
+}
diff --git a/arch/avr32/kernel/time.c b/arch/avr32/kernel/time.c
index b0e6b5855a38..5a247ba71a72 100644
--- a/arch/avr32/kernel/time.c
+++ b/arch/avr32/kernel/time.c
@@ -124,15 +124,15 @@ unsigned long long sched_clock(void)
*
* In UP mode, it is invoked from the (global) timer_interrupt.
*/
-static void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void local_timer_interrupt(int irq, void *dev_id)
{
if (current->pid)
- profile_tick(CPU_PROFILING, regs);
- update_process_times(user_mode(regs));
+ profile_tick(CPU_PROFILING);
+ update_process_times(user_mode(get_irq_regs()));
}
static irqreturn_t
-timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+timer_interrupt(int irq, void *dev_id)
{
unsigned int count;
@@ -148,7 +148,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* Call the generic timer interrupt handler
*/
write_seqlock(&xtime_lock);
- do_timer(regs);
+ do_timer(1);
write_sequnlock(&xtime_lock);
/*
@@ -157,7 +157,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*
* SMP is not supported yet.
*/
- local_timer_interrupt(irq, dev_id, regs);
+ local_timer_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
diff --git a/arch/avr32/mach-at32ap/at32ap.c b/arch/avr32/mach-at32ap/at32ap.c
index f7cedf5aabea..90f207e8e96d 100644
--- a/arch/avr32/mach-at32ap/at32ap.c
+++ b/arch/avr32/mach-at32ap/at32ap.c
@@ -48,9 +48,6 @@ void __init setup_platform(void)
at32_sm_init();
at32_clock_init();
at32_portmux_init();
-
- /* FIXME: This doesn't belong here */
- at32_setup_serial_console(1);
}
static int __init pdc_probe(struct platform_device *pdev)
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c
index 37982b60398e..7ff6ad8bab5f 100644
--- a/arch/avr32/mach-at32ap/at32ap7000.c
+++ b/arch/avr32/mach-at32ap/at32ap7000.c
@@ -523,33 +523,49 @@ void __init at32_add_system_devices(void)
* USART
* -------------------------------------------------------------------- */
-static struct resource usart0_resource[] = {
+static struct atmel_uart_data atmel_usart0_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart0_resource[] = {
PBMEM(0xffe00c00),
IRQ(7),
};
-DEFINE_DEV(usart, 0);
-DEV_CLK(usart, usart0, pba, 4);
+DEFINE_DEV_DATA(atmel_usart, 0);
+DEV_CLK(usart, atmel_usart0, pba, 4);
-static struct resource usart1_resource[] = {
+static struct atmel_uart_data atmel_usart1_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart1_resource[] = {
PBMEM(0xffe01000),
IRQ(7),
};
-DEFINE_DEV(usart, 1);
-DEV_CLK(usart, usart1, pba, 4);
+DEFINE_DEV_DATA(atmel_usart, 1);
+DEV_CLK(usart, atmel_usart1, pba, 4);
-static struct resource usart2_resource[] = {
+static struct atmel_uart_data atmel_usart2_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart2_resource[] = {
PBMEM(0xffe01400),
IRQ(8),
};
-DEFINE_DEV(usart, 2);
-DEV_CLK(usart, usart2, pba, 5);
+DEFINE_DEV_DATA(atmel_usart, 2);
+DEV_CLK(usart, atmel_usart2, pba, 5);
-static struct resource usart3_resource[] = {
+static struct atmel_uart_data atmel_usart3_data = {
+ .use_dma_tx = 1,
+ .use_dma_rx = 1,
+};
+static struct resource atmel_usart3_resource[] = {
PBMEM(0xffe01800),
IRQ(9),
};
-DEFINE_DEV(usart, 3);
-DEV_CLK(usart, usart3, pba, 6);
+DEFINE_DEV_DATA(atmel_usart, 3);
+DEV_CLK(usart, atmel_usart3, pba, 6);
static inline void configure_usart0_pins(void)
{
@@ -575,51 +591,54 @@ static inline void configure_usart3_pins(void)
portmux_set_func(PIOB, 17, FUNC_B); /* TXD */
}
-static struct platform_device *setup_usart(unsigned int id)
+static struct platform_device *at32_usarts[4];
+
+void __init at32_map_usart(unsigned int hw_id, unsigned int line)
{
struct platform_device *pdev;
- switch (id) {
+ switch (hw_id) {
case 0:
- pdev = &usart0_device;
+ pdev = &atmel_usart0_device;
configure_usart0_pins();
break;
case 1:
- pdev = &usart1_device;
+ pdev = &atmel_usart1_device;
configure_usart1_pins();
break;
case 2:
- pdev = &usart2_device;
+ pdev = &atmel_usart2_device;
configure_usart2_pins();
break;
case 3:
- pdev = &usart3_device;
+ pdev = &atmel_usart3_device;
configure_usart3_pins();
break;
default:
- pdev = NULL;
- break;
+ return;
}
- return pdev;
+ if (PXSEG(pdev->resource[0].start) == P4SEG) {
+ /* Addresses in the P4 segment are permanently mapped 1:1 */
+ struct atmel_uart_data *data = pdev->dev.platform_data;
+ data->regs = (void __iomem *)pdev->resource[0].start;
+ }
+
+ pdev->id = line;
+ at32_usarts[line] = pdev;
}
struct platform_device *__init at32_add_device_usart(unsigned int id)
{
- struct platform_device *pdev;
-
- pdev = setup_usart(id);
- if (pdev)
- platform_device_register(pdev);
-
- return pdev;
+ platform_device_register(at32_usarts[id]);
+ return at32_usarts[id];
}
-struct platform_device *at91_default_console_device;
+struct platform_device *atmel_default_console_device;
void __init at32_setup_serial_console(unsigned int usart_id)
{
- at91_default_console_device = setup_usart(usart_id);
+ atmel_default_console_device = at32_usarts[usart_id];
}
/* --------------------------------------------------------------------
@@ -813,10 +832,10 @@ struct clk *at32_clock_list[] = {
&pio1_mck,
&pio2_mck,
&pio3_mck,
- &usart0_usart,
- &usart1_usart,
- &usart2_usart,
- &usart3_usart,
+ &atmel_usart0_usart,
+ &atmel_usart1_usart,
+ &atmel_usart2_usart,
+ &atmel_usart3_usart,
&macb0_hclk,
&macb0_pclk,
&spi0_mck,
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
index 7da9c5f7a0eb..4dff1f988900 100644
--- a/arch/avr32/mach-at32ap/extint.c
+++ b/arch/avr32/mach-at32ap/extint.c
@@ -102,8 +102,7 @@ struct irq_chip eim_chip = {
.set_type = eim_set_irq_type,
};
-static void demux_eim_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+static void demux_eim_irq(unsigned int irq, struct irq_desc *desc)
{
struct at32_sm *sm = desc->handler_data;
struct irq_desc *ext_desc;
@@ -121,7 +120,7 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc,
ext_irq = i + sm->eim_first_irq;
ext_desc = irq_desc + ext_irq;
- ext_desc->handle_irq(ext_irq, ext_desc, regs);
+ ext_desc->handle_irq(ext_irq, ext_desc);
}
spin_unlock(&sm->lock);
diff --git a/arch/avr32/mach-at32ap/intc.c b/arch/avr32/mach-at32ap/intc.c
index 74f8c9f2f03d..eb87a18ad7b2 100644
--- a/arch/avr32/mach-at32ap/intc.c
+++ b/arch/avr32/mach-at32ap/intc.c
@@ -52,16 +52,19 @@ static struct intc intc0 = {
asmlinkage void do_IRQ(int level, struct pt_regs *regs)
{
struct irq_desc *desc;
+ struct pt_regs *old_regs;
unsigned int irq;
unsigned long status_reg;
local_irq_disable();
+ old_regs = set_irq_regs(regs);
+
irq_enter();
irq = intc_readl(&intc0, INTCAUSE0 - 4 * level);
desc = irq_desc + irq;
- desc->handle_irq(irq, desc, regs);
+ desc->handle_irq(irq, desc);
/*
* Clear all interrupt level masks so that we may handle
@@ -75,6 +78,8 @@ asmlinkage void do_IRQ(int level, struct pt_regs *regs)
sysreg_write(SR, status_reg);
irq_exit();
+
+ set_irq_regs(old_regs);
}
void __init init_IRQ(void)
diff --git a/arch/avr32/mm/ioremap.c b/arch/avr32/mm/ioremap.c
index 536021877df6..8cfec65e37f7 100644
--- a/arch/avr32/mm/ioremap.c
+++ b/arch/avr32/mm/ioremap.c
@@ -7,119 +7,11 @@
*/
#include <linux/vmalloc.h>
#include <linux/module.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/pgtable.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
#include <asm/addrspace.h>
-static inline int remap_area_pte(pte_t *pte, unsigned long address,
- unsigned long end, unsigned long phys_addr,
- pgprot_t prot)
-{
- unsigned long pfn;
-
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- WARN_ON(!pte_none(*pte));
-
- set_pte(pte, pfn_pte(pfn, prot));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-
- return 0;
-}
-
-static inline int remap_area_pmd(pmd_t *pmd, unsigned long address,
- unsigned long end, unsigned long phys_addr,
- pgprot_t prot)
-{
- unsigned long next;
-
- phys_addr -= address;
-
- do {
- pte_t *pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
-
- next = (address + PMD_SIZE) & PMD_MASK;
- if (remap_area_pte(pte, address, next,
- address + phys_addr, prot))
- return -ENOMEM;
-
- address = next;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-static int remap_area_pud(pud_t *pud, unsigned long address,
- unsigned long end, unsigned long phys_addr,
- pgprot_t prot)
-{
- unsigned long next;
-
- phys_addr -= address;
-
- do {
- pmd_t *pmd = pmd_alloc(&init_mm, pud, address);
- if (!pmd)
- return -ENOMEM;
- next = (address + PUD_SIZE) & PUD_MASK;
- if (remap_area_pmd(pmd, address, next,
- phys_addr + address, prot))
- return -ENOMEM;
-
- address = next;
- pud++;
- } while (address && address < end);
-
- return 0;
-}
-
-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
- size_t size, pgprot_t prot)
-{
- unsigned long end = address + size;
- unsigned long next;
- pgd_t *pgd;
- int err = 0;
-
- phys_addr -= address;
-
- pgd = pgd_offset_k(address);
- flush_cache_all();
- BUG_ON(address >= end);
-
- spin_lock(&init_mm.page_table_lock);
- do {
- pud_t *pud = pud_alloc(&init_mm, pgd, address);
-
- err = -ENOMEM;
- if (!pud)
- break;
-
- next = (address + PGDIR_SIZE) & PGDIR_MASK;
- if (next < address || next > end)
- next = end;
- err = remap_area_pud(pud, address, next,
- phys_addr + address, prot);
- if (err)
- break;
-
- address = next;
- pgd++;
- } while (address && (address < end));
-
- spin_unlock(&init_mm.page_table_lock);
- flush_tlb_all();
- return err;
-}
-
/*
* Re-map an arbitrary physical address space into the kernel virtual
* address space. Needed when the kernel wants to access physical
@@ -128,7 +20,7 @@ static int remap_area_pages(unsigned long address, unsigned long phys_addr,
void __iomem *__ioremap(unsigned long phys_addr, size_t size,
unsigned long flags)
{
- void *addr;
+ unsigned long addr;
struct vm_struct *area;
unsigned long offset, last_addr;
pgprot_t prot;
@@ -159,7 +51,7 @@ void __iomem *__ioremap(unsigned long phys_addr, size_t size,
phys_addr &= PAGE_MASK;
size = PAGE_ALIGN(last_addr + 1) - phys_addr;
- prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY
+ prot = __pgprot(_PAGE_PRESENT | _PAGE_GLOBAL | _PAGE_RW | _PAGE_DIRTY
| _PAGE_ACCESSED | _PAGE_TYPE_SMALL | flags);
/*
@@ -169,9 +61,9 @@ void __iomem *__ioremap(unsigned long phys_addr, size_t size,
if (!area)
return NULL;
area->phys_addr = phys_addr;
- addr = area->addr;
- if (remap_area_pages((unsigned long)addr, phys_addr, size, prot)) {
- vunmap(addr);
+ addr = (unsigned long )area->addr;
+ if (ioremap_page_range(addr, addr + size, phys_addr, prot)) {
+ vunmap((void *)addr);
return NULL;
}
diff --git a/arch/avr32/mm/tlb.c b/arch/avr32/mm/tlb.c
index 5d0523bbe298..7b073052203d 100644
--- a/arch/avr32/mm/tlb.c
+++ b/arch/avr32/mm/tlb.c
@@ -15,7 +15,8 @@
void show_dtlb_entry(unsigned int index)
{
- unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save, flags;
+ unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
+ unsigned long flags;
local_irq_save(flags);
mmucr_save = sysreg_read(MMUCR);
@@ -305,7 +306,8 @@ static void tlb_stop(struct seq_file *tlb, void *v)
static int tlb_show(struct seq_file *tlb, void *v)
{
- unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save, flags;
+ unsigned int tlbehi, tlbehi_save, tlbelo, mmucr, mmucr_save;
+ unsigned long flags;
unsigned long *index = v;
if (*index == 0)
diff --git a/arch/cris/arch-v10/drivers/Kconfig b/arch/cris/arch-v10/drivers/Kconfig
index 8b50e8402954..734d5f3a5304 100644
--- a/arch/cris/arch-v10/drivers/Kconfig
+++ b/arch/cris/arch-v10/drivers/Kconfig
@@ -550,7 +550,7 @@ config ETRAX_IDE
select BLK_DEV_IDEDMA
help
Enable this to get support for ATA/IDE.
- You can't use paralell ports or SCSI ports
+ You can't use parallel ports or SCSI ports
at the same time.
@@ -744,7 +744,7 @@ config ETRAX_PA_CHANGEABLE_BITS
default "FF"
help
This is a bitmask with information of what bits in PA that a user
- can change change the value on using ioctl's.
+ can change the value on using ioctl's.
Bit set = changeable.
You probably want 00 here.
diff --git a/arch/cris/arch-v10/kernel/time.c b/arch/cris/arch-v10/kernel/time.c
index 9c22b76e129a..ebacf1457d91 100644
--- a/arch/cris/arch-v10/kernel/time.c
+++ b/arch/cris/arch-v10/kernel/time.c
@@ -227,7 +227,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* call the real timer interrupt handler */
- do_timer(regs);
+ do_timer(1);
cris_do_profile(regs); /* Save profiling information */
diff --git a/arch/cris/arch-v32/Kconfig b/arch/cris/arch-v32/Kconfig
index 22f0ddc04c50..4f79d8ed3e1c 100644
--- a/arch/cris/arch-v32/Kconfig
+++ b/arch/cris/arch-v32/Kconfig
@@ -162,7 +162,7 @@ config ETRAX_SDRAM_GRP1_CONFIG
depends on ETRAX_ARCH_V32
default "0"
help
- SDRAM configuration for group 1. The defult value is 0
+ SDRAM configuration for group 1. The default value is 0
because group 1 is not used in the default configuration,
described in the help for SDRAM_GRP0_CONFIG.
diff --git a/arch/cris/arch-v32/kernel/smp.c b/arch/cris/arch-v32/kernel/smp.c
index 464ecaec3bc0..2d0023f2d49b 100644
--- a/arch/cris/arch-v32/kernel/smp.c
+++ b/arch/cris/arch-v32/kernel/smp.c
@@ -28,6 +28,7 @@ spinlock_t cris_atomic_locks[] = { [0 ... LOCK_COUNT - 1] = SPIN_LOCK_UNLOCKED};
/* CPU masks */
cpumask_t cpu_online_map = CPU_MASK_NONE;
+EXPORT_SYMBOL(cpu_online_map);
cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
EXPORT_SYMBOL(phys_cpu_present_map);
diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c
index 50f3f93293d6..be0a01657d4f 100644
--- a/arch/cris/arch-v32/kernel/time.c
+++ b/arch/cris/arch-v32/kernel/time.c
@@ -219,7 +219,7 @@ timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
/* call the real timer interrupt handler */
- do_timer(regs);
+ do_timer(1);
/*
* If we have an externally synchronized Linux clock, then update
diff --git a/arch/cris/kernel/setup.c b/arch/cris/kernel/setup.c
index 7af3d5d43e43..ca8b45a0fe2e 100644
--- a/arch/cris/kernel/setup.c
+++ b/arch/cris/kernel/setup.c
@@ -160,7 +160,7 @@ setup_arch(char **cmdline_p)
show_etrax_copyright();
/* Setup utsname */
- strcpy(system_utsname.machine, cris_machine_name);
+ strcpy(init_utsname()->machine, cris_machine_name);
}
static void *c_start(struct seq_file *m, loff_t *pos)
diff --git a/arch/cris/kernel/time.c b/arch/cris/kernel/time.c
index 66ba8898db07..0f9213cbd48e 100644
--- a/arch/cris/kernel/time.c
+++ b/arch/cris/kernel/time.c
@@ -37,7 +37,6 @@ int have_rtc; /* used to remember if we have an RTC or not */;
#define TICK_SIZE tick
-extern unsigned long wall_jiffies;
extern unsigned long loops_per_jiffy; /* init/main.c */
unsigned long loops_per_usec;
@@ -58,11 +57,6 @@ void do_gettimeofday(struct timeval *tv)
local_irq_save(flags);
local_irq_disable();
usec = do_gettimeoffset();
- {
- unsigned long lost = jiffies - wall_jiffies;
- if (lost)
- usec += lost * (1000000 / HZ);
- }
/*
* If time_adjust is negative then NTP is slowing the clock
@@ -103,7 +97,6 @@ int do_settimeofday(struct timespec *tv)
* made, and then undo it!
*/
nsec -= do_gettimeoffset() * NSEC_PER_USEC;
- nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
diff --git a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c
index 1780df3ed9e5..8b0b9348b574 100644
--- a/arch/cris/mm/ioremap.c
+++ b/arch/cris/mm/ioremap.c
@@ -10,93 +10,10 @@
*/
#include <linux/vmalloc.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
#include <asm/arch/memmap.h>
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
- set_pte(pte, mk_pte_phys(phys_addr, prot));
- address += PAGE_SIZE;
- phys_addr += PAGE_SIZE;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, pgprot_t prot)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, prot);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, pgprot_t prot)
-{
- int error;
- pgd_t * dir;
- unsigned long end = address + size;
-
- phys_addr -= address;
- dir = pgd_offset(&init_mm, address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pud_t *pud;
- pmd_t *pmd;
-
- error = -ENOMEM;
- pud = pud_alloc(&init_mm, dir, address);
- if (!pud)
- break;
- pmd = pmd_alloc(&init_mm, pud, address);
-
- if (!pmd)
- break;
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, prot))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return error;
-}
-
/*
* Generic mapping function (not visible outside):
*/
@@ -135,7 +52,8 @@ void __iomem * __ioremap_prot(unsigned long phys_addr, unsigned long size, pgpro
if (!area)
return NULL;
addr = (void __iomem *)area->addr;
- if (remap_area_pages((unsigned long) addr, phys_addr, size, prot)) {
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, prot)) {
vfree((void __force *)addr);
return NULL;
}
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index f7b171b92ea2..cf1c446e003a 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -86,6 +86,14 @@ config HIGHPTE
with a lot of RAM, this can be wasteful of precious low memory.
Setting this option will put user-space page tables in high memory.
+config LARGE_ALLOCS
+ bool "Allow allocating large blocks (> 1MB) of memory"
+ help
+ Allow the slab memory allocator to keep chains for very large memory
+ sizes - up to 32MB. You may need this if your system has a lot of
+ RAM, and you need to able to allocate very large contiguous chunks.
+ If unsure, say N.
+
source "mm/Kconfig"
choice
diff --git a/arch/frv/kernel/Makefile b/arch/frv/kernel/Makefile
index 32db3499c461..e8f73ed28b52 100644
--- a/arch/frv/kernel/Makefile
+++ b/arch/frv/kernel/Makefile
@@ -8,7 +8,7 @@ heads-$(CONFIG_MMU) := head-mmu-fr451.o
extra-y:= head.o init_task.o vmlinux.lds
obj-y := $(heads-y) entry.o entry-table.o break.o switch_to.o kernel_thread.o \
- process.o traps.o ptrace.o signal.o dma.o \
+ kernel_execve.o process.o traps.o ptrace.o signal.o dma.o \
sys_frv.o time.o semaphore.o setup.o frv_ksyms.o \
debug-stub.o irq.o sleep.o uaccess.o
diff --git a/arch/frv/kernel/dma.c b/arch/frv/kernel/dma.c
index f5de6cf7df4e..156184e17e57 100644
--- a/arch/frv/kernel/dma.c
+++ b/arch/frv/kernel/dma.c
@@ -121,15 +121,14 @@ unsigned long frv_dma_inprogress;
/*
* DMA irq handler - determine channel involved, grab status and call real handler
*/
-static irqreturn_t dma_irq_handler(int irq, void *_channel, struct pt_regs *regs)
+static irqreturn_t dma_irq_handler(int irq, void *_channel)
{
struct frv_dma_channel *channel = _channel;
frv_clear_dma_inprogress(channel - frv_dma_channels);
return channel->handler(channel - frv_dma_channels,
__get_DMAC(channel->ioaddr, CSTR),
- channel->data,
- regs);
+ channel->data);
} /* end dma_irq_handler() */
diff --git a/arch/frv/kernel/irq-mb93091.c b/arch/frv/kernel/irq-mb93091.c
index 369bc0a7443d..ad753c1e9b8f 100644
--- a/arch/frv/kernel/irq-mb93091.c
+++ b/arch/frv/kernel/irq-mb93091.c
@@ -80,7 +80,7 @@ static struct irq_chip frv_fpga_pic = {
/*
* FPGA PIC interrupt handler
*/
-static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs)
+static irqreturn_t fpga_interrupt(int irq, void *_mask)
{
uint16_t imr, mask = (unsigned long) _mask;
@@ -95,7 +95,7 @@ static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs)
irq = 31 - irq;
mask &= ~(1 << irq);
- generic_handle_irq(IRQ_BASE_FPGA + irq, regs);
+ generic_handle_irq(IRQ_BASE_FPGA + irq);
}
return IRQ_HANDLED;
diff --git a/arch/frv/kernel/irq-mb93093.c b/arch/frv/kernel/irq-mb93093.c
index a43a22158956..e0983f6926ed 100644
--- a/arch/frv/kernel/irq-mb93093.c
+++ b/arch/frv/kernel/irq-mb93093.c
@@ -79,7 +79,7 @@ static struct irq_chip frv_fpga_pic = {
/*
* FPGA PIC interrupt handler
*/
-static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs)
+static irqreturn_t fpga_interrupt(int irq, void *_mask)
{
uint16_t imr, mask = (unsigned long) _mask;
@@ -94,7 +94,7 @@ static irqreturn_t fpga_interrupt(int irq, void *_mask, struct pt_regs *regs)
irq = 31 - irq;
mask &= ~(1 << irq);
- generic_irq_handle(IRQ_BASE_FPGA + irq, regs);
+ generic_irq_handle(IRQ_BASE_FPGA + irq);
}
return IRQ_HANDLED;
diff --git a/arch/frv/kernel/irq-mb93493.c b/arch/frv/kernel/irq-mb93493.c
index 39c0188a3498..c157eeff871d 100644
--- a/arch/frv/kernel/irq-mb93493.c
+++ b/arch/frv/kernel/irq-mb93493.c
@@ -90,7 +90,7 @@ static struct irq_chip frv_mb93493_pic = {
/*
* MB93493 PIC interrupt handler
*/
-static irqreturn_t mb93493_interrupt(int irq, void *_piqsr, struct pt_regs *regs)
+static irqreturn_t mb93493_interrupt(int irq, void *_piqsr)
{
volatile void *piqsr = _piqsr;
uint32_t iqsr;
@@ -106,7 +106,7 @@ static irqreturn_t mb93493_interrupt(int irq, void *_piqsr, struct pt_regs *regs
irq = 31 - irq;
iqsr &= ~(1 << irq);
- generic_handle_irq(IRQ_BASE_MB93493 + irq, regs);
+ generic_handle_irq(IRQ_BASE_MB93493 + irq);
}
return IRQ_HANDLED;
diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c
index 5ac041c7c0a4..87f360a4ea27 100644
--- a/arch/frv/kernel/irq.c
+++ b/arch/frv/kernel/irq.c
@@ -143,7 +143,7 @@ static struct irq_chip frv_cpu_pic = {
asmlinkage void do_IRQ(void)
{
irq_enter();
- generic_handle_irq(__get_IRL(), __frame);
+ generic_handle_irq(__get_IRL());
irq_exit();
}
diff --git a/arch/frv/kernel/kernel_execve.S b/arch/frv/kernel/kernel_execve.S
new file mode 100644
index 000000000000..9b074a16a052
--- /dev/null
+++ b/arch/frv/kernel/kernel_execve.S
@@ -0,0 +1,33 @@
+/* in-kernel program execution
+ *
+ * Copyright (C) 2006 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/linkage.h>
+#include <asm/unistd.h>
+
+###############################################################################
+#
+# Do a system call from kernel instead of calling sys_execve so we end up with
+# proper pt_regs.
+#
+# int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+#
+# On entry: GR8/GR9/GR10: arguments to function
+# On return: GR8: syscall return.
+#
+###############################################################################
+ .globl kernel_execve
+ .type kernel_execve,@function
+kernel_execve:
+ setlos __NR_execve,gr7
+ tira gr0,#0
+ bralr
+
+ .size kernel_execve,.-kernel_execve
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index d96a57e5f030..a8c61dac1cee 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -31,7 +31,6 @@
#include <linux/serial_reg.h>
#include <asm/setup.h>
-#include <asm/serial.h>
#include <asm/irq.h>
#include <asm/sections.h>
#include <asm/pgalloc.h>
diff --git a/arch/frv/kernel/time.c b/arch/frv/kernel/time.c
index 3d0284bccb94..ed588d73d7d8 100644
--- a/arch/frv/kernel/time.c
+++ b/arch/frv/kernel/time.c
@@ -10,7 +10,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -41,7 +40,7 @@ unsigned long __nongprelbss __dsu_clock_speed_HZ;
unsigned long __nongprelbss __serial_clock_speed_HZ;
unsigned long __delay_loops_MHz;
-static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs *regs);
+static irqreturn_t timer_interrupt(int irq, void *dummy);
static struct irqaction timer_irq = {
timer_interrupt, IRQF_DISABLED, CPU_MASK_NONE, "timer", NULL, NULL
@@ -56,7 +55,7 @@ static inline int set_rtc_mmss(unsigned long nowtime)
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
+static irqreturn_t timer_interrupt(int irq, void *dummy)
{
/* last time the cmos clock got updated */
static long last_rtc_update = 0;
@@ -70,9 +69,9 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
*/
write_seqlock(&xtime_lock);
- do_timer(regs);
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ do_timer(1);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
/*
* If we have an externally synchronized Linux clock, then update
diff --git a/arch/h8300/kernel/ints.c b/arch/h8300/kernel/ints.c
index 1488b6ace18c..1bfc77e391d5 100644
--- a/arch/h8300/kernel/ints.c
+++ b/arch/h8300/kernel/ints.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/h8300/platform/h8300h/ints.c
+ * linux/arch/h8300/kernel/ints.c
*
* Yoshinori Sato <ysato@users.sourceforge.jp>
*
diff --git a/arch/h8300/kernel/sys_h8300.c b/arch/h8300/kernel/sys_h8300.c
index 0f61b7ad69ab..302a2dfe634a 100644
--- a/arch/h8300/kernel/sys_h8300.c
+++ b/arch/h8300/kernel/sys_h8300.c
@@ -25,6 +25,7 @@
#include <asm/cachectl.h>
#include <asm/traps.h>
#include <asm/ipc.h>
+#include <asm/unistd.h>
/*
* sys_pipe() is the normal C calling standard for creating
@@ -280,3 +281,26 @@ asmlinkage void syscall_print(void *dummy,...)
((regs->pc)&0xffffff)-2,regs->orig_er0,regs->er1,regs->er2,regs->er3,regs->er0);
}
#endif
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register long res __asm__("er0");
+ register const char * _a __asm__("er1") = filename;
+ register void *_b __asm__("er2") = argv;
+ register void *_c __asm__("er3") = envp;
+ __asm__ __volatile__ ("mov.l %1,er0\n\t"
+ "trapa #0\n\t"
+ : "=r" (res)
+ : "g" (__NR_execve),
+ "g" (_a),
+ "g" (_b),
+ "g" (_c)
+ : "cc", "memory");
+ return res;
+}
+
+
diff --git a/arch/h8300/kernel/time.c b/arch/h8300/kernel/time.c
index 688a5100604c..8abab3bc2b6f 100644
--- a/arch/h8300/kernel/time.c
+++ b/arch/h8300/kernel/time.c
@@ -16,7 +16,6 @@
* "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -41,7 +40,7 @@ static void timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
/* may need to kick the hardware timer */
platform_timer_eoi();
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index 758044f5e718..8ff1c6fb5aa1 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -401,6 +401,7 @@ config X86_REBOOTFIXUPS
config MICROCODE
tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
+ select FW_LOADER
---help---
If you say Y here and also to "/dev file system support" in the
'File systems' section, you will be able to update the microcode on
@@ -416,6 +417,11 @@ config MICROCODE
To compile this driver as a module, choose M here: the
module will be called microcode.
+config MICROCODE_OLD_INTERFACE
+ bool
+ depends on MICROCODE
+ default y
+
config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support"
help
@@ -598,12 +604,10 @@ config ARCH_SELECT_MEMORY_MODEL
def_bool y
depends on ARCH_SPARSEMEM_ENABLE
-source "mm/Kconfig"
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
-config HAVE_ARCH_EARLY_PFN_TO_NID
- bool
- default y
- depends on NUMA
+source "mm/Kconfig"
config HIGHPTE
bool "Allocate 3rd-level pagetables from highmem"
@@ -678,7 +682,7 @@ config EFI
depends on ACPI
default n
---help---
- This enables the the kernel to boot on EFI platforms using
+ This enables the kernel to boot on EFI platforms using
system configuration information passed to it from the firmware.
This also enables the kernel to use any EFI runtime services that are
available (such as the EFI variable services).
@@ -1138,7 +1142,7 @@ source "arch/i386/oprofile/Kconfig"
config KPROBES
bool "Kprobes (EXPERIMENTAL)"
- depends on EXPERIMENTAL && MODULES
+ depends on KALLSYMS && EXPERIMENTAL && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/i386/Kconfig.cpu b/arch/i386/Kconfig.cpu
index 21c9a4e71104..fc4f2abccf06 100644
--- a/arch/i386/Kconfig.cpu
+++ b/arch/i386/Kconfig.cpu
@@ -7,6 +7,7 @@ choice
config M386
bool "386"
+ depends on !UML
---help---
This is the processor type of your CPU. This information is used for
optimizing purposes. In order to compile a kernel that can run on
@@ -301,7 +302,7 @@ config X86_USE_PPRO_CHECKSUM
config X86_USE_3DNOW
bool
- depends on MCYRIXIII || MK7 || MGEODE_LX
+ depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML
default y
config X86_OOSTORE
diff --git a/arch/i386/Makefile b/arch/i386/Makefile
index 7cc0b189b82b..0677908dfa06 100644
--- a/arch/i386/Makefile
+++ b/arch/i386/Makefile
@@ -42,6 +42,10 @@ cflags-$(CONFIG_REGPARM) += -mregparm=3
# temporary until string.h is fixed
cflags-y += -ffreestanding
+# this works around some issues with generating unwind tables in older gccs
+# newer gccs do it by default
+cflags-y += -maccumulate-outgoing-args
+
# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
# a lot more stack due to the lack of sharing of stacklots:
CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then echo $(call cc-option,-fno-unit-at-a-time); fi ;)
@@ -51,8 +55,8 @@ cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
# is .cfi_signal_frame supported too?
-cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
-AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
+cflags-y += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,)
+AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_signal_frame\n.cfi_endproc,-DCONFIG_AS_CFI_SIGNAL_FRAME=1,)
CFLAGS += $(cflags-y)
diff --git a/arch/i386/boot/video.S b/arch/i386/boot/video.S
index 8c2a6faeeae5..2c5b5cc55f79 100644
--- a/arch/i386/boot/video.S
+++ b/arch/i386/boot/video.S
@@ -11,8 +11,6 @@
*
*/
-#include <linux/config.h> /* for CONFIG_VIDEO_* */
-
/* Enable autodetection of SVGA adapters and modes. */
#undef CONFIG_VIDEO_SVGA
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 1a29bfa26d0c..97aacd6bd7d8 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-git5
-# Tue Sep 26 09:30:47 2006
+# Linux kernel version: 2.6.19-rc2-git4
+# Sat Oct 21 03:38:56 2006
#
CONFIG_X86_32=y
CONFIG_GENERIC_TIME=y
@@ -31,9 +31,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -41,9 +43,10 @@ CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
CONFIG_UID16=y
-CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -76,6 +79,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -163,6 +167,7 @@ CONFIG_VM86=y
# CONFIG_I8K is not set
# CONFIG_X86_REBOOTFIXUPS is not set
CONFIG_MICROCODE=y
+CONFIG_MICROCODE_OLD_INTERFACE=y
CONFIG_X86_MSR=y
CONFIG_X86_CPUID=y
@@ -177,6 +182,7 @@ CONFIG_HIGHMEM4G=y
# CONFIG_HIGHMEM64G is not set
CONFIG_PAGE_OFFSET=0xC0000000
CONFIG_HIGHMEM=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -210,6 +216,7 @@ CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_PM=y
CONFIG_PM_LEGACY=y
# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SYSFS_DEPRECATED=y
#
# ACPI (Advanced Configuration and Power Interface) Support
@@ -292,7 +299,9 @@ CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
# CONFIG_PCIEPORTBUS is not set
CONFIG_PCI_MSI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
+# CONFIG_HT_IRQ is not set
CONFIG_ISA_DMA_API=y
# CONFIG_ISA is not set
# CONFIG_MCA is not set
@@ -352,6 +361,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
+# CONFIG_INET_XFRM_MODE_BEET is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -368,9 +378,10 @@ CONFIG_IPV6=y
# CONFIG_INET6_TUNNEL is not set
CONFIG_INET6_XFRM_MODE_TRANSPORT=y
CONFIG_INET6_XFRM_MODE_TUNNEL=y
+# CONFIG_INET6_XFRM_MODE_BEET is not set
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_SUBTREES is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -472,6 +483,13 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_IBM_ASM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -517,6 +535,7 @@ CONFIG_BLK_DEV_AMD74XX=y
# CONFIG_BLK_DEV_CS5535 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_IT821X is not set
@@ -613,6 +632,7 @@ CONFIG_AIC79XX_DEBUG_MASK=0
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
@@ -656,7 +676,6 @@ CONFIG_SATA_INTEL_COMBINED=y
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_JMICRON is not set
-# CONFIG_PATA_LEGACY is not set
# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_OLDPIIX is not set
@@ -665,7 +684,6 @@ CONFIG_SATA_INTEL_COMBINED=y
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC_OLD is not set
-# CONFIG_PATA_QDI is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RZ1000 is not set
# CONFIG_PATA_SC1200 is not set
@@ -682,6 +700,7 @@ CONFIG_SATA_INTEL_COMBINED=y
CONFIG_MD=y
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
# CONFIG_DM_CRYPT is not set
# CONFIG_DM_SNAPSHOT is not set
# CONFIG_DM_MIRROR is not set
@@ -872,6 +891,7 @@ CONFIG_NET_POLL_CONTROLLER=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -894,6 +914,7 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
@@ -1010,6 +1031,7 @@ CONFIG_HANGCHECK_TIMER=y
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -1018,15 +1040,9 @@ CONFIG_HANGCHECK_TIMER=y
# CONFIG_HWMON_VID is not set
#
-# Misc devices
-#
-# CONFIG_IBM_ASM is not set
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -1132,6 +1148,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -1185,6 +1202,7 @@ CONFIG_USB_MON=y
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
@@ -1192,12 +1210,13 @@ CONFIG_USB_MON=y
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1267,6 +1286,7 @@ CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
@@ -1279,6 +1299,7 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -1289,6 +1310,7 @@ CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
CONFIG_AUTOFS4_FS=y
# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
#
# CD-ROM/DVD Filesystems
@@ -1313,8 +1335,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
@@ -1427,6 +1451,7 @@ CONFIG_KPROBES=y
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_UNUSED_SYMBOLS=y
CONFIG_DEBUG_KERNEL=y
@@ -1449,11 +1474,14 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
# CONFIG_FRAME_POINTER is not set
CONFIG_UNWIND_INFO=y
CONFIG_STACK_UNWIND=y
# CONFIG_FORCED_INLINING is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
CONFIG_EARLY_PRINTK=y
CONFIG_DEBUG_STACKOVERFLOW=y
# CONFIG_DEBUG_STACK_USAGE is not set
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 1aaea6ab8c46..ab974ff97073 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -62,8 +62,6 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return
#include <mach_mpparse.h>
#endif /* CONFIG_X86_LOCAL_APIC */
-static inline int gsi_irq_sharing(int gsi) { return gsi; }
-
#endif /* X86 */
#define BAD_MADT_ENTRY(entry, end) ( \
@@ -334,7 +332,7 @@ acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
/*
* Parse Interrupt Source Override for the ACPI SCI
*/
-static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
+static void acpi_sci_ioapic_setup(u32 bus_irq, u32 gsi, u16 polarity, u16 trigger)
{
if (trigger == 0) /* compatible SCI trigger is level */
trigger = 3;
@@ -354,13 +352,13 @@ static void acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
* If GSI is < 16, this will update its flags,
* else it will create a new mp_irqs[] entry.
*/
- mp_override_legacy_irq(gsi, polarity, trigger, gsi);
+ mp_override_legacy_irq(bus_irq, polarity, trigger, gsi);
/*
* stash over-ride to indicate we've been here
* and for later update of acpi_fadt
*/
- acpi_sci_override_gsi = gsi;
+ acpi_sci_override_gsi = bus_irq;
return;
}
@@ -378,7 +376,7 @@ acpi_parse_int_src_ovr(acpi_table_entry_header * header,
acpi_table_print_madt_entry(header);
if (intsrc->bus_irq == acpi_fadt.sci_int) {
- acpi_sci_ioapic_setup(intsrc->global_irq,
+ acpi_sci_ioapic_setup(intsrc->bus_irq, intsrc->global_irq,
intsrc->flags.polarity,
intsrc->flags.trigger);
return 0;
@@ -468,12 +466,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
{
-#ifdef CONFIG_X86_IO_APIC
- if (use_pci_vector() && !platform_legacy_irq(gsi))
- *irq = IO_APIC_VECTOR(gsi);
- else
-#endif
- *irq = gsi_irq_sharing(gsi);
+ *irq = gsi;
return 0;
}
@@ -886,7 +879,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
* pretend we got one so we can set the SCI flags.
*/
if (!acpi_sci_override_gsi)
- acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
+ acpi_sci_ioapic_setup(acpi_fadt.sci_int, acpi_fadt.sci_int, 0, 0);
/* Fill in identity legacy mapings where no override */
mp_config_acpi_legacy_irqs();
diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c
index 25db49ef1770..20563e52c622 100644
--- a/arch/i386/kernel/acpi/cstate.c
+++ b/arch/i386/kernel/acpi/cstate.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
+#include <linux/cpu.h>
#include <acpi/processor.h>
#include <asm/acpi.h>
@@ -41,5 +42,124 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
flags->bm_check = 1;
}
}
-
EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
+
+/* The code below handles cstate entry with monitor-mwait pair on Intel*/
+
+struct cstate_entry_s {
+ struct {
+ unsigned int eax;
+ unsigned int ecx;
+ } states[ACPI_PROCESSOR_MAX_POWER];
+};
+static struct cstate_entry_s *cpu_cstate_entry; /* per CPU ptr */
+
+static short mwait_supported[ACPI_PROCESSOR_MAX_POWER];
+
+#define MWAIT_SUBSTATE_MASK (0xf)
+#define MWAIT_SUBSTATE_SIZE (4)
+
+#define CPUID_MWAIT_LEAF (5)
+#define CPUID5_ECX_EXTENSIONS_SUPPORTED (0x1)
+#define CPUID5_ECX_INTERRUPT_BREAK (0x2)
+
+#define MWAIT_ECX_INTERRUPT_BREAK (0x1)
+
+#define NATIVE_CSTATE_BEYOND_HALT (2)
+
+int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+ struct acpi_processor_cx *cx, struct acpi_power_register *reg)
+{
+ struct cstate_entry_s *percpu_entry;
+ struct cpuinfo_x86 *c = cpu_data + cpu;
+
+ cpumask_t saved_mask;
+ int retval;
+ unsigned int eax, ebx, ecx, edx;
+ unsigned int edx_part;
+ unsigned int cstate_type; /* C-state type and not ACPI C-state type */
+ unsigned int num_cstate_subtype;
+
+ if (!cpu_cstate_entry || c->cpuid_level < CPUID_MWAIT_LEAF )
+ return -1;
+
+ if (reg->bit_offset != NATIVE_CSTATE_BEYOND_HALT)
+ return -1;
+
+ percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+ percpu_entry->states[cx->index].eax = 0;
+ percpu_entry->states[cx->index].ecx = 0;
+
+ /* Make sure we are running on right CPU */
+ saved_mask = current->cpus_allowed;
+ retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ if (retval)
+ return -1;
+
+ cpuid(CPUID_MWAIT_LEAF, &eax, &ebx, &ecx, &edx);
+
+ /* Check whether this particular cx_type (in CST) is supported or not */
+ cstate_type = (cx->address >> MWAIT_SUBSTATE_SIZE) + 1;
+ edx_part = edx >> (cstate_type * MWAIT_SUBSTATE_SIZE);
+ num_cstate_subtype = edx_part & MWAIT_SUBSTATE_MASK;
+
+ retval = 0;
+ if (num_cstate_subtype < (cx->address & MWAIT_SUBSTATE_MASK)) {
+ retval = -1;
+ goto out;
+ }
+
+ /* mwait ecx extensions INTERRUPT_BREAK should be supported for C2/C3 */
+ if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) ||
+ !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) {
+ retval = -1;
+ goto out;
+ }
+ percpu_entry->states[cx->index].ecx = MWAIT_ECX_INTERRUPT_BREAK;
+
+ /* Use the hint in CST */
+ percpu_entry->states[cx->index].eax = cx->address;
+
+ if (!mwait_supported[cstate_type]) {
+ mwait_supported[cstate_type] = 1;
+ printk(KERN_DEBUG "Monitor-Mwait will be used to enter C-%d "
+ "state\n", cx->type);
+ }
+
+out:
+ set_cpus_allowed(current, saved_mask);
+ return retval;
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_probe);
+
+void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cx)
+{
+ unsigned int cpu = smp_processor_id();
+ struct cstate_entry_s *percpu_entry;
+
+ percpu_entry = per_cpu_ptr(cpu_cstate_entry, cpu);
+ mwait_idle_with_hints(percpu_entry->states[cx->index].eax,
+ percpu_entry->states[cx->index].ecx);
+}
+EXPORT_SYMBOL_GPL(acpi_processor_ffh_cstate_enter);
+
+static int __init ffh_cstate_init(void)
+{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+ if (c->x86_vendor != X86_VENDOR_INTEL)
+ return -1;
+
+ cpu_cstate_entry = alloc_percpu(struct cstate_entry_s);
+ return 0;
+}
+
+static void __exit ffh_cstate_exit(void)
+{
+ if (cpu_cstate_entry) {
+ free_percpu(cpu_cstate_entry);
+ cpu_cstate_entry = NULL;
+ }
+}
+
+arch_initcall(ffh_cstate_init);
+__exitcall(ffh_cstate_exit);
diff --git a/arch/i386/kernel/alternative.c b/arch/i386/kernel/alternative.c
index 28ab80649764..583c238e17fb 100644
--- a/arch/i386/kernel/alternative.c
+++ b/arch/i386/kernel/alternative.c
@@ -344,6 +344,7 @@ void alternatives_smp_switch(int smp)
void __init alternative_instructions(void)
{
+ unsigned long flags;
if (no_replacement) {
printk(KERN_INFO "(SMP-)alternatives turned off\n");
free_init_pages("SMP alternatives",
@@ -351,6 +352,8 @@ void __init alternative_instructions(void)
(unsigned long)__smp_alt_end);
return;
}
+
+ local_irq_save(flags);
apply_alternatives(__alt_instructions, __alt_instructions_end);
/* switch to patch-once-at-boottime-only mode and free the
@@ -386,4 +389,5 @@ void __init alternative_instructions(void)
alternatives_smp_switch(0);
}
#endif
+ local_irq_restore(flags);
}
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 90faae5c5d30..2fd4b7d927c2 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -1193,11 +1193,11 @@ EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
* value into /proc/profile.
*/
-inline void smp_local_timer_interrupt(struct pt_regs * regs)
+inline void smp_local_timer_interrupt(void)
{
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#ifdef CONFIG_SMP
- update_process_times(user_mode_vm(regs));
+ update_process_times(user_mode_vm(get_irq_regs()));
#endif
/*
@@ -1223,6 +1223,7 @@ inline void smp_local_timer_interrupt(struct pt_regs * regs)
fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
int cpu = smp_processor_id();
/*
@@ -1241,12 +1242,13 @@ fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
* interrupt lock, which is the WrongThing (tm) to do.
*/
irq_enter();
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
irq_exit();
+ set_irq_regs(old_regs);
}
#ifndef CONFIG_SMP
-static void up_apic_timer_interrupt_call(struct pt_regs *regs)
+static void up_apic_timer_interrupt_call(void)
{
int cpu = smp_processor_id();
@@ -1255,11 +1257,11 @@ static void up_apic_timer_interrupt_call(struct pt_regs *regs)
*/
per_cpu(irq_stat, cpu).apic_timer_irqs++;
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
}
#endif
-void smp_send_timer_broadcast_ipi(struct pt_regs *regs)
+void smp_send_timer_broadcast_ipi(void)
{
cpumask_t mask;
@@ -1272,7 +1274,7 @@ void smp_send_timer_broadcast_ipi(struct pt_regs *regs)
* We can directly call the apic timer interrupt handler
* in UP case. Minus all irq related functions
*/
- up_apic_timer_interrupt_call(regs);
+ up_apic_timer_interrupt_call();
#endif
}
}
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index ff9ce4b5eaa8..2af65858d322 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -225,6 +225,7 @@
#include <linux/smp_lock.h>
#include <linux/dmi.h>
#include <linux/suspend.h>
+#include <linux/kthread.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -402,8 +403,6 @@ static int realmode_power_off = 1;
#else
static int realmode_power_off;
#endif
-static int exit_kapmd __read_mostly;
-static int kapmd_running __read_mostly;
#ifdef CONFIG_APM_ALLOW_INTS
static int allow_ints = 1;
#else
@@ -419,6 +418,8 @@ static const struct desc_struct bad_bios_desc = { 0, 0x00409200 };
static const char driver_version[] = "1.16ac"; /* no spaces */
+static struct task_struct *kapmd_task;
+
/*
* APM event names taken from the APM 1.2 specification. These are
* the message codes that the BIOS uses to tell us about events
@@ -539,11 +540,30 @@ static inline void apm_restore_cpus(cpumask_t mask)
* Also, we KNOW that for the non error case of apm_bios_call, there
* is no useful data returned in the low order 8 bits of eax.
*/
-#define APM_DO_CLI \
- if (apm_info.allow_ints) \
- local_irq_enable(); \
- else \
+
+static inline unsigned long __apm_irq_save(void)
+{
+ unsigned long flags;
+ local_save_flags(flags);
+ if (apm_info.allow_ints) {
+ if (irqs_disabled_flags(flags))
+ local_irq_enable();
+ } else
+ local_irq_disable();
+
+ return flags;
+}
+
+#define apm_irq_save(flags) \
+ do { flags = __apm_irq_save(); } while (0)
+
+static inline void apm_irq_restore(unsigned long flags)
+{
+ if (irqs_disabled_flags(flags))
local_irq_disable();
+ else if (irqs_disabled())
+ local_irq_enable();
+}
#ifdef APM_ZERO_SEGS
# define APM_DECL_SEGS \
@@ -595,12 +615,11 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in,
save_desc_40 = gdt[0x40 / 8];
gdt[0x40 / 8] = bad_bios_desc;
- local_save_flags(flags);
- APM_DO_CLI;
+ apm_irq_save(flags);
APM_DO_SAVE_SEGS;
apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi);
APM_DO_RESTORE_SEGS;
- local_irq_restore(flags);
+ apm_irq_restore(flags);
gdt[0x40 / 8] = save_desc_40;
put_cpu();
apm_restore_cpus(cpus);
@@ -639,12 +658,11 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax)
save_desc_40 = gdt[0x40 / 8];
gdt[0x40 / 8] = bad_bios_desc;
- local_save_flags(flags);
- APM_DO_CLI;
+ apm_irq_save(flags);
APM_DO_SAVE_SEGS;
error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax);
APM_DO_RESTORE_SEGS;
- local_irq_restore(flags);
+ apm_irq_restore(flags);
gdt[0x40 / 8] = save_desc_40;
put_cpu();
apm_restore_cpus(cpus);
@@ -1423,7 +1441,7 @@ static void apm_mainloop(void)
set_current_state(TASK_INTERRUPTIBLE);
for (;;) {
schedule_timeout(APM_CHECK_TIMEOUT);
- if (exit_kapmd)
+ if (kthread_should_stop())
break;
/*
* Ok, check all events, check for idle (and mark us sleeping
@@ -1706,12 +1724,6 @@ static int apm(void *unused)
char * power_stat;
char * bat_stat;
- kapmd_running = 1;
-
- daemonize("kapmd");
-
- current->flags |= PF_NOFREEZE;
-
#ifdef CONFIG_SMP
/* 2002/08/01 - WT
* This is to avoid random crashes at boot time during initialization
@@ -1821,7 +1833,6 @@ static int apm(void *unused)
console_blank_hook = NULL;
#endif
}
- kapmd_running = 0;
return 0;
}
@@ -2220,7 +2231,7 @@ static int __init apm_init(void)
{
struct proc_dir_entry *apm_proc;
struct desc_struct *gdt;
- int ret;
+ int err;
dmi_check_system(apm_dmi_table);
@@ -2329,12 +2340,17 @@ static int __init apm_init(void)
if (apm_proc)
apm_proc->owner = THIS_MODULE;
- ret = kernel_thread(apm, NULL, CLONE_KERNEL | SIGCHLD);
- if (ret < 0) {
- printk(KERN_ERR "apm: disabled - Unable to start kernel thread.\n");
+ kapmd_task = kthread_create(apm, NULL, "kapmd");
+ if (IS_ERR(kapmd_task)) {
+ printk(KERN_ERR "apm: disabled - Unable to start kernel "
+ "thread.\n");
+ err = PTR_ERR(kapmd_task);
+ kapmd_task = NULL;
remove_proc_entry("apm", NULL);
- return -ENOMEM;
+ return err;
}
+ kapmd_task->flags |= PF_NOFREEZE;
+ wake_up_process(kapmd_task);
if (num_online_cpus() > 1 && !smp ) {
printk(KERN_NOTICE
@@ -2384,9 +2400,10 @@ static void __exit apm_exit(void)
remove_proc_entry("apm", NULL);
if (power_off)
pm_power_off = NULL;
- exit_kapmd = 1;
- while (kapmd_running)
- schedule();
+ if (kapmd_task) {
+ kthread_stop(kapmd_task);
+ kapmd_task = NULL;
+ }
#ifdef CONFIG_PM_LEGACY
pm_active = 0;
#endif
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 2799baaadf45..d9f3e3c31f05 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -184,7 +184,16 @@ static void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
static int __init x86_fxsr_setup(char * s)
{
+ /* Tell all the other CPU's to not use it... */
disable_x86_fxsr = 1;
+
+ /*
+ * ... and clear the bits early in the boot_cpu_data
+ * so that the bootup process doesn't try to do this
+ * either.
+ */
+ clear_bit(X86_FEATURE_FXSR, boot_cpu_data.x86_capability);
+ clear_bit(X86_FEATURE_XMM, boot_cpu_data.x86_capability);
return 1;
}
__setup("nofxsr", x86_fxsr_setup);
@@ -660,8 +669,7 @@ old_gdt:
*/
atomic_inc(&init_mm.mm_count);
current->active_mm = &init_mm;
- if (current->mm)
- BUG();
+ BUG_ON(current->mm);
enter_lazy_tlb(&init_mm, current);
load_esp0(t, thread);
diff --git a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
index ea19d091fd41..57c880bf0bd6 100644
--- a/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
+++ b/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c
@@ -396,13 +396,13 @@ static int acpi_cpufreq_early_init_acpi(void)
*/
static int bios_with_sw_any_bug;
-static int __init sw_any_bug_found(struct dmi_system_id *d)
+static int sw_any_bug_found(struct dmi_system_id *d)
{
bios_with_sw_any_bug = 1;
return 0;
}
-static struct dmi_system_id __initdata sw_any_bug_dmi_table[] = {
+static struct dmi_system_id sw_any_bug_dmi_table[] = {
{
.callback = sw_any_bug_found,
.ident = "Supermicro Server X6DLP",
@@ -597,7 +597,6 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
.name = "acpi-cpufreq",
.owner = THIS_MODULE,
.attr = acpi_cpufreq_attr,
- .flags = CPUFREQ_STICKY,
};
@@ -608,7 +607,7 @@ acpi_cpufreq_init (void)
acpi_cpufreq_early_init_acpi();
- return cpufreq_register_driver(&acpi_cpufreq_driver);
+ return cpufreq_register_driver(&acpi_cpufreq_driver);
}
diff --git a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
index f5cc9f5c9bab..7233abe5d695 100644
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c
@@ -178,11 +178,17 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
safe_halt();
/* Change frequency on next halt or sleep */
wrmsrl(MSR_VIA_LONGHAUL, longhaul.val);
- ACPI_FLUSH_CPU_CACHE();
- /* Invoke C3 */
- inb(cx_address);
- /* Dummy op - must do something useless after P_LVL3 read */
- t = inl(acpi_fadt.xpm_tmr_blk.address);
+ if (port22_en) {
+ ACPI_FLUSH_CPU_CACHE();
+ /* Invoke C1 */
+ halt();
+ } else {
+ ACPI_FLUSH_CPU_CACHE();
+ /* Invoke C3 */
+ inb(cx_address);
+ /* Dummy op - must do something useless after P_LVL3 read */
+ t = inl(acpi_fadt.xpm_tmr_blk.address);
+ }
/* Disable bus ratio bit */
local_irq_disable();
@@ -567,16 +573,23 @@ static acpi_status longhaul_walk_callback(acpi_handle obj_handle,
static int enable_arbiter_disable(void)
{
struct pci_dev *dev;
+ int reg;
u8 pci_cmd;
/* Find PLE133 host bridge */
+ reg = 0x78;
dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8601_0, NULL);
+ /* Find CLE266 host bridge */
+ if (dev == NULL) {
+ reg = 0x76;
+ dev = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_862X_0, NULL);
+ }
if (dev != NULL) {
/* Enable access to port 0x22 */
- pci_read_config_byte(dev, 0x78, &pci_cmd);
+ pci_read_config_byte(dev, reg, &pci_cmd);
if ( !(pci_cmd & 1<<7) ) {
pci_cmd |= 1<<7;
- pci_write_config_byte(dev, 0x78, pci_cmd);
+ pci_write_config_byte(dev, reg, pci_cmd);
}
return 1;
}
@@ -680,20 +693,25 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
if (longhaul_version == TYPE_POWERSAVER) {
/* Check ACPI support for C3 state */
cx = &pr->power.states[ACPI_STATE_C3];
- if (cx->address == 0 ||
- (cx->latency > 1000 && ignore_latency == 0) )
+ if (cx->address > 0 &&
+ (cx->latency <= 1000 || ignore_latency != 0) ) {
+ goto print_support_type;
+ }
+ }
+ /* Check ACPI support for bus master arbiter disable */
+ if (!pr->flags.bm_control) {
+ if (enable_arbiter_disable()) {
+ port22_en = 1;
+ } else {
goto err_acpi;
-
- } else {
- /* Check ACPI support for bus master arbiter disable */
- if (!pr->flags.bm_control) {
- if (!enable_arbiter_disable()) {
- printk(KERN_ERR PFX "No ACPI support. No VT8601 host bridge. Aborting.\n");
- return -ENODEV;
- } else
- port22_en = 1;
}
}
+print_support_type:
+ if (!port22_en) {
+ printk (KERN_INFO PFX "Using ACPI support.\n");
+ } else {
+ printk (KERN_INFO PFX "Using northbridge support.\n");
+ }
ret = longhaul_get_ranges();
if (ret != 0)
@@ -716,7 +734,7 @@ static int __init longhaul_cpu_init(struct cpufreq_policy *policy)
return 0;
err_acpi:
- printk(KERN_ERR PFX "No ACPI support for CPU frequency changes.\n");
+ printk(KERN_ERR PFX "No ACPI support. No VT8601 or VT8623 northbridge. Aborting.\n");
return -ENODEV;
}
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index 7a9325349e94..e8993baf3d14 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -386,7 +386,7 @@ static int centrino_cpu_early_init_acpi(void)
* than OS intended it to run at. Detect it and handle it cleanly.
*/
static int bios_with_sw_any_bug;
-static int __init sw_any_bug_found(struct dmi_system_id *d)
+static int sw_any_bug_found(struct dmi_system_id *d)
{
bios_with_sw_any_bug = 1;
return 0;
diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c
index 4f43047de406..2d8703b7ce65 100644
--- a/arch/i386/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c
@@ -110,17 +110,15 @@ int therm_throt_process(int curr)
#ifdef CONFIG_SYSFS
/* Add/Remove thermal_throttle interface for CPU device */
-static __cpuinit int thermal_throttle_add_dev(struct sys_device * sys_dev)
+static __cpuinit int thermal_throttle_add_dev(struct sys_device *sys_dev)
{
- sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
- return 0;
+ return sysfs_create_group(&sys_dev->kobj, &thermal_throttle_attr_group);
}
#ifdef CONFIG_HOTPLUG_CPU
-static __cpuinit int thermal_throttle_remove_dev(struct sys_device * sys_dev)
+static __cpuinit void thermal_throttle_remove_dev(struct sys_device *sys_dev)
{
- sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
- return 0;
+ return sysfs_remove_group(&sys_dev->kobj, &thermal_throttle_attr_group);
}
/* Mutex protecting device creation against CPU hotplug */
@@ -133,12 +131,14 @@ static __cpuinit int thermal_throttle_cpu_callback(struct notifier_block *nfb,
{
unsigned int cpu = (unsigned long)hcpu;
struct sys_device *sys_dev;
+ int err;
sys_dev = get_cpu_sysdev(cpu);
mutex_lock(&therm_cpu_lock);
switch (action) {
case CPU_ONLINE:
- thermal_throttle_add_dev(sys_dev);
+ err = thermal_throttle_add_dev(sys_dev);
+ WARN_ON(err);
break;
case CPU_DEAD:
thermal_throttle_remove_dev(sys_dev);
@@ -157,6 +157,7 @@ static struct notifier_block thermal_throttle_cpu_notifier =
static __init int thermal_throttle_init_device(void)
{
unsigned int cpu = 0;
+ int err;
if (!atomic_read(&therm_throt_en))
return 0;
@@ -167,8 +168,10 @@ static __init int thermal_throttle_init_device(void)
mutex_lock(&therm_cpu_lock);
#endif
/* connect live CPUs to sysfs */
- for_each_online_cpu(cpu)
- thermal_throttle_add_dev(get_cpu_sysdev(cpu));
+ for_each_online_cpu(cpu) {
+ err = thermal_throttle_add_dev(get_cpu_sysdev(cpu));
+ WARN_ON(err);
+ }
#ifdef CONFIG_HOTPLUG_CPU
mutex_unlock(&therm_cpu_lock);
#endif
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
index 67d297dc1003..144b43288965 100644
--- a/arch/i386/kernel/crash.c
+++ b/arch/i386/kernel/crash.c
@@ -23,6 +23,7 @@
#include <asm/hw_irq.h>
#include <asm/apic.h>
#include <asm/kdebug.h>
+#include <asm/smp.h>
#include <mach_ipi.h>
@@ -88,7 +89,7 @@ static void crash_save_self(struct pt_regs *regs)
{
int cpu;
- cpu = smp_processor_id();
+ cpu = safe_smp_processor_id();
crash_save_this_cpu(regs, cpu);
}
@@ -133,7 +134,10 @@ static int crash_nmi_callback(struct notifier_block *self,
static void smp_send_nmi_allbutself(void)
{
- send_IPI_allbutself(NMI_VECTOR);
+ cpumask_t mask = cpu_online_map;
+ cpu_clear(safe_smp_processor_id(), mask);
+ if (!cpus_empty(mask))
+ send_IPI_mask(mask, NMI_VECTOR);
}
static struct notifier_block crash_nmi_nb = {
@@ -185,7 +189,7 @@ void machine_crash_shutdown(struct pt_regs *regs)
local_irq_disable();
/* Make a note of crashing cpu. Will be used in NMI callback.*/
- crashing_cpu = smp_processor_id();
+ crashing_cpu = safe_smp_processor_id();
nmi_shootdown_cpus();
lapic_shutdown();
#if defined(CONFIG_X86_IO_APIC)
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index fe158042110b..8b40648d0ef0 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -65,7 +65,7 @@ static unsigned long efi_rt_eflags;
static DEFINE_SPINLOCK(efi_rt_lock);
static pgd_t efi_bak_pg_dir_pointer[2];
-static void efi_call_phys_prelog(void)
+static void efi_call_phys_prelog(void) __acquires(efi_rt_lock)
{
unsigned long cr4;
unsigned long temp;
@@ -109,7 +109,7 @@ static void efi_call_phys_prelog(void)
load_gdt(cpu_gdt_descr);
}
-static void efi_call_phys_epilog(void)
+static void efi_call_phys_epilog(void) __releases(efi_rt_lock)
{
unsigned long cr4;
struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0);
@@ -498,8 +498,7 @@ void __init efi_enter_virtual_mode(void)
check_range_for_systab(md);
}
- if (!efi.systab)
- BUG();
+ BUG_ON(!efi.systab);
status = phys_efi_set_virtual_address_map(
memmap.desc_size * memmap.nr_map,
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index be9d883c62ce..ca31f18d277c 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -317,7 +317,7 @@ is386: movl $2,%ecx # set MP
movl %eax,%gs
lldt %ax
cld # gcc2 wants the direction flag cleared at all times
- pushl %eax # fake return address
+ pushl $0 # fake return address for unwinder
#ifdef CONFIG_SMP
movb ready, %cl
movb $1, ready
diff --git a/arch/i386/kernel/i8237.c b/arch/i386/kernel/i8237.c
index c36d1c006c2f..6f508e8d7c57 100644
--- a/arch/i386/kernel/i8237.c
+++ b/arch/i386/kernel/i8237.c
@@ -2,6 +2,11 @@
* i8237.c: 8237A DMA controller suspend functions.
*
* Written by Pierre Ossman, 2005.
+ *
+ * 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/init.h>
diff --git a/arch/i386/kernel/i8253.c b/arch/i386/kernel/i8253.c
index 477b24daff53..9a0060b92e32 100644
--- a/arch/i386/kernel/i8253.c
+++ b/arch/i386/kernel/i8253.c
@@ -109,7 +109,7 @@ static struct clocksource clocksource_pit = {
static int __init init_pit_clocksource(void)
{
- if (num_possible_cpus() > 4) /* PIT does not scale! */
+ if (num_possible_cpus() > 1) /* PIT does not scale! */
return 0;
clocksource_pit.mult = clocksource_hz2mult(CLOCK_TICK_RATE, 20);
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index ea5f4e7958d8..62996cd17084 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -34,35 +34,15 @@
* moves to arch independent land
*/
-DEFINE_SPINLOCK(i8259A_lock);
-
-static void end_8259A_irq (unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
- irq_desc[irq].action)
- enable_8259A_irq(irq);
-}
-
-#define shutdown_8259A_irq disable_8259A_irq
-
static int i8259A_auto_eoi;
-
+DEFINE_SPINLOCK(i8259A_lock);
static void mask_and_ack_8259A(unsigned int);
-unsigned int startup_8259A_irq(unsigned int irq)
-{
- enable_8259A_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type i8259A_irq_type = {
- .typename = "XT-PIC",
- .startup = startup_8259A_irq,
- .shutdown = shutdown_8259A_irq,
- .enable = enable_8259A_irq,
- .disable = disable_8259A_irq,
- .ack = mask_and_ack_8259A,
- .end = end_8259A_irq,
+static struct irq_chip i8259A_chip = {
+ .name = "XT-PIC",
+ .mask = disable_8259A_irq,
+ .unmask = enable_8259A_irq,
+ .mask_ack = mask_and_ack_8259A,
};
/*
@@ -133,7 +113,8 @@ void make_8259A_irq(unsigned int irq)
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<<irq);
- irq_desc[irq].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
+ "XT");
enable_irq(irq);
}
@@ -327,12 +308,12 @@ void init_8259A(int auto_eoi)
outb_p(SLAVE_ICW4_DEFAULT, PIC_SLAVE_IMR); /* (slave's support for AEOI in flat mode is to be investigated) */
if (auto_eoi)
/*
- * in AEOI mode we just have to mask the interrupt
+ * In AEOI mode we just have to mask the interrupt
* when acking.
*/
- i8259A_irq_type.ack = disable_8259A_irq;
+ i8259A_chip.mask_ack = disable_8259A_irq;
else
- i8259A_irq_type.ack = mask_and_ack_8259A;
+ i8259A_chip.mask_ack = mask_and_ack_8259A;
udelay(100); /* wait for 8259A to initialize */
@@ -355,13 +336,13 @@ void init_8259A(int auto_eoi)
*/
-static irqreturn_t math_error_irq(int cpl, void *dev_id, struct pt_regs *regs)
+static irqreturn_t math_error_irq(int cpl, void *dev_id)
{
extern void math_error(void __user *);
outb(0,0xF0);
if (ignore_fpu_irq || !boot_cpu_data.hard_math)
return IRQ_NONE;
- math_error((void __user *)regs->eip);
+ math_error((void __user *)get_irq_regs()->eip);
return IRQ_HANDLED;
}
@@ -389,12 +370,13 @@ void __init init_ISA_irqs (void)
/*
* 16 old-style INTA-cycle interrupts:
*/
- irq_desc[i].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler_name(i, &i8259A_chip,
+ handle_level_irq, "XT");
} else {
/*
* 'high' PCI IRQs filled in on demand
*/
- irq_desc[i].chip = &no_irq_type;
+ irq_desc[i].chip = &no_irq_chip;
}
}
}
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index fd0df75cfbda..350192d6ab98 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -31,6 +31,9 @@
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/sysdev.h>
+#include <linux/pci.h>
+#include <linux/msi.h>
+#include <linux/htirq.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -38,6 +41,8 @@
#include <asm/timer.h>
#include <asm/i8259.h>
#include <asm/nmi.h>
+#include <asm/msidef.h>
+#include <asm/hypertransport.h>
#include <mach_apic.h>
#include <mach_apicdef.h>
@@ -86,15 +91,6 @@ static struct irq_pin_list {
int apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
-#ifdef CONFIG_PCI_MSI
-#define vector_to_irq(vector) \
- (platform_legacy_irq(vector) ? vector : vector_irq[vector])
-#else
-#define vector_to_irq(vector) (vector)
-#endif
-
-
union entry_union {
struct { u32 w1, w2; };
struct IO_APIC_route_entry entry;
@@ -280,7 +276,7 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask)
break;
entry = irq_2_pin + entry->next;
}
- set_irq_info(irq, cpumask);
+ set_native_irq_info(irq, cpumask);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
@@ -1181,46 +1177,45 @@ static inline int IO_APIC_irq_trigger(int irq)
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
-int assign_irq_vector(int irq)
+static int __assign_irq_vector(int irq)
{
static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
- unsigned long flags;
int vector;
- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
- spin_lock_irqsave(&vector_lock, flags);
+ if (irq_vector[irq] > 0)
+ return irq_vector[irq];
- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
- spin_unlock_irqrestore(&vector_lock, flags);
- return IO_APIC_VECTOR(irq);
- }
-next:
current_vector += 8;
if (current_vector == SYSCALL_VECTOR)
- goto next;
+ current_vector += 8;
if (current_vector >= FIRST_SYSTEM_VECTOR) {
offset++;
- if (!(offset%8)) {
- spin_unlock_irqrestore(&vector_lock, flags);
+ if (!(offset % 8))
return -ENOSPC;
- }
current_vector = FIRST_DEVICE_VECTOR + offset;
}
vector = current_vector;
- vector_irq[vector] = irq;
- if (irq != AUTO_ASSIGN)
- IO_APIC_VECTOR(irq) = vector;
+ irq_vector[irq] = vector;
+
+ return vector;
+}
+static int assign_irq_vector(int irq)
+{
+ unsigned long flags;
+ int vector;
+
+ spin_lock_irqsave(&vector_lock, flags);
+ vector = __assign_irq_vector(irq);
spin_unlock_irqrestore(&vector_lock, flags);
return vector;
}
-
-static struct hw_interrupt_type ioapic_level_type;
-static struct hw_interrupt_type ioapic_edge_type;
+static struct irq_chip ioapic_chip;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
@@ -1228,16 +1223,14 @@ static struct hw_interrupt_type ioapic_edge_type;
static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
{
- unsigned idx;
-
- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
-
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL)
- irq_desc[idx].chip = &ioapic_level_type;
+ set_irq_chip_and_handler_name(irq, &ioapic_chip,
+ handle_fasteoi_irq, "fasteoi");
else
- irq_desc[idx].chip = &ioapic_edge_type;
- set_intr_gate(vector, interrupt[idx]);
+ set_irq_chip_and_handler_name(irq, &ioapic_chip,
+ handle_edge_irq, "edge");
+ set_intr_gate(vector, interrupt[irq]);
}
static void __init setup_IO_APIC_irqs(void)
@@ -1346,7 +1339,8 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
* The timer IRQ doesn't have to know that behind the
* scene we have a 8259A-master in AEOI mode ...
*/
- irq_desc[0].chip = &ioapic_edge_type;
+ irq_desc[0].chip = &ioapic_chip;
+ set_irq_handler(0, handle_edge_irq);
/*
* Add it to the IO-APIC irq-routing table:
@@ -1481,17 +1475,12 @@ void __init print_IO_APIC(void)
);
}
}
- if (use_pci_vector())
- printk(KERN_INFO "Using vector-based indexing\n");
printk(KERN_DEBUG "IRQ to pin mappings:\n");
for (i = 0; i < NR_IRQS; i++) {
struct irq_pin_list *entry = irq_2_pin + i;
if (entry->pin < 0)
continue;
- if (use_pci_vector() && !platform_legacy_irq(i))
- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
- else
- printk(KERN_DEBUG "IRQ%d ", i);
+ printk(KERN_DEBUG "IRQ%d ", i);
for (;;) {
printk("-> %d:%d", entry->apic, entry->pin);
if (!entry->next)
@@ -1918,6 +1907,8 @@ static int __init timer_irq_works(void)
*/
/*
+ * Startup quirk:
+ *
* Starting up a edge-triggered IO-APIC interrupt is
* nasty - we need to make sure that we get the edge.
* If it is already asserted for some reason, we need
@@ -1925,8 +1916,10 @@ static int __init timer_irq_works(void)
*
* This is not complete - we should be able to fake
* an edge even if it isn't on the 8259A...
+ *
+ * (We do this for level-triggered IRQs too - it cannot hurt.)
*/
-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
unsigned long flags;
@@ -1943,47 +1936,18 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
return was_pending;
}
-/*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
-static void ack_edge_ioapic_irq(unsigned int irq)
+static void ack_ioapic_irq(unsigned int irq)
{
- move_irq(irq);
- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
- == (IRQ_PENDING | IRQ_DISABLED))
- mask_IO_APIC_irq(irq);
+ move_native_irq(irq);
ack_APIC_irq();
}
-/*
- * Level triggered interrupts can just be masked,
- * and shutting down and starting up the interrupt
- * is the same as enabling and disabling them -- except
- * with a startup need to return a "was pending" value.
- *
- * Level triggered interrupts are special because we
- * do not touch any IO-APIC register while handling
- * them. We ack the APIC in the end-IRQ handler, not
- * in the start-IRQ-handler. Protection against reentrance
- * from the same interrupt is still provided, both by the
- * generic IRQ layer and by the fact that an unacked local
- * APIC does not accept IRQs.
- */
-static unsigned int startup_level_ioapic_irq (unsigned int irq)
-{
- unmask_IO_APIC_irq(irq);
-
- return 0; /* don't check for pending */
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
+static void ack_ioapic_quirk_irq(unsigned int irq)
{
unsigned long v;
int i;
- move_irq(irq);
+ move_native_irq(irq);
/*
* It appears there is an erratum which affects at least version 0x11
* of I/O APIC (that's the 82093AA and cores integrated into various
@@ -2003,7 +1967,7 @@ static void end_level_ioapic_irq (unsigned int irq)
* operation to prevent an edge-triggered interrupt escaping meanwhile.
* The idea is from Manfred Spraul. --macro
*/
- i = IO_APIC_VECTOR(irq);
+ i = irq_vector[irq];
v = apic_read(APIC_TMR + ((i & ~0x1f) >> 1));
@@ -2018,105 +1982,26 @@ static void end_level_ioapic_irq (unsigned int irq)
}
}
-#ifdef CONFIG_PCI_MSI
-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_edge_ioapic_irq(irq);
-}
-
-static void ack_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- ack_edge_ioapic_irq(irq);
-}
-
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_level_ioapic_irq (irq);
-}
-
-static void end_level_ioapic_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- end_level_ioapic_irq(irq);
-}
-
-static void mask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- mask_IO_APIC_irq(irq);
-}
-
-static void unmask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- unmask_IO_APIC_irq(irq);
-}
-
-#ifdef CONFIG_SMP
-static void set_ioapic_affinity_vector (unsigned int vector,
- cpumask_t cpu_mask)
-{
- int irq = vector_to_irq(vector);
-
- set_native_irq_info(vector, cpu_mask);
- set_ioapic_affinity_irq(irq, cpu_mask);
-}
-#endif
-#endif
-
-static int ioapic_retrigger(unsigned int irq)
+static int ioapic_retrigger_irq(unsigned int irq)
{
- send_IPI_self(IO_APIC_VECTOR(irq));
+ send_IPI_self(irq_vector[irq]);
return 1;
}
-/*
- * Level and edge triggered IO-APIC interrupts need different handling,
- * so we use two separate IRQ descriptors. Edge triggered IRQs can be
- * handled with the level-triggered descriptor, but that one has slightly
- * more overhead. Level-triggered interrupts cannot be handled with the
- * edge-triggered handler, without risking IRQ storms and other ugly
- * races.
- */
-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
- .typename = "IO-APIC-edge",
- .startup = startup_edge_ioapic,
- .shutdown = shutdown_edge_ioapic,
- .enable = enable_edge_ioapic,
- .disable = disable_edge_ioapic,
- .ack = ack_edge_ioapic,
- .end = end_edge_ioapic,
+static struct irq_chip ioapic_chip __read_mostly = {
+ .name = "IO-APIC",
+ .startup = startup_ioapic_irq,
+ .mask = mask_IO_APIC_irq,
+ .unmask = unmask_IO_APIC_irq,
+ .ack = ack_ioapic_irq,
+ .eoi = ack_ioapic_quirk_irq,
#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
+ .set_affinity = set_ioapic_affinity_irq,
#endif
- .retrigger = ioapic_retrigger,
+ .retrigger = ioapic_retrigger_irq,
};
-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
- .typename = "IO-APIC-level",
- .startup = startup_level_ioapic,
- .shutdown = shutdown_level_ioapic,
- .enable = enable_level_ioapic,
- .disable = disable_level_ioapic,
- .ack = mask_and_ack_level_ioapic,
- .end = end_level_ioapic,
-#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
-#endif
- .retrigger = ioapic_retrigger,
-};
static inline void init_IO_APIC_traps(void)
{
@@ -2135,12 +2020,7 @@ static inline void init_IO_APIC_traps(void)
*/
for (irq = 0; irq < NR_IRQS ; irq++) {
int tmp = irq;
- if (use_pci_vector()) {
- if (!platform_legacy_irq(tmp))
- if ((tmp = vector_to_irq(tmp)) == -1)
- continue;
- }
- if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
+ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {
/*
* Hmm.. We don't have an entry for this,
* so default to an old-fashioned 8259
@@ -2150,20 +2030,21 @@ static inline void init_IO_APIC_traps(void)
make_8259A_irq(irq);
else
/* Strange. Oh, well.. */
- irq_desc[irq].chip = &no_irq_type;
+ irq_desc[irq].chip = &no_irq_chip;
}
}
}
-static void enable_lapic_irq (unsigned int irq)
-{
- unsigned long v;
+/*
+ * The local APIC irq-chip implementation:
+ */
- v = apic_read(APIC_LVT0);
- apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+static void ack_apic(unsigned int irq)
+{
+ ack_APIC_irq();
}
-static void disable_lapic_irq (unsigned int irq)
+static void mask_lapic_irq (unsigned int irq)
{
unsigned long v;
@@ -2171,21 +2052,19 @@ static void disable_lapic_irq (unsigned int irq)
apic_write_around(APIC_LVT0, v | APIC_LVT_MASKED);
}
-static void ack_lapic_irq (unsigned int irq)
+static void unmask_lapic_irq (unsigned int irq)
{
- ack_APIC_irq();
-}
+ unsigned long v;
-static void end_lapic_irq (unsigned int i) { /* nothing */ }
+ v = apic_read(APIC_LVT0);
+ apic_write_around(APIC_LVT0, v & ~APIC_LVT_MASKED);
+}
-static struct hw_interrupt_type lapic_irq_type __read_mostly = {
- .typename = "local-APIC-edge",
- .startup = NULL, /* startup_irq() not used for IRQ0 */
- .shutdown = NULL, /* shutdown_irq() not used for IRQ0 */
- .enable = enable_lapic_irq,
- .disable = disable_lapic_irq,
- .ack = ack_lapic_irq,
- .end = end_lapic_irq
+static struct irq_chip lapic_chip __read_mostly = {
+ .name = "local-APIC-edge",
+ .mask = mask_lapic_irq,
+ .unmask = unmask_lapic_irq,
+ .eoi = ack_apic,
};
static void setup_nmi (void)
@@ -2356,7 +2235,8 @@ static inline void check_timer(void)
printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
disable_8259A_irq(0);
- irq_desc[0].chip = &lapic_irq_type;
+ set_irq_chip_and_handler_name(0, &lapic_chip, handle_fasteoi_irq,
+ "fasteio");
apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector); /* Fixed mode */
enable_8259A_irq(0);
@@ -2531,6 +2411,240 @@ static int __init ioapic_init_sysfs(void)
device_initcall(ioapic_init_sysfs);
+/*
+ * Dynamic irq allocate and deallocation
+ */
+int create_irq(void)
+{
+ /* Allocate an unused irq */
+ int irq, new, vector;
+ unsigned long flags;
+
+ irq = -ENOSPC;
+ spin_lock_irqsave(&vector_lock, flags);
+ for (new = (NR_IRQS - 1); new >= 0; new--) {
+ if (platform_legacy_irq(new))
+ continue;
+ if (irq_vector[new] != 0)
+ continue;
+ vector = __assign_irq_vector(new);
+ if (likely(vector > 0))
+ irq = new;
+ break;
+ }
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ if (irq >= 0) {
+ set_intr_gate(vector, interrupt[irq]);
+ dynamic_irq_init(irq);
+ }
+ return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ dynamic_irq_cleanup(irq);
+
+ spin_lock_irqsave(&vector_lock, flags);
+ irq_vector[irq] = 0;
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+/*
+ * MSI mesage composition
+ */
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+{
+ int vector;
+ unsigned dest;
+
+ vector = assign_irq_vector(irq);
+ if (vector >= 0) {
+ dest = cpu_mask_to_apicid(TARGET_CPUS);
+
+ msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->address_lo =
+ MSI_ADDR_BASE_LO |
+ ((INT_DEST_MODE == 0) ?
+ MSI_ADDR_DEST_MODE_PHYSICAL:
+ MSI_ADDR_DEST_MODE_LOGICAL) |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_ADDR_REDIRECTION_CPU:
+ MSI_ADDR_REDIRECTION_LOWPRI) |
+ MSI_ADDR_DEST_ID(dest);
+
+ msg->data =
+ MSI_DATA_TRIGGER_EDGE |
+ MSI_DATA_LEVEL_ASSERT |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_DATA_DELIVERY_FIXED:
+ MSI_DATA_DELIVERY_LOWPRI) |
+ MSI_DATA_VECTOR(vector);
+ }
+ return vector;
+}
+
+#ifdef CONFIG_SMP
+static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ struct msi_msg msg;
+ unsigned int dest;
+ cpumask_t tmp;
+ int vector;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ vector = assign_irq_vector(irq);
+ if (vector < 0)
+ return;
+
+ dest = cpu_mask_to_apicid(mask);
+
+ read_msi_msg(irq, &msg);
+
+ msg.data &= ~MSI_DATA_VECTOR_MASK;
+ msg.data |= MSI_DATA_VECTOR(vector);
+ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, mask);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip msi_chip = {
+ .name = "PCI-MSI",
+ .unmask = unmask_msi_irq,
+ .mask = mask_msi_irq,
+ .ack = ack_ioapic_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = set_msi_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+{
+ struct msi_msg msg;
+ int ret;
+ ret = msi_compose_msg(dev, irq, &msg);
+ if (ret < 0)
+ return ret;
+
+ write_msi_msg(irq, &msg);
+
+ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
+ "edge");
+
+ return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ return;
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+/*
+ * Hypertransport interrupt support
+ */
+#ifdef CONFIG_HT_IRQ
+
+#ifdef CONFIG_SMP
+
+static void target_ht_irq(unsigned int irq, unsigned int dest)
+{
+ u32 low, high;
+ low = read_ht_irq_low(irq);
+ high = read_ht_irq_high(irq);
+
+ low &= ~(HT_IRQ_LOW_DEST_ID_MASK);
+ high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+
+ low |= HT_IRQ_LOW_DEST_ID(dest);
+ high |= HT_IRQ_HIGH_DEST_ID(dest);
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+}
+
+static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ unsigned int dest;
+ cpumask_t tmp;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+ dest = cpu_mask_to_apicid(mask);
+
+ target_ht_irq(irq, dest);
+ set_native_irq_info(irq, mask);
+}
+#endif
+
+static struct irq_chip ht_irq_chip = {
+ .name = "PCI-HT",
+ .mask = mask_ht_irq,
+ .unmask = unmask_ht_irq,
+ .ack = ack_ioapic_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = set_ht_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+{
+ int vector;
+
+ vector = assign_irq_vector(irq);
+ if (vector >= 0) {
+ u32 low, high;
+ unsigned dest;
+ cpumask_t tmp;
+
+ cpus_clear(tmp);
+ cpu_set(vector >> 8, tmp);
+ dest = cpu_mask_to_apicid(tmp);
+
+ high = HT_IRQ_HIGH_DEST_ID(dest);
+
+ low = HT_IRQ_LOW_BASE |
+ HT_IRQ_LOW_DEST_ID(dest) |
+ HT_IRQ_LOW_VECTOR(vector) |
+ ((INT_DEST_MODE == 0) ?
+ HT_IRQ_LOW_DM_PHYSICAL :
+ HT_IRQ_LOW_DM_LOGICAL) |
+ HT_IRQ_LOW_RQEOI_EDGE |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ HT_IRQ_LOW_MT_FIXED :
+ HT_IRQ_LOW_MT_ARBITRATED) |
+ HT_IRQ_LOW_IRQ_MASKED;
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+
+ set_irq_chip_and_handler_name(irq, &ht_irq_chip,
+ handle_edge_irq, "edge");
+ }
+ return vector;
+}
+#endif /* CONFIG_HT_IRQ */
+
/* --------------------------------------------------------------------------
ACPI-based IOAPIC Configuration
-------------------------------------------------------------------------- */
@@ -2684,7 +2798,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
ioapic_write_entry(ioapic, pin, entry);
spin_lock_irqsave(&ioapic_lock, flags);
- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
+ set_native_irq_info(irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 5fe547cd8f9f..3201d421090a 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -53,8 +53,10 @@ static union irq_ctx *softirq_ctx[NR_CPUS] __read_mostly;
*/
fastcall unsigned int do_IRQ(struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
/* high bit used in ret_from_ code */
int irq = ~regs->orig_eax;
+ struct irq_desc *desc = irq_desc + irq;
#ifdef CONFIG_4KSTACKS
union irq_ctx *curctx, *irqctx;
u32 *isp;
@@ -66,6 +68,7 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
BUG();
}
+ old_regs = set_irq_regs(regs);
irq_enter();
#ifdef CONFIG_DEBUG_STACKOVERFLOW
/* Debugging check for stack overflow: is there less than 1KB free? */
@@ -110,19 +113,20 @@ fastcall unsigned int do_IRQ(struct pt_regs *regs)
(curctx->tinfo.preempt_count & SOFTIRQ_MASK);
asm volatile(
- " xchgl %%ebx,%%esp \n"
- " call __do_IRQ \n"
+ " xchgl %%ebx,%%esp \n"
+ " call *%%edi \n"
" movl %%ebx,%%esp \n"
: "=a" (arg1), "=d" (arg2), "=b" (ebx)
- : "0" (irq), "1" (regs), "2" (isp)
- : "memory", "cc", "ecx"
+ : "0" (irq), "1" (desc), "2" (isp),
+ "D" (desc->handle_irq)
+ : "memory", "cc"
);
} else
#endif
- __do_IRQ(irq, regs);
+ desc->handle_irq(irq, desc);
irq_exit();
-
+ set_irq_regs(old_regs);
return 1;
}
@@ -253,7 +257,8 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- seq_printf(p, " %14s", irq_desc[i].chip->typename);
+ seq_printf(p, " %8s", irq_desc[i].chip->name);
+ seq_printf(p, "-%-8s", irq_desc[i].name);
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index afe6505ca0b3..d98e44b16fe2 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -230,20 +230,20 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)&regs->esp;
- struct kretprobe_instance *ri;
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->task = current;
+ struct kretprobe_instance *ri;
+
+ if ((ri = get_free_rp_inst(rp)) != NULL) {
+ ri->rp = rp;
+ ri->task = current;
ri->ret_addr = (kprobe_opcode_t *) *sara;
/* Replace the return addr with trampoline addr */
*sara = (unsigned long) &kretprobe_trampoline;
-
- add_rp_inst(ri);
- } else {
- rp->nmissed++;
- }
+ add_rp_inst(ri);
+ } else {
+ rp->nmissed++;
+ }
}
/*
@@ -359,7 +359,7 @@ no_kprobe:
void __kprobes kretprobe_trampoline_holder(void)
{
asm volatile ( ".global kretprobe_trampoline\n"
- "kretprobe_trampoline: \n"
+ "kretprobe_trampoline: \n"
" pushf\n"
/* skip cs, eip, orig_eax, es, ds */
" subl $20, %esp\n"
@@ -395,14 +395,15 @@ no_kprobe:
*/
fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
{
- struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
- struct hlist_node *node, *tmp;
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+ INIT_HLIST_HEAD(&empty_rp);
spin_lock_irqsave(&kretprobe_lock, flags);
- head = kretprobe_inst_table_head(current);
+ head = kretprobe_inst_table_head(current);
/*
* It is possible to have multiple instances associated with a given
@@ -413,14 +414,14 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
- * function, the first instance's ret_addr will point to the
+ * function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task != current)
+ if (ri->task != current)
/* another task is sharing our hash bucket */
- continue;
+ continue;
if (ri->rp && ri->rp->handler){
__get_cpu_var(current_kprobe) = &ri->rp->kp;
@@ -429,7 +430,7 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
}
orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_rp_inst(ri);
+ recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
@@ -444,6 +445,10 @@ fastcall void *__kprobes trampoline_handler(struct pt_regs *regs)
spin_unlock_irqrestore(&kretprobe_lock, flags);
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
return (void*)orig_ret_address;
}
diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
index 983f95707e11..445211eb2d57 100644
--- a/arch/i386/kernel/ldt.c
+++ b/arch/i386/kernel/ldt.c
@@ -1,5 +1,5 @@
/*
- * linux/kernel/ldt.c
+ * linux/arch/i386/kernel/ldt.c
*
* Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds
* Copyright (C) 1999 Ingo Molnar <mingo@redhat.com>
diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c
index 40b44cc0d14b..c4d0291b519f 100644
--- a/arch/i386/kernel/microcode.c
+++ b/arch/i386/kernel/microcode.c
@@ -2,6 +2,7 @@
* Intel CPU Microcode Update Driver for Linux
*
* Copyright (C) 2000-2004 Tigran Aivazian
+ * 2006 Shaohua Li <shaohua.li@intel.com>
*
* This driver allows to upgrade microcode on Intel processors
* belonging to IA-32 family - PentiumPro, Pentium II,
@@ -82,6 +83,9 @@
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/mutex.h>
+#include <linux/cpu.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
#include <asm/msr.h>
#include <asm/uaccess.h>
@@ -91,9 +95,6 @@ MODULE_DESCRIPTION("Intel CPU (IA-32) Microcode Update Driver");
MODULE_AUTHOR("Tigran Aivazian <tigran@veritas.com>");
MODULE_LICENSE("GPL");
-static int verbose;
-module_param(verbose, int, 0644);
-
#define MICROCODE_VERSION "1.14a"
#define DEFAULT_UCODE_DATASIZE (2000) /* 2000 bytes */
@@ -120,55 +121,40 @@ static DEFINE_SPINLOCK(microcode_update_lock);
/* no concurrent ->write()s are allowed on /dev/cpu/microcode */
static DEFINE_MUTEX(microcode_mutex);
-static void __user *user_buffer; /* user area microcode data buffer */
-static unsigned int user_buffer_size; /* it's size */
-
-typedef enum mc_error_code {
- MC_SUCCESS = 0,
- MC_IGNORED = 1,
- MC_NOTFOUND = 2,
- MC_MARKED = 3,
- MC_ALLOCATED = 4,
-} mc_error_code_t;
-
static struct ucode_cpu_info {
+ int valid;
unsigned int sig;
- unsigned int pf, orig_pf;
+ unsigned int pf;
unsigned int rev;
- unsigned int cksum;
- mc_error_code_t err;
microcode_t *mc;
} ucode_cpu_info[NR_CPUS];
-
-static int microcode_open (struct inode *unused1, struct file *unused2)
-{
- return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-}
-static void collect_cpu_info (void *unused)
+static void collect_cpu_info(int cpu_num)
{
- int cpu_num = smp_processor_id();
struct cpuinfo_x86 *c = cpu_data + cpu_num;
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
unsigned int val[2];
- uci->sig = uci->pf = uci->rev = uci->cksum = 0;
- uci->err = MC_NOTFOUND;
+ /* We should bind the task to the CPU */
+ BUG_ON(raw_smp_processor_id() != cpu_num);
+ uci->pf = uci->rev = 0;
uci->mc = NULL;
+ uci->valid = 1;
if (c->x86_vendor != X86_VENDOR_INTEL || c->x86 < 6 ||
cpu_has(c, X86_FEATURE_IA64)) {
- printk(KERN_ERR "microcode: CPU%d not a capable Intel processor\n", cpu_num);
+ printk(KERN_ERR "microcode: CPU%d not a capable Intel "
+ "processor\n", cpu_num);
+ uci->valid = 0;
return;
- } else {
- uci->sig = cpuid_eax(0x00000001);
+ }
- if ((c->x86_model >= 5) || (c->x86 > 6)) {
- /* get processor flags from MSR 0x17 */
- rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
- uci->pf = 1 << ((val[1] >> 18) & 7);
- }
- uci->orig_pf = uci->pf;
+ uci->sig = cpuid_eax(0x00000001);
+
+ if ((c->x86_model >= 5) || (c->x86 > 6)) {
+ /* get processor flags from MSR 0x17 */
+ rdmsr(MSR_IA32_PLATFORM_ID, val[0], val[1]);
+ uci->pf = 1 << ((val[1] >> 18) & 7);
}
wrmsr(MSR_IA32_UCODE_REV, 0, 0);
@@ -180,218 +166,159 @@ static void collect_cpu_info (void *unused)
uci->sig, uci->pf, uci->rev);
}
-static inline void mark_microcode_update (int cpu_num, microcode_header_t *mc_header, int sig, int pf, int cksum)
+static inline int microcode_update_match(int cpu_num,
+ microcode_header_t *mc_header, int sig, int pf)
{
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- pr_debug("Microcode Found.\n");
- pr_debug(" Header Revision 0x%x\n", mc_header->hdrver);
- pr_debug(" Loader Revision 0x%x\n", mc_header->ldrver);
- pr_debug(" Revision 0x%x \n", mc_header->rev);
- pr_debug(" Date %x/%x/%x\n",
- ((mc_header->date >> 24 ) & 0xff),
- ((mc_header->date >> 16 ) & 0xff),
- (mc_header->date & 0xFFFF));
- pr_debug(" Signature 0x%x\n", sig);
- pr_debug(" Type 0x%x Family 0x%x Model 0x%x Stepping 0x%x\n",
- ((sig >> 12) & 0x3),
- ((sig >> 8) & 0xf),
- ((sig >> 4) & 0xf),
- ((sig & 0xf)));
- pr_debug(" Processor Flags 0x%x\n", pf);
- pr_debug(" Checksum 0x%x\n", cksum);
-
- if (mc_header->rev < uci->rev) {
- if (uci->err == MC_NOTFOUND) {
- uci->err = MC_IGNORED;
- uci->cksum = mc_header->rev;
- } else if (uci->err == MC_IGNORED && uci->cksum < mc_header->rev)
- uci->cksum = mc_header->rev;
- } else if (mc_header->rev == uci->rev) {
- if (uci->err < MC_MARKED) {
- /* notify the caller of success on this cpu */
- uci->err = MC_SUCCESS;
- }
- } else if (uci->err != MC_ALLOCATED || mc_header->rev > uci->mc->hdr.rev) {
- pr_debug("microcode: CPU%d found a matching microcode update with "
- " revision 0x%x (current=0x%x)\n", cpu_num, mc_header->rev, uci->rev);
- uci->cksum = cksum;
- uci->pf = pf; /* keep the original mc pf for cksum calculation */
- uci->err = MC_MARKED; /* found the match */
- for_each_online_cpu(cpu_num) {
- if (ucode_cpu_info + cpu_num != uci
- && ucode_cpu_info[cpu_num].mc == uci->mc) {
- uci->mc = NULL;
- break;
- }
- }
- if (uci->mc != NULL) {
- vfree(uci->mc);
- uci->mc = NULL;
- }
- }
- return;
+ if (!sigmatch(sig, uci->sig, pf, uci->pf)
+ || mc_header->rev <= uci->rev)
+ return 0;
+ return 1;
}
-static int find_matching_ucodes (void)
+static int microcode_sanity_check(void *mc)
{
- int cursor = 0;
- int error = 0;
-
- while (cursor + MC_HEADER_SIZE < user_buffer_size) {
- microcode_header_t mc_header;
- void *newmc = NULL;
- int i, sum, cpu_num, allocated_flag, total_size, data_size, ext_table_size;
+ microcode_header_t *mc_header = mc;
+ struct extended_sigtable *ext_header = NULL;
+ struct extended_signature *ext_sig;
+ unsigned long total_size, data_size, ext_table_size;
+ int sum, orig_sum, ext_sigcount = 0, i;
+
+ total_size = get_totalsize(mc_header);
+ data_size = get_datasize(mc_header);
+ if (data_size + MC_HEADER_SIZE > total_size) {
+ printk(KERN_ERR "microcode: error! "
+ "Bad data size in microcode data file\n");
+ return -EINVAL;
+ }
- if (copy_from_user(&mc_header, user_buffer + cursor, MC_HEADER_SIZE)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- error = -EFAULT;
- goto out;
+ if (mc_header->ldrver != 1 || mc_header->hdrver != 1) {
+ printk(KERN_ERR "microcode: error! "
+ "Unknown microcode update format\n");
+ return -EINVAL;
+ }
+ ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
+ if (ext_table_size) {
+ if ((ext_table_size < EXT_HEADER_SIZE)
+ || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
+ printk(KERN_ERR "microcode: error! "
+ "Small exttable size in microcode data file\n");
+ return -EINVAL;
}
-
- total_size = get_totalsize(&mc_header);
- if ((cursor + total_size > user_buffer_size) || (total_size < DEFAULT_UCODE_TOTALSIZE)) {
- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
- error = -EINVAL;
- goto out;
+ ext_header = mc + MC_HEADER_SIZE + data_size;
+ if (ext_table_size != exttable_size(ext_header)) {
+ printk(KERN_ERR "microcode: error! "
+ "Bad exttable size in microcode data file\n");
+ return -EFAULT;
}
+ ext_sigcount = ext_header->count;
+ }
- data_size = get_datasize(&mc_header);
- if ((data_size + MC_HEADER_SIZE > total_size) || (data_size < DEFAULT_UCODE_DATASIZE)) {
- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
- error = -EINVAL;
- goto out;
+ /* check extended table checksum */
+ if (ext_table_size) {
+ int ext_table_sum = 0;
+ int *ext_tablep = (int *)ext_header;
+
+ i = ext_table_size / DWSIZE;
+ while (i--)
+ ext_table_sum += ext_tablep[i];
+ if (ext_table_sum) {
+ printk(KERN_WARNING "microcode: aborting, "
+ "bad extended signature table checksum\n");
+ return -EINVAL;
}
+ }
- if (mc_header.ldrver != 1 || mc_header.hdrver != 1) {
- printk(KERN_ERR "microcode: error! Unknown microcode update format\n");
- error = -EINVAL;
- goto out;
+ /* calculate the checksum */
+ orig_sum = 0;
+ i = (MC_HEADER_SIZE + data_size) / DWSIZE;
+ while (i--)
+ orig_sum += ((int *)mc)[i];
+ if (orig_sum) {
+ printk(KERN_ERR "microcode: aborting, bad checksum\n");
+ return -EINVAL;
+ }
+ if (!ext_table_size)
+ return 0;
+ /* check extended signature checksum */
+ for (i = 0; i < ext_sigcount; i++) {
+ ext_sig = (struct extended_signature *)((void *)ext_header
+ + EXT_HEADER_SIZE + EXT_SIGNATURE_SIZE * i);
+ sum = orig_sum
+ - (mc_header->sig + mc_header->pf + mc_header->cksum)
+ + (ext_sig->sig + ext_sig->pf + ext_sig->cksum);
+ if (sum) {
+ printk(KERN_ERR "microcode: aborting, bad checksum\n");
+ return -EINVAL;
}
+ }
+ return 0;
+}
- for_each_online_cpu(cpu_num) {
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
- if (sigmatch(mc_header.sig, uci->sig, mc_header.pf, uci->orig_pf))
- mark_microcode_update(cpu_num, &mc_header, mc_header.sig, mc_header.pf, mc_header.cksum);
- }
+/*
+ * return 0 - no update found
+ * return 1 - found update
+ * return < 0 - error
+ */
+static int get_maching_microcode(void *mc, int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+ microcode_header_t *mc_header = mc;
+ struct extended_sigtable *ext_header;
+ unsigned long total_size = get_totalsize(mc_header);
+ int ext_sigcount, i;
+ struct extended_signature *ext_sig;
+ void *new_mc;
+
+ if (microcode_update_match(cpu, mc_header,
+ mc_header->sig, mc_header->pf))
+ goto find;
+
+ if (total_size <= get_datasize(mc_header) + MC_HEADER_SIZE)
+ return 0;
+
+ ext_header = (struct extended_sigtable *)(mc +
+ get_datasize(mc_header) + MC_HEADER_SIZE);
+ ext_sigcount = ext_header->count;
+ ext_sig = (struct extended_signature *)((void *)ext_header
+ + EXT_HEADER_SIZE);
+ for (i = 0; i < ext_sigcount; i++) {
+ if (microcode_update_match(cpu, mc_header,
+ ext_sig->sig, ext_sig->pf))
+ goto find;
+ ext_sig++;
+ }
+ return 0;
+find:
+ pr_debug("microcode: CPU %d found a matching microcode update with"
+ " version 0x%x (current=0x%x)\n", cpu, mc_header->rev,uci->rev);
+ new_mc = vmalloc(total_size);
+ if (!new_mc) {
+ printk(KERN_ERR "microcode: error! Can not allocate memory\n");
+ return -ENOMEM;
+ }
- ext_table_size = total_size - (MC_HEADER_SIZE + data_size);
- if (ext_table_size) {
- struct extended_sigtable ext_header;
- struct extended_signature ext_sig;
- int ext_sigcount;
+ /* free previous update file */
+ vfree(uci->mc);
- if ((ext_table_size < EXT_HEADER_SIZE)
- || ((ext_table_size - EXT_HEADER_SIZE) % EXT_SIGNATURE_SIZE)) {
- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
- error = -EINVAL;
- goto out;
- }
- if (copy_from_user(&ext_header, user_buffer + cursor
- + MC_HEADER_SIZE + data_size, EXT_HEADER_SIZE)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- error = -EFAULT;
- goto out;
- }
- if (ext_table_size != exttable_size(&ext_header)) {
- printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
- error = -EFAULT;
- goto out;
- }
-
- ext_sigcount = ext_header.count;
-
- for (i = 0; i < ext_sigcount; i++) {
- if (copy_from_user(&ext_sig, user_buffer + cursor + MC_HEADER_SIZE + data_size + EXT_HEADER_SIZE
- + EXT_SIGNATURE_SIZE * i, EXT_SIGNATURE_SIZE)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- error = -EFAULT;
- goto out;
- }
- for_each_online_cpu(cpu_num) {
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
-
- if (sigmatch(ext_sig.sig, uci->sig, ext_sig.pf, uci->orig_pf)) {
- mark_microcode_update(cpu_num, &mc_header, ext_sig.sig, ext_sig.pf, ext_sig.cksum);
- }
- }
- }
- }
- /* now check if any cpu has matched */
- allocated_flag = 0;
- sum = 0;
- for_each_online_cpu(cpu_num) {
- if (ucode_cpu_info[cpu_num].err == MC_MARKED) {
- struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- if (!allocated_flag) {
- allocated_flag = 1;
- newmc = vmalloc(total_size);
- if (!newmc) {
- printk(KERN_ERR "microcode: error! Can not allocate memory\n");
- error = -ENOMEM;
- goto out;
- }
- if (copy_from_user(newmc + MC_HEADER_SIZE,
- user_buffer + cursor + MC_HEADER_SIZE,
- total_size - MC_HEADER_SIZE)) {
- printk(KERN_ERR "microcode: error! Can not read user data\n");
- vfree(newmc);
- error = -EFAULT;
- goto out;
- }
- memcpy(newmc, &mc_header, MC_HEADER_SIZE);
- /* check extended table checksum */
- if (ext_table_size) {
- int ext_table_sum = 0;
- int * ext_tablep = (((void *) newmc) + MC_HEADER_SIZE + data_size);
- i = ext_table_size / DWSIZE;
- while (i--) ext_table_sum += ext_tablep[i];
- if (ext_table_sum) {
- printk(KERN_WARNING "microcode: aborting, bad extended signature table checksum\n");
- vfree(newmc);
- error = -EINVAL;
- goto out;
- }
- }
-
- /* calculate the checksum */
- i = (MC_HEADER_SIZE + data_size) / DWSIZE;
- while (i--) sum += ((int *)newmc)[i];
- sum -= (mc_header.sig + mc_header.pf + mc_header.cksum);
- }
- ucode_cpu_info[cpu_num].mc = newmc;
- ucode_cpu_info[cpu_num].err = MC_ALLOCATED; /* mc updated */
- if (sum + uci->sig + uci->pf + uci->cksum != 0) {
- printk(KERN_ERR "microcode: CPU%d aborting, bad checksum\n", cpu_num);
- error = -EINVAL;
- goto out;
- }
- }
- }
- cursor += total_size; /* goto the next update patch */
- } /* end of while */
-out:
- return error;
+ memcpy(new_mc, mc, total_size);
+ uci->mc = new_mc;
+ return 1;
}
-static void do_update_one (void * unused)
+static void apply_microcode(int cpu)
{
unsigned long flags;
unsigned int val[2];
- int cpu_num = smp_processor_id();
+ int cpu_num = raw_smp_processor_id();
struct ucode_cpu_info *uci = ucode_cpu_info + cpu_num;
- if (uci->mc == NULL) {
- if (verbose) {
- if (uci->err == MC_SUCCESS)
- printk(KERN_INFO "microcode: CPU%d already at revision 0x%x\n",
- cpu_num, uci->rev);
- else
- printk(KERN_INFO "microcode: No new microcode data for CPU%d\n", cpu_num);
- }
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu_num != cpu);
+
+ if (uci->mc == NULL)
return;
- }
/* serialize access to the physical write to MSR 0x79 */
spin_lock_irqsave(&microcode_update_lock, flags);
@@ -408,68 +335,107 @@ static void do_update_one (void * unused)
/* get the current revision from MSR 0x8B */
rdmsr(MSR_IA32_UCODE_REV, val[0], val[1]);
- /* notify the caller of success on this cpu */
- uci->err = MC_SUCCESS;
spin_unlock_irqrestore(&microcode_update_lock, flags);
- printk(KERN_INFO "microcode: CPU%d updated from revision "
+ if (val[1] != uci->mc->hdr.rev) {
+ printk(KERN_ERR "microcode: CPU%d updated from revision "
+ "0x%x to 0x%x failed\n", cpu_num, uci->rev, val[1]);
+ return;
+ }
+ pr_debug("microcode: CPU%d updated from revision "
"0x%x to 0x%x, date = %08x \n",
cpu_num, uci->rev, val[1], uci->mc->hdr.date);
- return;
+ uci->rev = val[1];
}
-static int do_microcode_update (void)
-{
- int i, error;
+#ifdef CONFIG_MICROCODE_OLD_INTERFACE
+static void __user *user_buffer; /* user area microcode data buffer */
+static unsigned int user_buffer_size; /* it's size */
- if (on_each_cpu(collect_cpu_info, NULL, 1, 1) != 0) {
- printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
- error = -EIO;
- goto out;
+static long get_next_ucode(void **mc, long offset)
+{
+ microcode_header_t mc_header;
+ unsigned long total_size;
+
+ /* No more data */
+ if (offset >= user_buffer_size)
+ return 0;
+ if (copy_from_user(&mc_header, user_buffer + offset, MC_HEADER_SIZE)) {
+ printk(KERN_ERR "microcode: error! Can not read user data\n");
+ return -EFAULT;
}
-
- if ((error = find_matching_ucodes())) {
- printk(KERN_ERR "microcode: Error in the microcode data\n");
- goto out_free;
+ total_size = get_totalsize(&mc_header);
+ if (offset + total_size > user_buffer_size) {
+ printk(KERN_ERR "microcode: error! Bad total size in microcode "
+ "data file\n");
+ return -EINVAL;
}
-
- if (on_each_cpu(do_update_one, NULL, 1, 1) != 0) {
- printk(KERN_ERR "microcode: Error! Could not run on all processors\n");
- error = -EIO;
+ *mc = vmalloc(total_size);
+ if (!*mc)
+ return -ENOMEM;
+ if (copy_from_user(*mc, user_buffer + offset, total_size)) {
+ printk(KERN_ERR "microcode: error! Can not read user data\n");
+ vfree(*mc);
+ return -EFAULT;
}
+ return offset + total_size;
+}
+
+static int do_microcode_update (void)
+{
+ long cursor = 0;
+ int error = 0;
+ void *new_mc;
+ int cpu;
+ cpumask_t old;
+
+ old = current->cpus_allowed;
-out_free:
- for_each_online_cpu(i) {
- if (ucode_cpu_info[i].mc) {
- int j;
- void *tmp = ucode_cpu_info[i].mc;
- vfree(tmp);
- for_each_online_cpu(j) {
- if (ucode_cpu_info[j].mc == tmp)
- ucode_cpu_info[j].mc = NULL;
- }
+ while ((cursor = get_next_ucode(&new_mc, cursor)) > 0) {
+ error = microcode_sanity_check(new_mc);
+ if (error)
+ goto out;
+ /*
+ * It's possible the data file has multiple matching ucode,
+ * lets keep searching till the latest version
+ */
+ for_each_online_cpu(cpu) {
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (!uci->valid)
+ continue;
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ error = get_maching_microcode(new_mc, cpu);
+ if (error < 0)
+ goto out;
+ if (error == 1)
+ apply_microcode(cpu);
}
- if (ucode_cpu_info[i].err == MC_IGNORED && verbose)
- printk(KERN_WARNING "microcode: CPU%d not 'upgrading' to earlier revision"
- " 0x%x (current=0x%x)\n", i, ucode_cpu_info[i].cksum, ucode_cpu_info[i].rev);
+ vfree(new_mc);
}
out:
+ if (cursor > 0)
+ vfree(new_mc);
+ if (cursor < 0)
+ error = cursor;
+ set_cpus_allowed(current, old);
return error;
}
+static int microcode_open (struct inode *unused1, struct file *unused2)
+{
+ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
+}
+
static ssize_t microcode_write (struct file *file, const char __user *buf, size_t len, loff_t *ppos)
{
ssize_t ret;
- if (len < DEFAULT_UCODE_TOTALSIZE) {
- printk(KERN_ERR "microcode: not enough data\n");
- return -EINVAL;
- }
-
if ((len >> PAGE_SHIFT) > num_physpages) {
printk(KERN_ERR "microcode: too much data (max %ld pages)\n", num_physpages);
return -EINVAL;
}
+ lock_cpu_hotplug();
mutex_lock(&microcode_mutex);
user_buffer = (void __user *) buf;
@@ -480,6 +446,7 @@ static ssize_t microcode_write (struct file *file, const char __user *buf, size_
ret = (ssize_t)len;
mutex_unlock(&microcode_mutex);
+ unlock_cpu_hotplug();
return ret;
}
@@ -496,7 +463,7 @@ static struct miscdevice microcode_dev = {
.fops = &microcode_fops,
};
-static int __init microcode_init (void)
+static int __init microcode_dev_init (void)
{
int error;
@@ -508,6 +475,284 @@ static int __init microcode_init (void)
return error;
}
+ return 0;
+}
+
+static void __exit microcode_dev_exit (void)
+{
+ misc_deregister(&microcode_dev);
+}
+
+MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
+#else
+#define microcode_dev_init() 0
+#define microcode_dev_exit() do { } while(0)
+#endif
+
+static long get_next_ucode_from_buffer(void **mc, void *buf,
+ unsigned long size, long offset)
+{
+ microcode_header_t *mc_header;
+ unsigned long total_size;
+
+ /* No more data */
+ if (offset >= size)
+ return 0;
+ mc_header = (microcode_header_t *)(buf + offset);
+ total_size = get_totalsize(mc_header);
+
+ if (offset + total_size > size) {
+ printk(KERN_ERR "microcode: error! Bad data in microcode data file\n");
+ return -EINVAL;
+ }
+
+ *mc = vmalloc(total_size);
+ if (!*mc) {
+ printk(KERN_ERR "microcode: error! Can not allocate memory\n");
+ return -ENOMEM;
+ }
+ memcpy(*mc, buf + offset, total_size);
+ return offset + total_size;
+}
+
+/* fake device for request_firmware */
+static struct platform_device *microcode_pdev;
+
+static int cpu_request_microcode(int cpu)
+{
+ char name[30];
+ struct cpuinfo_x86 *c = cpu_data + cpu;
+ const struct firmware *firmware;
+ void *buf;
+ unsigned long size;
+ long offset = 0;
+ int error;
+ void *mc;
+
+ /* We should bind the task to the CPU */
+ BUG_ON(cpu != raw_smp_processor_id());
+ sprintf(name,"intel-ucode/%02x-%02x-%02x",
+ c->x86, c->x86_model, c->x86_mask);
+ error = request_firmware(&firmware, name, &microcode_pdev->dev);
+ if (error) {
+ pr_debug("ucode data file %s load failed\n", name);
+ return error;
+ }
+ buf = (void *)firmware->data;
+ size = firmware->size;
+ while ((offset = get_next_ucode_from_buffer(&mc, buf, size, offset))
+ > 0) {
+ error = microcode_sanity_check(mc);
+ if (error)
+ break;
+ error = get_maching_microcode(mc, cpu);
+ if (error < 0)
+ break;
+ /*
+ * It's possible the data file has multiple matching ucode,
+ * lets keep searching till the latest version
+ */
+ if (error == 1) {
+ apply_microcode(cpu);
+ error = 0;
+ }
+ vfree(mc);
+ }
+ if (offset > 0)
+ vfree(mc);
+ if (offset < 0)
+ error = offset;
+ release_firmware(firmware);
+
+ return error;
+}
+
+static void microcode_init_cpu(int cpu)
+{
+ cpumask_t old;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ old = current->cpus_allowed;
+
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+ mutex_lock(&microcode_mutex);
+ collect_cpu_info(cpu);
+ if (uci->valid)
+ cpu_request_microcode(cpu);
+ mutex_unlock(&microcode_mutex);
+ set_cpus_allowed(current, old);
+}
+
+static void microcode_fini_cpu(int cpu)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ mutex_lock(&microcode_mutex);
+ uci->valid = 0;
+ vfree(uci->mc);
+ uci->mc = NULL;
+ mutex_unlock(&microcode_mutex);
+}
+
+static ssize_t reload_store(struct sys_device *dev, const char *buf, size_t sz)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+ char *end;
+ unsigned long val = simple_strtoul(buf, &end, 0);
+ int err = 0;
+ int cpu = dev->id;
+
+ if (end == buf)
+ return -EINVAL;
+ if (val == 1) {
+ cpumask_t old;
+
+ old = current->cpus_allowed;
+
+ lock_cpu_hotplug();
+ set_cpus_allowed(current, cpumask_of_cpu(cpu));
+
+ mutex_lock(&microcode_mutex);
+ if (uci->valid)
+ err = cpu_request_microcode(cpu);
+ mutex_unlock(&microcode_mutex);
+ unlock_cpu_hotplug();
+ set_cpus_allowed(current, old);
+ }
+ if (err)
+ return err;
+ return sz;
+}
+
+static ssize_t version_show(struct sys_device *dev, char *buf)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+ return sprintf(buf, "0x%x\n", uci->rev);
+}
+
+static ssize_t pf_show(struct sys_device *dev, char *buf)
+{
+ struct ucode_cpu_info *uci = ucode_cpu_info + dev->id;
+
+ return sprintf(buf, "0x%x\n", uci->pf);
+}
+
+static SYSDEV_ATTR(reload, 0200, NULL, reload_store);
+static SYSDEV_ATTR(version, 0400, version_show, NULL);
+static SYSDEV_ATTR(processor_flags, 0400, pf_show, NULL);
+
+static struct attribute *mc_default_attrs[] = {
+ &attr_reload.attr,
+ &attr_version.attr,
+ &attr_processor_flags.attr,
+ NULL
+};
+
+static struct attribute_group mc_attr_group = {
+ .attrs = mc_default_attrs,
+ .name = "microcode",
+};
+
+static int mc_sysdev_add(struct sys_device *sys_dev)
+{
+ int err, cpu = sys_dev->id;
+ struct ucode_cpu_info *uci = ucode_cpu_info + cpu;
+
+ if (!cpu_online(cpu))
+ return 0;
+
+ pr_debug("Microcode:CPU %d added\n", cpu);
+ memset(uci, 0, sizeof(*uci));
+
+ err = sysfs_create_group(&sys_dev->kobj, &mc_attr_group);
+ if (err)
+ return err;
+
+ microcode_init_cpu(cpu);
+ return 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);
+ microcode_fini_cpu(cpu);
+ sysfs_remove_group(&sys_dev->kobj, &mc_attr_group);
+ return 0;
+}
+
+static int mc_sysdev_resume(struct sys_device *dev)
+{
+ int cpu = dev->id;
+
+ if (!cpu_online(cpu))
+ return 0;
+ pr_debug("Microcode:CPU %d resumed\n", cpu);
+ /* only CPU 0 will apply ucode here */
+ apply_microcode(0);
+ return 0;
+}
+
+static struct sysdev_driver mc_sysdev_driver = {
+ .add = mc_sysdev_add,
+ .remove = mc_sysdev_remove,
+ .resume = mc_sysdev_resume,
+};
+
+#ifdef CONFIG_HOTPLUG_CPU
+static __cpuinit int
+mc_cpu_callback(struct notifier_block *nb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct sys_device *sys_dev;
+
+ sys_dev = get_cpu_sysdev(cpu);
+ switch (action) {
+ case CPU_ONLINE:
+ case CPU_DOWN_FAILED:
+ mc_sysdev_add(sys_dev);
+ break;
+ case CPU_DOWN_PREPARE:
+ mc_sysdev_remove(sys_dev);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block mc_cpu_notifier = {
+ .notifier_call = mc_cpu_callback,
+};
+#endif
+
+static int __init microcode_init (void)
+{
+ int error;
+
+ error = microcode_dev_init();
+ if (error)
+ return error;
+ microcode_pdev = platform_device_register_simple("microcode", -1,
+ NULL, 0);
+ if (IS_ERR(microcode_pdev)) {
+ microcode_dev_exit();
+ return PTR_ERR(microcode_pdev);
+ }
+
+ lock_cpu_hotplug();
+ error = sysdev_driver_register(&cpu_sysdev_class, &mc_sysdev_driver);
+ unlock_cpu_hotplug();
+ if (error) {
+ microcode_dev_exit();
+ platform_device_unregister(microcode_pdev);
+ return error;
+ }
+
+ register_hotcpu_notifier(&mc_cpu_notifier);
+
printk(KERN_INFO
"IA-32 Microcode Update Driver: v" MICROCODE_VERSION " <tigran@veritas.com>\n");
return 0;
@@ -515,9 +760,16 @@ static int __init microcode_init (void)
static void __exit microcode_exit (void)
{
- misc_deregister(&microcode_dev);
+ microcode_dev_exit();
+
+ unregister_hotcpu_notifier(&mc_cpu_notifier);
+
+ lock_cpu_hotplug();
+ sysdev_driver_unregister(&cpu_sysdev_class, &mc_sysdev_driver);
+ unlock_cpu_hotplug();
+
+ platform_device_unregister(microcode_pdev);
}
module_init(microcode_init)
module_exit(microcode_exit)
-MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index dbda706fdd14..eaafe233a5da 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -13,7 +13,6 @@
* Mikael Pettersson : PM converted to driver model. Disable/enable API.
*/
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/module.h>
@@ -31,6 +30,9 @@
#include "mach_traps.h"
+int unknown_nmi_panic;
+int nmi_watchdog_enabled;
+
/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
* evtsel_nmi_owner tracks the ownership of the event selection
* - different performance counters/ event selection may be reserved for
@@ -217,11 +219,11 @@ static int __init check_nmi_watchdog(void)
int cpu;
/* Enable NMI watchdog for newer systems.
- Actually it should be safe for most systems before 2004 too except
- for some IBM systems that corrupt registers when NMI happens
- during SMM. Unfortunately we don't have more exact information
- on these and use this coarse check. */
- if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004)
+ Probably safe on most older systems too, but let's be careful.
+ IBM ThinkPads use INT10 inside SMM and that allows early NMI inside SMM
+ which hangs the system. Disable watchdog for all thinkpads */
+ if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004 &&
+ !dmi_name_in_vendors("ThinkPad"))
nmi_watchdog = NMI_LOCAL_APIC;
if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DEFAULT))
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 8c190ca7ae44..1e1fa3e391a3 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -236,20 +236,28 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
* We execute MONITOR against need_resched and enter optimized wait state
* through MWAIT. Whenever someone changes need_resched, we would be woken
* up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
*/
-static void mwait_idle(void)
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
{
- local_irq_enable();
-
- while (!need_resched()) {
+ if (!need_resched()) {
__monitor((void *)&current_thread_info()->flags, 0, 0);
smp_mb();
- if (need_resched())
- break;
- __mwait(0, 0);
+ if (!need_resched())
+ __mwait(eax, ecx);
}
}
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
+static void mwait_idle(void)
+{
+ local_irq_enable();
+ while (!need_resched())
+ mwait_idle_with_hints(0, 0);
+}
+
void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
{
if (cpu_has(c, X86_FEATURE_MWAIT)) {
@@ -297,9 +305,9 @@ void show_regs(struct pt_regs * regs)
if (user_mode_vm(regs))
printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
printk(" EFLAGS: %08lx %s (%s %.*s)\n",
- regs->eflags, print_tainted(), system_utsname.release,
- (int)strcspn(system_utsname.version, " "),
- system_utsname.version);
+ regs->eflags, print_tainted(), init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
regs->eax,regs->ebx,regs->ecx,regs->edx);
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
@@ -425,13 +433,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
tsk = current;
if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {
- p->thread.io_bitmap_ptr = kmalloc(IO_BITMAP_BYTES, GFP_KERNEL);
+ p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,
+ IO_BITMAP_BYTES, GFP_KERNEL);
if (!p->thread.io_bitmap_ptr) {
p->thread.io_bitmap_max = 0;
return -ENOMEM;
}
- memcpy(p->thread.io_bitmap_ptr, tsk->thread.io_bitmap_ptr,
- IO_BITMAP_BYTES);
set_tsk_thread_flag(p, TIF_IO_BITMAP);
}
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 76a524b4c90f..519e63c3c130 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -209,9 +209,6 @@ static struct resource adapter_rom_resources[] = { {
.flags = IORESOURCE_BUSY | IORESOURCE_READONLY | IORESOURCE_MEM
} };
-#define ADAPTER_ROM_RESOURCES \
- (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
-
static struct resource video_rom_resource = {
.name = "Video ROM",
.start = 0xc0000,
@@ -273,9 +270,6 @@ static struct resource standard_io_resources[] = { {
.flags = IORESOURCE_BUSY | IORESOURCE_IO
} };
-#define STANDARD_IO_RESOURCES \
- (sizeof standard_io_resources / sizeof standard_io_resources[0])
-
#define romsignature(x) (*(unsigned short *)(x) == 0xaa55)
static int __init romchecksum(unsigned char *rom, unsigned long length)
@@ -332,7 +326,7 @@ static void __init probe_roms(void)
}
/* check for adapter roms on 2k boundaries */
- for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
+ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper; start += 2048) {
rom = isa_bus_to_virt(start);
if (!romsignature(rom))
continue;
@@ -1089,22 +1083,19 @@ static unsigned long __init setup_memory(void)
void __init zone_sizes_init(void)
{
- unsigned long zones_size[MAX_NR_ZONES] = { 0, };
- unsigned int max_dma, low;
-
- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
- low = max_low_pfn;
-
- if (low < max_dma)
- zones_size[ZONE_DMA] = low;
- else {
- zones_size[ZONE_DMA] = max_dma;
- zones_size[ZONE_NORMAL] = low - max_dma;
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] =
+ virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = highend_pfn - low;
+ max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
+ add_active_range(0, 0, highend_pfn);
+#else
+ add_active_range(0, 0, max_low_pfn);
#endif
- }
- free_area_init(zones_size);
+
+ free_area_init_nodes(max_zone_pfns);
}
#else
extern unsigned long __init setup_memory(void);
@@ -1274,7 +1265,7 @@ static int __init request_standard_resources(void)
request_resource(&iomem_resource, &video_ram_resource);
/* request I/O space for devices used on all i[345]86 PCs */
- for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
request_resource(&ioport_resource, &standard_io_resources[i]);
return 0;
}
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 465188e2d701..31e5c6573aae 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -321,6 +321,7 @@ static inline void leave_mm (unsigned long cpu)
fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
unsigned long cpu;
cpu = get_cpu();
@@ -351,6 +352,7 @@ fastcall void smp_invalidate_interrupt(struct pt_regs *regs)
smp_mb__after_clear_bit();
out:
put_cpu_no_resched();
+ set_irq_regs(old_regs);
}
static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
@@ -605,11 +607,14 @@ void smp_send_stop(void)
*/
fastcall void smp_reschedule_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
ack_APIC_irq();
+ set_irq_regs(old_regs);
}
fastcall void smp_call_function_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
void (*func) (void *info) = call_data->func;
void *info = call_data->info;
int wait = call_data->wait;
@@ -632,6 +637,7 @@ fastcall void smp_call_function_interrupt(struct pt_regs *regs)
mb();
atomic_inc(&call_data->finished);
}
+ set_irq_regs(old_regs);
}
/*
@@ -700,3 +706,30 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
return 0;
}
EXPORT_SYMBOL(smp_call_function_single);
+
+static int convert_apicid_to_cpu(int apic_id)
+{
+ int i;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (x86_cpu_to_apicid[i] == apic_id)
+ return i;
+ }
+ return -1;
+}
+
+int safe_smp_processor_id(void)
+{
+ int apicid, cpuid;
+
+ if (!boot_cpu_has(X86_FEATURE_APIC))
+ return 0;
+
+ apicid = hard_smp_processor_id();
+ if (apicid == BAD_APICID)
+ return 0;
+
+ cpuid = convert_apicid_to_cpu(apicid);
+
+ return cpuid >= 0 ? cpuid : 0;
+}
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index 020d873b7d21..4bb8b77cd65b 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -102,6 +102,8 @@ u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = 0xff };
EXPORT_SYMBOL(x86_cpu_to_apicid);
+u8 apicid_2_node[MAX_APICID];
+
/*
* Trampoline 80x86 program as an array.
*/
@@ -610,6 +612,7 @@ extern struct {
/* which logical CPUs are on which nodes */
cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly =
{ [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
+EXPORT_SYMBOL(node_2_cpu_mask);
/* which node each logical CPU is on */
int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
EXPORT_SYMBOL(cpu_2_node);
@@ -954,6 +957,7 @@ static int __devinit do_boot_cpu(int apicid, int cpu)
irq_ctx_init(cpu);
+ x86_cpu_to_apicid[cpu] = apicid;
/*
* This grunge runs the startup process for
* the targeted processor.
@@ -1058,7 +1062,7 @@ static void __cpuinit do_warm_boot_cpu(void *p)
static int __cpuinit __smp_prepare_cpu(int cpu)
{
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
struct warm_boot_cpu_info info;
struct work_struct task;
int apicid, ret;
diff --git a/arch/i386/kernel/srat.c b/arch/i386/kernel/srat.c
index 83db411b3aa7..f7e735c077c3 100644
--- a/arch/i386/kernel/srat.c
+++ b/arch/i386/kernel/srat.c
@@ -30,6 +30,7 @@
#include <linux/nodemask.h>
#include <asm/srat.h>
#include <asm/topology.h>
+#include <asm/smp.h>
/*
* proximity macros and definitions
@@ -54,8 +55,7 @@ struct node_memory_chunk_s {
static struct node_memory_chunk_s node_memory_chunk[MAXCHUNKS];
static int num_memory_chunks; /* total number of memory chunks */
-static int zholes_size_init;
-static unsigned long zholes_size[MAX_NUMNODES * MAX_NR_ZONES];
+static u8 __initdata apicid_to_pxm[MAX_APICID];
extern void * boot_ioremap(unsigned long, unsigned long);
@@ -71,6 +71,8 @@ static void __init parse_cpu_affinity_structure(char *p)
/* mark this node as "seen" in node bitmap */
BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain);
+ apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain;
+
printk("CPU 0x%02X in proximity domain 0x%02X\n",
cpu_affinity->apic_id, cpu_affinity->proximity_domain);
}
@@ -135,47 +137,6 @@ static void __init parse_memory_affinity_structure (char *sratp)
"enabled and removable" : "enabled" ) );
}
-/* Take a chunk of pages from page frame cstart to cend and count the number
- * of pages in each zone, returned via zones[].
- */
-static __init void chunk_to_zones(unsigned long cstart, unsigned long cend,
- unsigned long *zones)
-{
- unsigned long max_dma;
- extern unsigned long max_low_pfn;
-
- int z;
- unsigned long rend;
-
- /* FIXME: MAX_DMA_ADDRESS and max_low_pfn are trying to provide
- * similarly scoped information and should be handled in a consistant
- * manner.
- */
- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-
- /* Split the hole into the zones in which it falls. Repeatedly
- * take the segment in which the remaining hole starts, round it
- * to the end of that zone.
- */
- memset(zones, 0, MAX_NR_ZONES * sizeof(long));
- while (cstart < cend) {
- if (cstart < max_dma) {
- z = ZONE_DMA;
- rend = (cend < max_dma)? cend : max_dma;
-
- } else if (cstart < max_low_pfn) {
- z = ZONE_NORMAL;
- rend = (cend < max_low_pfn)? cend : max_low_pfn;
-
- } else {
- z = ZONE_HIGHMEM;
- rend = cend;
- }
- zones[z] += rend - cstart;
- cstart = rend;
- }
-}
-
/*
* The SRAT table always lists ascending addresses, so can always
* assume that the first "start" address that you see is the real
@@ -220,7 +181,6 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
memset(pxm_bitmap, 0, sizeof(pxm_bitmap)); /* init proximity domain bitmap */
memset(node_memory_chunk, 0, sizeof(node_memory_chunk));
- memset(zholes_size, 0, sizeof(zholes_size));
num_memory_chunks = 0;
while (p < end) {
@@ -279,11 +239,15 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
printk("Number of logical nodes in system = %d\n", num_online_nodes());
printk("Number of memory chunks in system = %d\n", num_memory_chunks);
+ for (i = 0; i < MAX_APICID; i++)
+ apicid_2_node[i] = pxm_to_node(apicid_to_pxm[i]);
+
for (j = 0; j < num_memory_chunks; j++){
struct node_memory_chunk_s * chunk = &node_memory_chunk[j];
printk("chunk %d nid %d start_pfn %08lx end_pfn %08lx\n",
j, chunk->nid, chunk->start_pfn, chunk->end_pfn);
node_read_chunk(chunk->nid, chunk);
+ add_active_range(chunk->nid, chunk->start_pfn, chunk->end_pfn);
}
for_each_online_node(nid) {
@@ -392,57 +356,7 @@ int __init get_memcfg_from_srat(void)
return acpi20_parse_srat((struct acpi_table_srat *)header);
}
out_err:
+ remove_all_active_ranges();
printk("failed to get NUMA memory information from SRAT table\n");
return 0;
}
-
-/* For each node run the memory list to determine whether there are
- * any memory holes. For each hole determine which ZONE they fall
- * into.
- *
- * NOTE#1: this requires knowledge of the zone boundries and so
- * _cannot_ be performed before those are calculated in setup_memory.
- *
- * NOTE#2: we rely on the fact that the memory chunks are ordered by
- * start pfn number during setup.
- */
-static void __init get_zholes_init(void)
-{
- int nid;
- int c;
- int first;
- unsigned long end = 0;
-
- for_each_online_node(nid) {
- first = 1;
- for (c = 0; c < num_memory_chunks; c++){
- if (node_memory_chunk[c].nid == nid) {
- if (first) {
- end = node_memory_chunk[c].end_pfn;
- first = 0;
-
- } else {
- /* Record any gap between this chunk
- * and the previous chunk on this node
- * against the zones it spans.
- */
- chunk_to_zones(end,
- node_memory_chunk[c].start_pfn,
- &zholes_size[nid * MAX_NR_ZONES]);
- }
- }
- }
- }
-}
-
-unsigned long * __init get_zholes_size(int nid)
-{
- if (!zholes_size_init) {
- zholes_size_init++;
- get_zholes_init();
- }
- if (nid >= MAX_NUMNODES || !node_online(nid))
- printk("%s: nid = %d is invalid/offline. num_online_nodes = %d",
- __FUNCTION__, nid, num_online_nodes());
- return &zholes_size[nid * MAX_NR_ZONES];
-}
diff --git a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
index 8fdb1fb17a5f..4048397f1740 100644
--- a/arch/i386/kernel/sys_i386.c
+++ b/arch/i386/kernel/sys_i386.c
@@ -21,6 +21,7 @@
#include <linux/utsname.h>
#include <asm/uaccess.h>
+#include <asm/unistd.h>
#include <asm/ipc.h>
/*
@@ -210,7 +211,7 @@ asmlinkage int sys_uname(struct old_utsname __user * name)
if (!name)
return -EFAULT;
down_read(&uts_sem);
- err=copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
return err?-EFAULT:0;
}
@@ -226,16 +227,21 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name)
down_read(&uts_sem);
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
- error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
- error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
- error |= __put_user(0,name->release+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
- error |= __put_user(0,name->version+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
- error |= __put_user(0,name->machine+__OLD_UTS_LEN);
+ error = __copy_to_user(&name->sysname, &utsname()->sysname,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->release, &utsname()->release,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->release + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->version, &utsname()->version,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->version + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->machine, &utsname()->machine,
+ __OLD_UTS_LEN);
+ error |= __put_user(0, name->machine + __OLD_UTS_LEN);
up_read(&uts_sem);
@@ -243,3 +249,17 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name)
return error;
}
+
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ long __res;
+ asm volatile ("push %%ebx ; movl %2,%%ebx ; int $0x80 ; pop %%ebx"
+ : "=a" (__res)
+ : "0" (__NR_execve),"ri" (filename),"c" (argv), "d" (envp) : "memory");
+ return __res;
+}
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index 7e639f78b0b9..2697e9210e92 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -318,3 +318,4 @@ ENTRY(sys_call_table)
.long sys_vmsplice
.long sys_move_pages
.long sys_getcpu
+ .long sys_epoll_pwait
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index 86944acfb647..78af572fd17c 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -76,8 +76,6 @@ int pit_latch_buggy; /* extern */
unsigned int cpu_khz; /* Detected as we calibrate the TSC */
EXPORT_SYMBOL(cpu_khz);
-extern unsigned long wall_jiffies;
-
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
@@ -163,7 +161,7 @@ EXPORT_SYMBOL(profile_pc);
* Time Stamp Counter value at the time of the timer interrupt, so that
* we later on can estimate the time of day more exactly.
*/
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
{
/*
* Here we are in the timer irq handler. We just have irqs locally
@@ -190,7 +188,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
#endif
- do_timer_interrupt_hook(regs);
+ do_timer_interrupt_hook();
if (MCA_bus) {
@@ -203,15 +201,15 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
high bit of the PPI port B (0x61). Note that some PS/2s,
notably the 55SX, work fine if this is removed. */
- irq = inb_p( 0x61 ); /* read the current state */
- outb_p( irq|0x80, 0x61 ); /* reset the IRQ */
+ u8 irq_v = inb_p( 0x61 ); /* read the current state */
+ outb_p( irq_v|0x80, 0x61 ); /* reset the IRQ */
}
write_sequnlock(&xtime_lock);
#ifdef CONFIG_X86_LOCAL_APIC
if (using_apic_timer)
- smp_send_timer_broadcast_ipi(regs);
+ smp_send_timer_broadcast_ipi();
#endif
return IRQ_HANDLED;
@@ -329,7 +327,6 @@ static int timer_resume(struct sys_device *dev)
do_settimeofday(&ts);
write_seqlock_irqsave(&xtime_lock, flags);
jiffies_64 += sleep_length;
- wall_jiffies += sleep_length;
write_sequnlock_irqrestore(&xtime_lock, flags);
touch_softlockup_watchdog();
return 0;
diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c
index 6bf14a4e995e..1a2a979cf6a3 100644
--- a/arch/i386/kernel/time_hpet.c
+++ b/arch/i386/kernel/time_hpet.c
@@ -441,7 +441,7 @@ int hpet_rtc_dropped_irq(void)
return 1;
}
-irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
{
struct rtc_time curr_time;
unsigned long rtc_int_flag = 0;
@@ -480,7 +480,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (call_rtc_interrupt) {
rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
- rtc_interrupt(rtc_int_flag, dev_id, regs);
+ rtc_interrupt(rtc_int_flag, dev_id);
}
return IRQ_HANDLED;
}
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 21aa1cd57773..00489b706d27 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -28,6 +28,7 @@
#include <linux/kprobes.h>
#include <linux/kexec.h>
#include <linux/unwind.h>
+#include <linux/uaccess.h>
#ifdef CONFIG_EISA
#include <linux/ioport.h>
@@ -40,7 +41,6 @@
#include <asm/processor.h>
#include <asm/system.h>
-#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/debugreg.h>
@@ -57,6 +57,8 @@
#include "mach_traps.h"
+int panic_on_unrecovered_nmi;
+
asmlinkage int system_call(void);
struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 },
@@ -355,9 +357,9 @@ void show_registers(struct pt_regs *regs)
KERN_EMERG "EIP: %04x:[<%08lx>] %s VLI\n"
KERN_EMERG "EFLAGS: %08lx (%s %.*s)\n",
smp_processor_id(), 0xffff & regs->xcs, regs->eip,
- print_tainted(), regs->eflags, system_utsname.release,
- (int)strcspn(system_utsname.version, " "),
- system_utsname.version);
+ print_tainted(), regs->eflags, init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip);
printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
regs->eax, regs->ebx, regs->ecx, regs->edx);
@@ -409,7 +411,7 @@ static void handle_BUG(struct pt_regs *regs)
if (eip < PAGE_OFFSET)
return;
- if (__get_user(ud2, (unsigned short __user *)eip))
+ if (probe_kernel_address((unsigned short __user *)eip, ud2))
return;
if (ud2 != 0x0b0f)
return;
@@ -422,7 +424,8 @@ static void handle_BUG(struct pt_regs *regs)
char *file;
char c;
- if (__get_user(line, (unsigned short __user *)(eip + 2)))
+ if (probe_kernel_address((unsigned short __user *)(eip + 2),
+ line))
break;
if (__get_user(file, (char * __user *)(eip + 4)) ||
(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c
index b8fa0a8b2e47..fbc95828cd74 100644
--- a/arch/i386/kernel/tsc.c
+++ b/arch/i386/kernel/tsc.c
@@ -349,8 +349,8 @@ static int tsc_update_callback(void)
int change = 0;
/* check to see if we should switch to the safe clocksource: */
- if (clocksource_tsc.rating != 50 && check_tsc_unstable()) {
- clocksource_tsc.rating = 50;
+ if (clocksource_tsc.rating != 0 && check_tsc_unstable()) {
+ clocksource_tsc.rating = 0;
clocksource_reselect();
change = 1;
}
@@ -461,7 +461,7 @@ static int __init init_tsc_clocksource(void)
clocksource_tsc.shift);
/* lower the rating if we already know its unstable: */
if (check_tsc_unstable())
- clocksource_tsc.rating = 50;
+ clocksource_tsc.rating = 0;
init_timer(&verify_tsc_freq_timer);
verify_tsc_freq_timer.function = verify_tsc_freq;
diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
index 8355d8d87d18..cbcd61d6120b 100644
--- a/arch/i386/kernel/vm86.c
+++ b/arch/i386/kernel/vm86.c
@@ -714,7 +714,7 @@ static int irqbits;
| (1 << SIGUSR1) | (1 << SIGUSR2) | (1 << SIGIO) | (1 << SIGURG) \
| (1 << SIGUNUSED) )
-static irqreturn_t irq_handler(int intno, void *dev_id, struct pt_regs * regs)
+static irqreturn_t irq_handler(int intno, void *dev_id)
{
int irq_bit;
unsigned long flags;
diff --git a/arch/i386/lib/delay.c b/arch/i386/lib/delay.c
index 3c0714c4b669..f6edb11364df 100644
--- a/arch/i386/lib/delay.c
+++ b/arch/i386/lib/delay.c
@@ -11,7 +11,6 @@
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/delay.h>
diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S
index 01f80b5c45d2..c01eb39c0b43 100644
--- a/arch/i386/lib/semaphore.S
+++ b/arch/i386/lib/semaphore.S
@@ -13,7 +13,6 @@
* rw semaphores implemented November 1999 by Benjamin LaHaise <bcrl@kvack.org>
*/
-#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/rwlock.h>
#include <asm/alternative-asm.i>
@@ -153,6 +152,8 @@ ENTRY(__read_lock_failed)
#endif
+#ifdef CONFIG_RWSEM_XCHGADD_ALGORITHM
+
/* Fix up special calling conventions */
ENTRY(call_rwsem_down_read_failed)
CFI_STARTPROC
@@ -215,3 +216,4 @@ ENTRY(call_rwsem_downgrade_wake)
CFI_ENDPROC
END(call_rwsem_downgrade_wake)
+#endif
diff --git a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
index efc7e7d5f4d0..d22cfc9d656c 100644
--- a/arch/i386/lib/usercopy.c
+++ b/arch/i386/lib/usercopy.c
@@ -9,6 +9,7 @@
#include <linux/highmem.h>
#include <linux/blkdev.h>
#include <linux/module.h>
+#include <linux/backing-dev.h>
#include <asm/uaccess.h>
#include <asm/mmx.h>
@@ -179,7 +180,7 @@ __clear_user(void __user *to, unsigned long n)
EXPORT_SYMBOL(__clear_user);
/**
- * strlen_user: - Get the size of a string in user space.
+ * strnlen_user: - Get the size of a string in user space.
* @s: The string to measure.
* @n: The maximum valid length
*
@@ -739,9 +740,9 @@ survive:
retval = get_user_pages(current, current->mm,
(unsigned long )to, 1, 1, 0, &pg, NULL);
- if (retval == -ENOMEM && current->pid == 1) {
+ if (retval == -ENOMEM && is_init(current)) {
up_read(&current->mm->mmap_sem);
- blk_congestion_wait(WRITE, HZ/50);
+ congestion_wait(WRITE, HZ/50);
goto survive;
}
diff --git a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c
index 828522541a88..07097ed48890 100644
--- a/arch/i386/mach-visws/visws_apic.c
+++ b/arch/i386/mach-visws/visws_apic.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/i386/mach_visws/visws_apic.c
+ * linux/arch/i386/mach-visws/visws_apic.c
*
* Copyright (C) 1999 Bent Hagemark, Ingo Molnar
*
@@ -191,7 +191,7 @@ static struct hw_interrupt_type piix4_virtual_irq_type = {
* enable_irq gets the right irq. This 'master' irq is never directly
* manipulated by any driver.
*/
-static irqreturn_t piix4_master_intr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t piix4_master_intr(int irq, void *dev_id)
{
int realirq;
irq_desc_t *desc;
@@ -244,7 +244,7 @@ static irqreturn_t piix4_master_intr(int irq, void *dev_id, struct pt_regs * reg
kstat_cpu(smp_processor_id()).irqs[realirq]++;
if (likely(desc->action != NULL))
- handle_IRQ_event(realirq, regs, desc->action);
+ handle_IRQ_event(realirq, desc->action);
if (!(desc->status & IRQ_DISABLED))
enable_8259A_irq(realirq);
diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c
index 80b7f2fc4f46..8fe7e4593d5f 100644
--- a/arch/i386/mach-voyager/voyager_basic.c
+++ b/arch/i386/mach-voyager/voyager_basic.c
@@ -44,7 +44,7 @@ struct voyager_SUS *voyager_SUS = NULL;
#ifdef CONFIG_SMP
static void
-voyager_dump(int dummy1, struct pt_regs *dummy2, struct tty_struct *dummy3)
+voyager_dump(int dummy1, struct tty_struct *dummy3)
{
/* get here via a sysrq */
voyager_smp_dump();
@@ -87,7 +87,7 @@ voyager_detect(struct voyager_bios_info *bios)
}
void
-voyager_system_interrupt(int cpl, void *dev_id, struct pt_regs *regs)
+voyager_system_interrupt(int cpl, void *dev_id)
{
printk("Voyager: detected system interrupt\n");
}
@@ -166,7 +166,7 @@ voyager_memory_detect(int region, __u32 *start, __u32 *length)
* off the timer tick to the SMP code, since the VIC doesn't have an
* internal timer (The QIC does, but that's another story). */
void
-voyager_timer_interrupt(struct pt_regs *regs)
+voyager_timer_interrupt(void)
{
if((jiffies & 0x3ff) == 0) {
@@ -202,7 +202,7 @@ voyager_timer_interrupt(struct pt_regs *regs)
}
}
#ifdef CONFIG_SMP
- smp_vic_timer_interrupt(regs);
+ smp_vic_timer_interrupt();
#endif
}
diff --git a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
index 6c86575ffdcb..f3fea2ad50fe 100644
--- a/arch/i386/mach-voyager/voyager_smp.c
+++ b/arch/i386/mach-voyager/voyager_smp.c
@@ -85,8 +85,8 @@ static int ack_QIC_CPI(__u8 cpi);
static void ack_special_QIC_CPI(__u8 cpi);
static void ack_VIC_CPI(__u8 cpi);
static void send_CPI_allbutself(__u8 cpi);
-static void enable_vic_irq(unsigned int irq);
-static void disable_vic_irq(unsigned int irq);
+static void mask_vic_irq(unsigned int irq);
+static void unmask_vic_irq(unsigned int irq);
static unsigned int startup_vic_irq(unsigned int irq);
static void enable_local_vic_irq(unsigned int irq);
static void disable_local_vic_irq(unsigned int irq);
@@ -99,6 +99,7 @@ static void do_boot_cpu(__u8 cpuid);
static void do_quad_bootstrap(void);
int hard_smp_processor_id(void);
+int safe_smp_processor_id(void);
/* Inline functions */
static inline void
@@ -125,10 +126,10 @@ send_QIC_CPI(__u32 cpuset, __u8 cpi)
}
static inline void
-wrapper_smp_local_timer_interrupt(struct pt_regs *regs)
+wrapper_smp_local_timer_interrupt(void)
{
irq_enter();
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
irq_exit();
}
@@ -204,15 +205,12 @@ ack_CPI(__u8 cpi)
/* The VIC IRQ descriptors -- these look almost identical to the
* 8259 IRQs except that masks and things must be kept per processor
*/
-static struct hw_interrupt_type vic_irq_type = {
- .typename = "VIC-level",
- .startup = startup_vic_irq,
- .shutdown = disable_vic_irq,
- .enable = enable_vic_irq,
- .disable = disable_vic_irq,
- .ack = before_handle_vic_irq,
- .end = after_handle_vic_irq,
- .set_affinity = set_vic_irq_affinity,
+static struct irq_chip vic_chip = {
+ .name = "VIC",
+ .startup = startup_vic_irq,
+ .mask = mask_vic_irq,
+ .unmask = unmask_vic_irq,
+ .set_affinity = set_vic_irq_affinity,
};
/* used to count up as CPUs are brought on line (starts at 0) */
@@ -785,7 +783,7 @@ fastcall void
smp_vic_sys_interrupt(struct pt_regs *regs)
{
ack_CPI(VIC_SYS_INT);
- printk("Voyager SYSTEM INTERRUPT\n");
+ printk("Voyager SYSTEM INTERRUPT\n");
}
/* Handle a voyager CMN_INT; These interrupts occur either because of
@@ -1134,15 +1132,19 @@ EXPORT_SYMBOL(smp_call_function);
fastcall void
smp_apic_timer_interrupt(struct pt_regs *regs)
{
- wrapper_smp_local_timer_interrupt(regs);
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ wrapper_smp_local_timer_interrupt();
+ set_irq_regs(old_regs);
}
/* All of the QUAD interrupt GATES */
fastcall void
smp_qic_timer_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
ack_QIC_CPI(QIC_TIMER_CPI);
- wrapper_smp_local_timer_interrupt(regs);
+ wrapper_smp_local_timer_interrupt();
+ set_irq_regs(old_regs);
}
fastcall void
@@ -1176,6 +1178,7 @@ smp_qic_call_function_interrupt(struct pt_regs *regs)
fastcall void
smp_vic_cpi_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
__u8 cpu = smp_processor_id();
if(is_cpu_quad())
@@ -1184,7 +1187,7 @@ smp_vic_cpi_interrupt(struct pt_regs *regs)
ack_VIC_CPI(VIC_CPI_LEVEL0);
if(test_and_clear_bit(VIC_TIMER_CPI, &vic_cpi_mailbox[cpu]))
- wrapper_smp_local_timer_interrupt(regs);
+ wrapper_smp_local_timer_interrupt();
if(test_and_clear_bit(VIC_INVALIDATE_CPI, &vic_cpi_mailbox[cpu]))
smp_invalidate_interrupt();
if(test_and_clear_bit(VIC_RESCHEDULE_CPI, &vic_cpi_mailbox[cpu]))
@@ -1193,6 +1196,7 @@ smp_vic_cpi_interrupt(struct pt_regs *regs)
smp_enable_irq_interrupt();
if(test_and_clear_bit(VIC_CALL_FUNCTION_CPI, &vic_cpi_mailbox[cpu]))
smp_call_function_interrupt();
+ set_irq_regs(old_regs);
}
static void
@@ -1247,6 +1251,12 @@ hard_smp_processor_id(void)
return 0;
}
+int
+safe_smp_processor_id(void)
+{
+ return hard_smp_processor_id();
+}
+
/* broadcast a halt to all other CPUs */
void
smp_send_stop(void)
@@ -1257,10 +1267,10 @@ smp_send_stop(void)
/* this function is triggered in time.c when a clock tick fires
* we need to re-broadcast the tick to all CPUs */
void
-smp_vic_timer_interrupt(struct pt_regs *regs)
+smp_vic_timer_interrupt(void)
{
send_CPI_allbutself(VIC_TIMER_CPI);
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
}
/* local (per CPU) timer interrupt. It does both profiling and
@@ -1272,12 +1282,12 @@ smp_vic_timer_interrupt(struct pt_regs *regs)
* value into /proc/profile.
*/
void
-smp_local_timer_interrupt(struct pt_regs * regs)
+smp_local_timer_interrupt(void)
{
int cpu = smp_processor_id();
long weight;
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
if (--per_cpu(prof_counter, cpu) <= 0) {
/*
* The multiplier may have changed since the last time we got
@@ -1295,7 +1305,7 @@ smp_local_timer_interrupt(struct pt_regs * regs)
per_cpu(prof_counter, cpu);
}
- update_process_times(user_mode_vm(regs));
+ update_process_times(user_mode_vm(get_irq_regs()));
}
if( ((1<<cpu) & voyager_extended_vic_processors) == 0)
@@ -1382,6 +1392,17 @@ setup_profiling_timer(unsigned int multiplier)
return 0;
}
+/* This is a bit of a mess, but forced on us by the genirq changes
+ * there's no genirq handler that really does what voyager wants
+ * so hack it up with the simple IRQ handler */
+static void fastcall
+handle_vic_irq(unsigned int irq, struct irq_desc *desc)
+{
+ before_handle_vic_irq(irq);
+ handle_simple_irq(irq, desc);
+ after_handle_vic_irq(irq);
+}
+
/* The CPIs are handled in the per cpu 8259s, so they must be
* enabled to be received: FIX: enabling the CPIs in the early
@@ -1418,7 +1439,7 @@ smp_intr_init(void)
* This is for later: first 16 correspond to PC IRQs; next 16
* are Primary MC IRQs and final 16 are Secondary MC IRQs */
for(i = 0; i < 48; i++)
- irq_desc[i].chip = &vic_irq_type;
+ set_irq_chip_and_handler(i, &vic_chip, handle_vic_irq);
}
/* send a CPI at level cpi to a set of cpus in cpuset (set 1 bit per
@@ -1516,7 +1537,7 @@ ack_VIC_CPI(__u8 cpi)
static unsigned int
startup_vic_irq(unsigned int irq)
{
- enable_vic_irq(irq);
+ unmask_vic_irq(irq);
return 0;
}
@@ -1543,7 +1564,7 @@ startup_vic_irq(unsigned int irq)
* adjust their masks accordingly. */
static void
-enable_vic_irq(unsigned int irq)
+unmask_vic_irq(unsigned int irq)
{
/* linux doesn't to processor-irq affinity, so enable on
* all CPUs we know about */
@@ -1552,7 +1573,7 @@ enable_vic_irq(unsigned int irq)
__u32 processorList = 0;
unsigned long flags;
- VDEBUG(("VOYAGER: enable_vic_irq(%d) CPU%d affinity 0x%lx\n",
+ VDEBUG(("VOYAGER: unmask_vic_irq(%d) CPU%d affinity 0x%lx\n",
irq, cpu, cpu_irq_affinity[cpu]));
spin_lock_irqsave(&vic_irq_lock, flags);
for_each_online_cpu(real_cpu) {
@@ -1576,7 +1597,7 @@ enable_vic_irq(unsigned int irq)
}
static void
-disable_vic_irq(unsigned int irq)
+mask_vic_irq(unsigned int irq)
{
/* lazy disable, do nothing */
}
@@ -1804,7 +1825,7 @@ set_vic_irq_affinity(unsigned int irq, cpumask_t mask)
* disabled again as it comes in (voyager lazy disable). If
* the affinity map is tightened to disable the interrupt on a
* cpu, it will be pushed off when it comes in */
- enable_vic_irq(irq);
+ unmask_vic_irq(irq);
}
static void
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
index 941d1a5ebabb..ddbdb0336f28 100644
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -153,23 +153,7 @@ static void __init find_max_pfn_node(int nid)
*/
if (node_start_pfn[nid] > max_pfn)
node_start_pfn[nid] = max_pfn;
- if (node_start_pfn[nid] > node_end_pfn[nid])
- BUG();
-}
-
-/* Find the owning node for a pfn. */
-int early_pfn_to_nid(unsigned long pfn)
-{
- int nid;
-
- for_each_node(nid) {
- if (node_end_pfn[nid] == 0)
- break;
- if (node_start_pfn[nid] <= pfn && node_end_pfn[nid] >= pfn)
- return nid;
- }
-
- return 0;
+ BUG_ON(node_start_pfn[nid] > node_end_pfn[nid]);
}
/*
@@ -227,6 +211,8 @@ static unsigned long calculate_numa_remap_pages(void)
unsigned long pfn;
for_each_online_node(nid) {
+ unsigned old_end_pfn = node_end_pfn[nid];
+
/*
* The acpi/srat node info can show hot-add memroy zones
* where memory could be added but not currently present.
@@ -276,6 +262,7 @@ static unsigned long calculate_numa_remap_pages(void)
node_end_pfn[nid] -= size;
node_remap_start_pfn[nid] = node_end_pfn[nid];
+ shrink_active_range(nid, old_end_pfn, node_end_pfn[nid]);
}
printk("Reserving total of %ld pages for numa KVA remap\n",
reserve_pages);
@@ -369,45 +356,23 @@ void __init numa_kva_reserve(void)
void __init zone_sizes_init(void)
{
int nid;
-
-
- for_each_online_node(nid) {
- unsigned long zones_size[MAX_NR_ZONES] = {0, };
- unsigned long *zholes_size;
- unsigned int max_dma;
-
- unsigned long low = max_low_pfn;
- unsigned long start = node_start_pfn[nid];
- unsigned long high = node_end_pfn[nid];
-
- max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-
- if (node_has_online_mem(nid)){
- if (start > low) {
-#ifdef CONFIG_HIGHMEM
- BUG_ON(start > high);
- zones_size[ZONE_HIGHMEM] = high - start;
-#endif
- } else {
- if (low < max_dma)
- zones_size[ZONE_DMA] = low;
- else {
- BUG_ON(max_dma > low);
- BUG_ON(low > high);
- zones_size[ZONE_DMA] = max_dma;
- zones_size[ZONE_NORMAL] = low - max_dma;
-#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = high - low;
-#endif
- }
- }
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] =
+ virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ max_zone_pfns[ZONE_HIGHMEM] = highend_pfn;
+
+ /* If SRAT has not registered memory, register it now */
+ if (find_max_pfn_with_active_regions() == 0) {
+ for_each_online_node(nid) {
+ if (node_has_online_mem(nid))
+ add_active_range(nid, node_start_pfn[nid],
+ node_end_pfn[nid]);
}
-
- zholes_size = get_zholes_size(nid);
-
- free_area_init_node(nid, NODE_DATA(nid), zones_size, start,
- zholes_size);
}
+
+ free_area_init_nodes(max_zone_pfns);
return;
}
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index 5e17a3f43b41..2581575786c1 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -440,7 +440,7 @@ good_area:
case 1: /* read, present */
goto bad_area;
case 0: /* read, not present */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
}
@@ -589,7 +589,7 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (tsk->pid == 1) {
+ if (is_init(tsk)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c
index ba44000b9069..f9f647cdbc7b 100644
--- a/arch/i386/mm/highmem.c
+++ b/arch/i386/mm/highmem.c
@@ -38,22 +38,19 @@ void *kmap_atomic(struct page *page, enum km_type type)
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-#ifdef CONFIG_DEBUG_HIGHMEM
if (!pte_none(*(kmap_pte-idx)))
BUG();
-#endif
set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
- __flush_tlb_one(vaddr);
return (void*) vaddr;
}
void kunmap_atomic(void *kvaddr, enum km_type type)
{
-#ifdef CONFIG_DEBUG_HIGHMEM
unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
+#ifdef CONFIG_DEBUG_HIGHMEM
if (vaddr >= PAGE_OFFSET && vaddr < (unsigned long)high_memory) {
dec_preempt_count();
preempt_check_resched();
@@ -62,14 +59,14 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
if (vaddr != __fix_to_virt(FIX_KMAP_BEGIN+idx))
BUG();
-
+#endif
/*
- * force other mappings to Oops if they'll try to access
- * this pte without first remap it
+ * Force other mappings to Oops if they'll try to access this pte
+ * without first remap it. Keeping stale mappings around is a bad idea
+ * also, in case the page changes cacheability attributes or becomes
+ * a protected page in a hypervisor.
*/
- pte_clear(&init_mm, vaddr, kmap_pte-idx);
- __flush_tlb_one(vaddr);
-#endif
+ kpte_clear_flush(kmap_pte-idx, vaddr);
dec_preempt_count();
preempt_check_resched();
@@ -88,7 +85,6 @@ void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
idx = type + KM_TYPE_NR*smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot));
- __flush_tlb_one(vaddr);
return (void*) vaddr;
}
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 4a5a914b3432..167416155ee4 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -493,6 +493,7 @@ int __init set_kernel_exec(unsigned long vaddr, int enable)
pte->pte_high &= ~(1 << (_PAGE_BIT_NX - 32));
else
pte->pte_high |= 1 << (_PAGE_BIT_NX - 32);
+ pte_update_defer(&init_mm, vaddr, pte);
__flush_tlb_all();
out:
return ret;
@@ -568,8 +569,7 @@ void __init mem_init(void)
int bad_ppro;
#ifdef CONFIG_FLATMEM
- if (!mem_map)
- BUG();
+ BUG_ON(!mem_map);
#endif
bad_ppro = ppro_with_ram_bug();
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
index 247fde76aaed..fff08ae7b5ed 100644
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/fixmap.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
@@ -21,82 +21,6 @@
#define ISA_START_ADDRESS 0xa0000
#define ISA_END_ADDRESS 0x100000
-static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
- unsigned long end, unsigned long phys_addr, unsigned long flags)
-{
- pte_t *pte;
- unsigned long pfn;
-
- pfn = phys_addr >> PAGE_SHIFT;
- pte = pte_alloc_kernel(pmd, addr);
- if (!pte)
- return -ENOMEM;
- do {
- BUG_ON(!pte_none(*pte));
- set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW |
- _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
- pfn++;
- } while (pte++, addr += PAGE_SIZE, addr != end);
- return 0;
-}
-
-static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
- unsigned long end, unsigned long phys_addr, unsigned long flags)
-{
- pmd_t *pmd;
- unsigned long next;
-
- phys_addr -= addr;
- pmd = pmd_alloc(&init_mm, pud, addr);
- if (!pmd)
- return -ENOMEM;
- do {
- next = pmd_addr_end(addr, end);
- if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, flags))
- return -ENOMEM;
- } while (pmd++, addr = next, addr != end);
- return 0;
-}
-
-static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
- unsigned long end, unsigned long phys_addr, unsigned long flags)
-{
- pud_t *pud;
- unsigned long next;
-
- phys_addr -= addr;
- pud = pud_alloc(&init_mm, pgd, addr);
- if (!pud)
- return -ENOMEM;
- do {
- next = pud_addr_end(addr, end);
- if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, flags))
- return -ENOMEM;
- } while (pud++, addr = next, addr != end);
- return 0;
-}
-
-static int ioremap_page_range(unsigned long addr,
- unsigned long end, unsigned long phys_addr, unsigned long flags)
-{
- pgd_t *pgd;
- unsigned long next;
- int err;
-
- BUG_ON(addr >= end);
- flush_cache_all();
- phys_addr -= addr;
- pgd = pgd_offset_k(addr);
- do {
- next = pgd_addr_end(addr, end);
- err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, flags);
- if (err)
- break;
- } while (pgd++, addr = next, addr != end);
- flush_tlb_all();
- return err;
-}
-
/*
* Generic mapping function (not visible outside):
*/
@@ -115,6 +39,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
void __iomem * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
+ pgprot_t prot;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
@@ -142,6 +67,9 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
return NULL;
}
+ prot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY
+ | _PAGE_ACCESSED | flags);
+
/*
* Mappings have to be page-aligned
*/
@@ -158,7 +86,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
area->phys_addr = phys_addr;
addr = (void __iomem *) area->addr;
if (ioremap_page_range((unsigned long) addr,
- (unsigned long) addr + size, phys_addr, flags)) {
+ (unsigned long) addr + size, phys_addr, prot)) {
vunmap((void __force *) addr);
return NULL;
}
diff --git a/arch/i386/oprofile/op_model_ppro.c b/arch/i386/oprofile/op_model_ppro.c
index f88e05ba8eb3..ca2447e05e15 100644
--- a/arch/i386/oprofile/op_model_ppro.c
+++ b/arch/i386/oprofile/op_model_ppro.c
@@ -138,11 +138,14 @@ static int ppro_check_ctrs(struct pt_regs * const regs,
static void ppro_start(struct op_msrs const * const msrs)
{
unsigned int low,high;
+ int i;
- if (reset_value[0]) {
- CTRL_READ(low, high, msrs, 0);
- CTRL_SET_ACTIVE(low);
- CTRL_WRITE(low, high, msrs, 0);
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ if (reset_value[i]) {
+ CTRL_READ(low, high, msrs, i);
+ CTRL_SET_ACTIVE(low);
+ CTRL_WRITE(low, high, msrs, i);
+ }
}
}
@@ -150,11 +153,14 @@ static void ppro_start(struct op_msrs const * const msrs)
static void ppro_stop(struct op_msrs const * const msrs)
{
unsigned int low,high;
+ int i;
- if (reset_value[0]) {
- CTRL_READ(low, high, msrs, 0);
+ for (i = 0; i < NUM_COUNTERS; ++i) {
+ if (!reset_value[i])
+ continue;
+ CTRL_READ(low, high, msrs, i);
CTRL_SET_INACTIVE(low);
- CTRL_WRITE(low, high, msrs, 0);
+ CTRL_WRITE(low, high, msrs, i);
}
}
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index 68bce194e688..6d5ace845e44 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -20,6 +20,7 @@
unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
PCI_PROBE_MMCONF;
+int pci_bf_sort;
int pci_routeirq;
int pcibios_last_bus = -1;
unsigned long pirq_table_addr;
@@ -118,6 +119,20 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b)
}
/*
+ * Only use DMI information to set this if nothing was passed
+ * on the kernel command line (which was parsed earlier).
+ */
+
+static int __devinit set_bf_sort(struct dmi_system_id *d)
+{
+ if (pci_bf_sort == pci_bf_sort_default) {
+ pci_bf_sort = pci_dmi_bf;
+ printk(KERN_INFO "PCI: %s detected, enabling pci=bfsort.\n", d->ident);
+ }
+ return 0;
+}
+
+/*
* Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
*/
#ifdef __i386__
@@ -130,11 +145,11 @@ static int __devinit assign_all_busses(struct dmi_system_id *d)
}
#endif
+static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
+#ifdef __i386__
/*
* Laptops which need pci=assign-busses to see Cardbus cards
*/
-static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
-#ifdef __i386__
{
.callback = assign_all_busses,
.ident = "Samsung X20 Laptop",
@@ -144,6 +159,38 @@ static struct dmi_system_id __devinitdata pciprobe_dmi_table[] = {
},
},
#endif /* __i386__ */
+ {
+ .callback = set_bf_sort,
+ .ident = "Dell PowerEdge 1950",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1950"),
+ },
+ },
+ {
+ .callback = set_bf_sort,
+ .ident = "Dell PowerEdge 1955",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1955"),
+ },
+ },
+ {
+ .callback = set_bf_sort,
+ .ident = "Dell PowerEdge 2900",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2900"),
+ },
+ },
+ {
+ .callback = set_bf_sort,
+ .ident = "Dell PowerEdge 2950",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 2950"),
+ },
+ },
{}
};
@@ -189,6 +236,8 @@ static int __init pcibios_init(void)
pcibios_resource_survey();
+ if (pci_bf_sort >= pci_force_bf)
+ pci_sort_breadthfirst();
#ifdef CONFIG_PCI_BIOS
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
@@ -203,6 +252,12 @@ char * __devinit pcibios_setup(char *str)
if (!strcmp(str, "off")) {
pci_probe = 0;
return NULL;
+ } else if (!strcmp(str, "bfsort")) {
+ pci_bf_sort = pci_force_bf;
+ return NULL;
+ } else if (!strcmp(str, "nobfsort")) {
+ pci_bf_sort = pci_force_nobf;
+ return NULL;
}
#ifdef CONFIG_PCI_BIOS
else if (!strcmp(str, "bios")) {
diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
index 5acf0b4743cf..431c9a51b157 100644
--- a/arch/i386/pci/direct.c
+++ b/arch/i386/pci/direct.c
@@ -256,6 +256,8 @@ static int __init pci_check_type2(void)
void __init pci_direct_init(int type)
{
+ if (type == 0)
+ return;
printk(KERN_INFO "PCI: Using configuration type %d\n", type);
if (type == 1)
raw_pci_ops = &pci_direct_conf1;
diff --git a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
index 83c3645ccc43..908b410f4c93 100644
--- a/arch/i386/pci/fixup.c
+++ b/arch/i386/pci/fixup.c
@@ -343,57 +343,12 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC, pcie_ro
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MCH_PC1, pcie_rootport_aspm_quirk );
/*
- * Fixup to mark boot BIOS video selected by BIOS before it changes
- *
- * From information provided by "Jon Smirl" <jonsmirl@gmail.com>
- *
- * The standard boot ROM sequence for an x86 machine uses the BIOS
- * to select an initial video card for boot display. This boot video
- * card will have it's BIOS copied to C0000 in system RAM.
- * IORESOURCE_ROM_SHADOW is used to associate the boot video
- * card with this copy. On laptops this copy has to be used since
- * the main ROM may be compressed or combined with another image.
- * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
- * is marked here since the boot video device will be the only enabled
- * video device at this point.
- */
-
-static void __devinit pci_fixup_video(struct pci_dev *pdev)
-{
- struct pci_dev *bridge;
- struct pci_bus *bus;
- u16 config;
-
- if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
- return;
-
- /* Is VGA routed to us? */
- bus = pdev->bus;
- while (bus) {
- bridge = bus->self;
- if (bridge) {
- pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
- &config);
- if (!(config & PCI_BRIDGE_CTL_VGA))
- return;
- }
- bus = bus->parent;
- }
- pci_read_config_word(pdev, PCI_COMMAND, &config);
- if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
- pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
- printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_video);
-
-/*
* Some Toshiba laptops need extra code to enable their TI TSB43AB22/A.
*
* We pretend to bring them out of full D3 state, and restore the proper
* IRQ, PCI cache line size, and BARs, otherwise the device won't function
* properly. In some cases, the device will generate an interrupt on
- * the wrong IRQ line, causing any devices sharing the the line it's
+ * the wrong IRQ line, causing any devices sharing the line it's
* *supposed* to use to be disabled by the kernel's IRQ debug code.
*/
static u16 toshiba_line_size;
diff --git a/arch/i386/pci/init.c b/arch/i386/pci/init.c
index d028e1b05c36..b21b6da8ab1d 100644
--- a/arch/i386/pci/init.c
+++ b/arch/i386/pci/init.c
@@ -28,6 +28,10 @@ static __init int pci_access_init(void)
#ifdef CONFIG_PCI_DIRECT
pci_direct_init(type);
#endif
+ if (!raw_pci_ops)
+ printk(KERN_ERR
+ "PCI: Fatal: No config space access function found\n");
+
return 0;
}
arch_initcall(pci_access_init);
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 4a8995c9c762..dbc4aae91959 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -981,10 +981,6 @@ static void __init pcibios_fixup_irqs(void)
pci_name(bridge), 'A' + pin, irq);
}
if (irq >= 0) {
- if (use_pci_vector() &&
- !platform_legacy_irq(irq))
- irq = IO_APIC_VECTOR(irq);
-
printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
pci_name(dev), 'A' + pin, irq);
dev->irq = irq;
@@ -1145,10 +1141,6 @@ static int pirq_enable_irq(struct pci_dev *dev)
}
dev = temp_dev;
if (irq >= 0) {
-#ifdef CONFIG_PCI_MSI
- if (!platform_legacy_irq(irq))
- irq = IO_APIC_VECTOR(irq);
-#endif
printk(KERN_INFO "PCI->APIC IRQ transform: %s[%c] -> IRQ %d\n",
pci_name(dev), 'A' + pin, irq);
dev->irq = irq;
@@ -1169,33 +1161,3 @@ static int pirq_enable_irq(struct pci_dev *dev)
}
return 0;
}
-
-int pci_vector_resources(int last, int nr_released)
-{
- int count = nr_released;
-
- int next = last;
- int offset = (last % 8);
-
- while (next < FIRST_SYSTEM_VECTOR) {
- next += 8;
-#ifdef CONFIG_X86_64
- if (next == IA32_SYSCALL_VECTOR)
- continue;
-#else
- if (next == SYSCALL_VECTOR)
- continue;
-#endif
- count++;
- if (next >= FIRST_SYSTEM_VECTOR) {
- if (offset%8) {
- next = FIRST_DEVICE_VECTOR + offset;
- offset++;
- continue;
- }
- count--;
- }
- }
-
- return count;
-}
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index 05be8db58a8c..d0c3da3aa2aa 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -67,7 +67,10 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
return 0;
}
-static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
+/*
+ * This is always called under pci_config_lock
+ */
+static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
{
u32 dev_base = base | (bus << 20) | (devfn << 12);
if (dev_base != mmcfg_last_accessed_device) {
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
index 1814f74569c6..ad065cebd7b9 100644
--- a/arch/i386/pci/pci.h
+++ b/arch/i386/pci/pci.h
@@ -30,6 +30,13 @@
extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
+enum pci_bf_sort_state {
+ pci_bf_sort_default,
+ pci_force_nobf,
+ pci_force_bf,
+ pci_dmi_bf,
+};
+
/* pci-i386.c */
extern unsigned int pcibios_max_latency;
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index f521f2f60a78..70f7eb9fed35 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -356,6 +356,9 @@ config NODES_SHIFT
MAX_NUMNODES will be 2^(This value).
If in doubt, use the default.
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
# VIRTUAL_MEM_MAP and FLAT_NODE_MEM_MAP are functionally equivalent.
# VIRTUAL_MEM_MAP has been retained for historical reasons.
config VIRTUAL_MEM_MAP
@@ -420,6 +423,14 @@ config IA64_PALINFO
config SGI_SN
def_bool y if (IA64_SGI_SN2 || IA64_GENERIC)
+config IA64_ESI
+ bool "ESI (Extensible SAL Interface) support"
+ help
+ If you say Y here, support is built into the kernel to
+ make ESI calls. ESI calls are used to support vendor-specific
+ firmware extensions, such as the ability to inject memory-errors
+ for test-purposes. If you're unsure, say N.
+
source "drivers/sn/Kconfig"
source "drivers/firmware/Kconfig"
@@ -505,7 +516,7 @@ source "arch/ia64/oprofile/Kconfig"
config KPROBES
bool "Kprobes (EXPERIMENTAL)"
- depends on EXPERIMENTAL && MODULES
+ depends on KALLSYMS && EXPERIMENTAL && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
index 0f14a82b856e..64e951de4e57 100644
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -1,8 +1,9 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.17-rc3
-# Thu Apr 27 11:48:23 2006
+# Linux kernel version: 2.6.19-rc1
+# Mon Oct 9 10:53:59 2006
#
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
@@ -18,16 +19,22 @@ CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+CONFIG_TASKSTATS=y
+# CONFIG_TASK_DELAY_ACCT is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_CPUSETS=y
CONFIG_RELAY=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_TASK_XACCT=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -40,6 +47,8 @@ CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -58,6 +67,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -89,7 +99,7 @@ CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_IA64_UNCACHED_ALLOCATOR=y
-CONFIG_DMA_IS_DMA32=y
+CONFIG_AUDIT_ARCH=y
# CONFIG_IA64_GENERIC is not set
# CONFIG_IA64_DIG is not set
# CONFIG_IA64_HP_ZX1 is not set
@@ -116,6 +126,7 @@ CONFIG_FORCE_MAX_ZONEORDER=17
CONFIG_SMP=y
CONFIG_NR_CPUS=1024
# CONFIG_HOTPLUG_CPU is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_SCHED_SMT=y
CONFIG_PREEMPT=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -128,6 +139,7 @@ CONFIG_NEED_MULTIPLE_NODES=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
+CONFIG_RESOURCES_64BIT=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
CONFIG_ARCH_FLATMEM_ENABLE=y
@@ -135,15 +147,24 @@ CONFIG_ARCH_SPARSEMEM_ENABLE=y
CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
CONFIG_NUMA=y
CONFIG_NODES_SHIFT=10
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_VIRTUAL_MEM_MAP=y
CONFIG_HOLES_IN_ZONE=y
CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
+CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
CONFIG_IA32_SUPPORT=y
CONFIG_COMPAT=y
CONFIG_IA64_MCA_RECOVERY=y
CONFIG_PERFMON=y
CONFIG_IA64_PALINFO=y
CONFIG_SGI_SN=y
+# CONFIG_IA64_ESI is not set
+
+#
+# SN Devices
+#
+CONFIG_SGI_IOC4=y
+CONFIG_SGI_IOC3=y
#
# Firmware Drivers
@@ -159,6 +180,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_PM=y
# CONFIG_PM_LEGACY is not set
# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
#
# ACPI (Advanced Configuration and Power Interface) Support
@@ -166,6 +188,7 @@ CONFIG_PM=y
CONFIG_ACPI=y
# CONFIG_ACPI_BUTTON is not set
# CONFIG_ACPI_FAN is not set
+# CONFIG_ACPI_DOCK is not set
# CONFIG_ACPI_PROCESSOR is not set
CONFIG_ACPI_NUMA=y
CONFIG_ACPI_BLACKLIST_YEAR=0
@@ -185,7 +208,12 @@ CONFIG_ACPI_SYSTEM=y
#
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_HOTPLUG_PCI_PCIE=y
+# CONFIG_HOTPLUG_PCI_PCIE_POLL_EVENT_MODE is not set
+CONFIG_PCIEAER=y
# CONFIG_PCI_MSI is not set
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -215,6 +243,9 @@ CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -231,19 +262,31 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=m
CONFIG_INET_TCP_DIAG=m
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_IPV6=m
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -269,7 +312,6 @@ CONFIG_IPV6=m
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -298,6 +340,7 @@ CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
@@ -335,6 +378,7 @@ 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
CONFIG_ATA_OVER_ETH=m
@@ -381,6 +425,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_IT821X is not set
@@ -404,6 +449,7 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -425,12 +471,14 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SAS_ATTRS=y
+CONFIG_SCSI_SAS_LIBSAS=y
+# CONFIG_SCSI_SAS_LIBSAS_DEBUG is not set
#
# SCSI low-level drivers
@@ -443,46 +491,82 @@ CONFIG_ISCSI_TCP=m
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
-# CONFIG_SCSI_SATA_SVW is not set
-# CONFIG_SCSI_ATA_PIIX is not set
-# CONFIG_SCSI_SATA_MV is not set
-# CONFIG_SCSI_SATA_NV is not set
-# CONFIG_SCSI_PDC_ADMA is not set
-# CONFIG_SCSI_SATA_QSTOR is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
-# CONFIG_SCSI_SATA_SX4 is not set
-# CONFIG_SCSI_SATA_SIL is not set
-# CONFIG_SCSI_SATA_SIL24 is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_ULI is not set
-# CONFIG_SCSI_SATA_VIA is not set
-CONFIG_SCSI_SATA_VITESSE=y
+# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
CONFIG_SCSI_QLOGIC_1280=y
CONFIG_SCSI_QLA_FC=y
-CONFIG_SCSI_QLA2XXX_EMBEDDED_FIRMWARE=y
-# CONFIG_SCSI_QLA21XX is not set
-CONFIG_SCSI_QLA22XX=y
-CONFIG_SCSI_QLA2300=y
-CONFIG_SCSI_QLA2322=y
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+CONFIG_SATA_VITESSE=y
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
# Multi-device support (RAID and LVM)
#
CONFIG_MD=y
@@ -491,12 +575,12 @@ CONFIG_MD_LINEAR=y
CONFIG_MD_RAID0=y
CONFIG_MD_RAID1=y
# CONFIG_MD_RAID10 is not set
-CONFIG_MD_RAID5=y
+CONFIG_MD_RAID456=y
# CONFIG_MD_RAID5_RESHAPE is not set
-# CONFIG_MD_RAID6 is not set
CONFIG_MD_MULTIPATH=y
# CONFIG_MD_FAULTY is not set
CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
@@ -563,6 +647,7 @@ CONFIG_NETDEVICES=y
# CONFIG_SK98LIN is not set
CONFIG_TIGON3=y
# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -571,6 +656,7 @@ CONFIG_CHELSIO_T1=m
# CONFIG_IXGB is not set
CONFIG_S2IO=m
# CONFIG_S2IO_NAPI is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -612,6 +698,7 @@ CONFIG_NET_POLL_CONTROLLER=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -646,6 +733,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_COMPUTONE is not set
# CONFIG_ROCKETPORT is not set
@@ -659,10 +747,12 @@ CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_N_HDLC is not set
# CONFIG_SPECIALIX is not set
# CONFIG_SX is not set
+# CONFIG_RIO is not set
# CONFIG_STALDRV is not set
CONFIG_SGI_SNSC=y
CONFIG_SGI_TIOCX=y
CONFIG_SGI_MBCS=m
+CONFIG_MSPEC=y
#
# Serial drivers
@@ -701,6 +791,7 @@ CONFIG_EFI_RTC=y
# Ftape, the floppy tape device driver
#
CONFIG_AGP=y
+# CONFIG_AGP_SIS is not set
# CONFIG_AGP_VIA is not set
CONFIG_AGP_SGI_TIOCA=y
# CONFIG_DRM is not set
@@ -730,7 +821,6 @@ CONFIG_MMTIMER=y
#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -741,6 +831,7 @@ CONFIG_MMTIMER=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
@@ -756,6 +847,7 @@ CONFIG_MMTIMER=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
@@ -764,6 +856,7 @@ CONFIG_MMTIMER=y
CONFIG_VGA_CONSOLE=y
# CONFIG_VGACON_SOFT_SCROLLBACK is not set
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -794,6 +887,7 @@ CONFIG_USB=m
CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=m
# CONFIG_USB_OHCI_BIG_ENDIAN is not set
@@ -843,6 +937,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_ATI_REMOTE2 is not set
# CONFIG_USB_KEYSPAN_REMOTE is not set
# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
#
# USB Imaging devices
@@ -874,15 +969,18 @@ CONFIG_USB_MON=y
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
@@ -919,18 +1017,15 @@ CONFIG_USB_MON=y
CONFIG_INFINIBAND=m
# CONFIG_INFINIBAND_USER_MAD is not set
CONFIG_INFINIBAND_USER_ACCESS=m
+CONFIG_INFINIBAND_ADDR_TRANS=y
CONFIG_INFINIBAND_MTHCA=m
CONFIG_INFINIBAND_MTHCA_DEBUG=y
+# CONFIG_INFINIBAND_AMSO1100 is not set
CONFIG_INFINIBAND_IPOIB=m
CONFIG_INFINIBAND_IPOIB_DEBUG=y
# CONFIG_INFINIBAND_IPOIB_DEBUG_DATA is not set
CONFIG_INFINIBAND_SRP=m
-
-#
-# SN Devices
-#
-CONFIG_SGI_IOC4=y
-CONFIG_SGI_IOC3=y
+# CONFIG_INFINIBAND_ISER is not set
#
# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -942,6 +1037,19 @@ CONFIG_SGI_IOC3=y
# CONFIG_RTC_CLASS is not set
#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
@@ -965,15 +1073,16 @@ CONFIG_REISERFS_FS_SECURITY=y
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
CONFIG_XFS_FS=y
-CONFIG_XFS_EXPORT=y
CONFIG_XFS_QUOTA=y
# CONFIG_XFS_SECURITY is not set
CONFIG_XFS_POSIX_ACL=y
CONFIG_XFS_RT=y
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
CONFIG_QUOTA=y
# CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set
@@ -1007,8 +1116,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
@@ -1046,7 +1157,7 @@ CONFIG_NFSD_V4=y
CONFIG_NFSD_TCP=y
CONFIG_LOCKD=m
CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
+CONFIG_EXPORTFS=m
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=m
CONFIG_SUNRPC_GSS=m
@@ -1056,7 +1167,9 @@ CONFIG_SMB_FS=m
# CONFIG_SMB_NLS_DEFAULT is not set
CONFIG_CIFS=m
# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_CIFS_EXPERIMENTAL is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
@@ -1129,6 +1242,10 @@ CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_UTF8=y
#
+# Distributed Lock Manager
+#
+
+#
# Library routines
#
# CONFIG_CRC_CCITT is not set
@@ -1138,9 +1255,11 @@ CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=m
CONFIG_ZLIB_DEFLATE=m
CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_PLIST=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_IRQ_PER_CPU=y
#
# Instrumentation Support
@@ -1152,20 +1271,26 @@ CONFIG_GENERIC_PENDING_IRQ=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=20
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_PREEMPT=y
-# CONFIG_DEBUG_MUTEXES 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 is not set
+# CONFIG_DEBUG_RWSEMS is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_IA64_GRANULE_16MB=y
@@ -1186,6 +1311,10 @@ CONFIG_SYSVIPC_COMPAT=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -1195,6 +1324,8 @@ CONFIG_CRYPTO_SHA1=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index b5195be62818..424e9257c9a0 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -54,7 +54,7 @@ static int simeth_close(struct net_device *dev);
static int simeth_tx(struct sk_buff *skb, struct net_device *dev);
static int simeth_rx(struct net_device *dev);
static struct net_device_stats *simeth_get_stats(struct net_device *dev);
-static irqreturn_t simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t simeth_interrupt(int irq, void *dev_id);
static void set_multicast_list(struct net_device *dev);
static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr);
@@ -87,7 +87,7 @@ static int simeth_debug; /* set to 1 to get debug information */
*/
static struct notifier_block simeth_dev_notifier = {
simeth_device_event,
- 0
+ NULL
};
@@ -320,7 +320,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
}
printk(KERN_INFO "simeth_device_event: %s ipaddr=0x%x\n",
- dev->name, htonl(ifa->ifa_local));
+ dev->name, ntohl(ifa->ifa_local));
/*
* XXX Fix me
@@ -331,7 +331,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr)
local = dev->priv;
/* now do it for real */
r = event == NETDEV_UP ?
- netdev_attach(local->simfd, dev->irq, htonl(ifa->ifa_local)):
+ netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)):
netdev_detach(local->simfd);
printk(KERN_INFO "simeth: netdev_attach/detach: event=%s ->%d\n",
@@ -497,7 +497,7 @@ simeth_rx(struct net_device *dev)
* Interrupt handler (Yes, we can do it too !!!)
*/
static irqreturn_t
-simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+simeth_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
index 8f0a16a79a67..bb87682bbb1b 100644
--- a/arch/ia64/hp/sim/simscsi.c
+++ b/arch/ia64/hp/sim/simscsi.c
@@ -103,7 +103,7 @@ simscsi_interrupt (unsigned long val)
while ((sc = queue[rd].sc) != 0) {
atomic_dec(&num_reqs);
- queue[rd].sc = 0;
+ queue[rd].sc = NULL;
if (DBG)
printk("simscsi_interrupt: done with %ld\n", sc->serial_number);
(*sc->scsi_done)(sc);
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 0daacc20ed36..caab986af70c 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -92,7 +92,7 @@ static struct serial_uart_config uart_config[] = {
{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
UART_STARTECH },
{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
- { 0, 0}
+ { NULL, 0}
};
struct tty_driver *hp_simserial_driver;
@@ -130,7 +130,7 @@ static void rs_start(struct tty_struct *tty)
#endif
}
-static void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
+static void receive_chars(struct tty_struct *tty)
{
unsigned char ch;
static unsigned char seen_esc = 0;
@@ -152,7 +152,7 @@ static void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
ch = ia64_ssc(0, 0, 0, 0,
SSC_GETCHAR);
while (!ch);
- handle_sysrq(ch, regs, NULL);
+ handle_sysrq(ch, NULL);
}
#endif
seen_esc = 0;
@@ -170,7 +170,7 @@ static void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
/*
* This is the serial driver's interrupt routine for a single port
*/
-static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{
struct async_struct * info;
@@ -187,7 +187,7 @@ static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * r
* pretty simple in our case, because we only get interrupts
* on inbound traffic
*/
- receive_chars(info->tty, regs);
+ receive_chars(info->tty);
return IRQ_HANDLED;
}
@@ -555,7 +555,7 @@ static void shutdown(struct async_struct * info)
if (info->xmit.buf) {
free_page((unsigned long) info->xmit.buf);
- info->xmit.buf = 0;
+ info->xmit.buf = NULL;
}
if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -628,7 +628,7 @@ static void rs_close(struct tty_struct *tty, struct file * filp)
if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty);
if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty);
info->event = 0;
- info->tty = 0;
+ info->tty = NULL;
if (info->blocked_open) {
if (info->close_delay)
schedule_timeout_interruptible(info->close_delay);
@@ -668,7 +668,7 @@ static void rs_hangup(struct tty_struct *tty)
info->event = 0;
state->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
- info->tty = 0;
+ info->tty = NULL;
wake_up_interruptible(&info->open_wait);
}
@@ -714,7 +714,7 @@ startup(struct async_struct *info)
{
unsigned long flags;
int retval=0;
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
+ irq_handler_t handler;
struct serial_state *state= info->state;
unsigned long page;
@@ -769,7 +769,7 @@ startup(struct async_struct *info)
/*
* Insert serial port into IRQ chain.
*/
- info->prev_port = 0;
+ info->prev_port = NULL;
info->next_port = IRQ_ports[state->irq];
if (info->next_port)
info->next_port->prev_port = info;
@@ -940,7 +940,7 @@ static inline void show_serial_version(void)
printk(KERN_INFO " no serial options enabled\n");
}
-static struct tty_operations hp_ops = {
+static const struct tty_operations hp_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index 6aa3c51619ca..9d6a3f210148 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -125,6 +125,7 @@ sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __use
int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
{
+ compat_ino_t ino;
int err;
if ((u64) stat->size > MAX_NON_LFS ||
@@ -132,11 +133,15 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
!old_valid_dev(stat->rdev))
return -EOVERFLOW;
+ ino = stat->ino;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
if (clear_user(ubuf, sizeof(*ubuf)))
return -EFAULT;
err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
- err |= __put_user(stat->ino, &ubuf->st_ino);
+ err |= __put_user(ino, &ubuf->st_ino);
err |= __put_user(stat->mode, &ubuf->st_mode);
err |= __put_user(stat->nlink, &ubuf->st_nlink);
err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid);
@@ -1222,16 +1227,20 @@ struct readdir32_callback {
};
static int
-filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
+filldir32 (void *__buf, const char *name, int namlen, loff_t offset, u64 ino,
unsigned int d_type)
{
struct compat_dirent __user * dirent;
struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4);
+ u32 d_ino;
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
buf->error = -EFAULT; /* only used if we fail.. */
dirent = buf->previous;
if (dirent)
@@ -1239,7 +1248,7 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
return -EFAULT;
dirent = buf->current_dir;
buf->previous = dirent;
- if (put_user(ino, &dirent->d_ino)
+ if (put_user(d_ino, &dirent->d_ino)
|| put_user(reclen, &dirent->d_reclen)
|| copy_to_user(dirent->d_name, name, namlen)
|| put_user(0, dirent->d_name + namlen))
@@ -1287,17 +1296,21 @@ out:
}
static int
-fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
+fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, u64 ino,
unsigned int d_type)
{
struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
struct old_linux32_dirent __user * dirent;
+ u32 d_ino;
if (buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
buf->count++;
dirent = buf->dirent;
- if (put_user(ino, &dirent->d_ino)
+ if (put_user(d_ino, &dirent->d_ino)
|| put_user(offset, &dirent->d_offset)
|| put_user(namlen, &dirent->d_namlen)
|| copy_to_user(dirent->d_name, name, namlen)
@@ -1942,7 +1955,7 @@ struct sysctl32 {
unsigned int __unused[4];
};
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL_SYSCALL
asmlinkage long
sys32_sysctl (struct sysctl32 __user *args)
{
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index ad8215a3c586..cfa099b04cda 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -30,8 +30,14 @@ obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o
obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
obj-$(CONFIG_AUDIT) += audit.o
+obj-$(CONFIG_PCI_MSI) += msi_ia64.o
mca_recovery-y += mca_drv.o mca_drv_asm.o
+obj-$(CONFIG_IA64_ESI) += esi.o
+ifneq ($(CONFIG_IA64_ESI),)
+obj-y += esi_stub.o # must be in kernel proper
+endif
+
# The gate DSO image is built using a special linker script.
targets += gate.so gate-syms.o
diff --git a/arch/ia64/kernel/acpi-processor.c b/arch/ia64/kernel/acpi-processor.c
index e683630c8ce2..4d4993a47e55 100644
--- a/arch/ia64/kernel/acpi-processor.c
+++ b/arch/ia64/kernel/acpi-processor.c
@@ -1,5 +1,5 @@
/*
- * arch/ia64/kernel/cpufreq/processor.c
+ * arch/ia64/kernel/acpi-processor.c
*
* Copyright (C) 2005 Intel Corporation
* Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 32c3abededc6..73ef4a85b861 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -64,9 +64,6 @@ EXPORT_SYMBOL(pm_idle);
void (*pm_power_off) (void);
EXPORT_SYMBOL(pm_power_off);
-unsigned char acpi_kbd_controller_present = 1;
-unsigned char acpi_legacy_devices;
-
unsigned int acpi_cpei_override;
unsigned int acpi_cpei_phys_cpuid;
@@ -628,12 +625,6 @@ static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size)
fadt = (struct fadt_descriptor *)fadt_header;
- if (!(fadt->iapc_boot_arch & BAF_8042_KEYBOARD_CONTROLLER))
- acpi_kbd_controller_present = 0;
-
- if (fadt->iapc_boot_arch & BAF_LEGACY_DEVICES)
- acpi_legacy_devices = 1;
-
acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
return 0;
}
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index fef06571be99..3390b7c5a63f 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -1,5 +1,5 @@
/*
- * ia64/kernel/entry.S
+ * arch/ia64/kernel/entry.S
*
* Kernel entry points.
*
@@ -492,11 +492,11 @@ GLOBAL_ENTRY(prefetch_stack)
br.ret.sptk.many rp
END(prefetch_stack)
-GLOBAL_ENTRY(execve)
+GLOBAL_ENTRY(kernel_execve)
mov r15=__NR_execve // put syscall number in place
break __BREAK_SYSCALL
br.ret.sptk.many rp
-END(execve)
+END(kernel_execve)
GLOBAL_ENTRY(clone)
mov r15=__NR_clone // put syscall number in place
@@ -1605,8 +1605,8 @@ sys_call_table:
data8 sys_ni_syscall // 1295 reserved for ppoll
data8 sys_unshare
data8 sys_splice
- data8 sys_ni_syscall // reserved for set_robust_list
- data8 sys_ni_syscall // reserved for get_robust_list
+ data8 sys_set_robust_list
+ data8 sys_get_robust_list
data8 sys_sync_file_range // 1300
data8 sys_tee
data8 sys_vmsplice
diff --git a/arch/ia64/kernel/esi.c b/arch/ia64/kernel/esi.c
new file mode 100644
index 000000000000..ebf4e988e78c
--- /dev/null
+++ b/arch/ia64/kernel/esi.c
@@ -0,0 +1,205 @@
+/*
+ * Extensible SAL Interface (ESI) support routines.
+ *
+ * Copyright (C) 2006 Hewlett-Packard Co
+ * Alex Williamson <alex.williamson@hp.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+
+#include <asm/esi.h>
+#include <asm/sal.h>
+
+MODULE_AUTHOR("Alex Williamson <alex.williamson@hp.com>");
+MODULE_DESCRIPTION("Extensible SAL Interface (ESI) support");
+MODULE_LICENSE("GPL");
+
+#define MODULE_NAME "esi"
+
+#define ESI_TABLE_GUID \
+ EFI_GUID(0x43EA58DC, 0xCF28, 0x4b06, 0xB3, \
+ 0x91, 0xB7, 0x50, 0x59, 0x34, 0x2B, 0xD4)
+
+enum esi_systab_entry_type {
+ ESI_DESC_ENTRY_POINT = 0
+};
+
+/*
+ * Entry type: Size:
+ * 0 48
+ */
+#define ESI_DESC_SIZE(type) "\060"[(unsigned) (type)]
+
+typedef struct ia64_esi_desc_entry_point {
+ u8 type;
+ u8 reserved1[15];
+ u64 esi_proc;
+ u64 gp;
+ efi_guid_t guid;
+} ia64_esi_desc_entry_point_t;
+
+struct pdesc {
+ void *addr;
+ void *gp;
+};
+
+static struct ia64_sal_systab *esi_systab;
+
+static int __init esi_init (void)
+{
+ efi_config_table_t *config_tables;
+ struct ia64_sal_systab *systab;
+ unsigned long esi = 0;
+ char *p;
+ int i;
+
+ config_tables = __va(efi.systab->tables);
+
+ for (i = 0; i < (int) efi.systab->nr_tables; ++i) {
+ if (efi_guidcmp(config_tables[i].guid, ESI_TABLE_GUID) == 0) {
+ esi = config_tables[i].table;
+ break;
+ }
+ }
+
+ if (!esi)
+ return -ENODEV;;
+
+ systab = __va(esi);
+
+ if (strncmp(systab->signature, "ESIT", 4) != 0) {
+ printk(KERN_ERR "bad signature in ESI system table!");
+ return -ENODEV;
+ }
+
+ p = (char *) (systab + 1);
+ for (i = 0; i < systab->entry_count; i++) {
+ /*
+ * The first byte of each entry type contains the type
+ * descriptor.
+ */
+ switch (*p) {
+ case ESI_DESC_ENTRY_POINT:
+ break;
+ default:
+ printk(KERN_WARNING "Unkown table type %d found in "
+ "ESI table, ignoring rest of table\n", *p);
+ return -ENODEV;
+ }
+
+ p += ESI_DESC_SIZE(*p);
+ }
+
+ esi_systab = systab;
+ return 0;
+}
+
+
+int ia64_esi_call (efi_guid_t guid, struct ia64_sal_retval *isrvp,
+ enum esi_proc_type proc_type, u64 func,
+ u64 arg1, u64 arg2, u64 arg3, u64 arg4, u64 arg5, u64 arg6,
+ u64 arg7)
+{
+ struct ia64_fpreg fr[6];
+ unsigned long flags = 0;
+ int i;
+ char *p;
+
+ if (!esi_systab)
+ return -1;
+
+ p = (char *) (esi_systab + 1);
+ for (i = 0; i < esi_systab->entry_count; i++) {
+ if (*p == ESI_DESC_ENTRY_POINT) {
+ ia64_esi_desc_entry_point_t *esi = (void *)p;
+ if (!efi_guidcmp(guid, esi->guid)) {
+ ia64_sal_handler esi_proc;
+ struct pdesc pdesc;
+
+ pdesc.addr = __va(esi->esi_proc);
+ pdesc.gp = __va(esi->gp);
+
+ esi_proc = (ia64_sal_handler) &pdesc;
+
+ ia64_save_scratch_fpregs(fr);
+ if (proc_type == ESI_PROC_SERIALIZED)
+ spin_lock_irqsave(&sal_lock, flags);
+ else if (proc_type == ESI_PROC_MP_SAFE)
+ local_irq_save(flags);
+ else
+ preempt_disable();
+ *isrvp = (*esi_proc)(func, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7);
+ if (proc_type == ESI_PROC_SERIALIZED)
+ spin_unlock_irqrestore(&sal_lock,
+ flags);
+ else if (proc_type == ESI_PROC_MP_SAFE)
+ local_irq_restore(flags);
+ else
+ preempt_enable();
+ ia64_load_scratch_fpregs(fr);
+ return 0;
+ }
+ }
+ p += ESI_DESC_SIZE(*p);
+ }
+ return -1;
+}
+EXPORT_SYMBOL_GPL(ia64_esi_call);
+
+int ia64_esi_call_phys (efi_guid_t guid, struct ia64_sal_retval *isrvp,
+ u64 func, u64 arg1, u64 arg2, u64 arg3, u64 arg4,
+ u64 arg5, u64 arg6, u64 arg7)
+{
+ struct ia64_fpreg fr[6];
+ unsigned long flags;
+ u64 esi_params[8];
+ char *p;
+ int i;
+
+ if (!esi_systab)
+ return -1;
+
+ p = (char *) (esi_systab + 1);
+ for (i = 0; i < esi_systab->entry_count; i++) {
+ if (*p == ESI_DESC_ENTRY_POINT) {
+ ia64_esi_desc_entry_point_t *esi = (void *)p;
+ if (!efi_guidcmp(guid, esi->guid)) {
+ ia64_sal_handler esi_proc;
+ struct pdesc pdesc;
+
+ pdesc.addr = (void *)esi->esi_proc;
+ pdesc.gp = (void *)esi->gp;
+
+ esi_proc = (ia64_sal_handler) &pdesc;
+
+ esi_params[0] = func;
+ esi_params[1] = arg1;
+ esi_params[2] = arg2;
+ esi_params[3] = arg3;
+ esi_params[4] = arg4;
+ esi_params[5] = arg5;
+ esi_params[6] = arg6;
+ esi_params[7] = arg7;
+ ia64_save_scratch_fpregs(fr);
+ spin_lock_irqsave(&sal_lock, flags);
+ *isrvp = esi_call_phys(esi_proc, esi_params);
+ spin_unlock_irqrestore(&sal_lock, flags);
+ ia64_load_scratch_fpregs(fr);
+ return 0;
+ }
+ }
+ p += ESI_DESC_SIZE(*p);
+ }
+ return -1;
+}
+EXPORT_SYMBOL_GPL(ia64_esi_call_phys);
+
+static void __exit esi_exit (void)
+{
+}
+
+module_init(esi_init);
+module_exit(esi_exit); /* makes module removable... */
diff --git a/arch/ia64/kernel/esi_stub.S b/arch/ia64/kernel/esi_stub.S
new file mode 100644
index 000000000000..6b3d6c1f99b6
--- /dev/null
+++ b/arch/ia64/kernel/esi_stub.S
@@ -0,0 +1,96 @@
+/*
+ * ESI call stub.
+ *
+ * Copyright (C) 2005 Hewlett-Packard Co
+ * Alex Williamson <alex.williamson@hp.com>
+ *
+ * Based on EFI call stub by David Mosberger. The stub is virtually
+ * identical to the one for EFI phys-mode calls, except that ESI
+ * calls may have up to 8 arguments, so they get passed to this routine
+ * through memory.
+ *
+ * This stub allows us to make ESI calls in physical mode with interrupts
+ * turned off. ESI calls may not support calling from virtual mode.
+ *
+ * Google for "Extensible SAL specification" for a document describing the
+ * ESI standard.
+ */
+
+/*
+ * PSR settings as per SAL spec (Chapter 8 in the "IA-64 System
+ * Abstraction Layer Specification", revision 2.6e). Note that
+ * psr.dfl and psr.dfh MUST be cleared, despite what this manual says.
+ * Otherwise, SAL dies whenever it's trying to do an IA-32 BIOS call
+ * (the br.ia instruction fails unless psr.dfl and psr.dfh are
+ * cleared). Fortunately, SAL promises not to touch the floating
+ * point regs, so at least we don't have to save f2-f127.
+ */
+#define PSR_BITS_TO_CLEAR \
+ (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT | \
+ IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
+ IA64_PSR_DFL | IA64_PSR_DFH)
+
+#define PSR_BITS_TO_SET \
+ (IA64_PSR_BN)
+
+#include <asm/processor.h>
+#include <asm/asmmacro.h>
+
+/*
+ * Inputs:
+ * in0 = address of function descriptor of ESI routine to call
+ * in1 = address of array of ESI parameters
+ *
+ * Outputs:
+ * r8 = result returned by called function
+ */
+GLOBAL_ENTRY(esi_call_phys)
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(2)
+ alloc loc1=ar.pfs,2,7,8,0
+ ld8 r2=[in0],8 // load ESI function's entry point
+ mov loc0=rp
+ .body
+ ;;
+ ld8 out0=[in1],8 // ESI params loaded from array
+ ;; // passing all as inputs doesn't work
+ ld8 out1=[in1],8
+ ;;
+ ld8 out2=[in1],8
+ ;;
+ ld8 out3=[in1],8
+ ;;
+ ld8 out4=[in1],8
+ ;;
+ ld8 out5=[in1],8
+ ;;
+ ld8 out6=[in1],8
+ ;;
+ ld8 out7=[in1]
+ mov loc2=gp // save global pointer
+ mov loc4=ar.rsc // save RSE configuration
+ mov ar.rsc=0 // put RSE in enforced lazy, LE mode
+ ;;
+ ld8 gp=[in0] // load ESI function's global pointer
+ movl r16=PSR_BITS_TO_CLEAR
+ mov loc3=psr // save processor status word
+ movl r17=PSR_BITS_TO_SET
+ ;;
+ or loc3=loc3,r17
+ mov b6=r2
+ ;;
+ andcm r16=loc3,r16 // get psr with IT, DT, and RT bits cleared
+ br.call.sptk.many rp=ia64_switch_mode_phys
+.ret0: mov loc5=r19 // old ar.bsp
+ mov loc6=r20 // old sp
+ br.call.sptk.many rp=b6 // call the ESI function
+.ret1: mov ar.rsc=0 // put RSE in enforced lazy, LE mode
+ mov r16=loc3 // save virtual mode psr
+ mov r19=loc5 // save virtual mode bspstore
+ mov r20=loc6 // save virtual mode sp
+ br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
+.ret2: mov ar.rsc=loc4 // restore RSE configuration
+ mov ar.pfs=loc1
+ mov rp=loc0
+ mov gp=loc2
+ br.ret.sptk.many rp
+END(esi_call_phys)
diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
index 3ead20fb6f4b..879c1817bd1c 100644
--- a/arch/ia64/kernel/ia64_ksyms.c
+++ b/arch/ia64/kernel/ia64_ksyms.c
@@ -105,5 +105,9 @@ EXPORT_SYMBOL(ia64_spinlock_contention);
# endif
#endif
+#if defined(CONFIG_IA64_ESI) || defined(CONFIG_IA64_ESI_MODULE)
+extern void esi_call_phys (void);
+EXPORT_SYMBOL_GPL(esi_call_phys);
+#endif
extern char ia64_ivt[];
EXPORT_SYMBOL(ia64_ivt);
diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
index 7852382de2fa..f07c0864b0b4 100644
--- a/arch/ia64/kernel/irq.c
+++ b/arch/ia64/kernel/irq.c
@@ -194,8 +194,11 @@ void fixup_irqs(void)
*/
for (irq=0; irq < NR_IRQS; irq++) {
if (vectors_in_migration[irq]) {
+ struct pt_regs *old_regs = set_irq_regs(NULL);
+
vectors_in_migration[irq]=0;
- __do_IRQ(irq, NULL);
+ __do_IRQ(irq);
+ set_irq_regs(old_regs);
}
}
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index a041367f043b..9c6dafa2d0df 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/ia64/kernel/irq.c
+ * linux/arch/ia64/kernel/irq_ia64.c
*
* Copyright (C) 1998-2001 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
@@ -30,6 +30,7 @@
#include <linux/smp_lock.h>
#include <linux/threads.h>
#include <linux/bitops.h>
+#include <linux/irq.h>
#include <asm/delay.h>
#include <asm/intrinsics.h>
@@ -105,6 +106,25 @@ reserve_irq_vector (int vector)
return test_and_set_bit(pos, ia64_vector_mask);
}
+/*
+ * Dynamic irq allocate and deallocation for MSI
+ */
+int create_irq(void)
+{
+ int vector = assign_irq_vector(AUTO_ASSIGN);
+
+ if (vector >= 0)
+ dynamic_irq_init(vector);
+
+ return vector;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ dynamic_irq_cleanup(irq);
+ free_irq_vector(irq);
+}
+
#ifdef CONFIG_SMP
# define IS_RESCHEDULE(vec) (vec == IA64_IPI_RESCHEDULE)
#else
@@ -118,6 +138,7 @@ reserve_irq_vector (int vector)
void
ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
unsigned long saved_tpr;
#if IRQ_DEBUG
@@ -159,11 +180,13 @@ 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 (!IS_RESCHEDULE(vector)) {
+ if (unlikely(IS_RESCHEDULE(vector)))
+ kstat_this_cpu.irqs[vector]++;
+ else {
ia64_setreg(_IA64_REG_CR_TPR, vector);
ia64_srlz_d();
- __do_IRQ(local_vector_to_irq(vector), regs);
+ __do_IRQ(local_vector_to_irq(vector));
/*
* Disable interrupts and send EOI:
@@ -180,6 +203,7 @@ ia64_handle_irq (ia64_vector vector, struct pt_regs *regs)
* come through until ia64_eoi() has been done.
*/
irq_exit();
+ set_irq_regs(old_regs);
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -203,7 +227,11 @@ void ia64_process_pending_intr(void)
* Perform normal interrupt style processing
*/
while (vector != IA64_SPURIOUS_INT_VECTOR) {
- if (!IS_RESCHEDULE(vector)) {
+ if (unlikely(IS_RESCHEDULE(vector)))
+ kstat_this_cpu.irqs[vector]++;
+ else {
+ struct pt_regs *old_regs = set_irq_regs(NULL);
+
ia64_setreg(_IA64_REG_CR_TPR, vector);
ia64_srlz_d();
@@ -214,7 +242,8 @@ void ia64_process_pending_intr(void)
* Probably could shared code.
*/
vectors_in_migration[local_vector_to_irq(vector)]=0;
- __do_IRQ(local_vector_to_irq(vector), NULL);
+ __do_IRQ(local_vector_to_irq(vector));
+ set_irq_regs(old_regs);
/*
* Disable interrupts and send EOI
@@ -231,13 +260,24 @@ void ia64_process_pending_intr(void)
#ifdef CONFIG_SMP
-extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t handle_IPI (int irq, void *dev_id);
+
+static irqreturn_t dummy_handler (int irq, void *dev_id)
+{
+ BUG();
+}
static struct irqaction ipi_irqaction = {
.handler = handle_IPI,
.flags = IRQF_DISABLED,
.name = "IPI"
};
+
+static struct irqaction resched_irqaction = {
+ .handler = dummy_handler,
+ .flags = SA_INTERRUPT,
+ .name = "resched"
+};
#endif
void
@@ -262,6 +302,7 @@ init_IRQ (void)
register_percpu_irq(IA64_SPURIOUS_INT_VECTOR, NULL);
#ifdef CONFIG_SMP
register_percpu_irq(IA64_IPI_VECTOR, &ipi_irqaction);
+ register_percpu_irq(IA64_IPI_RESCHEDULE, &resched_irqaction);
#endif
#ifdef CONFIG_PERFMON
pfm_init_percpu();
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 781960f80b6f..51217d63285e 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -90,7 +90,7 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
p->ainsn.target_br_reg = 0;
/* Check for Break instruction
- * Bits 37:40 Major opcode to be zero
+ * Bits 37:40 Major opcode to be zero
* Bits 27:32 X6 to be zero
* Bits 32:35 X3 to be zero
*/
@@ -104,19 +104,19 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
switch (major_opcode) {
case INDIRECT_CALL_OPCODE:
p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
- p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
- break;
+ p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
+ break;
case IP_RELATIVE_PREDICT_OPCODE:
case IP_RELATIVE_BRANCH_OPCODE:
p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
- break;
+ break;
case IP_RELATIVE_CALL_OPCODE:
- p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
- p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
- p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
- break;
+ p->ainsn.inst_flag |= INST_FLAG_FIX_RELATIVE_IP_ADDR;
+ p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
+ p->ainsn.target_br_reg = ((kprobe_inst >> 6) & 0x7);
+ break;
}
- } else if (bundle_encoding[template][slot] == X) {
+ } else if (bundle_encoding[template][slot] == X) {
switch (major_opcode) {
case LONG_CALL_OPCODE:
p->ainsn.inst_flag |= INST_FLAG_FIX_BRANCH_REG;
@@ -136,10 +136,8 @@ static void __kprobes update_kprobe_inst_flag(uint template, uint slot,
static int __kprobes unsupported_inst(uint template, uint slot,
uint major_opcode,
unsigned long kprobe_inst,
- struct kprobe *p)
+ unsigned long addr)
{
- unsigned long addr = (unsigned long)p->addr;
-
if (bundle_encoding[template][slot] == I) {
switch (major_opcode) {
case 0x0: //I_UNIT_MISC_OPCODE:
@@ -217,7 +215,7 @@ static void __kprobes prepare_break_inst(uint template, uint slot,
struct kprobe *p)
{
unsigned long break_inst = BREAK_INST;
- bundle_t *bundle = &p->ainsn.insn.bundle;
+ bundle_t *bundle = &p->opcode.bundle;
/*
* Copy the original kprobe_inst qualifying predicate(qp)
@@ -260,18 +258,18 @@ static void __kprobes get_kprobe_inst(bundle_t *bundle, uint slot,
switch (slot) {
case 0:
- *major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
- *kprobe_inst = bundle->quad0.slot0;
- break;
+ *major_opcode = (bundle->quad0.slot0 >> SLOT0_OPCODE_SHIFT);
+ *kprobe_inst = bundle->quad0.slot0;
+ break;
case 1:
- *major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
- kprobe_inst_p0 = bundle->quad0.slot1_p0;
- kprobe_inst_p1 = bundle->quad1.slot1_p1;
- *kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46));
+ *major_opcode = (bundle->quad1.slot1_p1 >> SLOT1_p1_OPCODE_SHIFT);
+ kprobe_inst_p0 = bundle->quad0.slot1_p0;
+ kprobe_inst_p1 = bundle->quad1.slot1_p1;
+ *kprobe_inst = kprobe_inst_p0 | (kprobe_inst_p1 << (64-46));
break;
case 2:
- *major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
- *kprobe_inst = bundle->quad1.slot2;
+ *major_opcode = (bundle->quad1.slot2 >> SLOT2_OPCODE_SHIFT);
+ *kprobe_inst = bundle->quad1.slot2;
break;
}
}
@@ -292,11 +290,11 @@ static int __kprobes valid_kprobe_addr(int template, int slot,
return -EINVAL;
}
- if (in_ivt_functions(addr)) {
- printk(KERN_WARNING "Kprobes can't be inserted inside "
+ if (in_ivt_functions(addr)) {
+ printk(KERN_WARNING "Kprobes can't be inserted inside "
"IVT functions at 0x%lx\n", addr);
- return -EINVAL;
- }
+ return -EINVAL;
+ }
if (slot == 1 && bundle_encoding[template][1] != L) {
printk(KERN_WARNING "Inserting kprobes on slot #1 "
@@ -340,12 +338,13 @@ static void kretprobe_trampoline(void)
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
+ struct hlist_head *head, empty_rp;
struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =
((struct fnptr *)kretprobe_trampoline)->ip;
+ INIT_HLIST_HEAD(&empty_rp);
spin_lock_irqsave(&kretprobe_lock, flags);
head = kretprobe_inst_table_head(current);
@@ -371,7 +370,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_rp_inst(ri);
+ recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
@@ -389,6 +388,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
spin_unlock_irqrestore(&kretprobe_lock, flags);
preempt_enable_no_resched();
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
/*
* By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler
@@ -423,37 +426,34 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
unsigned long *kprobe_addr = (unsigned long *)(addr & ~0xFULL);
unsigned long kprobe_inst=0;
unsigned int slot = addr & 0xf, template, major_opcode = 0;
- bundle_t *bundle = &p->ainsn.insn.bundle;
+ bundle_t *bundle;
- memcpy(&p->opcode.bundle, kprobe_addr, sizeof(bundle_t));
- memcpy(&p->ainsn.insn.bundle, kprobe_addr, sizeof(bundle_t));
-
- template = bundle->quad0.template;
+ bundle = &((kprobe_opcode_t *)kprobe_addr)->bundle;
+ template = bundle->quad0.template;
if(valid_kprobe_addr(template, slot, addr))
return -EINVAL;
/* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
- if (slot == 1 && bundle_encoding[template][1] == L)
- slot++;
+ if (slot == 1 && bundle_encoding[template][1] == L)
+ slot++;
/* Get kprobe_inst and major_opcode from the bundle */
get_kprobe_inst(bundle, slot, &kprobe_inst, &major_opcode);
- if (unsupported_inst(template, slot, major_opcode, kprobe_inst, p))
+ if (unsupported_inst(template, slot, major_opcode, kprobe_inst, addr))
return -EINVAL;
- prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
- return 0;
-}
+ p->ainsn.insn = get_insn_slot();
+ if (!p->ainsn.insn)
+ return -ENOMEM;
+ memcpy(&p->opcode, kprobe_addr, sizeof(kprobe_opcode_t));
+ memcpy(p->ainsn.insn, kprobe_addr, sizeof(kprobe_opcode_t));
-void __kprobes flush_insn_slot(struct kprobe *p)
-{
- unsigned long arm_addr;
+ prepare_break_inst(template, slot, major_opcode, kprobe_inst, p);
- arm_addr = ((unsigned long)&p->opcode.bundle) & ~0xFULL;
- flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
+ return 0;
}
void __kprobes arch_arm_kprobe(struct kprobe *p)
@@ -461,9 +461,10 @@ void __kprobes arch_arm_kprobe(struct kprobe *p)
unsigned long addr = (unsigned long)p->addr;
unsigned long arm_addr = addr & ~0xFULL;
- flush_insn_slot(p);
- memcpy((char *)arm_addr, &p->ainsn.insn.bundle, sizeof(bundle_t));
- flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
+ flush_icache_range((unsigned long)p->ainsn.insn,
+ (unsigned long)p->ainsn.insn + sizeof(kprobe_opcode_t));
+ memcpy((char *)arm_addr, &p->opcode, sizeof(kprobe_opcode_t));
+ flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
}
void __kprobes arch_disarm_kprobe(struct kprobe *p)
@@ -471,11 +472,18 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
unsigned long addr = (unsigned long)p->addr;
unsigned long arm_addr = addr & ~0xFULL;
- /* p->opcode contains the original unaltered bundle */
- memcpy((char *) arm_addr, (char *) &p->opcode.bundle, sizeof(bundle_t));
- flush_icache_range(arm_addr, arm_addr + sizeof(bundle_t));
+ /* p->ainsn.insn contains the original unaltered kprobe_opcode_t */
+ memcpy((char *) arm_addr, (char *) p->ainsn.insn,
+ sizeof(kprobe_opcode_t));
+ flush_icache_range(arm_addr, arm_addr + sizeof(kprobe_opcode_t));
}
+void __kprobes arch_remove_kprobe(struct kprobe *p)
+{
+ mutex_lock(&kprobe_mutex);
+ free_insn_slot(p->ainsn.insn);
+ mutex_unlock(&kprobe_mutex);
+}
/*
* We are resuming execution after a single step fault, so the pt_regs
* structure reflects the register state after we executed the instruction
@@ -486,21 +494,22 @@ void __kprobes arch_disarm_kprobe(struct kprobe *p)
*/
static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
{
- unsigned long bundle_addr = ((unsigned long) (&p->opcode.bundle)) & ~0xFULL;
- unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
- unsigned long template;
- int slot = ((unsigned long)p->addr & 0xf);
+ unsigned long bundle_addr = (unsigned long) (&p->ainsn.insn->bundle);
+ unsigned long resume_addr = (unsigned long)p->addr & ~0xFULL;
+ unsigned long template;
+ int slot = ((unsigned long)p->addr & 0xf);
- template = p->opcode.bundle.quad0.template;
+ template = p->ainsn.insn->bundle.quad0.template;
- if (slot == 1 && bundle_encoding[template][1] == L)
- slot = 2;
+ if (slot == 1 && bundle_encoding[template][1] == L)
+ slot = 2;
if (p->ainsn.inst_flag) {
if (p->ainsn.inst_flag & INST_FLAG_FIX_RELATIVE_IP_ADDR) {
/* Fix relative IP address */
- regs->cr_iip = (regs->cr_iip - bundle_addr) + resume_addr;
+ regs->cr_iip = (regs->cr_iip - bundle_addr) +
+ resume_addr;
}
if (p->ainsn.inst_flag & INST_FLAG_FIX_BRANCH_REG) {
@@ -537,23 +546,23 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs)
}
if (slot == 2) {
- if (regs->cr_iip == bundle_addr + 0x10) {
- regs->cr_iip = resume_addr + 0x10;
- }
- } else {
- if (regs->cr_iip == bundle_addr) {
- regs->cr_iip = resume_addr;
- }
+ if (regs->cr_iip == bundle_addr + 0x10) {
+ regs->cr_iip = resume_addr + 0x10;
+ }
+ } else {
+ if (regs->cr_iip == bundle_addr) {
+ regs->cr_iip = resume_addr;
+ }
}
turn_ss_off:
- /* Turn off Single Step bit */
- ia64_psr(regs)->ss = 0;
+ /* Turn off Single Step bit */
+ ia64_psr(regs)->ss = 0;
}
static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
{
- unsigned long bundle_addr = (unsigned long) &p->opcode.bundle;
+ unsigned long bundle_addr = (unsigned long) &p->ainsn.insn->bundle;
unsigned long slot = (unsigned long)p->addr & 0xf;
/* single step inline if break instruction */
@@ -584,7 +593,7 @@ static int __kprobes is_ia64_break_inst(struct pt_regs *regs)
/* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
if (slot == 1 && bundle_encoding[template][1] == L)
- slot++;
+ slot++;
/* Get Kprobe probe instruction at given slot*/
get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode);
@@ -624,7 +633,7 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
if (p) {
if ((kcb->kprobe_status == KPROBE_HIT_SS) &&
(p->ainsn.inst_flag == INST_FLAG_BREAK_INST)) {
- ia64_psr(regs)->ss = 0;
+ ia64_psr(regs)->ss = 0;
goto no_kprobe;
}
/* We have reentered the pre_kprobe_handler(), since
@@ -768,6 +777,12 @@ static int __kprobes kprobes_fault_handler(struct pt_regs *regs, int trapnr)
*/
if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr))
return 1;
+ /*
+ * In case the user-specified fault handler returned
+ * zero, try to fix up.
+ */
+ if (ia64_done_with_exception(regs))
+ return 1;
/*
* Let ia64_do_page_fault() fix it.
@@ -878,7 +893,7 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
* fix the return address to our jprobe_inst_return() function
* in the jprobes.S file
*/
- regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip;
+ regs->b0 = ((struct fnptr *)(jprobe_inst_return))->ip;
return 1;
}
diff --git a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c
index d4a546aa5048..9620822270a6 100644
--- a/arch/ia64/kernel/machvec.c
+++ b/arch/ia64/kernel/machvec.c
@@ -60,7 +60,7 @@ machvec_setup (char **arg)
EXPORT_SYMBOL(machvec_setup);
void
-machvec_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+machvec_timer_interrupt (int irq, void *dev_id)
{
}
EXPORT_SYMBOL(machvec_timer_interrupt);
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 2fbe4536fe18..7cfa63a98cb3 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -54,6 +54,9 @@
*
* 2005-10-07 Keith Owens <kaos@sgi.com>
* Add notify_die() hooks.
+ *
+ * 2006-09-15 Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
+ * Add printing support for MCA/INIT.
*/
#include <linux/types.h>
#include <linux/init.h>
@@ -136,11 +139,175 @@ extern void salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe);
static int mca_init __initdata;
+/*
+ * limited & delayed printing support for MCA/INIT handler
+ */
+
+#define mprintk(fmt...) ia64_mca_printk(fmt)
+
+#define MLOGBUF_SIZE (512+256*NR_CPUS)
+#define MLOGBUF_MSGMAX 256
+static char mlogbuf[MLOGBUF_SIZE];
+static DEFINE_SPINLOCK(mlogbuf_wlock); /* mca context only */
+static DEFINE_SPINLOCK(mlogbuf_rlock); /* normal context only */
+static unsigned long mlogbuf_start;
+static unsigned long mlogbuf_end;
+static unsigned int mlogbuf_finished = 0;
+static unsigned long mlogbuf_timestamp = 0;
+
+static int loglevel_save = -1;
+#define BREAK_LOGLEVEL(__console_loglevel) \
+ oops_in_progress = 1; \
+ if (loglevel_save < 0) \
+ loglevel_save = __console_loglevel; \
+ __console_loglevel = 15;
+
+#define RESTORE_LOGLEVEL(__console_loglevel) \
+ if (loglevel_save >= 0) { \
+ __console_loglevel = loglevel_save; \
+ loglevel_save = -1; \
+ } \
+ mlogbuf_finished = 0; \
+ oops_in_progress = 0;
+
+/*
+ * Push messages into buffer, print them later if not urgent.
+ */
+void ia64_mca_printk(const char *fmt, ...)
+{
+ va_list args;
+ int printed_len;
+ char temp_buf[MLOGBUF_MSGMAX];
+ char *p;
+
+ va_start(args, fmt);
+ printed_len = vscnprintf(temp_buf, sizeof(temp_buf), fmt, args);
+ va_end(args);
+
+ /* Copy the output into mlogbuf */
+ if (oops_in_progress) {
+ /* mlogbuf was abandoned, use printk directly instead. */
+ printk(temp_buf);
+ } else {
+ spin_lock(&mlogbuf_wlock);
+ for (p = temp_buf; *p; p++) {
+ unsigned long next = (mlogbuf_end + 1) % MLOGBUF_SIZE;
+ if (next != mlogbuf_start) {
+ mlogbuf[mlogbuf_end] = *p;
+ mlogbuf_end = next;
+ } else {
+ /* buffer full */
+ break;
+ }
+ }
+ mlogbuf[mlogbuf_end] = '\0';
+ spin_unlock(&mlogbuf_wlock);
+ }
+}
+EXPORT_SYMBOL(ia64_mca_printk);
+
+/*
+ * Print buffered messages.
+ * NOTE: call this after returning normal context. (ex. from salinfod)
+ */
+void ia64_mlogbuf_dump(void)
+{
+ char temp_buf[MLOGBUF_MSGMAX];
+ char *p;
+ unsigned long index;
+ unsigned long flags;
+ unsigned int printed_len;
+
+ /* Get output from mlogbuf */
+ while (mlogbuf_start != mlogbuf_end) {
+ temp_buf[0] = '\0';
+ p = temp_buf;
+ printed_len = 0;
+
+ spin_lock_irqsave(&mlogbuf_rlock, flags);
+
+ index = mlogbuf_start;
+ while (index != mlogbuf_end) {
+ *p = mlogbuf[index];
+ index = (index + 1) % MLOGBUF_SIZE;
+ if (!*p)
+ break;
+ p++;
+ if (++printed_len >= MLOGBUF_MSGMAX - 1)
+ break;
+ }
+ *p = '\0';
+ if (temp_buf[0])
+ printk(temp_buf);
+ mlogbuf_start = index;
+
+ mlogbuf_timestamp = 0;
+ spin_unlock_irqrestore(&mlogbuf_rlock, flags);
+ }
+}
+EXPORT_SYMBOL(ia64_mlogbuf_dump);
+
+/*
+ * Call this if system is going to down or if immediate flushing messages to
+ * console is required. (ex. recovery was failed, crash dump is going to be
+ * invoked, long-wait rendezvous etc.)
+ * NOTE: this should be called from monarch.
+ */
+static void ia64_mlogbuf_finish(int wait)
+{
+ BREAK_LOGLEVEL(console_loglevel);
+
+ spin_lock_init(&mlogbuf_rlock);
+ ia64_mlogbuf_dump();
+ printk(KERN_EMERG "mlogbuf_finish: printing switched to urgent mode, "
+ "MCA/INIT might be dodgy or fail.\n");
+
+ if (!wait)
+ return;
+
+ /* wait for console */
+ printk("Delaying for 5 seconds...\n");
+ udelay(5*1000000);
+
+ mlogbuf_finished = 1;
+}
+EXPORT_SYMBOL(ia64_mlogbuf_finish);
+
+/*
+ * Print buffered messages from INIT context.
+ */
+static void ia64_mlogbuf_dump_from_init(void)
+{
+ if (mlogbuf_finished)
+ return;
+
+ if (mlogbuf_timestamp && (mlogbuf_timestamp + 30*HZ > jiffies)) {
+ printk(KERN_ERR "INIT: mlogbuf_dump is interrupted by INIT "
+ " and the system seems to be messed up.\n");
+ ia64_mlogbuf_finish(0);
+ return;
+ }
+
+ if (!spin_trylock(&mlogbuf_rlock)) {
+ printk(KERN_ERR "INIT: mlogbuf_dump is interrupted by INIT. "
+ "Generated messages other than stack dump will be "
+ "buffered to mlogbuf and will be printed later.\n");
+ printk(KERN_ERR "INIT: If messages would not printed after "
+ "this INIT, wait 30sec and assert INIT again.\n");
+ if (!mlogbuf_timestamp)
+ mlogbuf_timestamp = jiffies;
+ return;
+ }
+ spin_unlock(&mlogbuf_rlock);
+ ia64_mlogbuf_dump();
+}
static void inline
ia64_mca_spin(const char *func)
{
- printk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func);
+ if (monarch_cpu == smp_processor_id())
+ ia64_mlogbuf_finish(0);
+ mprintk(KERN_EMERG "%s: spinning here, not returning to SAL\n", func);
while (1)
cpu_relax();
}
@@ -221,7 +388,7 @@ ia64_log_get(int sal_info_type, u8 **buffer, int irq_safe)
{
sal_log_record_header_t *log_buffer;
u64 total_len = 0;
- int s;
+ unsigned long s;
IA64_LOG_LOCK(sal_info_type);
@@ -332,7 +499,7 @@ int cpe_vector = -1;
int ia64_cpe_irq = -1;
static irqreturn_t
-ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_cpe_int_handler (int cpe_irq, void *arg)
{
static unsigned long cpe_history[CPE_HISTORY_LENGTH];
static int index;
@@ -344,9 +511,6 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
/* SAL spec states this should run w/ interrupts enabled */
local_irq_enable();
- /* Get the CPE error record and log it */
- ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
-
spin_lock(&cpe_history_lock);
if (!cpe_poll_enabled && cpe_vector >= 0) {
@@ -375,7 +539,7 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
mod_timer(&cpe_poll_timer, jiffies + MIN_CPE_POLL_INTERVAL);
/* lock already released, get out now */
- return IRQ_HANDLED;
+ goto out;
} else {
cpe_history[index++] = now;
if (index == CPE_HISTORY_LENGTH)
@@ -383,6 +547,10 @@ ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
}
}
spin_unlock(&cpe_history_lock);
+out:
+ /* Get the CPE error record and log it */
+ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);
+
return IRQ_HANDLED;
}
@@ -576,7 +744,7 @@ ia64_mca_wakeup_all(void)
* Outputs : None
*/
static irqreturn_t
-ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
+ia64_mca_rendez_int_handler(int rendez_irq, void *arg)
{
unsigned long flags;
int cpu = smp_processor_id();
@@ -585,8 +753,8 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
/* Mask all interrupts */
local_irq_save(flags);
- if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", regs, (long)&nd, 0, 0)
- == NOTIFY_STOP)
+ if (notify_die(DIE_MCA_RENDZVOUS_ENTER, "MCA", get_irq_regs(),
+ (long)&nd, 0, 0) == NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_DONE;
@@ -595,16 +763,16 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
*/
ia64_sal_mc_rendez();
- if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", regs, (long)&nd, 0, 0)
- == NOTIFY_STOP)
+ if (notify_die(DIE_MCA_RENDZVOUS_PROCESS, "MCA", get_irq_regs(),
+ (long)&nd, 0, 0) == NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
/* Wait for the monarch cpu to exit. */
while (monarch_cpu != -1)
cpu_relax(); /* spin until monarch leaves */
- if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", regs, (long)&nd, 0, 0)
- == NOTIFY_STOP)
+ if (notify_die(DIE_MCA_RENDZVOUS_LEAVE, "MCA", get_irq_regs(),
+ (long)&nd, 0, 0) == NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
/* Enable all interrupts */
@@ -623,12 +791,11 @@ ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *regs)
*
* Inputs : wakeup_irq (Wakeup-interrupt bit)
* arg (Interrupt handler specific argument)
- * ptregs (Exception frame at the time of the interrupt)
* Outputs : None
*
*/
static irqreturn_t
-ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg)
{
return IRQ_HANDLED;
}
@@ -988,18 +1155,22 @@ ia64_wait_for_slaves(int monarch, const char *type)
}
if (!missing)
goto all_in;
- printk(KERN_INFO "OS %s slave did not rendezvous on cpu", type);
+ /*
+ * Maybe slave(s) dead. Print buffered messages immediately.
+ */
+ ia64_mlogbuf_finish(0);
+ mprintk(KERN_INFO "OS %s slave did not rendezvous on cpu", type);
for_each_online_cpu(c) {
if (c == monarch)
continue;
if (ia64_mc_info.imi_rendez_checkin[c] == IA64_MCA_RENDEZ_CHECKIN_NOTDONE)
- printk(" %d", c);
+ mprintk(" %d", c);
}
- printk("\n");
+ mprintk("\n");
return;
all_in:
- printk(KERN_INFO "All OS %s slaves have reached rendezvous\n", type);
+ mprintk(KERN_INFO "All OS %s slaves have reached rendezvous\n", type);
return;
}
@@ -1027,10 +1198,8 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
struct ia64_mca_notify_die nd =
{ .sos = sos, .monarch_cpu = &monarch_cpu };
- oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */
- console_loglevel = 15; /* make sure printks make it to console */
- printk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d monarch=%ld\n",
- sos->proc_state_param, cpu, sos->monarch);
+ mprintk(KERN_INFO "Entered OS MCA handler. PSP=%lx cpu=%d "
+ "monarch=%ld\n", sos->proc_state_param, cpu, sos->monarch);
previous_current = ia64_mca_modify_original_stack(regs, sw, sos, "MCA");
monarch_cpu = cpu;
@@ -1066,6 +1235,9 @@ ia64_mca_handler(struct pt_regs *regs, struct switch_stack *sw,
rh->severity = sal_log_severity_corrected;
ia64_sal_clear_state_info(SAL_INFO_TYPE_MCA);
sos->os_status = IA64_MCA_CORRECTED;
+ } else {
+ /* Dump buffered message to console */
+ ia64_mlogbuf_finish(1);
}
if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover)
== NOTIFY_STOP)
@@ -1088,13 +1260,12 @@ static DECLARE_WORK(cmc_enable_work, ia64_mca_cmc_vector_enable_keventd, NULL);
* Inputs
* interrupt number
* client data arg ptr
- * saved registers ptr
*
* Outputs
* None
*/
static irqreturn_t
-ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_cmc_int_handler(int cmc_irq, void *arg)
{
static unsigned long cmc_history[CMC_HISTORY_LENGTH];
static int index;
@@ -1106,9 +1277,6 @@ ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
/* SAL spec states this should run w/ interrupts enabled */
local_irq_enable();
- /* Get the CMC error record and log it */
- ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
-
spin_lock(&cmc_history_lock);
if (!cmc_polling_enabled) {
int i, count = 1; /* we know 1 happened now */
@@ -1141,7 +1309,7 @@ ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL);
/* lock already released, get out now */
- return IRQ_HANDLED;
+ goto out;
} else {
cmc_history[index++] = now;
if (index == CMC_HISTORY_LENGTH)
@@ -1149,6 +1317,10 @@ ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
}
}
spin_unlock(&cmc_history_lock);
+out:
+ /* Get the CMC error record and log it */
+ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);
+
return IRQ_HANDLED;
}
@@ -1162,12 +1334,11 @@ ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
* Inputs
* interrupt number
* client data arg ptr
- * saved registers ptr
* Outputs
* handled
*/
static irqreturn_t
-ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_cmc_int_caller(int cmc_irq, void *arg)
{
static int start_count = -1;
unsigned int cpuid;
@@ -1178,7 +1349,7 @@ ia64_mca_cmc_int_caller(int cmc_irq, void *arg, struct pt_regs *ptregs)
if (start_count == -1)
start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC);
- ia64_mca_cmc_int_handler(cmc_irq, arg, ptregs);
+ ia64_mca_cmc_int_handler(cmc_irq, arg);
for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
@@ -1229,14 +1400,13 @@ ia64_mca_cmc_poll (unsigned long dummy)
* Inputs
* interrupt number
* client data arg ptr
- * saved registers ptr
* Outputs
* handled
*/
#ifdef CONFIG_ACPI
static irqreturn_t
-ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
+ia64_mca_cpe_int_caller(int cpe_irq, void *arg)
{
static int start_count = -1;
static int poll_time = MIN_CPE_POLL_INTERVAL;
@@ -1248,7 +1418,7 @@ ia64_mca_cpe_int_caller(int cpe_irq, void *arg, struct pt_regs *ptregs)
if (start_count == -1)
start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CPE);
- ia64_mca_cpe_int_handler(cpe_irq, arg, ptregs);
+ ia64_mca_cpe_int_handler(cpe_irq, arg);
for (++cpuid ; cpuid < NR_CPUS && !cpu_online(cpuid) ; cpuid++);
@@ -1305,6 +1475,15 @@ default_monarch_init_process(struct notifier_block *self, unsigned long val, voi
struct task_struct *g, *t;
if (val != DIE_INIT_MONARCH_PROCESS)
return NOTIFY_DONE;
+
+ /*
+ * FIXME: mlogbuf will brim over with INIT stack dumps.
+ * To enable show_stack from INIT, we use oops_in_progress which should
+ * be used in real oops. This would cause something wrong after INIT.
+ */
+ BREAK_LOGLEVEL(console_loglevel);
+ ia64_mlogbuf_dump_from_init();
+
printk(KERN_ERR "Processes interrupted by INIT -");
for_each_online_cpu(c) {
struct ia64_sal_os_state *s;
@@ -1326,6 +1505,8 @@ default_monarch_init_process(struct notifier_block *self, unsigned long val, voi
} while_each_thread (g, t);
read_unlock(&tasklist_lock);
}
+ /* FIXME: This will not restore zapped printk locks. */
+ RESTORE_LOGLEVEL(console_loglevel);
return NOTIFY_DONE;
}
@@ -1357,12 +1538,9 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
struct ia64_mca_notify_die nd =
{ .sos = sos, .monarch_cpu = &monarch_cpu };
- oops_in_progress = 1; /* FIXME: make printk NMI/MCA/INIT safe */
- console_loglevel = 15; /* make sure printks make it to console */
-
(void) notify_die(DIE_INIT_ENTER, "INIT", regs, (long)&nd, 0, 0);
- printk(KERN_INFO "Entered OS INIT handler. PSP=%lx cpu=%d monarch=%ld\n",
+ mprintk(KERN_INFO "Entered OS INIT handler. PSP=%lx cpu=%d monarch=%ld\n",
sos->proc_state_param, cpu, sos->monarch);
salinfo_log_wakeup(SAL_INFO_TYPE_INIT, NULL, 0, 0);
@@ -1375,7 +1553,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
* fix their proms and get their customers updated.
*/
if (!sos->monarch && atomic_add_return(1, &slaves) == num_online_cpus()) {
- printk(KERN_WARNING "%s: Promoting cpu %d to monarch.\n",
+ mprintk(KERN_WARNING "%s: Promoting cpu %d to monarch.\n",
__FUNCTION__, cpu);
atomic_dec(&slaves);
sos->monarch = 1;
@@ -1387,7 +1565,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
* fix their proms and get their customers updated.
*/
if (sos->monarch && atomic_add_return(1, &monarchs) > 1) {
- printk(KERN_WARNING "%s: Demoting cpu %d to slave.\n",
+ mprintk(KERN_WARNING "%s: Demoting cpu %d to slave.\n",
__FUNCTION__, cpu);
atomic_dec(&monarchs);
sos->monarch = 0;
@@ -1408,7 +1586,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
if (notify_die(DIE_INIT_SLAVE_LEAVE, "INIT", regs, (long)&nd, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
- printk("Slave on cpu %d returning to normal service.\n", cpu);
+ mprintk("Slave on cpu %d returning to normal service.\n", cpu);
set_curr_task(cpu, previous_current);
ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
atomic_dec(&slaves);
@@ -1426,7 +1604,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
* same serial line, the user will need some time to switch out of the BMC before
* the dump begins.
*/
- printk("Delaying for 5 seconds...\n");
+ mprintk("Delaying for 5 seconds...\n");
udelay(5*1000000);
ia64_wait_for_slaves(cpu, "INIT");
/* If nobody intercepts DIE_INIT_MONARCH_PROCESS then we drop through
@@ -1439,7 +1617,7 @@ ia64_init_handler(struct pt_regs *regs, struct switch_stack *sw,
if (notify_die(DIE_INIT_MONARCH_LEAVE, "INIT", regs, (long)&nd, 0, 0)
== NOTIFY_STOP)
ia64_mca_spin(__FUNCTION__);
- printk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu);
+ mprintk("\nINIT dump complete. Monarch on cpu %d returning to normal service.\n", cpu);
atomic_dec(&monarchs);
set_curr_task(cpu, previous_current);
monarch_cpu = -1;
diff --git a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
index 96047491d1b9..c6b607c00dee 100644
--- a/arch/ia64/kernel/mca_asm.S
+++ b/arch/ia64/kernel/mca_asm.S
@@ -1025,18 +1025,13 @@ ia64_old_stack:
ia64_set_kernel_registers:
add temp3=MCA_SP_OFFSET, r3
- add temp4=MCA_SOS_OFFSET+SOS(OS_GP), r3
mov b0=r2 // save return address
GET_IA64_MCA_DATA(temp1)
;;
- add temp4=temp4, temp1 // &struct ia64_sal_os_state.os_gp
add r12=temp1, temp3 // kernel stack pointer on MCA/INIT stack
add r13=temp1, r3 // set current to start of MCA/INIT stack
add r20=temp1, r3 // physical start of MCA/INIT stack
;;
- ld8 r1=[temp4] // OS GP from SAL OS state
- ;;
- DATA_PA_TO_VA(r1,temp1)
DATA_PA_TO_VA(r12,temp2)
DATA_PA_TO_VA(r13,temp3)
;;
@@ -1067,6 +1062,10 @@ ia64_set_kernel_registers:
mov cr.itir=r18
mov cr.ifa=r13
mov r20=IA64_TR_CURRENT_STACK
+
+ movl r17=FPSR_DEFAULT
+ ;;
+ mov.m ar.fpsr=r17 // set ar.fpsr to kernel default value
;;
itr.d dtr[r20]=r21
;;
diff --git a/arch/ia64/kernel/mca_drv.c b/arch/ia64/kernel/mca_drv.c
index 8db6e0cedadc..a45009d2bc90 100644
--- a/arch/ia64/kernel/mca_drv.c
+++ b/arch/ia64/kernel/mca_drv.c
@@ -79,14 +79,30 @@ static int
fatal_mca(const char *fmt, ...)
{
va_list args;
+ char buf[256];
va_start(args, fmt);
- vprintk(fmt, args);
+ vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
+ ia64_mca_printk(KERN_ALERT "MCA: %s\n", buf);
return MCA_NOT_RECOVERED;
}
+static int
+mca_recovered(const char *fmt, ...)
+{
+ va_list args;
+ char buf[256];
+
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+ ia64_mca_printk(KERN_INFO "MCA: %s\n", buf);
+
+ return MCA_RECOVERED;
+}
+
/**
* mca_page_isolate - isolate a poisoned page in order not to use it later
* @paddr: poisoned memory location
@@ -140,6 +156,7 @@ mca_page_isolate(unsigned long paddr)
void
mca_handler_bh(unsigned long paddr, void *iip, unsigned long ipsr)
{
+ ia64_mlogbuf_dump();
printk(KERN_ERR "OS_MCA: process [cpu %d, pid: %d, uid: %d, "
"iip: %p, psr: 0x%lx,paddr: 0x%lx](%s) encounters MCA.\n",
raw_smp_processor_id(), current->pid, current->uid,
@@ -440,7 +457,7 @@ recover_from_read_error(slidx_table_t *slidx,
/* Is target address valid? */
if (!pbci->tv)
- return fatal_mca(KERN_ALERT "MCA: target address not valid\n");
+ return fatal_mca("target address not valid");
/*
* cpu read or memory-mapped io read
@@ -458,7 +475,7 @@ recover_from_read_error(slidx_table_t *slidx,
/* Is minstate valid? */
if (!peidx_bottom(peidx) || !(peidx_bottom(peidx)->valid.minstate))
- return fatal_mca(KERN_ALERT "MCA: minstate not valid\n");
+ return fatal_mca("minstate not valid");
psr1 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_ipsr);
psr2 =(struct ia64_psr *)&(peidx_minstate_area(peidx)->pmsa_xpsr);
@@ -492,13 +509,14 @@ recover_from_read_error(slidx_table_t *slidx,
psr2->bn = 1;
psr2->i = 0;
- return MCA_RECOVERED;
+ return mca_recovered("user memory corruption. "
+ "kill affected process - recovered.");
}
}
- return fatal_mca(KERN_ALERT "MCA: kernel context not recovered,"
- " iip 0x%lx\n", pmsa->pmsa_iip);
+ return fatal_mca("kernel context not recovered, iip 0x%lx\n",
+ pmsa->pmsa_iip);
}
/**
@@ -584,13 +602,13 @@ recover_from_processor_error(int platform, slidx_table_t *slidx,
* The machine check is corrected.
*/
if (psp->cm == 1)
- return MCA_RECOVERED;
+ return mca_recovered("machine check is already corrected.");
/*
* The error was not contained. Software must be reset.
*/
if (psp->us || psp->ci == 0)
- return fatal_mca(KERN_ALERT "MCA: error not contained\n");
+ return fatal_mca("error not contained");
/*
* The cache check and bus check bits have four possible states
@@ -601,22 +619,22 @@ recover_from_processor_error(int platform, slidx_table_t *slidx,
* 1 1 Memory error, attempt recovery
*/
if (psp->bc == 0 || pbci == NULL)
- return fatal_mca(KERN_ALERT "MCA: No bus check\n");
+ return fatal_mca("No bus check");
/*
* Sorry, we cannot handle so many.
*/
if (peidx_bus_check_num(peidx) > 1)
- return fatal_mca(KERN_ALERT "MCA: Too many bus checks\n");
+ return fatal_mca("Too many bus checks");
/*
* Well, here is only one bus error.
*/
if (pbci->ib)
- return fatal_mca(KERN_ALERT "MCA: Internal Bus error\n");
+ return fatal_mca("Internal Bus error");
if (pbci->cc)
- return fatal_mca(KERN_ALERT "MCA: Cache-cache error\n");
+ return fatal_mca("Cache-cache error");
if (pbci->eb && pbci->bsi > 0)
- return fatal_mca(KERN_ALERT "MCA: External bus check fatal status\n");
+ return fatal_mca("External bus check fatal status");
/*
* This is a local MCA and estimated as recoverble external bus error.
@@ -628,7 +646,7 @@ recover_from_processor_error(int platform, slidx_table_t *slidx,
/*
* On account of strange SAL error record, we cannot recover.
*/
- return fatal_mca(KERN_ALERT "MCA: Strange SAL record\n");
+ return fatal_mca("Strange SAL record");
}
/**
@@ -657,10 +675,10 @@ mca_try_to_recover(void *rec, struct ia64_sal_os_state *sos)
/* Now, OS can recover when there is one processor error section */
if (n_proc_err > 1)
- return fatal_mca(KERN_ALERT "MCA: Too Many Errors\n");
+ return fatal_mca("Too Many Errors");
else if (n_proc_err == 0)
- /* Weird SAL record ... We need not to recover */
- return fatal_mca(KERN_ALERT "MCA: Weird SAL record\n");
+ /* Weird SAL record ... We can't do anything */
+ return fatal_mca("Weird SAL record");
/* Make index of processor error section */
mca_make_peidx((sal_log_processor_info_t*)
@@ -671,7 +689,7 @@ mca_try_to_recover(void *rec, struct ia64_sal_os_state *sos)
/* Check whether MCA is global or not */
if (is_mca_global(&peidx, &pbci, sos))
- return fatal_mca(KERN_ALERT "MCA: global MCA\n");
+ return fatal_mca("global MCA");
/* Try to recover a processor error */
return recover_from_processor_error(platform_err, &slidx, &peidx,
diff --git a/arch/ia64/kernel/mca_drv.h b/arch/ia64/kernel/mca_drv.h
index 31a2e52bb16f..c85e943ba5fd 100644
--- a/arch/ia64/kernel/mca_drv.h
+++ b/arch/ia64/kernel/mca_drv.h
@@ -118,3 +118,7 @@ struct mca_table_entry {
extern const struct mca_table_entry *search_mca_tables (unsigned long addr);
extern int mca_recover_range(unsigned long);
+extern void ia64_mca_printk(const char * fmt, ...)
+ __attribute__ ((format (printf, 1, 2)));
+extern void ia64_mlogbuf_dump(void);
+
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
new file mode 100644
index 000000000000..822e59a1b822
--- /dev/null
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -0,0 +1,143 @@
+/*
+ * MSI hooks for standard x86 apic
+ */
+
+#include <linux/pci.h>
+#include <linux/irq.h>
+#include <linux/msi.h>
+#include <asm/smp.h>
+
+/*
+ * Shifts for APIC-based data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT 0
+#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
+
+#define MSI_DATA_DELIVERY_SHIFT 8
+#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
+#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT 14
+#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT 15
+#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for APIC-based bus address
+ */
+
+#define MSI_TARGET_CPU_SHIFT 4
+#define MSI_ADDR_HEADER 0xfee00000
+
+#define MSI_ADDR_DESTID_MASK 0xfff0000f
+#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
+
+#define MSI_ADDR_DESTMODE_SHIFT 2
+#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
+#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT 3
+#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
+#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
+
+static struct irq_chip ia64_msi_chip;
+
+#ifdef CONFIG_SMP
+static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
+{
+ struct msi_msg msg;
+ u32 addr;
+
+ read_msi_msg(irq, &msg);
+
+ addr = msg.address_lo;
+ addr &= MSI_ADDR_DESTID_MASK;
+ addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(first_cpu(cpu_mask)));
+ msg.address_lo = addr;
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, cpu_mask);
+}
+#endif /* CONFIG_SMP */
+
+int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+ struct msi_msg msg;
+ unsigned long dest_phys_id;
+ unsigned int vector;
+
+ dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
+ vector = irq;
+
+ msg.address_hi = 0;
+ msg.address_lo =
+ MSI_ADDR_HEADER |
+ MSI_ADDR_DESTMODE_PHYS |
+ MSI_ADDR_REDIRECTION_CPU |
+ MSI_ADDR_DESTID_CPU(dest_phys_id);
+
+ msg.data =
+ MSI_DATA_TRIGGER_EDGE |
+ MSI_DATA_LEVEL_ASSERT |
+ MSI_DATA_DELIVERY_FIXED |
+ MSI_DATA_VECTOR(vector);
+
+ write_msi_msg(irq, &msg);
+ set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
+
+ return 0;
+}
+
+void ia64_teardown_msi_irq(unsigned int irq)
+{
+ return; /* no-op */
+}
+
+static void ia64_ack_msi_irq(unsigned int irq)
+{
+ move_native_irq(irq);
+ ia64_eoi();
+}
+
+static int ia64_msi_retrigger_irq(unsigned int irq)
+{
+ unsigned int vector = irq;
+ ia64_resend_irq(vector);
+
+ return 1;
+}
+
+/*
+ * Generic ops used on most IA64 platforms.
+ */
+static struct irq_chip ia64_msi_chip = {
+ .name = "PCI-MSI",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .ack = ia64_ack_msi_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = ia64_set_msi_irq_affinity,
+#endif
+ .retrigger = ia64_msi_retrigger_irq,
+};
+
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+{
+ if (platform_setup_msi_irq)
+ return platform_setup_msi_irq(irq, pdev);
+
+ return ia64_setup_msi_irq(irq, pdev);
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ if (platform_teardown_msi_irq)
+ return platform_teardown_msi_irq(irq);
+
+ return ia64_teardown_msi_irq(irq);
+}
diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c
index 20340631179f..a78b45f5fe2f 100644
--- a/arch/ia64/kernel/numa.c
+++ b/arch/ia64/kernel/numa.c
@@ -28,6 +28,7 @@ u16 cpu_to_node_map[NR_CPUS] __cacheline_aligned;
EXPORT_SYMBOL(cpu_to_node_map);
cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
+EXPORT_SYMBOL(node_to_cpu_mask);
void __cpuinit map_cpu_to_node(int cpu, int nid)
{
diff --git a/arch/ia64/kernel/pal.S b/arch/ia64/kernel/pal.S
index ebaf1e685f5e..0b533441c3c9 100644
--- a/arch/ia64/kernel/pal.S
+++ b/arch/ia64/kernel/pal.S
@@ -21,11 +21,12 @@ pal_entry_point:
.text
/*
- * Set the PAL entry point address. This could be written in C code, but we do it here
- * to keep it all in one module (besides, it's so trivial that it's
+ * Set the PAL entry point address. This could be written in C code, but we
+ * do it here to keep it all in one module (besides, it's so trivial that it's
* not a big deal).
*
- * in0 Address of the PAL entry point (text address, NOT a function descriptor).
+ * in0 Address of the PAL entry point (text address, NOT a function
+ * descriptor).
*/
GLOBAL_ENTRY(ia64_pal_handler_init)
alloc r3=ar.pfs,1,0,0,0
@@ -36,9 +37,9 @@ GLOBAL_ENTRY(ia64_pal_handler_init)
END(ia64_pal_handler_init)
/*
- * Default PAL call handler. This needs to be coded in assembly because it uses
- * the static calling convention, i.e., the RSE may not be used and calls are
- * done via "br.cond" (not "br.call").
+ * Default PAL call handler. This needs to be coded in assembly because it
+ * uses the static calling convention, i.e., the RSE may not be used and
+ * calls are done via "br.cond" (not "br.call").
*/
GLOBAL_ENTRY(ia64_pal_default_handler)
mov r8=-1
@@ -50,12 +51,10 @@ END(ia64_pal_default_handler)
*
* in0 Index of PAL service
* in1 - in3 Remaining PAL arguments
- * in4 1 ==> clear psr.ic, 0 ==> don't clear psr.ic
- *
*/
GLOBAL_ENTRY(ia64_pal_call_static)
- .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
- alloc loc1 = ar.pfs,5,5,0,0
+ .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
+ alloc loc1 = ar.pfs,4,5,0,0
movl loc2 = pal_entry_point
1: {
mov r28 = in0
@@ -64,7 +63,6 @@ GLOBAL_ENTRY(ia64_pal_call_static)
}
;;
ld8 loc2 = [loc2] // loc2 <- entry point
- tbit.nz p6,p7 = in4, 0
adds r8 = 1f-1b,r8
mov loc4=ar.rsc // save RSE configuration
;;
@@ -74,13 +72,11 @@ GLOBAL_ENTRY(ia64_pal_call_static)
.body
mov r30 = in2
-(p6) rsm psr.i | psr.ic
mov r31 = in3
mov b7 = loc2
-(p7) rsm psr.i
+ rsm psr.i
;;
-(p6) srlz.i
mov rp = r8
br.cond.sptk.many b7
1: mov psr.l = loc3
@@ -96,8 +92,8 @@ END(ia64_pal_call_static)
* Make a PAL call using the stacked registers calling convention.
*
* Inputs:
- * in0 Index of PAL service
- * in2 - in3 Remaning PAL arguments
+ * in0 Index of PAL service
+ * in2 - in3 Remaining PAL arguments
*/
GLOBAL_ENTRY(ia64_pal_call_stacked)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(4)
@@ -131,18 +127,18 @@ END(ia64_pal_call_stacked)
* Make a physical mode PAL call using the static registers calling convention.
*
* Inputs:
- * in0 Index of PAL service
- * in2 - in3 Remaning PAL arguments
+ * in0 Index of PAL service
+ * in2 - in3 Remaining PAL arguments
*
* PSR_LP, PSR_TB, PSR_ID, PSR_DA are never set by the kernel.
* So we don't need to clear them.
*/
-#define PAL_PSR_BITS_TO_CLEAR \
- (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | IA64_PSR_RT | \
- IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
+#define PAL_PSR_BITS_TO_CLEAR \
+ (IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_DB | IA64_PSR_RT |\
+ IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED | \
IA64_PSR_DFL | IA64_PSR_DFH)
-#define PAL_PSR_BITS_TO_SET \
+#define PAL_PSR_BITS_TO_SET \
(IA64_PSR_BN)
@@ -178,7 +174,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static)
;;
andcm r16=loc3,r16 // removes bits to clear from psr
br.call.sptk.many rp=ia64_switch_mode_phys
-.ret1: mov rp = r8 // install return address (physical)
+ mov rp = r8 // install return address (physical)
mov loc5 = r19
mov loc6 = r20
br.cond.sptk.many b7
@@ -188,7 +184,6 @@ GLOBAL_ENTRY(ia64_pal_call_phys_static)
mov r19=loc5
mov r20=loc6
br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
-.ret2:
mov psr.l = loc3 // restore init PSR
mov ar.pfs = loc1
@@ -203,8 +198,8 @@ END(ia64_pal_call_phys_static)
* Make a PAL call using the stacked registers in physical mode.
*
* Inputs:
- * in0 Index of PAL service
- * in2 - in3 Remaning PAL arguments
+ * in0 Index of PAL service
+ * in2 - in3 Remaining PAL arguments
*/
GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(5)
@@ -212,7 +207,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
movl loc2 = pal_entry_point
1: {
mov r28 = in0 // copy procedure index
- mov loc0 = rp // save rp
+ mov loc0 = rp // save rp
}
.body
;;
@@ -245,7 +240,7 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
mov r16=loc3 // r16= original psr
mov r19=loc5
mov r20=loc6
- br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
+ br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual mode
mov psr.l = loc3 // restore init PSR
mov ar.pfs = loc1
@@ -257,10 +252,11 @@ GLOBAL_ENTRY(ia64_pal_call_phys_stacked)
END(ia64_pal_call_phys_stacked)
/*
- * Save scratch fp scratch regs which aren't saved in pt_regs already (fp10-fp15).
+ * Save scratch fp scratch regs which aren't saved in pt_regs already
+ * (fp10-fp15).
*
- * NOTE: We need to do this since firmware (SAL and PAL) may use any of the scratch
- * regs fp-low partition.
+ * NOTE: We need to do this since firmware (SAL and PAL) may use any of the
+ * scratch regs fp-low partition.
*
* Inputs:
* in0 Address of stack storage for fp regs
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 7bb7696e4ce2..3aaede0d6981 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -63,6 +63,9 @@
#define PFM_INVALID_ACTIVATION (~0UL)
+#define PFM_NUM_PMC_REGS 64 /* PMC save area for ctxsw */
+#define PFM_NUM_PMD_REGS 64 /* PMD save area for ctxsw */
+
/*
* depth of message queue
*/
@@ -297,14 +300,17 @@ typedef struct pfm_context {
unsigned long ctx_reload_pmcs[4]; /* bitmask of force reload PMC on ctxsw in */
unsigned long ctx_used_monitors[4]; /* bitmask of monitor PMC being used */
- unsigned long ctx_pmcs[IA64_NUM_PMC_REGS]; /* saved copies of PMC values */
+ unsigned long ctx_pmcs[PFM_NUM_PMC_REGS]; /* saved copies of PMC values */
unsigned int ctx_used_ibrs[1]; /* bitmask of used IBR (speedup ctxsw in) */
unsigned int ctx_used_dbrs[1]; /* bitmask of used DBR (speedup ctxsw in) */
unsigned long ctx_dbrs[IA64_NUM_DBG_REGS]; /* DBR values (cache) when not loaded */
unsigned long ctx_ibrs[IA64_NUM_DBG_REGS]; /* IBR values (cache) when not loaded */
- pfm_counter_t ctx_pmds[IA64_NUM_PMD_REGS]; /* software state for PMDS */
+ pfm_counter_t ctx_pmds[PFM_NUM_PMD_REGS]; /* software state for PMDS */
+
+ unsigned long th_pmcs[PFM_NUM_PMC_REGS]; /* PMC thread save state */
+ unsigned long th_pmds[PFM_NUM_PMD_REGS]; /* PMD thread save state */
u64 ctx_saved_psr_up; /* only contains psr.up value */
@@ -868,7 +874,6 @@ static void
pfm_mask_monitoring(struct task_struct *task)
{
pfm_context_t *ctx = PFM_GET_CTX(task);
- struct thread_struct *th = &task->thread;
unsigned long mask, val, ovfl_mask;
int i;
@@ -889,7 +894,7 @@ pfm_mask_monitoring(struct task_struct *task)
* So in both cases, the live register contains the owner's
* state. We can ONLY touch the PMU registers and NOT the PSR.
*
- * As a consequence to this call, the thread->pmds[] array
+ * As a consequence to this call, the ctx->th_pmds[] array
* contains stale information which must be ignored
* when context is reloaded AND monitoring is active (see
* pfm_restart).
@@ -924,9 +929,9 @@ pfm_mask_monitoring(struct task_struct *task)
mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
if ((mask & 0x1) == 0UL) continue;
- ia64_set_pmc(i, th->pmcs[i] & ~0xfUL);
- th->pmcs[i] &= ~0xfUL;
- DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, th->pmcs[i]));
+ ia64_set_pmc(i, ctx->th_pmcs[i] & ~0xfUL);
+ ctx->th_pmcs[i] &= ~0xfUL;
+ DPRINT_ovfl(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
}
/*
* make all of this visible
@@ -943,7 +948,6 @@ static void
pfm_restore_monitoring(struct task_struct *task)
{
pfm_context_t *ctx = PFM_GET_CTX(task);
- struct thread_struct *th = &task->thread;
unsigned long mask, ovfl_mask;
unsigned long psr, val;
int i, is_system;
@@ -1009,9 +1013,9 @@ pfm_restore_monitoring(struct task_struct *task)
mask = ctx->ctx_used_monitors[0] >> PMU_FIRST_COUNTER;
for(i= PMU_FIRST_COUNTER; mask; i++, mask>>=1) {
if ((mask & 0x1) == 0UL) continue;
- th->pmcs[i] = ctx->ctx_pmcs[i];
- ia64_set_pmc(i, th->pmcs[i]);
- DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, th->pmcs[i]));
+ ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
+ ia64_set_pmc(i, ctx->th_pmcs[i]);
+ DPRINT(("[%d] pmc[%d]=0x%lx\n", task->pid, i, ctx->th_pmcs[i]));
}
ia64_srlz_d();
@@ -1070,7 +1074,6 @@ pfm_restore_pmds(unsigned long *pmds, unsigned long mask)
static inline void
pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
{
- struct thread_struct *thread = &task->thread;
unsigned long ovfl_val = pmu_conf->ovfl_val;
unsigned long mask = ctx->ctx_all_pmds[0];
unsigned long val;
@@ -1092,11 +1095,11 @@ pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
ctx->ctx_pmds[i].val = val & ~ovfl_val;
val &= ovfl_val;
}
- thread->pmds[i] = val;
+ ctx->th_pmds[i] = val;
DPRINT(("pmd[%d]=0x%lx soft_val=0x%lx\n",
i,
- thread->pmds[i],
+ ctx->th_pmds[i],
ctx->ctx_pmds[i].val));
}
}
@@ -1107,7 +1110,6 @@ pfm_copy_pmds(struct task_struct *task, pfm_context_t *ctx)
static inline void
pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx)
{
- struct thread_struct *thread = &task->thread;
unsigned long mask = ctx->ctx_all_pmcs[0];
int i;
@@ -1115,8 +1117,8 @@ pfm_copy_pmcs(struct task_struct *task, pfm_context_t *ctx)
for (i=0; mask; i++, mask>>=1) {
/* masking 0 with ovfl_val yields 0 */
- thread->pmcs[i] = ctx->ctx_pmcs[i];
- DPRINT(("pmc[%d]=0x%lx\n", i, thread->pmcs[i]));
+ ctx->th_pmcs[i] = ctx->ctx_pmcs[i];
+ DPRINT(("pmc[%d]=0x%lx\n", i, ctx->th_pmcs[i]));
}
}
@@ -2860,7 +2862,6 @@ pfm_reset_regs(pfm_context_t *ctx, unsigned long *ovfl_regs, int is_long_reset)
static int
pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
{
- struct thread_struct *thread = NULL;
struct task_struct *task;
pfarg_reg_t *req = (pfarg_reg_t *)arg;
unsigned long value, pmc_pm;
@@ -2881,7 +2882,6 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
if (state == PFM_CTX_ZOMBIE) return -EINVAL;
if (is_loaded) {
- thread = &task->thread;
/*
* In system wide and when the context is loaded, access can only happen
* when the caller is running on the CPU being monitored by the session.
@@ -3036,7 +3036,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
*
* The value in ctx_pmcs[] can only be changed in pfm_write_pmcs().
*
- * The value in thread->pmcs[] may be modified on overflow, i.e., when
+ * The value in th_pmcs[] may be modified on overflow, i.e., when
* monitoring needs to be stopped.
*/
if (is_monitor) CTX_USED_MONITOR(ctx, 1UL << cnum);
@@ -3050,7 +3050,7 @@ pfm_write_pmcs(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
/*
* write thread state
*/
- if (is_system == 0) thread->pmcs[cnum] = value;
+ if (is_system == 0) ctx->th_pmcs[cnum] = value;
/*
* write hardware register if we can
@@ -3102,7 +3102,6 @@ error:
static int
pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
{
- struct thread_struct *thread = NULL;
struct task_struct *task;
pfarg_reg_t *req = (pfarg_reg_t *)arg;
unsigned long value, hw_value, ovfl_mask;
@@ -3126,7 +3125,6 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
* the owner of the local PMU.
*/
if (likely(is_loaded)) {
- thread = &task->thread;
/*
* In system wide and when the context is loaded, access can only happen
* when the caller is running on the CPU being monitored by the session.
@@ -3234,7 +3232,7 @@ pfm_write_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
/*
* write thread state
*/
- if (is_system == 0) thread->pmds[cnum] = hw_value;
+ if (is_system == 0) ctx->th_pmds[cnum] = hw_value;
/*
* write hardware register if we can
@@ -3300,7 +3298,6 @@ abort_mission:
static int
pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
{
- struct thread_struct *thread = NULL;
struct task_struct *task;
unsigned long val = 0UL, lval, ovfl_mask, sval;
pfarg_reg_t *req = (pfarg_reg_t *)arg;
@@ -3324,7 +3321,6 @@ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
if (state == PFM_CTX_ZOMBIE) return -EINVAL;
if (likely(is_loaded)) {
- thread = &task->thread;
/*
* In system wide and when the context is loaded, access can only happen
* when the caller is running on the CPU being monitored by the session.
@@ -3386,7 +3382,7 @@ pfm_read_pmds(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
* if context is zombie, then task does not exist anymore.
* In this case, we use the full value saved in the context (pfm_flush_regs()).
*/
- val = is_loaded ? thread->pmds[cnum] : 0UL;
+ val = is_loaded ? ctx->th_pmds[cnum] : 0UL;
}
rd_func = pmu_conf->pmd_desc[cnum].read_check;
@@ -4355,8 +4351,8 @@ pfm_context_load(pfm_context_t *ctx, void *arg, int count, struct pt_regs *regs)
pfm_copy_pmds(task, ctx);
pfm_copy_pmcs(task, ctx);
- pmcs_source = thread->pmcs;
- pmds_source = thread->pmds;
+ pmcs_source = ctx->th_pmcs;
+ pmds_source = ctx->th_pmds;
/*
* always the case for system-wide
@@ -5562,12 +5558,13 @@ report_spurious2:
}
static irqreturn_t
-pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
+pfm_interrupt_handler(int irq, void *arg)
{
unsigned long start_cycles, total_cycles;
unsigned long min, max;
int this_cpu;
int ret;
+ struct pt_regs *regs = get_irq_regs();
this_cpu = get_cpu();
if (likely(!pfm_alt_intr_handler)) {
@@ -5865,14 +5862,12 @@ void
pfm_save_regs(struct task_struct *task)
{
pfm_context_t *ctx;
- struct thread_struct *t;
unsigned long flags;
u64 psr;
ctx = PFM_GET_CTX(task);
if (ctx == NULL) return;
- t = &task->thread;
/*
* we always come here with interrupts ALREADY disabled by
@@ -5930,19 +5925,19 @@ pfm_save_regs(struct task_struct *task)
* guarantee we will be schedule at that same
* CPU again.
*/
- pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]);
+ pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
/*
* save pmc0 ia64_srlz_d() done in pfm_save_pmds()
* we will need it on the restore path to check
* for pending overflow.
*/
- t->pmcs[0] = ia64_get_pmc(0);
+ ctx->th_pmcs[0] = ia64_get_pmc(0);
/*
* unfreeze PMU if had pending overflows
*/
- if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
+ if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
/*
* finally, allow context access.
@@ -5987,7 +5982,6 @@ static void
pfm_lazy_save_regs (struct task_struct *task)
{
pfm_context_t *ctx;
- struct thread_struct *t;
unsigned long flags;
{ u64 psr = pfm_get_psr();
@@ -5995,7 +5989,6 @@ pfm_lazy_save_regs (struct task_struct *task)
}
ctx = PFM_GET_CTX(task);
- t = &task->thread;
/*
* we need to mask PMU overflow here to
@@ -6020,19 +6013,19 @@ pfm_lazy_save_regs (struct task_struct *task)
/*
* save all the pmds we use
*/
- pfm_save_pmds(t->pmds, ctx->ctx_used_pmds[0]);
+ pfm_save_pmds(ctx->th_pmds, ctx->ctx_used_pmds[0]);
/*
* save pmc0 ia64_srlz_d() done in pfm_save_pmds()
* it is needed to check for pended overflow
* on the restore path
*/
- t->pmcs[0] = ia64_get_pmc(0);
+ ctx->th_pmcs[0] = ia64_get_pmc(0);
/*
* unfreeze PMU if had pending overflows
*/
- if (t->pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
+ if (ctx->th_pmcs[0] & ~0x1UL) pfm_unfreeze_pmu();
/*
* now get can unmask PMU interrupts, they will
@@ -6051,7 +6044,6 @@ void
pfm_load_regs (struct task_struct *task)
{
pfm_context_t *ctx;
- struct thread_struct *t;
unsigned long pmc_mask = 0UL, pmd_mask = 0UL;
unsigned long flags;
u64 psr, psr_up;
@@ -6062,11 +6054,10 @@ pfm_load_regs (struct task_struct *task)
BUG_ON(GET_PMU_OWNER());
- t = &task->thread;
/*
* possible on unload
*/
- if (unlikely((t->flags & IA64_THREAD_PM_VALID) == 0)) return;
+ if (unlikely((task->thread.flags & IA64_THREAD_PM_VALID) == 0)) return;
/*
* we always come here with interrupts ALREADY disabled by
@@ -6148,21 +6139,21 @@ pfm_load_regs (struct task_struct *task)
*
* XXX: optimize here
*/
- if (pmd_mask) pfm_restore_pmds(t->pmds, pmd_mask);
- if (pmc_mask) pfm_restore_pmcs(t->pmcs, pmc_mask);
+ if (pmd_mask) pfm_restore_pmds(ctx->th_pmds, pmd_mask);
+ if (pmc_mask) pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
/*
* check for pending overflow at the time the state
* was saved.
*/
- if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
+ if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
/*
* reload pmc0 with the overflow information
* On McKinley PMU, this will trigger a PMU interrupt
*/
- ia64_set_pmc(0, t->pmcs[0]);
+ ia64_set_pmc(0, ctx->th_pmcs[0]);
ia64_srlz_d();
- t->pmcs[0] = 0UL;
+ ctx->th_pmcs[0] = 0UL;
/*
* will replay the PMU interrupt
@@ -6215,7 +6206,6 @@ pfm_load_regs (struct task_struct *task)
void
pfm_load_regs (struct task_struct *task)
{
- struct thread_struct *t;
pfm_context_t *ctx;
struct task_struct *owner;
unsigned long pmd_mask, pmc_mask;
@@ -6224,7 +6214,6 @@ pfm_load_regs (struct task_struct *task)
owner = GET_PMU_OWNER();
ctx = PFM_GET_CTX(task);
- t = &task->thread;
psr = pfm_get_psr();
BUG_ON(psr & (IA64_PSR_UP|IA64_PSR_PP));
@@ -6287,22 +6276,22 @@ pfm_load_regs (struct task_struct *task)
*/
pmc_mask = ctx->ctx_all_pmcs[0];
- pfm_restore_pmds(t->pmds, pmd_mask);
- pfm_restore_pmcs(t->pmcs, pmc_mask);
+ pfm_restore_pmds(ctx->th_pmds, pmd_mask);
+ pfm_restore_pmcs(ctx->th_pmcs, pmc_mask);
/*
* check for pending overflow at the time the state
* was saved.
*/
- if (unlikely(PMC0_HAS_OVFL(t->pmcs[0]))) {
+ if (unlikely(PMC0_HAS_OVFL(ctx->th_pmcs[0]))) {
/*
* reload pmc0 with the overflow information
* On McKinley PMU, this will trigger a PMU interrupt
*/
- ia64_set_pmc(0, t->pmcs[0]);
+ ia64_set_pmc(0, ctx->th_pmcs[0]);
ia64_srlz_d();
- t->pmcs[0] = 0UL;
+ ctx->th_pmcs[0] = 0UL;
/*
* will replay the PMU interrupt
@@ -6377,11 +6366,11 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
*/
pfm_unfreeze_pmu();
} else {
- pmc0 = task->thread.pmcs[0];
+ pmc0 = ctx->th_pmcs[0];
/*
* clear whatever overflow status bits there were
*/
- task->thread.pmcs[0] = 0;
+ ctx->th_pmcs[0] = 0;
}
ovfl_val = pmu_conf->ovfl_val;
/*
@@ -6402,7 +6391,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
/*
* can access PMU always true in system wide mode
*/
- val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : task->thread.pmds[i];
+ val = pmd_val = can_access_pmu ? ia64_get_pmd(i) : ctx->th_pmds[i];
if (PMD_IS_COUNTING(i)) {
DPRINT(("[%d] pmd[%d] ctx_pmd=0x%lx hw_pmd=0x%lx\n",
@@ -6434,7 +6423,7 @@ pfm_flush_pmds(struct task_struct *task, pfm_context_t *ctx)
DPRINT(("[%d] ctx_pmd[%d]=0x%lx pmd_val=0x%lx\n", task->pid, i, val, pmd_val));
- if (is_self) task->thread.pmds[i] = pmd_val;
+ if (is_self) ctx->th_pmds[i] = pmd_val;
ctx->ctx_pmds[i].val = val;
}
@@ -6678,7 +6667,7 @@ pfm_init(void)
ffz(pmu_conf->ovfl_val));
/* sanity check */
- if (pmu_conf->num_pmds >= IA64_NUM_PMD_REGS || pmu_conf->num_pmcs >= IA64_NUM_PMC_REGS) {
+ if (pmu_conf->num_pmds >= PFM_NUM_PMD_REGS || pmu_conf->num_pmcs >= PFM_NUM_PMC_REGS) {
printk(KERN_ERR "perfmon: not enough pmc/pmd, perfmon disabled\n");
pmu_conf = NULL;
return -1;
@@ -6753,7 +6742,6 @@ void
dump_pmu_state(const char *from)
{
struct task_struct *task;
- struct thread_struct *t;
struct pt_regs *regs;
pfm_context_t *ctx;
unsigned long psr, dcr, info, flags;
@@ -6798,16 +6786,14 @@ dump_pmu_state(const char *from)
ia64_psr(regs)->up = 0;
ia64_psr(regs)->pp = 0;
- t = &current->thread;
-
for (i=1; PMC_IS_LAST(i) == 0; i++) {
if (PMC_IS_IMPL(i) == 0) continue;
- printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, t->pmcs[i]);
+ printk("->CPU%d pmc[%d]=0x%lx thread_pmc[%d]=0x%lx\n", this_cpu, i, ia64_get_pmc(i), i, ctx->th_pmcs[i]);
}
for (i=1; PMD_IS_LAST(i) == 0; i++) {
if (PMD_IS_IMPL(i) == 0) continue;
- printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, t->pmds[i]);
+ printk("->CPU%d pmd[%d]=0x%lx thread_pmd[%d]=0x%lx\n", this_cpu, i, ia64_get_pmd(i), i, ctx->th_pmds[i]);
}
if (ctx) {
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index ea914cc6812a..51922b98086a 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -8,8 +8,6 @@
* 2005-10-07 Keith Owens <kaos@sgi.com>
* Add notify_die() hooks.
*/
-#define __KERNEL_SYSCALLS__ /* see <asm/unistd.h> */
-
#include <linux/cpu.h>
#include <linux/pm.h>
#include <linux/elf.h>
diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
index 9065f0f01ba3..e63b8ca5344a 100644
--- a/arch/ia64/kernel/salinfo.c
+++ b/arch/ia64/kernel/salinfo.c
@@ -266,6 +266,7 @@ salinfo_log_wakeup(int type, u8 *buffer, u64 size, int irqsafe)
/* Check for outstanding MCA/INIT records every minute (arbitrary) */
#define SALINFO_TIMER_DELAY (60*HZ)
static struct timer_list salinfo_timer;
+extern void ia64_mlogbuf_dump(void);
static void
salinfo_timeout_check(struct salinfo_data *data)
@@ -283,6 +284,7 @@ salinfo_timeout_check(struct salinfo_data *data)
static void
salinfo_timeout (unsigned long arg)
{
+ ia64_mlogbuf_dump();
salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_MCA);
salinfo_timeout_check(salinfo_data + SAL_INFO_TYPE_INIT);
salinfo_timer.expires = jiffies + SALINFO_TIMER_DELAY;
@@ -332,6 +334,8 @@ retry:
if (cpu == -1)
goto retry;
+ ia64_mlogbuf_dump();
+
/* for next read, start checking at next CPU */
data->cpu_check = cpu;
if (++data->cpu_check == NR_CPUS)
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index 7ad0d9cc6db6..c4caa8003492 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -54,7 +54,6 @@
#include <asm/processor.h>
#include <asm/sal.h>
#include <asm/sections.h>
-#include <asm/serial.h>
#include <asm/setup.h>
#include <asm/smp.h>
#include <asm/system.h>
@@ -509,7 +508,7 @@ show_cpuinfo (struct seq_file *m, void *v)
{ 1UL << 1, "spontaneous deferral"},
{ 1UL << 2, "16-byte atomic ops" }
};
- char family[32], features[128], *cp, sep;
+ char features[128], *cp, sep;
struct cpuinfo_ia64 *c = v;
unsigned long mask;
unsigned long proc_freq;
@@ -517,12 +516,6 @@ show_cpuinfo (struct seq_file *m, void *v)
mask = c->features;
- switch (c->family) {
- case 0x07: memcpy(family, "Itanium", 8); break;
- case 0x1f: memcpy(family, "Itanium 2", 10); break;
- default: sprintf(family, "%u", c->family); break;
- }
-
/* build the feature string: */
memcpy(features, " standard", 10);
cp = features;
@@ -553,8 +546,9 @@ show_cpuinfo (struct seq_file *m, void *v)
"processor : %d\n"
"vendor : %s\n"
"arch : IA-64\n"
- "family : %s\n"
+ "family : %u\n"
"model : %u\n"
+ "model name : %s\n"
"revision : %u\n"
"archrev : %u\n"
"features :%s\n" /* don't change this---it _is_ right! */
@@ -563,7 +557,8 @@ show_cpuinfo (struct seq_file *m, void *v)
"cpu MHz : %lu.%06lu\n"
"itc MHz : %lu.%06lu\n"
"BogoMIPS : %lu.%02lu\n",
- cpunum, c->vendor, family, c->model, c->revision, c->archrev,
+ cpunum, c->vendor, c->family, c->model,
+ c->model_name, c->revision, c->archrev,
features, c->ppn, c->number,
proc_freq / 1000, proc_freq % 1000,
c->itc_freq / 1000000, c->itc_freq % 1000000,
@@ -611,6 +606,31 @@ struct seq_operations cpuinfo_op = {
.show = show_cpuinfo
};
+static char brandname[128];
+
+static char * __cpuinit
+get_model_name(__u8 family, __u8 model)
+{
+ char brand[128];
+
+ if (ia64_pal_get_brand_info(brand)) {
+ if (family == 0x7)
+ memcpy(brand, "Merced", 7);
+ else if (family == 0x1f) switch (model) {
+ case 0: memcpy(brand, "McKinley", 9); break;
+ case 1: memcpy(brand, "Madison", 8); break;
+ case 2: memcpy(brand, "Madison up to 9M cache", 23); break;
+ } else
+ memcpy(brand, "Unknown", 8);
+ }
+ if (brandname[0] == '\0')
+ return strcpy(brandname, brand);
+ else if (strcmp(brandname, brand) == 0)
+ return brandname;
+ else
+ return kstrdup(brand, GFP_KERNEL);
+}
+
static void __cpuinit
identify_cpu (struct cpuinfo_ia64 *c)
{
@@ -640,7 +660,6 @@ identify_cpu (struct cpuinfo_ia64 *c)
pal_status_t status;
unsigned long impl_va_msb = 50, phys_addr_size = 44; /* Itanium defaults */
int i;
-
for (i = 0; i < 5; ++i)
cpuid.bits[i] = ia64_get_cpuid(i);
@@ -663,6 +682,7 @@ identify_cpu (struct cpuinfo_ia64 *c)
c->family = cpuid.field.family;
c->archrev = cpuid.field.archrev;
c->features = cpuid.field.features;
+ c->model_name = get_model_name(c->family, c->model);
status = ia64_pal_vm_summary(&vm1, &vm2);
if (status == PAL_STATUS_SUCCESS) {
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 6203ed4ec8cf..f7d7f5668144 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -879,3 +879,27 @@ identify_siblings(struct cpuinfo_ia64 *c)
c->core_id = info.log1_cid;
c->thread_id = info.log1_tid;
}
+
+/*
+ * returns non zero, if multi-threading is enabled
+ * on at least one physical package. Due to hotplug cpu
+ * and (maxcpus=), all threads may not necessarily be enabled
+ * even though the processor supports multi-threading.
+ */
+int is_multithreading_enabled(void)
+{
+ int i, j;
+
+ for_each_present_cpu(i) {
+ for_each_present_cpu(j) {
+ if (j == i)
+ continue;
+ if ((cpu_data(j)->socket_id == cpu_data(i)->socket_id)) {
+ if (cpu_data(j)->core_id == cpu_data(i)->core_id)
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(is_multithreading_enabled);
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 6928ef0d64d8..39e0cd3a0884 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -29,8 +29,6 @@
#include <asm/sections.h>
#include <asm/system.h>
-extern unsigned long wall_jiffies;
-
volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
#ifdef CONFIG_IA64_DEBUG_IRQ
@@ -47,7 +45,7 @@ static struct time_interpolator itc_interpolator = {
};
static irqreturn_t
-timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+timer_interrupt (int irq, void *dev_id)
{
unsigned long new_itm;
@@ -55,7 +53,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
- platform_timer_interrupt(irq, dev_id, regs);
+ platform_timer_interrupt(irq, dev_id);
new_itm = local_cpu_data->itm_next;
@@ -63,10 +61,10 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
printk(KERN_ERR "Oops: timer tick before it's due (itc=%lx,itm=%lx)\n",
ia64_get_itc(), new_itm);
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
while (1) {
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
new_itm += local_cpu_data->itm_delta;
@@ -78,7 +76,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
* xtime_lock.
*/
write_seqlock(&xtime_lock);
- do_timer(regs);
+ do_timer(1);
local_cpu_data->itm_next = new_itm;
write_sequnlock(&xtime_lock);
} else
@@ -86,6 +84,12 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
if (time_after(new_itm, ia64_get_itc()))
break;
+
+ /*
+ * Allow IPIs to interrupt the timer loop.
+ */
+ local_irq_enable();
+ local_irq_disable();
}
do {
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 05bdf7affb43..5629b45e89c6 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -36,10 +36,8 @@ int arch_register_cpu(int num)
*/
if (!can_cpei_retarget() && is_cpu_cpei_target(num))
sysfs_cpus[num].cpu.no_control = 1;
-#ifdef CONFIG_NUMA
map_cpu_to_node(num, node_cpuid[num].nid);
#endif
-#endif
return register_cpu(&sysfs_cpus[num].cpu, num);
}
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 5b0d5f64a9b1..b3b2e389d6b2 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -184,7 +184,9 @@ SECTIONS
*(.data.gate)
__stop_gate_section = .;
}
- . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose kernel data */
+ . = ALIGN(PAGE_SIZE); /* make sure the gate page doesn't expose
+ * kernel data
+ */
.data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET)
{ *(.data.read_mostly) }
@@ -202,7 +204,9 @@ SECTIONS
*(.data.percpu)
__per_cpu_end = .;
}
- . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits into percpu page size */
+ . = __phys_per_cpu_start + PERCPU_PAGE_SIZE; /* ensure percpu data fits
+ * into percpu page size
+ */
data : { } :data
.data : AT(ADDR(.data) - LOAD_OFFSET)
diff --git a/arch/ia64/mm/contig.c b/arch/ia64/mm/contig.c
index e004143ba86b..82deaa3a7c48 100644
--- a/arch/ia64/mm/contig.c
+++ b/arch/ia64/mm/contig.c
@@ -26,7 +26,6 @@
#include <asm/mca.h>
#ifdef CONFIG_VIRTUAL_MEM_MAP
-static unsigned long num_dma_physpages;
static unsigned long max_gap;
#endif
@@ -41,10 +40,11 @@ show_mem (void)
int i, total = 0, reserved = 0;
int shared = 0, cached = 0;
- printk("Mem-info:\n");
+ printk(KERN_INFO "Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ printk(KERN_INFO "Free swap: %6ldkB\n",
+ nr_swap_pages<<(PAGE_SHIFT-10));
i = max_mapnr;
for (i = 0; i < max_mapnr; i++) {
if (!pfn_valid(i)) {
@@ -63,12 +63,12 @@ show_mem (void)
else if (page_count(mem_map + i))
shared += page_count(mem_map + i) - 1;
}
- printk("%d pages of RAM\n", total);
- printk("%d reserved pages\n", reserved);
- printk("%d pages shared\n", shared);
- printk("%d pages swap cached\n", cached);
- printk("%ld pages in page table cache\n",
- pgtable_quicklist_total_size());
+ printk(KERN_INFO "%d pages of RAM\n", total);
+ printk(KERN_INFO "%d reserved pages\n", reserved);
+ printk(KERN_INFO "%d pages shared\n", shared);
+ printk(KERN_INFO "%d pages swap cached\n", cached);
+ printk(KERN_INFO "%ld pages in page table cache\n",
+ pgtable_quicklist_total_size());
}
/* physical address where the bootmem map is located */
@@ -218,18 +218,6 @@ count_pages (u64 start, u64 end, void *arg)
return 0;
}
-#ifdef CONFIG_VIRTUAL_MEM_MAP
-static int
-count_dma_pages (u64 start, u64 end, void *arg)
-{
- unsigned long *count = arg;
-
- if (start < MAX_DMA_ADDRESS)
- *count += (min(end, MAX_DMA_ADDRESS) - start) >> PAGE_SHIFT;
- return 0;
-}
-#endif
-
/*
* Set up the page tables.
*/
@@ -238,45 +226,23 @@ void __init
paging_init (void)
{
unsigned long max_dma;
- unsigned long zones_size[MAX_NR_ZONES];
-#ifdef CONFIG_VIRTUAL_MEM_MAP
- unsigned long zholes_size[MAX_NR_ZONES];
-#endif
-
- /* initialize mem_map[] */
-
- memset(zones_size, 0, sizeof(zones_size));
+ unsigned long nid = 0;
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
num_physpages = 0;
efi_memmap_walk(count_pages, &num_physpages);
max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = max_dma;
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
#ifdef CONFIG_VIRTUAL_MEM_MAP
- memset(zholes_size, 0, sizeof(zholes_size));
-
- num_dma_physpages = 0;
- efi_memmap_walk(count_dma_pages, &num_dma_physpages);
-
- if (max_low_pfn < max_dma) {
- zones_size[ZONE_DMA] = max_low_pfn;
- zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
- } else {
- zones_size[ZONE_DMA] = max_dma;
- zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
- if (num_physpages > num_dma_physpages) {
- zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
- zholes_size[ZONE_NORMAL] =
- ((max_low_pfn - max_dma) -
- (num_physpages - num_dma_physpages));
- }
- }
-
+ efi_memmap_walk(register_active_ranges, &nid);
efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
if (max_gap < LARGE_GAP) {
vmem_map = (struct page *) 0;
- free_area_init_node(0, NODE_DATA(0), zones_size, 0,
- zholes_size);
+ free_area_init_nodes(max_zone_pfns);
} else {
unsigned long map_size;
@@ -288,20 +254,19 @@ paging_init (void)
vmem_map = (struct page *) vmalloc_end;
efi_memmap_walk(create_mem_map_page_table, NULL);
- NODE_DATA(0)->node_mem_map = vmem_map;
- free_area_init_node(0, NODE_DATA(0), zones_size,
- 0, zholes_size);
+ /*
+ * alloc_node_mem_map makes an adjustment for mem_map
+ * which isn't compatible with vmem_map.
+ */
+ NODE_DATA(0)->node_mem_map = vmem_map +
+ find_min_pfn_with_active_regions();
+ free_area_init_nodes(max_zone_pfns);
printk("Virtual mem_map starts at 0x%p\n", mem_map);
}
#else /* !CONFIG_VIRTUAL_MEM_MAP */
- if (max_low_pfn < max_dma)
- zones_size[ZONE_DMA] = max_low_pfn;
- else {
- zones_size[ZONE_DMA] = max_dma;
- zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
- }
- free_area_init(zones_size);
+ add_active_range(0, 0, max_low_pfn);
+ free_area_init_nodes(max_zone_pfns);
#endif /* !CONFIG_VIRTUAL_MEM_MAP */
zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
}
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index d260bffa01ab..96722cb1b49d 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -547,15 +547,16 @@ void show_mem(void)
unsigned long total_present = 0;
pg_data_t *pgdat;
- printk("Mem-info:\n");
+ printk(KERN_INFO "Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ printk(KERN_INFO "Free swap: %6ldkB\n",
+ nr_swap_pages<<(PAGE_SHIFT-10));
+ printk(KERN_INFO "Node memory in pages:\n");
for_each_online_pgdat(pgdat) {
unsigned long present;
unsigned long flags;
int shared = 0, cached = 0, reserved = 0;
- printk("Node ID: %d\n", pgdat->node_id);
pgdat_resize_lock(pgdat, &flags);
present = pgdat->node_present_pages;
for(i = 0; i < pgdat->node_spanned_pages; i++) {
@@ -579,18 +580,17 @@ void show_mem(void)
total_reserved += reserved;
total_cached += cached;
total_shared += shared;
- printk("\t%ld pages of RAM\n", present);
- printk("\t%d reserved pages\n", reserved);
- printk("\t%d pages shared\n", shared);
- printk("\t%d pages swap cached\n", cached);
+ printk(KERN_INFO "Node %4d: RAM: %11ld, rsvd: %8d, "
+ "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+ present, reserved, shared, cached);
}
- printk("%ld pages of RAM\n", total_present);
- printk("%d reserved pages\n", total_reserved);
- printk("%d pages shared\n", total_shared);
- printk("%d pages swap cached\n", total_cached);
- printk("Total of %ld pages in page table cache\n",
- pgtable_quicklist_total_size());
- printk("%d free buffer pages\n", nr_free_buffer_pages());
+ printk(KERN_INFO "%ld pages of RAM\n", total_present);
+ printk(KERN_INFO "%d reserved pages\n", total_reserved);
+ printk(KERN_INFO "%d pages shared\n", total_shared);
+ printk(KERN_INFO "%d pages swap cached\n", total_cached);
+ printk(KERN_INFO "Total of %ld pages in page table cache\n",
+ pgtable_quicklist_total_size());
+ printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages());
}
/**
@@ -654,6 +654,7 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n
{
unsigned long end = start + len;
+ add_active_range(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT);
mem_data[node].num_physpages += len >> PAGE_SHIFT;
if (start <= __pa(MAX_DMA_ADDRESS))
mem_data[node].num_dma_physpages +=
@@ -678,10 +679,10 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n
void __init paging_init(void)
{
unsigned long max_dma;
- unsigned long zones_size[MAX_NR_ZONES];
- unsigned long zholes_size[MAX_NR_ZONES];
unsigned long pfn_offset = 0;
+ unsigned long max_pfn = 0;
int node;
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
@@ -698,47 +699,21 @@ void __init paging_init(void)
#endif
for_each_online_node(node) {
- memset(zones_size, 0, sizeof(zones_size));
- memset(zholes_size, 0, sizeof(zholes_size));
-
num_physpages += mem_data[node].num_physpages;
-
- if (mem_data[node].min_pfn >= max_dma) {
- /* All of this node's memory is above ZONE_DMA */
- zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
- mem_data[node].min_pfn;
- zholes_size[ZONE_NORMAL] = mem_data[node].max_pfn -
- mem_data[node].min_pfn -
- mem_data[node].num_physpages;
- } else if (mem_data[node].max_pfn < max_dma) {
- /* All of this node's memory is in ZONE_DMA */
- zones_size[ZONE_DMA] = mem_data[node].max_pfn -
- mem_data[node].min_pfn;
- zholes_size[ZONE_DMA] = mem_data[node].max_pfn -
- mem_data[node].min_pfn -
- mem_data[node].num_dma_physpages;
- } else {
- /* This node has memory in both zones */
- zones_size[ZONE_DMA] = max_dma -
- mem_data[node].min_pfn;
- zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] -
- mem_data[node].num_dma_physpages;
- zones_size[ZONE_NORMAL] = mem_data[node].max_pfn -
- max_dma;
- zholes_size[ZONE_NORMAL] = zones_size[ZONE_NORMAL] -
- (mem_data[node].num_physpages -
- mem_data[node].num_dma_physpages);
- }
-
pfn_offset = mem_data[node].min_pfn;
#ifdef CONFIG_VIRTUAL_MEM_MAP
NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset;
#endif
- free_area_init_node(node, NODE_DATA(node), zones_size,
- pfn_offset, zholes_size);
+ if (mem_data[node].max_pfn > max_pfn)
+ max_pfn = mem_data[node].max_pfn;
}
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = max_dma;
+ max_zone_pfns[ZONE_NORMAL] = max_pfn;
+ free_area_init_nodes(max_zone_pfns);
+
zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
}
diff --git a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
index 14ef7cceb208..59f3ab937615 100644
--- a/arch/ia64/mm/fault.c
+++ b/arch/ia64/mm/fault.c
@@ -146,9 +146,11 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
# error File is out of sync with <linux/mm.h>. Please update.
# endif
+ if (((isr >> IA64_ISR_R_BIT) & 1UL) && (!(vma->vm_flags & (VM_READ | VM_WRITE))))
+ goto bad_area;
+
mask = ( (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT)
- | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT)
- | (((isr >> IA64_ISR_R_BIT) & 1UL) << VM_READ_BIT));
+ | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT));
if ((vma->vm_flags & mask) != mask)
goto bad_area;
@@ -278,7 +280,7 @@ ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *re
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 30617ccb4f7e..ff87a5cba399 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -593,6 +593,18 @@ find_largest_hole (u64 start, u64 end, void *arg)
last_end = end;
return 0;
}
+
+int __init
+register_active_ranges(u64 start, u64 end, void *nid)
+{
+ BUG_ON(nid == NULL);
+ BUG_ON(*(unsigned long *)nid >= MAX_NUMNODES);
+
+ add_active_range(*(unsigned long *)nid,
+ __pa(start) >> PAGE_SHIFT,
+ __pa(end) >> PAGE_SHIFT);
+ return 0;
+}
#endif /* CONFIG_VIRTUAL_MEM_MAP */
static int __init
diff --git a/arch/ia64/mm/numa.c b/arch/ia64/mm/numa.c
index 64e4c21f311c..7807fc5c0422 100644
--- a/arch/ia64/mm/numa.c
+++ b/arch/ia64/mm/numa.c
@@ -16,6 +16,7 @@
#include <linux/node.h>
#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/module.h>
#include <asm/mmzone.h>
#include <asm/numa.h>
@@ -69,4 +70,21 @@ int early_pfn_to_nid(unsigned long pfn)
return 0;
}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * SRAT information is stored in node_memblk[], then we can use SRAT
+ * information at memory-hot-add if necessary.
+ */
+
+int memory_add_physaddr_to_nid(u64 addr)
+{
+ int nid = paddr_to_nid(addr);
+ if (nid < 0)
+ return 0;
+ return nid;
+}
+
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+#endif
#endif
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 60b45e79f080..b30be7c48ba8 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -562,7 +562,8 @@ pcibios_enable_device (struct pci_dev *dev, int mask)
void
pcibios_disable_device (struct pci_dev *dev)
{
- acpi_pci_irq_disable(dev);
+ if (dev->is_enabled)
+ acpi_pci_irq_disable(dev);
}
void
@@ -809,12 +810,3 @@ pcibios_prep_mwi (struct pci_dev *dev)
}
return rc;
}
-
-int pci_vector_resources(int last, int nr_released)
-{
- int count = nr_released;
-
- count += (IA64_LAST_DEVICE_VECTOR - last);
-
- return count;
-}
diff --git a/arch/ia64/sn/kernel/Makefile b/arch/ia64/sn/kernel/Makefile
index ab9c48c88012..2d78f34dd763 100644
--- a/arch/ia64/sn/kernel/Makefile
+++ b/arch/ia64/sn/kernel/Makefile
@@ -19,3 +19,4 @@ xp-y := xp_main.o xp_nofault.o
obj-$(CONFIG_IA64_SGI_SN_XP) += xpc.o
xpc-y := xpc_main.o xpc_channel.o xpc_partition.o
obj-$(CONFIG_IA64_SGI_SN_XP) += xpnet.o
+obj-$(CONFIG_PCI_MSI) += msi_sn.o
diff --git a/arch/ia64/sn/kernel/bte.c b/arch/ia64/sn/kernel/bte.c
index 27dee4584061..7f73ad4408aa 100644
--- a/arch/ia64/sn/kernel/bte.c
+++ b/arch/ia64/sn/kernel/bte.c
@@ -277,8 +277,7 @@ bte_result_t bte_unaligned_copy(u64 src, u64 dest, u64 len, u64 mode)
}
/* temporary buffer used during unaligned transfers */
- bteBlock_unaligned = kmalloc(len + 3 * L1_CACHE_BYTES,
- GFP_KERNEL | GFP_DMA);
+ bteBlock_unaligned = kmalloc(len + 3 * L1_CACHE_BYTES, GFP_KERNEL);
if (bteBlock_unaligned == NULL) {
return BTEFAIL_NOTAVAIL;
}
diff --git a/arch/ia64/sn/kernel/huberror.c b/arch/ia64/sn/kernel/huberror.c
index 96fb81e6321f..abca6bd7962f 100644
--- a/arch/ia64/sn/kernel/huberror.c
+++ b/arch/ia64/sn/kernel/huberror.c
@@ -22,7 +22,7 @@
void hubiio_crb_error_handler(struct hubdev_info *hubdev_info);
extern void bte_crb_error_handler(cnodeid_t, int, int, ioerror_t *,
int);
-static irqreturn_t hub_eint_handler(int irq, void *arg, struct pt_regs *ep)
+static irqreturn_t hub_eint_handler(int irq, void *arg)
{
struct hubdev_info *hubdev_info;
struct ia64_sal_retval ret_stuff;
@@ -178,7 +178,7 @@ void hubiio_crb_error_handler(struct hubdev_info *hubdev_info)
*/
void hub_error_init(struct hubdev_info *hubdev_info)
{
- if (request_irq(SGI_II_ERROR, (void *)hub_eint_handler, IRQF_SHARED,
+ if (request_irq(SGI_II_ERROR, hub_eint_handler, IRQF_SHARED,
"SN_hub_error", (void *)hubdev_info))
printk("hub_error_init: Failed to request_irq for 0x%p\n",
hubdev_info);
diff --git a/drivers/pci/msi-altix.c b/arch/ia64/sn/kernel/msi_sn.c
index bed4183a5e39..6ffd1f850d41 100644
--- a/drivers/pci/msi-altix.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -7,8 +7,10 @@
*/
#include <linux/types.h>
+#include <linux/irq.h>
#include <linux/pci.h>
#include <linux/cpumask.h>
+#include <linux/msi.h>
#include <asm/sn/addrs.h>
#include <asm/sn/intr.h>
@@ -16,17 +18,16 @@
#include <asm/sn/pcidev.h>
#include <asm/sn/nodepda.h>
-#include "msi.h"
-
struct sn_msi_info {
u64 pci_addr;
struct sn_irq_info *sn_irq_info;
};
-static struct sn_msi_info *sn_msi_info;
+static struct sn_msi_info sn_msi_info[NR_IRQS];
+
+static struct irq_chip sn_msi_chip;
-static void
-sn_msi_teardown(unsigned int vector)
+void sn_teardown_msi_irq(unsigned int irq)
{
nasid_t nasid;
int widget;
@@ -36,7 +37,7 @@ sn_msi_teardown(unsigned int vector)
struct pcibus_bussoft *bussoft;
struct sn_pcibus_provider *provider;
- sn_irq_info = sn_msi_info[vector].sn_irq_info;
+ sn_irq_info = sn_msi_info[irq].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return;
@@ -45,9 +46,9 @@ sn_msi_teardown(unsigned int vector)
provider = SN_PCIDEV_BUSPROVIDER(pdev);
(*provider->dma_unmap)(pdev,
- sn_msi_info[vector].pci_addr,
+ sn_msi_info[irq].pci_addr,
PCI_DMA_FROMDEVICE);
- sn_msi_info[vector].pci_addr = 0;
+ sn_msi_info[irq].pci_addr = 0;
bussoft = SN_PCIDEV_BUSSOFT(pdev);
nasid = NASID_GET(bussoft->bs_base);
@@ -56,15 +57,15 @@ sn_msi_teardown(unsigned int vector)
SWIN_WIDGETNUM(bussoft->bs_base);
sn_intr_free(nasid, widget, sn_irq_info);
- sn_msi_info[vector].sn_irq_info = NULL;
+ sn_msi_info[irq].sn_irq_info = NULL;
return;
}
-int
-sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
- u32 *addr_hi, u32 *addr_lo, u32 *data)
+int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
{
+ struct msi_msg msg;
+ struct msi_desc *entry;
int widget;
int status;
nasid_t nasid;
@@ -73,6 +74,10 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+ entry = get_irq_data(irq);
+ if (!entry->msi_attrib.is_64)
+ return -EINVAL;
+
if (bussoft == NULL)
return -EINVAL;
@@ -93,7 +98,7 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
if (! sn_irq_info)
return -ENOMEM;
- status = sn_intr_alloc(nasid, widget, sn_irq_info, vector, -1, -1);
+ status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
if (status) {
kfree(sn_irq_info);
return -ENOMEM;
@@ -119,29 +124,32 @@ sn_msi_setup(struct pci_dev *pdev, unsigned int vector,
return -ENOMEM;
}
- sn_msi_info[vector].sn_irq_info = sn_irq_info;
- sn_msi_info[vector].pci_addr = bus_addr;
+ sn_msi_info[irq].sn_irq_info = sn_irq_info;
+ sn_msi_info[irq].pci_addr = bus_addr;
- *addr_hi = (u32)(bus_addr >> 32);
- *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+ msg.address_hi = (u32)(bus_addr >> 32);
+ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
/*
* In the SN platform, bit 16 is a "send vector" bit which
* must be present in order to move the vector through the system.
*/
- *data = 0x100 + (unsigned int)vector;
+ msg.data = 0x100 + irq;
#ifdef CONFIG_SMP
- set_irq_affinity_info((vector & 0xff), sn_irq_info->irq_cpuid, 0);
+ set_irq_affinity_info(irq, sn_irq_info->irq_cpuid, 0);
#endif
+ write_msi_msg(irq, &msg);
+ set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
+
return 0;
}
-static void
-sn_msi_target(unsigned int vector, unsigned int cpu,
- u32 *addr_hi, u32 *addr_lo)
+#ifdef CONFIG_SMP
+static void sn_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
{
+ struct msi_msg msg;
int slice;
nasid_t nasid;
u64 bus_addr;
@@ -150,8 +158,10 @@ sn_msi_target(unsigned int vector, unsigned int cpu,
struct sn_irq_info *sn_irq_info;
struct sn_irq_info *new_irq_info;
struct sn_pcibus_provider *provider;
+ unsigned int cpu;
- sn_irq_info = sn_msi_info[vector].sn_irq_info;
+ cpu = first_cpu(cpu_mask);
+ sn_irq_info = sn_msi_info[irq].sn_irq_info;
if (sn_irq_info == NULL || sn_irq_info->irq_int_bit >= 0)
return;
@@ -159,19 +169,20 @@ sn_msi_target(unsigned int vector, unsigned int cpu,
* Release XIO resources for the old MSI PCI address
*/
+ read_msi_msg(irq, &msg);
sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
pdev = sn_pdev->pdi_linux_pcidev;
provider = SN_PCIDEV_BUSPROVIDER(pdev);
- bus_addr = (u64)(*addr_hi) << 32 | (u64)(*addr_lo);
+ bus_addr = (u64)(msg.address_hi) << 32 | (u64)(msg.address_lo);
(*provider->dma_unmap)(pdev, bus_addr, PCI_DMA_FROMDEVICE);
- sn_msi_info[vector].pci_addr = 0;
+ sn_msi_info[irq].pci_addr = 0;
nasid = cpuid_to_nasid(cpu);
slice = cpuid_to_slice(cpu);
new_irq_info = sn_retarget_vector(sn_irq_info, nasid, slice);
- sn_msi_info[vector].sn_irq_info = new_irq_info;
+ sn_msi_info[irq].sn_irq_info = new_irq_info;
if (new_irq_info == NULL)
return;
@@ -184,27 +195,36 @@ sn_msi_target(unsigned int vector, unsigned int cpu,
sizeof(new_irq_info->irq_xtalkaddr),
SN_DMA_MSI|SN_DMA_ADDR_XIO);
- sn_msi_info[vector].pci_addr = bus_addr;
- *addr_hi = (u32)(bus_addr >> 32);
- *addr_lo = (u32)(bus_addr & 0x00000000ffffffff);
+ sn_msi_info[irq].pci_addr = bus_addr;
+ msg.address_hi = (u32)(bus_addr >> 32);
+ msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, cpu_mask);
}
+#endif /* CONFIG_SMP */
-struct msi_ops sn_msi_ops = {
- .setup = sn_msi_setup,
- .teardown = sn_msi_teardown,
-#ifdef CONFIG_SMP
- .target = sn_msi_target,
-#endif
-};
+static void sn_ack_msi_irq(unsigned int irq)
+{
+ move_native_irq(irq);
+ ia64_eoi();
+}
-int
-sn_msi_init(void)
+static int sn_msi_retrigger_irq(unsigned int irq)
{
- sn_msi_info =
- kzalloc(sizeof(struct sn_msi_info) * NR_VECTORS, GFP_KERNEL);
- if (! sn_msi_info)
- return -ENOMEM;
+ unsigned int vector = irq;
+ ia64_resend_irq(vector);
- msi_register(&sn_msi_ops);
- return 0;
+ return 1;
}
+
+static struct irq_chip sn_msi_chip = {
+ .name = "PCI-MSI",
+ .mask = mask_msi_irq,
+ .unmask = unmask_msi_irq,
+ .ack = sn_ack_msi_irq,
+#ifdef CONFIG_SMP
+ .set_affinity = sn_set_msi_irq_affinity,
+#endif
+ .retrigger = sn_msi_retrigger_irq,
+};
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 5f2dcba7fa8d..7a2d824c5ce3 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -65,7 +65,6 @@ extern void sn_timer_init(void);
extern unsigned long last_time_offset;
extern void (*ia64_mark_idle) (int);
extern void snidle(int);
-extern unsigned char acpi_kbd_controller_present;
extern unsigned long long (*ia64_printk_clock)(void);
unsigned long sn_rtc_cycles_per_second;
@@ -452,17 +451,6 @@ void __init sn_setup(char **cmdline_p)
ia64_printk_clock = ia64_sn2_printk_clock;
- /*
- * Old PROMs do not provide an ACPI FADT. Disable legacy keyboard
- * support here so we don't have to listen to failed keyboard probe
- * messages.
- */
- if (is_shub1() && version <= 0x0209 && acpi_kbd_controller_present) {
- printk(KERN_INFO "Disabling legacy keyboard support as prom "
- "is too old and doesn't provide FADT\n");
- acpi_kbd_controller_present = 0;
- }
-
printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);
/*
diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
index b632b9c1e3b3..462ea178f49a 100644
--- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c
+++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c
@@ -423,7 +423,7 @@ static int sn_topology_show(struct seq_file *s, void *d)
"coherency_domain %d, "
"region_size %d\n",
- partid, system_utsname.nodename,
+ partid, utsname()->nodename,
shubtype ? "shub2" : "shub1",
(u64)nasid_mask << nasid_shift, nasid_msb, nasid_shift,
system_size, sharing_size, coher, region_size);
diff --git a/arch/ia64/sn/kernel/sn2/timer_interrupt.c b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
index fa7f69945917..103d6ea8e94b 100644
--- a/arch/ia64/sn/kernel/sn2/timer_interrupt.c
+++ b/arch/ia64/sn/kernel/sn2/timer_interrupt.c
@@ -36,7 +36,7 @@ extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
#define SN_LB_INT_WAR_INTERVAL 100
-void sn_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+void sn_timer_interrupt(int irq, void *dev_id)
{
/* LED blinking */
if (!pda->hb_count--) {
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index 4d026f9dd98b..fa96dfc0e1aa 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -222,7 +222,7 @@ xpc_timeout_partition_disengage_request(unsigned long data)
* Notify the heartbeat check thread that an IRQ has been received.
*/
static irqreturn_t
-xpc_act_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs)
+xpc_act_IRQ_handler(int irq, void *dev_id)
{
atomic_inc(&xpc_act_IRQ_rcvd);
wake_up_interruptible(&xpc_act_IRQ_wq);
@@ -607,12 +607,9 @@ xpc_activate_partition(struct xpc_partition *part)
* irq - Interrupt ReQuest number. NOT USED.
*
* dev_id - partid of IPI's potential sender.
- *
- * regs - processor's context before the processor entered
- * interrupt code. NOT USED.
*/
irqreturn_t
-xpc_notify_IRQ_handler(int irq, void *dev_id, struct pt_regs *regs)
+xpc_notify_IRQ_handler(int irq, void *dev_id)
{
partid_t partid = (partid_t) (u64) dev_id;
struct xpc_partition *part = &xpc_partitions[partid];
diff --git a/arch/ia64/sn/kernel/xpnet.c b/arch/ia64/sn/kernel/xpnet.c
index 007703c494a4..c8173db0d84f 100644
--- a/arch/ia64/sn/kernel/xpnet.c
+++ b/arch/ia64/sn/kernel/xpnet.c
@@ -225,7 +225,7 @@ xpnet_receive(partid_t partid, int channel, struct xpnet_message *msg)
skb_put(skb, (msg->size - msg->leadin_ignore - msg->tailout_ignore));
/*
- * Move the data over from the the other side.
+ * Move the data over from the other side.
*/
if ((XPNET_VERSION_MINOR(msg->version) == 1) &&
(msg->embedded_bytes != 0)) {
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
index 1f0253bfe0a0..935029fc400d 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
@@ -126,7 +126,7 @@ int pcibr_ate_alloc(struct pcibus_info *pcibus_info, int count)
* Setup an Address Translation Entry as specified. Use either the Bridge
* internal maps or the external map RAM, as appropriate.
*/
-static inline u64 *pcibr_ate_addr(struct pcibus_info *pcibus_info,
+static inline u64 __iomem *pcibr_ate_addr(struct pcibus_info *pcibus_info,
int ate_index)
{
if (ate_index < pcibus_info->pbi_int_ate_size) {
@@ -160,7 +160,7 @@ void pcibr_ate_free(struct pcibus_info *pcibus_info, int index)
volatile u64 ate;
int count;
- u64 flags;
+ unsigned long flags;
if (pcibr_invalidate_ate) {
/* For debugging purposes, clear the valid bit in the ATE */
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index a86c7b945962..1ee977fb6ebb 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -237,7 +237,7 @@ void sn_dma_flush(u64 addr)
int is_tio;
int wid_num;
int i, j;
- u64 flags;
+ unsigned long flags;
u64 itte;
struct hubdev_info *hubinfo;
struct sn_flush_device_kernel *p;
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 838c93c9a16a..27dd7df0f446 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -95,7 +95,7 @@ u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus)
* bridge sends an error interrupt.
*/
static irqreturn_t
-pcibr_error_intr_handler(int irq, void *arg, struct pt_regs *regs)
+pcibr_error_intr_handler(int irq, void *arg)
{
struct pcibus_info *soft = (struct pcibus_info *)arg;
@@ -138,7 +138,7 @@ pcibr_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
/*
* register the bridge's error interrupt handler
*/
- if (request_irq(SGI_PCIASIC_ERROR, (void *)pcibr_error_intr_handler,
+ if (request_irq(SGI_PCIASIC_ERROR, pcibr_error_intr_handler,
IRQF_SHARED, "PCIBR error", (void *)(soft))) {
printk(KERN_WARNING
"pcibr cannot allocate interrupt for error handler\n");
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
index c36b0f5affb3..8a2cb4e691fd 100644
--- a/arch/ia64/sn/pci/tioca_provider.c
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -550,13 +550,12 @@ tioca_dma_map(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma_flags)
* tioca_error_intr_handler - SGI TIO CA error interrupt handler
* @irq: unused
* @arg: pointer to tioca_common struct for the given CA
- * @pt: unused
*
* Handle a CA error interrupt. Simply a wrapper around a SAL call which
* defers processing to the SGI prom.
*/
static irqreturn_t
-tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
+tioca_error_intr_handler(int irq, void *arg)
{
struct tioca_common *soft = arg;
struct ia64_sal_retval ret_stuff;
diff --git a/arch/ia64/sn/pci/tioce_provider.c b/arch/ia64/sn/pci/tioce_provider.c
index af7171adcd2c..46e16dcf5971 100644
--- a/arch/ia64/sn/pci/tioce_provider.c
+++ b/arch/ia64/sn/pci/tioce_provider.c
@@ -53,7 +53,7 @@
*/
static void inline
-tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr)
+tioce_mmr_war_pre(struct tioce_kernel *kern, void __iomem *mmr_addr)
{
u64 mmr_base;
u64 mmr_offset;
@@ -62,7 +62,7 @@ tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr)
return;
mmr_base = kern->ce_common->ce_pcibus.bs_base;
- mmr_offset = (u64)mmr_addr - mmr_base;
+ mmr_offset = (unsigned long)mmr_addr - mmr_base;
if (mmr_offset < 0x45000) {
u64 mmr_war_offset;
@@ -79,7 +79,7 @@ tioce_mmr_war_pre(struct tioce_kernel *kern, void *mmr_addr)
}
static void inline
-tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr)
+tioce_mmr_war_post(struct tioce_kernel *kern, void __iomem *mmr_addr)
{
u64 mmr_base;
u64 mmr_offset;
@@ -88,7 +88,7 @@ tioce_mmr_war_post(struct tioce_kernel *kern, void *mmr_addr)
return;
mmr_base = kern->ce_common->ce_pcibus.bs_base;
- mmr_offset = (u64)mmr_addr - mmr_base;
+ mmr_offset = (unsigned long)mmr_addr - mmr_base;
if (mmr_offset < 0x45000) {
if (mmr_offset == 0x100)
@@ -223,7 +223,7 @@ tioce_dma_d64(unsigned long ct_addr, int dma_flags)
* @pci_dev.
*/
static inline void
-pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base,
+pcidev_to_tioce(struct pci_dev *pdev, struct tioce __iomem **base,
struct tioce_kernel **kernel, int *port)
{
struct pcidev_info *pcidev_info;
@@ -235,7 +235,7 @@ pcidev_to_tioce(struct pci_dev *pdev, struct tioce **base,
ce_kernel = (struct tioce_kernel *)ce_common->ce_kernel_private;
if (base)
- *base = (struct tioce *)ce_common->ce_pcibus.bs_base;
+ *base = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
if (kernel)
*kernel = ce_kernel;
@@ -275,13 +275,13 @@ tioce_alloc_map(struct tioce_kernel *ce_kern, int type, int port,
u64 pagesize;
int msi_capable, msi_wanted;
u64 *ate_shadow;
- u64 *ate_reg;
+ u64 __iomem *ate_reg;
u64 addr;
- struct tioce *ce_mmr;
+ struct tioce __iomem *ce_mmr;
u64 bus_base;
struct tioce_dmamap *map;
- ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base;
+ ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base;
switch (type) {
case TIOCE_ATE_M32:
@@ -386,7 +386,7 @@ tioce_dma_d32(struct pci_dev *pdev, u64 ct_addr, int dma_flags)
{
int dma_ok;
int port;
- struct tioce *ce_mmr;
+ struct tioce __iomem *ce_mmr;
struct tioce_kernel *ce_kern;
u64 ct_upper;
u64 ct_lower;
@@ -461,7 +461,7 @@ tioce_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
int i;
int port;
struct tioce_kernel *ce_kern;
- struct tioce *ce_mmr;
+ struct tioce __iomem *ce_mmr;
unsigned long flags;
bus_addr = tioce_dma_barrier(bus_addr, 0);
@@ -666,12 +666,11 @@ tioce_dma_consistent(struct pci_dev *pdev, u64 paddr, size_t byte_count, int dma
* tioce_error_intr_handler - SGI TIO CE error interrupt handler
* @irq: unused
* @arg: pointer to tioce_common struct for the given CE
- * @pt: unused
*
* Handle a CE error interrupt. Simply a wrapper around a SAL call which
* defers processing to the SGI prom.
*/ static irqreturn_t
-tioce_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
+tioce_error_intr_handler(int irq, void *arg)
{
struct tioce_common *soft = arg;
struct ia64_sal_retval ret_stuff;
@@ -701,9 +700,9 @@ static void
tioce_reserve_m32(struct tioce_kernel *ce_kern, u64 base, u64 limit)
{
int ate_index, last_ate, ps;
- struct tioce *ce_mmr;
+ struct tioce __iomem *ce_mmr;
- ce_mmr = (struct tioce *)ce_kern->ce_common->ce_pcibus.bs_base;
+ ce_mmr = (struct tioce __iomem *)ce_kern->ce_common->ce_pcibus.bs_base;
ps = ce_kern->ce_ate3240_pagesize;
ate_index = ATE_PAGE(base, ps);
last_ate = ate_index + ATE_NPAGES(base, limit-base+1, ps) - 1;
@@ -737,7 +736,7 @@ tioce_kern_init(struct tioce_common *tioce_common)
int dev;
u32 tmp;
unsigned int seg, bus;
- struct tioce *tioce_mmr;
+ struct tioce __iomem *tioce_mmr;
struct tioce_kernel *tioce_kern;
tioce_kern = kzalloc(sizeof(struct tioce_kernel), GFP_KERNEL);
@@ -768,7 +767,7 @@ tioce_kern_init(struct tioce_common *tioce_common)
* the ate's.
*/
- tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base;
+ tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base;
tioce_mmr_clri(tioce_kern, &tioce_mmr->ce_ure_page_map,
CE_URE_PAGESIZE_MASK);
tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_ure_page_map,
@@ -859,7 +858,7 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info)
struct pcidev_info *pcidev_info;
struct tioce_common *ce_common;
struct tioce_kernel *ce_kern;
- struct tioce *ce_mmr;
+ struct tioce __iomem *ce_mmr;
u64 force_int_val;
if (!sn_irq_info->irq_bridge)
@@ -873,7 +872,7 @@ tioce_force_interrupt(struct sn_irq_info *sn_irq_info)
return;
ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
- ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+ ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private;
/*
@@ -954,7 +953,7 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info)
struct pcidev_info *pcidev_info;
struct tioce_common *ce_common;
struct tioce_kernel *ce_kern;
- struct tioce *ce_mmr;
+ struct tioce __iomem *ce_mmr;
int bit;
u64 vector;
@@ -963,7 +962,7 @@ tioce_target_interrupt(struct sn_irq_info *sn_irq_info)
return;
ce_common = (struct tioce_common *)pcidev_info->pdi_pcibus_info;
- ce_mmr = (struct tioce *)ce_common->ce_pcibus.bs_base;
+ ce_mmr = (struct tioce __iomem *)ce_common->ce_pcibus.bs_base;
ce_kern = (struct tioce_kernel *)ce_common->ce_kernel_private;
bit = sn_irq_info->irq_int_bit;
@@ -995,7 +994,7 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
cnodeid_t my_cnode, mem_cnode;
struct tioce_common *tioce_common;
struct tioce_kernel *tioce_kern;
- struct tioce *tioce_mmr;
+ struct tioce __iomem *tioce_mmr;
/*
* Allocate kernel bus soft and copy from prom.
@@ -1019,7 +1018,7 @@ tioce_bus_fixup(struct pcibus_bussoft *prom_bussoft, struct pci_controller *cont
* interrupt handler.
*/
- tioce_mmr = (struct tioce *)tioce_common->ce_pcibus.bs_base;
+ tioce_mmr = (struct tioce __iomem *)tioce_common->ce_pcibus.bs_base;
tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_int_status_alias, ~0ULL);
tioce_mmr_seti(tioce_kern, &tioce_mmr->ce_adm_error_summary_alias,
~0ULL);
diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c
index 3841861df6a2..f8d8650383e0 100644
--- a/arch/m32r/kernel/irq.c
+++ b/arch/m32r/kernel/irq.c
@@ -77,13 +77,16 @@ skip:
*/
asmlinkage unsigned int do_IRQ(int irq, struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
+ old_regs = set_irq_regs(regs);
irq_enter();
#ifdef CONFIG_DEBUG_STACKOVERFLOW
/* FIXME M32R */
#endif
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
irq_exit();
+ set_irq_regs(old_regs);
return 1;
}
diff --git a/arch/m32r/kernel/setup.c b/arch/m32r/kernel/setup.c
index 3f35ab3d2dc2..0e7778be33cc 100644
--- a/arch/m32r/kernel/setup.c
+++ b/arch/m32r/kernel/setup.c
@@ -369,10 +369,10 @@ static void c_stop(struct seq_file *m, void *v)
}
struct seq_operations cpuinfo_op = {
- start: c_start,
- next: c_next,
- stop: c_stop,
- show: show_cpuinfo,
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_cpuinfo,
};
#endif /* CONFIG_PROC_FS */
diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c
index 67dbbdc9d111..6b2d77da0683 100644
--- a/arch/m32r/kernel/setup_mappi.c
+++ b/arch/m32r/kernel/setup_mappi.c
@@ -86,7 +86,7 @@ void __init init_IRQ(void)
/* INT0 : LAN controller (RTL8019AS) */
irq_desc[M32R_IRQ_INT0].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_INT0].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_INT0].action = 0;
+ irq_desc[M32R_IRQ_INT0].action = NULL;
irq_desc[M32R_IRQ_INT0].depth = 1;
icu_data[M32R_IRQ_INT0].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD10;
disable_mappi_irq(M32R_IRQ_INT0);
@@ -95,7 +95,7 @@ void __init init_IRQ(void)
/* MFT2 : system timer */
irq_desc[M32R_IRQ_MFT2].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_MFT2].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_MFT2].action = 0;
+ irq_desc[M32R_IRQ_MFT2].action = NULL;
irq_desc[M32R_IRQ_MFT2].depth = 1;
icu_data[M32R_IRQ_MFT2].icucr = M32R_ICUCR_IEN;
disable_mappi_irq(M32R_IRQ_MFT2);
@@ -104,7 +104,7 @@ void __init init_IRQ(void)
/* SIO0_R : uart receive data */
irq_desc[M32R_IRQ_SIO0_R].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_SIO0_R].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO0_R].action = 0;
+ irq_desc[M32R_IRQ_SIO0_R].action = NULL;
irq_desc[M32R_IRQ_SIO0_R].depth = 1;
icu_data[M32R_IRQ_SIO0_R].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO0_R);
@@ -112,7 +112,7 @@ void __init init_IRQ(void)
/* SIO0_S : uart send data */
irq_desc[M32R_IRQ_SIO0_S].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_SIO0_S].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO0_S].action = 0;
+ irq_desc[M32R_IRQ_SIO0_S].action = NULL;
irq_desc[M32R_IRQ_SIO0_S].depth = 1;
icu_data[M32R_IRQ_SIO0_S].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO0_S);
@@ -120,7 +120,7 @@ void __init init_IRQ(void)
/* SIO1_R : uart receive data */
irq_desc[M32R_IRQ_SIO1_R].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_SIO1_R].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO1_R].action = 0;
+ irq_desc[M32R_IRQ_SIO1_R].action = NULL;
irq_desc[M32R_IRQ_SIO1_R].depth = 1;
icu_data[M32R_IRQ_SIO1_R].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO1_R);
@@ -128,7 +128,7 @@ void __init init_IRQ(void)
/* SIO1_S : uart send data */
irq_desc[M32R_IRQ_SIO1_S].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_SIO1_S].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_SIO1_S].action = 0;
+ irq_desc[M32R_IRQ_SIO1_S].action = NULL;
irq_desc[M32R_IRQ_SIO1_S].depth = 1;
icu_data[M32R_IRQ_SIO1_S].icucr = 0;
disable_mappi_irq(M32R_IRQ_SIO1_S);
@@ -138,7 +138,7 @@ void __init init_IRQ(void)
/* INT1 : pccard0 interrupt */
irq_desc[M32R_IRQ_INT1].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_INT1].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_INT1].action = 0;
+ irq_desc[M32R_IRQ_INT1].action = NULL;
irq_desc[M32R_IRQ_INT1].depth = 1;
icu_data[M32R_IRQ_INT1].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
disable_mappi_irq(M32R_IRQ_INT1);
@@ -146,7 +146,7 @@ void __init init_IRQ(void)
/* INT2 : pccard1 interrupt */
irq_desc[M32R_IRQ_INT2].status = IRQ_DISABLED;
irq_desc[M32R_IRQ_INT2].chip = &mappi_irq_type;
- irq_desc[M32R_IRQ_INT2].action = 0;
+ irq_desc[M32R_IRQ_INT2].action = NULL;
irq_desc[M32R_IRQ_INT2].depth = 1;
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN | M32R_ICUCR_ISMOD00;
disable_mappi_irq(M32R_IRQ_INT2);
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index a9174efe80cb..b60cea4aebaa 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -33,7 +33,7 @@
int do_signal(struct pt_regs *, sigset_t *);
asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
+sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize,
unsigned long r2, unsigned long r3, unsigned long r4,
unsigned long r5, unsigned long r6, struct pt_regs *regs)
{
@@ -78,8 +78,8 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
struct rt_sigframe
{
int sig;
- struct siginfo *pinfo;
- void *puc;
+ struct siginfo __user *pinfo;
+ void __user *puc;
struct siginfo info;
struct ucontext uc;
// struct _fpstate fpstate;
diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c
index 8b1f6eb76870..360129174b2b 100644
--- a/arch/m32r/kernel/smp.c
+++ b/arch/m32r/kernel/smp.c
@@ -101,7 +101,7 @@ void smp_call_function_interrupt(void);
void smp_send_timer(void);
void smp_ipi_timer_interrupt(struct pt_regs *);
-void smp_local_timer_interrupt(struct pt_regs *);
+void smp_local_timer_interrupt(void);
void send_IPI_allbutself(int, int);
static void send_IPI_mask(cpumask_t, int, int);
@@ -231,7 +231,7 @@ void smp_flush_tlb_all(void)
local_irq_save(flags);
__flush_tlb_all();
local_irq_restore(flags);
- smp_call_function(flush_tlb_all_ipi, 0, 1, 1);
+ smp_call_function(flush_tlb_all_ipi, NULL, 1, 1);
preempt_enable();
}
@@ -734,9 +734,12 @@ void smp_send_timer(void)
*==========================================================================*/
void smp_ipi_timer_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
+ old_regs = set_irq_regs(regs);
irq_enter();
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
irq_exit();
+ set_irq_regs(old_regs);
}
/*==========================================================================*
@@ -762,9 +765,9 @@ void smp_ipi_timer_interrupt(struct pt_regs *regs)
* ---------- --- --------------------------------------------------------
* 2003-06-24 hy use per_cpu structure.
*==========================================================================*/
-void smp_local_timer_interrupt(struct pt_regs *regs)
+void smp_local_timer_interrupt(void)
{
- int user = user_mode(regs);
+ int user = user_mode(get_irq_regs());
int cpu_id = smp_processor_id();
/*
@@ -774,7 +777,7 @@ void smp_local_timer_interrupt(struct pt_regs *regs)
* useful with a profiling multiplier != 1
*/
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
if (--per_cpu(prof_counter, cpu_id) <= 0) {
/*
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c
index a9cea32eb824..b4e7bcb43540 100644
--- a/arch/m32r/kernel/sys_m32r.c
+++ b/arch/m32r/kernel/sys_m32r.c
@@ -25,11 +25,13 @@
#include <asm/cachectl.h>
#include <asm/cacheflush.h>
#include <asm/ipc.h>
+#include <asm/syscall.h>
+#include <asm/unistd.h>
/*
* sys_tas() - test-and-set
*/
-asmlinkage int sys_tas(int *addr)
+asmlinkage int sys_tas(int __user *addr)
{
int oldval;
@@ -88,7 +90,7 @@ sys_pipe(unsigned long r0, unsigned long r1, unsigned long r2,
error = do_pipe(fd);
if (!error) {
- if (copy_to_user((void *)r0, (void *)fd, 2*sizeof(int)))
+ if (copy_to_user((void __user *)r0, fd, 2*sizeof(int)))
error = -EFAULT;
}
return error;
@@ -199,13 +201,13 @@ asmlinkage int sys_ipc(uint call, int first, int second,
}
}
-asmlinkage int sys_uname(struct old_utsname * name)
+asmlinkage int sys_uname(struct old_utsname __user * name)
{
int err;
if (!name)
return -EFAULT;
down_read(&uts_sem);
- err=copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
return err?-EFAULT:0;
}
@@ -223,3 +225,21 @@ asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
return -ENOSYS;
}
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register long __scno __asm__ ("r7") = __NR_execve;
+ register long __arg3 __asm__ ("r2") = (long)(envp);
+ register long __arg2 __asm__ ("r1") = (long)(argv);
+ register long __res __asm__ ("r0") = (long)(filename);
+ __asm__ __volatile__ (
+ "trap #" SYSCALL_VECTOR "|| nop"
+ : "=r" (__res)
+ : "r" (__scno), "0" (__res), "r" (__arg2),
+ "r" (__arg3)
+ : "memory");
+ return __res;
+}
diff --git a/arch/m32r/kernel/time.c b/arch/m32r/kernel/time.c
index ded0be07a476..a09038282c78 100644
--- a/arch/m32r/kernel/time.c
+++ b/arch/m32r/kernel/time.c
@@ -35,10 +35,9 @@
#ifdef CONFIG_SMP
extern void send_IPI_allbutself(int, int);
-extern void smp_local_timer_interrupt(struct pt_regs *);
+extern void smp_local_timer_interrupt(void);
#endif
-extern unsigned long wall_jiffies;
#define TICK_SIZE (tick_nsec / 1000)
/*
@@ -108,24 +107,17 @@ void do_gettimeofday(struct timeval *tv)
unsigned long max_ntp_tick = tick_usec - tickadj;
do {
- unsigned long lost;
-
seq = read_seqbegin(&xtime_lock);
usec = do_gettimeoffset();
- lost = jiffies - wall_jiffies;
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
- if (unlikely(time_adjust < 0)) {
+ if (unlikely(time_adjust < 0))
usec = min(usec, max_ntp_tick);
- if (lost)
- usec += lost * max_ntp_tick;
- } else if (unlikely(lost))
- usec += lost * tick_usec;
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / 1000);
@@ -158,7 +150,6 @@ int do_settimeofday(struct timespec *tv)
* made, and then undo it!
*/
nsec -= do_gettimeoffset() * NSEC_PER_USEC;
- nsec -= (jiffies - wall_jiffies) * TICK_NSEC;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -197,15 +188,15 @@ static long last_rtc_update = 0;
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
{
#ifndef CONFIG_SMP
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#endif
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
/*
* If we have an externally synchronized Linux clock, then update
@@ -230,7 +221,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
a hack, so don't look closely for now.. */
#ifdef CONFIG_SMP
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
smp_send_timer();
#endif
diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c
index c1daf2c40c7c..97e0b1c0830e 100644
--- a/arch/m32r/kernel/traps.c
+++ b/arch/m32r/kernel/traps.c
@@ -268,7 +268,7 @@ static __inline__ void do_trap(int trapnr, int signr, const char * str,
#define DO_ERROR(trapnr, signr, str, name) \
asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
{ \
- do_trap(trapnr, signr, 0, regs, error_code, NULL); \
+ do_trap(trapnr, signr, NULL, regs, error_code, NULL); \
}
#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
diff --git a/arch/m32r/mm/fault.c b/arch/m32r/mm/fault.c
index dc18a33eefef..8d5f551b5754 100644
--- a/arch/m32r/mm/fault.c
+++ b/arch/m32r/mm/fault.c
@@ -299,7 +299,7 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (tsk->pid == 1) {
+ if (is_init(tsk)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/m32r/mm/ioremap.c b/arch/m32r/mm/ioremap.c
index a151849a605e..5152c4e6ac80 100644
--- a/arch/m32r/mm/ioremap.c
+++ b/arch/m32r/mm/ioremap.c
@@ -20,92 +20,8 @@
#include <asm/byteorder.h>
#include <linux/vmalloc.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
-#include <asm/cacheflush.h>
-#include <asm/tlbflush.h>
-
-static inline void
-remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
- unsigned long pfn;
- pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ
- | _PAGE_WRITE | flags);
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
- set_pte(pte, pfn_pte(pfn, pgprot));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int
-remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-static int
-remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, unsigned long flags)
-{
- int error;
- pgd_t * dir;
- unsigned long end = address + size;
-
- phys_addr -= address;
- dir = pgd_offset(&init_mm, address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pmd_t *pmd;
- pmd = pmd_alloc(&init_mm, dir, address);
- error = -ENOMEM;
- if (!pmd)
- break;
- if (remap_area_pmd(pmd, address, end - address,
- phys_addr + address, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- dir++;
- } while (address && (address < end));
- flush_tlb_all();
- return error;
-}
/*
* Generic mapping function (not visible outside):
@@ -129,6 +45,7 @@ __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
void __iomem * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
+ pgprot_t pgprot;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
@@ -157,6 +74,9 @@ __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
return NULL;
}
+ pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ
+ | _PAGE_WRITE | flags);
+
/*
* Mappings have to be page-aligned
*/
@@ -172,7 +92,8 @@ __ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags)
return NULL;
area->phys_addr = phys_addr;
addr = (void __iomem *) area->addr;
- if (remap_area_pages((unsigned long)addr, phys_addr, size, flags)) {
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, pgprot)) {
vunmap((void __force *) addr);
return NULL;
}
diff --git a/arch/m32r/mm/mmu.S b/arch/m32r/mm/mmu.S
index 0c28f11d6677..9a4d40b3d6a2 100644
--- a/arch/m32r/mm/mmu.S
+++ b/arch/m32r/mm/mmu.S
@@ -6,7 +6,6 @@
/* $Id: mmu.S,v 1.15 2004/03/16 02:56:27 takata Exp $ */
-#include <linux/config.h> /* CONFIG_MMU */
#include <linux/linkage.h>
#include <asm/assembler.h>
#include <asm/smp.h>
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 805b81fedf80..7bc14461a6ac 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -600,7 +600,7 @@ config MVME147_SCC
config SERIAL167
bool "CD2401 support for MVME166/7 serial ports"
- depends on MVME16x && BROKEN
+ depends on MVME16x
help
This is the driver for the serial ports on the Motorola MVME166,
167, and 172 boards. Everyone using one of these boards should say
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c
index 96c79d840cff..28d95cfe8ac0 100644
--- a/arch/m68k/amiga/amiints.c
+++ b/arch/m68k/amiga/amiints.c
@@ -47,10 +47,10 @@
static void amiga_enable_irq(unsigned int irq);
static void amiga_disable_irq(unsigned int irq);
-static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp);
-static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp);
-static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp);
-static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t ami_int1(int irq, void *dev_id);
+static irqreturn_t ami_int3(int irq, void *dev_id);
+static irqreturn_t ami_int4(int irq, void *dev_id);
+static irqreturn_t ami_int5(int irq, void *dev_id);
static struct irq_controller amiga_irq_controller = {
.name = "amiga",
@@ -113,98 +113,98 @@ static void amiga_disable_irq(unsigned int irq)
* The builtin Amiga hardware interrupt handlers.
*/
-static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t ami_int1(int irq, void *dev_id)
{
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
/* if serial transmit buffer empty, interrupt */
if (ints & IF_TBE) {
amiga_custom.intreq = IF_TBE;
- m68k_handle_int(IRQ_AMIGA_TBE, fp);
+ m68k_handle_int(IRQ_AMIGA_TBE);
}
/* if floppy disk transfer complete, interrupt */
if (ints & IF_DSKBLK) {
amiga_custom.intreq = IF_DSKBLK;
- m68k_handle_int(IRQ_AMIGA_DSKBLK, fp);
+ m68k_handle_int(IRQ_AMIGA_DSKBLK);
}
/* if software interrupt set, interrupt */
if (ints & IF_SOFT) {
amiga_custom.intreq = IF_SOFT;
- m68k_handle_int(IRQ_AMIGA_SOFT, fp);
+ m68k_handle_int(IRQ_AMIGA_SOFT);
}
return IRQ_HANDLED;
}
-static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t ami_int3(int irq, void *dev_id)
{
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
/* if a blitter interrupt */
if (ints & IF_BLIT) {
amiga_custom.intreq = IF_BLIT;
- m68k_handle_int(IRQ_AMIGA_BLIT, fp);
+ m68k_handle_int(IRQ_AMIGA_BLIT);
}
/* if a copper interrupt */
if (ints & IF_COPER) {
amiga_custom.intreq = IF_COPER;
- m68k_handle_int(IRQ_AMIGA_COPPER, fp);
+ m68k_handle_int(IRQ_AMIGA_COPPER);
}
/* if a vertical blank interrupt */
if (ints & IF_VERTB) {
amiga_custom.intreq = IF_VERTB;
- m68k_handle_int(IRQ_AMIGA_VERTB, fp);
+ m68k_handle_int(IRQ_AMIGA_VERTB);
}
return IRQ_HANDLED;
}
-static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t ami_int4(int irq, void *dev_id)
{
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
/* if audio 0 interrupt */
if (ints & IF_AUD0) {
amiga_custom.intreq = IF_AUD0;
- m68k_handle_int(IRQ_AMIGA_AUD0, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD0);
}
/* if audio 1 interrupt */
if (ints & IF_AUD1) {
amiga_custom.intreq = IF_AUD1;
- m68k_handle_int(IRQ_AMIGA_AUD1, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD1);
}
/* if audio 2 interrupt */
if (ints & IF_AUD2) {
amiga_custom.intreq = IF_AUD2;
- m68k_handle_int(IRQ_AMIGA_AUD2, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD2);
}
/* if audio 3 interrupt */
if (ints & IF_AUD3) {
amiga_custom.intreq = IF_AUD3;
- m68k_handle_int(IRQ_AMIGA_AUD3, fp);
+ m68k_handle_int(IRQ_AMIGA_AUD3);
}
return IRQ_HANDLED;
}
-static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t ami_int5(int irq, void *dev_id)
{
unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar;
/* if serial receive buffer full interrupt */
if (ints & IF_RBF) {
/* acknowledge of IF_RBF must be done by the serial interrupt */
- m68k_handle_int(IRQ_AMIGA_RBF, fp);
+ m68k_handle_int(IRQ_AMIGA_RBF);
}
/* if a disk sync interrupt */
if (ints & IF_DSKSYN) {
amiga_custom.intreq = IF_DSKSYN;
- m68k_handle_int(IRQ_AMIGA_DSKSYN, fp);
+ m68k_handle_int(IRQ_AMIGA_DSKSYN);
}
return IRQ_HANDLED;
}
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c
index dbad30054721..7a20058eb380 100644
--- a/arch/m68k/amiga/cia.c
+++ b/arch/m68k/amiga/cia.c
@@ -82,7 +82,7 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask)
return old;
}
-static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t cia_handler(int irq, void *dev_id)
{
struct ciabase *base = (struct ciabase *)dev_id;
int mach_irq;
@@ -93,7 +93,7 @@ static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp)
amiga_custom.intreq = base->int_mask;
for (; ints; mach_irq++, ints >>= 1) {
if (ints & 1)
- m68k_handle_int(mach_irq, fp);
+ m68k_handle_int(mach_irq);
}
return IRQ_HANDLED;
}
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c
index 092e50d2cb13..3204f412cad8 100644
--- a/arch/m68k/amiga/config.c
+++ b/arch/m68k/amiga/config.c
@@ -83,7 +83,7 @@ static char amiga_model_name[13] = "Amiga ";
extern char m68k_debug_device[];
-static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+static void amiga_sched_init(irq_handler_t handler);
/* amiga specific irq functions */
extern void amiga_init_IRQ (void);
static void amiga_get_model(char *model);
@@ -487,8 +487,7 @@ void __init config_amiga(void)
static unsigned short jiffy_ticks;
-static void __init amiga_sched_init(irqreturn_t (*timer_routine)(int, void *,
- struct pt_regs *))
+static void __init amiga_sched_init(irq_handler_t timer_routine)
{
static struct resource sched_res = {
.name = "timer", .start = 0x00bfd400, .end = 0x00bfd5ff,
diff --git a/arch/m68k/apollo/config.c b/arch/m68k/apollo/config.c
index 6f4581575fb4..cb8e7609df4c 100644
--- a/arch/m68k/apollo/config.c
+++ b/arch/m68k/apollo/config.c
@@ -25,7 +25,7 @@ u_long cpuctrl_physaddr;
u_long timer_physaddr;
u_long apollo_model;
-extern void dn_sched_init(irqreturn_t (*handler)(int,void *,struct pt_regs *));
+extern void dn_sched_init(irq_handler_t handler);
extern void dn_init_IRQ(void);
extern unsigned long dn_gettimeoffset(void);
extern int dn_dummy_hwclk(int, struct rtc_time *);
@@ -38,7 +38,7 @@ extern irqreturn_t dn_process_int(int irq, struct pt_regs *fp);
#ifdef CONFIG_HEARTBEAT
static void dn_heartbeat(int on);
#endif
-static irqreturn_t dn_timer_int(int irq,void *, struct pt_regs *);
+static irqreturn_t dn_timer_int(int irq,void *);
static void dn_get_model(char *model);
static const char *apollo_models[] = {
[APOLLO_DN3000-APOLLO_DN3000] = "DN3000 (Otter)",
@@ -174,13 +174,13 @@ void config_apollo(void) {
}
-irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp)
+irqreturn_t dn_timer_int(int irq, void *dev_id)
{
- irqreturn_t (*timer_handler)(int, void *, struct pt_regs *) = dev_id;
+ irq_handler_t timer_handler = dev_id;
volatile unsigned char x;
- timer_handler(irq, dev_id, fp);
+ timer_handler(irq, dev_id);
x=*(volatile unsigned char *)(timer+3);
x=*(volatile unsigned char *)(timer+5);
@@ -188,8 +188,8 @@ irqreturn_t dn_timer_int(int irq, void *dev_id, struct pt_regs *fp)
return IRQ_HANDLED;
}
-void dn_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *)) {
-
+void dn_sched_init(irq_handler_t timer_routine)
+{
/* program timer 1 */
*(volatile unsigned char *)(timer+3)=0x01;
*(volatile unsigned char *)(timer+1)=0x40;
diff --git a/arch/m68k/apollo/dma.c b/arch/m68k/apollo/dma.c
deleted file mode 100644
index aed8be177ef1..000000000000
--- a/arch/m68k/apollo/dma.c
+++ /dev/null
@@ -1,50 +0,0 @@
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/kd.h>
-#include <linux/tty.h>
-#include <linux/console.h>
-
-#include <asm/setup.h>
-#include <asm/bootinfo.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/apollodma.h>
-#include <asm/io.h>
-
-/* note only works for 16 Bit 1 page DMA's */
-
-static unsigned short next_free_xlat_entry=0;
-
-unsigned short dma_map_page(unsigned long phys_addr,int count,int type) {
-
- unsigned long page_aligned_addr=phys_addr & (~((1<<12)-1));
- unsigned short start_map_addr=page_aligned_addr >> 10;
- unsigned short free_xlat_entry, *xlat_map_entry;
- int i;
-
- free_xlat_entry=next_free_xlat_entry;
- for(i=0,xlat_map_entry=addr_xlat_map+(free_xlat_entry<<2);i<8;i++,xlat_map_entry++) {
-#if 0
- printk("phys_addr: %x, page_aligned_addr: %x, start_map_addr: %x\n",phys_addr,page_aligned_addr,start_map_addr+i);
-#endif
- out_be16(xlat_map_entry, start_map_addr+i);
- }
-
- next_free_xlat_entry+=2;
- if(next_free_xlat_entry>125)
- next_free_xlat_entry=0;
-
-#if 0
- printk("next_free_xlat_entry: %d\n",next_free_xlat_entry);
-#endif
-
- return free_xlat_entry<<10;
-}
-
-void dma_unmap_page(unsigned short dma_addr) {
-
- return ;
-
-}
-
diff --git a/arch/m68k/apollo/dn_ints.c b/arch/m68k/apollo/dn_ints.c
index 9fe07803797b..4274af125998 100644
--- a/arch/m68k/apollo/dn_ints.c
+++ b/arch/m68k/apollo/dn_ints.c
@@ -6,7 +6,7 @@
void dn_process_int(unsigned int irq, struct pt_regs *fp)
{
- m68k_handle_int(irq, fp);
+ __m68k_handle_int(irq, fp);
*(volatile unsigned char *)(pica)=0x20;
*(volatile unsigned char *)(picb)=0x20;
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c
index ece13cbf9950..7f812641790c 100644
--- a/arch/m68k/atari/ataints.c
+++ b/arch/m68k/atari/ataints.c
@@ -332,6 +332,9 @@ static void atari_shutdown_irq(unsigned int irq)
atari_disable_irq(irq);
atari_turnoff_irq(irq);
m68k_irq_shutdown(irq);
+
+ if (irq == IRQ_AUTO_4)
+ vectors[VEC_INT4] = falcon_hblhandler;
}
static struct irq_controller atari_irq_controller = {
@@ -356,7 +359,7 @@ static struct irq_controller atari_irq_controller = {
void __init atari_init_IRQ(void)
{
- m68k_setup_user_interrupt(VEC_USER, 192, NULL);
+ m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL);
m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
/* Initialize the MFP(s) */
@@ -403,8 +406,10 @@ void __init atari_init_IRQ(void)
* gets overruns)
*/
- if (!MACH_IS_HADES)
+ if (!MACH_IS_HADES) {
vectors[VEC_INT2] = falcon_hblhandler;
+ vectors[VEC_INT4] = falcon_hblhandler;
+ }
}
if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index b2079252a954..ca5cd4344e3d 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -62,7 +62,7 @@ static void atari_heartbeat( int on );
#endif
/* atari specific timer functions (in time.c) */
-extern void atari_sched_init(irqreturn_t (*)(int, void *, struct pt_regs *));
+extern void atari_sched_init(irq_handler_t );
extern unsigned long atari_gettimeoffset (void);
extern int atari_mste_hwclk (int, struct rtc_time *);
extern int atari_tt_hwclk (int, struct rtc_time *);
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index 288f5e6a124e..d64b5804e980 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -44,7 +44,7 @@
static int stdma_locked; /* the semaphore */
/* int func to be called */
-static irqreturn_t (*stdma_isr)(int, void *, struct pt_regs *);
+static irq_handler_t stdma_isr;
static void *stdma_isr_data; /* data passed to isr */
static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */
@@ -53,7 +53,7 @@ static DECLARE_WAIT_QUEUE_HEAD(stdma_wait); /* wait queue for ST-DMA */
/***************************** Prototypes *****************************/
-static irqreturn_t stdma_int (int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t stdma_int (int irq, void *dummy);
/************************* End of Prototypes **************************/
@@ -75,8 +75,7 @@ static irqreturn_t stdma_int (int irq, void *dummy, struct pt_regs *fp);
*
*/
-void stdma_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *),
- void *data)
+void stdma_lock(irq_handler_t handler, void *data)
{
unsigned long flags;
@@ -188,9 +187,9 @@ void __init stdma_init(void)
*
*/
-static irqreturn_t stdma_int(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t stdma_int(int irq, void *dummy)
{
if (stdma_isr)
- (*stdma_isr)(irq, stdma_isr_data, fp);
+ (*stdma_isr)(irq, stdma_isr_data);
return IRQ_HANDLED;
}
diff --git a/arch/m68k/atari/time.c b/arch/m68k/atari/time.c
index e79bbc94216d..e0d3c8bfb408 100644
--- a/arch/m68k/atari/time.c
+++ b/arch/m68k/atari/time.c
@@ -16,11 +16,12 @@
#include <linux/init.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/delay.h>
#include <asm/atariints.h>
void __init
-atari_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
+atari_sched_init(irq_handler_t timer_routine)
{
/* set Timer C data Register */
mfp.tim_dt_c = INT_TICKS;
@@ -212,8 +213,12 @@ int atari_tt_hwclk( int op, struct rtc_time *t )
* additionally the RTC_SET bit is set to prevent an update cycle.
*/
- while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP )
- schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
+ while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
+ if (in_atomic() || irqs_disabled())
+ mdelay(1);
+ else
+ schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
+ }
local_irq_save(flags);
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c
index d1e916ae55a8..896ae3d3d919 100644
--- a/arch/m68k/bvme6000/config.c
+++ b/arch/m68k/bvme6000/config.c
@@ -38,7 +38,7 @@
static void bvme6000_get_model(char *model);
static int bvme6000_get_hardware_list(char *buffer);
-extern void bvme6000_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+extern void bvme6000_sched_init(irq_handler_t handler);
extern unsigned long bvme6000_gettimeoffset (void);
extern int bvme6000_hwclk (int, struct rtc_time *);
extern int bvme6000_set_clock_mmss (unsigned long);
@@ -52,7 +52,7 @@ static unsigned char bin2bcd (unsigned char b);
/* Save tick handler routine pointer, will point to do_timer() in
* kernel/sched.c, called via bvme6000_process_int() */
-static irqreturn_t (*tick_handler)(int, void *, struct pt_regs *);
+static irq_handler_t tick_handler;
int bvme6000_parse_bootinfo(const struct bi_record *bi)
@@ -154,7 +154,7 @@ void __init config_bvme6000(void)
}
-irqreturn_t bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+irqreturn_t bvme6000_abort_int (int irq, void *dev_id)
{
unsigned long *new = (unsigned long *)vectors;
unsigned long *old = (unsigned long *)0xf8000000;
@@ -171,14 +171,14 @@ irqreturn_t bvme6000_abort_int (int irq, void *dev_id, struct pt_regs *fp)
}
-static irqreturn_t bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t bvme6000_timer_int (int irq, void *dev_id)
{
volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
unsigned char msr = rtc->msr & 0xc0;
rtc->msr = msr | 0x20; /* Ack the interrupt */
- return tick_handler(irq, dev_id, fp);
+ return tick_handler(irq, dev_id);
}
/*
@@ -190,7 +190,7 @@ static irqreturn_t bvme6000_timer_int (int irq, void *dev_id, struct pt_regs *fp
* so divide by 8 to get the microsecond result.
*/
-void bvme6000_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
+void bvme6000_sched_init (irq_handler_t timer_routine)
{
volatile RtcPtr_t rtc = (RtcPtr_t)BVME_RTC_BASE;
unsigned char msr = rtc->msr & 0xc0;
diff --git a/arch/m68k/hp300/time.c b/arch/m68k/hp300/time.c
index 7df05662b277..dd7c8a2583d3 100644
--- a/arch/m68k/hp300/time.c
+++ b/arch/m68k/hp300/time.c
@@ -36,15 +36,15 @@
#define INTVAL ((10000 / 4) - 1)
-static irqreturn_t hp300_tick(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hp300_tick(int irq, void *dev_id)
{
unsigned long tmp;
- irqreturn_t (*vector)(int, void *, struct pt_regs *) = dev_id;
+ irq_handler_t vector = dev_id;
in_8(CLOCKBASE + CLKSR);
asm volatile ("movpw %1@(5),%0" : "=d" (tmp) : "a" (CLOCKBASE));
/* Turn off the network and SCSI leds */
blinken_leds(0, 0xe0);
- return vector(irq, NULL, regs);
+ return vector(irq, NULL);
}
unsigned long hp300_gettimeoffset(void)
@@ -63,7 +63,7 @@ unsigned long hp300_gettimeoffset(void)
return (USECS_PER_JIFFY * ticks) / INTVAL;
}
-void __init hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
+void __init hp300_sched_init(irq_handler_t vector)
{
out_8(CLOCKBASE + CLKCR2, 0x1); /* select CR1 */
out_8(CLOCKBASE + CLKCR1, 0x1); /* reset */
diff --git a/arch/m68k/hp300/time.h b/arch/m68k/hp300/time.h
index 8ef9987b49ab..f5b3d098b0f5 100644
--- a/arch/m68k/hp300/time.h
+++ b/arch/m68k/hp300/time.h
@@ -1,4 +1,4 @@
-extern void hp300_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *));
+extern void hp300_sched_init(irq_handler_t vector);
extern unsigned long hp300_gettimeoffset (void);
diff --git a/arch/m68k/kernel/Makefile b/arch/m68k/kernel/Makefile
index dae609797dc0..1c9ecaa473d5 100644
--- a/arch/m68k/kernel/Makefile
+++ b/arch/m68k/kernel/Makefile
@@ -9,10 +9,11 @@ else
endif
extra-y += vmlinux.lds
-obj-y := entry.o process.o traps.o ints.o dma.o signal.o ptrace.o \
+obj-y := entry.o process.o traps.o ints.o signal.o ptrace.o \
sys_m68k.o time.o semaphore.o setup.o m68k_ksyms.o
obj-$(CONFIG_PCI) += bios32.o
obj-$(CONFIG_MODULES) += module.o
+obj-y$(CONFIG_MMU_SUN3) += dma.o # no, it's not a typo
EXTRA_AFLAGS := -traditional
diff --git a/arch/m68k/kernel/dma.c b/arch/m68k/kernel/dma.c
index fc449f8b2045..9d4e4b5b6bd8 100644
--- a/arch/m68k/kernel/dma.c
+++ b/arch/m68k/kernel/dma.c
@@ -15,7 +15,7 @@
#include <asm/scatterlist.h>
void *dma_alloc_coherent(struct device *dev, size_t size,
- dma_addr_t *handle, int flag)
+ dma_addr_t *handle, gfp_t flag)
{
struct page *page, **map;
pgprot_t pgprot;
@@ -51,7 +51,7 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
pgprot_val(pgprot) |= _PAGE_GLOBAL040 | _PAGE_NOCACHE_S;
else
pgprot_val(pgprot) |= _PAGE_NOCACHE030;
- addr = vmap(map, size, flag, pgprot);
+ addr = vmap(map, size, VM_MAP, pgprot);
kfree(map);
return addr;
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
index 9083c8b7659f..222ce4244564 100644
--- a/arch/m68k/kernel/entry.S
+++ b/arch/m68k/kernel/entry.S
@@ -205,7 +205,7 @@ ENTRY(auto_inthandler)
movel %sp,%sp@-
movel %d0,%sp@- | put vector # on stack
auto_irqhandler_fixup = . + 2
- jsr m68k_handle_int | process the IRQ
+ jsr __m68k_handle_int | process the IRQ
addql #8,%sp | pop parameters off stack
ret_from_interrupt:
@@ -239,7 +239,7 @@ user_irqvec_fixup = . + 2
movel %sp,%sp@-
movel %d0,%sp@- | put vector # on stack
user_irqhandler_fixup = . + 2
- jsr m68k_handle_int | process the IRQ
+ jsr __m68k_handle_int | process the IRQ
addql #8,%sp | pop parameters off stack
subqb #1,%curptr@(TASK_INFO+TINFO_PREEMPT+1)
@@ -706,4 +706,33 @@ sys_call_table:
.long sys_add_key
.long sys_request_key /* 280 */
.long sys_keyctl
+ .long sys_ioprio_set
+ .long sys_ioprio_get
+ .long sys_inotify_init
+ .long sys_inotify_add_watch /* 285 */
+ .long sys_inotify_rm_watch
+ .long sys_migrate_pages
+ .long sys_openat
+ .long sys_mkdirat
+ .long sys_mknodat /* 290 */
+ .long sys_fchownat
+ .long sys_futimesat
+ .long sys_fstatat64
+ .long sys_unlinkat
+ .long sys_renameat /* 295 */
+ .long sys_linkat
+ .long sys_symlinkat
+ .long sys_readlinkat
+ .long sys_fchmodat
+ .long sys_faccessat /* 300 */
+ .long sys_ni_syscall /* Reserved for pselect6 */
+ .long sys_ni_syscall /* Reserved for ppoll */
+ .long sys_unshare
+ .long sys_set_robust_list
+ .long sys_get_robust_list /* 305 */
+ .long sys_splice
+ .long sys_sync_file_range
+ .long sys_tee
+ .long sys_vmsplice
+ .long sys_move_pages /* 310 */
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c
index b33e37fb7b0e..84aceca6c05c 100644
--- a/arch/m68k/kernel/ints.c
+++ b/arch/m68k/kernel/ints.c
@@ -39,6 +39,7 @@
#include <asm/page.h>
#include <asm/machdep.h>
#include <asm/cacheflush.h>
+#include <asm/irq_regs.h>
#ifdef CONFIG_Q40
#include <asm/q40ints.h>
@@ -104,7 +105,7 @@ void __init init_IRQ(void)
* @handler: called from auto vector interrupts
*
* setup the handler to be called from auto vector interrupts instead of the
- * standard m68k_handle_int(), it will be called with irq numbers in the range
+ * standard __m68k_handle_int(), it will be called with irq numbers in the range
* from IRQ_AUTO_1 - IRQ_AUTO_7.
*/
void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
@@ -123,7 +124,7 @@ void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_re
* setup user vector interrupts, this includes activating the specified range
* of interrupts, only then these interrupts can be requested (note: this is
* different from auto vector interrupts). An optional handler can be installed
- * to be called instead of the default m68k_handle_int(), it will be called
+ * to be called instead of the default __m68k_handle_int(), it will be called
* with irq numbers starting from IRQ_USER.
*/
void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
@@ -131,6 +132,7 @@ void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
{
int i;
+ BUG_ON(IRQ_USER + cnt >= NR_IRQS);
m68k_first_user_vec = vec;
for (i = 0; i < cnt; i++)
irq_controller[IRQ_USER + i] = &user_irq_controller;
@@ -215,7 +217,7 @@ int setup_irq(unsigned int irq, struct irq_node *node)
}
int request_irq(unsigned int irq,
- irqreturn_t (*handler) (int, void *, struct pt_regs *),
+ irq_handler_t handler,
unsigned long flags, const char *devname, void *dev_id)
{
struct irq_node *node;
@@ -379,18 +381,25 @@ unsigned int irq_canonicalize(unsigned int irq)
EXPORT_SYMBOL(irq_canonicalize);
-asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs)
+asmlinkage void m68k_handle_int(unsigned int irq)
{
struct irq_node *node;
-
kstat_cpu(0).irqs[irq]++;
node = irq_list[irq];
do {
- node->handler(irq, node->dev_id, regs);
+ node->handler(irq, node->dev_id);
node = node->next;
} while (node);
}
+asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs)
+{
+ struct pt_regs *old_regs;
+ old_regs = set_irq_regs(regs);
+ m68k_handle_int(irq);
+ set_irq_regs(old_regs);
+}
+
asmlinkage void handle_badint(struct pt_regs *regs)
{
kstat_cpu(0).irqs[0]++;
diff --git a/arch/m68k/kernel/m68k_ksyms.c b/arch/m68k/kernel/m68k_ksyms.c
index aff26a52167c..6fc69c74fe2e 100644
--- a/arch/m68k/kernel/m68k_ksyms.c
+++ b/arch/m68k/kernel/m68k_ksyms.c
@@ -1,65 +1,10 @@
#include <linux/module.h>
-#include <linux/linkage.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/user.h>
-#include <linux/elfcore.h>
-#include <linux/in6.h>
-#include <linux/interrupt.h>
-
-#include <asm/setup.h>
-#include <asm/machdep.h>
-#include <asm/pgalloc.h>
-#include <asm/irq.h>
-#include <asm/io.h>
#include <asm/semaphore.h>
-#include <asm/checksum.h>
asmlinkage long long __ashldi3 (long long, int);
asmlinkage long long __ashrdi3 (long long, int);
asmlinkage long long __lshrdi3 (long long, int);
asmlinkage long long __muldi3 (long long, long long);
-extern char m68k_debug_device[];
-
-/* platform dependent support */
-
-EXPORT_SYMBOL(m68k_machtype);
-EXPORT_SYMBOL(m68k_cputype);
-EXPORT_SYMBOL(m68k_is040or060);
-EXPORT_SYMBOL(m68k_realnum_memory);
-EXPORT_SYMBOL(m68k_memory);
-#ifndef CONFIG_SUN3
-EXPORT_SYMBOL(cache_push);
-EXPORT_SYMBOL(cache_clear);
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
-EXPORT_SYMBOL(mm_vtop);
-EXPORT_SYMBOL(mm_ptov);
-EXPORT_SYMBOL(mm_end_of_chunk);
-#else
-EXPORT_SYMBOL(m68k_memoffset);
-#endif /* !CONFIG_SINGLE_MEMORY_CHUNK */
-EXPORT_SYMBOL(__ioremap);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(kernel_set_cachemode);
-#endif /* !CONFIG_SUN3 */
-EXPORT_SYMBOL(m68k_debug_device);
-EXPORT_SYMBOL(mach_hwclk);
-EXPORT_SYMBOL(mach_get_ss);
-EXPORT_SYMBOL(mach_get_rtc_pll);
-EXPORT_SYMBOL(mach_set_rtc_pll);
-#ifdef CONFIG_INPUT_M68K_BEEP_MODULE
-EXPORT_SYMBOL(mach_beep);
-#endif
-EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(dump_thread);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strrchr);
-EXPORT_SYMBOL(strstr);
-EXPORT_SYMBOL(kernel_thread);
-#ifdef CONFIG_VME
-EXPORT_SYMBOL(vme_brdtype);
-#endif
/* The following are special because they're not called
explicitly (the C compiler generates them). Fortunately,
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 45a46646c1b3..99fc1226f7f8 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -187,6 +187,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
set_fs (fs);
return pid;
}
+EXPORT_SYMBOL(kernel_thread);
void flush_thread(void)
{
@@ -221,13 +222,13 @@ asmlinkage int m68k_clone(struct pt_regs *regs)
{
unsigned long clone_flags;
unsigned long newsp;
- int *parent_tidptr, *child_tidptr;
+ int __user *parent_tidptr, *child_tidptr;
/* syscall2 puts clone_flags in d1 and usp in d2 */
clone_flags = regs->d1;
newsp = regs->d2;
- parent_tidptr = (int *)regs->d3;
- child_tidptr = (int *)regs->d4;
+ parent_tidptr = (int __user *)regs->d3;
+ child_tidptr = (int __user *)regs->d4;
if (!newsp)
newsp = rdusp();
return do_fork(clone_flags, newsp, regs, 0,
@@ -311,6 +312,7 @@ int dump_fpu (struct pt_regs *regs, struct user_m68kfp_struct *fpu)
: "memory");
return 1;
}
+EXPORT_SYMBOL(dump_fpu);
/*
* fill in the user structure for a core dump..
@@ -357,11 +359,12 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
/* dump floating point stuff */
dump->u_fpvalid = dump_fpu (regs, &dump->m68kfp);
}
+EXPORT_SYMBOL(dump_thread);
/*
* sys_execve() executes a new program.
*/
-asmlinkage int sys_execve(char *name, char **argv, char **envp)
+asmlinkage int sys_execve(char __user *name, char __user * __user *argv, char __user * __user *envp)
{
int error;
char * filename;
diff --git a/arch/m68k/kernel/setup.c b/arch/m68k/kernel/setup.c
index f2d7ee0ee18c..9af3ee0e555d 100644
--- a/arch/m68k/kernel/setup.c
+++ b/arch/m68k/kernel/setup.c
@@ -42,29 +42,39 @@
unsigned long m68k_machtype;
unsigned long m68k_cputype;
+EXPORT_SYMBOL(m68k_machtype);
+EXPORT_SYMBOL(m68k_cputype);
unsigned long m68k_fputype;
unsigned long m68k_mmutype;
#ifdef CONFIG_VME
unsigned long vme_brdtype;
+EXPORT_SYMBOL(vme_brdtype);
#endif
int m68k_is040or060;
+EXPORT_SYMBOL(m68k_is040or060);
extern int end;
extern unsigned long availmem;
int m68k_num_memory;
int m68k_realnum_memory;
+EXPORT_SYMBOL(m68k_realnum_memory);
+#ifdef CONFIG_SINGLE_MEMORY_CHUNK
unsigned long m68k_memoffset;
+EXPORT_SYMBOL(m68k_memoffset);
+#endif
struct mem_info m68k_memory[NUM_MEMINFO];
+EXPORT_SYMBOL(m68k_memory);
static struct mem_info m68k_ramdisk;
static char m68k_command_line[CL_SIZE];
char m68k_debug_device[6] = "";
+EXPORT_SYMBOL(m68k_debug_device);
-void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;
+void (*mach_sched_init) (irq_handler_t handler) __initdata = NULL;
/* machine dependent irq functions */
void (*mach_init_IRQ) (void) __initdata = NULL;
void (*mach_get_model) (char *model);
@@ -72,10 +82,14 @@ int (*mach_get_hardware_list) (char *buffer);
/* machine dependent timer functions */
unsigned long (*mach_gettimeoffset) (void);
int (*mach_hwclk) (int, struct rtc_time*);
+EXPORT_SYMBOL(mach_hwclk);
int (*mach_set_clock_mmss) (unsigned long);
unsigned int (*mach_get_ss)(void);
int (*mach_get_rtc_pll)(struct rtc_pll_info *);
int (*mach_set_rtc_pll)(struct rtc_pll_info *);
+EXPORT_SYMBOL(mach_get_ss);
+EXPORT_SYMBOL(mach_get_rtc_pll);
+EXPORT_SYMBOL(mach_set_rtc_pll);
void (*mach_reset)( void );
void (*mach_halt)( void );
void (*mach_power_off)( void );
@@ -89,6 +103,7 @@ void (*mach_l2_flush) (int);
#endif
#if defined(CONFIG_INPUT_M68K_BEEP) || defined(CONFIG_INPUT_M68K_BEEP_MODULE)
void (*mach_beep)(unsigned int, unsigned int);
+EXPORT_SYMBOL(mach_beep);
#endif
#if defined(CONFIG_ISA) && defined(MULTI_ISA)
int isa_type;
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 143c552d38f3..90238a8c9e14 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -27,6 +27,7 @@
#include <asm/traps.h>
#include <asm/ipc.h>
#include <asm/page.h>
+#include <asm/unistd.h>
/*
* sys_pipe() is the normal C calling standard for creating
@@ -663,3 +664,18 @@ asmlinkage int sys_getpagesize(void)
{
return PAGE_SIZE;
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register long __res asm ("%d0") = __NR_execve;
+ register long __a asm ("%d1") = (long)(filename);
+ register long __b asm ("%d2") = (long)(argv);
+ register long __c asm ("%d3") = (long)(envp);
+ asm volatile ("trap #0" : "+d" (__res)
+ : "d" (__a), "d" (__b), "d" (__c));
+ return __res;
+}
diff --git a/arch/m68k/kernel/time.c b/arch/m68k/kernel/time.c
index 98e4b1adfa29..2a599c3ed787 100644
--- a/arch/m68k/kernel/time.c
+++ b/arch/m68k/kernel/time.c
@@ -10,7 +10,6 @@
* "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
#include <linux/errno.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -22,6 +21,7 @@
#include <asm/machdep.h>
#include <asm/io.h>
+#include <asm/irq_regs.h>
#include <linux/time.h>
#include <linux/timex.h>
@@ -38,13 +38,13 @@ static inline int set_rtc_mmss(unsigned long nowtime)
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
+static irqreturn_t timer_interrupt(int irq, void *dummy)
{
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#ifdef CONFIG_HEARTBEAT
/* use power LED as a heartbeat instead -- much more useful
@@ -96,31 +96,23 @@ void time_init(void)
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
- extern unsigned long wall_jiffies;
unsigned long seq;
- unsigned long usec, sec, lost;
+ unsigned long usec, sec;
unsigned long max_ntp_tick = tick_usec - tickadj;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = mach_gettimeoffset();
- lost = jiffies - wall_jiffies;
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
- if (unlikely(time_adjust < 0)) {
+ if (unlikely(time_adjust < 0))
usec = min(usec, max_ntp_tick);
- if (lost)
- usec += lost * max_ntp_tick;
- }
- else if (unlikely(lost))
- usec += lost * tick_usec;
-
sec = xtime.tv_sec;
usec += xtime.tv_nsec/1000;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
@@ -141,7 +133,6 @@ int do_settimeofday(struct timespec *tv)
{
time_t wtm_sec, sec = tv->tv_sec;
long wtm_nsec, nsec = tv->tv_nsec;
- extern unsigned long wall_jiffies;
if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;
@@ -153,8 +144,7 @@ int do_settimeofday(struct timespec *tv)
* Discover what correction gettimeofday
* would have done, and then undo it!
*/
- nsec -= 1000 * (mach_gettimeoffset() +
- (jiffies - wall_jiffies) * (1000000 / HZ));
+ nsec -= 1000 * mach_gettimeoffset();
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c
index 4569406a2e1f..759fa244e6cd 100644
--- a/arch/m68k/kernel/traps.c
+++ b/arch/m68k/kernel/traps.c
@@ -326,13 +326,13 @@ static inline int do_040writeback1(unsigned short wbs, unsigned long wba,
switch (wbs & WBSIZ_040) {
case BA_SIZE_BYTE:
- res = put_user(wbd & 0xff, (char *)wba);
+ res = put_user(wbd & 0xff, (char __user *)wba);
break;
case BA_SIZE_WORD:
- res = put_user(wbd & 0xffff, (short *)wba);
+ res = put_user(wbd & 0xffff, (short __user *)wba);
break;
case BA_SIZE_LONG:
- res = put_user(wbd, (int *)wba);
+ res = put_user(wbd, (int __user *)wba);
break;
}
diff --git a/arch/m68k/lib/string.c b/arch/m68k/lib/string.c
index b92b89e1ea0c..891e1347bc4e 100644
--- a/arch/m68k/lib/string.c
+++ b/arch/m68k/lib/string.c
@@ -1,6 +1,19 @@
+/*
+ * 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.
+ */
+
+#define __IN_STRING_C
-#include <linux/types.h>
#include <linux/module.h>
+#include <linux/string.h>
+
+char *strcpy(char *dest, const char *src)
+{
+ return __kernel_strcpy(dest, src);
+}
+EXPORT_SYMBOL(strcpy);
void *memset(void *s, int c, size_t count)
{
diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c
index 1bc188c0d983..865f9fb9e686 100644
--- a/arch/m68k/lib/uaccess.c
+++ b/arch/m68k/lib/uaccess.c
@@ -84,7 +84,7 @@ unsigned long __generic_copy_to_user(void __user *to, const void *from,
" .even\n"
"20: lsl.l #2,%0\n"
"50: add.l %5,%0\n"
- " jra 7b\n"
+ " jra 8b\n"
" .previous\n"
"\n"
" .section __ex_table,\"a\"\n"
diff --git a/arch/m68k/mac/baboon.c b/arch/m68k/mac/baboon.c
index 6eaa881793d1..a1c7ec706741 100644
--- a/arch/m68k/mac/baboon.c
+++ b/arch/m68k/mac/baboon.c
@@ -25,7 +25,7 @@
int baboon_present,baboon_active;
volatile struct baboon *baboon;
-irqreturn_t baboon_irq(int, void *, struct pt_regs *);
+irqreturn_t baboon_irq(int, void *);
#if 0
extern int macide_ack_intr(struct ata_channel *);
@@ -64,7 +64,7 @@ void __init baboon_register_interrupts(void)
* Baboon interrupt handler. This works a lot like a VIA.
*/
-irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t baboon_irq(int irq, void *dev_id)
{
int irq_bit,i;
unsigned char events;
@@ -81,7 +81,7 @@ irqreturn_t baboon_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 3 ; i++, irq_bit <<= 1) {
if (events & irq_bit/* & baboon_active*/) {
baboon_active &= ~irq_bit;
- m68k_handle_int(IRQ_BABOON_0 + i, regs);
+ m68k_handle_int(IRQ_BABOON_0 + i);
baboon_active |= irq_bit;
baboon->mb_ifr &= ~irq_bit;
}
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index 85dda1095b1f..562b38d00180 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -72,7 +72,7 @@ extern int show_mac_interrupts(struct seq_file *, void *);
extern void iop_preinit(void);
extern void iop_init(void);
extern void via_init(void);
-extern void via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *));
+extern void via_init_clock(irq_handler_t func);
extern void via_flush_cache(void);
extern void oss_init(void);
extern void psc_init(void);
@@ -88,7 +88,7 @@ extern void mac_debugging_long(int, long);
static void mac_get_model(char *str);
-static void mac_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
+static void mac_sched_init(irq_handler_t vector)
{
via_init_clock(vector);
}
diff --git a/arch/m68k/mac/iop.c b/arch/m68k/mac/iop.c
index bc657b1057a7..0cea21f58192 100644
--- a/arch/m68k/mac/iop.c
+++ b/arch/m68k/mac/iop.c
@@ -132,7 +132,7 @@ static int iop_get_proc_info(char *, char **, off_t, int);
struct listener {
const char *devname;
- void (*handler)(struct iop_msg *, struct pt_regs *);
+ void (*handler)(struct iop_msg *);
};
/*
@@ -152,7 +152,7 @@ static struct iop_msg iop_msg_pool[NUM_IOP_MSGS];
static struct iop_msg *iop_send_queue[NUM_IOPS][NUM_IOP_CHAN];
static struct listener iop_listeners[NUM_IOPS][NUM_IOP_CHAN];
-irqreturn_t iop_ism_irq(int, void *, struct pt_regs *);
+irqreturn_t iop_ism_irq(int, void *);
extern void oss_irq_enable(int);
@@ -342,7 +342,7 @@ void __init iop_register_interrupts(void)
*/
int iop_listen(uint iop_num, uint chan,
- void (*handler)(struct iop_msg *, struct pt_regs *),
+ void (*handler)(struct iop_msg *),
const char *devname)
{
if ((iop_num >= NUM_IOPS) || !iop_base[iop_num]) return -EINVAL;
@@ -407,7 +407,7 @@ static void iop_do_send(struct iop_msg *msg)
* has gone into the IOP_MSG_COMPLETE state.
*/
-static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs)
+static void iop_handle_send(uint iop_num, uint chan)
{
volatile struct mac_iop *iop = iop_base[iop_num];
struct iop_msg *msg,*msg2;
@@ -426,7 +426,7 @@ static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs)
for (i = 0 ; i < IOP_MSG_LEN ; i++, offset++) {
msg->reply[i] = iop_readb(iop, offset);
}
- if (msg->handler) (*msg->handler)(msg, regs);
+ if (msg->handler) (*msg->handler)(msg);
msg2 = msg;
msg = msg->next;
iop_free_msg(msg2);
@@ -440,7 +440,7 @@ static void iop_handle_send(uint iop_num, uint chan, struct pt_regs *regs)
* gone into the IOP_MSG_NEW state.
*/
-static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs)
+static void iop_handle_recv(uint iop_num, uint chan)
{
volatile struct mac_iop *iop = iop_base[iop_num];
int i,offset;
@@ -468,7 +468,7 @@ static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs)
/* the message ourselves to avoid possible stalls. */
if (msg->handler) {
- (*msg->handler)(msg, regs);
+ (*msg->handler)(msg);
} else {
#ifdef DEBUG_IOP
printk("iop_handle_recv: unclaimed message on iop %d channel %d\n", iop_num, chan);
@@ -492,7 +492,7 @@ static void iop_handle_recv(uint iop_num, uint chan, struct pt_regs *regs)
int iop_send_message(uint iop_num, uint chan, void *privdata,
uint msg_len, __u8 *msg_data,
- void (*handler)(struct iop_msg *, struct pt_regs *))
+ void (*handler)(struct iop_msg *))
{
struct iop_msg *msg, *q;
@@ -584,7 +584,7 @@ __u8 *iop_compare_code(uint iop_num, __u8 *code_start,
* Handle an ISM IOP interrupt
*/
-irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t iop_ism_irq(int irq, void *dev_id)
{
uint iop_num = (uint) dev_id;
volatile struct mac_iop *iop = iop_base[iop_num];
@@ -608,7 +608,7 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs)
printk(" %02X", state);
#endif
if (state == IOP_MSG_COMPLETE) {
- iop_handle_send(iop_num, i, regs);
+ iop_handle_send(iop_num, i);
}
}
#ifdef DEBUG_IOP
@@ -628,7 +628,7 @@ irqreturn_t iop_ism_irq(int irq, void *dev_id, struct pt_regs *regs)
printk(" %02X", state);
#endif
if (state == IOP_MSG_NEW) {
- iop_handle_recv(iop_num, i, regs);
+ iop_handle_recv(iop_num, i);
}
}
#ifdef DEBUG_IOP
diff --git a/arch/m68k/mac/macints.c b/arch/m68k/mac/macints.c
index 694b14bb0de1..f6fcd754d8f6 100644
--- a/arch/m68k/mac/macints.c
+++ b/arch/m68k/mac/macints.c
@@ -133,6 +133,7 @@
#include <asm/hwtest.h>
#include <asm/errno.h>
#include <asm/macints.h>
+#include <asm/irq_regs.h>
#define DEBUG_SPURIOUS
#define SHUTUP_SONIC
@@ -208,8 +209,8 @@ static void scc_irq_disable(unsigned int);
* console_loglevel determines NMI handler function
*/
-irqreturn_t mac_nmi_handler(int, void *, struct pt_regs *);
-irqreturn_t mac_debug_handler(int, void *, struct pt_regs *);
+irqreturn_t mac_nmi_handler(int, void *);
+irqreturn_t mac_debug_handler(int, void *);
/* #define DEBUG_MACINTS */
@@ -393,7 +394,7 @@ int mac_irq_pending(unsigned int irq)
static int num_debug[8];
-irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t mac_debug_handler(int irq, void *dev_id)
{
if (num_debug[irq] < 10) {
printk("DEBUG: Unexpected IRQ %d\n", irq);
@@ -405,7 +406,7 @@ irqreturn_t mac_debug_handler(int irq, void *dev_id, struct pt_regs *regs)
static int in_nmi;
static volatile int nmi_hold;
-irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
+irqreturn_t mac_nmi_handler(int irq, void *dev_id)
{
int i;
/*
@@ -432,6 +433,7 @@ irqreturn_t mac_nmi_handler(int irq, void *dev_id, struct pt_regs *fp)
if (console_loglevel >= 8) {
#if 0
+ struct pt_regs *fp = get_irq_regs();
show_state();
printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
@@ -479,7 +481,7 @@ static void scc_irq_disable(unsigned int irq)
* here is cleaner than hacking it into drivers/char/macserial.c.
*/
-void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
+void mac_scc_dispatch(int irq, void *dev_id)
{
volatile unsigned char *scc = (unsigned char *) mac_bi_data.sccbase + 2;
unsigned char reg;
@@ -504,7 +506,7 @@ void mac_scc_dispatch(int irq, void *dev_id, struct pt_regs *regs)
/* pretty much kill the system. */
if (reg & 0x38)
- m68k_handle_int(IRQ_SCCA, regs);
+ m68k_handle_int(IRQ_SCCA);
if (reg & 0x07)
- m68k_handle_int(IRQ_SCCB, regs);
+ m68k_handle_int(IRQ_SCCB);
}
diff --git a/arch/m68k/mac/oss.c b/arch/m68k/mac/oss.c
index 63e04365191f..63690819565a 100644
--- a/arch/m68k/mac/oss.c
+++ b/arch/m68k/mac/oss.c
@@ -30,11 +30,11 @@
int oss_present;
volatile struct mac_oss *oss;
-irqreturn_t oss_irq(int, void *, struct pt_regs *);
-irqreturn_t oss_nubus_irq(int, void *, struct pt_regs *);
+irqreturn_t oss_irq(int, void *);
+irqreturn_t oss_nubus_irq(int, void *);
-extern irqreturn_t via1_irq(int, void *, struct pt_regs *);
-extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *);
+extern irqreturn_t via1_irq(int, void *);
+extern irqreturn_t mac_scc_dispatch(int, void *);
/*
* Initialize the OSS
@@ -92,7 +92,7 @@ void __init oss_nubus_init(void)
* and SCSI; everything else is routed to its own autovector IRQ.
*/
-irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t oss_irq(int irq, void *dev_id)
{
int events;
@@ -113,7 +113,7 @@ irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs)
oss->irq_pending &= ~OSS_IP_SOUND;
} else if (events & OSS_IP_SCSI) {
oss->irq_level[OSS_SCSI] = OSS_IRQLEV_DISABLED;
- m68k_handle_int(IRQ_MAC_SCSI, regs);
+ m68k_handle_int(IRQ_MAC_SCSI);
oss->irq_pending &= ~OSS_IP_SCSI;
oss->irq_level[OSS_SCSI] = OSS_IRQLEV_SCSI;
} else {
@@ -128,7 +128,7 @@ irqreturn_t oss_irq(int irq, void *dev_id, struct pt_regs *regs)
* Unlike the VIA/RBV this is on its own autovector interrupt level.
*/
-irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t oss_nubus_irq(int irq, void *dev_id)
{
int events, irq_bit, i;
@@ -146,7 +146,7 @@ irqreturn_t oss_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 6 ; i++, irq_bit <<= 1) {
if (events & irq_bit) {
oss->irq_level[i] = OSS_IRQLEV_DISABLED;
- m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
+ m68k_handle_int(NUBUS_SOURCE_BASE + i);
oss->irq_pending &= ~irq_bit;
oss->irq_level[i] = OSS_IRQLEV_NUBUS;
}
diff --git a/arch/m68k/mac/psc.c b/arch/m68k/mac/psc.c
index e26218091755..15378a5878c9 100644
--- a/arch/m68k/mac/psc.c
+++ b/arch/m68k/mac/psc.c
@@ -30,7 +30,7 @@
int psc_present;
volatile __u8 *psc;
-irqreturn_t psc_irq(int, void *, struct pt_regs *);
+irqreturn_t psc_irq(int, void *);
/*
* Debugging dump, used in various places to see what's going on.
@@ -127,7 +127,7 @@ void __init psc_register_interrupts(void)
* PSC interrupt handler. It's a lot like the VIA interrupt handler.
*/
-irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t psc_irq(int irq, void *dev_id)
{
int pIFR = pIFRbase + ((int) dev_id);
int pIER = pIERbase + ((int) dev_id);
@@ -149,7 +149,7 @@ irqreturn_t psc_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 4 ; i++, irq_bit <<= 1) {
if (events & irq_bit) {
psc_write_byte(pIER, irq_bit);
- m68k_handle_int(base_irq + i, regs);
+ m68k_handle_int(base_irq + i);
psc_write_byte(pIFR, irq_bit);
psc_write_byte(pIER, irq_bit | 0x80);
}
diff --git a/arch/m68k/mac/via.c b/arch/m68k/mac/via.c
index c4aa345d544e..e27735be2924 100644
--- a/arch/m68k/mac/via.c
+++ b/arch/m68k/mac/via.c
@@ -63,14 +63,14 @@ static int gIER,gIFR,gBufA,gBufB;
static int nubus_active;
void via_debug_dump(void);
-irqreturn_t via1_irq(int, void *, struct pt_regs *);
-irqreturn_t via2_irq(int, void *, struct pt_regs *);
-irqreturn_t via_nubus_irq(int, void *, struct pt_regs *);
+irqreturn_t via1_irq(int, void *);
+irqreturn_t via2_irq(int, void *);
+irqreturn_t via_nubus_irq(int, void *);
void via_irq_enable(int irq);
void via_irq_disable(int irq);
void via_irq_clear(int irq);
-extern irqreturn_t mac_scc_dispatch(int, void *, struct pt_regs *);
+extern irqreturn_t mac_scc_dispatch(int, void *);
extern int oss_present;
/*
@@ -235,7 +235,7 @@ void __init via_init(void)
* Start the 100 Hz clock
*/
-void __init via_init_clock(irqreturn_t (*func)(int, void *, struct pt_regs *))
+void __init via_init_clock(irq_handler_t func)
{
via1[vACR] |= 0x40;
via1[vT1LL] = MAC_CLOCK_LOW;
@@ -412,7 +412,7 @@ void __init via_nubus_init(void)
* the machspec interrupt number after clearing the interrupt.
*/
-irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t via1_irq(int irq, void *dev_id)
{
int irq_bit, i;
unsigned char events, mask;
@@ -424,7 +424,7 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1)
if (events & irq_bit) {
via1[vIER] = irq_bit;
- m68k_handle_int(VIA1_SOURCE_BASE + i, regs);
+ m68k_handle_int(VIA1_SOURCE_BASE + i);
via1[vIFR] = irq_bit;
via1[vIER] = irq_bit | 0x80;
}
@@ -439,14 +439,14 @@ irqreturn_t via1_irq(int irq, void *dev_id, struct pt_regs *regs)
/* No, it won't be set. that's why we're doing this. */
via_irq_disable(IRQ_MAC_NUBUS);
via_irq_clear(IRQ_MAC_NUBUS);
- m68k_handle_int(IRQ_MAC_NUBUS, regs);
+ m68k_handle_int(IRQ_MAC_NUBUS);
via_irq_enable(IRQ_MAC_NUBUS);
}
#endif
return IRQ_HANDLED;
}
-irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t via2_irq(int irq, void *dev_id)
{
int irq_bit, i;
unsigned char events, mask;
@@ -459,7 +459,7 @@ irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs)
if (events & irq_bit) {
via2[gIER] = irq_bit;
via2[gIFR] = irq_bit | rbv_clear;
- m68k_handle_int(VIA2_SOURCE_BASE + i, regs);
+ m68k_handle_int(VIA2_SOURCE_BASE + i);
via2[gIER] = irq_bit | 0x80;
}
return IRQ_HANDLED;
@@ -470,7 +470,7 @@ irqreturn_t via2_irq(int irq, void *dev_id, struct pt_regs *regs)
* VIA2 dispatcher as a fast interrupt handler.
*/
-irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t via_nubus_irq(int irq, void *dev_id)
{
int irq_bit, i;
unsigned char events;
@@ -481,7 +481,7 @@ irqreturn_t via_nubus_irq(int irq, void *dev_id, struct pt_regs *regs)
for (i = 0, irq_bit = 1 ; i < 7 ; i++, irq_bit <<= 1) {
if (events & irq_bit) {
via_irq_disable(NUBUS_SOURCE_BASE + i);
- m68k_handle_int(NUBUS_SOURCE_BASE + i, regs);
+ m68k_handle_int(NUBUS_SOURCE_BASE + i);
via_irq_enable(NUBUS_SOURCE_BASE + i);
}
}
diff --git a/arch/m68k/mm/fault.c b/arch/m68k/mm/fault.c
index aec15270d334..911f2ce3f53e 100644
--- a/arch/m68k/mm/fault.c
+++ b/arch/m68k/mm/fault.c
@@ -144,7 +144,7 @@ good_area:
case 1: /* read, present */
goto acc_err;
case 0: /* read, not present */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto acc_err;
}
@@ -181,7 +181,7 @@ good_area:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/m68k/mm/kmap.c b/arch/m68k/mm/kmap.c
index f46f049d29ff..b54ef1726c55 100644
--- a/arch/m68k/mm/kmap.c
+++ b/arch/m68k/mm/kmap.c
@@ -7,6 +7,7 @@
* used by other architectures /Roman Zippel
*/
+#include <linux/module.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -219,6 +220,7 @@ void __iomem *__ioremap(unsigned long physaddr, unsigned long size, int cachefla
return (void __iomem *)retaddr;
}
+EXPORT_SYMBOL(__ioremap);
/*
* Unmap a ioremap()ed region again
@@ -234,6 +236,7 @@ void iounmap(void __iomem *addr)
free_io_area((__force void *)addr);
#endif
}
+EXPORT_SYMBOL(iounmap);
/*
* __iounmap unmaps nearly everything, so be careful
@@ -360,3 +363,4 @@ void kernel_set_cachemode(void *addr, unsigned long size, int cmode)
flush_tlb_all();
}
+EXPORT_SYMBOL(kernel_set_cachemode);
diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c
index a0c095e17222..0f88812822b1 100644
--- a/arch/m68k/mm/memory.c
+++ b/arch/m68k/mm/memory.c
@@ -4,6 +4,7 @@
* Copyright (C) 1995 Hamish Macdonald
*/
+#include <linux/module.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/string.h>
@@ -157,9 +158,8 @@ unsigned long mm_vtop(unsigned long vaddr)
return -1;
}
-#endif
+EXPORT_SYMBOL(mm_vtop);
-#ifndef CONFIG_SINGLE_MEMORY_CHUNK
unsigned long mm_ptov (unsigned long paddr)
{
int i = 0;
@@ -185,6 +185,7 @@ unsigned long mm_ptov (unsigned long paddr)
#endif
return -1;
}
+EXPORT_SYMBOL(mm_ptov);
#endif
/* invalidate page in both caches */
@@ -298,6 +299,7 @@ void cache_clear (unsigned long paddr, int len)
mach_l2_flush(0);
#endif
}
+EXPORT_SYMBOL(cache_clear); /* probably can be unexported */
/*
@@ -350,6 +352,7 @@ void cache_push (unsigned long paddr, int len)
mach_l2_flush(1);
#endif
}
+EXPORT_SYMBOL(cache_push); /* probably can be unexported */
#ifndef CONFIG_SINGLE_MEMORY_CHUNK
int mm_end_of_chunk (unsigned long addr, int len)
@@ -361,4 +364,5 @@ int mm_end_of_chunk (unsigned long addr, int len)
return 1;
return 0;
}
+EXPORT_SYMBOL(mm_end_of_chunk);
#endif
diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c
index 49015e32d8fc..afcccdc6ad45 100644
--- a/arch/m68k/mm/motorola.c
+++ b/arch/m68k/mm/motorola.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/m68k/motorola.c
+ * linux/arch/m68k/mm/motorola.c
*
* Routines specific to the Motorola MMU, originally from:
* linux/arch/m68k/init.c
diff --git a/arch/m68k/mm/sun3kmap.c b/arch/m68k/mm/sun3kmap.c
index 7f0d86f3fe73..1af24cb5bfe1 100644
--- a/arch/m68k/mm/sun3kmap.c
+++ b/arch/m68k/mm/sun3kmap.c
@@ -8,6 +8,7 @@
* for more details.
*/
+#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
@@ -59,7 +60,7 @@ static inline void do_pmeg_mapin(unsigned long phys, unsigned long virt,
}
}
-void *sun3_ioremap(unsigned long phys, unsigned long size,
+void __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
unsigned long type)
{
struct vm_struct *area;
@@ -101,22 +102,24 @@ void *sun3_ioremap(unsigned long phys, unsigned long size,
virt += seg_pages * PAGE_SIZE;
}
- return (void *)ret;
+ return (void __iomem *)ret;
}
-void *__ioremap(unsigned long phys, unsigned long size, int cache)
+void __iomem *__ioremap(unsigned long phys, unsigned long size, int cache)
{
return sun3_ioremap(phys, size, SUN3_PAGE_TYPE_IO);
}
+EXPORT_SYMBOL(__ioremap);
-void iounmap(void *addr)
+void iounmap(void __iomem *addr)
{
vfree((void *)(PAGE_MASK & (unsigned long)addr));
}
+EXPORT_SYMBOL(iounmap);
/* sun3_map_test(addr, val) -- Reads a byte from addr, storing to val,
* trapping the potential read fault. Returns 0 if the access faulted,
diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c
index 0cd0e5bddcee..4a7df9c3f85a 100644
--- a/arch/m68k/mvme147/config.c
+++ b/arch/m68k/mvme147/config.c
@@ -38,7 +38,7 @@
static void mvme147_get_model(char *model);
static int mvme147_get_hardware_list(char *buffer);
-extern void mvme147_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+extern void mvme147_sched_init(irq_handler_t handler);
extern unsigned long mvme147_gettimeoffset (void);
extern int mvme147_hwclk (int, struct rtc_time *);
extern int mvme147_set_clock_mmss (unsigned long);
@@ -51,7 +51,7 @@ static int bcd2int (unsigned char b);
/* Save tick handler routine pointer, will point to do_timer() in
* kernel/sched.c, called via mvme147_process_int() */
-irqreturn_t (*tick_handler)(int, void *, struct pt_regs *);
+irq_handler_t tick_handler;
int mvme147_parse_bootinfo(const struct bi_record *bi)
@@ -114,15 +114,15 @@ void __init config_mvme147(void)
/* Using pcc tick timer 1 */
-static irqreturn_t mvme147_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t mvme147_timer_int (int irq, void *dev_id)
{
m147_pcc->t1_int_cntrl = PCC_TIMER_INT_CLR;
m147_pcc->t1_int_cntrl = PCC_INT_ENAB|PCC_LEVEL_TIMER1;
- return tick_handler(irq, dev_id, fp);
+ return tick_handler(irq, dev_id);
}
-void mvme147_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
+void mvme147_sched_init (irq_handler_t timer_routine)
{
tick_handler = timer_routine;
request_irq (PCC_IRQ_TIMER1, mvme147_timer_int,
diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c
index ce2727ed1bc0..c829ebb6b1af 100644
--- a/arch/m68k/mvme16x/config.c
+++ b/arch/m68k/mvme16x/config.c
@@ -42,7 +42,7 @@ static MK48T08ptr_t volatile rtc = (MK48T08ptr_t)MVME_RTC_BASE;
static void mvme16x_get_model(char *model);
static int mvme16x_get_hardware_list(char *buffer);
-extern void mvme16x_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+extern void mvme16x_sched_init(irq_handler_t handler);
extern unsigned long mvme16x_gettimeoffset (void);
extern int mvme16x_hwclk (int, struct rtc_time *);
extern int mvme16x_set_clock_mmss (unsigned long);
@@ -54,7 +54,7 @@ int bcd2int (unsigned char b);
/* Save tick handler routine pointer, will point to do_timer() in
* kernel/sched.c, called via mvme16x_process_int() */
-static irqreturn_t (*tick_handler)(int, void *, struct pt_regs *);
+static irq_handler_t tick_handler;
unsigned short mvme16x_config;
@@ -190,7 +190,7 @@ void __init config_mvme16x(void)
}
}
-static irqreturn_t mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t mvme16x_abort_int (int irq, void *dev_id)
{
p_bdid p = &mvme_bdid;
unsigned long *new = (unsigned long *)vectors;
@@ -218,13 +218,13 @@ static irqreturn_t mvme16x_abort_int (int irq, void *dev_id, struct pt_regs *fp)
return IRQ_HANDLED;
}
-static irqreturn_t mvme16x_timer_int (int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t mvme16x_timer_int (int irq, void *dev_id)
{
*(volatile unsigned char *)0xfff4201b |= 8;
- return tick_handler(irq, dev_id, fp);
+ return tick_handler(irq, dev_id);
}
-void mvme16x_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
+void mvme16x_sched_init (irq_handler_t timer_routine)
{
p_bdid p = &mvme_bdid;
int irq;
diff --git a/arch/m68k/q40/config.c b/arch/m68k/q40/config.c
index 9a1827876408..92f873cc7060 100644
--- a/arch/m68k/q40/config.c
+++ b/arch/m68k/q40/config.c
@@ -39,7 +39,7 @@ extern irqreturn_t q40_process_int (int level, struct pt_regs *regs);
extern void q40_init_IRQ (void);
static void q40_get_model(char *model);
static int q40_get_hardware_list(char *buffer);
-extern void q40_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+extern void q40_sched_init(irq_handler_t handler);
extern unsigned long q40_gettimeoffset (void);
extern int q40_hwclk (int, struct rtc_time *);
diff --git a/arch/m68k/q40/q40ints.c b/arch/m68k/q40/q40ints.c
index 472f41c4158b..31cc07d8cec4 100644
--- a/arch/m68k/q40/q40ints.c
+++ b/arch/m68k/q40/q40ints.c
@@ -125,9 +125,9 @@ void q40_mksound(unsigned int hz, unsigned int ticks)
sound_ticks = ticks << 1;
}
-static irqreturn_t (*q40_timer_routine)(int, void *, struct pt_regs *);
+static irq_handler_t q40_timer_routine;
-static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs)
+static irqreturn_t q40_timer_int (int irq, void * dev)
{
ql_ticks = ql_ticks ? 0 : 1;
if (sound_ticks) {
@@ -138,11 +138,11 @@ static irqreturn_t q40_timer_int (int irq, void * dev, struct pt_regs * regs)
}
if (!ql_ticks)
- q40_timer_routine(irq, dev, regs);
+ q40_timer_routine(irq, dev);
return IRQ_HANDLED;
}
-void q40_sched_init (irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
+void q40_sched_init (irq_handler_t timer_routine)
{
int timer_irq;
@@ -218,11 +218,11 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
switch (irq) {
case 4:
case 6:
- m68k_handle_int(Q40_IRQ_SAMPLE, fp);
+ __m68k_handle_int(Q40_IRQ_SAMPLE, fp);
return;
}
if (mir & Q40_IRQ_FRAME_MASK) {
- m68k_handle_int(Q40_IRQ_FRAME, fp);
+ __m68k_handle_int(Q40_IRQ_FRAME, fp);
master_outb(-1, FRAME_CLEAR_REG);
}
if ((mir & Q40_IRQ_SER_MASK) || (mir & Q40_IRQ_EXT_MASK)) {
@@ -257,7 +257,7 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
goto iirq;
}
q40_state[irq] |= IRQ_INPROGRESS;
- m68k_handle_int(irq, fp);
+ __m68k_handle_int(irq, fp);
q40_state[irq] &= ~IRQ_INPROGRESS;
/* naively enable everything, if that fails than */
@@ -288,7 +288,7 @@ static void q40_irq_handler(unsigned int irq, struct pt_regs *fp)
mir = master_inb(IIRQ_REG);
/* should test whether keyboard irq is really enabled, doing it in defhand */
if (mir & Q40_IRQ_KEYB_MASK)
- m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
+ __m68k_handle_int(Q40_IRQ_KEYBOARD, fp);
return;
}
diff --git a/arch/m68k/sun3/Makefile b/arch/m68k/sun3/Makefile
index 4d4f0695d985..be1a8470d636 100644
--- a/arch/m68k/sun3/Makefile
+++ b/arch/m68k/sun3/Makefile
@@ -2,6 +2,6 @@
# Makefile for Linux arch/m68k/sun3 source directory
#
-obj-y := sun3_ksyms.o sun3ints.o sun3dvma.o sbus.o idprom.o
+obj-y := sun3ints.o sun3dvma.o sbus.o idprom.o
obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o intersil.o
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index d09d03b3d956..4851b8437a87 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -35,7 +35,7 @@ extern char _text, _end;
char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
extern unsigned long sun3_gettimeoffset(void);
-extern void sun3_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+extern void sun3_sched_init(irq_handler_t handler);
extern void sun3_get_model (char* model);
extern void idprom_init (void);
extern int sun3_hwclk(int set, struct rtc_time *t);
@@ -162,7 +162,7 @@ void __init config_sun3(void)
sun3_bootmem_alloc(memory_start, memory_end);
}
-void __init sun3_sched_init(irqreturn_t (*timer_routine)(int, void *, struct pt_regs *))
+void __init sun3_sched_init(irq_handler_t timer_routine)
{
sun3_disable_interrupts();
intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE);
diff --git a/arch/m68k/sun3/idprom.c b/arch/m68k/sun3/idprom.c
index 02c1fee6fe74..dca6ab6a4ede 100644
--- a/arch/m68k/sun3/idprom.c
+++ b/arch/m68k/sun3/idprom.c
@@ -6,6 +6,7 @@
* Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au)
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
@@ -16,6 +17,8 @@
#include <asm/machines.h> /* Fun with Sun released architectures. */
struct idprom *idprom;
+EXPORT_SYMBOL(idprom);
+
static struct idprom idprom_buffer;
/* Here is the master table of Sun machines which use some implementation
diff --git a/arch/m68k/sun3/sun3_ksyms.c b/arch/m68k/sun3/sun3_ksyms.c
deleted file mode 100644
index 43e5a9af8abd..000000000000
--- a/arch/m68k/sun3/sun3_ksyms.c
+++ /dev/null
@@ -1,13 +0,0 @@
-#include <linux/module.h>
-#include <linux/types.h>
-#include <asm/dvma.h>
-#include <asm/idprom.h>
-
-/*
- * Add things here when you find the need for it.
- */
-EXPORT_SYMBOL(dvma_map_align);
-EXPORT_SYMBOL(dvma_unmap);
-EXPORT_SYMBOL(dvma_malloc_align);
-EXPORT_SYMBOL(dvma_free);
-EXPORT_SYMBOL(idprom);
diff --git a/arch/m68k/sun3/sun3dvma.c b/arch/m68k/sun3/sun3dvma.c
index 6c265222cbcd..8709677fa025 100644
--- a/arch/m68k/sun3/sun3dvma.c
+++ b/arch/m68k/sun3/sun3dvma.c
@@ -1,11 +1,12 @@
/*
- * linux/arch/m68k/mm/sun3dvma.c
+ * linux/arch/m68k/sun3/sun3dvma.c
*
* Copyright (C) 2000 Sam Creasey
*
* Contains common routines for sun3/sun3x DVMA management.
*/
+#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/list.h>
@@ -312,6 +313,7 @@ inline unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
BUG();
return 0;
}
+EXPORT_SYMBOL(dvma_map_align);
void dvma_unmap(void *baddr)
{
@@ -327,7 +329,7 @@ void dvma_unmap(void *baddr)
return;
}
-
+EXPORT_SYMBOL(dvma_unmap);
void *dvma_malloc_align(unsigned long len, unsigned long align)
{
@@ -367,6 +369,7 @@ void *dvma_malloc_align(unsigned long len, unsigned long align)
return (void *)vaddr;
}
+EXPORT_SYMBOL(dvma_malloc_align);
void dvma_free(void *vaddr)
{
@@ -374,3 +377,4 @@ void dvma_free(void *vaddr)
return;
}
+EXPORT_SYMBOL(dvma_free);
diff --git a/arch/m68k/sun3/sun3ints.c b/arch/m68k/sun3/sun3ints.c
index f18b9d3ef16d..baf74e8de8b5 100644
--- a/arch/m68k/sun3/sun3ints.c
+++ b/arch/m68k/sun3/sun3ints.c
@@ -15,6 +15,7 @@
#include <asm/intersil.h>
#include <asm/oplib.h>
#include <asm/sun3ints.h>
+#include <asm/irq_regs.h>
#include <linux/seq_file.h>
extern void sun3_leds (unsigned char);
@@ -48,7 +49,7 @@ void sun3_disable_irq(unsigned int irq)
*sun3_intreg &= ~(1 << irq);
}
-static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t sun3_int7(int irq, void *dev_id)
{
*sun3_intreg |= (1 << irq);
if (!(kstat_cpu(0).irqs[irq] % 2000))
@@ -56,7 +57,7 @@ static irqreturn_t sun3_int7(int irq, void *dev_id, struct pt_regs *fp)
return IRQ_HANDLED;
}
-static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t sun3_int5(int irq, void *dev_id)
{
#ifdef CONFIG_SUN3
intersil_clear();
@@ -65,16 +66,16 @@ static irqreturn_t sun3_int5(int irq, void *dev_id, struct pt_regs *fp)
#ifdef CONFIG_SUN3
intersil_clear();
#endif
- do_timer(fp);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(fp));
+ update_process_times(user_mode(get_irq_regs()));
#endif
if (!(kstat_cpu(0).irqs[irq] % 20))
sun3_leds(led_pattern[(kstat_cpu(0).irqs[irq] % 160) / 20]);
return IRQ_HANDLED;
}
-static irqreturn_t sun3_vec255(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t sun3_vec255(int irq, void *dev_id)
{
// intersil_clear();
return IRQ_HANDLED;
@@ -84,7 +85,7 @@ static void sun3_inthandle(unsigned int irq, struct pt_regs *fp)
{
*sun3_intreg &= ~(1 << irq);
- m68k_handle_int(irq, fp);
+ __m68k_handle_int(irq, fp);
}
static struct irq_controller sun3_irq_controller = {
diff --git a/arch/m68k/sun3x/time.c b/arch/m68k/sun3x/time.c
index 6f4204fbecd7..f5eaafb00d21 100644
--- a/arch/m68k/sun3x/time.c
+++ b/arch/m68k/sun3x/time.c
@@ -90,7 +90,7 @@ static void sun3x_timer_tick(int irq, void *dev_id, struct pt_regs *regs)
}
#endif
-void __init sun3x_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *))
+void __init sun3x_sched_init(irq_handler_t vector)
{
sun3_disable_interrupts();
diff --git a/arch/m68k/sun3x/time.h b/arch/m68k/sun3x/time.h
index e7e43b4ec4a1..6909e1297534 100644
--- a/arch/m68k/sun3x/time.h
+++ b/arch/m68k/sun3x/time.h
@@ -3,7 +3,7 @@
extern int sun3x_hwclk(int set, struct rtc_time *t);
unsigned long sun3x_gettimeoffset (void);
-void sun3x_sched_init(irqreturn_t (*vector)(int, void *, struct pt_regs *));
+void sun3x_sched_init(irq_handler_t vector);
struct mostek_dt {
volatile unsigned char csr;
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index e767f2ddae72..6d920d4bdc3d 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -161,8 +161,8 @@ config CLOCK_FREQ
frequency, it may or may not be the same as the external clock
crystal fitted to your board. Some processors have an internal
PLL and can have their frequency programmed at run time, others
- use internal dividers. In gernal the kernel won't setup a PLL
- if it is fitted (there are some expections). This value will be
+ use internal dividers. In general the kernel won't setup a PLL
+ if it is fitted (there are some exceptions). This value will be
specific to the exact CPU that you are using.
config CLOCK_DIV
@@ -495,7 +495,7 @@ config VECTORBASE
hex "Address of the base of system vectors"
default "0"
help
- Define the address of the the system vectors. Commonly this is
+ Define the address of the system vectors. Commonly this is
put at the start of RAM, but it doesn't have to be. On ColdFire
platforms this address is programmed into the VBR register, thus
actually setting the address to use.
diff --git a/arch/m68knommu/kernel/sys_m68k.c b/arch/m68knommu/kernel/sys_m68k.c
index d87e1e0a1336..c3494b8447d1 100644
--- a/arch/m68knommu/kernel/sys_m68k.c
+++ b/arch/m68knommu/kernel/sys_m68k.c
@@ -26,6 +26,7 @@
#include <asm/traps.h>
#include <asm/ipc.h>
#include <asm/cacheflush.h>
+#include <asm/unistd.h>
/*
* sys_pipe() is the normal C calling standard for creating
@@ -206,3 +207,17 @@ asmlinkage int sys_getpagesize(void)
return PAGE_SIZE;
}
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register long __res asm ("%d0") = __NR_execve;
+ register long __a asm ("%d1") = (long)(filename);
+ register long __b asm ("%d2") = (long)(argv);
+ register long __c asm ("%d3") = (long)(envp);
+ asm volatile ("trap #0" : "+d" (__res)
+ : "d" (__a), "d" (__b), "d" (__c));
+ return __res;
+}
diff --git a/arch/m68knommu/kernel/syscalltable.S b/arch/m68knommu/kernel/syscalltable.S
index 617e43ec95ae..4603f4f3c935 100644
--- a/arch/m68knommu/kernel/syscalltable.S
+++ b/arch/m68knommu/kernel/syscalltable.S
@@ -296,10 +296,39 @@ ENTRY(sys_call_table)
.long sys_mq_notify /* 275 */
.long sys_mq_getsetattr
.long sys_waitid
- .long sys_ni_syscall /* sys_setaltroot */
- .long sys_ni_syscall /* sys_add_key */
- .long sys_ni_syscall /* 280 */ /* sys_request_key */
- .long sys_ni_syscall /* sys_keyctl */
+ .long sys_ni_syscall /* for sys_vserver */
+ .long sys_add_key
+ .long sys_request_key /* 280 */
+ .long sys_keyctl
+ .long sys_ioprio_set
+ .long sys_ioprio_get
+ .long sys_inotify_init
+ .long sys_inotify_add_watch /* 285 */
+ .long sys_inotify_rm_watch
+ .long sys_migrate_pages
+ .long sys_openat
+ .long sys_mkdirat
+ .long sys_mknodat /* 290 */
+ .long sys_fchownat
+ .long sys_futimesat
+ .long sys_fstatat64
+ .long sys_unlinkat
+ .long sys_renameat /* 295 */
+ .long sys_linkat
+ .long sys_symlinkat
+ .long sys_readlinkat
+ .long sys_fchmodat
+ .long sys_faccessat /* 300 */
+ .long sys_ni_syscall /* Reserved for pselect6 */
+ .long sys_ni_syscall /* Reserved for ppoll */
+ .long sys_unshare
+ .long sys_set_robust_list
+ .long sys_get_robust_list /* 305 */
+ .long sys_splice
+ .long sys_sync_file_range
+ .long sys_tee
+ .long sys_vmsplice
+ .long sys_move_pages /* 310 */
.rept NR_syscalls-(.-sys_call_table)/4
.long sys_ni_syscall
diff --git a/arch/m68knommu/kernel/time.c b/arch/m68knommu/kernel/time.c
index 1db987272220..c5667bdddd5e 100644
--- a/arch/m68knommu/kernel/time.c
+++ b/arch/m68knommu/kernel/time.c
@@ -26,8 +26,6 @@
#define TICK_SIZE (tick_nsec / 1000)
-extern unsigned long wall_jiffies;
-
static inline int set_rtc_mmss(unsigned long nowtime)
{
@@ -51,7 +49,7 @@ static irqreturn_t timer_interrupt(int irq, void *dummy, struct pt_regs * regs)
write_seqlock(&xtime_lock);
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
@@ -124,15 +122,12 @@ void time_init(void)
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
- unsigned long lost, seq;
+ unsigned long seq;
unsigned long usec, sec;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = mach_gettimeoffset ? mach_gettimeoffset() : 0;
- lost = jiffies - wall_jiffies;
- if (lost)
- usec += lost * (1000000 / HZ);
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / 1000);
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
diff --git a/arch/m68knommu/platform/532x/config.c b/arch/m68knommu/platform/532x/config.c
index ceef9bc181ea..c7d6ad513820 100644
--- a/arch/m68knommu/platform/532x/config.c
+++ b/arch/m68knommu/platform/532x/config.c
@@ -17,7 +17,6 @@
/***************************************************************************/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/param.h>
diff --git a/arch/m68knommu/platform/68328/head-pilot.S b/arch/m68knommu/platform/68328/head-pilot.S
index 9e07faa3e81d..aecff532b343 100644
--- a/arch/m68knommu/platform/68328/head-pilot.S
+++ b/arch/m68knommu/platform/68328/head-pilot.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/m68knommu/platform/68328/head-rom.S
+ * linux/arch/m68knommu/platform/68328/head-pilot.S
* - A startup file for the MC68328
*
* Copyright (C) 1998 D. Jeff Dionne <jeff@ryeham.ee.ryerson.ca>,
diff --git a/arch/m68knommu/platform/68328/romvec.S b/arch/m68knommu/platform/68328/romvec.S
index 3e7fe1e14913..31084466eae8 100644
--- a/arch/m68knommu/platform/68328/romvec.S
+++ b/arch/m68knommu/platform/68328/romvec.S
@@ -10,8 +10,6 @@
* Copyright 2006 Greg Ungerer <gerg@snapgear.com>
*/
-#include <linux/config.h>
-
.global _start
.global _buserr
.global trap
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 330f6abc7703..14af6cce2fa2 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -126,7 +126,7 @@ config BASLER_EXCITE
select IRQ_CPU
select IRQ_CPU_RM7K
select IRQ_CPU_RM9K
- select SERIAL_RM9000
+ select MIPS_RM9122
select SYS_HAS_CPU_RM9000
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_64BIT_KERNEL
@@ -203,59 +203,6 @@ config MIPS_EV64120
<http://www.marvell.com/>. Say Y here if you wish to build a
kernel for this platform.
-config MIPS_EV96100
- bool "Galileo EV96100 Evaluation board (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select IRQ_CPU
- select MIPS_GT96100
- select RM7000_CPU_SCACHE
- select SWAP_IO_SPACE
- select SYS_HAS_CPU_R5000
- select SYS_HAS_CPU_RM7000
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
- select SYS_SUPPORTS_BIG_ENDIAN
- help
- This is an evaluation board based on the Galileo GT-96100 LAN/WAN
- communications controllers containing a MIPS R5000 compatible core
- running at 83MHz. Their website is <http://www.marvell.com/>. Say Y
- here if you wish to build a kernel for this platform.
-
-config MIPS_IVR
- bool "Globespan IVR board"
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select ITE_BOARD_GEN
- select SYS_HAS_CPU_NEVADA
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
- select SYS_SUPPORTS_LITTLE_ENDIAN
- help
- This is an evaluation board built by Globespan to showcase thir
- iVR (Internet Video Recorder) design. It utilizes a QED RM5231
- R5000 MIPS core. More information can be found out their website
- located at <http://www.globespan.net/>. Say Y here if you wish to
- build a kernel for this platform.
-
-config MIPS_ITE8172
- bool "ITE 8172G board"
- select DMA_NONCOHERENT
- select HW_HAS_PCI
- select ITE_BOARD_GEN
- select SYS_HAS_CPU_R5432
- select SYS_HAS_CPU_NEVADA
- select SYS_SUPPORTS_32BIT_KERNEL
- select SYS_SUPPORTS_64BIT_KERNEL if EXPERIMENTAL
- select SYS_SUPPORTS_LITTLE_ENDIAN
- help
- Ths is an evaluation board made by ITE <http://www.ite.com.tw/>
- with ATX form factor that utilizes a MIPS R5000 to work with its
- ITE8172G companion internet appliance chip. The MIPS core can be
- either a NEC Vr5432 or QED RM5231. Say Y here if you wish to build
- a kernel for this platform.
-
config MACH_JAZZ
bool "Jazz family of machines"
select ARC
@@ -493,13 +440,11 @@ config MIPS_XXS1500
config PNX8550_V2PCI
bool "Philips PNX8550 based Viper2-PCI board"
- depends on BROKEN
select PNX8550
select SYS_SUPPORTS_LITTLE_ENDIAN
config PNX8550_JBS
bool "Philips PNX8550 based JBS board"
- depends on BROKEN
select PNX8550
select SYS_SUPPORTS_LITTLE_ENDIAN
@@ -557,6 +502,7 @@ config QEMU
select SYS_HAS_CPU_MIPS32_R1
select SYS_SUPPORTS_32BIT_KERNEL
select SYS_SUPPORTS_BIG_ENDIAN
+ select SYS_SUPPORTS_LITTLE_ENDIAN
select ARCH_SPARSEMEM_ENABLE
help
Qemu is a software emulator which among other architectures also
@@ -823,7 +769,6 @@ endchoice
source "arch/mips/ddb5xxx/Kconfig"
source "arch/mips/gt64120/ev64120/Kconfig"
source "arch/mips/jazz/Kconfig"
-source "arch/mips/ite-boards/Kconfig"
source "arch/mips/lasat/Kconfig"
source "arch/mips/momentum/Kconfig"
source "arch/mips/pmc-sierra/Kconfig"
@@ -856,6 +801,10 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_TIME
+ bool
+ default y
+
config SCHED_NO_NO_OMIT_FRAME_POINTER
bool
default y
@@ -974,10 +923,13 @@ config MIPS_TX3927
bool
select HAS_TXX9_SERIAL
-config PCI_MARVELL
+config MIPS_RM9122
bool
+ select SERIAL_RM9000
+ select GPI_RM9000
+ select WDT_RM9000
-config ITE_BOARD_GEN
+config PCI_MARVELL
bool
config SOC_AU1000
@@ -1024,6 +976,15 @@ config EMMA2RH
depends on MARKEINS
default y
+config SERIAL_RM9000
+ bool
+
+config GPI_RM9000
+ bool
+
+config WDT_RM9000
+ bool
+
#
# Unfortunately not all GT64120 systems run the chip at the same clock.
# As the user for the clock rate and try to minimize the available options.
@@ -1049,25 +1010,6 @@ endchoice
config ARC32
bool
-config AU1X00_USB_DEVICE
- bool
- depends on MIPS_PB1500 || MIPS_PB1100 || MIPS_PB1000
- default n
-
-config MIPS_GT96100
- bool
- select MIPS_GT64120
-
-config IT8172_CIR
- bool
- depends on MIPS_ITE8172 || MIPS_IVR
- default y
-
-config IT8712
- bool
- depends on MIPS_ITE8172
- default y
-
config BOOT_ELF32
bool
@@ -1518,29 +1460,31 @@ config MIPS_MT_DISABLED
the option of an MT-enabled processor this option will be the only
option in this menu.
-config MIPS_MT_SMTC
- bool "SMTC: Use all TCs on all VPEs for SMP"
- depends on CPU_MIPS32_R2
- #depends on CPU_MIPS64_R2 # once there is hardware ...
+config MIPS_MT_SMP
+ bool "Use 1 TC on each available VPE for SMP"
depends on SYS_SUPPORTS_MULTITHREADING
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_SRS
select MIPS_MT
select SMP
+ select SYS_SUPPORTS_SMP
help
- This is a kernel model which is known a SMTC or lately has been
- marketesed into SMVP.
+ This is a kernel model which is also known a VSMP or lately
+ has been marketesed into SMVP.
-config MIPS_MT_SMP
- bool "Use 1 TC on each available VPE for SMP"
+config MIPS_MT_SMTC
+ bool "SMTC: Use all TCs on all VPEs for SMP"
+ depends on CPU_MIPS32_R2
+ #depends on CPU_MIPS64_R2 # once there is hardware ...
depends on SYS_SUPPORTS_MULTITHREADING
select CPU_MIPSR2_IRQ_VI
select CPU_MIPSR2_SRS
select MIPS_MT
select SMP
+ select SYS_SUPPORTS_SMP
help
- This is a kernel model which is also known a VSMP or lately
- has been marketesed into SMVP.
+ This is a kernel model which is known a SMTC or lately has been
+ marketesed into SMVP.
config MIPS_VPE_LOADER
bool "VPE loader support."
@@ -1649,9 +1593,7 @@ config GENERIC_IRQ_PROBE
default y
config IRQ_PER_CPU
- depends on SMP
bool
- default y
#
# - Highmem only makes sense for the 32-bit kernel.
@@ -1719,6 +1661,7 @@ source "mm/Kconfig"
config SMP
bool "Multi-Processing support"
depends on SYS_SUPPORTS_SMP
+ select IRQ_PER_CPU
help
This enables support for systems with more than one CPU. If you have
a system with only one CPU, like most personal computers, say N. If
@@ -1849,6 +1792,14 @@ config RWSEM_GENERIC_SPINLOCK
bool
default y
+config LOCKDEP_SUPPORT
+ bool
+ default y
+
+config STACKTRACE_SUPPORT
+ bool
+ default y
+
source "init/Kconfig"
menu "Bus options (PCI, PCMCIA, EISA, ISA, TC)"
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index d333ce4ba26b..641aa30b3638 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -91,8 +91,17 @@ cflags-y += -ffreestanding
# carefully avoid to add it redundantly because gcc 3.3/3.4 complains
# when fed the toolchain default!
#
-cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB -D__MIPSEB__)
-cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL -D__MIPSEL__)
+# 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
+# are used, so we kludge that here. A bug has been filed at
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29413.
+#
+undef-all += -UMIPSEB -U_MIPSEB -U__MIPSEB -U__MIPSEB__
+undef-all += -UMIPSEL -U_MIPSEL -U__MIPSEL -U__MIPSEL__
+predef-be += -DMIPSEB -D_MIPSEB -D__MIPSEB -D__MIPSEB__
+predef-le += -DMIPSEL -D_MIPSEL -D__MIPSEL -D__MIPSEL__
+cflags-$(CONFIG_CPU_BIG_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' && echo -EB $(undef-all) $(predef-be))
+cflags-$(CONFIG_CPU_LITTLE_ENDIAN) += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le))
cflags-$(CONFIG_SB1XXX_CORELIS) += $(call cc-option,-mno-sched-prolog) \
-fno-omit-frame-pointer
@@ -280,13 +289,6 @@ cflags-$(CONFIG_MIPS_EV64120) += -Iinclude/asm-mips/mach-ev64120
load-$(CONFIG_MIPS_EV64120) += 0xffffffff80100000
#
-# Galileo EV96100 Board
-#
-core-$(CONFIG_MIPS_EV96100) += arch/mips/galileo-boards/ev96100/
-cflags-$(CONFIG_MIPS_EV96100) += -Iinclude/asm-mips/mach-ev96100
-load-$(CONFIG_MIPS_EV96100) += 0xffffffff80100000
-
-#
# Wind River PPMC Board (4KC + GT64120)
#
core-$(CONFIG_WR_PPMC) += arch/mips/gt64120/wrppmc/
@@ -294,19 +296,6 @@ cflags-$(CONFIG_WR_PPMC) += -Iinclude/asm-mips/mach-wrppmc
load-$(CONFIG_WR_PPMC) += 0xffffffff80100000
#
-# Globespan IVR eval board with QED 5231 CPU
-#
-core-$(CONFIG_ITE_BOARD_GEN) += arch/mips/ite-boards/generic/
-core-$(CONFIG_MIPS_IVR) += arch/mips/ite-boards/ivr/
-load-$(CONFIG_MIPS_IVR) += 0xffffffff80100000
-
-#
-# ITE 8172 eval board with QED 5231 CPU
-#
-core-$(CONFIG_MIPS_ITE8172) += arch/mips/ite-boards/qed-4n-s01b/
-load-$(CONFIG_MIPS_ITE8172) += 0xffffffff80100000
-
-#
# For all MIPS, Inc. eval boards
#
core-$(CONFIG_MIPS_BOARDS_GEN) += arch/mips/mips-boards/generic/
@@ -330,6 +319,7 @@ load-$(CONFIG_MIPS_MALTA) += 0xffffffff80100000
# MIPS SEAD board
#
core-$(CONFIG_MIPS_SEAD) += arch/mips/mips-boards/sead/
+cflags-$(CONFIG_MIPS_SEAD) += -Iinclude/asm-mips/mach-mips
load-$(CONFIG_MIPS_SEAD) += 0xffffffff80100000
#
diff --git a/arch/mips/au1000/common/Makefile b/arch/mips/au1000/common/Makefile
index bf682f50b859..4c35525edb4f 100644
--- a/arch/mips/au1000/common/Makefile
+++ b/arch/mips/au1000/common/Makefile
@@ -10,6 +10,5 @@ obj-y += prom.o irq.o puts.o time.o reset.o \
au1xxx_irqmap.o clocks.o platform.o power.o setup.o \
sleeper.o cputable.o dma.o dbdma.o gpio.o
-obj-$(CONFIG_AU1X00_USB_DEVICE) += usbdev.o
obj-$(CONFIG_KGDB) += dbg_io.o
obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/mips/au1000/common/dbdma.c b/arch/mips/au1000/common/dbdma.c
index c4fae8ff4671..626de44bd888 100644
--- a/arch/mips/au1000/common/dbdma.c
+++ b/arch/mips/au1000/common/dbdma.c
@@ -849,7 +849,7 @@ au1xxx_dbdma_chan_free(u32 chanid)
EXPORT_SYMBOL(au1xxx_dbdma_chan_free);
static irqreturn_t
-dbdma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+dbdma_interrupt(int irq, void *dev_id)
{
u32 intstat;
u32 chan_index;
diff --git a/arch/mips/au1000/common/dma.c b/arch/mips/au1000/common/dma.c
index fb7c47c1585d..c78260d4e837 100644
--- a/arch/mips/au1000/common/dma.c
+++ b/arch/mips/au1000/common/dma.c
@@ -160,7 +160,7 @@ void dump_au1000_dma_channel(unsigned int dmanr)
* Requests the DMA done IRQ if irqhandler != NULL.
*/
int request_au1000_dma(int dev_id, const char *dev_str,
- irqreturn_t (*irqhandler)(int, void *, struct pt_regs *),
+ irq_handler_t irqhandler,
unsigned long irqflags,
void *irq_dev_id)
{
diff --git a/arch/mips/au1000/common/irq.c b/arch/mips/au1000/common/irq.c
index 316722ee8cf5..2abe132bb07d 100644
--- a/arch/mips/au1000/common/irq.c
+++ b/arch/mips/au1000/common/irq.c
@@ -67,7 +67,7 @@
extern void set_debug_traps(void);
extern irq_cpustat_t irq_stat [NR_CPUS];
-extern void mips_timer_interrupt(struct pt_regs *regs);
+extern void mips_timer_interrupt(void);
static void setup_local_irq(unsigned int irq, int type, int int_req);
static unsigned int startup_irq(unsigned int irq);
@@ -81,10 +81,6 @@ inline void local_disable_irq(unsigned int irq_nr);
void (*board_init_irq)(void);
-#ifdef CONFIG_PM
-extern irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs);
-#endif
-
static DEFINE_SPINLOCK(irq_lock);
@@ -292,7 +288,7 @@ static struct irq_chip level_irq_type = {
};
#ifdef CONFIG_PM
-void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *))
+void startup_match20_interrupt(irq_handler_t handler)
{
struct irq_desc *desc = &irq_desc[AU1000_TOY_MATCH2_INT];
@@ -501,14 +497,15 @@ void __init arch_init_irq(void)
* intcX_reqX_irqdispatch().
*/
-void intc0_req0_irqdispatch(struct pt_regs *regs)
+static void intc0_req0_irqdispatch(void)
{
int irq = 0;
static unsigned long intc0_req0 = 0;
intc0_req0 |= au_readl(IC0_REQ0INT);
- if (!intc0_req0) return;
+ if (!intc0_req0)
+ return;
#ifdef AU1000_USB_DEV_REQ_INT
/*
* Because of the tight timing of SETUP token to reply
@@ -517,28 +514,29 @@ void intc0_req0_irqdispatch(struct pt_regs *regs)
*/
if ((intc0_req0 & (1<<AU1000_USB_DEV_REQ_INT))) {
intc0_req0 &= ~(1<<AU1000_USB_DEV_REQ_INT);
- do_IRQ(AU1000_USB_DEV_REQ_INT, regs);
+ do_IRQ(AU1000_USB_DEV_REQ_INT);
return;
}
#endif
irq = au_ffs(intc0_req0) - 1;
intc0_req0 &= ~(1<<irq);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
-void intc0_req1_irqdispatch(struct pt_regs *regs)
+static void intc0_req1_irqdispatch(void)
{
int irq = 0;
static unsigned long intc0_req1 = 0;
intc0_req1 |= au_readl(IC0_REQ1INT);
- if (!intc0_req1) return;
+ if (!intc0_req1)
+ return;
irq = au_ffs(intc0_req1) - 1;
intc0_req1 &= ~(1<<irq);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
@@ -546,35 +544,37 @@ void intc0_req1_irqdispatch(struct pt_regs *regs)
* Interrupt Controller 1:
* interrupts 32 - 63
*/
-void intc1_req0_irqdispatch(struct pt_regs *regs)
+static void intc1_req0_irqdispatch(void)
{
int irq = 0;
static unsigned long intc1_req0 = 0;
intc1_req0 |= au_readl(IC1_REQ0INT);
- if (!intc1_req0) return;
+ if (!intc1_req0)
+ return;
irq = au_ffs(intc1_req0) - 1;
intc1_req0 &= ~(1<<irq);
irq += 32;
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
-void intc1_req1_irqdispatch(struct pt_regs *regs)
+static void intc1_req1_irqdispatch(void)
{
int irq = 0;
static unsigned long intc1_req1 = 0;
intc1_req1 |= au_readl(IC1_REQ1INT);
- if (!intc1_req1) return;
+ if (!intc1_req1)
+ return;
irq = au_ffs(intc1_req1) - 1;
intc1_req1 &= ~(1<<irq);
irq += 32;
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
#ifdef CONFIG_PM
@@ -660,20 +660,20 @@ restore_au1xxx_intctl(void)
}
#endif /* CONFIG_PM */
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause() & ST0_IM;
if (pending & CAUSEF_IP7)
- mips_timer_interrupt(regs);
+ mips_timer_interrupt();
else if (pending & CAUSEF_IP2)
- intc0_req0_irqdispatch(regs);
+ intc0_req0_irqdispatch();
else if (pending & CAUSEF_IP3)
- intc0_req1_irqdispatch(regs);
+ intc0_req1_irqdispatch();
else if (pending & CAUSEF_IP4)
- intc1_req0_irqdispatch(regs);
+ intc1_req0_irqdispatch();
else if (pending & CAUSEF_IP5)
- intc1_req1_irqdispatch(regs);
+ intc1_req1_irqdispatch();
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
diff --git a/arch/mips/au1000/common/time.c b/arch/mips/au1000/common/time.c
index 7fbea1bf7b48..94f09194d63d 100644
--- a/arch/mips/au1000/common/time.c
+++ b/arch/mips/au1000/common/time.c
@@ -41,7 +41,6 @@
#include <asm/compiler.h>
#include <asm/mipsregs.h>
-#include <asm/ptrace.h>
#include <asm/time.h>
#include <asm/div64.h>
#include <asm/mach-au1x00/au1000.h>
@@ -62,7 +61,7 @@ static unsigned int timerhi = 0, timerlo = 0;
#error "unsupported HZ value! Must be in [100,1000]"
#endif
#define MATCH20_INC (328*100/HZ) /* magic number 328 is for HZ=100... */
-extern void startup_match20_interrupt(irqreturn_t (*handler)(int, void *, struct pt_regs *));
+extern void startup_match20_interrupt(irq_handler_t handler);
static unsigned long last_pc0, last_match20;
#endif
@@ -79,7 +78,8 @@ static inline void ack_r4ktimer(unsigned long newval)
* is provably more robust.
*/
unsigned long wtimer;
-void mips_timer_interrupt(struct pt_regs *regs)
+
+void mips_timer_interrupt(void)
{
int irq = 63;
unsigned long count;
@@ -96,9 +96,9 @@ void mips_timer_interrupt(struct pt_regs *regs)
timerlo = count;
kstat_this_cpu.irqs[irq]++;
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
r4k_cur += r4k_offset;
ack_r4ktimer(r4k_cur);
@@ -115,7 +115,7 @@ null:
}
#ifdef CONFIG_PM
-irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t counter0_irq(int irq, void *dev_id)
{
unsigned long pc0;
int time_elapsed;
@@ -137,9 +137,9 @@ irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
}
while (time_elapsed > 0) {
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
time_elapsed -= MATCH20_INC;
last_match20 += MATCH20_INC;
@@ -156,9 +156,9 @@ irqreturn_t counter0_irq(int irq, void *dev_id, struct pt_regs *regs)
if (jiffie_drift >= 999) {
jiffie_drift -= 999;
- do_timer(regs); /* increment jiffies by one */
+ do_timer(1); /* increment jiffies by one */
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
}
diff --git a/arch/mips/au1000/common/usbdev.c b/arch/mips/au1000/common/usbdev.c
deleted file mode 100644
index 63bcb3a95dc7..000000000000
--- a/arch/mips/au1000/common/usbdev.c
+++ /dev/null
@@ -1,1555 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Au1000 USB Device-Side (device layer)
- *
- * Copyright 2001-2002 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/smp_lock.h>
-#define DEBUG
-#include <linux/usb.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/au1000.h>
-#include <asm/au1000_dma.h>
-#include <asm/au1000_usbdev.h>
-
-#ifdef DEBUG
-#undef VDEBUG
-#ifdef VDEBUG
-#define vdbg(fmt, arg...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ## arg)
-#else
-#define vdbg(fmt, arg...) do {} while (0)
-#endif
-#else
-#define vdbg(fmt, arg...) do {} while (0)
-#endif
-
-#define ALLOC_FLAGS (in_interrupt () ? GFP_ATOMIC : GFP_KERNEL)
-
-#define EP_FIFO_DEPTH 8
-
-typedef enum {
- SETUP_STAGE = 0,
- DATA_STAGE,
- STATUS_STAGE
-} ep0_stage_t;
-
-typedef struct {
- int read_fifo;
- int write_fifo;
- int ctrl_stat;
- int read_fifo_status;
- int write_fifo_status;
-} endpoint_reg_t;
-
-typedef struct {
- usbdev_pkt_t *head;
- usbdev_pkt_t *tail;
- int count;
-} pkt_list_t;
-
-typedef struct {
- int active;
- struct usb_endpoint_descriptor *desc;
- endpoint_reg_t *reg;
- /* Only one of these are used, unless this is the control ep */
- pkt_list_t inlist;
- pkt_list_t outlist;
- unsigned int indma, outdma; /* DMA channel numbers for IN, OUT */
- /* following are extracted from endpoint descriptor for easy access */
- int max_pkt_size;
- int type;
- int direction;
- /* WE assign endpoint addresses! */
- int address;
- spinlock_t lock;
-} endpoint_t;
-
-
-static struct usb_dev {
- endpoint_t ep[6];
- ep0_stage_t ep0_stage;
-
- struct usb_device_descriptor * dev_desc;
- struct usb_interface_descriptor* if_desc;
- struct usb_config_descriptor * conf_desc;
- u8 * full_conf_desc;
- struct usb_string_descriptor * str_desc[6];
-
- /* callback to function layer */
- void (*func_cb)(usbdev_cb_type_t type, unsigned long arg,
- void *cb_data);
- void* cb_data;
-
- usbdev_state_t state; // device state
- int suspended; // suspended flag
- int address; // device address
- int interface;
- int num_ep;
- u8 alternate_setting;
- u8 configuration; // configuration value
- int remote_wakeup_en;
-} usbdev;
-
-
-static endpoint_reg_t ep_reg[] = {
- // FIFO's 0 and 1 are EP0 default control
- {USBD_EP0RD, USBD_EP0WR, USBD_EP0CS, USBD_EP0RDSTAT, USBD_EP0WRSTAT },
- {0},
- // FIFO 2 is EP2, IN
- { -1, USBD_EP2WR, USBD_EP2CS, -1, USBD_EP2WRSTAT },
- // FIFO 3 is EP3, IN
- { -1, USBD_EP3WR, USBD_EP3CS, -1, USBD_EP3WRSTAT },
- // FIFO 4 is EP4, OUT
- {USBD_EP4RD, -1, USBD_EP4CS, USBD_EP4RDSTAT, -1 },
- // FIFO 5 is EP5, OUT
- {USBD_EP5RD, -1, USBD_EP5CS, USBD_EP5RDSTAT, -1 }
-};
-
-static struct {
- unsigned int id;
- const char *str;
-} ep_dma_id[] = {
- { DMA_ID_USBDEV_EP0_TX, "USBDev EP0 IN" },
- { DMA_ID_USBDEV_EP0_RX, "USBDev EP0 OUT" },
- { DMA_ID_USBDEV_EP2_TX, "USBDev EP2 IN" },
- { DMA_ID_USBDEV_EP3_TX, "USBDev EP3 IN" },
- { DMA_ID_USBDEV_EP4_RX, "USBDev EP4 OUT" },
- { DMA_ID_USBDEV_EP5_RX, "USBDev EP5 OUT" }
-};
-
-#define DIR_OUT 0
-#define DIR_IN (1<<3)
-
-#define CONTROL_EP USB_ENDPOINT_XFER_CONTROL
-#define BULK_EP USB_ENDPOINT_XFER_BULK
-
-static inline endpoint_t *
-epaddr_to_ep(struct usb_dev* dev, int ep_addr)
-{
- if (ep_addr >= 0 && ep_addr < 2)
- return &dev->ep[0];
- if (ep_addr < 6)
- return &dev->ep[ep_addr];
- return NULL;
-}
-
-static const char* std_req_name[] = {
- "GET_STATUS",
- "CLEAR_FEATURE",
- "RESERVED",
- "SET_FEATURE",
- "RESERVED",
- "SET_ADDRESS",
- "GET_DESCRIPTOR",
- "SET_DESCRIPTOR",
- "GET_CONFIGURATION",
- "SET_CONFIGURATION",
- "GET_INTERFACE",
- "SET_INTERFACE",
- "SYNCH_FRAME"
-};
-
-static inline const char*
-get_std_req_name(int req)
-{
- return (req >= 0 && req <= 12) ? std_req_name[req] : "UNKNOWN";
-}
-
-#if 0
-static void
-dump_setup(struct usb_ctrlrequest* s)
-{
- dbg("%s: requesttype=%d", __FUNCTION__, s->requesttype);
- dbg("%s: request=%d %s", __FUNCTION__, s->request,
- get_std_req_name(s->request));
- dbg("%s: value=0x%04x", __FUNCTION__, s->wValue);
- dbg("%s: index=%d", __FUNCTION__, s->index);
- dbg("%s: length=%d", __FUNCTION__, s->length);
-}
-#endif
-
-static inline usbdev_pkt_t *
-alloc_packet(endpoint_t * ep, int data_size, void* data)
-{
- usbdev_pkt_t* pkt = kmalloc(sizeof(usbdev_pkt_t) + data_size,
- ALLOC_FLAGS);
- if (!pkt)
- return NULL;
- pkt->ep_addr = ep->address;
- pkt->size = data_size;
- pkt->status = 0;
- pkt->next = NULL;
- if (data)
- memcpy(pkt->payload, data, data_size);
-
- return pkt;
-}
-
-
-/*
- * Link a packet to the tail of the enpoint's packet list.
- * EP spinlock must be held when calling.
- */
-static void
-link_tail(endpoint_t * ep, pkt_list_t * list, usbdev_pkt_t * pkt)
-{
- if (!list->tail) {
- list->head = list->tail = pkt;
- list->count = 1;
- } else {
- list->tail->next = pkt;
- list->tail = pkt;
- list->count++;
- }
-}
-
-/*
- * Unlink and return a packet from the head of the given packet
- * list. It is the responsibility of the caller to free the packet.
- * EP spinlock must be held when calling.
- */
-static usbdev_pkt_t *
-unlink_head(pkt_list_t * list)
-{
- usbdev_pkt_t *pkt;
-
- pkt = list->head;
- if (!pkt || !list->count) {
- return NULL;
- }
-
- list->head = pkt->next;
- if (!list->head) {
- list->head = list->tail = NULL;
- list->count = 0;
- } else
- list->count--;
-
- return pkt;
-}
-
-/*
- * Create and attach a new packet to the tail of the enpoint's
- * packet list. EP spinlock must be held when calling.
- */
-static usbdev_pkt_t *
-add_packet(endpoint_t * ep, pkt_list_t * list, int size)
-{
- usbdev_pkt_t *pkt = alloc_packet(ep, size, NULL);
- if (!pkt)
- return NULL;
-
- link_tail(ep, list, pkt);
- return pkt;
-}
-
-
-/*
- * Unlink and free a packet from the head of the enpoint's
- * packet list. EP spinlock must be held when calling.
- */
-static inline void
-free_packet(pkt_list_t * list)
-{
- kfree(unlink_head(list));
-}
-
-/* EP spinlock must be held when calling. */
-static inline void
-flush_pkt_list(pkt_list_t * list)
-{
- while (list->count)
- free_packet(list);
-}
-
-/* EP spinlock must be held when calling */
-static inline void
-flush_write_fifo(endpoint_t * ep)
-{
- if (ep->reg->write_fifo_status >= 0) {
- au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
- USBDEV_FSTAT_OF,
- ep->reg->write_fifo_status);
- //udelay(100);
- //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
- // ep->reg->write_fifo_status);
- }
-}
-
-/* EP spinlock must be held when calling */
-static inline void
-flush_read_fifo(endpoint_t * ep)
-{
- if (ep->reg->read_fifo_status >= 0) {
- au_writel(USBDEV_FSTAT_FLUSH | USBDEV_FSTAT_UF |
- USBDEV_FSTAT_OF,
- ep->reg->read_fifo_status);
- //udelay(100);
- //au_writel(USBDEV_FSTAT_UF | USBDEV_FSTAT_OF,
- // ep->reg->read_fifo_status);
- }
-}
-
-
-/* EP spinlock must be held when calling. */
-static void
-endpoint_flush(endpoint_t * ep)
-{
- // First, flush all packets
- flush_pkt_list(&ep->inlist);
- flush_pkt_list(&ep->outlist);
-
- // Now flush the endpoint's h/w FIFO(s)
- flush_write_fifo(ep);
- flush_read_fifo(ep);
-}
-
-/* EP spinlock must be held when calling. */
-static void
-endpoint_stall(endpoint_t * ep)
-{
- u32 cs;
-
- warn("%s", __FUNCTION__);
-
- cs = au_readl(ep->reg->ctrl_stat) | USBDEV_CS_STALL;
- au_writel(cs, ep->reg->ctrl_stat);
-}
-
-/* EP spinlock must be held when calling. */
-static void
-endpoint_unstall(endpoint_t * ep)
-{
- u32 cs;
-
- warn("%s", __FUNCTION__);
-
- cs = au_readl(ep->reg->ctrl_stat) & ~USBDEV_CS_STALL;
- au_writel(cs, ep->reg->ctrl_stat);
-}
-
-static void
-endpoint_reset_datatoggle(endpoint_t * ep)
-{
- // FIXME: is this possible?
-}
-
-
-/* EP spinlock must be held when calling. */
-static int
-endpoint_fifo_read(endpoint_t * ep)
-{
- int read_count = 0;
- u8 *bufptr;
- usbdev_pkt_t *pkt = ep->outlist.tail;
-
- if (!pkt)
- return -EINVAL;
-
- bufptr = &pkt->payload[pkt->size];
- while (au_readl(ep->reg->read_fifo_status) & USBDEV_FSTAT_FCNT_MASK) {
- *bufptr++ = au_readl(ep->reg->read_fifo) & 0xff;
- read_count++;
- pkt->size++;
- }
-
- return read_count;
-}
-
-#if 0
-/* EP spinlock must be held when calling. */
-static int
-endpoint_fifo_write(endpoint_t * ep, int index)
-{
- int write_count = 0;
- u8 *bufptr;
- usbdev_pkt_t *pkt = ep->inlist.head;
-
- if (!pkt)
- return -EINVAL;
-
- bufptr = &pkt->payload[index];
- while ((au_readl(ep->reg->write_fifo_status) &
- USBDEV_FSTAT_FCNT_MASK) < EP_FIFO_DEPTH) {
- if (bufptr < pkt->payload + pkt->size) {
- au_writel(*bufptr++, ep->reg->write_fifo);
- write_count++;
- } else {
- break;
- }
- }
-
- return write_count;
-}
-#endif
-
-/*
- * This routine is called to restart transmission of a packet.
- * The endpoint's TSIZE must be set to the new packet's size,
- * and DMA to the write FIFO needs to be restarted.
- * EP spinlock must be held when calling.
- */
-static void
-kickstart_send_packet(endpoint_t * ep)
-{
- u32 cs;
- usbdev_pkt_t *pkt = ep->inlist.head;
-
- vdbg("%s: ep%d, pkt=%p", __FUNCTION__, ep->address, pkt);
-
- if (!pkt) {
- err("%s: head=NULL! list->count=%d", __FUNCTION__,
- ep->inlist.count);
- return;
- }
-
- dma_cache_wback_inv((unsigned long)pkt->payload, pkt->size);
-
- /*
- * make sure FIFO is empty
- */
- flush_write_fifo(ep);
-
- cs = au_readl(ep->reg->ctrl_stat) & USBDEV_CS_STALL;
- cs |= (pkt->size << USBDEV_CS_TSIZE_BIT);
- au_writel(cs, ep->reg->ctrl_stat);
-
- if (get_dma_active_buffer(ep->indma) == 1) {
- set_dma_count1(ep->indma, pkt->size);
- set_dma_addr1(ep->indma, virt_to_phys(pkt->payload));
- enable_dma_buffer1(ep->indma); // reenable
- } else {
- set_dma_count0(ep->indma, pkt->size);
- set_dma_addr0(ep->indma, virt_to_phys(pkt->payload));
- enable_dma_buffer0(ep->indma); // reenable
- }
- if (dma_halted(ep->indma))
- start_dma(ep->indma);
-}
-
-
-/*
- * This routine is called when a packet in the inlist has been
- * completed. Frees the completed packet and starts sending the
- * next. EP spinlock must be held when calling.
- */
-static usbdev_pkt_t *
-send_packet_complete(endpoint_t * ep)
-{
- usbdev_pkt_t *pkt = unlink_head(&ep->inlist);
-
- if (pkt) {
- pkt->status =
- (au_readl(ep->reg->ctrl_stat) & USBDEV_CS_NAK) ?
- PKT_STATUS_NAK : PKT_STATUS_ACK;
-
- vdbg("%s: ep%d, %s pkt=%p, list count=%d", __FUNCTION__,
- ep->address, (pkt->status & PKT_STATUS_NAK) ?
- "NAK" : "ACK", pkt, ep->inlist.count);
- }
-
- /*
- * The write fifo should already be drained if things are
- * working right, but flush it anyway just in case.
- */
- flush_write_fifo(ep);
-
- // begin transmitting next packet in the inlist
- if (ep->inlist.count) {
- kickstart_send_packet(ep);
- }
-
- return pkt;
-}
-
-/*
- * Add a new packet to the tail of the given ep's packet
- * inlist. The transmit complete interrupt frees packets from
- * the head of this list. EP spinlock must be held when calling.
- */
-static int
-send_packet(struct usb_dev* dev, usbdev_pkt_t *pkt, int async)
-{
- pkt_list_t *list;
- endpoint_t* ep;
-
- if (!pkt || !(ep = epaddr_to_ep(dev, pkt->ep_addr)))
- return -EINVAL;
-
- if (!pkt->size)
- return 0;
-
- list = &ep->inlist;
-
- if (!async && list->count) {
- halt_dma(ep->indma);
- flush_pkt_list(list);
- }
-
- link_tail(ep, list, pkt);
-
- vdbg("%s: ep%d, pkt=%p, size=%d, list count=%d", __FUNCTION__,
- ep->address, pkt, pkt->size, list->count);
-
- if (list->count == 1) {
- /*
- * if the packet count is one, it means the list was empty,
- * and no more data will go out this ep until we kick-start
- * it again.
- */
- kickstart_send_packet(ep);
- }
-
- return pkt->size;
-}
-
-/*
- * This routine is called to restart reception of a packet.
- * EP spinlock must be held when calling.
- */
-static void
-kickstart_receive_packet(endpoint_t * ep)
-{
- usbdev_pkt_t *pkt;
-
- // get and link a new packet for next reception
- if (!(pkt = add_packet(ep, &ep->outlist, ep->max_pkt_size))) {
- err("%s: could not alloc new packet", __FUNCTION__);
- return;
- }
-
- if (get_dma_active_buffer(ep->outdma) == 1) {
- clear_dma_done1(ep->outdma);
- set_dma_count1(ep->outdma, ep->max_pkt_size);
- set_dma_count0(ep->outdma, 0);
- set_dma_addr1(ep->outdma, virt_to_phys(pkt->payload));
- enable_dma_buffer1(ep->outdma); // reenable
- } else {
- clear_dma_done0(ep->outdma);
- set_dma_count0(ep->outdma, ep->max_pkt_size);
- set_dma_count1(ep->outdma, 0);
- set_dma_addr0(ep->outdma, virt_to_phys(pkt->payload));
- enable_dma_buffer0(ep->outdma); // reenable
- }
- if (dma_halted(ep->outdma))
- start_dma(ep->outdma);
-}
-
-
-/*
- * This routine is called when a packet in the outlist has been
- * completed (received) and we need to prepare for a new packet
- * to be received. Halts DMA and computes the packet size from the
- * remaining DMA counter. Then prepares a new packet for reception
- * and restarts DMA. FIXME: what if another packet comes in
- * on top of the completed packet? Counter would be wrong.
- * EP spinlock must be held when calling.
- */
-static usbdev_pkt_t *
-receive_packet_complete(endpoint_t * ep)
-{
- usbdev_pkt_t *pkt = ep->outlist.tail;
- u32 cs;
-
- halt_dma(ep->outdma);
-
- cs = au_readl(ep->reg->ctrl_stat);
-
- if (!pkt)
- return NULL;
-
- pkt->size = ep->max_pkt_size - get_dma_residue(ep->outdma);
- if (pkt->size)
- dma_cache_inv((unsigned long)pkt->payload, pkt->size);
- /*
- * need to pull out any remaining bytes in the FIFO.
- */
- endpoint_fifo_read(ep);
- /*
- * should be drained now, but flush anyway just in case.
- */
- flush_read_fifo(ep);
-
- pkt->status = (cs & USBDEV_CS_NAK) ? PKT_STATUS_NAK : PKT_STATUS_ACK;
- if (ep->address == 0 && (cs & USBDEV_CS_SU))
- pkt->status |= PKT_STATUS_SU;
-
- vdbg("%s: ep%d, %s pkt=%p, size=%d", __FUNCTION__,
- ep->address, (pkt->status & PKT_STATUS_NAK) ?
- "NAK" : "ACK", pkt, pkt->size);
-
- kickstart_receive_packet(ep);
-
- return pkt;
-}
-
-
-/*
- ****************************************************************************
- * Here starts the standard device request handlers. They are
- * all called by do_setup() via a table of function pointers.
- ****************************************************************************
- */
-
-static ep0_stage_t
-do_get_status(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- switch (setup->bRequestType) {
- case 0x80: // Device
- // FIXME: send device status
- break;
- case 0x81: // Interface
- // FIXME: send interface status
- break;
- case 0x82: // End Point
- // FIXME: send endpoint status
- break;
- default:
- // Invalid Command
- endpoint_stall(&dev->ep[0]); // Stall End Point 0
- break;
- }
-
- return STATUS_STAGE;
-}
-
-static ep0_stage_t
-do_clear_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- switch (setup->bRequestType) {
- case 0x00: // Device
- if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
- dev->remote_wakeup_en = 0;
- else
- endpoint_stall(&dev->ep[0]);
- break;
- case 0x02: // End Point
- if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
- endpoint_t *ep =
- epaddr_to_ep(dev,
- le16_to_cpu(setup->wIndex) & 0xff);
-
- endpoint_unstall(ep);
- endpoint_reset_datatoggle(ep);
- } else
- endpoint_stall(&dev->ep[0]);
- break;
- }
-
- return SETUP_STAGE;
-}
-
-static ep0_stage_t
-do_reserved(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- // Invalid request, stall End Point 0
- endpoint_stall(&dev->ep[0]);
- return SETUP_STAGE;
-}
-
-static ep0_stage_t
-do_set_feature(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- switch (setup->bRequestType) {
- case 0x00: // Device
- if ((le16_to_cpu(setup->wValue) & 0xff) == 1)
- dev->remote_wakeup_en = 1;
- else
- endpoint_stall(&dev->ep[0]);
- break;
- case 0x02: // End Point
- if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
- endpoint_t *ep =
- epaddr_to_ep(dev,
- le16_to_cpu(setup->wIndex) & 0xff);
-
- endpoint_stall(ep);
- } else
- endpoint_stall(&dev->ep[0]);
- break;
- }
-
- return SETUP_STAGE;
-}
-
-static ep0_stage_t
-do_set_address(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- int new_state = dev->state;
- int new_addr = le16_to_cpu(setup->wValue);
-
- dbg("%s: our address=%d", __FUNCTION__, new_addr);
-
- if (new_addr > 127) {
- // usb spec doesn't tell us what to do, so just go to
- // default state
- new_state = DEFAULT;
- dev->address = 0;
- } else if (dev->address != new_addr) {
- dev->address = new_addr;
- new_state = ADDRESS;
- }
-
- if (dev->state != new_state) {
- dev->state = new_state;
- /* inform function layer of usbdev state change */
- dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
- }
-
- return SETUP_STAGE;
-}
-
-static ep0_stage_t
-do_get_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- int strnum, desc_len = le16_to_cpu(setup->wLength);
-
- switch (le16_to_cpu(setup->wValue) >> 8) {
- case USB_DT_DEVICE:
- // send device descriptor!
- desc_len = desc_len > dev->dev_desc->bLength ?
- dev->dev_desc->bLength : desc_len;
- dbg("sending device desc, size=%d", desc_len);
- send_packet(dev, alloc_packet(&dev->ep[0], desc_len,
- dev->dev_desc), 0);
- break;
- case USB_DT_CONFIG:
- // If the config descr index in low-byte of
- // setup->wValue is valid, send config descr,
- // otherwise stall ep0.
- if ((le16_to_cpu(setup->wValue) & 0xff) == 0) {
- // send config descriptor!
- if (desc_len <= USB_DT_CONFIG_SIZE) {
- dbg("sending partial config desc, size=%d",
- desc_len);
- send_packet(dev,
- alloc_packet(&dev->ep[0],
- desc_len,
- dev->conf_desc),
- 0);
- } else {
- int len = le16_to_cpu(dev->conf_desc->wTotalLength);
- dbg("sending whole config desc,"
- " size=%d, our size=%d", desc_len, len);
- desc_len = desc_len > len ? len : desc_len;
- send_packet(dev,
- alloc_packet(&dev->ep[0],
- desc_len,
- dev->full_conf_desc),
- 0);
- }
- } else
- endpoint_stall(&dev->ep[0]);
- break;
- case USB_DT_STRING:
- // If the string descr index in low-byte of setup->wValue
- // is valid, send string descr, otherwise stall ep0.
- strnum = le16_to_cpu(setup->wValue) & 0xff;
- if (strnum >= 0 && strnum < 6) {
- struct usb_string_descriptor *desc =
- dev->str_desc[strnum];
- desc_len = desc_len > desc->bLength ?
- desc->bLength : desc_len;
- dbg("sending string desc %d", strnum);
- send_packet(dev,
- alloc_packet(&dev->ep[0], desc_len,
- desc), 0);
- } else
- endpoint_stall(&dev->ep[0]);
- break;
- default:
- // Invalid request
- err("invalid get desc=%d, stalled",
- le16_to_cpu(setup->wValue) >> 8);
- endpoint_stall(&dev->ep[0]); // Stall endpoint 0
- break;
- }
-
- return STATUS_STAGE;
-}
-
-static ep0_stage_t
-do_set_descriptor(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- // TODO: implement
- // there will be an OUT data stage (the descriptor to set)
- return DATA_STAGE;
-}
-
-static ep0_stage_t
-do_get_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- // send dev->configuration
- dbg("sending config");
- send_packet(dev, alloc_packet(&dev->ep[0], 1, &dev->configuration),
- 0);
- return STATUS_STAGE;
-}
-
-static ep0_stage_t
-do_set_configuration(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- // set active config to low-byte of setup->wValue
- dev->configuration = le16_to_cpu(setup->wValue) & 0xff;
- dbg("set config, config=%d", dev->configuration);
- if (!dev->configuration && dev->state > DEFAULT) {
- dev->state = ADDRESS;
- /* inform function layer of usbdev state change */
- dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
- } else if (dev->configuration == 1) {
- dev->state = CONFIGURED;
- /* inform function layer of usbdev state change */
- dev->func_cb(CB_NEW_STATE, dev->state, dev->cb_data);
- } else {
- // FIXME: "respond with request error" - how?
- }
-
- return SETUP_STAGE;
-}
-
-static ep0_stage_t
-do_get_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- // interface must be zero.
- if ((le16_to_cpu(setup->wIndex) & 0xff) || dev->state == ADDRESS) {
- // FIXME: respond with "request error". how?
- } else if (dev->state == CONFIGURED) {
- // send dev->alternate_setting
- dbg("sending alt setting");
- send_packet(dev, alloc_packet(&dev->ep[0], 1,
- &dev->alternate_setting), 0);
- }
-
- return STATUS_STAGE;
-
-}
-
-static ep0_stage_t
-do_set_interface(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- if (dev->state == ADDRESS) {
- // FIXME: respond with "request error". how?
- } else if (dev->state == CONFIGURED) {
- dev->interface = le16_to_cpu(setup->wIndex) & 0xff;
- dev->alternate_setting =
- le16_to_cpu(setup->wValue) & 0xff;
- // interface and alternate_setting must be zero
- if (dev->interface || dev->alternate_setting) {
- // FIXME: respond with "request error". how?
- }
- }
-
- return SETUP_STAGE;
-}
-
-static ep0_stage_t
-do_synch_frame(struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- // TODO
- return SETUP_STAGE;
-}
-
-typedef ep0_stage_t (*req_method_t)(struct usb_dev* dev,
- struct usb_ctrlrequest* setup);
-
-
-/* Table of the standard device request handlers */
-static const req_method_t req_method[] = {
- do_get_status,
- do_clear_feature,
- do_reserved,
- do_set_feature,
- do_reserved,
- do_set_address,
- do_get_descriptor,
- do_set_descriptor,
- do_get_configuration,
- do_set_configuration,
- do_get_interface,
- do_set_interface,
- do_synch_frame
-};
-
-
-// SETUP packet request dispatcher
-static void
-do_setup (struct usb_dev* dev, struct usb_ctrlrequest* setup)
-{
- req_method_t m;
-
- dbg("%s: req %d %s", __FUNCTION__, setup->bRequestType,
- get_std_req_name(setup->bRequestType));
-
- if ((setup->bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD ||
- (setup->bRequestType & USB_RECIP_MASK) != USB_RECIP_DEVICE) {
- err("%s: invalid requesttype 0x%02x", __FUNCTION__,
- setup->bRequestType);
- return;
- }
-
- if ((setup->bRequestType & 0x80) == USB_DIR_OUT && setup->wLength)
- dbg("%s: OUT phase! length=%d", __FUNCTION__, setup->wLength);
-
- if (setup->bRequestType < sizeof(req_method)/sizeof(req_method_t))
- m = req_method[setup->bRequestType];
- else
- m = do_reserved;
-
- dev->ep0_stage = (*m)(dev, setup);
-}
-
-/*
- * A SETUP, DATA0, or DATA1 packet has been received
- * on the default control endpoint's fifo.
- */
-static void
-process_ep0_receive (struct usb_dev* dev)
-{
- endpoint_t *ep0 = &dev->ep[0];
- usbdev_pkt_t *pkt;
-
- spin_lock(&ep0->lock);
-
- // complete packet and prepare a new packet
- pkt = receive_packet_complete(ep0);
- if (!pkt) {
- // FIXME: should put a warn/err here.
- spin_unlock(&ep0->lock);
- return;
- }
-
- // unlink immediately from endpoint.
- unlink_head(&ep0->outlist);
-
- // override current stage if h/w says it's a setup packet
- if (pkt->status & PKT_STATUS_SU)
- dev->ep0_stage = SETUP_STAGE;
-
- switch (dev->ep0_stage) {
- case SETUP_STAGE:
- vdbg("SU bit is %s in setup stage",
- (pkt->status & PKT_STATUS_SU) ? "set" : "not set");
-
- if (pkt->size == sizeof(struct usb_ctrlrequest)) {
-#ifdef VDEBUG
- if (pkt->status & PKT_STATUS_ACK)
- vdbg("received SETUP");
- else
- vdbg("received NAK SETUP");
-#endif
- do_setup(dev, (struct usb_ctrlrequest*)pkt->payload);
- } else
- err("%s: wrong size SETUP received", __FUNCTION__);
- break;
- case DATA_STAGE:
- /*
- * this setup has an OUT data stage. Of the standard
- * device requests, only set_descriptor has this stage,
- * so this packet is that descriptor. TODO: drop it for
- * now, set_descriptor not implemented.
- *
- * Need to place a byte in the write FIFO here, to prepare
- * to send a zero-length DATA ack packet to the host in the
- * STATUS stage.
- */
- au_writel(0, ep0->reg->write_fifo);
- dbg("received OUT stage DATAx on EP0, size=%d", pkt->size);
- dev->ep0_stage = SETUP_STAGE;
- break;
- case STATUS_STAGE:
- // this setup had an IN data stage, and host is ACK'ing
- // the packet we sent during that stage.
- if (pkt->size != 0)
- warn("received non-zero ACK on EP0??");
-#ifdef VDEBUG
- else
- vdbg("received ACK on EP0");
-#endif
- dev->ep0_stage = SETUP_STAGE;
- break;
- }
-
- spin_unlock(&ep0->lock);
- // we're done processing the packet, free it
- kfree(pkt);
-}
-
-
-/*
- * A DATA0/1 packet has been received on one of the OUT endpoints (4 or 5)
- */
-static void
-process_ep_receive (struct usb_dev* dev, endpoint_t *ep)
-{
- usbdev_pkt_t *pkt;
-
- spin_lock(&ep->lock);
- pkt = receive_packet_complete(ep);
- spin_unlock(&ep->lock);
-
- dev->func_cb(CB_PKT_COMPLETE, (unsigned long)pkt, dev->cb_data);
-}
-
-
-
-/* This ISR handles the receive complete and suspend events */
-static void
-req_sus_intr (int irq, void *dev_id, struct pt_regs *regs)
-{
- struct usb_dev *dev = (struct usb_dev *) dev_id;
- u32 status;
-
- status = au_readl(USBD_INTSTAT);
- au_writel(status, USBD_INTSTAT); // ack'em
-
- if (status & (1<<0))
- process_ep0_receive(dev);
- if (status & (1<<4))
- process_ep_receive(dev, &dev->ep[4]);
- if (status & (1<<5))
- process_ep_receive(dev, &dev->ep[5]);
-}
-
-
-/* This ISR handles the DMA done events on EP0 */
-static void
-dma_done_ep0_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct usb_dev *dev = (struct usb_dev *) dev_id;
- usbdev_pkt_t* pkt;
- endpoint_t *ep0 = &dev->ep[0];
- u32 cs0, buff_done;
-
- spin_lock(&ep0->lock);
- cs0 = au_readl(ep0->reg->ctrl_stat);
-
- // first check packet transmit done
- if ((buff_done = get_dma_buffer_done(ep0->indma)) != 0) {
- // transmitted a DATAx packet during DATA stage
- // on control endpoint 0
- // clear DMA done bit
- if (buff_done & DMA_D0)
- clear_dma_done0(ep0->indma);
- if (buff_done & DMA_D1)
- clear_dma_done1(ep0->indma);
-
- pkt = send_packet_complete(ep0);
- kfree(pkt);
- }
-
- /*
- * Now check packet receive done. Shouldn't get these,
- * the receive packet complete intr should happen
- * before the DMA done intr occurs.
- */
- if ((buff_done = get_dma_buffer_done(ep0->outdma)) != 0) {
- // clear DMA done bit
- if (buff_done & DMA_D0)
- clear_dma_done0(ep0->outdma);
- if (buff_done & DMA_D1)
- clear_dma_done1(ep0->outdma);
-
- //process_ep0_receive(dev);
- }
-
- spin_unlock(&ep0->lock);
-}
-
-/* This ISR handles the DMA done events on endpoints 2,3,4,5 */
-static void
-dma_done_ep_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct usb_dev *dev = (struct usb_dev *) dev_id;
- int i;
-
- for (i = 2; i < 6; i++) {
- u32 buff_done;
- usbdev_pkt_t* pkt;
- endpoint_t *ep = &dev->ep[i];
-
- if (!ep->active) continue;
-
- spin_lock(&ep->lock);
-
- if (ep->direction == USB_DIR_IN) {
- buff_done = get_dma_buffer_done(ep->indma);
- if (buff_done != 0) {
- // transmitted a DATAx pkt on the IN ep
- // clear DMA done bit
- if (buff_done & DMA_D0)
- clear_dma_done0(ep->indma);
- if (buff_done & DMA_D1)
- clear_dma_done1(ep->indma);
-
- pkt = send_packet_complete(ep);
-
- spin_unlock(&ep->lock);
- dev->func_cb(CB_PKT_COMPLETE,
- (unsigned long)pkt,
- dev->cb_data);
- spin_lock(&ep->lock);
- }
- } else {
- /*
- * Check packet receive done (OUT ep). Shouldn't get
- * these, the rx packet complete intr should happen
- * before the DMA done intr occurs.
- */
- buff_done = get_dma_buffer_done(ep->outdma);
- if (buff_done != 0) {
- // received a DATAx pkt on the OUT ep
- // clear DMA done bit
- if (buff_done & DMA_D0)
- clear_dma_done0(ep->outdma);
- if (buff_done & DMA_D1)
- clear_dma_done1(ep->outdma);
-
- //process_ep_receive(dev, ep);
- }
- }
-
- spin_unlock(&ep->lock);
- }
-}
-
-
-/***************************************************************************
- * Here begins the external interface functions
- ***************************************************************************
- */
-
-/*
- * allocate a new packet
- */
-int
-usbdev_alloc_packet(int ep_addr, int data_size, usbdev_pkt_t** pkt)
-{
- endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
- usbdev_pkt_t* lpkt = NULL;
-
- if (!ep || !ep->active || ep->address < 2)
- return -ENODEV;
- if (data_size > ep->max_pkt_size)
- return -EINVAL;
-
- lpkt = *pkt = alloc_packet(ep, data_size, NULL);
- if (!lpkt)
- return -ENOMEM;
- return 0;
-}
-
-
-/*
- * packet send
- */
-int
-usbdev_send_packet(int ep_addr, usbdev_pkt_t * pkt)
-{
- unsigned long flags;
- int count;
- endpoint_t * ep;
-
- if (!pkt || !(ep = epaddr_to_ep(&usbdev, pkt->ep_addr)) ||
- !ep->active || ep->address < 2)
- return -ENODEV;
- if (ep->direction != USB_DIR_IN)
- return -EINVAL;
-
- spin_lock_irqsave(&ep->lock, flags);
- count = send_packet(&usbdev, pkt, 1);
- spin_unlock_irqrestore(&ep->lock, flags);
-
- return count;
-}
-
-/*
- * packet receive
- */
-int
-usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt)
-{
- unsigned long flags;
- usbdev_pkt_t* lpkt = NULL;
- endpoint_t *ep = epaddr_to_ep(&usbdev, ep_addr);
-
- if (!ep || !ep->active || ep->address < 2)
- return -ENODEV;
- if (ep->direction != USB_DIR_OUT)
- return -EINVAL;
-
- spin_lock_irqsave(&ep->lock, flags);
- if (ep->outlist.count > 1)
- lpkt = unlink_head(&ep->outlist);
- spin_unlock_irqrestore(&ep->lock, flags);
-
- if (!lpkt) {
- /* no packet available */
- *pkt = NULL;
- return -ENODATA;
- }
-
- *pkt = lpkt;
-
- return lpkt->size;
-}
-
-
-/*
- * return total queued byte count on the endpoint.
- */
-int
-usbdev_get_byte_count(int ep_addr)
-{
- unsigned long flags;
- pkt_list_t *list;
- usbdev_pkt_t *scan;
- int count = 0;
- endpoint_t * ep = epaddr_to_ep(&usbdev, ep_addr);
-
- if (!ep || !ep->active || ep->address < 2)
- return -ENODEV;
-
- if (ep->direction == USB_DIR_IN) {
- list = &ep->inlist;
-
- spin_lock_irqsave(&ep->lock, flags);
- for (scan = list->head; scan; scan = scan->next)
- count += scan->size;
- spin_unlock_irqrestore(&ep->lock, flags);
- } else {
- list = &ep->outlist;
-
- spin_lock_irqsave(&ep->lock, flags);
- if (list->count > 1) {
- for (scan = list->head; scan != list->tail;
- scan = scan->next)
- count += scan->size;
- }
- spin_unlock_irqrestore(&ep->lock, flags);
- }
-
- return count;
-}
-
-
-void
-usbdev_exit(void)
-{
- endpoint_t *ep;
- int i;
-
- au_writel(0, USBD_INTEN); // disable usb dev ints
- au_writel(0, USBD_ENABLE); // disable usb dev
-
- free_irq(AU1000_USB_DEV_REQ_INT, &usbdev);
- free_irq(AU1000_USB_DEV_SUS_INT, &usbdev);
-
- // free all control endpoint resources
- ep = &usbdev.ep[0];
- free_au1000_dma(ep->indma);
- free_au1000_dma(ep->outdma);
- endpoint_flush(ep);
-
- // free ep resources
- for (i = 2; i < 6; i++) {
- ep = &usbdev.ep[i];
- if (!ep->active) continue;
-
- if (ep->direction == USB_DIR_IN) {
- free_au1000_dma(ep->indma);
- } else {
- free_au1000_dma(ep->outdma);
- }
- endpoint_flush(ep);
- }
-
- kfree(usbdev.full_conf_desc);
-}
-
-int
-usbdev_init(struct usb_device_descriptor* dev_desc,
- struct usb_config_descriptor* config_desc,
- struct usb_interface_descriptor* if_desc,
- struct usb_endpoint_descriptor* ep_desc,
- struct usb_string_descriptor* str_desc[],
- void (*cb)(usbdev_cb_type_t, unsigned long, void *),
- void* cb_data)
-{
- endpoint_t *ep0;
- int i, ret=0;
- u8* fcd;
-
- if (dev_desc->bNumConfigurations > 1 ||
- config_desc->bNumInterfaces > 1 ||
- if_desc->bNumEndpoints > 4) {
- err("Only one config, one i/f, and no more "
- "than 4 ep's allowed");
- ret = -EINVAL;
- goto out;
- }
-
- if (!cb) {
- err("Function-layer callback required");
- ret = -EINVAL;
- goto out;
- }
-
- if (dev_desc->bMaxPacketSize0 != USBDEV_EP0_MAX_PACKET_SIZE) {
- warn("EP0 Max Packet size must be %d",
- USBDEV_EP0_MAX_PACKET_SIZE);
- dev_desc->bMaxPacketSize0 = USBDEV_EP0_MAX_PACKET_SIZE;
- }
-
- memset(&usbdev, 0, sizeof(struct usb_dev));
-
- usbdev.state = DEFAULT;
- usbdev.dev_desc = dev_desc;
- usbdev.if_desc = if_desc;
- usbdev.conf_desc = config_desc;
- for (i=0; i<6; i++)
- usbdev.str_desc[i] = str_desc[i];
- usbdev.func_cb = cb;
- usbdev.cb_data = cb_data;
-
- /* Initialize default control endpoint */
- ep0 = &usbdev.ep[0];
- ep0->active = 1;
- ep0->type = CONTROL_EP;
- ep0->max_pkt_size = USBDEV_EP0_MAX_PACKET_SIZE;
- spin_lock_init(&ep0->lock);
- ep0->desc = NULL; // ep0 has no descriptor
- ep0->address = 0;
- ep0->direction = 0;
- ep0->reg = &ep_reg[0];
-
- /* Initialize the other requested endpoints */
- for (i = 0; i < if_desc->bNumEndpoints; i++) {
- struct usb_endpoint_descriptor* epd = &ep_desc[i];
- endpoint_t *ep;
-
- if ((epd->bEndpointAddress & 0x80) == USB_DIR_IN) {
- ep = &usbdev.ep[2];
- ep->address = 2;
- if (ep->active) {
- ep = &usbdev.ep[3];
- ep->address = 3;
- if (ep->active) {
- err("too many IN ep's requested");
- ret = -ENODEV;
- goto out;
- }
- }
- } else {
- ep = &usbdev.ep[4];
- ep->address = 4;
- if (ep->active) {
- ep = &usbdev.ep[5];
- ep->address = 5;
- if (ep->active) {
- err("too many OUT ep's requested");
- ret = -ENODEV;
- goto out;
- }
- }
- }
-
- ep->active = 1;
- epd->bEndpointAddress &= ~0x0f;
- epd->bEndpointAddress |= (u8)ep->address;
- ep->direction = epd->bEndpointAddress & 0x80;
- ep->type = epd->bmAttributes & 0x03;
- ep->max_pkt_size = le16_to_cpu(epd->wMaxPacketSize);
- spin_lock_init(&ep->lock);
- ep->desc = epd;
- ep->reg = &ep_reg[ep->address];
- }
-
- /*
- * initialize the full config descriptor
- */
- usbdev.full_conf_desc = fcd = kmalloc(le16_to_cpu(config_desc->wTotalLength),
- ALLOC_FLAGS);
- if (!fcd) {
- err("failed to alloc full config descriptor");
- ret = -ENOMEM;
- goto out;
- }
-
- memcpy(fcd, config_desc, USB_DT_CONFIG_SIZE);
- fcd += USB_DT_CONFIG_SIZE;
- memcpy(fcd, if_desc, USB_DT_INTERFACE_SIZE);
- fcd += USB_DT_INTERFACE_SIZE;
- for (i = 0; i < if_desc->bNumEndpoints; i++) {
- memcpy(fcd, &ep_desc[i], USB_DT_ENDPOINT_SIZE);
- fcd += USB_DT_ENDPOINT_SIZE;
- }
-
- /* Now we're ready to enable the controller */
- au_writel(0x0002, USBD_ENABLE);
- udelay(100);
- au_writel(0x0003, USBD_ENABLE);
- udelay(100);
-
- /* build and send config table based on ep descriptors */
- for (i = 0; i < 6; i++) {
- endpoint_t *ep;
- if (i == 1)
- continue; // skip dummy ep
- ep = &usbdev.ep[i];
- if (ep->active) {
- au_writel((ep->address << 4) | 0x04, USBD_CONFIG);
- au_writel(((ep->max_pkt_size & 0x380) >> 7) |
- (ep->direction >> 4) | (ep->type << 4),
- USBD_CONFIG);
- au_writel((ep->max_pkt_size & 0x7f) << 1, USBD_CONFIG);
- au_writel(0x00, USBD_CONFIG);
- au_writel(ep->address, USBD_CONFIG);
- } else {
- u8 dir = (i==2 || i==3) ? DIR_IN : DIR_OUT;
- au_writel((i << 4) | 0x04, USBD_CONFIG);
- au_writel(((16 & 0x380) >> 7) | dir |
- (BULK_EP << 4), USBD_CONFIG);
- au_writel((16 & 0x7f) << 1, USBD_CONFIG);
- au_writel(0x00, USBD_CONFIG);
- au_writel(i, USBD_CONFIG);
- }
- }
-
- /*
- * Enable Receive FIFO Complete interrupts only. Transmit
- * complete is being handled by the DMA done interrupts.
- */
- au_writel(0x31, USBD_INTEN);
-
- /*
- * Controller is now enabled, request DMA and IRQ
- * resources.
- */
-
- /* request the USB device transfer complete interrupt */
- if (request_irq(AU1000_USB_DEV_REQ_INT, req_sus_intr, IRQF_DISABLED,
- "USBdev req", &usbdev)) {
- err("Can't get device request intr");
- ret = -ENXIO;
- goto out;
- }
- /* request the USB device suspend interrupt */
- if (request_irq(AU1000_USB_DEV_SUS_INT, req_sus_intr, IRQF_DISABLED,
- "USBdev sus", &usbdev)) {
- err("Can't get device suspend intr");
- ret = -ENXIO;
- goto out;
- }
-
- /* Request EP0 DMA and IRQ */
- if ((ep0->indma = request_au1000_dma(ep_dma_id[0].id,
- ep_dma_id[0].str,
- dma_done_ep0_intr,
- IRQF_DISABLED,
- &usbdev)) < 0) {
- err("Can't get %s DMA", ep_dma_id[0].str);
- ret = -ENXIO;
- goto out;
- }
- if ((ep0->outdma = request_au1000_dma(ep_dma_id[1].id,
- ep_dma_id[1].str,
- NULL, 0, NULL)) < 0) {
- err("Can't get %s DMA", ep_dma_id[1].str);
- ret = -ENXIO;
- goto out;
- }
-
- // Flush the ep0 buffers and FIFOs
- endpoint_flush(ep0);
- // start packet reception on ep0
- kickstart_receive_packet(ep0);
-
- /* Request DMA and IRQ for the other endpoints */
- for (i = 2; i < 6; i++) {
- endpoint_t *ep = &usbdev.ep[i];
- if (!ep->active)
- continue;
-
- // Flush the endpoint buffers and FIFOs
- endpoint_flush(ep);
-
- if (ep->direction == USB_DIR_IN) {
- ep->indma =
- request_au1000_dma(ep_dma_id[ep->address].id,
- ep_dma_id[ep->address].str,
- dma_done_ep_intr,
- IRQF_DISABLED,
- &usbdev);
- if (ep->indma < 0) {
- err("Can't get %s DMA",
- ep_dma_id[ep->address].str);
- ret = -ENXIO;
- goto out;
- }
- } else {
- ep->outdma =
- request_au1000_dma(ep_dma_id[ep->address].id,
- ep_dma_id[ep->address].str,
- NULL, 0, NULL);
- if (ep->outdma < 0) {
- err("Can't get %s DMA",
- ep_dma_id[ep->address].str);
- ret = -ENXIO;
- goto out;
- }
-
- // start packet reception on OUT endpoint
- kickstart_receive_packet(ep);
- }
- }
-
- out:
- if (ret)
- usbdev_exit();
- return ret;
-}
-
-EXPORT_SYMBOL(usbdev_init);
-EXPORT_SYMBOL(usbdev_exit);
-EXPORT_SYMBOL(usbdev_alloc_packet);
-EXPORT_SYMBOL(usbdev_receive_packet);
-EXPORT_SYMBOL(usbdev_send_packet);
-EXPORT_SYMBOL(usbdev_get_byte_count);
diff --git a/arch/mips/au1000/db1x00/Makefile b/arch/mips/au1000/db1x00/Makefile
index 4c7d763f2113..51d62bd5d900 100644
--- a/arch/mips/au1000/db1x00/Makefile
+++ b/arch/mips/au1000/db1x00/Makefile
@@ -6,4 +6,3 @@
# Makefile for the Alchemy Semiconductor Db1x00 board.
lib-y := init.o board_setup.o irqmap.o
-obj-$(CONFIG_WM97XX_COMODULE) += mirage_ts.o
diff --git a/arch/mips/au1000/db1x00/board_setup.c b/arch/mips/au1000/db1x00/board_setup.c
index 7a79293f8527..8b08edb977be 100644
--- a/arch/mips/au1000/db1x00/board_setup.c
+++ b/arch/mips/au1000/db1x00/board_setup.c
@@ -58,11 +58,6 @@ void __init board_setup(void)
pin_func = 0;
/* not valid for 1550 */
-#ifdef CONFIG_AU1X00_USB_DEVICE
- // 2nd USB port is USB device
- pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
- au_writel(pin_func, SYS_PINFUNC);
-#endif
#if defined(CONFIG_IRDA) && (defined(CONFIG_SOC_AU1000) || defined(CONFIG_SOC_AU1100))
/* set IRFIRSEL instead of GPIO15 */
diff --git a/arch/mips/au1000/db1x00/mirage_ts.c b/arch/mips/au1000/db1x00/mirage_ts.c
deleted file mode 100644
index 0942dcf69518..000000000000
--- a/arch/mips/au1000/db1x00/mirage_ts.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * linux/arch/mips/au1000/db1x00/mirage_ts.c
- *
- * BRIEF MODULE DESCRIPTION
- * Glue between Mirage board-specific touchscreen pieces
- * and generic Wolfson Codec touchscreen support.
- *
- * Based on pb1100_ts.c used in Hydrogen II.
- *
- * Copyright (c) 2003 Embedded Edge, LLC
- * dan@embeddededge.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/types.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
-#include <linux/proc_fs.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/wait.h>
-
-#include <asm/segment.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/delay.h>
-#include <asm/au1000.h>
-
-/*
- * Imported interface to Wolfson Codec driver.
- */
-extern void *wm97xx_ts_get_handle(int which);
-extern int wm97xx_ts_ready(void* ts_handle);
-extern void wm97xx_ts_set_cal(void* ts_handle, int xscale, int xtrans, int yscale, int ytrans);
-extern u16 wm97xx_ts_get_ac97(void* ts_handle, u8 reg);
-extern void wm97xx_ts_set_ac97(void* ts_handle, u8 reg, u16 val);
-extern int wm97xx_ts_read_data(void* ts_handle, long* x, long* y, long* pressure);
-extern void wm97xx_ts_send_data(void* ts_handle, long x, long y, long z);
-
-int wm97xx_comodule_present = 1;
-
-
-#define TS_NAME "mirage_ts"
-
-#define err(format, arg...) printk(KERN_ERR TS_NAME ": " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO TS_NAME ": " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING TS_NAME ": " format "\n" , ## arg)
-#define DPRINTK(format, arg...) printk("%s: " format "\n", __FUNCTION__ , ## arg)
-
-
-#define PEN_DOWN_IRQ AU1000_GPIO_7
-
-static struct task_struct *ts_task = 0;
-static DECLARE_COMPLETION(ts_complete);
-static DECLARE_WAIT_QUEUE_HEAD(pendown_wait);
-
-#ifdef CONFIG_WM97XX_FIVEWIRETS
-static int release_pressure = 1;
-#else
-static int release_pressure = 50;
-#endif
-
-typedef struct {
- long x;
- long y;
-} DOWN_EVENT;
-
-#define SAMPLE_RATE 50 /* samples per second */
-#define PEN_DEBOUNCE 5 /* samples for settling - fn of SAMPLE_RATE */
-#define PEN_UP_TIMEOUT 10 /* in seconds */
-#define PEN_UP_SETTLE 5 /* samples per second */
-
-static struct {
- int xscale;
- int xtrans;
- int yscale;
- int ytrans;
-} mirage_ts_cal =
-{
-#if 0
- .xscale = 84,
- .xtrans = -157,
- .yscale = 66,
- .ytrans = -150,
-#else
- .xscale = 84,
- .xtrans = -150,
- .yscale = 66,
- .ytrans = -146,
-#endif
-};
-
-
-static void pendown_irq(int irqnr, void *devid, struct pt_regs *regs)
-{
-//DPRINTK("got one 0x%x", au_readl(SYS_PINSTATERD));
- wake_up(&pendown_wait);
-}
-
-static int ts_thread(void *id)
-{
- static int pen_was_down = 0;
- static DOWN_EVENT pen_xy;
- long x, y, z;
- void *ts; /* handle */
- struct task_struct *tsk = current;
- int timeout = HZ / SAMPLE_RATE;
-
- ts_task = tsk;
-
- daemonize();
- tsk->tty = NULL;
- tsk->policy = SCHED_FIFO;
- tsk->rt_priority = 1;
- strcpy(tsk->comm, "touchscreen");
-
- /* only want to receive SIGKILL */
- spin_lock_irq(&tsk->sigmask_lock);
- siginitsetinv(&tsk->blocked, sigmask(SIGKILL));
- recalc_sigpending(tsk);
- spin_unlock_irq(&tsk->sigmask_lock);
-
- /* get handle for codec */
- ts = wm97xx_ts_get_handle(0);
-
- /* proceed only after everybody is ready */
- wait_event_timeout(pendown_wait, wm97xx_ts_ready(ts), HZ/4);
-
- /* board-specific calibration */
- wm97xx_ts_set_cal(ts,
- mirage_ts_cal.xscale,
- mirage_ts_cal.xtrans,
- mirage_ts_cal.yscale,
- mirage_ts_cal.ytrans);
-
- /* route Wolfson pendown interrupts to our GPIO */
- au_sync();
- wm97xx_ts_set_ac97(ts, 0x4c, wm97xx_ts_get_ac97(ts, 0x4c) & ~0x0008);
- au_sync();
- wm97xx_ts_set_ac97(ts, 0x56, wm97xx_ts_get_ac97(ts, 0x56) & ~0x0008);
- au_sync();
- wm97xx_ts_set_ac97(ts, 0x52, wm97xx_ts_get_ac97(ts, 0x52) | 0x2008);
- au_sync();
-
- for (;;) {
- interruptible_sleep_on_timeout(&pendown_wait, timeout);
- disable_irq(PEN_DOWN_IRQ);
- if (signal_pending(tsk)) {
- break;
- }
-
- /* read codec */
- if (!wm97xx_ts_read_data(ts, &x, &y, &z))
- z = 0; /* treat no-data and pen-up the same */
-
- if (signal_pending(tsk)) {
- break;
- }
-
- if (z >= release_pressure) {
- y = ~y; /* top to bottom */
- if (pen_was_down > 1 /*&& pen_was_down < PEN_DEBOUNCE*/) {//THXXX
- /* bounce ? */
- x = pen_xy.x;
- y = pen_xy.y;
- --pen_was_down;
- } else if (pen_was_down <= 1) {
- pen_xy.x = x;
- pen_xy.y = y;
- if (pen_was_down)
- wm97xx_ts_send_data(ts, x, y, z);
- pen_was_down = PEN_DEBOUNCE;
- }
- //wm97xx_ts_send_data(ts, x, y, z);
- timeout = HZ / SAMPLE_RATE;
- } else {
- if (pen_was_down) {
- if (--pen_was_down)
- z = release_pressure;
- else //THXXX
- wm97xx_ts_send_data(ts, pen_xy.x, pen_xy.y, z);
- }
- /* The pendown signal takes some time to settle after
- * reading the pen pressure so wait a little
- * before enabling the pen.
- */
- if (! pen_was_down) {
-// interruptible_sleep_on_timeout(&pendown_wait, HZ / PEN_UP_SETTLE);
- timeout = HZ * PEN_UP_TIMEOUT;
- }
- }
- enable_irq(PEN_DOWN_IRQ);
- }
- enable_irq(PEN_DOWN_IRQ);
- ts_task = NULL;
- complete(&ts_complete);
- return 0;
-}
-
-static int __init ts_mirage_init(void)
-{
- int ret;
-
- /* pen down signal is connected to GPIO 7 */
-
- ret = request_irq(PEN_DOWN_IRQ, pendown_irq, 0, "ts-pendown", NULL);
- if (ret) {
- err("unable to get pendown irq%d: [%d]", PEN_DOWN_IRQ, ret);
- return ret;
- }
-
- lock_kernel();
- ret = kernel_thread(ts_thread, NULL, CLONE_FS | CLONE_FILES);
- if (ret < 0) {
- unlock_kernel();
- return ret;
- }
- unlock_kernel();
-
- info("Mirage touchscreen IRQ initialized.");
-
- return 0;
-}
-
-static void __exit ts_mirage_exit(void)
-{
- if (ts_task) {
- send_sig(SIGKILL, ts_task, 1);
- wait_for_completion(&ts_complete);
- }
-
- free_irq(PEN_DOWN_IRQ, NULL);
-}
-
-module_init(ts_mirage_init);
-module_exit(ts_mirage_exit);
-
diff --git a/arch/mips/au1000/mtx-1/board_setup.c b/arch/mips/au1000/mtx-1/board_setup.c
index e917e54fc683..13f9bf5f91a6 100644
--- a/arch/mips/au1000/mtx-1/board_setup.c
+++ b/arch/mips/au1000/mtx-1/board_setup.c
@@ -51,15 +51,11 @@ void board_reset (void)
void __init board_setup(void)
{
-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
-#ifdef CONFIG_AU1X00_USB_DEVICE
- // 2nd USB port is USB device
- au_writel(au_readl(SYS_PINFUNC) & (u32)(~0x8000), SYS_PINFUNC);
-#endif
+#ifdef CONFIG_USB_OHCI
// enable USB power switch
au_writel( au_readl(GPIO2_DIR) | 0x10, GPIO2_DIR );
au_writel( 0x100000, GPIO2_OUTPUT );
-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+#endif // defined (CONFIG_USB_OHCI)
#ifdef CONFIG_PCI
#if defined(__MIPSEB__)
diff --git a/arch/mips/au1000/pb1000/board_setup.c b/arch/mips/au1000/pb1000/board_setup.c
index 1cf18e16ab54..824cfafaff92 100644
--- a/arch/mips/au1000/pb1000/board_setup.c
+++ b/arch/mips/au1000/pb1000/board_setup.c
@@ -54,7 +54,7 @@ void __init board_setup(void)
au_writel(0, SYS_PINSTATERD);
udelay(100);
-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+#ifdef CONFIG_USB_OHCI
/* zero and disable FREQ2 */
sys_freqctrl = au_readl(SYS_FREQCTRL0);
sys_freqctrl &= ~0xFFF00000;
@@ -105,22 +105,18 @@ void __init board_setup(void)
#ifdef CONFIG_USB_OHCI
sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
#endif
-#ifdef CONFIG_AU1X00_USB_DEVICE
- sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
-#endif
au_writel(sys_clksrc, SYS_CLKSRC);
// configure pins GPIO[14:9] as GPIO
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8080);
-#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func |= 0x8000;
-#endif
+
au_writel(pin_func, SYS_PINFUNC);
au_writel(0x2800, SYS_TRIOUTCLR);
au_writel(0x0030, SYS_OUTPUTCLR);
-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+#endif // defined (CONFIG_USB_OHCI)
// make gpio 15 an input (for interrupt line)
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x100);
diff --git a/arch/mips/au1000/pb1100/board_setup.c b/arch/mips/au1000/pb1100/board_setup.c
index db27b9331ff3..2d1533f116c0 100644
--- a/arch/mips/au1000/pb1100/board_setup.c
+++ b/arch/mips/au1000/pb1100/board_setup.c
@@ -55,7 +55,7 @@ void __init board_setup(void)
au_writel(0, SYS_PININPUTEN);
udelay(100);
-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+#ifdef CONFIG_USB_OHCI
// configure pins GPIO[14:9] as GPIO
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
@@ -92,12 +92,10 @@ void __init board_setup(void)
// get USB Functionality pin state (device vs host drive pins)
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
-#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func |= 0x8000;
-#endif
au_writel(pin_func, SYS_PINFUNC);
-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+#endif // defined (CONFIG_USB_OHCI)
/* Enable sys bus clock divider when IDLE state or no bus activity. */
au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
diff --git a/arch/mips/au1000/pb1200/irqmap.c b/arch/mips/au1000/pb1200/irqmap.c
index f66779f0d4cd..91983ba407c4 100644
--- a/arch/mips/au1000/pb1200/irqmap.c
+++ b/arch/mips/au1000/pb1200/irqmap.c
@@ -65,7 +65,7 @@ int __initdata au1xxx_nr_irqs = ARRAY_SIZE(au1xxx_irq_map);
*/
static volatile int pb1200_cascade_en=0;
-irqreturn_t pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t pb1200_cascade_handler( int irq, void *dev_id)
{
unsigned short bisr = bcsr->int_status;
int extirq_nr = 0;
@@ -76,8 +76,9 @@ irqreturn_t pb1200_cascade_handler( int irq, void *dev_id, struct pt_regs *regs)
{
extirq_nr = (PB1200_INT_BEGIN-1) + au_ffs(bisr);
/* Ack and dispatch IRQ */
- do_IRQ(extirq_nr,regs);
+ do_IRQ(extirq_nr);
}
+
return IRQ_RETVAL(1);
}
diff --git a/arch/mips/au1000/pb1500/board_setup.c b/arch/mips/au1000/pb1500/board_setup.c
index 1a9a293de6ab..0ffdb4fd575b 100644
--- a/arch/mips/au1000/pb1500/board_setup.c
+++ b/arch/mips/au1000/pb1500/board_setup.c
@@ -56,7 +56,7 @@ void __init board_setup(void)
au_writel(0, SYS_PINSTATERD);
udelay(100);
-#if defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+#ifdef CONFIG_USB_OHCI
/* GPIO201 is input for PCMCIA card detect */
/* GPIO203 is input for PCMCIA interrupt request */
@@ -88,19 +88,14 @@ void __init board_setup(void)
#ifdef CONFIG_USB_OHCI
sys_clksrc |= ((4<<12) | (0<<11) | (0<<10));
#endif
-#ifdef CONFIG_AU1X00_USB_DEVICE
- sys_clksrc |= ((4<<7) | (0<<6) | (0<<5));
-#endif
au_writel(sys_clksrc, SYS_CLKSRC);
pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
-#ifndef CONFIG_AU1X00_USB_DEVICE
// 2nd USB port is USB host
pin_func |= 0x8000;
-#endif
au_writel(pin_func, SYS_PINFUNC);
-#endif // defined (CONFIG_USB_OHCI) || defined (CONFIG_AU1X00_USB_DEVICE)
+#endif // defined (CONFIG_USB_OHCI)
diff --git a/arch/mips/basler/excite/excite_dbg_io.c b/arch/mips/basler/excite/excite_dbg_io.c
index c04505afa47f..d289e3a868cf 100644
--- a/arch/mips/basler/excite/excite_dbg_io.c
+++ b/arch/mips/basler/excite/excite_dbg_io.c
@@ -112,7 +112,7 @@ int putDebugChar(int data)
}
/* KGDB interrupt handler */
-asmlinkage void excite_kgdb_inthdl(struct pt_regs *regs)
+asmlinkage void excite_kgdb_inthdl(void)
{
if (unlikely(
((titan_readl(UAIIR) & 0x7) == 4)
diff --git a/arch/mips/basler/excite/excite_device.c b/arch/mips/basler/excite/excite_device.c
index bbb4ea43da88..cc1ce77eab4a 100644
--- a/arch/mips/basler/excite/excite_device.c
+++ b/arch/mips/basler/excite/excite_device.c
@@ -68,7 +68,7 @@ enum {
static struct resource
- excite_ctr_resource = {
+ excite_ctr_resource __attribute__((unused)) = {
.name = "GPI counters",
.start = 0,
.end = 5,
@@ -77,7 +77,7 @@ static struct resource
.sibling = NULL,
.child = NULL
},
- excite_gpislice_resource = {
+ excite_gpislice_resource __attribute__((unused)) = {
.name = "GPI slices",
.start = 0,
.end = 1,
@@ -86,7 +86,7 @@ static struct resource
.sibling = NULL,
.child = NULL
},
- excite_mdio_channel_resource = {
+ excite_mdio_channel_resource __attribute__((unused)) = {
.name = "MDIO channels",
.start = 0,
.end = 1,
@@ -95,7 +95,7 @@ static struct resource
.sibling = NULL,
.child = NULL
},
- excite_fifomem_resource = {
+ excite_fifomem_resource __attribute__((unused)) = {
.name = "FIFO memory",
.start = 0,
.end = 767,
@@ -104,7 +104,7 @@ static struct resource
.sibling = NULL,
.child = NULL
},
- excite_scram_resource = {
+ excite_scram_resource __attribute__((unused)) = {
.name = "Scratch RAM",
.start = EXCITE_PHYS_SCRAM,
.end = EXCITE_PHYS_SCRAM + EXCITE_SIZE_SCRAM - 1,
@@ -113,7 +113,7 @@ static struct resource
.sibling = NULL,
.child = NULL
},
- excite_fpga_resource = {
+ excite_fpga_resource __attribute__((unused)) = {
.name = "System FPGA",
.start = EXCITE_PHYS_FPGA,
.end = EXCITE_PHYS_FPGA + EXCITE_SIZE_FPGA - 1,
@@ -122,7 +122,7 @@ static struct resource
.sibling = NULL,
.child = NULL
},
- excite_nand_resource = {
+ excite_nand_resource __attribute__((unused)) = {
.name = "NAND flash control",
.start = EXCITE_PHYS_NAND,
.end = EXCITE_PHYS_NAND + EXCITE_SIZE_NAND - 1,
@@ -131,7 +131,7 @@ static struct resource
.sibling = NULL,
.child = NULL
},
- excite_titan_resource = {
+ excite_titan_resource __attribute__((unused)) = {
.name = "TITAN registers",
.start = EXCITE_PHYS_TITAN,
.end = EXCITE_PHYS_TITAN + EXCITE_SIZE_TITAN - 1,
diff --git a/arch/mips/basler/excite/excite_flashtest.c b/arch/mips/basler/excite/excite_flashtest.c
deleted file mode 100644
index f0024a8e3294..000000000000
--- a/arch/mips/basler/excite/excite_flashtest.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
-* Copyright (C) 2005 by Basler Vision Technologies AG
-* Author: Thies Moeller <thies.moeller@baslerweb.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/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/device.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/kernel.h>
-
-#include <excite.h>
-
-#include <asm/io.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <asm/rm9k-ocd.h> // for ocd_write
-#include <linux/workqueue.h> // for queue
-
-#include "excite_nandflash.h"
-#include "nandflash.h"
-
-#define PFX "excite flashtest: "
-typedef void __iomem *io_reg_t;
-
-#define io_readb(__a__) __raw_readb((__a__))
-#define io_writeb(__v__, __a__) __raw_writeb((__v__), (__a__))
-
-
-
-static inline const struct resource *excite_nandflash_get_resource(
- struct platform_device *d, unsigned long flags, const char *basename)
-{
- const char fmt[] = "%s_%u";
- char buf[80];
-
- if (unlikely(snprintf(buf, sizeof buf, fmt, basename, d->id) >= sizeof buf))
- return NULL;
-
- return platform_get_resource_byname(d, flags, buf);
-}
-
-static inline io_reg_t
-excite_nandflash_map_regs(struct platform_device *d, const char *basename)
-{
- void *result = NULL;
- const struct resource *const r =
- excite_nandflash_get_resource(d, IORESOURCE_MEM, basename);
- if (r)
- result = ioremap_nocache(r->start, r->end + 1 - r->start);
- return result;
-}
-
-/* controller and mtd information */
-
-struct excite_nandflash_drvdata {
- struct mtd_info board_mtd;
- struct nand_chip board_chip;
- io_reg_t regs;
-};
-
-
-/* command and control functions */
-static void excite_nandflash_hwcontrol(struct mtd_info *mtd, int cmd)
-{
- struct nand_chip *this = mtd->priv;
- io_reg_t regs = container_of(mtd,struct excite_nandflash_drvdata,board_mtd)->regs;
-
- switch (cmd) {
- /* Select the command latch */
- case NAND_CTL_SETCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_CMD;
- break;
- /* Deselect the command latch */
- case NAND_CTL_CLRCLE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA;
- break;
- /* Select the address latch */
- case NAND_CTL_SETALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_ADDR;
- break;
- /* Deselect the address latch */
- case NAND_CTL_CLRALE: this->IO_ADDR_W = regs + EXCITE_NANDFLASH_DATA;
- break;
- /* Select the chip -- not used */
- case NAND_CTL_SETNCE:
- break;
- /* Deselect the chip -- not used */
- case NAND_CTL_CLRNCE:
- break;
- }
-
- this->IO_ADDR_R = this->IO_ADDR_W;
-}
-
-/* excite_nandflash_devready()
- *
- * returns 0 if the nand is busy, 1 if it is ready
- */
-static int excite_nandflash_devready(struct mtd_info *mtd)
-{
- struct excite_nandflash_drvdata *drvdata =
- container_of(mtd, struct excite_nandflash_drvdata, board_mtd);
-
- return io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS);
-}
-
-/* device management functions */
-
-/* excite_nandflash_remove
- *
- * called by device layer to remove the driver
- * the binding to the mtd and all allocated
- * resources are released
- */
-static int excite_nandflash_remove(struct device *dev)
-{
- struct excite_nandflash_drvdata *this = dev_get_drvdata(dev);
-
- pr_info(PFX "remove");
-
- dev_set_drvdata(dev, NULL);
-
- if (this == NULL) {
- pr_debug(PFX "call remove without private data!!");
- return 0;
- }
-
-
- /* free the common resources */
- if (this->regs != NULL) {
- iounmap(this->regs);
- this->regs = NULL;
- }
-
- kfree(this);
-
- return 0;
-}
-
-static int elapsed;
-
-void my_workqueue_handler(void *arg)
-{
- elapsed = 1;
-}
-
-DECLARE_WORK(sigElapsed, my_workqueue_handler, 0);
-
-
-/* excite_nandflash_probe
- *
- * called by device layer when it finds a device matching
- * one our driver can handled. This code checks to see if
- * it can allocate all necessary resources then calls the
- * nand layer to look for devices
-*/
-static int excite_nandflash_probe(struct device *dev)
-{
- struct platform_device *pdev = to_platform_device(dev);
-
- struct excite_nandflash_drvdata *drvdata; /* private driver data */
- struct nand_chip *board_chip; /* private flash chip data */
- struct mtd_info *board_mtd; /* mtd info for this board */
-
- int err = 0;
- int count = 0;
- struct timeval tv,endtv;
- unsigned int dt;
-
- pr_info(PFX "probe dev: (%p)\n", dev);
-
- pr_info(PFX "adjust LB timing\n");
- ocd_writel(0x00000330, LDP2);
-
- drvdata = kmalloc(sizeof(*drvdata), GFP_KERNEL);
- if (unlikely(!drvdata)) {
- printk(KERN_ERR PFX "no memory for drvdata\n");
- err = -ENOMEM;
- goto mem_error;
- }
-
- /* Initialize structures */
- memset(drvdata, 0, sizeof(*drvdata));
-
- /* bind private data into driver */
- dev_set_drvdata(dev, drvdata);
-
- /* allocate and map the resource */
- drvdata->regs =
- excite_nandflash_map_regs(pdev, EXCITE_NANDFLASH_RESOURCE_REGS);
-
- if (unlikely(!drvdata->regs)) {
- printk(KERN_ERR PFX "cannot reserve register region\n");
- err = -ENXIO;
- goto io_error;
- }
-
- /* initialise our chip */
- board_chip = &drvdata->board_chip;
-
- board_chip->IO_ADDR_R = drvdata->regs + EXCITE_NANDFLASH_DATA;
- board_chip->IO_ADDR_W = drvdata->regs + EXCITE_NANDFLASH_DATA;
-
- board_chip->hwcontrol = excite_nandflash_hwcontrol;
- board_chip->dev_ready = excite_nandflash_devready;
-
- board_chip->chip_delay = 25;
- #if 0
- /* TODO: speedup the initial scan */
- board_chip->options = NAND_USE_FLASH_BBT;
- #endif
- board_chip->eccmode = NAND_ECC_SOFT;
-
- /* link chip to mtd */
- board_mtd = &drvdata->board_mtd;
- board_mtd->priv = board_chip;
-
-
- pr_info(PFX "FlashTest\n");
- elapsed = 0;
-/* schedule_delayed_work(&sigElapsed, 1*HZ);
- while (!elapsed) {
- io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS);
- count++;
- }
- pr_info(PFX "reads in 1 sec --> %d\n",count);
-*/
- do_gettimeofday(&tv);
- for (count = 0 ; count < 1000000; count ++) {
- io_readb(drvdata->regs + EXCITE_NANDFLASH_STATUS);
- }
- do_gettimeofday(&endtv);
- dt = (endtv.tv_sec - tv.tv_sec) * 1000000 + endtv.tv_usec - tv.tv_usec;
- pr_info(PFX "%8d us timeval\n",dt);
- pr_info(PFX "EndFlashTest\n");
-
-/* return with error to unload everything
-*/
-io_error:
- iounmap(drvdata->regs);
-
-mem_error:
- kfree(drvdata);
-
- if (err == 0)
- err = -EINVAL;
- return err;
-}
-
-static struct device_driver excite_nandflash_driver = {
- .name = "excite_nand",
- .bus = &platform_bus_type,
- .probe = excite_nandflash_probe,
- .remove = excite_nandflash_remove,
-};
-
-static int __init excite_nandflash_init(void)
-{
- pr_info(PFX "register Driver (Rev: $Revision:$)\n");
- return driver_register(&excite_nandflash_driver);
-}
-
-static void __exit excite_nandflash_exit(void)
-{
- driver_unregister(&excite_nandflash_driver);
- pr_info(PFX "Driver unregistered");
-}
-
-module_init(excite_nandflash_init);
-module_exit(excite_nandflash_exit);
-
-MODULE_AUTHOR("Thies Moeller <thies.moeller@baslerweb.com>");
-MODULE_DESCRIPTION("Basler eXcite NAND-Flash driver");
-MODULE_LICENSE("GPL");
diff --git a/arch/mips/basler/excite/excite_iodev.c b/arch/mips/basler/excite/excite_iodev.c
index 10bbb8cfb964..6af0b21ebc32 100644
--- a/arch/mips/basler/excite/excite_iodev.c
+++ b/arch/mips/basler/excite/excite_iodev.c
@@ -38,7 +38,7 @@ static int iodev_open(struct inode *, struct file *);
static int iodev_release(struct inode *, struct file *);
static ssize_t iodev_read(struct file *, char __user *, size_t s, loff_t *);
static unsigned int iodev_poll(struct file *, struct poll_table_struct *);
-static irqreturn_t iodev_irqhdl(int, void *, struct pt_regs *);
+static irqreturn_t iodev_irqhdl(int, void *);
@@ -108,16 +108,12 @@ static int __exit iodev_remove(struct device *dev)
return misc_deregister(&miscdev);
}
-
-
static int iodev_open(struct inode *i, struct file *f)
{
return request_irq(iodev_irq, iodev_irqhdl, IRQF_DISABLED,
iodev_name, &miscdev);
}
-
-
static int iodev_release(struct inode *i, struct file *f)
{
free_irq(iodev_irq, &miscdev);
@@ -148,17 +144,13 @@ static unsigned int iodev_poll(struct file *f, struct poll_table_struct *p)
return POLLOUT | POLLWRNORM;
}
-
-
-
-static irqreturn_t iodev_irqhdl(int irq, void *ctxt, struct pt_regs *regs)
+static irqreturn_t iodev_irqhdl(int irq, void *ctxt)
{
wake_up(&wq);
+
return IRQ_HANDLED;
}
-
-
static int __init iodev_init_module(void)
{
return driver_register(&iodev_driver);
diff --git a/arch/mips/basler/excite/excite_irq.c b/arch/mips/basler/excite/excite_irq.c
index 511ad8730f54..2e2061a286c5 100644
--- a/arch/mips/basler/excite/excite_irq.c
+++ b/arch/mips/basler/excite/excite_irq.c
@@ -56,7 +56,7 @@ void __init arch_init_irq(void)
#endif
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
const u32
interrupts = read_c0_cause() >> 8,
@@ -67,7 +67,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
/* process timer interrupt */
if (pending & (1 << TIMER_IRQ)) {
- do_IRQ(TIMER_IRQ, regs);
+ do_IRQ(TIMER_IRQ);
return;
}
@@ -80,7 +80,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
#else
if (pending & (1 << USB_IRQ)) {
#endif
- do_IRQ(USB_IRQ, regs);
+ do_IRQ(USB_IRQ);
return;
}
@@ -91,9 +91,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
if ((pending & (1 << TITAN_IRQ)) && msgint) {
ocd_writel(msgint, INTP0Clear0 + (TITAN_MSGINT / 0x20 * 0x10));
#if defined(CONFIG_KGDB)
- excite_kgdb_inthdl(regs);
+ excite_kgdb_inthdl();
#endif
- do_IRQ(TITAN_IRQ, regs);
+ do_IRQ(TITAN_IRQ);
return;
}
@@ -102,7 +102,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
msgintmask = ocd_readl(INTP0Mask0 + (FPGA0_MSGINT / 0x20 * 0x10));
msgint = msgintflags & msgintmask & (0x1 << (FPGA0_MSGINT % 0x20));
if ((pending & (1 << FPGA0_IRQ)) && msgint) {
- do_IRQ(FPGA0_IRQ, regs);
+ do_IRQ(FPGA0_IRQ);
return;
}
@@ -111,7 +111,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
msgintmask = ocd_readl(INTP0Mask0 + (FPGA1_MSGINT / 0x20 * 0x10));
msgint = msgintflags & msgintmask & (0x1 << (FPGA1_MSGINT % 0x20));
if ((pending & (1 << FPGA1_IRQ)) && msgint) {
- do_IRQ(FPGA1_IRQ, regs);
+ do_IRQ(FPGA1_IRQ);
return;
}
@@ -120,10 +120,10 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
msgintmask = ocd_readl(INTP0Mask0 + (PHY_MSGINT / 0x20 * 0x10));
msgint = msgintflags & msgintmask & (0x1 << (PHY_MSGINT % 0x20));
if ((pending & (1 << PHY_IRQ)) && msgint) {
- do_IRQ(PHY_IRQ, regs);
+ do_IRQ(PHY_IRQ);
return;
}
/* Process spurious interrupts */
- spurious_interrupt(regs);
+ spurious_interrupt();
}
diff --git a/arch/mips/cobalt/irq.c b/arch/mips/cobalt/irq.c
index 0b75f4fb7195..82e569d5b02c 100644
--- a/arch/mips/cobalt/irq.c
+++ b/arch/mips/cobalt/irq.c
@@ -16,7 +16,6 @@
#include <asm/i8259.h>
#include <asm/irq_cpu.h>
#include <asm/gt64120.h>
-#include <asm/ptrace.h>
#include <asm/mach-cobalt/cobalt.h>
@@ -42,7 +41,7 @@
* 15 - IDE1
*/
-static inline void galileo_irq(struct pt_regs *regs)
+static inline void galileo_irq(void)
{
unsigned int mask, pending, devfn;
@@ -52,7 +51,7 @@ static inline void galileo_irq(struct pt_regs *regs)
if (pending & GALILEO_INTR_T0EXP) {
GALILEO_OUTL(~GALILEO_INTR_T0EXP, GT_INTRCAUSE_OFS);
- do_IRQ(COBALT_GALILEO_IRQ, regs);
+ do_IRQ(COBALT_GALILEO_IRQ);
} else if (pending & GALILEO_INTR_RETRY_CTR) {
@@ -68,44 +67,31 @@ static inline void galileo_irq(struct pt_regs *regs)
}
}
-static inline void via_pic_irq(struct pt_regs *regs)
+static inline void via_pic_irq(void)
{
int irq;
irq = i8259_irq();
if (irq >= 0)
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
- unsigned pending;
-
- pending = read_c0_status() & read_c0_cause();
-
- if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */
-
- galileo_irq(regs);
-
- else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */
-
- via_pic_irq(regs);
-
- else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */
-
- do_IRQ(COBALT_CPU_IRQ + 3, regs);
-
- else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */
-
- do_IRQ(COBALT_CPU_IRQ + 4, regs);
-
- else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */
-
- do_IRQ(COBALT_CPU_IRQ + 5, regs);
-
- else if (pending & CAUSEF_IP7) /* IRQ 23 */
-
- do_IRQ(COBALT_CPU_IRQ + 7, regs);
+ unsigned pending = read_c0_status() & read_c0_cause();
+
+ if (pending & CAUSEF_IP2) /* COBALT_GALILEO_IRQ (18) */
+ galileo_irq();
+ else if (pending & CAUSEF_IP6) /* COBALT_VIA_IRQ (22) */
+ via_pic_irq();
+ else if (pending & CAUSEF_IP3) /* COBALT_ETH0_IRQ (19) */
+ do_IRQ(COBALT_CPU_IRQ + 3);
+ else if (pending & CAUSEF_IP4) /* COBALT_ETH1_IRQ (20) */
+ do_IRQ(COBALT_CPU_IRQ + 4);
+ else if (pending & CAUSEF_IP5) /* COBALT_SERIAL_IRQ (21) */
+ do_IRQ(COBALT_CPU_IRQ + 5);
+ else if (pending & CAUSEF_IP7) /* IRQ 23 */
+ do_IRQ(COBALT_CPU_IRQ + 7);
}
static struct irqaction irq_via = {
diff --git a/arch/mips/cobalt/setup.c b/arch/mips/cobalt/setup.c
index c01a0170e590..bf9dc72b9720 100644
--- a/arch/mips/cobalt/setup.c
+++ b/arch/mips/cobalt/setup.c
@@ -23,7 +23,6 @@
#include <asm/processor.h>
#include <asm/reboot.h>
#include <asm/gt64120.h>
-#include <asm/serial.h>
#include <asm/mach-cobalt/cobalt.h>
@@ -51,8 +50,8 @@ const char *get_system_type(void)
void __init plat_timer_setup(struct irqaction *irq)
{
- /* Load timer value for 1KHz (TCLK is 50MHz) */
- GALILEO_OUTL(50*1000*1000 / 1000, GT_TC0_OFS);
+ /* Load timer value for HZ (TCLK is 50MHz) */
+ GALILEO_OUTL(50*1000*1000 / HZ, GT_TC0_OFS);
/* Enable timer */
GALILEO_OUTL(GALILEO_ENTC0 | GALILEO_SELTC0, GT_TC_CONTROL_OFS);
diff --git a/arch/mips/configs/atlas_defconfig b/arch/mips/configs/atlas_defconfig
index 54274065e9a5..35931bedc3df 100644
--- a/arch/mips/configs/atlas_defconfig
+++ b/arch/mips/configs/atlas_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -162,6 +161,8 @@ CONFIG_HZ=100
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1193,7 +1194,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1305,6 +1306,7 @@ CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/bigsur_defconfig b/arch/mips/configs/bigsur_defconfig
index 887fd959482a..ba3bf733d27d 100644
--- a/arch/mips/configs/bigsur_defconfig
+++ b/arch/mips/configs/bigsur_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:02:58 2006
+# Linux kernel version: 2.6.19-rc1
+# Wed Oct 11 01:41:41 2006
#
CONFIG_MIPS=y
@@ -25,9 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_MIPS_ATLAS is not set
@@ -84,6 +81,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_COHERENT=y
CONFIG_CPU_BIG_ENDIAN=y
@@ -133,8 +131,8 @@ CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_64KB is not set
# CONFIG_SIBYTE_DMA_PAGEOPS is not set
CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
@@ -168,6 +166,8 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
# CONFIG_PREEMPT_BKL is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -184,9 +184,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -194,7 +196,9 @@ CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -203,12 +207,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -227,6 +231,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -248,18 +253,17 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
CONFIG_PCI_DEBUG=y
CONFIG_MMU=y
#
# PCCARD (PCMCIA/CardBus) support
#
-# CONFIG_PCCARD is not set
#
# PCI Hotplug Support
#
-# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -270,7 +274,7 @@ CONFIG_BINFMT_ELF=y
CONFIG_MIPS32_COMPAT=y
CONFIG_COMPAT=y
CONFIG_MIPS32_O32=y
-# CONFIG_MIPS32_N32 is not set
+CONFIG_MIPS32_N32=y
CONFIG_BINFMT_ELF32=y
#
@@ -287,6 +291,7 @@ CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=y
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -307,10 +312,12 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -340,7 +347,6 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -367,7 +373,6 @@ CONFIG_NETWORK_SECMARK=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
# CONFIG_SYS_HYPERVISOR is not set
@@ -403,7 +408,7 @@ CONFIG_BLK_DEV_LOOP=m
CONFIG_BLK_DEV_NBD=m
# CONFIG_BLK_DEV_SX8 is not set
# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -411,6 +416,7 @@ CONFIG_BLK_DEV_NBD=m
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
#
@@ -428,10 +434,40 @@ CONFIG_BLK_DEV_IDEFLOPPY=y
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_IDEPCI is not set
+CONFIG_BLK_DEV_IDEPCI=y
+# CONFIG_IDEPCI_SHARE_IRQ is not set
+# CONFIG_BLK_DEV_OFFBOARD is not set
+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 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# 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_SWARM is not set
# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
# CONFIG_IDEDMA_AUTO is not set
# CONFIG_BLK_DEV_HD is not set
@@ -440,6 +476,12 @@ CONFIG_IDE_GENERIC=y
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -515,6 +557,7 @@ CONFIG_NET_SB1250_MAC=y
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -649,7 +692,6 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_ALGOBIT is not set
# CONFIG_I2C_ALGOPCF is not set
# CONFIG_I2C_ALGOPCA is not set
-CONFIG_I2C_ALGO_SIBYTE=y
#
# I2C Hardware Bus support
@@ -711,12 +753,12 @@ CONFIG_I2C_DEBUG_CHIP=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -728,6 +770,7 @@ CONFIG_VIDEO_V4L2=y
#
# CONFIG_FIRMWARE_EDID is not set
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -810,6 +853,7 @@ CONFIG_FS_MBCACHE=y
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -839,8 +883,10 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -850,6 +896,7 @@ CONFIG_RAMFS=y
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
@@ -880,7 +927,6 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -898,6 +944,10 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
+# Distributed Lock Manager
+#
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -905,7 +955,9 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
-CONFIG_PRINTK_TIME=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
@@ -918,12 +970,15 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_SPINLOCK is not set
CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_CROSSCOMPILE=y
@@ -944,6 +999,10 @@ CONFIG_KEYS_DEBUG_PROC_KEYS=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_NULL=y
CONFIG_CRYPTO_MD4=y
@@ -953,9 +1012,12 @@ CONFIG_CRYPTO_SHA256=y
CONFIG_CRYPTO_SHA512=y
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_BLOWFISH=y
CONFIG_CRYPTO_TWOFISH=y
+CONFIG_CRYPTO_TWOFISH_COMMON=y
CONFIG_CRYPTO_SERPENT=y
CONFIG_CRYPTO_AES=m
# CONFIG_CRYPTO_CAST5 is not set
diff --git a/arch/mips/configs/capcella_defconfig b/arch/mips/configs/capcella_defconfig
index a01344f3a4c2..e5358121d2da 100644
--- a/arch/mips/configs/capcella_defconfig
+++ b/arch/mips/configs/capcella_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -150,6 +149,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -892,6 +893,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/cobalt_defconfig b/arch/mips/configs/cobalt_defconfig
index c95682445a28..adf1e8c98c65 100644
--- a/arch/mips/configs/cobalt_defconfig
+++ b/arch/mips/configs/cobalt_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
CONFIG_MIPS_COBALT=y
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -147,6 +146,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -828,7 +829,7 @@ CONFIG_FUSE_FS=y
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -890,6 +891,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/db1000_defconfig b/arch/mips/configs/db1000_defconfig
index c2f33d3af62c..4fd29ffdfb8d 100644
--- a/arch/mips/configs/db1000_defconfig
+++ b/arch/mips/configs/db1000_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1000=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -148,6 +147,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1007,6 +1008,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/db1100_defconfig b/arch/mips/configs/db1100_defconfig
index 8c44d16ae9a2..025b960ba990 100644
--- a/arch/mips/configs/db1100_defconfig
+++ b/arch/mips/configs/db1100_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1100=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -148,6 +147,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1007,6 +1008,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/db1200_defconfig b/arch/mips/configs/db1200_defconfig
index c13768e75ac5..80c9dd98f897 100644
--- a/arch/mips/configs/db1200_defconfig
+++ b/arch/mips/configs/db1200_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1200=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -148,6 +147,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1088,6 +1089,7 @@ CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/db1500_defconfig b/arch/mips/configs/db1500_defconfig
index 8aea73fae7fb..6caa90b0e176 100644
--- a/arch/mips/configs/db1500_defconfig
+++ b/arch/mips/configs/db1500_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1500=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -150,6 +149,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1291,6 +1292,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/db1550_defconfig b/arch/mips/configs/db1550_defconfig
index 90ccb7359630..c6cae86c6ab7 100644
--- a/arch/mips/configs/db1550_defconfig
+++ b/arch/mips/configs/db1550_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_DB1550=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -149,6 +148,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1112,6 +1113,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ddb5477_defconfig b/arch/mips/configs/ddb5477_defconfig
index b598cf08f156..72f24001c99e 100644
--- a/arch/mips/configs/ddb5477_defconfig
+++ b/arch/mips/configs/ddb5477_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -147,6 +146,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -853,6 +854,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/decstation_defconfig b/arch/mips/configs/decstation_defconfig
index 597150b14077..fe1387eb83c9 100644
--- a/arch/mips/configs/decstation_defconfig
+++ b/arch/mips/configs/decstation_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:01 2006
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:57:53 2006
#
CONFIG_MIPS=y
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
CONFIG_MACH_DECSTATION=y
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -148,6 +147,8 @@ CONFIG_HZ=128
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -166,27 +167,28 @@ CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
-CONFIG_RELAY=y
+# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
# CONFIG_HOTPLUG is not set
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -204,6 +206,7 @@ CONFIG_KMOD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -230,7 +233,6 @@ CONFIG_MMU=y
#
# PCCARD (PCMCIA/CardBus) support
#
-# CONFIG_PCCARD is not set
#
# PCI Hotplug Support
@@ -257,9 +259,10 @@ CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
-# CONFIG_NET_KEY is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=m
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
@@ -268,22 +271,37 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# 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_SYN_COOKIES=y
+CONFIG_INET_AH=m
+CONFIG_INET_ESP=m
+CONFIG_INET_IPCOMP=m
+CONFIG_INET_XFRM_TUNNEL=m
+CONFIG_INET_TUNNEL=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
-# CONFIG_IPV6 is not set
-# CONFIG_INET6_XFRM_TUNNEL is not set
-# CONFIG_INET6_TUNNEL is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+CONFIG_IPV6_MIP6=y
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
+# CONFIG_IPV6_TUNNEL is not set
+CONFIG_IPV6_SUBTREES=y
+CONFIG_IPV6_MULTIPLE_TABLES=y
CONFIG_NETWORK_SECMARK=y
# CONFIG_NETFILTER is not set
@@ -303,14 +321,13 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
+CONFIG_VLAN_8021Q=m
# CONFIG_DECNET is not set
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -326,13 +343,8 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_SOFTMAC=m
-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
-CONFIG_WIRELESS_EXT=y
+# CONFIG_IEEE80211 is not set
+CONFIG_FIB_RULES=y
#
# Device Drivers
@@ -343,8 +355,6 @@ CONFIG_WIRELESS_EXT=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-# CONFIG_DEBUG_DRIVER is not set
# CONFIG_SYS_HYPERVISOR is not set
#
@@ -386,8 +396,9 @@ CONFIG_BLK_DEV_LOOP=m
#
# SCSI device support
#
-CONFIG_RAID_ATTRS=m
+# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -409,12 +420,13 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=m
# CONFIG_SCSI_FC_ATTRS is not set
CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SAS_ATTRS=m
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
@@ -422,10 +434,14 @@ CONFIG_SCSI_SAS_ATTRS=m
CONFIG_ISCSI_TCP=m
CONFIG_SCSI_DECNCR=y
# CONFIG_SCSI_DECSII is not set
-# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -455,18 +471,7 @@ CONFIG_NETDEVICES=y
#
# PHY device support
#
-CONFIG_PHYLIB=m
-
-#
-# MII PHY device drivers
-#
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
+# CONFIG_PHYLIB is not set
#
# Ethernet (10 or 100Mbit)
@@ -711,7 +716,12 @@ CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
# CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
@@ -746,11 +756,13 @@ CONFIG_FUSE_FS=m
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
+CONFIG_CONFIGFS_FS=y
#
# Miscellaneous filesystems
@@ -768,7 +780,7 @@ CONFIG_RAMFS=y
# CONFIG_QNX4FS_FS is not set
# CONFIG_SYSV_FS is not set
CONFIG_UFS_FS=y
-# CONFIG_UFS_FS_WRITE is not set
+CONFIG_UFS_FS_WRITE=y
# CONFIG_UFS_DEBUG is not set
#
@@ -776,24 +788,25 @@ CONFIG_UFS_FS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V3_ACL=y
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_ACL_SUPPORT=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
# CONFIG_9P_FS is not set
+CONFIG_GENERIC_ACL=y
#
# Partition Types
@@ -829,45 +842,31 @@ CONFIG_ULTRIX_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
-CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_DETECT_SOFTLOCKUP=y
-# CONFIG_SCHEDSTATS 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 is not set
-# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
-# CONFIG_DEBUG_KOBJECT is not set
-# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_FS is not set
-# CONFIG_DEBUG_VM is not set
-CONFIG_FORCED_INLINING=y
-# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE=""
-# CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_KGDB is not set
-# CONFIG_RUNTIME_DEBUG is not set
-# CONFIG_MIPS_UNCACHED is not set
#
# Security options
#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
@@ -877,9 +876,12 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_CAST5=m
@@ -901,7 +903,7 @@ CONFIG_CRYPTO_CRC32C=m
# Library routines
#
# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=m
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
CONFIG_LIBCRC32C=m
CONFIG_ZLIB_INFLATE=m
diff --git a/arch/mips/configs/e55_defconfig b/arch/mips/configs/e55_defconfig
index fa2996bb4b7c..6133c28beb8c 100644
--- a/arch/mips/configs/e55_defconfig
+++ b/arch/mips/configs/e55_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:02 2006
+# Linux kernel version: 2.6.18-rc2
+# Tue Jul 25 23:15:03 2006
#
CONFIG_MIPS=y
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -148,6 +147,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -227,7 +228,6 @@ CONFIG_MMU=y
#
# PCCARD (PCMCIA/CardBus) support
#
-# CONFIG_PCCARD is not set
#
# PCI Hotplug Support
@@ -254,7 +254,6 @@ CONFIG_TRAD_SIGNALS=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
# CONFIG_SYS_HYPERVISOR is not set
#
@@ -284,6 +283,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
@@ -643,6 +643,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
@@ -650,7 +651,7 @@ CONFIG_MSDOS_PARTITION=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_FS is not set
CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="console=ttyVR0,19200 mem=8M"
+CONFIG_CMDLINE="console=ttyVR0,19200 ide0=0x1f0,0x3f6,40 mem=8M"
#
# Security options
diff --git a/arch/mips/configs/emma2rh_defconfig b/arch/mips/configs/emma2rh_defconfig
index 375b2ac24a49..a484b7d396fc 100644
--- a/arch/mips/configs/emma2rh_defconfig
+++ b/arch/mips/configs/emma2rh_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -148,6 +147,8 @@ CONFIG_HZ=1000
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_PREEMPT_BKL=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1181,6 +1182,7 @@ CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ev64120_defconfig b/arch/mips/configs/ev64120_defconfig
index b0afc118bd5c..21bfcdebf8f5 100644
--- a/arch/mips/configs/ev64120_defconfig
+++ b/arch/mips/configs/ev64120_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
CONFIG_MIPS_EV64120=y
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -149,6 +148,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -843,6 +844,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/excite_defconfig b/arch/mips/configs/excite_defconfig
index 045ebd089893..1a5b06cfb4d6 100644
--- a/arch/mips/configs/excite_defconfig
+++ b/arch/mips/configs/excite_defconfig
@@ -26,7 +26,6 @@ CONFIG_BASLER_EXCITE=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -150,6 +149,8 @@ CONFIG_HZ=1000
# CONFIG_PREEMPT_VOLUNTARY is not set
CONFIG_PREEMPT=y
CONFIG_PREEMPT_BKL=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1185,6 +1186,7 @@ CONFIG_NLS_ISO8859_1=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ip22_defconfig b/arch/mips/configs/ip22_defconfig
index ef16d1fb5071..21d53e0c9ee8 100644
--- a/arch/mips/configs/ip22_defconfig
+++ b/arch/mips/configs/ip22_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -154,6 +153,8 @@ CONFIG_HZ=1000
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1013,7 +1014,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1148,6 +1149,7 @@ CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ip27_defconfig b/arch/mips/configs/ip27_defconfig
index 4bf1ee7f5f00..e3e94c7e5ee1 100644
--- a/arch/mips/configs/ip27_defconfig
+++ b/arch/mips/configs/ip27_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -163,6 +162,8 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_BKL=y
# CONFIG_MIPS_INSANE_LARGE is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -900,7 +901,7 @@ CONFIG_FUSE_FS=m
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -981,6 +982,7 @@ CONFIG_SGI_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ip32_defconfig b/arch/mips/configs/ip32_defconfig
index f83dc09c3ca9..b4ab2bea9723 100644
--- a/arch/mips/configs/ip32_defconfig
+++ b/arch/mips/configs/ip32_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -154,6 +153,8 @@ CONFIG_HZ=1000
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -923,6 +924,7 @@ CONFIG_SGI_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/jaguar-atx_defconfig b/arch/mips/configs/jaguar-atx_defconfig
index 5d9eb11aba3d..9d4d17ace123 100644
--- a/arch/mips/configs/jaguar-atx_defconfig
+++ b/arch/mips/configs/jaguar-atx_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -154,6 +153,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -731,7 +732,7 @@ CONFIG_FUSE_FS=m
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
@@ -776,6 +777,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/jazz_defconfig b/arch/mips/configs/jazz_defconfig
new file mode 100644
index 000000000000..382083ebea0a
--- /dev/null
+++ b/arch/mips/configs/jazz_defconfig
@@ -0,0 +1,1404 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.19-rc1
+# Sun Oct 8 19:03:07 2006
+#
+CONFIG_MIPS=y
+
+#
+# Machine selection
+#
+# CONFIG_MIPS_MTX1 is not set
+# CONFIG_MIPS_BOSPORUS is not set
+# CONFIG_MIPS_PB1000 is not set
+# CONFIG_MIPS_PB1100 is not set
+# CONFIG_MIPS_PB1500 is not set
+# CONFIG_MIPS_PB1550 is not set
+# CONFIG_MIPS_PB1200 is not set
+# CONFIG_MIPS_DB1000 is not set
+# CONFIG_MIPS_DB1100 is not set
+# CONFIG_MIPS_DB1500 is not set
+# CONFIG_MIPS_DB1550 is not set
+# CONFIG_MIPS_DB1200 is not set
+# CONFIG_MIPS_MIRAGE is not set
+# CONFIG_BASLER_EXCITE is not set
+# CONFIG_MIPS_COBALT is not set
+# CONFIG_MACH_DECSTATION is not set
+# CONFIG_MIPS_EV64120 is not set
+CONFIG_MACH_JAZZ=y
+# CONFIG_LASAT is not set
+# CONFIG_MIPS_ATLAS is not set
+# CONFIG_MIPS_MALTA is not set
+# CONFIG_MIPS_SEAD is not set
+# CONFIG_WR_PPMC is not set
+# CONFIG_MIPS_SIM is not set
+# CONFIG_MOMENCO_JAGUAR_ATX is not set
+# CONFIG_MOMENCO_OCELOT is not set
+# CONFIG_MOMENCO_OCELOT_3 is not set
+# CONFIG_MOMENCO_OCELOT_C is not set
+# CONFIG_MOMENCO_OCELOT_G is not set
+# CONFIG_MIPS_XXS1500 is not set
+# CONFIG_PNX8550_V2PCI is not set
+# CONFIG_PNX8550_JBS is not set
+# CONFIG_DDB5477 is not set
+# CONFIG_MACH_VR41XX is not set
+# CONFIG_PMC_YOSEMITE is not set
+# CONFIG_QEMU is not set
+# CONFIG_MARKEINS is not set
+# CONFIG_SGI_IP22 is not set
+# CONFIG_SGI_IP27 is not set
+# CONFIG_SGI_IP32 is not set
+# CONFIG_SIBYTE_BIGSUR is not set
+# CONFIG_SIBYTE_SWARM is not set
+# CONFIG_SIBYTE_SENTOSA is not set
+# CONFIG_SIBYTE_RHONE is not set
+# CONFIG_SIBYTE_CARMEL is not set
+# CONFIG_SIBYTE_PTSWARM is not set
+# CONFIG_SIBYTE_LITTLESUR is not set
+# CONFIG_SIBYTE_CRHINE is not set
+# CONFIG_SIBYTE_CRHONE is not set
+# CONFIG_SNI_RM200_PCI is not set
+# CONFIG_TOSHIBA_JMR3927 is not set
+# CONFIG_TOSHIBA_RBTX4927 is not set
+# CONFIG_TOSHIBA_RBTX4938 is not set
+# CONFIG_ACER_PICA_61 is not set
+# CONFIG_MIPS_MAGNUM_4000 is not set
+CONFIG_OLIVETTI_M700=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARC=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DMA_NEED_PCI_MAP_STATE=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_I8259=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_ARC32=y
+CONFIG_MIPS_L1_CACHE_SHIFT=5
+CONFIG_ARC_MEMORY=y
+CONFIG_ARC_PROMLIB=y
+
+#
+# CPU selection
+#
+# CONFIG_CPU_MIPS32_R1 is not set
+# CONFIG_CPU_MIPS32_R2 is not set
+# CONFIG_CPU_MIPS64_R1 is not set
+# CONFIG_CPU_MIPS64_R2 is not set
+# CONFIG_CPU_R3000 is not set
+# CONFIG_CPU_TX39XX is not set
+# CONFIG_CPU_VR41XX is not set
+# CONFIG_CPU_R4300 is not set
+CONFIG_CPU_R4X00=y
+# CONFIG_CPU_TX49XX is not set
+# CONFIG_CPU_R5000 is not set
+# CONFIG_CPU_R5432 is not set
+# CONFIG_CPU_R6000 is not set
+# CONFIG_CPU_NEVADA is not set
+# CONFIG_CPU_R8000 is not set
+# CONFIG_CPU_R10000 is not set
+# CONFIG_CPU_RM7000 is not set
+# CONFIG_CPU_RM9000 is not set
+# CONFIG_CPU_SB1 is not set
+CONFIG_SYS_HAS_CPU_R4X00=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
+
+#
+# Kernel type
+#
+CONFIG_32BIT=y
+# CONFIG_64BIT is not set
+CONFIG_PAGE_SIZE_4KB=y
+# CONFIG_PAGE_SIZE_8KB is not set
+# CONFIG_PAGE_SIZE_16KB is not set
+# CONFIG_PAGE_SIZE_64KB is not set
+CONFIG_MIPS_MT_DISABLED=y
+# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
+# CONFIG_MIPS_VPE_LOADER is not set
+# CONFIG_64BIT_PHYS_ADDR is not set
+CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_HAS_SYNC=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_HZ_48 is not set
+CONFIG_HZ_100=y
+# CONFIG_HZ_128 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_256 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_HZ_1024 is not set
+CONFIG_SYS_SUPPORTS_100HZ=y
+CONFIG_HZ=100
+# CONFIG_PREEMPT_NONE is not set
+CONFIG_PREEMPT_VOLUNTARY=y
+# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_RELAY=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+#
+CONFIG_ISA=y
+CONFIG_MMU=y
+CONFIG_I8253=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=m
+CONFIG_TRAD_SIGNALS=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=m
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=m
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=m
+CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=m
+CONFIG_IPV6_PRIVACY=y
+CONFIG_IPV6_ROUTER_PREF=y
+CONFIG_IPV6_ROUTE_INFO=y
+CONFIG_INET6_AH=m
+CONFIG_INET6_ESP=m
+CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=m
+CONFIG_INET6_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
+CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+CONFIG_NETWORK_SECMARK=y
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_TARGET_SECMARK=m
+# CONFIG_NETFILTER_XT_TARGET_CONNSECMARK is not set
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+# CONFIG_IP_NF_CT_ACCT is not set
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CONNTRACK_SECMARK=y
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+CONFIG_IP_NF_CT_PROTO_SCTP=m
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+CONFIG_IP_NF_SIP=m
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_AMANDA=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_NAT_SIP=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# DECnet: Netfilter Configuration
+#
+CONFIG_DECNET_NF_GRABULATOR=m
+
+#
+# Bridge: Netfilter Configuration
+#
+CONFIG_BRIDGE_NF_EBTABLES=m
+CONFIG_BRIDGE_EBT_BROUTE=m
+CONFIG_BRIDGE_EBT_T_FILTER=m
+CONFIG_BRIDGE_EBT_T_NAT=m
+CONFIG_BRIDGE_EBT_802_3=m
+CONFIG_BRIDGE_EBT_AMONG=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_LIMIT=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
+CONFIG_BRIDGE_EBT_STP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_ARPREPLY=m
+CONFIG_BRIDGE_EBT_DNAT=m
+CONFIG_BRIDGE_EBT_MARK_T=m
+CONFIG_BRIDGE_EBT_REDIRECT=m
+CONFIG_BRIDGE_EBT_SNAT=m
+CONFIG_BRIDGE_EBT_LOG=m
+CONFIG_BRIDGE_EBT_ULOG=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+# CONFIG_VLAN_8021Q is not set
+CONFIG_DECNET=m
+# CONFIG_DECNET_ROUTER is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=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
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+CONFIG_HAMRADIO=y
+
+#
+# Packet Radio protocols
+#
+CONFIG_AX25=m
+CONFIG_AX25_DAMA_SLAVE=y
+CONFIG_NETROM=m
+CONFIG_ROSE=m
+
+#
+# AX.25 network device drivers
+#
+CONFIG_MKISS=m
+CONFIG_6PACK=m
+CONFIG_BPQETHER=m
+# CONFIG_BAYCOM_SER_FDX is not set
+# CONFIG_BAYCOM_SER_HDX is not set
+# CONFIG_BAYCOM_PAR is not set
+# CONFIG_BAYCOM_EPP is not set
+# CONFIG_YAM is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+# CONFIG_MTD is not set
+
+#
+# Parallel port support
+#
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+# CONFIG_PARPORT_PC_FIFO is not set
+# CONFIG_PARPORT_PC_SUPERIO is not set
+# CONFIG_PARPORT_GSC is not set
+# CONFIG_PARPORT_AX88796 is not set
+CONFIG_PARPORT_1284=y
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+CONFIG_BLK_DEV_FD=m
+CONFIG_PARIDE=m
+CONFIG_PARIDE_PARPORT=m
+
+#
+# Parallel IDE high-level drivers
+#
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_BPCK6=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+# CONFIG_PARIDE_EPATC8 is not set
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+CONFIG_RAID_ATTRS=m
+CONFIG_SCSI=y
+CONFIG_SCSI_NETLINK=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+CONFIG_BLK_DEV_SR_VENDOR=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+CONFIG_SCSI_CONSTANTS=y
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+CONFIG_SCSI_ISCSI_ATTRS=m
+CONFIG_SCSI_SAS_ATTRS=m
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_ISCSI_TCP=m
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_DEBUG is not set
+CONFIG_JAZZ_ESP=y
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+CONFIG_MD_RAID10=m
+CONFIG_MD_RAID456=m
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=m
+CONFIG_MD_FAULTY=m
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+CONFIG_DM_MULTIPATH=m
+CONFIG_DM_MULTIPATH_EMC=m
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+CONFIG_VITESSE_PHY=m
+CONFIG_SMSC_PHY=m
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+CONFIG_MIPS_JAZZ_SONIC=y
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_DM9000 is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_ISA=y
+# CONFIG_E2100 is not set
+# CONFIG_EWRK3 is not set
+# CONFIG_EEXPRESS is not set
+# CONFIG_EEXPRESS_PRO is not set
+# CONFIG_HPLAN_PLUS is not set
+# CONFIG_HPLAN is not set
+# CONFIG_LP486E is not set
+# CONFIG_ETH16I is not set
+CONFIG_NE2000=m
+# CONFIG_SEEQ8005 is not set
+CONFIG_NET_PCI=y
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_LAN_SAA9730 is not set
+# CONFIG_NET_POCKET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+CONFIG_PLIP=m
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+CONFIG_INPUT_FF_MEMLESS=m
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_INPORT is not set
+# CONFIG_MOUSE_LOGIBM is not set
+# CONFIG_MOUSE_PC110PAD is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_PARKBD=m
+CONFIG_SERIO_LIBPS2=y
+CONFIG_SERIO_RAW=m
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_8250_DETECT_IRQ=y
+CONFIG_SERIAL_8250_RSA=y
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=m
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_PRINTER=m
+# CONFIG_LP_CONSOLE is not set
+CONFIG_PPDEV=m
+CONFIG_TIPAR=m
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_RTC=m
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+CONFIG_W1=m
+CONFIG_W1_CON=y
+
+#
+# 1-wire Bus Masters
+#
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+# CONFIG_W1_SLAVE_SMEM is not set
+# CONFIG_W1_SLAVE_DS2433 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=m
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_XFS_FS=m
+CONFIG_XFS_QUOTA=y
+CONFIG_XFS_SECURITY=y
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=m
+CONFIG_ROMFS_FS=m
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_QUOTACTL=y
+CONFIG_DNOTIFY=y
+CONFIG_AUTOFS_FS=m
+CONFIG_AUTOFS4_FS=m
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+CONFIG_ADFS_FS=m
+# CONFIG_ADFS_FS_RW is not set
+CONFIG_AFFS_FS=m
+# CONFIG_ECRYPT_FS is not set
+CONFIG_HFS_FS=m
+# CONFIG_HFSPLUS_FS is not set
+CONFIG_BEFS_FS=m
+# CONFIG_BEFS_DEBUG is not set
+CONFIG_BFS_FS=m
+CONFIG_EFS_FS=m
+CONFIG_CRAMFS=m
+CONFIG_VXFS_FS=m
+CONFIG_HPFS_FS=m
+CONFIG_QNX4FS_FS=m
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+CONFIG_RPCSEC_GSS_KRB5=m
+CONFIG_RPCSEC_GSS_SPKM3=m
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
+CONFIG_CODA_FS=m
+CONFIG_CODA_FS_OLD_API=y
+CONFIG_AFS_FS=m
+CONFIG_RXRPC=m
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+
+#
+# Distributed Lock Manager
+#
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_FS is not set
+CONFIG_CROSSCOMPILE=y
+CONFIG_CMDLINE=""
+
+#
+# Security options
+#
+CONFIG_KEYS=y
+CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_DES=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=m
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_DEFLATE=m
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
diff --git a/arch/mips/configs/jmr3927_defconfig b/arch/mips/configs/jmr3927_defconfig
index be45a9044d06..d03746667a96 100644
--- a/arch/mips/configs/jmr3927_defconfig
+++ b/arch/mips/configs/jmr3927_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -144,6 +143,8 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
CONFIG_RTC_DS1742=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -873,6 +874,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/lasat200_defconfig b/arch/mips/configs/lasat200_defconfig
index 64dc9f45a19c..1db8249b4c0f 100644
--- a/arch/mips/configs/lasat200_defconfig
+++ b/arch/mips/configs/lasat200_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -152,6 +151,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -905,7 +906,7 @@ CONFIG_FUSE_FS=m
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -971,6 +972,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/malta_defconfig b/arch/mips/configs/malta_defconfig
index 2690baf15a85..101e80347dce 100644
--- a/arch/mips/configs/malta_defconfig
+++ b/arch/mips/configs/malta_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:13 2006
+# Linux kernel version: 2.6.19-rc1
+# Fri Oct 6 17:34:55 2006
#
CONFIG_MIPS=y
@@ -25,9 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_MIPS_ATLAS is not set
@@ -68,6 +65,7 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_DMA_NONCOHERENT=y
@@ -135,19 +133,19 @@ CONFIG_MIPS_CPU_SCACHE=y
CONFIG_CPU_HAS_PREFETCH=y
# CONFIG_MIPS_MT_DISABLED is not set
# CONFIG_MIPS_MT_SMTC is not set
-# CONFIG_MIPS_MT_SMP is not set
-CONFIG_MIPS_VPE_LOADER=y
+CONFIG_MIPS_MT_SMP=y
+# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_MIPS_MT=y
CONFIG_SYS_SUPPORTS_MULTITHREADING=y
CONFIG_MIPS_MT_FPAFF=y
-CONFIG_MIPS_VPE_LOADER_TOM=y
-CONFIG_MIPS_VPE_APSP_API=y
-CONFIG_MIPS_APSP_KSPD=y
# CONFIG_64BIT_PHYS_ADDR is not set
CONFIG_CPU_HAS_LLSC=y
+CONFIG_CPU_MIPSR2_IRQ_VI=y
+CONFIG_CPU_MIPSR2_SRS=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_IRQ_PER_CPU=y
CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_SELECT_MEMORY_MODEL=y
@@ -159,6 +157,9 @@ CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_RESOURCES_64BIT is not set
+CONFIG_SMP=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_NR_CPUS=2
# CONFIG_HZ_48 is not set
CONFIG_HZ_100=y
# CONFIG_HZ_128 is not set
@@ -171,13 +172,16 @@ CONFIG_HZ=100
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_PREEMPT_BKL=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
#
@@ -187,15 +191,20 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+# CONFIG_CPUSETS is not set
CONFIG_RELAY=y
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
@@ -203,12 +212,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -222,10 +231,12 @@ CONFIG_MODULE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_MODULE_SRCVERSION_ALL=y
CONFIG_KMOD=y
+CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -248,6 +259,7 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
CONFIG_MMU=y
#
@@ -281,6 +293,7 @@ CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -312,10 +325,12 @@ CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
#
# IP: Virtual Server Configuration
@@ -357,11 +372,16 @@ CONFIG_IPV6_ROUTE_INFO=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
CONFIG_INET6_XFRM_TUNNEL=m
CONFIG_INET6_TUNNEL=m
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
CONFIG_NETWORK_SECMARK=y
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
@@ -376,6 +396,7 @@ CONFIG_NETFILTER_NETLINK_LOG=m
CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
@@ -386,6 +407,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
@@ -428,7 +450,6 @@ CONFIG_IP_NF_MATCH_IPRANGE=m
CONFIG_IP_NF_MATCH_TOS=m
CONFIG_IP_NF_MATCH_RECENT=m
CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
CONFIG_IP_NF_MATCH_AH=m
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_MATCH_OWNER=m
@@ -456,7 +477,6 @@ CONFIG_IP_NF_NAT_SIP=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_RAW=m
@@ -535,13 +555,12 @@ CONFIG_LLC=m
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
CONFIG_ATALK=m
-CONFIG_DEV_APPLETALK=y
+CONFIG_DEV_APPLETALK=m
CONFIG_IPDDP=m
CONFIG_IPDDP_ENCAP=y
CONFIG_IPDDP_DECAP=y
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-CONFIG_NET_DIVERT=y
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -603,6 +622,7 @@ CONFIG_IEEE80211_CRYPT_CCMP=m
CONFIG_IEEE80211_SOFTMAC=m
# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
CONFIG_WIRELESS_EXT=y
+CONFIG_FIB_RULES=y
#
# Device Drivers
@@ -651,6 +671,7 @@ 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 is not set
CONFIG_CDROM_PKTCDVD=m
CONFIG_CDROM_PKTCDVD_BUFFERS=8
@@ -661,6 +682,7 @@ CONFIG_ATA_OVER_ETH=m
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
#
@@ -698,6 +720,7 @@ CONFIG_IDEDMA_PCI_AUTO=y
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_IT821X is not set
@@ -720,6 +743,7 @@ CONFIG_IDEDMA_AUTO=y
#
CONFIG_RAID_ATTRS=m
CONFIG_SCSI=m
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -741,12 +765,13 @@ CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=m
CONFIG_SCSI_FC_ATTRS=m
CONFIG_SCSI_ISCSI_ATTRS=m
CONFIG_SCSI_SAS_ATTRS=m
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
@@ -764,21 +789,23 @@ CONFIG_AIC7XXX_DEBUG_MASK=0
CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
@@ -786,6 +813,11 @@ CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
CONFIG_MD=y
@@ -799,6 +831,7 @@ CONFIG_MD_RAID5_RESHAPE=y
CONFIG_MD_MULTIPATH=m
CONFIG_MD_FAULTY=m
CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
@@ -853,6 +886,7 @@ CONFIG_LXT_PHY=m
CONFIG_CICADA_PHY=m
CONFIG_VITESSE_PHY=m
CONFIG_SMSC_PHY=m
+# CONFIG_FIXED_PHY is not set
#
# Ethernet (10 or 100Mbit)
@@ -872,6 +906,7 @@ CONFIG_MII=y
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
CONFIG_PCNET32=y
+# CONFIG_PCNET32_NAPI is not set
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
@@ -908,6 +943,7 @@ CONFIG_PCNET32=y
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -955,6 +991,7 @@ CONFIG_PCNET32=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -1069,12 +1106,12 @@ CONFIG_RTC=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -1092,6 +1129,7 @@ CONFIG_VIDEO_V4L2=y
#
# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -1190,6 +1228,7 @@ CONFIG_XFS_QUOTA=y
CONFIG_XFS_SECURITY=y
CONFIG_XFS_POSIX_ACL=y
# CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
CONFIG_MINIX_FS=m
CONFIG_ROMFS_FS=m
@@ -1229,8 +1268,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1278,7 +1319,6 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -1335,6 +1375,11 @@ CONFIG_NLS_KOI8_U=m
CONFIG_NLS_UTF8=m
#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
# Profiling support
#
# CONFIG_PROFILING is not set
@@ -1342,11 +1387,13 @@ CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_LOG_BUF_SHIFT=15
# CONFIG_DEBUG_FS is not set
CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE=""
@@ -1361,6 +1408,10 @@ CONFIG_CMDLINE=""
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
@@ -1370,9 +1421,12 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=m
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_CAST5=m
diff --git a/arch/mips/configs/mipssim_defconfig b/arch/mips/configs/mipssim_defconfig
index c298979c18ae..a3cbd23bf217 100644
--- a/arch/mips/configs/mipssim_defconfig
+++ b/arch/mips/configs/mipssim_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -149,6 +148,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -800,6 +801,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/mpc30x_defconfig b/arch/mips/configs/mpc30x_defconfig
index 938b38ab5239..6570b47426ce 100644
--- a/arch/mips/configs/mpc30x_defconfig
+++ b/arch/mips/configs/mpc30x_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:15 2006
+# Linux kernel version: 2.6.18-rc2
+# Tue Jul 25 23:16:46 2006
#
CONFIG_MIPS=y
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -71,7 +70,6 @@ CONFIG_MACH_VR41XX=y
CONFIG_VICTOR_MPC30X=y
# CONFIG_ZAO_CAPCELLA is not set
CONFIG_PCI_VR41XX=y
-CONFIG_VRC4173=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
@@ -150,6 +148,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -168,6 +168,7 @@ CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
@@ -841,7 +842,7 @@ CONFIG_USB_PEGASUS=m
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
-# CONFIG_USB_CY7C63 is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
@@ -982,7 +983,6 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -1007,6 +1007,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
@@ -1014,7 +1015,7 @@ CONFIG_MSDOS_PARTITION=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_FS is not set
CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="mem=32M console=ttyVR0,19200"
+CONFIG_CMDLINE="mem=32M console=ttyVR0,19200 ide0=0x170,0x376,73"
#
# Security options
diff --git a/arch/mips/configs/ocelot_3_defconfig b/arch/mips/configs/ocelot_3_defconfig
index ec5758f22676..440d65f93a94 100644
--- a/arch/mips/configs/ocelot_3_defconfig
+++ b/arch/mips/configs/ocelot_3_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -154,6 +153,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1092,6 +1093,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ocelot_c_defconfig b/arch/mips/configs/ocelot_c_defconfig
index 0d33d87de1a1..c2c7ae77da3e 100644
--- a/arch/mips/configs/ocelot_c_defconfig
+++ b/arch/mips/configs/ocelot_c_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -151,6 +150,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -774,7 +775,7 @@ CONFIG_FUSE_FS=y
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -840,6 +841,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ocelot_defconfig b/arch/mips/configs/ocelot_defconfig
index 4b999102715e..67efe270e0cc 100644
--- a/arch/mips/configs/ocelot_defconfig
+++ b/arch/mips/configs/ocelot_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -155,6 +154,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -723,7 +724,7 @@ CONFIG_FUSE_FS=y
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -789,6 +790,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/ocelot_g_defconfig b/arch/mips/configs/ocelot_g_defconfig
index 827b344f6010..a10f34de5f7e 100644
--- a/arch/mips/configs/ocelot_g_defconfig
+++ b/arch/mips/configs/ocelot_g_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -154,6 +153,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -777,7 +778,7 @@ CONFIG_FUSE_FS=y
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -843,6 +844,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/pb1100_defconfig b/arch/mips/configs/pb1100_defconfig
index 9ed60fef69e0..9e672f63a0aa 100644
--- a/arch/mips/configs/pb1100_defconfig
+++ b/arch/mips/configs/pb1100_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_PB1100=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -77,7 +76,6 @@ CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SOC_AU1100=y
CONFIG_SOC_AU1X00=y
CONFIG_SWAP_IO_SPACE=y
-# CONFIG_AU1X00_USB_DEVICE is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
@@ -150,6 +148,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1001,6 +1001,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/pb1500_defconfig b/arch/mips/configs/pb1500_defconfig
index 6774254b1be6..d0c0f4af1bff 100644
--- a/arch/mips/configs/pb1500_defconfig
+++ b/arch/mips/configs/pb1500_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_PB1500=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -76,7 +75,6 @@ CONFIG_CPU_LITTLE_ENDIAN=y
CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
CONFIG_SOC_AU1500=y
CONFIG_SOC_AU1X00=y
-# CONFIG_AU1X00_USB_DEVICE is not set
CONFIG_MIPS_L1_CACHE_SHIFT=5
#
@@ -149,6 +147,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1107,6 +1107,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/pb1550_defconfig b/arch/mips/configs/pb1550_defconfig
index 1afe5bf6e765..3db7427d1b55 100644
--- a/arch/mips/configs/pb1550_defconfig
+++ b/arch/mips/configs/pb1550_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS_PB1550=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -149,6 +148,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1099,6 +1100,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/pnx8550-jbs_defconfig b/arch/mips/configs/pnx8550-jbs_defconfig
index ac616c82d348..280a8001eacf 100644
--- a/arch/mips/configs/pnx8550-jbs_defconfig
+++ b/arch/mips/configs/pnx8550-jbs_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:18 2006
+# Linux kernel version: 2.6.19-rc2
+# Sat Oct 14 23:01:16 2006
#
CONFIG_MIPS=y
@@ -25,9 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_MIPS_ATLAS is not set
@@ -42,13 +39,13 @@ CONFIG_MIPS=y
# CONFIG_MOMENCO_OCELOT_G is not set
# CONFIG_MIPS_XXS1500 is not set
# CONFIG_PNX8550_V2PCI is not set
-# CONFIG_PNX8550_JBS is not set
+CONFIG_PNX8550_JBS=y
# CONFIG_DDB5477 is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_QEMU is not set
# CONFIG_MARKEINS is not set
-CONFIG_SGI_IP22=y
+# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_BIGSUR is not set
@@ -68,25 +65,21 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_ARC=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
-CONFIG_CPU_BIG_ENDIAN=y
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
-CONFIG_IRQ_CPU=y
-CONFIG_SWAP_IO_SPACE=y
-CONFIG_ARC32=y
-CONFIG_BOOT_ELF32=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_PNX8550=y
+CONFIG_SOC_PNX8550=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_ARC_CONSOLE is not set
-CONFIG_ARC_PROMLIB=y
#
# CPU selection
#
-# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R1=y
# CONFIG_CPU_MIPS32_R2 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
@@ -94,7 +87,7 @@ CONFIG_ARC_PROMLIB=y
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
-CONFIG_CPU_R4X00=y
+# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
@@ -105,12 +98,11 @@ CONFIG_CPU_R4X00=y
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_R4X00=y
-CONFIG_SYS_HAS_CPU_R5000=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
#
# Kernel type
@@ -121,17 +113,17 @@ CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_BOARD_SCACHE=y
-CONFIG_IP22_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_VPE_LOADER is not set
# CONFIG_64BIT_PHYS_ADDR is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
@@ -145,15 +137,17 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_HZ_48 is not set
# CONFIG_HZ_100 is not set
# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_256 is not set
-CONFIG_HZ_1000=y
+# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=1000
+CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -170,16 +164,20 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -188,12 +186,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -210,6 +208,7 @@ CONFIG_KMOD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -230,8 +229,10 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
-CONFIG_HW_HAS_EISA=y
-# CONFIG_EISA is not set
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
+# CONFIG_PCI_DEBUG is not set
CONFIG_MMU=y
#
@@ -242,6 +243,7 @@ CONFIG_MMU=y
#
# PCI Hotplug Support
#
+# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -264,6 +266,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -282,16 +285,18 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
-CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -317,7 +322,6 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -370,13 +374,20 @@ CONFIG_FW_LOADER=y
#
# Block devices
#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -385,6 +396,7 @@ CONFIG_BLK_DEV_INITRD=y
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
#
@@ -403,8 +415,39 @@ CONFIG_BLK_DEV_IDESCSI=y
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_OFFBOARD=y
+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 is not set
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+CONFIG_BLK_DEV_HPT366=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_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
+CONFIG_BLK_DEV_IDEDMA=y
+# CONFIG_IDEDMA_IVB is not set
# CONFIG_IDEDMA_AUTO is not set
# CONFIG_BLK_DEV_HD is not set
@@ -413,6 +456,7 @@ CONFIG_IDE_GENERIC=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -433,22 +477,54 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
# CONFIG_SCSI_SPI_ATTRS is not set
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=m
# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
#
CONFIG_ISCSI_TCP=m
-# CONFIG_SGIWD93_SCSI is not set
-# CONFIG_SCSI_SATA is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -457,14 +533,19 @@ CONFIG_ISCSI_TCP=m
# Fusion MPT device support
#
# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_IEEE1394 is not set
#
# I2O device support
#
+# CONFIG_I2O is not set
#
# Network device support
@@ -476,6 +557,11 @@ CONFIG_NETDEVICES=y
# CONFIG_TUN is not set
#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
# PHY device support
#
# CONFIG_PHYLIB is not set
@@ -485,20 +571,73 @@ CONFIG_NETDEVICES=y
#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_DM9000 is not set
-# CONFIG_SGISEEQ is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_TUNE_TWISTER=y
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_LAN_SAA9730 is not set
#
# Ethernet (1000 Mbit)
#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
#
+# CONFIG_TR is not set
#
# Wireless LAN (non-hamradio)
@@ -509,8 +648,11 @@ CONFIG_MII=y
# Wan interfaces
#
# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
@@ -530,6 +672,7 @@ CONFIG_MII=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -555,6 +698,7 @@ CONFIG_INPUT=y
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
@@ -565,7 +709,7 @@ CONFIG_SERIO_LIBPS2=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -576,7 +720,8 @@ CONFIG_VT_HW_CONSOLE_BINDING=y
#
# Non-8250 serial port support
#
-# CONFIG_SERIAL_IP22_ZILOG is not set
+# CONFIG_SERIAL_IP3106 is not set
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -590,16 +735,17 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=y
# CONFIG_RTC is not set
-# CONFIG_SGI_DS1286 is not set
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
+# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
@@ -630,35 +776,37 @@ CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
-# CONFIG_SGI_NEWPORT_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -668,15 +816,131 @@ CONFIG_DUMMY_CONSOLE=y
#
# USB support
#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+CONFIG_USB_STORAGE_USBAT=y
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+
+#
+# USB DSL modem support
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -702,6 +966,7 @@ CONFIG_DUMMY_CONSOLE=y
#
# InfiniBand support
#
+# CONFIG_INFINIBAND is not set
#
# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -732,10 +997,12 @@ CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -768,8 +1035,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -812,7 +1081,6 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -823,7 +1091,6 @@ CONFIG_SUNRPC=y
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-CONFIG_SGI_PARTITION=y
#
# Native Language Support
@@ -877,7 +1144,9 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
@@ -891,13 +1160,17 @@ CONFIG_DEBUG_SLAB=y
# CONFIG_DEBUG_SPINLOCK is not set
CONFIG_DEBUG_MUTEXES=y
# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FORCED_INLINING=y
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
@@ -916,6 +1189,9 @@ CONFIG_CMDLINE="console=ttyS1,38400n8 kgdb=ttyS0 root=/dev/nfs ip=bootp"
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -925,6 +1201,8 @@ CONFIG_CRYPTO_MD5=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/mips/configs/pnx8550-v2pci_defconfig b/arch/mips/configs/pnx8550-v2pci_defconfig
index a8eb51bae3f3..64b9fbf44a64 100644
--- a/arch/mips/configs/pnx8550-v2pci_defconfig
+++ b/arch/mips/configs/pnx8550-v2pci_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:18 2006
+# Linux kernel version: 2.6.19-rc2
+# Sat Oct 14 23:12:15 2006
#
CONFIG_MIPS=y
@@ -25,9 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_MIPS_ATLAS is not set
@@ -41,14 +38,14 @@ CONFIG_MIPS=y
# CONFIG_MOMENCO_OCELOT_C is not set
# CONFIG_MOMENCO_OCELOT_G is not set
# CONFIG_MIPS_XXS1500 is not set
-# CONFIG_PNX8550_V2PCI is not set
+CONFIG_PNX8550_V2PCI=y
# CONFIG_PNX8550_JBS is not set
# CONFIG_DDB5477 is not set
# CONFIG_MACH_VR41XX is not set
# CONFIG_PMC_YOSEMITE is not set
# CONFIG_QEMU is not set
# CONFIG_MARKEINS is not set
-CONFIG_SGI_IP22=y
+# CONFIG_SGI_IP22 is not set
# CONFIG_SGI_IP27 is not set
# CONFIG_SGI_IP32 is not set
# CONFIG_SIBYTE_BIGSUR is not set
@@ -68,25 +65,21 @@ CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_ARC=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
-CONFIG_CPU_BIG_ENDIAN=y
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
-CONFIG_IRQ_CPU=y
-CONFIG_SWAP_IO_SPACE=y
-CONFIG_ARC32=y
-CONFIG_BOOT_ELF32=y
+# CONFIG_CPU_BIG_ENDIAN is not set
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_PNX8550=y
+CONFIG_SOC_PNX8550=y
CONFIG_MIPS_L1_CACHE_SHIFT=5
-# CONFIG_ARC_CONSOLE is not set
-CONFIG_ARC_PROMLIB=y
#
# CPU selection
#
-# CONFIG_CPU_MIPS32_R1 is not set
+CONFIG_CPU_MIPS32_R1=y
# CONFIG_CPU_MIPS32_R2 is not set
# CONFIG_CPU_MIPS64_R1 is not set
# CONFIG_CPU_MIPS64_R2 is not set
@@ -94,7 +87,7 @@ CONFIG_ARC_PROMLIB=y
# CONFIG_CPU_TX39XX is not set
# CONFIG_CPU_VR41XX is not set
# CONFIG_CPU_R4300 is not set
-CONFIG_CPU_R4X00=y
+# CONFIG_CPU_R4X00 is not set
# CONFIG_CPU_TX49XX is not set
# CONFIG_CPU_R5000 is not set
# CONFIG_CPU_R5432 is not set
@@ -105,12 +98,11 @@ CONFIG_CPU_R4X00=y
# CONFIG_CPU_RM7000 is not set
# CONFIG_CPU_RM9000 is not set
# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_R4X00=y
-CONFIG_SYS_HAS_CPU_R5000=y
+CONFIG_SYS_HAS_CPU_MIPS32_R1=y
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_MIPSR1=y
CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
#
# Kernel type
@@ -121,17 +113,17 @@ CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_8KB is not set
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_BOARD_SCACHE=y
-CONFIG_IP22_CPU_SCACHE=y
+CONFIG_CPU_HAS_PREFETCH=y
CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_VPE_LOADER is not set
# CONFIG_64BIT_PHYS_ADDR is not set
CONFIG_CPU_HAS_LLSC=y
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
@@ -145,15 +137,17 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_HZ_48 is not set
# CONFIG_HZ_100 is not set
# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
+CONFIG_HZ_250=y
# CONFIG_HZ_256 is not set
-CONFIG_HZ_1000=y
+# CONFIG_HZ_1000 is not set
# CONFIG_HZ_1024 is not set
CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=1000
+CONFIG_HZ=250
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -170,16 +164,20 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
@@ -187,12 +185,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -209,6 +207,7 @@ CONFIG_KMOD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -229,8 +228,9 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Bus options (PCI, PCMCIA, EISA, ISA, TC)
#
-CONFIG_HW_HAS_EISA=y
-# CONFIG_EISA is not set
+CONFIG_HW_HAS_PCI=y
+CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
CONFIG_MMU=y
#
@@ -241,6 +241,7 @@ CONFIG_MMU=y
#
# PCI Hotplug Support
#
+# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -263,6 +264,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
@@ -281,12 +283,14 @@ CONFIG_IP_PNP=y
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
#
# IP: Virtual Server Configuration
@@ -299,12 +303,18 @@ CONFIG_IPV6_ROUTE_INFO=y
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
# CONFIG_IPV6_TUNNEL is not set
-CONFIG_NETWORK_SECMARK=y
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
@@ -317,9 +327,9 @@ CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_SECMARK=m
CONFIG_NETFILTER_XT_MATCH_COMMENT=m
CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
CONFIG_NETFILTER_XT_MATCH_ESP=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
CONFIG_NETFILTER_XT_MATCH_LIMIT=m
@@ -328,10 +338,10 @@ CONFIG_NETFILTER_XT_MATCH_MARK=m
# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
CONFIG_NETFILTER_XT_MATCH_REALM=m
CONFIG_NETFILTER_XT_MATCH_SCTP=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
CONFIG_NETFILTER_XT_MATCH_STRING=m
CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
@@ -372,7 +382,6 @@ CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -425,13 +434,20 @@ CONFIG_FW_LOADER=y
#
# Block devices
#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -440,6 +456,7 @@ CONFIG_BLK_DEV_INITRD=y
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
CONFIG_BLK_DEV_IDE=y
#
@@ -458,9 +475,41 @@ CONFIG_IDEDISK_MULTI_MODE=y
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+# CONFIG_BLK_DEV_GENERIC is not set
+# 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
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO 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
#
@@ -468,6 +517,7 @@ CONFIG_IDE_GENERIC=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -488,22 +538,59 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=m
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=m
# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
#
CONFIG_ISCSI_TCP=m
-# CONFIG_SGIWD93_SCSI is not set
-# CONFIG_SCSI_SATA is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+CONFIG_SCSI_AIC7XXX=m
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
+CONFIG_AIC7XXX_RESET_DELAY_MS=15000
+# CONFIG_AIC7XXX_DEBUG_ENABLE is not set
+CONFIG_AIC7XXX_DEBUG_MASK=0
+# CONFIG_AIC7XXX_REG_PRETTY_PRINT is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -512,14 +599,19 @@ CONFIG_ISCSI_TCP=m
# Fusion MPT device support
#
# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
#
+# CONFIG_IEEE1394 is not set
#
# I2O device support
#
+# CONFIG_I2O is not set
#
# Network device support
@@ -531,6 +623,11 @@ CONFIG_NETDEVICES=y
CONFIG_TUN=m
#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
# PHY device support
#
# CONFIG_PHYLIB is not set
@@ -540,20 +637,73 @@ CONFIG_TUN=m
#
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_DM9000 is not set
-# CONFIG_SGISEEQ is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+CONFIG_NATSEMI=y
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+# CONFIG_8139TOO_8129 is not set
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_LAN_SAA9730 is not set
#
# Ethernet (1000 Mbit)
#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
#
+# CONFIG_TR is not set
#
# Wireless LAN (non-hamradio)
@@ -564,6 +714,8 @@ CONFIG_MII=y
# Wan interfaces
#
# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
CONFIG_PPP=m
# CONFIG_PPP_MULTILINK is not set
# CONFIG_PPP_FILTER is not set
@@ -574,6 +726,8 @@ CONFIG_PPP_DEFLATE=m
CONFIG_PPP_MPPE=m
# CONFIG_PPPOE is not set
# CONFIG_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
# CONFIG_NETPOLL is not set
@@ -593,6 +747,7 @@ CONFIG_PPP_MPPE=m
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -615,6 +770,7 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
@@ -629,6 +785,7 @@ CONFIG_MOUSE_PS2=y
CONFIG_SERIO=y
CONFIG_SERIO_I8042=y
CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
@@ -639,7 +796,7 @@ CONFIG_SERIO_LIBPS2=y
CONFIG_VT=y
# CONFIG_VT_CONSOLE is not set
CONFIG_HW_CONSOLE=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_COMPUTONE is not set
# CONFIG_ROCKETPORT is not set
@@ -649,6 +806,7 @@ CONFIG_SERIAL_NONSTANDARD=y
# CONFIG_MOXA_SMARTIO is not set
# CONFIG_ISI is not set
# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
# CONFIG_N_HDLC is not set
# CONFIG_RISCOM8 is not set
# CONFIG_SPECIALIX is not set
@@ -664,7 +822,8 @@ CONFIG_SERIAL_NONSTANDARD=y
#
# Non-8250 serial port support
#
-# CONFIG_SERIAL_IP22_ZILOG is not set
+# CONFIG_SERIAL_IP3106 is not set
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -678,16 +837,17 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
+CONFIG_HW_RANDOM=y
# CONFIG_RTC is not set
-# CONFIG_SGI_DS1286 is not set
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
+# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
@@ -708,14 +868,30 @@ CONFIG_I2C_CHARDEV=m
CONFIG_I2C_ALGOBIT=m
# CONFIG_I2C_ALGOPCF is not set
# CONFIG_I2C_ALGOPCA is not set
-# CONFIG_I2C_ALGO_SGI is not set
#
# I2C Hardware Bus support
#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_PROSAVAGE is not set
+# CONFIG_I2C_SAVAGE4 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+# CONFIG_I2C_VOODOO3 is not set
# CONFIG_I2C_PCA_ISA is not set
#
@@ -775,9 +951,13 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
# CONFIG_SENSORS_W83792D is not set
@@ -789,23 +969,25 @@ CONFIG_HWMON=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
+# CONFIG_FB_DDC is not set
# CONFIG_FB_CFB_FILLRECT is not set
# CONFIG_FB_CFB_COPYAREA is not set
# CONFIG_FB_CFB_IMAGEBLIT is not set
@@ -813,14 +995,32 @@ CONFIG_FB=y
# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_CIRRUS is not set
+# CONFIG_FB_PM2 is not set
+# CONFIG_FB_CYBER2000 is not set
+# CONFIG_FB_ASILIANT is not set
+# CONFIG_FB_IMSTT is not set
# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
+# CONFIG_FB_RIVA is not set
+# CONFIG_FB_MATROX is not set
+# CONFIG_FB_RADEON is not set
+# CONFIG_FB_ATY128 is not set
+# CONFIG_FB_ATY is not set
+# CONFIG_FB_SAVAGE is not set
+# CONFIG_FB_SIS is not set
+# CONFIG_FB_NEOMAGIC is not set
+# CONFIG_FB_KYRO is not set
+# CONFIG_FB_3DFX is not set
+# CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_SMIVGX is not set
+# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_VIRTUAL is not set
#
# Console display driver support
#
# CONFIG_VGA_CONSOLE is not set
-# CONFIG_SGI_NEWPORT_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
# CONFIG_FRAMEBUFFER_CONSOLE is not set
@@ -838,15 +1038,129 @@ CONFIG_DUMMY_CONSOLE=y
#
# USB support
#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_EHCI_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_OHCI_HCD is not set
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=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
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -872,6 +1186,7 @@ CONFIG_DUMMY_CONSOLE=y
#
# InfiniBand support
#
+# CONFIG_INFINIBAND is not set
#
# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -905,6 +1220,7 @@ CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
@@ -916,6 +1232,7 @@ CONFIG_XFS_FS=m
# CONFIG_XFS_SECURITY is not set
# CONFIG_XFS_POSIX_ACL is not set
# CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -948,8 +1265,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -993,7 +1312,6 @@ CONFIG_SUNRPC=y
CONFIG_SMB_FS=m
# CONFIG_SMB_NLS_DEFAULT is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -1004,7 +1322,6 @@ CONFIG_SMB_FS=m
#
# CONFIG_PARTITION_ADVANCED is not set
CONFIG_MSDOS_PARTITION=y
-CONFIG_SGI_PARTITION=y
#
# Native Language Support
@@ -1058,12 +1375,15 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE=""
@@ -1077,6 +1397,9 @@ CONFIG_CMDLINE=""
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -1086,6 +1409,8 @@ CONFIG_CRYPTO_SHA1=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/mips/configs/qemu_defconfig b/arch/mips/configs/qemu_defconfig
index 6a63a113b7ea..9b0dab822bd0 100644
--- a/arch/mips/configs/qemu_defconfig
+++ b/arch/mips/configs/qemu_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -146,6 +145,8 @@ CONFIG_HZ=100
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -687,7 +688,7 @@ CONFIG_FUSE_FS=y
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
@@ -734,6 +735,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/rbhma4500_defconfig b/arch/mips/configs/rbhma4500_defconfig
index 6779f449bd2d..dd0296036026 100644
--- a/arch/mips/configs/rbhma4500_defconfig
+++ b/arch/mips/configs/rbhma4500_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -156,6 +155,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1336,6 +1337,7 @@ CONFIG_NLS_DEFAULT="iso8859-1"
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/rm200_defconfig b/arch/mips/configs/rm200_defconfig
index b7826d3a2b77..d8a498d64d62 100644
--- a/arch/mips/configs/rm200_defconfig
+++ b/arch/mips/configs/rm200_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -159,6 +158,8 @@ CONFIG_HZ=1000
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1442,7 +1443,7 @@ CONFIG_NTFS_FS=m
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1585,6 +1586,7 @@ CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/sb1250-swarm_defconfig b/arch/mips/configs/sb1250-swarm_defconfig
index 625c1c619b6b..805a4fe450f5 100644
--- a/arch/mips/configs/sb1250-swarm_defconfig
+++ b/arch/mips/configs/sb1250-swarm_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -172,6 +171,8 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_BKL=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -874,6 +875,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/sead_defconfig b/arch/mips/configs/sead_defconfig
index 4401b602118f..6fcb656d8d87 100644
--- a/arch/mips/configs/sead_defconfig
+++ b/arch/mips/configs/sead_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -152,6 +151,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -582,6 +583,7 @@ CONFIG_PARTITION_ADVANCED=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/tb0226_defconfig b/arch/mips/configs/tb0226_defconfig
index 2ba4e25e8c34..dc312f19ada7 100644
--- a/arch/mips/configs/tb0226_defconfig
+++ b/arch/mips/configs/tb0226_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -152,6 +151,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1060,6 +1061,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/tb0229_defconfig b/arch/mips/configs/tb0229_defconfig
index fc8a407c1add..85615d99b01a 100644
--- a/arch/mips/configs/tb0229_defconfig
+++ b/arch/mips/configs/tb0229_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -152,6 +151,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -969,6 +970,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/tb0287_defconfig b/arch/mips/configs/tb0287_defconfig
index effcb63b81a3..f7e8194809a1 100644
--- a/arch/mips/configs/tb0287_defconfig
+++ b/arch/mips/configs/tb0287_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:21 2006
+# Linux kernel version: 2.6.19-rc2
+# Wed Oct 18 12:57:11 2006
#
CONFIG_MIPS=y
@@ -25,9 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
# CONFIG_LASAT is not set
# CONFIG_MIPS_ATLAS is not set
@@ -73,11 +70,11 @@ CONFIG_TANBAC_TB0287=y
# CONFIG_VICTOR_MPC30X is not set
# CONFIG_ZAO_CAPCELLA is not set
CONFIG_PCI_VR41XX=y
-# CONFIG_VRC4173 is not set
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
CONFIG_DMA_NONCOHERENT=y
CONFIG_DMA_NEED_PCI_MAP_STATE=y
@@ -124,8 +121,8 @@ CONFIG_PAGE_SIZE_4KB=y
# CONFIG_PAGE_SIZE_16KB is not set
# CONFIG_PAGE_SIZE_64KB is not set
CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_MT_SMP is not set
+# CONFIG_MIPS_MT_SMTC is not set
# CONFIG_MIPS_VPE_LOADER is not set
CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
@@ -152,6 +149,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -168,15 +167,19 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
# CONFIG_HOTPLUG is not set
@@ -184,12 +187,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -207,6 +210,7 @@ CONFIG_KMOD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -229,17 +233,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
CONFIG_HW_HAS_PCI=y
CONFIG_PCI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
CONFIG_MMU=y
#
# PCCARD (PCMCIA/CardBus) support
#
-# CONFIG_PCCARD is not set
#
# PCI Hotplug Support
#
-# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -262,6 +265,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -290,13 +294,10 @@ CONFIG_SYN_COOKIES=y
CONFIG_INET_TUNNEL=m
CONFIG_INET_XFRM_MODE_TRANSPORT=m
CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
CONFIG_TCP_CONG_ADVANCED=y
-
-#
-# TCP congestion control
-#
CONFIG_TCP_CONG_BIC=y
CONFIG_TCP_CONG_CUBIC=m
CONFIG_TCP_CONG_WESTWOOD=m
@@ -307,7 +308,13 @@ CONFIG_TCP_CONG_HTCP=m
# CONFIG_TCP_CONG_SCALABLE is not set
# CONFIG_TCP_CONG_LP is not set
# CONFIG_TCP_CONG_VENO is not set
-# CONFIG_TCP_CONG_COMPOUND is not set
+CONFIG_DEFAULT_BIC=y
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="bic"
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -337,7 +344,6 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -354,6 +360,7 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_IRDA is not set
# CONFIG_BT is not set
# CONFIG_IEEE80211 is not set
+CONFIG_FIB_RULES=y
#
# Device Drivers
@@ -364,7 +371,6 @@ CONFIG_NETWORK_SECMARK=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
# CONFIG_SYS_HYPERVISOR is not set
#
@@ -402,6 +408,7 @@ 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 is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -409,65 +416,14 @@ CONFIG_BLK_DEV_RAM_SIZE=4096
#
# ATA/ATAPI/MFM/RLL support
#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_BLK_DEV_IDEPCI=y
-# CONFIG_IDEPCI_SHARE_IRQ is not set
-# CONFIG_BLK_DEV_OFFBOARD is not set
-# CONFIG_BLK_DEV_GENERIC is not set
-# 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 is not set
-# CONFIG_BLK_DEV_AEC62XX is not set
-# CONFIG_BLK_DEV_ALI15X3 is not set
-# CONFIG_BLK_DEV_AMD74XX is not set
-# CONFIG_BLK_DEV_CMD64X is not set
-# CONFIG_BLK_DEV_TRIFLEX is not set
-# CONFIG_BLK_DEV_CY82C693 is not set
-# CONFIG_BLK_DEV_CS5520 is not set
-# CONFIG_BLK_DEV_CS5530 is not set
-# CONFIG_BLK_DEV_HPT34X is not set
-# CONFIG_BLK_DEV_HPT366 is not set
-# CONFIG_BLK_DEV_SC1200 is not set
-# CONFIG_BLK_DEV_PIIX 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
-# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-# CONFIG_BLK_DEV_SVWKS is not set
-CONFIG_BLK_DEV_SIIMAGE=y
-# CONFIG_BLK_DEV_SLC90E66 is not set
-# CONFIG_BLK_DEV_TRM290 is not set
-# CONFIG_BLK_DEV_VIA82CXXX is not set
-# CONFIG_IDE_ARM is not set
-CONFIG_BLK_DEV_IDEDMA=y
-# CONFIG_IDEDMA_IVB is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_IDE is not set
#
# SCSI device support
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -488,12 +444,13 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
@@ -506,21 +463,24 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
@@ -528,6 +488,59 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+# CONFIG_PATA_PDC2027X is not set
+CONFIG_PATA_SIL680=y
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -631,6 +644,7 @@ CONFIG_R8169=y
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -678,6 +692,7 @@ CONFIG_R8169=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -757,7 +772,6 @@ CONFIG_GPIO_VR41XX=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -783,12 +797,12 @@ CONFIG_GPIO_VR41XX=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -896,13 +910,13 @@ CONFIG_USB_STORAGE=m
# CONFIG_USB_STORAGE_DEBUG is not set
# CONFIG_USB_STORAGE_DATAFAB is not set
# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
# CONFIG_USB_STORAGE_DPCM is not set
# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -931,6 +945,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_ATI_REMOTE2 is not set
# CONFIG_USB_KEYSPAN_REMOTE is not set
# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
#
# USB Imaging devices
@@ -962,16 +977,17 @@ CONFIG_USB_MON=y
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
# CONFIG_USB_LCD is not set
# CONFIG_USB_LED is not set
-# CONFIG_USB_CY7C63 is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
@@ -1040,6 +1056,7 @@ CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
@@ -1051,6 +1068,7 @@ CONFIG_XFS_QUOTA=y
# CONFIG_XFS_SECURITY is not set
CONFIG_XFS_POSIX_ACL=y
# CONFIG_XFS_RT is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=m
@@ -1081,8 +1099,10 @@ CONFIG_AUTOFS4_FS=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1122,7 +1142,6 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -1147,12 +1166,15 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
CONFIG_CROSSCOMPILE=y
CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
@@ -1168,10 +1190,6 @@ CONFIG_CMDLINE="mem=64M console=ttyVR0,115200 ip=any root=/dev/nfs"
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
diff --git a/arch/mips/configs/workpad_defconfig b/arch/mips/configs/workpad_defconfig
index 4891d02ef8ca..863f6a7cadfd 100644
--- a/arch/mips/configs/workpad_defconfig
+++ b/arch/mips/configs/workpad_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:21 2006
+# Linux kernel version: 2.6.18-rc2
+# Tue Jul 25 23:13:04 2006
#
CONFIG_MIPS=y
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -148,6 +147,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -166,6 +167,7 @@ CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
@@ -379,6 +381,7 @@ CONFIG_CONNECTOR=m
CONFIG_BLK_DEV_RAM=m
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
# CONFIG_ATA_OVER_ETH is not set
@@ -855,7 +858,6 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -880,6 +882,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
@@ -887,7 +890,7 @@ CONFIG_MSDOS_PARTITION=y
CONFIG_LOG_BUF_SHIFT=14
# CONFIG_DEBUG_FS is not set
CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE="console=ttyVR0,19200 mem=16M"
+CONFIG_CMDLINE="console=ttyVR0,19200 ide0=0x170,0x376,49 mem=16M"
#
# Security options
diff --git a/arch/mips/configs/wrppmc_defconfig b/arch/mips/configs/wrppmc_defconfig
index 3e4b16b39827..c10267d61cc9 100644
--- a/arch/mips/configs/wrppmc_defconfig
+++ b/arch/mips/configs/wrppmc_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -156,6 +155,8 @@ CONFIG_HZ=1000
CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -830,6 +831,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/configs/yosemite_defconfig b/arch/mips/configs/yosemite_defconfig
index 3a68d8a25b66..4d3c1329f3cf 100644
--- a/arch/mips/configs/yosemite_defconfig
+++ b/arch/mips/configs/yosemite_defconfig
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -153,6 +152,8 @@ CONFIG_PREEMPT_NONE=y
# CONFIG_PREEMPT_VOLUNTARY is not set
# CONFIG_PREEMPT is not set
CONFIG_PREEMPT_BKL=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -761,6 +762,7 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/ddb5xxx/ddb5477/irq.c b/arch/mips/ddb5xxx/ddb5477/irq.c
index 513fc6722d84..a8bd2e66705c 100644
--- a/arch/mips/ddb5xxx/ddb5477/irq.c
+++ b/arch/mips/ddb5xxx/ddb5477/irq.c
@@ -153,8 +153,7 @@ u8 i8259_interrupt_ack(void)
* the first level int-handler will jump here if it is a vrc5477 irq
*/
#define NUM_5477_IRQS 32
-static void
-vrc5477_irq_dispatch(struct pt_regs *regs)
+static void vrc5477_irq_dispatch(void)
{
u32 intStatus;
u32 bitmask;
@@ -178,7 +177,7 @@ vrc5477_irq_dispatch(struct pt_regs *regs)
/* check for i8259 interrupts */
if (intStatus & (1 << VRC5477_I8259_CASCADE)) {
int i8259_irq = i8259_interrupt_ack();
- do_IRQ(I8259_IRQ_BASE + i8259_irq, regs);
+ do_IRQ(I8259_IRQ_BASE + i8259_irq);
return;
}
}
@@ -186,7 +185,7 @@ vrc5477_irq_dispatch(struct pt_regs *regs)
for (i=0, bitmask=1; i<= NUM_5477_IRQS; bitmask <<=1, i++) {
/* do we need to "and" with the int mask? */
if (intStatus & bitmask) {
- do_IRQ(VRC5477_IRQ_BASE + i, regs);
+ do_IRQ(VRC5477_IRQ_BASE + i);
return;
}
}
@@ -194,18 +193,18 @@ vrc5477_irq_dispatch(struct pt_regs *regs)
#define VR5477INTS (STATUSF_IP2|STATUSF_IP3|STATUSF_IP4|STATUSF_IP5|STATUSF_IP6)
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP7)
- do_IRQ(CPU_IRQ_BASE + 7, regs);
+ do_IRQ(CPU_IRQ_BASE + 7);
else if (pending & VR5477INTS)
- vrc5477_irq_dispatch(regs);
+ vrc5477_irq_dispatch();
else if (pending & STATUSF_IP0)
- do_IRQ(CPU_IRQ_BASE, regs);
+ do_IRQ(CPU_IRQ_BASE);
else if (pending & STATUSF_IP1)
- do_IRQ(CPU_IRQ_BASE + 1, regs);
+ do_IRQ(CPU_IRQ_BASE + 1);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
diff --git a/arch/mips/dec/boot/Makefile b/arch/mips/dec/boot/Makefile
deleted file mode 100644
index bcea41698ef5..000000000000
--- a/arch/mips/dec/boot/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-#
-# Makefile for the DECstation family specific parts of the kernel
-#
-
-netboot: all
- $(LD) -N -G 0 -T ld.ecoff ../../boot/zImage \
- dec_boot.o ramdisk.img -o nbImage
-
-obj-y := decstation.o
-
-clean:
- rm -f nbImage
diff --git a/arch/mips/dec/boot/decstation.c b/arch/mips/dec/boot/decstation.c
deleted file mode 100644
index 4db8bacaf22d..000000000000
--- a/arch/mips/dec/boot/decstation.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * arch/mips/dec/decstation.c
- */
-#include <asm/sections.h>
-
-#define RELOC
-#define INITRD
-#define DEBUG_BOOT
-
-/*
- * Magic number indicating REX PROM available on DECSTATION.
- */
-#define REX_PROM_MAGIC 0x30464354
-
-#define REX_PROM_CLEARCACHE 0x7c/4
-#define REX_PROM_PRINTF 0x30/4
-
-#define VEC_RESET 0xBFC00000 /* Prom base address */
-#define PMAX_PROM_ENTRY(x) (VEC_RESET+((x)*8)) /* Prom jump table */
-#define PMAX_PROM_PRINTF PMAX_PROM_ENTRY(17)
-
-#define PARAM (k_start + 0x2000)
-
-#define LOADER_TYPE (*(unsigned char *) (PARAM+0x210))
-#define INITRD_START (*(unsigned long *) (PARAM+0x218))
-#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
-
-extern int _ftext; /* begin and end of kernel image */
-extern void kernel_entry(int, char **, unsigned long, int *);
-
-void * memcpy(void * dest, const void *src, unsigned int count)
-{
- unsigned long *tmp = (unsigned long *) dest, *s = (unsigned long *) src;
-
- count >>= 2;
- while (count--)
- *tmp++ = *s++;
-
- return dest;
-}
-
-void dec_entry(int argc, char **argv,
- unsigned long magic, int *prom_vec)
-{
- void (*rex_clear_cache)(void);
- int (*prom_printf)(char *, ...);
- unsigned long k_start, len;
-
- /*
- * The DS5100 leaves cpu with BEV enabled, clear it.
- */
- asm( "lui\t$8,0x3000\n\t"
- "mtc0\t$8,$12\n\t"
- ".section\t.sdata\n\t"
- ".section\t.sbss\n\t"
- ".section\t.text"
- : : : "$8");
-
-#ifdef DEBUG_BOOT
- if (magic == REX_PROM_MAGIC) {
- prom_printf = (int (*)(char *, ...)) *(prom_vec + REX_PROM_PRINTF);
- } else {
- prom_printf = (int (*)(char *, ...)) PMAX_PROM_PRINTF;
- }
- prom_printf("Launching kernel...\n");
-#endif
-
- k_start = (unsigned long) (&kernel_entry) & 0xffff0000;
-
-#ifdef RELOC
- /*
- * Now copy kernel image to its destination.
- */
- len = ((unsigned long) (&_end) - k_start);
- memcpy((void *)k_start, &_ftext, len);
-#endif
-
- if (magic == REX_PROM_MAGIC) {
- rex_clear_cache = (void (*)(void)) * (prom_vec + REX_PROM_CLEARCACHE);
- rex_clear_cache();
- }
-
- kernel_entry(argc, argv, magic, prom_vec);
-}
diff --git a/arch/mips/dec/boot/ld.ecoff b/arch/mips/dec/boot/ld.ecoff
deleted file mode 100644
index aaa633dfb5f7..000000000000
--- a/arch/mips/dec/boot/ld.ecoff
+++ /dev/null
@@ -1,43 +0,0 @@
-OUTPUT_FORMAT("ecoff-littlemips")
-OUTPUT_ARCH(mips)
-ENTRY(dec_entry)
-SECTIONS
-{
- . = 0x80200000;
-
- .text :
- {
- _ftext = .;
- *(.text)
- *(.fixup)
- }
- .rdata :
- {
- *(.rodata .rodata.* .rdata)
- }
- .data :
- {
- . = ALIGN(0x1000);
- ramdisk.img (.data)
- *(.data)
- }
- .sdata :
- {
- *(.sdata)
- }
- _gp = .;
- .sbss :
- {
- *(.sbss)
- *(.scommon)
- }
- .bss :
- {
- *(.dynbss)
- *(.bss)
- *(COMMON)
- }
- /DISCARD/ : {
- *(.reginfo .mdebug .note)
- }
-}
diff --git a/arch/mips/dec/ecc-berr.c b/arch/mips/dec/ecc-berr.c
index cc24c5ed0c05..3e374d05978f 100644
--- a/arch/mips/dec/ecc-berr.c
+++ b/arch/mips/dec/ecc-berr.c
@@ -24,6 +24,7 @@
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
#include <asm/cpu.h>
+#include <asm/irq_regs.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/traps.h>
@@ -200,8 +201,10 @@ int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup)
return dec_ecc_be_backend(regs, is_fixup, 0);
}
-irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id)
{
+ struct pt_regs *regs = get_irq_regs();
+
int action = dec_ecc_be_backend(regs, 0, 1);
if (action == MIPS_BE_DISCARD)
diff --git a/arch/mips/dec/int-handler.S b/arch/mips/dec/int-handler.S
index 455a65b91cb0..31dd47d1002d 100644
--- a/arch/mips/dec/int-handler.S
+++ b/arch/mips/dec/int-handler.S
@@ -264,10 +264,10 @@
srlv t3,t1,t2
handle_it:
- jal do_IRQ
- move a1,sp
-
- j ret_from_irq
+ LONG_L s0, TI_REGS($28)
+ LONG_S sp, TI_REGS($28)
+ PTR_LA ra, ret_from_irq
+ j do_IRQ
nop
#ifdef CONFIG_32BIT
@@ -277,9 +277,8 @@ fpu:
#endif
spurious:
- jal spurious_interrupt
- nop
- j ret_from_irq
+ PTR_LA ra, _ret_from_irq
+ j spurious_interrupt
nop
END(plat_irq_dispatch)
diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c
index b9271db9bc76..f19b4617a0a6 100644
--- a/arch/mips/dec/kn01-berr.c
+++ b/arch/mips/dec/kn01-berr.c
@@ -150,10 +150,10 @@ int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup)
return dec_kn01_be_backend(regs, is_fixup, 0);
}
-irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id)
{
volatile u16 *csr = (void *)CKSEG1ADDR(KN01_SLOT_BASE + KN01_CSR);
+ struct pt_regs *regs = get_irq_regs();
int action;
if (!(*csr & KN01_CSR_MEMERR))
diff --git a/arch/mips/dec/kn02xa-berr.c b/arch/mips/dec/kn02xa-berr.c
index 6cd3f94f79fe..7a053aadcd3a 100644
--- a/arch/mips/dec/kn02xa-berr.c
+++ b/arch/mips/dec/kn02xa-berr.c
@@ -21,6 +21,8 @@
#include <linux/types.h>
#include <asm/addrspace.h>
+#include <asm/irq_regs.h>
+#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/traps.h>
@@ -104,9 +106,9 @@ int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup)
return dec_kn02xa_be_backend(regs, is_fixup, 0);
}
-irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id)
{
+ struct pt_regs *regs = get_irq_regs();
int action = dec_kn02xa_be_backend(regs, 0, 1);
if (action == MIPS_BE_DISCARD)
diff --git a/arch/mips/dec/prom/call_o32.S b/arch/mips/dec/prom/call_o32.S
index 0dd56db9b3d0..e523454bda3a 100644
--- a/arch/mips/dec/prom/call_o32.S
+++ b/arch/mips/dec/prom/call_o32.S
@@ -1,5 +1,5 @@
/*
- * arch/mips/dec/call_o32.S
+ * arch/mips/dec/prom/call_o32.S
*
* O32 interface for the 64 (or N32) ABI.
*
diff --git a/arch/mips/dec/reset.c b/arch/mips/dec/reset.c
index f78c6da47921..56397227adb0 100644
--- a/arch/mips/dec/reset.c
+++ b/arch/mips/dec/reset.c
@@ -8,7 +8,6 @@
#include <linux/linkage.h>
#include <asm/addrspace.h>
-#include <asm/ptrace.h>
typedef void ATTRIB_NORET (* noret_func_t)(void);
@@ -35,7 +34,7 @@ void ATTRIB_NORET dec_machine_power_off(void)
back_to_prom();
}
-irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t dec_intr_halt(int irq, void *dev_id)
{
dec_machine_halt();
}
diff --git a/arch/mips/dec/setup.c b/arch/mips/dec/setup.c
index d43241c2f541..6b7481e97bec 100644
--- a/arch/mips/dec/setup.c
+++ b/arch/mips/dec/setup.c
@@ -46,7 +46,7 @@
extern void dec_machine_restart(char *command);
extern void dec_machine_halt(void);
extern void dec_machine_power_off(void);
-extern irqreturn_t dec_intr_halt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t dec_intr_halt(int irq, void *dev_id);
unsigned long dec_kn_slot_base, dec_kn_slot_size;
diff --git a/arch/mips/dec/time.c b/arch/mips/dec/time.c
index 57294740c2dd..4cf0c06e2414 100644
--- a/arch/mips/dec/time.c
+++ b/arch/mips/dec/time.c
@@ -184,8 +184,6 @@ void __init dec_time_init(void)
CMOS_WRITE(RTC_REF_CLCK_32KHZ | (16 - __ffs(HZ)), RTC_REG_A);
}
-EXPORT_SYMBOL(do_settimeofday);
-
void __init plat_timer_setup(struct irqaction *irq)
{
setup_irq(dec_interrupt[DEC_IRQ_RTC], irq);
diff --git a/arch/mips/defconfig b/arch/mips/defconfig
index fff6fcc96212..21d53e0c9ee8 100644
--- a/arch/mips/defconfig
+++ b/arch/mips/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 09:49:33 2006
+# Thu Jul 6 10:04:10 2006
#
CONFIG_MIPS=y
@@ -25,7 +25,6 @@ CONFIG_MIPS=y
# CONFIG_MIPS_COBALT is not set
# CONFIG_MACH_DECSTATION is not set
# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
# CONFIG_MIPS_IVR is not set
# CONFIG_MIPS_ITE8172 is not set
# CONFIG_MACH_JAZZ is not set
@@ -154,6 +153,8 @@ CONFIG_HZ=1000
# CONFIG_PREEMPT_NONE is not set
CONFIG_PREEMPT_VOLUNTARY=y
# CONFIG_PREEMPT is not set
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_STACKTRACE_SUPPORT=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -1013,7 +1014,7 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -1148,6 +1149,7 @@ CONFIG_NLS_UTF8=m
#
# Kernel hacking
#
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
diff --git a/arch/mips/emma2rh/common/irq.c b/arch/mips/emma2rh/common/irq.c
index 3af57693c84c..c191b3e9d9d9 100644
--- a/arch/mips/emma2rh/common/irq.c
+++ b/arch/mips/emma2rh/common/irq.c
@@ -39,7 +39,7 @@
/*
* the first level int-handler will jump here if it is a emma2rh irq
*/
-asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs)
+void emma2rh_irq_dispatch(void)
{
u32 intStatus;
u32 bitmask;
@@ -56,7 +56,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs)
& emma2rh_in32(EMMA2RH_BHIF_SW_INT_EN);
for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) {
if (swIntStatus & bitmask) {
- do_IRQ(EMMA2RH_SW_IRQ_BASE + i, regs);
+ do_IRQ(EMMA2RH_SW_IRQ_BASE + i);
return;
}
}
@@ -65,7 +65,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs)
for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) {
if (intStatus & bitmask) {
- do_IRQ(EMMA2RH_IRQ_BASE + i, regs);
+ do_IRQ(EMMA2RH_IRQ_BASE + i);
return;
}
}
@@ -81,7 +81,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs)
& emma2rh_in32(EMMA2RH_GPIO_INT_MASK);
for (i = 0, bitmask = 1; i < 32; i++, bitmask <<= 1) {
if (gpioIntStatus & bitmask) {
- do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i, regs);
+ do_IRQ(EMMA2RH_GPIO_IRQ_BASE + i);
return;
}
}
@@ -90,7 +90,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs)
for (i = 32, bitmask = 1; i < 64; i++, bitmask <<= 1) {
if (intStatus & bitmask) {
- do_IRQ(EMMA2RH_IRQ_BASE + i, regs);
+ do_IRQ(EMMA2RH_IRQ_BASE + i);
return;
}
}
@@ -100,7 +100,7 @@ asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs)
for (i = 64, bitmask = 1; i < 96; i++, bitmask <<= 1) {
if (intStatus & bitmask) {
- do_IRQ(EMMA2RH_IRQ_BASE + i, regs);
+ do_IRQ(EMMA2RH_IRQ_BASE + i);
return;
}
}
diff --git a/arch/mips/emma2rh/markeins/irq.c b/arch/mips/emma2rh/markeins/irq.c
index 2a736be42c8c..c93369cb4115 100644
--- a/arch/mips/emma2rh/markeins/irq.c
+++ b/arch/mips/emma2rh/markeins/irq.c
@@ -57,7 +57,7 @@
extern void emma2rh_sw_irq_init(u32 base);
extern void emma2rh_gpio_irq_init(u32 base);
extern void emma2rh_irq_init(u32 base);
-extern asmlinkage void emma2rh_irq_dispatch(struct pt_regs *regs);
+extern void emma2rh_irq_dispatch(void);
static struct irqaction irq_cascade = {
.handler = no_action,
@@ -114,20 +114,20 @@ void __init arch_init_irq(void)
setup_irq(CPU_IRQ_BASE + CPU_EMMA2RH_CASCADE, &irq_cascade);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP7)
- do_IRQ(CPU_IRQ_BASE + 7, regs);
+ do_IRQ(CPU_IRQ_BASE + 7);
else if (pending & STATUSF_IP2)
- emma2rh_irq_dispatch(regs);
+ emma2rh_irq_dispatch();
else if (pending & STATUSF_IP1)
- do_IRQ(CPU_IRQ_BASE + 1, regs);
+ do_IRQ(CPU_IRQ_BASE + 1);
else if (pending & STATUSF_IP0)
- do_IRQ(CPU_IRQ_BASE + 0, regs);
+ do_IRQ(CPU_IRQ_BASE + 0);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
diff --git a/arch/mips/galileo-boards/ev96100/Makefile b/arch/mips/galileo-boards/ev96100/Makefile
deleted file mode 100644
index cd868ec78cbc..000000000000
--- a/arch/mips/galileo-boards/ev96100/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-#
-# Copyright 2000 MontaVista Software Inc.
-# Author: MontaVista Software, Inc.
-# ppopov@mvista.com or source@mvista.com
-#
-# Makefile for the Galileo EV96100 board.
-#
-
-obj-y += init.o irq.o puts.o reset.o time.o setup.o
diff --git a/arch/mips/galileo-boards/ev96100/init.c b/arch/mips/galileo-boards/ev96100/init.c
deleted file mode 100644
index a01fe9b36f2c..000000000000
--- a/arch/mips/galileo-boards/ev96100/init.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * This file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/generic/generic.c
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-#include <asm/gt64120.h>
-
-
-/* Environment variable */
-
-typedef struct {
- char *name;
- char *val;
-} t_env_var;
-
-int prom_argc;
-char **prom_argv, **prom_envp;
-
-int init_debug = 0;
-
-char * __init prom_getcmdline(void)
-{
- return &(arcs_cmdline[0]);
-}
-
-unsigned long __init prom_free_prom_memory(void)
-{
- return 0;
-}
-
-void __init prom_init_cmdline(void)
-{
- char *cp;
- int actr;
-
- actr = 1; /* Always ignore argv[0] */
-
- cp = &(arcs_cmdline[0]);
- while(actr < prom_argc) {
- strcpy(cp, prom_argv[actr]);
- cp += strlen(prom_argv[actr]);
- *cp++ = ' ';
- actr++;
- }
- if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
- --cp;
- *cp = '\0';
-}
-
-char *prom_getenv(char *envname)
-{
- /*
- * Return a pointer to the given environment variable.
- */
-
- t_env_var *env = (t_env_var *) prom_envp;
- int i;
-
- i = strlen(envname);
-
- while (env->name) {
- if (strncmp(envname, env->name, i) == 0) {
- return (env->val);
- }
- env++;
- }
- return (NULL);
-}
-
-static inline unsigned char str2hexnum(unsigned char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- return 0; /* foo */
-}
-
-static inline void str2eaddr(unsigned char *ea, unsigned char *str)
-{
- int i;
-
- for (i = 0; i < 6; i++) {
- unsigned char num;
-
- if ((*str == '.') || (*str == ':'))
- str++;
- num = str2hexnum(*str++) << 4;
- num |= (str2hexnum(*str++));
- ea[i] = num;
- }
-}
-
-int get_ethernet_addr(char *ethernet_addr)
-{
- char *ethaddr_str;
-
- ethaddr_str = prom_getenv("ethaddr");
- if (!ethaddr_str) {
- printk("ethaddr not set in boot prom\n");
- return -1;
- }
- str2eaddr(ethernet_addr, ethaddr_str);
-
- if (init_debug > 1) {
- int i;
- printk("get_ethernet_addr: ");
- for (i = 0; i < 5; i++)
- printk("%02x:",
- (unsigned char) *(ethernet_addr + i));
- printk("%02x\n", *(ethernet_addr + i));
- }
-
- return 0;
-}
-
-const char *get_system_type(void)
-{
- return "Galileo EV96100";
-}
-
-void __init prom_init(void)
-{
- volatile unsigned char *uart;
- char ppbuf[8];
-
- prom_argc = fw_arg0;
- prom_argv = (char **) fw_arg1;
- prom_envp = (char **) fw_arg2;
-
- mips_machgroup = MACH_GROUP_GALILEO;
- mips_machtype = MACH_EV96100;
-
- prom_init_cmdline();
-
- /* 32 MB upgradable */
- add_memory_region(0, 32 << 20, BOOT_MEM_RAM);
-}
diff --git a/arch/mips/galileo-boards/ev96100/irq.c b/arch/mips/galileo-boards/ev96100/irq.c
deleted file mode 100644
index ee5d6720f23b..000000000000
--- a/arch/mips/galileo-boards/ev96100/irq.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * This file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/atlas/atlas_int.c.
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/irq.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <asm/irq_cpu.h>
-
-static inline unsigned int ffz8(unsigned int word)
-{
- unsigned long k;
-
- k = 7;
- if (word & 0x0fUL) { k -= 4; word <<= 4; }
- if (word & 0x30UL) { k -= 2; word <<= 2; }
- if (word & 0x40UL) { k -= 1; }
-
- return k;
-}
-
-extern void mips_timer_interrupt(struct pt_regs *regs);
-
-asmlinkage void ev96100_cpu_irq(unsigned int pending, struct pt_regs *regs)
-{
- do_IRQ(ffz8(pending >> 8), regs);
-}
-
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
-{
- unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
-
- if (pending & CAUSEF_IP7)
- mips_timer_interrupt(regs);
- else if (pending)
- ev96100_cpu_irq(pending, regs);
- else
- spurious_interrupt(regs);
-}
-
-void __init arch_init_irq(void)
-{
- mips_cpu_irq_init(0);
-}
diff --git a/arch/mips/galileo-boards/ev96100/puts.c b/arch/mips/galileo-boards/ev96100/puts.c
deleted file mode 100644
index 49dc6d137b9c..000000000000
--- a/arch/mips/galileo-boards/ev96100/puts.c
+++ /dev/null
@@ -1,138 +0,0 @@
-
-/*
- * Debug routines which directly access the uart.
- */
-
-#include <linux/types.h>
-#include <asm/gt64120.h>
-
-
-//#define SERIAL_BASE EV96100_UART0_REGS_BASE
-#define SERIAL_BASE 0xBD000020
-#define NS16550_BASE SERIAL_BASE
-
-#define SERA_CMD 0x0D
-#define SERA_DATA 0x08
-//#define SERB_CMD 0x05
-#define SERB_CMD 20
-#define SERB_DATA 0x00
-#define TX_BUSY 0x20
-
-#define TIMEOUT 0xffff
-#undef SLOW_DOWN
-
-static const char digits[16] = "0123456789abcdef";
-static volatile unsigned char *const com1 = (unsigned char *) SERIAL_BASE;
-
-
-#ifdef SLOW_DOWN
-static inline void slow_down()
-{
- int k;
- for (k = 0; k < 10000; k++);
-}
-#else
-#define slow_down()
-#endif
-
-void putch(const unsigned char c)
-{
- unsigned char ch;
- int i = 0;
-
- do {
- ch = com1[SERB_CMD];
- slow_down();
- i++;
- if (i > TIMEOUT) {
- break;
- }
- } while (0 == (ch & TX_BUSY));
- com1[SERB_DATA] = c;
-}
-
-void putchar(const unsigned char c)
-{
- unsigned char ch;
- int i = 0;
-
- do {
- ch = com1[SERB_CMD];
- slow_down();
- i++;
- if (i > TIMEOUT) {
- break;
- }
- } while (0 == (ch & TX_BUSY));
- com1[SERB_DATA] = c;
-}
-
-void puts(unsigned char *cp)
-{
- unsigned char ch;
- int i = 0;
-
- while (*cp) {
- do {
- ch = com1[SERB_CMD];
- slow_down();
- i++;
- if (i > TIMEOUT) {
- break;
- }
- } while (0 == (ch & TX_BUSY));
- com1[SERB_DATA] = *cp++;
- }
- putch('\r');
- putch('\n');
-}
-
-void fputs(unsigned char *cp)
-{
- unsigned char ch;
- int i = 0;
-
- while (*cp) {
-
- do {
- ch = com1[SERB_CMD];
- slow_down();
- i++;
- if (i > TIMEOUT) {
- break;
- }
- } while (0 == (ch & TX_BUSY));
- com1[SERB_DATA] = *cp++;
- }
-}
-
-
-void put64(uint64_t ul)
-{
- int cnt;
- unsigned ch;
-
- cnt = 16; /* 16 nibbles in a 64 bit long */
- putch('0');
- putch('x');
- do {
- cnt--;
- ch = (unsigned char) (ul >> cnt * 4) & 0x0F;
- putch(digits[ch]);
- } while (cnt > 0);
-}
-
-void put32(unsigned u)
-{
- int cnt;
- unsigned ch;
-
- cnt = 8; /* 8 nibbles in a 32 bit long */
- putch('0');
- putch('x');
- do {
- cnt--;
- ch = (unsigned char) (u >> cnt * 4) & 0x0F;
- putch(digits[ch]);
- } while (cnt > 0);
-}
diff --git a/arch/mips/galileo-boards/ev96100/reset.c b/arch/mips/galileo-boards/ev96100/reset.c
deleted file mode 100644
index 5ef9b7f896e6..000000000000
--- a/arch/mips/galileo-boards/ev96100/reset.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Galileo EV96100 reset routines.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * This file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/generic/reset.c
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
-#include <asm/gt64120.h>
-
-static void mips_machine_restart(char *command);
-static void mips_machine_halt(void);
-
-static void mips_machine_restart(char *command)
-{
- set_c0_status(ST0_BEV | ST0_ERL);
- change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
- flush_cache_all();
- write_c0_wired(0);
- __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
- while (1);
-}
-
-static void mips_machine_halt(void)
-{
- printk(KERN_NOTICE "You can safely turn off the power\n");
- while (1)
- __asm__(".set\tmips3\n\t"
- "wait\n\t"
- ".set\tmips0");
-}
-
-void mips_reboot_setup(void)
-{
- _machine_restart = mips_machine_restart;
- _machine_halt = mips_machine_halt;
-}
diff --git a/arch/mips/galileo-boards/ev96100/setup.c b/arch/mips/galileo-boards/ev96100/setup.c
deleted file mode 100644
index 639ad5562c63..000000000000
--- a/arch/mips/galileo-boards/ev96100/setup.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Galileo EV96100 setup.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * This file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/atlas/atlas_setup.c.
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/pci.h>
-
-#include <asm/cpu.h>
-#include <asm/bootinfo.h>
-#include <asm/mipsregs.h>
-#include <asm/irq.h>
-#include <asm/delay.h>
-#include <asm/gt64120.h>
-#include <asm/galileo-boards/ev96100int.h>
-
-
-extern char *__init prom_getcmdline(void);
-
-extern void mips_reboot_setup(void);
-
-unsigned char mac_0_1[12];
-
-void __init plat_mem_setup(void)
-{
- unsigned int config = read_c0_config();
- unsigned int status = read_c0_status();
- unsigned int info = read_c0_info();
- u32 tmp;
-
- char *argptr;
-
- clear_c0_status(ST0_FR);
-
- if (config & 0x8)
- printk("Secondary cache is enabled\n");
- else
- printk("Secondary cache is disabled\n");
-
- if (status & (1 << 27))
- printk("User-mode cache ops enabled\n");
- else
- printk("User-mode cache ops disabled\n");
-
- printk("CP0 info reg: %x\n", (unsigned) info);
- if (info & (1 << 28))
- printk("burst mode Scache RAMS\n");
- else
- printk("pipelined Scache RAMS\n");
-
- if (info & 0x1)
- printk("Atomic Enable is set\n");
-
- argptr = prom_getcmdline();
-#ifdef CONFIG_SERIAL_CONSOLE
- if (strstr(argptr, "console=") == NULL) {
- argptr = prom_getcmdline();
- strcat(argptr, " console=ttyS0,115200");
- }
-#endif
-
- mips_reboot_setup();
-
- set_io_port_base(KSEG1);
- ioport_resource.start = GT_PCI_IO_BASE;
- ioport_resource.end = GT_PCI_IO_BASE + 0x01ffffff;
-
-#ifdef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = MKDEV(RAMDISK_MAJOR, 0);
-#endif
-
-
- /*
- * Setup GT controller master bit so we can do config cycles
- */
-
- /* Clear cause register bits */
- GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
- GT_INTRCAUSE_TARABORT0_BIT));
- /* Setup address */
- GT_WRITE(GT_PCI0_CFGADDR_OFS,
- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
- ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
- GT_PCI0_CFGADDR_CONFIGEN_BIT);
-
- udelay(2);
- tmp = GT_READ(GT_PCI0_CFGDATA_OFS);
-
- tmp |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
- GT_WRITE(GT_PCI0_CFGADDR_OFS,
- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
- ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
- GT_PCI0_CFGADDR_CONFIGEN_BIT);
- udelay(2);
- GT_WRITE(GT_PCI0_CFGDATA_OFS, tmp);
-
- /* Setup address */
- GT_WRITE(GT_PCI0_CFGADDR_OFS,
- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
- ((PCI_COMMAND / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
- GT_PCI0_CFGADDR_CONFIGEN_BIT);
-
- udelay(2);
- tmp = GT_READ(GT_PCI0_CFGDATA_OFS);
-}
-
-unsigned short get_gt_devid(void)
-{
- u32 gt_devid;
-
- /* Figure out if this is a gt96100 or gt96100A */
- GT_WRITE(GT_PCI0_CFGADDR_OFS,
- (0 << GT_PCI0_CFGADDR_BUSNUM_SHF) |
- (0 << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
- ((PCI_VENDOR_ID / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
- GT_PCI0_CFGADDR_CONFIGEN_BIT);
-
- udelay(4);
- gt_devid = GT_READ(GT_PCI0_CFGDATA_OFS);
-
- return gt_devid >> 16;
-}
diff --git a/arch/mips/galileo-boards/ev96100/time.c b/arch/mips/galileo-boards/ev96100/time.c
deleted file mode 100644
index 8cbe8426491a..000000000000
--- a/arch/mips/galileo-boards/ev96100/time.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Galileo EV96100 rtc routines.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * This file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/atlas/atlas_rtc.c.
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/timex.h>
-
-#include <asm/mipsregs.h>
-#include <asm/ptrace.h>
-#include <asm/time.h>
-
-
-#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
-
-extern volatile unsigned long wall_jiffies;
-unsigned long missed_heart_beats = 0;
-
-static unsigned long r4k_offset; /* Amount to increment compare reg each time */
-static unsigned long r4k_cur; /* What counter should be at next timer irq */
-
-static inline void ack_r4ktimer(unsigned long newval)
-{
- write_c0_compare(newval);
-}
-
-/*
- * There are a lot of conceptually broken versions of the MIPS timer interrupt
- * handler floating around. This one is rather different, but the algorithm
- * is probably more robust.
- */
-void mips_timer_interrupt(struct pt_regs *regs)
-{
- int irq = 7; /* FIX ME */
-
- if (r4k_offset == 0) {
- goto null;
- }
-
- do {
- kstat_this_cpu.irqs[irq]++;
- do_timer(regs);
-#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
-#endif
- r4k_cur += r4k_offset;
- ack_r4ktimer(r4k_cur);
-
- } while (((unsigned long)read_c0_count()
- - r4k_cur) < 0x7fffffff);
- return;
-
-null:
- ack_r4ktimer(0);
-}
diff --git a/arch/mips/gt64120/common/time.c b/arch/mips/gt64120/common/time.c
index d837b26fbe51..c83ae6acd601 100644
--- a/arch/mips/gt64120/common/time.c
+++ b/arch/mips/gt64120/common/time.c
@@ -10,7 +10,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
-#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
#include <asm/gt64120.h>
/*
@@ -19,7 +19,7 @@
* differently than other MIPS interrupts.
*/
-static void gt64120_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gt64120_irq(int irq, void *dev_id)
{
unsigned int irq_src, int_high_src, irq_src_mask, int_high_src_mask;
int handled = 0;
@@ -34,14 +34,16 @@ static void gt64120_irq(int irq, void *dev_id, struct pt_regs *regs)
if (irq_src & 0x00000800) { /* Check for timer interrupt */
handled = 1;
irq_src &= ~0x00000800;
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
}
GT_WRITE(GT_INTRCAUSE_OFS, 0);
GT_WRITE(GT_HINTRCAUSE_OFS, 0);
+
+ return IRQ_HANDLED;
}
/*
diff --git a/arch/mips/gt64120/ev64120/irq.c b/arch/mips/gt64120/ev64120/irq.c
index 5d939ac58f3f..ed4d82b9a24a 100644
--- a/arch/mips/gt64120/ev64120/irq.c
+++ b/arch/mips/gt64120/ev64120/irq.c
@@ -46,22 +46,22 @@
#include <asm/system.h>
#include <asm/gt64120.h>
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP4) /* int2 hardware line (timer) */
- do_IRQ(4, regs);
+ do_IRQ(4);
else if (pending & STATUSF_IP2) /* int0 hardware line */
- do_IRQ(GT_INTA, regs);
+ do_IRQ(GT_INTA);
else if (pending & STATUSF_IP5) /* int3 hardware line */
- do_IRQ(GT_INTD, regs);
+ do_IRQ(GT_INTD);
else if (pending & STATUSF_IP6) /* int4 hardware line */
- do_IRQ(6, regs);
+ do_IRQ(6);
else if (pending & STATUSF_IP7) /* compare int */
- do_IRQ(7, regs);
+ do_IRQ(7);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
static void disable_ev64120_irq(unsigned int irq_nr)
diff --git a/arch/mips/gt64120/ev64120/setup.c b/arch/mips/gt64120/ev64120/setup.c
index 4236da31ecc6..91c2d3f41617 100644
--- a/arch/mips/gt64120/ev64120/setup.c
+++ b/arch/mips/gt64120/ev64120/setup.c
@@ -42,7 +42,6 @@
#include <asm/irq.h>
#include <asm/pci.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/time.h>
#include <asm/reboot.h>
#include <asm/traps.h>
diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c
index 885f67f32ea3..d9294401ccb0 100644
--- a/arch/mips/gt64120/momenco_ocelot/irq.c
+++ b/arch/mips/gt64120/momenco_ocelot/irq.c
@@ -48,22 +48,22 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP2) /* int0 hardware line */
- do_IRQ(2, regs);
+ do_IRQ(2);
else if (pending & STATUSF_IP3) /* int1 hardware line */
- do_IRQ(3, regs);
+ do_IRQ(3);
else if (pending & STATUSF_IP4) /* int2 hardware line */
- do_IRQ(4, regs);
+ do_IRQ(4);
else if (pending & STATUSF_IP5) /* int3 hardware line */
- do_IRQ(5, regs);
+ do_IRQ(5);
else if (pending & STATUSF_IP6) /* int4 hardware line */
- do_IRQ(6, regs);
+ do_IRQ(6);
else if (pending & STATUSF_IP7) /* cpu timer */
- do_IRQ(7, regs);
+ do_IRQ(7);
else {
/*
* Now look at the extended interrupts
@@ -71,13 +71,13 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8) /* int6 hardware line */
- do_IRQ(8, regs);
+ do_IRQ(8);
else if (pending & STATUSF_IP9) /* int7 hardware line */
- do_IRQ(9, regs);
+ do_IRQ(9);
else if (pending & STATUSF_IP10) /* int8 hardware line */
- do_IRQ(10, regs);
+ do_IRQ(10);
else if (pending & STATUSF_IP11) /* int9 hardware line */
- do_IRQ(11, regs);
+ do_IRQ(11);
}
}
diff --git a/arch/mips/gt64120/momenco_ocelot/setup.c b/arch/mips/gt64120/momenco_ocelot/setup.c
index 9804642ecf89..0e5bbee2d5b7 100644
--- a/arch/mips/gt64120/momenco_ocelot/setup.c
+++ b/arch/mips/gt64120/momenco_ocelot/setup.c
@@ -56,7 +56,6 @@
#include <asm/irq.h>
#include <asm/pci.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/traps.h>
#include <linux/bootmem.h>
diff --git a/arch/mips/gt64120/wrppmc/irq.c b/arch/mips/gt64120/wrppmc/irq.c
index 8d75a43ce877..eedfc24e1eae 100644
--- a/arch/mips/gt64120/wrppmc/irq.c
+++ b/arch/mips/gt64120/wrppmc/irq.c
@@ -30,18 +30,18 @@
#include <asm/irq_cpu.h>
#include <asm/gt64120.h>
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP7)
- do_IRQ(WRPPMC_MIPS_TIMER_IRQ, regs); /* CPU Compare/Count internal timer */
+ do_IRQ(WRPPMC_MIPS_TIMER_IRQ); /* CPU Compare/Count internal timer */
else if (pending & STATUSF_IP6)
- do_IRQ(WRPPMC_UART16550_IRQ, regs); /* UART 16550 port */
+ do_IRQ(WRPPMC_UART16550_IRQ); /* UART 16550 port */
else if (pending & STATUSF_IP3)
- do_IRQ(WRPPMC_PCI_INTA_IRQ, regs); /* PCI INT_A */
+ do_IRQ(WRPPMC_PCI_INTA_IRQ); /* PCI INT_A */
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
/**
diff --git a/arch/mips/ite-boards/Kconfig b/arch/mips/ite-boards/Kconfig
deleted file mode 100644
index a6d59ad8f846..000000000000
--- a/arch/mips/ite-boards/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-config IT8172_REVC
- bool "Support for older IT8172 (Rev C)"
- depends on MIPS_ITE8172
- help
- Say Y here to support the older, Revision C version of the Integrated
- Technology Express, Inc. ITE8172 SBC. Vendor page at
- <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
- board at <http://www.mvista.com/partners/semiconductor/ite.html>.
diff --git a/arch/mips/ite-boards/generic/Makefile b/arch/mips/ite-boards/generic/Makefile
deleted file mode 100644
index 63431538d0ec..000000000000
--- a/arch/mips/ite-boards/generic/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-#
-# Copyright 2000 MontaVista Software Inc.
-# Author: MontaVista Software, Inc.
-# ppopov@mvista.com or source@mvista.com
-#
-# Makefile for the ITE 8172 (qed-4n-s01b) board, generic files.
-#
-
-obj-y += it8172_setup.o irq.o pmon_prom.o \
- time.o lpc.o puts.o reset.o
-
-obj-$(CONFIG_IT8172_CIR)+= it8172_cir.o
-obj-$(CONFIG_KGDB) += dbg_io.o
-
-EXTRA_AFLAGS := $(CFLAGS)
diff --git a/arch/mips/ite-boards/generic/dbg_io.c b/arch/mips/ite-boards/generic/dbg_io.c
deleted file mode 100644
index 8e9cd8a9670a..000000000000
--- a/arch/mips/ite-boards/generic/dbg_io.c
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-#ifdef CONFIG_KGDB
-
-/* --- CONFIG --- */
-
-/* we need uint32 uint8 */
-/* #include "types.h" */
-typedef unsigned char uint8;
-typedef unsigned int uint32;
-
-/* --- END OF CONFIG --- */
-
-#define UART16550_BAUD_2400 2400
-#define UART16550_BAUD_4800 4800
-#define UART16550_BAUD_9600 9600
-#define UART16550_BAUD_19200 19200
-#define UART16550_BAUD_38400 38400
-#define UART16550_BAUD_57600 57600
-#define UART16550_BAUD_115200 115200
-
-#define UART16550_PARITY_NONE 0
-#define UART16550_PARITY_ODD 0x08
-#define UART16550_PARITY_EVEN 0x18
-#define UART16550_PARITY_MARK 0x28
-#define UART16550_PARITY_SPACE 0x38
-
-#define UART16550_DATA_5BIT 0x0
-#define UART16550_DATA_6BIT 0x1
-#define UART16550_DATA_7BIT 0x2
-#define UART16550_DATA_8BIT 0x3
-
-#define UART16550_STOP_1BIT 0x0
-#define UART16550_STOP_2BIT 0x4
-
-/* ----------------------------------------------------- */
-
-/* === CONFIG === */
-
-/* [stevel] we use the IT8712 serial port for kgdb */
-#define DEBUG_BASE 0xB40003F8 /* 8712 serial port 1 base address */
-#define MAX_BAUD 115200
-
-/* === END OF CONFIG === */
-
-/* register offset */
-#define OFS_RCV_BUFFER 0
-#define OFS_TRANS_HOLD 0
-#define OFS_SEND_BUFFER 0
-#define OFS_INTR_ENABLE 1
-#define OFS_INTR_ID 2
-#define OFS_DATA_FORMAT 3
-#define OFS_LINE_CONTROL 3
-#define OFS_MODEM_CONTROL 4
-#define OFS_RS232_OUTPUT 4
-#define OFS_LINE_STATUS 5
-#define OFS_MODEM_STATUS 6
-#define OFS_RS232_INPUT 6
-#define OFS_SCRATCH_PAD 7
-
-#define OFS_DIVISOR_LSB 0
-#define OFS_DIVISOR_MSB 1
-
-
-/* memory-mapped read/write of the port */
-#define UART16550_READ(y) (*((volatile uint8*)(DEBUG_BASE + y)))
-#define UART16550_WRITE(y,z) ((*((volatile uint8*)(DEBUG_BASE + y))) = z)
-
-void debugInit(uint32 baud, uint8 data, uint8 parity, uint8 stop)
-{
- /* disable interrupts */
- UART16550_WRITE(OFS_INTR_ENABLE, 0);
-
- /* set up baud rate */
- {
- uint32 divisor;
-
- /* set DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x80);
-
- /* set divisor */
- divisor = MAX_BAUD / baud;
- UART16550_WRITE(OFS_DIVISOR_LSB, divisor & 0xff);
- UART16550_WRITE(OFS_DIVISOR_MSB, (divisor & 0xff00) >> 8);
-
- /* clear DIAB bit */
- UART16550_WRITE(OFS_LINE_CONTROL, 0x0);
- }
-
- /* set data format */
- UART16550_WRITE(OFS_DATA_FORMAT, data | parity | stop);
-}
-
-static int remoteDebugInitialized = 0;
-
-uint8 getDebugChar(void)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(UART16550_BAUD_115200,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x1) == 0);
- return UART16550_READ(OFS_RCV_BUFFER);
-}
-
-
-int putDebugChar(uint8 byte)
-{
- if (!remoteDebugInitialized) {
- remoteDebugInitialized = 1;
- debugInit(UART16550_BAUD_115200,
- UART16550_DATA_8BIT,
- UART16550_PARITY_NONE, UART16550_STOP_1BIT);
- }
-
- while ((UART16550_READ(OFS_LINE_STATUS) & 0x20) == 0);
- UART16550_WRITE(OFS_SEND_BUFFER, byte);
- return 1;
-}
-
-#endif
diff --git a/arch/mips/ite-boards/generic/irq.c b/arch/mips/ite-boards/generic/irq.c
deleted file mode 100644
index cb59ca4f76f0..000000000000
--- a/arch/mips/ite-boards/generic/irq.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * ITE 8172G interrupt/setup routines.
- *
- * Copyright 2000,2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * Part of this file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/atlas/atlas_int.c.
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/kernel_stat.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/timex.h>
-#include <linux/slab.h>
-#include <linux/random.h>
-#include <linux/serial_reg.h>
-#include <linux/bitops.h>
-
-#include <asm/bootinfo.h>
-#include <asm/io.h>
-#include <asm/mipsregs.h>
-#include <asm/system.h>
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_int.h>
-#include <asm/it8172/it8172_dbg.h>
-
-/* revisit */
-#define EXT_IRQ0_TO_IP 2 /* IP 2 */
-#define EXT_IRQ5_TO_IP 7 /* IP 7 */
-
-#define ALLINTS_NOTIMER (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4)
-
-extern void set_debug_traps(void);
-extern void mips_timer_interrupt(int irq, struct pt_regs *regs);
-
-struct it8172_intc_regs volatile *it8172_hw0_icregs =
- (struct it8172_intc_regs volatile *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_INTC_BASE));
-
-static void disable_it8172_irq(unsigned int irq_nr)
-{
- if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
- /* LPC interrupt */
- it8172_hw0_icregs->lpc_mask |=
- (1 << (irq_nr - IT8172_LPC_IRQ_BASE));
- } else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
- /* Local Bus interrupt */
- it8172_hw0_icregs->lb_mask |=
- (1 << (irq_nr - IT8172_LB_IRQ_BASE));
- } else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
- /* PCI and other interrupts */
- it8172_hw0_icregs->pci_mask |=
- (1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
- } else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
- /* NMI interrupts */
- it8172_hw0_icregs->nmi_mask |=
- (1 << (irq_nr - IT8172_NMI_IRQ_BASE));
- } else {
- panic("disable_it8172_irq: bad irq %d", irq_nr);
- }
-}
-
-static void enable_it8172_irq(unsigned int irq_nr)
-{
- if ( (irq_nr >= IT8172_LPC_IRQ_BASE) && (irq_nr <= IT8172_SERIRQ_15)) {
- /* LPC interrupt */
- it8172_hw0_icregs->lpc_mask &=
- ~(1 << (irq_nr - IT8172_LPC_IRQ_BASE));
- }
- else if ( (irq_nr >= IT8172_LB_IRQ_BASE) && (irq_nr <= IT8172_IOCHK_IRQ)) {
- /* Local Bus interrupt */
- it8172_hw0_icregs->lb_mask &=
- ~(1 << (irq_nr - IT8172_LB_IRQ_BASE));
- }
- else if ( (irq_nr >= IT8172_PCI_DEV_IRQ_BASE) && (irq_nr <= IT8172_DMA_IRQ)) {
- /* PCI and other interrupts */
- it8172_hw0_icregs->pci_mask &=
- ~(1 << (irq_nr - IT8172_PCI_DEV_IRQ_BASE));
- }
- else if ( (irq_nr >= IT8172_NMI_IRQ_BASE) && (irq_nr <= IT8172_POWER_NMI_IRQ)) {
- /* NMI interrupts */
- it8172_hw0_icregs->nmi_mask &=
- ~(1 << (irq_nr - IT8172_NMI_IRQ_BASE));
- }
- else {
- panic("enable_it8172_irq: bad irq %d", irq_nr);
- }
-}
-
-static unsigned int startup_ite_irq(unsigned int irq)
-{
- enable_it8172_irq(irq);
- return 0;
-}
-
-#define shutdown_ite_irq disable_it8172_irq
-#define mask_and_ack_ite_irq disable_it8172_irq
-
-static void end_ite_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_it8172_irq(irq);
-}
-
-static struct irq_chip it8172_irq_type = {
- .typename = "ITE8172",
- .startup = startup_ite_irq,
- .shutdown = shutdown_ite_irq,
- .enable = enable_it8172_irq,
- .disable = disable_it8172_irq,
- .ack = mask_and_ack_ite_irq,
- .end = end_ite_irq,
-};
-
-
-static void enable_none(unsigned int irq) { }
-static unsigned int startup_none(unsigned int irq) { return 0; }
-static void disable_none(unsigned int irq) { }
-static void ack_none(unsigned int irq) { }
-
-/* startup is the same as "enable", shutdown is same as "disable" */
-#define shutdown_none disable_none
-#define end_none enable_none
-
-static struct irq_chip cp0_irq_type = {
- .typename = "CP0 Count",
- .startup = startup_none,
- .shutdown = shutdown_none,
- .enable = enable_none,
- .disable = disable_none,
- .ack = ack_none,
- .end = end_none
-};
-
-void enable_cpu_timer(void)
-{
- unsigned long flags;
-
- local_irq_save(flags);
- set_c0_status(0x100 << EXT_IRQ5_TO_IP);
- local_irq_restore(flags);
-}
-
-void __init arch_init_irq(void)
-{
- int i;
- unsigned long flags;
-
- /* mask all interrupts */
- it8172_hw0_icregs->lb_mask = 0xffff;
- it8172_hw0_icregs->lpc_mask = 0xffff;
- it8172_hw0_icregs->pci_mask = 0xffff;
- it8172_hw0_icregs->nmi_mask = 0xffff;
-
- /* make all interrupts level triggered */
- it8172_hw0_icregs->lb_trigger = 0;
- it8172_hw0_icregs->lpc_trigger = 0;
- it8172_hw0_icregs->pci_trigger = 0;
- it8172_hw0_icregs->nmi_trigger = 0;
-
- /* active level setting */
- /* uart, keyboard, and mouse are active high */
- it8172_hw0_icregs->lpc_level = (0x10 | 0x2 | 0x1000);
- it8172_hw0_icregs->lb_level |= 0x20;
-
- /* keyboard and mouse are edge triggered */
- it8172_hw0_icregs->lpc_trigger |= (0x2 | 0x1000);
-
-
-#if 0
- // Enable this piece of code to make internal USB interrupt
- // edge triggered.
- it8172_hw0_icregs->pci_trigger |=
- (1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
- it8172_hw0_icregs->pci_level &=
- ~(1 << (IT8172_USB_IRQ - IT8172_PCI_DEV_IRQ_BASE));
-#endif
-
- for (i = 0; i <= IT8172_LAST_IRQ; i++) {
- irq_desc[i].chip = &it8172_irq_type;
- spin_lock_init(&irq_desc[i].lock);
- }
- irq_desc[MIPS_CPU_TIMER_IRQ].chip = &cp0_irq_type;
- set_c0_status(ALLINTS_NOTIMER);
-}
-
-void mips_spurious_interrupt(struct pt_regs *regs)
-{
-#if 1
- return;
-#else
- unsigned long status, cause;
-
- printk("got spurious interrupt\n");
- status = read_c0_status();
- cause = read_c0_cause();
- printk("status %x cause %x\n", status, cause);
- printk("epc %x badvaddr %x \n", regs->cp0_epc, regs->cp0_badvaddr);
-#endif
-}
-
-void it8172_hw0_irqdispatch(struct pt_regs *regs)
-{
- int irq;
- unsigned short intstatus = 0, status = 0;
-
- intstatus = it8172_hw0_icregs->intstatus;
- if (intstatus & 0x8) {
- panic("Got NMI interrupt");
- } else if (intstatus & 0x4) {
- /* PCI interrupt */
- irq = 0;
- status |= it8172_hw0_icregs->pci_req;
- while (!(status & 0x1)) {
- irq++;
- status >>= 1;
- }
- irq += IT8172_PCI_DEV_IRQ_BASE;
- } else if (intstatus & 0x1) {
- /* Local Bus interrupt */
- irq = 0;
- status |= it8172_hw0_icregs->lb_req;
- while (!(status & 0x1)) {
- irq++;
- status >>= 1;
- }
- irq += IT8172_LB_IRQ_BASE;
- } else if (intstatus & 0x2) {
- /* LPC interrupt */
- /* Since some lpc interrupts are edge triggered,
- * we could lose an interrupt this way because
- * we acknowledge all ints at onces. Revisit.
- */
- status |= it8172_hw0_icregs->lpc_req;
- it8172_hw0_icregs->lpc_req = 0; /* acknowledge ints */
- irq = 0;
- while (!(status & 0x1)) {
- irq++;
- status >>= 1;
- }
- irq += IT8172_LPC_IRQ_BASE;
- } else
- return;
-
- do_IRQ(irq, regs);
-}
-
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
-{
- unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
-
- if (!pending)
- mips_spurious_interrupt(regs);
- else if (pending & CAUSEF_IP7)
- ll_timer_interrupt(127, regs);
- else if (pending & CAUSEF_IP2)
- it8172_hw0_irqdispatch(regs);
-}
-
-void show_pending_irqs(void)
-{
- fputs("intstatus: ");
- put32(it8172_hw0_icregs->intstatus);
- puts("");
-
- fputs("pci_req: ");
- put32(it8172_hw0_icregs->pci_req);
- puts("");
-
- fputs("lb_req: ");
- put32(it8172_hw0_icregs->lb_req);
- puts("");
-
- fputs("lpc_req: ");
- put32(it8172_hw0_icregs->lpc_req);
- puts("");
-}
diff --git a/arch/mips/ite-boards/generic/it8172_cir.c b/arch/mips/ite-boards/generic/it8172_cir.c
deleted file mode 100644
index bfc25adcfec6..000000000000
--- a/arch/mips/ite-boards/generic/it8172_cir.c
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * IT8172 Consumer IR port generic routines.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-
-#ifdef CONFIG_IT8172_CIR
-
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_cir.h>
-
-
-volatile struct it8172_cir_regs *cir_regs[NUM_CIR_PORTS] = {
- (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR0_BASE)),
- (volatile struct it8172_cir_regs *)(KSEG1ADDR(IT8172_PCI_IO_BASE + IT_CIR1_BASE))};
-
-
-/*
- * Initialize Consumer IR Port.
- */
-int cir_port_init(struct cir_port *cir)
-{
- int port = cir->port;
- unsigned char data;
-
- /* set baud rate */
- cir_regs[port]->bdlr = cir->baud_rate & 0xff;
- cir_regs[port]->bdhr = (cir->baud_rate >> 8) & 0xff;
-
- /* set receiver control register */
- cir_regs[port]->rcr = (CIR_SET_RDWOS(cir->rdwos) | CIR_SET_RXDCR(cir->rxdcr));
-
- /* set carrier frequency register */
- cir_regs[port]->cfr = (CIR_SET_CF(cir->cfq) | CIR_SET_HS(cir->hcfs));
-
- /* set fifo threshold */
- data = cir_regs[port]->mstcr & 0xf3;
- data |= CIR_SET_FIFO_TL(cir->fifo_tl);
- cir_regs[port]->mstcr = data;
-
- clear_fifo(cir);
- enable_receiver(cir);
- disable_rx_demodulation(cir);
-
- set_rx_active(cir);
- int_enable(cir);
- rx_int_enable(cir);
-
- return 0;
-}
-
-
-void clear_fifo(struct cir_port *cir)
-{
- cir_regs[cir->port]->mstcr |= CIR_FIFO_CLEAR;
-}
-
-void enable_receiver(struct cir_port *cir)
-{
- cir_regs[cir->port]->rcr |= CIR_RXEN;
-}
-
-void disable_receiver(struct cir_port *cir)
-{
- cir_regs[cir->port]->rcr &= ~CIR_RXEN;
-}
-
-void enable_rx_demodulation(struct cir_port *cir)
-{
- cir_regs[cir->port]->rcr |= CIR_RXEND;
-}
-
-void disable_rx_demodulation(struct cir_port *cir)
-{
- cir_regs[cir->port]->rcr &= ~CIR_RXEND;
-}
-
-void set_rx_active(struct cir_port *cir)
-{
- cir_regs[cir->port]->rcr |= CIR_RXACT;
-}
-
-void int_enable(struct cir_port *cir)
-{
- cir_regs[cir->port]->ier |= CIR_IEC;
-}
-
-void rx_int_enable(struct cir_port *cir)
-{
- cir_regs[cir->port]->ier |= CIR_RDAIE;
-}
-
-void dump_regs(struct cir_port *cir)
-{
- printk("mstcr %x ier %x iir %x cfr %x rcr %x tcr %x tfsr %x rfsr %x\n",
- cir_regs[cir->port]->mstcr,
- cir_regs[cir->port]->ier,
- cir_regs[cir->port]->iir,
- cir_regs[cir->port]->cfr,
- cir_regs[cir->port]->rcr,
- cir_regs[cir->port]->tcr,
- cir_regs[cir->port]->tfsr,
- cir_regs[cir->port]->rfsr);
-
- while (cir_regs[cir->port]->iir & CIR_RDAI) {
- printk("data %x\n", cir_regs[cir->port]->dr);
- }
-}
-
-void dump_reg_addr(struct cir_port *cir)
-{
- printk("dr %x mstcr %x ier %x iir %x cfr %x rcr %x tcr %x bdlr %x bdhr %x tfsr %x rfsr %x\n",
- (unsigned)&cir_regs[cir->port]->dr,
- (unsigned)&cir_regs[cir->port]->mstcr,
- (unsigned)&cir_regs[cir->port]->ier,
- (unsigned)&cir_regs[cir->port]->iir,
- (unsigned)&cir_regs[cir->port]->cfr,
- (unsigned)&cir_regs[cir->port]->rcr,
- (unsigned)&cir_regs[cir->port]->tcr,
- (unsigned)&cir_regs[cir->port]->bdlr,
- (unsigned)&cir_regs[cir->port]->bdhr,
- (unsigned)&cir_regs[cir->port]->tfsr,
- (unsigned)&cir_regs[cir->port]->rfsr);
-}
-
-int cir_get_rx_count(struct cir_port *cir)
-{
- return cir_regs[cir->port]->rfsr & CIR_RXFBC_MASK;
-}
-
-char cir_read_data(struct cir_port *cir)
-{
- return cir_regs[cir->port]->dr;
-}
-
-char get_int_status(struct cir_port *cir)
-{
- return cir_regs[cir->port]->iir;
-}
-#endif
diff --git a/arch/mips/ite-boards/generic/it8172_setup.c b/arch/mips/ite-boards/generic/it8172_setup.c
deleted file mode 100644
index 07faf3cacff2..000000000000
--- a/arch/mips/ite-boards/generic/it8172_setup.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * IT8172/QED5231 board setup.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/serial_reg.h>
-#include <linux/major.h>
-#include <linux/kdev_t.h>
-#include <linux/root_dev.h>
-#include <linux/pm.h>
-
-#include <asm/cpu.h>
-#include <asm/time.h>
-#include <asm/io.h>
-#include <asm/bootinfo.h>
-#include <asm/irq.h>
-#include <asm/mipsregs.h>
-#include <asm/reboot.h>
-#include <asm/traps.h>
-#include <asm/it8172/it8172.h>
-#include <asm/it8712.h>
-
-extern struct resource ioport_resource;
-#ifdef CONFIG_SERIO_I8042
-int init_8712_keyboard(void);
-#endif
-
-extern int SearchIT8712(void);
-extern void InitLPCInterface(void);
-extern char * __init prom_getcmdline(void);
-extern void it8172_restart(char *command);
-extern void it8172_halt(void);
-extern void it8172_power_off(void);
-
-extern void it8172_time_init(void);
-
-#ifdef CONFIG_IT8172_REVC
-struct {
- struct resource ram;
- struct resource pci_mem;
- struct resource pci_io;
- struct resource flash;
- struct resource boot;
-} it8172_resources = {
- {
- .start = 0, /* to be initted */
- .end = 0,
- .name = "RAM",
- .flags = IORESOURCE_MEM
- }, {
- .start = 0x10000000,
- .end = 0x13FFFFFF,
- .name = "PCI Mem",
- .flags = IORESOURCE_MEM
- }, {
- .start = 0x14000000,
- .end = 0x17FFFFFF
- .name = "PCI I/O",
- }, {
- .start = 0x08000000,
- .end = 0x0CFFFFFF
- .name = "Flash",
- }, {
- .start = 0x1FC00000,
- .end = 0x1FFFFFFF
- .name = "Boot ROM",
- }
-};
-#else
-struct {
- struct resource ram;
- struct resource pci_mem0;
- struct resource pci_mem1;
- struct resource pci_io;
- struct resource pci_mem2;
- struct resource pci_mem3;
- struct resource flash;
- struct resource boot;
-} it8172_resources = {
- {
- .start = 0, /* to be initted */
- .end = 0,
- .name = "RAM",
- .flags = IORESOURCE_MEM
- }, {
- .start = 0x0C000000,
- .end = 0x0FFFFFFF,
- .name = "PCI Mem0",
- .flags = IORESOURCE_MEM
- }, {
- .start = 0x10000000,
- .end = 0x13FFFFFF,
- .name = "PCI Mem1",
- .flags = IORESOURCE_MEM
- }, {
- .start = 0x14000000,
- .end = 0x17FFFFFF
- .name = "PCI I/O",
- }, {
- .start = 0x1A000000,
- .end = 0x1BFFFFFF,
- .name = "PCI Mem2",
- .flags = IORESOURCE_MEM
- }, {
- .start = 0x1C000000,
- .end = 0x1FBFFFFF,
- .name = "PCI Mem3",
- .flags = IORESOURCE_MEM
- }, {
- .start = 0x08000000,
- .end = 0x0CFFFFFF
- .name = "Flash",
- }, {
- .start = 0x1FC00000,
- .end = 0x1FFFFFFF
- .name = "Boot ROM",
- }
-};
-#endif
-
-
-void __init it8172_init_ram_resource(unsigned long memsize)
-{
- it8172_resources.ram.end = memsize;
-}
-
-void __init plat_mem_setup(void)
-{
- unsigned short dsr;
- char *argptr;
-
- argptr = prom_getcmdline();
-#ifdef CONFIG_SERIAL_CONSOLE
- if ((argptr = strstr(argptr, "console=")) == NULL) {
- argptr = prom_getcmdline();
- strcat(argptr, " console=ttyS0,115200");
- }
-#endif
-
- clear_c0_status(ST0_FR);
-
- board_time_init = it8172_time_init;
-
- _machine_restart = it8172_restart;
- _machine_halt = it8172_halt;
- pm_power_off = it8172_power_off;
-
- /*
- * IO/MEM resources.
- *
- * revisit this area.
- */
- set_io_port_base(KSEG1);
- ioport_resource.start = it8172_resources.pci_io.start;
- ioport_resource.end = it8172_resources.pci_io.end;
-#ifdef CONFIG_IT8172_REVC
- iomem_resource.start = it8172_resources.pci_mem.start;
- iomem_resource.end = it8172_resources.pci_mem.end;
-#else
- iomem_resource.start = it8172_resources.pci_mem0.start;
- iomem_resource.end = it8172_resources.pci_mem3.end;
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
- ROOT_DEV = Root_RAM0;
-#endif
-
- /*
- * Pull enabled devices out of standby
- */
- IT_IO_READ16(IT_PM_DSR, dsr);
-
- /*
- * Fixme: This breaks when these drivers are modules!!!
- */
-#ifdef CONFIG_SOUND_IT8172
- dsr &= ~IT_PM_DSR_ACSB;
-#else
- dsr |= IT_PM_DSR_ACSB;
-#endif
-#ifdef CONFIG_BLK_DEV_IT8172
- dsr &= ~IT_PM_DSR_IDESB;
-#else
- dsr |= IT_PM_DSR_IDESB;
-#endif
- IT_IO_WRITE16(IT_PM_DSR, dsr);
-
- InitLPCInterface();
-
-#ifdef CONFIG_MIPS_ITE8172
- if (SearchIT8712()) {
- printk("Found IT8712 Super IO\n");
- /* enable IT8712 serial port */
- LPCSetConfig(LDN_SERIAL1, 0x30, 0x01); /* enable */
- LPCSetConfig(LDN_SERIAL1, 0x23, 0x01); /* clock selection */
-#ifdef CONFIG_SERIO_I8042
- if (init_8712_keyboard()) {
- printk("Unable to initialize keyboard\n");
- LPCSetConfig(LDN_KEYBOARD, 0x30, 0x0); /* disable keyboard */
- } else {
- LPCSetConfig(LDN_KEYBOARD, 0x30, 0x1); /* enable keyboard */
- LPCSetConfig(LDN_KEYBOARD, 0xf0, 0x2);
- LPCSetConfig(LDN_KEYBOARD, 0x71, 0x3);
-
- LPCSetConfig(LDN_MOUSE, 0x30, 0x1); /* enable mouse */
-
- LPCSetConfig(0x4, 0x30, 0x1);
- LPCSetConfig(0x4, 0xf4, LPCGetConfig(0x4, 0xf4) | 0x80);
-
- if ((LPCGetConfig(LDN_KEYBOARD, 0x30) == 0) ||
- (LPCGetConfig(LDN_MOUSE, 0x30) == 0))
- printk("Error: keyboard or mouse not enabled\n");
-
- }
-#endif
- }
- else {
- printk("IT8712 Super IO not found\n");
- }
-#endif
-
-#ifdef CONFIG_IT8172_CIR
- {
- unsigned long data;
- //printk("Enabling CIR0\n");
- IT_IO_READ16(IT_PM_DSR, data);
- data &= ~IT_PM_DSR_CIR0SB;
- IT_IO_WRITE16(IT_PM_DSR, data);
- //printk("DSR register: %x\n", (unsigned)IT_IO_READ16(IT_PM_DSR, data));
- }
-#endif
-#ifdef CONFIG_IT8172_SCR0
- {
- unsigned i;
- /* Enable Smart Card Reader 0 */
- /* First power it up */
- IT_IO_READ16(IT_PM_DSR, i);
- i &= ~IT_PM_DSR_SCR0SB;
- IT_IO_WRITE16(IT_PM_DSR, i);
- /* Then initialize its registers */
- outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT
- |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
- |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
- |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
- |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT),
- IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SFR);
- outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
- IT8172_PCI_IO_BASE + IT_SCR0_BASE + IT_SCR_SCDR);
- }
-#endif /* CONFIG_IT8172_SCR0 */
-#ifdef CONFIG_IT8172_SCR1
- {
- unsigned i;
- /* Enable Smart Card Reader 1 */
- /* First power it up */
- IT_IO_READ16(IT_PM_DSR, i);
- i &= ~IT_PM_DSR_SCR1SB;
- IT_IO_WRITE16(IT_PM_DSR, i);
- /* Then initialize its registers */
- outb(( IT_SCR_SFR_GATE_UART_OFF << IT_SCR_SFR_GATE_UART_BIT
- |IT_SCR_SFR_FET_CHARGE_213_US << IT_SCR_SFR_FET_CHARGE_BIT
- |IT_SCR_SFR_CARD_FREQ_3_5_MHZ << IT_SCR_SFR_CARD_FREQ_BIT
- |IT_SCR_SFR_FET_ACTIVE_INVERT << IT_SCR_SFR_FET_ACTIVE_BIT
- |IT_SCR_SFR_ENABLE_ON << IT_SCR_SFR_ENABLE_BIT),
- IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SFR);
- outb(IT_SCR_SCDR_RESET_MODE_ASYNC << IT_SCR_SCDR_RESET_MODE_BIT,
- IT8172_PCI_IO_BASE + IT_SCR1_BASE + IT_SCR_SCDR);
- }
-#endif /* CONFIG_IT8172_SCR1 */
-}
-
-#ifdef CONFIG_SERIO_I8042
-/*
- * According to the ITE Special BIOS Note for waking up the
- * keyboard controller...
- */
-static int init_8712_keyboard(void)
-{
- unsigned int cmd_port = 0x14000064;
- unsigned int data_port = 0x14000060;
- ^^^^^^^^^^^
- Somebody here doesn't grok the concept of io ports.
-
- unsigned char data;
- int i;
-
- outb(0xaa, cmd_port); /* send self-test cmd */
- i = 0;
- while (!(inb(cmd_port) & 0x1)) { /* wait output buffer full */
- i++;
- if (i > 0xffffff)
- return 1;
- }
-
- data = inb(data_port);
- outb(0xcb, cmd_port); /* set ps2 mode */
- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
- i++;
- if (i > 0xffffff)
- return 1;
- }
- outb(0x01, data_port);
- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
- i++;
- if (i > 0xffffff)
- return 1;
- }
-
- outb(0x60, cmd_port); /* write 8042 command byte */
- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
- i++;
- if (i > 0xffffff)
- return 1;
- }
- outb(0x45, data_port); /* at interface, keyboard enabled, system flag */
- while (inb(cmd_port) & 0x2) { /* wait while input buffer full */
- i++;
- if (i > 0xffffff)
- return 1;
- }
-
- outb(0xae, cmd_port); /* enable interface */
- return 0;
-}
-#endif
diff --git a/arch/mips/ite-boards/generic/lpc.c b/arch/mips/ite-boards/generic/lpc.c
deleted file mode 100644
index cc7584fbef8a..000000000000
--- a/arch/mips/ite-boards/generic/lpc.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * ITE Semi IT8712 Super I/O functions.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <asm/io.h>
-#include <asm/types.h>
-#include <asm/it8712.h>
-#include <asm/it8172/it8172.h>
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-void LPCEnterMBPnP(void)
-{
- int i;
- unsigned char key[4] = {0x87, 0x01, 0x55, 0x55};
-
- for (i = 0; i<4; i++)
- outb(key[i], LPC_KEY_ADDR);
-
-}
-
-void LPCExitMBPnP(void)
-{
- outb(0x02, LPC_KEY_ADDR);
- outb(0x02, LPC_DATA_ADDR);
-}
-
-void LPCSetConfig(char LdnNumber, char Index, char data)
-{
- LPCEnterMBPnP(); // Enter IT8712 MB PnP mode
- outb(0x07, LPC_KEY_ADDR);
- outb(LdnNumber, LPC_DATA_ADDR);
- outb(Index, LPC_KEY_ADDR);
- outb(data, LPC_DATA_ADDR);
- LPCExitMBPnP();
-}
-
-char LPCGetConfig(char LdnNumber, char Index)
-{
- char rtn;
-
- LPCEnterMBPnP(); // Enter IT8712 MB PnP mode
- outb(0x07, LPC_KEY_ADDR);
- outb(LdnNumber, LPC_DATA_ADDR);
- outb(Index, LPC_KEY_ADDR);
- rtn = inb(LPC_DATA_ADDR);
- LPCExitMBPnP();
- return rtn;
-}
-
-int SearchIT8712(void)
-{
- unsigned char Id1, Id2;
- unsigned short Id;
-
- LPCEnterMBPnP();
- outb(0x20, LPC_KEY_ADDR); /* chip id byte 1 */
- Id1 = inb(LPC_DATA_ADDR);
- outb(0x21, LPC_KEY_ADDR); /* chip id byte 2 */
- Id2 = inb(LPC_DATA_ADDR);
- Id = (Id1 << 8) | Id2;
- LPCExitMBPnP();
- if (Id == 0x8712)
- return TRUE;
- else
- return FALSE;
-}
-
-void InitLPCInterface(void)
-{
- unsigned char bus, dev_fn;
- unsigned long data;
-
- bus = 0;
- dev_fn = 1<<3 | 4;
-
-
- /* pci cmd, SERR# Enable */
- IT_WRITE(IT_CONFADDR,
- (bus << IT_BUSNUM_SHF) |
- (dev_fn << IT_FUNCNUM_SHF) |
- ((0x4 / 4) << IT_REGNUM_SHF));
- IT_READ(IT_CONFDATA, data);
- data |= 0x0100;
- IT_WRITE(IT_CONFADDR,
- (bus << IT_BUSNUM_SHF) |
- (dev_fn << IT_FUNCNUM_SHF) |
- ((0x4 / 4) << IT_REGNUM_SHF));
- IT_WRITE(IT_CONFDATA, data);
-
- /* setup serial irq control register */
- IT_WRITE(IT_CONFADDR,
- (bus << IT_BUSNUM_SHF) |
- (dev_fn << IT_FUNCNUM_SHF) |
- ((0x48 / 4) << IT_REGNUM_SHF));
- IT_READ(IT_CONFDATA, data);
- data = (data & 0xffff00ff) | 0xc400;
- IT_WRITE(IT_CONFADDR,
- (bus << IT_BUSNUM_SHF) |
- (dev_fn << IT_FUNCNUM_SHF) |
- ((0x48 / 4) << IT_REGNUM_SHF));
- IT_WRITE(IT_CONFDATA, data);
-
-
- /* Enable I/O Space Subtractive Decode */
- /* default 0x4C is 0x3f220000 */
- IT_WRITE(IT_CONFADDR,
- (bus << IT_BUSNUM_SHF) |
- (dev_fn << IT_FUNCNUM_SHF) |
- ((0x4C / 4) << IT_REGNUM_SHF));
- IT_WRITE(IT_CONFDATA, 0x3f2200f3);
-}
diff --git a/arch/mips/ite-boards/generic/pmon_prom.c b/arch/mips/ite-boards/generic/pmon_prom.c
deleted file mode 100644
index 7d0a79be34d8..000000000000
--- a/arch/mips/ite-boards/generic/pmon_prom.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * PROM library initialisation code, assuming a version of
- * pmon is the boot code.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * This file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/xx files.
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/string.h>
-
-#include <asm/bootinfo.h>
-
-extern int prom_argc;
-extern char **prom_argv, **prom_envp;
-
-typedef struct
-{
- char *name;
-/* char *val; */
-}t_env_var;
-
-
-char * __init prom_getcmdline(void)
-{
- return &(arcs_cmdline[0]);
-}
-
-void __init prom_init_cmdline(void)
-{
- char *cp;
- int actr;
-
- actr = 1; /* Always ignore argv[0] */
-
- cp = &(arcs_cmdline[0]);
- while(actr < prom_argc) {
- strcpy(cp, prom_argv[actr]);
- cp += strlen(prom_argv[actr]);
- *cp++ = ' ';
- actr++;
- }
- if (cp != &(arcs_cmdline[0])) /* get rid of trailing space */
- --cp;
- *cp = '\0';
-
-}
-
-
-char *prom_getenv(char *envname)
-{
- /*
- * Return a pointer to the given environment variable.
- * Environment variables are stored in the form of "memsize=64".
- */
-
- t_env_var *env = (t_env_var *)prom_envp;
- int i;
-
- i = strlen(envname);
-
- while(env->name) {
- if(strncmp(envname, env->name, i) == 0) {
- return(env->name + strlen(envname) + 1);
- }
- env++;
- }
- return(NULL);
-}
-
-static inline unsigned char str2hexnum(unsigned char c)
-{
- if(c >= '0' && c <= '9')
- return c - '0';
- if(c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- return 0; /* foo */
-}
-
-unsigned long __init prom_free_prom_memory(void)
-{
- return 0;
-}
-
-unsigned long __init prom_get_memsize(void)
-{
- char *memsize_str;
- unsigned int memsize;
-
- memsize_str = prom_getenv("memsize");
- if (!memsize_str) {
-#ifdef CONFIG_MIPS_ITE8172
- memsize = 32;
-#elif defined(CONFIG_MIPS_IVR)
- memsize = 64;
-#else
- memsize = 8;
-#endif
- printk("memsize unknown: setting to %dMB\n", memsize);
- } else {
- printk("memsize: %s\n", memsize_str);
- memsize = simple_strtol(memsize_str, NULL, 0);
- }
- return memsize;
-}
diff --git a/arch/mips/ite-boards/generic/puts.c b/arch/mips/ite-boards/generic/puts.c
deleted file mode 100644
index 20b02df6b414..000000000000
--- a/arch/mips/ite-boards/generic/puts.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * Low level uart routines to directly access a 16550 uart.
- *
- * Copyright 2000,2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/types.h>
-
-#define SERIAL_BASE 0xB4011800 /* it8172 */
-#define SER_CMD 5
-#define SER_DATA 0x00
-#define TX_BUSY 0x20
-
-#define TIMEOUT 0xffff
-#undef SLOW_DOWN
-
-static const char digits[16] = "0123456789abcdef";
-static volatile unsigned char *const com1 = (unsigned char *) SERIAL_BASE;
-
-
-#ifdef SLOW_DOWN
-static inline void slow_down()
-{
- int k;
- for (k = 0; k < 10000; k++);
-}
-#else
-#define slow_down()
-#endif
-
-void putch(const unsigned char c)
-{
- unsigned char ch;
- int i = 0;
-
- do {
- ch = com1[SER_CMD];
- slow_down();
- i++;
- if (i > TIMEOUT) {
- break;
- }
- } while (0 == (ch & TX_BUSY));
- com1[SER_DATA] = c;
-}
-
-void puts(unsigned char *cp)
-{
- unsigned char ch;
- int i = 0;
-
- while (*cp) {
- do {
- ch = com1[SER_CMD];
- slow_down();
- i++;
- if (i > TIMEOUT) {
- break;
- }
- } while (0 == (ch & TX_BUSY));
- com1[SER_DATA] = *cp++;
- }
- putch('\r');
- putch('\n');
-}
-
-void fputs(unsigned char *cp)
-{
- unsigned char ch;
- int i = 0;
-
- while (*cp) {
-
- do {
- ch = com1[SER_CMD];
- slow_down();
- i++;
- if (i > TIMEOUT) {
- break;
- }
- } while (0 == (ch & TX_BUSY));
- com1[SER_DATA] = *cp++;
- }
-}
-
-
-void put64(uint64_t ul)
-{
- int cnt;
- unsigned ch;
-
- cnt = 16; /* 16 nibbles in a 64 bit long */
- putch('0');
- putch('x');
- do {
- cnt--;
- ch = (unsigned char) (ul >> cnt * 4) & 0x0F;
- putch(digits[ch]);
- } while (cnt > 0);
-}
-
-void put32(unsigned u)
-{
- int cnt;
- unsigned ch;
-
- cnt = 8; /* 8 nibbles in a 32 bit long */
- putch('0');
- putch('x');
- do {
- cnt--;
- ch = (unsigned char) (u >> cnt * 4) & 0x0F;
- putch(digits[ch]);
- } while (cnt > 0);
-}
diff --git a/arch/mips/ite-boards/generic/reset.c b/arch/mips/ite-boards/generic/reset.c
deleted file mode 100644
index 03bd5ba8c913..000000000000
--- a/arch/mips/ite-boards/generic/reset.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * ITE 8172 reset routines.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <asm/cacheflush.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/reboot.h>
-#include <asm/system.h>
-
-void it8172_restart()
-{
- set_c0_status(ST0_BEV | ST0_ERL);
- change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
- flush_cache_all();
- write_c0_wired(0);
- __asm__ __volatile__("jr\t%0"::"r"(0xbfc00000));
-}
-
-void it8172_halt(void)
-{
- printk(KERN_NOTICE "\n** You can safely turn off the power\n");
- while (1)
- __asm__(".set\tmips3\n\t"
- "wait\n\t"
- ".set\tmips0");
-}
-
-void it8172_power_off(void)
-{
- it8172_halt();
-}
diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c
deleted file mode 100644
index 3dc55569ff7f..000000000000
--- a/arch/mips/ite-boards/generic/time.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * Copyright (C) 2003 MontaVista Software Inc.
- * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net
- *
- * ########################################################################
- *
- * This program is free software; you can distribute 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 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.
- *
- * ########################################################################
- *
- * Setting up the clock on the MIPS boards.
- */
-#include <linux/init.h>
-#include <linux/kernel_stat.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/spinlock.h>
-#include <linux/mc146818rtc.h>
-
-#include <asm/time.h>
-#include <asm/mipsregs.h>
-#include <asm/ptrace.h>
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_int.h>
-#include <asm/debug.h>
-
-#define IT8172_RTC_ADR_REG (IT8172_PCI_IO_BASE + IT_RTC_BASE)
-#define IT8172_RTC_DAT_REG (IT8172_RTC_ADR_REG + 1)
-#define IT8172_RTC_CENTURY_REG (IT8172_PCI_IO_BASE + IT_RTC_CENTURY)
-
-static volatile char *rtc_adr_reg = (char*)KSEG1ADDR(IT8172_RTC_ADR_REG);
-static volatile char *rtc_dat_reg = (char*)KSEG1ADDR(IT8172_RTC_DAT_REG);
-static volatile char *rtc_century_reg = (char*)KSEG1ADDR(IT8172_RTC_CENTURY_REG);
-
-unsigned char it8172_rtc_read_data(unsigned long addr)
-{
- unsigned char retval;
-
- *rtc_adr_reg = addr;
- retval = *rtc_dat_reg;
- return retval;
-}
-
-void it8172_rtc_write_data(unsigned char data, unsigned long addr)
-{
- *rtc_adr_reg = addr;
- *rtc_dat_reg = data;
-}
-
-#undef CMOS_READ
-#undef CMOS_WRITE
-#define CMOS_READ(addr) it8172_rtc_read_data(addr)
-#define CMOS_WRITE(data, addr) it8172_rtc_write_data(data, addr)
-
-static unsigned char saved_control; /* remember rtc control reg */
-static inline int rtc_24h(void) { return saved_control & RTC_24H; }
-static inline int rtc_dm_binary(void) { return saved_control & RTC_DM_BINARY; }
-
-static inline unsigned char
-bin_to_hw(unsigned char c)
-{
- if (rtc_dm_binary())
- return c;
- else
- return ((c/10) << 4) + (c%10);
-}
-
-static inline unsigned char
-hw_to_bin(unsigned char c)
-{
- if (rtc_dm_binary())
- return c;
- else
- return (c>>4)*10 + (c &0xf);
-}
-
-/* 0x80 bit indicates pm in 12-hour format */
-static inline unsigned char
-hour_bin_to_hw(unsigned char c)
-{
- if (rtc_24h())
- return bin_to_hw(c);
- if (c >= 12)
- return 0x80 | bin_to_hw((c==12)?12:c-12); /* 12 is 12pm */
- else
- return bin_to_hw((c==0)?12:c); /* 0 is 12 AM, not 0 am */
-}
-
-static inline unsigned char
-hour_hw_to_bin(unsigned char c)
-{
- unsigned char tmp = hw_to_bin(c&0x3f);
- if (rtc_24h())
- return tmp;
- if (c & 0x80)
- return (tmp==12)?12:tmp+12; /* 12pm is 12, not 24 */
- else
- return (tmp==12)?0:tmp; /* 12am is 0 */
-}
-
-static unsigned long r4k_offset; /* Amount to increment compare reg each time */
-static unsigned long r4k_cur; /* What counter should be at next timer irq */
-extern unsigned int mips_hpt_frequency;
-
-/*
- * Figure out the r4k offset, the amount to increment the compare
- * register for each time tick.
- * Use the RTC to calculate offset.
- */
-static unsigned long __init cal_r4koff(void)
-{
- unsigned int flags;
-
- local_irq_save(flags);
-
- /* Start counter exactly on falling edge of update flag */
- while (CMOS_READ(RTC_REG_A) & RTC_UIP);
- while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
-
- /* Start r4k counter. */
- write_c0_count(0);
-
- /* Read counter exactly on falling edge of update flag */
- while (CMOS_READ(RTC_REG_A) & RTC_UIP);
- while (!(CMOS_READ(RTC_REG_A) & RTC_UIP));
-
- mips_hpt_frequency = read_c0_count();
-
- /* restore interrupts */
- local_irq_restore(flags);
-
- return (mips_hpt_frequency / HZ);
-}
-
-static unsigned long
-it8172_rtc_get_time(void)
-{
- unsigned int year, mon, day, hour, min, sec;
- unsigned int flags;
-
- /* avoid update-in-progress. */
- for (;;) {
- local_irq_save(flags);
- if (! (CMOS_READ(RTC_REG_A) & RTC_UIP))
- break;
- /* don't hold intr closed all the time */
- local_irq_restore(flags);
- }
-
- /* Read regs. */
- sec = hw_to_bin(CMOS_READ(RTC_SECONDS));
- min = hw_to_bin(CMOS_READ(RTC_MINUTES));
- hour = hour_hw_to_bin(CMOS_READ(RTC_HOURS));
- day = hw_to_bin(CMOS_READ(RTC_DAY_OF_MONTH));
- mon = hw_to_bin(CMOS_READ(RTC_MONTH));
- year = hw_to_bin(CMOS_READ(RTC_YEAR)) +
- hw_to_bin(*rtc_century_reg) * 100;
-
- /* restore interrupts */
- local_irq_restore(flags);
-
- return mktime(year, mon, day, hour, min, sec);
-}
-
-static int
-it8172_rtc_set_time(unsigned long t)
-{
- struct rtc_time tm;
- unsigned int flags;
-
- /* convert */
- to_tm(t, &tm);
-
- /* avoid update-in-progress. */
- for (;;) {
- local_irq_save(flags);
- if (! (CMOS_READ(RTC_REG_A) & RTC_UIP))
- break;
- /* don't hold intr closed all the time */
- local_irq_restore(flags);
- }
-
- *rtc_century_reg = bin_to_hw(tm.tm_year/100);
- CMOS_WRITE(bin_to_hw(tm.tm_sec), RTC_SECONDS);
- CMOS_WRITE(bin_to_hw(tm.tm_min), RTC_MINUTES);
- CMOS_WRITE(hour_bin_to_hw(tm.tm_hour), RTC_HOURS);
- CMOS_WRITE(bin_to_hw(tm.tm_mday), RTC_DAY_OF_MONTH);
- CMOS_WRITE(bin_to_hw(tm.tm_mon+1), RTC_MONTH); /* tm_mon starts from 0 */
- CMOS_WRITE(bin_to_hw(tm.tm_year%100), RTC_YEAR);
-
- /* restore interrupts */
- local_irq_restore(flags);
-
- return 0;
-}
-
-void __init it8172_time_init(void)
-{
- unsigned int est_freq, flags;
-
- local_irq_save(flags);
-
- saved_control = CMOS_READ(RTC_CONTROL);
-
- printk("calculating r4koff... ");
- r4k_offset = cal_r4koff();
- printk("%08lx(%d)\n", r4k_offset, (int) r4k_offset);
-
- est_freq = 2*r4k_offset*HZ;
- est_freq += 5000; /* round */
- est_freq -= est_freq%10000;
- printk("CPU frequency %d.%02d MHz\n", est_freq/1000000,
- (est_freq%1000000)*100/1000000);
-
- local_irq_restore(flags);
-
- rtc_mips_get_time = it8172_rtc_get_time;
- rtc_mips_set_time = it8172_rtc_set_time;
-}
-
-#define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
-
-void __init plat_timer_setup(struct irqaction *irq)
-{
- puts("timer_setup\n");
- put32(NR_IRQS);
- puts("");
- /* we are using the cpu counter for timer interrupts */
- setup_irq(MIPS_CPU_TIMER_IRQ, irq);
-
- /* to generate the first timer interrupt */
- r4k_cur = (read_c0_count() + r4k_offset);
- write_c0_compare(r4k_cur);
- set_c0_status(ALLINTS);
-}
diff --git a/arch/mips/ite-boards/ivr/Makefile b/arch/mips/ite-boards/ivr/Makefile
deleted file mode 100644
index e4fa6042b472..000000000000
--- a/arch/mips/ite-boards/ivr/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Copyright 2000 MontaVista Software Inc.
-# Author: MontaVista Software, Inc.
-# ppopov@mvista.com or source@mvista.com
-#
-# Makefile for the Globespan IVR board,
-# board-specific files.
-#
-
-obj-y += init.o
diff --git a/arch/mips/ite-boards/ivr/README b/arch/mips/ite-boards/ivr/README
deleted file mode 100644
index aa7d8db855bb..000000000000
--- a/arch/mips/ite-boards/ivr/README
+++ /dev/null
@@ -1,3 +0,0 @@
-This is not really a board made by ITE Semi, but it's very
-similar to the ITE QED-4N-S01B board. The IVR board is made
-by Globespan and it's a reference board for the PVR chip.
diff --git a/arch/mips/ite-boards/ivr/init.c b/arch/mips/ite-boards/ivr/init.c
deleted file mode 100644
index 05cf9218c432..000000000000
--- a/arch/mips/ite-boards/ivr/init.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * IVR board setup.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <asm/sections.h>
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_dbg.h>
-
-int prom_argc;
-char **prom_argv, **prom_envp;
-
-extern void __init prom_init_cmdline(void);
-extern unsigned long __init prom_get_memsize(void);
-extern void __init it8172_init_ram_resource(unsigned long memsize);
-
-const char *get_system_type(void)
-{
- return "Globespan IVR";
-}
-
-void __init prom_init(void)
-{
- unsigned long mem_size;
- unsigned long pcicr;
-
- prom_argc = fw_arg0;
- prom_argv = (char **) fw_arg1;
- prom_envp = (int *) fw_arg3;
-
- mips_machgroup = MACH_GROUP_GLOBESPAN;
- mips_machtype = MACH_IVR; /* Globespan's iTVC15 reference board */
-
- prom_init_cmdline();
-
- /* pmon does not set memsize */
- mem_size = prom_get_memsize();
- mem_size = mem_size << 20;
-
- /*
- * make the entire physical memory visible to pci bus masters
- */
- IT_READ(IT_MC_PCICR, pcicr);
- pcicr &= ~0x1f;
- pcicr |= (mem_size - 1) >> 22;
- IT_WRITE(IT_MC_PCICR, pcicr);
-
- it8172_init_ram_resource(mem_size);
- add_memory_region(0, mem_size, BOOT_MEM_RAM);
-}
diff --git a/arch/mips/ite-boards/qed-4n-s01b/Makefile b/arch/mips/ite-boards/qed-4n-s01b/Makefile
deleted file mode 100644
index bb9972ad9c45..000000000000
--- a/arch/mips/ite-boards/qed-4n-s01b/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Copyright 2000 MontaVista Software Inc.
-# Author: MontaVista Software, Inc.
-# ppopov@mvista.com or source@mvista.com
-#
-# Makefile for the ITE 8172 (qed-4n-s01b) board, board
-# specific files.
-#
-
-obj-y := init.o
diff --git a/arch/mips/ite-boards/qed-4n-s01b/README b/arch/mips/ite-boards/qed-4n-s01b/README
deleted file mode 100644
index fb4b5197e800..000000000000
--- a/arch/mips/ite-boards/qed-4n-s01b/README
+++ /dev/null
@@ -1,2 +0,0 @@
-This is an ITE (www.iteusa.com) eval board for the ITE 8172G
-system controller, with a QED 5231 CPU.
diff --git a/arch/mips/ite-boards/qed-4n-s01b/init.c b/arch/mips/ite-boards/qed-4n-s01b/init.c
deleted file mode 100644
index ea2a754cafe5..000000000000
--- a/arch/mips/ite-boards/qed-4n-s01b/init.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * IT8172/QED5231 board setup.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/bootmem.h>
-#include <asm/addrspace.h>
-#include <asm/bootinfo.h>
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <asm/sections.h>
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_dbg.h>
-
-int prom_argc;
-char **prom_argv, **prom_envp;
-
-extern void __init prom_init_cmdline(void);
-extern unsigned long __init prom_get_memsize(void);
-extern void __init it8172_init_ram_resource(unsigned long memsize);
-
-const char *get_system_type(void)
-{
- return "ITE QED-4N-S01B";
-}
-
-void __init prom_init(void)
-{
- unsigned long mem_size;
- unsigned long pcicr;
-
- prom_argc = fw_arg0;
- prom_argv = (char **) fw_arg1;
- prom_envp = (int *) fw_arg3;
-
- mips_machgroup = MACH_GROUP_ITE;
- mips_machtype = MACH_QED_4N_S01B; /* ITE board name/number */
-
- prom_init_cmdline();
- mem_size = prom_get_memsize();
-
- printk("Memory size: %dMB\n", (unsigned)mem_size);
-
- mem_size <<= 20; /* MB */
-
- /*
- * make the entire physical memory visible to pci bus masters
- */
- IT_READ(IT_MC_PCICR, pcicr);
- pcicr &= ~0x1f;
- pcicr |= (mem_size - 1) >> 22;
- IT_WRITE(IT_MC_PCICR, pcicr);
-
- it8172_init_ram_resource(mem_size);
- add_memory_region(0, mem_size, BOOT_MEM_RAM);
-}
diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c
index eef05093deb4..d5bd6b3a0933 100644
--- a/arch/mips/jazz/irq.c
+++ b/arch/mips/jazz/irq.c
@@ -94,26 +94,26 @@ void __init arch_init_irq(void)
change_c0_status(ST0_IM, IE_IRQ4 | IE_IRQ3 | IE_IRQ2 | IE_IRQ1);
}
-static void loc_call(unsigned int irq, struct pt_regs *regs, unsigned int mask)
+static void loc_call(unsigned int irq, unsigned int mask)
{
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) & mask);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
r4030_write_reg16(JAZZ_IO_IRQ_ENABLE,
r4030_read_reg16(JAZZ_IO_IRQ_ENABLE) | mask);
}
-static void ll_local_dev(struct pt_regs *regs)
+static void ll_local_dev(void)
{
switch (r4030_read_reg32(JAZZ_IO_IRQ_SOURCE)) {
case 0:
panic("Unimplemented loc_no_irq handler");
break;
case 4:
- loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_PARALLEL);
+ loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_PARALLEL);
break;
case 8:
- loc_call(JAZZ_PARALLEL_IRQ, regs, JAZZ_IE_FLOPPY);
+ loc_call(JAZZ_PARALLEL_IRQ, JAZZ_IE_FLOPPY);
break;
case 12:
panic("Unimplemented loc_sound handler");
@@ -122,27 +122,27 @@ static void ll_local_dev(struct pt_regs *regs)
panic("Unimplemented loc_video handler");
break;
case 20:
- loc_call(JAZZ_ETHERNET_IRQ, regs, JAZZ_IE_ETHERNET);
+ loc_call(JAZZ_ETHERNET_IRQ, JAZZ_IE_ETHERNET);
break;
case 24:
- loc_call(JAZZ_SCSI_IRQ, regs, JAZZ_IE_SCSI);
+ loc_call(JAZZ_SCSI_IRQ, JAZZ_IE_SCSI);
break;
case 28:
- loc_call(JAZZ_KEYBOARD_IRQ, regs, JAZZ_IE_KEYBOARD);
+ loc_call(JAZZ_KEYBOARD_IRQ, JAZZ_IE_KEYBOARD);
break;
case 32:
- loc_call(JAZZ_MOUSE_IRQ, regs, JAZZ_IE_MOUSE);
+ loc_call(JAZZ_MOUSE_IRQ, JAZZ_IE_MOUSE);
break;
case 36:
- loc_call(JAZZ_SERIAL1_IRQ, regs, JAZZ_IE_SERIAL1);
+ loc_call(JAZZ_SERIAL1_IRQ, JAZZ_IE_SERIAL1);
break;
case 40:
- loc_call(JAZZ_SERIAL2_IRQ, regs, JAZZ_IE_SERIAL2);
+ loc_call(JAZZ_SERIAL2_IRQ, JAZZ_IE_SERIAL2);
break;
}
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
@@ -150,13 +150,13 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
write_c0_compare(0);
else if (pending & IE_IRQ4) {
r4030_read_reg32(JAZZ_TIMER_REGISTER);
- do_IRQ(JAZZ_TIMER_IRQ, regs);
+ do_IRQ(JAZZ_TIMER_IRQ);
} else if (pending & IE_IRQ3)
panic("Unimplemented ISA NMI handler");
else if (pending & IE_IRQ2)
- do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK), regs);
+ do_IRQ(r4030_read_reg32(JAZZ_EISA_IRQ_ACK));
else if (pending & IE_IRQ1) {
- ll_local_dev(regs);
+ ll_local_dev();
} else if (unlikely(pending & IE_IRQ0))
panic("Unimplemented local_dma handler");
else if (pending & IE_SW1) {
diff --git a/arch/mips/jazz/setup.c b/arch/mips/jazz/setup.c
index 487a9ea1ef00..d848f1a07786 100644
--- a/arch/mips/jazz/setup.c
+++ b/arch/mips/jazz/setup.c
@@ -19,12 +19,12 @@
#include <linux/fb.h>
#include <linux/ide.h>
#include <linux/pm.h>
+#include <linux/screen_info.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
#include <asm/jazz.h>
#include <asm/jazzdma.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/io.h>
#include <asm/pgtable.h>
@@ -37,7 +37,7 @@ extern void jazz_machine_restart(char *command);
extern void jazz_machine_halt(void);
extern void jazz_machine_power_off(void);
-void __init plat_time_init(struct irqaction *irq)
+void __init plat_timer_setup(struct irqaction *irq)
{
/* set the clock to 100 Hz */
r4030_write_reg32(JAZZ_TIMER_INTERVAL, 9);
@@ -45,10 +45,27 @@ void __init plat_time_init(struct irqaction *irq)
}
static struct resource jazz_io_resources[] = {
- { "dma1", 0x00, 0x1f, IORESOURCE_BUSY },
- { "timer", 0x40, 0x5f, IORESOURCE_BUSY },
- { "dma page reg", 0x80, 0x8f, IORESOURCE_BUSY },
- { "dma2", 0xc0, 0xdf, IORESOURCE_BUSY },
+ {
+ .start = 0x00,
+ .end = 0x1f,
+ .name = "dma1",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0x40,
+ .end = 0x5f,
+ .name = "timer",
+ .end = IORESOURCE_BUSY
+ }, {
+ .start = 0x80,
+ .end = 0x8f,
+ .name = "dma page reg",
+ .flags = IORESOURCE_BUSY
+ }, {
+ .start = 0xc0,
+ .end = 0xdf,
+ .name = "dma2",
+ .flags = IORESOURCE_BUSY
+ }
};
void __init plat_mem_setup(void)
@@ -81,8 +98,6 @@ void __init plat_mem_setup(void)
_machine_halt = jazz_machine_halt;
pm_power_off = jazz_machine_power_off;
-#warning "Somebody should check if screen_info is ok for Jazz."
-
screen_info = (struct screen_info) {
0, 0, /* orig-x, orig-y */
0, /* unused */
diff --git a/arch/mips/jmr3927/rbhma3100/irq.c b/arch/mips/jmr3927/rbhma3100/irq.c
index 722174481467..39a0243bed9a 100644
--- a/arch/mips/jmr3927/rbhma3100/irq.c
+++ b/arch/mips/jmr3927/rbhma3100/irq.c
@@ -46,6 +46,7 @@
#include <linux/smp_lock.h>
#include <linux/bitops.h>
+#include <asm/irq_regs.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
@@ -239,45 +240,80 @@ struct tb_irq_space jmr3927_ioc_irqspace = {
.space_id = 0,
can_share : 1
};
+
struct tb_irq_space jmr3927_irc_irqspace = {
- .next = NULL,
- .start_irqno = JMR3927_IRQ_IRC,
- nr_irqs : JMR3927_NR_IRQ_IRC,
- .mask_func = mask_irq_irc,
- .unmask_func = unmask_irq_irc,
- .name = "on-chip",
- .space_id = 0,
- can_share : 0
+ .next = NULL,
+ .start_irqno = JMR3927_IRQ_IRC,
+ .nr_irqs = JMR3927_NR_IRQ_IRC,
+ .mask_func = mask_irq_irc,
+ .unmask_func = unmask_irq_irc,
+ .name = "on-chip",
+ .space_id = 0,
+ .can_share = 0
};
-void jmr3927_spurious(struct pt_regs *regs)
+
+#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
+static int tx_branch_likely_bug_count = 0;
+static int have_tx_branch_likely_bug = 0;
+
+static void tx_branch_likely_bug_fixup(void)
+{
+ struct pt_regs *regs = get_irq_regs();
+
+ /* TX39/49-BUG: Under this condition, the insn in delay slot
+ of the branch likely insn is executed (not nullified) even
+ the branch condition is false. */
+ if (!have_tx_branch_likely_bug)
+ return;
+ if ((regs->cp0_epc & 0xfff) == 0xffc &&
+ KSEGX(regs->cp0_epc) != KSEG0 &&
+ KSEGX(regs->cp0_epc) != KSEG1) {
+ unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4);
+ /* beql,bnel,blezl,bgtzl */
+ /* bltzl,bgezl,blezall,bgezall */
+ /* bczfl, bcztl */
+ if ((insn & 0xf0000000) == 0x50000000 ||
+ (insn & 0xfc0e0000) == 0x04020000 ||
+ (insn & 0xf3fe0000) == 0x41020000) {
+ regs->cp0_epc -= 4;
+ tx_branch_likely_bug_count++;
+ printk(KERN_INFO
+ "fix branch-likery bug in %s (insn %08x)\n",
+ current->comm, insn);
+ }
+ }
+}
+#endif
+
+static void jmr3927_spurious(void)
{
#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
- tx_branch_likely_bug_fixup(regs);
+ tx_branch_likely_bug_fixup();
#endif
printk(KERN_WARNING "spurious interrupt (cause 0x%lx, pc 0x%lx, ra 0x%lx).\n",
regs->cp0_cause, regs->cp0_epc, regs->regs[31]);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
int irq;
#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
- tx_branch_likely_bug_fixup(regs);
+ tx_branch_likely_bug_fixup();
#endif
if ((regs->cp0_cause & CAUSEF_IP7) == 0) {
#if 0
- jmr3927_spurious(regs);
+ jmr3927_spurious();
#endif
return;
}
irq = (regs->cp0_cause >> CAUSEB_IP2) & 0x0f;
- do_IRQ(irq + JMR3927_IRQ_IRC, regs);
+ do_IRQ(irq + JMR3927_IRQ_IRC);
}
-static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id)
{
unsigned char istat = jmr3927_ioc_reg_in(JMR3927_IOC_INTS2_ADDR);
int i;
@@ -285,7 +321,7 @@ static irqreturn_t jmr3927_ioc_interrupt(int irq, void *dev_id, struct pt_regs *
for (i = 0; i < JMR3927_NR_IRQ_IOC; i++) {
if (istat & (1 << i)) {
irq = JMR3927_IRQ_IOC + i;
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
}
return IRQ_HANDLED;
@@ -295,7 +331,7 @@ static struct irqaction ioc_action = {
jmr3927_ioc_interrupt, 0, CPU_MASK_NONE, "IOC", NULL, NULL,
};
-static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id)
{
unsigned char istat = jmr3927_isac_reg_in(JMR3927_ISAC_INTS2_ADDR);
int i;
@@ -303,7 +339,7 @@ static irqreturn_t jmr3927_isac_interrupt(int irq, void *dev_id, struct pt_regs
for (i = 0; i < JMR3927_NR_IRQ_ISAC; i++) {
if (istat & (1 << i)) {
irq = JMR3927_IRQ_ISAC + i;
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
}
return IRQ_HANDLED;
@@ -314,7 +350,7 @@ static struct irqaction isac_action = {
};
-static irqreturn_t jmr3927_isaerr_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+static irqreturn_t jmr3927_isaerr_interrupt(int irq, void *dev_id)
{
printk(KERN_WARNING "ISA error interrupt (irq 0x%x).\n", irq);
@@ -324,7 +360,7 @@ static struct irqaction isaerr_action = {
jmr3927_isaerr_interrupt, 0, CPU_MASK_NONE, "ISA error", NULL, NULL,
};
-static irqreturn_t jmr3927_pcierr_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id)
{
printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq);
printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n",
@@ -439,33 +475,3 @@ void jmr3927_irq_init(u32 irq_base)
jmr3927_irq_base = irq_base;
}
-
-#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
-static int tx_branch_likely_bug_count = 0;
-static int have_tx_branch_likely_bug = 0;
-void tx_branch_likely_bug_fixup(struct pt_regs *regs)
-{
- /* TX39/49-BUG: Under this condition, the insn in delay slot
- of the branch likely insn is executed (not nullified) even
- the branch condition is false. */
- if (!have_tx_branch_likely_bug)
- return;
- if ((regs->cp0_epc & 0xfff) == 0xffc &&
- KSEGX(regs->cp0_epc) != KSEG0 &&
- KSEGX(regs->cp0_epc) != KSEG1) {
- unsigned int insn = *(unsigned int*)(regs->cp0_epc - 4);
- /* beql,bnel,blezl,bgtzl */
- /* bltzl,bgezl,blezall,bgezall */
- /* bczfl, bcztl */
- if ((insn & 0xf0000000) == 0x50000000 ||
- (insn & 0xfc0e0000) == 0x04020000 ||
- (insn & 0xf3fe0000) == 0x41020000) {
- regs->cp0_epc -= 4;
- tx_branch_likely_bug_count++;
- printk(KERN_INFO
- "fix branch-likery bug in %s (insn %08x)\n",
- current->comm, insn);
- }
- }
-}
-#endif
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 881c467c6982..cd9cec9e39e9 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -11,6 +11,7 @@ obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \
irix5sys.o sysirix.o
+obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
obj-$(CONFIG_APM) += apm.o
diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c
index ec28077d5ee2..e9ce5b3721af 100644
--- a/arch/mips/kernel/asm-offsets.c
+++ b/arch/mips/kernel/asm-offsets.c
@@ -93,11 +93,12 @@ void output_thread_info_defines(void)
offset("#define TI_TASK ", struct thread_info, task);
offset("#define TI_EXEC_DOMAIN ", struct thread_info, exec_domain);
offset("#define TI_FLAGS ", struct thread_info, flags);
+ offset("#define TI_TP_VALUE ", struct thread_info, tp_value);
offset("#define TI_CPU ", struct thread_info, cpu);
offset("#define TI_PRE_COUNT ", struct thread_info, preempt_count);
offset("#define TI_ADDR_LIMIT ", struct thread_info, addr_limit);
offset("#define TI_RESTART_BLOCK ", struct thread_info, restart_block);
- offset("#define TI_TP_VALUE ", struct thread_info, tp_value);
+ offset("#define TI_REGS ", struct thread_info, regs);
constant("#define _THREAD_SIZE_ORDER ", THREAD_SIZE_ORDER);
constant("#define _THREAD_SIZE ", THREAD_SIZE);
constant("#define _THREAD_MASK ", THREAD_MASK);
diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c
index aa2caa67299a..8485af340ee1 100644
--- a/arch/mips/kernel/cpu-probe.c
+++ b/arch/mips/kernel/cpu-probe.c
@@ -38,15 +38,40 @@ static void r3081_wait(void)
static void r39xx_wait(void)
{
- unsigned long cfg = read_c0_conf();
- write_c0_conf(cfg | TX39_CONF_HALT);
+ local_irq_disable();
+ if (!need_resched())
+ write_c0_conf(read_c0_conf() | TX39_CONF_HALT);
+ local_irq_enable();
}
+/*
+ * There is a race when WAIT instruction executed with interrupt
+ * enabled.
+ * But it is implementation-dependent wheter the pipelie restarts when
+ * a non-enabled interrupt is requested.
+ */
static void r4k_wait(void)
{
- __asm__(".set\tmips3\n\t"
- "wait\n\t"
- ".set\tmips0");
+ __asm__(" .set mips3 \n"
+ " wait \n"
+ " .set mips0 \n");
+}
+
+/*
+ * This variant is preferable as it allows testing need_resched and going to
+ * sleep depending on the outcome atomically. Unfortunately the "It is
+ * implementation-dependent whether the pipeline restarts when a non-enabled
+ * interrupt is requested" restriction in the MIPS32/MIPS64 architecture makes
+ * using this version a gamble.
+ */
+static void r4k_wait_irqoff(void)
+{
+ local_irq_disable();
+ if (!need_resched())
+ __asm__(" .set mips3 \n"
+ " wait \n"
+ " .set mips0 \n");
+ local_irq_enable();
}
/* The Au1xxx wait is available only if using 32khz counter or
@@ -56,17 +81,17 @@ int allow_au1k_wait;
static void au1k_wait(void)
{
/* using the wait instruction makes CP0 counter unusable */
- __asm__(".set mips3\n\t"
- "cache 0x14, 0(%0)\n\t"
- "cache 0x14, 32(%0)\n\t"
- "sync\n\t"
- "nop\n\t"
- "wait\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- "nop\n\t"
- ".set mips0\n\t"
+ __asm__(" .set mips3 \n"
+ " cache 0x14, 0(%0) \n"
+ " cache 0x14, 32(%0) \n"
+ " sync \n"
+ " nop \n"
+ " wait \n"
+ " nop \n"
+ " nop \n"
+ " nop \n"
+ " nop \n"
+ " .set mips0 \n"
: : "r" (au1k_wait));
}
@@ -110,8 +135,6 @@ static inline void check_wait(void)
case CPU_R5000:
case CPU_NEVADA:
case CPU_RM7000:
- case CPU_RM9000:
- case CPU_TX49XX:
case CPU_4KC:
case CPU_4KEC:
case CPU_4KSC:
@@ -125,6 +148,10 @@ static inline void check_wait(void)
cpu_wait = r4k_wait;
printk(" available.\n");
break;
+ case CPU_TX49XX:
+ cpu_wait = r4k_wait_irqoff;
+ printk(" available.\n");
+ break;
case CPU_AU1000:
case CPU_AU1100:
case CPU_AU1500:
@@ -136,6 +163,14 @@ static inline void check_wait(void)
} else
printk(" unavailable.\n");
break;
+ case CPU_RM9000:
+ if ((c->processor_id & 0x00ff) >= 0x40) {
+ cpu_wait = r4k_wait;
+ printk(" available.\n");
+ } else {
+ printk(" unavailable.\n");
+ }
+ break;
default:
printk(" unavailable.\n");
break;
diff --git a/arch/mips/kernel/entry.S b/arch/mips/kernel/entry.S
index 766655f35250..417c08ac76eb 100644
--- a/arch/mips/kernel/entry.S
+++ b/arch/mips/kernel/entry.S
@@ -20,10 +20,7 @@
#include <asm/mipsmtregs.h>
#endif
-#ifdef CONFIG_PREEMPT
- .macro preempt_stop
- .endm
-#else
+#ifndef CONFIG_PREEMPT
.macro preempt_stop
local_irq_disable
.endm
@@ -32,9 +29,16 @@
.text
.align 5
+FEXPORT(ret_from_irq)
+ LONG_S s0, TI_REGS($28)
+#ifdef CONFIG_PREEMPT
+FEXPORT(ret_from_exception)
+#else
+ b _ret_from_irq
FEXPORT(ret_from_exception)
preempt_stop
-FEXPORT(ret_from_irq)
+#endif
+FEXPORT(_ret_from_irq)
LONG_L t0, PT_STATUS(sp) # returning to kernel mode?
andi t0, t0, KU_USER
beqz t0, resume_kernel
@@ -79,7 +83,6 @@ FEXPORT(syscall_exit)
FEXPORT(restore_all) # restore full frame
#ifdef CONFIG_MIPS_MT_SMTC
/* Detect and execute deferred IPI "interrupts" */
- move a0,sp
jal deferred_smtc_ipi
/* Re-arm any temporarily masked interrupts not explicitly "acked" */
mfc0 v0, CP0_TCSTATUS
diff --git a/arch/mips/kernel/genex.S b/arch/mips/kernel/genex.S
index 37fda3dcdfc5..5baca16993d0 100644
--- a/arch/mips/kernel/genex.S
+++ b/arch/mips/kernel/genex.S
@@ -131,8 +131,9 @@ NESTED(handle_int, PT_SIZE, sp)
CLI
TRACE_IRQS_OFF
+ LONG_L s0, TI_REGS($28)
+ LONG_S sp, TI_REGS($28)
PTR_LA ra, ret_from_irq
- move a0, sp
j plat_irq_dispatch
END(handle_int)
@@ -219,9 +220,11 @@ NESTED(except_vec_vi_handler, 0, sp)
#endif /* CONFIG_MIPS_MT_SMTC */
CLI
TRACE_IRQS_OFF
- move a0, sp
- jalr v0
- j ret_from_irq
+
+ LONG_L s0, TI_REGS($28)
+ LONG_S sp, TI_REGS($28)
+ PTR_LA ra, ret_from_irq
+ jr v0
END(except_vec_vi_handler)
/*
@@ -349,8 +352,8 @@ NESTED(nmi_handler, PT_SIZE, sp)
.set at
__BUILD_\verbose \exception
move a0, sp
- jal do_\handler
- j ret_from_exception
+ PTR_LA ra, ret_from_exception
+ j do_\handler
END(handle_\exception)
.endm
diff --git a/arch/mips/kernel/i8259.c b/arch/mips/kernel/i8259.c
index ea36c8e8852c..48e3418c217b 100644
--- a/arch/mips/kernel/i8259.c
+++ b/arch/mips/kernel/i8259.c
@@ -302,11 +302,11 @@ static struct irqaction irq2 = {
};
static struct resource pic1_io_resource = {
- .name = "pic1", .start = 0x20, .end = 0x3f, .flags = IORESOURCE_BUSY
+ .name = "pic1", .start = 0x20, .end = 0x21, .flags = IORESOURCE_BUSY
};
static struct resource pic2_io_resource = {
- .name = "pic2", .start = 0xa0, .end = 0xbf, .flags = IORESOURCE_BUSY
+ .name = "pic2", .start = 0xa0, .end = 0xa1, .flags = IORESOURCE_BUSY
};
/*
diff --git a/arch/mips/kernel/irixsig.c b/arch/mips/kernel/irixsig.c
index 676e868d26fb..2132485caa74 100644
--- a/arch/mips/kernel/irixsig.c
+++ b/arch/mips/kernel/irixsig.c
@@ -17,6 +17,7 @@
#include <asm/ptrace.h>
#include <asm/uaccess.h>
+#include <asm/unistd.h>
#undef DEBUG_SIG
@@ -172,11 +173,12 @@ static inline int handle_signal(unsigned long sig, siginfo_t *info,
return ret;
}
-asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
+void do_irix_signal(struct pt_regs *regs)
{
struct k_sigaction ka;
siginfo_t info;
int signr;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which is why we may in certain
@@ -184,19 +186,28 @@ asmlinkage int do_irix_signal(sigset_t *oldset, struct pt_regs *regs)
* if so.
*/
if (!user_mode(regs))
- return 1;
+ return;
- if (try_to_freeze())
- goto no_signal;
-
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
- if (signr > 0)
- return handle_signal(signr, &info, &ka, oldset, regs);
+ if (signr > 0) {
+ /* Whee! Actually deliver the signal. */
+ if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
+ /* 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;
+ }
-no_signal:
/*
* Who's code doesn't conform to the restartable syscall convention
* dies here!!! The li instruction, a single machine instruction,
@@ -208,8 +219,22 @@ no_signal:
regs->regs[2] == ERESTARTNOINTR) {
regs->cp0_epc -= 8;
}
+ if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
+ regs->regs[2] = __NR_restart_syscall;
+ regs->regs[7] = regs->regs[26];
+ regs->cp0_epc -= 4;
+ }
+ regs->regs[0] = 0; /* Don't deal with this again. */
+ }
+
+ /*
+ * 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);
}
- return 0;
}
asmlinkage void
@@ -298,6 +323,9 @@ struct sigact_irix5 {
int _unused0[2];
};
+#define SIG_SETMASK32 256 /* Goodie from SGI for BSD compatibility:
+ set only the low 32 bit of the sigset. */
+
#ifdef DEBUG_SIG
static inline void dump_sigact_irix5(struct sigact_irix5 *p)
{
@@ -413,7 +441,7 @@ asmlinkage int irix_sigprocmask(int how, irix_sigset_t __user *new,
asmlinkage int irix_sigsuspend(struct pt_regs *regs)
{
- sigset_t saveset, newset;
+ sigset_t newset;
sigset_t __user *uset;
uset = (sigset_t __user *) regs->regs[4];
@@ -422,18 +450,15 @@ asmlinkage int irix_sigsuspend(struct pt_regs *regs)
sigdelsetmask(&newset, ~_BLOCKABLE);
spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
current->blocked = newset;
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- regs->regs[2] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_irix_signal(&saveset, regs))
- return -EINTR;
- }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
}
/* hate hate hate... */
diff --git a/arch/mips/kernel/irq-msc01.c b/arch/mips/kernel/irq-msc01.c
index 63dfeb41796b..650a80ca3741 100644
--- a/arch/mips/kernel/irq-msc01.c
+++ b/arch/mips/kernel/irq-msc01.c
@@ -1,16 +1,17 @@
/*
- * Copyright (c) 2004 MIPS Inc
- * Author: chris@mips.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.
+ *
+ * Copyright (c) 2004 MIPS Inc
+ * Author: chris@mips.com
+ *
+ * Copyright (C) 2004, 06 Ralf Baechle <ralf@linux-mips.org>
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <asm/ptrace.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <asm/io.h>
@@ -115,14 +116,14 @@ static void end_msc_irq(unsigned int irq)
/*
* Interrupt handler for interrupts coming from SOC-it.
*/
-void ll_msc_irq(struct pt_regs *regs)
+void ll_msc_irq(void)
{
unsigned int irq;
/* read the interrupt vector register */
MSCIC_READ(MSC01_IC_VEC, irq);
if (irq < 64)
- do_IRQ(irq + irq_base, regs);
+ do_IRQ(irq + irq_base);
else {
/* Ignore spurious interrupt */
}
diff --git a/arch/mips/kernel/irq-mv6434x.c b/arch/mips/kernel/irq-mv6434x.c
index b117e64da64d..37d106202b83 100644
--- a/arch/mips/kernel/irq-mv6434x.c
+++ b/arch/mips/kernel/irq-mv6434x.c
@@ -1,7 +1,7 @@
/*
* Copyright 2002 Momentum Computer
* Author: mdharm@momenco.com
- * Copyright (C) 2004 Ralf Baechle <ralf@linux-mips.org>
+ * Copyright (C) 2004, 06 Ralf Baechle <ralf@linux-mips.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
@@ -15,7 +15,6 @@
#include <linux/mv643xx.h>
#include <linux/sched.h>
-#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/marvell.h>
@@ -113,7 +112,7 @@ static void end_mv64340_irq(unsigned int irq)
* Interrupt handler for interrupts coming from the Marvell chip.
* It could be built in ethernet ports etc...
*/
-void ll_mv64340_irq(struct pt_regs *regs)
+void ll_mv64340_irq(void)
{
unsigned int irq_src_low, irq_src_high;
unsigned int irq_mask_low, irq_mask_high;
@@ -129,9 +128,9 @@ void ll_mv64340_irq(struct pt_regs *regs)
irq_src_high &= irq_mask_high;
if (irq_src_low)
- do_IRQ(ls1bit32(irq_src_low) + irq_base, regs);
+ do_IRQ(ls1bit32(irq_src_low) + irq_base);
else
- do_IRQ(ls1bit32(irq_src_high) + irq_base + 32, regs);
+ do_IRQ(ls1bit32(irq_src_high) + irq_base + 32);
}
#define shutdown_mv64340_irq disable_mv64340_irq
diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c
index d955aaefbb8e..dd24434392b6 100644
--- a/arch/mips/kernel/irq.c
+++ b/arch/mips/kernel/irq.c
@@ -53,12 +53,12 @@ unsigned long irq_hwmask[NR_IRQS];
* SMP cross-CPU interrupts have their own specific
* handlers).
*/
-asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs)
+asmlinkage unsigned int do_IRQ(unsigned int irq)
{
irq_enter();
__DO_IRQ_SMTC_HOOK();
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
irq_exit();
@@ -110,7 +110,7 @@ skip:
return 0;
}
-asmlinkage void spurious_interrupt(struct pt_regs *regs)
+asmlinkage void spurious_interrupt(void)
{
atomic_inc(&irq_err_count);
}
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 450ac592da57..7a3ebbeba1f3 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -77,6 +77,8 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
memset(&tmp, 0, sizeof(tmp));
tmp.st_dev = new_encode_dev(stat->dev);
tmp.st_ino = stat->ino;
+ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
+ return -EOVERFLOW;
tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
SET_UID(tmp.st_uid, stat->uid);
@@ -991,7 +993,7 @@ struct sysctl_args32
unsigned int __unused[4];
};
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL_SYSCALL
asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args)
{
@@ -1032,14 +1034,14 @@ asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args)
return error;
}
-#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_SYSCTL_SYSCALL */
asmlinkage long sys32_newuname(struct new_utsname __user * name)
{
int ret = 0;
down_read(&uts_sem);
- if (copy_to_user(name,&system_utsname,sizeof *name))
+ if (copy_to_user(name, utsname(), sizeof *name))
ret = -EFAULT;
up_read(&uts_sem);
@@ -1053,7 +1055,9 @@ asmlinkage long sys32_newuname(struct new_utsname __user * name)
asmlinkage int sys32_personality(unsigned long personality)
{
int ret;
- if (current->personality == PER_LINUX32 && personality == PER_LINUX)
+ personality &= 0xffffffff;
+ if (personality(current->personality) == PER_LINUX32 &&
+ personality == PER_LINUX)
personality = PER_LINUX32;
ret = sys_personality(personality);
if (ret == PER_LINUX32)
@@ -1296,9 +1300,3 @@ _sys32_clone(nabi_no_regargs struct pt_regs regs)
return do_fork(clone_flags, newsp, &regs, 0,
parent_tidptr, child_tidptr);
}
-
-extern asmlinkage void sys_set_thread_area(u32 addr);
-asmlinkage void sys32_set_thread_area(u32 addr)
-{
- sys_set_thread_area(AA(addr));
-}
diff --git a/arch/mips/kernel/proc.c b/arch/mips/kernel/proc.c
index d8beef107902..4ed37ba19731 100644
--- a/arch/mips/kernel/proc.c
+++ b/arch/mips/kernel/proc.c
@@ -89,9 +89,9 @@ static const char *cpu_name[] = {
static int show_cpuinfo(struct seq_file *m, void *v)
{
- unsigned int version = current_cpu_data.processor_id;
- unsigned int fp_vers = current_cpu_data.fpu_id;
unsigned long n = (unsigned long) v - 1;
+ unsigned int version = cpu_data[n].processor_id;
+ unsigned int fp_vers = cpu_data[n].fpu_id;
char fmt [64];
#ifdef CONFIG_SMP
@@ -107,9 +107,9 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "processor\t\t: %ld\n", n);
sprintf(fmt, "cpu model\t\t: %%s V%%d.%%d%s\n",
- cpu_has_fpu ? " FPU V%d.%d" : "");
- seq_printf(m, fmt, cpu_name[current_cpu_data.cputype <= CPU_LAST ?
- current_cpu_data.cputype : CPU_UNKNOWN],
+ cpu_data[n].options & MIPS_CPU_FPU ? " FPU V%d.%d" : "");
+ seq_printf(m, fmt, cpu_name[cpu_data[n].cputype <= CPU_LAST ?
+ cpu_data[n].cputype : CPU_UNKNOWN],
(version >> 4) & 0x0f, version & 0x0f,
(fp_vers >> 4) & 0x0f, fp_vers & 0x0f);
seq_printf(m, "BogoMIPS\t\t: %lu.%02lu\n",
@@ -118,7 +118,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "wait instruction\t: %s\n", cpu_wait ? "yes" : "no");
seq_printf(m, "microsecond timers\t: %s\n",
cpu_has_counter ? "yes" : "no");
- seq_printf(m, "tlb_entries\t\t: %d\n", current_cpu_data.tlbsize);
+ seq_printf(m, "tlb_entries\t\t: %d\n", cpu_data[n].tlbsize);
seq_printf(m, "extra interrupt vector\t: %s\n",
cpu_has_divec ? "yes" : "no");
seq_printf(m, "hardware watchpoint\t: %s\n",
diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c
index 7ab67f786bfe..ec8209f3a0c6 100644
--- a/arch/mips/kernel/process.c
+++ b/arch/mips/kernel/process.c
@@ -40,6 +40,7 @@
#include <asm/elf.h>
#include <asm/isadep.h>
#include <asm/inst.h>
+#include <asm/stacktrace.h>
#ifdef CONFIG_MIPS_MT_SMTC
#include <asm/mipsmtregs.h>
extern void smtc_idle_loop_hook(void);
@@ -114,7 +115,7 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
status |= KU_USER;
regs->cp0_status = status;
clear_used_math();
- lose_fpu();
+ clear_fpu_owner();
if (cpu_has_dsp)
__init_dsp();
regs->cp0_epc = pc;
@@ -273,104 +274,105 @@ long kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}
-static struct mips_frame_info {
- void *func;
- unsigned long func_size;
- int frame_size;
- int pc_offset;
-} *schedule_frame, mfinfo[64];
-static int mfinfo_num;
+/*
+ *
+ */
+struct mips_frame_info {
+ void *func;
+ unsigned long func_size;
+ int frame_size;
+ int pc_offset;
+};
-static int __init get_frame_info(struct mips_frame_info *info)
+static inline int is_ra_save_ins(union mips_instruction *ip)
{
- int i;
- void *func = info->func;
- union mips_instruction *ip = (union mips_instruction *)func;
+ /* sw / sd $ra, offset($sp) */
+ return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
+ ip->i_format.rs == 29 &&
+ ip->i_format.rt == 31;
+}
+
+static inline int is_jal_jalr_jr_ins(union mips_instruction *ip)
+{
+ if (ip->j_format.opcode == jal_op)
+ return 1;
+ if (ip->r_format.opcode != spec_op)
+ return 0;
+ return ip->r_format.func == jalr_op || ip->r_format.func == jr_op;
+}
+
+static inline int is_sp_move_ins(union mips_instruction *ip)
+{
+ /* addiu/daddiu sp,sp,-imm */
+ if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
+ return 0;
+ if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
+ return 1;
+ return 0;
+}
+
+static int get_frame_info(struct mips_frame_info *info)
+{
+ union mips_instruction *ip = info->func;
+ unsigned max_insns = info->func_size / sizeof(union mips_instruction);
+ unsigned i;
+
info->pc_offset = -1;
info->frame_size = 0;
- for (i = 0; i < 128; i++, ip++) {
- /* if jal, jalr, jr, stop. */
- if (ip->j_format.opcode == jal_op ||
- (ip->r_format.opcode == spec_op &&
- (ip->r_format.func == jalr_op ||
- ip->r_format.func == jr_op)))
- break;
- if (info->func_size && i >= info->func_size / 4)
+ if (!ip)
+ goto err;
+
+ if (max_insns == 0)
+ max_insns = 128U; /* unknown function size */
+ max_insns = min(128U, max_insns);
+
+ for (i = 0; i < max_insns; i++, ip++) {
+
+ if (is_jal_jalr_jr_ins(ip))
break;
- if (
-#ifdef CONFIG_32BIT
- ip->i_format.opcode == addiu_op &&
-#endif
-#ifdef CONFIG_64BIT
- ip->i_format.opcode == daddiu_op &&
-#endif
- ip->i_format.rs == 29 &&
- ip->i_format.rt == 29) {
- /* addiu/daddiu sp,sp,-imm */
- if (info->frame_size)
- continue;
- info->frame_size = - ip->i_format.simmediate;
+ if (!info->frame_size) {
+ if (is_sp_move_ins(ip))
+ info->frame_size = - ip->i_format.simmediate;
+ continue;
}
-
- if (
-#ifdef CONFIG_32BIT
- ip->i_format.opcode == sw_op &&
-#endif
-#ifdef CONFIG_64BIT
- ip->i_format.opcode == sd_op &&
-#endif
- ip->i_format.rs == 29 &&
- ip->i_format.rt == 31) {
- /* sw / sd $ra, offset($sp) */
- if (info->pc_offset != -1)
- continue;
+ if (info->pc_offset == -1 && is_ra_save_ins(ip)) {
info->pc_offset =
ip->i_format.simmediate / sizeof(long);
+ break;
}
}
- if (info->pc_offset == -1 || info->frame_size == 0) {
- if (func == schedule)
- printk("Can't analyze prologue code at %p\n", func);
- info->pc_offset = -1;
- info->frame_size = 0;
- }
-
- return 0;
+ if (info->frame_size && info->pc_offset >= 0) /* nested */
+ return 0;
+ if (info->pc_offset < 0) /* leaf */
+ return 1;
+ /* prologue seems boggus... */
+err:
+ return -1;
}
+static struct mips_frame_info schedule_mfi __read_mostly;
+
static int __init frame_info_init(void)
{
- int i;
+ unsigned long size = 0;
#ifdef CONFIG_KALLSYMS
- char *modname;
- char namebuf[KSYM_NAME_LEN + 1];
- unsigned long start, size, ofs;
- extern char __sched_text_start[], __sched_text_end[];
- extern char __lock_text_start[], __lock_text_end[];
-
- start = (unsigned long)__sched_text_start;
- for (i = 0; i < ARRAY_SIZE(mfinfo); i++) {
- if (start == (unsigned long)schedule)
- schedule_frame = &mfinfo[i];
- if (!kallsyms_lookup(start, &size, &ofs, &modname, namebuf))
- break;
- mfinfo[i].func = (void *)(start + ofs);
- mfinfo[i].func_size = size;
- start += size - ofs;
- if (start >= (unsigned long)__lock_text_end)
- break;
- if (start == (unsigned long)__sched_text_end)
- start = (unsigned long)__lock_text_start;
- }
-#else
- mfinfo[0].func = schedule;
- schedule_frame = &mfinfo[0];
+ unsigned long ofs;
+
+ kallsyms_lookup_size_offset((unsigned long)schedule, &size, &ofs);
#endif
- for (i = 0; i < ARRAY_SIZE(mfinfo) && mfinfo[i].func; i++)
- get_frame_info(&mfinfo[i]);
+ schedule_mfi.func = schedule;
+ schedule_mfi.func_size = size;
+
+ get_frame_info(&schedule_mfi);
+
+ /*
+ * Without schedule() frame info, result given by
+ * thread_saved_pc() and get_wchan() are not reliable.
+ */
+ if (schedule_mfi.pc_offset < 0)
+ printk("Can't analyze schedule() prologue at %p\n", schedule);
- mfinfo_num = i;
return 0;
}
@@ -386,54 +388,110 @@ unsigned long thread_saved_pc(struct task_struct *tsk)
/* New born processes are a special case */
if (t->reg31 == (unsigned long) ret_from_fork)
return t->reg31;
-
- if (!schedule_frame || schedule_frame->pc_offset < 0)
+ if (schedule_mfi.pc_offset < 0)
return 0;
- return ((unsigned long *)t->reg29)[schedule_frame->pc_offset];
+ return ((unsigned long *)t->reg29)[schedule_mfi.pc_offset];
}
-/* get_wchan - a maintenance nightmare^W^Wpain in the ass ... */
-unsigned long get_wchan(struct task_struct *p)
+
+#ifdef CONFIG_KALLSYMS
+/* used by show_backtrace() */
+unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
+ unsigned long pc, unsigned long *ra)
{
unsigned long stack_page;
- unsigned long pc;
-#ifdef CONFIG_KALLSYMS
- unsigned long frame;
-#endif
+ struct mips_frame_info info;
+ unsigned long size, ofs;
+ int leaf;
+ extern void ret_from_irq(void);
+ extern void ret_from_exception(void);
+
+ stack_page = (unsigned long)task_stack_page(task);
+ if (!stack_page)
+ return 0;
- if (!p || p == current || p->state == TASK_RUNNING)
+ /*
+ * If we reached the bottom of interrupt context,
+ * return saved pc in pt_regs.
+ */
+ if (pc == (unsigned long)ret_from_irq ||
+ pc == (unsigned long)ret_from_exception) {
+ struct pt_regs *regs;
+ if (*sp >= stack_page &&
+ *sp + sizeof(*regs) <= stack_page + THREAD_SIZE - 32) {
+ regs = (struct pt_regs *)*sp;
+ pc = regs->cp0_epc;
+ if (__kernel_text_address(pc)) {
+ *sp = regs->regs[29];
+ *ra = regs->regs[31];
+ return pc;
+ }
+ }
+ return 0;
+ }
+ if (!kallsyms_lookup_size_offset(pc, &size, &ofs))
+ return 0;
+ /*
+ * Return ra if an exception occured at the first instruction
+ */
+ if (unlikely(ofs == 0)) {
+ pc = *ra;
+ *ra = 0;
+ return pc;
+ }
+
+ info.func = (void *)(pc - ofs);
+ info.func_size = ofs; /* analyze from start to ofs */
+ leaf = get_frame_info(&info);
+ if (leaf < 0)
return 0;
- stack_page = (unsigned long)task_stack_page(p);
- if (!stack_page || !mfinfo_num)
+ if (*sp < stack_page ||
+ *sp + info.frame_size > stack_page + THREAD_SIZE - 32)
return 0;
- pc = thread_saved_pc(p);
+ if (leaf)
+ /*
+ * For some extreme cases, get_frame_info() can
+ * consider wrongly a nested function as a leaf
+ * one. In that cases avoid to return always the
+ * same value.
+ */
+ pc = pc != *ra ? *ra : 0;
+ else
+ pc = ((unsigned long *)(*sp))[info.pc_offset];
+
+ *sp += info.frame_size;
+ *ra = 0;
+ return __kernel_text_address(pc) ? pc : 0;
+}
+#endif
+
+/*
+ * get_wchan - a maintenance nightmare^W^Wpain in the ass ...
+ */
+unsigned long get_wchan(struct task_struct *task)
+{
+ unsigned long pc = 0;
#ifdef CONFIG_KALLSYMS
- if (!in_sched_functions(pc))
- return pc;
+ unsigned long sp;
+ unsigned long ra = 0;
+#endif
- frame = p->thread.reg29 + schedule_frame->frame_size;
- do {
- int i;
+ if (!task || task == current || task->state == TASK_RUNNING)
+ goto out;
+ if (!task_stack_page(task))
+ goto out;
- if (frame < stack_page || frame > stack_page + THREAD_SIZE - 32)
- return 0;
+ pc = thread_saved_pc(task);
- for (i = mfinfo_num - 1; i >= 0; i--) {
- if (pc >= (unsigned long) mfinfo[i].func)
- break;
- }
- if (i < 0)
- break;
+#ifdef CONFIG_KALLSYMS
+ sp = task->thread.reg29 + schedule_mfi.frame_size;
- pc = ((unsigned long *)frame)[mfinfo[i].pc_offset];
- if (!mfinfo[i].frame_size)
- break;
- frame += mfinfo[i].frame_size;
- } while (in_sched_functions(pc));
+ while (in_sched_functions(pc))
+ pc = unwind_stack(task, &sp, pc, &ra);
#endif
+out:
return pc;
}
-
diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
index 362d1728e531..258d74fd0b63 100644
--- a/arch/mips/kernel/ptrace.c
+++ b/arch/mips/kernel/ptrace.c
@@ -106,6 +106,7 @@ int ptrace_setregs (struct task_struct *child, __s64 __user *data)
int ptrace_getfpregs (struct task_struct *child, __u32 __user *data)
{
int i;
+ unsigned int tmp;
if (!access_ok(VERIFY_WRITE, data, 33 * 8))
return -EIO;
@@ -121,10 +122,10 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data)
__put_user (child->thread.fpu.fcr31, data + 64);
+ preempt_disable();
if (cpu_has_fpu) {
- unsigned int flags, tmp;
+ unsigned int flags;
- preempt_disable();
if (cpu_has_mipsmt) {
unsigned int vpflags = dvpe();
flags = read_c0_status();
@@ -138,11 +139,11 @@ int ptrace_getfpregs (struct task_struct *child, __u32 __user *data)
__asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
write_c0_status(flags);
}
- preempt_enable();
- __put_user (tmp, data + 65);
} else {
- __put_user ((__u32) 0, data + 65);
+ tmp = 0;
}
+ preempt_enable();
+ __put_user (tmp, data + 65);
return 0;
}
@@ -245,16 +246,17 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
unsigned int mtflags;
#endif /* CONFIG_MIPS_MT_SMTC */
- if (!cpu_has_fpu)
+ preempt_disable();
+ if (!cpu_has_fpu) {
+ preempt_enable();
break;
+ }
#ifdef CONFIG_MIPS_MT_SMTC
/* Read-modify-write of Status must be atomic */
local_irq_save(irqflags);
mtflags = dmt();
#endif /* CONFIG_MIPS_MT_SMTC */
-
- preempt_disable();
if (cpu_has_mipsmt) {
unsigned int vpflags = dvpe();
flags = read_c0_status();
diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c
index f40ecd8be05f..d9a39c169450 100644
--- a/arch/mips/kernel/ptrace32.c
+++ b/arch/mips/kernel/ptrace32.c
@@ -175,7 +175,9 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
unsigned int mtflags;
#endif /* CONFIG_MIPS_MT_SMTC */
+ preempt_disable();
if (!cpu_has_fpu) {
+ preempt_enable();
tmp = 0;
break;
}
@@ -186,7 +188,6 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data)
mtflags = dmt();
#endif /* CONFIG_MIPS_MT_SMTC */
- preempt_disable();
if (cpu_has_mipsmt) {
unsigned int vpflags = dvpe();
flags = read_c0_status();
diff --git a/arch/mips/kernel/rtlx.c b/arch/mips/kernel/rtlx.c
index cdab1b2cd134..8c8c8324f775 100644
--- a/arch/mips/kernel/rtlx.c
+++ b/arch/mips/kernel/rtlx.c
@@ -61,16 +61,16 @@ static int sp_stopping = 0;
extern void *vpe_get_shared(int index);
-static void rtlx_dispatch(struct pt_regs *regs)
+static void rtlx_dispatch(void)
{
- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ, regs);
+ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ);
}
/* Interrupt handler may be called before rtlx_init has otherwise had
a chance to run.
*/
-static irqreturn_t rtlx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
{
int i;
diff --git a/arch/mips/kernel/scall32-o32.S b/arch/mips/kernel/scall32-o32.S
index ba1bcd83c7d3..720fac3435d5 100644
--- a/arch/mips/kernel/scall32-o32.S
+++ b/arch/mips/kernel/scall32-o32.S
@@ -28,18 +28,7 @@
NESTED(handle_sys, PT_SIZE, sp)
.set noat
SAVE_SOME
-#ifdef CONFIG_TRACE_IRQFLAGS
- TRACE_IRQS_ON
-#ifdef CONFIG_64BIT
- LONG_L $8, PT_R8(sp)
- LONG_L $9, PT_R9(sp)
-#endif
- LONG_L $7, PT_R7(sp)
- LONG_L $6, PT_R6(sp)
- LONG_L $5, PT_R5(sp)
- LONG_L $4, PT_R4(sp)
- LONG_L $2, PT_R2(sp)
-#endif
+ TRACE_IRQS_ON_RELOAD
STI
.set at
@@ -662,6 +651,9 @@ einval: li v0, -EINVAL
sys sys_tee 4
sys sys_vmsplice 4
sys sys_move_pages 6
+ sys sys_set_robust_list 2
+ sys sys_get_robust_list 3 /* 4310 */
+ sys sys_ni_syscall 0
.endm
/* We pre-compute the number of _instruction_ bytes needed to
diff --git a/arch/mips/kernel/scall64-64.S b/arch/mips/kernel/scall64-64.S
index 939e172db953..3a34f62c8b1b 100644
--- a/arch/mips/kernel/scall64-64.S
+++ b/arch/mips/kernel/scall64-64.S
@@ -34,7 +34,7 @@ NESTED(handle_sys64, PT_SIZE, sp)
*/
.set noat
SAVE_SOME
- TRACE_IRQS_ON
+ TRACE_IRQS_ON_RELOAD
STI
.set at
#endif
@@ -466,3 +466,6 @@ sys_call_table:
PTR sys_tee /* 5265 */
PTR sys_vmsplice
PTR sys_move_pages
+ PTR sys_set_robust_list
+ PTR sys_get_robust_list
+ PTR sys_ni_syscall /* 5270 */
diff --git a/arch/mips/kernel/scall64-n32.S b/arch/mips/kernel/scall64-n32.S
index 98abbc5a9f13..67b92a1d6c72 100644
--- a/arch/mips/kernel/scall64-n32.S
+++ b/arch/mips/kernel/scall64-n32.S
@@ -33,7 +33,7 @@ NESTED(handle_sysn32, PT_SIZE, sp)
#ifndef CONFIG_MIPS32_O32
.set noat
SAVE_SOME
- TRACE_IRQS_ON
+ TRACE_IRQS_ON_RELOAD
STI
.set at
#endif
@@ -247,7 +247,7 @@ EXPORT(sysn32_call_table)
PTR sys_capset
PTR sys32_rt_sigpending /* 6125 */
PTR compat_sys_rt_sigtimedwait
- PTR sys_rt_sigqueueinfo
+ PTR sys32_rt_sigqueueinfo
PTR sysn32_rt_sigsuspend
PTR sys32_sigaltstack
PTR compat_sys_utime /* 6130 */
@@ -280,7 +280,7 @@ EXPORT(sysn32_call_table)
PTR sys_sync
PTR sys_acct
PTR sys32_settimeofday
- PTR sys_mount /* 6160 */
+ PTR compat_sys_mount /* 6160 */
PTR sys_umount
PTR sys_swapon
PTR sys_swapoff
@@ -390,5 +390,8 @@ EXPORT(sysn32_call_table)
PTR sys_splice
PTR sys_sync_file_range
PTR sys_tee
- PTR sys_vmsplice /* 6271 */
+ PTR sys_vmsplice /* 6270 */
PTR sys_move_pages
+ PTR compat_sys_set_robust_list
+ PTR compat_sys_get_robust_list
+ PTR sys_ni_syscall
diff --git a/arch/mips/kernel/scall64-o32.S b/arch/mips/kernel/scall64-o32.S
index 505c9ee54009..2875c4a3fa58 100644
--- a/arch/mips/kernel/scall64-o32.S
+++ b/arch/mips/kernel/scall64-o32.S
@@ -28,7 +28,7 @@
NESTED(handle_sys, PT_SIZE, sp)
.set noat
SAVE_SOME
- TRACE_IRQS_ON
+ TRACE_IRQS_ON_RELOAD
STI
.set at
ld t1, PT_EPC(sp) # skip syscall on return
@@ -226,7 +226,7 @@ sys_call_table:
PTR sys_ni_syscall /* was sys_stat */
PTR sys_lseek
PTR sys_getpid /* 4020 */
- PTR sys_mount
+ PTR compat_sys_mount
PTR sys_oldumount
PTR sys_setuid
PTR sys_getuid
@@ -498,7 +498,7 @@ sys_call_table:
PTR sys_mknodat /* 4290 */
PTR sys_fchownat
PTR compat_sys_futimesat
- PTR compat_sys_newfstatat
+ PTR sys_newfstatat
PTR sys_unlinkat
PTR sys_renameat /* 4295 */
PTR sys_linkat
@@ -514,4 +514,7 @@ sys_call_table:
PTR sys_tee
PTR sys_vmsplice
PTR compat_sys_move_pages
+ PTR compat_sys_set_robust_list
+ PTR compat_sys_get_robust_list /* 4310 */
+ PTR sys_ni_syscall
.size sys_call_table,.-sys_call_table
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 8c2b596a136f..fdbb508661c5 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -10,29 +10,15 @@
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2000 2001, 2002 Maciej W. Rozycki
*/
-#include <linux/errno.h>
#include <linux/init.h>
#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/user.h>
-#include <linux/utsname.h>
-#include <linux/a.out.h>
#include <linux/screen_info.h>
#include <linux/bootmem.h>
#include <linux/initrd.h>
-#include <linux/major.h>
-#include <linux/kdev_t.h>
#include <linux/root_dev.h>
#include <linux/highmem.h>
#include <linux/console.h>
-#include <linux/mmzone.h>
#include <linux/pfn.h>
#include <asm/addrspace.h>
@@ -96,6 +82,12 @@ void __init add_memory_region(phys_t start, phys_t size, long type)
int x = boot_mem_map.nr_map;
struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1;
+ /* Sanity check */
+ if (start + size < start) {
+ printk("Trying to add an invalid memory region, skipped\n");
+ return;
+ }
+
/*
* Try to merge with previous entry if any. This is far less than
* perfect but is sufficient for most real world cases.
@@ -143,167 +135,132 @@ static void __init print_memory_map(void)
}
}
-static inline void parse_cmdline_early(void)
+/*
+ * Manage initrd
+ */
+#ifdef CONFIG_BLK_DEV_INITRD
+
+static int __init rd_start_early(char *p)
{
- char c = ' ', *to = command_line, *from = saved_command_line;
- unsigned long start_at, mem_size;
- int len = 0;
- int usermem = 0;
+ unsigned long start = memparse(p, &p);
- printk("Determined physical RAM map:\n");
- print_memory_map();
+#ifdef CONFIG_64BIT
+ /* HACK: Guess if the sign extension was forgotten */
+ if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
+ start |= 0xffffffff00000000UL;
+#endif
+ initrd_start = start;
+ initrd_end += start;
- for (;;) {
- /*
- * "mem=XXX[kKmM]" defines a memory region from
- * 0 to <XXX>, overriding the determined size.
- * "mem=XXX[KkmM]@YYY[KkmM]" defines a memory region from
- * <YYY> to <YYY>+<XXX>, overriding the determined size.
- */
- if (c == ' ' && !memcmp(from, "mem=", 4)) {
- if (to != command_line)
- to--;
- /*
- * If a user specifies memory size, we
- * blow away any automatically generated
- * size.
- */
- if (usermem == 0) {
- boot_mem_map.nr_map = 0;
- usermem = 1;
- }
- mem_size = memparse(from + 4, &from);
- if (*from == '@')
- start_at = memparse(from + 1, &from);
- else
- start_at = 0;
- add_memory_region(start_at, mem_size, BOOT_MEM_RAM);
- }
- c = *(from++);
- if (!c)
- break;
- if (CL_SIZE <= ++len)
- break;
- *(to++) = c;
- }
- *to = '\0';
+ return 0;
+}
+early_param("rd_start", rd_start_early);
- if (usermem) {
- printk("User-defined physical RAM map:\n");
- print_memory_map();
- }
+static int __init rd_size_early(char *p)
+{
+ initrd_end += memparse(p, &p);
+
+ return 0;
}
+early_param("rd_size", rd_size_early);
-static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_end)
+static unsigned long __init init_initrd(void)
{
+ unsigned long tmp, end, size;
+ u32 *initrd_header;
+
+ ROOT_DEV = Root_RAM0;
+
/*
- * "rd_start=0xNNNNNNNN" defines the memory address of an initrd
- * "rd_size=0xNN" it's size
+ * Board specific code or command line parser should have
+ * already set up initrd_start and initrd_end. In these cases
+ * perfom sanity checks and use them if all looks good.
*/
- unsigned long start = 0;
- unsigned long size = 0;
- unsigned long end;
- char cmd_line[CL_SIZE];
- char *start_str;
- char *size_str;
- char *tmp;
-
- strcpy(cmd_line, command_line);
- *command_line = 0;
- tmp = cmd_line;
- /* Ignore "rd_start=" strings in other parameters. */
- start_str = strstr(cmd_line, "rd_start=");
- if (start_str && start_str != cmd_line && *(start_str - 1) != ' ')
- start_str = strstr(start_str, " rd_start=");
- while (start_str) {
- if (start_str != cmd_line)
- strncat(command_line, tmp, start_str - tmp);
- start = memparse(start_str + 9, &start_str);
- tmp = start_str + 1;
- start_str = strstr(start_str, " rd_start=");
+ size = initrd_end - initrd_start;
+ if (initrd_end == 0 || size == 0) {
+ initrd_start = 0;
+ initrd_end = 0;
+ } else
+ return initrd_end;
+
+ end = (unsigned long)&_end;
+ tmp = PAGE_ALIGN(end) - sizeof(u32) * 2;
+ if (tmp < end)
+ tmp += PAGE_SIZE;
+
+ initrd_header = (u32 *)tmp;
+ if (initrd_header[0] == 0x494E5244) {
+ initrd_start = (unsigned long)&initrd_header[2];
+ initrd_end = initrd_start + initrd_header[1];
}
- if (*tmp)
- strcat(command_line, tmp);
-
- strcpy(cmd_line, command_line);
- *command_line = 0;
- tmp = cmd_line;
- /* Ignore "rd_size" strings in other parameters. */
- size_str = strstr(cmd_line, "rd_size=");
- if (size_str && size_str != cmd_line && *(size_str - 1) != ' ')
- size_str = strstr(size_str, " rd_size=");
- while (size_str) {
- if (size_str != cmd_line)
- strncat(command_line, tmp, size_str - tmp);
- size = memparse(size_str + 8, &size_str);
- tmp = size_str + 1;
- size_str = strstr(size_str, " rd_size=");
+ return initrd_end;
+}
+
+static void __init finalize_initrd(void)
+{
+ unsigned long size = initrd_end - initrd_start;
+
+ if (size == 0) {
+ printk(KERN_INFO "Initrd not found or empty");
+ goto disable;
+ }
+ if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
+ printk("Initrd extends beyond end of memory");
+ goto disable;
}
- if (*tmp)
- strcat(command_line, tmp);
-#ifdef CONFIG_64BIT
- /* HACK: Guess if the sign extension was forgotten */
- if (start > 0x0000000080000000 && start < 0x00000000ffffffff)
- start |= 0xffffffff00000000UL;
+ reserve_bootmem(CPHYSADDR(initrd_start), size);
+ initrd_below_start_ok = 1;
+
+ printk(KERN_INFO "Initial ramdisk at: 0x%lx (%lu bytes)\n",
+ initrd_start, size);
+ return;
+disable:
+ printk(" - disabling initrd\n");
+ initrd_start = 0;
+ initrd_end = 0;
+}
+
+#else /* !CONFIG_BLK_DEV_INITRD */
+
+#define init_initrd() 0
+#define finalize_initrd() do {} while (0)
+
#endif
- end = start + size;
- if (start && end) {
- *rd_start = start;
- *rd_end = end;
- return 1;
- }
- return 0;
+/*
+ * Initialize the bootmem allocator. It also setup initrd related data
+ * if needed.
+ */
+#ifdef CONFIG_SGI_IP27
+
+static void __init bootmem_init(void)
+{
+ init_initrd();
+ finalize_initrd();
}
-#define MAXMEM HIGHMEM_START
-#define MAXMEM_PFN PFN_DOWN(MAXMEM)
+#else /* !CONFIG_SGI_IP27 */
-static inline void bootmem_init(void)
+static void __init bootmem_init(void)
{
- unsigned long start_pfn;
- unsigned long reserved_end = (unsigned long)&_end;
-#ifndef CONFIG_SGI_IP27
- unsigned long first_usable_pfn;
+ unsigned long reserved_end;
+ unsigned long highest = 0;
+ unsigned long mapstart = -1UL;
unsigned long bootmap_size;
int i;
-#endif
-#ifdef CONFIG_BLK_DEV_INITRD
- int initrd_reserve_bootmem = 0;
-
- /* Board specific code should have set up initrd_start and initrd_end */
- ROOT_DEV = Root_RAM0;
- if (parse_rd_cmdline(&initrd_start, &initrd_end)) {
- reserved_end = max(reserved_end, initrd_end);
- initrd_reserve_bootmem = 1;
- } else {
- unsigned long tmp;
- u32 *initrd_header;
-
- tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - sizeof(u32) * 2;
- if (tmp < reserved_end)
- tmp += PAGE_SIZE;
- initrd_header = (u32 *)tmp;
- if (initrd_header[0] == 0x494E5244) {
- initrd_start = (unsigned long)&initrd_header[2];
- initrd_end = initrd_start + initrd_header[1];
- reserved_end = max(reserved_end, initrd_end);
- initrd_reserve_bootmem = 1;
- }
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
/*
- * Partially used pages are not usable - thus
- * we are rounding upwards.
+ * Init any data related to initrd. It's a nop if INITRD is
+ * not selected. Once that done we can determine the low bound
+ * of usable memory.
*/
- start_pfn = PFN_UP(CPHYSADDR(reserved_end));
+ reserved_end = init_initrd();
+ reserved_end = PFN_UP(CPHYSADDR(max(reserved_end, (unsigned long)&_end)));
-#ifndef CONFIG_SGI_IP27
- /* Find the highest page frame number we have available. */
- max_pfn = 0;
- first_usable_pfn = -1UL;
+ /*
+ * Find the highest page frame number we have available.
+ */
for (i = 0; i < boot_mem_map.nr_map; i++) {
unsigned long start, end;
@@ -312,56 +269,38 @@ static inline void bootmem_init(void)
start = PFN_UP(boot_mem_map.map[i].addr);
end = PFN_DOWN(boot_mem_map.map[i].addr
- + boot_mem_map.map[i].size);
+ + boot_mem_map.map[i].size);
- if (start >= end)
+ if (end > highest)
+ highest = end;
+ if (end <= reserved_end)
continue;
- if (end > max_pfn)
- max_pfn = end;
- if (start < first_usable_pfn) {
- if (start > start_pfn) {
- first_usable_pfn = start;
- } else if (end > start_pfn) {
- first_usable_pfn = start_pfn;
- }
- }
+ if (start >= mapstart)
+ continue;
+ mapstart = max(reserved_end, start);
}
/*
* Determine low and high memory ranges
*/
- max_low_pfn = max_pfn;
- if (max_low_pfn > MAXMEM_PFN) {
- max_low_pfn = MAXMEM_PFN;
-#ifndef CONFIG_HIGHMEM
- /* Maximum memory usable is what is directly addressable */
- printk(KERN_WARNING "Warning only %ldMB will be used.\n",
- MAXMEM >> 20);
- printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n");
+ if (highest > PFN_DOWN(HIGHMEM_START)) {
+#ifdef CONFIG_HIGHMEM
+ highstart_pfn = PFN_DOWN(HIGHMEM_START);
+ highend_pfn = highest;
#endif
+ highest = PFN_DOWN(HIGHMEM_START);
}
-#ifdef CONFIG_HIGHMEM
/*
- * Crude, we really should make a better attempt at detecting
- * highstart_pfn
+ * Initialize the boot-time allocator with low memory only.
*/
- highstart_pfn = highend_pfn = max_pfn;
- if (max_pfn > MAXMEM_PFN) {
- highstart_pfn = MAXMEM_PFN;
- printk(KERN_NOTICE "%ldMB HIGHMEM available.\n",
- (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT));
- }
-#endif
-
- /* Initialize the boot-time allocator with low memory only. */
- bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn);
+ bootmap_size = init_bootmem(mapstart, highest);
/*
* Register fully available low RAM pages with the bootmem allocator.
*/
for (i = 0; i < boot_mem_map.nr_map; i++) {
- unsigned long curr_pfn, last_pfn, size;
+ unsigned long start, end, size;
/*
* Reserve usable memory.
@@ -369,85 +308,50 @@ static inline void bootmem_init(void)
if (boot_mem_map.map[i].type != BOOT_MEM_RAM)
continue;
- /*
- * We are rounding up the start address of usable memory:
- */
- curr_pfn = PFN_UP(boot_mem_map.map[i].addr);
- if (curr_pfn >= max_low_pfn)
- continue;
- if (curr_pfn < start_pfn)
- curr_pfn = start_pfn;
-
- /*
- * ... and at the end of the usable range downwards:
- */
- last_pfn = PFN_DOWN(boot_mem_map.map[i].addr
+ start = PFN_UP(boot_mem_map.map[i].addr);
+ end = PFN_DOWN(boot_mem_map.map[i].addr
+ boot_mem_map.map[i].size);
-
- if (last_pfn > max_low_pfn)
- last_pfn = max_low_pfn;
-
/*
- * Only register lowmem part of lowmem segment with bootmem.
+ * We are rounding up the start address of usable memory
+ * and at the end of the usable range downwards.
*/
- size = last_pfn - curr_pfn;
- if (curr_pfn > PFN_DOWN(HIGHMEM_START))
- continue;
- if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START))
- size = PFN_DOWN(HIGHMEM_START) - curr_pfn;
- if (!size)
+ if (start >= max_low_pfn)
continue;
+ if (start < reserved_end)
+ start = reserved_end;
+ if (end > max_low_pfn)
+ end = max_low_pfn;
/*
- * ... finally, did all the rounding and playing
- * around just make the area go away?
+ * ... finally, is the area going away?
*/
- if (last_pfn <= curr_pfn)
+ if (end <= start)
continue;
+ size = end - start;
/* Register lowmem ranges */
- free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size));
- memory_present(0, curr_pfn, curr_pfn + size - 1);
+ free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT);
+ memory_present(0, start, end);
}
- /* Reserve the bootmap memory. */
- reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size);
-#endif /* CONFIG_SGI_IP27 */
-
-#ifdef CONFIG_BLK_DEV_INITRD
- initrd_below_start_ok = 1;
- if (initrd_start) {
- unsigned long initrd_size = ((unsigned char *)initrd_end) -
- ((unsigned char *)initrd_start);
- const int width = sizeof(long) * 2;
-
- printk("Initial ramdisk at: 0x%p (%lu bytes)\n",
- (void *)initrd_start, initrd_size);
-
- if (CPHYSADDR(initrd_end) > PFN_PHYS(max_low_pfn)) {
- printk("initrd extends beyond end of memory "
- "(0x%0*Lx > 0x%0*Lx)\ndisabling initrd\n",
- width,
- (unsigned long long) CPHYSADDR(initrd_end),
- width,
- (unsigned long long) PFN_PHYS(max_low_pfn));
- initrd_start = initrd_end = 0;
- initrd_reserve_bootmem = 0;
- }
+ /*
+ * Reserve the bootmap memory.
+ */
+ reserve_bootmem(PFN_PHYS(mapstart), bootmap_size);
- if (initrd_reserve_bootmem)
- reserve_bootmem(CPHYSADDR(initrd_start), initrd_size);
- }
-#endif /* CONFIG_BLK_DEV_INITRD */
+ /*
+ * Reserve initrd memory if needed.
+ */
+ finalize_initrd();
}
+#endif /* CONFIG_SGI_IP27 */
+
/*
* arch_mem_init - initialize memory managment subsystem
*
* o plat_mem_setup() detects the memory configuration and will record detected
* memory areas using add_memory_region.
- * o parse_cmdline_early() parses the command line for mem= options which,
- * iff detected, will override the results of the automatic detection.
*
* At this stage the memory configuration of the system is known to the
* kernel but generic memory managment system is still entirely uninitialized.
@@ -465,25 +369,59 @@ static inline void bootmem_init(void)
* initialization hook for anything else was introduced.
*/
-extern void plat_mem_setup(void);
+static int usermem __initdata = 0;
+
+static int __init early_parse_mem(char *p)
+{
+ unsigned long start, size;
+
+ /*
+ * If a user specifies memory size, we
+ * blow away any automatically generated
+ * size.
+ */
+ if (usermem == 0) {
+ boot_mem_map.nr_map = 0;
+ usermem = 1;
+ }
+ start = 0;
+ size = memparse(p, &p);
+ if (*p == '@')
+ start = memparse(p + 1, &p);
+
+ add_memory_region(start, size, BOOT_MEM_RAM);
+ return 0;
+}
+early_param("mem", early_parse_mem);
static void __init arch_mem_init(char **cmdline_p)
{
+ extern void plat_mem_setup(void);
+
/* call board setup routine */
plat_mem_setup();
+ printk("Determined physical RAM map:\n");
+ print_memory_map();
+
strlcpy(command_line, arcs_cmdline, sizeof(command_line));
strlcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
*cmdline_p = command_line;
- parse_cmdline_early();
+ parse_early_param();
+
+ if (usermem) {
+ printk("User-defined physical RAM map:\n");
+ print_memory_map();
+ }
+
bootmem_init();
sparse_init();
paging_init();
}
-static inline void resource_init(void)
+static void __init resource_init(void)
{
int i;
@@ -504,10 +442,10 @@ static inline void resource_init(void)
start = boot_mem_map.map[i].addr;
end = boot_mem_map.map[i].addr + boot_mem_map.map[i].size - 1;
- if (start >= MAXMEM)
+ if (start >= HIGHMEM_START)
continue;
- if (end >= MAXMEM)
- end = MAXMEM - 1;
+ if (end >= HIGHMEM_START)
+ end = HIGHMEM_START - 1;
res = alloc_bootmem(sizeof(struct resource));
switch (boot_mem_map.map[i].type) {
@@ -536,9 +474,6 @@ static inline void resource_init(void)
}
}
-#undef MAXMEM
-#undef MAXMEM_PFN
-
void __init setup_arch(char **cmdline_p)
{
cpu_probe();
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 6b4d9be31615..b9d358e05214 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -424,15 +424,11 @@ void do_signal(struct pt_regs *regs)
if (!user_mode(regs))
return;
- if (try_to_freeze())
- goto no_signal;
-
if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = &current->saved_sigmask;
else
oldset = &current->blocked;
-
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
@@ -446,9 +442,10 @@ void do_signal(struct pt_regs *regs)
if (test_thread_flag(TIF_RESTORE_SIGMASK))
clear_thread_flag(TIF_RESTORE_SIGMASK);
}
+
+ return;
}
-no_signal:
/*
* Who's code doesn't conform to the restartable syscall convention
* dies here!!! The li instruction, a single machine instruction,
@@ -466,6 +463,7 @@ no_signal:
regs->regs[7] = regs->regs[26];
regs->cp0_epc -= 4;
}
+ regs->regs[0] = 0; /* Don't deal with this again. */
}
/*
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index f32a22997c3d..c86a5ddff050 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -815,9 +815,6 @@ void do_signal32(struct pt_regs *regs)
if (!user_mode(regs))
return;
- if (try_to_freeze())
- goto no_signal;
-
if (test_thread_flag(TIF_RESTORE_SIGMASK))
oldset = &current->saved_sigmask;
else
@@ -836,9 +833,10 @@ void do_signal32(struct pt_regs *regs)
if (test_thread_flag(TIF_RESTORE_SIGMASK))
clear_thread_flag(TIF_RESTORE_SIGMASK);
}
+
+ return;
}
-no_signal:
/*
* Who's code doesn't conform to the restartable syscall convention
* dies here!!! The li instruction, a single machine instruction,
@@ -856,6 +854,7 @@ no_signal:
regs->regs[7] = regs->regs[26];
regs->cp0_epc -= 4;
}
+ regs->regs[0] = 0; /* Don't deal with this again. */
}
/*
diff --git a/arch/mips/kernel/smp-mt.c b/arch/mips/kernel/smp-mt.c
index 93429a4d3012..3b5f3b632622 100644
--- a/arch/mips/kernel/smp-mt.c
+++ b/arch/mips/kernel/smp-mt.c
@@ -106,22 +106,22 @@ void __init sanitize_tlb_entries(void)
clear_c0_mvpcontrol(MVPCONTROL_VPC);
}
-static void ipi_resched_dispatch (struct pt_regs *regs)
+static void ipi_resched_dispatch(void)
{
- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ, regs);
+ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
}
-static void ipi_call_dispatch (struct pt_regs *regs)
+static void ipi_call_dispatch(void)
{
- do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ, regs);
+ do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ);
}
-irqreturn_t ipi_resched_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
{
return IRQ_HANDLED;
}
-irqreturn_t ipi_call_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ipi_call_interrupt(int irq, void *dev_id)
{
smp_call_function_interrupt();
@@ -203,7 +203,7 @@ void plat_smp_setup(void)
write_vpe_c0_config( read_c0_config());
/* make sure there are no software interrupts pending */
- write_vpe_c0_cause(read_vpe_c0_cause() & ~(C_SW1|C_SW0));
+ write_vpe_c0_cause(0);
/* Propagate Config7 */
write_vpe_c0_config7(read_c0_config7());
@@ -250,8 +250,8 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
{
/* set up ipi interrupts */
if (cpu_has_vint) {
- set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
- set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
+ set_vi_handler(MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
+ set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
}
cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c
index 221895802dca..db80957ada89 100644
--- a/arch/mips/kernel/smp.c
+++ b/arch/mips/kernel/smp.c
@@ -310,7 +310,7 @@ static void flush_tlb_all_ipi(void *info)
void flush_tlb_all(void)
{
- on_each_cpu(flush_tlb_all_ipi, 0, 1, 1);
+ on_each_cpu(flush_tlb_all_ipi, NULL, 1, 1);
}
static void flush_tlb_mm_ipi(void *mm)
@@ -467,14 +467,18 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices);
static int __init topology_init(void)
{
- int cpu;
- int ret;
+ int i, ret;
- for_each_present_cpu(cpu) {
- ret = register_cpu(&per_cpu(cpu_devices, cpu), cpu);
+#ifdef CONFIG_NUMA
+ for_each_online_node(i)
+ register_one_node(i);
+#endif /* CONFIG_NUMA */
+
+ for_each_present_cpu(i) {
+ ret = register_cpu(&per_cpu(cpu_devices, i), i);
if (ret)
printk(KERN_WARNING "topology_init: register_cpu %d "
- "failed (%d)\n", cpu, ret);
+ "failed (%d)\n", i, ret);
}
return 0;
diff --git a/arch/mips/kernel/smtc-asm.S b/arch/mips/kernel/smtc-asm.S
index 4cc3dea36612..1cb9441f1474 100644
--- a/arch/mips/kernel/smtc-asm.S
+++ b/arch/mips/kernel/smtc-asm.S
@@ -8,7 +8,7 @@
#include <asm/regdef.h>
#include <asm/asmmacro.h>
#include <asm/stackframe.h>
-#include <asm/stackframe.h>
+#include <asm/irqflags.h>
/*
* "Software Interrupt" linkage.
@@ -97,15 +97,12 @@ FEXPORT(__smtc_ipi_vector)
SAVE_ALL
CLI
TRACE_IRQS_OFF
- move a0,sp
/* Function to be invoked passed stack pad slot 5 */
lw t0,PT_PADSLOT5(sp)
/* Argument from sender passed in stack pad slot 4 */
- lw a1,PT_PADSLOT4(sp)
- jalr t0
- nop
- j ret_from_irq
- nop
+ lw a0,PT_PADSLOT4(sp)
+ PTR_LA ra, _ret_from_irq
+ jr t0
/*
* Called from idle loop to provoke processing of queued IPIs
diff --git a/arch/mips/kernel/smtc.c b/arch/mips/kernel/smtc.c
index 604bcc5cb7c8..cc1f7474f7d7 100644
--- a/arch/mips/kernel/smtc.c
+++ b/arch/mips/kernel/smtc.c
@@ -82,7 +82,7 @@ struct smtc_ipi_q freeIPIq;
/* Forward declarations */
-void ipi_decode(struct pt_regs *, struct smtc_ipi *);
+void ipi_decode(struct smtc_ipi *);
void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
void setup_cross_vpe_interrupts(void);
void init_smtc_stats(void);
@@ -820,19 +820,19 @@ void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
write_tc_c0_tcrestart(__smtc_ipi_vector);
}
-void ipi_resched_interrupt(struct pt_regs *regs)
+static void ipi_resched_interrupt(void)
{
/* Return from interrupt should be enough to cause scheduler check */
}
-void ipi_call_interrupt(struct pt_regs *regs)
+static void ipi_call_interrupt(void)
{
/* Invoke generic function invocation code in smp.c */
smp_call_function_interrupt();
}
-void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi)
+void ipi_decode(struct smtc_ipi *pipi)
{
void *arg_copy = pipi->arg;
int type_copy = pipi->type;
@@ -846,15 +846,15 @@ void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi)
#ifdef SMTC_IDLE_HOOK_DEBUG
clock_hang_reported[dest_copy] = 0;
#endif /* SMTC_IDLE_HOOK_DEBUG */
- local_timer_interrupt(0, NULL, regs);
+ local_timer_interrupt(0, NULL);
break;
case LINUX_SMP_IPI:
switch ((int)arg_copy) {
case SMP_RESCHEDULE_YOURSELF:
- ipi_resched_interrupt(regs);
+ ipi_resched_interrupt();
break;
case SMP_CALL_FUNCTION:
- ipi_call_interrupt(regs);
+ ipi_call_interrupt();
break;
default:
printk("Impossible SMTC IPI Argument 0x%x\n",
@@ -868,7 +868,7 @@ void ipi_decode(struct pt_regs *regs, struct smtc_ipi *pipi)
}
}
-void deferred_smtc_ipi(struct pt_regs *regs)
+void deferred_smtc_ipi(void)
{
struct smtc_ipi *pipi;
unsigned long flags;
@@ -883,7 +883,7 @@ void deferred_smtc_ipi(struct pt_regs *regs)
while((pipi = smtc_ipi_dq(&IPIQ[q])) != NULL) {
/* ipi_decode() should be called with interrupts off */
local_irq_save(flags);
- ipi_decode(regs, pipi);
+ ipi_decode(pipi);
local_irq_restore(flags);
}
}
@@ -917,7 +917,7 @@ void smtc_timer_broadcast(int vpe)
static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ;
-static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs)
+static irqreturn_t ipi_interrupt(int irq, void *dev_idm)
{
int my_vpe = cpu_data[smp_processor_id()].vpe_id;
int my_tc = cpu_data[smp_processor_id()].tc_id;
@@ -978,7 +978,7 @@ static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs)
* with interrupts off
*/
local_irq_save(flags);
- ipi_decode(regs, pipi);
+ ipi_decode(pipi);
local_irq_restore(flags);
}
}
@@ -987,9 +987,9 @@ static irqreturn_t ipi_interrupt(int irq, void *dev_idm, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static void ipi_irq_dispatch(struct pt_regs *regs)
+static void ipi_irq_dispatch(void)
{
- do_IRQ(cpu_ipi_irq, regs);
+ do_IRQ(cpu_ipi_irq);
}
static struct irqaction irq_ipi;
diff --git a/arch/mips/kernel/stacktrace.c b/arch/mips/kernel/stacktrace.c
new file mode 100644
index 000000000000..a586aba337a7
--- /dev/null
+++ b/arch/mips/kernel/stacktrace.c
@@ -0,0 +1,85 @@
+/*
+ * arch/mips/kernel/stacktrace.c
+ *
+ * Stack trace management functions
+ *
+ * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ */
+#include <linux/sched.h>
+#include <linux/stacktrace.h>
+#include <asm/stacktrace.h>
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer:
+ */
+static void save_raw_context_stack(struct stack_trace *trace,
+ unsigned long reg29)
+{
+ unsigned long *sp = (unsigned long *)reg29;
+ unsigned long addr;
+
+ while (!kstack_end(sp)) {
+ addr = *sp++;
+ if (__kernel_text_address(addr)) {
+ if (trace->skip > 0)
+ trace->skip--;
+ else
+ trace->entries[trace->nr_entries++] = addr;
+ if (trace->nr_entries >= trace->max_entries)
+ break;
+ }
+ }
+}
+
+static void save_context_stack(struct stack_trace *trace,
+ struct task_struct *task, struct pt_regs *regs)
+{
+ unsigned long sp = regs->regs[29];
+#ifdef CONFIG_KALLSYMS
+ unsigned long ra = regs->regs[31];
+ unsigned long pc = regs->cp0_epc;
+
+ if (raw_show_trace || !__kernel_text_address(pc)) {
+ unsigned long stack_page =
+ (unsigned long)task_stack_page(task);
+ if (stack_page && sp >= stack_page &&
+ sp <= stack_page + THREAD_SIZE - 32)
+ save_raw_context_stack(trace, sp);
+ return;
+ }
+ do {
+ if (trace->skip > 0)
+ trace->skip--;
+ else
+ trace->entries[trace->nr_entries++] = pc;
+ if (trace->nr_entries >= trace->max_entries)
+ break;
+ pc = unwind_stack(task, &sp, pc, &ra);
+ } while (pc);
+#else
+ save_raw_context_stack(trace, sp);
+#endif
+}
+
+/*
+ * Save stack-backtrace addresses into a stack_trace buffer.
+ */
+void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
+{
+ struct pt_regs dummyregs;
+ struct pt_regs *regs = &dummyregs;
+
+ WARN_ON(trace->nr_entries || !trace->max_entries);
+
+ if (task && task != current) {
+ regs->regs[29] = task->thread.reg29;
+ regs->regs[31] = 0;
+ regs->cp0_epc = task->thread.reg31;
+ } else {
+ if (!task)
+ task = current;
+ prepare_frametrace(regs);
+ }
+
+ save_context_stack(trace, task, regs);
+}
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 0721314db657..26e1a7e78d13 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -231,7 +231,7 @@ out:
*/
asmlinkage int sys_uname(struct old_utsname __user * name)
{
- if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+ if (name && !copy_to_user(name, utsname(), sizeof (*name)))
return 0;
return -EFAULT;
}
@@ -248,22 +248,27 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name)
if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
return -EFAULT;
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
- error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
- error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
- error -= __put_user(0,name->release+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
- error -= __put_user(0,name->version+__OLD_UTS_LEN);
- error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
- error = __put_user(0,name->machine+__OLD_UTS_LEN);
+ error = __copy_to_user(&name->sysname, &utsname()->sysname,
+ __OLD_UTS_LEN);
+ error -= __put_user(0, name->sysname + __OLD_UTS_LEN);
+ error -= __copy_to_user(&name->nodename, &utsname()->nodename,
+ __OLD_UTS_LEN);
+ error -= __put_user(0, name->nodename + __OLD_UTS_LEN);
+ error -= __copy_to_user(&name->release, &utsname()->release,
+ __OLD_UTS_LEN);
+ error -= __put_user(0, name->release + __OLD_UTS_LEN);
+ error -= __copy_to_user(&name->version, &utsname()->version,
+ __OLD_UTS_LEN);
+ error -= __put_user(0, name->version + __OLD_UTS_LEN);
+ error -= __copy_to_user(&name->machine, &utsname()->machine,
+ __OLD_UTS_LEN);
+ error = __put_user(0, name->machine + __OLD_UTS_LEN);
error = error ? -EFAULT : 0;
return error;
}
-void sys_set_thread_area(unsigned long addr)
+asmlinkage int sys_set_thread_area(unsigned long addr)
{
struct thread_info *ti = task_thread_info(current);
@@ -271,6 +276,8 @@ void sys_set_thread_area(unsigned long addr)
/* If some future MIPS implementation has this register in hardware,
* we will need to update it here (and in context switches). */
+
+ return 0;
}
asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
@@ -399,3 +406,32 @@ asmlinkage void bad_stack(void)
{
do_exit(SIGSEGV);
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register unsigned long __a0 asm("$4") = (unsigned long) filename;
+ register unsigned long __a1 asm("$5") = (unsigned long) argv;
+ register unsigned long __a2 asm("$6") = (unsigned long) envp;
+ register unsigned long __a3 asm("$7");
+ unsigned long __v0;
+
+ __asm__ volatile (" \n"
+ " .set noreorder \n"
+ " li $2, %5 # __NR_execve \n"
+ " syscall \n"
+ " move %0, $2 \n"
+ " .set reorder \n"
+ : "=&r" (__v0), "=r" (__a3)
+ : "r" (__a0), "r" (__a1), "r" (__a2), "i" (__NR_execve)
+ : "$2", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24",
+ "memory");
+
+ if (__a3 == 0)
+ return __v0;
+
+ return -__v0;
+}
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 1137dd6ea7aa..93c74fefff76 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -884,7 +884,7 @@ asmlinkage int irix_getdomainname(char __user *name, int len)
down_read(&uts_sem);
if (len > __NEW_UTS_LEN)
len = __NEW_UTS_LEN;
- err = copy_to_user(name, system_utsname.domainname, len) ? -EFAULT : 0;
+ err = copy_to_user(name, utsname()->domainname, len) ? -EFAULT : 0;
up_read(&uts_sem);
return err;
@@ -1127,11 +1127,11 @@ struct iuname {
asmlinkage int irix_uname(struct iuname __user *buf)
{
down_read(&uts_sem);
- if (copy_from_user(system_utsname.sysname, buf->sysname, 65)
- || copy_from_user(system_utsname.nodename, buf->nodename, 65)
- || copy_from_user(system_utsname.release, buf->release, 65)
- || copy_from_user(system_utsname.version, buf->version, 65)
- || copy_from_user(system_utsname.machine, buf->machine, 65)) {
+ if (copy_from_user(utsname()->sysname, buf->sysname, 65)
+ || copy_from_user(utsname()->nodename, buf->nodename, 65)
+ || copy_from_user(utsname()->release, buf->release, 65)
+ || copy_from_user(utsname()->version, buf->version, 65)
+ || copy_from_user(utsname()->machine, buf->machine, 65)) {
return -EFAULT;
}
up_read(&uts_sem);
@@ -1739,12 +1739,13 @@ struct irix_dirent32_callback {
#define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
static int irix_filldir32(void *__buf, const char *name,
- int namlen, loff_t offset, ino_t ino, unsigned int d_type)
+ int namlen, loff_t offset, u64 ino, unsigned int d_type)
{
struct irix_dirent32 __user *dirent;
struct irix_dirent32_callback *buf = __buf;
unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
int err = 0;
+ u32 d_ino;
#ifdef DEBUG_GETDENTS
printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
@@ -1753,12 +1754,15 @@ static int irix_filldir32(void *__buf, const char *name,
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
if (dirent)
err = __put_user(offset, &dirent->d_off);
dirent = buf->current_dir;
err |= __put_user(dirent, &buf->previous);
- err |= __put_user(ino, &dirent->d_ino);
+ err |= __put_user(d_ino, &dirent->d_ino);
err |= __put_user(reclen, &dirent->d_reclen);
err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0;
err |= __put_user(0, &dirent->d_name[namlen]);
@@ -1837,7 +1841,7 @@ struct irix_dirent64_callback {
#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
static int irix_filldir64(void *__buf, const char *name,
- int namlen, loff_t offset, ino_t ino, unsigned int d_type)
+ int namlen, loff_t offset, u64 ino, unsigned int d_type)
{
struct irix_dirent64 __user *dirent;
struct irix_dirent64_callback * buf = __buf;
diff --git a/arch/mips/kernel/time.c b/arch/mips/kernel/time.c
index 170cb67f4ede..debe86c2f691 100644
--- a/arch/mips/kernel/time.c
+++ b/arch/mips/kernel/time.c
@@ -47,8 +47,6 @@
/*
* forward reference
*/
-extern volatile unsigned long wall_jiffies;
-
DEFINE_SPINLOCK(rtc_lock);
/*
@@ -151,88 +149,6 @@ void (*mips_timer_ack)(void);
unsigned int (*mips_hpt_read)(void);
void (*mips_hpt_init)(unsigned int);
-
-/*
- * This version of gettimeofday has microsecond resolution and better than
- * microsecond precision on fast machines with cycle counter.
- */
-void do_gettimeofday(struct timeval *tv)
-{
- unsigned long seq;
- unsigned long lost;
- unsigned long usec, sec;
- unsigned long max_ntp_tick;
-
- do {
- seq = read_seqbegin(&xtime_lock);
-
- usec = do_gettimeoffset();
-
- lost = jiffies - wall_jiffies;
-
- /*
- * If time_adjust is negative then NTP is slowing the clock
- * so make sure not to go into next possible interval.
- * Better to lose some accuracy than have time go backwards..
- */
- if (unlikely(time_adjust < 0)) {
- max_ntp_tick = (USEC_PER_SEC / HZ) - tickadj;
- usec = min(usec, max_ntp_tick);
-
- if (lost)
- usec += lost * max_ntp_tick;
- } else if (unlikely(lost))
- usec += lost * (USEC_PER_SEC / HZ);
-
- sec = xtime.tv_sec;
- usec += (xtime.tv_nsec / 1000);
-
- } while (read_seqretry(&xtime_lock, seq));
-
- while (usec >= 1000000) {
- usec -= 1000000;
- sec++;
- }
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
- time_t wtm_sec, sec = tv->tv_sec;
- long wtm_nsec, nsec = tv->tv_nsec;
-
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_seqlock_irq(&xtime_lock);
-
- /*
- * This is revolting. We need to set "xtime" correctly. However,
- * the value in this location is the value at the most recent update
- * of wall time. Discover what correction gettimeofday() would have
- * made, and then undo it!
- */
- nsec -= do_gettimeoffset() * NSEC_PER_USEC;
- nsec -= (jiffies - wall_jiffies) * tick_nsec;
-
- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
- set_normalized_timespec(&xtime, sec, nsec);
- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
- ntp_clear();
- write_sequnlock_irq(&xtime_lock);
- clock_was_set();
- return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
/*
* Gettimeoffset routines. These routines returns the time duration
* since last timer interrupt in usecs.
@@ -406,18 +322,17 @@ static long last_rtc_update;
* a broadcasted inter-processor interrupt which itself is triggered
* by the global timer interrupt.
*/
-void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+void local_timer_interrupt(int irq, void *dev_id)
{
- if (current->pid)
- profile_tick(CPU_PROFILING, regs);
- update_process_times(user_mode(regs));
+ profile_tick(CPU_PROFILING);
+ update_process_times(user_mode(get_irq_regs()));
}
/*
* High-level timer interrupt service routines. This function
* is set as irqaction->handler and is invoked through do_IRQ.
*/
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
{
unsigned long j;
unsigned int count;
@@ -434,7 +349,7 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*
* call the generic timer interrupt handling
*/
- do_timer(regs);
+ do_timer(1);
/*
* If we have an externally synchronized Linux clock, then update
@@ -503,22 +418,22 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* In SMP mode, local_timer_interrupt() is invoked by appropriate
* low-level local timer interrupt handler.
*/
- local_timer_interrupt(irq, dev_id, regs);
+ local_timer_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
-int null_perf_irq(struct pt_regs *regs)
+int null_perf_irq(void)
{
return 0;
}
-int (*perf_irq)(struct pt_regs *regs) = null_perf_irq;
+int (*perf_irq)(void) = null_perf_irq;
EXPORT_SYMBOL(null_perf_irq);
EXPORT_SYMBOL(perf_irq);
-asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs)
+asmlinkage void ll_timer_interrupt(int irq)
{
int r2 = cpu_has_mips_r2;
@@ -532,25 +447,25 @@ asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs)
* performance counter interrupt handler anyway.
*/
if (!r2 || (read_c0_cause() & (1 << 26)))
- if (perf_irq(regs))
+ if (perf_irq())
goto out;
/* we keep interrupt disabled all the time */
if (!r2 || (read_c0_cause() & (1 << 30)))
- timer_interrupt(irq, NULL, regs);
+ timer_interrupt(irq, NULL);
out:
irq_exit();
}
-asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs)
+asmlinkage void ll_local_timer_interrupt(int irq)
{
irq_enter();
if (smp_processor_id() != 0)
kstat_this_cpu.irqs[irq]++;
/* we keep interrupt disabled all the time */
- local_timer_interrupt(irq, NULL, regs);
+ local_timer_interrupt(irq, NULL);
irq_exit();
}
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 954a198494ef..cce8313ec27d 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -20,6 +20,7 @@
#include <linux/spinlock.h>
#include <linux/kallsyms.h>
#include <linux/bootmem.h>
+#include <linux/interrupt.h>
#include <asm/bootinfo.h>
#include <asm/branch.h>
@@ -40,6 +41,7 @@
#include <asm/mmu_context.h>
#include <asm/watch.h>
#include <asm/types.h>
+#include <asm/stacktrace.h>
extern asmlinkage void handle_int(void);
extern asmlinkage void handle_tlbm(void);
@@ -64,7 +66,7 @@ extern asmlinkage void handle_mcheck(void);
extern asmlinkage void handle_reserved(void);
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
- struct mips_fpu_struct *ctx);
+ struct mips_fpu_struct *ctx, int has_fpu);
void (*board_be_init)(void);
int (*board_be_handler)(struct pt_regs *regs, int is_fixup);
@@ -72,28 +74,62 @@ void (*board_nmi_handler_setup)(void);
void (*board_ejtag_handler_setup)(void);
void (*board_bind_eic_interrupt)(int irq, int regset);
-/*
- * These constant is for searching for possible module text segments.
- * MODULE_RANGE is a guess of how much space is likely to be vmalloced.
- */
-#define MODULE_RANGE (8*1024*1024)
+
+static void show_raw_backtrace(unsigned long reg29)
+{
+ unsigned long *sp = (unsigned long *)reg29;
+ unsigned long addr;
+
+ printk("Call Trace:");
+#ifdef CONFIG_KALLSYMS
+ printk("\n");
+#endif
+ while (!kstack_end(sp)) {
+ addr = *sp++;
+ if (__kernel_text_address(addr))
+ print_ip_sym(addr);
+ }
+ printk("\n");
+}
+
+#ifdef CONFIG_KALLSYMS
+int raw_show_trace;
+static int __init set_raw_show_trace(char *str)
+{
+ raw_show_trace = 1;
+ return 1;
+}
+__setup("raw_show_trace", set_raw_show_trace);
+#endif
+
+static void show_backtrace(struct task_struct *task, struct pt_regs *regs)
+{
+ unsigned long sp = regs->regs[29];
+ unsigned long ra = regs->regs[31];
+ unsigned long pc = regs->cp0_epc;
+
+ if (raw_show_trace || !__kernel_text_address(pc)) {
+ show_raw_backtrace(sp);
+ return;
+ }
+ printk("Call Trace:\n");
+ do {
+ print_ip_sym(pc);
+ pc = unwind_stack(task, &sp, pc, &ra);
+ } while (pc);
+ printk("\n");
+}
/*
* This routine abuses get_user()/put_user() to reference pointers
* with at least a bit of error checking ...
*/
-void show_stack(struct task_struct *task, unsigned long *sp)
+static void show_stacktrace(struct task_struct *task, struct pt_regs *regs)
{
const int field = 2 * sizeof(unsigned long);
long stackdata;
int i;
-
- if (!sp) {
- if (task && task != current)
- sp = (unsigned long *) task->thread.reg29;
- else
- sp = (unsigned long *) &sp;
- }
+ unsigned long *sp = (unsigned long *)regs->regs[29];
printk("Stack :");
i = 0;
@@ -114,32 +150,26 @@ void show_stack(struct task_struct *task, unsigned long *sp)
i++;
}
printk("\n");
+ show_backtrace(task, regs);
}
-void show_trace(struct task_struct *task, unsigned long *stack)
+void show_stack(struct task_struct *task, unsigned long *sp)
{
- const int field = 2 * sizeof(unsigned long);
- unsigned long addr;
-
- if (!stack) {
- if (task && task != current)
- stack = (unsigned long *) task->thread.reg29;
- else
- stack = (unsigned long *) &stack;
- }
-
- printk("Call Trace:");
-#ifdef CONFIG_KALLSYMS
- printk("\n");
-#endif
- while (!kstack_end(stack)) {
- addr = *stack++;
- if (__kernel_text_address(addr)) {
- printk(" [<%0*lx>] ", field, addr);
- print_symbol("%s\n", addr);
+ struct pt_regs regs;
+ if (sp) {
+ regs.regs[29] = (unsigned long)sp;
+ regs.regs[31] = 0;
+ regs.cp0_epc = 0;
+ } else {
+ if (task && task != current) {
+ regs.regs[29] = task->thread.reg29;
+ regs.regs[31] = 0;
+ regs.cp0_epc = task->thread.reg31;
+ } else {
+ prepare_frametrace(&regs);
}
}
- printk("\n");
+ show_stacktrace(task, &regs);
}
/*
@@ -147,9 +177,10 @@ void show_trace(struct task_struct *task, unsigned long *stack)
*/
void dump_stack(void)
{
- unsigned long stack;
+ struct pt_regs regs;
- show_trace(current, &stack);
+ prepare_frametrace(&regs);
+ show_backtrace(current, &regs);
}
EXPORT_SYMBOL(dump_stack);
@@ -268,8 +299,7 @@ void show_registers(struct pt_regs *regs)
print_modules();
printk("Process %s (pid: %d, threadinfo=%p, task=%p)\n",
current->comm, current->pid, current_thread_info(), current);
- show_stack(current, (long *) regs->regs[29]);
- show_trace(current, (long *) regs->regs[29]);
+ show_stacktrace(current, regs);
show_code((unsigned int *) regs->cp0_epc);
printk("\n");
}
@@ -292,6 +322,16 @@ NORET_TYPE void ATTRIB_NORET die(const char * str, struct pt_regs * regs)
printk("%s[#%d]:\n", str, ++die_counter);
show_registers(regs);
spin_unlock_irq(&die_lock);
+
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops) {
+ printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+ ssleep(5);
+ panic("Fatal exception");
+ }
+
do_exit(SIGSEGV);
}
@@ -601,7 +641,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31)
preempt_enable();
/* Run the emulator */
- sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu);
+ sig = fpu_emulator_cop1Handler (regs, &current->thread.fpu, 1);
preempt_disable();
@@ -751,11 +791,13 @@ asmlinkage void do_cpu(struct pt_regs *regs)
set_used_math();
}
- preempt_enable();
-
- if (!cpu_has_fpu) {
- int sig = fpu_emulator_cop1Handler(regs,
- &current->thread.fpu);
+ if (cpu_has_fpu) {
+ preempt_enable();
+ } else {
+ int sig;
+ preempt_enable();
+ sig = fpu_emulator_cop1Handler(regs,
+ &current->thread.fpu, 0);
if (sig)
force_sig(sig, current);
#ifdef CONFIG_MIPS_MT_FPAFF
diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c
index 9ee0ec2cd067..51ddd2166898 100644
--- a/arch/mips/kernel/vpe.c
+++ b/arch/mips/kernel/vpe.c
@@ -768,10 +768,16 @@ int vpe_run(struct vpe * v)
*/
write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | v->minor);
+ write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
+
+ back_to_back_c0_hazard();
+
/* Set up the XTC bit in vpeconf0 to point at our tc */
write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
| (t->index << VPECONF0_XTC_SHIFT));
+ back_to_back_c0_hazard();
+
/* enable this VPE */
write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
diff --git a/arch/mips/lasat/interrupt.c b/arch/mips/lasat/interrupt.c
index 456be8fc961a..a144a002dcc4 100644
--- a/arch/mips/lasat/interrupt.c
+++ b/arch/mips/lasat/interrupt.c
@@ -108,14 +108,14 @@ static unsigned long get_int_status_200(void)
return int_status;
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned long int_status;
unsigned int cause = read_c0_cause();
int irq;
if (cause & CAUSEF_IP7) { /* R4000 count / compare IRQ */
- ll_timer_interrupt(7, regs);
+ ll_timer_interrupt(7);
return;
}
@@ -125,7 +125,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
if (int_status) {
irq = ls1bit32(int_status);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
}
diff --git a/arch/mips/lasat/setup.c b/arch/mips/lasat/setup.c
index 0ffc43c600d9..14c55168f1ff 100644
--- a/arch/mips/lasat/setup.c
+++ b/arch/mips/lasat/setup.c
@@ -34,7 +34,6 @@
#include <asm/cpu.h>
#include <asm/bootinfo.h>
#include <asm/irq.h>
-#include <asm/serial.h>
#include <asm/lasat/lasat.h>
#include <asm/lasat/serial.h>
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c
index 3f0d5d26d506..80531b35cd61 100644
--- a/arch/mips/math-emu/cp1emu.c
+++ b/arch/mips/math-emu/cp1emu.c
@@ -38,8 +38,6 @@
#include <asm/inst.h>
#include <asm/bootinfo.h>
-#include <asm/cpu.h>
-#include <asm/cpu-features.h>
#include <asm/processor.h>
#include <asm/ptrace.h>
#include <asm/signal.h>
@@ -1233,7 +1231,8 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
return 0;
}
-int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
+int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
+ int has_fpu)
{
unsigned long oldepc, prevepc;
mips_instruction insn;
@@ -1263,7 +1262,7 @@ int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx)
ieee754_csr.rm = mips_rm[ieee754_csr.rm];
}
- if (cpu_has_fpu)
+ if (has_fpu)
break;
if (sig)
break;
diff --git a/arch/mips/mips-boards/atlas/atlas_int.c b/arch/mips/mips-boards/atlas/atlas_int.c
index fb25e0377f11..be624b8c3b0e 100644
--- a/arch/mips/mips-boards/atlas/atlas_int.c
+++ b/arch/mips/mips-boards/atlas/atlas_int.c
@@ -1,6 +1,8 @@
/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 1999, 2000, 2006 MIPS Technologies, Inc.
+ * All rights reserved.
+ * Authors: Carsten Langgaard <carstenl@mips.com>
+ * Maciej W. Rozycki <macro@mips.com>
*
* ########################################################################
*
@@ -25,17 +27,20 @@
*/
#include <linux/compiler.h>
#include <linux/init.h>
+#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
-#include <asm/irq.h>
+#include <asm/gdb-stub.h>
#include <asm/io.h>
+#include <asm/irq_cpu.h>
+#include <asm/msc01_ic.h>
+
#include <asm/mips-boards/atlas.h>
#include <asm/mips-boards/atlasint.h>
-#include <asm/gdb-stub.h>
-
+#include <asm/mips-boards/generic.h>
static struct atlas_ictrl_regs *atlas_hw0_icregs;
@@ -47,13 +52,13 @@ static struct atlas_ictrl_regs *atlas_hw0_icregs;
void disable_atlas_irq(unsigned int irq_nr)
{
- atlas_hw0_icregs->intrsten = (1 << (irq_nr-ATLASINT_BASE));
+ atlas_hw0_icregs->intrsten = 1 << (irq_nr - ATLAS_INT_BASE);
iob();
}
void enable_atlas_irq(unsigned int irq_nr)
{
- atlas_hw0_icregs->intseten = (1 << (irq_nr-ATLASINT_BASE));
+ atlas_hw0_icregs->intseten = 1 << (irq_nr - ATLAS_INT_BASE);
iob();
}
@@ -96,7 +101,7 @@ static inline int ls1bit32(unsigned int x)
return b;
}
-static inline void atlas_hw0_irqdispatch(struct pt_regs *regs)
+static inline void atlas_hw0_irqdispatch(void)
{
unsigned long int_status;
int irq;
@@ -107,11 +112,11 @@ static inline void atlas_hw0_irqdispatch(struct pt_regs *regs)
if (unlikely(int_status == 0))
return;
- irq = ATLASINT_BASE + ls1bit32(int_status);
+ irq = ATLAS_INT_BASE + ls1bit32(int_status);
DEBUG_INT("atlas_hw0_irqdispatch: irq=%d\n", irq);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
static inline int clz(unsigned long x)
@@ -161,15 +166,14 @@ static inline unsigned int irq_ffs(unsigned int pending)
}
/*
- * IRQs on the Atlas board look basically (barring software IRQs which we
- * don't use at all and all external interrupt sources are combined together
- * on hardware interrupt 0 (MIPS IRQ 2)) like:
+ * IRQs on the Atlas board look basically like (all external interrupt
+ * sources are combined together on hardware interrupt 0 (MIPS IRQ 2)):
*
- * MIPS IRQ Source
+ * MIPS IRQ Source
* -------- ------
- * 0 Software (ignored)
- * 1 Software (ignored)
- * 2 Combined hardware interrupt (hw0)
+ * 0 Software 0 (reschedule IPI on MT)
+ * 1 Software 1 (remote call IPI on MT)
+ * 2 Combined Atlas hardware interrupt (hw0)
* 3 Hardware (ignored)
* 4 Hardware (ignored)
* 5 Hardware (ignored)
@@ -179,12 +183,12 @@ static inline unsigned int irq_ffs(unsigned int pending)
* We handle the IRQ according to _our_ priority which is:
*
* Highest ---- R4k Timer
- * Lowest ---- Combined hardware interrupt
+ * Lowest ---- Software 0
*
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
@@ -192,18 +196,20 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
irq = irq_ffs(pending);
if (irq == MIPSCPU_INT_ATLAS)
- atlas_hw0_irqdispatch(regs);
- else if (irq > 0)
- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ atlas_hw0_irqdispatch();
+ else if (irq >= 0)
+ do_IRQ(MIPSCPU_INT_BASE + irq);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
-void __init arch_init_irq(void)
+static inline void init_atlas_irqs (int base)
{
int i;
- atlas_hw0_icregs = (struct atlas_ictrl_regs *)ioremap (ATLAS_ICTRL_REGS_BASE, sizeof(struct atlas_ictrl_regs *));
+ atlas_hw0_icregs = (struct atlas_ictrl_regs *)
+ ioremap(ATLAS_ICTRL_REGS_BASE,
+ sizeof(struct atlas_ictrl_regs *));
/*
* Mask out all interrupt by writing "1" to all bit position in
@@ -211,7 +217,7 @@ void __init arch_init_irq(void)
*/
atlas_hw0_icregs->intrsten = 0xffffffff;
- for (i = ATLASINT_BASE; i <= ATLASINT_END; i++) {
+ for (i = ATLAS_INT_BASE; i <= ATLAS_INT_END; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
@@ -219,3 +225,62 @@ void __init arch_init_irq(void)
spin_lock_init(&irq_desc[i].lock);
}
}
+
+static struct irqaction atlasirq = {
+ .handler = no_action,
+ .name = "Atlas cascade"
+};
+
+msc_irqmap_t __initdata msc_irqmap[] = {
+ {MSC01C_INT_TMR, MSC01_IRQ_EDGE, 0},
+ {MSC01C_INT_PCI, MSC01_IRQ_LEVEL, 0},
+};
+int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap);
+
+msc_irqmap_t __initdata msc_eicirqmap[] = {
+ {MSC01E_INT_SW0, MSC01_IRQ_LEVEL, 0},
+ {MSC01E_INT_SW1, MSC01_IRQ_LEVEL, 0},
+ {MSC01E_INT_ATLAS, MSC01_IRQ_LEVEL, 0},
+ {MSC01E_INT_TMR, MSC01_IRQ_EDGE, 0},
+ {MSC01E_INT_PCI, MSC01_IRQ_LEVEL, 0},
+ {MSC01E_INT_PERFCTR, MSC01_IRQ_LEVEL, 0},
+ {MSC01E_INT_CPUCTR, MSC01_IRQ_LEVEL, 0}
+};
+int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap);
+
+void __init arch_init_irq(void)
+{
+ init_atlas_irqs(ATLAS_INT_BASE);
+
+ if (!cpu_has_veic)
+ mips_cpu_irq_init(MIPSCPU_INT_BASE);
+
+ switch(mips_revision_corid) {
+ case MIPS_REVISION_CORID_CORE_MSC:
+ case MIPS_REVISION_CORID_CORE_FPGA2:
+ case MIPS_REVISION_CORID_CORE_FPGA3:
+ case MIPS_REVISION_CORID_CORE_24K:
+ case MIPS_REVISION_CORID_CORE_EMUL_MSC:
+ if (cpu_has_veic)
+ init_msc_irqs (MSC01E_INT_BASE,
+ msc_eicirqmap, msc_nr_eicirqs);
+ else
+ init_msc_irqs (MSC01C_INT_BASE,
+ msc_irqmap, msc_nr_irqs);
+ }
+
+
+ if (cpu_has_veic) {
+ set_vi_handler (MSC01E_INT_ATLAS, atlas_hw0_irqdispatch);
+ setup_irq (MSC01E_INT_BASE + MSC01E_INT_ATLAS, &atlasirq);
+ } else if (cpu_has_vint) {
+ set_vi_handler (MIPSCPU_INT_ATLAS, atlas_hw0_irqdispatch);
+#ifdef CONFIG_MIPS_MT_SMTC
+ setup_irq_smtc (MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS,
+ &atlasirq, (0x100 << MIPSCPU_INT_ATLAS));
+#else /* Not SMTC */
+ setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq);
+#endif /* CONFIG_MIPS_MT_SMTC */
+ } else
+ setup_irq(MIPSCPU_INT_BASE + MIPSCPU_INT_ATLAS, &atlasirq);
+}
diff --git a/arch/mips/mips-boards/atlas/atlas_setup.c b/arch/mips/mips-boards/atlas/atlas_setup.c
index 9871a91fdb07..0c6b0ce15028 100644
--- a/arch/mips/mips-boards/atlas/atlas_setup.c
+++ b/arch/mips/mips-boards/atlas/atlas_setup.c
@@ -77,7 +77,7 @@ static void __init serial_init(void)
#else
s.iobase = ATLAS_UART_REGS_BASE+3;
#endif
- s.irq = ATLASINT_UART;
+ s.irq = ATLAS_INT_UART;
s.uartclk = ATLAS_BASE_BAUD * 16;
s.flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ;
s.iotype = UPIO_PORT;
diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c
index 557bf961f36a..6f8a9fe7c1e3 100644
--- a/arch/mips/mips-boards/generic/time.c
+++ b/arch/mips/mips-boards/generic/time.c
@@ -30,7 +30,6 @@
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
-#include <asm/ptrace.h>
#include <asm/hardirq.h>
#include <asm/irq.h>
#include <asm/div64.h>
@@ -41,8 +40,13 @@
#include <asm/mips-boards/generic.h>
#include <asm/mips-boards/prom.h>
+
+#ifdef CONFIG_MIPS_ATLAS
+#include <asm/mips-boards/atlasint.h>
+#endif
+#ifdef CONFIG_MIPS_MALTA
#include <asm/mips-boards/maltaint.h>
-#include <asm/mc146818-time.h>
+#endif
unsigned long cpu_khz;
@@ -77,25 +81,24 @@ static inline void scroll_display_message(void)
}
}
-static void mips_timer_dispatch (struct pt_regs *regs)
+static void mips_timer_dispatch(void)
{
- do_IRQ (mips_cpu_timer_irq, regs);
+ do_IRQ(mips_cpu_timer_irq);
}
/*
* Redeclare until I get around mopping the timer code insanity on MIPS.
*/
-extern int null_perf_irq(struct pt_regs *regs);
+extern int null_perf_irq(void);
-extern int (*perf_irq)(struct pt_regs *regs);
+extern int (*perf_irq)(void);
-irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t mips_timer_interrupt(int irq, void *dev_id)
{
int cpu = smp_processor_id();
- int r2 = cpu_has_mips_r2;
#ifdef CONFIG_MIPS_MT_SMTC
- /*
+ /*
* In an SMTC system, one Count/Compare set exists per VPE.
* Which TC within a VPE gets the interrupt is essentially
* random - we only know that it shouldn't be one with
@@ -108,29 +111,46 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* the general MIPS timer_interrupt routine.
*/
+ int vpflags;
+
/*
- * DVPE is necessary so long as cross-VPE interrupts
- * are done via read-modify-write of Cause register.
+ * We could be here due to timer interrupt,
+ * perf counter overflow, or both.
*/
- int vpflags = dvpe();
- write_c0_compare (read_c0_count() - 1);
- clear_c0_cause(CPUCTR_IMASKBIT);
- evpe(vpflags);
+ if (read_c0_cause() & (1 << 26))
+ perf_irq();
- if (cpu_data[cpu].vpe_id == 0) {
- timer_interrupt(irq, dev_id, regs);
- scroll_display_message();
- } else
- write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
- smtc_timer_broadcast(cpu_data[cpu].vpe_id);
-
- if (cpu != 0)
+ if (read_c0_cause() & (1 << 30)) {
+ /* If timer interrupt, make it de-assert */
+ write_c0_compare (read_c0_count() - 1);
/*
- * Other CPUs should do profiling and process accounting
+ * DVPE is necessary so long as cross-VPE interrupts
+ * are done via read-modify-write of Cause register.
*/
- local_timer_interrupt(irq, dev_id, regs);
-
+ vpflags = dvpe();
+ clear_c0_cause(CPUCTR_IMASKBIT);
+ evpe(vpflags);
+ /*
+ * There are things we only want to do once per tick
+ * in an "MP" system. One TC of each VPE will take
+ * the actual timer interrupt. The others will get
+ * timer broadcast IPIs. We use whoever it is that takes
+ * the tick on VPE 0 to run the full timer_interrupt().
+ */
+ if (cpu_data[cpu].vpe_id == 0) {
+ timer_interrupt(irq, NULL);
+ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+ scroll_display_message();
+ } else {
+ write_c0_compare(read_c0_count() +
+ (mips_hpt_frequency/HZ));
+ local_timer_interrupt(irq, dev_id);
+ smtc_timer_broadcast(cpu_data[cpu].vpe_id);
+ }
+ }
#else /* CONFIG_MIPS_MT_SMTC */
+ int r2 = cpu_has_mips_r2;
+
if (cpu == 0) {
/*
* CPU 0 handles the global timer interrupt job and process
@@ -138,12 +158,12 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* timer int.
*/
if (!r2 || (read_c0_cause() & (1 << 26)))
- if (perf_irq(regs))
+ if (perf_irq())
goto out;
/* we keep interrupt disabled all the time */
if (!r2 || (read_c0_cause() & (1 << 30)))
- timer_interrupt(irq, NULL, regs);
+ timer_interrupt(irq, NULL);
scroll_display_message();
} else {
@@ -159,11 +179,10 @@ irqreturn_t mips_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*
* Other CPUs should do profiling and process accounting
*/
- local_timer_interrupt(irq, dev_id, regs);
+ local_timer_interrupt(irq, dev_id);
}
-#endif /* CONFIG_MIPS_MT_SMTC */
-
out:
+#endif /* CONFIG_MIPS_MT_SMTC */
return IRQ_HANDLED;
}
diff --git a/arch/mips/mips-boards/malta/malta_int.c b/arch/mips/mips-boards/malta/malta_int.c
index 7cc0ba4f553a..90ad5bf3e2f1 100644
--- a/arch/mips/mips-boards/malta/malta_int.c
+++ b/arch/mips/mips-boards/malta/malta_int.c
@@ -32,6 +32,7 @@
#include <asm/i8259.h>
#include <asm/irq_cpu.h>
#include <asm/io.h>
+#include <asm/irq_regs.h>
#include <asm/mips-boards/malta.h>
#include <asm/mips-boards/maltaint.h>
#include <asm/mips-boards/piix4.h>
@@ -114,7 +115,7 @@ static inline int get_int(void)
return irq;
}
-static void malta_hw0_irqdispatch(struct pt_regs *regs)
+static void malta_hw0_irqdispatch(void)
{
int irq;
@@ -123,17 +124,21 @@ static void malta_hw0_irqdispatch(struct pt_regs *regs)
return; /* interrupt has already been cleared */
}
- do_IRQ(MALTA_INT_BASE+irq, regs);
+ do_IRQ(MALTA_INT_BASE + irq);
}
-void corehi_irqdispatch(struct pt_regs *regs)
+static void corehi_irqdispatch(void)
{
+ unsigned int intedge, intsteer, pcicmd, pcibadaddr;
+ unsigned int pcimstat, intisr, inten, intpol;
unsigned int intrcause,datalo,datahi;
- unsigned int pcimstat, intisr, inten, intpol, intedge, intsteer, pcicmd, pcibadaddr;
+ struct pt_regs *regs = get_irq_regs();
printk("CoreHI interrupt, shouldn't happen, so we die here!!!\n");
- printk("epc : %08lx\nStatus: %08lx\nCause : %08lx\nbadVaddr : %08lx\n"
-, regs->cp0_epc, regs->cp0_status, regs->cp0_cause, regs->cp0_badvaddr);
+ printk("epc : %08lx\nStatus: %08lx\n"
+ "Cause : %08lx\nbadVaddr : %08lx\n",
+ regs->cp0_epc, regs->cp0_status,
+ regs->cp0_cause, regs->cp0_badvaddr);
/* Read all the registers and then print them as there is a
problem with interspersed printk's upsetting the Bonito controller.
@@ -146,7 +151,7 @@ void corehi_irqdispatch(struct pt_regs *regs)
case MIPS_REVISION_CORID_CORE_FPGA3:
case MIPS_REVISION_CORID_CORE_24K:
case MIPS_REVISION_CORID_CORE_EMUL_MSC:
- ll_msc_irq(regs);
+ ll_msc_irq();
break;
case MIPS_REVISION_CORID_QED_RM5261:
case MIPS_REVISION_CORID_CORE_LV:
@@ -208,23 +213,23 @@ static inline unsigned int irq_ffs(unsigned int pending)
unsigned int a0 = 7;
unsigned int t0;
- t0 = s0 & 0xf000;
+ t0 = pending & 0xf000;
t0 = t0 < 1;
t0 = t0 << 2;
a0 = a0 - t0;
- s0 = s0 << t0;
+ pending = pending << t0;
- t0 = s0 & 0xc000;
+ t0 = pending & 0xc000;
t0 = t0 < 1;
t0 = t0 << 1;
a0 = a0 - t0;
- s0 = s0 << t0;
+ pending = pending << t0;
- t0 = s0 & 0x8000;
+ t0 = pending & 0x8000;
t0 = t0 < 1;
//t0 = t0 << 2;
a0 = a0 - t0;
- //s0 = s0 << t0;
+ //pending = pending << t0;
return a0;
#endif
@@ -255,7 +260,7 @@ static inline unsigned int irq_ffs(unsigned int pending)
* another exception, big deal.
*/
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
@@ -263,11 +268,11 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
irq = irq_ffs(pending);
if (irq == MIPSCPU_INT_I8259A)
- malta_hw0_irqdispatch(regs);
+ malta_hw0_irqdispatch();
else if (irq > 0)
- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ do_IRQ(MIPSCPU_INT_BASE + irq);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
static struct irqaction i8259irq = {
diff --git a/arch/mips/mips-boards/sead/sead_int.c b/arch/mips/mips-boards/sead/sead_int.c
index 9168d934c661..f445fcddfdfd 100644
--- a/arch/mips/mips-boards/sead/sead_int.c
+++ b/arch/mips/mips-boards/sead/sead_int.c
@@ -98,7 +98,7 @@ static inline unsigned int irq_ffs(unsigned int pending)
* then we just return, if multiple IRQs are pending then we will just take
* another exception, big deal.
*/
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
@@ -106,7 +106,7 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
irq = irq_ffs(pending);
if (irq >= 0)
- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ do_IRQ(MIPSCPU_INT_BASE + irq);
else
spurious_interrupt(regs);
}
diff --git a/arch/mips/mips-boards/sim/sim_int.c b/arch/mips/mips-boards/sim/sim_int.c
index 2c15c8efec4e..2ce449dce6f2 100644
--- a/arch/mips/mips-boards/sim/sim_int.c
+++ b/arch/mips/mips-boards/sim/sim_int.c
@@ -71,12 +71,7 @@ static inline unsigned int irq_ffs(unsigned int pending)
#endif
}
-static inline void sim_hw0_irqdispatch(struct pt_regs *regs)
-{
- do_IRQ(2, regs);
-}
-
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
int irq;
@@ -84,9 +79,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
irq = irq_ffs(pending);
if (irq > 0)
- do_IRQ(MIPSCPU_INT_BASE + irq, regs);
+ do_IRQ(MIPSCPU_INT_BASE + irq);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
void __init arch_init_irq(void)
diff --git a/arch/mips/mips-boards/sim/sim_time.c b/arch/mips/mips-boards/sim/sim_time.c
index 230929ecd57f..c566b9bd0427 100644
--- a/arch/mips/mips-boards/sim/sim_time.c
+++ b/arch/mips/mips-boards/sim/sim_time.c
@@ -15,7 +15,6 @@
#include <linux/mc146818rtc.h>
#include <linux/timex.h>
#include <asm/mipsregs.h>
-#include <asm/ptrace.h>
#include <asm/hardirq.h>
#include <asm/irq.h>
#include <asm/div64.h>
@@ -33,7 +32,7 @@
unsigned long cpu_khz;
-irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t sim_timer_interrupt(int irq, void *dev_id)
{
#ifdef CONFIG_SMP
int cpu = smp_processor_id();
@@ -44,7 +43,7 @@ irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/
#ifndef CONFIG_MIPS_MT_SMTC
if (cpu == 0) {
- timer_interrupt(irq, dev_id, regs);
+ timer_interrupt(irq, dev_id);
}
else {
/* Everyone else needs to reset the timer int here as
@@ -84,7 +83,7 @@ irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
irq_enable_hazard();
evpe(vpflags);
- if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id, regs);
+ if(cpu_data[cpu].vpe_id == 0) timer_interrupt(irq, dev_id);
else write_c0_compare (read_c0_count() + ( mips_hpt_frequency/HZ));
smtc_timer_broadcast(cpu_data[cpu].vpe_id);
@@ -93,10 +92,10 @@ irqreturn_t sim_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/*
* every CPU should do profiling and process accounting
*/
- local_timer_interrupt (irq, dev_id, regs);
+ local_timer_interrupt (irq, dev_id);
return IRQ_HANDLED;
#else
- return timer_interrupt (irq, dev_id, regs);
+ return timer_interrupt (irq, dev_id);
#endif
}
@@ -177,9 +176,9 @@ void __init sim_time_init(void)
static int mips_cpu_timer_irq;
-static void mips_timer_dispatch (struct pt_regs *regs)
+static void mips_timer_dispatch(void)
{
- do_IRQ (mips_cpu_timer_irq, regs);
+ do_IRQ(mips_cpu_timer_irq);
}
diff --git a/arch/mips/mm/c-r3k.c b/arch/mips/mm/c-r3k.c
index bb041a22f20a..d1af42c2a52e 100644
--- a/arch/mips/mm/c-r3k.c
+++ b/arch/mips/mm/c-r3k.c
@@ -268,26 +268,6 @@ static void r3k_flush_data_cache_page(unsigned long addr)
{
}
-static void r3k_flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
- struct mm_struct *mm = vma->vm_mm;
- unsigned long physpage;
-
- if (cpu_context(smp_processor_id(), mm) == 0)
- return;
-
- if (!(vma->vm_flags & VM_EXEC))
- return;
-
-#ifdef DEBUG_CACHE
- printk("cpage[%d,%08lx]", cpu_context(smp_processor_id(), mm), page);
-#endif
-
- physpage = (unsigned long) page_address(page);
- if (physpage)
- r3k_flush_icache_range(physpage, physpage + PAGE_SIZE);
-}
-
static void r3k_flush_cache_sigtramp(unsigned long addr)
{
unsigned long flags;
@@ -335,7 +315,6 @@ void __init r3k_cache_init(void)
flush_cache_mm = r3k_flush_cache_mm;
flush_cache_range = r3k_flush_cache_range;
flush_cache_page = r3k_flush_cache_page;
- flush_icache_page = r3k_flush_icache_page;
flush_icache_range = r3k_flush_icache_range;
flush_cache_sigtramp = r3k_flush_cache_sigtramp;
diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c
index 069803f58f3b..cc895dad71d2 100644
--- a/arch/mips/mm/c-r4k.c
+++ b/arch/mips/mm/c-r4k.c
@@ -89,7 +89,7 @@ static inline void r4k_blast_dcache_page_dc32(unsigned long addr)
blast_dcache32_page(addr);
}
-static inline void r4k_blast_dcache_page_setup(void)
+static void __init r4k_blast_dcache_page_setup(void)
{
unsigned long dc_lsize = cpu_dcache_line_size();
@@ -103,7 +103,7 @@ static inline void r4k_blast_dcache_page_setup(void)
static void (* r4k_blast_dcache_page_indexed)(unsigned long addr);
-static inline void r4k_blast_dcache_page_indexed_setup(void)
+static void __init r4k_blast_dcache_page_indexed_setup(void)
{
unsigned long dc_lsize = cpu_dcache_line_size();
@@ -117,7 +117,7 @@ static inline void r4k_blast_dcache_page_indexed_setup(void)
static void (* r4k_blast_dcache)(void);
-static inline void r4k_blast_dcache_setup(void)
+static void __init r4k_blast_dcache_setup(void)
{
unsigned long dc_lsize = cpu_dcache_line_size();
@@ -202,7 +202,7 @@ static inline void tx49_blast_icache32_page_indexed(unsigned long page)
static void (* r4k_blast_icache_page)(unsigned long addr);
-static inline void r4k_blast_icache_page_setup(void)
+static void __init r4k_blast_icache_page_setup(void)
{
unsigned long ic_lsize = cpu_icache_line_size();
@@ -219,7 +219,7 @@ static inline void r4k_blast_icache_page_setup(void)
static void (* r4k_blast_icache_page_indexed)(unsigned long addr);
-static inline void r4k_blast_icache_page_indexed_setup(void)
+static void __init r4k_blast_icache_page_indexed_setup(void)
{
unsigned long ic_lsize = cpu_icache_line_size();
@@ -243,7 +243,7 @@ static inline void r4k_blast_icache_page_indexed_setup(void)
static void (* r4k_blast_icache)(void);
-static inline void r4k_blast_icache_setup(void)
+static void __init r4k_blast_icache_setup(void)
{
unsigned long ic_lsize = cpu_icache_line_size();
@@ -264,7 +264,7 @@ static inline void r4k_blast_icache_setup(void)
static void (* r4k_blast_scache_page)(unsigned long addr);
-static inline void r4k_blast_scache_page_setup(void)
+static void __init r4k_blast_scache_page_setup(void)
{
unsigned long sc_lsize = cpu_scache_line_size();
@@ -282,7 +282,7 @@ static inline void r4k_blast_scache_page_setup(void)
static void (* r4k_blast_scache_page_indexed)(unsigned long addr);
-static inline void r4k_blast_scache_page_indexed_setup(void)
+static void __init r4k_blast_scache_page_indexed_setup(void)
{
unsigned long sc_lsize = cpu_scache_line_size();
@@ -300,7 +300,7 @@ static inline void r4k_blast_scache_page_indexed_setup(void)
static void (* r4k_blast_scache)(void);
-static inline void r4k_blast_scache_setup(void)
+static void __init r4k_blast_scache_setup(void)
{
unsigned long sc_lsize = cpu_scache_line_size();
@@ -475,7 +475,7 @@ static inline void local_r4k_flush_cache_page(void *args)
}
}
if (exec) {
- if (cpu_has_vtag_icache) {
+ if (cpu_has_vtag_icache && mm == current->active_mm) {
int cpu = smp_processor_id();
if (cpu_context(cpu, mm) != 0)
@@ -551,82 +551,6 @@ static void r4k_flush_icache_range(unsigned long start, unsigned long end)
instruction_hazard();
}
-/*
- * Ok, this seriously sucks. We use them to flush a user page but don't
- * know the virtual address, so we have to blast away the whole icache
- * which is significantly more expensive than the real thing. Otoh we at
- * least know the kernel address of the page so we can flush it
- * selectivly.
- */
-
-struct flush_icache_page_args {
- struct vm_area_struct *vma;
- struct page *page;
-};
-
-static inline void local_r4k_flush_icache_page(void *args)
-{
- struct flush_icache_page_args *fip_args = args;
- struct vm_area_struct *vma = fip_args->vma;
- struct page *page = fip_args->page;
-
- /*
- * Tricky ... Because we don't know the virtual address we've got the
- * choice of either invalidating the entire primary and secondary
- * caches or invalidating the secondary caches also. With the subset
- * enforcment on R4000SC, R4400SC, R10000 and R12000 invalidating the
- * secondary cache will result in any entries in the primary caches
- * also getting invalidated which hopefully is a bit more economical.
- */
- if (cpu_has_inclusive_pcaches) {
- unsigned long addr = (unsigned long) page_address(page);
-
- r4k_blast_scache_page(addr);
- ClearPageDcacheDirty(page);
-
- return;
- }
-
- if (!cpu_has_ic_fills_f_dc) {
- unsigned long addr = (unsigned long) page_address(page);
- r4k_blast_dcache_page(addr);
- if (!cpu_icache_snoops_remote_store)
- r4k_blast_scache_page(addr);
- ClearPageDcacheDirty(page);
- }
-
- /*
- * We're not sure of the virtual address(es) involved here, so
- * we have to flush the entire I-cache.
- */
- if (cpu_has_vtag_icache) {
- int cpu = smp_processor_id();
-
- if (cpu_context(cpu, vma->vm_mm) != 0)
- drop_mmu_context(vma->vm_mm, cpu);
- } else
- r4k_blast_icache();
-}
-
-static void r4k_flush_icache_page(struct vm_area_struct *vma,
- struct page *page)
-{
- struct flush_icache_page_args args;
-
- /*
- * If there's no context yet, or the page isn't executable, no I-cache
- * flush is needed.
- */
- if (!(vma->vm_flags & VM_EXEC))
- return;
-
- args.vma = vma;
- args.page = page;
-
- r4k_on_each_cpu(local_r4k_flush_icache_page, &args, 1, 1);
-}
-
-
#ifdef CONFIG_DMA_NONCOHERENT
static void r4k_dma_cache_wback_inv(unsigned long addr, unsigned long size)
@@ -1221,7 +1145,7 @@ void au1x00_fixup_config_od(void)
}
}
-static inline void coherency_setup(void)
+static void __init coherency_setup(void)
{
change_c0_config(CONF_CM_CMASK, CONF_CM_DEFAULT);
@@ -1242,7 +1166,7 @@ static inline void coherency_setup(void)
clear_c0_config(CONF_CU);
break;
/*
- * We need to catch the ealry Alchemy SOCs with
+ * We need to catch the early Alchemy SOCs with
* the write-only co_config.od bit and set it back to one...
*/
case CPU_AU1000: /* rev. DA, HA, HB */
@@ -1291,7 +1215,6 @@ void __init r4k_cache_init(void)
__flush_cache_all = r4k___flush_cache_all;
flush_cache_mm = r4k_flush_cache_mm;
flush_cache_page = r4k_flush_cache_page;
- flush_icache_page = r4k_flush_icache_page;
flush_cache_range = r4k_flush_cache_range;
flush_cache_sigtramp = r4k_flush_cache_sigtramp;
diff --git a/arch/mips/mm/c-sb1.c b/arch/mips/mm/c-sb1.c
index 2d71efb82ac5..5537558f19f7 100644
--- a/arch/mips/mm/c-sb1.c
+++ b/arch/mips/mm/c-sb1.c
@@ -155,6 +155,26 @@ static inline void __sb1_flush_icache_all(void)
}
/*
+ * Invalidate a range of the icache. The addresses are virtual, and
+ * the cache is virtually indexed and tagged. However, we don't
+ * necessarily have the right ASID context, so use index ops instead
+ * of hit ops.
+ */
+static inline void __sb1_flush_icache_range(unsigned long start,
+ unsigned long end)
+{
+ start &= ~(icache_line_size - 1);
+ end = (end + icache_line_size - 1) & ~(icache_line_size - 1);
+
+ while (start != end) {
+ cache_set_op(Index_Invalidate_I, start & icache_index_mask);
+ start += icache_line_size;
+ }
+ mispredict();
+ sync();
+}
+
+/*
* Flush the icache for a given physical page. Need to writeback the
* dcache first, then invalidate the icache. If the page isn't
* executable, nothing is required.
@@ -173,8 +193,11 @@ static void local_sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long
/*
* Bumping the ASID is probably cheaper than the flush ...
*/
- if (cpu_context(cpu, vma->vm_mm) != 0)
- drop_mmu_context(vma->vm_mm, cpu);
+ if (vma->vm_mm == current->active_mm) {
+ if (cpu_context(cpu, vma->vm_mm) != 0)
+ drop_mmu_context(vma->vm_mm, cpu);
+ } else
+ __sb1_flush_icache_range(addr, addr + PAGE_SIZE);
}
#ifdef CONFIG_SMP
@@ -210,26 +233,6 @@ void sb1_flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsign
__attribute__((alias("local_sb1_flush_cache_page")));
#endif
-/*
- * Invalidate a range of the icache. The addresses are virtual, and
- * the cache is virtually indexed and tagged. However, we don't
- * necessarily have the right ASID context, so use index ops instead
- * of hit ops.
- */
-static inline void __sb1_flush_icache_range(unsigned long start,
- unsigned long end)
-{
- start &= ~(icache_line_size - 1);
- end = (end + icache_line_size - 1) & ~(icache_line_size - 1);
-
- while (start != end) {
- cache_set_op(Index_Invalidate_I, start & icache_index_mask);
- start += icache_line_size;
- }
- mispredict();
- sync();
-}
-
/*
* Invalidate all caches on this CPU
@@ -304,63 +307,6 @@ void sb1_flush_icache_range(unsigned long start, unsigned long end)
#endif
/*
- * Flush the icache for a given physical page. Need to writeback the
- * dcache first, then invalidate the icache. If the page isn't
- * executable, nothing is required.
- */
-static void local_sb1_flush_icache_page(struct vm_area_struct *vma,
- struct page *page)
-{
- unsigned long start;
- int cpu = smp_processor_id();
-
-#ifndef CONFIG_SMP
- if (!(vma->vm_flags & VM_EXEC))
- return;
-#endif
-
- /* Need to writeback any dirty data for that page, we have the PA */
- start = (unsigned long)(page-mem_map) << PAGE_SHIFT;
- __sb1_writeback_inv_dcache_phys_range(start, start + PAGE_SIZE);
- /*
- * If there's a context, bump the ASID (cheaper than a flush,
- * since we don't know VAs!)
- */
- if (cpu_context(cpu, vma->vm_mm) != 0) {
- drop_mmu_context(vma->vm_mm, cpu);
- }
-}
-
-#ifdef CONFIG_SMP
-struct flush_icache_page_args {
- struct vm_area_struct *vma;
- struct page *page;
-};
-
-static void sb1_flush_icache_page_ipi(void *info)
-{
- struct flush_icache_page_args *args = info;
- local_sb1_flush_icache_page(args->vma, args->page);
-}
-
-/* Dirty dcache could be on another CPU, so do the IPIs */
-static void sb1_flush_icache_page(struct vm_area_struct *vma,
- struct page *page)
-{
- struct flush_icache_page_args args;
-
- if (!(vma->vm_flags & VM_EXEC))
- return;
- args.vma = vma;
- args.page = page;
- on_each_cpu(sb1_flush_icache_page_ipi, (void *) &args, 1, 1);
-}
-#else
-void sb1_flush_icache_page(struct vm_area_struct *vma, struct page *page)
- __attribute__((alias("local_sb1_flush_icache_page")));
-#endif
-
-/*
* A signal trampoline must fit into a single cacheline.
*/
static void local_sb1_flush_cache_sigtramp(unsigned long addr)
@@ -520,7 +466,6 @@ void sb1_cache_init(void)
/* These routines are for Icache coherence with the Dcache */
flush_icache_range = sb1_flush_icache_range;
- flush_icache_page = sb1_flush_icache_page;
flush_icache_all = __sb1_flush_icache_all; /* local only */
/* This implies an Icache flush too, so can't be nop'ed */
diff --git a/arch/mips/mm/c-tx39.c b/arch/mips/mm/c-tx39.c
index 5dfc9b1901f6..f32ebde30ccf 100644
--- a/arch/mips/mm/c-tx39.c
+++ b/arch/mips/mm/c-tx39.c
@@ -248,33 +248,6 @@ static void tx39_flush_icache_range(unsigned long start, unsigned long end)
}
}
-/*
- * Ok, this seriously sucks. We use them to flush a user page but don't
- * know the virtual address, so we have to blast away the whole icache
- * which is significantly more expensive than the real thing. Otoh we at
- * least know the kernel address of the page so we can flush it
- * selectivly.
- */
-static void tx39_flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
- unsigned long addr;
- /*
- * If there's no context yet, or the page isn't executable, no icache
- * flush is needed.
- */
- if (!(vma->vm_flags & VM_EXEC))
- return;
-
- addr = (unsigned long) page_address(page);
- tx39_blast_dcache_page(addr);
-
- /*
- * We're not sure of the virtual address(es) involved here, so
- * we have to flush the entire I-cache.
- */
- tx39_blast_icache();
-}
-
static void tx39_dma_cache_wback_inv(unsigned long addr, unsigned long size)
{
unsigned long end;
@@ -382,7 +355,6 @@ void __init tx39_cache_init(void)
flush_cache_mm = (void *) tx39h_flush_icache_all;
flush_cache_range = (void *) tx39h_flush_icache_all;
flush_cache_page = (void *) tx39h_flush_icache_all;
- flush_icache_page = (void *) tx39h_flush_icache_all;
flush_icache_range = (void *) tx39h_flush_icache_all;
flush_cache_sigtramp = (void *) tx39h_flush_icache_all;
@@ -408,7 +380,6 @@ void __init tx39_cache_init(void)
flush_cache_mm = tx39_flush_cache_mm;
flush_cache_range = tx39_flush_cache_range;
flush_cache_page = tx39_flush_cache_page;
- flush_icache_page = tx39_flush_icache_page;
flush_icache_range = tx39_flush_icache_range;
flush_cache_sigtramp = tx39_flush_cache_sigtramp;
diff --git a/arch/mips/mm/cache.c b/arch/mips/mm/cache.c
index ddd3a2de1d73..caf807ded514 100644
--- a/arch/mips/mm/cache.c
+++ b/arch/mips/mm/cache.c
@@ -25,7 +25,6 @@ void (*flush_cache_range)(struct vm_area_struct *vma, unsigned long start,
void (*flush_cache_page)(struct vm_area_struct *vma, unsigned long page,
unsigned long pfn);
void (*flush_icache_range)(unsigned long start, unsigned long end);
-void (*flush_icache_page)(struct vm_area_struct *vma, struct page *page);
/* MIPS specific cache operations */
void (*flush_cache_sigtramp)(unsigned long addr);
@@ -70,6 +69,8 @@ void __flush_dcache_page(struct page *page)
struct address_space *mapping = page_mapping(page);
unsigned long addr;
+ if (PageHighMem(page))
+ return;
if (mapping && !mapping_mapped(mapping)) {
SetPageDcacheDirty(page);
return;
@@ -91,16 +92,16 @@ void __update_cache(struct vm_area_struct *vma, unsigned long address,
{
struct page *page;
unsigned long pfn, addr;
+ int exec = (vma->vm_flags & VM_EXEC) && !cpu_has_ic_fills_f_dc;
pfn = pte_pfn(pte);
- if (pfn_valid(pfn) && (page = pfn_to_page(pfn), page_mapping(page)) &&
- Page_dcache_dirty(page)) {
- if (pages_do_alias((unsigned long)page_address(page),
- address & PAGE_MASK)) {
- addr = (unsigned long) page_address(page);
+ if (unlikely(!pfn_valid(pfn)))
+ return;
+ page = pfn_to_page(pfn);
+ if (page_mapping(page) && Page_dcache_dirty(page)) {
+ addr = (unsigned long) page_address(page);
+ if (exec || pages_do_alias(addr, address & PAGE_MASK))
flush_data_cache_page(addr);
- }
-
ClearPageDcacheDirty(page);
}
}
diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c
index e3a617224868..8423d8590779 100644
--- a/arch/mips/mm/fault.c
+++ b/arch/mips/mm/fault.c
@@ -89,7 +89,7 @@ good_area:
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
} else {
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_WRITE | VM_EXEC)))
goto bad_area;
}
@@ -171,7 +171,7 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (tsk->pid == 1) {
+ if (is_init(tsk)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 5b06349af2d5..88b72c9a8495 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -163,10 +163,10 @@ static int __init page_is_ram(unsigned long pagenr)
void __init paging_init(void)
{
- unsigned long zones_size[] = { 0, };
+ unsigned long zones_size[MAX_NR_ZONES] = { 0, };
unsigned long max_dma, high, low;
#ifndef CONFIG_FLATMEM
- unsigned long zholes_size[] = { 0, };
+ unsigned long zholes_size[MAX_NR_ZONES] = { 0, };
unsigned long i, j, pfn;
#endif
diff --git a/arch/mips/mm/ioremap.c b/arch/mips/mm/ioremap.c
index 3101d1db5592..cea7d0ea36e4 100644
--- a/arch/mips/mm/ioremap.c
+++ b/arch/mips/mm/ioremap.c
@@ -176,7 +176,7 @@ void __iomem * __ioremap(phys_t phys_addr, phys_t size, unsigned long flags)
#define IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1)
-void __iounmap(volatile void __iomem *addr)
+void __iounmap(const volatile void __iomem *addr)
{
struct vm_struct *p;
diff --git a/arch/mips/mm/tlb-r4k.c b/arch/mips/mm/tlb-r4k.c
index 2cde1b772443..2e0e21ef433e 100644
--- a/arch/mips/mm/tlb-r4k.c
+++ b/arch/mips/mm/tlb-r4k.c
@@ -26,11 +26,6 @@ extern void build_tlb_refill_handler(void);
*/
#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
-/* CP0 hazard avoidance. */
-#define BARRIER __asm__ __volatile__(".set noreorder\n\t" \
- "nop; nop; nop; nop; nop; nop;\n\t" \
- ".set reorder\n\t")
-
/* Atomicity and interruptability */
#ifdef CONFIG_MIPS_MT_SMTC
@@ -126,7 +121,7 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
start += (PAGE_SIZE << 1);
mtc0_tlbw_hazard();
tlb_probe();
- BARRIER;
+ tlb_probe_hazard();
idx = read_c0_index();
write_c0_entrylo0(0);
write_c0_entrylo1(0);
@@ -168,7 +163,7 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
start += (PAGE_SIZE << 1);
mtc0_tlbw_hazard();
tlb_probe();
- BARRIER;
+ tlb_probe_hazard();
idx = read_c0_index();
write_c0_entrylo0(0);
write_c0_entrylo1(0);
@@ -202,7 +197,7 @@ void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
write_c0_entryhi(page | newpid);
mtc0_tlbw_hazard();
tlb_probe();
- BARRIER;
+ tlb_probe_hazard();
idx = read_c0_index();
write_c0_entrylo0(0);
write_c0_entrylo1(0);
@@ -235,7 +230,7 @@ void local_flush_tlb_one(unsigned long page)
write_c0_entryhi(page);
mtc0_tlbw_hazard();
tlb_probe();
- BARRIER;
+ tlb_probe_hazard();
idx = read_c0_index();
write_c0_entrylo0(0);
write_c0_entrylo1(0);
@@ -279,7 +274,7 @@ void __update_tlb(struct vm_area_struct * vma, unsigned long address, pte_t pte)
pgdp = pgd_offset(vma->vm_mm, address);
mtc0_tlbw_hazard();
tlb_probe();
- BARRIER;
+ tlb_probe_hazard();
pudp = pud_offset(pgdp, address);
pmdp = pmd_offset(pudp, address);
idx = read_c0_index();
@@ -320,7 +315,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma,
pgdp = pgd_offset(vma->vm_mm, address);
mtc0_tlbw_hazard();
tlb_probe();
- BARRIER;
+ tlb_probe_hazard();
pmdp = pmd_offset(pgdp, address);
idx = read_c0_index();
ptep = pte_offset_map(pmdp, address);
@@ -351,7 +346,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
wired = read_c0_wired();
write_c0_wired(wired + 1);
write_c0_index(wired);
- BARRIER;
+ tlbw_use_hazard(); /* What is the hazard here? */
write_c0_pagemask(pagemask);
write_c0_entryhi(entryhi);
write_c0_entrylo0(entrylo0);
@@ -361,7 +356,7 @@ void __init add_wired_entry(unsigned long entrylo0, unsigned long entrylo1,
tlbw_use_hazard();
write_c0_entryhi(old_ctx);
- BARRIER;
+ tlbw_use_hazard(); /* What is the hazard here? */
write_c0_pagemask(old_pagemask);
local_flush_tlb_all();
EXIT_CRITICAL(flags);
diff --git a/arch/mips/mm/tlbex-fault.S b/arch/mips/mm/tlbex-fault.S
index 9e7f4175b493..e99eaa1fbedc 100644
--- a/arch/mips/mm/tlbex-fault.S
+++ b/arch/mips/mm/tlbex-fault.S
@@ -19,8 +19,8 @@
move a0, sp
REG_S a2, PT_BVADDR(sp)
li a1, \write
- jal do_page_fault
- j ret_from_exception
+ PTR_LA ra, ret_from_exception
+ j do_page_fault
END(tlb_do_page_fault_\write)
.endm
diff --git a/arch/mips/mm/tlbex.c b/arch/mips/mm/tlbex.c
index 375e0991505d..6f8b25cfa6f0 100644
--- a/arch/mips/mm/tlbex.c
+++ b/arch/mips/mm/tlbex.c
@@ -1211,7 +1211,7 @@ static void __init build_r4000_tlb_refill_handler(void)
* Overflow check: For the 64bit handler, we need at least one
* free instruction slot for the wrap-around branch. In worst
* case, if the intended insertion point is a delay slot, we
- * need three, with the the second nop'ed and the third being
+ * need three, with the second nop'ed and the third being
* unused.
*/
#ifdef CONFIG_32BIT
diff --git a/arch/mips/momentum/jaguar_atx/irq.c b/arch/mips/momentum/jaguar_atx/irq.c
index f9067469a656..2efb25aa1aed 100644
--- a/arch/mips/momentum/jaguar_atx/irq.c
+++ b/arch/mips/momentum/jaguar_atx/irq.c
@@ -40,33 +40,33 @@
#include <asm/mipsregs.h>
#include <asm/time.h>
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP0)
- do_IRQ(0, regs);
+ do_IRQ(0);
else if (pending & STATUSF_IP1)
- do_IRQ(1, regs);
+ do_IRQ(1);
else if (pending & STATUSF_IP2)
- do_IRQ(2, regs);
+ do_IRQ(2);
else if (pending & STATUSF_IP3)
- do_IRQ(3, regs);
+ do_IRQ(3);
else if (pending & STATUSF_IP4)
- do_IRQ(4, regs);
+ do_IRQ(4);
else if (pending & STATUSF_IP5)
- do_IRQ(5, regs);
+ do_IRQ(5);
else if (pending & STATUSF_IP6)
- do_IRQ(6, regs);
+ do_IRQ(6);
else if (pending & STATUSF_IP7)
- ll_timer_interrupt(7, regs);
+ ll_timer_interrupt(7);
else {
/*
* Now look at the extended interrupts
*/
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8)
- ll_mv64340_irq(regs);
+ ll_mv64340_irq();
}
}
diff --git a/arch/mips/momentum/jaguar_atx/setup.c b/arch/mips/momentum/jaguar_atx/setup.c
index e6fe2992227d..5a510142b978 100644
--- a/arch/mips/momentum/jaguar_atx/setup.c
+++ b/arch/mips/momentum/jaguar_atx/setup.c
@@ -62,7 +62,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/tlbflush.h>
diff --git a/arch/mips/momentum/ocelot_3/irq.c b/arch/mips/momentum/ocelot_3/irq.c
index 793782a9c195..cea0e5deb80e 100644
--- a/arch/mips/momentum/ocelot_3/irq.c
+++ b/arch/mips/momentum/ocelot_3/irq.c
@@ -75,26 +75,26 @@ void __init arch_init_irq(void)
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP0)
- do_IRQ(0, regs);
+ do_IRQ(0);
else if (pending & STATUSF_IP1)
- do_IRQ(1, regs);
+ do_IRQ(1);
else if (pending & STATUSF_IP2)
- do_IRQ(2, regs);
+ do_IRQ(2);
else if (pending & STATUSF_IP3)
- do_IRQ(3, regs);
+ do_IRQ(3);
else if (pending & STATUSF_IP4)
- do_IRQ(4, regs);
+ do_IRQ(4);
else if (pending & STATUSF_IP5)
- do_IRQ(5, regs);
+ do_IRQ(5);
else if (pending & STATUSF_IP6)
- do_IRQ(6, regs);
+ do_IRQ(6);
else if (pending & STATUSF_IP7)
- do_IRQ(7, regs);
+ do_IRQ(7);
else {
/*
* Now look at the extended interrupts
@@ -102,8 +102,8 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8)
- ll_mv64340_irq(regs);
+ ll_mv64340_irq();
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
}
diff --git a/arch/mips/momentum/ocelot_3/setup.c b/arch/mips/momentum/ocelot_3/setup.c
index 435d0787329e..7d74f8c54129 100644
--- a/arch/mips/momentum/ocelot_3/setup.c
+++ b/arch/mips/momentum/ocelot_3/setup.c
@@ -67,7 +67,6 @@
#include <asm/irq.h>
#include <asm/pci.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/mc146818rtc.h>
#include <asm/tlbflush.h>
diff --git a/arch/mips/momentum/ocelot_c/cpci-irq.c b/arch/mips/momentum/ocelot_c/cpci-irq.c
index a5dc230520df..47e3fa32b075 100644
--- a/arch/mips/momentum/ocelot_c/cpci-irq.c
+++ b/arch/mips/momentum/ocelot_c/cpci-irq.c
@@ -21,7 +21,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
-#include <asm/ptrace.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <asm/io.h>
@@ -112,7 +111,7 @@ static void end_cpci_irq(unsigned int irq)
* Interrupt handler for interrupts coming from the FPGA chip.
* It could be built in ethernet ports etc...
*/
-void ll_cpci_irq(struct pt_regs *regs)
+void ll_cpci_irq(void)
{
unsigned int irq_src, irq_mask;
@@ -123,7 +122,7 @@ void ll_cpci_irq(struct pt_regs *regs)
/* mask for just the interrupts we want */
irq_src &= ~irq_mask;
- do_IRQ(ls1bit8(irq_src) + CPCI_IRQ_BASE, regs);
+ do_IRQ(ls1bit8(irq_src) + CPCI_IRQ_BASE);
}
#define shutdown_cpci_irq disable_cpci_irq
diff --git a/arch/mips/momentum/ocelot_c/irq.c b/arch/mips/momentum/ocelot_c/irq.c
index 9d44ae1e156b..ea65223a6d2c 100644
--- a/arch/mips/momentum/ocelot_c/irq.c
+++ b/arch/mips/momentum/ocelot_c/irq.c
@@ -59,31 +59,31 @@ static struct irqaction cascade_mv64340 = {
no_action, IRQF_DISABLED, CPU_MASK_NONE, "cascade via MV64340", NULL, NULL
};
-extern void ll_uart_irq(struct pt_regs *regs);
-extern void ll_cpci_irq(struct pt_regs *regs);
+extern void ll_uart_irq(void);
+extern void ll_cpci_irq(void);
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP0)
- do_IRQ(0, regs);
+ do_IRQ(0);
else if (pending & STATUSF_IP1)
- do_IRQ(1, regs);
+ do_IRQ(1);
else if (pending & STATUSF_IP2)
- do_IRQ(2, regs);
+ do_IRQ(2);
else if (pending & STATUSF_IP3)
- ll_uart_irq(regs);
+ ll_uart_irq();
else if (pending & STATUSF_IP4)
- do_IRQ(4, regs);
+ do_IRQ(4);
else if (pending & STATUSF_IP5)
- ll_cpci_irq(regs);
+ ll_cpci_irq();
else if (pending & STATUSF_IP6)
- ll_mv64340_irq(regs);
+ ll_mv64340_irq();
else if (pending & STATUSF_IP7)
- do_IRQ(7, regs);
+ do_IRQ(7);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
void __init arch_init_irq(void)
diff --git a/arch/mips/momentum/ocelot_c/setup.c b/arch/mips/momentum/ocelot_c/setup.c
index 36f570ecc6fb..9c0c462af650 100644
--- a/arch/mips/momentum/ocelot_c/setup.c
+++ b/arch/mips/momentum/ocelot_c/setup.c
@@ -62,7 +62,6 @@
#include <asm/irq.h>
#include <asm/pci.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/marvell.h>
#include <linux/bootmem.h>
diff --git a/arch/mips/momentum/ocelot_c/uart-irq.c b/arch/mips/momentum/ocelot_c/uart-irq.c
index 9f33d8f1d826..510257dc205a 100644
--- a/arch/mips/momentum/ocelot_c/uart-irq.c
+++ b/arch/mips/momentum/ocelot_c/uart-irq.c
@@ -16,7 +16,6 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/kernel.h>
-#include <asm/ptrace.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <asm/io.h>
@@ -105,7 +104,7 @@ static void end_uart_irq(unsigned int irq)
/*
* Interrupt handler for interrupts coming from the FPGA chip.
*/
-void ll_uart_irq(struct pt_regs *regs)
+void ll_uart_irq(void)
{
unsigned int irq_src, irq_mask;
@@ -116,7 +115,7 @@ void ll_uart_irq(struct pt_regs *regs)
/* mask for just the interrupts we want */
irq_src &= ~irq_mask;
- do_IRQ(ls1bit8(irq_src) + 74, regs);
+ do_IRQ(ls1bit8(irq_src) + 74);
}
#define shutdown_uart_irq disable_uart_irq
diff --git a/arch/mips/momentum/ocelot_g/gt-irq.c b/arch/mips/momentum/ocelot_g/gt-irq.c
index 9fb2493fff02..7b5cc6648f7e 100644
--- a/arch/mips/momentum/ocelot_g/gt-irq.c
+++ b/arch/mips/momentum/ocelot_g/gt-irq.c
@@ -14,7 +14,6 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
-#include <asm/ptrace.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <asm/gt64240.h>
@@ -108,7 +107,7 @@ int disable_galileo_irq(int int_cause, int bit_num)
* we keep this particular structure in the function.
*/
-static irqreturn_t gt64240_p0int_irq(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t gt64240_p0int_irq(int irq, void *dev)
{
uint32_t irq_src, irq_src_mask;
int handled;
@@ -133,9 +132,9 @@ static irqreturn_t gt64240_p0int_irq(int irq, void *dev, struct pt_regs *regs)
MV_WRITE(TIMER_COUNTER_0_3_INTERRUPT_CAUSE, 0x0);
/* handle the timer call */
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
}
diff --git a/arch/mips/momentum/ocelot_g/irq.c b/arch/mips/momentum/ocelot_g/irq.c
index 7a4a419804f1..da46524e87cb 100644
--- a/arch/mips/momentum/ocelot_g/irq.c
+++ b/arch/mips/momentum/ocelot_g/irq.c
@@ -48,22 +48,22 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP2)
- do_IRQ(2, regs);
+ do_IRQ(2);
else if (pending & STATUSF_IP3)
- do_IRQ(3, regs);
+ do_IRQ(3);
else if (pending & STATUSF_IP4)
- do_IRQ(4, regs);
+ do_IRQ(4);
else if (pending & STATUSF_IP5)
- do_IRQ(5, regs);
+ do_IRQ(5);
else if (pending & STATUSF_IP6)
- do_IRQ(6, regs);
+ do_IRQ(6);
else if (pending & STATUSF_IP7)
- do_IRQ(7, regs);
+ do_IRQ(7);
else {
/*
* Now look at the extended interrupts
@@ -71,15 +71,15 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
pending = (read_c0_cause() & (read_c0_intcontrol() << 8)) >> 16;
if (pending & STATUSF_IP8)
- do_IRQ(8, regs);
+ do_IRQ(8);
else if (pending & STATUSF_IP9)
- do_IRQ(9, regs);
+ do_IRQ(9);
else if (pending & STATUSF_IP10)
- do_IRQ(10, regs);
+ do_IRQ(10);
else if (pending & STATUSF_IP11)
- do_IRQ(11, regs);
+ do_IRQ(11);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
}
diff --git a/arch/mips/momentum/ocelot_g/setup.c b/arch/mips/momentum/ocelot_g/setup.c
index c580b1de33bc..56ec47039c16 100644
--- a/arch/mips/momentum/ocelot_g/setup.c
+++ b/arch/mips/momentum/ocelot_g/setup.c
@@ -58,7 +58,6 @@
#include <asm/irq.h>
#include <asm/pci.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <linux/bootmem.h>
diff --git a/arch/mips/oprofile/op_impl.h b/arch/mips/oprofile/op_impl.h
index 5cfce7d87a4d..fa6b4aae7523 100644
--- a/arch/mips/oprofile/op_impl.h
+++ b/arch/mips/oprofile/op_impl.h
@@ -10,10 +10,8 @@
#ifndef OP_IMPL_H
#define OP_IMPL_H 1
-struct pt_regs;
-
-extern int null_perf_irq(struct pt_regs *regs);
-extern int (*perf_irq)(struct pt_regs *regs);
+extern int null_perf_irq(void);
+extern int (*perf_irq)(void);
/* Per-counter configuration as set via oprofilefs. */
struct op_counter_config {
diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c
index a175d673540f..dd0aec9c3ce1 100644
--- a/arch/mips/oprofile/op_model_mipsxx.c
+++ b/arch/mips/oprofile/op_model_mipsxx.c
@@ -3,12 +3,13 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2004, 2005 by Ralf Baechle
+ * Copyright (C) 2004, 05, 06 by Ralf Baechle
* Copyright (C) 2005 by MIPS Technologies, Inc.
*/
#include <linux/oprofile.h>
#include <linux/interrupt.h>
#include <linux/smp.h>
+#include <asm/irq_regs.h>
#include "op_impl.h"
@@ -170,7 +171,7 @@ static void mipsxx_cpu_stop(void *args)
}
}
-static int mipsxx_perfcount_handler(struct pt_regs *regs)
+static int mipsxx_perfcount_handler(void)
{
unsigned int counters = op_model_mipsxx_ops.num_counters;
unsigned int control;
@@ -184,7 +185,7 @@ static int mipsxx_perfcount_handler(struct pt_regs *regs)
counter = r_c0_perfcntr ## n(); \
if ((control & M_PERFCTL_INTERRUPT_ENABLE) && \
(counter & M_COUNTER_OVERFLOW)) { \
- oprofile_add_sample(regs, n); \
+ oprofile_add_sample(get_irq_regs(), n); \
w_c0_perfcntr ## n(reg.counter[n]); \
handled = 1; \
}
diff --git a/arch/mips/oprofile/op_model_rm9000.c b/arch/mips/oprofile/op_model_rm9000.c
index b7063fefa65b..7dc9bf6f1321 100644
--- a/arch/mips/oprofile/op_model_rm9000.c
+++ b/arch/mips/oprofile/op_model_rm9000.c
@@ -80,8 +80,7 @@ static void rm9000_cpu_stop(void *args)
write_c0_perfcontrol(0);
}
-static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id,
- struct pt_regs *regs)
+static irqreturn_t rm9000_perfcount_handler(int irq, void * dev_id)
{
unsigned int control = read_c0_perfcontrol();
uint32_t counter1, counter2;
diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile
index 35d5927706ea..3cf0dd4ba548 100644
--- a/arch/mips/pci/Makefile
+++ b/arch/mips/pci/Makefile
@@ -7,11 +7,9 @@ obj-y += pci.o
#
# PCI bus host bridge specific code
#
-obj-$(CONFIG_ITE_BOARD_GEN) += ops-it8172.o
obj-$(CONFIG_MIPS_BONITO64) += ops-bonito64.o
obj-$(CONFIG_MIPS_GT64111) += ops-gt64111.o
obj-$(CONFIG_MIPS_GT64120) += ops-gt64120.o
-obj-$(CONFIG_MIPS_GT96100) += ops-gt96100.o
obj-$(CONFIG_PCI_MARVELL) += ops-marvell.o
obj-$(CONFIG_MIPS_MSC) += ops-msc.o
obj-$(CONFIG_MIPS_NILE4) += ops-nile4.o
@@ -28,10 +26,7 @@ obj-$(CONFIG_DDB5477) += fixup-ddb5477.o pci-ddb5477.o ops-ddb5477.o
obj-$(CONFIG_LASAT) += pci-lasat.o
obj-$(CONFIG_MIPS_ATLAS) += fixup-atlas.o
obj-$(CONFIG_MIPS_COBALT) += fixup-cobalt.o
-obj-$(CONFIG_MIPS_EV96100) += fixup-ev64120.o
-obj-$(CONFIG_MIPS_EV96100) += fixup-ev96100.o pci-ev96100.o
-obj-$(CONFIG_MIPS_ITE8172) += fixup-ite8172g.o
-obj-$(CONFIG_MIPS_IVR) += fixup-ivr.o
+obj-$(CONFIG_MIPS_EV64120) += fixup-ev64120.o
obj-$(CONFIG_SOC_AU1500) += fixup-au1000.o ops-au1000.o
obj-$(CONFIG_SOC_AU1550) += fixup-au1000.o ops-au1000.o
obj-$(CONFIG_SOC_PNX8550) += fixup-pnx8550.o ops-pnx8550.o
diff --git a/arch/mips/pci/fixup-atlas.c b/arch/mips/pci/fixup-atlas.c
index 439510af3037..c6cd6e9cdfbc 100644
--- a/arch/mips/pci/fixup-atlas.c
+++ b/arch/mips/pci/fixup-atlas.c
@@ -21,16 +21,16 @@
#include <asm/mips-boards/atlasint.h>
-#define PCIA ATLASINT_PCIA
-#define PCIB ATLASINT_PCIB
-#define PCIC ATLASINT_PCIC
-#define PCID ATLASINT_PCID
-#define INTA ATLASINT_INTA
-#define INTB ATLASINT_INTB
-#define ETH ATLASINT_ETH
-#define INTC ATLASINT_INTC
-#define SCSI ATLASINT_SCSI
-#define INTD ATLASINT_INTD
+#define PCIA ATLAS_INT_PCIA
+#define PCIB ATLAS_INT_PCIB
+#define PCIC ATLAS_INT_PCIC
+#define PCID ATLAS_INT_PCID
+#define INTA ATLAS_INT_INTA
+#define INTB ATLAS_INT_INTB
+#define ETH ATLAS_INT_ETH
+#define INTC ATLAS_INT_INTC
+#define SCSI ATLAS_INT_SCSI
+#define INTD ATLAS_INT_INTD
static char irq_tab[][5] __initdata = {
/* INTA INTB INTC INTD */
diff --git a/arch/mips/pci/fixup-ev96100.c b/arch/mips/pci/fixup-ev96100.c
deleted file mode 100644
index e2bc977b6d58..000000000000
--- a/arch/mips/pci/fixup-ev96100.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * EV96100 Board specific pci fixups.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-
-static char irq_tab_ev96100[][5] __initdata = {
- [8] = { 0, 5, 5, 5, 5 },
- [9] = { 0, 2, 2, 2, 2 }
-};
-
-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- return irq_tab_ev96100[slot][pin];
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- return 0;
-}
diff --git a/arch/mips/pci/fixup-ite8172g.c b/arch/mips/pci/fixup-ite8172g.c
deleted file mode 100644
index 2290ea4228dd..000000000000
--- a/arch/mips/pci/fixup-ite8172g.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Board specific pci fixups.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_pci.h>
-#include <asm/it8172/it8172_int.h>
-
-/*
- * Shortcuts
- */
-#define INTA IT8172_PCI_INTA_IRQ
-#define INTB IT8172_PCI_INTB_IRQ
-#define INTC IT8172_PCI_INTC_IRQ
-#define INTD IT8172_PCI_INTD_IRQ
-
-static const int internal_func_irqs[7] __initdata = {
- IT8172_AC97_IRQ,
- IT8172_DMA_IRQ,
- IT8172_CDMA_IRQ,
- IT8172_USB_IRQ,
- IT8172_BRIDGE_MASTER_IRQ,
- IT8172_IDE_IRQ,
- IT8172_MC68K_IRQ
-};
-
-static char irq_tab_ite8172g[][5] __initdata = {
- [0x10] = { 0, INTA, INTB, INTC, INTD },
- [0x11] = { 0, INTA, INTB, INTC, INTD },
- [0x12] = { 0, INTB, INTC, INTD, INTA },
- [0x13] = { 0, INTC, INTD, INTA, INTB },
- [0x14] = { 0, INTD, INTA, INTB, INTC },
-};
-
-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- /*
- * Internal device 1 is actually 7 different internal devices on the
- * IT8172G (a multifunction device).
- */
- if (slot == 1)
- return internal_func_irqs[PCI_FUNC(dev->devfn)];
-
- return irq_tab_ite8172g[slot][pin];
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- return 0;
-}
diff --git a/arch/mips/pci/fixup-ivr.c b/arch/mips/pci/fixup-ivr.c
deleted file mode 100644
index 0c7c16464c11..000000000000
--- a/arch/mips/pci/fixup-ivr.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * Globespan IVR board-specific pci fixups.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_pci.h>
-#include <asm/it8172/it8172_int.h>
-
-/*
- * Shortcuts
- */
-#define INTA IT8172_PCI_INTA_IRQ
-#define INTB IT8172_PCI_INTB_IRQ
-#define INTC IT8172_PCI_INTC_IRQ
-#define INTD IT8172_PCI_INTD_IRQ
-
-static const int internal_func_irqs[7] __initdata = {
- IT8172_AC97_IRQ,
- IT8172_DMA_IRQ,
- IT8172_CDMA_IRQ,
- IT8172_USB_IRQ,
- IT8172_BRIDGE_MASTER_IRQ,
- IT8172_IDE_IRQ,
- IT8172_MC68K_IRQ
-};
-
-static char irq_tab_ivr[][5] __initdata = {
- [0x11] = { INTC, INTC, INTD, INTA, INTB }, /* Realtek RTL-8139 */
- [0x12] = { INTB, INTB, INTB, INTC, INTC }, /* IVR slot */
- [0x13] = { INTA, INTA, INTB, INTC, INTD } /* Expansion slot */
-};
-
-int __init pcibios_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- if (slot == 1)
- return internal_func_irqs[PCI_FUNC(dev->devfn)];
-
- return irq_tab_ivr[slot][pin];
-}
-
-/* Do platform specific device initialization at pci_enable_device() time */
-int pcibios_plat_dev_init(struct pci_dev *dev)
-{
- return 0;
-}
diff --git a/arch/mips/pci/fixup-sb1250.c b/arch/mips/pci/fixup-sb1250.c
index 13791b78e598..7a7444874e80 100644
--- a/arch/mips/pci/fixup-sb1250.c
+++ b/arch/mips/pci/fixup-sb1250.c
@@ -1,7 +1,7 @@
/*
* arch/mips/pci/fixup-sb1250.c
*
- * Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 2004, 2006 MIPS Technologies, Inc. All rights reserved.
* Author: Maciej W. Rozycki <macro@mips.com>
*
* This program is free software; you can redistribute it and/or
@@ -14,6 +14,17 @@
#include <linux/pci.h>
/*
+ * Set the the BCM1250, etc. PCI host bridge's TRDY timeout
+ * to the finite max.
+ */
+static void __init quirk_sb1250_pci(struct pci_dev *dev)
+{
+ pci_write_config_byte(dev, 0x40, 0xff);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIBYTE, PCI_DEVICE_ID_BCM1250_PCI,
+ quirk_sb1250_pci);
+
+/*
* The BCM1250, etc. PCI/HT bridge reports as a host bridge.
*/
static void __init quirk_sb1250_ht(struct pci_dev *dev)
@@ -22,3 +33,13 @@ static void __init quirk_sb1250_ht(struct pci_dev *dev)
}
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.
+ */
+static void __init quirk_sp1011(struct pci_dev *dev)
+{
+ pci_write_config_byte(dev, 0x64, 0xff);
+}
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SIPACKETS, PCI_DEVICE_ID_SP1011,
+ quirk_sp1011);
diff --git a/arch/mips/pci/fixup-vr4133.c b/arch/mips/pci/fixup-vr4133.c
index 8e01d0c1b76b..597b89764ba1 100644
--- a/arch/mips/pci/fixup-vr4133.c
+++ b/arch/mips/pci/fixup-vr4133.c
@@ -1,5 +1,5 @@
/*
- * arch/mips/vr41xx/nec-cmbvr4133/pci_fixup.c
+ * arch/mips/pci/fixup-vr4133.c
*
* The NEC CMB-VR4133 Board specific PCI fixups.
*
diff --git a/arch/mips/pci/ops-au1000.c b/arch/mips/pci/ops-au1000.c
index 0c0c1e6519f9..8ae46481fcb7 100644
--- a/arch/mips/pci/ops-au1000.c
+++ b/arch/mips/pci/ops-au1000.c
@@ -110,7 +110,7 @@ static int config_access(unsigned char access_type, struct pci_bus *bus,
if (first_cfg) {
/* reserve a wired entry for pci config accesses */
first_cfg = 0;
- pci_cfg_vm = get_vm_area(0x2000, 0);
+ pci_cfg_vm = get_vm_area(0x2000, VM_IOREMAP);
if (!pci_cfg_vm)
panic (KERN_ERR "PCI unable to get vm area\n");
pci_cfg_wired_entry = read_c0_wired();
diff --git a/arch/mips/pci/ops-gt96100.c b/arch/mips/pci/ops-gt96100.c
deleted file mode 100644
index 9e4ea6627e21..000000000000
--- a/arch/mips/pci/ops-gt96100.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * Galileo EV96100 board specific pci support.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * This file was derived from Carsten Langgaard's
- * arch/mips/mips-boards/generic/pci.c
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/delay.h>
-#include <asm/gt64120.h>
-#include <asm/galileo-boards/ev96100.h>
-
-#define PCI_ACCESS_READ 0
-#define PCI_ACCESS_WRITE 1
-
-static int static gt96100_config_access(unsigned char access_type,
- struct pci_bus *bus, unsigned int devfn, int where, u32 * data)
-{
- unsigned char bus = bus->number;
- u32 intr;
-
- /*
- * Because of a bug in the galileo (for slot 31).
- */
- if (bus == 0 && devfn >= PCI_DEVFN(31, 0))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- /* Clear cause register bits */
- GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
- GT_INTRCAUSE_TARABORT0_BIT));
-
- /* Setup address */
- GT_WRITE(GT_PCI0_CFGADDR_OFS,
- (bus << GT_PCI0_CFGADDR_BUSNUM_SHF) |
- (devfn << GT_PCI0_CFGADDR_FUNCTNUM_SHF) |
- ((where / 4) << GT_PCI0_CFGADDR_REGNUM_SHF) |
- GT_PCI0_CFGADDR_CONFIGEN_BIT);
- udelay(2);
-
-
- if (access_type == PCI_ACCESS_WRITE) {
- if (devfn != 0)
- *data = le32_to_cpu(*data);
- GT_WRITE(GT_PCI0_CFGDATA_OFS, *data);
- } else {
- *data = GT_READ(GT_PCI0_CFGDATA_OFS);
- if (devfn != 0)
- *data = le32_to_cpu(*data);
- }
-
- udelay(2);
-
- /* Check for master or target abort */
- intr = GT_READ(GT_INTRCAUSE_OFS);
-
- if (intr & (GT_INTRCAUSE_MASABORT0_BIT | GT_INTRCAUSE_TARABORT0_BIT)) {
- /* Error occured */
-
- /* Clear bits */
- GT_WRITE(GT_INTRCAUSE_OFS, ~(GT_INTRCAUSE_MASABORT0_BIT |
- GT_INTRCAUSE_TARABORT0_BIT));
- return -1;
- }
- return 0;
-}
-
-/*
- * We can't address 8 and 16 bit words directly. Instead we have to
- * read/write a 32bit word and mask/modify the data we actually want.
- */
-static int gt96100_pcibios_read(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 * val)
-{
- u32 data = 0;
-
- if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- switch (size) {
- case 1:
- *val = (data >> ((where & 3) << 3)) & 0xff;
- break;
-
- case 2:
- *val = (data >> ((where & 3) << 3)) & 0xffff;
- break;
-
- case 4:
- *val = data;
- break;
- }
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int gt96100_pcibios_write(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 val)
-{
- u32 data = 0;
-
- switch (size) {
- case 1:
- if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
- return -1;
-
- data = (data & ~(0xff << ((where & 3) << 3))) |
- (val << ((where & 3) << 3));
-
- if (gt96100_config_access(PCI_ACCESS_WRITE, bus, devfn, where, &data))
- return -1;
-
- return PCIBIOS_SUCCESSFUL;
-
- case 2:
- if (gt96100_config_access(PCI_ACCESS_READ, bus, devfn, where, &data))
- return -1;
-
- data = (data & ~(0xffff << ((where & 3) << 3))) |
- (val << ((where & 3) << 3));
-
- if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &data))
- return -1;
-
-
- return PCIBIOS_SUCCESSFUL;
-
- case 4:
- if (gt96100_config_access(PCI_ACCESS_WRITE, dev, where, &val))
- return -1;
-
- return PCIBIOS_SUCCESSFUL;
- }
-}
-
-struct pci_ops gt96100_pci_ops = {
- .read = gt96100_pcibios_read,
- .write = gt96100_pcibios_write
-};
diff --git a/arch/mips/pci/ops-it8172.c b/arch/mips/pci/ops-it8172.c
deleted file mode 100644
index ba8328505a0a..000000000000
--- a/arch/mips/pci/ops-it8172.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * IT8172 system controller specific pci support.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_pci.h>
-
-#define PCI_ACCESS_READ 0
-#define PCI_ACCESS_WRITE 1
-
-#undef DEBUG
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-static struct resource pci_mem_resource_1;
-
-static struct resource pci_io_resource = {
- .start = 0x14018000,
- .end = 0x17FFFFFF,
- .name = "io pci IO space",
- .flags = IORESOURCE_IO
-};
-
-static struct resource pci_mem_resource_0 = {
- .start = 0x10101000,
- .end = 0x13FFFFFF,
- .name = "ext pci memory space 0/1",
- .flags = IORESOURCE_MEM,
- .parent = &pci_mem_resource_0,
- .sibling = NULL,
- .child = &pci_mem_resource_1
-};
-
-static struct resource pci_mem_resource_1 = {
- .start = 0x1A000000,
- .end = 0x1FBFFFFF,
- .name = "ext pci memory space 2/3",
- .flags = IORESOURCE_MEM,
- .parent = &pci_mem_resource_0
-};
-
-extern struct pci_ops it8172_pci_ops;
-
-struct pci_controller it8172_controller = {
- .pci_ops = &it8172_pci_ops,
- .io_resource = &pci_io_resource,
- .mem_resource = &pci_mem_resource_0,
-};
-
-static int it8172_pcibios_config_access(unsigned char access_type,
- struct pci_bus *bus,
- unsigned int devfn, int where,
- u32 * data)
-{
- /*
- * config cycles are on 4 byte boundary only
- */
-
- /* Setup address */
- IT_WRITE(IT_CONFADDR, (bus->number << IT_BUSNUM_SHF) |
- (devfn << IT_FUNCNUM_SHF) | (where & ~0x3));
-
- if (access_type == PCI_ACCESS_WRITE) {
- IT_WRITE(IT_CONFDATA, *data);
- } else {
- IT_READ(IT_CONFDATA, *data);
- }
-
- /*
- * Revisit: check for master or target abort.
- */
- return 0;
-}
-
-
-/*
- * We can't address 8 and 16 bit words directly. Instead we have to
- * read/write a 32bit word and mask/modify the data we actually want.
- */
-static write_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 val)
-{
- u32 data = 0;
-
- switch (size) {
- case 1:
- if (it8172_pcibios_config_access
- (PCI_ACCESS_READ, dev, where, &data))
- return -1;
-
- *val = (data >> ((where & 3) << 3)) & 0xff;
-
- return PCIBIOS_SUCCESSFUL;
-
- case 2:
-
- if (where & 1)
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (it8172_pcibios_config_access
- (PCI_ACCESS_READ, dev, where, &data))
- return -1;
-
- *val = (data >> ((where & 3) << 3)) & 0xffff;
- DBG("cfg read word: bus %d dev_fn %x where %x: val %x\n",
- dev->bus->number, dev->devfn, where, *val);
-
- return PCIBIOS_SUCCESSFUL;
-
- case 4:
-
- if (where & 3)
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (it8172_pcibios_config_access
- (PCI_ACCESS_READ, dev, where, &data))
- return -1;
-
- *val = data;
-
- return PCIBIOS_SUCCESSFUL;
- }
-}
-
-
-static write_config(struct pci_bus *bus, unsigned int devfn, int where,
- int size, u32 val)
-{
- u32 data = 0;
-
- switch (size) {
- case 1:
- if (it8172_pcibios_config_access
- (PCI_ACCESS_READ, dev, where, &data))
- return -1;
-
- data = (data & ~(0xff << ((where & 3) << 3))) |
- (val << ((where & 3) << 3));
-
- if (it8172_pcibios_config_access
- (PCI_ACCESS_WRITE, dev, where, &data))
- return -1;
-
- return PCIBIOS_SUCCESSFUL;
-
- case 2:
- if (where & 1)
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (it8172_pcibios_config_access
- (PCI_ACCESS_READ, dev, where, &data))
- eturn - 1;
-
- data = (data & ~(0xffff << ((where & 3) << 3))) |
- (val << ((where & 3) << 3));
-
- if (it8172_pcibios_config_access
- (PCI_ACCESS_WRITE, dev, where, &data))
- return -1;
-
- return PCIBIOS_SUCCESSFUL;
-
- case 4:
- if (where & 3)
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- if (it8172_pcibios_config_access
- (PCI_ACCESS_WRITE, dev, where, &val))
- return -1;
-
- return PCIBIOS_SUCCESSFUL;
- }
-}
-
-struct pci_ops it8172_pci_ops = {
- .read = read_config,
- .write = write_config,
-};
diff --git a/arch/mips/pci/pci-ev96100.c b/arch/mips/pci/pci-ev96100.c
deleted file mode 100644
index f9457ea00def..000000000000
--- a/arch/mips/pci/pci-ev96100.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc. All rights reserved.
- *
- * Copyright (C) 2004 by Ralf Baechle (ralf@linux-mips.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.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-
-static struct resource pci_io_resource = {
- .name = "io pci IO space",
- .start = 0x10000000,
- .end = 0x11ffffff,
- .flags = IORESOURCE_IO
-};
-
-static struct resource pci_mem_resource = {
- .name = "ext pci memory space",
- .start = 0x12000000,
- .end = 0x13ffffff,
- .flags = IORESOURCE_MEM
-};
-
-extern struct pci_ops gt96100_pci_ops;
-
-struct pci_controller ev96100_controller = {
- .pci_ops = &gt96100_pci_ops,
- .io_resource = &pci_io_resource,
- .mem_resource = &pci_mem_resource,
-};
-
-static void ev96100_pci_init(void)
-{
- register_pci_controller(&ev96100_controller);
-}
-
-arch_initcall(ev96100_pci_init);
diff --git a/arch/mips/pci/pci-ip27.c b/arch/mips/pci/pci-ip27.c
index 80eb9af9ecdf..405ce0152739 100644
--- a/arch/mips/pci/pci-ip27.c
+++ b/arch/mips/pci/pci-ip27.c
@@ -16,8 +16,6 @@
#include <asm/sn/intr.h>
#include <asm/sn/sn0/hub.h>
-extern unsigned int allocate_irqno(void);
-
/*
* Max #PCI busses we can handle; ie, max #PCI bridges.
*/
diff --git a/arch/mips/pci/pci-ip32.c b/arch/mips/pci/pci-ip32.c
index 17c7932cf0ae..618ea7dbc474 100644
--- a/arch/mips/pci/pci-ip32.c
+++ b/arch/mips/pci/pci-ip32.c
@@ -22,7 +22,7 @@
* registered on the bridge error irq. It's conceivable that some of these
* conditions warrant a panic. Anybody care to say which ones?
*/
-static irqreturn_t macepci_error(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t macepci_error(int irq, void *dev)
{
char s;
unsigned int flags = mace->pci.error;
diff --git a/arch/mips/philips/pnx8550/common/int.c b/arch/mips/philips/pnx8550/common/int.c
index 099679a9dfb9..710611615ca2 100644
--- a/arch/mips/philips/pnx8550/common/int.c
+++ b/arch/mips/philips/pnx8550/common/int.c
@@ -23,6 +23,7 @@
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
*
*/
+#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/sched.h>
@@ -52,7 +53,7 @@ static char gic_prio[PNX8550_INT_GIC_TOTINT] = {
1 // 70
};
-static void hw0_irqdispatch(int irq, struct pt_regs *regs)
+static void hw0_irqdispatch(int irq)
{
/* find out which interrupt */
irq = PNX8550_GIC_VECTOR_0 >> 3;
@@ -61,42 +62,39 @@ static void hw0_irqdispatch(int irq, struct pt_regs *regs)
printk("hw0_irqdispatch: irq 0, spurious interrupt?\n");
return;
}
- do_IRQ(PNX8550_INT_GIC_MIN + irq, regs);
+ do_IRQ(PNX8550_INT_GIC_MIN + irq);
}
-static void timer_irqdispatch(int irq, struct pt_regs *regs)
+static void timer_irqdispatch(int irq)
{
irq = (0x01c0 & read_c0_config7()) >> 6;
- if (irq == 0) {
+ if (unlikely(irq == 0)) {
printk("timer_irqdispatch: irq 0, spurious interrupt?\n");
return;
}
- if (irq & 0x1) {
- do_IRQ(PNX8550_INT_TIMER1, regs);
- }
- if (irq & 0x2) {
- do_IRQ(PNX8550_INT_TIMER2, regs);
- }
- if (irq & 0x4) {
- do_IRQ(PNX8550_INT_TIMER3, regs);
- }
+ if (irq & 0x1)
+ do_IRQ(PNX8550_INT_TIMER1);
+ if (irq & 0x2)
+ do_IRQ(PNX8550_INT_TIMER2);
+ if (irq & 0x4)
+ do_IRQ(PNX8550_INT_TIMER3);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP2)
- do_IRQ(2, regs);
+ hw0_irqdispatch(2);
else if (pending & STATUSF_IP7) {
if (read_c0_config7() & 0x01c0)
- timer_irqdispatch(7, regs);
+ timer_irqdispatch(7);
}
- spurious_interrupt(regs);
+ spurious_interrupt();
}
static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
diff --git a/arch/mips/philips/pnx8550/common/platform.c b/arch/mips/philips/pnx8550/common/platform.c
index 5436b4b97455..d43f56e2cd78 100644
--- a/arch/mips/philips/pnx8550/common/platform.c
+++ b/arch/mips/philips/pnx8550/common/platform.c
@@ -17,15 +17,13 @@
#include <linux/init.h>
#include <linux/resource.h>
#include <linux/serial.h>
-#include <linux/serial_ip3106.h>
+#include <linux/serial_pnx8xxx.h>
#include <linux/platform_device.h>
#include <int.h>
#include <usb.h>
#include <uart.h>
-extern struct uart_ops ip3106_pops;
-
static struct resource pnx8550_usb_ohci_resources[] = {
[0] = {
.start = PNX8550_USB_OHCI_OP_BASE,
@@ -63,31 +61,29 @@ static struct resource pnx8550_uart_resources[] = {
},
};
-struct ip3106_port ip3106_ports[] = {
+struct pnx8xxx_port pnx8xxx_ports[] = {
[0] = {
.port = {
- .type = PORT_IP3106,
+ .type = PORT_PNX8XXX,
.iotype = UPIO_MEM,
.membase = (void __iomem *)PNX8550_UART_PORT0,
.mapbase = PNX8550_UART_PORT0,
.irq = PNX8550_UART_INT(0),
.uartclk = 3692300,
.fifosize = 16,
- .ops = &ip3106_pops,
.flags = UPF_BOOT_AUTOCONF,
.line = 0,
},
},
[1] = {
.port = {
- .type = PORT_IP3106,
+ .type = PORT_PNX8XXX,
.iotype = UPIO_MEM,
.membase = (void __iomem *)PNX8550_UART_PORT1,
.mapbase = PNX8550_UART_PORT1,
.irq = PNX8550_UART_INT(1),
.uartclk = 3692300,
.fifosize = 16,
- .ops = &ip3106_pops,
.flags = UPF_BOOT_AUTOCONF,
.line = 1,
},
@@ -111,12 +107,12 @@ static struct platform_device pnx8550_usb_ohci_device = {
};
static struct platform_device pnx8550_uart_device = {
- .name = "ip3106-uart",
+ .name = "pnx8xxx-uart",
.id = -1,
.dev = {
.dma_mask = &uart_dmamask,
.coherent_dma_mask = 0xffffffff,
- .platform_data = ip3106_ports,
+ .platform_data = pnx8xxx_ports,
},
.num_resources = ARRAY_SIZE(pnx8550_uart_resources),
.resource = pnx8550_uart_resources,
diff --git a/arch/mips/philips/pnx8550/common/prom.c b/arch/mips/philips/pnx8550/common/prom.c
index 70aac9759412..f8952c1359cd 100644
--- a/arch/mips/philips/pnx8550/common/prom.c
+++ b/arch/mips/philips/pnx8550/common/prom.c
@@ -13,7 +13,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
-#include <linux/serial_ip3106.h>
+#include <linux/serial_pnx8xxx.h>
#include <asm/bootinfo.h>
#include <uart.h>
@@ -126,7 +126,7 @@ void prom_putchar(char c)
{
if (pnx8550_console_port != -1) {
/* Wait until FIFO not full */
- while( ((ip3106_fifo(UART_BASE, pnx8550_console_port) & IP3106_UART_FIFO_TXFIFO) >> 16) >= 16)
+ while( ((ip3106_fifo(UART_BASE, pnx8550_console_port) & PNX8XXX_UART_FIFO_TXFIFO) >> 16) >= 16)
;
/* Send one char */
ip3106_fifo(UART_BASE, pnx8550_console_port) = c;
diff --git a/arch/mips/philips/pnx8550/common/setup.c b/arch/mips/philips/pnx8550/common/setup.c
index 36b0c8bc6c06..e62123ca9b64 100644
--- a/arch/mips/philips/pnx8550/common/setup.c
+++ b/arch/mips/philips/pnx8550/common/setup.c
@@ -24,7 +24,7 @@
#include <linux/mm.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/serial_ip3106.h>
+#include <linux/serial_pnx8xxx.h>
#include <linux/pm.h>
#include <asm/cpu.h>
@@ -56,7 +56,7 @@ extern char *prom_getcmdline(void);
struct resource standard_io_resources[] = {
{
- .start = .0x00,
+ .start = 0x00,
.end = 0x1f,
.name = "dma1",
.flags = IORESOURCE_BUSY
@@ -144,7 +144,7 @@ void __init plat_mem_setup(void)
/* We must initialize the UART (console) before prom_printf */
/* Set LCR to 8-bit and BAUD to 38400 (no 5) */
ip3106_lcr(UART_BASE, pnx8550_console_port) =
- IP3106_UART_LCR_8BIT;
+ PNX8XXX_UART_LCR_8BIT;
ip3106_baud(UART_BASE, pnx8550_console_port) = 5;
}
diff --git a/arch/mips/pmc-sierra/yosemite/irq.c b/arch/mips/pmc-sierra/yosemite/irq.c
index b91d0aa3b7ed..adb048527e76 100644
--- a/arch/mips/pmc-sierra/yosemite/irq.c
+++ b/arch/mips/pmc-sierra/yosemite/irq.c
@@ -56,15 +56,13 @@
#define HYPERTRANSPORT_INTC 0x7a /* INTC# */
#define HYPERTRANSPORT_INTD 0x7b /* INTD# */
-extern void jaguar_mailbox_irq(struct pt_regs *);
-
/*
* Handle hypertransport & SMP interrupts. The interrupt lines are scarce.
* For interprocessor interrupts, the best thing to do is to use the INTMSG
* register. We use the same external interrupt line, i.e. INTB3 and monitor
* another status bit
*/
-asmlinkage void ll_ht_smp_irq_handler(int irq, struct pt_regs *regs)
+static void ll_ht_smp_irq_handler(int irq)
{
u32 status = OCD_READ(RM9000x2_OCD_INTP0STATUS4);
@@ -107,50 +105,35 @@ asmlinkage void ll_ht_smp_irq_handler(int irq, struct pt_regs *regs)
}
#endif /* CONFIG_HT_LEVEL_TRIGGER */
- do_IRQ(irq, regs);
-}
-
-asmlinkage void do_extended_irq(struct pt_regs *regs)
-{
- unsigned int intcontrol = read_c0_intcontrol();
- unsigned int cause = read_c0_cause();
- unsigned int status = read_c0_status();
- unsigned int pending_sr, pending_ic;
-
- pending_sr = status & cause & 0xff00;
- pending_ic = (cause >> 8) & intcontrol & 0xff00;
-
- if (pending_ic & (1 << 13))
- do_IRQ(13, regs);
-
+ do_IRQ(irq);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int cause = read_c0_cause();
unsigned int status = read_c0_status();
unsigned int pending = cause & status;
if (pending & STATUSF_IP7) {
- do_IRQ(7, regs);
+ do_IRQ(7);
} else if (pending & STATUSF_IP2) {
#ifdef CONFIG_HYPERTRANSPORT
- ll_ht_smp_irq_handler(2, regs);
+ ll_ht_smp_irq_handler(2);
#else
- do_IRQ(2, regs);
+ do_IRQ(2);
#endif
} else if (pending & STATUSF_IP3) {
- do_IRQ(3, regs);
+ do_IRQ(3);
} else if (pending & STATUSF_IP4) {
- do_IRQ(4, regs);
+ do_IRQ(4);
} else if (pending & STATUSF_IP5) {
#ifdef CONFIG_SMP
- titan_mailbox_irq(regs);
+ titan_mailbox_irq();
#else
- do_IRQ(5, regs);
+ do_IRQ(5);
#endif
} else if (pending & STATUSF_IP6) {
- do_IRQ(4, regs);
+ do_IRQ(4);
}
}
@@ -178,18 +161,3 @@ void __init arch_init_irq(void)
register_gdb_console();
#endif
}
-
-#ifdef CONFIG_KGDB
-/*
- * The 16550 DUART has two ports, but is allocated one IRQ
- * for the serial console. Hence, a generic framework for
- * serial IRQ routing in place. Currently, just calls the
- * do_IRQ fuction. But, going in the future, need to check
- * DUART registers for channel A and B, then decide the
- * appropriate action
- */
-asmlinkage void yosemite_kgdb_irq(int irq, struct pt_regs *regs)
-{
- do_IRQ(irq, regs);
-}
-#endif
diff --git a/arch/mips/pmc-sierra/yosemite/setup.c b/arch/mips/pmc-sierra/yosemite/setup.c
index 0a6ee8e5eec2..1b9b0d396d3e 100644
--- a/arch/mips/pmc-sierra/yosemite/setup.c
+++ b/arch/mips/pmc-sierra/yosemite/setup.c
@@ -46,7 +46,6 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/serial.h>
#include <asm/titan_dep.h>
diff --git a/arch/mips/pmc-sierra/yosemite/smp.c b/arch/mips/pmc-sierra/yosemite/smp.c
index c197311e15d3..65fa3a23ea5e 100644
--- a/arch/mips/pmc-sierra/yosemite/smp.c
+++ b/arch/mips/pmc-sierra/yosemite/smp.c
@@ -110,7 +110,7 @@ void prom_smp_finish(void)
{
}
-asmlinkage void titan_mailbox_irq(struct pt_regs *regs)
+asmlinkage void titan_mailbox_irq(void)
{
int cpu = smp_processor_id();
unsigned long status;
diff --git a/arch/mips/qemu/q-irq.c b/arch/mips/qemu/q-irq.c
index 3352374c4c7d..f5ea2fe10f14 100644
--- a/arch/mips/qemu/q-irq.c
+++ b/arch/mips/qemu/q-irq.c
@@ -9,19 +9,19 @@
extern asmlinkage void qemu_handle_int(void);
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & 0x8000) {
- ll_timer_interrupt(Q_COUNT_COMPARE_IRQ, regs);
+ ll_timer_interrupt(Q_COUNT_COMPARE_IRQ);
return;
}
if (pending & 0x0400) {
int irq = i8259_irq();
if (likely(irq >= 0))
- do_IRQ(irq, regs);
+ do_IRQ(irq);
return;
}
diff --git a/arch/mips/sgi-ip22/ip22-berr.c b/arch/mips/sgi-ip22/ip22-berr.c
index a28dc7800072..de6a0cc32fea 100644
--- a/arch/mips/sgi-ip22/ip22-berr.c
+++ b/arch/mips/sgi-ip22/ip22-berr.c
@@ -12,6 +12,7 @@
#include <asm/system.h>
#include <asm/traps.h>
#include <asm/branch.h>
+#include <asm/irq_regs.h>
#include <asm/sgi/mc.h>
#include <asm/sgi/hpc3.h>
#include <asm/sgi/ioc.h>
@@ -85,9 +86,10 @@ static void print_buserr(void)
* and then clear the interrupt when this happens.
*/
-void ip22_be_interrupt(int irq, struct pt_regs *regs)
+void ip22_be_interrupt(int irq)
{
const int field = 2 * sizeof(unsigned long);
+ const struct pt_regs *regs = get_irq_regs();
save_and_clear_buserr();
print_buserr();
diff --git a/arch/mips/sgi-ip22/ip22-eisa.c b/arch/mips/sgi-ip22/ip22-eisa.c
index ee0514a29922..0d18ed47c47a 100644
--- a/arch/mips/sgi-ip22/ip22-eisa.c
+++ b/arch/mips/sgi-ip22/ip22-eisa.c
@@ -70,7 +70,7 @@ static char __init *decode_eisa_sig(unsigned long addr)
return sig_str;
}
-static irqreturn_t ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ip22_eisa_intr(int irq, void *dev_id)
{
u8 eisa_irq;
u8 dma1, dma2;
@@ -80,7 +80,7 @@ static irqreturn_t ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs)
dma2 = inb(EISA_DMA2_STATUS);
if (eisa_irq < EISA_MAX_IRQ) {
- do_IRQ(eisa_irq, regs);
+ do_IRQ(eisa_irq);
return IRQ_HANDLED;
}
@@ -89,6 +89,7 @@ static irqreturn_t ip22_eisa_intr(int irq, void *dev_id, struct pt_regs *regs)
outb(0x20, EISA_INT2_CTRL);
outb(0x20, EISA_INT1_CTRL);
+
return IRQ_NONE;
}
diff --git a/arch/mips/sgi-ip22/ip22-int.c b/arch/mips/sgi-ip22/ip22-int.c
index f66026e5d64b..af518898eaa1 100644
--- a/arch/mips/sgi-ip22/ip22-int.c
+++ b/arch/mips/sgi-ip22/ip22-int.c
@@ -222,7 +222,7 @@ static struct irq_chip ip22_local3_irq_type = {
.end = end_local3_irq,
};
-static void indy_local0_irqdispatch(struct pt_regs *regs)
+static void indy_local0_irqdispatch(void)
{
u8 mask = sgint->istat0 & sgint->imask0;
u8 mask2;
@@ -236,11 +236,10 @@ static void indy_local0_irqdispatch(struct pt_regs *regs)
/* if irq == 0, then the interrupt has already been cleared */
if (irq)
- do_IRQ(irq, regs);
- return;
+ do_IRQ(irq);
}
-static void indy_local1_irqdispatch(struct pt_regs *regs)
+static void indy_local1_irqdispatch(void)
{
u8 mask = sgint->istat1 & sgint->imask1;
u8 mask2;
@@ -254,19 +253,18 @@ static void indy_local1_irqdispatch(struct pt_regs *regs)
/* if irq == 0, then the interrupt has already been cleared */
if (irq)
- do_IRQ(irq, regs);
- return;
+ do_IRQ(irq);
}
-extern void ip22_be_interrupt(int irq, struct pt_regs *regs);
+extern void ip22_be_interrupt(int irq);
-static void indy_buserror_irq(struct pt_regs *regs)
+static void indy_buserror_irq(void)
{
int irq = SGI_BUSERR_IRQ;
irq_enter();
kstat_this_cpu.irqs[irq]++;
- ip22_be_interrupt(irq, regs);
+ ip22_be_interrupt(irq);
irq_exit();
}
@@ -305,8 +303,8 @@ static struct irqaction map1_cascade = {
#define SGI_INTERRUPTS SGINT_LOCAL3
#endif
-extern void indy_r4k_timer_interrupt(struct pt_regs *regs);
-extern void indy_8254timer_irq(struct pt_regs *regs);
+extern void indy_r4k_timer_interrupt(void);
+extern void indy_8254timer_irq(void);
/*
* IRQs on the INDY look basically (barring software IRQs which we don't use
@@ -336,7 +334,7 @@ extern void indy_8254timer_irq(struct pt_regs *regs);
* another exception, big deal.
*/
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause();
@@ -344,15 +342,15 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
* First we check for r4k counter/timer IRQ.
*/
if (pending & CAUSEF_IP7)
- indy_r4k_timer_interrupt(regs);
+ indy_r4k_timer_interrupt();
else if (pending & CAUSEF_IP2)
- indy_local0_irqdispatch(regs);
+ indy_local0_irqdispatch();
else if (pending & CAUSEF_IP3)
- indy_local1_irqdispatch(regs);
+ indy_local1_irqdispatch();
else if (pending & CAUSEF_IP6)
- indy_buserror_irq(regs);
+ indy_buserror_irq();
else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
- indy_8254timer_irq(regs);
+ indy_8254timer_irq();
}
extern void mips_cpu_irq_init(unsigned int irq_base);
diff --git a/arch/mips/sgi-ip22/ip22-reset.c b/arch/mips/sgi-ip22/ip22-reset.c
index 8134220ed600..66df5ac8f089 100644
--- a/arch/mips/sgi-ip22/ip22-reset.c
+++ b/arch/mips/sgi-ip22/ip22-reset.c
@@ -123,7 +123,8 @@ static inline void power_button(void)
if (machine_state & MACHINE_PANICED)
return;
- if ((machine_state & MACHINE_SHUTTING_DOWN) || kill_proc(1,SIGINT,1)) {
+ if ((machine_state & MACHINE_SHUTTING_DOWN) ||
+ kill_cad_pid(SIGINT, 1)) {
/* No init process or button pressed twice. */
sgi_machine_power_off();
}
@@ -168,7 +169,7 @@ static inline void volume_down_button(unsigned long data)
}
}
-static irqreturn_t panel_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t panel_int(int irq, void *dev_id)
{
unsigned int buttons;
diff --git a/arch/mips/sgi-ip22/ip22-time.c b/arch/mips/sgi-ip22/ip22-time.c
index 0e061890f797..205554734099 100644
--- a/arch/mips/sgi-ip22/ip22-time.c
+++ b/arch/mips/sgi-ip22/ip22-time.c
@@ -175,7 +175,7 @@ static __init void indy_time_init(void)
}
/* Generic SGI handler for (spurious) 8254 interrupts */
-void indy_8254timer_irq(struct pt_regs *regs)
+void indy_8254timer_irq(void)
{
int irq = SGI_8254_0_IRQ;
ULONG cnt;
@@ -189,13 +189,13 @@ void indy_8254timer_irq(struct pt_regs *regs)
irq_exit();
}
-void indy_r4k_timer_interrupt(struct pt_regs *regs)
+void indy_r4k_timer_interrupt(void)
{
int irq = SGI_TIMER_IRQ;
irq_enter();
kstat_this_cpu.irqs[irq]++;
- timer_interrupt(irq, NULL, regs);
+ timer_interrupt(irq, NULL);
irq_exit();
}
diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c
index 24a85372284f..f01ba1f90770 100644
--- a/arch/mips/sgi-ip27/ip27-irq.c
+++ b/arch/mips/sgi-ip27/ip27-irq.c
@@ -30,7 +30,6 @@
#include <asm/mipsregs.h>
#include <asm/system.h>
-#include <asm/ptrace.h>
#include <asm/processor.h>
#include <asm/pci/bridge.h>
#include <asm/sn/addrs.h>
@@ -129,7 +128,7 @@ static int ms1bit(unsigned long x)
* Kanoj 05.13.00
*/
-static void ip27_do_irq_mask0(struct pt_regs *regs)
+static void ip27_do_irq_mask0(void)
{
int irq, swlevel;
hubreg_t pend0, mask0;
@@ -164,13 +163,13 @@ static void ip27_do_irq_mask0(struct pt_regs *regs)
struct slice_data *si = cpu_data[cpu].data;
irq = si->level_to_irq[swlevel];
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
LOCAL_HUB_L(PI_INT_PEND0);
}
-static void ip27_do_irq_mask1(struct pt_regs *regs)
+static void ip27_do_irq_mask1(void)
{
int irq, swlevel;
hubreg_t pend1, mask1;
@@ -190,17 +189,17 @@ static void ip27_do_irq_mask1(struct pt_regs *regs)
/* "map" swlevel to irq */
irq = si->level_to_irq[swlevel];
LOCAL_HUB_CLR_INTR(swlevel);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
LOCAL_HUB_L(PI_INT_PEND1);
}
-static void ip27_prof_timer(struct pt_regs *regs)
+static void ip27_prof_timer(void)
{
panic("CPU %d got a profiling interrupt", smp_processor_id());
}
-static void ip27_hub_error(struct pt_regs *regs)
+static void ip27_hub_error(void)
{
panic("CPU %d got a hub error interrupt", smp_processor_id());
}
@@ -418,22 +417,22 @@ int __devinit request_bridge_irq(struct bridge_controller *bc)
return irq;
}
-extern void ip27_rt_timer_interrupt(struct pt_regs *regs);
+extern void ip27_rt_timer_interrupt(void);
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned long pending = read_c0_cause() & read_c0_status();
if (pending & CAUSEF_IP4)
- ip27_rt_timer_interrupt(regs);
+ ip27_rt_timer_interrupt();
else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */
- ip27_do_irq_mask0(regs);
+ ip27_do_irq_mask0();
else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */
- ip27_do_irq_mask1(regs);
+ ip27_do_irq_mask1();
else if (pending & CAUSEF_IP5)
- ip27_prof_timer(regs);
+ ip27_prof_timer();
else if (pending & CAUSEF_IP6)
- ip27_hub_error(regs);
+ ip27_hub_error();
}
void __init arch_init_irq(void)
diff --git a/arch/mips/sgi-ip27/ip27-klnuma.c b/arch/mips/sgi-ip27/ip27-klnuma.c
index d777b7d1a9fe..f9f404a8ddad 100644
--- a/arch/mips/sgi-ip27/ip27-klnuma.c
+++ b/arch/mips/sgi-ip27/ip27-klnuma.c
@@ -26,7 +26,7 @@ static cpumask_t ktext_repmask;
* kernel. For example, we should never put a copy on a headless node,
* and we should respect the topology of the machine.
*/
-void __init setup_replication_mask()
+void __init setup_replication_mask(void)
{
cnodeid_t cnode;
diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c
index b029ba79c27a..4e870fc4469b 100644
--- a/arch/mips/sgi-ip27/ip27-timer.c
+++ b/arch/mips/sgi-ip27/ip27-timer.c
@@ -42,8 +42,6 @@
static unsigned long ct_cur[NR_CPUS]; /* What counter should be at next timer irq */
static long last_rtc_update; /* Last time the rtc clock got updated */
-extern volatile unsigned long wall_jiffies;
-
#if 0
static int set_rtc_mmss(unsigned long nowtime)
{
@@ -91,7 +89,7 @@ static int set_rtc_mmss(unsigned long nowtime)
static unsigned int rt_timer_irq;
-void ip27_rt_timer_interrupt(struct pt_regs *regs)
+void ip27_rt_timer_interrupt(void)
{
int cpu = smp_processor_id();
int cpuA = cputoslice(cpu) == 0;
@@ -111,9 +109,9 @@ again:
kstat_this_cpu.irqs[irq]++; /* kstat only for bootcpu? */
if (cpu == 0)
- do_timer(regs);
+ do_timer(1);
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
/*
* If we have an externally synchronized Linux clock, then update
diff --git a/arch/mips/sgi-ip32/crime.c b/arch/mips/sgi-ip32/crime.c
index 41b5eca1148c..bff508704d03 100644
--- a/arch/mips/sgi-ip32/crime.c
+++ b/arch/mips/sgi-ip32/crime.c
@@ -14,7 +14,6 @@
#include <asm/bootinfo.h>
#include <asm/io.h>
#include <asm/mipsregs.h>
-#include <asm/ptrace.h>
#include <asm/page.h>
#include <asm/ip32/crime.h>
#include <asm/ip32/mace.h>
@@ -40,8 +39,7 @@ void __init crime_init(void)
id, rev, field, (unsigned long) CRIME_BASE);
}
-irqreturn_t
-crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t crime_memerr_intr(unsigned int irq, void *dev_id)
{
unsigned long stat, addr;
int fatal = 0;
@@ -92,8 +90,7 @@ crime_memerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-irqreturn_t
-crime_cpuerr_intr (unsigned int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t crime_cpuerr_intr(unsigned int irq, void *dev_id)
{
unsigned long stat = crime->cpu_error_stat & CRIME_CPU_ERROR_MASK;
unsigned long addr = crime->cpu_error_addr & CRIME_CPU_ERROR_ADDR_MASK;
diff --git a/arch/mips/sgi-ip32/ip32-irq.c b/arch/mips/sgi-ip32/ip32-irq.c
index c64a820373de..c9acadd0846b 100644
--- a/arch/mips/sgi-ip32/ip32-irq.c
+++ b/arch/mips/sgi-ip32/ip32-irq.c
@@ -120,10 +120,8 @@ static void inline flush_mace_bus(void)
static DEFINE_SPINLOCK(ip32_irq_lock);
/* Some initial interrupts to set up */
-extern irqreturn_t crime_memerr_intr (int irq, void *dev_id,
- struct pt_regs *regs);
-extern irqreturn_t crime_cpuerr_intr (int irq, void *dev_id,
- struct pt_regs *regs);
+extern irqreturn_t crime_memerr_intr(int irq, void *dev_id);
+extern irqreturn_t crime_cpuerr_intr(int irq, void *dev_id);
struct irqaction memerr_irq = { crime_memerr_intr, IRQF_DISABLED,
CPU_MASK_NONE, "CRIME memory error", NULL, NULL };
@@ -479,7 +477,7 @@ static struct irq_chip ip32_mace_interrupt = {
.end = end_mace_irq,
};
-static void ip32_unknown_interrupt(struct pt_regs *regs)
+static void ip32_unknown_interrupt(void)
{
printk ("Unknown interrupt occurred!\n");
printk ("cp0_status: %08x\n", read_c0_status());
@@ -492,7 +490,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs)
printk ("MACE PCI control register: %08x\n", mace->pci.control);
printk("Register dump:\n");
- show_regs(regs);
+ show_regs(get_irq_regs());
printk("Please mail this report to linux-mips@linux-mips.org\n");
printk("Spinning...");
@@ -501,7 +499,7 @@ static void ip32_unknown_interrupt(struct pt_regs *regs)
/* CRIME 1.1 appears to deliver all interrupts to this one pin. */
/* change this to loop over all edge-triggered irqs, exception masked out ones */
-static void ip32_irq0(struct pt_regs *regs)
+static void ip32_irq0(void)
{
uint64_t crime_int;
int irq = 0;
@@ -516,50 +514,50 @@ static void ip32_irq0(struct pt_regs *regs)
}
irq++;
DBG("*irq %u*\n", irq);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
-static void ip32_irq1(struct pt_regs *regs)
+static void ip32_irq1(void)
{
- ip32_unknown_interrupt(regs);
+ ip32_unknown_interrupt();
}
-static void ip32_irq2(struct pt_regs *regs)
+static void ip32_irq2(void)
{
- ip32_unknown_interrupt(regs);
+ ip32_unknown_interrupt();
}
-static void ip32_irq3(struct pt_regs *regs)
+static void ip32_irq3(void)
{
- ip32_unknown_interrupt(regs);
+ ip32_unknown_interrupt();
}
-static void ip32_irq4(struct pt_regs *regs)
+static void ip32_irq4(void)
{
- ip32_unknown_interrupt(regs);
+ ip32_unknown_interrupt();
}
-static void ip32_irq5(struct pt_regs *regs)
+static void ip32_irq5(void)
{
- ll_timer_interrupt(IP32_R4K_TIMER_IRQ, regs);
+ ll_timer_interrupt(IP32_R4K_TIMER_IRQ);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause();
if (likely(pending & IE_IRQ0))
- ip32_irq0(regs);
+ ip32_irq0();
else if (unlikely(pending & IE_IRQ1))
- ip32_irq1(regs);
+ ip32_irq1();
else if (unlikely(pending & IE_IRQ2))
- ip32_irq2(regs);
+ ip32_irq2();
else if (unlikely(pending & IE_IRQ3))
- ip32_irq3(regs);
+ ip32_irq3();
else if (unlikely(pending & IE_IRQ4))
- ip32_irq4(regs);
+ ip32_irq4();
else if (likely(pending & IE_IRQ5))
- ip32_irq5(regs);
+ ip32_irq5();
}
void __init arch_init_irq(void)
diff --git a/arch/mips/sgi-ip32/ip32-reset.c b/arch/mips/sgi-ip32/ip32-reset.c
index 79ddb4605659..db8084411538 100644
--- a/arch/mips/sgi-ip32/ip32-reset.c
+++ b/arch/mips/sgi-ip32/ip32-reset.c
@@ -120,7 +120,7 @@ static inline void ip32_power_button(void)
if (has_panicked)
return;
- if (shuting_down || kill_proc(1, SIGINT, 1)) {
+ if (shuting_down || kill_cad_pid(SIGINT, 1)) {
/* No init process or button pressed twice. */
ip32_machine_power_off();
}
@@ -135,7 +135,7 @@ static inline void ip32_power_button(void)
add_timer(&power_timer);
}
-static irqreturn_t ip32_rtc_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ip32_rtc_int(int irq, void *dev_id)
{
volatile unsigned char reg_c;
diff --git a/arch/mips/sibyte/bcm1480/irq.c b/arch/mips/sibyte/bcm1480/irq.c
index ed325f0ab28a..8b1f41484923 100644
--- a/arch/mips/sibyte/bcm1480/irq.c
+++ b/arch/mips/sibyte/bcm1480/irq.c
@@ -25,9 +25,9 @@
#include <linux/kernel_stat.h>
#include <asm/errno.h>
+#include <asm/irq_regs.h>
#include <asm/signal.h>
#include <asm/system.h>
-#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/sibyte/bcm1480_regs.h>
@@ -284,8 +284,7 @@ void __init init_bcm1480_irqs(void)
}
-static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t bcm1480_dummy_handler(int irq, void *dev_id)
{
return IRQ_NONE;
}
@@ -453,7 +452,7 @@ void __init arch_init_irq(void)
#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
-void bcm1480_kgdb_interrupt(struct pt_regs *regs)
+static void bcm1480_kgdb_interrupt(void)
{
/*
* Clear break-change status (allow some time for the remote
@@ -464,31 +463,15 @@ void bcm1480_kgdb_interrupt(struct pt_regs *regs)
mdelay(500);
duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
M_DUART_RX_EN | M_DUART_TX_EN);
- set_async_breakpoint(&regs->cp0_epc);
+ set_async_breakpoint(&get_irq_regs()->cp0_epc);
}
#endif /* CONFIG_KGDB */
-static inline int dclz(unsigned long long x)
-{
- int lz;
-
- __asm__ (
- " .set push \n"
- " .set mips64 \n"
- " dclz %0, %1 \n"
- " .set pop \n"
- : "=r" (lz)
- : "r" (x));
-
- return lz;
-}
-
-extern void bcm1480_timer_interrupt(struct pt_regs *regs);
-extern void bcm1480_mailbox_interrupt(struct pt_regs *regs);
-extern void bcm1480_kgdb_interrupt(struct pt_regs *regs);
+extern void bcm1480_timer_interrupt(void);
+extern void bcm1480_mailbox_interrupt(void);
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending;
@@ -497,25 +480,25 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
write_c0_compare(read_c0_count());
#endif
- pending = read_c0_cause();
+ pending = read_c0_cause() & read_c0_status();
#ifdef CONFIG_SIBYTE_BCM1480_PROF
if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */
- sbprof_cpu_intr(exception_epc(regs));
+ sbprof_cpu_intr();
else
#endif
if (pending & CAUSEF_IP4)
- bcm1480_timer_interrupt(regs);
+ bcm1480_timer_interrupt();
#ifdef CONFIG_SMP
else if (pending & CAUSEF_IP3)
- bcm1480_mailbox_interrupt(regs);
+ bcm1480_mailbox_interrupt();
#endif
#ifdef CONFIG_KGDB
else if (pending & CAUSEF_IP6)
- bcm1480_kgdb_interrupt(regs); /* KGDB (uart 1) */
+ bcm1480_kgdb_interrupt(); /* KGDB (uart 1) */
#endif
else if (pending & CAUSEF_IP2) {
@@ -536,9 +519,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
if (mask_h) {
if (mask_h ^ 1)
- do_IRQ(63 - dclz(mask_h), regs);
+ do_IRQ(fls64(mask_h) - 1);
else
- do_IRQ(127 - dclz(mask_l), regs);
+ do_IRQ(63 + fls64(mask_l));
}
}
}
diff --git a/arch/mips/sibyte/bcm1480/smp.c b/arch/mips/sibyte/bcm1480/smp.c
index 584a4b33faac..bf328277c775 100644
--- a/arch/mips/sibyte/bcm1480/smp.c
+++ b/arch/mips/sibyte/bcm1480/smp.c
@@ -34,21 +34,21 @@ extern void smp_call_function_interrupt(void);
* independent of board/firmware
*/
-static void *mailbox_0_set_regs[] = {
+static volatile void *mailbox_0_set_regs[] = {
IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_SET_CPU),
};
-static void *mailbox_0_clear_regs[] = {
+static volatile void *mailbox_0_clear_regs[] = {
IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
IOADDR(A_BCM1480_IMR_CPU3_BASE + R_BCM1480_IMR_MAILBOX_0_CLR_CPU),
};
-static void *mailbox_0_regs[] = {
+static volatile void *mailbox_0_regs[] = {
IOADDR(A_BCM1480_IMR_CPU0_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
IOADDR(A_BCM1480_IMR_CPU1_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
IOADDR(A_BCM1480_IMR_CPU2_BASE + R_BCM1480_IMR_MAILBOX_0_CPU),
@@ -88,7 +88,7 @@ void core_send_ipi(int cpu, unsigned int action)
__raw_writeq((((u64)action)<< 48), mailbox_0_set_regs[cpu]);
}
-void bcm1480_mailbox_interrupt(struct pt_regs *regs)
+void bcm1480_mailbox_interrupt(void)
{
int cpu = smp_processor_id();
unsigned int action;
diff --git a/arch/mips/sibyte/bcm1480/time.c b/arch/mips/sibyte/bcm1480/time.c
index 7e088f6c4a86..bf12af46132e 100644
--- a/arch/mips/sibyte/bcm1480/time.c
+++ b/arch/mips/sibyte/bcm1480/time.c
@@ -31,7 +31,6 @@
#include <linux/kernel_stat.h>
#include <asm/irq.h>
-#include <asm/ptrace.h>
#include <asm/addrspace.h>
#include <asm/time.h>
#include <asm/io.h>
@@ -100,10 +99,10 @@ void bcm1480_time_init(void)
#include <asm/sibyte/sb1250.h>
-void bcm1480_timer_interrupt(struct pt_regs *regs)
+void bcm1480_timer_interrupt(void)
{
int cpu = smp_processor_id();
- int irq = K_BCM1480_INT_TIMER_0+cpu;
+ int irq = K_BCM1480_INT_TIMER_0 + cpu;
/* Reset the timer */
__raw_writeq(M_SCD_TIMER_ENABLE|M_SCD_TIMER_MODE_CONTINUOUS,
@@ -113,13 +112,13 @@ void bcm1480_timer_interrupt(struct pt_regs *regs)
/*
* CPU 0 handles the global timer interrupt job
*/
- ll_timer_interrupt(irq, regs);
+ ll_timer_interrupt(irq);
}
else {
/*
* other CPUs should just do profiling and process accounting
*/
- ll_local_timer_interrupt(irq, regs);
+ ll_local_timer_interrupt(irq);
}
}
diff --git a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
index 992e0d8dbb67..d1a906e683b2 100644
--- a/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
+++ b/arch/mips/sibyte/sb1250/bcm1250_tbprof.c
@@ -88,7 +88,7 @@ static void arm_tb(void)
sbp.tb_armed = 1;
}
-static irqreturn_t sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sbprof_tb_intr(int irq, void *dev_id)
{
int i;
DBG(printk(DEVNAME ": tb_intr\n"));
@@ -138,7 +138,7 @@ static irqreturn_t sbprof_tb_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t sbprof_pc_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sbprof_pc_intr(int irq, void *dev_id)
{
printk(DEVNAME ": unexpected pc_intr");
return IRQ_NONE;
diff --git a/arch/mips/sibyte/sb1250/bus_watcher.c b/arch/mips/sibyte/sb1250/bus_watcher.c
index bb90649fbc48..45274bd3cd8b 100644
--- a/arch/mips/sibyte/sb1250/bus_watcher.c
+++ b/arch/mips/sibyte/sb1250/bus_watcher.c
@@ -171,7 +171,7 @@ static void create_proc_decoder(struct bw_stats_struct *stats)
* notes: possible re-entry due to multiple sources
* should check/indicate saturation
*/
-static irqreturn_t sibyte_bw_int(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t sibyte_bw_int(int irq, void *data)
{
struct bw_stats_struct *stats = data;
unsigned long cntr;
diff --git a/arch/mips/sibyte/sb1250/irq.c b/arch/mips/sibyte/sb1250/irq.c
index 1de71adec6c6..d5d26770daf6 100644
--- a/arch/mips/sibyte/sb1250/irq.c
+++ b/arch/mips/sibyte/sb1250/irq.c
@@ -28,7 +28,6 @@
#include <asm/errno.h>
#include <asm/signal.h>
#include <asm/system.h>
-#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/sibyte/sb1250_regs.h>
@@ -254,8 +253,7 @@ void __init init_sb1250_irqs(void)
}
-static irqreturn_t sb1250_dummy_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t sb1250_dummy_handler(int irq, void *dev_id)
{
return IRQ_NONE;
}
@@ -403,7 +401,7 @@ void __init arch_init_irq(void)
#define duart_out(reg, val) csr_out32(val, IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
#define duart_in(reg) csr_in32(IOADDR(A_DUART_CHANREG(kgdb_port,reg)))
-static void sb1250_kgdb_interrupt(struct pt_regs *regs)
+static void sb1250_kgdb_interrupt(void)
{
/*
* Clear break-change status (allow some time for the remote
@@ -414,31 +412,15 @@ static void sb1250_kgdb_interrupt(struct pt_regs *regs)
mdelay(500);
duart_out(R_DUART_CMD, V_DUART_MISC_CMD_RESET_BREAK_INT |
M_DUART_RX_EN | M_DUART_TX_EN);
- set_async_breakpoint(&regs->cp0_epc);
+ set_async_breakpoint(&get_irq_regs()->cp0_epc);
}
#endif /* CONFIG_KGDB */
-static inline int dclz(unsigned long long x)
-{
- int lz;
-
- __asm__ (
- " .set push \n"
- " .set mips64 \n"
- " dclz %0, %1 \n"
- " .set pop \n"
- : "=r" (lz)
- : "r" (x));
-
- return lz;
-}
-
-extern void sb1250_timer_interrupt(struct pt_regs *regs);
-extern void sb1250_mailbox_interrupt(struct pt_regs *regs);
-extern void sb1250_kgdb_interrupt(struct pt_regs *regs);
+extern void sb1250_timer_interrupt(void);
+extern void sb1250_mailbox_interrupt(void);
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending;
@@ -457,25 +439,25 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
* blasting the high 32 bits.
*/
- pending = read_c0_cause();
+ pending = read_c0_cause() & read_c0_status();
#ifdef CONFIG_SIBYTE_SB1250_PROF
if (pending & CAUSEF_IP7) /* Cpu performance counter interrupt */
- sbprof_cpu_intr(exception_epc(regs));
+ sbprof_cpu_intr();
else
#endif
if (pending & CAUSEF_IP4)
- sb1250_timer_interrupt(regs);
+ sb1250_timer_interrupt();
#ifdef CONFIG_SMP
else if (pending & CAUSEF_IP3)
- sb1250_mailbox_interrupt(regs);
+ sb1250_mailbox_interrupt();
#endif
#ifdef CONFIG_KGDB
else if (pending & CAUSEF_IP6) /* KGDB (uart 1) */
- sb1250_kgdb_interrupt(regs);
+ sb1250_kgdb_interrupt();
#endif
else if (pending & CAUSEF_IP2) {
@@ -490,6 +472,9 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
mask = __raw_readq(IOADDR(A_IMR_REGISTER(smp_processor_id(),
R_IMR_INTERRUPT_STATUS_BASE)));
if (mask)
- do_IRQ(63 - dclz(mask), regs);
- }
+ do_IRQ(fls64(mask) - 1);
+ else
+ spurious_interrupt();
+ } else
+ spurious_interrupt();
}
diff --git a/arch/mips/sibyte/sb1250/smp.c b/arch/mips/sibyte/sb1250/smp.c
index f859db02d3c9..c38e1f34460d 100644
--- a/arch/mips/sibyte/sb1250/smp.c
+++ b/arch/mips/sibyte/sb1250/smp.c
@@ -76,7 +76,7 @@ void core_send_ipi(int cpu, unsigned int action)
__raw_writeq((((u64)action) << 48), mailbox_set_regs[cpu]);
}
-void sb1250_mailbox_interrupt(struct pt_regs *regs)
+void sb1250_mailbox_interrupt(void)
{
int cpu = smp_processor_id();
unsigned int action;
diff --git a/arch/mips/sibyte/sb1250/time.c b/arch/mips/sibyte/sb1250/time.c
index 4b669dc86ef4..0ccf1796dd78 100644
--- a/arch/mips/sibyte/sb1250/time.c
+++ b/arch/mips/sibyte/sb1250/time.c
@@ -31,7 +31,6 @@
#include <linux/kernel_stat.h>
#include <asm/irq.h>
-#include <asm/ptrace.h>
#include <asm/addrspace.h>
#include <asm/time.h>
#include <asm/io.h>
@@ -125,7 +124,7 @@ void sb1250_time_init(void)
*/
}
-void sb1250_timer_interrupt(struct pt_regs *regs)
+void sb1250_timer_interrupt(void)
{
int cpu = smp_processor_id();
int irq = K_INT_TIMER_0 + cpu;
@@ -138,13 +137,13 @@ void sb1250_timer_interrupt(struct pt_regs *regs)
/*
* CPU 0 handles the global timer interrupt job
*/
- ll_timer_interrupt(irq, regs);
+ ll_timer_interrupt(irq);
}
else {
/*
* other CPUs should just do profiling and process accounting
*/
- ll_local_timer_interrupt(irq, regs);
+ ll_local_timer_interrupt(irq);
}
}
diff --git a/arch/mips/sni/irq.c b/arch/mips/sni/irq.c
index cda165f42b6a..48fb74a7aaec 100644
--- a/arch/mips/sni/irq.c
+++ b/arch/mips/sni/irq.c
@@ -69,20 +69,20 @@ static struct irq_chip pciasic_irq_type = {
* hwint0 should deal with MP agent, ASIC PCI, EISA NMI and debug
* button interrupts. Later ...
*/
-static void pciasic_hwint0(struct pt_regs *regs)
+static void pciasic_hwint0(void)
{
panic("Received int0 but no handler yet ...");
}
/* This interrupt was used for the com1 console on the first prototypes. */
-static void pciasic_hwint2(struct pt_regs *regs)
+static void pciasic_hwint2(void)
{
/* I think this shouldn't happen on production machines. */
panic("hwint2 and no handler yet");
}
/* hwint5 is the r4k count / compare interrupt */
-static void pciasic_hwint5(struct pt_regs *regs)
+static void pciasic_hwint5(void)
{
panic("hwint5 and no handler yet");
}
@@ -103,7 +103,7 @@ static unsigned int ls1bit8(unsigned int x)
*
* The EISA_INT bit in CSITPEND is high active, all others are low active.
*/
-static void pciasic_hwint1(struct pt_regs *regs)
+static void pciasic_hwint1(void)
{
u8 pend = *(volatile char *)PCIMT_CSITPEND;
unsigned long flags;
@@ -119,13 +119,13 @@ static void pciasic_hwint1(struct pt_regs *regs)
if (unlikely(irq < 0))
return;
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
if (!(pend & IT_SCSI)) {
flags = read_c0_status();
clear_c0_status(ST0_IM);
- do_IRQ(PCIMT_IRQ_SCSI, regs);
+ do_IRQ(PCIMT_IRQ_SCSI);
write_c0_status(flags);
}
}
@@ -133,7 +133,7 @@ static void pciasic_hwint1(struct pt_regs *regs)
/*
* hwint 3 should deal with the PCI A - D interrupts,
*/
-static void pciasic_hwint3(struct pt_regs *regs)
+static void pciasic_hwint3(void)
{
u8 pend = *(volatile char *)PCIMT_CSITPEND;
int irq;
@@ -141,21 +141,21 @@ static void pciasic_hwint3(struct pt_regs *regs)
pend &= (IT_INTA | IT_INTB | IT_INTC | IT_INTD);
clear_c0_status(IE_IRQ3);
irq = PCIMT_IRQ_INT2 + ls1bit8(pend);
- do_IRQ(irq, regs);
+ do_IRQ(irq);
set_c0_status(IE_IRQ3);
}
/*
* hwint 4 is used for only the onboard PCnet 32.
*/
-static void pciasic_hwint4(struct pt_regs *regs)
+static void pciasic_hwint4(void)
{
clear_c0_status(IE_IRQ4);
- do_IRQ(PCIMT_IRQ_ETHERNET, regs);
+ do_IRQ(PCIMT_IRQ_ETHERNET);
set_c0_status(IE_IRQ4);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
static unsigned char led_cache;
@@ -163,17 +163,17 @@ asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
*(volatile unsigned char *) PCIMT_CSLED = ++led_cache;
if (pending & 0x0800)
- pciasic_hwint1(regs);
+ pciasic_hwint1();
else if (pending & 0x4000)
- pciasic_hwint4(regs);
+ pciasic_hwint4();
else if (pending & 0x2000)
- pciasic_hwint3(regs);
+ pciasic_hwint3();
else if (pending & 0x1000)
- pciasic_hwint2(regs);
+ pciasic_hwint2();
else if (pending & 0x8000)
- pciasic_hwint5(regs);
+ pciasic_hwint5();
else if (pending & 0x0400)
- pciasic_hwint0(regs);
+ pciasic_hwint0();
}
void __init init_pciasic(void)
diff --git a/arch/mips/sni/setup.c b/arch/mips/sni/setup.c
index 4e98feb15410..afeb7f13e5b5 100644
--- a/arch/mips/sni/setup.c
+++ b/arch/mips/sni/setup.c
@@ -31,7 +31,6 @@
#include <asm/irq.h>
#include <asm/mc146818-time.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/sni.h>
#include <asm/time.h>
diff --git a/arch/mips/tx4927/common/tx4927_irq.c b/arch/mips/tx4927/common/tx4927_irq.c
index cd176f6a06c8..8266a88a3f88 100644
--- a/arch/mips/tx4927/common/tx4927_irq.c
+++ b/arch/mips/tx4927/common/tx4927_irq.c
@@ -576,24 +576,24 @@ static int tx4927_irq_nested(void)
return (sw_irq);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_status() & read_c0_cause();
if (pending & STATUSF_IP7) /* cpu timer */
- do_IRQ(TX4927_IRQ_CPU_TIMER, regs);
+ do_IRQ(TX4927_IRQ_CPU_TIMER);
else if (pending & STATUSF_IP2) { /* tx4927 pic */
unsigned int irq = tx4927_irq_nested();
if (unlikely(irq == 0)) {
- spurious_interrupt(regs);
+ spurious_interrupt();
return;
}
- do_IRQ(irq, regs);
+ do_IRQ(irq);
} else if (pending & STATUSF_IP0) /* user line 0 */
- do_IRQ(TX4927_IRQ_USER0, regs);
+ do_IRQ(TX4927_IRQ_USER0);
else if (pending & STATUSF_IP1) /* user line 1 */
- do_IRQ(TX4927_IRQ_USER1, regs);
+ do_IRQ(TX4927_IRQ_USER1);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
diff --git a/arch/mips/tx4927/common/tx4927_setup.c b/arch/mips/tx4927/common/tx4927_setup.c
index 3ace4037343e..4658b2ae4833 100644
--- a/arch/mips/tx4927/common/tx4927_setup.c
+++ b/arch/mips/tx4927/common/tx4927_setup.c
@@ -53,19 +53,9 @@ void __init tx4927_time_init(void);
void dump_cp0(char *key);
-void (*__wbflush) (void);
-
-static void tx4927_write_buffer_flush(void)
-{
- __asm__ __volatile__
- ("sync\n\t" "nop\n\t" "loop: bc0f loop\n\t" "nop\n\t");
-}
-
-
void __init plat_mem_setup(void)
{
board_time_init = tx4927_time_init;
- __wbflush = tx4927_write_buffer_flush;
#ifdef CONFIG_TOSHIBA_RBTX4927
{
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
index b0f021f2a6c4..0c3c3f668230 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
@@ -127,9 +127,9 @@ JP7 is not bus master -- do NOT use -- only 4 pci bus master's allowed -- SouthB
#include <asm/irq.h>
#include <asm/pci.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/time.h>
+#include <asm/wbflush.h>
#include <linux/bootmem.h>
#include <linux/blkdev.h>
#ifdef CONFIG_RTC_DS1742
diff --git a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
index f0d70c476005..735cb8778f4c 100644
--- a/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
+++ b/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c
@@ -58,8 +58,8 @@
#include <asm/page.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/irq_regs.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/time.h>
#include <linux/bootmem.h>
@@ -160,8 +160,7 @@ int tx4927_pci66 = 0; /* 0:auto */
char *toshiba_name = "";
#ifdef CONFIG_PCI
-static void tx4927_pcierr_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static void tx4927_pcierr_interrupt(int irq, void *dev_id)
{
#ifdef CONFIG_BLK_DEV_IDEPCI
/* ignore MasterAbort for ide probing... */
@@ -185,7 +184,7 @@ static void tx4927_pcierr_interrupt(int irq, void *dev_id,
(unsigned long) tx4927_ccfgptr->ccfg,
(unsigned long) (tx4927_ccfgptr->tear >> 32),
(unsigned long) tx4927_ccfgptr->tear);
- show_regs(regs);
+ show_regs(get_irq_regs());
}
void __init toshiba_rbtx4927_pci_irq_init(void)
diff --git a/arch/mips/tx4938/common/irq.c b/arch/mips/tx4938/common/irq.c
index dc30d66123b6..77fe2454f5b9 100644
--- a/arch/mips/tx4938/common/irq.c
+++ b/arch/mips/tx4938/common/irq.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/mps/tx4938/common/irq.c
+ * linux/arch/mips/tx4938/common/irq.c
*
* Common tx4938 irq handler
* Copyright (C) 2000-2001 Toshiba Corporation
@@ -30,6 +30,7 @@
#include <asm/irq.h>
#include <asm/mipsregs.h>
#include <asm/system.h>
+#include <asm/wbflush.h>
#include <asm/tx4938/rbtx4938.h>
/**********************************************************************************/
@@ -104,8 +105,6 @@ tx4938_irq_cp0_init(void)
irq_desc[i].depth = 1;
irq_desc[i].chip = &tx4938_irq_cp0_type;
}
-
- return;
}
static unsigned int
@@ -113,7 +112,7 @@ tx4938_irq_cp0_startup(unsigned int irq)
{
tx4938_irq_cp0_enable(irq);
- return (0);
+ return 0;
}
static void
@@ -144,16 +143,12 @@ tx4938_irq_cp0_disable(unsigned int irq)
clear_c0_status(tx4938_irq_cp0_mask(irq));
spin_unlock_irqrestore(&tx4938_cp0_lock, flags);
-
- return;
}
static void
tx4938_irq_cp0_mask_and_ack(unsigned int irq)
{
tx4938_irq_cp0_disable(irq);
-
- return;
}
static void
@@ -162,8 +157,6 @@ tx4938_irq_cp0_end(unsigned int irq)
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
tx4938_irq_cp0_enable(irq);
}
-
- return;
}
/**********************************************************************************/
@@ -227,7 +220,7 @@ tx4938_irq_pic_addr(int irq)
}
}
- return (0);
+ return 0;
}
u32
@@ -278,7 +271,7 @@ tx4938_irq_pic_mask(int irq)
return (0x00000007);
}
}
- return (0x00000000);
+ return 0x00000000;
}
static void
@@ -292,8 +285,6 @@ tx4938_irq_pic_modify(unsigned pic_reg, unsigned clr_bits, unsigned set_bits)
TX4938_WR(pic_reg, val);
mmiowb();
TX4938_RD(pic_reg);
-
- return;
}
static void __init
@@ -317,8 +308,6 @@ tx4938_irq_pic_init(void)
TX4938_WR(0xff1ff600, TX4938_RD(0xff1ff600) | 0x1); /* irq enable */
spin_unlock_irqrestore(&tx4938_pic_lock, flags);
-
- return;
}
static unsigned int
@@ -326,15 +315,13 @@ tx4938_irq_pic_startup(unsigned int irq)
{
tx4938_irq_pic_enable(irq);
- return (0);
+ return 0;
}
static void
tx4938_irq_pic_shutdown(unsigned int irq)
{
tx4938_irq_pic_disable(irq);
-
- return;
}
static void
@@ -348,8 +335,6 @@ tx4938_irq_pic_enable(unsigned int irq)
tx4938_irq_pic_mask(irq));
spin_unlock_irqrestore(&tx4938_pic_lock, flags);
-
- return;
}
static void
@@ -363,16 +348,12 @@ tx4938_irq_pic_disable(unsigned int irq)
tx4938_irq_pic_mask(irq), 0);
spin_unlock_irqrestore(&tx4938_pic_lock, flags);
-
- return;
}
static void
tx4938_irq_pic_mask_and_ack(unsigned int irq)
{
tx4938_irq_pic_disable(irq);
-
- return;
}
static void
@@ -381,8 +362,6 @@ tx4938_irq_pic_end(unsigned int irq)
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))) {
tx4938_irq_pic_enable(irq);
}
-
- return;
}
/**********************************************************************************/
@@ -394,8 +373,6 @@ tx4938_irq_init(void)
{
tx4938_irq_cp0_init();
tx4938_irq_pic_init();
-
- return;
}
int
@@ -417,23 +394,23 @@ tx4938_irq_nested(void)
}
wbflush();
- return (sw_irq);
+ return sw_irq;
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status();
if (pending & STATUSF_IP7)
- do_IRQ(TX4938_IRQ_CPU_TIMER, regs);
+ do_IRQ(TX4938_IRQ_CPU_TIMER);
else if (pending & STATUSF_IP2) {
int irq = tx4938_irq_nested();
if (irq)
- do_IRQ(irq, regs);
+ do_IRQ(irq);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
} else if (pending & STATUSF_IP1)
- do_IRQ(TX4938_IRQ_USER1, regs);
+ do_IRQ(TX4938_IRQ_USER1);
else if (pending & STATUSF_IP0)
- do_IRQ(TX4938_IRQ_USER0, regs);
+ do_IRQ(TX4938_IRQ_USER0);
}
diff --git a/arch/mips/tx4938/common/setup.c b/arch/mips/tx4938/common/setup.c
index 71859c4fee84..f415a1f18fba 100644
--- a/arch/mips/tx4938/common/setup.c
+++ b/arch/mips/tx4938/common/setup.c
@@ -41,29 +41,10 @@ void __init tx4938_setup(void);
void __init tx4938_time_init(void);
void dump_cp0(char *key);
-void (*__wbflush) (void);
-
-static void
-tx4938_write_buffer_flush(void)
-{
- mmiowb();
-
- __asm__ __volatile__(
- ".set push\n\t"
- ".set noreorder\n\t"
- "lw $0,%0\n\t"
- "nop\n\t"
- ".set pop"
- : /* no output */
- : "m" (*(int *)KSEG1)
- : "memory");
-}
-
void __init
plat_mem_setup(void)
{
board_time_init = tx4938_time_init;
- __wbflush = tx4938_write_buffer_flush;
toshiba_rbtx4938_setup();
}
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/irq.c b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
index 83f2750825a4..102e473c10a2 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/irq.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/irq.c
@@ -81,9 +81,9 @@ IRQ Device
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
-#include <asm/ptrace.h>
#include <asm/reboot.h>
#include <asm/time.h>
+#include <asm/wbflush.h>
#include <linux/bootmem.h>
#include <asm/tx4938/rbtx4938.h>
diff --git a/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
index fae3136f462d..b926e6a75c29 100644
--- a/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
+++ b/arch/mips/tx4938/toshiba_rbtx4938/spi_txx9.c
@@ -35,7 +35,8 @@ void __init txx9_spi_init(unsigned long base, int (*cs_func)(int chipid, int on)
}
static DECLARE_WAIT_QUEUE_HEAD(txx9_spi_wait);
-static void txx9_spi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+
+static void txx9_spi_interrupt(int irq, void *dev_id)
{
/* disable rx intr */
tx4938_spiptr->cr0 &= ~TXx9_SPCR0_RBSIE;
diff --git a/arch/mips/vr41xx/common/icu.c b/arch/mips/vr41xx/common/icu.c
index 7a5c31d58378..c215c0d39fae 100644
--- a/arch/mips/vr41xx/common/icu.c
+++ b/arch/mips/vr41xx/common/icu.c
@@ -635,7 +635,7 @@ int vr41xx_set_intassign(unsigned int irq, unsigned char intassign)
EXPORT_SYMBOL(vr41xx_set_intassign);
-static int icu_get_irq(unsigned int irq, struct pt_regs *regs)
+static int icu_get_irq(unsigned int irq)
{
uint16_t pend1, pend2;
uint16_t mask1, mask2;
diff --git a/arch/mips/vr41xx/common/irq.c b/arch/mips/vr41xx/common/irq.c
index 4733c5344467..397ba94cd7ec 100644
--- a/arch/mips/vr41xx/common/irq.c
+++ b/arch/mips/vr41xx/common/irq.c
@@ -25,7 +25,7 @@
#include <asm/vr41xx/irq.h>
typedef struct irq_cascade {
- int (*get_irq)(unsigned int, struct pt_regs *);
+ int (*get_irq)(unsigned int);
} irq_cascade_t;
static irq_cascade_t irq_cascade[NR_IRQS] __cacheline_aligned;
@@ -36,7 +36,7 @@ static struct irqaction cascade_irqaction = {
.name = "cascade",
};
-int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *))
+int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int))
{
int retval = 0;
@@ -59,7 +59,7 @@ int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *)
EXPORT_SYMBOL_GPL(cascade_irq);
-static void irq_dispatch(unsigned int irq, struct pt_regs *regs)
+static void irq_dispatch(unsigned int irq)
{
irq_cascade_t *cascade;
struct irq_desc *desc;
@@ -74,39 +74,39 @@ static void irq_dispatch(unsigned int irq, struct pt_regs *regs)
unsigned int source_irq = irq;
desc = irq_desc + source_irq;
desc->chip->ack(source_irq);
- irq = cascade->get_irq(irq, regs);
+ irq = cascade->get_irq(irq);
if (irq < 0)
atomic_inc(&irq_err_count);
else
- irq_dispatch(irq, regs);
+ irq_dispatch(irq);
desc->chip->end(source_irq);
} else
- do_IRQ(irq, regs);
+ do_IRQ(irq);
}
-asmlinkage void plat_irq_dispatch(struct pt_regs *regs)
+asmlinkage void plat_irq_dispatch(void)
{
unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
if (pending & CAUSEF_IP7)
- do_IRQ(7, regs);
+ do_IRQ(7);
else if (pending & 0x7800) {
if (pending & CAUSEF_IP3)
- irq_dispatch(3, regs);
+ irq_dispatch(3);
else if (pending & CAUSEF_IP4)
- irq_dispatch(4, regs);
+ irq_dispatch(4);
else if (pending & CAUSEF_IP5)
- irq_dispatch(5, regs);
+ irq_dispatch(5);
else if (pending & CAUSEF_IP6)
- irq_dispatch(6, regs);
+ irq_dispatch(6);
} else if (pending & CAUSEF_IP2)
- irq_dispatch(2, regs);
+ irq_dispatch(2);
else if (pending & CAUSEF_IP0)
- do_IRQ(0, regs);
+ do_IRQ(0);
else if (pending & CAUSEF_IP1)
- do_IRQ(1, regs);
+ do_IRQ(1);
else
- spurious_interrupt(regs);
+ spurious_interrupt();
}
void __init arch_init_irq(void)
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index 6dd0ea8f88e0..d2101237442e 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -127,7 +127,7 @@ config PA11
config PREFETCH
def_bool y
- depends on PA8X00
+ depends on PA8X00 || PA7200
config 64BIT
bool "64-bit kernel"
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index d7c80edf4489..4204cd1f3cf9 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -73,26 +73,30 @@ struct getdents_callback {
#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
- ino_t ino, unsigned d_type)
+ u64 ino, unsigned d_type)
{
struct hpux_dirent * dirent;
struct getdents_callback * buf = (struct getdents_callback *) __buf;
+ ino_t d_ino;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
if (dirent)
put_user(offset, &dirent->d_off);
dirent = buf->current_dir;
buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(reclen, &dirent->d_reclen);
put_user(namlen, &dirent->d_namlen);
copy_to_user(dirent->d_name, name, namlen);
put_user(0, dirent->d_name + namlen);
- ((char *) dirent) += reclen;
+ dirent = (void __user *)dirent + reclen;
buf->current_dir = dirent;
buf->count -= reclen;
return 0;
diff --git a/arch/parisc/hpux/sys_hpux.c b/arch/parisc/hpux/sys_hpux.c
index cb69727027ae..2e2dc4f2c853 100644
--- a/arch/parisc/hpux/sys_hpux.c
+++ b/arch/parisc/hpux/sys_hpux.c
@@ -266,16 +266,21 @@ static int hpux_uname(struct hpux_utsname *name)
down_read(&uts_sem);
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1);
- error |= __put_user(0,name->sysname+HPUX_UTSLEN-1);
- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1);
- error |= __put_user(0,name->nodename+HPUX_UTSLEN-1);
- error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1);
- error |= __put_user(0,name->release+HPUX_UTSLEN-1);
- error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1);
- error |= __put_user(0,name->version+HPUX_UTSLEN-1);
- error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1);
- error |= __put_user(0,name->machine+HPUX_UTSLEN-1);
+ error = __copy_to_user(&name->sysname, &utsname()->sysname,
+ HPUX_UTSLEN - 1);
+ error |= __put_user(0, name->sysname + HPUX_UTSLEN - 1);
+ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+ HPUX_UTSLEN - 1);
+ error |= __put_user(0, name->nodename + HPUX_UTSLEN - 1);
+ error |= __copy_to_user(&name->release, &utsname()->release,
+ HPUX_UTSLEN - 1);
+ error |= __put_user(0, name->release + HPUX_UTSLEN - 1);
+ error |= __copy_to_user(&name->version, &utsname()->version,
+ HPUX_UTSLEN - 1);
+ error |= __put_user(0, name->version + HPUX_UTSLEN - 1);
+ error |= __copy_to_user(&name->machine, &utsname()->machine,
+ HPUX_UTSLEN - 1);
+ error |= __put_user(0, name->machine + HPUX_UTSLEN - 1);
up_read(&uts_sem);
@@ -373,8 +378,8 @@ int hpux_utssys(char *ubuf, int n, int type)
/* TODO: print a warning about using this? */
down_write(&uts_sem);
error = -EFAULT;
- if (!copy_from_user(system_utsname.sysname, ubuf, len)) {
- system_utsname.sysname[len] = 0;
+ if (!copy_from_user(utsname()->sysname, ubuf, len)) {
+ utsname()->sysname[len] = 0;
error = 0;
}
up_write(&uts_sem);
@@ -400,8 +405,8 @@ int hpux_utssys(char *ubuf, int n, int type)
/* TODO: print a warning about this? */
down_write(&uts_sem);
error = -EFAULT;
- if (!copy_from_user(system_utsname.release, ubuf, len)) {
- system_utsname.release[len] = 0;
+ if (!copy_from_user(utsname()->release, ubuf, len)) {
+ utsname()->release[len] = 0;
error = 0;
}
up_write(&uts_sem);
@@ -422,13 +427,13 @@ int hpux_getdomainname(char *name, int len)
down_read(&uts_sem);
- nlen = strlen(system_utsname.domainname) + 1;
+ nlen = strlen(utsname()->domainname) + 1;
if (nlen < len)
len = nlen;
if(len > __NEW_UTS_LEN)
goto done;
- if(copy_to_user(name, system_utsname.domainname, len))
+ if(copy_to_user(name, utsname()->domainname, len))
goto done;
err = 0;
done:
diff --git a/arch/parisc/kernel/binfmt_elf32.c b/arch/parisc/kernel/binfmt_elf32.c
index d1833f164bbe..1e64e7b88110 100644
--- a/arch/parisc/kernel/binfmt_elf32.c
+++ b/arch/parisc/kernel/binfmt_elf32.c
@@ -87,7 +87,7 @@ struct elf_prpsinfo32
*/
#define SET_PERSONALITY(ex, ibcs2) \
- current->personality = PER_LINUX32; \
+ set_thread_flag(TIF_32BIT); \
current->thread.map_base = DEFAULT_MAP_BASE32; \
current->thread.task_size = DEFAULT_TASK_SIZE32 \
@@ -102,25 +102,3 @@ cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
}
#include "../../../fs/binfmt_elf.c"
-
-/* Set up a separate execution domain for ELF32 binaries running
- * on an ELF64 kernel */
-
-static struct exec_domain parisc32_exec_domain = {
- .name = "Linux/ELF32",
- .pers_low = PER_LINUX32,
- .pers_high = PER_LINUX32,
-};
-
-static int __init parisc32_exec_init(void)
-{
- /* steal the identity signal mappings from the default domain */
- parisc32_exec_domain.signal_map = default_exec_domain.signal_map;
- parisc32_exec_domain.signal_invmap = default_exec_domain.signal_invmap;
-
- register_exec_domain(&parisc32_exec_domain);
-
- return 0;
-}
-
-__initcall(parisc32_exec_init);
diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c
index bc7c4a4e26a1..0be51e92a2fc 100644
--- a/arch/parisc/kernel/cache.c
+++ b/arch/parisc/kernel/cache.c
@@ -35,15 +35,12 @@ int icache_stride __read_mostly;
EXPORT_SYMBOL(dcache_stride);
-#if defined(CONFIG_SMP)
/* On some machines (e.g. ones with the Merced bus), there can be
* only a single PxTLB broadcast at a time; this must be guaranteed
* by software. We put a spinlock around all TLB flushes to
* ensure this.
*/
DEFINE_SPINLOCK(pa_tlb_lock);
-EXPORT_SYMBOL(pa_tlb_lock);
-#endif
struct pdc_cache_info cache_info __read_mostly;
#ifndef CONFIG_PA20
@@ -91,7 +88,8 @@ update_mmu_cache(struct vm_area_struct *vma, unsigned long address, pte_t pte)
flush_kernel_dcache_page(page);
clear_bit(PG_dcache_dirty, &page->flags);
- }
+ } else if (parisc_requires_coherency())
+ flush_kernel_dcache_page(page);
}
void
@@ -370,3 +368,45 @@ void parisc_setup_cache_timing(void)
printk(KERN_INFO "Setting cache flush threshold to %x (%d CPUs online)\n", parisc_cache_flush_threshold, num_online_cpus());
}
+
+extern void purge_kernel_dcache_page(unsigned long);
+extern void clear_user_page_asm(void *page, unsigned long vaddr);
+
+void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
+{
+ purge_kernel_dcache_page((unsigned long)page);
+ purge_tlb_start();
+ pdtlb_kernel(page);
+ purge_tlb_end();
+ clear_user_page_asm(page, vaddr);
+}
+EXPORT_SYMBOL(clear_user_page);
+
+void flush_kernel_dcache_page_addr(void *addr)
+{
+ flush_kernel_dcache_page_asm(addr);
+ purge_tlb_start();
+ pdtlb_kernel(addr);
+ purge_tlb_end();
+}
+EXPORT_SYMBOL(flush_kernel_dcache_page_addr);
+
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+ struct page *pg)
+{
+ /* no coherency needed (all in kmap/kunmap) */
+ copy_user_page_asm(vto, vfrom);
+ if (!parisc_requires_coherency())
+ flush_kernel_dcache_page_asm(vto);
+}
+EXPORT_SYMBOL(copy_user_page);
+
+#ifdef CONFIG_PA8X00
+
+void kunmap_parisc(void *addr)
+{
+ if (parisc_requires_coherency())
+ flush_kernel_dcache_page_addr(addr);
+}
+EXPORT_SYMBOL(kunmap_parisc);
+#endif
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 3d569a485a1a..d6c486e9501c 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -424,7 +424,10 @@ struct parisc_device * create_tree_node(char id, struct device *parent)
/* make the generic dma mask a pointer to the parisc one */
dev->dev.dma_mask = &dev->dma_mask;
dev->dev.coherent_dma_mask = dev->dma_mask;
- device_register(&dev->dev);
+ if (device_register(&dev->dev)) {
+ kfree(dev);
+ return NULL;
+ }
return dev;
}
@@ -850,8 +853,10 @@ static void print_parisc_device(struct parisc_device *dev)
*/
void init_parisc_bus(void)
{
- bus_register(&parisc_bus_type);
- device_register(&root);
+ if (bus_register(&parisc_bus_type))
+ panic("Could not register PA-RISC bus type\n");
+ if (device_register(&root))
+ panic("Could not register PA-RISC root device\n");
get_device(&root);
}
diff --git a/arch/parisc/kernel/entry.S b/arch/parisc/kernel/entry.S
index 95c1b8ec4289..340b5e8d67ba 100644
--- a/arch/parisc/kernel/entry.S
+++ b/arch/parisc/kernel/entry.S
@@ -30,6 +30,7 @@
#include <asm/psw.h>
+#include <asm/cache.h> /* for L1_CACHE_SHIFT */
#include <asm/assembly.h> /* for LDREG/STREG defines */
#include <asm/pgtable.h>
#include <asm/signal.h>
@@ -478,11 +479,7 @@
bb,>=,n \pmd,_PxD_PRESENT_BIT,\fault
DEP %r0,31,PxD_FLAG_SHIFT,\pmd /* clear flags */
copy \pmd,%r9
-#ifdef CONFIG_64BIT
- shld %r9,PxD_VALUE_SHIFT,\pmd
-#else
- shlw %r9,PxD_VALUE_SHIFT,\pmd
-#endif
+ SHLREG %r9,PxD_VALUE_SHIFT,\pmd
EXTR \va,31-PAGE_SHIFT,ASM_BITS_PER_PTE,\index
DEP %r0,31,PAGE_SHIFT,\pmd /* clear offset */
shladd \index,BITS_PER_PTE_ENTRY,\pmd,\pmd
@@ -941,8 +938,8 @@ syscall_exit_rfi:
* to "proper" values now (otherwise we'll wind up restoring
* whatever was last stored in the task structure, which might
* be inconsistent if an interrupt occured while on the gateway
- * page) Note that we may be "trashing" values the user put in
- * them, but we don't support the the user changing them.
+ * page). Note that we may be "trashing" values the user put in
+ * them, but we don't support the user changing them.
*/
STREG %r0,PT_SR2(%r16)
@@ -970,11 +967,7 @@ intr_return:
/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) amount
** irq_stat[] is defined using ____cacheline_aligned.
*/
-#ifdef CONFIG_64BIT
- shld %r1, 6, %r20
-#else
- shlw %r1, 5, %r20
-#endif
+ SHLREG %r1,L1_CACHE_SHIFT,%r20
add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
#endif /* CONFIG_SMP */
@@ -1076,7 +1069,7 @@ intr_do_preempt:
BL preempt_schedule_irq, %r2
nop
- b intr_restore /* ssm PSW_SM_I done by intr_restore */
+ b,n intr_restore /* ssm PSW_SM_I done by intr_restore */
#endif /* CONFIG_PREEMPT */
.import do_signal,code
@@ -2115,11 +2108,7 @@ syscall_check_bh:
ldw TI_CPU-THREAD_SZ_ALGN-FRAME_SIZE(%r30),%r26 /* cpu # */
/* shift left ____cacheline_aligned (aka L1_CACHE_BYTES) bits */
-#ifdef CONFIG_64BIT
- shld %r26, 6, %r20
-#else
- shlw %r26, 5, %r20
-#endif
+ SHLREG %r26,L1_CACHE_SHIFT,%r20
add %r19,%r20,%r19 /* now have &irq_stat[smp_processor_id()] */
#endif /* CONFIG_SMP */
diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c
index 4398d2a95789..9158b707c0dd 100644
--- a/arch/parisc/kernel/firmware.c
+++ b/arch/parisc/kernel/firmware.c
@@ -160,13 +160,14 @@ void __init set_firmware_width(void)
{
#ifdef __LP64__
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
if(pdc_result[0] != NARROW_FIRMWARE)
parisc_narrow_firmware = 0;
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
#endif
}
@@ -196,10 +197,11 @@ void pdc_emergency_unlock(void)
int pdc_add_valid(unsigned long address)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_ADD_VALID, PDC_ADD_VALID_VERIFY, address);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -216,15 +218,16 @@ EXPORT_SYMBOL(pdc_add_valid);
int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_info, unsigned long len)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
memcpy(&pdc_result, chassis_info, sizeof(*chassis_info));
memcpy(&pdc_result2, led_info, len);
retval = mem_pdc_call(PDC_CHASSIS, PDC_RETURN_CHASSIS_INFO,
__pa(pdc_result), __pa(pdc_result2), len);
memcpy(chassis_info, pdc_result, sizeof(*chassis_info));
memcpy(led_info, pdc_result2, len);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -239,13 +242,14 @@ int __init pdc_chassis_info(struct pdc_chassis_info *chassis_info, void *led_inf
int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
{
int retval = 0;
+ unsigned long flags;
if (!is_pdc_pat())
return -1;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_CHASSIS_LOG, PDC_PAT_CHASSIS_WRITE_LOG, __pa(&state), __pa(&data));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -258,10 +262,11 @@ int pdc_pat_chassis_send_log(unsigned long state, unsigned long data)
int pdc_chassis_disp(unsigned long disp)
{
int retval = 0;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_DISP, disp);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -273,11 +278,12 @@ int pdc_chassis_disp(unsigned long disp)
int pdc_chassis_warn(unsigned long *warn)
{
int retval = 0;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_CHASSIS, PDC_CHASSIS_WARN, __pa(pdc_result));
*warn = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -292,15 +298,16 @@ int pdc_chassis_warn(unsigned long *warn)
int __init pdc_coproc_cfg(struct pdc_coproc_cfg *pdc_coproc_info)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_COPROC, PDC_COPROC_CFG, __pa(pdc_result));
convert_to_wide(pdc_result);
pdc_coproc_info->ccr_functional = pdc_result[0];
pdc_coproc_info->ccr_present = pdc_result[1];
pdc_coproc_info->revision = pdc_result[17];
pdc_coproc_info->model = pdc_result[18];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -320,14 +327,15 @@ int pdc_iodc_read(unsigned long *actcnt, unsigned long hpa, unsigned int index,
void *iodc_data, unsigned int iodc_data_size)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_IODC, PDC_IODC_READ, __pa(pdc_result), hpa,
index, __pa(pdc_result2), iodc_data_size);
convert_to_wide(pdc_result);
*actcnt = pdc_result[0];
memcpy(iodc_data, pdc_result2, iodc_data_size);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -346,14 +354,15 @@ int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,
struct pdc_module_path *mod_path, long mod_index)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result),
__pa(pdc_result2), mod_index);
convert_to_wide(pdc_result);
memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info));
memcpy(mod_path, pdc_result2, sizeof(*mod_path));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
pdc_mod_info->mod_addr = f_extend(pdc_mod_info->mod_addr);
return retval;
@@ -372,13 +381,14 @@ int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info,
long mod_index, long addr_index)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_ADDRESS, __pa(pdc_result),
mod_index, addr_index);
convert_to_wide(pdc_result);
memcpy(pdc_addr_info, pdc_result, sizeof(*pdc_addr_info));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
pdc_addr_info->mod_addr = f_extend(pdc_addr_info->mod_addr);
return retval;
@@ -393,12 +403,13 @@ int pdc_system_map_find_addrs(struct pdc_system_map_addr_info *pdc_addr_info,
int pdc_model_info(struct pdc_model *model)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_INFO, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
memcpy(model, pdc_result, sizeof(*model));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -414,8 +425,9 @@ int pdc_model_info(struct pdc_model *model)
int pdc_model_sysmodel(char *name)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_SYSMODEL, __pa(pdc_result),
OS_ID_HPUX, __pa(name));
convert_to_wide(pdc_result);
@@ -425,7 +437,7 @@ int pdc_model_sysmodel(char *name)
} else {
name[0] = 0;
}
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -443,12 +455,13 @@ int pdc_model_sysmodel(char *name)
int pdc_model_versions(unsigned long *versions, int id)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_VERSIONS, __pa(pdc_result), id);
convert_to_wide(pdc_result);
*versions = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -463,13 +476,14 @@ int pdc_model_versions(unsigned long *versions, int id)
int pdc_model_cpuid(unsigned long *cpu_id)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CPU_ID, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
*cpu_id = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -484,13 +498,14 @@ int pdc_model_cpuid(unsigned long *cpu_id)
int pdc_model_capabilities(unsigned long *capabilities)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
pdc_result[0] = 0; /* preset zero (call may not be implemented!) */
retval = mem_pdc_call(PDC_MODEL, PDC_MODEL_CAPABILITIES, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
*capabilities = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -504,12 +519,13 @@ int pdc_model_capabilities(unsigned long *capabilities)
int pdc_cache_info(struct pdc_cache_info *cache_info)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_INFO, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
memcpy(cache_info, pdc_result, sizeof(*cache_info));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -523,13 +539,14 @@ int pdc_cache_info(struct pdc_cache_info *cache_info)
int pdc_spaceid_bits(unsigned long *space_bits)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
pdc_result[0] = 0;
retval = mem_pdc_call(PDC_CACHE, PDC_CACHE_RET_SPID, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
*space_bits = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -544,11 +561,12 @@ int pdc_spaceid_bits(unsigned long *space_bits)
int pdc_btlb_info(struct pdc_btlb_info *btlb)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_BLOCK_TLB, PDC_BTLB_INFO, __pa(pdc_result), 0);
memcpy(btlb, pdc_result, sizeof(*btlb));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
if(retval < 0) {
btlb->max_size = 0;
@@ -572,13 +590,14 @@ int pdc_mem_map_hpa(struct pdc_memory_map *address,
struct pdc_module_path *mod_path)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
memcpy(pdc_result2, mod_path, sizeof(*mod_path));
retval = mem_pdc_call(PDC_MEM_MAP, PDC_MEM_MAP_HPA, __pa(pdc_result),
__pa(pdc_result2));
memcpy(address, pdc_result, sizeof(*address));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -594,8 +613,9 @@ int pdc_mem_map_hpa(struct pdc_memory_map *address,
int pdc_lan_station_id(char *lan_addr, unsigned long hpa)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_LAN_STATION_ID, PDC_LAN_STATION_ID_READ,
__pa(pdc_result), hpa);
if (retval < 0) {
@@ -604,7 +624,7 @@ int pdc_lan_station_id(char *lan_addr, unsigned long hpa)
} else {
memcpy(lan_addr, pdc_result, PDC_LAN_STATION_ID_SIZE);
}
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -623,13 +643,14 @@ EXPORT_SYMBOL(pdc_lan_station_id);
int pdc_stable_read(unsigned long staddr, void *memaddr, unsigned long count)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_READ, staddr,
__pa(pdc_result), count);
convert_to_wide(pdc_result);
memcpy(memaddr, pdc_result, count);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -648,13 +669,14 @@ EXPORT_SYMBOL(pdc_stable_read);
int pdc_stable_write(unsigned long staddr, void *memaddr, unsigned long count)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
memcpy(pdc_result, memaddr, count);
convert_to_wide(pdc_result);
retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_WRITE, staddr,
__pa(pdc_result), count);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -672,11 +694,12 @@ EXPORT_SYMBOL(pdc_stable_write);
int pdc_stable_get_size(unsigned long *size)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_RETURN_SIZE, __pa(pdc_result));
*size = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -691,10 +714,11 @@ EXPORT_SYMBOL(pdc_stable_get_size);
int pdc_stable_verify_contents(void)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_VERIFY_CONTENTS);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -709,10 +733,11 @@ EXPORT_SYMBOL(pdc_stable_verify_contents);
int pdc_stable_initialize(void)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_STABLE, PDC_STABLE_INITIALIZE);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -735,8 +760,9 @@ EXPORT_SYMBOL(pdc_stable_initialize);
int pdc_get_initiator(struct hardware_path *hwpath, struct pdc_initiator *initiator)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
/* BCJ-XXXX series boxes. E.G. "9000/785/C3000" */
#define IS_SPROCKETS() (strlen(boot_cpu_data.pdc.sys_model_name) == 14 && \
@@ -776,7 +802,8 @@ int pdc_get_initiator(struct hardware_path *hwpath, struct pdc_initiator *initia
}
out:
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
return (retval >= PDC_OK);
}
EXPORT_SYMBOL(pdc_get_initiator);
@@ -794,13 +821,14 @@ EXPORT_SYMBOL(pdc_get_initiator);
int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL_SIZE,
__pa(pdc_result), hpa);
convert_to_wide(pdc_result);
*num_entries = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -817,14 +845,15 @@ int pdc_pci_irt_size(unsigned long *num_entries, unsigned long hpa)
int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl)
{
int retval;
+ unsigned long flags;
BUG_ON((unsigned long)tbl & 0x7);
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
pdc_result[0] = num_entries;
retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_GET_INT_TBL,
__pa(pdc_result), hpa, __pa(tbl));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -842,12 +871,15 @@ int pdc_pci_irt(unsigned long num_entries, unsigned long hpa, void *tbl)
unsigned int pdc_pci_config_read(void *hpa, unsigned long cfg_addr)
{
int retval;
- spin_lock_irq(&pdc_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
pdc_result[0] = 0;
pdc_result[1] = 0;
retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_READ_CONFIG,
__pa(pdc_result), hpa, cfg_addr&~3UL, 4UL);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
return retval ? ~0 : (unsigned int) pdc_result[0];
}
@@ -863,12 +895,15 @@ unsigned int pdc_pci_config_read(void *hpa, unsigned long cfg_addr)
void pdc_pci_config_write(void *hpa, unsigned long cfg_addr, unsigned int val)
{
int retval;
- spin_lock_irq(&pdc_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
pdc_result[0] = 0;
retval = mem_pdc_call(PDC_PCI_INDEX, PDC_PCI_WRITE_CONFIG,
__pa(pdc_result), hpa,
cfg_addr&~3UL, 4UL, (unsigned long) val);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
return retval;
}
#endif /* UNTESTED CODE */
@@ -882,12 +917,13 @@ void pdc_pci_config_write(void *hpa, unsigned long cfg_addr, unsigned int val)
int pdc_tod_read(struct pdc_tod *tod)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_TOD, PDC_TOD_READ, __pa(pdc_result), 0);
convert_to_wide(pdc_result);
memcpy(tod, pdc_result, sizeof(*tod));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -903,10 +939,11 @@ EXPORT_SYMBOL(pdc_tod_read);
int pdc_tod_set(unsigned long sec, unsigned long usec)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_TOD, PDC_TOD_WRITE, sec, usec);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -917,13 +954,14 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
struct pdc_memory_table *tbl, unsigned long entries)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_MEM, PDC_MEM_TABLE, __pa(pdc_result), __pa(pdc_result2), entries);
convert_to_wide(pdc_result);
memcpy(r_addr, pdc_result, sizeof(*r_addr));
memcpy(tbl, pdc_result2, entries * sizeof(*tbl));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -936,11 +974,12 @@ int pdc_mem_mem_table(struct pdc_memory_table_raddr *r_addr,
int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_FIRM_TEST_RESET,
PDC_FIRM_TEST_MAGIC, ftc_bitmap);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -953,10 +992,11 @@ int pdc_do_firm_test_reset(unsigned long ftc_bitmap)
int pdc_do_reset(void)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_BROADCAST_RESET, PDC_DO_RESET);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -970,16 +1010,17 @@ int pdc_do_reset(void)
int __init pdc_soft_power_info(unsigned long *power_reg)
{
int retval;
+ unsigned long flags;
*power_reg = (unsigned long) (-1);
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_INFO, __pa(pdc_result), 0);
if (retval == PDC_OK) {
convert_to_wide(pdc_result);
*power_reg = f_extend(pdc_result[0]);
}
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -998,9 +1039,12 @@ int __init pdc_soft_power_info(unsigned long *power_reg)
int pdc_soft_power_button(int sw_control)
{
int retval;
- spin_lock_irq(&pdc_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_SOFT_POWER, PDC_SOFT_POWER_ENABLE, __pa(pdc_result), sw_control);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
+
return retval;
}
@@ -1011,9 +1055,11 @@ int pdc_soft_power_button(int sw_control)
*/
void pdc_io_reset(void)
{
- spin_lock_irq(&pdc_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
mem_pdc_call(PDC_IO, PDC_IO_RESET, 0);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
}
/*
@@ -1027,9 +1073,11 @@ void pdc_io_reset(void)
*/
void pdc_io_reset_devices(void)
{
- spin_lock_irq(&pdc_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
mem_pdc_call(PDC_IO, PDC_IO_RESET_DEVICES, 0);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
}
@@ -1049,7 +1097,7 @@ void pdc_iodc_putc(unsigned char c)
static int __attribute__((aligned(8))) iodc_retbuf[32];
static char __attribute__((aligned(64))) iodc_dbuf[4096];
unsigned int n;
- unsigned int flags;
+ unsigned long flags;
switch (c) {
case '\n':
@@ -1088,7 +1136,8 @@ void pdc_iodc_putc(unsigned char c)
*/
void pdc_iodc_outc(unsigned char c)
{
- unsigned int n, flags;
+ unsigned int n;
+ unsigned long flags;
/* fill buffer with one caracter and print it */
static int __attribute__((aligned(8))) iodc_retbuf[32];
@@ -1113,7 +1162,7 @@ void pdc_iodc_outc(unsigned char c)
*/
int pdc_iodc_getc(void)
{
- unsigned int flags;
+ unsigned long flags;
static int __attribute__((aligned(8))) iodc_retbuf[32];
static char __attribute__((aligned(64))) iodc_dbuf[4096];
int ch;
@@ -1145,10 +1194,11 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
unsigned long glob_cfg)
{
int retval;
+ unsigned long irqflags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, irqflags);
retval = real32_call(func, flags, inptr, outputr, glob_cfg);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, irqflags);
return retval;
}
@@ -1165,11 +1215,12 @@ EXPORT_SYMBOL(pdc_sti_call);
int pdc_pat_cell_get_number(struct pdc_pat_cell_num *cell_info)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_GET_NUMBER, __pa(pdc_result));
memcpy(cell_info, pdc_result, sizeof(*cell_info));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -1189,16 +1240,17 @@ int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long
unsigned long view_type, void *mem_addr)
{
int retval;
+ unsigned long flags;
static struct pdc_pat_cell_mod_maddr_block result __attribute__ ((aligned (8)));
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_CELL, PDC_PAT_CELL_MODULE, __pa(pdc_result),
ploc, mod, view_type, __pa(&result));
if(!retval) {
*actcnt = pdc_result[0];
memcpy(mem_addr, &result, *actcnt);
}
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -1213,12 +1265,13 @@ int pdc_pat_cell_module(unsigned long *actcnt, unsigned long ploc, unsigned long
int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_CPU, PDC_PAT_CPU_GET_NUMBER,
__pa(&pdc_result), hpa);
memcpy(cpu_info, pdc_result, sizeof(*cpu_info));
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -1234,12 +1287,13 @@ int pdc_pat_cpu_get_number(struct pdc_pat_cpu_num *cpu_info, void *hpa)
int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE_SIZE,
__pa(pdc_result), cell_num);
*num_entries = pdc_result[0];
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -1254,11 +1308,12 @@ int pdc_pat_get_irt_size(unsigned long *num_entries, unsigned long cell_num)
int pdc_pat_get_irt(void *r_addr, unsigned long cell_num)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_GET_PCI_ROUTING_TABLE,
__pa(r_addr), cell_num);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -1275,13 +1330,14 @@ int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr,
unsigned long count, unsigned long offset)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_PD, PDC_PAT_PD_GET_ADDR_MAP, __pa(pdc_result),
__pa(pdc_result2), count, offset);
*actual_len = pdc_result[0];
memcpy(mem_addr, pdc_result2, *actual_len);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -1296,7 +1352,9 @@ int pdc_pat_pd_get_addr_map(unsigned long *actual_len, void *mem_addr,
int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr)
{
int retval;
- spin_lock_irq(&pdc_lock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_READ,
__pa(pdc_result), pci_addr, pci_size);
switch(pci_size) {
@@ -1304,7 +1362,7 @@ int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr)
case 2: *(u16 *)mem_addr = (u16) pdc_result[0];
case 4: *(u32 *)mem_addr = (u32) pdc_result[0];
}
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
@@ -1320,11 +1378,12 @@ int pdc_pat_io_pci_cfg_read(unsigned long pci_addr, int pci_size, u32 *mem_addr)
int pdc_pat_io_pci_cfg_write(unsigned long pci_addr, int pci_size, u32 val)
{
int retval;
+ unsigned long flags;
- spin_lock_irq(&pdc_lock);
+ spin_lock_irqsave(&pdc_lock, flags);
retval = mem_pdc_call(PDC_PAT_IO, PDC_PAT_IO_PCI_CONFIG_WRITE,
pci_addr, pci_size, val);
- spin_unlock_irq(&pdc_lock);
+ spin_unlock_irqrestore(&pdc_lock, flags);
return retval;
}
diff --git a/arch/parisc/kernel/hardware.c b/arch/parisc/kernel/hardware.c
index 3058bffd8a2c..18ba4cb9159b 100644
--- a/arch/parisc/kernel/hardware.c
+++ b/arch/parisc/kernel/hardware.c
@@ -231,6 +231,7 @@ static struct hp_hardware hp_hardware_list[] __initdata = {
{HPHW_NPROC,0x5E6,0x4,0x91,"Keystone/Matterhorn W2 650"},
{HPHW_NPROC,0x5E7,0x4,0x91,"Caribe W2 800"},
{HPHW_NPROC,0x5E8,0x4,0x91,"Pikes Peak W2"},
+ {HPHW_NPROC,0x5EB,0x4,0x91,"Perf/Leone 875 W2+"},
{HPHW_NPROC,0x5FF,0x4,0x91,"Hitachi W"},
{HPHW_NPROC,0x600,0x4,0x81,"Gecko (712/60)"},
{HPHW_NPROC,0x601,0x4,0x81,"Gecko 80 (712/80)"},
@@ -584,8 +585,10 @@ static struct hp_hardware hp_hardware_list[] __initdata = {
{HPHW_CONSOLE, 0x01A, 0x0001F, 0x00, "Jason/Anole 64 Null Console"},
{HPHW_CONSOLE, 0x01B, 0x0001F, 0x00, "Jason/Anole 100 Null Console"},
{HPHW_FABRIC, 0x004, 0x000AA, 0x80, "Halfdome DNA Central Agent"},
+ {HPHW_FABRIC, 0x005, 0x000AA, 0x80, "Keystone DNA Central Agent"},
{HPHW_FABRIC, 0x007, 0x000AA, 0x80, "Caribe DNA Central Agent"},
{HPHW_FABRIC, 0x004, 0x000AB, 0x00, "Halfdome TOGO Fabric Crossbar"},
+ {HPHW_FABRIC, 0x005, 0x000AB, 0x00, "Keystone TOGO Fabric Crossbar"},
{HPHW_FABRIC, 0x004, 0x000AC, 0x00, "Halfdome Sakura Fabric Router"},
{HPHW_FIO, 0x025, 0x0002E, 0x80, "Armyknife Optional X.25"},
{HPHW_FIO, 0x004, 0x0004F, 0x0, "8-Port X.25 EISA-ACC (AMSO)"},
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 3e79e62f7b0b..eaad2328fea1 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -12,8 +12,6 @@
* Initial Version 04-23-1999 by Helge Deller <deller@gmx.de>
*/
-#include <linux/config.h> /* for CONFIG_SMP */
-
#include <asm/asm-offsets.h>
#include <asm/psw.h>
#include <asm/pdc.h>
diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
index 5b8803cc3d69..b39c5b9aff46 100644
--- a/arch/parisc/kernel/irq.c
+++ b/arch/parisc/kernel/irq.c
@@ -35,8 +35,8 @@
#undef PARISC_IRQ_CR16_COUNTS
-extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
-extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
+extern irqreturn_t timer_interrupt(int, void *);
+extern irqreturn_t ipi_interrupt(int, void *);
#define EIEM_MASK(irq) (1UL<<(CPU_IRQ_MAX - irq))
@@ -45,6 +45,17 @@ extern irqreturn_t ipi_interrupt(int, void *, struct pt_regs *);
*/
static volatile unsigned long cpu_eiem = 0;
+/*
+** ack bitmap ... habitually set to 1, but reset to zero
+** between ->ack() and ->end() of the interrupt to prevent
+** re-interruption of a processing interrupt.
+*/
+static volatile unsigned long global_ack_eiem = ~0UL;
+/*
+** Local bitmap, same as above but for per-cpu interrupts
+*/
+static DEFINE_PER_CPU(unsigned long, local_ack_eiem) = ~0UL;
+
static void cpu_disable_irq(unsigned int irq)
{
unsigned long eirr_bit = EIEM_MASK(irq);
@@ -62,13 +73,6 @@ static void cpu_enable_irq(unsigned int irq)
cpu_eiem |= eirr_bit;
- /* FIXME: while our interrupts aren't nested, we cannot reset
- * the eiem mask if we're already in an interrupt. Once we
- * implement nested interrupts, this can go away
- */
- if (!in_interrupt())
- set_eiem(cpu_eiem);
-
/* This is just a simple NOP IPI. But what it does is cause
* all the other CPUs to do a set_eiem(cpu_eiem) at the end
* of the interrupt handler */
@@ -84,13 +88,45 @@ static unsigned int cpu_startup_irq(unsigned int irq)
void no_ack_irq(unsigned int irq) { }
void no_end_irq(unsigned int irq) { }
+void cpu_ack_irq(unsigned int irq)
+{
+ unsigned long mask = EIEM_MASK(irq);
+ int cpu = smp_processor_id();
+
+ /* Clear in EIEM so we can no longer process */
+ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
+ per_cpu(local_ack_eiem, cpu) &= ~mask;
+ else
+ global_ack_eiem &= ~mask;
+
+ /* disable the interrupt */
+ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
+ /* and now ack it */
+ mtctl(mask, 23);
+}
+
+void cpu_end_irq(unsigned int irq)
+{
+ unsigned long mask = EIEM_MASK(irq);
+ int cpu = smp_processor_id();
+
+ /* set it in the eiems---it's no longer in process */
+ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status))
+ per_cpu(local_ack_eiem, cpu) |= mask;
+ else
+ global_ack_eiem |= mask;
+
+ /* enable the interrupt */
+ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
+}
+
#ifdef CONFIG_SMP
int cpu_check_affinity(unsigned int irq, cpumask_t *dest)
{
int cpu_dest;
/* timer and ipi have to always be received on all CPUs */
- if (irq == TIMER_IRQ || irq == IPI_IRQ) {
+ if (CHECK_IRQ_PER_CPU(irq)) {
/* Bad linux design decision. The mask has already
* been set; we must reset it */
irq_desc[irq].affinity = CPU_MASK_ALL;
@@ -119,8 +155,8 @@ static struct hw_interrupt_type cpu_interrupt_type = {
.shutdown = cpu_disable_irq,
.enable = cpu_enable_irq,
.disable = cpu_disable_irq,
- .ack = no_ack_irq,
- .end = no_end_irq,
+ .ack = cpu_ack_irq,
+ .end = cpu_end_irq,
#ifdef CONFIG_SMP
.set_affinity = cpu_set_affinity_irq,
#endif
@@ -209,7 +245,7 @@ int show_interrupts(struct seq_file *p, void *v)
** Then use that to get the Transaction address and data.
*/
-int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *type, void *data)
+int cpu_claim_irq(unsigned int irq, struct irq_chip *type, void *data)
{
if (irq_desc[irq].action)
return -EBUSY;
@@ -298,82 +334,72 @@ unsigned int txn_alloc_data(unsigned int virt_irq)
return virt_irq - CPU_IRQ_BASE;
}
+static inline int eirr_to_irq(unsigned long eirr)
+{
+#ifdef CONFIG_64BIT
+ int bit = fls64(eirr);
+#else
+ int bit = fls(eirr);
+#endif
+ return (BITS_PER_LONG - bit) + TIMER_IRQ;
+}
+
/* ONLY called from entry.S:intr_extint() */
void do_cpu_irq_mask(struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
unsigned long eirr_val;
-
- irq_enter();
-
- /*
- * Don't allow TIMER or IPI nested interrupts.
- * Allowing any single interrupt to nest can lead to that CPU
- * handling interrupts with all enabled interrupts unmasked.
- */
- set_eiem(0UL);
-
- /* 1) only process IRQs that are enabled/unmasked (cpu_eiem)
- * 2) We loop here on EIRR contents in order to avoid
- * nested interrupts or having to take another interrupt
- * when we could have just handled it right away.
- */
- for (;;) {
- unsigned long bit = (1UL << (BITS_PER_LONG - 1));
- unsigned int irq;
- eirr_val = mfctl(23) & cpu_eiem;
- if (!eirr_val)
- break;
-
- mtctl(eirr_val, 23); /* reset bits we are going to process */
-
- /* Work our way from MSb to LSb...same order we alloc EIRs */
- for (irq = TIMER_IRQ; eirr_val && bit; bit>>=1, irq++) {
+ int irq, cpu = smp_processor_id();
#ifdef CONFIG_SMP
- cpumask_t dest = irq_desc[irq].affinity;
+ cpumask_t dest;
#endif
- if (!(bit & eirr_val))
- continue;
- /* clear bit in mask - can exit loop sooner */
- eirr_val &= ~bit;
+ old_regs = set_irq_regs(regs);
+ local_irq_disable();
+ irq_enter();
-#ifdef CONFIG_SMP
- /* FIXME: because generic set affinity mucks
- * with the affinity before sending it to us
- * we can get the situation where the affinity is
- * wrong for our CPU type interrupts */
- if (irq != TIMER_IRQ && irq != IPI_IRQ &&
- !cpu_isset(smp_processor_id(), dest)) {
- int cpu = first_cpu(dest);
-
- printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
- irq, smp_processor_id(), cpu);
- gsc_writel(irq + CPU_IRQ_BASE,
- cpu_data[cpu].hpa);
- continue;
- }
-#endif
+ eirr_val = mfctl(23) & cpu_eiem & global_ack_eiem &
+ per_cpu(local_ack_eiem, cpu);
+ if (!eirr_val)
+ goto set_out;
+ irq = eirr_to_irq(eirr_val);
- __do_IRQ(irq, regs);
- }
+#ifdef CONFIG_SMP
+ dest = irq_desc[irq].affinity;
+ if (CHECK_IRQ_PER_CPU(irq_desc[irq].status) &&
+ !cpu_isset(smp_processor_id(), dest)) {
+ int cpu = first_cpu(dest);
+
+ printk(KERN_DEBUG "redirecting irq %d from CPU %d to %d\n",
+ irq, smp_processor_id(), cpu);
+ gsc_writel(irq + CPU_IRQ_BASE,
+ cpu_data[cpu].hpa);
+ goto set_out;
}
+#endif
+ __do_IRQ(irq);
- set_eiem(cpu_eiem); /* restore original mask */
+ out:
irq_exit();
-}
+ set_irq_regs(old_regs);
+ return;
+ set_out:
+ set_eiem(cpu_eiem & global_ack_eiem & per_cpu(local_ack_eiem, cpu));
+ goto out;
+}
static struct irqaction timer_action = {
.handler = timer_interrupt,
.name = "timer",
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_TIMER | IRQF_PERCPU,
};
#ifdef CONFIG_SMP
static struct irqaction ipi_action = {
.handler = ipi_interrupt,
.name = "IPI",
- .flags = IRQF_DISABLED,
+ .flags = IRQF_DISABLED | IRQF_PERCPU,
};
#endif
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
index aee311884f3f..f50b982b0834 100644
--- a/arch/parisc/kernel/module.c
+++ b/arch/parisc/kernel/module.c
@@ -27,7 +27,7 @@
* - SEGREL32 handling
* We are not doing SEGREL32 handling correctly. According to the ABI, we
* should do a value offset, like this:
- * if (is_init(me, (void *)val))
+ * if (in_init(me, (void *)val))
* val -= (uint32_t)me->module_init;
* else
* val -= (uint32_t)me->module_core;
@@ -72,27 +72,27 @@
/* three functions to determine where in the module core
* or init pieces the location is */
-static inline int is_init(struct module *me, void *loc)
+static inline int in_init(struct module *me, void *loc)
{
return (loc >= me->module_init &&
loc <= (me->module_init + me->init_size));
}
-static inline int is_core(struct module *me, void *loc)
+static inline int in_core(struct module *me, void *loc)
{
return (loc >= me->module_core &&
loc <= (me->module_core + me->core_size));
}
-static inline int is_local(struct module *me, void *loc)
+static inline int in_local(struct module *me, void *loc)
{
- return is_init(me, loc) || is_core(me, loc);
+ return in_init(me, loc) || in_core(me, loc);
}
-static inline int is_local_section(struct module *me, void *loc, void *dot)
+static inline int in_local_section(struct module *me, void *loc, void *dot)
{
- return (is_init(me, loc) && is_init(me, dot)) ||
- (is_core(me, loc) && is_core(me, dot));
+ return (in_init(me, loc) && in_init(me, dot)) ||
+ (in_core(me, loc) && in_core(me, dot));
}
@@ -566,14 +566,14 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
break;
case R_PARISC_PCREL17F:
/* 17-bit PC relative address */
- val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
+ val = get_stub(me, val, addend, ELF_STUB_GOT, in_init(me, loc));
val = (val - dot - 8)/4;
CHECK_RELOC(val, 17)
*loc = (*loc & ~0x1f1ffd) | reassemble_17(val);
break;
case R_PARISC_PCREL22F:
/* 22-bit PC relative address; only defined for pa20 */
- val = get_stub(me, val, addend, ELF_STUB_GOT, is_init(me, loc));
+ val = get_stub(me, val, addend, ELF_STUB_GOT, in_init(me, loc));
DEBUGP("STUB FOR %s loc %lx+%lx at %lx\n",
strtab + sym->st_name, (unsigned long)loc, addend,
val)
@@ -670,9 +670,9 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
strtab + sym->st_name,
loc, val);
/* can we reach it locally? */
- if(!is_local_section(me, (void *)val, (void *)dot)) {
+ if(!in_local_section(me, (void *)val, (void *)dot)) {
- if (is_local(me, (void *)val))
+ if (in_local(me, (void *)val))
/* this is the case where the
* symbol is local to the
* module, but in a different
@@ -680,14 +680,14 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
* in case it's more than 22
* bits away */
val = get_stub(me, val, addend, ELF_STUB_DIRECT,
- is_init(me, loc));
+ in_init(me, loc));
else if (strncmp(strtab + sym->st_name, "$$", 2)
== 0)
val = get_stub(me, val, addend, ELF_STUB_MILLI,
- is_init(me, loc));
+ in_init(me, loc));
else
val = get_stub(me, val, addend, ELF_STUB_GOT,
- is_init(me, loc));
+ in_init(me, loc));
}
DEBUGP("STUB FOR %s loc %lx, val %lx+%lx at %lx\n",
strtab + sym->st_name, loc, sym->st_value,
@@ -720,7 +720,7 @@ int apply_relocate_add(Elf_Shdr *sechdrs,
break;
case R_PARISC_FPTR64:
/* 64-bit function address */
- if(is_local(me, (void *)(val + addend))) {
+ if(in_local(me, (void *)(val + addend))) {
*loc64 = get_fdesc(me, val+addend);
DEBUGP("FDESC for %s at %p points to %lx\n",
strtab + sym->st_name, *loc64,
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index 6d57553d8ef8..8f6a0b312f7a 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -69,10 +69,6 @@ EXPORT_SYMBOL(memcpy_toio);
EXPORT_SYMBOL(memcpy_fromio);
EXPORT_SYMBOL(memset_io);
-#include <asm/unistd.h>
-EXPORT_SYMBOL(sys_lseek);
-EXPORT_SYMBOL(sys_write);
-
#include <asm/semaphore.h>
EXPORT_SYMBOL(__up);
EXPORT_SYMBOL(__down_interruptible);
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index d3b8fc52dfc1..199887a61c76 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -290,7 +290,7 @@ EXPORT_SYMBOL(pcibios_bus_to_resource);
void pcibios_align_resource(void *data, struct resource *res,
resource_size_t size, resource_size_t alignment)
{
- unsigned long mask, align;
+ resource_size_t mask, align;
DBG_RES("pcibios_align_resource(%s, (%p) [%lx,%lx]/%x, 0x%lx, 0x%lx)\n",
pci_name(((struct pci_dev *) data)),
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 0b485ef4be89..2f9f9dfa66f7 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -368,7 +368,14 @@ out:
return error;
}
-unsigned long
+extern int __execve(const char *filename, char *const argv[],
+ char *const envp[], struct task_struct *task);
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ return __execve(filename, argv, envp, current);
+}
+
+unsigned long
get_wchan(struct task_struct *p)
{
struct unwind_frame_info info;
diff --git a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
index 99d7fca93104..fb81e5687e7c 100644
--- a/arch/parisc/kernel/processor.c
+++ b/arch/parisc/kernel/processor.c
@@ -143,8 +143,9 @@ static int __init processor_probe(struct parisc_device *dev)
p = &cpu_data[cpuid];
boot_cpu_data.cpu_count++;
- /* initialize counters */
- memset(p, 0, sizeof(struct cpuinfo_parisc));
+ /* initialize counters - CPU 0 gets it_value set in time_init() */
+ if (cpuid)
+ memset(p, 0, sizeof(struct cpuinfo_parisc));
p->loops_per_jiffy = loops_per_jiffy;
p->dev = dev; /* Save IODC data in case we need it */
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index bb83880c5ee3..ee6653edeb7a 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -26,7 +26,6 @@
#include <linux/stddef.h>
#include <linux/compat.h>
#include <linux/elf.h>
-#include <linux/personality.h>
#include <asm/ucontext.h>
#include <asm/rt_sigframe.h>
#include <asm/uaccess.h>
@@ -433,13 +432,13 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if (in_syscall) {
regs->gr[31] = haddr;
#ifdef __LP64__
- if (personality(current->personality) == PER_LINUX)
+ if (!test_thread_flag(TIF_32BIT))
sigframe_size |= 1;
#endif
} else {
unsigned long psw = USER_PSW;
#ifdef __LP64__
- if (personality(current->personality) == PER_LINUX)
+ if (!test_thread_flag(TIF_32BIT))
psw |= PSW_W;
#endif
diff --git a/arch/parisc/kernel/smp.c b/arch/parisc/kernel/smp.c
index 98e40959a564..4a23a97b06cd 100644
--- a/arch/parisc/kernel/smp.c
+++ b/arch/parisc/kernel/smp.c
@@ -154,7 +154,7 @@ halt_processor(void)
irqreturn_t
-ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ipi_interrupt(int irq, void *dev_id)
{
int this_cpu = smp_processor_id();
struct cpuinfo_parisc *p = &cpu_data[this_cpu];
@@ -262,6 +262,9 @@ ipi_interrupt(int irq, void *dev_id, struct pt_regs *regs)
this_cpu, which);
return IRQ_NONE;
} /* Switch */
+ /* let in any pending interrupts */
+ local_irq_enable();
+ local_irq_disable();
} /* while (ops) */
}
return IRQ_HANDLED;
@@ -411,27 +414,15 @@ smp_flush_tlb_all(void)
on_each_cpu(flush_tlb_all_local, NULL, 1, 1);
}
-
-void
-smp_do_timer(struct pt_regs *regs)
-{
- int cpu = smp_processor_id();
- struct cpuinfo_parisc *data = &cpu_data[cpu];
-
- if (!--data->prof_counter) {
- data->prof_counter = data->prof_multiplier;
- update_process_times(user_mode(regs));
- }
-}
-
/*
* Called by secondaries to update state and initialize CPU registers.
*/
static void __init
smp_cpu_init(int cpunum)
{
- extern int init_per_cpu(int); /* arch/parisc/kernel/setup.c */
+ extern int init_per_cpu(int); /* arch/parisc/kernel/processor.c */
extern void init_IRQ(void); /* arch/parisc/kernel/irq.c */
+ extern void start_cpu_itimer(void); /* arch/parisc/kernel/time.c */
/* Set modes and Enable floating point coprocessor */
(void) init_per_cpu(cpunum);
@@ -457,6 +448,7 @@ smp_cpu_init(int cpunum)
enter_lazy_tlb(&init_mm, current);
init_IRQ(); /* make sure no IRQ's are enabled or pending */
+ start_cpu_itimer();
}
diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
index 8b5df98e2b31..512642d8f707 100644
--- a/arch/parisc/kernel/sys_parisc.c
+++ b/arch/parisc/kernel/sys_parisc.c
@@ -31,6 +31,8 @@
#include <linux/shm.h>
#include <linux/smp_lock.h>
#include <linux/syscalls.h>
+#include <linux/utsname.h>
+#include <linux/personality.h>
int sys_pipe(int __user *fildes)
{
@@ -248,3 +250,33 @@ asmlinkage int sys_free_hugepages(unsigned long addr)
{
return -EINVAL;
}
+
+long parisc_personality(unsigned long personality)
+{
+ long err;
+
+ if (personality(current->personality) == PER_LINUX32
+ && personality == PER_LINUX)
+ personality = PER_LINUX32;
+
+ err = sys_personality(personality);
+ if (err == PER_LINUX32)
+ err = PER_LINUX;
+
+ return err;
+}
+
+long parisc_newuname(struct new_utsname __user *name)
+{
+ int err = sys_newuname(name);
+
+#ifdef CONFIG_COMPAT
+ if (!err && personality(current->personality) == PER_LINUX32) {
+ if (__put_user(0, name->machine + 6) ||
+ __put_user(0, name->machine + 7))
+ err = -EFAULT;
+ }
+#endif
+
+ return err;
+}
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index b74869803081..29be4377aca6 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -111,13 +111,14 @@ struct __sysctl_args32 {
asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
{
+#ifndef CONFIG_SYSCTL_SYSCALL
+ return -ENOSYS;
+#else
struct __sysctl_args32 tmp;
int error;
unsigned int oldlen32;
- size_t oldlen, *oldlenp = NULL;
+ size_t oldlen, __user *oldlenp = NULL;
unsigned long addr = (((long __force)&args->__unused[0]) + 7) & ~7;
- extern int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
- void *newval, size_t newlen);
DBG(("sysctl32(%p)\n", args));
@@ -144,8 +145,9 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
}
lock_kernel();
- error = do_sysctl((int *)(u64)tmp.name, tmp.nlen, (void *)(u64)tmp.oldval,
- oldlenp, (void *)(u64)tmp.newval, tmp.newlen);
+ error = do_sysctl((int __user *)(u64)tmp.name, tmp.nlen,
+ (void __user *)(u64)tmp.oldval, oldlenp,
+ (void __user *)(u64)tmp.newval, tmp.newlen);
unlock_kernel();
if (oldlenp) {
if (!error) {
@@ -157,10 +159,11 @@ asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
error = -EFAULT;
}
}
- if (copy_to_user(&args->__unused[0], tmp.__unused, sizeof(tmp.__unused)))
+ if (copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)))
error = -EFAULT;
}
return error;
+#endif
}
#endif /* CONFIG_SYSCTL */
@@ -237,14 +240,19 @@ int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user
int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
+ compat_ino_t ino;
int err;
if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
!new_valid_dev(stat->rdev))
return -EOVERFLOW;
+ ino = stat->ino;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
- err |= put_user(stat->ino, &statbuf->st_ino);
+ err |= put_user(ino, &statbuf->st_ino);
err |= put_user(stat->mode, &statbuf->st_mode);
err |= put_user(stat->nlink, &statbuf->st_nlink);
err |= put_user(0, &statbuf->st_reserved1);
@@ -305,23 +313,26 @@ struct readdir32_callback {
#define ROUND_UP(x,a) ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-static int
-filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
- unsigned int d_type)
+static int filldir32 (void *__buf, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct linux32_dirent __user * dirent;
struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
+ u32 d_ino;
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
if (dirent)
put_user(offset, &dirent->d_off);
dirent = buf->current_dir;
buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(reclen, &dirent->d_reclen);
copy_to_user(dirent->d_name, name, namlen);
put_user(0, dirent->d_name + namlen);
@@ -365,18 +376,21 @@ out:
return error;
}
-static int
-fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino,
- unsigned int d_type)
+static int fillonedir32(void * __buf, const char * name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
struct old_linux32_dirent __user * dirent;
+ u32 d_ino;
if (buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
buf->count++;
dirent = buf->dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(offset, &dirent->d_offset);
put_user(namlen, &dirent->d_namlen);
copy_to_user(dirent->d_name, name, namlen);
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index 9670a89c77fe..a05800429304 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -6,7 +6,6 @@
* thanks to Philipp Rumpf, Mike Shaver and various others
* sorry about the wall, puffin..
*/
-#include <linux/config.h> /* for CONFIG_SMP */
#include <asm/asm-offsets.h>
#include <asm/unistd.h>
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index e27b432f90a8..701d66a596e8 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -132,7 +132,7 @@
ENTRY_SAME(socketpair)
ENTRY_SAME(setpgid)
ENTRY_SAME(send)
- ENTRY_SAME(newuname)
+ ENTRY_OURS(newuname)
ENTRY_SAME(umask) /* 60 */
ENTRY_SAME(chroot)
ENTRY_SAME(ustat)
@@ -221,7 +221,7 @@
ENTRY_SAME(fchdir)
ENTRY_SAME(bdflush)
ENTRY_SAME(sysfs) /* 135 */
- ENTRY_SAME(personality)
+ ENTRY_OURS(personality)
ENTRY_SAME(ni_syscall) /* for afs_syscall */
ENTRY_SAME(setfsuid)
ENTRY_SAME(setfsgid)
diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c
index 5facc9bff4ef..bad7d1eb62b9 100644
--- a/arch/parisc/kernel/time.c
+++ b/arch/parisc/kernel/time.c
@@ -32,58 +32,121 @@
#include <linux/timex.h>
-/* xtime and wall_jiffies keep wall-clock time */
-extern unsigned long wall_jiffies;
+static unsigned long clocktick __read_mostly; /* timer cycles per tick */
-static long clocktick __read_mostly; /* timer cycles per tick */
-static long halftick __read_mostly;
+/*
+ * We keep time on PA-RISC Linux by using the Interval Timer which is
+ * a pair of registers; one is read-only and one is write-only; both
+ * accessed through CR16. The read-only register is 32 or 64 bits wide,
+ * and increments by 1 every CPU clock tick. The architecture only
+ * guarantees us a rate between 0.5 and 2, but all implementations use a
+ * rate of 1. The write-only register is 32-bits wide. When the lowest
+ * 32 bits of the read-only register compare equal to the write-only
+ * register, it raises a maskable external interrupt. Each processor has
+ * an Interval Timer of its own and they are not synchronised.
+ *
+ * We want to generate an interrupt every 1/HZ seconds. So we program
+ * CR16 to interrupt every @clocktick cycles. The it_value in cpu_data
+ * is programmed with the intended time of the next tick. We can be
+ * held off for an arbitrarily long period of time by interrupts being
+ * disabled, so we may miss one or more ticks.
+ */
+irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ unsigned long now;
+ unsigned long next_tick;
+ unsigned long cycles_elapsed, ticks_elapsed;
+ unsigned long cycles_remainder;
+ unsigned int cpu = smp_processor_id();
+ struct cpuinfo_parisc *cpuinfo = &cpu_data[cpu];
-#ifdef CONFIG_SMP
-extern void smp_do_timer(struct pt_regs *regs);
-#endif
+ /* gcc can optimize for "read-only" case with a local clocktick */
+ unsigned long cpt = clocktick;
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- long now;
- long next_tick;
- int nticks;
- int cpu = smp_processor_id();
+ profile_tick(CPU_PROFILING);
- profile_tick(CPU_PROFILING, regs);
+ /* Initialize next_tick to the expected tick time. */
+ next_tick = cpuinfo->it_value;
+ /* Get current interval timer.
+ * CR16 reads as 64 bits in CPU wide mode.
+ * CR16 reads as 32 bits in CPU narrow mode.
+ */
now = mfctl(16);
- /* initialize next_tick to time at last clocktick */
- next_tick = cpu_data[cpu].it_value;
- /* since time passes between the interrupt and the mfctl()
- * above, it is never true that last_tick + clocktick == now. If we
- * never miss a clocktick, we could set next_tick = last_tick + clocktick
- * but maybe we'll miss ticks, hence the loop.
+ cycles_elapsed = now - next_tick;
+
+ if ((cycles_elapsed >> 5) < cpt) {
+ /* use "cheap" math (add/subtract) instead
+ * of the more expensive div/mul method
+ */
+ cycles_remainder = cycles_elapsed;
+ ticks_elapsed = 1;
+ while (cycles_remainder > cpt) {
+ cycles_remainder -= cpt;
+ ticks_elapsed++;
+ }
+ } else {
+ cycles_remainder = cycles_elapsed % cpt;
+ ticks_elapsed = 1 + cycles_elapsed / cpt;
+ }
+
+ /* Can we differentiate between "early CR16" (aka Scenario 1) and
+ * "long delay" (aka Scenario 3)? I don't think so.
*
- * Variables are *signed*.
+ * We expected timer_interrupt to be delivered at least a few hundred
+ * cycles after the IT fires. But it's arbitrary how much time passes
+ * before we call it "late". I've picked one second.
*/
-
- nticks = 0;
- while((next_tick - now) < halftick) {
- next_tick += clocktick;
- nticks++;
+ if (ticks_elapsed > HZ) {
+ /* Scenario 3: very long delay? bad in any case */
+ printk (KERN_CRIT "timer_interrupt(CPU %d): delayed!"
+ " cycles %lX rem %lX "
+ " next/now %lX/%lX\n",
+ cpu,
+ cycles_elapsed, cycles_remainder,
+ next_tick, now );
}
+
+ /* convert from "division remainder" to "remainder of clock tick" */
+ cycles_remainder = cpt - cycles_remainder;
+
+ /* Determine when (in CR16 cycles) next IT interrupt will fire.
+ * We want IT to fire modulo clocktick even if we miss/skip some.
+ * But those interrupts don't in fact get delivered that regularly.
+ */
+ next_tick = now + cycles_remainder;
+
+ cpuinfo->it_value = next_tick;
+
+ /* Skip one clocktick on purpose if we are likely to miss next_tick.
+ * We want to avoid the new next_tick being less than CR16.
+ * If that happened, itimer wouldn't fire until CR16 wrapped.
+ * We'll catch the tick we missed on the tick after that.
+ */
+ if (!(cycles_remainder >> 13))
+ next_tick += cpt;
+
+ /* Program the IT when to deliver the next interrupt. */
+ /* Only bottom 32-bits of next_tick are written to cr16. */
mtctl(next_tick, 16);
- cpu_data[cpu].it_value = next_tick;
- while (nticks--) {
-#ifdef CONFIG_SMP
- smp_do_timer(regs);
-#else
- update_process_times(user_mode(regs));
-#endif
- if (cpu == 0) {
- write_seqlock(&xtime_lock);
- do_timer(regs);
- write_sequnlock(&xtime_lock);
- }
+
+ /* Done mucking with unreliable delivery of interrupts.
+ * Go do system house keeping.
+ */
+
+ if (!--cpuinfo->prof_counter) {
+ cpuinfo->prof_counter = cpuinfo->prof_multiplier;
+ update_process_times(user_mode(get_irq_regs()));
}
-
+
+ if (cpu == 0) {
+ write_seqlock(&xtime_lock);
+ do_timer(ticks_elapsed);
+ write_sequnlock(&xtime_lock);
+ }
+
/* check soft power switch status */
if (cpu == 0 && !atomic_read(&power_tasklet.count))
tasklet_schedule(&power_tasklet);
@@ -109,14 +172,12 @@ unsigned long profile_pc(struct pt_regs *regs)
EXPORT_SYMBOL(profile_pc);
-/*** converted from ia64 ***/
/*
* Return the number of micro-seconds that elapsed since the last
- * update to wall time (aka xtime aka wall_jiffies). The xtime_lock
+ * update to wall time (aka xtime). The xtime_lock
* must be at least read-locked when calling this routine.
*/
-static inline unsigned long
-gettimeoffset (void)
+static inline unsigned long gettimeoffset (void)
{
#ifndef CONFIG_SMP
/*
@@ -124,21 +185,44 @@ gettimeoffset (void)
* Once parisc-linux learns the cr16 difference between processors,
* this could be made to work.
*/
- long last_tick;
- long elapsed_cycles;
-
- /* it_value is the intended time of the next tick */
- last_tick = cpu_data[smp_processor_id()].it_value;
-
- /* Subtract one tick and account for possible difference between
- * when we expected the tick and when it actually arrived.
- * (aka wall vs real)
- */
- last_tick -= clocktick * (jiffies - wall_jiffies + 1);
- elapsed_cycles = mfctl(16) - last_tick;
+ unsigned long now;
+ unsigned long prev_tick;
+ unsigned long next_tick;
+ unsigned long elapsed_cycles;
+ unsigned long usec;
+ unsigned long cpuid = smp_processor_id();
+ unsigned long cpt = clocktick;
+
+ next_tick = cpu_data[cpuid].it_value;
+ now = mfctl(16); /* Read the hardware interval timer. */
+
+ prev_tick = next_tick - cpt;
+
+ /* Assume Scenario 1: "now" is later than prev_tick. */
+ elapsed_cycles = now - prev_tick;
+
+/* aproximate HZ with shifts. Intended math is "(elapsed/clocktick) > HZ" */
+#if HZ == 1000
+ if (elapsed_cycles > (cpt << 10) )
+#elif HZ == 250
+ if (elapsed_cycles > (cpt << 8) )
+#elif HZ == 100
+ if (elapsed_cycles > (cpt << 7) )
+#else
+#warn WTF is HZ set to anyway?
+ if (elapsed_cycles > (HZ * cpt) )
+#endif
+ {
+ /* Scenario 3: clock ticks are missing. */
+ printk (KERN_CRIT "gettimeoffset(CPU %ld): missing %ld ticks!"
+ " cycles %lX prev/now/next %lX/%lX/%lX clock %lX\n",
+ cpuid, elapsed_cycles / cpt,
+ elapsed_cycles, prev_tick, now, next_tick, cpt);
+ }
- /* the precision of this math could be improved */
- return elapsed_cycles / (PAGE0->mem_10msec / 10000);
+ /* FIXME: Can we improve the precision? Not with PAGE0. */
+ usec = (elapsed_cycles * 10000) / PAGE0->mem_10msec;
+ return usec;
#else
return 0;
#endif
@@ -149,6 +233,7 @@ do_gettimeofday (struct timeval *tv)
{
unsigned long flags, seq, usec, sec;
+ /* Hold xtime_lock and adjust timeval. */
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = gettimeoffset();
@@ -156,25 +241,13 @@ do_gettimeofday (struct timeval *tv)
usec += (xtime.tv_nsec / 1000);
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- if (unlikely(usec > LONG_MAX)) {
- /* This can happen if the gettimeoffset adjustment is
- * negative and xtime.tv_nsec is smaller than the
- * adjustment */
- printk(KERN_ERR "do_gettimeofday() spurious xtime.tv_nsec of %ld\n", usec);
- usec += USEC_PER_SEC;
- --sec;
- /* This should never happen, it means the negative
- * time adjustment was more than a second, so there's
- * something seriously wrong */
- BUG_ON(usec > LONG_MAX);
- }
-
-
+ /* Move adjusted usec's into sec's. */
while (usec >= USEC_PER_SEC) {
usec -= USEC_PER_SEC;
++sec;
}
+ /* Return adjusted result. */
tv->tv_sec = sec;
tv->tv_usec = usec;
}
@@ -226,30 +299,33 @@ unsigned long long sched_clock(void)
}
+void __init start_cpu_itimer(void)
+{
+ unsigned int cpu = smp_processor_id();
+ unsigned long next_tick = mfctl(16) + clocktick;
+
+ mtctl(next_tick, 16); /* kick off Interval Timer (CR16) */
+
+ cpu_data[cpu].it_value = next_tick;
+}
+
void __init time_init(void)
{
- unsigned long next_tick;
static struct pdc_tod tod_data;
clocktick = (100 * PAGE0->mem_10msec) / HZ;
- halftick = clocktick / 2;
-
- /* Setup clock interrupt timing */
- next_tick = mfctl(16);
- next_tick += clocktick;
- cpu_data[smp_processor_id()].it_value = next_tick;
+ start_cpu_itimer(); /* get CPU 0 started */
- /* kick off Itimer (CR16) */
- mtctl(next_tick, 16);
+ if (pdc_tod_read(&tod_data) == 0) {
+ unsigned long flags;
- if(pdc_tod_read(&tod_data) == 0) {
- write_seqlock_irq(&xtime_lock);
+ write_seqlock_irqsave(&xtime_lock, flags);
xtime.tv_sec = tod_data.tod_sec;
xtime.tv_nsec = tod_data.tod_usec * 1000;
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
- write_sequnlock_irq(&xtime_lock);
+ write_sequnlock_irqrestore(&xtime_lock, flags);
} else {
printk(KERN_ERR "Error reading tod clock\n");
xtime.tv_sec = 0;
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 77b28cb8aca6..65cd6ca32fed 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -16,6 +16,7 @@
#include <linux/errno.h>
#include <linux/ptrace.h>
#include <linux/timer.h>
+#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/smp.h>
@@ -245,6 +246,15 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err)
current->comm, current->pid, str, err);
show_regs(regs);
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops) {
+ printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+ ssleep(5);
+ panic("Fatal exception");
+ }
+
/* Wot's wrong wif bein' racy? */
if (current->thread.flags & PARISC_KERNEL_DEATH) {
printk(KERN_CRIT "%s() recursion detected.\n", __FUNCTION__);
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 25ad28d63e88..0667f2b4f977 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -31,10 +31,7 @@
DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
-extern char _text; /* start of kernel code, defined by linker */
extern int data_start;
-extern char _end; /* end of BSS, defined by linker */
-extern char __init_begin, __init_end;
#ifdef CONFIG_DISCONTIGMEM
struct node_map_data node_data[MAX_NUMNODES] __read_mostly;
@@ -319,8 +316,8 @@ static void __init setup_bootmem(void)
reserve_bootmem_node(NODE_DATA(0), 0UL,
(unsigned long)(PAGE0->mem_free + PDC_CONSOLE_IO_IODC_SIZE));
- reserve_bootmem_node(NODE_DATA(0),__pa((unsigned long)&_text),
- (unsigned long)(&_end - &_text));
+ reserve_bootmem_node(NODE_DATA(0), __pa((unsigned long)_text),
+ (unsigned long)(_end - _text));
reserve_bootmem_node(NODE_DATA(0), (bootmap_start_pfn << PAGE_SHIFT),
((bootmap_pfn - bootmap_start_pfn) << PAGE_SHIFT));
@@ -355,8 +352,8 @@ static void __init setup_bootmem(void)
#endif
data_resource.start = virt_to_phys(&data_start);
- data_resource.end = virt_to_phys(&_end)-1;
- code_resource.start = virt_to_phys(&_text);
+ data_resource.end = virt_to_phys(_end) - 1;
+ code_resource.start = virt_to_phys(_text);
code_resource.end = virt_to_phys(&data_start)-1;
/* We don't know which region the kernel will be in, so try
@@ -385,12 +382,12 @@ void free_initmem(void)
*/
local_irq_disable();
- memset(&__init_begin, 0x00,
- (unsigned long)&__init_end - (unsigned long)&__init_begin);
+ memset(__init_begin, 0x00,
+ (unsigned long)__init_end - (unsigned long)__init_begin);
flush_data_cache();
asm volatile("sync" : : );
- flush_icache_range((unsigned long)&__init_begin, (unsigned long)&__init_end);
+ flush_icache_range((unsigned long)__init_begin, (unsigned long)__init_end);
asm volatile("sync" : : );
local_irq_enable();
@@ -398,8 +395,8 @@ void free_initmem(void)
/* align __init_begin and __init_end to page size,
ignoring linker script where we might have tried to save RAM */
- init_begin = PAGE_ALIGN((unsigned long)(&__init_begin));
- init_end = PAGE_ALIGN((unsigned long)(&__init_end));
+ init_begin = PAGE_ALIGN((unsigned long)(__init_begin));
+ init_end = PAGE_ALIGN((unsigned long)(__init_end));
for (addr = init_begin; addr < init_end; addr += PAGE_SIZE) {
ClearPageReserved(virt_to_page(addr));
init_page_count(virt_to_page(addr));
@@ -578,7 +575,7 @@ static void __init map_pages(unsigned long start_vaddr, unsigned long start_padd
extern const unsigned long fault_vector_20;
extern void * const linux_gateway_page;
- ro_start = __pa((unsigned long)&_text);
+ ro_start = __pa((unsigned long)_text);
ro_end = __pa((unsigned long)&data_start);
fv_addr = __pa((unsigned long)&fault_vector_20) & PAGE_MASK;
gw_addr = __pa((unsigned long)&linux_gateway_page) & PAGE_MASK;
diff --git a/arch/parisc/mm/ioremap.c b/arch/parisc/mm/ioremap.c
index 27384567a1d0..47a1d2ac9419 100644
--- a/arch/parisc/mm/ioremap.c
+++ b/arch/parisc/mm/ioremap.c
@@ -188,7 +188,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
}
EXPORT_SYMBOL(__ioremap);
-void iounmap(void __iomem *addr)
+void iounmap(const volatile void __iomem *addr)
{
if (addr > high_memory)
return vfree((void *) (PAGE_MASK & (unsigned long __force) addr));
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index de1ef2fa1a20..2bd9b7fb0f6c 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -338,10 +338,6 @@ config PPC_MULTIPLATFORM
RS/6000 machine, an Apple machine, or a PReP, CHRP,
Maple or Cell-based machine.
-config PPC_ISERIES
- bool "IBM Legacy iSeries"
- depends on PPC64
-
config EMBEDDED6xx
bool "Embedded 6xx/7xx/7xxx-based board"
depends on PPC32 && (BROKEN||BROKEN_ON_SMP)
@@ -355,6 +351,16 @@ config APUS
<http://linux-apus.sourceforge.net/>.
endchoice
+config QUICC_ENGINE
+ bool
+ depends on PPC_MPC836x || PPC_MPC832x
+ default y
+ help
+ The QUICC Engine (QE) is a new generation of communications
+ coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
+ Selecting this option means that you wish to build a kernel
+ for a machine with a QE coprocessor.
+
config PPC_PSERIES
depends on PPC_MULTIPLATFORM && PPC64
bool "IBM pSeries & new (POWER5-based) iSeries"
@@ -365,6 +371,10 @@ config PPC_PSERIES
select PPC_UDBG_16550
default y
+config PPC_ISERIES
+ bool "IBM Legacy iSeries"
+ depends on PPC_MULTIPLATFORM && PPC64
+
config PPC_CHRP
bool "Common Hardware Reference Platform (CHRP) based machines"
depends on PPC_MULTIPLATFORM && PPC32
@@ -594,6 +604,7 @@ endmenu
source arch/powerpc/platforms/embedded6xx/Kconfig
source arch/powerpc/platforms/4xx/Kconfig
+source arch/powerpc/platforms/82xx/Kconfig
source arch/powerpc/platforms/83xx/Kconfig
source arch/powerpc/platforms/85xx/Kconfig
source arch/powerpc/platforms/86xx/Kconfig
@@ -731,16 +742,24 @@ config ARCH_SPARSEMEM_DEFAULT
def_bool y
depends on SMP && PPC_PSERIES
-source "mm/Kconfig"
-
-config HAVE_ARCH_EARLY_PFN_TO_NID
+config ARCH_POPULATES_NODE_MAP
def_bool y
- depends on NEED_MULTIPLE_NODES
+
+source "mm/Kconfig"
config ARCH_MEMORY_PROBE
def_bool y
depends on MEMORY_HOTPLUG
+# Some NUMA nodes have memory ranges that span
+# other nodes. Even though a pfn is valid and
+# between a node's start and end pfns, it may not
+# reside on that node. See memmap_init_zone()
+# for details.
+config NODES_SPAN_OTHER_NODES
+ def_bool y
+ depends on NEED_MULTIPLE_NODES
+
config PPC_64K_PAGES
bool "64k page size"
depends on PPC64
@@ -1003,7 +1022,7 @@ config CONSISTENT_START_BOOL
depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
help
This option allows you to set the base virtual address
- of the the consistent memory pool. This pool of virtual
+ of the consistent memory pool. This pool of virtual
memory is used to make consistent memory allocations.
config CONSISTENT_START
@@ -1014,7 +1033,7 @@ config CONSISTENT_SIZE_BOOL
bool "Set custom consistent memory pool size"
depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
help
- This option allows you to set the size of the the
+ This option allows you to set the size of the
consistent memory pool. This pool of virtual memory
is used to make consistent memory allocations.
@@ -1059,6 +1078,8 @@ source "fs/Kconfig"
# XXX source "arch/ppc/8260_io/Kconfig"
+source "arch/powerpc/sysdev/qe_lib/Kconfig"
+
source "arch/powerpc/platforms/iseries/Kconfig"
source "lib/Kconfig"
@@ -1070,7 +1091,7 @@ source "arch/powerpc/oprofile/Kconfig"
config KPROBES
bool "Kprobes (EXPERIMENTAL)"
- depends on PPC64 && EXPERIMENTAL && MODULES
+ depends on PPC64 && KALLSYMS && EXPERIMENTAL && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile
index 01667d1d571d..a00fe7236555 100644
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -20,6 +20,7 @@ CROSS32_COMPILE ?=
CROSS32CC := $(CROSS32_COMPILE)gcc
CROSS32AS := $(CROSS32_COMPILE)as
CROSS32LD := $(CROSS32_COMPILE)ld
+CROSS32AR := $(CROSS32_COMPILE)ar
CROSS32OBJCOPY := $(CROSS32_COMPILE)objcopy
ifeq ($(HAS_BIARCH),y)
@@ -28,10 +29,11 @@ CROSS32CC := $(CC) -m32
CROSS32AS := $(AS) -a32
CROSS32LD := $(LD) -m elf32ppc
CROSS32OBJCOPY := $(OBJCOPY)
+CROSS32AR := $(AR)
endif
endif
-export CROSS32CC CROSS32AS CROSS32LD CROSS32OBJCOPY
+export CROSS32CC CROSS32AS CROSS32LD CROSS32AR CROSS32OBJCOPY
KBUILD_DEFCONFIG := $(shell uname -m)_defconfig
@@ -146,7 +148,7 @@ all: $(KBUILD_IMAGE)
CPPFLAGS_vmlinux.lds := -Upowerpc
-BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd vmlinux.sm uImage vmlinux.bin
+BOOT_TARGETS = zImage zImage.initrd uImage
PHONY += $(BOOT_TARGETS)
diff --git a/arch/powerpc/boot/Makefile b/arch/powerpc/boot/Makefile
index e73774136b55..37ddfcab0003 100644
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -20,33 +20,34 @@
# CROSS32_COMPILE is setup as a prefix just like CROSS_COMPILE
# in the toplevel makefile.
+all: $(obj)/zImage
HOSTCC := gcc
BOOTCFLAGS := $(HOSTCFLAGS) -fno-builtin -nostdinc -isystem \
$(shell $(CROSS32CC) -print-file-name=include) -fPIC
BOOTAFLAGS := -D__ASSEMBLY__ $(BOOTCFLAGS) -traditional -nostdinc
-OBJCOPYFLAGS := contents,alloc,load,readonly,data
-OBJCOPY_COFF_ARGS := -O aixcoff-rs6000 --set-start 0x500000
-OBJCOPY_MIB_ARGS := -O aixcoff-rs6000 -R .stab -R .stabstr -R .comment
+
+ifeq ($(call cc-option-yn, -fstack-protector),y)
+BOOTCFLAGS += -fno-stack-protector
+endif
+
+BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
zlib := inffast.c inflate.c inftrees.c
zlibheader := inffast.h inffixed.h inflate.h inftrees.h infutil.h
zliblinuxheader := zlib.h zconf.h zutil.h
-$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
-#$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
+$(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) \
+ $(addprefix $(obj)/,$(zlibheader))
+
+src-wlib := string.S stdio.c main.c div64.S $(zlib)
+src-plat := of.c
+src-boot := crt0.S $(src-wlib) $(src-plat) empty.c
-src-boot-$(CONFIG_PPC_MULTIPLATFORM) := of.c
-src-boot := crt0.S string.S stdio.c main.c div64.S $(src-boot-y)
-src-boot += $(zlib)
src-boot := $(addprefix $(obj)/, $(src-boot))
obj-boot := $(addsuffix .o, $(basename $(src-boot)))
-
-ifeq ($(call cc-option-yn, -fstack-protector),y)
-BOOTCFLAGS += -fno-stack-protector
-endif
-
-BOOTCFLAGS += -I$(obj) -I$(srctree)/$(obj)
+obj-wlib := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-wlib))))
+obj-plat := $(addsuffix .o, $(basename $(addprefix $(obj)/, $(src-plat))))
quiet_cmd_copy_zlib = COPY $@
cmd_copy_zlib = sed "s@__attribute_used__@@;s@<linux/\([^>]\+\).*@\"\1\"@" $< > $@
@@ -66,8 +67,14 @@ $(addprefix $(obj)/,$(zlibheader)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
$(addprefix $(obj)/,$(zliblinuxheader)): $(obj)/%: $(srctree)/include/linux/%
$(call cmd,copy_zliblinuxheader)
-clean-files := $(zlib) $(zlibheader) $(zliblinuxheader)
+$(obj)/empty.c:
+ @touch $@
+
+$(obj)/zImage.lds $(obj)/zImage.coff.lds: $(obj)/%: $(srctree)/$(src)/%.S
+ @cp $< $@
+clean-files := $(zlib) $(zlibheader) $(zliblinuxheader) \
+ $(obj)/empty.c
quiet_cmd_bootcc = BOOTCC $@
cmd_bootcc = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTCFLAGS) -c -o $@ $<
@@ -75,146 +82,97 @@ quiet_cmd_bootcc = BOOTCC $@
quiet_cmd_bootas = BOOTAS $@
cmd_bootas = $(CROSS32CC) -Wp,-MD,$(depfile) $(BOOTAFLAGS) -c -o $@ $<
-quiet_cmd_bootld = BOOTLD $@
- cmd_bootld = $(CROSS32LD) -T $(srctree)/$(src)/$(3) -o $@ $(2)
+quiet_cmd_bootar = BOOTAR $@
+ cmd_bootar = $(CROSS32AR) -cr $@.$$$$ $^; mv $@.$$$$ $@
$(patsubst %.c,%.o, $(filter %.c, $(src-boot))): %.o: %.c
$(call if_changed_dep,bootcc)
$(patsubst %.S,%.o, $(filter %.S, $(src-boot))): %.o: %.S
$(call if_changed_dep,bootas)
-#-----------------------------------------------------------
-# ELF sections within the zImage bootloader/wrapper
-#-----------------------------------------------------------
-required := vmlinux.strip
-initrd := initrd
+$(obj)/wrapper.a: $(obj-wlib)
+ $(call cmd,bootar)
-obj-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.o, $(section)))
-src-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.c, $(section)))
-gz-sec = $(foreach section, $(1), $(patsubst %,$(obj)/kernel-%.gz, $(section)))
+hostprogs-y := addnote addRamDisk hack-coff
-hostprogs-y := addnote addRamDisk hack-coff
+extra-y := $(obj)/crt0.o $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
+ $(obj)/zImage.lds $(obj)/zImage.coff.lds
-targets += zImage.vmode zImage.initrd.vmode zImage zImage.initrd \
- zImage.coff zImage.initrd.coff miboot.image miboot.initrd.image \
- $(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
- $(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
- $(patsubst $(obj)/%,%, $(call gz-sec, $(required) $(initrd))) \
- vmlinux.initrd dummy.o
-extra-y := initrd.o
+wrapper :=$(srctree)/$(src)/wrapper
+wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff)
-quiet_cmd_ramdisk = RAMDISK $@
- cmd_ramdisk = $(obj)/addRamDisk $(obj)/ramdisk.image.gz $< $@
+#############
+# Bits for building various flavours of zImage
-quiet_cmd_stripvm = STRIP $@
- cmd_stripvm = $(STRIP) -s -R .comment $< -o $@
+ifneq ($(CROSS32_COMPILE),)
+CROSSWRAP := -C "$(CROSS32_COMPILE)"
+else
+ifneq ($(CROSS_COMPILE),)
+CROSSWRAP := -C "$(CROSS_COMPILE)"
+endif
+endif
-vmlinux.strip: vmlinux
- $(call if_changed,stripvm)
-$(obj)/vmlinux.initrd: vmlinux.strip $(obj)/addRamDisk $(obj)/ramdisk.image.gz
- $(call if_changed,ramdisk)
+quiet_cmd_wrap = WRAP $@
+ cmd_wrap =$(CONFIG_SHELL) $(wrapper) -c -o $@ -p $2 $(CROSSWRAP) vmlinux
+quiet_cmd_wrap_initrd = WRAP $@
+ cmd_wrap_initrd =$(wrapper) -c -o $@ -p $2 $(CROSSWRAP) \
+ -i $(obj)/ramdisk.image.gz vmlinux
-quiet_cmd_addsection = ADDSEC $@
- cmd_addsection = $(CROSS32OBJCOPY) $@ \
- --add-section=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(patsubst %.o,%.gz, $@) \
- --set-section-flags=.kernel:$(strip $(patsubst $(obj)/kernel-%.o,%, $@))=$(OBJCOPYFLAGS)
+$(obj)/zImage.chrp: vmlinux $(wrapperbits)
+ $(call cmd,wrap,chrp)
-quiet_cmd_addnote = ADDNOTE $@
- cmd_addnote = $(obj)/addnote $@
+$(obj)/zImage.initrd.chrp: vmlinux $(wrapperbits)
+ $(call cmd,wrap_initrd,chrp)
-quiet_cmd_gen-miboot = GEN $@
- cmd_gen-miboot = $(OBJCOPY) $(OBJCOPY_MIB_ARGS) \
- --add-section=$1=$(word 2, $^) $< $@
+$(obj)/zImage.pseries: vmlinux $(wrapperbits)
+ $(call cmd,wrap,pseries)
-quiet_cmd_gencoff = COFF $@
- cmd_gencoff = $(OBJCOPY) $(OBJCOPY_COFF_ARGS) $@ && \
- $(obj)/hack-coff $@
+$(obj)/zImage.initrd.pseries: vmlinux $(wrapperbits)
+ $(call cmd,wrap_initrd,pseries)
-$(call gz-sec, $(required)): $(obj)/kernel-%.gz: %
- $(call if_changed,gzip)
+$(obj)/zImage.pmac: vmlinux $(wrapperbits)
+ $(call cmd,wrap,pmac)
-$(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz
- cp -f $(obj)/ramdisk.image.gz $@
+$(obj)/zImage.initrd.pmac: vmlinux $(wrapperbits)
+ $(call cmd,wrap_initrd,pmac)
-$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz
- @touch $@
+$(obj)/zImage.coff: vmlinux $(wrapperbits)
+ $(call cmd,wrap,pmaccoff)
-$(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c
- $(call if_changed_dep,bootcc)
- $(call cmd,addsection)
+$(obj)/zImage.initrd.coff: vmlinux $(wrapperbits)
+ $(call cmd,wrap_initrd,pmaccoff)
+
+$(obj)/zImage.miboot: vmlinux $(wrapperbits)
+ $(call cmd,wrap,miboot)
-$(obj)/zImage.vmode $(obj)/zImage.coff: obj-boot += $(call obj-sec, $(required))
-$(obj)/zImage.vmode: $(call obj-sec, $(required)) $(obj-boot) $(srctree)/$(src)/zImage.lds
- $(call cmd,bootld,$(obj-boot),zImage.lds)
+$(obj)/zImage.initrd.miboot: vmlinux $(wrapperbits)
+ $(call cmd,wrap_initrd,miboot)
-$(obj)/zImage.initrd.vmode $(obj)/zImage.initrd.coff: obj-boot += $(call obj-sec, $(required) $(initrd))
-$(obj)/zImage.initrd.vmode: $(call obj-sec, $(required) $(initrd)) $(obj-boot) $(srctree)/$(src)/zImage.lds
- $(call cmd,bootld,$(obj-boot),zImage.lds)
+$(obj)/uImage: vmlinux $(wrapperbits)
+ $(call cmd,wrap,uboot)
+
+image-$(CONFIG_PPC_PSERIES) += zImage.pseries
+image-$(CONFIG_PPC_MAPLE) += zImage.pseries
+image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
+image-$(CONFIG_PPC_CHRP) += zImage.chrp
+image-$(CONFIG_PPC_PMAC) += zImage.pmac
+image-$(CONFIG_DEFAULT_UIMAGE) += uImage
# For 32-bit powermacs, build the COFF and miboot images
# as well as the ELF images.
-coffimage-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.coff
-coffrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/zImage.initrd.coff
-mibootimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/miboot.image
-mibrdimg-$(CONFIG_PPC_PMAC)-$(CONFIG_PPC32) := $(obj)/miboot.initrd.image
-
-$(obj)/zImage: $(obj)/zImage.vmode $(obj)/addnote $(coffimage-y-y) \
- $(mibootimg-y-y)
- @cp -f $< $@
- $(call if_changed,addnote)
-
-$(obj)/zImage.initrd: $(obj)/zImage.initrd.vmode $(obj)/addnote \
- $(coffrdimg-y-y) $(mibrdimg-y-y)
- @cp -f $< $@
- $(call if_changed,addnote)
-
-$(obj)/zImage.coff: $(call obj-sec, $(required)) $(obj-boot) \
- $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
- $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
- $(call cmd,gencoff)
-
-$(obj)/zImage.initrd.coff: $(call obj-sec, $(required) $(initrd)) $(obj-boot) \
- $(srctree)/$(src)/zImage.coff.lds $(obj)/hack-coff
- $(call cmd,bootld,$(obj-boot),zImage.coff.lds)
- $(call cmd,gencoff)
-
-$(obj)/miboot.image: $(obj)/dummy.o $(obj)/vmlinux.gz
- $(call cmd,gen-miboot,image)
-
-$(obj)/miboot.initrd.image: $(obj)/miboot.image $(images)/ramdisk.image.gz
- $(call cmd,gen-miboot,initrd)
-
-#-----------------------------------------------------------
-# build u-boot images
-#-----------------------------------------------------------
-quiet_cmd_mygzip = GZIP $@
-cmd_mygzip = gzip -f -9 < $< > $@.$$$$ && mv $@.$$$$ $@
-
-quiet_cmd_objbin = OBJCOPY $@
- cmd_objbin = $(OBJCOPY) -O binary $< $@
-
-quiet_cmd_uimage = UIMAGE $@
- cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A ppc -O linux -T kernel \
- -C gzip -a 00000000 -e 00000000 -n 'Linux-$(KERNELRELEASE)' \
- -d $< $@
-
-MKIMAGE := $(srctree)/scripts/mkuboot.sh
-targets += uImage
-extra-y += vmlinux.bin vmlinux.gz
-
-$(obj)/vmlinux.bin: vmlinux FORCE
- $(call if_changed,objbin)
-
-$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
- $(call if_changed,mygzip)
-
-$(obj)/uImage: $(obj)/vmlinux.gz
- $(Q)rm -f $@
- $(call cmd,uimage)
- @echo -n ' Image: $@ '
- @if [ -f $@ ]; then echo 'is ready' ; else echo 'not made'; fi
-
-install: $(CONFIGURE) $(BOOTIMAGE)
- sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" "$(BOOTIMAGE)"
-
-clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip)
+ifeq ($(CONFIG_PPC32),y)
+image-$(CONFIG_PPC_PMAC) += zImage.coff zImage.miboot
+endif
+
+initrd-y := $(patsubst zImage%, zImage.initrd%, $(image-y))
+
+$(obj)/zImage: $(addprefix $(obj)/, $(image-y))
+ @rm -f $@; ln $< $@
+$(obj)/zImage.initrd: $(addprefix $(obj)/, $(initrd-y))
+ @rm -f $@; ln $< $@
+
+install: $(CONFIGURE) $(image-y)
+ sh -x $(srctree)/$(src)/install.sh "$(KERNELRELEASE)" vmlinux System.map "$(INSTALL_PATH)" $<
+
+clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.strip.gz)
+clean-files += $(addprefix $(objtree)/, $(obj-boot) vmlinux.bin.gz)
diff --git a/arch/powerpc/boot/dts/mpc8272ads.dts b/arch/powerpc/boot/dts/mpc8272ads.dts
new file mode 100644
index 000000000000..34efdd028c4f
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8272ads.dts
@@ -0,0 +1,223 @@
+/*
+ * MPC8272 ADS Device Tree Source
+ *
+ * Copyright 2005 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+/ {
+ model = "MPC8272ADS";
+ compatible = "MPC8260ADS";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ linux,phandle = <100>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ linux,phandle = <200>;
+
+ PowerPC,8272@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <4000>; // L1, 16K
+ i-cache-size = <4000>; // L1, 16K
+ timebase-frequency = <0>;
+ bus-frequency = <0>;
+ clock-frequency = <0>;
+ 32-bit;
+ linux,phandle = <201>;
+ linux,boot-cpu;
+ };
+ };
+
+ interrupt-controller@f8200000 {
+ linux,phandle = <f8200000>;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <f8200000 f8200004>;
+ built-in;
+ device_type = "pci-pic";
+ };
+ memory {
+ device_type = "memory";
+ linux,phandle = <300>;
+ reg = <00000000 4000000 f4500000 00000020>;
+ };
+
+ soc8272@f0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = < 0 0 2 00000000 f0000000 00053000>;
+ reg = <f0000000 0>;
+
+ mdio@0 {
+ device_type = "mdio";
+ compatible = "fs_enet";
+ reg = <0 0>;
+ linux,phandle = <24520>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethernet-phy@0 {
+ linux,phandle = <2452000>;
+ interrupt-parent = <10c00>;
+ interrupts = <19 1>;
+ reg = <0>;
+ bitbang = [ 12 12 13 02 02 01 ];
+ device_type = "ethernet-phy";
+ };
+ ethernet-phy@1 {
+ linux,phandle = <2452001>;
+ interrupt-parent = <10c00>;
+ interrupts = <19 1>;
+ bitbang = [ 12 12 13 02 02 01 ];
+ reg = <3>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ ethernet@24000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "network";
+ device-id = <2>;
+ compatible = "fs_enet";
+ model = "FCC";
+ reg = <11300 20 8400 100 11380 30>;
+ mac-address = [ 00 11 2F 99 43 54 ];
+ interrupts = <20 2>;
+ interrupt-parent = <10c00>;
+ phy-handle = <2452000>;
+ rx-clock = <13>;
+ tx-clock = <12>;
+ };
+
+ ethernet@25000 {
+ device_type = "network";
+ device-id = <3>;
+ compatible = "fs_enet";
+ model = "FCC";
+ reg = <11320 20 8500 100 113b0 30>;
+ mac-address = [ 00 11 2F 99 44 54 ];
+ interrupts = <21 2>;
+ interrupt-parent = <10c00>;
+ phy-handle = <2452001>;
+ rx-clock = <17>;
+ tx-clock = <18>;
+ };
+
+ cpm@f0000000 {
+ linux,phandle = <f0000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "cpm";
+ model = "CPM2";
+ ranges = <00000000 00000000 3ffff>;
+ reg = <10d80 3280>;
+ command-proc = <119c0>;
+ brg-frequency = <17D7840>;
+ cpm_clk = <BEBC200>;
+
+ scc@11a00 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SCC";
+ device-id = <2>;
+ reg = <11a00 20 8000 100>;
+ current-speed = <1c200>;
+ interrupts = <28 2>;
+ interrupt-parent = <10c00>;
+ clock-setup = <0 00ffffff>;
+ rx-clock = <1>;
+ tx-clock = <1>;
+ };
+
+ scc@11a60 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SCC";
+ device-id = <5>;
+ reg = <11a60 20 8300 100>;
+ current-speed = <1c200>;
+ interrupts = <2b 2>;
+ interrupt-parent = <10c00>;
+ clock-setup = <1b ffffff00>;
+ rx-clock = <4>;
+ tx-clock = <4>;
+ };
+
+ };
+ interrupt-controller@10c00 {
+ linux,phandle = <10c00>;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupt-controller;
+ reg = <10c00 80>;
+ built-in;
+ device_type = "cpm-pic";
+ compatible = "CPM2";
+ };
+ pci@0500 {
+ linux,phandle = <0500>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "8272";
+ device_type = "pci";
+ reg = <10430 4dc>;
+ clock-frequency = <3f940aa>;
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+
+ /* IDSEL 0x16 */
+ b000 0 0 1 f8200000 40 0
+ b000 0 0 2 f8200000 41 0
+ b000 0 0 3 f8200000 42 0
+ b000 0 0 4 f8200000 43 0
+
+ /* IDSEL 0x17 */
+ b800 0 0 1 f8200000 43 0
+ b800 0 0 2 f8200000 40 0
+ b800 0 0 3 f8200000 41 0
+ b800 0 0 4 f8200000 42 0
+
+ /* IDSEL 0x18 */
+ c000 0 0 1 f8200000 42 0
+ c000 0 0 2 f8200000 43 0
+ c000 0 0 3 f8200000 40 0
+ c000 0 0 4 f8200000 41 0>;
+ interrupt-parent = <10c00>;
+ interrupts = <14 3>;
+ bus-range = <0 0>;
+ ranges = <02000000 0 80000000 80000000 0 40000000
+ 01000000 0 00000000 f6000000 0 02000000>;
+ };
+
+/* May need to remove if on a part without crypto engine */
+ crypto@30000 {
+ device_type = "crypto";
+ model = "SEC2";
+ compatible = "talitos";
+ reg = <30000 10000>;
+ interrupts = <b 0>;
+ interrupt-parent = <10c00>;
+ num-channels = <4>;
+ channel-fifo-len = <18>;
+ exec-units-mask = <0000007e>;
+/* desc mask is for rev1.x, we need runtime fixup for >=2.x */
+ descriptor-types-mask = <01010ebf>;
+ };
+
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts
new file mode 100644
index 000000000000..27807fc45888
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8349emitx.dts
@@ -0,0 +1,246 @@
+/*
+ * MPC8349E-mITX Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+/ {
+ model = "MPC8349EMITX";
+ compatible = "MPC834xMITX";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ PowerPC,8349@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>;
+ i-cache-line-size = <20>;
+ d-cache-size = <8000>;
+ i-cache-size = <8000>;
+ timebase-frequency = <0>; // from bootloader
+ bus-frequency = <0>; // from bootloader
+ clock-frequency = <0>; // from bootloader
+ 32-bit;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <00000000 10000000>;
+ };
+
+ soc8349@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 e0000000 00100000>;
+ reg = <e0000000 00000200>;
+ bus-frequency = <0>; // from bootloader
+
+ wdt@200 {
+ device_type = "watchdog";
+ compatible = "mpc83xx_wdt";
+ reg = <200 100>;
+ };
+
+ i2c@3000 {
+ device_type = "i2c";
+ compatible = "fsl-i2c";
+ reg = <3000 100>;
+ interrupts = <e 8>;
+ interrupt-parent = <700>;
+ dfsrr;
+ };
+
+ i2c@3100 {
+ device_type = "i2c";
+ compatible = "fsl-i2c";
+ reg = <3100 100>;
+ interrupts = <f 8>;
+ interrupt-parent = <700>;
+ dfsrr;
+ };
+
+ spi@7000 {
+ device_type = "spi";
+ compatible = "mpc83xx_spi";
+ reg = <7000 1000>;
+ interrupts = <10 8>;
+ interrupt-parent = <700>;
+ mode = <0>;
+ };
+
+ usb@22000 {
+ device_type = "usb";
+ compatible = "fsl-usb2-mph";
+ reg = <22000 1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <700>;
+ interrupts = <27 2>;
+ phy_type = "ulpi";
+ port1;
+ };
+
+ usb@23000 {
+ device_type = "usb";
+ compatible = "fsl-usb2-dr";
+ reg = <23000 1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupt-parent = <700>;
+ interrupts = <26 2>;
+ phy_type = "ulpi";
+ };
+
+ mdio@24520 {
+ device_type = "mdio";
+ compatible = "gianfar";
+ reg = <24520 20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ linux,phandle = <24520>;
+
+ /* Vitesse 8201 */
+ ethernet-phy@1c {
+ linux,phandle = <245201c>;
+ interrupt-parent = <700>;
+ interrupts = <12 2>;
+ reg = <1c>;
+ device_type = "ethernet-phy";
+ };
+
+ /* Vitesse 7385 */
+ ethernet-phy@1f {
+ linux,phandle = <245201f>;
+ interrupt-parent = <700>;
+ interrupts = <12 2>;
+ reg = <1f>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ ethernet@24000 {
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <24000 1000>;
+ address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <20 8 21 8 22 8>;
+ interrupt-parent = <700>;
+ phy-handle = <245201c>;
+ };
+
+ ethernet@25000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <25000 1000>;
+ address = [ 00 00 00 00 00 00 ];
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ interrupts = <23 8 24 8 25 8>;
+ interrupt-parent = <700>;
+ phy-handle = <245201f>;
+ };
+
+ serial@4500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4500 100>;
+ clock-frequency = <0>; // from bootloader
+ interrupts = <9 8>;
+ interrupt-parent = <700>;
+ };
+
+ serial@4600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4600 100>;
+ clock-frequency = <0>; // from bootloader
+ interrupts = <a 8>;
+ interrupt-parent = <700>;
+ };
+
+ pci@8500 {
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x10 - SATA */
+ 8000 0 0 1 700 16 8 /* SATA_INTA */
+ >;
+ interrupt-parent = <700>;
+ interrupts = <42 8>;
+ bus-range = <0 0>;
+ ranges = <42000000 0 80000000 80000000 0 10000000
+ 02000000 0 90000000 90000000 0 10000000
+ 01000000 0 00000000 e2000000 0 01000000>;
+ clock-frequency = <3f940aa>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <8500 100>;
+ compatible = "83xx";
+ device_type = "pci";
+ };
+
+ pci@8600 {
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+ /* IDSEL 0x0E - MiniPCI Slot */
+ 7000 0 0 1 700 15 8 /* PCI_INTA */
+
+ /* IDSEL 0x0F - PCI Slot */
+ 7800 0 0 1 700 14 8 /* PCI_INTA */
+ 7800 0 0 2 700 15 8 /* PCI_INTB */
+ >;
+ interrupt-parent = <700>;
+ interrupts = <43 8>;
+ bus-range = <1 1>;
+ ranges = <42000000 0 a0000000 a0000000 0 10000000
+ 02000000 0 b0000000 b0000000 0 10000000
+ 01000000 0 00000000 e3000000 0 01000000>;
+ clock-frequency = <3f940aa>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <8600 100>;
+ compatible = "83xx";
+ device_type = "pci";
+ };
+
+ crypto@30000 {
+ device_type = "crypto";
+ model = "SEC2";
+ compatible = "talitos";
+ reg = <30000 10000>;
+ interrupts = <b 8>;
+ interrupt-parent = <700>;
+ num-channels = <4>;
+ channel-fifo-len = <18>;
+ exec-units-mask = <0000007e>;
+ descriptor-types-mask = <01010ebf>;
+ };
+
+ pic@700 {
+ linux,phandle = <700>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <700 100>;
+ built-in;
+ device_type = "ipic";
+ };
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8360emds.dts b/arch/powerpc/boot/dts/mpc8360emds.dts
new file mode 100644
index 000000000000..9022192155b9
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8360emds.dts
@@ -0,0 +1,375 @@
+/*
+ * MPC8360E EMDS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+
+/*
+/memreserve/ 00000000 1000000;
+*/
+
+/ {
+ model = "MPC8360EPB";
+ compatible = "MPC83xx";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ linux,phandle = <100>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ linux,phandle = <200>;
+
+ PowerPC,8360@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <8000>; // L1, 32K
+ i-cache-size = <8000>; // L1, 32K
+ timebase-frequency = <3EF1480>;
+ bus-frequency = <FBC5200>;
+ clock-frequency = <1F78A400>;
+ 32-bit;
+ linux,phandle = <201>;
+ linux,boot-cpu;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ linux,phandle = <300>;
+ reg = <00000000 10000000>;
+ };
+
+ bcsr@f8000000 {
+ device_type = "board-control";
+ reg = <f8000000 8000>;
+ };
+
+ soc8360@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 e0000000 00100000>;
+ reg = <e0000000 00000200>;
+ bus-frequency = <FBC5200>;
+
+ wdt@200 {
+ device_type = "watchdog";
+ compatible = "mpc83xx_wdt";
+ reg = <200 100>;
+ };
+
+ i2c@3000 {
+ device_type = "i2c";
+ compatible = "fsl-i2c";
+ reg = <3000 100>;
+ interrupts = <e 8>;
+ interrupt-parent = <700>;
+ dfsrr;
+ };
+
+ i2c@3100 {
+ device_type = "i2c";
+ compatible = "fsl-i2c";
+ reg = <3100 100>;
+ interrupts = <f 8>;
+ interrupt-parent = <700>;
+ dfsrr;
+ };
+
+ serial@4500 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4500 100>;
+ clock-frequency = <FBC5200>;
+ interrupts = <9 8>;
+ interrupt-parent = <700>;
+ };
+
+ serial@4600 {
+ device_type = "serial";
+ compatible = "ns16550";
+ reg = <4600 100>;
+ clock-frequency = <FBC5200>;
+ interrupts = <a 8>;
+ interrupt-parent = <700>;
+ };
+
+ crypto@30000 {
+ device_type = "crypto";
+ model = "SEC2";
+ compatible = "talitos";
+ reg = <30000 10000>;
+ interrupts = <b 8>;
+ interrupt-parent = <700>;
+ num-channels = <4>;
+ channel-fifo-len = <18>;
+ exec-units-mask = <0000007e>;
+ /* desc mask is for rev1.x, we need runtime fixup for >=2.x */
+ descriptor-types-mask = <01010ebf>;
+ };
+
+ pci@8500 {
+ linux,phandle = <8500>;
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+
+ /* IDSEL 0x11 AD17 */
+ 8800 0 0 1 700 14 8
+ 8800 0 0 2 700 15 8
+ 8800 0 0 3 700 16 8
+ 8800 0 0 4 700 17 8
+
+ /* IDSEL 0x12 AD18 */
+ 9000 0 0 1 700 16 8
+ 9000 0 0 2 700 17 8
+ 9000 0 0 3 700 14 8
+ 9000 0 0 4 700 15 8
+
+ /* IDSEL 0x13 AD19 */
+ 9800 0 0 1 700 17 8
+ 9800 0 0 2 700 14 8
+ 9800 0 0 3 700 15 8
+ 9800 0 0 4 700 16 8
+
+ /* IDSEL 0x15 AD21*/
+ a800 0 0 1 700 14 8
+ a800 0 0 2 700 15 8
+ a800 0 0 3 700 16 8
+ a800 0 0 4 700 17 8
+
+ /* IDSEL 0x16 AD22*/
+ b000 0 0 1 700 17 8
+ b000 0 0 2 700 14 8
+ b000 0 0 3 700 15 8
+ b000 0 0 4 700 16 8
+
+ /* IDSEL 0x17 AD23*/
+ b800 0 0 1 700 16 8
+ b800 0 0 2 700 17 8
+ b800 0 0 3 700 14 8
+ b800 0 0 4 700 15 8
+
+ /* IDSEL 0x18 AD24*/
+ c000 0 0 1 700 15 8
+ c000 0 0 2 700 16 8
+ c000 0 0 3 700 17 8
+ c000 0 0 4 700 14 8>;
+ interrupt-parent = <700>;
+ interrupts = <42 8>;
+ bus-range = <0 0>;
+ ranges = <02000000 0 a0000000 a0000000 0 10000000
+ 42000000 0 80000000 80000000 0 10000000
+ 01000000 0 00000000 e2000000 0 00100000>;
+ clock-frequency = <3f940aa>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ reg = <8500 100>;
+ compatible = "83xx";
+ device_type = "pci";
+ };
+
+ pic@700 {
+ linux,phandle = <700>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <700 100>;
+ built-in;
+ device_type = "ipic";
+ };
+
+ par_io@1400 {
+ reg = <1400 100>;
+ device_type = "par_io";
+ num-ports = <7>;
+
+ ucc_pin@01 {
+ linux,phandle = <140001>;
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0 3 1 0 1 0 /* TxD0 */
+ 0 4 1 0 1 0 /* TxD1 */
+ 0 5 1 0 1 0 /* TxD2 */
+ 0 6 1 0 1 0 /* TxD3 */
+ 1 6 1 0 3 0 /* TxD4 */
+ 1 7 1 0 1 0 /* TxD5 */
+ 1 9 1 0 2 0 /* TxD6 */
+ 1 a 1 0 2 0 /* TxD7 */
+ 0 9 2 0 1 0 /* RxD0 */
+ 0 a 2 0 1 0 /* RxD1 */
+ 0 b 2 0 1 0 /* RxD2 */
+ 0 c 2 0 1 0 /* RxD3 */
+ 0 d 2 0 1 0 /* RxD4 */
+ 1 1 2 0 2 0 /* RxD5 */
+ 1 0 2 0 2 0 /* RxD6 */
+ 1 4 2 0 2 0 /* RxD7 */
+ 0 7 1 0 1 0 /* TX_EN */
+ 0 8 1 0 1 0 /* TX_ER */
+ 0 f 2 0 1 0 /* RX_DV */
+ 0 10 2 0 1 0 /* RX_ER */
+ 0 0 2 0 1 0 /* RX_CLK */
+ 2 9 1 0 3 0 /* GTX_CLK - CLK10 */
+ 2 8 2 0 1 0>; /* GTX125 - CLK9 */
+ };
+ ucc_pin@02 {
+ linux,phandle = <140002>;
+ pio-map = <
+ /* port pin dir open_drain assignment has_irq */
+ 0 11 1 0 1 0 /* TxD0 */
+ 0 12 1 0 1 0 /* TxD1 */
+ 0 13 1 0 1 0 /* TxD2 */
+ 0 14 1 0 1 0 /* TxD3 */
+ 1 2 1 0 1 0 /* TxD4 */
+ 1 3 1 0 2 0 /* TxD5 */
+ 1 5 1 0 3 0 /* TxD6 */
+ 1 8 1 0 3 0 /* TxD7 */
+ 0 17 2 0 1 0 /* RxD0 */
+ 0 18 2 0 1 0 /* RxD1 */
+ 0 19 2 0 1 0 /* RxD2 */
+ 0 1a 2 0 1 0 /* RxD3 */
+ 0 1b 2 0 1 0 /* RxD4 */
+ 1 c 2 0 2 0 /* RxD5 */
+ 1 d 2 0 3 0 /* RxD6 */
+ 1 b 2 0 2 0 /* RxD7 */
+ 0 15 1 0 1 0 /* TX_EN */
+ 0 16 1 0 1 0 /* TX_ER */
+ 0 1d 2 0 1 0 /* RX_DV */
+ 0 1e 2 0 1 0 /* RX_ER */
+ 0 1f 2 0 1 0 /* RX_CLK */
+ 2 2 1 0 2 0 /* GTX_CLK - CLK10 */
+ 2 3 2 0 1 0 /* GTX125 - CLK4 */
+ 0 1 3 0 2 0 /* MDIO */
+ 0 2 1 0 1 0>; /* MDC */
+ };
+
+ };
+ };
+
+ qe@e0100000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ device_type = "qe";
+ model = "QE";
+ ranges = <0 e0100000 00100000>;
+ reg = <e0100000 480>;
+ brg-frequency = <0>;
+ bus-frequency = <179A7B00>;
+
+ muram@10000 {
+ device_type = "muram";
+ ranges = <0 00010000 0000c000>;
+
+ data-only@0{
+ reg = <0 c000>;
+ };
+ };
+
+ spi@4c0 {
+ device_type = "spi";
+ compatible = "fsl_spi";
+ reg = <4c0 40>;
+ interrupts = <2>;
+ interrupt-parent = <80>;
+ mode = "cpu";
+ };
+
+ spi@500 {
+ device_type = "spi";
+ compatible = "fsl_spi";
+ reg = <500 40>;
+ interrupts = <1>;
+ interrupt-parent = <80>;
+ mode = "cpu";
+ };
+
+ usb@6c0 {
+ device_type = "usb";
+ compatible = "qe_udc";
+ reg = <6c0 40 8B00 100>;
+ interrupts = <b>;
+ interrupt-parent = <80>;
+ mode = "slave";
+ };
+
+ ucc@2000 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <1>;
+ reg = <2000 200>;
+ interrupts = <20>;
+ interrupt-parent = <80>;
+ mac-address = [ 00 04 9f 00 23 23 ];
+ rx-clock = <0>;
+ tx-clock = <19>;
+ phy-handle = <212000>;
+ pio-handle = <140001>;
+ };
+
+ ucc@3000 {
+ device_type = "network";
+ compatible = "ucc_geth";
+ model = "UCC";
+ device-id = <2>;
+ reg = <3000 200>;
+ interrupts = <21>;
+ interrupt-parent = <80>;
+ mac-address = [ 00 11 22 33 44 55 ];
+ rx-clock = <0>;
+ tx-clock = <14>;
+ phy-handle = <212001>;
+ pio-handle = <140002>;
+ };
+
+ mdio@2120 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <2120 18>;
+ device_type = "mdio";
+ compatible = "ucc_geth_phy";
+
+ ethernet-phy@00 {
+ linux,phandle = <212000>;
+ interrupt-parent = <700>;
+ interrupts = <11 2>;
+ reg = <0>;
+ device_type = "ethernet-phy";
+ interface = <6>; //ENET_1000_GMII
+ };
+ ethernet-phy@01 {
+ linux,phandle = <212001>;
+ interrupt-parent = <700>;
+ interrupts = <12 2>;
+ reg = <1>;
+ device_type = "ethernet-phy";
+ interface = <6>;
+ };
+ };
+
+ qeic@80 {
+ linux,phandle = <80>;
+ interrupt-controller;
+ device_type = "qeic";
+ #address-cells = <0>;
+ #interrupt-cells = <1>;
+ reg = <80 80>;
+ built-in;
+ big-endian;
+ interrupts = <20 8 21 8>; //high:32 low:33
+ interrupt-parent = <700>;
+ };
+
+ };
+};
diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts
new file mode 100644
index 000000000000..2b168486aeba
--- /dev/null
+++ b/arch/powerpc/boot/dts/mpc8560ads.dts
@@ -0,0 +1,302 @@
+/*
+ * MPC8560 ADS Device Tree Source
+ *
+ * Copyright 2006 Freescale Semiconductor Inc.
+ *
+ * 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.
+ */
+
+
+/ {
+ model = "MPC8560ADS";
+ compatible = "MPC85xxADS";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ linux,phandle = <100>;
+
+ cpus {
+ #cpus = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ linux,phandle = <200>;
+
+ PowerPC,8560@0 {
+ device_type = "cpu";
+ reg = <0>;
+ d-cache-line-size = <20>; // 32 bytes
+ i-cache-line-size = <20>; // 32 bytes
+ d-cache-size = <8000>; // L1, 32K
+ i-cache-size = <8000>; // L1, 32K
+ timebase-frequency = <04ead9a0>;
+ bus-frequency = <13ab6680>;
+ clock-frequency = <312c8040>;
+ 32-bit;
+ linux,phandle = <201>;
+ linux,boot-cpu;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ linux,phandle = <300>;
+ reg = <00000000 10000000>;
+ };
+
+ soc8560@e0000000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "soc";
+ ranges = <0 e0000000 00100000>;
+ reg = <e0000000 00000200>;
+ bus-frequency = <13ab6680>;
+
+ mdio@24520 {
+ device_type = "mdio";
+ compatible = "gianfar";
+ reg = <24520 20>;
+ linux,phandle = <24520>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ethernet-phy@0 {
+ linux,phandle = <2452000>;
+ interrupt-parent = <40000>;
+ interrupts = <35 1>;
+ reg = <0>;
+ device_type = "ethernet-phy";
+ };
+ ethernet-phy@1 {
+ linux,phandle = <2452001>;
+ interrupt-parent = <40000>;
+ interrupts = <35 1>;
+ reg = <1>;
+ device_type = "ethernet-phy";
+ };
+ ethernet-phy@2 {
+ linux,phandle = <2452002>;
+ interrupt-parent = <40000>;
+ interrupts = <37 1>;
+ reg = <2>;
+ device_type = "ethernet-phy";
+ };
+ ethernet-phy@3 {
+ linux,phandle = <2452003>;
+ interrupt-parent = <40000>;
+ interrupts = <37 1>;
+ reg = <3>;
+ device_type = "ethernet-phy";
+ };
+ };
+
+ ethernet@24000 {
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <24000 1000>;
+ address = [ 00 00 0C 00 00 FD ];
+ interrupts = <d 2 e 2 12 2>;
+ interrupt-parent = <40000>;
+ phy-handle = <2452000>;
+ };
+
+ ethernet@25000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ device_type = "network";
+ model = "TSEC";
+ compatible = "gianfar";
+ reg = <25000 1000>;
+ address = [ 00 00 0C 00 01 FD ];
+ interrupts = <13 2 14 2 18 2>;
+ interrupt-parent = <40000>;
+ phy-handle = <2452001>;
+ };
+
+ pci@8000 {
+ linux,phandle = <8000>;
+ #interrupt-cells = <1>;
+ #size-cells = <2>;
+ #address-cells = <3>;
+ compatible = "85xx";
+ device_type = "pci";
+ reg = <8000 400>;
+ clock-frequency = <3f940aa>;
+ interrupt-map-mask = <f800 0 0 7>;
+ interrupt-map = <
+
+ /* IDSEL 0x2 */
+ 1000 0 0 1 40000 31 1
+ 1000 0 0 2 40000 32 1
+ 1000 0 0 3 40000 33 1
+ 1000 0 0 4 40000 34 1
+
+ /* IDSEL 0x3 */
+ 1800 0 0 1 40000 34 1
+ 1800 0 0 2 40000 31 1
+ 1800 0 0 3 40000 32 1
+ 1800 0 0 4 40000 33 1
+
+ /* IDSEL 0x4 */
+ 2000 0 0 1 40000 33 1
+ 2000 0 0 2 40000 34 1
+ 2000 0 0 3 40000 31 1
+ 2000 0 0 4 40000 32 1
+
+ /* IDSEL 0x5 */
+ 2800 0 0 1 40000 32 1
+ 2800 0 0 2 40000 33 1
+ 2800 0 0 3 40000 34 1
+ 2800 0 0 4 40000 31 1
+
+ /* IDSEL 12 */
+ 6000 0 0 1 40000 31 1
+ 6000 0 0 2 40000 32 1
+ 6000 0 0 3 40000 33 1
+ 6000 0 0 4 40000 34 1
+
+ /* IDSEL 13 */
+ 6800 0 0 1 40000 34 1
+ 6800 0 0 2 40000 31 1
+ 6800 0 0 3 40000 32 1
+ 6800 0 0 4 40000 33 1
+
+ /* IDSEL 14*/
+ 7000 0 0 1 40000 33 1
+ 7000 0 0 2 40000 34 1
+ 7000 0 0 3 40000 31 1
+ 7000 0 0 4 40000 32 1
+
+ /* IDSEL 15 */
+ 7800 0 0 1 40000 32 1
+ 7800 0 0 2 40000 33 1
+ 7800 0 0 3 40000 34 1
+ 7800 0 0 4 40000 31 1
+
+ /* IDSEL 18 */
+ 9000 0 0 1 40000 31 1
+ 9000 0 0 2 40000 32 1
+ 9000 0 0 3 40000 33 1
+ 9000 0 0 4 40000 34 1
+
+ /* IDSEL 19 */
+ 9800 0 0 1 40000 34 1
+ 9800 0 0 2 40000 31 1
+ 9800 0 0 3 40000 32 1
+ 9800 0 0 4 40000 33 1
+
+ /* IDSEL 20 */
+ a000 0 0 1 40000 33 1
+ a000 0 0 2 40000 34 1
+ a000 0 0 3 40000 31 1
+ a000 0 0 4 40000 32 1
+
+ /* IDSEL 21 */
+ a800 0 0 1 40000 32 1
+ a800 0 0 2 40000 33 1
+ a800 0 0 3 40000 34 1
+ a800 0 0 4 40000 31 1>;
+
+ interrupt-parent = <40000>;
+ interrupts = <42 0>;
+ bus-range = <0 0>;
+ ranges = <02000000 0 80000000 80000000 0 20000000
+ 01000000 0 00000000 e2000000 0 01000000>;
+ };
+
+ pic@40000 {
+ linux,phandle = <40000>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ reg = <40000 20100>;
+ built-in;
+ device_type = "open-pic";
+ };
+
+ cpm@e0000000 {
+ linux,phandle = <e0000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ #interrupt-cells = <2>;
+ device_type = "cpm";
+ model = "CPM2";
+ ranges = <0 0 c0000>;
+ reg = <80000 40000>;
+ command-proc = <919c0>;
+ brg-frequency = <9d5b340>;
+
+ pic@90c00 {
+ linux,phandle = <90c00>;
+ interrupt-controller;
+ #address-cells = <0>;
+ #interrupt-cells = <2>;
+ interrupts = <1e 0>;
+ interrupt-parent = <40000>;
+ reg = <90c00 80>;
+ built-in;
+ device_type = "cpm-pic";
+ };
+
+ scc@91a00 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SCC";
+ device-id = <1>;
+ reg = <91a00 20 88000 100>;
+ clock-setup = <00ffffff 0>;
+ rx-clock = <1>;
+ tx-clock = <1>;
+ current-speed = <1c200>;
+ interrupts = <64 1>;
+ interrupt-parent = <90c00>;
+ };
+
+ scc@91a20 {
+ device_type = "serial";
+ compatible = "cpm_uart";
+ model = "SCC";
+ device-id = <2>;
+ reg = <91a20 20 88100 100>;
+ clock-setup = <ff00ffff 90000>;
+ rx-clock = <2>;
+ tx-clock = <2>;
+ current-speed = <1c200>;
+ interrupts = <65 1>;
+ interrupt-parent = <90c00>;
+ };
+
+ fcc@91320 {
+ device_type = "network";
+ compatible = "fs_enet";
+ model = "FCC";
+ device-id = <2>;
+ reg = <91320 20 88500 100 913a0 30>;
+ mac-address = [ 00 00 0C 00 02 FD ];
+ clock-setup = <ff00ffff 250000>;
+ rx-clock = <15>;
+ tx-clock = <16>;
+ interrupts = <5d 1>;
+ interrupt-parent = <90c00>;
+ phy-handle = <2452002>;
+ };
+
+ fcc@91340 {
+ device_type = "network";
+ compatible = "fs_enet";
+ model = "FCC";
+ device-id = <3>;
+ reg = <91340 20 88600 100 913d0 30>;
+ mac-address = [ 00 00 0C 00 03 FD ];
+ clock-setup = <ffff00ff 3700>;
+ rx-clock = <17>;
+ tx-clock = <18>;
+ interrupts = <5e 1>;
+ interrupt-parent = <90c00>;
+ phy-handle = <2452003>;
+ };
+ };
+ };
+};
diff --git a/arch/powerpc/boot/of.c b/arch/powerpc/boot/of.c
index fd99f789a37b..3a71845afc6c 100644
--- a/arch/powerpc/boot/of.c
+++ b/arch/powerpc/boot/of.c
@@ -176,12 +176,9 @@ static void *claim(unsigned long virt, unsigned long size, unsigned long align)
static void *of_try_claim(u32 size)
{
unsigned long addr = 0;
- static u8 first_time = 1;
- if (first_time) {
+ if (claim_base == 0)
claim_base = _ALIGN_UP((unsigned long)_end, ONE_MB);
- first_time = 0;
- }
for(; claim_base < RAM_END; claim_base += ONE_MB) {
#ifdef DEBUG
diff --git a/arch/powerpc/boot/wrapper b/arch/powerpc/boot/wrapper
new file mode 100755
index 000000000000..eab7318729e9
--- /dev/null
+++ b/arch/powerpc/boot/wrapper
@@ -0,0 +1,204 @@
+#!/bin/sh
+
+# Copyright (C) 2006 Paul Mackerras, IBM Corporation <paulus@samba.org>
+# This program may be used under the terms of version 2 of the GNU
+# General Public License.
+
+# This script takes a kernel binary and optionally an initrd image
+# and/or a device-tree blob, and creates a bootable zImage for a
+# given platform.
+
+# Options:
+# -o zImage specify output file
+# -p platform specify platform (links in $platform.o)
+# -i initrd specify initrd file
+# -d devtree specify device-tree blob
+# -s tree.dts specify device-tree source file (needs dtc installed)
+# -c cache $kernel.strip.gz (use if present & newer, else make)
+# -C prefix specify command prefix for cross-building tools
+# (strip, objcopy, ld)
+# -D dir specify directory containing data files used by script
+# (default ./arch/powerpc/boot)
+# -W dir specify working directory for temporary files (default .)
+
+# defaults
+kernel=
+ofile=zImage
+platform=of
+initrd=
+dtb=
+dts=
+cacheit=
+
+# cross-compilation prefix
+CROSS=
+
+# directory for object and other files used by this script
+object=arch/powerpc/boot
+
+# directory for working files
+tmpdir=.
+
+usage() {
+ echo 'Usage: wrapper [-o output] [-p platform] [-i initrd]' >&2
+ echo ' [-d devtree] [-s tree.dts] [-c] [-C cross-prefix]' >&2
+ echo ' [-D datadir] [-W workingdir] [vmlinux]' >&2
+ exit 1
+}
+
+while [ "$#" -gt 0 ]; do
+ case "$1" in
+ -o)
+ shift
+ [ "$#" -gt 0 ] || usage
+ ofile="$1"
+ ;;
+ -p)
+ shift
+ [ "$#" -gt 0 ] || usage
+ platform="$1"
+ ;;
+ -i)
+ shift
+ [ "$#" -gt 0 ] || usage
+ initrd="$1"
+ ;;
+ -d)
+ shift
+ [ "$#" -gt 0 ] || usage
+ dtb="$1"
+ ;;
+ -s)
+ shift
+ [ "$#" -gt 0 ] || usage
+ dts="$1"
+ ;;
+ -c)
+ cacheit=y
+ ;;
+ -C)
+ shift
+ [ "$#" -gt 0 ] || usage
+ CROSS="$1"
+ ;;
+ -D)
+ shift
+ [ "$#" -gt 0 ] || usage
+ object="$1"
+ ;;
+ -W)
+ shift
+ [ "$#" -gt 0 ] || usage
+ tmpdir="$1"
+ ;;
+ -?)
+ usage
+ ;;
+ *)
+ [ -z "$kernel" ] || usage
+ kernel="$1"
+ ;;
+ esac
+ shift
+done
+
+if [ -n "$dts" ]; then
+ if [ -z "$dtb" ]; then
+ dtb="$platform.dtb"
+ fi
+ dtc -O dtb -o "$dtb" -b 0 -V 16 "$dts" || exit 1
+fi
+
+if [ -z "$kernel" ]; then
+ kernel=vmlinux
+fi
+
+platformo=$object/"$platform".o
+lds=$object/zImage.lds
+ext=strip
+objflags=-S
+tmp=$tmpdir/zImage.$$.o
+ksection=.kernel:vmlinux.strip
+isection=.kernel:initrd
+
+case "$platform" in
+pmac|pseries|chrp)
+ platformo=$object/of.o
+ ;;
+pmaccoff)
+ platformo=$object/of.o
+ lds=$object/zImage.coff.lds
+ ;;
+miboot|uboot)
+ # miboot and U-boot want just the bare bits, not an ELF binary
+ ext=bin
+ objflags="-O binary"
+ tmp="$ofile"
+ ksection=image
+ isection=initrd
+ ;;
+esac
+
+vmz="$tmpdir/`basename \"$kernel\"`.$ext"
+if [ -z "$cacheit" -o ! -f "$vmz.gz" -o "$vmz.gz" -ot "$kernel" ]; then
+ ${CROSS}objcopy $objflags "$kernel" "$vmz.$$"
+ gzip -f -9 "$vmz.$$"
+ if [ -n "$cacheit" ]; then
+ mv -f "$vmz.$$.gz" "$vmz.gz"
+ else
+ vmz="$vmz.$$"
+ fi
+fi
+
+case "$platform" in
+uboot)
+ rm -f "$ofile"
+ version=`${CROSS}strings "$kernel" | grep '^Linux version [-0-9.]' | \
+ cut -d' ' -f3`
+ if [ -n "$version" ]; then
+ version="-n Linux-$version"
+ fi
+ mkimage -A ppc -O linux -T kernel -C gzip -a 00000000 -e 00000000 \
+ $version -d "$vmz.gz" "$ofile"
+ if [ -z "$cacheit" ]; then
+ rm -f $vmz.gz
+ fi
+ exit 0
+ ;;
+esac
+
+addsec() {
+ ${CROSS}objcopy $4 $1 \
+ --add-section=$3="$2" \
+ --set-section-flags=$3=contents,alloc,load,readonly,data
+}
+
+addsec $tmp "$vmz.gz" $ksection $object/empty.o
+if [ -z "$cacheit" ]; then
+ rm -f "$vmz.gz"
+fi
+
+if [ -n "$initrd" ]; then
+ addsec $tmp "$initrd" initrd
+fi
+
+if [ -n "$dtb" ]; then
+ addsec $tmp "$dtb" dtb
+fi
+
+if [ "$platform" != "miboot" ]; then
+ ${CROSS}ld -m elf32ppc -T $lds -o "$ofile" \
+ $object/crt0.o $platformo $tmp $object/wrapper.a
+ rm $tmp
+fi
+
+# post-processing needed for some platforms
+case "$platform" in
+pseries|chrp)
+ $object/addnote "$ofile"
+ ;;
+pmaccoff)
+ ${CROSS}objcopy -O aixcoff-rs6000 --set-start 0x500000 "$ofile"
+ $object/hack-coff "$ofile"
+ ;;
+esac
diff --git a/arch/powerpc/boot/zImage.coff.lds b/arch/powerpc/boot/zImage.coff.lds.S
index 6016251a1a2c..05f32388b953 100644
--- a/arch/powerpc/boot/zImage.coff.lds
+++ b/arch/powerpc/boot/zImage.coff.lds.S
@@ -15,6 +15,7 @@ SECTIONS
{
*(.rodata*)
*(.data*)
+ *(__builtin_*)
*(.sdata*)
__got2_start = .;
*(.got2)
diff --git a/arch/powerpc/boot/zImage.lds b/arch/powerpc/boot/zImage.lds.S
index 4b6bb3ffe3dc..4b6bb3ffe3dc 100644
--- a/arch/powerpc/boot/zImage.lds
+++ b/arch/powerpc/boot/zImage.lds.S
diff --git a/arch/powerpc/configs/cell_defconfig b/arch/powerpc/configs/cell_defconfig
index 6fd9e7acec29..892d5dd3254e 100644
--- a/arch/powerpc/configs/cell_defconfig
+++ b/arch/powerpc/configs/cell_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:20:32 2006
+# Linux kernel version: 2.6.18
+# Wed Oct 4 15:30:50 2006
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -52,10 +53,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -63,7 +65,9 @@ CONFIG_CPUSETS=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -72,12 +76,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -96,6 +100,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -115,12 +120,13 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# Platform support
#
CONFIG_PPC_MULTIPLATFORM=y
-# CONFIG_PPC_ISERIES is not set
# CONFIG_EMBEDDED6xx is not set
# CONFIG_APUS is not set
# CONFIG_PPC_PSERIES is not set
+# CONFIG_PPC_ISERIES is not set
# CONFIG_PPC_PMAC is not set
# CONFIG_PPC_MAPLE is not set
+# CONFIG_PPC_PASEMI is not set
CONFIG_PPC_CELL=y
CONFIG_PPC_CELL_NATIVE=y
CONFIG_PPC_IBM_CELL_BLADE=y
@@ -142,7 +148,6 @@ CONFIG_MMIO_NVRAM=y
#
CONFIG_SPU_FS=m
CONFIG_SPU_BASE=y
-CONFIG_SPUFS_MMAP=y
CONFIG_CBE_RAS=y
#
@@ -158,7 +163,7 @@ CONFIG_PREEMPT_NONE=y
CONFIG_PREEMPT_BKL=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
-CONFIG_FORCE_MAX_ZONEORDER=13
+CONFIG_FORCE_MAX_ZONEORDER=9
# CONFIG_IOMMU_VMERGE is not set
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
CONFIG_KEXEC=y
@@ -168,6 +173,7 @@ CONFIG_NUMA=y
CONFIG_NODES_SHIFT=4
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
# CONFIG_FLATMEM_MANUAL is not set
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -178,12 +184,12 @@ CONFIG_HAVE_MEMORY_PRESENT=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPARSEMEM_EXTREME=y
CONFIG_MEMORY_HOTPLUG=y
+CONFIG_MEMORY_HOTPLUG_SPARSE=y
CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
CONFIG_RESOURCES_64BIT=y
-CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
CONFIG_ARCH_MEMORY_PROBE=y
-# CONFIG_PPC_64K_PAGES is not set
+CONFIG_PPC_64K_PAGES=y
CONFIG_SCHED_SMT=y
CONFIG_PROC_DEVICETREE=y
# CONFIG_CMDLINE_BOOL is not set
@@ -201,6 +207,7 @@ CONFIG_GENERIC_ISA_DMA=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
CONFIG_PCIEPORTBUS=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -228,6 +235,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -249,7 +257,8 @@ CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
#
# IP: Virtual Server Configuration
@@ -261,11 +270,15 @@ CONFIG_IPV6=y
CONFIG_INET6_AH=m
CONFIG_INET6_ESP=m
CONFIG_INET6_IPCOMP=m
+# CONFIG_IPV6_MIP6 is not set
CONFIG_INET6_XFRM_TUNNEL=m
CONFIG_INET6_TUNNEL=m
CONFIG_INET6_XFRM_MODE_TRANSPORT=y
CONFIG_INET6_XFRM_MODE_TUNNEL=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
CONFIG_NETFILTER=y
# CONFIG_NETFILTER_DEBUG is not set
@@ -322,7 +335,6 @@ CONFIG_IP_NF_QUEUE=m
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -434,6 +446,7 @@ CONFIG_BLK_DEV_AEC62XX=y
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_IT821X is not set
@@ -456,6 +469,12 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -470,6 +489,7 @@ CONFIG_MD_RAID1=m
# CONFIG_MD_MULTIPATH is not set
# CONFIG_MD_FAULTY is not set
CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
@@ -504,7 +524,7 @@ CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
CONFIG_BONDING=y
# CONFIG_EQUALIZER is not set
-# CONFIG_TUN is not set
+CONFIG_TUN=y
#
# ARCnet devices
@@ -552,7 +572,7 @@ CONFIG_SKGE=m
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
CONFIG_SPIDER_NET=m
-# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -599,6 +619,7 @@ CONFIG_SPIDER_NET=m
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -865,6 +886,7 @@ CONFIG_INFINIBAND_USER_ACCESS=m
CONFIG_INFINIBAND_ADDR_TRANS=y
CONFIG_INFINIBAND_MTHCA=m
CONFIG_INFINIBAND_MTHCA_DEBUG=y
+# CONFIG_INFINIBAND_AMSO1100 is not set
CONFIG_INFINIBAND_IPOIB=m
CONFIG_INFINIBAND_IPOIB_DEBUG=y
CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
@@ -916,7 +938,7 @@ CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
+CONFIG_AUTOFS4_FS=m
# CONFIG_FUSE_FS is not set
#
@@ -943,8 +965,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
@@ -1084,6 +1108,7 @@ CONFIG_PLIST=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
@@ -1102,6 +1127,7 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
# CONFIG_FORCED_INLINING is not set
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUG_STACKOVERFLOW is not set
@@ -1123,6 +1149,10 @@ CONFIG_IRQSTACKS=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+# CONFIG_CRYPTO_MANAGER is not set
CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -1132,6 +1162,8 @@ CONFIG_CRYPTO_SHA1=m
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=m
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/powerpc/configs/chrp32_defconfig b/arch/powerpc/configs/chrp32_defconfig
index bbf2b5f8a8cb..fee72f8a2fb7 100644
--- a/arch/powerpc/configs/chrp32_defconfig
+++ b/arch/powerpc/configs/chrp32_defconfig
@@ -492,7 +492,7 @@ CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
+# CONFIG_ATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
diff --git a/arch/powerpc/configs/g5_defconfig b/arch/powerpc/configs/g5_defconfig
index 4b9c2ed925f5..92d0a9dd0b8f 100644
--- a/arch/powerpc/configs/g5_defconfig
+++ b/arch/powerpc/configs/g5_defconfig
@@ -490,23 +490,23 @@ CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
-CONFIG_SCSI_SATA_SVW=y
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SVW=y
# CONFIG_SCSI_ATA_PIIX is not set
-# CONFIG_SCSI_SATA_MV is not set
-# CONFIG_SCSI_SATA_NV is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
# CONFIG_SCSI_PDC_ADMA is not set
# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_SATA_QSTOR is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
-# CONFIG_SCSI_SATA_SX4 is not set
-# CONFIG_SCSI_SATA_SIL is not set
-# CONFIG_SCSI_SATA_SIL24 is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_ULI is not set
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
diff --git a/arch/powerpc/configs/iseries_defconfig b/arch/powerpc/configs/iseries_defconfig
index eb0885ea0731..b5005506c2f8 100644
--- a/arch/powerpc/configs/iseries_defconfig
+++ b/arch/powerpc/configs/iseries_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:22:57 2006
+# Linux kernel version: 2.6.19-rc1
+# Fri Oct 6 13:25:04 2006
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_PPC_OF=y
# CONFIG_PPC_UDBG_16550 is not set
# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -52,10 +53,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
CONFIG_AUDIT=y
CONFIG_AUDITSYSCALL=y
CONFIG_IKCONFIG=y
@@ -64,7 +66,9 @@ CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -73,12 +77,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -97,6 +101,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -115,13 +120,18 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
#
# Platform support
#
-# CONFIG_PPC_MULTIPLATFORM is not set
-CONFIG_PPC_ISERIES=y
+CONFIG_PPC_MULTIPLATFORM=y
# CONFIG_EMBEDDED6xx is not set
# CONFIG_APUS is not set
+# CONFIG_PPC_PSERIES is not set
+CONFIG_PPC_ISERIES=y
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_MAPLE is not set
+# CONFIG_PPC_PASEMI is not set
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
-# CONFIG_UDBG_RTAS_CONSOLE is not set
+# CONFIG_PPC_IBM_CELL_BLADE is not set
+# CONFIG_U3_DART is not set
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
CONFIG_IBMVIO=y
@@ -147,12 +157,15 @@ CONFIG_BINFMT_ELF=y
CONFIG_FORCE_MAX_ZONEORDER=13
CONFIG_IOMMU_VMERGE=y
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
CONFIG_IRQ_ALL_CPUS=y
CONFIG_LPARCFG=y
# CONFIG_NUMA is not set
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -179,6 +192,7 @@ CONFIG_GENERIC_ISA_DMA=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -206,6 +220,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
+CONFIG_XFRM_SUB_POLICY=y
CONFIG_NET_KEY=m
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -224,10 +239,12 @@ CONFIG_INET_XFRM_TUNNEL=m
CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=m
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
#
# IP: Virtual Server Configuration
@@ -247,6 +264,7 @@ CONFIG_NETFILTER=y
CONFIG_NETFILTER_XTABLES=m
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+CONFIG_NETFILTER_XT_TARGET_DSCP=m
CONFIG_NETFILTER_XT_TARGET_MARK=m
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
@@ -255,6 +273,7 @@ CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+CONFIG_NETFILTER_XT_MATCH_DSCP=m
# CONFIG_NETFILTER_XT_MATCH_ESP is not set
CONFIG_NETFILTER_XT_MATCH_HELPER=m
CONFIG_NETFILTER_XT_MATCH_LENGTH=m
@@ -294,7 +313,6 @@ CONFIG_IP_NF_MATCH_IPRANGE=m
CONFIG_IP_NF_MATCH_TOS=m
CONFIG_IP_NF_MATCH_RECENT=m
CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_DSCP=m
# CONFIG_IP_NF_MATCH_AH is not set
CONFIG_IP_NF_MATCH_TTL=m
CONFIG_IP_NF_MATCH_OWNER=m
@@ -319,7 +337,6 @@ CONFIG_IP_NF_NAT_AMANDA=m
CONFIG_IP_NF_MANGLE=m
CONFIG_IP_NF_TARGET_TOS=m
CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_DSCP=m
CONFIG_IP_NF_TARGET_TTL=m
CONFIG_IP_NF_TARGET_CLUSTERIP=m
CONFIG_IP_NF_RAW=m
@@ -351,7 +368,6 @@ CONFIG_LLC=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -433,6 +449,7 @@ CONFIG_BLK_DEV_INITRD=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -454,12 +471,14 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
+CONFIG_SCSI_SAS_ATTRS=m
+CONFIG_SCSI_SAS_LIBSAS=m
+CONFIG_SCSI_SAS_LIBSAS_DEBUG=y
#
# SCSI low-level drivers
@@ -472,10 +491,11 @@ CONFIG_SCSI_FC_ATTRS=y
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -486,16 +506,22 @@ CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_IBMVSCSI=m
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
CONFIG_MD=y
@@ -508,6 +534,7 @@ CONFIG_MD_RAID10=m
CONFIG_MD_MULTIPATH=m
CONFIG_MD_FAULTY=m
CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
@@ -573,6 +600,7 @@ CONFIG_MII=y
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
CONFIG_PCNET32=y
+CONFIG_PCNET32_NAPI=y
# CONFIG_AMD8111_ETH is not set
# CONFIG_ADAPTEC_STARFIRE is not set
# CONFIG_B44 is not set
@@ -610,6 +638,7 @@ CONFIG_E1000=m
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -649,6 +678,7 @@ CONFIG_PPP_BSDCOMP=m
# CONFIG_PPP_MPPE is not set
CONFIG_PPPOE=m
# CONFIG_SLIP is not set
+CONFIG_SLHC=m
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
CONFIG_NETCONSOLE=y
@@ -671,6 +701,7 @@ CONFIG_NET_POLL_CONTROLLER=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -774,12 +805,12 @@ CONFIG_MAX_RAW_DEVS=256
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -893,6 +924,9 @@ CONFIG_XFS_FS=m
CONFIG_XFS_SECURITY=y
CONFIG_XFS_POSIX_ACL=y
# CONFIG_XFS_RT is not set
+CONFIG_GFS2_FS=m
+CONFIG_GFS2_FS_LOCKING_NOLOCK=m
+CONFIG_GFS2_FS_LOCKING_DLM=m
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -929,12 +963,14 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
-# CONFIG_CONFIGFS_FS is not set
+CONFIG_CONFIGFS_FS=m
#
# Miscellaneous filesystems
@@ -988,6 +1024,7 @@ CONFIG_CIFS_POSIX=y
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
# CONFIG_9P_FS is not set
+CONFIG_GENERIC_ACL=y
#
# Partition Types
@@ -1040,6 +1077,12 @@ CONFIG_NLS_ISO8859_1=y
# CONFIG_NLS_UTF8 is not set
#
+# Distributed Lock Manager
+#
+CONFIG_DLM=m
+# CONFIG_DLM_DEBUG is not set
+
+#
# iSeries device drivers
#
CONFIG_VIOCONS=y
@@ -1073,6 +1116,7 @@ CONFIG_PLIST=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
@@ -1091,6 +1135,7 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
# CONFIG_FORCED_INLINING is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_STACKOVERFLOW=y
@@ -1109,6 +1154,10 @@ CONFIG_IRQSTACKS=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_HMAC=y
CONFIG_CRYPTO_NULL=m
CONFIG_CRYPTO_MD4=m
@@ -1118,9 +1167,12 @@ CONFIG_CRYPTO_SHA256=m
CONFIG_CRYPTO_SHA512=m
CONFIG_CRYPTO_WP512=m
CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=y
CONFIG_CRYPTO_BLOWFISH=m
CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
CONFIG_CRYPTO_SERPENT=m
CONFIG_CRYPTO_AES=m
CONFIG_CRYPTO_CAST5=m
diff --git a/arch/powerpc/configs/maple_defconfig b/arch/powerpc/configs/maple_defconfig
index 62ba66091a13..ae96a5b2f00d 100644
--- a/arch/powerpc/configs/maple_defconfig
+++ b/arch/powerpc/configs/maple_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:24:55 2006
+# Linux kernel version: 2.6.18
+# Mon Oct 9 11:59:34 2006
#
CONFIG_PPC64=y
CONFIG_64BIT=y
@@ -22,6 +22,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
# CONFIG_DEFAULT_UIMAGE is not set
#
@@ -34,7 +35,7 @@ CONFIG_PPC_FPU=y
CONFIG_PPC_STD_MMU=y
CONFIG_VIRT_CPU_ACCOUNTING=y
CONFIG_SMP=y
-CONFIG_NR_CPUS=2
+CONFIG_NR_CPUS=4
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -51,10 +52,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -62,7 +64,9 @@ CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -71,12 +75,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -95,6 +99,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -114,16 +119,16 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# Platform support
#
CONFIG_PPC_MULTIPLATFORM=y
-# CONFIG_PPC_ISERIES is not set
# CONFIG_EMBEDDED6xx is not set
# CONFIG_APUS is not set
# CONFIG_PPC_PSERIES is not set
+# CONFIG_PPC_ISERIES is not set
# CONFIG_PPC_PMAC is not set
CONFIG_PPC_MAPLE=y
+# CONFIG_PPC_PASEMI is not set
# CONFIG_PPC_CELL is not set
# CONFIG_PPC_CELL_NATIVE is not set
# CONFIG_PPC_IBM_CELL_BLADE is not set
-# CONFIG_UDBG_RTAS_CONSOLE is not set
CONFIG_U3_DART=y
# CONFIG_PPC_RTAS is not set
# CONFIG_MMIO_NVRAM is not set
@@ -157,6 +162,7 @@ CONFIG_IRQ_ALL_CPUS=y
CONFIG_ARCH_SELECT_MEMORY_MODEL=y
CONFIG_ARCH_FLATMEM_ENABLE=y
CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -184,6 +190,7 @@ CONFIG_GENERIC_ISA_DMA=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
# CONFIG_PCIEPORTBUS is not set
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
#
@@ -211,6 +218,7 @@ CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -232,10 +240,12 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
@@ -265,7 +275,6 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -377,6 +386,7 @@ CONFIG_BLK_DEV_AMD74XX=y
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_IT821X is not set
@@ -399,6 +409,12 @@ CONFIG_IDEDMA_AUTO=y
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -498,7 +514,7 @@ CONFIG_E1000=y
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=y
# CONFIG_BNX2 is not set
-# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -545,6 +561,7 @@ CONFIG_TIGON3=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -704,6 +721,7 @@ CONFIG_I2C_AMD8111=y
#
# Misc devices
#
+# CONFIG_TIFM_CORE is not set
#
# Multimedia devices
@@ -779,7 +797,6 @@ CONFIG_USB_UHCI_HCD=y
#
# may also be needed; see USB_STORAGE Help for more information
#
-# CONFIG_USB_STORAGE is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -802,6 +819,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_ATI_REMOTE2 is not set
# CONFIG_USB_KEYSPAN_REMOTE is not set
# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
#
# USB Imaging devices
@@ -828,6 +846,7 @@ CONFIG_USB_MON=y
CONFIG_USB_SERIAL=y
# CONFIG_USB_SERIAL_CONSOLE is not set
CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
# CONFIG_USB_SERIAL_AIRPRIME is not set
# CONFIG_USB_SERIAL_ARK3116 is not set
# CONFIG_USB_SERIAL_BELKIN is not set
@@ -862,6 +881,7 @@ CONFIG_USB_SERIAL_KEYSPAN_USA49WLC=y
# CONFIG_USB_SERIAL_KLSI is not set
# CONFIG_USB_SERIAL_KOBIL_SCT is not set
# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
# CONFIG_USB_SERIAL_NAVMAN is not set
# CONFIG_USB_SERIAL_PL2303 is not set
# CONFIG_USB_SERIAL_HP4X is not set
@@ -879,6 +899,7 @@ CONFIG_USB_EZUSB=y
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
@@ -886,9 +907,9 @@ CONFIG_USB_EZUSB=y
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
@@ -995,8 +1016,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
@@ -1129,6 +1152,7 @@ CONFIG_PLIST=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
@@ -1148,6 +1172,7 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
# CONFIG_FORCED_INLINING is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_DEBUG_STACKOVERFLOW=y
@@ -1169,6 +1194,9 @@ CONFIG_BOOTX_TEXT=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -1178,6 +1206,8 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/powerpc/configs/mpc7448_hpc2_defconfig b/arch/powerpc/configs/mpc7448_hpc2_defconfig
index 719fba4eb421..d1811e754518 100644
--- a/arch/powerpc/configs/mpc7448_hpc2_defconfig
+++ b/arch/powerpc/configs/mpc7448_hpc2_defconfig
@@ -413,23 +413,23 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
-# CONFIG_SCSI_SATA_SVW is not set
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
# CONFIG_SCSI_ATA_PIIX is not set
-CONFIG_SCSI_SATA_MV=y
-# CONFIG_SCSI_SATA_NV is not set
+CONFIG_SATA_MV=y
+# CONFIG_SATA_NV is not set
# CONFIG_SCSI_PDC_ADMA is not set
# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_SATA_QSTOR is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
-# CONFIG_SCSI_SATA_SX4 is not set
-# CONFIG_SCSI_SATA_SIL is not set
-# CONFIG_SCSI_SATA_SIL24 is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_ULI is not set
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
diff --git a/arch/powerpc/configs/mpc834x_itx_defconfig b/arch/powerpc/configs/mpc834x_itx_defconfig
index 8da6a47f0339..0561b73a918f 100644
--- a/arch/powerpc/configs/mpc834x_itx_defconfig
+++ b/arch/powerpc/configs/mpc834x_itx_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc6
-# Sun Sep 10 10:28:05 2006
+# Linux kernel version: 2.6.18
+# Mon Sep 25 19:41:14 2006
#
# CONFIG_PPC64 is not set
CONFIG_PPC32=y
@@ -21,6 +21,7 @@ CONFIG_ARCH_MAY_HAVE_PC_FDC=y
CONFIG_PPC_OF=y
CONFIG_PPC_UDBG_16550=y
# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
CONFIG_DEFAULT_UIMAGE=y
#
@@ -61,25 +62,25 @@ CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EMBEDDED=y
+CONFIG_SYSCTL=y
# CONFIG_KALLSYMS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
# CONFIG_EPOLL is not set
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -259,7 +260,6 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -313,6 +313,7 @@ CONFIG_MTD_CHAR=y
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
#
# RAM/ROM/Flash chip drivers
@@ -464,23 +465,23 @@ CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
-# CONFIG_SCSI_SATA_SVW is not set
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SVW is not set
# CONFIG_SCSI_ATA_PIIX is not set
-# CONFIG_SCSI_SATA_MV is not set
-# CONFIG_SCSI_SATA_NV is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
# CONFIG_SCSI_PDC_ADMA is not set
# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_SATA_QSTOR is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
-# CONFIG_SCSI_SATA_SX4 is not set
-CONFIG_SCSI_SATA_SIL=y
-# CONFIG_SCSI_SATA_SIL24 is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_ULI is not set
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+CONFIG_SATA_SIL=y
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
@@ -1247,7 +1248,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
-# CONFIG_MSDOS_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
# CONFIG_LDM_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
@@ -1277,11 +1278,11 @@ CONFIG_PLIST=y
#
# Kernel hacking
#
-CONFIG_PRINTK_TIME=y
+# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
-CONFIG_LOG_BUF_SHIFT=17
+CONFIG_LOG_BUF_SHIFT=14
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
@@ -1293,15 +1294,15 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_FS is not set
# CONFIG_DEBUG_VM is not set
CONFIG_FORCED_INLINING=y
# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_DEBUGGER is not set
# CONFIG_BDI_SWITCH is not set
-CONFIG_BOOTX_TEXT=y
-CONFIG_SERIAL_TEXT_DEBUG=y
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
# CONFIG_PPC_EARLY_DEBUG is not set
#
@@ -1314,6 +1315,8 @@ CONFIG_SERIAL_TEXT_DEBUG=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+# CONFIG_CRYPTO_MANAGER is not set
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -1323,6 +1326,8 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_CBC is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/arm/configs/iq80331_defconfig b/arch/powerpc/configs/mpc8360emds_defconfig
index 46c79e1efe07..c0703415d608 100644
--- a/arch/arm/configs/iq80331_defconfig
+++ b/arch/powerpc/configs/mpc8360emds_defconfig
@@ -1,50 +1,89 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 15:13:37 2005
+# Linux kernel version: 2.6.18
+# Thu Sep 21 18:14:27 2006
#
-CONFIG_ARM=y
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
CONFIG_MMU=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+CONFIG_PPC_83xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_6xx=y
+CONFIG_83xx=y
+CONFIG_PPC_FPU=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_SMP is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL=y
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_EPOLL is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -52,120 +91,192 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
+# CONFIG_KMOD is not set
#
-# System Type
+# Block layer
#
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-CONFIG_ARCH_IOP3XX=y
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_RPC is not set
-# CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
#
-# IOP3xx Implementation Options
+# IO Schedulers
#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_QUICC_ENGINE=y
+CONFIG_PPC_GEN550=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC834x_SYS is not set
+# CONFIG_MPC834x_ITX is not set
+CONFIG_MPC8360E_PB=y
+CONFIG_PPC_MPC836x=y
+# CONFIG_MPIC is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
#
-# IOP3xx Platform Types
+# Bus options
#
-# CONFIG_ARCH_IQ80321 is not set
-# CONFIG_ARCH_IQ31244 is not set
-CONFIG_ARCH_IQ80331=y
-# CONFIG_MACH_IQ80332 is not set
-# CONFIG_ARCH_EP80219 is not set
-CONFIG_ARCH_IOP331=y
+CONFIG_GENERIC_ISA_DMA=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
#
-# IOP3xx Chipset Features
+# PCCARD (PCMCIA/CardBus) support
#
-CONFIG_IOP331_STEPD=y
+# CONFIG_PCCARD is not set
#
-# Processor Type
+# PCI Hotplug Support
#
-CONFIG_CPU_32=y
-CONFIG_CPU_XSCALE=y
-CONFIG_CPU_32v5=y
-CONFIG_CPU_ABRT_EV5T=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
+# CONFIG_HOTPLUG_PCI is not set
#
-# Processor Features
+# Advanced setup
#
-# CONFIG_ARM_THUMB is not set
-CONFIG_XSCALE_PMU=y
+# CONFIG_ADVANCED_OPTIONS is not set
#
-# Bus support
+# Default settings for advanced configuration options are used
#
-CONFIG_PCI=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
#
-# PCCARD (PCMCIA/CardBus) support
+# Networking
#
-# CONFIG_PCCARD is not set
+CONFIG_NET=y
#
-# Kernel Features
+# Networking options
#
-# CONFIG_PREEMPT is not set
-CONFIG_ALIGNMENT_TRAP=y
+# 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_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
#
-# Boot options
+# DCCP Configuration (EXPERIMENTAL)
#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="ip=boot root=nfs console=ttyS0,115200"
-# CONFIG_XIP_KERNEL is not set
+# CONFIG_IP_DCCP is not set
#
-# Floating point emulation
+# SCTP Configuration (EXPERIMENTAL)
#
+# CONFIG_IP_SCTP is not set
#
-# At least one emulation must be selected
+# TIPC Configuration (EXPERIMENTAL)
#
-CONFIG_FPE_NWFPE=y
-# CONFIG_FPE_NWFPE_XP is not set
-# CONFIG_FPE_FASTFPE is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
#
-# Userspace binary formats
+# QoS and/or fair queueing
#
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
+# CONFIG_NET_SCHED is not set
#
-# Power management options
+# Network testing
#
-# CONFIG_PM is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -177,92 +288,17 @@ CONFIG_BINFMT_AOUT=y
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
#
-# Memory Technology Devices (MTD)
-#
-CONFIG_MTD=y
-# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_REDBOOT_PARTS=y
-CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-1
-CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
-CONFIG_MTD_REDBOOT_PARTS_READONLY=y
-# CONFIG_MTD_CMDLINE_PARTS is not set
-# CONFIG_MTD_AFS_PARTS is not set
-
-#
-# User Modules And Translation Layers
-#
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-# CONFIG_FTL is not set
-# CONFIG_NFTL is not set
-# CONFIG_INFTL is not set
-
-#
-# RAM/ROM/Flash chip drivers
-#
-CONFIG_MTD_CFI=y
-# CONFIG_MTD_JEDECPROBE is not set
-CONFIG_MTD_GEN_PROBE=y
-CONFIG_MTD_CFI_ADV_OPTIONS=y
-CONFIG_MTD_CFI_NOSWAP=y
-# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
-# CONFIG_MTD_CFI_GEOMETRY is not set
-CONFIG_MTD_MAP_BANK_WIDTH_1=y
-CONFIG_MTD_MAP_BANK_WIDTH_2=y
-CONFIG_MTD_MAP_BANK_WIDTH_4=y
-# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
-# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
-CONFIG_MTD_CFI_I1=y
-CONFIG_MTD_CFI_I2=y
-# CONFIG_MTD_CFI_I4 is not set
-# CONFIG_MTD_CFI_I8 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_CFI_STAA is not set
-CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_ABSENT is not set
-# CONFIG_MTD_XIP is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0xc0000000
-CONFIG_MTD_PHYSMAP_LEN=0x00800000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=1
-# CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_EDB7312 is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_PHRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
-# CONFIG_MTD_BLOCK2MTD is not set
-
-#
-# Disk-On-Chip Device Drivers
+# Connector - unified userspace <-> kernelspace linker
#
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_CONNECTOR is not set
#
-# NAND Flash Device Drivers
+# Memory Technology Devices (MTD)
#
-# CONFIG_MTD_NAND is not set
+# CONFIG_MTD is not set
#
# Parallel port support
@@ -282,23 +318,16 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=1
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=8192
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_INITRAMFS_SOURCE=""
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -309,17 +338,19 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
CONFIG_SCSI_PROC_FS=y
#
# SCSI support type (disk, tape, CD-ROM)
#
-CONFIG_BLK_DEV_SD=y
+# CONFIG_BLK_DEV_SD is not set
# CONFIG_CHR_DEV_ST is not set
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
-CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -334,10 +365,12 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -348,7 +381,9 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_DPT_I2O is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
# CONFIG_SCSI_SATA is not set
+# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
@@ -359,14 +394,9 @@ CONFIG_CHR_DEV_SG=y
# CONFIG_SCSI_INIA100 is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
@@ -375,27 +405,15 @@ CONFIG_SCSI_QLA2XXX=y
#
# Multi-device support (RAID and LVM)
#
-CONFIG_MD=y
-CONFIG_BLK_DEV_MD=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_RAID0=y
-CONFIG_MD_RAID1=y
-# CONFIG_MD_RAID10 is not set
-CONFIG_MD_RAID5=y
-# CONFIG_MD_RAID6 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_MD_FAULTY is not set
-CONFIG_BLK_DEV_DM=y
-# CONFIG_DM_CRYPT is not set
-# CONFIG_DM_SNAPSHOT is not set
-# CONFIG_DM_MIRROR is not set
-# CONFIG_DM_ZERO is not set
-# CONFIG_DM_MULTIPATH is not set
+# CONFIG_MD is not set
#
# Fusion MPT device support
#
# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
@@ -408,71 +426,13 @@ CONFIG_BLK_DEV_DM=y
# CONFIG_I2O is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
+# Macintosh device drivers
#
-CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
+# CONFIG_WINDFARM is not set
#
-# SCTP Configuration (EXPERIMENTAL)
+# Network device support
#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -485,30 +445,57 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
-# CONFIG_NET_ETHERNET is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_PCI is not set
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
-CONFIG_E1000=y
-CONFIG_E1000_NAPI=y
-# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_E1000 is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_GIANFAR is not set
+CONFIG_UCC_GETH=y
+# CONFIG_UGETH_NAPI is not set
+# CONFIG_UGETH_MAGIC_PACKET is not set
+# CONFIG_UGETH_FILTERING is not set
+# CONFIG_UGETH_TX_ON_DEMOND is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -531,6 +518,8 @@ CONFIG_E1000_NAPI=y
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -538,6 +527,11 @@ CONFIG_E1000_NAPI=y
# CONFIG_ISDN is not set
#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
# Input device support
#
CONFIG_INPUT=y
@@ -545,10 +539,7 @@ CONFIG_INPUT=y
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
@@ -568,14 +559,11 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
+# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -583,7 +571,9 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
@@ -591,6 +581,7 @@ CONFIG_SERIAL_8250_NR_UARTS=4
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -603,9 +594,24 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Watchdog Cards
#
-# CONFIG_WATCHDOG is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_83xx_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+CONFIG_HW_RANDOM=y
# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -613,6 +619,7 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Ftape, the floppy tape device driver
#
+# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -620,6 +627,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# TPM devices
#
# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -644,14 +652,13 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
-CONFIG_I2C_IOP3XX=y
-# CONFIG_I2C_ISA is not set
+# CONFIG_I2C_PIIX4 is not set
+CONFIG_I2C_MPC=y
# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_OCORES is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
-# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
@@ -662,15 +669,46 @@ CONFIG_I2C_IOP3XX=y
# CONFIG_I2C_PCA_ISA is not set
#
-# Hardware Sensors Chip support
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_M41T00 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
#
-# CONFIG_I2C_SENSOR is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
# CONFIG_SENSORS_ADM1021 is not set
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
# CONFIG_SENSORS_GL518SM is not set
@@ -685,27 +723,22 @@ CONFIG_I2C_IOP3XX=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
-# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_SIS5595 is not set
# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
-
-#
-# Other I2C Chip support
-#
-# CONFIG_SENSORS_EEPROM is not set
-# CONFIG_SENSORS_PCF8574 is not set
-# CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_SENSORS_RTC8564 is not set
-# CONFIG_I2C_DEBUG_CORE is not set
-# CONFIG_I2C_DEBUG_ALGO is not set
-# CONFIG_I2C_DEBUG_BUS is not set
-# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -715,6 +748,7 @@ CONFIG_I2C_IOP3XX=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -724,13 +758,9 @@ CONFIG_I2C_IOP3XX=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -742,9 +772,14 @@ CONFIG_DUMMY_CONSOLE=y
#
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
# CONFIG_USB is not set
#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -755,10 +790,51 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -768,22 +844,18 @@ CONFIG_JBD=y
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
-CONFIG_XFS_FS=y
-CONFIG_XFS_EXPORT=y
-# CONFIG_XFS_RT is not set
-# CONFIG_XFS_QUOTA is not set
-CONFIG_XFS_SECURITY=y
-CONFIG_XFS_POSIX_ACL=y
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -802,13 +874,12 @@ CONFIG_DNOTIFY=y
# Pseudo filesystems
#
CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -820,8 +891,6 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
@@ -834,24 +903,24 @@ CONFIG_RAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
-# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
# CONFIG_NFS_DIRECTIO is not set
-CONFIG_NFSD=y
-CONFIG_NFSD_V3=y
-# CONFIG_NFSD_V4 is not set
-# CONFIG_NFSD_TCP is not set
+# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
-CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -862,15 +931,12 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_AMIGA_PARTITION is not set
# CONFIG_ATARI_PARTITION is not set
# CONFIG_MAC_PARTITION is not set
-CONFIG_MSDOS_PARTITION=y
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MINIX_SUBPARTITION is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_MSDOS_PARTITION is not set
# CONFIG_LDM_PARTITION is not set
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
#
@@ -879,7 +945,23 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
-# Profiling support
+# QE Options
+#
+# CONFIG_UCC_SLOW is not set
+CONFIG_UCC_FAST=y
+CONFIG_UCC=y
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+
+#
+# Instrumentation Support
#
# CONFIG_PROFILING is not set
@@ -887,11 +969,14 @@ CONFIG_MSDOS_PARTITION=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_FS is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_SERIAL_TEXT_DEBUG is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
#
# Security options
@@ -902,15 +987,32 @@ CONFIG_DEBUG_USER=y
#
# Cryptographic options
#
-# CONFIG_CRYPTO is not set
+CONFIG_CRYPTO=y
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
#
# Hardware crypto devices
#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC32 is not set
-# CONFIG_LIBCRC32C is not set
diff --git a/arch/mips/configs/ivr_defconfig b/arch/powerpc/configs/mpc8560_ads_defconfig
index cebc67212d06..ddc2a7b07ba0 100644
--- a/arch/mips/configs/ivr_defconfig
+++ b/arch/powerpc/configs/mpc8560_ads_defconfig
@@ -1,150 +1,47 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:12 2006
-#
-CONFIG_MIPS=y
-
-#
-# Machine selection
-#
-# CONFIG_MIPS_MTX1 is not set
-# CONFIG_MIPS_BOSPORUS is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1100 is not set
-# CONFIG_MIPS_PB1500 is not set
-# CONFIG_MIPS_PB1550 is not set
-# CONFIG_MIPS_PB1200 is not set
-# CONFIG_MIPS_DB1000 is not set
-# CONFIG_MIPS_DB1100 is not set
-# CONFIG_MIPS_DB1500 is not set
-# CONFIG_MIPS_DB1550 is not set
-# CONFIG_MIPS_DB1200 is not set
-# CONFIG_MIPS_MIRAGE is not set
-# CONFIG_BASLER_EXCITE is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_MACH_DECSTATION is not set
-# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-CONFIG_MIPS_IVR=y
-# CONFIG_MIPS_ITE8172 is not set
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_LASAT is not set
-# CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_SEAD is not set
-# CONFIG_WR_PPMC is not set
-# CONFIG_MIPS_SIM is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_3 is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MIPS_XXS1500 is not set
-# CONFIG_PNX8550_V2PCI is not set
-# CONFIG_PNX8550_JBS is not set
-# CONFIG_DDB5477 is not set
-# CONFIG_MACH_VR41XX is not set
-# CONFIG_PMC_YOSEMITE is not set
-# CONFIG_QEMU is not set
-# CONFIG_MARKEINS is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_BIGSUR is not set
-# CONFIG_SIBYTE_SWARM is not set
-# CONFIG_SIBYTE_SENTOSA is not set
-# CONFIG_SIBYTE_RHONE is not set
-# CONFIG_SIBYTE_CARMEL is not set
-# CONFIG_SIBYTE_PTSWARM is not set
-# CONFIG_SIBYTE_LITTLESUR is not set
-# CONFIG_SIBYTE_CRHINE is not set
-# CONFIG_SIBYTE_CRHONE is not set
-# CONFIG_SNI_RM200_PCI is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
-# CONFIG_TOSHIBA_RBTX4938 is not set
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_FIND_NEXT_BIT=y
+# Linux kernel version: 2.6.18-rc4
+# Fri Aug 11 16:45:05 2006
+#
+# CONFIG_PPC64 is not set
+CONFIG_PPC32=y
+CONFIG_PPC_MERGE=y
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_IRQ_PER_CPU=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-# CONFIG_CPU_BIG_ENDIAN is not set
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
-CONFIG_ITE_BOARD_GEN=y
-CONFIG_IT8172_CIR=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-
-#
-# CPU selection
-#
-# CONFIG_CPU_MIPS32_R1 is not set
-# CONFIG_CPU_MIPS32_R2 is not set
-# CONFIG_CPU_MIPS64_R1 is not set
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_VR41XX is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R6000 is not set
-CONFIG_CPU_NEVADA=y
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
-# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_NEVADA=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
-
-#
-# Kernel type
-#
-CONFIG_32BIT=y
-# CONFIG_64BIT is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMTC is not set
-# CONFIG_MIPS_MT_SMP is not set
-# CONFIG_MIPS_VPE_LOADER is not set
-CONFIG_CPU_HAS_LLSC=y
-CONFIG_CPU_HAS_SYNC=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-# CONFIG_HZ_48 is not set
-# CONFIG_HZ_100 is not set
-# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_256 is not set
-CONFIG_HZ_1000=y
-# CONFIG_HZ_1024 is not set
-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=1000
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_DEFAULT_UIMAGE=y
+
+#
+# Processor support
+#
+# CONFIG_CLASSIC32 is not set
+# CONFIG_PPC_52xx is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_86xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_8xx is not set
+# CONFIG_E200 is not set
+CONFIG_85xx=y
+CONFIG_E500=y
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -162,16 +59,17 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
-CONFIG_RELAY=y
+# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
@@ -191,12 +89,7 @@ CONFIG_BASE_SMALL=0
#
# Loadable module support
#
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
+# CONFIG_MODULES is not set
#
# Block layer
@@ -217,13 +110,62 @@ CONFIG_DEFAULT_AS=y
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_MPIC=y
+CONFIG_CPM2=y
+# CONFIG_WANT_EARLY_SERIAL is not set
+
+#
+# Platform support
+#
+# CONFIG_MPC8540_ADS is not set
+CONFIG_MPC8560_ADS=y
+# CONFIG_MPC85xx_CDS is not set
+CONFIG_MPC8560=y
+CONFIG_PPC_INDIRECT_PCI_BE=y
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+# CONFIG_MATH_EMULATION is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+# CONFIG_PC_KEYBOARD is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PROC_DEVICETREE is not set
+# CONFIG_CMDLINE_BOOL is not set
+# CONFIG_PM is not set
+# CONFIG_SOFTWARE_SUSPEND is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
#
-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+# Bus options
#
-CONFIG_HW_HAS_PCI=y
+# CONFIG_PPC_I8259 is not set
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
CONFIG_PCI=y
-CONFIG_MMU=y
+CONFIG_PCI_DOMAINS=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_PCI_DEBUG=y
#
# PCCARD (PCMCIA/CardBus) support
@@ -236,11 +178,18 @@ CONFIG_MMU=y
# CONFIG_HOTPLUG_PCI is not set
#
-# Executable file formats
+# Advanced setup
#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_BOOT_LOAD=0x00800000
#
# Networking
@@ -252,30 +201,31 @@ CONFIG_NET=y
#
# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
-CONFIG_PACKET_MMAP=y
+# CONFIG_PACKET_MMAP is not set
CONFIG_UNIX=y
CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-CONFIG_NET_KEY=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_NET_KEY is not set
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -283,7 +233,7 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
-CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -325,13 +275,7 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_SOFTMAC=m
-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
-CONFIG_WIRELESS_EXT=y
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -342,13 +286,14 @@ CONFIG_WIRELESS_EXT=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-CONFIG_FW_LOADER=m
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
#
-CONFIG_CONNECTOR=m
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -367,52 +312,33 @@ CONFIG_CONNECTOR=m
#
# Block devices
#
+# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-CONFIG_ATA_OVER_ETH=m
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=32768
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_BLK_DEV_IDEPCI is not set
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_IDE is not set
#
# SCSI device support
#
-CONFIG_RAID_ATTRS=m
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
#
@@ -436,6 +362,11 @@ CONFIG_RAID_ATTRS=m
# CONFIG_I2O is not set
#
+# Macintosh device drivers
+#
+# CONFIG_WINDFARM is not set
+
+#
# Network device support
#
CONFIG_NETDEVICES=y
@@ -452,29 +383,29 @@ CONFIG_NETDEVICES=y
#
# PHY device support
#
-CONFIG_PHYLIB=m
+CONFIG_PHYLIB=y
#
# MII PHY device drivers
#
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
+CONFIG_MARVELL_PHY=y
+CONFIG_DAVICOM_PHY=y
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_FIXED_PHY is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_DM9000 is not set
#
# Tulip family network device support
@@ -482,13 +413,18 @@ CONFIG_NET_ETHERNET=y
# CONFIG_NET_TULIP is not set
# CONFIG_HP100 is not set
# CONFIG_NET_PCI is not set
+CONFIG_FS_ENET=y
+# CONFIG_FS_ENET_HAS_SCC is not set
+CONFIG_FS_ENET_HAS_FCC=y
#
# Ethernet (1000 Mbit)
#
# CONFIG_ACENIC is not set
# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
+CONFIG_E1000=y
+CONFIG_E1000_NAPI=y
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
# CONFIG_NS83820 is not set
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
@@ -499,6 +435,8 @@ CONFIG_NET_ETHERNET=y
# CONFIG_SK98LIN is not set
# CONFIG_TIGON3 is not set
# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+CONFIG_GFAR_NAPI=y
#
# Ethernet (10000 Mbit)
@@ -549,10 +487,7 @@ CONFIG_INPUT=y
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
@@ -570,45 +505,38 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# Hardware I/O ports
#
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-CONFIG_SERIO_RAW=m
+# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
-CONFIG_QTRONIX_KEYBOARD=y
-CONFIG_IT8172_SCR0=y
-CONFIG_IT8172_SCR1=y
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_PCI=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+CONFIG_SERIAL_CPM_SCC1=y
+CONFIG_SERIAL_CPM_SCC2=y
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+# CONFIG_SERIAL_CPM_SMC1 is not set
+# CONFIG_SERIAL_CPM_SMC2 is not set
# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_BRIQ_PANEL is not set
#
# IPMI
@@ -619,8 +547,10 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_RTC=y
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+CONFIG_GEN_RTC=y
+# CONFIG_GEN_RTC_X is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
# CONFIG_APPLICOM is not set
@@ -628,6 +558,7 @@ CONFIG_RTC=y
#
# Ftape, the floppy tape device driver
#
+# CONFIG_AGP is not set
# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
@@ -651,13 +582,15 @@ CONFIG_RTC=y
#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
#
# Hardware Monitoring support
#
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -677,14 +610,9 @@ CONFIG_VIDEO_V4L2=y
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -759,7 +687,13 @@ CONFIG_USB_ARCH_HAS_EHCI=y
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
-# CONFIG_EXT3_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
@@ -773,7 +707,7 @@ CONFIG_INOTIFY_USER=y
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=m
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -794,7 +728,7 @@ CONFIG_FUSE_FS=m
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -832,7 +766,6 @@ CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -841,8 +774,19 @@ CONFIG_SUNRPC=y
#
# Partition Types
#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+# CONFIG_MSDOS_PARTITION is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
#
# Native Language Support
@@ -850,7 +794,16 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_NLS is not set
#
-# Profiling support
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+
+#
+# Instrumentation Support
#
# CONFIG_PROFILING is not set
@@ -860,59 +813,42 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_PRINTK_TIME is not set
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
-# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS 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 is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_FS is not set
-CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE=""
+# CONFIG_DEBUG_VM is not set
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUGGER is not set
+# CONFIG_KGDB_CONSOLE is not set
+# CONFIG_BDI_SWITCH is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
#
# Security options
#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_CRC32C=m
-# CONFIG_CRYPTO_TEST is not set
+# CONFIG_CRYPTO is not set
#
# Hardware crypto devices
#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=m
-CONFIG_CRC32=m
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=m
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
diff --git a/arch/powerpc/configs/pmac32_defconfig b/arch/powerpc/configs/pmac32_defconfig
index 6861dde7d77b..765c8bb90ddd 100644
--- a/arch/powerpc/configs/pmac32_defconfig
+++ b/arch/powerpc/configs/pmac32_defconfig
@@ -682,7 +682,7 @@ CONFIG_SCSI_AIC7XXX_OLD=m
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
+# CONFIG_ATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
@@ -1826,7 +1826,7 @@ CONFIG_OPROFILE=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig
index 7517d0c5303f..be11df7c11aa 100644
--- a/arch/powerpc/configs/ppc64_defconfig
+++ b/arch/powerpc/configs/ppc64_defconfig
@@ -520,23 +520,23 @@ CONFIG_SCSI_ISCSI_ATTRS=m
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-CONFIG_SCSI_SATA=y
-# CONFIG_SCSI_SATA_AHCI is not set
-CONFIG_SCSI_SATA_SVW=y
+CONFIG_ATA=y
+# CONFIG_SATA_AHCI is not set
+CONFIG_SATA_SVW=y
# CONFIG_SCSI_ATA_PIIX is not set
-# CONFIG_SCSI_SATA_MV is not set
-# CONFIG_SCSI_SATA_NV is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
# CONFIG_SCSI_PDC_ADMA is not set
# CONFIG_SCSI_HPTIOP is not set
-# CONFIG_SCSI_SATA_QSTOR is not set
-# CONFIG_SCSI_SATA_PROMISE is not set
-# CONFIG_SCSI_SATA_SX4 is not set
-# CONFIG_SCSI_SATA_SIL is not set
-# CONFIG_SCSI_SATA_SIL24 is not set
-# CONFIG_SCSI_SATA_SIS is not set
-# CONFIG_SCSI_SATA_ULI is not set
-# CONFIG_SCSI_SATA_VIA is not set
-# CONFIG_SCSI_SATA_VITESSE is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_EATA is not set
diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig
index a8cdf312e1b0..d2833c1a1f3d 100644
--- a/arch/powerpc/configs/pseries_defconfig
+++ b/arch/powerpc/configs/pseries_defconfig
@@ -184,6 +184,7 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
CONFIG_MIGRATION=y
CONFIG_RESOURCES_64BIT=y
CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
+CONFIG_NODES_SPAN_OTHER_NODES=y
# CONFIG_PPC_64K_PAGES is not set
CONFIG_SCHED_SMT=y
CONFIG_PROC_DEVICETREE=y
@@ -506,7 +507,7 @@ CONFIG_SCSI_SAS_ATTRS=m
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
+CONFIG_ATA=y
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_BUSLOGIC is not set
# CONFIG_SCSI_DMX3191D is not set
diff --git a/arch/powerpc/kernel/cputable.c b/arch/powerpc/kernel/cputable.c
index 190a57e20765..95382f994404 100644
--- a/arch/powerpc/kernel/cputable.c
+++ b/arch/powerpc/kernel/cputable.c
@@ -268,7 +268,7 @@ struct cpu_spec cpu_specs[] = {
.cpu_user_features = COMMON_USER_POWER6,
.icache_bsize = 128,
.dcache_bsize = 128,
- .num_pmcs = 8,
+ .num_pmcs = 6,
.oprofile_cpu_type = "ppc64/power6",
.oprofile_type = PPC_OPROFILE_POWER4,
.oprofile_mmcra_sihv = POWER6_MMCRA_SIHV,
@@ -763,10 +763,10 @@ struct cpu_spec cpu_specs[] = {
.cpu_setup = __setup_cpu_603,
.platform = "ppc603",
},
- { /* e300 (a 603e core, plus some) on 83xx */
+ { /* e300c1 (a 603e core, plus some) on 83xx */
.pvr_mask = 0x7fff0000,
.pvr_value = 0x00830000,
- .cpu_name = "e300",
+ .cpu_name = "e300c1",
.cpu_features = CPU_FTRS_E300,
.cpu_user_features = COMMON_USER,
.icache_bsize = 32,
@@ -774,6 +774,17 @@ struct cpu_spec cpu_specs[] = {
.cpu_setup = __setup_cpu_603,
.platform = "ppc603",
},
+ { /* e300c2 (an e300c1 core, plus some, minus FPU) on 83xx */
+ .pvr_mask = 0x7fff0000,
+ .pvr_value = 0x00840000,
+ .cpu_name = "e300c2",
+ .cpu_features = CPU_FTRS_E300,
+ .cpu_user_features = PPC_FEATURE_32 | PPC_FEATURE_HAS_MMU,
+ .icache_bsize = 32,
+ .dcache_bsize = 32,
+ .cpu_setup = __setup_cpu_603,
+ .platform = "ppc603",
+ },
{ /* default match, we assume split I/D cache & TB (non-601)... */
.pvr_mask = 0x00000000,
.pvr_value = 0x00000000,
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S
index 2cd872b5283b..748e74fcf541 100644
--- a/arch/powerpc/kernel/entry_64.S
+++ b/arch/powerpc/kernel/entry_64.S
@@ -27,10 +27,7 @@
#include <asm/ppc_asm.h>
#include <asm/asm-offsets.h>
#include <asm/cputable.h>
-
-#ifdef CONFIG_PPC_ISERIES
-#define DO_SOFT_DISABLE
-#endif
+#include <asm/firmware.h>
/*
* System calls.
@@ -91,6 +88,7 @@ system_call_common:
ld r11,exception_marker@toc(r2)
std r11,-16(r9) /* "regshere" marker */
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
/* Hack for handling interrupts when soft-enabling on iSeries */
cmpdi cr1,r0,0x5555 /* syscall 0x5555 */
andi. r10,r12,MSR_PR /* from kernel */
@@ -98,6 +96,7 @@ system_call_common:
beq hardware_interrupt_entry
lbz r10,PACAPROCENABLED(r13)
std r10,SOFTE(r1)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
mfmsr r11
ori r11,r11,MSR_EE
@@ -462,6 +461,7 @@ _GLOBAL(ret_from_except_lite)
restore:
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
ld r5,SOFTE(r1)
cmpdi 0,r5,0
beq 4f
@@ -480,6 +480,7 @@ restore:
b .ret_from_except_lite /* loop back and handle more */
4: stb r5,PACAPROCENABLED(r13)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
ld r3,_MSR(r1)
@@ -538,18 +539,23 @@ do_work:
lwz r8,TI_PREEMPT(r9)
cmpwi cr1,r8,0
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
ld r0,SOFTE(r1)
cmpdi r0,0
-#else
- andi. r0,r3,MSR_EE
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
+BEGIN_FW_FTR_SECTION
+ andi. r0,r3,MSR_EE
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
crandc eq,cr1*4+eq,eq
bne restore
/* here we are preempting the current task */
1:
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
li r0,1
stb r0,PACAPROCENABLED(r13)
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
ori r10,r10,MSR_EE
mtmsrd r10,1 /* reenable interrupts */
diff --git a/arch/powerpc/kernel/head_64.S b/arch/powerpc/kernel/head_64.S
index 3065b472b95d..645c7f10fb28 100644
--- a/arch/powerpc/kernel/head_64.S
+++ b/arch/powerpc/kernel/head_64.S
@@ -33,6 +33,7 @@
#include <asm/hvcall.h>
#include <asm/iseries/lpar_map.h>
#include <asm/thread_info.h>
+#include <asm/firmware.h>
#ifdef CONFIG_PPC_ISERIES
#define DO_SOFT_DISABLE
@@ -365,19 +366,28 @@ label##_iSeries: \
#ifdef DO_SOFT_DISABLE
#define DISABLE_INTS \
+BEGIN_FW_FTR_SECTION; \
lbz r10,PACAPROCENABLED(r13); \
li r11,0; \
std r10,SOFTE(r1); \
mfmsr r10; \
stb r11,PACAPROCENABLED(r13); \
ori r10,r10,MSR_EE; \
- mtmsrd r10,1
+ mtmsrd r10,1; \
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#define ENABLE_INTS \
+BEGIN_FW_FTR_SECTION; \
lbz r10,PACAPROCENABLED(r13); \
mfmsr r11; \
std r10,SOFTE(r1); \
ori r11,r11,MSR_EE; \
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES); \
+BEGIN_FW_FTR_SECTION; \
+ ld r12,_MSR(r1); \
+ mfmsr r11; \
+ rlwimi r11,r12,0,MSR_EE; \
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES); \
mtmsrd r11,1
#else /* hard enable/disable interrupts */
@@ -1071,8 +1081,10 @@ _GLOBAL(slb_miss_realmode)
ld r3,PACA_EXSLB+EX_R3(r13)
lwz r9,PACA_EXSLB+EX_CCR(r13) /* get saved CR */
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
ld r11,PACALPPACAPTR(r13)
ld r11,LPPACASRR0(r11) /* get SRR0 value */
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif /* CONFIG_PPC_ISERIES */
mtlr r10
@@ -1087,8 +1099,10 @@ _GLOBAL(slb_miss_realmode)
.machine pop
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
mtspr SPRN_SRR0,r11
mtspr SPRN_SRR1,r12
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif /* CONFIG_PPC_ISERIES */
ld r9,PACA_EXSLB+EX_R9(r13)
ld r10,PACA_EXSLB+EX_R10(r13)
@@ -1301,6 +1315,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
cmpdi r3,0 /* see if hash_page succeeded */
#ifdef DO_SOFT_DISABLE
+BEGIN_FW_FTR_SECTION
/*
* If we had interrupts soft-enabled at the point where the
* DSI/ISI occurred, and an interrupt came in during hash_page,
@@ -1321,12 +1336,14 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
ld r3,SOFTE(r1)
bl .local_irq_restore
b 11f
-#else
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
+#endif
+BEGIN_FW_FTR_SECTION
beq fast_exception_return /* Return from exception on success */
ble- 12f /* Failure return from hash_page */
/* fall through */
-#endif
+END_FW_FTR_SECTION_IFCLR(FW_FEATURE_ISERIES)
/* Here we have a page fault that hash_page can't handle. */
_GLOBAL(handle_page_fault)
@@ -1861,7 +1878,9 @@ _GLOBAL(__secondary_start)
LOAD_REG_ADDR(r3, .start_secondary_prolog)
LOAD_REG_IMMEDIATE(r4, MSR_KERNEL)
#ifdef DO_SOFT_DISABLE
+BEGIN_FW_FTR_SECTION
ori r4,r4,MSR_EE
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
mtspr SPRN_SRR0,r3
mtspr SPRN_SRR1,r4
@@ -1986,6 +2005,7 @@ _STATIC(start_here_common)
*/
li r3,0
bl .do_cpu_ftr_fixups
+ bl .do_fw_ftr_fixups
/* ptr to current */
LOAD_REG_IMMEDIATE(r4, init_task)
@@ -2000,11 +2020,13 @@ _STATIC(start_here_common)
/* Load up the kernel context */
5:
#ifdef DO_SOFT_DISABLE
+BEGIN_FW_FTR_SECTION
li r5,0
stb r5,PACAPROCENABLED(r13) /* Soft Disabled */
mfmsr r5
ori r5,r5,MSR_EE /* Hard Enabled */
mtmsrd r5
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif
bl .start_kernel
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c
index 124dbcba94a8..39db7a3affe1 100644
--- a/arch/powerpc/kernel/ibmebus.c
+++ b/arch/powerpc/kernel/ibmebus.c
@@ -319,7 +319,7 @@ EXPORT_SYMBOL(ibmebus_unregister_driver);
int ibmebus_request_irq(struct ibmebus_dev *dev,
u32 ist,
- irqreturn_t (*handler)(int, void*, struct pt_regs *),
+ irq_handler_t handler,
unsigned long irq_flags, const char * devname,
void *dev_id)
{
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index ba0694071728..f88a2a675d90 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -75,7 +75,7 @@ static unsigned long iommu_range_alloc(struct iommu_table *tbl,
/* This allocator was derived from x86_64's bit string search */
/* Sanity check */
- if (unlikely(npages) == 0) {
+ if (unlikely(npages == 0)) {
if (printk_ratelimit())
WARN_ON(1);
return DMA_ERROR_CODE;
diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c
index b4432332341f..5e37bf14ef2d 100644
--- a/arch/powerpc/kernel/irq.c
+++ b/arch/powerpc/kernel/irq.c
@@ -187,6 +187,7 @@ void fixup_irqs(cpumask_t map)
void do_IRQ(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
unsigned int irq;
#ifdef CONFIG_IRQSTACKS
struct thread_info *curtp, *irqtp;
@@ -216,7 +217,7 @@ void do_IRQ(struct pt_regs *regs)
* The value -2 is for buggy hardware and means that this IRQ
* has already been handled. -- Tom
*/
- irq = ppc_md.get_irq(regs);
+ irq = ppc_md.get_irq();
if (irq != NO_IRQ && irq != NO_IRQ_IGNORE) {
#ifdef CONFIG_IRQSTACKS
@@ -230,18 +231,19 @@ void do_IRQ(struct pt_regs *regs)
handler = &__do_IRQ;
irqtp->task = curtp->task;
irqtp->flags = 0;
- call_handle_irq(irq, desc, regs, irqtp, handler);
+ call_handle_irq(irq, desc, irqtp, handler);
irqtp->task = NULL;
if (irqtp->flags)
set_bits(irqtp->flags, &curtp->flags);
} else
#endif
- generic_handle_irq(irq, regs);
+ generic_handle_irq(irq);
} else if (irq != NO_IRQ_IGNORE)
/* That's not SMP safe ... but who cares ? */
ppc_spurious_interrupts++;
irq_exit();
+ set_irq_regs(old_regs);
#ifdef CONFIG_PPC_ISERIES
if (get_lppaca()->int_dword.fields.decr_int) {
@@ -570,8 +572,8 @@ unsigned int irq_create_mapping(struct irq_host *host,
}
EXPORT_SYMBOL_GPL(irq_create_mapping);
-extern unsigned int irq_create_of_mapping(struct device_node *controller,
- u32 *intspec, unsigned int intsize)
+unsigned int irq_create_of_mapping(struct device_node *controller,
+ u32 *intspec, unsigned int intsize)
{
struct irq_host *host;
irq_hw_number_t hwirq;
@@ -777,7 +779,6 @@ unsigned int irq_alloc_virt(struct irq_host *host,
{
unsigned long flags;
unsigned int i, j, found = NO_IRQ;
- unsigned int limit = irq_virq_count - count;
if (count == 0 || count > (irq_virq_count - NUM_ISA_INTERRUPTS))
return NO_IRQ;
@@ -794,14 +795,16 @@ unsigned int irq_alloc_virt(struct irq_host *host,
/* Look for count consecutive numbers in the allocatable
* (non-legacy) space
*/
- for (i = NUM_ISA_INTERRUPTS; i <= limit; ) {
- for (j = i; j < (i + count); j++)
- if (irq_map[j].host != NULL) {
- i = j + 1;
- continue;
- }
- found = i;
- break;
+ for (i = NUM_ISA_INTERRUPTS, j = 0; i < irq_virq_count; i++) {
+ if (irq_map[i].host != NULL)
+ j = 0;
+ else
+ j++;
+
+ if (j == count) {
+ found = i - count + 1;
+ break;
+ }
}
if (found == NO_IRQ) {
spin_unlock_irqrestore(&irq_big_lock, flags);
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index cd65c367b8b6..7b8d12b9026c 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -259,14 +259,15 @@ void kretprobe_trampoline_holder(void)
*/
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
- struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
- struct hlist_node *node, *tmp;
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+ INIT_HLIST_HEAD(&empty_rp);
spin_lock_irqsave(&kretprobe_lock, flags);
- head = kretprobe_inst_table_head(current);
+ head = kretprobe_inst_table_head(current);
/*
* It is possible to have multiple instances associated with a given
@@ -277,20 +278,20 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
- * function, the first instance's ret_addr will point to the
+ * function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task != current)
+ if (ri->task != current)
/* another task is sharing our hash bucket */
- continue;
+ continue;
if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_rp_inst(ri);
+ recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
@@ -308,12 +309,16 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
spin_unlock_irqrestore(&kretprobe_lock, flags);
preempt_enable_no_resched();
- /*
- * By returning a non-zero value, we are telling
- * kprobe_handler() that we don't want the post_handler
- * to run (and have re-enabled preemption)
- */
- return 1;
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we don't want the post_handler
+ * to run (and have re-enabled preemption)
+ */
+ return 1;
}
/*
diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S
index 58758d883361..88fd73fdf048 100644
--- a/arch/powerpc/kernel/misc_32.S
+++ b/arch/powerpc/kernel/misc_32.S
@@ -843,7 +843,7 @@ _GLOBAL(kernel_thread)
addi r1,r1,16
blr
-_GLOBAL(execve)
+_GLOBAL(kernel_execve)
li r0,__NR_execve
sc
bnslr
diff --git a/arch/powerpc/kernel/misc_64.S b/arch/powerpc/kernel/misc_64.S
index e3ed21cd3d94..c70e20708a1f 100644
--- a/arch/powerpc/kernel/misc_64.S
+++ b/arch/powerpc/kernel/misc_64.S
@@ -52,12 +52,12 @@ _GLOBAL(call_do_softirq)
blr
_GLOBAL(call_handle_irq)
- ld r8,0(r7)
+ ld r8,0(r6)
mflr r0
std r0,16(r1)
mtctr r8
- stdu r1,THREAD_SIZE-112(r6)
- mr r1,r6
+ stdu r1,THREAD_SIZE-112(r5)
+ mr r1,r5
bctrl
ld r1,0(r1)
ld r0,16(r1)
@@ -325,6 +325,52 @@ _GLOBAL(do_cpu_ftr_fixups)
isync
b 1b
+/*
+ * do_fw_ftr_fixups - goes through the list of firmware feature fixups
+ * and writes nop's over sections of code that don't apply for this firmware.
+ * r3 = data offset (not changed)
+ */
+_GLOBAL(do_fw_ftr_fixups)
+ /* Get firmware features */
+ LOAD_REG_IMMEDIATE(r6,powerpc_firmware_features)
+ sub r6,r6,r3
+ ld r4,0(r6)
+ /* Get the fixup table */
+ LOAD_REG_IMMEDIATE(r6,__start___fw_ftr_fixup)
+ sub r6,r6,r3
+ LOAD_REG_IMMEDIATE(r7,__stop___fw_ftr_fixup)
+ sub r7,r7,r3
+ /* Do the fixup */
+1: cmpld r6,r7
+ bgelr
+ addi r6,r6,32
+ ld r8,-32(r6) /* mask */
+ and r8,r8,r4
+ ld r9,-24(r6) /* value */
+ cmpld r8,r9
+ beq 1b
+ ld r8,-16(r6) /* section begin */
+ ld r9,-8(r6) /* section end */
+ subf. r9,r8,r9
+ beq 1b
+ /* write nops over the section of code */
+ /* todo: if large section, add a branch at the start of it */
+ srwi r9,r9,2
+ mtctr r9
+ sub r8,r8,r3
+ lis r0,0x60000000@h /* nop */
+3: stw r0,0(r8)
+BEGIN_FTR_SECTION
+ dcbst 0,r8 /* suboptimal, but simpler */
+ sync
+ icbi 0,r8
+END_FTR_SECTION_IFSET(CPU_FTR_SPLIT_ID_CACHE)
+ addi r8,r8,4
+ bdnz 3b
+ sync /* additional sync needed on g4 */
+ isync
+ b 1b
+
#if defined(CONFIG_PPC_PMAC) || defined(CONFIG_PPC_MAPLE)
/*
* Do an IO access in real mode
@@ -556,7 +602,7 @@ _GLOBAL(giveup_altivec)
#endif /* CONFIG_ALTIVEC */
-_GLOBAL(execve)
+_GLOBAL(kernel_execve)
li r0,__NR_execve
sc
bnslr
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c
index 9b49f8691d29..0d9ff72e2852 100644
--- a/arch/powerpc/kernel/pci_32.c
+++ b/arch/powerpc/kernel/pci_32.c
@@ -441,14 +441,14 @@ update_bridge_base(struct pci_bus *bus, int i)
end = res->end - off;
io_base_lo = (start >> 8) & PCI_IO_RANGE_MASK;
io_limit_lo = (end >> 8) & PCI_IO_RANGE_MASK;
- if (end > 0xffff) {
- pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
- start >> 16);
- pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
- end >> 16);
+ if (end > 0xffff)
io_base_lo |= PCI_IO_RANGE_TYPE_32;
- } else
+ else
io_base_lo |= PCI_IO_RANGE_TYPE_16;
+ pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
+ start >> 16);
+ pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
+ end >> 16);
pci_write_config_byte(dev, PCI_IO_BASE, io_base_lo);
pci_write_config_byte(dev, PCI_IO_LIMIT, io_limit_lo);
diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c
index c1b1e14775e4..9bae8a5bf671 100644
--- a/arch/powerpc/kernel/pci_64.c
+++ b/arch/powerpc/kernel/pci_64.c
@@ -30,6 +30,7 @@
#include <asm/byteorder.h>
#include <asm/machdep.h>
#include <asm/ppc-pci.h>
+#include <asm/firmware.h>
#ifdef DEBUG
#include <asm/udbg.h>
@@ -198,8 +199,14 @@ struct pci_controller * pcibios_alloc_controller(struct device_node *dev)
pci_setup_pci_controller(phb);
phb->arch_data = dev;
phb->is_dynamic = mem_init_done;
- if (dev)
- PHB_SET_NODE(phb, of_node_to_nid(dev));
+ if (dev) {
+ int nid = of_node_to_nid(dev);
+
+ if (nid < 0 || !node_online(nid))
+ nid = -1;
+
+ PHB_SET_NODE(phb, nid);
+ }
return phb;
}
@@ -209,7 +216,6 @@ void pcibios_free_controller(struct pci_controller *phb)
kfree(phb);
}
-#ifndef CONFIG_PPC_ISERIES
void __devinit pcibios_claim_one_bus(struct pci_bus *b)
{
struct pci_dev *dev;
@@ -238,10 +244,12 @@ static void __init pcibios_claim_of_setup(void)
{
struct pci_bus *b;
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return;
+
list_for_each_entry(b, &pci_root_buses, node)
pcibios_claim_one_bus(b);
}
-#endif
#ifdef CONFIG_PPC_MULTIPLATFORM
static u32 get_int_prop(struct device_node *np, const char *name, u32 def)
@@ -554,9 +562,8 @@ static int __init pcibios_init(void)
*/
ppc_md.phys_mem_access_prot = pci_phys_mem_access_prot;
-#ifdef CONFIG_PPC_ISERIES
- iSeries_pcibios_init();
-#endif
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ iSeries_pcibios_init();
printk(KERN_DEBUG "PCI: Probing PCI hardware\n");
@@ -566,15 +573,15 @@ static int __init pcibios_init(void)
pci_bus_add_devices(hose->bus);
}
-#ifndef CONFIG_PPC_ISERIES
- if (pci_probe_only)
- pcibios_claim_of_setup();
- else
- /* FIXME: `else' will be removed when
- pci_assign_unassigned_resources() is able to work
- correctly with [partially] allocated PCI tree. */
- pci_assign_unassigned_resources();
-#endif /* !CONFIG_PPC_ISERIES */
+ if (!firmware_has_feature(FW_FEATURE_ISERIES)) {
+ if (pci_probe_only)
+ pcibios_claim_of_setup();
+ else
+ /* FIXME: `else' will be removed when
+ pci_assign_unassigned_resources() is able to work
+ correctly with [partially] allocated PCI tree. */
+ pci_assign_unassigned_resources();
+ }
/* Call machine dependent final fixup */
if (ppc_md.pcibios_fixup)
@@ -586,8 +593,9 @@ static int __init pcibios_init(void)
printk(KERN_DEBUG "ISA bridge at %s\n", pci_name(ppc64_isabridge_dev));
#ifdef CONFIG_PPC_MULTIPLATFORM
- /* map in PCI I/O space */
- phbs_remap_io();
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ /* map in PCI I/O space */
+ phbs_remap_io();
#endif
printk(KERN_DEBUG "PCI: Probing PCI hardware done\n");
@@ -637,13 +645,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
*/
int pci_domain_nr(struct pci_bus *bus)
{
-#ifdef CONFIG_PPC_ISERIES
- return 0;
-#else
- struct pci_controller *hose = pci_bus_to_host(bus);
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+ else {
+ struct pci_controller *hose = pci_bus_to_host(bus);
- return hose->global_number;
-#endif
+ return hose->global_number;
+ }
}
EXPORT_SYMBOL(pci_domain_nr);
@@ -651,12 +659,12 @@ EXPORT_SYMBOL(pci_domain_nr);
/* Decide whether to display the domain number in /proc */
int pci_proc_domain(struct pci_bus *bus)
{
-#ifdef CONFIG_PPC_ISERIES
- return 0;
-#else
- struct pci_controller *hose = pci_bus_to_host(bus);
- return hose->buid;
-#endif
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return 0;
+ else {
+ struct pci_controller *hose = pci_bus_to_host(bus);
+ return hose->buid;
+ }
}
/*
diff --git a/arch/powerpc/kernel/perfmon_fsl_booke.c b/arch/powerpc/kernel/perfmon_fsl_booke.c
index bdc3977a7b06..e0dcf2b41fbe 100644
--- a/arch/powerpc/kernel/perfmon_fsl_booke.c
+++ b/arch/powerpc/kernel/perfmon_fsl_booke.c
@@ -1,4 +1,4 @@
-/* kernel/perfmon_fsl_booke.c
+/* arch/powerpc/kernel/perfmon_fsl_booke.c
* Freescale Book-E Performance Monitor code
*
* Author: Andy Fleming
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index a127a1e3c097..f3d4dd580dd6 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -341,13 +341,6 @@ struct task_struct *__switch_to(struct task_struct *prev,
static int instructions_to_print = 16;
-#ifdef CONFIG_PPC64
-#define BAD_PC(pc) ((REGION_ID(pc) != KERNEL_REGION_ID) && \
- (REGION_ID(pc) != VMALLOC_REGION_ID))
-#else
-#define BAD_PC(pc) ((pc) < KERNELBASE)
-#endif
-
static void show_instructions(struct pt_regs *regs)
{
int i;
@@ -366,7 +359,8 @@ static void show_instructions(struct pt_regs *regs)
* bad address because the pc *should* only be a
* kernel address.
*/
- if (BAD_PC(pc) || __get_user(instr, (unsigned int __user *)pc)) {
+ if (!__kernel_text_address(pc) ||
+ __get_user(instr, (unsigned int __user *)pc)) {
printk("XXXXXXXX ");
} else {
if (regs->nip == pc)
@@ -424,7 +418,7 @@ void show_regs(struct pt_regs * regs)
printk("NIP: "REG" LR: "REG" CTR: "REG"\n",
regs->nip, regs->link, regs->ctr);
printk("REGS: %p TRAP: %04lx %s (%s)\n",
- regs, regs->trap, print_tainted(), system_utsname.release);
+ regs, regs->trap, print_tainted(), init_utsname()->release);
printk("MSR: "REG" ", regs->msr);
printbits(regs->msr, msr_bits);
printk(" CR: %08lX XER: %08lX\n", regs->ccr, regs->xer);
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index eb913f80bfb1..865b9648d0d5 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -724,7 +724,7 @@ static int __init early_init_dt_scan_chosen(unsigned long node,
strlcpy(cmd_line, p, min((int)l, COMMAND_LINE_SIZE));
#ifdef CONFIG_CMDLINE
- if (l == 0 || (l == 1 && (*p) == 0))
+ if (p == NULL || l == 0 || (l == 1 && (*p) == 0))
strlcpy(cmd_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
#endif /* CONFIG_CMDLINE */
diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c
index dea75d73f983..975102a020d9 100644
--- a/arch/powerpc/kernel/ptrace.c
+++ b/arch/powerpc/kernel/ptrace.c
@@ -526,9 +526,7 @@ static void do_syscall_trace(void)
void do_syscall_trace_enter(struct pt_regs *regs)
{
-#ifdef CONFIG_PPC64
secure_computing(regs->gpr[0]);
-#endif
if (test_thread_flag(TIF_SYSCALL_TRACE)
&& (current->ptrace & PT_PTRACED))
@@ -548,12 +546,8 @@ void do_syscall_trace_enter(struct pt_regs *regs)
void do_syscall_trace_leave(struct pt_regs *regs)
{
-#ifdef CONFIG_PPC32
- secure_computing(regs->gpr[0]);
-#endif
-
if (unlikely(current->audit_context))
- audit_syscall_exit((regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
+ audit_syscall_exit((regs->ccr&0x10000000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
regs->result);
if ((test_thread_flag(TIF_SYSCALL_TRACE)
@@ -561,8 +555,3 @@ void do_syscall_trace_leave(struct pt_regs *regs)
&& (current->ptrace & PT_PTRACED))
do_syscall_trace();
}
-
-#ifdef CONFIG_PPC32
-EXPORT_SYMBOL(do_syscall_trace_enter);
-EXPORT_SYMBOL(do_syscall_trace_leave);
-#endif
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 0af3fc1bdcc9..89cfaf49d3de 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -442,31 +442,6 @@ void __init smp_setup_cpu_maps(void)
}
#endif /* CONFIG_SMP */
-int __initdata do_early_xmon;
-#ifdef CONFIG_XMON
-extern int xmon_no_auto_backtrace;
-
-static int __init early_xmon(char *p)
-{
- /* ensure xmon is enabled */
- if (p) {
- if (strncmp(p, "on", 2) == 0)
- xmon_init(1);
- if (strncmp(p, "off", 3) == 0)
- xmon_init(0);
- if (strncmp(p, "nobt", 4) == 0)
- xmon_no_auto_backtrace = 1;
- if (strncmp(p, "early", 5) != 0)
- return 0;
- }
- xmon_init(1);
- do_early_xmon = 1;
-
- return 0;
-}
-early_param("xmon", early_xmon);
-#endif
-
static __init int add_pcspkr(void)
{
struct device_node *np;
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index e0df2ba1ab9f..191d0ab09222 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -67,10 +67,6 @@ int have_of = 1;
dev_t boot_dev;
#endif /* CONFIG_PPC_MULTIPLATFORM */
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned long SYSRQ_KEY = 0x54;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
#ifdef CONFIG_VGA_CONSOLE
unsigned long vgacon_remap_base;
#endif
@@ -242,12 +238,11 @@ void __init setup_arch(char **cmdline_p)
smp_setup_cpu_maps();
-#ifdef CONFIG_XMON_DEFAULT
- xmon_init(1);
-#endif
/* Register early console */
register_early_udbg_console();
+ xmon_setup();
+
#if defined(CONFIG_KGDB)
if (ppc_md.kgdb_map_scc)
ppc_md.kgdb_map_scc();
@@ -284,9 +279,6 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = klimit;
- if (do_early_xmon)
- debugger(NULL);
-
/* set up the bootmem stuff with available memory */
do_init_bootmem();
if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index 00d6b8addd78..4b2e32eab9dc 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -93,11 +93,6 @@ int dcache_bsize;
int icache_bsize;
int ucache_bsize;
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned long SYSRQ_KEY;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
-
#ifdef CONFIG_SMP
static int smt_enabled_cmdline;
@@ -396,18 +391,14 @@ void __init setup_system(void)
find_legacy_serial_ports();
/*
- * Initialize xmon
- */
-#ifdef CONFIG_XMON_DEFAULT
- xmon_init(1);
-#endif
- /*
* Register early console
*/
register_early_udbg_console();
- if (do_early_xmon)
- debugger(NULL);
+ /*
+ * Initialize xmon
+ */
+ xmon_setup();
check_smt_enabled();
smp_setup_cpu_maps();
@@ -419,7 +410,7 @@ void __init setup_system(void)
smp_release_cpus();
#endif
- printk("Starting Linux PPC64 %s\n", system_utsname.version);
+ printk("Starting Linux PPC64 %s\n", init_utsname()->version);
printk("-----------------------------------------------------\n");
printk("ppc64_pft_size = 0x%lx\n", ppc64_pft_size);
diff --git a/arch/powerpc/kernel/smp.c b/arch/powerpc/kernel/smp.c
index 6a9bc9ce54e0..35c6309bdb76 100644
--- a/arch/powerpc/kernel/smp.c
+++ b/arch/powerpc/kernel/smp.c
@@ -115,7 +115,7 @@ void __devinit smp_generic_kick_cpu(int nr)
}
#endif
-void smp_message_recv(int msg, struct pt_regs *regs)
+void smp_message_recv(int msg)
{
switch(msg) {
case PPC_MSG_CALL_FUNCTION:
@@ -127,11 +127,11 @@ void smp_message_recv(int msg, struct pt_regs *regs)
break;
case PPC_MSG_DEBUGGER_BREAK:
if (crash_ipi_function_ptr) {
- crash_ipi_function_ptr(regs);
+ crash_ipi_function_ptr(get_irq_regs());
break;
}
#ifdef CONFIG_DEBUGGER
- debugger_ipi(regs);
+ debugger_ipi(get_irq_regs());
break;
#endif /* CONFIG_DEBUGGER */
/* FALLTHROUGH */
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 2e292863e982..d15c33e95959 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -69,16 +69,20 @@ struct readdir_callback32 {
};
static int fillonedir(void * __buf, const char * name, int namlen,
- off_t offset, ino_t ino, unsigned int d_type)
+ off_t offset, u64 ino, unsigned int d_type)
{
struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
struct old_linux_dirent32 __user * dirent;
+ ino_t d_ino;
if (buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
buf->count++;
dirent = buf->dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(offset, &dirent->d_offset);
put_user(namlen, &dirent->d_namlen);
copy_to_user(dirent->d_name, name, namlen);
@@ -120,15 +124,20 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
+ compat_ino_t ino;
long err;
if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
!new_valid_dev(stat->rdev))
return -EOVERFLOW;
+ ino = stat->ino;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
- err |= __put_user(stat->ino, &statbuf->st_ino);
+ err |= __put_user(ino, &statbuf->st_ino);
err |= __put_user(stat->mode, &statbuf->st_mode);
err |= __put_user(stat->nlink, &statbuf->st_nlink);
err |= __put_user(stat->uid, &statbuf->st_uid);
@@ -740,7 +749,7 @@ asmlinkage long compat_sys_umask(u32 mask)
return sys_umask((int)mask);
}
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL_SYSCALL
struct __sysctl_args32 {
u32 name;
int nlen;
diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c
index 9b69d99a9103..d358866b880f 100644
--- a/arch/powerpc/kernel/syscalls.c
+++ b/arch/powerpc/kernel/syscalls.c
@@ -260,7 +260,7 @@ long ppc_newuname(struct new_utsname __user * name)
int err = 0;
down_read(&uts_sem);
- if (copy_to_user(name, &system_utsname, sizeof(*name)))
+ if (copy_to_user(name, utsname(), sizeof(*name)))
err = -EFAULT;
up_read(&uts_sem);
if (!err)
@@ -273,7 +273,7 @@ int sys_uname(struct old_utsname __user *name)
int err = 0;
down_read(&uts_sem);
- if (copy_to_user(name, &system_utsname, sizeof(*name)))
+ if (copy_to_user(name, utsname(), sizeof(*name)))
err = -EFAULT;
up_read(&uts_sem);
if (!err)
@@ -289,19 +289,19 @@ int sys_olduname(struct oldold_utsname __user *name)
return -EFAULT;
down_read(&uts_sem);
- error = __copy_to_user(&name->sysname, &system_utsname.sysname,
+ error = __copy_to_user(&name->sysname, &utsname()->sysname,
__OLD_UTS_LEN);
error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
- error |= __copy_to_user(&name->nodename, &system_utsname.nodename,
+ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
__OLD_UTS_LEN);
error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
- error |= __copy_to_user(&name->release, &system_utsname.release,
+ error |= __copy_to_user(&name->release, &utsname()->release,
__OLD_UTS_LEN);
error |= __put_user(0, name->release + __OLD_UTS_LEN);
- error |= __copy_to_user(&name->version, &system_utsname.version,
+ error |= __copy_to_user(&name->version, &utsname()->version,
__OLD_UTS_LEN);
error |= __put_user(0, name->version + __OLD_UTS_LEN);
- error |= __copy_to_user(&name->machine, &system_utsname.machine,
+ error |= __copy_to_user(&name->machine, &utsname()->machine,
__OLD_UTS_LEN);
error |= override_machine(name->machine);
up_read(&uts_sem);
diff --git a/arch/powerpc/kernel/sysfs.c b/arch/powerpc/kernel/sysfs.c
index 406f308ddead..d45a168bdaca 100644
--- a/arch/powerpc/kernel/sysfs.c
+++ b/arch/powerpc/kernel/sysfs.c
@@ -25,8 +25,8 @@ static DEFINE_PER_CPU(struct cpu, cpu_devices);
/* SMT stuff */
#ifdef CONFIG_PPC_MULTIPLATFORM
-/* default to snooze disabled */
-DEFINE_PER_CPU(unsigned long, smt_snooze_delay);
+/* Time in microseconds we delay before sleeping in the idle loop */
+DEFINE_PER_CPU(unsigned long, smt_snooze_delay) = { 100 };
static ssize_t store_smt_snooze_delay(struct sys_device *dev, const char *buf,
size_t count)
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 7a3c3f791ade..5b59bc18dfe7 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -51,6 +51,7 @@
#include <linux/rtc.h>
#include <linux/jiffies.h>
#include <linux/posix-timers.h>
+#include <linux/irq.h>
#include <asm/io.h>
#include <asm/processor.h>
@@ -117,8 +118,6 @@ unsigned tb_to_ns_shift;
struct gettimeofday_struct do_gtod;
-extern unsigned long wall_jiffies;
-
extern struct timezone sys_tz;
static long timezone_offset;
@@ -645,6 +644,7 @@ static void iSeries_tb_recal(void)
*/
void timer_interrupt(struct pt_regs * regs)
{
+ struct pt_regs *old_regs;
int next_dec;
int cpu = smp_processor_id();
unsigned long ticks;
@@ -655,9 +655,10 @@ void timer_interrupt(struct pt_regs * regs)
do_IRQ(regs);
#endif
+ old_regs = set_irq_regs(regs);
irq_enter();
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
calculate_steal_time();
#ifdef CONFIG_PPC_ISERIES
@@ -693,7 +694,7 @@ void timer_interrupt(struct pt_regs * regs)
tb_next_jiffy = tb_last_jiffy + tb_ticks_per_jiffy;
if (per_cpu(last_jiffy, cpu) >= tb_next_jiffy) {
tb_last_jiffy = tb_next_jiffy;
- do_timer(regs);
+ do_timer(1);
timer_recalc_offset(tb_last_jiffy);
timer_check_rtc();
}
@@ -705,7 +706,7 @@ void timer_interrupt(struct pt_regs * regs)
#ifdef CONFIG_PPC_ISERIES
if (hvlpevent_is_pending())
- process_hvlpevents(regs);
+ process_hvlpevents();
#endif
#ifdef CONFIG_PPC64
@@ -717,6 +718,7 @@ void timer_interrupt(struct pt_regs * regs)
#endif
irq_exit();
+ set_irq_regs(old_regs);
}
void wakeup_decrementer(void)
@@ -816,11 +818,6 @@ int do_settimeofday(struct timespec *tv)
/*
* Subtract off the number of nanoseconds since the
* beginning of the last tick.
- * Note that since we don't increment jiffies_64 anywhere other
- * than in do_timer (since we don't have a lost tick problem),
- * wall_jiffies will always be the same as jiffies,
- * and therefore the (jiffies - wall_jiffies) computation
- * has been removed.
*/
tb_delta = tb_ticks_since(tb_last_jiffy);
tb_delta = mulhdu(tb_delta, do_gtod.varp->tb_to_xs); /* in xsec */
@@ -1048,6 +1045,48 @@ void __init time_init(void)
set_dec(tb_ticks_per_jiffy);
}
+#ifdef CONFIG_RTC_CLASS
+static int set_rtc_class_time(struct rtc_time *tm)
+{
+ int err;
+ struct class_device *class_dev =
+ rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+ if (class_dev == NULL)
+ return -ENODEV;
+
+ err = rtc_set_time(class_dev, tm);
+
+ rtc_class_close(class_dev);
+
+ return 0;
+}
+
+static void get_rtc_class_time(struct rtc_time *tm)
+{
+ int err;
+ struct class_device *class_dev =
+ rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+ if (class_dev == NULL)
+ return;
+
+ err = rtc_read_time(class_dev, tm);
+
+ rtc_class_close(class_dev);
+
+ return;
+}
+
+int __init rtc_class_hookup(void)
+{
+ ppc_md.get_rtc_time = get_rtc_class_time;
+ ppc_md.set_rtc_time = set_rtc_class_time;
+
+ return 0;
+}
+#endif /* CONFIG_RTC_CLASS */
+
#define FEBRUARY 2
#define STARTOFTIME 1970
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index d9f10f2fc372..5ed4c2ceb5ca 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -900,14 +900,13 @@ void kernel_fp_unavailable_exception(struct pt_regs *regs)
void altivec_unavailable_exception(struct pt_regs *regs)
{
-#if !defined(CONFIG_ALTIVEC)
if (user_mode(regs)) {
/* A user program has executed an altivec instruction,
but this kernel doesn't support altivec. */
_exception(SIGILL, regs, ILL_ILLOPC, regs->nip);
return;
}
-#endif
+
printk(KERN_EMERG "Unrecoverable VMX/Altivec Unavailable Exception "
"%lx at %lx\n", regs->trap, regs->nip);
die("Unrecoverable VMX/Altivec Unavailable Exception", regs, SIGABRT);
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 02665a02130d..cb0e8d46c3e8 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -132,6 +132,14 @@ SECTIONS
*(__ftr_fixup)
__stop___ftr_fixup = .;
}
+#ifdef CONFIG_PPC64
+ . = ALIGN(8);
+ __fw_ftr_fixup : {
+ __start___fw_ftr_fixup = .;
+ *(__fw_ftr_fixup)
+ __stop___fw_ftr_fixup = .;
+ }
+#endif
. = ALIGN(PAGE_SIZE);
.init.ramfs : {
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile
index 336dd191f768..a0360ae10d0c 100644
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -14,9 +14,15 @@ endif
obj-$(CONFIG_PPC64) += checksum_64.o copypage_64.o copyuser_64.o \
memcpy_64.o usercopy_64.o mem_64.o string.o \
strcase.o
+obj-$(CONFIG_QUICC_ENGINE) += rheap.o
obj-$(CONFIG_XMON) += sstep.o
ifeq ($(CONFIG_PPC64),y)
obj-$(CONFIG_SMP) += locks.o
obj-$(CONFIG_DEBUG_KERNEL) += sstep.o
endif
+
+# Temporary hack until we have migrated to asm-powerpc
+ifeq ($(CONFIG_PPC_MERGE),y)
+obj-$(CONFIG_CPM2) += rheap.o
+endif
diff --git a/arch/powerpc/lib/rheap.c b/arch/powerpc/lib/rheap.c
index 31e511856dc5..57bf991ccd6e 100644
--- a/arch/powerpc/lib/rheap.c
+++ b/arch/powerpc/lib/rheap.c
@@ -423,17 +423,21 @@ void *rh_detach_region(rh_info_t * info, void *start, int size)
return (void *)s;
}
-void *rh_alloc(rh_info_t * info, int size, const char *owner)
+void *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;
- /* Validate size */
- if (size <= 0)
+ /* Validate size, (must be power of two) */
+ if (size <= 0 || (alignment & (alignment - 1)) != 0)
return ERR_PTR(-EINVAL);
+ /* given alignment larger that default rheap alignment */
+ if (alignment > info->alignment)
+ size += alignment - 1;
+
/* Align to configured alignment */
size = (size + (info->alignment - 1)) & ~(info->alignment - 1);
@@ -476,15 +480,27 @@ void *rh_alloc(rh_info_t * info, int size, const char *owner)
attach_taken_block(info, newblk);
+ /* for larger alignment return fixed up pointer */
+ /* 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));
+
return start;
}
+void *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)
{
struct list_head *l;
rh_block_t *blk, *newblk1, *newblk2;
- unsigned long s, e, m, bs, be;
+ unsigned long s, e, m, bs = 0, be = 0;
/* Validate size */
if (size <= 0)
diff --git a/arch/powerpc/math-emu/Makefile b/arch/powerpc/math-emu/Makefile
index 754143e8936b..29bc9126241b 100644
--- a/arch/powerpc/math-emu/Makefile
+++ b/arch/powerpc/math-emu/Makefile
@@ -11,3 +11,6 @@ obj-$(CONFIG_MATH_EMULATION) += fabs.o fadd.o fadds.o fcmpo.o fcmpu.o \
mcrfs.o mffs.o mtfsb0.o mtfsb1.o \
mtfsf.o mtfsfi.o stfiwx.o stfs.o \
udivmodti4.o
+
+CFLAGS_fabs.o = -fno-builtin-fabs
+CFLAGS_math.o = -fno-builtin-fabs
diff --git a/arch/powerpc/mm/fault.c b/arch/powerpc/mm/fault.c
index 78a0d59903ee..e8fa50624b70 100644
--- a/arch/powerpc/mm/fault.c
+++ b/arch/powerpc/mm/fault.c
@@ -333,7 +333,7 @@ good_area:
/* protection fault */
if (error_code & 0x08000000)
goto bad_area;
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
}
@@ -386,7 +386,7 @@ bad_area_nosemaphore:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index eebd8b83a6b0..d1c0758c5611 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -256,20 +256,22 @@ void __init do_init_bootmem(void)
boot_mapsize = init_bootmem(start >> PAGE_SHIFT, total_pages);
+ /* Add active regions with valid PFNs */
+ for (i = 0; i < lmb.memory.cnt; i++) {
+ unsigned long start_pfn, end_pfn;
+ start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
+ end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
+ add_active_range(0, start_pfn, end_pfn);
+ }
+
/* Add all physical memory to the bootmem map, mark each area
* present.
*/
- for (i = 0; i < lmb.memory.cnt; i++) {
- unsigned long base = lmb.memory.region[i].base;
- unsigned long size = lmb_size_bytes(&lmb.memory, i);
#ifdef CONFIG_HIGHMEM
- if (base >= total_lowmem)
- continue;
- if (base + size > total_lowmem)
- size = total_lowmem - base;
+ free_bootmem_with_active_regions(0, total_lowmem >> PAGE_SHIFT);
+#else
+ free_bootmem_with_active_regions(0, max_pfn);
#endif
- free_bootmem(base, size);
- }
/* reserve the sections we're already using */
for (i = 0; i < lmb.reserved.cnt; i++)
@@ -277,9 +279,8 @@ void __init do_init_bootmem(void)
lmb_size_bytes(&lmb.reserved, i));
/* XXX need to clip this if using highmem? */
- for (i = 0; i < lmb.memory.cnt; i++)
- memory_present(0, lmb_start_pfn(&lmb.memory, i),
- lmb_end_pfn(&lmb.memory, i));
+ sparse_memory_present_with_active_regions(0);
+
init_bootmem_done = 1;
}
@@ -288,10 +289,9 @@ void __init do_init_bootmem(void)
*/
void __init paging_init(void)
{
- unsigned long zones_size[MAX_NR_ZONES];
- unsigned long zholes_size[MAX_NR_ZONES];
unsigned long total_ram = lmb_phys_mem_size();
unsigned long top_of_ram = lmb_end_of_DRAM();
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
#ifdef CONFIG_HIGHMEM
map_page(PKMAP_BASE, 0, 0); /* XXX gross */
@@ -307,26 +307,14 @@ void __init paging_init(void)
top_of_ram, total_ram);
printk(KERN_DEBUG "Memory hole size: %ldMB\n",
(top_of_ram - total_ram) >> 20);
- /*
- * All pages are DMA-able so we put them all in the DMA zone.
- */
- memset(zones_size, 0, sizeof(zones_size));
- memset(zholes_size, 0, sizeof(zholes_size));
-
- zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
- zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT;
-
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
- zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT;
- zholes_size[ZONE_HIGHMEM] = (top_of_ram - total_ram) >> PAGE_SHIFT;
+ max_zone_pfns[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
+ max_zone_pfns[ZONE_HIGHMEM] = top_of_ram >> PAGE_SHIFT;
#else
- zones_size[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
- zholes_size[ZONE_DMA] = (top_of_ram - total_ram) >> PAGE_SHIFT;
-#endif /* CONFIG_HIGHMEM */
-
- free_area_init_node(0, NODE_DATA(0), zones_size,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
+ max_zone_pfns[ZONE_DMA] = top_of_ram >> PAGE_SHIFT;
+#endif
+ free_area_init_nodes(max_zone_pfns);
}
#endif /* ! CONFIG_NEED_MULTIPLE_NODES */
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index 6c0f1c7d83e5..9da01dc8cfd9 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -39,96 +39,6 @@ static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
static int min_common_depth;
static int n_mem_addr_cells, n_mem_size_cells;
-/*
- * We need somewhere to store start/end/node for each region until we have
- * allocated the real node_data structures.
- */
-#define MAX_REGIONS (MAX_LMB_REGIONS*2)
-static struct {
- unsigned long start_pfn;
- unsigned long end_pfn;
- int nid;
-} init_node_data[MAX_REGIONS] __initdata;
-
-int __init early_pfn_to_nid(unsigned long pfn)
-{
- unsigned int i;
-
- for (i = 0; init_node_data[i].end_pfn; i++) {
- unsigned long start_pfn = init_node_data[i].start_pfn;
- unsigned long end_pfn = init_node_data[i].end_pfn;
-
- if ((start_pfn <= pfn) && (pfn < end_pfn))
- return init_node_data[i].nid;
- }
-
- return -1;
-}
-
-void __init add_region(unsigned int nid, unsigned long start_pfn,
- unsigned long pages)
-{
- unsigned int i;
-
- dbg("add_region nid %d start_pfn 0x%lx pages 0x%lx\n",
- nid, start_pfn, pages);
-
- for (i = 0; init_node_data[i].end_pfn; i++) {
- if (init_node_data[i].nid != nid)
- continue;
- if (init_node_data[i].end_pfn == start_pfn) {
- init_node_data[i].end_pfn += pages;
- return;
- }
- if (init_node_data[i].start_pfn == (start_pfn + pages)) {
- init_node_data[i].start_pfn -= pages;
- return;
- }
- }
-
- /*
- * Leave last entry NULL so we dont iterate off the end (we use
- * entry.end_pfn to terminate the walk).
- */
- if (i >= (MAX_REGIONS - 1)) {
- printk(KERN_ERR "WARNING: too many memory regions in "
- "numa code, truncating\n");
- return;
- }
-
- init_node_data[i].start_pfn = start_pfn;
- init_node_data[i].end_pfn = start_pfn + pages;
- init_node_data[i].nid = nid;
-}
-
-/* We assume init_node_data has no overlapping regions */
-void __init get_region(unsigned int nid, unsigned long *start_pfn,
- unsigned long *end_pfn, unsigned long *pages_present)
-{
- unsigned int i;
-
- *start_pfn = -1UL;
- *end_pfn = *pages_present = 0;
-
- for (i = 0; init_node_data[i].end_pfn; i++) {
- if (init_node_data[i].nid != nid)
- continue;
-
- *pages_present += init_node_data[i].end_pfn -
- init_node_data[i].start_pfn;
-
- if (init_node_data[i].start_pfn < *start_pfn)
- *start_pfn = init_node_data[i].start_pfn;
-
- if (init_node_data[i].end_pfn > *end_pfn)
- *end_pfn = init_node_data[i].end_pfn;
- }
-
- /* We didnt find a matching region, return start/end as 0 */
- if (*start_pfn == -1UL)
- *start_pfn = 0;
-}
-
static void __cpuinit map_cpu_to_node(int cpu, int node)
{
numa_cpu_lookup_table[cpu] = node;
@@ -468,8 +378,8 @@ new_range:
continue;
}
- add_region(nid, start >> PAGE_SHIFT,
- size >> PAGE_SHIFT);
+ add_active_range(nid, start >> PAGE_SHIFT,
+ (start >> PAGE_SHIFT) + (size >> PAGE_SHIFT));
if (--ranges)
goto new_range;
@@ -482,6 +392,7 @@ static void __init setup_nonnuma(void)
{
unsigned long top_of_ram = lmb_end_of_DRAM();
unsigned long total_ram = lmb_phys_mem_size();
+ unsigned long start_pfn, end_pfn;
unsigned int i;
printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
@@ -489,9 +400,11 @@ static void __init setup_nonnuma(void)
printk(KERN_DEBUG "Memory hole size: %ldMB\n",
(top_of_ram - total_ram) >> 20);
- for (i = 0; i < lmb.memory.cnt; ++i)
- add_region(0, lmb.memory.region[i].base >> PAGE_SHIFT,
- lmb_size_pages(&lmb.memory, i));
+ for (i = 0; i < lmb.memory.cnt; ++i) {
+ start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
+ end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
+ add_active_range(0, start_pfn, end_pfn);
+ }
node_set_online(0);
}
@@ -630,11 +543,11 @@ void __init do_init_bootmem(void)
(void *)(unsigned long)boot_cpuid);
for_each_online_node(nid) {
- unsigned long start_pfn, end_pfn, pages_present;
+ unsigned long start_pfn, end_pfn;
unsigned long bootmem_paddr;
unsigned long bootmap_pages;
- get_region(nid, &start_pfn, &end_pfn, &pages_present);
+ get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
/* Allocate the node structure node local if possible */
NODE_DATA(nid) = careful_allocation(nid,
@@ -667,19 +580,7 @@ void __init do_init_bootmem(void)
init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,
start_pfn, end_pfn);
- /* Add free regions on this node */
- for (i = 0; init_node_data[i].end_pfn; i++) {
- unsigned long start, end;
-
- if (init_node_data[i].nid != nid)
- continue;
-
- start = init_node_data[i].start_pfn << PAGE_SHIFT;
- end = init_node_data[i].end_pfn << PAGE_SHIFT;
-
- dbg("free_bootmem %lx %lx\n", start, end - start);
- free_bootmem_node(NODE_DATA(nid), start, end - start);
- }
+ free_bootmem_with_active_regions(nid, end_pfn);
/* Mark reserved regions on this node */
for (i = 0; i < lmb.reserved.cnt; i++) {
@@ -710,44 +611,16 @@ void __init do_init_bootmem(void)
}
}
- /* Add regions into sparsemem */
- for (i = 0; init_node_data[i].end_pfn; i++) {
- unsigned long start, end;
-
- if (init_node_data[i].nid != nid)
- continue;
-
- start = init_node_data[i].start_pfn;
- end = init_node_data[i].end_pfn;
-
- memory_present(nid, start, end);
- }
+ sparse_memory_present_with_active_regions(nid);
}
}
void __init paging_init(void)
{
- unsigned long zones_size[MAX_NR_ZONES];
- unsigned long zholes_size[MAX_NR_ZONES];
- int nid;
-
- memset(zones_size, 0, sizeof(zones_size));
- memset(zholes_size, 0, sizeof(zholes_size));
-
- for_each_online_node(nid) {
- unsigned long start_pfn, end_pfn, pages_present;
-
- get_region(nid, &start_pfn, &end_pfn, &pages_present);
-
- zones_size[ZONE_DMA] = end_pfn - start_pfn;
- zholes_size[ZONE_DMA] = zones_size[ZONE_DMA] - pages_present;
-
- dbg("free_area_init node %d %lx %lx (hole: %lx)\n", nid,
- zones_size[ZONE_DMA], start_pfn, zholes_size[ZONE_DMA]);
-
- free_area_init_node(nid, NODE_DATA(nid), zones_size, start_pfn,
- zholes_size);
- }
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = lmb_end_of_DRAM() >> PAGE_SHIFT;
+ free_area_init_nodes(max_zone_pfns);
}
static int __init early_numa(char *p)
diff --git a/arch/powerpc/mm/pgtable_64.c b/arch/powerpc/mm/pgtable_64.c
index b1da03165496..ac64f4aaa509 100644
--- a/arch/powerpc/mm/pgtable_64.c
+++ b/arch/powerpc/mm/pgtable_64.c
@@ -63,32 +63,13 @@
#include <asm/iommu.h>
#include <asm/abs_addr.h>
#include <asm/vdso.h>
+#include <asm/firmware.h>
#include "mmu_decl.h"
unsigned long ioremap_bot = IMALLOC_BASE;
static unsigned long phbs_io_bot = PHBS_IO_BASE;
-#ifdef CONFIG_PPC_ISERIES
-
-void __iomem *ioremap(unsigned long addr, unsigned long size)
-{
- return (void __iomem *)addr;
-}
-
-extern void __iomem *__ioremap(unsigned long addr, unsigned long size,
- unsigned long flags)
-{
- return (void __iomem *)addr;
-}
-
-void iounmap(volatile void __iomem *addr)
-{
- return;
-}
-
-#else
-
/*
* map_io_page currently only called by __ioremap
* map_io_page adds an entry to the ioremap page table
@@ -161,6 +142,9 @@ void __iomem * __ioremap(unsigned long addr, unsigned long size,
unsigned long pa, ea;
void __iomem *ret;
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return (void __iomem *)addr;
+
/*
* Choose an address to map it to.
* Once the imalloc system is running, we use it.
@@ -255,6 +239,9 @@ void iounmap(volatile void __iomem *token)
{
void *addr;
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return;
+
if (!mem_init_done)
return;
@@ -315,8 +302,6 @@ int iounmap_explicit(volatile void __iomem *start, unsigned long size)
return 0;
}
-#endif
-
EXPORT_SYMBOL(ioremap);
EXPORT_SYMBOL(__ioremap);
EXPORT_SYMBOL(iounmap);
diff --git a/arch/powerpc/mm/slb_low.S b/arch/powerpc/mm/slb_low.S
index dbc1abbde038..b10e4707d7c1 100644
--- a/arch/powerpc/mm/slb_low.S
+++ b/arch/powerpc/mm/slb_low.S
@@ -21,6 +21,7 @@
#include <asm/page.h>
#include <asm/mmu.h>
#include <asm/pgtable.h>
+#include <asm/firmware.h>
/* void slb_allocate_realmode(unsigned long ea);
*
@@ -183,6 +184,7 @@ slb_finish_load:
* dont have any LRU information to help us choose a slot.
*/
#ifdef CONFIG_PPC_ISERIES
+BEGIN_FW_FTR_SECTION
/*
* On iSeries, the "bolted" stack segment can be cast out on
* shared processor switch so we need to check for a miss on
@@ -194,6 +196,7 @@ slb_finish_load:
li r10,SLB_NUM_BOLTED-1 /* Stack goes in last bolted slot */
cmpld r9,r3
beq 3f
+END_FW_FTR_SECTION_IFSET(FW_FEATURE_ISERIES)
#endif /* CONFIG_PPC_ISERIES */
ld r10,PACASTABRR(r13)
diff --git a/arch/powerpc/oprofile/backtrace.c b/arch/powerpc/oprofile/backtrace.c
index 75f57bc96b40..b4278cfd1f80 100644
--- a/arch/powerpc/oprofile/backtrace.c
+++ b/arch/powerpc/oprofile/backtrace.c
@@ -11,6 +11,7 @@
#include <linux/sched.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
+#include <asm/compat.h>
#define STACK_SP(STACK) *(STACK)
@@ -26,8 +27,9 @@
static unsigned int user_getsp32(unsigned int sp, int is_first)
{
unsigned int stack_frame[2];
+ void __user *p = compat_ptr(sp);
- if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
+ if (!access_ok(VERIFY_READ, p, sizeof(stack_frame)))
return 0;
/*
@@ -35,8 +37,7 @@ static unsigned int user_getsp32(unsigned int sp, int is_first)
* which means that we've done all that we can do from
* interrupt context.
*/
- if (__copy_from_user_inatomic(stack_frame, (void *)(long)sp,
- sizeof(stack_frame)))
+ if (__copy_from_user_inatomic(stack_frame, p, sizeof(stack_frame)))
return 0;
if (!is_first)
@@ -54,10 +55,10 @@ static unsigned long user_getsp64(unsigned long sp, int is_first)
{
unsigned long stack_frame[3];
- if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
+ if (!access_ok(VERIFY_READ, (void __user *)sp, sizeof(stack_frame)))
return 0;
- if (__copy_from_user_inatomic(stack_frame, (void *)sp,
+ if (__copy_from_user_inatomic(stack_frame, (void __user *)sp,
sizeof(stack_frame)))
return 0;
diff --git a/arch/powerpc/oprofile/op_model_7450.c b/arch/powerpc/oprofile/op_model_7450.c
index e0491c3c71f1..d8ee3aea83f8 100644
--- a/arch/powerpc/oprofile/op_model_7450.c
+++ b/arch/powerpc/oprofile/op_model_7450.c
@@ -1,5 +1,5 @@
/*
- * oprofile/op_model_7450.c
+ * arch/powerpc/oprofile/op_model_7450.c
*
* Freescale 745x/744x oprofile support, based on fsl_booke support
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
diff --git a/arch/powerpc/oprofile/op_model_fsl_booke.c b/arch/powerpc/oprofile/op_model_fsl_booke.c
index 93d63e62662f..e29dede31423 100644
--- a/arch/powerpc/oprofile/op_model_fsl_booke.c
+++ b/arch/powerpc/oprofile/op_model_fsl_booke.c
@@ -1,5 +1,5 @@
/*
- * oprofile/op_model_e500.c
+ * arch/powerpc/oprofile/op_model_fsl_booke.c
*
* Freescale Book-E oprofile support, based on ppc64 oprofile support
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
diff --git a/arch/powerpc/platforms/82xx/Kconfig b/arch/powerpc/platforms/82xx/Kconfig
new file mode 100644
index 000000000000..47d841ecf2e2
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/Kconfig
@@ -0,0 +1,21 @@
+menu "Platform support"
+ depends on PPC_82xx
+
+choice
+ prompt "Machine Type"
+ default MPC82xx_ADS
+
+config MPC82xx_ADS
+ bool "Freescale MPC82xx ADS"
+ select DEFAULT_UIMAGE
+ select PQ2ADS
+ select 8272
+ select 8260
+ select CPM2
+ select FSL_SOC
+ help
+ This option enables support for the MPC8272 ADS board
+
+endchoice
+
+endmenu
diff --git a/arch/powerpc/platforms/82xx/Makefile b/arch/powerpc/platforms/82xx/Makefile
new file mode 100644
index 000000000000..d9fd4c84d2e0
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the PowerPC 82xx linux kernel.
+#
+obj-$(CONFIG_PPC_82xx) += mpc82xx.o
+obj-$(CONFIG_MPC82xx_ADS) += mpc82xx_ads.o
diff --git a/arch/powerpc/platforms/82xx/m82xx_pci.h b/arch/powerpc/platforms/82xx/m82xx_pci.h
new file mode 100644
index 000000000000..9cd8893b5a32
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/m82xx_pci.h
@@ -0,0 +1,19 @@
+#ifndef _PPC_KERNEL_M82XX_PCI_H
+#define _PPC_KERNEL_M82XX_PCI_H
+
+/*
+ * 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 <asm/m8260_pci.h>
+
+#define SIU_INT_IRQ1 ((uint)0x13 + CPM_IRQ_OFFSET)
+
+#ifndef _IO_BASE
+#define _IO_BASE isa_io_base
+#endif
+
+#endif /* _PPC_KERNEL_M8260_PCI_H */
diff --git a/arch/powerpc/platforms/82xx/mpc82xx.c b/arch/powerpc/platforms/82xx/mpc82xx.c
new file mode 100644
index 000000000000..0f5b30dc60da
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/mpc82xx.c
@@ -0,0 +1,110 @@
+/*
+ * MPC82xx setup and early boot code plus other random bits.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Copyright (c) 2006 MontaVista Software, Inc.
+ *
+ * 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+#include <linux/fs_uart_pd.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc8260.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/cpm2.h>
+#include <asm/udbg.h>
+#include <asm/i8259.h>
+#include <linux/fs_enet_pd.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/cpm2_pic.h>
+
+#include "pq2ads_pd.h"
+
+static int __init get_freq(char *name, unsigned long *val)
+{
+ struct device_node *cpu;
+ unsigned int *fp;
+ int found = 0;
+
+ /* The cpu node should have timebase and clock frequency properties */
+ cpu = of_find_node_by_type(NULL, "cpu");
+
+ if (cpu) {
+ fp = (unsigned int *)get_property(cpu, name, NULL);
+ if (fp) {
+ found = 1;
+ *val = *fp++;
+ }
+
+ of_node_put(cpu);
+ }
+
+ return found;
+}
+
+void __init m82xx_calibrate_decr(void)
+{
+ ppc_tb_freq = 125000000;
+ if (!get_freq("bus-frequency", &ppc_tb_freq)) {
+ printk(KERN_ERR "WARNING: Estimating decrementer frequency "
+ "(not found)\n");
+ }
+ ppc_tb_freq /= 4;
+ ppc_proc_freq = 1000000000;
+ if (!get_freq("clock-frequency", &ppc_proc_freq))
+ printk(KERN_ERR "WARNING: Estimating processor frequency"
+ "(not found)\n");
+}
+
+void mpc82xx_ads_show_cpuinfo(struct seq_file *m)
+{
+ uint pvid, svid, phid1;
+ uint memsize = total_memory;
+
+ pvid = mfspr(SPRN_PVR);
+ svid = mfspr(SPRN_SVR);
+
+ seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+ seq_printf(m, "Machine\t\t: %s\n", CPUINFO_MACHINE);
+ seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+ seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+
+ /* Display cpu Pll setting */
+ phid1 = mfspr(SPRN_HID1);
+ seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+ /* Display the amount of memory */
+ seq_printf(m, "Memory\t\t: %d MB\n", memsize / (1024 * 1024));
+}
diff --git a/arch/powerpc/platforms/82xx/mpc82xx_ads.c b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
new file mode 100644
index 000000000000..bb9acbb98176
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/mpc82xx_ads.c
@@ -0,0 +1,658 @@
+/*
+ * MPC82xx_ads setup and early boot code plus other random bits.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ * m82xx_restart fix by Wade Farnsworth <wfarnsworth@mvista.com>
+ *
+ * Copyright (c) 2006 MontaVista Software, Inc.
+ *
+ * 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/fsl_devices.h>
+#include <linux/fs_uart_pd.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/bootinfo.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc8260.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/cpm2.h>
+#include <asm/udbg.h>
+#include <asm/i8259.h>
+#include <linux/fs_enet_pd.h>
+
+#include <sysdev/fsl_soc.h>
+#include <../sysdev/cpm2_pic.h>
+
+#include "pq2ads_pd.h"
+
+#ifdef CONFIG_PCI
+static uint pci_clk_frq;
+static struct {
+ unsigned long *pci_int_stat_reg;
+ unsigned long *pci_int_mask_reg;
+} pci_regs;
+
+static unsigned long pci_int_base;
+static struct irq_host *pci_pic_host;
+static struct device_node *pci_pic_node;
+#endif
+
+static void __init mpc82xx_ads_pic_init(void)
+{
+ struct device_node *np = of_find_compatible_node(NULL, "cpm-pic", "CPM2");
+ struct resource r;
+ cpm2_map_t *cpm_reg;
+
+ if (np == NULL) {
+ printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
+ return;
+ }
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_ERR "PIC init: invalid resource\n");
+ of_node_put(np);
+ return;
+ }
+ cpm2_pic_init(np);
+ of_node_put(np);
+
+ /* Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ cpm_reg = (cpm2_map_t *) ioremap(get_immrbase(), sizeof(cpm2_map_t));
+ cpm_reg->im_intctl.ic_siprr = 0x05309770;
+ iounmap(cpm_reg);
+#ifdef CONFIG_PCI
+ /* Initialize stuff for the 82xx CPLD IC and install demux */
+ m82xx_pci_init_irq();
+#endif
+}
+
+static void init_fcc1_ioports(struct fs_platform_info *fpi)
+{
+ struct io_port *io;
+ u32 tempval;
+ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+ struct device_node *np;
+ struct resource r;
+ u32 *bcsr;
+
+ np = of_find_node_by_type(NULL, "memory");
+ if (!np) {
+ printk(KERN_INFO "No memory node in device tree\n");
+ return;
+ }
+ if (of_address_to_resource(np, 1, &r)) {
+ printk(KERN_INFO "No memory reg property [1] in devicetree\n");
+ return;
+ }
+ of_node_put(np);
+ bcsr = ioremap(r.start + 4, sizeof(u32));
+ io = &immap->im_ioport;
+
+ /* Enable the PHY */
+ clrbits32(bcsr, BCSR1_FETHIEN);
+ setbits32(bcsr, BCSR1_FETH_RST);
+
+ /* FCC1 pins are on port A/C. */
+ /* Configure port A and C pins for FCC1 Ethernet. */
+
+ tempval = in_be32(&io->iop_pdira);
+ tempval &= ~PA1_DIRA0;
+ tempval |= PA1_DIRA1;
+ out_be32(&io->iop_pdira, tempval);
+
+ tempval = in_be32(&io->iop_psora);
+ tempval &= ~PA1_PSORA0;
+ tempval |= PA1_PSORA1;
+ out_be32(&io->iop_psora, tempval);
+
+ setbits32(&io->iop_ppara, PA1_DIRA0 | PA1_DIRA1);
+
+ /* Alter clocks */
+ tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8);
+
+ clrbits32(&io->iop_psorc, tempval);
+ clrbits32(&io->iop_pdirc, tempval);
+ setbits32(&io->iop_pparc, tempval);
+
+ cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_rx, CPM_CLK_RX);
+ cpm2_clk_setup(CPM_CLK_FCC1, fpi->clk_tx, CPM_CLK_TX);
+
+ iounmap(bcsr);
+ iounmap(immap);
+}
+
+static void init_fcc2_ioports(struct fs_platform_info *fpi)
+{
+ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+ struct device_node *np;
+ struct resource r;
+ u32 *bcsr;
+
+ struct io_port *io;
+ u32 tempval;
+
+ np = of_find_node_by_type(NULL, "memory");
+ if (!np) {
+ printk(KERN_INFO "No memory node in device tree\n");
+ return;
+ }
+ if (of_address_to_resource(np, 1, &r)) {
+ printk(KERN_INFO "No memory reg property [1] in devicetree\n");
+ return;
+ }
+ of_node_put(np);
+ io = &immap->im_ioport;
+ bcsr = ioremap(r.start + 12, sizeof(u32));
+
+ /* Enable the PHY */
+ clrbits32(bcsr, BCSR3_FETHIEN2);
+ setbits32(bcsr, BCSR3_FETH2_RST);
+
+ /* FCC2 are port B/C. */
+ /* Configure port A and C pins for FCC2 Ethernet. */
+
+ tempval = in_be32(&io->iop_pdirb);
+ tempval &= ~PB2_DIRB0;
+ tempval |= PB2_DIRB1;
+ out_be32(&io->iop_pdirb, tempval);
+
+ tempval = in_be32(&io->iop_psorb);
+ tempval &= ~PB2_PSORB0;
+ tempval |= PB2_PSORB1;
+ out_be32(&io->iop_psorb, tempval);
+
+ setbits32(&io->iop_pparb, PB2_DIRB0 | PB2_DIRB1);
+
+ tempval = PC_CLK(fpi->clk_tx - 8) | PC_CLK(fpi->clk_rx - 8);
+
+ /* Alter clocks */
+ clrbits32(&io->iop_psorc, tempval);
+ clrbits32(&io->iop_pdirc, tempval);
+ setbits32(&io->iop_pparc, tempval);
+
+ cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_rx, CPM_CLK_RX);
+ cpm2_clk_setup(CPM_CLK_FCC2, fpi->clk_tx, CPM_CLK_TX);
+
+ iounmap(bcsr);
+ iounmap(immap);
+}
+
+void init_fcc_ioports(struct fs_platform_info *fpi)
+{
+ int fcc_no = fs_get_fcc_index(fpi->fs_no);
+
+ switch (fcc_no) {
+ case 0:
+ init_fcc1_ioports(fpi);
+ break;
+ case 1:
+ init_fcc2_ioports(fpi);
+ break;
+ default:
+ printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n");
+ return;
+ }
+}
+
+static void init_scc1_uart_ioports(struct fs_uart_platform_info *data)
+{
+ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+
+ /* SCC1 is only on port D */
+ setbits32(&immap->im_ioport.iop_ppard, 0x00000003);
+ clrbits32(&immap->im_ioport.iop_psord, 0x00000001);
+ setbits32(&immap->im_ioport.iop_psord, 0x00000002);
+ clrbits32(&immap->im_ioport.iop_pdird, 0x00000001);
+ setbits32(&immap->im_ioport.iop_pdird, 0x00000002);
+
+ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx)));
+ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx)));
+ setbits32(&immap->im_cpmux.cmx_scr,
+ ((data->clk_tx - 1) << (4 - data->clk_tx)));
+ setbits32(&immap->im_cpmux.cmx_scr,
+ ((data->clk_rx - 1) << (4 - data->clk_rx)));
+
+ iounmap(immap);
+}
+
+static void init_scc4_uart_ioports(struct fs_uart_platform_info *data)
+{
+ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+
+ setbits32(&immap->im_ioport.iop_ppard, 0x00000600);
+ clrbits32(&immap->im_ioport.iop_psord, 0x00000600);
+ clrbits32(&immap->im_ioport.iop_pdird, 0x00000200);
+ setbits32(&immap->im_ioport.iop_pdird, 0x00000400);
+
+ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000007 << (4 - data->clk_tx)));
+ clrbits32(&immap->im_cpmux.cmx_scr, (0x00000038 << (4 - data->clk_rx)));
+ setbits32(&immap->im_cpmux.cmx_scr,
+ ((data->clk_tx - 1) << (4 - data->clk_tx)));
+ setbits32(&immap->im_cpmux.cmx_scr,
+ ((data->clk_rx - 1) << (4 - data->clk_rx)));
+
+ iounmap(immap);
+}
+
+void init_scc_ioports(struct fs_uart_platform_info *data)
+{
+ int scc_no = fs_get_scc_index(data->fs_no);
+
+ switch (scc_no) {
+ case 0:
+ init_scc1_uart_ioports(data);
+ data->brg = data->clk_rx;
+ break;
+ case 3:
+ init_scc4_uart_ioports(data);
+ data->brg = data->clk_rx;
+ break;
+ default:
+ printk(KERN_ERR "init_scc_ioports: invalid SCC number\n");
+ return;
+ }
+}
+
+void __init m82xx_board_setup(void)
+{
+ cpm2_map_t *immap = ioremap(get_immrbase(), sizeof(cpm2_map_t));
+ struct device_node *np;
+ struct resource r;
+ u32 *bcsr;
+
+ np = of_find_node_by_type(NULL, "memory");
+ if (!np) {
+ printk(KERN_INFO "No memory node in device tree\n");
+ return;
+ }
+ if (of_address_to_resource(np, 1, &r)) {
+ printk(KERN_INFO "No memory reg property [1] in devicetree\n");
+ return;
+ }
+ of_node_put(np);
+ bcsr = ioremap(r.start + 4, sizeof(u32));
+ /* Enable the 2nd UART port */
+ clrbits32(bcsr, BCSR1_RS232_EN2);
+
+#ifdef CONFIG_SERIAL_CPM_SCC1
+ clrbits32((u32 *) & immap->im_scc[0].scc_sccm,
+ UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32((u32 *) & immap->im_scc[0].scc_gsmrl,
+ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC2
+ clrbits32((u32 *) & immap->im_scc[1].scc_sccm,
+ UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32((u32 *) & immap->im_scc[1].scc_gsmrl,
+ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC3
+ clrbits32((u32 *) & immap->im_scc[2].scc_sccm,
+ UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32((u32 *) & immap->im_scc[2].scc_gsmrl,
+ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+#ifdef CONFIG_SERIAL_CPM_SCC4
+ clrbits32((u32 *) & immap->im_scc[3].scc_sccm,
+ UART_SCCM_TX | UART_SCCM_RX);
+ clrbits32((u32 *) & immap->im_scc[3].scc_gsmrl,
+ SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+
+ iounmap(bcsr);
+ iounmap(immap);
+}
+
+#ifdef CONFIG_PCI
+static void m82xx_pci_mask_irq(unsigned int irq)
+{
+ int bit = irq - pci_int_base;
+
+ *pci_regs.pci_int_mask_reg |= (1 << (31 - bit));
+ return;
+}
+
+static void m82xx_pci_unmask_irq(unsigned int irq)
+{
+ int bit = irq - pci_int_base;
+
+ *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit));
+ return;
+}
+
+static void m82xx_pci_mask_and_ack(unsigned int irq)
+{
+ int bit = irq - pci_int_base;
+
+ *pci_regs.pci_int_mask_reg |= (1 << (31 - bit));
+ return;
+}
+
+static void m82xx_pci_end_irq(unsigned int irq)
+{
+ int bit = irq - pci_int_base;
+
+ *pci_regs.pci_int_mask_reg &= ~(1 << (31 - bit));
+ return;
+}
+
+struct hw_interrupt_type m82xx_pci_ic = {
+ .typename = "MPC82xx ADS PCI",
+ .name = "MPC82xx ADS PCI",
+ .enable = m82xx_pci_unmask_irq,
+ .disable = m82xx_pci_mask_irq,
+ .ack = m82xx_pci_mask_and_ack,
+ .end = m82xx_pci_end_irq,
+ .mask = m82xx_pci_mask_irq,
+ .mask_ack = m82xx_pci_mask_and_ack,
+ .unmask = m82xx_pci_unmask_irq,
+ .eoi = m82xx_pci_end_irq,
+};
+
+static void
+m82xx_pci_irq_demux(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned long stat, mask, pend;
+ int bit;
+
+ for (;;) {
+ stat = *pci_regs.pci_int_stat_reg;
+ mask = *pci_regs.pci_int_mask_reg;
+ pend = stat & ~mask & 0xf0000000;
+ if (!pend)
+ break;
+ for (bit = 0; pend != 0; ++bit, pend <<= 1) {
+ if (pend & 0x80000000)
+ __do_IRQ(pci_int_base + bit);
+ }
+ }
+}
+
+static int pci_pic_host_match(struct irq_host *h, struct device_node *node)
+{
+ return node == pci_pic_node;
+}
+
+static int pci_pic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ get_irq_desc(virq)->status |= IRQ_LEVEL;
+ set_irq_chip(virq, &m82xx_pci_ic);
+ return 0;
+}
+
+static void pci_host_unmap(struct irq_host *h, unsigned int virq)
+{
+ /* remove chip and handler */
+ set_irq_chip(virq, NULL);
+}
+
+static struct irq_host_ops pci_pic_host_ops = {
+ .match = pci_pic_host_match,
+ .map = pci_pic_host_map,
+ .unmap = pci_host_unmap,
+};
+
+void m82xx_pci_init_irq(void)
+{
+ int irq;
+ cpm2_map_t *immap;
+ struct device_node *np;
+ struct resource r;
+ const u32 *regs;
+ unsigned int size;
+ const u32 *irq_map;
+ int i;
+ unsigned int irq_max, irq_min;
+
+ if ((np = of_find_node_by_type(NULL, "soc")) == NULL) {
+ printk(KERN_INFO "No SOC node in device tree\n");
+ return;
+ }
+ memset(&r, 0, sizeof(r));
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_INFO "No SOC reg property in device tree\n");
+ return;
+ }
+ immap = ioremap(r.start, sizeof(*immap));
+ of_node_put(np);
+
+ /* install the demultiplexer for the PCI cascade interrupt */
+ np = of_find_node_by_type(NULL, "pci");
+ if (!np) {
+ printk(KERN_INFO "No pci node on device tree\n");
+ iounmap(immap);
+ return;
+ }
+ irq_map = get_property(np, "interrupt-map", &size);
+ if ((!irq_map) || (size <= 7)) {
+ printk(KERN_INFO "No interrupt-map property of pci node\n");
+ iounmap(immap);
+ return;
+ }
+ size /= sizeof(irq_map[0]);
+ for (i = 0, irq_max = 0, irq_min = 512; i < size; i += 7, irq_map += 7) {
+ if (irq_map[5] < irq_min)
+ irq_min = irq_map[5];
+ if (irq_map[5] > irq_max)
+ irq_max = irq_map[5];
+ }
+ pci_int_base = irq_min;
+ irq = irq_of_parse_and_map(np, 0);
+ set_irq_chained_handler(irq, m82xx_pci_irq_demux);
+ of_node_put(np);
+ np = of_find_node_by_type(NULL, "pci-pic");
+ if (!np) {
+ printk(KERN_INFO "No pci pic node on device tree\n");
+ iounmap(immap);
+ return;
+ }
+ pci_pic_node = of_node_get(np);
+ /* PCI interrupt controller registers: status and mask */
+ regs = get_property(np, "reg", &size);
+ if ((!regs) || (size <= 2)) {
+ printk(KERN_INFO "No reg property in pci pic node\n");
+ iounmap(immap);
+ return;
+ }
+ pci_regs.pci_int_stat_reg =
+ ioremap(regs[0], sizeof(*pci_regs.pci_int_stat_reg));
+ pci_regs.pci_int_mask_reg =
+ ioremap(regs[1], sizeof(*pci_regs.pci_int_mask_reg));
+ of_node_put(np);
+ /* configure chip select for PCI interrupt controller */
+ immap->im_memctl.memc_br3 = regs[0] | 0x00001801;
+ immap->im_memctl.memc_or3 = 0xffff8010;
+ /* make PCI IRQ level sensitive */
+ immap->im_intctl.ic_siexr &= ~(1 << (14 - (irq - SIU_INT_IRQ1)));
+
+ /* mask all PCI interrupts */
+ *pci_regs.pci_int_mask_reg |= 0xfff00000;
+ iounmap(immap);
+ pci_pic_host =
+ irq_alloc_host(IRQ_HOST_MAP_LINEAR, irq_max - irq_min + 1,
+ &pci_pic_host_ops, irq_max + 1);
+ return;
+}
+
+static int m82xx_pci_exclude_device(u_char bus, u_char devfn)
+{
+ if (bus == 0 && PCI_SLOT(devfn) == 0)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ else
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static void
+__init mpc82xx_pcibios_fixup(void)
+{
+ struct pci_dev *dev = NULL;
+
+ for_each_pci_dev(dev) {
+ pci_read_irq_line(dev);
+ }
+}
+
+void __init add_bridge(struct device_node *np)
+{
+ int len;
+ struct pci_controller *hose;
+ struct resource r;
+ const int *bus_range;
+ const void *ptr;
+
+ memset(&r, 0, sizeof(r));
+ if (of_address_to_resource(np, 0, &r)) {
+ printk(KERN_INFO "No PCI reg property in device tree\n");
+ return;
+ }
+ if (!(ptr = get_property(np, "clock-frequency", NULL))) {
+ printk(KERN_INFO "No clock-frequency property in PCI node");
+ return;
+ }
+ pci_clk_frq = *(uint *) ptr;
+ of_node_put(np);
+ bus_range = get_property(np, "bus-range", &len);
+ if (bus_range == NULL || len < 2 * sizeof(int)) {
+ printk(KERN_WARNING "Can't get bus-range for %s, assume"
+ " bus 0\n", np->full_name);
+ }
+
+ pci_assign_all_buses = 1;
+
+ hose = pcibios_alloc_controller();
+
+ if (!hose)
+ return;
+
+ hose->arch_data = np;
+ hose->set_cfg_type = 1;
+
+ hose->first_busno = bus_range ? bus_range[0] : 0;
+ hose->last_busno = bus_range ? bus_range[1] : 0xff;
+ hose->bus_offset = 0;
+
+ hose->set_cfg_type = 1;
+
+ setup_indirect_pci(hose,
+ r.start + offsetof(pci_cpm2_t, pci_cfg_addr),
+ r.start + offsetof(pci_cpm2_t, pci_cfg_data));
+
+ pci_process_bridge_OF_ranges(hose, np, 1);
+}
+#endif
+
+/*
+ * Setup the architecture
+ */
+static void __init mpc82xx_ads_setup_arch(void)
+{
+#ifdef CONFIG_PCI
+ struct device_node *np;
+#endif
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc82xx_ads_setup_arch()", 0);
+ cpm2_reset();
+
+ /* Map I/O region to a 256MB BAT */
+
+ m82xx_board_setup();
+
+#ifdef CONFIG_PCI
+ ppc_md.pci_exclude_device = m82xx_pci_exclude_device;
+ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+ add_bridge(np);
+
+ of_node_put(np);
+ ppc_md.pci_map_irq = NULL;
+ ppc_md.pcibios_fixup = mpc82xx_pcibios_fixup;
+ ppc_md.pcibios_fixup_bus = NULL;
+#endif
+
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc82xx_ads_setup_arch(), finish", 0);
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mpc82xx_ads_probe(void)
+{
+ /* We always match for now, eventually we should look at
+ * the flat dev tree to ensure this is the board we are
+ * supposed to run on
+ */
+ return 1;
+}
+
+#define RMR_CSRE 0x00000001
+static void m82xx_restart(char *cmd)
+{
+ __volatile__ unsigned char dummy;
+
+ local_irq_disable();
+ ((cpm2_map_t *) cpm2_immr)->im_clkrst.car_rmr |= RMR_CSRE;
+
+ /* Clear the ME,EE,IR & DR bits in MSR to cause checkstop */
+ mtmsr(mfmsr() & ~(MSR_ME | MSR_EE | MSR_IR | MSR_DR));
+ dummy = ((cpm2_map_t *) cpm2_immr)->im_clkrst.res[0];
+ printk("Restart failed\n");
+ while (1) ;
+}
+
+static void m82xx_halt(void)
+{
+ local_irq_disable();
+ while (1) ;
+}
+
+define_machine(mpc82xx_ads)
+{
+ .name = "MPC82xx ADS",
+ .probe = mpc82xx_ads_probe,
+ .setup_arch = mpc82xx_ads_setup_arch,
+ .init_IRQ = mpc82xx_ads_pic_init,
+ .show_cpuinfo = mpc82xx_ads_show_cpuinfo,
+ .get_irq = cpm2_get_irq,
+ .calibrate_decr = m82xx_calibrate_decr,
+ .restart = m82xx_restart,.halt = m82xx_halt,
+};
diff --git a/arch/powerpc/platforms/82xx/pq2ads.h b/arch/powerpc/platforms/82xx/pq2ads.h
new file mode 100644
index 000000000000..fb2f92bcd770
--- /dev/null
+++ b/arch/powerpc/platforms/82xx/pq2ads.h
@@ -0,0 +1,65 @@
+/*
+ * PQ2/mpc8260 board-specific stuff
+ *
+ * A collection of structures, addresses, and values associated with
+ * the Freescale MPC8260ADS/MPC8266ADS-PCI boards.
+ * Copied from the RPX-Classic and SBS8260 stuff.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * Originally written by Dan Malek for Motorola MPC8260 family
+ *
+ * Copyright (c) 2001 Dan Malek <dan@embeddedalley.com>
+ * Copyright (c) 2006 MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __MACH_ADS8260_DEFS
+#define __MACH_ADS8260_DEFS
+
+#include <asm/ppcboot.h>
+
+/* For our show_cpuinfo hooks. */
+#define CPUINFO_VENDOR "Freescale Semiconductor"
+#define CPUINFO_MACHINE "PQ2 ADS PowerPC"
+
+/* Backword-compatibility stuff for the drivers */
+#define CPM_MAP_ADDR ((uint)0xf0000000)
+#define CPM_IRQ_OFFSET 0
+
+/* The ADS8260 has 16, 32-bit wide control/status registers, accessed
+ * only on word boundaries.
+ * Not all are used (yet), or are interesting to us (yet).
+ */
+
+/* Things of interest in the CSR.
+ */
+#define BCSR0_LED0 ((uint)0x02000000) /* 0 == on */
+#define BCSR0_LED1 ((uint)0x01000000) /* 0 == on */
+#define BCSR1_FETHIEN ((uint)0x08000000) /* 0 == enable*/
+#define BCSR1_FETH_RST ((uint)0x04000000) /* 0 == reset */
+#define BCSR1_RS232_EN1 ((uint)0x02000000) /* 0 ==enable */
+#define BCSR1_RS232_EN2 ((uint)0x01000000) /* 0 ==enable */
+#define BCSR3_FETHIEN2 ((uint)0x10000000) /* 0 == enable*/
+#define BCSR3_FETH2_RS ((uint)0x80000000) /* 0 == reset */
+
+/* cpm serial driver works with constants below */
+
+#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET)
+#define SIU_INT_SMC2i ((uint)0x05+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET)
+
+void m82xx_pci_init_irq(void);
+void mpc82xx_ads_show_cpuinfo(struct seq_file*);
+void m82xx_calibrate_decr(void);
+
+#endif /* __MACH_ADS8260_DEFS */
+#endif /* __KERNEL__ */
diff --git a/arch/powerpc/platforms/83xx/Kconfig b/arch/powerpc/platforms/83xx/Kconfig
index 5fe7b7faf45f..7edb6b461382 100644
--- a/arch/powerpc/platforms/83xx/Kconfig
+++ b/arch/powerpc/platforms/83xx/Kconfig
@@ -5,6 +5,13 @@ choice
prompt "Machine Type"
default MPC834x_SYS
+config MPC832x_MDS
+ bool "Freescale MPC832x MDS"
+ select DEFAULT_UIMAGE
+ select QUICC_ENGINE
+ help
+ This option enables support for the MPC832x MDS evaluation board.
+
config MPC834x_SYS
bool "Freescale MPC834x SYS"
select DEFAULT_UIMAGE
@@ -25,12 +32,31 @@ config MPC834x_ITX
Be aware that PCI initialization is the bootloader's
responsiblilty.
+config MPC8360E_PB
+ bool "Freescale MPC8360E PB"
+ select DEFAULT_UIMAGE
+ select QUICC_ENGINE
+ help
+ This option enables support for the MPC836x EMDS Processor Board.
+
endchoice
+config PPC_MPC832x
+ bool
+ select PPC_UDBG_16550
+ select PPC_INDIRECT_PCI
+ default y if MPC832x_MDS
+
config MPC834x
bool
select PPC_UDBG_16550
select PPC_INDIRECT_PCI
default y if MPC834x_SYS || MPC834x_ITX
+config PPC_MPC836x
+ bool
+ select PPC_UDBG_16550
+ select PPC_INDIRECT_PCI
+ default y if MPC8360E_PB
+
endmenu
diff --git a/arch/powerpc/platforms/83xx/Makefile b/arch/powerpc/platforms/83xx/Makefile
index 9387a110d28a..f1aa7e24a938 100644
--- a/arch/powerpc/platforms/83xx/Makefile
+++ b/arch/powerpc/platforms/83xx/Makefile
@@ -5,3 +5,5 @@ obj-y := misc.o
obj-$(CONFIG_PCI) += pci.o
obj-$(CONFIG_MPC834x_SYS) += mpc834x_sys.o
obj-$(CONFIG_MPC834x_ITX) += mpc834x_itx.o
+obj-$(CONFIG_MPC8360E_PB) += mpc8360e_pb.o
+obj-$(CONFIG_MPC832x_MDS) += mpc832x_mds.o
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
new file mode 100644
index 000000000000..54dea9d42dc9
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Description:
+ * MPC832xE MDS board specific routines.
+ *
+ * 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+
+#include "mpc83xx.h"
+#include "mpc832x_mds.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+static u8 *bcsr_regs = NULL;
+
+u8 *get_bcsr(void)
+{
+ return bcsr_regs;
+}
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init mpc832x_sys_setup_arch(void)
+{
+ struct device_node *np;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc832x_sys_setup_arch()", 0);
+
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np != 0) {
+ unsigned int *fp =
+ (int *)get_property(np, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 50000000 / HZ;
+ of_node_put(np);
+ }
+
+ /* Map BCSR area */
+ np = of_find_node_by_name(NULL, "bcsr");
+ if (np != 0) {
+ struct resource res;
+
+ of_address_to_resource(np, 0, &res);
+ bcsr_regs = ioremap(res.start, res.end - res.start +1);
+ of_node_put(np);
+ }
+
+#ifdef CONFIG_PCI
+ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+ add_bridge(np);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef CONFIG_QUICC_ENGINE
+ qe_reset();
+
+ if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+ par_io_init(np);
+ of_node_put(np);
+
+ for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
+ par_io_of_config(np);
+ }
+
+ if ((np = of_find_compatible_node(NULL, "network", "ucc_geth"))
+ != NULL){
+ /* Reset the Ethernet PHY */
+ bcsr_regs[9] &= ~0x20;
+ udelay(1000);
+ bcsr_regs[9] |= 0x20;
+ iounmap(bcsr_regs);
+ of_node_put(np);
+ }
+
+#endif /* CONFIG_QUICC_ENGINE */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+void __init mpc832x_sys_init_IRQ(void)
+{
+
+ struct device_node *np;
+
+ np = of_find_node_by_type(NULL, "ipic");
+ if (!np)
+ return;
+
+ ipic_init(np, 0);
+
+ /* Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ ipic_set_default_priority();
+ of_node_put(np);
+
+#ifdef CONFIG_QUICC_ENGINE
+ np = of_find_node_by_type(NULL, "qeic");
+ if (!np)
+ return;
+
+ qe_ic_init(np, 0);
+ of_node_put(np);
+#endif /* CONFIG_QUICC_ENGINE */
+}
+
+#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+extern ulong ds1374_get_rtc_time(void);
+extern int ds1374_set_rtc_time(ulong);
+
+static int __init mpc832x_rtc_hookup(void)
+{
+ struct timespec tv;
+
+ ppc_md.get_rtc_time = ds1374_get_rtc_time;
+ ppc_md.set_rtc_time = ds1374_set_rtc_time;
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = (ppc_md.get_rtc_time) ();
+ do_settimeofday(&tv);
+
+ return 0;
+}
+
+late_initcall(mpc832x_rtc_hookup);
+#endif
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc832x_sys_probe(void)
+{
+ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "model", NULL);
+
+ if (model == NULL)
+ return 0;
+ if (strcmp(model, "MPC8323EMDS"))
+ return 0;
+
+ DBG("%s found\n", model);
+
+ return 1;
+}
+
+define_machine(mpc832x_mds) {
+ .name = "MPC832x MDS",
+ .probe = mpc832x_sys_probe,
+ .setup_arch = mpc832x_sys_setup_arch,
+ .init_IRQ = mpc832x_sys_init_IRQ,
+ .get_irq = ipic_get_irq,
+ .restart = mpc83xx_restart,
+ .time_init = mpc83xx_time_init,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.h b/arch/powerpc/platforms/83xx/mpc832x_mds.h
new file mode 100644
index 000000000000..a49588904f8a
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Description:
+ * MPC832x MDS board specific header.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MACH_MPC832x_MDS_H__
+#define __MACH_MPC832x_MDS_H__
+
+extern u8 *get_bcsr(void);
+
+#endif /* __MACH_MPC832x_MDS_H__ */
diff --git a/arch/powerpc/platforms/83xx/mpc834x_itx.c b/arch/powerpc/platforms/83xx/mpc834x_itx.c
index 969fbb6d8c46..5446bab08eca 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_itx.c
+++ b/arch/powerpc/platforms/83xx/mpc834x_itx.c
@@ -11,7 +11,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -109,6 +108,10 @@ static int __init mpc834x_itx_probe(void)
return 1;
}
+#ifdef CONFIG_RTC_CLASS
+late_initcall(rtc_class_hookup);
+#endif
+
define_machine(mpc834x_itx) {
.name = "MPC834x ITX",
.probe = mpc834x_itx_probe,
diff --git a/arch/powerpc/platforms/83xx/mpc834x_sys.h b/arch/powerpc/platforms/83xx/mpc834x_sys.h
index fedecb73f7ff..7d5bbef084e7 100644
--- a/arch/powerpc/platforms/83xx/mpc834x_sys.h
+++ b/arch/powerpc/platforms/83xx/mpc834x_sys.h
@@ -1,5 +1,5 @@
/*
- * arch/powerppc/platforms/83xx/mpc834x_sys.h
+ * arch/powerpc/platforms/83xx/mpc834x_sys.h
*
* MPC834X SYS common board definitions
*
diff --git a/arch/powerpc/platforms/83xx/mpc8360e_pb.c b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
new file mode 100644
index 000000000000..1a523c81c06e
--- /dev/null
+++ b/arch/powerpc/platforms/83xx/mpc8360e_pb.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Li Yang <LeoLi@freescale.com>
+ * Yin Olivia <Hong-hua.Yin@freescale.com>
+ *
+ * Description:
+ * MPC8360E MDS PB board specific routines.
+ *
+ * Changelog:
+ * Jun 21, 2006 Initial version
+ *
+ * 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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+#include <linux/initrd.h>
+
+#include <asm/of_device.h>
+#include <asm/system.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/ipic.h>
+#include <asm/bootinfo.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/udbg.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+
+#include "mpc83xx.h"
+
+#undef DEBUG
+#ifdef DEBUG
+#define DBG(fmt...) udbg_printf(fmt)
+#else
+#define DBG(fmt...)
+#endif
+
+#ifndef CONFIG_PCI
+unsigned long isa_io_base = 0;
+unsigned long isa_mem_base = 0;
+#endif
+
+static u8 *bcsr_regs = NULL;
+
+u8 *get_bcsr(void)
+{
+ return bcsr_regs;
+}
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init mpc8360_sys_setup_arch(void)
+{
+ struct device_node *np;
+
+ if (ppc_md.progress)
+ ppc_md.progress("mpc8360_sys_setup_arch()", 0);
+
+ np = of_find_node_by_type(NULL, "cpu");
+ if (np != 0) {
+ const unsigned int *fp =
+ get_property(np, "clock-frequency", NULL);
+ if (fp != 0)
+ loops_per_jiffy = *fp / HZ;
+ else
+ loops_per_jiffy = 50000000 / HZ;
+ of_node_put(np);
+ }
+
+ /* Map BCSR area */
+ np = of_find_node_by_name(NULL, "bcsr");
+ if (np != 0) {
+ struct resource res;
+
+ of_address_to_resource(np, 0, &res);
+ bcsr_regs = ioremap(res.start, res.end - res.start +1);
+ of_node_put(np);
+ }
+
+#ifdef CONFIG_PCI
+ for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
+ add_bridge(np);
+
+ ppc_md.pci_swizzle = common_swizzle;
+ ppc_md.pci_exclude_device = mpc83xx_exclude_device;
+#endif
+
+#ifdef CONFIG_QUICC_ENGINE
+ qe_reset();
+
+ if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
+ par_io_init(np);
+ of_node_put(np);
+
+ for (np = NULL; (np = of_find_node_by_name(np, "ucc")) != NULL;)
+ par_io_of_config(np);
+ }
+
+ if ((np = of_find_compatible_node(NULL, "network", "ucc_geth"))
+ != NULL){
+ /* Reset the Ethernet PHY */
+ bcsr_regs[9] &= ~0x20;
+ udelay(1000);
+ bcsr_regs[9] |= 0x20;
+ iounmap(bcsr_regs);
+ of_node_put(np);
+ }
+
+#endif /* CONFIG_QUICC_ENGINE */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start)
+ ROOT_DEV = Root_RAM0;
+ else
+#endif
+#ifdef CONFIG_ROOT_NFS
+ ROOT_DEV = Root_NFS;
+#else
+ ROOT_DEV = Root_HDA1;
+#endif
+}
+
+static int __init mpc8360_declare_of_platform_devices(void)
+{
+ struct device_node *np;
+
+ for (np = NULL; (np = of_find_compatible_node(np, "network",
+ "ucc_geth")) != NULL;) {
+ int ucc_num;
+ char bus_id[BUS_ID_SIZE];
+
+ ucc_num = *((uint *) get_property(np, "device-id", NULL)) - 1;
+ snprintf(bus_id, BUS_ID_SIZE, "ucc_geth.%u", ucc_num);
+ of_platform_device_create(np, bus_id, NULL);
+ }
+
+ return 0;
+}
+device_initcall(mpc8360_declare_of_platform_devices);
+
+void __init mpc8360_sys_init_IRQ(void)
+{
+
+ struct device_node *np;
+
+ np = of_find_node_by_type(NULL, "ipic");
+ if (!np)
+ return;
+
+ ipic_init(np, 0);
+
+ /* Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ ipic_set_default_priority();
+ of_node_put(np);
+
+#ifdef CONFIG_QUICC_ENGINE
+ np = of_find_node_by_type(NULL, "qeic");
+ if (!np)
+ return;
+
+ qe_ic_init(np, 0);
+ of_node_put(np);
+#endif /* CONFIG_QUICC_ENGINE */
+}
+
+#if defined(CONFIG_I2C_MPC) && defined(CONFIG_SENSORS_DS1374)
+extern ulong ds1374_get_rtc_time(void);
+extern int ds1374_set_rtc_time(ulong);
+
+static int __init mpc8360_rtc_hookup(void)
+{
+ struct timespec tv;
+
+ ppc_md.get_rtc_time = ds1374_get_rtc_time;
+ ppc_md.set_rtc_time = ds1374_set_rtc_time;
+
+ tv.tv_nsec = 0;
+ tv.tv_sec = (ppc_md.get_rtc_time) ();
+ do_settimeofday(&tv);
+
+ return 0;
+}
+
+late_initcall(mpc8360_rtc_hookup);
+#endif
+
+/*
+ * Called very early, MMU is off, device-tree isn't unflattened
+ */
+static int __init mpc8360_sys_probe(void)
+{
+ char *model = of_get_flat_dt_prop(of_get_flat_dt_root(),
+ "model", NULL);
+ if (model == NULL)
+ return 0;
+ if (strcmp(model, "MPC8360EPB"))
+ return 0;
+
+ DBG("MPC8360EMDS-PB found\n");
+
+ return 1;
+}
+
+define_machine(mpc8360_sys) {
+ .name = "MPC8360E PB",
+ .probe = mpc8360_sys_probe,
+ .setup_arch = mpc8360_sys_setup_arch,
+ .init_IRQ = mpc8360_sys_init_IRQ,
+ .get_irq = ipic_get_irq,
+ .restart = mpc83xx_restart,
+ .time_init = mpc83xx_time_init,
+ .calibrate_decr = generic_calibrate_decr,
+ .progress = udbg_progress,
+};
diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index c3268d9877e4..0584f3c7e884 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -11,6 +11,12 @@ config MPC8540_ADS
help
This option enables support for the MPC 8540 ADS board
+config MPC8560_ADS
+ bool "Freescale MPC8560 ADS"
+ select DEFAULT_UIMAGE
+ help
+ This option enables support for the MPC 8560 ADS board
+
config MPC85xx_CDS
bool "Freescale MPC85xx CDS"
select DEFAULT_UIMAGE
@@ -25,6 +31,11 @@ config MPC8540
select PPC_INDIRECT_PCI
default y if MPC8540_ADS || MPC85xx_CDS
+config MPC8560
+ bool
+ select PPC_INDIRECT_PCI
+ default y if MPC8560_ADS
+
config PPC_INDIRECT_PCI_BE
bool
depends on PPC_85xx
@@ -34,4 +45,14 @@ config MPIC
bool
default y
+config CPM2
+ bool
+ depends on MPC8560
+ default y
+ help
+ The CPM2 (Communications Processor Module) is a coprocessor on
+ embedded CPUs made by Motorola. Selecting this option means that
+ you wish to build a kernel for a machine with a CPM2 coprocessor
+ on it.
+
endmenu
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 7615aa59c78b..282f5d0d0152 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -3,4 +3,5 @@
#
obj-$(CONFIG_PPC_85xx) += misc.o pci.o
obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
+obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
obj-$(CONFIG_MPC85xx_CDS) += mpc85xx_cds.o
diff --git a/arch/powerpc/platforms/85xx/mpc8540_ads.h b/arch/powerpc/platforms/85xx/mpc8540_ads.h
index c0d56d2bb5a5..da82f4c0fdac 100644
--- a/arch/powerpc/platforms/85xx/mpc8540_ads.h
+++ b/arch/powerpc/platforms/85xx/mpc8540_ads.h
@@ -1,5 +1,5 @@
/*
- * arch/ppc/platforms/85xx/mpc8540_ads.h
+ * arch/powerpc/platforms/85xx/mpc8540_ads.h
*
* MPC8540ADS board definitions
*
diff --git a/arch/powerpc/platforms/85xx/mpc85xx.h b/arch/powerpc/platforms/85xx/mpc85xx.h
index b44db6268f3d..83415db33378 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx.h
+++ b/arch/powerpc/platforms/85xx/mpc85xx.h
@@ -1,5 +1,5 @@
/*
- * arch/ppc/platforms/85xx/mpc85xx.h
+ * arch/powerpc/platforms/85xx/mpc85xx.h
*
* MPC85xx soc definitions/function decls
*
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.c b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
index cae6b73357d5..d3e669d69c73 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ads.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.c
@@ -32,6 +32,13 @@
#include <sysdev/fsl_soc.h>
#include "mpc85xx.h"
+#ifdef CONFIG_CPM2
+#include <linux/fs_enet_pd.h>
+#include <asm/cpm2.h>
+#include <sysdev/cpm2_pic.h>
+#include <asm/fs_pd.h>
+#endif
+
#ifndef CONFIG_PCI
unsigned long isa_io_base = 0;
unsigned long isa_mem_base = 0;
@@ -57,12 +64,28 @@ mpc85xx_pcibios_fixup(void)
}
#endif /* CONFIG_PCI */
+#ifdef CONFIG_CPM2
+
+static void cpm2_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ int cascade_irq;
+
+ while ((cascade_irq = cpm2_get_irq()) >= 0) {
+ generic_handle_irq(cascade_irq);
+ }
+ desc->chip->eoi(irq);
+}
+
+#endif /* CONFIG_CPM2 */
void __init mpc85xx_ads_pic_init(void)
{
struct mpic *mpic;
struct resource r;
struct device_node *np = NULL;
+#ifdef CONFIG_CPM2
+ int irq;
+#endif
np = of_find_node_by_type(np, "open-pic");
@@ -104,11 +127,103 @@ void __init mpc85xx_ads_pic_init(void)
mpic_assign_isu(mpic, 14, r.start + 0x10100);
mpic_init(mpic);
+
+#ifdef CONFIG_CPM2
+ /* Setup CPM2 PIC */
+ np = of_find_node_by_type(NULL, "cpm-pic");
+ if (np == NULL) {
+ printk(KERN_ERR "PIC init: can not find cpm-pic node\n");
+ return;
+ }
+ irq = irq_of_parse_and_map(np, 0);
+
+ cpm2_pic_init(np);
+ set_irq_chained_handler(irq, cpm2_cascade);
+#endif
}
/*
* Setup the architecture
*/
+#ifdef CONFIG_CPM2
+void init_fcc_ioports(struct fs_platform_info *fpi)
+{
+ struct io_port *io = cpm2_map(im_ioport);
+ int fcc_no = fs_get_fcc_index(fpi->fs_no);
+ int target;
+ u32 tempval;
+
+ switch(fcc_no) {
+ case 1:
+ tempval = in_be32(&io->iop_pdirb);
+ tempval &= ~PB2_DIRB0;
+ tempval |= PB2_DIRB1;
+ out_be32(&io->iop_pdirb, tempval);
+
+ tempval = in_be32(&io->iop_psorb);
+ tempval &= ~PB2_PSORB0;
+ tempval |= PB2_PSORB1;
+ out_be32(&io->iop_psorb, tempval);
+
+ tempval = in_be32(&io->iop_pparb);
+ tempval |= (PB2_DIRB0 | PB2_DIRB1);
+ out_be32(&io->iop_pparb, tempval);
+
+ target = CPM_CLK_FCC2;
+ break;
+ case 2:
+ tempval = in_be32(&io->iop_pdirb);
+ tempval &= ~PB3_DIRB0;
+ tempval |= PB3_DIRB1;
+ out_be32(&io->iop_pdirb, tempval);
+
+ tempval = in_be32(&io->iop_psorb);
+ tempval &= ~PB3_PSORB0;
+ tempval |= PB3_PSORB1;
+ out_be32(&io->iop_psorb, tempval);
+
+ tempval = in_be32(&io->iop_pparb);
+ tempval |= (PB3_DIRB0 | PB3_DIRB1);
+ out_be32(&io->iop_pparb, tempval);
+
+ tempval = in_be32(&io->iop_pdirc);
+ tempval |= PC3_DIRC1;
+ out_be32(&io->iop_pdirc, tempval);
+
+ tempval = in_be32(&io->iop_pparc);
+ tempval |= PC3_DIRC1;
+ out_be32(&io->iop_pparc, tempval);
+
+ target = CPM_CLK_FCC3;
+ break;
+ default:
+ printk(KERN_ERR "init_fcc_ioports: invalid FCC number\n");
+ return;
+ }
+
+ /* Port C has clocks...... */
+ tempval = in_be32(&io->iop_psorc);
+ tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8));
+ out_be32(&io->iop_psorc, tempval);
+
+ tempval = in_be32(&io->iop_pdirc);
+ tempval &= ~(PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8));
+ out_be32(&io->iop_pdirc, tempval);
+ tempval = in_be32(&io->iop_pparc);
+ tempval |= (PC_CLK(fpi->clk_rx - 8) | PC_CLK(fpi->clk_tx - 8));
+ out_be32(&io->iop_pparc, tempval);
+
+ cpm2_unmap(io);
+
+ /* Configure Serial Interface clock routing.
+ * First, clear FCC bits to zero,
+ * then set the ones we want.
+ */
+ cpm2_clk_setup(target, fpi->clk_rx, CPM_CLK_RX);
+ cpm2_clk_setup(target, fpi->clk_tx, CPM_CLK_TX);
+}
+#endif
+
static void __init mpc85xx_ads_setup_arch(void)
{
struct device_node *cpu;
@@ -131,6 +246,10 @@ static void __init mpc85xx_ads_setup_arch(void)
of_node_put(cpu);
}
+#ifdef CONFIG_CPM2
+ cpm2_reset();
+#endif
+
#ifdef CONFIG_PCI
for (np = NULL; (np = of_find_node_by_type(np, "pci")) != NULL;)
add_bridge(np);
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ads.h b/arch/powerpc/platforms/85xx/mpc85xx_ads.h
new file mode 100644
index 000000000000..46c3532992aa
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ads.h
@@ -0,0 +1,60 @@
+/*
+ * MPC85xx ADS board definitions
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * Copyright 2004 Freescale Semiconductor Inc.
+ *
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.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.
+ *
+ */
+
+#ifndef __MACH_MPC85XXADS_H
+#define __MACH_MPC85XXADS_H
+
+#include <linux/initrd.h>
+#include <sysdev/fsl_soc.h>
+
+#define BCSR_ADDR ((uint)0xf8000000)
+#define BCSR_SIZE ((uint)(32 * 1024))
+
+#ifdef CONFIG_CPM2
+
+#define MPC85xx_CPM_OFFSET (0x80000)
+
+#define CPM_MAP_ADDR (get_immrbase() + MPC85xx_CPM_OFFSET)
+#define CPM_IRQ_OFFSET 60
+
+#define SIU_INT_SMC1 ((uint)0x04+CPM_IRQ_OFFSET)
+#define SIU_INT_SMC2 ((uint)0x05+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC1 ((uint)0x28+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC2 ((uint)0x29+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC3 ((uint)0x2a+CPM_IRQ_OFFSET)
+#define SIU_INT_SCC4 ((uint)0x2b+CPM_IRQ_OFFSET)
+
+/* FCC1 Clock Source Configuration. These can be
+ * redefined in the board specific file.
+ * Can only choose from CLK9-12 */
+#define F1_RXCLK 12
+#define F1_TXCLK 11
+
+/* FCC2 Clock Source Configuration. These can be
+ * redefined in the board specific file.
+ * Can only choose from CLK13-16 */
+#define F2_RXCLK 13
+#define F2_TXCLK 14
+
+/* FCC3 Clock Source Configuration. These can be
+ * redefined in the board specific file.
+ * Can only choose from CLK13-16 */
+#define F3_RXCLK 15
+#define F3_TXCLK 16
+
+#endif /* CONFIG_CPM2 */
+#endif /* __MACH_MPC85XXADS_H */
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.c b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
index 4c1fede6470e..953cd5dd3f54 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.c
@@ -11,7 +11,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -133,13 +132,12 @@ mpc85xx_cds_pcibios_fixup(void)
#ifdef CONFIG_PPC_I8259
#warning The i8259 PIC support is currently broken
-static void mpc85xx_8259_cascade(unsigned int irq, struct
- irq_desc *desc, struct pt_regs *regs)
+static void mpc85xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
- unsigned int cascade_irq = i8259_irq(regs);
+ unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ)
- generic_handle_irq(cascade_irq, regs);
+ generic_handle_irq(cascade_irq);
desc->chip->eoi(irq);
}
@@ -151,8 +149,10 @@ void __init mpc85xx_cds_pic_init(void)
struct mpic *mpic;
struct resource r;
struct device_node *np = NULL;
+#ifdef CONFIG_PPC_I8259
struct device_node *cascade_node = NULL;
int cascade_irq;
+#endif
np = of_find_node_by_type(np, "open-pic");
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_cds.h b/arch/powerpc/platforms/85xx/mpc85xx_cds.h
index 671f54ff185a..b251c9feb3dc 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_cds.h
+++ b/arch/powerpc/platforms/85xx/mpc85xx_cds.h
@@ -1,5 +1,5 @@
/*
- * arch/ppc/platforms/85xx/mpc85xx_cds_common.h
+ * arch/powerpc/platforms/85xx/mpc85xx_cds.h
*
* MPC85xx CDS board definitions
*
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index b637e8157f7b..1a1c226ad4d9 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -53,12 +53,11 @@ unsigned long pci_dram_offset = 0;
#ifdef CONFIG_PCI
-static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+static void mpc86xx_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
- unsigned int cascade_irq = i8259_irq(regs);
+ unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ)
- generic_handle_irq(cascade_irq, regs);
+ generic_handle_irq(cascade_irq);
desc->chip->eoi(irq);
}
#endif /* CONFIG_PCI */
diff --git a/arch/powerpc/platforms/cell/Kconfig b/arch/powerpc/platforms/cell/Kconfig
index 0c8c7b6ab897..3e430b489bb7 100644
--- a/arch/powerpc/platforms/cell/Kconfig
+++ b/arch/powerpc/platforms/cell/Kconfig
@@ -16,11 +16,6 @@ config SPU_BASE
bool
default n
-config SPUFS_MMAP
- bool
- depends on SPU_FS && SPARSEMEM
- default y
-
config CBE_RAS
bool "RAS features for bare metal Cell BE"
default y
diff --git a/arch/powerpc/platforms/cell/cbe_regs.c b/arch/powerpc/platforms/cell/cbe_regs.c
index 3f3859d12e00..2f194ba29899 100644
--- a/arch/powerpc/platforms/cell/cbe_regs.c
+++ b/arch/powerpc/platforms/cell/cbe_regs.c
@@ -6,8 +6,6 @@
* (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
*/
-
-#include <linux/config.h>
#include <linux/percpu.h>
#include <linux/types.h>
diff --git a/arch/powerpc/platforms/cell/interrupt.c b/arch/powerpc/platforms/cell/interrupt.c
index 6b57a47c5d37..a914c12b4060 100644
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -21,6 +21,12 @@
* 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.
+ *
+ * TODO:
+ * - Fix various assumptions related to HW CPU numbers vs. linux CPU numbers
+ * vs node numbers in the setup code
+ * - Implement proper handling of maxcpus=1/2 (that is, routing of irqs from
+ * a non-active node to the active node)
*/
#include <linux/interrupt.h>
@@ -44,24 +50,25 @@ struct iic {
u8 target_id;
u8 eoi_stack[16];
int eoi_ptr;
- struct irq_host *host;
+ struct device_node *node;
};
static DEFINE_PER_CPU(struct iic, iic);
#define IIC_NODE_COUNT 2
-static struct irq_host *iic_hosts[IIC_NODE_COUNT];
+static struct irq_host *iic_host;
/* Convert between "pending" bits and hw irq number */
static irq_hw_number_t iic_pending_to_hwnum(struct cbe_iic_pending_bits bits)
{
unsigned char unit = bits.source & 0xf;
+ unsigned char node = bits.source >> 4;
+ unsigned char class = bits.class & 3;
+ /* Decode IPIs */
if (bits.flags & CBE_IIC_IRQ_IPI)
- return IIC_IRQ_IPI0 | (bits.prio >> 4);
- else if (bits.class <= 3)
- return (bits.class << 4) | unit;
+ return IIC_IRQ_TYPE_IPI | (bits.prio >> 4);
else
- return IIC_IRQ_INVALID;
+ return (node << IIC_IRQ_NODE_SHIFT) | (class << 4) | unit;
}
static void iic_mask(unsigned int irq)
@@ -86,21 +93,69 @@ static struct irq_chip iic_chip = {
.eoi = iic_eoi,
};
+
+static void iic_ioexc_eoi(unsigned int irq)
+{
+}
+
+static void iic_ioexc_cascade(unsigned int irq, struct irq_desc *desc)
+{
+ struct cbe_iic_regs __iomem *node_iic = (void __iomem *)desc->handler_data;
+ unsigned int base = (irq & 0xffffff00) | IIC_IRQ_TYPE_IOEXC;
+ unsigned long bits, ack;
+ int cascade;
+
+ for (;;) {
+ bits = in_be64(&node_iic->iic_is);
+ if (bits == 0)
+ break;
+ /* pre-ack edge interrupts */
+ ack = bits & IIC_ISR_EDGE_MASK;
+ if (ack)
+ out_be64(&node_iic->iic_is, ack);
+ /* handle them */
+ for (cascade = 63; cascade >= 0; cascade--)
+ if (bits & (0x8000000000000000UL >> cascade)) {
+ unsigned int cirq =
+ irq_linear_revmap(iic_host,
+ base | cascade);
+ if (cirq != NO_IRQ)
+ generic_handle_irq(cirq);
+ }
+ /* post-ack level interrupts */
+ ack = bits & ~IIC_ISR_EDGE_MASK;
+ if (ack)
+ out_be64(&node_iic->iic_is, ack);
+ }
+ desc->chip->eoi(irq);
+}
+
+
+static struct irq_chip iic_ioexc_chip = {
+ .typename = " CELL-IOEX",
+ .mask = iic_mask,
+ .unmask = iic_unmask,
+ .eoi = iic_ioexc_eoi,
+};
+
/* Get an IRQ number from the pending state register of the IIC */
-static unsigned int iic_get_irq(struct pt_regs *regs)
+static unsigned int iic_get_irq(void)
{
struct cbe_iic_pending_bits pending;
struct iic *iic;
+ unsigned int virq;
iic = &__get_cpu_var(iic);
*(unsigned long *) &pending =
in_be64((unsigned long __iomem *) &iic->regs->pending_destr);
+ if (!(pending.flags & CBE_IIC_IRQ_VALID))
+ return NO_IRQ;
+ virq = irq_linear_revmap(iic_host, iic_pending_to_hwnum(pending));
+ if (virq == NO_IRQ)
+ return NO_IRQ;
iic->eoi_stack[++iic->eoi_ptr] = pending.prio;
BUG_ON(iic->eoi_ptr > 15);
- if (pending.flags & CBE_IIC_IRQ_VALID)
- return irq_linear_revmap(iic->host,
- iic_pending_to_hwnum(pending));
- return NO_IRQ;
+ return virq;
}
#ifdef CONFIG_SMP
@@ -108,12 +163,7 @@ static unsigned int iic_get_irq(struct pt_regs *regs)
/* Use the highest interrupt priorities for IPI */
static inline int iic_ipi_to_irq(int ipi)
{
- return IIC_IRQ_IPI0 + IIC_NUM_IPIS - 1 - ipi;
-}
-
-static inline int iic_irq_to_ipi(int irq)
-{
- return IIC_NUM_IPIS - 1 - (irq - IIC_IRQ_IPI0);
+ return IIC_IRQ_TYPE_IPI + 0xf - ipi;
}
void iic_setup_cpu(void)
@@ -123,7 +173,7 @@ void iic_setup_cpu(void)
void iic_cause_IPI(int cpu, int mesg)
{
- out_be64(&per_cpu(iic, cpu).regs->generate, (IIC_NUM_IPIS - 1 - mesg) << 4);
+ out_be64(&per_cpu(iic, cpu).regs->generate, (0xf - mesg) << 4);
}
u8 iic_get_target_id(int cpu)
@@ -134,49 +184,33 @@ EXPORT_SYMBOL_GPL(iic_get_target_id);
struct irq_host *iic_get_irq_host(int node)
{
- if (node < 0 || node >= IIC_NODE_COUNT)
- return NULL;
- return iic_hosts[node];
+ return iic_host;
}
EXPORT_SYMBOL_GPL(iic_get_irq_host);
-static irqreturn_t iic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t iic_ipi_action(int irq, void *dev_id)
{
int ipi = (int)(long)dev_id;
- smp_message_recv(ipi, regs);
+ smp_message_recv(ipi);
return IRQ_HANDLED;
}
-
static void iic_request_ipi(int ipi, const char *name)
{
- int node, virq;
+ int virq;
- for (node = 0; node < IIC_NODE_COUNT; node++) {
- char *rname;
- if (iic_hosts[node] == NULL)
- continue;
- virq = irq_create_mapping(iic_hosts[node],
- iic_ipi_to_irq(ipi));
- if (virq == NO_IRQ) {
- printk(KERN_ERR
- "iic: failed to map IPI %s on node %d\n",
- name, node);
- continue;
- }
- rname = kzalloc(strlen(name) + 16, GFP_KERNEL);
- if (rname)
- sprintf(rname, "%s node %d", name, node);
- else
- rname = (char *)name;
- if (request_irq(virq, iic_ipi_action, IRQF_DISABLED,
- rname, (void *)(long)ipi))
- printk(KERN_ERR
- "iic: failed to request IPI %s on node %d\n",
- name, node);
+ virq = irq_create_mapping(iic_host, iic_ipi_to_irq(ipi));
+ if (virq == NO_IRQ) {
+ printk(KERN_ERR
+ "iic: failed to map IPI %s\n", name);
+ return;
}
+ if (request_irq(virq, iic_ipi_action, IRQF_DISABLED, name,
+ (void *)(long)ipi))
+ printk(KERN_ERR
+ "iic: failed to request IPI %s\n", name);
}
void iic_request_IPIs(void)
@@ -193,16 +227,24 @@ void iic_request_IPIs(void)
static int iic_host_match(struct irq_host *h, struct device_node *node)
{
- return h->host_data != NULL && node == h->host_data;
+ return device_is_compatible(node,
+ "IBM,CBEA-Internal-Interrupt-Controller");
}
static int iic_host_map(struct irq_host *h, unsigned int virq,
irq_hw_number_t hw)
{
- if (hw < IIC_IRQ_IPI0)
- set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
- else
+ switch (hw & IIC_IRQ_TYPE_MASK) {
+ case IIC_IRQ_TYPE_IPI:
set_irq_chip_and_handler(virq, &iic_chip, handle_percpu_irq);
+ break;
+ case IIC_IRQ_TYPE_IOEXC:
+ set_irq_chip_and_handler(virq, &iic_ioexc_chip,
+ handle_fasteoi_irq);
+ break;
+ default:
+ set_irq_chip_and_handler(virq, &iic_chip, handle_fasteoi_irq);
+ }
return 0;
}
@@ -211,11 +253,39 @@ static int iic_host_xlate(struct irq_host *h, struct device_node *ct,
irq_hw_number_t *out_hwirq, unsigned int *out_flags)
{
- /* Currently, we don't translate anything. That needs to be fixed as
- * we get better defined device-trees. iic interrupts have to be
- * explicitely mapped by whoever needs them
- */
- return -ENODEV;
+ unsigned int node, ext, unit, class;
+ const u32 *val;
+
+ if (!device_is_compatible(ct,
+ "IBM,CBEA-Internal-Interrupt-Controller"))
+ return -ENODEV;
+ if (intsize != 1)
+ return -ENODEV;
+ val = get_property(ct, "#interrupt-cells", NULL);
+ if (val == NULL || *val != 1)
+ return -ENODEV;
+
+ node = intspec[0] >> 24;
+ ext = (intspec[0] >> 16) & 0xff;
+ class = (intspec[0] >> 8) & 0xff;
+ unit = intspec[0] & 0xff;
+
+ /* Check if node is in supported range */
+ if (node > 1)
+ return -EINVAL;
+
+ /* Build up interrupt number, special case for IO exceptions */
+ *out_hwirq = (node << IIC_IRQ_NODE_SHIFT);
+ if (unit == IIC_UNIT_IIC && class == 1)
+ *out_hwirq |= IIC_IRQ_TYPE_IOEXC | ext;
+ else
+ *out_hwirq |= IIC_IRQ_TYPE_NORMAL |
+ (class << IIC_IRQ_CLASS_SHIFT) | unit;
+
+ /* Dummy flags, ignored by iic code */
+ *out_flags = IRQ_TYPE_EDGE_RISING;
+
+ return 0;
}
static struct irq_host_ops iic_host_ops = {
@@ -225,7 +295,7 @@ static struct irq_host_ops iic_host_ops = {
};
static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
- struct irq_host *host)
+ struct device_node *node)
{
/* XXX FIXME: should locate the linux CPU number from the HW cpu
* number properly. We are lucky for now
@@ -237,19 +307,19 @@ static void __init init_one_iic(unsigned int hw_cpu, unsigned long addr,
iic->target_id = ((hw_cpu & 2) << 3) | ((hw_cpu & 1) ? 0xf : 0xe);
iic->eoi_stack[0] = 0xff;
- iic->host = host;
+ iic->node = of_node_get(node);
out_be64(&iic->regs->prio, 0);
- printk(KERN_INFO "IIC for CPU %d at %lx mapped to %p, target id 0x%x\n",
- hw_cpu, addr, iic->regs, iic->target_id);
+ printk(KERN_INFO "IIC for CPU %d target id 0x%x : %s\n",
+ hw_cpu, iic->target_id, node->full_name);
}
static int __init setup_iic(void)
{
struct device_node *dn;
struct resource r0, r1;
- struct irq_host *host;
- int found = 0;
+ unsigned int node, cascade, found = 0;
+ struct cbe_iic_regs __iomem *node_iic;
const u32 *np;
for (dn = NULL;
@@ -269,19 +339,37 @@ static int __init setup_iic(void)
of_node_put(dn);
return -ENODEV;
}
- host = NULL;
- if (found < IIC_NODE_COUNT) {
- host = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
- IIC_SOURCE_COUNT,
- &iic_host_ops,
- IIC_IRQ_INVALID);
- iic_hosts[found] = host;
- BUG_ON(iic_hosts[found] == NULL);
- iic_hosts[found]->host_data = of_node_get(dn);
- found++;
- }
- init_one_iic(np[0], r0.start, host);
- init_one_iic(np[1], r1.start, host);
+ found++;
+ init_one_iic(np[0], r0.start, dn);
+ init_one_iic(np[1], r1.start, dn);
+
+ /* Setup cascade for IO exceptions. XXX cleanup tricks to get
+ * node vs CPU etc...
+ * Note that we configure the IIC_IRR here with a hard coded
+ * priority of 1. We might want to improve that later.
+ */
+ node = np[0] >> 1;
+ node_iic = cbe_get_cpu_iic_regs(np[0]);
+ cascade = node << IIC_IRQ_NODE_SHIFT;
+ cascade |= 1 << IIC_IRQ_CLASS_SHIFT;
+ cascade |= IIC_UNIT_IIC;
+ cascade = irq_create_mapping(iic_host, cascade);
+ if (cascade == NO_IRQ)
+ continue;
+ /*
+ * irq_data is a generic pointer that gets passed back
+ * to us later, so the forced cast is fine.
+ */
+ set_irq_data(cascade, (void __force *)node_iic);
+ set_irq_chained_handler(cascade , iic_ioexc_cascade);
+ out_be64(&node_iic->iic_ir,
+ (1 << 12) /* priority */ |
+ (node << 4) /* dest node */ |
+ IIC_UNIT_THREAD_0 /* route them to thread 0 */);
+ /* Flush pending (make sure it triggers if there is
+ * anything pending
+ */
+ out_be64(&node_iic->iic_is, 0xfffffffffffffffful);
}
if (found)
@@ -292,6 +380,12 @@ static int __init setup_iic(void)
void __init iic_init_IRQ(void)
{
+ /* Setup an irq host data structure */
+ iic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, IIC_SOURCE_COUNT,
+ &iic_host_ops, IIC_IRQ_INVALID);
+ BUG_ON(iic_host == NULL);
+ irq_set_default_host(iic_host);
+
/* Discover and initialize iics */
if (setup_iic() < 0)
panic("IIC: Failed to initialize !\n");
diff --git a/arch/powerpc/platforms/cell/interrupt.h b/arch/powerpc/platforms/cell/interrupt.h
index 5560a92ec3ab..9ba1d3c17b4b 100644
--- a/arch/powerpc/platforms/cell/interrupt.h
+++ b/arch/powerpc/platforms/cell/interrupt.h
@@ -2,48 +2,76 @@
#define ASM_CELL_PIC_H
#ifdef __KERNEL__
/*
- * Mapping of IIC pending bits into per-node
- * interrupt numbers.
+ * Mapping of IIC pending bits into per-node interrupt numbers.
*
- * IRQ FF CC SS PP FF CC SS PP Description
+ * Interrupt numbers are in the range 0...0x1ff where the top bit
+ * (0x100) represent the source node. Only 2 nodes are supported with
+ * the current code though it's trivial to extend that if necessary using
+ * higher level bits
*
- * 00-3f 80 02 +0 00 - 80 02 +0 3f South Bridge
- * 00-3f 80 02 +b 00 - 80 02 +b 3f South Bridge
- * 41-4a 80 00 +1 ** - 80 00 +a ** SPU Class 0
- * 51-5a 80 01 +1 ** - 80 01 +a ** SPU Class 1
- * 61-6a 80 02 +1 ** - 80 02 +a ** SPU Class 2
- * 70-7f C0 ** ** 00 - C0 ** ** 0f IPI
+ * The bottom 8 bits are split into 2 type bits and 6 data bits that
+ * depend on the type:
*
- * F flags
- * C class
- * S source
- * P Priority
- * + node number
- * * don't care
+ * 00 (0x00 | data) : normal interrupt. data is (class << 4) | source
+ * 01 (0x40 | data) : IO exception. data is the exception number as
+ * defined by bit numbers in IIC_SR
+ * 10 (0x80 | data) : IPI. data is the IPI number (obtained from the priority)
+ * and node is always 0 (IPIs are per-cpu, their source is
+ * not relevant)
+ * 11 (0xc0 | data) : reserved
*
- * A node consists of a Cell Broadband Engine and an optional
- * south bridge device providing a maximum of 64 IRQs.
- * The south bridge may be connected to either IOIF0
- * or IOIF1.
- * Each SPE is represented as three IRQ lines, one per
- * interrupt class.
- * 16 IRQ numbers are reserved for inter processor
- * interruptions, although these are only used in the
- * range of the first node.
+ * In addition, interrupt number 0x80000000 is defined as always invalid
+ * (that is the node field is expected to never extend to move than 23 bits)
*
- * This scheme needs 128 IRQ numbers per BIF node ID,
- * which means that with the total of 512 lines
- * available, we can have a maximum of four nodes.
*/
enum {
- IIC_IRQ_INVALID = 0xff,
- IIC_IRQ_MAX = 0x3f,
- IIC_IRQ_EXT_IOIF0 = 0x20,
- IIC_IRQ_EXT_IOIF1 = 0x2b,
- IIC_IRQ_IPI0 = 0x40,
- IIC_NUM_IPIS = 0x10, /* IRQs reserved for IPI */
- IIC_SOURCE_COUNT = 0x50,
+ IIC_IRQ_INVALID = 0x80000000u,
+ IIC_IRQ_NODE_MASK = 0x100,
+ IIC_IRQ_NODE_SHIFT = 8,
+ IIC_IRQ_MAX = 0x1ff,
+ IIC_IRQ_TYPE_MASK = 0xc0,
+ IIC_IRQ_TYPE_NORMAL = 0x00,
+ IIC_IRQ_TYPE_IOEXC = 0x40,
+ IIC_IRQ_TYPE_IPI = 0x80,
+ IIC_IRQ_CLASS_SHIFT = 4,
+ IIC_IRQ_CLASS_0 = 0x00,
+ IIC_IRQ_CLASS_1 = 0x10,
+ IIC_IRQ_CLASS_2 = 0x20,
+ IIC_SOURCE_COUNT = 0x200,
+
+ /* Here are defined the various source/dest units. Avoid using those
+ * definitions if you can, they are mostly here for reference
+ */
+ IIC_UNIT_SPU_0 = 0x4,
+ IIC_UNIT_SPU_1 = 0x7,
+ IIC_UNIT_SPU_2 = 0x3,
+ IIC_UNIT_SPU_3 = 0x8,
+ IIC_UNIT_SPU_4 = 0x2,
+ IIC_UNIT_SPU_5 = 0x9,
+ IIC_UNIT_SPU_6 = 0x1,
+ IIC_UNIT_SPU_7 = 0xa,
+ IIC_UNIT_IOC_0 = 0x0,
+ IIC_UNIT_IOC_1 = 0xb,
+ IIC_UNIT_THREAD_0 = 0xe, /* target only */
+ IIC_UNIT_THREAD_1 = 0xf, /* target only */
+ IIC_UNIT_IIC = 0xe, /* source only (IO exceptions) */
+
+ /* Base numbers for the external interrupts */
+ IIC_IRQ_EXT_IOIF0 =
+ IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_0,
+ IIC_IRQ_EXT_IOIF1 =
+ IIC_IRQ_TYPE_NORMAL | IIC_IRQ_CLASS_2 | IIC_UNIT_IOC_1,
+
+ /* Base numbers for the IIC_ISR interrupts */
+ IIC_IRQ_IOEX_TMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 63,
+ IIC_IRQ_IOEX_PMI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 62,
+ IIC_IRQ_IOEX_ATI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 61,
+ IIC_IRQ_IOEX_MATBFI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 60,
+ IIC_IRQ_IOEX_ELDI = IIC_IRQ_TYPE_IOEXC | IIC_IRQ_CLASS_1 | 59,
+
+ /* Which bits in IIC_ISR are edge sensitive */
+ IIC_ISR_EDGE_MASK = 0x4ul,
};
extern void iic_init_IRQ(void);
@@ -52,7 +80,6 @@ extern void iic_request_IPIs(void);
extern void iic_setup_cpu(void);
extern u8 iic_get_target_id(int cpu);
-extern struct irq_host *iic_get_irq_host(int node);
extern void spider_init_IRQ(void);
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index d2b20eba5b87..aca4c3db0dde 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -345,8 +345,8 @@ static int cell_map_iommu_hardcoded(int num_nodes)
/* node 0 */
iommu = &cell_iommus[0];
- iommu->mapped_base = ioremap(0x20000511000, 0x1000);
- iommu->mapped_mmio_base = ioremap(0x20000510000, 0x1000);
+ iommu->mapped_base = ioremap(0x20000511000ul, 0x1000);
+ iommu->mapped_mmio_base = ioremap(0x20000510000ul, 0x1000);
enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
@@ -358,8 +358,8 @@ static int cell_map_iommu_hardcoded(int num_nodes)
/* node 1 */
iommu = &cell_iommus[1];
- iommu->mapped_base = ioremap(0x30000511000, 0x1000);
- iommu->mapped_mmio_base = ioremap(0x30000510000, 0x1000);
+ iommu->mapped_base = ioremap(0x30000511000ul, 0x1000);
+ iommu->mapped_mmio_base = ioremap(0x30000510000ul, 0x1000);
enable_mapping(iommu->mapped_base, iommu->mapped_mmio_base);
diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c
index 033ad6e2827b..0984c7071695 100644
--- a/arch/powerpc/platforms/cell/ras.c
+++ b/arch/powerpc/platforms/cell/ras.c
@@ -1,6 +1,5 @@
#define DEBUG
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/smp.h>
diff --git a/arch/powerpc/platforms/cell/spider-pic.c b/arch/powerpc/platforms/cell/spider-pic.c
index 742a03282b44..21a9ebd4978e 100644
--- a/arch/powerpc/platforms/cell/spider-pic.c
+++ b/arch/powerpc/platforms/cell/spider-pic.c
@@ -213,8 +213,7 @@ static struct irq_host_ops spider_host_ops = {
.xlate = spider_host_xlate,
};
-static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc)
{
struct spider_pic *pic = desc->handler_data;
unsigned int cs, virq;
@@ -225,7 +224,7 @@ static void spider_irq_cascade(unsigned int irq, struct irq_desc *desc,
else
virq = irq_linear_revmap(pic->host, cs);
if (virq != NO_IRQ)
- generic_handle_irq(virq, regs);
+ generic_handle_irq(virq);
desc->chip->eoi(irq);
}
@@ -243,9 +242,7 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
const u32 *imap, *tmp;
int imaplen, intsize, unit;
struct device_node *iic;
- struct irq_host *iic_host;
-#if 0 /* Enable that when we have a way to retreive the node as well */
/* First, we check wether we have a real "interrupts" in the device
* tree in case the device-tree is ever fixed
*/
@@ -253,9 +250,8 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
if (of_irq_map_one(pic->of_node, 0, &oirq) == 0) {
virq = irq_create_of_mapping(oirq.controller, oirq.specifier,
oirq.size);
- goto bail;
+ return virq;
}
-#endif
/* Now do the horrible hacks */
tmp = get_property(pic->of_node, "#interrupt-cells", NULL);
@@ -289,11 +285,11 @@ static unsigned int __init spider_find_cascade_and_node(struct spider_pic *pic)
* the iic host from the iic OF node, but that way I'm still compatible
* with really really old old firmwares for which we don't have a node
*/
- iic_host = iic_get_irq_host(pic->node_id);
- if (iic_host == NULL)
- return NO_IRQ;
/* Manufacture an IIC interrupt number of class 2 */
- virq = irq_create_mapping(iic_host, 0x20 | unit);
+ virq = irq_create_mapping(NULL,
+ (pic->node_id << IIC_IRQ_NODE_SHIFT) |
+ (2 << IIC_IRQ_CLASS_SHIFT) |
+ unit);
if (virq == NO_IRQ)
printk(KERN_ERR "spider_pic: failed to map cascade !");
return virq;
@@ -370,7 +366,7 @@ void __init spider_init_IRQ(void)
} else if (device_is_compatible(dn, "sti,platform-spider-pic")
&& (chip < 2)) {
static long hard_coded_pics[] =
- { 0x24000008000, 0x34000008000 };
+ { 0x24000008000ul, 0x34000008000ul};
r.start = hard_coded_pics[chip];
} else
continue;
diff --git a/arch/powerpc/platforms/cell/spu_base.c b/arch/powerpc/platforms/cell/spu_base.c
index 3bd36d46ab4a..d0fb959e3ef1 100644
--- a/arch/powerpc/platforms/cell/spu_base.c
+++ b/arch/powerpc/platforms/cell/spu_base.c
@@ -25,11 +25,13 @@
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/module.h>
+#include <linux/pci.h>
#include <linux/poll.h>
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/wait.h>
+#include <asm/firmware.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <linux/mutex.h>
@@ -46,21 +48,21 @@ EXPORT_SYMBOL_GPL(spu_priv1_ops);
static int __spu_trap_invalid_dma(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
- force_sig(SIGBUS, /* info, */ current);
+ spu->dma_callback(spu, SPE_EVENT_INVALID_DMA);
return 0;
}
static int __spu_trap_dma_align(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
- force_sig(SIGBUS, /* info, */ current);
+ spu->dma_callback(spu, SPE_EVENT_DMA_ALIGNMENT);
return 0;
}
static int __spu_trap_error(struct spu *spu)
{
pr_debug("%s\n", __FUNCTION__);
- force_sig(SIGILL, /* info, */ current);
+ spu->dma_callback(spu, SPE_EVENT_SPE_ERROR);
return 0;
}
@@ -145,7 +147,7 @@ static int __spu_trap_data_map(struct spu *spu, unsigned long ea, u64 dsisr)
}
static irqreturn_t
-spu_irq_class_0(int irq, void *data, struct pt_regs *regs)
+spu_irq_class_0(int irq, void *data)
{
struct spu *spu;
@@ -184,7 +186,7 @@ spu_irq_class_0_bottom(struct spu *spu)
EXPORT_SYMBOL_GPL(spu_irq_class_0_bottom);
static irqreturn_t
-spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
+spu_irq_class_1(int irq, void *data)
{
struct spu *spu;
unsigned long stat, mask, dar, dsisr;
@@ -222,7 +224,7 @@ spu_irq_class_1(int irq, void *data, struct pt_regs *regs)
EXPORT_SYMBOL_GPL(spu_irq_class_1_bottom);
static irqreturn_t
-spu_irq_class_2(int irq, void *data, struct pt_regs *regs)
+spu_irq_class_2(int irq, void *data)
{
struct spu *spu;
unsigned long stat;
@@ -317,7 +319,7 @@ static void spu_free_irqs(struct spu *spu)
free_irq(spu->irqs[2], spu);
}
-static LIST_HEAD(spu_list);
+static struct list_head spu_list[MAX_NUMNODES];
static DEFINE_MUTEX(spu_mutex);
static void spu_init_channels(struct spu *spu)
@@ -354,32 +356,42 @@ static void spu_init_channels(struct spu *spu)
}
}
-struct spu *spu_alloc(void)
+struct spu *spu_alloc_node(int node)
{
- struct spu *spu;
+ struct spu *spu = NULL;
mutex_lock(&spu_mutex);
- if (!list_empty(&spu_list)) {
- spu = list_entry(spu_list.next, struct spu, list);
+ if (!list_empty(&spu_list[node])) {
+ spu = list_entry(spu_list[node].next, struct spu, list);
list_del_init(&spu->list);
- pr_debug("Got SPU %x %d\n", spu->isrc, spu->number);
- } else {
- pr_debug("No SPU left\n");
- spu = NULL;
+ pr_debug("Got SPU %x %d %d\n",
+ spu->isrc, spu->number, spu->node);
+ spu_init_channels(spu);
}
mutex_unlock(&spu_mutex);
- if (spu)
- spu_init_channels(spu);
+ return spu;
+}
+EXPORT_SYMBOL_GPL(spu_alloc_node);
+
+struct spu *spu_alloc(void)
+{
+ struct spu *spu = NULL;
+ int node;
+
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ spu = spu_alloc_node(node);
+ if (spu)
+ break;
+ }
return spu;
}
-EXPORT_SYMBOL_GPL(spu_alloc);
void spu_free(struct spu *spu)
{
mutex_lock(&spu_mutex);
- list_add_tail(&spu->list, &spu_list);
+ list_add_tail(&spu->list, &spu_list[spu->node]);
mutex_unlock(&spu_mutex);
}
EXPORT_SYMBOL_GPL(spu_free);
@@ -538,7 +550,7 @@ static void __iomem * __init map_spe_prop(struct spu *spu,
const void *p;
int proplen;
- void* ret = NULL;
+ void __iomem *ret = NULL;
int err = 0;
p = get_property(n, name, &proplen);
@@ -562,36 +574,35 @@ static void spu_unmap(struct spu *spu)
iounmap(spu->priv2);
iounmap(spu->priv1);
iounmap(spu->problem);
- iounmap((u8 __iomem *)spu->local_store);
+ iounmap((__force u8 __iomem *)spu->local_store);
}
/* This function shall be abstracted for HV platforms */
-static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
+static int __init spu_map_interrupts_old(struct spu *spu, struct device_node *np)
{
- struct irq_host *host;
unsigned int isrc;
const u32 *tmp;
- host = iic_get_irq_host(spu->node);
- if (host == NULL)
- return -ENODEV;
-
- /* Get the interrupt source from the device-tree */
+ /* Get the interrupt source unit from the device-tree */
tmp = get_property(np, "isrc", NULL);
if (!tmp)
return -ENODEV;
- spu->isrc = isrc = tmp[0];
+ isrc = tmp[0];
+
+ /* Add the node number */
+ isrc |= spu->node << IIC_IRQ_NODE_SHIFT;
+ spu->isrc = isrc;
/* Now map interrupts of all 3 classes */
- spu->irqs[0] = irq_create_mapping(host, 0x00 | isrc);
- spu->irqs[1] = irq_create_mapping(host, 0x10 | isrc);
- spu->irqs[2] = irq_create_mapping(host, 0x20 | isrc);
+ spu->irqs[0] = irq_create_mapping(NULL, IIC_IRQ_CLASS_0 | isrc);
+ spu->irqs[1] = irq_create_mapping(NULL, IIC_IRQ_CLASS_1 | isrc);
+ spu->irqs[2] = irq_create_mapping(NULL, IIC_IRQ_CLASS_2 | isrc);
/* Right now, we only fail if class 2 failed */
return spu->irqs[2] == NO_IRQ ? -EINVAL : 0;
}
-static int __init spu_map_device(struct spu *spu, struct device_node *node)
+static int __init spu_map_device_old(struct spu *spu, struct device_node *node)
{
const char *prop;
int ret;
@@ -636,6 +647,88 @@ out:
return ret;
}
+static int __init spu_map_interrupts(struct spu *spu, struct device_node *np)
+{
+ struct of_irq oirq;
+ int ret;
+ int i;
+
+ for (i=0; i < 3; i++) {
+ ret = of_irq_map_one(np, i, &oirq);
+ if (ret)
+ goto err;
+
+ ret = -EINVAL;
+ spu->irqs[i] = irq_create_of_mapping(oirq.controller,
+ oirq.specifier, oirq.size);
+ if (spu->irqs[i] == NO_IRQ)
+ goto err;
+ }
+ return 0;
+
+err:
+ pr_debug("failed to map irq %x for spu %s\n", *oirq.specifier, spu->name);
+ for (; i >= 0; i--) {
+ if (spu->irqs[i] != NO_IRQ)
+ irq_dispose_mapping(spu->irqs[i]);
+ }
+ return ret;
+}
+
+static int spu_map_resource(struct device_node *node, int nr,
+ void __iomem** virt, unsigned long *phys)
+{
+ struct resource resource = { };
+ int ret;
+
+ ret = of_address_to_resource(node, 0, &resource);
+ if (ret)
+ goto out;
+
+ if (phys)
+ *phys = resource.start;
+ *virt = ioremap(resource.start, resource.end - resource.start);
+ if (!*virt)
+ ret = -EINVAL;
+
+out:
+ return ret;
+}
+
+static int __init spu_map_device(struct spu *spu, struct device_node *node)
+{
+ int ret = -ENODEV;
+ spu->name = get_property(node, "name", NULL);
+ if (!spu->name)
+ goto out;
+
+ ret = spu_map_resource(node, 0, (void __iomem**)&spu->local_store,
+ &spu->local_store_phys);
+ if (ret)
+ goto out;
+ ret = spu_map_resource(node, 1, (void __iomem**)&spu->problem,
+ &spu->problem_phys);
+ if (ret)
+ goto out_unmap;
+ ret = spu_map_resource(node, 2, (void __iomem**)&spu->priv2,
+ NULL);
+ if (ret)
+ goto out_unmap;
+
+ if (!firmware_has_feature(FW_FEATURE_LPAR))
+ ret = spu_map_resource(node, 3, (void __iomem**)&spu->priv1,
+ NULL);
+ if (ret)
+ goto out_unmap;
+ return 0;
+
+out_unmap:
+ spu_unmap(spu);
+out:
+ pr_debug("failed to map spe %s: %d\n", spu->name, ret);
+ return ret;
+}
+
struct sysdev_class spu_sysdev_class = {
set_kset_name("spu")
};
@@ -688,16 +781,28 @@ static int __init create_spu(struct device_node *spe)
if (!spu)
goto out;
- ret = spu_map_device(spu, spe);
- if (ret)
- goto out_free;
-
spu->node = find_spu_node_id(spe);
+ if (spu->node >= MAX_NUMNODES) {
+ printk(KERN_WARNING "SPE %s on node %d ignored,"
+ " node number too big\n", spe->full_name, spu->node);
+ printk(KERN_WARNING "Check if CONFIG_NUMA is enabled.\n");
+ return -ENODEV;
+ }
spu->nid = of_node_to_nid(spe);
if (spu->nid == -1)
spu->nid = 0;
+
+ ret = spu_map_device(spu, spe);
+ /* try old method */
+ if (ret)
+ ret = spu_map_device_old(spu, spe);
+ if (ret)
+ goto out_free;
+
ret = spu_map_interrupts(spu, spe);
if (ret)
+ ret = spu_map_interrupts_old(spu, spe);
+ if (ret)
goto out_unmap;
spin_lock_init(&spu->register_lock);
spu_mfc_sdr_set(spu, mfspr(SPRN_SDR1));
@@ -707,13 +812,13 @@ static int __init create_spu(struct device_node *spe)
spu->number = number++;
ret = spu_request_irqs(spu);
if (ret)
- goto out_unmap;
+ goto out_unlock;
ret = spu_create_sysdev(spu);
if (ret)
goto out_free_irqs;
- list_add(&spu->list, &spu_list);
+ list_add(&spu->list, &spu_list[spu->node]);
mutex_unlock(&spu_mutex);
pr_debug(KERN_DEBUG "Using SPE %s %02x %p %p %p %p %d\n",
@@ -723,9 +828,9 @@ static int __init create_spu(struct device_node *spe)
out_free_irqs:
spu_free_irqs(spu);
-
-out_unmap:
+out_unlock:
mutex_unlock(&spu_mutex);
+out_unmap:
spu_unmap(spu);
out_free:
kfree(spu);
@@ -746,9 +851,13 @@ static void destroy_spu(struct spu *spu)
static void cleanup_spu_base(void)
{
struct spu *spu, *tmp;
+ int node;
+
mutex_lock(&spu_mutex);
- list_for_each_entry_safe(spu, tmp, &spu_list, list)
- destroy_spu(spu);
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ list_for_each_entry_safe(spu, tmp, &spu_list[node], list)
+ destroy_spu(spu);
+ }
mutex_unlock(&spu_mutex);
sysdev_class_unregister(&spu_sysdev_class);
}
@@ -757,13 +866,16 @@ module_exit(cleanup_spu_base);
static int __init init_spu_base(void)
{
struct device_node *node;
- int ret;
+ int i, ret;
/* create sysdev class for spus */
ret = sysdev_class_register(&spu_sysdev_class);
if (ret)
return ret;
+ for (i = 0; i < MAX_NUMNODES; i++)
+ INIT_LIST_HEAD(&spu_list[i]);
+
ret = -ENODEV;
for (node = of_find_node_by_type(NULL, "spe");
node; node = of_find_node_by_type(node, "spe")) {
@@ -775,18 +887,6 @@ static int __init init_spu_base(void)
break;
}
}
- /* in some old firmware versions, the spe is called 'spc', so we
- look for that as well */
- for (node = of_find_node_by_type(NULL, "spc");
- node; node = of_find_node_by_type(node, "spc")) {
- ret = create_spu(node);
- if (ret) {
- printk(KERN_WARNING "%s: Error initializing %s\n",
- __FUNCTION__, node->name);
- cleanup_spu_base();
- break;
- }
- }
return ret;
}
module_init(init_spu_base);
diff --git a/arch/powerpc/platforms/cell/spufs/Makefile b/arch/powerpc/platforms/cell/spufs/Makefile
index bb5dc634272c..ecdfbb35f82e 100644
--- a/arch/powerpc/platforms/cell/spufs/Makefile
+++ b/arch/powerpc/platforms/cell/spufs/Makefile
@@ -2,7 +2,7 @@ obj-y += switch.o
obj-$(CONFIG_SPU_FS) += spufs.o
spufs-y += inode.o file.o context.o syscalls.o
-spufs-y += sched.o backing_ops.o hw_ops.o run.o
+spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
# Rules to build switch.o with the help of SPU tool chain
SPU_CROSS := spu-
diff --git a/arch/powerpc/platforms/cell/spufs/context.c b/arch/powerpc/platforms/cell/spufs/context.c
index 36439c5e9f2d..034cf6af53a2 100644
--- a/arch/powerpc/platforms/cell/spufs/context.c
+++ b/arch/powerpc/platforms/cell/spufs/context.c
@@ -27,7 +27,7 @@
#include <asm/spu_csa.h>
#include "spufs.h"
-struct spu_context *alloc_spu_context(void)
+struct spu_context *alloc_spu_context(struct spu_gang *gang)
{
struct spu_context *ctx;
ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
@@ -51,6 +51,8 @@ struct spu_context *alloc_spu_context(void)
ctx->state = SPU_STATE_SAVED;
ctx->ops = &spu_backing_ops;
ctx->owner = get_task_mm(current);
+ if (gang)
+ spu_gang_add_ctx(gang, ctx);
goto out;
out_free:
kfree(ctx);
@@ -67,6 +69,8 @@ void destroy_spu_context(struct kref *kref)
spu_deactivate(ctx);
up_write(&ctx->state_sema);
spu_fini_csa(&ctx->csa);
+ if (ctx->gang)
+ spu_gang_remove_ctx(ctx->gang, ctx);
kfree(ctx);
}
diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c
index 58e794f9da1b..0de8e114e6b6 100644
--- a/arch/powerpc/platforms/cell/spufs/file.c
+++ b/arch/powerpc/platforms/cell/spufs/file.c
@@ -36,6 +36,8 @@
#include "spufs.h"
+#define SPUFS_MMAP_4K (PAGE_SIZE == 0x1000)
+
static int
spufs_mem_open(struct inode *inode, struct file *file)
@@ -88,7 +90,6 @@ spufs_mem_write(struct file *file, const char __user *buffer,
return ret;
}
-#ifdef CONFIG_SPUFS_MMAP
static struct page *
spufs_mem_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
@@ -101,12 +102,16 @@ spufs_mem_mmap_nopage(struct vm_area_struct *vma,
spu_acquire(ctx);
- if (ctx->state == SPU_STATE_SAVED)
+ if (ctx->state == SPU_STATE_SAVED) {
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ & ~(_PAGE_NO_CACHE | _PAGE_GUARDED));
page = vmalloc_to_page(ctx->csa.lscsa->ls + offset);
- else
+ } else {
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE | _PAGE_GUARDED);
page = pfn_to_page((ctx->spu->local_store_phys + offset)
>> PAGE_SHIFT);
-
+ }
spu_release(ctx);
if (type)
@@ -133,22 +138,19 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_mem_mmap_vmops;
return 0;
}
-#endif
static struct file_operations spufs_mem_fops = {
.open = spufs_mem_open,
.read = spufs_mem_read,
.write = spufs_mem_write,
.llseek = generic_file_llseek,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mem_mmap,
-#endif
};
-#ifdef CONFIG_SPUFS_MMAP
static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
unsigned long address,
- int *type, unsigned long ps_offs)
+ int *type, unsigned long ps_offs,
+ unsigned long ps_size)
{
struct page *page = NOPAGE_SIGBUS;
int fault_type = VM_FAULT_SIGBUS;
@@ -158,7 +160,7 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
int ret;
offset += vma->vm_pgoff << PAGE_SHIFT;
- if (offset >= 0x4000)
+ if (offset >= ps_size)
goto out;
ret = spu_acquire_runnable(ctx);
@@ -179,10 +181,11 @@ static struct page *spufs_ps_nopage(struct vm_area_struct *vma,
return page;
}
+#if SPUFS_MMAP_4K
static struct page *spufs_cntl_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x4000);
+ return spufs_ps_nopage(vma, address, type, 0x4000, 0x1000);
}
static struct vm_operations_struct spufs_cntl_mmap_vmops = {
@@ -191,17 +194,12 @@ static struct vm_operations_struct spufs_cntl_mmap_vmops = {
/*
* mmap support for problem state control area [0x4000 - 0x4fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
*/
static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -209,42 +207,49 @@ static int spufs_cntl_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_cntl_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_cntl_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
-static int spufs_cntl_open(struct inode *inode, struct file *file)
+static u64 spufs_cntl_get(void *data)
{
- struct spufs_inode_info *i = SPUFS_I(inode);
- struct spu_context *ctx = i->i_ctx;
+ struct spu_context *ctx = data;
+ u64 val;
- file->private_data = ctx;
- file->f_mapping = inode->i_mapping;
- ctx->cntl = inode->i_mapping;
- return 0;
+ spu_acquire(ctx);
+ val = ctx->ops->status_read(ctx);
+ spu_release(ctx);
+
+ return val;
}
-static ssize_t
-spufs_cntl_read(struct file *file, char __user *buffer,
- size_t size, loff_t *pos)
+static void spufs_cntl_set(void *data, u64 val)
{
- /* FIXME: read from spu status */
- return -EINVAL;
+ struct spu_context *ctx = data;
+
+ spu_acquire(ctx);
+ ctx->ops->runcntl_write(ctx, val);
+ spu_release(ctx);
}
-static ssize_t
-spufs_cntl_write(struct file *file, const char __user *buffer,
- size_t size, loff_t *pos)
+static int spufs_cntl_open(struct inode *inode, struct file *file)
{
- /* FIXME: write to runctl bit */
- return -EINVAL;
+ struct spufs_inode_info *i = SPUFS_I(inode);
+ struct spu_context *ctx = i->i_ctx;
+
+ file->private_data = ctx;
+ file->f_mapping = inode->i_mapping;
+ ctx->cntl = inode->i_mapping;
+ return simple_attr_open(inode, file, spufs_cntl_get,
+ spufs_cntl_set, "0x%08lx");
}
static struct file_operations spufs_cntl_fops = {
.open = spufs_cntl_open,
- .read = spufs_cntl_read,
- .write = spufs_cntl_write,
-#ifdef CONFIG_SPUFS_MMAP
+ .release = simple_attr_close,
+ .read = simple_attr_read,
+ .write = simple_attr_write,
.mmap = spufs_cntl_mmap,
-#endif
};
static int
@@ -356,27 +361,54 @@ static int spufs_pipe_open(struct inode *inode, struct file *file)
return nonseekable_open(inode, file);
}
+/*
+ * Read as many bytes from the mailbox as possible, until
+ * one of the conditions becomes true:
+ *
+ * - no more data available in the mailbox
+ * - end of the user provided buffer
+ * - end of the mapped area
+ */
static ssize_t spufs_mbox_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
- u32 mbox_data;
- int ret;
+ u32 mbox_data, __user *udata;
+ ssize_t count;
if (len < 4)
return -EINVAL;
+ if (!access_ok(VERIFY_WRITE, buf, len))
+ return -EFAULT;
+
+ udata = (void __user *)buf;
+
spu_acquire(ctx);
- ret = ctx->ops->mbox_read(ctx, &mbox_data);
+ for (count = 0; count <= len; count += 4, udata++) {
+ int ret;
+ ret = ctx->ops->mbox_read(ctx, &mbox_data);
+ if (ret == 0)
+ break;
+
+ /*
+ * at the end of the mapped area, we can fault
+ * but still need to return the data we have
+ * read successfully so far.
+ */
+ ret = __put_user(mbox_data, udata);
+ if (ret) {
+ if (!count)
+ count = -EFAULT;
+ break;
+ }
+ }
spu_release(ctx);
- if (!ret)
- return -EAGAIN;
-
- if (copy_to_user(buf, &mbox_data, sizeof mbox_data))
- return -EFAULT;
+ if (!count)
+ count = -EAGAIN;
- return 4;
+ return count;
}
static struct file_operations spufs_mbox_fops = {
@@ -432,36 +464,70 @@ void spufs_ibox_callback(struct spu *spu)
kill_fasync(&ctx->ibox_fasync, SIGIO, POLLIN);
}
+/*
+ * Read as many bytes from the interrupt mailbox as possible, until
+ * one of the conditions becomes true:
+ *
+ * - no more data available in the mailbox
+ * - end of the user provided buffer
+ * - end of the mapped area
+ *
+ * If the file is opened without O_NONBLOCK, we wait here until
+ * any data is available, but return when we have been able to
+ * read something.
+ */
static ssize_t spufs_ibox_read(struct file *file, char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
- u32 ibox_data;
- ssize_t ret;
+ u32 ibox_data, __user *udata;
+ ssize_t count;
if (len < 4)
return -EINVAL;
+ if (!access_ok(VERIFY_WRITE, buf, len))
+ return -EFAULT;
+
+ udata = (void __user *)buf;
+
spu_acquire(ctx);
- ret = 0;
+ /* wait only for the first element */
+ count = 0;
if (file->f_flags & O_NONBLOCK) {
if (!spu_ibox_read(ctx, &ibox_data))
- ret = -EAGAIN;
+ count = -EAGAIN;
} else {
- ret = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
+ count = spufs_wait(ctx->ibox_wq, spu_ibox_read(ctx, &ibox_data));
}
+ if (count)
+ goto out;
- spu_release(ctx);
+ /* if we can't write at all, return -EFAULT */
+ count = __put_user(ibox_data, udata);
+ if (count)
+ goto out;
- if (ret)
- return ret;
+ for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
+ int ret;
+ ret = ctx->ops->ibox_read(ctx, &ibox_data);
+ if (ret == 0)
+ break;
+ /*
+ * at the end of the mapped area, we can fault
+ * but still need to return the data we have
+ * read successfully so far.
+ */
+ ret = __put_user(ibox_data, udata);
+ if (ret)
+ break;
+ }
- ret = 4;
- if (copy_to_user(buf, &ibox_data, sizeof ibox_data))
- ret = -EFAULT;
+out:
+ spu_release(ctx);
- return ret;
+ return count;
}
static unsigned int spufs_ibox_poll(struct file *file, poll_table *wait)
@@ -534,32 +600,67 @@ void spufs_wbox_callback(struct spu *spu)
kill_fasync(&ctx->wbox_fasync, SIGIO, POLLOUT);
}
+/*
+ * Write as many bytes to the interrupt mailbox as possible, until
+ * one of the conditions becomes true:
+ *
+ * - the mailbox is full
+ * - end of the user provided buffer
+ * - end of the mapped area
+ *
+ * If the file is opened without O_NONBLOCK, we wait here until
+ * space is availabyl, but return when we have been able to
+ * write something.
+ */
static ssize_t spufs_wbox_write(struct file *file, const char __user *buf,
size_t len, loff_t *pos)
{
struct spu_context *ctx = file->private_data;
- u32 wbox_data;
- int ret;
+ u32 wbox_data, __user *udata;
+ ssize_t count;
if (len < 4)
return -EINVAL;
- if (copy_from_user(&wbox_data, buf, sizeof wbox_data))
+ udata = (void __user *)buf;
+ if (!access_ok(VERIFY_READ, buf, len))
+ return -EFAULT;
+
+ if (__get_user(wbox_data, udata))
return -EFAULT;
spu_acquire(ctx);
- ret = 0;
+ /*
+ * make sure we can at least write one element, by waiting
+ * in case of !O_NONBLOCK
+ */
+ count = 0;
if (file->f_flags & O_NONBLOCK) {
if (!spu_wbox_write(ctx, wbox_data))
- ret = -EAGAIN;
+ count = -EAGAIN;
} else {
- ret = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
+ count = spufs_wait(ctx->wbox_wq, spu_wbox_write(ctx, wbox_data));
}
- spu_release(ctx);
+ if (count)
+ goto out;
+
+ /* write aѕ much as possible */
+ for (count = 4, udata++; (count + 4) <= len; count += 4, udata++) {
+ int ret;
+ ret = __get_user(wbox_data, udata);
+ if (ret)
+ break;
+
+ ret = spu_wbox_write(ctx, wbox_data);
+ if (ret == 0)
+ break;
+ }
- return ret ? ret : sizeof wbox_data;
+out:
+ spu_release(ctx);
+ return count;
}
static unsigned int spufs_wbox_poll(struct file *file, poll_table *wait)
@@ -657,11 +758,19 @@ static ssize_t spufs_signal1_write(struct file *file, const char __user *buf,
return 4;
}
-#ifdef CONFIG_SPUFS_MMAP
static struct page *spufs_signal1_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x14000);
+#if PAGE_SIZE == 0x1000
+ return spufs_ps_nopage(vma, address, type, 0x14000, 0x1000);
+#elif PAGE_SIZE == 0x10000
+ /* For 64k pages, both signal1 and signal2 can be used to mmap the whole
+ * signal 1 and 2 area
+ */
+ return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
+#else
+#error unsupported page size
+#endif
}
static struct vm_operations_struct spufs_signal1_mmap_vmops = {
@@ -680,15 +789,12 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_signal1_mmap_vmops;
return 0;
}
-#endif
static struct file_operations spufs_signal1_fops = {
.open = spufs_signal1_open,
.read = spufs_signal1_read,
.write = spufs_signal1_write,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_signal1_mmap,
-#endif
};
static int spufs_signal2_open(struct inode *inode, struct file *file)
@@ -743,11 +849,20 @@ static ssize_t spufs_signal2_write(struct file *file, const char __user *buf,
return 4;
}
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
static struct page *spufs_signal2_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x1c000);
+#if PAGE_SIZE == 0x1000
+ return spufs_ps_nopage(vma, address, type, 0x1c000, 0x1000);
+#elif PAGE_SIZE == 0x10000
+ /* For 64k pages, both signal1 and signal2 can be used to mmap the whole
+ * signal 1 and 2 area
+ */
+ return spufs_ps_nopage(vma, address, type, 0x10000, 0x10000);
+#else
+#error unsupported page size
+#endif
}
static struct vm_operations_struct spufs_signal2_mmap_vmops = {
@@ -767,15 +882,15 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_signal2_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_signal2_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
static struct file_operations spufs_signal2_fops = {
.open = spufs_signal2_open,
.read = spufs_signal2_read,
.write = spufs_signal2_write,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_signal2_mmap,
-#endif
};
static void spufs_signal1_type_set(void *data, u64 val)
@@ -824,11 +939,11 @@ static u64 spufs_signal2_type_get(void *data)
DEFINE_SIMPLE_ATTRIBUTE(spufs_signal2_type, spufs_signal2_type_get,
spufs_signal2_type_set, "%llu");
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
static struct page *spufs_mss_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x0000);
+ return spufs_ps_nopage(vma, address, type, 0x0000, 0x1000);
}
static struct vm_operations_struct spufs_mss_mmap_vmops = {
@@ -837,17 +952,12 @@ static struct vm_operations_struct spufs_mss_mmap_vmops = {
/*
* mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
*/
static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -855,7 +965,9 @@ static int spufs_mss_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_mss_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_mss_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
static int spufs_mss_open(struct inode *inode, struct file *file)
{
@@ -867,17 +979,54 @@ static int spufs_mss_open(struct inode *inode, struct file *file)
static struct file_operations spufs_mss_fops = {
.open = spufs_mss_open,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mss_mmap,
-#endif
+};
+
+static struct page *spufs_psmap_mmap_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ return spufs_ps_nopage(vma, address, type, 0x0000, 0x20000);
+}
+
+static struct vm_operations_struct spufs_psmap_mmap_vmops = {
+ .nopage = spufs_psmap_mmap_nopage,
+};
+
+/*
+ * mmap support for full problem state area [0x00000 - 0x1ffff].
+ */
+static int spufs_psmap_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (!(vma->vm_flags & VM_SHARED))
+ return -EINVAL;
+
+ vma->vm_flags |= VM_RESERVED;
+ vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
+ | _PAGE_NO_CACHE | _PAGE_GUARDED);
+
+ vma->vm_ops = &spufs_psmap_mmap_vmops;
+ return 0;
+}
+
+static int spufs_psmap_open(struct inode *inode, struct file *file)
+{
+ struct spufs_inode_info *i = SPUFS_I(inode);
+
+ file->private_data = i->i_ctx;
+ return nonseekable_open(inode, file);
+}
+
+static struct file_operations spufs_psmap_fops = {
+ .open = spufs_psmap_open,
+ .mmap = spufs_psmap_mmap,
};
-#ifdef CONFIG_SPUFS_MMAP
+#if SPUFS_MMAP_4K
static struct page *spufs_mfc_mmap_nopage(struct vm_area_struct *vma,
unsigned long address, int *type)
{
- return spufs_ps_nopage(vma, address, type, 0x3000);
+ return spufs_ps_nopage(vma, address, type, 0x3000, 0x1000);
}
static struct vm_operations_struct spufs_mfc_mmap_vmops = {
@@ -886,17 +1035,12 @@ static struct vm_operations_struct spufs_mfc_mmap_vmops = {
/*
* mmap support for problem state MFC DMA area [0x0000 - 0x0fff].
- * Mapping this area requires that the application have CAP_SYS_RAWIO,
- * as these registers require special care when read/writing.
*/
static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
{
if (!(vma->vm_flags & VM_SHARED))
return -EINVAL;
- if (!capable(CAP_SYS_RAWIO))
- return -EPERM;
-
vma->vm_flags |= VM_RESERVED;
vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot)
| _PAGE_NO_CACHE | _PAGE_GUARDED);
@@ -904,7 +1048,9 @@ static int spufs_mfc_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_ops = &spufs_mfc_mmap_vmops;
return 0;
}
-#endif
+#else /* SPUFS_MMAP_4K */
+#define spufs_mfc_mmap NULL
+#endif /* !SPUFS_MMAP_4K */
static int spufs_mfc_open(struct inode *inode, struct file *file)
{
@@ -1194,9 +1340,7 @@ static struct file_operations spufs_mfc_fops = {
.flush = spufs_mfc_flush,
.fsync = spufs_mfc_fsync,
.fasync = spufs_mfc_fasync,
-#ifdef CONFIG_SPUFS_MMAP
.mmap = spufs_mfc_mmap,
-#endif
};
static void spufs_npc_set(void *data, u64 val)
@@ -1342,7 +1486,22 @@ static u64 spufs_id_get(void *data)
return num;
}
-DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, 0, "0x%llx\n")
+DEFINE_SIMPLE_ATTRIBUTE(spufs_id_ops, spufs_id_get, NULL, "0x%llx\n")
+
+static u64 spufs_object_id_get(void *data)
+{
+ struct spu_context *ctx = data;
+ return ctx->object_id;
+}
+
+static void spufs_object_id_set(void *data, u64 id)
+{
+ struct spu_context *ctx = data;
+ ctx->object_id = id;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(spufs_object_id_ops, spufs_object_id_get,
+ spufs_object_id_set, "0x%llx\n");
struct tree_descr spufs_dir_contents[] = {
{ "mem", &spufs_mem_fops, 0666, },
@@ -1367,6 +1526,8 @@ struct tree_descr spufs_dir_contents[] = {
{ "spu_tag_mask", &spufs_spu_tag_mask_ops, 0666, },
{ "event_mask", &spufs_event_mask_ops, 0666, },
{ "srr0", &spufs_srr0_ops, 0666, },
+ { "psmap", &spufs_psmap_fops, 0666, },
{ "phys-id", &spufs_id_ops, 0666, },
+ { "object-id", &spufs_object_id_ops, 0666, },
{},
};
diff --git a/arch/powerpc/platforms/cell/spufs/gang.c b/arch/powerpc/platforms/cell/spufs/gang.c
new file mode 100644
index 000000000000..212ea78f9051
--- /dev/null
+++ b/arch/powerpc/platforms/cell/spufs/gang.c
@@ -0,0 +1,81 @@
+/*
+ * SPU file system
+ *
+ * (C) Copyright IBM Deutschland Entwicklung GmbH 2005
+ *
+ * Author: Arnd Bergmann <arndb@de.ibm.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, 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.
+ */
+
+#include <linux/list.h>
+#include <linux/slab.h>
+
+#include "spufs.h"
+
+struct spu_gang *alloc_spu_gang(void)
+{
+ struct spu_gang *gang;
+
+ gang = kzalloc(sizeof *gang, GFP_KERNEL);
+ if (!gang)
+ goto out;
+
+ kref_init(&gang->kref);
+ mutex_init(&gang->mutex);
+ INIT_LIST_HEAD(&gang->list);
+
+out:
+ return gang;
+}
+
+static void destroy_spu_gang(struct kref *kref)
+{
+ struct spu_gang *gang;
+ gang = container_of(kref, struct spu_gang, kref);
+ WARN_ON(gang->contexts || !list_empty(&gang->list));
+ kfree(gang);
+}
+
+struct spu_gang *get_spu_gang(struct spu_gang *gang)
+{
+ kref_get(&gang->kref);
+ return gang;
+}
+
+int put_spu_gang(struct spu_gang *gang)
+{
+ return kref_put(&gang->kref, &destroy_spu_gang);
+}
+
+void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx)
+{
+ mutex_lock(&gang->mutex);
+ ctx->gang = get_spu_gang(gang);
+ list_add(&ctx->gang_list, &gang->list);
+ gang->contexts++;
+ mutex_unlock(&gang->mutex);
+}
+
+void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx)
+{
+ mutex_lock(&gang->mutex);
+ WARN_ON(ctx->gang != gang);
+ list_del_init(&ctx->gang_list);
+ gang->contexts--;
+ mutex_unlock(&gang->mutex);
+
+ put_spu_gang(gang);
+}
diff --git a/arch/powerpc/platforms/cell/spufs/hw_ops.c b/arch/powerpc/platforms/cell/spufs/hw_ops.c
index c8670f519734..efc452e71ab0 100644
--- a/arch/powerpc/platforms/cell/spufs/hw_ops.c
+++ b/arch/powerpc/platforms/cell/spufs/hw_ops.c
@@ -234,7 +234,7 @@ static void spu_hw_runcntl_stop(struct spu_context *ctx)
static int spu_hw_set_mfc_query(struct spu_context * ctx, u32 mask, u32 mode)
{
- struct spu_problem *prob = ctx->spu->problem;
+ struct spu_problem __iomem *prob = ctx->spu->problem;
int ret;
spin_lock_irq(&ctx->spu->register_lock);
@@ -263,7 +263,7 @@ static int spu_hw_send_mfc_command(struct spu_context *ctx,
struct mfc_dma_command *cmd)
{
u32 status;
- struct spu_problem *prob = ctx->spu->problem;
+ struct spu_problem __iomem *prob = ctx->spu->problem;
spin_lock_irq(&ctx->spu->register_lock);
out_be32(&prob->mfc_lsa_W, cmd->lsa);
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 7b4572805db9..427d00a4f6a0 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -50,6 +50,10 @@ spufs_alloc_inode(struct super_block *sb)
ei = kmem_cache_alloc(spufs_inode_cache, SLAB_KERNEL);
if (!ei)
return NULL;
+
+ ei->i_gang = NULL;
+ ei->i_ctx = NULL;
+
return &ei->vfs_inode;
}
@@ -82,7 +86,6 @@ spufs_new_inode(struct super_block *sb, int mode)
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
out:
@@ -120,7 +123,7 @@ spufs_new_file(struct super_block *sb, struct dentry *dentry,
ret = 0;
inode->i_op = &spufs_file_iops;
inode->i_fop = fops;
- inode->u.generic_ip = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
+ inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx);
d_add(dentry, inode);
out:
return ret;
@@ -129,14 +132,19 @@ out:
static void
spufs_delete_inode(struct inode *inode)
{
- if (SPUFS_I(inode)->i_ctx)
- put_spu_context(SPUFS_I(inode)->i_ctx);
+ struct spufs_inode_info *ei = SPUFS_I(inode);
+
+ if (ei->i_ctx)
+ put_spu_context(ei->i_ctx);
+ if (ei->i_gang)
+ put_spu_gang(ei->i_gang);
clear_inode(inode);
}
static void spufs_prune_dir(struct dentry *dir)
{
struct dentry *dentry, *tmp;
+
mutex_lock(&dir->d_inode->i_mutex);
list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
spin_lock(&dcache_lock);
@@ -157,13 +165,13 @@ static void spufs_prune_dir(struct dentry *dir)
mutex_unlock(&dir->d_inode->i_mutex);
}
-/* Caller must hold root->i_mutex */
-static int spufs_rmdir(struct inode *root, struct dentry *dir_dentry)
+/* Caller must hold parent->i_mutex */
+static int spufs_rmdir(struct inode *parent, struct dentry *dir)
{
/* remove all entries */
- spufs_prune_dir(dir_dentry);
+ spufs_prune_dir(dir);
- return simple_rmdir(root, dir_dentry);
+ return simple_rmdir(parent, dir);
}
static int spufs_fill_dir(struct dentry *dir, struct tree_descr *files,
@@ -192,17 +200,17 @@ out:
static int spufs_dir_close(struct inode *inode, struct file *file)
{
struct spu_context *ctx;
- struct inode *dir;
- struct dentry *dentry;
+ struct inode *parent;
+ struct dentry *dir;
int ret;
- dentry = file->f_dentry;
- dir = dentry->d_parent->d_inode;
- ctx = SPUFS_I(dentry->d_inode)->i_ctx;
+ dir = file->f_dentry;
+ parent = dir->d_parent->d_inode;
+ ctx = SPUFS_I(dir->d_inode)->i_ctx;
- mutex_lock(&dir->i_mutex);
- ret = spufs_rmdir(dir, dentry);
- mutex_unlock(&dir->i_mutex);
+ mutex_lock(&parent->i_mutex);
+ ret = spufs_rmdir(parent, dir);
+ mutex_unlock(&parent->i_mutex);
WARN_ON(ret);
/* We have to give up the mm_struct */
@@ -225,7 +233,8 @@ struct file_operations spufs_context_fops = {
};
static int
-spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+spufs_mkdir(struct inode *dir, struct dentry *dentry, unsigned int flags,
+ int mode)
{
int ret;
struct inode *inode;
@@ -240,11 +249,13 @@ spufs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
inode->i_gid = dir->i_gid;
inode->i_mode &= S_ISGID;
}
- ctx = alloc_spu_context();
+ ctx = alloc_spu_context(SPUFS_I(dir)->i_gang); /* XXX gang */
SPUFS_I(inode)->i_ctx = ctx;
if (!ctx)
goto out_iput;
+ ctx->flags = flags;
+
inode->i_op = &spufs_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
ret = spufs_fill_dir(dentry, spufs_dir_contents, mode, ctx);
@@ -290,24 +301,177 @@ out:
return ret;
}
+static int spufs_create_context(struct inode *inode,
+ struct dentry *dentry,
+ struct vfsmount *mnt, int flags, int mode)
+{
+ int ret;
+
+ ret = spufs_mkdir(inode, dentry, flags, mode & S_IRWXUGO);
+ if (ret)
+ goto out_unlock;
+
+ /*
+ * get references for dget and mntget, will be released
+ * in error path of *_open().
+ */
+ ret = spufs_context_open(dget(dentry), mntget(mnt));
+ if (ret < 0) {
+ WARN_ON(spufs_rmdir(inode, dentry));
+ mutex_unlock(&inode->i_mutex);
+ spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
+ goto out;
+ }
+
+out_unlock:
+ mutex_unlock(&inode->i_mutex);
+out:
+ dput(dentry);
+ return ret;
+}
+
+static int spufs_rmgang(struct inode *root, struct dentry *dir)
+{
+ /* FIXME: this fails if the dir is not empty,
+ which causes a leak of gangs. */
+ return simple_rmdir(root, dir);
+}
+
+static int spufs_gang_close(struct inode *inode, struct file *file)
+{
+ struct inode *parent;
+ struct dentry *dir;
+ int ret;
+
+ dir = file->f_dentry;
+ parent = dir->d_parent->d_inode;
+
+ ret = spufs_rmgang(parent, dir);
+ WARN_ON(ret);
+
+ return dcache_dir_close(inode, file);
+}
+
+struct file_operations spufs_gang_fops = {
+ .open = dcache_dir_open,
+ .release = spufs_gang_close,
+ .llseek = dcache_dir_lseek,
+ .read = generic_read_dir,
+ .readdir = dcache_readdir,
+ .fsync = simple_sync_file,
+};
+
+static int
+spufs_mkgang(struct inode *dir, struct dentry *dentry, int mode)
+{
+ int ret;
+ struct inode *inode;
+ struct spu_gang *gang;
+
+ ret = -ENOSPC;
+ inode = spufs_new_inode(dir->i_sb, mode | S_IFDIR);
+ if (!inode)
+ goto out;
+
+ ret = 0;
+ if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+ inode->i_mode &= S_ISGID;
+ }
+ gang = alloc_spu_gang();
+ SPUFS_I(inode)->i_ctx = NULL;
+ SPUFS_I(inode)->i_gang = gang;
+ if (!gang)
+ goto out_iput;
+
+ inode->i_op = &spufs_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ dir->i_nlink++;
+ dentry->d_inode->i_nlink++;
+ return ret;
+
+out_iput:
+ iput(inode);
+out:
+ return ret;
+}
+
+static int spufs_gang_open(struct dentry *dentry, struct vfsmount *mnt)
+{
+ int ret;
+ struct file *filp;
+
+ ret = get_unused_fd();
+ if (ret < 0) {
+ dput(dentry);
+ mntput(mnt);
+ goto out;
+ }
+
+ filp = dentry_open(dentry, mnt, O_RDONLY);
+ if (IS_ERR(filp)) {
+ put_unused_fd(ret);
+ ret = PTR_ERR(filp);
+ goto out;
+ }
+
+ filp->f_op = &spufs_gang_fops;
+ fd_install(ret, filp);
+out:
+ return ret;
+}
+
+static int spufs_create_gang(struct inode *inode,
+ struct dentry *dentry,
+ struct vfsmount *mnt, int mode)
+{
+ int ret;
+
+ ret = spufs_mkgang(inode, dentry, mode & S_IRWXUGO);
+ if (ret)
+ goto out;
+
+ /*
+ * get references for dget and mntget, will be released
+ * in error path of *_open().
+ */
+ ret = spufs_gang_open(dget(dentry), mntget(mnt));
+ if (ret < 0)
+ WARN_ON(spufs_rmgang(inode, dentry));
+
+out:
+ mutex_unlock(&inode->i_mutex);
+ dput(dentry);
+ return ret;
+}
+
+
static struct file_system_type spufs_type;
-long spufs_create_thread(struct nameidata *nd,
- unsigned int flags, mode_t mode)
+long spufs_create(struct nameidata *nd, unsigned int flags, mode_t mode)
{
struct dentry *dentry;
int ret;
- /* need to be at the root of spufs */
ret = -EINVAL;
- if (nd->dentry->d_sb->s_type != &spufs_type ||
- nd->dentry != nd->dentry->d_sb->s_root)
+ /* check if we are on spufs */
+ if (nd->dentry->d_sb->s_type != &spufs_type)
goto out;
- /* all flags are reserved */
- if (flags)
+ /* don't accept undefined flags */
+ if (flags & (~SPU_CREATE_FLAG_ALL))
goto out;
+ /* only threads can be underneath a gang */
+ if (nd->dentry != nd->dentry->d_sb->s_root) {
+ if ((flags & SPU_CREATE_GANG) ||
+ !SPUFS_I(nd->dentry->d_inode)->i_gang)
+ goto out;
+ }
+
dentry = lookup_create(nd, 1);
ret = PTR_ERR(dentry);
if (IS_ERR(dentry))
@@ -318,22 +482,13 @@ long spufs_create_thread(struct nameidata *nd,
goto out_dput;
mode &= ~current->fs->umask;
- ret = spufs_mkdir(nd->dentry->d_inode, dentry, mode & S_IRWXUGO);
- if (ret)
- goto out_dput;
- /*
- * get references for dget and mntget, will be released
- * in error path of *_open().
- */
- ret = spufs_context_open(dget(dentry), mntget(nd->mnt));
- if (ret < 0) {
- WARN_ON(spufs_rmdir(nd->dentry->d_inode, dentry));
- mutex_unlock(&nd->dentry->d_inode->i_mutex);
- spu_forget(SPUFS_I(dentry->d_inode)->i_ctx);
- dput(dentry);
- goto out;
- }
+ if (flags & SPU_CREATE_GANG)
+ return spufs_create_gang(nd->dentry->d_inode,
+ dentry, nd->mnt, mode);
+ else
+ return spufs_create_context(nd->dentry->d_inode,
+ dentry, nd->mnt, flags, mode);
out_dput:
dput(dentry);
diff --git a/arch/powerpc/platforms/cell/spufs/run.c b/arch/powerpc/platforms/cell/spufs/run.c
index 483c8b76232c..63df8cf4ba16 100644
--- a/arch/powerpc/platforms/cell/spufs/run.c
+++ b/arch/powerpc/platforms/cell/spufs/run.c
@@ -14,6 +14,26 @@ void spufs_stop_callback(struct spu *spu)
wake_up_all(&ctx->stop_wq);
}
+void spufs_dma_callback(struct spu *spu, int type)
+{
+ struct spu_context *ctx = spu->ctx;
+
+ if (ctx->flags & SPU_CREATE_EVENTS_ENABLED) {
+ ctx->event_return |= type;
+ wake_up_all(&ctx->stop_wq);
+ } else {
+ switch (type) {
+ case SPE_EVENT_DMA_ALIGNMENT:
+ case SPE_EVENT_INVALID_DMA:
+ force_sig(SIGBUS, /* info, */ current);
+ break;
+ case SPE_EVENT_SPE_ERROR:
+ force_sig(SIGILL, /* info */ current);
+ break;
+ }
+ }
+}
+
static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
{
struct spu *spu;
@@ -28,8 +48,7 @@ static inline int spu_stopped(struct spu_context *ctx, u32 * stat)
return (!(*stat & 0x1) || pte_fault || spu->class_0_pending) ? 1 : 0;
}
-static inline int spu_run_init(struct spu_context *ctx, u32 * npc,
- u32 * status)
+static inline int spu_run_init(struct spu_context *ctx, u32 * npc)
{
int ret;
@@ -72,7 +91,7 @@ static inline int spu_reacquire_runnable(struct spu_context *ctx, u32 *npc,
SPU_STATUS_STOPPED_BY_HALT)) {
return *status;
}
- if ((ret = spu_run_init(ctx, npc, status)) != 0)
+ if ((ret = spu_run_init(ctx, npc)) != 0)
return ret;
return 0;
}
@@ -177,46 +196,49 @@ static inline int spu_process_events(struct spu_context *ctx)
}
long spufs_run_spu(struct file *file, struct spu_context *ctx,
- u32 * npc, u32 * status)
+ u32 *npc, u32 *event)
{
int ret;
+ u32 status;
if (down_interruptible(&ctx->run_sema))
return -ERESTARTSYS;
- ret = spu_run_init(ctx, npc, status);
+ ctx->event_return = 0;
+ ret = spu_run_init(ctx, npc);
if (ret)
goto out;
do {
- ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, status));
+ ret = spufs_wait(ctx->stop_wq, spu_stopped(ctx, &status));
if (unlikely(ret))
break;
- if ((*status & SPU_STATUS_STOPPED_BY_STOP) &&
- (*status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
+ if ((status & SPU_STATUS_STOPPED_BY_STOP) &&
+ (status >> SPU_STOP_STATUS_SHIFT == 0x2104)) {
ret = spu_process_callback(ctx);
if (ret)
break;
- *status &= ~SPU_STATUS_STOPPED_BY_STOP;
+ status &= ~SPU_STATUS_STOPPED_BY_STOP;
}
if (unlikely(ctx->state != SPU_STATE_RUNNABLE)) {
- ret = spu_reacquire_runnable(ctx, npc, status);
+ ret = spu_reacquire_runnable(ctx, npc, &status);
if (ret)
goto out;
continue;
}
ret = spu_process_events(ctx);
- } while (!ret && !(*status & (SPU_STATUS_STOPPED_BY_STOP |
+ } while (!ret && !(status & (SPU_STATUS_STOPPED_BY_STOP |
SPU_STATUS_STOPPED_BY_HALT)));
ctx->ops->runcntl_stop(ctx);
- ret = spu_run_fini(ctx, npc, status);
+ ret = spu_run_fini(ctx, npc, &status);
if (!ret)
- ret = *status;
+ ret = status;
spu_yield(ctx);
out:
+ *event = ctx->event_return;
up(&ctx->run_sema);
return ret;
}
diff --git a/arch/powerpc/platforms/cell/spufs/sched.c b/arch/powerpc/platforms/cell/spufs/sched.c
index 1350294484b6..bd6fe4b7a84b 100644
--- a/arch/powerpc/platforms/cell/spufs/sched.c
+++ b/arch/powerpc/platforms/cell/spufs/sched.c
@@ -3,11 +3,7 @@
* Copyright (C) IBM 2005
* Author: Mark Nutter <mnutter@us.ibm.com>
*
- * SPU scheduler, based on Linux thread priority. For now use
- * a simple "cooperative" yield model with no preemption. SPU
- * scheduling will eventually be preemptive: When a thread with
- * a higher static priority gets ready to run, then an active SPU
- * context will be preempted and returned to the waitq.
+ * 2006-03-31 NUMA domains added.
*
* 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
@@ -37,6 +33,9 @@
#include <linux/smp_lock.h>
#include <linux/stddef.h>
#include <linux/unistd.h>
+#include <linux/numa.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
#include <asm/io.h>
#include <asm/mmu_context.h>
@@ -49,128 +48,59 @@
#define SPU_BITMAP_SIZE (((MAX_PRIO+BITS_PER_LONG)/BITS_PER_LONG)+1)
struct spu_prio_array {
- atomic_t nr_blocked;
unsigned long bitmap[SPU_BITMAP_SIZE];
wait_queue_head_t waitq[MAX_PRIO];
+ struct list_head active_list[MAX_NUMNODES];
+ struct mutex active_mutex[MAX_NUMNODES];
};
-/* spu_runqueue - This is the main runqueue data structure for SPUs. */
-struct spu_runqueue {
- struct semaphore sem;
- unsigned long nr_active;
- unsigned long nr_idle;
- unsigned long nr_switches;
- struct list_head active_list;
- struct list_head idle_list;
- struct spu_prio_array prio;
-};
-
-static struct spu_runqueue *spu_runqueues = NULL;
-
-static inline struct spu_runqueue *spu_rq(void)
-{
- /* Future: make this a per-NODE array,
- * and use cpu_to_node(smp_processor_id())
- */
- return spu_runqueues;
-}
+static struct spu_prio_array *spu_prio;
-static inline struct spu *del_idle(struct spu_runqueue *rq)
+static inline int node_allowed(int node)
{
- struct spu *spu;
+ cpumask_t mask;
- BUG_ON(rq->nr_idle <= 0);
- BUG_ON(list_empty(&rq->idle_list));
- /* Future: Move SPU out of low-power SRI state. */
- spu = list_entry(rq->idle_list.next, struct spu, sched_list);
- list_del_init(&spu->sched_list);
- rq->nr_idle--;
- return spu;
+ if (!nr_cpus_node(node))
+ return 0;
+ mask = node_to_cpumask(node);
+ if (!cpus_intersects(mask, current->cpus_allowed))
+ return 0;
+ return 1;
}
-static inline void del_active(struct spu_runqueue *rq, struct spu *spu)
+static inline void mm_needs_global_tlbie(struct mm_struct *mm)
{
- BUG_ON(rq->nr_active <= 0);
- BUG_ON(list_empty(&rq->active_list));
- list_del_init(&spu->sched_list);
- rq->nr_active--;
-}
+ int nr = (NR_CPUS > 1) ? NR_CPUS : NR_CPUS + 1;
-static inline void add_idle(struct spu_runqueue *rq, struct spu *spu)
-{
- /* Future: Put SPU into low-power SRI state. */
- list_add_tail(&spu->sched_list, &rq->idle_list);
- rq->nr_idle++;
+ /* Global TLBIE broadcast required with SPEs. */
+ __cpus_setall(&mm->cpu_vm_mask, nr);
}
-static inline void add_active(struct spu_runqueue *rq, struct spu *spu)
-{
- rq->nr_active++;
- rq->nr_switches++;
- list_add_tail(&spu->sched_list, &rq->active_list);
-}
+static BLOCKING_NOTIFIER_HEAD(spu_switch_notifier);
-static void prio_wakeup(struct spu_runqueue *rq)
+static void spu_switch_notify(struct spu *spu, struct spu_context *ctx)
{
- if (atomic_read(&rq->prio.nr_blocked) && rq->nr_idle) {
- int best = sched_find_first_bit(rq->prio.bitmap);
- if (best < MAX_PRIO) {
- wait_queue_head_t *wq = &rq->prio.waitq[best];
- wake_up_interruptible_nr(wq, 1);
- }
- }
+ blocking_notifier_call_chain(&spu_switch_notifier,
+ ctx ? ctx->object_id : 0, spu);
}
-static void prio_wait(struct spu_runqueue *rq, struct spu_context *ctx,
- u64 flags)
+int spu_switch_event_register(struct notifier_block * n)
{
- int prio = current->prio;
- wait_queue_head_t *wq = &rq->prio.waitq[prio];
- DEFINE_WAIT(wait);
-
- __set_bit(prio, rq->prio.bitmap);
- atomic_inc(&rq->prio.nr_blocked);
- prepare_to_wait_exclusive(wq, &wait, TASK_INTERRUPTIBLE);
- if (!signal_pending(current)) {
- up(&rq->sem);
- up_write(&ctx->state_sema);
- pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
- current->pid, current->prio);
- schedule();
- down_write(&ctx->state_sema);
- down(&rq->sem);
- }
- finish_wait(wq, &wait);
- atomic_dec(&rq->prio.nr_blocked);
- if (!waitqueue_active(wq))
- __clear_bit(prio, rq->prio.bitmap);
+ return blocking_notifier_chain_register(&spu_switch_notifier, n);
}
-static inline int is_best_prio(struct spu_runqueue *rq)
+int spu_switch_event_unregister(struct notifier_block * n)
{
- int best_prio;
-
- best_prio = sched_find_first_bit(rq->prio.bitmap);
- return (current->prio < best_prio) ? 1 : 0;
+ return blocking_notifier_chain_unregister(&spu_switch_notifier, n);
}
-static inline void mm_needs_global_tlbie(struct mm_struct *mm)
-{
- /* Global TLBIE broadcast required with SPEs. */
-#if (NR_CPUS > 1)
- __cpus_setall(&mm->cpu_vm_mask, NR_CPUS);
-#else
- __cpus_setall(&mm->cpu_vm_mask, NR_CPUS+1); /* is this ok? */
-#endif
-}
static inline void bind_context(struct spu *spu, struct spu_context *ctx)
{
- pr_debug("%s: pid=%d SPU=%d\n", __FUNCTION__, current->pid,
- spu->number);
+ pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
+ spu->number, spu->node);
spu->ctx = ctx;
spu->flags = 0;
- ctx->flags = 0;
ctx->spu = spu;
ctx->ops = &spu_hw_ops;
spu->pid = current->pid;
@@ -181,16 +111,20 @@ static inline void bind_context(struct spu *spu, struct spu_context *ctx)
spu->wbox_callback = spufs_wbox_callback;
spu->stop_callback = spufs_stop_callback;
spu->mfc_callback = spufs_mfc_callback;
+ spu->dma_callback = spufs_dma_callback;
mb();
spu_unmap_mappings(ctx);
spu_restore(&ctx->csa, spu);
spu->timestamp = jiffies;
+ spu_cpu_affinity_set(spu, raw_smp_processor_id());
+ spu_switch_notify(spu, ctx);
}
static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
{
- pr_debug("%s: unbind pid=%d SPU=%d\n", __FUNCTION__,
- spu->pid, spu->number);
+ pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
+ spu->pid, spu->number, spu->node);
+ spu_switch_notify(spu, NULL);
spu_unmap_mappings(ctx);
spu_save(&ctx->csa, spu);
spu->timestamp = jiffies;
@@ -199,173 +133,158 @@ static inline void unbind_context(struct spu *spu, struct spu_context *ctx)
spu->wbox_callback = NULL;
spu->stop_callback = NULL;
spu->mfc_callback = NULL;
+ spu->dma_callback = NULL;
spu->mm = NULL;
spu->pid = 0;
spu->prio = MAX_PRIO;
ctx->ops = &spu_backing_ops;
ctx->spu = NULL;
- ctx->flags = 0;
spu->flags = 0;
spu->ctx = NULL;
}
-static void spu_reaper(void *data)
+static inline void spu_add_wq(wait_queue_head_t * wq, wait_queue_t * wait,
+ int prio)
{
- struct spu_context *ctx = data;
- struct spu *spu;
-
- down_write(&ctx->state_sema);
- spu = ctx->spu;
- if (spu && test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
- if (atomic_read(&spu->rq->prio.nr_blocked)) {
- pr_debug("%s: spu=%d\n", __func__, spu->number);
- ctx->ops->runcntl_stop(ctx);
- spu_deactivate(ctx);
- wake_up_all(&ctx->stop_wq);
- } else {
- clear_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
- }
- }
- up_write(&ctx->state_sema);
- put_spu_context(ctx);
+ prepare_to_wait_exclusive(wq, wait, TASK_INTERRUPTIBLE);
+ set_bit(prio, spu_prio->bitmap);
}
-static void schedule_spu_reaper(struct spu_runqueue *rq, struct spu *spu)
+static inline void spu_del_wq(wait_queue_head_t * wq, wait_queue_t * wait,
+ int prio)
{
- struct spu_context *ctx = get_spu_context(spu->ctx);
- unsigned long now = jiffies;
- unsigned long expire = spu->timestamp + SPU_MIN_TIMESLICE;
-
- set_bit(SPU_CONTEXT_PREEMPT, &ctx->flags);
- INIT_WORK(&ctx->reap_work, spu_reaper, ctx);
- if (time_after(now, expire))
- schedule_work(&ctx->reap_work);
- else
- schedule_delayed_work(&ctx->reap_work, expire - now);
-}
+ u64 flags;
-static void check_preempt_active(struct spu_runqueue *rq)
-{
- struct list_head *p;
- struct spu *worst = NULL;
-
- list_for_each(p, &rq->active_list) {
- struct spu *spu = list_entry(p, struct spu, sched_list);
- struct spu_context *ctx = spu->ctx;
- if (!test_bit(SPU_CONTEXT_PREEMPT, &ctx->flags)) {
- if (!worst || (spu->prio > worst->prio)) {
- worst = spu;
- }
- }
- }
- if (worst && (current->prio < worst->prio))
- schedule_spu_reaper(rq, worst);
+ __set_current_state(TASK_RUNNING);
+
+ spin_lock_irqsave(&wq->lock, flags);
+
+ remove_wait_queue_locked(wq, wait);
+ if (list_empty(&wq->task_list))
+ clear_bit(prio, spu_prio->bitmap);
+
+ spin_unlock_irqrestore(&wq->lock, flags);
}
-static struct spu *get_idle_spu(struct spu_context *ctx, u64 flags)
+static void spu_prio_wait(struct spu_context *ctx, u64 flags)
{
- struct spu_runqueue *rq;
- struct spu *spu = NULL;
+ int prio = current->prio;
+ wait_queue_head_t *wq = &spu_prio->waitq[prio];
+ DEFINE_WAIT(wait);
- rq = spu_rq();
- down(&rq->sem);
- for (;;) {
- if (rq->nr_idle > 0) {
- if (is_best_prio(rq)) {
- /* Fall through. */
- spu = del_idle(rq);
- break;
- } else {
- prio_wakeup(rq);
- up(&rq->sem);
- yield();
- if (signal_pending(current)) {
- return NULL;
- }
- rq = spu_rq();
- down(&rq->sem);
- continue;
- }
- } else {
- check_preempt_active(rq);
- prio_wait(rq, ctx, flags);
- if (signal_pending(current)) {
- prio_wakeup(rq);
- spu = NULL;
- break;
- }
- continue;
- }
+ if (ctx->spu)
+ return;
+
+ spu_add_wq(wq, &wait, prio);
+
+ if (!signal_pending(current)) {
+ up_write(&ctx->state_sema);
+ pr_debug("%s: pid=%d prio=%d\n", __FUNCTION__,
+ current->pid, current->prio);
+ schedule();
+ down_write(&ctx->state_sema);
}
- up(&rq->sem);
- return spu;
+
+ spu_del_wq(wq, &wait, prio);
}
-static void put_idle_spu(struct spu *spu)
+static void spu_prio_wakeup(void)
{
- struct spu_runqueue *rq = spu->rq;
-
- down(&rq->sem);
- add_idle(rq, spu);
- prio_wakeup(rq);
- up(&rq->sem);
+ int best = sched_find_first_bit(spu_prio->bitmap);
+ if (best < MAX_PRIO) {
+ wait_queue_head_t *wq = &spu_prio->waitq[best];
+ wake_up_interruptible_nr(wq, 1);
+ }
}
static int get_active_spu(struct spu *spu)
{
- struct spu_runqueue *rq = spu->rq;
- struct list_head *p;
+ int node = spu->node;
struct spu *tmp;
int rc = 0;
- down(&rq->sem);
- list_for_each(p, &rq->active_list) {
- tmp = list_entry(p, struct spu, sched_list);
+ mutex_lock(&spu_prio->active_mutex[node]);
+ list_for_each_entry(tmp, &spu_prio->active_list[node], list) {
if (tmp == spu) {
- del_active(rq, spu);
+ list_del_init(&spu->list);
rc = 1;
break;
}
}
- up(&rq->sem);
+ mutex_unlock(&spu_prio->active_mutex[node]);
return rc;
}
static void put_active_spu(struct spu *spu)
{
- struct spu_runqueue *rq = spu->rq;
+ int node = spu->node;
+
+ mutex_lock(&spu_prio->active_mutex[node]);
+ list_add_tail(&spu->list, &spu_prio->active_list[node]);
+ mutex_unlock(&spu_prio->active_mutex[node]);
+}
+
+static struct spu *spu_get_idle(struct spu_context *ctx, u64 flags)
+{
+ struct spu *spu = NULL;
+ int node = cpu_to_node(raw_smp_processor_id());
+ int n;
- down(&rq->sem);
- add_active(rq, spu);
- up(&rq->sem);
+ for (n = 0; n < MAX_NUMNODES; n++, node++) {
+ node = (node < MAX_NUMNODES) ? node : 0;
+ if (!node_allowed(node))
+ continue;
+ spu = spu_alloc_node(node);
+ if (spu)
+ break;
+ }
+ return spu;
}
-/* Lock order:
- * spu_activate() & spu_deactivate() require the
- * caller to have down_write(&ctx->state_sema).
+static inline struct spu *spu_get(struct spu_context *ctx, u64 flags)
+{
+ /* Future: spu_get_idle() if possible,
+ * otherwise try to preempt an active
+ * context.
+ */
+ return spu_get_idle(ctx, flags);
+}
+
+/* The three externally callable interfaces
+ * for the scheduler begin here.
*
- * The rq->sem is breifly held (inside or outside a
- * given ctx lock) for list management, but is never
- * held during save/restore.
+ * spu_activate - bind a context to SPU, waiting as needed.
+ * spu_deactivate - unbind a context from its SPU.
+ * spu_yield - yield an SPU if others are waiting.
*/
int spu_activate(struct spu_context *ctx, u64 flags)
{
struct spu *spu;
+ int ret = 0;
- if (ctx->spu)
- return 0;
- spu = get_idle_spu(ctx, flags);
- if (!spu)
- return (signal_pending(current)) ? -ERESTARTSYS : -EAGAIN;
- bind_context(spu, ctx);
- /*
- * We're likely to wait for interrupts on the same
- * CPU that we are now on, so send them here.
- */
- spu_cpu_affinity_set(spu, raw_smp_processor_id());
- put_active_spu(spu);
- return 0;
+ for (;;) {
+ if (ctx->spu)
+ return 0;
+ spu = spu_get(ctx, flags);
+ if (spu != NULL) {
+ if (ctx->spu != NULL) {
+ spu_free(spu);
+ spu_prio_wakeup();
+ break;
+ }
+ bind_context(spu, ctx);
+ put_active_spu(spu);
+ break;
+ }
+ spu_prio_wait(ctx, flags);
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ spu_prio_wakeup();
+ break;
+ }
+ }
+ return ret;
}
void spu_deactivate(struct spu_context *ctx)
@@ -378,8 +297,10 @@ void spu_deactivate(struct spu_context *ctx)
return;
needs_idle = get_active_spu(spu);
unbind_context(spu, ctx);
- if (needs_idle)
- put_idle_spu(spu);
+ if (needs_idle) {
+ spu_free(spu);
+ spu_prio_wakeup();
+ }
}
void spu_yield(struct spu_context *ctx)
@@ -387,77 +308,60 @@ void spu_yield(struct spu_context *ctx)
struct spu *spu;
int need_yield = 0;
- down_write(&ctx->state_sema);
- spu = ctx->spu;
- if (spu && (sched_find_first_bit(spu->rq->prio.bitmap) < MAX_PRIO)) {
- pr_debug("%s: yielding SPU %d\n", __FUNCTION__, spu->number);
- spu_deactivate(ctx);
- ctx->state = SPU_STATE_SAVED;
- need_yield = 1;
- } else if (spu) {
- spu->prio = MAX_PRIO;
+ if (down_write_trylock(&ctx->state_sema)) {
+ if ((spu = ctx->spu) != NULL) {
+ int best = sched_find_first_bit(spu_prio->bitmap);
+ if (best < MAX_PRIO) {
+ pr_debug("%s: yielding SPU %d NODE %d\n",
+ __FUNCTION__, spu->number, spu->node);
+ spu_deactivate(ctx);
+ ctx->state = SPU_STATE_SAVED;
+ need_yield = 1;
+ } else {
+ spu->prio = MAX_PRIO;
+ }
+ }
+ up_write(&ctx->state_sema);
}
- up_write(&ctx->state_sema);
if (unlikely(need_yield))
yield();
}
int __init spu_sched_init(void)
{
- struct spu_runqueue *rq;
- struct spu *spu;
int i;
- rq = spu_runqueues = kmalloc(sizeof(struct spu_runqueue), GFP_KERNEL);
- if (!rq) {
- printk(KERN_WARNING "%s: Unable to allocate runqueues.\n",
+ spu_prio = kzalloc(sizeof(struct spu_prio_array), GFP_KERNEL);
+ if (!spu_prio) {
+ printk(KERN_WARNING "%s: Unable to allocate priority queue.\n",
__FUNCTION__);
return 1;
}
- memset(rq, 0, sizeof(struct spu_runqueue));
- init_MUTEX(&rq->sem);
- INIT_LIST_HEAD(&rq->active_list);
- INIT_LIST_HEAD(&rq->idle_list);
- rq->nr_active = 0;
- rq->nr_idle = 0;
- rq->nr_switches = 0;
- atomic_set(&rq->prio.nr_blocked, 0);
for (i = 0; i < MAX_PRIO; i++) {
- init_waitqueue_head(&rq->prio.waitq[i]);
- __clear_bit(i, rq->prio.bitmap);
+ init_waitqueue_head(&spu_prio->waitq[i]);
+ __clear_bit(i, spu_prio->bitmap);
}
- __set_bit(MAX_PRIO, rq->prio.bitmap);
- for (;;) {
- spu = spu_alloc();
- if (!spu)
- break;
- pr_debug("%s: adding SPU[%d]\n", __FUNCTION__, spu->number);
- add_idle(rq, spu);
- spu->rq = rq;
- spu->timestamp = jiffies;
- }
- if (!rq->nr_idle) {
- printk(KERN_WARNING "%s: No available SPUs.\n", __FUNCTION__);
- kfree(rq);
- return 1;
+ __set_bit(MAX_PRIO, spu_prio->bitmap);
+ for (i = 0; i < MAX_NUMNODES; i++) {
+ mutex_init(&spu_prio->active_mutex[i]);
+ INIT_LIST_HEAD(&spu_prio->active_list[i]);
}
return 0;
}
void __exit spu_sched_exit(void)
{
- struct spu_runqueue *rq = spu_rq();
- struct spu *spu;
-
- if (!rq) {
- printk(KERN_WARNING "%s: no runqueues!\n", __FUNCTION__);
- return;
- }
- while (rq->nr_idle > 0) {
- spu = del_idle(rq);
- if (!spu)
- break;
- spu_free(spu);
+ struct spu *spu, *tmp;
+ int node;
+
+ for (node = 0; node < MAX_NUMNODES; node++) {
+ mutex_lock(&spu_prio->active_mutex[node]);
+ list_for_each_entry_safe(spu, tmp, &spu_prio->active_list[node],
+ list) {
+ list_del_init(&spu->list);
+ spu_free(spu);
+ }
+ mutex_unlock(&spu_prio->active_mutex[node]);
}
- kfree(rq);
+ kfree(spu_prio);
}
diff --git a/arch/powerpc/platforms/cell/spufs/spufs.h b/arch/powerpc/platforms/cell/spufs/spufs.h
index 4485738e2102..a0f55ca2d488 100644
--- a/arch/powerpc/platforms/cell/spufs/spufs.h
+++ b/arch/powerpc/platforms/cell/spufs/spufs.h
@@ -39,6 +39,8 @@ struct spu_context_ops;
#define SPU_CONTEXT_PREEMPT 0UL
+struct spu_gang;
+
struct spu_context {
struct spu *spu; /* pointer to a physical SPU */
struct spu_state csa; /* SPU context save area. */
@@ -48,6 +50,7 @@ struct spu_context {
struct address_space *cntl; /* 'control' area mappings. */
struct address_space *signal1; /* 'signal1' area mappings. */
struct address_space *signal2; /* 'signal2' area mappings. */
+ u64 object_id; /* user space pointer for oprofile */
enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
struct rw_semaphore state_sema;
@@ -66,7 +69,18 @@ struct spu_context {
u32 tagwait;
struct spu_context_ops *ops;
struct work_struct reap_work;
- u64 flags;
+ unsigned long flags;
+ unsigned long event_return;
+
+ struct list_head gang_list;
+ struct spu_gang *gang;
+};
+
+struct spu_gang {
+ struct list_head list;
+ struct mutex mutex;
+ struct kref kref;
+ int contexts;
};
struct mfc_dma_command {
@@ -114,6 +128,7 @@ extern struct spu_context_ops spu_backing_ops;
struct spufs_inode_info {
struct spu_context *i_ctx;
+ struct spu_gang *i_gang;
struct inode vfs_inode;
};
#define SPUFS_I(inode) \
@@ -124,12 +139,19 @@ extern struct tree_descr spufs_dir_contents[];
/* system call implementation */
long spufs_run_spu(struct file *file,
struct spu_context *ctx, u32 *npc, u32 *status);
-long spufs_create_thread(struct nameidata *nd,
+long spufs_create(struct nameidata *nd,
unsigned int flags, mode_t mode);
extern struct file_operations spufs_context_fops;
+/* gang management */
+struct spu_gang *alloc_spu_gang(void);
+struct spu_gang *get_spu_gang(struct spu_gang *gang);
+int put_spu_gang(struct spu_gang *gang);
+void spu_gang_remove_ctx(struct spu_gang *gang, struct spu_context *ctx);
+void spu_gang_add_ctx(struct spu_gang *gang, struct spu_context *ctx);
+
/* context management */
-struct spu_context * alloc_spu_context(void);
+struct spu_context * alloc_spu_context(struct spu_gang *gang);
void destroy_spu_context(struct kref *kref);
struct spu_context * get_spu_context(struct spu_context *ctx);
int put_spu_context(struct spu_context *ctx);
@@ -183,5 +205,6 @@ void spufs_ibox_callback(struct spu *spu);
void spufs_wbox_callback(struct spu *spu);
void spufs_stop_callback(struct spu *spu);
void spufs_mfc_callback(struct spu *spu);
+void spufs_dma_callback(struct spu *spu, int type);
#endif
diff --git a/arch/powerpc/platforms/cell/spufs/switch.c b/arch/powerpc/platforms/cell/spufs/switch.c
index 9d9d82dd32ba..0f782ca662ba 100644
--- a/arch/powerpc/platforms/cell/spufs/switch.c
+++ b/arch/powerpc/platforms/cell/spufs/switch.c
@@ -1779,6 +1779,15 @@ static inline void restore_mfc_cntl(struct spu_state *csa, struct spu *spu)
*/
out_be64(&priv2->mfc_control_RW, csa->priv2.mfc_control_RW);
eieio();
+ /*
+ * FIXME: this is to restart a DMA that we were processing
+ * before the save. better remember the fault information
+ * in the csa instead.
+ */
+ if ((csa->priv2.mfc_control_RW & MFC_CNTL_SUSPEND_DMA_QUEUE_MASK)) {
+ out_be64(&priv2->mfc_control_RW, MFC_CNTL_RESTART_DMA_COMMAND);
+ eieio();
+ }
}
static inline void enable_user_access(struct spu_state *csa, struct spu *spu)
diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c
index e6565a949ddc..a6d1ae4dc2a3 100644
--- a/arch/powerpc/platforms/cell/spufs/syscalls.c
+++ b/arch/powerpc/platforms/cell/spufs/syscalls.c
@@ -38,7 +38,7 @@ static long do_spu_run(struct file *filp,
u32 npc, status;
ret = -EFAULT;
- if (get_user(npc, unpc) || get_user(status, ustatus))
+ if (get_user(npc, unpc))
goto out;
/* check if this file was created by spu_create */
@@ -49,7 +49,10 @@ static long do_spu_run(struct file *filp,
i = SPUFS_I(filp->f_dentry->d_inode);
ret = spufs_run_spu(filp, i->i_ctx, &npc, &status);
- if (put_user(npc, unpc) || put_user(status, ustatus))
+ if (put_user(npc, unpc))
+ ret = -EFAULT;
+
+ if (ustatus && put_user(status, ustatus))
ret = -EFAULT;
out:
return ret;
@@ -87,7 +90,7 @@ asmlinkage long sys_spu_create(const char __user *pathname,
ret = path_lookup(tmp, LOOKUP_PARENT|
LOOKUP_OPEN|LOOKUP_CREATE, &nd);
if (!ret) {
- ret = spufs_create_thread(&nd, flags, mode);
+ ret = spufs_create(&nd, flags, mode);
path_release(&nd);
}
putname(tmp);
diff --git a/arch/powerpc/platforms/chrp/setup.c b/arch/powerpc/platforms/chrp/setup.c
index 488dbd9b51ae..cae3d13229b9 100644
--- a/arch/powerpc/platforms/chrp/setup.c
+++ b/arch/powerpc/platforms/chrp/setup.c
@@ -70,7 +70,7 @@ unsigned long event_scan_interval;
* has to include <linux/interrupt.h> (to get irqreturn_t), which
* causes all sorts of problems. -- paulus
*/
-extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
+extern irqreturn_t xmon_irq(int, void *);
extern unsigned long loops_per_jiffy;
@@ -335,12 +335,11 @@ chrp_event_scan(unsigned long unused)
jiffies + event_scan_interval);
}
-static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+static void chrp_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
- unsigned int cascade_irq = i8259_irq(regs);
+ unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ)
- generic_handle_irq(cascade_irq, regs);
+ generic_handle_irq(cascade_irq);
desc->chip->eoi(irq);
}
diff --git a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
index e4f2b9df5e17..bdb475c65cba 100644
--- a/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
+++ b/arch/powerpc/platforms/embedded6xx/mpc7448_hpc2.c
@@ -18,7 +18,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -62,8 +61,7 @@ pci_dram_offset = MPC7448_HPC2_PCI_MEM_OFFSET;
extern int tsi108_setup_pci(struct device_node *dev);
extern void _nmask_and_or_msr(unsigned long nmask, unsigned long or_val);
extern void tsi108_pci_int_init(void);
-extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
+extern void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc);
int mpc7448_hpc2_exclude_device(u_char bus, u_char devfn)
{
@@ -201,7 +199,7 @@ static void __init mpc7448_hpc2_init_IRQ(void)
tsi_pic = of_find_node_by_type(NULL, "open-pic");
if (tsi_pic) {
unsigned int size;
- void *prop = get_property(tsi_pic, "reg", &size);
+ const void *prop = get_property(tsi_pic, "reg", &size);
mpic_paddr = of_translate_address(tsi_pic, prop);
}
diff --git a/arch/powerpc/platforms/iseries/irq.c b/arch/powerpc/platforms/iseries/irq.c
index e32446877e78..5225abfafd9b 100644
--- a/arch/powerpc/platforms/iseries/irq.c
+++ b/arch/powerpc/platforms/iseries/irq.c
@@ -43,10 +43,7 @@
#include "irq.h"
#include "pci.h"
#include "call_pci.h"
-
-#if defined(CONFIG_SMP)
-extern void iSeries_smp_message_recv(struct pt_regs *);
-#endif
+#include "smp.h"
#ifdef CONFIG_PCI
@@ -88,7 +85,7 @@ static DEFINE_SPINLOCK(pending_irqs_lock);
static int num_pending_irqs;
static int pending_irqs[NR_IRQS];
-static void int_received(struct pci_event *event, struct pt_regs *regs)
+static void int_received(struct pci_event *event)
{
int irq;
@@ -146,11 +143,11 @@ static void int_received(struct pci_event *event, struct pt_regs *regs)
}
}
-static void pci_event_handler(struct HvLpEvent *event, struct pt_regs *regs)
+static void pci_event_handler(struct HvLpEvent *event)
{
if (event && (event->xType == HvLpEvent_Type_PciIo)) {
if (hvlpevent_is_int(event))
- int_received((struct pci_event *)event, regs);
+ int_received((struct pci_event *)event);
else
printk(KERN_ERR
"pci_event_handler: unexpected ack received\n");
@@ -308,18 +305,18 @@ int __init iSeries_allocate_IRQ(HvBusNumber bus,
/*
* Get the next pending IRQ.
*/
-unsigned int iSeries_get_irq(struct pt_regs *regs)
+unsigned int iSeries_get_irq(void)
{
int irq = NO_IRQ_IGNORE;
#ifdef CONFIG_SMP
if (get_lppaca()->int_dword.fields.ipi_cnt) {
get_lppaca()->int_dword.fields.ipi_cnt = 0;
- iSeries_smp_message_recv(regs);
+ iSeries_smp_message_recv();
}
#endif /* CONFIG_SMP */
if (hvlpevent_is_pending())
- process_hvlpevents(regs);
+ process_hvlpevents();
#ifdef CONFIG_PCI
if (num_pending_irqs) {
diff --git a/arch/powerpc/platforms/iseries/irq.h b/arch/powerpc/platforms/iseries/irq.h
index 1ee8985140e5..69f1b437fc7b 100644
--- a/arch/powerpc/platforms/iseries/irq.h
+++ b/arch/powerpc/platforms/iseries/irq.h
@@ -4,6 +4,6 @@
extern void iSeries_init_IRQ(void);
extern int iSeries_allocate_IRQ(HvBusNumber, HvSubBusNumber, u32);
extern void iSeries_activate_IRQs(void);
-extern unsigned int iSeries_get_irq(struct pt_regs *);
+extern unsigned int iSeries_get_irq(void);
#endif /* _ISERIES_IRQ_H */
diff --git a/arch/powerpc/platforms/iseries/lpevents.c b/arch/powerpc/platforms/iseries/lpevents.c
index 98c1c2440aad..e3e929e1b460 100644
--- a/arch/powerpc/platforms/iseries/lpevents.c
+++ b/arch/powerpc/platforms/iseries/lpevents.c
@@ -116,7 +116,7 @@ static void hvlpevent_clear_valid(struct HvLpEvent * event)
hvlpevent_invalidate(event);
}
-void process_hvlpevents(struct pt_regs *regs)
+void process_hvlpevents(void)
{
struct HvLpEvent * event;
@@ -144,7 +144,7 @@ void process_hvlpevents(struct pt_regs *regs)
__get_cpu_var(hvlpevent_counts)[event->xType]++;
if (event->xType < HvLpEvent_Type_NumTypes &&
lpEventHandler[event->xType])
- lpEventHandler[event->xType](event, regs);
+ lpEventHandler[event->xType](event);
else
printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType );
diff --git a/arch/powerpc/platforms/iseries/mf.c b/arch/powerpc/platforms/iseries/mf.c
index 1a2c2a50f922..b5737d68d6c4 100644
--- a/arch/powerpc/platforms/iseries/mf.c
+++ b/arch/powerpc/platforms/iseries/mf.c
@@ -357,7 +357,7 @@ static int dma_and_signal_ce_msg(char *ce_msg,
*/
static int shutdown(void)
{
- int rc = kill_proc(1, SIGINT, 1);
+ int rc = kill_cad_pid(SIGINT, 1);
if (rc) {
printk(KERN_ALERT "mf.c: SIGINT to init failed (%d), "
@@ -513,7 +513,7 @@ static void handle_ack(struct io_mf_lp_event *event)
* parse it enough to know if it is an interrupt or an
* acknowledge.
*/
-static void hv_handler(struct HvLpEvent *event, struct pt_regs *regs)
+static void hv_handler(struct HvLpEvent *event)
{
if ((event != NULL) && (event->xType == HvLpEvent_Type_MachineFac)) {
if (hvlpevent_is_ack(event))
@@ -847,7 +847,7 @@ static int mf_get_boot_rtc(struct rtc_time *tm)
/* We need to poll here as we are not yet taking interrupts */
while (rtc_data.busy) {
if (hvlpevent_is_pending())
- process_hvlpevents(NULL);
+ process_hvlpevents();
}
return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
}
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 3eb12065df23..4aa165e010d9 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -262,14 +262,6 @@ void __init iSeries_pci_final_fixup(void)
mf_display_src(0xC9000200);
}
-void pcibios_fixup_bus(struct pci_bus *PciBus)
-{
-}
-
-void pcibios_fixup_resources(struct pci_dev *pdev)
-{
-}
-
/*
* Look down the chain to find the matching Device Device
*/
diff --git a/arch/powerpc/platforms/iseries/setup.c b/arch/powerpc/platforms/iseries/setup.c
index 7f1953066ff8..a0ff7ba7d666 100644
--- a/arch/powerpc/platforms/iseries/setup.c
+++ b/arch/powerpc/platforms/iseries/setup.c
@@ -649,15 +649,21 @@ static void iseries_dedicated_idle(void)
void __init iSeries_init_IRQ(void) { }
#endif
+/*
+ * iSeries has no legacy IO, anything calling this function has to
+ * fail or bad things will happen
+ */
+static int iseries_check_legacy_ioport(unsigned int baseport)
+{
+ return -ENODEV;
+}
+
static int __init iseries_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "IBM,iSeries"))
return 0;
- powerpc_firmware_features |= FW_FEATURE_ISERIES;
- powerpc_firmware_features |= FW_FEATURE_LPAR;
-
hpte_init_iSeries();
return 1;
@@ -680,6 +686,7 @@ define_machine(iseries) {
.calibrate_decr = generic_calibrate_decr,
.progress = iSeries_progress,
.probe = iseries_probe,
+ .check_legacy_ioport = iseries_check_legacy_ioport,
/* XXX Implement enable_pmcs for iSeries */
};
@@ -687,6 +694,9 @@ void * __init iSeries_early_setup(void)
{
unsigned long phys_mem_size;
+ powerpc_firmware_features |= FW_FEATURE_ISERIES;
+ powerpc_firmware_features |= FW_FEATURE_LPAR;
+
iSeries_fixup_klimit();
/*
diff --git a/arch/powerpc/platforms/iseries/smp.c b/arch/powerpc/platforms/iseries/smp.c
index 2eb095edb472..aee5908df700 100644
--- a/arch/powerpc/platforms/iseries/smp.c
+++ b/arch/powerpc/platforms/iseries/smp.c
@@ -43,9 +43,11 @@
#include <asm/cputable.h>
#include <asm/system.h>
+#include "smp.h"
+
static unsigned long iSeries_smp_message[NR_CPUS];
-void iSeries_smp_message_recv(struct pt_regs *regs)
+void iSeries_smp_message_recv(void)
{
int cpu = smp_processor_id();
int msg;
@@ -55,7 +57,7 @@ void iSeries_smp_message_recv(struct pt_regs *regs)
for (msg = 0; msg < 4; msg++)
if (test_and_clear_bit(msg, &iSeries_smp_message[cpu]))
- smp_message_recv(msg, regs);
+ smp_message_recv(msg);
}
static inline void smp_iSeries_do_message(int cpu, int msg)
diff --git a/arch/powerpc/platforms/iseries/smp.h b/arch/powerpc/platforms/iseries/smp.h
new file mode 100644
index 000000000000..d501f7de01e7
--- /dev/null
+++ b/arch/powerpc/platforms/iseries/smp.h
@@ -0,0 +1,6 @@
+#ifndef _PLATFORMS_ISERIES_SMP_H
+#define _PLATFORMS_ISERIES_SMP_H
+
+extern void iSeries_smp_message_recv(void);
+
+#endif /* _PLATFORMS_ISERIES_SMP_H */
diff --git a/arch/powerpc/platforms/iseries/viopath.c b/arch/powerpc/platforms/iseries/viopath.c
index 9baa4ee82592..04e07e5da0c1 100644
--- a/arch/powerpc/platforms/iseries/viopath.c
+++ b/arch/powerpc/platforms/iseries/viopath.c
@@ -378,7 +378,7 @@ void vio_set_hostlp(void)
}
EXPORT_SYMBOL(vio_set_hostlp);
-static void vio_handleEvent(struct HvLpEvent *event, struct pt_regs *regs)
+static void vio_handleEvent(struct HvLpEvent *event)
{
HvLpIndex remoteLp;
int subtype = (event->xSubtype & VIOMAJOR_SUBTYPE_MASK)
diff --git a/arch/powerpc/platforms/maple/pci.c b/arch/powerpc/platforms/maple/pci.c
index c3aa46b8e2b9..63b4d1bff359 100644
--- a/arch/powerpc/platforms/maple/pci.c
+++ b/arch/powerpc/platforms/maple/pci.c
@@ -8,7 +8,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#define DEBUG
+#undef DEBUG
#include <linux/kernel.h>
#include <linux/pci.h>
@@ -16,6 +16,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/irq.h>
#include <asm/sections.h>
#include <asm/io.h>
@@ -33,7 +34,7 @@
#define DBG(x...)
#endif
-static struct pci_controller *u3_agp, *u3_ht;
+static struct pci_controller *u3_agp, *u3_ht, *u4_pcie;
static int __init fixup_one_level_bus_range(struct device_node *node, int higher)
{
@@ -96,14 +97,14 @@ static unsigned long u3_agp_cfa1(u8 bus, u8 devfn, u8 off)
1UL;
}
-static unsigned long u3_agp_cfg_access(struct pci_controller* hose,
+static volatile void __iomem *u3_agp_cfg_access(struct pci_controller* hose,
u8 bus, u8 dev_fn, u8 offset)
{
unsigned int caddr;
if (bus == hose->first_busno) {
if (dev_fn < (11 << 3))
- return 0;
+ return NULL;
caddr = u3_agp_cfa0(dev_fn, offset);
} else
caddr = u3_agp_cfa1(bus, dev_fn, offset);
@@ -114,14 +115,14 @@ static unsigned long u3_agp_cfg_access(struct pci_controller* hose,
} while (in_le32(hose->cfg_addr) != caddr);
offset &= 0x07;
- return ((unsigned long)hose->cfg_data) + offset;
+ return hose->cfg_data + offset;
}
static int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct pci_controller *hose;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -136,13 +137,13 @@ static int u3_agp_read_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- *val = in_8((u8 *)addr);
+ *val = in_8(addr);
break;
case 2:
- *val = in_le16((u16 *)addr);
+ *val = in_le16(addr);
break;
default:
- *val = in_le32((u32 *)addr);
+ *val = in_le32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -152,7 +153,7 @@ static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct pci_controller *hose;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -167,16 +168,16 @@ static int u3_agp_write_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- out_8((u8 *)addr, val);
- (void) in_8((u8 *)addr);
+ out_8(addr, val);
+ (void) in_8(addr);
break;
case 2:
- out_le16((u16 *)addr, val);
- (void) in_le16((u16 *)addr);
+ out_le16(addr, val);
+ (void) in_le16(addr);
break;
default:
- out_le32((u32 *)addr, val);
- (void) in_le32((u32 *)addr);
+ out_le32(addr, val);
+ (void) in_le32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -198,22 +199,22 @@ static unsigned long u3_ht_cfa1(u8 bus, u8 devfn, u8 off)
return u3_ht_cfa0(devfn, off) + (bus << 16) + 0x01000000UL;
}
-static unsigned long u3_ht_cfg_access(struct pci_controller* hose,
+static volatile void __iomem *u3_ht_cfg_access(struct pci_controller* hose,
u8 bus, u8 devfn, u8 offset)
{
if (bus == hose->first_busno) {
if (PCI_SLOT(devfn) == 0)
- return 0;
- return ((unsigned long)hose->cfg_data) + u3_ht_cfa0(devfn, offset);
+ return NULL;
+ return hose->cfg_data + u3_ht_cfa0(devfn, offset);
} else
- return ((unsigned long)hose->cfg_data) + u3_ht_cfa1(bus, devfn, offset);
+ return hose->cfg_data + u3_ht_cfa1(bus, devfn, offset);
}
static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct pci_controller *hose;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -232,13 +233,13 @@ static int u3_ht_read_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- *val = in_8((u8 *)addr);
+ *val = in_8(addr);
break;
case 2:
- *val = in_le16((u16 *)addr);
+ *val = in_le16(addr);
break;
default:
- *val = in_le32((u32 *)addr);
+ *val = in_le32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -248,7 +249,7 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct pci_controller *hose;
- unsigned long addr;
+ volatile void __iomem *addr;
hose = pci_bus_to_host(bus);
if (hose == NULL)
@@ -266,16 +267,16 @@ static int u3_ht_write_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- out_8((u8 *)addr, val);
- (void) in_8((u8 *)addr);
+ out_8(addr, val);
+ (void) in_8(addr);
break;
case 2:
- out_le16((u16 *)addr, val);
- (void) in_le16((u16 *)addr);
+ out_le16(addr, val);
+ (void) in_le16(addr);
break;
default:
- out_le32((u32 *)addr, val);
- (void) in_le32((u32 *)addr);
+ out_le32(addr, val);
+ (void) in_le32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
@@ -287,6 +288,114 @@ static struct pci_ops u3_ht_pci_ops =
u3_ht_write_config
};
+static unsigned int u4_pcie_cfa0(unsigned int devfn, unsigned int off)
+{
+ return (1 << PCI_SLOT(devfn)) |
+ (PCI_FUNC(devfn) << 8) |
+ ((off >> 8) << 28) |
+ (off & 0xfcu);
+}
+
+static unsigned int u4_pcie_cfa1(unsigned int bus, unsigned int devfn,
+ unsigned int off)
+{
+ return (bus << 16) |
+ (devfn << 8) |
+ ((off >> 8) << 28) |
+ (off & 0xfcu) | 1u;
+}
+
+static volatile void __iomem *u4_pcie_cfg_access(struct pci_controller* hose,
+ u8 bus, u8 dev_fn, int offset)
+{
+ unsigned int caddr;
+
+ if (bus == hose->first_busno)
+ caddr = u4_pcie_cfa0(dev_fn, offset);
+ else
+ caddr = u4_pcie_cfa1(bus, dev_fn, offset);
+
+ /* Uninorth will return garbage if we don't read back the value ! */
+ do {
+ out_le32(hose->cfg_addr, caddr);
+ } while (in_le32(hose->cfg_addr) != caddr);
+
+ offset &= 0x03;
+ return hose->cfg_data + offset;
+}
+
+static int u4_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 *val)
+{
+ struct pci_controller *hose;
+ volatile void __iomem *addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset >= 0x1000)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ *val = in_8(addr);
+ break;
+ case 2:
+ *val = in_le16(addr);
+ break;
+ default:
+ *val = in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+static int u4_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
+ int offset, int len, u32 val)
+{
+ struct pci_controller *hose;
+ volatile void __iomem *addr;
+
+ hose = pci_bus_to_host(bus);
+ if (hose == NULL)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ if (offset >= 0x1000)
+ return PCIBIOS_BAD_REGISTER_NUMBER;
+ addr = u4_pcie_cfg_access(hose, bus->number, devfn, offset);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ /*
+ * Note: the caller has already checked that offset is
+ * suitably aligned and that len is 1, 2 or 4.
+ */
+ switch (len) {
+ case 1:
+ out_8(addr, val);
+ (void) in_8(addr);
+ break;
+ case 2:
+ out_le16(addr, val);
+ (void) in_le16(addr);
+ break;
+ default:
+ out_le32(addr, val);
+ (void) in_le32(addr);
+ break;
+ }
+ return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops u4_pcie_pci_ops =
+{
+ u4_pcie_read_config,
+ u4_pcie_write_config
+};
+
static void __init setup_u3_agp(struct pci_controller* hose)
{
/* On G5, we move AGP up to high bus number so we don't need
@@ -307,6 +416,26 @@ static void __init setup_u3_agp(struct pci_controller* hose)
u3_agp = hose;
}
+static void __init setup_u4_pcie(struct pci_controller* hose)
+{
+ /* We currently only implement the "non-atomic" config space, to
+ * be optimised later.
+ */
+ hose->ops = &u4_pcie_pci_ops;
+ hose->cfg_addr = ioremap(0xf0000000 + 0x800000, 0x1000);
+ hose->cfg_data = ioremap(0xf0000000 + 0xc00000, 0x1000);
+
+ /* The bus contains a bridge from root -> device, we need to
+ * make it visible on bus 0 so that we pick the right type
+ * of config cycles. If we didn't, we would have to force all
+ * config cycles to be type 1. So we override the "bus-range"
+ * property here
+ */
+ hose->first_busno = 0x00;
+ hose->last_busno = 0xff;
+ u4_pcie = hose;
+}
+
static void __init setup_u3_ht(struct pci_controller* hose)
{
hose->ops = &u3_ht_pci_ops;
@@ -315,7 +444,7 @@ static void __init setup_u3_ht(struct pci_controller* hose)
* the reg address cell, we shall fix that by killing struct
* reg_property and using some accessor functions instead
*/
- hose->cfg_data = (volatile unsigned char *)ioremap(0xf2000000, 0x02000000);
+ hose->cfg_data = ioremap(0xf2000000, 0x02000000);
hose->first_busno = 0;
hose->last_busno = 0xef;
@@ -354,6 +483,10 @@ static int __init add_bridge(struct device_node *dev)
setup_u3_ht(hose);
disp_name = "U3-HT";
primary = 1;
+ } else if (device_is_compatible(dev, "u4-pcie")) {
+ setup_u4_pcie(hose);
+ disp_name = "U4-PCIE";
+ primary = 0;
}
printk(KERN_INFO "Found %s PCI host bridge. Firmware bus number: %d->%d\n",
disp_name, hose->first_busno, hose->last_busno);
@@ -361,7 +494,6 @@ static int __init add_bridge(struct device_node *dev)
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges(hose, dev, primary);
- pci_setup_phb_io(hose, primary);
/* Fixup "bus-range" OF property */
fixup_bus_range(dev);
@@ -376,8 +508,30 @@ void __init maple_pcibios_fixup(void)
DBG(" -> maple_pcibios_fixup\n");
- for_each_pci_dev(dev)
+ for_each_pci_dev(dev) {
+ /* Fixup IRQ for PCIe host */
+ if (u4_pcie != NULL && dev->bus->number == 0 &&
+ pci_bus_to_host(dev->bus) == u4_pcie) {
+ printk(KERN_DEBUG "Fixup U4 PCIe IRQ\n");
+ dev->irq = irq_create_mapping(NULL, 1);
+ if (dev->irq != NO_IRQ)
+ set_irq_type(dev->irq, IRQ_TYPE_LEVEL_LOW);
+ continue;
+ }
+
+ /* Hide AMD8111 IDE interrupt when in legacy mode so
+ * the driver calls pci_get_legacy_ide_irq()
+ */
+ if (dev->vendor == PCI_VENDOR_ID_AMD &&
+ dev->device == PCI_DEVICE_ID_AMD_8111_IDE &&
+ (dev->class & 5) != 5) {
+ dev->irq = NO_IRQ;
+ continue;
+ }
+
+ /* For all others, map the interrupt from the device-tree */
pci_read_irq_line(dev);
+ }
DBG(" <- maple_pcibios_fixup\n");
}
@@ -388,8 +542,10 @@ static void __init maple_fixup_phb_resources(void)
list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
unsigned long offset = (unsigned long)hose->io_base_virt - pci_io_base;
+
hose->io_resource.start += offset;
hose->io_resource.end += offset;
+
printk(KERN_INFO "PCI Host %d, io start: %llx; io end: %llx\n",
hose->global_number,
(unsigned long long)hose->io_resource.start,
@@ -431,6 +587,19 @@ void __init maple_pci_init(void)
if (ht && add_bridge(ht) != 0)
of_node_put(ht);
+ /*
+ * We need to call pci_setup_phb_io for the HT bridge first
+ * so it gets the I/O port numbers starting at 0, and we
+ * need to call it for the AGP bridge after that so it gets
+ * small positive I/O port numbers.
+ */
+ if (u3_ht)
+ pci_setup_phb_io(u3_ht, 1);
+ if (u3_agp)
+ pci_setup_phb_io(u3_agp, 0);
+ if (u4_pcie)
+ pci_setup_phb_io(u4_pcie, 0);
+
/* Fixup the IO resources on our host bridges as the common code
* does it only for childs of the host bridges
*/
@@ -465,8 +634,11 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
return defirq;
np = pci_device_to_OF_node(pdev);
- if (np == NULL)
+ if (np == NULL) {
+ printk("Failed to locate OF node for IDE %s\n",
+ pci_name(pdev));
return defirq;
+ }
irq = irq_of_parse_and_map(np, channel & 0x1);
if (irq == NO_IRQ) {
printk("Failed to map onboard IDE interrupt for channel %d\n",
@@ -479,6 +651,9 @@ int maple_pci_get_legacy_ide_irq(struct pci_dev *pdev, int channel)
/* XXX: To remove once all firmwares are ok */
static void fixup_maple_ide(struct pci_dev* dev)
{
+ if (!machine_is(maple))
+ return;
+
#if 0 /* Enable this to enable IDE port 0 */
{
u8 v;
@@ -495,7 +670,7 @@ static void fixup_maple_ide(struct pci_dev* dev)
dev->resource[4].start = 0xcc00;
dev->resource[4].end = 0xcc10;
#endif
-#if 1 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */
+#if 0 /* Enable this to fixup IDE sense/polarity of irqs in IO-APICs */
{
struct pci_dev *apicdev;
u32 v;
diff --git a/arch/powerpc/platforms/pasemi/pci.c b/arch/powerpc/platforms/pasemi/pci.c
index 4679c5230413..39020c1fa13d 100644
--- a/arch/powerpc/platforms/pasemi/pci.c
+++ b/arch/powerpc/platforms/pasemi/pci.c
@@ -35,17 +35,17 @@
#define CONFIG_OFFSET_VALID(off) ((off) < 4096)
-static unsigned long pa_pxp_cfg_addr(struct pci_controller *hose,
+static void volatile __iomem *pa_pxp_cfg_addr(struct pci_controller *hose,
u8 bus, u8 devfn, int offset)
{
- return ((unsigned long)hose->cfg_data) + PA_PXP_CFA(bus, devfn, offset);
+ return hose->cfg_data + PA_PXP_CFA(bus, devfn, offset);
}
static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct pci_controller *hose;
- unsigned long addr;
+ void volatile __iomem *addr;
hose = pci_bus_to_host(bus);
if (!hose)
@@ -62,13 +62,13 @@ static int pa_pxp_read_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- *val = in_8((u8 *)addr);
+ *val = in_8(addr);
break;
case 2:
- *val = in_le16((u16 *)addr);
+ *val = in_le16(addr);
break;
default:
- *val = in_le32((u32 *)addr);
+ *val = in_le32(addr);
break;
}
@@ -79,7 +79,7 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct pci_controller *hose;
- unsigned long addr;
+ void volatile __iomem *addr;
hose = pci_bus_to_host(bus);
if (!hose)
@@ -96,16 +96,16 @@ static int pa_pxp_write_config(struct pci_bus *bus, unsigned int devfn,
*/
switch (len) {
case 1:
- out_8((u8 *)addr, val);
- (void) in_8((u8 *)addr);
+ out_8(addr, val);
+ (void) in_8(addr);
break;
case 2:
- out_le16((u16 *)addr, val);
- (void) in_le16((u16 *)addr);
+ out_le16(addr, val);
+ (void) in_le16(addr);
break;
default:
- out_le32((u32 *)addr, val);
- (void) in_le32((u32 *)addr);
+ out_le32(addr, val);
+ (void) in_le32(addr);
break;
}
return PCIBIOS_SUCCESSFUL;
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index 628482671c15..106896c3b60a 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -22,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/delay.h>
diff --git a/arch/powerpc/platforms/pasemi/time.c b/arch/powerpc/platforms/pasemi/time.c
index 9bd410b8fec6..fa54351ac268 100644
--- a/arch/powerpc/platforms/pasemi/time.c
+++ b/arch/powerpc/platforms/pasemi/time.c
@@ -17,7 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/time.h>
#include <asm/time.h>
diff --git a/arch/powerpc/platforms/powermac/cpufreq_64.c b/arch/powerpc/platforms/powermac/cpufreq_64.c
index d30466d74194..9d22361a26d6 100644
--- a/arch/powerpc/platforms/powermac/cpufreq_64.c
+++ b/arch/powerpc/platforms/powermac/cpufreq_64.c
@@ -104,7 +104,7 @@ static void g5_smu_switch_volt(int speed_mode)
{
struct smu_simple_cmd cmd;
- DECLARE_COMPLETION(comp);
+ DECLARE_COMPLETION_ONSTACK(comp);
smu_queue_simple(&cmd, SMU_CMD_POWER_COMMAND, 8, smu_done_complete,
&comp, 'V', 'S', 'L', 'E', 'W',
0xff, g5_fvt_cur+1, speed_mode);
diff --git a/arch/powerpc/platforms/powermac/low_i2c.c b/arch/powerpc/platforms/powermac/low_i2c.c
index c2c7cf75dd5f..bfc4829162f1 100644
--- a/arch/powerpc/platforms/powermac/low_i2c.c
+++ b/arch/powerpc/platforms/powermac/low_i2c.c
@@ -342,7 +342,7 @@ static void kw_i2c_handle_interrupt(struct pmac_i2c_host_kw *host, u8 isr)
}
/* Interrupt handler */
-static irqreturn_t kw_i2c_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t kw_i2c_irq(int irq, void *dev_id)
{
struct pmac_i2c_host_kw *host = dev_id;
unsigned long flags;
diff --git a/arch/powerpc/platforms/powermac/nvram.c b/arch/powerpc/platforms/powermac/nvram.c
index 6a36ea9bf673..692945c14919 100644
--- a/arch/powerpc/platforms/powermac/nvram.c
+++ b/arch/powerpc/platforms/powermac/nvram.c
@@ -195,7 +195,7 @@ static void pmu_nvram_complete(struct adb_request *req)
static unsigned char pmu_nvram_read_byte(int addr)
{
struct adb_request req;
- DECLARE_COMPLETION(req_complete);
+ DECLARE_COMPLETION_ONSTACK(req_complete);
req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
if (pmu_request(&req, pmu_nvram_complete, 3, PMU_READ_NVRAM,
@@ -211,7 +211,7 @@ static unsigned char pmu_nvram_read_byte(int addr)
static void pmu_nvram_write_byte(int addr, unsigned char val)
{
struct adb_request req;
- DECLARE_COMPLETION(req_complete);
+ DECLARE_COMPLETION_ONSTACK(req_complete);
req.arg = system_state == SYSTEM_RUNNING ? &req_complete : NULL;
if (pmu_request(&req, pmu_nvram_complete, 4, PMU_WRITE_NVRAM,
diff --git a/arch/powerpc/platforms/powermac/pfunc_base.c b/arch/powerpc/platforms/powermac/pfunc_base.c
index ee3b223ab17a..5c6c15c5f9a3 100644
--- a/arch/powerpc/platforms/powermac/pfunc_base.c
+++ b/arch/powerpc/platforms/powermac/pfunc_base.c
@@ -15,7 +15,7 @@
#define DBG(fmt...)
#endif
-static irqreturn_t macio_gpio_irq(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t macio_gpio_irq(int irq, void *data)
{
pmf_do_irq(data);
diff --git a/arch/powerpc/platforms/powermac/pic.c b/arch/powerpc/platforms/powermac/pic.c
index 39f7ddb554ea..39db12890214 100644
--- a/arch/powerpc/platforms/powermac/pic.c
+++ b/arch/powerpc/platforms/powermac/pic.c
@@ -42,7 +42,7 @@
* has to include <linux/interrupt.h> (to get irqreturn_t), which
* causes all sorts of problems. -- paulus
*/
-extern irqreturn_t xmon_irq(int, void *, struct pt_regs *);
+extern irqreturn_t xmon_irq(int, void *);
#ifdef CONFIG_PPC32
struct pmac_irq_hw {
@@ -210,7 +210,7 @@ static struct irq_chip pmac_pic = {
.retrigger = pmac_retrigger,
};
-static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gatwick_action(int cpl, void *dev_id)
{
unsigned long flags;
int irq, bits;
@@ -227,7 +227,7 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
continue;
irq += __ilog2(bits);
spin_unlock_irqrestore(&pmac_pic_lock, flags);
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
spin_lock_irqsave(&pmac_pic_lock, flags);
rc = IRQ_HANDLED;
}
@@ -235,18 +235,18 @@ static irqreturn_t gatwick_action(int cpl, void *dev_id, struct pt_regs *regs)
return rc;
}
-static unsigned int pmac_pic_get_irq(struct pt_regs *regs)
+static unsigned int pmac_pic_get_irq(void)
{
int irq;
unsigned long bits = 0;
unsigned long flags;
#ifdef CONFIG_SMP
- void psurge_smp_message_recv(struct pt_regs *);
+ void psurge_smp_message_recv(void);
/* IPI's are a hack on the powersurge -- Cort */
if ( smp_processor_id() != 0 ) {
- psurge_smp_message_recv(regs);
+ psurge_smp_message_recv();
return NO_IRQ_IGNORE; /* ignore, already handled */
}
#endif /* CONFIG_SMP */
@@ -440,14 +440,13 @@ static void __init pmac_pic_probe_oldstyle(void)
}
#endif /* CONFIG_PPC32 */
-static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)
{
struct mpic *mpic = desc->handler_data;
- unsigned int cascade_irq = mpic_get_one_irq(mpic, regs);
+ unsigned int cascade_irq = mpic_get_one_irq(mpic);
if (cascade_irq != NO_IRQ)
- generic_handle_irq(cascade_irq, regs);
+ generic_handle_irq(cascade_irq);
desc->chip->eoi(irq);
}
diff --git a/arch/powerpc/platforms/powermac/pic.h b/arch/powerpc/platforms/powermac/pic.h
index 664103dfeef9..c44c89f5e532 100644
--- a/arch/powerpc/platforms/powermac/pic.h
+++ b/arch/powerpc/platforms/powermac/pic.h
@@ -5,7 +5,7 @@
extern struct hw_interrupt_type pmac_pic;
-void pmac_pic_init(void);
-int pmac_get_irq(struct pt_regs *regs);
+extern void pmac_pic_init(void);
+extern int pmac_get_irq(void);
#endif /* __PPC_PLATFORMS_PMAC_PIC_H */
diff --git a/arch/powerpc/platforms/powermac/smp.c b/arch/powerpc/platforms/powermac/smp.c
index 1949b657b092..eeb2ae5ffc58 100644
--- a/arch/powerpc/platforms/powermac/smp.c
+++ b/arch/powerpc/platforms/powermac/smp.c
@@ -160,7 +160,7 @@ static inline void psurge_clr_ipi(int cpu)
*/
static unsigned long psurge_smp_message[NR_CPUS];
-void psurge_smp_message_recv(struct pt_regs *regs)
+void psurge_smp_message_recv(void)
{
int cpu = smp_processor_id();
int msg;
@@ -174,12 +174,12 @@ void psurge_smp_message_recv(struct pt_regs *regs)
/* make sure there is a message there */
for (msg = 0; msg < 4; msg++)
if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
- smp_message_recv(msg, regs);
+ smp_message_recv(msg);
}
-irqreturn_t psurge_primary_intr(int irq, void *d, struct pt_regs *regs)
+irqreturn_t psurge_primary_intr(int irq, void *d)
{
- psurge_smp_message_recv(regs);
+ psurge_smp_message_recv();
return IRQ_HANDLED;
}
@@ -328,6 +328,7 @@ static void __init smp_psurge_kick_cpu(int nr)
{
unsigned long start = __pa(__secondary_start_pmac_0) + nr * 8;
unsigned long a;
+ int i;
/* may need to flush here if secondary bats aren't setup */
for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
@@ -340,7 +341,11 @@ static void __init smp_psurge_kick_cpu(int nr)
mb();
psurge_set_ipi(nr);
- udelay(10);
+ /*
+ * We can't use udelay here because the timebase is now frozen.
+ */
+ for (i = 0; i < 2000; ++i)
+ barrier();
psurge_clr_ipi(nr);
if (ppc_md.progress) ppc_md.progress("smp_psurge_kick_cpu - done", 0x354);
diff --git a/arch/powerpc/platforms/powermac/udbg_scc.c b/arch/powerpc/platforms/powermac/udbg_scc.c
index ce1a235855f7..379db05b0082 100644
--- a/arch/powerpc/platforms/powermac/udbg_scc.c
+++ b/arch/powerpc/platforms/powermac/udbg_scc.c
@@ -111,8 +111,6 @@ void udbg_scc_init(int force_scc)
pmac_call_feature(PMAC_FTR_SCC_ENABLE, ch,
PMAC_SCC_ASYNC | PMAC_SCC_FLAG_XMON, 1);
-
- /* Setup for 57600 8N1 */
if (ch == ch_a)
addr += 0x20;
sccc = ioremap(addr & PAGE_MASK, PAGE_SIZE) ;
@@ -125,9 +123,21 @@ void udbg_scc_init(int force_scc)
x = in_8(sccc);
out_8(sccc, 0x09); /* reset A or B side */
out_8(sccc, 0xc0);
+
+ /* If SCC was the OF output port, read the BRG value, else
+ * Setup for 57600 8N1
+ */
+ if (ch_def != NULL) {
+ out_8(sccc, 13);
+ scc_inittab[1] = in_8(sccc);
+ out_8(sccc, 12);
+ scc_inittab[3] = in_8(sccc);
+ }
+
for (i = 0; i < sizeof(scc_inittab); ++i)
out_8(sccc, scc_inittab[i]);
+
udbg_putc = udbg_scc_putc;
udbg_getc = udbg_scc_getc;
udbg_getc_poll = udbg_scc_getc_poll;
diff --git a/arch/powerpc/platforms/pseries/eeh.c b/arch/powerpc/platforms/pseries/eeh.c
index 84bc8f7e17ef..3c2d63ebf787 100644
--- a/arch/powerpc/platforms/pseries/eeh.c
+++ b/arch/powerpc/platforms/pseries/eeh.c
@@ -225,6 +225,7 @@ static void __eeh_mark_slot (struct device_node *dn, int mode_flag)
void eeh_mark_slot (struct device_node *dn, int mode_flag)
{
+ struct pci_dev *dev;
dn = find_device_pe (dn);
/* Back up one, since config addrs might be shared */
@@ -232,6 +233,12 @@ void eeh_mark_slot (struct device_node *dn, int mode_flag)
dn = dn->parent;
PCI_DN(dn)->eeh_mode |= mode_flag;
+
+ /* Mark the pci device too */
+ dev = PCI_DN(dn)->pcidev;
+ if (dev)
+ dev->error_state = pci_channel_io_frozen;
+
__eeh_mark_slot (dn->child, mode_flag);
}
diff --git a/arch/powerpc/platforms/pseries/hvCall_inst.c b/arch/powerpc/platforms/pseries/hvCall_inst.c
index 641e6511cf06..446e17d162a5 100644
--- a/arch/powerpc/platforms/pseries/hvCall_inst.c
+++ b/arch/powerpc/platforms/pseries/hvCall_inst.c
@@ -85,7 +85,7 @@ static int hcall_inst_seq_open(struct inode *inode, struct file *file)
rc = seq_open(file, &hcall_inst_seq_ops);
seq = file->private_data;
- seq->private = file->f_dentry->d_inode->u.generic_ip;
+ seq->private = file->f_dentry->d_inode->i_private;
return rc;
}
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index bbf2e34dc358..d24ba547e53f 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -267,7 +267,8 @@ static void iommu_table_setparms(struct pci_controller *phb,
struct iommu_table *tbl)
{
struct device_node *node;
- const unsigned long *basep, *sizep;
+ const unsigned long *basep;
+ const u32 *sizep;
node = (struct device_node *)phb->arch_data;
diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c
index 903115d67fdc..b1d3d161249e 100644
--- a/arch/powerpc/platforms/pseries/ras.c
+++ b/arch/powerpc/platforms/pseries/ras.c
@@ -65,16 +65,14 @@ static int ras_check_exception_token;
#define EPOW_SENSOR_INDEX 0
#define RAS_VECTOR_OFFSET 0x500
-static irqreturn_t ras_epow_interrupt(int irq, void *dev_id,
- struct pt_regs * regs);
-static irqreturn_t ras_error_interrupt(int irq, void *dev_id,
- struct pt_regs * regs);
+static irqreturn_t ras_epow_interrupt(int irq, void *dev_id);
+static irqreturn_t ras_error_interrupt(int irq, void *dev_id);
/* #define DEBUG */
static void request_ras_irqs(struct device_node *np,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ irq_handler_t handler,
const char *name)
{
int i, index, count = 0;
@@ -166,8 +164,7 @@ __initcall(init_ras_IRQ);
* to examine the type of power failure and take appropriate action where
* the time horizon permits something useful to be done.
*/
-static irqreturn_t
-ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ras_epow_interrupt(int irq, void *dev_id)
{
int status = 0xdeadbeef;
int state = 0;
@@ -210,8 +207,7 @@ ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
* For nonrecoverable errors, an error is logged and we stop all processing
* as quickly as possible in order to prevent propagation of the failure.
*/
-static irqreturn_t
-ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
{
struct rtas_error_log *rtas_elog;
int status = 0xdeadbeef;
@@ -337,7 +333,7 @@ static int recover_mce(struct pt_regs *regs, struct rtas_error_log * err)
err->disposition == RTAS_DISP_NOT_RECOVERED &&
err->target == RTAS_TARGET_MEMORY &&
err->type == RTAS_TYPE_ECC_UNCORR &&
- !(current->pid == 0 || current->pid == 1)) {
+ !(current->pid == 0 || is_init(current))) {
/* Kill off a user process with an ECC error */
printk(KERN_ERR "MCE: uncorrectable ecc error for pid %d\n",
current->pid);
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index a6398fbe530d..89a8119f988d 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -121,12 +121,11 @@ static void __init fwnmi_init(void)
fwnmi_active = 1;
}
-void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
- unsigned int cascade_irq = i8259_irq(regs);
+ unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ)
- generic_handle_irq(cascade_irq, regs);
+ generic_handle_irq(cascade_irq);
desc->chip->eoi(irq);
}
@@ -180,7 +179,7 @@ static void __init pseries_mpic_init_IRQ(void)
cascade_irq = irq_of_parse_and_map(cascade, 0);
if (cascade == NO_IRQ) {
- printk(KERN_ERR "xics: failed to map cascade interrupt");
+ printk(KERN_ERR "mpic: failed to map cascade interrupt");
return;
}
@@ -342,7 +341,7 @@ static int __init pSeries_init_panel(void)
{
/* Manually leave the kernel version on the panel. */
ppc_md.progress("Linux ppc64\n", 0);
- ppc_md.progress(system_utsname.release, 0);
+ ppc_md.progress(init_utsname()->version, 0);
return 0;
}
@@ -477,7 +476,6 @@ static void pseries_dedicated_idle_sleep(void)
{
unsigned int cpu = smp_processor_id();
unsigned long start_snooze;
- unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
/*
* Indicate to the HV that we are idle. Now would be
@@ -490,9 +488,9 @@ static void pseries_dedicated_idle_sleep(void)
* has been checked recently. If we should poll for a little
* while, do so.
*/
- if (*smt_snooze_delay) {
+ if (__get_cpu_var(smt_snooze_delay)) {
start_snooze = get_tb() +
- *smt_snooze_delay * tb_ticks_per_usec;
+ __get_cpu_var(smt_snooze_delay) * tb_ticks_per_usec;
local_irq_enable();
set_thread_flag(TIF_POLLING_NRFLAG);
@@ -512,24 +510,7 @@ static void pseries_dedicated_idle_sleep(void)
goto out;
}
- /*
- * If not SMT, cede processor. If CPU is running SMT
- * cede if the other thread is not idle, so that it can
- * go single-threaded. If the other thread is idle,
- * we ask the hypervisor if it has pending work it
- * wants to do and cede if it does. Otherwise we keep
- * polling in order to reduce interrupt latency.
- *
- * Doing the cede when the other thread is active will
- * result in this thread going dormant, meaning the other
- * thread gets to run in single-threaded (ST) mode, which
- * is slightly faster than SMT mode with this thread at
- * very low priority. The cede enables interrupts, which
- * doesn't matter here.
- */
- if (!cpu_has_feature(CPU_FTR_SMT) || !lppaca[cpu ^ 1].idle
- || poll_pending() == H_PENDING)
- cede_processor();
+ cede_processor();
out:
HMT_medium();
diff --git a/arch/powerpc/platforms/pseries/xics.c b/arch/powerpc/platforms/pseries/xics.c
index 253972e5479f..d071abe78ab1 100644
--- a/arch/powerpc/platforms/pseries/xics.c
+++ b/arch/powerpc/platforms/pseries/xics.c
@@ -308,14 +308,14 @@ static inline unsigned int xics_remap_irq(unsigned int vec)
return NO_IRQ;
}
-static unsigned int xics_get_irq_direct(struct pt_regs *regs)
+static unsigned int xics_get_irq_direct(void)
{
unsigned int cpu = smp_processor_id();
return xics_remap_irq(direct_xirr_info_get(cpu));
}
-static unsigned int xics_get_irq_lpar(struct pt_regs *regs)
+static unsigned int xics_get_irq_lpar(void)
{
unsigned int cpu = smp_processor_id();
@@ -324,7 +324,7 @@ static unsigned int xics_get_irq_lpar(struct pt_regs *regs)
#ifdef CONFIG_SMP
-static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs)
+static irqreturn_t xics_ipi_dispatch(int cpu)
{
WARN_ON(cpu_is_offline(cpu));
@@ -332,47 +332,47 @@ static irqreturn_t xics_ipi_dispatch(int cpu, struct pt_regs *regs)
if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
&xics_ipi_message[cpu].value)) {
mb();
- smp_message_recv(PPC_MSG_CALL_FUNCTION, regs);
+ smp_message_recv(PPC_MSG_CALL_FUNCTION);
}
if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
&xics_ipi_message[cpu].value)) {
mb();
- smp_message_recv(PPC_MSG_RESCHEDULE, regs);
+ smp_message_recv(PPC_MSG_RESCHEDULE);
}
#if 0
if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK,
&xics_ipi_message[cpu].value)) {
mb();
- smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
+ smp_message_recv(PPC_MSG_MIGRATE_TASK);
}
#endif
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK,
&xics_ipi_message[cpu].value)) {
mb();
- smp_message_recv(PPC_MSG_DEBUGGER_BREAK, regs);
+ smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
}
#endif
}
return IRQ_HANDLED;
}
-static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t xics_ipi_action_direct(int irq, void *dev_id)
{
int cpu = smp_processor_id();
direct_qirr_info(cpu, 0xff);
- return xics_ipi_dispatch(cpu, regs);
+ return xics_ipi_dispatch(cpu);
}
-static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t xics_ipi_action_lpar(int irq, void *dev_id)
{
int cpu = smp_processor_id();
lpar_qirr_info(cpu, 0xff);
- return xics_ipi_dispatch(cpu, regs);
+ return xics_ipi_dispatch(cpu);
}
void xics_cause_IPI(int cpu)
diff --git a/arch/powerpc/platforms/pseries/xics.h b/arch/powerpc/platforms/pseries/xics.h
index 6ee1055b0ffb..db0ec3ba3ae2 100644
--- a/arch/powerpc/platforms/pseries/xics.h
+++ b/arch/powerpc/platforms/pseries/xics.h
@@ -31,7 +31,6 @@ struct xics_ipi_struct {
extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
struct irq_desc;
-extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
+extern void pseries_8259_cascade(unsigned int irq, struct irq_desc *desc);
#endif /* _POWERPC_KERNEL_XICS_H */
diff --git a/arch/powerpc/sysdev/Makefile b/arch/powerpc/sysdev/Makefile
index e5e999ea891a..91f052d8cce0 100644
--- a/arch/powerpc/sysdev/Makefile
+++ b/arch/powerpc/sysdev/Makefile
@@ -12,8 +12,14 @@ obj-$(CONFIG_MMIO_NVRAM) += mmio_nvram.o
obj-$(CONFIG_FSL_SOC) += fsl_soc.o
obj-$(CONFIG_PPC_TODC) += todc.o
obj-$(CONFIG_TSI108_BRIDGE) += tsi108_pci.o tsi108_dev.o
+obj-$(CONFIG_QUICC_ENGINE) += qe_lib/
ifeq ($(CONFIG_PPC_MERGE),y)
obj-$(CONFIG_PPC_I8259) += i8259.o
obj-$(CONFIG_PPC_83xx) += ipic.o
endif
+
+# Temporary hack until we have migrated to asm-powerpc
+ifeq ($(ARCH),powerpc)
+obj-$(CONFIG_CPM2) += cpm2_common.o cpm2_pic.o
+endif
diff --git a/arch/powerpc/sysdev/cpm2_common.c b/arch/powerpc/sysdev/cpm2_common.c
new file mode 100644
index 000000000000..ec265995d5d8
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_common.c
@@ -0,0 +1,309 @@
+/*
+ * General Purpose functions for the global management of the
+ * 8260 Communication Processor Module.
+ * Copyright (c) 1999-2001 Dan Malek <dan@embeddedalley.com>
+ * Copyright (c) 2000 MontaVista Software, Inc (source@mvista.com)
+ * 2.3.99 Updates
+ *
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ * Merged to arch/powerpc from arch/ppc/syslib/cpm2_common.c
+ *
+ * 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.
+ */
+
+/*
+ *
+ * In addition to the individual control of the communication
+ * channels, there are a few functions that globally affect the
+ * communication processor.
+ *
+ * Buffer descriptors must be allocated from the dual ported memory
+ * space. The allocator for that is here. When the communication
+ * process is reset, we reclaim the memory available. There is
+ * currently no deallocator for this memory.
+ */
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mpc8260.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/cpm2.h>
+#include <asm/rheap.h>
+#include <asm/fs_pd.h>
+
+#include <sysdev/fsl_soc.h>
+
+static void cpm2_dpinit(void);
+cpm_cpm2_t *cpmp; /* Pointer to comm processor space */
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+cpm2_map_t *cpm2_immr;
+intctl_cpm2_t *cpm2_intctl;
+
+#define CPM_MAP_SIZE (0x40000) /* 256k - the PQ3 reserve this amount
+ of space for CPM as it is larger
+ than on PQ2 */
+
+void
+cpm2_reset(void)
+{
+ cpm2_immr = (cpm2_map_t *)ioremap(CPM_MAP_ADDR, CPM_MAP_SIZE);
+ cpm2_intctl = cpm2_map(im_intctl);
+
+ /* Reclaim the DP memory for our use.
+ */
+ cpm2_dpinit();
+
+ /* Tell everyone where the comm processor resides.
+ */
+ cpmp = &cpm2_immr->im_cpm;
+}
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * eight BRGs, which can be connected to the CPM channels or output
+ * as clocks. The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers). Documentation uses 1-based numbering.
+ */
+#define BRG_INT_CLK (get_brgfreq())
+#define BRG_UART_CLK (BRG_INT_CLK/16)
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void
+cpm_setbrg(uint brg, uint rate)
+{
+ volatile uint *bp;
+
+ /* This is good enough to get SMCs running.....
+ */
+ if (brg < 4) {
+ bp = cpm2_map_size(im_brgc1, 16);
+ } else {
+ bp = cpm2_map_size(im_brgc5, 16);
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = ((BRG_UART_CLK / rate) << 1) | CPM_BRG_EN;
+
+ cpm2_unmap(bp);
+}
+
+/* This function is used to set high speed synchronous baud rate
+ * clocks.
+ */
+void
+cpm2_fastbrg(uint brg, uint rate, int div16)
+{
+ volatile uint *bp;
+
+ if (brg < 4) {
+ bp = cpm2_map_size(im_brgc1, 16);
+ }
+ else {
+ bp = cpm2_map_size(im_brgc5, 16);
+ brg -= 4;
+ }
+ bp += brg;
+ *bp = ((BRG_INT_CLK / rate) << 1) | CPM_BRG_EN;
+ if (div16)
+ *bp |= CPM_BRG_DIV16;
+
+ cpm2_unmap(bp);
+}
+
+int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode)
+{
+ int ret = 0;
+ int shift;
+ int i, bits = 0;
+ cpmux_t *im_cpmux;
+ u32 *reg;
+ u32 mask = 7;
+ u8 clk_map [24][3] = {
+ {CPM_CLK_FCC1, CPM_BRG5, 0},
+ {CPM_CLK_FCC1, CPM_BRG6, 1},
+ {CPM_CLK_FCC1, CPM_BRG7, 2},
+ {CPM_CLK_FCC1, CPM_BRG8, 3},
+ {CPM_CLK_FCC1, CPM_CLK9, 4},
+ {CPM_CLK_FCC1, CPM_CLK10, 5},
+ {CPM_CLK_FCC1, CPM_CLK11, 6},
+ {CPM_CLK_FCC1, CPM_CLK12, 7},
+ {CPM_CLK_FCC2, CPM_BRG5, 0},
+ {CPM_CLK_FCC2, CPM_BRG6, 1},
+ {CPM_CLK_FCC2, CPM_BRG7, 2},
+ {CPM_CLK_FCC2, CPM_BRG8, 3},
+ {CPM_CLK_FCC2, CPM_CLK13, 4},
+ {CPM_CLK_FCC2, CPM_CLK14, 5},
+ {CPM_CLK_FCC2, CPM_CLK15, 6},
+ {CPM_CLK_FCC2, CPM_CLK16, 7},
+ {CPM_CLK_FCC3, CPM_BRG5, 0},
+ {CPM_CLK_FCC3, CPM_BRG6, 1},
+ {CPM_CLK_FCC3, CPM_BRG7, 2},
+ {CPM_CLK_FCC3, CPM_BRG8, 3},
+ {CPM_CLK_FCC3, CPM_CLK13, 4},
+ {CPM_CLK_FCC3, CPM_CLK14, 5},
+ {CPM_CLK_FCC3, CPM_CLK15, 6},
+ {CPM_CLK_FCC3, CPM_CLK16, 7}
+ };
+
+ im_cpmux = cpm2_map(im_cpmux);
+
+ switch (target) {
+ case CPM_CLK_SCC1:
+ reg = &im_cpmux->cmx_scr;
+ shift = 24;
+ case CPM_CLK_SCC2:
+ reg = &im_cpmux->cmx_scr;
+ shift = 16;
+ break;
+ case CPM_CLK_SCC3:
+ reg = &im_cpmux->cmx_scr;
+ shift = 8;
+ break;
+ case CPM_CLK_SCC4:
+ reg = &im_cpmux->cmx_scr;
+ shift = 0;
+ break;
+ case CPM_CLK_FCC1:
+ reg = &im_cpmux->cmx_fcr;
+ shift = 24;
+ break;
+ case CPM_CLK_FCC2:
+ reg = &im_cpmux->cmx_fcr;
+ shift = 16;
+ break;
+ case CPM_CLK_FCC3:
+ reg = &im_cpmux->cmx_fcr;
+ shift = 8;
+ break;
+ default:
+ printk(KERN_ERR "cpm2_clock_setup: invalid clock target\n");
+ return -EINVAL;
+ }
+
+ if (mode == CPM_CLK_RX)
+ shift +=3;
+
+ for (i=0; i<24; i++) {
+ if (clk_map[i][0] == target && clk_map[i][1] == clock) {
+ bits = clk_map[i][2];
+ break;
+ }
+ }
+ if (i == sizeof(clk_map)/3)
+ ret = -EINVAL;
+
+ bits <<= shift;
+ mask <<= shift;
+ out_be32(reg, (in_be32(reg) & ~mask) | bits);
+
+ cpm2_unmap(im_cpmux);
+ return ret;
+}
+
+/*
+ * dpalloc / dpfree bits.
+ */
+static spinlock_t cpm_dpmem_lock;
+/* 16 blocks should be enough to satisfy all requests
+ * until the memory subsystem goes up... */
+static rh_block_t cpm_boot_dpmem_rh_block[16];
+static rh_info_t cpm_dpmem_info;
+static u8* im_dprambase;
+
+static void cpm2_dpinit(void)
+{
+ spin_lock_init(&cpm_dpmem_lock);
+
+ im_dprambase = ioremap(CPM_MAP_ADDR, CPM_DATAONLY_BASE + CPM_DATAONLY_SIZE);
+
+ /* initialize the info header */
+ rh_init(&cpm_dpmem_info, 1,
+ sizeof(cpm_boot_dpmem_rh_block) /
+ sizeof(cpm_boot_dpmem_rh_block[0]),
+ cpm_boot_dpmem_rh_block);
+
+ /* Attach the usable dpmem area */
+ /* XXX: This is actually crap. CPM_DATAONLY_BASE and
+ * CPM_DATAONLY_SIZE is only a subset of the available dpram. It
+ * 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);
+}
+
+/* This function returns an index into the DPRAM area.
+ */
+uint cpm_dpalloc(uint size, uint align)
+{
+ void *start;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cpm_dpmem_lock, flags);
+ cpm_dpmem_info.alignment = align;
+ start = rh_alloc(&cpm_dpmem_info, size, "commproc");
+ spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+ return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc);
+
+int cpm_dpfree(uint offset)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cpm_dpmem_lock, flags);
+ ret = rh_free(&cpm_dpmem_info, (void *)offset);
+ spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(cpm_dpfree);
+
+/* not sure if this is ever needed */
+uint cpm_dpalloc_fixed(uint offset, uint size, uint align)
+{
+ void *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");
+ spin_unlock_irqrestore(&cpm_dpmem_lock, flags);
+
+ return (uint)start;
+}
+EXPORT_SYMBOL(cpm_dpalloc_fixed);
+
+void cpm_dpdump(void)
+{
+ rh_dump(&cpm_dpmem_info);
+}
+EXPORT_SYMBOL(cpm_dpdump);
+
+void *cpm_dpram_addr(uint offset)
+{
+ return (void *)(im_dprambase + offset);
+}
+EXPORT_SYMBOL(cpm_dpram_addr);
diff --git a/arch/powerpc/sysdev/cpm2_pic.c b/arch/powerpc/sysdev/cpm2_pic.c
new file mode 100644
index 000000000000..767ee6651adc
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_pic.c
@@ -0,0 +1,256 @@
+/*
+ * Platform information definitions.
+ *
+ * Copied from arch/ppc/syslib/cpm2_pic.c with minor subsequent updates
+ * to make in work in arch/powerpc/. Original (c) belongs to Dan Malek.
+ *
+ * Author: Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * 1999-2001 (c) Dan Malek <dan@embeddedalley.com>
+ * 2006 (c) MontaVista Software, Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/* The CPM2 internal interrupt controller. It is usually
+ * the only interrupt controller.
+ * There are two 32-bit registers (high/low) for up to 64
+ * possible interrupts.
+ *
+ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
+ * in a simple arithmetic fashion to mask or pending registers.
+ * That is, interrupt 4 does not map to bit position 4.
+ * We create two tables, indexed by vector number, to indicate
+ * which register to use and which bit in the register to use.
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+
+#include <asm/immap_cpm2.h>
+#include <asm/mpc8260.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+
+#include "cpm2_pic.h"
+
+static struct device_node *cpm2_pic_node;
+static struct irq_host *cpm2_pic_host;
+#define NR_MASK_WORDS ((NR_IRQS + 31) / 32)
+static unsigned long ppc_cached_irq_mask[NR_MASK_WORDS];
+
+static const u_char irq_to_siureg[] = {
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* bit numbers do not match the docs, these are precomputed so the bit for
+ * a given irq is (1 << irq_to_siubit[irq]) */
+static const u_char irq_to_siubit[] = {
+ 0, 15, 14, 13, 12, 11, 10, 9,
+ 8, 7, 6, 5, 4, 3, 2, 1,
+ 2, 1, 0, 14, 13, 12, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 0,
+ 31, 30, 29, 28, 27, 26, 25, 24,
+ 23, 22, 21, 20, 19, 18, 17, 16,
+ 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31,
+};
+
+static void cpm2_mask_irq(unsigned int irq_nr)
+{
+ int bit, word;
+ volatile uint *simr;
+
+ irq_nr -= CPM_IRQ_OFFSET;
+
+ bit = irq_to_siubit[irq_nr];
+ word = irq_to_siureg[irq_nr];
+
+ simr = &(cpm2_intctl->ic_simrh);
+ ppc_cached_irq_mask[word] &= ~(1 << bit);
+ simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void cpm2_unmask_irq(unsigned int irq_nr)
+{
+ int bit, word;
+ volatile uint *simr;
+
+ irq_nr -= CPM_IRQ_OFFSET;
+
+ bit = irq_to_siubit[irq_nr];
+ word = irq_to_siureg[irq_nr];
+
+ simr = &(cpm2_intctl->ic_simrh);
+ ppc_cached_irq_mask[word] |= 1 << bit;
+ simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void cpm2_mask_and_ack(unsigned int irq_nr)
+{
+ int bit, word;
+ volatile uint *simr, *sipnr;
+
+ irq_nr -= CPM_IRQ_OFFSET;
+
+ bit = irq_to_siubit[irq_nr];
+ word = irq_to_siureg[irq_nr];
+
+ simr = &(cpm2_intctl->ic_simrh);
+ sipnr = &(cpm2_intctl->ic_sipnrh);
+ ppc_cached_irq_mask[word] &= ~(1 << bit);
+ simr[word] = ppc_cached_irq_mask[word];
+ sipnr[word] = 1 << bit;
+}
+
+static void cpm2_end_irq(unsigned int irq_nr)
+{
+ int bit, word;
+ volatile uint *simr;
+
+ if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+ && irq_desc[irq_nr].action) {
+
+ irq_nr -= CPM_IRQ_OFFSET;
+ bit = irq_to_siubit[irq_nr];
+ word = irq_to_siureg[irq_nr];
+
+ simr = &(cpm2_intctl->ic_simrh);
+ ppc_cached_irq_mask[word] |= 1 << bit;
+ simr[word] = ppc_cached_irq_mask[word];
+ /*
+ * Work around large numbers of spurious IRQs on PowerPC 82xx
+ * systems.
+ */
+ mb();
+ }
+}
+
+static struct irq_chip cpm2_pic = {
+ .typename = " CPM2 SIU ",
+ .enable = cpm2_unmask_irq,
+ .disable = cpm2_mask_irq,
+ .unmask = cpm2_unmask_irq,
+ .mask_ack = cpm2_mask_and_ack,
+ .end = cpm2_end_irq,
+};
+
+unsigned int cpm2_get_irq(void)
+{
+ int irq;
+ unsigned long bits;
+
+ /* For CPM2, read the SIVEC register and shift the bits down
+ * to get the irq number. */
+ bits = cpm2_intctl->ic_sivec;
+ irq = bits >> 26;
+
+ if (irq == 0)
+ return(-1);
+ return irq+CPM_IRQ_OFFSET;
+}
+
+static int cpm2_pic_host_match(struct irq_host *h, struct device_node *node)
+{
+ return cpm2_pic_node == NULL || cpm2_pic_node == node;
+}
+
+static int cpm2_pic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ pr_debug("cpm2_pic_host_map(%d, 0x%lx)\n", virq, hw);
+
+ get_irq_desc(virq)->status |= IRQ_LEVEL;
+ set_irq_chip_and_handler(virq, &cpm2_pic, handle_level_irq);
+ return 0;
+}
+
+static void cpm2_host_unmap(struct irq_host *h, unsigned int virq)
+{
+ /* Make sure irq is masked in hardware */
+ cpm2_mask_irq(virq);
+
+ /* remove chip and handler */
+ set_irq_chip_and_handler(virq, NULL, NULL);
+}
+
+static int cpm2_pic_host_xlate(struct irq_host *h, struct device_node *ct,
+ u32 *intspec, unsigned int intsize,
+ irq_hw_number_t *out_hwirq, unsigned int *out_flags)
+{
+ static const unsigned char map_cpm2_senses[4] = {
+ IRQ_TYPE_LEVEL_LOW,
+ IRQ_TYPE_LEVEL_HIGH,
+ IRQ_TYPE_EDGE_FALLING,
+ IRQ_TYPE_EDGE_RISING,
+ };
+
+ *out_hwirq = intspec[0];
+ if (intsize > 1 && intspec[1] < 4)
+ *out_flags = map_cpm2_senses[intspec[1]];
+ else
+ *out_flags = IRQ_TYPE_NONE;
+
+ return 0;
+}
+
+static struct irq_host_ops cpm2_pic_host_ops = {
+ .match = cpm2_pic_host_match,
+ .map = cpm2_pic_host_map,
+ .unmap = cpm2_host_unmap,
+ .xlate = cpm2_pic_host_xlate,
+};
+
+void cpm2_pic_init(struct device_node *node)
+{
+ int i;
+
+ /* Clear the CPM IRQ controller, in case it has any bits set
+ * from the bootloader
+ */
+
+ /* Mask out everything */
+
+ cpm2_intctl->ic_simrh = 0x00000000;
+ cpm2_intctl->ic_simrl = 0x00000000;
+
+ wmb();
+
+ /* Ack everything */
+ cpm2_intctl->ic_sipnrh = 0xffffffff;
+ cpm2_intctl->ic_sipnrl = 0xffffffff;
+ wmb();
+
+ /* Dummy read of the vector */
+ i = cpm2_intctl->ic_sivec;
+ rmb();
+
+ /* Initialize the default interrupt mapping priorities,
+ * in case the boot rom changed something on us.
+ */
+ cpm2_intctl->ic_sicr = 0;
+ cpm2_intctl->ic_scprrh = 0x05309770;
+ cpm2_intctl->ic_scprrl = 0x05309770;
+
+ /* create a legacy host */
+ if (node)
+ cpm2_pic_node = of_node_get(node);
+
+ cpm2_pic_host = irq_alloc_host(IRQ_HOST_MAP_LINEAR, 64, &cpm2_pic_host_ops, 64);
+ if (cpm2_pic_host == NULL) {
+ printk(KERN_ERR "CPM2 PIC: failed to allocate irq host!\n");
+ return;
+ }
+}
diff --git a/arch/powerpc/sysdev/cpm2_pic.h b/arch/powerpc/sysdev/cpm2_pic.h
new file mode 100644
index 000000000000..2840616529e4
--- /dev/null
+++ b/arch/powerpc/sysdev/cpm2_pic.h
@@ -0,0 +1,10 @@
+#ifndef _PPC_KERNEL_CPM2_H
+#define _PPC_KERNEL_CPM2_H
+
+extern intctl_cpm2_t *cpm2_intctl;
+
+extern unsigned int cpm2_get_irq(void);
+
+extern void cpm2_pic_init(struct device_node*);
+
+#endif /* _PPC_KERNEL_CPM2_H */
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 92ba378b7990..dbe92ae20333 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -3,6 +3,9 @@
*
* Maintained by Kumar Gala (see MAINTAINERS for contact information)
*
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.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
@@ -20,15 +23,21 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
+#include <linux/fs_enet_pd.h>
+#include <linux/fs_uart_pd.h>
#include <asm/system.h>
#include <asm/atomic.h>
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/time.h>
#include <asm/prom.h>
#include <sysdev/fsl_soc.h>
#include <mm/mmu_decl.h>
+#include <asm/cpm2.h>
+extern void init_fcc_ioports(struct fs_platform_info*);
+extern void init_scc_ioports(struct fs_uart_platform_info*);
static phys_addr_t immrbase = -1;
phys_addr_t get_immrbase(void)
@@ -42,7 +51,9 @@ phys_addr_t get_immrbase(void)
if (soc) {
unsigned int size;
const void *prop = get_property(soc, "reg", &size);
- immrbase = of_translate_address(soc, prop);
+
+ if (prop)
+ immrbase = of_translate_address(soc, prop);
of_node_put(soc);
};
@@ -51,6 +62,59 @@ phys_addr_t get_immrbase(void)
EXPORT_SYMBOL(get_immrbase);
+#ifdef CONFIG_CPM2
+
+static u32 brgfreq = -1;
+
+u32 get_brgfreq(void)
+{
+ struct device_node *node;
+
+ if (brgfreq != -1)
+ return brgfreq;
+
+ node = of_find_node_by_type(NULL, "cpm");
+ if (node) {
+ unsigned int size;
+ const unsigned int *prop = get_property(node, "brg-frequency",
+ &size);
+
+ if (prop)
+ brgfreq = *prop;
+ of_node_put(node);
+ };
+
+ return brgfreq;
+}
+
+EXPORT_SYMBOL(get_brgfreq);
+
+static u32 fs_baudrate = -1;
+
+u32 get_baudrate(void)
+{
+ struct device_node *node;
+
+ if (fs_baudrate != -1)
+ return fs_baudrate;
+
+ node = of_find_node_by_type(NULL, "serial");
+ if (node) {
+ unsigned int size;
+ const unsigned int *prop = get_property(node, "current-speed",
+ &size);
+
+ if (prop)
+ fs_baudrate = *prop;
+ of_node_put(node);
+ };
+
+ return fs_baudrate;
+}
+
+EXPORT_SYMBOL(get_baudrate);
+#endif /* CONFIG_CPM2 */
+
static int __init gfar_mdio_of_init(void)
{
struct device_node *np;
@@ -85,8 +149,11 @@ static int __init gfar_mdio_of_init(void)
mdio_data.irq[k] = -1;
while ((child = of_get_next_child(np, child)) != NULL) {
- const u32 *id = get_property(child, "reg", NULL);
- mdio_data.irq[*id] = irq_of_parse_and_map(child, 0);
+ int irq = irq_of_parse_and_map(child, 0);
+ if (irq != NO_IRQ) {
+ const u32 *id = get_property(child, "reg", NULL);
+ mdio_data.irq[*id] = irq;
+ }
}
ret =
@@ -128,7 +195,7 @@ static int __init gfar_of_init(void)
const char *model;
const void *mac_addr;
const phandle *ph;
- int n_res = 1;
+ int n_res = 2;
memset(r, 0, sizeof(r));
memset(&gfar_data, 0, sizeof(gfar_data));
@@ -159,7 +226,7 @@ static int __init gfar_of_init(void)
gfar_dev =
platform_device_register_simple("fsl-gianfar", i, &r[0],
- n_res + 1);
+ n_res);
if (IS_ERR(gfar_dev)) {
ret = PTR_ERR(gfar_dev);
@@ -478,3 +545,256 @@ err:
}
arch_initcall(fsl_usb_of_init);
+
+#ifdef CONFIG_CPM2
+
+static const char fcc_regs[] = "fcc_regs";
+static const char fcc_regs_c[] = "fcc_regs_c";
+static const char fcc_pram[] = "fcc_pram";
+static char bus_id[9][BUS_ID_SIZE];
+
+static int __init fs_enet_of_init(void)
+{
+ struct device_node *np;
+ unsigned int i;
+ struct platform_device *fs_enet_dev;
+ struct resource res;
+ int ret;
+
+ for (np = NULL, i = 0;
+ (np = of_find_compatible_node(np, "network", "fs_enet")) != NULL;
+ i++) {
+ struct resource r[4];
+ struct device_node *phy, *mdio;
+ struct fs_platform_info fs_enet_data;
+ const unsigned int *id, *phy_addr, *phy_irq;
+ const void *mac_addr;
+ const phandle *ph;
+ const char *model;
+
+ memset(r, 0, sizeof(r));
+ memset(&fs_enet_data, 0, sizeof(fs_enet_data));
+
+ ret = of_address_to_resource(np, 0, &r[0]);
+ if (ret)
+ goto err;
+ r[0].name = fcc_regs;
+
+ ret = of_address_to_resource(np, 1, &r[1]);
+ if (ret)
+ goto err;
+ r[1].name = fcc_pram;
+
+ ret = of_address_to_resource(np, 2, &r[2]);
+ if (ret)
+ goto err;
+ r[2].name = fcc_regs_c;
+ fs_enet_data.fcc_regs_c = r[2].start;
+
+ r[3].start = r[3].end = irq_of_parse_and_map(np, 0);
+ r[3].flags = IORESOURCE_IRQ;
+
+ fs_enet_dev =
+ platform_device_register_simple("fsl-cpm-fcc", i, &r[0], 4);
+
+ if (IS_ERR(fs_enet_dev)) {
+ ret = PTR_ERR(fs_enet_dev);
+ goto err;
+ }
+
+ model = get_property(np, "model", NULL);
+ if (model == NULL) {
+ ret = -ENODEV;
+ goto unreg;
+ }
+
+ mac_addr = get_property(np, "mac-address", NULL);
+ memcpy(fs_enet_data.macaddr, mac_addr, 6);
+
+ ph = get_property(np, "phy-handle", NULL);
+ phy = of_find_node_by_phandle(*ph);
+
+ if (phy == NULL) {
+ ret = -ENODEV;
+ goto unreg;
+ }
+
+ phy_addr = get_property(phy, "reg", NULL);
+ fs_enet_data.phy_addr = *phy_addr;
+
+ phy_irq = get_property(phy, "interrupts", NULL);
+
+ id = get_property(np, "device-id", NULL);
+ fs_enet_data.fs_no = *id;
+ strcpy(fs_enet_data.fs_type, model);
+
+ mdio = of_get_parent(phy);
+ ret = of_address_to_resource(mdio, 0, &res);
+ if (ret) {
+ of_node_put(phy);
+ of_node_put(mdio);
+ goto unreg;
+ }
+
+ fs_enet_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
+ fs_enet_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+
+ if (strstr(model, "FCC")) {
+ int fcc_index = *id - 1;
+ const unsigned char *mdio_bb_prop;
+
+ fs_enet_data.dpram_offset = (u32)cpm_dpram_addr(0);
+ fs_enet_data.rx_ring = 32;
+ fs_enet_data.tx_ring = 32;
+ fs_enet_data.rx_copybreak = 240;
+ fs_enet_data.use_napi = 0;
+ fs_enet_data.napi_weight = 17;
+ fs_enet_data.mem_offset = FCC_MEM_OFFSET(fcc_index);
+ fs_enet_data.cp_page = CPM_CR_FCC_PAGE(fcc_index);
+ fs_enet_data.cp_block = CPM_CR_FCC_SBLOCK(fcc_index);
+
+ snprintf((char*)&bus_id[(*id)], BUS_ID_SIZE, "%x:%02x",
+ (u32)res.start, fs_enet_data.phy_addr);
+ fs_enet_data.bus_id = (char*)&bus_id[(*id)];
+ fs_enet_data.init_ioports = init_fcc_ioports;
+
+ mdio_bb_prop = get_property(phy, "bitbang", NULL);
+ if (mdio_bb_prop) {
+ struct platform_device *fs_enet_mdio_bb_dev;
+ struct fs_mii_bb_platform_info fs_enet_mdio_bb_data;
+
+ fs_enet_mdio_bb_dev =
+ platform_device_register_simple("fsl-bb-mdio",
+ i, NULL, 0);
+ memset(&fs_enet_mdio_bb_data, 0,
+ sizeof(struct fs_mii_bb_platform_info));
+ fs_enet_mdio_bb_data.mdio_dat.bit =
+ mdio_bb_prop[0];
+ fs_enet_mdio_bb_data.mdio_dir.bit =
+ mdio_bb_prop[1];
+ fs_enet_mdio_bb_data.mdc_dat.bit =
+ mdio_bb_prop[2];
+ fs_enet_mdio_bb_data.mdio_port =
+ mdio_bb_prop[3];
+ fs_enet_mdio_bb_data.mdc_port =
+ mdio_bb_prop[4];
+ fs_enet_mdio_bb_data.delay =
+ mdio_bb_prop[5];
+
+ fs_enet_mdio_bb_data.irq[0] = phy_irq[0];
+ fs_enet_mdio_bb_data.irq[1] = -1;
+ fs_enet_mdio_bb_data.irq[2] = -1;
+ fs_enet_mdio_bb_data.irq[3] = phy_irq[0];
+ fs_enet_mdio_bb_data.irq[31] = -1;
+
+ fs_enet_mdio_bb_data.mdio_dat.offset =
+ (u32)&cpm2_immr->im_ioport.iop_pdatc;
+ fs_enet_mdio_bb_data.mdio_dir.offset =
+ (u32)&cpm2_immr->im_ioport.iop_pdirc;
+ fs_enet_mdio_bb_data.mdc_dat.offset =
+ (u32)&cpm2_immr->im_ioport.iop_pdatc;
+
+ ret = platform_device_add_data(
+ fs_enet_mdio_bb_dev,
+ &fs_enet_mdio_bb_data,
+ sizeof(struct fs_mii_bb_platform_info));
+ if (ret)
+ goto unreg;
+ }
+
+ of_node_put(phy);
+ of_node_put(mdio);
+
+ ret = platform_device_add_data(fs_enet_dev, &fs_enet_data,
+ sizeof(struct
+ fs_platform_info));
+ if (ret)
+ goto unreg;
+ }
+ }
+ return 0;
+
+unreg:
+ platform_device_unregister(fs_enet_dev);
+err:
+ return ret;
+}
+
+arch_initcall(fs_enet_of_init);
+
+static const char scc_regs[] = "regs";
+static const char scc_pram[] = "pram";
+
+static int __init cpm_uart_of_init(void)
+{
+ struct device_node *np;
+ unsigned int i;
+ struct platform_device *cpm_uart_dev;
+ int ret;
+
+ for (np = NULL, i = 0;
+ (np = of_find_compatible_node(np, "serial", "cpm_uart")) != NULL;
+ i++) {
+ struct resource r[3];
+ struct fs_uart_platform_info cpm_uart_data;
+ const int *id;
+ const char *model;
+
+ memset(r, 0, sizeof(r));
+ memset(&cpm_uart_data, 0, sizeof(cpm_uart_data));
+
+ ret = of_address_to_resource(np, 0, &r[0]);
+ if (ret)
+ goto err;
+
+ r[0].name = scc_regs;
+
+ ret = of_address_to_resource(np, 1, &r[1]);
+ if (ret)
+ goto err;
+ r[1].name = scc_pram;
+
+ r[2].start = r[2].end = irq_of_parse_and_map(np, 0);
+ r[2].flags = IORESOURCE_IRQ;
+
+ cpm_uart_dev =
+ platform_device_register_simple("fsl-cpm-scc:uart", i, &r[0], 3);
+
+ if (IS_ERR(cpm_uart_dev)) {
+ ret = PTR_ERR(cpm_uart_dev);
+ goto err;
+ }
+
+ id = get_property(np, "device-id", NULL);
+ cpm_uart_data.fs_no = *id;
+
+ model = (char*)get_property(np, "model", NULL);
+ strcpy(cpm_uart_data.fs_type, model);
+
+ cpm_uart_data.uart_clk = ppc_proc_freq;
+
+ cpm_uart_data.tx_num_fifo = 4;
+ cpm_uart_data.tx_buf_size = 32;
+ cpm_uart_data.rx_num_fifo = 4;
+ cpm_uart_data.rx_buf_size = 32;
+ cpm_uart_data.clk_rx = *((u32 *) get_property(np, "rx-clock", NULL));
+ cpm_uart_data.clk_tx = *((u32 *) get_property(np, "tx-clock", NULL));
+
+ ret =
+ platform_device_add_data(cpm_uart_dev, &cpm_uart_data,
+ sizeof(struct
+ fs_uart_platform_info));
+ if (ret)
+ goto unreg;
+ }
+
+ return 0;
+
+unreg:
+ platform_device_unregister(cpm_uart_dev);
+err:
+ return ret;
+}
+
+arch_initcall(cpm_uart_of_init);
+#endif /* CONFIG_CPM2 */
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 5a3dd480d2fd..04e145b5fc32 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -5,6 +5,8 @@
#include <asm/mmu.h>
extern phys_addr_t get_immrbase(void);
+extern u32 get_brgfreq(void);
+extern u32 get_baudrate(void);
#endif
#endif
diff --git a/arch/powerpc/sysdev/i8259.c b/arch/powerpc/sysdev/i8259.c
index 26a6a3becd66..0450265d73bb 100644
--- a/arch/powerpc/sysdev/i8259.c
+++ b/arch/powerpc/sysdev/i8259.c
@@ -34,7 +34,7 @@ static struct irq_host *i8259_host;
* which is called. It should be noted that polling is broken on some
* IBM and Motorola PReP boxes so we must use the int-ack feature on them.
*/
-unsigned int i8259_irq(struct pt_regs *regs)
+unsigned int i8259_irq(void)
{
int irq;
int lock = 0;
diff --git a/arch/powerpc/sysdev/ipic.c b/arch/powerpc/sysdev/ipic.c
index 0251b7c68d0e..bc4d4a7f9657 100644
--- a/arch/powerpc/sysdev/ipic.c
+++ b/arch/powerpc/sysdev/ipic.c
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/ipic.c
+ * arch/powerpc/sysdev/ipic.c
*
* IPIC routines implementations.
*
@@ -709,7 +709,7 @@ void ipic_clear_mcp_status(u32 mask)
}
/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
-unsigned int ipic_get_irq(struct pt_regs *regs)
+unsigned int ipic_get_irq(void)
{
int irq;
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c
index b604926401f5..ba4833f57d47 100644
--- a/arch/powerpc/sysdev/mpic.c
+++ b/arch/powerpc/sysdev/mpic.c
@@ -339,9 +339,9 @@ static void __init mpic_scan_ht_pic(struct mpic *mpic, u8 __iomem *devbase,
for (pos = readb(devbase + PCI_CAPABILITY_LIST); pos != 0;
pos = readb(devbase + pos + PCI_CAP_LIST_NEXT)) {
u8 id = readb(devbase + pos + PCI_CAP_LIST_ID);
- if (id == PCI_CAP_ID_HT_IRQCONF) {
+ if (id == PCI_CAP_ID_HT) {
id = readb(devbase + pos + 3);
- if (id == 0x80)
+ if (id == HT_CAPTYPE_IRQ)
break;
}
}
@@ -489,9 +489,9 @@ static inline void mpic_eoi(struct mpic *mpic)
}
#ifdef CONFIG_SMP
-static irqreturn_t mpic_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mpic_ipi_action(int irq, void *dev_id)
{
- smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0, regs);
+ smp_message_recv(mpic_irq_to_hw(irq) - MPIC_VEC_IPI_0);
return IRQ_HANDLED;
}
#endif /* CONFIG_SMP */
@@ -1217,7 +1217,7 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0]));
}
-unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
+unsigned int mpic_get_one_irq(struct mpic *mpic)
{
u32 src;
@@ -1230,13 +1230,13 @@ unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs)
return irq_linear_revmap(mpic->irqhost, src);
}
-unsigned int mpic_get_irq(struct pt_regs *regs)
+unsigned int mpic_get_irq(void)
{
struct mpic *mpic = mpic_primary;
BUG_ON(mpic == NULL);
- return mpic_get_one_irq(mpic, regs);
+ return mpic_get_one_irq(mpic);
}
diff --git a/arch/powerpc/sysdev/qe_lib/Kconfig b/arch/powerpc/sysdev/qe_lib/Kconfig
new file mode 100644
index 000000000000..a725e80befa8
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/Kconfig
@@ -0,0 +1,30 @@
+#
+# QE Communication options
+#
+
+menu "QE Options"
+ depends on QUICC_ENGINE
+
+config UCC_SLOW
+ bool "UCC Slow Protocols Support"
+ default n
+ select UCC
+ help
+ This option provides qe_lib support to UCC slow
+ protocols: UART, BISYNC, QMC
+
+config UCC_FAST
+ bool "UCC Fast Protocols Support"
+ default n
+ select UCC
+ select UCC_SLOW
+ help
+ This option provides qe_lib support to UCC fast
+ protocols: HDLC, Ethernet, ATM, transparent
+
+config UCC
+ bool
+ default y if UCC_FAST || UCC_SLOW
+
+endmenu
+
diff --git a/arch/powerpc/sysdev/qe_lib/Makefile b/arch/powerpc/sysdev/qe_lib/Makefile
new file mode 100644
index 000000000000..874fe1a5b1cf
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux ppc-specific parts of QE
+#
+obj-$(CONFIG_QUICC_ENGINE)+= qe.o qe_ic.o qe_io.o
+
+obj-$(CONFIG_UCC) += ucc.o
+obj-$(CONFIG_UCC_SLOW) += ucc_slow.o
+obj-$(CONFIG_UCC_FAST) += ucc_fast.o
diff --git a/arch/powerpc/sysdev/qe_lib/qe.c b/arch/powerpc/sysdev/qe_lib/qe.c
new file mode 100644
index 000000000000..2bae632d3ad7
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ * Based on cpm2_common.c from Dan Malek (dmalek@jlc.net)
+ *
+ * Description:
+ * General Purpose functions for the global management of the
+ * QUICC Engine (QE).
+ *
+ * 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/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/bootmem.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <asm/irq.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+#include <asm/prom.h>
+#include <asm/rheap.h>
+
+static void qe_snums_init(void);
+static void qe_muram_init(void);
+static int qe_sdma_init(void);
+
+static DEFINE_SPINLOCK(qe_lock);
+
+/* QE snum state */
+enum qe_snum_state {
+ QE_SNUM_STATE_USED,
+ QE_SNUM_STATE_FREE
+};
+
+/* QE snum */
+struct qe_snum {
+ u8 num;
+ enum qe_snum_state state;
+};
+
+/* We allocate this here because it is used almost exclusively for
+ * the communication processor devices.
+ */
+struct qe_immap *qe_immr = NULL;
+EXPORT_SYMBOL(qe_immr);
+
+static struct qe_snum snums[QE_NUM_OF_SNUM]; /* Dynamically allocated SNUMs */
+
+static phys_addr_t qebase = -1;
+
+phys_addr_t get_qe_base(void)
+{
+ struct device_node *qe;
+
+ if (qebase != -1)
+ return qebase;
+
+ qe = of_find_node_by_type(NULL, "qe");
+ if (qe) {
+ unsigned int size;
+ const void *prop = get_property(qe, "reg", &size);
+ qebase = of_translate_address(qe, prop);
+ of_node_put(qe);
+ };
+
+ return qebase;
+}
+
+EXPORT_SYMBOL(get_qe_base);
+
+void qe_reset(void)
+{
+ if (qe_immr == NULL)
+ qe_immr = ioremap(get_qe_base(), QE_IMMAP_SIZE);
+
+ qe_snums_init();
+
+ qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ /* Reclaim the MURAM memory for our use. */
+ qe_muram_init();
+
+ if (qe_sdma_init())
+ panic("sdma init failed!");
+}
+
+int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, u32 cmd_input)
+{
+ unsigned long flags;
+ u8 mcn_shift = 0, dev_shift = 0;
+
+ spin_lock_irqsave(&qe_lock, flags);
+ if (cmd == QE_RESET) {
+ out_be32(&qe_immr->cp.cecr, (u32) (cmd | QE_CR_FLG));
+ } else {
+ if (cmd == QE_ASSIGN_PAGE) {
+ /* Here device is the SNUM, not sub-block */
+ dev_shift = QE_CR_SNUM_SHIFT;
+ } else if (cmd == QE_ASSIGN_RISC) {
+ /* Here device is the SNUM, and mcnProtocol is
+ * e_QeCmdRiscAssignment value */
+ dev_shift = QE_CR_SNUM_SHIFT;
+ mcn_shift = QE_CR_MCN_RISC_ASSIGN_SHIFT;
+ } else {
+ if (device == QE_CR_SUBBLOCK_USB)
+ mcn_shift = QE_CR_MCN_USB_SHIFT;
+ else
+ mcn_shift = QE_CR_MCN_NORMAL_SHIFT;
+ }
+
+ out_be32(&qe_immr->cp.cecdr,
+ immrbar_virt_to_phys((void *)cmd_input));
+ out_be32(&qe_immr->cp.cecr,
+ (cmd | QE_CR_FLG | ((u32) device << dev_shift) | (u32)
+ mcn_protocol << mcn_shift));
+ }
+
+ /* wait for the QE_CR_FLG to clear */
+ while(in_be32(&qe_immr->cp.cecr) & QE_CR_FLG)
+ cpu_relax();
+ spin_unlock_irqrestore(&qe_lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL(qe_issue_cmd);
+
+/* Set a baud rate generator. This needs lots of work. There are
+ * 16 BRGs, which can be connected to the QE channels or output
+ * as clocks. The BRGs are in two different block of internal
+ * memory mapped space.
+ * The baud rate clock is the system clock divided by something.
+ * It was set up long ago during the initial boot phase and is
+ * is given to us.
+ * Baud rate clocks are zero-based in the driver code (as that maps
+ * to port numbers). Documentation uses 1-based numbering.
+ */
+static unsigned int brg_clk = 0;
+
+unsigned int get_brg_clk(void)
+{
+ struct device_node *qe;
+ if (brg_clk)
+ return brg_clk;
+
+ qe = of_find_node_by_type(NULL, "qe");
+ if (qe) {
+ unsigned int size;
+ const u32 *prop = get_property(qe, "brg-frequency", &size);
+ brg_clk = *prop;
+ of_node_put(qe);
+ };
+ return brg_clk;
+}
+
+/* This function is used by UARTS, or anything else that uses a 16x
+ * oversampled clock.
+ */
+void qe_setbrg(u32 brg, u32 rate)
+{
+ volatile u32 *bp;
+ u32 divisor, tempval;
+ int div16 = 0;
+
+ bp = &qe_immr->brg.brgc1;
+ bp += brg;
+
+ divisor = (get_brg_clk() / rate);
+ if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
+ div16 = 1;
+ divisor /= 16;
+ }
+
+ tempval = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
+ if (div16)
+ tempval |= QE_BRGC_DIV16;
+
+ out_be32(bp, tempval);
+}
+
+/* Initialize SNUMs (thread serial numbers) according to
+ * QE Module Control chapter, SNUM table
+ */
+static void qe_snums_init(void)
+{
+ int i;
+ static const u8 snum_init[] = {
+ 0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
+ 0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
+ 0x98, 0x99, 0xA8, 0xA9, 0xB8, 0xB9, 0xC8, 0xC9,
+ 0xD8, 0xD9, 0xE8, 0xE9,
+ };
+
+ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+ snums[i].num = snum_init[i];
+ snums[i].state = QE_SNUM_STATE_FREE;
+ }
+}
+
+int qe_get_snum(void)
+{
+ unsigned long flags;
+ int snum = -EBUSY;
+ int i;
+
+ spin_lock_irqsave(&qe_lock, flags);
+ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+ if (snums[i].state == QE_SNUM_STATE_FREE) {
+ snums[i].state = QE_SNUM_STATE_USED;
+ snum = snums[i].num;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&qe_lock, flags);
+
+ return snum;
+}
+EXPORT_SYMBOL(qe_get_snum);
+
+void qe_put_snum(u8 snum)
+{
+ int i;
+
+ for (i = 0; i < QE_NUM_OF_SNUM; i++) {
+ if (snums[i].num == snum) {
+ snums[i].state = QE_SNUM_STATE_FREE;
+ break;
+ }
+ }
+}
+EXPORT_SYMBOL(qe_put_snum);
+
+static int qe_sdma_init(void)
+{
+ struct sdma *sdma = &qe_immr->sdma;
+ u32 sdma_buf_offset;
+
+ if (!sdma)
+ return -ENODEV;
+
+ /* allocate 2 internal temporary buffers (512 bytes size each) for
+ * the SDMA */
+ sdma_buf_offset = qe_muram_alloc(512 * 2, 64);
+ if (IS_MURAM_ERR(sdma_buf_offset))
+ return -ENOMEM;
+
+ out_be32(&sdma->sdebcr, sdma_buf_offset & QE_SDEBCR_BA_MASK);
+ out_be32(&sdma->sdmr, (QE_SDMR_GLB_1_MSK | (0x1 >>
+ QE_SDMR_CEN_SHIFT)));
+
+ return 0;
+}
+
+/*
+ * muram_alloc / muram_free bits.
+ */
+static DEFINE_SPINLOCK(qe_muram_lock);
+
+/* 16 blocks should be enough to satisfy all requests
+ * until the memory subsystem goes up... */
+static rh_block_t qe_boot_muram_rh_block[16];
+static rh_info_t qe_muram_info;
+
+static void qe_muram_init(void)
+{
+ struct device_node *np;
+ u32 address;
+ u64 size;
+ unsigned int flags;
+
+ /* initialize the info header */
+ rh_init(&qe_muram_info, 1,
+ sizeof(qe_boot_muram_rh_block) /
+ sizeof(qe_boot_muram_rh_block[0]), qe_boot_muram_rh_block);
+
+ /* Attach the usable muram area */
+ /* XXX: This is a subset of the available muram. It
+ * varies with the processor and the microcode patches activated.
+ */
+ 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);
+ }
+}
+
+/* This function returns an index into the MURAM area.
+ */
+u32 qe_muram_alloc(u32 size, u32 align)
+{
+ void *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;
+}
+EXPORT_SYMBOL(qe_muram_alloc);
+
+int qe_muram_free(u32 offset)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_muram_lock, flags);
+ ret = rh_free(&qe_muram_info, (void *)offset);
+ spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+ return ret;
+}
+EXPORT_SYMBOL(qe_muram_free);
+
+/* not sure if this is ever needed */
+u32 qe_muram_alloc_fixed(u32 offset, u32 size)
+{
+ void *start;
+ unsigned long flags;
+
+ spin_lock_irqsave(&qe_muram_lock, flags);
+ start = rh_alloc_fixed(&qe_muram_info, (void *)offset, size, "commproc");
+ spin_unlock_irqrestore(&qe_muram_lock, flags);
+
+ return (u32) start;
+}
+EXPORT_SYMBOL(qe_muram_alloc_fixed);
+
+void qe_muram_dump(void)
+{
+ rh_dump(&qe_muram_info);
+}
+EXPORT_SYMBOL(qe_muram_dump);
+
+void *qe_muram_addr(u32 offset)
+{
+ return (void *)&qe_immr->muram[offset];
+}
+EXPORT_SYMBOL(qe_muram_addr);
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
new file mode 100644
index 000000000000..6995f51b9488
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -0,0 +1,553 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/qe_ic.c
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ * Based on code from Shlomi Gridish <gridish@freescale.com>
+ *
+ * QUICC ENGINE Interrupt Controller
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/sysdev.h>
+#include <linux/device.h>
+#include <linux/bootmem.h>
+#include <linux/spinlock.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/qe_ic.h>
+
+#include "qe_ic.h"
+
+static DEFINE_SPINLOCK(qe_ic_lock);
+
+static struct qe_ic_info qe_ic_info[] = {
+ [1] = {
+ .mask = 0x00008000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 0,
+ .pri_reg = QEIC_CIPWCC,
+ },
+ [2] = {
+ .mask = 0x00004000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 1,
+ .pri_reg = QEIC_CIPWCC,
+ },
+ [3] = {
+ .mask = 0x00002000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 2,
+ .pri_reg = QEIC_CIPWCC,
+ },
+ [10] = {
+ .mask = 0x00000040,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 1,
+ .pri_reg = QEIC_CIPZCC,
+ },
+ [11] = {
+ .mask = 0x00000020,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 2,
+ .pri_reg = QEIC_CIPZCC,
+ },
+ [12] = {
+ .mask = 0x00000010,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 3,
+ .pri_reg = QEIC_CIPZCC,
+ },
+ [13] = {
+ .mask = 0x00000008,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 4,
+ .pri_reg = QEIC_CIPZCC,
+ },
+ [14] = {
+ .mask = 0x00000004,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 5,
+ .pri_reg = QEIC_CIPZCC,
+ },
+ [15] = {
+ .mask = 0x00000002,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 6,
+ .pri_reg = QEIC_CIPZCC,
+ },
+ [20] = {
+ .mask = 0x10000000,
+ .mask_reg = QEIC_CRIMR,
+ .pri_code = 3,
+ .pri_reg = QEIC_CIPRTA,
+ },
+ [25] = {
+ .mask = 0x00800000,
+ .mask_reg = QEIC_CRIMR,
+ .pri_code = 0,
+ .pri_reg = QEIC_CIPRTB,
+ },
+ [26] = {
+ .mask = 0x00400000,
+ .mask_reg = QEIC_CRIMR,
+ .pri_code = 1,
+ .pri_reg = QEIC_CIPRTB,
+ },
+ [27] = {
+ .mask = 0x00200000,
+ .mask_reg = QEIC_CRIMR,
+ .pri_code = 2,
+ .pri_reg = QEIC_CIPRTB,
+ },
+ [28] = {
+ .mask = 0x00100000,
+ .mask_reg = QEIC_CRIMR,
+ .pri_code = 3,
+ .pri_reg = QEIC_CIPRTB,
+ },
+ [32] = {
+ .mask = 0x80000000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 0,
+ .pri_reg = QEIC_CIPXCC,
+ },
+ [33] = {
+ .mask = 0x40000000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 1,
+ .pri_reg = QEIC_CIPXCC,
+ },
+ [34] = {
+ .mask = 0x20000000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 2,
+ .pri_reg = QEIC_CIPXCC,
+ },
+ [35] = {
+ .mask = 0x10000000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 3,
+ .pri_reg = QEIC_CIPXCC,
+ },
+ [36] = {
+ .mask = 0x08000000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 4,
+ .pri_reg = QEIC_CIPXCC,
+ },
+ [40] = {
+ .mask = 0x00800000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 0,
+ .pri_reg = QEIC_CIPYCC,
+ },
+ [41] = {
+ .mask = 0x00400000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 1,
+ .pri_reg = QEIC_CIPYCC,
+ },
+ [42] = {
+ .mask = 0x00200000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 2,
+ .pri_reg = QEIC_CIPYCC,
+ },
+ [43] = {
+ .mask = 0x00100000,
+ .mask_reg = QEIC_CIMR,
+ .pri_code = 3,
+ .pri_reg = QEIC_CIPYCC,
+ },
+};
+
+static inline u32 qe_ic_read(volatile __be32 __iomem * base, unsigned int reg)
+{
+ return in_be32(base + (reg >> 2));
+}
+
+static inline void qe_ic_write(volatile __be32 __iomem * base, unsigned int reg,
+ u32 value)
+{
+ out_be32(base + (reg >> 2), value);
+}
+
+static inline struct qe_ic *qe_ic_from_irq(unsigned int virq)
+{
+ return irq_desc[virq].chip_data;
+}
+
+#define virq_to_hw(virq) ((unsigned int)irq_map[virq].hwirq)
+
+static void qe_ic_unmask_irq(unsigned int virq)
+{
+ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+ unsigned int src = virq_to_hw(virq);
+ unsigned long flags;
+ u32 temp;
+
+ spin_lock_irqsave(&qe_ic_lock, flags);
+
+ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+ temp | qe_ic_info[src].mask);
+
+ spin_unlock_irqrestore(&qe_ic_lock, flags);
+}
+
+static void qe_ic_mask_irq(unsigned int virq)
+{
+ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+ unsigned int src = virq_to_hw(virq);
+ unsigned long flags;
+ u32 temp;
+
+ spin_lock_irqsave(&qe_ic_lock, flags);
+
+ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+ temp & ~qe_ic_info[src].mask);
+
+ spin_unlock_irqrestore(&qe_ic_lock, flags);
+}
+
+static void qe_ic_mask_irq_and_ack(unsigned int virq)
+{
+ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+ unsigned int src = virq_to_hw(virq);
+ unsigned long flags;
+ u32 temp;
+
+ spin_lock_irqsave(&qe_ic_lock, flags);
+
+ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].mask_reg);
+ qe_ic_write(qe_ic->regs, qe_ic_info[src].mask_reg,
+ temp & ~qe_ic_info[src].mask);
+
+ /* There is nothing to do for ack here, ack is handled in ISR */
+
+ spin_unlock_irqrestore(&qe_ic_lock, flags);
+}
+
+static struct irq_chip qe_ic_irq_chip = {
+ .typename = " QEIC ",
+ .unmask = qe_ic_unmask_irq,
+ .mask = qe_ic_mask_irq,
+ .mask_ack = qe_ic_mask_irq_and_ack,
+};
+
+static int qe_ic_host_match(struct irq_host *h, struct device_node *node)
+{
+ struct qe_ic *qe_ic = h->host_data;
+
+ /* Exact match, unless qe_ic node is NULL */
+ return qe_ic->of_node == NULL || qe_ic->of_node == node;
+}
+
+static int qe_ic_host_map(struct irq_host *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct qe_ic *qe_ic = h->host_data;
+ struct irq_chip *chip;
+
+ if (qe_ic_info[hw].mask == 0) {
+ printk(KERN_ERR "Can't map reserved IRQ \n");
+ return -EINVAL;
+ }
+ /* Default chip */
+ chip = &qe_ic->hc_irq;
+
+ set_irq_chip_data(virq, qe_ic);
+ get_irq_desc(virq)->status |= IRQ_LEVEL;
+
+ set_irq_chip_and_handler(virq, chip, handle_level_irq);
+
+ return 0;
+}
+
+static int qe_ic_host_xlate(struct irq_host *h, struct device_node *ct,
+ u32 * intspec, unsigned int intsize,
+ irq_hw_number_t * out_hwirq,
+ unsigned int *out_flags)
+{
+ *out_hwirq = intspec[0];
+ if (intsize > 1)
+ *out_flags = intspec[1];
+ else
+ *out_flags = IRQ_TYPE_NONE;
+ return 0;
+}
+
+static struct irq_host_ops qe_ic_host_ops = {
+ .match = qe_ic_host_match,
+ .map = qe_ic_host_map,
+ .xlate = qe_ic_host_xlate,
+};
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic)
+{
+ int irq;
+
+ BUG_ON(qe_ic == NULL);
+
+ /* get the interrupt source vector. */
+ irq = qe_ic_read(qe_ic->regs, QEIC_CIVEC) >> 26;
+
+ if (irq == 0)
+ return NO_IRQ;
+
+ return irq_linear_revmap(qe_ic->irqhost, irq);
+}
+
+/* Return an interrupt vector or NO_IRQ if no interrupt is pending. */
+unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
+{
+ int irq;
+
+ BUG_ON(qe_ic == NULL);
+
+ /* get the interrupt source vector. */
+ irq = qe_ic_read(qe_ic->regs, QEIC_CHIVEC) >> 26;
+
+ if (irq == 0)
+ return NO_IRQ;
+
+ return irq_linear_revmap(qe_ic->irqhost, irq);
+}
+
+/* FIXME: We mask all the QE Low interrupts while handling. We should
+ * let other interrupt come in, but BAD interrupts are generated */
+void fastcall qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
+{
+ struct qe_ic *qe_ic = desc->handler_data;
+ struct irq_chip *chip = irq_desc[irq].chip;
+
+ unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
+
+ chip->mask_ack(irq);
+ if (cascade_irq != NO_IRQ)
+ generic_handle_irq(cascade_irq);
+ chip->unmask(irq);
+}
+
+/* FIXME: We mask all the QE High interrupts while handling. We should
+ * let other interrupt come in, but BAD interrupts are generated */
+void fastcall qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
+{
+ struct qe_ic *qe_ic = desc->handler_data;
+ struct irq_chip *chip = irq_desc[irq].chip;
+
+ unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
+
+ chip->mask_ack(irq);
+ if (cascade_irq != NO_IRQ)
+ generic_handle_irq(cascade_irq);
+ chip->unmask(irq);
+}
+
+void __init qe_ic_init(struct device_node *node, unsigned int flags)
+{
+ struct qe_ic *qe_ic;
+ struct resource res;
+ u32 temp = 0, ret, high_active = 0;
+
+ qe_ic = alloc_bootmem(sizeof(struct qe_ic));
+ if (qe_ic == NULL)
+ return;
+
+ memset(qe_ic, 0, sizeof(struct qe_ic));
+ qe_ic->of_node = node ? of_node_get(node) : NULL;
+
+ qe_ic->irqhost = irq_alloc_host(IRQ_HOST_MAP_LINEAR,
+ NR_QE_IC_INTS, &qe_ic_host_ops, 0);
+ if (qe_ic->irqhost == NULL) {
+ of_node_put(node);
+ return;
+ }
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret)
+ return;
+
+ qe_ic->regs = ioremap(res.start, res.end - res.start + 1);
+
+ qe_ic->irqhost->host_data = qe_ic;
+ qe_ic->hc_irq = qe_ic_irq_chip;
+
+ qe_ic->virq_high = irq_of_parse_and_map(node, 0);
+ qe_ic->virq_low = irq_of_parse_and_map(node, 1);
+
+ if (qe_ic->virq_low == NO_IRQ) {
+ printk(KERN_ERR "Failed to map QE_IC low IRQ\n");
+ return;
+ }
+
+ /* default priority scheme is grouped. If spread mode is */
+ /* required, configure cicr accordingly. */
+ if (flags & QE_IC_SPREADMODE_GRP_W)
+ temp |= CICR_GWCC;
+ if (flags & QE_IC_SPREADMODE_GRP_X)
+ temp |= CICR_GXCC;
+ if (flags & QE_IC_SPREADMODE_GRP_Y)
+ temp |= CICR_GYCC;
+ if (flags & QE_IC_SPREADMODE_GRP_Z)
+ temp |= CICR_GZCC;
+ if (flags & QE_IC_SPREADMODE_GRP_RISCA)
+ temp |= CICR_GRTA;
+ if (flags & QE_IC_SPREADMODE_GRP_RISCB)
+ temp |= CICR_GRTB;
+
+ /* choose destination signal for highest priority interrupt */
+ if (flags & QE_IC_HIGH_SIGNAL) {
+ temp |= (SIGNAL_HIGH << CICR_HPIT_SHIFT);
+ high_active = 1;
+ }
+
+ qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+
+ set_irq_data(qe_ic->virq_low, qe_ic);
+ set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low);
+
+ if (qe_ic->virq_high != NO_IRQ) {
+ set_irq_data(qe_ic->virq_high, qe_ic);
+ set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high);
+ }
+
+ printk("QEIC (%d IRQ sources) at %p\n", NR_QE_IC_INTS, qe_ic->regs);
+}
+
+void qe_ic_set_highest_priority(unsigned int virq, int high)
+{
+ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+ unsigned int src = virq_to_hw(virq);
+ u32 temp = 0;
+
+ temp = qe_ic_read(qe_ic->regs, QEIC_CICR);
+
+ temp &= ~CICR_HP_MASK;
+ temp |= src << CICR_HP_SHIFT;
+
+ temp &= ~CICR_HPIT_MASK;
+ temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << CICR_HPIT_SHIFT;
+
+ qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
+}
+
+/* Set Priority level within its group, from 1 to 8 */
+int qe_ic_set_priority(unsigned int virq, unsigned int priority)
+{
+ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+ unsigned int src = virq_to_hw(virq);
+ u32 temp;
+
+ if (priority > 8 || priority == 0)
+ return -EINVAL;
+ if (src > 127)
+ return -EINVAL;
+ if (qe_ic_info[src].pri_reg == 0)
+ return -EINVAL;
+
+ temp = qe_ic_read(qe_ic->regs, qe_ic_info[src].pri_reg);
+
+ if (priority < 4) {
+ temp &= ~(0x7 << (32 - priority * 3));
+ temp |= qe_ic_info[src].pri_code << (32 - priority * 3);
+ } else {
+ temp &= ~(0x7 << (24 - priority * 3));
+ temp |= qe_ic_info[src].pri_code << (24 - priority * 3);
+ }
+
+ qe_ic_write(qe_ic->regs, qe_ic_info[src].pri_reg, temp);
+
+ return 0;
+}
+
+/* Set a QE priority to use high irq, only priority 1~2 can use high irq */
+int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high)
+{
+ struct qe_ic *qe_ic = qe_ic_from_irq(virq);
+ unsigned int src = virq_to_hw(virq);
+ u32 temp, control_reg = QEIC_CICNR, shift = 0;
+
+ if (priority > 2 || priority == 0)
+ return -EINVAL;
+
+ switch (qe_ic_info[src].pri_reg) {
+ case QEIC_CIPZCC:
+ shift = CICNR_ZCC1T_SHIFT;
+ break;
+ case QEIC_CIPWCC:
+ shift = CICNR_WCC1T_SHIFT;
+ break;
+ case QEIC_CIPYCC:
+ shift = CICNR_YCC1T_SHIFT;
+ break;
+ case QEIC_CIPXCC:
+ shift = CICNR_XCC1T_SHIFT;
+ break;
+ case QEIC_CIPRTA:
+ shift = CRICR_RTA1T_SHIFT;
+ control_reg = QEIC_CRICR;
+ break;
+ case QEIC_CIPRTB:
+ shift = CRICR_RTB1T_SHIFT;
+ control_reg = QEIC_CRICR;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ shift += (2 - priority) * 2;
+ temp = qe_ic_read(qe_ic->regs, control_reg);
+ temp &= ~(SIGNAL_MASK << shift);
+ temp |= (high ? SIGNAL_HIGH : SIGNAL_LOW) << shift;
+ qe_ic_write(qe_ic->regs, control_reg, temp);
+
+ return 0;
+}
+
+static struct sysdev_class qe_ic_sysclass = {
+ set_kset_name("qe_ic"),
+};
+
+static struct sys_device device_qe_ic = {
+ .id = 0,
+ .cls = &qe_ic_sysclass,
+};
+
+static int __init init_qe_ic_sysfs(void)
+{
+ int rc;
+
+ printk(KERN_DEBUG "Registering qe_ic with sysfs...\n");
+
+ rc = sysdev_class_register(&qe_ic_sysclass);
+ if (rc) {
+ printk(KERN_ERR "Failed registering qe_ic sys class\n");
+ return -ENODEV;
+ }
+ rc = sysdev_register(&device_qe_ic);
+ if (rc) {
+ printk(KERN_ERR "Failed registering qe_ic sys device\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+subsys_initcall(init_qe_ic_sysfs);
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.h b/arch/powerpc/sysdev/qe_lib/qe_ic.h
new file mode 100644
index 000000000000..9a631adb189d
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.h
@@ -0,0 +1,106 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/qe_ic.h
+ *
+ * QUICC ENGINE Interrupt Controller Header
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Author: Li Yang <leoli@freescale.com>
+ * Based on code from Shlomi Gridish <gridish@freescale.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.
+ */
+#ifndef _POWERPC_SYSDEV_QE_IC_H
+#define _POWERPC_SYSDEV_QE_IC_H
+
+#include <asm/qe_ic.h>
+
+#define NR_QE_IC_INTS 64
+
+/* QE IC registers offset */
+#define QEIC_CICR 0x00
+#define QEIC_CIVEC 0x04
+#define QEIC_CRIPNR 0x08
+#define QEIC_CIPNR 0x0c
+#define QEIC_CIPXCC 0x10
+#define QEIC_CIPYCC 0x14
+#define QEIC_CIPWCC 0x18
+#define QEIC_CIPZCC 0x1c
+#define QEIC_CIMR 0x20
+#define QEIC_CRIMR 0x24
+#define QEIC_CICNR 0x28
+#define QEIC_CIPRTA 0x30
+#define QEIC_CIPRTB 0x34
+#define QEIC_CRICR 0x3c
+#define QEIC_CHIVEC 0x60
+
+/* Interrupt priority registers */
+#define CIPCC_SHIFT_PRI0 29
+#define CIPCC_SHIFT_PRI1 26
+#define CIPCC_SHIFT_PRI2 23
+#define CIPCC_SHIFT_PRI3 20
+#define CIPCC_SHIFT_PRI4 13
+#define CIPCC_SHIFT_PRI5 10
+#define CIPCC_SHIFT_PRI6 7
+#define CIPCC_SHIFT_PRI7 4
+
+/* CICR priority modes */
+#define CICR_GWCC 0x00040000
+#define CICR_GXCC 0x00020000
+#define CICR_GYCC 0x00010000
+#define CICR_GZCC 0x00080000
+#define CICR_GRTA 0x00200000
+#define CICR_GRTB 0x00400000
+#define CICR_HPIT_SHIFT 8
+#define CICR_HPIT_MASK 0x00000300
+#define CICR_HP_SHIFT 24
+#define CICR_HP_MASK 0x3f000000
+
+/* CICNR */
+#define CICNR_WCC1T_SHIFT 20
+#define CICNR_ZCC1T_SHIFT 28
+#define CICNR_YCC1T_SHIFT 12
+#define CICNR_XCC1T_SHIFT 4
+
+/* CRICR */
+#define CRICR_RTA1T_SHIFT 20
+#define CRICR_RTB1T_SHIFT 28
+
+/* Signal indicator */
+#define SIGNAL_MASK 3
+#define SIGNAL_HIGH 2
+#define SIGNAL_LOW 0
+
+struct qe_ic {
+ /* Control registers offset */
+ volatile u32 __iomem *regs;
+
+ /* The remapper for this QEIC */
+ struct irq_host *irqhost;
+
+ /* The "linux" controller struct */
+ struct irq_chip hc_irq;
+
+ /* The device node of the interrupt controller */
+ struct device_node *of_node;
+
+ /* VIRQ numbers of QE high/low irqs */
+ unsigned int virq_high;
+ unsigned int virq_low;
+};
+
+/*
+ * QE interrupt controller internal structure
+ */
+struct qe_ic_info {
+ u32 mask; /* location of this source at the QIMR register. */
+ u32 mask_reg; /* Mask register offset */
+ u8 pri_code; /* for grouped interrupts sources - the interrupt
+ code as appears at the group priority register */
+ u32 pri_reg; /* Group priority register offset */
+};
+
+#endif /* _POWERPC_SYSDEV_QE_IC_H */
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
new file mode 100644
index 000000000000..0afe6bfe3714
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -0,0 +1,225 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/qe_io.c
+ *
+ * QE Parallel I/O ports configuration routines
+ *
+ * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved.
+ *
+ * Author: Li Yang <LeoLi@freescale.com>
+ * Based on code from Shlomi Gridish <gridish@freescale.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/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <sysdev/fsl_soc.h>
+
+#undef DEBUG
+
+#define NUM_OF_PINS 32
+
+struct port_regs {
+ __be32 cpodr; /* Open drain register */
+ __be32 cpdata; /* Data register */
+ __be32 cpdir1; /* Direction register */
+ __be32 cpdir2; /* Direction register */
+ __be32 cppar1; /* Pin assignment register */
+ __be32 cppar2; /* Pin assignment register */
+};
+
+static struct port_regs *par_io = NULL;
+static int num_par_io_ports = 0;
+
+int par_io_init(struct device_node *np)
+{
+ struct resource res;
+ int ret;
+ const u32 *num_ports;
+
+ /* Map Parallel I/O ports registers */
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ return ret;
+ par_io = ioremap(res.start, res.end - res.start + 1);
+
+ num_ports = get_property(np, "num-ports", NULL);
+ if (num_ports)
+ num_par_io_ports = *num_ports;
+
+ return 0;
+}
+
+int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
+ int assignment, int has_irq)
+{
+ u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val;
+
+ if (!par_io)
+ return -1;
+
+ /* calculate pin location for single and 2 bits information */
+ pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
+
+ /* Set open drain, if required */
+ tmp_val = in_be32(&par_io[port].cpodr);
+ if (open_drain)
+ out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val);
+ else
+ out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val);
+
+ /* define direction */
+ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+ in_be32(&par_io[port].cpdir2) :
+ in_be32(&par_io[port].cpdir1);
+
+ /* get all bits mask for 2 bit per port */
+ pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS -
+ (pin % (NUM_OF_PINS / 2) + 1) * 2));
+
+ /* Get the final mask we need for the right definition */
+ new_mask2bits = (u32) (dir << (NUM_OF_PINS -
+ (pin % (NUM_OF_PINS / 2) + 1) * 2));
+
+ /* clear and set 2 bits mask */
+ if (pin > (NUM_OF_PINS / 2) - 1) {
+ out_be32(&par_io[port].cpdir2,
+ ~pin_mask2bits & tmp_val);
+ tmp_val &= ~pin_mask2bits;
+ out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val);
+ } else {
+ out_be32(&par_io[port].cpdir1,
+ ~pin_mask2bits & tmp_val);
+ tmp_val &= ~pin_mask2bits;
+ out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val);
+ }
+ /* define pin assignment */
+ tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
+ in_be32(&par_io[port].cppar2) :
+ in_be32(&par_io[port].cppar1);
+
+ new_mask2bits = (u32) (assignment << (NUM_OF_PINS -
+ (pin % (NUM_OF_PINS / 2) + 1) * 2));
+ /* clear and set 2 bits mask */
+ if (pin > (NUM_OF_PINS / 2) - 1) {
+ out_be32(&par_io[port].cppar2,
+ ~pin_mask2bits & tmp_val);
+ tmp_val &= ~pin_mask2bits;
+ out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val);
+ } else {
+ out_be32(&par_io[port].cppar1,
+ ~pin_mask2bits & tmp_val);
+ tmp_val &= ~pin_mask2bits;
+ out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(par_io_config_pin);
+
+int par_io_data_set(u8 port, u8 pin, u8 val)
+{
+ u32 pin_mask, tmp_val;
+
+ if (port >= num_par_io_ports)
+ return -EINVAL;
+ if (pin >= NUM_OF_PINS)
+ return -EINVAL;
+ /* calculate pin location */
+ pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - pin));
+
+ tmp_val = in_be32(&par_io[port].cpdata);
+
+ if (val == 0) /* clear */
+ out_be32(&par_io[port].cpdata, ~pin_mask & tmp_val);
+ else /* set */
+ out_be32(&par_io[port].cpdata, pin_mask | tmp_val);
+
+ return 0;
+}
+EXPORT_SYMBOL(par_io_data_set);
+
+int par_io_of_config(struct device_node *np)
+{
+ struct device_node *pio;
+ const phandle *ph;
+ int pio_map_len;
+ const unsigned int *pio_map;
+
+ if (par_io == NULL) {
+ printk(KERN_ERR "par_io not initialized \n");
+ return -1;
+ }
+
+ ph = get_property(np, "pio-handle", NULL);
+ if (ph == 0) {
+ printk(KERN_ERR "pio-handle not available \n");
+ return -1;
+ }
+
+ pio = of_find_node_by_phandle(*ph);
+
+ pio_map = get_property(pio, "pio-map", &pio_map_len);
+ if (pio_map == NULL) {
+ printk(KERN_ERR "pio-map is not set! \n");
+ return -1;
+ }
+ pio_map_len /= sizeof(unsigned int);
+ if ((pio_map_len % 6) != 0) {
+ printk(KERN_ERR "pio-map format wrong! \n");
+ return -1;
+ }
+
+ while (pio_map_len > 0) {
+ par_io_config_pin((u8) pio_map[0], (u8) pio_map[1],
+ (int) pio_map[2], (int) pio_map[3],
+ (int) pio_map[4], (int) pio_map[5]);
+ pio_map += 6;
+ pio_map_len -= 6;
+ }
+ of_node_put(pio);
+ return 0;
+}
+EXPORT_SYMBOL(par_io_of_config);
+
+#ifdef DEBUG
+static void dump_par_io(void)
+{
+ int i;
+
+ printk(KERN_INFO "PAR IO registars:\n");
+ printk(KERN_INFO "Base address: 0x%08x\n", (u32) par_io);
+ for (i = 0; i < num_par_io_ports; i++) {
+ printk(KERN_INFO "cpodr[%d] : addr - 0x%08x, val - 0x%08x\n",
+ i, (u32) & par_io[i].cpodr,
+ in_be32(&par_io[i].cpodr));
+ printk(KERN_INFO "cpdata[%d]: addr - 0x%08x, val - 0x%08x\n",
+ i, (u32) & par_io[i].cpdata,
+ in_be32(&par_io[i].cpdata));
+ printk(KERN_INFO "cpdir1[%d]: addr - 0x%08x, val - 0x%08x\n",
+ i, (u32) & par_io[i].cpdir1,
+ in_be32(&par_io[i].cpdir1));
+ printk(KERN_INFO "cpdir2[%d]: addr - 0x%08x, val - 0x%08x\n",
+ i, (u32) & par_io[i].cpdir2,
+ in_be32(&par_io[i].cpdir2));
+ printk(KERN_INFO "cppar1[%d]: addr - 0x%08x, val - 0x%08x\n",
+ i, (u32) & par_io[i].cppar1,
+ in_be32(&par_io[i].cppar1));
+ printk(KERN_INFO "cppar2[%d]: addr - 0x%08x, val - 0x%08x\n",
+ i, (u32) & par_io[i].cppar2,
+ in_be32(&par_io[i].cppar2));
+ }
+
+}
+EXPORT_SYMBOL(dump_par_io);
+#endif /* DEBUG */
diff --git a/arch/powerpc/sysdev/qe_lib/ucc.c b/arch/powerpc/sysdev/qe_lib/ucc.c
new file mode 100644
index 000000000000..916c9e5df57f
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/ucc.c
@@ -0,0 +1,251 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/ucc.c
+ *
+ * QE UCC API Set - UCC specific routines implementations.
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.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/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+#include <asm/ucc.h>
+
+static DEFINE_SPINLOCK(ucc_lock);
+
+int ucc_set_qe_mux_mii_mng(int ucc_num)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ucc_lock, flags);
+ out_be32(&qe_immr->qmx.cmxgcr,
+ ((in_be32(&qe_immr->qmx.cmxgcr) &
+ ~QE_CMXGCR_MII_ENET_MNG) |
+ (ucc_num << QE_CMXGCR_MII_ENET_MNG_SHIFT)));
+ spin_unlock_irqrestore(&ucc_lock, flags);
+
+ return 0;
+}
+
+int ucc_set_type(int ucc_num, struct ucc_common *regs,
+ enum ucc_speed_type speed)
+{
+ u8 guemr = 0;
+
+ /* check if the UCC number is in range. */
+ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+ return -EINVAL;
+
+ guemr = regs->guemr;
+ guemr &= ~(UCC_GUEMR_MODE_MASK_RX | UCC_GUEMR_MODE_MASK_TX);
+ switch (speed) {
+ case UCC_SPEED_TYPE_SLOW:
+ guemr |= (UCC_GUEMR_MODE_SLOW_RX | UCC_GUEMR_MODE_SLOW_TX);
+ break;
+ case UCC_SPEED_TYPE_FAST:
+ guemr |= (UCC_GUEMR_MODE_FAST_RX | UCC_GUEMR_MODE_FAST_TX);
+ break;
+ default:
+ return -EINVAL;
+ }
+ regs->guemr = guemr;
+
+ return 0;
+}
+
+int ucc_init_guemr(struct ucc_common *regs)
+{
+ u8 guemr = 0;
+
+ if (!regs)
+ return -EINVAL;
+
+ /* Set bit 3 (which is reserved in the GUEMR register) to 1 */
+ guemr = UCC_GUEMR_SET_RESERVED3;
+
+ regs->guemr = guemr;
+
+ return 0;
+}
+
+static void get_cmxucr_reg(int ucc_num, volatile u32 ** p_cmxucr, u8 * reg_num,
+ u8 * shift)
+{
+ switch (ucc_num) {
+ case 0: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
+ *reg_num = 1;
+ *shift = 16;
+ break;
+ case 2: *p_cmxucr = &(qe_immr->qmx.cmxucr1);
+ *reg_num = 1;
+ *shift = 0;
+ break;
+ case 4: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
+ *reg_num = 2;
+ *shift = 16;
+ break;
+ case 6: *p_cmxucr = &(qe_immr->qmx.cmxucr2);
+ *reg_num = 2;
+ *shift = 0;
+ break;
+ case 1: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
+ *reg_num = 3;
+ *shift = 16;
+ break;
+ case 3: *p_cmxucr = &(qe_immr->qmx.cmxucr3);
+ *reg_num = 3;
+ *shift = 0;
+ break;
+ case 5: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
+ *reg_num = 4;
+ *shift = 16;
+ break;
+ case 7: *p_cmxucr = &(qe_immr->qmx.cmxucr4);
+ *reg_num = 4;
+ *shift = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask)
+{
+ volatile u32 *p_cmxucr;
+ u8 reg_num;
+ u8 shift;
+
+ /* check if the UCC number is in range. */
+ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+ return -EINVAL;
+
+ get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
+
+ if (set)
+ out_be32(p_cmxucr, in_be32(p_cmxucr) | (mask << shift));
+ else
+ out_be32(p_cmxucr, in_be32(p_cmxucr) & ~(mask << shift));
+
+ return 0;
+}
+
+int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode)
+{
+ volatile u32 *p_cmxucr;
+ u8 reg_num;
+ u8 shift;
+ u32 clock_bits;
+ u32 clock_mask;
+ int source = -1;
+
+ /* check if the UCC number is in range. */
+ if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0))
+ return -EINVAL;
+
+ if (!((mode == COMM_DIR_RX) || (mode == COMM_DIR_TX))) {
+ printk(KERN_ERR
+ "ucc_set_qe_mux_rxtx: bad comm mode type passed.");
+ return -EINVAL;
+ }
+
+ get_cmxucr_reg(ucc_num, &p_cmxucr, &reg_num, &shift);
+
+ switch (reg_num) {
+ case 1:
+ switch (clock) {
+ case QE_BRG1: source = 1; break;
+ case QE_BRG2: source = 2; break;
+ case QE_BRG7: source = 3; break;
+ case QE_BRG8: source = 4; break;
+ case QE_CLK9: source = 5; break;
+ case QE_CLK10: source = 6; break;
+ case QE_CLK11: source = 7; break;
+ case QE_CLK12: source = 8; break;
+ case QE_CLK15: source = 9; break;
+ case QE_CLK16: source = 10; break;
+ default: source = -1; break;
+ }
+ break;
+ case 2:
+ switch (clock) {
+ case QE_BRG5: source = 1; break;
+ case QE_BRG6: source = 2; break;
+ case QE_BRG7: source = 3; break;
+ case QE_BRG8: source = 4; break;
+ case QE_CLK13: source = 5; break;
+ case QE_CLK14: source = 6; break;
+ case QE_CLK19: source = 7; break;
+ case QE_CLK20: source = 8; break;
+ case QE_CLK15: source = 9; break;
+ case QE_CLK16: source = 10; break;
+ default: source = -1; break;
+ }
+ break;
+ case 3:
+ switch (clock) {
+ case QE_BRG9: source = 1; break;
+ case QE_BRG10: source = 2; break;
+ case QE_BRG15: source = 3; break;
+ case QE_BRG16: source = 4; break;
+ case QE_CLK3: source = 5; break;
+ case QE_CLK4: source = 6; break;
+ case QE_CLK17: source = 7; break;
+ case QE_CLK18: source = 8; break;
+ case QE_CLK7: source = 9; break;
+ case QE_CLK8: source = 10; break;
+ default: source = -1; break;
+ }
+ break;
+ case 4:
+ switch (clock) {
+ case QE_BRG13: source = 1; break;
+ case QE_BRG14: source = 2; break;
+ case QE_BRG15: source = 3; break;
+ case QE_BRG16: source = 4; break;
+ case QE_CLK5: source = 5; break;
+ case QE_CLK6: source = 6; break;
+ case QE_CLK21: source = 7; break;
+ case QE_CLK22: source = 8; break;
+ case QE_CLK7: source = 9; break;
+ case QE_CLK8: source = 10; break;
+ default: source = -1; break;
+ }
+ break;
+ default:
+ source = -1;
+ break;
+ }
+
+ if (source == -1) {
+ printk(KERN_ERR
+ "ucc_set_qe_mux_rxtx: Bad combination of clock and UCC.");
+ return -ENOENT;
+ }
+
+ clock_bits = (u32) source;
+ clock_mask = QE_CMXUCR_TX_CLK_SRC_MASK;
+ if (mode == COMM_DIR_RX) {
+ clock_bits <<= 4; /* Rx field is 4 bits to left of Tx field */
+ clock_mask <<= 4; /* Rx field is 4 bits to left of Tx field */
+ }
+ clock_bits <<= shift;
+ clock_mask <<= shift;
+
+ out_be32(p_cmxucr, (in_be32(p_cmxucr) & ~clock_mask) | clock_bits);
+
+ return 0;
+}
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_fast.c b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
new file mode 100644
index 000000000000..c2be7348fcbd
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/ucc_fast.c
@@ -0,0 +1,396 @@
+/*
+ * arch/powerpc/sysdev/qe_lib/ucc_fast.c
+ *
+ * QE UCC Fast API Set - UCC Fast specific routines implementations.
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.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/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include <asm/ucc.h>
+#include <asm/ucc_fast.h>
+
+#define uccf_printk(level, format, arg...) \
+ printk(level format "\n", ## arg)
+
+#define uccf_dbg(format, arg...) \
+ uccf_printk(KERN_DEBUG , format , ## arg)
+#define uccf_err(format, arg...) \
+ uccf_printk(KERN_ERR , format , ## arg)
+#define uccf_info(format, arg...) \
+ uccf_printk(KERN_INFO , format , ## arg)
+#define uccf_warn(format, arg...) \
+ uccf_printk(KERN_WARNING , format , ## arg)
+
+#ifdef UCCF_VERBOSE_DEBUG
+#define uccf_vdbg uccf_dbg
+#else
+#define uccf_vdbg(fmt, args...) do { } while (0)
+#endif /* UCCF_VERBOSE_DEBUG */
+
+void ucc_fast_dump_regs(struct ucc_fast_private * uccf)
+{
+ uccf_info("UCC%d Fast registers:", uccf->uf_info->ucc_num);
+ uccf_info("Base address: 0x%08x", (u32) uccf->uf_regs);
+
+ uccf_info("gumr : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->gumr, in_be32(&uccf->uf_regs->gumr));
+ uccf_info("upsmr : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->upsmr, in_be32(&uccf->uf_regs->upsmr));
+ uccf_info("utodr : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utodr, in_be16(&uccf->uf_regs->utodr));
+ uccf_info("udsr : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->udsr, in_be16(&uccf->uf_regs->udsr));
+ uccf_info("ucce : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->ucce, in_be32(&uccf->uf_regs->ucce));
+ uccf_info("uccm : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->uccm, in_be32(&uccf->uf_regs->uccm));
+ uccf_info("uccs : addr - 0x%08x, val - 0x%02x",
+ (u32) & uccf->uf_regs->uccs, uccf->uf_regs->uccs);
+ uccf_info("urfb : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->urfb, in_be32(&uccf->uf_regs->urfb));
+ uccf_info("urfs : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->urfs, in_be16(&uccf->uf_regs->urfs));
+ uccf_info("urfet : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->urfet, in_be16(&uccf->uf_regs->urfet));
+ uccf_info("urfset: addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->urfset,
+ in_be16(&uccf->uf_regs->urfset));
+ uccf_info("utfb : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->utfb, in_be32(&uccf->uf_regs->utfb));
+ uccf_info("utfs : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utfs, in_be16(&uccf->uf_regs->utfs));
+ uccf_info("utfet : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utfet, in_be16(&uccf->uf_regs->utfet));
+ uccf_info("utftt : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utftt, in_be16(&uccf->uf_regs->utftt));
+ uccf_info("utpt : addr - 0x%08x, val - 0x%04x",
+ (u32) & uccf->uf_regs->utpt, in_be16(&uccf->uf_regs->utpt));
+ uccf_info("urtry : addr - 0x%08x, val - 0x%08x",
+ (u32) & uccf->uf_regs->urtry, in_be32(&uccf->uf_regs->urtry));
+ uccf_info("guemr : addr - 0x%08x, val - 0x%02x",
+ (u32) & uccf->uf_regs->guemr, uccf->uf_regs->guemr);
+}
+
+u32 ucc_fast_get_qe_cr_subblock(int uccf_num)
+{
+ switch (uccf_num) {
+ case 0: return QE_CR_SUBBLOCK_UCCFAST1;
+ case 1: return QE_CR_SUBBLOCK_UCCFAST2;
+ case 2: return QE_CR_SUBBLOCK_UCCFAST3;
+ case 3: return QE_CR_SUBBLOCK_UCCFAST4;
+ case 4: return QE_CR_SUBBLOCK_UCCFAST5;
+ case 5: return QE_CR_SUBBLOCK_UCCFAST6;
+ case 6: return QE_CR_SUBBLOCK_UCCFAST7;
+ case 7: return QE_CR_SUBBLOCK_UCCFAST8;
+ default: return QE_CR_SUBBLOCK_INVALID;
+ }
+}
+
+void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf)
+{
+ out_be16(&uccf->uf_regs->utodr, UCC_FAST_TOD);
+}
+
+void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode)
+{
+ struct ucc_fast *uf_regs;
+ u32 gumr;
+
+ uf_regs = uccf->uf_regs;
+
+ /* Enable reception and/or transmission on this UCC. */
+ gumr = in_be32(&uf_regs->gumr);
+ if (mode & COMM_DIR_TX) {
+ gumr |= UCC_FAST_GUMR_ENT;
+ uccf->enabled_tx = 1;
+ }
+ if (mode & COMM_DIR_RX) {
+ gumr |= UCC_FAST_GUMR_ENR;
+ uccf->enabled_rx = 1;
+ }
+ out_be32(&uf_regs->gumr, gumr);
+}
+
+void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode)
+{
+ struct ucc_fast *uf_regs;
+ u32 gumr;
+
+ uf_regs = uccf->uf_regs;
+
+ /* Disable reception and/or transmission on this UCC. */
+ gumr = in_be32(&uf_regs->gumr);
+ if (mode & COMM_DIR_TX) {
+ gumr &= ~UCC_FAST_GUMR_ENT;
+ uccf->enabled_tx = 0;
+ }
+ if (mode & COMM_DIR_RX) {
+ gumr &= ~UCC_FAST_GUMR_ENR;
+ uccf->enabled_rx = 0;
+ }
+ out_be32(&uf_regs->gumr, gumr);
+}
+
+int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret)
+{
+ struct ucc_fast_private *uccf;
+ struct ucc_fast *uf_regs;
+ u32 gumr = 0;
+ int ret;
+
+ uccf_vdbg("%s: IN", __FUNCTION__);
+
+ if (!uf_info)
+ return -EINVAL;
+
+ /* check if the UCC port number is in range. */
+ if ((uf_info->ucc_num < 0) || (uf_info->ucc_num > UCC_MAX_NUM - 1)) {
+ uccf_err("ucc_fast_init: Illagal UCC number!");
+ return -EINVAL;
+ }
+
+ /* Check that 'max_rx_buf_length' is properly aligned (4). */
+ if (uf_info->max_rx_buf_length & (UCC_FAST_MRBLR_ALIGNMENT - 1)) {
+ uccf_err("ucc_fast_init: max_rx_buf_length not aligned.");
+ return -EINVAL;
+ }
+
+ /* Validate Virtual Fifo register values */
+ if (uf_info->urfs < UCC_FAST_URFS_MIN_VAL) {
+ uccf_err
+ ("ucc_fast_init: Virtual Fifo register urfs too small.");
+ return -EINVAL;
+ }
+
+ if (uf_info->urfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err
+ ("ucc_fast_init: Virtual Fifo register urfs not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->urfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err
+ ("ucc_fast_init: Virtual Fifo register urfet not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->urfset & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err
+ ("ucc_fast_init: Virtual Fifo register urfset not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->utfs & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err
+ ("ucc_fast_init: Virtual Fifo register utfs not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->utfet & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err
+ ("ucc_fast_init: Virtual Fifo register utfet not aligned.");
+ return -EINVAL;
+ }
+
+ if (uf_info->utftt & (UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT - 1)) {
+ uccf_err
+ ("ucc_fast_init: Virtual Fifo register utftt not aligned.");
+ return -EINVAL;
+ }
+
+ uccf = (struct ucc_fast_private *)
+ kmalloc(sizeof(struct ucc_fast_private), GFP_KERNEL);
+ if (!uccf) {
+ uccf_err
+ ("ucc_fast_init: No memory for UCC slow data structure!");
+ return -ENOMEM;
+ }
+ memset(uccf, 0, sizeof(struct ucc_fast_private));
+
+ /* Fill fast UCC structure */
+ uccf->uf_info = uf_info;
+ /* Set the PHY base address */
+ uccf->uf_regs =
+ (struct ucc_fast *) ioremap(uf_info->regs, sizeof(struct ucc_fast));
+ if (uccf->uf_regs == NULL) {
+ uccf_err
+ ("ucc_fast_init: No memory map for UCC slow controller!");
+ return -ENOMEM;
+ }
+
+ uccf->enabled_tx = 0;
+ uccf->enabled_rx = 0;
+ uccf->stopped_tx = 0;
+ uccf->stopped_rx = 0;
+ uf_regs = uccf->uf_regs;
+ uccf->p_ucce = (u32 *) & (uf_regs->ucce);
+ uccf->p_uccm = (u32 *) & (uf_regs->uccm);
+#ifdef STATISTICS
+ uccf->tx_frames = 0;
+ uccf->rx_frames = 0;
+ uccf->rx_discarded = 0;
+#endif /* STATISTICS */
+
+ /* Init Guemr register */
+ if ((ret = ucc_init_guemr((struct ucc_common *) (uf_regs)))) {
+ uccf_err("ucc_fast_init: Could not init the guemr register.");
+ ucc_fast_free(uccf);
+ return ret;
+ }
+
+ /* Set UCC to fast type */
+ if ((ret = ucc_set_type(uf_info->ucc_num,
+ (struct ucc_common *) (uf_regs),
+ UCC_SPEED_TYPE_FAST))) {
+ uccf_err("ucc_fast_init: Could not set type to fast.");
+ ucc_fast_free(uccf);
+ return ret;
+ }
+
+ uccf->mrblr = uf_info->max_rx_buf_length;
+
+ /* Set GUMR */
+ /* For more details see the hardware spec. */
+ /* gumr starts as zero. */
+ if (uf_info->tci)
+ gumr |= UCC_FAST_GUMR_TCI;
+ gumr |= uf_info->ttx_trx;
+ if (uf_info->cdp)
+ gumr |= UCC_FAST_GUMR_CDP;
+ if (uf_info->ctsp)
+ gumr |= UCC_FAST_GUMR_CTSP;
+ if (uf_info->cds)
+ gumr |= UCC_FAST_GUMR_CDS;
+ if (uf_info->ctss)
+ gumr |= UCC_FAST_GUMR_CTSS;
+ if (uf_info->txsy)
+ gumr |= UCC_FAST_GUMR_TXSY;
+ if (uf_info->rsyn)
+ gumr |= UCC_FAST_GUMR_RSYN;
+ gumr |= uf_info->synl;
+ if (uf_info->rtsm)
+ gumr |= UCC_FAST_GUMR_RTSM;
+ gumr |= uf_info->renc;
+ if (uf_info->revd)
+ gumr |= UCC_FAST_GUMR_REVD;
+ gumr |= uf_info->tenc;
+ gumr |= uf_info->tcrc;
+ gumr |= uf_info->mode;
+ out_be32(&uf_regs->gumr, gumr);
+
+ /* 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)) {
+ uccf_err
+ ("ucc_fast_init: Can not allocate MURAM memory for "
+ "struct ucc_fastx_virtual_fifo_base_offset.");
+ uccf->ucc_fast_tx_virtual_fifo_base_offset = 0;
+ ucc_fast_free(uccf);
+ return -ENOMEM;
+ }
+
+ /* Allocate memory for Rx Virtual Fifo */
+ uccf->ucc_fast_rx_virtual_fifo_base_offset =
+ qe_muram_alloc(uf_info->urfs +
+ (u32)
+ 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)) {
+ uccf_err
+ ("ucc_fast_init: Can not allocate MURAM memory for "
+ "ucc_fast_rx_virtual_fifo_base_offset.");
+ uccf->ucc_fast_rx_virtual_fifo_base_offset = 0;
+ ucc_fast_free(uccf);
+ return -ENOMEM;
+ }
+
+ /* Set Virtual Fifo registers */
+ out_be16(&uf_regs->urfs, uf_info->urfs);
+ out_be16(&uf_regs->urfet, uf_info->urfet);
+ out_be16(&uf_regs->urfset, uf_info->urfset);
+ out_be16(&uf_regs->utfs, uf_info->utfs);
+ out_be16(&uf_regs->utfet, uf_info->utfet);
+ out_be16(&uf_regs->utftt, uf_info->utftt);
+ /* utfb, urfb are offsets from MURAM base */
+ out_be32(&uf_regs->utfb, uccf->ucc_fast_tx_virtual_fifo_base_offset);
+ out_be32(&uf_regs->urfb, uccf->ucc_fast_rx_virtual_fifo_base_offset);
+
+ /* Mux clocking */
+ /* Grant Support */
+ ucc_set_qe_mux_grant(uf_info->ucc_num, uf_info->grant_support);
+ /* Breakpoint Support */
+ ucc_set_qe_mux_bkpt(uf_info->ucc_num, uf_info->brkpt_support);
+ /* Set Tsa or NMSI mode. */
+ ucc_set_qe_mux_tsa(uf_info->ucc_num, uf_info->tsa);
+ /* If NMSI (not Tsa), set Tx and Rx clock. */
+ if (!uf_info->tsa) {
+ /* Rx clock routing */
+ if (uf_info->rx_clock != QE_CLK_NONE) {
+ if (ucc_set_qe_mux_rxtx
+ (uf_info->ucc_num, uf_info->rx_clock,
+ COMM_DIR_RX)) {
+ uccf_err
+ ("ucc_fast_init: Illegal value for parameter 'RxClock'.");
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+ }
+ /* Tx clock routing */
+ if (uf_info->tx_clock != QE_CLK_NONE) {
+ if (ucc_set_qe_mux_rxtx
+ (uf_info->ucc_num, uf_info->tx_clock,
+ COMM_DIR_TX)) {
+ uccf_err
+ ("ucc_fast_init: Illegal value for parameter 'TxClock'.");
+ ucc_fast_free(uccf);
+ return -EINVAL;
+ }
+ }
+ }
+
+ /* Set interrupt mask register at UCC level. */
+ out_be32(&uf_regs->uccm, uf_info->uccm_mask);
+
+ /* First, clear anything pending at UCC level,
+ * otherwise, old garbage may come through
+ * as soon as the dam is opened
+ * Writing '1' clears
+ */
+ out_be32(&uf_regs->ucce, 0xffffffff);
+
+ *uccf_ret = uccf;
+ return 0;
+}
+
+void ucc_fast_free(struct ucc_fast_private * uccf)
+{
+ if (!uccf)
+ return;
+
+ if (uccf->ucc_fast_tx_virtual_fifo_base_offset)
+ qe_muram_free(uccf->ucc_fast_tx_virtual_fifo_base_offset);
+
+ if (uccf->ucc_fast_rx_virtual_fifo_base_offset)
+ qe_muram_free(uccf->ucc_fast_rx_virtual_fifo_base_offset);
+
+ kfree(uccf);
+}
diff --git a/arch/powerpc/sysdev/qe_lib/ucc_slow.c b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
new file mode 100644
index 000000000000..1fb88ef7cf06
--- /dev/null
+++ b/arch/powerpc/sysdev/qe_lib/ucc_slow.c
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * QE UCC Slow API Set - UCC Slow specific routines implementations.
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include <asm/ucc.h>
+#include <asm/ucc_slow.h>
+
+#define uccs_printk(level, format, arg...) \
+ printk(level format "\n", ## arg)
+
+#define uccs_dbg(format, arg...) \
+ uccs_printk(KERN_DEBUG , format , ## arg)
+#define uccs_err(format, arg...) \
+ uccs_printk(KERN_ERR , format , ## arg)
+#define uccs_info(format, arg...) \
+ uccs_printk(KERN_INFO , format , ## arg)
+#define uccs_warn(format, arg...) \
+ uccs_printk(KERN_WARNING , format , ## arg)
+
+#ifdef UCCS_VERBOSE_DEBUG
+#define uccs_vdbg uccs_dbg
+#else
+#define uccs_vdbg(fmt, args...) do { } while (0)
+#endif /* UCCS_VERBOSE_DEBUG */
+
+u32 ucc_slow_get_qe_cr_subblock(int uccs_num)
+{
+ switch (uccs_num) {
+ case 0: return QE_CR_SUBBLOCK_UCCSLOW1;
+ case 1: return QE_CR_SUBBLOCK_UCCSLOW2;
+ case 2: return QE_CR_SUBBLOCK_UCCSLOW3;
+ case 3: return QE_CR_SUBBLOCK_UCCSLOW4;
+ case 4: return QE_CR_SUBBLOCK_UCCSLOW5;
+ case 5: return QE_CR_SUBBLOCK_UCCSLOW6;
+ case 6: return QE_CR_SUBBLOCK_UCCSLOW7;
+ case 7: return QE_CR_SUBBLOCK_UCCSLOW8;
+ default: return QE_CR_SUBBLOCK_INVALID;
+ }
+}
+
+void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs)
+{
+ out_be16(&uccs->us_regs->utodr, UCC_SLOW_TOD);
+}
+
+void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs)
+{
+ struct ucc_slow_info *us_info = uccs->us_info;
+ u32 id;
+
+ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+ qe_issue_cmd(QE_GRACEFUL_STOP_TX, id,
+ QE_CR_PROTOCOL_UNSPECIFIED, 0);
+}
+
+void ucc_slow_stop_tx(struct ucc_slow_private * uccs)
+{
+ struct ucc_slow_info *us_info = uccs->us_info;
+ u32 id;
+
+ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+ qe_issue_cmd(QE_STOP_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
+}
+
+void ucc_slow_restart_tx(struct ucc_slow_private * uccs)
+{
+ struct ucc_slow_info *us_info = uccs->us_info;
+ u32 id;
+
+ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+ qe_issue_cmd(QE_RESTART_TX, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
+}
+
+void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode)
+{
+ struct ucc_slow *us_regs;
+ u32 gumr_l;
+
+ us_regs = uccs->us_regs;
+
+ /* Enable reception and/or transmission on this UCC. */
+ gumr_l = in_be32(&us_regs->gumr_l);
+ if (mode & COMM_DIR_TX) {
+ gumr_l |= UCC_SLOW_GUMR_L_ENT;
+ uccs->enabled_tx = 1;
+ }
+ if (mode & COMM_DIR_RX) {
+ gumr_l |= UCC_SLOW_GUMR_L_ENR;
+ uccs->enabled_rx = 1;
+ }
+ out_be32(&us_regs->gumr_l, gumr_l);
+}
+
+void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode)
+{
+ struct ucc_slow *us_regs;
+ u32 gumr_l;
+
+ us_regs = uccs->us_regs;
+
+ /* Disable reception and/or transmission on this UCC. */
+ gumr_l = in_be32(&us_regs->gumr_l);
+ if (mode & COMM_DIR_TX) {
+ gumr_l &= ~UCC_SLOW_GUMR_L_ENT;
+ uccs->enabled_tx = 0;
+ }
+ if (mode & COMM_DIR_RX) {
+ gumr_l &= ~UCC_SLOW_GUMR_L_ENR;
+ uccs->enabled_rx = 0;
+ }
+ out_be32(&us_regs->gumr_l, gumr_l);
+}
+
+int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret)
+{
+ u32 i;
+ struct ucc_slow *us_regs;
+ u32 gumr;
+ u8 function_code = 0;
+ u8 *bd;
+ struct ucc_slow_private *uccs;
+ u32 id;
+ u32 command;
+ int ret;
+
+ uccs_vdbg("%s: IN", __FUNCTION__);
+
+ if (!us_info)
+ return -EINVAL;
+
+ /* check if the UCC port number is in range. */
+ if ((us_info->ucc_num < 0) || (us_info->ucc_num > UCC_MAX_NUM - 1)) {
+ uccs_err("ucc_slow_init: Illagal UCC number!");
+ return -EINVAL;
+ }
+
+ /*
+ * Set mrblr
+ * Check that 'max_rx_buf_length' is properly aligned (4), unless
+ * rfw is 1, meaning that QE accepts one byte at a time, unlike normal
+ * case when QE accepts 32 bits at a time.
+ */
+ if ((!us_info->rfw) &&
+ (us_info->max_rx_buf_length & (UCC_SLOW_MRBLR_ALIGNMENT - 1))) {
+ uccs_err("max_rx_buf_length not aligned.");
+ return -EINVAL;
+ }
+
+ uccs = (struct ucc_slow_private *)
+ kmalloc(sizeof(struct ucc_slow_private), GFP_KERNEL);
+ if (!uccs) {
+ uccs_err
+ ("ucc_slow_init: No memory for UCC slow data structure!");
+ return -ENOMEM;
+ }
+ memset(uccs, 0, sizeof(struct ucc_slow_private));
+
+ /* Fill slow UCC structure */
+ uccs->us_info = us_info;
+ uccs->saved_uccm = 0;
+ uccs->p_rx_frame = 0;
+ uccs->us_regs = us_info->us_regs;
+ us_regs = uccs->us_regs;
+ uccs->p_ucce = (u16 *) & (us_regs->ucce);
+ uccs->p_uccm = (u16 *) & (us_regs->uccm);
+#ifdef STATISTICS
+ uccs->rx_frames = 0;
+ uccs->tx_frames = 0;
+ uccs->rx_discarded = 0;
+#endif /* STATISTICS */
+
+ /* 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)) {
+ uccs_err
+ ("ucc_slow_init: Can not allocate MURAM memory "
+ "for Slow UCC.");
+ ucc_slow_free(uccs);
+ return -ENOMEM;
+ }
+ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+ qe_issue_cmd(QE_ASSIGN_PAGE_TO_DEVICE, id, QE_CR_PROTOCOL_UNSPECIFIED,
+ (u32) uccs->us_pram_offset);
+
+ uccs->us_pram = qe_muram_addr(uccs->us_pram_offset);
+
+ /* Init Guemr register */
+ if ((ret = ucc_init_guemr((struct ucc_common *) (us_info->us_regs)))) {
+ uccs_err("ucc_slow_init: Could not init the guemr register.");
+ ucc_slow_free(uccs);
+ return ret;
+ }
+
+ /* Set UCC to slow type */
+ if ((ret = ucc_set_type(us_info->ucc_num,
+ (struct ucc_common *) (us_info->us_regs),
+ UCC_SPEED_TYPE_SLOW))) {
+ uccs_err("ucc_slow_init: Could not init the guemr register.");
+ ucc_slow_free(uccs);
+ return ret;
+ }
+
+ out_be16(&uccs->us_pram->mrblr, us_info->max_rx_buf_length);
+
+ INIT_LIST_HEAD(&uccs->confQ);
+
+ /* Allocate BDs. */
+ 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)) {
+ uccs_err("ucc_slow_init: No memory for Rx BD's.");
+ uccs->rx_base_offset = 0;
+ ucc_slow_free(uccs);
+ return -ENOMEM;
+ }
+
+ 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)) {
+ uccs_err("ucc_slow_init: No memory for Tx BD's.");
+ uccs->tx_base_offset = 0;
+ ucc_slow_free(uccs);
+ return -ENOMEM;
+ }
+
+ /* Init Tx bds */
+ bd = uccs->confBd = uccs->tx_bd = qe_muram_addr(uccs->tx_base_offset);
+ for (i = 0; i < us_info->tx_bd_ring_len; i++) {
+ /* clear bd buffer */
+ out_be32(&(((struct qe_bd *)bd)->buf), 0);
+ /* set bd status and length */
+ out_be32((u32*)bd, 0);
+ bd += sizeof(struct qe_bd);
+ }
+ bd -= sizeof(struct qe_bd);
+ /* set bd status and length */
+ out_be32((u32*)bd, T_W); /* for last BD set Wrap bit */
+
+ /* Init Rx bds */
+ bd = uccs->rx_bd = qe_muram_addr(uccs->rx_base_offset);
+ for (i = 0; i < us_info->rx_bd_ring_len; i++) {
+ /* set bd status and length */
+ out_be32((u32*)bd, 0);
+ /* clear bd buffer */
+ out_be32(&(((struct qe_bd *)bd)->buf), 0);
+ bd += sizeof(struct qe_bd);
+ }
+ bd -= sizeof(struct qe_bd);
+ /* set bd status and length */
+ out_be32((u32*)bd, R_W); /* for last BD set Wrap bit */
+
+ /* Set GUMR (For more details see the hardware spec.). */
+ /* gumr_h */
+ gumr = 0;
+ gumr |= us_info->tcrc;
+ if (us_info->cdp)
+ gumr |= UCC_SLOW_GUMR_H_CDP;
+ if (us_info->ctsp)
+ gumr |= UCC_SLOW_GUMR_H_CTSP;
+ if (us_info->cds)
+ gumr |= UCC_SLOW_GUMR_H_CDS;
+ if (us_info->ctss)
+ gumr |= UCC_SLOW_GUMR_H_CTSS;
+ if (us_info->tfl)
+ gumr |= UCC_SLOW_GUMR_H_TFL;
+ if (us_info->rfw)
+ gumr |= UCC_SLOW_GUMR_H_RFW;
+ if (us_info->txsy)
+ gumr |= UCC_SLOW_GUMR_H_TXSY;
+ if (us_info->rtsm)
+ gumr |= UCC_SLOW_GUMR_H_RTSM;
+ out_be32(&us_regs->gumr_h, gumr);
+
+ /* gumr_l */
+ gumr = 0;
+ if (us_info->tci)
+ gumr |= UCC_SLOW_GUMR_L_TCI;
+ if (us_info->rinv)
+ gumr |= UCC_SLOW_GUMR_L_RINV;
+ if (us_info->tinv)
+ gumr |= UCC_SLOW_GUMR_L_TINV;
+ if (us_info->tend)
+ gumr |= UCC_SLOW_GUMR_L_TEND;
+ gumr |= us_info->tdcr;
+ gumr |= us_info->rdcr;
+ gumr |= us_info->tenc;
+ gumr |= us_info->renc;
+ gumr |= us_info->diag;
+ gumr |= us_info->mode;
+ out_be32(&us_regs->gumr_l, gumr);
+
+ /* Function code registers */
+ /* function_code has initial value 0 */
+
+ /* if the data is in cachable memory, the 'global' */
+ /* in the function code should be set. */
+ function_code |= us_info->data_mem_part;
+ function_code |= QE_BMR_BYTE_ORDER_BO_MOT; /* Required for QE */
+ uccs->us_pram->tfcr = function_code;
+ uccs->us_pram->rfcr = function_code;
+
+ /* rbase, tbase are offsets from MURAM base */
+ out_be16(&uccs->us_pram->rbase, uccs->us_pram_offset);
+ out_be16(&uccs->us_pram->tbase, uccs->us_pram_offset);
+
+ /* Mux clocking */
+ /* Grant Support */
+ ucc_set_qe_mux_grant(us_info->ucc_num, us_info->grant_support);
+ /* Breakpoint Support */
+ ucc_set_qe_mux_bkpt(us_info->ucc_num, us_info->brkpt_support);
+ /* Set Tsa or NMSI mode. */
+ ucc_set_qe_mux_tsa(us_info->ucc_num, us_info->tsa);
+ /* If NMSI (not Tsa), set Tx and Rx clock. */
+ if (!us_info->tsa) {
+ /* Rx clock routing */
+ if (ucc_set_qe_mux_rxtx
+ (us_info->ucc_num, us_info->rx_clock, COMM_DIR_RX)) {
+ uccs_err
+ ("ucc_slow_init: Illegal value for parameter"
+ " 'RxClock'.");
+ ucc_slow_free(uccs);
+ return -EINVAL;
+ }
+ /* Tx clock routing */
+ if (ucc_set_qe_mux_rxtx(us_info->ucc_num,
+ us_info->tx_clock, COMM_DIR_TX)) {
+ uccs_err
+ ("ucc_slow_init: Illegal value for parameter "
+ "'TxClock'.");
+ ucc_slow_free(uccs);
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * INTERRUPTS
+ */
+ /* Set interrupt mask register at UCC level. */
+ out_be16(&us_regs->uccm, us_info->uccm_mask);
+
+ /* First, clear anything pending at UCC level, */
+ /* otherwise, old garbage may come through */
+ /* as soon as the dam is opened. */
+
+ /* Writing '1' clears */
+ out_be16(&us_regs->ucce, 0xffff);
+
+ /* Issue QE Init command */
+ if (us_info->init_tx && us_info->init_rx)
+ command = QE_INIT_TX_RX;
+ else if (us_info->init_tx)
+ command = QE_INIT_TX;
+ else
+ command = QE_INIT_RX; /* We know at least one is TRUE */
+ id = ucc_slow_get_qe_cr_subblock(us_info->ucc_num);
+ qe_issue_cmd(command, id, QE_CR_PROTOCOL_UNSPECIFIED, 0);
+
+ *uccs_ret = uccs;
+ return 0;
+}
+
+void ucc_slow_free(struct ucc_slow_private * uccs)
+{
+ if (!uccs)
+ return;
+
+ if (uccs->rx_base_offset)
+ qe_muram_free(uccs->rx_base_offset);
+
+ if (uccs->tx_base_offset)
+ qe_muram_free(uccs->tx_base_offset);
+
+ if (uccs->us_pram) {
+ qe_muram_free(uccs->us_pram_offset);
+ uccs->us_pram = NULL;
+ }
+
+ kfree(uccs);
+}
diff --git a/arch/powerpc/sysdev/tsi108_dev.c b/arch/powerpc/sysdev/tsi108_dev.c
index f3038461d4c0..11de090eb901 100644
--- a/arch/powerpc/sysdev/tsi108_dev.c
+++ b/arch/powerpc/sysdev/tsi108_dev.c
@@ -9,7 +9,6 @@
* option) any later version.
*/
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c
index c28f69bef8e2..322f86e93de5 100644
--- a/arch/powerpc/sysdev/tsi108_pci.c
+++ b/arch/powerpc/sysdev/tsi108_pci.c
@@ -405,11 +405,10 @@ void __init tsi108_pci_int_init(void)
init_pci_source();
}
-void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+void tsi108_irq_cascade(unsigned int irq, struct irq_desc *desc)
{
unsigned int cascade_irq = get_pci_source();
if (cascade_irq != NO_IRQ)
- generic_handle_irq(cascade_irq, regs);
+ generic_handle_irq(cascade_irq);
desc->chip->eoi(irq);
}
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index 8adad1444a51..f56ffef4defa 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -2,6 +2,8 @@
* Routines providing a simple monitor for use on the PowerMac.
*
* Copyright (C) 1996-2005 Paul Mackerras.
+ * Copyright (C) 2001 PPC64 Team, IBM Corp
+ * Copyrignt (C) 2006 Michael Ellerman, IBM Corp
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -19,6 +21,7 @@
#include <linux/module.h>
#include <linux/sysrq.h>
#include <linux/interrupt.h>
+#include <linux/irq.h>
#include <asm/ptrace.h>
#include <asm/string.h>
@@ -33,6 +36,7 @@
#include <asm/rtas.h>
#include <asm/sstep.h>
#include <asm/bug.h>
+#include <asm/irq_regs.h>
#ifdef CONFIG_PPC64
#include <asm/hvcall.h>
@@ -503,7 +507,7 @@ static int xmon_core(struct pt_regs *regs, int fromipi)
mtmsr(msr); /* restore interrupt enable */
- return cmd != 'X';
+ return cmd != 'X' && cmd != EOF;
}
int xmon(struct pt_regs *excp)
@@ -518,13 +522,12 @@ int xmon(struct pt_regs *excp)
}
EXPORT_SYMBOL(xmon);
-irqreturn_t
-xmon_irq(int irq, void *d, struct pt_regs *regs)
+irqreturn_t xmon_irq(int irq, void *d)
{
unsigned long flags;
local_irq_save(flags);
printf("Keyboard interrupt\n");
- xmon(regs);
+ xmon(get_irq_regs());
local_irq_restore(flags);
return IRQ_HANDLED;
}
@@ -2575,12 +2578,11 @@ void xmon_init(int enable)
}
#ifdef CONFIG_MAGIC_SYSRQ
-static void sysrq_handle_xmon(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_xmon(int key, struct tty_struct *tty)
{
/* ensure xmon is enabled */
xmon_init(1);
- debugger(pt_regs);
+ debugger(get_irq_regs());
}
static struct sysrq_key_op sysrq_xmon_op =
@@ -2597,3 +2599,34 @@ static int __init setup_xmon_sysrq(void)
}
__initcall(setup_xmon_sysrq);
#endif /* CONFIG_MAGIC_SYSRQ */
+
+int __initdata xmon_early, xmon_off;
+
+static int __init early_parse_xmon(char *p)
+{
+ if (!p || strncmp(p, "early", 5) == 0) {
+ /* just "xmon" is equivalent to "xmon=early" */
+ xmon_init(1);
+ xmon_early = 1;
+ } else if (strncmp(p, "on", 2) == 0)
+ xmon_init(1);
+ else if (strncmp(p, "off", 3) == 0)
+ xmon_off = 1;
+ else if (strncmp(p, "nobt", 4) == 0)
+ xmon_no_auto_backtrace = 1;
+ else
+ return 1;
+
+ return 0;
+}
+early_param("xmon", early_parse_xmon);
+
+void __init xmon_setup(void)
+{
+#ifdef CONFIG_XMON_DEFAULT
+ if (!xmon_off)
+ xmon_init(1);
+#endif
+ if (xmon_early)
+ debugger(NULL);
+}
diff --git a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c
index b81a367dc278..e35483961b90 100644
--- a/arch/ppc/4xx_io/serial_sicc.c
+++ b/arch/ppc/4xx_io/serial_sicc.c
@@ -414,7 +414,7 @@ static void siccuart_event(struct SICC_info *info, int event)
}
static void
-siccuart_rx_chars(struct SICC_info *info, struct pt_regs *regs)
+siccuart_rx_chars(struct SICC_info *info)
{
struct tty_struct *tty = info->tty;
unsigned int status, ch, rsr, flg, ignored = 0;
@@ -441,7 +441,7 @@ siccuart_rx_chars(struct SICC_info *info, struct pt_regs *regs)
#ifdef SUPPORT_SYSRQ
if (info->sysrq) {
if (ch && time_before(jiffies, info->sysrq)) {
- handle_sysrq(ch, regs, NULL);
+ handle_sysrq(ch, NULL);
info->sysrq = 0;
goto ignore_char;
}
@@ -553,15 +553,15 @@ static void siccuart_tx_chars(struct SICC_info *info)
}
-static irqreturn_t siccuart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t siccuart_int_rx(int irq, void *dev_id)
{
struct SICC_info *info = dev_id;
- siccuart_rx_chars(info, regs);
+ siccuart_rx_chars(info)
return IRQ_HANDLED;
}
-static irqreturn_t siccuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t siccuart_int_tx(int irq, void *dev_id)
{
struct SICC_info *info = dev_id;
siccuart_tx_chars(info);
@@ -1720,7 +1720,7 @@ static int siccuart_open(struct tty_struct *tty, struct file *filp)
return 0;
}
-static struct tty_operations sicc_ops = {
+static const struct tty_operations sicc_ops = {
.open = siccuart_open,
.close = siccuart_close,
.write = siccuart_write,
diff --git a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c
index ac6d55fe2235..a6056c29cf00 100644
--- a/arch/ppc/8260_io/enet.c
+++ b/arch/ppc/8260_io/enet.c
@@ -122,7 +122,7 @@ struct scc_enet_private {
static int scc_enet_open(struct net_device *dev);
static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int scc_enet_rx(struct net_device *dev);
-static irqreturn_t scc_enet_interrupt(int irq, void *dev_id, struct pt_regs *);
+static irqreturn_t scc_enet_interrupt(int irq, void *dev_id);
static int scc_enet_close(struct net_device *dev);
static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -273,7 +273,7 @@ scc_enet_timeout(struct net_device *dev)
* This is called from the CPM handler, not the MPC core interrupt.
*/
static irqreturn_t
-scc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+scc_enet_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
volatile struct scc_enet_private *cep;
diff --git a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c
index e347fe88316d..2e1943e27819 100644
--- a/arch/ppc/8260_io/fcc_enet.c
+++ b/arch/ppc/8260_io/fcc_enet.c
@@ -140,7 +140,7 @@ typedef struct {
static int fcc_enet_open(struct net_device *dev);
static int fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int fcc_enet_rx(struct net_device *dev);
-static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id, struct pt_regs *);
+static irqreturn_t fcc_enet_interrupt(int irq, void *dev_id);
static int fcc_enet_close(struct net_device *dev);
static struct net_device_stats *fcc_enet_get_stats(struct net_device *dev);
/* static void set_multicast_list(struct net_device *dev); */
@@ -524,7 +524,7 @@ fcc_enet_timeout(struct net_device *dev)
/* The interrupt handler. */
static irqreturn_t
-fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+fcc_enet_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
volatile struct fcc_enet_private *cep;
@@ -1563,7 +1563,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
#ifdef PHY_INTERRUPT
/* This interrupt occurs when the PHY detects a link change. */
static irqreturn_t
-mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+mii_link_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
struct fcc_enet_private *fep = dev->priv;
diff --git a/arch/ppc/8xx_io/commproc.c b/arch/ppc/8xx_io/commproc.c
index 9b3ace26280c..3b23bcb35b7a 100644
--- a/arch/ppc/8xx_io/commproc.c
+++ b/arch/ppc/8xx_io/commproc.c
@@ -47,12 +47,12 @@ cpm8xx_t *cpmp; /* Pointer to comm processor space */
/* CPM interrupt vector functions.
*/
struct cpm_action {
- void (*handler)(void *, struct pt_regs * regs);
+ void (*handler)(void *);
void *dev_id;
};
static struct cpm_action cpm_vecs[CPMVEC_NR];
-static irqreturn_t cpm_interrupt(int irq, void * dev, struct pt_regs * regs);
-static irqreturn_t cpm_error_interrupt(int irq, void *dev, struct pt_regs * regs);
+static irqreturn_t cpm_interrupt(int irq, void * dev);
+static irqreturn_t cpm_error_interrupt(int irq, void *dev);
static void alloc_host_memory(void);
/* Define a table of names to identify CPM interrupt handlers in
* /proc/interrupts.
@@ -205,7 +205,7 @@ cpm_interrupt_init(void)
* Get the CPM interrupt vector.
*/
int
-cpm_get_irq(struct pt_regs *regs)
+cpm_get_irq(void)
{
int cpm_vec;
@@ -222,7 +222,7 @@ cpm_get_irq(struct pt_regs *regs)
/* CPM interrupt controller cascade interrupt.
*/
static irqreturn_t
-cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
+cpm_interrupt(int irq, void * dev)
{
/* This interrupt handler never actually gets called. It is
* installed only to unmask the CPM cascade interrupt in the SIU
@@ -237,7 +237,7 @@ cpm_interrupt(int irq, void * dev, struct pt_regs * regs)
* tests in the interrupt handler.
*/
static irqreturn_t
-cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
+cpm_error_interrupt(int irq, void *dev)
{
return IRQ_HANDLED;
}
@@ -246,11 +246,11 @@ cpm_error_interrupt(int irq, void *dev, struct pt_regs *regs)
* request_irq() to the handler prototype required by cpm_install_handler().
*/
static irqreturn_t
-cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
+cpm_handler_helper(int irq, void *dev_id)
{
int cpm_vec = irq - CPM_IRQ_OFFSET;
- (*cpm_vecs[cpm_vec].handler)(dev_id, regs);
+ (*cpm_vecs[cpm_vec].handler)(dev_id);
return IRQ_HANDLED;
}
@@ -267,8 +267,7 @@ cpm_handler_helper(int irq, void *dev_id, struct pt_regs *regs)
* request_irq() or cpm_install_handler().
*/
void
-cpm_install_handler(int cpm_vec, void (*handler)(void *, struct pt_regs *regs),
- void *dev_id)
+cpm_install_handler(int cpm_vec, void (*handler)(void *), void *dev_id)
{
int err;
diff --git a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
index f5f300fc213d..959d31c26cbb 100644
--- a/arch/ppc/8xx_io/cs4218_tdm.c
+++ b/arch/ppc/8xx_io/cs4218_tdm.c
@@ -331,7 +331,7 @@ static int CS_SetFormat(int format);
static int CS_SetVolume(int volume);
static void cs4218_tdm_tx_intr(void *devid);
static void cs4218_tdm_rx_intr(void *devid);
-static void cs4218_intr(void *devid, struct pt_regs *regs);
+static void cs4218_intr(void *devid);
static int cs_get_volume(uint reg);
static int cs_volume_setter(int volume, int mute);
static int cs_get_gain(uint reg);
@@ -2646,7 +2646,7 @@ int __init tdm8xx_sound_init(void)
* full duplex operation.
*/
static void
-cs4218_intr(void *dev_id, struct pt_regs *regs)
+cs4218_intr(void *dev_id)
{
volatile smc_t *sp;
volatile cpm8xx_t *cp;
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index a695375c3e4c..b23c45bc151a 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -149,7 +149,7 @@ struct scc_enet_private {
static int scc_enet_open(struct net_device *dev);
static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int scc_enet_rx(struct net_device *dev);
-static void scc_enet_interrupt(void *dev_id, struct pt_regs *regs);
+static void scc_enet_interrupt(void *dev_id);
static int scc_enet_close(struct net_device *dev);
static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -305,7 +305,7 @@ scc_enet_timeout(struct net_device *dev)
* This is called from the CPM handler, not the MPC core interrupt.
*/
static void
-scc_enet_interrupt(void *dev_id, struct pt_regs *regs)
+scc_enet_interrupt(void *dev_id)
{
struct net_device *dev = dev_id;
volatile struct scc_enet_private *cep;
diff --git a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c
index 8b6295bbb564..2f9fa9e3d331 100644
--- a/arch/ppc/8xx_io/fec.c
+++ b/arch/ppc/8xx_io/fec.c
@@ -198,8 +198,7 @@ static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
#ifdef CONFIG_USE_MDIO
static void fec_enet_mii(struct net_device *dev);
#endif /* CONFIG_USE_MDIO */
-static irqreturn_t fec_enet_interrupt(int irq, void * dev_id,
- struct pt_regs * regs);
+static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
#ifdef CONFIG_FEC_PACKETHOOK
static void fec_enet_tx(struct net_device *dev, __u32 regval);
static void fec_enet_rx(struct net_device *dev, __u32 regval);
@@ -472,7 +471,7 @@ fec_timeout(struct net_device *dev)
* This is called from the MPC core interrupt.
*/
static irqreturn_t
-fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+fec_enet_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
volatile fec_t *fecp;
@@ -1408,7 +1407,7 @@ static
#ifdef CONFIG_RPXCLASSIC
void mii_link_interrupt(void *dev_id)
#else
-irqreturn_t mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+irqreturn_t mii_link_interrupt(int irq, void * dev_id)
#endif
{
#ifdef CONFIG_USE_MDIO
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 8fa10cf661a8..077711e63104 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -953,6 +953,9 @@ config NR_CPUS
config HIGHMEM
bool "High memory support"
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
source kernel/Kconfig.hz
source kernel/Kconfig.preempt
source "mm/Kconfig"
@@ -1342,7 +1345,7 @@ config CONSISTENT_START_BOOL
depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
help
This option allows you to set the base virtual address
- of the the consistent memory pool. This pool of virtual
+ of the consistent memory pool. This pool of virtual
memory is used to make consistent memory allocations.
config CONSISTENT_START
@@ -1353,7 +1356,7 @@ config CONSISTENT_SIZE_BOOL
bool "Set custom consistent memory pool size"
depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE
help
- This option allows you to set the size of the the
+ This option allows you to set the size of the
consistent memory pool. This pool of virtual memory
is used to make consistent memory allocations.
diff --git a/arch/ppc/amiga/time.c b/arch/ppc/amiga/time.c
index 0073527a7036..8c880c0ca380 100644
--- a/arch/ppc/amiga/time.c
+++ b/arch/ppc/amiga/time.c
@@ -1,4 +1,3 @@
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
diff --git a/arch/ppc/boot/include/mpsc_defs.h b/arch/ppc/boot/include/mpsc_defs.h
index 2ce7bbba7277..9f37e1355b17 100644
--- a/arch/ppc/boot/include/mpsc_defs.h
+++ b/arch/ppc/boot/include/mpsc_defs.h
@@ -1,5 +1,5 @@
/*
- * drivers/serial/mpsc/mpsc_defs.h
+ * arch/ppc/boot/include/mpsc_defs.h
*
* Register definitions for the Marvell Multi-Protocol Serial Controller (MPSC),
* Serial DMA Controller (SDMA), and Baud Rate Generator (BRG).
diff --git a/arch/ppc/boot/utils/mkbugboot.c b/arch/ppc/boot/utils/mkbugboot.c
index 29115e01f60a..1640c4199ca6 100644
--- a/arch/ppc/boot/utils/mkbugboot.c
+++ b/arch/ppc/boot/utils/mkbugboot.c
@@ -19,36 +19,13 @@
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
+#include <netinet/in.h>
#ifdef __sun__
#include <inttypes.h>
#else
#include <stdint.h>
#endif
-#ifdef __i386__
-#define cpu_to_be32(x) le32_to_cpu(x)
-#define cpu_to_be16(x) le16_to_cpu(x)
-#else
-#define cpu_to_be32(x) (x)
-#define cpu_to_be16(x) (x)
-#endif
-
-#define cpu_to_le32(x) le32_to_cpu((x))
-unsigned long le32_to_cpu(unsigned long x)
-{
- return (((x & 0x000000ffU) << 24) |
- ((x & 0x0000ff00U) << 8) |
- ((x & 0x00ff0000U) >> 8) |
- ((x & 0xff000000U) >> 24));
-}
-
-#define cpu_to_le16(x) le16_to_cpu((x))
-unsigned short le16_to_cpu(unsigned short x)
-{
- return (((x & 0x00ff) << 8) |
- ((x & 0xff00) >> 8));
-}
-
/* size of read buffer */
#define SIZE 0x1000
@@ -62,124 +39,109 @@ typedef struct bug_boot_header {
#define HEADER_SIZE sizeof(bug_boot_header_t)
-uint32_t copy_image(int32_t in_fd, int32_t out_fd)
+void update_checksum(void *buf, size_t size, uint16_t *sum)
{
- uint8_t buf[SIZE];
- int n;
- uint32_t image_size = 0;
- uint8_t zero = 0;
-
- lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET);
-
- /* Copy an image while recording its size */
- while ( (n = read(in_fd, buf, SIZE)) > 0 )
- {
- image_size = image_size + n;
- write(out_fd, buf, n);
- }
-
- /* BUG romboot requires that our size is divisible by 2 */
- /* align image to 2 byte boundary */
- if (image_size % 2)
- {
- image_size++;
- write(out_fd, &zero, 1);
- }
-
- return image_size;
+ uint32_t csum = *sum;
+
+ while (size) {
+ csum += *(uint16_t *)buf;
+ if (csum > 0xffff)
+ csum -= 0xffff;
+ buf = (uint16_t *)buf + 1;
+ size -= 2;
+ }
+ *sum = csum;
}
-void write_bugboot_header(int32_t out_fd, uint32_t boot_size)
+uint32_t copy_image(int in_fd, int out_fd, uint16_t *sum)
{
- uint8_t header_block[HEADER_SIZE];
- bug_boot_header_t *bbh = (bug_boot_header_t *)&header_block[0];
-
- memset(header_block, 0, HEADER_SIZE);
-
- /* Fill in the PPCBUG ROM boot header */
- strncpy(bbh->magic_word, "BOOT", 4); /* PPCBUG magic word */
- bbh->entry_offset = cpu_to_be32(HEADER_SIZE); /* Entry address */
- bbh->routine_length= cpu_to_be32(HEADER_SIZE+boot_size+2); /* Routine length */
- strncpy(bbh->routine_name, "LINUXROM", 8); /* Routine name */
-
- /* Output the header and bootloader to the file */
- write(out_fd, header_block, HEADER_SIZE);
+ uint8_t buf[SIZE];
+ int offset = 0;
+ int n;
+ uint32_t image_size = 0;
+
+ lseek(in_fd, ELF_HEADER_SIZE, SEEK_SET);
+
+ /* Copy an image while recording its size */
+ while ( (n = read(in_fd, buf + offset, SIZE - offset)) > 0 ) {
+ n += offset;
+ offset = n & 1;
+ n -= offset;
+ image_size = image_size + n;
+ /* who's going to deal with short writes? */
+ write(out_fd, buf, n);
+ update_checksum(buf, n, sum);
+ if (offset)
+ buf[0] = buf[n];
+ }
+
+ /* BUG romboot requires that our size is divisible by 2 */
+ /* align image to 2 byte boundary */
+ if (offset) {
+ image_size += 2;
+ buf[1] = '\0';
+ write(out_fd, buf, 2);
+ update_checksum(buf, 2, sum);
+ }
+ return image_size;
}
-uint16_t calc_checksum(int32_t bug_fd)
+void write_bugboot_header(int out_fd, uint32_t boot_size, uint16_t *sum)
{
- uint32_t checksum_var = 0;
- uint8_t buf[2];
- int n;
-
- /* Checksum loop */
- while ( (n = read(bug_fd, buf, 2) ) )
- {
- checksum_var = checksum_var + *(uint16_t *)buf;
-
- /* If we carry out, mask it and add one to the checksum */
- if (checksum_var >> 16)
- checksum_var = (checksum_var & 0x0000ffff) + 1;
- }
-
- return checksum_var;
+ static bug_boot_header_t bbh = {
+ .magic_word = "BOOT",
+ .routine_name = "LINUXROM"
+ };
+
+ /* Fill in the PPCBUG ROM boot header */
+ bbh.entry_offset = htonl(HEADER_SIZE); /* Entry address */
+ bbh.routine_length= htonl(HEADER_SIZE+boot_size+2); /* Routine length */
+
+ /* Output the header and bootloader to the file */
+ write(out_fd, &bbh, sizeof(bug_boot_header_t));
+ update_checksum(&bbh, sizeof(bug_boot_header_t), sum);
}
int main(int argc, char *argv[])
{
- int32_t image_fd, bugboot_fd;
- int argptr = 1;
- uint32_t kernel_size = 0;
- uint16_t checksum = 0;
- uint8_t bugbootname[256];
-
- if ( (argc != 3) )
- {
- fprintf(stderr, "usage: %s <kernel_image> <bugboot>\n",argv[0]);
- exit(-1);
- }
-
- /* Get file args */
-
- /* kernel image file */
- if ((image_fd = open( argv[argptr] , 0)) < 0)
- exit(-1);
- argptr++;
+ int image_fd, bugboot_fd;
+ uint32_t kernel_size = 0;
+ uint16_t checksum = 0;
- /* bugboot file */
- if ( !strcmp( argv[argptr], "-" ) )
- bugboot_fd = 1; /* stdout */
- else
- if ((bugboot_fd = creat( argv[argptr] , 0755)) < 0)
- exit(-1);
- else
- strcpy(bugbootname, argv[argptr]);
- argptr++;
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s <kernel_image> <bugboot>\n",argv[0]);
+ exit(-1);
+ }
- /* Set file position after ROM header block where zImage will be written */
- lseek(bugboot_fd, HEADER_SIZE, SEEK_SET);
+ /* Get file args */
- /* Copy kernel image into bugboot image */
- kernel_size = copy_image(image_fd, bugboot_fd);
- close(image_fd);
+ /* kernel image file */
+ if ((image_fd = open(argv[1] , 0)) < 0)
+ exit(-1);
- /* Set file position to beginning where header/romboot will be written */
- lseek(bugboot_fd, 0, SEEK_SET);
+ /* bugboot file */
+ if (!strcmp(argv[2], "-"))
+ bugboot_fd = 1; /* stdout */
+ else if ((bugboot_fd = creat(argv[2] , 0755)) < 0)
+ exit(-1);
- /* Write out BUG header/romboot */
- write_bugboot_header(bugboot_fd, kernel_size);
+ /* Set file position after ROM header block where zImage will be written */
+ lseek(bugboot_fd, HEADER_SIZE, SEEK_SET);
- /* Close bugboot file */
- close(bugboot_fd);
+ /* Copy kernel image into bugboot image */
+ kernel_size = copy_image(image_fd, bugboot_fd, &checksum);
- /* Reopen it as read/write */
- bugboot_fd = open(bugbootname, O_RDWR);
+ /* Set file position to beginning where header/romboot will be written */
+ lseek(bugboot_fd, 0, SEEK_SET);
- /* Calculate checksum */
- checksum = calc_checksum(bugboot_fd);
+ /* Write out BUG header/romboot */
+ write_bugboot_header(bugboot_fd, kernel_size, &checksum);
- /* Write out the calculated checksum */
- write(bugboot_fd, &checksum, 2);
+ /* Write out the calculated checksum */
+ lseek(bugboot_fd, 0, SEEK_END);
+ write(bugboot_fd, &checksum, 2);
- return 0;
+ /* Close bugboot file */
+ close(bugboot_fd);
+ return 0;
}
diff --git a/arch/ppc/boot/utils/mkprep.c b/arch/ppc/boot/utils/mkprep.c
index f6d5a2f2fcf6..192bb397126f 100644
--- a/arch/ppc/boot/utils/mkprep.c
+++ b/arch/ppc/boot/utils/mkprep.c
@@ -15,279 +15,227 @@
* Modified for Sparc hosted builds by Peter Wahl <PeterWahl@web.de>
*/
-#include <fcntl.h>
#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
-#include <strings.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#define cpu_to_le32(x) le32_to_cpu((x))
-unsigned long le32_to_cpu(unsigned long x)
-{
- return (((x & 0x000000ffU) << 24) |
- ((x & 0x0000ff00U) << 8) |
- ((x & 0x00ff0000U) >> 8) |
- ((x & 0xff000000U) >> 24));
-}
-
-
-#define cpu_to_le16(x) le16_to_cpu((x))
-unsigned short le16_to_cpu(unsigned short x)
-{
- return (((x & 0x00ff) << 8) |
- ((x & 0xff00) >> 8));
-}
-
-#define cpu_to_be32(x) (x)
-#define be32_to_cpu(x) (x)
-#define cpu_to_be16(x) (x)
-#define be16_to_cpu(x) (x)
+#include <stdlib.h>
/* size of read buffer */
#define SIZE 0x1000
-
-typedef unsigned long dword_t;
-typedef unsigned short word_t;
-typedef unsigned char byte_t;
-typedef byte_t block_t[512];
-typedef byte_t page_t[4096];
-
-
/*
* Partition table entry
* - from the PReP spec
*/
typedef struct partition_entry {
- byte_t boot_indicator;
- byte_t starting_head;
- byte_t starting_sector;
- byte_t starting_cylinder;
-
- byte_t system_indicator;
- byte_t ending_head;
- byte_t ending_sector;
- byte_t ending_cylinder;
-
- dword_t beginning_sector;
- dword_t number_of_sectors;
+ unsigned char boot_indicator;
+ unsigned char starting_head;
+ unsigned char starting_sector;
+ unsigned char starting_cylinder;
+
+ unsigned char system_indicator;
+ unsigned char ending_head;
+ unsigned char ending_sector;
+ unsigned char ending_cylinder;
+
+ unsigned char beginning_sector[4];
+ unsigned char number_of_sectors[4];
} partition_entry_t;
#define BootActive 0x80
#define SystemPrep 0x41
-void copy_image(int , int);
-void write_prep_partition(int , int );
-void write_asm_data( int in, int out );
+void copy_image(FILE *, FILE *);
+void write_prep_partition(FILE *, FILE *);
+void write_asm_data(FILE *, FILE *);
unsigned int elfhdr_size = 65536;
int main(int argc, char *argv[])
{
- int in_fd, out_fd;
- int argptr = 1;
- unsigned int prep = 0;
- unsigned int asmoutput = 0;
-
- if ( (argc < 3) || (argc > 4) )
- {
- fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",argv[0]);
- exit(-1);
- }
-
- /* needs to handle args more elegantly -- but this is a small/simple program */
-
- /* check for -pbp */
- if ( !strcmp( argv[argptr], "-pbp" ) )
- {
- prep = 1;
- argptr++;
- }
-
- /* check for -asm */
- if ( !strcmp( argv[argptr], "-asm" ) )
- {
- asmoutput = 1;
- argptr++;
- }
-
- /* input file */
- if ( !strcmp( argv[argptr], "-" ) )
- in_fd = 0; /* stdin */
- else
- if ((in_fd = open( argv[argptr] , 0)) < 0)
- exit(-1);
- argptr++;
-
- /* output file */
- if ( !strcmp( argv[argptr], "-" ) )
- out_fd = 1; /* stdout */
- else
- if ((out_fd = creat( argv[argptr] , 0755)) < 0)
- exit(-1);
- argptr++;
-
- /* skip elf header in input file */
- /*if ( !prep )*/
- lseek(in_fd, elfhdr_size, SEEK_SET);
-
- /* write prep partition if necessary */
- if ( prep )
- write_prep_partition( in_fd, out_fd );
-
- /* write input image to bootimage */
- if ( asmoutput )
- write_asm_data( in_fd, out_fd );
- else
- copy_image(in_fd, out_fd);
-
- return 0;
+ FILE *in, *out;
+ int argptr = 1;
+ int prep = 0;
+ int asmoutput = 0;
+
+ if (argc < 3 || argc > 4) {
+ fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",
+ argv[0]);
+ exit(-1);
+ }
+
+/* needs to handle args more elegantly -- but this is a small/simple program */
+
+ /* check for -pbp */
+ if (!strcmp(argv[argptr], "-pbp")) {
+ prep = 1;
+ argptr++;
+ }
+
+ /* check for -asm */
+ if (!strcmp(argv[argptr], "-asm")) {
+ asmoutput = 1;
+ argptr++;
+ }
+
+ /* input file */
+ if (!strcmp(argv[argptr], "-"))
+ in = stdin;
+ else if (!(in = fopen(argv[argptr], "r")))
+ exit(-1);
+ argptr++;
+
+ /* output file */
+ if (!strcmp(argv[argptr], "-"))
+ out = stdout;
+ else if (!(out = fopen(argv[argptr], "w")))
+ exit(-1);
+ argptr++;
+
+ /* skip elf header in input file */
+ /*if ( !prep )*/
+ fseek(in, elfhdr_size, SEEK_SET);
+
+ /* write prep partition if necessary */
+ if (prep)
+ write_prep_partition(in, out);
+
+ /* write input image to bootimage */
+ if (asmoutput)
+ write_asm_data(in, out);
+ else
+ copy_image(in, out);
+
+ return 0;
}
-void write_prep_partition(int in, int out)
+void store_le32(unsigned int v, unsigned char *p)
{
- unsigned char block[512];
- partition_entry_t pe;
- dword_t *entry = (dword_t *)&block[0];
- dword_t *length = (dword_t *)&block[sizeof(long)];
- struct stat info;
-
- if (fstat(in, &info) < 0)
- {
- fprintf(stderr,"info failed\n");
- exit(-1);
- }
-
- bzero( block, sizeof block );
-
- /* set entry point and boot image size skipping over elf header */
-#ifdef __i386__
- *entry = 0x400/*+65536*/;
- *length = info.st_size-elfhdr_size+0x400;
-#else
- *entry = cpu_to_le32(0x400/*+65536*/);
- *length = cpu_to_le32(info.st_size-elfhdr_size+0x400);
-#endif /* __i386__ */
-
- /* sets magic number for msdos partition (used by linux) */
- block[510] = 0x55;
- block[511] = 0xAA;
-
- /*
- * Build a "PReP" partition table entry in the boot record
- * - "PReP" may only look at the system_indicator
- */
- pe.boot_indicator = BootActive;
- pe.system_indicator = SystemPrep;
- /*
- * The first block of the diskette is used by this "boot record" which
- * actually contains the partition table. (The first block of the
- * partition contains the boot image, but I digress...) We'll set up
- * one partition on the diskette and it shall contain the rest of the
- * diskette.
- */
- pe.starting_head = 0; /* zero-based */
- pe.starting_sector = 2; /* one-based */
- pe.starting_cylinder = 0; /* zero-based */
- pe.ending_head = 1; /* assumes two heads */
- pe.ending_sector = 18; /* assumes 18 sectors/track */
- pe.ending_cylinder = 79; /* assumes 80 cylinders/diskette */
-
- /*
- * The "PReP" software ignores the above fields and just looks at
- * the next two.
- * - size of the diskette is (assumed to be)
- * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
- * - unlike the above sector numbers, the beginning sector is zero-based!
- */
+ p[0] = v;
+ p[1] = v >>= 8;
+ p[2] = v >>= 8;
+ p[3] = v >> 8;
+}
+
+void write_prep_partition(FILE *in, FILE *out)
+{
+ unsigned char block[512];
+ partition_entry_t pe;
+ unsigned char *entry = block;
+ unsigned char *length = block + 4;
+ long pos = ftell(in), size;
+
+ if (fseek(in, 0, SEEK_END) < 0) {
+ fprintf(stderr,"info failed\n");
+ exit(-1);
+ }
+ size = ftell(in);
+ if (fseek(in, pos, SEEK_SET) < 0) {
+ fprintf(stderr,"info failed\n");
+ exit(-1);
+ }
+
+ memset(block, '\0', sizeof(block));
+
+ /* set entry point and boot image size skipping over elf header */
+ store_le32(0x400/*+65536*/, entry);
+ store_le32(size-elfhdr_size+0x400, length);
+
+ /* sets magic number for msdos partition (used by linux) */
+ block[510] = 0x55;
+ block[511] = 0xAA;
+
+ /*
+ * Build a "PReP" partition table entry in the boot record
+ * - "PReP" may only look at the system_indicator
+ */
+ pe.boot_indicator = BootActive;
+ pe.system_indicator = SystemPrep;
+ /*
+ * The first block of the diskette is used by this "boot record" which
+ * actually contains the partition table. (The first block of the
+ * partition contains the boot image, but I digress...) We'll set up
+ * one partition on the diskette and it shall contain the rest of the
+ * diskette.
+ */
+ pe.starting_head = 0; /* zero-based */
+ pe.starting_sector = 2; /* one-based */
+ pe.starting_cylinder = 0; /* zero-based */
+ pe.ending_head = 1; /* assumes two heads */
+ pe.ending_sector = 18; /* assumes 18 sectors/track */
+ pe.ending_cylinder = 79; /* assumes 80 cylinders/diskette */
+
+ /*
+ * The "PReP" software ignores the above fields and just looks at
+ * the next two.
+ * - size of the diskette is (assumed to be)
+ * (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
+ * - unlike the above sector numbers, the beginning sector is zero-based!
+ */
#if 0
- pe.beginning_sector = cpu_to_le32(1);
-#else
- /* This has to be 0 on the PowerStack? */
-#ifdef __i386__
- pe.beginning_sector = 0;
+ store_le32(1, pe.beginning_sector);
#else
- pe.beginning_sector = cpu_to_le32(0);
-#endif /* __i386__ */
+ /* This has to be 0 on the PowerStack? */
+ store_le32(0, pe.beginning_sector);
#endif
-#ifdef __i386__
- pe.number_of_sectors = 2*18*80-1;
-#else
- pe.number_of_sectors = cpu_to_le32(2*18*80-1);
-#endif /* __i386__ */
+ store_le32(2*18*80-1, pe.number_of_sectors);
- memcpy(&block[0x1BE], &pe, sizeof(pe));
+ memcpy(&block[0x1BE], &pe, sizeof(pe));
- write( out, block, sizeof(block) );
- write( out, entry, sizeof(*entry) );
- write( out, length, sizeof(*length) );
- /* set file position to 2nd sector where image will be written */
- lseek( out, 0x400, SEEK_SET );
+ fwrite(block, sizeof(block), 1, out);
+ fwrite(entry, 4, 1, out);
+ fwrite(length, 4, 1, out);
+ /* set file position to 2nd sector where image will be written */
+ fseek( out, 0x400, SEEK_SET );
}
-void
-copy_image(int in, int out)
+void copy_image(FILE *in, FILE *out)
{
- char buf[SIZE];
- int n;
+ char buf[SIZE];
+ int n;
- while ( (n = read(in, buf, SIZE)) > 0 )
- write(out, buf, n);
+ while ( (n = fread(buf, 1, SIZE, in)) > 0 )
+ fwrite(buf, 1, n, out);
}
void
-write_asm_data( int in, int out )
+write_asm_data(FILE *in, FILE *out)
{
- int i, cnt, pos, len;
- unsigned int cksum, val;
- unsigned char *lp;
- unsigned char buf[SIZE];
- unsigned char str[256];
-
- write( out, "\t.data\n\t.globl input_data\ninput_data:\n",
- strlen( "\t.data\n\t.globl input_data\ninput_data:\n" ) );
- pos = 0;
- cksum = 0;
- while ((len = read(in, buf, sizeof(buf))) > 0)
- {
- cnt = 0;
- lp = (unsigned char *)buf;
- len = (len + 3) & ~3; /* Round up to longwords */
- for (i = 0; i < len; i += 4)
- {
- if (cnt == 0)
- {
- write( out, "\t.long\t", strlen( "\t.long\t" ) );
- }
- sprintf( str, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
- write( out, str, strlen(str) );
- val = *(unsigned long *)lp;
- cksum ^= val;
- lp += 4;
- if (++cnt == 4)
- {
- cnt = 0;
- sprintf( str, " # %x \n", pos+i-12);
- write( out, str, strlen(str) );
- } else
- {
- write( out, ",", 1 );
- }
- }
- if (cnt)
- {
- write( out, "0\n", 2 );
- }
- pos += len;
- }
- sprintf(str, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
- write( out, str, strlen(str) );
-
- fprintf(stderr, "cksum = %x\n", cksum);
+ int i, cnt, pos = 0;
+ unsigned int cksum = 0, val;
+ unsigned char *lp;
+ unsigned char buf[SIZE];
+ size_t len;
+
+ fputs("\t.data\n\t.globl input_data\ninput_data:\n", out);
+ while ((len = fread(buf, 1, sizeof(buf), in)) > 0) {
+ cnt = 0;
+ lp = buf;
+ /* Round up to longwords */
+ while (len & 3)
+ buf[len++] = '\0';
+ for (i = 0; i < len; i += 4) {
+ if (cnt == 0)
+ fputs("\t.long\t", out);
+ fprintf(out, "0x%02X%02X%02X%02X",
+ lp[0], lp[1], lp[2], lp[3]);
+ val = *(unsigned long *)lp;
+ cksum ^= val;
+ lp += 4;
+ if (++cnt == 4) {
+ cnt = 0;
+ fprintf(out, " # %x \n", pos+i-12);
+ } else {
+ fputs(",", out);
+ }
+ }
+ if (cnt)
+ fputs("0\n", out);
+ pos += len;
+ }
+ fprintf(out, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
+ fprintf(stderr, "cksum = %x\n", cksum);
}
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 50b4bbd06804..5f6684012ded 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -942,20 +942,16 @@ _GLOBAL(kernel_thread)
addi r1,r1,16
blr
+_GLOBAL(kernel_execve)
+ li r0,__NR_execve
+ sc
+ bnslr
+ neg r3,r3
+ blr
+
/*
* This routine is just here to keep GCC happy - sigh...
*/
_GLOBAL(__main)
blr
-#define SYSCALL(name) \
-_GLOBAL(name) \
- li r0,__NR_##name; \
- sc; \
- bnslr; \
- lis r4,errno@ha; \
- stw r3,errno@l(r4); \
- li r3,-1; \
- blr
-
-SYSCALL(execve)
diff --git a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
index 5458ac5da7c3..75fe13815be2 100644
--- a/arch/ppc/kernel/setup.c
+++ b/arch/ppc/kernel/setup.c
@@ -86,10 +86,6 @@ int ppc_do_canonicalize_irqs;
EXPORT_SYMBOL(ppc_do_canonicalize_irqs);
#endif
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned long SYSRQ_KEY = 0x54;
-#endif /* CONFIG_MAGIC_SYSRQ */
-
#ifdef CONFIG_VGA_CONSOLE
unsigned long vgacon_remap_base;
#endif
diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
index ca57e896a36c..96a55972b986 100644
--- a/arch/ppc/kernel/smp.c
+++ b/arch/ppc/kernel/smp.c
@@ -84,7 +84,7 @@ smp_message_pass(int target, int msg)
/*
* Common functions
*/
-void smp_message_recv(int msg, struct pt_regs *regs)
+void smp_message_recv(int msg)
{
atomic_inc(&ipi_recv);
@@ -100,7 +100,7 @@ void smp_message_recv(int msg, struct pt_regs *regs)
break;
#ifdef CONFIG_XMON
case PPC_MSG_XMON_BREAK:
- xmon(regs);
+ xmon(get_irq_regs());
break;
#endif /* CONFIG_XMON */
default:
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 6ab8cc7226ab..18ee851e33e3 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -62,6 +62,7 @@
#include <asm/cache.h>
#include <asm/8xx_immap.h>
#include <asm/machdep.h>
+#include <asm/irq_regs.h>
#include <asm/time.h>
@@ -80,8 +81,6 @@ unsigned tb_to_us;
unsigned tb_last_stamp;
unsigned long tb_to_ns_scale;
-extern unsigned long wall_jiffies;
-
/* used for timezone offset */
static long timezone_offset;
@@ -131,6 +130,7 @@ void wakeup_decrementer(void)
*/
void timer_interrupt(struct pt_regs * regs)
{
+ struct pt_regs *old_regs;
int next_dec;
unsigned long cpu = smp_processor_id();
unsigned jiffy_stamp = last_jiffy_stamp(cpu);
@@ -139,12 +139,13 @@ void timer_interrupt(struct pt_regs * regs)
if (atomic_read(&ppc_n_lost_interrupts) != 0)
do_IRQ(regs);
+ old_regs = set_irq_regs(regs);
irq_enter();
while ((next_dec = tb_ticks_per_jiffy - tb_delta(&jiffy_stamp)) <= 0) {
jiffy_stamp += tb_ticks_per_jiffy;
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
update_process_times(user_mode(regs));
if (smp_processor_id())
@@ -153,7 +154,7 @@ void timer_interrupt(struct pt_regs * regs)
/* We are in an interrupt, no need to save/restore flags */
write_seqlock(&xtime_lock);
tb_last_stamp = jiffy_stamp;
- do_timer(regs);
+ do_timer(1);
/*
* update the rtc when needed, this should be performed on the
@@ -173,8 +174,7 @@ void timer_interrupt(struct pt_regs * regs)
*/
if ( ppc_md.set_rtc_time && ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
- abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ &&
- jiffies - wall_jiffies == 1) {
+ abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ) {
if (ppc_md.set_rtc_time(xtime.tv_sec+1 + timezone_offset) == 0)
last_rtc_update = xtime.tv_sec+1;
else
@@ -191,6 +191,7 @@ void timer_interrupt(struct pt_regs * regs)
ppc_md.heartbeat();
irq_exit();
+ set_irq_regs(old_regs);
}
/*
@@ -200,7 +201,7 @@ void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
unsigned long seq;
- unsigned delta, lost_ticks, usec, sec;
+ unsigned delta, usec, sec;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
@@ -214,10 +215,9 @@ void do_gettimeofday(struct timeval *tv)
if (!smp_tb_synchronized)
delta = 0;
#endif /* CONFIG_SMP */
- lost_ticks = jiffies - wall_jiffies;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- usec += mulhwu(tb_to_us, tb_ticks_per_jiffy * lost_ticks + delta);
+ usec += mulhwu(tb_to_us, delta);
while (usec >= 1000000) {
sec++;
usec -= 1000000;
@@ -258,7 +258,6 @@ int do_settimeofday(struct timespec *tv)
* still reasonable when gettimeofday resolution is 1 jiffy.
*/
tb_delta = tb_ticks_since(last_jiffy_stamp(smp_processor_id()));
- tb_delta += (jiffies - wall_jiffies) * tb_ticks_per_jiffy;
new_nsec -= 1000 * mulhwu(tb_to_us, tb_delta);
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index d7a433049b48..aafc8e8893d1 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -119,7 +119,7 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr)
* generate the same exception over and over again and we get
* nowhere. Better to kill it and let the kernel panic.
*/
- if (current->pid == 1) {
+ if (is_init(current)) {
__sighandler_t handler;
spin_lock_irq(&current->sighand->siglock);
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index 5cdfb71fcb07..465f451f3bc3 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -239,7 +239,7 @@ good_area:
/* protection fault */
if (error_code & 0x08000000)
goto bad_area;
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
}
@@ -291,7 +291,7 @@ bad_area:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 523392d460fa..c374e53ae03a 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -358,8 +358,8 @@ void __init do_init_bootmem(void)
*/
void __init paging_init(void)
{
- unsigned long zones_size[MAX_NR_ZONES], i;
-
+ unsigned long start_pfn, end_pfn;
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
#ifdef CONFIG_HIGHMEM
map_page(PKMAP_BASE, 0, 0); /* XXX gross */
pkmap_page_table = pte_offset_kernel(pmd_offset(pgd_offset_k
@@ -369,19 +369,19 @@ void __init paging_init(void)
(KMAP_FIX_BEGIN), KMAP_FIX_BEGIN), KMAP_FIX_BEGIN);
kmap_prot = PAGE_KERNEL;
#endif /* CONFIG_HIGHMEM */
+ /* All pages are DMA-able so we put them all in the DMA zone. */
+ start_pfn = __pa(PAGE_OFFSET) >> PAGE_SHIFT;
+ end_pfn = start_pfn + (total_memory >> PAGE_SHIFT);
+ add_active_range(0, start_pfn, end_pfn);
- /*
- * All pages are DMA-able so we put them all in the DMA zone.
- */
- zones_size[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
- for (i = 1; i < MAX_NR_ZONES; i++)
- zones_size[i] = 0;
-
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
#ifdef CONFIG_HIGHMEM
- zones_size[ZONE_HIGHMEM] = (total_memory - total_lowmem) >> PAGE_SHIFT;
+ max_zone_pfns[ZONE_DMA] = total_lowmem >> PAGE_SHIFT;
+ max_zone_pfns[ZONE_HIGHMEM] = total_memory >> PAGE_SHIFT;
+#else
+ max_zone_pfns[ZONE_DMA] = total_memory >> PAGE_SHIFT;
#endif /* CONFIG_HIGHMEM */
-
- free_area_init(zones_size);
+ free_area_init_nodes(max_zone_pfns);
}
void __init mem_init(void)
diff --git a/arch/ppc/platforms/4xx/cpci405.h b/arch/ppc/platforms/4xx/cpci405.h
index f5a5c0cd062d..a6c0a138b0d7 100644
--- a/arch/ppc/platforms/4xx/cpci405.h
+++ b/arch/ppc/platforms/4xx/cpci405.h
@@ -13,7 +13,6 @@
#ifndef __CPCI405_H__
#define __CPCI405_H__
-#include <linux/config.h>
#include <platforms/4xx/ibm405gp.h>
#include <asm/ppcboot.h>
diff --git a/arch/ppc/platforms/4xx/xparameters/xparameters.h b/arch/ppc/platforms/4xx/xparameters/xparameters.h
index cd7d0e7d9863..66ec5f35f306 100644
--- a/arch/ppc/platforms/4xx/xparameters/xparameters.h
+++ b/arch/ppc/platforms/4xx/xparameters/xparameters.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/xparameters.h
+ * arch/ppc/platforms/4xx/xparameters/xparameters.h
*
* This file includes the correct xparameters.h for the CONFIG'ed board plus
* fixups to translate board specific XPAR values to a common set of names
diff --git a/arch/ppc/platforms/85xx/Kconfig b/arch/ppc/platforms/85xx/Kconfig
index 7ddd331a7145..6f2d0add7de6 100644
--- a/arch/ppc/platforms/85xx/Kconfig
+++ b/arch/ppc/platforms/85xx/Kconfig
@@ -24,12 +24,12 @@ config MPC8540_ADS
config MPC8548_CDS
bool "Freescale MPC8548 CDS"
help
- This option enablese support for the MPC8548 CDS evaluation board.
+ This option enables support for the MPC8548 CDS evaluation board.
config MPC8555_CDS
bool "Freescale MPC8555 CDS"
help
- This option enablese support for the MPC8555 CDS evaluation board.
+ This option enables support for the MPC8555 CDS evaluation board.
config MPC8560_ADS
bool "Freescale MPC8560 ADS"
@@ -51,22 +51,22 @@ config STX_GP3
config TQM8540
bool "TQ Components TQM8540"
help
- This option enablese support for the TQ Components TQM8540 board.
+ This option enables support for the TQ Components TQM8540 board.
config TQM8541
bool "TQ Components TQM8541"
help
- This option enablese support for the TQ Components TQM8541 board.
+ This option enables support for the TQ Components TQM8541 board.
config TQM8555
bool "TQ Components TQM8555"
help
- This option enablese support for the TQ Components TQM8555 board.
+ This option enables support for the TQ Components TQM8555 board.
config TQM8560
bool "TQ Components TQM8560"
help
- This option enablese support for the TQ Components TQM8560 board.
+ This option enables support for the TQ Components TQM8560 board.
endchoice
@@ -94,7 +94,7 @@ config MPC8560
default y
config 85xx_PCI2
- bool "Supprt for 2nd PCI host controller"
+ bool "Support for 2nd PCI host controller"
depends on MPC8555_CDS
default y
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
index 94badafe4ef1..14ecec7bbed7 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -211,10 +211,10 @@ mpc8560ads_setup_arch(void)
#endif
}
-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cpm2_cascade(int irq, void *dev_id)
{
- while ((irq = cpm2_get_irq(regs)) >= 0)
- __do_IRQ(irq, regs);
+ while ((irq = cpm2_get_irq()) >= 0)
+ __do_IRQ(irq);
return IRQ_HANDLED;
}
diff --git a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
index 75204588a3e7..5ce0f69c1db6 100644
--- a/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
+++ b/arch/ppc/platforms/85xx/mpc85xx_cds_common.c
@@ -127,10 +127,10 @@ mpc85xx_cds_show_cpuinfo(struct seq_file *m)
}
#ifdef CONFIG_CPM2
-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cpm2_cascade(int irq, void *dev_id)
{
- while((irq = cpm2_get_irq(regs)) >= 0)
- __do_IRQ(irq, regs);
+ while((irq = cpm2_get_irq()) >= 0)
+ __do_IRQ(irq);
return IRQ_HANDLED;
}
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c
index 495aa79bb3a1..4bb18ab27672 100644
--- a/arch/ppc/platforms/85xx/stx_gp3.c
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -156,10 +156,10 @@ gp3_setup_arch(void)
printk ("bi_immr_base = %8.8lx\n", binfo->bi_immr_base);
}
-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cpm2_cascade(int irq, void *dev_id)
{
- while ((irq = cpm2_get_irq(regs)) >= 0)
- __do_IRQ(irq, regs);
+ while ((irq = cpm2_get_irq()) >= 0)
+ __do_IRQ(irq);
return IRQ_HANDLED;
}
diff --git a/arch/ppc/platforms/85xx/tqm85xx.c b/arch/ppc/platforms/85xx/tqm85xx.c
index 189ed4175f9f..dd45f2e18449 100644
--- a/arch/ppc/platforms/85xx/tqm85xx.c
+++ b/arch/ppc/platforms/85xx/tqm85xx.c
@@ -181,10 +181,10 @@ tqm85xx_setup_arch(void)
}
#ifdef CONFIG_MPC8560
-static irqreturn_t cpm2_cascade(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cpm2_cascade(int irq, void *dev_id)
{
- while ((irq = cpm2_get_irq(regs)) >= 0)
- __do_IRQ(irq, regs);
+ while ((irq = cpm2_get_irq()) >= 0)
+ __do_IRQ(irq);
return IRQ_HANDLED;
}
diff --git a/arch/ppc/platforms/apus_setup.c b/arch/ppc/platforms/apus_setup.c
index 1d034ead2c9a..063274d2c503 100644
--- a/arch/ppc/platforms/apus_setup.c
+++ b/arch/ppc/platforms/apus_setup.c
@@ -492,7 +492,7 @@ apus_halt(void)
static unsigned char last_ipl[8];
-int apus_get_irq(struct pt_regs* regs)
+int apus_get_irq(void)
{
unsigned char ipl_emu, mask;
unsigned int level;
diff --git a/arch/ppc/platforms/hdpu.c b/arch/ppc/platforms/hdpu.c
index e0f112a1fd0b..d809e17aa536 100644
--- a/arch/ppc/platforms/hdpu.c
+++ b/arch/ppc/platforms/hdpu.c
@@ -659,8 +659,7 @@ static void __init hdpu_map_io(void)
char hdpu_smp0[] = "SMP Cpu #0";
char hdpu_smp1[] = "SMP Cpu #1";
-static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id)
{
volatile unsigned int doorbell;
@@ -670,22 +669,21 @@ static irqreturn_t hdpu_smp_cpu0_int_handler(int irq, void *dev_id,
mv64x60_write(&bh, MV64360_CPU0_DOORBELL_CLR, doorbell);
if (doorbell & 1) {
- smp_message_recv(0, regs);
+ smp_message_recv(0);
}
if (doorbell & 2) {
- smp_message_recv(1, regs);
+ smp_message_recv(1);
}
if (doorbell & 4) {
- smp_message_recv(2, regs);
+ smp_message_recv(2);
}
if (doorbell & 8) {
- smp_message_recv(3, regs);
+ smp_message_recv(3);
}
return IRQ_HANDLED;
}
-static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id)
{
volatile unsigned int doorbell;
@@ -695,16 +693,16 @@ static irqreturn_t hdpu_smp_cpu1_int_handler(int irq, void *dev_id,
mv64x60_write(&bh, MV64360_CPU1_DOORBELL_CLR, doorbell);
if (doorbell & 1) {
- smp_message_recv(0, regs);
+ smp_message_recv(0);
}
if (doorbell & 2) {
- smp_message_recv(1, regs);
+ smp_message_recv(1);
}
if (doorbell & 4) {
- smp_message_recv(2, regs);
+ smp_message_recv(2);
}
if (doorbell & 8) {
- smp_message_recv(3, regs);
+ smp_message_recv(3);
}
return IRQ_HANDLED;
}
diff --git a/arch/ppc/platforms/lopec.h b/arch/ppc/platforms/lopec.h
index 5490edb2d263..d597b6878693 100644
--- a/arch/ppc/platforms/lopec.h
+++ b/arch/ppc/platforms/lopec.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/lopec_serial.h
+ * arch/ppc/platforms/lopec.h
*
* Definitions for Motorola LoPEC board.
*
diff --git a/arch/ppc/platforms/mpc8272ads_setup.c b/arch/ppc/platforms/mpc8272ads_setup.c
index 2a35fe2b9b96..1f9ea36837b1 100644
--- a/arch/ppc/platforms/mpc8272ads_setup.c
+++ b/arch/ppc/platforms/mpc8272ads_setup.c
@@ -1,5 +1,5 @@
/*
- * arch/ppc/platforms/82xx/pq2ads_pd.c
+ * arch/ppc/platforms/mpc8272ads_setup.c
*
* MPC82xx Board-specific PlatformDevice descriptions
*
@@ -103,7 +103,7 @@ static struct fs_platform_info mpc82xx_enet_pdata[] = {
},
};
-static void init_fcc1_ioports(void)
+static void init_fcc1_ioports(struct fs_platform_info*)
{
struct io_port *io;
u32 tempval;
@@ -144,7 +144,7 @@ static void init_fcc1_ioports(void)
iounmap(immap);
}
-static void init_fcc2_ioports(void)
+static void init_fcc2_ioports(struct fs_platform_info*)
{
cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
u32 *bcsr = ioremap(BCSR_ADDR+12, sizeof(u32));
@@ -196,7 +196,7 @@ static void __init mpc8272ads_fixup_enet_pdata(struct platform_device *pdev,
bd_t* bi = (void*)__res;
int fs_no = fsid_fcc1+pdev->id-1;
- if(fs_no > ARRAY_SIZE(mpc82xx_enet_pdata)) {
+ if(fs_no >= ARRAY_SIZE(mpc82xx_enet_pdata)) {
return;
}
@@ -222,14 +222,14 @@ static void mpc8272ads_fixup_uart_pdata(struct platform_device *pdev,
int id = fs_uart_id_scc2fsid(idx);
/* no need to alter anything if console */
- if ((id <= num) && (!pdev->dev.platform_data)) {
+ if ((id < num) && (!pdev->dev.platform_data)) {
pinfo = &mpc8272_uart_pdata[id];
pinfo->uart_clk = bd->bi_intfreq;
pdev->dev.platform_data = pinfo;
}
}
-static void init_scc1_uart_ioports(void)
+static void init_scc1_uart_ioports(struct fs_uart_platform_info*)
{
cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
@@ -246,7 +246,7 @@ static void init_scc1_uart_ioports(void)
iounmap(immap);
}
-static void init_scc4_uart_ioports(void)
+static void init_scc4_uart_ioports(struct fs_uart_platform_info*)
{
cpm2_map_t* immap = ioremap(CPM_MAP_ADDR, sizeof(cpm2_map_t));
diff --git a/arch/ppc/platforms/mpc866ads_setup.c b/arch/ppc/platforms/mpc866ads_setup.c
index e12cece4c9fd..e95d2c111747 100644
--- a/arch/ppc/platforms/mpc866ads_setup.c
+++ b/arch/ppc/platforms/mpc866ads_setup.c
@@ -137,7 +137,7 @@ void __init board_init(void)
iounmap(bcsr_io);
}
-static void setup_fec1_ioports(void)
+static void setup_fec1_ioports(struct fs_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
@@ -145,7 +145,7 @@ static void setup_fec1_ioports(void)
setbits16(&immap->im_ioport.iop_pddir, 0x1fff);
}
-static void setup_scc1_ioports(void)
+static void setup_scc1_ioports(struct fs_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
unsigned *bcsr_io;
@@ -194,7 +194,7 @@ static void setup_scc1_ioports(void)
}
-static void setup_smc1_ioports(void)
+static void setup_smc1_ioports(struct fs_uart_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
unsigned *bcsr_io;
@@ -216,7 +216,7 @@ static void setup_smc1_ioports(void)
}
-static void setup_smc2_ioports(void)
+static void setup_smc2_ioports(struct fs_uart_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
unsigned *bcsr_io;
@@ -259,7 +259,7 @@ static void mpc866ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
/* Get pointer to Communication Processor */
cp = cpmp;
- if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) {
+ if(fs_no >= ARRAY_SIZE(mpc8xx_enet_pdata)) {
printk(KERN_ERR"No network-suitable #%d device on bus", fs_no);
return;
}
@@ -305,7 +305,7 @@ static void __init mpc866ads_fixup_uart_pdata(struct platform_device *pdev,
int id = fs_uart_id_smc2fsid(idx);
/* no need to alter anything if console */
- if ((id <= num) && (!pdev->dev.platform_data)) {
+ if ((id < num) && (!pdev->dev.platform_data)) {
pinfo = &mpc866_uart_pdata[id];
pinfo->uart_clk = bd->bi_intfreq;
pdev->dev.platform_data = pinfo;
diff --git a/arch/ppc/platforms/mpc885ads_setup.c b/arch/ppc/platforms/mpc885ads_setup.c
index 5dfa4e6c2af0..f8161f3557f5 100644
--- a/arch/ppc/platforms/mpc885ads_setup.c
+++ b/arch/ppc/platforms/mpc885ads_setup.c
@@ -1,4 +1,4 @@
-/*arch/ppc/platforms/mpc885ads-setup.c
+/*arch/ppc/platforms/mpc885ads_setup.c
*
* Platform setup for the Freescale mpc885ads board
*
@@ -161,7 +161,7 @@ void __init board_init(void)
#endif
}
-static void setup_fec1_ioports(void)
+static void setup_fec1_ioports(struct fs_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
@@ -181,7 +181,7 @@ static void setup_fec1_ioports(void)
clrbits32(&immap->im_cpm.cp_cptr, 0x00000100);
}
-static void setup_fec2_ioports(void)
+static void setup_fec2_ioports(struct fs_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
@@ -193,7 +193,7 @@ static void setup_fec2_ioports(void)
clrbits32(&immap->im_cpm.cp_cptr, 0x00000080);
}
-static void setup_scc3_ioports(void)
+static void setup_scc3_ioports(struct fs_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
unsigned *bcsr_io;
@@ -263,7 +263,7 @@ static void mpc885ads_fixup_enet_pdata(struct platform_device *pdev, int fs_no)
char *e;
int i;
- if(fs_no > ARRAY_SIZE(mpc8xx_enet_pdata)) {
+ if(fs_no >= ARRAY_SIZE(mpc8xx_enet_pdata)) {
printk(KERN_ERR"No network-suitable #%d device on bus", fs_no);
return;
}
@@ -315,7 +315,7 @@ static void __init mpc885ads_fixup_scc_enet_pdata(struct platform_device *pdev,
mpc885ads_fixup_enet_pdata(pdev, fsid_scc1 + pdev->id - 1);
}
-static void setup_smc1_ioports(void)
+static void setup_smc1_ioports(struct fs_uart_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
unsigned *bcsr_io;
@@ -335,7 +335,7 @@ static void setup_smc1_ioports(void)
clrbits16(&immap->im_cpm.cp_pbodr, iobits);
}
-static void setup_smc2_ioports(void)
+static void setup_smc2_ioports(struct fs_uart_platform_info*)
{
immap_t *immap = (immap_t *) IMAP_ADDR;
unsigned *bcsr_io;
@@ -371,7 +371,7 @@ static void __init mpc885ads_fixup_uart_pdata(struct platform_device *pdev,
int id = fs_uart_id_smc2fsid(idx);
/* no need to alter anything if console */
- if ((id <= num) && (!pdev->dev.platform_data)) {
+ if ((id < num) && (!pdev->dev.platform_data)) {
pinfo = &mpc885_uart_pdata[id];
pinfo->uart_clk = bd->bi_intfreq;
pdev->dev.platform_data = pinfo;
diff --git a/arch/ppc/platforms/mvme5100.h b/arch/ppc/platforms/mvme5100.h
index edd479439a4e..9e2a09e636ae 100644
--- a/arch/ppc/platforms/mvme5100.h
+++ b/arch/ppc/platforms/mvme5100.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/platforms/mvme5100.h
+ * arch/ppc/platforms/mvme5100.h
*
* Definitions for Motorola MVME5100.
*
diff --git a/arch/ppc/platforms/powerpmc250.h b/arch/ppc/platforms/powerpmc250.h
index 41a6dc881911..d33ad8dc0439 100644
--- a/arch/ppc/platforms/powerpmc250.h
+++ b/arch/ppc/platforms/powerpmc250.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/platforms/powerpmc250.h
+ * arch/ppc/platforms/powerpmc250.h
*
* Definitions for Force PowerPMC-250 board support
*
diff --git a/arch/ppc/platforms/prpmc750.h b/arch/ppc/platforms/prpmc750.h
index 015b4f52c3eb..4c7adcc9ae33 100644
--- a/arch/ppc/platforms/prpmc750.h
+++ b/arch/ppc/platforms/prpmc750.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/platforms/prpmc750.h
+ * arch/ppc/platforms/prpmc750.h
*
* Definitions for Motorola PrPMC750 board support
*
diff --git a/arch/ppc/platforms/prpmc800.h b/arch/ppc/platforms/prpmc800.h
index e53ec9b42a35..26f604e05cfa 100644
--- a/arch/ppc/platforms/prpmc800.h
+++ b/arch/ppc/platforms/prpmc800.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/platforms/prpmc800.h
+ * arch/ppc/platforms/prpmc800.h
*
* Definitions for Motorola PrPMC800 board support
*
diff --git a/arch/ppc/platforms/radstone_ppc7d.c b/arch/ppc/platforms/radstone_ppc7d.c
index 3bb530af0297..13d70ab50bf1 100644
--- a/arch/ppc/platforms/radstone_ppc7d.c
+++ b/arch/ppc/platforms/radstone_ppc7d.c
@@ -451,11 +451,11 @@ static void __init ppc7d_calibrate_decr(void)
* Interrupt stuff
*****************************************************************************/
-static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ppc7d_i8259_intr(int irq, void *dev_id)
{
u32 temp = mv64x60_read(&bh, MV64x60_GPP_INTR_CAUSE);
if (temp & (1 << 28)) {
- i8259_irq(regs);
+ i8259_irq();
mv64x60_write(&bh, MV64x60_GPP_INTR_CAUSE, temp & (~(1 << 28)));
return IRQ_HANDLED;
}
@@ -536,13 +536,13 @@ static u32 ppc7d_irq_canonicalize(u32 irq)
return irq;
}
-static int ppc7d_get_irq(struct pt_regs *regs)
+static int ppc7d_get_irq(void)
{
int irq;
- irq = mv64360_get_irq(regs);
+ irq = mv64360_get_irq();
if (irq == (mv64360_irq_base + MV64x60_IRQ_GPP28))
- irq = i8259_irq(regs);
+ irq = i8259_irq();
return irq;
}
diff --git a/arch/ppc/platforms/sbc82xx.c b/arch/ppc/platforms/sbc82xx.c
index 60b769c7f3fc..cc0935ccab7a 100644
--- a/arch/ppc/platforms/sbc82xx.c
+++ b/arch/ppc/platforms/sbc82xx.c
@@ -121,7 +121,7 @@ struct hw_interrupt_type sbc82xx_i8259_ic = {
.end = sbc82xx_i8259_end_irq,
};
-static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id)
{
spin_lock(&sbc82xx_i8259_lock);
@@ -139,7 +139,7 @@ static irqreturn_t sbc82xx_i8259_demux(int irq, void *dev_id, struct pt_regs *re
return IRQ_HANDLED;
}
}
- __do_IRQ(NR_SIU_INTS + irq, regs);
+ __do_IRQ(NR_SIU_INTS + irq);
return IRQ_HANDLED;
}
diff --git a/arch/ppc/platforms/spruce.h b/arch/ppc/platforms/spruce.h
index a31ff7ee698f..f1f96f1de72a 100644
--- a/arch/ppc/platforms/spruce.h
+++ b/arch/ppc/platforms/spruce.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/platforms/spruce.h
+ * arch/ppc/platforms/spruce.h
*
* Definitions for IBM Spruce reference board support
*
diff --git a/arch/ppc/syslib/cpc700.h b/arch/ppc/syslib/cpc700.h
index 0a8a5d84390f..987e9aa0dd45 100644
--- a/arch/ppc/syslib/cpc700.h
+++ b/arch/ppc/syslib/cpc700.h
@@ -91,6 +91,6 @@ extern struct hw_interrupt_type cpc700_pic;
extern unsigned int cpc700_irq_assigns[32][2];
extern void __init cpc700_init_IRQ(void);
-extern int cpc700_get_irq(struct pt_regs *);
+extern int cpc700_get_irq(void);
#endif /* __PPC_SYSLIB_CPC700_H__ */
diff --git a/arch/ppc/syslib/cpc700_pic.c b/arch/ppc/syslib/cpc700_pic.c
index 172aa215fdb0..d48e8f45c050 100644
--- a/arch/ppc/syslib/cpc700_pic.c
+++ b/arch/ppc/syslib/cpc700_pic.c
@@ -158,7 +158,7 @@ cpc700_init_IRQ(void)
* Find the highest IRQ that generating an interrupt, if any.
*/
int
-cpc700_get_irq(struct pt_regs *regs)
+cpc700_get_irq(void)
{
int irq = 0;
u_int irq_status, irq_test = 1;
diff --git a/arch/ppc/syslib/cpm2_pic.c b/arch/ppc/syslib/cpm2_pic.c
index c0fee0beb815..fb2d5842641a 100644
--- a/arch/ppc/syslib/cpm2_pic.c
+++ b/arch/ppc/syslib/cpm2_pic.c
@@ -123,7 +123,7 @@ static struct hw_interrupt_type cpm2_pic = {
.end = cpm2_end_irq,
};
-int cpm2_get_irq(struct pt_regs *regs)
+int cpm2_get_irq(void)
{
int irq;
unsigned long bits;
diff --git a/arch/ppc/syslib/cpm2_pic.h b/arch/ppc/syslib/cpm2_pic.h
index 97cab8f13a1a..467339337a78 100644
--- a/arch/ppc/syslib/cpm2_pic.h
+++ b/arch/ppc/syslib/cpm2_pic.h
@@ -1,7 +1,7 @@
#ifndef _PPC_KERNEL_CPM2_H
#define _PPC_KERNEL_CPM2_H
-extern int cpm2_get_irq(struct pt_regs *regs);
+extern int cpm2_get_irq(void);
extern void cpm2_init_IRQ(void);
diff --git a/arch/ppc/syslib/gt64260_pic.c b/arch/ppc/syslib/gt64260_pic.c
index 7fd550a7d586..e84d432c0657 100644
--- a/arch/ppc/syslib/gt64260_pic.c
+++ b/arch/ppc/syslib/gt64260_pic.c
@@ -110,9 +110,6 @@ gt64260_init_irq(void)
* This function returns the lowest interrupt number of all interrupts that
* are currently asserted.
*
- * Input Variable(s):
- * struct pt_regs* not used
- *
* Output Variable(s):
* None.
*
@@ -120,7 +117,7 @@ gt64260_init_irq(void)
* int <interrupt number> or -2 (bogus interrupt)
*/
int
-gt64260_get_irq(struct pt_regs *regs)
+gt64260_get_irq(void)
{
int irq;
int irq_gpp;
@@ -229,7 +226,7 @@ gt64260_mask_irq(unsigned int irq)
}
static irqreturn_t
-gt64260_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+gt64260_cpu_error_int_handler(int irq, void *dev_id)
{
printk(KERN_ERR "gt64260_cpu_error_int_handler: %s 0x%08x\n",
"Error on CPU interface - Cause regiser",
@@ -250,7 +247,7 @@ gt64260_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
}
static irqreturn_t
-gt64260_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+gt64260_pci_error_int_handler(int irq, void *dev_id)
{
u32 val;
unsigned int pci_bus = (unsigned int)dev_id;
diff --git a/arch/ppc/syslib/i8259.c b/arch/ppc/syslib/i8259.c
index eb35353af837..a43dda5a8334 100644
--- a/arch/ppc/syslib/i8259.c
+++ b/arch/ppc/syslib/i8259.c
@@ -28,7 +28,7 @@ static int i8259_pic_irq_offset;
* which is called. It should be noted that polling is broken on some
* IBM and Motorola PReP boxes so we must use the int-ack feature on them.
*/
-int i8259_irq(struct pt_regs *regs)
+int i8259_irq(void)
{
int irq;
diff --git a/arch/ppc/syslib/ibm440gx_common.c b/arch/ppc/syslib/ibm440gx_common.c
index 4b77e6c8c87f..6ad52f4a26e1 100644
--- a/arch/ppc/syslib/ibm440gx_common.c
+++ b/arch/ppc/syslib/ibm440gx_common.c
@@ -119,7 +119,7 @@ static inline u32 l2c_diag(u32 addr)
return mfdcr(DCRN_L2C0_DATA);
}
-static irqreturn_t l2c_error_handler(int irq, void* dev, struct pt_regs* regs)
+static irqreturn_t l2c_error_handler(int irq, void* dev)
{
u32 sr = mfdcr(DCRN_L2C0_SR);
if (sr & L2C_SR_CPE){
diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
index 46801f5ec03f..10659c24b1be 100644
--- a/arch/ppc/syslib/ipic.c
+++ b/arch/ppc/syslib/ipic.c
@@ -601,7 +601,7 @@ void ipic_clear_mcp_status(u32 mask)
}
/* Return an interrupt vector or -1 if no interrupt is pending. */
-int ipic_get_irq(struct pt_regs *regs)
+int ipic_get_irq(void)
{
int irq;
diff --git a/arch/ppc/syslib/m82xx_pci.c b/arch/ppc/syslib/m82xx_pci.c
index d3fa264e179e..e3b586b1ede9 100644
--- a/arch/ppc/syslib/m82xx_pci.c
+++ b/arch/ppc/syslib/m82xx_pci.c
@@ -117,7 +117,7 @@ struct hw_interrupt_type pq2pci_ic = {
};
static irqreturn_t
-pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
+pq2pci_irq_demux(int irq, void *dev_id)
{
unsigned long stat, mask, pend;
int bit;
@@ -130,7 +130,7 @@ pq2pci_irq_demux(int irq, void *dev_id, struct pt_regs *regs)
break;
for (bit = 0; pend != 0; ++bit, pend <<= 1) {
if (pend & 0x80000000)
- __do_IRQ(NR_CPM_INTS + bit, regs);
+ __do_IRQ(NR_CPM_INTS + bit);
}
}
diff --git a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
index 54303a7b4e69..d8d299bd1a12 100644
--- a/arch/ppc/syslib/m8xx_setup.c
+++ b/arch/ppc/syslib/m8xx_setup.c
@@ -169,7 +169,7 @@ abort(void)
}
/* A place holder for time base interrupts, if they are ever enabled. */
-irqreturn_t timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+irqreturn_t timebase_interrupt(int irq, void * dev)
{
printk ("timebase_interrupt()\n");
diff --git a/arch/ppc/syslib/m8xx_wdt.c b/arch/ppc/syslib/m8xx_wdt.c
index ac11d7bab443..fffac8cbeb51 100644
--- a/arch/ppc/syslib/m8xx_wdt.c
+++ b/arch/ppc/syslib/m8xx_wdt.c
@@ -21,7 +21,7 @@
static int wdt_timeout;
int m8xx_has_internal_rtc = 0;
-static irqreturn_t m8xx_wdt_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t m8xx_wdt_interrupt(int, void *);
static struct irqaction m8xx_wdt_irqaction = {
.handler = m8xx_wdt_interrupt,
.name = "watchdog",
@@ -35,7 +35,7 @@ void m8xx_wdt_reset(void)
out_be16(&imap->im_siu_conf.sc_swsr, 0xaa39); /* write magic2 */
}
-static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t m8xx_wdt_interrupt(int irq, void *dev)
{
volatile immap_t *imap = (volatile immap_t *)IMAP_ADDR;
diff --git a/arch/ppc/syslib/mpc52xx_pic.c b/arch/ppc/syslib/mpc52xx_pic.c
index 6425b5cee7db..af35a316544a 100644
--- a/arch/ppc/syslib/mpc52xx_pic.c
+++ b/arch/ppc/syslib/mpc52xx_pic.c
@@ -220,7 +220,7 @@ mpc52xx_init_irq(void)
}
int
-mpc52xx_get_irq(struct pt_regs *regs)
+mpc52xx_get_irq(void)
{
u32 status;
int irq = -1;
diff --git a/arch/ppc/syslib/mv64360_pic.c b/arch/ppc/syslib/mv64360_pic.c
index 3f6d162f87cf..4b7a3338e122 100644
--- a/arch/ppc/syslib/mv64360_pic.c
+++ b/arch/ppc/syslib/mv64360_pic.c
@@ -55,10 +55,9 @@
static void mv64360_unmask_irq(unsigned int);
static void mv64360_mask_irq(unsigned int);
-static irqreturn_t mv64360_cpu_error_int_handler(int, void *, struct pt_regs *);
-static irqreturn_t mv64360_sram_error_int_handler(int, void *,
- struct pt_regs *);
-static irqreturn_t mv64360_pci_error_int_handler(int, void *, struct pt_regs *);
+static irqreturn_t mv64360_cpu_error_int_handler(int, void *);
+static irqreturn_t mv64360_sram_error_int_handler(int, void *);
+static irqreturn_t mv64360_pci_error_int_handler(int, void *);
/* ========================== local declarations =========================== */
@@ -131,9 +130,6 @@ mv64360_init_irq(void)
* This function returns the lowest interrupt number of all interrupts that
* are currently asserted.
*
- * Input Variable(s):
- * struct pt_regs* not used
- *
* Output Variable(s):
* None.
*
@@ -142,7 +138,7 @@ mv64360_init_irq(void)
*
*/
int
-mv64360_get_irq(struct pt_regs *regs)
+mv64360_get_irq(void)
{
int irq;
int irq_gpp;
@@ -283,7 +279,7 @@ mv64360_mask_irq(unsigned int irq)
}
static irqreturn_t
-mv64360_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+mv64360_cpu_error_int_handler(int irq, void *dev_id)
{
printk(KERN_ERR "mv64360_cpu_error_int_handler: %s 0x%08x\n",
"Error on CPU interface - Cause regiser",
@@ -304,7 +300,7 @@ mv64360_cpu_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
}
static irqreturn_t
-mv64360_sram_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+mv64360_sram_error_int_handler(int irq, void *dev_id)
{
printk(KERN_ERR "mv64360_sram_error_int_handler: %s 0x%08x\n",
"Error in internal SRAM - Cause register",
@@ -325,7 +321,7 @@ mv64360_sram_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
}
static irqreturn_t
-mv64360_pci_error_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+mv64360_pci_error_int_handler(int irq, void *dev_id)
{
u32 val;
unsigned int pci_bus = (unsigned int)dev_id;
@@ -380,7 +376,7 @@ mv64360_register_hdlrs(void)
/* Clear old errors and register CPU interface error intr handler */
mv64x60_write(&bh, MV64x60_CPU_ERR_CAUSE, 0);
if ((rc = request_irq(MV64x60_IRQ_CPU_ERR + mv64360_irq_base,
- mv64360_cpu_error_int_handler, IRQF_DISABLED, CPU_INTR_STR, 0)))
+ mv64360_cpu_error_int_handler, IRQF_DISABLED, CPU_INTR_STR, NULL)))
printk(KERN_WARNING "Can't register cpu error handler: %d", rc);
mv64x60_write(&bh, MV64x60_CPU_ERR_MASK, 0);
@@ -389,7 +385,7 @@ mv64360_register_hdlrs(void)
/* Clear old errors and register internal SRAM error intr handler */
mv64x60_write(&bh, MV64360_SRAM_ERR_CAUSE, 0);
if ((rc = request_irq(MV64360_IRQ_SRAM_PAR_ERR + mv64360_irq_base,
- mv64360_sram_error_int_handler,IRQF_DISABLED,SRAM_INTR_STR, 0)))
+ mv64360_sram_error_int_handler,IRQF_DISABLED,SRAM_INTR_STR, NULL)))
printk(KERN_WARNING "Can't register SRAM error handler: %d",rc);
/* Clear old errors and register PCI 0 error intr handler */
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
index aa0b95788705..18ec94733293 100644
--- a/arch/ppc/syslib/open_pic.c
+++ b/arch/ppc/syslib/open_pic.c
@@ -45,7 +45,7 @@ static u_int NumSources;
static int open_pic_irq_offset;
static volatile OpenPIC_Source __iomem *ISR[NR_IRQS];
static int openpic_cascade_irq = -1;
-static int (*openpic_cascade_fn)(struct pt_regs *);
+static int (*openpic_cascade_fn)(void);
/* Global Operations */
static void openpic_disable_8259_pass_through(void);
@@ -54,7 +54,7 @@ static void openpic_set_spurious(u_int vector);
#ifdef CONFIG_SMP
/* Interprocessor Interrupts */
static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
-static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *);
+static irqreturn_t openpic_ipi_action(int cpl, void *dev_id);
#endif
/* Timer Interrupts */
@@ -700,7 +700,7 @@ static struct irqaction openpic_cascade_irqaction = {
void __init
openpic_hookup_cascade(u_int irq, char *name,
- int (*cascade_fn)(struct pt_regs *))
+ int (*cascade_fn)(void))
{
openpic_cascade_irq = irq;
openpic_cascade_fn = cascade_fn;
@@ -857,16 +857,16 @@ static void openpic_end_ipi(unsigned int irq_nr)
{
}
-static irqreturn_t openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+static irqreturn_t openpic_ipi_action(int cpl, void *dev_id)
{
- smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
+ smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset);
return IRQ_HANDLED;
}
#endif /* CONFIG_SMP */
int
-openpic_get_irq(struct pt_regs *regs)
+openpic_get_irq(void)
{
int irq = openpic_irq();
@@ -876,7 +876,7 @@ openpic_get_irq(struct pt_regs *regs)
* This should move to irq.c eventually. -- paulus
*/
if (irq == openpic_cascade_irq && openpic_cascade_fn != NULL) {
- int cirq = openpic_cascade_fn(regs);
+ int cirq = openpic_cascade_fn();
/* Allow for the cascade being shared with other devices */
if (cirq != -1) {
diff --git a/arch/ppc/syslib/open_pic2.c b/arch/ppc/syslib/open_pic2.c
index e1ff971539ea..d585207f9f77 100644
--- a/arch/ppc/syslib/open_pic2.c
+++ b/arch/ppc/syslib/open_pic2.c
@@ -529,7 +529,7 @@ static void openpic2_end_irq(unsigned int irq_nr)
}
int
-openpic2_get_irq(struct pt_regs *regs)
+openpic2_get_irq(void)
{
int irq = openpic2_irq();
diff --git a/arch/ppc/syslib/ppc403_pic.c b/arch/ppc/syslib/ppc403_pic.c
index 1584c8b1229f..607ebd111d44 100644
--- a/arch/ppc/syslib/ppc403_pic.c
+++ b/arch/ppc/syslib/ppc403_pic.c
@@ -42,7 +42,7 @@ static struct hw_interrupt_type ppc403_aic = {
};
int
-ppc403_pic_get_irq(struct pt_regs *regs)
+ppc403_pic_get_irq(void)
{
int irq;
unsigned long bits;
diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c
index 745685df5984..ee0da4b4b993 100644
--- a/arch/ppc/syslib/ppc4xx_pic.c
+++ b/arch/ppc/syslib/ppc4xx_pic.c
@@ -96,7 +96,7 @@ UIC_HANDLERS(1);
UIC_HANDLERS(2);
UIC_HANDLERS(3);
-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
+static int ppc4xx_pic_get_irq(void)
{
u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
if (uic0 & UIC0_UIC1NC)
@@ -125,7 +125,7 @@ UIC_HANDLERS(0);
UIC_HANDLERS(1);
UIC_HANDLERS(2);
-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
+static int ppc4xx_pic_get_irq(void)
{
u32 uicb = mfdcr(DCRN_UIC_MSR(UICB));
if (uicb & UICB_UIC0NC)
@@ -158,7 +158,7 @@ static void __init ppc4xx_pic_impl_init(void)
UIC_HANDLERS(0);
UIC_HANDLERS(1);
-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
+static int ppc4xx_pic_get_irq(void)
{
u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
if (uic0 & UIC0_UIC1NC)
@@ -179,7 +179,7 @@ static void __init ppc4xx_pic_impl_init(void)
#define ACK_UIC0_PARENT
UIC_HANDLERS(0);
-static int ppc4xx_pic_get_irq(struct pt_regs *regs)
+static int ppc4xx_pic_get_irq(void)
{
u32 uic0 = mfdcr(DCRN_UIC_MSR(UIC0));
return uic0 ? 32 - ffs(uic0) : -1;
diff --git a/arch/ppc/syslib/ppc85xx_rio.c b/arch/ppc/syslib/ppc85xx_rio.c
index d9b471b4d695..05b0e9415085 100644
--- a/arch/ppc/syslib/ppc85xx_rio.c
+++ b/arch/ppc/syslib/ppc85xx_rio.c
@@ -349,13 +349,12 @@ EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
* mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler
* @irq: Linux interrupt number
* @dev_instance: Pointer to interrupt-specific data
- * @regs: Register context
*
* Handles outbound message interrupts. Executes a register outbound
* mailbox event handler and acks the interrupt occurence.
*/
static irqreturn_t
-mpc85xx_rio_tx_handler(int irq, void *dev_instance, struct pt_regs *regs)
+mpc85xx_rio_tx_handler(int irq, void *dev_instance)
{
int osr;
struct rio_mport *port = (struct rio_mport *)dev_instance;
@@ -517,13 +516,12 @@ void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
* mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler
* @irq: Linux interrupt number
* @dev_instance: Pointer to interrupt-specific data
- * @regs: Register context
*
* Handles inbound message interrupts. Executes a registered inbound
* mailbox event handler and acks the interrupt occurence.
*/
static irqreturn_t
-mpc85xx_rio_rx_handler(int irq, void *dev_instance, struct pt_regs *regs)
+mpc85xx_rio_rx_handler(int irq, void *dev_instance)
{
int isr;
struct rio_mport *port = (struct rio_mport *)dev_instance;
@@ -736,13 +734,12 @@ EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
* mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler
* @irq: Linux interrupt number
* @dev_instance: Pointer to interrupt-specific data
- * @regs: Register context
*
* Handles doorbell interrupts. Parses a list of registered
* doorbell event handlers and executes a matching event handler.
*/
static irqreturn_t
-mpc85xx_rio_dbell_handler(int irq, void *dev_instance, struct pt_regs *regs)
+mpc85xx_rio_dbell_handler(int irq, void *dev_instance)
{
int dsr;
struct rio_mport *port = (struct rio_mport *)dev_instance;
diff --git a/arch/ppc/syslib/ppc8xx_pic.c b/arch/ppc/syslib/ppc8xx_pic.c
index d6c25fe25011..e8619c750732 100644
--- a/arch/ppc/syslib/ppc8xx_pic.c
+++ b/arch/ppc/syslib/ppc8xx_pic.c
@@ -10,7 +10,7 @@
#include <asm/mpc8xx.h>
#include "ppc8xx_pic.h"
-extern int cpm_get_irq(struct pt_regs *regs);
+extern int cpm_get_irq(void);
/* The 8xx internal interrupt controller. It is usually
* the only interrupt controller. Some boards, like the MBX and
@@ -96,7 +96,7 @@ m8xx_get_irq(struct pt_regs *regs)
* get back SIU_LEVEL7. In this case, return -1
*/
if (irq == CPM_INTERRUPT)
- irq = CPM_IRQ_OFFSET + cpm_get_irq(regs);
+ irq = CPM_IRQ_OFFSET + cpm_get_irq();
#if defined(CONFIG_PCI)
else if (irq == ISA_BRIDGE_INT) {
int isa_irq;
diff --git a/arch/ppc/syslib/xilinx_pic.c b/arch/ppc/syslib/xilinx_pic.c
index 39a93dc6375b..6fd4cdbada72 100644
--- a/arch/ppc/syslib/xilinx_pic.c
+++ b/arch/ppc/syslib/xilinx_pic.c
@@ -86,7 +86,7 @@ static struct hw_interrupt_type xilinx_intc = {
};
int
-xilinx_pic_get_irq(struct pt_regs *regs)
+xilinx_pic_get_irq(void)
{
int irq;
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index b216ca659cdf..608193cfe43f 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -30,6 +30,9 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+config GENERIC_TIME
+ def_bool y
+
config GENERIC_BUST_SPINLOCK
bool
@@ -51,6 +54,10 @@ config 64BIT
Select this option if you have a 64 bit IBM zSeries machine
and want to use the 64 bit addressing mode.
+config 32BIT
+ bool
+ default y if !64BIT
+
config SMP
bool "Symmetric multi-processing support"
---help---
@@ -149,6 +156,14 @@ config MARCH_Z990
This will be slightly faster but does not work on
older machines such as the z900.
+config MARCH_Z9_109
+ bool "IBM System z9"
+ help
+ Select this to enable optimizations for IBM System z9-109, IBM
+ System z9 Enterprise Class (z9 EC), and IBM System z9 Business
+ Class (z9 BC). The kernel will be slightly faster but will not
+ work on older machines such as the z990, z890, z900, and z800.
+
endchoice
config PACK_STACK
@@ -221,6 +236,9 @@ config WARN_STACK_SIZE
This allows you to specify the maximum frame size a function may
have without the compiler complaining about it.
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
source "mm/Kconfig"
comment "I/O subsystem configuration"
diff --git a/arch/s390/Makefile b/arch/s390/Makefile
index 74ef57dcfa60..5deb9f7544a1 100644
--- a/arch/s390/Makefile
+++ b/arch/s390/Makefile
@@ -33,6 +33,7 @@ endif
cflags-$(CONFIG_MARCH_G5) += $(call cc-option,-march=g5)
cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900)
cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990)
+cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109)
#
# Prevent tail-call optimizations, to get clearer backtraces:
diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c
index b69ed742f981..45c9fa7d7545 100644
--- a/arch/s390/appldata/appldata_base.c
+++ b/arch/s390/appldata/appldata_base.c
@@ -16,7 +16,7 @@
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/proc_fs.h>
-#include <linux/page-flags.h>
+#include <linux/mm.h>
#include <linux/swap.h>
#include <linux/pagemap.h>
#include <linux/sysctl.h>
@@ -109,7 +109,7 @@ static LIST_HEAD(appldata_ops_list);
*
* schedule work and reschedule timer
*/
-static void appldata_timer_function(unsigned long data, struct pt_regs *regs)
+static void appldata_timer_function(unsigned long data)
{
P_DEBUG(" -= Timer =-\n");
P_DEBUG("CPU: %i, expire_count: %i\n", smp_processor_id(),
@@ -157,12 +157,12 @@ int appldata_diag(char record_nr, u16 function, unsigned long buffer,
.prod_nr = {0xD3, 0xC9, 0xD5, 0xE4,
0xE7, 0xD2, 0xD9}, /* "LINUXKR" */
.prod_fn = 0xD5D3, /* "NL" */
- .record_nr = record_nr,
.version_nr = 0xF2F6, /* "26" */
.release_nr = 0xF0F1, /* "01" */
- .mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1],
};
+ id.record_nr = record_nr;
+ id.mod_lvl = (mod_lvl[0]) << 8 | mod_lvl[1];
return appldata_asm(&id, function, (void *) buffer, length);
}
/************************ timer, work, DIAG <END> ****************************/
diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
index efd836c2e4a6..2b137089f625 100644
--- a/arch/s390/crypto/crypt_s390.h
+++ b/arch/s390/crypto/crypt_s390.h
@@ -105,63 +105,6 @@ struct crypt_s390_query_status {
};
/*
- * Standard fixup and ex_table sections for crypt_s390 inline functions.
- * label 0: the s390 crypto operation
- * label 1: just after 1 to catch illegal operation exception
- * (unsupported model)
- * label 6: the return point after fixup
- * label 7: set error value if exception _in_ crypto operation
- * label 8: set error value if illegal operation exception
- * [ret] is the variable to receive the error code
- * [ERR] is the error code value
- */
-#ifndef CONFIG_64BIT
-#define __crypt_s390_fixup \
- ".section .fixup,\"ax\" \n" \
- "7: lhi %0,%h[e1] \n" \
- " bras 1,9f \n" \
- " .long 6b \n" \
- "8: lhi %0,%h[e2] \n" \
- " bras 1,9f \n" \
- " .long 6b \n" \
- "9: l 1,0(1) \n" \
- " br 1 \n" \
- ".previous \n" \
- ".section __ex_table,\"a\" \n" \
- " .align 4 \n" \
- " .long 0b,7b \n" \
- " .long 1b,8b \n" \
- ".previous"
-#else /* CONFIG_64BIT */
-#define __crypt_s390_fixup \
- ".section .fixup,\"ax\" \n" \
- "7: lhi %0,%h[e1] \n" \
- " jg 6b \n" \
- "8: lhi %0,%h[e2] \n" \
- " jg 6b \n" \
- ".previous\n" \
- ".section __ex_table,\"a\" \n" \
- " .align 8 \n" \
- " .quad 0b,7b \n" \
- " .quad 1b,8b \n" \
- ".previous"
-#endif /* CONFIG_64BIT */
-
-/*
- * Standard code for setting the result of s390 crypto instructions.
- * %0: the register which will receive the result
- * [result]: the register containing the result (e.g. second operand length
- * to compute number of processed bytes].
- */
-#ifndef CONFIG_64BIT
-#define __crypt_s390_set_result \
- " lr %0,%[result] \n"
-#else /* CONFIG_64BIT */
-#define __crypt_s390_set_result \
- " lgr %0,%[result] \n"
-#endif
-
-/*
* Executes the KM (CIPHER MESSAGE) operation of the CPU.
* @param func: the function code passed to KM; see crypt_s390_km_func
* @param param: address of parameter block; see POP for details on each func
@@ -176,28 +119,24 @@ crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
register void* __param asm("1") = param;
- register u8* __dest asm("4") = dest;
register const u8* __src asm("2") = src;
register long __src_len asm("3") = src_len;
+ register u8* __dest asm("4") = dest;
int ret;
- ret = 0;
- __asm__ __volatile__ (
- "0: .insn rre,0xB92E0000,%1,%2 \n" /* KM opcode */
+ asm volatile(
+ "0: .insn rre,0xb92e0000,%3,%1 \n" /* KM opcode */
"1: brc 1,0b \n" /* handle partial completion */
- __crypt_s390_set_result
- "6: \n"
- __crypt_s390_fixup
- : "+d" (ret), "+a" (__dest), "+a" (__src),
- [result] "+d" (__src_len)
- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
- "a" (__param)
- : "cc", "memory"
- );
- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
- ret = src_len - ret;
- }
- return ret;
+ " ahi %0,%h7\n"
+ "2: ahi %0,%h8\n"
+ "3:\n"
+ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
+ : "d" (__func), "a" (__param), "0" (-EFAULT),
+ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
/*
@@ -215,28 +154,24 @@ crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len)
{
register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
register void* __param asm("1") = param;
- register u8* __dest asm("4") = dest;
register const u8* __src asm("2") = src;
register long __src_len asm("3") = src_len;
+ register u8* __dest asm("4") = dest;
int ret;
- ret = 0;
- __asm__ __volatile__ (
- "0: .insn rre,0xB92F0000,%1,%2 \n" /* KMC opcode */
+ asm volatile(
+ "0: .insn rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
"1: brc 1,0b \n" /* handle partial completion */
- __crypt_s390_set_result
- "6: \n"
- __crypt_s390_fixup
- : "+d" (ret), "+a" (__dest), "+a" (__src),
- [result] "+d" (__src_len)
- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
- "a" (__param)
- : "cc", "memory"
- );
- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
- ret = src_len - ret;
- }
- return ret;
+ " ahi %0,%h7\n"
+ "2: ahi %0,%h8\n"
+ "3:\n"
+ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
+ : "d" (__func), "a" (__param), "0" (-EFAULT),
+ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
/*
@@ -258,22 +193,19 @@ crypt_s390_kimd(long func, void* param, const u8* src, long src_len)
register long __src_len asm("3") = src_len;
int ret;
- ret = 0;
- __asm__ __volatile__ (
- "0: .insn rre,0xB93E0000,%1,%1 \n" /* KIMD opcode */
- "1: brc 1,0b \n" /* handle partical completion */
- __crypt_s390_set_result
- "6: \n"
- __crypt_s390_fixup
- : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
- "a" (__param)
- : "cc", "memory"
- );
- if (ret >= 0 && (func & CRYPT_S390_FUNC_MASK)){
- ret = src_len - ret;
- }
- return ret;
+ asm volatile(
+ "0: .insn rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " ahi %0,%h6\n"
+ "2: ahi %0,%h7\n"
+ "3:\n"
+ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len)
+ : "d" (__func), "a" (__param), "0" (-EFAULT),
+ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
/*
@@ -294,22 +226,19 @@ crypt_s390_klmd(long func, void* param, const u8* src, long src_len)
register long __src_len asm("3") = src_len;
int ret;
- ret = 0;
- __asm__ __volatile__ (
- "0: .insn rre,0xB93F0000,%1,%1 \n" /* KLMD opcode */
- "1: brc 1,0b \n" /* handle partical completion */
- __crypt_s390_set_result
- "6: \n"
- __crypt_s390_fixup
- : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
- "a" (__param)
- : "cc", "memory"
- );
- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
- ret = src_len - ret;
- }
- return ret;
+ asm volatile(
+ "0: .insn rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " ahi %0,%h6\n"
+ "2: ahi %0,%h7\n"
+ "3:\n"
+ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len)
+ : "d" (__func), "a" (__param), "0" (-EFAULT),
+ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
/*
@@ -331,22 +260,19 @@ crypt_s390_kmac(long func, void* param, const u8* src, long src_len)
register long __src_len asm("3") = src_len;
int ret;
- ret = 0;
- __asm__ __volatile__ (
- "0: .insn rre,0xB91E0000,%5,%5 \n" /* KMAC opcode */
- "1: brc 1,0b \n" /* handle partical completion */
- __crypt_s390_set_result
- "6: \n"
- __crypt_s390_fixup
- : "+d" (ret), "+a" (__src), [result] "+d" (__src_len)
- : [e1] "K" (-EFAULT), [e2] "K" (-ENOSYS), "d" (__func),
- "a" (__param)
- : "cc", "memory"
- );
- if (ret >= 0 && func & CRYPT_S390_FUNC_MASK){
- ret = src_len - ret;
- }
- return ret;
+ asm volatile(
+ "0: .insn rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
+ "1: brc 1,0b \n" /* handle partial completion */
+ " ahi %0,%h6\n"
+ "2: ahi %0,%h7\n"
+ "3:\n"
+ EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+ : "=d" (ret), "+a" (__src), "+d" (__src_len)
+ : "d" (__func), "a" (__param), "0" (-EFAULT),
+ "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+ if (ret < 0)
+ return ret;
+ return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
}
/**
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 35da53986b1b..c313e9a9304f 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc2
-# Thu Jul 27 13:51:07 2006
+# Linux kernel version: 2.6.19-rc2
+# Wed Oct 18 17:11:10 2006
#
CONFIG_MMU=y
CONFIG_LOCKDEP_SUPPORT=y
@@ -9,6 +9,7 @@ CONFIG_STACKTRACE_SUPPORT=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
CONFIG_S390=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -26,10 +27,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
-CONFIG_SYSCTL=y
+# CONFIG_UTS_NS is not set
CONFIG_AUDIT=y
# CONFIG_AUDITSYSCALL is not set
CONFIG_IKCONFIG=y
@@ -38,7 +40,9 @@ CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -47,12 +51,12 @@ CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -71,6 +75,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_BLK_DEV_IO_TRACE is not set
#
@@ -100,6 +105,7 @@ CONFIG_HOTPLUG_CPU=y
CONFIG_DEFAULT_MIGRATION_COST=1000000
CONFIG_COMPAT=y
CONFIG_SYSVIPC_COMPAT=y
+CONFIG_AUDIT_ARCH=y
#
# Code generation options
@@ -107,11 +113,13 @@ CONFIG_SYSVIPC_COMPAT=y
# CONFIG_MARCH_G5 is not set
CONFIG_MARCH_Z900=y
# CONFIG_MARCH_Z990 is not set
+# CONFIG_MARCH_Z9_109 is not set
CONFIG_PACK_STACK=y
# CONFIG_SMALL_STACK is not set
CONFIG_CHECK_STACK=y
CONFIG_STACK_GUARD=256
# CONFIG_WARN_STACK is not set
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -165,6 +173,7 @@ CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_XFRM=y
# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
CONFIG_NET_KEY=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
@@ -183,21 +192,29 @@ CONFIG_IP_FIB_HASH=y
# CONFIG_INET_TUNNEL is not set
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_IPV6=y
# CONFIG_IPV6_PRIVACY is not set
# CONFIG_IPV6_ROUTER_PREF is not set
# CONFIG_INET6_AH is not set
# CONFIG_INET6_ESP is not set
# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
CONFIG_INET6_XFRM_MODE_TRANSPORT=y
CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -224,7 +241,6 @@ CONFIG_INET6_XFRM_MODE_TUNNEL=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -301,6 +317,7 @@ CONFIG_SYS_HYPERVISOR=y
#
# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -322,18 +339,18 @@ CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
#
-# SCSI Transport Attributes
+# SCSI Transports
#
# CONFIG_SCSI_SPI_ATTRS is not set
CONFIG_SCSI_FC_ATTRS=y
# CONFIG_SCSI_ISCSI_ATTRS is not set
# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
#
# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_DEBUG is not set
CONFIG_ZFCP=y
CONFIG_CCW=y
@@ -378,6 +395,7 @@ CONFIG_MD_RAID1=m
CONFIG_MD_MULTIPATH=m
# CONFIG_MD_FAULTY is not set
CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
CONFIG_DM_CRYPT=y
CONFIG_DM_SNAPSHOT=y
CONFIG_DM_MIRROR=y
@@ -487,14 +505,12 @@ CONFIG_IUCV=m
# CONFIG_NETIUCV is not set
# CONFIG_SMSGIUCV is not set
# CONFIG_CLAW is not set
-# CONFIG_MPC is not set
CONFIG_QETH=y
#
# Gigabit Ethernet default settings
#
# CONFIG_QETH_IPV6 is not set
-# CONFIG_QETH_PERF_STATS is not set
CONFIG_CCWGROUP=y
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
@@ -513,13 +529,15 @@ CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -549,8 +567,10 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -598,6 +618,7 @@ CONFIG_SUNRPC=y
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
# CONFIG_9P_FS is not set
+CONFIG_GENERIC_ACL=y
#
# Partition Types
@@ -629,8 +650,11 @@ CONFIG_MSDOS_PARTITION=y
#
# Instrumentation Support
#
+
+#
+# Profiling support
+#
# CONFIG_PROFILING is not set
-CONFIG_STATISTICS=y
CONFIG_KPROBES=y
#
@@ -638,11 +662,11 @@ CONFIG_KPROBES=y
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=17
-# CONFIG_DETECT_SOFTLOCKUP is not set
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
CONFIG_DEBUG_PREEMPT=y
@@ -659,10 +683,13 @@ CONFIG_DEBUG_SPINLOCK_SLEEP=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
# CONFIG_FRAME_POINTER is not set
# CONFIG_UNWIND_INFO is not set
CONFIG_FORCED_INLINING=y
+CONFIG_HEADERS_CHECK=y
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
#
# Security options
@@ -674,6 +701,9 @@ CONFIG_FORCED_INLINING=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -685,6 +715,8 @@ CONFIG_CRYPTO=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
# CONFIG_CRYPTO_DES is not set
# CONFIG_CRYPTO_DES_S390 is not set
# CONFIG_CRYPTO_BLOWFISH is not set
diff --git a/arch/s390/hypfs/hypfs_diag.c b/arch/s390/hypfs/hypfs_diag.c
index 75144efbb92b..443fa377d9ff 100644
--- a/arch/s390/hypfs/hypfs_diag.c
+++ b/arch/s390/hypfs/hypfs_diag.c
@@ -333,22 +333,14 @@ static int diag204(unsigned long subcode, unsigned long size, void *addr)
register unsigned long _subcode asm("0") = subcode;
register unsigned long _size asm("1") = size;
- asm volatile (" diag %2,%0,0x204\n"
- "0: \n" ".section __ex_table,\"a\"\n"
-#ifndef __s390x__
- " .align 4\n"
- " .long 0b,0b\n"
-#else
- " .align 8\n"
- " .quad 0b,0b\n"
-#endif
- ".previous":"+d" (_subcode), "+d"(_size)
- :"d"(addr)
- :"memory");
+ asm volatile(
+ " diag %2,%0,0x204\n"
+ "0:\n"
+ EX_TABLE(0b,0b)
+ : "+d" (_subcode), "+d" (_size) : "d" (addr) : "memory");
if (_subcode)
return -1;
- else
- return _size;
+ return _size;
}
/*
@@ -403,7 +395,8 @@ static void *diag204_get_buffer(enum diag204_format fmt, int *pages)
*pages = 1;
return diag204_alloc_rbuf();
} else {/* INFO_EXT */
- *pages = diag204(SUBC_RSI | INFO_EXT, 0, NULL);
+ *pages = diag204((unsigned long)SUBC_RSI |
+ (unsigned long)INFO_EXT, 0, NULL);
if (*pages <= 0)
return ERR_PTR(-ENOSYS);
else
@@ -490,8 +483,7 @@ out:
static void diag224(void *ptr)
{
- asm volatile(" diag %0,%1,0x224\n"
- : :"d" (0), "d"(ptr) : "memory");
+ asm volatile("diag %0,%1,0x224" : :"d" (0), "d"(ptr) : "memory");
}
static int diag224_get_name_table(void)
diff --git a/arch/s390/hypfs/inode.c b/arch/s390/hypfs/inode.c
index bdade5f2e325..cd702ae45d6d 100644
--- a/arch/s390/hypfs/inode.c
+++ b/arch/s390/hypfs/inode.c
@@ -91,7 +91,6 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
ret->i_mode = mode;
ret->i_uid = hypfs_info->uid;
ret->i_gid = hypfs_info->gid;
- ret->i_blksize = PAGE_CACHE_SIZE;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
if (mode & S_IFDIR)
@@ -104,13 +103,13 @@ static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
static void hypfs_drop_inode(struct inode *inode)
{
- kfree(inode->u.generic_ip);
+ kfree(inode->i_private);
generic_delete_inode(inode);
}
static int hypfs_open(struct inode *inode, struct file *filp)
{
- char *data = filp->f_dentry->d_inode->u.generic_ip;
+ char *data = filp->f_dentry->d_inode->i_private;
struct hypfs_sb_info *fs_info;
if (filp->f_mode & FMODE_WRITE) {
@@ -135,12 +134,20 @@ static int hypfs_open(struct inode *inode, struct file *filp)
return 0;
}
-static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
- size_t count, loff_t offset)
+static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
{
char *data;
size_t len;
struct file *filp = iocb->ki_filp;
+ /* XXX: temporary */
+ char __user *buf = iov[0].iov_base;
+ size_t count = iov[0].iov_len;
+
+ if (nr_segs != 1) {
+ count = -EINVAL;
+ goto out;
+ }
data = filp->private_data;
len = strlen(data);
@@ -159,12 +166,13 @@ static ssize_t hypfs_aio_read(struct kiocb *iocb, __user char *buf,
out:
return count;
}
-static ssize_t hypfs_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
+static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t offset)
{
int rc;
struct super_block *sb;
struct hypfs_sb_info *fs_info;
+ size_t count = iov_length(iov, nr_segs);
sb = iocb->ki_filp->f_dentry->d_inode->i_sb;
fs_info = sb->s_fs_info;
@@ -352,7 +360,7 @@ static struct dentry *hypfs_create_file(struct super_block *sb,
parent->d_inode->i_nlink++;
} else
BUG();
- inode->u.generic_ip = data;
+ inode->i_private = data;
d_instantiate(dentry, inode);
dget(dentry);
return dentry;
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index 785c9f70ac98..2001767e1dc7 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -295,6 +295,7 @@ static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
*
* This is really horribly ugly.
*/
+#ifdef CONFIG_SYSVIPC
asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr)
{
if (call >> 16) /* hack for backward compatibility */
@@ -338,6 +339,7 @@ asmlinkage long sys32_ipc(u32 call, int first, int second, int third, u32 ptr)
return -ENOSYS;
}
+#endif
asmlinkage long sys32_truncate64(const char __user * path, unsigned long high, unsigned long low)
{
@@ -357,11 +359,16 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
+ compat_ino_t ino;
int err;
if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
return -EOVERFLOW;
+ ino = stat->ino;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
err |= put_user(stat->ino, &statbuf->st_ino);
err |= put_user(stat->mode, &statbuf->st_mode);
@@ -544,10 +551,7 @@ sys32_execve(struct pt_regs regs)
current->ptrace &= ~PT_DTRACE;
task_unlock(current);
current->thread.fp_regs.fpc=0;
- __asm__ __volatile__
- ("sr 0,0\n\t"
- "sfpc 0,0\n\t"
- : : :"0");
+ asm volatile("sfpc %0,0" : : "d" (0));
}
putname(filename);
out:
@@ -708,7 +712,7 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
return ret;
}
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL_SYSCALL
struct __sysctl_args32 {
u32 name;
int nlen;
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 4d53b2739357..cb0efae6802f 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -4,97 +4,97 @@
*
* Copyright (C) IBM Corp. 2000,2006
* Author(s): Gerhard Tonn (ton@de.ibm.com),
-* Thomas Spatzier (tspat@de.ibm.com)
-*/
+* Thomas Spatzier (tspat@de.ibm.com)
+*/
- .globl sys32_exit_wrapper
+ .globl sys32_exit_wrapper
sys32_exit_wrapper:
lgfr %r2,%r2 # int
jg sys_exit # branch to sys_exit
-
- .globl sys32_read_wrapper
+
+ .globl sys32_read_wrapper
sys32_read_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # char *
llgfr %r4,%r4 # size_t
jg sys32_read # branch to sys_read
- .globl sys32_write_wrapper
+ .globl sys32_write_wrapper
sys32_write_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # const char *
llgfr %r4,%r4 # size_t
jg sys32_write # branch to system call
- .globl sys32_open_wrapper
+ .globl sys32_open_wrapper
sys32_open_wrapper:
llgtr %r2,%r2 # const char *
lgfr %r3,%r3 # int
lgfr %r4,%r4 # int
jg sys_open # branch to system call
- .globl sys32_close_wrapper
+ .globl sys32_close_wrapper
sys32_close_wrapper:
llgfr %r2,%r2 # unsigned int
jg sys_close # branch to system call
- .globl sys32_creat_wrapper
+ .globl sys32_creat_wrapper
sys32_creat_wrapper:
llgtr %r2,%r2 # const char *
lgfr %r3,%r3 # int
jg sys_creat # branch to system call
- .globl sys32_link_wrapper
+ .globl sys32_link_wrapper
sys32_link_wrapper:
llgtr %r2,%r2 # const char *
llgtr %r3,%r3 # const char *
jg sys_link # branch to system call
- .globl sys32_unlink_wrapper
+ .globl sys32_unlink_wrapper
sys32_unlink_wrapper:
llgtr %r2,%r2 # const char *
jg sys_unlink # branch to system call
- .globl sys32_chdir_wrapper
+ .globl sys32_chdir_wrapper
sys32_chdir_wrapper:
llgtr %r2,%r2 # const char *
jg sys_chdir # branch to system call
- .globl sys32_time_wrapper
+ .globl sys32_time_wrapper
sys32_time_wrapper:
llgtr %r2,%r2 # int *
jg compat_sys_time # branch to system call
- .globl sys32_mknod_wrapper
+ .globl sys32_mknod_wrapper
sys32_mknod_wrapper:
llgtr %r2,%r2 # const char *
- lgfr %r3,%r3 # int
+ lgfr %r3,%r3 # int
llgfr %r4,%r4 # dev
jg sys_mknod # branch to system call
- .globl sys32_chmod_wrapper
+ .globl sys32_chmod_wrapper
sys32_chmod_wrapper:
llgtr %r2,%r2 # const char *
llgfr %r3,%r3 # mode_t
jg sys_chmod # branch to system call
- .globl sys32_lchown16_wrapper
+ .globl sys32_lchown16_wrapper
sys32_lchown16_wrapper:
llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
jg sys32_lchown16 # branch to system call
- .globl sys32_lseek_wrapper
+ .globl sys32_lseek_wrapper
sys32_lseek_wrapper:
llgfr %r2,%r2 # unsigned int
lgfr %r3,%r3 # off_t
llgfr %r4,%r4 # unsigned int
jg sys_lseek # branch to system call
-#sys32_getpid_wrapper # void
+#sys32_getpid_wrapper # void
- .globl sys32_mount_wrapper
+ .globl sys32_mount_wrapper
sys32_mount_wrapper:
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # char *
@@ -103,19 +103,19 @@ sys32_mount_wrapper:
llgtr %r6,%r6 # void *
jg compat_sys_mount # branch to system call
- .globl sys32_oldumount_wrapper
+ .globl sys32_oldumount_wrapper
sys32_oldumount_wrapper:
llgtr %r2,%r2 # char *
jg sys_oldumount # branch to system call
- .globl sys32_setuid16_wrapper
+ .globl sys32_setuid16_wrapper
sys32_setuid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
jg sys32_setuid16 # branch to system call
-#sys32_getuid16_wrapper # void
+#sys32_getuid16_wrapper # void
- .globl sys32_ptrace_wrapper
+ .globl sys32_ptrace_wrapper
sys32_ptrace_wrapper:
lgfr %r2,%r2 # long
lgfr %r3,%r3 # long
@@ -123,168 +123,168 @@ sys32_ptrace_wrapper:
llgfr %r5,%r5 # long
jg sys_ptrace # branch to system call
- .globl sys32_alarm_wrapper
+ .globl sys32_alarm_wrapper
sys32_alarm_wrapper:
llgfr %r2,%r2 # unsigned int
jg sys_alarm # branch to system call
-#sys32_pause_wrapper # void
+#sys32_pause_wrapper # void
- .globl compat_sys_utime_wrapper
+ .globl compat_sys_utime_wrapper
compat_sys_utime_wrapper:
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # struct compat_utimbuf *
jg compat_sys_utime # branch to system call
- .globl sys32_access_wrapper
+ .globl sys32_access_wrapper
sys32_access_wrapper:
llgtr %r2,%r2 # const char *
lgfr %r3,%r3 # int
jg sys_access # branch to system call
- .globl sys32_nice_wrapper
+ .globl sys32_nice_wrapper
sys32_nice_wrapper:
lgfr %r2,%r2 # int
jg sys_nice # branch to system call
-#sys32_sync_wrapper # void
+#sys32_sync_wrapper # void
- .globl sys32_kill_wrapper
+ .globl sys32_kill_wrapper
sys32_kill_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
jg sys_kill # branch to system call
- .globl sys32_rename_wrapper
+ .globl sys32_rename_wrapper
sys32_rename_wrapper:
llgtr %r2,%r2 # const char *
llgtr %r3,%r3 # const char *
jg sys_rename # branch to system call
- .globl sys32_mkdir_wrapper
+ .globl sys32_mkdir_wrapper
sys32_mkdir_wrapper:
llgtr %r2,%r2 # const char *
lgfr %r3,%r3 # int
jg sys_mkdir # branch to system call
- .globl sys32_rmdir_wrapper
+ .globl sys32_rmdir_wrapper
sys32_rmdir_wrapper:
llgtr %r2,%r2 # const char *
jg sys_rmdir # branch to system call
- .globl sys32_dup_wrapper
+ .globl sys32_dup_wrapper
sys32_dup_wrapper:
llgfr %r2,%r2 # unsigned int
jg sys_dup # branch to system call
- .globl sys32_pipe_wrapper
+ .globl sys32_pipe_wrapper
sys32_pipe_wrapper:
llgtr %r2,%r2 # u32 *
jg sys_pipe # branch to system call
- .globl compat_sys_times_wrapper
+ .globl compat_sys_times_wrapper
compat_sys_times_wrapper:
llgtr %r2,%r2 # struct compat_tms *
jg compat_sys_times # branch to system call
- .globl sys32_brk_wrapper
+ .globl sys32_brk_wrapper
sys32_brk_wrapper:
llgtr %r2,%r2 # unsigned long
jg sys_brk # branch to system call
- .globl sys32_setgid16_wrapper
+ .globl sys32_setgid16_wrapper
sys32_setgid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
jg sys32_setgid16 # branch to system call
-#sys32_getgid16_wrapper # void
+#sys32_getgid16_wrapper # void
.globl sys32_signal_wrapper
sys32_signal_wrapper:
- lgfr %r2,%r2 # int
+ lgfr %r2,%r2 # int
llgtr %r3,%r3 # __sighandler_t
jg sys_signal
-#sys32_geteuid16_wrapper # void
+#sys32_geteuid16_wrapper # void
-#sys32_getegid16_wrapper # void
+#sys32_getegid16_wrapper # void
- .globl sys32_acct_wrapper
+ .globl sys32_acct_wrapper
sys32_acct_wrapper:
llgtr %r2,%r2 # char *
jg sys_acct # branch to system call
- .globl sys32_umount_wrapper
+ .globl sys32_umount_wrapper
sys32_umount_wrapper:
llgtr %r2,%r2 # char *
lgfr %r3,%r3 # int
jg sys_umount # branch to system call
- .globl compat_sys_ioctl_wrapper
+ .globl compat_sys_ioctl_wrapper
compat_sys_ioctl_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # unsigned int
llgfr %r4,%r4 # unsigned int
jg compat_sys_ioctl # branch to system call
- .globl compat_sys_fcntl_wrapper
+ .globl compat_sys_fcntl_wrapper
compat_sys_fcntl_wrapper:
llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
+ llgfr %r3,%r3 # unsigned int
llgfr %r4,%r4 # unsigned long
jg compat_sys_fcntl # branch to system call
- .globl sys32_setpgid_wrapper
+ .globl sys32_setpgid_wrapper
sys32_setpgid_wrapper:
lgfr %r2,%r2 # pid_t
lgfr %r3,%r3 # pid_t
jg sys_setpgid # branch to system call
- .globl sys32_umask_wrapper
+ .globl sys32_umask_wrapper
sys32_umask_wrapper:
lgfr %r2,%r2 # int
jg sys_umask # branch to system call
- .globl sys32_chroot_wrapper
+ .globl sys32_chroot_wrapper
sys32_chroot_wrapper:
llgtr %r2,%r2 # char *
jg sys_chroot # branch to system call
.globl sys32_ustat_wrapper
sys32_ustat_wrapper:
- llgfr %r2,%r2 # dev_t
+ llgfr %r2,%r2 # dev_t
llgtr %r3,%r3 # struct ustat *
jg sys_ustat
- .globl sys32_dup2_wrapper
+ .globl sys32_dup2_wrapper
sys32_dup2_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # unsigned int
jg sys_dup2 # branch to system call
-#sys32_getppid_wrapper # void
+#sys32_getppid_wrapper # void
-#sys32_getpgrp_wrapper # void
+#sys32_getpgrp_wrapper # void
-#sys32_setsid_wrapper # void
+#sys32_setsid_wrapper # void
- .globl sys32_sigaction_wrapper
+ .globl sys32_sigaction_wrapper
sys32_sigaction_wrapper:
- lgfr %r2,%r2 # int
+ lgfr %r2,%r2 # int
llgtr %r3,%r3 # const struct old_sigaction *
llgtr %r4,%r4 # struct old_sigaction32 *
jg sys32_sigaction # branch to system call
- .globl sys32_setreuid16_wrapper
+ .globl sys32_setreuid16_wrapper
sys32_setreuid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
jg sys32_setreuid16 # branch to system call
- .globl sys32_setregid16_wrapper
+ .globl sys32_setregid16_wrapper
sys32_setregid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
jg sys32_setregid16 # branch to system call
.globl sys_sigsuspend_wrapper
@@ -294,95 +294,95 @@ sys_sigsuspend_wrapper:
llgfr %r4,%r4 # old_sigset_t
jg sys_sigsuspend
- .globl compat_sys_sigpending_wrapper
+ .globl compat_sys_sigpending_wrapper
compat_sys_sigpending_wrapper:
llgtr %r2,%r2 # compat_old_sigset_t *
jg compat_sys_sigpending # branch to system call
- .globl sys32_sethostname_wrapper
+ .globl sys32_sethostname_wrapper
sys32_sethostname_wrapper:
llgtr %r2,%r2 # char *
lgfr %r3,%r3 # int
jg sys_sethostname # branch to system call
- .globl compat_sys_setrlimit_wrapper
+ .globl compat_sys_setrlimit_wrapper
compat_sys_setrlimit_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # struct rlimit_emu31 *
jg compat_sys_setrlimit # branch to system call
- .globl compat_sys_old_getrlimit_wrapper
+ .globl compat_sys_old_getrlimit_wrapper
compat_sys_old_getrlimit_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # struct rlimit_emu31 *
jg compat_sys_old_getrlimit # branch to system call
- .globl compat_sys_getrlimit_wrapper
+ .globl compat_sys_getrlimit_wrapper
compat_sys_getrlimit_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # struct rlimit_emu31 *
jg compat_sys_getrlimit # branch to system call
- .globl sys32_mmap2_wrapper
+ .globl sys32_mmap2_wrapper
sys32_mmap2_wrapper:
llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
jg sys32_mmap2 # branch to system call
- .globl compat_sys_getrusage_wrapper
+ .globl compat_sys_getrusage_wrapper
compat_sys_getrusage_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # struct rusage_emu31 *
jg compat_sys_getrusage # branch to system call
- .globl sys32_gettimeofday_wrapper
+ .globl sys32_gettimeofday_wrapper
sys32_gettimeofday_wrapper:
llgtr %r2,%r2 # struct timeval_emu31 *
llgtr %r3,%r3 # struct timezone *
jg sys32_gettimeofday # branch to system call
- .globl sys32_settimeofday_wrapper
+ .globl sys32_settimeofday_wrapper
sys32_settimeofday_wrapper:
llgtr %r2,%r2 # struct timeval_emu31 *
llgtr %r3,%r3 # struct timezone *
jg sys32_settimeofday # branch to system call
- .globl sys32_getgroups16_wrapper
+ .globl sys32_getgroups16_wrapper
sys32_getgroups16_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
jg sys32_getgroups16 # branch to system call
- .globl sys32_setgroups16_wrapper
+ .globl sys32_setgroups16_wrapper
sys32_setgroups16_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
jg sys32_setgroups16 # branch to system call
- .globl sys32_symlink_wrapper
+ .globl sys32_symlink_wrapper
sys32_symlink_wrapper:
llgtr %r2,%r2 # const char *
llgtr %r3,%r3 # const char *
jg sys_symlink # branch to system call
- .globl sys32_readlink_wrapper
+ .globl sys32_readlink_wrapper
sys32_readlink_wrapper:
llgtr %r2,%r2 # const char *
llgtr %r3,%r3 # char *
lgfr %r4,%r4 # int
jg sys_readlink # branch to system call
- .globl sys32_uselib_wrapper
+ .globl sys32_uselib_wrapper
sys32_uselib_wrapper:
llgtr %r2,%r2 # const char *
jg sys_uselib # branch to system call
- .globl sys32_swapon_wrapper
+ .globl sys32_swapon_wrapper
sys32_swapon_wrapper:
llgtr %r2,%r2 # const char *
lgfr %r3,%r3 # int
jg sys_swapon # branch to system call
- .globl sys32_reboot_wrapper
+ .globl sys32_reboot_wrapper
sys32_reboot_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
@@ -390,121 +390,121 @@ sys32_reboot_wrapper:
llgtr %r5,%r5 # void *
jg sys_reboot # branch to system call
- .globl old32_readdir_wrapper
+ .globl old32_readdir_wrapper
old32_readdir_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # void *
llgfr %r4,%r4 # unsigned int
jg compat_sys_old_readdir # branch to system call
- .globl old32_mmap_wrapper
+ .globl old32_mmap_wrapper
old32_mmap_wrapper:
llgtr %r2,%r2 # struct mmap_arg_struct_emu31 *
jg old32_mmap # branch to system call
- .globl sys32_munmap_wrapper
+ .globl sys32_munmap_wrapper
sys32_munmap_wrapper:
llgfr %r2,%r2 # unsigned long
- llgfr %r3,%r3 # size_t
+ llgfr %r3,%r3 # size_t
jg sys_munmap # branch to system call
- .globl sys32_truncate_wrapper
+ .globl sys32_truncate_wrapper
sys32_truncate_wrapper:
llgtr %r2,%r2 # const char *
llgfr %r3,%r3 # unsigned long
jg sys_truncate # branch to system call
- .globl sys32_ftruncate_wrapper
+ .globl sys32_ftruncate_wrapper
sys32_ftruncate_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # unsigned long
jg sys_ftruncate # branch to system call
- .globl sys32_fchmod_wrapper
+ .globl sys32_fchmod_wrapper
sys32_fchmod_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # mode_t
jg sys_fchmod # branch to system call
- .globl sys32_fchown16_wrapper
+ .globl sys32_fchown16_wrapper
sys32_fchown16_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # compat_uid_t
llgfr %r4,%r4 # compat_uid_t
jg sys32_fchown16 # branch to system call
- .globl sys32_getpriority_wrapper
+ .globl sys32_getpriority_wrapper
sys32_getpriority_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
jg sys_getpriority # branch to system call
- .globl sys32_setpriority_wrapper
+ .globl sys32_setpriority_wrapper
sys32_setpriority_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
lgfr %r4,%r4 # int
jg sys_setpriority # branch to system call
- .globl compat_sys_statfs_wrapper
+ .globl compat_sys_statfs_wrapper
compat_sys_statfs_wrapper:
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # struct compat_statfs *
jg compat_sys_statfs # branch to system call
- .globl compat_sys_fstatfs_wrapper
+ .globl compat_sys_fstatfs_wrapper
compat_sys_fstatfs_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # struct compat_statfs *
jg compat_sys_fstatfs # branch to system call
- .globl compat_sys_socketcall_wrapper
+ .globl compat_sys_socketcall_wrapper
compat_sys_socketcall_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # u32 *
jg compat_sys_socketcall # branch to system call
- .globl sys32_syslog_wrapper
+ .globl sys32_syslog_wrapper
sys32_syslog_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # char *
lgfr %r4,%r4 # int
jg sys_syslog # branch to system call
- .globl compat_sys_setitimer_wrapper
+ .globl compat_sys_setitimer_wrapper
compat_sys_setitimer_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # struct itimerval_emu31 *
llgtr %r4,%r4 # struct itimerval_emu31 *
jg compat_sys_setitimer # branch to system call
- .globl compat_sys_getitimer_wrapper
+ .globl compat_sys_getitimer_wrapper
compat_sys_getitimer_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # struct itimerval_emu31 *
jg compat_sys_getitimer # branch to system call
- .globl compat_sys_newstat_wrapper
+ .globl compat_sys_newstat_wrapper
compat_sys_newstat_wrapper:
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # struct stat_emu31 *
jg compat_sys_newstat # branch to system call
- .globl compat_sys_newlstat_wrapper
+ .globl compat_sys_newlstat_wrapper
compat_sys_newlstat_wrapper:
llgtr %r2,%r2 # char *
llgtr %r3,%r3 # struct stat_emu31 *
jg compat_sys_newlstat # branch to system call
- .globl compat_sys_newfstat_wrapper
+ .globl compat_sys_newfstat_wrapper
compat_sys_newfstat_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # struct stat_emu31 *
jg compat_sys_newfstat # branch to system call
-#sys32_vhangup_wrapper # void
+#sys32_vhangup_wrapper # void
- .globl compat_sys_wait4_wrapper
+ .globl compat_sys_wait4_wrapper
compat_sys_wait4_wrapper:
lgfr %r2,%r2 # pid_t
llgtr %r3,%r3 # unsigned int *
@@ -512,17 +512,17 @@ compat_sys_wait4_wrapper:
llgtr %r5,%r5 # struct rusage *
jg compat_sys_wait4 # branch to system call
- .globl sys32_swapoff_wrapper
+ .globl sys32_swapoff_wrapper
sys32_swapoff_wrapper:
llgtr %r2,%r2 # const char *
jg sys_swapoff # branch to system call
- .globl sys32_sysinfo_wrapper
+ .globl sys32_sysinfo_wrapper
sys32_sysinfo_wrapper:
llgtr %r2,%r2 # struct sysinfo_emu31 *
jg sys32_sysinfo # branch to system call
- .globl sys32_ipc_wrapper
+ .globl sys32_ipc_wrapper
sys32_ipc_wrapper:
llgfr %r2,%r2 # uint
lgfr %r3,%r3 # int
@@ -531,59 +531,59 @@ sys32_ipc_wrapper:
llgfr %r6,%r6 # u32
jg sys32_ipc # branch to system call
- .globl sys32_fsync_wrapper
+ .globl sys32_fsync_wrapper
sys32_fsync_wrapper:
llgfr %r2,%r2 # unsigned int
jg sys_fsync # branch to system call
-#sys32_sigreturn_wrapper # done in sigreturn_glue
+#sys32_sigreturn_wrapper # done in sigreturn_glue
-#sys32_clone_wrapper # done in clone_glue
+#sys32_clone_wrapper # done in clone_glue
- .globl sys32_setdomainname_wrapper
+ .globl sys32_setdomainname_wrapper
sys32_setdomainname_wrapper:
llgtr %r2,%r2 # char *
lgfr %r3,%r3 # int
jg sys_setdomainname # branch to system call
- .globl sys32_newuname_wrapper
+ .globl sys32_newuname_wrapper
sys32_newuname_wrapper:
llgtr %r2,%r2 # struct new_utsname *
jg s390x_newuname # branch to system call
- .globl compat_sys_adjtimex_wrapper
+ .globl compat_sys_adjtimex_wrapper
compat_sys_adjtimex_wrapper:
llgtr %r2,%r2 # struct compat_timex *
jg compat_sys_adjtimex # branch to system call
- .globl sys32_mprotect_wrapper
+ .globl sys32_mprotect_wrapper
sys32_mprotect_wrapper:
llgtr %r2,%r2 # unsigned long (actually pointer
llgfr %r3,%r3 # size_t
llgfr %r4,%r4 # unsigned long
jg sys_mprotect # branch to system call
- .globl compat_sys_sigprocmask_wrapper
+ .globl compat_sys_sigprocmask_wrapper
compat_sys_sigprocmask_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # compat_old_sigset_t *
llgtr %r4,%r4 # compat_old_sigset_t *
jg compat_sys_sigprocmask # branch to system call
- .globl sys32_init_module_wrapper
+ .globl sys32_init_module_wrapper
sys32_init_module_wrapper:
llgtr %r2,%r2 # void *
llgfr %r3,%r3 # unsigned long
llgtr %r4,%r4 # char *
jg sys32_init_module # branch to system call
- .globl sys32_delete_module_wrapper
+ .globl sys32_delete_module_wrapper
sys32_delete_module_wrapper:
llgtr %r2,%r2 # const char *
llgfr %r3,%r3 # unsigned int
jg sys32_delete_module # branch to system call
- .globl sys32_quotactl_wrapper
+ .globl sys32_quotactl_wrapper
sys32_quotactl_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # const char *
@@ -591,45 +591,45 @@ sys32_quotactl_wrapper:
llgtr %r5,%r5 # caddr_t
jg sys_quotactl # branch to system call
- .globl sys32_getpgid_wrapper
+ .globl sys32_getpgid_wrapper
sys32_getpgid_wrapper:
lgfr %r2,%r2 # pid_t
jg sys_getpgid # branch to system call
- .globl sys32_fchdir_wrapper
+ .globl sys32_fchdir_wrapper
sys32_fchdir_wrapper:
llgfr %r2,%r2 # unsigned int
jg sys_fchdir # branch to system call
- .globl sys32_bdflush_wrapper
+ .globl sys32_bdflush_wrapper
sys32_bdflush_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # long
jg sys_bdflush # branch to system call
- .globl sys32_sysfs_wrapper
+ .globl sys32_sysfs_wrapper
sys32_sysfs_wrapper:
lgfr %r2,%r2 # int
llgfr %r3,%r3 # unsigned long
llgfr %r4,%r4 # unsigned long
jg sys_sysfs # branch to system call
- .globl sys32_personality_wrapper
+ .globl sys32_personality_wrapper
sys32_personality_wrapper:
llgfr %r2,%r2 # unsigned long
jg s390x_personality # branch to system call
- .globl sys32_setfsuid16_wrapper
+ .globl sys32_setfsuid16_wrapper
sys32_setfsuid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
jg sys32_setfsuid16 # branch to system call
- .globl sys32_setfsgid16_wrapper
+ .globl sys32_setfsgid16_wrapper
sys32_setfsgid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
jg sys32_setfsgid16 # branch to system call
- .globl sys32_llseek_wrapper
+ .globl sys32_llseek_wrapper
sys32_llseek_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # unsigned long
@@ -638,14 +638,14 @@ sys32_llseek_wrapper:
llgfr %r6,%r6 # unsigned int
jg sys_llseek # branch to system call
- .globl sys32_getdents_wrapper
+ .globl sys32_getdents_wrapper
sys32_getdents_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # void *
llgfr %r4,%r4 # unsigned int
jg compat_sys_getdents # branch to system call
- .globl compat_sys_select_wrapper
+ .globl compat_sys_select_wrapper
compat_sys_select_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # compat_fd_set *
@@ -654,113 +654,113 @@ compat_sys_select_wrapper:
llgtr %r6,%r6 # struct compat_timeval *
jg compat_sys_select # branch to system call
- .globl sys32_flock_wrapper
+ .globl sys32_flock_wrapper
sys32_flock_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # unsigned int
jg sys_flock # branch to system call
- .globl sys32_msync_wrapper
+ .globl sys32_msync_wrapper
sys32_msync_wrapper:
llgfr %r2,%r2 # unsigned long
llgfr %r3,%r3 # size_t
lgfr %r4,%r4 # int
jg sys_msync # branch to system call
- .globl compat_sys_readv_wrapper
+ .globl compat_sys_readv_wrapper
compat_sys_readv_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # const struct compat_iovec *
llgfr %r4,%r4 # unsigned long
jg compat_sys_readv # branch to system call
- .globl compat_sys_writev_wrapper
+ .globl compat_sys_writev_wrapper
compat_sys_writev_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # const struct compat_iovec *
llgfr %r4,%r4 # unsigned long
jg compat_sys_writev # branch to system call
- .globl sys32_getsid_wrapper
+ .globl sys32_getsid_wrapper
sys32_getsid_wrapper:
lgfr %r2,%r2 # pid_t
jg sys_getsid # branch to system call
- .globl sys32_fdatasync_wrapper
+ .globl sys32_fdatasync_wrapper
sys32_fdatasync_wrapper:
llgfr %r2,%r2 # unsigned int
jg sys_fdatasync # branch to system call
-#sys32_sysctl_wrapper # tbd
+#sys32_sysctl_wrapper # tbd
- .globl sys32_mlock_wrapper
+ .globl sys32_mlock_wrapper
sys32_mlock_wrapper:
llgfr %r2,%r2 # unsigned long
llgfr %r3,%r3 # size_t
jg sys_mlock # branch to system call
- .globl sys32_munlock_wrapper
+ .globl sys32_munlock_wrapper
sys32_munlock_wrapper:
llgfr %r2,%r2 # unsigned long
llgfr %r3,%r3 # size_t
jg sys_munlock # branch to system call
- .globl sys32_mlockall_wrapper
+ .globl sys32_mlockall_wrapper
sys32_mlockall_wrapper:
lgfr %r2,%r2 # int
jg sys_mlockall # branch to system call
-#sys32_munlockall_wrapper # void
+#sys32_munlockall_wrapper # void
- .globl sys32_sched_setparam_wrapper
+ .globl sys32_sched_setparam_wrapper
sys32_sched_setparam_wrapper:
lgfr %r2,%r2 # pid_t
llgtr %r3,%r3 # struct sched_param *
jg sys_sched_setparam # branch to system call
- .globl sys32_sched_getparam_wrapper
+ .globl sys32_sched_getparam_wrapper
sys32_sched_getparam_wrapper:
lgfr %r2,%r2 # pid_t
llgtr %r3,%r3 # struct sched_param *
jg sys_sched_getparam # branch to system call
- .globl sys32_sched_setscheduler_wrapper
+ .globl sys32_sched_setscheduler_wrapper
sys32_sched_setscheduler_wrapper:
lgfr %r2,%r2 # pid_t
lgfr %r3,%r3 # int
llgtr %r4,%r4 # struct sched_param *
jg sys_sched_setscheduler # branch to system call
- .globl sys32_sched_getscheduler_wrapper
+ .globl sys32_sched_getscheduler_wrapper
sys32_sched_getscheduler_wrapper:
lgfr %r2,%r2 # pid_t
jg sys_sched_getscheduler # branch to system call
-#sys32_sched_yield_wrapper # void
+#sys32_sched_yield_wrapper # void
- .globl sys32_sched_get_priority_max_wrapper
+ .globl sys32_sched_get_priority_max_wrapper
sys32_sched_get_priority_max_wrapper:
lgfr %r2,%r2 # int
jg sys_sched_get_priority_max # branch to system call
- .globl sys32_sched_get_priority_min_wrapper
+ .globl sys32_sched_get_priority_min_wrapper
sys32_sched_get_priority_min_wrapper:
lgfr %r2,%r2 # int
jg sys_sched_get_priority_min # branch to system call
- .globl sys32_sched_rr_get_interval_wrapper
+ .globl sys32_sched_rr_get_interval_wrapper
sys32_sched_rr_get_interval_wrapper:
lgfr %r2,%r2 # pid_t
llgtr %r3,%r3 # struct compat_timespec *
jg sys32_sched_rr_get_interval # branch to system call
- .globl compat_sys_nanosleep_wrapper
+ .globl compat_sys_nanosleep_wrapper
compat_sys_nanosleep_wrapper:
llgtr %r2,%r2 # struct compat_timespec *
llgtr %r3,%r3 # struct compat_timespec *
jg compat_sys_nanosleep # branch to system call
- .globl sys32_mremap_wrapper
+ .globl sys32_mremap_wrapper
sys32_mremap_wrapper:
llgfr %r2,%r2 # unsigned long
llgfr %r3,%r3 # unsigned long
@@ -769,49 +769,49 @@ sys32_mremap_wrapper:
llgfr %r6,%r6 # unsigned long
jg sys_mremap # branch to system call
- .globl sys32_setresuid16_wrapper
+ .globl sys32_setresuid16_wrapper
sys32_setresuid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_uid_emu31_t
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_uid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_uid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_uid_emu31_t
jg sys32_setresuid16 # branch to system call
- .globl sys32_getresuid16_wrapper
+ .globl sys32_getresuid16_wrapper
sys32_getresuid16_wrapper:
llgtr %r2,%r2 # __kernel_old_uid_emu31_t *
llgtr %r3,%r3 # __kernel_old_uid_emu31_t *
llgtr %r4,%r4 # __kernel_old_uid_emu31_t *
jg sys32_getresuid16 # branch to system call
- .globl sys32_poll_wrapper
+ .globl sys32_poll_wrapper
sys32_poll_wrapper:
- llgtr %r2,%r2 # struct pollfd *
- llgfr %r3,%r3 # unsigned int
- lgfr %r4,%r4 # long
+ llgtr %r2,%r2 # struct pollfd *
+ llgfr %r3,%r3 # unsigned int
+ lgfr %r4,%r4 # long
jg sys_poll # branch to system call
- .globl compat_sys_nfsservctl_wrapper
+ .globl compat_sys_nfsservctl_wrapper
compat_sys_nfsservctl_wrapper:
- lgfr %r2,%r2 # int
+ lgfr %r2,%r2 # int
llgtr %r3,%r3 # struct compat_nfsctl_arg*
llgtr %r4,%r4 # union compat_nfsctl_res*
jg compat_sys_nfsservctl # branch to system call
- .globl sys32_setresgid16_wrapper
+ .globl sys32_setresgid16_wrapper
sys32_setresgid16_wrapper:
- llgfr %r2,%r2 # __kernel_old_gid_emu31_t
- llgfr %r3,%r3 # __kernel_old_gid_emu31_t
- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ llgfr %r2,%r2 # __kernel_old_gid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_gid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
jg sys32_setresgid16 # branch to system call
- .globl sys32_getresgid16_wrapper
+ .globl sys32_getresgid16_wrapper
sys32_getresgid16_wrapper:
llgtr %r2,%r2 # __kernel_old_gid_emu31_t *
llgtr %r3,%r3 # __kernel_old_gid_emu31_t *
llgtr %r4,%r4 # __kernel_old_gid_emu31_t *
jg sys32_getresgid16 # branch to system call
- .globl sys32_prctl_wrapper
+ .globl sys32_prctl_wrapper
sys32_prctl_wrapper:
lgfr %r2,%r2 # int
llgfr %r3,%r3 # unsigned long
@@ -820,9 +820,9 @@ sys32_prctl_wrapper:
llgfr %r6,%r6 # unsigned long
jg sys_prctl # branch to system call
-#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
+#sys32_rt_sigreturn_wrapper # done in rt_sigreturn_glue
- .globl sys32_rt_sigaction_wrapper
+ .globl sys32_rt_sigaction_wrapper
sys32_rt_sigaction_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # const struct sigaction_emu31 *
@@ -830,7 +830,7 @@ sys32_rt_sigaction_wrapper:
llgfr %r5,%r5 # size_t
jg sys32_rt_sigaction # branch to system call
- .globl sys32_rt_sigprocmask_wrapper
+ .globl sys32_rt_sigprocmask_wrapper
sys32_rt_sigprocmask_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # old_sigset_emu31 *
@@ -838,13 +838,13 @@ sys32_rt_sigprocmask_wrapper:
llgfr %r5,%r5 # size_t
jg sys32_rt_sigprocmask # branch to system call
- .globl sys32_rt_sigpending_wrapper
+ .globl sys32_rt_sigpending_wrapper
sys32_rt_sigpending_wrapper:
llgtr %r2,%r2 # sigset_emu31 *
llgfr %r3,%r3 # size_t
jg sys32_rt_sigpending # branch to system call
- .globl compat_sys_rt_sigtimedwait_wrapper
+ .globl compat_sys_rt_sigtimedwait_wrapper
compat_sys_rt_sigtimedwait_wrapper:
llgtr %r2,%r2 # const sigset_emu31_t *
llgtr %r3,%r3 # siginfo_emu31_t *
@@ -852,7 +852,7 @@ compat_sys_rt_sigtimedwait_wrapper:
llgfr %r5,%r5 # size_t
jg compat_sys_rt_sigtimedwait # branch to system call
- .globl sys32_rt_sigqueueinfo_wrapper
+ .globl sys32_rt_sigqueueinfo_wrapper
sys32_rt_sigqueueinfo_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
@@ -865,7 +865,7 @@ compat_sys_rt_sigsuspend_wrapper:
llgfr %r3,%r3 # compat_size_t
jg compat_sys_rt_sigsuspend
- .globl sys32_pread64_wrapper
+ .globl sys32_pread64_wrapper
sys32_pread64_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # char *
@@ -874,7 +874,7 @@ sys32_pread64_wrapper:
llgfr %r6,%r6 # u32
jg sys32_pread64 # branch to system call
- .globl sys32_pwrite64_wrapper
+ .globl sys32_pwrite64_wrapper
sys32_pwrite64_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # const char *
@@ -883,26 +883,26 @@ sys32_pwrite64_wrapper:
llgfr %r6,%r6 # u32
jg sys32_pwrite64 # branch to system call
- .globl sys32_chown16_wrapper
+ .globl sys32_chown16_wrapper
sys32_chown16_wrapper:
llgtr %r2,%r2 # const char *
- llgfr %r3,%r3 # __kernel_old_uid_emu31_t
- llgfr %r4,%r4 # __kernel_old_gid_emu31_t
+ llgfr %r3,%r3 # __kernel_old_uid_emu31_t
+ llgfr %r4,%r4 # __kernel_old_gid_emu31_t
jg sys32_chown16 # branch to system call
- .globl sys32_getcwd_wrapper
+ .globl sys32_getcwd_wrapper
sys32_getcwd_wrapper:
llgtr %r2,%r2 # char *
llgfr %r3,%r3 # unsigned long
jg sys_getcwd # branch to system call
- .globl sys32_capget_wrapper
+ .globl sys32_capget_wrapper
sys32_capget_wrapper:
llgtr %r2,%r2 # cap_user_header_t
llgtr %r3,%r3 # cap_user_data_t
jg sys_capget # branch to system call
- .globl sys32_capset_wrapper
+ .globl sys32_capset_wrapper
sys32_capset_wrapper:
llgtr %r2,%r2 # cap_user_header_t
llgtr %r3,%r3 # const cap_user_data_t
@@ -910,11 +910,11 @@ sys32_capset_wrapper:
.globl sys32_sigaltstack_wrapper
sys32_sigaltstack_wrapper:
- llgtr %r2,%r2 # const stack_emu31_t *
- llgtr %r3,%r3 # stack_emu31_t *
+ llgtr %r2,%r2 # const stack_emu31_t *
+ llgtr %r3,%r3 # stack_emu31_t *
jg sys32_sigaltstack
- .globl sys32_sendfile_wrapper
+ .globl sys32_sendfile_wrapper
sys32_sendfile_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
@@ -922,33 +922,33 @@ sys32_sendfile_wrapper:
llgfr %r5,%r5 # size_t
jg sys32_sendfile # branch to system call
-#sys32_vfork_wrapper # done in vfork_glue
+#sys32_vfork_wrapper # done in vfork_glue
- .globl sys32_truncate64_wrapper
+ .globl sys32_truncate64_wrapper
sys32_truncate64_wrapper:
llgtr %r2,%r2 # const char *
llgfr %r3,%r3 # unsigned long
llgfr %r4,%r4 # unsigned long
jg sys32_truncate64 # branch to system call
- .globl sys32_ftruncate64_wrapper
+ .globl sys32_ftruncate64_wrapper
sys32_ftruncate64_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # unsigned long
llgfr %r4,%r4 # unsigned long
jg sys32_ftruncate64 # branch to system call
- .globl sys32_lchown_wrapper
+ .globl sys32_lchown_wrapper
sys32_lchown_wrapper:
llgtr %r2,%r2 # const char *
llgfr %r3,%r3 # uid_t
llgfr %r4,%r4 # gid_t
jg sys_lchown # branch to system call
-#sys32_getuid_wrapper # void
-#sys32_getgid_wrapper # void
-#sys32_geteuid_wrapper # void
-#sys32_getegid_wrapper # void
+#sys32_getuid_wrapper # void
+#sys32_getgid_wrapper # void
+#sys32_geteuid_wrapper # void
+#sys32_getegid_wrapper # void
.globl sys32_setreuid_wrapper
sys32_setreuid_wrapper:
@@ -962,111 +962,111 @@ sys32_setregid_wrapper:
llgfr %r3,%r3 # gid_t
jg sys_setregid # branch to system call
- .globl sys32_getgroups_wrapper
+ .globl sys32_getgroups_wrapper
sys32_getgroups_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # gid_t *
jg sys_getgroups # branch to system call
- .globl sys32_setgroups_wrapper
+ .globl sys32_setgroups_wrapper
sys32_setgroups_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # gid_t *
jg sys_setgroups # branch to system call
- .globl sys32_fchown_wrapper
+ .globl sys32_fchown_wrapper
sys32_fchown_wrapper:
llgfr %r2,%r2 # unsigned int
llgfr %r3,%r3 # uid_t
llgfr %r4,%r4 # gid_t
jg sys_fchown # branch to system call
- .globl sys32_setresuid_wrapper
+ .globl sys32_setresuid_wrapper
sys32_setresuid_wrapper:
llgfr %r2,%r2 # uid_t
llgfr %r3,%r3 # uid_t
llgfr %r4,%r4 # uid_t
jg sys_setresuid # branch to system call
- .globl sys32_getresuid_wrapper
+ .globl sys32_getresuid_wrapper
sys32_getresuid_wrapper:
llgtr %r2,%r2 # uid_t *
llgtr %r3,%r3 # uid_t *
llgtr %r4,%r4 # uid_t *
jg sys_getresuid # branch to system call
- .globl sys32_setresgid_wrapper
+ .globl sys32_setresgid_wrapper
sys32_setresgid_wrapper:
llgfr %r2,%r2 # gid_t
llgfr %r3,%r3 # gid_t
llgfr %r4,%r4 # gid_t
jg sys_setresgid # branch to system call
- .globl sys32_getresgid_wrapper
+ .globl sys32_getresgid_wrapper
sys32_getresgid_wrapper:
llgtr %r2,%r2 # gid_t *
llgtr %r3,%r3 # gid_t *
llgtr %r4,%r4 # gid_t *
jg sys_getresgid # branch to system call
- .globl sys32_chown_wrapper
+ .globl sys32_chown_wrapper
sys32_chown_wrapper:
llgtr %r2,%r2 # const char *
llgfr %r3,%r3 # uid_t
llgfr %r4,%r4 # gid_t
jg sys_chown # branch to system call
- .globl sys32_setuid_wrapper
+ .globl sys32_setuid_wrapper
sys32_setuid_wrapper:
llgfr %r2,%r2 # uid_t
jg sys_setuid # branch to system call
- .globl sys32_setgid_wrapper
+ .globl sys32_setgid_wrapper
sys32_setgid_wrapper:
llgfr %r2,%r2 # gid_t
jg sys_setgid # branch to system call
- .globl sys32_setfsuid_wrapper
+ .globl sys32_setfsuid_wrapper
sys32_setfsuid_wrapper:
llgfr %r2,%r2 # uid_t
jg sys_setfsuid # branch to system call
- .globl sys32_setfsgid_wrapper
+ .globl sys32_setfsgid_wrapper
sys32_setfsgid_wrapper:
llgfr %r2,%r2 # gid_t
jg sys_setfsgid # branch to system call
- .globl sys32_pivot_root_wrapper
+ .globl sys32_pivot_root_wrapper
sys32_pivot_root_wrapper:
llgtr %r2,%r2 # const char *
llgtr %r3,%r3 # const char *
jg sys_pivot_root # branch to system call
- .globl sys32_mincore_wrapper
+ .globl sys32_mincore_wrapper
sys32_mincore_wrapper:
llgfr %r2,%r2 # unsigned long
llgfr %r3,%r3 # size_t
llgtr %r4,%r4 # unsigned char *
jg sys_mincore # branch to system call
- .globl sys32_madvise_wrapper
+ .globl sys32_madvise_wrapper
sys32_madvise_wrapper:
llgfr %r2,%r2 # unsigned long
llgfr %r3,%r3 # size_t
lgfr %r4,%r4 # int
jg sys_madvise # branch to system call
- .globl sys32_getdents64_wrapper
+ .globl sys32_getdents64_wrapper
sys32_getdents64_wrapper:
llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # void *
llgfr %r4,%r4 # unsigned int
jg sys_getdents64 # branch to system call
- .globl compat_sys_fcntl64_wrapper
+ .globl compat_sys_fcntl64_wrapper
compat_sys_fcntl64_wrapper:
llgfr %r2,%r2 # unsigned int
- llgfr %r3,%r3 # unsigned int
+ llgfr %r3,%r3 # unsigned int
llgfr %r4,%r4 # unsigned long
jg compat_sys_fcntl64 # branch to system call
@@ -1087,10 +1087,10 @@ sys32_stime_wrapper:
llgtr %r2,%r2 # long *
jg compat_sys_stime # branch to system call
- .globl sys32_sysctl_wrapper
+ .globl sys32_sysctl_wrapper
sys32_sysctl_wrapper:
- llgtr %r2,%r2 # struct __sysctl_args32 *
- jg sys32_sysctl
+ llgtr %r2,%r2 # struct __sysctl_args32 *
+ jg sys32_sysctl
.globl sys32_fstat64_wrapper
sys32_fstat64_wrapper:
@@ -1098,7 +1098,7 @@ sys32_fstat64_wrapper:
llgtr %r3,%r3 # struct stat64 *
jg sys32_fstat64 # branch to system call
- .globl compat_sys_futex_wrapper
+ .globl compat_sys_futex_wrapper
compat_sys_futex_wrapper:
llgtr %r2,%r2 # u32 *
lgfr %r3,%r3 # int
@@ -1213,22 +1213,22 @@ sys32_sched_getaffinity_wrapper:
llgtr %r4,%r4 # unsigned long *
jg compat_sys_sched_getaffinity
- .globl sys32_exit_group_wrapper
+ .globl sys32_exit_group_wrapper
sys32_exit_group_wrapper:
lgfr %r2,%r2 # int
jg sys_exit_group # branch to system call
- .globl sys32_set_tid_address_wrapper
+ .globl sys32_set_tid_address_wrapper
sys32_set_tid_address_wrapper:
llgtr %r2,%r2 # int *
jg sys_set_tid_address # branch to system call
- .globl sys_epoll_create_wrapper
+ .globl sys_epoll_create_wrapper
sys_epoll_create_wrapper:
lgfr %r2,%r2 # int
jg sys_epoll_create # branch to system call
- .globl sys_epoll_ctl_wrapper
+ .globl sys_epoll_ctl_wrapper
sys_epoll_ctl_wrapper:
lgfr %r2,%r2 # int
lgfr %r3,%r3 # int
@@ -1236,7 +1236,7 @@ sys_epoll_ctl_wrapper:
llgtr %r5,%r5 # struct epoll_event *
jg sys_epoll_ctl # branch to system call
- .globl sys_epoll_wait_wrapper
+ .globl sys_epoll_wait_wrapper
sys_epoll_wait_wrapper:
lgfr %r2,%r2 # int
llgtr %r3,%r3 # struct epoll_event *
@@ -1658,3 +1658,10 @@ compat_sys_vmsplice_wrapper:
llgfr %r4,%r4 # unsigned int
llgfr %r5,%r5 # unsigned int
jg compat_sys_vmsplice
+
+ .globl sys_getcpu_wrapper
+sys_getcpu_wrapper:
+ llgtr %r2,%r2 # unsigned *
+ llgtr %r3,%r3 # unsigned *
+ llgtr %r4,%r4 # struct getcpu_cache *
+ jg sys_tee
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index 4ef44e536b2c..1eae74e72f95 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -25,11 +25,8 @@ static char cpcmd_buf[241];
*/
int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
{
- const int mask = 0x40000000L;
- unsigned long flags;
- int return_code;
- int return_len;
- int cmdlen;
+ unsigned long flags, cmdlen;
+ int return_code, return_len;
spin_lock_irqsave(&cpcmd_lock, flags);
cmdlen = strlen(cmd);
@@ -38,64 +35,44 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
ASCEBC(cpcmd_buf, cmdlen);
if (response != NULL && rlen > 0) {
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = (addr_t) response;
+ register unsigned long reg4 asm ("4") = cmdlen | 0x40000000L;
+ register unsigned long reg5 asm ("5") = rlen;
+
memset(response, 0, rlen);
+ asm volatile(
#ifndef CONFIG_64BIT
- asm volatile ( "lra 2,0(%2)\n"
- "lr 4,%3\n"
- "o 4,%6\n"
- "lra 3,0(%4)\n"
- "lr 5,%5\n"
- "diag 2,4,0x8\n"
- "brc 8, 1f\n"
- "ar 5, %5\n"
- "1: \n"
- "lr %0,4\n"
- "lr %1,5\n"
- : "=d" (return_code), "=d" (return_len)
- : "a" (cpcmd_buf), "d" (cmdlen),
- "a" (response), "d" (rlen), "m" (mask)
- : "cc", "2", "3", "4", "5" );
+ " diag %2,%0,0x8\n"
+ " brc 8,1f\n"
+ " ar %1,%4\n"
#else /* CONFIG_64BIT */
- asm volatile ( "lrag 2,0(%2)\n"
- "lgr 4,%3\n"
- "o 4,%6\n"
- "lrag 3,0(%4)\n"
- "lgr 5,%5\n"
- "sam31\n"
- "diag 2,4,0x8\n"
- "sam64\n"
- "brc 8, 1f\n"
- "agr 5, %5\n"
- "1: \n"
- "lgr %0,4\n"
- "lgr %1,5\n"
- : "=d" (return_code), "=d" (return_len)
- : "a" (cpcmd_buf), "d" (cmdlen),
- "a" (response), "d" (rlen), "m" (mask)
- : "cc", "2", "3", "4", "5" );
+ " sam31\n"
+ " diag %2,%0,0x8\n"
+ " sam64\n"
+ " brc 8,1f\n"
+ " agr %1,%4\n"
#endif /* CONFIG_64BIT */
+ "1:\n"
+ : "+d" (reg4), "+d" (reg5)
+ : "d" (reg2), "d" (reg3), "d" (rlen) : "cc");
+ return_code = (int) reg4;
+ return_len = (int) reg5;
EBCASC(response, rlen);
} else {
+ register unsigned long reg2 asm ("2") = (addr_t) cpcmd_buf;
+ register unsigned long reg3 asm ("3") = cmdlen;
return_len = 0;
+ asm volatile(
#ifndef CONFIG_64BIT
- asm volatile ( "lra 2,0(%1)\n"
- "lr 3,%2\n"
- "diag 2,3,0x8\n"
- "lr %0,3\n"
- : "=d" (return_code)
- : "a" (cpcmd_buf), "d" (cmdlen)
- : "2", "3" );
+ " diag %1,%0,0x8\n"
#else /* CONFIG_64BIT */
- asm volatile ( "lrag 2,0(%1)\n"
- "lgr 3,%2\n"
- "sam31\n"
- "diag 2,3,0x8\n"
- "sam64\n"
- "lgr %0,3\n"
- : "=d" (return_code)
- : "a" (cpcmd_buf), "d" (cmdlen)
- : "2", "3" );
+ " sam31\n"
+ " diag %1,%0,0x8\n"
+ " sam64\n"
#endif /* CONFIG_64BIT */
+ : "+d" (reg3) : "d" (reg2) : "cc");
+ return_code = (int) reg3;
}
spin_unlock_irqrestore(&cpcmd_lock, flags);
if (response_code != NULL)
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index 7ba20922a535..43f3d0c7e132 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -603,7 +603,7 @@ debug_open(struct inode *inode, struct file *file)
debug_info_t *debug_info, *debug_info_snapshot;
down(&debug_lock);
- debug_info = (struct debug_info*)file->f_dentry->d_inode->u.generic_ip;
+ debug_info = file->f_dentry->d_inode->i_private;
/* find debug view */
for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
if (!debug_info->views[i])
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index 0c712b78a7e8..dddc3de30401 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -4,8 +4,8 @@
*
* Copyright (C) IBM Corp. 1999,2006
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- * Hartmut Penner (hp@de.ibm.com),
- * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Hartmut Penner (hp@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
* Heiko Carstens <heiko.carstens@de.ibm.com>
*/
@@ -24,29 +24,29 @@
* Stack layout for the system_call stack entry.
* The first few entries are identical to the user_regs_struct.
*/
-SP_PTREGS = STACK_FRAME_OVERHEAD
-SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
-SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
-SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
-SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4
-SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
-SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12
-SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
-SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20
-SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
-SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28
-SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
-SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36
-SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
-SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44
-SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
-SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52
-SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
-SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
-SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
-SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
-SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
-SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
+SP_PTREGS = STACK_FRAME_OVERHEAD
+SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
+SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
+SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
+SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 4
+SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 12
+SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 20
+SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 28
+SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 36
+SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 44
+SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 52
+SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 60
+SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
+SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
+SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
_TIF_MCCK_PENDING | _TIF_RESTART_SVC | _TIF_SINGLE_STEP )
@@ -81,14 +81,14 @@ STACK_SIZE = 1 << STACK_SHIFT
* R15 - kernel stack pointer
*/
- .macro STORE_TIMER lc_offset
+ .macro STORE_TIMER lc_offset
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
stpt \lc_offset
#endif
.endm
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- .macro UPDATE_VTIME lc_from,lc_to,lc_sum
+ .macro UPDATE_VTIME lc_from,lc_to,lc_sum
lm %r10,%r11,\lc_from
sl %r10,\lc_to
sl %r11,\lc_to+4
@@ -147,7 +147,7 @@ STACK_SIZE = 1 << STACK_SHIFT
2:
.endm
- .macro CREATE_STACK_FRAME psworg,savearea
+ .macro CREATE_STACK_FRAME psworg,savearea
s %r15,BASED(.Lc_spsize) # make room for registers & psw
mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
la %r12,\psworg
@@ -160,7 +160,7 @@ STACK_SIZE = 1 << STACK_SHIFT
st %r12,__SF_BACKCHAIN(%r15) # clear back chain
.endm
- .macro RESTORE_ALL psworg,sync
+ .macro RESTORE_ALL psworg,sync
mvc \psworg(8),SP_PSW(%r15) # move user PSW to lowcore
.if !\sync
ni \psworg+1,0xfd # clear wait state bit
@@ -177,16 +177,16 @@ STACK_SIZE = 1 << STACK_SHIFT
* Returns:
* gpr2 = prev
*/
- .globl __switch_to
+ .globl __switch_to
__switch_to:
- basr %r1,0
+ basr %r1,0
__switch_to_base:
tm __THREAD_per(%r3),0xe8 # new process is using per ?
bz __switch_to_noper-__switch_to_base(%r1) # if not we're fine
- stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff
- clc __THREAD_per(12,%r3),__SF_EMPTY(%r15)
- be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
- lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
+ stctl %c9,%c11,__SF_EMPTY(%r15) # We are using per stuff
+ clc __THREAD_per(12,%r3),__SF_EMPTY(%r15)
+ be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
+ lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
__switch_to_noper:
l %r4,__THREAD_info(%r2) # get thread_info of prev
tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
@@ -195,13 +195,13 @@ __switch_to_noper:
l %r4,__THREAD_info(%r3) # get thread_info of next
oi __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next
__switch_to_no_mcck:
- stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
+ stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
lm %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
st %r3,__LC_CURRENT # __LC_CURRENT = current task struct
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
- l %r3,__THREAD_info(%r3) # load thread_info from task struct
+ l %r3,__THREAD_info(%r3) # load thread_info from task struct
st %r3,__LC_THREAD_INFO
ahi %r3,STACK_SIZE
st %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
@@ -213,7 +213,7 @@ __critical_start:
* are executed with interrupts enabled.
*/
- .globl system_call
+ .globl system_call
system_call:
STORE_TIMER __LC_SYNC_ENTER_TIMER
sysc_saveall:
@@ -233,24 +233,24 @@ sysc_update:
#endif
sysc_do_svc:
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
- sla %r7,2 # *4 and test for svc 0
- bnz BASED(sysc_nr_ok) # svc number > 0
+ sla %r7,2 # *4 and test for svc 0
+ bnz BASED(sysc_nr_ok) # svc number > 0
# svc 0: system call number in %r1
cl %r1,BASED(.Lnr_syscalls)
bnl BASED(sysc_nr_ok)
- lr %r7,%r1 # copy svc number to %r7
- sla %r7,2 # *4
+ lr %r7,%r1 # copy svc number to %r7
+ sla %r7,2 # *4
sysc_nr_ok:
mvc SP_ARGS(4,%r15),SP_R7(%r15)
sysc_do_restart:
l %r8,BASED(.Lsysc_table)
tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
l %r8,0(%r7,%r8) # get system call addr.
- bnz BASED(sysc_tracesys)
- basr %r14,%r8 # call sys_xxxx
- st %r2,SP_R2(%r15) # store return value (change R2 on stack)
- # ATTENTION: check sys_execve_glue before
- # changing anything here !!
+ bnz BASED(sysc_tracesys)
+ basr %r14,%r8 # call sys_xxxx
+ st %r2,SP_R2(%r15) # store return value (change R2 on stack)
+ # ATTENTION: check sys_execve_glue before
+ # changing anything here !!
sysc_return:
tm SP_PSW+1(%r15),0x01 # returning to user ?
@@ -258,14 +258,14 @@ sysc_return:
tm __TI_flags+3(%r9),_TIF_WORK_SVC
bnz BASED(sysc_work) # there is work to do (signals etc.)
sysc_leave:
- RESTORE_ALL __LC_RETURN_PSW,1
+ RESTORE_ALL __LC_RETURN_PSW,1
#
# recheck if there is more work to do
#
sysc_work_loop:
tm __TI_flags+3(%r9),_TIF_WORK_SVC
- bz BASED(sysc_leave) # there is no work to do
+ bz BASED(sysc_leave) # there is no work to do
#
# One of the work bits is on. Find out which one.
#
@@ -284,11 +284,11 @@ sysc_work:
#
# _TIF_NEED_RESCHED is set, call schedule
-#
-sysc_reschedule:
- l %r1,BASED(.Lschedule)
- la %r14,BASED(sysc_work_loop)
- br %r1 # call scheduler
+#
+sysc_reschedule:
+ l %r1,BASED(.Lschedule)
+ la %r14,BASED(sysc_work_loop)
+ br %r1 # call scheduler
#
# _TIF_MCCK_PENDING is set, call handler
@@ -301,11 +301,11 @@ sysc_mcck_pending:
#
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
-sysc_sigpending:
+sysc_sigpending:
ni __TI_flags+3(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
- la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,BASED(.Ldo_signal)
- basr %r14,%r1 # call do_signal
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ldo_signal)
+ basr %r14,%r1 # call do_signal
tm __TI_flags+3(%r9),_TIF_RESTART_SVC
bo BASED(sysc_restart)
tm __TI_flags+3(%r9),_TIF_SINGLE_STEP
@@ -317,11 +317,11 @@ sysc_sigpending:
#
sysc_restart:
ni __TI_flags+3(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
- l %r7,SP_R2(%r15) # load new svc number
+ l %r7,SP_R2(%r15) # load new svc number
sla %r7,2
mvc SP_R2(4,%r15),SP_ORIG_R2(%r15) # restore first argument
- lm %r2,%r6,SP_R2(%r15) # load svc arguments
- b BASED(sysc_do_restart) # restart svc
+ lm %r2,%r6,SP_R2(%r15) # load svc arguments
+ b BASED(sysc_do_restart) # restart svc
#
# _TIF_SINGLE_STEP is set, call do_single_step
@@ -338,8 +338,8 @@ sysc_singlestep:
# call trace before and after sys_call
#
sysc_tracesys:
- l %r1,BASED(.Ltrace)
- la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ltrace)
+ la %r2,SP_PTREGS(%r15) # load pt_regs
la %r3,0
srl %r7,2
st %r7,SP_R2(%r15)
@@ -347,19 +347,19 @@ sysc_tracesys:
clc SP_R2(4,%r15),BASED(.Lnr_syscalls)
bnl BASED(sysc_tracenogo)
l %r8,BASED(.Lsysc_table)
- l %r7,SP_R2(%r15) # strace might have changed the
- sll %r7,2 # system call
+ l %r7,SP_R2(%r15) # strace might have changed the
+ sll %r7,2 # system call
l %r8,0(%r7,%r8)
sysc_tracego:
lm %r3,%r6,SP_R3(%r15)
l %r2,SP_ORIG_R2(%r15)
- basr %r14,%r8 # call sys_xxx
- st %r2,SP_R2(%r15) # store return value
+ basr %r14,%r8 # call sys_xxx
+ st %r2,SP_R2(%r15) # store return value
sysc_tracenogo:
tm __TI_flags+3(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
- bz BASED(sysc_return)
+ bz BASED(sysc_return)
l %r1,BASED(.Ltrace)
- la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r2,SP_PTREGS(%r15) # load pt_regs
la %r3,1
la %r14,BASED(sysc_return)
br %r1
@@ -367,17 +367,17 @@ sysc_tracenogo:
#
# a new process exits the kernel with ret_from_fork
#
- .globl ret_from_fork
+ .globl ret_from_fork
ret_from_fork:
l %r13,__LC_SVC_NEW_PSW+4
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
bo BASED(0f)
st %r15,SP_R15(%r15) # store stack pointer for new kthread
-0: l %r1,BASED(.Lschedtail)
- basr %r14,%r1
+0: l %r1,BASED(.Lschedtail)
+ basr %r14,%r1
TRACE_IRQS_ON
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
b BASED(sysc_return)
#
@@ -386,52 +386,51 @@ ret_from_fork:
# but are called with different parameter.
# return-address is set up above
#
-sys_clone_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,BASED(.Lclone)
- br %r1 # branch to sys_clone
-
-sys_fork_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,BASED(.Lfork)
- br %r1 # branch to sys_fork
-
-sys_vfork_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,BASED(.Lvfork)
- br %r1 # branch to sys_vfork
-
-sys_execve_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,BASED(.Lexecve)
- lr %r12,%r14 # save return address
- basr %r14,%r1 # call sys_execve
- ltr %r2,%r2 # check if execve failed
- bnz 0(%r12) # it did fail -> store result in gpr2
- b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8
- # in system_call/sysc_tracesys
-
-sys_sigreturn_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- l %r1,BASED(.Lsigreturn)
- br %r1 # branch to sys_sigreturn
-
-sys_rt_sigreturn_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- l %r1,BASED(.Lrt_sigreturn)
- br %r1 # branch to sys_sigreturn
+sys_clone_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Lclone)
+ br %r1 # branch to sys_clone
-sys_sigaltstack_glue:
- la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
- l %r1,BASED(.Lsigaltstack)
- br %r1 # branch to sys_sigreturn
+sys_fork_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Lfork)
+ br %r1 # branch to sys_fork
+sys_vfork_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Lvfork)
+ br %r1 # branch to sys_vfork
+
+sys_execve_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Lexecve)
+ lr %r12,%r14 # save return address
+ basr %r14,%r1 # call sys_execve
+ ltr %r2,%r2 # check if execve failed
+ bnz 0(%r12) # it did fail -> store result in gpr2
+ b 4(%r12) # SKIP ST 2,SP_R2(15) after BASR 14,8
+ # in system_call/sysc_tracesys
+
+sys_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ l %r1,BASED(.Lsigreturn)
+ br %r1 # branch to sys_sigreturn
+
+sys_rt_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ l %r1,BASED(.Lrt_sigreturn)
+ br %r1 # branch to sys_sigreturn
+
+sys_sigaltstack_glue:
+ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+ l %r1,BASED(.Lsigaltstack)
+ br %r1 # branch to sys_sigreturn
/*
* Program check handler routine
*/
- .globl pgm_check_handler
+ .globl pgm_check_handler
pgm_check_handler:
/*
* First we need to check for a special case:
@@ -448,8 +447,8 @@ pgm_check_handler:
*/
STORE_TIMER __LC_SYNC_ENTER_TIMER
SAVE_ALL_BASE __LC_SAVE_AREA
- tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
- bnz BASED(pgm_per) # got per exception -> special case
+ tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+ bnz BASED(pgm_per) # got per exception -> special case
SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -461,29 +460,29 @@ pgm_check_handler:
pgm_no_vtime:
#endif
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
- l %r3,__LC_PGM_ILC # load program interruption code
+ l %r3,__LC_PGM_ILC # load program interruption code
la %r8,0x7f
nr %r8,%r3
pgm_do_call:
- l %r7,BASED(.Ljump_table)
- sll %r8,2
- l %r7,0(%r8,%r7) # load address of handler routine
- la %r2,SP_PTREGS(%r15) # address of register-save area
- la %r14,BASED(sysc_return)
- br %r7 # branch to interrupt-handler
+ l %r7,BASED(.Ljump_table)
+ sll %r8,2
+ l %r7,0(%r8,%r7) # load address of handler routine
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ la %r14,BASED(sysc_return)
+ br %r7 # branch to interrupt-handler
#
# handle per exception
#
pgm_per:
- tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
- bnz BASED(pgm_per_std) # ok, normal per event from user space
+ tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
+ bnz BASED(pgm_per_std) # ok, normal per event from user space
# ok its one of the special cases, now we need to find out which one
- clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
- be BASED(pgm_svcper)
+ clc __LC_PGM_OLD_PSW(8),__LC_SVC_NEW_PSW
+ be BASED(pgm_svcper)
# no interesting special case, ignore PER event
- lm %r12,%r15,__LC_SAVE_AREA
- lpsw 0x28
+ lm %r12,%r15,__LC_SAVE_AREA
+ lpsw 0x28
#
# Normal per exception
@@ -507,10 +506,10 @@ pgm_no_vtime2:
oi __TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
tm SP_PSW+1(%r15),0x01 # kernel per event ?
bz BASED(kernel_per)
- l %r3,__LC_PGM_ILC # load program interruption code
+ l %r3,__LC_PGM_ILC # load program interruption code
la %r8,0x7f
- nr %r8,%r3 # clear per-event-bit and ilc
- be BASED(sysc_return) # only per or per+check ?
+ nr %r8,%r3 # clear per-event-bit and ilc
+ be BASED(sysc_return) # only per or per+check ?
b BASED(pgm_do_call)
#
@@ -552,7 +551,7 @@ kernel_per:
* IO interrupt handler routine
*/
- .globl io_int_handler
+ .globl io_int_handler
io_int_handler:
STORE_TIMER __LC_ASYNC_ENTER_TIMER
stck __LC_INT_CLOCK
@@ -569,42 +568,42 @@ io_no_vtime:
#endif
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
- l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
- la %r2,SP_PTREGS(%r15) # address of register-save area
- basr %r14,%r1 # branch to standard irq handler
+ l %r1,BASED(.Ldo_IRQ) # load address of do_IRQ
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ basr %r14,%r1 # branch to standard irq handler
TRACE_IRQS_ON
io_return:
- tm SP_PSW+1(%r15),0x01 # returning to user ?
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
#ifdef CONFIG_PREEMPT
- bno BASED(io_preempt) # no -> check for preemptive scheduling
+ bno BASED(io_preempt) # no -> check for preemptive scheduling
#else
- bno BASED(io_leave) # no-> skip resched & signal
+ bno BASED(io_leave) # no-> skip resched & signal
#endif
tm __TI_flags+3(%r9),_TIF_WORK_INT
- bnz BASED(io_work) # there is work to do (signals etc.)
+ bnz BASED(io_work) # there is work to do (signals etc.)
io_leave:
- RESTORE_ALL __LC_RETURN_PSW,0
+ RESTORE_ALL __LC_RETURN_PSW,0
io_done:
#ifdef CONFIG_PREEMPT
io_preempt:
icm %r0,15,__TI_precount(%r9)
- bnz BASED(io_leave)
+ bnz BASED(io_leave)
l %r1,SP_R15(%r15)
s %r1,BASED(.Lc_spsize)
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
- xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
lr %r15,%r1
io_resume_loop:
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bno BASED(io_leave)
- mvc __TI_precount(4,%r9),BASED(.Lc_pactive)
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
- l %r1,BASED(.Lschedule)
+ mvc __TI_precount(4,%r9),BASED(.Lc_pactive)
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ l %r1,BASED(.Lschedule)
basr %r14,%r1 # call schedule
- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
- xc __TI_precount(4,%r9),__TI_precount(%r9)
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ xc __TI_precount(4,%r9),__TI_precount(%r9)
b BASED(io_resume_loop)
#endif
@@ -615,16 +614,16 @@ io_work:
l %r1,__LC_KERNEL_STACK
s %r1,BASED(.Lc_spsize)
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
- xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
lr %r15,%r1
#
# One of the work bits is on. Find out which one.
# Checked are: _TIF_SIGPENDING, _TIF_RESTORE_SIGMASK, _TIF_NEED_RESCHED
-# and _TIF_MCCK_PENDING
+# and _TIF_MCCK_PENDING
#
io_work_loop:
tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
- bo BASED(io_mcck_pending)
+ bo BASED(io_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bo BASED(io_reschedule)
tm __TI_flags+3(%r9),(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK)
@@ -637,36 +636,36 @@ io_work_loop:
io_mcck_pending:
l %r1,BASED(.Ls390_handle_mcck)
la %r14,BASED(io_work_loop)
- br %r1 # TIF bit will be cleared by handler
+ br %r1 # TIF bit will be cleared by handler
#
# _TIF_NEED_RESCHED is set, call schedule
-#
-io_reschedule:
- l %r1,BASED(.Lschedule)
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
- basr %r14,%r1 # call scheduler
- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+#
+io_reschedule:
+ l %r1,BASED(.Lschedule)
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ basr %r14,%r1 # call scheduler
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
tm __TI_flags+3(%r9),_TIF_WORK_INT
- bz BASED(io_leave) # there is no work to do
+ bz BASED(io_leave) # there is no work to do
b BASED(io_work_loop)
#
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
-io_sigpending:
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
- la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,BASED(.Ldo_signal)
- basr %r14,%r1 # call do_signal
- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+io_sigpending:
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ l %r1,BASED(.Ldo_signal)
+ basr %r14,%r1 # call do_signal
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
b BASED(io_work_loop)
/*
* External interrupt handler routine
*/
- .globl ext_int_handler
+ .globl ext_int_handler
ext_int_handler:
STORE_TIMER __LC_ASYNC_ENTER_TIMER
stck __LC_INT_CLOCK
@@ -683,8 +682,8 @@ ext_no_vtime:
#endif
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
- la %r2,SP_PTREGS(%r15) # address of register-save area
- lh %r3,__LC_EXT_INT_CODE # get interruption code
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ lh %r3,__LC_EXT_INT_CODE # get interruption code
l %r1,BASED(.Ldo_extint)
basr %r14,%r1
TRACE_IRQS_ON
@@ -696,13 +695,13 @@ __critical_end:
* Machine check handler routines
*/
- .globl mcck_int_handler
+ .globl mcck_int_handler
mcck_int_handler:
spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer
lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+32
la %r12,__LC_MCK_OLD_PSW
- tm __LC_MCCK_CODE,0x80 # system damage?
+ tm __LC_MCCK_CODE,0x80 # system damage?
bo BASED(mcck_int_main) # yes -> rest of mcck code invalid
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER
@@ -741,7 +740,7 @@ mcck_int_main:
l %r15,__LC_PANIC_STACK # load panic stack
0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
bno BASED(mcck_no_vtime) # no -> skip cleanup critical
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(mcck_no_vtime)
@@ -752,14 +751,14 @@ mcck_no_vtime:
#endif
l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
la %r2,SP_PTREGS(%r15) # load pt_regs
- l %r1,BASED(.Ls390_mcck)
- basr %r14,%r1 # call machine check handler
- tm SP_PSW+1(%r15),0x01 # returning to user ?
+ l %r1,BASED(.Ls390_mcck)
+ basr %r14,%r1 # call machine check handler
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
bno BASED(mcck_return)
- l %r1,__LC_KERNEL_STACK # switch to kernel stack
+ l %r1,__LC_KERNEL_STACK # switch to kernel stack
s %r1,BASED(.Lc_spsize)
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
- xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
lr %r15,%r1
stosm __SF_EMPTY(%r15),0x04 # turn dat on
tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
@@ -783,36 +782,36 @@ mcck_return:
lm %r0,%r15,SP_R0(%r15) # load gprs 0-15
lpsw __LC_RETURN_MCCK_PSW # back to caller
- RESTORE_ALL __LC_RETURN_MCCK_PSW,0
+ RESTORE_ALL __LC_RETURN_MCCK_PSW,0
#ifdef CONFIG_SMP
/*
* Restart interruption handler, kick starter for additional CPUs
*/
- .globl restart_int_handler
+ .globl restart_int_handler
restart_int_handler:
- l %r15,__LC_SAVE_AREA+60 # load ksp
- lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
- lam %a0,%a15,__LC_AREGS_SAVE_AREA
- lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone
- stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
- basr %r14,0
- l %r14,restart_addr-.(%r14)
- br %r14 # branch to start_secondary
+ l %r15,__LC_SAVE_AREA+60 # load ksp
+ lctl %c0,%c15,__LC_CREGS_SAVE_AREA # get new ctl regs
+ lam %a0,%a15,__LC_AREGS_SAVE_AREA
+ lm %r6,%r15,__SF_GPRS(%r15) # load registers from clone
+ stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
+ basr %r14,0
+ l %r14,restart_addr-.(%r14)
+ br %r14 # branch to start_secondary
restart_addr:
- .long start_secondary
+ .long start_secondary
#else
/*
* If we do not run with SMP enabled, let the new CPU crash ...
*/
- .globl restart_int_handler
+ .globl restart_int_handler
restart_int_handler:
- basr %r1,0
+ basr %r1,0
restart_base:
- lpsw restart_crash-restart_base(%r1)
- .align 8
+ lpsw restart_crash-restart_base(%r1)
+ .align 8
restart_crash:
- .long 0x000a0000,0x00000000
+ .long 0x000a0000,0x00000000
restart_go:
#endif
@@ -834,11 +833,11 @@ stack_overflow:
be BASED(0f)
la %r1,__LC_SAVE_AREA+16
0: mvc SP_R12(16,%r15),0(%r1) # move %r12-%r15 to stack
- xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear back chain
l %r1,BASED(1f) # branch to kernel_stack_overflow
- la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r2,SP_PTREGS(%r15) # load pt_regs
br %r1
-1: .long kernel_stack_overflow
+1: .long kernel_stack_overflow
#endif
cleanup_table_system_call:
@@ -940,10 +939,10 @@ cleanup_novtime:
cleanup_system_call_insn:
.long sysc_saveall + 0x80000000
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- .long system_call + 0x80000000
- .long sysc_vtime + 0x80000000
- .long sysc_stime + 0x80000000
- .long sysc_update + 0x80000000
+ .long system_call + 0x80000000
+ .long sysc_vtime + 0x80000000
+ .long sysc_stime + 0x80000000
+ .long sysc_update + 0x80000000
#endif
cleanup_sysc_return:
@@ -1009,57 +1008,57 @@ cleanup_io_leave_insn:
/*
* Integer constants
*/
- .align 4
-.Lc_spsize: .long SP_SIZE
-.Lc_overhead: .long STACK_FRAME_OVERHEAD
-.Lc_pactive: .long PREEMPT_ACTIVE
-.Lnr_syscalls: .long NR_syscalls
-.L0x018: .short 0x018
-.L0x020: .short 0x020
-.L0x028: .short 0x028
-.L0x030: .short 0x030
-.L0x038: .short 0x038
-.Lc_1: .long 1
+ .align 4
+.Lc_spsize: .long SP_SIZE
+.Lc_overhead: .long STACK_FRAME_OVERHEAD
+.Lc_pactive: .long PREEMPT_ACTIVE
+.Lnr_syscalls: .long NR_syscalls
+.L0x018: .short 0x018
+.L0x020: .short 0x020
+.L0x028: .short 0x028
+.L0x030: .short 0x030
+.L0x038: .short 0x038
+.Lc_1: .long 1
/*
* Symbol constants
*/
-.Ls390_mcck: .long s390_do_machine_check
+.Ls390_mcck: .long s390_do_machine_check
.Ls390_handle_mcck:
- .long s390_handle_mcck
-.Lmck_old_psw: .long __LC_MCK_OLD_PSW
-.Ldo_IRQ: .long do_IRQ
-.Ldo_extint: .long do_extint
-.Ldo_signal: .long do_signal
-.Lhandle_per: .long do_single_step
-.Ljump_table: .long pgm_check_table
-.Lschedule: .long schedule
-.Lclone: .long sys_clone
-.Lexecve: .long sys_execve
-.Lfork: .long sys_fork
-.Lrt_sigreturn:.long sys_rt_sigreturn
+ .long s390_handle_mcck
+.Lmck_old_psw: .long __LC_MCK_OLD_PSW
+.Ldo_IRQ: .long do_IRQ
+.Ldo_extint: .long do_extint
+.Ldo_signal: .long do_signal
+.Lhandle_per: .long do_single_step
+.Ljump_table: .long pgm_check_table
+.Lschedule: .long schedule
+.Lclone: .long sys_clone
+.Lexecve: .long sys_execve
+.Lfork: .long sys_fork
+.Lrt_sigreturn: .long sys_rt_sigreturn
.Lrt_sigsuspend:
- .long sys_rt_sigsuspend
-.Lsigreturn: .long sys_sigreturn
-.Lsigsuspend: .long sys_sigsuspend
-.Lsigaltstack: .long sys_sigaltstack
-.Ltrace: .long syscall_trace
-.Lvfork: .long sys_vfork
-.Lschedtail: .long schedule_tail
-.Lsysc_table: .long sys_call_table
+ .long sys_rt_sigsuspend
+.Lsigreturn: .long sys_sigreturn
+.Lsigsuspend: .long sys_sigsuspend
+.Lsigaltstack: .long sys_sigaltstack
+.Ltrace: .long syscall_trace
+.Lvfork: .long sys_vfork
+.Lschedtail: .long schedule_tail
+.Lsysc_table: .long sys_call_table
#ifdef CONFIG_TRACE_IRQFLAGS
-.Ltrace_irq_on:.long trace_hardirqs_on
+.Ltrace_irq_on: .long trace_hardirqs_on
.Ltrace_irq_off:
- .long trace_hardirqs_off
+ .long trace_hardirqs_off
#endif
.Lcritical_start:
- .long __critical_start + 0x80000000
+ .long __critical_start + 0x80000000
.Lcritical_end:
- .long __critical_end + 0x80000000
+ .long __critical_end + 0x80000000
.Lcleanup_critical:
- .long cleanup_critical
+ .long cleanup_critical
- .section .rodata, "a"
+ .section .rodata, "a"
#define SYSCALL(esa,esame,emu) .long esa
sys_call_table:
#include "syscalls.S"
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 29bbfbab7332..0f758c329a5d 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -4,8 +4,8 @@
*
* Copyright (C) IBM Corp. 1999,2006
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- * Hartmut Penner (hp@de.ibm.com),
- * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Hartmut Penner (hp@de.ibm.com),
+ * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
* Heiko Carstens <heiko.carstens@de.ibm.com>
*/
@@ -24,29 +24,29 @@
* Stack layout for the system_call stack entry.
* The first few entries are identical to the user_regs_struct.
*/
-SP_PTREGS = STACK_FRAME_OVERHEAD
-SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
-SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
-SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
-SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
-SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
-SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
-SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
-SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
-SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
-SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
-SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64
-SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72
-SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80
-SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88
-SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96
-SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104
-SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
-SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
-SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
-SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
-SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
-SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
+SP_PTREGS = STACK_FRAME_OVERHEAD
+SP_ARGS = STACK_FRAME_OVERHEAD + __PT_ARGS
+SP_PSW = STACK_FRAME_OVERHEAD + __PT_PSW
+SP_R0 = STACK_FRAME_OVERHEAD + __PT_GPRS
+SP_R1 = STACK_FRAME_OVERHEAD + __PT_GPRS + 8
+SP_R2 = STACK_FRAME_OVERHEAD + __PT_GPRS + 16
+SP_R3 = STACK_FRAME_OVERHEAD + __PT_GPRS + 24
+SP_R4 = STACK_FRAME_OVERHEAD + __PT_GPRS + 32
+SP_R5 = STACK_FRAME_OVERHEAD + __PT_GPRS + 40
+SP_R6 = STACK_FRAME_OVERHEAD + __PT_GPRS + 48
+SP_R7 = STACK_FRAME_OVERHEAD + __PT_GPRS + 56
+SP_R8 = STACK_FRAME_OVERHEAD + __PT_GPRS + 64
+SP_R9 = STACK_FRAME_OVERHEAD + __PT_GPRS + 72
+SP_R10 = STACK_FRAME_OVERHEAD + __PT_GPRS + 80
+SP_R11 = STACK_FRAME_OVERHEAD + __PT_GPRS + 88
+SP_R12 = STACK_FRAME_OVERHEAD + __PT_GPRS + 96
+SP_R13 = STACK_FRAME_OVERHEAD + __PT_GPRS + 104
+SP_R14 = STACK_FRAME_OVERHEAD + __PT_GPRS + 112
+SP_R15 = STACK_FRAME_OVERHEAD + __PT_GPRS + 120
+SP_ORIG_R2 = STACK_FRAME_OVERHEAD + __PT_ORIG_GPR2
+SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
+SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
+SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
@@ -71,14 +71,14 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
#define TRACE_IRQS_OFF
#endif
- .macro STORE_TIMER lc_offset
+ .macro STORE_TIMER lc_offset
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
stpt \lc_offset
#endif
.endm
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- .macro UPDATE_VTIME lc_from,lc_to,lc_sum
+ .macro UPDATE_VTIME lc_from,lc_to,lc_sum
lg %r10,\lc_from
slg %r10,\lc_to
alg %r10,\lc_sum
@@ -94,7 +94,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
* R15 - kernel stack pointer
*/
- .macro SAVE_ALL_BASE savearea
+ .macro SAVE_ALL_BASE savearea
stmg %r12,%r15,\savearea
larl %r13,system_call
.endm
@@ -139,8 +139,8 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
.endm
.macro CREATE_STACK_FRAME psworg,savearea
- aghi %r15,-SP_SIZE # make room for registers & psw
- mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
+ aghi %r15,-SP_SIZE # make room for registers & psw
+ mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
la %r12,\psworg
stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
icm %r12,12,__LC_SVC_ILC
@@ -149,7 +149,7 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
mvc SP_R12(32,%r15),\savearea # move %r12-%r15 to stack
la %r12,0
stg %r12,__SF_BACKCHAIN(%r15)
- .endm
+ .endm
.macro RESTORE_ALL psworg,sync
mvc \psworg(16),SP_PSW(%r15) # move user PSW to lowcore
@@ -168,29 +168,29 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK | _TIF_NEED_RESCHED | \
* Returns:
* gpr2 = prev
*/
- .globl __switch_to
+ .globl __switch_to
__switch_to:
tm __THREAD_per+4(%r3),0xe8 # is the new process using per ?
jz __switch_to_noper # if not we're fine
- stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff
- clc __THREAD_per(24,%r3),__SF_EMPTY(%r15)
- je __switch_to_noper # we got away without bashing TLB's
- lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
+ stctg %c9,%c11,__SF_EMPTY(%r15)# We are using per stuff
+ clc __THREAD_per(24,%r3),__SF_EMPTY(%r15)
+ je __switch_to_noper # we got away without bashing TLB's
+ lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
__switch_to_noper:
- lg %r4,__THREAD_info(%r2) # get thread_info of prev
+ lg %r4,__THREAD_info(%r2) # get thread_info of prev
tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
jz __switch_to_no_mcck
ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
lg %r4,__THREAD_info(%r3) # get thread_info of next
oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next
__switch_to_no_mcck:
- stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
+ stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
- lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
+ lmg %r6,%r15,__SF_GPRS(%r15)# load __switch_to registers of next task
stg %r3,__LC_CURRENT # __LC_CURRENT = current task struct
lctl %c4,%c4,__TASK_pid(%r3) # load pid to control reg. 4
- lg %r3,__THREAD_info(%r3) # load thread_info from task struct
+ lg %r3,__THREAD_info(%r3) # load thread_info from task struct
stg %r3,__LC_THREAD_INFO
aghi %r3,STACK_SIZE
stg %r3,__LC_KERNEL_STACK # __LC_KERNEL_STACK = new kernel stack
@@ -202,14 +202,14 @@ __critical_start:
* are executed with interrupts enabled.
*/
- .globl system_call
+ .globl system_call
system_call:
STORE_TIMER __LC_SYNC_ENTER_TIMER
sysc_saveall:
SAVE_ALL_BASE __LC_SAVE_AREA
SAVE_ALL_SYNC __LC_SVC_OLD_PSW,__LC_SAVE_AREA
- CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
- llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
+ llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime:
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
@@ -222,45 +222,45 @@ sysc_update:
#endif
sysc_do_svc:
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
- slag %r7,%r7,2 # *4 and test for svc 0
+ slag %r7,%r7,2 # *4 and test for svc 0
jnz sysc_nr_ok
# svc 0: system call number in %r1
cl %r1,BASED(.Lnr_syscalls)
jnl sysc_nr_ok
- lgfr %r7,%r1 # clear high word in r1
- slag %r7,%r7,2 # svc 0: system call number in %r1
+ lgfr %r7,%r1 # clear high word in r1
+ slag %r7,%r7,2 # svc 0: system call number in %r1
sysc_nr_ok:
mvc SP_ARGS(8,%r15),SP_R7(%r15)
sysc_do_restart:
- larl %r10,sys_call_table
+ larl %r10,sys_call_table
#ifdef CONFIG_COMPAT
tm __TI_flags+5(%r9),(_TIF_31BIT>>16) # running in 31 bit mode ?
jno sysc_noemu
- larl %r10,sys_call_table_emu # use 31 bit emulation system calls
+ larl %r10,sys_call_table_emu # use 31 bit emulation system calls
sysc_noemu:
#endif
tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
- lgf %r8,0(%r7,%r10) # load address of system call routine
- jnz sysc_tracesys
- basr %r14,%r8 # call sys_xxxx
- stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
- # ATTENTION: check sys_execve_glue before
- # changing anything here !!
+ lgf %r8,0(%r7,%r10) # load address of system call routine
+ jnz sysc_tracesys
+ basr %r14,%r8 # call sys_xxxx
+ stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
+ # ATTENTION: check sys_execve_glue before
+ # changing anything here !!
sysc_return:
- tm SP_PSW+1(%r15),0x01 # returning to user ?
- jno sysc_leave
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jno sysc_leave
tm __TI_flags+7(%r9),_TIF_WORK_SVC
- jnz sysc_work # there is work to do (signals etc.)
+ jnz sysc_work # there is work to do (signals etc.)
sysc_leave:
- RESTORE_ALL __LC_RETURN_PSW,1
+ RESTORE_ALL __LC_RETURN_PSW,1
#
# recheck if there is more work to do
#
sysc_work_loop:
tm __TI_flags+7(%r9),_TIF_WORK_SVC
- jz sysc_leave # there is no work to do
+ jz sysc_leave # there is no work to do
#
# One of the work bits is on. Find out which one.
#
@@ -279,25 +279,25 @@ sysc_work:
#
# _TIF_NEED_RESCHED is set, call schedule
-#
-sysc_reschedule:
- larl %r14,sysc_work_loop
- jg schedule # return point is sysc_return
+#
+sysc_reschedule:
+ larl %r14,sysc_work_loop
+ jg schedule # return point is sysc_return
#
# _TIF_MCCK_PENDING is set, call handler
#
sysc_mcck_pending:
larl %r14,sysc_work_loop
- jg s390_handle_mcck # TIF bit will be cleared by handler
+ jg s390_handle_mcck # TIF bit will be cleared by handler
#
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
-sysc_sigpending:
+sysc_sigpending:
ni __TI_flags+7(%r9),255-_TIF_SINGLE_STEP # clear TIF_SINGLE_STEP
- la %r2,SP_PTREGS(%r15) # load pt_regs
- brasl %r14,do_signal # call do_signal
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,do_signal # call do_signal
tm __TI_flags+7(%r9),_TIF_RESTART_SVC
jo sysc_restart
tm __TI_flags+7(%r9),_TIF_SINGLE_STEP
@@ -309,11 +309,11 @@ sysc_sigpending:
#
sysc_restart:
ni __TI_flags+7(%r9),255-_TIF_RESTART_SVC # clear TIF_RESTART_SVC
- lg %r7,SP_R2(%r15) # load new svc number
- slag %r7,%r7,2 # *4
+ lg %r7,SP_R2(%r15) # load new svc number
+ slag %r7,%r7,2 # *4
mvc SP_R2(8,%r15),SP_ORIG_R2(%r15) # restore first argument
- lmg %r2,%r6,SP_R2(%r15) # load svc arguments
- j sysc_do_restart # restart svc
+ lmg %r2,%r6,SP_R2(%r15) # load svc arguments
+ j sysc_do_restart # restart svc
#
# _TIF_SINGLE_STEP is set, call do_single_step
@@ -326,49 +326,48 @@ sysc_singlestep:
larl %r14,sysc_return # load adr. of system return
jg do_single_step # branch to do_sigtrap
-
#
# call syscall_trace before and after system call
# special linkage: %r12 contains the return address for trace_svc
#
sysc_tracesys:
- la %r2,SP_PTREGS(%r15) # load pt_regs
+ la %r2,SP_PTREGS(%r15) # load pt_regs
la %r3,0
srl %r7,2
- stg %r7,SP_R2(%r15)
- brasl %r14,syscall_trace
+ stg %r7,SP_R2(%r15)
+ brasl %r14,syscall_trace
lghi %r0,NR_syscalls
clg %r0,SP_R2(%r15)
jnh sysc_tracenogo
- lg %r7,SP_R2(%r15) # strace might have changed the
- sll %r7,2 # system call
+ lg %r7,SP_R2(%r15) # strace might have changed the
+ sll %r7,2 # system call
lgf %r8,0(%r7,%r10)
sysc_tracego:
- lmg %r3,%r6,SP_R3(%r15)
- lg %r2,SP_ORIG_R2(%r15)
- basr %r14,%r8 # call sys_xxx
- stg %r2,SP_R2(%r15) # store return value
+ lmg %r3,%r6,SP_R3(%r15)
+ lg %r2,SP_ORIG_R2(%r15)
+ basr %r14,%r8 # call sys_xxx
+ stg %r2,SP_R2(%r15) # store return value
sysc_tracenogo:
tm __TI_flags+7(%r9),(_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
- jz sysc_return
- la %r2,SP_PTREGS(%r15) # load pt_regs
+ jz sysc_return
+ la %r2,SP_PTREGS(%r15) # load pt_regs
la %r3,1
- larl %r14,sysc_return # return point is sysc_return
+ larl %r14,sysc_return # return point is sysc_return
jg syscall_trace
#
# a new process exits the kernel with ret_from_fork
#
- .globl ret_from_fork
+ .globl ret_from_fork
ret_from_fork:
lg %r13,__LC_SVC_NEW_PSW+8
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
tm SP_PSW+1(%r15),0x01 # forking a kernel thread ?
jo 0f
stg %r15,SP_R15(%r15) # store stack pointer for new kthread
-0: brasl %r14,schedule_tail
+0: brasl %r14,schedule_tail
TRACE_IRQS_ON
- stosm 24(%r15),0x03 # reenable interrupts
+ stosm 24(%r15),0x03 # reenable interrupts
j sysc_return
#
@@ -377,78 +376,78 @@ ret_from_fork:
# but are called with different parameter.
# return-address is set up above
#
-sys_clone_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- jg sys_clone # branch to sys_clone
+sys_clone_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg sys_clone # branch to sys_clone
#ifdef CONFIG_COMPAT
-sys32_clone_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- jg sys32_clone # branch to sys32_clone
+sys32_clone_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg sys32_clone # branch to sys32_clone
#endif
-sys_fork_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- jg sys_fork # branch to sys_fork
-
-sys_vfork_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- jg sys_vfork # branch to sys_vfork
-
-sys_execve_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- lgr %r12,%r14 # save return address
- brasl %r14,sys_execve # call sys_execve
- ltgr %r2,%r2 # check if execve failed
- bnz 0(%r12) # it did fail -> store result in gpr2
- b 6(%r12) # SKIP STG 2,SP_R2(15) in
- # system_call/sysc_tracesys
+sys_fork_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg sys_fork # branch to sys_fork
+
+sys_vfork_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ jg sys_vfork # branch to sys_vfork
+
+sys_execve_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ lgr %r12,%r14 # save return address
+ brasl %r14,sys_execve # call sys_execve
+ ltgr %r2,%r2 # check if execve failed
+ bnz 0(%r12) # it did fail -> store result in gpr2
+ b 6(%r12) # SKIP STG 2,SP_R2(15) in
+ # system_call/sysc_tracesys
#ifdef CONFIG_COMPAT
-sys32_execve_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs
- lgr %r12,%r14 # save return address
- brasl %r14,sys32_execve # call sys32_execve
- ltgr %r2,%r2 # check if execve failed
- bnz 0(%r12) # it did fail -> store result in gpr2
- b 6(%r12) # SKIP STG 2,SP_R2(15) in
- # system_call/sysc_tracesys
+sys32_execve_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ lgr %r12,%r14 # save return address
+ brasl %r14,sys32_execve # call sys32_execve
+ ltgr %r2,%r2 # check if execve failed
+ bnz 0(%r12) # it did fail -> store result in gpr2
+ b 6(%r12) # SKIP STG 2,SP_R2(15) in
+ # system_call/sysc_tracesys
#endif
-sys_sigreturn_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- jg sys_sigreturn # branch to sys_sigreturn
+sys_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys_sigreturn # branch to sys_sigreturn
#ifdef CONFIG_COMPAT
-sys32_sigreturn_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- jg sys32_sigreturn # branch to sys32_sigreturn
+sys32_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys32_sigreturn # branch to sys32_sigreturn
#endif
-sys_rt_sigreturn_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- jg sys_rt_sigreturn # branch to sys_sigreturn
+sys_rt_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys_rt_sigreturn # branch to sys_sigreturn
#ifdef CONFIG_COMPAT
-sys32_rt_sigreturn_glue:
- la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
- jg sys32_rt_sigreturn # branch to sys32_sigreturn
+sys32_rt_sigreturn_glue:
+ la %r2,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys32_rt_sigreturn # branch to sys32_sigreturn
#endif
sys_sigaltstack_glue:
- la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
- jg sys_sigaltstack # branch to sys_sigreturn
+ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys_sigaltstack # branch to sys_sigreturn
#ifdef CONFIG_COMPAT
sys32_sigaltstack_glue:
- la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
- jg sys32_sigaltstack_wrapper # branch to sys_sigreturn
+ la %r4,SP_PTREGS(%r15) # load pt_regs as parameter
+ jg sys32_sigaltstack_wrapper # branch to sys_sigreturn
#endif
/*
* Program check handler routine
*/
- .globl pgm_check_handler
+ .globl pgm_check_handler
pgm_check_handler:
/*
* First we need to check for a special case:
@@ -465,8 +464,8 @@ pgm_check_handler:
*/
STORE_TIMER __LC_SYNC_ENTER_TIMER
SAVE_ALL_BASE __LC_SAVE_AREA
- tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
- jnz pgm_per # got per exception -> special case
+ tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
+ jnz pgm_per # got per exception -> special case
SAVE_ALL_SYNC __LC_PGM_OLD_PSW,__LC_SAVE_AREA
CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -478,29 +477,29 @@ pgm_check_handler:
pgm_no_vtime:
#endif
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
- lgf %r3,__LC_PGM_ILC # load program interruption code
+ lgf %r3,__LC_PGM_ILC # load program interruption code
lghi %r8,0x7f
ngr %r8,%r3
pgm_do_call:
- sll %r8,3
- larl %r1,pgm_check_table
- lg %r1,0(%r8,%r1) # load address of handler routine
- la %r2,SP_PTREGS(%r15) # address of register-save area
+ sll %r8,3
+ larl %r1,pgm_check_table
+ lg %r1,0(%r8,%r1) # load address of handler routine
+ la %r2,SP_PTREGS(%r15) # address of register-save area
larl %r14,sysc_return
- br %r1 # branch to interrupt-handler
+ br %r1 # branch to interrupt-handler
#
# handle per exception
#
pgm_per:
- tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
- jnz pgm_per_std # ok, normal per event from user space
+ tm __LC_PGM_OLD_PSW,0x40 # test if per event recording is on
+ jnz pgm_per_std # ok, normal per event from user space
# ok its one of the special cases, now we need to find out which one
- clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
- je pgm_svcper
+ clc __LC_PGM_OLD_PSW(16),__LC_SVC_NEW_PSW
+ je pgm_svcper
# no interesting special case, ignore PER event
lmg %r12,%r15,__LC_SAVE_AREA
- lpswe __LC_PGM_OLD_PSW
+ lpswe __LC_PGM_OLD_PSW
#
# Normal per exception
@@ -524,9 +523,9 @@ pgm_no_vtime2:
mvc __THREAD_per+__PER_address(8,%r1),__LC_PER_ADDRESS
mvc __THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
oi __TI_flags+7(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
- lgf %r3,__LC_PGM_ILC # load program interruption code
+ lgf %r3,__LC_PGM_ILC # load program interruption code
lghi %r8,0x7f
- ngr %r8,%r3 # clear per-event-bit and ilc
+ ngr %r8,%r3 # clear per-event-bit and ilc
je sysc_return
j pgm_do_call
@@ -544,7 +543,7 @@ pgm_svcper:
mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
pgm_no_vtime3:
#endif
- llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
+ llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
lg %r1,__TI_task(%r9)
mvc __THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
@@ -568,7 +567,7 @@ kernel_per:
/*
* IO interrupt handler routine
*/
- .globl io_int_handler
+ .globl io_int_handler
io_int_handler:
STORE_TIMER __LC_ASYNC_ENTER_TIMER
stck __LC_INT_CLOCK
@@ -585,42 +584,42 @@ io_no_vtime:
#endif
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
- la %r2,SP_PTREGS(%r15) # address of register-save area
- brasl %r14,do_IRQ # call standard irq handler
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ brasl %r14,do_IRQ # call standard irq handler
TRACE_IRQS_ON
io_return:
- tm SP_PSW+1(%r15),0x01 # returning to user ?
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
#ifdef CONFIG_PREEMPT
- jno io_preempt # no -> check for preemptive scheduling
+ jno io_preempt # no -> check for preemptive scheduling
#else
- jno io_leave # no-> skip resched & signal
+ jno io_leave # no-> skip resched & signal
#endif
tm __TI_flags+7(%r9),_TIF_WORK_INT
- jnz io_work # there is work to do (signals etc.)
+ jnz io_work # there is work to do (signals etc.)
io_leave:
- RESTORE_ALL __LC_RETURN_PSW,0
+ RESTORE_ALL __LC_RETURN_PSW,0
io_done:
#ifdef CONFIG_PREEMPT
io_preempt:
- icm %r0,15,__TI_precount(%r9)
- jnz io_leave
+ icm %r0,15,__TI_precount(%r9)
+ jnz io_leave
# switch to kernel stack
lg %r1,SP_R15(%r15)
aghi %r1,-SP_SIZE
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
- xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
lgr %r15,%r1
io_resume_loop:
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jno io_leave
- larl %r1,.Lc_pactive
- mvc __TI_precount(4,%r9),0(%r1)
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
- brasl %r14,schedule # call schedule
- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
- xc __TI_precount(4,%r9),__TI_precount(%r9)
+ larl %r1,.Lc_pactive
+ mvc __TI_precount(4,%r9),0(%r1)
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ brasl %r14,schedule # call schedule
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ xc __TI_precount(4,%r9),__TI_precount(%r9)
j io_resume_loop
#endif
@@ -631,7 +630,7 @@ io_work:
lg %r1,__LC_KERNEL_STACK
aghi %r1,-SP_SIZE
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
- xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
lgr %r15,%r1
#
# One of the work bits is on. Find out which one.
@@ -656,11 +655,11 @@ io_mcck_pending:
#
# _TIF_NEED_RESCHED is set, call schedule
-#
-io_reschedule:
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
- brasl %r14,schedule # call scheduler
- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+#
+io_reschedule:
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ brasl %r14,schedule # call scheduler
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
tm __TI_flags+7(%r9),_TIF_WORK_INT
jz io_leave # there is no work to do
j io_work_loop
@@ -668,17 +667,17 @@ io_reschedule:
#
# _TIF_SIGPENDING or _TIF_RESTORE_SIGMASK is set, call do_signal
#
-io_sigpending:
- stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
- la %r2,SP_PTREGS(%r15) # load pt_regs
+io_sigpending:
+ stosm __SF_EMPTY(%r15),0x03 # reenable interrupts
+ la %r2,SP_PTREGS(%r15) # load pt_regs
brasl %r14,do_signal # call do_signal
- stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
+ stnsm __SF_EMPTY(%r15),0xfc # disable I/O and ext. interrupts
j io_work_loop
/*
* External interrupt handler routine
*/
- .globl ext_int_handler
+ .globl ext_int_handler
ext_int_handler:
STORE_TIMER __LC_ASYNC_ENTER_TIMER
stck __LC_INT_CLOCK
@@ -695,9 +694,9 @@ ext_no_vtime:
#endif
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
TRACE_IRQS_OFF
- la %r2,SP_PTREGS(%r15) # address of register-save area
- llgh %r3,__LC_EXT_INT_CODE # get interruption code
- brasl %r14,do_extint
+ la %r2,SP_PTREGS(%r15) # address of register-save area
+ llgh %r3,__LC_EXT_INT_CODE # get interruption code
+ brasl %r14,do_extint
TRACE_IRQS_ON
j io_return
@@ -706,14 +705,14 @@ __critical_end:
/*
* Machine check handler routines
*/
- .globl mcck_int_handler
+ .globl mcck_int_handler
mcck_int_handler:
la %r1,4095 # revalidate r1
spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
- lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+64
la %r12,__LC_MCK_OLD_PSW
- tm __LC_MCCK_CODE,0x80 # system damage?
+ tm __LC_MCCK_CODE,0x80 # system damage?
jo mcck_int_main # yes -> rest of mcck code invalid
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
la %r14,4095
@@ -737,19 +736,19 @@ mcck_int_handler:
#endif
tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
jno mcck_int_main # no -> skip cleanup critical
- tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+ tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
jnz mcck_int_main # from user -> load kernel stack
clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end)
jhe mcck_int_main
- clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start)
+ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start)
jl mcck_int_main
- brasl %r14,cleanup_critical
+ brasl %r14,cleanup_critical
mcck_int_main:
- lg %r14,__LC_PANIC_STACK # are we already on the panic stack?
+ lg %r14,__LC_PANIC_STACK # are we already on the panic stack?
slgr %r14,%r15
srag %r14,%r14,PAGE_SHIFT
jz 0f
- lg %r15,__LC_PANIC_STACK # load panic stack
+ lg %r15,__LC_PANIC_STACK # load panic stack
0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
@@ -764,7 +763,7 @@ mcck_no_vtime:
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
la %r2,SP_PTREGS(%r15) # load pt_regs
brasl %r14,s390_do_machine_check
- tm SP_PSW+1(%r15),0x01 # returning to user ?
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
jno mcck_return
lg %r1,__LC_KERNEL_STACK # switch to kernel stack
aghi %r1,-SP_SIZE
@@ -794,28 +793,28 @@ mcck_return:
/*
* Restart interruption handler, kick starter for additional CPUs
*/
- .globl restart_int_handler
+ .globl restart_int_handler
restart_int_handler:
- lg %r15,__LC_SAVE_AREA+120 # load ksp
- lghi %r10,__LC_CREGS_SAVE_AREA
- lctlg %c0,%c15,0(%r10) # get new ctl regs
- lghi %r10,__LC_AREGS_SAVE_AREA
- lam %a0,%a15,0(%r10)
- lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
- stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
- jg start_secondary
+ lg %r15,__LC_SAVE_AREA+120 # load ksp
+ lghi %r10,__LC_CREGS_SAVE_AREA
+ lctlg %c0,%c15,0(%r10) # get new ctl regs
+ lghi %r10,__LC_AREGS_SAVE_AREA
+ lam %a0,%a15,0(%r10)
+ lmg %r6,%r15,__SF_GPRS(%r15) # load registers from clone
+ stosm __SF_EMPTY(%r15),0x04 # now we can turn dat on
+ jg start_secondary
#else
/*
* If we do not run with SMP enabled, let the new CPU crash ...
*/
- .globl restart_int_handler
+ .globl restart_int_handler
restart_int_handler:
- basr %r1,0
+ basr %r1,0
restart_base:
- lpswe restart_crash-restart_base(%r1)
- .align 8
+ lpswe restart_crash-restart_base(%r1)
+ .align 8
restart_crash:
- .long 0x000a0000,0x00000000,0x00000000,0x00000000
+ .long 0x000a0000,0x00000000,0x00000000,0x00000000
restart_go:
#endif
@@ -836,9 +835,9 @@ stack_overflow:
chi %r12,__LC_PGM_OLD_PSW
je 0f
la %r1,__LC_SAVE_AREA+32
-0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack
- xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
- la %r2,SP_PTREGS(%r15) # load pt_regs
+0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack
+ xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
+ la %r2,SP_PTREGS(%r15) # load pt_regs
jg kernel_stack_overflow
#endif
@@ -941,10 +940,10 @@ cleanup_novtime:
cleanup_system_call_insn:
.quad sysc_saveall
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- .quad system_call
- .quad sysc_vtime
- .quad sysc_stime
- .quad sysc_update
+ .quad system_call
+ .quad sysc_vtime
+ .quad sysc_stime
+ .quad sysc_update
#endif
cleanup_sysc_return:
@@ -1010,21 +1009,21 @@ cleanup_io_leave_insn:
/*
* Integer constants
*/
- .align 4
+ .align 4
.Lconst:
-.Lc_pactive: .long PREEMPT_ACTIVE
-.Lnr_syscalls: .long NR_syscalls
-.L0x0130: .short 0x130
-.L0x0140: .short 0x140
-.L0x0150: .short 0x150
-.L0x0160: .short 0x160
-.L0x0170: .short 0x170
+.Lc_pactive: .long PREEMPT_ACTIVE
+.Lnr_syscalls: .long NR_syscalls
+.L0x0130: .short 0x130
+.L0x0140: .short 0x140
+.L0x0150: .short 0x150
+.L0x0160: .short 0x160
+.L0x0170: .short 0x170
.Lcritical_start:
- .quad __critical_start
+ .quad __critical_start
.Lcritical_end:
- .quad __critical_end
+ .quad __critical_end
- .section .rodata, "a"
+ .section .rodata, "a"
#define SYSCALL(esa,esame,emu) .long esame
sys_call_table:
#include "syscalls.S"
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index 0f1db268a8a9..0cf59bb7a857 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -36,449 +36,449 @@
#endif
#ifndef CONFIG_IPL
- .org 0
- .long 0x00080000,0x80000000+startup # Just a restart PSW
+ .org 0
+ .long 0x00080000,0x80000000+startup # Just a restart PSW
#else
#ifdef CONFIG_IPL_TAPE
#define IPL_BS 1024
- .org 0
- .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
- .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
- .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
- .long 0x00000000,0x00000000 # external old psw
- .long 0x00000000,0x00000000 # svc old psw
- .long 0x00000000,0x00000000 # program check old psw
- .long 0x00000000,0x00000000 # machine check old psw
- .long 0x00000000,0x00000000 # io old psw
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x000a0000,0x00000058 # external new psw
- .long 0x000a0000,0x00000060 # svc new psw
- .long 0x000a0000,0x00000068 # program check new psw
- .long 0x000a0000,0x00000070 # machine check new psw
- .long 0x00080000,0x80000000+.Lioint # io new psw
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x27000000,0x60000001 # by ipl to addresses 0-23.
+ .long 0x02000000,0x20000000+IPL_BS # (a PSW and two CCWs).
+ .long 0x00000000,0x00000000 # external old psw
+ .long 0x00000000,0x00000000 # svc old psw
+ .long 0x00000000,0x00000000 # program check old psw
+ .long 0x00000000,0x00000000 # machine check old psw
+ .long 0x00000000,0x00000000 # io old psw
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x000a0000,0x00000058 # external new psw
+ .long 0x000a0000,0x00000060 # svc new psw
+ .long 0x000a0000,0x00000068 # program check new psw
+ .long 0x000a0000,0x00000070 # machine check new psw
+ .long 0x00080000,0x80000000+.Lioint # io new psw
- .org 0x100
+ .org 0x100
#
# subroutine for loading from tape
-# Paramters:
+# Paramters:
# R1 = device number
# R2 = load address
-.Lloader:
- st %r14,.Lldret
- la %r3,.Lorbread # r3 = address of orb
- la %r5,.Lirb # r5 = address of irb
- st %r2,.Lccwread+4 # initialize CCW data addresses
- lctl %c6,%c6,.Lcr6
- slr %r2,%r2
+.Lloader:
+ st %r14,.Lldret
+ la %r3,.Lorbread # r3 = address of orb
+ la %r5,.Lirb # r5 = address of irb
+ st %r2,.Lccwread+4 # initialize CCW data addresses
+ lctl %c6,%c6,.Lcr6
+ slr %r2,%r2
.Lldlp:
- la %r6,3 # 3 retries
+ la %r6,3 # 3 retries
.Lssch:
- ssch 0(%r3) # load chunk of IPL_BS bytes
- bnz .Llderr
+ ssch 0(%r3) # load chunk of IPL_BS bytes
+ bnz .Llderr
.Lw4end:
- bas %r14,.Lwait4io
- tm 8(%r5),0x82 # do we have a problem ?
- bnz .Lrecov
- slr %r7,%r7
- icm %r7,3,10(%r5) # get residual count
- lcr %r7,%r7
- la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
- ar %r2,%r7 # add to total size
- tm 8(%r5),0x01 # found a tape mark ?
- bnz .Ldone
- l %r0,.Lccwread+4 # update CCW data addresses
- ar %r0,%r7
- st %r0,.Lccwread+4
- b .Lldlp
+ bas %r14,.Lwait4io
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Lrecov
+ slr %r7,%r7
+ icm %r7,3,10(%r5) # get residual count
+ lcr %r7,%r7
+ la %r7,IPL_BS(%r7) # IPL_BS-residual=#bytes read
+ ar %r2,%r7 # add to total size
+ tm 8(%r5),0x01 # found a tape mark ?
+ bnz .Ldone
+ l %r0,.Lccwread+4 # update CCW data addresses
+ ar %r0,%r7
+ st %r0,.Lccwread+4
+ b .Lldlp
.Ldone:
- l %r14,.Lldret
- br %r14 # r2 contains the total size
+ l %r14,.Lldret
+ br %r14 # r2 contains the total size
.Lrecov:
- bas %r14,.Lsense # do the sensing
- bct %r6,.Lssch # dec. retry count & branch
- b .Llderr
+ bas %r14,.Lsense # do the sensing
+ bct %r6,.Lssch # dec. retry count & branch
+ b .Llderr
#
# Sense subroutine
#
.Lsense:
- st %r14,.Lsnsret
- la %r7,.Lorbsense
- ssch 0(%r7) # start sense command
- bnz .Llderr
- bas %r14,.Lwait4io
- l %r14,.Lsnsret
- tm 8(%r5),0x82 # do we have a problem ?
- bnz .Llderr
- br %r14
+ st %r14,.Lsnsret
+ la %r7,.Lorbsense
+ ssch 0(%r7) # start sense command
+ bnz .Llderr
+ bas %r14,.Lwait4io
+ l %r14,.Lsnsret
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Llderr
+ br %r14
#
# Wait for interrupt subroutine
#
.Lwait4io:
- lpsw .Lwaitpsw
+ lpsw .Lwaitpsw
.Lioint:
- c %r1,0xb8 # compare subchannel number
- bne .Lwait4io
- tsch 0(%r5)
- slr %r0,%r0
- tm 8(%r5),0x82 # do we have a problem ?
- bnz .Lwtexit
- tm 8(%r5),0x04 # got device end ?
- bz .Lwait4io
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwait4io
+ tsch 0(%r5)
+ slr %r0,%r0
+ tm 8(%r5),0x82 # do we have a problem ?
+ bnz .Lwtexit
+ tm 8(%r5),0x04 # got device end ?
+ bz .Lwait4io
.Lwtexit:
- br %r14
+ br %r14
.Llderr:
- lpsw .Lcrash
+ lpsw .Lcrash
- .align 8
+ .align 8
.Lorbread:
- .long 0x00000000,0x0080ff00,.Lccwread
- .align 8
+ .long 0x00000000,0x0080ff00,.Lccwread
+ .align 8
.Lorbsense:
- .long 0x00000000,0x0080ff00,.Lccwsense
- .align 8
+ .long 0x00000000,0x0080ff00,.Lccwsense
+ .align 8
.Lccwread:
- .long 0x02200000+IPL_BS,0x00000000
+ .long 0x02200000+IPL_BS,0x00000000
.Lccwsense:
- .long 0x04200001,0x00000000
+ .long 0x04200001,0x00000000
.Lwaitpsw:
- .long 0x020a0000,0x80000000+.Lioint
+ .long 0x020a0000,0x80000000+.Lioint
-.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-.Lcr6: .long 0xff000000
- .align 8
-.Lcrash:.long 0x000a0000,0x00000000
-.Lldret:.long 0
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
+.Lldret:.long 0
.Lsnsret: .long 0
-#endif /* CONFIG_IPL_TAPE */
+#endif /* CONFIG_IPL_TAPE */
#ifdef CONFIG_IPL_VM
-#define IPL_BS 0x730
- .org 0
- .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
- .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
- .long 0x02000068,0x60000050 # (a PSW and two CCWs).
- .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
- .long 0x020000f0,0x60000050 # The next 160 byte are loaded
- .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
- .long 0x02000190,0x60000050 # They form the continuation
- .long 0x020001e0,0x60000050 # of the CCW program started
- .long 0x02000230,0x60000050 # by ipl and load the range
- .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
- .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
- .long 0x02000320,0x60000050 # in memory. At the end of
- .long 0x02000370,0x60000050 # the channel program the PSW
- .long 0x020003c0,0x60000050 # at location 0 is loaded.
- .long 0x02000410,0x60000050 # Initial processing starts
- .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
- .long 0x020004b0,0x60000050
- .long 0x02000500,0x60000050
- .long 0x02000550,0x60000050
- .long 0x020005a0,0x60000050
- .long 0x020005f0,0x60000050
- .long 0x02000640,0x60000050
- .long 0x02000690,0x60000050
- .long 0x020006e0,0x20000050
+#define IPL_BS 0x730
+ .org 0
+ .long 0x00080000,0x80000000+iplstart # The first 24 bytes are loaded
+ .long 0x02000018,0x60000050 # by ipl to addresses 0-23.
+ .long 0x02000068,0x60000050 # (a PSW and two CCWs).
+ .fill 80-24,1,0x40 # bytes 24-79 are discarded !!
+ .long 0x020000f0,0x60000050 # The next 160 byte are loaded
+ .long 0x02000140,0x60000050 # to addresses 0x18-0xb7
+ .long 0x02000190,0x60000050 # They form the continuation
+ .long 0x020001e0,0x60000050 # of the CCW program started
+ .long 0x02000230,0x60000050 # by ipl and load the range
+ .long 0x02000280,0x60000050 # 0x0f0-0x730 from the image
+ .long 0x020002d0,0x60000050 # to the range 0x0f0-0x730
+ .long 0x02000320,0x60000050 # in memory. At the end of
+ .long 0x02000370,0x60000050 # the channel program the PSW
+ .long 0x020003c0,0x60000050 # at location 0 is loaded.
+ .long 0x02000410,0x60000050 # Initial processing starts
+ .long 0x02000460,0x60000050 # at 0xf0 = iplstart.
+ .long 0x020004b0,0x60000050
+ .long 0x02000500,0x60000050
+ .long 0x02000550,0x60000050
+ .long 0x020005a0,0x60000050
+ .long 0x020005f0,0x60000050
+ .long 0x02000640,0x60000050
+ .long 0x02000690,0x60000050
+ .long 0x020006e0,0x20000050
- .org 0xf0
+ .org 0xf0
#
# subroutine for loading cards from the reader
#
-.Lloader:
- la %r3,.Lorb # r2 = address of orb into r2
- la %r5,.Lirb # r4 = address of irb
- la %r6,.Lccws
- la %r7,20
+.Lloader:
+ la %r3,.Lorb # r2 = address of orb into r2
+ la %r5,.Lirb # r4 = address of irb
+ la %r6,.Lccws
+ la %r7,20
.Linit:
- st %r2,4(%r6) # initialize CCW data addresses
- la %r2,0x50(%r2)
- la %r6,8(%r6)
- bct 7,.Linit
+ st %r2,4(%r6) # initialize CCW data addresses
+ la %r2,0x50(%r2)
+ la %r6,8(%r6)
+ bct 7,.Linit
- lctl %c6,%c6,.Lcr6 # set IO subclass mask
- slr %r2,%r2
+ lctl %c6,%c6,.Lcr6 # set IO subclass mask
+ slr %r2,%r2
.Lldlp:
- ssch 0(%r3) # load chunk of 1600 bytes
- bnz .Llderr
+ ssch 0(%r3) # load chunk of 1600 bytes
+ bnz .Llderr
.Lwait4irq:
- mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
- lpsw .Lwaitpsw
+ mvc 0x78(8),.Lnewpsw # set up IO interrupt psw
+ lpsw .Lwaitpsw
.Lioint:
- c %r1,0xb8 # compare subchannel number
- bne .Lwait4irq
- tsch 0(%r5)
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwait4irq
+ tsch 0(%r5)
- slr %r0,%r0
- ic %r0,8(%r5) # get device status
- chi %r0,8 # channel end ?
- be .Lcont
- chi %r0,12 # channel end + device end ?
- be .Lcont
+ slr %r0,%r0
+ ic %r0,8(%r5) # get device status
+ chi %r0,8 # channel end ?
+ be .Lcont
+ chi %r0,12 # channel end + device end ?
+ be .Lcont
- l %r0,4(%r5)
- s %r0,8(%r3) # r0/8 = number of ccws executed
- mhi %r0,10 # *10 = number of bytes in ccws
- lh %r3,10(%r5) # get residual count
- sr %r0,%r3 # #ccws*80-residual=#bytes read
- ar %r2,%r0
-
- br %r14 # r2 contains the total size
+ l %r0,4(%r5)
+ s %r0,8(%r3) # r0/8 = number of ccws executed
+ mhi %r0,10 # *10 = number of bytes in ccws
+ lh %r3,10(%r5) # get residual count
+ sr %r0,%r3 # #ccws*80-residual=#bytes read
+ ar %r2,%r0
+
+ br %r14 # r2 contains the total size
.Lcont:
- ahi %r2,0x640 # add 0x640 to total size
- la %r6,.Lccws
- la %r7,20
+ ahi %r2,0x640 # add 0x640 to total size
+ la %r6,.Lccws
+ la %r7,20
.Lincr:
- l %r0,4(%r6) # update CCW data addresses
- ahi %r0,0x640
- st %r0,4(%r6)
- ahi %r6,8
- bct 7,.Lincr
+ l %r0,4(%r6) # update CCW data addresses
+ ahi %r0,0x640
+ st %r0,4(%r6)
+ ahi %r6,8
+ bct 7,.Lincr
- b .Lldlp
+ b .Lldlp
.Llderr:
- lpsw .Lcrash
+ lpsw .Lcrash
- .align 8
-.Lorb: .long 0x00000000,0x0080ff00,.Lccws
-.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
-.Lcr6: .long 0xff000000
-.Lloadp:.long 0,0
- .align 8
-.Lcrash:.long 0x000a0000,0x00000000
+ .align 8
+.Lorb: .long 0x00000000,0x0080ff00,.Lccws
+.Lirb: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+.Lcr6: .long 0xff000000
+.Lloadp:.long 0,0
+ .align 8
+.Lcrash:.long 0x000a0000,0x00000000
.Lnewpsw:
- .long 0x00080000,0x80000000+.Lioint
+ .long 0x00080000,0x80000000+.Lioint
.Lwaitpsw:
- .long 0x020a0000,0x80000000+.Lioint
+ .long 0x020a0000,0x80000000+.Lioint
- .align 8
-.Lccws: .rept 19
- .long 0x02600050,0x00000000
- .endr
- .long 0x02200050,0x00000000
-#endif /* CONFIG_IPL_VM */
+ .align 8
+.Lccws: .rept 19
+ .long 0x02600050,0x00000000
+ .endr
+ .long 0x02200050,0x00000000
+#endif /* CONFIG_IPL_VM */
iplstart:
- lh %r1,0xb8 # test if subchannel number
- bct %r1,.Lnoload # is valid
- l %r1,0xb8 # load ipl subchannel number
- la %r2,IPL_BS # load start address
- bas %r14,.Lloader # load rest of ipl image
- l %r12,.Lparm # pointer to parameter area
- st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number
+ lh %r1,0xb8 # test if subchannel number
+ bct %r1,.Lnoload # is valid
+ l %r1,0xb8 # load ipl subchannel number
+ la %r2,IPL_BS # load start address
+ bas %r14,.Lloader # load rest of ipl image
+ l %r12,.Lparm # pointer to parameter area
+ st %r1,IPL_DEVICE+ARCH_OFFSET-PARMAREA(%r12) # save ipl device number
#
# load parameter file from ipl device
#
.Lagain1:
- l %r2,.Linitrd # ramdisk loc. is temp
- bas %r14,.Lloader # load parameter file
- ltr %r2,%r2 # got anything ?
- bz .Lnopf
- chi %r2,895
- bnh .Lnotrunc
- la %r2,895
+ l %r2,.Linitrd # ramdisk loc. is temp
+ bas %r14,.Lloader # load parameter file
+ ltr %r2,%r2 # got anything ?
+ bz .Lnopf
+ chi %r2,895
+ bnh .Lnotrunc
+ la %r2,895
.Lnotrunc:
- l %r4,.Linitrd
- clc 0(3,%r4),.L_hdr # if it is HDRx
- bz .Lagain1 # skip dataset header
- clc 0(3,%r4),.L_eof # if it is EOFx
- bz .Lagain1 # skip dateset trailer
- la %r5,0(%r4,%r2)
- lr %r3,%r2
+ l %r4,.Linitrd
+ clc 0(3,%r4),.L_hdr # if it is HDRx
+ bz .Lagain1 # skip dataset header
+ clc 0(3,%r4),.L_eof # if it is EOFx
+ bz .Lagain1 # skip dateset trailer
+ la %r5,0(%r4,%r2)
+ lr %r3,%r2
.Lidebc:
- tm 0(%r5),0x80 # high order bit set ?
- bo .Ldocv # yes -> convert from EBCDIC
- ahi %r5,-1
- bct %r3,.Lidebc
- b .Lnocv
+ tm 0(%r5),0x80 # high order bit set ?
+ bo .Ldocv # yes -> convert from EBCDIC
+ ahi %r5,-1
+ bct %r3,.Lidebc
+ b .Lnocv
.Ldocv:
- l %r3,.Lcvtab
- tr 0(256,%r4),0(%r3) # convert parameters to ascii
- tr 256(256,%r4),0(%r3)
- tr 512(256,%r4),0(%r3)
- tr 768(122,%r4),0(%r3)
-.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
- mvc 0(256,%r3),0(%r4)
- mvc 256(256,%r3),256(%r4)
- mvc 512(256,%r3),512(%r4)
- mvc 768(122,%r3),768(%r4)
- slr %r0,%r0
- b .Lcntlp
+ l %r3,.Lcvtab
+ tr 0(256,%r4),0(%r3) # convert parameters to ascii
+ tr 256(256,%r4),0(%r3)
+ tr 512(256,%r4),0(%r3)
+ tr 768(122,%r4),0(%r3)
+.Lnocv: la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
+ mvc 0(256,%r3),0(%r4)
+ mvc 256(256,%r3),256(%r4)
+ mvc 512(256,%r3),512(%r4)
+ mvc 768(122,%r3),768(%r4)
+ slr %r0,%r0
+ b .Lcntlp
.Ldelspc:
- ic %r0,0(%r2,%r3)
- chi %r0,0x20 # is it a space ?
- be .Lcntlp
- ahi %r2,1
- b .Leolp
+ ic %r0,0(%r2,%r3)
+ chi %r0,0x20 # is it a space ?
+ be .Lcntlp
+ ahi %r2,1
+ b .Leolp
.Lcntlp:
- brct %r2,.Ldelspc
+ brct %r2,.Ldelspc
.Leolp:
- slr %r0,%r0
- stc %r0,0(%r2,%r3) # terminate buffer
+ slr %r0,%r0
+ stc %r0,0(%r2,%r3) # terminate buffer
.Lnopf:
#
# load ramdisk from ipl device
-#
+#
.Lagain2:
- l %r2,.Linitrd # addr of ramdisk
- st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
- bas %r14,.Lloader # load ramdisk
- st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of ramdisk
- ltr %r2,%r2
- bnz .Lrdcont
- st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found
+ l %r2,.Linitrd # addr of ramdisk
+ st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12)
+ bas %r14,.Lloader # load ramdisk
+ st %r2,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r12) # store size of rd
+ ltr %r2,%r2
+ bnz .Lrdcont
+ st %r2,INITRD_START+ARCH_OFFSET-PARMAREA(%r12) # no ramdisk found
.Lrdcont:
- l %r2,.Linitrd
+ l %r2,.Linitrd
- clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
- bz .Lagain2
- clc 0(3,%r2),.L_eof
- bz .Lagain2
+ clc 0(3,%r2),.L_hdr # skip HDRx and EOFx
+ bz .Lagain2
+ clc 0(3,%r2),.L_eof
+ bz .Lagain2
#ifdef CONFIG_IPL_VM
#
# reset files in VM reader
#
- stidp __LC_CPUID # store cpuid
- tm __LC_CPUID,0xff # running VM ?
- bno .Lnoreset
- la %r2,.Lreset
- lhi %r3,26
- diag %r2,%r3,8
- la %r5,.Lirb
- stsch 0(%r5) # check if irq is pending
- tm 30(%r5),0x0f # by verifying if any of the
- bnz .Lwaitforirq # activity or status control
- tm 31(%r5),0xff # bits is set in the schib
- bz .Lnoreset
+ stidp __LC_CPUID # store cpuid
+ tm __LC_CPUID,0xff # running VM ?
+ bno .Lnoreset
+ la %r2,.Lreset
+ lhi %r3,26
+ diag %r2,%r3,8
+ la %r5,.Lirb
+ stsch 0(%r5) # check if irq is pending
+ tm 30(%r5),0x0f # by verifying if any of the
+ bnz .Lwaitforirq # activity or status control
+ tm 31(%r5),0xff # bits is set in the schib
+ bz .Lnoreset
.Lwaitforirq:
- mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
+ mvc 0x78(8),.Lrdrnewpsw # set up IO interrupt psw
.Lwaitrdrirq:
- lpsw .Lrdrwaitpsw
+ lpsw .Lrdrwaitpsw
.Lrdrint:
- c %r1,0xb8 # compare subchannel number
- bne .Lwaitrdrirq
- la %r5,.Lirb
- tsch 0(%r5)
+ c %r1,0xb8 # compare subchannel number
+ bne .Lwaitrdrirq
+ la %r5,.Lirb
+ tsch 0(%r5)
.Lnoreset:
- b .Lnoload
+ b .Lnoload
- .align 8
+ .align 8
.Lrdrnewpsw:
- .long 0x00080000,0x80000000+.Lrdrint
+ .long 0x00080000,0x80000000+.Lrdrint
.Lrdrwaitpsw:
- .long 0x020a0000,0x80000000+.Lrdrint
+ .long 0x020a0000,0x80000000+.Lrdrint
#endif
#
# everything loaded, go for it
#
.Lnoload:
- l %r1,.Lstartup
- br %r1
+ l %r1,.Lstartup
+ br %r1
-.Linitrd:.long _end + 0x400000 # default address of initrd
+.Linitrd:.long _end + 0x400000 # default address of initrd
.Lparm: .long PARMAREA
.Lstartup: .long startup
-.Lcvtab:.long _ebcasc # ebcdic to ascii table
-.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
- .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
- .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
-.L_eof: .long 0xc5d6c600 /* C'EOF' */
-.L_hdr: .long 0xc8c4d900 /* C'HDR' */
+.Lcvtab:.long _ebcasc # ebcdic to ascii table
+.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
+ .byte 0xc1,0xd3,0xd3,0x40,0xd2,0xc5,0xc5,0xd7,0x40,0xd5,0xd6
+ .byte 0xc8,0xd6,0xd3,0xc4 # "change rdr all keep nohold"
+.L_eof: .long 0xc5d6c600 /* C'EOF' */
+.L_hdr: .long 0xc8c4d900 /* C'HDR' */
-#endif /* CONFIG_IPL */
+#endif /* CONFIG_IPL */
#
# SALIPL loader support. Based on a patch by Rob van der Heij.
# This entry point is called directly from the SALIPL loader and
# doesn't need a builtin ipl record.
#
- .org 0x800
- .globl start
+ .org 0x800
+ .globl start
start:
- stm %r0,%r15,0x07b0 # store registers
- basr %r12,%r0
+ stm %r0,%r15,0x07b0 # store registers
+ basr %r12,%r0
.base:
- l %r11,.parm
- l %r8,.cmd # pointer to command buffer
+ l %r11,.parm
+ l %r8,.cmd # pointer to command buffer
- ltr %r9,%r9 # do we have SALIPL parameters?
- bp .sk8x8
+ ltr %r9,%r9 # do we have SALIPL parameters?
+ bp .sk8x8
- mvc 0(64,%r8),0x00b0 # copy saved registers
- xc 64(240-64,%r8),0(%r8) # remainder of buffer
- tr 0(64,%r8),.lowcase
- b .gotr
+ mvc 0(64,%r8),0x00b0 # copy saved registers
+ xc 64(240-64,%r8),0(%r8) # remainder of buffer
+ tr 0(64,%r8),.lowcase
+ b .gotr
.sk8x8:
- mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
+ mvc 0(240,%r8),0(%r9) # copy iplparms into buffer
.gotr:
- l %r10,.tbl # EBCDIC to ASCII table
- tr 0(240,%r8),0(%r10)
- stidp __LC_CPUID # Are we running on VM maybe
- cli __LC_CPUID,0xff
- bnz .test
- .long 0x83300060 # diag 3,0,x'0060' - storage size
- b .done
+ l %r10,.tbl # EBCDIC to ASCII table
+ tr 0(240,%r8),0(%r10)
+ stidp __LC_CPUID # Are we running on VM maybe
+ cli __LC_CPUID,0xff
+ bnz .test
+ .long 0x83300060 # diag 3,0,x'0060' - storage size
+ b .done
.test:
- mvc 0x68(8),.pgmnw # set up pgm check handler
- l %r2,.fourmeg
- lr %r3,%r2
- bctr %r3,%r0 # 4M-1
-.loop: iske %r0,%r3
- ar %r3,%r2
+ mvc 0x68(8),.pgmnw # set up pgm check handler
+ l %r2,.fourmeg
+ lr %r3,%r2
+ bctr %r3,%r0 # 4M-1
+.loop: iske %r0,%r3
+ ar %r3,%r2
.pgmx:
- sr %r3,%r2
- la %r3,1(%r3)
+ sr %r3,%r2
+ la %r3,1(%r3)
.done:
- l %r1,.memsize
- st %r3,ARCH_OFFSET(%r1)
- slr %r0,%r0
- st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
- st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
- j startup # continue with startup
-.tbl: .long _ebcasc # translate table
-.cmd: .long COMMAND_LINE # address of command line buffer
-.parm: .long PARMAREA
+ l %r1,.memsize
+ st %r3,ARCH_OFFSET(%r1)
+ slr %r0,%r0
+ st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11)
+ st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11)
+ j startup # continue with startup
+.tbl: .long _ebcasc # translate table
+.cmd: .long COMMAND_LINE # address of command line buffer
+.parm: .long PARMAREA
.memsize: .long memory_size
.fourmeg: .long 0x00400000 # 4M
-.pgmnw: .long 0x00080000,.pgmx
+.pgmnw: .long 0x00080000,.pgmx
.lowcase:
- .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
+ .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07
.byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f
- .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
+ .byte 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17
.byte 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f
- .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
+ .byte 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
.byte 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f
- .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
+ .byte 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37
.byte 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f
- .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
+ .byte 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47
.byte 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f
- .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
+ .byte 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57
.byte 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f
- .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
+ .byte 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67
.byte 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f
- .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
+ .byte 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77
.byte 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f
- .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
+ .byte 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87
.byte 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f
- .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
+ .byte 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97
.byte 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
- .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
+ .byte 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7
.byte 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf
- .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
+ .byte 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7
.byte 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf
- .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
+ .byte 0xc0,0x81,0x82,0x83,0x84,0x85,0x86,0x87 # .abcdefg
.byte 0x88,0x89,0xca,0xcb,0xcc,0xcd,0xce,0xcf # hi
- .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
+ .byte 0xd0,0x91,0x92,0x93,0x94,0x95,0x96,0x97 # .jklmnop
.byte 0x98,0x99,0xda,0xdb,0xdc,0xdd,0xde,0xdf # qr
.byte 0xe0,0xe1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 # ..stuvwx
.byte 0xa8,0xa9,0xea,0xeb,0xec,0xed,0xee,0xef # yz
- .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
+ .byte 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7
.byte 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
#ifdef CONFIG_64BIT
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S
index 1fa9fa1ca740..0a2c929486ab 100644
--- a/arch/s390/kernel/head31.S
+++ b/arch/s390/kernel/head31.S
@@ -254,6 +254,16 @@ startup_continue:
oi 3(%r12),0x80 # set IDTE flag
.Lchkidte:
+#
+# find out if the diag 0x9c is available
+#
+ mvc __LC_PGM_NEW_PSW(8),.Lpcdiag9c-.LPG1(%r13)
+ stap __LC_CPUID+4 # store cpu address
+ lh %r1,__LC_CPUID+4
+ diag %r1,0,0x9c # test diag 0x9c
+ oi 2(%r12),1 # set diag9c flag
+.Lchkdiag9c:
+
lpsw .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.align 8
@@ -281,6 +291,7 @@ startup_continue:
.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
.Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte
+.Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c
.Lmemsize:.long memory_size
.Lmchunk:.long memory_chunk
.Lmflags:.long machine_flags
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S
index a8bdd96494c7..42f54d482441 100644
--- a/arch/s390/kernel/head64.S
+++ b/arch/s390/kernel/head64.S
@@ -15,232 +15,232 @@
# this is called either by the ipl loader or directly by PSW restart
# or linload or SALIPL
#
- .org 0x10000
-startup:basr %r13,0 # get base
-.LPG0: l %r13,0f-.LPG0(%r13)
- b 0(%r13)
-0: .long startup_continue
+ .org 0x10000
+startup:basr %r13,0 # get base
+.LPG0: l %r13,0f-.LPG0(%r13)
+ b 0(%r13)
+0: .long startup_continue
#
# params at 10400 (setup.h)
#
- .org PARMAREA
- .quad 0 # IPL_DEVICE
- .quad 0 # INITRD_START
- .quad 0 # INITRD_SIZE
+ .org PARMAREA
+ .quad 0 # IPL_DEVICE
+ .quad 0 # INITRD_START
+ .quad 0 # INITRD_SIZE
- .org COMMAND_LINE
- .byte "root=/dev/ram0 ro"
- .byte 0
+ .org COMMAND_LINE
+ .byte "root=/dev/ram0 ro"
+ .byte 0
- .org 0x11000
+ .org 0x11000
startup_continue:
- basr %r13,0 # get base
-.LPG1: sll %r13,1 # remove high order bit
- srl %r13,1
- lhi %r1,1 # mode 1 = esame
- mvi __LC_AR_MODE_ID,1 # set esame flag
- slr %r0,%r0 # set cpuid to zero
- sigp %r1,%r0,0x12 # switch to esame mode
- sam64 # switch to 64 bit mode
- lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
- lg %r12,.Lparmaddr-.LPG1(%r13)# pointer to parameter area
- # move IPL device to lowcore
- mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
+ basr %r13,0 # get base
+.LPG1: sll %r13,1 # remove high order bit
+ srl %r13,1
+ lhi %r1,1 # mode 1 = esame
+ mvi __LC_AR_MODE_ID,1 # set esame flag
+ slr %r0,%r0 # set cpuid to zero
+ sigp %r1,%r0,0x12 # switch to esame mode
+ sam64 # switch to 64 bit mode
+ lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
+ lg %r12,.Lparmaddr-.LPG1(%r13) # pointer to parameter area
+ # move IPL device to lowcore
+ mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
#
# Setup stack
#
- larl %r15,init_thread_union
- lg %r14,__TI_task(%r15) # cache current in lowcore
- stg %r14,__LC_CURRENT
- aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
- stg %r15,__LC_KERNEL_STACK # set end of kernel stack
- aghi %r15,-160
- xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
+ larl %r15,init_thread_union
+ lg %r14,__TI_task(%r15) # cache current in lowcore
+ stg %r14,__LC_CURRENT
+ aghi %r15,1<<(PAGE_SHIFT+THREAD_ORDER) # init_task_union + THREAD_SIZE
+ stg %r15,__LC_KERNEL_STACK # set end of kernel stack
+ aghi %r15,-160
+ xc __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
- brasl %r14,ipl_save_parameters
+ brasl %r14,ipl_save_parameters
#
# clear bss memory
#
- larl %r2,__bss_start # start of bss segment
- larl %r3,_end # end of bss segment
- sgr %r3,%r2 # length of bss
- sgr %r4,%r4 #
- sgr %r5,%r5 # set src,length and pad to zero
- mvcle %r2,%r4,0 # clear mem
- jo .-4 # branch back, if not finish
+ larl %r2,__bss_start # start of bss segment
+ larl %r3,_end # end of bss segment
+ sgr %r3,%r2 # length of bss
+ sgr %r4,%r4 #
+ sgr %r5,%r5 # set src,length and pad to zero
+ mvcle %r2,%r4,0 # clear mem
+ jo .-4 # branch back, if not finish
- l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
+ l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word
.Lservicecall:
- stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
+ stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts
- stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0
- la %r1,0x200 # set bit 22
- og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
- stg %r1,.Lcr-.LPG1(%r13)
- lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0
+ stctg %r0,%r0,.Lcr-.LPG1(%r13) # get cr0
+ la %r1,0x200 # set bit 22
+ og %r1,.Lcr-.LPG1(%r13) # or old cr0 with r1
+ stg %r1,.Lcr-.LPG1(%r13)
+ lctlg %r0,%r0,.Lcr-.LPG1(%r13) # load modified cr0
- mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
- larl %r1,.Lsclph
- stg %r1,__LC_EXT_NEW_PSW+8 # set handler
+ mvc __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
+ larl %r1,.Lsclph
+ stg %r1,__LC_EXT_NEW_PSW+8 # set handler
- larl %r4,.Lsccb # %r4 is our index for sccb stuff
- lgr %r1,%r4 # our sccb
- .insn rre,0xb2200000,%r2,%r1 # service call
- ipm %r1
- srl %r1,28 # get cc code
- xr %r3,%r3
- chi %r1,3
- be .Lfchunk-.LPG1(%r13) # leave
- chi %r1,2
- be .Lservicecall-.LPG1(%r13)
- lpswe .Lwaitsclp-.LPG1(%r13)
+ larl %r4,.Lsccb # %r4 is our index for sccb stuff
+ lgr %r1,%r4 # our sccb
+ .insn rre,0xb2200000,%r2,%r1 # service call
+ ipm %r1
+ srl %r1,28 # get cc code
+ xr %r3,%r3
+ chi %r1,3
+ be .Lfchunk-.LPG1(%r13) # leave
+ chi %r1,2
+ be .Lservicecall-.LPG1(%r13)
+ lpswe .Lwaitsclp-.LPG1(%r13)
.Lsclph:
- lh %r1,.Lsccbr-.Lsccb(%r4)
- chi %r1,0x10 # 0x0010 is the sucess code
- je .Lprocsccb # let's process the sccb
- chi %r1,0x1f0
- bne .Lfchunk-.LPG1(%r13) # unhandled error code
- c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced
- bne .Lfchunk-.LPG1(%r13) # if no, give up
- l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP
- b .Lservicecall-.LPG1(%r13)
+ lh %r1,.Lsccbr-.Lsccb(%r4)
+ chi %r1,0x10 # 0x0010 is the sucess code
+ je .Lprocsccb # let's process the sccb
+ chi %r1,0x1f0
+ bne .Lfchunk-.LPG1(%r13) # unhandled error code
+ c %r2,.Lrcp-.LPG1(%r13) # Did we try Read SCP forced
+ bne .Lfchunk-.LPG1(%r13) # if no, give up
+ l %r2,.Lrcp2-.LPG1(%r13) # try with Read SCP
+ b .Lservicecall-.LPG1(%r13)
.Lprocsccb:
- lghi %r1,0
- icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
- jnz .Lscnd
- lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one
+ lghi %r1,0
+ icm %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
+ jnz .Lscnd
+ lg %r1,.Lscpincr2-.Lsccb(%r4) # otherwise use this one
.Lscnd:
- xr %r3,%r3 # same logic
- ic %r3,.Lscpa1-.Lsccb(%r4)
- chi %r3,0x00
- jne .Lcompmem
- l %r3,.Lscpa2-.Lsccb(%r4)
+ xr %r3,%r3 # same logic
+ ic %r3,.Lscpa1-.Lsccb(%r4)
+ chi %r3,0x00
+ jne .Lcompmem
+ l %r3,.Lscpa2-.Lsccb(%r4)
.Lcompmem:
- mlgr %r2,%r1 # mem in MB on 128-bit
- l %r1,.Lonemb-.LPG1(%r13)
- mlgr %r2,%r1 # mem size in bytes in %r3
- b .Lfchunk-.LPG1(%r13)
+ mlgr %r2,%r1 # mem in MB on 128-bit
+ l %r1,.Lonemb-.LPG1(%r13)
+ mlgr %r2,%r1 # mem size in bytes in %r3
+ b .Lfchunk-.LPG1(%r13)
- .align 4
+ .align 4
.Lpmask:
- .byte 0
- .align 8
+ .byte 0
+ .align 8
.Lcr:
- .quad 0x00 # place holder for cr0
+ .quad 0x00 # place holder for cr0
.Lwaitsclp:
- .quad 0x0102000180000000,.Lsclph
+ .quad 0x0102000180000000,.Lsclph
.Lrcp:
- .int 0x00120001 # Read SCP forced code
+ .int 0x00120001 # Read SCP forced code
.Lrcp2:
- .int 0x00020001 # Read SCP code
+ .int 0x00020001 # Read SCP code
.Lonemb:
- .int 0x100000
+ .int 0x100000
.Lfchunk:
- # set program check new psw mask
- mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
+ # set program check new psw mask
+ mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
#
# find memory chunks.
#
- lgr %r9,%r3 # end of mem
- larl %r1,.Lchkmem # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- la %r1,1 # test in increments of 128KB
- sllg %r1,%r1,17
- larl %r3,memory_chunk
- slgr %r4,%r4 # set start of chunk to zero
- slgr %r5,%r5 # set end of chunk to zero
- slr %r6,%r6 # set access code to zero
- la %r10,MEMORY_CHUNKS # number of chunks
+ lgr %r9,%r3 # end of mem
+ larl %r1,.Lchkmem # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ la %r1,1 # test in increments of 128KB
+ sllg %r1,%r1,17
+ larl %r3,memory_chunk
+ slgr %r4,%r4 # set start of chunk to zero
+ slgr %r5,%r5 # set end of chunk to zero
+ slr %r6,%r6 # set access code to zero
+ la %r10,MEMORY_CHUNKS # number of chunks
.Lloop:
- tprot 0(%r5),0 # test protection of first byte
- ipm %r7
- srl %r7,28
- clr %r6,%r7 # compare cc with last access code
- je .Lsame
- j .Lchkmem
+ tprot 0(%r5),0 # test protection of first byte
+ ipm %r7
+ srl %r7,28
+ clr %r6,%r7 # compare cc with last access code
+ je .Lsame
+ j .Lchkmem
.Lsame:
- algr %r5,%r1 # add 128KB to end of chunk
- # no need to check here,
- brc 12,.Lloop # this is the same chunk
-.Lchkmem: # > 16EB or tprot got a program check
- clgr %r4,%r5 # chunk size > 0?
- je .Lchkloop
- stg %r4,0(%r3) # store start address of chunk
- lgr %r0,%r5
- slgr %r0,%r4
- stg %r0,8(%r3) # store size of chunk
- st %r6,20(%r3) # store type of chunk
- la %r3,24(%r3)
- larl %r8,memory_size
- stg %r5,0(%r8) # store memory size
- ahi %r10,-1 # update chunk number
+ algr %r5,%r1 # add 128KB to end of chunk
+ # no need to check here,
+ brc 12,.Lloop # this is the same chunk
+.Lchkmem: # > 16EB or tprot got a program check
+ clgr %r4,%r5 # chunk size > 0?
+ je .Lchkloop
+ stg %r4,0(%r3) # store start address of chunk
+ lgr %r0,%r5
+ slgr %r0,%r4
+ stg %r0,8(%r3) # store size of chunk
+ st %r6,20(%r3) # store type of chunk
+ la %r3,24(%r3)
+ larl %r8,memory_size
+ stg %r5,0(%r8) # store memory size
+ ahi %r10,-1 # update chunk number
.Lchkloop:
- lr %r6,%r7 # set access code to last cc
+ lr %r6,%r7 # set access code to last cc
# we got an exception or we're starting a new
# chunk , we must check if we should
# still try to find valid memory (if we detected
# the amount of available storage), and if we
# have chunks left
- lghi %r4,1
- sllg %r4,%r4,31
- clgr %r5,%r4
- je .Lhsaskip
- xr %r0, %r0
- clgr %r0, %r9 # did we detect memory?
- je .Ldonemem # if not, leave
- chi %r10, 0 # do we have chunks left?
- je .Ldonemem
+ lghi %r4,1
+ sllg %r4,%r4,31
+ clgr %r5,%r4
+ je .Lhsaskip
+ xr %r0, %r0
+ clgr %r0, %r9 # did we detect memory?
+ je .Ldonemem # if not, leave
+ chi %r10, 0 # do we have chunks left?
+ je .Ldonemem
.Lhsaskip:
- algr %r5,%r1 # add 128KB to end of chunk
- lgr %r4,%r5 # potential new chunk
- clgr %r5,%r9 # should we go on?
- jl .Lloop
-.Ldonemem:
+ algr %r5,%r1 # add 128KB to end of chunk
+ lgr %r4,%r5 # potential new chunk
+ clgr %r5,%r9 # should we go on?
+ jl .Lloop
+.Ldonemem:
- larl %r12,machine_flags
+ larl %r12,machine_flags
#
# find out if we are running under VM
#
- stidp __LC_CPUID # store cpuid
- tm __LC_CPUID,0xff # running under VM ?
- bno 0f-.LPG1(%r13)
- oi 7(%r12),1 # set VM flag
-0: lh %r0,__LC_CPUID+4 # get cpu version
- chi %r0,0x7490 # running on a P/390 ?
- bne 1f-.LPG1(%r13)
- oi 7(%r12),4 # set P/390 flag
+ stidp __LC_CPUID # store cpuid
+ tm __LC_CPUID,0xff # running under VM ?
+ bno 0f-.LPG1(%r13)
+ oi 7(%r12),1 # set VM flag
+0: lh %r0,__LC_CPUID+4 # get cpu version
+ chi %r0,0x7490 # running on a P/390 ?
+ bne 1f-.LPG1(%r13)
+ oi 7(%r12),4 # set P/390 flag
1:
#
# find out if we have the MVPG instruction
#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- sgr %r0,%r0
- lghi %r1,0
- lghi %r2,0
- mvpg %r1,%r2 # test MVPG instruction
- oi 7(%r12),16 # set MVPG flag
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ sgr %r0,%r0
+ lghi %r1,0
+ lghi %r2,0
+ mvpg %r1,%r2 # test MVPG instruction
+ oi 7(%r12),16 # set MVPG flag
0:
#
# find out if the diag 0x44 works in 64 bit mode
#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
- diag 0,0,0x44 # test diag 0x44
- oi 7(%r12),32 # set diag44 flag
-0:
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ diag 0,0,0x44 # test diag 0x44
+ oi 7(%r12),32 # set diag44 flag
+0:
#
# find out if we have the IDTE instruction
#
- la %r1,0f-.LPG1(%r13) # set program check address
- stg %r1,__LC_PGM_NEW_PSW+8
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
.long 0xb2b10000 # store facility list
tm 0xc8,0x08 # check bit for clearing-by-ASCE
bno 0f-.LPG1(%r13)
@@ -251,6 +251,17 @@ startup_continue:
0:
#
+# find out if the diag 0x9c is available
+#
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ stap __LC_CPUID+4 # store cpu address
+ lh %r1,__LC_CPUID+4
+ diag %r1,0,0x9c # test diag 0x9c
+ oi 6(%r12),1 # set diag9c flag
+0:
+
+#
# find out if we have the MVCOS instruction
#
la %r1,0f-.LPG1(%r13) # set program check address
@@ -263,45 +274,45 @@ startup_continue:
oi 6(%r12),2 # set MVCOS flag
1:
- lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
- # virtual and never return ...
- .align 16
-.Lentry:.quad 0x0000000180000000,_stext
-.Lctl: .quad 0x04b50002 # cr0: various things
- .quad 0 # cr1: primary space segment table
- .quad .Lduct # cr2: dispatchable unit control table
- .quad 0 # cr3: instruction authorization
- .quad 0 # cr4: instruction authorization
- .quad 0xffffffffffffffff # cr5: primary-aste origin
- .quad 0 # cr6: I/O interrupts
- .quad 0 # cr7: secondary space segment table
- .quad 0 # cr8: access registers translation
- .quad 0 # cr9: tracing off
- .quad 0 # cr10: tracing off
- .quad 0 # cr11: tracing off
- .quad 0 # cr12: tracing off
- .quad 0 # cr13: home space segment table
- .quad 0xc0000000 # cr14: machine check handling off
- .quad 0 # cr15: linkage stack operations
-.Lduct: .long 0,0,0,0,0,0,0,0
- .long 0,0,0,0,0,0,0,0
-.Lpcmsk:.quad 0x0000000180000000
+ lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
+ # virtual and never return ...
+ .align 16
+.Lentry:.quad 0x0000000180000000,_stext
+.Lctl: .quad 0x04b50002 # cr0: various things
+ .quad 0 # cr1: primary space segment table
+ .quad .Lduct # cr2: dispatchable unit control table
+ .quad 0 # cr3: instruction authorization
+ .quad 0 # cr4: instruction authorization
+ .quad 0xffffffffffffffff # cr5: primary-aste origin
+ .quad 0 # cr6: I/O interrupts
+ .quad 0 # cr7: secondary space segment table
+ .quad 0 # cr8: access registers translation
+ .quad 0 # cr9: tracing off
+ .quad 0 # cr10: tracing off
+ .quad 0 # cr11: tracing off
+ .quad 0 # cr12: tracing off
+ .quad 0 # cr13: home space segment table
+ .quad 0xc0000000 # cr14: machine check handling off
+ .quad 0 # cr15: linkage stack operations
+.Lduct: .long 0,0,0,0,0,0,0,0
+ .long 0,0,0,0,0,0,0,0
+.Lpcmsk:.quad 0x0000000180000000
.L4malign:.quad 0xffffffffffc00000
-.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
-.Lnop: .long 0x07000700
+.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
+.Lnop: .long 0x07000700
.Lparmaddr:
.quad PARMAREA
- .globl ipl_schib
+ .globl ipl_schib
ipl_schib:
.rept 13
.long 0
.endr
- .globl ipl_flags
+ .globl ipl_flags
ipl_flags:
- .long 0
- .globl ipl_devno
+ .long 0
+ .globl ipl_devno
ipl_devno:
.word 0
@@ -309,47 +320,47 @@ ipl_devno:
.globl s390_readinfo_sccb
s390_readinfo_sccb:
.Lsccb:
- .hword 0x1000 # length, one page
- .byte 0x00,0x00,0x00
- .byte 0x80 # variable response bit set
+ .hword 0x1000 # length, one page
+ .byte 0x00,0x00,0x00
+ .byte 0x80 # variable response bit set
.Lsccbr:
- .hword 0x00 # response code
+ .hword 0x00 # response code
.Lscpincr1:
- .hword 0x00
+ .hword 0x00
.Lscpa1:
- .byte 0x00
- .fill 89,1,0
+ .byte 0x00
+ .fill 89,1,0
.Lscpa2:
- .int 0x00
+ .int 0x00
.Lscpincr2:
- .quad 0x00
- .fill 3984,1,0
+ .quad 0x00
+ .fill 3984,1,0
.org 0x13000
#ifdef CONFIG_SHARED_KERNEL
- .org 0x100000
+ .org 0x100000
#endif
-
+
#
# startup-code, running in absolute addressing mode
#
- .globl _stext
-_stext: basr %r13,0 # get base
+ .globl _stext
+_stext: basr %r13,0 # get base
.LPG3:
# check control registers
- stctg %c0,%c15,0(%r15)
- oi 6(%r15),0x40 # enable sigp emergency signal
- oi 4(%r15),0x10 # switch on low address proctection
- lctlg %c0,%c15,0(%r15)
+ stctg %c0,%c15,0(%r15)
+ oi 6(%r15),0x40 # enable sigp emergency signal
+ oi 4(%r15),0x10 # switch on low address proctection
+ lctlg %c0,%c15,0(%r15)
- lam 0,15,.Laregs-.LPG3(%r13) # load access regs needed by uaccess
- brasl %r14,start_kernel # go to C code
+ lam 0,15,.Laregs-.LPG3(%r13) # load acrs needed by uaccess
+ brasl %r14,start_kernel # go to C code
#
# We returned from start_kernel ?!? PANIK
#
- basr %r13,0
- lpswe .Ldw-.(%r13) # load disabled wait psw
+ basr %r13,0
+ lpswe .Ldw-.(%r13) # load disabled wait psw
- .align 8
-.Ldw: .quad 0x0002000180000000,0x0000000000000000
-.Laregs: .long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+ .align 8
+.Ldw: .quad 0x0002000180000000,0x0000000000000000
+.Laregs:.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c
index 6555cc48e28f..1f5e782b3d05 100644
--- a/arch/s390/kernel/ipl.c
+++ b/arch/s390/kernel/ipl.c
@@ -120,24 +120,15 @@ static enum shutdown_action on_panic_action = SHUTDOWN_STOP;
static int diag308(unsigned long subcode, void *addr)
{
- register unsigned long _addr asm("0") = (unsigned long)addr;
+ register unsigned long _addr asm("0") = (unsigned long) addr;
register unsigned long _rc asm("1") = 0;
- asm volatile (
- " diag %0,%2,0x308\n"
- "0: \n"
- ".section __ex_table,\"a\"\n"
-#ifdef CONFIG_64BIT
- " .align 8\n"
- " .quad 0b, 0b\n"
-#else
- " .align 4\n"
- " .long 0b, 0b\n"
-#endif
- ".previous\n"
+ asm volatile(
+ " diag %0,%2,0x308\n"
+ "0:\n"
+ EX_TABLE(0b,0b)
: "+d" (_addr), "+d" (_rc)
- : "d" (subcode) : "cc", "memory" );
-
+ : "d" (subcode) : "cc", "memory");
return _rc;
}
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c
index ca28fb0b3790..67914fe7f317 100644
--- a/arch/s390/kernel/kprobes.c
+++ b/arch/s390/kernel/kprobes.c
@@ -20,7 +20,6 @@
* s390 port, used ppc64 as template. Mike Grundy <grundym@us.ibm.com>
*/
-#include <linux/config.h>
#include <linux/kprobes.h>
#include <linux/ptrace.h>
#include <linux/preempt.h>
@@ -369,11 +368,12 @@ void __kprobes kretprobe_trampoline_holder(void)
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
+ struct hlist_head *head, empty_rp;
struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline;
+ INIT_HLIST_HEAD(&empty_rp);
spin_lock_irqsave(&kretprobe_lock, flags);
head = kretprobe_inst_table_head(current);
@@ -399,7 +399,7 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_rp_inst(ri);
+ recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address) {
/*
@@ -417,6 +417,10 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
spin_unlock_irqrestore(&kretprobe_lock, flags);
preempt_enable_no_resched();
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
/*
* By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index d3cbfa3005ec..6603fbb41d07 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -45,7 +45,7 @@
#include <asm/irq.h>
#include <asm/timer.h>
-asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
+asmlinkage void ret_from_fork(void) asm ("ret_from_fork");
/*
* Return saved PC of a blocked thread. used in kernel/sched.
@@ -177,7 +177,8 @@ void show_regs(struct pt_regs *regs)
extern void kernel_thread_starter(void);
-__asm__(".align 4\n"
+asm(
+ ".align 4\n"
"kernel_thread_starter:\n"
" la 2,0(10)\n"
" basr 14,9\n"
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S
index 4562cdbce8eb..0340477f3b08 100644
--- a/arch/s390/kernel/reipl.S
+++ b/arch/s390/kernel/reipl.S
@@ -32,58 +32,58 @@ do_reipl_asm: basr %r13,0
st %r13, __LC_PSW_SAVE_AREA+4
lctl %c6,%c6,.Lall-.Lpg0(%r13)
- lr %r1,%r2
- mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
- stsch .Lschib-.Lpg0(%r13)
- oi .Lschib+5-.Lpg0(%r13),0x84
-.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
- msch .Lschib-.Lpg0(%r13)
- lhi %r0,5
-.Lssch: ssch .Liplorb-.Lpg0(%r13)
+ lr %r1,%r2
+ mvc __LC_PGM_NEW_PSW(8),.Lpcnew-.Lpg0(%r13)
+ stsch .Lschib-.Lpg0(%r13)
+ oi .Lschib+5-.Lpg0(%r13),0x84
+.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
+ msch .Lschib-.Lpg0(%r13)
+ lhi %r0,5
+.Lssch: ssch .Liplorb-.Lpg0(%r13)
jz .L001
- brct %r0,.Lssch
+ brct %r0,.Lssch
bas %r14,.Ldisab-.Lpg0(%r13)
-.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
-.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
+.L001: mvc __LC_IO_NEW_PSW(8),.Lionew-.Lpg0(%r13)
+.Ltpi: lpsw .Lwaitpsw-.Lpg0(%r13)
.Lcont: c %r1,__LC_SUBCHANNEL_ID
jnz .Ltpi
clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
jnz .Ltpi
- tsch .Liplirb-.Lpg0(%r13)
+ tsch .Liplirb-.Lpg0(%r13)
tm .Liplirb+9-.Lpg0(%r13),0xbf
- jz .L002
- bas %r14,.Ldisab-.Lpg0(%r13)
-.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
- jz .L003
- bas %r14,.Ldisab-.Lpg0(%r13)
+ jz .L002
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
+ jz .L003
+ bas %r14,.Ldisab-.Lpg0(%r13)
.L003: spx .Lnull-.Lpg0(%r13)
- st %r1,__LC_SUBCHANNEL_ID
- lpsw 0
- sigp 0,0,0(6)
-.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
+ st %r1,__LC_SUBCHANNEL_ID
+ lpsw 0
+ sigp 0,0,0(6)
+.Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13)
lpsw .Ldispsw-.Lpg0(%r13)
- .align 8
+ .align 8
.Lclkcmp: .quad 0x0000000000000000
.Lall: .long 0xff000000
-.Lnull: .long 0x00000000
+.Lnull: .long 0x00000000
.Lctlsave1: .long 0x00000000
.Lctlsave2: .long 0x00000000
- .align 8
-.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
-.Lpcnew: .long 0x00080000,0x80000000+.Lecs
-.Lionew: .long 0x00080000,0x80000000+.Lcont
+ .align 8
+.Lnewpsw: .long 0x00080000,0x80000000+.Lpg1
+.Lpcnew: .long 0x00080000,0x80000000+.Lecs
+.Lionew: .long 0x00080000,0x80000000+.Lcont
.Lwaitpsw: .long 0x020a0000,0x00000000+.Ltpi
-.Ldispsw: .long 0x000a0000,0x00000000
-.Liplccws: .long 0x02000000,0x60000018
- .long 0x08000008,0x20000001
+.Ldispsw: .long 0x000a0000,0x00000000
+.Liplccws: .long 0x02000000,0x60000018
+ .long 0x08000008,0x20000001
.Liplorb: .long 0x0049504c,0x0040ff80
.long 0x00000000+.Liplccws
-.Lschib: .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
+.Lschib: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
.Liplirb: .long 0x00000000,0x00000000
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
@@ -92,6 +92,3 @@ do_reipl_asm: basr %r13,0
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
-
-
-
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S
index 95bd1e234f63..de7435054f7c 100644
--- a/arch/s390/kernel/reipl64.S
+++ b/arch/s390/kernel/reipl64.S
@@ -4,7 +4,7 @@
* S390 version
* Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com)
- Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+ Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
*/
#include <asm/lowcore.h>
@@ -32,46 +32,46 @@ do_reipl_asm: basr %r13,0
stctg %c0,%c0,.Lregsave-.Lpg0(%r13)
ni .Lregsave+4-.Lpg0(%r13),0xef
lctlg %c0,%c0,.Lregsave-.Lpg0(%r13)
- lgr %r1,%r2
- mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
- stsch .Lschib-.Lpg0(%r13)
- oi .Lschib+5-.Lpg0(%r13),0x84
-.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
- msch .Lschib-.Lpg0(%r13)
- lghi %r0,5
-.Lssch: ssch .Liplorb-.Lpg0(%r13)
+ lgr %r1,%r2
+ mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13)
+ stsch .Lschib-.Lpg0(%r13)
+ oi .Lschib+5-.Lpg0(%r13),0x84
+.Lecs: xi .Lschib+27-.Lpg0(%r13),0x01
+ msch .Lschib-.Lpg0(%r13)
+ lghi %r0,5
+.Lssch: ssch .Liplorb-.Lpg0(%r13)
jz .L001
- brct %r0,.Lssch
+ brct %r0,.Lssch
bas %r14,.Ldisab-.Lpg0(%r13)
-.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
-.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
+.L001: mvc __LC_IO_NEW_PSW(16),.Lionew-.Lpg0(%r13)
+.Ltpi: lpswe .Lwaitpsw-.Lpg0(%r13)
.Lcont: c %r1,__LC_SUBCHANNEL_ID
jnz .Ltpi
clc __LC_IO_INT_PARM(4),.Liplorb-.Lpg0(%r13)
jnz .Ltpi
- tsch .Liplirb-.Lpg0(%r13)
+ tsch .Liplirb-.Lpg0(%r13)
tm .Liplirb+9-.Lpg0(%r13),0xbf
- jz .L002
- bas %r14,.Ldisab-.Lpg0(%r13)
-.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
- jz .L003
- bas %r14,.Ldisab-.Lpg0(%r13)
+ jz .L002
+ bas %r14,.Ldisab-.Lpg0(%r13)
+.L002: tm .Liplirb+8-.Lpg0(%r13),0xf3
+ jz .L003
+ bas %r14,.Ldisab-.Lpg0(%r13)
.L003: spx .Lnull-.Lpg0(%r13)
- st %r1,__LC_SUBCHANNEL_ID
- lhi %r1,0 # mode 0 = esa
- slr %r0,%r0 # set cpuid to zero
- sigp %r1,%r0,0x12 # switch to esa mode
- lpsw 0
-.Ldisab: sll %r14,1
- srl %r14,1 # need to kill hi bit to avoid specification exceptions.
- st %r14,.Ldispsw+12-.Lpg0(%r13)
+ st %r1,__LC_SUBCHANNEL_ID
+ lhi %r1,0 # mode 0 = esa
+ slr %r0,%r0 # set cpuid to zero
+ sigp %r1,%r0,0x12 # switch to esa mode
+ lpsw 0
+.Ldisab: sll %r14,1
+ srl %r14,1 # need to kill hi bit to avoid specification exceptions.
+ st %r14,.Ldispsw+12-.Lpg0(%r13)
lpswe .Ldispsw-.Lpg0(%r13)
- .align 8
+ .align 8
.Lclkcmp: .quad 0x0000000000000000
.Lall: .quad 0x00000000ff000000
.Lregsave: .quad 0x0000000000000000
-.Lnull: .long 0x0000000000000000
- .align 16
+.Lnull: .long 0x0000000000000000
+ .align 16
/*
* These addresses have to be 31 bit otherwise
* the sigp will throw a specifcation exception
@@ -81,26 +81,26 @@ do_reipl_asm: basr %r13,0
* 31bit lpswe instruction a fact they appear to have
* ommited from the pop.
*/
-.Lnewpsw: .quad 0x0000000080000000
- .quad .Lpg1
-.Lpcnew: .quad 0x0000000080000000
- .quad .Lecs
-.Lionew: .quad 0x0000000080000000
- .quad .Lcont
+.Lnewpsw: .quad 0x0000000080000000
+ .quad .Lpg1
+.Lpcnew: .quad 0x0000000080000000
+ .quad .Lecs
+.Lionew: .quad 0x0000000080000000
+ .quad .Lcont
.Lwaitpsw: .quad 0x0202000080000000
- .quad .Ltpi
-.Ldispsw: .quad 0x0002000080000000
- .quad 0x0000000000000000
-.Liplccws: .long 0x02000000,0x60000018
- .long 0x08000008,0x20000001
+ .quad .Ltpi
+.Ldispsw: .quad 0x0002000080000000
+ .quad 0x0000000000000000
+.Liplccws: .long 0x02000000,0x60000018
+ .long 0x08000008,0x20000001
.Liplorb: .long 0x0049504c,0x0040ff80
.long 0x00000000+.Liplccws
-.Lschib: .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
- .long 0x00000000,0x00000000
+.Lschib: .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
+ .long 0x00000000,0x00000000
.Liplirb: .long 0x00000000,0x00000000
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
@@ -109,4 +109,3 @@ do_reipl_asm: basr %r13,0
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
.long 0x00000000,0x00000000
-
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
index 2a25ec7147ff..f9899ff2e5b0 100644
--- a/arch/s390/kernel/relocate_kernel.S
+++ b/arch/s390/kernel/relocate_kernel.S
@@ -3,7 +3,7 @@
*
* (C) Copyright IBM Corp. 2005
*
- * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ * Author(s): Rolf Adelsberger,
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
*/
@@ -24,14 +24,14 @@
.text
.globl relocate_kernel
relocate_kernel:
- basr %r13,0 #base address
+ basr %r13,0 # base address
.base:
- stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external)
- spx zero64-.base(%r13) #absolute addressing mode
+ stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external)
+ spx zero64-.base(%r13) # absolute addressing mode
stctl %c0,%c15,ctlregs-.base(%r13)
stm %r0,%r15,gprregs-.base(%r13)
la %r1,load_psw-.base(%r13)
- mvc 0(8,%r0),0(%r1)
+ mvc 0(8,%r0),0(%r1)
la %r0,.back-.base(%r13)
st %r0,4(%r0)
oi 4(%r0),0x80
@@ -51,50 +51,50 @@
.back_pgm:
lm %r0,%r15,gprregs-.base(%r13)
.start_reloc:
- lhi %r10,-1 #preparing the mask
- sll %r10,12 #shift it such that it becomes 0xf000
+ lhi %r10,-1 # preparing the mask
+ sll %r10,12 # shift it such that it becomes 0xf000
.top:
- lhi %r7,4096 #load PAGE_SIZE in r7
- lhi %r9,4096 #load PAGE_SIZE in r9
- l %r5,0(%r2) #read another word for indirection page
- ahi %r2,4 #increment pointer
- tml %r5,0x1 #is it a destination page?
- je .indir_check #NO, goto "indir_check"
- lr %r6,%r5 #r6 = r5
- nr %r6,%r10 #mask it out and...
- j .top #...next iteration
+ lhi %r7,4096 # load PAGE_SIZE in r7
+ lhi %r9,4096 # load PAGE_SIZE in r9
+ l %r5,0(%r2) # read another word for indirection page
+ ahi %r2,4 # increment pointer
+ tml %r5,0x1 # is it a destination page?
+ je .indir_check # NO, goto "indir_check"
+ lr %r6,%r5 # r6 = r5
+ nr %r6,%r10 # mask it out and...
+ j .top # ...next iteration
.indir_check:
- tml %r5,0x2 #is it a indirection page?
- je .done_test #NO, goto "done_test"
- nr %r5,%r10 #YES, mask out,
- lr %r2,%r5 #move it into the right register,
- j .top #and read next...
+ tml %r5,0x2 # is it a indirection page?
+ je .done_test # NO, goto "done_test"
+ nr %r5,%r10 # YES, mask out,
+ lr %r2,%r5 # move it into the right register,
+ j .top # and read next...
.done_test:
- tml %r5,0x4 #is it the done indicator?
- je .source_test #NO! Well, then it should be the source indicator...
- j .done #ok, lets finish it here...
+ tml %r5,0x4 # is it the done indicator?
+ je .source_test # NO! Well, then it should be the source indicator...
+ j .done # ok, lets finish it here...
.source_test:
- tml %r5,0x8 #it should be a source indicator...
- je .top #NO, ignore it...
- lr %r8,%r5 #r8 = r5
- nr %r8,%r10 #masking
- 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+ tml %r5,0x8 # it should be a source indicator...
+ je .top # NO, ignore it...
+ lr %r8,%r5 # r8 = r5
+ nr %r8,%r10 # masking
+ 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0
jo 0b
j .top
.done:
- sr %r0,%r0 #clear register r0
- la %r4,load_psw-.base(%r13) #load psw-address into the register
- o %r3,4(%r4) #or load address into psw
+ sr %r0,%r0 # clear register r0
+ la %r4,load_psw-.base(%r13) # load psw-address into the register
+ o %r3,4(%r4) # or load address into psw
st %r3,4(%r4)
- mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0
+ mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0
tm have_diag308-.base(%r13),0x01
jno .no_diag308
diag %r0,%r0,0x308
.no_diag308:
- sr %r1,%r1 #clear %r1
- sr %r2,%r2 #clear %r2
- sigp %r1,%r2,0x12 #set cpuid to zero
- lpsw 0 #hopefully start new kernel...
+ sr %r1,%r1 # clear %r1
+ sr %r2,%r2 # clear %r2
+ sigp %r1,%r2,0x12 # set cpuid to zero
+ lpsw 0 # hopefully start new kernel...
.align 8
zero64:
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S
index 8cdb86e8911f..4fb443042d9c 100644
--- a/arch/s390/kernel/relocate_kernel64.S
+++ b/arch/s390/kernel/relocate_kernel64.S
@@ -3,7 +3,7 @@
*
* (C) Copyright IBM Corp. 2005
*
- * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ * Author(s): Rolf Adelsberger,
* Heiko Carstens <heiko.carstens@de.ibm.com>
*
*/
@@ -25,10 +25,10 @@
.text
.globl relocate_kernel
relocate_kernel:
- basr %r13,0 #base address
+ basr %r13,0 # base address
.base:
- stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQs
- spx zero64-.base(%r13) #absolute addressing mode
+ stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs
+ spx zero64-.base(%r13) # absolute addressing mode
stctg %c0,%c15,ctlregs-.base(%r13)
stmg %r0,%r15,gprregs-.base(%r13)
lghi %r0,3
@@ -37,16 +37,16 @@
la %r0,.back_pgm-.base(%r13)
stg %r0,0x1d8(%r0)
la %r1,load_psw-.base(%r13)
- mvc 0(8,%r0),0(%r1)
+ mvc 0(8,%r0),0(%r1)
la %r0,.back-.base(%r13)
st %r0,4(%r0)
oi 4(%r0),0x80
lghi %r0,0
diag %r0,%r0,0x308
.back:
- lhi %r1,1 #mode 1 = esame
- sigp %r1,%r0,0x12 #switch to esame mode
- sam64 #switch to 64 bit addressing mode
+ lhi %r1,1 # mode 1 = esame
+ sigp %r1,%r0,0x12 # switch to esame mode
+ sam64 # switch to 64 bit addressing mode
basr %r13,0
.back_base:
oi have_diag308-.back_base(%r13),0x01
@@ -56,50 +56,50 @@
.back_pgm:
lmg %r0,%r15,gprregs-.base(%r13)
.top:
- lghi %r7,4096 #load PAGE_SIZE in r7
- lghi %r9,4096 #load PAGE_SIZE in r9
- lg %r5,0(%r2) #read another word for indirection page
- aghi %r2,8 #increment pointer
- tml %r5,0x1 #is it a destination page?
- je .indir_check #NO, goto "indir_check"
- lgr %r6,%r5 #r6 = r5
- nill %r6,0xf000 #mask it out and...
- j .top #...next iteration
+ lghi %r7,4096 # load PAGE_SIZE in r7
+ lghi %r9,4096 # load PAGE_SIZE in r9
+ lg %r5,0(%r2) # read another word for indirection page
+ aghi %r2,8 # increment pointer
+ tml %r5,0x1 # is it a destination page?
+ je .indir_check # NO, goto "indir_check"
+ lgr %r6,%r5 # r6 = r5
+ nill %r6,0xf000 # mask it out and...
+ j .top # ...next iteration
.indir_check:
- tml %r5,0x2 #is it a indirection page?
- je .done_test #NO, goto "done_test"
- nill %r5,0xf000 #YES, mask out,
- lgr %r2,%r5 #move it into the right register,
- j .top #and read next...
+ tml %r5,0x2 # is it a indirection page?
+ je .done_test # NO, goto "done_test"
+ nill %r5,0xf000 # YES, mask out,
+ lgr %r2,%r5 # move it into the right register,
+ j .top # and read next...
.done_test:
- tml %r5,0x4 #is it the done indicator?
- je .source_test #NO! Well, then it should be the source indicator...
- j .done #ok, lets finish it here...
+ tml %r5,0x4 # is it the done indicator?
+ je .source_test # NO! Well, then it should be the source indicator...
+ j .done # ok, lets finish it here...
.source_test:
- tml %r5,0x8 #it should be a source indicator...
- je .top #NO, ignore it...
- lgr %r8,%r5 #r8 = r5
- nill %r8,0xf000 #masking
- 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+ tml %r5,0x8 # it should be a source indicator...
+ je .top # NO, ignore it...
+ lgr %r8,%r5 # r8 = r5
+ nill %r8,0xf000 # masking
+ 0: mvcle %r6,%r8,0x0 # copy PAGE_SIZE bytes from r8 to r6 - pad with 0
jo 0b
- j .top
+ j .top
.done:
- sgr %r0,%r0 #clear register r0
- la %r4,load_psw-.base(%r13) #load psw-address into the register
- o %r3,4(%r4) #or load address into psw
+ sgr %r0,%r0 # clear register r0
+ la %r4,load_psw-.base(%r13) # load psw-address into the register
+ o %r3,4(%r4) # or load address into psw
st %r3,4(%r4)
- mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0
+ mvc 0(8,%r0),0(%r4) # copy psw to absolute address 0
tm have_diag308-.base(%r13),0x01
jno .no_diag308
diag %r0,%r0,0x308
.no_diag308:
- sam31 #31 bit mode
- sr %r1,%r1 #erase register r1
- sr %r2,%r2 #erase register r2
- sigp %r1,%r2,0x12 #set cpuid to zero
- lpsw 0 #hopefully start new kernel...
+ sam31 # 31 bit mode
+ sr %r1,%r1 # erase register r1
+ sr %r2,%r2 # erase register r2
+ sigp %r1,%r2,0x12 # set cpuid to zero
+ lpsw 0 # hopefully start new kernel...
- .align 8
+ .align 8
zero64:
.quad 0
load_psw:
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index c1b383537fec..4faf96f8a834 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -16,6 +16,7 @@
#include <asm/lowcore.h>
#include <asm/s390_ext.h>
+#include <asm/irq_regs.h>
#include <asm/irq.h>
/*
@@ -114,7 +115,9 @@ void do_extint(struct pt_regs *regs, unsigned short code)
{
ext_int_info_t *p;
int index;
+ struct pt_regs *old_regs;
+ old_regs = set_irq_regs(regs);
irq_enter();
asm volatile ("mc 0,0");
if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
@@ -122,18 +125,18 @@ void do_extint(struct pt_regs *regs, unsigned short code)
* Make sure that the i/o interrupt did not "overtake"
* the last HZ timer interrupt.
*/
- account_ticks(regs);
+ account_ticks();
kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
index = ext_hash(code);
for (p = ext_int_hash[index]; p; p = p->next) {
if (likely(p->code == code)) {
if (likely(p->handler))
- p->handler(regs, code);
+ p->handler(code);
}
}
irq_exit();
+ set_irq_regs(old_regs);
}
EXPORT_SYMBOL(register_external_interrupt);
EXPORT_SYMBOL(unregister_external_interrupt);
-
diff --git a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
index 9f19e833a562..90b5ef529eb7 100644
--- a/arch/s390/kernel/s390_ksyms.c
+++ b/arch/s390/kernel/s390_ksyms.c
@@ -51,4 +51,3 @@ EXPORT_SYMBOL(csum_fold);
EXPORT_SYMBOL(console_mode);
EXPORT_SYMBOL(console_devno);
EXPORT_SYMBOL(console_irq);
-EXPORT_SYMBOL(sys_wait4);
diff --git a/arch/s390/kernel/semaphore.c b/arch/s390/kernel/semaphore.c
index 8dfb690c159f..191303f6c1d8 100644
--- a/arch/s390/kernel/semaphore.c
+++ b/arch/s390/kernel/semaphore.c
@@ -26,17 +26,17 @@ static inline int __sem_update_count(struct semaphore *sem, int incr)
{
int old_val, new_val;
- __asm__ __volatile__(" l %0,0(%3)\n"
- "0: ltr %1,%0\n"
- " jhe 1f\n"
- " lhi %1,0\n"
- "1: ar %1,%4\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b\n"
- : "=&d" (old_val), "=&d" (new_val),
- "=m" (sem->count)
- : "a" (&sem->count), "d" (incr), "m" (sem->count)
- : "cc" );
+ asm volatile(
+ " l %0,0(%3)\n"
+ "0: ltr %1,%0\n"
+ " jhe 1f\n"
+ " lhi %1,0\n"
+ "1: ar %1,%4\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b\n"
+ : "=&d" (old_val), "=&d" (new_val), "=m" (sem->count)
+ : "a" (&sem->count), "d" (incr), "m" (sem->count)
+ : "cc");
return old_val;
}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index e3d9325f6022..49f2b68e32b1 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -70,7 +70,6 @@ struct {
#define CHUNK_READ_WRITE 0
#define CHUNK_READ_ONLY 1
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
-unsigned long __initdata zholes_size[MAX_NR_ZONES];
static unsigned long __initdata memory_end;
/*
@@ -101,7 +100,7 @@ void __devinit cpu_init (void)
/*
* Store processor id in lowcore (used e.g. in timer_interrupt)
*/
- asm volatile ("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
+ asm volatile("stidp %0": "=m" (S390_lowcore.cpu_data.cpu_id));
S390_lowcore.cpu_data.cpu_addr = addr;
/*
@@ -358,21 +357,6 @@ void machine_power_off(void)
*/
void (*pm_power_off)(void) = machine_power_off;
-static void __init
-add_memory_hole(unsigned long start, unsigned long end)
-{
- unsigned long dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
-
- if (end <= dma_pfn)
- zholes_size[ZONE_DMA] += end - start + 1;
- else if (start > dma_pfn)
- zholes_size[ZONE_NORMAL] += end - start + 1;
- else {
- zholes_size[ZONE_DMA] += dma_pfn - start + 1;
- zholes_size[ZONE_NORMAL] += end - dma_pfn;
- }
-}
-
static int __init early_parse_mem(char *p)
{
memory_end = memparse(p, &p);
@@ -494,7 +478,6 @@ setup_memory(void)
{
unsigned long bootmap_size;
unsigned long start_pfn, end_pfn, init_pfn;
- unsigned long last_rw_end;
int i;
/*
@@ -543,46 +526,34 @@ setup_memory(void)
#endif
/*
- * Initialize the boot-time allocator (with low memory only):
+ * Initialize the boot-time allocator
*/
bootmap_size = init_bootmem(start_pfn, end_pfn);
/*
* Register RAM areas with the bootmem allocator.
*/
- last_rw_end = start_pfn;
for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) {
- unsigned long start_chunk, end_chunk;
+ unsigned long start_chunk, end_chunk, pfn;
if (memory_chunk[i].type != CHUNK_READ_WRITE)
continue;
- start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1);
- start_chunk >>= PAGE_SHIFT;
- end_chunk = (memory_chunk[i].addr + memory_chunk[i].size);
- end_chunk >>= PAGE_SHIFT;
- if (start_chunk < start_pfn)
- start_chunk = start_pfn;
- if (end_chunk > end_pfn)
- end_chunk = end_pfn;
- if (start_chunk < end_chunk) {
- /* Initialize storage key for RAM pages */
- for (init_pfn = start_chunk ; init_pfn < end_chunk;
- init_pfn++)
- page_set_storage_key(init_pfn << PAGE_SHIFT,
- PAGE_DEFAULT_KEY);
- free_bootmem(start_chunk << PAGE_SHIFT,
- (end_chunk - start_chunk) << PAGE_SHIFT);
- if (last_rw_end < start_chunk)
- add_memory_hole(last_rw_end, start_chunk - 1);
- last_rw_end = end_chunk;
- }
+ start_chunk = PFN_DOWN(memory_chunk[i].addr);
+ end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size) - 1;
+ end_chunk = min(end_chunk, end_pfn);
+ if (start_chunk >= end_chunk)
+ continue;
+ add_active_range(0, start_chunk, end_chunk);
+ pfn = max(start_chunk, start_pfn);
+ for (; pfn <= end_chunk; pfn++)
+ page_set_storage_key(PFN_PHYS(pfn), PAGE_DEFAULT_KEY);
}
psw_set_key(PAGE_DEFAULT_KEY);
- if (last_rw_end < end_pfn - 1)
- add_memory_hole(last_rw_end, end_pfn - 1);
+ free_bootmem_with_active_regions(0, max_pfn);
+ reserve_bootmem(0, PFN_PHYS(start_pfn));
/*
* Reserve the bootmem bitmap itself as well. We do this in two
diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c
index 642095ec7c07..4392a77cbae8 100644
--- a/arch/s390/kernel/signal.c
+++ b/arch/s390/kernel/signal.c
@@ -113,17 +113,15 @@ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
/* Returns non-zero on fault. */
static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
{
- unsigned long old_mask = regs->psw.mask;
_sigregs user_sregs;
save_access_regs(current->thread.acrs);
/* Copy a 'clean' PSW mask to the user to avoid leaking
information about whether PER is currently on. */
- regs->psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
- memcpy(&user_sregs.regs.psw, &regs->psw, sizeof(sregs->regs.psw) +
- sizeof(sregs->regs.gprs));
- regs->psw.mask = old_mask;
+ user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
+ user_sregs.regs.psw.addr = regs->psw.addr;
+ memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
memcpy(&user_sregs.regs.acrs, current->thread.acrs,
sizeof(sregs->regs.acrs));
/*
@@ -139,7 +137,6 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
/* Returns positive number on error */
static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
{
- unsigned long old_mask = regs->psw.mask;
int err;
_sigregs user_sregs;
@@ -147,12 +144,12 @@ static int restore_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
current_thread_info()->restart_block.fn = do_no_restart_syscall;
err = __copy_from_user(&user_sregs, sregs, sizeof(_sigregs));
- regs->psw.mask = PSW_MASK_MERGE(old_mask, regs->psw.mask);
- regs->psw.addr |= PSW_ADDR_AMODE;
if (err)
return err;
- memcpy(&regs->psw, &user_sregs.regs.psw, sizeof(sregs->regs.psw) +
- sizeof(sregs->regs.gprs));
+ regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask,
+ user_sregs.regs.psw.mask);
+ regs->psw.addr = PSW_ADDR_AMODE | user_sregs.regs.psw.addr;
+ memcpy(&regs->gprs, &user_sregs.regs.gprs, sizeof(sregs->regs.gprs));
memcpy(&current->thread.acrs, &user_sregs.regs.acrs,
sizeof(sregs->regs.acrs));
restore_access_regs(current->thread.acrs);
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index b2e6f4c8d382..62822245f9be 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -63,7 +63,7 @@ static void smp_ext_bitcall(int, ec_bit_sig);
static void smp_ext_bitcall_others(ec_bit_sig);
/*
- * Structure and data for smp_call_function(). This is designed to minimise
+5B * Structure and data for smp_call_function(). This is designed to minimise
* static memory requirements. It also looks cleaner.
*/
static DEFINE_SPINLOCK(call_lock);
@@ -339,7 +339,7 @@ void machine_power_off_smp(void)
* cpus are handled.
*/
-void do_ext_call_interrupt(struct pt_regs *regs, __u16 code)
+void do_ext_call_interrupt(__u16 code)
{
unsigned long bits;
@@ -418,59 +418,49 @@ void smp_send_reschedule(int cpu)
/*
* parameter area for the set/clear control bit callbacks
*/
-typedef struct
-{
- __u16 start_ctl;
- __u16 end_ctl;
+struct ec_creg_mask_parms {
unsigned long orvals[16];
unsigned long andvals[16];
-} ec_creg_mask_parms;
+};
/*
* callback for setting/clearing control bits
*/
void smp_ctl_bit_callback(void *info) {
- ec_creg_mask_parms *pp;
+ struct ec_creg_mask_parms *pp = info;
unsigned long cregs[16];
int i;
- pp = (ec_creg_mask_parms *) info;
- __ctl_store(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl);
- for (i = pp->start_ctl; i <= pp->end_ctl; i++)
+ __ctl_store(cregs, 0, 15);
+ for (i = 0; i <= 15; i++)
cregs[i] = (cregs[i] & pp->andvals[i]) | pp->orvals[i];
- __ctl_load(cregs[pp->start_ctl], pp->start_ctl, pp->end_ctl);
+ __ctl_load(cregs, 0, 15);
}
/*
* Set a bit in a control register of all cpus
*/
-void smp_ctl_set_bit(int cr, int bit) {
- ec_creg_mask_parms parms;
+void smp_ctl_set_bit(int cr, int bit)
+{
+ struct ec_creg_mask_parms parms;
- parms.start_ctl = cr;
- parms.end_ctl = cr;
+ memset(&parms.orvals, 0, sizeof(parms.orvals));
+ memset(&parms.andvals, 0xff, sizeof(parms.andvals));
parms.orvals[cr] = 1 << bit;
- parms.andvals[cr] = -1L;
- preempt_disable();
- smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
- __ctl_set_bit(cr, bit);
- preempt_enable();
+ on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
}
/*
* Clear a bit in a control register of all cpus
*/
-void smp_ctl_clear_bit(int cr, int bit) {
- ec_creg_mask_parms parms;
+void smp_ctl_clear_bit(int cr, int bit)
+{
+ struct ec_creg_mask_parms parms;
- parms.start_ctl = cr;
- parms.end_ctl = cr;
- parms.orvals[cr] = 0;
+ memset(&parms.orvals, 0, sizeof(parms.orvals));
+ memset(&parms.andvals, 0xff, sizeof(parms.andvals));
parms.andvals[cr] = ~(1L << bit);
- preempt_disable();
- smp_call_function(smp_ctl_bit_callback, &parms, 0, 1);
- __ctl_clear_bit(cr, bit);
- preempt_enable();
+ on_each_cpu(smp_ctl_bit_callback, &parms, 0, 1);
}
/*
@@ -650,9 +640,9 @@ __cpu_up(unsigned int cpu)
sf->gprs[9] = (unsigned long) sf;
cpu_lowcore->save_area[15] = (unsigned long) sf;
__ctl_store(cpu_lowcore->cregs_save_area[0], 0, 15);
- __asm__ __volatile__("stam 0,15,0(%0)"
- : : "a" (&cpu_lowcore->access_regs_save_area)
- : "memory");
+ asm volatile(
+ " stam 0,15,0(%0)"
+ : : "a" (&cpu_lowcore->access_regs_save_area) : "memory");
cpu_lowcore->percpu_offset = __per_cpu_offset[cpu];
cpu_lowcore->current_task = (unsigned long) idle;
cpu_lowcore->cpu_data.cpu_nr = cpu;
@@ -708,7 +698,7 @@ int
__cpu_disable(void)
{
unsigned long flags;
- ec_creg_mask_parms cr_parms;
+ struct ec_creg_mask_parms cr_parms;
int cpu = smp_processor_id();
spin_lock_irqsave(&smp_reserve_lock, flags);
@@ -724,30 +714,21 @@ __cpu_disable(void)
pfault_fini();
#endif
- /* disable all external interrupts */
+ memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals));
+ memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals));
- cr_parms.start_ctl = 0;
- cr_parms.end_ctl = 0;
+ /* disable all external interrupts */
cr_parms.orvals[0] = 0;
cr_parms.andvals[0] = ~(1<<15 | 1<<14 | 1<<13 | 1<<12 |
1<<11 | 1<<10 | 1<< 6 | 1<< 4);
- smp_ctl_bit_callback(&cr_parms);
-
/* disable all I/O interrupts */
-
- cr_parms.start_ctl = 6;
- cr_parms.end_ctl = 6;
cr_parms.orvals[6] = 0;
cr_parms.andvals[6] = ~(1<<31 | 1<<30 | 1<<29 | 1<<28 |
1<<27 | 1<<26 | 1<<25 | 1<<24);
- smp_ctl_bit_callback(&cr_parms);
-
/* disable most machine checks */
-
- cr_parms.start_ctl = 14;
- cr_parms.end_ctl = 14;
cr_parms.orvals[14] = 0;
cr_parms.andvals[14] = ~(1<<28 | 1<<27 | 1<<26 | 1<<25 | 1<<24);
+
smp_ctl_bit_callback(&cr_parms);
spin_unlock_irqrestore(&smp_reserve_lock, flags);
diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c
index d9428a0fc8fb..0d14a4789bf2 100644
--- a/arch/s390/kernel/stacktrace.c
+++ b/arch/s390/kernel/stacktrace.c
@@ -62,27 +62,26 @@ static inline unsigned long save_context_stack(struct stack_trace *trace,
void save_stack_trace(struct stack_trace *trace, struct task_struct *task)
{
register unsigned long sp asm ("15");
- unsigned long orig_sp;
+ unsigned long orig_sp, new_sp;
- sp &= PSW_ADDR_INSN;
- orig_sp = sp;
+ orig_sp = sp & PSW_ADDR_INSN;
- sp = save_context_stack(trace, &trace->skip, sp,
+ new_sp = save_context_stack(trace, &trace->skip, orig_sp,
S390_lowcore.panic_stack - PAGE_SIZE,
S390_lowcore.panic_stack);
- if ((sp != orig_sp) && !trace->all_contexts)
+ if ((new_sp != orig_sp) && !trace->all_contexts)
return;
- sp = save_context_stack(trace, &trace->skip, sp,
+ new_sp = save_context_stack(trace, &trace->skip, new_sp,
S390_lowcore.async_stack - ASYNC_SIZE,
S390_lowcore.async_stack);
- if ((sp != orig_sp) && !trace->all_contexts)
+ if ((new_sp != orig_sp) && !trace->all_contexts)
return;
if (task)
- save_context_stack(trace, &trace->skip, sp,
+ save_context_stack(trace, &trace->skip, new_sp,
(unsigned long) task_stack_page(task),
(unsigned long) task_stack_page(task) + THREAD_SIZE);
else
- save_context_stack(trace, &trace->skip, sp,
+ save_context_stack(trace, &trace->skip, new_sp,
S390_lowcore.thread_info,
S390_lowcore.thread_info + THREAD_SIZE);
return;
diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c
index e351780bb660..584ed95f3380 100644
--- a/arch/s390/kernel/sys_s390.c
+++ b/arch/s390/kernel/sys_s390.c
@@ -27,6 +27,7 @@
#include <linux/file.h>
#include <linux/utsname.h>
#include <linux/personality.h>
+#include <linux/unistd.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
@@ -266,3 +267,22 @@ s390_fadvise64_64(struct fadvise64_64_args __user *args)
return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice);
}
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register const char *__arg1 asm("2") = filename;
+ register char *const*__arg2 asm("3") = argv;
+ register char *const*__arg3 asm("4") = envp;
+ register long __svcres asm("2");
+ asm volatile(
+ "svc %b1"
+ : "=d" (__svcres)
+ : "i" (__NR_execve),
+ "0" (__arg1),
+ "d" (__arg2),
+ "d" (__arg3) : "memory");
+ return __svcres;
+}
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 93be1d56c036..a4ceae3dbcf1 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -318,3 +318,6 @@ SYSCALL(sys_splice,sys_splice,sys_splice_wrapper)
SYSCALL(sys_sync_file_range,sys_sync_file_range,sys_sync_file_range_wrapper)
SYSCALL(sys_tee,sys_tee,sys_tee_wrapper)
SYSCALL(sys_vmsplice,sys_vmsplice,compat_sys_vmsplice_wrapper)
+NI_SYSCALL /* 310 sys_move_pages */
+SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper)
+SYSCALL(sys_epoll_pwait,sys_epoll_pwait,sys_ni_syscall)
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 74e6178fbaf2..6cceed4df73e 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -28,12 +28,14 @@
#include <linux/profile.h>
#include <linux/timex.h>
#include <linux/notifier.h>
+#include <linux/clocksource.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
#include <asm/s390_ext.h>
#include <asm/div64.h>
#include <asm/irq.h>
+#include <asm/irq_regs.h>
#include <asm/timer.h>
/* change this if you have some constant time drift */
@@ -53,8 +55,6 @@ static u64 init_timer_cc;
static u64 jiffies_timer_cc;
static u64 xtime_cc;
-extern unsigned long wall_jiffies;
-
/*
* Scheduler clock - returns current time in nanosec units.
*/
@@ -83,79 +83,10 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
xtime->tv_nsec = ((todval * 1000) >> 12);
}
-static inline unsigned long do_gettimeoffset(void)
-{
- __u64 now;
-
- now = (get_clock() - jiffies_timer_cc) >> 12;
- /* We require the offset from the latest update of xtime */
- now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
- return (unsigned long) now;
-}
-
-/*
- * This version of gettimeofday has microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
- unsigned long flags;
- unsigned long seq;
- unsigned long usec, sec;
-
- do {
- seq = read_seqbegin_irqsave(&xtime_lock, flags);
-
- sec = xtime.tv_sec;
- usec = xtime.tv_nsec / 1000 + do_gettimeoffset();
- } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
- while (usec >= 1000000) {
- usec -= 1000000;
- sec++;
- }
-
- tv->tv_sec = sec;
- tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
- time_t wtm_sec, sec = tv->tv_sec;
- long wtm_nsec, nsec = tv->tv_nsec;
-
- if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
- return -EINVAL;
-
- write_seqlock_irq(&xtime_lock);
- /* This is revolting. We need to set the xtime.tv_nsec
- * correctly. However, the value in this location is
- * is value at the last tick.
- * Discover what correction gettimeofday
- * would have done, and then undo it!
- */
- nsec -= do_gettimeoffset() * 1000;
-
- wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
- wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
- set_normalized_timespec(&xtime, sec, nsec);
- set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
- ntp_clear();
- write_sequnlock_irq(&xtime_lock);
- clock_was_set();
- return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
-
#ifdef CONFIG_PROFILING
-#define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs)
+#define s390_do_profile() profile_tick(CPU_PROFILING)
#else
-#define s390_do_profile(regs) do { ; } while(0)
+#define s390_do_profile() do { ; } while(0)
#endif /* CONFIG_PROFILING */
@@ -163,10 +94,10 @@ EXPORT_SYMBOL(do_settimeofday);
* timer_interrupt() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-void account_ticks(struct pt_regs *regs)
+void account_ticks(void)
{
__u64 tmp;
- __u32 ticks, xticks;
+ __u32 ticks;
/* Calculate how many ticks have passed. */
if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
@@ -204,6 +135,7 @@ void account_ticks(struct pt_regs *regs)
*/
write_seqlock(&xtime_lock);
if (S390_lowcore.jiffy_timer > xtime_cc) {
+ __u32 xticks;
tmp = S390_lowcore.jiffy_timer - xtime_cc;
if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
xticks = __div(tmp, CLK_TICKS_PER_JIFFY);
@@ -212,23 +144,21 @@ void account_ticks(struct pt_regs *regs)
xticks = 1;
xtime_cc += CLK_TICKS_PER_JIFFY;
}
- while (xticks--)
- do_timer(regs);
+ do_timer(xticks);
}
write_sequnlock(&xtime_lock);
#else
- for (xticks = ticks; xticks > 0; xticks--)
- do_timer(regs);
+ do_timer(ticks);
#endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
account_tick_vtime(current);
#else
while (ticks--)
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
- s390_do_profile(regs);
+ s390_do_profile();
}
#ifdef CONFIG_NO_IDLE_HZ
@@ -289,9 +219,11 @@ static inline void stop_hz_timer(void)
*/
static inline void start_hz_timer(void)
{
+ BUG_ON(!in_interrupt());
+
if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
return;
- account_ticks(task_pt_regs(current));
+ account_ticks();
cpu_clear(smp_processor_id(), nohz_cpu_mask);
}
@@ -341,6 +273,22 @@ void init_cpu_timer(void)
extern void vtime_init(void);
+static cycle_t read_tod_clock(void)
+{
+ return get_clock();
+}
+
+static struct clocksource clocksource_tod = {
+ .name = "tod",
+ .rating = 100,
+ .read = read_tod_clock,
+ .mask = -1ULL,
+ .mult = 1000,
+ .shift = 12,
+ .is_continuous = 1,
+};
+
+
/*
* Initialize the TOD clock and the CPU timer of
* the boot cpu.
@@ -351,10 +299,12 @@ void __init time_init(void)
int cc;
/* kick the TOD clock */
- asm volatile ("STCK 0(%1)\n\t"
- "IPM %0\n\t"
- "SRL %0,28" : "=r" (cc) : "a" (&init_timer_cc)
- : "memory", "cc");
+ asm volatile(
+ " stck 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (cc), "=m" (init_timer_cc)
+ : "a" (&init_timer_cc) : "cc");
switch (cc) {
case 0: /* clock in set state: all is fine */
break;
@@ -383,6 +333,9 @@ void __init time_init(void)
&ext_int_info_cc) != 0)
panic("Couldn't request external interrupt 0x1004");
+ if (clocksource_register(&clocksource_tod) != 0)
+ panic("Could not register TOD clock source");
+
init_cpu_timer();
#ifdef CONFIG_NO_IDLE_HZ
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index c4982c963424..66375a5e3d12 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -61,7 +61,7 @@ extern pgm_check_handler_t do_dat_exception;
#ifdef CONFIG_PFAULT
extern int pfault_init(void);
extern void pfault_fini(void);
-extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+extern void pfault_interrupt(__u16 error_code);
static ext_int_info_t ext_int_pfault;
#endif
extern pgm_check_handler_t do_monitor_call;
@@ -474,7 +474,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
signal = math_emu_b3(opcode, regs);
} else if (opcode[0] == 0xed) {
get_user(*((__u32 *) (opcode+2)),
- (__u32 *)(location+1));
+ (__u32 __user *)(location+1));
signal = math_emu_ed(opcode, regs);
} else if (*((__u16 *) opcode) == 0xb299) {
get_user(*((__u16 *) (opcode+2)), location+1);
@@ -499,7 +499,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
info.si_signo = signal;
info.si_errno = 0;
info.si_code = SEGV_MAPERR;
- info.si_addr = (void *) location;
+ info.si_addr = (void __user *) location;
do_trap(interruption_code, signal,
"user address fault", regs, &info);
} else
@@ -520,10 +520,10 @@ asmlinkage void
specification_exception(struct pt_regs * regs, long interruption_code)
{
__u8 opcode[6];
- __u16 *location = NULL;
+ __u16 __user *location = NULL;
int signal = 0;
- location = (__u16 *) get_check_address(regs);
+ location = (__u16 __user *) get_check_address(regs);
/*
* We got all needed information from the lowcore and can
@@ -597,8 +597,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
local_irq_enable();
if (MACHINE_HAS_IEEE)
- __asm__ volatile ("stfpc %0\n\t"
- : "=m" (current->thread.fp_regs.fpc));
+ asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
#ifdef CONFIG_MATHEMU
else if (regs->psw.mask & PSW_MASK_PSTATE) {
@@ -633,7 +632,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
break;
case 0xed:
get_user(*((__u32 *) (opcode+2)),
- (__u32 *)(location+1));
+ (__u32 __user *)(location+1));
signal = math_emu_ed(opcode, regs);
break;
case 0xb2:
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c
index 2306cd83fca1..21baaf5496d6 100644
--- a/arch/s390/kernel/vtime.c
+++ b/arch/s390/kernel/vtime.c
@@ -22,6 +22,7 @@
#include <asm/s390_ext.h>
#include <asm/timer.h>
+#include <asm/irq_regs.h>
static ext_int_info_t ext_int_info_timer;
DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
@@ -208,11 +209,11 @@ static void list_add_sorted(struct vtimer_list *timer, struct list_head *head)
* Do the callback functions of expired vtimer events.
* Called from within the interrupt handler.
*/
-static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs)
+static void do_callbacks(struct list_head *cb_list)
{
struct vtimer_queue *vt_list;
struct vtimer_list *event, *tmp;
- void (*fn)(unsigned long, struct pt_regs*);
+ void (*fn)(unsigned long);
unsigned long data;
if (list_empty(cb_list))
@@ -223,7 +224,7 @@ static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs)
list_for_each_entry_safe(event, tmp, cb_list, entry) {
fn = event->function;
data = event->data;
- fn(data, regs);
+ fn(data);
if (!event->interval)
/* delete one shot timer */
@@ -241,7 +242,7 @@ static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs)
/*
* Handler for the virtual CPU timer.
*/
-static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code)
+static void do_cpu_timer_interrupt(__u16 error_code)
{
int cpu;
__u64 next, delta;
@@ -274,7 +275,7 @@ static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code)
list_move_tail(&event->entry, &cb_list);
}
spin_unlock(&vt_list->lock);
- do_callbacks(&cb_list, regs);
+ do_callbacks(&cb_list);
/* next event is first in list */
spin_lock(&vt_list->lock);
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile
index c42ffedfdb49..b0cfa6c4883d 100644
--- a/arch/s390/lib/Makefile
+++ b/arch/s390/lib/Makefile
@@ -5,5 +5,6 @@
EXTRA_AFLAGS := -traditional
lib-y += delay.o string.o uaccess_std.o
+lib-$(CONFIG_32BIT) += div64.o
lib-$(CONFIG_64BIT) += uaccess_mvcos.o
lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 468f4ea33f99..027c4742a001 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -27,9 +27,7 @@ void __delay(unsigned long loops)
* yield the megahertz number of the cpu. The important function
* is udelay and that is done using the tod clock. -- martin.
*/
- __asm__ __volatile__(
- "0: brct %0,0b"
- : /* no outputs */ : "r" ((loops/2) + 1));
+ asm volatile("0: brct %0,0b" : : "d" ((loops/2) + 1));
}
/*
@@ -38,13 +36,12 @@ void __delay(unsigned long loops)
*/
void __udelay(unsigned long usecs)
{
- uint64_t start_cc, end_cc;
+ uint64_t start_cc;
if (usecs == 0)
return;
- asm volatile ("STCK %0" : "=m" (start_cc));
+ start_cc = get_clock();
do {
cpu_relax();
- asm volatile ("STCK %0" : "=m" (end_cc));
- } while (((end_cc - start_cc)/4096) < usecs);
+ } while (((get_clock() - start_cc)/4096) < usecs);
}
diff --git a/arch/s390/lib/div64.c b/arch/s390/lib/div64.c
new file mode 100644
index 000000000000..0481f3424a13
--- /dev/null
+++ b/arch/s390/lib/div64.c
@@ -0,0 +1,151 @@
+/*
+ * arch/s390/lib/div64.c
+ *
+ * __div64_32 implementation for 31 bit.
+ *
+ * Copyright (C) IBM Corp. 2006
+ * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+
+#ifdef CONFIG_MARCH_G5
+
+/*
+ * Function to divide an unsigned 64 bit integer by an unsigned
+ * 31 bit integer using signed 64/32 bit division.
+ */
+static uint32_t __div64_31(uint64_t *n, uint32_t base)
+{
+ register uint32_t reg2 asm("2");
+ register uint32_t reg3 asm("3");
+ uint32_t *words = (uint32_t *) n;
+ uint32_t tmp;
+
+ /* Special case base==1, remainder = 0, quotient = n */
+ if (base == 1)
+ return 0;
+ /*
+ * Special case base==0 will cause a fixed point divide exception
+ * on the dr instruction and may not happen anyway. For the
+ * following calculation we can assume base > 1. The first
+ * signed 64 / 32 bit division with an upper half of 0 will
+ * give the correct upper half of the 64 bit quotient.
+ */
+ reg2 = 0UL;
+ reg3 = words[0];
+ asm volatile(
+ " dr %0,%2\n"
+ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
+ words[0] = reg3;
+ reg3 = words[1];
+ /*
+ * To get the lower half of the 64 bit quotient and the 32 bit
+ * remainder we have to use a little trick. Since we only have
+ * a signed division the quotient can get too big. To avoid this
+ * the 64 bit dividend is halved, then the signed division will
+ * work. Afterwards the quotient and the remainder are doubled.
+ * If the last bit of the dividend has been one the remainder
+ * is increased by one then checked against the base. If the
+ * remainder has overflown subtract base and increase the
+ * quotient. Simple, no ?
+ */
+ asm volatile(
+ " nr %2,%1\n"
+ " srdl %0,1\n"
+ " dr %0,%3\n"
+ " alr %0,%0\n"
+ " alr %1,%1\n"
+ " alr %0,%2\n"
+ " clr %0,%3\n"
+ " jl 0f\n"
+ " slr %0,%3\n"
+ " alr %1,%2\n"
+ "0:\n"
+ : "+d" (reg2), "+d" (reg3), "=d" (tmp)
+ : "d" (base), "2" (1UL) : "cc" );
+ words[1] = reg3;
+ return reg2;
+}
+
+/*
+ * Function to divide an unsigned 64 bit integer by an unsigned
+ * 32 bit integer using the unsigned 64/31 bit division.
+ */
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+ uint32_t r;
+
+ /*
+ * If the most significant bit of base is set, divide n by
+ * (base/2). That allows to use 64/31 bit division and gives a
+ * good approximation of the result: n = (base/2)*q + r. The
+ * result needs to be corrected with two simple transformations.
+ * If base is already < 2^31-1 __div64_31 can be used directly.
+ */
+ r = __div64_31(n, ((signed) base < 0) ? (base/2) : base);
+ if ((signed) base < 0) {
+ uint64_t q = *n;
+ /*
+ * First transformation:
+ * n = (base/2)*q + r
+ * = ((base/2)*2)*(q/2) + ((q&1) ? (base/2) : 0) + r
+ * Since r < (base/2), r + (base/2) < base.
+ * With q1 = (q/2) and r1 = r + ((q&1) ? (base/2) : 0)
+ * n = ((base/2)*2)*q1 + r1 with r1 < base.
+ */
+ if (q & 1)
+ r += base/2;
+ q >>= 1;
+ /*
+ * Second transformation. ((base/2)*2) could have lost the
+ * last bit.
+ * n = ((base/2)*2)*q1 + r1
+ * = base*q1 - ((base&1) ? q1 : 0) + r1
+ */
+ if (base & 1) {
+ int64_t rx = r - q;
+ /*
+ * base is >= 2^31. The worst case for the while
+ * loop is n=2^64-1 base=2^31+1. That gives a
+ * maximum for q=(2^64-1)/2^31 = 0x1ffffffff. Since
+ * base >= 2^31 the loop is finished after a maximum
+ * of three iterations.
+ */
+ while (rx < 0) {
+ rx += base;
+ q--;
+ }
+ r = rx;
+ }
+ *n = q;
+ }
+ return r;
+}
+
+#else /* MARCH_G5 */
+
+uint32_t __div64_32(uint64_t *n, uint32_t base)
+{
+ register uint32_t reg2 asm("2");
+ register uint32_t reg3 asm("3");
+ uint32_t *words = (uint32_t *) n;
+
+ reg2 = 0UL;
+ reg3 = words[0];
+ asm volatile(
+ " dlr %0,%2\n"
+ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
+ words[0] = reg3;
+ reg3 = words[1];
+ asm volatile(
+ " dlr %0,%2\n"
+ : "+d" (reg2), "+d" (reg3) : "d" (base) : "cc" );
+ words[1] = reg3;
+ return reg2;
+}
+
+#endif /* MARCH_G5 */
+
+EXPORT_SYMBOL(__div64_32);
diff --git a/arch/s390/lib/spinlock.c b/arch/s390/lib/spinlock.c
index b9b7958a226a..8d76403fcf89 100644
--- a/arch/s390/lib/spinlock.c
+++ b/arch/s390/lib/spinlock.c
@@ -24,57 +24,76 @@ static int __init spin_retry_setup(char *str)
}
__setup("spin_retry=", spin_retry_setup);
-static inline void
-_diag44(void)
+static inline void _raw_yield(void)
{
-#ifdef CONFIG_64BIT
if (MACHINE_HAS_DIAG44)
-#endif
asm volatile("diag 0,0,0x44");
}
-void
-_raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
+static inline void _raw_yield_cpu(int cpu)
+{
+ if (MACHINE_HAS_DIAG9C)
+ asm volatile("diag %0,0,0x9c"
+ : : "d" (__cpu_logical_map[cpu]));
+ else
+ _raw_yield();
+}
+
+void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc)
{
int count = spin_retry;
+ unsigned int cpu = ~smp_processor_id();
while (1) {
if (count-- <= 0) {
- _diag44();
+ unsigned int owner = lp->owner_cpu;
+ if (owner != 0)
+ _raw_yield_cpu(~owner);
count = spin_retry;
}
if (__raw_spin_is_locked(lp))
continue;
- if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
+ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
+ lp->owner_pc = pc;
return;
+ }
}
}
EXPORT_SYMBOL(_raw_spin_lock_wait);
-int
-_raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
+int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc)
{
- int count = spin_retry;
+ unsigned int cpu = ~smp_processor_id();
+ int count;
- while (count-- > 0) {
+ for (count = spin_retry; count > 0; count--) {
if (__raw_spin_is_locked(lp))
continue;
- if (_raw_compare_and_swap(&lp->lock, 0, pc) == 0)
+ if (_raw_compare_and_swap(&lp->owner_cpu, 0, cpu) == 0) {
+ lp->owner_pc = pc;
return 1;
+ }
}
return 0;
}
EXPORT_SYMBOL(_raw_spin_trylock_retry);
-void
-_raw_read_lock_wait(raw_rwlock_t *rw)
+void _raw_spin_relax(raw_spinlock_t *lock)
+{
+ unsigned int cpu = lock->owner_cpu;
+ if (cpu != 0)
+ _raw_yield_cpu(~cpu);
+}
+EXPORT_SYMBOL(_raw_spin_relax);
+
+void _raw_read_lock_wait(raw_rwlock_t *rw)
{
unsigned int old;
int count = spin_retry;
while (1) {
if (count-- <= 0) {
- _diag44();
+ _raw_yield();
count = spin_retry;
}
if (!__raw_read_can_lock(rw))
@@ -86,8 +105,7 @@ _raw_read_lock_wait(raw_rwlock_t *rw)
}
EXPORT_SYMBOL(_raw_read_lock_wait);
-int
-_raw_read_trylock_retry(raw_rwlock_t *rw)
+int _raw_read_trylock_retry(raw_rwlock_t *rw)
{
unsigned int old;
int count = spin_retry;
@@ -103,14 +121,13 @@ _raw_read_trylock_retry(raw_rwlock_t *rw)
}
EXPORT_SYMBOL(_raw_read_trylock_retry);
-void
-_raw_write_lock_wait(raw_rwlock_t *rw)
+void _raw_write_lock_wait(raw_rwlock_t *rw)
{
int count = spin_retry;
while (1) {
if (count-- <= 0) {
- _diag44();
+ _raw_yield();
count = spin_retry;
}
if (!__raw_write_can_lock(rw))
@@ -121,8 +138,7 @@ _raw_write_lock_wait(raw_rwlock_t *rw)
}
EXPORT_SYMBOL(_raw_write_lock_wait);
-int
-_raw_write_trylock_retry(raw_rwlock_t *rw)
+int _raw_write_trylock_retry(raw_rwlock_t *rw)
{
int count = spin_retry;
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
index 86c96d6c191a..121b2935a422 100644
--- a/arch/s390/lib/uaccess_mvcos.c
+++ b/arch/s390/lib/uaccess_mvcos.c
@@ -35,7 +35,7 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
tmp1 = -4096UL;
asm volatile(
"0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
- " jz 4f\n"
+ " jz 7f\n"
"1:"ALR" %0,%3\n"
" "SLR" %1,%3\n"
" "SLR" %2,%3\n"
@@ -44,13 +44,23 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
" nr %4,%3\n" /* %4 = (ptr + 4095) & -4096 */
" "SLR" %4,%1\n"
" "CLR" %0,%4\n" /* copy crosses next page boundary? */
- " jnh 5f\n"
+ " jnh 4f\n"
"3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
" "SLR" %0,%4\n"
- " j 5f\n"
- "4:"SLR" %0,%0\n"
- "5: \n"
- EX_TABLE(0b,2b) EX_TABLE(3b,5b)
+ " "ALR" %2,%4\n"
+ "4:"LHI" %4,-1\n"
+ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
+ " bras %3,6f\n" /* memset loop */
+ " xc 0(1,%2),0(%2)\n"
+ "5: xc 0(256,%2),0(%2)\n"
+ " la %2,256(%2)\n"
+ "6:"AHI" %4,-256\n"
+ " jnm 5b\n"
+ " ex %4,0(%3)\n"
+ " j 8f\n"
+ "7:"SLR" %0,%0\n"
+ "8: \n"
+ EX_TABLE(0b,2b) EX_TABLE(3b,4b)
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
: "d" (reg0) : "cc", "memory");
return size;
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c
index 9a4d4a29ea79..f44f0078b354 100644
--- a/arch/s390/lib/uaccess_std.c
+++ b/arch/s390/lib/uaccess_std.c
@@ -35,25 +35,35 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
tmp1 = -256UL;
asm volatile(
"0: mvcp 0(%0,%2),0(%1),%3\n"
- " jz 5f\n"
+ " jz 8f\n"
"1:"ALR" %0,%3\n"
" la %1,256(%1)\n"
" la %2,256(%2)\n"
"2: mvcp 0(%0,%2),0(%1),%3\n"
" jnz 1b\n"
- " j 5f\n"
+ " j 8f\n"
"3: la %4,255(%1)\n" /* %4 = ptr + 255 */
" "LHI" %3,-4096\n"
" nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
" "SLR" %4,%1\n"
" "CLR" %0,%4\n" /* copy crosses next page boundary? */
- " jnh 6f\n"
+ " jnh 5f\n"
"4: mvcp 0(%4,%2),0(%1),%3\n"
" "SLR" %0,%4\n"
- " j 6f\n"
- "5:"SLR" %0,%0\n"
- "6: \n"
- EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
+ " "ALR" %2,%4\n"
+ "5:"LHI" %4,-1\n"
+ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
+ " bras %3,7f\n" /* memset loop */
+ " xc 0(1,%2),0(%2)\n"
+ "6: xc 0(256,%2),0(%2)\n"
+ " la %2,256(%2)\n"
+ "7:"AHI" %4,-256\n"
+ " jnm 6b\n"
+ " ex %4,0(%3)\n"
+ " j 9f\n"
+ "8:"SLR" %0,%0\n"
+ "9: \n"
+ EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,5b)
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
: : "cc", "memory");
return size;
@@ -67,16 +77,22 @@ size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x)
asm volatile(
"0: mvcp 0(%0,%2),0(%1),%3\n"
" "SLR" %0,%0\n"
- " j 3f\n"
+ " j 5f\n"
"1: la %4,255(%1)\n" /* %4 = ptr + 255 */
" "LHI" %3,-4096\n"
" nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */
" "SLR" %4,%1\n"
" "CLR" %0,%4\n" /* copy crosses next page boundary? */
- " jnh 3f\n"
+ " jnh 5f\n"
"2: mvcp 0(%4,%2),0(%1),%3\n"
" "SLR" %0,%4\n"
- "3:\n"
+ " "ALR" %2,%4\n"
+ "3:"LHI" %4,-1\n"
+ " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */
+ " bras %3,4f\n"
+ " xc 0(1,%2),0(%2)\n"
+ "4: ex %4,0(%3)\n"
+ "5:\n"
EX_TABLE(0b,1b) EX_TABLE(2b,3b)
: "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
: : "cc", "memory");
diff --git a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
index b4957c84e4d6..6b9aec5a2c18 100644
--- a/arch/s390/math-emu/math.c
+++ b/arch/s390/math-emu/math.c
@@ -1564,52 +1564,52 @@ static int emu_tceb (struct pt_regs *regs, int rx, long val) {
}
static inline void emu_load_regd(int reg) {
- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
return;
- asm volatile ( /* load reg from fp_regs.fprs[reg] */
- " bras 1,0f\n"
- " ld 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" (reg<<4),"a" (&current->thread.fp_regs.fprs[reg].d)
- : "1" );
+ asm volatile( /* load reg from fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " ld 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4),"a" (&current->thread.fp_regs.fprs[reg].d)
+ : "1");
}
static inline void emu_load_rege(int reg) {
- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
return;
- asm volatile ( /* load reg from fp_regs.fprs[reg] */
- " bras 1,0f\n"
- " le 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
- : "1" );
+ asm volatile( /* load reg from fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " le 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+ : "1");
}
static inline void emu_store_regd(int reg) {
- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
return;
- asm volatile ( /* store reg to fp_regs.fprs[reg] */
- " bras 1,0f\n"
- " std 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
- : "1" );
+ asm volatile( /* store reg to fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " std 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
+ : "1");
}
static inline void emu_store_rege(int reg) {
- if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
+ if ((reg&9) != 0) /* test if reg in {0,2,4,6} */
return;
- asm volatile ( /* store reg to fp_regs.fprs[reg] */
- " bras 1,0f\n"
- " ste 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
- : "1" );
+ asm volatile( /* store reg to fp_regs.fprs[reg] */
+ " bras 1,0f\n"
+ " ste 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
+ : "1");
}
int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
@@ -2089,23 +2089,22 @@ int math_emu_ldr(__u8 *opcode) {
if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
/* we got an exception therfore ry can't be in {0,2,4,6} */
- __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
- " bras 1,0f\n"
- " ld 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" (opc & 0xf0),
- "a" (&fp_regs->fprs[opc & 0xf].d)
- : "1" );
+ asm volatile( /* load rx from fp_regs.fprs[ry] */
+ " bras 1,0f\n"
+ " ld 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].d)
+ : "1");
} else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
- __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
- " bras 1,0f\n"
- " std 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" ((opc & 0xf) << 4),
- "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
- : "1" );
+ asm volatile ( /* store ry to fp_regs.fprs[rx] */
+ " bras 1,0f\n"
+ " std 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" ((opc & 0xf) << 4),
+ "a" (&fp_regs->fprs[(opc & 0xf0)>>4].d)
+ : "1");
} else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
return 0;
@@ -2120,23 +2119,22 @@ int math_emu_ler(__u8 *opcode) {
if ((opc & 0x90) == 0) { /* test if rx in {0,2,4,6} */
/* we got an exception therfore ry can't be in {0,2,4,6} */
- __asm__ __volatile ( /* load rx from fp_regs.fprs[ry] */
- " bras 1,0f\n"
- " le 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" (opc & 0xf0),
- "a" (&fp_regs->fprs[opc & 0xf].f)
- : "1" );
+ asm volatile( /* load rx from fp_regs.fprs[ry] */
+ " bras 1,0f\n"
+ " le 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" (opc & 0xf0), "a" (&fp_regs->fprs[opc & 0xf].f)
+ : "1");
} else if ((opc & 0x9) == 0) { /* test if ry in {0,2,4,6} */
- __asm__ __volatile ( /* store ry to fp_regs.fprs[rx] */
- " bras 1,0f\n"
- " ste 0,0(%1)\n"
- "0: ex %0,0(1)"
- : /* no output */
- : "a" ((opc & 0xf) << 4),
- "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
- : "1" );
+ asm volatile( /* store ry to fp_regs.fprs[rx] */
+ " bras 1,0f\n"
+ " ste 0,0(%1)\n"
+ "0: ex %0,0(1)"
+ : /* no output */
+ : "a" ((opc & 0xf) << 4),
+ "a" (&fp_regs->fprs[(opc & 0xf0) >> 4].f)
+ : "1");
} else /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
fp_regs->fprs[(opc & 0xf0) >> 4] = fp_regs->fprs[opc & 0xf];
return 0;
diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h
index ab556b600f73..5b6ca4570ea4 100644
--- a/arch/s390/math-emu/sfp-util.h
+++ b/arch/s390/math-emu/sfp-util.h
@@ -4,48 +4,51 @@
#include <asm/byteorder.h>
#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({ \
- unsigned int __sh = (ah); \
- unsigned int __sl = (al); \
- __asm__ (" alr %1,%3\n" \
- " brc 12,0f\n" \
- " ahi %0,1\n" \
- "0: alr %0,%2" \
- : "+&d" (__sh), "+d" (__sl) \
- : "d" (bh), "d" (bl) : "cc" ); \
- (sh) = __sh; \
- (sl) = __sl; \
+ unsigned int __sh = (ah); \
+ unsigned int __sl = (al); \
+ asm volatile( \
+ " alr %1,%3\n" \
+ " brc 12,0f\n" \
+ " ahi %0,1\n" \
+ "0: alr %0,%2" \
+ : "+&d" (__sh), "+d" (__sl) \
+ : "d" (bh), "d" (bl) : "cc"); \
+ (sh) = __sh; \
+ (sl) = __sl; \
})
#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({ \
- unsigned int __sh = (ah); \
- unsigned int __sl = (al); \
- __asm__ (" slr %1,%3\n" \
- " brc 3,0f\n" \
- " ahi %0,-1\n" \
- "0: slr %0,%2" \
- : "+&d" (__sh), "+d" (__sl) \
- : "d" (bh), "d" (bl) : "cc" ); \
- (sh) = __sh; \
- (sl) = __sl; \
+ unsigned int __sh = (ah); \
+ unsigned int __sl = (al); \
+ asm volatile( \
+ " slr %1,%3\n" \
+ " brc 3,0f\n" \
+ " ahi %0,-1\n" \
+ "0: slr %0,%2" \
+ : "+&d" (__sh), "+d" (__sl) \
+ : "d" (bh), "d" (bl) : "cc"); \
+ (sh) = __sh; \
+ (sl) = __sl; \
})
/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
#define umul_ppmm(wh, wl, u, v) ({ \
- unsigned int __wh = u; \
- unsigned int __wl = v; \
- __asm__ (" ltr 1,%0\n" \
- " mr 0,%1\n" \
- " jnm 0f\n" \
- " alr 0,%1\n" \
- "0: ltr %1,%1\n" \
- " jnm 1f\n" \
- " alr 0,%0\n" \
- "1: lr %0,0\n" \
- " lr %1,1\n" \
- : "+d" (__wh), "+d" (__wl) \
- : : "0", "1", "cc" ); \
- wh = __wh; \
- wl = __wl; \
+ unsigned int __wh = u; \
+ unsigned int __wl = v; \
+ asm volatile( \
+ " ltr 1,%0\n" \
+ " mr 0,%1\n" \
+ " jnm 0f\n" \
+ " alr 0,%1\n" \
+ "0: ltr %1,%1\n" \
+ " jnm 1f\n" \
+ " alr 0,%0\n" \
+ "1: lr %0,0\n" \
+ " lr %1,1\n" \
+ : "+d" (__wh), "+d" (__wl) \
+ : : "0", "1", "cc"); \
+ wh = __wh; \
+ wl = __wl; \
})
#define udiv_qrnnd(q, r, n1, n0, d) \
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 9b11e3e20903..226275d5c4f6 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -142,17 +142,17 @@ dcss_diag (__u8 func, void *parameter,
rx = (unsigned long) parameter;
ry = (unsigned long) func;
- __asm__ __volatile__(
+ asm volatile(
#ifdef CONFIG_64BIT
- " sam31\n" // switch to 31 bit
- " diag %0,%1,0x64\n"
- " sam64\n" // switch back to 64 bit
+ " sam31\n"
+ " diag %0,%1,0x64\n"
+ " sam64\n"
#else
- " diag %0,%1,0x64\n"
+ " diag %0,%1,0x64\n"
#endif
- " ipm %2\n"
- " srl %2,28\n"
- : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc" );
+ " ipm %2\n"
+ " srl %2,28\n"
+ : "+d" (rx), "+d" (ry), "=d" (rc) : : "cc");
*ret1 = rx;
*ret2 = ry;
return rc;
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 44f0cda7e72e..1c323bbfda91 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -353,8 +353,9 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (tsk->pid == 1) {
+ if (is_init(tsk)) {
yield();
+ down_read(&mm->mmap_sem);
goto survive;
}
printk("VM: killing process %s\n", tsk->comm);
@@ -423,20 +424,13 @@ int pfault_init(void)
if (pfault_disable)
return -1;
- __asm__ __volatile__(
- " diag %1,%0,0x258\n"
- "0: j 2f\n"
- "1: la %0,8\n"
+ asm volatile(
+ " diag %1,%0,0x258\n"
+ "0: j 2f\n"
+ "1: la %0,8\n"
"2:\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
-#ifndef CONFIG_64BIT
- " .long 0b,1b\n"
-#else /* CONFIG_64BIT */
- " .quad 0b,1b\n"
-#endif /* CONFIG_64BIT */
- ".previous"
- : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc" );
+ EX_TABLE(0b,1b)
+ : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc");
__ctl_set_bit(0, 9);
return rc;
}
@@ -449,22 +443,15 @@ void pfault_fini(void)
if (pfault_disable)
return;
__ctl_clear_bit(0,9);
- __asm__ __volatile__(
- " diag %0,0,0x258\n"
+ asm volatile(
+ " diag %0,0,0x258\n"
"0:\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
-#ifndef CONFIG_64BIT
- " .long 0b,0b\n"
-#else /* CONFIG_64BIT */
- " .quad 0b,0b\n"
-#endif /* CONFIG_64BIT */
- ".previous"
- : : "a" (&refbk), "m" (refbk) : "cc" );
+ EX_TABLE(0b,0b)
+ : : "a" (&refbk), "m" (refbk) : "cc");
}
asmlinkage void
-pfault_interrupt(struct pt_regs *regs, __u16 error_code)
+pfault_interrupt(__u16 error_code)
{
struct task_struct *tsk;
__u16 subcode;
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index cfd9b8f7a523..d99891718709 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -45,45 +45,38 @@ void diag10(unsigned long addr)
{
if (addr >= 0x7ff00000)
return;
+ asm volatile(
#ifdef CONFIG_64BIT
- asm volatile (
- " sam31\n"
- " diag %0,%0,0x10\n"
- "0: sam64\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b, 0b\n"
- ".previous\n"
- : : "a" (addr));
+ " sam31\n"
+ " diag %0,%0,0x10\n"
+ "0: sam64\n"
#else
- asm volatile (
- " diag %0,%0,0x10\n"
+ " diag %0,%0,0x10\n"
"0:\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b, 0b\n"
- ".previous\n"
- : : "a" (addr));
#endif
+ EX_TABLE(0b,0b)
+ : : "a" (addr));
}
void show_mem(void)
{
int i, total = 0, reserved = 0;
int shared = 0, cached = 0;
+ struct page *page;
printk("Mem-info:\n");
show_free_areas();
printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
i = max_mapnr;
while (i-- > 0) {
+ page = pfn_to_page(i);
total++;
- if (PageReserved(mem_map+i))
+ if (PageReserved(page))
reserved++;
- else if (PageSwapCache(mem_map+i))
+ else if (PageSwapCache(page))
cached++;
- else if (page_count(mem_map+i))
- shared += page_count(mem_map+i) - 1;
+ else if (page_count(page))
+ shared += page_count(page) - 1;
}
printk("%d pages of RAM\n",total);
printk("%d reserved pages\n",reserved);
@@ -91,7 +84,6 @@ void show_mem(void)
printk("%d pages swap cached\n",cached);
}
-extern unsigned long __initdata zholes_size[];
/*
* paging_init() sets up the page tables
*/
@@ -108,16 +100,15 @@ void __init paging_init(void)
unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
static const int ssm_mask = 0x04000000L;
unsigned long ro_start_pfn, ro_end_pfn;
- unsigned long zones_size[MAX_NR_ZONES];
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata);
ro_end_pfn = PFN_UP((unsigned long)&__end_rodata);
- memset(zones_size, 0, sizeof(zones_size));
- zones_size[ZONE_DMA] = max_low_pfn;
- free_area_init_node(0, &contig_page_data, zones_size,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT,
- zholes_size);
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = max_low_pfn;
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ free_area_init_nodes(max_zone_pfns);
/* unmap whole virtual address space */
@@ -156,14 +147,12 @@ void __init paging_init(void)
S390_lowcore.kernel_asce = pgdir_k;
/* enable virtual mapping in kernel mode */
- __asm__ __volatile__(" LCTL 1,1,%0\n"
- " LCTL 7,7,%0\n"
- " LCTL 13,13,%0\n"
- " SSM %1"
- : : "m" (pgdir_k), "m" (ssm_mask));
+ __ctl_load(pgdir_k, 1, 1);
+ __ctl_load(pgdir_k, 7, 7);
+ __ctl_load(pgdir_k, 13, 13);
+ __raw_local_irq_ssm(ssm_mask);
local_flush_tlb();
- return;
}
#else /* CONFIG_64BIT */
@@ -179,26 +168,16 @@ void __init paging_init(void)
unsigned long pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) |
_KERN_REGION_TABLE;
static const int ssm_mask = 0x04000000L;
- unsigned long zones_size[MAX_NR_ZONES];
- unsigned long dma_pfn, high_pfn;
unsigned long ro_start_pfn, ro_end_pfn;
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
- memset(zones_size, 0, sizeof(zones_size));
- dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT;
- high_pfn = max_low_pfn;
ro_start_pfn = PFN_DOWN((unsigned long)&__start_rodata);
ro_end_pfn = PFN_UP((unsigned long)&__end_rodata);
- if (dma_pfn > high_pfn)
- zones_size[ZONE_DMA] = high_pfn;
- else {
- zones_size[ZONE_DMA] = dma_pfn;
- zones_size[ZONE_NORMAL] = high_pfn - dma_pfn;
- }
-
- /* Initialize mem_map[]. */
- free_area_init_node(0, &contig_page_data, zones_size,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size);
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = PFN_DOWN(MAX_DMA_ADDRESS);
+ max_zone_pfns[ZONE_NORMAL] = max_low_pfn;
+ free_area_init_nodes(max_zone_pfns);
/*
* map whole physical memory to virtual memory (identity mapping)
@@ -241,15 +220,12 @@ void __init paging_init(void)
S390_lowcore.kernel_asce = pgdir_k;
/* enable virtual mapping in kernel mode */
- __asm__ __volatile__("lctlg 1,1,%0\n\t"
- "lctlg 7,7,%0\n\t"
- "lctlg 13,13,%0\n\t"
- "ssm %1"
- : :"m" (pgdir_k), "m" (ssm_mask));
+ __ctl_load(pgdir_k, 1, 1);
+ __ctl_load(pgdir_k, 7, 7);
+ __ctl_load(pgdir_k, 13, 13);
+ __raw_local_irq_ssm(ssm_mask);
local_flush_tlb();
-
- return;
}
#endif /* CONFIG_64BIT */
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 1a0db1d4c952..6a461d4caeff 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -8,6 +8,7 @@ mainmenu "Linux/SuperH Kernel Configuration"
config SUPERH
bool
default y
+ select EMBEDDED
help
The SuperH is a RISC processor targeted for use in embedded systems
and consumer electronics; it was also used in the Sega Dreamcast
@@ -44,6 +45,9 @@ config GENERIC_CALIBRATE_DELAY
config GENERIC_IOMAP
bool
+config GENERIC_TIME
+ def_bool n
+
config ARCH_MAY_HAVE_PC_FDC
bool
@@ -51,18 +55,23 @@ source "init/Kconfig"
menu "System type"
+config SOLUTION_ENGINE
+ bool
+
choice
prompt "SuperH system type"
default SH_UNKNOWN
config SH_SOLUTION_ENGINE
bool "SolutionEngine"
+ select SOLUTION_ENGINE
help
Select SolutionEngine if configuring for a Hitachi SH7709
or SH7750 evaluation board.
config SH_7751_SOLUTION_ENGINE
bool "SolutionEngine7751"
+ select SOLUTION_ENGINE
select CPU_SUBTYPE_SH7751
help
Select 7751 SolutionEngine if configuring for a Hitachi SH7751
@@ -70,17 +79,27 @@ config SH_7751_SOLUTION_ENGINE
config SH_7300_SOLUTION_ENGINE
bool "SolutionEngine7300"
+ select SOLUTION_ENGINE
select CPU_SUBTYPE_SH7300
help
- Select 7300 SolutionEngine if configuring for a Hitachi SH7300(SH-Mobile V)
- evaluation board.
+ Select 7300 SolutionEngine if configuring for a Hitachi
+ SH7300(SH-Mobile V) evaluation board.
+
+config SH_7343_SOLUTION_ENGINE
+ bool "SolutionEngine7343"
+ select SOLUTION_ENGINE
+ select CPU_SUBTYPE_SH7343
+ help
+ Select 7343 SolutionEngine if configuring for a Hitachi
+ SH7343 (SH-Mobile 3AS) evaluation board.
config SH_73180_SOLUTION_ENGINE
bool "SolutionEngine73180"
- select CPU_SUBTYPE_SH73180
- help
- Select 73180 SolutionEngine if configuring for a Hitachi SH73180(SH-Mobile 3)
- evaluation board.
+ select SOLUTION_ENGINE
+ select CPU_SUBTYPE_SH73180
+ help
+ Select 73180 SolutionEngine if configuring for a Hitachi
+ SH73180(SH-Mobile 3) evaluation board.
config SH_7751_SYSTEMH
bool "SystemH7751R"
@@ -89,12 +108,6 @@ config SH_7751_SYSTEMH
Select SystemH if you are configuring for a Renesas SystemH
7751R evaluation board.
-config SH_STB1_HARP
- bool "STB1_Harp"
-
-config SH_STB1_OVERDRIVE
- bool "STB1_Overdrive"
-
config SH_HP6XX
bool "HP6XX"
help
@@ -102,19 +115,6 @@ config SH_HP6XX
More information (hardware only) at
<http://www.hp.com/jornada/>.
-config SH_CQREEK
- bool "CqREEK"
- help
- Select CqREEK if configuring for a CqREEK SH7708 or SH7750.
- More information at
- <http://sources.redhat.com/ecos/hardware.html#SuperH>.
-
-config SH_DMIDA
- bool "DMIDA"
- help
- Select DMIDA if configuring for a DataMyte 4000 Industrial
- Digital Assistant. More information at <http://www.dmida.com/>.
-
config SH_EC3104
bool "EC3104"
help
@@ -136,25 +136,9 @@ config SH_DREAMCAST
<http://www.m17n.org/linux-sh/dreamcast/>. There is a
Dreamcast project is at <http://linuxdc.sourceforge.net/>.
-config SH_CAT68701
- bool "CAT68701"
-
config SH_BIGSUR
bool "BigSur"
-config SH_SH2000
- bool "SH2000"
- select CPU_SUBTYPE_SH7709
- help
- SH-2000 is a single-board computer based around SH7709A chip
- intended for embedded applications.
- It has an Ethernet interface (CS8900A), direct connected
- Compact Flash socket, three serial ports and PC-104 bus.
- More information at <http://sh2000.sh-linux.org>.
-
-config SH_ADX
- bool "ADX"
-
config SH_MPC1211
bool "Interface MPC1211"
help
@@ -184,6 +168,13 @@ config SH_HS7751RVOIP
Select HS7751RVOIP if configuring for a Renesas Technology
Sales VoIP board.
+config SH_7710VOIPGW
+ bool "SH7710-VOIP-GW"
+ select CPU_SUBTYPE_SH7710
+ help
+ Select this option to build a kernel for the SH7710 based
+ VOIP GW.
+
config SH_RTS7751R2D
bool "RTS7751R2D"
select CPU_SUBTYPE_SH7751R
@@ -222,6 +213,12 @@ config SH_TITAN
Select Titan if you are configuring for a Nimble Microsystems
NetEngine NP51R.
+config SH_SHMIN
+ bool "SHMIN"
+ select CPU_SUBTYPE_SH7706
+ help
+ Select SHMIN if configureing for the SHMIN board
+
config SH_UNKNOWN
bool "BareCPU"
help
@@ -238,35 +235,9 @@ endchoice
source "arch/sh/mm/Kconfig"
-config MEMORY_START
- hex "Physical memory start address"
- default "0x08000000"
- ---help---
- Computers built with Hitachi SuperH processors always
- map the ROM starting at address zero. But the processor
- does not specify the range that RAM takes.
-
- The physical memory (RAM) start address will be automatically
- set to 08000000. Other platforms, such as the Solution Engine
- boards typically map RAM at 0C000000.
-
- Tweak this only when porting to a new machine which does not
- already have a defconfig. Changing it from the known correct
- value on any of the known systems will only lead to disaster.
-
-config MEMORY_SIZE
- hex "Physical memory size"
- default "0x00400000"
- help
- This sets the default memory size assumed by your SH kernel. It can
- be overridden as normal by the 'mem=' argument on the kernel command
- line. If unsure, consult your board specifications or just leave it
- as 0x00400000 which was the default value before this became
- configurable.
-
config CF_ENABLER
bool "Compact Flash Enabler support"
- depends on SH_ADX || SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_CAT68701 || SH_SH03
+ depends on SH_SOLUTION_ENGINE || SH_UNKNOWN || SH_SH03
---help---
Compact Flash is a small, removable mass storage device introduced
in 1994 originally as a PCMCIA device. If you say `Y' here, you
@@ -294,7 +265,7 @@ config CF_AREA5
- "Area5" if CompactFlash is connected to Area 5 (0x14000000)
- "Area6" if it is connected to Area 6 (0x18000000)
- "Area6" will work for most boards. For ADX, select "Area5".
+ "Area6" will work for most boards.
config CF_AREA6
bool "Area6"
@@ -316,19 +287,6 @@ config CPU_LITTLE_ENDIAN
endian byte order. These modes require different kernels. Say Y if
your machine is little endian, N if it's a big endian machine.
-# The SH7750 RTC module is disabled in the Dreamcast
-config SH_RTC
- bool
- depends on !SH_DREAMCAST && !SH_SATURN && !SH_7300_SOLUTION_ENGINE && \
- !SH_73180_SOLUTION_ENGINE && !SH_LANDISK && \
- !SH_R7780RP
- default y
- help
- Selecting this option will allow the Linux kernel to emulate
- PC's RTC.
-
- If unsure, say N.
-
config SH_FPU
bool "FPU support"
depends on !CPU_SH3
@@ -339,14 +297,22 @@ config SH_FPU
This option must be set in order to enable the FPU.
+config SH_FPU_EMU
+ bool "FPU emulation support"
+ depends on !SH_FPU && EXPERIMENTAL
+ default n
+ help
+ Selecting this option will enable support for software FPU emulation.
+ Most SH-3 users will want to say Y here, whereas most SH-4 users will
+ want to say N.
+
config SH_DSP
bool "DSP support"
- depends on !CPU_SH4
- default y
+ default y if SH4AL_DSP || !CPU_SH4
+ default n
help
Selecting this option will enable support for SH processors that
- have DSP units (ie, SH2-DSP and SH3-DSP). It is safe to say Y here
- by default, as the existance of the DSP will be probed at runtime.
+ have DSP units (ie, SH2-DSP, SH3-DSP, and SH4AL-DSP).
This option must be set in order to enable the DSP.
@@ -373,6 +339,9 @@ config CPU_HAS_INTEVT
config CPU_HAS_PINT_IRQ
bool
+config CPU_HAS_MASKREG_IRQ
+ bool
+
config CPU_HAS_INTC2_IRQ
bool
@@ -391,6 +360,7 @@ config CPU_HAS_SR_RB
endmenu
menu "Timer support"
+depends on !GENERIC_TIME
config SH_TMU
bool "TMU timer support"
@@ -400,16 +370,19 @@ config SH_TMU
endmenu
-#source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
+source "arch/sh/boards/renesas/hs7751rvoip/Kconfig"
-#source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
+source "arch/sh/boards/renesas/rts7751r2d/Kconfig"
+
+source "arch/sh/boards/renesas/r7780rp/Kconfig"
config SH_PCLK_FREQ
int "Peripheral clock frequency (in Hz)"
default "50000000" if CPU_SUBTYPE_SH7750 || CPU_SUBTYPE_SH7780
default "60000000" if CPU_SUBTYPE_SH7751
- default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || CPU_SUBTYPE_SH7760
- default "27000000" if CPU_SUBTYPE_SH73180
+ default "33333333" if CPU_SUBTYPE_SH7300 || CPU_SUBTYPE_SH7770 || \
+ CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7705
+ default "27000000" if CPU_SUBTYPE_SH73180 || CPU_SUBTYPE_SH7343
default "66000000" if CPU_SUBTYPE_SH4_202
help
This option is used to specify the peripheral clock frequency.
@@ -440,10 +413,8 @@ source "arch/sh/cchips/Kconfig"
config HEARTBEAT
bool "Heartbeat LED"
- depends on SH_MPC1211 || SH_SH03 || SH_CAT68701 || \
- SH_STB1_HARP || SH_STB1_OVERDRIVE || SH_BIGSUR || \
- SH_7751_SOLUTION_ENGINE || SH_7300_SOLUTION_ENGINE || \
- SH_73180_SOLUTION_ENGINE || SH_SOLUTION_ENGINE || \
+ depends on SH_MPC1211 || SH_SH03 || \
+ SH_BIGSUR || SOLUTION_ENGINE || \
SH_RTS7751R2D || SH_SH4202_MICRODEV || SH_LANDISK
help
Use the power-on LED on your machine as a load meter. The exact
@@ -459,6 +430,8 @@ config ISA_DMA_API
menu "Kernel features"
+source kernel/Kconfig.hz
+
config KEXEC
bool "kexec system call (EXPERIMENTAL)"
depends on EXPERIMENTAL
@@ -476,10 +449,6 @@ config KEXEC
support. As of this writing the exact hardware interface is
strongly in flux, so no good recommendation can be made.
-config PREEMPT
- bool "Preemptible Kernel (EXPERIMENTAL)"
- depends on EXPERIMENTAL
-
config SMP
bool "Symmetric multi-processing support"
---help---
@@ -515,6 +484,8 @@ config NR_CPUS
This is purely to save memory - each supported CPU adds
approximately eight kilobytes to the kernel image.
+source "kernel/Kconfig.preempt"
+
config CPU_HAS_SR_RB
bool "CPU has SR.RB"
depends on CPU_SH3 || CPU_SH4
@@ -636,6 +607,16 @@ source "fs/Kconfig.binfmt"
endmenu
+menu "Power management options (EXPERIMENTAL)"
+depends on EXPERIMENTAL
+
+source kernel/power/Kconfig
+
+config APM
+ bool "Advanced Power Management Emulation"
+ depends on PM
+endmenu
+
source "net/Kconfig"
source "drivers/Kconfig"
diff --git a/arch/sh/Kconfig.debug b/arch/sh/Kconfig.debug
index 8fb31ab2c02c..48479e014dac 100644
--- a/arch/sh/Kconfig.debug
+++ b/arch/sh/Kconfig.debug
@@ -30,8 +30,35 @@ config EARLY_PRINTK
when the kernel may crash or hang before the serial console is
initialised. If unsure, say N.
+config DEBUG_STACKOVERFLOW
+ bool "Check for stack overflows"
+ depends on DEBUG_KERNEL
+ help
+ This option will cause messages to be printed if free stack space
+ drops below a certain limit.
+
+config DEBUG_STACK_USAGE
+ bool "Stack utilization instrumentation"
+ depends on DEBUG_KERNEL
+ help
+ Enables the display of the minimum amount of free stack which each
+ task has ever had available in the sysrq-T and sysrq-P debug output.
+
+ This option will slow down process creation somewhat.
+
+config 4KSTACKS
+ bool "Use 4Kb for kernel stacks instead of 8Kb"
+ depends on DEBUG_KERNEL
+ help
+ If you say Y here the kernel will use a 4Kb stacksize for the
+ kernel stack attached to each process/thread. This facilitates
+ running more threads on a system and also reduces the pressure
+ on the VM subsystem for higher order allocations. This option
+ will also use IRQ stacks to compensate for the reduced stackspace.
+
config KGDB
bool "Include KGDB kernel debugger"
+ select FRAME_POINTER
help
Include in-kernel hooks for kgdb, the Linux kernel source level
debugger. See <http://kgdb.sourceforge.net/> for more information.
@@ -112,13 +139,4 @@ endchoice
endmenu
-config FRAME_POINTER
- bool "Compile the kernel with frame pointers"
- default y if KGDB
- help
- If you say Y here the resulting kernel image will be slightly larger
- and slower, but it will give very useful debugging information.
- If you don't debug the kernel, you can say N, but we may not be able
- to solve problems without frame pointers.
-
endmenu
diff --git a/arch/sh/Makefile b/arch/sh/Makefile
index e467a450662b..26d62ff51a64 100644
--- a/arch/sh/Makefile
+++ b/arch/sh/Makefile
@@ -18,11 +18,13 @@ cflags-y := -mb
cflags-$(CONFIG_CPU_LITTLE_ENDIAN) := -ml
isa-y := any
+isa-$(CONFIG_SH_DSP) := sh
isa-$(CONFIG_CPU_SH2) := sh2
+isa-$(CONFIG_CPU_SH2A) := sh2a
isa-$(CONFIG_CPU_SH3) := sh3
isa-$(CONFIG_CPU_SH4) := sh4
isa-$(CONFIG_CPU_SH4A) := sh4a
-isa-$(CONFIG_CPU_SH2A) := sh2a
+isa-$(CONFIG_CPU_SH4AL_DSP) := sh4al
isa-$(CONFIG_SH_DSP) := $(isa-y)-dsp
@@ -30,9 +32,11 @@ ifndef CONFIG_MMU
isa-y := $(isa-y)-nommu
endif
+ifndef CONFIG_SH_DSP
ifndef CONFIG_SH_FPU
isa-y := $(isa-y)-nofpu
endif
+endif
cflags-y += $(call as-option,-Wa$(comma)-isa=$(isa-y),)
@@ -79,24 +83,19 @@ head-y := arch/sh/kernel/head.o arch/sh/kernel/init_task.o
LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
core-y += arch/sh/kernel/ arch/sh/mm/
+core-$(CONFIG_SH_FPU_EMU) += arch/sh/math-emu/
# Boards
machdir-$(CONFIG_SH_SOLUTION_ENGINE) := se/770x
machdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se/7751
machdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se/7300
+machdir-$(CONFIG_SH_7343_SOLUTION_ENGINE) := se/7343
machdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se/73180
-machdir-$(CONFIG_SH_STB1_HARP) := harp
-machdir-$(CONFIG_SH_STB1_OVERDRIVE) := overdrive
machdir-$(CONFIG_SH_HP6XX) := hp6xx
-machdir-$(CONFIG_SH_CQREEK) := cqreek
-machdir-$(CONFIG_SH_DMIDA) := dmida
machdir-$(CONFIG_SH_EC3104) := ec3104
machdir-$(CONFIG_SH_SATURN) := saturn
machdir-$(CONFIG_SH_DREAMCAST) := dreamcast
-machdir-$(CONFIG_SH_CAT68701) := cat68701
machdir-$(CONFIG_SH_BIGSUR) := bigsur
-machdir-$(CONFIG_SH_SH2000) := sh2000
-machdir-$(CONFIG_SH_ADX) := adx
machdir-$(CONFIG_SH_MPC1211) := mpc1211
machdir-$(CONFIG_SH_SH03) := sh03
machdir-$(CONFIG_SH_SECUREEDGE5410) := snapgear
@@ -104,16 +103,16 @@ machdir-$(CONFIG_SH_HS7751RVOIP) := renesas/hs7751rvoip
machdir-$(CONFIG_SH_RTS7751R2D) := renesas/rts7751r2d
machdir-$(CONFIG_SH_7751_SYSTEMH) := renesas/systemh
machdir-$(CONFIG_SH_EDOSK7705) := renesas/edosk7705
+machdir-$(CONFIG_SH_R7780RP) := renesas/r7780rp
+machdir-$(CONFIG_SH_7710VOIPGW) := renesas/sh7710voipgw
machdir-$(CONFIG_SH_SH4202_MICRODEV) := superh/microdev
+machdir-$(CONFIG_SH_LANDISK) := landisk
+machdir-$(CONFIG_SH_TITAN) := titan
+machdir-$(CONFIG_SH_SHMIN) := shmin
machdir-$(CONFIG_SH_UNKNOWN) := unknown
incdir-y := $(notdir $(machdir-y))
-
-incdir-$(CONFIG_SH_SOLUTION_ENGINE) := se
-incdir-$(CONFIG_SH_7751_SOLUTION_ENGINE) := se7751
-incdir-$(CONFIG_SH_7300_SOLUTION_ENGINE) := se7300
-incdir-$(CONFIG_SH_73180_SOLUTION_ENGINE) := se73180
-incdir-$(CONFIG_SH_HP600) := hp6xx
+incdir-$(CONFIG_SH_HP6XX) := hp6xx
ifneq ($(machdir-y),)
core-y += arch/sh/boards/$(machdir-y)/
@@ -137,17 +136,14 @@ boot := arch/sh/boot
CPPFLAGS_vmlinux.lds := -traditional
-ifneq ($(KBUILD_SRC),)
incdir-prefix := $(srctree)/include/asm-sh/
-else
-incdir-prefix :=
-endif
# Update machine arch and proc symlinks if something which affects
# them changed. We use .arch and .mach to indicate when they were
# updated last, otherwise make uses the target directory mtime.
-include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) include/config/auto.conf
+include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) \
+ include/config/auto.conf FORCE
@echo ' SYMLINK include/asm-sh/cpu -> include/asm-sh/$(cpuincdir-y)'
$(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
$(Q)ln -fsn $(incdir-prefix)$(cpuincdir-y) include/asm-sh/cpu
@@ -157,7 +153,8 @@ include/asm-sh/.cpu: $(wildcard include/config/cpu/*.h) include/config/auto.conf
# don't, just reference the parent directory so the semantics are
# kept roughly the same.
-include/asm-sh/.mach: $(wildcard include/config/sh/*.h) include/config/auto.conf
+include/asm-sh/.mach: $(wildcard include/config/sh/*.h) \
+ include/config/auto.conf FORCE
@echo -n ' SYMLINK include/asm-sh/mach -> '
$(Q)if [ ! -d include/asm-sh ]; then mkdir -p include/asm-sh; fi
$(Q)if [ -d $(incdir-prefix)$(incdir-y) ]; then \
@@ -170,7 +167,7 @@ include/asm-sh/.mach: $(wildcard include/config/sh/*.h) include/config/auto.conf
fi
@touch $@
-archprepare: maketools include/asm-sh/.cpu include/asm-sh/.mach
+archprepare: include/asm-sh/.cpu include/asm-sh/.mach maketools
PHONY += maketools FORCE
maketools: include/linux/version.h FORCE
@@ -191,4 +188,3 @@ CLEAN_FILES += include/asm-sh/machtypes.h
define archhelp
@echo ' zImage - Compressed kernel image (arch/sh/boot/zImage)'
endef
-
diff --git a/arch/sh/boards/adx/Makefile b/arch/sh/boards/adx/Makefile
deleted file mode 100644
index 5b1c531b3991..000000000000
--- a/arch/sh/boards/adx/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for ADX boards
-#
-
-obj-y := setup.o irq.o irq_maskreq.o
-
diff --git a/arch/sh/boards/adx/irq.c b/arch/sh/boards/adx/irq.c
deleted file mode 100644
index c6ca409dff98..000000000000
--- a/arch/sh/boards/adx/irq.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * linux/arch/sh/boards/adx/irq.c
- *
- * Copyright (C) 2001 A&D Co., Ltd.
- *
- * I/O routine and setup routines for A&D ADX Board
- *
- * 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/irq.h>
-
-void init_adx_IRQ(void)
-{
- int i;
-
-/* printk("init_adx_IRQ()\n");*/
- /* setup irq_mask_register */
- irq_mask_register = (unsigned short *)0xa6000008;
-
- /* cover all external interrupt area by maskreg_irq_type
- * (Actually, irq15 doesn't exist)
- */
- for (i = 0; i < 16; i++) {
- make_maskreg_irq(i);
- disable_irq(i);
- }
-}
diff --git a/arch/sh/boards/adx/setup.c b/arch/sh/boards/adx/setup.c
deleted file mode 100644
index 4938d9592343..000000000000
--- a/arch/sh/boards/adx/setup.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * linux/arch/sh/board/adx/setup.c
- *
- * Copyright (C) 2001 A&D Co., Ltd.
- *
- * I/O routine and setup routines for A&D ADX Board
- *
- * 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/machvec.h>
-#include <linux/module.h>
-
-extern void init_adx_IRQ(void);
-extern void *cf_io_base;
-
-const char *get_system_type(void)
-{
- return "A&D ADX";
-}
-
-unsigned long adx_isa_port2addr(unsigned long offset)
-{
- /* CompactFlash (IDE) */
- if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset == 0x3f6)) {
- return (unsigned long)cf_io_base + offset;
- }
-
- /* eth0 */
- if ((offset >= 0x300) && (offset <= 0x30f)) {
- return 0xa5000000 + offset; /* COMM BOARD (AREA1) */
- }
-
- return offset + 0xb0000000; /* IOBUS (AREA 4)*/
-}
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_adx __initmv = {
- .mv_nr_irqs = 48,
- .mv_isa_port2addr = adx_isa_port2addr,
- .mv_init_irq = init_adx_IRQ,
-};
-ALIAS_MV(adx)
-
-int __init platform_setup(void)
-{
- /* Nothing to see here .. */
- return 0;
-}
-
diff --git a/arch/sh/boards/bigsur/io.c b/arch/sh/boards/bigsur/io.c
index 6835381da5fd..23071f97eec3 100644
--- a/arch/sh/boards/bigsur/io.c
+++ b/arch/sh/boards/bigsur/io.c
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/io_bigsur.c
+ * arch/sh/boards/bigsur/io.c
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
* Derived from io_hd64465.h, which bore the message:
diff --git a/arch/sh/boards/bigsur/irq.c b/arch/sh/boards/bigsur/irq.c
index ac946a2201c7..1ab04da36382 100644
--- a/arch/sh/boards/bigsur/irq.c
+++ b/arch/sh/boards/bigsur/irq.c
@@ -19,6 +19,7 @@
* IRQ functions for a Hitachi Big Sur Evaluation Board.
*
*/
+#undef DEBUG
#include <linux/sched.h>
#include <linux/module.h>
@@ -41,10 +42,8 @@
#undef BIGSUR_DEBUG
#ifdef BIGSUR_DEBUG
-#define DPRINTK(args...) printk(args)
#define DIPRINTK(n, args...) if (BIGSUR_DEBUG>(n)) printk(args)
#else
-#define DPRINTK(args...)
#define DIPRINTK(n, args...)
#endif /* BIGSUR_DEBUG */
@@ -60,45 +59,39 @@ extern int hd64465_irq_demux(int irq);
/* Level 1 IRQ routines */
static void disable_bigsur_l1irq(unsigned int irq)
{
- unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
- DPRINTK("Disable L1 IRQ %d\n", irq);
+ pr_debug("Disable L1 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
- local_irq_save(flags);
/* Disable IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
- local_irq_restore(flags);
return;
}
- DPRINTK("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+ pr_debug("disable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l1irq(unsigned int irq)
{
- unsigned long flags;
unsigned char mask;
unsigned int mask_port = ((irq - BIGSUR_IRQ_LOW)/8) ? BIGSUR_IRLMR1 : BIGSUR_IRLMR0;
unsigned char bit = (1 << ((irq - MGATE_IRQ_LOW)%8) );
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
- DPRINTK("Enable L1 IRQ %d\n", irq);
+ pr_debug("Enable L1 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l1irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
- local_irq_save(flags);
/* Enable L1 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
- local_irq_restore(flags);
return;
}
- DPRINTK("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
+ pr_debug("enable_bigsur_l1irq: Invalid IRQ %d\n", irq);
}
@@ -126,51 +119,45 @@ static const u32 imr_offset = BIGSUR_IMR0 - BIGSUR_IMR1;
/* Level 2 IRQ routines */
static void disable_bigsur_l2irq(unsigned int irq)
{
- unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
- if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
- DPRINTK("Disable L2 IRQ %d\n", irq);
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ pr_debug("Disable L2 IRQ %d\n", irq);
DIPRINTK(2,"disable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
- local_irq_save(flags);
/* Disable L2 IRQ - set mask bit */
mask = inb(mask_port) | bit;
outb(mask, mask_port);
- local_irq_restore(flags);
return;
}
- DPRINTK("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+ pr_debug("disable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void enable_bigsur_l2irq(unsigned int irq)
{
- unsigned long flags;
unsigned char mask;
unsigned char bit = 1 << ((irq-BIGSUR_2NDLVL_IRQ_LOW)%8);
unsigned int mask_port = imr_base - REG_NUM(irq)*imr_offset;
- if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
- DPRINTK("Enable L2 IRQ %d\n", irq);
+ if(irq >= BIGSUR_2NDLVL_IRQ_LOW && irq < BIGSUR_2NDLVL_IRQ_HIGH) {
+ pr_debug("Enable L2 IRQ %d\n", irq);
DIPRINTK(2,"enable_bigsur_l2irq: IMR=0x%08x mask=0x%x\n",
mask_port, bit);
- local_irq_save(flags);
/* Enable L2 IRQ - clear mask bit */
mask = inb(mask_port) & ~bit;
outb(mask, mask_port);
- local_irq_restore(flags);
return;
}
- DPRINTK("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
+ pr_debug("enable_bigsur_l2irq: Invalid IRQ %d\n", irq);
}
static void mask_and_ack_bigsur(unsigned int irq)
{
- DPRINTK("mask_and_ack_bigsur IRQ %d\n", irq);
+ pr_debug("mask_and_ack_bigsur IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
@@ -179,7 +166,7 @@ static void mask_and_ack_bigsur(unsigned int irq)
static void end_bigsur_irq(unsigned int irq)
{
- DPRINTK("end_bigsur_irq IRQ %d\n", irq);
+ pr_debug("end_bigsur_irq IRQ %d\n", irq);
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
enable_bigsur_l1irq(irq);
@@ -193,7 +180,7 @@ static unsigned int startup_bigsur_irq(unsigned int irq)
u8 mask;
u32 reg;
- DPRINTK("startup_bigsur_irq IRQ %d\n", irq);
+ pr_debug("startup_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH) {
/* Enable the L1 IRQ */
@@ -218,7 +205,7 @@ static unsigned int startup_bigsur_irq(unsigned int irq)
static void shutdown_bigsur_irq(unsigned int irq)
{
- DPRINTK("shutdown_bigsur_irq IRQ %d\n", irq);
+ pr_debug("shutdown_bigsur_irq IRQ %d\n", irq);
if(irq >= BIGSUR_IRQ_LOW && irq < BIGSUR_IRQ_HIGH)
disable_bigsur_l1irq(irq);
else
@@ -260,7 +247,7 @@ static void make_bigsur_l1isr(unsigned int irq) {
disable_bigsur_l1irq(irq);
return;
}
- DPRINTK("make_bigsur_l1isr: bad irq, %d\n", irq);
+ pr_debug("make_bigsur_l1isr: bad irq, %d\n", irq);
return;
}
@@ -277,7 +264,7 @@ static void make_bigsur_l2isr(unsigned int irq) {
disable_bigsur_l2irq(irq);
return;
}
- DPRINTK("make_bigsur_l2isr: bad irq, %d\n", irq);
+ pr_debug("make_bigsur_l2isr: bad irq, %d\n", irq);
return;
}
diff --git a/arch/sh/boards/bigsur/led.c b/arch/sh/boards/bigsur/led.c
index 6b08c0e1c453..d221439aafcc 100644
--- a/arch/sh/boards/bigsur/led.c
+++ b/arch/sh/boards/bigsur/led.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/led_bigsur.c
+ * linux/arch/sh/boards/bigsur/led.c
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
* Derived from led_se.c and led.c, which bore the message:
diff --git a/arch/sh/boards/bigsur/setup.c b/arch/sh/boards/bigsur/setup.c
index dfeede9da50f..9711c20fc9e4 100644
--- a/arch/sh/boards/bigsur/setup.c
+++ b/arch/sh/boards/bigsur/setup.c
@@ -41,31 +41,7 @@
// Big Sur Init Routines
/*===========================================================*/
-const char *get_system_type(void)
-{
- return "Big Sur";
-}
-
-/*
- * The Machine Vector
- */
-extern void heartbeat_bigsur(void);
-extern void init_bigsur_IRQ(void);
-
-struct sh_machine_vector mv_bigsur __initmv = {
- .mv_nr_irqs = NR_IRQS, // Defined in <asm/irq.h>
-
- .mv_isa_port2addr = bigsur_isa_port2addr,
- .mv_irq_demux = bigsur_irq_demux,
-
- .mv_init_irq = init_bigsur_IRQ,
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_bigsur,
-#endif
-};
-ALIAS_MV(bigsur)
-
-int __init platform_setup(void)
+static void __init bigsur_setup(char **cmdline_p)
{
/* Mask all 2nd level IRQ's */
outb(-1,BIGSUR_IMR0);
@@ -89,7 +65,24 @@ int __init platform_setup(void)
outw(1, BIGSUR_ETHR+0xe);
/* set the IO port to BIGSUR_ETHER_IOPORT */
outw(BIGSUR_ETHER_IOPORT<<3, BIGSUR_ETHR+0x2);
-
- return 0;
}
+/*
+ * The Machine Vector
+ */
+extern void heartbeat_bigsur(void);
+extern void init_bigsur_IRQ(void);
+
+struct sh_machine_vector mv_bigsur __initmv = {
+ .mv_name = "Big Sur",
+ .mv_setup = bigsur_setup,
+
+ .mv_isa_port2addr = bigsur_isa_port2addr,
+ .mv_irq_demux = bigsur_irq_demux,
+
+ .mv_init_irq = init_bigsur_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_bigsur,
+#endif
+};
+ALIAS_MV(bigsur)
diff --git a/arch/sh/boards/cat68701/Makefile b/arch/sh/boards/cat68701/Makefile
deleted file mode 100644
index 52c1de0a6dfd..000000000000
--- a/arch/sh/boards/cat68701/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the CAT-68701 specific parts of the kernel
-#
-
-obj-y := setup.o irq.o
-
diff --git a/arch/sh/boards/cat68701/irq.c b/arch/sh/boards/cat68701/irq.c
deleted file mode 100644
index f9a6d185fb8b..000000000000
--- a/arch/sh/boards/cat68701/irq.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * linux/arch/sh/boards/cat68701/irq.c
- *
- * Copyright (C) 2000 Niibe Yutaka
- * 2001 Yutaro Ebihara
- *
- * Setup routines for A-ONE Corp CAT-68701 SH7708 Board
- *
- * 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/irq.h>
-
-int cat68701_irq_demux(int irq)
-{
- if(irq==13) return 14;
- if(irq==7) return 10;
- return irq;
-}
-
-void init_cat68701_IRQ()
-{
- make_imask_irq(10);
- make_imask_irq(14);
-}
diff --git a/arch/sh/boards/cat68701/setup.c b/arch/sh/boards/cat68701/setup.c
deleted file mode 100644
index 90e5175df227..000000000000
--- a/arch/sh/boards/cat68701/setup.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * linux/arch/sh/boards/cat68701/setup.c
- *
- * Copyright (C) 2000 Niibe Yutaka
- * 2001 Yutaro Ebihara
- *
- * Setup routines for A-ONE Corp CAT-68701 SH7708 Board
- *
- * 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/io.h>
-#include <asm/machvec.h>
-#include <asm/mach/io.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-
-const char *get_system_type(void)
-{
- return "CAT-68701";
-}
-
-#ifdef CONFIG_HEARTBEAT
-void heartbeat_cat68701()
-{
- static unsigned int cnt = 0, period = 0 , bit = 0;
- cnt += 1;
- if (cnt < period) {
- return;
- }
- cnt = 0;
-
- /* Go through the points (roughly!):
- * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
- */
- period = 110 - ( (300<<FSHIFT)/
- ((avenrun[0]/5) + (3<<FSHIFT)) );
-
- if(bit){ bit=0; }else{ bit=1; }
- outw(bit<<15,0x3fe);
-}
-#endif /* CONFIG_HEARTBEAT */
-
-unsigned long cat68701_isa_port2addr(unsigned long offset)
-{
- /* CompactFlash (IDE) */
- if (((offset >= 0x1f0) && (offset <= 0x1f7)) || (offset==0x3f6))
- return 0xba000000 + offset;
-
- /* INPUT PORT */
- if ((offset >= 0x3fc) && (offset <= 0x3fd))
- return 0xb4007000 + offset;
-
- /* OUTPUT PORT */
- if ((offset >= 0x3fe) && (offset <= 0x3ff))
- return 0xb4007400 + offset;
-
- return offset + 0xb4000000; /* other I/O (EREA 5)*/
-}
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_cat68701 __initmv = {
- .mv_nr_irqs = 32,
- .mv_isa_port2addr = cat68701_isa_port2addr,
- .mv_irq_demux = cat68701_irq_demux,
-
- .mv_init_irq = init_cat68701_IRQ,
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_cat68701,
-#endif
-};
-ALIAS_MV(cat68701)
-
-int __init platform_setup(void)
-{
- /* dummy read erea5 (CS8900A) */
-}
-
diff --git a/arch/sh/boards/cqreek/Makefile b/arch/sh/boards/cqreek/Makefile
deleted file mode 100644
index 1a788a85eba3..000000000000
--- a/arch/sh/boards/cqreek/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the CqREEK specific parts of the kernel
-#
-
-obj-y := setup.o irq.o
-
diff --git a/arch/sh/boards/cqreek/irq.c b/arch/sh/boards/cqreek/irq.c
deleted file mode 100644
index 2955adc52310..000000000000
--- a/arch/sh/boards/cqreek/irq.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/* $Id: irq.c,v 1.1.2.4 2002/11/04 20:33:56 lethal Exp $
- *
- * arch/sh/boards/cqreek/irq.c
- *
- * Copyright (C) 2000 Niibe Yutaka
- *
- * CqREEK IDE/ISA Bridge Support.
- *
- */
-
-#include <linux/irq.h>
-#include <linux/init.h>
-
-#include <asm/cqreek/cqreek.h>
-#include <asm/io.h>
-#include <asm/io_generic.h>
-#include <asm/irq.h>
-#include <asm/machvec.h>
-#include <asm/machvec_init.h>
-#include <asm/rtc.h>
-
-struct cqreek_irq_data {
- unsigned short mask_port; /* Port of Interrupt Mask Register */
- unsigned short stat_port; /* Port of Interrupt Status Register */
- unsigned short bit; /* Value of the bit */
-};
-static struct cqreek_irq_data cqreek_irq_data[NR_IRQS];
-
-static void disable_cqreek_irq(unsigned int irq)
-{
- unsigned long flags;
- unsigned short mask;
- unsigned short mask_port = cqreek_irq_data[irq].mask_port;
- unsigned short bit = cqreek_irq_data[irq].bit;
-
- local_irq_save(flags);
- /* Disable IRQ */
- mask = inw(mask_port) & ~bit;
- outw_p(mask, mask_port);
- local_irq_restore(flags);
-}
-
-static void enable_cqreek_irq(unsigned int irq)
-{
- unsigned long flags;
- unsigned short mask;
- unsigned short mask_port = cqreek_irq_data[irq].mask_port;
- unsigned short bit = cqreek_irq_data[irq].bit;
-
- local_irq_save(flags);
- /* Enable IRQ */
- mask = inw(mask_port) | bit;
- outw_p(mask, mask_port);
- local_irq_restore(flags);
-}
-
-static void mask_and_ack_cqreek(unsigned int irq)
-{
- unsigned short stat_port = cqreek_irq_data[irq].stat_port;
- unsigned short bit = cqreek_irq_data[irq].bit;
-
- disable_cqreek_irq(irq);
- /* Clear IRQ (it might be edge IRQ) */
- inw(stat_port);
- outw_p(bit, stat_port);
-}
-
-static void end_cqreek_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_cqreek_irq(irq);
-}
-
-static unsigned int startup_cqreek_irq(unsigned int irq)
-{
- enable_cqreek_irq(irq);
- return 0;
-}
-
-static void shutdown_cqreek_irq(unsigned int irq)
-{
- disable_cqreek_irq(irq);
-}
-
-static struct hw_interrupt_type cqreek_irq_type = {
- .typename = "CqREEK-IRQ",
- .startup = startup_cqreek_irq,
- .shutdown = shutdown_cqreek_irq,
- .enable = enable_cqreek_irq,
- .disable = disable_cqreek_irq,
- .ack = mask_and_ack_cqreek,
- .end = end_cqreek_irq
-};
-
-int cqreek_has_ide, cqreek_has_isa;
-
-/* XXX: This is just for test for my NE2000 ISA board
- What we really need is virtualized IRQ and demultiplexer like HP600 port */
-void __init init_cqreek_IRQ(void)
-{
- if (cqreek_has_ide) {
- cqreek_irq_data[14].mask_port = BRIDGE_IDE_INTR_MASK;
- cqreek_irq_data[14].stat_port = BRIDGE_IDE_INTR_STAT;
- cqreek_irq_data[14].bit = 1;
-
- irq_desc[14].chip = &cqreek_irq_type;
- irq_desc[14].status = IRQ_DISABLED;
- irq_desc[14].action = 0;
- irq_desc[14].depth = 1;
-
- disable_cqreek_irq(14);
- }
-
- if (cqreek_has_isa) {
- cqreek_irq_data[10].mask_port = BRIDGE_ISA_INTR_MASK;
- cqreek_irq_data[10].stat_port = BRIDGE_ISA_INTR_STAT;
- cqreek_irq_data[10].bit = (1 << 10);
-
- /* XXX: Err... we may need demultiplexer for ISA irq... */
- irq_desc[10].chip = &cqreek_irq_type;
- irq_desc[10].status = IRQ_DISABLED;
- irq_desc[10].action = 0;
- irq_desc[10].depth = 1;
-
- disable_cqreek_irq(10);
- }
-}
-
diff --git a/arch/sh/boards/cqreek/setup.c b/arch/sh/boards/cqreek/setup.c
deleted file mode 100644
index eff4ed93599f..000000000000
--- a/arch/sh/boards/cqreek/setup.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/* $Id: setup.c,v 1.5 2003/08/04 01:51:58 lethal Exp $
- *
- * arch/sh/kernel/setup_cqreek.c
- *
- * Copyright (C) 2000 Niibe Yutaka
- *
- * CqREEK IDE/ISA Bridge Support.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <asm/mach/cqreek.h>
-#include <asm/machvec.h>
-#include <asm/io.h>
-#include <asm/io_generic.h>
-#include <asm/irq.h>
-#include <asm/rtc.h>
-
-#define IDE_OFFSET 0xA4000000UL
-#define ISA_OFFSET 0xA4A00000UL
-
-const char *get_system_type(void)
-{
- return "CqREEK";
-}
-
-static unsigned long cqreek_port2addr(unsigned long port)
-{
- if (0x0000<=port && port<=0x0040)
- return IDE_OFFSET + port;
- if ((0x01f0<=port && port<=0x01f7) || port == 0x03f6)
- return IDE_OFFSET + port;
-
- return ISA_OFFSET + port;
-}
-
-/*
- * The Machine Vector
- */
-struct sh_machine_vector mv_cqreek __initmv = {
-#if defined(CONFIG_CPU_SH4)
- .mv_nr_irqs = 48,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
- .mv_nr_irqs = 32,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
- .mv_nr_irqs = 61,
-#endif
-
- .mv_init_irq = init_cqreek_IRQ,
-
- .mv_isa_port2addr = cqreek_port2addr,
-};
-ALIAS_MV(cqreek)
-
-/*
- * Initialize the board
- */
-void __init platform_setup(void)
-{
- int i;
-/* udelay is not available at setup time yet... */
-#define DELAY() do {for (i=0; i<10000; i++) ctrl_inw(0xa0000000);} while(0)
-
- if ((inw (BRIDGE_FEATURE) & 1)) { /* We have IDE interface */
- outw_p(0, BRIDGE_IDE_INTR_LVL);
- outw_p(0, BRIDGE_IDE_INTR_MASK);
-
- outw_p(0, BRIDGE_IDE_CTRL);
- DELAY();
-
- outw_p(0x8000, BRIDGE_IDE_CTRL);
- DELAY();
-
- outw_p(0xffff, BRIDGE_IDE_INTR_STAT); /* Clear interrupt status */
- outw_p(0x0f-14, BRIDGE_IDE_INTR_LVL); /* Use 14 IPR */
- outw_p(1, BRIDGE_IDE_INTR_MASK); /* Enable interrupt */
- cqreek_has_ide=1;
- }
-
- if ((inw (BRIDGE_FEATURE) & 2)) { /* We have ISA interface */
- outw_p(0, BRIDGE_ISA_INTR_LVL);
- outw_p(0, BRIDGE_ISA_INTR_MASK);
-
- outw_p(0, BRIDGE_ISA_CTRL);
- DELAY();
- outw_p(0x8000, BRIDGE_ISA_CTRL);
- DELAY();
-
- outw_p(0xffff, BRIDGE_ISA_INTR_STAT); /* Clear interrupt status */
- outw_p(0x0f-10, BRIDGE_ISA_INTR_LVL); /* Use 10 IPR */
- outw_p(0xfff8, BRIDGE_ISA_INTR_MASK); /* Enable interrupt */
- cqreek_has_isa=1;
- }
-
- printk(KERN_INFO "CqREEK Setup (IDE=%d, ISA=%d)...done\n", cqreek_has_ide, cqreek_has_isa);
-}
-
diff --git a/arch/sh/boards/dmida/Makefile b/arch/sh/boards/dmida/Makefile
deleted file mode 100644
index 75999aa0a2d9..000000000000
--- a/arch/sh/boards/dmida/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-#
-# Makefile for the DataMyte Industrial Digital Assistant(tm) specific parts
-# of the kernel
-#
-
-obj-y := mach.o
-
diff --git a/arch/sh/boards/dmida/mach.c b/arch/sh/boards/dmida/mach.c
deleted file mode 100644
index d03a25f989c2..000000000000
--- a/arch/sh/boards/dmida/mach.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * linux/arch/sh/boards/dmida/mach.c
- *
- * by Greg Banks <gbanks@pocketpenguins.com>
- * (c) 2000 PocketPenguins Inc
- *
- * Derived from mach_hp600.c, which bore the message:
- * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the DataMyte Industrial Digital Assistant(tm).
- * See http://www.dmida.com
- *
- */
-
-#include <linux/init.h>
-
-#include <asm/machvec.h>
-#include <asm/rtc.h>
-#include <asm/machvec_init.h>
-
-#include <asm/io.h>
-#include <asm/hd64465/hd64465.h>
-#include <asm/irq.h>
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_dmida __initmv = {
- .mv_nr_irqs = HD64465_IRQ_BASE+HD64465_IRQ_NUM,
-
- .mv_inb = hd64465_inb,
- .mv_inw = hd64465_inw,
- .mv_inl = hd64465_inl,
- .mv_outb = hd64465_outb,
- .mv_outw = hd64465_outw,
- .mv_outl = hd64465_outl,
-
- .mv_inb_p = hd64465_inb_p,
- .mv_inw_p = hd64465_inw,
- .mv_inl_p = hd64465_inl,
- .mv_outb_p = hd64465_outb_p,
- .mv_outw_p = hd64465_outw,
- .mv_outl_p = hd64465_outl,
-
- .mv_insb = hd64465_insb,
- .mv_insw = hd64465_insw,
- .mv_insl = hd64465_insl,
- .mv_outsb = hd64465_outsb,
- .mv_outsw = hd64465_outsw,
- .mv_outsl = hd64465_outsl,
-
- .mv_irq_demux = hd64465_irq_demux,
-};
-ALIAS_MV(dmida)
-
diff --git a/arch/sh/boards/dreamcast/irq.c b/arch/sh/boards/dreamcast/irq.c
index b10a6b11c034..5bf01f86c20c 100644
--- a/arch/sh/boards/dreamcast/irq.c
+++ b/arch/sh/boards/dreamcast/irq.c
@@ -10,7 +10,6 @@
*/
#include <linux/irq.h>
-
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/dreamcast/sysasic.h>
@@ -26,10 +25,10 @@
event.
There are three 32-bit ESRs located at 0xa05f8900 - 0xa05f6908. Event
- types can be found in include/asm-sh/dc_sysasic.h. There are three groups
- of EMRs that parallel the ESRs. Each EMR group corresponds to an IRQ, so
- 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928 triggers
- IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
+ types can be found in include/asm-sh/dreamcast/sysasic.h. There are three
+ groups of EMRs that parallel the ESRs. Each EMR group corresponds to an
+ IRQ, so 0xa05f6910 - 0xa05f6918 triggers IRQ 13, 0xa05f6920 - 0xa05f6928
+ triggers IRQ 11, and 0xa05f6930 - 0xa05f6938 triggers IRQ 9.
In the kernel, these events are mapped to virtual IRQs so that drivers can
respond to them as they would a normal interrupt. In order to keep this
@@ -57,29 +56,23 @@
/* Disable the hardware event by masking its bit in its EMR */
static inline void disable_systemasic_irq(unsigned int irq)
{
- unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
- local_irq_save(flags);
mask = inl(emr);
mask &= ~(1 << EVENT_BIT(irq));
outl(mask, emr);
- local_irq_restore(flags);
}
/* Enable the hardware event by setting its bit in its EMR */
static inline void enable_systemasic_irq(unsigned int irq)
{
- unsigned long flags;
__u32 emr = EMR_BASE + (LEVEL(irq) << 4) + (LEVEL(irq) << 2);
__u32 mask;
- local_irq_save(flags);
mask = inl(emr);
mask |= (1 << EVENT_BIT(irq));
outl(mask, emr);
- local_irq_restore(flags);
}
/* Acknowledge a hardware event by writing its bit back to its ESR */
diff --git a/arch/sh/boards/dreamcast/rtc.c b/arch/sh/boards/dreamcast/rtc.c
index 379de1629134..b3a876a3b859 100644
--- a/arch/sh/boards/dreamcast/rtc.c
+++ b/arch/sh/boards/dreamcast/rtc.c
@@ -1,4 +1,5 @@
-/* arch/sh/kernel/rtc-aica.c
+/*
+ * arch/sh/boards/dreamcast/rtc.c
*
* Dreamcast AICA RTC routines.
*
@@ -10,15 +11,12 @@
*/
#include <linux/time.h>
-
+#include <asm/rtc.h>
#include <asm/io.h>
-extern void (*rtc_get_time)(struct timespec *);
-extern int (*rtc_set_time)(const time_t);
-
/* The AICA RTC has an Epoch of 1/1/1950, so we must subtract 20 years (in
- seconds to get the standard Unix Epoch when getting the time, and add 20
- years when setting the time. */
+ seconds) to get the standard Unix Epoch when getting the time, and add
+ 20 years when setting the time. */
#define TWENTY_YEARS ((20 * 365LU + 5) * 86400)
/* The AICA RTC is represented by a 32-bit seconds counter stored in 2 16-bit
@@ -32,7 +30,8 @@ extern int (*rtc_set_time)(const time_t);
*
* Grabs the current RTC seconds counter and adjusts it to the Unix Epoch.
*/
-void aica_rtc_gettimeofday(struct timespec *ts) {
+void aica_rtc_gettimeofday(struct timespec *ts)
+{
unsigned long val1, val2;
do {
@@ -55,7 +54,8 @@ void aica_rtc_gettimeofday(struct timespec *ts) {
*
* Adjusts the given @tv to the AICA Epoch and sets the RTC seconds counter.
*/
-int aica_rtc_settimeofday(const time_t secs) {
+int aica_rtc_settimeofday(const time_t secs)
+{
unsigned long val1, val2;
unsigned long adj = secs + TWENTY_YEARS;
@@ -75,7 +75,7 @@ int aica_rtc_settimeofday(const time_t secs) {
void aica_time_init(void)
{
- rtc_get_time = aica_rtc_gettimeofday;
- rtc_set_time = aica_rtc_settimeofday;
+ rtc_sh_get_time = aica_rtc_gettimeofday;
+ rtc_sh_set_time = aica_rtc_settimeofday;
}
diff --git a/arch/sh/boards/dreamcast/setup.c b/arch/sh/boards/dreamcast/setup.c
index 0027b80a2343..f13017eeeb27 100644
--- a/arch/sh/boards/dreamcast/setup.c
+++ b/arch/sh/boards/dreamcast/setup.c
@@ -22,41 +22,21 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/device.h>
-
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/rtc.h>
#include <asm/machvec.h>
-#include <asm/machvec_init.h>
#include <asm/mach/sysasic.h>
extern struct hw_interrupt_type systemasic_int;
-/* XXX: Move this into it's proper header. */
-extern void (*board_time_init)(void);
extern void aica_time_init(void);
extern int gapspci_init(void);
extern int systemasic_irq_demux(int);
-void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, int);
+void *dreamcast_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
int dreamcast_consistent_free(struct device *, size_t, void *, dma_addr_t);
-const char *get_system_type(void)
-{
- return "Sega Dreamcast";
-}
-
-struct sh_machine_vector mv_dreamcast __initmv = {
- .mv_nr_irqs = NR_IRQS,
-
- .mv_irq_demux = systemasic_irq_demux,
-
-#ifdef CONFIG_PCI
- .mv_consistent_alloc = dreamcast_consistent_alloc,
- .mv_consistent_free = dreamcast_consistent_free,
-#endif
-};
-ALIAS_MV(dreamcast)
-
-int __init platform_setup(void)
+static void __init dreamcast_setup(char **cmdline_p)
{
int i;
@@ -78,6 +58,16 @@ int __init platform_setup(void)
if (gapspci_init() < 0)
printk(KERN_WARNING "GAPSPCI was not detected.\n");
#endif
-
- return 0;
}
+
+struct sh_machine_vector mv_dreamcast __initmv = {
+ .mv_name = "Sega Dreamcast",
+ .mv_setup = dreamcast_setup,
+ .mv_irq_demux = systemasic_irq_demux,
+
+#ifdef CONFIG_PCI
+ .mv_consistent_alloc = dreamcast_consistent_alloc,
+ .mv_consistent_free = dreamcast_consistent_free,
+#endif
+};
+ALIAS_MV(dreamcast)
diff --git a/arch/sh/boards/ec3104/io.c b/arch/sh/boards/ec3104/io.c
index a70928c44753..2f86394b280b 100644
--- a/arch/sh/boards/ec3104/io.c
+++ b/arch/sh/boards/ec3104/io.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/io_ec3104.c
+ * linux/arch/sh/boards/ec3104/io.c
* EC3104 companion chip support
*
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
diff --git a/arch/sh/boards/ec3104/setup.c b/arch/sh/boards/ec3104/setup.c
index 4b3ef16a0e96..902bc975a13e 100644
--- a/arch/sh/boards/ec3104/setup.c
+++ b/arch/sh/boards/ec3104/setup.c
@@ -21,22 +21,36 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/types.h>
-
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/machvec.h>
#include <asm/mach/ec3104.h>
-const char *get_system_type(void)
+static void __init ec3104_setup(char **cmdline_p)
{
- return "EC3104";
+ char str[8];
+ int i;
+
+ for (i=0; i<8; i++)
+ str[i] = ctrl_readb(EC3104_BASE + i);
+
+ for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
+ irq_desc[i].handler = &ec3104_int;
+
+ printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
+ str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
+
+ /* mask all interrupts. this should have been done by the boot
+ * loader for us but we want to be sure ... */
+ ctrl_writel(0xffffffff, EC3104_IMR);
}
/*
* The Machine Vector
*/
-
struct sh_machine_vector mv_ec3104 __initmv = {
+ .mv_name = "EC3104",
+ .mv_setup = ec3104_setup,
.mv_nr_irqs = 96,
.mv_inb = ec3104_inb,
@@ -48,31 +62,4 @@ struct sh_machine_vector mv_ec3104 __initmv = {
.mv_irq_demux = ec3104_irq_demux,
};
-
ALIAS_MV(ec3104)
-
-int __init platform_setup(void)
-{
- char str[8];
- int i;
-
- if (0)
- return 0;
-
- for (i=0; i<8; i++)
- str[i] = ctrl_readb(EC3104_BASE + i);
-
- for (i = EC3104_IRQBASE; i < EC3104_IRQBASE + 32; i++)
- irq_desc[i].chip = &ec3104_int;
-
- printk("initializing EC3104 \"%.8s\" at %08x, IRQ %d, IRQ base %d\n",
- str, EC3104_BASE, EC3104_IRQ, EC3104_IRQBASE);
-
-
- /* mask all interrupts. this should have been done by the boot
- * loader for us but we want to be sure ... */
- ctrl_writel(0xffffffff, EC3104_IMR);
-
- return 0;
-}
-
diff --git a/arch/sh/boards/harp/Makefile b/arch/sh/boards/harp/Makefile
deleted file mode 100644
index eb753d31812e..000000000000
--- a/arch/sh/boards/harp/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for STMicroelectronics board specific parts of the kernel
-#
-
-obj-y := irq.o setup.o mach.o led.o
-
-obj-$(CONFIG_PCI) += pcidma.o
-
diff --git a/arch/sh/boards/harp/irq.c b/arch/sh/boards/harp/irq.c
deleted file mode 100644
index 96bb41c9fc55..000000000000
--- a/arch/sh/boards/harp/irq.c
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Looks after interrupts on the HARP board.
- *
- * Bases on the IPR irq system
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/harp/harp.h>
-
-
-#define NUM_EXTERNAL_IRQS 16
-
-// Early versions of the STB1 Overdrive required this nasty frig
-//#define INVERT_INTMASK_WRITES
-
-static void enable_harp_irq(unsigned int irq);
-static void disable_harp_irq(unsigned int irq);
-
-/* shutdown is same as "disable" */
-#define shutdown_harp_irq disable_harp_irq
-
-static void mask_and_ack_harp(unsigned int);
-static void end_harp_irq(unsigned int irq);
-
-static unsigned int startup_harp_irq(unsigned int irq)
-{
- enable_harp_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type harp_irq_type = {
- .typename = "Harp-IRQ",
- .startup = startup_harp_irq,
- .shutdown = shutdown_harp_irq,
- .enable = enable_harp_irq,
- .disable = disable_harp_irq,
- .ack = mask_and_ack_harp,
- .end = end_harp_irq
-};
-
-static void disable_harp_irq(unsigned int irq)
-{
- unsigned val, flags;
- unsigned maskReg;
- unsigned mask;
- int pri;
-
- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
- return;
-
- pri = 15 - irq;
-
- if (pri < 8) {
- maskReg = EPLD_INTMASK0;
- } else {
- maskReg = EPLD_INTMASK1;
- pri -= 8;
- }
-
- local_irq_save(flags);
- mask = ctrl_inl(maskReg);
- mask &= (~(1 << pri));
-#if defined(INVERT_INTMASK_WRITES)
- mask ^= 0xff;
-#endif
- ctrl_outl(mask, maskReg);
- local_irq_restore(flags);
-}
-
-static void enable_harp_irq(unsigned int irq)
-{
- unsigned flags;
- unsigned maskReg;
- unsigned mask;
- int pri;
-
- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
- return;
-
- pri = 15 - irq;
-
- if (pri < 8) {
- maskReg = EPLD_INTMASK0;
- } else {
- maskReg = EPLD_INTMASK1;
- pri -= 8;
- }
-
- local_irq_save(flags);
- mask = ctrl_inl(maskReg);
-
-
- mask |= (1 << pri);
-
-#if defined(INVERT_INTMASK_WRITES)
- mask ^= 0xff;
-#endif
- ctrl_outl(mask, maskReg);
-
- local_irq_restore(flags);
-}
-
-/* This functions sets the desired irq handler to be an overdrive type */
-static void __init make_harp_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
- irq_desc[irq].chip = &harp_irq_type;
- disable_harp_irq(irq);
-}
-
-static void mask_and_ack_harp(unsigned int irq)
-{
- disable_harp_irq(irq);
-}
-
-static void end_harp_irq(unsigned int irq)
-{
- enable_harp_irq(irq);
-}
-
-void __init init_harp_irq(void)
-{
- int i;
-
-#if !defined(INVERT_INTMASK_WRITES)
- // On the harp these are set to enable an interrupt
- ctrl_outl(0x00, EPLD_INTMASK0);
- ctrl_outl(0x00, EPLD_INTMASK1);
-#else
- // On the Overdrive the data is inverted before being stored in the reg
- ctrl_outl(0xff, EPLD_INTMASK0);
- ctrl_outl(0xff, EPLD_INTMASK1);
-#endif
-
- for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
- make_harp_irq(i);
- }
-}
diff --git a/arch/sh/boards/harp/led.c b/arch/sh/boards/harp/led.c
deleted file mode 100644
index aeb7b392b190..000000000000
--- a/arch/sh/boards/harp/led.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * linux/arch/sh/stboards/led.c
- *
- * Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * This file contains ST40STB1 HARP and compatible code.
- */
-
-#include <asm/io.h>
-#include <asm/harp/harp.h>
-
-/* Harp: Flash LD10 (front pannel) connected to EPLD (IC8) */
-/* Overdrive: Flash LD1 (front panel) connected to EPLD (IC4) */
-/* Works for HARP and overdrive */
-static void mach_led(int position, int value)
-{
- if (value) {
- ctrl_outl(EPLD_LED_ON, EPLD_LED);
- } else {
- ctrl_outl(EPLD_LED_OFF, EPLD_LED);
- }
-}
-
-#ifdef CONFIG_HEARTBEAT
-
-#include <linux/sched.h>
-
-/* acts like an actual heart beat -- ie thump-thump-pause... */
-void heartbeat_harp(void)
-{
- static unsigned cnt = 0, period = 0, dist = 0;
-
- if (cnt == 0 || cnt == dist)
- mach_led( -1, 1);
- else if (cnt == 7 || cnt == dist+7)
- mach_led( -1, 0);
-
- if (++cnt > period) {
- cnt = 0;
- /* The hyperbolic function below modifies the heartbeat period
- * length in dependency of the current (5min) load. It goes
- * through the points f(0)=126, f(1)=86, f(5)=51,
- * f(inf)->30. */
- period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
- dist = period / 4;
- }
-}
-#endif
diff --git a/arch/sh/boards/harp/mach.c b/arch/sh/boards/harp/mach.c
deleted file mode 100644
index a946dd1674ca..000000000000
--- a/arch/sh/boards/harp/mach.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * linux/arch/sh/boards/harp/mach.c
- *
- * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the STMicroelectronics STB1 HARP and compatible boards
- */
-
-#include <linux/init.h>
-
-#include <asm/machvec.h>
-#include <asm/rtc.h>
-#include <asm/machvec_init.h>
-#include <asm/hd64465/io.h>
-#include <asm/hd64465/hd64465.h>
-
-void setup_harp(void);
-void init_harp_irq(void);
-void heartbeat_harp(void);
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_harp __initmv = {
- .mv_nr_irqs = 89 + HD64465_IRQ_NUM,
-
- .mv_inb = hd64465_inb,
- .mv_inw = hd64465_inw,
- .mv_inl = hd64465_inl,
- .mv_outb = hd64465_outb,
- .mv_outw = hd64465_outw,
- .mv_outl = hd64465_outl,
-
- .mv_inb_p = hd64465_inb_p,
- .mv_inw_p = hd64465_inw,
- .mv_inl_p = hd64465_inl,
- .mv_outb_p = hd64465_outb_p,
- .mv_outw_p = hd64465_outw,
- .mv_outl_p = hd64465_outl,
-
- .mv_insb = hd64465_insb,
- .mv_insw = hd64465_insw,
- .mv_insl = hd64465_insl,
- .mv_outsb = hd64465_outsb,
- .mv_outsw = hd64465_outsw,
- .mv_outsl = hd64465_outsl,
-
- .mv_isa_port2addr = hd64465_isa_port2addr,
-
-#ifdef CONFIG_PCI
- .mv_init_irq = init_harp_irq,
-#endif
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_harp,
-#endif
-};
-
-ALIAS_MV(harp)
diff --git a/arch/sh/boards/harp/pcidma.c b/arch/sh/boards/harp/pcidma.c
deleted file mode 100644
index 475311390fd6..000000000000
--- a/arch/sh/boards/harp/pcidma.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Dynamic DMA mapping support.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t * dma_handle)
-{
- void *ret;
- int gfp = GFP_ATOMIC;
-
- ret = (void *) __get_free_pages(gfp, get_order(size));
-
- if (ret != NULL) {
- /* Is it neccessary to do the memset? */
- memset(ret, 0, size);
- *dma_handle = virt_to_bus(ret);
- }
- /* We must flush the cache before we pass it on to the device */
- flush_cache_all();
- return P2SEGADDR(ret);
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- unsigned long p1addr=P1SEGADDR((unsigned long)vaddr);
-
- free_pages(p1addr, get_order(size));
-}
diff --git a/arch/sh/boards/harp/setup.c b/arch/sh/boards/harp/setup.c
deleted file mode 100644
index 886e450ab63e..000000000000
--- a/arch/sh/boards/harp/setup.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * arch/sh/stboard/setup.c
- *
- * Copyright (C) 2001 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * STMicroelectronics ST40STB1 HARP and compatible support.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-#include <asm/harp/harp.h>
-
-const char *get_system_type(void)
-{
- return "STB1 Harp";
-}
-
-/*
- * Initialize the board
- */
-int __init platform_setup(void)
-{
-#ifdef CONFIG_SH_STB1_HARP
- unsigned long ic8_version, ic36_version;
-
- ic8_version = ctrl_inl(EPLD_REVID2);
- ic36_version = ctrl_inl(EPLD_REVID1);
-
- printk("STMicroelectronics STB1 HARP initialisaton\n");
- printk("EPLD versions: IC8: %d.%02d, IC36: %d.%02d\n",
- (ic8_version >> 4) & 0xf, ic8_version & 0xf,
- (ic36_version >> 4) & 0xf, ic36_version & 0xf);
-#elif defined(CONFIG_SH_STB1_OVERDRIVE)
- unsigned long version;
-
- version = ctrl_inl(EPLD_REVID);
-
- printk("STMicroelectronics STB1 Overdrive initialisaton\n");
- printk("EPLD version: %d.%02d\n",
- (version >> 4) & 0xf, version & 0xf);
-#else
-#error Undefined machine
-#endif
-
- /* Currently all STB1 chips have problems with the sleep instruction,
- * so disable it here.
- */
- disable_hlt();
-
- return 0;
-}
-
-/*
- * pcibios_map_platform_irq
- *
- * This is board specific and returns the IRQ for a given PCI device.
- * It is used by the PCI code (arch/sh/kernel/st40_pci*)
- *
- */
-
-#define HARP_PCI_IRQ 1
-#define HARP_BRIDGE_IRQ 2
-#define OVERDRIVE_SLOT0_IRQ 0
-
-
-int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- switch (slot) {
-#ifdef CONFIG_SH_STB1_HARP
- case 2: /*This is the PCI slot on the */
- return HARP_PCI_IRQ;
- case 1: /* this is the bridge */
- return HARP_BRIDGE_IRQ;
-#elif defined(CONFIG_SH_STB1_OVERDRIVE)
- case 1:
- case 2:
- case 3:
- return slot - 1;
-#else
-#error Unknown board
-#endif
- default:
- return -1;
- }
-}
-
diff --git a/arch/sh/boards/hp6xx/Makefile b/arch/sh/boards/hp6xx/Makefile
index 927fe0aa5dfa..ff1b7f5b4e91 100644
--- a/arch/sh/boards/hp6xx/Makefile
+++ b/arch/sh/boards/hp6xx/Makefile
@@ -2,5 +2,6 @@
# Makefile for the HP6xx specific parts of the kernel
#
-obj-y := mach.o setup.o
-
+obj-y := setup.o
+obj-$(CONFIG_PM) += pm.o pm_wakeup.o
+obj-$(CONFIG_APM) += hp6xx_apm.o
diff --git a/arch/sh/boards/hp6xx/hp6xx_apm.c b/arch/sh/boards/hp6xx/hp6xx_apm.c
new file mode 100644
index 000000000000..219179114f0f
--- /dev/null
+++ b/arch/sh/boards/hp6xx/hp6xx_apm.c
@@ -0,0 +1,122 @@
+/*
+ * bios-less APM driver for hp680
+ *
+ * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+#include <linux/module.h>
+#include <linux/apm_bios.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/apm.h>
+#include <asm/adc.h>
+#include <asm/hp6xx/hp6xx.h>
+
+#define SH7709_PGDR 0xa400012c
+
+#define APM_CRITICAL 10
+#define APM_LOW 30
+
+#define HP680_BATTERY_MAX 875
+#define HP680_BATTERY_MIN 600
+#define HP680_BATTERY_AC_ON 900
+
+#define MODNAME "hp6x0_apm"
+
+static int hp6x0_apm_get_info(char *buf, char **start, off_t fpos, int length)
+{
+ u8 pgdr;
+ char *p;
+ int battery_status;
+ int battery_flag;
+ int ac_line_status;
+ int time_units = APM_BATTERY_LIFE_UNKNOWN;
+
+ int battery = adc_single(ADC_CHANNEL_BATTERY);
+ int backup = adc_single(ADC_CHANNEL_BACKUP);
+ int charging = adc_single(ADC_CHANNEL_CHARGE);
+ int percentage;
+
+ percentage = 100 * (battery - HP680_BATTERY_MIN) /
+ (HP680_BATTERY_MAX - HP680_BATTERY_MIN);
+
+ ac_line_status = (battery > HP680_BATTERY_AC_ON) ?
+ APM_AC_ONLINE : APM_AC_OFFLINE;
+
+ p = buf;
+
+ pgdr = ctrl_inb(SH7709_PGDR);
+ if (pgdr & PGDR_MAIN_BATTERY_OUT) {
+ battery_status = APM_BATTERY_STATUS_NOT_PRESENT;
+ battery_flag = 0x80;
+ percentage = -1;
+ } else if (charging < 8 ) {
+ battery_status = APM_BATTERY_STATUS_CHARGING;
+ battery_flag = 0x08;
+ ac_line_status = 0xff;
+ } else if (percentage <= APM_CRITICAL) {
+ battery_status = APM_BATTERY_STATUS_CRITICAL;
+ battery_flag = 0x04;
+ } else if (percentage <= APM_LOW) {
+ battery_status = APM_BATTERY_STATUS_LOW;
+ battery_flag = 0x02;
+ } else {
+ battery_status = APM_BATTERY_STATUS_HIGH;
+ battery_flag = 0x01;
+ }
+
+ p += sprintf(p, "1.0 1.2 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n",
+ APM_32_BIT_SUPPORT,
+ ac_line_status,
+ battery_status,
+ battery_flag,
+ percentage,
+ time_units,
+ "min");
+ p += sprintf(p, "bat=%d backup=%d charge=%d\n",
+ battery, backup, charging);
+
+ return p - buf;
+}
+
+static irqreturn_t hp6x0_apm_interrupt(int irq, void *dev)
+{
+ if (!apm_suspended)
+ apm_queue_event(APM_USER_SUSPEND);
+
+ return IRQ_HANDLED;
+}
+
+static int __init hp6x0_apm_init(void)
+{
+ int ret;
+
+ ret = request_irq(HP680_BTN_IRQ, hp6x0_apm_interrupt,
+ IRQF_DISABLED, MODNAME, 0);
+ if (unlikely(ret < 0)) {
+ printk(KERN_ERR MODNAME ": IRQ %d request failed\n",
+ HP680_BTN_IRQ);
+ return ret;
+ }
+
+ apm_get_info = hp6x0_apm_get_info;
+
+ return ret;
+}
+
+static void __exit hp6x0_apm_exit(void)
+{
+ free_irq(HP680_BTN_IRQ, 0);
+ apm_get_info = 0;
+}
+
+module_init(hp6x0_apm_init);
+module_exit(hp6x0_apm_exit);
+
+MODULE_AUTHOR("Adriy Skulysh");
+MODULE_DESCRIPTION("hp6xx Advanced Power Management");
+MODULE_LICENSE("GPL");
diff --git a/arch/sh/boards/hp6xx/pm.c b/arch/sh/boards/hp6xx/pm.c
new file mode 100644
index 000000000000..83d327212064
--- /dev/null
+++ b/arch/sh/boards/hp6xx/pm.c
@@ -0,0 +1,87 @@
+/*
+ * hp6x0 Power Management Routines
+ *
+ * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <asm/hd64461.h>
+#include <asm/hp6xx/hp6xx.h>
+#include <asm/cpu/dac.h>
+#include <asm/pm.h>
+
+#define STBCR 0xffffff82
+#define STBCR2 0xffffff88
+
+static int hp6x0_pm_enter(suspend_state_t state)
+{
+ u8 stbcr, stbcr2;
+#ifdef CONFIG_HD64461_ENABLER
+ u8 scr;
+ u16 hd64461_stbcr;
+#endif
+
+ if (state != PM_SUSPEND_MEM)
+ return -EINVAL;
+
+#ifdef CONFIG_HD64461_ENABLER
+ outb(0, HD64461_PCC1CSCIER);
+
+ scr = inb(HD64461_PCC1SCR);
+ scr |= HD64461_PCCSCR_VCC1;
+ outb(scr, HD64461_PCC1SCR);
+
+ hd64461_stbcr = inw(HD64461_STBCR);
+ hd64461_stbcr |= HD64461_STBCR_SPC1ST;
+ outw(hd64461_stbcr, HD64461_STBCR);
+#endif
+
+ ctrl_outb(0x1f, DACR);
+
+ stbcr = ctrl_inb(STBCR);
+ ctrl_outb(0x01, STBCR);
+
+ stbcr2 = ctrl_inb(STBCR2);
+ ctrl_outb(0x7f , STBCR2);
+
+ outw(0xf07f, HD64461_SCPUCR);
+
+ pm_enter();
+
+ outw(0, HD64461_SCPUCR);
+ ctrl_outb(stbcr, STBCR);
+ ctrl_outb(stbcr2, STBCR2);
+
+#ifdef CONFIG_HD64461_ENABLER
+ hd64461_stbcr = inw(HD64461_STBCR);
+ hd64461_stbcr &= ~HD64461_STBCR_SPC1ST;
+ outw(hd64461_stbcr, HD64461_STBCR);
+
+ outb(0x4c, HD64461_PCC1CSCIER);
+ outb(0x00, HD64461_PCC1CSCR);
+#endif
+
+ return 0;
+}
+
+/*
+ * Set to PM_DISK_FIRMWARE so we can quickly veto suspend-to-disk.
+ */
+static struct pm_ops hp6x0_pm_ops = {
+ .pm_disk_mode = PM_DISK_FIRMWARE,
+ .enter = hp6x0_pm_enter,
+};
+
+static int __init hp6x0_pm_init(void)
+{
+ pm_set_ops(&hp6x0_pm_ops);
+ return 0;
+}
+
+late_initcall(hp6x0_pm_init);
diff --git a/arch/sh/boards/hp6xx/pm_wakeup.S b/arch/sh/boards/hp6xx/pm_wakeup.S
new file mode 100644
index 000000000000..45e9bf0b9115
--- /dev/null
+++ b/arch/sh/boards/hp6xx/pm_wakeup.S
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.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/linkage.h>
+#include <asm/cpu/mmu_context.h>
+
+#define k0 r0
+#define k1 r1
+#define k2 r2
+#define k3 r3
+#define k4 r4
+
+/*
+ * Kernel mode register usage:
+ * k0 scratch
+ * k1 scratch
+ * k2 scratch (Exception code)
+ * k3 scratch (Return address)
+ * k4 scratch
+ * k5 reserved
+ * k6 Global Interrupt Mask (0--15 << 4)
+ * k7 CURRENT_THREAD_INFO (pointer to current thread info)
+ */
+
+ENTRY(wakeup_start)
+! clear STBY bit
+ mov #-126, k2
+ and #127, k0
+ mov.b k0, @k2
+! enable refresh
+ mov.l 5f, k1
+ mov.w 6f, k0
+ mov.w k0, @k1
+! jump to handler
+ mov.l 2f, k2
+ mov.l 3f, k3
+ mov.l @k2, k2
+
+ mov.l 4f, k1
+ jmp @k1
+ nop
+
+ .align 2
+1: .long EXPEVT
+2: .long INTEVT
+3: .long ret_from_irq
+4: .long handle_exception
+5: .long 0xffffff68
+6: .word 0x0524
+
+ENTRY(wakeup_end)
+ nop
diff --git a/arch/sh/boards/hp6xx/setup.c b/arch/sh/boards/hp6xx/setup.c
index 71f315663cc9..2d3a5b4faf58 100644
--- a/arch/sh/boards/hp6xx/setup.c
+++ b/arch/sh/boards/hp6xx/setup.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/boards/hp6xx/hp680/setup.c
+ * linux/arch/sh/boards/hp6xx/setup.c
*
* Copyright (C) 2002 Andriy Skulysh
*
@@ -8,22 +8,22 @@
*
* Setup code for an HP680 (internal peripherials only)
*/
-
+#include <linux/types.h>
#include <linux/init.h>
-#include <asm/io.h>
#include <asm/hd64461.h>
+#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/hp6xx/hp6xx.h>
#include <asm/cpu/dac.h>
-const char *get_system_type(void)
-{
- return "HP6xx";
-}
+#define SCPCR 0xa4000116
+#define SCPDR 0xa4000136
-int __init platform_setup(void)
+static void __init hp6xx_setup(char **cmdline_p)
{
u8 v8;
u16 v;
+
v = inw(HD64461_STBCR);
v |= HD64461_STBCR_SURTST | HD64461_STBCR_SIRST |
HD64461_STBCR_STM1ST | HD64461_STBCR_STM0ST |
@@ -50,5 +50,51 @@ int __init platform_setup(void)
v8 &= ~DACR_DAE;
ctrl_outb(v8,DACR);
- return 0;
+ v8 = ctrl_inb(SCPDR);
+ v8 |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
+ v8 &= ~SCPDR_TS_SCAN_ENABLE;
+ ctrl_outb(v8, SCPDR);
+
+ v = ctrl_inw(SCPCR);
+ v &= ~SCPCR_TS_MASK;
+ v |= SCPCR_TS_ENABLE;
+ ctrl_outw(v, SCPCR);
}
+
+/*
+ * XXX: This is stupid, we should have a generic machine vector for the cchips
+ * and just wrap the platform setup code in to this, as it's the only thing
+ * that ends up being different.
+ */
+struct sh_machine_vector mv_hp6xx __initmv = {
+ .mv_name = "hp6xx",
+ .mv_setup = hp6xx_setup,
+ .mv_nr_irqs = HD64461_IRQBASE + HD64461_IRQ_NUM,
+
+ .mv_inb = hd64461_inb,
+ .mv_inw = hd64461_inw,
+ .mv_inl = hd64461_inl,
+ .mv_outb = hd64461_outb,
+ .mv_outw = hd64461_outw,
+ .mv_outl = hd64461_outl,
+
+ .mv_inb_p = hd64461_inb_p,
+ .mv_inw_p = hd64461_inw,
+ .mv_inl_p = hd64461_inl,
+ .mv_outb_p = hd64461_outb_p,
+ .mv_outw_p = hd64461_outw,
+ .mv_outl_p = hd64461_outl,
+
+ .mv_insb = hd64461_insb,
+ .mv_insw = hd64461_insw,
+ .mv_insl = hd64461_insl,
+ .mv_outsb = hd64461_outsb,
+ .mv_outsw = hd64461_outsw,
+ .mv_outsl = hd64461_outsl,
+
+ .mv_readw = hd64461_readw,
+ .mv_writew = hd64461_writew,
+
+ .mv_irq_demux = hd64461_irq_demux,
+};
+ALIAS_MV(hp6xx)
diff --git a/arch/sh/boards/landisk/Makefile b/arch/sh/boards/landisk/Makefile
new file mode 100644
index 000000000000..89e4beb2ad47
--- /dev/null
+++ b/arch/sh/boards/landisk/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for I-O DATA DEVICE, INC. "LANDISK Series"
+#
+
+obj-y := setup.o io.o irq.o rtc.o landisk_pwb.o
diff --git a/arch/sh/boards/landisk/io.c b/arch/sh/boards/landisk/io.c
new file mode 100644
index 000000000000..92498b4947d5
--- /dev/null
+++ b/arch/sh/boards/landisk/io.c
@@ -0,0 +1,250 @@
+/*
+ * arch/sh/boards/landisk/io.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for I-O Data Device, Inc. LANDISK.
+ *
+ * Initial version only to support LAN access; some
+ * placeholder code from io_landisk.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+/*
+ * modifed by kogiidena
+ * 2005.03.03
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/landisk/iodata_landisk.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+
+extern void *area5_io_base; /* Area 5 I/O Base address */
+extern void *area6_io_base; /* Area 6 I/O Base address */
+
+static inline unsigned long port2adr(unsigned int port)
+{
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ if (port == 0x3f6)
+ return ((unsigned long)area5_io_base + 0x2c);
+ else
+ return ((unsigned long)area5_io_base + PA_PIDE_OFFSET +
+ ((port - 0x1f0) << 1));
+ else if ((0x170 <= port && port < 0x178) || port == 0x376)
+ if (port == 0x376)
+ return ((unsigned long)area6_io_base + 0x2c);
+ else
+ return ((unsigned long)area6_io_base + PA_SIDE_OFFSET +
+ ((port - 0x170) << 1));
+ else
+ maybebadio((unsigned long)port);
+
+ return port;
+}
+
+/*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+u8 landisk_inb(unsigned long port)
+{
+ if (PXSEG(port))
+ return ctrl_inb(port);
+ else if (is_pci_ioaddr(port))
+ return ctrl_inb(pci_ioaddr(port));
+
+ return ctrl_inw(port2adr(port)) & 0xff;
+}
+
+u8 landisk_inb_p(unsigned long port)
+{
+ u8 v;
+
+ if (PXSEG(port))
+ v = ctrl_inb(port);
+ else if (is_pci_ioaddr(port))
+ v = ctrl_inb(pci_ioaddr(port));
+ else
+ v = ctrl_inw(port2adr(port)) & 0xff;
+
+ ctrl_delay();
+
+ return v;
+}
+
+u16 landisk_inw(unsigned long port)
+{
+ if (PXSEG(port))
+ return ctrl_inw(port);
+ else if (is_pci_ioaddr(port))
+ return ctrl_inw(pci_ioaddr(port));
+ else
+ maybebadio(port);
+
+ return 0;
+}
+
+u32 landisk_inl(unsigned long port)
+{
+ if (PXSEG(port))
+ return ctrl_inl(port);
+ else if (is_pci_ioaddr(port))
+ return ctrl_inl(pci_ioaddr(port));
+ else
+ maybebadio(port);
+
+ return 0;
+}
+
+void landisk_outb(u8 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outb(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outb(value, pci_ioaddr(port));
+ else
+ ctrl_outw(value, port2adr(port));
+}
+
+void landisk_outb_p(u8 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outb(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outb(value, pci_ioaddr(port));
+ else
+ ctrl_outw(value, port2adr(port));
+ ctrl_delay();
+}
+
+void landisk_outw(u16 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outw(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outw(value, pci_ioaddr(port));
+ else
+ maybebadio(port);
+}
+
+void landisk_outl(u32 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outl(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outl(value, pci_ioaddr(port));
+ else
+ maybebadio(port);
+}
+
+void landisk_insb(unsigned long port, void *dst, unsigned long count)
+{
+ volatile u16 *p;
+ u8 *buf = dst;
+
+ if (PXSEG(port)) {
+ while (count--)
+ *buf++ = *(volatile u8 *)port;
+ } else if (is_pci_ioaddr(port)) {
+ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+
+ while (count--)
+ *buf++ = *bp;
+ } else {
+ p = (volatile u16 *)port2adr(port);
+ while (count--)
+ *buf++ = *p & 0xff;
+ }
+}
+
+void landisk_insw(unsigned long port, void *dst, unsigned long count)
+{
+ volatile u16 *p;
+ u16 *buf = dst;
+
+ if (PXSEG(port))
+ p = (volatile u16 *)port;
+ else if (is_pci_ioaddr(port))
+ p = (volatile u16 *)pci_ioaddr(port);
+ else
+ p = (volatile u16 *)port2adr(port);
+ while (count--)
+ *buf++ = *p;
+}
+
+void landisk_insl(unsigned long port, void *dst, unsigned long count)
+{
+ u32 *buf = dst;
+
+ if (is_pci_ioaddr(port)) {
+ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+
+ while (count--)
+ *buf++ = *p;
+ } else
+ maybebadio(port);
+}
+
+void landisk_outsb(unsigned long port, const void *src, unsigned long count)
+{
+ volatile u16 *p;
+ const u8 *buf = src;
+
+ if (PXSEG(port))
+ while (count--)
+ ctrl_outb(*buf++, port);
+ else if (is_pci_ioaddr(port)) {
+ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+
+ while (count--)
+ *bp = *buf++;
+ } else {
+ p = (volatile u16 *)port2adr(port);
+ while (count--)
+ *p = *buf++;
+ }
+}
+
+void landisk_outsw(unsigned long port, const void *src, unsigned long count)
+{
+ volatile u16 *p;
+ const u16 *buf = src;
+
+ if (PXSEG(port))
+ p = (volatile u16 *)port;
+ else if (is_pci_ioaddr(port))
+ p = (volatile u16 *)pci_ioaddr(port);
+ else
+ p = (volatile u16 *)port2adr(port);
+
+ while (count--)
+ *p = *buf++;
+}
+
+void landisk_outsl(unsigned long port, const void *src, unsigned long count)
+{
+ const u32 *buf = src;
+
+ if (is_pci_ioaddr(port)) {
+ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+
+ while (count--)
+ *p = *buf++;
+ } else
+ maybebadio(port);
+}
+
+void __iomem *landisk_ioport_map(unsigned long port, unsigned int size)
+{
+ if (PXSEG(port))
+ return (void __iomem *)port;
+ else if (is_pci_ioaddr(port))
+ return (void __iomem *)pci_ioaddr(port);
+
+ return (void __iomem *)port2adr(port);
+}
diff --git a/arch/sh/boards/landisk/irq.c b/arch/sh/boards/landisk/irq.c
new file mode 100644
index 000000000000..8f2e1c68b90f
--- /dev/null
+++ b/arch/sh/boards/landisk/irq.c
@@ -0,0 +1,97 @@
+/*
+ * arch/sh/boards/landisk/irq.c
+ *
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for I-O Data Device, Inc. LANDISK.
+ *
+ * Initial version only to support LAN access; some
+ * placeholder code from io_landisk.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+/*
+ * modified by kogiidena
+ * 2005.03.03
+ */
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/landisk/iodata_landisk.h>
+
+static void enable_landisk_irq(unsigned int irq);
+static void disable_landisk_irq(unsigned int irq);
+
+/* shutdown is same as "disable" */
+#define shutdown_landisk_irq disable_landisk_irq
+
+static void ack_landisk_irq(unsigned int irq);
+static void end_landisk_irq(unsigned int irq);
+
+static unsigned int startup_landisk_irq(unsigned int irq)
+{
+ enable_landisk_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static void disable_landisk_irq(unsigned int irq)
+{
+ unsigned char val;
+ unsigned char mask = 0xff ^ (0x01 << (irq - 5));
+
+ /* Set the priority in IPR to 0 */
+ val = ctrl_inb(PA_IMASK);
+ val &= mask;
+ ctrl_outb(val, PA_IMASK);
+}
+
+static void enable_landisk_irq(unsigned int irq)
+{
+ unsigned char val;
+ unsigned char value = (0x01 << (irq - 5));
+
+ /* Set priority in IPR back to original value */
+ val = ctrl_inb(PA_IMASK);
+ val |= value;
+ ctrl_outb(val, PA_IMASK);
+}
+
+static void ack_landisk_irq(unsigned int irq)
+{
+ disable_landisk_irq(irq);
+}
+
+static void end_landisk_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ enable_landisk_irq(irq);
+}
+
+static struct hw_interrupt_type landisk_irq_type = {
+ .typename = "LANDISK IRQ",
+ .startup = startup_landisk_irq,
+ .shutdown = shutdown_landisk_irq,
+ .enable = enable_landisk_irq,
+ .disable = disable_landisk_irq,
+ .ack = ack_landisk_irq,
+ .end = end_landisk_irq
+};
+
+static void make_landisk_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].chip = &landisk_irq_type;
+ disable_landisk_irq(irq);
+}
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_landisk_IRQ(void)
+{
+ int i;
+
+ for (i = 5; i < 14; i++)
+ make_landisk_irq(i);
+}
diff --git a/arch/sh/boards/landisk/landisk_pwb.c b/arch/sh/boards/landisk/landisk_pwb.c
new file mode 100644
index 000000000000..e62524978160
--- /dev/null
+++ b/arch/sh/boards/landisk/landisk_pwb.c
@@ -0,0 +1,346 @@
+/*
+ * arch/sh/boards/landisk/landisk_pwb.c -- driver for the Power control switch.
+ *
+ * This driver will also support the I-O DATA Device, Inc. LANDISK Board.
+ *
+ * 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.
+ *
+ * Copylight (C) 2002 Atom Create Engineering Co., Ltd.
+ *
+ * LED control drive function added by kogiidena
+ */
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/major.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/landisk/iodata_landisk.h>
+
+#define SHUTDOWN_BTN_MINOR 1 /* Shutdown button device minor no. */
+#define LED_MINOR 21 /* LED minor no. */
+#define BTN_MINOR 22 /* BUTTON minor no. */
+#define GIO_MINOR 40 /* GIO minor no. */
+
+static int openCnt;
+static int openCntLED;
+static int openCntGio;
+static int openCntBtn;
+static int landisk_btn;
+static int landisk_btnctrlpid;
+/*
+ * Functions prototypes
+ */
+
+static int gio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
+static int swdrv_open(struct inode *inode, struct file *filp)
+{
+ int minor;
+
+ minor = MINOR(inode->i_rdev);
+ filp->private_data = (void *)minor;
+
+ if (minor == SHUTDOWN_BTN_MINOR) {
+ if (openCnt > 0) {
+ return -EALREADY;
+ } else {
+ openCnt++;
+ return 0;
+ }
+ } else if (minor == LED_MINOR) {
+ if (openCntLED > 0) {
+ return -EALREADY;
+ } else {
+ openCntLED++;
+ return 0;
+ }
+ } else if (minor == BTN_MINOR) {
+ if (openCntBtn > 0) {
+ return -EALREADY;
+ } else {
+ openCntBtn++;
+ return 0;
+ }
+ } else if (minor == GIO_MINOR) {
+ if (openCntGio > 0) {
+ return -EALREADY;
+ } else {
+ openCntGio++;
+ return 0;
+ }
+ }
+ return -ENOENT;
+
+}
+
+static int swdrv_close(struct inode *inode, struct file *filp)
+{
+ int minor;
+
+ minor = MINOR(inode->i_rdev);
+ if (minor == SHUTDOWN_BTN_MINOR) {
+ openCnt--;
+ } else if (minor == LED_MINOR) {
+ openCntLED--;
+ } else if (minor == BTN_MINOR) {
+ openCntBtn--;
+ } else if (minor == GIO_MINOR) {
+ openCntGio--;
+ }
+ return 0;
+}
+
+static int swdrv_read(struct file *filp, char *buff, size_t count,
+ loff_t * ppos)
+{
+ int minor;
+ minor = (int)(filp->private_data);
+
+ if (!access_ok(VERIFY_WRITE, (void *)buff, count))
+ return -EFAULT;
+
+ if (minor == SHUTDOWN_BTN_MINOR) {
+ if (landisk_btn & 0x10) {
+ put_user(1, buff);
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ return 0;
+}
+
+static int swdrv_write(struct file *filp, const char *buff, size_t count,
+ loff_t * ppos)
+{
+ int minor;
+ minor = (int)(filp->private_data);
+
+ if (minor == SHUTDOWN_BTN_MINOR) {
+ return count;
+ }
+ return count;
+}
+
+static irqreturn_t sw_interrupt(int irq, void *dev_id)
+{
+ landisk_btn = (0x0ff & (~ctrl_inb(PA_STATUS)));
+ disable_irq(IRQ_BUTTON);
+ disable_irq(IRQ_POWER);
+ ctrl_outb(0x00, PA_PWRINT_CLR);
+
+ if (landisk_btnctrlpid != 0) {
+ kill_proc(landisk_btnctrlpid, SIGUSR1, 1);
+ landisk_btnctrlpid = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct file_operations swdrv_fops = {
+ .read = swdrv_read, /* read */
+ .write = swdrv_write, /* write */
+ .open = swdrv_open, /* open */
+ .release = swdrv_close, /* release */
+ .ioctl = gio_ioctl, /* ioctl */
+
+};
+
+static char banner[] __initdata =
+ KERN_INFO "LANDISK and USL-5P Button, LED and GIO driver initialized\n";
+
+int __init swdrv_init(void)
+{
+ int error;
+
+ printk("%s", banner);
+
+ openCnt = 0;
+ openCntLED = 0;
+ openCntBtn = 0;
+ openCntGio = 0;
+ landisk_btn = 0;
+ landisk_btnctrlpid = 0;
+
+ if ((error = register_chrdev(SHUTDOWN_BTN_MAJOR, "swdrv", &swdrv_fops))) {
+ printk(KERN_ERR
+ "Button, LED and GIO driver:Couldn't register driver, error=%d\n",
+ error);
+ return 1;
+ }
+
+ if (request_irq(IRQ_POWER, sw_interrupt, 0, "SHUTDOWNSWITCH", NULL)) {
+ printk(KERN_ERR "Unable to get IRQ 11.\n");
+ return 1;
+ }
+ if (request_irq(IRQ_BUTTON, sw_interrupt, 0, "USL-5P BUTTON", NULL)) {
+ printk(KERN_ERR "Unable to get IRQ 12.\n");
+ return 1;
+ }
+ ctrl_outb(0x00, PA_PWRINT_CLR);
+
+ return 0;
+}
+
+module_init(swdrv_init);
+
+/*
+ * gio driver
+ *
+ */
+
+#include <asm/landisk/gio.h>
+
+static int gio_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ int minor;
+ unsigned int data, mask;
+ static unsigned int addr = 0;
+
+ minor = (int)(filp->private_data);
+
+ /* access control */
+ if (minor == GIO_MINOR) {
+ ;
+ } else if (minor == LED_MINOR) {
+ if (((cmd & 0x0ff) >= 9) && ((cmd & 0x0ff) < 20)) {
+ ;
+ } else {
+ return -EINVAL;
+ }
+ } else if (minor == BTN_MINOR) {
+ if (((cmd & 0x0ff) >= 20) && ((cmd & 0x0ff) < 30)) {
+ ;
+ } else {
+ return -EINVAL;
+ }
+ } else {
+ return -EINVAL;
+ }
+
+ if (cmd & 0x01) { /* write */
+ if (copy_from_user(&data, (int *)arg, sizeof(int))) {
+ return -EFAULT;
+ }
+ }
+
+ switch (cmd) {
+ case GIODRV_IOCSGIOSETADDR: /* addres set */
+ addr = data;
+ break;
+
+ case GIODRV_IOCSGIODATA1: /* write byte */
+ ctrl_outb((unsigned char)(0x0ff & data), addr);
+ break;
+
+ case GIODRV_IOCSGIODATA2: /* write word */
+ if (addr & 0x01) {
+ return -EFAULT;
+ }
+ ctrl_outw((unsigned short int)(0x0ffff & data), addr);
+ break;
+
+ case GIODRV_IOCSGIODATA4: /* write long */
+ if (addr & 0x03) {
+ return -EFAULT;
+ }
+ ctrl_outl(data, addr);
+ break;
+
+ case GIODRV_IOCGGIODATA1: /* read byte */
+ data = ctrl_inb(addr);
+ break;
+
+ case GIODRV_IOCGGIODATA2: /* read word */
+ if (addr & 0x01) {
+ return -EFAULT;
+ }
+ data = ctrl_inw(addr);
+ break;
+
+ case GIODRV_IOCGGIODATA4: /* read long */
+ if (addr & 0x03) {
+ return -EFAULT;
+ }
+ data = ctrl_inl(addr);
+ break;
+ case GIODRV_IOCSGIO_LED: /* write */
+ mask = ((data & 0x00ffffff) << 8)
+ | ((data & 0x0000ffff) << 16)
+ | ((data & 0x000000ff) << 24);
+ landisk_ledparam = data & (~mask);
+ if (landisk_arch == 0) { /* arch == landisk */
+ landisk_ledparam &= 0x03030303;
+ mask = (~(landisk_ledparam >> 22)) & 0x000c;
+ landisk_ledparam |= mask;
+ } else { /* arch == usl-5p */
+ mask = (landisk_ledparam >> 24) & 0x0001;
+ landisk_ledparam |= mask;
+ landisk_ledparam &= 0x007f7f7f;
+ }
+ landisk_ledparam |= 0x80;
+ break;
+ case GIODRV_IOCGGIO_LED: /* read */
+ data = landisk_ledparam;
+ if (landisk_arch == 0) { /* arch == landisk */
+ data &= 0x03030303;
+ } else { /* arch == usl-5p */
+ ;
+ }
+ data &= (~0x080);
+ break;
+ case GIODRV_IOCSGIO_BUZZER: /* write */
+ landisk_buzzerparam = data;
+ landisk_ledparam |= 0x80;
+ break;
+ case GIODRV_IOCGGIO_LANDISK: /* read */
+ data = landisk_arch & 0x01;
+ break;
+ case GIODRV_IOCGGIO_BTN: /* read */
+ data = (0x0ff & ctrl_inb(PA_PWRINT_CLR));
+ data <<= 8;
+ data |= (0x0ff & ctrl_inb(PA_IMASK));
+ data <<= 8;
+ data |= (0x0ff & landisk_btn);
+ data <<= 8;
+ data |= (0x0ff & (~ctrl_inb(PA_STATUS)));
+ break;
+ case GIODRV_IOCSGIO_BTNPID: /* write */
+ landisk_btnctrlpid = data;
+ landisk_btn = 0;
+ if (irq_desc[IRQ_BUTTON].depth) {
+ enable_irq(IRQ_BUTTON);
+ }
+ if (irq_desc[IRQ_POWER].depth) {
+ enable_irq(IRQ_POWER);
+ }
+ break;
+ case GIODRV_IOCGGIO_BTNPID: /* read */
+ data = landisk_btnctrlpid;
+ break;
+ default:
+ return -EFAULT;
+ break;
+ }
+
+ if ((cmd & 0x01) == 0) { /* read */
+ if (copy_to_user((int *)arg, &data, sizeof(int))) {
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
diff --git a/arch/sh/boards/landisk/rtc.c b/arch/sh/boards/landisk/rtc.c
new file mode 100644
index 000000000000..0a9a2a2ad05b
--- /dev/null
+++ b/arch/sh/boards/landisk/rtc.c
@@ -0,0 +1,91 @@
+/*
+ * arch/sh/boards/landisk/rtc.c -- RTC support
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+ */
+/*
+ * modifed by kogiidena
+ * 2005.09.16
+ */
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/time.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/bcd.h>
+#include <asm/rtc.h>
+
+extern spinlock_t rtc_lock;
+
+extern void
+rs5c313_set_cmos_time(unsigned int BCD_yr, unsigned int BCD_mon,
+ unsigned int BCD_day, unsigned int BCD_hr,
+ unsigned int BCD_min, unsigned int BCD_sec);
+
+extern unsigned long
+rs5c313_get_cmos_time(unsigned int *BCD_yr, unsigned int *BCD_mon,
+ unsigned int *BCD_day, unsigned int *BCD_hr,
+ unsigned int *BCD_min, unsigned int *BCD_sec);
+
+void landisk_rtc_gettimeofday(struct timespec *tv)
+{
+ unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+ tv->tv_sec = rs5c313_get_cmos_time
+ (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
+ tv->tv_nsec = 0;
+ spin_unlock_irqrestore(&rtc_lock, flags);
+}
+
+int landisk_rtc_settimeofday(const time_t secs)
+{
+ int retval = 0;
+ int real_seconds, real_minutes, cmos_minutes;
+ unsigned long flags;
+ unsigned long nowtime = secs;
+ unsigned int BCD_yr, BCD_mon, BCD_day, BCD_hr, BCD_min, BCD_sec;
+
+ spin_lock_irqsave(&rtc_lock, flags);
+
+ rs5c313_get_cmos_time
+ (&BCD_yr, &BCD_mon, &BCD_day, &BCD_hr, &BCD_min, &BCD_sec);
+ cmos_minutes = BCD_min;
+ BCD_TO_BIN(cmos_minutes);
+
+ /*
+ * since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 15 minutes
+ */
+ real_seconds = nowtime % 60;
+ real_minutes = nowtime / 60;
+ if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
+ real_minutes += 30; /* correct for half hour time zone */
+ real_minutes %= 60;
+
+ if (abs(real_minutes - cmos_minutes) < 30) {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ rs5c313_set_cmos_time(BCD_yr, BCD_mon, BCD_day, BCD_hr,
+ real_minutes, real_seconds);
+ } else {
+ printk(KERN_WARNING
+ "set_rtc_time: can't update from %d to %d\n",
+ cmos_minutes, real_minutes);
+ retval = -1;
+ }
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+ return retval;
+}
+
+void landisk_time_init(void)
+{
+ rtc_sh_get_time = landisk_rtc_gettimeofday;
+ rtc_sh_set_time = landisk_rtc_settimeofday;
+}
diff --git a/arch/sh/boards/landisk/setup.c b/arch/sh/boards/landisk/setup.c
new file mode 100644
index 000000000000..122d69962637
--- /dev/null
+++ b/arch/sh/boards/landisk/setup.c
@@ -0,0 +1,176 @@
+/*
+ * arch/sh/boards/landisk/setup.c
+ *
+ * Copyright (C) 2000 Kazumoto Kojima
+ * Copyright (C) 2002 Paul Mundt
+ *
+ * I-O DATA Device, Inc. LANDISK Support.
+ *
+ * Modified for LANDISK by
+ * Atom Create Engineering Co., Ltd. 2002.
+ *
+ * modifed by kogiidena
+ * 2005.09.16
+ *
+ * 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/init.h>
+#include <linux/pm.h>
+#include <linux/mm.h>
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/landisk/iodata_landisk.h>
+#include <asm/io.h>
+
+void landisk_time_init(void);
+void init_landisk_IRQ(void);
+
+int landisk_ledparam;
+int landisk_buzzerparam;
+int landisk_arch;
+
+/* cycle the led's in the clasic knightrider/sun pattern */
+static void heartbeat_landisk(void)
+{
+ static unsigned int cnt = 0, blink = 0x00, period = 25;
+ volatile u8 *p = (volatile u8 *)PA_LED;
+ char data;
+
+ if ((landisk_ledparam & 0x080) == 0)
+ return;
+
+ cnt += 1;
+
+ if (cnt < period)
+ return;
+
+ cnt = 0;
+ blink++;
+
+ data = (blink & 0x01) ? (landisk_ledparam >> 16) : 0;
+ data |= (blink & 0x02) ? (landisk_ledparam >> 8) : 0;
+ data |= landisk_ledparam;
+
+ /* buzzer */
+ if (landisk_buzzerparam & 0x1) {
+ data |= 0x80;
+ } else {
+ data &= 0x7f;
+ }
+ *p = data;
+
+ if (((landisk_ledparam & 0x007f7f00) == 0) &&
+ (landisk_buzzerparam == 0))
+ landisk_ledparam &= (~0x0080);
+
+ landisk_buzzerparam >>= 1;
+}
+
+static void landisk_power_off(void)
+{
+ ctrl_outb(0x01, PA_SHUTDOWN);
+}
+
+static void check_usl5p(void)
+{
+ volatile u8 *p = (volatile u8 *)PA_LED;
+ u8 tmp1, tmp2;
+
+ tmp1 = *p;
+ *p = 0x40;
+ tmp2 = *p;
+ *p = tmp1;
+
+ landisk_arch = (tmp2 == 0x40);
+ if (landisk_arch == 1) {
+ /* arch == usl-5p */
+ landisk_ledparam = 0x00000380;
+ landisk_ledparam |= (tmp1 & 0x07c);
+ } else {
+ /* arch == landisk */
+ landisk_ledparam = 0x02000180;
+ landisk_ledparam |= 0x04;
+ }
+}
+
+void *area5_io_base;
+void *area6_io_base;
+
+static int __init landisk_cf_init(void)
+{
+ pgprot_t prot;
+ unsigned long paddrbase, psize;
+
+ /* open I/O area window */
+ paddrbase = virt_to_phys((void *)PA_AREA5_IO);
+ psize = PAGE_SIZE;
+ prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_IO16);
+ area5_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ if (!area5_io_base) {
+ printk("allocate_cf_area : can't open CF I/O window!\n");
+ return -ENOMEM;
+ }
+
+ paddrbase = virt_to_phys((void *)PA_AREA6_IO);
+ psize = PAGE_SIZE;
+ prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
+ area6_io_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ if (!area6_io_base) {
+ printk("allocate_cf_area : can't open HDD I/O window!\n");
+ return -ENOMEM;
+ }
+
+ printk(KERN_INFO "Allocate Area5/6 success.\n");
+
+ /* XXX : do we need attribute and common-memory area also? */
+
+ return 0;
+}
+
+static void __init landisk_setup(char **cmdline_p)
+{
+ device_initcall(landisk_cf_init);
+
+ landisk_buzzerparam = 0;
+ check_usl5p();
+
+ printk(KERN_INFO "I-O DATA DEVICE, INC. \"LANDISK Series\" support.\n");
+
+ board_time_init = landisk_time_init;
+ pm_power_off = landisk_power_off;
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_landisk __initmv = {
+ .mv_name = "LANDISK",
+ .mv_setup = landisk_setup,
+ .mv_nr_irqs = 72,
+ .mv_inb = landisk_inb,
+ .mv_inw = landisk_inw,
+ .mv_inl = landisk_inl,
+ .mv_outb = landisk_outb,
+ .mv_outw = landisk_outw,
+ .mv_outl = landisk_outl,
+ .mv_inb_p = landisk_inb_p,
+ .mv_inw_p = landisk_inw,
+ .mv_inl_p = landisk_inl,
+ .mv_outb_p = landisk_outb_p,
+ .mv_outw_p = landisk_outw,
+ .mv_outl_p = landisk_outl,
+ .mv_insb = landisk_insb,
+ .mv_insw = landisk_insw,
+ .mv_insl = landisk_insl,
+ .mv_outsb = landisk_outsb,
+ .mv_outsw = landisk_outsw,
+ .mv_outsl = landisk_outsl,
+ .mv_ioport_map = landisk_ioport_map,
+ .mv_init_irq = init_landisk_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_landisk,
+#endif
+};
+ALIAS_MV(landisk)
diff --git a/arch/sh/boards/mpc1211/led.c b/arch/sh/boards/mpc1211/led.c
index 1fe36927f691..8df1591823d6 100644
--- a/arch/sh/boards/mpc1211/led.c
+++ b/arch/sh/boards/mpc1211/led.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/led_mpc1211.c
+ * linux/arch/sh/boards/mpc1211/led.c
*
* Copyright (C) 2001 Saito.K & Jeanne
*
diff --git a/arch/sh/boards/mpc1211/rtc.c b/arch/sh/boards/mpc1211/rtc.c
index a76c655dceee..03b123a4bba4 100644
--- a/arch/sh/boards/mpc1211/rtc.c
+++ b/arch/sh/boards/mpc1211/rtc.c
@@ -130,7 +130,7 @@ int mpc1211_rtc_settimeofday(const struct timeval *tv)
void mpc1211_time_init(void)
{
- rtc_get_time = mpc1211_rtc_gettimeofday;
- rtc_set_time = mpc1211_rtc_settimeofday;
+ rtc_sh_get_time = mpc1211_rtc_gettimeofday;
+ rtc_sh_set_time = mpc1211_rtc_settimeofday;
}
diff --git a/arch/sh/boards/mpc1211/setup.c b/arch/sh/boards/mpc1211/setup.c
index 2bfb221cc35c..7c3d1d304157 100644
--- a/arch/sh/boards/mpc1211/setup.c
+++ b/arch/sh/boards/mpc1211/setup.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/board/mpc1211/setup.c
+ * linux/arch/sh/boards/mpc1211/setup.c
*
* Copyright (C) 2002 Saito.K & Jeanne, Fujii.Y
*
@@ -10,14 +10,12 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <linux/interrupt.h>
-
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/mpc1211/mpc1211.h>
#include <asm/mpc1211/pci.h>
#include <asm/mpc1211/m1543c.h>
-
/* ALI15X3 SMBus address offsets */
#define SMBHSTSTS (0 + 0x3100)
#define SMBHSTCNT (1 + 0x3100)
@@ -50,11 +48,6 @@
#define ALI15X3_STS_TERM 0x80 /* terminated by abort */
#define ALI15X3_STS_ERR 0xE0 /* all the bad error bits */
-const char *get_system_type(void)
-{
- return "Interface MPC-1211(CTP/PCI/MPC-SH02)";
-}
-
static void __init pci_write_config(unsigned long busNo,
unsigned long devNo,
unsigned long fncNo,
@@ -76,13 +69,9 @@ static void __init pci_write_config(unsigned long busNo,
static unsigned char m_irq_mask = 0xfb;
static unsigned char s_irq_mask = 0xff;
-volatile unsigned long irq_err_count;
static void disable_mpc1211_irq(unsigned int irq)
{
- unsigned long flags;
-
- save_and_cli(flags);
if( irq < 8) {
m_irq_mask |= (1 << irq);
outb(m_irq_mask,I8259_M_MR);
@@ -90,16 +79,11 @@ static void disable_mpc1211_irq(unsigned int irq)
s_irq_mask |= (1 << (irq - 8));
outb(s_irq_mask,I8259_S_MR);
}
- restore_flags(flags);
}
static void enable_mpc1211_irq(unsigned int irq)
{
- unsigned long flags;
-
- save_and_cli(flags);
-
if( irq < 8) {
m_irq_mask &= ~(1 << irq);
outb(m_irq_mask,I8259_M_MR);
@@ -107,7 +91,6 @@ static void enable_mpc1211_irq(unsigned int irq)
s_irq_mask &= ~(1 << (irq - 8));
outb(s_irq_mask,I8259_S_MR);
}
- restore_flags(flags);
}
static inline int mpc1211_irq_real(unsigned int irq)
@@ -131,14 +114,10 @@ static inline int mpc1211_irq_real(unsigned int irq)
static void mask_and_ack_mpc1211(unsigned int irq)
{
- unsigned long flags;
-
- save_and_cli(flags);
-
if(irq < 8) {
if(m_irq_mask & (1<<irq)){
if(!mpc1211_irq_real(irq)){
- irq_err_count++;
+ atomic_inc(&irq_err_count)
printk("spurious 8259A interrupt: IRQ %x\n",irq);
}
} else {
@@ -151,7 +130,7 @@ static void mask_and_ack_mpc1211(unsigned int irq)
} else {
if(s_irq_mask & (1<<(irq - 8))){
if(!mpc1211_irq_real(irq)){
- irq_err_count++;
+ atomic_inc(&irq_err_count);
printk("spurious 8259A interrupt: IRQ %x\n",irq);
}
} else {
@@ -162,7 +141,6 @@ static void mask_and_ack_mpc1211(unsigned int irq)
outb(0x60+(irq-8),I8259_S_CR); /* EOI */
outb(0x60+2,I8259_M_CR);
}
- restore_flags(flags);
}
static void end_mpc1211_irq(unsigned int irq)
@@ -219,7 +197,7 @@ int mpc1211_irq_demux(int irq)
return irq;
}
-void __init init_mpc1211_IRQ(void)
+static void __init init_mpc1211_IRQ(void)
{
int i;
/*
@@ -255,23 +233,12 @@ void __init init_mpc1211_IRQ(void)
}
}
-/*
- Initialize the board
-*/
-
-
-static void delay (void)
-{
- volatile unsigned short tmp;
- tmp = *(volatile unsigned short *) 0xa0000000;
-}
-
-static void delay1000 (void)
+static void delay1000(void)
{
int i;
for (i=0; i<1000; i++)
- delay ();
+ ctrl_delay();
}
static int put_smb_blk(unsigned char *p, int address, int command, int no)
@@ -314,26 +281,10 @@ static int put_smb_blk(unsigned char *p, int address, int command, int no)
return 0;
}
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_mpc1211 __initmv = {
- .mv_nr_irqs = 48,
- .mv_irq_demux = mpc1211_irq_demux,
- .mv_init_irq = init_mpc1211_IRQ,
-
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_mpc1211,
-#endif
-};
-
-ALIAS_MV(mpc1211)
-
/* arch/sh/boards/mpc1211/rtc.c */
void mpc1211_time_init(void);
-int __init platform_setup(void)
+static void __init mpc1211_setup(char **cmdline_p)
{
unsigned char spd_buf[128];
@@ -357,3 +308,18 @@ int __init platform_setup(void)
return 0;
}
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_mpc1211 __initmv = {
+ .mv_name = "Interface MPC-1211(CTP/PCI/MPC-SH02)",
+ .mv_setup = mpc1211_setup,
+ .mv_nr_irqs = 48,
+ .mv_irq_demux = mpc1211_irq_demux,
+ .mv_init_irq = init_mpc1211_IRQ,
+
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_mpc1211,
+#endif
+};
+ALIAS_MV(mpc1211)
diff --git a/arch/sh/boards/overdrive/Makefile b/arch/sh/boards/overdrive/Makefile
deleted file mode 100644
index 245f03baf762..000000000000
--- a/arch/sh/boards/overdrive/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-#
-# Makefile for the STMicroelectronics Overdrive specific parts of the kernel
-#
-
-obj-y := mach.o setup.o io.o irq.o led.o
-
-obj-$(CONFIG_PCI) += fpga.o galileo.o pcidma.o
-
diff --git a/arch/sh/boards/overdrive/fpga.c b/arch/sh/boards/overdrive/fpga.c
deleted file mode 100644
index 956c23901228..000000000000
--- a/arch/sh/boards/overdrive/fpga.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * This file handles programming up the Altera Flex10K that interfaces to
- * the Galileo, and does the PS/2 keyboard and mouse
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-
-
-#include <asm/overdriver/gt64111.h>
-#include <asm/overdrive/overdrive.h>
-#include <asm/overdrive/fpga.h>
-
-#define FPGA_NotConfigHigh() (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT
-#define FPGA_NotConfigLow() (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK
-
-/* I need to find out what (if any) the real delay factor here is */
-/* The delay is definately not critical */
-#define long_delay() {int i;for(i=0;i<10000;i++);}
-#define short_delay() {int i;for(i=0;i<100;i++);}
-
-static void __init program_overdrive_fpga(const unsigned char *fpgacode,
- int size)
-{
- int timeout = 0;
- int i, j;
- unsigned char b;
- static volatile unsigned char *FPGA_ControlReg =
- (volatile unsigned char *) (OVERDRIVE_CTRL);
- static volatile unsigned char *FPGA_ProgramReg =
- (volatile unsigned char *) (FPGA_DCLK_ADDRESS);
-
- printk("FPGA: Commencing FPGA Programming\n");
-
- /* The PCI reset but MUST be low when programming the FPGA !!! */
- b = (*FPGA_ControlReg) & RESET_PCI_MASK;
-
- (*FPGA_ControlReg) = b;
-
- /* Prepare FPGA to program */
-
- FPGA_NotConfigHigh();
- long_delay();
-
- FPGA_NotConfigLow();
- short_delay();
-
- while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) {
- printk("FPGA: Waiting for NotStatus to go Low ... \n");
- }
-
- FPGA_NotConfigHigh();
-
- /* Wait for FPGA "ready to be programmed" signal */
- printk("FPGA: Waiting for NotStatus to go high (FPGA ready)... \n");
-
- for (timeout = 0;
- (((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0)
- && (timeout < FPGA_TIMEOUT)); timeout++);
-
- /* Check if timeout condition occured - i.e. an error */
-
- if (timeout == FPGA_TIMEOUT) {
- printk
- ("FPGA: Failed to program - Timeout waiting for notSTATUS to go high\n");
- return;
- }
-
- printk("FPGA: Copying data to FPGA ... %d bytes\n", size);
-
- /* Copy array to FPGA - bit at a time */
-
- for (i = 0; i < size; i++) {
- volatile unsigned w = 0;
-
- for (j = 0; j < 8; j++) {
- *FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01;
- short_delay();
- }
- if ((i & 0x3ff) == 0) {
- printk(".");
- }
- }
-
- /* Waiting for CONFDONE to go high - means the program is complete */
-
- for (timeout = 0;
- (((*FPGA_ProgramReg & FPGA_CONFDONE) == 0)
- && (timeout < FPGA_TIMEOUT)); timeout++) {
-
- *FPGA_ProgramReg = 0x0;
- long_delay();
- }
-
- if (timeout == FPGA_TIMEOUT) {
- printk
- ("FPGA: Failed to program - Timeout waiting for CONFDONE to go high\n");
- return;
- } else { /* Clock another 10 times - gets the device into a working state */
- for (i = 0; i < 10; i++) {
- *FPGA_ProgramReg = 0x0;
- short_delay();
- }
- }
-
- printk("FPGA: Programming complete\n");
-}
-
-
-static const unsigned char __init fpgacode[] = {
-#include "./overdrive.ttf" /* Code from maxplus2 compiler */
- , 0, 0
-};
-
-
-int __init init_overdrive_fpga(void)
-{
- program_overdrive_fpga(fpgacode, sizeof(fpgacode));
-
- return 0;
-}
diff --git a/arch/sh/boards/overdrive/galileo.c b/arch/sh/boards/overdrive/galileo.c
deleted file mode 100644
index 29e48971bba0..000000000000
--- a/arch/sh/boards/overdrive/galileo.c
+++ /dev/null
@@ -1,587 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * This file contains the PCI routines required for the Galileo GT6411
- * PCI bridge as used on the Orion and Overdrive boards.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/errno.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/types.h>
-#include <linux/ioport.h>
-
-#include <asm/overdrive/overdrive.h>
-#include <asm/overdrive/gt64111.h>
-
-
-/* After boot, we shift the Galileo registers so that they appear
- * in BANK6, along with IO space. This means we can have one contingous
- * lump of PCI address space without these registers appearing in the
- * middle of them
- */
-
-#define GT64111_BASE_ADDRESS 0xbb000000
-#define GT64111_IO_BASE_ADDRESS 0x1000
-/* The GT64111 registers appear at this address to the SH4 after reset */
-#define RESET_GT64111_BASE_ADDRESS 0xb4000000
-
-/* Macros used to access the Galileo registers */
-#define RESET_GT64111_REG(x) (RESET_GT64111_BASE_ADDRESS+x)
-#define GT64111_REG(x) (GT64111_BASE_ADDRESS+x)
-
-#define RESET_GT_WRITE(x,v) writel((v),RESET_GT64111_REG(x))
-
-#define RESET_GT_READ(x) readl(RESET_GT64111_REG(x))
-
-#define GT_WRITE(x,v) writel((v),GT64111_REG(x))
-#define GT_WRITE_BYTE(x,v) writeb((v),GT64111_REG(x))
-#define GT_WRITE_SHORT(x,v) writew((v),GT64111_REG(x))
-
-#define GT_READ(x) readl(GT64111_REG(x))
-#define GT_READ_BYTE(x) readb(GT64111_REG(x))
-#define GT_READ_SHORT(x) readw(GT64111_REG(x))
-
-
-/* Where the various SH banks start at */
-#define SH_BANK4_ADR 0xb0000000
-#define SH_BANK5_ADR 0xb4000000
-#define SH_BANK6_ADR 0xb8000000
-
-/* Masks out everything but lines 28,27,26 */
-#define BANK_SELECT_MASK 0x1c000000
-
-#define SH4_TO_BANK(x) ( (x) & BANK_SELECT_MASK)
-
-/*
- * Masks used for address conversaion. Bank 6 is used for IO and
- * has all the address bits zeroed by the FPGA. Special case this
- */
-#define MEMORY_BANK_MASK 0x1fffffff
-#define IO_BANK_MASK 0x03ffffff
-
-/* Mark bank 6 as the bank used for IO. You can change this in the FPGA code
- * if you want
- */
-#define IO_BANK_ADR PCI_GTIO_BASE
-
-/* Will select the correct mask to apply depending on the SH$ address */
-#define SELECT_BANK_MASK(x) \
- ( (SH4_TO_BANK(x)==SH4_TO_BANK(IO_BANK_ADR)) ? IO_BANK_MASK : MEMORY_BANK_MASK)
-
-/* Converts between PCI space and P2 region */
-#define SH4_TO_PCI(x) ((x)&SELECT_BANK_MASK(x))
-
-/* Various macros for figuring out what to stick in the Galileo registers.
- * You *really* don't want to figure this stuff out by hand, you always get
- * it wrong
- */
-#define GT_MEM_LO_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7ff)
-#define GT_MEM_HI_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>21)&0x7f)
-#define GT_MEM_SUB_ADR(x) ((((unsigned)((x)&SELECT_BANK_MASK(x)))>>20)&0xff)
-
-#define PROGRAM_HI_LO(block,a,s) \
- GT_WRITE(block##_LO_DEC_ADR,GT_MEM_LO_ADR(a));\
- GT_WRITE(block##_HI_DEC_ADR,GT_MEM_HI_ADR(a+s-1))
-
-#define PROGRAM_SUB_HI_LO(block,a,s) \
- GT_WRITE(block##_LO_DEC_ADR,GT_MEM_SUB_ADR(a));\
- GT_WRITE(block##_HI_DEC_ADR,GT_MEM_SUB_ADR(a+s-1))
-
-/* We need to set the size, and the offset register */
-
-#define GT_BAR_MASK(x) ((x)&~0xfff)
-
-/* Macro to set up the BAR in the Galileo. Essentially used for the DRAM */
-#define PROGRAM_GT_BAR(block,a,s) \
- GT_WRITE(PCI_##block##_BANK_SIZE,GT_BAR_MASK((s-1)));\
- write_config_to_galileo(PCI_CONFIG_##block##_BASE_ADR,\
- GT_BAR_MASK(a))
-
-#define DISABLE_GT_BAR(block) \
- GT_WRITE(PCI_##block##_BANK_SIZE,0),\
- GT_CONFIG_WRITE(PCI_CONFIG_##block##_BASE_ADR,\
- 0x80000000)
-
-/* Macros to disable things we are not going to use */
-#define DISABLE_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0x7ff);\
- GT_WRITE(x##_HI_DEC_ADR,0x00)
-
-#define DISABLE_SUB_DECODE(x) GT_WRITE(x##_LO_DEC_ADR,0xff);\
- GT_WRITE(x##_HI_DEC_ADR,0x00)
-
-static void __init reset_pci(void)
-{
- /* Set RESET_PCI bit high */
- writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
- udelay(250);
-
- /* Set RESET_PCI bit low */
- writeb(readb(OVERDRIVE_CTRL) & RESET_PCI_MASK, OVERDRIVE_CTRL);
- udelay(250);
-
- writeb(readb(OVERDRIVE_CTRL) | ENABLE_PCI_BIT, OVERDRIVE_CTRL);
- udelay(250);
-}
-
-static int write_config_to_galileo(int where, u32 val);
-#define GT_CONFIG_WRITE(where,val) write_config_to_galileo(where,val)
-
-#define ENABLE_PCI_DRAM
-
-
-#ifdef TEST_DRAM
-/* Test function to check out if the PCI DRAM is working OK */
-static int /* __init */ test_dram(unsigned *base, unsigned size)
-{
- unsigned *p = base;
- unsigned *end = (unsigned *) (((unsigned) base) + size);
- unsigned w;
-
- for (p = base; p < end; p++) {
- *p = 0xffffffff;
- if (*p != 0xffffffff) {
- printk("AAARGH -write failed!!! at %p is %x\n", p,
- *p);
- return 0;
- }
- *p = 0x0;
- if (*p != 0x0) {
- printk("AAARGH -write failed!!!\n");
- return 0;
- }
- }
-
- for (p = base; p < end; p++) {
- *p = (unsigned) p;
- if (*p != (unsigned) p) {
- printk("Failed at 0x%p, actually is 0x%x\n", p,
- *p);
- return 0;
- }
- }
-
- for (p = base; p < end; p++) {
- w = ((unsigned) p & 0xffff0000);
- *p = w | (w >> 16);
- }
-
- for (p = base; p < end; p++) {
- w = ((unsigned) p & 0xffff0000);
- w |= (w >> 16);
- if (*p != w) {
- printk
- ("Failed at 0x%p, should be 0x%x actually is 0x%x\n",
- p, w, *p);
- return 0;
- }
- }
-
- return 1;
-}
-#endif
-
-
-/* Function to set up and initialise the galileo. This sets up the BARS,
- * maps the DRAM into the address space etc,etc
- */
-int __init galileo_init(void)
-{
- reset_pci();
-
- /* Now shift the galileo regs into this block */
- RESET_GT_WRITE(INTERNAL_SPACE_DEC,
- GT_MEM_LO_ADR(GT64111_BASE_ADDRESS));
-
- /* Should have a sanity check here, that you can read back at the new
- * address what you just wrote
- */
-
- /* Disable decode for all regions */
- DISABLE_DECODE(RAS10);
- DISABLE_DECODE(RAS32);
- DISABLE_DECODE(CS20);
- DISABLE_DECODE(CS3);
- DISABLE_DECODE(PCI_IO);
- DISABLE_DECODE(PCI_MEM0);
- DISABLE_DECODE(PCI_MEM1);
-
- /* Disable all BARS */
- GT_WRITE(BAR_ENABLE_ADR, 0x1ff);
- DISABLE_GT_BAR(RAS10);
- DISABLE_GT_BAR(RAS32);
- DISABLE_GT_BAR(CS20);
- DISABLE_GT_BAR(CS3);
-
- /* Tell the BAR where the IO registers now are */
- GT_CONFIG_WRITE(PCI_CONFIG_INT_REG_IO_ADR,GT_BAR_MASK(
- (GT64111_IO_BASE_ADDRESS &
- IO_BANK_MASK)));
- /* set up a 112 Mb decode */
- PROGRAM_HI_LO(PCI_MEM0, SH_BANK4_ADR, 112 * 1024 * 1024);
-
- /* Set up a 32 MB io space decode */
- PROGRAM_HI_LO(PCI_IO, IO_BANK_ADR, 32 * 1024 * 1024);
-
-#ifdef ENABLE_PCI_DRAM
- /* Program up the DRAM configuration - there is DRAM only in bank 0 */
- /* Now set up the DRAM decode */
- PROGRAM_HI_LO(RAS10, PCI_DRAM_BASE, PCI_DRAM_SIZE);
- /* And the sub decode */
- PROGRAM_SUB_HI_LO(RAS0, PCI_DRAM_BASE, PCI_DRAM_SIZE);
-
- DISABLE_SUB_DECODE(RAS1);
-
- /* Set refresh rate */
- GT_WRITE(DRAM_BANK0_PARMS, 0x3f);
- GT_WRITE(DRAM_CFG, 0x100);
-
- /* we have to lob off the top bits rememeber!! */
- PROGRAM_GT_BAR(RAS10, SH4_TO_PCI(PCI_DRAM_BASE), PCI_DRAM_SIZE);
-
-#endif
-
- /* We are only interested in decoding RAS10 and the Galileo's internal
- * registers (as IO) on the PCI bus
- */
-#ifdef ENABLE_PCI_DRAM
- GT_WRITE(BAR_ENABLE_ADR, (~((1 << 8) | (1 << 3))) & 0x1ff);
-#else
- GT_WRITE(BAR_ENABLE_ADR, (~(1 << 3)) & 0x1ff);
-#endif
-
- /* Change the class code to host bridge, it actually powers up
- * as a memory controller
- */
- GT_CONFIG_WRITE(8, 0x06000011);
-
- /* Allow the galileo to master the PCI bus */
- GT_CONFIG_WRITE(PCI_COMMAND,
- PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
- PCI_COMMAND_IO);
-
-
-#if 0
- printk("Testing PCI DRAM - ");
- if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
- printk("Passed\n");
- }else {
- printk("FAILED\n");
- }
-#endif
- return 0;
-
-}
-
-
-#define SET_CONFIG_BITS(bus,devfn,where)\
- ((1<<31) | ((bus) << 16) | ((devfn) << 8) | ((where) & ~3))
-
-#define CONFIG_CMD(dev, where) SET_CONFIG_BITS((dev)->bus->number,(dev)->devfn,where)
-
-/* This write to the galileo config registers, unlike the functions below, can
- * be used before the PCI subsystem has started up
- */
-static int __init write_config_to_galileo(int where, u32 val)
-{
- GT_WRITE(PCI_CFG_ADR, SET_CONFIG_BITS(0, 0, where));
-
- GT_WRITE(PCI_CFG_DATA, val);
- return 0;
-}
-
-/* We exclude the galileo and slot 31, the galileo because I don't know how to stop
- * the setup code shagging up the setup I have done on it, and 31 because the whole
- * thing locks up if you try to access that slot (which doesn't exist of course anyway
- */
-
-#define EXCLUDED_DEV(dev) ((dev->bus->number==0) && ((PCI_SLOT(dev->devfn)==0) || (PCI_SLOT(dev->devfn) == 31)))
-
-static int galileo_read_config_byte(struct pci_dev *dev, int where,
- u8 * val)
-{
-
-
- /* I suspect this doesn't work because this drives a special cycle ? */
- if (EXCLUDED_DEV(dev)) {
- *val = 0xff;
- return PCIBIOS_SUCCESSFUL;
- }
- /* Start the config cycle */
- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
- /* Read back the result */
- *val = GT_READ_BYTE(PCI_CFG_DATA + (where & 3));
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int galileo_read_config_word(struct pci_dev *dev, int where,
- u16 * val)
-{
-
- if (EXCLUDED_DEV(dev)) {
- *val = 0xffff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
- *val = GT_READ_SHORT(PCI_CFG_DATA + (where & 2));
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int galileo_read_config_dword(struct pci_dev *dev, int where,
- u32 * val)
-{
- if (EXCLUDED_DEV(dev)) {
- *val = 0xffffffff;
- return PCIBIOS_SUCCESSFUL;
- }
-
- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
- *val = GT_READ(PCI_CFG_DATA);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int galileo_write_config_byte(struct pci_dev *dev, int where,
- u8 val)
-{
- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
-
- GT_WRITE_BYTE(PCI_CFG_DATA + (where & 3), val);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-
-static int galileo_write_config_word(struct pci_dev *dev, int where,
- u16 val)
-{
- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
-
- GT_WRITE_SHORT(PCI_CFG_DATA + (where & 2), val);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int galileo_write_config_dword(struct pci_dev *dev, int where,
- u32 val)
-{
- GT_WRITE(PCI_CFG_ADR, CONFIG_CMD(dev, where));
-
- GT_WRITE(PCI_CFG_DATA, val);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops pci_config_ops = {
- galileo_read_config_byte,
- galileo_read_config_word,
- galileo_read_config_dword,
- galileo_write_config_byte,
- galileo_write_config_word,
- galileo_write_config_dword
-};
-
-
-/* Everything hangs off this */
-static struct pci_bus *pci_root_bus;
-
-
-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
-{
- return PCI_SLOT(dev->devfn);
-}
-
-static int __init map_od_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- /* Slot 1: Galileo
- * Slot 2: PCI Slot 1
- * Slot 3: PCI Slot 2
- * Slot 4: ESS
- */
- switch (slot) {
- case 2:
- return OVERDRIVE_PCI_IRQ1;
- case 3:
- /* Note this assumes you have a hacked card in slot 2 */
- return OVERDRIVE_PCI_IRQ2;
- case 4:
- return OVERDRIVE_ESS_IRQ;
- default:
- /* printk("PCI: Unexpected IRQ mapping request for slot %d\n", slot); */
- return -1;
- }
-}
-
-
-
-void __init
-pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
-{
- ranges->io_start -= bus->resource[0]->start;
- ranges->io_end -= bus->resource[0]->start;
- ranges->mem_start -= bus->resource[1]->start;
- ranges->mem_end -= bus->resource[1]->start;
-}
-
-static void __init pci_fixup_ide_bases(struct pci_dev *d)
-{
- int i;
-
- /*
- * PCI IDE controllers use non-standard I/O port decoding, respect it.
- */
- if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
- return;
- printk("PCI: IDE base address fixup for %s\n", pci_name(d));
- for(i=0; i<4; i++) {
- struct resource *r = &d->resource[i];
- if ((r->start & ~0x80) == 0x374) {
- r->start |= 2;
- r->end = r->start;
- }
- }
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
-
-void __init pcibios_init(void)
-{
- static struct resource galio,galmem;
-
- /* Allocate the registers used by the Galileo */
- galio.flags = IORESOURCE_IO;
- galio.name = "Galileo GT64011";
- galmem.flags = IORESOURCE_MEM|IORESOURCE_PREFETCH;
- galmem.name = "Galileo GT64011 DRAM";
-
- allocate_resource(&ioport_resource, &galio, 256,
- GT64111_IO_BASE_ADDRESS,GT64111_IO_BASE_ADDRESS+256, 256, NULL, NULL);
- allocate_resource(&iomem_resource, &galmem,PCI_DRAM_SIZE,
- PHYSADDR(PCI_DRAM_BASE), PHYSADDR(PCI_DRAM_BASE)+PCI_DRAM_SIZE,
- PCI_DRAM_SIZE, NULL, NULL);
-
- /* ok, do the scan man */
- pci_root_bus = pci_scan_bus(0, &pci_config_ops, NULL);
-
- pci_assign_unassigned_resources();
- pci_fixup_irqs(no_swizzle, map_od_irq);
-
-#ifdef TEST_DRAM
- printk("Testing PCI DRAM - ");
- if(test_dram(PCI_DRAM_BASE,PCI_DRAM_SIZE)) {
- printk("Passed\n");
- }else {
- printk("FAILED\n");
- }
-#endif
-
-}
-
-char * __init pcibios_setup(char *str)
-{
- return str;
-}
-
-
-
-int pcibios_enable_device(struct pci_dev *dev)
-{
-
- u16 cmd, old_cmd;
- int idx;
- struct resource *r;
-
- pci_read_config_word(dev, PCI_COMMAND, &cmd);
- old_cmd = cmd;
- for (idx = 0; idx < 6; idx++) {
- r = dev->resource + idx;
- if (!r->start && r->end) {
- printk(KERN_ERR
- "PCI: Device %s not available because"
- " of resource collisions\n",
- pci_name(dev));
- return -EINVAL;
- }
- if (r->flags & IORESOURCE_IO)
- cmd |= PCI_COMMAND_IO;
- if (r->flags & IORESOURCE_MEM)
- cmd |= PCI_COMMAND_MEMORY;
- }
- if (cmd != old_cmd) {
- printk("PCI: enabling device %s (%04x -> %04x)\n",
- pci_name(dev), old_cmd, cmd);
- pci_write_config_word(dev, PCI_COMMAND, cmd);
- }
- return 0;
-
-}
-
-/* We should do some optimisation work here I think. Ok for now though */
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-
-}
-
-void pcibios_align_resource(void *data, struct resource *res,
- resource_size_t size)
-{
-}
-
-void __init pcibios_update_resource(struct pci_dev *dev, struct resource *root,
- struct resource *res, int resource)
-{
-
- unsigned long where, size;
- u32 reg;
-
-
- printk("PCI: Assigning %3s %08lx to %s\n",
- res->flags & IORESOURCE_IO ? "IO" : "MEM",
- res->start, dev->name);
-
- where = PCI_BASE_ADDRESS_0 + resource * 4;
- size = res->end - res->start;
-
- pci_read_config_dword(dev, where, &reg);
- reg = (reg & size) | (((u32) (res->start - root->start)) & ~size);
- pci_write_config_dword(dev, where, reg);
-}
-
-
-void __init pcibios_update_irq(struct pci_dev *dev, int irq)
-{
- printk("PCI: Assigning IRQ %02d to %s\n", irq, dev->name);
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
-}
-
-/*
- * If we set up a device for bus mastering, we need to check the latency
- * timer as certain crappy BIOSes forget to set it properly.
- */
-unsigned int pcibios_max_latency = 255;
-
-void pcibios_set_master(struct pci_dev *dev)
-{
- u8 lat;
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
- if (lat < 16)
- lat = (64 <= pcibios_max_latency) ? 64 : pcibios_max_latency;
- else if (lat > pcibios_max_latency)
- lat = pcibios_max_latency;
- else
- return;
- printk("PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
-}
diff --git a/arch/sh/boards/overdrive/io.c b/arch/sh/boards/overdrive/io.c
deleted file mode 100644
index 4671b6b047bb..000000000000
--- a/arch/sh/boards/overdrive/io.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * This file contains the I/O routines for use on the overdrive board
- *
- */
-
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <asm/processor.h>
-#include <asm/io.h>
-#include <asm/addrspace.h>
-
-#include <asm/overdrive/overdrive.h>
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the SuperH architecture, we just read/write the
- * memory location directly.
- */
-
-#define dprintk(x...)
-
-/* Translates an IO address to where it is mapped in memory */
-
-#define io_addr(x) (((unsigned)(x))|PCI_GTIO_BASE)
-
-unsigned char od_inb(unsigned long port)
-{
-dprintk("od_inb(%x)\n", port);
- return readb(io_addr(port)) & 0xff;
-}
-
-
-unsigned short od_inw(unsigned long port)
-{
-dprintk("od_inw(%x)\n", port);
- return readw(io_addr(port)) & 0xffff;
-}
-
-unsigned int od_inl(unsigned long port)
-{
-dprintk("od_inl(%x)\n", port);
- return readl(io_addr(port));
-}
-
-void od_outb(unsigned char value, unsigned long port)
-{
-dprintk("od_outb(%x, %x)\n", value, port);
- writeb(value, io_addr(port));
-}
-
-void od_outw(unsigned short value, unsigned long port)
-{
-dprintk("od_outw(%x, %x)\n", value, port);
- writew(value, io_addr(port));
-}
-
-void od_outl(unsigned int value, unsigned long port)
-{
-dprintk("od_outl(%x, %x)\n", value, port);
- writel(value, io_addr(port));
-}
-
-/* This is horrible at the moment - needs more work to do something sensible */
-#define IO_DELAY() udelay(10)
-
-#define OUT_DELAY(x,type) \
-void od_out##x##_p(unsigned type value,unsigned long port){out##x(value,port);IO_DELAY();}
-
-#define IN_DELAY(x,type) \
-unsigned type od_in##x##_p(unsigned long port) {unsigned type tmp=in##x(port);IO_DELAY();return tmp;}
-
-
-OUT_DELAY(b,char)
-OUT_DELAY(w,short)
-OUT_DELAY(l,int)
-
-IN_DELAY(b,char)
-IN_DELAY(w,short)
-IN_DELAY(l,int)
-
-
-/* Now for the string version of these functions */
-void od_outsb(unsigned long port, const void *addr, unsigned long count)
-{
- int i;
- unsigned char *p = (unsigned char *) addr;
-
- for (i = 0; i < count; i++, p++) {
- outb(*p, port);
- }
-}
-
-
-void od_insb(unsigned long port, void *addr, unsigned long count)
-{
- int i;
- unsigned char *p = (unsigned char *) addr;
-
- for (i = 0; i < count; i++, p++) {
- *p = inb(port);
- }
-}
-
-/* For the 16 and 32 bit string functions, we have to worry about alignment.
- * The SH does not do unaligned accesses, so we have to read as bytes and
- * then write as a word or dword.
- * This can be optimised a lot more, especially in the case where the data
- * is aligned
- */
-
-void od_outsw(unsigned long port, const void *addr, unsigned long count)
-{
- int i;
- unsigned short tmp;
- unsigned char *p = (unsigned char *) addr;
-
- for (i = 0; i < count; i++, p += 2) {
- tmp = (*p) | ((*(p + 1)) << 8);
- outw(tmp, port);
- }
-}
-
-
-void od_insw(unsigned long port, void *addr, unsigned long count)
-{
- int i;
- unsigned short tmp;
- unsigned char *p = (unsigned char *) addr;
-
- for (i = 0; i < count; i++, p += 2) {
- tmp = inw(port);
- p[0] = tmp & 0xff;
- p[1] = (tmp >> 8) & 0xff;
- }
-}
-
-
-void od_outsl(unsigned long port, const void *addr, unsigned long count)
-{
- int i;
- unsigned tmp;
- unsigned char *p = (unsigned char *) addr;
-
- for (i = 0; i < count; i++, p += 4) {
- tmp = (*p) | ((*(p + 1)) << 8) | ((*(p + 2)) << 16) |
- ((*(p + 3)) << 24);
- outl(tmp, port);
- }
-}
-
-
-void od_insl(unsigned long port, void *addr, unsigned long count)
-{
- int i;
- unsigned tmp;
- unsigned char *p = (unsigned char *) addr;
-
- for (i = 0; i < count; i++, p += 4) {
- tmp = inl(port);
- p[0] = tmp & 0xff;
- p[1] = (tmp >> 8) & 0xff;
- p[2] = (tmp >> 16) & 0xff;
- p[3] = (tmp >> 24) & 0xff;
-
- }
-}
diff --git a/arch/sh/boards/overdrive/irq.c b/arch/sh/boards/overdrive/irq.c
deleted file mode 100644
index 5d730c70389e..000000000000
--- a/arch/sh/boards/overdrive/irq.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Looks after interrupts on the overdrive board.
- *
- * Bases on the IPR irq system
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-
-#include <asm/overdrive/overdrive.h>
-
-struct od_data {
- int overdrive_irq;
- int irq_mask;
-};
-
-#define NUM_EXTERNAL_IRQS 16
-#define EXTERNAL_IRQ_NOT_IN_USE (-1)
-#define EXTERNAL_IRQ_NOT_ASSIGNED (-1)
-
-/*
- * This table is used to determine what to program into the FPGA's CT register
- * for the specified Linux IRQ.
- *
- * The irq_mask gives the interrupt number from the PCI board (PCI_Int(6:0))
- * but is one greater than that because the because the FPGA treats 0
- * as disabled, a value of 1 asserts PCI_Int0, and so on.
- *
- * The overdrive_irq specifies which of the eight interrupt sources generates
- * that interrupt, and but is multiplied by four to give the bit offset into
- * the CT register.
- *
- * The seven interrupts levels (SH4 IRL's) we have available here is hardwired
- * by the EPLD. The assignments here of which PCI interrupt generates each
- * level is arbitary.
- */
-static struct od_data od_data_table[NUM_EXTERNAL_IRQS] = {
- /* overdrive_irq , irq_mask */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 0 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, 7}, /* 1 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, 6}, /* 2 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 3 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, 5}, /* 4 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 5 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 6 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, 4}, /* 7 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 8 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 9 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, 3}, /* 10 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, 2}, /* 11 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 12 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, 1}, /* 13 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE}, /* 14 */
- {EXTERNAL_IRQ_NOT_ASSIGNED, EXTERNAL_IRQ_NOT_IN_USE} /* 15 */
-};
-
-static void set_od_data(int overdrive_irq, int irq)
-{
- if (irq >= NUM_EXTERNAL_IRQS || irq < 0)
- return;
- od_data_table[irq].overdrive_irq = overdrive_irq << 2;
-}
-
-static void enable_od_irq(unsigned int irq);
-void disable_od_irq(unsigned int irq);
-
-/* shutdown is same as "disable" */
-#define shutdown_od_irq disable_od_irq
-
-static void mask_and_ack_od(unsigned int);
-static void end_od_irq(unsigned int irq);
-
-static unsigned int startup_od_irq(unsigned int irq)
-{
- enable_od_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type od_irq_type = {
- .typename = "Overdrive-IRQ",
- .startup = startup_od_irq,
- .shutdown = shutdown_od_irq,
- .enable = enable_od_irq,
- .disable = disable_od_irq,
- .ack = mask_and_ack_od,
- .end = end_od_irq
-};
-
-static void disable_od_irq(unsigned int irq)
-{
- unsigned val, flags;
- int overdrive_irq;
- unsigned mask;
-
- /* Not a valid interrupt */
- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
- return;
-
- /* Is is necessary to use a cli here? Would a spinlock not be
- * mroe efficient?
- */
- local_irq_save(flags);
- overdrive_irq = od_data_table[irq].overdrive_irq;
- if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
- mask = ~(0x7 << overdrive_irq);
- val = ctrl_inl(OVERDRIVE_INT_CT);
- val &= mask;
- ctrl_outl(val, OVERDRIVE_INT_CT);
- }
- local_irq_restore(flags);
-}
-
-static void enable_od_irq(unsigned int irq)
-{
- unsigned val, flags;
- int overdrive_irq;
- unsigned mask;
-
- /* Not a valid interrupt */
- if (irq < 0 || irq >= NUM_EXTERNAL_IRQS)
- return;
-
- /* Set priority in OD back to original value */
- local_irq_save(flags);
- /* This one is not in use currently */
- overdrive_irq = od_data_table[irq].overdrive_irq;
- if (overdrive_irq != EXTERNAL_IRQ_NOT_ASSIGNED) {
- val = ctrl_inl(OVERDRIVE_INT_CT);
- mask = ~(0x7 << overdrive_irq);
- val &= mask;
- mask = od_data_table[irq].irq_mask << overdrive_irq;
- val |= mask;
- ctrl_outl(val, OVERDRIVE_INT_CT);
- }
- local_irq_restore(flags);
-}
-
-
-
-/* this functions sets the desired irq handler to be an overdrive type */
-static void __init make_od_irq(unsigned int irq)
-{
- disable_irq_nosync(irq);
- irq_desc[irq].chip = &od_irq_type;
- disable_od_irq(irq);
-}
-
-
-static void mask_and_ack_od(unsigned int irq)
-{
- disable_od_irq(irq);
-}
-
-static void end_od_irq(unsigned int irq)
-{
- enable_od_irq(irq);
-}
-
-void __init init_overdrive_irq(void)
-{
- int i;
-
- /* Disable all interrupts */
- ctrl_outl(0, OVERDRIVE_INT_CT);
-
- /* Update interrupt pin mode to use encoded interrupts */
- i = ctrl_inw(INTC_ICR);
- i &= ~INTC_ICR_IRLM;
- ctrl_outw(i, INTC_ICR);
-
- for (i = 0; i < NUM_EXTERNAL_IRQS; i++) {
- if (od_data_table[i].irq_mask != EXTERNAL_IRQ_NOT_IN_USE) {
- make_od_irq(i);
- } else if (i != 15) { // Cannot use imask on level 15
- make_imask_irq(i);
- }
- }
-
- /* Set up the interrupts */
- set_od_data(OVERDRIVE_PCI_INTA, OVERDRIVE_PCI_IRQ1);
- set_od_data(OVERDRIVE_PCI_INTB, OVERDRIVE_PCI_IRQ2);
- set_od_data(OVERDRIVE_AUDIO_INT, OVERDRIVE_ESS_IRQ);
-}
diff --git a/arch/sh/boards/overdrive/led.c b/arch/sh/boards/overdrive/led.c
deleted file mode 100644
index 860d7f204a4e..000000000000
--- a/arch/sh/boards/overdrive/led.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * linux/arch/sh/overdrive/led.c
- *
- * Copyright (C) 1999 Stuart Menefy <stuart.menefy@st.com>
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * This file contains an Overdrive specific LED feature.
- */
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/overdrive/overdrive.h>
-
-static void mach_led(int position, int value)
-{
- unsigned long flags;
- unsigned long reg;
-
- local_irq_save(flags);
-
- reg = readl(OVERDRIVE_CTRL);
- if (value) {
- reg |= (1<<3);
- } else {
- reg &= ~(1<<3);
- }
- writel(reg, OVERDRIVE_CTRL);
-
- local_irq_restore(flags);
-}
-
-#ifdef CONFIG_HEARTBEAT
-
-#include <linux/sched.h>
-
-/* acts like an actual heart beat -- ie thump-thump-pause... */
-void heartbeat_od(void)
-{
- static unsigned cnt = 0, period = 0, dist = 0;
-
- if (cnt == 0 || cnt == dist)
- mach_led( -1, 1);
- else if (cnt == 7 || cnt == dist+7)
- mach_led( -1, 0);
-
- if (++cnt > period) {
- cnt = 0;
- /* The hyperbolic function below modifies the heartbeat period
- * length in dependency of the current (5min) load. It goes
- * through the points f(0)=126, f(1)=86, f(5)=51,
- * f(inf)->30. */
- period = ((672<<FSHIFT)/(5*avenrun[0]+(7<<FSHIFT))) + 30;
- dist = period / 4;
- }
-}
-#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/overdrive/mach.c b/arch/sh/boards/overdrive/mach.c
deleted file mode 100644
index 2834a03ae477..000000000000
--- a/arch/sh/boards/overdrive/mach.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * linux/arch/sh/overdrive/mach.c
- *
- * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the STMicroelectronics Overdrive
- */
-
-#include <linux/init.h>
-
-#include <asm/machvec.h>
-#include <asm/rtc.h>
-#include <asm/machvec_init.h>
-
-#include <asm/io_unknown.h>
-#include <asm/io_generic.h>
-#include <asm/overdrive/io.h>
-
-void heartbeat_od(void);
-void init_overdrive_irq(void);
-void galileo_pcibios_init(void);
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_od __initmv = {
- .mv_nr_irqs = 48,
-
- .mv_inb = od_inb,
- .mv_inw = od_inw,
- .mv_inl = od_inl,
- .mv_outb = od_outb,
- .mv_outw = od_outw,
- .mv_outl = od_outl,
-
- .mv_inb_p = od_inb_p,
- .mv_inw_p = od_inw_p,
- .mv_inl_p = od_inl_p,
- .mv_outb_p = od_outb_p,
- .mv_outw_p = od_outw_p,
- .mv_outl_p = od_outl_p,
-
- .mv_insb = od_insb,
- .mv_insw = od_insw,
- .mv_insl = od_insl,
- .mv_outsb = od_outsb,
- .mv_outsw = od_outsw,
- .mv_outsl = od_outsl,
-
-#ifdef CONFIG_PCI
- .mv_init_irq = init_overdrive_irq,
-#endif
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_od,
-#endif
-};
-
-ALIAS_MV(od)
diff --git a/arch/sh/boards/overdrive/pcidma.c b/arch/sh/boards/overdrive/pcidma.c
deleted file mode 100644
index 1c9bfeda00b7..000000000000
--- a/arch/sh/boards/overdrive/pcidma.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Dynamic DMA mapping support.
- *
- * On the overdrive, we can only DMA from memory behind the PCI bus!
- * this means that all DMA'able memory must come from there.
- * this restriction will not apply to later boards.
- */
-
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-
-void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
- dma_addr_t * dma_handle)
-{
- void *ret;
- int gfp = GFP_ATOMIC;
-
- printk("BUG: pci_alloc_consistent() called - not yet supported\n");
- /* We ALWAYS need DMA memory on the overdrive hardware,
- * due to it's extreme weirdness
- * Need to flush the cache here as well, since the memory
- * can still be seen through the cache!
- */
- gfp |= GFP_DMA;
- ret = (void *) __get_free_pages(gfp, get_order(size));
-
- if (ret != NULL) {
- memset(ret, 0, size);
- *dma_handle = virt_to_bus(ret);
- }
- return ret;
-}
-
-void pci_free_consistent(struct pci_dev *hwdev, size_t size,
- void *vaddr, dma_addr_t dma_handle)
-{
- free_pages((unsigned long) vaddr, get_order(size));
-}
diff --git a/arch/sh/boards/overdrive/setup.c b/arch/sh/boards/overdrive/setup.c
deleted file mode 100644
index a3a7744c2047..000000000000
--- a/arch/sh/boards/overdrive/setup.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * arch/sh/overdrive/setup.c
- *
- * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * STMicroelectronics Overdrive Support.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <asm/overdrive/overdrive.h>
-#include <asm/overdrive/fpga.h>
-
-const char *get_system_type(void)
-{
- return "SH7750 Overdrive";
-}
-
-/*
- * Initialize the board
- */
-int __init platform_setup(void)
-{
-#ifdef CONFIG_PCI
- init_overdrive_fpga();
- galileo_init();
-#endif
-
- /* Enable RS232 receive buffers */
- writel(0x1e, OVERDRIVE_CTRL);
-}
diff --git a/arch/sh/boards/renesas/edosk7705/Makefile b/arch/sh/boards/renesas/edosk7705/Makefile
index 7fccbf2e4a1d..14bdd531f116 100644
--- a/arch/sh/boards/renesas/edosk7705/Makefile
+++ b/arch/sh/boards/renesas/edosk7705/Makefile
@@ -1,10 +1,6 @@
#
# Makefile for the EDOSK7705 specific parts of the kernel
#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
obj-y := setup.o io.o
diff --git a/arch/sh/boards/renesas/edosk7705/setup.c b/arch/sh/boards/renesas/edosk7705/setup.c
index ba143fa4afaa..ec5be0107719 100644
--- a/arch/sh/boards/renesas/edosk7705/setup.c
+++ b/arch/sh/boards/renesas/edosk7705/setup.c
@@ -8,19 +8,21 @@
* Modified for edosk7705 development
* board by S. Dunn, 2003.
*/
-
#include <linux/init.h>
#include <asm/machvec.h>
-#include <asm/machvec_init.h>
#include <asm/edosk7705/io.h>
-static void init_edosk7705(void);
+static void __init sh_edosk7705_init_irq(void)
+{
+ /* This is the Ethernet interrupt */
+ make_imask_irq(0x09);
+}
/*
* The Machine Vector
*/
-
struct sh_machine_vector mv_edosk7705 __initmv = {
+ .mv_name = "EDOSK7705",
.mv_nr_irqs = 80,
.mv_inb = sh_edosk7705_inb,
@@ -37,23 +39,6 @@ struct sh_machine_vector mv_edosk7705 __initmv = {
.mv_outsl = sh_edosk7705_outsl,
.mv_isa_port2addr = sh_edosk7705_isa_port2addr,
- .mv_init_irq = init_edosk7705,
+ .mv_init_irq = sh_edosk7705_init_irq,
};
ALIAS_MV(edosk7705)
-
-static void __init init_edosk7705(void)
-{
- /* This is the Ethernet interrupt */
- make_imask_irq(0x09);
-}
-
-const char *get_system_type(void)
-{
- return "EDOSK7705";
-}
-
-void __init platform_setup(void)
-{
- /* Nothing .. */
-}
-
diff --git a/arch/sh/boards/renesas/hs7751rvoip/Kconfig b/arch/sh/boards/renesas/hs7751rvoip/Kconfig
new file mode 100644
index 000000000000..1743be477be5
--- /dev/null
+++ b/arch/sh/boards/renesas/hs7751rvoip/Kconfig
@@ -0,0 +1,12 @@
+if SH_HS7751RVOIP
+
+menu "HS7751RVoIP options"
+
+config HS7751RVOIP_CODEC
+ bool "Support VoIP Codec section"
+ help
+ Selecting this option will support CODEC section.
+
+endmenu
+
+endif
diff --git a/arch/sh/boards/renesas/hs7751rvoip/Makefile b/arch/sh/boards/renesas/hs7751rvoip/Makefile
index e8b4109ace11..e626377c55ee 100644
--- a/arch/sh/boards/renesas/hs7751rvoip/Makefile
+++ b/arch/sh/boards/renesas/hs7751rvoip/Makefile
@@ -1,12 +1,8 @@
#
# Makefile for the HS7751RVoIP specific parts of the kernel
#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-obj-y := mach.o setup.o io.o irq.o led.o
+obj-y := setup.o io.o irq.o
obj-$(CONFIG_PCI) += pci.o
diff --git a/arch/sh/boards/renesas/hs7751rvoip/io.c b/arch/sh/boards/renesas/hs7751rvoip/io.c
index 3a1abfa2fefb..51f3f6574210 100644
--- a/arch/sh/boards/renesas/hs7751rvoip/io.c
+++ b/arch/sh/boards/renesas/hs7751rvoip/io.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/io_hs7751rvoip.c
+ * linux/arch/sh/boards/renesas/hs7751rvoip/io.c
*
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
@@ -10,21 +10,16 @@
* placeholder code from io_hs7751rvoip.c left in with the
* expectation of later SuperIO and PCMCIA access.
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
#include <asm/io.h>
#include <asm/hs7751rvoip/hs7751rvoip.h>
#include <asm/addrspace.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include "../../../drivers/pci/pci-sh7751.h"
-
-extern void *area5_io8_base; /* Area 5 8bit I/O Base address */
extern void *area6_io8_base; /* Area 6 8bit I/O Base address */
extern void *area5_io16_base; /* Area 5 16bit I/O Base address */
-extern void *area6_io16_base; /* Area 6 16bit I/O Base address */
/*
* The 7751R HS7751RVoIP uses the built-in PCI controller (PCIC)
@@ -33,25 +28,8 @@ extern void *area6_io16_base; /* Area 6 16bit I/O Base address */
* like the other Solution Engine boards.
*/
-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
-#define PCI_IO_AREA SH7751_PCI_IO_BASE
-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
-
-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
-
-#if defined(CONFIG_HS7751RVOIP_CODEC)
#define CODEC_IO_BASE 0x1000
-#endif
-
-#define maybebadio(name,port) \
- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
- #name, (port), (__u32) __builtin_return_address(0))
-
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000);
-}
+#define CODEC_IOMAP(a) ((unsigned long)area6_io8_base + ((a) - CODEC_IO_BASE))
static inline unsigned long port2adr(unsigned int port)
{
@@ -59,9 +37,10 @@ static inline unsigned long port2adr(unsigned int port)
if (port == 0x3f6)
return ((unsigned long)area5_io16_base + 0x0c);
else
- return ((unsigned long)area5_io16_base + 0x800 + ((port-0x1f0) << 1));
+ return ((unsigned long)area5_io16_base + 0x800 +
+ ((port-0x1f0) << 1));
else
- maybebadio(port2adr, (unsigned long)port);
+ maybebadio((unsigned long)port);
return port;
}
@@ -78,25 +57,10 @@ static inline int shifted_port(unsigned long port)
}
#if defined(CONFIG_HS7751RVOIP_CODEC)
-static inline int
-codec_port(unsigned long port)
-{
- if (CODEC_IO_BASE <= port && port < (CODEC_IO_BASE+0x20))
- return 1;
- else
- return 0;
-}
-#endif
-
-/* In case someone configures the kernel w/o PCI support: in that */
-/* scenario, don't ever bother to check for PCI-window addresses */
-
-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
-#if defined(CONFIG_PCI)
-#define CHECK_SH7751_PCIIO(port) \
- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
+#define codec_port(port) \
+ ((CODEC_IO_BASE <= (port)) && ((port) < (CODEC_IO_BASE + 0x20)))
#else
-#define CHECK_SH7751_PCIIO(port) (0)
+#define codec_port(port) (0)
#endif
/*
@@ -109,15 +73,13 @@ codec_port(unsigned long port)
unsigned char hs7751rvoip_inb(unsigned long port)
{
if (PXSEG(port))
- return *(volatile unsigned char *)port;
-#if defined(CONFIG_HS7751RVOIP_CODEC)
+ return ctrl_inb(port);
else if (codec_port(port))
- return *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
-#endif
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- return *(volatile unsigned char *)PCI_IOMAP(port);
+ return ctrl_inb(CODEC_IOMAP(port));
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return ctrl_inb(pci_ioaddr(port));
else
- return (*(volatile unsigned short *)port2adr(port) & 0xff);
+ return ctrl_inw(port2adr(port)) & 0xff;
}
unsigned char hs7751rvoip_inb_p(unsigned long port)
@@ -125,38 +87,36 @@ unsigned char hs7751rvoip_inb_p(unsigned long port)
unsigned char v;
if (PXSEG(port))
- v = *(volatile unsigned char *)port;
-#if defined(CONFIG_HS7751RVOIP_CODEC)
+ v = ctrl_inb(port);
else if (codec_port(port))
- v = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
-#endif
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- v = *(volatile unsigned char *)PCI_IOMAP(port);
+ v = ctrl_inb(CODEC_IOMAP(port));
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ v = ctrl_inb(pci_ioaddr(port));
else
- v = (*(volatile unsigned short *)port2adr(port) & 0xff);
- delay();
+ v = ctrl_inw(port2adr(port)) & 0xff;
+ ctrl_delay();
return v;
}
unsigned short hs7751rvoip_inw(unsigned long port)
{
if (PXSEG(port))
- return *(volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- return *(volatile unsigned short *)PCI_IOMAP(port);
+ return ctrl_inw(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return ctrl_inw(pci_ioaddr(port));
else
- maybebadio(inw, port);
+ maybebadio(port);
return 0;
}
unsigned int hs7751rvoip_inl(unsigned long port)
{
if (PXSEG(port))
- return *(volatile unsigned long *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- return *(volatile unsigned long *)PCI_IOMAP(port);
+ return ctrl_inl(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return ctrl_inl(pci_ioaddr(port));
else
- maybebadio(inl, port);
+ maybebadio(port);
return 0;
}
@@ -164,146 +124,160 @@ void hs7751rvoip_outb(unsigned char value, unsigned long port)
{
if (PXSEG(port))
- *(volatile unsigned char *)port = value;
-#if defined(CONFIG_HS7751RVOIP_CODEC)
+ ctrl_outb(value, port);
else if (codec_port(port))
- *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
-#endif
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *(unsigned char *)PCI_IOMAP(port) = value;
+ ctrl_outb(value, CODEC_IOMAP(port));
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outb(value, pci_ioaddr(port));
else
- *(volatile unsigned short *)port2adr(port) = value;
+ ctrl_outb(value, port2adr(port));
}
void hs7751rvoip_outb_p(unsigned char value, unsigned long port)
{
if (PXSEG(port))
- *(volatile unsigned char *)port = value;
-#if defined(CONFIG_HS7751RVOIP_CODEC)
+ ctrl_outb(value, port);
else if (codec_port(port))
- *(volatile unsigned cjar *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = value;
-#endif
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *(unsigned char *)PCI_IOMAP(port) = value;
+ ctrl_outb(value, CODEC_IOMAP(port));
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outb(value, pci_ioaddr(port));
else
- *(volatile unsigned short *)port2adr(port) = value;
- delay();
+ ctrl_outw(value, port2adr(port));
+
+ ctrl_delay();
}
void hs7751rvoip_outw(unsigned short value, unsigned long port)
{
if (PXSEG(port))
- *(volatile unsigned short *)port = value;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *(unsigned short *)PCI_IOMAP(port) = value;
+ ctrl_outw(value, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outw(value, pci_ioaddr(port));
else
- maybebadio(outw, port);
+ maybebadio(port);
}
void hs7751rvoip_outl(unsigned int value, unsigned long port)
{
if (PXSEG(port))
- *(volatile unsigned long *)port = value;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *((unsigned long *)PCI_IOMAP(port)) = value;
+ ctrl_outl(value, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outl(value, pci_ioaddr(port));
else
- maybebadio(outl, port);
+ maybebadio(port);
}
void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count)
{
+ u8 *buf = addr;
+
if (PXSEG(port))
- while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)port;
-#if defined(CONFIG_HS7751RVOIP_CODEC)
+ while (count--)
+ *buf++ = ctrl_inb(port);
else if (codec_port(port))
- while (count--) *((unsigned char *) addr)++ = *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE));
-#endif
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
+ while (count--)
+ *buf++ = ctrl_inb(CODEC_IOMAP(port));
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
- while (count--) *((volatile unsigned char *) addr)++ = *bp;
+ while (count--)
+ *buf++ = *bp;
} else {
- volatile __u16 *p = (volatile unsigned short *)port2adr(port);
+ volatile u16 *p = (volatile u16 *)port2adr(port);
- while (count--) *((unsigned char *) addr)++ = *p & 0xff;
+ while (count--)
+ *buf++ = *p & 0xff;
}
}
void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count)
{
- volatile __u16 *p;
+ volatile u16 *p;
+ u16 *buf = addr;
if (PXSEG(port))
- p = (volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- p = (volatile unsigned short *)PCI_IOMAP(port);
+ p = (volatile u16 *)port;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ p = (volatile u16 *)pci_ioaddr(port);
else
- p = (volatile unsigned short *)port2adr(port);
- while (count--) *((__u16 *) addr)++ = *p;
+ p = (volatile u16 *)port2adr(port);
+ while (count--)
+ *buf++ = *p;
}
void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count)
{
- if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
- while (count--) *((__u32 *) addr)++ = *p;
+ if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+ u32 *buf = addr;
+
+ while (count--)
+ *buf++ = *p;
} else
- maybebadio(insl, port);
+ maybebadio(port);
}
void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count)
{
+ const u8 *buf = addr;
+
if (PXSEG(port))
- while (count--) *(volatile unsigned char *)port = *((unsigned char *) addr)++;
-#if defined(CONFIG_HS7751RVOIP_CODEC)
+ while (count--)
+ ctrl_outb(*buf++, port);
else if (codec_port(port))
- while (count--) *(volatile unsigned char *)((unsigned long)area6_io8_base+(port-CODEC_IO_BASE)) = *((unsigned char *) addr)++;
-#endif
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- volatile __u8 *bp = (__u8 *)PCI_IOMAP(port);
+ while (count--)
+ ctrl_outb(*buf++, CODEC_IOMAP(port));
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
- while (count--) *bp = *((volatile unsigned char *) addr)++;
+ while (count--)
+ *bp = *buf++;
} else {
- volatile __u16 *p = (volatile unsigned short *)port2adr(port);
+ volatile u16 *p = (volatile u16 *)port2adr(port);
- while (count--) *p = *((unsigned char *) addr)++;
+ while (count--)
+ *p = *buf++;
}
}
void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count)
{
- volatile __u16 *p;
+ volatile u16 *p;
+ const u16 *buf = addr;
if (PXSEG(port))
- p = (volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- p = (volatile unsigned short *)PCI_IOMAP(port);
+ p = (volatile u16 *)port;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ p = (volatile u16 *)pci_ioaddr(port);
else
- p = (volatile unsigned short *)port2adr(port);
- while (count--) *p = *((__u16 *) addr)++;
+ p = (volatile u16 *)port2adr(port);
+
+ while (count--)
+ *p = *buf++;
}
void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count)
{
- if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
+ const u32 *buf = addr;
- while (count--) *p = *((__u32 *) addr)++;
+ if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+
+ while (count--)
+ *p = *buf++;
} else
- maybebadio(outsl, port);
+ maybebadio(port);
}
-void *hs7751rvoip_ioremap(unsigned long offset, unsigned long size)
+void __iomem *hs7751rvoip_ioport_map(unsigned long port, unsigned int size)
{
- if (offset >= 0xfd000000)
- return (void *)offset;
- else
- return (void *)P2SEGADDR(offset);
-}
-EXPORT_SYMBOL(hs7751rvoip_ioremap);
+ if (PXSEG(port))
+ return (void __iomem *)port;
+ else if (unlikely(codec_port(port) && (size == 1)))
+ return (void __iomem *)CODEC_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return (void __iomem *)pci_ioaddr(port);
-unsigned long hs7751rvoip_isa_port2addr(unsigned long offset)
-{
- return port2adr(offset);
+ return (void __iomem *)port2adr(port);
}
diff --git a/arch/sh/boards/renesas/hs7751rvoip/irq.c b/arch/sh/boards/renesas/hs7751rvoip/irq.c
index 705b7ddcb0d2..c617b188258a 100644
--- a/arch/sh/boards/renesas/hs7751rvoip/irq.c
+++ b/arch/sh/boards/renesas/hs7751rvoip/irq.c
@@ -35,30 +35,24 @@ static unsigned int startup_hs7751rvoip_irq(unsigned int irq)
static void disable_hs7751rvoip_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short val;
unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
/* Set the priority in IPR to 0 */
- local_irq_save(flags);
val = ctrl_inw(IRLCNTR3);
val &= mask;
ctrl_outw(val, IRLCNTR3);
- local_irq_restore(flags);
}
static void enable_hs7751rvoip_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short val;
unsigned short value = (0x0001 << mask_pos[irq]);
/* Set priority in IPR back to original value */
- local_irq_save(flags);
val = ctrl_inw(IRLCNTR3);
val |= value;
ctrl_outw(val, IRLCNTR3);
- local_irq_restore(flags);
}
static void ack_hs7751rvoip_irq(unsigned int irq)
diff --git a/arch/sh/boards/renesas/hs7751rvoip/led.c b/arch/sh/boards/renesas/hs7751rvoip/led.c
deleted file mode 100644
index b6608fff9f38..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/led.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * linux/arch/sh/kernel/setup_hs7751rvoip.c
- *
- * Copyright (C) 2000 Kazumoto Kojima
- *
- * Renesas Technology Sales HS7751RVoIP Support.
- *
- * Modified for HS7751RVoIP by
- * Atom Create Engineering Co., Ltd. 2002.
- * Lineo uSolutions, Inc. 2003.
- */
-
-#include <asm/io.h>
-#include <asm/hs7751rvoip/hs7751rvoip.h>
-
-extern unsigned int debug_counter;
-
-void debug_led_disp(void)
-{
- unsigned short value;
-
- value = (unsigned char)debug_counter++;
- ctrl_outb((0xf0|value), PA_OUTPORTR);
- if (value == 0x0f)
- debug_counter = 0;
-}
diff --git a/arch/sh/boards/renesas/hs7751rvoip/mach.c b/arch/sh/boards/renesas/hs7751rvoip/mach.c
deleted file mode 100644
index caf967f77c61..000000000000
--- a/arch/sh/boards/renesas/hs7751rvoip/mach.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * linux/arch/sh/kernel/mach_hs7751rvoip.c
- *
- * Minor tweak of mach_se.c file to reference hs7751rvoip-specific items.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the Renesas Technology sales HS7751RVoIP
- */
-
-#include <linux/init.h>
-
-#include <asm/machvec.h>
-#include <asm/rtc.h>
-#include <asm/irq.h>
-#include <asm/hs7751rvoip/io.h>
-
-extern void init_hs7751rvoip_IRQ(void);
-extern void *hs7751rvoip_ioremap(unsigned long, unsigned long);
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_hs7751rvoip __initmv = {
- .mv_nr_irqs = 72,
-
- .mv_inb = hs7751rvoip_inb,
- .mv_inw = hs7751rvoip_inw,
- .mv_inl = hs7751rvoip_inl,
- .mv_outb = hs7751rvoip_outb,
- .mv_outw = hs7751rvoip_outw,
- .mv_outl = hs7751rvoip_outl,
-
- .mv_inb_p = hs7751rvoip_inb_p,
- .mv_inw_p = hs7751rvoip_inw,
- .mv_inl_p = hs7751rvoip_inl,
- .mv_outb_p = hs7751rvoip_outb_p,
- .mv_outw_p = hs7751rvoip_outw,
- .mv_outl_p = hs7751rvoip_outl,
-
- .mv_insb = hs7751rvoip_insb,
- .mv_insw = hs7751rvoip_insw,
- .mv_insl = hs7751rvoip_insl,
- .mv_outsb = hs7751rvoip_outsb,
- .mv_outsw = hs7751rvoip_outsw,
- .mv_outsl = hs7751rvoip_outsl,
-
- .mv_ioremap = hs7751rvoip_ioremap,
- .mv_isa_port2addr = hs7751rvoip_isa_port2addr,
- .mv_init_irq = init_hs7751rvoip_IRQ,
-};
-ALIAS_MV(hs7751rvoip)
diff --git a/arch/sh/boards/renesas/hs7751rvoip/pci.c b/arch/sh/boards/renesas/hs7751rvoip/pci.c
index 7e5786b58110..1c0ddee30d21 100644
--- a/arch/sh/boards/renesas/hs7751rvoip/pci.c
+++ b/arch/sh/boards/renesas/hs7751rvoip/pci.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/pci-hs7751rvoip.c
+ * linux/arch/sh/boards/renesas/hs7751rvoip/pci.c
*
* Author: Ian DaSilva (idasilva@mvista.com)
*
diff --git a/arch/sh/boards/renesas/hs7751rvoip/setup.c b/arch/sh/boards/renesas/hs7751rvoip/setup.c
index 29fb5ff70fb5..0414c15c3458 100644
--- a/arch/sh/boards/renesas/hs7751rvoip/setup.c
+++ b/arch/sh/boards/renesas/hs7751rvoip/setup.c
@@ -1,44 +1,38 @@
/*
- * linux/arch/sh/kernel/setup_hs7751rvoip.c
+ * Renesas Technology Sales HS7751RVoIP Support.
*
* Copyright (C) 2000 Kazumoto Kojima
*
- * Renesas Technology Sales HS7751RVoIP Support.
- *
* Modified for HS7751RVoIP by
* Atom Create Engineering Co., Ltd. 2002.
* Lineo uSolutions, Inc. 2003.
*/
-
#include <linux/init.h>
#include <linux/irq.h>
-
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
#include <linux/hdreg.h>
#include <linux/ide.h>
+#include <linux/pm.h>
#include <asm/io.h>
#include <asm/hs7751rvoip/hs7751rvoip.h>
+#include <asm/machvec.h>
+#include <asm/rtc.h>
+#include <asm/irq.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-
-/* defined in mm/ioremap.c */
-extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
-
-unsigned int debug_counter;
-
-const char *get_system_type(void)
+static void __init hs7751rvoip_init_irq(void)
{
- return "HS7751RVoIP";
+#if defined(CONFIG_HS7751RVOIP_CODEC)
+ make_ipr_irq(DMTE0_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+ make_ipr_irq(DMTE1_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+#endif
+
+ init_hs7751rvoip_IRQ();
}
-/*
- * Initialize the board
- */
-void __init platform_setup(void)
+static void hs7751rvoip_power_off(void)
{
- printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
- ctrl_outb(0xf0, PA_OUTPORTR);
- debug_counter = 0;
+ ctrl_outw(ctrl_inw(PA_OUTPORTR) & 0xffdf, PA_OUTPORTR);
}
void *area5_io8_base;
@@ -46,16 +40,15 @@ void *area6_io8_base;
void *area5_io16_base;
void *area6_io16_base;
-int __init cf_init(void)
+static int __init hs7751rvoip_cf_init(void)
{
pgprot_t prot;
- unsigned long paddrbase, psize;
+ unsigned long paddrbase;
/* open I/O area window */
paddrbase = virt_to_phys((void *)(PA_AREA5_IO+0x00000800));
- psize = PAGE_SIZE;
prot = PAGE_KERNEL_PCC(1, _PAGE_PCC_COM16);
- area5_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ area5_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
if (!area5_io16_base) {
printk("allocate_cf_area : can't open CF I/O window!\n");
return -ENOMEM;
@@ -64,19 +57,18 @@ int __init cf_init(void)
/* XXX : do we need attribute and common-memory area also? */
paddrbase = virt_to_phys((void *)PA_AREA6_IO);
- psize = PAGE_SIZE;
#if defined(CONFIG_HS7751RVOIP_CODEC)
prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_COM8);
#else
prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO8);
#endif
- area6_io8_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ area6_io8_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
if (!area6_io8_base) {
printk("allocate_cf_area : can't open CODEC I/O 8bit window!\n");
return -ENOMEM;
}
prot = PAGE_KERNEL_PCC(0, _PAGE_PCC_IO16);
- area6_io16_base = p3_ioremap(paddrbase, psize, prot.pgprot);
+ area6_io16_base = p3_ioremap(paddrbase, PAGE_SIZE, prot.pgprot);
if (!area6_io16_base) {
printk("allocate_cf_area : can't open CODEC I/O 16bit window!\n");
return -ENOMEM;
@@ -85,4 +77,46 @@ int __init cf_init(void)
return 0;
}
-__initcall (cf_init);
+/*
+ * Initialize the board
+ */
+static void __init hs7751rvoip_setup(char **cmdline_p)
+{
+ device_initcall(hs7751rvoip_cf_init);
+
+ ctrl_outb(0xf0, PA_OUTPORTR);
+ pm_power_off = hs7751rvoip_power_off;
+
+ printk(KERN_INFO "Renesas Technology Sales HS7751RVoIP-2 support.\n");
+}
+
+struct sh_machine_vector mv_hs7751rvoip __initmv = {
+ .mv_name = "HS7751RVoIP",
+ .mv_setup = hs7751rvoip_setup,
+ .mv_nr_irqs = 72,
+
+ .mv_inb = hs7751rvoip_inb,
+ .mv_inw = hs7751rvoip_inw,
+ .mv_inl = hs7751rvoip_inl,
+ .mv_outb = hs7751rvoip_outb,
+ .mv_outw = hs7751rvoip_outw,
+ .mv_outl = hs7751rvoip_outl,
+
+ .mv_inb_p = hs7751rvoip_inb_p,
+ .mv_inw_p = hs7751rvoip_inw,
+ .mv_inl_p = hs7751rvoip_inl,
+ .mv_outb_p = hs7751rvoip_outb_p,
+ .mv_outw_p = hs7751rvoip_outw,
+ .mv_outl_p = hs7751rvoip_outl,
+
+ .mv_insb = hs7751rvoip_insb,
+ .mv_insw = hs7751rvoip_insw,
+ .mv_insl = hs7751rvoip_insl,
+ .mv_outsb = hs7751rvoip_outsb,
+ .mv_outsw = hs7751rvoip_outsw,
+ .mv_outsl = hs7751rvoip_outsl,
+
+ .mv_init_irq = hs7751rvoip_init_irq,
+ .mv_ioport_map = hs7751rvoip_ioport_map,
+};
+ALIAS_MV(hs7751rvoip)
diff --git a/arch/sh/boards/renesas/r7780rp/Kconfig b/arch/sh/boards/renesas/r7780rp/Kconfig
new file mode 100644
index 000000000000..c26d9813d239
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/Kconfig
@@ -0,0 +1,14 @@
+if SH_R7780RP
+
+menu "R7780RP options"
+
+config SH_R7780MP
+ bool "R7780MP board support"
+ default y
+ help
+ Selecting this option will enable support for the mass-production
+ version of the R7780RP. If in doubt, say Y.
+
+endmenu
+
+endif
diff --git a/arch/sh/boards/renesas/r7780rp/Makefile b/arch/sh/boards/renesas/r7780rp/Makefile
new file mode 100644
index 000000000000..f1776d027978
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/Makefile
@@ -0,0 +1,6 @@
+#
+# Makefile for the R7780RP-1 specific parts of the kernel
+#
+
+obj-y := setup.o io.o irq.o
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/renesas/r7780rp/io.c b/arch/sh/boards/renesas/r7780rp/io.c
new file mode 100644
index 000000000000..db92d6e6ae99
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/io.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2001 Ian da Silva, Jeremy Siegel
+ * Based largely on io_se.c.
+ *
+ * I/O routine for Renesas Solutions Highlander R7780RP-1
+ *
+ * Initial version only to support LAN access; some
+ * placeholder code from io_r7780rp.c left in with the
+ * expectation of later SuperIO and PCMCIA access.
+ */
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/r7780rp/r7780rp.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+
+static inline unsigned long port2adr(unsigned int port)
+{
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ if (port == 0x3f6)
+ return (PA_AREA5_IO + 0x80c);
+ else
+ return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1));
+ else
+ maybebadio((unsigned long)port);
+
+ return port;
+}
+
+static inline unsigned long port88796l(unsigned int port, int flag)
+{
+ unsigned long addr;
+
+ if (flag)
+ addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1);
+ else
+ addr = PA_AX88796L + ((port - AX88796L_IO_BASE) << 1) + 0x1000;
+
+ return addr;
+}
+
+/* The 7780 R7780RP-1 seems to have everything hooked */
+/* up pretty normally (nothing on high-bytes only...) so this */
+/* shouldn't be needed */
+static inline int shifted_port(unsigned long port)
+{
+ /* For IDE registers, value is not shifted */
+ if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
+ return 0;
+ else
+ return 1;
+}
+
+#if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE)
+#define CHECK_AX88796L_PORT(port) \
+ ((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20)))
+#else
+#define CHECK_AX88796L_PORT(port) (0)
+#endif
+
+/*
+ * General outline: remap really low stuff [eventually] to SuperIO,
+ * stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
+ * is mapped through the PCI IO window. Stuff with high bits (PXSEG)
+ * should be way beyond the window, and is used w/o translation for
+ * compatibility.
+ */
+u8 r7780rp_inb(unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ return ctrl_inw(port88796l(port, 0)) & 0xff;
+ else if (PXSEG(port))
+ return ctrl_inb(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return ctrl_inb(pci_ioaddr(port));
+
+ return ctrl_inw(port2adr(port)) & 0xff;
+}
+
+u8 r7780rp_inb_p(unsigned long port)
+{
+ u8 v;
+
+ if (CHECK_AX88796L_PORT(port))
+ v = ctrl_inw(port88796l(port, 0)) & 0xff;
+ else if (PXSEG(port))
+ v = ctrl_inb(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ v = ctrl_inb(pci_ioaddr(port));
+ else
+ v = ctrl_inw(port2adr(port)) & 0xff;
+
+ ctrl_delay();
+
+ return v;
+}
+
+u16 r7780rp_inw(unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(port);
+ else if (PXSEG(port))
+ return ctrl_inw(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return ctrl_inw(pci_ioaddr(port));
+ else
+ maybebadio(port);
+
+ return 0;
+}
+
+u32 r7780rp_inl(unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(port);
+ else if (PXSEG(port))
+ return ctrl_inl(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return ctrl_inl(pci_ioaddr(port));
+ else
+ maybebadio(port);
+
+ return 0;
+}
+
+void r7780rp_outb(u8 value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ ctrl_outw(value, port88796l(port, 0));
+ else if (PXSEG(port))
+ ctrl_outb(value, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outb(value, pci_ioaddr(port));
+ else
+ ctrl_outw(value, port2adr(port));
+}
+
+void r7780rp_outb_p(u8 value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ ctrl_outw(value, port88796l(port, 0));
+ else if (PXSEG(port))
+ ctrl_outb(value, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outb(value, pci_ioaddr(port));
+ else
+ ctrl_outw(value, port2adr(port));
+
+ ctrl_delay();
+}
+
+void r7780rp_outw(u16 value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(port);
+ else if (PXSEG(port))
+ ctrl_outw(value, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outw(value, pci_ioaddr(port));
+ else
+ maybebadio(port);
+}
+
+void r7780rp_outl(u32 value, unsigned long port)
+{
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(port);
+ else if (PXSEG(port))
+ ctrl_outl(value, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ ctrl_outl(value, pci_ioaddr(port));
+ else
+ maybebadio(port);
+}
+
+void r7780rp_insb(unsigned long port, void *dst, unsigned long count)
+{
+ volatile u16 *p;
+ u8 *buf = dst;
+
+ if (CHECK_AX88796L_PORT(port)) {
+ p = (volatile u16 *)port88796l(port, 0);
+ while (count--)
+ *buf++ = *p & 0xff;
+ } else if (PXSEG(port)) {
+ while (count--)
+ *buf++ = *(volatile u8 *)port;
+ } else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+
+ while (count--)
+ *buf++ = *bp;
+ } else {
+ p = (volatile u16 *)port2adr(port);
+ while (count--)
+ *buf++ = *p & 0xff;
+ }
+}
+
+void r7780rp_insw(unsigned long port, void *dst, unsigned long count)
+{
+ volatile u16 *p;
+ u16 *buf = dst;
+
+ if (CHECK_AX88796L_PORT(port))
+ p = (volatile u16 *)port88796l(port, 1);
+ else if (PXSEG(port))
+ p = (volatile u16 *)port;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ p = (volatile u16 *)pci_ioaddr(port);
+ else
+ p = (volatile u16 *)port2adr(port);
+
+ while (count--)
+ *buf++ = *p;
+}
+
+void r7780rp_insl(unsigned long port, void *dst, unsigned long count)
+{
+ u32 *buf = dst;
+
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+
+ while (count--)
+ *buf++ = *p;
+ } else
+ maybebadio(port);
+}
+
+void r7780rp_outsb(unsigned long port, const void *src, unsigned long count)
+{
+ volatile u16 *p;
+ const u8 *buf = src;
+
+ if (CHECK_AX88796L_PORT(port)) {
+ p = (volatile u16 *)port88796l(port, 0);
+ while (count--)
+ *p = *buf++;
+ } else if (PXSEG(port))
+ while (count--)
+ ctrl_outb(*buf++, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u8 *bp = (volatile u8 *)pci_ioaddr(port);
+
+ while (count--)
+ *bp = *buf++;
+ } else {
+ p = (volatile u16 *)port2adr(port);
+ while (count--)
+ *p = *buf++;
+ }
+}
+
+void r7780rp_outsw(unsigned long port, const void *src, unsigned long count)
+{
+ volatile u16 *p;
+ const u16 *buf = src;
+
+ if (CHECK_AX88796L_PORT(port))
+ p = (volatile u16 *)port88796l(port, 1);
+ else if (PXSEG(port))
+ p = (volatile u16 *)port;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ p = (volatile u16 *)pci_ioaddr(port);
+ else
+ p = (volatile u16 *)port2adr(port);
+
+ while (count--)
+ *p = *buf++;
+}
+
+void r7780rp_outsl(unsigned long port, const void *src, unsigned long count)
+{
+ const u32 *buf = src;
+
+ if (CHECK_AX88796L_PORT(port))
+ maybebadio(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ volatile u32 *p = (volatile u32 *)pci_ioaddr(port);
+
+ while (count--)
+ *p = *buf++;
+ } else
+ maybebadio(port);
+}
+
+void __iomem *r7780rp_ioport_map(unsigned long port, unsigned int size)
+{
+ if (CHECK_AX88796L_PORT(port))
+ return (void __iomem *)port88796l(port, size > 1);
+ else if (PXSEG(port))
+ return (void __iomem *)port;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return (void __iomem *)pci_ioaddr(port);
+
+ return (void __iomem *)port2adr(port);
+}
diff --git a/arch/sh/boards/renesas/r7780rp/irq.c b/arch/sh/boards/renesas/r7780rp/irq.c
new file mode 100644
index 000000000000..b544772cbc72
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/irq.c
@@ -0,0 +1,54 @@
+/*
+ * Renesas Solutions Highlander R7780RP-1 Support.
+ *
+ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 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/init.h>
+#include <linux/irq.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SH_R7780MP
+static int mask_pos[] = {12, 11, 9, 14, 15, 8, 13, 6, 5, 4, 3, 2, 0, 0, 1, 0};
+#else
+static int mask_pos[] = {15, 14, 13, 12, 11, 10, 9, 8, 7, 5, 6, 4, 0, 1, 2, 0};
+#endif
+
+static void enable_r7780rp_irq(unsigned int irq)
+{
+ /* Set priority in IPR back to original value */
+ ctrl_outw(ctrl_inw(IRLCNTR1) | (1 << mask_pos[irq]), IRLCNTR1);
+}
+
+static void disable_r7780rp_irq(unsigned int irq)
+{
+ /* Set the priority in IPR to 0 */
+ ctrl_outw(ctrl_inw(IRLCNTR1) & (0xffff ^ (1 << mask_pos[irq])),
+ IRLCNTR1);
+}
+
+static struct irq_chip r7780rp_irq_chip __read_mostly = {
+ .name = "r7780rp",
+ .mask = disable_r7780rp_irq,
+ .unmask = enable_r7780rp_irq,
+ .mask_ack = disable_r7780rp_irq,
+};
+
+/*
+ * Initialize IRQ setting
+ */
+void __init init_r7780rp_IRQ(void)
+{
+ int i;
+
+ for (i = 0; i < 15; i++) {
+ disable_irq_nosync(i);
+ set_irq_chip_and_handler(i, &r7780rp_irq_chip,
+ handle_level_irq);
+ enable_r7780rp_irq(i);
+ }
+}
diff --git a/arch/sh/boards/renesas/r7780rp/led.c b/arch/sh/boards/renesas/r7780rp/led.c
new file mode 100644
index 000000000000..6a00a257afd2
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/led.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) Atom Create Engineering Co., Ltd.
+ *
+ * May be copied or modified under the terms of GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * This file contains Renesas Solutions HIGHLANDER R7780RP-1 specific LED code.
+ */
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/r7780rp/r7780rp.h>
+
+/* Cycle the LED's in the clasic Knightriger/Sun pattern */
+void heartbeat_r7780rp(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short *p = (volatile unsigned short *)PA_OBLED;
+ static unsigned bit = 0, up = 1;
+ unsigned bit_pos[] = {2, 1, 0, 3, 6, 5, 4, 7};
+
+ cnt += 1;
+ if (cnt < period)
+ return;
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35, f(int)->110
+ */
+ period = 110 - ((300 << FSHIFT)/((avenrun[0]/5) + (3<<FSHIFT)));
+
+ *p = 1 << bit_pos[bit];
+ if (up)
+ if (bit == 7) {
+ bit--;
+ up = 0;
+ } else
+ bit++;
+ else if (bit == 0)
+ up = 1;
+ else
+ bit--;
+}
diff --git a/arch/sh/boards/renesas/r7780rp/setup.c b/arch/sh/boards/renesas/r7780rp/setup.c
new file mode 100644
index 000000000000..b941aa0aa34e
--- /dev/null
+++ b/arch/sh/boards/renesas/r7780rp/setup.c
@@ -0,0 +1,163 @@
+/*
+ * arch/sh/boards/renesas/r7780rp/setup.c
+ *
+ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2005, 2006 Paul Mundt
+ *
+ * Renesas Solutions Highlander R7780RP-1 Support.
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <asm/machvec.h>
+#include <asm/r7780rp/r7780rp.h>
+#include <asm/clock.h>
+#include <asm/io.h>
+
+extern void heartbeat_r7780rp(void);
+extern void init_r7780rp_IRQ(void);
+
+static struct resource m66596_usb_host_resources[] = {
+ [0] = {
+ .start = 0xa4800000,
+ .end = 0xa4ffffff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 6, /* irq number */
+ .end = 6,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device m66596_usb_host_device = {
+ .name = "m66596-hcd",
+ .id = 0,
+ .dev = {
+ .dma_mask = NULL, /* don't use dma */
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(m66596_usb_host_resources),
+ .resource = m66596_usb_host_resources,
+};
+
+static struct platform_device *r7780rp_devices[] __initdata = {
+ &m66596_usb_host_device,
+};
+
+static int __init r7780rp_devices_setup(void)
+{
+ return platform_add_devices(r7780rp_devices,
+ ARRAY_SIZE(r7780rp_devices));
+}
+
+/*
+ * Platform specific clocks
+ */
+static void ivdr_clk_enable(struct clk *clk)
+{
+ ctrl_outw(ctrl_inw(PA_IVDRCTL) | (1 << 8), PA_IVDRCTL);
+}
+
+static void ivdr_clk_disable(struct clk *clk)
+{
+ ctrl_outw(ctrl_inw(PA_IVDRCTL) & ~(1 << 8), PA_IVDRCTL);
+}
+
+static struct clk_ops ivdr_clk_ops = {
+ .enable = ivdr_clk_enable,
+ .disable = ivdr_clk_disable,
+};
+
+static struct clk ivdr_clk = {
+ .name = "ivdr_clk",
+ .ops = &ivdr_clk_ops,
+};
+
+static struct clk *r7780rp_clocks[] = {
+ &ivdr_clk,
+};
+
+static void r7780rp_power_off(void)
+{
+#ifdef CONFIG_SH_R7780MP
+ ctrl_outw(0x0001, PA_POFF);
+#endif
+}
+
+/*
+ * Initialize the board
+ */
+static void __init r7780rp_setup(char **cmdline_p)
+{
+ u16 ver = ctrl_inw(PA_VERREG);
+ int i;
+
+ device_initcall(r7780rp_devices_setup);
+
+ printk(KERN_INFO "Renesas Solutions Highlander R7780RP-1 support.\n");
+
+ printk(KERN_INFO "Board version: %d (revision %d), "
+ "FPGA version: %d (revision %d)\n",
+ (ver >> 12) & 0xf, (ver >> 8) & 0xf,
+ (ver >> 4) & 0xf, ver & 0xf);
+
+ /*
+ * Enable the important clocks right away..
+ */
+ for (i = 0; i < ARRAY_SIZE(r7780rp_clocks); i++) {
+ struct clk *clk = r7780rp_clocks[i];
+
+ clk_register(clk);
+ clk_enable(clk);
+ }
+
+ ctrl_outw(0x0000, PA_OBLED); /* Clear LED. */
+#ifndef CONFIG_SH_R7780MP
+ ctrl_outw(0x0001, PA_SDPOW); /* SD Power ON */
+#endif
+ ctrl_outw(ctrl_inw(PA_IVDRCTL) | 0x0100, PA_IVDRCTL); /* Si13112 */
+
+ pm_power_off = r7780rp_power_off;
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_r7780rp __initmv = {
+ .mv_name = "Highlander R7780RP-1",
+ .mv_setup = r7780rp_setup,
+
+ .mv_nr_irqs = 109,
+
+ .mv_inb = r7780rp_inb,
+ .mv_inw = r7780rp_inw,
+ .mv_inl = r7780rp_inl,
+ .mv_outb = r7780rp_outb,
+ .mv_outw = r7780rp_outw,
+ .mv_outl = r7780rp_outl,
+
+ .mv_inb_p = r7780rp_inb_p,
+ .mv_inw_p = r7780rp_inw,
+ .mv_inl_p = r7780rp_inl,
+ .mv_outb_p = r7780rp_outb_p,
+ .mv_outw_p = r7780rp_outw,
+ .mv_outl_p = r7780rp_outl,
+
+ .mv_insb = r7780rp_insb,
+ .mv_insw = r7780rp_insw,
+ .mv_insl = r7780rp_insl,
+ .mv_outsb = r7780rp_outsb,
+ .mv_outsw = r7780rp_outsw,
+ .mv_outsl = r7780rp_outsl,
+
+ .mv_ioport_map = r7780rp_ioport_map,
+ .mv_init_irq = init_r7780rp_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_r7780rp,
+#endif
+};
+ALIAS_MV(r7780rp)
diff --git a/arch/sh/boards/renesas/rts7751r2d/Kconfig b/arch/sh/boards/renesas/rts7751r2d/Kconfig
new file mode 100644
index 000000000000..7780d1fb13ff
--- /dev/null
+++ b/arch/sh/boards/renesas/rts7751r2d/Kconfig
@@ -0,0 +1,12 @@
+if SH_RTS7751R2D
+
+menu "RTS7751R2D options"
+
+config RTS7751R2D_REV11
+ bool "RTS7751R2D Rev. 1.1 board support"
+ help
+ Selecting this option will support version rev. 1.1.
+endmenu
+
+endif
+
diff --git a/arch/sh/boards/renesas/rts7751r2d/Makefile b/arch/sh/boards/renesas/rts7751r2d/Makefile
index daa53334bdc3..686fc9ea5989 100644
--- a/arch/sh/boards/renesas/rts7751r2d/Makefile
+++ b/arch/sh/boards/renesas/rts7751r2d/Makefile
@@ -1,10 +1,6 @@
#
# Makefile for the RTS7751R2D specific parts of the kernel
#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-
-obj-y := mach.o setup.o io.o irq.o led.o
+obj-y := setup.o io.o irq.o
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/renesas/rts7751r2d/io.c b/arch/sh/boards/renesas/rts7751r2d/io.c
index 123abbbc91e0..135aa0b5e62d 100644
--- a/arch/sh/boards/renesas/rts7751r2d/io.c
+++ b/arch/sh/boards/renesas/rts7751r2d/io.c
@@ -1,6 +1,4 @@
/*
- * linux/arch/sh/kernel/io_rts7751r2d.c
- *
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
@@ -10,17 +8,13 @@
* placeholder code from io_rts7751r2d.c left in with the
* expectation of later SuperIO and PCMCIA access.
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
-#include <asm/io.h>
+#include <linux/pci.h>
#include <asm/rts7751r2d/rts7751r2d.h>
+#include <asm/io.h>
#include <asm/addrspace.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include "../../../drivers/pci/pci-sh7751.h"
-
/*
* The 7751R RTS7751R2D uses the built-in PCI controller (PCIC)
* of the 7751R processor, and has a SuperIO accessible via the PCI.
@@ -28,22 +22,6 @@
* like the other Solution Engine boards.
*/
-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
-#define PCI_IO_AREA SH7751_PCI_IO_BASE
-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
-
-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
-
-#define maybebadio(name,port) \
- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
- #name, (port), (__u32) __builtin_return_address(0))
-
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000);
-}
-
static inline unsigned long port2adr(unsigned int port)
{
if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
@@ -52,7 +30,7 @@ static inline unsigned long port2adr(unsigned int port)
else
return (PA_AREA5_IO + 0x1000 + ((port-0x1f0) << 1));
else
- maybebadio(port2adr, (unsigned long)port);
+ maybebadio((unsigned long)port);
return port;
}
@@ -81,17 +59,6 @@ static inline int shifted_port(unsigned long port)
return 1;
}
-/* In case someone configures the kernel w/o PCI support: in that */
-/* scenario, don't ever bother to check for PCI-window addresses */
-
-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
-#if defined(CONFIG_PCI)
-#define CHECK_SH7751_PCIIO(port) \
- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
-#else
-#define CHECK_SH7751_PCIIO(port) (0)
-#endif
-
#if defined(CONFIG_NE2000) || defined(CONFIG_NE2000_MODULE)
#define CHECK_AX88796L_PORT(port) \
((port >= AX88796L_IO_BASE) && (port < (AX88796L_IO_BASE+0x20)))
@@ -112,8 +79,8 @@ unsigned char rts7751r2d_inb(unsigned long port)
return (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
else if (PXSEG(port))
return *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- return *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return *(volatile unsigned char *)pci_ioaddr(port);
else
return (*(volatile unsigned short *)port2adr(port) & 0xff);
}
@@ -126,11 +93,12 @@ unsigned char rts7751r2d_inb_p(unsigned long port)
v = (*(volatile unsigned short *)port88796l(port, 0)) & 0xff;
else if (PXSEG(port))
v = *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ v = *(volatile unsigned char *)pci_ioaddr(port);
else
v = (*(volatile unsigned short *)port2adr(port) & 0xff);
- delay();
+
+ ctrl_delay();
return v;
}
@@ -138,13 +106,13 @@ unsigned char rts7751r2d_inb_p(unsigned long port)
unsigned short rts7751r2d_inw(unsigned long port)
{
if (CHECK_AX88796L_PORT(port))
- maybebadio(inw, port);
+ maybebadio(port);
else if (PXSEG(port))
return *(volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- return *(volatile unsigned short *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return *(volatile unsigned short *)pci_ioaddr(port);
else
- maybebadio(inw, port);
+ maybebadio(port);
return 0;
}
@@ -152,13 +120,13 @@ unsigned short rts7751r2d_inw(unsigned long port)
unsigned int rts7751r2d_inl(unsigned long port)
{
if (CHECK_AX88796L_PORT(port))
- maybebadio(inl, port);
+ maybebadio(port);
else if (PXSEG(port))
return *(volatile unsigned long *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- return *(volatile unsigned long *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ return *(volatile unsigned long *)pci_ioaddr(port);
else
- maybebadio(inl, port);
+ maybebadio(port);
return 0;
}
@@ -169,8 +137,8 @@ void rts7751r2d_outb(unsigned char value, unsigned long port)
*((volatile unsigned short *)port88796l(port, 0)) = value;
else if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *(volatile unsigned char *)PCI_IOMAP(port) = value;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ *(volatile unsigned char *)pci_ioaddr(port) = value;
else
*(volatile unsigned short *)port2adr(port) = value;
}
@@ -181,143 +149,152 @@ void rts7751r2d_outb_p(unsigned char value, unsigned long port)
*((volatile unsigned short *)port88796l(port, 0)) = value;
else if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *(volatile unsigned char *)PCI_IOMAP(port) = value;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ *(volatile unsigned char *)pci_ioaddr(port) = value;
else
*(volatile unsigned short *)port2adr(port) = value;
- delay();
+
+ ctrl_delay();
}
void rts7751r2d_outw(unsigned short value, unsigned long port)
{
if (CHECK_AX88796L_PORT(port))
- maybebadio(outw, port);
+ maybebadio(port);
else if (PXSEG(port))
*(volatile unsigned short *)port = value;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *(volatile unsigned short *)PCI_IOMAP(port) = value;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ *(volatile unsigned short *)pci_ioaddr(port) = value;
else
- maybebadio(outw, port);
+ maybebadio(port);
}
void rts7751r2d_outl(unsigned int value, unsigned long port)
{
if (CHECK_AX88796L_PORT(port))
- maybebadio(outl, port);
+ maybebadio(port);
else if (PXSEG(port))
*(volatile unsigned long *)port = value;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- *(volatile unsigned long *)PCI_IOMAP(port) = value;
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ *(volatile unsigned long *)pci_ioaddr(port) = value;
else
- maybebadio(outl, port);
+ maybebadio(port);
}
void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count)
{
+ unsigned long a = (unsigned long)addr;
volatile __u8 *bp;
volatile __u16 *p;
- unsigned char *s = addr;
if (CHECK_AX88796L_PORT(port)) {
p = (volatile unsigned short *)port88796l(port, 0);
- while (count--) *s++ = *p & 0xff;
+ while (count--)
+ ctrl_outb(*p & 0xff, a++);
} else if (PXSEG(port))
- while (count--) *s++ = *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- bp = (__u8 *)PCI_IOMAP(port);
- while (count--) *s++ = *bp;
+ while (count--)
+ ctrl_outb(ctrl_inb(port), a++);
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ bp = (__u8 *)pci_ioaddr(port);
+ while (count--)
+ ctrl_outb(*bp, a++);
} else {
p = (volatile unsigned short *)port2adr(port);
- while (count--) *s++ = *p & 0xff;
+ while (count--)
+ ctrl_outb(*p & 0xff, a++);
}
}
void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count)
{
+ unsigned long a = (unsigned long)addr;
volatile __u16 *p;
- __u16 *s = addr;
if (CHECK_AX88796L_PORT(port))
p = (volatile unsigned short *)port88796l(port, 1);
else if (PXSEG(port))
p = (volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- p = (volatile unsigned short *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ p = (volatile unsigned short *)pci_ioaddr(port);
else
p = (volatile unsigned short *)port2adr(port);
- while (count--) *s++ = *p;
+ while (count--)
+ ctrl_outw(*p, a++);
}
void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count)
{
if (CHECK_AX88796L_PORT(port))
- maybebadio(insl, port);
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
- __u32 *s = addr;
-
- while (count--) *s++ = *p;
+ maybebadio(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ unsigned long a = (unsigned long)addr;
+
+ while (count--) {
+ ctrl_outl(ctrl_inl(pci_ioaddr(port)), a);
+ a += 4;
+ }
} else
- maybebadio(insl, port);
+ maybebadio(port);
}
void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count)
{
+ unsigned long a = (unsigned long)addr;
volatile __u8 *bp;
volatile __u16 *p;
- const __u8 *s = addr;
if (CHECK_AX88796L_PORT(port)) {
p = (volatile unsigned short *)port88796l(port, 0);
- while (count--) *p = *s++;
+ while (count--)
+ *p = ctrl_inb(a++);
} else if (PXSEG(port))
- while (count--) *(volatile unsigned char *)port = *s++;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- bp = (__u8 *)PCI_IOMAP(port);
- while (count--) *bp = *s++;
+ while (count--)
+ ctrl_outb(a++, port);
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ bp = (__u8 *)pci_ioaddr(port);
+ while (count--)
+ *bp = ctrl_inb(a++);
} else {
p = (volatile unsigned short *)port2adr(port);
- while (count--) *p = *s++;
+ while (count--)
+ *p = ctrl_inb(a++);
}
}
void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count)
{
+ unsigned long a = (unsigned long)addr;
volatile __u16 *p;
- const __u16 *s = addr;
if (CHECK_AX88796L_PORT(port))
p = (volatile unsigned short *)port88796l(port, 1);
else if (PXSEG(port))
p = (volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port))
- p = (volatile unsigned short *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port))
+ p = (volatile unsigned short *)pci_ioaddr(port);
else
p = (volatile unsigned short *)port2adr(port);
- while (count--) *p = *s++;
+
+ while (count--) {
+ ctrl_outw(*p, a);
+ a += 2;
+ }
}
void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count)
{
if (CHECK_AX88796L_PORT(port))
- maybebadio(outsl, port);
- else if (CHECK_SH7751_PCIIO(port) || shifted_port(port)) {
- volatile __u32 *p = (__u32 *)PCI_IOMAP(port);
- const __u32 *s = addr;
-
- while (count--) *p = *s++;
+ maybebadio(port);
+ else if (is_pci_ioaddr(port) || shifted_port(port)) {
+ unsigned long a = (unsigned long)addr;
+
+ while (count--) {
+ ctrl_outl(ctrl_inl(a), pci_ioaddr(port));
+ a += 4;
+ }
} else
- maybebadio(outsl, port);
-}
-
-void *rts7751r2d_ioremap(unsigned long offset, unsigned long size)
-{
- if (offset >= 0xfd000000)
- return (void *)offset;
- else
- return (void *)P2SEGADDR(offset);
+ maybebadio(port);
}
-EXPORT_SYMBOL(rts7751r2d_ioremap);
unsigned long rts7751r2d_isa_port2addr(unsigned long offset)
{
diff --git a/arch/sh/boards/renesas/rts7751r2d/irq.c b/arch/sh/boards/renesas/rts7751r2d/irq.c
index 154535440bbf..c915e7a3693a 100644
--- a/arch/sh/boards/renesas/rts7751r2d/irq.c
+++ b/arch/sh/boards/renesas/rts7751r2d/irq.c
@@ -41,30 +41,24 @@ static unsigned int startup_rts7751r2d_irq(unsigned int irq)
static void disable_rts7751r2d_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short val;
unsigned short mask = 0xffff ^ (0x0001 << mask_pos[irq]);
/* Set the priority in IPR to 0 */
- local_irq_save(flags);
val = ctrl_inw(IRLCNTR1);
val &= mask;
ctrl_outw(val, IRLCNTR1);
- local_irq_restore(flags);
}
static void enable_rts7751r2d_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short val;
unsigned short value = (0x0001 << mask_pos[irq]);
/* Set priority in IPR back to original value */
- local_irq_save(flags);
val = ctrl_inw(IRLCNTR1);
val |= value;
ctrl_outw(val, IRLCNTR1);
- local_irq_restore(flags);
}
int rts7751r2d_irq_demux(int irq)
diff --git a/arch/sh/boards/renesas/rts7751r2d/led.c b/arch/sh/boards/renesas/rts7751r2d/led.c
index 4d16de71fac1..a7ce66c1e4f0 100644
--- a/arch/sh/boards/renesas/rts7751r2d/led.c
+++ b/arch/sh/boards/renesas/rts7751r2d/led.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/led_rts7751r2d.c
+ * linux/arch/sh/boards/renesas/rts7751r2d/led.c
*
* Copyright (C) Atom Create Engineering Co., Ltd.
*
@@ -12,8 +12,6 @@
#include <asm/io.h>
#include <asm/rts7751r2d/rts7751r2d.h>
-extern unsigned int debug_counter;
-
#ifdef CONFIG_HEARTBEAT
#include <linux/sched.h>
@@ -55,12 +53,3 @@ void rts7751r2d_led(unsigned short value)
ctrl_outw(value, PA_OUTPORT);
}
-void debug_led_disp(void)
-{
- unsigned short value;
-
- value = (unsigned short)debug_counter++;
- rts7751r2d_led(value);
- if (value == 0xff)
- debug_counter = 0;
-}
diff --git a/arch/sh/boards/renesas/rts7751r2d/mach.c b/arch/sh/boards/renesas/rts7751r2d/mach.c
deleted file mode 100644
index 5ed9e97ea197..000000000000
--- a/arch/sh/boards/renesas/rts7751r2d/mach.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * linux/arch/sh/kernel/mach_rts7751r2d.c
- *
- * Minor tweak of mach_se.c file to reference rts7751r2d-specific items.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the Renesas Technology sales RTS7751R2D
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-
-#include <asm/machvec.h>
-#include <asm/rtc.h>
-#include <asm/irq.h>
-#include <asm/rts7751r2d/io.h>
-
-extern void heartbeat_rts7751r2d(void);
-extern void init_rts7751r2d_IRQ(void);
-extern void *rts7751r2d_ioremap(unsigned long, unsigned long);
-extern int rts7751r2d_irq_demux(int irq);
-
-extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
-extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_rts7751r2d __initmv = {
- .mv_nr_irqs = 72,
-
- .mv_inb = rts7751r2d_inb,
- .mv_inw = rts7751r2d_inw,
- .mv_inl = rts7751r2d_inl,
- .mv_outb = rts7751r2d_outb,
- .mv_outw = rts7751r2d_outw,
- .mv_outl = rts7751r2d_outl,
-
- .mv_inb_p = rts7751r2d_inb_p,
- .mv_inw_p = rts7751r2d_inw,
- .mv_inl_p = rts7751r2d_inl,
- .mv_outb_p = rts7751r2d_outb_p,
- .mv_outw_p = rts7751r2d_outw,
- .mv_outl_p = rts7751r2d_outl,
-
- .mv_insb = rts7751r2d_insb,
- .mv_insw = rts7751r2d_insw,
- .mv_insl = rts7751r2d_insl,
- .mv_outsb = rts7751r2d_outsb,
- .mv_outsw = rts7751r2d_outsw,
- .mv_outsl = rts7751r2d_outsl,
-
- .mv_ioremap = rts7751r2d_ioremap,
- .mv_isa_port2addr = rts7751r2d_isa_port2addr,
- .mv_init_irq = init_rts7751r2d_IRQ,
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_rts7751r2d,
-#endif
- .mv_irq_demux = rts7751r2d_irq_demux,
-
-#ifdef CONFIG_USB_OHCI_HCD
- .mv_consistent_alloc = voyagergx_consistent_alloc,
- .mv_consistent_free = voyagergx_consistent_free,
-#endif
-};
-ALIAS_MV(rts7751r2d)
diff --git a/arch/sh/boards/renesas/rts7751r2d/setup.c b/arch/sh/boards/renesas/rts7751r2d/setup.c
index 2587fd1a0240..20597a6e6702 100644
--- a/arch/sh/boards/renesas/rts7751r2d/setup.c
+++ b/arch/sh/boards/renesas/rts7751r2d/setup.c
@@ -1,31 +1,142 @@
/*
- * linux/arch/sh/kernel/setup_rts7751r2d.c
- *
- * Copyright (C) 2000 Kazumoto Kojima
- *
* Renesas Technology Sales RTS7751R2D Support.
*
- * Modified for RTS7751R2D by
- * Atom Create Engineering Co., Ltd. 2002.
+ * Copyright (C) 2002 Atom Create Engineering Co., Ltd.
+ * Copyright (C) 2004 - 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/serial_8250.h>
+#include <linux/pm.h>
#include <asm/io.h>
-#include <asm/rts7751r2d/rts7751r2d.h>
+#include <asm/machvec.h>
+#include <asm/mach/rts7751r2d.h>
+#include <asm/voyagergx.h>
+
+extern void heartbeat_rts7751r2d(void);
+extern void init_rts7751r2d_IRQ(void);
+extern int rts7751r2d_irq_demux(int irq);
+
+extern void *voyagergx_consistent_alloc(struct device *, size_t, dma_addr_t *, gfp_t);
+extern int voyagergx_consistent_free(struct device *, size_t, void *, dma_addr_t);
+
+static struct plat_serial8250_port uart_platform_data[] = {
+ {
+ .membase = (void *)VOYAGER_UART_BASE,
+ .mapbase = VOYAGER_UART_BASE,
+ .iotype = UPIO_MEM,
+ .irq = VOYAGER_UART0_IRQ,
+ .flags = UPF_BOOT_AUTOCONF,
+ .regshift = 2,
+ .uartclk = (9600 * 16),
+ }, {
+ .flags = 0,
+ },
+};
+
+static void __init voyagergx_serial_init(void)
+{
+ unsigned long val;
+
+ /*
+ * GPIO Control
+ */
+ val = inl(GPIO_MUX_HIGH);
+ val |= 0x00001fe0;
+ outl(val, GPIO_MUX_HIGH);
+
+ /*
+ * Power Mode Gate
+ */
+ val = inl(POWER_MODE0_GATE);
+ val |= (POWER_MODE0_GATE_U0 | POWER_MODE0_GATE_U1);
+ outl(val, POWER_MODE0_GATE);
+
+ val = inl(POWER_MODE1_GATE);
+ val |= (POWER_MODE1_GATE_U0 | POWER_MODE1_GATE_U1);
+ outl(val, POWER_MODE1_GATE);
+}
+
+static struct platform_device uart_device = {
+ .name = "serial8250",
+ .id = -1,
+ .dev = {
+ .platform_data = uart_platform_data,
+ },
+};
+
+static struct platform_device *rts7751r2d_devices[] __initdata = {
+ &uart_device,
+};
-unsigned int debug_counter;
+static int __init rts7751r2d_devices_setup(void)
+{
+ return platform_add_devices(rts7751r2d_devices,
+ ARRAY_SIZE(rts7751r2d_devices));
+}
-const char *get_system_type(void)
+static void rts7751r2d_power_off(void)
{
- return "RTS7751R2D";
+ ctrl_outw(0x0001, PA_POWOFF);
}
/*
* Initialize the board
*/
-void __init platform_setup(void)
+static void __init rts7751r2d_setup(char **cmdline_p)
{
- printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n");
+ device_initcall(rts7751r2d_devices_setup);
+
ctrl_outw(0x0000, PA_OUTPORT);
- debug_counter = 0;
+ pm_power_off = rts7751r2d_power_off;
+
+ voyagergx_serial_init();
+
+ printk(KERN_INFO "Renesas Technology Sales RTS7751R2D support.\n");
}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_rts7751r2d __initmv = {
+ .mv_name = "RTS7751R2D",
+ .mv_setup = rts7751r2d_setup,
+ .mv_nr_irqs = 72,
+
+ .mv_inb = rts7751r2d_inb,
+ .mv_inw = rts7751r2d_inw,
+ .mv_inl = rts7751r2d_inl,
+ .mv_outb = rts7751r2d_outb,
+ .mv_outw = rts7751r2d_outw,
+ .mv_outl = rts7751r2d_outl,
+
+ .mv_inb_p = rts7751r2d_inb_p,
+ .mv_inw_p = rts7751r2d_inw,
+ .mv_inl_p = rts7751r2d_inl,
+ .mv_outb_p = rts7751r2d_outb_p,
+ .mv_outw_p = rts7751r2d_outw,
+ .mv_outl_p = rts7751r2d_outl,
+
+ .mv_insb = rts7751r2d_insb,
+ .mv_insw = rts7751r2d_insw,
+ .mv_insl = rts7751r2d_insl,
+ .mv_outsb = rts7751r2d_outsb,
+ .mv_outsw = rts7751r2d_outsw,
+ .mv_outsl = rts7751r2d_outsl,
+
+ .mv_init_irq = init_rts7751r2d_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_rts7751r2d,
+#endif
+ .mv_irq_demux = rts7751r2d_irq_demux,
+
+#ifdef CONFIG_USB_SM501
+ .mv_consistent_alloc = voyagergx_consistent_alloc,
+ .mv_consistent_free = voyagergx_consistent_free,
+#endif
+};
+ALIAS_MV(rts7751r2d)
diff --git a/arch/sh/boards/renesas/sh7710voipgw/Makefile b/arch/sh/boards/renesas/sh7710voipgw/Makefile
new file mode 100644
index 000000000000..77037567633b
--- /dev/null
+++ b/arch/sh/boards/renesas/sh7710voipgw/Makefile
@@ -0,0 +1 @@
+obj-y := setup.o
diff --git a/arch/sh/boards/renesas/sh7710voipgw/setup.c b/arch/sh/boards/renesas/sh7710voipgw/setup.c
new file mode 100644
index 000000000000..e57e7afab8c6
--- /dev/null
+++ b/arch/sh/boards/renesas/sh7710voipgw/setup.c
@@ -0,0 +1,109 @@
+/*
+ * Renesas Technology SH7710 VoIP Gateway
+ *
+ * Copyright (C) 2006 Ranjit Deshpande
+ * Kenati Technologies Inc.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+#include <linux/init.h>
+#include <asm/machvec.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/*
+ * Initialize IRQ setting
+ */
+static void __init sh7710voipgw_init_irq(void)
+{
+ /* Disable all interrupts in IPR registers */
+ ctrl_outw(0x0, INTC_IPRA);
+ ctrl_outw(0x0, INTC_IPRB);
+ ctrl_outw(0x0, INTC_IPRC);
+ ctrl_outw(0x0, INTC_IPRD);
+ ctrl_outw(0x0, INTC_IPRE);
+ ctrl_outw(0x0, INTC_IPRF);
+ ctrl_outw(0x0, INTC_IPRG);
+ ctrl_outw(0x0, INTC_IPRH);
+ ctrl_outw(0x0, INTC_IPRI);
+
+ /* Ack all interrupt sources in the IRR0 register */
+ ctrl_outb(0x3f, INTC_IRR0);
+
+ /* Use IRQ0 - IRQ3 as active low interrupt lines i.e. disable
+ * IRL mode.
+ */
+ ctrl_outw(0x2aa, INTC_ICR1);
+
+ /* Now make IPR interrupts */
+ make_ipr_irq(TIMER2_IRQ, TIMER2_IPR_ADDR,
+ TIMER2_IPR_POS, TIMER2_PRIORITY);
+ make_ipr_irq(WDT_IRQ, WDT_IPR_ADDR, WDT_IPR_POS, WDT_PRIORITY);
+
+ /* SCIF0 */
+ make_ipr_irq(SCIF0_ERI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS,
+ SCIF0_PRIORITY);
+ make_ipr_irq(SCIF0_RXI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS,
+ SCIF0_PRIORITY);
+ make_ipr_irq(SCIF0_BRI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS,
+ SCIF0_PRIORITY);
+ make_ipr_irq(SCIF0_TXI_IRQ, SCIF0_IPR_ADDR, SCIF0_IPR_POS,
+ SCIF0_PRIORITY);
+
+ /* DMAC-1 */
+ make_ipr_irq(DMTE0_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+ make_ipr_irq(DMTE1_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+ make_ipr_irq(DMTE2_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+ make_ipr_irq(DMTE3_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
+
+ /* DMAC-2 */
+ make_ipr_irq(DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY);
+ make_ipr_irq(DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY);
+
+ /* IPSEC */
+ make_ipr_irq(IPSEC_IRQ, IPSEC_IPR_ADDR, IPSEC_IPR_POS, IPSEC_PRIORITY);
+
+ /* EDMAC */
+ make_ipr_irq(EDMAC0_IRQ, EDMAC0_IPR_ADDR, EDMAC0_IPR_POS,
+ EDMAC0_PRIORITY);
+ make_ipr_irq(EDMAC1_IRQ, EDMAC1_IPR_ADDR, EDMAC1_IPR_POS,
+ EDMAC1_PRIORITY);
+ make_ipr_irq(EDMAC2_IRQ, EDMAC2_IPR_ADDR, EDMAC2_IPR_POS,
+ EDMAC2_PRIORITY);
+
+ /* SIOF0 */
+ make_ipr_irq(SIOF0_ERI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS,
+ SIOF0_PRIORITY);
+ make_ipr_irq(SIOF0_TXI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS,
+ SIOF0_PRIORITY);
+ make_ipr_irq(SIOF0_RXI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS,
+ SIOF0_PRIORITY);
+ make_ipr_irq(SIOF0_CCI_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS,
+ SIOF0_PRIORITY);
+
+ /* SIOF1 */
+ make_ipr_irq(SIOF1_ERI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS,
+ SIOF1_PRIORITY);
+ make_ipr_irq(SIOF1_TXI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS,
+ SIOF1_PRIORITY);
+ make_ipr_irq(SIOF1_RXI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS,
+ SIOF1_PRIORITY);
+ make_ipr_irq(SIOF1_CCI_IRQ, SIOF1_IPR_ADDR, SIOF1_IPR_POS,
+ SIOF1_PRIORITY);
+
+ /* SLIC IRQ's */
+ make_ipr_irq(IRQ1_IRQ, IRQ1_IPR_ADDR, IRQ1_IPR_POS, IRQ1_PRIORITY);
+ make_ipr_irq(IRQ2_IRQ, IRQ2_IPR_ADDR, IRQ2_IPR_POS, IRQ2_PRIORITY);
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_sh7710voipgw __initmv = {
+ .mv_name = "SH7710 VoIP Gateway",
+ .mv_nr_irqs = 104,
+ .mv_init_irq = sh7710voipgw_init_irq,
+};
+ALIAS_MV(sh7710voipgw)
diff --git a/arch/sh/boards/renesas/systemh/io.c b/arch/sh/boards/renesas/systemh/io.c
index cf979011aa94..1b767e1a1428 100644
--- a/arch/sh/boards/renesas/systemh/io.c
+++ b/arch/sh/boards/renesas/systemh/io.c
@@ -1,70 +1,29 @@
/*
- * linux/arch/sh/boards/systemh/io.c
+ * linux/arch/sh/boards/renesas/systemh/io.c
*
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
* I/O routine for Hitachi 7751 Systemh.
- *
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
-#include <asm/systemh/7751systemh.h>
+#include <linux/pci.h>
+#include <asm/systemh7751.h>
#include <asm/addrspace.h>
#include <asm/io.h>
-#include <linux/pci.h>
-#include "../../drivers/pci/pci-sh7751.h"
-
-/*
- * The 7751 SystemH Engine uses the built-in PCI controller (PCIC)
- * of the 7751 processor, and has a SuperIO accessible on its memory
- * bus.
- */
-
-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
-#define PCI_IO_AREA SH7751_PCI_IO_BASE
-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
-
-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
#define ETHER_IOMAP(adr) (0xB3000000 + (adr)) /*map to 16bits access area
of smc lan chip*/
-
-#define maybebadio(name,port) \
- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
- #name, (port), (__u32) __builtin_return_address(0))
-
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000);
-}
-
static inline volatile __u16 *
port2adr(unsigned int port)
{
if (port >= 0x2000)
return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-#if 0
- else
- return (volatile __u16 *) (PA_SUPERIO + (port << 1));
-#endif
- maybebadio(name,(unsigned long)port);
+ maybebadio((unsigned long)port);
return (volatile __u16*)port;
}
-/* In case someone configures the kernel w/o PCI support: in that */
-/* scenario, don't ever bother to check for PCI-window addresses */
-
-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
-#if defined(CONFIG_PCI)
-#define CHECK_SH7751_PCIIO(port) \
- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
-#else
-#define CHECK_SH7751_PCIIO(port) (0)
-#endif
-
/*
* General outline: remap really low stuff [eventually] to SuperIO,
* stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
@@ -76,8 +35,8 @@ unsigned char sh7751systemh_inb(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned char *)pci_ioaddr(port);
else if (port <= 0x3F1)
return *(volatile unsigned char *)ETHER_IOMAP(port);
else
@@ -90,13 +49,13 @@ unsigned char sh7751systemh_inb_p(unsigned long port)
if (PXSEG(port))
v = *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port))
- v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ v = *(volatile unsigned char *)pci_ioaddr(port);
else if (port <= 0x3F1)
v = *(volatile unsigned char *)ETHER_IOMAP(port);
else
v = (*port2adr(port))&0xff;
- delay();
+ ctrl_delay();
return v;
}
@@ -104,14 +63,14 @@ unsigned short sh7751systemh_inw(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned short *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned short *)pci_ioaddr(port);
else if (port >= 0x2000)
return *port2adr(port);
else if (port <= 0x3F1)
return *(volatile unsigned int *)ETHER_IOMAP(port);
else
- maybebadio(inw, port);
+ maybebadio(port);
return 0;
}
@@ -119,14 +78,14 @@ unsigned int sh7751systemh_inl(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned long *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned int *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned int *)pci_ioaddr(port);
else if (port >= 0x2000)
return *port2adr(port);
else if (port <= 0x3F1)
return *(volatile unsigned int *)ETHER_IOMAP(port);
else
- maybebadio(inl, port);
+ maybebadio(port);
return 0;
}
@@ -135,8 +94,8 @@ void sh7751systemh_outb(unsigned char value, unsigned long port)
if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned char*)pci_ioaddr(port)) = value;
else if (port <= 0x3F1)
*(volatile unsigned char *)ETHER_IOMAP(port) = value;
else
@@ -147,37 +106,37 @@ void sh7751systemh_outb_p(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned char*)pci_ioaddr(port)) = value;
else if (port <= 0x3F1)
*(volatile unsigned char *)ETHER_IOMAP(port) = value;
else
*(port2adr(port)) = value;
- delay();
+ ctrl_delay();
}
void sh7751systemh_outw(unsigned short value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned short *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned short *)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned short *)pci_ioaddr(port)) = value;
else if (port >= 0x2000)
*port2adr(port) = value;
else if (port <= 0x3F1)
*(volatile unsigned short *)ETHER_IOMAP(port) = value;
else
- maybebadio(outw, port);
+ maybebadio(port);
}
void sh7751systemh_outl(unsigned int value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned long *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned long*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned long*)pci_ioaddr(port)) = value;
else
- maybebadio(outl, port);
+ maybebadio(port);
}
void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count)
@@ -194,7 +153,7 @@ void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count)
void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count)
{
- maybebadio(insl, port);
+ maybebadio(port);
}
void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count)
@@ -211,73 +170,5 @@ void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long cou
void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count)
{
- maybebadio(outsw, port);
-}
-
-/* For read/write calls, just copy generic (pass-thru); PCIMBR is */
-/* already set up. For a larger memory space, these would need to */
-/* reset PCIMBR as needed on a per-call basis... */
-
-unsigned char sh7751systemh_readb(unsigned long addr)
-{
- return *(volatile unsigned char*)addr;
-}
-
-unsigned short sh7751systemh_readw(unsigned long addr)
-{
- return *(volatile unsigned short*)addr;
-}
-
-unsigned int sh7751systemh_readl(unsigned long addr)
-{
- return *(volatile unsigned long*)addr;
-}
-
-void sh7751systemh_writeb(unsigned char b, unsigned long addr)
-{
- *(volatile unsigned char*)addr = b;
-}
-
-void sh7751systemh_writew(unsigned short b, unsigned long addr)
-{
- *(volatile unsigned short*)addr = b;
-}
-
-void sh7751systemh_writel(unsigned int b, unsigned long addr)
-{
- *(volatile unsigned long*)addr = b;
-}
-
-
-
-/* Map ISA bus address to the real address. Only for PCMCIA. */
-
-/* ISA page descriptor. */
-static __u32 sh_isa_memmap[256];
-
-#if 0
-static int
-sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
-{
- int idx;
-
- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
- return -1;
-
- idx = start >> 12;
- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
- start, length, offset, idx, sh_isa_memmap[idx]);
- return 0;
-}
-#endif
-
-unsigned long
-sh7751systemh_isa_port2addr(unsigned long offset)
-{
- int idx;
-
- idx = (offset >> 12) & 0xff;
- offset &= 0xfff;
- return sh_isa_memmap[idx] + offset;
+ maybebadio(port);
}
diff --git a/arch/sh/boards/renesas/systemh/irq.c b/arch/sh/boards/renesas/systemh/irq.c
index 8372d967f601..0ba2fe674c47 100644
--- a/arch/sh/boards/renesas/systemh/irq.c
+++ b/arch/sh/boards/renesas/systemh/irq.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/boards/systemh/irq.c
+ * linux/arch/sh/boards/renesas/systemh/irq.c
*
* Copyright (C) 2000 Kazumoto Kojima
*
@@ -15,7 +15,7 @@
#include <linux/hdreg.h>
#include <linux/ide.h>
#include <asm/io.h>
-#include <asm/mach/7751systemh.h>
+#include <asm/systemh7751.h>
#include <asm/smc37c93x.h>
/* address of external interrupt mask register
@@ -57,12 +57,9 @@ static void shutdown_systemh_irq(unsigned int irq)
static void disable_systemh_irq(unsigned int irq)
{
if (systemh_irq_mask_register) {
- unsigned long flags;
unsigned long val, mask = 0x01 << 1;
/* Clear the "irq"th bit in the mask and set it in the request */
- local_irq_save(flags);
-
val = ctrl_inl((unsigned long)systemh_irq_mask_register);
val &= ~mask;
ctrl_outl(val, (unsigned long)systemh_irq_mask_register);
@@ -70,23 +67,18 @@ static void disable_systemh_irq(unsigned int irq)
val = ctrl_inl((unsigned long)systemh_irq_request_register);
val |= mask;
ctrl_outl(val, (unsigned long)systemh_irq_request_register);
-
- local_irq_restore(flags);
}
}
static void enable_systemh_irq(unsigned int irq)
{
if (systemh_irq_mask_register) {
- unsigned long flags;
unsigned long val, mask = 0x01 << 1;
/* Set "irq"th bit in the mask register */
- local_irq_save(flags);
val = ctrl_inl((unsigned long)systemh_irq_mask_register);
val |= mask;
ctrl_outl(val, (unsigned long)systemh_irq_mask_register);
- local_irq_restore(flags);
}
}
diff --git a/arch/sh/boards/renesas/systemh/setup.c b/arch/sh/boards/renesas/systemh/setup.c
index 826fa3d7669c..936117659b74 100644
--- a/arch/sh/boards/renesas/systemh/setup.c
+++ b/arch/sh/boards/renesas/systemh/setup.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/boards/systemh/setup.c
+ * linux/arch/sh/boards/renesas/systemh/setup.c
*
* Copyright (C) 2000 Kazumoto Kojima
* Copyright (C) 2003 Paul Mundt
@@ -15,28 +15,21 @@
* for more details.
*/
#include <linux/init.h>
-#include <asm/mach/7751systemh.h>
-#include <asm/mach/io.h>
#include <asm/machvec.h>
+#include <asm/systemh7751.h>
extern void make_systemh_irq(unsigned int irq);
-const char *get_system_type(void)
-{
- return "7751 SystemH";
-}
-
/*
* Initialize IRQ setting
*/
-void __init init_7751systemh_IRQ(void)
+static void __init sh7751systemh_init_irq(void)
{
-/* make_ipr_irq(10, BCR_ILCRD, 1, 0x0f-10); LAN */
-/* make_ipr_irq(14, BCR_ILCRA, 2, 0x0f-4); */
make_systemh_irq(0xb); /* Ethernet interrupt */
}
struct sh_machine_vector mv_7751systemh __initmv = {
+ .mv_name = "7751 SystemH",
.mv_nr_irqs = 72,
.mv_inb = sh7751systemh_inb,
@@ -60,21 +53,6 @@ struct sh_machine_vector mv_7751systemh __initmv = {
.mv_outsw = sh7751systemh_outsw,
.mv_outsl = sh7751systemh_outsl,
- .mv_readb = sh7751systemh_readb,
- .mv_readw = sh7751systemh_readw,
- .mv_readl = sh7751systemh_readl,
- .mv_writeb = sh7751systemh_writeb,
- .mv_writew = sh7751systemh_writew,
- .mv_writel = sh7751systemh_writel,
-
- .mv_isa_port2addr = sh7751systemh_isa_port2addr,
-
- .mv_init_irq = init_7751systemh_IRQ,
+ .mv_init_irq = sh7751systemh_init_irq,
};
ALIAS_MV(7751systemh)
-
-int __init platform_setup(void)
-{
- return 0;
-}
-
diff --git a/arch/sh/boards/saturn/setup.c b/arch/sh/boards/saturn/setup.c
index bea6c572ad82..a3a37c9aad2e 100644
--- a/arch/sh/boards/saturn/setup.c
+++ b/arch/sh/boards/saturn/setup.c
@@ -9,22 +9,17 @@
*/
#include <linux/kernel.h>
#include <linux/init.h>
-
#include <asm/io.h>
#include <asm/machvec.h>
#include <asm/mach/io.h>
extern int saturn_irq_demux(int irq_nr);
-const char *get_system_type(void)
-{
- return "Sega Saturn";
-}
-
/*
* The Machine Vector
*/
struct sh_machine_vector mv_saturn __initmv = {
+ .mv_name = "Sega Saturn",
.mv_nr_irqs = 80, /* Fix this later */
.mv_isa_port2addr = saturn_isa_port2addr,
@@ -33,11 +28,4 @@ struct sh_machine_vector mv_saturn __initmv = {
.mv_ioremap = saturn_ioremap,
.mv_iounmap = saturn_iounmap,
};
-
ALIAS_MV(saturn)
-
-int __init platform_setup(void)
-{
- return 0;
-}
-
diff --git a/arch/sh/boards/se/7300/io.c b/arch/sh/boards/se/7300/io.c
index f449a94ddffd..8a03d7a52a7c 100644
--- a/arch/sh/boards/se/7300/io.c
+++ b/arch/sh/boards/se/7300/io.c
@@ -9,8 +9,8 @@
*/
#include <linux/kernel.h>
-#include <asm/mach/se7300.h>
#include <asm/io.h>
+#include <asm/se7300.h>
#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
@@ -99,6 +99,7 @@ bad_outb(struct iop *p, unsigned char value, unsigned long port)
badio(inw, port);
}
+#ifdef CONFIG_SMC91X
/* MSTLANEX01 LAN at 0xb400:0000 */
static struct iop laniop = {
.start = 0x300,
@@ -110,6 +111,7 @@ static struct iop laniop = {
.outb = simple_outb,
.outw = simple_outw,
};
+#endif
/* NE2000 pc card NIC */
static struct iop neiop = {
@@ -123,6 +125,7 @@ static struct iop neiop = {
.outw = simple_outw,
};
+#ifdef CONFIG_IDE
/* CF in CF slot */
static struct iop cfiop = {
.base = 0xb0600000,
@@ -132,12 +135,13 @@ static struct iop cfiop = {
.outb = pcc_outb,
.outw = simple_outw,
};
+#endif
static __inline__ struct iop *
port2iop(unsigned long port)
{
if (0) ;
-#if defined(CONFIG_SMC91111)
+#if defined(CONFIG_SMC91X)
else if (laniop.check(&laniop, port))
return &laniop;
#endif
diff --git a/arch/sh/boards/se/7300/irq.c b/arch/sh/boards/se/7300/irq.c
index 216a78d1a108..ad1034f98a29 100644
--- a/arch/sh/boards/se/7300/irq.c
+++ b/arch/sh/boards/se/7300/irq.c
@@ -11,7 +11,7 @@
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/mach/se7300.h>
+#include <asm/se7300.h>
/*
* Initialize IRQ setting
diff --git a/arch/sh/boards/se/7300/led.c b/arch/sh/boards/se/7300/led.c
index ad51f0a9c1e3..4d03bb7774be 100644
--- a/arch/sh/boards/se/7300/led.c
+++ b/arch/sh/boards/se/7300/led.c
@@ -12,24 +12,10 @@
*/
#include <linux/sched.h>
-#include <asm/mach/se7300.h>
-
-static void
-mach_led(int position, int value)
-{
- volatile unsigned short *p = (volatile unsigned short *) PA_LED;
-
- if (value) {
- *p |= (1 << 8);
- } else {
- *p &= ~(1 << 8);
- }
-}
-
+#include <asm/se7300.h>
/* Cycle the LED's in the clasic Knightrider/Sun pattern */
-void
-heartbeat_7300se(void)
+void heartbeat_7300se(void)
{
static unsigned int cnt = 0, period = 0;
volatile unsigned short *p = (volatile unsigned short *) PA_LED;
diff --git a/arch/sh/boards/se/7300/setup.c b/arch/sh/boards/se/7300/setup.c
index ebcd98d4c081..6f082a722d42 100644
--- a/arch/sh/boards/se/7300/setup.c
+++ b/arch/sh/boards/se/7300/setup.c
@@ -9,23 +9,16 @@
#include <linux/init.h>
#include <asm/machvec.h>
-#include <asm/machvec_init.h>
-#include <asm/mach/io.h>
+#include <asm/se7300.h>
void heartbeat_7300se(void);
void init_7300se_IRQ(void);
-const char *
-get_system_type(void)
-{
- return "SolutionEngine 7300";
-}
-
/*
* The Machine Vector
*/
-
struct sh_machine_vector mv_7300se __initmv = {
+ .mv_name = "SolutionEngine 7300",
.mv_nr_irqs = 109,
.mv_inb = sh7300se_inb,
.mv_inw = sh7300se_inw,
@@ -53,13 +46,4 @@ struct sh_machine_vector mv_7300se __initmv = {
.mv_heartbeat = heartbeat_7300se,
#endif
};
-
ALIAS_MV(7300se)
-/*
- * Initialize the board
- */
-void __init
-platform_setup(void)
-{
-
-}
diff --git a/arch/sh/boards/se/73180/io.c b/arch/sh/boards/se/73180/io.c
index 755df5ac4a4e..72715575458b 100644
--- a/arch/sh/boards/se/73180/io.c
+++ b/arch/sh/boards/se/73180/io.c
@@ -99,6 +99,7 @@ bad_outb(struct iop *p, unsigned char value, unsigned long port)
badio(inw, port);
}
+#ifdef CONFIG_SMC91X
/* MSTLANEX01 LAN at 0xb400:0000 */
static struct iop laniop = {
.start = 0x300,
@@ -110,6 +111,7 @@ static struct iop laniop = {
.outb = simple_outb,
.outw = simple_outw,
};
+#endif
/* NE2000 pc card NIC */
static struct iop neiop = {
@@ -123,6 +125,7 @@ static struct iop neiop = {
.outw = simple_outw,
};
+#ifdef CONFIG_IDE
/* CF in CF slot */
static struct iop cfiop = {
.base = 0xb0600000,
@@ -132,12 +135,13 @@ static struct iop cfiop = {
.outb = pcc_outb,
.outw = simple_outw,
};
+#endif
static __inline__ struct iop *
port2iop(unsigned long port)
{
if (0) ;
-#if defined(CONFIG_SMC91111)
+#if defined(CONFIG_SMC91X)
else if (laniop.check(&laniop, port))
return &laniop;
#endif
diff --git a/arch/sh/boards/se/73180/irq.c b/arch/sh/boards/se/73180/irq.c
index 4344d0ef24aa..2c62b8ea350e 100644
--- a/arch/sh/boards/se/73180/irq.c
+++ b/arch/sh/boards/se/73180/irq.c
@@ -7,7 +7,6 @@
* Modified for SH-Mobile SolutionEngine 73180 Support
* by YOSHII Takashi <yoshii-takashi@hitachi-ul.co.jp>
*
- *
*/
#include <linux/init.h>
@@ -17,14 +16,6 @@
#include <asm/mach/se73180.h>
static int
-intreq2irq(int i)
-{
- if (i == 5)
- return 10;
- return 32 + 7 - i;
-}
-
-static int
irq2intreq(int irq)
{
if (irq == 10)
diff --git a/arch/sh/boards/se/73180/led.c b/arch/sh/boards/se/73180/led.c
index 610439fde6ee..4b72e9a3ead9 100644
--- a/arch/sh/boards/se/73180/led.c
+++ b/arch/sh/boards/se/73180/led.c
@@ -14,21 +14,8 @@
#include <linux/sched.h>
#include <asm/mach/se73180.h>
-static void
-mach_led(int position, int value)
-{
- volatile unsigned short *p = (volatile unsigned short *) PA_LED;
-
- if (value) {
- *p |= (1 << LED_SHIFT);
- } else {
- *p &= ~(1 << LED_SHIFT);
- }
-}
-
/* Cycle the LED's in the clasic Knightrider/Sun pattern */
-void
-heartbeat_73180se(void)
+void heartbeat_73180se(void)
{
static unsigned int cnt = 0, period = 0;
volatile unsigned short *p = (volatile unsigned short *) PA_LED;
diff --git a/arch/sh/boards/se/73180/setup.c b/arch/sh/boards/se/73180/setup.c
index cdb7b5f8d942..b38ef50a160a 100644
--- a/arch/sh/boards/se/73180/setup.c
+++ b/arch/sh/boards/se/73180/setup.c
@@ -11,23 +11,17 @@
#include <linux/init.h>
#include <asm/machvec.h>
-#include <asm/machvec_init.h>
-#include <asm/mach/io.h>
+#include <asm/se73180.h>
+#include <asm/irq.h>
void heartbeat_73180se(void);
void init_73180se_IRQ(void);
-const char *
-get_system_type(void)
-{
- return "SolutionEngine 73180";
-}
-
/*
* The Machine Vector
*/
-
struct sh_machine_vector mv_73180se __initmv = {
+ .mv_name = "SolutionEngine 73180",
.mv_nr_irqs = 108,
.mv_inb = sh73180se_inb,
.mv_inw = sh73180se_inw,
@@ -51,17 +45,9 @@ struct sh_machine_vector mv_73180se __initmv = {
.mv_outsl = sh73180se_outsl,
.mv_init_irq = init_73180se_IRQ,
+ .mv_irq_demux = shmse_irq_demux,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_73180se,
#endif
};
-
ALIAS_MV(73180se)
-/*
- * Initialize the board
- */
-void __init
-platform_setup(void)
-{
-
-}
diff --git a/arch/sh/boards/se/7343/Makefile b/arch/sh/boards/se/7343/Makefile
new file mode 100644
index 000000000000..4291069c0b4f
--- /dev/null
+++ b/arch/sh/boards/se/7343/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the 7343 SolutionEngine specific parts of the kernel
+#
+
+obj-y := setup.o io.o irq.o
+
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/se/7343/io.c b/arch/sh/boards/se/7343/io.c
new file mode 100644
index 000000000000..3a6d11424938
--- /dev/null
+++ b/arch/sh/boards/se/7343/io.c
@@ -0,0 +1,273 @@
+/*
+ * arch/sh/boards/se/7343/io.c
+ *
+ * I/O routine for SH-Mobile3AS 7343 SolutionEngine.
+ *
+ */
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <asm/mach/se7343.h>
+
+#define badio(fn, a) panic("bad i/o operation %s for %08lx.", #fn, a)
+
+struct iop {
+ unsigned long start, end;
+ unsigned long base;
+ struct iop *(*check) (struct iop * p, unsigned long port);
+ unsigned char (*inb) (struct iop * p, unsigned long port);
+ unsigned short (*inw) (struct iop * p, unsigned long port);
+ void (*outb) (struct iop * p, unsigned char value, unsigned long port);
+ void (*outw) (struct iop * p, unsigned short value, unsigned long port);
+};
+
+struct iop *
+simple_check(struct iop *p, unsigned long port)
+{
+ static int count;
+
+ if (count < 100)
+ count++;
+
+ port &= 0xFFFF;
+
+ if ((p->start <= port) && (port <= p->end))
+ return p;
+ else
+ badio(check, port);
+}
+
+struct iop *
+ide_check(struct iop *p, unsigned long port)
+{
+ if (((0x1f0 <= port) && (port <= 0x1f7)) || (port == 0x3f7))
+ return p;
+ return NULL;
+}
+
+unsigned char
+simple_inb(struct iop *p, unsigned long port)
+{
+ return *(unsigned char *) (p->base + port);
+}
+
+unsigned short
+simple_inw(struct iop *p, unsigned long port)
+{
+ return *(unsigned short *) (p->base + port);
+}
+
+void
+simple_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ *(unsigned char *) (p->base + port) = value;
+}
+
+void
+simple_outw(struct iop *p, unsigned short value, unsigned long port)
+{
+ *(unsigned short *) (p->base + port) = value;
+}
+
+unsigned char
+pcc_inb(struct iop *p, unsigned long port)
+{
+ unsigned long addr = p->base + port + 0x40000;
+ unsigned long v;
+
+ if (port & 1)
+ addr += 0x00400000;
+ v = *(volatile unsigned char *) addr;
+ return v;
+}
+
+void
+pcc_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ unsigned long addr = p->base + port + 0x40000;
+
+ if (port & 1)
+ addr += 0x00400000;
+ *(volatile unsigned char *) addr = value;
+}
+
+unsigned char
+bad_inb(struct iop *p, unsigned long port)
+{
+ badio(inb, port);
+}
+
+void
+bad_outb(struct iop *p, unsigned char value, unsigned long port)
+{
+ badio(inw, port);
+}
+
+#ifdef CONFIG_SMC91X
+/* MSTLANEX01 LAN at 0xb400:0000 */
+static struct iop laniop = {
+ .start = 0x00,
+ .end = 0x0F,
+ .base = 0x04000000,
+ .check = simple_check,
+ .inb = simple_inb,
+ .inw = simple_inw,
+ .outb = simple_outb,
+ .outw = simple_outw,
+};
+#endif
+
+#ifdef CONFIG_NE2000
+/* NE2000 pc card NIC */
+static struct iop neiop = {
+ .start = 0x280,
+ .end = 0x29f,
+ .base = 0xb0600000 + 0x80, /* soft 0x280 -> hard 0x300 */
+ .check = simple_check,
+ .inb = pcc_inb,
+ .inw = simple_inw,
+ .outb = pcc_outb,
+ .outw = simple_outw,
+};
+#endif
+
+#ifdef CONFIG_IDE
+/* CF in CF slot */
+static struct iop cfiop = {
+ .base = 0xb0600000,
+ .check = ide_check,
+ .inb = pcc_inb,
+ .inw = simple_inw,
+ .outb = pcc_outb,
+ .outw = simple_outw,
+};
+#endif
+
+static __inline__ struct iop *
+port2iop(unsigned long port)
+{
+ if (0) ;
+#if defined(CONFIG_SMC91X)
+ else if (laniop.check(&laniop, port))
+ return &laniop;
+#endif
+#if defined(CONFIG_NE2000)
+ else if (neiop.check(&neiop, port))
+ return &neiop;
+#endif
+#if defined(CONFIG_IDE)
+ else if (cfiop.check(&cfiop, port))
+ return &cfiop;
+#endif
+ else
+ return NULL;
+}
+
+static inline void
+delay(void)
+{
+ ctrl_inw(0xac000000);
+ ctrl_inw(0xac000000);
+}
+
+unsigned char
+sh7343se_inb(unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ return (p->inb) (p, port);
+}
+
+unsigned char
+sh7343se_inb_p(unsigned long port)
+{
+ unsigned char v = sh7343se_inb(port);
+ delay();
+ return v;
+}
+
+unsigned short
+sh7343se_inw(unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ return (p->inw) (p, port);
+}
+
+unsigned int
+sh7343se_inl(unsigned long port)
+{
+ badio(inl, port);
+}
+
+void
+sh7343se_outb(unsigned char value, unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ (p->outb) (p, value, port);
+}
+
+void
+sh7343se_outb_p(unsigned char value, unsigned long port)
+{
+ sh7343se_outb(value, port);
+ delay();
+}
+
+void
+sh7343se_outw(unsigned short value, unsigned long port)
+{
+ struct iop *p = port2iop(port);
+ (p->outw) (p, value, port);
+}
+
+void
+sh7343se_outl(unsigned int value, unsigned long port)
+{
+ badio(outl, port);
+}
+
+void
+sh7343se_insb(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned char *a = addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ *a++ = (p->inb) (p, port);
+}
+
+void
+sh7343se_insw(unsigned long port, void *addr, unsigned long count)
+{
+ unsigned short *a = addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ *a++ = (p->inw) (p, port);
+}
+
+void
+sh7343se_insl(unsigned long port, void *addr, unsigned long count)
+{
+ badio(insl, port);
+}
+
+void
+sh7343se_outsb(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned char *a = (unsigned char *) addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ (p->outb) (p, *a++, port);
+}
+
+void
+sh7343se_outsw(unsigned long port, const void *addr, unsigned long count)
+{
+ unsigned short *a = (unsigned short *) addr;
+ struct iop *p = port2iop(port);
+ while (count--)
+ (p->outw) (p, *a++, port);
+}
+
+void
+sh7343se_outsl(unsigned long port, const void *addr, unsigned long count)
+{
+ badio(outsw, port);
+}
diff --git a/arch/sh/boards/se/7343/irq.c b/arch/sh/boards/se/7343/irq.c
new file mode 100644
index 000000000000..288b62f59419
--- /dev/null
+++ b/arch/sh/boards/se/7343/irq.c
@@ -0,0 +1,191 @@
+/*
+ * arch/sh/boards/se/7343/irq.c
+ *
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/mach/se7343.h>
+
+static void
+disable_intreq_irq(unsigned int irq)
+{
+ int bit = irq - OFFCHIP_IRQ_BASE;
+ u16 val;
+
+ val = ctrl_inw(PA_CPLD_IMSK);
+ val |= 1 << bit;
+ ctrl_outw(val, PA_CPLD_IMSK);
+}
+
+static void
+enable_intreq_irq(unsigned int irq)
+{
+ int bit = irq - OFFCHIP_IRQ_BASE;
+ u16 val;
+
+ val = ctrl_inw(PA_CPLD_IMSK);
+ val &= ~(1 << bit);
+ ctrl_outw(val, PA_CPLD_IMSK);
+}
+
+static void
+mask_and_ack_intreq_irq(unsigned int irq)
+{
+ disable_intreq_irq(irq);
+}
+
+static unsigned int
+startup_intreq_irq(unsigned int irq)
+{
+ enable_intreq_irq(irq);
+ return 0;
+}
+
+static void
+shutdown_intreq_irq(unsigned int irq)
+{
+ disable_intreq_irq(irq);
+}
+
+static void
+end_intreq_irq(unsigned int irq)
+{
+ if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
+ enable_intreq_irq(irq);
+}
+
+static struct hw_interrupt_type intreq_irq_type = {
+ .typename = "FPGA-IRQ",
+ .startup = startup_intreq_irq,
+ .shutdown = shutdown_intreq_irq,
+ .enable = enable_intreq_irq,
+ .disable = disable_intreq_irq,
+ .ack = mask_and_ack_intreq_irq,
+ .end = end_intreq_irq
+};
+
+static void
+make_intreq_irq(unsigned int irq)
+{
+ disable_irq_nosync(irq);
+ irq_desc[irq].chip = &intreq_irq_type;
+ disable_intreq_irq(irq);
+}
+
+int
+shmse_irq_demux(int irq)
+{
+ int bit;
+ volatile u16 val;
+
+ if (irq == IRQ5_IRQ) {
+ /* Read status Register */
+ val = ctrl_inw(PA_CPLD_ST);
+ bit = ffs(val);
+ if (bit != 0)
+ return OFFCHIP_IRQ_BASE + bit - 1;
+ }
+ return irq;
+}
+
+/* IRQ5 is multiplexed between the following sources:
+ * 1. PC Card socket
+ * 2. Extension slot
+ * 3. USB Controller
+ * 4. Serial Controller
+ *
+ * We configure IRQ5 as a cascade IRQ.
+ */
+static struct irqaction irq5 = { no_action, 0, CPU_MASK_NONE, "IRQ5-cascade",
+ NULL, NULL};
+
+/*
+ * Initialize IRQ setting
+ */
+void __init
+init_7343se_IRQ(void)
+{
+ /* Setup Multiplexed interrupts */
+ ctrl_outw(8, PA_CPLD_MODESET); /* Set all CPLD interrupts to active
+ * low.
+ */
+ /* Mask all CPLD controller interrupts */
+ ctrl_outw(0x0fff, PA_CPLD_IMSK);
+
+ /* PC Card interrupts */
+ make_intreq_irq(PC_IRQ0);
+ make_intreq_irq(PC_IRQ1);
+ make_intreq_irq(PC_IRQ2);
+ make_intreq_irq(PC_IRQ3);
+
+ /* Extension Slot Interrupts */
+ make_intreq_irq(EXT_IRQ0);
+ make_intreq_irq(EXT_IRQ1);
+ make_intreq_irq(EXT_IRQ2);
+ make_intreq_irq(EXT_IRQ3);
+
+ /* USB Controller interrupts */
+ make_intreq_irq(USB_IRQ0);
+ make_intreq_irq(USB_IRQ1);
+
+ /* Serial Controller interrupts */
+ make_intreq_irq(UART_IRQ0);
+ make_intreq_irq(UART_IRQ1);
+
+ /* Setup all external interrupts to be active low */
+ ctrl_outw(0xaaaa, INTC_ICR1);
+
+ make_ipr_irq(IRQ5_IRQ, IRQ5_IPR_ADDR+2, IRQ5_IPR_POS, IRQ5_PRIORITY);
+ setup_irq(IRQ5_IRQ, &irq5);
+ /* Set port control to use IRQ5 */
+ *(u16 *)0xA4050108 &= ~0xc;
+
+ make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+ make_ipr_irq(VPU_IRQ, VPU_IPR_ADDR, VPU_IPR_POS, 8);
+
+ ctrl_outb(0x0f, INTC_IMCR5); /* enable SCIF IRQ */
+
+ make_ipr_irq(DMTE0_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(DMTE1_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(DMTE2_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(DMTE3_IRQ, DMA1_IPR_ADDR, DMA1_IPR_POS, DMA1_PRIORITY);
+ make_ipr_irq(DMTE4_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY);
+ make_ipr_irq(DMTE5_IRQ, DMA2_IPR_ADDR, DMA2_IPR_POS, DMA2_PRIORITY);
+
+ /* I2C block */
+ make_ipr_irq(IIC0_ALI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+ make_ipr_irq(IIC0_TACKI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+ IIC0_PRIORITY);
+ make_ipr_irq(IIC0_WAITI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS,
+ IIC0_PRIORITY);
+ make_ipr_irq(IIC0_DTEI_IRQ, IIC0_IPR_ADDR, IIC0_IPR_POS, IIC0_PRIORITY);
+
+ make_ipr_irq(IIC1_ALI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS, IIC1_PRIORITY);
+ make_ipr_irq(IIC1_TACKI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS,
+ IIC1_PRIORITY);
+ make_ipr_irq(IIC1_WAITI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS,
+ IIC1_PRIORITY);
+ make_ipr_irq(IIC1_DTEI_IRQ, IIC1_IPR_ADDR, IIC1_IPR_POS, IIC1_PRIORITY);
+
+ /* SIOF */
+ make_ipr_irq(SIOF0_IRQ, SIOF0_IPR_ADDR, SIOF0_IPR_POS, SIOF0_PRIORITY);
+
+ /* SIU */
+ make_ipr_irq(SIU_IRQ, SIU_IPR_ADDR, SIU_IPR_POS, SIU_PRIORITY);
+
+ /* VIO interrupt */
+ make_ipr_irq(CEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+ make_ipr_irq(BEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+ make_ipr_irq(VEU_IRQ, VIO_IPR_ADDR, VIO_IPR_POS, VIO_PRIORITY);
+
+ /*MFI interrupt*/
+
+ make_ipr_irq(MFI_IRQ, MFI_IPR_ADDR, MFI_IPR_POS, MFI_PRIORITY);
+
+ /* LCD controller */
+ make_ipr_irq(LCDC_IRQ, LCDC_IPR_ADDR, LCDC_IPR_POS, LCDC_PRIORITY);
+ ctrl_outw(0x2000, PA_MRSHPC + 0x0c); /* mrshpc irq enable */
+}
diff --git a/arch/sh/boards/se/7343/led.c b/arch/sh/boards/se/7343/led.c
new file mode 100644
index 000000000000..6b39e191c420
--- /dev/null
+++ b/arch/sh/boards/se/7343/led.c
@@ -0,0 +1,44 @@
+/*
+ * arch/sh/boards/se/7343/led.c
+ *
+ */
+#include <linux/sched.h>
+#include <asm/mach/se7343.h>
+
+/* Cycle the LED's in the clasic Knightrider/Sun pattern */
+void heartbeat_7343se(void)
+{
+ static unsigned int cnt = 0, period = 0;
+ volatile unsigned short *p = (volatile unsigned short *) PA_LED;
+ static unsigned bit = 0, up = 1;
+
+ cnt += 1;
+ if (cnt < period) {
+ return;
+ }
+
+ cnt = 0;
+
+ /* Go through the points (roughly!):
+ * f(0)=10, f(1)=16, f(2)=20, f(5)=35,f(inf)->110
+ */
+ period = 110 - ((300 << FSHIFT) / ((avenrun[0] / 5) + (3 << FSHIFT)));
+
+ if (up) {
+ if (bit == 7) {
+ bit--;
+ up = 0;
+ } else {
+ bit++;
+ }
+ } else {
+ if (bit == 0) {
+ bit++;
+ up = 1;
+ } else {
+ bit--;
+ }
+ }
+ *p = 1 << (bit + LED_SHIFT);
+
+}
diff --git a/arch/sh/boards/se/7343/setup.c b/arch/sh/boards/se/7343/setup.c
new file mode 100644
index 000000000000..c7d17fe7764e
--- /dev/null
+++ b/arch/sh/boards/se/7343/setup.c
@@ -0,0 +1,83 @@
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <asm/machvec.h>
+#include <asm/mach/se7343.h>
+#include <asm/irq.h>
+
+void heartbeat_7343se(void);
+void init_7343se_IRQ(void);
+
+static struct resource smc91x_resources[] = {
+ [0] = {
+ .start = 0x10000000,
+ .end = 0x1000000F,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ /*
+ * shared with other devices via externel
+ * interrupt controller in FPGA...
+ */
+ .start = EXT_IRQ2,
+ .end = EXT_IRQ2,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device smc91x_device = {
+ .name = "smc91x",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(smc91x_resources),
+ .resource = smc91x_resources,
+};
+
+static struct platform_device *smc91x_platform_devices[] __initdata = {
+ &smc91x_device,
+};
+
+static int __init sh7343se_devices_setup(void)
+{
+ return platform_add_devices(smc91x_platform_devices,
+ ARRAY_SIZE(smc91x_platform_devices));
+}
+
+static void __init sh7343se_setup(char **cmdline_p)
+{
+ device_initcall(sh7343se_devices_setup);
+}
+
+/*
+ * The Machine Vector
+ */
+struct sh_machine_vector mv_7343se __initmv = {
+ .mv_name = "SolutionEngine 7343",
+ .mv_setup = sh7343se_setup,
+ .mv_nr_irqs = 108,
+ .mv_inb = sh7343se_inb,
+ .mv_inw = sh7343se_inw,
+ .mv_inl = sh7343se_inl,
+ .mv_outb = sh7343se_outb,
+ .mv_outw = sh7343se_outw,
+ .mv_outl = sh7343se_outl,
+
+ .mv_inb_p = sh7343se_inb_p,
+ .mv_inw_p = sh7343se_inw,
+ .mv_inl_p = sh7343se_inl,
+ .mv_outb_p = sh7343se_outb_p,
+ .mv_outw_p = sh7343se_outw,
+ .mv_outl_p = sh7343se_outl,
+
+ .mv_insb = sh7343se_insb,
+ .mv_insw = sh7343se_insw,
+ .mv_insl = sh7343se_insl,
+ .mv_outsb = sh7343se_outsb,
+ .mv_outsw = sh7343se_outsw,
+ .mv_outsl = sh7343se_outsl,
+
+ .mv_init_irq = init_7343se_IRQ,
+ .mv_irq_demux = shmse_irq_demux,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_7343se,
+#endif
+};
+ALIAS_MV(7343se)
diff --git a/arch/sh/boards/se/770x/Makefile b/arch/sh/boards/se/770x/Makefile
index be89a73cc418..9a5035f80ec0 100644
--- a/arch/sh/boards/se/770x/Makefile
+++ b/arch/sh/boards/se/770x/Makefile
@@ -2,5 +2,5 @@
# Makefile for the 770x SolutionEngine specific parts of the kernel
#
-obj-y := mach.o setup.o io.o irq.o led.o
-
+obj-y := setup.o io.o irq.o
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/se/770x/io.c b/arch/sh/boards/se/770x/io.c
index 9a39ee963143..9941949331ab 100644
--- a/arch/sh/boards/se/770x/io.c
+++ b/arch/sh/boards/se/770x/io.c
@@ -1,4 +1,4 @@
-/* $Id: io.c,v 1.5 2004/02/22 23:08:43 kkojima Exp $
+/* $Id: io.c,v 1.7 2006/02/05 21:55:29 lethal Exp $
*
* linux/arch/sh/kernel/io_se.c
*
@@ -11,7 +11,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <asm/io.h>
-#include <asm/se/se.h>
+#include <asm/se.h>
/* SH pcmcia io window base, start and end. */
int sh_pcic_io_wbase = 0xb8400000;
@@ -20,11 +20,6 @@ int sh_pcic_io_stop;
int sh_pcic_io_type;
int sh_pcic_io_dummy;
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000);
-}
-
/* MS7750 requires special versions of in*, out* routines, since
PC-like io ports are located at upper half byte of 16-bit word which
can be accessed only with 16-bit wide. */
@@ -52,10 +47,6 @@ shifted_port(unsigned long port)
return 1;
}
-#define maybebadio(name,port) \
- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
- #name, (port), (__u32) __builtin_return_address(0))
-
unsigned char se_inb(unsigned long port)
{
if (sh_pcic_io_start <= port && port <= sh_pcic_io_stop)
@@ -76,7 +67,7 @@ unsigned char se_inb_p(unsigned long port)
v = (*port2adr(port) >> 8);
else
v = (*port2adr(port))&0xff;
- delay();
+ ctrl_delay();
return v;
}
@@ -86,13 +77,13 @@ unsigned short se_inw(unsigned long port)
(sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
return *port2adr(port);
else
- maybebadio(inw, port);
+ maybebadio(port);
return 0;
}
unsigned int se_inl(unsigned long port)
{
- maybebadio(inl, port);
+ maybebadio(port);
return 0;
}
@@ -114,7 +105,7 @@ void se_outb_p(unsigned char value, unsigned long port)
*(port2adr(port)) = value << 8;
else
*(port2adr(port)) = value;
- delay();
+ ctrl_delay();
}
void se_outw(unsigned short value, unsigned long port)
@@ -123,12 +114,12 @@ void se_outw(unsigned short value, unsigned long port)
(sh_pcic_io_start <= port && port <= sh_pcic_io_stop))
*port2adr(port) = value;
else
- maybebadio(outw, port);
+ maybebadio(port);
}
void se_outl(unsigned int value, unsigned long port)
{
- maybebadio(outl, port);
+ maybebadio(port);
}
void se_insb(unsigned long port, void *addr, unsigned long count)
@@ -159,7 +150,7 @@ void se_insw(unsigned long port, void *addr, unsigned long count)
void se_insl(unsigned long port, void *addr, unsigned long count)
{
- maybebadio(insl, port);
+ maybebadio(port);
}
void se_outsb(unsigned long port, const void *addr, unsigned long count)
@@ -190,37 +181,5 @@ void se_outsw(unsigned long port, const void *addr, unsigned long count)
void se_outsl(unsigned long port, const void *addr, unsigned long count)
{
- maybebadio(outsw, port);
-}
-
-/* Map ISA bus address to the real address. Only for PCMCIA. */
-
-/* ISA page descriptor. */
-static __u32 sh_isa_memmap[256];
-
-static int
-sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
-{
- int idx;
-
- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
- return -1;
-
- idx = start >> 12;
- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
-#if 0
- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
- start, length, offset, idx, sh_isa_memmap[idx]);
-#endif
- return 0;
-}
-
-unsigned long
-se_isa_port2addr(unsigned long offset)
-{
- int idx;
-
- idx = (offset >> 12) & 0xff;
- offset &= 0xfff;
- return sh_isa_memmap[idx] + offset;
+ maybebadio(port);
}
diff --git a/arch/sh/boards/se/770x/irq.c b/arch/sh/boards/se/770x/irq.c
index 3e558716ce10..cff6700bbafd 100644
--- a/arch/sh/boards/se/770x/irq.c
+++ b/arch/sh/boards/se/770x/irq.c
@@ -11,7 +11,7 @@
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
-#include <asm/se/se.h>
+#include <asm/se.h>
/*
* Initialize IRQ setting
diff --git a/arch/sh/boards/se/770x/led.c b/arch/sh/boards/se/770x/led.c
index 3cddbda025fc..d93dd831b2ad 100644
--- a/arch/sh/boards/se/770x/led.c
+++ b/arch/sh/boards/se/770x/led.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/led_se.c
+ * linux/arch/sh/boards/se/770x/led.c
*
* Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
*
@@ -9,22 +9,8 @@
* This file contains Solution Engine specific LED code.
*/
-#include <asm/se/se.h>
-
-static void mach_led(int position, int value)
-{
- volatile unsigned short* p = (volatile unsigned short*)PA_LED;
-
- if (value) {
- *p |= (1<<8);
- } else {
- *p &= ~(1<<8);
- }
-}
-
-#ifdef CONFIG_HEARTBEAT
-
#include <linux/sched.h>
+#include <asm/se.h>
/* Cycle the LED's in the clasic Knightrider/Sun pattern */
void heartbeat_se(void)
@@ -64,4 +50,3 @@ void heartbeat_se(void)
*p = 1<<(bit+8);
}
-#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/se/770x/mach.c b/arch/sh/boards/se/770x/mach.c
deleted file mode 100644
index 6ec07bd3dcf1..000000000000
--- a/arch/sh/boards/se/770x/mach.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * linux/arch/sh/kernel/mach_se.c
- *
- * Copyright (C) 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the Hitachi SolutionEngine
- */
-
-#include <linux/init.h>
-
-#include <asm/machvec.h>
-#include <asm/rtc.h>
-#include <asm/machvec_init.h>
-
-#include <asm/se/io.h>
-
-void heartbeat_se(void);
-void setup_se(void);
-void init_se_IRQ(void);
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_se __initmv = {
-#if defined(CONFIG_CPU_SH4)
- .mv_nr_irqs = 48,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
- .mv_nr_irqs = 32,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
- .mv_nr_irqs = 61,
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
- .mv_nr_irqs = 86,
-#endif
-
- .mv_inb = se_inb,
- .mv_inw = se_inw,
- .mv_inl = se_inl,
- .mv_outb = se_outb,
- .mv_outw = se_outw,
- .mv_outl = se_outl,
-
- .mv_inb_p = se_inb_p,
- .mv_inw_p = se_inw,
- .mv_inl_p = se_inl,
- .mv_outb_p = se_outb_p,
- .mv_outw_p = se_outw,
- .mv_outl_p = se_outl,
-
- .mv_insb = se_insb,
- .mv_insw = se_insw,
- .mv_insl = se_insl,
- .mv_outsb = se_outsb,
- .mv_outsw = se_outsw,
- .mv_outsl = se_outsl,
-
- .mv_isa_port2addr = se_isa_port2addr,
-
- .mv_init_irq = init_se_IRQ,
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_se,
-#endif
-};
-ALIAS_MV(se)
diff --git a/arch/sh/boards/se/770x/setup.c b/arch/sh/boards/se/770x/setup.c
index 7d1a071727cc..a1d51d5fa925 100644
--- a/arch/sh/boards/se/770x/setup.c
+++ b/arch/sh/boards/se/770x/setup.c
@@ -7,15 +7,14 @@
* Hitachi SolutionEngine Support.
*
*/
-
#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <linux/hdreg.h>
-#include <linux/ide.h>
+#include <asm/machvec.h>
+#include <asm/se.h>
#include <asm/io.h>
-#include <asm/se/se.h>
-#include <asm/se/smc37c93x.h>
+#include <asm/smc37c93x.h>
+
+void heartbeat_se(void);
+void init_se_IRQ(void);
/*
* Configure the Super I/O chip
@@ -26,7 +25,8 @@ static void __init smsc_config(int index, int data)
outb_p(data, DATA_PORT);
}
-static void __init init_smsc(void)
+/* XXX: Another candidate for a more generic cchip machine vector */
+static void __init smsc_setup(char **cmdline_p)
{
outb_p(CONFIG_ENTER, CONFIG_PORT);
outb_p(CONFIG_ENTER, CONFIG_PORT);
@@ -69,16 +69,46 @@ static void __init init_smsc(void)
outb_p(CONFIG_EXIT, CONFIG_PORT);
}
-const char *get_system_type(void)
-{
- return "SolutionEngine";
-}
-
/*
- * Initialize the board
+ * The Machine Vector
*/
-void __init platform_setup(void)
-{
- init_smsc();
- /* XXX: RTC setting comes here */
-}
+struct sh_machine_vector mv_se __initmv = {
+ .mv_name = "SolutionEngine",
+ .mv_setup = smsc_setup,
+#if defined(CONFIG_CPU_SH4)
+ .mv_nr_irqs = 48,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
+ .mv_nr_irqs = 32,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7709)
+ .mv_nr_irqs = 61,
+#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
+ .mv_nr_irqs = 86,
+#endif
+
+ .mv_inb = se_inb,
+ .mv_inw = se_inw,
+ .mv_inl = se_inl,
+ .mv_outb = se_outb,
+ .mv_outw = se_outw,
+ .mv_outl = se_outl,
+
+ .mv_inb_p = se_inb_p,
+ .mv_inw_p = se_inw,
+ .mv_inl_p = se_inl,
+ .mv_outb_p = se_outb_p,
+ .mv_outw_p = se_outw,
+ .mv_outl_p = se_outl,
+
+ .mv_insb = se_insb,
+ .mv_insw = se_insw,
+ .mv_insl = se_insl,
+ .mv_outsb = se_outsb,
+ .mv_outsw = se_outsw,
+ .mv_outsl = se_outsl,
+
+ .mv_init_irq = init_se_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_se,
+#endif
+};
+ALIAS_MV(se)
diff --git a/arch/sh/boards/se/7751/Makefile b/arch/sh/boards/se/7751/Makefile
index ce7ca247f84d..188900c48321 100644
--- a/arch/sh/boards/se/7751/Makefile
+++ b/arch/sh/boards/se/7751/Makefile
@@ -2,7 +2,7 @@
# Makefile for the 7751 SolutionEngine specific parts of the kernel
#
-obj-y := mach.o setup.o io.o irq.o led.o
+obj-y := setup.o io.o irq.o
obj-$(CONFIG_PCI) += pci.o
-
+obj-$(CONFIG_HEARTBEAT) += led.o
diff --git a/arch/sh/boards/se/7751/io.c b/arch/sh/boards/se/7751/io.c
index 99041b269261..e8d846cec89d 100644
--- a/arch/sh/boards/se/7751/io.c
+++ b/arch/sh/boards/se/7751/io.c
@@ -1,6 +1,4 @@
-/*
- * linux/arch/sh/kernel/io_7751se.c
- *
+/*
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
*
@@ -10,96 +8,21 @@
* placeholder code from io_se.c left in with the
* expectation of later SuperIO and PCMCIA access.
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/pci.h>
#include <asm/io.h>
-#include <asm/se7751/se7751.h>
+#include <asm/se7751.h>
#include <asm/addrspace.h>
-#include <linux/pci.h>
-#include "../../../drivers/pci/pci-sh7751.h"
-
-#if 0
-/******************************************************************
- * Variables from io_se.c, related to PCMCIA (not PCI); we're not
- * compiling them in, and have removed references from functions
- * which follow. [Many checked for IO ports in the range bounded
- * by sh_pcic_io_start/stop, and used sh_pcic_io_wbase as offset.
- * As start/stop are uninitialized, only port 0x0 would match?]
- * When used, remember to adjust names to avoid clash with io_se?
- *****************************************************************/
-/* SH pcmcia io window base, start and end. */
-int sh_pcic_io_wbase = 0xb8400000;
-int sh_pcic_io_start;
-int sh_pcic_io_stop;
-int sh_pcic_io_type;
-int sh_pcic_io_dummy;
-/*************************************************************/
-#endif
-
-/*
- * The 7751 Solution Engine uses the built-in PCI controller (PCIC)
- * of the 7751 processor, and has a SuperIO accessible via the PCI.
- * The board also includes a PCMCIA controller on its memory bus,
- * like the other Solution Engine boards.
- */
-
-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
-#define PCI_IO_AREA SH7751_PCI_IO_BASE
-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
-
-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
-
-#define maybebadio(name,port) \
- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
- #name, (port), (__u32) __builtin_return_address(0))
-
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000);
-}
-
-static inline volatile __u16 *
-port2adr(unsigned int port)
+static inline volatile u16 *port2adr(unsigned int port)
{
if (port >= 0x2000)
return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-#if 0
- else
- return (volatile __u16 *) (PA_SUPERIO + (port << 1));
-#endif
- maybebadio(name,(unsigned long)port);
+ maybebadio((unsigned long)port);
return (volatile __u16*)port;
}
-#if 0
-/* The 7751 Solution Engine seems to have everything hooked */
-/* up pretty normally (nothing on high-bytes only...) so this */
-/* shouldn't be needed */
-static inline int
-shifted_port(unsigned long port)
-{
- /* For IDE registers, value is not shifted */
- if ((0x1f0 <= port && port < 0x1f8) || port == 0x3f6)
- return 0;
- else
- return 1;
-}
-#endif
-
-/* In case someone configures the kernel w/o PCI support: in that */
-/* scenario, don't ever bother to check for PCI-window addresses */
-
-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
-#if defined(CONFIG_PCI)
-#define CHECK_SH7751_PCIIO(port) \
- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
-#else
-#define CHECK_SH7751_PCIIO(port) (0)
-#endif
-
/*
* General outline: remap really low stuff [eventually] to SuperIO,
* stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
@@ -111,10 +34,10 @@ unsigned char sh7751se_inb(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned char *)pci_ioaddr(port);
else
- return (*port2adr(port))&0xff;
+ return (*port2adr(port)) & 0xff;
}
unsigned char sh7751se_inb_p(unsigned long port)
@@ -123,11 +46,11 @@ unsigned char sh7751se_inb_p(unsigned long port)
if (PXSEG(port))
v = *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port))
- v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ v = *(volatile unsigned char *)pci_ioaddr(port);
else
- v = (*port2adr(port))&0xff;
- delay();
+ v = (*port2adr(port)) & 0xff;
+ ctrl_delay();
return v;
}
@@ -135,12 +58,12 @@ unsigned short sh7751se_inw(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned short *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned short *)pci_ioaddr(port);
else if (port >= 0x2000)
return *port2adr(port);
else
- maybebadio(inw, port);
+ maybebadio(port);
return 0;
}
@@ -148,12 +71,12 @@ unsigned int sh7751se_inl(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned long *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned int *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned int *)pci_ioaddr(port);
else if (port >= 0x2000)
return *port2adr(port);
else
- maybebadio(inl, port);
+ maybebadio(port);
return 0;
}
@@ -162,8 +85,8 @@ void sh7751se_outb(unsigned char value, unsigned long port)
if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned char*)pci_ioaddr(port)) = value;
else
*(port2adr(port)) = value;
}
@@ -172,73 +95,41 @@ void sh7751se_outb_p(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned char*)pci_ioaddr(port)) = value;
else
*(port2adr(port)) = value;
- delay();
+ ctrl_delay();
}
void sh7751se_outw(unsigned short value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned short *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned short *)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned short *)pci_ioaddr(port)) = value;
else if (port >= 0x2000)
*port2adr(port) = value;
else
- maybebadio(outw, port);
+ maybebadio(port);
}
void sh7751se_outl(unsigned int value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned long *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned long*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned long*)pci_ioaddr(port)) = value;
else
- maybebadio(outl, port);
+ maybebadio(port);
}
void sh7751se_insl(unsigned long port, void *addr, unsigned long count)
{
- maybebadio(insl, port);
+ maybebadio(port);
}
void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count)
{
- maybebadio(outsw, port);
-}
-
-/* Map ISA bus address to the real address. Only for PCMCIA. */
-
-/* ISA page descriptor. */
-static __u32 sh_isa_memmap[256];
-
-#if 0
-static int
-sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
-{
- int idx;
-
- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
- return -1;
-
- idx = start >> 12;
- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
- start, length, offset, idx, sh_isa_memmap[idx]);
- return 0;
-}
-#endif
-
-unsigned long
-sh7751se_isa_port2addr(unsigned long offset)
-{
- int idx;
-
- idx = (offset >> 12) & 0xff;
- offset &= 0xfff;
- return sh_isa_memmap[idx] + offset;
+ maybebadio(port);
}
diff --git a/arch/sh/boards/se/7751/irq.c b/arch/sh/boards/se/7751/irq.c
index bf6c023615df..c607b0a48479 100644
--- a/arch/sh/boards/se/7751/irq.c
+++ b/arch/sh/boards/se/7751/irq.c
@@ -12,7 +12,7 @@
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/irq.h>
-#include <asm/se7751/se7751.h>
+#include <asm/se7751.h>
/*
* Initialize IRQ setting
diff --git a/arch/sh/boards/se/7751/led.c b/arch/sh/boards/se/7751/led.c
index a878726d3c7c..de4194d97c88 100644
--- a/arch/sh/boards/se/7751/led.c
+++ b/arch/sh/boards/se/7751/led.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/led_se.c
+ * linux/arch/sh/boards/se/7751/led.c
*
* Copyright (C) 2000 Stuart Menefy <stuart.menefy@st.com>
*
@@ -8,23 +8,8 @@
*
* This file contains Solution Engine specific LED code.
*/
-
-#include <asm/se7751/se7751.h>
-
-static void mach_led(int position, int value)
-{
- volatile unsigned short* p = (volatile unsigned short*)PA_LED;
-
- if (value) {
- *p |= (1<<8);
- } else {
- *p &= ~(1<<8);
- }
-}
-
-#ifdef CONFIG_HEARTBEAT
-
#include <linux/sched.h>
+#include <asm/se7751.h>
/* Cycle the LED's in the clasic Knightrider/Sun pattern */
void heartbeat_7751se(void)
@@ -64,4 +49,3 @@ void heartbeat_7751se(void)
*p = 1<<(bit+8);
}
-#endif /* CONFIG_HEARTBEAT */
diff --git a/arch/sh/boards/se/7751/mach.c b/arch/sh/boards/se/7751/mach.c
deleted file mode 100644
index 62d8d3e62590..000000000000
--- a/arch/sh/boards/se/7751/mach.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * linux/arch/sh/kernel/mach_7751se.c
- *
- * Minor tweak of mach_se.c file to reference 7751se-specific items.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Machine vector for the Hitachi 7751 SolutionEngine
- */
-
-#include <linux/init.h>
-
-#include <asm/machvec.h>
-#include <asm/rtc.h>
-#include <asm/machvec_init.h>
-
-#include <asm/se7751/io.h>
-
-void heartbeat_7751se(void);
-void init_7751se_IRQ(void);
-
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_7751se __initmv = {
- .mv_nr_irqs = 72,
-
- .mv_inb = sh7751se_inb,
- .mv_inw = sh7751se_inw,
- .mv_inl = sh7751se_inl,
- .mv_outb = sh7751se_outb,
- .mv_outw = sh7751se_outw,
- .mv_outl = sh7751se_outl,
-
- .mv_inb_p = sh7751se_inb_p,
- .mv_inw_p = sh7751se_inw,
- .mv_inl_p = sh7751se_inl,
- .mv_outb_p = sh7751se_outb_p,
- .mv_outw_p = sh7751se_outw,
- .mv_outl_p = sh7751se_outl,
-
- .mv_insl = sh7751se_insl,
- .mv_outsl = sh7751se_outsl,
-
- .mv_isa_port2addr = sh7751se_isa_port2addr,
-
- .mv_init_irq = init_7751se_IRQ,
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = heartbeat_7751se,
-#endif
-};
-ALIAS_MV(7751se)
diff --git a/arch/sh/boards/se/7751/pci.c b/arch/sh/boards/se/7751/pci.c
index 3ee03014dea3..203b2923fe7f 100644
--- a/arch/sh/boards/se/7751/pci.c
+++ b/arch/sh/boards/se/7751/pci.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/pci-7751se.c
+ * linux/arch/sh/boards/se/7751/pci.c
*
* Author: Ian DaSilva (idasilva@mvista.com)
*
diff --git a/arch/sh/boards/se/7751/setup.c b/arch/sh/boards/se/7751/setup.c
index 48dc5aee67d4..f7e1dd39c836 100644
--- a/arch/sh/boards/se/7751/setup.c
+++ b/arch/sh/boards/se/7751/setup.c
@@ -1,4 +1,4 @@
-/*
+/*
* linux/arch/sh/kernel/setup_7751se.c
*
* Copyright (C) 2000 Kazumoto Kojima
@@ -8,81 +8,16 @@
* Modified for 7751 Solution Engine by
* Ian da Silva and Jeremy Siegel, 2001.
*/
-
#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <linux/hdreg.h>
-#include <linux/ide.h>
+#include <asm/machvec.h>
+#include <asm/se7751.h>
#include <asm/io.h>
-#include <asm/se7751/se7751.h>
-
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
-#endif
-
-/*
- * Configure the Super I/O chip
- */
-#if 0
-/* Leftover code from regular Solution Engine, for reference. */
-/* The SH7751 Solution Engine has a different SuperIO. */
-static void __init smsc_config(int index, int data)
-{
- outb_p(index, INDEX_PORT);
- outb_p(data, DATA_PORT);
-}
-
-static void __init init_smsc(void)
-{
- outb_p(CONFIG_ENTER, CONFIG_PORT);
- outb_p(CONFIG_ENTER, CONFIG_PORT);
-
- /* FDC */
- smsc_config(CURRENT_LDN_INDEX, LDN_FDC);
- smsc_config(ACTIVATE_INDEX, 0x01);
- smsc_config(IRQ_SELECT_INDEX, 6); /* IRQ6 */
-
- /* IDE1 */
- smsc_config(CURRENT_LDN_INDEX, LDN_IDE1);
- smsc_config(ACTIVATE_INDEX, 0x01);
- smsc_config(IRQ_SELECT_INDEX, 14); /* IRQ14 */
-
- /* AUXIO (GPIO): to use IDE1 */
- smsc_config(CURRENT_LDN_INDEX, LDN_AUXIO);
- smsc_config(GPIO46_INDEX, 0x00); /* nIOROP */
- smsc_config(GPIO47_INDEX, 0x00); /* nIOWOP */
-
- /* COM1 */
- smsc_config(CURRENT_LDN_INDEX, LDN_COM1);
- smsc_config(ACTIVATE_INDEX, 0x01);
- smsc_config(IO_BASE_HI_INDEX, 0x03);
- smsc_config(IO_BASE_LO_INDEX, 0xf8);
- smsc_config(IRQ_SELECT_INDEX, 4); /* IRQ4 */
-
- /* COM2 */
- smsc_config(CURRENT_LDN_INDEX, LDN_COM2);
- smsc_config(ACTIVATE_INDEX, 0x01);
- smsc_config(IO_BASE_HI_INDEX, 0x02);
- smsc_config(IO_BASE_LO_INDEX, 0xf8);
- smsc_config(IRQ_SELECT_INDEX, 3); /* IRQ3 */
-
- /* RTC */
- smsc_config(CURRENT_LDN_INDEX, LDN_RTC);
- smsc_config(ACTIVATE_INDEX, 0x01);
- smsc_config(IRQ_SELECT_INDEX, 8); /* IRQ8 */
-
- /* XXX: PARPORT, KBD, and MOUSE will come here... */
- outb_p(CONFIG_EXIT, CONFIG_PORT);
-}
-#endif
-const char *get_system_type(void)
-{
- return "7751 SolutionEngine";
-}
+void heartbeat_7751se(void);
+void init_7751se_IRQ(void);
#ifdef CONFIG_SH_KGDB
+#include <asm/kgdb.h>
static int kgdb_uart_setup(void);
static struct kgdb_sermap kgdb_uart_sermap =
{ "ttyS", 0, kgdb_uart_setup, NULL };
@@ -91,7 +26,7 @@ static struct kgdb_sermap kgdb_uart_sermap =
/*
* Initialize the board
*/
-void __init platform_setup(void)
+static void __init sh7751se_setup(char **cmdline_p)
{
/* Call init_smsc() replacement to set up SuperIO. */
/* XXX: RTC setting comes here */
@@ -225,3 +160,37 @@ static int kgdb_uart_setup(void)
return 0;
}
#endif /* CONFIG_SH_KGDB */
+
+
+/*
+ * The Machine Vector
+ */
+
+struct sh_machine_vector mv_7751se __initmv = {
+ .mv_name = "7751 SolutionEngine",
+ .mv_setup = sh7751se_setup,
+ .mv_nr_irqs = 72,
+
+ .mv_inb = sh7751se_inb,
+ .mv_inw = sh7751se_inw,
+ .mv_inl = sh7751se_inl,
+ .mv_outb = sh7751se_outb,
+ .mv_outw = sh7751se_outw,
+ .mv_outl = sh7751se_outl,
+
+ .mv_inb_p = sh7751se_inb_p,
+ .mv_inw_p = sh7751se_inw,
+ .mv_inl_p = sh7751se_inl,
+ .mv_outb_p = sh7751se_outb_p,
+ .mv_outw_p = sh7751se_outw,
+ .mv_outl_p = sh7751se_outl,
+
+ .mv_insl = sh7751se_insl,
+ .mv_outsl = sh7751se_outsl,
+
+ .mv_init_irq = init_7751se_IRQ,
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = heartbeat_7751se,
+#endif
+};
+ALIAS_MV(7751se)
diff --git a/arch/sh/boards/sh03/rtc.c b/arch/sh/boards/sh03/rtc.c
index d609863cfe53..0a9266bb51c5 100644
--- a/arch/sh/boards/sh03/rtc.c
+++ b/arch/sh/boards/sh03/rtc.c
@@ -10,9 +10,10 @@
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/bcd.h>
-#include <asm/io.h>
#include <linux/rtc.h>
#include <linux/spinlock.h>
+#include <asm/io.h>
+#include <asm/rtc.h>
#define RTC_BASE 0xb0000000
#define RTC_SEC1 (RTC_BASE + 0)
@@ -34,8 +35,6 @@
#define RTC_BUSY 1
#define RTC_STOP 2
-extern void (*rtc_get_time)(struct timespec *);
-extern int (*rtc_set_time)(const time_t);
extern spinlock_t rtc_lock;
unsigned long get_cmos_time(void)
@@ -128,6 +127,6 @@ int sh03_rtc_settimeofday(const time_t secs)
void sh03_time_init(void)
{
- rtc_get_time = sh03_rtc_gettimeofday;
- rtc_set_time = sh03_rtc_settimeofday;
+ rtc_sh_get_time = sh03_rtc_gettimeofday;
+ rtc_sh_set_time = sh03_rtc_settimeofday;
}
diff --git a/arch/sh/boards/sh03/setup.c b/arch/sh/boards/sh03/setup.c
index 60290f8f289c..137e2ba9243e 100644
--- a/arch/sh/boards/sh03/setup.c
+++ b/arch/sh/boards/sh03/setup.c
@@ -7,22 +7,14 @@
#include <linux/init.h>
#include <linux/irq.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
+#include <linux/pci.h>
#include <asm/io.h>
+#include <asm/rtc.h>
#include <asm/sh03/io.h>
#include <asm/sh03/sh03.h>
#include <asm/addrspace.h>
-#include "../../drivers/pci/pci-sh7751.h"
-extern void (*board_time_init)(void);
-
-const char *get_system_type(void)
-{
- return "Interface CTP/PCI-SH03)";
-}
-
-void init_sh03_IRQ(void)
+static void __init init_sh03_IRQ(void)
{
ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
@@ -34,38 +26,34 @@ void init_sh03_IRQ(void)
extern void *cf_io_base;
-unsigned long sh03_isa_port2addr(unsigned long port)
+static void __iomem *sh03_ioport_map(unsigned long port, unsigned int size)
{
if (PXSEG(port))
- return port;
+ return (void __iomem *)port;
/* CompactFlash (IDE) */
- if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6)) {
- return (unsigned long)cf_io_base + port;
- }
- return port + SH7751_PCI_IO_BASE;
+ if (((port >= 0x1f0) && (port <= 0x1f7)) || (port == 0x3f6))
+ return (void __iomem *)((unsigned long)cf_io_base + port);
+
+ return (void __iomem *)(port + PCI_IO_BASE);
}
-/*
- * The Machine Vector
- */
+/* arch/sh/boards/sh03/rtc.c */
+void sh03_time_init(void);
+
+static void __init sh03_setup(char **cmdline_p)
+{
+ board_time_init = sh03_time_init;
+}
struct sh_machine_vector mv_sh03 __initmv = {
+ .mv_name = "Interface (CTP/PCI-SH03)",
+ .mv_setup = sh03_setup,
.mv_nr_irqs = 48,
- .mv_isa_port2addr = sh03_isa_port2addr,
+ .mv_ioport_map = sh03_ioport_map,
.mv_init_irq = init_sh03_IRQ,
#ifdef CONFIG_HEARTBEAT
.mv_heartbeat = heartbeat_sh03,
#endif
};
-
ALIAS_MV(sh03)
-
-/* arch/sh/boards/sh03/rtc.c */
-void sh03_time_init(void);
-
-int __init platform_setup(void)
-{
- board_time_init = sh03_time_init;
- return 0;
-}
diff --git a/arch/sh/boards/sh2000/Makefile b/arch/sh/boards/sh2000/Makefile
deleted file mode 100644
index 05d390c3599c..000000000000
--- a/arch/sh/boards/sh2000/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Makefile for the SH2000 specific parts of the kernel
-#
-
-obj-y := setup.o
-
diff --git a/arch/sh/boards/sh2000/setup.c b/arch/sh/boards/sh2000/setup.c
deleted file mode 100644
index 2fe6a11765e9..000000000000
--- a/arch/sh/boards/sh2000/setup.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * linux/arch/sh/kernel/setup_sh2000.c
- *
- * Copyright (C) 2001 SUGIOKA Tochinobu
- *
- * SH-2000 Support.
- *
- */
-
-#include <linux/init.h>
-#include <linux/irq.h>
-
-#include <asm/io.h>
-#include <asm/machvec.h>
-#include <asm/mach/sh2000.h>
-
-#define CF_CIS_BASE 0xb4200000
-
-#define PORT_PECR 0xa4000108
-#define PORT_PHCR 0xa400010E
-#define PORT_ICR1 0xa4000010
-#define PORT_IRR0 0xa4000004
-
-#define IDE_OFFSET 0xb6200000
-#define NIC_OFFSET 0xb6000000
-#define EXTBUS_OFFSET 0xba000000
-
-
-const char *get_system_type(void)
-{
- return "sh2000";
-}
-
-static unsigned long sh2000_isa_port2addr(unsigned long offset)
-{
- if((offset & ~7) == 0x1f0 || offset == 0x3f6)
- return IDE_OFFSET + offset;
- else if((offset & ~0x1f) == 0x300)
- return NIC_OFFSET + offset;
- return EXTBUS_OFFSET + offset;
-}
-
-/*
- * The Machine Vector
- */
-struct sh_machine_vector mv_sh2000 __initmv = {
- .mv_nr_irqs = 80,
- .mv_isa_port2addr = sh2000_isa_port2addr,
-};
-ALIAS_MV(sh2000)
-
-/*
- * Initialize the board
- */
-int __init platform_setup(void)
-{
- /* XXX: RTC setting comes here */
-
- /* These should be done by BIOS/IPL ... */
- /* Enable nCE2A, nCE2B output */
- ctrl_outw(ctrl_inw(PORT_PECR) & ~0xf00, PORT_PECR);
- /* Enable the Compact Flash card, and set the level interrupt */
- ctrl_outw(0x0042, CF_CIS_BASE+0x0200);
- /* Enable interrupt */
- ctrl_outw(ctrl_inw(PORT_PHCR) & ~0x03f3, PORT_PHCR);
- ctrl_outw(1, PORT_ICR1);
- ctrl_outw(ctrl_inw(PORT_IRR0) & ~0xff3f, PORT_IRR0);
- printk(KERN_INFO "SH-2000 Setup...done\n");
- return 0;
-}
diff --git a/arch/sh/boards/shmin/Makefile b/arch/sh/boards/shmin/Makefile
new file mode 100644
index 000000000000..3190cc72430e
--- /dev/null
+++ b/arch/sh/boards/shmin/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the SHMIN board.
+#
+
+obj-y := setup.o
diff --git a/arch/sh/boards/shmin/setup.c b/arch/sh/boards/shmin/setup.c
new file mode 100644
index 000000000000..2f0c19706cf9
--- /dev/null
+++ b/arch/sh/boards/shmin/setup.c
@@ -0,0 +1,41 @@
+/*
+ * arch/sh/boards/shmin/setup.c
+ *
+ * Copyright (C) 2006 Takashi YOSHII
+ *
+ * SHMIN Support.
+ */
+#include <linux/init.h>
+#include <asm/machvec.h>
+#include <asm/shmin/shmin.h>
+#include <asm/clock.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#define PFC_PHCR 0xa400010e
+
+static void __init init_shmin_irq(void)
+{
+ ctrl_outw(0x2a00, PFC_PHCR); // IRQ0-3=IRQ
+ ctrl_outw(0x0aaa, INTC_ICR1); // IRQ0-3=IRQ-mode,Low-active.
+}
+
+static void __iomem *shmin_ioport_map(unsigned long port, unsigned int size)
+{
+ static int dummy;
+
+ if ((port & ~0x1f) == SHMIN_NE_BASE)
+ return (void __iomem *)(SHMIN_IO_BASE + port);
+
+ dummy = 0;
+
+ return &dummy;
+
+}
+
+struct sh_machine_vector mv_shmin __initmv = {
+ .mv_name = "SHMIN",
+ .mv_init_irq = init_shmin_irq,
+ .mv_ioport_map = shmin_ioport_map,
+};
+ALIAS_MV(shmin)
diff --git a/arch/sh/boards/snapgear/io.c b/arch/sh/boards/snapgear/io.c
index e2eb78fc381d..0f4824264557 100644
--- a/arch/sh/boards/snapgear/io.c
+++ b/arch/sh/boards/snapgear/io.c
@@ -1,6 +1,4 @@
-/*
- * linux/arch/sh/kernel/io_7751se.c
- *
+/*
* Copyright (C) 2002 David McCullough <davidm@snapgear.com>
* Copyright (C) 2001 Ian da Silva, Jeremy Siegel
* Based largely on io_se.c.
@@ -11,67 +9,22 @@
* placeholder code from io_se.c left in with the
* expectation of later SuperIO and PCMCIA access.
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/addrspace.h>
-#include <asm/pci.h>
-#include "../../drivers/pci/pci-sh7751.h"
-
#ifdef CONFIG_SH_SECUREEDGE5410
unsigned short secureedge5410_ioport;
#endif
-/*
- * The SnapGear uses the built-in PCI controller (PCIC)
- * of the 7751 processor
- */
-
-#define PCIIOBR (volatile long *)PCI_REG(SH7751_PCIIOBR)
-#define PCIMBR (volatile long *)PCI_REG(SH7751_PCIMBR)
-#define PCI_IO_AREA SH7751_PCI_IO_BASE
-#define PCI_MEM_AREA SH7751_PCI_CONFIG_BASE
-
-
-#define PCI_IOMAP(adr) (PCI_IO_AREA + (adr & ~SH7751_PCIIOBR_MASK))
-
-
-#define maybebadio(name,port) \
- printk("bad PC-like io %s for port 0x%lx at 0x%08x\n", \
- #name, (port), (__u32) __builtin_return_address(0))
-
-
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000);
-}
-
-
static inline volatile __u16 *port2adr(unsigned int port)
{
-#if 0
- if (port >= 0x2000)
- return (volatile __u16 *) (PA_MRSHPC + (port - 0x2000));
-#endif
- maybebadio(name,(unsigned long)port);
+ maybebadio((unsigned long)port);
return (volatile __u16*)port;
}
-
-/* In case someone configures the kernel w/o PCI support: in that */
-/* scenario, don't ever bother to check for PCI-window addresses */
-
-/* NOTE: WINDOW CHECK MAY BE A BIT OFF, HIGH PCIBIOS_MIN_IO WRAPS? */
-#if defined(CONFIG_PCI)
-#define CHECK_SH7751_PCIIO(port) \
- ((port >= PCIBIOS_MIN_IO) && (port < (PCIBIOS_MIN_IO + SH7751_PCI_IO_SIZE)))
-#else
-#define CHECK_SH7751_PCIIO(port) (0)
-#endif
-
/*
* General outline: remap really low stuff [eventually] to SuperIO,
* stuff in PCI IO space (at or above window at pci.h:PCIBIOS_MIN_IO)
@@ -79,148 +32,106 @@ static inline volatile __u16 *port2adr(unsigned int port)
* should be way beyond the window, and is used w/o translation for
* compatibility.
*/
-
unsigned char snapgear_inb(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned char *)pci_ioaddr(port);
else
- return (*port2adr(port))&0xff;
+ return (*port2adr(port)) & 0xff;
}
-
unsigned char snapgear_inb_p(unsigned long port)
{
unsigned char v;
if (PXSEG(port))
v = *(volatile unsigned char *)port;
- else if (CHECK_SH7751_PCIIO(port))
- v = *(volatile unsigned char *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ v = *(volatile unsigned char *)pci_ioaddr(port);
else
- v = (*port2adr(port))&0xff;
- delay();
+ v = (*port2adr(port))&0xff;
+ ctrl_delay();
return v;
}
-
unsigned short snapgear_inw(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned short *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned short *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned short *)pci_ioaddr(port);
else if (port >= 0x2000)
return *port2adr(port);
else
- maybebadio(inw, port);
+ maybebadio(port);
return 0;
}
-
unsigned int snapgear_inl(unsigned long port)
{
if (PXSEG(port))
return *(volatile unsigned long *)port;
- else if (CHECK_SH7751_PCIIO(port))
- return *(volatile unsigned int *)PCI_IOMAP(port);
+ else if (is_pci_ioaddr(port))
+ return *(volatile unsigned int *)pci_ioaddr(port);
else if (port >= 0x2000)
return *port2adr(port);
else
- maybebadio(inl, port);
+ maybebadio(port);
return 0;
}
-
void snapgear_outb(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned char*)pci_ioaddr(port)) = value;
else
*(port2adr(port)) = value;
}
-
void snapgear_outb_p(unsigned char value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned char *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned char*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned char*)pci_ioaddr(port)) = value;
else
*(port2adr(port)) = value;
- delay();
+ ctrl_delay();
}
-
void snapgear_outw(unsigned short value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned short *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned short *)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned short *)pci_ioaddr(port)) = value;
else if (port >= 0x2000)
*port2adr(port) = value;
else
- maybebadio(outw, port);
+ maybebadio(port);
}
-
void snapgear_outl(unsigned int value, unsigned long port)
{
if (PXSEG(port))
*(volatile unsigned long *)port = value;
- else if (CHECK_SH7751_PCIIO(port))
- *((unsigned long*)PCI_IOMAP(port)) = value;
+ else if (is_pci_ioaddr(port))
+ *((unsigned long*)pci_ioaddr(port)) = value;
else
- maybebadio(outl, port);
+ maybebadio(port);
}
void snapgear_insl(unsigned long port, void *addr, unsigned long count)
{
- maybebadio(insl, port);
+ maybebadio(port);
}
void snapgear_outsl(unsigned long port, const void *addr, unsigned long count)
{
- maybebadio(outsw, port);
-}
-
-/* Map ISA bus address to the real address. Only for PCMCIA. */
-
-
-/* ISA page descriptor. */
-static __u32 sh_isa_memmap[256];
-
-
-#if 0
-static int sh_isa_mmap(__u32 start, __u32 length, __u32 offset)
-{
- int idx;
-
- if (start >= 0x100000 || (start & 0xfff) || (length != 0x1000))
- return -1;
-
- idx = start >> 12;
- sh_isa_memmap[idx] = 0xb8000000 + (offset &~ 0xfff);
-#if 0
- printk("sh_isa_mmap: start %x len %x offset %x (idx %x paddr %x)\n",
- start, length, offset, idx, sh_isa_memmap[idx]);
-#endif
- return 0;
-}
-#endif
-
-unsigned long snapgear_isa_port2addr(unsigned long offset)
-{
- int idx;
-
- idx = (offset >> 12) & 0xff;
- offset &= 0xfff;
- return sh_isa_memmap[idx] + offset;
+ maybebadio(port);
}
diff --git a/arch/sh/boards/snapgear/rtc.c b/arch/sh/boards/snapgear/rtc.c
index b71e009da35c..1659fdd6695a 100644
--- a/arch/sh/boards/snapgear/rtc.c
+++ b/arch/sh/boards/snapgear/rtc.c
@@ -17,14 +17,9 @@
#include <linux/time.h>
#include <linux/rtc.h>
#include <linux/mc146818rtc.h>
-
#include <asm/io.h>
-#include <asm/rtc.h>
-#include <asm/mc146818rtc.h>
-
-/****************************************************************************/
-static int use_ds1302 = 0;
+static int use_ds1302;
/****************************************************************************/
/*
@@ -82,10 +77,6 @@ static unsigned int ds1302_readbyte(unsigned int addr)
unsigned int val;
unsigned long flags;
-#if 0
- printk("SnapGear RTC: ds1302_readbyte(addr=%x)\n", addr);
-#endif
-
local_irq_save(flags);
set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK);
set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
@@ -104,10 +95,6 @@ static void ds1302_writebyte(unsigned int addr, unsigned int val)
{
unsigned long flags;
-#if 0
- printk("SnapGear RTC: ds1302_writebyte(addr=%x)\n", addr);
-#endif
-
local_irq_save(flags);
set_dirp(get_dirp() | RTC_RESET | RTC_IODATA | RTC_SCLK);
set_dp(get_dp() & ~(RTC_RESET | RTC_IODATA | RTC_SCLK));
@@ -168,11 +155,8 @@ void __init secureedge5410_rtc_init(void)
}
if (use_ds1302) {
- rtc_get_time = snapgear_rtc_gettimeofday;
- rtc_set_time = snapgear_rtc_settimeofday;
- } else {
- rtc_get_time = sh_rtc_gettimeofday;
- rtc_set_time = sh_rtc_settimeofday;
+ rtc_sh_get_time = snapgear_rtc_gettimeofday;
+ rtc_sh_set_time = snapgear_rtc_settimeofday;
}
printk("SnapGear RTC: using %s rtc.\n", use_ds1302 ? "ds1302" : "internal");
@@ -187,10 +171,8 @@ void snapgear_rtc_gettimeofday(struct timespec *ts)
{
unsigned int sec, min, hr, day, mon, yr;
- if (!use_ds1302) {
- sh_rtc_gettimeofday(ts);
+ if (!use_ds1302)
return;
- }
sec = bcd2int(ds1302_readbyte(RTC_ADDR_SEC));
min = bcd2int(ds1302_readbyte(RTC_ADDR_MIN));
@@ -231,7 +213,7 @@ int snapgear_rtc_settimeofday(const time_t secs)
unsigned long nowtime;
if (!use_ds1302)
- return sh_rtc_settimeofday(secs);
+ return 0;
/*
* This is called direct from the kernel timer handling code.
@@ -240,10 +222,6 @@ int snapgear_rtc_settimeofday(const time_t secs)
nowtime = secs;
-#if 1
- printk("SnapGear RTC: snapgear_rtc_settimeofday(nowtime=%ld)\n", nowtime);
-#endif
-
/* STOP RTC */
ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
@@ -329,5 +307,3 @@ void secureedge5410_cmos_write(unsigned char val, int addr)
default: break;
}
}
-
-/****************************************************************************/
diff --git a/arch/sh/boards/snapgear/setup.c b/arch/sh/boards/snapgear/setup.c
index f1f7c70c9402..540d0bf16446 100644
--- a/arch/sh/boards/snapgear/setup.c
+++ b/arch/sh/boards/snapgear/setup.c
@@ -1,5 +1,4 @@
-/****************************************************************************/
-/*
+/*
* linux/arch/sh/boards/snapgear/setup.c
*
* Copyright (C) 2002 David McCullough <davidm@snapgear.com>
@@ -12,8 +11,6 @@
* Modified for 7751 Solution Engine by
* Ian da Silva and Jeremy Siegel, 2001.
*/
-/****************************************************************************/
-
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -21,14 +18,13 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/sched.h>
-
#include <asm/machvec.h>
-#include <asm/mach/io.h>
+#include <asm/snapgear.h>
#include <asm/irq.h>
#include <asm/io.h>
+#include <asm/rtc.h>
#include <asm/cpu/timer.h>
-extern void (*board_time_init)(void);
extern void secureedge5410_rtc_init(void);
extern void pcibios_init(void);
@@ -37,7 +33,7 @@ extern void pcibios_init(void);
* EraseConfig handling functions
*/
-static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t eraseconfig_interrupt(int irq, void *dev_id)
{
volatile char dummy __attribute__((unused)) = * (volatile char *) 0xb8000000;
@@ -85,101 +81,20 @@ static void __init init_snapgear_IRQ(void)
make_ipr_irq(IRL3_IRQ, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY);
}
-/****************************************************************************/
-/*
- * Fast poll interrupt simulator.
- */
-
/*
- * Leave all of the fast timer/fast poll stuff commented out for now, since
- * it's not clear whether it actually works or not. Since it wasn't being used
- * at all in 2.4, we'll assume it's not sane for 2.6 either.. -- PFM
- */
-#if 0
-#define FAST_POLL 1000
-//#define FAST_POLL_INTR
-
-#define FASTTIMER_IRQ 17
-#define FASTTIMER_IPR_ADDR INTC_IPRA
-#define FASTTIMER_IPR_POS 2
-#define FASTTIMER_PRIORITY 3
-
-#ifdef FAST_POLL_INTR
-#define TMU1_TCR_INIT 0x0020
-#else
-#define TMU1_TCR_INIT 0
-#endif
-#define TMU_TSTR_INIT 1
-#define TMU1_TCR_CALIB 0x0000
-
-
-#ifdef FAST_POLL_INTR
-static void fast_timer_irq(int irq, void *dev_instance, struct pt_regs *regs)
-{
- unsigned long timer_status;
- timer_status = ctrl_inw(TMU1_TCR);
- timer_status &= ~0x100;
- ctrl_outw(timer_status, TMU1_TCR);
-}
-#endif
-
-/*
- * return the current ticks on the fast timer
- */
-
-unsigned long fast_timer_count(void)
-{
- return(ctrl_inl(TMU1_TCNT));
-}
-
-/*
- * setup a fast timer for profiling etc etc
+ * Initialize the board
*/
-
-static void setup_fast_timer()
-{
- unsigned long interval;
-
-#ifdef FAST_POLL_INTR
- interval = (current_cpu_data.module_clock/4 + FAST_POLL/2) / FAST_POLL;
-
- make_ipr_irq(FASTTIMER_IRQ, FASTTIMER_IPR_ADDR, FASTTIMER_IPR_POS,
- FASTTIMER_PRIORITY);
-
- printk("SnapGear: %dHz fast timer on IRQ %d\n",FAST_POLL,FASTTIMER_IRQ);
-
- if (request_irq(FASTTIMER_IRQ, fast_timer_irq, 0, "SnapGear fast timer",
- NULL) != 0)
- printk("%s(%d): request_irq() failed?\n", __FILE__, __LINE__);
-#else
- printk("SnapGear: fast timer running\n",FAST_POLL,FASTTIMER_IRQ);
- interval = 0xffffffff;
-#endif
-
- ctrl_outb(ctrl_inb(TMU_TSTR) & ~0x2, TMU_TSTR); /* disable timer 1 */
- ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
- ctrl_outl(interval, TMU1_TCOR);
- ctrl_outl(interval, TMU1_TCNT);
- ctrl_outb(ctrl_inb(TMU_TSTR) | 0x2, TMU_TSTR); /* enable timer 1 */
-
- printk("Timer count 1 = 0x%x\n", fast_timer_count());
- udelay(1000);
- printk("Timer count 2 = 0x%x\n", fast_timer_count());
-}
-#endif
-
-/****************************************************************************/
-
-const char *get_system_type(void)
+static void __init snapgear_setup(char **cmdline_p)
{
- return "SnapGear SecureEdge5410";
+ board_time_init = secureedge5410_rtc_init;
}
/*
* The Machine Vector
*/
-
struct sh_machine_vector mv_snapgear __initmv = {
+ .mv_name = "SnapGear SecureEdge5410",
+ .mv_setup = snapgear_setup,
.mv_nr_irqs = 72,
.mv_inb = snapgear_inb,
@@ -196,20 +111,6 @@ struct sh_machine_vector mv_snapgear __initmv = {
.mv_outw_p = snapgear_outw,
.mv_outl_p = snapgear_outl,
- .mv_isa_port2addr = snapgear_isa_port2addr,
-
.mv_init_irq = init_snapgear_IRQ,
};
ALIAS_MV(snapgear)
-
-/*
- * Initialize the board
- */
-
-int __init platform_setup(void)
-{
- board_time_init = secureedge5410_rtc_init;
-
- return 0;
-}
-
diff --git a/arch/sh/boards/superh/microdev/io.c b/arch/sh/boards/superh/microdev/io.c
index 4836b9422e27..83419bf4c834 100644
--- a/arch/sh/boards/superh/microdev/io.c
+++ b/arch/sh/boards/superh/microdev/io.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/io_microdev.c
+ * linux/arch/sh/boards/superh/microdev/io.c
*
* Copyright (C) 2003 Sean McGoogan (Sean.McGoogan@superh.com)
* Copyright (C) 2003, 2004 SuperH, Inc.
diff --git a/arch/sh/boards/superh/microdev/irq.c b/arch/sh/boards/superh/microdev/irq.c
index 236398fbc083..8c64baa30364 100644
--- a/arch/sh/boards/superh/microdev/irq.c
+++ b/arch/sh/boards/superh/microdev/irq.c
@@ -11,14 +11,12 @@
#include <linux/init.h>
#include <linux/irq.h>
-
#include <asm/system.h>
#include <asm/io.h>
#include <asm/microdev.h>
#define NUM_EXTERNAL_IRQS 16 /* IRL0 .. IRL15 */
-
static const struct {
unsigned char fpgaIrq;
unsigned char mapped;
@@ -93,53 +91,42 @@ static struct hw_interrupt_type microdev_irq_type = {
static void disable_microdev_irq(unsigned int irq)
{
- unsigned int flags;
unsigned int fpgaIrq;
- if (irq >= NUM_EXTERNAL_IRQS) return;
- if (!fpgaIrqTable[irq].mapped) return;
+ if (irq >= NUM_EXTERNAL_IRQS)
+ return;
+ if (!fpgaIrqTable[irq].mapped)
+ return;
fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
- /* disable interrupts */
- local_irq_save(flags);
-
- /* disable interupts on the FPGA INTC register */
+ /* disable interupts on the FPGA INTC register */
ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTDSB_REG);
-
- /* restore interrupts */
- local_irq_restore(flags);
}
static void enable_microdev_irq(unsigned int irq)
{
unsigned long priorityReg, priorities, pri;
- unsigned int flags;
unsigned int fpgaIrq;
-
- if (irq >= NUM_EXTERNAL_IRQS) return;
- if (!fpgaIrqTable[irq].mapped) return;
+ if (unlikely(irq >= NUM_EXTERNAL_IRQS))
+ return;
+ if (unlikely(!fpgaIrqTable[irq].mapped))
+ return;
pri = 15 - irq;
fpgaIrq = fpgaIrqTable[irq].fpgaIrq;
priorityReg = MICRODEV_FPGA_INTPRI_REG(fpgaIrq);
- /* disable interrupts */
- local_irq_save(flags);
-
- /* set priority for the interrupt */
+ /* set priority for the interrupt */
priorities = ctrl_inl(priorityReg);
priorities &= ~MICRODEV_FPGA_INTPRI_MASK(fpgaIrq);
priorities |= MICRODEV_FPGA_INTPRI_LEVEL(fpgaIrq, pri);
ctrl_outl(priorities, priorityReg);
- /* enable interupts on the FPGA INTC register */
+ /* enable interupts on the FPGA INTC register */
ctrl_outl(MICRODEV_FPGA_INTC_MASK(fpgaIrq), MICRODEV_FPGA_INTENB_REG);
-
- /* restore interrupts */
- local_irq_restore(flags);
}
/* This functions sets the desired irq handler to be a MicroDev type */
@@ -158,9 +145,7 @@ static void mask_and_ack_microdev(unsigned int irq)
static void end_microdev_irq(unsigned int irq)
{
if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- {
enable_microdev_irq(irq);
- }
}
extern void __init init_microdev_irq(void)
@@ -171,9 +156,7 @@ extern void __init init_microdev_irq(void)
ctrl_outl(~0ul, MICRODEV_FPGA_INTDSB_REG);
for (i = 0; i < NUM_EXTERNAL_IRQS; i++)
- {
make_microdev_irq(i);
- }
}
extern void microdev_print_fpga_intc_status(void)
diff --git a/arch/sh/boards/superh/microdev/led.c b/arch/sh/boards/superh/microdev/led.c
index a38f5351bd16..36e54b47a752 100644
--- a/arch/sh/boards/superh/microdev/led.c
+++ b/arch/sh/boards/superh/microdev/led.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/led_microdev.c
+ * linux/arch/sh/boards/superh/microdev/led.c
*
* Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
* Copyright (C) 2003 Richard Curnow (Richard.Curnow@superh.com)
diff --git a/arch/sh/boards/superh/microdev/setup.c b/arch/sh/boards/superh/microdev/setup.c
index 61b402a3f5d7..031c814e6e76 100644
--- a/arch/sh/boards/superh/microdev/setup.c
+++ b/arch/sh/boards/superh/microdev/setup.c
@@ -10,7 +10,6 @@
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*/
-
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
@@ -21,41 +20,6 @@
extern void microdev_heartbeat(void);
-/*
- * The Machine Vector
- */
-
-struct sh_machine_vector mv_sh4202_microdev __initmv = {
- .mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */
-
- .mv_inb = microdev_inb,
- .mv_inw = microdev_inw,
- .mv_inl = microdev_inl,
- .mv_outb = microdev_outb,
- .mv_outw = microdev_outw,
- .mv_outl = microdev_outl,
-
- .mv_inb_p = microdev_inb_p,
- .mv_inw_p = microdev_inw_p,
- .mv_inl_p = microdev_inl_p,
- .mv_outb_p = microdev_outb_p,
- .mv_outw_p = microdev_outw_p,
- .mv_outl_p = microdev_outl_p,
-
- .mv_insb = microdev_insb,
- .mv_insw = microdev_insw,
- .mv_insl = microdev_insl,
- .mv_outsb = microdev_outsb,
- .mv_outsw = microdev_outsw,
- .mv_outsl = microdev_outsl,
-
- .mv_init_irq = init_microdev_irq,
-
-#ifdef CONFIG_HEARTBEAT
- .mv_heartbeat = microdev_heartbeat,
-#endif
-};
-ALIAS_MV(sh4202_microdev)
/****************************************************************************/
@@ -113,11 +77,6 @@ ALIAS_MV(sh4202_microdev)
/* assume a Keyboard Controller is present */
int microdev_kbd_controller_present = 1;
-const char *get_system_type(void)
-{
- return "SH4-202 MicroDev";
-}
-
static struct resource smc91x_resources[] = {
[0] = {
.start = 0x300,
@@ -291,25 +250,9 @@ static int __init microdev_devices_setup(void)
return platform_add_devices(microdev_devices, ARRAY_SIZE(microdev_devices));
}
-__initcall(microdev_devices_setup);
-
-void __init platform_setup(void)
-{
- int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
- const int fpgaRevision = *fpgaRevisionRegister;
- int * const CacheControlRegister = (int*)CCR;
-
- printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
- get_system_type(), fpgaRevision, *CacheControlRegister);
-}
-
-
-/****************************************************************************/
-
-
- /*
- * Setup for the SMSC FDC37C93xAPM
- */
+/*
+ * Setup for the SMSC FDC37C93xAPM
+ */
static int __init smsc_superio_setup(void)
{
@@ -412,8 +355,52 @@ static int __init smsc_superio_setup(void)
return 0;
}
+static void __init microdev_setup(char **cmdline_p)
+{
+ int * const fpgaRevisionRegister = (int*)(MICRODEV_FPGA_GP_BASE + 0x8ul);
+ const int fpgaRevision = *fpgaRevisionRegister;
+ int * const CacheControlRegister = (int*)CCR;
+
+ device_initcall(microdev_devices_setup);
+ device_initcall(smsc_superio_setup);
-/* This is grotty, but, because kernel is always referenced on the link line
- * before any devices, this is safe.
+ printk("SuperH %s board (FPGA rev: 0x%0x, CCR: 0x%0x)\n",
+ get_system_type(), fpgaRevision, *CacheControlRegister);
+}
+
+/*
+ * The Machine Vector
*/
-__initcall(smsc_superio_setup);
+struct sh_machine_vector mv_sh4202_microdev __initmv = {
+ .mv_name = "SH4-202 MicroDev",
+ .mv_setup = microdev_setup,
+ .mv_nr_irqs = 72, /* QQQ need to check this - use the MACRO */
+
+ .mv_inb = microdev_inb,
+ .mv_inw = microdev_inw,
+ .mv_inl = microdev_inl,
+ .mv_outb = microdev_outb,
+ .mv_outw = microdev_outw,
+ .mv_outl = microdev_outl,
+
+ .mv_inb_p = microdev_inb_p,
+ .mv_inw_p = microdev_inw_p,
+ .mv_inl_p = microdev_inl_p,
+ .mv_outb_p = microdev_outb_p,
+ .mv_outw_p = microdev_outw_p,
+ .mv_outl_p = microdev_outl_p,
+
+ .mv_insb = microdev_insb,
+ .mv_insw = microdev_insw,
+ .mv_insl = microdev_insl,
+ .mv_outsb = microdev_outsb,
+ .mv_outsw = microdev_outsw,
+ .mv_outsl = microdev_outsl,
+
+ .mv_init_irq = init_microdev_irq,
+
+#ifdef CONFIG_HEARTBEAT
+ .mv_heartbeat = microdev_heartbeat,
+#endif
+};
+ALIAS_MV(sh4202_microdev)
diff --git a/arch/sh/boards/titan/Makefile b/arch/sh/boards/titan/Makefile
new file mode 100644
index 000000000000..08d753700062
--- /dev/null
+++ b/arch/sh/boards/titan/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for the Nimble Microsystems TITAN specific parts of the kernel
+#
+
+obj-y := setup.o io.o
diff --git a/arch/sh/boards/titan/io.c b/arch/sh/boards/titan/io.c
new file mode 100644
index 000000000000..4730c1dd697d
--- /dev/null
+++ b/arch/sh/boards/titan/io.c
@@ -0,0 +1,126 @@
+/*
+ * I/O routines for Titan
+ */
+#include <linux/pci.h>
+#include <asm/machvec.h>
+#include <asm/addrspace.h>
+#include <asm/titan.h>
+#include <asm/io.h>
+
+static inline unsigned int port2adr(unsigned int port)
+{
+ maybebadio((unsigned long)port);
+ return port;
+}
+
+u8 titan_inb(unsigned long port)
+{
+ if (PXSEG(port))
+ return ctrl_inb(port);
+ else if (is_pci_ioaddr(port))
+ return ctrl_inb(pci_ioaddr(port));
+ return ctrl_inw(port2adr(port)) & 0xff;
+}
+
+u8 titan_inb_p(unsigned long port)
+{
+ u8 v;
+
+ if (PXSEG(port))
+ v = ctrl_inb(port);
+ else if (is_pci_ioaddr(port))
+ v = ctrl_inb(pci_ioaddr(port));
+ else
+ v = ctrl_inw(port2adr(port)) & 0xff;
+ ctrl_delay();
+ return v;
+}
+
+u16 titan_inw(unsigned long port)
+{
+ if (PXSEG(port))
+ return ctrl_inw(port);
+ else if (is_pci_ioaddr(port))
+ return ctrl_inw(pci_ioaddr(port));
+ else if (port >= 0x2000)
+ return ctrl_inw(port2adr(port));
+ else
+ maybebadio(port);
+ return 0;
+}
+
+u32 titan_inl(unsigned long port)
+{
+ if (PXSEG(port))
+ return ctrl_inl(port);
+ else if (is_pci_ioaddr(port))
+ return ctrl_inl(pci_ioaddr(port));
+ else if (port >= 0x2000)
+ return ctrl_inw(port2adr(port));
+ else
+ maybebadio(port);
+ return 0;
+}
+
+void titan_outb(u8 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outb(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outb(value, pci_ioaddr(port));
+ else
+ ctrl_outw(value, port2adr(port));
+}
+
+void titan_outb_p(u8 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outb(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outb(value, pci_ioaddr(port));
+ else
+ ctrl_outw(value, port2adr(port));
+ ctrl_delay();
+}
+
+void titan_outw(u16 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outw(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outw(value, pci_ioaddr(port));
+ else if (port >= 0x2000)
+ ctrl_outw(value, port2adr(port));
+ else
+ maybebadio(port);
+}
+
+void titan_outl(u32 value, unsigned long port)
+{
+ if (PXSEG(port))
+ ctrl_outl(value, port);
+ else if (is_pci_ioaddr(port))
+ ctrl_outl(value, pci_ioaddr(port));
+ else
+ maybebadio(port);
+}
+
+void titan_insl(unsigned long port, void *dst, unsigned long count)
+{
+ maybebadio(port);
+}
+
+void titan_outsl(unsigned long port, const void *src, unsigned long count)
+{
+ maybebadio(port);
+}
+
+void __iomem *titan_ioport_map(unsigned long port, unsigned int size)
+{
+ if (PXSEG(port) || is_pci_memaddr(port))
+ return (void __iomem *)port;
+ else if (is_pci_ioaddr(port))
+ return (void __iomem *)pci_ioaddr(port);
+
+ return (void __iomem *)port2adr(port);
+}
diff --git a/arch/sh/boards/titan/setup.c b/arch/sh/boards/titan/setup.c
new file mode 100644
index 000000000000..52b66d8b8d2a
--- /dev/null
+++ b/arch/sh/boards/titan/setup.c
@@ -0,0 +1,48 @@
+/*
+ * Setup for Titan
+ */
+
+#include <linux/init.h>
+#include <asm/irq.h>
+#include <asm/titan.h>
+#include <asm/io.h>
+
+extern void __init pcibios_init_platform(void);
+
+static void __init init_titan_irq(void)
+{
+ /* enable individual interrupt mode for externals */
+ ctrl_outw(ctrl_inw(INTC_ICR) | INTC_ICR_IRLM, INTC_ICR);
+
+ make_ipr_irq( TITAN_IRQ_WAN, IRL0_IPR_ADDR, IRL0_IPR_POS, IRL0_PRIORITY); /* PCIRQ0 */
+ make_ipr_irq( TITAN_IRQ_LAN, IRL1_IPR_ADDR, IRL1_IPR_POS, IRL1_PRIORITY); /* PCIRQ1 */
+ make_ipr_irq( TITAN_IRQ_MPCIA, IRL2_IPR_ADDR, IRL2_IPR_POS, IRL2_PRIORITY); /* PCIRQ2 */
+ make_ipr_irq( TITAN_IRQ_USB, IRL3_IPR_ADDR, IRL3_IPR_POS, IRL3_PRIORITY); /* PCIRQ3 */
+}
+
+struct sh_machine_vector mv_titan __initmv = {
+ .mv_name = "Titan",
+
+ .mv_inb = titan_inb,
+ .mv_inw = titan_inw,
+ .mv_inl = titan_inl,
+ .mv_outb = titan_outb,
+ .mv_outw = titan_outw,
+ .mv_outl = titan_outl,
+
+ .mv_inb_p = titan_inb_p,
+ .mv_inw_p = titan_inw,
+ .mv_inl_p = titan_inl,
+ .mv_outb_p = titan_outb_p,
+ .mv_outw_p = titan_outw,
+ .mv_outl_p = titan_outl,
+
+ .mv_insl = titan_insl,
+ .mv_outsl = titan_outsl,
+
+ .mv_ioport_map = titan_ioport_map,
+
+ .mv_init_irq = init_titan_irq,
+ .mv_init_pci = pcibios_init_platform,
+};
+ALIAS_MV(titan)
diff --git a/arch/sh/boards/unknown/setup.c b/arch/sh/boards/unknown/setup.c
index c5e4ed10876b..1c941370a2e3 100644
--- a/arch/sh/boards/unknown/setup.c
+++ b/arch/sh/boards/unknown/setup.c
@@ -14,19 +14,8 @@
*/
#include <linux/init.h>
#include <asm/machvec.h>
-#include <asm/irq.h>
struct sh_machine_vector mv_unknown __initmv = {
- .mv_nr_irqs = NR_IRQS,
+ .mv_name = "Unknown",
};
ALIAS_MV(unknown)
-
-const char *get_system_type(void)
-{
- return "Unknown";
-}
-
-void __init platform_setup(void)
-{
-}
-
diff --git a/arch/sh/boot/.gitignore b/arch/sh/boot/.gitignore
new file mode 100644
index 000000000000..b6718de23693
--- /dev/null
+++ b/arch/sh/boot/.gitignore
@@ -0,0 +1 @@
+zImage
diff --git a/arch/sh/boot/compressed/Makefile b/arch/sh/boot/compressed/Makefile
index 75a6876bf6c6..e5f443790079 100644
--- a/arch/sh/boot/compressed/Makefile
+++ b/arch/sh/boot/compressed/Makefile
@@ -18,13 +18,20 @@ endif
# Assign dummy values if these 2 variables are not defined,
# in order to suppress error message.
#
+CONFIG_PAGE_OFFSET ?= 0x80000000
CONFIG_MEMORY_START ?= 0x0c000000
CONFIG_BOOT_LINK_OFFSET ?= 0x00800000
-IMAGE_OFFSET := $(shell printf "0x%8x" $$[0x80000000+$(CONFIG_MEMORY_START)+$(CONFIG_BOOT_LINK_OFFSET)])
+
+IMAGE_OFFSET := $(shell printf "0x%08x" $$[$(CONFIG_PAGE_OFFSET) + \
+ $(CONFIG_MEMORY_START) + \
+ $(CONFIG_BOOT_LINK_OFFSET)])
+
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
LDFLAGS_vmlinux := -Ttext $(IMAGE_OFFSET) -e startup -T $(obj)/../../kernel/vmlinux.lds
-$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o FORCE
+
+$(obj)/vmlinux: $(OBJECTS) $(obj)/piggy.o $(LIBGCC) FORCE
$(call if_changed,ld)
@:
diff --git a/arch/sh/cchips/Kconfig b/arch/sh/cchips/Kconfig
index 155d139884c3..0582ca8346b6 100644
--- a/arch/sh/cchips/Kconfig
+++ b/arch/sh/cchips/Kconfig
@@ -65,6 +65,11 @@ config HD64461_IRQ
Do not change this unless you know what you are doing.
+config HD64461_IOBASE
+ hex "HD64461 start address"
+ depends on HD64461
+ default "0xb0000000"
+
config HD64461_ENABLER
bool "HD64461 PCMCIA enabler"
depends on HD64461
@@ -73,7 +78,6 @@ config HD64461_ENABLER
via the HD64461 companion chip.
Otherwise, say N.
-
config HD64465_IOBASE
hex "HD64465 start address"
depends on HD64465
diff --git a/arch/sh/cchips/hd6446x/hd64461/io.c b/arch/sh/cchips/hd6446x/hd64461/io.c
index ac3062671db7..7909a1b7b512 100644
--- a/arch/sh/cchips/hd6446x/hd64461/io.c
+++ b/arch/sh/cchips/hd6446x/hd64461/io.c
@@ -1,11 +1,10 @@
/*
- * $Id: io.c,v 1.6 2004/03/16 00:07:50 lethal Exp $
* Copyright (C) 2000 YAEGASHI Takeshi
* Typical I/O routines for HD64461 system.
*/
#include <asm/io.h>
-#include <asm/hd64461/hd64461.h>
+#include <asm/hd64461.h>
#define MEM_BASE (CONFIG_HD64461_IOBASE - HD64461_STBCR)
@@ -54,11 +53,6 @@ static __inline__ unsigned long PORT2ADDR(unsigned long port)
return 0xa0000000 + (port & 0x1fffffff);
}
-static inline void delay(void)
-{
- ctrl_inw(0xa0000000);
-}
-
unsigned char hd64461_inb(unsigned long port)
{
return *(volatile unsigned char*)PORT2ADDR(port);
@@ -67,7 +61,7 @@ unsigned char hd64461_inb(unsigned long port)
unsigned char hd64461_inb_p(unsigned long port)
{
unsigned long v = *(volatile unsigned char*)PORT2ADDR(port);
- delay();
+ ctrl_delay();
return v;
}
@@ -89,7 +83,7 @@ void hd64461_outb(unsigned char b, unsigned long port)
void hd64461_outb_p(unsigned char b, unsigned long port)
{
*(volatile unsigned char*)PORT2ADDR(port) = b;
- delay();
+ ctrl_delay();
}
void hd64461_outw(unsigned short b, unsigned long port)
@@ -144,13 +138,13 @@ void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count)
while(count--) *addr=*buf++;
}
-unsigned short hd64461_readw(unsigned long addr)
+unsigned short hd64461_readw(void __iomem *addr)
{
- return *(volatile unsigned short*)(MEM_BASE+addr);
+ return ctrl_inw(MEM_BASE+(unsigned long __force)addr);
}
-void hd64461_writew(unsigned short b, unsigned long addr)
+void hd64461_writew(unsigned short b, void __iomem *addr)
{
- *(volatile unsigned short*)(MEM_BASE+addr) = b;
+ ctrl_outw(b, MEM_BASE+(unsigned long __force)addr);
}
diff --git a/arch/sh/cchips/hd6446x/hd64461/setup.c b/arch/sh/cchips/hd6446x/hd64461/setup.c
index ad126016720f..4d49b5cbcc13 100644
--- a/arch/sh/cchips/hd6446x/hd64461/setup.c
+++ b/arch/sh/cchips/hd6446x/hd64461/setup.c
@@ -11,36 +11,28 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/irq.h>
-
#include <asm/io.h>
#include <asm/irq.h>
-
-#include <asm/hd64461/hd64461.h>
+#include <asm/hd64461.h>
static void disable_hd64461_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64461_IRQBASE);
- local_irq_save(flags);
nimr = inw(HD64461_NIMR);
nimr |= mask;
outw(nimr, HD64461_NIMR);
- local_irq_restore(flags);
}
static void enable_hd64461_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64461_IRQBASE);
- local_irq_save(flags);
nimr = inw(HD64461_NIMR);
nimr &= ~mask;
outw(nimr, HD64461_NIMR);
- local_irq_restore(flags);
}
static void mask_and_ack_hd64461(unsigned int irq)
@@ -79,7 +71,7 @@ static struct hw_interrupt_type hd64461_irq_type = {
.end = end_hd64461_irq,
};
-static irqreturn_t hd64461_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hd64461_interrupt(int irq, void *dev_id)
{
printk(KERN_INFO
"HD64461: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
diff --git a/arch/sh/cchips/hd6446x/hd64465/gpio.c b/arch/sh/cchips/hd6446x/hd64465/gpio.c
index 72320d02d69a..43431855ec86 100644
--- a/arch/sh/cchips/hd6446x/hd64465/gpio.c
+++ b/arch/sh/cchips/hd6446x/hd64465/gpio.c
@@ -85,7 +85,7 @@ static struct {
void *dev;
} handlers[GPIO_NPORTS * 8];
-static irqreturn_t hd64465_gpio_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t hd64465_gpio_interrupt(int irq, void *dev)
{
unsigned short port, pin, isr, mask, portpin;
diff --git a/arch/sh/cchips/hd6446x/hd64465/setup.c b/arch/sh/cchips/hd6446x/hd64465/setup.c
index d2b2851bc44b..d126e1f30dee 100644
--- a/arch/sh/cchips/hd6446x/hd64465/setup.c
+++ b/arch/sh/cchips/hd6446x/hd64465/setup.c
@@ -25,31 +25,25 @@
static void disable_hd64465_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
pr_debug("disable_hd64465_irq(%d): mask=%x\n", irq, mask);
- local_irq_save(flags);
nimr = inw(HD64465_REG_NIMR);
nimr |= mask;
outw(nimr, HD64465_REG_NIMR);
- local_irq_restore(flags);
}
static void enable_hd64465_irq(unsigned int irq)
{
- unsigned long flags;
unsigned short nimr;
unsigned short mask = 1 << (irq - HD64465_IRQ_BASE);
pr_debug("enable_hd64465_irq(%d): mask=%x\n", irq, mask);
- local_irq_save(flags);
nimr = inw(HD64465_REG_NIMR);
nimr &= ~mask;
outw(nimr, HD64465_REG_NIMR);
- local_irq_restore(flags);
}
@@ -90,7 +84,7 @@ static struct hw_interrupt_type hd64465_irq_type = {
};
-static irqreturn_t hd64465_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hd64465_interrupt(int irq, void *dev_id)
{
printk(KERN_INFO
"HD64465: spurious interrupt, nirr: 0x%x nimr: 0x%x\n",
diff --git a/arch/sh/cchips/voyagergx/irq.c b/arch/sh/cchips/voyagergx/irq.c
index 0dc1fb8f9687..bf1b28feca06 100644
--- a/arch/sh/cchips/voyagergx/irq.c
+++ b/arch/sh/cchips/voyagergx/irq.c
@@ -32,37 +32,30 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/rts7751r2d/rts7751r2d.h>
-#include <asm/rts7751r2d/voyagergx_reg.h>
+#include <asm/voyagergx.h>
static void disable_voyagergx_irq(unsigned int irq)
{
- unsigned long flags, val;
- unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
+ unsigned long val;
+ unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
- local_irq_save(flags);
val = inl(VOYAGER_INT_MASK);
val &= ~mask;
outl(val, VOYAGER_INT_MASK);
- local_irq_restore(flags);
}
-
static void enable_voyagergx_irq(unsigned int irq)
{
- unsigned long flags, val;
- unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
+ unsigned long val;
+ unsigned long mask = 1 << (irq - VOYAGER_IRQ_BASE);
pr_debug("disable_voyagergx_irq(%d): mask=%x\n", irq, mask);
- local_irq_save(flags);
val = inl(VOYAGER_INT_MASK);
val |= mask;
outl(val, VOYAGER_INT_MASK);
- local_irq_restore(flags);
}
-
static void mask_and_ack_voyagergx(unsigned int irq)
{
disable_voyagergx_irq(irq);
@@ -95,7 +88,7 @@ static struct hw_interrupt_type voyagergx_irq_type = {
.end = end_voyagergx_irq,
};
-static irqreturn_t voyagergx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t voyagergx_interrupt(int irq, void *dev_id)
{
printk(KERN_INFO
"VoyagerGX: spurious interrupt, status: 0x%x\n",
@@ -103,9 +96,6 @@ static irqreturn_t voyagergx_interrupt(int irq, void *dev_id, struct pt_regs *re
return IRQ_HANDLED;
}
-
-/*====================================================*/
-
static struct {
int (*func)(int, void *);
void *dev;
diff --git a/arch/sh/cchips/voyagergx/setup.c b/arch/sh/cchips/voyagergx/setup.c
index 139ca88ac9e6..66b2fedd7ad9 100644
--- a/arch/sh/cchips/voyagergx/setup.c
+++ b/arch/sh/cchips/voyagergx/setup.c
@@ -13,7 +13,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <asm/io.h>
-#include <asm/rts7751r2d/voyagergx_reg.h>
+#include <asm/voyagergx.h>
static int __init setup_voyagergx(void)
{
diff --git a/arch/sh/configs/adx_defconfig b/arch/sh/configs/adx_defconfig
deleted file mode 100644
index 353bfdc457d4..000000000000
--- a/arch/sh/configs/adx_defconfig
+++ /dev/null
@@ -1,539 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:26 2005
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-CONFIG_SH_ADX=y
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
-CONFIG_CPU_SH4=y
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7705 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-# CONFIG_CPU_SUBTYPE_SH7708 is not set
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-CONFIG_CPU_SUBTYPE_SH7750=y
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_MEMORY_START=0x08000000
-CONFIG_MEMORY_SIZE=0x00400000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_CF_ENABLER=y
-# CONFIG_CF_AREA5 is not set
-CONFIG_CF_AREA6=y
-CONFIG_CF_BASE_ADDR=0xb8000000
-CONFIG_SH_RTC=y
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
-CONFIG_SH_PCLK_FREQ=50000000
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# DMA support
-#
-# CONFIG_SH_DMA is not set
-
-#
-# Companion Chips
-#
-# CONFIG_HD6446X_SERIES is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-# CONFIG_PCI is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
-
-#
-# PCI Hotplug Support
-#
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# SH initrd options
-#
-# CONFIG_EMBEDDED_RAMDISK is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_IDE_SH=y
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-# CONFIG_NET is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_PROC_KCORE is not set
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
-CONFIG_SH_STANDARD_BIOS=y
-# CONFIG_EARLY_SCIF_CONSOLE is not set
-# CONFIG_EARLY_PRINTK is not set
-# CONFIG_KGDB is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC32 is not set
-# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/cqreek_defconfig b/arch/sh/configs/cqreek_defconfig
deleted file mode 100644
index 614662ae5789..000000000000
--- a/arch/sh/configs/cqreek_defconfig
+++ /dev/null
@@ -1,533 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:38 2005
-#
-CONFIG_SUPERH=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_HARDIRQS=y
-CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-
-#
-# Code maturity level options
-#
-CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
-CONFIG_BROKEN_ON_SMP=y
-
-#
-# General setup
-#
-CONFIG_LOCALVERSION=""
-CONFIG_SWAP=y
-# CONFIG_SYSVIPC is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-
-#
-# Loadable module support
-#
-# CONFIG_MODULES is not set
-
-#
-# System type
-#
-# CONFIG_SH_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SOLUTION_ENGINE is not set
-# CONFIG_SH_7300_SOLUTION_ENGINE is not set
-# CONFIG_SH_73180_SOLUTION_ENGINE is not set
-# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-CONFIG_SH_CQREEK=y
-# CONFIG_SH_DMIDA is not set
-# CONFIG_SH_EC3104 is not set
-# CONFIG_SH_SATURN is not set
-# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
-# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
-# CONFIG_SH_MPC1211 is not set
-# CONFIG_SH_SH03 is not set
-# CONFIG_SH_SECUREEDGE5410 is not set
-# CONFIG_SH_HS7751RVOIP is not set
-# CONFIG_SH_RTS7751R2D is not set
-# CONFIG_SH_EDOSK7705 is not set
-# CONFIG_SH_SH4202_MICRODEV is not set
-# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
-# CONFIG_CPU_SUBTYPE_SH7604 is not set
-# CONFIG_CPU_SUBTYPE_SH7300 is not set
-# CONFIG_CPU_SUBTYPE_SH7705 is not set
-# CONFIG_CPU_SUBTYPE_SH7707 is not set
-CONFIG_CPU_SUBTYPE_SH7708=y
-# CONFIG_CPU_SUBTYPE_SH7709 is not set
-# CONFIG_CPU_SUBTYPE_SH7750 is not set
-# CONFIG_CPU_SUBTYPE_SH7751 is not set
-# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
-# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
-# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_SH_DSP=y
-CONFIG_SH_ADC=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
-CONFIG_SH_PCLK_FREQ=1193182
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# DMA support
-#
-# CONFIG_SH_DMA is not set
-
-#
-# Companion Chips
-#
-# CONFIG_HD6446X_SERIES is not set
-
-#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
-#
-# CONFIG_PCI is not set
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-# CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
-
-#
-# PCI Hotplug Support
-#
-
-#
-# Executable file formats
-#
-CONFIG_BINFMT_ELF=y
-# CONFIG_BINFMT_FLAT is not set
-# CONFIG_BINFMT_MISC is not set
-
-#
-# SH initrd options
-#
-# CONFIG_EMBEDDED_RAMDISK is not set
-
-#
-# Device Drivers
-#
-
-#
-# Generic Driver Options
-#
-CONFIG_STANDALONE=y
-CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
-
-#
-# Memory Technology Devices (MTD)
-#
-# CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
-# CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-# CONFIG_BLK_DEV_LOOP is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
-CONFIG_IDE=y
-CONFIG_IDE_MAX_HWIFS=4
-CONFIG_BLK_DEV_IDE=y
-
-#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-CONFIG_IDE_SH=y
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
-
-#
-# SCSI device support
-#
-# CONFIG_SCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
-# CONFIG_MD is not set
-
-#
-# Fusion MPT device support
-#
-
-#
-# IEEE 1394 (FireWire) support
-#
-
-#
-# I2O device support
-#
-
-#
-# Networking support
-#
-# CONFIG_NET is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
-
-#
-# Telephony Support
-#
-# CONFIG_PHONE is not set
-
-#
-# Input device support
-#
-CONFIG_INPUT=y
-
-#
-# Userland interfaces
-#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
-# CONFIG_INPUT_EVDEV is not set
-# CONFIG_INPUT_EVBUG is not set
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
-# Input Device Drivers
-#
-CONFIG_INPUT_KEYBOARD=y
-CONFIG_KEYBOARD_ATKBD=y
-# CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_LKKBD is not set
-# CONFIG_KEYBOARD_XTKBD is not set
-# CONFIG_KEYBOARD_NEWTON is not set
-CONFIG_INPUT_MOUSE=y
-CONFIG_MOUSE_PS2=y
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_INPUT_MISC is not set
-
-#
-# Character devices
-#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-# CONFIG_SERIAL_NONSTANDARD is not set
-
-#
-# Serial drivers
-#
-# CONFIG_SERIAL_8250 is not set
-
-#
-# Non-8250 serial port support
-#
-# CONFIG_SERIAL_SH_SCI is not set
-CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
-
-#
-# IPMI
-#
-# CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
-# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
-# CONFIG_GEN_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C is not set
-
-#
-# Dallas's 1-wire bus
-#
-# CONFIG_W1 is not set
-
-#
-# Misc devices
-#
-
-#
-# Multimedia devices
-#
-# CONFIG_VIDEO_DEV is not set
-
-#
-# Digital Video Broadcasting Devices
-#
-
-#
-# Graphics support
-#
-# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-CONFIG_VGA_CONSOLE=y
-CONFIG_DUMMY_CONSOLE=y
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-# CONFIG_USB_ARCH_HAS_HCD is not set
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-
-#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
-#
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC is not set
-
-#
-# InfiniBand support
-#
-# CONFIG_INFINIBAND is not set
-
-#
-# File systems
-#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
-# CONFIG_REISERFS_FS is not set
-# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# CONFIG_AUTOFS_FS is not set
-# CONFIG_AUTOFS4_FS is not set
-
-#
-# CD-ROM/DVD Filesystems
-#
-# CONFIG_ISO9660_FS is not set
-# CONFIG_UDF_FS is not set
-
-#
-# DOS/FAT/NT Filesystems
-#
-# CONFIG_MSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-# CONFIG_PROC_KCORE is not set
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-# CONFIG_TMPFS is not set
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
-CONFIG_RAMFS=y
-
-#
-# Miscellaneous filesystems
-#
-# CONFIG_ADFS_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_HFSPLUS_FS is not set
-# CONFIG_BEFS_FS is not set
-# CONFIG_BFS_FS is not set
-# CONFIG_EFS_FS is not set
-# CONFIG_CRAMFS is not set
-# CONFIG_VXFS_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_QNX4FS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
-
-#
-# Partition Types
-#
-# CONFIG_PARTITION_ADVANCED is not set
-CONFIG_MSDOS_PARTITION=y
-
-#
-# Native Language Support
-#
-# CONFIG_NLS is not set
-
-#
-# Profiling support
-#
-# CONFIG_PROFILING is not set
-
-#
-# Kernel hacking
-#
-# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
-CONFIG_SH_STANDARD_BIOS=y
-# CONFIG_EARLY_PRINTK is not set
-# CONFIG_KGDB is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-# CONFIG_CRC32 is not set
-# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/dreamcast_defconfig b/arch/sh/configs/dreamcast_defconfig
index 776c1909bee3..8b6b5a779de8 100644
--- a/arch/sh/configs/dreamcast_defconfig
+++ b/arch/sh/configs/dreamcast_defconfig
@@ -1,50 +1,63 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:40 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 10:51:55 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -52,82 +65,158 @@ CONFIG_CC_ALIGN_JUMPS=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
CONFIG_SH_DREAMCAST=y
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
CONFIG_CPU_SUBTYPE_SH7750=y
+CONFIG_CPU_SUBTYPE_SH7091=y
+CONFIG_CPU_SUBTYPE_SH7750R=y
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-CONFIG_HUGETLB_PAGE_SIZE_64K=y
-# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_PREEMPT=y
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_VSYSCALL=y
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
-CONFIG_SH_OCRAM=y
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
CONFIG_SH_STORE_QUEUES=y
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
CONFIG_SH_PCLK_FREQ=49876504
#
# CPU Frequency scaling
#
CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
# CONFIG_CPU_FREQ_DEBUG is not set
CONFIG_CPU_FREQ_STAT=y
# CONFIG_CPU_FREQ_STAT_DETAILS is not set
@@ -137,8 +226,8 @@ CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
CONFIG_CPU_FREQ_GOV_POWERSAVE=y
CONFIG_CPU_FREQ_GOV_USERSPACE=y
# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-CONFIG_CPU_FREQ_TABLE=y
-CONFIG_SH_CPU_FREQ=y
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+# CONFIG_SH_CPU_FREQ is not set
#
# DMA support
@@ -154,14 +243,35 @@ CONFIG_NR_DMA_CHANNELS=9
# CONFIG_HD6446X_SERIES is not set
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,115200 panic=3"
+
+#
+# Bus options
#
-CONFIG_MAPLE=y
CONFIG_PCI=y
# CONFIG_SH_PCIDMA_NONCOHERENT is not set
CONFIG_PCI_AUTO=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -169,10 +279,6 @@ CONFIG_PCI_NAMES=y
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# PCI Hotplug Support
#
# CONFIG_HOTPLUG_PCI is not set
@@ -185,9 +291,92 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
#
-# CONFIG_EMBEDDED_RAMDISK is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -199,6 +388,12 @@ CONFIG_BINFMT_ELF=y
# CONFIG_STANDALONE is not set
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -217,7 +412,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -226,21 +420,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_SX8 is not set
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=1024
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -251,7 +433,14 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -261,6 +450,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -273,70 +463,8 @@ CONFIG_IOSCHED_CFQ=y
# CONFIG_I2O is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
+# Network device support
#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -349,6 +477,11 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -356,6 +489,7 @@ CONFIG_MII=y
# CONFIG_STNIC is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
@@ -398,15 +532,22 @@ CONFIG_8139TOO=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -428,6 +569,8 @@ CONFIG_8139TOO=y
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -443,6 +586,7 @@ CONFIG_8139TOO=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -457,19 +601,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
@@ -478,22 +609,33 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
-# CONFIG_KEYBOARD_MAPLE is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_MAPLE is not set
# CONFIG_MOUSE_VSXXXAA is not set
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -505,9 +647,11 @@ CONFIG_HW_CONSOLE=y
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -528,13 +672,14 @@ CONFIG_WATCHDOG=y
#
# CONFIG_SOFT_WATCHDOG is not set
CONFIG_SH_WDT=y
+# CONFIG_SH_WDT_MMAP is not set
#
# PCI-based Watchdog Cards
#
# CONFIG_PCIPCWATCHDOG is not set
# CONFIG_WDTPCI is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -547,14 +692,35 @@ CONFIG_SH_WDT=y
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -564,6 +730,7 @@ CONFIG_SH_WDT=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -573,7 +740,13 @@ CONFIG_SH_WDT=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
# CONFIG_FB_CIRRUS is not set
@@ -583,9 +756,10 @@ CONFIG_FB=y
# CONFIG_FB_IMSTT is not set
CONFIG_FB_PVR2=y
# CONFIG_FB_EPSON1355 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON_OLD is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
@@ -601,18 +775,20 @@ CONFIG_FB_PVR2=y
#
# Console display driver support
#
-# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
#
# Logo configuration
@@ -634,12 +810,13 @@ CONFIG_LOGO_SUPERH_CLUT224=y
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -653,29 +830,64 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
# CONFIG_INFINIBAND is not set
#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# File systems
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
-CONFIG_ROMFS_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
+# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -695,16 +907,14 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -716,7 +926,7 @@ CONFIG_RAMFS=y
# CONFIG_BEFS_FS is not set
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
-CONFIG_CRAMFS=y
+# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
# CONFIG_QNX4FS_FS is not set
@@ -726,22 +936,14 @@ CONFIG_CRAMFS=y
#
# Network File Systems
#
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFS_FS is not set
# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
-CONFIG_LOCKD=y
-CONFIG_LOCKD_V4=y
-CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -758,14 +960,19 @@ CONFIG_MSDOS_PARTITION=y
# Profiling support
#
CONFIG_PROFILING=y
-CONFIG_OPROFILE=y
+# CONFIG_OPROFILE is not set
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_KGDB is not set
@@ -782,13 +989,10 @@ CONFIG_DEBUG_PREEMPT=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/hp6xx_defconfig b/arch/sh/configs/hp6xx_defconfig
index b36f102cec81..b931d9b2d579 100644
--- a/arch/sh/configs/hp6xx_defconfig
+++ b/arch/sh/configs/hp6xx_defconfig
@@ -1,21 +1,21 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-sh
-# Wed Jan 4 15:32:56 2006
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:10:06 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
@@ -27,26 +27,31 @@ CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-CONFIG_HOTPLUG=y
+# CONFIG_UTS_NS is not set
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
+CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -56,7 +61,10 @@ CONFIG_BASE_SMALL=0
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
#
# IO Schedulers
@@ -77,29 +85,26 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
CONFIG_SH_HP6XX=y
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
# CONFIG_SH_LANDISK is not set
# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
#
@@ -117,9 +122,11 @@ CONFIG_CPU_SH3=y
#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
CONFIG_CPU_SUBTYPE_SH7709=y
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
#
# SH-4 Processor Support
@@ -142,14 +149,23 @@ CONFIG_CPU_SUBTYPE_SH7709=y
#
# SH-4A Processor Support
#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
# Memory management options
#
CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x00400000
+CONFIG_VSYSCALL=y
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -158,6 +174,7 @@ CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
#
# Cache configuration
@@ -165,22 +182,22 @@ CONFIG_SPLIT_PTLOCK_CPUS=4
# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
-CONFIG_MEMORY_START=0x0c000000
-CONFIG_MEMORY_SIZE=0x00400000
#
# Processor features
#
CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SH_RTC=y
+# CONFIG_SH_FPU_EMU is not set
# CONFIG_SH_DSP is not set
CONFIG_SH_ADC=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_PINT_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
#
# Timer support
#
CONFIG_SH_TMU=y
-CONFIG_SH_PCLK_FREQ_BOOL=y
CONFIG_SH_PCLK_FREQ=22110000
#
@@ -194,7 +211,6 @@ CONFIG_SH_PCLK_FREQ=22110000
CONFIG_SH_DMA=y
CONFIG_NR_ONCHIP_DMA_CHANNELS=4
# CONFIG_NR_DMA_CHANNELS_BOOL is not set
-# CONFIG_DMA_PAGE_OPS is not set
#
# Companion Chips
@@ -209,9 +225,15 @@ CONFIG_HD64461_ENABLER=y
#
# Kernel features
#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
# CONFIG_KEXEC is not set
-# CONFIG_PREEMPT is not set
# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
#
# Boot options
@@ -241,8 +263,6 @@ CONFIG_PCMCIA_IOCTL=y
#
# CONFIG_I82365 is not set
# CONFIG_TCIC is not set
-CONFIG_HD64461_PCMCIA=y
-CONFIG_HD64461_PCMCIA_SOCKETS=1
CONFIG_PCMCIA_PROBE=y
#
@@ -257,6 +277,15 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
+# Power management options (EXPERIMENTAL)
+#
+CONFIG_PM=y
+CONFIG_PM_LEGACY=y
+# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
+CONFIG_APM=y
+
+#
# Networking
#
# CONFIG_NET is not set
@@ -271,6 +300,7 @@ CONFIG_BINFMT_ELF=y
# CONFIG_STANDALONE is not set
CONFIG_PREVENT_FIRMWARE_BUILD=y
CONFIG_FW_LOADER=y
+# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
@@ -299,6 +329,7 @@ CONFIG_FW_LOADER=y
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
@@ -315,7 +346,7 @@ CONFIG_BLK_DEV_IDE=y
# CONFIG_BLK_DEV_IDE_SATA is not set
CONFIG_BLK_DEV_IDEDISK=y
# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECS=y
# CONFIG_BLK_DEV_IDECD is not set
# CONFIG_BLK_DEV_IDETAPE is not set
# CONFIG_BLK_DEV_IDEFLOPPY is not set
@@ -325,7 +356,6 @@ CONFIG_BLK_DEV_IDEDISK=y
# IDE chipset support/bugfixes
#
CONFIG_IDE_GENERIC=y
-CONFIG_IDE_SH=y
# CONFIG_IDE_ARM is not set
# CONFIG_IDE_CHIPSETS is not set
# CONFIG_BLK_DEV_IDEDMA is not set
@@ -337,6 +367,12 @@ CONFIG_IDE_SH=y
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Old CD-ROM drivers (not SCSI, not IDE)
@@ -356,19 +392,12 @@ CONFIG_IDE_SH=y
#
# IEEE 1394 (FireWire) support
#
-# CONFIG_IEEE1394 is not set
#
# I2O device support
#
#
-# Network device support
-#
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
# ISDN subsystem
#
@@ -381,6 +410,7 @@ CONFIG_IDE_SH=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -390,17 +420,33 @@ CONFIG_INPUT_MOUSEDEV_PSAUX=y
CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
# CONFIG_INPUT_EVDEV is not set
# CONFIG_INPUT_EVBUG is not set
#
# Input Device Drivers
#
-# CONFIG_INPUT_KEYBOARD is not set
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
# CONFIG_INPUT_MOUSE is not set
# CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_INPUT_TOUCHSCREEN is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+CONFIG_TOUCHSCREEN_HP600=y
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
# CONFIG_INPUT_MISC is not set
#
@@ -409,6 +455,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
@@ -418,6 +465,7 @@ CONFIG_SERIO=y
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -442,7 +490,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -471,15 +519,23 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
#
# Hardware Monitoring support
#
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -487,13 +543,10 @@ CONFIG_HWMON=y
#
#
-# Multimedia Capabilities Port drivers
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -502,11 +555,13 @@ CONFIG_HWMON=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
# CONFIG_FB_EPSON1355 is not set
@@ -553,7 +608,7 @@ CONFIG_SOUND=y
# Open Sound System
#
CONFIG_SOUND_PRIME=y
-# CONFIG_OBSOLETE_OSS_DRIVER is not set
+# CONFIG_OSS_OBSOLETE_DRIVER is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
CONFIG_SOUND_SH_DAC_AUDIO=y
@@ -564,6 +619,7 @@ CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -580,12 +636,42 @@ CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL=1
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
-# CONFIG_INFINIBAND is not set
#
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
#
#
@@ -595,7 +681,6 @@ CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
# CONFIG_FS_POSIX_ACL is not set
@@ -603,6 +688,7 @@ CONFIG_EXT2_FS=y
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
@@ -630,12 +716,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
# CONFIG_TMPFS is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -713,9 +800,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_FRAME_POINTER is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_KGDB is not set
@@ -731,13 +823,10 @@ CONFIG_LOG_BUF_SHIFT=14
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
diff --git a/arch/mips/configs/ev96100_defconfig b/arch/sh/configs/hs7751rvoip_defconfig
index 0bdc10f11610..e1a886d621db 100644
--- a/arch/mips/configs/ev96100_defconfig
+++ b/arch/sh/configs/hs7751rvoip_defconfig
@@ -1,158 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:05 2006
-#
-CONFIG_MIPS=y
-
-#
-# Machine selection
-#
-# CONFIG_MIPS_MTX1 is not set
-# CONFIG_MIPS_BOSPORUS is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1100 is not set
-# CONFIG_MIPS_PB1500 is not set
-# CONFIG_MIPS_PB1550 is not set
-# CONFIG_MIPS_PB1200 is not set
-# CONFIG_MIPS_DB1000 is not set
-# CONFIG_MIPS_DB1100 is not set
-# CONFIG_MIPS_DB1500 is not set
-# CONFIG_MIPS_DB1550 is not set
-# CONFIG_MIPS_DB1200 is not set
-# CONFIG_MIPS_MIRAGE is not set
-# CONFIG_BASLER_EXCITE is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_MACH_DECSTATION is not set
-# CONFIG_MIPS_EV64120 is not set
-CONFIG_MIPS_EV96100=y
-# CONFIG_MIPS_IVR is not set
-# CONFIG_MIPS_ITE8172 is not set
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_LASAT is not set
-# CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_SEAD is not set
-# CONFIG_WR_PPMC is not set
-# CONFIG_MIPS_SIM is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_3 is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MIPS_XXS1500 is not set
-# CONFIG_PNX8550_V2PCI is not set
-# CONFIG_PNX8550_JBS is not set
-# CONFIG_DDB5477 is not set
-# CONFIG_MACH_VR41XX is not set
-# CONFIG_PMC_YOSEMITE is not set
-# CONFIG_QEMU is not set
-# CONFIG_MARKEINS is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_BIGSUR is not set
-# CONFIG_SIBYTE_SWARM is not set
-# CONFIG_SIBYTE_SENTOSA is not set
-# CONFIG_SIBYTE_RHONE is not set
-# CONFIG_SIBYTE_CARMEL is not set
-# CONFIG_SIBYTE_PTSWARM is not set
-# CONFIG_SIBYTE_LITTLESUR is not set
-# CONFIG_SIBYTE_CRHINE is not set
-# CONFIG_SIBYTE_CRHONE is not set
-# CONFIG_SNI_RM200_PCI is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
-# CONFIG_TOSHIBA_RBTX4938 is not set
+# Linux kernel version: 2.6.18
+# Tue Oct 3 13:04:52 2006
+#
+CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-CONFIG_CPU_BIG_ENDIAN=y
-# CONFIG_CPU_LITTLE_ENDIAN is not set
-CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
-CONFIG_IRQ_CPU=y
-CONFIG_MIPS_GT64120=y
-CONFIG_SWAP_IO_SPACE=y
-CONFIG_MIPS_GT96100=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-
-#
-# CPU selection
-#
-# CONFIG_CPU_MIPS32_R1 is not set
-# CONFIG_CPU_MIPS32_R2 is not set
-# CONFIG_CPU_MIPS64_R1 is not set
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_VR41XX is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R6000 is not set
-# CONFIG_CPU_NEVADA is not set
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
-CONFIG_CPU_RM7000=y
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_R5000=y
-CONFIG_SYS_HAS_CPU_RM7000=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
-
-#
-# Kernel type
-#
-CONFIG_32BIT=y
-# CONFIG_64BIT is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_BOARD_SCACHE=y
-CONFIG_RM7000_CPU_SCACHE=y
-CONFIG_CPU_HAS_PREFETCH=y
-CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMTC is not set
-# CONFIG_MIPS_MT_SMP is not set
-# CONFIG_MIPS_VPE_LOADER is not set
-# CONFIG_64BIT_PHYS_ADDR is not set
-CONFIG_CPU_HAS_LLSC=y
-CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_CPU_SUPPORTS_HIGHMEM=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-# CONFIG_HZ_48 is not set
-# CONFIG_HZ_100 is not set
-# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_256 is not set
-CONFIG_HZ_1000=y
-# CONFIG_HZ_1024 is not set
-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=1000
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -160,6 +17,7 @@ CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
#
@@ -169,28 +27,33 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
-CONFIG_RELAY=y
+# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_HOTPLUG is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -201,13 +64,14 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_KMOD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -226,11 +90,172 @@ CONFIG_DEFAULT_AS=y
CONFIG_DEFAULT_IOSCHED="anticipatory"
#
-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+CONFIG_SH_HS7751RVOIP=y
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+CONFIG_CPU_SUBTYPE_SH7751R=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
#
-CONFIG_HW_HAS_PCI=y
-# CONFIG_PCI is not set
CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+
+#
+# HS7751RVoIP options
+#
+CONFIG_HS7751RVOIP_CODEC=y
+CONFIG_SH_PCLK_FREQ=60000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="mem=64M console=ttySC1,115200 root=/dev/hda1"
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -245,8 +270,13 @@ CONFIG_MMU=y
# Executable file formats
#
CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
#
# Networking
@@ -257,21 +287,26 @@ CONFIG_NET=y
# Networking options
#
# CONFIG_NETDEBUG is not set
-# CONFIG_PACKET is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-CONFIG_NET_KEY=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
CONFIG_IP_FIB_HASH=y
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
# CONFIG_ARPD is not set
# CONFIG_SYN_COOKIES is not set
# CONFIG_INET_AH is not set
@@ -279,16 +314,17 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
-CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -314,7 +350,6 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -330,13 +365,7 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_SOFTMAC=m
-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
-CONFIG_WIRELESS_EXT=y
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -347,13 +376,13 @@ CONFIG_WIRELESS_EXT=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=m
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
#
-CONFIG_CONNECTOR=m
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -377,21 +406,47 @@ CONFIG_CONNECTOR=m
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-CONFIG_ATA_OVER_ETH=m
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
#
-# CONFIG_IDE is not set
+CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=1
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+# CONFIG_IDE_ARM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+# CONFIG_IDEDMA_AUTO is not set
+# CONFIG_BLK_DEV_HD is not set
#
# SCSI device support
#
-CONFIG_RAID_ATTRS=m
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -423,26 +478,15 @@ CONFIG_NETDEVICES=y
#
# PHY device support
#
-CONFIG_PHYLIB=m
-
-#
-# MII PHY device drivers
-#
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
+# CONFIG_PHYLIB is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-CONFIG_MIPS_GT96100ETH=y
-# CONFIG_DM9000 is not set
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
#
# Ethernet (1000 Mbit)
@@ -486,14 +530,12 @@ CONFIG_MIPS_GT96100ETH=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
@@ -512,38 +554,33 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# Hardware I/O ports
#
CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
+CONFIG_SERIO_I8042=y
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_LIBPS2 is not set
-CONFIG_SERIO_RAW=m
+# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
#
# Character devices
#
-CONFIG_VT=y
-CONFIG_VT_CONSOLE=y
-CONFIG_HW_CONSOLE=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
CONFIG_UNIX98_PTYS=y
-CONFIG_LEGACY_PTYS=y
-CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_LEGACY_PTYS is not set
#
# IPMI
@@ -554,8 +591,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -585,13 +621,16 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
#
# Hardware Monitoring support
#
-# CONFIG_HWMON is not set
+CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -611,14 +650,9 @@ CONFIG_VIDEO_V4L2=y
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
-
-#
-# Console display driver support
-#
-# CONFIG_VGA_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -705,7 +739,7 @@ CONFIG_INOTIFY_USER=y
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=m
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -725,8 +759,11 @@ CONFIG_FUSE_FS=m
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -752,19 +789,20 @@ CONFIG_RAMFS=y
# Network File Systems
#
CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_NFS_DIRECTIO=y
# CONFIG_NFSD is not set
-CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
-# CONFIG_RPCSEC_GSS_KRB5 is not set
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -773,8 +811,23 @@ CONFIG_SUNRPC=y
#
# Partition Types
#
-# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
#
# Native Language Support
@@ -790,48 +843,55 @@ CONFIG_MSDOS_PARTITION=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_FS is not set
-CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE=""
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_KGDB is not set
#
# Security options
#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
CONFIG_CRYPTO=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_MANAGER=m
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
# CONFIG_CRYPTO_TEST is not set
#
@@ -842,9 +902,7 @@ CONFIG_CRYPTO_CRC32C=m
# Library routines
#
# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=m
-CONFIG_CRC32=m
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=m
-CONFIG_ZLIB_DEFLATE=m
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
CONFIG_PLIST=y
diff --git a/arch/sh/configs/landisk_defconfig b/arch/sh/configs/landisk_defconfig
new file mode 100644
index 000000000000..238c0f109907
--- /dev/null
+++ b/arch/sh/configs/landisk_defconfig
@@ -0,0 +1,1450 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:14:13 2006
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+CONFIG_SH_LANDISK=y
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+CONFIG_CPU_SUBTYPE_SH7751R=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=33333333
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=4
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_KEXEC=y
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+CONFIG_ISA=y
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+CONFIG_CARDBUS=y
+
+#
+# PC-card bridges
+#
+CONFIG_YENTA=y
+CONFIG_YENTA_O2=y
+CONFIG_YENTA_RICOH=y
+CONFIG_YENTA_TI=y
+CONFIG_YENTA_ENE_TUNE=y
+CONFIG_YENTA_TOSHIBA=y
+# CONFIG_PD6729 is not set
+# CONFIG_I82092 is not set
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_PROBE=y
+CONFIG_PCCARD_NONSTATIC=y
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+# CONFIG_IP_NF_NETBIOS_NS is not set
+CONFIG_IP_NF_TFTP=m
+CONFIG_IP_NF_AMANDA=m
+# CONFIG_IP_NF_PPTP is not set
+# CONFIG_IP_NF_H323 is not set
+# CONFIG_IP_NF_SIP is not set
+CONFIG_IP_NF_QUEUE=m
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+CONFIG_ATALK=m
+# CONFIG_DEV_APPLETALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# 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
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+# CONFIG_PNP is not set
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+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 is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=y
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_BLK_DEV_IDEDISK=y
+# CONFIG_IDEDISK_MULTI_MODE is not set
+# CONFIG_BLK_DEV_IDECS is not set
+CONFIG_BLK_DEV_IDECD=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_BLK_DEV_IDESCSI=y
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=y
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+CONFIG_BLK_DEV_OFFBOARD=y
+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=y
+CONFIG_BLK_DEV_AEC62XX=y
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_IDE_ARM is not set
+# CONFIG_IDE_CHIPSETS 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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AHA152X is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_PSI240I is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# PCMCIA SCSI adapter support
+#
+# CONFIG_PCMCIA_AHA152X is not set
+# CONFIG_PCMCIA_FDOMAIN is not set
+# CONFIG_PCMCIA_NINJA_SCSI is not set
+# CONFIG_PCMCIA_QLOGIC is not set
+# CONFIG_PCMCIA_SYM53C500 is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Old CD-ROM drivers (not SCSI, not IDE)
+#
+# CONFIG_CD_NO_IDESCSI is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID456 is not set
+# CONFIG_MD_MULTIPATH is not set
+# CONFIG_MD_FAULTY is not set
+# CONFIG_BLK_DEV_DM is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_NET_VENDOR_SMC is not set
+# CONFIG_SMC91X is not set
+# CONFIG_NET_VENDOR_RACAL is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_AT1700 is not set
+# CONFIG_DEPCA is not set
+# CONFIG_HP100 is not set
+# CONFIG_NET_ISA is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_AC3200 is not set
+# CONFIG_APRICOT is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_CS89x0 is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+CONFIG_8139CP=y
+# CONFIG_8139TOO is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# PCMCIA network device support
+#
+# CONFIG_NET_PCMCIA is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
+CONFIG_VIDEO_V4L2=y
+
+#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_STRADIS is not set
+
+#
+# V4L USB devices
+#
+CONFIG_VIDEO_USBVIDEO=m
+CONFIG_USB_VICAM=m
+CONFIG_USB_IBMCAM=m
+CONFIG_USB_KONICAWC=m
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+CONFIG_USB_OV511=m
+CONFIG_USB_SE401=m
+CONFIG_USB_SN9C102=m
+CONFIG_USB_STV680=m
+# CONFIG_USB_ZC0301 is not set
+CONFIG_USB_PWC=m
+# CONFIG_USB_PWC_DEBUG is not set
+
+#
+# Radio Adapters
+#
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+CONFIG_USB_DSBR=m
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+CONFIG_USB_DABUSB=m
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FONT_8x16=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_OSS_OBSOLETE_DRIVER is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DATAFAB=y
+CONFIG_USB_STORAGE_FREECOM=y
+CONFIG_USB_STORAGE_ISD200=y
+CONFIG_USB_STORAGE_DPCM=y
+# CONFIG_USB_STORAGE_USBAT is not set
+CONFIG_USB_STORAGE_SDDR09=y
+CONFIG_USB_STORAGE_SDDR55=y
+CONFIG_USB_STORAGE_JUMPSHOT=y
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+CONFIG_USB_HIDINPUT=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+CONFIG_USB_PEGASUS=m
+CONFIG_USB_RTL8150=m
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_SERIAL_GENERIC is not set
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+CONFIG_USB_SERIAL_FTDI_SIO=m
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+CONFIG_USB_EMI62=m
+CONFIG_USB_EMI26=m
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+CONFIG_USB_SISUSBVGA=m
+CONFIG_USB_SISUSBVGA_CON=y
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_UFS_DEBUG is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+# CONFIG_NLS_ISO8859_1 is not set
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_SH_STANDARD_BIOS=y
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/microdev_defconfig b/arch/sh/configs/microdev_defconfig
index ab3db76d1e51..e89d951c3c16 100644
--- a/arch/sh/configs/microdev_defconfig
+++ b/arch/sh/configs/microdev_defconfig
@@ -1,19 +1,21 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc1
-# Fri Jan 27 19:43:20 2006
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:27:01 2006
#
CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
CONFIG_INIT_ENV_ARG_LIMIT=32
@@ -28,13 +30,17 @@ CONFIG_SWAP=y
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-CONFIG_UID16=y
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
CONFIG_HOTPLUG=y
@@ -45,11 +51,9 @@ CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -62,7 +66,10 @@ CONFIG_BASE_SMALL=0
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
#
# IO Schedulers
@@ -83,30 +90,26 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
# CONFIG_SH_HP6XX is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
CONFIG_SH_SH4202_MICRODEV=y
# CONFIG_SH_LANDISK is not set
# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
#
@@ -124,9 +127,11 @@ CONFIG_CPU_SH4=y
#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
#
# SH-4 Processor Support
@@ -149,14 +154,25 @@ CONFIG_CPU_SUBTYPE_SH4_202=y
#
# SH-4A Processor Support
#
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
# CONFIG_CPU_SUBTYPE_SH7770 is not set
# CONFIG_CPU_SUBTYPE_SH7780 is not set
#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
# Memory management options
#
CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x04000000
+CONFIG_VSYSCALL=y
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
CONFIG_SELECT_MEMORY_MODEL=y
CONFIG_FLATMEM_MANUAL=y
# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -165,22 +181,21 @@ CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
#
# Cache configuration
#
# CONFIG_SH_DIRECT_MAPPED is not set
-# CONFIG_SH_WRITETHROUGH is not set
+CONFIG_SH_WRITETHROUGH=y
# CONFIG_SH_OCRAM is not set
-CONFIG_MEMORY_START=0x08000000
-CONFIG_MEMORY_SIZE=0x04000000
#
# Processor features
#
CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SH_RTC=y
CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
CONFIG_CPU_HAS_INTEVT=y
CONFIG_CPU_HAS_SR_RB=y
@@ -212,9 +227,16 @@ CONFIG_HEARTBEAT=y
#
# Kernel features
#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
# CONFIG_KEXEC is not set
-CONFIG_PREEMPT=y
# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
#
# Boot options
@@ -223,12 +245,12 @@ CONFIG_ZERO_PAGE_OFFSET=0x00001000
CONFIG_BOOT_LINK_OFFSET=0x00800000
# CONFIG_UBC_WAKEUP is not set
CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC0,115200"
+CONFIG_CMDLINE="console=ttySC0,115200 root=/dev/hda1"
#
# Bus options
#
-# CONFIG_SUPERHYWAY is not set
+CONFIG_SUPERHYWAY=y
# CONFIG_PCI is not set
#
@@ -248,6 +270,11 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
# Networking
#
CONFIG_NET=y
@@ -255,15 +282,19 @@ CONFIG_NET=y
#
# Networking options
#
+# CONFIG_NETDEBUG is not set
# CONFIG_PACKET is not set
# CONFIG_UNIX is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_DHCP is not set
# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
@@ -273,12 +304,19 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_AH is not set
# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -304,7 +342,6 @@ CONFIG_TCP_CONG_BIC=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -332,6 +369,7 @@ CONFIG_TCP_CONG_BIC=y
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
@@ -361,6 +399,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
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
# CONFIG_ATA_OVER_ETH is not set
@@ -397,6 +436,12 @@ CONFIG_IDE_GENERIC=y
#
# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -502,6 +547,7 @@ CONFIG_SMC91X=y
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
@@ -518,7 +564,8 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-CONFIG_RTC=y
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -547,13 +594,15 @@ CONFIG_RTC=y
#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
#
# Hardware Monitoring support
#
CONFIG_HWMON=y
# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_HWMON_DEBUG_CHIP is not set
#
@@ -561,13 +610,10 @@ CONFIG_HWMON=y
#
#
-# Multimedia Capabilities Port drivers
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -577,7 +623,9 @@ CONFIG_HWMON=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -589,6 +637,7 @@ CONFIG_HWMON=y
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
@@ -605,15 +654,42 @@ CONFIG_HWMON=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
#
-# SN Devices
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
#
#
-# EDAC - error detection and reporting (RAS)
+# DMA Devices
#
#
@@ -637,6 +713,7 @@ CONFIG_FS_MBCACHE=y
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
@@ -664,12 +741,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
-# CONFIG_HUGETLBFS is not set
-# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
-# CONFIG_RELAYFS_FS is not set
# CONFIG_CONFIGFS_FS is not set
#
@@ -772,10 +850,14 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_FRAME_POINTER is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_KGDB is not set
@@ -790,6 +872,9 @@ CONFIG_LOG_BUF_SHIFT=14
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_MANAGER=y
# CONFIG_CRYPTO_HMAC is not set
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -799,6 +884,8 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=y
+CONFIG_CRYPTO_CBC=y
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
@@ -813,7 +900,6 @@ CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_DEFLATE is not set
# CONFIG_CRYPTO_MICHAEL_MIC is not set
# CONFIG_CRYPTO_CRC32C is not set
-# CONFIG_CRYPTO_TEST is not set
#
# Hardware crypto devices
@@ -826,3 +912,4 @@ CONFIG_CRYPTO_DES=y
# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/r7780rp_defconfig b/arch/sh/configs/r7780rp_defconfig
new file mode 100644
index 000000000000..2470364948e7
--- /dev/null
+++ b/arch/sh/configs/r7780rp_defconfig
@@ -0,0 +1,1221 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:32:47 2006
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+CONFIG_SH_R7780RP=y
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+CONFIG_CPU_SUBTYPE_SH7780=y
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08000000
+CONFIG_MEMORY_SIZE=0x08000000
+CONFIG_32BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_HUGETLB_PAGE_SIZE_64K=y
+# CONFIG_HUGETLB_PAGE_SIZE_1MB is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+CONFIG_SH_STORE_QUEUES=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_INTC2_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+
+#
+# R7780RP options
+#
+CONFIG_SH_R7780MP=y
+CONFIG_SH_PCLK_FREQ=32000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=6
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="mem=128M console=ttySC0,115200 root=/dev/hda1"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=m
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+CONFIG_LLC=m
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_WIRELESS_EXT=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER 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
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+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 is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+CONFIG_IDE=m
+CONFIG_IDE_MAX_HWIFS=4
+CONFIG_BLK_DEV_IDE=m
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
+CONFIG_BLK_DEV_IDE_SATA=y
+CONFIG_BLK_DEV_IDEDISK=m
+CONFIG_IDEDISK_MULTI_MODE=y
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEFLOPPY is not set
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_IDE_TASK_IOCTL is not set
+
+#
+# IDE chipset support/bugfixes
+#
+CONFIG_IDE_GENERIC=m
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_SHARE_IRQ=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=m
+# 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=m
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+# CONFIG_BLK_DEV_CMD64X is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CY82C693 is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT34X is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX 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
+CONFIG_BLK_DEV_PDC202XX_NEW=m
+# CONFIG_BLK_DEV_SVWKS is not set
+CONFIG_BLK_DEV_SIIMAGE=m
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# 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
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+CONFIG_PCNET32=m
+# CONFIG_PCNET32_NAPI is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+CONFIG_8139CP=m
+CONFIG_8139TOO=m
+# CONFIG_8139TOO_PIO is not set
+# CONFIG_8139TOO_TUNE_TWISTER is not set
+CONFIG_8139TOO_8129=y
+# CONFIG_8139_OLD_RX_RESET is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+CONFIG_VIA_RHINE=m
+CONFIG_VIA_RHINE_MMIO=y
+# CONFIG_VIA_RHINE_NAPI is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=m
+# CONFIG_E1000_NAPI is not set
+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+CONFIG_R8169=y
+# CONFIG_R8169_NAPI is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_NORTEL_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+# CONFIG_HOSTAP is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+CONFIG_SOUND=m
+
+#
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_OSS_OBSOLETE_DRIVER is not set
+# CONFIG_SOUND_BT878 is not set
+# CONFIG_SOUND_ES1371 is not set
+# CONFIG_SOUND_ICH is not set
+# CONFIG_SOUND_TRIDENT is not set
+# CONFIG_SOUND_MSNDCLAS is not set
+# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_VIA82CXXX is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+CONFIG_MINIX_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=y
+# CONFIG_NTFS_DEBUG is not set
+CONFIG_NTFS_RW=y
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+# CONFIG_TMPFS is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+CONFIG_RPCSEC_GSS_KRB5=y
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+CONFIG_NLS_CODEPAGE_932=y
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SPINLOCK=y
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_HMAC=y
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/rts7751r2d_defconfig b/arch/sh/configs/rts7751r2d_defconfig
index e43cf57326bd..099e98f14729 100644
--- a/arch/sh/configs/rts7751r2d_defconfig
+++ b/arch/sh/configs/rts7751r2d_defconfig
@@ -1,125 +1,215 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:42 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:38:36 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
CONFIG_SH_RTS7751R2D=y
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
CONFIG_CPU_SUBTYPE_SH7751=y
+CONFIG_CPU_SUBTYPE_SH7751R=y
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1"
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00010000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+
+#
+# RTS7751R2D options
+#
CONFIG_RTS7751R2D_REV11=y
-CONFIG_SH_PCLK_CALC=y
CONFIG_SH_PCLK_FREQ=60000000
#
@@ -140,17 +230,37 @@ CONFIG_NR_ONCHIP_DMA_CHANNELS=8
CONFIG_VOYAGERGX=y
# CONFIG_HD6446X_SERIES is not set
CONFIG_HEARTBEAT=y
-CONFIG_RTC_9701JE=y
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="mem=64M console=ttySC0,115200 root=/dev/hda1"
+
+#
+# Bus options
#
CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -158,10 +268,6 @@ CONFIG_PCI_NAMES=y
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# PCI Hotplug Support
#
CONFIG_HOTPLUG_PCI=y
@@ -177,6 +283,95 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+CONFIG_WIRELESS_EXT=y
+
+#
# Device Drivers
#
@@ -186,6 +381,12 @@ CONFIG_BINFMT_ELF=y
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -204,7 +405,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -216,18 +416,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
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 is not set
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -253,7 +444,6 @@ CONFIG_BLK_DEV_IDEDISK=y
#
CONFIG_IDE_GENERIC=y
# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_IDE_SH=y
# CONFIG_IDE_ARM is not set
# CONFIG_BLK_DEV_IDEDMA is not set
# CONFIG_IDEDMA_AUTO is not set
@@ -262,7 +452,14 @@ CONFIG_IDE_SH=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -272,6 +469,7 @@ CONFIG_IDE_SH=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -284,67 +482,8 @@ CONFIG_IDE_SH=y
# CONFIG_I2O is not set
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-# CONFIG_IP_PNP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -357,6 +496,11 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -364,6 +508,7 @@ CONFIG_MII=y
# CONFIG_STNIC is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
@@ -406,15 +551,22 @@ CONFIG_8139TOO=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -425,6 +577,7 @@ CONFIG_8139TOO=y
# Wireless LAN (non-hamradio)
#
CONFIG_NET_RADIO=y
+# CONFIG_NET_WIRELESS_RTNETLINK is not set
#
# Obsolete Wireless cards support (pre-802.11)
@@ -434,9 +587,12 @@ CONFIG_NET_RADIO=y
#
# Wireless 802.11b ISA/PCI cards support
#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
CONFIG_HERMES=m
# CONFIG_PLX_HERMES is not set
# CONFIG_TMD_HERMES is not set
+# CONFIG_NORTEL_HERMES is not set
# CONFIG_PCI_HERMES is not set
# CONFIG_ATMEL is not set
@@ -444,6 +600,7 @@ CONFIG_HERMES=m
# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
#
# CONFIG_PRISM54 is not set
+# CONFIG_HOSTAP is not set
CONFIG_NET_WIRELESS=y
#
@@ -456,6 +613,8 @@ CONFIG_NET_WIRELESS=y
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -473,20 +632,10 @@ CONFIG_NET_WIRELESS=y
# CONFIG_INPUT is not set
#
-# Userland interfaces
-#
-
+# Hardware I/O ports
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
+# CONFIG_GAMEPORT is not set
#
# Character devices
@@ -503,6 +652,7 @@ CONFIG_SOUND_GAMEPORT=y
# Non-8250 serial port support
#
# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_SERIAL_JSM is not set
# CONFIG_UNIX98_PTYS is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -516,7 +666,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -529,14 +679,35 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -546,6 +717,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -555,7 +727,9 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -573,6 +747,9 @@ CONFIG_SND_RAWMIDI=m
# CONFIG_SND_SEQUENCER is not set
# CONFIG_SND_MIXER_OSS is not set
# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
# CONFIG_SND_VERBOSE_PRINTK is not set
# CONFIG_SND_DEBUG is not set
@@ -581,6 +758,8 @@ CONFIG_SND_RAWMIDI=m
#
CONFIG_SND_MPU401_UART=m
CONFIG_SND_OPL3_LIB=m
+CONFIG_SND_AC97_CODEC=m
+CONFIG_SND_AC97_BUS=m
# CONFIG_SND_DUMMY is not set
# CONFIG_SND_MTPAV is not set
# CONFIG_SND_SERIAL_U16550 is not set
@@ -589,7 +768,8 @@ CONFIG_SND_OPL3_LIB=m
#
# PCI devices
#
-CONFIG_SND_AC97_CODEC=m
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALS300 is not set
# CONFIG_SND_ALI5451 is not set
# CONFIG_SND_ATIIXP is not set
# CONFIG_SND_ATIIXP_MODEM is not set
@@ -598,73 +778,63 @@ CONFIG_SND_AC97_CODEC=m
# CONFIG_SND_AU8830 is not set
# CONFIG_SND_AZT3328 is not set
# CONFIG_SND_BT87X is not set
-# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
# CONFIG_SND_EMU10K1 is not set
# CONFIG_SND_EMU10K1X is not set
-# CONFIG_SND_CA0106 is not set
-# CONFIG_SND_KORG1212 is not set
-# CONFIG_SND_MIXART is not set
-# CONFIG_SND_NM256 is not set
-# CONFIG_SND_RME32 is not set
-# CONFIG_SND_RME96 is not set
-# CONFIG_SND_RME9652 is not set
-# CONFIG_SND_HDSP is not set
-# CONFIG_SND_TRIDENT is not set
-CONFIG_SND_YMFPCI=m
-# CONFIG_SND_ALS4000 is not set
-# CONFIG_SND_CMIPCI is not set
# CONFIG_SND_ENS1370 is not set
# CONFIG_SND_ENS1371 is not set
# CONFIG_SND_ES1938 is not set
# CONFIG_SND_ES1968 is not set
-# CONFIG_SND_MAESTRO3 is not set
# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
# CONFIG_SND_ICE1712 is not set
# CONFIG_SND_ICE1724 is not set
# CONFIG_SND_INTEL8X0 is not set
# CONFIG_SND_INTEL8X0M is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
# CONFIG_SND_VIA82XX is not set
# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VX222 is not set
+CONFIG_SND_YMFPCI=m
+# CONFIG_SND_AC97_POWER_SAVE is not set
#
# Open Sound System
#
CONFIG_SOUND_PRIME=m
+# CONFIG_OSS_OBSOLETE_DRIVER is not set
# CONFIG_SOUND_BT878 is not set
-CONFIG_SOUND_CMPCI=m
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_SOUND_FUSION is not set
-# CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ES1370 is not set
# CONFIG_SOUND_ES1371 is not set
-# CONFIG_SOUND_ESSSOLO1 is not set
-# CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_MAESTRO3 is not set
# CONFIG_SOUND_ICH is not set
-# CONFIG_SOUND_SONICVIBES is not set
# CONFIG_SOUND_TRIDENT is not set
# CONFIG_SOUND_MSNDCLAS is not set
# CONFIG_SOUND_MSNDPIN is not set
# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_ALI5455 is not set
-# CONFIG_SOUND_FORTE is not set
-# CONFIG_SOUND_RME96XX is not set
-# CONFIG_SOUND_AD1980 is not set
-CONFIG_SOUND_VOYAGERGX=m
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -678,30 +848,66 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
# CONFIG_INFINIBAND is not set
#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
CONFIG_MINIX_FS=y
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -724,12 +930,13 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_TMPFS is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -758,6 +965,7 @@ CONFIG_RAMFS=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -818,8 +1026,14 @@ CONFIG_OPROFILE=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_KGDB is not set
@@ -836,12 +1050,10 @@ CONFIG_OPROFILE=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/se7300_defconfig b/arch/sh/configs/se7300_defconfig
index 4b71cd692fa5..8a217908b81f 100644
--- a/arch/sh/configs/se7300_defconfig
+++ b/arch/sh/configs/se7300_defconfig
@@ -1,45 +1,55 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:43 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:43:22 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
# CONFIG_SWAP is not set
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
+# CONFIG_UTS_NS is not set
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -47,68 +57,145 @@ CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_MODULES is not set
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
# System type
#
+CONFIG_SOLUTION_ENGINE=y
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
CONFIG_SH_7300_SOLUTION_ENGINE=y
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
CONFIG_CPU_SUBTYPE_SH7300=y
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram0"
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_DSP=y
-# CONFIG_SH_ADC is not set
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00210000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
-# CONFIG_SMP is not set
-# CONFIG_SH_PCLK_CALC is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+# CONFIG_SH_ADC is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
CONFIG_SH_PCLK_FREQ=33333333
#
@@ -128,17 +215,34 @@ CONFIG_SH_PCLK_FREQ=33333333
CONFIG_HEARTBEAT=y
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
#
-# CONFIG_PCI is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
#
-# PCCARD (PCMCIA/CardBus) support
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00210000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram0"
+
+#
+# Bus options
#
-# CONFIG_PCCARD is not set
+# CONFIG_PCI is not set
#
-# PC-card bridges
+# PCCARD (PCMCIA/CardBus) support
#
#
@@ -153,10 +257,14 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
#
-CONFIG_EMBEDDED_RAMDISK=y
-CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.gz"
+# CONFIG_NET is not set
#
# Device Drivers
@@ -167,7 +275,11 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.gz"
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
#
# Memory Technology Devices (MTD)
@@ -186,26 +298,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
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_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-
-#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -213,7 +315,14 @@ CONFIG_IOSCHED_NOOP=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -223,6 +332,7 @@ CONFIG_IOSCHED_NOOP=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -233,13 +343,6 @@ CONFIG_IOSCHED_NOOP=y
#
#
-# Networking support
-#
-# CONFIG_NET is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
# ISDN subsystem
#
@@ -252,6 +355,7 @@ CONFIG_IOSCHED_NOOP=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -266,18 +370,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -287,6 +379,16 @@ CONFIG_SERIO=y
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -301,6 +403,7 @@ CONFIG_SERIO=y
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
@@ -328,7 +431,7 @@ CONFIG_WATCHDOG=y
#
CONFIG_SOFT_WATCHDOG=y
# CONFIG_SH_WDT is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -336,18 +439,38 @@ CONFIG_SOFT_WATCHDOG=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -357,6 +480,7 @@ CONFIG_SOFT_WATCHDOG=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -365,7 +489,9 @@ CONFIG_SOFT_WATCHDOG=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -377,9 +503,10 @@ CONFIG_SOFT_WATCHDOG=y
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -393,30 +520,64 @@ CONFIG_SOFT_WATCHDOG=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
-# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -436,14 +597,13 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
# CONFIG_TMPFS is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -481,8 +641,16 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
CONFIG_SH_STANDARD_BIOS=y
CONFIG_EARLY_PRINTK=y
CONFIG_KGDB=y
@@ -520,12 +688,9 @@ CONFIG_KGDB_DEFBITS_8=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
diff --git a/arch/sh/configs/se73180_defconfig b/arch/sh/configs/se73180_defconfig
index d217e44c89a6..1a766153cbb0 100644
--- a/arch/sh/configs/se73180_defconfig
+++ b/arch/sh/configs/se73180_defconfig
@@ -1,119 +1,208 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:44 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:44:45 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
+# CONFIG_UTS_NS is not set
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
# CONFIG_FUTEX is not set
# CONFIG_EPOLL is not set
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
# System type
#
+CONFIG_SOLUTION_ENGINE=y
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
CONFIG_SH_73180_SOLUTION_ENGINE=y
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SH4AL_DSP=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-CONFIG_CPU_SUBTYPE_SH73180=y
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+CONFIG_CPU_SUBTYPE_SH73180=y
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram"
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x02000000
-# CONFIG_MEMORY_OVERRIDE is not set
-# CONFIG_SH_FPU is not set
-CONFIG_ZERO_PAGE_OFFSET=0x00010000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_32BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_SH_FPU is not set
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-# CONFIG_SH_PCLK_CALC is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
CONFIG_SH_PCLK_FREQ=27000000
#
@@ -133,17 +222,34 @@ CONFIG_SH_PCLK_FREQ=27000000
CONFIG_HEARTBEAT=y
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
#
-# CONFIG_PCI is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
#
-# PCCARD (PCMCIA/CardBus) support
+# Boot options
#
-# CONFIG_PCCARD is not set
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC0,38400 root=/dev/ram"
#
-# PC-card bridges
+# Bus options
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
#
#
@@ -158,10 +264,14 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
#
-CONFIG_EMBEDDED_RAMDISK=y
-CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.gz"
+# CONFIG_NET is not set
#
# Device Drivers
@@ -172,7 +282,11 @@ CONFIG_EMBEDDED_RAMDISK_IMAGE="ramdisk.gz"
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
#
# Memory Technology Devices (MTD)
@@ -191,27 +305,17 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
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_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-# CONFIG_IOSCHED_AS is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-
-#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -219,7 +323,14 @@ CONFIG_IOSCHED_NOOP=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -229,6 +340,7 @@ CONFIG_IOSCHED_NOOP=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -239,13 +351,6 @@ CONFIG_IOSCHED_NOOP=y
#
#
-# Networking support
-#
-# CONFIG_NET is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-
-#
# ISDN subsystem
#
@@ -260,20 +365,10 @@ CONFIG_IOSCHED_NOOP=y
# CONFIG_INPUT is not set
#
-# Userland interfaces
-#
-
+# Hardware I/O ports
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
+# CONFIG_GAMEPORT is not set
#
# Character devices
@@ -290,6 +385,7 @@ CONFIG_SOUND_GAMEPORT=y
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
@@ -312,7 +408,7 @@ CONFIG_WATCHDOG=y
#
# CONFIG_SOFT_WATCHDOG is not set
# CONFIG_SH_WDT is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -320,18 +416,38 @@ CONFIG_WATCHDOG=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -341,6 +457,7 @@ CONFIG_WATCHDOG=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -349,6 +466,7 @@ CONFIG_WATCHDOG=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
@@ -361,9 +479,10 @@ CONFIG_WATCHDOG=y
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -377,30 +496,64 @@ CONFIG_WATCHDOG=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
-# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -420,12 +573,10 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
# CONFIG_SYSFS is not set
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
@@ -466,8 +617,13 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
CONFIG_SH_STANDARD_BIOS=y
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_EARLY_PRINTK is not set
@@ -477,7 +633,6 @@ CONFIG_SH_STANDARD_BIOS=y
# Security options
#
# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
#
# Cryptographic options
@@ -485,12 +640,9 @@ CONFIG_SH_STANDARD_BIOS=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
diff --git a/arch/mips/configs/it8172_defconfig b/arch/sh/configs/se7343_defconfig
index a91d72a9ca86..84c0075e2ad4 100644
--- a/arch/mips/configs/it8172_defconfig
+++ b/arch/sh/configs/se7343_defconfig
@@ -1,153 +1,15 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-rc1
-# Thu Jul 6 10:04:11 2006
-#
-CONFIG_MIPS=y
-
-#
-# Machine selection
-#
-# CONFIG_MIPS_MTX1 is not set
-# CONFIG_MIPS_BOSPORUS is not set
-# CONFIG_MIPS_PB1000 is not set
-# CONFIG_MIPS_PB1100 is not set
-# CONFIG_MIPS_PB1500 is not set
-# CONFIG_MIPS_PB1550 is not set
-# CONFIG_MIPS_PB1200 is not set
-# CONFIG_MIPS_DB1000 is not set
-# CONFIG_MIPS_DB1100 is not set
-# CONFIG_MIPS_DB1500 is not set
-# CONFIG_MIPS_DB1550 is not set
-# CONFIG_MIPS_DB1200 is not set
-# CONFIG_MIPS_MIRAGE is not set
-# CONFIG_BASLER_EXCITE is not set
-# CONFIG_MIPS_COBALT is not set
-# CONFIG_MACH_DECSTATION is not set
-# CONFIG_MIPS_EV64120 is not set
-# CONFIG_MIPS_EV96100 is not set
-# CONFIG_MIPS_IVR is not set
-CONFIG_MIPS_ITE8172=y
-# CONFIG_MACH_JAZZ is not set
-# CONFIG_LASAT is not set
-# CONFIG_MIPS_ATLAS is not set
-# CONFIG_MIPS_MALTA is not set
-# CONFIG_MIPS_SEAD is not set
-# CONFIG_WR_PPMC is not set
-# CONFIG_MIPS_SIM is not set
-# CONFIG_MOMENCO_JAGUAR_ATX is not set
-# CONFIG_MOMENCO_OCELOT is not set
-# CONFIG_MOMENCO_OCELOT_3 is not set
-# CONFIG_MOMENCO_OCELOT_C is not set
-# CONFIG_MOMENCO_OCELOT_G is not set
-# CONFIG_MIPS_XXS1500 is not set
-# CONFIG_PNX8550_V2PCI is not set
-# CONFIG_PNX8550_JBS is not set
-# CONFIG_DDB5477 is not set
-# CONFIG_MACH_VR41XX is not set
-# CONFIG_PMC_YOSEMITE is not set
-# CONFIG_QEMU is not set
-# CONFIG_MARKEINS is not set
-# CONFIG_SGI_IP22 is not set
-# CONFIG_SGI_IP27 is not set
-# CONFIG_SGI_IP32 is not set
-# CONFIG_SIBYTE_BIGSUR is not set
-# CONFIG_SIBYTE_SWARM is not set
-# CONFIG_SIBYTE_SENTOSA is not set
-# CONFIG_SIBYTE_RHONE is not set
-# CONFIG_SIBYTE_CARMEL is not set
-# CONFIG_SIBYTE_PTSWARM is not set
-# CONFIG_SIBYTE_LITTLESUR is not set
-# CONFIG_SIBYTE_CRHINE is not set
-# CONFIG_SIBYTE_CRHONE is not set
-# CONFIG_SNI_RM200_PCI is not set
-# CONFIG_TOSHIBA_JMR3927 is not set
-# CONFIG_TOSHIBA_RBTX4927 is not set
-# CONFIG_TOSHIBA_RBTX4938 is not set
-# CONFIG_IT8172_REVC is not set
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:46:17 2006
+#
+CONFIG_SUPERH=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_FIND_NEXT_BIT=y
CONFIG_GENERIC_HWEIGHT=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-CONFIG_DMA_NONCOHERENT=y
-CONFIG_DMA_NEED_PCI_MAP_STATE=y
-# CONFIG_CPU_BIG_ENDIAN is not set
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
-CONFIG_ITE_BOARD_GEN=y
-CONFIG_IT8172_CIR=y
-CONFIG_IT8712=y
-CONFIG_MIPS_L1_CACHE_SHIFT=5
-
-#
-# CPU selection
-#
-# CONFIG_CPU_MIPS32_R1 is not set
-# CONFIG_CPU_MIPS32_R2 is not set
-# CONFIG_CPU_MIPS64_R1 is not set
-# CONFIG_CPU_MIPS64_R2 is not set
-# CONFIG_CPU_R3000 is not set
-# CONFIG_CPU_TX39XX is not set
-# CONFIG_CPU_VR41XX is not set
-# CONFIG_CPU_R4300 is not set
-# CONFIG_CPU_R4X00 is not set
-# CONFIG_CPU_TX49XX is not set
-# CONFIG_CPU_R5000 is not set
-# CONFIG_CPU_R5432 is not set
-# CONFIG_CPU_R6000 is not set
-CONFIG_CPU_NEVADA=y
-# CONFIG_CPU_R8000 is not set
-# CONFIG_CPU_R10000 is not set
-# CONFIG_CPU_RM7000 is not set
-# CONFIG_CPU_RM9000 is not set
-# CONFIG_CPU_SB1 is not set
-CONFIG_SYS_HAS_CPU_R5432=y
-CONFIG_SYS_HAS_CPU_NEVADA=y
-CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
-CONFIG_SYS_SUPPORTS_64BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
-CONFIG_CPU_SUPPORTS_64BIT_KERNEL=y
-
-#
-# Kernel type
-#
-CONFIG_32BIT=y
-# CONFIG_64BIT is not set
-CONFIG_PAGE_SIZE_4KB=y
-# CONFIG_PAGE_SIZE_8KB is not set
-# CONFIG_PAGE_SIZE_16KB is not set
-# CONFIG_PAGE_SIZE_64KB is not set
-CONFIG_MIPS_MT_DISABLED=y
-# CONFIG_MIPS_MT_SMTC is not set
-# CONFIG_MIPS_MT_SMP is not set
-# CONFIG_MIPS_VPE_LOADER is not set
-CONFIG_CPU_HAS_LLSC=y
-CONFIG_CPU_HAS_SYNC=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
-CONFIG_ARCH_FLATMEM_ENABLE=y
-CONFIG_SELECT_MEMORY_MODEL=y
-CONFIG_FLATMEM_MANUAL=y
-# CONFIG_DISCONTIGMEM_MANUAL is not set
-# CONFIG_SPARSEMEM_MANUAL is not set
-CONFIG_FLATMEM=y
-CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-# CONFIG_HZ_48 is not set
-# CONFIG_HZ_100 is not set
-# CONFIG_HZ_128 is not set
-# CONFIG_HZ_250 is not set
-# CONFIG_HZ_256 is not set
-CONFIG_HZ_1000=y
-# CONFIG_HZ_1024 is not set
-CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
-CONFIG_HZ=1000
-CONFIG_PREEMPT_NONE=y
-# CONFIG_PREEMPT_VOLUNTARY is not set
-# CONFIG_PREEMPT is not set
+CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
@@ -162,32 +24,35 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
#
CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
+# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
-# CONFIG_POSIX_MQUEUE is not set
-CONFIG_BSD_PROCESS_ACCT=y
-# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
-CONFIG_RELAY=y
+# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
-# CONFIG_HOTPLUG is not set
+CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
-CONFIG_RT_MUTEXES=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_SHMEM=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SHMEM is not set
CONFIG_SLAB=y
CONFIG_VM_EVENT_COUNTERS=y
-# CONFIG_TINY_SHMEM is not set
+CONFIG_TINY_SHMEM=y
CONFIG_BASE_SMALL=0
# CONFIG_SLOB is not set
@@ -196,14 +61,15 @@ CONFIG_BASE_SMALL=0
#
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
-# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
#
# Block layer
#
+CONFIG_BLOCK=y
# CONFIG_LBD is not set
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -212,21 +78,181 @@ CONFIG_KMOD=y
# IO Schedulers
#
CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_AS is not set
CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-CONFIG_DEFAULT_AS=y
-# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
# CONFIG_DEFAULT_CFQ is not set
# CONFIG_DEFAULT_NOOP is not set
-CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_DEFAULT_IOSCHED="deadline"
#
-# Bus options (PCI, PCMCIA, EISA, ISA, TC)
+# System type
+#
+CONFIG_SOLUTION_ENGINE=y
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+CONFIG_SH_7343_SOLUTION_ENGINE=y
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+CONFIG_CPU_SH4A=y
+CONFIG_CPU_SH4AL_DSP=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+CONFIG_CPU_SUBTYPE_SH7343=y
+
+#
+# Memory management options
#
-CONFIG_HW_HAS_PCI=y
-# CONFIG_PCI is not set
CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x01000000
+CONFIG_32BIT=y
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_SH_FPU is not set
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=27000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+CONFIG_HEARTBEAT=y
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -241,8 +267,13 @@ CONFIG_MMU=y
# Executable file formats
#
CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
# CONFIG_BINFMT_MISC is not set
-CONFIG_TRAD_SIGNALS=y
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
#
# Networking
@@ -257,35 +288,36 @@ CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-CONFIG_NET_KEY=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
# CONFIG_IP_PNP_RARP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_SYN_COOKIES=y
# CONFIG_INET_AH is not set
# CONFIG_INET_ESP is not set
# CONFIG_INET_IPCOMP is not set
# CONFIG_INET_XFRM_TUNNEL is not set
# CONFIG_INET_TUNNEL is not set
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_DIAG=y
-CONFIG_INET_TCP_DIAG=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+# CONFIG_INET_DIAG is not set
# CONFIG_TCP_CONG_ADVANCED is not set
-CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
# CONFIG_IPV6 is not set
# CONFIG_INET6_XFRM_TUNNEL is not set
# CONFIG_INET6_TUNNEL is not set
-CONFIG_NETWORK_SECMARK=y
+# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
#
@@ -311,7 +343,6 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -327,13 +358,7 @@ CONFIG_NETWORK_SECMARK=y
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_SOFTMAC=m
-# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
-CONFIG_WIRELESS_EXT=y
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -344,32 +369,34 @@ CONFIG_WIRELESS_EXT=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
# CONFIG_SYS_HYPERVISOR is not set
#
# Connector - unified userspace <-> kernelspace linker
#
-CONFIG_CONNECTOR=m
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
#
CONFIG_MTD=y
# CONFIG_MTD_DEBUG is not set
-# CONFIG_MTD_CONCAT is not set
-# CONFIG_MTD_PARTITIONS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
#
# User Modules And Translation Layers
#
CONFIG_MTD_CHAR=y
-# CONFIG_MTD_BLOCK is not set
-# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
#
# RAM/ROM/Flash chip drivers
@@ -388,11 +415,11 @@ CONFIG_MTD_CFI_I1=y
CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I4 is not set
# CONFIG_MTD_CFI_I8 is not set
-CONFIG_MTD_CFI_INTELEXT=y
-# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=y
-# CONFIG_MTD_RAM is not set
+CONFIG_MTD_RAM=y
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
# CONFIG_MTD_OBSOLETE_CHIPS is not set
@@ -401,10 +428,7 @@ CONFIG_MTD_CFI_UTIL=y
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PHYSMAP_START=0x8000000
-CONFIG_MTD_PHYSMAP_LEN=0x2000000
-CONFIG_MTD_PHYSMAP_BANKWIDTH=2
+# CONFIG_MTD_PHYSMAP is not set
# CONFIG_MTD_PLATRAM is not set
#
@@ -445,47 +469,29 @@ CONFIG_MTD_PHYSMAP_BANKWIDTH=2
# Block devices
#
# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=y
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
# CONFIG_BLK_DEV_INITRD is not set
-CONFIG_CDROM_PKTCDVD=m
-CONFIG_CDROM_PKTCDVD_BUFFERS=8
-# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-CONFIG_ATA_OVER_ETH=m
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
#
-CONFIG_IDE=y
-CONFIG_BLK_DEV_IDE=y
+# CONFIG_IDE is not set
#
-# Please see Documentation/ide.txt for help/info on IDE drives
-#
-# CONFIG_BLK_DEV_IDE_SATA is not set
-CONFIG_BLK_DEV_IDEDISK=y
-# CONFIG_IDEDISK_MULTI_MODE is not set
-# CONFIG_BLK_DEV_IDECD is not set
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
+# SCSI device support
#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_ARM is not set
-# CONFIG_BLK_DEV_IDEDMA is not set
-# CONFIG_IDEDMA_AUTO is not set
-# CONFIG_BLK_DEV_HD is not set
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
#
-# SCSI device support
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
#
-CONFIG_RAID_ATTRS=m
-# CONFIG_SCSI is not set
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -517,25 +523,15 @@ CONFIG_NETDEVICES=y
#
# PHY device support
#
-CONFIG_PHYLIB=m
-
-#
-# MII PHY device drivers
-#
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
+# CONFIG_PHYLIB is not set
#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_DM9000 is not set
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+CONFIG_SMC91X=y
#
# Ethernet (1000 Mbit)
@@ -579,14 +575,12 @@ CONFIG_NET_ETHERNET=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
#
-CONFIG_INPUT_MOUSEDEV=y
-CONFIG_INPUT_MOUSEDEV_PSAUX=y
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_MOUSEDEV is not set
# CONFIG_INPUT_JOYDEV is not set
# CONFIG_INPUT_TSDEV is not set
# CONFIG_INPUT_EVDEV is not set
@@ -604,11 +598,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# Hardware I/O ports
#
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_LIBPS2 is not set
-CONFIG_SERIO_RAW=m
+# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
#
@@ -617,28 +607,23 @@ CONFIG_SERIO_RAW=m
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
-CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_QTRONIX_KEYBOARD is not set
-# CONFIG_IT8172_SCR0 is not set
-# CONFIG_IT8172_SCR1 is not set
-# CONFIG_ITE_GPIO is not set
#
# Serial drivers
#
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
#
# Non-8250 serial port support
#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
-CONFIG_UNIX98_PTYS=y
+# CONFIG_UNIX98_PTYS is not set
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -651,8 +636,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -671,7 +655,38 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# I2C support
#
-# CONFIG_I2C is not set
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
#
# SPI support
@@ -682,7 +697,6 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -697,10 +711,31 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Multimedia devices
#
-# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
CONFIG_VIDEO_V4L2=y
#
+# Video Capture Adapters
+#
+
+#
+# Video Capture Adapters
+#
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_TUNER_3036 is not set
+
+#
+# Radio Adapters
+#
+
+#
# Digital Video Broadcasting Devices
#
# CONFIG_DVB is not set
@@ -708,14 +743,30 @@ CONFIG_VIDEO_V4L2=y
#
# Graphics support
#
-# CONFIG_FIRMWARE_EDID is not set
-# CONFIG_FB is not set
+CONFIG_FIRMWARE_EDID=y
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_EPSON1355 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
#
# Console display driver support
#
-# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -725,15 +776,35 @@ CONFIG_SOUND=y
#
# Advanced Linux Sound Architecture
#
-# CONFIG_SND is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+# CONFIG_SND_MIXER_OSS is not set
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_SEQUENCER_OSS is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
#
# Open Sound System
#
-CONFIG_SOUND_PRIME=y
-CONFIG_SOUND_IT8172=y
-# CONFIG_SOUND_MSNDCLAS is not set
-# CONFIG_SOUND_MSNDPIN is not set
+# CONFIG_SOUND_PRIME is not set
#
# USB support
@@ -798,9 +869,7 @@ CONFIG_SOUND_IT8172=y
#
# File systems
#
-CONFIG_EXT2_FS=y
-# CONFIG_EXT2_FS_XATTR is not set
-# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
@@ -809,13 +878,12 @@ CONFIG_EXT2_FS=y
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
-CONFIG_INOTIFY=y
-CONFIG_INOTIFY_USER=y
+# CONFIG_INOTIFY is not set
# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
+# CONFIG_DNOTIFY is not set
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=m
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -834,9 +902,12 @@ CONFIG_FUSE_FS=m
# Pseudo filesystems
#
CONFIG_PROC_FS=y
-CONFIG_PROC_KCORE=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_TMPFS is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
# CONFIG_CONFIGFS_FS is not set
@@ -852,7 +923,15 @@ CONFIG_RAMFS=y
# CONFIG_BFS_FS is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
# CONFIG_CRAMFS is not set
# CONFIG_VXFS_FS is not set
# CONFIG_HPFS_FS is not set
@@ -864,19 +943,23 @@ CONFIG_RAMFS=y
# Network File Systems
#
CONFIG_NFS_FS=y
-# CONFIG_NFS_V3 is not set
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_TCP is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
# CONFIG_SMB_FS is not set
# CONFIG_CIFS is not set
-# CONFIG_CIFS_DEBUG2 is not set
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
@@ -902,61 +985,34 @@ CONFIG_MSDOS_PARTITION=y
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_DEBUG_FS is not set
-CONFIG_CROSSCOMPILE=y
-CONFIG_CMDLINE=""
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_EARLY_SCIF_CONSOLE is not set
+# CONFIG_KGDB is not set
#
# Security options
#
-CONFIG_KEYS=y
-CONFIG_KEYS_DEBUG_PROC_KEYS=y
+# CONFIG_KEYS is not set
# CONFIG_SECURITY is not set
#
# Cryptographic options
#
-CONFIG_CRYPTO=y
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_DES=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_DEFLATE=m
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_CRC32C=m
-# CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+# CONFIG_CRYPTO is not set
#
# Library routines
#
# CONFIG_CRC_CCITT is not set
-CONFIG_CRC16=m
-CONFIG_CRC32=m
-CONFIG_LIBCRC32C=m
-CONFIG_ZLIB_INFLATE=m
-CONFIG_ZLIB_DEFLATE=m
-CONFIG_PLIST=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sh/configs/se7705_defconfig b/arch/sh/configs/se7705_defconfig
index e4a14602b169..06ebd6ec0cdb 100644
--- a/arch/sh/configs/se7705_defconfig
+++ b/arch/sh/configs/se7705_defconfig
@@ -1,125 +1,212 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:45 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:03:04 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
# CONFIG_SWAP is not set
# CONFIG_SYSVIPC is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
+CONFIG_SOLUTION_ENGINE=y
CONFIG_SH_SOLUTION_ENGINE=y
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH3=y
-# CONFIG_CPU_SH4 is not set
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
CONFIG_CPU_SUBTYPE_SH7705=y
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
-CONFIG_SH7705_CACHE_32KB=y
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x02000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+CONFIG_SH7705_CACHE_32KB=y
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
# CONFIG_CF_ENABLER is not set
-CONFIG_SH_RTC=y
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_SH_FPU_EMU is not set
# CONFIG_SH_DSP is not set
# CONFIG_SH_ADC is not set
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_PREEMPT=y
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_PINT_IRQ=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
CONFIG_SH_PCLK_FREQ=33333333
#
@@ -139,17 +226,34 @@ CONFIG_SH_PCLK_FREQ=33333333
CONFIG_HEARTBEAT=y
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
#
-# CONFIG_PCI is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
#
-# PCCARD (PCMCIA/CardBus) support
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
#
-# CONFIG_PCCARD is not set
+# CONFIG_PCI is not set
#
-# PC-card bridges
+# PCCARD (PCMCIA/CardBus) support
#
#
@@ -164,9 +268,95 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
#
-# CONFIG_EMBEDDED_RAMDISK is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -177,15 +367,20 @@ CONFIG_BINFMT_ELF=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER 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=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
@@ -197,6 +392,8 @@ CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
#
# RAM/ROM/Flash chip drivers
@@ -217,22 +414,19 @@ CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_AMDSTD_RETRY=0
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PHYSMAP is not set
-CONFIG_MTD_SOLUTIONENGINE=y
-CONFIG_MTD_SUPERH_RESERVE=0x300000
-# CONFIG_MTD_MPC1211 is not set
-# CONFIG_MTD_RTS7751R2D is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -240,7 +434,6 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
@@ -256,6 +449,11 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
# CONFIG_MTD_NAND is not set
#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
# Parallel port support
#
# CONFIG_PARPORT is not set
@@ -267,25 +465,15 @@ CONFIG_MTD_SUPERH_RESERVE=0x300000
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
# CONFIG_ATA_OVER_ETH is not set
#
@@ -296,7 +484,14 @@ CONFIG_IOSCHED_AS=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -306,6 +501,7 @@ CONFIG_IOSCHED_AS=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -316,70 +512,8 @@ CONFIG_IOSCHED_AS=y
#
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
+# Network device support
#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -387,6 +521,11 @@ CONFIG_NETDEVICES=y
# CONFIG_TUN is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -422,10 +561,14 @@ CONFIG_PPP_ASYNC=y
# CONFIG_PPP_SYNC_TTY is not set
CONFIG_PPP_DEFLATE=y
# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set
# CONFIG_SLIP is not set
+CONFIG_SLHC=y
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -441,6 +584,7 @@ CONFIG_PPP_DEFLATE=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -452,18 +596,6 @@ CONFIG_INPUT=y
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-# CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_LIBPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -473,6 +605,16 @@ CONFIG_SERIO=y
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
# CONFIG_VT is not set
@@ -487,6 +629,7 @@ CONFIG_SERIO=y
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
@@ -502,7 +645,7 @@ CONFIG_UNIX98_PTYS=y
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -510,18 +653,38 @@ CONFIG_UNIX98_PTYS=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -531,6 +694,7 @@ CONFIG_UNIX98_PTYS=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -540,6 +704,7 @@ CONFIG_UNIX98_PTYS=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
@@ -552,9 +717,10 @@ CONFIG_UNIX98_PTYS=y
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -568,30 +734,64 @@ CONFIG_UNIX98_PTYS=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
-# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -611,9 +811,8 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
# CONFIG_SYSFS is not set
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
# CONFIG_TMPFS is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
@@ -632,8 +831,9 @@ CONFIG_RAMFS=y
# CONFIG_JFFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_RTIME=y
@@ -655,6 +855,7 @@ CONFIG_NFS_FS=y
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -663,6 +864,7 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -683,9 +885,13 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_KGDB is not set
@@ -693,7 +899,6 @@ CONFIG_DEBUG_PREEMPT=y
# Security options
#
# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
#
# Cryptographic options
@@ -701,14 +906,12 @@ CONFIG_DEBUG_PREEMPT=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/se7750_defconfig b/arch/sh/configs/se7750_defconfig
index 6dc31584752a..5d357d68b234 100644
--- a/arch/sh/configs/se7750_defconfig
+++ b/arch/sh/configs/se7750_defconfig
@@ -1,131 +1,218 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:46 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 11:49:01 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
# CONFIG_SWAP is not set
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
+CONFIG_SOLUTION_ENGINE=y
CONFIG_SH_SOLUTION_ENGINE=y
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
CONFIG_CPU_SUBTYPE_SH7750=y
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC1,38400 root=/dev/nfs ip=bootp"
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x02000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
CONFIG_CF_ENABLER=y
# CONFIG_CF_AREA5 is not set
CONFIG_CF_AREA6=y
CONFIG_CF_BASE_ADDR=0xb8000000
-CONFIG_SH_RTC=y
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
+
+#
+# Processor features
+#
CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
-CONFIG_SH_PCLK_FREQ=49876504
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=50000000
#
# CPU Frequency scaling
@@ -144,17 +231,34 @@ CONFIG_SH_PCLK_FREQ=49876504
CONFIG_HEARTBEAT=y
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
#
-# CONFIG_PCI is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
#
-# PCCARD (PCMCIA/CardBus) support
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,38400 root=/dev/nfs ip=bootp"
+
+#
+# Bus options
#
-# CONFIG_PCCARD is not set
+# CONFIG_PCI is not set
#
-# PC-card bridges
+# PCCARD (PCMCIA/CardBus) support
#
#
@@ -169,6 +273,98 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
# Device Drivers
#
@@ -177,15 +373,20 @@ CONFIG_BINFMT_ELF=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER 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=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
@@ -197,6 +398,8 @@ CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
#
# RAM/ROM/Flash chip drivers
@@ -217,22 +420,19 @@ CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_AMDSTD_RETRY=0
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=y
# CONFIG_MTD_RAM is not set
CONFIG_MTD_ROM=y
# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PHYSMAP is not set
-CONFIG_MTD_SOLUTIONENGINE=y
-CONFIG_MTD_SUPERH_RESERVE=0x00010000
-# CONFIG_MTD_MPC1211 is not set
-# CONFIG_MTD_RTS7751R2D is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
@@ -240,7 +440,6 @@ CONFIG_MTD_SUPERH_RESERVE=0x00010000
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
@@ -256,6 +455,11 @@ CONFIG_MTD_SUPERH_RESERVE=0x00010000
# CONFIG_MTD_NAND is not set
#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
# Parallel port support
#
# CONFIG_PARPORT is not set
@@ -267,23 +471,12 @@ CONFIG_MTD_SUPERH_RESERVE=0x00010000
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
# CONFIG_BLK_DEV_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_INITRD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -294,7 +487,14 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -304,6 +504,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -314,71 +515,8 @@ CONFIG_IOSCHED_CFQ=y
#
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
+# Network device support
#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -386,6 +524,11 @@ CONFIG_NETDEVICES=y
# CONFIG_TUN is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -418,6 +561,8 @@ CONFIG_STNIC=y
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -435,20 +580,10 @@ CONFIG_STNIC=y
# CONFIG_INPUT is not set
#
-# Userland interfaces
+# Hardware I/O ports
#
-
-#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
+# CONFIG_GAMEPORT is not set
#
# Character devices
@@ -462,12 +597,14 @@ CONFIG_SOUND_GAMEPORT=y
CONFIG_SERIAL_8250=y
# CONFIG_SERIAL_8250_CONSOLE is not set
CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
# CONFIG_SERIAL_8250_EXTENDED is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
@@ -491,7 +628,8 @@ CONFIG_WATCHDOG=y
#
# CONFIG_SOFT_WATCHDOG is not set
CONFIG_SH_WDT=y
-# CONFIG_RTC is not set
+# CONFIG_SH_WDT_MMAP is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -499,18 +637,38 @@ CONFIG_SH_WDT=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -520,6 +678,7 @@ CONFIG_SH_WDT=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -529,7 +688,9 @@ CONFIG_SH_WDT=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -541,9 +702,10 @@ CONFIG_SH_WDT=y
#
# CONFIG_USB_ARCH_HAS_HCD is not set
# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -557,29 +719,63 @@ CONFIG_SH_WDT=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
-# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
#
# File systems
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -599,14 +795,14 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -621,8 +817,9 @@ CONFIG_RAMFS=y
# CONFIG_JFFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_RTIME=y
@@ -644,6 +841,7 @@ CONFIG_NFS_FS=y
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -652,6 +850,7 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -667,6 +866,7 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
#
@@ -682,8 +882,14 @@ CONFIG_PARTITION_ADVANCED=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_KGDB is not set
@@ -700,14 +906,12 @@ CONFIG_PARTITION_ADVANCED=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/se7751_defconfig b/arch/sh/configs/se7751_defconfig
index 1ce028947459..a9095593f8f3 100644
--- a/arch/sh/configs/se7751_defconfig
+++ b/arch/sh/configs/se7751_defconfig
@@ -1,126 +1,213 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:48 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:10:12 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
# CONFIG_POSIX_MQUEUE is not set
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
#
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
+CONFIG_SOLUTION_ENGINE=y
# CONFIG_SH_SOLUTION_ENGINE is not set
CONFIG_SH_7751_SOLUTION_ENGINE=y
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC1,38400"
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x04000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00010000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
-CONFIG_SH_PCLK_FREQ=60013568
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=60000000
#
# CPU Frequency scaling
@@ -139,28 +226,39 @@ CONFIG_SH_PCLK_FREQ=60013568
CONFIG_HEARTBEAT=y
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
#
-CONFIG_PCI=y
-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-# CONFIG_PCI_LEGACY_PROC is not set
-# CONFIG_PCI_NAMES is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
#
-# PCCARD (PCMCIA/CardBus) support
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00010000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,38400"
+
#
-# CONFIG_PCCARD is not set
+# Bus options
+#
+# CONFIG_PCI is not set
#
-# PC-card bridges
+# PCCARD (PCMCIA/CardBus) support
#
#
# PCI Hotplug Support
#
-# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -170,9 +268,115 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+CONFIG_NETFILTER_DEBUG=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_IP_NF_CONNTRACK is not set
+CONFIG_IP_NF_QUEUE=y
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
#
-# CONFIG_EMBEDDED_RAMDISK is not set
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -183,15 +387,20 @@ CONFIG_BINFMT_ELF=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER 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=y
# CONFIG_MTD_DEBUG is not set
-CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
# CONFIG_MTD_REDBOOT_PARTS is not set
# CONFIG_MTD_CMDLINE_PARTS is not set
@@ -203,6 +412,8 @@ CONFIG_MTD_BLOCK=y
# CONFIG_FTL is not set
# CONFIG_NFTL is not set
# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
#
# RAM/ROM/Flash chip drivers
@@ -223,30 +434,26 @@ CONFIG_MTD_CFI_I2=y
# CONFIG_MTD_CFI_I8 is not set
# CONFIG_MTD_CFI_INTELEXT is not set
CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_AMDSTD_RETRY=0
# CONFIG_MTD_CFI_STAA is not set
CONFIG_MTD_CFI_UTIL=y
CONFIG_MTD_RAM=y
# CONFIG_MTD_ROM is not set
# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
#
# Mapping drivers for chip access
#
# CONFIG_MTD_COMPLEX_MAPPINGS is not set
# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SOLUTIONENGINE is not set
-# CONFIG_MTD_MPC1211 is not set
-# CONFIG_MTD_RTS7751R2D is not set
+# CONFIG_MTD_PLATRAM is not set
#
# Self-contained MTD device drivers
#
-# CONFIG_MTD_PMC551 is not set
# CONFIG_MTD_SLRAM is not set
# CONFIG_MTD_PHRAM is not set
# CONFIG_MTD_MTDRAM is not set
-# CONFIG_MTD_BLKMTD is not set
# CONFIG_MTD_BLOCK2MTD is not set
#
@@ -262,6 +469,11 @@ CONFIG_MTD_RAM=y
# CONFIG_MTD_NAND is not set
#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
# Parallel port support
#
# CONFIG_PARPORT is not set
@@ -273,30 +485,15 @@ CONFIG_MTD_RAM=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
# CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_SX8 is not set
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_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -307,7 +504,14 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -317,109 +521,29 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
#
-# CONFIG_IEEE1394 is not set
#
# I2O device support
#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-CONFIG_NETLINK_DEV=y
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-CONFIG_NETFILTER_DEBUG=y
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
-CONFIG_IP_NF_QUEUE=y
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
#
-# Network testing
+# Network device support
#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
# CONFIG_TUN is not set
-# CONFIG_ETHERTAP is not set
#
-# ARCnet devices
+# PHY device support
#
-# CONFIG_ARCNET is not set
+# CONFIG_PHYLIB is not set
#
# Ethernet (10 or 100Mbit)
@@ -427,60 +551,19 @@ CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
# CONFIG_STNIC is not set
-# CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNGEM is not set
-# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
#
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-# CONFIG_HP100 is not set
-CONFIG_NET_PCI=y
-CONFIG_PCNET32=y
-# CONFIG_AMD8111_ETH is not set
-# CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_B44 is not set
-# CONFIG_FORCEDETH is not set
-# CONFIG_DGRS is not set
-# CONFIG_EEPRO100 is not set
-# CONFIG_E100 is not set
-# CONFIG_FEALNX is not set
-# CONFIG_NATSEMI is not set
-# CONFIG_NE2K_PCI is not set
-# CONFIG_8139CP is not set
-# CONFIG_8139TOO is not set
-# CONFIG_SIS900 is not set
-# CONFIG_EPIC100 is not set
-# CONFIG_SUNDANCE is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-
-#
# Ethernet (1000 Mbit)
#
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_R8169 is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_VIA_VELOCITY is not set
-# CONFIG_TIGON3 is not set
#
# Ethernet (10000 Mbit)
#
-# CONFIG_IXGB is not set
-# CONFIG_S2IO is not set
#
# Token Ring devices
#
-# CONFIG_TR is not set
#
# Wireless LAN (non-hamradio)
@@ -491,12 +574,12 @@ CONFIG_PCNET32=y
# Wan interfaces
#
# CONFIG_WAN is not set
-# CONFIG_FDDI is not set
-# CONFIG_HIPPI is not set
# CONFIG_PPP is not set
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -514,20 +597,10 @@ CONFIG_PCNET32=y
# CONFIG_INPUT is not set
#
-# Userland interfaces
-#
-
+# Hardware I/O ports
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
-# Input Device Drivers
-#
+# CONFIG_GAMEPORT is not set
#
# Character devices
@@ -564,33 +637,46 @@ CONFIG_WATCHDOG=y
#
# CONFIG_SOFT_WATCHDOG is not set
# CONFIG_SH_WDT is not set
-
-#
-# PCI-based Watchdog Cards
-#
-# CONFIG_PCIPCWATCHDOG is not set
-# CONFIG_WDTPCI is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -600,6 +686,7 @@ CONFIG_WATCHDOG=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -609,7 +696,9 @@ CONFIG_WATCHDOG=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -619,12 +708,12 @@ CONFIG_WATCHDOG=y
#
# USB support
#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -638,30 +727,65 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
-# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -681,14 +805,14 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -703,8 +827,9 @@ CONFIG_RAMFS=y
# CONFIG_JFFS_FS is not set
CONFIG_JFFS2_FS=y
CONFIG_JFFS2_FS_DEBUG=0
-# CONFIG_JFFS2_FS_NAND is not set
-# CONFIG_JFFS2_FS_NOR_ECC is not set
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
CONFIG_JFFS2_ZLIB=y
CONFIG_JFFS2_RTIME=y
@@ -726,6 +851,7 @@ CONFIG_JFFS2_RTIME=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -746,8 +872,14 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_KGDB is not set
@@ -764,14 +896,12 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/sh03_defconfig b/arch/sh/configs/sh03_defconfig
index 078f78c7fe53..9fd5ea7304e5 100644
--- a/arch/sh/configs/sh03_defconfig
+++ b/arch/sh/configs/sh03_defconfig
@@ -1,51 +1,63 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:49 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:13:26 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
CONFIG_BSD_PROCESS_ACCT=y
# CONFIG_BSD_PROCESS_ACCT_V3 is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -53,81 +65,154 @@ CONFIG_CC_ALIGN_JUMPS=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_OBSOLETE_MODPARM=y
CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
CONFIG_SH_SH03=y
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
CONFIG_CPU_SUBTYPE_SH7751=y
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-CONFIG_CMDLINE_BOOL=y
-CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x08000000
CONFIG_MEMORY_SIZE=0x08000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
CONFIG_CF_ENABLER=y
CONFIG_CF_AREA5=y
# CONFIG_CF_AREA6 is not set
CONFIG_CF_BASE_ADDR=0xb4000000
-CONFIG_SH_RTC=y
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00004000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
+
+#
+# Processor features
+#
CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_PREEMPT=y
-# CONFIG_UBC_WAKEUP is not set
-# CONFIG_SH_WRITETHROUGH is not set
-# CONFIG_SH_OCRAM is not set
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
-CONFIG_SH_PCLK_FREQ=49876504
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=60000000
#
# CPU Frequency scaling
@@ -146,14 +231,36 @@ CONFIG_SH_PCLK_FREQ=49876504
CONFIG_HEARTBEAT=y
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00004000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,115200 mem=64M root=/dev/nfs"
+
+#
+# Bus options
#
CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
CONFIG_PCI_AUTO=y
CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -161,10 +268,6 @@ CONFIG_PCI_NAMES=y
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# PCI Hotplug Support
#
CONFIG_HOTPLUG_PCI=m
@@ -180,9 +283,96 @@ CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=y
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
#
-# CONFIG_EMBEDDED_RAMDISK is not set
+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_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -194,6 +384,12 @@ CONFIG_BINFMT_MISC=y
# CONFIG_STANDALONE is not set
# CONFIG_PREVENT_FIRMWARE_BUILD is not set
# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -212,7 +408,6 @@ CONFIG_BINFMT_MISC=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -225,18 +420,9 @@ CONFIG_BLK_DEV_NBD=y
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_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -263,7 +449,6 @@ CONFIG_BLK_DEV_IDEFLOPPY=m
#
CONFIG_IDE_GENERIC=y
# CONFIG_BLK_DEV_IDEPCI is not set
-CONFIG_IDE_SH=y
# CONFIG_IDE_ARM is not set
# CONFIG_BLK_DEV_IDEDMA is not set
# CONFIG_IDEDMA_AUTO is not set
@@ -272,7 +457,9 @@ CONFIG_IDE_SH=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=m
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -284,6 +471,7 @@ CONFIG_BLK_DEV_SD=m
CONFIG_BLK_DEV_SR=m
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -293,15 +481,18 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
# CONFIG_SCSI_SPI_ATTRS is not set
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -309,40 +500,35 @@ CONFIG_CHR_DEV_SG=m
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_DPT_I2O is not set
-# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_CPQFCTS is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=m
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -351,6 +537,9 @@ CONFIG_SCSI_QLA2XXX=m
# Fusion MPT device support
#
# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
@@ -363,73 +552,8 @@ CONFIG_SCSI_QLA2XXX=m
# CONFIG_I2O is not set
#
-# Networking support
+# Network device support
#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -442,6 +566,11 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -449,6 +578,7 @@ CONFIG_MII=y
# CONFIG_STNIC is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
@@ -487,15 +617,22 @@ CONFIG_8139CP=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -518,6 +655,8 @@ CONFIG_8139CP=y
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -533,6 +672,7 @@ CONFIG_8139CP=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -547,14 +687,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-# CONFIG_SERIO is not set
-# CONFIG_SERIO_I8042 is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -564,27 +696,38 @@ CONFIG_SOUND_GAMEPORT=y
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
# Serial drivers
#
CONFIG_SERIAL_8250=m
+CONFIG_SERIAL_8250_PCI=m
CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
# CONFIG_SERIAL_8250_EXTENDED is not set
#
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -605,14 +748,14 @@ CONFIG_WATCHDOG=y
#
# CONFIG_SOFT_WATCHDOG is not set
CONFIG_SH_WDT=m
+# CONFIG_SH_WDT_MMAP is not set
#
# PCI-based Watchdog Cards
#
# CONFIG_PCIPCWATCHDOG is not set
# CONFIG_WDTPCI is not set
-# CONFIG_RTC is not set
-CONFIG_SH03_RTC=y
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -625,14 +768,35 @@ CONFIG_SH03_RTC=y
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -642,6 +806,7 @@ CONFIG_SH03_RTC=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -651,13 +816,14 @@ CONFIG_SH03_RTC=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
# Console display driver support
#
-# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -667,12 +833,13 @@ CONFIG_DUMMY_CONSOLE=y
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -686,17 +853,53 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
# CONFIG_INFINIBAND is not set
#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
# CONFIG_EXT2_FS_POSIX_ACL is not set
# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
@@ -707,17 +910,17 @@ CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
-
-#
-# XFS support
-#
# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
CONFIG_AUTOFS_FS=y
CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -744,14 +947,14 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -775,16 +978,19 @@ CONFIG_RAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
# CONFIG_NFS_DIRECTIO is not set
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
CONFIG_NFSD_TCP=y
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
CONFIG_RPCSEC_GSS_KRB5=y
@@ -794,6 +1000,7 @@ CONFIG_RPCSEC_GSS_KRB5=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -813,6 +1020,7 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
#
@@ -868,9 +1076,14 @@ CONFIG_OPROFILE=m
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
CONFIG_SH_STANDARD_BIOS=y
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_EARLY_PRINTK is not set
@@ -886,6 +1099,10 @@ CONFIG_SH_STANDARD_BIOS=y
# Cryptographic options
#
CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
CONFIG_CRYPTO_HMAC=y
# CONFIG_CRYPTO_NULL is not set
# CONFIG_CRYPTO_MD4 is not set
@@ -894,6 +1111,9 @@ CONFIG_CRYPTO_SHA1=y
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=m
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
@@ -918,7 +1138,9 @@ CONFIG_CRYPTO_DEFLATE=y
# Library routines
#
CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/sh7710voipgw_defconfig b/arch/sh/configs/sh7710voipgw_defconfig
new file mode 100644
index 000000000000..9380c321169a
--- /dev/null
+++ b/arch/sh/configs/sh7710voipgw_defconfig
@@ -0,0 +1,955 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:48:56 2006
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SHMEM is not set
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+CONFIG_SH_7710VOIPGW=y
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH3=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+CONFIG_CPU_SUBTYPE_SH7710=y
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x00800000
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_SH_FPU_EMU is not set
+CONFIG_SH_DSP=y
+# CONFIG_SH_ADC is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=32768000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=y
+# CONFIG_IP_NF_CT_ACCT is not set
+# CONFIG_IP_NF_CONNTRACK_MARK is not set
+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+# CONFIG_IP_NF_IRC is not set
+# CONFIG_IP_NF_NETBIOS_NS is not set
+# CONFIG_IP_NF_TFTP is not set
+# CONFIG_IP_NF_AMANDA is not set
+CONFIG_IP_NF_PPTP=m
+# CONFIG_IP_NF_H323 is not set
+# CONFIG_IP_NF_SIP is not set
+# CONFIG_IP_NF_QUEUE is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=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
+#
+CONFIG_NET_SCH_CBQ=y
+# CONFIG_NET_SCH_HTB is not set
+# CONFIG_NET_SCH_HFSC is not set
+# CONFIG_NET_SCH_PRIO is not set
+# CONFIG_NET_SCH_RED is not set
+# CONFIG_NET_SCH_SFQ is not set
+# CONFIG_NET_SCH_TEQL is not set
+# CONFIG_NET_SCH_TBF is not set
+# CONFIG_NET_SCH_GRED is not set
+# CONFIG_NET_SCH_DSMARK is not set
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=y
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=y
+CONFIG_NET_CLS_TCINDEX=y
+CONFIG_NET_CLS_ROUTE4=y
+CONFIG_NET_CLS_ROUTE=y
+# CONFIG_NET_CLS_FW is not set
+CONFIG_NET_CLS_U32=y
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_CLS_U32_MARK is not set
+# CONFIG_NET_CLS_RSVP is not set
+# CONFIG_NET_CLS_RSVP6 is not set
+# CONFIG_NET_EMATCH is not set
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+CONFIG_MTD_RAM=y
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+CONFIG_PHONE=y
+# CONFIG_PHONE_IXJ is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_UNIX98_PTYS is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_NFS_FS is not set
+# CONFIG_NFSD is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/arch/sh/configs/shmin_defconfig b/arch/sh/configs/shmin_defconfig
new file mode 100644
index 000000000000..8800fefcbaf0
--- /dev/null
+++ b/arch/sh/configs/shmin_defconfig
@@ -0,0 +1,862 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:52:49 2006
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+# CONFIG_UID16 is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+# CONFIG_BUG is not set
+# CONFIG_ELF_CORE is not set
+# CONFIG_BASE_FULL is not set
+# CONFIG_FUTEX is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SHMEM is not set
+# CONFIG_SLAB is not set
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+CONFIG_SLOB=y
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+CONFIG_DEFAULT_NOOP=y
+CONFIG_DEFAULT_IOSCHED="noop"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+CONFIG_SH_SHMIN=y
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH3=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+CONFIG_CPU_SUBTYPE_SH7706=y
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+# CONFIG_CPU_SUBTYPE_SH7751 is not set
+# CONFIG_CPU_SUBTYPE_SH7751R is not set
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x0c000000
+CONFIG_MEMORY_SIZE=0x00800000
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+# CONFIG_SH_FPU_EMU is not set
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_ADC is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=32000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+# CONFIG_SH_DMA is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00210000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,115200 root=1f01 mtdparts=phys_mapped_flash:64k(firm)ro,-(sys) netdev=34,0x300,eth0 "
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+# CONFIG_PACKET is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+
+#
+# User Modules And Translation Layers
+#
+# CONFIG_MTD_CHAR is not set
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0xa0000000
+CONFIG_MTD_PHYSMAP_LEN=0x80000
+CONFIG_MTD_PHYSMAP_BANKWIDTH=1
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+# CONFIG_MTD_NAND is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+# CONFIG_BLK_DEV_INITRD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_STNIC is not set
+# CONFIG_SMC91X is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+# CONFIG_INPUT is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_INOTIFY is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+# CONFIG_SYSFS is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UNWIND_INFO is not set
+CONFIG_SH_STANDARD_BIOS=y
+CONFIG_EARLY_PRINTK=y
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
diff --git a/arch/sh/configs/snapgear_defconfig b/arch/sh/configs/snapgear_defconfig
index 69cf02a24761..98503f16f3f5 100644
--- a/arch/sh/configs/snapgear_defconfig
+++ b/arch/sh/configs/snapgear_defconfig
@@ -1,48 +1,60 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:51 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:55:47 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
# CONFIG_SYSVIPC is not set
# CONFIG_POSIX_MQUEUE is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -50,70 +62,145 @@ CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_MODULES is not set
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SYSTEMH is not set
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
CONFIG_SH_SECUREEDGE5410=y
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
CONFIG_CPU_SUBTYPE_SH7751=y
+CONFIG_CPU_SUBTYPE_SH7751R=y
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x08000000
CONFIG_MEMORY_SIZE=0x01000000
-CONFIG_MEMORY_SET=y
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-# CONFIG_PREEMPT is not set
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
-CONFIG_SH_PCLK_FREQ=60013568
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=60000000
#
# CPU Frequency scaling
@@ -133,28 +220,42 @@ CONFIG_NR_ONCHIP_DMA_CHANNELS=4
# CONFIG_HD6446X_SERIES is not set
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
#
CONFIG_PCI=y
# CONFIG_SH_PCIDMA_NONCOHERENT is not set
CONFIG_PCI_AUTO=y
CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-# CONFIG_PCI_LEGACY_PROC is not set
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
#
# PCCARD (PCMCIA/CardBus) support
#
-# CONFIG_PCCARD is not set
-
-#
-# PC-card bridges
-#
#
# PCI Hotplug Support
#
-# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -164,9 +265,94 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+# CONFIG_PACKET is not set
+# CONFIG_UNIX is not set
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
#
-# CONFIG_EMBEDDED_RAMDISK is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
#
# Device Drivers
@@ -177,7 +363,12 @@ CONFIG_BINFMT_ELF=y
#
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -196,7 +387,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -208,18 +398,9 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
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_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -230,7 +411,14 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -240,6 +428,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -252,69 +441,8 @@ CONFIG_IOSCHED_CFQ=y
# CONFIG_I2O is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
-#
-# CONFIG_PACKET is not set
-# CONFIG_NETLINK_DEV is not set
-# CONFIG_UNIX is not set
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
+# Network device support
#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -327,6 +455,11 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -334,6 +467,7 @@ CONFIG_MII=y
# CONFIG_STNIC is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
@@ -376,15 +510,22 @@ CONFIG_8139TOO=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -406,6 +547,8 @@ CONFIG_8139TOO=y
# CONFIG_SLIP is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -421,6 +564,7 @@ CONFIG_8139TOO=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -435,18 +579,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-# CONFIG_SERIO_RAW is not set
-
-#
# Input Device Drivers
#
# CONFIG_INPUT_KEYBOARD is not set
@@ -456,11 +588,23 @@ CONFIG_SERIO_SERPORT=y
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -472,6 +616,7 @@ CONFIG_HW_CONSOLE=y
# Non-8250 serial port support
#
# CONFIG_SERIAL_SH_SCI is not set
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -485,7 +630,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -498,14 +643,35 @@ CONFIG_LEGACY_PTY_COUNT=256
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -515,6 +681,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -524,13 +691,14 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
#
# Console display driver support
#
-CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -540,12 +708,13 @@ CONFIG_DUMMY_CONSOLE=y
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -559,30 +728,66 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
# CONFIG_INFINIBAND is not set
#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -602,16 +807,14 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -635,12 +838,14 @@ CONFIG_CRAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -649,6 +854,7 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -669,8 +875,15 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_UNWIND_INFO is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_KGDB is not set
@@ -687,13 +900,11 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/systemh_defconfig b/arch/sh/configs/systemh_defconfig
index 431c9c9da165..c16350dac01b 100644
--- a/arch/sh/configs/systemh_defconfig
+++ b/arch/sh/configs/systemh_defconfig
@@ -1,48 +1,58 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11-sh
-# Wed Mar 2 15:09:53 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:57:29 2006
#
CONFIG_SUPERH=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-# CONFIG_CLEAN_COMPILE is not set
-CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
# CONFIG_SYSVIPC is not set
# CONFIG_BSD_PROCESS_ACCT is not set
-# CONFIG_SYSCTL is not set
-# CONFIG_AUDIT is not set
-CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_HOTPLUG is not set
+# CONFIG_UTS_NS is not set
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_HOTPLUG is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -50,75 +60,150 @@ CONFIG_CC_ALIGN_JUMPS=0
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
# System type
#
# CONFIG_SH_SOLUTION_ENGINE is not set
# CONFIG_SH_7751_SOLUTION_ENGINE is not set
# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
# CONFIG_SH_73180_SOLUTION_ENGINE is not set
CONFIG_SH_7751_SYSTEMH=y
-# CONFIG_SH_STB1_HARP is not set
-# CONFIG_SH_STB1_OVERDRIVE is not set
-# CONFIG_SH_HP620 is not set
-# CONFIG_SH_HP680 is not set
-# CONFIG_SH_HP690 is not set
-# CONFIG_SH_CQREEK is not set
-# CONFIG_SH_DMIDA is not set
+# CONFIG_SH_HP6XX is not set
# CONFIG_SH_EC3104 is not set
# CONFIG_SH_SATURN is not set
# CONFIG_SH_DREAMCAST is not set
-# CONFIG_SH_CAT68701 is not set
# CONFIG_SH_BIGSUR is not set
-# CONFIG_SH_SH2000 is not set
-# CONFIG_SH_ADX is not set
# CONFIG_SH_MPC1211 is not set
# CONFIG_SH_SH03 is not set
# CONFIG_SH_SECUREEDGE5410 is not set
# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
# CONFIG_SH_EDOSK7705 is not set
# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+# CONFIG_SH_TITAN is not set
+# CONFIG_SH_SHMIN is not set
# CONFIG_SH_UNKNOWN is not set
-# CONFIG_CPU_SH2 is not set
-# CONFIG_CPU_SH3 is not set
+
+#
+# Processor selection
+#
CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7300 is not set
# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
# CONFIG_CPU_SUBTYPE_SH7707 is not set
# CONFIG_CPU_SUBTYPE_SH7708 is not set
# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
CONFIG_CPU_SUBTYPE_SH7751=y
+CONFIG_CPU_SUBTYPE_SH7751R=y
# CONFIG_CPU_SUBTYPE_SH7760 is not set
-# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
-# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
CONFIG_MMU=y
-# CONFIG_CMDLINE_BOOL is not set
+CONFIG_PAGE_OFFSET=0x80000000
CONFIG_MEMORY_START=0x0c000000
CONFIG_MEMORY_SIZE=0x00400000
-# CONFIG_MEMORY_OVERRIDE is not set
-CONFIG_SH_RTC=y
-CONFIG_SH_FPU=y
-CONFIG_ZERO_PAGE_OFFSET=0x00001000
-CONFIG_BOOT_LINK_OFFSET=0x00800000
-CONFIG_CPU_LITTLE_ENDIAN=y
-CONFIG_PREEMPT=y
-# CONFIG_UBC_WAKEUP is not set
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
# CONFIG_SH_WRITETHROUGH is not set
# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
# CONFIG_SH_STORE_QUEUES is not set
-# CONFIG_SMP is not set
-CONFIG_SH_PCLK_CALC=y
-CONFIG_SH_PCLK_FREQ=49876504
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=60000000
#
# CPU Frequency scaling
@@ -136,28 +221,39 @@ CONFIG_SH_PCLK_FREQ=49876504
# CONFIG_HD6446X_SERIES is not set
#
-# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
+# Kernel features
#
-CONFIG_PCI=y
-# CONFIG_SH_PCIDMA_NONCOHERENT is not set
-CONFIG_PCI_AUTO=y
-CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_PREEMPT_BKL=y
#
-# PCCARD (PCMCIA/CardBus) support
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x00800000
+# CONFIG_UBC_WAKEUP is not set
+# CONFIG_CMDLINE_BOOL is not set
+
+#
+# Bus options
#
-# CONFIG_PCCARD is not set
+# CONFIG_PCI is not set
#
-# PC-card bridges
+# PCCARD (PCMCIA/CardBus) support
#
#
# PCI Hotplug Support
#
-# CONFIG_HOTPLUG_PCI is not set
#
# Executable file formats
@@ -167,9 +263,14 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
-# SH initrd options
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
#
-# CONFIG_EMBEDDED_RAMDISK is not set
+# CONFIG_NET is not set
#
# Device Drivers
@@ -180,7 +281,11 @@ CONFIG_BINFMT_ELF=y
#
# CONFIG_STANDALONE is not set
CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
#
# Memory Technology Devices (MTD)
@@ -199,31 +304,16 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_SX8 is not set
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_BLK_DEV_RAM_SIZE=1024
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
CONFIG_BLK_DEV_INITRD=y
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-
-#
# ATA/ATAPI/MFM/RLL support
#
# CONFIG_IDE is not set
@@ -231,7 +321,14 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
# CONFIG_SCSI is not set
+# CONFIG_SCSI_NETLINK is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
#
# Multi-device support (RAID and LVM)
@@ -241,23 +338,15 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
#
-# CONFIG_IEEE1394 is not set
#
# I2O device support
#
-# CONFIG_I2O is not set
-
-#
-# Networking support
-#
-# CONFIG_NET is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -274,25 +363,14 @@ CONFIG_IOSCHED_CFQ=y
# CONFIG_INPUT is not set
#
-# Userland interfaces
-#
-
+# Hardware I/O ports
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
CONFIG_SERIO=y
# CONFIG_SERIO_I8042 is not set
# CONFIG_SERIO_SERPORT is not set
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
# CONFIG_SERIO_LIBPS2 is not set
# CONFIG_SERIO_RAW is not set
-
-#
-# Input Device Drivers
-#
+# CONFIG_GAMEPORT is not set
#
# Character devices
@@ -322,27 +400,46 @@ CONFIG_LEGACY_PTY_COUNT=256
# Watchdog Cards
#
# CONFIG_WATCHDOG is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
-# CONFIG_APPLICOM is not set
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -352,6 +449,7 @@ CONFIG_LEGACY_PTY_COUNT=256
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -360,7 +458,9 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -370,12 +470,12 @@ CONFIG_LEGACY_PTY_COUNT=256
#
# USB support
#
-# CONFIG_USB is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -389,29 +489,62 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
-# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
#
# File systems
#
# CONFIG_EXT2_FS is not set
# CONFIG_EXT3_FS is not set
-# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -431,16 +564,14 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-CONFIG_DEVFS_FS=y
-CONFIG_DEVFS_MOUNT=y
-# CONFIG_DEVFS_DEBUG is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
# CONFIG_HUGETLBFS is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -478,9 +609,14 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
# CONFIG_DEBUG_KERNEL is not set
-CONFIG_DEBUG_PREEMPT=y
-# CONFIG_FRAME_POINTER is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_FS is not set
# CONFIG_SH_STANDARD_BIOS is not set
# CONFIG_EARLY_SCIF_CONSOLE is not set
# CONFIG_KGDB is not set
@@ -497,13 +633,11 @@ CONFIG_DEBUG_PREEMPT=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
diff --git a/arch/sh/configs/titan_defconfig b/arch/sh/configs/titan_defconfig
new file mode 100644
index 000000000000..5e8175461138
--- /dev/null
+++ b/arch/sh/configs/titan_defconfig
@@ -0,0 +1,1654 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.18
+# Tue Oct 3 12:59:14 2006
+#
+CONFIG_SUPERH=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System type
+#
+# CONFIG_SH_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SOLUTION_ENGINE is not set
+# CONFIG_SH_7300_SOLUTION_ENGINE is not set
+# CONFIG_SH_7343_SOLUTION_ENGINE is not set
+# CONFIG_SH_73180_SOLUTION_ENGINE is not set
+# CONFIG_SH_7751_SYSTEMH is not set
+# CONFIG_SH_HP6XX is not set
+# CONFIG_SH_EC3104 is not set
+# CONFIG_SH_SATURN is not set
+# CONFIG_SH_DREAMCAST is not set
+# CONFIG_SH_BIGSUR is not set
+# CONFIG_SH_MPC1211 is not set
+# CONFIG_SH_SH03 is not set
+# CONFIG_SH_SECUREEDGE5410 is not set
+# CONFIG_SH_HS7751RVOIP is not set
+# CONFIG_SH_7710VOIPGW is not set
+# CONFIG_SH_RTS7751R2D is not set
+# CONFIG_SH_R7780RP is not set
+# CONFIG_SH_EDOSK7705 is not set
+# CONFIG_SH_SH4202_MICRODEV is not set
+# CONFIG_SH_LANDISK is not set
+CONFIG_SH_TITAN=y
+# CONFIG_SH_SHMIN is not set
+# CONFIG_SH_UNKNOWN is not set
+
+#
+# Processor selection
+#
+CONFIG_CPU_SH4=y
+
+#
+# SH-2 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7604 is not set
+
+#
+# SH-3 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7300 is not set
+# CONFIG_CPU_SUBTYPE_SH7705 is not set
+# CONFIG_CPU_SUBTYPE_SH7706 is not set
+# CONFIG_CPU_SUBTYPE_SH7707 is not set
+# CONFIG_CPU_SUBTYPE_SH7708 is not set
+# CONFIG_CPU_SUBTYPE_SH7709 is not set
+# CONFIG_CPU_SUBTYPE_SH7710 is not set
+
+#
+# SH-4 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7750 is not set
+# CONFIG_CPU_SUBTYPE_SH7091 is not set
+# CONFIG_CPU_SUBTYPE_SH7750R is not set
+# CONFIG_CPU_SUBTYPE_SH7750S is not set
+CONFIG_CPU_SUBTYPE_SH7751=y
+CONFIG_CPU_SUBTYPE_SH7751R=y
+# CONFIG_CPU_SUBTYPE_SH7760 is not set
+# CONFIG_CPU_SUBTYPE_SH4_202 is not set
+
+#
+# ST40 Processor Support
+#
+# CONFIG_CPU_SUBTYPE_ST40STB1 is not set
+# CONFIG_CPU_SUBTYPE_ST40GX1 is not set
+
+#
+# SH-4A Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH7770 is not set
+# CONFIG_CPU_SUBTYPE_SH7780 is not set
+
+#
+# SH4AL-DSP Processor Support
+#
+# CONFIG_CPU_SUBTYPE_SH73180 is not set
+# CONFIG_CPU_SUBTYPE_SH7343 is not set
+
+#
+# Memory management options
+#
+CONFIG_MMU=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_MEMORY_START=0x08030000
+CONFIG_MEMORY_SIZE=0x7fd0000
+CONFIG_VSYSCALL=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
+
+#
+# Cache configuration
+#
+# CONFIG_SH_DIRECT_MAPPED is not set
+# CONFIG_SH_WRITETHROUGH is not set
+# CONFIG_SH_OCRAM is not set
+
+#
+# Processor features
+#
+CONFIG_CPU_LITTLE_ENDIAN=y
+CONFIG_SH_FPU=y
+# CONFIG_SH_DSP is not set
+# CONFIG_SH_STORE_QUEUES is not set
+CONFIG_CPU_HAS_INTEVT=y
+CONFIG_CPU_HAS_SR_RB=y
+
+#
+# Timer support
+#
+CONFIG_SH_TMU=y
+CONFIG_SH_PCLK_FREQ=30000000
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# DMA support
+#
+CONFIG_SH_DMA=y
+CONFIG_NR_ONCHIP_DMA_CHANNELS=8
+# CONFIG_NR_DMA_CHANNELS_BOOL is not set
+
+#
+# Companion Chips
+#
+# CONFIG_HD6446X_SERIES is not set
+
+#
+# Kernel features
+#
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+# CONFIG_KEXEC is not set
+# CONFIG_SMP is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+
+#
+# Boot options
+#
+CONFIG_ZERO_PAGE_OFFSET=0x00001000
+CONFIG_BOOT_LINK_OFFSET=0x009e0000
+# CONFIG_UBC_WAKEUP is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttySC1,38400N81 root=/dev/nfs ip=:::::eth1:autoconf"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+CONFIG_SH_PCIDMA_NONCOHERENT=y
+CONFIG_PCI_AUTO=y
+CONFIG_PCI_AUTO_UPDATE_RESOURCES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
+# CONFIG_PCI_DEBUG is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PCI Hotplug Support
+#
+CONFIG_HOTPLUG_PCI=y
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+
+#
+# Executable file formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_FLAT is not set
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options (EXPERIMENTAL)
+#
+# CONFIG_PM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+CONFIG_NET_KEY=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_MULTIPLE_TABLES=y
+# CONFIG_IP_ROUTE_FWMARK is not set
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_MULTIPATH_CACHED=y
+CONFIG_IP_ROUTE_MULTIPATH_RR=m
+CONFIG_IP_ROUTE_MULTIPATH_RANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_WRANDOM=m
+CONFIG_IP_ROUTE_MULTIPATH_DRR=m
+# CONFIG_IP_ROUTE_VERBOSE is not set
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+CONFIG_NET_IPGRE=y
+CONFIG_NET_IPGRE_BROADCAST=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+CONFIG_INET_AH=y
+CONFIG_INET_ESP=y
+CONFIG_INET_IPCOMP=y
+CONFIG_INET_XFRM_TUNNEL=y
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+
+#
+# IP: Virtual Server Configuration
+#
+# CONFIG_IP_VS is not set
+CONFIG_IPV6=y
+CONFIG_IPV6_PRIVACY=y
+# CONFIG_IPV6_ROUTER_PREF is not set
+CONFIG_INET6_AH=y
+CONFIG_INET6_ESP=y
+CONFIG_INET6_IPCOMP=y
+# CONFIG_IPV6_MIP6 is not set
+CONFIG_INET6_XFRM_TUNNEL=y
+CONFIG_INET6_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_TUNNEL=y
+# CONFIG_IPV6_SUBTREES is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_BRIDGE_NETFILTER=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=m
+CONFIG_NETFILTER_NETLINK_QUEUE=m
+CONFIG_NETFILTER_NETLINK_LOG=m
+CONFIG_NETFILTER_XTABLES=m
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
+CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+CONFIG_NETFILTER_XT_TARGET_MARK=m
+CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
+CONFIG_NETFILTER_XT_TARGET_NOTRACK=m
+CONFIG_NETFILTER_XT_MATCH_COMMENT=m
+CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
+CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
+CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
+CONFIG_NETFILTER_XT_MATCH_DCCP=m
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+CONFIG_NETFILTER_XT_MATCH_ESP=m
+CONFIG_NETFILTER_XT_MATCH_HELPER=m
+CONFIG_NETFILTER_XT_MATCH_LENGTH=m
+CONFIG_NETFILTER_XT_MATCH_LIMIT=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_MARK=m
+CONFIG_NETFILTER_XT_MATCH_POLICY=m
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
+CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+CONFIG_NETFILTER_XT_MATCH_REALM=m
+CONFIG_NETFILTER_XT_MATCH_SCTP=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+CONFIG_NETFILTER_XT_MATCH_STRING=m
+CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_IP_NF_CONNTRACK=m
+CONFIG_IP_NF_CT_ACCT=y
+CONFIG_IP_NF_CONNTRACK_MARK=y
+CONFIG_IP_NF_CONNTRACK_EVENTS=y
+CONFIG_IP_NF_CONNTRACK_NETLINK=m
+# CONFIG_IP_NF_CT_PROTO_SCTP is not set
+CONFIG_IP_NF_FTP=m
+CONFIG_IP_NF_IRC=m
+CONFIG_IP_NF_NETBIOS_NS=m
+CONFIG_IP_NF_TFTP=m
+# CONFIG_IP_NF_AMANDA is not set
+CONFIG_IP_NF_PPTP=m
+CONFIG_IP_NF_H323=m
+# CONFIG_IP_NF_SIP is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_IPRANGE=m
+CONFIG_IP_NF_MATCH_TOS=m
+CONFIG_IP_NF_MATCH_RECENT=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_TTL=m
+CONFIG_IP_NF_MATCH_OWNER=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_HASHLIMIT=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_TARGET_LOG=m
+CONFIG_IP_NF_TARGET_ULOG=m
+CONFIG_IP_NF_TARGET_TCPMSS=m
+CONFIG_IP_NF_NAT=m
+CONFIG_IP_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=m
+CONFIG_IP_NF_TARGET_REDIRECT=m
+CONFIG_IP_NF_TARGET_NETMAP=m
+CONFIG_IP_NF_TARGET_SAME=m
+CONFIG_IP_NF_NAT_SNMP_BASIC=m
+CONFIG_IP_NF_NAT_IRC=m
+CONFIG_IP_NF_NAT_FTP=m
+CONFIG_IP_NF_NAT_TFTP=m
+CONFIG_IP_NF_NAT_PPTP=m
+CONFIG_IP_NF_NAT_H323=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_TOS=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_TARGET_CLUSTERIP=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+
+#
+# IPv6: Netfilter Configuration (EXPERIMENTAL)
+#
+CONFIG_IP6_NF_QUEUE=m
+CONFIG_IP6_NF_IPTABLES=m
+CONFIG_IP6_NF_MATCH_RT=m
+CONFIG_IP6_NF_MATCH_OPTS=m
+CONFIG_IP6_NF_MATCH_FRAG=m
+CONFIG_IP6_NF_MATCH_HL=m
+CONFIG_IP6_NF_MATCH_OWNER=m
+CONFIG_IP6_NF_MATCH_IPV6HEADER=m
+CONFIG_IP6_NF_MATCH_AH=m
+CONFIG_IP6_NF_MATCH_EUI64=m
+CONFIG_IP6_NF_FILTER=m
+CONFIG_IP6_NF_TARGET_LOG=m
+CONFIG_IP6_NF_TARGET_REJECT=m
+CONFIG_IP6_NF_MANGLE=m
+CONFIG_IP6_NF_TARGET_HL=m
+CONFIG_IP6_NF_RAW=m
+
+#
+# Bridge: Netfilter Configuration
+#
+# CONFIG_BRIDGE_NF_EBTABLES is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+CONFIG_BRIDGE=y
+CONFIG_VLAN_8021Q=y
+# CONFIG_DECNET is not set
+CONFIG_LLC=y
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=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
+#
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+CONFIG_NET_SCH_HFSC=m
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+CONFIG_NET_SCH_NETEM=m
+CONFIG_NET_SCH_INGRESS=m
+
+#
+# Classification
+#
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_BASIC=m
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+CONFIG_CLS_U32_PERF=y
+CONFIG_CLS_U32_MARK=y
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+CONFIG_NET_EMATCH=y
+CONFIG_NET_EMATCH_STACK=32
+CONFIG_NET_EMATCH_CMP=m
+CONFIG_NET_EMATCH_NBYTE=m
+CONFIG_NET_EMATCH_U32=m
+CONFIG_NET_EMATCH_META=m
+CONFIG_NET_EMATCH_TEXT=m
+CONFIG_NET_CLS_ACT=y
+CONFIG_NET_ACT_POLICE=m
+CONFIG_NET_ACT_GACT=m
+CONFIG_GACT_PROB=y
+CONFIG_NET_ACT_MIRRED=m
+CONFIG_NET_ACT_IPT=m
+CONFIG_NET_ACT_PEDIT=m
+# CONFIG_NET_ACT_SIMP is not set
+CONFIG_NET_CLS_IND=y
+CONFIG_NET_ESTIMATOR=y
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+CONFIG_IEEE80211=y
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=y
+CONFIG_IEEE80211_CRYPT_CCMP=y
+CONFIG_IEEE80211_CRYPT_TKIP=y
+CONFIG_IEEE80211_SOFTMAC=m
+# CONFIG_IEEE80211_SOFTMAC_DEBUG is not set
+CONFIG_WIRELESS_EXT=y
+CONFIG_FIB_RULES=y
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+CONFIG_CONNECTOR=m
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=m
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_CONCAT is not set
+# CONFIG_MTD_PARTITIONS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=m
+CONFIG_MTD_BLOCK=m
+# CONFIG_MTD_BLOCK_RO is not set
+CONFIG_FTL=m
+CONFIG_NFTL=m
+# CONFIG_NFTL_RW is not set
+CONFIG_INFTL=m
+CONFIG_RFD_FTL=m
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=m
+CONFIG_MTD_JEDECPROBE=m
+CONFIG_MTD_GEN_PROBE=m
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=m
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_IDS=m
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+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
+CONFIG_ATA_OVER_ETH=m
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
+# CONFIG_SCSI_SYM53C8XX_2 is not set
+# CONFIG_SCSI_IPR is not set
+# CONFIG_SCSI_QLOGIC_1280 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_IFB is not set
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+
+#
+# ARCnet devices
+#
+# CONFIG_ARCNET is not set
+
+#
+# PHY device support
+#
+CONFIG_PHYLIB=m
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=m
+CONFIG_DAVICOM_PHY=m
+CONFIG_QSEMI_PHY=m
+CONFIG_LXT_PHY=m
+CONFIG_CICADA_PHY=m
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_FIXED_PHY is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_STNIC is not set
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
+
+#
+# Tulip family network device support
+#
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+# CONFIG_DGRS is not set
+# CONFIG_EEPRO100 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+CONFIG_8139TOO=y
+# CONFIG_8139TOO_PIO is not set
+CONFIG_8139TOO_TUNE_TWISTER=y
+# CONFIG_8139TOO_8129 is not set
+CONFIG_8139_OLD_RX_RESET=y
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+# CONFIG_E1000 is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+
+#
+# Token Ring devices
+#
+# CONFIG_TR is not set
+
+#
+# Wireless LAN (non-hamradio)
+#
+CONFIG_NET_RADIO=y
+CONFIG_NET_WIRELESS_RTNETLINK=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_IPW2100 is not set
+# CONFIG_IPW2200 is not set
+# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+CONFIG_PRISM54=m
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_HOSTAP is not set
+CONFIG_BCM43XX=m
+CONFIG_BCM43XX_DEBUG=y
+CONFIG_BCM43XX_DMA=y
+CONFIG_BCM43XX_PIO=y
+CONFIG_BCM43XX_DMA_AND_PIO_MODE=y
+# CONFIG_BCM43XX_DMA_MODE is not set
+# CONFIG_BCM43XX_PIO_MODE is not set
+# CONFIG_ZD1211RW is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+CONFIG_PPP=m
+CONFIG_PPP_MULTILINK=y
+CONFIG_PPP_FILTER=y
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
+CONFIG_PPP_MPPE=m
+CONFIG_PPPOE=m
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLHC=m
+CONFIG_SLIP_SMART=y
+# CONFIG_SLIP_MODE_SLIP6 is not set
+# CONFIG_NET_FC is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Telephony Support
+#
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
+CONFIG_SERIAL_SH_SCI_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SH_WDT=m
+# CONFIG_SH_WDT_MMAP is not set
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB is not set
+
+#
+# Console display driver support
+#
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+CONFIG_USB_EHCI_HCD=y
+# CONFIG_USB_EHCI_SPLIT_ISO is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+CONFIG_USB_ACM=m
+CONFIG_USB_PRINTER=m
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
+# CONFIG_USB_KBTAB is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_TOUCHSCREEN is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE is not set
+# CONFIG_USB_ATI_REMOTE2 is not set
+# CONFIG_USB_KEYSPAN_REMOTE is not set
+# CONFIG_USB_APPLETOUCH is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=m
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+CONFIG_USB_SERIAL_ARK3116=m
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+CONFIG_USB_SERIAL_PL2303=m
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_SECURITY is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_ZISOFS_FS=m
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLBFS is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_JFFS_FS is not set
+# CONFIG_JFFS2_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+CONFIG_NFSD=y
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_NFSD_TCP=y
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+# CONFIG_SMB_NLS_DEFAULT is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_9P_FS=m
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS 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 is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_FORCED_INLINING is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_SH_STANDARD_BIOS is not set
+CONFIG_EARLY_SCIF_CONSOLE=y
+# CONFIG_EARLY_PRINTK is not set
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_4KSTACKS is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+CONFIG_CRYPTO=y
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_HMAC=y
+CONFIG_CRYPTO_NULL=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_SHA1=y
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+CONFIG_CRYPTO_WP512=m
+CONFIG_CRYPTO_TGR192=m
+CONFIG_CRYPTO_ECB=m
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_KHAZAD=m
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=m
+CONFIG_CRC16=m
+CONFIG_CRC32=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_TEXTSEARCH=y
+CONFIG_TEXTSEARCH_KMP=m
+CONFIG_TEXTSEARCH_BM=m
+CONFIG_TEXTSEARCH_FSM=m
+CONFIG_PLIST=y
diff --git a/arch/sh/drivers/dma/Kconfig b/arch/sh/drivers/dma/Kconfig
index 0f15216cd39d..defc13c37d48 100644
--- a/arch/sh/drivers/dma/Kconfig
+++ b/arch/sh/drivers/dma/Kconfig
@@ -11,6 +11,8 @@ config SH_DMA
config NR_ONCHIP_DMA_CHANNELS
depends on SH_DMA
int "Number of on-chip DMAC channels"
+ default "8" if CPU_SUBTYPE_SH7750R || CPU_SUBTYPE_SH7751R
+ default "12" if CPU_SUBTYPE_SH7780
default "4"
help
This allows you to specify the number of channels that the on-chip
@@ -52,4 +54,3 @@ config DMA_PAGE_OPS_CHANNEL
are dual-address capable.
endmenu
-
diff --git a/arch/sh/drivers/dma/dma-g2.c b/arch/sh/drivers/dma/dma-g2.c
index 0f866f8789f0..0caf11bb7e27 100644
--- a/arch/sh/drivers/dma/dma-g2.c
+++ b/arch/sh/drivers/dma/dma-g2.c
@@ -3,7 +3,7 @@
*
* G2 bus DMA support
*
- * Copyright (C) 2003, 2004 Paul Mundt
+ * 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
@@ -13,7 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-
+#include <asm/cacheflush.h>
#include <asm/mach/sysasic.h>
#include <asm/mach/dma.h>
#include <asm/dma.h>
@@ -47,17 +47,31 @@ struct g2_dma_info {
static volatile struct g2_dma_info *g2_dma = (volatile struct g2_dma_info *)0xa05f7800;
-static irqreturn_t g2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+#define g2_bytes_remaining(i) \
+ ((g2_dma->channel[i].size - \
+ g2_dma->status[i].size) & 0x0fffffff)
+
+static irqreturn_t g2_dma_interrupt(int irq, void *dev_id)
{
- /* FIXME: Do some meaningful completion work here.. */
- return IRQ_HANDLED;
-}
+ int i;
-static struct irqaction g2_dma_irq = {
- .name = "g2 DMA handler",
- .handler = g2_dma_interrupt,
- .flags = IRQF_DISABLED,
-};
+ for (i = 0; i < G2_NR_DMA_CHANNELS; i++) {
+ if (g2_dma->status[i].status & 0x20000000) {
+ unsigned int bytes = g2_bytes_remaining(i);
+
+ if (likely(bytes == 0)) {
+ struct dma_info *info = dev_id;
+ struct dma_channel *chan = info->channels + i;
+
+ wake_up(&chan->wait_queue);
+
+ return IRQ_HANDLED;
+ }
+ }
+ }
+
+ return IRQ_NONE;
+}
static int g2_enable_dma(struct dma_channel *chan)
{
@@ -135,8 +149,14 @@ static int g2_xfer_dma(struct dma_channel *chan)
return 0;
}
+static int g2_get_residue(struct dma_channel *chan)
+{
+ return g2_bytes_remaining(chan->chan);
+}
+
static struct dma_ops g2_dma_ops = {
.xfer = g2_xfer_dma,
+ .get_residue = g2_get_residue,
};
static struct dma_info g2_dma_info = {
@@ -148,13 +168,22 @@ static struct dma_info g2_dma_info = {
static int __init g2_dma_init(void)
{
- setup_irq(HW_EVENT_G2_DMA, &g2_dma_irq);
+ int ret;
+
+ ret = request_irq(HW_EVENT_G2_DMA, g2_dma_interrupt, IRQF_DISABLED,
+ "g2 DMA handler", &g2_dma_info);
+ if (unlikely(ret))
+ return -EINVAL;
/* Magic */
g2_dma->wait_state = 27;
g2_dma->magic = 0x4659404f;
- return register_dmac(&g2_dma_info);
+ ret = register_dmac(&g2_dma_info);
+ if (unlikely(ret != 0))
+ free_irq(HW_EVENT_G2_DMA, 0);
+
+ return ret;
}
static void __exit g2_dma_exit(void)
@@ -169,4 +198,3 @@ module_exit(g2_dma_exit);
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
MODULE_DESCRIPTION("G2 bus DMA driver");
MODULE_LICENSE("GPL");
-
diff --git a/arch/sh/drivers/dma/dma-pvr2.c b/arch/sh/drivers/dma/dma-pvr2.c
index 30a580aa7cbd..838fad566eaf 100644
--- a/arch/sh/drivers/dma/dma-pvr2.c
+++ b/arch/sh/drivers/dma/dma-pvr2.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/boards/dreamcast/dma-pvr2.c
+ * arch/sh/drivers/dma/dma-pvr2.c
*
* NEC PowerVR 2 (Dreamcast) DMA support
*
@@ -18,10 +18,10 @@
#include <asm/dma.h>
#include <asm/io.h>
-static unsigned int xfer_complete = 0;
-static int count = 0;
+static unsigned int xfer_complete;
+static int count;
-static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pvr2_dma_interrupt(int irq, void *dev_id)
{
if (get_dma_residue(PVR2_CASCADE_CHAN)) {
printk(KERN_WARNING "DMA: SH DMAC did not complete transfer "
@@ -107,4 +107,3 @@ module_exit(pvr2_dma_exit);
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
MODULE_DESCRIPTION("NEC PowerVR 2 DMA driver");
MODULE_LICENSE("GPL");
-
diff --git a/arch/sh/drivers/dma/dma-sh.c b/arch/sh/drivers/dma/dma-sh.c
index e028a2d2a4ea..d8ece20bb2cf 100644
--- a/arch/sh/drivers/dma/dma-sh.c
+++ b/arch/sh/drivers/dma/dma-sh.c
@@ -11,14 +11,10 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-
#include <linux/init.h>
-#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/dreamcast/dma.h>
-#include <asm/signal.h>
-#include <asm/irq.h>
#include <asm/dma.h>
#include <asm/io.h>
#include "dma-sh.h"
@@ -64,9 +60,9 @@ static inline unsigned int calc_xmit_shift(struct dma_channel *chan)
* Besides that it needs to waken any waiting process, which should handle
* setting up the next transfer.
*/
-static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_tei(int irq, void *dev_id)
{
- struct dma_channel *chan = (struct dma_channel *)dev_id;
+ struct dma_channel *chan = dev_id;
u32 chcr;
chcr = ctrl_inl(CHCR[chan->chan]);
@@ -84,18 +80,23 @@ static irqreturn_t dma_tei(int irq, void *dev_id, struct pt_regs *regs)
static int sh_dmac_request_dma(struct dma_channel *chan)
{
- char name[32];
+ if (unlikely(!chan->flags & DMA_TEI_CAPABLE))
+ return 0;
- snprintf(name, sizeof(name), "DMAC Transfer End (Channel %d)",
+ chan->name = kzalloc(32, GFP_KERNEL);
+ if (unlikely(chan->name == NULL))
+ return -ENOMEM;
+ snprintf(chan->name, 32, "DMAC Transfer End (Channel %d)",
chan->chan);
return request_irq(get_dmte_irq(chan->chan), dma_tei,
- IRQF_DISABLED, name, chan);
+ IRQF_DISABLED, chan->name, chan);
}
static void sh_dmac_free_dma(struct dma_channel *chan)
{
free_irq(get_dmte_irq(chan->chan), chan);
+ kfree(chan->name);
}
static void
@@ -227,7 +228,7 @@ static inline int dmaor_reset(void)
}
#if defined(CONFIG_CPU_SH4)
-static irqreturn_t dma_err(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dma_err(int irq, void *dummy)
{
dmaor_reset();
disable_irq(irq);
@@ -259,7 +260,7 @@ static int __init sh_dmac_init(void)
#ifdef CONFIG_CPU_SH4
make_ipr_irq(DMAE_IRQ, DMA_IPR_ADDR, DMA_IPR_POS, DMA_PRIORITY);
i = request_irq(DMAE_IRQ, dma_err, IRQF_DISABLED, "DMAC Address Error", 0);
- if (i < 0)
+ if (unlikely(i < 0))
return i;
#endif
@@ -274,7 +275,7 @@ static int __init sh_dmac_init(void)
* been set.
*/
i = dmaor_reset();
- if (i < 0)
+ if (unlikely(i != 0))
return i;
return register_dmac(info);
diff --git a/arch/sh/drivers/dma/dma-sysfs.c b/arch/sh/drivers/dma/dma-sysfs.c
index 70a5d82eb2f8..29b8ef9873d1 100644
--- a/arch/sh/drivers/dma/dma-sysfs.c
+++ b/arch/sh/drivers/dma/dma-sysfs.c
@@ -48,12 +48,11 @@ static int __init dma_sysclass_init(void)
int ret;
ret = sysdev_class_register(&dma_sysclass);
- if (ret == 0)
- sysfs_create_file(&dma_sysclass.kset.kobj, &attr_devices.attr);
+ if (unlikely(ret))
+ return ret;
- return ret;
+ return sysfs_create_file(&dma_sysclass.kset.kobj, &attr_devices.attr);
}
-
postcore_initcall(dma_sysclass_init);
static ssize_t dma_show_dev_id(struct sys_device *dev, char *buf)
@@ -152,4 +151,3 @@ void dma_remove_sysfs_files(struct dma_channel *chan, struct dma_info *info)
sysdev_unregister(dev);
}
-
diff --git a/arch/sh/drivers/pci/Makefile b/arch/sh/drivers/pci/Makefile
index 365bc16a4a83..9e00cb8a39e9 100644
--- a/arch/sh/drivers/pci/Makefile
+++ b/arch/sh/drivers/pci/Makefile
@@ -6,7 +6,8 @@ obj-y += pci.o
obj-$(CONFIG_PCI_AUTO) += pci-auto.o
obj-$(CONFIG_CPU_SUBTYPE_ST40STB1) += pci-st40.o
-obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751) += pci-sh7751.o ops-sh4.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7780) += pci-sh7780.o ops-sh4.o
obj-$(CONFIG_SH_DREAMCAST) += ops-dreamcast.o fixups-dreamcast.o \
dma-dreamcast.o
@@ -14,3 +15,6 @@ obj-$(CONFIG_SH_SECUREEDGE5410) += ops-snapgear.o
obj-$(CONFIG_SH_BIGSUR) += ops-bigsur.o
obj-$(CONFIG_SH_RTS7751R2D) += ops-rts7751r2d.o fixups-rts7751r2d.o
obj-$(CONFIG_SH_SH03) += ops-sh03.o fixups-sh03.o
+obj-$(CONFIG_SH_R7780RP) += ops-r7780rp.o fixups-r7780rp.o
+obj-$(CONFIG_SH_TITAN) += ops-titan.o
+obj-$(CONFIG_SH_LANDISK) += ops-landisk.o
diff --git a/arch/sh/drivers/pci/dma-dreamcast.c b/arch/sh/drivers/pci/dma-dreamcast.c
index 6acf02b9375b..230d6ec0d239 100644
--- a/arch/sh/drivers/pci/dma-dreamcast.c
+++ b/arch/sh/drivers/pci/dma-dreamcast.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/pci/dma-dreamcast.c
+ * arch/sh/drivers/pci/dma-dreamcast.c
*
* PCI DMA support for the Sega Dreamcast
*
diff --git a/arch/sh/drivers/pci/fixups-dreamcast.c b/arch/sh/drivers/pci/fixups-dreamcast.c
index 63b1c6f4b8d2..6f53f8200dc3 100644
--- a/arch/sh/drivers/pci/fixups-dreamcast.c
+++ b/arch/sh/drivers/pci/fixups-dreamcast.c
@@ -1,10 +1,10 @@
/*
- * arch/sh/pci/fixups-dreamcast.c
+ * arch/sh/drivers/pci/fixups-dreamcast.c
*
* PCI fixups for the Sega Dreamcast
*
* Copyright (C) 2001, 2002 M. R. Brown
- * Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2002, 2003, 2006 Paul Mundt
*
* This file originally bore the message (with enclosed-$):
* Id: pci.c,v 1.3 2003/05/04 19:29:46 lethal Exp
@@ -45,36 +45,16 @@ static void __init gapspci_fixup_resources(struct pci_dev *dev)
printk("PCI: Failed resource fixup\n");
}
}
-
DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, gapspci_fixup_resources);
-void __init pcibios_fixup_bus(struct pci_bus *bus)
+int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
- /*
- * We don't have any sub bus to fix up, and this is a rather
- * stupid place to put general device fixups. Don't do it.
- * Use the pcibios_fixups table or suffer the consequences.
+ /*
+ * The interrupt routing semantics here are quite trivial.
+ *
+ * We basically only support one interrupt, so we only bother
+ * updating a device's interrupt line with this single shared
+ * interrupt. Keeps routing quite simple, doesn't it?
*/
+ return GAPSPCI_IRQ;
}
-
-void __init pcibios_fixup_irqs(void)
-{
- struct pci_dev *dev = 0;
-
- for_each_pci_dev(dev) {
- /*
- * The interrupt routing semantics here are quite trivial.
- *
- * We basically only support one interrupt, so we only bother
- * updating a device's interrupt line with this single shared
- * interrupt. Keeps routing quite simple, doesn't it?
- */
- printk(KERN_NOTICE "PCI: Fixing up IRQ routing for device %s\n",
- pci_name(dev));
-
- dev->irq = GAPSPCI_IRQ;
-
- pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
- }
-}
-
diff --git a/arch/sh/drivers/pci/fixups-r7780rp.c b/arch/sh/drivers/pci/fixups-r7780rp.c
new file mode 100644
index 000000000000..3e321df65d22
--- /dev/null
+++ b/arch/sh/drivers/pci/fixups-r7780rp.c
@@ -0,0 +1,45 @@
+/*
+ * arch/sh/drivers/pci/fixups-r7780rp.c
+ *
+ * Highlander R7780RP-1 PCI fixups
+ *
+ * Copyright (C) 2003 Lineo uSolutions, Inc.
+ * Copyright (C) 2004 - 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/pci.h>
+#include "pci-sh4.h"
+#include <asm/io.h>
+
+int pci_fixup_pcic(void)
+{
+ pci_write_reg(0x000043ff, SH4_PCIINTM);
+ pci_write_reg(0x0000380f, SH4_PCIAINTM);
+
+ pci_write_reg(0xfbb00047, SH7780_PCICMD);
+ pci_write_reg(0x00000000, SH7780_PCIIBAR);
+
+ pci_write_reg(0x00011912, SH7780_PCISVID);
+ pci_write_reg(0x08000000, SH7780_PCICSCR0);
+ pci_write_reg(0x0000001b, SH7780_PCICSAR0);
+ pci_write_reg(0xfd000000, SH7780_PCICSCR1);
+ pci_write_reg(0x0000000f, SH7780_PCICSAR1);
+
+ pci_write_reg(0xfd000000, SH7780_PCIMBR0);
+ pci_write_reg(0x00fc0000, SH7780_PCIMBMR0);
+
+#ifdef CONFIG_32BIT
+ pci_write_reg(0xc0000000, SH7780_PCIMBR2);
+ pci_write_reg(0x20000000 - SH7780_PCI_IO_SIZE, SH7780_PCIMBMR2);
+#endif
+
+ /* Set IOBR for windows containing area specified in pci.h */
+ pci_write_reg((PCIBIOS_MIN_IO & ~(SH7780_PCI_IO_SIZE - 1)),
+ SH7780_PCIIOBR);
+ pci_write_reg(((SH7780_PCI_IO_SIZE-1) & (7<<18)), SH7780_PCIIOBMR);
+
+ return 0;
+}
diff --git a/arch/sh/drivers/pci/fixups-rts7751r2d.c b/arch/sh/drivers/pci/fixups-rts7751r2d.c
index 0c590fc7a081..e72ceb560d5b 100644
--- a/arch/sh/drivers/pci/fixups-rts7751r2d.c
+++ b/arch/sh/drivers/pci/fixups-rts7751r2d.c
@@ -10,8 +10,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*/
-#include "pci-sh7751.h"
-#include <asm/io.h>
+#include "pci-sh4.h"
#define PCIMCR_MRSET_OFF 0xBFFFFFFF
#define PCIMCR_RFSH_OFF 0xFFFFFFFB
@@ -22,22 +21,23 @@ int pci_fixup_pcic(void)
bcr1 = inl(SH7751_BCR1);
bcr1 |= 0x40080000; /* Enable Bit 19 BREQEN, set PCIC to slave */
- outl(bcr1, PCI_REG(SH7751_PCIBCR1));
+ pci_write_reg(bcr1, SH4_PCIBCR1);
/* Enable all interrupts, so we known what to fix */
- outl(0x0000c3ff, PCI_REG(SH7751_PCIINTM));
- outl(0x0000380f, PCI_REG(SH7751_PCIAINTM));
+ pci_write_reg(0x0000c3ff, SH4_PCIINTM);
+ pci_write_reg(0x0000380f, SH4_PCIAINTM);
- outl(0xfb900047, PCI_REG(SH7751_PCICONF1));
- outl(0xab000001, PCI_REG(SH7751_PCICONF4));
+ pci_write_reg(0xfb900047, SH7751_PCICONF1);
+ pci_write_reg(0xab000001, SH7751_PCICONF4);
mcr = inl(SH7751_MCR);
mcr = (mcr & PCIMCR_MRSET_OFF) & PCIMCR_RFSH_OFF;
- outl(mcr, PCI_REG(SH7751_PCIMCR));
+ pci_write_reg(mcr, SH4_PCIMCR);
+
+ pci_write_reg(0x0c000000, SH7751_PCICONF5);
+ pci_write_reg(0xd0000000, SH7751_PCICONF6);
+ pci_write_reg(0x0c000000, SH4_PCILAR0);
+ pci_write_reg(0x00000000, SH4_PCILAR1);
- outl(0x0c000000, PCI_REG(SH7751_PCICONF5));
- outl(0xd0000000, PCI_REG(SH7751_PCICONF6));
- outl(0x0c000000, PCI_REG(SH7751_PCILAR0));
- outl(0x00000000, PCI_REG(SH7751_PCILAR1));
return 0;
}
diff --git a/arch/sh/drivers/pci/fixups-sh03.c b/arch/sh/drivers/pci/fixups-sh03.c
index 57ac26c2171f..2e8a18b7ee53 100644
--- a/arch/sh/drivers/pci/fixups-sh03.c
+++ b/arch/sh/drivers/pci/fixups-sh03.c
@@ -3,11 +3,7 @@
#include <linux/types.h>
#include <linux/pci.h>
-/*
- * IRQ functions
- */
-
-int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev)
+int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
int irq;
@@ -17,8 +13,9 @@ int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev)
case 8: return 5; /* eth1 */
case 6: return 2; /* PCI bridge */
default:
- printk("PCI: Bad IRQ mapping request for slot %d\n", slot);
- return 2;
+ printk(KERN_ERR "PCI: Bad IRQ mapping request "
+ "for slot %d\n", slot);
+ return 2;
}
} else {
switch (pin) {
@@ -32,30 +29,3 @@ int __init pcibios_map_platform_irq(u8 slot, u8 pin, struct pci_dev *dev)
}
return irq;
}
-
-static u8 __init sh03_no_swizzle(struct pci_dev *dev, u8 *pin)
-{
- /* no swizzling */
- return PCI_SLOT(dev->devfn);
-}
-
-static int sh03_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- int irq = -1;
-
- /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
- irq = pcibios_map_platform_irq(slot, pin, dev);
- if( irq < 0 ) {
- pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
- return irq;
- }
-
- pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
-
- return irq;
-}
-
-void __init pcibios_fixup_irqs(void)
-{
- pci_fixup_irqs(sh03_no_swizzle, sh03_pci_lookup_irq);
-}
diff --git a/arch/sh/drivers/pci/ops-bigsur.c b/arch/sh/drivers/pci/ops-bigsur.c
index ae82c6ca05e5..eb31be751524 100644
--- a/arch/sh/drivers/pci/ops-bigsur.c
+++ b/arch/sh/drivers/pci/ops-bigsur.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/pci-bigsur.c
+ * linux/arch/sh/drivers/pci/ops-bigsur.c
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
*
@@ -10,15 +10,12 @@
*
* PCI initialization for the Hitachi Big Sur Evaluation Board
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/pci.h>
-
#include <asm/io.h>
-#include "pci-sh7751.h"
+#include "pci-sh4.h"
#include <asm/bigsur/bigsur.h>
#define BIGSUR_PCI_IO 0x4000
@@ -41,11 +38,11 @@ static struct resource sh7751_mem_resource = {
extern struct pci_ops sh7751_pci_ops;
struct pci_channel board_pci_channels[] = {
- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
{ 0, }
};
-static struct sh7751_pci_address_map sh7751_pci_map = {
+static struct sh4_pci_address_map sh7751_pci_map = {
.window0 = {
.base = SH7751_CS3_BASE_ADDR,
.size = BIGSUR_LSR0_SIZE,
@@ -58,7 +55,7 @@ static struct sh7751_pci_address_map sh7751_pci_map = {
};
/*
- * Initialize the Big Sur PCI interface
+ * Initialize the Big Sur PCI interface
* Setup hardware to be Central Funtion
* Copy the BSR regs to the PCI interface
* Setup PCI windows into local RAM
@@ -68,15 +65,15 @@ int __init pcibios_init_platform(void)
return sh7751_pcic_init(&sh7751_pci_map);
}
-int pcibios_map_platform_irq(u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
- /*
+ /*
* The Big Sur can be used in a CPCI chassis, but the SH7751 PCI
* interface is on the wrong end of the board so that it can also
* support a V320 CPI interface chip... Therefor the IRQ mapping is
* somewhat use dependent... I'l assume a linear map for now, i.e.
* INTA=slot0,pin0... INTD=slot3,pin0...
- */
+ */
int irq = (slot + pin-1) % 4 + BIGSUR_SH7751_PCI_IRQ_BASE;
PCIDBG(2, "PCI: Mapping Big Sur IRQ for slot %d, pin %c to irq %d\n",
@@ -84,4 +81,3 @@ int pcibios_map_platform_irq(u8 slot, u8 pin)
return irq;
}
-
diff --git a/arch/sh/drivers/pci/ops-dreamcast.c b/arch/sh/drivers/pci/ops-dreamcast.c
index 23d52791917e..381306cf5425 100644
--- a/arch/sh/drivers/pci/ops-dreamcast.c
+++ b/arch/sh/drivers/pci/ops-dreamcast.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/pci/ops-dreamcast.c
+ * arch/sh/drivers/pci/ops-dreamcast.c
*
* PCI operations for the Sega Dreamcast
*
diff --git a/arch/sh/drivers/pci/ops-landisk.c b/arch/sh/drivers/pci/ops-landisk.c
new file mode 100644
index 000000000000..d06030815a96
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-landisk.c
@@ -0,0 +1,67 @@
+/*
+ * arch/sh/drivers/pci/ops-landisk.c
+ *
+ * PCI initialization for the I-O DATA Device, Inc. LANDISK board
+ *
+ * Copyright (C) 2006 kogiidena
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include "pci-sh4.h"
+
+static struct resource sh7751_io_resource = {
+ .name = "SH7751 IO",
+ .start = 0x4000,
+ .end = 0x4000 + SH7751_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sh7751_mem_resource = {
+ .name = "SH7751 mem",
+ .start = SH7751_PCI_MEMORY_BASE,
+ .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+struct pci_channel board_pci_channels[] = {
+ {&sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0x3ff},
+ {NULL, NULL, NULL, 0, 0},
+};
+
+static struct sh4_pci_address_map sh7751_pci_map = {
+ .window0 = {
+ .base = SH7751_CS3_BASE_ADDR,
+ .size = (64 << 20), /* 64MB */
+ },
+
+ .flags = SH4_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+ return sh7751_pcic_init(&sh7751_pci_map);
+}
+
+int pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+ /*
+ * slot0: pin1-4 = irq5,6,7,8
+ * slot1: pin1-4 = irq6,7,8,5
+ * slot2: pin1-4 = irq7,8,5,6
+ * slot3: pin1-4 = irq8,5,6,7
+ */
+ int irq = ((slot + pin - 1) & 0x3) + 5;
+
+ if ((slot | (pin - 1)) > 0x3) {
+ printk("PCI: Bad IRQ mapping request for slot %d pin %c\n",
+ slot, pin - 1 + 'A');
+ return -1;
+ }
+ return irq;
+}
diff --git a/arch/sh/drivers/pci/ops-r7780rp.c b/arch/sh/drivers/pci/ops-r7780rp.c
new file mode 100644
index 000000000000..6e3ba9c65b40
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-r7780rp.c
@@ -0,0 +1,73 @@
+/*
+ * Author: Ian DaSilva (idasilva@mvista.com)
+ *
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * PCI initialization for the Renesas SH7780 Highlander R7780RP-1 board
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <asm/r7780rp/r7780rp.h>
+#include <asm/io.h>
+#include "pci-sh4.h"
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+ switch (slot) {
+ case 0: return IRQ_PCISLOT1; /* PCI Interrupt #1 */
+ case 1: return IRQ_PCISLOT2; /* PCI Interrupt #2 */
+ case 2: return IRQ_PCISLOT3; /* PCI Interrupt #3 */
+ case 3: return IRQ_PCISLOT4; /* PCI Interrupt E4 */
+ default:
+ printk(KERN_ERR "PCI: Bad IRQ mapping "
+ "request for slot %d, func %d\n", slot, pin-1);
+ return -1;
+ }
+}
+
+static struct resource sh7780_io_resource = {
+ .name = "SH7780_IO",
+ .start = 0x2000,
+ .end = 0x2000 + SH7780_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sh7780_mem_resource = {
+ .name = "SH7780_mem",
+ .start = SH7780_PCI_MEMORY_BASE,
+ .end = SH7780_PCI_MEMORY_BASE + SH7780_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+extern struct pci_ops sh7780_pci_ops;
+
+struct pci_channel board_pci_channels[] = {
+ { &sh4_pci_ops, &sh7780_io_resource, &sh7780_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+EXPORT_SYMBOL(board_pci_channels);
+
+static struct sh4_pci_address_map sh7780_pci_map = {
+ .window0 = {
+ .base = SH7780_CS2_BASE_ADDR,
+ .size = 0x04000000,
+ },
+
+ .window1 = {
+ .base = SH7780_CS3_BASE_ADDR,
+ .size = 0x04000000,
+ },
+
+ .flags = SH4_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+ return sh7780_pcic_init(&sh7780_pci_map);
+}
diff --git a/arch/sh/drivers/pci/ops-rts7751r2d.c b/arch/sh/drivers/pci/ops-rts7751r2d.c
index 83171d10141a..b68824c8b81e 100644
--- a/arch/sh/drivers/pci/ops-rts7751r2d.c
+++ b/arch/sh/drivers/pci/ops-rts7751r2d.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sh/kernel/pci-rts7751r2d.c
+ * linux/arch/sh/drivers/pci/ops-rts7751r2d.c
*
* Author: Ian DaSilva (idasilva@mvista.com)
*
@@ -17,12 +17,11 @@
#include <linux/delay.h>
#include <linux/pci.h>
#include <linux/module.h>
-
-#include <asm/io.h>
-#include "pci-sh7751.h"
#include <asm/rts7751r2d/rts7751r2d.h>
+#include <asm/io.h>
+#include "pci-sh4.h"
-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
switch (slot) {
case 0: return IRQ_PCISLOT1; /* PCI Extend slot #1 */
@@ -52,12 +51,12 @@ static struct resource sh7751_mem_resource = {
extern struct pci_ops sh7751_pci_ops;
struct pci_channel board_pci_channels[] = {
- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
{ NULL, NULL, NULL, 0, 0 },
};
EXPORT_SYMBOL(board_pci_channels);
-static struct sh7751_pci_address_map sh7751_pci_map = {
+static struct sh4_pci_address_map sh7751_pci_map = {
.window0 = {
.base = SH7751_CS3_BASE_ADDR,
.size = 0x04000000,
@@ -68,7 +67,7 @@ static struct sh7751_pci_address_map sh7751_pci_map = {
.size = 0x00000000, /* Unused */
},
- .flags = SH7751_PCIC_NO_RESET,
+ .flags = SH4_PCIC_NO_RESET,
};
int __init pcibios_init_platform(void)
diff --git a/arch/sh/drivers/pci/ops-sh03.c b/arch/sh/drivers/pci/ops-sh03.c
index e58d556e5f94..ebb58e605d9d 100644
--- a/arch/sh/drivers/pci/ops-sh03.c
+++ b/arch/sh/drivers/pci/ops-sh03.c
@@ -35,10 +35,10 @@ static struct resource sh7751_mem_resource = {
.flags = IORESOURCE_MEM
};
-extern struct pci_ops sh7751_pci_ops;
+extern struct pci_ops sh4_pci_ops;
struct pci_channel board_pci_channels[] = {
- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
{ NULL, NULL, NULL, 0, 0 },
};
diff --git a/arch/sh/drivers/pci/ops-sh4.c b/arch/sh/drivers/pci/ops-sh4.c
new file mode 100644
index 000000000000..2d4371009a5e
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-sh4.c
@@ -0,0 +1,164 @@
+/*
+ * Generic SH-4 / SH-4A PCIC operations (SH7751, SH7780).
+ *
+ * Copyright (C) 2002 - 2006 Paul Mundt
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License v2. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/pci.h>
+#include <asm/addrspace.h>
+#include <asm/io.h>
+#include "pci-sh4.h"
+
+/*
+ * Direct access to PCI hardware...
+ */
+#define CONFIG_CMD(bus, devfn, where) \
+ P1SEGADDR((bus->number << 16) | (devfn << 8) | (where & ~3))
+
+static DEFINE_SPINLOCK(sh4_pci_lock);
+
+/*
+ * Functions for accessing PCI configuration space with type 1 accesses
+ */
+static int sh4_pci_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ unsigned long flags;
+ u32 data;
+
+ /*
+ * PCIPDR may only be accessed as 32 bit words,
+ * so we must do byte alignment by hand
+ */
+ spin_lock_irqsave(&sh4_pci_lock, flags);
+ pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
+ data = pci_read_reg(SH4_PCIPDR);
+ spin_unlock_irqrestore(&sh4_pci_lock, flags);
+
+ switch (size) {
+ case 1:
+ *val = (data >> ((where & 3) << 3)) & 0xff;
+ break;
+ case 2:
+ *val = (data >> ((where & 2) << 3)) & 0xffff;
+ break;
+ case 4:
+ *val = data;
+ break;
+ default:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ }
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+/*
+ * Since SH4 only does 32bit access we'll have to do a read,
+ * mask,write operation.
+ * We'll allow an odd byte offset, though it should be illegal.
+ */
+static int sh4_pci_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ unsigned long flags;
+ int shift;
+ u32 data;
+
+ spin_lock_irqsave(&sh4_pci_lock, flags);
+ pci_write_reg(CONFIG_CMD(bus, devfn, where), SH4_PCIPAR);
+ data = pci_read_reg(SH4_PCIPDR);
+ spin_unlock_irqrestore(&sh4_pci_lock, flags);
+
+ switch (size) {
+ case 1:
+ shift = (where & 3) << 3;
+ data &= ~(0xff << shift);
+ data |= ((val & 0xff) << shift);
+ break;
+ case 2:
+ shift = (where & 2) << 3;
+ data &= ~(0xffff << shift);
+ data |= ((val & 0xffff) << shift);
+ break;
+ case 4:
+ data = val;
+ break;
+ default:
+ return PCIBIOS_FUNC_NOT_SUPPORTED;
+ }
+
+ pci_write_reg(data, SH4_PCIPDR);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+
+struct pci_ops sh4_pci_ops = {
+ .read = sh4_pci_read,
+ .write = sh4_pci_write,
+};
+
+/*
+ * Not really related to pci_ops, but it's common and not worth shoving
+ * somewhere else for now..
+ */
+static unsigned int pci_probe = PCI_PROBE_CONF1;
+
+int __init sh4_pci_check_direct(void)
+{
+ /*
+ * Check if configuration works.
+ */
+ if (pci_probe & PCI_PROBE_CONF1) {
+ unsigned int tmp = pci_read_reg(SH4_PCIPAR);
+
+ pci_write_reg(P1SEG, SH4_PCIPAR);
+
+ if (pci_read_reg(SH4_PCIPAR) == P1SEG) {
+ pci_write_reg(tmp, SH4_PCIPAR);
+ printk(KERN_INFO "PCI: Using configuration type 1\n");
+ request_region(PCI_REG(SH4_PCIPAR), 8, "PCI conf1");
+
+ return 0;
+ }
+
+ pci_write_reg(tmp, SH4_PCIPAR);
+ }
+
+ pr_debug("PCI: pci_check_direct failed\n");
+ return -EINVAL;
+}
+
+/* Handle generic fixups */
+static void __init pci_fixup_ide_bases(struct pci_dev *d)
+{
+ int i;
+
+ /*
+ * PCI IDE controllers use non-standard I/O port decoding, respect it.
+ */
+ if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
+ return;
+ pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d));
+ for(i = 0; i < 4; i++) {
+ struct resource *r = &d->resource[i];
+
+ if ((r->start & ~0x80) == 0x374) {
+ r->start |= 2;
+ r->end = r->start;
+ }
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
+
+char * __init pcibios_setup(char *str)
+{
+ if (!strcmp(str, "off")) {
+ pci_probe = 0;
+ return NULL;
+ }
+
+ return str;
+}
diff --git a/arch/sh/drivers/pci/ops-snapgear.c b/arch/sh/drivers/pci/ops-snapgear.c
index 3cbd14dd28fe..53dd893d4e54 100644
--- a/arch/sh/drivers/pci/ops-snapgear.c
+++ b/arch/sh/drivers/pci/ops-snapgear.c
@@ -2,7 +2,7 @@
* arch/sh/drivers/pci/ops-snapgear.c
*
* Author: David McCullough <davidm@snapgear.com>
- *
+ *
* Ported to new API by Paul Mundt <lethal@linux-sh.org>
*
* Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
@@ -12,15 +12,11 @@
*
* PCI initialization for the SnapGear boards
*/
-
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/pci.h>
-
-#include <asm/io.h>
-#include "pci-sh7751.h"
+#include "pci-sh4.h"
#define SNAPGEAR_PCI_IO 0x4000
#define SNAPGEAR_PCI_MEM 0xfd000000
@@ -43,14 +39,12 @@ static struct resource sh7751_mem_resource = {
.flags = IORESOURCE_MEM,
};
-extern struct pci_ops sh7751_pci_ops;
-
struct pci_channel board_pci_channels[] = {
- { &sh7751_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
{ 0, }
};
-static struct sh7751_pci_address_map sh7751_pci_map = {
+static struct sh4_pci_address_map sh7751_pci_map = {
.window0 = {
.base = SH7751_CS2_BASE_ADDR,
.size = SNAPGEAR_LSR0_SIZE,
@@ -61,11 +55,11 @@ static struct sh7751_pci_address_map sh7751_pci_map = {
.size = SNAPGEAR_LSR1_SIZE,
},
- .flags = SH7751_PCIC_NO_RESET,
+ .flags = SH4_PCIC_NO_RESET,
};
/*
- * Initialize the SnapGear PCI interface
+ * Initialize the SnapGear PCI interface
* Setup hardware to be Central Funtion
* Copy the BSR regs to the PCI interface
* Setup PCI windows into local RAM
@@ -75,7 +69,7 @@ int __init pcibios_init_platform(void)
return sh7751_pcic_init(&sh7751_pci_map);
}
-int __init pcibios_map_platform_irq(u8 slot, u8 pin)
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
{
int irq = -1;
@@ -98,4 +92,3 @@ void __init pcibios_fixup(void)
{
/* Nothing to fixup .. */
}
-
diff --git a/arch/sh/drivers/pci/ops-titan.c b/arch/sh/drivers/pci/ops-titan.c
new file mode 100644
index 000000000000..cd56d53375e7
--- /dev/null
+++ b/arch/sh/drivers/pci/ops-titan.c
@@ -0,0 +1,81 @@
+/*
+ * arch/sh/drivers/pci/ops-titan.c
+ *
+ * Ported to new API by Paul Mundt <lethal@linux-sh.org>
+ *
+ * Modified from ops-snapgear.c written by David McCullough
+ * Highly leveraged from pci-bigsur.c, written by Dustin McIntire.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ * PCI initialization for the Titan boards
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/titan.h>
+#include "pci-sh4.h"
+
+int __init pcibios_map_platform_irq(struct pci_dev *pdev, u8 slot, u8 pin)
+{
+ int irq = -1;
+
+ switch (slot) {
+ case 0: irq = TITAN_IRQ_WAN; break; /* eth0 (WAN) */
+ case 1: irq = TITAN_IRQ_LAN; break; /* eth1 (LAN) */
+ case 2: irq = TITAN_IRQ_MPCIA; break; /* mPCI A */
+ case 3: irq = TITAN_IRQ_MPCIB; break; /* mPCI B */
+ case 4: irq = TITAN_IRQ_USB; break; /* USB */
+ default:
+ printk(KERN_INFO "PCI: Bad IRQ mapping "
+ "request for slot %d\n", slot);
+ return -1;
+ }
+
+ printk("PCI: Mapping TITAN IRQ for slot %d, pin %c to irq %d\n",
+ slot, pin - 1 + 'A', irq);
+
+ return irq;
+}
+
+static struct resource sh7751_io_resource = {
+ .name = "SH7751_IO",
+ .start = SH7751_PCI_IO_BASE,
+ .end = SH7751_PCI_IO_BASE + SH7751_PCI_IO_SIZE - 1,
+ .flags = IORESOURCE_IO
+};
+
+static struct resource sh7751_mem_resource = {
+ .name = "SH7751_mem",
+ .start = SH7751_PCI_MEMORY_BASE,
+ .end = SH7751_PCI_MEMORY_BASE + SH7751_PCI_MEM_SIZE - 1,
+ .flags = IORESOURCE_MEM
+};
+
+struct pci_channel board_pci_channels[] = {
+ { &sh4_pci_ops, &sh7751_io_resource, &sh7751_mem_resource, 0, 0xff },
+ { NULL, NULL, NULL, 0, 0 },
+};
+EXPORT_SYMBOL(board_pci_channels);
+
+static struct sh4_pci_address_map sh7751_pci_map = {
+ .window0 = {
+ .base = SH7751_CS2_BASE_ADDR,
+ .size = SH7751_MEM_REGION_SIZE*2, /* cs2 and cs3 */
+ },
+
+ .window1 = {
+ .base = SH7751_CS2_BASE_ADDR,
+ .size = SH7751_MEM_REGION_SIZE*2,
+ },
+
+ .flags = SH4_PCIC_NO_RESET,
+};
+
+int __init pcibios_init_platform(void)
+{
+ return sh7751_pcic_init(&sh7751_pci_map);
+}
diff --git a/arch/sh/drivers/pci/pci-auto.c b/arch/sh/drivers/pci/pci-auto.c
index 4cef4d1d8c84..ecf16344f94a 100644
--- a/arch/sh/drivers/pci/pci-auto.c
+++ b/arch/sh/drivers/pci/pci-auto.c
@@ -45,11 +45,11 @@
#include <linux/types.h>
#include <linux/pci.h>
-#undef DEBUG
-#ifdef DEBUG
+#define DEBUG
+#ifdef DEBUG
#define DBG(x...) printk(x)
#else
-#define DBG(x...)
+#define DBG(x...)
#endif
/*
@@ -102,7 +102,7 @@ static u32 pciauto_upper_iospc;
static u32 pciauto_lower_memspc;
static u32 pciauto_upper_memspc;
-static void __init
+static void __init
pciauto_setup_bars(struct pci_channel *hose,
int top_bus,
int current_bus,
@@ -116,7 +116,6 @@ pciauto_setup_bars(struct pci_channel *hose,
int found_mem64 = 0;
for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
u32 bar_addr;
/* Read the old BAR value */
@@ -125,7 +124,6 @@ pciauto_setup_bars(struct pci_channel *hose,
pci_devfn,
bar,
&bar_addr);
-#endif
/* Tickle the BAR and get the response */
early_write_config_dword(hose, top_bus,
@@ -140,8 +138,7 @@ pciauto_setup_bars(struct pci_channel *hose,
bar,
&bar_response);
-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
- /*
+ /*
* Write the old BAR value back out, only update the BAR
* if we implicitly want resources to be updated, which
* is done by the generic code further down. -- PFM.
@@ -151,7 +148,6 @@ pciauto_setup_bars(struct pci_channel *hose,
pci_devfn,
bar,
bar_addr);
-#endif
/* If BAR is not implemented go to the next BAR */
if (!bar_response)
@@ -177,7 +173,7 @@ retry:
PCI_BASE_ADDRESS_MEM_TYPE_64)
found_mem64 = 1;
- addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
+ addr_mask = PCI_BASE_ADDRESS_MEM_MASK;
upper_limit = &pciauto_upper_memspc;
lower_limit = &pciauto_lower_memspc;
DBG(" Mem");
@@ -193,22 +189,22 @@ retry:
if ((bar_value + bar_size) > *upper_limit) {
if (bar_response & PCI_BASE_ADDRESS_SPACE) {
if (io_resource_inuse->child) {
- io_resource_inuse =
+ io_resource_inuse =
io_resource_inuse->child;
- pciauto_lower_iospc =
+ pciauto_lower_iospc =
io_resource_inuse->start;
- pciauto_upper_iospc =
+ pciauto_upper_iospc =
io_resource_inuse->end + 1;
goto retry;
}
} else {
if (mem_resource_inuse->child) {
- mem_resource_inuse =
+ mem_resource_inuse =
mem_resource_inuse->child;
- pciauto_lower_memspc =
+ pciauto_lower_memspc =
mem_resource_inuse->start;
- pciauto_upper_memspc =
+ pciauto_upper_memspc =
mem_resource_inuse->end + 1;
goto retry;
}
@@ -230,7 +226,7 @@ retry:
* If we are a 64-bit decoder then increment to the
* upper 32 bits of the bar and force it to locate
* in the lower 4GB of memory.
- */
+ */
if (found_mem64) {
bar += 4;
early_write_config_dword(hose, top_bus,
@@ -362,7 +358,6 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose,
{
u32 temp;
-#if !defined(CONFIG_SH_HS7751RVOIP) && !defined(CONFIG_SH_RTS7751R2D)
/*
* [jsun] we always bump up baselines a little, so that if there
* nothing behind P2P bridge, we don't wind up overlapping IO/MEM
@@ -370,7 +365,6 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose,
*/
pciauto_lower_memspc += 1;
pciauto_lower_iospc += 1;
-#endif
/*
* Configure subordinate bus number. The PCI subsystem
@@ -396,11 +390,6 @@ pciauto_postscan_setup_cardbus_bridge(struct pci_channel *hose,
* configured by this routine to happily live behind a
* P2P bridge in a system.
*/
-#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
- pciauto_lower_memspc += 0x00400000;
- pciauto_lower_iospc += 0x00004000;
-#endif
-
/* Align memory and I/O to 4KB and 4 byte boundaries. */
pciauto_lower_memspc = (pciauto_lower_memspc + (0x1000 - 1))
& ~(0x1000 - 1);
@@ -433,12 +422,12 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
int devfn_stop = 0xff;
sub_bus = current_bus;
-
+
if (hose->first_devfn)
devfn_start = hose->first_devfn;
if (hose->last_devfn)
devfn_stop = hose->last_devfn;
-
+
for (pci_devfn=devfn_start; pci_devfn<devfn_stop; pci_devfn++) {
if (PCI_FUNC(pci_devfn) && !found_multi)
@@ -471,9 +460,6 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
DBG(" Bridge: primary=%.2x, secondary=%.2x\n",
current_bus, sub_bus + 1);
-#if defined(CONFIG_SH_HS7751RVOIP) || defined(CONFIG_SH_RTS7751R2D)
- pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_1);
-#endif
pciauto_prescan_setup_bridge(hose, top_bus, current_bus,
pci_devfn, sub_bus);
DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
@@ -490,10 +476,10 @@ pciauto_bus_scan(struct pci_channel *hose, int top_bus, int current_bus)
DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
/* Place CardBus Socket/ExCA registers */
pciauto_setup_bars(hose, top_bus, current_bus, pci_devfn, PCI_BASE_ADDRESS_0);
-
+
pciauto_prescan_setup_cardbus_bridge(hose, top_bus,
current_bus, pci_devfn, sub_bus);
-
+
DBG("Scanning sub bus %.2x, I/O 0x%.8x, Mem 0x%.8x\n",
sub_bus + 1,
pciauto_lower_iospc, pciauto_lower_memspc);
diff --git a/arch/sh/drivers/pci/pci-sh4.h b/arch/sh/drivers/pci/pci-sh4.h
new file mode 100644
index 000000000000..5a61d6041f2c
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-sh4.h
@@ -0,0 +1,180 @@
+#ifndef __PCI_SH4_H
+#define __PCI_SH4_H
+
+#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#include "pci-sh7780.h"
+#else
+#include "pci-sh7751.h"
+#endif
+
+#include <asm/io.h>
+
+/* startup values */
+#define PCI_PROBE_BIOS 1
+#define PCI_PROBE_CONF1 2
+#define PCI_PROBE_CONF2 4
+#define PCI_NO_SORT 0x100
+#define PCI_BIOS_SORT 0x200
+#define PCI_NO_CHECKS 0x400
+#define PCI_ASSIGN_ROMS 0x1000
+#define PCI_BIOS_IRQ_SCAN 0x2000
+
+#define SH4_PCICR 0x100 /* PCI Control Register */
+ #define SH4_PCICR_PREFIX 0xA5000000 /* CR prefix for write */
+ #define SH4_PCICR_FTO 0x00000400 /* TRDY/IRDY Enable */
+ #define SH4_PCICR_TRSB 0x00000200 /* Target Read Single */
+ #define SH4_PCICR_BSWP 0x00000100 /* Target Byte Swap */
+ #define SH4_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */
+ #define SH4_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */
+ #define SH4_PCICR_MD 0x00000030 /* MD9 and MD10 status */
+ #define SH4_PCICR_SERR 0x00000008 /* SERR output assert */
+ #define SH4_PCICR_INTA 0x00000004 /* INTA output assert */
+ #define SH4_PCICR_PRST 0x00000002 /* PCI Reset Assert */
+ #define SH4_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */
+#define SH4_PCILSR0 0x104 /* PCI Local Space Register0 */
+#define SH4_PCILSR1 0x108 /* PCI Local Space Register1 */
+#define SH4_PCILAR0 0x10C /* PCI Local Addr Register1 */
+#define SH4_PCILAR1 0x110 /* PCI Local Addr Register1 */
+#define SH4_PCIINT 0x114 /* PCI Interrupt Register */
+ #define SH4_PCIINT_MLCK 0x00008000 /* Master Lock Error */
+ #define SH4_PCIINT_TABT 0x00004000 /* Target Abort Error */
+ #define SH4_PCIINT_TRET 0x00000200 /* Target Retry Error */
+ #define SH4_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */
+ #define SH4_PCIINT_PRTY 0x00000080 /* Address Parity Error */
+ #define SH4_PCIINT_SERR 0x00000040 /* SERR Detection Error */
+ #define SH4_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */
+ #define SH4_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Err Det. */
+ #define SH4_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */
+ #define SH4_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */
+ #define SH4_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */
+ #define SH4_PCIINT_MRPD 0x00000001 /* Master Read PERR Detect */
+#define SH4_PCIINTM 0x118 /* PCI Interrupt Mask */
+#define SH4_PCIALR 0x11C /* Error Address Register */
+#define SH4_PCICLR 0x120 /* Error Command/Data */
+ #define SH4_PCICLR_MPIO 0x80000000
+ #define SH4_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */
+ #define SH4_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */
+ #define SH4_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */
+ #define SH4_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */
+ #define SH4_PCICLR_TGT 0x04000000 /* Target Transfer Error */
+ #define SH4_PCICLR_CMDL 0x0000000F /* PCI Command at Error */
+#define SH4_PCIAINT 0x130 /* Arbiter Interrupt Register */
+ #define SH4_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */
+ #define SH4_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */
+ #define SH4_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */
+ #define SH4_PCIAINT_TABT 0x00000008 /* Target Abort */
+ #define SH4_PCIAINT_MABT 0x00000004 /* Master Abort */
+ #define SH4_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */
+ #define SH4_PCIAINT_WDPE 0x00000001 /* Write Data Parity Error */
+#define SH4_PCIAINTM 0x134 /* Arbiter Int. Mask Register */
+#define SH4_PCIBMLR 0x138 /* Error Bus Master Register */
+ #define SH4_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */
+ #define SH4_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */
+ #define SH4_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */
+ #define SH4_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */
+ #define SH4_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */
+#define SH4_PCIDMABT 0x140 /* DMA Transfer Arb. Register */
+ #define SH4_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */
+#define SH4_PCIDPA0 0x180 /* DMA0 Transfer Addr. */
+#define SH4_PCIDLA0 0x184 /* DMA0 Local Addr. */
+#define SH4_PCIDTC0 0x188 /* DMA0 Transfer Cnt. */
+#define SH4_PCIDCR0 0x18C /* DMA0 Control Register */
+ #define SH4_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */
+ #define SH4_PCIDCR_MAST 0x00000100 /* DMA Termination Type */
+ #define SH4_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/
+ #define SH4_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */
+ #define SH4_PCIDCR_LHLD 0x00000020 /* Local Address Control */
+ #define SH4_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/
+ #define SH4_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */
+ #define SH4_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */
+ #define SH4_PCIDCR_STOP 0x00000002 /* Force DMA Stop */
+ #define SH4_PCIDCR_STRT 0x00000001 /* DMA Start */
+#define SH4_PCIDPA1 0x190 /* DMA1 Transfer Addr. */
+#define SH4_PCIDLA1 0x194 /* DMA1 Local Addr. */
+#define SH4_PCIDTC1 0x198 /* DMA1 Transfer Cnt. */
+#define SH4_PCIDCR1 0x19C /* DMA1 Control Register */
+#define SH4_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. */
+#define SH4_PCIDLA2 0x1A4 /* DMA2 Local Addr. */
+#define SH4_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. */
+#define SH4_PCIDCR2 0x1AC /* DMA2 Control Register */
+#define SH4_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. */
+#define SH4_PCIDLA3 0x1B4 /* DMA3 Local Addr. */
+#define SH4_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. */
+#define SH4_PCIDCR3 0x1BC /* DMA3 Control Register */
+#define SH4_PCIPAR 0x1C0 /* PIO Address Register */
+ #define SH4_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */
+ #define SH4_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */
+ #define SH4_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */
+ #define SH4_PCIPAR_REGAD 0x000000FC /* Register Address Number */
+#define SH4_PCIMBR 0x1C4 /* Memory Base Address */
+ #define SH4_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */
+ #define SH4_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */
+#define SH4_PCIIOBR 0x1C8 /* I/O Base Address Register */
+ #define SH4_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */
+ #define SH4_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */
+#define SH4_PCIPINT 0x1CC /* Power Mgmnt Int. Register */
+ #define SH4_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */
+ #define SH4_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */
+#define SH4_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */
+#define SH4_PCICLKR 0x1D4 /* Clock Ctrl. Register */
+ #define SH4_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */
+ #define SH4_PCICLKR_BCSTP 0x00000001 /* BCLK Clock Stop */
+/* For definitions of BCR, MCR see ... */
+#define SH4_PCIBCR1 0x1E0 /* Memory BCR1 Register */
+ #define SH4_PCIMBR0 SH4_PCIBCR1
+#define SH4_PCIBCR2 0x1E4 /* Memory BCR2 Register */
+ #define SH4_PCIMBMR0 SH4_PCIBCR2
+#define SH4_PCIWCR1 0x1E8 /* Wait Control 1 Register */
+#define SH4_PCIWCR2 0x1EC /* Wait Control 2 Register */
+#define SH4_PCIWCR3 0x1F0 /* Wait Control 3 Register */
+ #define SH4_PCIMBR2 SH4_PCIWCR3
+#define SH4_PCIMCR 0x1F4 /* Memory Control Register */
+#define SH4_PCIBCR3 0x1f8 /* Memory BCR3 Register */
+#define SH4_PCIPCTR 0x200 /* Port Control Register */
+ #define SH4_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */
+ #define SH4_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */
+ #define SH4_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */
+ #define SH4_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */
+ #define SH4_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */
+ #define SH4_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */
+ #define SH4_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */
+ #define SH4_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */
+ #define SH4_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */
+#define SH4_PCIPDTR 0x204 /* Port Data Register */
+ #define SH4_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */
+ #define SH4_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */
+ #define SH4_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */
+ #define SH4_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */
+ #define SH4_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */
+ #define SH4_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */
+#define SH4_PCIPDR 0x220 /* Port IO Data Register */
+
+/* Flags */
+#define SH4_PCIC_NO_RESET 0x0001
+
+/* arch/sh/kernel/drivers/pci/ops-sh4.c */
+extern struct pci_ops sh4_pci_ops;
+int sh4_pci_check_direct(void);
+int pci_fixup_pcic(void);
+
+struct sh4_pci_address_space {
+ unsigned long base;
+ unsigned long size;
+};
+
+struct sh4_pci_address_map {
+ struct sh4_pci_address_space window0;
+ struct sh4_pci_address_space window1;
+ unsigned long flags;
+};
+
+static inline void pci_write_reg(unsigned long val, unsigned long reg)
+{
+ outl(val, PCI_REG(reg));
+}
+
+static inline unsigned long pci_read_reg(unsigned long reg)
+{
+ return inl(PCI_REG(reg));
+}
+#endif /* __PCI_SH4_H */
diff --git a/arch/sh/drivers/pci/pci-sh7751.c b/arch/sh/drivers/pci/pci-sh7751.c
index 682f3dae305d..85e1ee2e2e7b 100644
--- a/arch/sh/drivers/pci/pci-sh7751.c
+++ b/arch/sh/drivers/pci/pci-sh7751.c
@@ -15,180 +15,14 @@
#undef DEBUG
-#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
+#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/irq.h>
#include <linux/delay.h>
-
-#include <asm/machvec.h>
+#include "pci-sh4.h"
+#include <asm/addrspace.h>
#include <asm/io.h>
-#include "pci-sh7751.h"
-
-static unsigned int pci_probe = PCI_PROBE_CONF1;
-extern int pci_fixup_pcic(void);
-
-void pcibios_fixup_irqs(void) __attribute__ ((weak));
-
-/*
- * Direct access to PCI hardware...
- */
-
-#define CONFIG_CMD(bus, devfn, where) (0x80000000 | (bus->number << 16) | (devfn << 8) | (where & ~3))
-
-/*
- * Functions for accessing PCI configuration space with type 1 accesses
- */
-static int sh7751_pci_read(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *val)
-{
- unsigned long flags;
- u32 data;
-
- /*
- * PCIPDR may only be accessed as 32 bit words,
- * so we must do byte alignment by hand
- */
- local_irq_save(flags);
- outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
- data = inl(PCI_REG(SH7751_PCIPDR));
- local_irq_restore(flags);
-
- switch (size) {
- case 1:
- *val = (data >> ((where & 3) << 3)) & 0xff;
- break;
- case 2:
- *val = (data >> ((where & 2) << 3)) & 0xffff;
- break;
- case 4:
- *val = data;
- break;
- default:
- return PCIBIOS_FUNC_NOT_SUPPORTED;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-/*
- * Since SH7751 only does 32bit access we'll have to do a read,
- * mask,write operation.
- * We'll allow an odd byte offset, though it should be illegal.
- */
-static int sh7751_pci_write(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 val)
-{
- unsigned long flags;
- int shift;
- u32 data;
-
- local_irq_save(flags);
- outl(CONFIG_CMD(bus,devfn,where), PCI_REG(SH7751_PCIPAR));
- data = inl(PCI_REG(SH7751_PCIPDR));
- local_irq_restore(flags);
-
- switch (size) {
- case 1:
- shift = (where & 3) << 3;
- data &= ~(0xff << shift);
- data |= ((val & 0xff) << shift);
- break;
- case 2:
- shift = (where & 2) << 3;
- data &= ~(0xffff << shift);
- data |= ((val & 0xffff) << shift);
- break;
- case 4:
- data = val;
- break;
- default:
- return PCIBIOS_FUNC_NOT_SUPPORTED;
- }
-
- outl(data, PCI_REG(SH7751_PCIPDR));
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-#undef CONFIG_CMD
-
-struct pci_ops sh7751_pci_ops = {
- .read = sh7751_pci_read,
- .write = sh7751_pci_write,
-};
-
-static int __init pci_check_direct(void)
-{
- unsigned int tmp, id;
-
- /* check for SH7751/SH7751R hardware */
- id = inl(SH7751_PCIREG_BASE+SH7751_PCICONF0);
- if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
- id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
- pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
- return -ENODEV;
- }
-
- /*
- * Check if configuration works.
- */
- if (pci_probe & PCI_PROBE_CONF1) {
- tmp = inl (PCI_REG(SH7751_PCIPAR));
- outl (0x80000000, PCI_REG(SH7751_PCIPAR));
- if (inl (PCI_REG(SH7751_PCIPAR)) == 0x80000000) {
- outl (tmp, PCI_REG(SH7751_PCIPAR));
- printk(KERN_INFO "PCI: Using configuration type 1\n");
- request_region(PCI_REG(SH7751_PCIPAR), 8, "PCI conf1");
- return 0;
- }
- outl (tmp, PCI_REG(SH7751_PCIPAR));
- }
-
- pr_debug("PCI: pci_check_direct failed\n");
- return -EINVAL;
-}
-
-/***************************************************************************************/
-
-/*
- * Handle bus scanning and fixups ....
- */
-
-static void __init pci_fixup_ide_bases(struct pci_dev *d)
-{
- int i;
-
- /*
- * PCI IDE controllers use non-standard I/O port decoding, respect it.
- */
- if ((d->class >> 8) != PCI_CLASS_STORAGE_IDE)
- return;
- pr_debug("PCI: IDE base address fixup for %s\n", pci_name(d));
- for(i=0; i<4; i++) {
- struct resource *r = &d->resource[i];
- if ((r->start & ~0x80) == 0x374) {
- r->start |= 2;
- r->end = r->start;
- }
- }
-}
-
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pci_fixup_ide_bases);
-
-/*
- * Called after each bus is probed, but before its children
- * are examined.
- */
-
-void __init pcibios_fixup_bus(struct pci_bus *b)
-{
- pci_read_bridge_bases(b);
-}
/*
* Initialization. Try all known PCI access methods. Note that we support
@@ -196,25 +30,29 @@ void __init pcibios_fixup_bus(struct pci_bus *b)
* to access config space.
*
* Note that the platform specific initialization (BSC registers, and memory
- * space mapping) will be called via the machine vectors (sh_mv.mv_pci_init()) if it
- * exitst and via the platform defined function pcibios_init_platform().
- * See pci_bigsur.c for implementation;
- *
- * The BIOS version of the pci functions is not yet implemented but it is left
- * in for completeness. Currently an error will be genereated at compile time.
+ * space mapping) will be called via the platform defined function
+ * pcibios_init_platform().
*/
-
static int __init sh7751_pci_init(void)
{
+ unsigned int id;
int ret;
pr_debug("PCI: Starting intialization.\n");
- if ((ret = pci_check_direct()) != 0)
+
+ /* check for SH7751/SH7751R hardware */
+ id = pci_read_reg(SH7751_PCICONF0);
+ if (id != ((SH7751_DEVICE_ID << 16) | SH7751_VENDOR_ID) &&
+ id != ((SH7751R_DEVICE_ID << 16) | SH7751_VENDOR_ID)) {
+ pr_debug("PCI: This is not an SH7751(R) (%x)\n", id);
+ return -ENODEV;
+ }
+
+ if ((ret = sh4_pci_check_direct()) != 0)
return ret;
return pcibios_init_platform();
}
-
subsys_initcall(sh7751_pci_init);
static int __init __area_sdram_check(unsigned int area)
@@ -223,26 +61,26 @@ static int __init __area_sdram_check(unsigned int area)
word = inl(SH7751_BCR1);
/* check BCR for SDRAM in area */
- if(((word >> area) & 1) == 0) {
+ if (((word >> area) & 1) == 0) {
printk("PCI: Area %d is not configured for SDRAM. BCR1=0x%x\n",
area, word);
return 0;
}
- outl(word, PCI_REG(SH7751_PCIBCR1));
+ pci_write_reg(word, SH4_PCIBCR1);
word = (u16)inw(SH7751_BCR2);
/* check BCR2 for 32bit SDRAM interface*/
- if(((word >> (area << 1)) & 0x3) != 0x3) {
+ if (((word >> (area << 1)) & 0x3) != 0x3) {
printk("PCI: Area %d is not 32 bit SDRAM. BCR2=0x%x\n",
area, word);
return 0;
}
- outl(word, PCI_REG(SH7751_PCIBCR2));
+ pci_write_reg(word, SH4_PCIBCR2);
return 1;
}
-int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
+int __init sh7751_pcic_init(struct sh4_pci_address_map *map)
{
u32 reg;
u32 word;
@@ -251,39 +89,39 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
reg = inl(SH7751_BCR1);
reg |= 0x80000;
outl(reg, SH7751_BCR1);
-
+
/* Turn the clocks back on (not done in reset)*/
- outl(0, PCI_REG(SH7751_PCICLKR));
+ pci_write_reg(0, SH4_PCICLKR);
/* Clear Powerdown IRQ's (not done in reset) */
- word = SH7751_PCIPINT_D3 | SH7751_PCIPINT_D0;
- outl(word, PCI_REG(SH7751_PCIPINT));
+ word = SH4_PCIPINT_D3 | SH4_PCIPINT_D0;
+ pci_write_reg(word, SH4_PCIPINT);
/*
* This code is unused for some boards as it is done in the
* bootloader and doing it here means the MAC addresses loaded
* by the bootloader get lost.
*/
- if (!(map->flags & SH7751_PCIC_NO_RESET)) {
+ if (!(map->flags & SH4_PCIC_NO_RESET)) {
/* toggle PCI reset pin */
- word = SH7751_PCICR_PREFIX | SH7751_PCICR_PRST;
- outl(word,PCI_REG(SH7751_PCICR));
+ word = SH4_PCICR_PREFIX | SH4_PCICR_PRST;
+ pci_write_reg(word, SH4_PCICR);
/* Wait for a long time... not 1 sec. but long enough */
mdelay(100);
- word = SH7751_PCICR_PREFIX;
- outl(word,PCI_REG(SH7751_PCICR));
+ word = SH4_PCICR_PREFIX;
+ pci_write_reg(word, SH4_PCICR);
}
-
+
/* set the command/status bits to:
* Wait Cycle Control + Parity Enable + Bus Master +
* Mem space enable
*/
word = SH7751_PCICONF1_WCC | SH7751_PCICONF1_PER |
SH7751_PCICONF1_BUM | SH7751_PCICONF1_MES;
- outl(word, PCI_REG(SH7751_PCICONF1));
+ pci_write_reg(word, SH7751_PCICONF1);
/* define this host as the host bridge */
- word = SH7751_PCI_HOST_BRIDGE << 24;
- outl(word, PCI_REG(SH7751_PCICONF2));
+ word = PCI_BASE_CLASS_BRIDGE << 24;
+ pci_write_reg(word, SH7751_PCICONF2);
/* Set IO and Mem windows to local address
* Make PCI and local address the same for easy 1 to 1 mapping
@@ -291,46 +129,49 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
* Window1 = map->window1.size @ cached area base = SDRAM
*/
word = map->window0.size - 1;
- outl(word, PCI_REG(SH7751_PCILSR0));
+ pci_write_reg(word, SH4_PCILSR0);
word = map->window1.size - 1;
- outl(word, PCI_REG(SH7751_PCILSR1));
+ pci_write_reg(word, SH4_PCILSR1);
/* Set the values on window 0 PCI config registers */
word = P2SEGADDR(map->window0.base);
- outl(word, PCI_REG(SH7751_PCILAR0));
- outl(word, PCI_REG(SH7751_PCICONF5));
+ pci_write_reg(word, SH4_PCILAR0);
+ pci_write_reg(word, SH7751_PCICONF5);
/* Set the values on window 1 PCI config registers */
word = PHYSADDR(map->window1.base);
- outl(word, PCI_REG(SH7751_PCILAR1));
- outl(word, PCI_REG(SH7751_PCICONF6));
+ pci_write_reg(word, SH4_PCILAR1);
+ pci_write_reg(word, SH7751_PCICONF6);
- /* Set the local 16MB PCI memory space window to
+ /* Set the local 16MB PCI memory space window to
* the lowest PCI mapped address
*/
- word = PCIBIOS_MIN_MEM & SH7751_PCIMBR_MASK;
- PCIDBG(2,"PCI: Setting upper bits of Memory window to 0x%x\n", word);
- outl(word , PCI_REG(SH7751_PCIMBR));
+ word = PCIBIOS_MIN_MEM & SH4_PCIMBR_MASK;
+ pr_debug("PCI: Setting upper bits of Memory window to 0x%x\n", word);
+ pci_write_reg(word , SH4_PCIMBR);
/* Map IO space into PCI IO window
* The IO window is 64K-PCIBIOS_MIN_IO in size
- * IO addresses will be translated to the
+ * IO addresses will be translated to the
* PCI IO window base address
*/
- PCIDBG(3,"PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n", PCIBIOS_MIN_IO,
- (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO);
+ pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n",
+ PCIBIOS_MIN_IO, (64 << 10),
+ SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO);
- /*
+ /*
* XXX: For now, leave this board-specific. In the event we have other
* boards that need to do similar work, this can be wrapped.
*/
#ifdef CONFIG_SH_BIGSUR
- bigsur_port_map(PCIBIOS_MIN_IO, (64*1024), SH7751_PCI_IO_BASE+PCIBIOS_MIN_IO,0);
+ bigsur_port_map(PCIBIOS_MIN_IO, (64 << 10),
+ SH7751_PCI_IO_BASE + PCIBIOS_MIN_IO, 0);
#endif
- /* Make sure the MSB's of IO window are set to access PCI space correctly */
- word = PCIBIOS_MIN_IO & SH7751_PCIIOBR_MASK;
- PCIDBG(2,"PCI: Setting upper bits of IO window to 0x%x\n", word);
- outl(word, PCI_REG(SH7751_PCIIOBR));
-
+ /* Make sure the MSB's of IO window are set to access PCI space
+ * correctly */
+ word = PCIBIOS_MIN_IO & SH4_PCIIOBR_MASK;
+ pr_debug("PCI: Setting upper bits of IO window to 0x%x\n", word);
+ pci_write_reg(word, SH4_PCIIOBR);
+
/* Set PCI WCRx, BCRx's, copy from BSC locations */
/* check BCR for SDRAM in specified area */
@@ -349,13 +190,13 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
/* configure the wait control registers */
word = inl(SH7751_WCR1);
- outl(word, PCI_REG(SH7751_PCIWCR1));
+ pci_write_reg(word, SH4_PCIWCR1);
word = inl(SH7751_WCR2);
- outl(word, PCI_REG(SH7751_PCIWCR2));
+ pci_write_reg(word, SH4_PCIWCR2);
word = inl(SH7751_WCR3);
- outl(word, PCI_REG(SH7751_PCIWCR3));
+ pci_write_reg(word, SH4_PCIWCR3);
word = inl(SH7751_MCR);
- outl(word, PCI_REG(SH7751_PCIMCR));
+ pci_write_reg(word, SH4_PCIMCR);
/* NOTE: I'm ignoring the PCI error IRQs for now..
* TODO: add support for the internal error interrupts and
@@ -368,49 +209,8 @@ int __init sh7751_pcic_init(struct sh7751_pci_address_map *map)
/* SH7751 init done, set central function init complete */
/* use round robin mode to stop a device starving/overruning */
- word = SH7751_PCICR_PREFIX | SH7751_PCICR_CFIN | SH7751_PCICR_ARBM;
- outl(word,PCI_REG(SH7751_PCICR));
+ word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_ARBM;
+ pci_write_reg(word, SH4_PCICR);
return 1;
}
-
-char * __init pcibios_setup(char *str)
-{
- if (!strcmp(str, "off")) {
- pci_probe = 0;
- return NULL;
- }
-
- return str;
-}
-
-/*
- * IRQ functions
- */
-static u8 __init sh7751_no_swizzle(struct pci_dev *dev, u8 *pin)
-{
- /* no swizzling */
- return PCI_SLOT(dev->devfn);
-}
-
-static int sh7751_pci_lookup_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
- int irq = -1;
-
- /* now lookup the actual IRQ on a platform specific basis (pci-'platform'.c) */
- irq = pcibios_map_platform_irq(slot,pin);
- if( irq < 0 ) {
- pr_debug("PCI: Error mapping IRQ on device %s\n", pci_name(dev));
- return irq;
- }
-
- pr_debug("Setting IRQ for slot %s to %d\n", pci_name(dev), irq);
-
- return irq;
-}
-
-void __init pcibios_fixup_irqs(void)
-{
- pci_fixup_irqs(sh7751_no_swizzle, sh7751_pci_lookup_irq);
-}
-
diff --git a/arch/sh/drivers/pci/pci-sh7751.h b/arch/sh/drivers/pci/pci-sh7751.h
index 1fee5cae10d1..68e3cb5e6bec 100644
--- a/arch/sh/drivers/pci/pci-sh7751.h
+++ b/arch/sh/drivers/pci/pci-sh7751.h
@@ -3,7 +3,7 @@
*
* Dustin McIntire (dustin@sensoria.com) (c) 2001
* Paul Mundt (lethal@linux-sh.org) (c) 2003
- *
+ *
* May be copied or modified under the terms of the GNU General Public
* License. See linux/COPYING for more information.
*
@@ -12,28 +12,6 @@
#ifndef _PCI_SH7751_H_
#define _PCI_SH7751_H_
-#include <linux/pci.h>
-
-/* set debug level 4=verbose...1=terse */
-//#define DEBUG_PCI 3
-#undef DEBUG_PCI
-
-#ifdef DEBUG_PCI
-#define PCIDBG(n, x...) { if(DEBUG_PCI>=n) printk(x); }
-#else
-#define PCIDBG(n, x...)
-#endif
-
-/* startup values */
-#define PCI_PROBE_BIOS 1
-#define PCI_PROBE_CONF1 2
-#define PCI_PROBE_CONF2 4
-#define PCI_NO_SORT 0x100
-#define PCI_BIOS_SORT 0x200
-#define PCI_NO_CHECKS 0x400
-#define PCI_ASSIGN_ROMS 0x1000
-#define PCI_BIOS_IRQ_SCAN 0x2000
-
/* Platform Specific Values */
#define SH7751_VENDOR_ID 0x1054
#define SH7751_DEVICE_ID 0x3505
@@ -128,131 +106,6 @@
#define SH7751_PCICONF17_PMEN 0x00010000 /* PME Enable */
#define SH7751_PCICONF17_PWST 0x00000003 /* Power State */
/* SH7715 Internal PCI Registers */
-#define SH7751_PCICR 0x100 /* PCI Control Register */
- #define SH7751_PCICR_PREFIX 0xA5000000 /* CR prefix for write */
- #define SH7751_PCICR_TRSB 0x00000200 /* Target Read Single */
- #define SH7751_PCICR_BSWP 0x00000100 /* Target Byte Swap */
- #define SH7751_PCICR_PLUP 0x00000080 /* Enable PCI Pullup */
- #define SH7751_PCICR_ARBM 0x00000040 /* PCI Arbitration Mode */
- #define SH7751_PCICR_MD 0x00000030 /* MD9 and MD10 status */
- #define SH7751_PCICR_SERR 0x00000008 /* SERR output assert */
- #define SH7751_PCICR_INTA 0x00000004 /* INTA output assert */
- #define SH7751_PCICR_PRST 0x00000002 /* PCI Reset Assert */
- #define SH7751_PCICR_CFIN 0x00000001 /* Central Fun. Init Done */
-#define SH7751_PCILSR0 0x104 /* PCI Local Space Register0 */
-#define SH7751_PCILSR1 0x108 /* PCI Local Space Register1 */
-#define SH7751_PCILAR0 0x10C /* PCI Local Address Register1 */
-#define SH7751_PCILAR1 0x110 /* PCI Local Address Register1 */
-#define SH7751_PCIINT 0x114 /* PCI Interrupt Register */
- #define SH7751_PCIINT_MLCK 0x00008000 /* Master Lock Error */
- #define SH7751_PCIINT_TABT 0x00004000 /* Target Abort Error */
- #define SH7751_PCIINT_TRET 0x00000200 /* Target Retry Error */
- #define SH7751_PCIINT_MFDE 0x00000100 /* Master Func. Disable Error */
- #define SH7751_PCIINT_PRTY 0x00000080 /* Address Parity Error */
- #define SH7751_PCIINT_SERR 0x00000040 /* SERR Detection Error */
- #define SH7751_PCIINT_TWDP 0x00000020 /* Tgt. Write Parity Error */
- #define SH7751_PCIINT_TRDP 0x00000010 /* Tgt. Read Parity Error Det. */
- #define SH7751_PCIINT_MTABT 0x00000008 /* Master-Tgt. Abort Error */
- #define SH7751_PCIINT_MMABT 0x00000004 /* Master-Master Abort Error */
- #define SH7751_PCIINT_MWPD 0x00000002 /* Master Write PERR Detect */
- #define SH7751_PCIINT_MRPD 0x00000002 /* Master Read PERR Detect */
-#define SH7751_PCIINTM 0x118 /* PCI Interrupt Mask Register */
-#define SH7751_PCIALR 0x11C /* Error Address Register */
-#define SH7751_PCICLR 0x120 /* Error Command/Data Register */
- #define SH7751_PCICLR_MPIO 0x80000000 /* Error Command/Data Register */
- #define SH7751_PCICLR_MDMA0 0x40000000 /* DMA0 Transfer Error */
- #define SH7751_PCICLR_MDMA1 0x20000000 /* DMA1 Transfer Error */
- #define SH7751_PCICLR_MDMA2 0x10000000 /* DMA2 Transfer Error */
- #define SH7751_PCICLR_MDMA3 0x08000000 /* DMA3 Transfer Error */
- #define SH7751_PCICLR_TGT 0x04000000 /* Target Transfer Error */
- #define SH7751_PCICLR_CMDL 0x0000000F /* PCI Command at Error */
-#define SH7751_PCIAINT 0x130 /* Arbiter Interrupt Register */
- #define SH7751_PCIAINT_MBKN 0x00002000 /* Master Broken Interrupt */
- #define SH7751_PCIAINT_TBTO 0x00001000 /* Target Bus Time Out */
- #define SH7751_PCIAINT_MBTO 0x00001000 /* Master Bus Time Out */
- #define SH7751_PCIAINT_TABT 0x00000008 /* Target Abort */
- #define SH7751_PCIAINT_MABT 0x00000004 /* Master Abort */
- #define SH7751_PCIAINT_RDPE 0x00000002 /* Read Data Parity Error */
- #define SH7751_PCIAINT_WDPE 0x00000002 /* Write Data Parity Error */
-#define SH7751_PCIAINTM 0x134 /* Arbiter Int. Mask Register */
-#define SH7751_PCIBMLR 0x138 /* Error Bus Master Register */
- #define SH7751_PCIBMLR_REQ4 0x00000010 /* REQ4 bus master at error */
- #define SH7751_PCIBMLR_REQ3 0x00000008 /* REQ3 bus master at error */
- #define SH7751_PCIBMLR_REQ2 0x00000004 /* REQ2 bus master at error */
- #define SH7751_PCIBMLR_REQ1 0x00000002 /* REQ1 bus master at error */
- #define SH7751_PCIBMLR_REQ0 0x00000001 /* REQ0 bus master at error */
-#define SH7751_PCIDMABT 0x140 /* DMA Transfer Arb. Register */
- #define SH7751_PCIDMABT_RRBN 0x00000001 /* DMA Arbitor Round-Robin */
-#define SH7751_PCIDPA0 0x180 /* DMA0 Transfer Addr. Register */
-#define SH7751_PCIDLA0 0x184 /* DMA0 Local Addr. Register */
-#define SH7751_PCIDTC0 0x188 /* DMA0 Transfer Cnt. Register */
-#define SH7751_PCIDCR0 0x18C /* DMA0 Control Register */
- #define SH7751_PCIDCR_ALGN 0x00000600 /* DMA Alignment Mode */
- #define SH7751_PCIDCR_MAST 0x00000100 /* DMA Termination Type */
- #define SH7751_PCIDCR_INTM 0x00000080 /* DMA Interrupt Done Mask*/
- #define SH7751_PCIDCR_INTS 0x00000040 /* DMA Interrupt Done Status */
- #define SH7751_PCIDCR_LHLD 0x00000020 /* Local Address Control */
- #define SH7751_PCIDCR_PHLD 0x00000010 /* PCI Address Control*/
- #define SH7751_PCIDCR_IOSEL 0x00000008 /* PCI Address Space Type */
- #define SH7751_PCIDCR_DIR 0x00000004 /* DMA Transfer Direction */
- #define SH7751_PCIDCR_STOP 0x00000002 /* Force DMA Stop */
- #define SH7751_PCIDCR_STRT 0x00000001 /* DMA Start */
-#define SH7751_PCIDPA1 0x190 /* DMA1 Transfer Addr. Register */
-#define SH7751_PCIDLA1 0x194 /* DMA1 Local Addr. Register */
-#define SH7751_PCIDTC1 0x198 /* DMA1 Transfer Cnt. Register */
-#define SH7751_PCIDCR1 0x19C /* DMA1 Control Register */
-#define SH7751_PCIDPA2 0x1A0 /* DMA2 Transfer Addr. Register */
-#define SH7751_PCIDLA2 0x1A4 /* DMA2 Local Addr. Register */
-#define SH7751_PCIDTC2 0x1A8 /* DMA2 Transfer Cnt. Register */
-#define SH7751_PCIDCR2 0x1AC /* DMA2 Control Register */
-#define SH7751_PCIDPA3 0x1B0 /* DMA3 Transfer Addr. Register */
-#define SH7751_PCIDLA3 0x1B4 /* DMA3 Local Addr. Register */
-#define SH7751_PCIDTC3 0x1B8 /* DMA3 Transfer Cnt. Register */
-#define SH7751_PCIDCR3 0x1BC /* DMA3 Control Register */
-#define SH7751_PCIPAR 0x1C0 /* PIO Address Register */
- #define SH7751_PCIPAR_CFGEN 0x80000000 /* Configuration Enable */
- #define SH7751_PCIPAR_BUSNO 0x00FF0000 /* Config. Bus Number */
- #define SH7751_PCIPAR_DEVNO 0x0000FF00 /* Config. Device Number */
- #define SH7751_PCIPAR_REGAD 0x000000FC /* Register Address Number */
-#define SH7751_PCIMBR 0x1C4 /* Memory Base Address Register */
- #define SH7751_PCIMBR_MASK 0xFF000000 /* Memory Space Mask */
- #define SH7751_PCIMBR_LOCK 0x00000001 /* Lock Memory Space */
-#define SH7751_PCIIOBR 0x1C8 /* I/O Base Address Register */
- #define SH7751_PCIIOBR_MASK 0xFFFC0000 /* IO Space Mask */
- #define SH7751_PCIIOBR_LOCK 0x00000001 /* Lock IO Space */
-#define SH7751_PCIPINT 0x1CC /* Power Mgmnt Int. Register */
- #define SH7751_PCIPINT_D3 0x00000002 /* D3 Pwr Mgmt. Interrupt */
- #define SH7751_PCIPINT_D0 0x00000001 /* D0 Pwr Mgmt. Interrupt */
-#define SH7751_PCIPINTM 0x1D0 /* Power Mgmnt Mask Register */
-#define SH7751_PCICLKR 0x1D4 /* Clock Ctrl. Register */
- #define SH7751_PCICLKR_PCSTP 0x00000002 /* PCI Clock Stop */
- #define SH7751_PCICLKR_BCSTP 0x00000002 /* BCLK Clock Stop */
-/* For definitions of BCR, MCR see ... */
-#define SH7751_PCIBCR1 0x1E0 /* Memory BCR1 Register */
-#define SH7751_PCIBCR2 0x1E4 /* Memory BCR2 Register */
-#define SH7751_PCIWCR1 0x1E8 /* Wait Control 1 Register */
-#define SH7751_PCIWCR2 0x1EC /* Wait Control 2 Register */
-#define SH7751_PCIWCR3 0x1F0 /* Wait Control 3 Register */
-#define SH7751_PCIMCR 0x1F4 /* Memory Control Register */
-#define SH7751_PCIBCR3 0x1f8 /* Memory BCR3 Register */
-#define SH7751_PCIPCTR 0x200 /* Port Control Register */
- #define SH7751_PCIPCTR_P2EN 0x000400000 /* Port 2 Enable */
- #define SH7751_PCIPCTR_P1EN 0x000200000 /* Port 1 Enable */
- #define SH7751_PCIPCTR_P0EN 0x000100000 /* Port 0 Enable */
- #define SH7751_PCIPCTR_P2UP 0x000000020 /* Port2 Pull Up Enable */
- #define SH7751_PCIPCTR_P2IO 0x000000010 /* Port2 Output Enable */
- #define SH7751_PCIPCTR_P1UP 0x000000008 /* Port1 Pull Up Enable */
- #define SH7751_PCIPCTR_P1IO 0x000000004 /* Port1 Output Enable */
- #define SH7751_PCIPCTR_P0UP 0x000000002 /* Port0 Pull Up Enable */
- #define SH7751_PCIPCTR_P0IO 0x000000001 /* Port0 Output Enable */
-#define SH7751_PCIPDTR 0x204 /* Port Data Register */
- #define SH7751_PCIPDTR_PB5 0x000000020 /* Port 5 Enable */
- #define SH7751_PCIPDTR_PB4 0x000000010 /* Port 4 Enable */
- #define SH7751_PCIPDTR_PB3 0x000000008 /* Port 3 Enable */
- #define SH7751_PCIPDTR_PB2 0x000000004 /* Port 2 Enable */
- #define SH7751_PCIPDTR_PB1 0x000000002 /* Port 1 Enable */
- #define SH7751_PCIPDTR_PB0 0x000000001 /* Port 0 Enable */
-#define SH7751_PCIPDR 0x220 /* Port IO Data Register */
/* Memory Control Registers */
#define SH7751_BCR1 0xFF800000 /* Memory BCR1 Register */
@@ -274,30 +127,9 @@
#define SH7751_CS5_BASE_ADDR (SH7751_CS4_BASE_ADDR + SH7751_MEM_REGION_SIZE)
#define SH7751_CS6_BASE_ADDR (SH7751_CS5_BASE_ADDR + SH7751_MEM_REGION_SIZE)
-/* General PCI values */
-#define SH7751_PCI_HOST_BRIDGE 0x6
-
-/* Flags */
-#define SH7751_PCIC_NO_RESET 0x0001
-
-/* External functions defined per platform i.e. Big Sur, SE... (these could be routed
- * through the machine vectors... */
-extern int pcibios_init_platform(void);
-extern int pcibios_map_platform_irq(u8 slot, u8 pin);
-
-struct sh7751_pci_address_space {
- unsigned long base;
- unsigned long size;
-};
-
-struct sh7751_pci_address_map {
- struct sh7751_pci_address_space window0;
- struct sh7751_pci_address_space window1;
- unsigned long flags;
-};
+struct sh4_pci_address_map;
/* arch/sh/drivers/pci/pci-sh7751.c */
-extern int sh7751_pcic_init(struct sh7751_pci_address_map *map);
+int sh7751_pcic_init(struct sh4_pci_address_map *map);
#endif /* _PCI_SH7751_H_ */
-
diff --git a/arch/sh/drivers/pci/pci-sh7780.c b/arch/sh/drivers/pci/pci-sh7780.c
new file mode 100644
index 000000000000..d6e635296534
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-sh7780.c
@@ -0,0 +1,137 @@
+/*
+ * Low-Level PCI Support for the SH7780
+ *
+ * Dustin McIntire (dustin@sensoria.com)
+ * Derived from arch/i386/kernel/pci-*.c which bore the message:
+ * (c) 1999--2000 Martin Mares <mj@ucw.cz>
+ *
+ * Ported to the new API by Paul Mundt <lethal@linux-sh.org>
+ * With cleanup by Paul van Gool <pvangool@mimotech.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ */
+#undef DEBUG
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include "pci-sh4.h"
+
+/*
+ * Initialization. Try all known PCI access methods. Note that we support
+ * using both PCI BIOS and direct access: in such cases, we use I/O ports
+ * to access config space.
+ *
+ * Note that the platform specific initialization (BSC registers, and memory
+ * space mapping) will be called via the platform defined function
+ * pcibios_init_platform().
+ */
+static int __init sh7780_pci_init(void)
+{
+ unsigned int id;
+ int ret;
+
+ pr_debug("PCI: Starting intialization.\n");
+
+ outl(0x00000001, SH7780_PCI_VCR2); /* Enable PCIC */
+
+ /* check for SH7780/SH7780R hardware */
+ id = pci_read_reg(SH7780_PCIVID);
+ if ((id != ((SH7780_DEVICE_ID << 16) | SH7780_VENDOR_ID)) &&
+ (id != ((SH7781_DEVICE_ID << 16) | SH7780_VENDOR_ID))) {
+ printk(KERN_ERR "PCI: This is not an SH7780 (%x)\n", id);
+ return -ENODEV;
+ }
+
+ /* Setup the INTC */
+ ctrl_outl(0x00200000, INTC_ICR0); /* INTC SH-4 Mode */
+ ctrl_outl(0x00078000, INTC_INT2MSKCR); /* enable PCIINTA - PCIINTD */
+ ctrl_outl(0x40000000, INTC_INTMSK1); /* disable IRL4-7 Interrupt */
+ ctrl_outl(0x0000fffe, INTC_INTMSK2); /* disable IRL4-7 Interrupt */
+ ctrl_outl(0x80000000, INTC_INTMSKCLR1); /* enable IRL0-3 Interrupt */
+ ctrl_outl(0xfffe0000, INTC_INTMSKCLR2); /* enable IRL0-3 Interrupt */
+
+ if ((ret = sh4_pci_check_direct()) != 0)
+ return ret;
+
+ return pcibios_init_platform();
+}
+core_initcall(sh7780_pci_init);
+
+int __init sh7780_pcic_init(struct sh4_pci_address_map *map)
+{
+ u32 word;
+
+ /*
+ * This code is unused for some boards as it is done in the
+ * bootloader and doing it here means the MAC addresses loaded
+ * by the bootloader get lost.
+ */
+ if (!(map->flags & SH4_PCIC_NO_RESET)) {
+ /* toggle PCI reset pin */
+ word = SH4_PCICR_PREFIX | SH4_PCICR_PRST;
+ pci_write_reg(word, SH4_PCICR);
+ /* Wait for a long time... not 1 sec. but long enough */
+ mdelay(100);
+ word = SH4_PCICR_PREFIX;
+ pci_write_reg(word, SH4_PCICR);
+ }
+
+ /* set the command/status bits to:
+ * Wait Cycle Control + Parity Enable + Bus Master +
+ * Mem space enable
+ */
+ pci_write_reg(0x00000046, SH7780_PCICMD);
+
+ /* define this host as the host bridge */
+ word = PCI_BASE_CLASS_BRIDGE << 24;
+ pci_write_reg(word, SH7780_PCIRID);
+
+ /* Set IO and Mem windows to local address
+ * Make PCI and local address the same for easy 1 to 1 mapping
+ * Window0 = map->window0.size @ non-cached area base = SDRAM
+ * Window1 = map->window1.size @ cached area base = SDRAM
+ */
+ word = ((map->window0.size - 1) & 0x1ff00001) | 0x01;
+ pci_write_reg(0x07f00001, SH4_PCILSR0);
+ word = ((map->window1.size - 1) & 0x1ff00001) | 0x01;
+ pci_write_reg(0x00000001, SH4_PCILSR1);
+ /* Set the values on window 0 PCI config registers */
+ word = P2SEGADDR(map->window0.base);
+ pci_write_reg(0xa8000000, SH4_PCILAR0);
+ pci_write_reg(0x08000000, SH7780_PCIMBAR0);
+ /* Set the values on window 1 PCI config registers */
+ word = P2SEGADDR(map->window1.base);
+ pci_write_reg(0x00000000, SH4_PCILAR1);
+ pci_write_reg(0x00000000, SH7780_PCIMBAR1);
+
+ /* Map IO space into PCI IO window
+ * The IO window is 64K-PCIBIOS_MIN_IO in size
+ * IO addresses will be translated to the
+ * PCI IO window base address
+ */
+ pr_debug("PCI: Mapping IO address 0x%x - 0x%x to base 0x%x\n",
+ PCIBIOS_MIN_IO, (64 << 10),
+ SH7780_PCI_IO_BASE + PCIBIOS_MIN_IO);
+
+ /* NOTE: I'm ignoring the PCI error IRQs for now..
+ * TODO: add support for the internal error interrupts and
+ * DMA interrupts...
+ */
+
+#ifdef CONFIG_SH_R7780RP
+ pci_fixup_pcic();
+#endif
+
+ /* SH7780 init done, set central function init complete */
+ /* use round robin mode to stop a device starving/overruning */
+ word = SH4_PCICR_PREFIX | SH4_PCICR_CFIN | SH4_PCICR_FTO;
+ pci_write_reg(word, SH4_PCICR);
+
+ return 1;
+}
diff --git a/arch/sh/drivers/pci/pci-sh7780.h b/arch/sh/drivers/pci/pci-sh7780.h
new file mode 100644
index 000000000000..f02d2180a4bc
--- /dev/null
+++ b/arch/sh/drivers/pci/pci-sh7780.h
@@ -0,0 +1,94 @@
+/*
+ * Low-Level PCI Support for SH7780 targets
+ *
+ * Dustin McIntire (dustin@sensoria.com) (c) 2001
+ * Paul Mundt (lethal@linux-sh.org) (c) 2003
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License. See linux/COPYING for more information.
+ *
+ */
+
+#ifndef _PCI_SH7780_H_
+#define _PCI_SH7780_H_
+
+/* Platform Specific Values */
+#define SH7780_VENDOR_ID 0x1912
+#define SH7780_DEVICE_ID 0x0002
+#define SH7781_DEVICE_ID 0x0001
+
+/* SH7780 Control Registers */
+#define SH7780_PCI_VCR0 0xFE000000
+#define SH7780_PCI_VCR1 0xFE000004
+#define SH7780_PCI_VCR2 0xFE000008
+
+/* SH7780 Specific Values */
+#define SH7780_PCI_CONFIG_BASE 0xFD000000 /* Config space base addr */
+#define SH7780_PCI_CONFIG_SIZE 0x01000000 /* Config space size */
+
+#define SH7780_PCI_MEMORY_BASE 0xFD000000 /* Memory space base addr */
+#define SH7780_PCI_MEM_SIZE 0x01000000 /* Size of Memory window */
+
+#define SH7780_PCI_IO_BASE 0xFE400000 /* IO space base address */
+#define SH7780_PCI_IO_SIZE 0x00400000 /* Size of IO window */
+
+#define SH7780_PCIREG_BASE 0xFE040000 /* PCI regs base address */
+#define PCI_REG(n) (SH7780_PCIREG_BASE+n)
+
+/* SH7780 PCI Config Registers */
+#define SH7780_PCIVID 0x000 /* Vendor ID */
+#define SH7780_PCIDID 0x002 /* Device ID */
+#define SH7780_PCICMD 0x004 /* Command */
+#define SH7780_PCISTATUS 0x006 /* Status */
+#define SH7780_PCIRID 0x008 /* Revision ID */
+#define SH7780_PCIPIF 0x009 /* Program Interface */
+#define SH7780_PCISUB 0x00a /* Sub class code */
+#define SH7780_PCIBCC 0x00b /* Base class code */
+#define SH7780_PCICLS 0x00c /* Cache line size */
+#define SH7780_PCILTM 0x00d /* latency timer */
+#define SH7780_PCIHDR 0x00e /* Header type */
+#define SH7780_PCIBIST 0x00f /* BIST */
+#define SH7780_PCIIBAR 0x010 /* IO Base address */
+#define SH7780_PCIMBAR0 0x014 /* Memory base address0 */
+#define SH7780_PCIMBAR1 0x018 /* Memory base address1 */
+#define SH7780_PCISVID 0x02c /* Sub system vendor ID */
+#define SH7780_PCISID 0x02e /* Sub system ID */
+#define SH7780_PCICP 0x034
+#define SH7780_PCIINTLINE 0x03c /* Interrupt line */
+#define SH7780_PCIINTPIN 0x03d /* Interrupt pin */
+#define SH7780_PCIMINGNT 0x03e /* Minumum grand */
+#define SH7780_PCIMAXLAT 0x03f /* Maxmum latency */
+#define SH7780_PCICID 0x040
+#define SH7780_PCINIP 0x041
+#define SH7780_PCIPMC 0x042
+#define SH7780_PCIPMCSR 0x044
+#define SH7780_PCIPMCSR_BSE 0x046
+#define SH7780_PCICDD 0x047
+
+#define SH7780_PCIMBR0 0x1E0
+#define SH7780_PCIMBMR0 0x1E4
+#define SH7780_PCIMBR2 0x1F0
+#define SH7780_PCIMBMR2 0x1F4
+#define SH7780_PCIIOBR 0x1F8
+#define SH7780_PCIIOBMR 0x1FC
+#define SH7780_PCICSCR0 0x210 /* Cache Snoop1 Cnt. Register */
+#define SH7780_PCICSCR1 0x214 /* Cache Snoop2 Cnt. Register */
+#define SH7780_PCICSAR0 0x218 /* Cache Snoop1 Addr. Register */
+#define SH7780_PCICSAR1 0x21C /* Cache Snoop2 Addr. Register */
+
+/* General Memory Config Addresses */
+#define SH7780_CS0_BASE_ADDR 0x0
+#define SH7780_MEM_REGION_SIZE 0x04000000
+#define SH7780_CS1_BASE_ADDR (SH7780_CS0_BASE_ADDR + SH7780_MEM_REGION_SIZE)
+#define SH7780_CS2_BASE_ADDR (SH7780_CS1_BASE_ADDR + SH7780_MEM_REGION_SIZE)
+#define SH7780_CS3_BASE_ADDR (SH7780_CS2_BASE_ADDR + SH7780_MEM_REGION_SIZE)
+#define SH7780_CS4_BASE_ADDR (SH7780_CS3_BASE_ADDR + SH7780_MEM_REGION_SIZE)
+#define SH7780_CS5_BASE_ADDR (SH7780_CS4_BASE_ADDR + SH7780_MEM_REGION_SIZE)
+#define SH7780_CS6_BASE_ADDR (SH7780_CS5_BASE_ADDR + SH7780_MEM_REGION_SIZE)
+
+struct sh4_pci_address_map;
+
+/* arch/sh/drivers/pci/pci-sh7780.c */
+int sh7780_pcic_init(struct sh4_pci_address_map *map);
+
+#endif /* _PCI_SH7780_H_ */
diff --git a/arch/sh/drivers/pci/pci-st40.c b/arch/sh/drivers/pci/pci-st40.c
index 7c81b8b65bb5..efecb3d5995c 100644
--- a/arch/sh/drivers/pci/pci-st40.c
+++ b/arch/sh/drivers/pci/pci-st40.c
@@ -70,12 +70,6 @@
static void pci_set_rbar_region(unsigned int region, unsigned long localAddr,
unsigned long pciOffset, unsigned long regionSize);
-/*
- * The pcibios_map_platform_irq function is defined in the appropriate
- * board specific code and referenced here
- */
-extern int __init pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
-
static __init void SetPCIPLL(void)
{
{
@@ -167,7 +161,7 @@ static char * pci_commands[16]={
"Memory Write-and-Invalidate"
};
-static irqreturn_t st40_pci_irq(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t st40_pci_irq(int irq, void *dev_instance)
{
unsigned pci_int, pci_air, pci_cir, pci_aint;
static int count=0;
@@ -422,13 +416,6 @@ struct pci_ops st40pci_config_ops = {
/* Everything hangs off this */
static struct pci_bus *pci_root_bus;
-
-static u8 __init no_swizzle(struct pci_dev *dev, u8 * pin)
-{
- return PCI_SLOT(dev->devfn);
-}
-
-
static int __init pcibios_init(void)
{
extern unsigned long memory_start, memory_end;
@@ -465,17 +452,11 @@ static int __init pcibios_init(void)
/* ok, do the scan man */
pci_root_bus = pci_scan_bus(0, &st40pci_config_ops, NULL);
pci_assign_unassigned_resources();
- pci_fixup_irqs(no_swizzle, pcibios_map_platform_irq);
return 0;
}
-
subsys_initcall(pcibios_init);
-void __init pcibios_fixup_bus(struct pci_bus *bus)
-{
-}
-
/*
* Publish a region of local address space over the PCI bus
* to other devices.
diff --git a/arch/sh/drivers/pci/pci.c b/arch/sh/drivers/pci/pci.c
index 3d546ba329cf..d439336d2e18 100644
--- a/arch/sh/drivers/pci/pci.c
+++ b/arch/sh/drivers/pci/pci.c
@@ -1,21 +1,45 @@
-/* arch/sh/kernel/pci.c
- * $Id: pci.c,v 1.1 2003/08/24 19:15:45 lethal Exp $
+/*
+ * arch/sh/drivers/pci/pci.c
*
* Copyright (c) 2002 M. R. Brown <mrbrown@linux-sh.org>
- *
- *
+ * Copyright (c) 2004 - 2006 Paul Mundt <lethal@linux-sh.org>
+ *
* These functions are collected here to reduce duplication of common
* code amongst the many platform-specific PCI support code files.
- *
+ *
* These routines require the following board-specific routines:
* void pcibios_fixup_irqs();
*
* See include/asm-sh/pci.h for more information.
+ *
+ * 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/pci.h>
#include <linux/init.h>
+#include <asm/io.h>
+
+static inline u8 bridge_swizzle(u8 pin, u8 slot)
+{
+ return (((pin - 1) + slot) % 4) + 1;
+}
+
+static u8 __init simple_swizzle(struct pci_dev *dev, u8 *pinp)
+{
+ u8 pin = *pinp;
+
+ while (dev->bus->parent) {
+ pin = bridge_swizzle(pin, PCI_SLOT(dev->devfn));
+ /* Move up the chain of bridges. */
+ dev = dev->bus->self;
+ }
+ *pinp = pin;
+
+ /* The slot is the slot of the last bridge. */
+ return PCI_SLOT(dev->devfn);
+}
static int __init pcibios_init(void)
{
@@ -26,26 +50,32 @@ static int __init pcibios_init(void)
#ifdef CONFIG_PCI_AUTO
/* assign resources */
busno = 0;
- for (p = board_pci_channels; p->pci_ops != NULL; p++) {
+ for (p = board_pci_channels; p->pci_ops != NULL; p++)
busno = pciauto_assign_resources(busno, p) + 1;
- }
#endif
/* scan the buses */
busno = 0;
- for (p= board_pci_channels; p->pci_ops != NULL; p++) {
+ for (p = board_pci_channels; p->pci_ops != NULL; p++) {
bus = pci_scan_bus(busno, p->pci_ops, p);
- busno = bus->subordinate+1;
+ busno = bus->subordinate + 1;
}
- /* board-specific fixups */
- pcibios_fixup_irqs();
+ pci_fixup_irqs(simple_swizzle, pcibios_map_platform_irq);
return 0;
}
-
subsys_initcall(pcibios_init);
+/*
+ * Called after each bus is probed, but before its children
+ * are examined.
+ */
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+ pci_read_bridge_bases(bus);
+}
+
void
pcibios_update_resource(struct pci_dev *dev, struct resource *root,
struct resource *res, int resource)
@@ -61,13 +91,17 @@ pcibios_update_resource(struct pci_dev *dev, struct resource *root,
new |= PCI_ROM_ADDRESS_ENABLE;
reg = dev->rom_base_reg;
} else {
- /* Somebody might have asked allocation of a non-standard resource */
+ /*
+ * Somebody might have asked allocation of a non-standard
+ * resource
+ */
return;
}
-
+
pci_write_config_dword(dev, reg, new);
pci_read_config_dword(dev, reg, &check);
- if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
+ if ((new ^ check) & ((new & PCI_BASE_ADDRESS_SPACE_IO) ?
+ PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK)) {
printk(KERN_ERR "PCI: Error while updating region "
"%s/%d (%08x != %08x)\n", pci_name(dev), resource,
new, check);
@@ -145,7 +179,8 @@ void pcibios_set_master(struct pci_dev *dev)
lat = pcibios_max_latency;
else
return;
- printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n", pci_name(dev), lat);
+ printk(KERN_INFO "PCI: Setting latency timer of device %s to %d\n",
+ pci_name(dev), lat);
pci_write_config_byte(dev, PCI_LATENCY_TIMER, lat);
}
@@ -153,3 +188,39 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq)
{
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
}
+
+void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen)
+{
+ unsigned long start = pci_resource_start(dev, bar);
+ unsigned long len = pci_resource_len(dev, bar);
+ unsigned long flags = pci_resource_flags(dev, bar);
+
+ if (unlikely(!len || !start))
+ return NULL;
+ if (maxlen && len > maxlen)
+ len = maxlen;
+
+ /*
+ * Presently the IORESOURCE_MEM case is a bit special, most
+ * SH7751 style PCI controllers have PCI memory at a fixed
+ * location in the address space where no remapping is desired
+ * (typically at 0xfd000000, but is_pci_memaddr() will know
+ * best). With the IORESOURCE_MEM case more care has to be taken
+ * to inhibit page table mapping for legacy cores, but this is
+ * punted off to __ioremap().
+ * -- PFM.
+ */
+ if (flags & IORESOURCE_IO)
+ return ioport_map(start, len);
+ if (flags & IORESOURCE_MEM)
+ return ioremap(start, len);
+
+ return NULL;
+}
+EXPORT_SYMBOL(pci_iomap);
+
+void pci_iounmap(struct pci_dev *dev, void __iomem *addr)
+{
+ iounmap(addr);
+}
+EXPORT_SYMBOL(pci_iounmap);
diff --git a/arch/sh/kernel/Makefile b/arch/sh/kernel/Makefile
index f05cd96f8867..5da88a43d350 100644
--- a/arch/sh/kernel/Makefile
+++ b/arch/sh/kernel/Makefile
@@ -6,9 +6,10 @@ extra-y := head.o init_task.o vmlinux.lds
obj-y := process.o signal.o entry.o traps.o irq.o \
ptrace.o setup.o time.o sys_sh.o semaphore.o \
- io.o io_generic.o sh_ksyms.o
+ io.o io_generic.o sh_ksyms.o syscalls.o
obj-y += cpu/ timers/
+obj-$(CONFIG_VSYSCALL) += vsyscall/
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_CF_ENABLER) += cf-enabler.o
@@ -18,3 +19,5 @@ obj-$(CONFIG_SH_CPU_FREQ) += cpufreq.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_APM) += apm.o
+obj-$(CONFIG_PM) += pm.o
diff --git a/arch/sh/kernel/apm.c b/arch/sh/kernel/apm.c
new file mode 100644
index 000000000000..4f66f91b1006
--- /dev/null
+++ b/arch/sh/kernel/apm.c
@@ -0,0 +1,538 @@
+/*
+ * bios-less APM driver for hp680
+ *
+ * Copyright 2005 (c) Andriy Skulysh <askulysh@gmail.com>
+ *
+ * based on ARM APM driver by
+ * Jamey Hicks <jamey@crl.dec.com>
+ *
+ * adapted from the APM BIOS driver for Linux by
+ * Stephen Rothwell (sfr@linuxcare.com)
+ *
+ * APM 1.2 Reference:
+ * Intel Corporation, Microsoft Corporation. Advanced Power Management
+ * (APM) BIOS Interface Specification, Revision 1.2, February 1996.
+ *
+ * [This document is available from Microsoft at:
+ * http://www.microsoft.com/hwdev/busbios/amp_12.htm]
+ */
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/timer.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/miscdevice.h>
+#include <linux/apm_bios.h>
+#include <linux/pm.h>
+#include <linux/pm_legacy.h>
+#include <asm/apm.h>
+
+#define MODNAME "apm"
+
+/*
+ * The apm_bios device is one of the misc char devices.
+ * This is its minor number.
+ */
+#define APM_MINOR_DEV 134
+
+/*
+ * Maximum number of events stored
+ */
+#define APM_MAX_EVENTS 16
+
+struct apm_queue {
+ unsigned int event_head;
+ unsigned int event_tail;
+ apm_event_t events[APM_MAX_EVENTS];
+};
+
+/*
+ * The per-file APM data
+ */
+struct apm_user {
+ struct list_head list;
+
+ unsigned int suser: 1;
+ unsigned int writer: 1;
+ unsigned int reader: 1;
+
+ int suspend_result;
+ unsigned int suspend_state;
+#define SUSPEND_NONE 0 /* no suspend pending */
+#define SUSPEND_PENDING 1 /* suspend pending read */
+#define SUSPEND_READ 2 /* suspend read, pending ack */
+#define SUSPEND_ACKED 3 /* suspend acked */
+#define SUSPEND_DONE 4 /* suspend completed */
+
+ struct apm_queue queue;
+};
+
+/*
+ * Local variables
+ */
+static int suspends_pending;
+
+static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue);
+static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue);
+
+/*
+ * This is a list of everyone who has opened /dev/apm_bios
+ */
+static DECLARE_RWSEM(user_list_lock);
+static LIST_HEAD(apm_user_list);
+
+/*
+ * kapmd info. kapmd provides us a process context to handle
+ * "APM" events within - specifically necessary if we're going
+ * to be suspending the system.
+ */
+static DECLARE_WAIT_QUEUE_HEAD(kapmd_wait);
+static DECLARE_COMPLETION(kapmd_exit);
+static DEFINE_SPINLOCK(kapmd_queue_lock);
+static struct apm_queue kapmd_queue;
+
+int apm_suspended;
+EXPORT_SYMBOL(apm_suspended);
+
+/* Platform-specific apm_read_proc(). */
+int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
+EXPORT_SYMBOL(apm_get_info);
+
+/*
+ * APM event queue management.
+ */
+static inline int queue_empty(struct apm_queue *q)
+{
+ return q->event_head == q->event_tail;
+}
+
+static inline apm_event_t queue_get_event(struct apm_queue *q)
+{
+ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
+ return q->events[q->event_tail];
+}
+
+static void queue_add_event(struct apm_queue *q, apm_event_t event)
+{
+ q->event_head = (q->event_head + 1) % APM_MAX_EVENTS;
+ if (q->event_head == q->event_tail) {
+ static int notified;
+
+ if (notified++ == 0)
+ printk(KERN_ERR "apm: an event queue overflowed\n");
+
+ q->event_tail = (q->event_tail + 1) % APM_MAX_EVENTS;
+ }
+ q->events[q->event_head] = event;
+}
+
+static void queue_event_one_user(struct apm_user *as, apm_event_t event)
+{
+ if (as->suser && as->writer) {
+ switch (event) {
+ case APM_SYS_SUSPEND:
+ case APM_USER_SUSPEND:
+ /*
+ * If this user already has a suspend pending,
+ * don't queue another one.
+ */
+ if (as->suspend_state != SUSPEND_NONE)
+ return;
+
+ as->suspend_state = SUSPEND_PENDING;
+ suspends_pending++;
+ break;
+ }
+ }
+ queue_add_event(&as->queue, event);
+}
+
+static void queue_event(apm_event_t event, struct apm_user *sender)
+{
+ struct apm_user *as;
+
+ down_read(&user_list_lock);
+
+ list_for_each_entry(as, &apm_user_list, list)
+ if (as != sender && as->reader)
+ queue_event_one_user(as, event);
+
+ up_read(&user_list_lock);
+ wake_up_interruptible(&apm_waitqueue);
+}
+
+/**
+ * apm_queue_event - queue an APM event for kapmd
+ * @event: APM event
+ *
+ * Queue an APM event for kapmd to process and ultimately take the
+ * appropriate action. Only a subset of events are handled:
+ * %APM_LOW_BATTERY
+ * %APM_POWER_STATUS_CHANGE
+ * %APM_USER_SUSPEND
+ * %APM_SYS_SUSPEND
+ * %APM_CRITICAL_SUSPEND
+ */
+void apm_queue_event(apm_event_t event)
+{
+ spin_lock_irq(&kapmd_queue_lock);
+ queue_add_event(&kapmd_queue, event);
+ spin_unlock_irq(&kapmd_queue_lock);
+
+ wake_up_interruptible(&kapmd_wait);
+}
+EXPORT_SYMBOL(apm_queue_event);
+
+static void apm_suspend(void)
+{
+ struct apm_user *as;
+ int err;
+
+ apm_suspended = 1;
+ err = pm_suspend(PM_SUSPEND_MEM);
+
+ /*
+ * Anyone on the APM queues will think we're still suspended.
+ * Send a message so everyone knows we're now awake again.
+ */
+ queue_event(APM_NORMAL_RESUME, NULL);
+
+ /*
+ * Finally, wake up anyone who is sleeping on the suspend.
+ */
+ down_read(&user_list_lock);
+ list_for_each_entry(as, &apm_user_list, list) {
+ as->suspend_result = err;
+ as->suspend_state = SUSPEND_DONE;
+ }
+ up_read(&user_list_lock);
+
+ wake_up(&apm_suspend_waitqueue);
+ apm_suspended = 0;
+}
+
+static ssize_t apm_read(struct file *fp, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct apm_user *as = fp->private_data;
+ apm_event_t event;
+ int i = count, ret = 0;
+
+ if (count < sizeof(apm_event_t))
+ return -EINVAL;
+
+ if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue));
+
+ while ((i >= sizeof(event)) && !queue_empty(&as->queue)) {
+ event = queue_get_event(&as->queue);
+
+ ret = -EFAULT;
+ if (copy_to_user(buf, &event, sizeof(event)))
+ break;
+
+ if (event == APM_SYS_SUSPEND || event == APM_USER_SUSPEND)
+ as->suspend_state = SUSPEND_READ;
+
+ buf += sizeof(event);
+ i -= sizeof(event);
+ }
+
+ if (i < count)
+ ret = count - i;
+
+ return ret;
+}
+
+static unsigned int apm_poll(struct file *fp, poll_table * wait)
+{
+ struct apm_user *as = fp->private_data;
+
+ poll_wait(fp, &apm_waitqueue, wait);
+ return queue_empty(&as->queue) ? 0 : POLLIN | POLLRDNORM;
+}
+
+/*
+ * apm_ioctl - handle APM ioctl
+ *
+ * APM_IOC_SUSPEND
+ * This IOCTL is overloaded, and performs two functions. It is used to:
+ * - initiate a suspend
+ * - acknowledge a suspend read from /dev/apm_bios.
+ * Only when everyone who has opened /dev/apm_bios with write permission
+ * has acknowledge does the actual suspend happen.
+ */
+static int
+apm_ioctl(struct inode * inode, struct file *filp, u_int cmd, u_long arg)
+{
+ struct apm_user *as = filp->private_data;
+ unsigned long flags;
+ int err = -EINVAL;
+
+ if (!as->suser || !as->writer)
+ return -EPERM;
+
+ switch (cmd) {
+ case APM_IOC_SUSPEND:
+ as->suspend_result = -EINTR;
+
+ if (as->suspend_state == SUSPEND_READ) {
+ /*
+ * If we read a suspend command from /dev/apm_bios,
+ * then the corresponding APM_IOC_SUSPEND ioctl is
+ * interpreted as an acknowledge.
+ */
+ as->suspend_state = SUSPEND_ACKED;
+ suspends_pending--;
+ } else {
+ /*
+ * Otherwise it is a request to suspend the system.
+ * Queue an event for all readers, and expect an
+ * acknowledge from all writers who haven't already
+ * acknowledged.
+ */
+ queue_event(APM_USER_SUSPEND, as);
+ }
+
+ /*
+ * If there are no further acknowledges required, suspend
+ * the system.
+ */
+ if (suspends_pending == 0)
+ apm_suspend();
+
+ /*
+ * Wait for the suspend/resume to complete. If there are
+ * pending acknowledges, we wait here for them.
+ *
+ * Note that we need to ensure that the PM subsystem does
+ * not kick us out of the wait when it suspends the threads.
+ */
+ flags = current->flags;
+ current->flags |= PF_NOFREEZE;
+
+ /*
+ * Note: do not allow a thread which is acking the suspend
+ * to escape until the resume is complete.
+ */
+ if (as->suspend_state == SUSPEND_ACKED)
+ wait_event(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE);
+ else
+ wait_event_interruptible(apm_suspend_waitqueue,
+ as->suspend_state == SUSPEND_DONE);
+
+ current->flags = flags;
+ err = as->suspend_result;
+ as->suspend_state = SUSPEND_NONE;
+ break;
+ }
+
+ return err;
+}
+
+static int apm_release(struct inode * inode, struct file * filp)
+{
+ struct apm_user *as = filp->private_data;
+ filp->private_data = NULL;
+
+ down_write(&user_list_lock);
+ list_del(&as->list);
+ up_write(&user_list_lock);
+
+ /*
+ * We are now unhooked from the chain. As far as new
+ * events are concerned, we no longer exist. However, we
+ * need to balance suspends_pending, which means the
+ * possibility of sleeping.
+ */
+ if (as->suspend_state != SUSPEND_NONE) {
+ suspends_pending -= 1;
+ if (suspends_pending == 0)
+ apm_suspend();
+ }
+
+ kfree(as);
+ return 0;
+}
+
+static int apm_open(struct inode * inode, struct file * filp)
+{
+ struct apm_user *as;
+
+ as = kzalloc(sizeof(*as), GFP_KERNEL);
+ if (as) {
+ /*
+ * XXX - this is a tiny bit broken, when we consider BSD
+ * process accounting. If the device is opened by root, we
+ * instantly flag that we used superuser privs. Who knows,
+ * we might close the device immediately without doing a
+ * privileged operation -- cevans
+ */
+ as->suser = capable(CAP_SYS_ADMIN);
+ as->writer = (filp->f_mode & FMODE_WRITE) == FMODE_WRITE;
+ as->reader = (filp->f_mode & FMODE_READ) == FMODE_READ;
+
+ down_write(&user_list_lock);
+ list_add(&as->list, &apm_user_list);
+ up_write(&user_list_lock);
+
+ filp->private_data = as;
+ }
+
+ return as ? 0 : -ENOMEM;
+}
+
+static struct file_operations apm_bios_fops = {
+ .owner = THIS_MODULE,
+ .read = apm_read,
+ .poll = apm_poll,
+ .ioctl = apm_ioctl,
+ .open = apm_open,
+ .release = apm_release,
+};
+
+static struct miscdevice apm_device = {
+ .minor = APM_MINOR_DEV,
+ .name = "apm_bios",
+ .fops = &apm_bios_fops
+};
+
+
+#ifdef CONFIG_PROC_FS
+/*
+ * Arguments, with symbols from linux/apm_bios.h.
+ *
+ * 0) Linux driver version (this will change if format changes)
+ * 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2.
+ * 2) APM flags from APM Installation Check (0x00):
+ * bit 0: APM_16_BIT_SUPPORT
+ * bit 1: APM_32_BIT_SUPPORT
+ * bit 2: APM_IDLE_SLOWS_CLOCK
+ * bit 3: APM_BIOS_DISABLED
+ * bit 4: APM_BIOS_DISENGAGED
+ * 3) AC line status
+ * 0x00: Off-line
+ * 0x01: On-line
+ * 0x02: On backup power (BIOS >= 1.1 only)
+ * 0xff: Unknown
+ * 4) Battery status
+ * 0x00: High
+ * 0x01: Low
+ * 0x02: Critical
+ * 0x03: Charging
+ * 0x04: Selected battery not present (BIOS >= 1.2 only)
+ * 0xff: Unknown
+ * 5) Battery flag
+ * bit 0: High
+ * bit 1: Low
+ * bit 2: Critical
+ * bit 3: Charging
+ * bit 7: No system battery
+ * 0xff: Unknown
+ * 6) Remaining battery life (percentage of charge):
+ * 0-100: valid
+ * -1: Unknown
+ * 7) Remaining battery life (time units):
+ * Number of remaining minutes or seconds
+ * -1: Unknown
+ * 8) min = minutes; sec = seconds
+ */
+static int apm_read_proc(char *buf, char **start, off_t fpos, int length)
+{
+ if (likely(apm_get_info))
+ return apm_get_info(buf, start, fpos, length);
+
+ return -EINVAL;
+}
+#endif
+
+static int kapmd(void *arg)
+{
+ daemonize("kapmd");
+ current->flags |= PF_NOFREEZE;
+
+ do {
+ apm_event_t event;
+
+ wait_event_interruptible(kapmd_wait,
+ !queue_empty(&kapmd_queue) || !pm_active);
+
+ if (!pm_active)
+ break;
+
+ spin_lock_irq(&kapmd_queue_lock);
+ event = 0;
+ if (!queue_empty(&kapmd_queue))
+ event = queue_get_event(&kapmd_queue);
+ spin_unlock_irq(&kapmd_queue_lock);
+
+ switch (event) {
+ case 0:
+ break;
+
+ case APM_LOW_BATTERY:
+ case APM_POWER_STATUS_CHANGE:
+ queue_event(event, NULL);
+ break;
+
+ case APM_USER_SUSPEND:
+ case APM_SYS_SUSPEND:
+ queue_event(event, NULL);
+ if (suspends_pending == 0)
+ apm_suspend();
+ break;
+
+ case APM_CRITICAL_SUSPEND:
+ apm_suspend();
+ break;
+ }
+ } while (1);
+
+ complete_and_exit(&kapmd_exit, 0);
+}
+
+static int __init apm_init(void)
+{
+ int ret;
+
+ pm_active = 1;
+
+ ret = kernel_thread(kapmd, NULL, CLONE_KERNEL);
+ if (unlikely(ret < 0)) {
+ pm_active = 0;
+ return ret;
+ }
+
+ create_proc_info_entry("apm", 0, NULL, apm_read_proc);
+
+ ret = misc_register(&apm_device);
+ if (unlikely(ret != 0)) {
+ remove_proc_entry("apm", NULL);
+
+ pm_active = 0;
+ wake_up(&kapmd_wait);
+ wait_for_completion(&kapmd_exit);
+ }
+
+ return ret;
+}
+
+static void __exit apm_exit(void)
+{
+ misc_deregister(&apm_device);
+ remove_proc_entry("apm", NULL);
+
+ pm_active = 0;
+ wake_up(&kapmd_wait);
+ wait_for_completion(&kapmd_exit);
+}
+
+module_init(apm_init);
+module_exit(apm_exit);
+
+MODULE_AUTHOR("Stephen Rothwell, Andriy Skulysh");
+MODULE_DESCRIPTION("Advanced Power Management");
+MODULE_LICENSE("GPL");
diff --git a/arch/sh/kernel/cf-enabler.c b/arch/sh/kernel/cf-enabler.c
index f1f9ab87f0b0..3e5fa1e24df0 100644
--- a/arch/sh/kernel/cf-enabler.c
+++ b/arch/sh/kernel/cf-enabler.c
@@ -10,7 +10,8 @@
*/
#include <linux/init.h>
-
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -32,8 +33,6 @@
/* SH4 can't access PCMCIA interface through P2 area.
* we must remap it with appropreate attribute bit of the page set.
* this part is based on Greg Banks' hd64465_ss.c implementation - Masahiro Abe */
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
#if defined(CONFIG_CF_AREA6)
#define slot_no 0
@@ -41,9 +40,6 @@
#define slot_no 1
#endif
-/* defined in mm/ioremap.c */
-extern void * p3_ioremap(unsigned long phys_addr, unsigned long size, unsigned long flags);
-
/* use this pointer to access to directly connected compact flash io area*/
void *cf_io_base;
@@ -62,7 +58,7 @@ static int __init allocate_cf_area(void)
return -ENOMEM;
}
/* printk("p3_ioremap(paddr=0x%08lx, psize=0x%08lx, prot=0x%08lx)=0x%08lx\n",
- paddrbase, psize, prot.pgprot, cf_io_base);*/
+ paddrbase, psize, prot.pgprot, cf_io_base);*/
/* XXX : do we need attribute and common-memory area also? */
@@ -87,7 +83,7 @@ static int __init cf_init_default(void)
}
#if defined(CONFIG_SH_SOLUTION_ENGINE)
-#include <asm/se/se.h>
+#include <asm/se.h>
/*
* SolutionEngine
diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile
index 59d5b748752f..fb5dac069382 100644
--- a/arch/sh/kernel/cpu/Makefile
+++ b/arch/sh/kernel/cpu/Makefile
@@ -8,6 +8,5 @@ obj-$(CONFIG_CPU_SH2) += sh2/
obj-$(CONFIG_CPU_SH3) += sh3/
obj-$(CONFIG_CPU_SH4) += sh4/
-obj-$(CONFIG_SH_RTC) += rtc.o
obj-$(CONFIG_UBC_WAKEUP) += ubc.o
obj-$(CONFIG_SH_ADC) += adc.o
diff --git a/arch/sh/kernel/cpu/clock.c b/arch/sh/kernel/cpu/clock.c
index 97fa37f42b84..51ec64cdf348 100644
--- a/arch/sh/kernel/cpu/clock.c
+++ b/arch/sh/kernel/cpu/clock.c
@@ -1,7 +1,7 @@
/*
* arch/sh/kernel/cpu/clock.c - SuperH clock framework
*
- * Copyright (C) 2005 Paul Mundt
+ * Copyright (C) 2005, 2006 Paul Mundt
*
* This clock framework is derived from the OMAP version by:
*
@@ -15,6 +15,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <linux/seq_file.h>
@@ -24,7 +25,7 @@
static LIST_HEAD(clock_list);
static DEFINE_SPINLOCK(clock_lock);
-static DECLARE_MUTEX(clock_list_sem);
+static DEFINE_MUTEX(clock_list_sem);
/*
* Each subtype is expected to define the init routines for these clocks,
@@ -140,21 +141,21 @@ void clk_disable(struct clk *clk)
int clk_register(struct clk *clk)
{
- down(&clock_list_sem);
+ mutex_lock(&clock_list_sem);
list_add(&clk->node, &clock_list);
kref_init(&clk->kref);
- up(&clock_list_sem);
+ mutex_unlock(&clock_list_sem);
return 0;
}
void clk_unregister(struct clk *clk)
{
- down(&clock_list_sem);
+ mutex_lock(&clock_list_sem);
list_del(&clk->node);
- up(&clock_list_sem);
+ mutex_unlock(&clock_list_sem);
}
inline unsigned long clk_get_rate(struct clk *clk)
@@ -198,14 +199,14 @@ struct clk *clk_get(const char *id)
{
struct clk *p, *clk = ERR_PTR(-ENOENT);
- down(&clock_list_sem);
+ mutex_lock(&clock_list_sem);
list_for_each_entry(p, &clock_list, node) {
if (strcmp(id, p->name) == 0 && try_module_get(p->owner)) {
clk = p;
break;
}
}
- up(&clock_list_sem);
+ mutex_unlock(&clock_list_sem);
return clk;
}
@@ -225,7 +226,7 @@ int __init clk_init(void)
{
int i, ret = 0;
- BUG_ON(unlikely(!master_clk.rate));
+ BUG_ON(!master_clk.rate);
for (i = 0; i < ARRAY_SIZE(onchip_clocks); i++) {
struct clk *clk = onchip_clocks[i];
diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c
index 868e68b28880..bfb90eb0b7a6 100644
--- a/arch/sh/kernel/cpu/init.c
+++ b/arch/sh/kernel/cpu/init.c
@@ -4,6 +4,7 @@
* CPU init code
*
* Copyright (C) 2002, 2003 Paul Mundt
+ * Copyright (C) 2003 Richard Curnow
*
* 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
@@ -13,6 +14,7 @@
#include <linux/kernel.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
+#include <asm/page.h>
#include <asm/system.h>
#include <asm/cacheflush.h>
#include <asm/cache.h>
@@ -51,7 +53,15 @@ static void __init cache_init(void)
ccr = ctrl_inl(CCR);
/*
- * If the cache is already enabled .. flush it.
+ * At this point we don't know whether the cache is enabled or not - a
+ * bootloader may have enabled it. There are at least 2 things that
+ * could be dirty in the cache at this point:
+ * 1. kernel command line set up by boot loader
+ * 2. spilled registers from the prolog of this function
+ * => before re-initialising the cache, we must do a purge of the whole
+ * cache out to memory for safety. As long as nothing is spilled
+ * during the loop to lines that have already been done, this is safe.
+ * - RPC
*/
if (ccr & CCR_CACHE_ENABLE) {
unsigned long ways, waysize, addrstart;
@@ -98,6 +108,8 @@ static void __init cache_init(void)
/* Force EMODE if possible */
if (cpu_data->dcache.ways > 1)
flags |= CCR_CACHE_EMODE;
+ else
+ flags &= ~CCR_CACHE_EMODE;
#endif
#ifdef CONFIG_SH_WRITETHROUGH
@@ -112,6 +124,9 @@ static void __init cache_init(void)
/* Turn on OCRAM -- halve the OC */
flags |= CCR_CACHE_ORA;
cpu_data->dcache.sets >>= 1;
+
+ cpu_data->dcache.way_size = cpu_data->dcache.sets *
+ cpu_data->dcache.linesz;
#endif
ctrl_outl(flags, CCR);
@@ -184,6 +199,10 @@ asmlinkage void __init sh_cpu_init(void)
/* Init the cache */
cache_init();
+ shm_align_mask = max_t(unsigned long,
+ cpu_data->dcache.way_size - 1,
+ PAGE_SIZE - 1);
+
/* Disable the FPU */
if (fpu_disabled) {
printk("FPU Disabled\n");
diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile
index e3cccea15e1d..1c034c283f59 100644
--- a/arch/sh/kernel/cpu/irq/Makefile
+++ b/arch/sh/kernel/cpu/irq/Makefile
@@ -3,5 +3,6 @@
#
obj-y += ipr.o imask.o
-obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
-obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
+obj-$(CONFIG_CPU_HAS_PINT_IRQ) += pint.o
+obj-$(CONFIG_CPU_HAS_MASKREG_IRQ) += maskreg.o
+obj-$(CONFIG_CPU_HAS_INTC2_IRQ) += intc2.o
diff --git a/arch/sh/kernel/cpu/irq/intc2.c b/arch/sh/kernel/cpu/irq/intc2.c
index 30064bf6e154..d4b2bb7e08c7 100644
--- a/arch/sh/kernel/cpu/irq/intc2.c
+++ b/arch/sh/kernel/cpu/irq/intc2.c
@@ -10,93 +10,32 @@
* These are the "new Hitachi style" interrupts, as present on the
* Hitachi 7751, the STM ST40 STB1, SH7760, and SH7780.
*/
-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/machvec.h>
-
-struct intc2_data {
- unsigned char msk_offset;
- unsigned char msk_shift;
-
- int (*clear_irq) (int);
-};
-
-static struct intc2_data intc2_data[NR_INTC2_IRQS];
-
-static void enable_intc2_irq(unsigned int irq);
-static void disable_intc2_irq(unsigned int irq);
-
-/* shutdown is same as "disable" */
-#define shutdown_intc2_irq disable_intc2_irq
-
-static void mask_and_ack_intc2(unsigned int);
-static void end_intc2_irq(unsigned int irq);
-
-static unsigned int startup_intc2_irq(unsigned int irq)
-{
- enable_intc2_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type intc2_irq_type = {
- .typename = "INTC2-IRQ",
- .startup = startup_intc2_irq,
- .shutdown = shutdown_intc2_irq,
- .enable = enable_intc2_irq,
- .disable = disable_intc2_irq,
- .ack = mask_and_ack_intc2,
- .end = end_intc2_irq
-};
static void disable_intc2_irq(unsigned int irq)
{
- int irq_offset = irq - INTC2_FIRST_IRQ;
- int msk_shift, msk_offset;
-
- /* Sanity check */
- if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
- return;
-
- msk_shift = intc2_data[irq_offset].msk_shift;
- msk_offset = intc2_data[irq_offset].msk_offset;
-
- ctrl_outl(1 << msk_shift,
- INTC2_BASE + INTC2_INTMSK_OFFSET + msk_offset);
+ struct intc2_data *p = get_irq_chip_data(irq);
+ ctrl_outl(1 << p->msk_shift,
+ INTC2_BASE + INTC2_INTMSK_OFFSET + p->msk_offset);
}
static void enable_intc2_irq(unsigned int irq)
{
- int irq_offset = irq - INTC2_FIRST_IRQ;
- int msk_shift, msk_offset;
-
- /* Sanity check */
- if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
- return;
-
- msk_shift = intc2_data[irq_offset].msk_shift;
- msk_offset = intc2_data[irq_offset].msk_offset;
-
- ctrl_outl(1 << msk_shift,
- INTC2_BASE + INTC2_INTMSKCLR_OFFSET + msk_offset);
-}
-
-static void mask_and_ack_intc2(unsigned int irq)
-{
- disable_intc2_irq(irq);
+ struct intc2_data *p = get_irq_chip_data(irq);
+ ctrl_outl(1 << p->msk_shift,
+ INTC2_BASE + INTC2_INTMSKCLR_OFFSET + p->msk_offset);
}
-static void end_intc2_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_intc2_irq(irq);
-
- if (unlikely(intc2_data[irq - INTC2_FIRST_IRQ].clear_irq))
- intc2_data[irq - INTC2_FIRST_IRQ].clear_irq(irq);
-}
+static struct irq_chip intc2_irq_chip = {
+ .typename = "intc2",
+ .mask = disable_intc2_irq,
+ .unmask = enable_intc2_irq,
+ .mask_ack = disable_intc2_irq,
+};
/*
* Setup an INTC2 style interrupt.
@@ -108,46 +47,30 @@ static void end_intc2_irq(unsigned int irq)
* | | | |
* make_intc2_irq(84, 0, 16, 0, 13);
*/
-void make_intc2_irq(unsigned int irq,
- unsigned int ipr_offset, unsigned int ipr_shift,
- unsigned int msk_offset, unsigned int msk_shift,
- unsigned int priority)
+void make_intc2_irq(struct intc2_data *p)
{
- int irq_offset = irq - INTC2_FIRST_IRQ;
unsigned int flags;
unsigned long ipr;
- if (unlikely(irq_offset < 0 || irq_offset >= NR_INTC2_IRQS))
- return;
-
- disable_irq_nosync(irq);
-
- /* Fill the data we need */
- intc2_data[irq_offset].msk_offset = msk_offset;
- intc2_data[irq_offset].msk_shift = msk_shift;
- intc2_data[irq_offset].clear_irq = NULL;
+ disable_irq_nosync(p->irq);
/* Set the priority level */
local_irq_save(flags);
- ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset);
- ipr &= ~(0xf << ipr_shift);
- ipr |= priority << ipr_shift;
- ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + ipr_offset);
+ ipr = ctrl_inl(INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset);
+ ipr &= ~(0xf << p->ipr_shift);
+ ipr |= p->priority << p->ipr_shift;
+ ctrl_outl(ipr, INTC2_BASE + INTC2_INTPRI_OFFSET + p->ipr_offset);
local_irq_restore(flags);
- irq_desc[irq].chip = &intc2_irq_type;
+ set_irq_chip_and_handler(p->irq, &intc2_irq_chip, handle_level_irq);
+ set_irq_chip_data(p->irq, p);
- disable_intc2_irq(irq);
+ enable_intc2_irq(p->irq);
}
-static struct intc2_init {
- unsigned short irq;
- unsigned char ipr_offset, ipr_shift;
- unsigned char msk_offset, msk_shift;
- unsigned char priority;
-} intc2_init_data[] __initdata = {
+static struct intc2_data intc2_irq_table[] = {
#if defined(CONFIG_CPU_SUBTYPE_ST40)
{64, 0, 0, 0, 0, 13}, /* PCI serr */
{65, 0, 4, 0, 1, 13}, /* PCI err */
@@ -241,9 +164,9 @@ static struct intc2_init {
/* 110-111 reserved/unused */
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
{ TIMER_IRQ, 0, 24, 0, INTC_TMU0_MSK, 2},
-#ifdef CONFIG_SH_RTC
- { RTC_IRQ, 4, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY },
-#endif
+ { 21, 1, 0, 0, INTC_RTC_MSK, TIMER_PRIORITY },
+ { 22, 1, 1, 0, INTC_RTC_MSK, TIMER_PRIORITY },
+ { 23, 1, 2, 0, INTC_RTC_MSK, TIMER_PRIORITY },
{ SCIF0_ERI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
{ SCIF0_RXI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
{ SCIF0_BRI_IRQ, 8, 24, 0, INTC_SCIF0_MSK, SCIF0_PRIORITY },
@@ -266,19 +189,6 @@ void __init init_IRQ_intc2(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(intc2_init_data); i++) {
- struct intc2_init *p = intc2_init_data + i;
- make_intc2_irq(p->irq, p->ipr_offset, p->ipr_shift,
- p-> msk_offset, p->msk_shift, p->priority);
- }
-}
-
-/* Adds a termination callback to the interrupt */
-void intc2_add_clear_irq(int irq, int (*fn)(int))
-{
- if (unlikely(irq < INTC2_FIRST_IRQ))
- return;
-
- intc2_data[irq - INTC2_FIRST_IRQ].clear_irq = fn;
+ for (i = 0; i < ARRAY_SIZE(intc2_irq_table); i++)
+ make_intc2_irq(intc2_irq_table + i);
}
-
diff --git a/arch/sh/kernel/cpu/irq/ipr.c b/arch/sh/kernel/cpu/irq/ipr.c
index 0f545941fb4f..8944abdf6e1c 100644
--- a/arch/sh/kernel/cpu/irq/ipr.c
+++ b/arch/sh/kernel/cpu/irq/ipr.c
@@ -1,11 +1,10 @@
/*
- * arch/sh/kernel/cpu/irq/ipr.c
+ * Interrupt handling for IPR-based IRQ.
*
* Copyright (C) 1999 Niibe Yutaka & Takeshi Yaegashi
* Copyright (C) 2000 Kazumoto Kojima
- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
- *
- * Interrupt handling for IPR-based IRQ.
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ * Copyright (C) 2006 Paul Mundt
*
* Supported system:
* On-chip supporting modules (TMU, RTC, etc.).
@@ -13,12 +12,13 @@
* Hitachi SolutionEngine external I/O:
* MS7709SE01, MS7709ASE01, and MS7750SE01
*
+ * 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/init.h>
#include <linux/irq.h>
#include <linux/module.h>
-
#include <asm/system.h>
#include <asm/io.h>
#include <asm/machvec.h>
@@ -28,102 +28,51 @@ struct ipr_data {
int shift; /* Shifts of the 16-bit data */
int priority; /* The priority */
};
-static struct ipr_data ipr_data[NR_IRQS];
-
-static void enable_ipr_irq(unsigned int irq);
-static void disable_ipr_irq(unsigned int irq);
-
-/* shutdown is same as "disable" */
-#define shutdown_ipr_irq disable_ipr_irq
-
-static void mask_and_ack_ipr(unsigned int);
-static void end_ipr_irq(unsigned int irq);
-
-static unsigned int startup_ipr_irq(unsigned int irq)
-{
- enable_ipr_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type ipr_irq_type = {
- .typename = "IPR-IRQ",
- .startup = startup_ipr_irq,
- .shutdown = shutdown_ipr_irq,
- .enable = enable_ipr_irq,
- .disable = disable_ipr_irq,
- .ack = mask_and_ack_ipr,
- .end = end_ipr_irq
-};
static void disable_ipr_irq(unsigned int irq)
{
- unsigned long val, flags;
- unsigned int addr = ipr_data[irq].addr;
- unsigned short mask = 0xffff ^ (0x0f << ipr_data[irq].shift);
-
+ struct ipr_data *p = get_irq_chip_data(irq);
/* Set the priority in IPR to 0 */
- local_irq_save(flags);
- val = ctrl_inw(addr);
- val &= mask;
- ctrl_outw(val, addr);
- local_irq_restore(flags);
+ ctrl_outw(ctrl_inw(p->addr) & (0xffff ^ (0xf << p->shift)), p->addr);
}
static void enable_ipr_irq(unsigned int irq)
{
- unsigned long val, flags;
- unsigned int addr = ipr_data[irq].addr;
- int priority = ipr_data[irq].priority;
- unsigned short value = (priority << ipr_data[irq].shift);
-
+ struct ipr_data *p = get_irq_chip_data(irq);
/* Set priority in IPR back to original value */
- local_irq_save(flags);
- val = ctrl_inw(addr);
- val |= value;
- ctrl_outw(val, addr);
- local_irq_restore(flags);
+ ctrl_outw(ctrl_inw(p->addr) | (p->priority << p->shift), p->addr);
}
-static void mask_and_ack_ipr(unsigned int irq)
-{
- disable_ipr_irq(irq);
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
- defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
- /* This is needed when we use edge triggered setting */
- /* XXX: Is it really needed? */
- if (IRQ0_IRQ <= irq && irq <= IRQ5_IRQ) {
- /* Clear external interrupt request */
- int a = ctrl_inb(INTC_IRR0);
- a &= ~(1 << (irq - IRQ0_IRQ));
- ctrl_outb(a, INTC_IRR0);
- }
-#endif
-}
-
-static void end_ipr_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- enable_ipr_irq(irq);
-}
+static struct irq_chip ipr_irq_chip = {
+ .name = "ipr",
+ .mask = disable_ipr_irq,
+ .unmask = enable_ipr_irq,
+ .mask_ack = disable_ipr_irq,
+};
void make_ipr_irq(unsigned int irq, unsigned int addr, int pos, int priority)
{
+ struct ipr_data ipr_data;
+
disable_irq_nosync(irq);
- ipr_data[irq].addr = addr;
- ipr_data[irq].shift = pos*4; /* POSition (0-3) x 4 means shift */
- ipr_data[irq].priority = priority;
- irq_desc[irq].chip = &ipr_irq_type;
- disable_ipr_irq(irq);
+ ipr_data.addr = addr;
+ ipr_data.shift = pos*4; /* POSition (0-3) x 4 means shift */
+ ipr_data.priority = priority;
+
+ set_irq_chip_and_handler(irq, &ipr_irq_chip, handle_level_irq);
+ set_irq_chip_data(irq, &ipr_data);
+
+ enable_ipr_irq(irq);
}
+/* XXX: This needs to die a horrible death.. */
void __init init_IRQ(void)
{
#ifndef CONFIG_CPU_SUBTYPE_SH7780
make_ipr_irq(TIMER_IRQ, TIMER_IPR_ADDR, TIMER_IPR_POS, TIMER_PRIORITY);
make_ipr_irq(TIMER1_IRQ, TIMER1_IPR_ADDR, TIMER1_IPR_POS, TIMER1_PRIORITY);
-#if defined(CONFIG_SH_RTC)
+#ifdef RTC_IRQ
make_ipr_irq(RTC_IRQ, RTC_IPR_ADDR, RTC_IPR_POS, RTC_PRIORITY);
#endif
@@ -162,6 +111,7 @@ void __init init_IRQ(void)
#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
/*
* Initialize the Interrupt Controller (INTC)
@@ -192,6 +142,8 @@ void __init init_IRQ(void)
/* Perform the machine specific initialisation */
if (sh_mv.mv_init_irq != NULL)
sh_mv.mv_init_irq();
+
+ irq_ctx_init(smp_processor_id());
}
#if !defined(CONFIG_CPU_HAS_PINT_IRQ)
diff --git a/arch/sh/boards/adx/irq_maskreg.c b/arch/sh/kernel/cpu/irq/maskreg.c
index 4b2abe5eb165..492db31b3cab 100644
--- a/arch/sh/boards/adx/irq_maskreg.c
+++ b/arch/sh/kernel/cpu/irq/maskreg.c
@@ -1,30 +1,23 @@
/*
- * linux/arch/sh/kernel/irq_maskreg.c
+ * Interrupt handling for Simple external interrupt mask register
*
* Copyright (C) 2001 A&D Co., Ltd. <http://www.aandd.co.jp>
*
- * This file may be copied or modified under the terms of the GNU
- * General Public License. See linux/COPYING for more information.
- *
- * Interrupt handling for Simple external interrupt mask register
- *
* This is for the machine which have single 16 bit register
* for masking external IRQ individually.
- * Each bit of the register is for masking each interrupt.
+ * Each bit of the register is for masking each interrupt.
+ *
+ * This file may be copied or modified under the terms of the GNU
+ * General Public License. See linux/COPYING for more information.
*/
-
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
-
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/machvec.h>
-/* address of external interrupt mask register
- * address must be set prior to use these (maybe in init_XXX_irq())
- * XXX : is it better to use .config than specifying it in code? */
-unsigned short *irq_mask_register = 0;
+/* address of external interrupt mask register */
+unsigned long irq_mask_register;
/* forward declaration */
static unsigned int startup_maskreg_irq(unsigned int irq);
@@ -36,7 +29,7 @@ static void end_maskreg_irq(unsigned int irq);
/* hw_interrupt_type */
static struct hw_interrupt_type maskreg_irq_type = {
- .typename = " Mask Register",
+ .typename = "Mask Register",
.startup = startup_maskreg_irq,
.shutdown = shutdown_maskreg_irq,
.enable = enable_maskreg_irq,
@@ -47,7 +40,7 @@ static struct hw_interrupt_type maskreg_irq_type = {
/* actual implementatin */
static unsigned int startup_maskreg_irq(unsigned int irq)
-{
+{
enable_maskreg_irq(irq);
return 0; /* never anything pending */
}
@@ -59,32 +52,26 @@ static void shutdown_maskreg_irq(unsigned int irq)
static void disable_maskreg_irq(unsigned int irq)
{
- if (irq_mask_register) {
- unsigned long flags;
- unsigned short val, mask = 0x01 << irq;
+ unsigned short val, mask = 0x01 << irq;
+
+ BUG_ON(!irq_mask_register);
- /* Set "irq"th bit */
- local_irq_save(flags);
- val = ctrl_inw((unsigned long)irq_mask_register);
- val |= mask;
- ctrl_outw(val, (unsigned long)irq_mask_register);
- local_irq_restore(flags);
- }
+ /* Set "irq"th bit */
+ val = ctrl_inw(irq_mask_register);
+ val |= mask;
+ ctrl_outw(val, irq_mask_register);
}
static void enable_maskreg_irq(unsigned int irq)
{
- if (irq_mask_register) {
- unsigned long flags;
- unsigned short val, mask = ~(0x01 << irq);
+ unsigned short val, mask = ~(0x01 << irq);
+
+ BUG_ON(!irq_mask_register);
- /* Clear "irq"th bit */
- local_irq_save(flags);
- val = ctrl_inw((unsigned long)irq_mask_register);
- val &= mask;
- ctrl_outw(val, (unsigned long)irq_mask_register);
- local_irq_restore(flags);
- }
+ /* Clear "irq"th bit */
+ val = ctrl_inw(irq_mask_register);
+ val &= mask;
+ ctrl_outw(val, irq_mask_register);
}
static void mask_and_ack_maskreg(unsigned int irq)
@@ -101,6 +88,6 @@ static void end_maskreg_irq(unsigned int irq)
void make_maskreg_irq(unsigned int irq)
{
disable_irq_nosync(irq);
- irq_desc[irq].chip = &maskreg_irq_type;
+ irq_desc[irq].handler = &maskreg_irq_type;
disable_maskreg_irq(irq);
}
diff --git a/arch/sh/kernel/cpu/irq/pint.c b/arch/sh/kernel/cpu/irq/pint.c
index 80cd8108d36a..17f47b373d6e 100644
--- a/arch/sh/kernel/cpu/irq/pint.c
+++ b/arch/sh/kernel/cpu/irq/pint.c
@@ -48,26 +48,22 @@ static struct hw_interrupt_type pint_irq_type = {
static void disable_pint_irq(unsigned int irq)
{
- unsigned long val, flags;
+ unsigned long val;
- local_irq_save(flags);
val = ctrl_inw(INTC_INTER);
val &= ~(1 << (irq - PINT_IRQ_BASE));
ctrl_outw(val, INTC_INTER); /* disable PINTn */
portcr_mask &= ~(3 << (irq - PINT_IRQ_BASE)*2);
- local_irq_restore(flags);
}
static void enable_pint_irq(unsigned int irq)
{
- unsigned long val, flags;
+ unsigned long val;
- local_irq_save(flags);
val = ctrl_inw(INTC_INTER);
val |= 1 << (irq - PINT_IRQ_BASE);
ctrl_outw(val, INTC_INTER); /* enable PINTn */
portcr_mask |= 3 << (irq - PINT_IRQ_BASE)*2;
- local_irq_restore(flags);
}
static void mask_and_ack_pint(unsigned int irq)
diff --git a/arch/sh/kernel/cpu/rtc.c b/arch/sh/kernel/cpu/rtc.c
deleted file mode 100644
index 4304cf75cfa2..000000000000
--- a/arch/sh/kernel/cpu/rtc.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * linux/arch/sh/kernel/rtc.c -- SH3 / SH4 on-chip RTC support
- *
- * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
- */
-
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/time.h>
-#include <linux/bcd.h>
-#include <asm/io.h>
-#include <asm/rtc.h>
-
-void sh_rtc_gettimeofday(struct timespec *ts)
-{
- unsigned int sec128, sec, sec2, min, hr, wk, day, mon, yr, yr100, cf_bit;
- unsigned long flags;
-
- again:
- do {
- local_irq_save(flags);
- ctrl_outb(0, RCR1); /* Clear CF-bit */
- sec128 = ctrl_inb(R64CNT);
- sec = ctrl_inb(RSECCNT);
- min = ctrl_inb(RMINCNT);
- hr = ctrl_inb(RHRCNT);
- wk = ctrl_inb(RWKCNT);
- day = ctrl_inb(RDAYCNT);
- mon = ctrl_inb(RMONCNT);
-#if defined(CONFIG_CPU_SH4)
- yr = ctrl_inw(RYRCNT);
- yr100 = (yr >> 8);
- yr &= 0xff;
-#else
- yr = ctrl_inb(RYRCNT);
- yr100 = (yr == 0x99) ? 0x19 : 0x20;
-#endif
- sec2 = ctrl_inb(R64CNT);
- cf_bit = ctrl_inb(RCR1) & RCR1_CF;
- local_irq_restore(flags);
- } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
-
- BCD_TO_BIN(yr100);
- BCD_TO_BIN(yr);
- BCD_TO_BIN(mon);
- BCD_TO_BIN(day);
- BCD_TO_BIN(hr);
- BCD_TO_BIN(min);
- BCD_TO_BIN(sec);
-
- if (yr > 99 || mon < 1 || mon > 12 || day > 31 || day < 1 ||
- hr > 23 || min > 59 || sec > 59) {
- printk(KERN_ERR
- "SH RTC: invalid value, resetting to 1 Jan 2000\n");
- local_irq_save(flags);
- ctrl_outb(RCR2_RESET, RCR2); /* Reset & Stop */
- ctrl_outb(0, RSECCNT);
- ctrl_outb(0, RMINCNT);
- ctrl_outb(0, RHRCNT);
- ctrl_outb(6, RWKCNT);
- ctrl_outb(1, RDAYCNT);
- ctrl_outb(1, RMONCNT);
-#if defined(CONFIG_CPU_SH4)
- ctrl_outw(0x2000, RYRCNT);
-#else
- ctrl_outb(0, RYRCNT);
-#endif
- ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start */
- goto again;
- }
-
-#if RTC_BIT_INVERTED != 0
- if ((sec128 & RTC_BIT_INVERTED))
- sec--;
-#endif
-
- ts->tv_sec = mktime(yr100 * 100 + yr, mon, day, hr, min, sec);
- ts->tv_nsec = ((sec128 * 1000000) / 128) * 1000;
-}
-
-/*
- * Changed to only care about tv_sec, and not the full timespec struct
- * (i.e. tv_nsec). It can easily be switched to timespec for future cpus
- * that support setting usec or nsec RTC values.
- */
-int sh_rtc_settimeofday(const time_t secs)
-{
- int retval = 0;
- int real_seconds, real_minutes, cmos_minutes;
- unsigned long flags;
-
- local_irq_save(flags);
- ctrl_outb(RCR2_RESET, RCR2); /* Reset pre-scaler & stop RTC */
-
- cmos_minutes = ctrl_inb(RMINCNT);
- BCD_TO_BIN(cmos_minutes);
-
- /*
- * since we're only adjusting minutes and seconds,
- * don't interfere with hour overflow. This avoids
- * messing with unknown time zones but requires your
- * RTC not to be off by more than 15 minutes
- */
- real_seconds = secs % 60;
- real_minutes = secs / 60;
- if (((abs(real_minutes - cmos_minutes) + 15)/30) & 1)
- real_minutes += 30; /* correct for half hour time zone */
- real_minutes %= 60;
-
- if (abs(real_minutes - cmos_minutes) < 30) {
- BIN_TO_BCD(real_seconds);
- BIN_TO_BCD(real_minutes);
- ctrl_outb(real_seconds, RSECCNT);
- ctrl_outb(real_minutes, RMINCNT);
- } else {
- printk(KERN_WARNING
- "set_rtc_time: can't update from %d to %d\n",
- cmos_minutes, real_minutes);
- retval = -1;
- }
-
- ctrl_outb(RCR2_RTCEN|RCR2_START, RCR2); /* Start RTC */
- local_irq_restore(flags);
-
- return retval;
-}
diff --git a/arch/sh/kernel/cpu/sh3/Makefile b/arch/sh/kernel/cpu/sh3/Makefile
index b54dbb9a0c86..58d3815695ff 100644
--- a/arch/sh/kernel/cpu/sh3/Makefile
+++ b/arch/sh/kernel/cpu/sh3/Makefile
@@ -4,10 +4,21 @@
obj-y := ex.o probe.o
+# CPU subtype setup
+obj-$(CONFIG_CPU_SUBTYPE_SH7705) += setup-sh7705.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7706) += setup-sh7709.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7707) += setup-sh7709.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7708) += setup-sh7708.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7709) += setup-sh7709.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7300) += setup-sh7300.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7710) += setup-sh7710.o
+
+# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH3) := clock-sh3.o
clock-$(CONFIG_CPU_SUBTYPE_SH7300) := clock-sh7300.o
clock-$(CONFIG_CPU_SUBTYPE_SH7705) := clock-sh7705.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7706) := clock-sh7706.o
clock-$(CONFIG_CPU_SUBTYPE_SH7709) := clock-sh7709.o
+clock-$(CONFIG_CPU_SUBTYPE_SH7710) := clock-sh7300.o
obj-y += $(clock-y)
-
diff --git a/arch/sh/kernel/cpu/sh3/clock-sh7706.c b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
new file mode 100644
index 000000000000..0cf96f9833bc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/clock-sh7706.c
@@ -0,0 +1,84 @@
+/*
+ * arch/sh/kernel/cpu/sh3/clock-sh7706.c
+ *
+ * SH7706 support for the clock framework
+ *
+ * Copyright (C) 2006 Takashi YOSHII
+ *
+ * Based on arch/sh/kernel/cpu/sh3/clock-sh7709.c
+ * Copyright (C) 2005 Andriy Skulysh
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <asm/clock.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+
+static int stc_multipliers[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
+static int ifc_divisors[] = { 1, 2, 4, 1, 3, 1, 1, 1 };
+static int pfc_divisors[] = { 1, 2, 4, 1, 3, 6, 1, 1 };
+
+static void master_clk_init(struct clk *clk)
+{
+ int frqcr = ctrl_inw(FRQCR);
+ int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
+
+ clk->rate *= pfc_divisors[idx];
+}
+
+static struct clk_ops sh7706_master_clk_ops = {
+ .init = master_clk_init,
+};
+
+static void module_clk_recalc(struct clk *clk)
+{
+ int frqcr = ctrl_inw(FRQCR);
+ int idx = ((frqcr & 0x2000) >> 11) | (frqcr & 0x0003);
+
+ clk->rate = clk->parent->rate / pfc_divisors[idx];
+}
+
+static struct clk_ops sh7706_module_clk_ops = {
+ .recalc = module_clk_recalc,
+};
+
+static void bus_clk_recalc(struct clk *clk)
+{
+ int frqcr = ctrl_inw(FRQCR);
+ int idx = ((frqcr & 0x8000) >> 13) | ((frqcr & 0x0030) >> 4);
+
+ clk->rate = clk->parent->rate / stc_multipliers[idx];
+}
+
+static struct clk_ops sh7706_bus_clk_ops = {
+ .recalc = bus_clk_recalc,
+};
+
+static void cpu_clk_recalc(struct clk *clk)
+{
+ int frqcr = ctrl_inw(FRQCR);
+ int idx = ((frqcr & 0x4000) >> 12) | ((frqcr & 0x000c) >> 2);
+
+ clk->rate = clk->parent->rate / ifc_divisors[idx];
+}
+
+static struct clk_ops sh7706_cpu_clk_ops = {
+ .recalc = cpu_clk_recalc,
+};
+
+static struct clk_ops *sh7706_clk_ops[] = {
+ &sh7706_master_clk_ops,
+ &sh7706_module_clk_ops,
+ &sh7706_bus_clk_ops,
+ &sh7706_cpu_clk_ops,
+};
+
+void __init arch_init_clk_ops(struct clk_ops **ops, int idx)
+{
+ if (idx < ARRAY_SIZE(sh7706_clk_ops))
+ *ops = sh7706_clk_ops[idx];
+}
diff --git a/arch/sh/kernel/cpu/sh3/ex.S b/arch/sh/kernel/cpu/sh3/ex.S
index cc04e9e239ff..6be46f0686b7 100644
--- a/arch/sh/kernel/cpu/sh3/ex.S
+++ b/arch/sh/kernel/cpu/sh3/ex.S
@@ -49,150 +49,3 @@ ENTRY(nmi_slot)
#endif
ENTRY(user_break_point_trap)
.long break_point_trap /* 1E0 */
-ENTRY(interrupt_table)
- ! external hardware
- .long do_IRQ ! 0000 /* 200 */
- .long do_IRQ ! 0001
- .long do_IRQ ! 0010
- .long do_IRQ ! 0011
- .long do_IRQ ! 0100
- .long do_IRQ ! 0101
- .long do_IRQ ! 0110
- .long do_IRQ ! 0111
- .long do_IRQ ! 1000 /* 300 */
- .long do_IRQ ! 1001
- .long do_IRQ ! 1010
- .long do_IRQ ! 1011
- .long do_IRQ ! 1100
- .long do_IRQ ! 1101
- .long do_IRQ ! 1110
- .long exception_error
- ! Internal hardware
- .long do_IRQ ! TMU0 tuni0 /* 400 */
- .long do_IRQ ! TMU1 tuni1
- .long do_IRQ ! TMU2 tuni2
- .long do_IRQ ! ticpi2
- .long do_IRQ ! RTC ati
- .long do_IRQ ! pri
- .long do_IRQ ! cui
- .long do_IRQ ! SCI eri
- .long do_IRQ ! rxi /* 500 */
- .long do_IRQ ! txi
- .long do_IRQ ! tei
- .long do_IRQ ! WDT iti /* 560 */
- .long do_IRQ ! REF rcmi
- .long do_IRQ ! rovi
- .long do_IRQ
- .long do_IRQ /* 5E0 */
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
- defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
- .long do_IRQ ! 32 IRQ irq0 /* 600 */
- .long do_IRQ ! 33 irq1
- .long do_IRQ ! 34 irq2
- .long do_IRQ ! 35 irq3
- .long do_IRQ ! 36 irq4
- .long do_IRQ ! 37 irq5
- .long do_IRQ ! 38
- .long do_IRQ ! 39
- .long do_IRQ ! 40 PINT pint0-7 /* 700 */
- .long do_IRQ ! 41 pint8-15
- .long do_IRQ ! 42
- .long do_IRQ ! 43
- .long do_IRQ ! 44
- .long do_IRQ ! 45
- .long do_IRQ ! 46
- .long do_IRQ ! 47
- .long do_IRQ ! 48 DMAC dei0 /* 800 */
- .long do_IRQ ! 49 dei1
- .long do_IRQ ! 50 dei2
- .long do_IRQ ! 51 dei3
- .long do_IRQ ! 52 IrDA eri1
- .long do_IRQ ! 53 rxi1
- .long do_IRQ ! 54 bri1
- .long do_IRQ ! 55 txi1
- .long do_IRQ ! 56 SCIF eri2
- .long do_IRQ ! 57 rxi2
- .long do_IRQ ! 58 bri2
- .long do_IRQ ! 59 txi2
- .long do_IRQ ! 60 ADC adi /* 980 */
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
- .long exception_none ! 61 /* 9A0 */
- .long exception_none ! 62
- .long exception_none ! 63
- .long exception_none ! 64 /* A00 */
- .long do_IRQ ! 65 USB usi0
- .long do_IRQ ! 66 usi1
- .long exception_none ! 67
- .long exception_none ! 68
- .long exception_none ! 69
- .long exception_none ! 70
- .long exception_none ! 71
- .long exception_none ! 72 /* B00 */
- .long exception_none ! 73
- .long exception_none ! 74
- .long exception_none ! 75
- .long exception_none ! 76
- .long exception_none ! 77
- .long exception_none ! 78
- .long exception_none ! 79
- .long do_IRQ ! 80 TPU0 tpi0 /* C00 */
- .long do_IRQ ! 81 TPU1 tpi1
- .long exception_none ! 82
- .long exception_none ! 83
- .long do_IRQ ! 84 TPU2 tpi2
- .long do_IRQ ! 85 TPU3 tpi3 /* CA0 */
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7300)
- .long do_IRQ ! 61 LCDC lcdi /* 9A0 */
- .long do_IRQ ! 62 PCC pcc0i
- .long do_IRQ ! 63 pcc1i /* 9E0 */
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7300)
- .long do_IRQ ! 64
- .long do_IRQ ! 65
- .long do_IRQ ! 66
- .long do_IRQ ! 67
- .long do_IRQ ! 68
- .long do_IRQ ! 69
- .long do_IRQ ! 70
- .long do_IRQ ! 71
- .long do_IRQ ! 72
- .long do_IRQ ! 73
- .long do_IRQ ! 74
- .long do_IRQ ! 75
- .long do_IRQ ! 76
- .long do_IRQ ! 77
- .long do_IRQ ! 78
- .long do_IRQ ! 79
- .long do_IRQ ! 80 SCIF0(SH7300)
- .long do_IRQ ! 81
- .long do_IRQ ! 82
- .long do_IRQ ! 83
- .long do_IRQ ! 84
- .long do_IRQ ! 85
- .long do_IRQ ! 86
- .long do_IRQ ! 87
- .long do_IRQ ! 88
- .long do_IRQ ! 89
- .long do_IRQ ! 90
- .long do_IRQ ! 91
- .long do_IRQ ! 92
- .long do_IRQ ! 93
- .long do_IRQ ! 94
- .long do_IRQ ! 95
- .long do_IRQ ! 96
- .long do_IRQ ! 97
- .long do_IRQ ! 98
- .long do_IRQ ! 99
- .long do_IRQ ! 100
- .long do_IRQ ! 101
- .long do_IRQ ! 102
- .long do_IRQ ! 103
- .long do_IRQ ! 104
- .long do_IRQ ! 105
- .long do_IRQ ! 106
- .long do_IRQ ! 107
- .long do_IRQ ! 108
-#endif
-#endif
-
diff --git a/arch/sh/kernel/cpu/sh3/probe.c b/arch/sh/kernel/cpu/sh3/probe.c
index 5cdc88638601..e67098836290 100644
--- a/arch/sh/kernel/cpu/sh3/probe.c
+++ b/arch/sh/kernel/cpu/sh3/probe.c
@@ -72,6 +72,12 @@ int __init detect_cpu_and_cache_system(void)
cpu_data->dcache.sets = 256;
cpu_data->type = CPU_SH7729;
+#if defined(CONFIG_CPU_SUBTYPE_SH7706)
+ cpu_data->type = CPU_SH7706;
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+ cpu_data->type = CPU_SH7710;
+#endif
#if defined(CONFIG_CPU_SUBTYPE_SH7705)
cpu_data->type = CPU_SH7705;
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7300.c b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
new file mode 100644
index 000000000000..ab4d204bfba5
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7300.c
@@ -0,0 +1,43 @@
+/*
+ * SH7300 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xa4430000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCI,
+ .irqs = { 80, 80, 80, 80 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7300_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7300_devices_setup(void)
+{
+ return platform_add_devices(sh7300_devices,
+ ARRAY_SIZE(sh7300_devices));
+}
+__initcall(sh7300_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7705.c b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
new file mode 100644
index 000000000000..a8e41c5241fa
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7705.c
@@ -0,0 +1,48 @@
+/*
+ * SH7705 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xa4400000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 52, 53, 55, 54 },
+ }, {
+ .mapbase = 0xa4410000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 56, 57, 59, 58 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7705_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7705_devices_setup(void)
+{
+ return platform_add_devices(sh7705_devices,
+ ARRAY_SIZE(sh7705_devices));
+}
+__initcall(sh7705_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7708.c b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
new file mode 100644
index 000000000000..f933723911ca
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7708.c
@@ -0,0 +1,43 @@
+/*
+ * SH7708 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xfffffe80,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCI,
+ .irqs = { 23, 24, 25, 0 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7708_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7708_devices_setup(void)
+{
+ return platform_add_devices(sh7708_devices,
+ ARRAY_SIZE(sh7708_devices));
+}
+__initcall(sh7708_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7709.c b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
new file mode 100644
index 000000000000..ff43ef2a1f0c
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7709.c
@@ -0,0 +1,53 @@
+/*
+ * SH7707/SH7709 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xfffffe80,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCI,
+ .irqs = { 23, 24, 25, 0 },
+ }, {
+ .mapbase = 0xa4000150,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 56, 57, 59, 58 },
+ }, {
+ .mapbase = 0xa4000140,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_IRDA,
+ .irqs = { 52, 53, 55, 54 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7709_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7709_devices_setup(void)
+{
+ return platform_add_devices(sh7709_devices,
+ ARRAY_SIZE(sh7709_devices));
+}
+__initcall(sh7709_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh3/setup-sh7710.c b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
new file mode 100644
index 000000000000..895f99ee6a95
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh3/setup-sh7710.c
@@ -0,0 +1,43 @@
+/*
+ * SH7710 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xa4400000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 52, 53, 55, 54 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7710_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7710_devices_setup(void)
+{
+ return platform_add_devices(sh7710_devices,
+ ARRAY_SIZE(sh7710_devices));
+}
+__initcall(sh7710_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/Makefile b/arch/sh/kernel/cpu/sh4/Makefile
index 3d5cafc71ae3..8dbf3895ece7 100644
--- a/arch/sh/kernel/cpu/sh4/Makefile
+++ b/arch/sh/kernel/cpu/sh4/Makefile
@@ -7,6 +7,16 @@ obj-y := ex.o probe.o
obj-$(CONFIG_SH_FPU) += fpu.o
obj-$(CONFIG_SH_STORE_QUEUES) += sq.o
+# CPU subtype setup
+obj-$(CONFIG_CPU_SUBTYPE_SH7750) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7751) += setup-sh7750.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7760) += setup-sh7760.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7770) += setup-sh7770.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7780) += setup-sh7780.o
+obj-$(CONFIG_CPU_SUBTYPE_SH73180) += setup-sh73180.o
+obj-$(CONFIG_CPU_SUBTYPE_SH7343) += setup-sh7343.o
+obj-$(CONFIG_CPU_SUBTYPE_SH4_202) += setup-sh4-202.o
+
# Primary on-chip clocks (common)
clock-$(CONFIG_CPU_SH4) := clock-sh4.o
clock-$(CONFIG_CPU_SUBTYPE_SH73180) := clock-sh73180.o
diff --git a/arch/sh/kernel/cpu/sh4/ex.S b/arch/sh/kernel/cpu/sh4/ex.S
index 26a27df06505..3f4cd043e900 100644
--- a/arch/sh/kernel/cpu/sh4/ex.S
+++ b/arch/sh/kernel/cpu/sh4/ex.S
@@ -53,331 +53,3 @@ ENTRY(nmi_slot)
#endif
ENTRY(user_break_point_trap)
.long break_point_trap /* 1E0 */
-ENTRY(interrupt_table)
- ! external hardware
- .long do_IRQ ! 0000 /* 200 */
- .long do_IRQ ! 0001
- .long do_IRQ ! 0010
- .long do_IRQ ! 0011
- .long do_IRQ ! 0100
- .long do_IRQ ! 0101
- .long do_IRQ ! 0110
- .long do_IRQ ! 0111
- .long do_IRQ ! 1000 /* 300 */
- .long do_IRQ ! 1001
- .long do_IRQ ! 1010
- .long do_IRQ ! 1011
- .long do_IRQ ! 1100
- .long do_IRQ ! 1101
- .long do_IRQ ! 1110
- .long exception_error
- ! Internal hardware
- .long do_IRQ ! TMU0 tuni0 /* 400 */
- .long do_IRQ ! TMU1 tuni1
- .long do_IRQ ! TMU2 tuni2
- .long do_IRQ ! ticpi2
-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error /* 500 */
- .long exception_error
- .long exception_error
-#else
- .long do_IRQ ! RTC ati
- .long do_IRQ ! pri
- .long do_IRQ ! cui
- .long do_IRQ ! SCI eri
- .long do_IRQ ! rxi /* 500 */
- .long do_IRQ ! txi
- .long do_IRQ ! tei
-#endif
- .long do_IRQ ! WDT iti /* 560 */
- .long do_IRQ ! REF rcmi
- .long do_IRQ ! rovi
- .long do_IRQ
- .long do_IRQ /* 5E0 */
- .long do_IRQ ! 32 Hitachi UDI /* 600 */
- .long do_IRQ ! 33 GPIO
- .long do_IRQ ! 34 DMAC dmte0
- .long do_IRQ ! 35 dmte1
- .long do_IRQ ! 36 dmte2
- .long do_IRQ ! 37 dmte3
- .long do_IRQ ! 38 dmae
- .long exception_error ! 39 /* 6E0 */
-#if defined(CONFIG_CPU_SUBTYPE_SH7760)
- .long exception_error /* 700 */
- .long exception_error
- .long exception_error
- .long exception_error /* 760 */
-#else
- .long do_IRQ ! 40 SCIF eri /* 700 */
- .long do_IRQ ! 41 rxi
- .long do_IRQ ! 42 bri
- .long do_IRQ ! 43 txi
-#endif
-#if CONFIG_NR_ONCHIP_DMA_CHANNELS == 8
- .long do_IRQ ! 44 DMAC dmte4 /* 780 */
- .long do_IRQ ! 45 dmte5
- .long do_IRQ ! 46 dmte6
- .long do_IRQ ! 47 dmte7 /* 7E0 */
-#else
- .long exception_error ! 44 /* 780 */
- .long exception_error ! 45
- .long exception_error ! 46
- .long exception_error ! 47
-#endif
-#if defined(CONFIG_SH_FPU)
- .long do_fpu_state_restore ! 48 /* 800 */
- .long do_fpu_state_restore ! 49 /* 820 */
-#else
- .long exception_error
- .long exception_error
-#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7751)
- .long exception_error /* 840 */
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error /* 900 */
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long do_IRQ ! PCI serr /* A00 */
- .long do_IRQ ! dma3
- .long do_IRQ ! dma2
- .long do_IRQ ! dma1
- .long do_IRQ ! dma0
- .long do_IRQ ! pwon
- .long do_IRQ ! pwdwn
- .long do_IRQ ! err
- .long do_IRQ ! TMU3 tuni3 /* B00 */
- .long exception_error
- .long exception_error
- .long exception_error
- .long do_IRQ ! TMU4 tuni4 /* B80 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
- .long do_IRQ ! IRQ irq6 /* 840 */
- .long do_IRQ ! irq7
- .long do_IRQ ! SCIF eri0
- .long do_IRQ ! rxi0
- .long do_IRQ ! bri0
- .long do_IRQ ! txi0
- .long do_IRQ ! HCAN2 cani0 /* 900 */
- .long do_IRQ ! cani1
- .long do_IRQ ! SSI ssii0
- .long do_IRQ ! ssii1
- .long do_IRQ ! HAC haci0
- .long do_IRQ ! haci1
- .long do_IRQ ! IIC iici0
- .long do_IRQ ! iici1
- .long do_IRQ ! USB usbi /* A00 */
- .long do_IRQ ! LCDC vint
- .long exception_error
- .long exception_error
- .long do_IRQ ! DMABRG dmabrgi0
- .long do_IRQ ! dmabrgi1
- .long do_IRQ ! dmabrgi2
- .long exception_error
- .long do_IRQ ! SCIF eri1 /* B00 */
- .long do_IRQ ! rxi1
- .long do_IRQ ! bri1
- .long do_IRQ ! txi1
- .long do_IRQ ! eri2
- .long do_IRQ ! rxi2
- .long do_IRQ ! bri2
- .long do_IRQ ! txi2
- .long do_IRQ ! SIM simeri /* C00 */
- .long do_IRQ ! simrxi
- .long do_IRQ ! simtxi
- .long do_IRQ ! simtei
- .long do_IRQ ! HSPI spii
- .long exception_error
- .long exception_error
- .long exception_error
- .long do_IRQ ! MMCIF mmci0 /* D00 */
- .long do_IRQ ! mmci1
- .long do_IRQ ! mmci2
- .long do_IRQ ! mmci3
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error /* E00 */
- .long exception_error
- .long exception_error
- .long exception_error
- .long do_IRQ ! MFI mfii
- .long exception_error
- .long exception_error
- .long exception_error
- .long exception_error /* F00 */
- .long exception_error
- .long exception_error
- .long exception_error
- .long do_IRQ ! ADC adi
- .long do_IRQ ! CMT cmti /* FA0 */
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
- .long do_IRQ ! 50 0x840
- .long do_IRQ ! 51 0x860
- .long do_IRQ ! 52 0x880
- .long do_IRQ ! 53 0x8a0
- .long do_IRQ ! 54 0x8c0
- .long do_IRQ ! 55 0x8e0
- .long do_IRQ ! 56 0x900
- .long do_IRQ ! 57 0x920
- .long do_IRQ ! 58 0x940
- .long do_IRQ ! 59 0x960
- .long do_IRQ ! 60 0x980
- .long do_IRQ ! 61 0x9a0
- .long do_IRQ ! 62 0x9c0
- .long do_IRQ ! 63 0x9e0
- .long do_IRQ ! 64 0xa00
- .long do_IRQ ! 65 0xa20
- .long do_IRQ ! 66 0xa40
- .long do_IRQ ! 67 0xa60
- .long do_IRQ ! 68 0xa80
- .long do_IRQ ! 69 0xaa0
- .long do_IRQ ! 70 0xac0
- .long do_IRQ ! 71 0xae0
- .long do_IRQ ! 72 0xb00
- .long do_IRQ ! 73 0xb20
- .long do_IRQ ! 74 0xb40
- .long do_IRQ ! 75 0xb60
- .long do_IRQ ! 76 0xb80
- .long do_IRQ ! 77 0xba0
- .long do_IRQ ! 78 0xbc0
- .long do_IRQ ! 79 0xbe0
- .long do_IRQ ! 80 0xc00
- .long do_IRQ ! 81 0xc20
- .long do_IRQ ! 82 0xc40
- .long do_IRQ ! 83 0xc60
- .long do_IRQ ! 84 0xc80
- .long do_IRQ ! 85 0xca0
- .long do_IRQ ! 86 0xcc0
- .long do_IRQ ! 87 0xce0
- .long do_IRQ ! 88 0xd00
- .long do_IRQ ! 89 0xd20
- .long do_IRQ ! 90 0xd40
- .long do_IRQ ! 91 0xd60
- .long do_IRQ ! 92 0xd80
- .long do_IRQ ! 93 0xda0
- .long do_IRQ ! 94 0xdc0
- .long do_IRQ ! 95 0xde0
- .long do_IRQ ! 96 0xe00
- .long do_IRQ ! 97 0xe20
- .long do_IRQ ! 98 0xe40
- .long do_IRQ ! 99 0xe60
- .long do_IRQ ! 100 0xe80
- .long do_IRQ ! 101 0xea0
- .long do_IRQ ! 102 0xec0
- .long do_IRQ ! 103 0xee0
- .long do_IRQ ! 104 0xf00
- .long do_IRQ ! 105 0xf20
- .long do_IRQ ! 106 0xf40
- .long do_IRQ ! 107 0xf60
- .long do_IRQ ! 108 0xf80
-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
- .long exception_error ! 50 0x840
- .long exception_error ! 51 0x860
- .long exception_error ! 52 0x880
- .long exception_error ! 53 0x8a0
- .long exception_error ! 54 0x8c0
- .long exception_error ! 55 0x8e0
- .long exception_error ! 56 0x900
- .long exception_error ! 57 0x920
- .long exception_error ! 58 0x940
- .long exception_error ! 59 0x960
- .long exception_error ! 60 0x980
- .long exception_error ! 61 0x9a0
- .long exception_error ! 62 0x9c0
- .long exception_error ! 63 0x9e0
- .long do_IRQ ! 64 0xa00 PCI serr
- .long do_IRQ ! 65 0xa20 err
- .long do_IRQ ! 66 0xa40 ad
- .long do_IRQ ! 67 0xa60 pwr_dwn
- .long exception_error ! 68 0xa80
- .long exception_error ! 69 0xaa0
- .long exception_error ! 70 0xac0
- .long exception_error ! 71 0xae0
- .long do_IRQ ! 72 0xb00 DMA INT0
- .long do_IRQ ! 73 0xb20 INT1
- .long do_IRQ ! 74 0xb40 INT2
- .long do_IRQ ! 75 0xb60 INT3
- .long do_IRQ ! 76 0xb80 INT4
- .long exception_error ! 77 0xba0
- .long do_IRQ ! 78 0xbc0 DMA ERR
- .long exception_error ! 79 0xbe0
- .long do_IRQ ! 80 0xc00 PIO0
- .long do_IRQ ! 81 0xc20 PIO1
- .long do_IRQ ! 82 0xc40 PIO2
- .long exception_error ! 83 0xc60
- .long exception_error ! 84 0xc80
- .long exception_error ! 85 0xca0
- .long exception_error ! 86 0xcc0
- .long exception_error ! 87 0xce0
- .long exception_error ! 88 0xd00
- .long exception_error ! 89 0xd20
- .long exception_error ! 90 0xd40
- .long exception_error ! 91 0xd60
- .long exception_error ! 92 0xd80
- .long exception_error ! 93 0xda0
- .long exception_error ! 94 0xdc0
- .long exception_error ! 95 0xde0
- .long exception_error ! 96 0xe00
- .long exception_error ! 97 0xe20
- .long exception_error ! 98 0xe40
- .long exception_error ! 99 0xe60
- .long exception_error ! 100 0xe80
- .long exception_error ! 101 0xea0
- .long exception_error ! 102 0xec0
- .long exception_error ! 103 0xee0
- .long exception_error ! 104 0xf00
- .long exception_error ! 105 0xf20
- .long exception_error ! 106 0xf40
- .long exception_error ! 107 0xf60
- .long exception_error ! 108 0xf80
- .long exception_error ! 109 0xfa0
- .long exception_error ! 110 0xfc0
- .long exception_error ! 111 0xfe0
- .long do_IRQ ! 112 0x1000 Mailbox
- .long exception_error ! 113 0x1020
- .long exception_error ! 114 0x1040
- .long exception_error ! 115 0x1060
- .long exception_error ! 116 0x1080
- .long exception_error ! 117 0x10a0
- .long exception_error ! 118 0x10c0
- .long exception_error ! 119 0x10e0
- .long exception_error ! 120 0x1100
- .long exception_error ! 121 0x1120
- .long exception_error ! 122 0x1140
- .long exception_error ! 123 0x1160
- .long exception_error ! 124 0x1180
- .long exception_error ! 125 0x11a0
- .long exception_error ! 126 0x11c0
- .long exception_error ! 127 0x11e0
- .long exception_error ! 128 0x1200
- .long exception_error ! 129 0x1220
- .long exception_error ! 130 0x1240
- .long exception_error ! 131 0x1260
- .long exception_error ! 132 0x1280
- .long exception_error ! 133 0x12a0
- .long exception_error ! 134 0x12c0
- .long exception_error ! 135 0x12e0
- .long exception_error ! 136 0x1300
- .long exception_error ! 137 0x1320
- .long exception_error ! 138 0x1340
- .long exception_error ! 139 0x1360
- .long do_IRQ ! 140 0x1380 EMPI INV_ADDR
- .long exception_error ! 141 0x13a0
- .long exception_error ! 142 0x13c0
- .long exception_error ! 143 0x13e0
-#endif
-
diff --git a/arch/sh/kernel/cpu/sh4/probe.c b/arch/sh/kernel/cpu/sh4/probe.c
index 42427b79697b..c294de1e14a3 100644
--- a/arch/sh/kernel/cpu/sh4/probe.c
+++ b/arch/sh/kernel/cpu/sh4/probe.c
@@ -3,7 +3,7 @@
*
* CPU Subtype Probing for SH-4.
*
- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2001 - 2006 Paul Mundt
* Copyright (C) 2003 Richard Curnow
*
* This file is subject to the terms and conditions of the GNU General Public
@@ -29,7 +29,7 @@ int __init detect_cpu_and_cache_system(void)
[9] = (1 << 16)
};
- pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffff;
+ pvr = (ctrl_inl(CCN_PVR) >> 8) & 0xffffff;
prr = (ctrl_inl(CCN_PRR) >> 4) & 0xff;
cvr = (ctrl_inl(CCN_CVR));
@@ -38,7 +38,6 @@ int __init detect_cpu_and_cache_system(void)
*/
cpu_data->icache.way_incr = (1 << 13);
cpu_data->icache.entry_shift = 5;
- cpu_data->icache.entry_mask = 0x1fe0;
cpu_data->icache.sets = 256;
cpu_data->icache.ways = 1;
cpu_data->icache.linesz = L1_CACHE_BYTES;
@@ -48,13 +47,29 @@ int __init detect_cpu_and_cache_system(void)
*/
cpu_data->dcache.way_incr = (1 << 14);
cpu_data->dcache.entry_shift = 5;
- cpu_data->dcache.entry_mask = 0x3fe0;
cpu_data->dcache.sets = 512;
cpu_data->dcache.ways = 1;
cpu_data->dcache.linesz = L1_CACHE_BYTES;
- /* Set the FPU flag, virtually all SH-4's have one */
- cpu_data->flags |= CPU_HAS_FPU;
+ /*
+ * Setup some generic flags we can probe
+ * (L2 and DSP detection only work on SH-4A)
+ */
+ if (((pvr >> 16) & 0xff) == 0x10) {
+ if ((cvr & 0x02000000) == 0)
+ cpu_data->flags |= CPU_HAS_L2_CACHE;
+ if ((cvr & 0x10000000) == 0)
+ cpu_data->flags |= CPU_HAS_DSP;
+
+ cpu_data->flags |= CPU_HAS_LLSC;
+ }
+
+ /* FPU detection works for everyone */
+ if ((cvr & 0x20000000) == 1)
+ cpu_data->flags |= CPU_HAS_FPU;
+
+ /* Mask off the upper chip ID */
+ pvr &= 0xffff;
/*
* Probe the underlying processor version/revision and
@@ -63,56 +78,101 @@ int __init detect_cpu_and_cache_system(void)
switch (pvr) {
case 0x205:
cpu_data->type = CPU_SH7750;
- cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+ cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+ CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
break;
case 0x206:
cpu_data->type = CPU_SH7750S;
- cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_PERF_COUNTER;
+ cpu_data->flags |= CPU_HAS_P2_FLUSH_BUG | CPU_HAS_FPU |
+ CPU_HAS_PERF_COUNTER | CPU_HAS_PTEA;
break;
case 0x1100:
cpu_data->type = CPU_SH7751;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x2000:
cpu_data->type = CPU_SH73180;
cpu_data->icache.ways = 4;
cpu_data->dcache.ways = 4;
- cpu_data->flags &= ~CPU_HAS_FPU;
+ cpu_data->flags |= CPU_HAS_LLSC;
+ break;
+ case 0x2001:
+ case 0x2004:
+ cpu_data->type = CPU_SH7770;
+ cpu_data->icache.ways = 4;
+ cpu_data->dcache.ways = 4;
+
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_LLSC;
+ break;
+ case 0x2006:
+ case 0x200A:
+ if (prr == 0x61)
+ cpu_data->type = CPU_SH7781;
+ else
+ cpu_data->type = CPU_SH7780;
+
+ cpu_data->icache.ways = 4;
+ cpu_data->dcache.ways = 4;
+
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PERF_COUNTER |
+ CPU_HAS_LLSC;
+ break;
+ case 0x3000:
+ case 0x3003:
+ cpu_data->type = CPU_SH7343;
+ cpu_data->icache.ways = 4;
+ cpu_data->dcache.ways = 4;
+ cpu_data->flags |= CPU_HAS_LLSC;
break;
case 0x8000:
cpu_data->type = CPU_ST40RA;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x8100:
cpu_data->type = CPU_ST40GX1;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x700:
cpu_data->type = CPU_SH4_501;
cpu_data->icache.ways = 2;
cpu_data->dcache.ways = 2;
-
- /* No FPU on the SH4-500 series.. */
- cpu_data->flags &= ~CPU_HAS_FPU;
+ cpu_data->flags |= CPU_HAS_PTEA;
break;
case 0x600:
cpu_data->type = CPU_SH4_202;
cpu_data->icache.ways = 2;
cpu_data->dcache.ways = 2;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
break;
case 0x500 ... 0x501:
switch (prr) {
- case 0x10: cpu_data->type = CPU_SH7750R; break;
- case 0x11: cpu_data->type = CPU_SH7751R; break;
- case 0x50: cpu_data->type = CPU_SH7760; break;
+ case 0x10:
+ cpu_data->type = CPU_SH7750R;
+ break;
+ case 0x11:
+ cpu_data->type = CPU_SH7751R;
+ break;
+ case 0x50 ... 0x5f:
+ cpu_data->type = CPU_SH7760;
+ break;
}
cpu_data->icache.ways = 2;
cpu_data->dcache.ways = 2;
+ cpu_data->flags |= CPU_HAS_FPU | CPU_HAS_PTEA;
+
break;
default:
cpu_data->type = CPU_SH_NONE;
break;
}
+#ifdef CONFIG_SH_DIRECT_MAPPED
+ cpu_data->icache.ways = 1;
+ cpu_data->dcache.ways = 1;
+#endif
+
/*
* On anything that's not a direct-mapped cache, look to the CVR
* for I/D-cache specifics.
@@ -121,18 +181,56 @@ int __init detect_cpu_and_cache_system(void)
size = sizes[(cvr >> 20) & 0xf];
cpu_data->icache.way_incr = (size >> 1);
cpu_data->icache.sets = (size >> 6);
- cpu_data->icache.entry_mask =
- (cpu_data->icache.way_incr - (1 << 5));
+
}
+ /* Setup the rest of the I-cache info */
+ cpu_data->icache.entry_mask = cpu_data->icache.way_incr -
+ cpu_data->icache.linesz;
+
+ cpu_data->icache.way_size = cpu_data->icache.sets *
+ cpu_data->icache.linesz;
+
+ /* And the rest of the D-cache */
if (cpu_data->dcache.ways > 1) {
size = sizes[(cvr >> 16) & 0xf];
cpu_data->dcache.way_incr = (size >> 1);
cpu_data->dcache.sets = (size >> 6);
- cpu_data->dcache.entry_mask =
- (cpu_data->dcache.way_incr - (1 << 5));
+ }
+
+ cpu_data->dcache.entry_mask = cpu_data->dcache.way_incr -
+ cpu_data->dcache.linesz;
+
+ cpu_data->dcache.way_size = cpu_data->dcache.sets *
+ cpu_data->dcache.linesz;
+
+ /*
+ * Setup the L2 cache desc
+ *
+ * SH-4A's have an optional PIPT L2.
+ */
+ if (cpu_data->flags & CPU_HAS_L2_CACHE) {
+ /*
+ * Size calculation is much more sensible
+ * than it is for the L1.
+ *
+ * Sizes are 128KB, 258KB, 512KB, and 1MB.
+ */
+ size = (cvr & 0xf) << 17;
+
+ BUG_ON(!size);
+
+ cpu_data->scache.way_incr = (1 << 16);
+ cpu_data->scache.entry_shift = 5;
+ cpu_data->scache.ways = 4;
+ cpu_data->scache.linesz = L1_CACHE_BYTES;
+ cpu_data->scache.entry_mask =
+ (cpu_data->scache.way_incr - cpu_data->scache.linesz);
+ cpu_data->scache.sets = size /
+ (cpu_data->scache.linesz * cpu_data->scache.ways);
+ cpu_data->scache.way_size =
+ (cpu_data->scache.sets * cpu_data->scache.linesz);
}
return 0;
}
-
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh4-202.c b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
new file mode 100644
index 000000000000..6e4e96541358
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh4-202.c
@@ -0,0 +1,43 @@
+/*
+ * SH4-202 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe80000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh4202_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh4202_devices_setup(void)
+{
+ return platform_add_devices(sh4202_devices,
+ ARRAY_SIZE(sh4202_devices));
+}
+__initcall(sh4202_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh73180.c b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
new file mode 100644
index 000000000000..cc9ea1e2e5df
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh73180.c
@@ -0,0 +1,43 @@
+/*
+ * SH73180 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe80000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 80, 81, 83, 82 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh73180_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh73180_devices_setup(void)
+{
+ return platform_add_devices(sh73180_devices,
+ ARRAY_SIZE(sh73180_devices));
+}
+__initcall(sh73180_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7343.c b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
new file mode 100644
index 000000000000..91d61cf91ba1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7343.c
@@ -0,0 +1,43 @@
+/*
+ * SH7343 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe00000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 80, 81, 83, 82 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7343_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7343_devices_setup(void)
+{
+ return platform_add_devices(sh7343_devices,
+ ARRAY_SIZE(sh7343_devices));
+}
+__initcall(sh7343_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7750.c b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
new file mode 100644
index 000000000000..50812d57c1c1
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7750.c
@@ -0,0 +1,48 @@
+/*
+ * SH7750/SH7751 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe00000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCI,
+ .irqs = { 23, 24, 25, 0 },
+ }, {
+ .mapbase = 0xffe80000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7750_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7750_devices_setup(void)
+{
+ return platform_add_devices(sh7750_devices,
+ ARRAY_SIZE(sh7750_devices));
+}
+__initcall(sh7750_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7760.c b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
new file mode 100644
index 000000000000..97f1c9af35d6
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7760.c
@@ -0,0 +1,53 @@
+/*
+ * SH7760 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xfe600000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 52, 53, 55, 54 },
+ }, {
+ .mapbase = 0xfe610000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 72, 73, 75, 74 },
+ }, {
+ .mapbase = 0xfe620000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 76, 77, 79, 78 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7760_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7760_devices_setup(void)
+{
+ return platform_add_devices(sh7760_devices,
+ ARRAY_SIZE(sh7760_devices));
+}
+__initcall(sh7760_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7770.c b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
new file mode 100644
index 000000000000..6a04cc5f5aca
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7770.c
@@ -0,0 +1,53 @@
+/*
+ * SH7770 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xff923000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 61, 61, 61, 61 },
+ }, {
+ .mapbase = 0xff924000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 62, 62, 62, 62 },
+ }, {
+ .mapbase = 0xff925000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 63, 63, 63, 63 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7770_devices[] __initdata = {
+ &sci_device,
+};
+
+static int __init sh7770_devices_setup(void)
+{
+ return platform_add_devices(sh7770_devices,
+ ARRAY_SIZE(sh7770_devices));
+}
+__initcall(sh7770_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/setup-sh7780.c b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
new file mode 100644
index 000000000000..72493f259edc
--- /dev/null
+++ b/arch/sh/kernel/cpu/sh4/setup-sh7780.c
@@ -0,0 +1,79 @@
+/*
+ * SH7780 Setup
+ *
+ * Copyright (C) 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/platform_device.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <asm/sci.h>
+
+static struct resource rtc_resources[] = {
+ [0] = {
+ .start = 0xffe80000,
+ .end = 0xffe80000 + 0x58 - 1,
+ .flags = IORESOURCE_IO,
+ },
+ [1] = {
+ /* Period IRQ */
+ .start = 21,
+ .flags = IORESOURCE_IRQ,
+ },
+ [2] = {
+ /* Carry IRQ */
+ .start = 22,
+ .flags = IORESOURCE_IRQ,
+ },
+ [3] = {
+ /* Alarm IRQ */
+ .start = 23,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device rtc_device = {
+ .name = "sh-rtc",
+ .id = -1,
+ .num_resources = ARRAY_SIZE(rtc_resources),
+ .resource = rtc_resources,
+};
+
+static struct plat_sci_port sci_platform_data[] = {
+ {
+ .mapbase = 0xffe00000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 40, 41, 43, 42 },
+ }, {
+ .mapbase = 0xffe10000,
+ .flags = UPF_BOOT_AUTOCONF,
+ .type = PORT_SCIF,
+ .irqs = { 76, 77, 79, 78 },
+ }, {
+ .flags = 0,
+ }
+};
+
+static struct platform_device sci_device = {
+ .name = "sh-sci",
+ .id = -1,
+ .dev = {
+ .platform_data = sci_platform_data,
+ },
+};
+
+static struct platform_device *sh7780_devices[] __initdata = {
+ &rtc_device,
+ &sci_device,
+};
+
+static int __init sh7780_devices_setup(void)
+{
+ return platform_add_devices(sh7780_devices,
+ ARRAY_SIZE(sh7780_devices));
+}
+__initcall(sh7780_devices_setup);
diff --git a/arch/sh/kernel/cpu/sh4/sq.c b/arch/sh/kernel/cpu/sh4/sq.c
index b09805f3ee23..7bcc73f9b8df 100644
--- a/arch/sh/kernel/cpu/sh4/sq.c
+++ b/arch/sh/kernel/cpu/sh4/sq.c
@@ -1,49 +1,52 @@
/*
- * arch/sh/kernel/cpu/sq.c
+ * arch/sh/kernel/cpu/sh4/sq.c
*
* General management API for SH-4 integrated Store Queues
*
- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2001 - 2006 Paul Mundt
* Copyright (C) 2001, 2002 M. R. Brown
*
- * Some of this code has been adopted directly from the old arch/sh/mm/sq.c
- * hack that was part of the LinuxDC project. For all intents and purposes,
- * this is a completely new interface that really doesn't have much in common
- * with the old zone-based approach at all. In fact, it's only listed here for
- * general completeness.
- *
* 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/init.h>
+#include <linux/cpu.h>
+#include <linux/bitmap.h>
+#include <linux/sysdev.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/proc_fs.h>
-#include <linux/miscdevice.h>
#include <linux/vmalloc.h>
-
+#include <linux/mm.h>
#include <asm/io.h>
#include <asm/page.h>
-#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
#include <asm/cpu/sq.h>
-static LIST_HEAD(sq_mapping_list);
+struct sq_mapping;
+
+struct sq_mapping {
+ const char *name;
+
+ unsigned long sq_addr;
+ unsigned long addr;
+ unsigned int size;
+
+ struct sq_mapping *next;
+};
+
+static struct sq_mapping *sq_mapping_list;
static DEFINE_SPINLOCK(sq_mapping_lock);
+static kmem_cache_t *sq_cache;
+static unsigned long *sq_bitmap;
-/**
- * sq_flush - Flush (prefetch) the store queue cache
- * @addr: the store queue address to flush
- *
- * Executes a prefetch instruction on the specified store queue cache,
- * so that the cached data is written to physical memory.
- */
-inline void sq_flush(void *addr)
-{
- __asm__ __volatile__ ("pref @%0" : : "r" (addr) : "memory");
-}
+#define store_queue_barrier() \
+do { \
+ (void)ctrl_inl(P4SEG_STORE_QUE); \
+ ctrl_outl(0, P4SEG_STORE_QUE + 0); \
+ ctrl_outl(0, P4SEG_STORE_QUE + 8); \
+} while (0);
/**
* sq_flush_range - Flush (prefetch) a specific SQ range
@@ -56,152 +59,73 @@ inline void sq_flush(void *addr)
void sq_flush_range(unsigned long start, unsigned int len)
{
volatile unsigned long *sq = (unsigned long *)start;
- unsigned long dummy;
/* Flush the queues */
for (len >>= 5; len--; sq += 8)
- sq_flush((void *)sq);
+ prefetchw((void *)sq);
/* Wait for completion */
- dummy = ctrl_inl(P4SEG_STORE_QUE);
-
- ctrl_outl(0, P4SEG_STORE_QUE + 0);
- ctrl_outl(0, P4SEG_STORE_QUE + 8);
+ store_queue_barrier();
}
-static struct sq_mapping *__sq_alloc_mapping(unsigned long virt, unsigned long phys, unsigned long size, const char *name)
+static inline void sq_mapping_list_add(struct sq_mapping *map)
{
- struct sq_mapping *map;
-
- if (virt + size > SQ_ADDRMAX)
- return ERR_PTR(-ENOSPC);
-
- map = kmalloc(sizeof(struct sq_mapping), GFP_KERNEL);
- if (!map)
- return ERR_PTR(-ENOMEM);
+ struct sq_mapping **p, *tmp;
- INIT_LIST_HEAD(&map->list);
+ spin_lock_irq(&sq_mapping_lock);
- map->sq_addr = virt;
- map->addr = phys;
- map->size = size + 1;
- map->name = name;
+ p = &sq_mapping_list;
+ while ((tmp = *p) != NULL)
+ p = &tmp->next;
- list_add(&map->list, &sq_mapping_list);
+ map->next = tmp;
+ *p = map;
- return map;
+ spin_unlock_irq(&sq_mapping_lock);
}
-static unsigned long __sq_get_next_addr(void)
+static inline void sq_mapping_list_del(struct sq_mapping *map)
{
- if (!list_empty(&sq_mapping_list)) {
- struct list_head *pos, *tmp;
-
- /*
- * Read one off the list head, as it will have the highest
- * mapped allocation. Set the next one up right above it.
- *
- * This is somewhat sub-optimal, as we don't look at
- * gaps between allocations or anything lower then the
- * highest-level allocation.
- *
- * However, in the interest of performance and the general
- * lack of desire to do constant list rebalancing, we don't
- * worry about it.
- */
- list_for_each_safe(pos, tmp, &sq_mapping_list) {
- struct sq_mapping *entry;
-
- entry = list_entry(pos, typeof(*entry), list);
-
- return entry->sq_addr + entry->size;
+ struct sq_mapping **p, *tmp;
+
+ spin_lock_irq(&sq_mapping_lock);
+
+ for (p = &sq_mapping_list; (tmp = *p); p = &tmp->next)
+ if (tmp == map) {
+ *p = tmp->next;
+ break;
}
- }
- return P4SEG_STORE_QUE;
+ spin_unlock_irq(&sq_mapping_lock);
}
-/**
- * __sq_remap - Perform a translation from the SQ to a phys addr
- * @map: sq mapping containing phys and store queue addresses.
- *
- * Maps the store queue address specified in the mapping to the physical
- * address specified in the mapping.
- */
-static struct sq_mapping *__sq_remap(struct sq_mapping *map)
+static int __sq_remap(struct sq_mapping *map, unsigned long flags)
{
- unsigned long flags, pteh, ptel;
+#if defined(CONFIG_MMU)
struct vm_struct *vma;
- pgprot_t pgprot;
-
- /*
- * Without an MMU (or with it turned off), this is much more
- * straightforward, as we can just load up each queue's QACR with
- * the physical address appropriately masked.
- */
-
- ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
- ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
-#ifdef CONFIG_MMU
- /*
- * With an MMU on the other hand, things are slightly more involved.
- * Namely, we have to have a direct mapping between the SQ addr and
- * the associated physical address in the UTLB by way of setting up
- * a virt<->phys translation by hand. We do this by simply specifying
- * the SQ addr in UTLB.VPN and the associated physical address in
- * UTLB.PPN.
- *
- * Notably, even though this is a special case translation, and some
- * of the configuration bits are meaningless, we're still required
- * to have a valid ASID context in PTEH.
- *
- * We could also probably get by without explicitly setting PTEA, but
- * we do it here just for good measure.
- */
- spin_lock_irqsave(&sq_mapping_lock, flags);
-
- pteh = map->sq_addr;
- ctrl_outl((pteh & MMU_VPN_MASK) | get_asid(), MMU_PTEH);
-
- ptel = map->addr & PAGE_MASK;
- ctrl_outl(((ptel >> 28) & 0xe) | (ptel & 0x1), MMU_PTEA);
-
- pgprot = pgprot_noncached(PAGE_KERNEL);
-
- ptel &= _PAGE_FLAGS_HARDWARE_MASK;
- ptel |= pgprot_val(pgprot);
- ctrl_outl(ptel, MMU_PTEL);
-
- __asm__ __volatile__ ("ldtlb" : : : "memory");
-
- spin_unlock_irqrestore(&sq_mapping_lock, flags);
-
- /*
- * Next, we need to map ourselves in the kernel page table, so that
- * future accesses after a TLB flush will be handled when we take a
- * page fault.
- *
- * Theoretically we could just do this directly and not worry about
- * setting up the translation by hand ahead of time, but for the
- * cases where we want a one-shot SQ mapping followed by a quick
- * writeout before we hit the TLB flush, we do it anyways. This way
- * we at least save ourselves the initial page fault overhead.
- */
vma = __get_vm_area(map->size, VM_ALLOC, map->sq_addr, SQ_ADDRMAX);
if (!vma)
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
vma->phys_addr = map->addr;
if (remap_area_pages((unsigned long)vma->addr, vma->phys_addr,
- map->size, pgprot_val(pgprot))) {
+ map->size, flags)) {
vunmap(vma->addr);
- return NULL;
+ return -EAGAIN;
}
-#endif /* CONFIG_MMU */
+#else
+ /*
+ * Without an MMU (or with it turned off), this is much more
+ * straightforward, as we can just load up each queue's QACR with
+ * the physical address appropriately masked.
+ */
+ ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR0);
+ ctrl_outl(((map->addr >> 26) << 2) & 0x1c, SQ_QACR1);
+#endif
- return map;
+ return 0;
}
/**
@@ -209,42 +133,65 @@ static struct sq_mapping *__sq_remap(struct sq_mapping *map)
* @phys: Physical address of mapping.
* @size: Length of mapping.
* @name: User invoking mapping.
+ * @flags: Protection flags.
*
* Remaps the physical address @phys through the next available store queue
* address of @size length. @name is logged at boot time as well as through
- * the procfs interface.
- *
- * A pre-allocated and filled sq_mapping pointer is returned, and must be
- * cleaned up with a call to sq_unmap() when the user is done with the
- * mapping.
+ * the sysfs interface.
*/
-struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name)
+unsigned long sq_remap(unsigned long phys, unsigned int size,
+ const char *name, unsigned long flags)
{
struct sq_mapping *map;
- unsigned long virt, end;
+ unsigned long end;
unsigned int psz;
+ int ret, page;
/* Don't allow wraparound or zero size */
end = phys + size - 1;
- if (!size || end < phys)
- return NULL;
+ if (unlikely(!size || end < phys))
+ return -EINVAL;
/* Don't allow anyone to remap normal memory.. */
- if (phys < virt_to_phys(high_memory))
- return NULL;
+ if (unlikely(phys < virt_to_phys(high_memory)))
+ return -EINVAL;
phys &= PAGE_MASK;
+ size = PAGE_ALIGN(end + 1) - phys;
+
+ map = kmem_cache_alloc(sq_cache, GFP_KERNEL);
+ if (unlikely(!map))
+ return -ENOMEM;
+
+ map->addr = phys;
+ map->size = size;
+ map->name = name;
+
+ page = bitmap_find_free_region(sq_bitmap, 0x04000000,
+ get_order(map->size));
+ if (unlikely(page < 0)) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ map->sq_addr = P4SEG_STORE_QUE + (page << PAGE_SHIFT);
+
+ ret = __sq_remap(map, flags);
+ if (unlikely(ret != 0))
+ goto out;
+
+ psz = (size + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ pr_info("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n",
+ likely(map->name) ? map->name : "???",
+ psz, psz == 1 ? " " : "s",
+ map->sq_addr, map->addr);
- size = PAGE_ALIGN(end + 1) - phys;
- virt = __sq_get_next_addr();
- psz = (size + (PAGE_SIZE - 1)) / PAGE_SIZE;
- map = __sq_alloc_mapping(virt, phys, size, name);
+ sq_mapping_list_add(map);
- printk("sqremap: %15s [%4d page%s] va 0x%08lx pa 0x%08lx\n",
- map->name ? map->name : "???",
- psz, psz == 1 ? " " : "s",
- map->sq_addr, map->addr);
+ return map->sq_addr;
- return __sq_remap(map);
+out:
+ kmem_cache_free(sq_cache, map);
+ return ret;
}
/**
@@ -255,188 +202,198 @@ struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *n
* sq_remap(). Also frees up the pte that was previously inserted into
* the kernel page table and discards the UTLB translation.
*/
-void sq_unmap(struct sq_mapping *map)
+void sq_unmap(unsigned long vaddr)
{
- if (map->sq_addr > (unsigned long)high_memory)
- vfree((void *)(map->sq_addr & PAGE_MASK));
+ struct sq_mapping **p, *map;
+ struct vm_struct *vma;
+ int page;
- list_del(&map->list);
- kfree(map);
-}
+ for (p = &sq_mapping_list; (map = *p); p = &map->next)
+ if (map->sq_addr == vaddr)
+ break;
-/**
- * sq_clear - Clear a store queue range
- * @addr: Address to start clearing from.
- * @len: Length to clear.
- *
- * A quick zero-fill implementation for clearing out memory that has been
- * remapped through the store queues.
- */
-void sq_clear(unsigned long addr, unsigned int len)
-{
- int i;
+ if (unlikely(!map)) {
+ printk("%s: bad store queue address 0x%08lx\n",
+ __FUNCTION__, vaddr);
+ return;
+ }
- /* Clear out both queues linearly */
- for (i = 0; i < 8; i++) {
- ctrl_outl(0, addr + i + 0);
- ctrl_outl(0, addr + i + 8);
+ page = (map->sq_addr - P4SEG_STORE_QUE) >> PAGE_SHIFT;
+ bitmap_release_region(sq_bitmap, page, get_order(map->size));
+
+#ifdef CONFIG_MMU
+ vma = remove_vm_area((void *)(map->sq_addr & PAGE_MASK));
+ if (!vma) {
+ printk(KERN_ERR "%s: bad address 0x%08lx\n",
+ __FUNCTION__, map->sq_addr);
+ return;
}
+#endif
+
+ sq_mapping_list_del(map);
- sq_flush_range(addr, len);
+ kmem_cache_free(sq_cache, map);
}
-/**
- * sq_vma_unmap - Unmap a VMA range
- * @area: VMA containing range.
- * @addr: Start of range.
- * @len: Length of range.
+/*
+ * Needlessly complex sysfs interface. Unfortunately it doesn't seem like
+ * there is any other easy way to add things on a per-cpu basis without
+ * putting the directory entries somewhere stupid and having to create
+ * links in sysfs by hand back in to the per-cpu directories.
*
- * Searches the sq_mapping_list for a mapping matching the sq addr @addr,
- * and subsequently frees up the entry. Further cleanup is done by generic
- * code.
+ * Some day we may want to have an additional abstraction per store
+ * queue, but considering the kobject hell we already have to deal with,
+ * it's simply not worth the trouble.
*/
-static void sq_vma_unmap(struct vm_area_struct *area,
- unsigned long addr, size_t len)
-{
- struct list_head *pos, *tmp;
+static struct kobject *sq_kobject[NR_CPUS];
- list_for_each_safe(pos, tmp, &sq_mapping_list) {
- struct sq_mapping *entry;
+struct sq_sysfs_attr {
+ struct attribute attr;
+ ssize_t (*show)(char *buf);
+ ssize_t (*store)(const char *buf, size_t count);
+};
- entry = list_entry(pos, typeof(*entry), list);
+#define to_sq_sysfs_attr(attr) container_of(attr, struct sq_sysfs_attr, attr)
- if (entry->sq_addr == addr) {
- /*
- * We could probably get away without doing the tlb flush
- * here, as generic code should take care of most of this
- * when unmapping the rest of the VMA range for us. Leave
- * it in for added sanity for the time being..
- */
- __flush_tlb_page(get_asid(), entry->sq_addr & PAGE_MASK);
+static ssize_t sq_sysfs_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
- list_del(&entry->list);
- kfree(entry);
+ if (likely(sattr->show))
+ return sattr->show(buf);
- return;
- }
- }
+ return -EIO;
}
-/**
- * sq_vma_sync - Sync a VMA range
- * @area: VMA containing range.
- * @start: Start of range.
- * @len: Length of range.
- * @flags: Additional flags.
- *
- * Synchronizes an sq mapped range by flushing the store queue cache for
- * the duration of the mapping.
- *
- * Used internally for user mappings, which must use msync() to prefetch
- * the store queue cache.
- */
-static int sq_vma_sync(struct vm_area_struct *area,
- unsigned long start, size_t len, unsigned int flags)
+static ssize_t sq_sysfs_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t count)
{
- sq_flush_range(start, len);
+ struct sq_sysfs_attr *sattr = to_sq_sysfs_attr(attr);
- return 0;
+ if (likely(sattr->store))
+ return sattr->store(buf, count);
+
+ return -EIO;
}
-static struct vm_operations_struct sq_vma_ops = {
- .unmap = sq_vma_unmap,
- .sync = sq_vma_sync,
-};
+static ssize_t mapping_show(char *buf)
+{
+ struct sq_mapping **list, *entry;
+ char *p = buf;
-/**
- * sq_mmap - mmap() for /dev/cpu/sq
- * @file: unused.
- * @vma: VMA to remap.
- *
- * Remap the specified vma @vma through the store queues, and setup associated
- * information for the new mapping. Also build up the page tables for the new
- * area.
- */
-static int sq_mmap(struct file *file, struct vm_area_struct *vma)
+ for (list = &sq_mapping_list; (entry = *list); list = &entry->next)
+ p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n",
+ entry->sq_addr, entry->sq_addr + entry->size,
+ entry->addr, entry->name);
+
+ return p - buf;
+}
+
+static ssize_t mapping_store(const char *buf, size_t count)
{
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct sq_mapping *map;
+ unsigned long base = 0, len = 0;
- /*
- * We're not interested in any arbitrary virtual address that has
- * been stuck in the VMA, as we already know what addresses we
- * want. Save off the size, and reposition the VMA to begin at
- * the next available sq address.
- */
- vma->vm_start = __sq_get_next_addr();
- vma->vm_end = vma->vm_start + size;
+ sscanf(buf, "%lx %lx", &base, &len);
+ if (!base)
+ return -EIO;
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ if (likely(len)) {
+ int ret = sq_remap(base, len, "Userspace",
+ pgprot_val(PAGE_SHARED));
+ if (ret < 0)
+ return ret;
+ } else
+ sq_unmap(base);
- vma->vm_flags |= VM_IO | VM_RESERVED;
+ return count;
+}
- map = __sq_alloc_mapping(vma->vm_start, offset, size, "Userspace");
+static struct sq_sysfs_attr mapping_attr =
+ __ATTR(mapping, 0644, mapping_show, mapping_store);
- if (io_remap_pfn_range(vma, map->sq_addr, map->addr >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
+static struct attribute *sq_sysfs_attrs[] = {
+ &mapping_attr.attr,
+ NULL,
+};
- vma->vm_ops = &sq_vma_ops;
+static struct sysfs_ops sq_sysfs_ops = {
+ .show = sq_sysfs_show,
+ .store = sq_sysfs_store,
+};
- return 0;
-}
+static struct kobj_type ktype_percpu_entry = {
+ .sysfs_ops = &sq_sysfs_ops,
+ .default_attrs = sq_sysfs_attrs,
+};
-#ifdef CONFIG_PROC_FS
-static int sq_mapping_read_proc(char *buf, char **start, off_t off,
- int len, int *eof, void *data)
+static int __devinit sq_sysdev_add(struct sys_device *sysdev)
{
- struct list_head *pos;
- char *p = buf;
+ unsigned int cpu = sysdev->id;
+ struct kobject *kobj;
- list_for_each_prev(pos, &sq_mapping_list) {
- struct sq_mapping *entry;
+ sq_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
+ if (unlikely(!sq_kobject[cpu]))
+ return -ENOMEM;
- entry = list_entry(pos, typeof(*entry), list);
+ kobj = sq_kobject[cpu];
+ kobj->parent = &sysdev->kobj;
+ kobject_set_name(kobj, "%s", "sq");
+ kobj->ktype = &ktype_percpu_entry;
- p += sprintf(p, "%08lx-%08lx [%08lx]: %s\n", entry->sq_addr,
- entry->sq_addr + entry->size - 1, entry->addr,
- entry->name);
- }
-
- return p - buf;
+ return kobject_register(kobj);
}
-#endif
-static struct file_operations sq_fops = {
- .owner = THIS_MODULE,
- .mmap = sq_mmap,
-};
+static int __devexit sq_sysdev_remove(struct sys_device *sysdev)
+{
+ unsigned int cpu = sysdev->id;
+ struct kobject *kobj = sq_kobject[cpu];
-static struct miscdevice sq_dev = {
- .minor = STORE_QUEUE_MINOR,
- .name = "sq",
- .fops = &sq_fops,
+ kobject_unregister(kobj);
+ return 0;
+}
+
+static struct sysdev_driver sq_sysdev_driver = {
+ .add = sq_sysdev_add,
+ .remove = __devexit_p(sq_sysdev_remove),
};
static int __init sq_api_init(void)
{
- int ret;
+ unsigned int nr_pages = 0x04000000 >> PAGE_SHIFT;
+ unsigned int size = (nr_pages + (BITS_PER_LONG - 1)) / BITS_PER_LONG;
+ int ret = -ENOMEM;
+
printk(KERN_NOTICE "sq: Registering store queue API.\n");
- create_proc_read_entry("sq_mapping", 0, 0, sq_mapping_read_proc, 0);
+ sq_cache = kmem_cache_create("store_queue_cache",
+ sizeof(struct sq_mapping), 0, 0,
+ NULL, NULL);
+ if (unlikely(!sq_cache))
+ return ret;
- ret = misc_register(&sq_dev);
- if (ret)
- remove_proc_entry("sq_mapping", NULL);
+ sq_bitmap = kzalloc(size, GFP_KERNEL);
+ if (unlikely(!sq_bitmap))
+ goto out;
+
+ ret = sysdev_driver_register(&cpu_sysdev_class, &sq_sysdev_driver);
+ if (unlikely(ret != 0))
+ goto out;
+
+ return 0;
+
+out:
+ kfree(sq_bitmap);
+ kmem_cache_destroy(sq_cache);
return ret;
}
static void __exit sq_api_exit(void)
{
- misc_deregister(&sq_dev);
- remove_proc_entry("sq_mapping", NULL);
+ sysdev_driver_unregister(&cpu_sysdev_class, &sq_sysdev_driver);
+ kfree(sq_bitmap);
+ kmem_cache_destroy(sq_cache);
}
module_init(sq_api_init);
@@ -445,11 +402,7 @@ module_exit(sq_api_exit);
MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>");
MODULE_DESCRIPTION("Simple API for SH-4 integrated Store Queues");
MODULE_LICENSE("GPL");
-MODULE_ALIAS_MISCDEV(STORE_QUEUE_MINOR);
EXPORT_SYMBOL(sq_remap);
EXPORT_SYMBOL(sq_unmap);
-EXPORT_SYMBOL(sq_clear);
-EXPORT_SYMBOL(sq_flush);
EXPORT_SYMBOL(sq_flush_range);
-
diff --git a/arch/sh/kernel/cpu/ubc.S b/arch/sh/kernel/cpu/ubc.S
index 0c569b20e1c1..81923079fa12 100644
--- a/arch/sh/kernel/cpu/ubc.S
+++ b/arch/sh/kernel/cpu/ubc.S
@@ -1,5 +1,5 @@
/*
- * arch/sh/kernel/ubc.S
+ * arch/sh/kernel/cpu/ubc.S
*
* Set of management routines for the User Break Controller (UBC)
*
diff --git a/arch/sh/kernel/early_printk.c b/arch/sh/kernel/early_printk.c
index 1378db375e17..a00022722e9e 100644
--- a/arch/sh/kernel/early_printk.c
+++ b/arch/sh/kernel/early_printk.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 1999, 2000 Niibe Yutaka
* Copyright (C) 2002 M. R. Brown
- * Copyright (C) 2004 Paul Mundt
+ * Copyright (C) 2004 - 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
@@ -49,7 +49,7 @@ static int __init sh_console_setup(struct console *co, char *options)
return 0;
}
-static struct console early_console = {
+static struct console bios_console = {
.name = "bios",
.write = sh_console_write,
.setup = sh_console_setup,
@@ -59,34 +59,43 @@ static struct console early_console = {
#endif
#ifdef CONFIG_EARLY_SCIF_CONSOLE
+#include <linux/serial_core.h>
+#include "../../../drivers/serial/sh-sci.h"
+
+#ifdef CONFIG_CPU_SH4
#define SCIF_REG 0xffe80000
+#elif defined(CONFIG_CPU_SUBTYPE_SH72060)
+#define SCIF_REG 0xfffe9800
+#else
+#error "Undefined SCIF for this subtype"
+#endif
+
+static struct uart_port scif_port = {
+ .mapbase = SCIF_REG,
+ .membase = (char __iomem *)SCIF_REG,
+};
static void scif_sercon_putc(int c)
{
- while (!(ctrl_inw(SCIF_REG + 0x10) & 0x20)) ;
+ while (((sci_in(&scif_port, SCFDR) & 0x1f00 >> 8) == 16))
+ ;
- ctrl_outb(c, SCIF_REG + 12);
- ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0x9f), SCIF_REG + 0x10);
+ sci_out(&scif_port, SCxTDR, c);
+ sci_in(&scif_port, SCxSR);
+ sci_out(&scif_port, SCxSR, 0xf3 & ~(0x20 | 0x40));
+
+ while ((sci_in(&scif_port, SCxSR) & 0x40) == 0);
+ ;
if (c == '\n')
scif_sercon_putc('\r');
}
-static void scif_sercon_flush(void)
-{
- ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
-
- while (!(ctrl_inw(SCIF_REG + 0x10) & 0x40)) ;
-
- ctrl_outw((ctrl_inw(SCIF_REG + 0x10) & 0xbf), SCIF_REG + 0x10);
-}
-
-static void scif_sercon_write(struct console *con, const char *s, unsigned count)
+static void scif_sercon_write(struct console *con, const char *s,
+ unsigned count)
{
while (count-- > 0)
scif_sercon_putc(*s++);
-
- scif_sercon_flush();
}
static int __init scif_sercon_setup(struct console *con, char *options)
@@ -96,7 +105,7 @@ static int __init scif_sercon_setup(struct console *con, char *options)
return 0;
}
-static struct console early_console = {
+static struct console scif_console = {
.name = "sercon",
.write = scif_sercon_write,
.setup = scif_sercon_setup,
@@ -104,7 +113,7 @@ static struct console early_console = {
.index = -1,
};
-void scif_sercon_init(int baud)
+static void scif_sercon_init(int baud)
{
ctrl_outw(0, SCIF_REG + 8);
ctrl_outw(0, SCIF_REG);
@@ -122,16 +131,61 @@ void scif_sercon_init(int baud)
}
#endif
-void __init enable_early_printk(void)
+/*
+ * Setup a default console, if more than one is compiled in, rely on the
+ * earlyprintk= parsing to give priority.
+ */
+static struct console *early_console =
+#ifdef CONFIG_SH_STANDARD_BIOS
+ &bios_console
+#elif defined(CONFIG_EARLY_SCIF_CONSOLE)
+ &scif_console
+#else
+ NULL
+#endif
+ ;
+
+static int __initdata keep_early;
+
+int __init setup_early_printk(char *opt)
{
-#ifdef CONFIG_EARLY_SCIF_CONSOLE
- scif_sercon_init(115200);
+ char *space;
+ char buf[256];
+
+ strlcpy(buf, opt, sizeof(buf));
+ space = strchr(buf, ' ');
+ if (space)
+ *space = 0;
+
+ if (strstr(buf, "keep"))
+ keep_early = 1;
+
+#ifdef CONFIG_SH_STANDARD_BIOS
+ if (!strncmp(buf, "bios", 4))
+ early_console = &bios_console;
+#endif
+#if defined(CONFIG_EARLY_SCIF_CONSOLE)
+ if (!strncmp(buf, "serial", 6)) {
+ early_console = &scif_console;
+
+#ifdef CONFIG_CPU_SH4
+ scif_sercon_init(115200);
+#endif
+ }
#endif
- register_console(&early_console);
+
+ if (likely(early_console))
+ register_console(early_console);
+
+ return 1;
}
+__setup("earlyprintk=", setup_early_printk);
-void disable_early_printk(void)
+void __init disable_early_printk(void)
{
- unregister_console(&early_console);
+ if (!keep_early) {
+ printk("disabling early console\n");
+ unregister_console(early_console);
+ } else
+ printk("keeping early console\n");
}
-
diff --git a/arch/sh/kernel/entry.S b/arch/sh/kernel/entry.S
index 7dfd2ba75f7f..39aaefb2d83f 100644
--- a/arch/sh/kernel/entry.S
+++ b/arch/sh/kernel/entry.S
@@ -1,41 +1,22 @@
-/* $Id: entry.S,v 1.37 2004/06/11 13:02:46 doyu Exp $
- *
+/*
* linux/arch/sh/entry.S
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2003 Paul Mundt
+ * 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/sys.h>
+#include <linux/errno.h>
#include <linux/linkage.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
#include <asm/cpu/mmu_context.h>
#include <asm/unistd.h>
-#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
-#define sys_nfsservctl sys_ni_syscall
-#endif
-
-#if !defined(CONFIG_MMU)
-#define sys_madvise sys_ni_syscall
-#define sys_readahead sys_ni_syscall
-#define sys_mprotect sys_ni_syscall
-#define sys_msync sys_ni_syscall
-#define sys_mlock sys_ni_syscall
-#define sys_munlock sys_ni_syscall
-#define sys_mlockall sys_ni_syscall
-#define sys_munlockall sys_ni_syscall
-#define sys_mremap sys_ni_syscall
-#define sys_mincore sys_ni_syscall
-#define sys_remap_file_pages sys_ni_syscall
-#endif
-
! NOTE:
! GNU as (as of 2.9.1) changes bf/s into bt/s and bra, when the address
! to be jumped is too far, but it causes illegal slot exception.
@@ -71,10 +52,6 @@
* syscall #
*
*/
-
-ENOSYS = 38
-EINVAL = 22
-
#if defined(CONFIG_KGDB_NMI)
NMI_VEC = 0x1c0 ! Must catch early for debounce
#endif
@@ -100,7 +77,6 @@ OFF_TRA = (16*4+6*4)
#define k3 r3
#define k4 r4
-#define k_ex_code r2_bank /* r2_bank1 */
#define g_imask r6 /* r6_bank1 */
#define k_g_imask r6_bank /* r6_bank1 */
#define current r7 /* r7_bank1 */
@@ -326,7 +302,7 @@ ENTRY(exception_error)
.align 2
ret_from_exception:
preempt_stop()
-ret_from_irq:
+ENTRY(ret_from_irq)
!
mov #OFF_SR, r0
mov.l @(r0,r15), r0 ! get status register
@@ -389,11 +365,12 @@ work_pending:
! r8: current_thread_info
! t: result of "tst #_TIF_NEED_RESCHED, r0"
bf/s work_resched
- tst #_TIF_SIGPENDING, r0
+ tst #(_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK), r0
work_notifysig:
bt/s restore_all
mov r15, r4
- mov #0, r5
+ mov r12, r5 ! set arg1(save_r0)
+ mov r0, r6
mov.l 2f, r1
mova restore_all, r0
jmp @r1
@@ -431,7 +408,7 @@ work_resched:
.align 2
1: .long schedule
-2: .long do_signal
+2: .long do_notify_resume
.align 2
syscall_exit_work:
@@ -552,6 +529,7 @@ syscall_call:
mov.l @r9, r8
jsr @r8 ! jump to specific syscall handler
nop
+ mov.l @(OFF_R0,r15), r12 ! save r0
mov.l r0, @(OFF_R0,r15) ! save the return value
!
syscall_exit:
@@ -644,7 +622,7 @@ skip_restore:
!
#if defined(CONFIG_KGDB_NMI)
! Clear in_nmi
- mov.l 4f, k0
+ mov.l 6f, k0
mov #0, k1
mov.b k1, @k0
#endif
@@ -711,7 +689,7 @@ interrupt:
0:
#endif /* defined(CONFIG_KGDB_NMI) */
bra handle_exception
- mov.l @k2, k2
+ mov #-1, k2 ! interrupt exception marker
.align 2
1: .long EXPEVT
@@ -722,7 +700,7 @@ interrupt:
!
!
.align 2
-handle_exception:
+ENTRY(handle_exception)
! Using k0, k1 for scratch registers (r0_bank1, r1_bank),
! save all registers onto stack.
!
@@ -732,13 +710,12 @@ handle_exception:
bt/s 1f ! It's a kernel to kernel transition.
mov r15, k0 ! save original stack to k0
/* User space to kernel */
- mov #0x20, k1
- shll8 k1 ! k1 := 8192 (== THREAD_SIZE)
+ mov #(THREAD_SIZE >> 8), k1
+ shll8 k1 ! k1 := THREAD_SIZE
add current, k1
mov k1, r15 ! change to kernel stack
!
-1: mov #-1, k4
- mov.l 2f, k1
+1: mov.l 2f, k1
!
#ifdef CONFIG_SH_DSP
mov.l r2, @-r15 ! Save r2, we need another reg
@@ -783,6 +760,8 @@ skip_save:
#endif
! Save the user registers on the stack.
mov.l k2, @-r15 ! EXPEVT
+
+ mov #-1, k4
mov.l k4, @-r15 ! set TRA (default: -1)
!
sts.l macl, @-r15
@@ -817,8 +796,21 @@ skip_save:
mov.l r2, @-r15
mov.l r1, @-r15
mov.l r0, @-r15
- ! Then, dispatch to the handler, according to the exception code.
- stc k_ex_code, r8
+
+ /*
+ * This gets a bit tricky.. in the INTEVT case we don't want to use
+ * the VBR offset as a destination in the jump call table, since all
+ * of the destinations are the same. In this case, (interrupt) sets
+ * a marker in r2 (now r2_bank since SR.RB changed), which we check
+ * to determine the exception type. For all other exceptions, we
+ * forcibly read EXPEVT from memory and fix up the jump address, in
+ * the interrupt exception case we jump to do_IRQ() and defer the
+ * INTEVT read until there. As a bonus, we can also clean up the SR.RB
+ * checks that do_IRQ() was doing..
+ */
+ stc r2_bank, r8
+ cmp/pz r8
+ bf interrupt_exception
shlr2 r8
shlr r8
mov.l 4f, r9
@@ -826,6 +818,8 @@ skip_save:
mov.l @r9, r9
jmp @r9
nop
+ rts
+ nop
.align 2
1: .long 0x00001000 ! DSP=1
@@ -833,305 +827,17 @@ skip_save:
3: .long 0xcfffffff ! RB=0, BL=0
4: .long exception_handling_table
+interrupt_exception:
+ mov.l 1f, r9
+ jmp @r9
+ nop
+ rts
+ nop
+
+ .align 2
+1: .long do_IRQ
+
.align 2
ENTRY(exception_none)
rts
nop
-
- .data
-ENTRY(sys_call_table)
- .long sys_ni_syscall /* 0 - old "setup()" system call*/
- .long sys_exit
- .long sys_fork
- .long sys_read
- .long sys_write
- .long sys_open /* 5 */
- .long sys_close
- .long sys_waitpid
- .long sys_creat
- .long sys_link
- .long sys_unlink /* 10 */
- .long sys_execve
- .long sys_chdir
- .long sys_time
- .long sys_mknod
- .long sys_chmod /* 15 */
- .long sys_lchown16
- .long sys_ni_syscall /* old break syscall holder */
- .long sys_stat
- .long sys_lseek
- .long sys_getpid /* 20 */
- .long sys_mount
- .long sys_oldumount
- .long sys_setuid16
- .long sys_getuid16
- .long sys_stime /* 25 */
- .long sys_ptrace
- .long sys_alarm
- .long sys_fstat
- .long sys_pause
- .long sys_utime /* 30 */
- .long sys_ni_syscall /* old stty syscall holder */
- .long sys_ni_syscall /* old gtty syscall holder */
- .long sys_access
- .long sys_nice
- .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
- .long sys_sync
- .long sys_kill
- .long sys_rename
- .long sys_mkdir
- .long sys_rmdir /* 40 */
- .long sys_dup
- .long sys_pipe
- .long sys_times
- .long sys_ni_syscall /* old prof syscall holder */
- .long sys_brk /* 45 */
- .long sys_setgid16
- .long sys_getgid16
- .long sys_signal
- .long sys_geteuid16
- .long sys_getegid16 /* 50 */
- .long sys_acct
- .long sys_umount /* recycled never used phys() */
- .long sys_ni_syscall /* old lock syscall holder */
- .long sys_ioctl
- .long sys_fcntl /* 55 */
- .long sys_ni_syscall /* old mpx syscall holder */
- .long sys_setpgid
- .long sys_ni_syscall /* old ulimit syscall holder */
- .long sys_ni_syscall /* sys_olduname */
- .long sys_umask /* 60 */
- .long sys_chroot
- .long sys_ustat
- .long sys_dup2
- .long sys_getppid
- .long sys_getpgrp /* 65 */
- .long sys_setsid
- .long sys_sigaction
- .long sys_sgetmask
- .long sys_ssetmask
- .long sys_setreuid16 /* 70 */
- .long sys_setregid16
- .long sys_sigsuspend
- .long sys_sigpending
- .long sys_sethostname
- .long sys_setrlimit /* 75 */
- .long sys_old_getrlimit
- .long sys_getrusage
- .long sys_gettimeofday
- .long sys_settimeofday
- .long sys_getgroups16 /* 80 */
- .long sys_setgroups16
- .long sys_ni_syscall /* sys_oldselect */
- .long sys_symlink
- .long sys_lstat
- .long sys_readlink /* 85 */
- .long sys_uselib
- .long sys_swapon
- .long sys_reboot
- .long old_readdir
- .long old_mmap /* 90 */
- .long sys_munmap
- .long sys_truncate
- .long sys_ftruncate
- .long sys_fchmod
- .long sys_fchown16 /* 95 */
- .long sys_getpriority
- .long sys_setpriority
- .long sys_ni_syscall /* old profil syscall holder */
- .long sys_statfs
- .long sys_fstatfs /* 100 */
- .long sys_ni_syscall /* ioperm */
- .long sys_socketcall
- .long sys_syslog
- .long sys_setitimer
- .long sys_getitimer /* 105 */
- .long sys_newstat
- .long sys_newlstat
- .long sys_newfstat
- .long sys_uname
- .long sys_ni_syscall /* 110 */ /* iopl */
- .long sys_vhangup
- .long sys_ni_syscall /* idle */
- .long sys_ni_syscall /* vm86old */
- .long sys_wait4
- .long sys_swapoff /* 115 */
- .long sys_sysinfo
- .long sys_ipc
- .long sys_fsync
- .long sys_sigreturn
- .long sys_clone /* 120 */
- .long sys_setdomainname
- .long sys_newuname
- .long sys_ni_syscall /* sys_modify_ldt */
- .long sys_adjtimex
- .long sys_mprotect /* 125 */
- .long sys_sigprocmask
- .long sys_ni_syscall /* old "create_module" */
- .long sys_init_module
- .long sys_delete_module
- .long sys_ni_syscall /* 130: old "get_kernel_syms" */
- .long sys_quotactl
- .long sys_getpgid
- .long sys_fchdir
- .long sys_bdflush
- .long sys_sysfs /* 135 */
- .long sys_personality
- .long sys_ni_syscall /* for afs_syscall */
- .long sys_setfsuid16
- .long sys_setfsgid16
- .long sys_llseek /* 140 */
- .long sys_getdents
- .long sys_select
- .long sys_flock
- .long sys_msync
- .long sys_readv /* 145 */
- .long sys_writev
- .long sys_getsid
- .long sys_fdatasync
- .long sys_sysctl
- .long sys_mlock /* 150 */
- .long sys_munlock
- .long sys_mlockall
- .long sys_munlockall
- .long sys_sched_setparam
- .long sys_sched_getparam /* 155 */
- .long sys_sched_setscheduler
- .long sys_sched_getscheduler
- .long sys_sched_yield
- .long sys_sched_get_priority_max
- .long sys_sched_get_priority_min /* 160 */
- .long sys_sched_rr_get_interval
- .long sys_nanosleep
- .long sys_mremap
- .long sys_setresuid16
- .long sys_getresuid16 /* 165 */
- .long sys_ni_syscall /* vm86 */
- .long sys_ni_syscall /* old "query_module" */
- .long sys_poll
- .long sys_nfsservctl
- .long sys_setresgid16 /* 170 */
- .long sys_getresgid16
- .long sys_prctl
- .long sys_rt_sigreturn
- .long sys_rt_sigaction
- .long sys_rt_sigprocmask /* 175 */
- .long sys_rt_sigpending
- .long sys_rt_sigtimedwait
- .long sys_rt_sigqueueinfo
- .long sys_rt_sigsuspend
- .long sys_pread_wrapper /* 180 */
- .long sys_pwrite_wrapper
- .long sys_chown16
- .long sys_getcwd
- .long sys_capget
- .long sys_capset /* 185 */
- .long sys_sigaltstack
- .long sys_sendfile
- .long sys_ni_syscall /* streams1 */
- .long sys_ni_syscall /* streams2 */
- .long sys_vfork /* 190 */
- .long sys_getrlimit
- .long sys_mmap2
- .long sys_truncate64
- .long sys_ftruncate64
- .long sys_stat64 /* 195 */
- .long sys_lstat64
- .long sys_fstat64
- .long sys_lchown
- .long sys_getuid
- .long sys_getgid /* 200 */
- .long sys_geteuid
- .long sys_getegid
- .long sys_setreuid
- .long sys_setregid
- .long sys_getgroups /* 205 */
- .long sys_setgroups
- .long sys_fchown
- .long sys_setresuid
- .long sys_getresuid
- .long sys_setresgid /* 210 */
- .long sys_getresgid
- .long sys_chown
- .long sys_setuid
- .long sys_setgid
- .long sys_setfsuid /* 215 */
- .long sys_setfsgid
- .long sys_pivot_root
- .long sys_mincore
- .long sys_madvise
- .long sys_getdents64 /* 220 */
- .long sys_fcntl64
- .long sys_ni_syscall /* reserved for TUX */
- .long sys_ni_syscall /* Reserved for Security */
- .long sys_gettid
- .long sys_readahead /* 225 */
- .long sys_setxattr
- .long sys_lsetxattr
- .long sys_fsetxattr
- .long sys_getxattr
- .long sys_lgetxattr /* 230 */
- .long sys_fgetxattr
- .long sys_listxattr
- .long sys_llistxattr
- .long sys_flistxattr
- .long sys_removexattr /* 235 */
- .long sys_lremovexattr
- .long sys_fremovexattr
- .long sys_tkill
- .long sys_sendfile64
- .long sys_futex /* 240 */
- .long sys_sched_setaffinity
- .long sys_sched_getaffinity
- .long sys_ni_syscall
- .long sys_ni_syscall
- .long sys_io_setup /* 245 */
- .long sys_io_destroy
- .long sys_io_getevents
- .long sys_io_submit
- .long sys_io_cancel
- .long sys_fadvise64 /* 250 */
- .long sys_ni_syscall
- .long sys_exit_group
- .long sys_lookup_dcookie
- .long sys_epoll_create
- .long sys_epoll_ctl /* 255 */
- .long sys_epoll_wait
- .long sys_remap_file_pages
- .long sys_set_tid_address
- .long sys_timer_create
- .long sys_timer_settime /* 260 */
- .long sys_timer_gettime
- .long sys_timer_getoverrun
- .long sys_timer_delete
- .long sys_clock_settime
- .long sys_clock_gettime /* 265 */
- .long sys_clock_getres
- .long sys_clock_nanosleep
- .long sys_statfs64
- .long sys_fstatfs64
- .long sys_tgkill /* 270 */
- .long sys_utimes
- .long sys_fadvise64_64_wrapper
- .long sys_ni_syscall /* Reserved for vserver */
- .long sys_ni_syscall /* Reserved for mbind */
- .long sys_ni_syscall /* 275 - get_mempolicy */
- .long sys_ni_syscall /* set_mempolicy */
- .long sys_mq_open
- .long sys_mq_unlink
- .long sys_mq_timedsend
- .long sys_mq_timedreceive /* 280 */
- .long sys_mq_notify
- .long sys_mq_getsetattr
- .long sys_ni_syscall /* Reserved for kexec */
- .long sys_waitid
- .long sys_add_key /* 285 */
- .long sys_request_key
- .long sys_keyctl
- .long sys_ioprio_set
- .long sys_ioprio_get
- .long sys_inotify_init /* 290 */
- .long sys_inotify_add_watch
- .long sys_inotify_rm_watch
-
-/* End of entry.S */
diff --git a/arch/sh/kernel/head.S b/arch/sh/kernel/head.S
index 9b9e6ef626ce..f5f53d14f245 100644
--- a/arch/sh/kernel/head.S
+++ b/arch/sh/kernel/head.S
@@ -11,6 +11,18 @@
* Head.S contains the SH exception handlers and startup code.
*/
#include <linux/linkage.h>
+#include <asm/thread_info.h>
+
+#ifdef CONFIG_CPU_SH4A
+#define SYNCO() synco
+
+#define PREFI(label, reg) \
+ mov.l label, reg; \
+ prefi @reg
+#else
+#define SYNCO()
+#define PREFI(label, reg)
+#endif
.section .empty_zero_page, "aw"
ENTRY(empty_zero_page)
@@ -42,18 +54,25 @@ ENTRY(_stext)
! Initialize global interrupt mask
mov #0, r0
ldc r0, r6_bank
+
+ /*
+ * Prefetch if possible to reduce cache miss penalty.
+ *
+ * We do this early on for SH-4A as a micro-optimization,
+ * as later on we will have speculative execution enabled
+ * and this will become less of an issue.
+ */
+ PREFI(5f, r0)
+ PREFI(6f, r0)
+
!
mov.l 2f, r0
mov r0, r15 ! Set initial r15 (stack pointer)
- mov #0x20, r1 !
- shll8 r1 ! r1 = 8192
+ mov #(THREAD_SIZE >> 8), r1
+ shll8 r1 ! r1 = THREAD_SIZE
sub r1, r0 !
ldc r0, r7_bank ! ... and initial thread_info
- !
- ! Additional CPU initialization
- mov.l 6f, r0
- jsr @r0
- nop
+
! Clear BSS area
mov.l 3f, r1
add #4, r1
@@ -62,6 +81,14 @@ ENTRY(_stext)
9: cmp/hs r2, r1
bf/s 9b ! while (r1 < r2)
mov.l r0,@-r2
+
+ ! Additional CPU initialization
+ mov.l 6f, r0
+ jsr @r0
+ nop
+
+ SYNCO() ! Wait for pending instructions..
+
! Start kernel
mov.l 5f, r0
jmp @r0
@@ -69,7 +96,7 @@ ENTRY(_stext)
.balign 4
1: .long 0x400080F0 ! MD=1, RB=0, BL=0, FD=1, IMASK=0xF
-2: .long stack
+2: .long init_thread_union+THREAD_SIZE
3: .long __bss_start
4: .long _end
5: .long start_kernel
diff --git a/arch/sh/kernel/io.c b/arch/sh/kernel/io.c
index 71c9fde2fd90..501fe03e3715 100644
--- a/arch/sh/kernel/io.c
+++ b/arch/sh/kernel/io.c
@@ -61,6 +61,73 @@ void memset_io(volatile void __iomem *dst, int c, unsigned long count)
}
EXPORT_SYMBOL(memset_io);
+void __raw_readsl(unsigned long addr, void *datap, int len)
+{
+ u32 *data;
+
+ for (data = datap; (len != 0) && (((u32)data & 0x1f) != 0); len--)
+ *data++ = ctrl_inl(addr);
+
+ if (likely(len >= (0x20 >> 2))) {
+ int tmp2, tmp3, tmp4, tmp5, tmp6;
+
+ __asm__ __volatile__(
+ "1: \n\t"
+ "mov.l @%7, r0 \n\t"
+ "mov.l @%7, %2 \n\t"
+#ifdef CONFIG_CPU_SH4
+ "movca.l r0, @%0 \n\t"
+#else
+ "mov.l r0, @%0 \n\t"
+#endif
+ "mov.l @%7, %3 \n\t"
+ "mov.l @%7, %4 \n\t"
+ "mov.l @%7, %5 \n\t"
+ "mov.l @%7, %6 \n\t"
+ "mov.l @%7, r7 \n\t"
+ "mov.l @%7, r0 \n\t"
+ "mov.l %2, @(0x04,%0) \n\t"
+ "mov #0x20>>2, %2 \n\t"
+ "mov.l %3, @(0x08,%0) \n\t"
+ "sub %2, %1 \n\t"
+ "mov.l %4, @(0x0c,%0) \n\t"
+ "cmp/hi %1, %2 ! T if 32 > len \n\t"
+ "mov.l %5, @(0x10,%0) \n\t"
+ "mov.l %6, @(0x14,%0) \n\t"
+ "mov.l r7, @(0x18,%0) \n\t"
+ "mov.l r0, @(0x1c,%0) \n\t"
+ "bf.s 1b \n\t"
+ " add #0x20, %0 \n\t"
+ : "=&r" (data), "=&r" (len),
+ "=&r" (tmp2), "=&r" (tmp3), "=&r" (tmp4),
+ "=&r" (tmp5), "=&r" (tmp6)
+ : "r"(addr), "0" (data), "1" (len)
+ : "r0", "r7", "t", "memory");
+ }
+
+ for (; len != 0; len--)
+ *data++ = ctrl_inl(addr);
+}
+EXPORT_SYMBOL(__raw_readsl);
+
+void __raw_writesl(unsigned long addr, const void *data, int len)
+{
+ if (likely(len != 0)) {
+ int tmp1;
+
+ __asm__ __volatile__ (
+ "1: \n\t"
+ "mov.l @%0+, %1 \n\t"
+ "dt %3 \n\t"
+ "bf.s 1b \n\t"
+ " mov.l %1, @%4 \n\t"
+ : "=&r" (data), "=&r" (tmp1)
+ : "0" (data), "r" (len), "r"(addr)
+ : "t", "memory");
+ }
+}
+EXPORT_SYMBOL(__raw_writesl);
+
void __iomem *ioport_map(unsigned long port, unsigned int nr)
{
return sh_mv.mv_ioport_map(port, nr);
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index c2e07f7f3496..acf2602569c4 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -1,5 +1,4 @@
-/* $Id: irq.c,v 1.20 2004/01/13 05:52:11 kkojima Exp $
- *
+/*
* linux/arch/sh/kernel/irq.c
*
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
@@ -7,15 +6,20 @@
*
* SuperH version: Copyright (C) 1999 Niibe Yutaka
*/
-
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/kernel_stat.h>
#include <linux/seq_file.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/thread_info.h>
#include <asm/cpu/mmu_context.h>
+atomic_t irq_err_count;
+
/*
* 'what should we do if we get a hw irq event on an illegal vector'.
* each architecture has to answer this themselves, it doesn't deserve
@@ -23,6 +27,7 @@
*/
void ack_bad_irq(unsigned int irq)
{
+ atomic_inc(&irq_err_count);
printk("unexpected IRQ trap at vector %02x\n", irq);
}
@@ -46,8 +51,10 @@ int show_interrupts(struct seq_file *p, void *v)
if (!action)
goto unlock;
seq_printf(p, "%3d: ",i);
- seq_printf(p, "%10u ", kstat_irqs(i));
- seq_printf(p, " %14s", irq_desc[i].chip->typename);
+ for_each_online_cpu(j)
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+ seq_printf(p, " %14s", irq_desc[i].chip->name);
+ seq_printf(p, "-%s", handle_irq_name(irq_desc[i].handle_irq));
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
@@ -55,39 +62,190 @@ int show_interrupts(struct seq_file *p, void *v)
seq_putc(p, '\n');
unlock:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
- }
+ } else if (i == NR_IRQS)
+ seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count));
+
return 0;
}
#endif
+#ifdef CONFIG_4KSTACKS
+/*
+ * per-CPU IRQ handling contexts (thread information and stack)
+ */
+union irq_ctx {
+ struct thread_info tinfo;
+ u32 stack[THREAD_SIZE/sizeof(u32)];
+};
+
+static union irq_ctx *hardirq_ctx[NR_CPUS];
+static union irq_ctx *softirq_ctx[NR_CPUS];
+#endif
asmlinkage int do_IRQ(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- int irq = r4;
+ struct pt_regs *old_regs = set_irq_regs(&regs);
+ int irq;
+#ifdef CONFIG_4KSTACKS
+ union irq_ctx *curctx, *irqctx;
+#endif
irq_enter();
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /* Debugging check for stack overflow: is there less than 1KB free? */
+ {
+ long sp;
+
+ __asm__ __volatile__ ("and r15, %0" :
+ "=r" (sp) : "0" (THREAD_SIZE - 1));
+
+ if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) {
+ printk("do_IRQ: stack overflow: %ld\n",
+ sp - sizeof(struct thread_info));
+ dump_stack();
+ }
+ }
+#endif
+
#ifdef CONFIG_CPU_HAS_INTEVT
- __asm__ __volatile__ (
-#ifdef CONFIG_CPU_HAS_SR_RB
- "stc r2_bank, %0\n\t"
+ irq = (ctrl_inl(INTEVT) >> 5) - 16;
#else
- "mov.l @%1, %0\n\t"
-#endif
- "shlr2 %0\n\t"
- "shlr2 %0\n\t"
- "shlr %0\n\t"
- "add #-16, %0\n\t"
- : "=z" (irq), "=r" (r4)
- : "1" (INTEVT)
- : "memory"
- );
+ irq = r4;
#endif
irq = irq_demux(irq);
- __do_IRQ(irq, &regs);
+
+#ifdef CONFIG_4KSTACKS
+ curctx = (union irq_ctx *)current_thread_info();
+ irqctx = hardirq_ctx[smp_processor_id()];
+
+ /*
+ * this is where we switch to the IRQ stack. However, if we are
+ * already using the IRQ stack (because we interrupted a hardirq
+ * handler) we can't do that and just have to keep using the
+ * current stack (which is the irq stack already after all)
+ */
+ if (curctx != irqctx) {
+ u32 *isp;
+
+ isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
+ irqctx->tinfo.task = curctx->tinfo.task;
+ irqctx->tinfo.previous_sp = current_stack_pointer;
+
+ __asm__ __volatile__ (
+ "mov %0, r4 \n"
+ "mov r15, r9 \n"
+ "jsr @%1 \n"
+ /* swith to the irq stack */
+ " mov %2, r15 \n"
+ /* restore the stack (ring zero) */
+ "mov r9, r15 \n"
+ : /* no outputs */
+ : "r" (irq), "r" (generic_handle_irq), "r" (isp)
+ /* XXX: A somewhat excessive clobber list? -PFM */
+ : "memory", "r0", "r1", "r2", "r3", "r4",
+ "r5", "r6", "r7", "r8", "t", "pr"
+ );
+ } else
+#endif
+ generic_handle_irq(irq);
+
irq_exit();
+
+ set_irq_regs(old_regs);
return 1;
}
+
+#ifdef CONFIG_4KSTACKS
+/*
+ * These should really be __section__(".bss.page_aligned") as well, but
+ * gcc's 3.0 and earlier don't handle that correctly.
+ */
+static char softirq_stack[NR_CPUS * THREAD_SIZE]
+ __attribute__((__aligned__(THREAD_SIZE)));
+
+static char hardirq_stack[NR_CPUS * THREAD_SIZE]
+ __attribute__((__aligned__(THREAD_SIZE)));
+
+/*
+ * allocate per-cpu stacks for hardirq and for softirq processing
+ */
+void irq_ctx_init(int cpu)
+{
+ union irq_ctx *irqctx;
+
+ if (hardirq_ctx[cpu])
+ return;
+
+ irqctx = (union irq_ctx *)&hardirq_stack[cpu * THREAD_SIZE];
+ irqctx->tinfo.task = NULL;
+ irqctx->tinfo.exec_domain = NULL;
+ irqctx->tinfo.cpu = cpu;
+ irqctx->tinfo.preempt_count = HARDIRQ_OFFSET;
+ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
+
+ hardirq_ctx[cpu] = irqctx;
+
+ irqctx = (union irq_ctx *)&softirq_stack[cpu * THREAD_SIZE];
+ irqctx->tinfo.task = NULL;
+ irqctx->tinfo.exec_domain = NULL;
+ irqctx->tinfo.cpu = cpu;
+ irqctx->tinfo.preempt_count = SOFTIRQ_OFFSET;
+ irqctx->tinfo.addr_limit = MAKE_MM_SEG(0);
+
+ softirq_ctx[cpu] = irqctx;
+
+ printk("CPU %u irqstacks, hard=%p soft=%p\n",
+ cpu, hardirq_ctx[cpu], softirq_ctx[cpu]);
+}
+
+void irq_ctx_exit(int cpu)
+{
+ hardirq_ctx[cpu] = NULL;
+}
+
+extern asmlinkage void __do_softirq(void);
+
+asmlinkage void do_softirq(void)
+{
+ unsigned long flags;
+ struct thread_info *curctx;
+ union irq_ctx *irqctx;
+ u32 *isp;
+
+ if (in_interrupt())
+ return;
+
+ local_irq_save(flags);
+
+ if (local_softirq_pending()) {
+ curctx = current_thread_info();
+ irqctx = softirq_ctx[smp_processor_id()];
+ irqctx->tinfo.task = curctx->task;
+ irqctx->tinfo.previous_sp = current_stack_pointer;
+
+ /* build the stack frame on the softirq stack */
+ isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
+
+ __asm__ __volatile__ (
+ "mov r15, r9 \n"
+ "jsr @%0 \n"
+ /* switch to the softirq stack */
+ " mov %1, r15 \n"
+ /* restore the thread stack */
+ "mov r9, r15 \n"
+ : /* no outputs */
+ : "r" (__do_softirq), "r" (isp)
+ /* XXX: A somewhat excessive clobber list? -PFM */
+ : "memory", "r0", "r1", "r2", "r3", "r4",
+ "r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
+ );
+ }
+
+ local_irq_restore(flags);
+}
+EXPORT_SYMBOL(do_softirq);
+#endif
diff --git a/arch/sh/kernel/kgdb_stub.c b/arch/sh/kernel/kgdb_stub.c
index 42638b92b51c..9c6315f0335d 100644
--- a/arch/sh/kernel/kgdb_stub.c
+++ b/arch/sh/kernel/kgdb_stub.c
@@ -101,16 +101,17 @@
#include <linux/linkage.h>
#include <linux/init.h>
+#ifdef CONFIG_SH_KGDB_CONSOLE
+#include <linux/console.h>
+#endif
+
#include <asm/system.h>
#include <asm/current.h>
#include <asm/signal.h>
#include <asm/pgtable.h>
#include <asm/ptrace.h>
#include <asm/kgdb.h>
-
-#ifdef CONFIG_SH_KGDB_CONSOLE
-#include <linux/console.h>
-#endif
+#include <asm/io.h>
/* Function pointers for linkage */
kgdb_debug_hook_t *kgdb_debug_hook;
@@ -240,7 +241,6 @@ static jmp_buf rem_com_env;
/* Misc static */
static int stepped_address;
static short stepped_opcode;
-static const char hexchars[] = "0123456789abcdef";
static char in_buffer[BUFMAX];
static char out_buffer[OUTBUFMAX];
@@ -253,29 +253,6 @@ typedef unsigned char threadref[8];
#define BUF_THREAD_ID_SIZE 16
#endif
-/* Return addr as a real volatile address */
-static inline unsigned int ctrl_inl(const unsigned long addr)
-{
- return *(volatile unsigned long *) addr;
-}
-
-/* Correctly set *addr using volatile */
-static inline void ctrl_outl(const unsigned int b, unsigned long addr)
-{
- *(volatile unsigned long *) addr = b;
-}
-
-/* Get high hex bits */
-static char highhex(const int x)
-{
- return hexchars[(x >> 4) & 0xf];
-}
-
-/* Get low hex bits */
-static char lowhex(const int x)
-{
- return hexchars[x & 0xf];
-}
/* Convert ch to hex */
static int hex(const char ch)
diff --git a/arch/sh/kernel/machine_kexec.c b/arch/sh/kernel/machine_kexec.c
index 6bcd8d92399f..08587cdb64d6 100644
--- a/arch/sh/kernel/machine_kexec.c
+++ b/arch/sh/kernel/machine_kexec.c
@@ -29,12 +29,6 @@ extern const unsigned char relocate_new_kernel[];
extern const unsigned int relocate_new_kernel_size;
extern void *gdb_vbr_vector;
-/*
- * Provide a dummy crash_notes definition while crash dump arrives to ppc.
- * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
- */
-void *crash_notes = NULL;
-
void machine_shutdown(void)
{
}
diff --git a/arch/sh/kernel/pm.c b/arch/sh/kernel/pm.c
new file mode 100644
index 000000000000..10ab62c9aede
--- /dev/null
+++ b/arch/sh/kernel/pm.c
@@ -0,0 +1,88 @@
+/*
+ * Generic Power Management Routine
+ *
+ * Copyright (c) 2006 Andriy Skulysh <askulsyh@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License.
+ */
+#include <linux/suspend.h>
+#include <linux/delay.h>
+#include <linux/gfp.h>
+#include <asm/freq.h>
+#include <asm/io.h>
+#include <asm/watchdog.h>
+#include <asm/pm.h>
+
+#define INTR_OFFSET 0x600
+
+#define STBCR 0xffffff82
+#define STBCR2 0xffffff88
+
+#define STBCR_STBY 0x80
+#define STBCR_MSTP2 0x04
+
+#define MCR 0xffffff68
+#define RTCNT 0xffffff70
+
+#define MCR_RMODE 2
+#define MCR_RFSH 4
+
+void pm_enter(void)
+{
+ u8 stbcr, csr;
+ u16 frqcr, mcr;
+ u32 vbr_new, vbr_old;
+
+ set_bl_bit();
+
+ /* set wdt */
+ csr = sh_wdt_read_csr();
+ csr &= ~WTCSR_TME;
+ csr |= WTCSR_CKS_4096;
+ sh_wdt_write_csr(csr);
+ csr = sh_wdt_read_csr();
+ sh_wdt_write_cnt(0);
+
+ /* disable PLL1 */
+ frqcr = ctrl_inw(FRQCR);
+ frqcr &= ~(FRQCR_PLLEN | FRQCR_PSTBY);
+ ctrl_outw(frqcr, FRQCR);
+
+ /* enable standby */
+ stbcr = ctrl_inb(STBCR);
+ ctrl_outb(stbcr | STBCR_STBY | STBCR_MSTP2, STBCR);
+
+ /* set self-refresh */
+ mcr = ctrl_inw(MCR);
+ ctrl_outw(mcr & ~MCR_RFSH, MCR);
+
+ /* set interrupt handler */
+ asm volatile("stc vbr, %0" : "=r" (vbr_old));
+ vbr_new = get_zeroed_page(GFP_ATOMIC);
+ udelay(50);
+ memcpy((void*)(vbr_new + INTR_OFFSET),
+ &wakeup_start, &wakeup_end - &wakeup_start);
+ asm volatile("ldc %0, vbr" : : "r" (vbr_new));
+
+ ctrl_outw(0, RTCNT);
+ ctrl_outw(mcr | MCR_RFSH | MCR_RMODE, MCR);
+
+ cpu_sleep();
+
+ asm volatile("ldc %0, vbr" : : "r" (vbr_old));
+
+ free_page(vbr_new);
+
+ /* enable PLL1 */
+ frqcr = ctrl_inw(FRQCR);
+ frqcr |= FRQCR_PSTBY;
+ ctrl_outw(frqcr, FRQCR);
+ udelay(50);
+ frqcr |= FRQCR_PLLEN;
+ ctrl_outw(frqcr, FRQCR);
+
+ ctrl_outb(stbcr, STBCR);
+
+ clear_bl_bit();
+}
diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c
index f2031314cb2b..91516dca4a85 100644
--- a/arch/sh/kernel/process.c
+++ b/arch/sh/kernel/process.c
@@ -5,6 +5,7 @@
* Copyright (C) 1995 Linus Torvalds
*
* SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
+ * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
*/
/*
@@ -81,16 +82,6 @@ void cpu_idle(void)
void machine_restart(char * __unused)
{
-
-#ifdef CONFIG_KEXEC
- struct kimage *image;
- image = xchg(&kexec_image, 0);
- if (image) {
- machine_shutdown();
- machine_kexec(image);
- }
-#endif
-
/* SR.BL=1 and invoke address error to let CPU reset (manual reset) */
asm volatile("ldc %0, sr\n\t"
"mov.l @%1, %0" : : "r" (0x10000000), "r" (0x80000001));
@@ -263,6 +254,7 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
unsigned long unused,
struct task_struct *p, struct pt_regs *regs)
{
+ struct thread_info *ti = task_thread_info(p);
struct pt_regs *childregs;
#if defined(CONFIG_SH_FPU)
struct task_struct *tsk = current;
@@ -277,8 +269,10 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
if (user_mode(regs)) {
childregs->regs[15] = usp;
+ ti->addr_limit = USER_DS;
} else {
childregs->regs[15] = (unsigned long)task_stack_page(p) + THREAD_SIZE;
+ ti->addr_limit = KERNEL_DS;
}
if (clone_flags & CLONE_SETTLS) {
childregs->gbr = childregs->regs[0];
@@ -297,21 +291,42 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
static void
ubc_set_tracing(int asid, unsigned long pc)
{
+#if defined(CONFIG_CPU_SH4A)
+ unsigned long val;
+
+ val = (UBC_CBR_ID_INST | UBC_CBR_RW_READ | UBC_CBR_CE);
+ val |= (UBC_CBR_AIE | UBC_CBR_AIV_SET(asid));
+
+ ctrl_outl(val, UBC_CBR0);
+ ctrl_outl(pc, UBC_CAR0);
+ ctrl_outl(0x0, UBC_CAMR0);
+ ctrl_outl(0x0, UBC_CBCR);
+
+ val = (UBC_CRR_RES | UBC_CRR_PCB | UBC_CRR_BIE);
+ ctrl_outl(val, UBC_CRR0);
+
+ /* Read UBC register that we writed last. For chekking UBC Register changed */
+ val = ctrl_inl(UBC_CRR0);
+
+#else /* CONFIG_CPU_SH4A */
ctrl_outl(pc, UBC_BARA);
+#ifdef CONFIG_MMU
/* We don't have any ASID settings for the SH-2! */
if (cpu_data->type != CPU_SH7604)
ctrl_outb(asid, UBC_BASRA);
+#endif
ctrl_outl(0, UBC_BAMRA);
- if (cpu_data->type == CPU_SH7729) {
+ if (cpu_data->type == CPU_SH7729 || cpu_data->type == CPU_SH7710) {
ctrl_outw(BBR_INST | BBR_READ | BBR_CPU, UBC_BBRA);
ctrl_outl(BRCR_PCBA | BRCR_PCTE, UBC_BRCR);
} else {
ctrl_outw(BBR_INST | BBR_READ, UBC_BBRA);
ctrl_outw(BRCR_PCBA, UBC_BRCR);
}
+#endif /* CONFIG_CPU_SH4A */
}
/*
@@ -344,6 +359,7 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
}
#endif
+#ifdef CONFIG_MMU
/*
* Restore the kernel mode register
* k7 (r7_bank1)
@@ -351,19 +367,26 @@ struct task_struct *__switch_to(struct task_struct *prev, struct task_struct *ne
asm volatile("ldc %0, r7_bank"
: /* no output */
: "r" (task_thread_info(next)));
+#endif
-#ifdef CONFIG_MMU
/* If no tasks are using the UBC, we're done */
if (ubc_usercnt == 0)
/* If no tasks are using the UBC, we're done */;
else if (next->thread.ubc_pc && next->mm) {
- ubc_set_tracing(next->mm->context & MMU_CONTEXT_ASID_MASK,
- next->thread.ubc_pc);
+ int asid = 0;
+#ifdef CONFIG_MMU
+ asid |= next->mm->context.id & MMU_CONTEXT_ASID_MASK;
+#endif
+ ubc_set_tracing(asid, next->thread.ubc_pc);
} else {
+#if defined(CONFIG_CPU_SH4A)
+ ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
+ ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
+#else
ctrl_outw(0, UBC_BBRA);
ctrl_outw(0, UBC_BBRB);
- }
#endif
+ }
return prev;
}
@@ -462,8 +485,13 @@ asmlinkage void break_point_trap(unsigned long r4, unsigned long r5,
struct pt_regs regs)
{
/* Clear tracing. */
+#if defined(CONFIG_CPU_SH4A)
+ ctrl_outl(UBC_CBR_INIT, UBC_CBR0);
+ ctrl_outl(UBC_CRR_INIT, UBC_CRR0);
+#else
ctrl_outw(0, UBC_BBRA);
ctrl_outw(0, UBC_BBRB);
+#endif
current->thread.ubc_pc = 0;
ubc_usercnt -= 1;
diff --git a/arch/sh/kernel/ptrace.c b/arch/sh/kernel/ptrace.c
index f7eebbde3291..04ca13a041c1 100644
--- a/arch/sh/kernel/ptrace.c
+++ b/arch/sh/kernel/ptrace.c
@@ -224,7 +224,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_SETDSPREGS: {
unsigned long dp;
- int i;
ret = -EIO;
dp = ((unsigned long) child) + THREAD_SIZE -
diff --git a/arch/sh/kernel/semaphore.c b/arch/sh/kernel/semaphore.c
index a3c24dcbf01d..184119eeae56 100644
--- a/arch/sh/kernel/semaphore.c
+++ b/arch/sh/kernel/semaphore.c
@@ -14,7 +14,7 @@
#include <asm/semaphore.h>
#include <asm/semaphore-helper.h>
-spinlock_t semaphore_wake_lock;
+DEFINE_SPINLOCK(semaphore_wake_lock);
/*
* Semaphores are implemented using a two-way counter:
diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c
index e75189cb1db7..36d86f9ac38a 100644
--- a/arch/sh/kernel/setup.c
+++ b/arch/sh/kernel/setup.c
@@ -1,5 +1,4 @@
-/* $Id: setup.c,v 1.30 2003/10/13 07:21:19 lethal Exp $
- *
+/*
* linux/arch/sh/kernel/setup.c
*
* Copyright (C) 1999 Niibe Yutaka
@@ -21,6 +20,7 @@
#include <linux/utsname.h>
#include <linux/cpu.h>
#include <linux/pfn.h>
+#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/sections.h>
@@ -43,27 +43,14 @@ extern void * __rd_start, * __rd_end;
* The bigger value means no problem.
*/
struct sh_cpuinfo boot_cpu_data = { CPU_SH_NONE, 10000000, };
+#ifdef CONFIG_VT
struct screen_info screen_info;
+#endif
#if defined(CONFIG_SH_UNKNOWN)
struct sh_machine_vector sh_mv;
#endif
-/* We need this to satisfy some external references. */
-struct screen_info screen_info = {
- 0, 25, /* orig-x, orig-y */
- 0, /* unused */
- 0, /* orig-video-page */
- 0, /* orig-video-mode */
- 80, /* orig-video-cols */
- 0,0,0, /* ega_ax, ega_bx, ega_cx */
- 25, /* orig-video-lines */
- 0, /* orig-video-isVGA */
- 16 /* orig-video-points */
-};
-
-extern void platform_setup(void);
-extern char *get_system_type(void);
extern int root_mountflags;
#define MV_NAME_SIZE 32
@@ -90,29 +77,8 @@ static struct sh_machine_vector* __init get_mv_byname(const char* name);
static char command_line[COMMAND_LINE_SIZE] = { 0, };
-struct resource standard_io_resources[] = {
- { "dma1", 0x00, 0x1f },
- { "pic1", 0x20, 0x3f },
- { "timer", 0x40, 0x5f },
- { "keyboard", 0x60, 0x6f },
- { "dma page reg", 0x80, 0x8f },
- { "pic2", 0xa0, 0xbf },
- { "dma2", 0xc0, 0xdf },
- { "fpu", 0xf0, 0xff }
-};
-
-#define STANDARD_IO_RESOURCES (sizeof(standard_io_resources)/sizeof(struct resource))
-
-/* System RAM - interrupted by the 640kB-1M hole */
-#define code_resource (ram_resources[3])
-#define data_resource (ram_resources[4])
-static struct resource ram_resources[] = {
- { "System RAM", 0x000000, 0x09ffff, IORESOURCE_BUSY },
- { "System RAM", 0x100000, 0x100000, IORESOURCE_BUSY },
- { "Video RAM area", 0x0a0000, 0x0bffff },
- { "Kernel code", 0x100000, 0 },
- { "Kernel data", 0, 0 }
-};
+static struct resource code_resource = { .name = "Kernel code", };
+static struct resource data_resource = { .name = "Kernel data", };
unsigned long memory_start, memory_end;
@@ -145,6 +111,24 @@ static inline void parse_cmdline (char ** cmdline_p, char mv_name[MV_NAME_SIZE],
memory_end = memory_start + mem_size;
}
}
+
+#ifdef CONFIG_EARLY_PRINTK
+ if (c == ' ' && !memcmp(from, "earlyprintk=", 12)) {
+ char *ep_end;
+
+ if (to != command_line)
+ to--;
+
+ from += 12;
+ ep_end = strchr(from, ' ');
+
+ setup_early_printk(from);
+ printk("early console enabled\n");
+
+ from = ep_end;
+ }
+#endif
+
if (c == ' ' && !memcmp(from, "sh_mv=", 6)) {
char* mv_end;
char* mv_comma;
@@ -237,6 +221,9 @@ static int __init sh_mv_setup(char **cmdline_p)
__set_io_port_base(mv_io_base);
#endif
+ if (!sh_mv.mv_nr_irqs)
+ sh_mv.mv_nr_irqs = NR_IRQS;
+
return 0;
}
@@ -245,11 +232,6 @@ void __init setup_arch(char **cmdline_p)
unsigned long bootmap_size;
unsigned long start_pfn, max_pfn, max_low_pfn;
-#ifdef CONFIG_EARLY_PRINTK
- extern void enable_early_printk(void);
-
- enable_early_printk();
-#endif
#ifdef CONFIG_CMDLINE_BOOL
strcpy(COMMAND_LINE, CONFIG_CMDLINE);
#endif
@@ -368,14 +350,14 @@ void __init setup_arch(char **cmdline_p)
#endif
/* Perform the machine specific initialisation */
- platform_setup();
+ if (likely(sh_mv.mv_setup))
+ sh_mv.mv_setup(cmdline_p);
paging_init();
}
struct sh_machine_vector* __init get_mv_byname(const char* name)
{
- extern int strcasecmp(const char *, const char *);
extern long __machvec_start, __machvec_end;
struct sh_machine_vector *all_vecs =
(struct sh_machine_vector *)&__machvec_start;
@@ -410,25 +392,18 @@ static int __init topology_init(void)
subsys_initcall(topology_init);
static const char *cpu_name[] = {
- [CPU_SH7604] = "SH7604",
- [CPU_SH7705] = "SH7705",
- [CPU_SH7708] = "SH7708",
- [CPU_SH7729] = "SH7729",
- [CPU_SH7300] = "SH7300",
- [CPU_SH7750] = "SH7750",
- [CPU_SH7750S] = "SH7750S",
- [CPU_SH7750R] = "SH7750R",
- [CPU_SH7751] = "SH7751",
- [CPU_SH7751R] = "SH7751R",
- [CPU_SH7760] = "SH7760",
- [CPU_SH73180] = "SH73180",
- [CPU_ST40RA] = "ST40RA",
- [CPU_ST40GX1] = "ST40GX1",
- [CPU_SH4_202] = "SH4-202",
- [CPU_SH4_501] = "SH4-501",
- [CPU_SH7770] = "SH7770",
- [CPU_SH7780] = "SH7780",
- [CPU_SH7781] = "SH7781",
+ [CPU_SH7604] = "SH7604", [CPU_SH7300] = "SH7300",
+ [CPU_SH7705] = "SH7705", [CPU_SH7706] = "SH7706",
+ [CPU_SH7707] = "SH7707", [CPU_SH7708] = "SH7708",
+ [CPU_SH7709] = "SH7709", [CPU_SH7710] = "SH7710",
+ [CPU_SH7729] = "SH7729", [CPU_SH7750] = "SH7750",
+ [CPU_SH7750S] = "SH7750S", [CPU_SH7750R] = "SH7750R",
+ [CPU_SH7751] = "SH7751", [CPU_SH7751R] = "SH7751R",
+ [CPU_SH7760] = "SH7760", [CPU_SH73180] = "SH73180",
+ [CPU_ST40RA] = "ST40RA", [CPU_ST40GX1] = "ST40GX1",
+ [CPU_SH4_202] = "SH4-202", [CPU_SH4_501] = "SH4-501",
+ [CPU_SH7770] = "SH7770", [CPU_SH7780] = "SH7780",
+ [CPU_SH7781] = "SH7781", [CPU_SH7343] = "SH7343",
[CPU_SH_NONE] = "Unknown"
};
@@ -438,8 +413,10 @@ const char *get_cpu_subtype(void)
}
#ifdef CONFIG_PROC_FS
+/* Symbolic CPU flags, keep in sync with asm/cpu-features.h */
static const char *cpu_flags[] = {
- "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr", "ptea", NULL
+ "none", "fpu", "p2flush", "mmuassoc", "dsp", "perfctr",
+ "ptea", "llsc", "l2", NULL
};
static void show_cpuflags(struct seq_file *m)
@@ -460,7 +437,8 @@ static void show_cpuflags(struct seq_file *m)
seq_printf(m, "\n");
}
-static void show_cacheinfo(struct seq_file *m, const char *type, struct cache_info info)
+static void show_cacheinfo(struct seq_file *m, const char *type,
+ struct cache_info info)
{
unsigned int cache_size;
@@ -481,7 +459,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "machine\t\t: %s\n", get_system_type());
seq_printf(m, "processor\t: %d\n", cpu);
- seq_printf(m, "cpu family\t: %s\n", system_utsname.machine);
+ seq_printf(m, "cpu family\t: %s\n", init_utsname()->machine);
seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype());
show_cpuflags(m);
@@ -493,7 +471,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
* unified cache on the SH-2 and SH-3, as well as the harvard
* style cache on the SH-4.
*/
- if (test_bit(SH_CACHE_COMBINED, &(boot_cpu_data.icache.flags))) {
+ if (boot_cpu_data.icache.flags & SH_CACHE_COMBINED) {
seq_printf(m, "unified\n");
show_cacheinfo(m, "cache", boot_cpu_data.icache);
} else {
@@ -502,6 +480,10 @@ static int show_cpuinfo(struct seq_file *m, void *v)
show_cacheinfo(m, "dcache", boot_cpu_data.dcache);
}
+ /* Optional secondary cache */
+ if (boot_cpu_data.flags & CPU_HAS_L2_CACHE)
+ show_cacheinfo(m, "scache", boot_cpu_data.scache);
+
seq_printf(m, "bogomips\t: %lu.%02lu\n",
boot_cpu_data.loops_per_jiffy/(500000/HZ),
(boot_cpu_data.loops_per_jiffy/(5000/HZ)) % 100);
@@ -617,4 +599,3 @@ static int __init kgdb_parse_options(char *options)
}
__setup("kgdb=", kgdb_parse_options);
#endif /* CONFIG_SH_KGDB */
-
diff --git a/arch/sh/kernel/sh_ksyms.c b/arch/sh/kernel/sh_ksyms.c
index 245ed8f945e8..9daad70bc305 100644
--- a/arch/sh/kernel/sh_ksyms.c
+++ b/arch/sh/kernel/sh_ksyms.c
@@ -27,21 +27,11 @@ EXPORT_SYMBOL(sh_mv);
/* platform dependent support */
EXPORT_SYMBOL(dump_fpu);
-EXPORT_SYMBOL(iounmap);
-EXPORT_SYMBOL(enable_irq);
-EXPORT_SYMBOL(disable_irq);
-EXPORT_SYMBOL(probe_irq_mask);
EXPORT_SYMBOL(kernel_thread);
-EXPORT_SYMBOL(disable_irq_nosync);
EXPORT_SYMBOL(irq_desc);
EXPORT_SYMBOL(no_irq_type);
-EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(strnlen);
-EXPORT_SYMBOL(strchr);
-EXPORT_SYMBOL(strcat);
-EXPORT_SYMBOL(strncat);
/* PCI exports */
#ifdef CONFIG_PCI
@@ -52,13 +42,8 @@ EXPORT_SYMBOL(pci_free_consistent);
/* mem exports */
EXPORT_SYMBOL(memchr);
EXPORT_SYMBOL(memcpy);
-EXPORT_SYMBOL(memcpy_fromio);
-EXPORT_SYMBOL(memcpy_toio);
EXPORT_SYMBOL(memset);
-EXPORT_SYMBOL(memset_io);
EXPORT_SYMBOL(memmove);
-EXPORT_SYMBOL(memcmp);
-EXPORT_SYMBOL(memscan);
EXPORT_SYMBOL(__copy_user);
EXPORT_SYMBOL(boot_cpu_data);
@@ -87,6 +72,7 @@ DECLARE_EXPORT(__ashrdi3);
DECLARE_EXPORT(__ashldi3);
DECLARE_EXPORT(__lshrdi3);
DECLARE_EXPORT(__movstr);
+DECLARE_EXPORT(__movstrSI16);
EXPORT_SYMBOL(strcpy);
@@ -94,7 +80,9 @@ EXPORT_SYMBOL(strcpy);
DECLARE_EXPORT(__movstr_i4_even);
DECLARE_EXPORT(__movstr_i4_odd);
DECLARE_EXPORT(__movstrSI12_i4);
+#endif
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_SH7705_CACHE_32KB)
/* needed by some modules */
EXPORT_SYMBOL(flush_cache_all);
EXPORT_SYMBOL(flush_cache_range);
@@ -102,11 +90,9 @@ EXPORT_SYMBOL(flush_dcache_page);
EXPORT_SYMBOL(__flush_purge_region);
#endif
-#if defined(CONFIG_SH7705_CACHE_32KB)
-EXPORT_SYMBOL(flush_cache_all);
-EXPORT_SYMBOL(flush_cache_range);
-EXPORT_SYMBOL(flush_dcache_page);
-EXPORT_SYMBOL(__flush_purge_region);
+#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
+ defined(CONFIG_SH7705_CACHE_32KB))
+EXPORT_SYMBOL(clear_user_page);
#endif
EXPORT_SYMBOL(flush_tlb_page);
@@ -116,7 +102,12 @@ EXPORT_SYMBOL(__down_trylock);
EXPORT_SYMBOL(synchronize_irq);
#endif
+#ifdef CONFIG_PM
+EXPORT_SYMBOL(pm_suspend);
+#endif
+
EXPORT_SYMBOL(csum_partial);
+#ifdef CONFIG_IPV6
EXPORT_SYMBOL(csum_ipv6_magic);
-EXPORT_SYMBOL(consistent_sync);
+#endif
EXPORT_SYMBOL(clear_page);
diff --git a/arch/sh/kernel/signal.c b/arch/sh/kernel/signal.c
index b475c4d2405f..5213f5bc6ce0 100644
--- a/arch/sh/kernel/signal.c
+++ b/arch/sh/kernel/signal.c
@@ -8,7 +8,6 @@
* SuperH version: Copyright (C) 1999, 2000 Niibe Yutaka & Kaz Kojima
*
*/
-
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
@@ -21,6 +20,7 @@
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/tty.h>
+#include <linux/elf.h>
#include <linux/personality.h>
#include <linux/binfmts.h>
@@ -29,12 +29,8 @@
#include <asm/pgtable.h>
#include <asm/cacheflush.h>
-#define DEBUG_SIG 0
-
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
-
/*
* Atomically swap in the new signal mask, and wait for a signal.
*/
@@ -43,51 +39,17 @@ sys_sigsuspend(old_sigset_t mask,
unsigned long r5, unsigned long r6, unsigned long r7,
struct pt_regs regs)
{
- sigset_t saveset;
-
mask &= _BLOCKABLE;
spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
+ current->saved_sigmask = current->blocked;
siginitset(&current->blocked, mask);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
- regs.regs[0] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&regs, &saveset))
- return -EINTR;
- }
-}
-
-asmlinkage int
-sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize,
- unsigned long r6, unsigned long r7,
- struct pt_regs regs)
-{
- sigset_t saveset, newset;
-
- /* XXX: Don't preclude handling different sized sigset_t's. */
- if (sigsetsize != sizeof(sigset_t))
- return -EINVAL;
-
- if (copy_from_user(&newset, unewset, sizeof(newset)))
- return -EFAULT;
- sigdelsetmask(&newset, ~_BLOCKABLE);
- spin_lock_irq(&current->sighand->siglock);
- saveset = current->blocked;
- current->blocked = newset;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-
- regs.regs[0] = -EINTR;
- while (1) {
- current->state = TASK_INTERRUPTIBLE;
- schedule();
- if (do_signal(&regs, &saveset))
- return -EINTR;
- }
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ set_thread_flag(TIF_RESTORE_SIGMASK);
+ return -ERESTARTNOHAND;
}
asmlinkage int
@@ -348,7 +310,12 @@ get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
return (void __user *)((sp - frame_size) & -8ul);
}
-static void setup_frame(int sig, struct k_sigaction *ka,
+/* These symbols are defined with the addresses in the vsyscall page.
+ See vsyscall-trapa.S. */
+extern void __user __kernel_sigreturn;
+extern void __user __kernel_rt_sigreturn;
+
+static int setup_frame(int sig, struct k_sigaction *ka,
sigset_t *set, struct pt_regs *regs)
{
struct sigframe __user *frame;
@@ -368,15 +335,18 @@ static void setup_frame(int sig, struct k_sigaction *ka,
err |= setup_sigcontext(&frame->sc, regs, set->sig[0]);
- if (_NSIG_WORDS > 1) {
+ if (_NSIG_WORDS > 1)
err |= __copy_to_user(frame->extramask, &set->sig[1],
sizeof(frame->extramask));
- }
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
regs->pr = (unsigned long) ka->sa.sa_restorer;
+#ifdef CONFIG_VSYSCALL
+ } else if (likely(current->mm->context.vdso)) {
+ regs->pr = VDSO_SYM(&__kernel_sigreturn);
+#endif
} else {
/* Generate return code (system call to sigreturn) */
err |= __put_user(MOVW(7), &frame->retcode[0]);
@@ -402,21 +372,22 @@ static void setup_frame(int sig, struct k_sigaction *ka,
set_fs(USER_DS);
-#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
- current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+ pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+ current->comm, current->pid, frame, regs->pc, regs->pr);
flush_cache_sigtramp(regs->pr);
+
if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
- return;
+
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
-static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *set, struct pt_regs *regs)
{
struct rt_sigframe __user *frame;
@@ -452,6 +423,10 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
already in userspace. */
if (ka->sa.sa_flags & SA_RESTORER) {
regs->pr = (unsigned long) ka->sa.sa_restorer;
+#ifdef CONFIG_VSYSCALL
+ } else if (likely(current->mm->context.vdso)) {
+ regs->pr = VDSO_SYM(&__kernel_rt_sigreturn);
+#endif
} else {
/* Generate return code (system call to rt_sigreturn) */
err |= __put_user(MOVW(7), &frame->retcode[0]);
@@ -477,28 +452,31 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
set_fs(USER_DS);
-#if DEBUG_SIG
- printk("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
- current->comm, current->pid, frame, regs->pc, regs->pr);
-#endif
+ pr_debug("SIG deliver (%s:%d): sp=%p pc=%08lx pr=%08lx\n",
+ current->comm, current->pid, frame, regs->pc, regs->pr);
flush_cache_sigtramp(regs->pr);
+
if ((-regs->pr & (L1_CACHE_BYTES-1)) < sizeof(frame->retcode))
flush_cache_sigtramp(regs->pr + L1_CACHE_BYTES);
- return;
+
+ return 0;
give_sigsegv:
force_sigsegv(sig, current);
+ return -EFAULT;
}
/*
* OK, we're invoking a handler
*/
-static void
+static int
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
sigset_t *oldset, struct pt_regs *regs)
{
+ int ret;
+
/* Are we from a system call? */
if (regs->tra >= 0) {
/* If so, check system call restarting.. */
@@ -539,19 +517,23 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
/* Set up the stack frame */
if (ka->sa.sa_flags & SA_SIGINFO)
- setup_rt_frame(sig, ka, info, oldset, regs);
+ ret = setup_rt_frame(sig, ka, info, oldset, regs);
else
- setup_frame(sig, ka, oldset, regs);
+ ret = setup_frame(sig, ka, oldset, regs);
if (ka->sa.sa_flags & SA_ONESHOT)
ka->sa.sa_handler = SIG_DFL;
- spin_lock_irq(&current->sighand->siglock);
- sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
- if (!(ka->sa.sa_flags & SA_NODEFER))
- sigaddset(&current->blocked,sig);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
+ if (ret == 0) {
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+ if (!(ka->sa.sa_flags & SA_NODEFER))
+ sigaddset(&current->blocked,sig);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+
+ return ret;
}
/*
@@ -563,11 +545,12 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
* the kernel can handle, and then we build all the user-level signal handling
* stack-frames in one go after that.
*/
-int do_signal(struct pt_regs *regs, sigset_t *oldset)
+static void do_signal(struct pt_regs *regs, unsigned int save_r0)
{
siginfo_t info;
int signr;
struct k_sigaction ka;
+ sigset_t *oldset;
/*
* We want the common case to go fast, which
@@ -576,19 +559,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
* if so.
*/
if (!user_mode(regs))
- return 1;
+ return;
if (try_to_freeze())
goto no_signal;
- if (!oldset)
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = &current->saved_sigmask;
+ else
oldset = &current->blocked;
signr = get_signal_to_deliver(&info, &ka, regs, NULL);
if (signr > 0) {
/* Whee! Actually deliver the signal. */
- handle_signal(signr, &ka, &info, oldset, regs);
- return 1;
+ if (handle_signal(signr, &ka, &info, oldset, regs) == 0) {
+ /* 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);
+ }
}
no_signal:
@@ -597,10 +588,27 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
/* Restart the system call - no handlers present */
if (regs->regs[0] == -ERESTARTNOHAND ||
regs->regs[0] == -ERESTARTSYS ||
- regs->regs[0] == -ERESTARTNOINTR ||
- regs->regs[0] == -ERESTART_RESTARTBLOCK) {
+ regs->regs[0] == -ERESTARTNOINTR) {
+ regs->regs[0] = save_r0;
+ regs->pc -= 2;
+ } else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
regs->pc -= 2;
+ regs->regs[3] = __NR_restart_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);
+ }
+}
+
+asmlinkage void do_notify_resume(struct pt_regs *regs, unsigned int save_r0,
+ __u32 thread_info_flags)
+{
+ /* deal with pending signal delivery */
+ if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
+ do_signal(regs, save_r0);
}
diff --git a/arch/sh/kernel/smp.c b/arch/sh/kernel/smp.c
index 6c0fb7c4af11..dbebaddcfe39 100644
--- a/arch/sh/kernel/smp.c
+++ b/arch/sh/kernel/smp.c
@@ -42,6 +42,7 @@ cpumask_t cpu_possible_map;
EXPORT_SYMBOL(cpu_possible_map);
cpumask_t cpu_online_map;
+EXPORT_SYMBOL(cpu_online_map);
static atomic_t cpus_booted = ATOMIC_INIT(0);
/* These are defined by the board-specific code. */
diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c
index 917b2f32f260..8fde95001c34 100644
--- a/arch/sh/kernel/sys_sh.c
+++ b/arch/sh/kernel/sys_sh.c
@@ -21,9 +21,11 @@
#include <linux/mman.h>
#include <linux/file.h>
#include <linux/utsname.h>
-
+#include <linux/module.h>
+#include <asm/cacheflush.h>
#include <asm/uaccess.h>
#include <asm/ipc.h>
+#include <asm/unistd.h>
/*
* sys_pipe() is the normal C calling standard for creating
@@ -44,11 +46,16 @@ asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
return error;
}
-#if defined(HAVE_ARCH_UNMAPPED_AREA)
+unsigned long shm_align_mask = PAGE_SIZE - 1; /* Sane caches */
+
+EXPORT_SYMBOL(shm_align_mask);
+
/*
- * To avoid cache alias, we map the shard page with same color.
+ * To avoid cache aliases, we map the shared page with same color.
*/
-#define COLOUR_ALIGN(addr) (((addr)+SHMLBA-1)&~(SHMLBA-1))
+#define COLOUR_ALIGN(addr, pgoff) \
+ ((((addr) + shm_align_mask) & ~shm_align_mask) + \
+ (((pgoff) << PAGE_SHIFT) & shm_align_mask))
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
unsigned long len, unsigned long pgoff, unsigned long flags)
@@ -56,43 +63,52 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned long start_addr;
+ int do_colour_align;
if (flags & MAP_FIXED) {
/* We do not accept a shared mapping if it would violate
* cache aliasing constraints.
*/
- if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1)))
+ if ((flags & MAP_SHARED) && (addr & shm_align_mask))
return -EINVAL;
return addr;
}
- if (len > TASK_SIZE)
+ if (unlikely(len > TASK_SIZE))
return -ENOMEM;
+ do_colour_align = 0;
+ if (filp || (flags & MAP_SHARED))
+ do_colour_align = 1;
+
if (addr) {
- if (flags & MAP_PRIVATE)
- addr = PAGE_ALIGN(addr);
+ if (do_colour_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
else
- addr = COLOUR_ALIGN(addr);
+ addr = PAGE_ALIGN(addr);
+
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
(!vma || addr + len <= vma->vm_start))
return addr;
}
- if (len <= mm->cached_hole_size) {
+
+ if (len > mm->cached_hole_size) {
+ start_addr = addr = mm->free_area_cache;
+ } else {
mm->cached_hole_size = 0;
- mm->free_area_cache = TASK_UNMAPPED_BASE;
+ start_addr = addr = TASK_UNMAPPED_BASE;
}
- if (flags & MAP_PRIVATE)
- addr = PAGE_ALIGN(mm->free_area_cache);
- else
- addr = COLOUR_ALIGN(mm->free_area_cache);
- start_addr = addr;
full_search:
+ if (do_colour_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
+ else
+ addr = PAGE_ALIGN(mm->free_area_cache);
+
for (vma = find_vma(mm, addr); ; vma = vma->vm_next) {
/* At this point: (!vma || addr < vma->vm_end). */
- if (TASK_SIZE - len < addr) {
+ if (unlikely(TASK_SIZE - len < addr)) {
/*
* Start a new search - just in case we missed
* some holes.
@@ -104,7 +120,7 @@ full_search:
}
return -ENOMEM;
}
- if (!vma || addr + len <= vma->vm_start) {
+ if (likely(!vma || addr + len <= vma->vm_start)) {
/*
* Remember the place where we stopped the search:
*/
@@ -115,11 +131,10 @@ full_search:
mm->cached_hole_size = vma->vm_start - addr;
addr = vma->vm_end;
- if (!(flags & MAP_PRIVATE))
- addr = COLOUR_ALIGN(addr);
+ if (do_colour_align)
+ addr = COLOUR_ALIGN(addr, pgoff);
}
}
-#endif
static inline long
do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
@@ -267,7 +282,7 @@ asmlinkage int sys_uname(struct old_utsname * name)
if (!name)
return -EFAULT;
down_read(&uts_sem);
- err=copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
return err?-EFAULT:0;
}
@@ -295,3 +310,19 @@ asmlinkage int sys_fadvise64_64_wrapper(int fd, u32 offset0, u32 offset1,
(u64)len0 << 32 | len1, advice);
#endif
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register long __sc0 __asm__ ("r3") = __NR_execve;
+ register long __sc4 __asm__ ("r4") = (long) filename;
+ register long __sc5 __asm__ ("r5") = (long) argv;
+ register long __sc6 __asm__ ("r6") = (long) envp;
+ __asm__ __volatile__ ("trapa #0x13" : "=z" (__sc0)
+ : "0" (__sc0), "r" (__sc4), "r" (__sc5), "r" (__sc6)
+ : "memory");
+ return __sc0;
+}
diff --git a/arch/sh/kernel/syscalls.S b/arch/sh/kernel/syscalls.S
new file mode 100644
index 000000000000..768334e95075
--- /dev/null
+++ b/arch/sh/kernel/syscalls.S
@@ -0,0 +1,353 @@
+/*
+ * arch/sh/kernel/syscalls.S
+ *
+ * System call table for SuperH
+ *
+ * Copyright (C) 1999, 2000, 2002 Niibe Yutaka
+ * Copyright (C) 2003 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/sys.h>
+#include <linux/linkage.h>
+
+#if !defined(CONFIG_NFSD) && !defined(CONFIG_NFSD_MODULE)
+#define sys_nfsservctl sys_ni_syscall
+#endif
+
+#if !defined(CONFIG_MMU)
+#define sys_madvise sys_ni_syscall
+#define sys_readahead sys_ni_syscall
+#define sys_mprotect sys_ni_syscall
+#define sys_msync sys_ni_syscall
+#define sys_mlock sys_ni_syscall
+#define sys_munlock sys_ni_syscall
+#define sys_mlockall sys_ni_syscall
+#define sys_munlockall sys_ni_syscall
+#define sys_mremap sys_ni_syscall
+#define sys_mincore sys_ni_syscall
+#define sys_remap_file_pages sys_ni_syscall
+#endif
+
+ .data
+ENTRY(sys_call_table)
+ .long sys_restart_syscall /* 0 - old "setup()" system call*/
+ .long sys_exit
+ .long sys_fork
+ .long sys_read
+ .long sys_write
+ .long sys_open /* 5 */
+ .long sys_close
+ .long sys_waitpid
+ .long sys_creat
+ .long sys_link
+ .long sys_unlink /* 10 */
+ .long sys_execve
+ .long sys_chdir
+ .long sys_time
+ .long sys_mknod
+ .long sys_chmod /* 15 */
+ .long sys_lchown16
+ .long sys_ni_syscall /* old break syscall holder */
+ .long sys_stat
+ .long sys_lseek
+ .long sys_getpid /* 20 */
+ .long sys_mount
+ .long sys_oldumount
+ .long sys_setuid16
+ .long sys_getuid16
+ .long sys_stime /* 25 */
+ .long sys_ptrace
+ .long sys_alarm
+ .long sys_fstat
+ .long sys_pause
+ .long sys_utime /* 30 */
+ .long sys_ni_syscall /* old stty syscall holder */
+ .long sys_ni_syscall /* old gtty syscall holder */
+ .long sys_access
+ .long sys_nice
+ .long sys_ni_syscall /* 35 */ /* old ftime syscall holder */
+ .long sys_sync
+ .long sys_kill
+ .long sys_rename
+ .long sys_mkdir
+ .long sys_rmdir /* 40 */
+ .long sys_dup
+ .long sys_pipe
+ .long sys_times
+ .long sys_ni_syscall /* old prof syscall holder */
+ .long sys_brk /* 45 */
+ .long sys_setgid16
+ .long sys_getgid16
+ .long sys_signal
+ .long sys_geteuid16
+ .long sys_getegid16 /* 50 */
+ .long sys_acct
+ .long sys_umount /* recycled never used phys() */
+ .long sys_ni_syscall /* old lock syscall holder */
+ .long sys_ioctl
+ .long sys_fcntl /* 55 */
+ .long sys_ni_syscall /* old mpx syscall holder */
+ .long sys_setpgid
+ .long sys_ni_syscall /* old ulimit syscall holder */
+ .long sys_ni_syscall /* sys_olduname */
+ .long sys_umask /* 60 */
+ .long sys_chroot
+ .long sys_ustat
+ .long sys_dup2
+ .long sys_getppid
+ .long sys_getpgrp /* 65 */
+ .long sys_setsid
+ .long sys_sigaction
+ .long sys_sgetmask
+ .long sys_ssetmask
+ .long sys_setreuid16 /* 70 */
+ .long sys_setregid16
+ .long sys_sigsuspend
+ .long sys_sigpending
+ .long sys_sethostname
+ .long sys_setrlimit /* 75 */
+ .long sys_old_getrlimit
+ .long sys_getrusage
+ .long sys_gettimeofday
+ .long sys_settimeofday
+ .long sys_getgroups16 /* 80 */
+ .long sys_setgroups16
+ .long sys_ni_syscall /* sys_oldselect */
+ .long sys_symlink
+ .long sys_lstat
+ .long sys_readlink /* 85 */
+ .long sys_uselib
+ .long sys_swapon
+ .long sys_reboot
+ .long old_readdir
+ .long old_mmap /* 90 */
+ .long sys_munmap
+ .long sys_truncate
+ .long sys_ftruncate
+ .long sys_fchmod
+ .long sys_fchown16 /* 95 */
+ .long sys_getpriority
+ .long sys_setpriority
+ .long sys_ni_syscall /* old profil syscall holder */
+ .long sys_statfs
+ .long sys_fstatfs /* 100 */
+ .long sys_ni_syscall /* ioperm */
+ .long sys_socketcall
+ .long sys_syslog
+ .long sys_setitimer
+ .long sys_getitimer /* 105 */
+ .long sys_newstat
+ .long sys_newlstat
+ .long sys_newfstat
+ .long sys_uname
+ .long sys_ni_syscall /* 110 */ /* iopl */
+ .long sys_vhangup
+ .long sys_ni_syscall /* idle */
+ .long sys_ni_syscall /* vm86old */
+ .long sys_wait4
+ .long sys_swapoff /* 115 */
+ .long sys_sysinfo
+ .long sys_ipc
+ .long sys_fsync
+ .long sys_sigreturn
+ .long sys_clone /* 120 */
+ .long sys_setdomainname
+ .long sys_newuname
+ .long sys_ni_syscall /* sys_modify_ldt */
+ .long sys_adjtimex
+ .long sys_mprotect /* 125 */
+ .long sys_sigprocmask
+ .long sys_ni_syscall /* old "create_module" */
+ .long sys_init_module
+ .long sys_delete_module
+ .long sys_ni_syscall /* 130: old "get_kernel_syms" */
+ .long sys_quotactl
+ .long sys_getpgid
+ .long sys_fchdir
+ .long sys_bdflush
+ .long sys_sysfs /* 135 */
+ .long sys_personality
+ .long sys_ni_syscall /* for afs_syscall */
+ .long sys_setfsuid16
+ .long sys_setfsgid16
+ .long sys_llseek /* 140 */
+ .long sys_getdents
+ .long sys_select
+ .long sys_flock
+ .long sys_msync
+ .long sys_readv /* 145 */
+ .long sys_writev
+ .long sys_getsid
+ .long sys_fdatasync
+ .long sys_sysctl
+ .long sys_mlock /* 150 */
+ .long sys_munlock
+ .long sys_mlockall
+ .long sys_munlockall
+ .long sys_sched_setparam
+ .long sys_sched_getparam /* 155 */
+ .long sys_sched_setscheduler
+ .long sys_sched_getscheduler
+ .long sys_sched_yield
+ .long sys_sched_get_priority_max
+ .long sys_sched_get_priority_min /* 160 */
+ .long sys_sched_rr_get_interval
+ .long sys_nanosleep
+ .long sys_mremap
+ .long sys_setresuid16
+ .long sys_getresuid16 /* 165 */
+ .long sys_ni_syscall /* vm86 */
+ .long sys_ni_syscall /* old "query_module" */
+ .long sys_poll
+ .long sys_nfsservctl
+ .long sys_setresgid16 /* 170 */
+ .long sys_getresgid16
+ .long sys_prctl
+ .long sys_rt_sigreturn
+ .long sys_rt_sigaction
+ .long sys_rt_sigprocmask /* 175 */
+ .long sys_rt_sigpending
+ .long sys_rt_sigtimedwait
+ .long sys_rt_sigqueueinfo
+ .long sys_rt_sigsuspend
+ .long sys_pread_wrapper /* 180 */
+ .long sys_pwrite_wrapper
+ .long sys_chown16
+ .long sys_getcwd
+ .long sys_capget
+ .long sys_capset /* 185 */
+ .long sys_sigaltstack
+ .long sys_sendfile
+ .long sys_ni_syscall /* streams1 */
+ .long sys_ni_syscall /* streams2 */
+ .long sys_vfork /* 190 */
+ .long sys_getrlimit
+ .long sys_mmap2
+ .long sys_truncate64
+ .long sys_ftruncate64
+ .long sys_stat64 /* 195 */
+ .long sys_lstat64
+ .long sys_fstat64
+ .long sys_lchown
+ .long sys_getuid
+ .long sys_getgid /* 200 */
+ .long sys_geteuid
+ .long sys_getegid
+ .long sys_setreuid
+ .long sys_setregid
+ .long sys_getgroups /* 205 */
+ .long sys_setgroups
+ .long sys_fchown
+ .long sys_setresuid
+ .long sys_getresuid
+ .long sys_setresgid /* 210 */
+ .long sys_getresgid
+ .long sys_chown
+ .long sys_setuid
+ .long sys_setgid
+ .long sys_setfsuid /* 215 */
+ .long sys_setfsgid
+ .long sys_pivot_root
+ .long sys_mincore
+ .long sys_madvise
+ .long sys_getdents64 /* 220 */
+ .long sys_fcntl64
+ .long sys_ni_syscall /* reserved for TUX */
+ .long sys_ni_syscall /* Reserved for Security */
+ .long sys_gettid
+ .long sys_readahead /* 225 */
+ .long sys_setxattr
+ .long sys_lsetxattr
+ .long sys_fsetxattr
+ .long sys_getxattr
+ .long sys_lgetxattr /* 230 */
+ .long sys_fgetxattr
+ .long sys_listxattr
+ .long sys_llistxattr
+ .long sys_flistxattr
+ .long sys_removexattr /* 235 */
+ .long sys_lremovexattr
+ .long sys_fremovexattr
+ .long sys_tkill
+ .long sys_sendfile64
+ .long sys_futex /* 240 */
+ .long sys_sched_setaffinity
+ .long sys_sched_getaffinity
+ .long sys_ni_syscall
+ .long sys_ni_syscall
+ .long sys_io_setup /* 245 */
+ .long sys_io_destroy
+ .long sys_io_getevents
+ .long sys_io_submit
+ .long sys_io_cancel
+ .long sys_fadvise64 /* 250 */
+ .long sys_ni_syscall
+ .long sys_exit_group
+ .long sys_lookup_dcookie
+ .long sys_epoll_create
+ .long sys_epoll_ctl /* 255 */
+ .long sys_epoll_wait
+ .long sys_remap_file_pages
+ .long sys_set_tid_address
+ .long sys_timer_create
+ .long sys_timer_settime /* 260 */
+ .long sys_timer_gettime
+ .long sys_timer_getoverrun
+ .long sys_timer_delete
+ .long sys_clock_settime
+ .long sys_clock_gettime /* 265 */
+ .long sys_clock_getres
+ .long sys_clock_nanosleep
+ .long sys_statfs64
+ .long sys_fstatfs64
+ .long sys_tgkill /* 270 */
+ .long sys_utimes
+ .long sys_fadvise64_64_wrapper
+ .long sys_ni_syscall /* Reserved for vserver */
+ .long sys_ni_syscall /* Reserved for mbind */
+ .long sys_ni_syscall /* 275 - get_mempolicy */
+ .long sys_ni_syscall /* set_mempolicy */
+ .long sys_mq_open
+ .long sys_mq_unlink
+ .long sys_mq_timedsend
+ .long sys_mq_timedreceive /* 280 */
+ .long sys_mq_notify
+ .long sys_mq_getsetattr
+ .long sys_kexec_load
+ .long sys_waitid
+ .long sys_ni_syscall /* 285 */
+ .long sys_add_key
+ .long sys_request_key
+ .long sys_keyctl
+ .long sys_ioprio_set
+ .long sys_ioprio_get /* 290 */
+ .long sys_inotify_init
+ .long sys_inotify_add_watch
+ .long sys_inotify_rm_watch
+ .long sys_migrate_pages
+ .long sys_openat /* 295 */
+ .long sys_mkdirat
+ .long sys_mknodat
+ .long sys_fchownat
+ .long sys_futimesat
+ .long sys_fstatat64 /* 300 */
+ .long sys_unlinkat
+ .long sys_renameat
+ .long sys_linkat
+ .long sys_symlinkat
+ .long sys_readlinkat /* 305 */
+ .long sys_fchmodat
+ .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
diff --git a/arch/sh/kernel/time.c b/arch/sh/kernel/time.c
index a1589f85499d..57e708d7b52d 100644
--- a/arch/sh/kernel/time.c
+++ b/arch/sh/kernel/time.c
@@ -3,13 +3,12 @@
*
* Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
- * Copyright (C) 2002, 2003, 2004, 2005 Paul Mundt
+ * Copyright (C) 2002 - 2006 Paul Mundt
* Copyright (C) 2002 M. R. Brown <mrbrown@linux-sh.org>
*
* Some code taken from i386 version.
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
*/
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -19,22 +18,26 @@
#include <asm/timer.h>
#include <asm/kgdb.h>
-extern unsigned long wall_jiffies;
struct sys_timer *sys_timer;
/* Move this somewhere more sensible.. */
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
-/* XXX: Can we initialize this in a routine somewhere? Dreamcast doesn't want
- * these routines anywhere... */
-#ifdef CONFIG_SH_RTC
-void (*rtc_get_time)(struct timespec *) = sh_rtc_gettimeofday;
-int (*rtc_set_time)(const time_t) = sh_rtc_settimeofday;
-#else
-void (*rtc_get_time)(struct timespec *);
-int (*rtc_set_time)(const time_t);
-#endif
+/* Dummy RTC ops */
+static void null_rtc_get_time(struct timespec *tv)
+{
+ tv->tv_sec = mktime(2000, 1, 1, 0, 0, 0);
+ tv->tv_nsec = 0;
+}
+
+static int null_rtc_set_time(const time_t secs)
+{
+ 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;
/*
* Scheduler clock - returns current time in nanosec units.
@@ -44,20 +47,15 @@ unsigned long long __attribute__ ((weak)) sched_clock(void)
return (unsigned long long)jiffies * (1000000000 / HZ);
}
+#ifndef CONFIG_GENERIC_TIME
void do_gettimeofday(struct timeval *tv)
{
unsigned long seq;
unsigned long usec, sec;
- unsigned long lost;
do {
seq = read_seqbegin(&xtime_lock);
usec = get_timer_offset();
-
- lost = jiffies - wall_jiffies;
- if (lost)
- usec += lost * (1000000 / HZ);
-
sec = xtime.tv_sec;
usec += xtime.tv_nsec / 1000;
} while (read_seqretry(&xtime_lock, seq));
@@ -70,7 +68,6 @@ void do_gettimeofday(struct timeval *tv)
tv->tv_sec = sec;
tv->tv_usec = usec;
}
-
EXPORT_SYMBOL(do_gettimeofday);
int do_settimeofday(struct timespec *tv)
@@ -88,8 +85,7 @@ int do_settimeofday(struct timespec *tv)
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
- nsec -= 1000 * (get_timer_offset() +
- (jiffies - wall_jiffies) * (1000000 / HZ));
+ nsec -= 1000 * get_timer_offset();
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -103,8 +99,8 @@ int do_settimeofday(struct timespec *tv)
return 0;
}
-
EXPORT_SYMBOL(do_settimeofday);
+#endif /* !CONFIG_GENERIC_TIME */
/* last time the RTC clock got updated */
static long last_rtc_update;
@@ -113,13 +109,14 @@ static long last_rtc_update;
* handle_timer_tick() needs to keep up the real-time clock,
* as well as call the "do_timer()" routine every clocktick
*/
-void handle_timer_tick(struct pt_regs *regs)
+void handle_timer_tick(void)
{
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
- profile_tick(CPU_PROFILING, regs);
+ if (current->pid)
+ profile_tick(CPU_PROFILING);
#ifdef CONFIG_HEARTBEAT
if (sh_mv.mv_heartbeat != NULL)
@@ -135,7 +132,7 @@ void handle_timer_tick(struct pt_regs *regs)
xtime.tv_sec > last_rtc_update + 660 &&
(xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
(xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
- if (rtc_set_time(xtime.tv_sec) == 0)
+ if (rtc_sh_set_time(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
/* do it again in 60s */
@@ -143,8 +140,33 @@ void handle_timer_tick(struct pt_regs *regs)
}
}
+#ifdef CONFIG_PM
+int timer_suspend(struct sys_device *dev, pm_message_t state)
+{
+ struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
+
+ sys_timer->ops->stop();
+
+ return 0;
+}
+
+int timer_resume(struct sys_device *dev)
+{
+ struct sys_timer *sys_timer = container_of(dev, struct sys_timer, dev);
+
+ sys_timer->ops->start();
+
+ return 0;
+}
+#else
+#define timer_suspend NULL
+#define timer_resume NULL
+#endif
+
static struct sysdev_class timer_sysclass = {
set_kset_name("timer"),
+ .suspend = timer_suspend,
+ .resume = timer_resume,
};
static int __init timer_init_sysfs(void)
@@ -156,7 +178,6 @@ static int __init timer_init_sysfs(void)
sys_timer->dev.cls = &timer_sysclass;
return sysdev_register(&sys_timer->dev);
}
-
device_initcall(timer_init_sysfs);
void (*board_time_init)(void);
@@ -168,15 +189,9 @@ void __init time_init(void)
clk_init();
- if (rtc_get_time) {
- rtc_get_time(&xtime);
- } else {
- xtime.tv_sec = mktime(2000, 1, 1, 0, 0, 0);
- xtime.tv_nsec = 0;
- }
-
- set_normalized_timespec(&wall_to_monotonic,
- -xtime.tv_sec, -xtime.tv_nsec);
+ rtc_sh_get_time(&xtime);
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
/*
* Find the timer to use as the system timer, it will be
diff --git a/arch/sh/kernel/timers/timer-tmu.c b/arch/sh/kernel/timers/timer-tmu.c
index d4212add53b2..24927015dc31 100644
--- a/arch/sh/kernel/timers/timer-tmu.c
+++ b/arch/sh/kernel/timers/timer-tmu.c
@@ -80,8 +80,7 @@ static unsigned long tmu_timer_get_offset(void)
return count;
}
-static irqreturn_t tmu_timer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t tmu_timer_interrupt(int irq, void *dummy)
{
unsigned long timer_status;
@@ -98,7 +97,7 @@ static irqreturn_t tmu_timer_interrupt(int irq, void *dev_id,
* locally disabled. -arca
*/
write_seqlock(&xtime_lock);
- handle_timer_tick(regs);
+ handle_timer_tick();
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
@@ -111,60 +110,6 @@ static struct irqaction tmu_irq = {
.mask = CPU_MASK_NONE,
};
-/*
- * Hah! We'll see if this works (switching from usecs to nsecs).
- */
-static unsigned long tmu_timer_get_frequency(void)
-{
- u32 freq;
- struct timespec ts1, ts2;
- unsigned long diff_nsec;
- unsigned long factor;
-
- /* Setup the timer: We don't want to generate interrupts, just
- * have it count down at its natural rate.
- */
- ctrl_outb(0, TMU_TSTR);
-#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
- ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
-#endif
- ctrl_outw(TMU0_TCR_CALIB, TMU0_TCR);
- ctrl_outl(0xffffffff, TMU0_TCOR);
- ctrl_outl(0xffffffff, TMU0_TCNT);
-
- rtc_get_time(&ts2);
-
- do {
- rtc_get_time(&ts1);
- } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
-
- /* actually start the timer */
- ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
-
- do {
- rtc_get_time(&ts2);
- } while (ts1.tv_nsec == ts2.tv_nsec && ts1.tv_sec == ts2.tv_sec);
-
- freq = 0xffffffff - ctrl_inl(TMU0_TCNT);
- if (ts2.tv_nsec < ts1.tv_nsec) {
- ts2.tv_nsec += 1000000000;
- ts2.tv_sec--;
- }
-
- diff_nsec = (ts2.tv_sec - ts1.tv_sec) * 1000000000 + (ts2.tv_nsec - ts1.tv_nsec);
-
- /* this should work well if the RTC has a precision of n Hz, where
- * n is an integer. I don't think we have to worry about the other
- * cases. */
- factor = (1000000000 + diff_nsec/2) / diff_nsec;
-
- if (factor * diff_nsec > 1100000000 ||
- factor * diff_nsec < 900000000)
- panic("weird RTC (diff_nsec %ld)", diff_nsec);
-
- return freq * factor;
-}
-
static void tmu_clk_init(struct clk *clk)
{
u8 divisor = TMU0_TCR_INIT & 0x7;
@@ -188,6 +133,18 @@ static struct clk tmu0_clk = {
.ops = &tmu_clk_ops,
};
+static int tmu_timer_start(void)
+{
+ ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
+ return 0;
+}
+
+static int tmu_timer_stop(void)
+{
+ ctrl_outb(0, TMU_TSTR);
+ return 0;
+}
+
static int tmu_timer_init(void)
{
unsigned long interval;
@@ -197,7 +154,7 @@ static int tmu_timer_init(void)
tmu0_clk.parent = clk_get("module_clk");
/* Start TMU0 */
- ctrl_outb(0, TMU_TSTR);
+ tmu_timer_stop();
#if !defined(CONFIG_CPU_SUBTYPE_SH7300) && !defined(CONFIG_CPU_SUBTYPE_SH7760)
ctrl_outb(TMU_TOCR_INIT, TMU_TOCR);
#endif
@@ -211,19 +168,21 @@ static int tmu_timer_init(void)
ctrl_outl(interval, TMU0_TCOR);
ctrl_outl(interval, TMU0_TCNT);
- ctrl_outb(TMU_TSTR_INIT, TMU_TSTR);
+ tmu_timer_start();
return 0;
}
struct sys_timer_ops tmu_timer_ops = {
.init = tmu_timer_init,
- .get_frequency = tmu_timer_get_frequency,
+ .start = tmu_timer_start,
+ .stop = tmu_timer_stop,
+#ifndef CONFIG_GENERIC_TIME
.get_offset = tmu_timer_get_offset,
+#endif
};
struct sys_timer tmu_timer = {
.name = "tmu",
.ops = &tmu_timer_ops,
};
-
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index d9db1180f770..c2c597e09482 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -36,40 +36,15 @@
#ifdef CONFIG_SH_KGDB
#include <asm/kgdb.h>
-#define CHK_REMOTE_DEBUG(regs) \
-{ \
- if ((kgdb_debug_hook != (kgdb_debug_hook_t *) NULL) && (!user_mode(regs))) \
- { \
- (*kgdb_debug_hook)(regs); \
- } \
+#define CHK_REMOTE_DEBUG(regs) \
+{ \
+ if (kgdb_debug_hook && !user_mode(regs))\
+ (*kgdb_debug_hook)(regs); \
}
#else
#define CHK_REMOTE_DEBUG(regs)
#endif
-#define DO_ERROR(trapnr, signr, str, name, tsk) \
-asmlinkage void do_##name(unsigned long r4, unsigned long r5, \
- unsigned long r6, unsigned long r7, \
- struct pt_regs regs) \
-{ \
- unsigned long error_code; \
- \
- /* Check if it's a DSP instruction */ \
- if (is_dsp_inst(&regs)) { \
- /* Enable DSP mode, and restart instruction. */ \
- regs.sr |= SR_DSP; \
- return; \
- } \
- \
- asm volatile("stc r2_bank, %0": "=r" (error_code)); \
- local_irq_enable(); \
- tsk->thread.error_code = error_code; \
- tsk->thread.trap_no = trapnr; \
- CHK_REMOTE_DEBUG(&regs); \
- force_sig(signr, tsk); \
- die_if_no_fixup(str,&regs,error_code); \
-}
-
#ifdef CONFIG_CPU_SH2
#define TRAP_RESERVED_INST 4
#define TRAP_ILLEGAL_SLOT_INST 6
@@ -86,7 +61,7 @@ asmlinkage void do_##name(unsigned long r4, unsigned long r5, \
#define VMALLOC_OFFSET (8*1024*1024)
#define MODULE_RANGE (8*1024*1024)
-spinlock_t die_lock;
+DEFINE_SPINLOCK(die_lock);
void die(const char * str, struct pt_regs * regs, long err)
{
@@ -575,8 +550,117 @@ int is_dsp_inst(struct pt_regs *regs)
#define is_dsp_inst(regs) (0)
#endif /* CONFIG_SH_DSP */
-DO_ERROR(TRAP_RESERVED_INST, SIGILL, "reserved instruction", reserved_inst, current)
-DO_ERROR(TRAP_ILLEGAL_SLOT_INST, SIGILL, "illegal slot instruction", illegal_slot_inst, current)
+extern int do_fpu_inst(unsigned short, struct pt_regs*);
+
+asmlinkage void do_reserved_inst(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs regs)
+{
+ unsigned long error_code;
+ struct task_struct *tsk = current;
+
+#ifdef CONFIG_SH_FPU_EMU
+ unsigned short inst;
+ int err;
+
+ get_user(inst, (unsigned short*)regs.pc);
+
+ err = do_fpu_inst(inst, &regs);
+ if (!err) {
+ regs.pc += 2;
+ return;
+ }
+ /* not a FPU inst. */
+#endif
+
+#ifdef CONFIG_SH_DSP
+ /* Check if it's a DSP instruction */
+ if (is_dsp_inst(&regs)) {
+ /* Enable DSP mode, and restart instruction. */
+ regs.sr |= SR_DSP;
+ return;
+ }
+#endif
+
+ asm volatile("stc r2_bank, %0": "=r" (error_code));
+ local_irq_enable();
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = TRAP_RESERVED_INST;
+ CHK_REMOTE_DEBUG(&regs);
+ force_sig(SIGILL, tsk);
+ die_if_no_fixup("reserved instruction", &regs, error_code);
+}
+
+#ifdef CONFIG_SH_FPU_EMU
+static int emulate_branch(unsigned short inst, struct pt_regs* regs)
+{
+ /*
+ * bfs: 8fxx: PC+=d*2+4;
+ * bts: 8dxx: PC+=d*2+4;
+ * bra: axxx: PC+=D*2+4;
+ * bsr: bxxx: PC+=D*2+4 after PR=PC+4;
+ * braf:0x23: PC+=Rn*2+4;
+ * bsrf:0x03: PC+=Rn*2+4 after PR=PC+4;
+ * jmp: 4x2b: PC=Rn;
+ * jsr: 4x0b: PC=Rn after PR=PC+4;
+ * rts: 000b: PC=PR;
+ */
+ if ((inst & 0xfd00) == 0x8d00) {
+ regs->pc += SH_PC_8BIT_OFFSET(inst);
+ return 0;
+ }
+
+ if ((inst & 0xe000) == 0xa000) {
+ regs->pc += SH_PC_12BIT_OFFSET(inst);
+ return 0;
+ }
+
+ if ((inst & 0xf0df) == 0x0003) {
+ regs->pc += regs->regs[(inst & 0x0f00) >> 8] + 4;
+ return 0;
+ }
+
+ if ((inst & 0xf0df) == 0x400b) {
+ regs->pc = regs->regs[(inst & 0x0f00) >> 8];
+ return 0;
+ }
+
+ if ((inst & 0xffff) == 0x000b) {
+ regs->pc = regs->pr;
+ return 0;
+ }
+
+ return 1;
+}
+#endif
+
+asmlinkage void do_illegal_slot_inst(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs regs)
+{
+ unsigned long error_code;
+ struct task_struct *tsk = current;
+#ifdef CONFIG_SH_FPU_EMU
+ unsigned short inst;
+
+ get_user(inst, (unsigned short *)regs.pc + 1);
+ if (!do_fpu_inst(inst, &regs)) {
+ get_user(inst, (unsigned short *)regs.pc);
+ if (!emulate_branch(inst, &regs))
+ return;
+ /* fault in branch.*/
+ }
+ /* not a FPU inst. */
+#endif
+
+ asm volatile("stc r2_bank, %0": "=r" (error_code));
+ local_irq_enable();
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = TRAP_RESERVED_INST;
+ CHK_REMOTE_DEBUG(&regs);
+ force_sig(SIGILL, tsk);
+ die_if_no_fixup("illegal slot instruction", &regs, error_code);
+}
asmlinkage void do_exception_error(unsigned long r4, unsigned long r5,
unsigned long r6, unsigned long r7,
@@ -634,14 +718,16 @@ void __init trap_init(void)
exception_handling_table[TRAP_ILLEGAL_SLOT_INST]
= (void *)do_illegal_slot_inst;
-#ifdef CONFIG_CPU_SH4
- if (!(cpu_data->flags & CPU_HAS_FPU)) {
- /* For SH-4 lacking an FPU, treat floating point instructions
- as reserved. */
- /* entry 64 corresponds to EXPEVT=0x800 */
- exception_handling_table[64] = (void *)do_reserved_inst;
- exception_handling_table[65] = (void *)do_illegal_slot_inst;
- }
+#if defined(CONFIG_CPU_SH4) && !defined(CONFIG_SH_FPU) || \
+ defined(CONFIG_SH_FPU_EMU)
+ /*
+ * For SH-4 lacking an FPU, treat floating point instructions as
+ * reserved. They'll be handled in the math-emu case, or faulted on
+ * otherwise.
+ */
+ /* entry 64 corresponds to EXPEVT=0x800 */
+ exception_handling_table[64] = (void *)do_reserved_inst;
+ exception_handling_table[65] = (void *)do_illegal_slot_inst;
#endif
/* Setup VBR for boot cpu */
@@ -655,20 +741,12 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
unsigned long module_end = VMALLOC_END;
int i = 1;
- if (tsk && !sp) {
+ if (!tsk)
+ tsk = current;
+ if (tsk == current)
+ sp = (unsigned long *)current_stack_pointer;
+ else
sp = (unsigned long *)tsk->thread.sp;
- }
-
- if (!sp) {
- __asm__ __volatile__ (
- "mov r15, %0\n\t"
- "stc r7_bank, %1\n\t"
- : "=r" (module_start),
- "=r" (module_end)
- );
-
- sp = (unsigned long *)module_start;
- }
stack = sp;
diff --git a/arch/sh/kernel/vmlinux.lds.S b/arch/sh/kernel/vmlinux.lds.S
index 95fdd9135fcf..5eb930918186 100644
--- a/arch/sh/kernel/vmlinux.lds.S
+++ b/arch/sh/kernel/vmlinux.lds.S
@@ -2,6 +2,7 @@
* ld script to make SuperH Linux kernel
* Written by Niibe Yutaka
*/
+#include <asm/thread_info.h>
#include <asm-generic/vmlinux.lds.h>
#ifdef CONFIG_CPU_LITTLE_ENDIAN
@@ -13,7 +14,7 @@ OUTPUT_ARCH(sh)
ENTRY(_start)
SECTIONS
{
- . = 0x80000000 + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
+ . = CONFIG_PAGE_OFFSET + CONFIG_MEMORY_START + CONFIG_ZERO_PAGE_OFFSET;
_text = .; /* Text and read-only data */
text = .; /* Text and read-only data */
.empty_zero_page : {
@@ -40,16 +41,16 @@ SECTIONS
*(.data)
/* Align the initial ramdisk image (INITRD) on page boundaries. */
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
__rd_start = .;
*(.initrd)
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
__rd_end = .;
CONSTRUCTORS
}
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
.data.page_aligned : { *(.data.idt) }
. = ALIGN(32);
@@ -60,12 +61,10 @@ SECTIONS
_edata = .; /* End of data section */
- . = ALIGN(8192); /* init_task */
+ . = ALIGN(THREAD_SIZE); /* init_task */
.data.init_task : { *(.data.init_task) }
- /* stack */
- .stack : { stack = .; _stack = .; }
- . = ALIGN(4096); /* Init code and data */
+ . = ALIGN(PAGE_SIZE); /* Init code and data */
__init_begin = .;
_sinittext = .;
.init.text : { *(.init.text) }
@@ -96,7 +95,7 @@ SECTIONS
__machvec_start = .;
.init.machvec : { *(.init.machvec) }
__machvec_end = .;
- . = ALIGN(4096);
+ . = ALIGN(PAGE_SIZE);
__init_end = .;
. = ALIGN(4);
diff --git a/arch/sh/kernel/vsyscall/.gitignore b/arch/sh/kernel/vsyscall/.gitignore
new file mode 100644
index 000000000000..40836ad9079c
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/.gitignore
@@ -0,0 +1 @@
+vsyscall.lds
diff --git a/arch/sh/kernel/vsyscall/Makefile b/arch/sh/kernel/vsyscall/Makefile
new file mode 100644
index 000000000000..4bbce1cfa359
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/Makefile
@@ -0,0 +1,36 @@
+obj-y += vsyscall.o vsyscall-syscall.o
+
+$(obj)/vsyscall-syscall.o: \
+ $(foreach F,trapa,$(obj)/vsyscall-$F.so)
+
+# Teach kbuild about targets
+targets += $(foreach F,trapa,vsyscall-$F.o vsyscall-$F.so)
+targets += vsyscall-note.o vsyscall.lds
+
+# The DSO images are built using a special linker script
+quiet_cmd_syscall = SYSCALL $@
+ cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \
+ -Wl,-T,$(filter-out FORCE,$^) -o $@
+
+export CPPFLAGS_vsyscall.lds += -P -C -Ush
+
+vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \
+ $(call ld-option, -Wl$(comma)--hash-style=sysv)
+
+SYSCFLAGS_vsyscall-trapa.so = $(vsyscall-flags)
+
+$(obj)/vsyscall-trapa.so: \
+$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
+ $(call if_changed,syscall)
+
+# We also create a special relocatable object that should mirror the symbol
+# table and layout of the linked DSO. With ld -R we can then refer to
+# these symbols in the kernel code rather than hand-coded addresses.
+extra-y += vsyscall-syms.o
+$(obj)/built-in.o: $(obj)/vsyscall-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
+
+SYSCFLAGS_vsyscall-syms.o = -r
+$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \
+ $(obj)/vsyscall-trapa.o $(obj)/vsyscall-note.o FORCE
+ $(call if_changed,syscall)
diff --git a/arch/sh/kernel/vsyscall/vsyscall-note.S b/arch/sh/kernel/vsyscall/vsyscall-note.S
new file mode 100644
index 000000000000..d4b5be4f3d5f
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-note.S
@@ -0,0 +1,25 @@
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+
+#define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \
+ .section name, flags; \
+ .balign 4; \
+ .long 1f - 0f; /* name length */ \
+ .long 3f - 2f; /* data length */ \
+ .long type; /* note type */ \
+0: .asciz vendor; /* vendor name */ \
+1: .balign 4; \
+2:
+
+#define ASM_ELF_NOTE_END \
+3: .balign 4; /* pad out section */ \
+ .previous
+
+ ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0)
+ .long LINUX_VERSION_CODE
+ ASM_ELF_NOTE_END
diff --git a/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S
new file mode 100644
index 000000000000..555a64f124ca
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-sigreturn.S
@@ -0,0 +1,39 @@
+#include <asm/unistd.h>
+
+ .text
+ .balign 32
+ .globl __kernel_sigreturn
+ .type __kernel_sigreturn,@function
+__kernel_sigreturn:
+.LSTART_sigreturn:
+ mov.w 1f, r3
+ trapa #0x10
+ or r0, r0
+ or r0, r0
+ or r0, r0
+ or r0, r0
+ or r0, r0
+
+1: .short __NR_sigreturn
+.LEND_sigreturn:
+ .size __kernel_sigreturn,.-.LSTART_sigreturn
+
+ .balign 32
+ .globl __kernel_rt_sigreturn
+ .type __kernel_rt_sigreturn,@function
+__kernel_rt_sigreturn:
+.LSTART_rt_sigreturn:
+ mov.w 1f, r3
+ trapa #0x10
+ or r0, r0
+ or r0, r0
+ or r0, r0
+ or r0, r0
+ or r0, r0
+
+1: .short __NR_rt_sigreturn
+.LEND_rt_sigreturn:
+ .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
+
+ .section .eh_frame,"a",@progbits
+ .previous
diff --git a/arch/sh/kernel/vsyscall/vsyscall-syscall.S b/arch/sh/kernel/vsyscall/vsyscall-syscall.S
new file mode 100644
index 000000000000..c2ac7f0282b3
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-syscall.S
@@ -0,0 +1,10 @@
+#include <linux/init.h>
+
+__INITDATA
+
+ .globl vsyscall_trapa_start, vsyscall_trapa_end
+vsyscall_trapa_start:
+ .incbin "arch/sh/kernel/vsyscall/vsyscall-trapa.so"
+vsyscall_trapa_end:
+
+__FINIT
diff --git a/arch/sh/kernel/vsyscall/vsyscall-trapa.S b/arch/sh/kernel/vsyscall/vsyscall-trapa.S
new file mode 100644
index 000000000000..3b6eb34c43fa
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall-trapa.S
@@ -0,0 +1,42 @@
+ .text
+ .globl __kernel_vsyscall
+ .type __kernel_vsyscall,@function
+__kernel_vsyscall:
+.LSTART_vsyscall:
+ /* XXX: We'll have to do something here once we opt to use the vDSO
+ * page for something other than the signal trampoline.. as well as
+ * fill out .eh_frame -- PFM. */
+.LEND_vsyscall:
+ .size __kernel_vsyscall,.-.LSTART_vsyscall
+ .previous
+
+ .section .eh_frame,"a",@progbits
+.LCIE:
+ .ualong .LCIE_end - .LCIE_start
+.LCIE_start:
+ .ualong 0 /* CIE ID */
+ .byte 0x1 /* Version number */
+ .string "zRS" /* NUL-terminated augmentation string */
+ .uleb128 0x1 /* Code alignment factor */
+ .sleb128 -4 /* Data alignment factor */
+ .byte 0x11 /* Return address register column */
+ /* Augmentation length and data (none) */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .uleb128 0xf /* r15 */
+ .uleb128 0x0 /* offset 0 */
+
+ .align 2
+.LCIE_end:
+
+ .ualong .LFDE_end-.LFDE_start /* Length FDE */
+.LFDE_start:
+ .ualong .LCIE /* CIE pointer */
+ .ualong .LSTART_vsyscall-. /* start address */
+ .ualong .LEND_vsyscall-.LSTART_vsyscall
+ .uleb128 0
+ .align 2
+.LFDE_end:
+ .previous
+
+/* Get the common code for the sigreturn entry points */
+#include "vsyscall-sigreturn.S"
diff --git a/arch/sh/kernel/vsyscall/vsyscall.c b/arch/sh/kernel/vsyscall/vsyscall.c
new file mode 100644
index 000000000000..075d6cc1a2d7
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall.c
@@ -0,0 +1,150 @@
+/*
+ * arch/sh/kernel/vsyscall.c
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * vDSO randomization
+ * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar
+ *
+ * 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/mm.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gfp.h>
+#include <linux/module.h>
+#include <linux/elf.h>
+
+/*
+ * Should the kernel map a VDSO page into processes and pass its
+ * address down to glibc upon exec()?
+ */
+unsigned int __read_mostly vdso_enabled = 1;
+EXPORT_SYMBOL_GPL(vdso_enabled);
+
+static int __init vdso_setup(char *s)
+{
+ vdso_enabled = simple_strtoul(s, NULL, 0);
+ return 1;
+}
+__setup("vdso=", vdso_setup);
+
+/*
+ * These symbols are defined by vsyscall.o to mark the bounds
+ * of the ELF DSO images included therein.
+ */
+extern const char vsyscall_trapa_start, vsyscall_trapa_end;
+static void *syscall_page;
+
+int __init vsyscall_init(void)
+{
+ syscall_page = (void *)get_zeroed_page(GFP_ATOMIC);
+
+ /*
+ * XXX: Map this page to a fixmap entry if we get around
+ * to adding the page to ELF core dumps
+ */
+
+ memcpy(syscall_page,
+ &vsyscall_trapa_start,
+ &vsyscall_trapa_end - &vsyscall_trapa_start);
+
+ return 0;
+}
+
+static struct page *syscall_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ unsigned long offset = address - vma->vm_start;
+ struct page *page;
+
+ if (address < vma->vm_start || address > vma->vm_end)
+ return NOPAGE_SIGBUS;
+
+ page = virt_to_page(syscall_page + offset);
+
+ get_page(page);
+
+ return page;
+}
+
+/* Prevent VMA merging */
+static void syscall_vma_close(struct vm_area_struct *vma)
+{
+}
+
+static struct vm_operations_struct syscall_vm_ops = {
+ .nopage = syscall_vma_nopage,
+ .close = syscall_vma_close,
+};
+
+/* Setup a VMA at program startup for the vsyscall page */
+int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm = current->mm;
+ unsigned long addr;
+ int ret;
+
+ down_write(&mm->mmap_sem);
+ addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL);
+ if (!vma) {
+ ret = -ENOMEM;
+ goto up_fail;
+ }
+
+ vma->vm_start = addr;
+ vma->vm_end = addr + PAGE_SIZE;
+ /* MAYWRITE to allow gdb to COW and set breakpoints */
+ vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
+ vma->vm_flags |= mm->def_flags;
+ vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+ vma->vm_ops = &syscall_vm_ops;
+ vma->vm_mm = mm;
+
+ ret = insert_vm_struct(mm, vma);
+ if (unlikely(ret)) {
+ kmem_cache_free(vm_area_cachep, vma);
+ goto up_fail;
+ }
+
+ current->mm->context.vdso = (void *)addr;
+
+ mm->total_vm++;
+up_fail:
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
+ return "[vdso]";
+
+ return NULL;
+}
+
+struct vm_area_struct *get_gate_vma(struct task_struct *task)
+{
+ return NULL;
+}
+
+int in_gate_area(struct task_struct *task, unsigned long address)
+{
+ return 0;
+}
+
+int in_gate_area_no_task(unsigned long address)
+{
+ return 0;
+}
diff --git a/arch/sh/kernel/vsyscall/vsyscall.lds.S b/arch/sh/kernel/vsyscall/vsyscall.lds.S
new file mode 100644
index 000000000000..b13c3d439fee
--- /dev/null
+++ b/arch/sh/kernel/vsyscall/vsyscall.lds.S
@@ -0,0 +1,74 @@
+/*
+ * Linker script for vsyscall DSO. The vsyscall page is an ELF shared
+ * object prelinked to its virtual address, and with only one read-only
+ * segment (that fits in one page). This script controls its layout.
+ */
+#include <asm/asm-offsets.h>
+
+#ifdef CONFIG_CPU_LITTLE_ENDIAN
+OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux")
+#else
+OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux")
+#endif
+OUTPUT_ARCH(sh)
+
+/* The ELF entry point can be used to set the AT_SYSINFO value. */
+ENTRY(__kernel_vsyscall);
+
+SECTIONS
+{
+ . = SIZEOF_HEADERS;
+
+ .hash : { *(.hash) } :text
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+
+ /* This linker script is used both with -r and with -shared.
+ For the layouts to match, we need to skip more than enough
+ space for the dynamic symbol table et al. If this amount
+ is insufficient, ld -shared will barf. Just increase it here. */
+ . = 0x400;
+
+ .text : { *(.text) } :text =0x90909090
+ .note : { *(.note.*) } :text :note
+ .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
+ .eh_frame : { KEEP (*(.eh_frame)) } :text
+ .dynamic : { *(.dynamic) } :text :dynamic
+ .useless : {
+ *(.got.plt) *(.got)
+ *(.data .data.* .gnu.linkonce.d.*)
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ } :text
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+ text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+ dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
+ note PT_NOTE FLAGS(4); /* PF_R */
+ eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+ LINUX_2.6 {
+ global:
+ __kernel_vsyscall;
+ __kernel_sigreturn;
+ __kernel_rt_sigreturn;
+
+ local: *;
+ };
+}
diff --git a/arch/sh/lib/checksum.S b/arch/sh/lib/checksum.S
index 7c50dfe68c07..cbdd0d40e545 100644
--- a/arch/sh/lib/checksum.S
+++ b/arch/sh/lib/checksum.S
@@ -202,8 +202,9 @@ ENTRY(csum_partial_copy_generic)
cmp/pz r6 ! Jump if we had at least two bytes.
bt/s 1f
clrt
+ add #2,r6 ! r6 was < 2. Deal with it.
bra 4f
- add #2,r6 ! r6 was < 2. Deal with it.
+ mov r6,r2
3: ! Handle different src and dest alignments.
! This is not common, so simple byte by byte copy will do.
diff --git a/arch/sh/lib/memcpy-sh4.S b/arch/sh/lib/memcpy-sh4.S
index db6b736537ad..560bc17eebdd 100644
--- a/arch/sh/lib/memcpy-sh4.S
+++ b/arch/sh/lib/memcpy-sh4.S
@@ -727,8 +727,8 @@ ENTRY(memcpy)
mov.l @(0x04,r5), r11 ! 18 LS (latency=2)
xtrct r9, r8 ! 48 EX
- mov.w @(0x02,r5), r12 ! 18 LS (latency=2)
- xtrct r10, r9 ! 48 EX
+ mov.l @(0x00,r5), r12 ! 18 LS (latency=2)
+ xtrct r10, r9 ! 48 EX
movca.l r0,@r1 ! 40 LS (latency=3-7)
add #-0x1c, r1 ! 50 EX
diff --git a/arch/sh/lib/memset.S b/arch/sh/lib/memset.S
index 95670090680e..af91fe2b72a6 100644
--- a/arch/sh/lib/memset.S
+++ b/arch/sh/lib/memset.S
@@ -29,6 +29,7 @@ ENTRY(memset)
bf/s 1b
mov.b r5,@-r4
2: ! make VVVV
+ extu.b r5,r5
swap.b r5,r0 ! V0
or r0,r5 ! VV
swap.w r5,r0 ! VV00
diff --git a/arch/sh/math-emu/Makefile b/arch/sh/math-emu/Makefile
new file mode 100644
index 000000000000..638b342c781a
--- /dev/null
+++ b/arch/sh/math-emu/Makefile
@@ -0,0 +1 @@
+obj-y := math.o
diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c
new file mode 100644
index 000000000000..1efbac15ff4e
--- /dev/null
+++ b/arch/sh/math-emu/math.c
@@ -0,0 +1,623 @@
+/*
+ * arch/sh/math-emu/math.c
+ *
+ * Copyright (C) 2006 Takashi YOSHII <takasi-y@ops.dti.ne.jp>
+ *
+ * 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/errno.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/io.h>
+
+#include "sfp-util.h"
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+#include <math-emu/double.h>
+
+#define FPUL (fregs->fpul)
+#define FPSCR (fregs->fpscr)
+#define FPSCR_RM (FPSCR&3)
+#define FPSCR_DN ((FPSCR>>18)&1)
+#define FPSCR_PR ((FPSCR>>19)&1)
+#define FPSCR_SZ ((FPSCR>>20)&1)
+#define FPSCR_FR ((FPSCR>>21)&1)
+#define FPSCR_MASK 0x003fffffUL
+
+#define BANK(n) (n^(FPSCR_FR?16:0))
+#define FR ((unsigned long*)(fregs->fp_regs))
+#define FR0 (FR[BANK(0)])
+#define FRn (FR[BANK(n)])
+#define FRm (FR[BANK(m)])
+#define DR ((unsigned long long*)(fregs->fp_regs))
+#define DRn (DR[BANK(n)/2])
+#define DRm (DR[BANK(m)/2])
+
+#define XREG(n) (n^16)
+#define XFn (FR[BANK(XREG(n))])
+#define XFm (FR[BANK(XREG(m))])
+#define XDn (DR[BANK(XREG(n))/2])
+#define XDm (DR[BANK(XREG(m))/2])
+
+#define R0 (regs->regs[0])
+#define Rn (regs->regs[n])
+#define Rm (regs->regs[m])
+
+#define WRITE(d,a) ({if(put_user(d, (typeof (d)*)a)) return -EFAULT;})
+#define READ(d,a) ({if(get_user(d, (typeof (d)*)a)) return -EFAULT;})
+
+#define PACK_S(r,f) FP_PACK_SP(&r,f)
+#define UNPACK_S(f,r) FP_UNPACK_SP(f,&r)
+#define PACK_D(r,f) \
+ {u32 t[2]; FP_PACK_DP(t,f); ((u32*)&r)[0]=t[1]; ((u32*)&r)[1]=t[0];}
+#define UNPACK_D(f,r) \
+ {u32 t[2]; t[0]=((u32*)&r)[1]; t[1]=((u32*)&r)[0]; FP_UNPACK_DP(f,t);}
+
+// 2 args instructions.
+#define BOTH_PRmn(op,x) \
+ FP_DECL_EX; if(FPSCR_PR) op(D,x,DRm,DRn); else op(S,x,FRm,FRn);
+
+#define CMP_X(SZ,R,M,N) do{ \
+ FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \
+ UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
+ FP_CMP_##SZ(R, Fn, Fm, 2); }while(0)
+#define EQ_X(SZ,R,M,N) do{ \
+ FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \
+ UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
+ FP_CMP_EQ_##SZ(R, Fn, Fm); }while(0)
+#define CMP(OP) ({ int r; BOTH_PRmn(OP##_X,r); r; })
+
+static int
+fcmp_gt(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ if (CMP(CMP) > 0)
+ regs->sr |= 1;
+ else
+ regs->sr &= ~1;
+
+ return 0;
+}
+
+static int
+fcmp_eq(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ if (CMP(CMP /*EQ*/) == 0)
+ regs->sr |= 1;
+ else
+ regs->sr &= ~1;
+ return 0;
+}
+
+#define ARITH_X(SZ,OP,M,N) do{ \
+ FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); FP_DECL_##SZ(Fr); \
+ UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
+ FP_##OP##_##SZ(Fr, Fn, Fm); \
+ PACK_##SZ(N, Fr); }while(0)
+
+static int
+fadd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ BOTH_PRmn(ARITH_X, ADD);
+ return 0;
+}
+
+static int
+fsub(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ BOTH_PRmn(ARITH_X, SUB);
+ return 0;
+}
+
+static int
+fmul(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ BOTH_PRmn(ARITH_X, MUL);
+ return 0;
+}
+
+static int
+fdiv(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ BOTH_PRmn(ARITH_X, DIV);
+ return 0;
+}
+
+static int
+fmac(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ FP_DECL_EX;
+ FP_DECL_S(Fr);
+ FP_DECL_S(Ft);
+ FP_DECL_S(F0);
+ FP_DECL_S(Fm);
+ FP_DECL_S(Fn);
+ UNPACK_S(F0, FR0);
+ UNPACK_S(Fm, FRm);
+ UNPACK_S(Fn, FRn);
+ FP_MUL_S(Ft, Fm, F0);
+ FP_ADD_S(Fr, Fn, Ft);
+ PACK_S(FRn, Fr);
+ return 0;
+}
+
+// to process fmov's extention (odd n for DR access XD).
+#define FMOV_EXT(x) if(x&1) x+=16-1
+
+static int
+fmov_idx_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
+ int n)
+{
+ if (FPSCR_SZ) {
+ FMOV_EXT(n);
+ READ(FRn, Rm + R0 + 4);
+ n++;
+ READ(FRn, Rm + R0);
+ } else {
+ READ(FRn, Rm + R0);
+ }
+
+ return 0;
+}
+
+static int
+fmov_mem_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
+ int n)
+{
+ if (FPSCR_SZ) {
+ FMOV_EXT(n);
+ READ(FRn, Rm + 4);
+ n++;
+ READ(FRn, Rm);
+ } else {
+ READ(FRn, Rm);
+ }
+
+ return 0;
+}
+
+static int
+fmov_inc_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
+ int n)
+{
+ if (FPSCR_SZ) {
+ FMOV_EXT(n);
+ READ(FRn, Rm + 4);
+ n++;
+ READ(FRn, Rm);
+ Rm += 8;
+ } else {
+ READ(FRn, Rm);
+ Rm += 4;
+ }
+
+ return 0;
+}
+
+static int
+fmov_reg_idx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
+ int n)
+{
+ if (FPSCR_SZ) {
+ FMOV_EXT(m);
+ WRITE(FRm, Rn + R0 + 4);
+ m++;
+ WRITE(FRm, Rn + R0);
+ } else {
+ WRITE(FRm, Rn + R0);
+ }
+
+ return 0;
+}
+
+static int
+fmov_reg_mem(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
+ int n)
+{
+ if (FPSCR_SZ) {
+ FMOV_EXT(m);
+ WRITE(FRm, Rn + 4);
+ m++;
+ WRITE(FRm, Rn);
+ } else {
+ WRITE(FRm, Rn);
+ }
+
+ return 0;
+}
+
+static int
+fmov_reg_dec(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
+ int n)
+{
+ if (FPSCR_SZ) {
+ FMOV_EXT(m);
+ Rn -= 8;
+ WRITE(FRm, Rn + 4);
+ m++;
+ WRITE(FRm, Rn);
+ } else {
+ Rn -= 4;
+ WRITE(FRm, Rn);
+ }
+
+ return 0;
+}
+
+static int
+fmov_reg_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
+ int n)
+{
+ if (FPSCR_SZ) {
+ FMOV_EXT(m);
+ FMOV_EXT(n);
+ DRn = DRm;
+ } else {
+ FRn = FRm;
+ }
+
+ return 0;
+}
+
+static int
+fnop_mn(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
+{
+ return -EINVAL;
+}
+
+// 1 arg instructions.
+#define NOTYETn(i) static int i(struct sh_fpu_soft_struct *fregs, int n) \
+ { printk( #i " not yet done.\n"); return 0; }
+
+NOTYETn(ftrv)
+NOTYETn(fsqrt)
+NOTYETn(fipr)
+NOTYETn(fsca)
+NOTYETn(fsrra)
+
+#define EMU_FLOAT_X(SZ,N) do { \
+ FP_DECL_##SZ(Fn); \
+ FP_FROM_INT_##SZ(Fn, FPUL, 32, int); \
+ PACK_##SZ(N, Fn); }while(0)
+static int ffloat(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FP_DECL_EX;
+
+ if (FPSCR_PR)
+ EMU_FLOAT_X(D, DRn);
+ else
+ EMU_FLOAT_X(S, FRn);
+
+ return 0;
+}
+
+#define EMU_FTRC_X(SZ,N) do { \
+ FP_DECL_##SZ(Fn); \
+ UNPACK_##SZ(Fn, N); \
+ FP_TO_INT_##SZ(FPUL, Fn, 32, 1); }while(0)
+static int ftrc(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FP_DECL_EX;
+
+ if (FPSCR_PR)
+ EMU_FTRC_X(D, DRn);
+ else
+ EMU_FTRC_X(S, FRn);
+
+ return 0;
+}
+
+static int fcnvsd(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FP_DECL_EX;
+ FP_DECL_S(Fn);
+ FP_DECL_D(Fr);
+ UNPACK_S(Fn, FPUL);
+ FP_CONV(D, S, 2, 1, Fr, Fn);
+ PACK_D(DRn, Fr);
+ return 0;
+}
+
+static int fcnvds(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FP_DECL_EX;
+ FP_DECL_D(Fn);
+ FP_DECL_S(Fr);
+ UNPACK_D(Fn, DRn);
+ FP_CONV(S, D, 1, 2, Fr, Fn);
+ PACK_S(FPUL, Fr);
+ return 0;
+}
+
+static int fxchg(struct sh_fpu_soft_struct *fregs, int flag)
+{
+ FPSCR ^= flag;
+ return 0;
+}
+
+static int fsts(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FRn = FPUL;
+ return 0;
+}
+
+static int flds(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FPUL = FRn;
+ return 0;
+}
+
+static int fneg(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FRn ^= (1 << (_FP_W_TYPE_SIZE - 1));
+ return 0;
+}
+
+static int fabs(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FRn &= ~(1 << (_FP_W_TYPE_SIZE - 1));
+ return 0;
+}
+
+static int fld0(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FRn = 0;
+ return 0;
+}
+
+static int fld1(struct sh_fpu_soft_struct *fregs, int n)
+{
+ FRn = (_FP_EXPBIAS_S << (_FP_FRACBITS_S - 1));
+ return 0;
+}
+
+static int fnop_n(struct sh_fpu_soft_struct *fregs, int n)
+{
+ return -EINVAL;
+}
+
+/// Instruction decoders.
+
+static int id_fxfd(struct sh_fpu_soft_struct *, int);
+static int id_fnxd(struct sh_fpu_soft_struct *, struct pt_regs *, int, int);
+
+static int (*fnxd[])(struct sh_fpu_soft_struct *, int) = {
+ fsts, flds, ffloat, ftrc, fneg, fabs, fsqrt, fsrra,
+ fld0, fld1, fcnvsd, fcnvds, fnop_n, fnop_n, fipr, id_fxfd
+};
+
+static int (*fnmx[])(struct sh_fpu_soft_struct *, struct pt_regs *, int, int) = {
+ fadd, fsub, fmul, fdiv, fcmp_eq, fcmp_gt, fmov_idx_reg, fmov_reg_idx,
+ fmov_mem_reg, fmov_inc_reg, fmov_reg_mem, fmov_reg_dec,
+ fmov_reg_reg, id_fnxd, fmac, fnop_mn};
+
+static int id_fxfd(struct sh_fpu_soft_struct *fregs, int x)
+{
+ const int flag[] = { FPSCR_SZ, FPSCR_PR, FPSCR_FR, 0 };
+ switch (x & 3) {
+ case 3:
+ fxchg(fregs, flag[x >> 2]);
+ break;
+ case 1:
+ ftrv(fregs, x - 1);
+ break;
+ default:
+ fsca(fregs, x);
+ }
+ return 0;
+}
+
+static int
+id_fnxd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int x, int n)
+{
+ return (fnxd[x])(fregs, n);
+}
+
+static int
+id_fnmx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code)
+{
+ int n = (code >> 8) & 0xf, m = (code >> 4) & 0xf, x = code & 0xf;
+ return (fnmx[x])(fregs, regs, m, n);
+}
+
+static int
+id_sys(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code)
+{
+ int n = ((code >> 8) & 0xf);
+ unsigned long *reg = (code & 0x0010) ? &FPUL : &FPSCR;
+
+ switch (code & 0xf0ff) {
+ case 0x005a:
+ case 0x006a:
+ Rn = *reg;
+ break;
+ case 0x405a:
+ case 0x406a:
+ *reg = Rn;
+ break;
+ case 0x4052:
+ case 0x4062:
+ Rn -= 4;
+ WRITE(*reg, Rn);
+ break;
+ case 0x4056:
+ case 0x4066:
+ READ(*reg, Rn);
+ Rn += 4;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fpu_emulate(u16 code, struct sh_fpu_soft_struct *fregs, struct pt_regs *regs)
+{
+ if ((code & 0xf000) == 0xf000)
+ return id_fnmx(fregs, regs, code);
+ else
+ return id_sys(fregs, regs, code);
+}
+
+/**
+ * denormal_to_double - Given denormalized float number,
+ * store double float
+ *
+ * @fpu: Pointer to sh_fpu_hard structure
+ * @n: Index to FP register
+ */
+static void denormal_to_double(struct sh_fpu_hard_struct *fpu, int n)
+{
+ unsigned long du, dl;
+ unsigned long x = fpu->fpul;
+ int exp = 1023 - 126;
+
+ if (x != 0 && (x & 0x7f800000) == 0) {
+ du = (x & 0x80000000);
+ while ((x & 0x00800000) == 0) {
+ x <<= 1;
+ exp--;
+ }
+ x &= 0x007fffff;
+ du |= (exp << 20) | (x >> 3);
+ dl = x << 29;
+
+ fpu->fp_regs[n] = du;
+ fpu->fp_regs[n+1] = dl;
+ }
+}
+
+/**
+ * ieee_fpe_handler - Handle denormalized number exception
+ *
+ * @regs: Pointer to register structure
+ *
+ * Returns 1 when it's handled (should not cause exception).
+ */
+static int ieee_fpe_handler(struct pt_regs *regs)
+{
+ unsigned short insn = *(unsigned short *)regs->pc;
+ unsigned short finsn;
+ unsigned long nextpc;
+ int nib[4] = {
+ (insn >> 12) & 0xf,
+ (insn >> 8) & 0xf,
+ (insn >> 4) & 0xf,
+ insn & 0xf};
+
+ if (nib[0] == 0xb ||
+ (nib[0] == 0x4 && nib[2] == 0x0 && nib[3] == 0xb)) /* bsr & jsr */
+ regs->pr = regs->pc + 4;
+
+ if (nib[0] == 0xa || nib[0] == 0xb) { /* bra & bsr */
+ nextpc = regs->pc + 4 + ((short) ((insn & 0xfff) << 4) >> 3);
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x8 && nib[1] == 0xd) { /* bt/s */
+ if (regs->sr & 1)
+ nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+ else
+ nextpc = regs->pc + 4;
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x8 && nib[1] == 0xf) { /* bf/s */
+ if (regs->sr & 1)
+ nextpc = regs->pc + 4;
+ else
+ nextpc = regs->pc + 4 + ((char) (insn & 0xff) << 1);
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x4 && nib[3] == 0xb &&
+ (nib[2] == 0x0 || nib[2] == 0x2)) { /* jmp & jsr */
+ nextpc = regs->regs[nib[1]];
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (nib[0] == 0x0 && nib[3] == 0x3 &&
+ (nib[2] == 0x0 || nib[2] == 0x2)) { /* braf & bsrf */
+ nextpc = regs->pc + 4 + regs->regs[nib[1]];
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else if (insn == 0x000b) { /* rts */
+ nextpc = regs->pr;
+ finsn = *(unsigned short *) (regs->pc + 2);
+ } else {
+ nextpc = regs->pc + 2;
+ finsn = insn;
+ }
+
+ if ((finsn & 0xf1ff) == 0xf0ad) { /* fcnvsd */
+ struct task_struct *tsk = current;
+
+ if ((tsk->thread.fpu.hard.fpscr & (1 << 17))) {
+ /* FPU error */
+ denormal_to_double (&tsk->thread.fpu.hard,
+ (finsn >> 8) & 0xf);
+ tsk->thread.fpu.hard.fpscr &=
+ ~(FPSCR_CAUSE_MASK | FPSCR_FLAG_MASK);
+ set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ } else {
+ tsk->thread.trap_no = 11;
+ tsk->thread.error_code = 0;
+ force_sig(SIGFPE, tsk);
+ }
+
+ regs->pc = nextpc;
+ return 1;
+ }
+
+ return 0;
+}
+
+asmlinkage void do_fpu_error(unsigned long r4, unsigned long r5,
+ unsigned long r6, unsigned long r7,
+ struct pt_regs regs)
+{
+ struct task_struct *tsk = current;
+
+ if (ieee_fpe_handler (&regs))
+ return;
+
+ regs.pc += 2;
+ tsk->thread.trap_no = 11;
+ tsk->thread.error_code = 0;
+ force_sig(SIGFPE, tsk);
+}
+
+/**
+ * fpu_init - Initialize FPU registers
+ * @fpu: Pointer to software emulated FPU registers.
+ */
+static void fpu_init(struct sh_fpu_soft_struct *fpu)
+{
+ int i;
+
+ fpu->fpscr = FPSCR_INIT;
+ fpu->fpul = 0;
+
+ for (i = 0; i < 16; i++) {
+ fpu->fp_regs[i] = 0;
+ fpu->xfp_regs[i]= 0;
+ }
+}
+
+/**
+ * do_fpu_inst - Handle reserved instructions for FPU emulation
+ * @inst: instruction code.
+ * @regs: registers on stack.
+ */
+int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
+{
+ struct task_struct *tsk = current;
+ struct sh_fpu_soft_struct *fpu = &(tsk->thread.fpu.soft);
+
+ if (!test_tsk_thread_flag(tsk, TIF_USEDFPU)) {
+ /* initialize once. */
+ fpu_init(fpu);
+ set_tsk_thread_flag(tsk, TIF_USEDFPU);
+ }
+
+ return fpu_emulate(inst, fpu, regs);
+}
diff --git a/arch/sh/math-emu/sfp-util.h b/arch/sh/math-emu/sfp-util.h
new file mode 100644
index 000000000000..8ae1bd310ad0
--- /dev/null
+++ b/arch/sh/math-emu/sfp-util.h
@@ -0,0 +1,72 @@
+/*
+ * These are copied from glibc/stdlib/longlong.h
+ */
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) + (bl); \
+ (sh) = (ah) + (bh) + (__x < (al)); \
+ (sl) = __x; \
+ } while (0)
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
+ do { \
+ UWtype __x; \
+ __x = (al) - (bl); \
+ (sh) = (ah) - (bh) - (__x > (al)); \
+ (sl) = __x; \
+ } while (0)
+
+#define umul_ppmm(w1, w0, u, v) \
+ __asm__ ("dmulu.l %2,%3\n\tsts macl,%1\n\tsts mach,%0" \
+ : "=r" ((u32)(w1)), "=r" ((u32)(w0)) \
+ : "r" ((u32)(u)), "r" ((u32)(v)) \
+ : "macl", "mach")
+
+#define __ll_B ((UWtype) 1 << (W_TYPE_SIZE / 2))
+#define __ll_lowpart(t) ((UWtype) (t) & (__ll_B - 1))
+#define __ll_highpart(t) ((UWtype) (t) >> (W_TYPE_SIZE / 2))
+
+#define udiv_qrnnd(q, r, n1, n0, d) \
+ do { \
+ UWtype __d1, __d0, __q1, __q0; \
+ UWtype __r1, __r0, __m; \
+ __d1 = __ll_highpart (d); \
+ __d0 = __ll_lowpart (d); \
+ \
+ __r1 = (n1) % __d1; \
+ __q1 = (n1) / __d1; \
+ __m = (UWtype) __q1 * __d0; \
+ __r1 = __r1 * __ll_B | __ll_highpart (n0); \
+ if (__r1 < __m) \
+ { \
+ __q1--, __r1 += (d); \
+ if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
+ if (__r1 < __m) \
+ __q1--, __r1 += (d); \
+ } \
+ __r1 -= __m; \
+ \
+ __r0 = __r1 % __d1; \
+ __q0 = __r1 / __d1; \
+ __m = (UWtype) __q0 * __d0; \
+ __r0 = __r0 * __ll_B | __ll_lowpart (n0); \
+ if (__r0 < __m) \
+ { \
+ __q0--, __r0 += (d); \
+ if (__r0 >= (d)) \
+ if (__r0 < __m) \
+ __q0--, __r0 += (d); \
+ } \
+ __r0 -= __m; \
+ \
+ (q) = (UWtype) __q1 * __ll_B | __q0; \
+ (r) = __r0; \
+ } while (0)
+
+#define abort() return 0
+
+#define __BYTE_ORDER __LITTLE_ENDIAN
+
+
diff --git a/arch/sh/mm/Kconfig b/arch/sh/mm/Kconfig
index fb586b1cf8bb..9dd606464d23 100644
--- a/arch/sh/mm/Kconfig
+++ b/arch/sh/mm/Kconfig
@@ -20,7 +20,10 @@ config CPU_SH4
config CPU_SH4A
bool
select CPU_SH4
- select CPU_HAS_INTC2_IRQ
+
+config CPU_SH4AL_DSP
+ bool
+ select CPU_SH4A
config CPU_SUBTYPE_ST40
bool
@@ -48,6 +51,12 @@ config CPU_SUBTYPE_SH7705
select CPU_SH3
select CPU_HAS_PINT_IRQ
+config CPU_SUBTYPE_SH7706
+ bool "Support SH7706 processor"
+ select CPU_SH3
+ help
+ Select SH7706 if you have a 133 Mhz SH-3 HD6417706 CPU.
+
config CPU_SUBTYPE_SH7707
bool "Support SH7707 processor"
select CPU_SH3
@@ -69,6 +78,12 @@ config CPU_SUBTYPE_SH7709
help
Select SH7709 if you have a 80 Mhz SH-3 HD6417709 CPU.
+config CPU_SUBTYPE_SH7710
+ bool "Support SH7710 processor"
+ select CPU_SH3
+ help
+ Select SH7710 if you have a SH3-DSP SH7710 CPU.
+
comment "SH-4 Processor Support"
config CPU_SUBTYPE_SH7750
@@ -133,10 +148,6 @@ config CPU_SUBTYPE_ST40GX1
comment "SH-4A Processor Support"
-config CPU_SUBTYPE_SH73180
- bool "Support SH73180 processor"
- select CPU_SH4A
-
config CPU_SUBTYPE_SH7770
bool "Support SH7770 processor"
select CPU_SH4A
@@ -144,6 +155,17 @@ config CPU_SUBTYPE_SH7770
config CPU_SUBTYPE_SH7780
bool "Support SH7780 processor"
select CPU_SH4A
+ select CPU_HAS_INTC2_IRQ
+
+comment "SH4AL-DSP Processor Support"
+
+config CPU_SUBTYPE_SH73180
+ bool "Support SH73180 processor"
+ select CPU_SH4AL_DSP
+
+config CPU_SUBTYPE_SH7343
+ bool "Support SH7343 processor"
+ select CPU_SH4AL_DSP
endmenu
@@ -161,15 +183,59 @@ config MMU
turning this off will boot the kernel on these machines with the
MMU implicitly switched off.
+config PAGE_OFFSET
+ hex
+ default "0x80000000" if MMU
+ default "0x00000000"
+
+config MEMORY_START
+ hex "Physical memory start address"
+ default "0x08000000"
+ ---help---
+ Computers built with Hitachi SuperH processors always
+ map the ROM starting at address zero. But the processor
+ does not specify the range that RAM takes.
+
+ The physical memory (RAM) start address will be automatically
+ set to 08000000. Other platforms, such as the Solution Engine
+ boards typically map RAM at 0C000000.
+
+ Tweak this only when porting to a new machine which does not
+ already have a defconfig. Changing it from the known correct
+ value on any of the known systems will only lead to disaster.
+
+config MEMORY_SIZE
+ hex "Physical memory size"
+ default "0x00400000"
+ help
+ This sets the default memory size assumed by your SH kernel. It can
+ be overridden as normal by the 'mem=' argument on the kernel command
+ line. If unsure, consult your board specifications or just leave it
+ as 0x00400000 which was the default value before this became
+ configurable.
+
config 32BIT
bool "Support 32-bit physical addressing through PMB"
- depends on CPU_SH4A
+ depends on CPU_SH4A && MMU
default y
help
If you say Y here, physical addressing will be extended to
32-bits through the SH-4A PMB. If this is not set, legacy
29-bit physical addressing will be used.
+config VSYSCALL
+ bool "Support vsyscall page"
+ depends on MMU
+ default y
+ help
+ This will enable support for the kernel mapping a vDSO page
+ in process space, and subsequently handing down the entry point
+ to the libc through the ELF auxiliary vector.
+
+ From the kernel side this is used for the signal trampoline.
+ For systems with an MMU that can afford to give up a page,
+ (the default value) say Y.
+
choice
prompt "HugeTLB page size"
depends on HUGETLB_PAGE && CPU_SH4 && MMU
diff --git a/arch/sh/mm/Makefile b/arch/sh/mm/Makefile
index 9489a1424644..3ffd7f68c0a2 100644
--- a/arch/sh/mm/Makefile
+++ b/arch/sh/mm/Makefile
@@ -6,20 +6,26 @@ obj-y := init.o extable.o consistent.o
obj-$(CONFIG_CPU_SH2) += cache-sh2.o
obj-$(CONFIG_CPU_SH3) += cache-sh3.o
-obj-$(CONFIG_CPU_SH4) += cache-sh4.o pg-sh4.o
+obj-$(CONFIG_CPU_SH4) += cache-sh4.o
obj-$(CONFIG_DMA_PAGE_OPS) += pg-dma.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
mmu-y := fault-nommu.o tlb-nommu.o pg-nommu.o
-mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o
+mmu-$(CONFIG_MMU) := fault.o clear_page.o copy_page.o tlb-flush.o \
+ ioremap.o
obj-y += $(mmu-y)
+ifdef CONFIG_DEBUG_FS
+obj-$(CONFIG_CPU_SH4) += cache-debugfs.o
+endif
+
ifdef CONFIG_MMU
-obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
-obj-$(CONFIG_CPU_SH4) += tlb-sh4.o ioremap.o
+obj-$(CONFIG_CPU_SH3) += tlb-sh3.o
+obj-$(CONFIG_CPU_SH4) += tlb-sh4.o pg-sh4.o
obj-$(CONFIG_SH7705_CACHE_32KB) += pg-sh7705.o
endif
-obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
+obj-$(CONFIG_SH7705_CACHE_32KB) += cache-sh7705.o
+obj-$(CONFIG_32BIT) += pmb.o
diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c
new file mode 100644
index 000000000000..e0122bd33ddb
--- /dev/null
+++ b/arch/sh/mm/cache-debugfs.c
@@ -0,0 +1,147 @@
+/*
+ * debugfs ops for the L1 cache
+ *
+ * Copyright (C) 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/init.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+
+enum cache_type {
+ CACHE_TYPE_ICACHE,
+ CACHE_TYPE_DCACHE,
+ CACHE_TYPE_UNIFIED,
+};
+
+static int cache_seq_show(struct seq_file *file, void *iter)
+{
+ unsigned int cache_type = (unsigned int)file->private;
+ struct cache_info *cache;
+ unsigned int waysize, way, cache_size;
+ unsigned long ccr, base;
+ static unsigned long addrstart = 0;
+
+ /*
+ * Go uncached immediately so we don't skew the results any
+ * more than we already are..
+ */
+ jump_to_P2();
+
+ ccr = ctrl_inl(CCR);
+ if ((ccr & CCR_CACHE_ENABLE) == 0) {
+ back_to_P1();
+
+ seq_printf(file, "disabled\n");
+ return 0;
+ }
+
+ if (cache_type == CACHE_TYPE_DCACHE) {
+ base = CACHE_OC_ADDRESS_ARRAY;
+ cache = &cpu_data->dcache;
+ } else {
+ base = CACHE_IC_ADDRESS_ARRAY;
+ cache = &cpu_data->icache;
+ }
+
+ /*
+ * Due to the amount of data written out (depending on the cache size),
+ * we may be iterated over multiple times. In this case, keep track of
+ * the entry position in addrstart, and rewind it when we've hit the
+ * end of the cache.
+ *
+ * Likewise, the same code is used for multiple caches, so care must
+ * be taken for bouncing addrstart back and forth so the appropriate
+ * cache is hit.
+ */
+ cache_size = cache->ways * cache->sets * cache->linesz;
+ if (((addrstart & 0xff000000) != base) ||
+ (addrstart & 0x00ffffff) > cache_size)
+ addrstart = base;
+
+ waysize = cache->sets;
+
+ /*
+ * If the OC is already in RAM mode, we only have
+ * half of the entries to consider..
+ */
+ if ((ccr & CCR_CACHE_ORA) && cache_type == CACHE_TYPE_DCACHE)
+ waysize >>= 1;
+
+ waysize <<= cache->entry_shift;
+
+ for (way = 0; way < cache->ways; way++) {
+ unsigned long addr;
+ unsigned int line;
+
+ seq_printf(file, "-----------------------------------------\n");
+ seq_printf(file, "Way %d\n", way);
+ seq_printf(file, "-----------------------------------------\n");
+
+ for (addr = addrstart, line = 0;
+ addr < addrstart + waysize;
+ addr += cache->linesz, line++) {
+ unsigned long data = ctrl_inl(addr);
+
+ /* Check the V bit, ignore invalid cachelines */
+ if ((data & 1) == 0)
+ continue;
+
+ /* U: Dirty, cache tag is 10 bits up */
+ seq_printf(file, "%3d: %c 0x%lx\n",
+ line, data & 2 ? 'U' : ' ',
+ data & 0x1ffffc00);
+ }
+
+ addrstart += cache->way_incr;
+ }
+
+ back_to_P1();
+
+ return 0;
+}
+
+static int cache_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cache_seq_show, inode->i_private);
+}
+
+static struct file_operations cache_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = cache_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init cache_debugfs_init(void)
+{
+ struct dentry *dcache_dentry, *icache_dentry;
+
+ dcache_dentry = debugfs_create_file("dcache", S_IRUSR, NULL,
+ (unsigned int *)CACHE_TYPE_DCACHE,
+ &cache_debugfs_fops);
+ if (IS_ERR(dcache_dentry))
+ return PTR_ERR(dcache_dentry);
+
+ icache_dentry = debugfs_create_file("icache", S_IRUSR, NULL,
+ (unsigned int *)CACHE_TYPE_ICACHE,
+ &cache_debugfs_fops);
+ if (IS_ERR(icache_dentry)) {
+ debugfs_remove(dcache_dentry);
+ return PTR_ERR(icache_dentry);
+ }
+
+ return 0;
+}
+module_init(cache_debugfs_init);
+
+MODULE_LICENSE("GPL v2");
diff --git a/arch/sh/mm/cache-sh4.c b/arch/sh/mm/cache-sh4.c
index 524cea5b47f9..e48cc22724d9 100644
--- a/arch/sh/mm/cache-sh4.c
+++ b/arch/sh/mm/cache-sh4.c
@@ -2,49 +2,120 @@
* arch/sh/mm/cache-sh4.c
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2001, 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2001 - 2006 Paul Mundt
* Copyright (C) 2003 Richard Curnow
*
* 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/init.h>
-#include <linux/mman.h>
#include <linux/mm.h>
-#include <linux/threads.h>
#include <asm/addrspace.h>
-#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
#include <asm/cache.h>
#include <asm/io.h>
-#include <asm/uaccess.h>
#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
-extern void __flush_cache_4096_all(unsigned long start);
-static void __flush_cache_4096_all_ex(unsigned long start);
-extern void __flush_dcache_all(void);
-static void __flush_dcache_all_ex(void);
+/*
+ * The maximum number of pages we support up to when doing ranged dcache
+ * flushing. Anything exceeding this will simply flush the dcache in its
+ * entirety.
+ */
+#define MAX_DCACHE_PAGES 64 /* XXX: Tune for ways */
+
+static void __flush_dcache_segment_1way(unsigned long start,
+ unsigned long extent);
+static void __flush_dcache_segment_2way(unsigned long start,
+ unsigned long extent);
+static void __flush_dcache_segment_4way(unsigned long start,
+ unsigned long extent);
+
+static void __flush_cache_4096(unsigned long addr, unsigned long phys,
+ unsigned long exec_offset);
+
+/*
+ * This is initialised here to ensure that it is not placed in the BSS. If
+ * that were to happen, note that cache_init gets called before the BSS is
+ * cleared, so this would get nulled out which would be hopeless.
+ */
+static void (*__flush_dcache_segment_fn)(unsigned long, unsigned long) =
+ (void (*)(unsigned long, unsigned long))0xdeadbeef;
+
+static void compute_alias(struct cache_info *c)
+{
+ c->alias_mask = ((c->sets - 1) << c->entry_shift) & ~(PAGE_SIZE - 1);
+ c->n_aliases = (c->alias_mask >> PAGE_SHIFT) + 1;
+}
+
+static void __init emit_cache_params(void)
+{
+ printk("PVR=%08x CVR=%08x PRR=%08x\n",
+ ctrl_inl(CCN_PVR),
+ ctrl_inl(CCN_CVR),
+ ctrl_inl(CCN_PRR));
+ printk("I-cache : n_ways=%d n_sets=%d way_incr=%d\n",
+ cpu_data->icache.ways,
+ cpu_data->icache.sets,
+ cpu_data->icache.way_incr);
+ printk("I-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
+ cpu_data->icache.entry_mask,
+ cpu_data->icache.alias_mask,
+ cpu_data->icache.n_aliases);
+ printk("D-cache : n_ways=%d n_sets=%d way_incr=%d\n",
+ cpu_data->dcache.ways,
+ cpu_data->dcache.sets,
+ cpu_data->dcache.way_incr);
+ printk("D-cache : entry_mask=0x%08x alias_mask=0x%08x n_aliases=%d\n",
+ cpu_data->dcache.entry_mask,
+ cpu_data->dcache.alias_mask,
+ cpu_data->dcache.n_aliases);
+
+ if (!__flush_dcache_segment_fn)
+ panic("unknown number of cache ways\n");
+}
/*
* SH-4 has virtually indexed and physically tagged cache.
*/
-struct semaphore p3map_sem[4];
+/* Worst case assumed to be 64k cache, direct-mapped i.e. 4 synonym bits. */
+#define MAX_P3_SEMAPHORES 16
+
+struct semaphore p3map_sem[MAX_P3_SEMAPHORES];
void __init p3_cache_init(void)
{
- if (remap_area_pages(P3SEG, 0, PAGE_SIZE*4, _PAGE_CACHABLE))
+ int i;
+
+ compute_alias(&cpu_data->icache);
+ compute_alias(&cpu_data->dcache);
+
+ switch (cpu_data->dcache.ways) {
+ case 1:
+ __flush_dcache_segment_fn = __flush_dcache_segment_1way;
+ break;
+ case 2:
+ __flush_dcache_segment_fn = __flush_dcache_segment_2way;
+ break;
+ case 4:
+ __flush_dcache_segment_fn = __flush_dcache_segment_4way;
+ break;
+ default:
+ __flush_dcache_segment_fn = NULL;
+ break;
+ }
+
+ emit_cache_params();
+
+ if (remap_area_pages(P3SEG, 0, PAGE_SIZE * 4, _PAGE_CACHABLE))
panic("%s failed.", __FUNCTION__);
- sema_init (&p3map_sem[0], 1);
- sema_init (&p3map_sem[1], 1);
- sema_init (&p3map_sem[2], 1);
- sema_init (&p3map_sem[3], 1);
+ for (i = 0; i < cpu_data->dcache.n_aliases; i++)
+ sema_init(&p3map_sem[i], 1);
}
/*
@@ -89,7 +160,6 @@ void __flush_purge_region(void *start, int size)
}
}
-
/*
* No write back please
*/
@@ -108,40 +178,6 @@ void __flush_invalidate_region(void *start, int size)
}
}
-static void __flush_dcache_all_ex(void)
-{
- unsigned long addr, end_addr, entry_offset;
-
- end_addr = CACHE_OC_ADDRESS_ARRAY + (cpu_data->dcache.sets << cpu_data->dcache.entry_shift) * cpu_data->dcache.ways;
- entry_offset = 1 << cpu_data->dcache.entry_shift;
- for (addr = CACHE_OC_ADDRESS_ARRAY; addr < end_addr; addr += entry_offset) {
- ctrl_outl(0, addr);
- }
-}
-
-static void __flush_cache_4096_all_ex(unsigned long start)
-{
- unsigned long addr, entry_offset;
- int i;
-
- entry_offset = 1 << cpu_data->dcache.entry_shift;
- for (i = 0; i < cpu_data->dcache.ways; i++, start += cpu_data->dcache.way_incr) {
- for (addr = CACHE_OC_ADDRESS_ARRAY + start;
- addr < CACHE_OC_ADDRESS_ARRAY + 4096 + start;
- addr += entry_offset) {
- ctrl_outl(0, addr);
- }
- }
-}
-
-void flush_cache_4096_all(unsigned long start)
-{
- if (cpu_data->dcache.ways == 1)
- __flush_cache_4096_all(start);
- else
- __flush_cache_4096_all_ex(start);
-}
-
/*
* Write back the range of D-cache, and purge the I-cache.
*
@@ -153,14 +189,14 @@ void flush_icache_range(unsigned long start, unsigned long end)
}
/*
- * Write back the D-cache and purge the I-cache for signal trampoline.
+ * Write back the D-cache and purge the I-cache for signal trampoline.
* .. which happens to be the same behavior as flush_icache_range().
* So, we simply flush out a line.
*/
void flush_cache_sigtramp(unsigned long addr)
{
unsigned long v, index;
- unsigned long flags;
+ unsigned long flags;
int i;
v = addr & ~(L1_CACHE_BYTES-1);
@@ -172,30 +208,33 @@ void flush_cache_sigtramp(unsigned long addr)
local_irq_save(flags);
jump_to_P2();
- for(i = 0; i < cpu_data->icache.ways; i++, index += cpu_data->icache.way_incr)
+
+ for (i = 0; i < cpu_data->icache.ways;
+ i++, index += cpu_data->icache.way_incr)
ctrl_outl(0, index); /* Clear out Valid-bit */
+
back_to_P1();
+ wmb();
local_irq_restore(flags);
}
static inline void flush_cache_4096(unsigned long start,
unsigned long phys)
{
- unsigned long flags;
- extern void __flush_cache_4096(unsigned long addr, unsigned long phys, unsigned long exec_offset);
+ unsigned long flags, exec_offset = 0;
/*
- * SH7751, SH7751R, and ST40 have no restriction to handle cache.
- * (While SH7750 must do that at P2 area.)
+ * All types of SH-4 require PC to be in P2 to operate on the I-cache.
+ * Some types of SH-4 require PC to be in P2 to operate on the D-cache.
*/
- if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG)
- || start < CACHE_OC_ADDRESS_ARRAY) {
- local_irq_save(flags);
- __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0x20000000);
- local_irq_restore(flags);
- } else {
- __flush_cache_4096(start | SH_CACHE_ASSOC, P1SEGADDR(phys), 0);
- }
+ if ((cpu_data->flags & CPU_HAS_P2_FLUSH_BUG) ||
+ (start < CACHE_OC_ADDRESS_ARRAY))
+ exec_offset = 0x20000000;
+
+ local_irq_save(flags);
+ __flush_cache_4096(start | SH_CACHE_ASSOC,
+ P1SEGADDR(phys), exec_offset);
+ local_irq_restore(flags);
}
/*
@@ -206,15 +245,19 @@ void flush_dcache_page(struct page *page)
{
if (test_bit(PG_mapped, &page->flags)) {
unsigned long phys = PHYSADDR(page_address(page));
+ unsigned long addr = CACHE_OC_ADDRESS_ARRAY;
+ int i, n;
/* Loop all the D-cache */
- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY, phys);
- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x1000, phys);
- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x2000, phys);
- flush_cache_4096(CACHE_OC_ADDRESS_ARRAY | 0x3000, phys);
+ n = cpu_data->dcache.n_aliases;
+ for (i = 0; i < n; i++, addr += PAGE_SIZE)
+ flush_cache_4096(addr, phys);
}
+
+ wmb();
}
+/* TODO: Selective icache invalidation through IC address array.. */
static inline void flush_icache_all(void)
{
unsigned long flags, ccr;
@@ -227,34 +270,142 @@ static inline void flush_icache_all(void)
ccr |= CCR_CACHE_ICI;
ctrl_outl(ccr, CCR);
+ /*
+ * back_to_P1() will take care of the barrier for us, don't add
+ * another one!
+ */
+
back_to_P1();
local_irq_restore(flags);
}
+void flush_dcache_all(void)
+{
+ (*__flush_dcache_segment_fn)(0UL, cpu_data->dcache.way_size);
+ wmb();
+}
+
void flush_cache_all(void)
{
- if (cpu_data->dcache.ways == 1)
- __flush_dcache_all();
- else
- __flush_dcache_all_ex();
+ flush_dcache_all();
flush_icache_all();
}
+static void __flush_cache_mm(struct mm_struct *mm, unsigned long start,
+ unsigned long end)
+{
+ unsigned long d = 0, p = start & PAGE_MASK;
+ unsigned long alias_mask = cpu_data->dcache.alias_mask;
+ unsigned long n_aliases = cpu_data->dcache.n_aliases;
+ unsigned long select_bit;
+ unsigned long all_aliases_mask;
+ unsigned long addr_offset;
+ pgd_t *dir;
+ pmd_t *pmd;
+ pud_t *pud;
+ pte_t *pte;
+ int i;
+
+ dir = pgd_offset(mm, p);
+ pud = pud_offset(dir, p);
+ pmd = pmd_offset(pud, p);
+ end = PAGE_ALIGN(end);
+
+ all_aliases_mask = (1 << n_aliases) - 1;
+
+ do {
+ if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) {
+ p &= PMD_MASK;
+ p += PMD_SIZE;
+ pmd++;
+
+ continue;
+ }
+
+ pte = pte_offset_kernel(pmd, p);
+
+ do {
+ unsigned long phys;
+ pte_t entry = *pte;
+
+ if (!(pte_val(entry) & _PAGE_PRESENT)) {
+ pte++;
+ p += PAGE_SIZE;
+ continue;
+ }
+
+ phys = pte_val(entry) & PTE_PHYS_MASK;
+
+ if ((p ^ phys) & alias_mask) {
+ d |= 1 << ((p & alias_mask) >> PAGE_SHIFT);
+ d |= 1 << ((phys & alias_mask) >> PAGE_SHIFT);
+
+ if (d == all_aliases_mask)
+ goto loop_exit;
+ }
+
+ pte++;
+ p += PAGE_SIZE;
+ } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
+ pmd++;
+ } while (p < end);
+
+loop_exit:
+ addr_offset = 0;
+ select_bit = 1;
+
+ for (i = 0; i < n_aliases; i++) {
+ if (d & select_bit) {
+ (*__flush_dcache_segment_fn)(addr_offset, PAGE_SIZE);
+ wmb();
+ }
+
+ select_bit <<= 1;
+ addr_offset += PAGE_SIZE;
+ }
+}
+
+/*
+ * Note : (RPC) since the caches are physically tagged, the only point
+ * of flush_cache_mm for SH-4 is to get rid of aliases from the
+ * D-cache. The assumption elsewhere, e.g. flush_cache_range, is that
+ * lines can stay resident so long as the virtual address they were
+ * accessed with (hence cache set) is in accord with the physical
+ * address (i.e. tag). It's no different here. So I reckon we don't
+ * need to flush the I-cache, since aliases don't matter for that. We
+ * should try that.
+ *
+ * Caller takes mm->mmap_sem.
+ */
void flush_cache_mm(struct mm_struct *mm)
{
- /* Is there any good way? */
- /* XXX: possibly call flush_cache_range for each vm area */
- /*
- * FIXME: Really, the optimal solution here would be able to flush out
- * individual lines created by the specified context, but this isn't
- * feasible for a number of architectures (such as MIPS, and some
- * SPARC) .. is this possible for SuperH?
- *
- * In the meantime, we'll just flush all of the caches.. this
- * seems to be the simplest way to avoid at least a few wasted
- * cache flushes. -Lethal
+ /*
+ * If cache is only 4k-per-way, there are never any 'aliases'. Since
+ * the cache is physically tagged, the data can just be left in there.
*/
- flush_cache_all();
+ if (cpu_data->dcache.n_aliases == 0)
+ return;
+
+ /*
+ * Don't bother groveling around the dcache for the VMA ranges
+ * if there are too many PTEs to make it worthwhile.
+ */
+ if (mm->nr_ptes >= MAX_DCACHE_PAGES)
+ flush_dcache_all();
+ else {
+ struct vm_area_struct *vma;
+
+ /*
+ * In this case there are reasonably sized ranges to flush,
+ * iterate through the VMA list and take care of any aliases.
+ */
+ for (vma = mm->mmap; vma; vma = vma->vm_next)
+ __flush_cache_mm(mm, vma->vm_start, vma->vm_end);
+ }
+
+ /* Only touch the icache if one of the VMAs has VM_EXEC set. */
+ if (mm->exec_vm)
+ flush_icache_all();
}
/*
@@ -263,27 +414,40 @@ void flush_cache_mm(struct mm_struct *mm)
* ADDR: Virtual Address (U0 address)
* PFN: Physical page number
*/
-void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn)
+void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
+ unsigned long pfn)
{
unsigned long phys = pfn << PAGE_SHIFT;
+ unsigned int alias_mask;
+
+ alias_mask = cpu_data->dcache.alias_mask;
/* We only need to flush D-cache when we have alias */
- if ((address^phys) & CACHE_ALIAS) {
+ if ((address^phys) & alias_mask) {
/* Loop 4K of the D-cache */
flush_cache_4096(
- CACHE_OC_ADDRESS_ARRAY | (address & CACHE_ALIAS),
+ CACHE_OC_ADDRESS_ARRAY | (address & alias_mask),
phys);
/* Loop another 4K of the D-cache */
flush_cache_4096(
- CACHE_OC_ADDRESS_ARRAY | (phys & CACHE_ALIAS),
+ CACHE_OC_ADDRESS_ARRAY | (phys & alias_mask),
phys);
}
- if (vma->vm_flags & VM_EXEC)
- /* Loop 4K (half) of the I-cache */
+ alias_mask = cpu_data->icache.alias_mask;
+ if (vma->vm_flags & VM_EXEC) {
+ /*
+ * Evict entries from the portion of the cache from which code
+ * may have been executed at this address (virtual). There's
+ * no need to evict from the portion corresponding to the
+ * physical address as for the D-cache, because we know the
+ * kernel has never executed the code through its identity
+ * translation.
+ */
flush_cache_4096(
- CACHE_IC_ADDRESS_ARRAY | (address & 0x1000),
+ CACHE_IC_ADDRESS_ARRAY | (address & alias_mask),
phys);
+ }
}
/*
@@ -298,52 +462,31 @@ void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigne
void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
unsigned long end)
{
- unsigned long p = start & PAGE_MASK;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
- pte_t entry;
- unsigned long phys;
- unsigned long d = 0;
-
- dir = pgd_offset(vma->vm_mm, p);
- pmd = pmd_offset(dir, p);
+ /*
+ * If cache is only 4k-per-way, there are never any 'aliases'. Since
+ * the cache is physically tagged, the data can just be left in there.
+ */
+ if (cpu_data->dcache.n_aliases == 0)
+ return;
- do {
- if (pmd_none(*pmd) || pmd_bad(*pmd)) {
- p &= ~((1 << PMD_SHIFT) -1);
- p += (1 << PMD_SHIFT);
- pmd++;
- continue;
- }
- pte = pte_offset_kernel(pmd, p);
- do {
- entry = *pte;
- if ((pte_val(entry) & _PAGE_PRESENT)) {
- phys = pte_val(entry)&PTE_PHYS_MASK;
- if ((p^phys) & CACHE_ALIAS) {
- d |= 1 << ((p & CACHE_ALIAS)>>12);
- d |= 1 << ((phys & CACHE_ALIAS)>>12);
- if (d == 0x0f)
- goto loop_exit;
- }
- }
- pte++;
- p += PAGE_SIZE;
- } while (p < end && ((unsigned long)pte & ~PAGE_MASK));
- pmd++;
- } while (p < end);
- loop_exit:
- if (d & 1)
- flush_cache_4096_all(0);
- if (d & 2)
- flush_cache_4096_all(0x1000);
- if (d & 4)
- flush_cache_4096_all(0x2000);
- if (d & 8)
- flush_cache_4096_all(0x3000);
- if (vma->vm_flags & VM_EXEC)
+ /*
+ * Don't bother with the lookup and alias check if we have a
+ * wide range to cover, just blow away the dcache in its
+ * entirety instead. -- PFM.
+ */
+ if (((end - start) >> PAGE_SHIFT) >= MAX_DCACHE_PAGES)
+ flush_dcache_all();
+ else
+ __flush_cache_mm(vma->vm_mm, start, end);
+
+ if (vma->vm_flags & VM_EXEC) {
+ /*
+ * TODO: Is this required??? Need to look at how I-cache
+ * coherency is assured when new programs are loaded to see if
+ * this matters.
+ */
flush_icache_all();
+ }
}
/*
@@ -357,5 +500,273 @@ void flush_icache_user_range(struct vm_area_struct *vma,
struct page *page, unsigned long addr, int len)
{
flush_cache_page(vma, addr, page_to_pfn(page));
+ mb();
+}
+
+/**
+ * __flush_cache_4096
+ *
+ * @addr: address in memory mapped cache array
+ * @phys: P1 address to flush (has to match tags if addr has 'A' bit
+ * set i.e. associative write)
+ * @exec_offset: set to 0x20000000 if flush has to be executed from P2
+ * region else 0x0
+ *
+ * The offset into the cache array implied by 'addr' selects the
+ * 'colour' of the virtual address range that will be flushed. The
+ * operation (purge/write-back) is selected by the lower 2 bits of
+ * 'phys'.
+ */
+static void __flush_cache_4096(unsigned long addr, unsigned long phys,
+ unsigned long exec_offset)
+{
+ int way_count;
+ unsigned long base_addr = addr;
+ struct cache_info *dcache;
+ unsigned long way_incr;
+ unsigned long a, ea, p;
+ unsigned long temp_pc;
+
+ dcache = &cpu_data->dcache;
+ /* Write this way for better assembly. */
+ way_count = dcache->ways;
+ way_incr = dcache->way_incr;
+
+ /*
+ * Apply exec_offset (i.e. branch to P2 if required.).
+ *
+ * FIXME:
+ *
+ * If I write "=r" for the (temp_pc), it puts this in r6 hence
+ * trashing exec_offset before it's been added on - why? Hence
+ * "=&r" as a 'workaround'
+ */
+ asm volatile("mov.l 1f, %0\n\t"
+ "add %1, %0\n\t"
+ "jmp @%0\n\t"
+ "nop\n\t"
+ ".balign 4\n\t"
+ "1: .long 2f\n\t"
+ "2:\n" : "=&r" (temp_pc) : "r" (exec_offset));
+
+ /*
+ * We know there will be >=1 iteration, so write as do-while to avoid
+ * pointless nead-of-loop check for 0 iterations.
+ */
+ do {
+ ea = base_addr + PAGE_SIZE;
+ a = base_addr;
+ p = phys;
+
+ do {
+ *(volatile unsigned long *)a = p;
+ /*
+ * Next line: intentionally not p+32, saves an add, p
+ * will do since only the cache tag bits need to
+ * match.
+ */
+ *(volatile unsigned long *)(a+32) = p;
+ a += 64;
+ p += 64;
+ } while (a < ea);
+
+ base_addr += way_incr;
+ } while (--way_count != 0);
}
+/*
+ * Break the 1, 2 and 4 way variants of this out into separate functions to
+ * avoid nearly all the overhead of having the conditional stuff in the function
+ * bodies (+ the 1 and 2 way cases avoid saving any registers too).
+ */
+static void __flush_dcache_segment_1way(unsigned long start,
+ unsigned long extent_per_way)
+{
+ unsigned long orig_sr, sr_with_bl;
+ unsigned long base_addr;
+ unsigned long way_incr, linesz, way_size;
+ struct cache_info *dcache;
+ register unsigned long a0, a0e;
+
+ asm volatile("stc sr, %0" : "=r" (orig_sr));
+ sr_with_bl = orig_sr | (1<<28);
+ base_addr = ((unsigned long)&empty_zero_page[0]);
+
+ /*
+ * The previous code aligned base_addr to 16k, i.e. the way_size of all
+ * existing SH-4 D-caches. Whilst I don't see a need to have this
+ * aligned to any better than the cache line size (which it will be
+ * anyway by construction), let's align it to at least the way_size of
+ * any existing or conceivable SH-4 D-cache. -- RPC
+ */
+ base_addr = ((base_addr >> 16) << 16);
+ base_addr |= start;
+
+ dcache = &cpu_data->dcache;
+ linesz = dcache->linesz;
+ way_incr = dcache->way_incr;
+ way_size = dcache->way_size;
+
+ a0 = base_addr;
+ a0e = base_addr + extent_per_way;
+ do {
+ asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
+ asm volatile("movca.l r0, @%0\n\t"
+ "ocbi @%0" : : "r" (a0));
+ a0 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "ocbi @%0" : : "r" (a0));
+ a0 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "ocbi @%0" : : "r" (a0));
+ a0 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "ocbi @%0" : : "r" (a0));
+ asm volatile("ldc %0, sr" : : "r" (orig_sr));
+ a0 += linesz;
+ } while (a0 < a0e);
+}
+
+static void __flush_dcache_segment_2way(unsigned long start,
+ unsigned long extent_per_way)
+{
+ unsigned long orig_sr, sr_with_bl;
+ unsigned long base_addr;
+ unsigned long way_incr, linesz, way_size;
+ struct cache_info *dcache;
+ register unsigned long a0, a1, a0e;
+
+ asm volatile("stc sr, %0" : "=r" (orig_sr));
+ sr_with_bl = orig_sr | (1<<28);
+ base_addr = ((unsigned long)&empty_zero_page[0]);
+
+ /* See comment under 1-way above */
+ base_addr = ((base_addr >> 16) << 16);
+ base_addr |= start;
+
+ dcache = &cpu_data->dcache;
+ linesz = dcache->linesz;
+ way_incr = dcache->way_incr;
+ way_size = dcache->way_size;
+
+ a0 = base_addr;
+ a1 = a0 + way_incr;
+ a0e = base_addr + extent_per_way;
+ do {
+ asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1" : :
+ "r" (a0), "r" (a1));
+ a0 += linesz;
+ a1 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1" : :
+ "r" (a0), "r" (a1));
+ a0 += linesz;
+ a1 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1" : :
+ "r" (a0), "r" (a1));
+ a0 += linesz;
+ a1 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1" : :
+ "r" (a0), "r" (a1));
+ asm volatile("ldc %0, sr" : : "r" (orig_sr));
+ a0 += linesz;
+ a1 += linesz;
+ } while (a0 < a0e);
+}
+
+static void __flush_dcache_segment_4way(unsigned long start,
+ unsigned long extent_per_way)
+{
+ unsigned long orig_sr, sr_with_bl;
+ unsigned long base_addr;
+ unsigned long way_incr, linesz, way_size;
+ struct cache_info *dcache;
+ register unsigned long a0, a1, a2, a3, a0e;
+
+ asm volatile("stc sr, %0" : "=r" (orig_sr));
+ sr_with_bl = orig_sr | (1<<28);
+ base_addr = ((unsigned long)&empty_zero_page[0]);
+
+ /* See comment under 1-way above */
+ base_addr = ((base_addr >> 16) << 16);
+ base_addr |= start;
+
+ dcache = &cpu_data->dcache;
+ linesz = dcache->linesz;
+ way_incr = dcache->way_incr;
+ way_size = dcache->way_size;
+
+ a0 = base_addr;
+ a1 = a0 + way_incr;
+ a2 = a1 + way_incr;
+ a3 = a2 + way_incr;
+ a0e = base_addr + extent_per_way;
+ do {
+ asm volatile("ldc %0, sr" : : "r" (sr_with_bl));
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "movca.l r0, @%2\n\t"
+ "movca.l r0, @%3\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1\n\t"
+ "ocbi @%2\n\t"
+ "ocbi @%3\n\t" : :
+ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
+ a0 += linesz;
+ a1 += linesz;
+ a2 += linesz;
+ a3 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "movca.l r0, @%2\n\t"
+ "movca.l r0, @%3\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1\n\t"
+ "ocbi @%2\n\t"
+ "ocbi @%3\n\t" : :
+ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
+ a0 += linesz;
+ a1 += linesz;
+ a2 += linesz;
+ a3 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "movca.l r0, @%2\n\t"
+ "movca.l r0, @%3\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1\n\t"
+ "ocbi @%2\n\t"
+ "ocbi @%3\n\t" : :
+ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
+ a0 += linesz;
+ a1 += linesz;
+ a2 += linesz;
+ a3 += linesz;
+ asm volatile("movca.l r0, @%0\n\t"
+ "movca.l r0, @%1\n\t"
+ "movca.l r0, @%2\n\t"
+ "movca.l r0, @%3\n\t"
+ "ocbi @%0\n\t"
+ "ocbi @%1\n\t"
+ "ocbi @%2\n\t"
+ "ocbi @%3\n\t" : :
+ "r" (a0), "r" (a1), "r" (a2), "r" (a3));
+ asm volatile("ldc %0, sr" : : "r" (orig_sr));
+ a0 += linesz;
+ a1 += linesz;
+ a2 += linesz;
+ a3 += linesz;
+ } while (a0 < a0e);
+}
diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c
index bf94eedb0a8e..045abdf078f5 100644
--- a/arch/sh/mm/cache-sh7705.c
+++ b/arch/sh/mm/cache-sh7705.c
@@ -9,7 +9,6 @@
* for more details.
*
*/
-
#include <linux/init.h>
#include <linux/mman.h>
#include <linux/mm.h>
@@ -25,14 +24,10 @@
#include <asm/mmu_context.h>
#include <asm/cacheflush.h>
-/* The 32KB cache on the SH7705 suffers from the same synonym problem
- * as SH4 CPUs */
-
-#define __pte_offset(address) \
- ((address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
-#define pte_offset(dir, address) ((pte_t *) pmd_page_vaddr(*(dir)) + \
- __pte_offset(address))
-
+/*
+ * The 32KB cache on the SH7705 suffers from the same synonym problem
+ * as SH4 CPUs
+ */
static inline void cache_wback_all(void)
{
unsigned long ways, waysize, addrstart;
@@ -73,7 +68,6 @@ void flush_icache_range(unsigned long start, unsigned long end)
__flush_wback_region((void *)start, end - start);
}
-
/*
* Writeback&Invalidate the D-cache of the page
*/
@@ -128,7 +122,6 @@ static void __flush_dcache_page(unsigned long phys)
local_irq_restore(flags);
}
-
/*
* Write back & invalidate the D-cache of the page.
* (To avoid "alias" issues)
@@ -186,7 +179,8 @@ void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
*
* ADDRESS: Virtual Address (U0 address)
*/
-void flush_cache_page(struct vm_area_struct *vma, unsigned long address, unsigned long pfn)
+void flush_cache_page(struct vm_area_struct *vma, unsigned long address,
+ unsigned long pfn)
{
__flush_dcache_page(pfn << PAGE_SHIFT);
}
@@ -203,4 +197,3 @@ void flush_icache_page(struct vm_area_struct *vma, struct page *page)
{
__flush_purge_region(page_address(page), PAGE_SIZE);
}
-
diff --git a/arch/sh/mm/clear_page.S b/arch/sh/mm/clear_page.S
index 08acead7b2a1..7b96425ae270 100644
--- a/arch/sh/mm/clear_page.S
+++ b/arch/sh/mm/clear_page.S
@@ -193,102 +193,5 @@ ENTRY(__clear_user_page)
nop
.L4096: .word 4096
-ENTRY(__flush_cache_4096)
- mov.l 1f,r3
- add r6,r3
- mov r4,r0
- mov #64,r2
- shll r2
- mov #64,r6
- jmp @r3
- mov #96,r7
- .align 2
-1: .long 2f
-2:
- .rept 32
- mov.l r5,@r0
- mov.l r5,@(32,r0)
- mov.l r5,@(r0,r6)
- mov.l r5,@(r0,r7)
- add r2,r5
- add r2,r0
- .endr
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- rts
- nop
-
-ENTRY(__flush_dcache_all)
- mov.l 2f,r0
- mov.l 3f,r4
- and r0,r4 ! r4 = (unsigned long)&empty_zero_page[0] & ~0xffffc000
- stc sr,r1 ! save SR
- mov.l 4f,r2
- or r1,r2
- mov #32,r3
- shll2 r3
-1:
- ldc r2,sr ! set BL bit
- movca.l r0,@r4
- ocbi @r4
- add #32,r4
- movca.l r0,@r4
- ocbi @r4
- add #32,r4
- movca.l r0,@r4
- ocbi @r4
- add #32,r4
- movca.l r0,@r4
- ocbi @r4
- ldc r1,sr ! restore SR
- dt r3
- bf/s 1b
- add #32,r4
-
- rts
- nop
- .align 2
-2: .long 0xffffc000
-3: .long empty_zero_page
-4: .long 0x10000000 ! BL bit
-
-/* __flush_cache_4096_all(unsigned long addr) */
-ENTRY(__flush_cache_4096_all)
- mov.l 2f,r0
- mov.l 3f,r2
- and r0,r2
- or r2,r4 ! r4 = addr | (unsigned long)&empty_zero_page[0] & ~0x3fff
- stc sr,r1 ! save SR
- mov.l 4f,r2
- or r1,r2
- mov #32,r3
-1:
- ldc r2,sr ! set BL bit
- movca.l r0,@r4
- ocbi @r4
- add #32,r4
- movca.l r0,@r4
- ocbi @r4
- add #32,r4
- movca.l r0,@r4
- ocbi @r4
- add #32,r4
- movca.l r0,@r4
- ocbi @r4
- ldc r1,sr ! restore SR
- dt r3
- bf/s 1b
- add #32,r4
-
- rts
- nop
- .align 2
-2: .long 0xffffc000
-3: .long empty_zero_page
-4: .long 0x10000000 ! BL bit
#endif
+
diff --git a/arch/sh/mm/consistent.c b/arch/sh/mm/consistent.c
index ee73e30263af..38c82d890ffd 100644
--- a/arch/sh/mm/consistent.c
+++ b/arch/sh/mm/consistent.c
@@ -9,6 +9,8 @@
*/
#include <linux/mm.h>
#include <linux/dma-mapping.h>
+#include <asm/cacheflush.h>
+#include <asm/addrspace.h>
#include <asm/io.h>
void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
@@ -26,6 +28,7 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *handle)
split_page(page, order);
ret = page_address(page);
+ memset(ret, 0, size);
*handle = virt_to_phys(ret);
/*
diff --git a/arch/sh/mm/fault.c b/arch/sh/mm/fault.c
index 775f86cd3fe8..68663b8f99ae 100644
--- a/arch/sh/mm/fault.c
+++ b/arch/sh/mm/fault.c
@@ -1,33 +1,22 @@
-/* $Id: fault.c,v 1.14 2004/01/13 05:52:11 kkojima Exp $
+/*
+ * Page fault handler for SH with an MMU.
*
- * linux/arch/sh/mm/fault.c
* Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2003 Paul Mundt
*
* Based on linux/arch/i386/mm/fault.c:
* Copyright (C) 1995 Linus Torvalds
+ *
+ * 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/signal.h>
-#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/mman.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
+#include <linux/hardirq.h>
+#include <linux/kprobes.h>
#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/pgalloc.h>
#include <asm/mmu_context.h>
-#include <asm/cacheflush.h>
#include <asm/kgdb.h>
extern void die(const char *,struct pt_regs *,long);
@@ -80,7 +69,7 @@ good_area:
if (!(vma->vm_flags & VM_WRITE))
goto bad_area;
} else {
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
}
@@ -160,7 +149,7 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
@@ -187,18 +176,30 @@ do_sigbus:
goto no_context;
}
+#ifdef CONFIG_SH_STORE_QUEUES
/*
- * Called with interrupt disabled.
+ * This is a special case for the SH-4 store queues, as pages for this
+ * space still need to be faulted in before it's possible to flush the
+ * store queue cache for writeout to the remapped region.
*/
-asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
- unsigned long address)
+#define P3_ADDR_MAX (P4SEG_STORE_QUE + 0x04000000)
+#else
+#define P3_ADDR_MAX P4SEG
+#endif
+
+/*
+ * Called with interrupts disabled.
+ */
+asmlinkage int __kprobes __do_page_fault(struct pt_regs *regs,
+ unsigned long writeaccess,
+ unsigned long address)
{
- unsigned long addrmax = P4SEG;
pgd_t *pgd;
+ pud_t *pud;
pmd_t *pmd;
pte_t *pte;
pte_t entry;
- struct mm_struct *mm;
+ struct mm_struct *mm = current->mm;
spinlock_t *ptl;
int ret = 1;
@@ -207,31 +208,37 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
kgdb_bus_err_hook();
#endif
-#ifdef CONFIG_SH_STORE_QUEUES
- addrmax = P4SEG_STORE_QUE + 0x04000000;
-#endif
-
- if (address >= P3SEG && address < addrmax) {
+ /*
+ * We don't take page faults for P1, P2, and parts of P4, these
+ * are always mapped, whether it be due to legacy behaviour in
+ * 29-bit mode, or due to PMB configuration in 32-bit mode.
+ */
+ if (address >= P3SEG && address < P3_ADDR_MAX) {
pgd = pgd_offset_k(address);
mm = NULL;
- } else if (address >= TASK_SIZE)
- return 1;
- else if (!(mm = current->mm))
- return 1;
- else
+ } else {
+ if (unlikely(address >= TASK_SIZE || !mm))
+ return 1;
+
pgd = pgd_offset(mm, address);
+ }
- pmd = pmd_offset(pgd, address);
+ pud = pud_offset(pgd, address);
+ if (pud_none_or_clear_bad(pud))
+ return 1;
+ pmd = pmd_offset(pud, address);
if (pmd_none_or_clear_bad(pmd))
return 1;
+
if (mm)
pte = pte_offset_map_lock(mm, pmd, address, &ptl);
else
pte = pte_offset_kernel(pmd, address);
entry = *pte;
- if (pte_none(entry) || pte_not_present(entry)
- || (writeaccess && !pte_write(entry)))
+ if (unlikely(pte_none(entry) || pte_not_present(entry)))
+ goto unlock;
+ if (unlikely(writeaccess && !pte_write(entry)))
goto unlock;
if (writeaccess)
@@ -243,13 +250,7 @@ asmlinkage int __do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
* ITLB is not affected by "ldtlb" instruction.
* So, we need to flush the entry by ourselves.
*/
-
- {
- unsigned long flags;
- local_irq_save(flags);
- __flush_tlb_page(get_asid(), address&PAGE_MASK);
- local_irq_restore(flags);
- }
+ __flush_tlb_page(get_asid(), address & PAGE_MASK);
#endif
set_pte(pte, entry);
@@ -260,121 +261,3 @@ unlock:
pte_unmap_unlock(pte, ptl);
return ret;
}
-
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
-{
- if (vma->vm_mm && vma->vm_mm->context != NO_CONTEXT) {
- unsigned long flags;
- unsigned long asid;
- unsigned long saved_asid = MMU_NO_ASID;
-
- asid = vma->vm_mm->context & MMU_CONTEXT_ASID_MASK;
- page &= PAGE_MASK;
-
- local_irq_save(flags);
- if (vma->vm_mm != current->mm) {
- saved_asid = get_asid();
- set_asid(asid);
- }
- __flush_tlb_page(asid, page);
- if (saved_asid != MMU_NO_ASID)
- set_asid(saved_asid);
- local_irq_restore(flags);
- }
-}
-
-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
-{
- struct mm_struct *mm = vma->vm_mm;
-
- if (mm->context != NO_CONTEXT) {
- unsigned long flags;
- int size;
-
- local_irq_save(flags);
- size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
- if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
- mm->context = NO_CONTEXT;
- if (mm == current->mm)
- activate_context(mm);
- } else {
- unsigned long asid = mm->context&MMU_CONTEXT_ASID_MASK;
- unsigned long saved_asid = MMU_NO_ASID;
-
- start &= PAGE_MASK;
- end += (PAGE_SIZE - 1);
- end &= PAGE_MASK;
- if (mm != current->mm) {
- saved_asid = get_asid();
- set_asid(asid);
- }
- while (start < end) {
- __flush_tlb_page(asid, start);
- start += PAGE_SIZE;
- }
- if (saved_asid != MMU_NO_ASID)
- set_asid(saved_asid);
- }
- local_irq_restore(flags);
- }
-}
-
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
- unsigned long flags;
- int size;
-
- local_irq_save(flags);
- size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
- if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
- flush_tlb_all();
- } else {
- unsigned long asid = init_mm.context&MMU_CONTEXT_ASID_MASK;
- unsigned long saved_asid = get_asid();
-
- start &= PAGE_MASK;
- end += (PAGE_SIZE - 1);
- end &= PAGE_MASK;
- set_asid(asid);
- while (start < end) {
- __flush_tlb_page(asid, start);
- start += PAGE_SIZE;
- }
- set_asid(saved_asid);
- }
- local_irq_restore(flags);
-}
-
-void flush_tlb_mm(struct mm_struct *mm)
-{
- /* Invalidate all TLB of this process. */
- /* Instead of invalidating each TLB, we get new MMU context. */
- if (mm->context != NO_CONTEXT) {
- unsigned long flags;
-
- local_irq_save(flags);
- mm->context = NO_CONTEXT;
- if (mm == current->mm)
- activate_context(mm);
- local_irq_restore(flags);
- }
-}
-
-void flush_tlb_all(void)
-{
- unsigned long flags, status;
-
- /*
- * Flush all the TLB.
- *
- * Write to the MMU control register's bit:
- * TF-bit for SH-3, TI-bit for SH-4.
- * It's same position, bit #2.
- */
- local_irq_save(flags);
- status = ctrl_inl(MMUCR);
- status |= 0x04;
- ctrl_outl(status, MMUCR);
- local_irq_restore(flags);
-}
diff --git a/arch/sh/mm/hugetlbpage.c b/arch/sh/mm/hugetlbpage.c
index 2a85bc15a412..329059d6b54a 100644
--- a/arch/sh/mm/hugetlbpage.c
+++ b/arch/sh/mm/hugetlbpage.c
@@ -26,61 +26,41 @@
pte_t *huge_pte_alloc(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
+ pud_t *pud;
pmd_t *pmd;
pte_t *pte = NULL;
pgd = pgd_offset(mm, addr);
if (pgd) {
- pmd = pmd_alloc(mm, pgd, addr);
- if (pmd)
- pte = pte_alloc_map(mm, pmd, addr);
+ pud = pud_alloc(mm, pgd, addr);
+ if (pud) {
+ pmd = pmd_alloc(mm, pud, addr);
+ if (pmd)
+ pte = pte_alloc_map(mm, pmd, addr);
+ }
}
+
return pte;
}
pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
{
pgd_t *pgd;
+ pud_t *pud;
pmd_t *pmd;
pte_t *pte = NULL;
pgd = pgd_offset(mm, addr);
if (pgd) {
- pmd = pmd_offset(pgd, addr);
- if (pmd)
- pte = pte_offset_map(pmd, addr);
- }
- return pte;
-}
-
-void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep, pte_t entry)
-{
- int i;
-
- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- set_pte_at(mm, addr, ptep, entry);
- ptep++;
- addr += PAGE_SIZE;
- pte_val(entry) += PAGE_SIZE;
+ pud = pud_offset(pgd, addr);
+ if (pud) {
+ pmd = pmd_offset(pud, addr);
+ if (pmd)
+ pte = pte_offset_map(pmd, addr);
+ }
}
-}
-
-pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
- pte_t *ptep)
-{
- pte_t entry;
- int i;
-
- entry = *ptep;
- for (i = 0; i < (1 << HUGETLB_PAGE_ORDER); i++) {
- pte_clear(mm, addr, ptep);
- addr += PAGE_SIZE;
- ptep++;
- }
-
- return entry;
+ return pte;
}
struct page *follow_huge_addr(struct mm_struct *mm,
diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c
index 8ea27ca4b700..7154d1ce9785 100644
--- a/arch/sh/mm/init.c
+++ b/arch/sh/mm/init.c
@@ -24,7 +24,7 @@
#include <linux/highmem.h>
#include <linux/bootmem.h>
#include <linux/pagemap.h>
-
+#include <linux/proc_fs.h>
#include <asm/processor.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -80,6 +80,7 @@ void show_mem(void)
static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
{
pgd_t *pgd;
+ pud_t *pud;
pmd_t *pmd;
pte_t *pte;
@@ -89,7 +90,17 @@ static void set_pte_phys(unsigned long addr, unsigned long phys, pgprot_t prot)
return;
}
- pmd = pmd_offset(pgd, addr);
+ pud = pud_offset(pgd, addr);
+ if (pud_none(*pud)) {
+ pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
+ set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | _PAGE_USER));
+ if (pmd != pmd_offset(pud, 0)) {
+ pud_ERROR(*pud);
+ return;
+ }
+ }
+
+ pmd = pmd_offset(pud, addr);
if (pmd_none(*pmd)) {
pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE | _PAGE_USER));
@@ -212,6 +223,8 @@ void __init paging_init(void)
free_area_init_node(0, NODE_DATA(0), zones_size, __MEMORY_START >> PAGE_SHIFT, 0);
}
+static struct kcore_list kcore_mem, kcore_vmalloc;
+
void __init mem_init(void)
{
extern unsigned long empty_zero_page[1024];
@@ -237,8 +250,13 @@ void __init mem_init(void)
* Setup wrappers for copy/clear_page(), these will get overridden
* later in the boot process if a better method is available.
*/
+#ifdef CONFIG_MMU
copy_page = copy_page_slow;
clear_page = clear_page_slow;
+#else
+ copy_page = copy_page_nommu;
+ clear_page = clear_page_nommu;
+#endif
/* this will put all low memory onto the freelists */
totalram_pages += free_all_bootmem_node(NODE_DATA(0));
@@ -254,7 +272,12 @@ void __init mem_init(void)
datasize = (unsigned long) &_edata - (unsigned long) &_etext;
initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
- printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data, %dk init)\n",
+ kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT);
+ kclist_add(&kcore_vmalloc, (void *)VMALLOC_START,
+ VMALLOC_END - VMALLOC_START);
+
+ printk(KERN_INFO "Memory: %luk/%luk available (%dk kernel code, "
+ "%dk reserved, %dk data, %dk init)\n",
(unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
max_mapnr << (PAGE_SHIFT-10),
codesize >> 10,
@@ -263,6 +286,9 @@ void __init mem_init(void)
initsize >> 10);
p3_cache_init();
+
+ /* Initialize the vDSO */
+ vsyscall_init();
}
void free_initmem(void)
diff --git a/arch/sh/mm/ioremap.c b/arch/sh/mm/ioremap.c
index 96fa4a999e2a..a9fe80cfc233 100644
--- a/arch/sh/mm/ioremap.c
+++ b/arch/sh/mm/ioremap.c
@@ -15,6 +15,7 @@
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/mm.h>
+#include <linux/pci.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/pgalloc.h>
@@ -135,6 +136,20 @@ void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
return (void __iomem *)phys_to_virt(phys_addr);
/*
+ * If we're on an SH7751 or SH7780 PCI controller, PCI memory is
+ * mapped at the end of the address space (typically 0xfd000000)
+ * in a non-translatable area, so mapping through page tables for
+ * this area is not only pointless, but also fundamentally
+ * broken. Just return the physical address instead.
+ *
+ * For boards that map a small PCI memory aperture somewhere in
+ * P1/P2 space, ioremap() will already do the right thing,
+ * and we'll never get this far.
+ */
+ if (is_pci_memaddr(phys_addr) && is_pci_memaddr(last_addr))
+ return (void __iomem *)phys_addr;
+
+ /*
* Don't allow anybody to remap normal RAM that we're using..
*/
if (phys_addr < virt_to_phys(high_memory))
@@ -192,7 +207,7 @@ void __iounmap(void __iomem *addr)
unsigned long vaddr = (unsigned long __force)addr;
struct vm_struct *p;
- if (PXSEG(vaddr) < P3SEG)
+ if (PXSEG(vaddr) < P3SEG || is_pci_memaddr(vaddr))
return;
#ifdef CONFIG_32BIT
diff --git a/arch/sh/mm/pg-nommu.c b/arch/sh/mm/pg-nommu.c
index 8f9165a4e333..d15221beaa16 100644
--- a/arch/sh/mm/pg-nommu.c
+++ b/arch/sh/mm/pg-nommu.c
@@ -14,23 +14,24 @@
#include <linux/string.h>
#include <asm/page.h>
-static void copy_page_nommu(void *to, void *from)
+void copy_page_nommu(void *to, void *from)
{
memcpy(to, from, PAGE_SIZE);
}
-static void clear_page_nommu(void *to)
+void clear_page_nommu(void *to)
{
memset(to, 0, PAGE_SIZE);
}
-static int __init pg_nommu_init(void)
+__kernel_size_t __copy_user(void *to, const void *from, __kernel_size_t n)
{
- copy_page = copy_page_nommu;
- clear_page = clear_page_nommu;
-
+ memcpy(to, from, n);
return 0;
}
-subsys_initcall(pg_nommu_init);
-
+__kernel_size_t __clear_user(void *to, __kernel_size_t n)
+{
+ memset(to, 0, n);
+ return 0;
+}
diff --git a/arch/sh/mm/pg-sh4.c b/arch/sh/mm/pg-sh4.c
index c776b60fc250..07371ed7a313 100644
--- a/arch/sh/mm/pg-sh4.c
+++ b/arch/sh/mm/pg-sh4.c
@@ -2,7 +2,7 @@
* arch/sh/mm/pg-sh4.c
*
* Copyright (C) 1999, 2000, 2002 Niibe Yutaka
- * Copyright (C) 2002 Paul Mundt
+ * Copyright (C) 2002 - 2005 Paul Mundt
*
* Released under the terms of the GNU GPL v2.0.
*/
@@ -23,6 +23,8 @@
extern struct semaphore p3map_sem[];
+#define CACHE_ALIAS (cpu_data->dcache.alias_mask)
+
/*
* clear_user_page
* @to: P1 address
@@ -35,14 +37,15 @@ void clear_user_page(void *to, unsigned long address, struct page *page)
if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
clear_page(to);
else {
- pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
+ pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
_PAGE_RW | _PAGE_CACHABLE |
- _PAGE_DIRTY | _PAGE_ACCESSED |
+ _PAGE_DIRTY | _PAGE_ACCESSED |
_PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
unsigned long phys_addr = PHYSADDR(to);
unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
- pgd_t *dir = pgd_offset_k(p3_addr);
- pmd_t *pmd = pmd_offset(dir, p3_addr);
+ pgd_t *pgd = pgd_offset_k(p3_addr);
+ pud_t *pud = pud_offset(pgd, p3_addr);
+ pmd_t *pmd = pmd_offset(pud, p3_addr);
pte_t *pte = pte_offset_kernel(pmd, p3_addr);
pte_t entry;
unsigned long flags;
@@ -67,21 +70,22 @@ void clear_user_page(void *to, unsigned long address, struct page *page)
* @address: U0 address to be mapped
* @page: page (virt_to_page(to))
*/
-void copy_user_page(void *to, void *from, unsigned long address,
+void copy_user_page(void *to, void *from, unsigned long address,
struct page *page)
{
__set_bit(PG_mapped, &page->flags);
if (((address ^ (unsigned long)to) & CACHE_ALIAS) == 0)
copy_page(to, from);
else {
- pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
+ pgprot_t pgprot = __pgprot(_PAGE_PRESENT |
_PAGE_RW | _PAGE_CACHABLE |
- _PAGE_DIRTY | _PAGE_ACCESSED |
+ _PAGE_DIRTY | _PAGE_ACCESSED |
_PAGE_HW_SHARED | _PAGE_FLAGS_HARD);
unsigned long phys_addr = PHYSADDR(to);
unsigned long p3_addr = P3SEG + (address & CACHE_ALIAS);
- pgd_t *dir = pgd_offset_k(p3_addr);
- pmd_t *pmd = pmd_offset(dir, p3_addr);
+ pgd_t *pgd = pgd_offset_k(p3_addr);
+ pud_t *pud = pud_offset(pgd, p3_addr);
+ pmd_t *pmd = pmd_offset(pud, p3_addr);
pte_t *pte = pte_offset_kernel(pmd, p3_addr);
pte_t entry;
unsigned long flags;
diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c
new file mode 100644
index 000000000000..92e745341e4d
--- /dev/null
+++ b/arch/sh/mm/pmb.c
@@ -0,0 +1,400 @@
+/*
+ * arch/sh/mm/pmb.c
+ *
+ * Privileged Space Mapping Buffer (PMB) Support.
+ *
+ * Copyright (C) 2005, 2006 Paul Mundt
+ *
+ * P1/P2 Section mapping definitions from map32.h, which was:
+ *
+ * Copyright 2003 (c) Lineo Solutions,Inc.
+ *
+ * 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/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <linux/err.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/mmu.h>
+#include <asm/io.h>
+
+#define NR_PMB_ENTRIES 16
+
+static kmem_cache_t *pmb_cache;
+static unsigned long pmb_map;
+
+static struct pmb_entry pmb_init_map[] = {
+ /* vpn ppn flags (ub/sz/c/wt) */
+
+ /* P1 Section Mappings */
+ { 0x80000000, 0x00000000, PMB_SZ_64M | PMB_C, },
+ { 0x84000000, 0x04000000, PMB_SZ_64M | PMB_C, },
+ { 0x88000000, 0x08000000, PMB_SZ_128M | PMB_C, },
+ { 0x90000000, 0x10000000, PMB_SZ_64M | PMB_C, },
+ { 0x94000000, 0x14000000, PMB_SZ_64M | PMB_C, },
+ { 0x98000000, 0x18000000, PMB_SZ_64M | PMB_C, },
+
+ /* P2 Section Mappings */
+ { 0xa0000000, 0x00000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
+ { 0xa4000000, 0x04000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
+ { 0xa8000000, 0x08000000, PMB_UB | PMB_SZ_128M | PMB_WT, },
+ { 0xb0000000, 0x10000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
+ { 0xb4000000, 0x14000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
+ { 0xb8000000, 0x18000000, PMB_UB | PMB_SZ_64M | PMB_WT, },
+};
+
+static inline unsigned long mk_pmb_entry(unsigned int entry)
+{
+ return (entry & PMB_E_MASK) << PMB_E_SHIFT;
+}
+
+static inline unsigned long mk_pmb_addr(unsigned int entry)
+{
+ return mk_pmb_entry(entry) | PMB_ADDR;
+}
+
+static inline unsigned long mk_pmb_data(unsigned int entry)
+{
+ return mk_pmb_entry(entry) | PMB_DATA;
+}
+
+struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
+ unsigned long flags)
+{
+ struct pmb_entry *pmbe;
+
+ pmbe = kmem_cache_alloc(pmb_cache, GFP_KERNEL);
+ if (!pmbe)
+ return ERR_PTR(-ENOMEM);
+
+ pmbe->vpn = vpn;
+ pmbe->ppn = ppn;
+ pmbe->flags = flags;
+
+ return pmbe;
+}
+
+void pmb_free(struct pmb_entry *pmbe)
+{
+ kmem_cache_free(pmb_cache, pmbe);
+}
+
+/*
+ * Must be in P2 for __set_pmb_entry()
+ */
+int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int *entry)
+{
+ unsigned int pos = *entry;
+
+ if (unlikely(pos == PMB_NO_ENTRY))
+ pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
+
+repeat:
+ if (unlikely(pos > NR_PMB_ENTRIES))
+ return -ENOSPC;
+
+ if (test_and_set_bit(pos, &pmb_map)) {
+ pos = find_first_zero_bit(&pmb_map, NR_PMB_ENTRIES);
+ goto repeat;
+ }
+
+ ctrl_outl(vpn | PMB_V, mk_pmb_addr(pos));
+
+#ifdef CONFIG_SH_WRITETHROUGH
+ /*
+ * When we are in 32-bit address extended mode, CCR.CB becomes
+ * invalid, so care must be taken to manually adjust cacheable
+ * translations.
+ */
+ if (likely(flags & PMB_C))
+ flags |= PMB_WT;
+#endif
+
+ ctrl_outl(ppn | flags | PMB_V, mk_pmb_data(pos));
+
+ *entry = pos;
+
+ return 0;
+}
+
+int set_pmb_entry(struct pmb_entry *pmbe)
+{
+ int ret;
+
+ jump_to_P2();
+ ret = __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &pmbe->entry);
+ back_to_P1();
+
+ return ret;
+}
+
+void clear_pmb_entry(struct pmb_entry *pmbe)
+{
+ unsigned int entry = pmbe->entry;
+ unsigned long addr;
+
+ /*
+ * Don't allow clearing of wired init entries, P1 or P2 access
+ * without a corresponding mapping in the PMB will lead to reset
+ * by the TLB.
+ */
+ if (unlikely(entry < ARRAY_SIZE(pmb_init_map) ||
+ entry >= NR_PMB_ENTRIES))
+ return;
+
+ jump_to_P2();
+
+ /* Clear V-bit */
+ addr = mk_pmb_addr(entry);
+ ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
+
+ addr = mk_pmb_data(entry);
+ ctrl_outl(ctrl_inl(addr) & ~PMB_V, addr);
+
+ back_to_P1();
+
+ clear_bit(entry, &pmb_map);
+}
+
+static DEFINE_SPINLOCK(pmb_list_lock);
+static struct pmb_entry *pmb_list;
+
+static inline void pmb_list_add(struct pmb_entry *pmbe)
+{
+ struct pmb_entry **p, *tmp;
+
+ p = &pmb_list;
+ while ((tmp = *p) != NULL)
+ p = &tmp->next;
+
+ pmbe->next = tmp;
+ *p = pmbe;
+}
+
+static inline void pmb_list_del(struct pmb_entry *pmbe)
+{
+ struct pmb_entry **p, *tmp;
+
+ for (p = &pmb_list; (tmp = *p); p = &tmp->next)
+ if (tmp == pmbe) {
+ *p = tmp->next;
+ return;
+ }
+}
+
+static struct {
+ unsigned long size;
+ int flag;
+} pmb_sizes[] = {
+ { .size = 0x20000000, .flag = PMB_SZ_512M, },
+ { .size = 0x08000000, .flag = PMB_SZ_128M, },
+ { .size = 0x04000000, .flag = PMB_SZ_64M, },
+ { .size = 0x01000000, .flag = PMB_SZ_16M, },
+};
+
+long pmb_remap(unsigned long vaddr, unsigned long phys,
+ unsigned long size, unsigned long flags)
+{
+ struct pmb_entry *pmbp;
+ unsigned long wanted;
+ int pmb_flags, i;
+
+ /* Convert typical pgprot value to the PMB equivalent */
+ if (flags & _PAGE_CACHABLE) {
+ if (flags & _PAGE_WT)
+ pmb_flags = PMB_WT;
+ else
+ pmb_flags = PMB_C;
+ } else
+ pmb_flags = PMB_WT | PMB_UB;
+
+ pmbp = NULL;
+ wanted = size;
+
+again:
+ for (i = 0; i < ARRAY_SIZE(pmb_sizes); i++) {
+ struct pmb_entry *pmbe;
+ int ret;
+
+ if (size < pmb_sizes[i].size)
+ continue;
+
+ pmbe = pmb_alloc(vaddr, phys, pmb_flags | pmb_sizes[i].flag);
+ if (IS_ERR(pmbe))
+ return PTR_ERR(pmbe);
+
+ ret = set_pmb_entry(pmbe);
+ if (ret != 0) {
+ pmb_free(pmbe);
+ return -EBUSY;
+ }
+
+ phys += pmb_sizes[i].size;
+ vaddr += pmb_sizes[i].size;
+ size -= pmb_sizes[i].size;
+
+ /*
+ * Link adjacent entries that span multiple PMB entries
+ * for easier tear-down.
+ */
+ if (likely(pmbp))
+ pmbp->link = pmbe;
+
+ pmbp = pmbe;
+ }
+
+ if (size >= 0x1000000)
+ goto again;
+
+ return wanted - size;
+}
+
+void pmb_unmap(unsigned long addr)
+{
+ struct pmb_entry **p, *pmbe;
+
+ for (p = &pmb_list; (pmbe = *p); p = &pmbe->next)
+ if (pmbe->vpn == addr)
+ break;
+
+ if (unlikely(!pmbe))
+ return;
+
+ WARN_ON(!test_bit(pmbe->entry, &pmb_map));
+
+ do {
+ struct pmb_entry *pmblink = pmbe;
+
+ clear_pmb_entry(pmbe);
+ pmbe = pmblink->link;
+
+ pmb_free(pmblink);
+ } while (pmbe);
+}
+
+static void pmb_cache_ctor(void *pmb, kmem_cache_t *cachep, unsigned long flags)
+{
+ struct pmb_entry *pmbe = pmb;
+
+ memset(pmb, 0, sizeof(struct pmb_entry));
+
+ spin_lock_irq(&pmb_list_lock);
+
+ pmbe->entry = PMB_NO_ENTRY;
+ pmb_list_add(pmbe);
+
+ spin_unlock_irq(&pmb_list_lock);
+}
+
+static void pmb_cache_dtor(void *pmb, kmem_cache_t *cachep, unsigned long flags)
+{
+ spin_lock_irq(&pmb_list_lock);
+ pmb_list_del(pmb);
+ spin_unlock_irq(&pmb_list_lock);
+}
+
+static int __init pmb_init(void)
+{
+ unsigned int nr_entries = ARRAY_SIZE(pmb_init_map);
+ unsigned int entry;
+
+ BUG_ON(unlikely(nr_entries >= NR_PMB_ENTRIES));
+
+ pmb_cache = kmem_cache_create("pmb", sizeof(struct pmb_entry),
+ 0, 0, pmb_cache_ctor, pmb_cache_dtor);
+ BUG_ON(!pmb_cache);
+
+ jump_to_P2();
+
+ /*
+ * Ordering is important, P2 must be mapped in the PMB before we
+ * can set PMB.SE, and P1 must be mapped before we jump back to
+ * P1 space.
+ */
+ for (entry = 0; entry < nr_entries; entry++) {
+ struct pmb_entry *pmbe = pmb_init_map + entry;
+
+ __set_pmb_entry(pmbe->vpn, pmbe->ppn, pmbe->flags, &entry);
+ }
+
+ ctrl_outl(0, PMB_IRMCR);
+
+ /* PMB.SE and UB[7] */
+ ctrl_outl((1 << 31) | (1 << 7), PMB_PASCR);
+
+ back_to_P1();
+
+ return 0;
+}
+arch_initcall(pmb_init);
+
+static int pmb_seq_show(struct seq_file *file, void *iter)
+{
+ int i;
+
+ seq_printf(file, "V: Valid, C: Cacheable, WT: Write-Through\n"
+ "CB: Copy-Back, B: Buffered, UB: Unbuffered\n");
+ seq_printf(file, "ety vpn ppn size flags\n");
+
+ for (i = 0; i < NR_PMB_ENTRIES; i++) {
+ unsigned long addr, data;
+ unsigned int size;
+ char *sz_str = NULL;
+
+ addr = ctrl_inl(mk_pmb_addr(i));
+ data = ctrl_inl(mk_pmb_data(i));
+
+ size = data & PMB_SZ_MASK;
+ sz_str = (size == PMB_SZ_16M) ? " 16MB":
+ (size == PMB_SZ_64M) ? " 64MB":
+ (size == PMB_SZ_128M) ? "128MB":
+ "512MB";
+
+ /* 02: V 0x88 0x08 128MB C CB B */
+ seq_printf(file, "%02d: %c 0x%02lx 0x%02lx %s %c %s %s\n",
+ i, ((addr & PMB_V) && (data & PMB_V)) ? 'V' : ' ',
+ (addr >> 24) & 0xff, (data >> 24) & 0xff,
+ sz_str, (data & PMB_C) ? 'C' : ' ',
+ (data & PMB_WT) ? "WT" : "CB",
+ (data & PMB_UB) ? "UB" : " B");
+ }
+
+ return 0;
+}
+
+static int pmb_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pmb_seq_show, NULL);
+}
+
+static struct file_operations pmb_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = pmb_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init pmb_debugfs_init(void)
+{
+ struct dentry *dentry;
+
+ dentry = debugfs_create_file("pmb", S_IFREG | S_IRUGO,
+ NULL, NULL, &pmb_debugfs_fops);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ return 0;
+}
+postcore_initcall(pmb_debugfs_init);
diff --git a/arch/sh/mm/tlb-flush.c b/arch/sh/mm/tlb-flush.c
new file mode 100644
index 000000000000..73ec7f6084fa
--- /dev/null
+++ b/arch/sh/mm/tlb-flush.c
@@ -0,0 +1,134 @@
+/*
+ * TLB flushing operations for SH with an MMU.
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 2003 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/mm.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
+{
+ if (vma->vm_mm && vma->vm_mm->context.id != NO_CONTEXT) {
+ unsigned long flags;
+ unsigned long asid;
+ unsigned long saved_asid = MMU_NO_ASID;
+
+ asid = vma->vm_mm->context.id & MMU_CONTEXT_ASID_MASK;
+ page &= PAGE_MASK;
+
+ local_irq_save(flags);
+ if (vma->vm_mm != current->mm) {
+ saved_asid = get_asid();
+ set_asid(asid);
+ }
+ __flush_tlb_page(asid, page);
+ if (saved_asid != MMU_NO_ASID)
+ set_asid(saved_asid);
+ local_irq_restore(flags);
+ }
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ struct mm_struct *mm = vma->vm_mm;
+
+ if (mm->context.id != NO_CONTEXT) {
+ unsigned long flags;
+ int size;
+
+ local_irq_save(flags);
+ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
+ mm->context.id = NO_CONTEXT;
+ if (mm == current->mm)
+ activate_context(mm);
+ } else {
+ unsigned long asid;
+ unsigned long saved_asid = MMU_NO_ASID;
+
+ asid = mm->context.id & MMU_CONTEXT_ASID_MASK;
+ start &= PAGE_MASK;
+ end += (PAGE_SIZE - 1);
+ end &= PAGE_MASK;
+ if (mm != current->mm) {
+ saved_asid = get_asid();
+ set_asid(asid);
+ }
+ while (start < end) {
+ __flush_tlb_page(asid, start);
+ start += PAGE_SIZE;
+ }
+ if (saved_asid != MMU_NO_ASID)
+ set_asid(saved_asid);
+ }
+ local_irq_restore(flags);
+ }
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ unsigned long flags;
+ int size;
+
+ local_irq_save(flags);
+ size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
+ if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
+ flush_tlb_all();
+ } else {
+ unsigned long asid;
+ unsigned long saved_asid = get_asid();
+
+ asid = init_mm.context.id & MMU_CONTEXT_ASID_MASK;
+ start &= PAGE_MASK;
+ end += (PAGE_SIZE - 1);
+ end &= PAGE_MASK;
+ set_asid(asid);
+ while (start < end) {
+ __flush_tlb_page(asid, start);
+ start += PAGE_SIZE;
+ }
+ set_asid(saved_asid);
+ }
+ local_irq_restore(flags);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ /* Invalidate all TLB of this process. */
+ /* Instead of invalidating each TLB, we get new MMU context. */
+ if (mm->context.id != NO_CONTEXT) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ mm->context.id = NO_CONTEXT;
+ if (mm == current->mm)
+ activate_context(mm);
+ local_irq_restore(flags);
+ }
+}
+
+void flush_tlb_all(void)
+{
+ unsigned long flags, status;
+
+ /*
+ * Flush all the TLB.
+ *
+ * Write to the MMU control register's bit:
+ * TF-bit for SH-3, TI-bit for SH-4.
+ * It's same position, bit #2.
+ */
+ local_irq_save(flags);
+ status = ctrl_inl(MMUCR);
+ status |= 0x04;
+ ctrl_outl(status, MMUCR);
+ ctrl_barrier();
+ local_irq_restore(flags);
+}
diff --git a/arch/sh/mm/tlb-sh4.c b/arch/sh/mm/tlb-sh4.c
index 115b1b6be40b..812b2d567de2 100644
--- a/arch/sh/mm/tlb-sh4.c
+++ b/arch/sh/mm/tlb-sh4.c
@@ -36,7 +36,6 @@ void update_mmu_cache(struct vm_area_struct * vma,
unsigned long vpn;
struct page *page;
unsigned long pfn;
- unsigned long ptea;
/* Ptrace may call this routine. */
if (vma && current->active_mm != vma->vm_mm)
@@ -59,10 +58,11 @@ void update_mmu_cache(struct vm_area_struct * vma,
ctrl_outl(vpn, MMU_PTEH);
pteval = pte_val(pte);
+
/* Set PTEA register */
- /* TODO: make this look less hacky */
- ptea = ((pteval >> 28) & 0xe) | (pteval & 0x1);
- ctrl_outl(ptea, MMU_PTEA);
+ if (cpu_data->flags & CPU_HAS_PTEA)
+ /* TODO: make this look less hacky */
+ ctrl_outl(((pteval >> 28) & 0xe) | (pteval & 0x1), MMU_PTEA);
/* Set PTEL register */
pteval &= _PAGE_FLAGS_HARDWARE_MASK; /* drop software flags */
diff --git a/arch/sh/oprofile/Makefile b/arch/sh/oprofile/Makefile
index 686738d4aa3c..1f25d9bb7538 100644
--- a/arch/sh/oprofile/Makefile
+++ b/arch/sh/oprofile/Makefile
@@ -7,7 +7,11 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
timer_int.o )
profdrvr-y := op_model_null.o
+
+# SH7750-style performance counters exist across 7750/7750S and 7091.
+profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750S) := op_model_sh7750.o
profdrvr-$(CONFIG_CPU_SUBTYPE_SH7750) := op_model_sh7750.o
+profdrvr-$(CONFIG_CPU_SUBTYPE_SH7091) := op_model_sh7750.o
oprofile-y := $(DRIVER_OBJS) $(profdrvr-y)
diff --git a/arch/sh/tools/gen-mach-types b/arch/sh/tools/gen-mach-types
index bb2b82234e83..65161e368353 100644
--- a/arch/sh/tools/gen-mach-types
+++ b/arch/sh/tools/gen-mach-types
@@ -20,8 +20,6 @@ END {
printf("#ifndef __ASM_SH_MACHTYPES_H\n");
printf("#define __ASM_SH_MACHTYPES_H\n");
printf("\n");
- printf("#include <linux/config.h>\n");
- printf("\n");
printf("/*\n");
printf(" * We'll use the following MACH_xxx defs for placeholders for the time\n");
printf(" * being .. these will all go away once sh_machtype is assigned per-board.\n");
diff --git a/arch/sh/tools/mach-types b/arch/sh/tools/mach-types
index 182fe9092577..ac57638977ee 100644
--- a/arch/sh/tools/mach-types
+++ b/arch/sh/tools/mach-types
@@ -8,16 +8,15 @@
SE SH_SOLUTION_ENGINE
7751SE SH_7751_SOLUTION_ENGINE
7300SE SH_7300_SOLUTION_ENGINE
+7343SE SH_7343_SOLUTION_ENGINE
73180SE SH_73180_SOLUTION_ENGINE
7751SYSTEMH SH_7751_SYSTEMH
HP6XX SH_HP6XX
HD64461 HD64461
HD64465 HD64465
-SH2000 SH_SH2000
SATURN SH_SATURN
DREAMCAST SH_DREAMCAST
BIGSUR SH_BIGSUR
-ADX SH_ADX
MPC1211 SH_MPC1211
SNAPGEAR SH_SECUREEDGE5410
HS7751RVOIP SH_HS7751RVOIP
@@ -25,4 +24,9 @@ RTS7751R2D SH_RTS7751R2D
EDOSK7705 SH_EDOSK7705
SH4202_MICRODEV SH_SH4202_MICRODEV
SH03 SH_SH03
-
+LANDISK SH_LANDISK
+R7780RP SH_R7780RP
+R7780MP SH_R7780MP
+TITAN SH_TITAN
+SHMIN SH_SHMIN
+7710VOIPGW SH_7710VOIPGW
diff --git a/arch/sh64/boot/compressed/misc.c b/arch/sh64/boot/compressed/misc.c
index ee7a1b6acb83..aea00c53ce29 100644
--- a/arch/sh64/boot/compressed/misc.c
+++ b/arch/sh64/boot/compressed/misc.c
@@ -1,5 +1,5 @@
/*
- * arch/shmedia/boot/compressed/misc.c
+ * arch/sh64/boot/compressed/misc.c
*
* This is a collection of several routines from gzip-1.0.3
* adapted for Linux.
diff --git a/arch/sh64/configs/cayman_defconfig b/arch/sh64/configs/cayman_defconfig
index 48f27407d5e4..d81df574a7f7 100644
--- a/arch/sh64/configs/cayman_defconfig
+++ b/arch/sh64/configs/cayman_defconfig
@@ -1,49 +1,62 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.11
-# Fri Feb 25 18:14:31 2005
+# Linux kernel version: 2.6.18
+# Tue Oct 3 13:30:51 2006
#
CONFIG_SUPERH=y
CONFIG_SUPERH64=y
CONFIG_MMU=y
-CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_HWEIGHT=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
#
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
#
CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
# CONFIG_SYSVIPC is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_RT_MUTEXES=y
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -51,6 +64,27 @@ CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_MODULES is not set
#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
# System type
#
# CONFIG_SH_GENERIC is not set
@@ -103,15 +137,23 @@ CONFIG_HEARTBEAT=y
CONFIG_HDSP253_LED=y
CONFIG_SH_DMA=y
CONFIG_PREEMPT=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_RESOURCES_64BIT is not set
#
# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
#
-CONFIG_SUPERHYWAY=y
CONFIG_PCI=y
CONFIG_SH_PCIDMA_NONCOHERENT=y
-CONFIG_PCI_LEGACY_PROC=y
-CONFIG_PCI_NAMES=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -119,10 +161,6 @@ CONFIG_PCI_NAMES=y
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# PCI Hotplug Support
#
# CONFIG_HOTPLUG_PCI is not set
@@ -135,6 +173,92 @@ CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
#
+# Networking
+#
+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_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# 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_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# DCCP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_DCCP is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
# Device Drivers
#
@@ -145,6 +269,12 @@ CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
#
# Memory Technology Devices (MTD)
@@ -163,7 +293,6 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -176,18 +305,9 @@ CONFIG_BLK_DEV_LOOP=y
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 is not set
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_LBD is not set
# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
# CONFIG_ATA_OVER_ETH is not set
#
@@ -198,7 +318,9 @@ CONFIG_IOSCHED_CFQ=y
#
# SCSI device support
#
+# CONFIG_RAID_ATTRS is not set
CONFIG_SCSI=y
+# CONFIG_SCSI_NETLINK is not set
CONFIG_SCSI_PROC_FS=y
#
@@ -209,6 +331,7 @@ CONFIG_BLK_DEV_SD=y
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -218,15 +341,18 @@ CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_FC_ATTRS is not set
# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -234,40 +360,39 @@ CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
-# CONFIG_SCSI_SATA is not set
-# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_EATA is not set
-# CONFIG_SCSI_EATA_PIO is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_NSP32 is not set
# CONFIG_SCSI_DEBUG is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
# CONFIG_MD is not set
@@ -276,6 +401,9 @@ CONFIG_SCSI_QLA2XXX=y
# Fusion MPT device support
#
# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
+# CONFIG_FUSION_SAS is not set
#
# IEEE 1394 (FireWire) support
@@ -288,70 +416,8 @@ CONFIG_SCSI_QLA2XXX=y
# CONFIG_I2O is not set
#
-# Networking support
-#
-CONFIG_NET=y
-
-#
-# Networking options
+# Network device support
#
-CONFIG_PACKET=y
-# CONFIG_PACKET_MMAP is not set
-# CONFIG_NETLINK_DEV is not set
-CONFIG_UNIX=y
-# CONFIG_NET_KEY is not set
-CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
-# CONFIG_IP_ADVANCED_ROUTER is not set
-CONFIG_IP_PNP=y
-# CONFIG_IP_PNP_DHCP is not set
-# CONFIG_IP_PNP_BOOTP is not set
-# CONFIG_IP_PNP_RARP is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_ARPD is not set
-# CONFIG_SYN_COOKIES is not set
-# CONFIG_INET_AH is not set
-# CONFIG_INET_ESP is not set
-# CONFIG_INET_IPCOMP is not set
-# CONFIG_INET_TUNNEL is not set
-CONFIG_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-# CONFIG_IPV6 is not set
-# CONFIG_NETFILTER is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP_SCTP is not set
-# CONFIG_ATM is not set
-# CONFIG_BRIDGE is not set
-# CONFIG_VLAN_8021Q is not set
-# CONFIG_DECNET is not set
-# CONFIG_LLC2 is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_X25 is not set
-# CONFIG_LAPB is not set
-# CONFIG_NET_DIVERT is not set
-# CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
-
-#
-# QoS and/or fair queueing
-#
-# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
-
-#
-# Network testing
-#
-# CONFIG_NET_PKTGEN is not set
-# CONFIG_NETPOLL is not set
-# CONFIG_NET_POLL_CONTROLLER is not set
-# CONFIG_HAMRADIO is not set
-# CONFIG_IRDA is not set
-# CONFIG_BT is not set
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
# CONFIG_BONDING is not set
@@ -364,6 +430,11 @@ CONFIG_NETDEVICES=y
# CONFIG_ARCNET is not set
#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
@@ -371,7 +442,9 @@ CONFIG_NET_ETHERNET=y
# CONFIG_STNIC is not set
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
# CONFIG_NET_VENDOR_3COM is not set
+# CONFIG_SMC91X is not set
#
# Tulip family network device support
@@ -385,6 +458,7 @@ CONFIG_TULIP=y
# CONFIG_DE4X5 is not set
# CONFIG_WINBOND_840 is not set
# CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
# CONFIG_HP100 is not set
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
@@ -416,15 +490,22 @@ CONFIG_NET_PCI=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
#
+# CONFIG_CHELSIO_T1 is not set
# CONFIG_IXGB is not set
# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
#
# Token Ring devices
@@ -447,6 +528,8 @@ CONFIG_NET_PCI=y
# CONFIG_NET_FC is not set
# CONFIG_SHAPER is not set
# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
#
# ISDN subsystem
@@ -462,6 +545,7 @@ CONFIG_NET_PCI=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -476,19 +560,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
# CONFIG_INPUT_EVBUG is not set
#
-# Input I/O drivers
-#
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-CONFIG_SERIO=y
-CONFIG_SERIO_I8042=y
-CONFIG_SERIO_SERPORT=y
-# CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PCIPS2 is not set
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-
-#
# Input Device Drivers
#
CONFIG_INPUT_KEYBOARD=y
@@ -497,6 +568,7 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
@@ -506,11 +578,23 @@ CONFIG_MOUSE_PS2=y
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
CONFIG_VT_CONSOLE=y
CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
# CONFIG_SERIAL_NONSTANDARD is not set
#
@@ -522,9 +606,11 @@ CONFIG_HW_CONSOLE=y
# Non-8250 serial port support
#
CONFIG_SERIAL_SH_SCI=y
+CONFIG_SERIAL_SH_SCI_NR_UARTS=2
CONFIG_SERIAL_SH_SCI_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -551,7 +637,7 @@ CONFIG_WATCHDOG=y
#
# CONFIG_PCIPCWATCHDOG is not set
# CONFIG_WDTPCI is not set
-# CONFIG_RTC is not set
+CONFIG_HW_RANDOM=y
# CONFIG_GEN_RTC is not set
# CONFIG_DTLK is not set
# CONFIG_R3964 is not set
@@ -564,14 +650,35 @@ CONFIG_WATCHDOG=y
# CONFIG_RAW_DRIVER is not set
#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+# CONFIG_TELCLOCK is not set
+
+#
# I2C support
#
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
-# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ABITUGURU is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
#
# Misc devices
@@ -581,6 +688,7 @@ CONFIG_WATCHDOG=y
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -590,7 +698,13 @@ CONFIG_WATCHDOG=y
#
# Graphics support
#
+CONFIG_FIRMWARE_EDID=y
CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
# CONFIG_FB_CIRRUS is not set
@@ -599,9 +713,10 @@ CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
# CONFIG_FB_EPSON1355 is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_MATROX is not set
-# CONFIG_FB_RADEON_OLD is not set
# CONFIG_FB_RADEON is not set
# CONFIG_FB_ATY128 is not set
# CONFIG_FB_ATY is not set
@@ -617,18 +732,20 @@ CONFIG_FB_KYRO=y
#
# Console display driver support
#
-# CONFIG_VGA_CONSOLE is not set
CONFIG_DUMMY_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_FONTS=y
# CONFIG_FONT_8x8 is not set
CONFIG_FONT_8x16=y
# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
#
# Logo configuration
@@ -650,12 +767,13 @@ CONFIG_LOGO_SUPERH_CLUT224=y
#
# USB support
#
-# CONFIG_USB is not set
CONFIG_USB_ARCH_HAS_HCD=y
CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+# CONFIG_USB is not set
#
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
#
#
@@ -669,15 +787,51 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_MMC is not set
#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
# InfiniBand support
#
# CONFIG_INFINIBAND is not set
#
+# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
+#
+
+#
+# Real Time Clock
+#
+# CONFIG_RTC_CLASS is not set
+
+#
+# DMA Engine support
+#
+# CONFIG_DMA_ENGINE is not set
+
+#
+# DMA Clients
+#
+
+#
+# DMA Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -687,17 +841,18 @@ CONFIG_JBD=y
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
-
-#
-# XFS support
-#
+# CONFIG_FS_POSIX_ACL is not set
# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
CONFIG_MINIX_FS=y
CONFIG_ROMFS_FS=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
# CONFIG_QUOTA is not set
CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
#
# CD-ROM/DVD Filesystems
@@ -717,14 +872,14 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
-# CONFIG_TMPFS_XATTR is not set
+# CONFIG_TMPFS_POSIX_ACL is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
#
# Miscellaneous filesystems
@@ -748,12 +903,14 @@ CONFIG_RAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
@@ -762,6 +919,7 @@ CONFIG_SUNRPC=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -781,6 +939,7 @@ CONFIG_MSDOS_PARTITION=y
# CONFIG_SGI_PARTITION is not set
# CONFIG_ULTRIX_PARTITION is not set
# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
# CONFIG_EFI_PARTITION is not set
#
@@ -796,13 +955,32 @@ CONFIG_MSDOS_PARTITION=y
#
# Kernel hacking
#
-CONFIG_DEBUG_KERNEL=y
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
CONFIG_SCHEDSTATS=y
+# 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 is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
CONFIG_FRAME_POINTER=y
+# CONFIG_UNWIND_INFO is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
# CONFIG_EARLY_PRINTK is not set
# CONFIG_DEBUG_KERNEL_WITH_GDB_STUB is not set
CONFIG_SH64_PROC_TLB=y
@@ -824,14 +1002,12 @@ CONFIG_SH64_SR_WATCH=y
# CONFIG_CRYPTO is not set
#
-# Hardware crypto devices
-#
-
-#
# Library routines
#
# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
CONFIG_GENERIC_HARDIRQS=y
CONFIG_GENERIC_IRQ_PROBE=y
diff --git a/arch/sh64/kernel/alphanum.c b/arch/sh64/kernel/alphanum.c
index 9079d1e94f2b..91707c1acd70 100644
--- a/arch/sh64/kernel/alphanum.c
+++ b/arch/sh64/kernel/alphanum.c
@@ -1,5 +1,5 @@
/*
- * arch/sh64/kernel/alpanum.c
+ * arch/sh64/kernel/alphanum.c
*
* Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
*
diff --git a/arch/sh64/kernel/process.c b/arch/sh64/kernel/process.c
index db475b7833fb..525d0ec19b78 100644
--- a/arch/sh64/kernel/process.c
+++ b/arch/sh64/kernel/process.c
@@ -20,261 +20,16 @@
/*
* This file handles the architecture-dependent parts of process handling..
*/
-
-/* Temporary flags/tests. All to be removed/undefined. BEGIN */
-#define IDLE_TRACE
-#define VM_SHOW_TABLES
-#define VM_TEST_FAULT
-#define VM_TEST_RTLBMISS
-#define VM_TEST_WTLBMISS
-
-#undef VM_SHOW_TABLES
-#undef IDLE_TRACE
-/* Temporary flags/tests. All to be removed/undefined. END */
-
-#define __KERNEL_SYSCALLS__
-#include <stdarg.h>
-
-#include <linux/kernel.h>
-#include <linux/rwsem.h>
#include <linux/mm.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
#include <linux/ptrace.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/interrupt.h>
-#include <linux/unistd.h>
-#include <linux/delay.h>
#include <linux/reboot.h>
#include <linux/init.h>
-
+#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/processor.h> /* includes also <asm/registers.h> */
-#include <asm/mmu_context.h>
-#include <asm/elf.h>
-#include <asm/page.h>
-
-#include <linux/irq.h>
struct task_struct *last_task_used_math = NULL;
-#ifdef IDLE_TRACE
-#ifdef VM_SHOW_TABLES
-/* For testing */
-static void print_PTE(long base)
-{
- int i, skip=0;
- long long x, y, *p = (long long *) base;
-
- for (i=0; i< 512; i++, p++){
- if (*p == 0) {
- if (!skip) {
- skip++;
- printk("(0s) ");
- }
- } else {
- skip=0;
- x = (*p) >> 32;
- y = (*p) & 0xffffffff;
- printk("%08Lx%08Lx ", x, y);
- if (!((i+1)&0x3)) printk("\n");
- }
- }
-}
-
-/* For testing */
-static void print_DIR(long base)
-{
- int i, skip=0;
- long *p = (long *) base;
-
- for (i=0; i< 512; i++, p++){
- if (*p == 0) {
- if (!skip) {
- skip++;
- printk("(0s) ");
- }
- } else {
- skip=0;
- printk("%08lx ", *p);
- if (!((i+1)&0x7)) printk("\n");
- }
- }
-}
-
-/* For testing */
-static void print_vmalloc_first_tables(void)
-{
-
-#define PRESENT 0x800 /* Bit 11 */
-
- /*
- * Do it really dirty by looking at raw addresses,
- * raw offsets, no types. If we used pgtable/pgalloc
- * macros/definitions we could hide potential bugs.
- *
- * Note that pointers are 32-bit for CDC.
- */
- long pgdt, pmdt, ptet;
-
- pgdt = (long) &swapper_pg_dir;
- printk("-->PGD (0x%08lx):\n", pgdt);
- print_DIR(pgdt);
- printk("\n");
-
- /* VMALLOC pool is mapped at 0xc0000000, second (pointer) entry in PGD */
- pgdt += 4;
- pmdt = (long) (* (long *) pgdt);
- if (!(pmdt & PRESENT)) {
- printk("No PMD\n");
- return;
- } else pmdt &= 0xfffff000;
-
- printk("-->PMD (0x%08lx):\n", pmdt);
- print_DIR(pmdt);
- printk("\n");
-
- /* Get the pmdt displacement for 0xc0000000 */
- pmdt += 2048;
-
- /* just look at first two address ranges ... */
- /* ... 0xc0000000 ... */
- ptet = (long) (* (long *) pmdt);
- if (!(ptet & PRESENT)) {
- printk("No PTE0\n");
- return;
- } else ptet &= 0xfffff000;
-
- printk("-->PTE0 (0x%08lx):\n", ptet);
- print_PTE(ptet);
- printk("\n");
-
- /* ... 0xc0001000 ... */
- ptet += 4;
- if (!(ptet & PRESENT)) {
- printk("No PTE1\n");
- return;
- } else ptet &= 0xfffff000;
- printk("-->PTE1 (0x%08lx):\n", ptet);
- print_PTE(ptet);
- printk("\n");
-}
-#else
-#define print_vmalloc_first_tables()
-#endif /* VM_SHOW_TABLES */
-
-static void test_VM(void)
-{
- void *a, *b, *c;
-
-#ifdef VM_SHOW_TABLES
- printk("Initial PGD/PMD/PTE\n");
-#endif
- print_vmalloc_first_tables();
-
- printk("Allocating 2 bytes\n");
- a = vmalloc(2);
- print_vmalloc_first_tables();
-
- printk("Allocating 4100 bytes\n");
- b = vmalloc(4100);
- print_vmalloc_first_tables();
-
- printk("Allocating 20234 bytes\n");
- c = vmalloc(20234);
- print_vmalloc_first_tables();
-
-#ifdef VM_TEST_FAULT
- /* Here you may want to fault ! */
-
-#ifdef VM_TEST_RTLBMISS
- printk("Ready to fault upon read.\n");
- if (* (char *) a) {
- printk("RTLBMISSed on area a !\n");
- }
- printk("RTLBMISSed on area a !\n");
-#endif
-
-#ifdef VM_TEST_WTLBMISS
- printk("Ready to fault upon write.\n");
- *((char *) b) = 'L';
- printk("WTLBMISSed on area b !\n");
-#endif
-
-#endif /* VM_TEST_FAULT */
-
- printk("Deallocating the 4100 byte chunk\n");
- vfree(b);
- print_vmalloc_first_tables();
-
- printk("Deallocating the 2 byte chunk\n");
- vfree(a);
- print_vmalloc_first_tables();
-
- printk("Deallocating the last chunk\n");
- vfree(c);
- print_vmalloc_first_tables();
-}
-
-extern unsigned long volatile jiffies;
-int once = 0;
-unsigned long old_jiffies;
-int pid = -1, pgid = -1;
-
-void idle_trace(void)
-{
-
- _syscall0(int, getpid)
- _syscall1(int, getpgid, int, pid)
-
- if (!once) {
- /* VM allocation/deallocation simple test */
- test_VM();
- pid = getpid();
-
- printk("Got all through to Idle !!\n");
- printk("I'm now going to loop forever ...\n");
- printk("Any ! below is a timer tick.\n");
- printk("Any . below is a getpgid system call from pid = %d.\n", pid);
-
-
- old_jiffies = jiffies;
- once++;
- }
-
- if (old_jiffies != jiffies) {
- old_jiffies = jiffies - old_jiffies;
- switch (old_jiffies) {
- case 1:
- printk("!");
- break;
- case 2:
- printk("!!");
- break;
- case 3:
- printk("!!!");
- break;
- case 4:
- printk("!!!!");
- break;
- default:
- printk("(%d!)", (int) old_jiffies);
- }
- old_jiffies = jiffies;
- }
- pgid = getpgid(pid);
- printk(".");
-}
-#else
-#define idle_trace() do { } while (0)
-#endif /* IDLE_TRACE */
-
static int hlt_counter = 1;
#define HARD_IDLE_TIMEOUT (HZ / 3)
@@ -323,7 +78,6 @@ void cpu_idle(void)
local_irq_disable();
while (!need_resched()) {
local_irq_enable();
- idle_trace();
hlt();
local_irq_disable();
}
@@ -622,6 +376,10 @@ void free_task_struct(struct task_struct *p)
/*
* Create a kernel thread
*/
+ATTRIB_NORET void kernel_thread_helper(void *arg, int (*fn)(void *))
+{
+ do_exit(fn(arg));
+}
/*
* This is the mechanism for creating a new kernel thread.
@@ -633,19 +391,17 @@ void free_task_struct(struct task_struct *p)
*/
int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
{
- /* A bit less processor dependent than older sh ... */
- unsigned int reply;
+ struct pt_regs regs;
-static __inline__ _syscall2(int,clone,unsigned long,flags,unsigned long,newsp)
-static __inline__ _syscall1(int,exit,int,ret)
+ memset(&regs, 0, sizeof(regs));
+ regs.regs[2] = (unsigned long)arg;
+ regs.regs[3] = (unsigned long)fn;
- reply = clone(flags | CLONE_VM, 0);
- if (!reply) {
- /* Child */
- reply = exit(fn(arg));
- }
+ regs.pc = (unsigned long)kernel_thread_helper;
+ regs.sr = (1 << 30);
- return reply;
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0,
+ &regs, 0, NULL, NULL);
}
/*
diff --git a/arch/sh64/kernel/sys_sh64.c b/arch/sh64/kernel/sys_sh64.c
index 58ff7d522d81..ad0fa4e003e7 100644
--- a/arch/sh64/kernel/sys_sh64.c
+++ b/arch/sh64/kernel/sys_sh64.c
@@ -32,6 +32,7 @@
#include <asm/uaccess.h>
#include <asm/ipc.h>
#include <asm/ptrace.h>
+#include <asm/unistd.h>
#define REG_3 3
@@ -279,7 +280,25 @@ asmlinkage int sys_uname(struct old_utsname * name)
if (!name)
return -EFAULT;
down_read(&uts_sem);
- err=copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
return err?-EFAULT:0;
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register unsigned long __sc0 __asm__ ("r9") = ((0x13 << 16) | __NR_execve);
+ register unsigned long __sc2 __asm__ ("r2") = (unsigned long) filename;
+ register unsigned long __sc3 __asm__ ("r3") = (unsigned long) argv;
+ register unsigned long __sc4 __asm__ ("r4") = (unsigned long) envp;
+ __asm__ __volatile__ ("trapa %1 !\t\t\t execve(%2,%3,%4)"
+ : "=r" (__sc0)
+ : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) );
+ __asm__ __volatile__ ("!dummy %0 %1 %2 %3"
+ : : "r" (__sc0), "r" (__sc2), "r" (__sc3), "r" (__sc4) : "memory");
+ return __sc0;
+}
diff --git a/arch/sh64/kernel/time.c b/arch/sh64/kernel/time.c
index b8162e59030e..9c4a38a8698c 100644
--- a/arch/sh64/kernel/time.c
+++ b/arch/sh64/kernel/time.c
@@ -107,8 +107,6 @@
#define TICK_SIZE (tick_nsec / 1000)
-extern unsigned long wall_jiffies;
-
static unsigned long tmu_base, rtc_base;
unsigned long cprc_base;
@@ -194,13 +192,6 @@ void do_gettimeofday(struct timeval *tv)
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = usecs_since_tick();
- {
- unsigned long lost = jiffies - wall_jiffies;
-
- if (lost)
- usec += lost * (1000000 / HZ);
- }
-
sec = xtime.tv_sec;
usec += xtime.tv_nsec / 1000;
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
@@ -229,8 +220,7 @@ int do_settimeofday(struct timespec *tv)
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
- nsec -= 1000 * (usecs_since_tick() +
- (jiffies - wall_jiffies) * (1000000 / HZ));
+ nsec -= 1000 * usecs_since_tick();
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -298,7 +288,7 @@ static inline void do_timer_interrupt(int irq, struct pt_regs *regs)
asm ("getcon cr62, %0" : "=r" (current_ctc));
ctc_last_interrupt = (unsigned long) current_ctc;
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
diff --git a/arch/sh64/lib/c-checksum.c b/arch/sh64/lib/c-checksum.c
index 53c1cabb3428..0e8a742abf8c 100644
--- a/arch/sh64/lib/c-checksum.c
+++ b/arch/sh64/lib/c-checksum.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/lib/csum_parial.c
+ * arch/sh64/lib/c-checksum.c
*
* This file contains network checksum routines that are better done
* in an architecture-specific manner due to speed..
diff --git a/arch/sh64/mach-cayman/led.c b/arch/sh64/mach-cayman/led.c
index 8b3cc4c78870..b4e122fd9502 100644
--- a/arch/sh64/mach-cayman/led.c
+++ b/arch/sh64/mach-cayman/led.c
@@ -1,5 +1,5 @@
/*
- * arch/sh64/kernel/led_cayman.c
+ * arch/sh64/mach-cayman/led.c
*
* Copyright (C) 2002 Stuart Menefy <stuart.menefy@st.com>
*
diff --git a/arch/sh64/mm/fault.c b/arch/sh64/mm/fault.c
index f08d0eaf6497..8e2f6c28b739 100644
--- a/arch/sh64/mm/fault.c
+++ b/arch/sh64/mm/fault.c
@@ -277,7 +277,7 @@ bad_area:
show_regs(regs);
#endif
}
- if (tsk->pid == 1) {
+ if (is_init(tsk)) {
panic("INIT had user mode bad_area\n");
}
tsk->thread.address = address;
@@ -319,14 +319,14 @@ no_context:
* us unable to handle the page fault gracefully.
*/
out_of_memory:
- if (current->pid == 1) {
+ if (is_init(current)) {
panic("INIT out of memory\n");
yield();
goto survive;
}
printk("fault:Out of memory\n");
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/sh64/oprofile/op_model_null.c b/arch/sh64/oprofile/op_model_null.c
index a845b088edb4..a750ea1fee98 100644
--- a/arch/sh64/oprofile/op_model_null.c
+++ b/arch/sh64/oprofile/op_model_null.c
@@ -1,5 +1,5 @@
/*
- * arch/sh/oprofile/op_model_null.c
+ * arch/sh64/oprofile/op_model_null.c
*
* Copyright (C) 2003 Paul Mundt
*
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 9431e967aa45..2f96610a83e9 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -289,6 +289,13 @@ endmenu
source "fs/Kconfig"
+menu "Instrumentation Support"
+ depends on EXPERIMENTAL
+
+source "arch/sparc/oprofile/Kconfig"
+
+endmenu
+
source "arch/sparc/Kconfig.debug"
source "security/Kconfig"
diff --git a/arch/sparc/Makefile b/arch/sparc/Makefile
index 4cdbb2d59ed0..f33c3817f014 100644
--- a/arch/sparc/Makefile
+++ b/arch/sparc/Makefile
@@ -30,6 +30,8 @@ HEAD_Y := $(head-y)
core-y += arch/sparc/kernel/ arch/sparc/mm/ arch/sparc/math-emu/
libs-y += arch/sparc/prom/ arch/sparc/lib/
+drivers-$(CONFIG_OPROFILE) += arch/sparc/oprofile/
+
# Export what is needed by arch/sparc/boot/Makefile
# Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-)
INIT_Y := $(patsubst %/, %/built-in.o, $(init-y))
diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
index d33f8a07ccac..54d51b404603 100644
--- a/arch/sparc/kernel/ioport.c
+++ b/arch/sparc/kernel/ioport.c
@@ -25,7 +25,6 @@
* <zaitcev> Sounds reasonable
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c
index 72f0201051a0..c8cb211b9072 100644
--- a/arch/sparc/kernel/irq.c
+++ b/arch/sparc/kernel/irq.c
@@ -46,6 +46,7 @@
#include <asm/pgtable.h>
#include <asm/pcic.h>
#include <asm/cacheflush.h>
+#include <asm/irq_regs.h>
#ifdef CONFIG_SMP
#define SMP_NOP2 "nop; nop;\n\t"
@@ -133,8 +134,8 @@ static void irq_panic(void)
prom_halt();
}
-void (*sparc_init_timers)(irqreturn_t (*)(int, void *,struct pt_regs *)) =
- (void (*)(irqreturn_t (*)(int, void *,struct pt_regs *))) irq_panic;
+void (*sparc_init_timers)(irq_handler_t ) =
+ (void (*)(irq_handler_t )) irq_panic;
/*
* Dave Redman (djhr@tadpole.co.uk)
@@ -319,12 +320,14 @@ void unexpected_irq(int irq, void *dev_id, struct pt_regs * regs)
void handler_irq(int irq, struct pt_regs * regs)
{
+ struct pt_regs *old_regs;
struct irqaction * action;
int cpu = smp_processor_id();
#ifdef CONFIG_SMP
extern void smp4m_irq_rotate(int cpu);
#endif
+ old_regs = set_irq_regs(regs);
irq_enter();
disable_pil_irq(irq);
#ifdef CONFIG_SMP
@@ -338,27 +341,31 @@ void handler_irq(int irq, struct pt_regs * regs)
do {
if (!action || !action->handler)
unexpected_irq(irq, NULL, regs);
- action->handler(irq, action->dev_id, regs);
+ action->handler(irq, action->dev_id);
action = action->next;
} while (action);
sparc_irq[irq].flags &= ~SPARC_IRQ_INPROGRESS;
enable_pil_irq(irq);
irq_exit();
+ set_irq_regs(old_regs);
}
#ifdef CONFIG_BLK_DEV_FD
-extern void floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern void floppy_interrupt(int irq, void *dev_id);
void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
int cpu = smp_processor_id();
+ old_regs = set_irq_regs(regs);
disable_pil_irq(irq);
irq_enter();
kstat_cpu(cpu).irqs[irq]++;
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
irq_exit();
enable_pil_irq(irq);
+ set_irq_regs(old_regs);
// XXX Eek, it's totally changed with preempt_count() and such
// if (softirq_pending(cpu))
// do_softirq();
@@ -369,7 +376,7 @@ void sparc_floppy_irq(int irq, void *dev_id, struct pt_regs *regs)
* thus no sharing possible.
*/
int request_fast_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ irq_handler_t handler,
unsigned long irqflags, const char *devname)
{
struct irqaction *action;
@@ -468,7 +475,7 @@ out:
}
int request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ irq_handler_t handler,
unsigned long irqflags, const char * devname, void *dev_id)
{
struct irqaction * action, **actionp;
@@ -478,7 +485,7 @@ int request_irq(unsigned int irq,
if (sparc_cpu_model == sun4d) {
extern int sun4d_request_irq(unsigned int,
- irqreturn_t (*)(int, void *, struct pt_regs *),
+ irq_handler_t ,
unsigned long, const char *, void *);
return sun4d_request_irq(irq, handler, irqflags, devname, dev_id);
}
diff --git a/arch/sparc/kernel/of_device.c b/arch/sparc/kernel/of_device.c
index 97bf87e8cdde..74bef2a2d37f 100644
--- a/arch/sparc/kernel/of_device.c
+++ b/arch/sparc/kernel/of_device.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c
index bfd31aac2df3..207f1b6eef53 100644
--- a/arch/sparc/kernel/pcic.c
+++ b/arch/sparc/kernel/pcic.c
@@ -34,6 +34,7 @@
#include <asm/pcic.h>
#include <asm/timer.h>
#include <asm/uaccess.h>
+#include <asm/irq_regs.h>
unsigned int pcic_pin_to_irq(unsigned int pin, char *name);
@@ -708,13 +709,13 @@ static void pcic_clear_clock_irq(void)
pcic_timer_dummy = readl(pcic0.pcic_regs+PCI_SYS_LIMIT);
}
-static irqreturn_t pcic_timer_handler (int irq, void *h, struct pt_regs *regs)
+static irqreturn_t pcic_timer_handler (int irq, void *h)
{
write_seqlock(&xtime_lock); /* Dummy, to show that we remember */
pcic_clear_clock_irq();
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
write_sequnlock(&xtime_lock);
return IRQ_HANDLED;
@@ -765,8 +766,6 @@ static __inline__ unsigned long do_gettimeoffset(void)
return count;
}
-extern unsigned long wall_jiffies;
-
static void pci_do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
@@ -775,26 +774,17 @@ static void pci_do_gettimeofday(struct timeval *tv)
unsigned long max_ntp_tick = tick_usec - tickadj;
do {
- unsigned long lost;
-
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = do_gettimeoffset();
- lost = jiffies - wall_jiffies;
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
- if (unlikely(time_adjust < 0)) {
+ if (unlikely(time_adjust < 0))
usec = min(usec, max_ntp_tick);
- if (lost)
- usec += lost * max_ntp_tick;
- }
- else if (unlikely(lost))
- usec += lost * tick_usec;
-
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / 1000);
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
@@ -819,8 +809,7 @@ static int pci_do_settimeofday(struct timespec *tv)
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
- tv->tv_nsec -= 1000 * (do_gettimeoffset() +
- (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ));
+ tv->tv_nsec -= 1000 * do_gettimeoffset();
while (tv->tv_nsec < 0) {
tv->tv_nsec += NSEC_PER_SEC;
tv->tv_sec--;
diff --git a/arch/sparc/kernel/prom.c b/arch/sparc/kernel/prom.c
index 4ca9e5fc97f4..2cc302b6bec0 100644
--- a/arch/sparc/kernel/prom.c
+++ b/arch/sparc/kernel/prom.c
@@ -243,7 +243,7 @@ int of_set_property(struct device_node *dp, const char *name, void *val, int len
void *old_val = prop->value;
int ret;
- ret = prom_setprop(dp->node, name, val, len);
+ ret = prom_setprop(dp->node, (char *) name, val, len);
err = -EINVAL;
if (ret >= 0) {
prop->value = new_val;
@@ -477,7 +477,10 @@ static struct property * __init build_one_prop(phandle node, char *prev, char *s
p->length = 0;
} else {
p->value = prom_early_alloc(p->length + 1);
- prom_getproperty(node, p->name, p->value, p->length);
+ len = prom_getproperty(node, p->name, p->value,
+ p->length);
+ if (len <= 0)
+ p->length = 0;
((unsigned char *)p->value)[p->length] = '\0';
}
}
diff --git a/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c
index 0251cab4708b..383526ad94fc 100644
--- a/arch/sparc/kernel/setup.c
+++ b/arch/sparc/kernel/setup.c
@@ -103,7 +103,6 @@ void prom_sync_me(void)
unsigned int boot_flags __initdata = 0;
#define BOOTME_DEBUG 0x1
-#define BOOTME_SINGLE 0x2
/* Exported for mm/init.c:paging_init. */
unsigned long cmdline_memory_size __initdata = 0;
@@ -121,16 +120,6 @@ static struct console prom_debug_console = {
.index = -1,
};
-int obp_system_intr(void)
-{
- if (boot_flags & BOOTME_DEBUG) {
- printk("OBP: system interrupted\n");
- prom_halt();
- return 1;
- }
- return 0;
-}
-
/*
* Process kernel command line switches that are specific to the
* SPARC or that require special low-level processing.
@@ -142,7 +131,6 @@ static void __init process_switch(char c)
boot_flags |= BOOTME_DEBUG;
break;
case 's':
- boot_flags |= BOOTME_SINGLE;
break;
case 'h':
prom_printf("boot_flags_init: Halt!\n");
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
index 4d441a554d35..33dadd9f2871 100644
--- a/arch/sparc/kernel/sparc_ksyms.c
+++ b/arch/sparc/kernel/sparc_ksyms.c
@@ -87,6 +87,7 @@ extern void ___set_bit(void);
extern void ___clear_bit(void);
extern void ___change_bit(void);
extern void ___rw_read_enter(void);
+extern void ___rw_read_try(void);
extern void ___rw_read_exit(void);
extern void ___rw_write_enter(void);
@@ -104,8 +105,9 @@ extern unsigned _Urem(unsigned, unsigned);
EXPORT_SYMBOL(sparc_cpu_model);
EXPORT_SYMBOL(kernel_thread);
#ifdef CONFIG_SMP
-// XXX find what uses (or used) these.
+// XXX find what uses (or used) these. AV: see asm/spinlock.h
EXPORT_SYMBOL(___rw_read_enter);
+EXPORT_SYMBOL(___rw_read_try);
EXPORT_SYMBOL(___rw_read_exit);
EXPORT_SYMBOL(___rw_write_enter);
#endif
diff --git a/arch/sparc/kernel/sun4c_irq.c b/arch/sparc/kernel/sun4c_irq.c
index 4be2c86ea540..009e891a4329 100644
--- a/arch/sparc/kernel/sun4c_irq.c
+++ b/arch/sparc/kernel/sun4c_irq.c
@@ -154,7 +154,7 @@ static void sun4c_load_profile_irq(int cpu, unsigned int limit)
/* Errm.. not sure how to do this.. */
}
-static void __init sun4c_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
+static void __init sun4c_init_timers(irq_handler_t counter_fn)
{
int irq;
diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c
index 74eed9775ac0..d4f9da8170c5 100644
--- a/arch/sparc/kernel/sun4d_irq.c
+++ b/arch/sparc/kernel/sun4d_irq.c
@@ -38,6 +38,7 @@
#include <asm/sbus.h>
#include <asm/sbi.h>
#include <asm/cacheflush.h>
+#include <asm/irq_regs.h>
/* If you trust current SCSI layer to handle different SCSI IRQs, enable this. I don't trust it... -jj */
/* #define DISTRIBUTE_IRQS */
@@ -198,6 +199,7 @@ extern void unexpected_irq(int, void *, struct pt_regs *);
void sun4d_handler_irq(int irq, struct pt_regs * regs)
{
+ struct pt_regs *old_regs;
struct irqaction * action;
int cpu = smp_processor_id();
/* SBUS IRQ level (1 - 7) */
@@ -208,6 +210,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
cc_set_iclr(1 << irq);
+ old_regs = set_irq_regs(regs);
irq_enter();
kstat_cpu(cpu).irqs[irq]++;
if (!sbusl) {
@@ -215,7 +218,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
if (!action)
unexpected_irq(irq, NULL, regs);
do {
- action->handler(irq, action->dev_id, regs);
+ action->handler(irq, action->dev_id);
action = action->next;
} while (action);
} else {
@@ -242,7 +245,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
if (!action)
unexpected_irq(irq, NULL, regs);
do {
- action->handler(irq, action->dev_id, regs);
+ action->handler(irq, action->dev_id);
action = action->next;
} while (action);
release_sbi(SBI2DEVID(sbino), slot);
@@ -250,6 +253,7 @@ void sun4d_handler_irq(int irq, struct pt_regs * regs)
}
}
irq_exit();
+ set_irq_regs(old_regs);
}
unsigned int sun4d_build_irq(struct sbus_dev *sdev, int irq)
@@ -272,7 +276,7 @@ unsigned int sun4d_sbint_to_irq(struct sbus_dev *sdev, unsigned int sbint)
}
int sun4d_request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ irq_handler_t handler,
unsigned long irqflags, const char * devname, void *dev_id)
{
struct irqaction *action, *tmp = NULL, **actionp;
@@ -466,7 +470,7 @@ static void sun4d_load_profile_irq(int cpu, unsigned int limit)
bw_set_prof_limit(cpu, limit);
}
-static void __init sun4d_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
+static void __init sun4d_init_timers(irq_handler_t counter_fn)
{
int irq;
int cpu;
diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c
index 3ff4edd32815..c80ea61e8ba0 100644
--- a/arch/sparc/kernel/sun4d_smp.c
+++ b/arch/sparc/kernel/sun4d_smp.c
@@ -23,6 +23,7 @@
#include <asm/ptrace.h>
#include <asm/atomic.h>
+#include <asm/irq_regs.h>
#include <asm/delay.h>
#include <asm/irq.h>
@@ -369,10 +370,12 @@ void smp4d_message_pass(int target, int msg, unsigned long data, int wait)
void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
int cpu = hard_smp4d_processor_id();
static int cpu_tick[NR_CPUS];
static char led_mask[] = { 0xe, 0xd, 0xb, 0x7, 0xb, 0xd };
+ old_regs = set_irq_regs(regs);
bw_get_prof_limit(cpu);
bw_clear_intr_mask(0, 1); /* INTR_TABLE[0] & 1 is Profile IRQ */
@@ -384,7 +387,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
show_leds(cpu);
}
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
if(!--prof_counter(cpu)) {
int user = user_mode(regs);
@@ -395,6 +398,7 @@ void smp4d_percpu_timer_interrupt(struct pt_regs *regs)
prof_counter(cpu) = prof_multiplier(cpu);
}
+ set_irq_regs(old_regs);
}
extern unsigned int lvl14_resolution;
diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c
index 7cefa301efea..a654c16f4027 100644
--- a/arch/sparc/kernel/sun4m_irq.c
+++ b/arch/sparc/kernel/sun4m_irq.c
@@ -228,7 +228,7 @@ static void sun4m_load_profile_irq(int cpu, unsigned int limit)
sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
}
-static void __init sun4m_init_timers(irqreturn_t (*counter_fn)(int, void *, struct pt_regs *))
+static void __init sun4m_init_timers(irq_handler_t counter_fn)
{
int reg_count, irq, cpu;
struct linux_prom_registers cnt_regs[PROMREG_MAX];
diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c
index 7d4a649138f6..e2d9c018bd56 100644
--- a/arch/sparc/kernel/sun4m_smp.c
+++ b/arch/sparc/kernel/sun4m_smp.c
@@ -19,6 +19,7 @@
#include <linux/profile.h>
#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
+#include <asm/irq_regs.h>
#include <asm/ptrace.h>
#include <asm/atomic.h>
@@ -353,11 +354,14 @@ void smp4m_cross_call_irq(void)
void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs;
int cpu = smp_processor_id();
+ old_regs = set_irq_regs(regs);
+
clear_profile_irq(cpu);
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
if(!--prof_counter(cpu)) {
int user = user_mode(regs);
@@ -368,6 +372,7 @@ void smp4m_percpu_timer_interrupt(struct pt_regs *regs)
prof_counter(cpu) = prof_multiplier(cpu);
}
+ set_irq_regs(old_regs);
}
extern unsigned int lvl14_resolution;
diff --git a/arch/sparc/kernel/sys_solaris.c b/arch/sparc/kernel/sys_solaris.c
index c09afd96dd9c..01b07bb440f0 100644
--- a/arch/sparc/kernel/sys_solaris.c
+++ b/arch/sparc/kernel/sys_solaris.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/sparc/sys_solaris.c
+ * linux/arch/sparc/kernel/sys_solaris.c
*
* Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
*/
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index 896863fb208a..a954a0c00000 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -24,6 +24,7 @@
#include <asm/uaccess.h>
#include <asm/ipc.h>
+#include <asm/unistd.h>
/* #define DEBUG_UNIMP_SYSCALL */
@@ -475,16 +476,38 @@ asmlinkage int sys_getdomainname(char __user *name, int len)
down_read(&uts_sem);
- nlen = strlen(system_utsname.domainname) + 1;
+ nlen = strlen(utsname()->domainname) + 1;
err = -EINVAL;
if (nlen > len)
goto out;
err = -EFAULT;
- if (!copy_to_user(name, system_utsname.domainname, nlen))
+ if (!copy_to_user(name, utsname()->domainname, nlen))
err = 0;
out:
up_read(&uts_sem);
return err;
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ long __res;
+ register long __g1 __asm__ ("g1") = __NR_execve;
+ register long __o0 __asm__ ("o0") = (long)(filename);
+ register long __o1 __asm__ ("o1") = (long)(argv);
+ register long __o2 __asm__ ("o2") = (long)(envp);
+ asm volatile ("t 0x10\n\t"
+ "bcc 1f\n\t"
+ "mov %%o0, %0\n\t"
+ "sub %%g0, %%o0, %0\n\t"
+ "1:\n\t"
+ : "=r" (__res), "=&r" (__o0)
+ : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
+ : "cc");
+ return __res;
+}
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index aa0fb2efb615..6f3ac548ee66 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -325,21 +325,25 @@ struct sunos_dirent_callback {
#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
static int sunos_filldir(void * __buf, const char * name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct sunos_dirent __user *dirent;
struct sunos_dirent_callback * buf = __buf;
+ unsigned long d_ino;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
if (dirent)
put_user(offset, &dirent->d_off);
dirent = buf->curr;
buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(namlen, &dirent->d_namlen);
put_user(reclen, &dirent->d_reclen);
copy_to_user(dirent->d_name, name, namlen);
@@ -406,19 +410,23 @@ struct sunos_direntry_callback {
};
static int sunos_filldirentry(void * __buf, const char * name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct sunos_direntry __user *dirent;
struct sunos_direntry_callback *buf = __buf;
+ unsigned long d_ino;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
dirent = buf->curr;
buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(namlen, &dirent->d_namlen);
put_user(reclen, &dirent->d_reclen);
copy_to_user(dirent->d_name, name, namlen);
@@ -483,13 +491,18 @@ asmlinkage int sunos_uname(struct sunos_utsname __user *name)
{
int ret;
down_read(&uts_sem);
- ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1);
+ ret = copy_to_user(&name->sname[0], &utsname()->sysname[0],
+ sizeof(name->sname) - 1);
if (!ret) {
- ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1);
+ ret |= __copy_to_user(&name->nname[0], &utsname()->nodename[0],
+ sizeof(name->nname) - 1);
ret |= __put_user('\0', &name->nname[8]);
- ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1);
- ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1);
- ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1);
+ ret |= __copy_to_user(&name->rel[0], &utsname()->release[0],
+ sizeof(name->rel) - 1);
+ ret |= __copy_to_user(&name->ver[0], &utsname()->version[0],
+ sizeof(name->ver) - 1);
+ ret |= __copy_to_user(&name->mach[0], &utsname()->machine[0],
+ sizeof(name->mach) - 1);
}
up_read(&uts_sem);
return ret ? -EFAULT : 0;
diff --git a/arch/sparc/kernel/tick14.c b/arch/sparc/kernel/tick14.c
index d3b4daac705f..f1a7bd19e04f 100644
--- a/arch/sparc/kernel/tick14.c
+++ b/arch/sparc/kernel/tick14.c
@@ -55,7 +55,7 @@ void install_obp_ticker(void)
linux_lvl14[3] = obp_lvl14[3];
}
-void claim_ticker14(irqreturn_t (*handler)(int, void *, struct pt_regs *),
+void claim_ticker14(irq_handler_t handler,
int irq_nr, unsigned int timeout )
{
int cpu = smp_processor_id();
diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c
index 845081b01267..6c7aa51b590f 100644
--- a/arch/sparc/kernel/time.c
+++ b/arch/sparc/kernel/time.c
@@ -42,8 +42,7 @@
#include <asm/page.h>
#include <asm/pcic.h>
#include <asm/of_device.h>
-
-extern unsigned long wall_jiffies;
+#include <asm/irq_regs.h>
DEFINE_SPINLOCK(rtc_lock);
enum sparc_clock_type sp_clock_typ;
@@ -96,6 +95,8 @@ unsigned long profile_pc(struct pt_regs *regs)
return pc;
}
+EXPORT_SYMBOL(profile_pc);
+
__volatile__ unsigned int *master_l10_counter;
__volatile__ unsigned int *master_l10_limit;
@@ -106,13 +107,13 @@ __volatile__ unsigned int *master_l10_limit;
#define TICK_SIZE (tick_nsec / 1000)
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
{
/* last time the cmos clock got updated */
static long last_rtc_update;
#ifndef CONFIG_SMP
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#endif
/* Protect counter clear so that do_gettimeoffset works */
@@ -128,9 +129,9 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#endif
clear_clock_irq();
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
@@ -449,7 +450,7 @@ unsigned long long sched_clock(void)
/* Ok, my cute asm atomicity trick doesn't work anymore.
* There are just too many variables that need to be protected
- * now (both members of xtime, wall_jiffies, et al.)
+ * now (both members of xtime, et al.)
*/
void do_gettimeofday(struct timeval *tv)
{
@@ -459,26 +460,17 @@ void do_gettimeofday(struct timeval *tv)
unsigned long max_ntp_tick = tick_usec - tickadj;
do {
- unsigned long lost;
-
seq = read_seqbegin_irqsave(&xtime_lock, flags);
usec = do_gettimeoffset();
- lost = jiffies - wall_jiffies;
/*
* If time_adjust is negative then NTP is slowing the clock
* so make sure not to go into next possible interval.
* Better to lose some accuracy than have time go backwards..
*/
- if (unlikely(time_adjust < 0)) {
+ if (unlikely(time_adjust < 0))
usec = min(usec, max_ntp_tick);
- if (lost)
- usec += lost * max_ntp_tick;
- }
- else if (unlikely(lost))
- usec += lost * tick_usec;
-
sec = xtime.tv_sec;
usec += (xtime.tv_nsec / 1000);
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
@@ -521,8 +513,7 @@ static int sbus_do_settimeofday(struct timespec *tv)
* wall time. Discover what correction gettimeofday() would have
* made, and then undo it!
*/
- nsec -= 1000 * (do_gettimeoffset() +
- (jiffies - wall_jiffies) * (USEC_PER_SEC / HZ));
+ nsec -= 1000 * do_gettimeoffset();
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 346c19a949fd..1dd78c84888a 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -36,11 +36,11 @@ SECTIONS
. = ALIGN(4096);
__init_begin = .;
+ _sinittext = .;
.init.text : {
- _sinittext = .;
*(.init.text)
- _einittext = .;
}
+ _einittext = .;
__init_text_end = .;
.init.data : { *(.init.data) }
. = ALIGN(16);
diff --git a/arch/sparc/lib/copy_user.S b/arch/sparc/lib/copy_user.S
index 577505b692ae..ef095b6c43b1 100644
--- a/arch/sparc/lib/copy_user.S
+++ b/arch/sparc/lib/copy_user.S
@@ -14,6 +14,7 @@
#include <asm/ptrace.h>
#include <asm/asmmacro.h>
#include <asm/page.h>
+#include <asm/thread_info.h>
/* Work around cpp -rob */
#define ALLOC #alloc
@@ -366,6 +367,9 @@ fixupretl:
blu 1f
cmp %o1, %g1
bgeu 1f
+ ld [%g6 + TI_PREEMPT], %g1
+ cmp %g1, 0
+ bne 1f
nop
save %sp, -64, %sp
mov %i0, %o0
diff --git a/arch/sparc/lib/locks.S b/arch/sparc/lib/locks.S
index 95fa48424967..b1df55cb2215 100644
--- a/arch/sparc/lib/locks.S
+++ b/arch/sparc/lib/locks.S
@@ -25,6 +25,15 @@ ___rw_read_enter_spin_on_wlock:
ldstub [%g1 + 3], %g2
b ___rw_read_enter_spin_on_wlock
ldub [%g1 + 3], %g2
+___rw_read_try_spin_on_wlock:
+ andcc %g2, 0xff, %g0
+ be,a ___rw_read_try
+ ldstub [%g1 + 3], %g2
+ xnorcc %g2, 0x0, %o0 /* if g2 is ~0, set o0 to 0 and bugger off */
+ bne,a ___rw_read_enter_spin_on_wlock
+ ld [%g1], %g2
+ retl
+ mov %g4, %o7
___rw_read_exit_spin_on_wlock:
orcc %g2, 0x0, %g0
be,a ___rw_read_exit
@@ -60,6 +69,17 @@ ___rw_read_exit:
retl
mov %g4, %o7
+ .globl ___rw_read_try
+___rw_read_try:
+ orcc %g2, 0x0, %g0
+ bne ___rw_read_try_spin_on_wlock
+ ld [%g1], %g2
+ add %g2, 1, %g2
+ st %g2, [%g1]
+ set 1, %o1
+ retl
+ mov %g4, %o7
+
.globl ___rw_write_enter
___rw_write_enter:
orcc %g2, 0x0, %g0
diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
index b27a506309ee..0df7121cef07 100644
--- a/arch/sparc/mm/srmmu.c
+++ b/arch/sparc/mm/srmmu.c
@@ -402,7 +402,7 @@ void srmmu_nocache_calcsize(void)
srmmu_nocache_end = SRMMU_NOCACHE_VADDR + srmmu_nocache_size;
}
-void srmmu_nocache_init(void)
+void __init srmmu_nocache_init(void)
{
unsigned int bitmap_bits;
pgd_t *pgd;
diff --git a/arch/sparc/oprofile/Kconfig b/arch/sparc/oprofile/Kconfig
new file mode 100644
index 000000000000..d8a84088471a
--- /dev/null
+++ b/arch/sparc/oprofile/Kconfig
@@ -0,0 +1,17 @@
+config PROFILING
+ bool "Profiling support (EXPERIMENTAL)"
+ help
+ Say Y here to enable the extended profiling support mechanisms used
+ by profilers such as OProfile.
+
+
+config OPROFILE
+ tristate "OProfile system profiling (EXPERIMENTAL)"
+ depends on PROFILING
+ help
+ OProfile is a profiling system capable of profiling the
+ whole system, include the kernel, kernel modules, libraries,
+ and applications.
+
+ If unsure, say N.
+
diff --git a/arch/sparc/oprofile/Makefile b/arch/sparc/oprofile/Makefile
new file mode 100644
index 000000000000..e9feca1ca28b
--- /dev/null
+++ b/arch/sparc/oprofile/Makefile
@@ -0,0 +1,9 @@
+obj-$(CONFIG_OPROFILE) += oprofile.o
+
+DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
+ oprof.o cpu_buffer.o buffer_sync.o \
+ event_buffer.o oprofile_files.o \
+ oprofilefs.o oprofile_stats.o \
+ timer_int.o )
+
+oprofile-y := $(DRIVER_OBJS) init.o
diff --git a/arch/sparc/oprofile/init.c b/arch/sparc/oprofile/init.c
new file mode 100644
index 000000000000..9ab815b95b5a
--- /dev/null
+++ b/arch/sparc/oprofile/init.c
@@ -0,0 +1,23 @@
+/**
+ * @file init.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/oprofile.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+
+int __init oprofile_arch_init(struct oprofile_operations * ops)
+{
+ return -ENODEV;
+}
+
+
+void oprofile_arch_exit(void)
+{
+}
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index 8d8ca716f7a7..b627f8dbcaad 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -420,7 +420,7 @@ source "arch/sparc64/oprofile/Kconfig"
config KPROBES
bool "Kprobes (EXPERIMENTAL)"
- depends on EXPERIMENTAL && MODULES
+ depends on KALLSYMS && EXPERIMENTAL && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 51cf6027b701..2f4612fa81f2 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18
-# Sat Sep 23 18:32:19 2006
+# Linux kernel version: 2.6.19-rc2
+# Tue Oct 17 19:29:20 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -35,17 +35,20 @@ CONFIG_LOCALVERSION=""
# CONFIG_LOCALVERSION_AUTO is not set
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
# CONFIG_IKCONFIG is not set
CONFIG_RELAY=y
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
CONFIG_UID16=y
-CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -77,6 +80,7 @@ CONFIG_KMOD=y
#
# Block layer
#
+CONFIG_BLOCK=y
CONFIG_BLK_DEV_IO_TRACE=y
#
@@ -141,6 +145,7 @@ CONFIG_SUN_AUXIO=y
CONFIG_SUN_IO=y
CONFIG_PCI=y
CONFIG_PCI_DOMAINS=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
CONFIG_SUN_OPENPROMFS=m
CONFIG_SPARC32_COMPAT=y
@@ -153,7 +158,7 @@ CONFIG_BINFMT_ELF32=y
#
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
-# CONFIG_SOLARIS_EMUL is not set
+CONFIG_SOLARIS_EMUL=y
# CONFIG_CMDLINE_BOOL is not set
#
@@ -192,23 +197,12 @@ CONFIG_INET_XFRM_TUNNEL=y
CONFIG_INET_TUNNEL=y
CONFIG_INET_XFRM_MODE_TRANSPORT=y
CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
-CONFIG_TCP_CONG_ADVANCED=y
-
-#
-# TCP congestion control
-#
-CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_CUBIC=m
-CONFIG_TCP_CONG_WESTWOOD=m
-CONFIG_TCP_CONG_HTCP=m
-CONFIG_TCP_CONG_HSTCP=m
-CONFIG_TCP_CONG_HYBLA=m
-CONFIG_TCP_CONG_VEGAS=m
-CONFIG_TCP_CONG_SCALABLE=m
-CONFIG_TCP_CONG_LP=m
-CONFIG_TCP_CONG_VENO=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
CONFIG_IPV6=m
CONFIG_IPV6_PRIVACY=y
CONFIG_IPV6_ROUTER_PREF=y
@@ -221,7 +215,9 @@ CONFIG_INET6_XFRM_TUNNEL=m
CONFIG_INET6_TUNNEL=m
CONFIG_INET6_XFRM_MODE_TRANSPORT=m
CONFIG_INET6_XFRM_MODE_TUNNEL=m
+CONFIG_INET6_XFRM_MODE_BEET=m
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=m
CONFIG_IPV6_TUNNEL=m
# CONFIG_IPV6_SUBTREES is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
@@ -247,6 +243,7 @@ CONFIG_IP_DCCP_TFRC_LIB=m
# DCCP Kernel Hacking
#
# CONFIG_IP_DCCP_DEBUG is not set
+# CONFIG_NET_DCCPPROBE is not set
#
# SCTP Configuration (EXPERIMENTAL)
@@ -338,6 +335,12 @@ CONFIG_CDROM_PKTCDVD_WCACHE=y
CONFIG_ATA_OVER_ETH=m
#
+# Misc devices
+#
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -379,6 +382,7 @@ CONFIG_BLK_DEV_ALI15X3=y
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
# CONFIG_BLK_DEV_IT821X is not set
@@ -401,6 +405,7 @@ CONFIG_IDEDMA_AUTO=y
#
CONFIG_RAID_ATTRS=m
CONFIG_SCSI=y
+CONFIG_SCSI_NETLINK=y
CONFIG_SCSI_PROC_FS=y
#
@@ -422,12 +427,13 @@ CONFIG_SCSI_CONSTANTS=y
# CONFIG_SCSI_LOGGING is not set
#
-# SCSI Transport Attributes
+# SCSI Transports
#
CONFIG_SCSI_SPI_ATTRS=y
CONFIG_SCSI_FC_ATTRS=y
CONFIG_SCSI_ISCSI_ATTRS=m
# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
#
# SCSI low-level drivers
@@ -440,21 +446,23 @@ CONFIG_ISCSI_TCP=m
# CONFIG_SCSI_AIC7XXX is not set
# CONFIG_SCSI_AIC7XXX_OLD is not set
# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_ARCMSR is not set
# CONFIG_MEGARAID_NEWGEN is not set
# CONFIG_MEGARAID_LEGACY is not set
# CONFIG_MEGARAID_SAS is not set
-# CONFIG_SCSI_SATA is not set
# CONFIG_SCSI_HPTIOP is not set
# CONFIG_SCSI_DMX3191D is not set
# CONFIG_SCSI_FUTURE_DOMAIN is not set
# CONFIG_SCSI_IPS is not set
# CONFIG_SCSI_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_STEX is not set
# CONFIG_SCSI_SYM53C8XX_2 is not set
-# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLOGICPTI is not set
# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
@@ -462,6 +470,11 @@ CONFIG_ISCSI_TCP=m
# CONFIG_SCSI_SUNESP is not set
#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
# Multi-device support (RAID and LVM)
#
CONFIG_MD=y
@@ -475,6 +488,7 @@ CONFIG_MD_RAID456=m
CONFIG_MD_MULTIPATH=m
# CONFIG_MD_FAULTY is not set
CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
CONFIG_DM_CRYPT=m
CONFIG_DM_SNAPSHOT=m
CONFIG_DM_MIRROR=m
@@ -575,6 +589,7 @@ CONFIG_E1000_NAPI=y
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=m
CONFIG_BNX2=m
+# CONFIG_QLA3XXX is not set
#
# Ethernet (10000 Mbit)
@@ -622,6 +637,7 @@ CONFIG_BNX2=m
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -644,6 +660,7 @@ CONFIG_KEYBOARD_SUNKBD=y
CONFIG_KEYBOARD_LKKBD=m
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
CONFIG_MOUSE_SERIAL=y
@@ -718,7 +735,6 @@ CONFIG_RTC=y
# TPM devices
#
# CONFIG_TCG_TPM is not set
-# CONFIG_TELCLOCK is not set
#
# I2C support
@@ -821,6 +837,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47M192 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
@@ -831,14 +848,9 @@ CONFIG_HWMON=y
# CONFIG_HWMON_DEBUG_CHIP is not set
#
-# Misc devices
-#
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -851,6 +863,7 @@ CONFIG_VIDEO_V4L2=y
#
# CONFIG_FIRMWARE_EDID is not set
CONFIG_FB=y
+CONFIG_FB_DDC=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
@@ -1006,6 +1019,7 @@ CONFIG_SND_ALI5451=m
# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VX222 is not set
# CONFIG_SND_YMFPCI is not set
+# CONFIG_SND_AC97_POWER_SAVE is not set
#
# USB devices
@@ -1122,6 +1136,7 @@ CONFIG_USB_HIDDEV=y
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
@@ -1129,12 +1144,13 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1219,6 +1235,7 @@ CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
@@ -1226,6 +1243,7 @@ CONFIG_FS_MBCACHE=y
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -1255,8 +1273,10 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
@@ -1267,6 +1287,7 @@ CONFIG_RAMFS=y
#
# CONFIG_ADFS_FS is not set
# CONFIG_AFFS_FS is not set
+# CONFIG_ECRYPT_FS is not set
# CONFIG_HFS_FS is not set
# CONFIG_HFSPLUS_FS is not set
# CONFIG_BEFS_FS is not set
@@ -1353,6 +1374,7 @@ CONFIG_KPROBES=y
# Kernel hacking
#
CONFIG_PRINTK_TIME=y
+CONFIG_ENABLE_MUST_CHECK=y
CONFIG_MAGIC_SYSRQ=y
# CONFIG_UNUSED_SYMBOLS is not set
CONFIG_DEBUG_KERNEL=y
@@ -1372,9 +1394,12 @@ CONFIG_DEBUG_BUGVERBOSE=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
# CONFIG_UNWIND_INFO is not set
CONFIG_FORCED_INLINING=y
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
# CONFIG_DEBUG_STACK_USAGE is not set
# CONFIG_DEBUG_DCFLUSH is not set
# CONFIG_STACK_DEBUG is not set
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index 718350aba1ec..826118ee53d5 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -5,7 +5,6 @@
* Refactoring for unified NCR/PCIO support 2002 Eric Brower (ebrower@usa.net)
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/arch/sparc64/kernel/ebus.c b/arch/sparc64/kernel/ebus.c
index 8a9b470e1b65..2df25c2b4071 100644
--- a/arch/sparc64/kernel/ebus.c
+++ b/arch/sparc64/kernel/ebus.c
@@ -79,7 +79,7 @@ static void __ebus_dma_reset(struct ebus_dma_info *p, int no_drain)
}
}
-static irqreturn_t ebus_dma_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ebus_dma_irq(int irq, void *dev_id)
{
struct ebus_dma_info *p = dev_id;
unsigned long flags;
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 4e64724cb9ae..d64b1ea848de 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -522,12 +522,13 @@ void ack_bad_irq(unsigned int virt_irq)
}
#ifndef CONFIG_SMP
-extern irqreturn_t timer_interrupt(int, void *, struct pt_regs *);
+extern irqreturn_t timer_interrupt(int, void *);
void timer_irq(int irq, struct pt_regs *regs)
{
unsigned long clr_mask = 1 << irq;
unsigned long tick_mask = tick_ops->softint_mask;
+ struct pt_regs *old_regs;
if (get_softint() & tick_mask) {
irq = 0;
@@ -535,21 +536,25 @@ void timer_irq(int irq, struct pt_regs *regs)
}
clear_softint(clr_mask);
+ old_regs = set_irq_regs(regs);
irq_enter();
kstat_this_cpu.irqs[0]++;
- timer_interrupt(irq, NULL, regs);
+ timer_interrupt(irq, NULL);
irq_exit();
+ set_irq_regs(old_regs);
}
#endif
void handler_irq(int irq, struct pt_regs *regs)
{
struct ino_bucket *bucket;
+ struct pt_regs *old_regs;
clear_softint(1 << irq);
+ old_regs = set_irq_regs(regs);
irq_enter();
/* Sliiiick... */
@@ -558,12 +563,13 @@ void handler_irq(int irq, struct pt_regs *regs)
struct ino_bucket *next = __bucket(bucket->irq_chain);
bucket->irq_chain = 0;
- __do_IRQ(bucket->virt_irq, regs);
+ __do_IRQ(bucket->virt_irq);
bucket = next;
}
irq_exit();
+ set_irq_regs(old_regs);
}
struct sun5_timer {
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c
index 238bbf6de07d..d3dfb2a36d47 100644
--- a/arch/sparc64/kernel/of_device.c
+++ b/arch/sparc64/kernel/of_device.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/init.h>
@@ -132,8 +131,13 @@ static int of_device_resume(struct device * dev)
void __iomem *of_ioremap(struct resource *res, unsigned long offset, unsigned long size, char *name)
{
unsigned long ret = res->start + offset;
+ struct resource *r;
- if (!request_region(ret, size, name))
+ if (res->flags & IORESOURCE_MEM)
+ r = request_mem_region(ret, size, name);
+ else
+ r = request_region(ret, size, name);
+ if (!r)
ret = 0;
return (void __iomem *) ret;
@@ -842,7 +846,7 @@ static struct of_device * __init scan_one_device(struct device_node *dp,
if (!parent)
strcpy(op->dev.bus_id, "root");
else
- strcpy(op->dev.bus_id, dp->path_component_name);
+ sprintf(op->dev.bus_id, "%s@%08x", dp->name, dp->node);
if (of_device_register(op)) {
printk("%s: Could not register of device.\n",
diff --git a/arch/sparc64/kernel/pci_common.c b/arch/sparc64/kernel/pci_common.c
index 7a59cc72c844..827ae30aa497 100644
--- a/arch/sparc64/kernel/pci_common.c
+++ b/arch/sparc64/kernel/pci_common.c
@@ -330,19 +330,6 @@ __init get_device_resource(struct linux_prom_pci_registers *ap,
return res;
}
-static int __init pdev_resource_collisions_expected(struct pci_dev *pdev)
-{
- if (pdev->vendor != PCI_VENDOR_ID_SUN)
- return 0;
-
- if (pdev->device == PCI_DEVICE_ID_SUN_RIO_EBUS ||
- pdev->device == PCI_DEVICE_ID_SUN_RIO_1394 ||
- pdev->device == PCI_DEVICE_ID_SUN_RIO_USB)
- return 1;
-
- return 0;
-}
-
static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
struct pci_dev *pdev)
{
@@ -400,19 +387,23 @@ static void __init pdev_record_assignments(struct pci_pbm_info *pbm,
pbm->parent->resource_adjust(pdev, res, root);
if (request_resource(root, res) < 0) {
+ int rnum;
+
/* OK, there is some conflict. But this is fine
* since we'll reassign it in the fixup pass.
*
- * We notify the user that OBP made an error if it
- * is a case we don't expect.
+ * Do not print the warning for ROM resources
+ * as such a conflict is quite common and
+ * harmless as the ROM bar is disabled.
*/
- if (!pdev_resource_collisions_expected(pdev)) {
- printk(KERN_ERR "PCI: Address space collision on region %ld "
+ rnum = (res - &pdev->resource[0]);
+ if (rnum != PCI_ROM_RESOURCE)
+ printk(KERN_ERR "PCI: Resource collision, "
+ "region %d "
"[%016lx:%016lx] of device %s\n",
- (res - &pdev->resource[0]),
+ rnum,
res->start, res->end,
pci_name(pdev));
- }
}
}
}
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 1ec0aab68c08..fda5db223d96 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -533,7 +533,7 @@ static void psycho_check_iommu_error(struct pci_controller_info *p,
#define PSYCHO_UEAFSR_RESV2 0x00000000007fffffUL /* Reserved */
#define PSYCHO_UE_AFAR 0x0038UL
-static irqreturn_t psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
+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;
@@ -610,7 +610,7 @@ static irqreturn_t psycho_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
#define PSYCHO_CEAFSR_RESV2 0x00000000007fffffUL /* Reserved */
#define PSYCHO_CE_AFAR 0x0040UL
-static irqreturn_t psycho_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
+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;
@@ -735,7 +735,7 @@ static irqreturn_t psycho_pcierr_intr_other(struct pci_pbm_info *pbm, int is_pbm
return ret;
}
-static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t psycho_pcierr_intr(int irq, void *dev_id)
{
struct pci_pbm_info *pbm = dev_id;
struct pci_controller_info *p = pbm->parent;
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 45891850b90d..94bb681f2323 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -574,7 +574,7 @@ static void sabre_check_iommu_error(struct pci_controller_info *p,
spin_unlock_irqrestore(&iommu->lock, flags);
}
-static irqreturn_t sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
+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;
@@ -634,7 +634,7 @@ static irqreturn_t sabre_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t sabre_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
+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;
@@ -726,7 +726,7 @@ static irqreturn_t sabre_pcierr_intr_other(struct pci_controller_info *p)
return ret;
}
-static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sabre_pcierr_intr(int irq, void *dev_id)
{
struct pci_controller_info *p = dev_id;
unsigned long afsr_reg, afar_reg;
@@ -1196,7 +1196,7 @@ static void pbm_register_toplevel_resources(struct pci_controller_info *p,
&pbm->mem_space);
}
-static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_begin)
+static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp, u32 dma_start, u32 dma_end)
{
struct pci_pbm_info *pbm;
struct device_node *node;
@@ -1261,6 +1261,8 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
node = node->sibling;
}
if (simbas_found == 0) {
+ struct resource *rp;
+
/* No APBs underneath, probably this is a hummingbird
* system.
*/
@@ -1302,8 +1304,10 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
pbm->io_space.end = pbm->io_space.start + (1UL << 24) - 1UL;
pbm->io_space.flags = IORESOURCE_IO;
- pbm->mem_space.start = p->pbm_A.controller_regs + SABRE_MEMSPACE;
- pbm->mem_space.end = pbm->mem_space.start + (unsigned long)dma_begin - 1UL;
+ pbm->mem_space.start =
+ (p->pbm_A.controller_regs + SABRE_MEMSPACE);
+ pbm->mem_space.end =
+ (pbm->mem_space.start + ((1UL << 32UL) - 1UL));
pbm->mem_space.flags = IORESOURCE_MEM;
if (request_resource(&ioport_resource, &pbm->io_space) < 0) {
@@ -1315,6 +1319,17 @@ static void sabre_pbm_init(struct pci_controller_info *p, struct device_node *dp
prom_halt();
}
+ rp = kmalloc(sizeof(*rp), GFP_KERNEL);
+ if (!rp) {
+ prom_printf("Cannot allocate IOMMU resource.\n");
+ prom_halt();
+ }
+ rp->name = "IOMMU";
+ rp->start = pbm->mem_space.start + (unsigned long) dma_start;
+ rp->end = pbm->mem_space.start + (unsigned long) dma_end - 1UL;
+ rp->flags = IORESOURCE_BUSY;
+ request_resource(&pbm->mem_space, rp);
+
pci_register_legacy_regions(&pbm->io_space,
&pbm->mem_space);
}
@@ -1450,5 +1465,5 @@ void sabre_init(struct device_node *dp, char *model_name)
/*
* Look for APB underneath.
*/
- sabre_pbm_init(p, dp, vdma[0]);
+ sabre_pbm_init(p, dp, vdma[0], vdma[0] + vdma[1]);
}
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 75ade83ecc65..66911b126aed 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -515,7 +515,7 @@ static void schizo_check_iommu_error(struct pci_controller_info *p,
#define SCHIZO_UEAFSR_MTAG 0x000000000000e000UL /* Safari */
#define SCHIZO_UEAFSR_ECCSYND 0x00000000000001ffUL /* Safari */
-static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
+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;
@@ -603,7 +603,7 @@ static irqreturn_t schizo_ue_intr(int irq, void *dev_id, struct pt_regs *regs)
#define SCHIZO_CEAFSR_MTAG 0x000000000000e000UL
#define SCHIZO_CEAFSR_ECCSYND 0x00000000000001ffUL
-static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
+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;
@@ -778,7 +778,7 @@ static irqreturn_t schizo_pcierr_intr_other(struct pci_pbm_info *pbm)
return ret;
}
-static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id)
{
struct pci_pbm_info *pbm = dev_id;
struct pci_controller_info *p = pbm->parent;
@@ -933,7 +933,7 @@ static irqreturn_t schizo_pcierr_intr(int irq, void *dev_id, struct pt_regs *reg
/* We only expect UNMAP errors here. The rest of the Safari errors
* are marked fatal and thus cause a system reset.
*/
-static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t schizo_safarierr_intr(int irq, void *dev_id)
{
struct pci_controller_info *p = dev_id;
u64 errlog;
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index e55466c77b61..699b24b890df 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -4,8 +4,6 @@
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
-#define __KERNEL_SYSCALLS__
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -14,6 +12,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/pm.h>
+#include <linux/syscalls.h>
#include <asm/system.h>
#include <asm/auxio.h>
@@ -36,7 +35,7 @@ static void __iomem *power_reg;
static DECLARE_WAIT_QUEUE_HEAD(powerd_wait);
static int button_pressed;
-static irqreturn_t power_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t power_handler(int irq, void *dev_id)
{
if (button_pressed == 0) {
button_pressed = 1;
@@ -98,7 +97,7 @@ again:
/* Ok, down we go... */
button_pressed = 0;
- if (execve("/sbin/shutdown", argv, envp) < 0) {
+ if (kernel_execve("/sbin/shutdown", argv, envp) < 0) {
printk("powerd: shutdown execution failed\n");
add_wait_queue(&powerd_wait, &wait);
goto again;
diff --git a/arch/sparc64/kernel/prom.c b/arch/sparc64/kernel/prom.c
index 5cc5ab63293f..e21cd6afa709 100644
--- a/arch/sparc64/kernel/prom.c
+++ b/arch/sparc64/kernel/prom.c
@@ -15,7 +15,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/string.h>
diff --git a/arch/sparc64/kernel/sbus.c b/arch/sparc64/kernel/sbus.c
index c49a57795743..01d6d869ea2b 100644
--- a/arch/sparc64/kernel/sbus.c
+++ b/arch/sparc64/kernel/sbus.c
@@ -839,7 +839,7 @@ unsigned int sbus_build_irq(void *buscookie, unsigned int ino)
#define SYSIO_UEAFSR_SIZE 0x00001c0000000000UL /* Bad transfer size 2^SIZE */
#define SYSIO_UEAFSR_MID 0x000003e000000000UL /* UPA MID causing the fault */
#define SYSIO_UEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
-static irqreturn_t sysio_ue_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sysio_ue_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
struct sbus_iommu *iommu = sbus->iommu;
@@ -911,7 +911,7 @@ static irqreturn_t sysio_ue_handler(int irq, void *dev_id, struct pt_regs *regs)
#define SYSIO_CEAFSR_SIZE 0x00001c0000000000UL /* Bad transfer size 2^SIZE */
#define SYSIO_CEAFSR_MID 0x000003e000000000UL /* UPA MID causing the fault */
#define SYSIO_CEAFSR_RESV2 0x0000001fffffffffUL /* Reserved */
-static irqreturn_t sysio_ce_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sysio_ce_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
struct sbus_iommu *iommu = sbus->iommu;
@@ -988,7 +988,7 @@ static irqreturn_t sysio_ce_handler(int irq, void *dev_id, struct pt_regs *regs)
#define SYSIO_SBAFSR_SIZE 0x00001c0000000000UL /* Size of transfer */
#define SYSIO_SBAFSR_MID 0x000003e000000000UL /* MID causing the error */
#define SYSIO_SBAFSR_RESV3 0x0000001fffffffffUL /* Reserved */
-static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sysio_sbus_error_handler(int irq, void *dev_id)
{
struct sbus_bus *sbus = dev_id;
struct sbus_iommu *iommu = sbus->iommu;
diff --git a/arch/sparc64/kernel/setup.c b/arch/sparc64/kernel/setup.c
index 958287448cfe..bf033b31d437 100644
--- a/arch/sparc64/kernel/setup.c
+++ b/arch/sparc64/kernel/setup.c
@@ -74,7 +74,6 @@ prom_console_write(struct console *con, const char *s, unsigned n)
unsigned int boot_flags = 0;
#define BOOTME_DEBUG 0x1
-#define BOOTME_SINGLE 0x2
/* Exported for mm/init.c:paging_init. */
unsigned long cmdline_memory_size = 0;
@@ -91,16 +90,6 @@ void kernel_enter_debugger(void)
{
}
-int obp_system_intr(void)
-{
- if (boot_flags & BOOTME_DEBUG) {
- printk("OBP: system interrupted\n");
- prom_halt();
- return 1;
- }
- return 0;
-}
-
/*
* Process kernel command line switches that are specific to the
* SPARC or that require special low-level processing.
@@ -112,7 +101,6 @@ static void __init process_switch(char c)
boot_flags |= BOOTME_DEBUG;
break;
case 's':
- boot_flags |= BOOTME_SINGLE;
break;
case 'h':
prom_printf("boot_flags_init: Halt!\n");
diff --git a/arch/sparc64/kernel/signal32.c b/arch/sparc64/kernel/signal32.c
index 708ba9b42cda..c45f21b881d5 100644
--- a/arch/sparc64/kernel/signal32.c
+++ b/arch/sparc64/kernel/signal32.c
@@ -29,6 +29,7 @@
#include <asm/psrcompat.h>
#include <asm/fpumacro.h>
#include <asm/visasm.h>
+#include <asm/compat_signal.h>
#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index f62bf3a2de1a..cc09d8266414 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -31,6 +31,7 @@
#include <asm/cpudata.h>
#include <asm/irq.h>
+#include <asm/irq_regs.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/oplib.h>
@@ -1187,6 +1188,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
unsigned long compare, tick, pstate;
int cpu = smp_processor_id();
int user = user_mode(regs);
+ struct pt_regs *old_regs;
/*
* Check for level 14 softint.
@@ -1203,8 +1205,9 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
clear_softint(tick_mask);
}
+ old_regs = set_irq_regs(regs);
do {
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
if (!--prof_counter(cpu)) {
irq_enter();
@@ -1236,6 +1239,7 @@ void smp_percpu_timer_interrupt(struct pt_regs *regs)
: /* no outputs */
: "r" (pstate));
} while (time_after_eq(tick, compare));
+ set_irq_regs(old_regs);
}
static void __init smp_setup_percpu_timer(void)
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index c608c947e6c3..a53d4abb4b49 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -31,6 +31,7 @@
#include <asm/utrap.h>
#include <asm/perfctr.h>
#include <asm/a.out.h>
+#include <asm/unistd.h>
/* #define DEBUG_UNIMP_SYSCALL */
@@ -712,13 +713,13 @@ asmlinkage long sys_getdomainname(char __user *name, int len)
down_read(&uts_sem);
- nlen = strlen(system_utsname.domainname) + 1;
+ nlen = strlen(utsname()->domainname) + 1;
err = -EINVAL;
if (nlen > len)
goto out;
err = -EFAULT;
- if (!copy_to_user(name, system_utsname.domainname, nlen))
+ if (!copy_to_user(name, utsname()->domainname, nlen))
err = 0;
out:
@@ -963,3 +964,23 @@ asmlinkage long sys_perfctr(int opcode, unsigned long arg0, unsigned long arg1,
};
return err;
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ long __res;
+ register long __g1 __asm__ ("g1") = __NR_execve;
+ register long __o0 __asm__ ("o0") = (long)(filename);
+ register long __o1 __asm__ ("o1") = (long)(argv);
+ register long __o2 __asm__ ("o2") = (long)(envp);
+ asm volatile ("t 0x6d\n\t"
+ "sub %%g0, %%o0, %0\n\t"
+ "movcc %%xcc, %%o0, %0\n\t"
+ : "=r" (__res), "=&r" (__o0)
+ : "1" (__o0), "r" (__o1), "r" (__o2), "r" (__g1)
+ : "cc");
+ return __res;
+}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index c88ae23ce812..e27cb71bd8e2 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -61,6 +61,7 @@
#include <asm/semaphore.h>
#include <asm/mmu_context.h>
#include <asm/a.out.h>
+#include <asm/compat_signal.h>
asmlinkage long sys32_chown16(const char __user * filename, u16 user, u16 group)
{
@@ -337,12 +338,17 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
{
+ compat_ino_t ino;
int err;
if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
!old_valid_dev(stat->rdev))
return -EOVERFLOW;
+ ino = stat->ino;
+ if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+ return -EOVERFLOW;
+
err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
err |= put_user(stat->ino, &statbuf->st_ino);
err |= put_user(stat->mode, &statbuf->st_mode);
@@ -1016,7 +1022,7 @@ struct __sysctl_args32 {
asmlinkage long sys32_sysctl(struct __sysctl_args32 __user *args)
{
-#ifndef CONFIG_SYSCTL
+#ifndef CONFIG_SYSCTL_SYSCALL
return -ENOSYS;
#else
struct __sysctl_args32 tmp;
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 87ebdf858a3a..7da72d3b322a 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -43,6 +43,7 @@
#include <asm/idprom.h> /* for gethostid() */
#include <asm/unistd.h>
#include <asm/system.h>
+#include <asm/compat_signal.h>
/* For the nfs mount emulation */
#include <linux/socket.h>
@@ -280,16 +281,20 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
struct sunos_dirent __user *dirent;
struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+ u32 d_ino;
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
if (dirent)
put_user(offset, &dirent->d_off);
dirent = buf->curr;
buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(namlen, &dirent->d_namlen);
put_user(reclen, &dirent->d_reclen);
if (copy_to_user(dirent->d_name, name, namlen))
@@ -363,14 +368,18 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
struct sunos_direntry_callback * buf =
(struct sunos_direntry_callback *) __buf;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
+ u32 d_ino;
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
dirent = buf->curr;
buf->previous = dirent;
- put_user(ino, &dirent->d_ino);
+ put_user(d_ino, &dirent->d_ino);
put_user(namlen, &dirent->d_namlen);
put_user(reclen, &dirent->d_reclen);
if (copy_to_user(dirent->d_name, name, namlen))
@@ -439,16 +448,16 @@ asmlinkage int sunos_uname(struct sunos_utsname __user *name)
int ret;
down_read(&uts_sem);
- ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0],
+ ret = copy_to_user(&name->sname[0], &utsname()->sysname[0],
sizeof(name->sname) - 1);
- ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0],
+ ret |= copy_to_user(&name->nname[0], &utsname()->nodename[0],
sizeof(name->nname) - 1);
ret |= put_user('\0', &name->nname[8]);
- ret |= copy_to_user(&name->rel[0], &system_utsname.release[0],
+ ret |= copy_to_user(&name->rel[0], &utsname()->release[0],
sizeof(name->rel) - 1);
- ret |= copy_to_user(&name->ver[0], &system_utsname.version[0],
+ ret |= copy_to_user(&name->ver[0], &utsname()->version[0],
sizeof(name->ver) - 1);
- ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0],
+ ret |= copy_to_user(&name->mach[0], &utsname()->machine[0],
sizeof(name->mach) - 1);
up_read(&uts_sem);
return (ret ? -EFAULT : 0);
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index b0b4feeec098..061e1b1fa583 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -45,6 +45,7 @@
#include <asm/cpudata.h>
#include <asm/uaccess.h>
#include <asm/prom.h>
+#include <asm/irq_regs.h>
DEFINE_SPINLOCK(mostek_lock);
DEFINE_SPINLOCK(rtc_lock);
@@ -53,8 +54,6 @@ void __iomem *mstk48t02_regs = NULL;
unsigned long ds1287_regs = 0UL;
#endif
-extern unsigned long wall_jiffies;
-
static void __iomem *mstk48t08_regs;
static void __iomem *mstk48t59_regs;
@@ -454,7 +453,7 @@ static inline void timer_check_rtc(void)
}
}
-irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t timer_interrupt(int irq, void *dev_id)
{
unsigned long ticks, compare, pstate;
@@ -462,10 +461,10 @@ irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
do {
#ifndef CONFIG_SMP
- profile_tick(CPU_PROFILING, regs);
- update_process_times(user_mode(regs));
+ profile_tick(CPU_PROFILING);
+ update_process_times(user_mode(get_irq_regs()));
#endif
- do_timer(regs);
+ do_timer(1);
/* Guarantee that the following sequences execute
* uninterrupted.
@@ -496,7 +495,7 @@ void timer_tick_interrupt(struct pt_regs *regs)
{
write_seqlock(&xtime_lock);
- do_timer(regs);
+ do_timer(1);
timer_check_rtc();
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index dcba4e6ab570..09cb7fccc03a 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -920,8 +920,7 @@ static unsigned long __init bootmem_init(unsigned long *pages_avail,
if (sparc_ramdisk_image || sparc_ramdisk_image64) {
unsigned long ramdisk_image = sparc_ramdisk_image ?
sparc_ramdisk_image : sparc_ramdisk_image64;
- if (ramdisk_image >= (unsigned long)_end - 2 * PAGE_SIZE)
- ramdisk_image -= KERNBASE;
+ ramdisk_image -= KERNBASE;
initrd_start = ramdisk_image + phys_base;
initrd_end = initrd_start + sparc_ramdisk_size;
if (initrd_end > end_of_phys_memory) {
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 0f0eb6aa1c40..12a940cc791f 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -82,12 +82,17 @@ struct sol_stat64 {
static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf)
{
+ u32 ino;
+
if (kbuf->size > MAX_NON_LFS ||
!sysv_valid_dev(kbuf->dev) ||
!sysv_valid_dev(kbuf->rdev))
return -EOVERFLOW;
+ ino = kbuf->ino;
+ if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
+ return -EOVERFLOW;
if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev) ||
- __put_user (kbuf->ino, &ubuf->st_ino) ||
+ __put_user (ino, &ubuf->st_ino) ||
__put_user (kbuf->mode, &ubuf->st_mode) ||
__put_user (kbuf->nlink, &ubuf->st_nlink) ||
__put_user (kbuf->uid, &ubuf->st_uid) ||
diff --git a/arch/sparc64/solaris/misc.c b/arch/sparc64/solaris/misc.c
index 642541769a17..9ed997982f8d 100644
--- a/arch/sparc64/solaris/misc.c
+++ b/arch/sparc64/solaris/misc.c
@@ -11,6 +11,7 @@
#include <linux/limits.h>
#include <linux/mm.h>
#include <linux/smp.h>
+#include <linux/tty.h>
#include <linux/mman.h>
#include <linux/file.h>
#include <linux/timex.h>
@@ -248,7 +249,7 @@ asmlinkage int solaris_utssys(u32 buf, u32 flags, int which, u32 buf2)
/* Let's cheat */
err = set_utsfield(v->sysname, "SunOS", 1, 0);
down_read(&uts_sem);
- err |= set_utsfield(v->nodename, system_utsname.nodename,
+ err |= set_utsfield(v->nodename, utsname()->nodename,
1, 1);
up_read(&uts_sem);
err |= set_utsfield(v->release, "2.6", 0, 0);
@@ -272,7 +273,7 @@ asmlinkage int solaris_utsname(u32 buf)
/* Why should we not lie a bit? */
down_read(&uts_sem);
err = set_utsfield(v->sysname, "SunOS", 0, 0);
- err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1);
+ err |= set_utsfield(v->nodename, utsname()->nodename, 1, 1);
err |= set_utsfield(v->release, "5.6", 0, 0);
err |= set_utsfield(v->version, "Generic", 0, 0);
err |= set_utsfield(v->machine, machine(), 0, 0);
@@ -304,7 +305,7 @@ asmlinkage int solaris_sysinfo(int cmd, u32 buf, s32 count)
case SI_HOSTNAME:
r = buffer + 256;
down_read(&uts_sem);
- for (p = system_utsname.nodename, q = buffer;
+ for (p = utsname()->nodename, q = buffer;
q < r && *p && *p != '.'; *q++ = *p++);
up_read(&uts_sem);
*q = 0;
@@ -422,7 +423,9 @@ asmlinkage int solaris_procids(int cmd, s32 pid, s32 pgid)
Solaris setpgrp and setsid? */
ret = sys_setpgid(0, 0);
if (ret) return ret;
+ mutex_lock(&tty_mutex);
current->signal->tty = NULL;
+ mutex_unlock(&tty_mutex);
return process_group(current);
}
case 2: /* getsid */
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 76e85bbaea55..5ac1f2963ae3 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -1,3 +1,8 @@
+config DEFCONFIG_LIST
+ string
+ option defconfig_list
+ default "arch/$ARCH/defconfig"
+
# UML uses the generic IRQ sugsystem
config GENERIC_HARDIRQS
bool
@@ -25,6 +30,19 @@ config PCI
config PCMCIA
bool
+# Yet to do!
+config TRACE_IRQFLAGS_SUPPORT
+ bool
+ default n
+
+config LOCKDEP_SUPPORT
+ bool
+ default y
+
+config STACKTRACE_SUPPORT
+ bool
+ default y
+
config GENERIC_CALIBRATE_DELAY
bool
default y
@@ -37,13 +55,16 @@ config IRQ_RELEASE_METHOD
menu "UML-specific options"
config MODE_TT
- bool "Tracing thread support"
+ bool "Tracing thread support (DEPRECATED)"
default n
+ depends on BROKEN
help
This option controls whether tracing thread support is compiled
- into UML. This option is largely obsolete, given that skas0 provides
+ into UML. This option is largely obsolete, given that skas0 provides
skas security and performance without needing to patch the host.
- It is safe to say 'N' here.
+ It is safe to say 'N' here; saying 'Y' may cause additional problems
+ with the resulting binary even if you run UML in SKAS mode, and running
+ in TT mode is strongly *NOT RECOMMENDED*.
config STATIC_LINK
bool "Force a static link"
@@ -56,6 +77,9 @@ config STATIC_LINK
for use in a chroot jail. So, if you intend to run UML inside a
chroot, and you disable CONFIG_MODE_TT, you probably want to say Y
here.
+ Additionally, this option enables using higher memory spaces (up to
+ 2.75G) for UML - disabling CONFIG_MODE_TT and enabling this option leads
+ to best results for this.
config KERNEL_HALF_GIGS
int "Kernel address space size (in .5G units)"
@@ -72,10 +96,13 @@ config MODE_SKAS
default y
help
This option controls whether skas (separate kernel address space)
- support is compiled in. If you have applied the skas patch to the
- host, then you certainly want to say Y here (and consider saying N
- to CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this
- option will shrink the UML binary slightly.
+ support is compiled in.
+ Unless you have specific needs to use TT mode (which applies almost only
+ to developers), you should say Y here.
+ SKAS mode will make use of the SKAS3 patch if it is applied on the host
+ (and your UML will run in SKAS3 mode), but if no SKAS patch is applied
+ on the host it will run in SKAS0 mode, which is anyway faster than TT
+ mode.
source "arch/um/Kconfig.arch"
source "mm/Kconfig"
@@ -257,7 +284,7 @@ config UML_REAL_TIME_CLOCK
UML and spend long times with UML stopped at a breakpoint. In this
case, when UML is restarted, it will call the timer enough times to make
up for the time spent at the breakpoint. This could result in a
- noticable lag. If this is a problem, then disable this option.
+ noticeable lag. If this is a problem, then disable this option.
endmenu
diff --git a/arch/um/Kconfig.char b/arch/um/Kconfig.char
index 62d87b71179b..e03e40c7aac3 100644
--- a/arch/um/Kconfig.char
+++ b/arch/um/Kconfig.char
@@ -190,6 +190,11 @@ config HOSTAUDIO
tristate
default UML_SOUND
+#It is selected elsewhere, so kconfig would warn without this.
+config HW_RANDOM
+ tristate
+ default n
+
config UML_RANDOM
tristate "Hardware random number generator"
help
diff --git a/arch/um/Kconfig.i386 b/arch/um/Kconfig.i386
index f6eb72d117b9..f191a550a079 100644
--- a/arch/um/Kconfig.i386
+++ b/arch/um/Kconfig.i386
@@ -16,23 +16,42 @@ config SEMAPHORE_SLEEPERS
bool
default y
-config HOST_2G_2G
- bool "2G/2G host address space split"
- default n
- help
- This is needed when the host on which you run has a 2G/2G memory
- split, instead of the customary 3G/1G.
-
- Note that to enable such a host
- configuration, which makes sense only in some cases, you need special
- host patches.
-
- So, if you do not know what to do here, say 'N'.
+choice
+ prompt "Host memory split"
+ default HOST_VMSPLIT_3G
+ ---help---
+ This is needed when the host kernel on which you run has a non-default
+ (like 2G/2G) memory split, instead of the customary 3G/1G. If you did
+ not recompile your own kernel but use the default distro's one, you can
+ safely accept the "Default split" option.
+
+ It can be enabled on recent (>=2.6.16-rc2) vanilla kernels via
+ CONFIG_VM_SPLIT_*, or on previous kernels with special patches (-ck
+ patchset by Con Kolivas, or other ones) - option names match closely the
+ host CONFIG_VM_SPLIT_* ones.
+
+ A lower setting (where 1G/3G is lowest and 3G/1G is higher) will
+ tolerate even more "normal" host kernels, but an higher setting will be
+ stricter.
+
+ So, if you do not know what to do here, say 'Default split'.
+
+ config HOST_VMSPLIT_3G
+ bool "Default split (3G/1G user/kernel host split)"
+ config HOST_VMSPLIT_3G_OPT
+ bool "3G/1G user/kernel host split (for full 1G low memory)"
+ config HOST_VMSPLIT_2G
+ bool "2G/2G user/kernel host split"
+ config HOST_VMSPLIT_1G
+ bool "1G/3G user/kernel host split"
+endchoice
config TOP_ADDR
- hex
- default 0xc0000000 if !HOST_2G_2G
- default 0x80000000 if HOST_2G_2G
+ hex
+ default 0xB0000000 if HOST_VMSPLIT_3G_OPT
+ default 0x78000000 if HOST_VMSPLIT_2G
+ default 0x40000000 if HOST_VMSPLIT_1G
+ default 0xC0000000
config 3_LEVEL_PGTABLES
bool "Three-level pagetables (EXPERIMENTAL)"
diff --git a/arch/um/Makefile b/arch/um/Makefile
index f6ad832faf13..c8016a98483b 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -102,7 +102,7 @@ linux: vmlinux
define archhelp
echo '* linux - Binary kernel image (./linux) - for backward'
echo ' compatibility only, this creates a hard link to the'
- echo ' real kernel binary, the the "vmlinux" binary you'
+ echo ' real kernel binary, the "vmlinux" binary you'
echo ' find in the kernel root.'
endef
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 9558a7cf34d5..d278682dd799 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -1,13 +1,16 @@
# Copyright 2003 - 2004 Pathscale, Inc
# Released under the GPL
-core-y += arch/um/sys-x86_64/
+core-y += arch/um/sys-x86_64/ arch/x86_64/crypto/
START := 0x60000000
+_extra_flags_ = -fno-builtin -m64
+
#We #undef __x86_64__ for kernelspace, not for userspace where
#it's needed for headers to work!
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin -m64
-USER_CFLAGS += -fno-builtin -m64
+CFLAGS += -U__$(SUBARCH)__ $(_extra_flags_)
+USER_CFLAGS += $(_extra_flags_)
+
CHECKFLAGS += -m64
AFLAGS += -m64
LDFLAGS += -m elf_x86_64
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index e82764f75e7f..3576b3cc505e 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -110,7 +110,7 @@ static void not_configged_free(void *data)
"UML\n");
}
-static struct chan_ops not_configged_ops = {
+static const struct chan_ops not_configged_ops = {
.init = not_configged_init,
.open = not_configged_open,
.close = not_configged_close,
@@ -373,7 +373,7 @@ int console_write_chan(struct list_head *chans, const char *buf, int len)
}
int console_open_chan(struct line *line, struct console *co,
- struct chan_opts *opts)
+ const struct chan_opts *opts)
{
int err;
@@ -494,10 +494,10 @@ int chan_config_string(struct list_head *chans, char *str, int size,
struct chan_type {
char *key;
- struct chan_ops *ops;
+ const struct chan_ops *ops;
};
-static struct chan_type chan_table[] = {
+static const struct chan_type chan_table[] = {
{ "fd", &fd_ops },
#ifdef CONFIG_NULL_CHAN
@@ -534,10 +534,10 @@ static struct chan_type chan_table[] = {
};
static struct chan *parse_chan(struct line *line, char *str, int device,
- struct chan_opts *opts)
+ const struct chan_opts *opts)
{
- struct chan_type *entry;
- struct chan_ops *ops;
+ const struct chan_type *entry;
+ const struct chan_ops *ops;
struct chan *chan;
void *data;
int i;
@@ -582,7 +582,7 @@ static struct chan *parse_chan(struct line *line, char *str, int device,
}
int parse_chan_pair(char *str, struct line *line, int device,
- struct chan_opts *opts)
+ const struct chan_opts *opts)
{
struct list_head *chans = &line->chan_list;
struct chan *new, *chan;
diff --git a/arch/um/drivers/cow_sys.h b/arch/um/drivers/cow_sys.h
index 7a5b4afde692..c6a308464acb 100644
--- a/arch/um/drivers/cow_sys.h
+++ b/arch/um/drivers/cow_sys.h
@@ -5,6 +5,7 @@
#include "user_util.h"
#include "os.h"
#include "user.h"
+#include "um_malloc.h"
static inline void *cow_malloc(int size)
{
diff --git a/arch/um/drivers/daemon.h b/arch/um/drivers/daemon.h
index 7326c42f7ef9..3bc3cf6b94aa 100644
--- a/arch/um/drivers/daemon.h
+++ b/arch/um/drivers/daemon.h
@@ -18,7 +18,7 @@ struct daemon_data {
void *dev;
};
-extern struct net_user_info daemon_user_info;
+extern const struct net_user_info daemon_user_info;
extern int daemon_user_write(int fd, void *buf, int len,
struct daemon_data *pri);
diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c
index 53d09ed78b42..824386974f88 100644
--- a/arch/um/drivers/daemon_kern.c
+++ b/arch/um/drivers/daemon_kern.c
@@ -57,7 +57,7 @@ static int daemon_write(int fd, struct sk_buff **skb,
(struct daemon_data *) &lp->user));
}
-static struct net_kern_info daemon_kern_info = {
+static const struct net_kern_info daemon_kern_info = {
.init = daemon_init,
.protocol = eth_protocol,
.read = daemon_read,
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index c944265955e2..310af0f1e49e 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -17,6 +17,7 @@
#include "user_util.h"
#include "user.h"
#include "os.h"
+#include "um_malloc.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
@@ -182,7 +183,7 @@ static int daemon_set_mtu(int mtu, void *data)
return(mtu);
}
-struct net_user_info daemon_user_info = {
+const struct net_user_info daemon_user_info = {
.init = daemon_user_init,
.open = daemon_open,
.close = NULL,
diff --git a/arch/um/drivers/fd.c b/arch/um/drivers/fd.c
index c41f75e4acb5..218aa0e9b792 100644
--- a/arch/um/drivers/fd.c
+++ b/arch/um/drivers/fd.c
@@ -12,6 +12,7 @@
#include "user_util.h"
#include "chan_user.h"
#include "os.h"
+#include "um_malloc.h"
struct fd_chan {
int fd;
@@ -20,7 +21,7 @@ struct fd_chan {
char str[sizeof("1234567890\0")];
};
-static void *fd_init(char *str, int device, struct chan_opts *opts)
+static void *fd_init(char *str, int device, const struct chan_opts *opts)
{
struct fd_chan *data;
char *end;
@@ -77,7 +78,7 @@ static void fd_close(int fd, void *d)
}
}
-struct chan_ops fd_ops = {
+const struct chan_ops fd_ops = {
.type = "fd",
.init = fd_init,
.open = fd_open,
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index 37232f908cd7..a0d148ea63d6 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/module.h"
#include "linux/init.h"
#include "linux/slab.h"
@@ -280,7 +279,7 @@ static int hostmixer_release(struct inode *inode, struct file *file)
/* kernel module operations */
-static struct file_operations hostaudio_fops = {
+static const struct file_operations hostaudio_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = hostaudio_read,
@@ -292,7 +291,7 @@ static struct file_operations hostaudio_fops = {
.release = hostaudio_release,
};
-static struct file_operations hostmixer_fops = {
+static const struct file_operations hostmixer_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.ioctl = hostmixer_ioctl_mixdev,
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index ebebaabb78ad..426633e5d6e3 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -20,7 +20,7 @@
#define LINE_BUFSIZE 4096
-static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused)
+static irqreturn_t line_interrupt(int irq, void *data)
{
struct chan *chan = data;
struct line *line = chan->line;
@@ -251,7 +251,7 @@ void line_set_termios(struct tty_struct *tty, struct termios * old)
/* nothing */
}
-static struct {
+static const struct {
int cmd;
char *level;
char *name;
@@ -364,8 +364,7 @@ void line_unthrottle(struct tty_struct *tty)
reactivate_chan(&line->chan_list, line->driver->read_irq);
}
-static irqreturn_t line_write_interrupt(int irq, void *data,
- struct pt_regs *unused)
+static irqreturn_t line_write_interrupt(int irq, void *data)
{
struct chan *chan = data;
struct line *line = chan->line;
@@ -405,7 +404,7 @@ static irqreturn_t line_write_interrupt(int irq, void *data,
int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
{
- struct line_driver *driver = line->driver;
+ const struct line_driver *driver = line->driver;
int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
if (input)
@@ -497,7 +496,7 @@ void close_lines(struct line *lines, int nlines)
}
/* Common setup code for both startup command line and mconsole initialization.
- * @lines contains the the array (of size @num) to modify;
+ * @lines contains the array (of size @num) to modify;
* @init is the setup string;
*/
@@ -558,7 +557,7 @@ int line_setup(struct line *lines, unsigned int num, char *init)
}
int line_config(struct line *lines, unsigned int num, char *str,
- struct chan_opts *opts)
+ const struct chan_opts *opts)
{
struct line *line;
char *new;
@@ -642,9 +641,9 @@ int line_remove(struct line *lines, unsigned int num, int n)
}
struct tty_driver *line_register_devfs(struct lines *set,
- struct line_driver *line_driver,
- struct tty_operations *ops, struct line *lines,
- int nlines)
+ struct line_driver *line_driver,
+ const struct tty_operations *ops,
+ struct line *lines, int nlines)
{
int i;
struct tty_driver *driver = alloc_tty_driver(nlines);
@@ -712,7 +711,7 @@ struct winch {
struct tty_struct *tty;
};
-static irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
+static irqreturn_t winch_interrupt(int irq, void *data)
{
struct winch *winch = data;
struct tty_struct *tty;
diff --git a/arch/um/drivers/mcast.h b/arch/um/drivers/mcast.h
index a2c6db243458..bc56af9d3e53 100644
--- a/arch/um/drivers/mcast.h
+++ b/arch/um/drivers/mcast.h
@@ -13,7 +13,7 @@ struct mcast_data {
void *dev;
};
-extern struct net_user_info mcast_user_info;
+extern const struct net_user_info mcast_user_info;
extern int mcast_user_write(int fd, void *buf, int len,
struct mcast_data *pri);
diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c
index 3a7af18cf944..c090fbd464e7 100644
--- a/arch/um/drivers/mcast_kern.c
+++ b/arch/um/drivers/mcast_kern.c
@@ -61,7 +61,7 @@ static int mcast_write(int fd, struct sk_buff **skb,
(struct mcast_data *) &lp->user);
}
-static struct net_kern_info mcast_kern_info = {
+static const struct net_kern_info mcast_kern_info = {
.init = mcast_init,
.protocol = eth_protocol,
.read = mcast_read,
diff --git a/arch/um/drivers/mcast_user.c b/arch/um/drivers/mcast_user.c
index afe85bfa66e0..8138f5ea1bf7 100644
--- a/arch/um/drivers/mcast_user.c
+++ b/arch/um/drivers/mcast_user.c
@@ -23,6 +23,7 @@
#include "user_util.h"
#include "user.h"
#include "os.h"
+#include "um_malloc.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
@@ -152,7 +153,7 @@ static int mcast_set_mtu(int mtu, void *data)
return(mtu);
}
-struct net_user_info mcast_user_info = {
+const struct net_user_info mcast_user_info = {
.init = mcast_user_init,
.open = mcast_open,
.close = mcast_close,
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index 79610b5ce67e..d08bd036ccb8 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -74,8 +74,7 @@ static void mc_work_proc(void *unused)
static DECLARE_WORK(mconsole_work, mc_work_proc, NULL);
-static irqreturn_t mconsole_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t mconsole_interrupt(int irq, void *dev_id)
{
/* long to avoid size mismatch warnings from gcc */
long fd;
@@ -106,9 +105,9 @@ void mconsole_version(struct mc_request *req)
{
char version[256];
- sprintf(version, "%s %s %s %s %s", system_utsname.sysname,
- system_utsname.nodename, system_utsname.release,
- system_utsname.version, system_utsname.machine);
+ sprintf(version, "%s %s %s %s %s", utsname()->sysname,
+ utsname()->nodename, utsname()->release,
+ utsname()->version, utsname()->machine);
mconsole_reply(req, version, 0, 0);
}
@@ -598,6 +597,11 @@ out:
mconsole_reply(req, err_msg, err, 0);
}
+struct mconsole_output {
+ struct list_head list;
+ struct mc_request *req;
+};
+
static DEFINE_SPINLOCK(console_lock);
static LIST_HEAD(clients);
static char console_buf[MCONSOLE_MAX_DATA];
@@ -622,10 +626,10 @@ static void console_write(struct console *console, const char *string,
return;
list_for_each(ele, &clients){
- struct mconsole_entry *entry;
+ struct mconsole_output *entry;
- entry = list_entry(ele, struct mconsole_entry, list);
- mconsole_reply_len(&entry->request, console_buf,
+ entry = list_entry(ele, struct mconsole_output, list);
+ mconsole_reply_len(entry->req, console_buf,
console_index, 0, 1);
}
@@ -649,10 +653,10 @@ late_initcall(mc_add_console);
static void with_console(struct mc_request *req, void (*proc)(void *),
void *arg)
{
- struct mconsole_entry entry;
+ struct mconsole_output entry;
unsigned long flags;
- entry.request = *req;
+ entry.req = req;
list_add(&entry.list, &clients);
spin_lock_irqsave(&console_lock, flags);
@@ -669,8 +673,9 @@ static void with_console(struct mc_request *req, void (*proc)(void *),
static void sysrq_proc(void *arg)
{
char *op = arg;
-
- handle_sysrq(*op, &current->thread.regs, NULL);
+ struct pt_regs *old_regs = set_irq_regs(&current->thread.regs);
+ handle_sysrq(*op, NULL);
+ set_irq_regs(old_regs);
}
void mconsole_sysrq(struct mc_request *req)
diff --git a/arch/um/drivers/mconsole_user.c b/arch/um/drivers/mconsole_user.c
index 5b2f5fe9e426..17068eb746c0 100644
--- a/arch/um/drivers/mconsole_user.c
+++ b/arch/um/drivers/mconsole_user.c
@@ -131,6 +131,10 @@ int mconsole_get_request(int fd, struct mc_request *req)
int mconsole_reply_len(struct mc_request *req, const char *str, int total,
int err, int more)
{
+ /* XXX This is a stack consumption problem. It'd be nice to
+ * make it global and serialize access to it, but there are a
+ * ton of callers to this function.
+ */
struct mconsole_reply reply;
int len, n;
diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
index 022f67bb6873..df3516e47d4d 100644
--- a/arch/um/drivers/mmapper_kern.c
+++ b/arch/um/drivers/mmapper_kern.c
@@ -85,7 +85,7 @@ mmapper_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations mmapper_fops = {
+static const struct file_operations mmapper_fops = {
.owner = THIS_MODULE,
.read = mmapper_read,
.write = mmapper_write,
@@ -95,6 +95,7 @@ static struct file_operations mmapper_fops = {
.release = mmapper_release,
};
+/* No locking needed - only used (and modified) by below initcall and exitcall. */
static struct miscdevice mmapper_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "mmapper",
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 4a7966b21931..ec9eb8bd9432 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -5,7 +5,6 @@
* Licensed under the GPL.
*/
-#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/netdevice.h"
#include "linux/rtnetlink.h"
@@ -78,7 +77,7 @@ static void uml_dev_close(void* dev)
dev_close( (struct net_device *) dev);
}
-irqreturn_t uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t uml_net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct uml_net_private *lp = dev->priv;
@@ -114,18 +113,11 @@ static int uml_net_open(struct net_device *dev)
struct uml_net_private *lp = dev->priv;
int err;
- spin_lock(&lp->lock);
-
if(lp->fd >= 0){
err = -ENXIO;
goto out;
}
- if(!lp->have_mac){
- dev_ip_addr(dev, &lp->mac[2]);
- set_ether_mac(dev, lp->mac);
- }
-
lp->fd = (*lp->open)(&lp->user);
if(lp->fd < 0){
err = lp->fd;
@@ -149,8 +141,6 @@ static int uml_net_open(struct net_device *dev)
*/
while((err = uml_net_rx(dev)) > 0) ;
- spin_unlock(&lp->lock);
-
spin_lock(&opened_lock);
list_add(&lp->list, &opened);
spin_unlock(&opened_lock);
@@ -160,7 +150,6 @@ out_close:
if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user);
lp->fd = -1;
out:
- spin_unlock(&lp->lock);
return err;
}
@@ -169,15 +158,12 @@ static int uml_net_close(struct net_device *dev)
struct uml_net_private *lp = dev->priv;
netif_stop_queue(dev);
- spin_lock(&lp->lock);
free_irq(dev->irq, dev);
if(lp->close != NULL)
(*lp->close)(lp->fd, &lp->user);
lp->fd = -1;
- spin_unlock(&lp->lock);
-
spin_lock(&opened_lock);
list_del(&lp->list);
spin_unlock(&opened_lock);
@@ -246,9 +232,9 @@ static int uml_net_set_mac(struct net_device *dev, void *addr)
struct uml_net_private *lp = dev->priv;
struct sockaddr *hwaddr = addr;
- spin_lock(&lp->lock);
+ spin_lock_irq(&lp->lock);
set_ether_mac(dev, hwaddr->sa_data);
- spin_unlock(&lp->lock);
+ spin_unlock_irq(&lp->lock);
return(0);
}
@@ -258,7 +244,7 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
struct uml_net_private *lp = dev->priv;
int err = 0;
- spin_lock(&lp->lock);
+ spin_lock_irq(&lp->lock);
new_mtu = (*lp->set_mtu)(new_mtu, &lp->user);
if(new_mtu < 0){
@@ -269,7 +255,7 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu)
dev->mtu = new_mtu;
out:
- spin_unlock(&lp->lock);
+ spin_unlock_irq(&lp->lock);
return err;
}
@@ -295,6 +281,37 @@ void uml_net_user_timer_expire(unsigned long _conn)
#endif
}
+static void setup_etheraddr(char *str, unsigned char *addr)
+{
+ char *end;
+ int i;
+
+ if(str == NULL)
+ goto random;
+
+ for(i=0;i<6;i++){
+ addr[i] = simple_strtoul(str, &end, 16);
+ if((end == str) ||
+ ((*end != ':') && (*end != ',') && (*end != '\0'))){
+ printk(KERN_ERR
+ "setup_etheraddr: failed to parse '%s' "
+ "as an ethernet address\n", str);
+ goto random;
+ }
+ str = end + 1;
+ }
+ if(addr[0] & 1){
+ printk(KERN_ERR
+ "Attempt to assign a broadcast ethernet address to a "
+ "device disallowed\n");
+ goto random;
+ }
+ return;
+
+random:
+ random_ether_addr(addr);
+}
+
static DEFINE_SPINLOCK(devices_lock);
static LIST_HEAD(devices);
@@ -330,15 +347,13 @@ static int eth_configure(int n, void *init, char *mac,
list_add(&device->list, &devices);
spin_unlock(&devices_lock);
- if (setup_etheraddr(mac, device->mac))
- device->have_mac = 1;
+ setup_etheraddr(mac, device->mac);
printk(KERN_INFO "Netdevice %d ", n);
- if (device->have_mac)
- printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
- device->mac[0], device->mac[1],
- device->mac[2], device->mac[3],
- device->mac[4], device->mac[5]);
+ printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
+ device->mac[0], device->mac[1],
+ device->mac[2], device->mac[3],
+ device->mac[4], device->mac[5]);
printk(": ");
dev = alloc_etherdev(size);
if (dev == NULL) {
@@ -404,7 +419,6 @@ static int eth_configure(int n, void *init, char *mac,
.dev = dev,
.fd = -1,
.mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0},
- .have_mac = device->have_mac,
.protocol = transport->kern->protocol,
.open = transport->user->open,
.close = transport->user->close,
@@ -419,14 +433,12 @@ static int eth_configure(int n, void *init, char *mac,
init_timer(&lp->tl);
spin_lock_init(&lp->lock);
lp->tl.function = uml_net_user_timer_expire;
- if (lp->have_mac)
- memcpy(lp->mac, device->mac, sizeof(lp->mac));
+ memcpy(lp->mac, device->mac, sizeof(lp->mac));
if (transport->user->init)
(*transport->user->init)(&lp->user, dev);
- if (device->have_mac)
- set_ether_mac(dev, device->mac);
+ set_ether_mac(dev, device->mac);
return 0;
}
@@ -569,12 +581,13 @@ static int eth_setup(char *str)
int n, err;
err = eth_parse(str, &n, &str);
- if(err) return(1);
+ if(err)
+ return 1;
- new = alloc_bootmem(sizeof(new));
+ new = alloc_bootmem(sizeof(*new));
if (new == NULL){
printk("eth_init : alloc_bootmem failed\n");
- return(1);
+ return 1;
}
INIT_LIST_HEAD(&new->list);
@@ -582,7 +595,7 @@ static int eth_setup(char *str)
new->init = str;
list_add_tail(&new->list, &eth_cmd_line);
- return(1);
+ return 1;
}
__setup("eth", eth_setup);
@@ -754,47 +767,6 @@ static void close_devices(void)
__uml_exitcall(close_devices);
-int setup_etheraddr(char *str, unsigned char *addr)
-{
- char *end;
- int i;
-
- if(str == NULL)
- return(0);
- for(i=0;i<6;i++){
- addr[i] = simple_strtoul(str, &end, 16);
- if((end == str) ||
- ((*end != ':') && (*end != ',') && (*end != '\0'))){
- printk(KERN_ERR
- "setup_etheraddr: failed to parse '%s' "
- "as an ethernet address\n", str);
- return(0);
- }
- str = end + 1;
- }
- if(addr[0] & 1){
- printk(KERN_ERR
- "Attempt to assign a broadcast ethernet address to a "
- "device disallowed\n");
- return(0);
- }
- return(1);
-}
-
-void dev_ip_addr(void *d, unsigned char *bin_buf)
-{
- struct net_device *dev = d;
- struct in_device *ip = dev->ip_ptr;
- struct in_ifaddr *in;
-
- if((ip == NULL) || ((in = ip->ifa_list) == NULL)){
- printk(KERN_WARNING "dev_ip_addr - device not assigned an "
- "IP address\n");
- return;
- }
- memcpy(bin_buf, &in->ifa_address, sizeof(in->ifa_address));
-}
-
struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
{
if((skb != NULL) && (skb_tailroom(skb) < extra)){
@@ -832,7 +804,7 @@ int dev_netmask(void *d, void *m)
struct net_device *dev = d;
struct in_device *ip = dev->ip_ptr;
struct in_ifaddr *in;
- __u32 *mask_out = m;
+ __be32 *mask_out = m;
if(ip == NULL)
return(1);
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c
index 107c5e43fa00..0ffd7ac295d4 100644
--- a/arch/um/drivers/net_user.c
+++ b/arch/um/drivers/net_user.c
@@ -12,11 +12,13 @@
#include <string.h>
#include <sys/socket.h>
#include <sys/wait.h>
+#include <sys/time.h>
#include "user.h"
#include "user_util.h"
#include "kern_util.h"
#include "net_user.h"
#include "os.h"
+#include "um_malloc.h"
int tap_open_common(void *dev, char *gate_addr)
{
diff --git a/arch/um/drivers/null.c b/arch/um/drivers/null.c
index 14cc5f78398a..9016c68beee8 100644
--- a/arch/um/drivers/null.c
+++ b/arch/um/drivers/null.c
@@ -8,9 +8,10 @@
#include "chan_user.h"
#include "os.h"
+/* This address is used only as a unique identifer */
static int null_chan;
-static void *null_init(char *str, int device, struct chan_opts *opts)
+static void *null_init(char *str, int device, const struct chan_opts *opts)
{
return(&null_chan);
}
@@ -31,7 +32,7 @@ static void null_free(void *data)
{
}
-struct chan_ops null_ops = {
+const struct chan_ops null_ops = {
.type = "null",
.init = null_init,
.open = null_open,
diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c
index 4c767c7adb96..6e1ef8558283 100644
--- a/arch/um/drivers/pcap_kern.c
+++ b/arch/um/drivers/pcap_kern.c
@@ -46,7 +46,7 @@ static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
return(-EPERM);
}
-static struct net_kern_info pcap_kern_info = {
+static const struct net_kern_info pcap_kern_info = {
.init = pcap_init,
.protocol = eth_protocol,
.read = pcap_read,
diff --git a/arch/um/drivers/pcap_user.c b/arch/um/drivers/pcap_user.c
index edfcb29273e1..11921a7baa7b 100644
--- a/arch/um/drivers/pcap_user.c
+++ b/arch/um/drivers/pcap_user.c
@@ -12,6 +12,7 @@
#include "net_user.h"
#include "pcap_user.h"
#include "user.h"
+#include "um_malloc.h"
#define MAX_PACKET (ETH_MAX_PACKET + ETH_HEADER_OTHER)
@@ -120,7 +121,7 @@ int pcap_user_read(int fd, void *buffer, int len, struct pcap_data *pri)
return(hdata.len);
}
-struct net_user_info pcap_user_info = {
+const struct net_user_info pcap_user_info = {
.init = pcap_user_init,
.open = pcap_open,
.close = NULL,
diff --git a/arch/um/drivers/pcap_user.h b/arch/um/drivers/pcap_user.h
index 58f9f6a1420f..96b80b565eeb 100644
--- a/arch/um/drivers/pcap_user.h
+++ b/arch/um/drivers/pcap_user.h
@@ -15,7 +15,7 @@ struct pcap_data {
void *dev;
};
-extern struct net_user_info pcap_user_info;
+extern const struct net_user_info pcap_user_info;
extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri);
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index 73755f37a8a8..ce9f3733f73e 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -47,7 +47,7 @@ struct connection {
struct port_list *port;
};
-static irqreturn_t pipe_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t pipe_interrupt(int irq, void *data)
{
struct connection *conn = data;
int fd;
@@ -152,7 +152,7 @@ void port_work_proc(void *unused)
DECLARE_WORK(port_work, port_work_proc, NULL);
-static irqreturn_t port_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t port_interrupt(int irq, void *data)
{
struct port_list *port = data;
diff --git a/arch/um/drivers/port_user.c b/arch/um/drivers/port_user.c
index c43e8bb32502..bc6afaf74c1a 100644
--- a/arch/um/drivers/port_user.c
+++ b/arch/um/drivers/port_user.c
@@ -19,6 +19,7 @@
#include "chan_user.h"
#include "port.h"
#include "os.h"
+#include "um_malloc.h"
struct port_chan {
int raw;
@@ -27,7 +28,7 @@ struct port_chan {
char dev[sizeof("32768\0")];
};
-static void *port_init(char *str, int device, struct chan_opts *opts)
+static void *port_init(char *str, int device, const struct chan_opts *opts)
{
struct port_chan *data;
void *kern_data;
@@ -100,7 +101,7 @@ static void port_close(int fd, void *d)
os_close_file(fd);
}
-struct chan_ops port_ops = {
+const struct chan_ops port_ops = {
.type = "port",
.init = port_init,
.open = port_open,
diff --git a/arch/um/drivers/pty.c b/arch/um/drivers/pty.c
index 1c555c38de4d..829a5eca8c07 100644
--- a/arch/um/drivers/pty.c
+++ b/arch/um/drivers/pty.c
@@ -13,6 +13,7 @@
#include "user_util.h"
#include "kern_util.h"
#include "os.h"
+#include "um_malloc.h"
struct pty_chan {
void (*announce)(char *dev_name, int dev);
@@ -22,7 +23,7 @@ struct pty_chan {
char dev_name[sizeof("/dev/pts/0123456\0")];
};
-static void *pty_chan_init(char *str, int device, struct chan_opts *opts)
+static void *pty_chan_init(char *str, int device, const struct chan_opts *opts)
{
struct pty_chan *data;
@@ -118,7 +119,7 @@ static int pty_open(int input, int output, int primary, void *d,
return(fd);
}
-struct chan_ops pty_ops = {
+const struct chan_ops pty_ops = {
.type = "pty",
.init = pty_chan_init,
.open = pty_open,
@@ -131,7 +132,7 @@ struct chan_ops pty_ops = {
.winch = 0,
};
-struct chan_ops pts_ops = {
+const struct chan_ops pts_ops = {
.type = "pts",
.init = pty_chan_init,
.open = pts_open,
diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c
index ba471f5864a6..73b2bdd6d2d3 100644
--- a/arch/um/drivers/random.c
+++ b/arch/um/drivers/random.c
@@ -20,6 +20,10 @@
#define RNG_MISCDEV_MINOR 183 /* official */
+/* Changed at init time, in the non-modular case, and at module load
+ * time, in the module case. Presumably, the module subsystem
+ * protects against a module being loaded twice at the same time.
+ */
static int random_fd = -1;
static int rng_dev_open (struct inode *inode, struct file *filp)
@@ -68,7 +72,7 @@ static ssize_t rng_dev_read (struct file *filp, char __user *buf, size_t size,
return ret;
}
-static struct file_operations rng_chrdev_ops = {
+static const struct file_operations rng_chrdev_ops = {
.owner = THIS_MODULE,
.open = rng_dev_open,
.read = rng_dev_read,
diff --git a/arch/um/drivers/slip.h b/arch/um/drivers/slip.h
index bb0dab41c2e4..c64f8c61d274 100644
--- a/arch/um/drivers/slip.h
+++ b/arch/um/drivers/slip.h
@@ -12,7 +12,7 @@ struct slip_data {
struct slip_proto slip;
};
-extern struct net_user_info slip_user_info;
+extern const struct net_user_info slip_user_info;
extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri);
extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri);
diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c
index 163ee0d5f75e..788da5439a2d 100644
--- a/arch/um/drivers/slip_kern.c
+++ b/arch/um/drivers/slip_kern.c
@@ -1,4 +1,3 @@
-#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/stddef.h"
#include "linux/init.h"
@@ -61,7 +60,7 @@ static int slip_write(int fd, struct sk_buff **skb,
(struct slip_data *) &lp->user));
}
-struct net_kern_info slip_kern_info = {
+const struct net_kern_info slip_kern_info = {
.init = slip_init,
.protocol = slip_protocol,
.read = slip_read,
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c
index 89fbec185cc1..7eddacc53b6e 100644
--- a/arch/um/drivers/slip_user.c
+++ b/arch/um/drivers/slip_user.c
@@ -15,6 +15,7 @@
#include "slip.h"
#include "slip_common.h"
#include "os.h"
+#include "um_malloc.h"
void slip_user_init(void *data, void *dev)
{
@@ -241,7 +242,7 @@ static void slip_del_addr(unsigned char *addr, unsigned char *netmask,
close_addr(addr, netmask, pri->name);
}
-struct net_user_info slip_user_info = {
+const struct net_user_info slip_user_info = {
.init = slip_user_init,
.open = slip_open,
.close = slip_close,
diff --git a/arch/um/drivers/slirp.h b/arch/um/drivers/slirp.h
index 6cf88ab580c9..89ccf83b7577 100644
--- a/arch/um/drivers/slirp.h
+++ b/arch/um/drivers/slirp.h
@@ -24,7 +24,7 @@ struct slirp_data {
struct slip_proto slip;
};
-extern struct net_user_info slirp_user_info;
+extern const struct net_user_info slirp_user_info;
extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri);
extern int slirp_user_write(int fd, void *buf, int len,
diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c
index 95e50c943e14..ae322e1c8a87 100644
--- a/arch/um/drivers/slirp_kern.c
+++ b/arch/um/drivers/slirp_kern.c
@@ -64,7 +64,7 @@ static int slirp_write(int fd, struct sk_buff **skb,
(struct slirp_data *) &lp->user));
}
-struct net_kern_info slirp_kern_info = {
+const struct net_kern_info slirp_kern_info = {
.init = slirp_init,
.protocol = slirp_protocol,
.read = slirp_read,
diff --git a/arch/um/drivers/slirp_user.c b/arch/um/drivers/slirp_user.c
index 33c5f6e625e8..ce5e85d1de3d 100644
--- a/arch/um/drivers/slirp_user.c
+++ b/arch/um/drivers/slirp_user.c
@@ -126,7 +126,7 @@ static int slirp_set_mtu(int mtu, void *data)
return(mtu);
}
-struct net_user_info slirp_user_info = {
+const struct net_user_info slirp_user_info = {
.init = slirp_user_init,
.open = slirp_open,
.close = slirp_close,
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index 6dafd6fbfdae..ed9c59082d0d 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/fs.h"
#include "linux/tty.h"
#include "linux/tty_driver.h"
@@ -23,7 +22,7 @@
#include "irq_user.h"
#include "mconsole_kern.h"
-static int ssl_version = 1;
+static const int ssl_version = 1;
/* Referenced only by tty_driver below - presumably it's locked correctly
* by the tty driver.
@@ -123,7 +122,7 @@ void ssl_hangup(struct tty_struct *tty)
}
#endif
-static struct tty_operations ssl_ops = {
+static const struct tty_operations ssl_ops = {
.open = ssl_open,
.close = line_close,
.write = line_write,
diff --git a/arch/um/drivers/stderr_console.c b/arch/um/drivers/stderr_console.c
index 6d2cf32a9e8f..911539293871 100644
--- a/arch/um/drivers/stderr_console.c
+++ b/arch/um/drivers/stderr_console.c
@@ -9,6 +9,8 @@
/*
* Don't register by default -- as this registeres very early in the
* boot process it becomes the default console.
+ *
+ * Initialized at init time.
*/
static int use_stderr_console = 0;
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index 856f568c2687..7a4897e27f42 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/posix_types.h"
#include "linux/tty.h"
#include "linux/tty_flip.h"
@@ -108,9 +107,10 @@ static int con_open(struct tty_struct *tty, struct file *filp)
return line_open(vts, tty);
}
+/* Set in an initcall, checked in an exitcall */
static int con_init_done = 0;
-static struct tty_operations console_ops = {
+static const struct tty_operations console_ops = {
.open = con_open,
.close = line_close,
.write = line_write,
diff --git a/arch/um/drivers/tty.c b/arch/um/drivers/tty.c
index 9f70edf5d8ef..d95d64309eaf 100644
--- a/arch/um/drivers/tty.c
+++ b/arch/um/drivers/tty.c
@@ -11,6 +11,7 @@
#include "user_util.h"
#include "user.h"
#include "os.h"
+#include "um_malloc.h"
struct tty_chan {
char *dev;
@@ -18,7 +19,7 @@ struct tty_chan {
struct termios tt;
};
-static void *tty_chan_init(char *str, int device, struct chan_opts *opts)
+static void *tty_chan_init(char *str, int device, const struct chan_opts *opts)
{
struct tty_chan *data;
@@ -62,7 +63,7 @@ static int tty_open(int input, int output, int primary, void *d,
return fd;
}
-struct chan_ops tty_ops = {
+const struct chan_ops tty_ops = {
.type = "tty",
.init = tty_chan_init,
.open = tty_open,
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 34085315aa57..bc458f57921b 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -20,7 +20,6 @@
#define MAJOR_NR UBD_MAJOR
#define UBD_SHIFT 4
-#include "linux/config.h"
#include "linux/module.h"
#include "linux/blkdev.h"
#include "linux/hdreg.h"
@@ -525,7 +524,7 @@ static void ubd_handler(void)
do_ubd_request(ubd_queue);
}
-static irqreturn_t ubd_intr(int irq, void *dev, struct pt_regs *unused)
+static irqreturn_t ubd_intr(int irq, void *dev)
{
ubd_handler();
return(IRQ_HANDLED);
@@ -668,18 +667,15 @@ static int ubd_add(int n)
if(dev->file == NULL)
goto out;
- if (ubd_open_dev(dev))
- goto out;
-
err = ubd_file_size(dev, &dev->size);
if(err < 0)
- goto out_close;
+ goto out;
dev->size = ROUND_BLOCK(dev->size);
err = ubd_new_disk(MAJOR_NR, dev->size, n, &ubd_gendisk[n]);
if(err)
- goto out_close;
+ goto out;
if(fake_major != MAJOR_NR)
ubd_new_disk(fake_major, dev->size, n,
@@ -691,8 +687,6 @@ static int ubd_add(int n)
make_ide_entries(ubd_gendisk[n]->disk_name);
err = 0;
-out_close:
- ubd_close(dev);
out:
return err;
}
@@ -986,8 +980,6 @@ static int prepare_request(struct request *req, struct io_thread_req *io_req)
__u64 offset;
int len;
- if(req->rq_status == RQ_INACTIVE) return(1);
-
/* This should be impossible now */
if((rq_data_dir(req) == WRITE) && !dev->openflags.w){
printk("Write attempted on readonly ubd device %s\n",
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c
index aaa636661043..850221d9b4c9 100644
--- a/arch/um/drivers/xterm.c
+++ b/arch/um/drivers/xterm.c
@@ -31,7 +31,7 @@ struct xterm_chan {
};
/* Not static because it's called directly by the tt mode gdb code */
-void *xterm_init(char *str, int device, struct chan_opts *opts)
+void *xterm_init(char *str, int device, const struct chan_opts *opts)
{
struct xterm_chan *data;
@@ -136,8 +136,6 @@ int xterm_open(int input, int output, int primary, void *d,
return(pid);
}
- if(data->stack == 0) free_stack(stack, 0);
-
if (data->direct_rcv) {
new = os_rcv_fd(fd, &data->helper_pid);
} else {
@@ -194,7 +192,7 @@ static void xterm_free(void *d)
free(d);
}
-struct chan_ops xterm_ops = {
+const struct chan_ops xterm_ops = {
.type = "xterm",
.init = xterm_init,
.open = xterm_open,
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index 6036ec85895a..a4ce7058e10e 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -21,7 +21,7 @@ struct xterm_wait {
int new_fd;
};
-static irqreturn_t xterm_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t xterm_interrupt(int irq, void *data)
{
struct xterm_wait *xterm = data;
int fd;
diff --git a/arch/um/include/chan_kern.h b/arch/um/include/chan_kern.h
index 1bb5e9d94270..572d286ed2c6 100644
--- a/arch/um/include/chan_kern.h
+++ b/arch/um/include/chan_kern.h
@@ -23,21 +23,21 @@ struct chan {
unsigned int opened:1;
unsigned int enabled:1;
int fd;
- struct chan_ops *ops;
+ const struct chan_ops *ops;
void *data;
};
extern void chan_interrupt(struct list_head *chans, struct work_struct *task,
struct tty_struct *tty, int irq);
extern int parse_chan_pair(char *str, struct line *line, int device,
- struct chan_opts *opts);
+ const struct chan_opts *opts);
extern int open_chan(struct list_head *chans);
extern int write_chan(struct list_head *chans, const char *buf, int len,
int write_irq);
extern int console_write_chan(struct list_head *chans, const char *buf,
int len);
extern int console_open_chan(struct line *line, struct console *co,
- struct chan_opts *opts);
+ const struct chan_opts *opts);
extern void deactivate_chan(struct list_head *chans, int irq);
extern void reactivate_chan(struct list_head *chans, int irq);
extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty);
diff --git a/arch/um/include/chan_user.h b/arch/um/include/chan_user.h
index 659bb3cac32f..a795547a1dbd 100644
--- a/arch/um/include/chan_user.h
+++ b/arch/um/include/chan_user.h
@@ -20,7 +20,7 @@ enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE };
struct chan_ops {
char *type;
- void *(*init)(char *, int, struct chan_opts *);
+ void *(*init)(char *, int, const struct chan_opts *);
int (*open)(int, int, int, void *, char **);
void (*close)(int, void *);
int (*read)(int, char *, void *);
@@ -31,8 +31,8 @@ struct chan_ops {
int winch;
};
-extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops,
- xterm_ops;
+extern const struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops,
+ tty_ops, xterm_ops;
extern void generic_close(int fd, void *unused);
extern int generic_read(int fd, char *c_out, void *unused);
diff --git a/arch/um/include/common-offsets.h b/arch/um/include/common-offsets.h
index 356390d1f8b9..461175f8b1d9 100644
--- a/arch/um/include/common-offsets.h
+++ b/arch/um/include/common-offsets.h
@@ -1,9 +1,16 @@
/* for use by sys-$SUBARCH/kernel-offsets.c */
+DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
+#ifdef CONFIG_MODE_TT
+OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
+#endif
+
OFFSET(HOST_TASK_REGS, task_struct, thread.regs);
OFFSET(HOST_TASK_PID, task_struct, pid);
+
DEFINE(UM_KERN_PAGE_SIZE, PAGE_SIZE);
DEFINE(UM_NSEC_PER_SEC, NSEC_PER_SEC);
+
DEFINE_STR(UM_KERN_EMERG, KERN_EMERG);
DEFINE_STR(UM_KERN_ALERT, KERN_ALERT);
DEFINE_STR(UM_KERN_CRIT, KERN_CRIT);
@@ -12,6 +19,10 @@ DEFINE_STR(UM_KERN_WARNING, KERN_WARNING);
DEFINE_STR(UM_KERN_NOTICE, KERN_NOTICE);
DEFINE_STR(UM_KERN_INFO, KERN_INFO);
DEFINE_STR(UM_KERN_DEBUG, KERN_DEBUG);
+
DEFINE(UM_ELF_CLASS, ELF_CLASS);
DEFINE(UM_ELFCLASS32, ELFCLASS32);
DEFINE(UM_ELFCLASS64, ELFCLASS64);
+
+/* For crypto assembler code. */
+DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
diff --git a/arch/um/include/irq_kern.h b/arch/um/include/irq_kern.h
index c222d56b1494..4f775597fd5f 100644
--- a/arch/um/include/irq_kern.h
+++ b/arch/um/include/irq_kern.h
@@ -10,12 +10,11 @@
#include "asm/ptrace.h"
extern int um_request_irq(unsigned int irq, int fd, int type,
- irqreturn_t (*handler)(int, void *,
- struct pt_regs *),
+ irq_handler_t handler,
unsigned long irqflags, const char * devname,
void *dev_id);
extern int init_aio_irq(int irq, char *name,
- irqreturn_t (*handler)(int, void *, struct pt_regs *));
+ irq_handler_t handler);
#endif
diff --git a/arch/um/include/kern_util.h b/arch/um/include/kern_util.h
index 89e1dc835a5b..cec9fcc57bf5 100644
--- a/arch/um/include/kern_util.h
+++ b/arch/um/include/kern_util.h
@@ -6,7 +6,6 @@
#ifndef __KERN_UTIL_H__
#define __KERN_UTIL_H__
-#include "linux/threads.h"
#include "sysdep/ptrace.h"
#include "sysdep/faultinfo.h"
@@ -21,7 +20,7 @@ struct kern_handlers {
kern_hndl timer_handler;
};
-extern struct kern_handlers handlinfo_kern;
+extern const struct kern_handlers handlinfo_kern;
extern int ncpus;
extern char *linux_prog;
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 27bf2f6fbc05..7be24811bb30 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -52,7 +52,7 @@ struct line {
int sigio;
struct work_struct task;
- struct line_driver *driver;
+ const struct line_driver *driver;
int have_irq;
};
@@ -91,15 +91,14 @@ extern int line_setup_irq(int fd, int input, int output, struct line *line,
void *data);
extern void line_close_chan(struct line *line);
extern struct tty_driver * line_register_devfs(struct lines *set,
- struct line_driver *line_driver,
- struct tty_operations *driver,
- struct line *lines,
- int nlines);
+ struct line_driver *line_driver,
+ const struct tty_operations *driver,
+ struct line *lines, int nlines);
extern void lines_init(struct line *lines, int nlines, struct chan_opts *opts);
extern void close_lines(struct line *lines, int nlines);
extern int line_config(struct line *lines, unsigned int sizeof_lines,
- char *str, struct chan_opts *opts);
+ char *str, const struct chan_opts *opts);
extern int line_id(char **str, int *start_out, int *end_out);
extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n);
extern int line_get_config(char *dev, struct line *lines,
diff --git a/arch/um/include/longjmp.h b/arch/um/include/longjmp.h
index e93c6d3e893b..e860bc5848e0 100644
--- a/arch/um/include/longjmp.h
+++ b/arch/um/include/longjmp.h
@@ -12,7 +12,8 @@ extern void longjmp(jmp_buf, int);
} while(0)
#define UML_SETJMP(buf) ({ \
- int n, enable; \
+ int n; \
+ volatile int enable; \
enable = get_signals(); \
n = setjmp(*buf); \
if(n != 0) \
diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
index d86ee14260ce..d0b690197fd7 100644
--- a/arch/um/include/mconsole_kern.h
+++ b/arch/um/include/mconsole_kern.h
@@ -6,7 +6,6 @@
#ifndef __MCONSOLE_KERN_H__
#define __MCONSOLE_KERN_H__
-#include "linux/config.h"
#include "linux/list.h"
#include "mconsole.h"
diff --git a/arch/um/include/mode_kern.h b/arch/um/include/mode_kern.h
index e7539a8451ef..88e5e77bf517 100644
--- a/arch/um/include/mode_kern.h
+++ b/arch/um/include/mode_kern.h
@@ -6,8 +6,6 @@
#ifndef __MODE_KERN_H__
#define __MODE_KERN_H__
-#include "linux/config.h"
-
#ifdef CONFIG_MODE_TT
#include "mode_kern_tt.h"
#endif
diff --git a/arch/um/include/net_kern.h b/arch/um/include/net_kern.h
index f7de6df60dd7..280459fb0b26 100644
--- a/arch/um/include/net_kern.h
+++ b/arch/um/include/net_kern.h
@@ -18,7 +18,6 @@ struct uml_net {
struct platform_device pdev;
int index;
unsigned char mac[ETH_ALEN];
- int have_mac;
};
struct uml_net_private {
@@ -29,7 +28,6 @@ struct uml_net_private {
struct net_device_stats stats;
int fd;
unsigned char mac[ETH_ALEN];
- int have_mac;
unsigned short (*protocol)(struct sk_buff *);
int (*open)(void *);
void (*close)(int, void *);
@@ -54,15 +52,14 @@ struct transport {
struct list_head list;
char *name;
int (*setup)(char *, char **, void *);
- struct net_user_info *user;
- struct net_kern_info *kern;
+ const struct net_user_info *user;
+ const struct net_kern_info *kern;
int private_size;
int setup_size;
};
extern struct net_device *ether_init(int);
extern unsigned short ether_protocol(struct sk_buff *);
-extern int setup_etheraddr(char *str, unsigned char *addr);
extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra);
extern int tap_setup_common(char *str, char *type, char **dev_name,
char **mac_out, char **gate_addr);
@@ -70,14 +67,3 @@ extern void register_transport(struct transport *new);
extern unsigned short eth_protocol(struct sk_buff *skb);
#endif
-
-/*
- * 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:
- */
diff --git a/arch/um/include/net_user.h b/arch/um/include/net_user.h
index 47ef7cb49a8e..19f207cd70fe 100644
--- a/arch/um/include/net_user.h
+++ b/arch/um/include/net_user.h
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
* Licensed under the GPL
*/
@@ -25,9 +25,8 @@ struct net_user_info {
};
extern void ether_user_init(void *data, void *dev);
-extern void dev_ip_addr(void *d, unsigned char *bin_buf);
-extern void iter_addresses(void *d, void (*cb)(unsigned char *,
- unsigned char *, void *),
+extern void iter_addresses(void *d, void (*cb)(unsigned char *,
+ unsigned char *, void *),
void *arg);
extern void *get_output_buffer(int *len_out);
@@ -52,14 +51,3 @@ extern char *split_if_spec(char *str, ...);
extern int dev_netmask(void *d, void *m);
#endif
-
-/*
- * 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:
- */
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 24fb6d8680e1..6516f6dca96d 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -14,6 +14,7 @@
#include "skas/mm_id.h"
#include "irq_user.h"
#include "sysdep/tls.h"
+#include "sysdep/archsetjmp.h"
#define OS_TYPE_FILE 1
#define OS_TYPE_DIR 2
@@ -198,7 +199,10 @@ extern long os_ptrace_ldt(long pid, long addr, long data);
extern int os_getpid(void);
extern int os_getpgrp(void);
+#ifdef UML_CONFIG_MODE_TT
extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int));
+extern void stop(void);
+#endif
extern void init_new_thread_signals(void);
extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr);
@@ -216,7 +220,6 @@ extern void os_flush_stdout(void);
*/
extern void forward_ipi(int fd, int pid);
extern void kill_child_dead(int pid);
-extern void stop(void);
extern int wait_for_stop(int pid, int sig, int cont_type, void *relay);
extern int protect_memory(unsigned long addr, unsigned long len,
int r, int w, int x, int must_succeed);
@@ -307,12 +310,9 @@ extern int copy_context_skas0(unsigned long stack, int pid);
extern void userspace(union uml_pt_regs *regs);
extern void map_stub_pages(int fd, unsigned long code,
unsigned long data, unsigned long stack);
-extern void new_thread(void *stack, void **switch_buf_ptr,
- void **fork_buf_ptr, void (*handler)(int));
-extern void thread_wait(void *sw, void *fb);
-extern void switch_threads(void *me, void *next);
-extern int start_idle_thread(void *stack, void *switch_buf_ptr,
- void **fork_buf_ptr);
+extern void new_thread(void *stack, jmp_buf *buf, void (*handler)(void));
+extern void switch_threads(jmp_buf *me, jmp_buf *you);
+extern int start_idle_thread(void *stack, jmp_buf *switch_buf);
extern void initial_thread_cb_skas(void (*proc)(void *),
void *arg);
extern void halt_skas(void);
diff --git a/arch/um/include/skas/mmu-skas.h b/arch/um/include/skas/mmu-skas.h
index d8869a6ef1b4..b26986c0c3d2 100644
--- a/arch/um/include/skas/mmu-skas.h
+++ b/arch/um/include/skas/mmu-skas.h
@@ -6,7 +6,6 @@
#ifndef __SKAS_MMU_H
#define __SKAS_MMU_H
-#include "linux/config.h"
#include "mm_id.h"
#include "asm/ldt.h"
diff --git a/arch/um/include/skas/skas.h b/arch/um/include/skas/skas.h
index 853b26f148c5..e88926b16072 100644
--- a/arch/um/include/skas/skas.h
+++ b/arch/um/include/skas/skas.h
@@ -14,8 +14,7 @@ extern int proc_mm, ptrace_faultinfo, ptrace_ldt;
extern int skas_needs_stub;
extern int user_thread(unsigned long stack, int flags);
-extern void new_thread_proc(void *stack, void (*handler)(int sig));
-extern void new_thread_handler(int sig);
+extern void new_thread_handler(void);
extern void handle_syscall(union uml_pt_regs *regs);
extern int new_mm(unsigned long stack);
extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
diff --git a/arch/um/include/sysdep-i386/archsetjmp.h b/arch/um/include/sysdep-i386/archsetjmp.h
index ea1ba3d42aee..11bafab669e9 100644
--- a/arch/um/include/sysdep-i386/archsetjmp.h
+++ b/arch/um/include/sysdep-i386/archsetjmp.h
@@ -16,4 +16,7 @@ struct __jmp_buf {
typedef struct __jmp_buf jmp_buf[1];
+#define JB_IP __eip
+#define JB_SP __esp
+
#endif /* _SETJMP_H */
diff --git a/arch/um/include/sysdep-i386/kernel-offsets.h b/arch/um/include/sysdep-i386/kernel-offsets.h
index 2c13de321f2f..97ec9d894d75 100644
--- a/arch/um/include/sysdep-i386/kernel-offsets.h
+++ b/arch/um/include/sysdep-i386/kernel-offsets.h
@@ -1,6 +1,7 @@
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/elf.h>
+#include <linux/crypto.h>
#include <asm/mman.h>
#define DEFINE(sym, val) \
@@ -17,9 +18,5 @@
void foo(void)
{
OFFSET(HOST_TASK_DEBUGREGS, task_struct, thread.arch.debugregs);
- DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
-#ifdef CONFIG_MODE_TT
- OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
-#endif
#include <common-offsets.h>
}
diff --git a/arch/um/include/sysdep-ppc/ptrace.h b/arch/um/include/sysdep-ppc/ptrace.h
index 8a27353733a9..df2397dba3e5 100644
--- a/arch/um/include/sysdep-ppc/ptrace.h
+++ b/arch/um/include/sysdep-ppc/ptrace.h
@@ -5,7 +5,6 @@
#ifndef __SYS_PTRACE_PPC_H
#define __SYS_PTRACE_PPC_H
-#include "linux/config.h"
#include "linux/types.h"
/* the following taken from <asm-ppc/ptrace.h> */
diff --git a/arch/um/include/sysdep-x86_64/archsetjmp.h b/arch/um/include/sysdep-x86_64/archsetjmp.h
index 454fc60aff6d..9a5e1a6ec800 100644
--- a/arch/um/include/sysdep-x86_64/archsetjmp.h
+++ b/arch/um/include/sysdep-x86_64/archsetjmp.h
@@ -18,4 +18,7 @@ struct __jmp_buf {
typedef struct __jmp_buf jmp_buf[1];
+#define JB_IP __rip
+#define JB_SP __rsp
+
#endif /* _SETJMP_H */
diff --git a/arch/um/include/sysdep-x86_64/kernel-offsets.h b/arch/um/include/sysdep-x86_64/kernel-offsets.h
index 91d129fb3930..a307237b7964 100644
--- a/arch/um/include/sysdep-x86_64/kernel-offsets.h
+++ b/arch/um/include/sysdep-x86_64/kernel-offsets.h
@@ -2,6 +2,7 @@
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/elf.h>
+#include <linux/crypto.h>
#include <asm/page.h>
#include <asm/mman.h>
@@ -18,9 +19,5 @@
void foo(void)
{
- DEFINE(KERNEL_MADV_REMOVE, MADV_REMOVE);
-#ifdef CONFIG_MODE_TT
- OFFSET(HOST_TASK_EXTERN_PID, task_struct, thread.mode.tt.extern_pid);
-#endif
#include <common-offsets.h>
}
diff --git a/arch/um/include/sysdep-x86_64/ptrace.h b/arch/um/include/sysdep-x86_64/ptrace.h
index 8d353f0feec1..617bb9efc934 100644
--- a/arch/um/include/sysdep-x86_64/ptrace.h
+++ b/arch/um/include/sysdep-x86_64/ptrace.h
@@ -50,6 +50,21 @@
#define HOST_FS 25
#define HOST_GS 26
+/* Also defined in asm/ptrace-x86_64.h, but not in libc headers. So, these
+ * are already defined for kernel code, but not for userspace code.
+ */
+#ifndef FS_BASE
+/* These aren't defined in ptrace.h, but exist in struct user_regs_struct,
+ * which is what x86_64 ptrace actually uses.
+ */
+#define FS_BASE (HOST_FS_BASE * sizeof(long))
+#define GS_BASE (HOST_GS_BASE * sizeof(long))
+#define DS (HOST_DS * sizeof(long))
+#define ES (HOST_ES * sizeof(long))
+#define FS (HOST_FS * sizeof(long))
+#define GS (HOST_GS * sizeof(long))
+#endif
+
#define REGS_FS_BASE(r) ((r)[HOST_FS_BASE])
#define REGS_GS_BASE(r) ((r)[HOST_GS_BASE])
#define REGS_DS(r) ((r)[HOST_DS])
@@ -89,9 +104,12 @@ union uml_pt_regs {
#endif
#ifdef UML_CONFIG_MODE_SKAS
struct skas_regs {
- /* XXX */
- unsigned long regs[27];
- unsigned long fp[65];
+ /* x86_64 ptrace uses sizeof(user_regs_struct) as its register
+ * file size, while i386 uses FRAME_SIZE. Therefore, we need
+ * to use UM_FRAME_SIZE here instead of HOST_FRAME_SIZE.
+ */
+ unsigned long regs[UM_FRAME_SIZE];
+ unsigned long fp[HOST_FP_SIZE];
struct faultinfo faultinfo;
long syscall;
int is_user;
@@ -120,11 +138,16 @@ extern int mode_tt;
#define UPT_R14(r) __CHOOSE_MODE(SC_R14(UPT_SC(r)), REGS_R14((r)->skas.regs))
#define UPT_R15(r) __CHOOSE_MODE(SC_R15(UPT_SC(r)), REGS_R15((r)->skas.regs))
#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+#define UPT_FS_BASE(r) \
+ __CHOOSE_MODE(SC_FS_BASE(UPT_SC(r)), REGS_FS_BASE((r)->skas.regs))
#define UPT_FS(r) __CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs))
+#define UPT_GS_BASE(r) \
+ __CHOOSE_MODE(SC_GS_BASE(UPT_SC(r)), REGS_GS_BASE((r)->skas.regs))
#define UPT_GS(r) __CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs))
#define UPT_DS(r) __CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs))
#define UPT_ES(r) __CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs))
#define UPT_CS(r) __CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs))
+#define UPT_SS(r) __CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs))
#define UPT_ORIG_RAX(r) \
__CHOOSE_MODE((r)->tt.orig_rax, REGS_ORIG_RAX((r)->skas.regs))
@@ -183,6 +206,13 @@ struct syscall_args {
case RBP: val = UPT_RBP(regs); break; \
case ORIG_RAX: val = UPT_ORIG_RAX(regs); break; \
case CS: val = UPT_CS(regs); break; \
+ case SS: val = UPT_SS(regs); break; \
+ case FS_BASE: val = UPT_FS_BASE(regs); break; \
+ case GS_BASE: val = UPT_GS_BASE(regs); break; \
+ case DS: val = UPT_DS(regs); break; \
+ case ES: val = UPT_ES(regs); break; \
+ case FS : val = UPT_FS (regs); break; \
+ case GS: val = UPT_GS(regs); break; \
case EFLAGS: val = UPT_EFLAGS(regs); break; \
default : \
panic("Bad register in UPT_REG : %d\n", reg); \
@@ -214,6 +244,13 @@ struct syscall_args {
case RBP: UPT_RBP(regs) = __upt_val; break; \
case ORIG_RAX: UPT_ORIG_RAX(regs) = __upt_val; break; \
case CS: UPT_CS(regs) = __upt_val; break; \
+ case SS: UPT_SS(regs) = __upt_val; break; \
+ case FS_BASE: UPT_FS_BASE(regs) = __upt_val; break; \
+ case GS_BASE: UPT_GS_BASE(regs) = __upt_val; break; \
+ case DS: UPT_DS(regs) = __upt_val; break; \
+ case ES: UPT_ES(regs) = __upt_val; break; \
+ case FS: UPT_FS(regs) = __upt_val; break; \
+ case GS: UPT_GS(regs) = __upt_val; break; \
case EFLAGS: UPT_EFLAGS(regs) = __upt_val; break; \
default : \
panic("Bad register in UPT_SET : %d\n", reg); \
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
index 128faf027364..4cd61a852fab 100644
--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -55,7 +55,7 @@
#define PTRACE_OLDSETOPTIONS 21
#endif
-/* These are before the system call, so the the system call number is RAX
+/* These are before the system call, so the system call number is RAX
* rather than ORIG_RAX, and arg4 is R10 rather than RCX
*/
#define REGS_SYSCALL_NR PT_INDEX(RAX)
diff --git a/arch/um/include/sysdep-x86_64/sc.h b/arch/um/include/sysdep-x86_64/sc.h
index a160d9fcc596..8aee45b07434 100644
--- a/arch/um/include/sysdep-x86_64/sc.h
+++ b/arch/um/include/sysdep-x86_64/sc.h
@@ -35,11 +35,11 @@
#define SC_GS(sc) SC_OFFSET(sc, SC_GS)
#define SC_EFLAGS(sc) SC_OFFSET(sc, SC_EFLAGS)
#define SC_SIGMASK(sc) SC_OFFSET(sc, SC_SIGMASK)
+#define SC_SS(sc) SC_OFFSET(sc, SC_SS)
#if 0
#define SC_ORIG_RAX(sc) SC_OFFSET(sc, SC_ORIG_RAX)
#define SC_DS(sc) SC_OFFSET(sc, SC_DS)
#define SC_ES(sc) SC_OFFSET(sc, SC_ES)
-#define SC_SS(sc) SC_OFFSET(sc, SC_SS)
#endif
#endif
diff --git a/arch/um/include/um_malloc.h b/arch/um/include/um_malloc.h
new file mode 100644
index 000000000000..0363a9b53f8d
--- /dev/null
+++ b/arch/um/include/um_malloc.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2005 Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
+ * Licensed under the GPL
+ */
+
+#ifndef __UM_MALLOC_H__
+#define __UM_MALLOC_H__
+
+extern void *um_kmalloc(int size);
+extern void *um_kmalloc_atomic(int size);
+extern void kfree(const void *ptr);
+
+extern void *um_vmalloc(int size);
+extern void *um_vmalloc_atomic(int size);
+extern void vfree(void *ptr);
+
+#endif /* __UM_MALLOC_H__ */
diff --git a/arch/um/include/um_uaccess.h b/arch/um/include/um_uaccess.h
index 4567f1eeb4a7..5126a99b5961 100644
--- a/arch/um/include/um_uaccess.h
+++ b/arch/um/include/um_uaccess.h
@@ -6,7 +6,6 @@
#ifndef __ARCH_UM_UACCESS_H
#define __ARCH_UM_UACCESS_H
-#include "linux/config.h"
#include "choose-mode.h"
#ifdef CONFIG_MODE_TT
diff --git a/arch/um/include/user.h b/arch/um/include/user.h
index 39f8c8801076..acadce3f271f 100644
--- a/arch/um/include/user.h
+++ b/arch/um/include/user.h
@@ -11,17 +11,11 @@ extern void panic(const char *fmt, ...)
extern int printk(const char *fmt, ...)
__attribute__ ((format (printf, 1, 2)));
extern void schedule(void);
-extern void *um_kmalloc(int size);
-extern void *um_kmalloc_atomic(int size);
-extern void kfree(void *ptr);
extern int in_aton(char *str);
extern int open_gdb_chan(void);
/* These use size_t, however unsigned long is correct on both i386 and x86_64. */
extern unsigned long strlcpy(char *, const char *, unsigned long);
extern unsigned long strlcat(char *, const char *, unsigned long);
-extern void *um_vmalloc(int size);
-extern void *um_vmalloc_atomic(int size);
-extern void vfree(void *ptr);
#endif
diff --git a/arch/um/include/user_util.h b/arch/um/include/user_util.h
index 802d7842514d..06625fefef33 100644
--- a/arch/um/include/user_util.h
+++ b/arch/um/include/user_util.h
@@ -52,7 +52,6 @@ extern int linux_main(int argc, char **argv);
extern void set_cmdline(char *cmd);
extern void input_cb(void (*proc)(void *), void *arg, int arg_len);
extern int get_pty(void);
-extern void *um_kmalloc(int size);
extern int switcheroo(int fd, int prot, void *from, void *to, int size);
extern void do_exec(int old_pid, int new_pid);
extern void tracer_panic(char *msg, ...)
diff --git a/arch/um/kernel/Makefile b/arch/um/kernel/Makefile
index a2d93065b2d0..6fa63a2a89e3 100644
--- a/arch/um/kernel/Makefile
+++ b/arch/um/kernel/Makefile
@@ -7,7 +7,7 @@ extra-y := vmlinux.lds
clean-files :=
obj-y = config.o exec.o exitcode.o init_task.o irq.o ksyms.o mem.o \
- physmem.o process_kern.o ptrace.o reboot.o resource.o sigio.o \
+ physmem.o process.o ptrace.o reboot.o resource.o sigio.o \
signal.o smp.o syscall.o sysrq.o time.o tlb.o trap.o uaccess.o \
um_arch.o umid.o
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
index d21ebad666b4..8b7f2cdedf94 100644
--- a/arch/um/kernel/exitcode.c
+++ b/arch/um/kernel/exitcode.c
@@ -16,9 +16,13 @@ int uml_exitcode = 0;
static int read_proc_exitcode(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- int len;
+ int len, val;
- len = sprintf(page, "%d\n", uml_exitcode);
+ /* Save uml_exitcode in a local so that we don't need to guarantee
+ * that sprintf accesses it atomically.
+ */
+ val = uml_exitcode;
+ len = sprintf(page, "%d\n", val);
len -= off;
if(len <= off+count) *eof = 1;
*start = page + off;
diff --git a/arch/um/kernel/gmon_syms.c b/arch/um/kernel/gmon_syms.c
index 2c86e7fdb014..13aa115cd1b4 100644
--- a/arch/um/kernel/gmon_syms.c
+++ b/arch/um/kernel/gmon_syms.c
@@ -5,7 +5,7 @@
#include "linux/module.h"
-extern void __bb_init_func(void *);
+extern void __bb_init_func(void *) __attribute__((weak));
EXPORT_SYMBOL(__bb_init_func);
/* This is defined (and referred to in profiling stub code) only by some GCC
@@ -21,14 +21,3 @@ EXPORT_SYMBOL(__gcov_init);
extern void __gcov_merge_add(void *) __attribute__((weak));
EXPORT_SYMBOL(__gcov_merge_add);
-
-/*
- * 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:
- */
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index 49ed5ddf0704..8cde431348cc 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/mm.h"
#include "linux/module.h"
#include "linux/sched.h"
diff --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index ce7f233fc490..5c1e611f628d 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -5,7 +5,6 @@
* Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
*/
-#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/module.h"
#include "linux/smp.h"
@@ -32,6 +31,7 @@
#include "irq_kern.h"
#include "os.h"
#include "sigio.h"
+#include "um_malloc.h"
#include "misc_constants.h"
/*
@@ -356,14 +356,16 @@ void forward_interrupts(int pid)
*/
unsigned int do_IRQ(int irq, union uml_pt_regs *regs)
{
- irq_enter();
- __do_IRQ(irq, (struct pt_regs *)regs);
- irq_exit();
- return 1;
+ struct pt_regs *old_regs = set_irq_regs((struct pt_regs *)regs);
+ irq_enter();
+ __do_IRQ(irq);
+ irq_exit();
+ set_irq_regs(old_regs);
+ return 1;
}
int um_request_irq(unsigned int irq, int fd, int type,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+ irq_handler_t handler,
unsigned long irqflags, const char * devname,
void *dev_id)
{
@@ -424,8 +426,7 @@ void __init init_IRQ(void)
}
}
-int init_aio_irq(int irq, char *name, irqreturn_t (*handler)(int, void *,
- struct pt_regs *))
+int init_aio_irq(int irq, char *name, irq_handler_t handler)
{
int fds[2], err;
diff --git a/arch/um/kernel/ksyms.c b/arch/um/kernel/ksyms.c
index c97045d6d89f..0e00cf93f900 100644
--- a/arch/um/kernel/ksyms.c
+++ b/arch/um/kernel/ksyms.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/module.h"
#include "linux/string.h"
#include "linux/smp_lock.h"
@@ -21,7 +20,6 @@
#include "mem_user.h"
#include "os.h"
-EXPORT_SYMBOL(stop);
EXPORT_SYMBOL(uml_physmem);
EXPORT_SYMBOL(set_signals);
EXPORT_SYMBOL(get_signals);
@@ -41,12 +39,14 @@ EXPORT_SYMBOL(handle_page_fault);
EXPORT_SYMBOL(find_iomem);
#ifdef CONFIG_MODE_TT
+EXPORT_SYMBOL(stop);
EXPORT_SYMBOL(strncpy_from_user_tt);
EXPORT_SYMBOL(copy_from_user_tt);
EXPORT_SYMBOL(copy_to_user_tt);
#endif
#ifdef CONFIG_MODE_SKAS
+EXPORT_SYMBOL(strnlen_user_skas);
EXPORT_SYMBOL(strncpy_from_user_skas);
EXPORT_SYMBOL(copy_to_user_skas);
EXPORT_SYMBOL(copy_from_user_skas);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index 93121c6d26e5..c95855ba6ab5 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -226,7 +226,8 @@ void paging_init(void)
for(i = 0; i < ARRAY_SIZE(zones_size); i++)
zones_size[i] = 0;
- zones_size[ZONE_DMA] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT);
+ zones_size[ZONE_NORMAL] = (end_iomem >> PAGE_SHIFT) -
+ (uml_physmem >> PAGE_SHIFT);
#ifdef CONFIG_HIGHMEM
zones_size[ZONE_HIGHMEM] = highmem >> PAGE_SHIFT;
#endif
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process.c
index 537895d68ad1..348b272bb766 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process.c
@@ -1,10 +1,9 @@
-/*
+/*
* Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
* Copyright 2003 PathScale, Inc.
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/sched.h"
#include "linux/interrupt.h"
@@ -47,6 +46,7 @@
#include "mode.h"
#include "mode_kern.h"
#include "choose-mode.h"
+#include "um_malloc.h"
/* This is a per-cpu array. A processor only modifies its entry and it only
* cares about its entry, so it's OK if another processor is modifying its
@@ -113,11 +113,11 @@ void set_current(void *t)
void *_switch_to(void *prev, void *next, void *last)
{
- struct task_struct *from = prev;
- struct task_struct *to= next;
+ struct task_struct *from = prev;
+ struct task_struct *to= next;
- to->thread.prev_sched = from;
- set_current(to);
+ to->thread.prev_sched = from;
+ set_current(to);
do {
current->thread.saved_task = NULL ;
@@ -128,7 +128,7 @@ void *_switch_to(void *prev, void *next, void *last)
prev= current;
} while(current->thread.saved_task);
- return(current->thread.prev_sched);
+ return(current->thread.prev_sched);
}
@@ -142,19 +142,19 @@ void release_thread(struct task_struct *task)
{
CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task));
}
-
+
void exit_thread(void)
{
unprotect_stack((unsigned long) current_thread);
}
-
+
void *get_current(void)
{
return(current);
}
int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
- unsigned long stack_top, struct task_struct * p,
+ unsigned long stack_top, struct task_struct * p,
struct pt_regs *regs)
{
int ret;
@@ -183,11 +183,11 @@ void initial_thread_cb(void (*proc)(void *), void *arg)
int save_kmalloc_ok = kmalloc_ok;
kmalloc_ok = 0;
- CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
+ CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc,
arg);
kmalloc_ok = save_kmalloc_ok;
}
-
+
unsigned long stack_sp(unsigned long page)
{
return(page + PAGE_SIZE - sizeof(void *));
@@ -211,7 +211,7 @@ void default_idle(void)
*/
if(need_resched())
schedule();
-
+
idle_sleep(10);
}
}
@@ -226,7 +226,7 @@ int page_size(void)
return(PAGE_SIZE);
}
-void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
+void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
pte_t *pte_out)
{
pgd_t *pgd;
@@ -235,7 +235,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
pte_t *pte;
pte_t ptent;
- if(task->mm == NULL)
+ if(task->mm == NULL)
return(ERR_PTR(-EINVAL));
pgd = pgd_offset(task->mm, addr);
if(!pgd_present(*pgd))
@@ -246,7 +246,7 @@ void *um_virt_to_phys(struct task_struct *task, unsigned long addr,
return(ERR_PTR(-EINVAL));
pmd = pmd_offset(pud, addr);
- if(!pmd_present(*pmd))
+ if(!pmd_present(*pmd))
return(ERR_PTR(-EINVAL));
pte = pte_offset_kernel(pmd, addr);
@@ -271,7 +271,7 @@ char *current_cmd(void)
void force_sigbus(void)
{
- printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
+ printk(KERN_ERR "Killing pid %d because of a lack of memory\n",
current->pid);
lock_kernel();
sigaddset(&current->pending.signal, SIGBUS);
diff --git a/arch/um/kernel/sigio.c b/arch/um/kernel/sigio.c
index 0ad755ceb212..2b0ab438301c 100644
--- a/arch/um/kernel/sigio.c
+++ b/arch/um/kernel/sigio.c
@@ -17,7 +17,7 @@
/* Protected by sigio_lock() called from write_sigio_workaround */
static int sigio_irq_fd = -1;
-static irqreturn_t sigio_interrupt(int irq, void *data, struct pt_regs *unused)
+static irqreturn_t sigio_interrupt(int irq, void *data)
{
char c;
diff --git a/arch/um/kernel/signal.c b/arch/um/kernel/signal.c
index 4aa9808ba264..2a32e5e8e9c9 100644
--- a/arch/um/kernel/signal.c
+++ b/arch/um/kernel/signal.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/stddef.h"
#include "linux/sys.h"
#include "linux/sched.h"
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index ea3a8e409a6e..3e3fa7e7e3cf 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,8 +3,7 @@
# Licensed under the GPL
#
-obj-y := clone.o exec_kern.o mem.o mmu.o process_kern.o \
- syscall.o tlb.o uaccess.o
+obj-y := clone.o exec.o mem.o mmu.o process.o syscall.o tlb.o uaccess.o
# clone.o is in the stub, so it can't be built with profiling
# GCC hardened also auto-enables -fpic, but we need %ebx so it can't work ->
diff --git a/arch/um/kernel/skas/exec.c b/arch/um/kernel/skas/exec.c
new file mode 100644
index 000000000000..54b795951372
--- /dev/null
+++ b/arch/um/kernel/skas/exec.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include "linux/kernel.h"
+#include "asm/current.h"
+#include "asm/page.h"
+#include "asm/signal.h"
+#include "asm/ptrace.h"
+#include "asm/uaccess.h"
+#include "asm/mmu_context.h"
+#include "tlb.h"
+#include "skas.h"
+#include "um_mmu.h"
+#include "os.h"
+
+void flush_thread_skas(void)
+{
+ force_flush_all();
+ switch_mm_skas(&current->mm->context.skas.id);
+}
+
+void start_thread_skas(struct pt_regs *regs, unsigned long eip,
+ unsigned long esp)
+{
+ set_fs(USER_DS);
+ PT_REGS_IP(regs) = eip;
+ PT_REGS_SP(regs) = esp;
+}
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
deleted file mode 100644
index 77ed7bbab219..000000000000
--- a/arch/um/kernel/skas/exec_kern.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include "linux/kernel.h"
-#include "asm/current.h"
-#include "asm/page.h"
-#include "asm/signal.h"
-#include "asm/ptrace.h"
-#include "asm/uaccess.h"
-#include "asm/mmu_context.h"
-#include "tlb.h"
-#include "skas.h"
-#include "um_mmu.h"
-#include "os.h"
-
-void flush_thread_skas(void)
-{
- force_flush_all();
- switch_mm_skas(&current->mm->context.skas.id);
-}
-
-void start_thread_skas(struct pt_regs *regs, unsigned long eip,
- unsigned long esp)
-{
- set_fs(USER_DS);
- PT_REGS_IP(regs) = eip;
- PT_REGS_SP(regs) = esp;
-}
-
-/*
- * 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:
- */
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 27bbf54b1e52..0d2cce621134 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/mm.h"
#include "asm/pgtable.h"
#include "mem_user.h"
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 79c22707a637..2c6d090a2e87 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/sched.h"
#include "linux/list.h"
#include "linux/spinlock.h"
@@ -61,8 +60,7 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
#endif
*pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
- *pte = pte_mkexec(*pte);
- *pte = pte_wrprotect(*pte);
+ *pte = pte_mkread(*pte);
return(0);
out_pmd:
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process.c
index 55caeec8b257..ae4fa71d3b8b 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process.c
@@ -33,7 +33,7 @@ void switch_to_skas(void *prev, void *next)
switch_timers(0);
switch_threads(&from->thread.mode.skas.switch_buf,
- to->thread.mode.skas.switch_buf);
+ &to->thread.mode.skas.switch_buf);
arch_switch_to_skas(current->thread.prev_sched, current);
@@ -43,21 +43,21 @@ void switch_to_skas(void *prev, void *next)
extern void schedule_tail(struct task_struct *prev);
-void new_thread_handler(int sig)
+/* This is called magically, by its address being stuffed in a jmp_buf
+ * and being longjmp-d to.
+ */
+void new_thread_handler(void)
{
int (*fn)(void *), n;
void *arg;
- fn = current->thread.request.u.thread.proc;
- arg = current->thread.request.u.thread.arg;
- os_usr1_signal(1);
- thread_wait(&current->thread.mode.skas.switch_buf,
- current->thread.mode.skas.fork_buf);
-
if(current->thread.prev_sched != NULL)
schedule_tail(current->thread.prev_sched);
current->thread.prev_sched = NULL;
+ fn = current->thread.request.u.thread.proc;
+ arg = current->thread.request.u.thread.arg;
+
/* The return value is 1 if the kernel thread execs a process,
* 0 if it just exits
*/
@@ -70,22 +70,13 @@ void new_thread_handler(int sig)
else do_exit(0);
}
-void new_thread_proc(void *stack, void (*handler)(int sig))
-{
- init_new_thread_stack(stack, handler);
- os_usr1_process(os_getpid());
-}
-
void release_thread_skas(struct task_struct *task)
{
}
-void fork_handler(int sig)
+/* Called magically, see new_thread_handler above */
+void fork_handler(void)
{
- os_usr1_signal(1);
- thread_wait(&current->thread.mode.skas.switch_buf,
- current->thread.mode.skas.fork_buf);
-
force_flush_all();
if(current->thread.prev_sched == NULL)
panic("blech");
@@ -109,7 +100,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
unsigned long stack_top, struct task_struct * p,
struct pt_regs *regs)
{
- void (*handler)(int);
+ void (*handler)(void);
if(current->thread.forking){
memcpy(&p->thread.regs.regs.skas, &regs->regs.skas,
@@ -123,12 +114,12 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
}
else {
init_thread_registers(&p->thread.regs.regs);
- p->thread.request.u.thread = current->thread.request.u.thread;
+ p->thread.request.u.thread = current->thread.request.u.thread;
handler = new_thread_handler;
}
new_thread(task_stack_page(p), &p->thread.mode.skas.switch_buf,
- &p->thread.mode.skas.fork_buf, handler);
+ handler);
return(0);
}
@@ -164,7 +155,7 @@ static int start_kernel_proc(void *unused)
cpu_tasks[0].pid = pid;
cpu_tasks[0].task = current;
#ifdef CONFIG_SMP
- cpu_online_map = cpumask_of_cpu(0);
+ cpu_online_map = cpumask_of_cpu(0);
#endif
start_kernel();
return(0);
@@ -182,8 +173,7 @@ int start_uml_skas(void)
init_task.thread.request.u.thread.proc = start_kernel_proc;
init_task.thread.request.u.thread.arg = NULL;
return(start_idle_thread(task_stack_page(&init_task),
- &init_task.thread.mode.skas.switch_buf,
- &init_task.thread.mode.skas.fork_buf));
+ &init_task.thread.mode.skas.switch_buf));
}
int external_pid_skas(struct task_struct *task)
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 6e84963dfc29..27eb29ce666b 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,7 +6,6 @@
#include "linux/stddef.h"
#include "linux/sched.h"
-#include "linux/config.h"
#include "linux/mm.h"
#include "asm/page.h"
#include "asm/pgtable.h"
diff --git a/arch/um/kernel/smp.c b/arch/um/kernel/smp.c
index 511116aebaf7..759b07053160 100644
--- a/arch/um/kernel/smp.c
+++ b/arch/um/kernel/smp.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/percpu.h"
#include "asm/pgalloc.h"
#include "asm/tlb.h"
diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c
index 48cf88dd02d4..f5ed8624648b 100644
--- a/arch/um/kernel/syscall.c
+++ b/arch/um/kernel/syscall.c
@@ -110,7 +110,7 @@ long sys_uname(struct old_utsname __user * name)
if (!name)
return -EFAULT;
down_read(&uts_sem);
- err = copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
return err?-EFAULT:0;
}
@@ -126,21 +126,21 @@ long sys_olduname(struct oldold_utsname __user * name)
down_read(&uts_sem);
- error = __copy_to_user(&name->sysname,&system_utsname.sysname,
+ error = __copy_to_user(&name->sysname, &utsname()->sysname,
__OLD_UTS_LEN);
- error |= __put_user(0,name->sysname+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->nodename,&system_utsname.nodename,
+ error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->nodename, &utsname()->nodename,
__OLD_UTS_LEN);
- error |= __put_user(0,name->nodename+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->release,&system_utsname.release,
+ error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->release, &utsname()->release,
__OLD_UTS_LEN);
- error |= __put_user(0,name->release+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->version,&system_utsname.version,
+ error |= __put_user(0, name->release + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->version, &utsname()->version,
__OLD_UTS_LEN);
- error |= __put_user(0,name->version+__OLD_UTS_LEN);
- error |= __copy_to_user(&name->machine,&system_utsname.machine,
+ error |= __put_user(0, name->version + __OLD_UTS_LEN);
+ error |= __copy_to_user(&name->machine, &utsname()->machine,
__OLD_UTS_LEN);
- error |= __put_user(0,name->machine+__OLD_UTS_LEN);
+ error |= __put_user(0, name->machine + __OLD_UTS_LEN);
up_read(&uts_sem);
@@ -164,3 +164,16 @@ int next_syscall_index(int limit)
spin_unlock(&syscall_lock);
return(ret);
}
+
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ mm_segment_t fs;
+ int ret;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ ret = um_execve(filename, argv, envp);
+ set_fs(fs);
+
+ return ret;
+}
diff --git a/arch/um/kernel/sysrq.c b/arch/um/kernel/sysrq.c
index b331e970002f..239c98054dec 100644
--- a/arch/um/kernel/sysrq.c
+++ b/arch/um/kernel/sysrq.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/sched.h"
#include "linux/kernel.h"
#include "linux/module.h"
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index 2454bbd9555d..2e354b3ca060 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -86,16 +86,16 @@ static inline unsigned long long get_time(void)
return nsecs;
}
-irqreturn_t um_timer(int irq, void *dev, struct pt_regs *regs)
+irqreturn_t um_timer(int irq, void *dev)
{
unsigned long long nsecs;
unsigned long flags;
write_seqlock_irqsave(&xtime_lock, flags);
- do_timer(regs);
+ do_timer(1);
- nsecs = get_time() + local_offset;
+ nsecs = get_time();
xtime.tv_sec = nsecs / NSEC_PER_SEC;
xtime.tv_nsec = nsecs - xtime.tv_sec * NSEC_PER_SEC;
diff --git a/arch/um/kernel/trap.c b/arch/um/kernel/trap.c
index e5eeaf2b6af1..b5f124a2f6ae 100644
--- a/arch/um/kernel/trap.c
+++ b/arch/um/kernel/trap.c
@@ -8,7 +8,6 @@
#include "linux/sched.h"
#include "linux/mm.h"
#include "linux/spinlock.h"
-#include "linux/config.h"
#include "linux/init.h"
#include "linux/ptrace.h"
#include "asm/semaphore.h"
@@ -120,7 +119,7 @@ out_nosemaphore:
* us unable to handle the page fault gracefully.
*/
out_of_memory:
- if (current->pid == 1) {
+ if (is_init(current)) {
up_read(&mm->mmap_sem);
yield();
down_read(&mm->mmap_sem);
@@ -140,14 +139,6 @@ void segv_handler(int sig, union uml_pt_regs *regs)
segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
}
-struct kern_handlers handlinfo_kern = {
- .relay_signal = relay_signal,
- .winch = winch,
- .bus_handler = relay_signal,
- .page_fault = segv_handler,
- .sigio_handler = sigio_handler,
- .timer_handler = timer_handler
-};
/*
* We give a *copy* of the faultinfo in the regs to segv.
* This must be done, since nesting SEGVs could overwrite
@@ -253,6 +244,15 @@ void winch(int sig, union uml_pt_regs *regs)
do_IRQ(WINCH_IRQ, regs);
}
+const struct kern_handlers handlinfo_kern = {
+ .relay_signal = relay_signal,
+ .winch = winch,
+ .bus_handler = bus_handler,
+ .page_fault = segv_handler,
+ .sigio_handler = sigio_handler,
+ .timer_handler = timer_handler
+};
+
void trap_init(void)
{
}
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
index 26506388a6aa..68e1bf63cd0a 100644
--- a/arch/um/kernel/tt/gdb_kern.c
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -4,7 +4,6 @@
*/
#include "linux/init.h"
-#include "linux/config.h"
#include "mconsole_kern.h"
#ifdef CONFIG_MCONSOLE
diff --git a/arch/um/kernel/tt/mem.c b/arch/um/kernel/tt/mem.c
index 84a23b14f770..4d1929dfa285 100644
--- a/arch/um/kernel/tt/mem.c
+++ b/arch/um/kernel/tt/mem.c
@@ -4,7 +4,6 @@
*/
#include "linux/stddef.h"
-#include "linux/config.h"
#include "linux/mm.h"
#include "asm/uaccess.h"
#include "mem_user.h"
diff --git a/arch/um/kernel/tt/uaccess_user.c b/arch/um/kernel/tt/uaccess_user.c
index 6c92bbccb49c..ed1abcf4d057 100644
--- a/arch/um/kernel/tt/uaccess_user.c
+++ b/arch/um/kernel/tt/uaccess_user.c
@@ -4,13 +4,13 @@
* Licensed under the GPL
*/
-#include <setjmp.h>
#include <string.h>
#include "user_util.h"
#include "uml_uaccess.h"
#include "task.h"
#include "kern_util.h"
#include "os.h"
+#include "longjmp.h"
int __do_copy_from_user(void *to, const void *from, int n,
void **fault_addr, void **fault_catcher)
@@ -80,10 +80,10 @@ int __do_strnlen_user(const char *str, unsigned long n,
struct tt_regs save = TASK_REGS(get_current())->tt;
int ret;
unsigned long *faddrp = (unsigned long *)fault_addr;
- sigjmp_buf jbuf;
+ jmp_buf jbuf;
*fault_catcher = &jbuf;
- if(sigsetjmp(jbuf, 1) == 0)
+ if(UML_SETJMP(&jbuf) == 0)
ret = strlen(str) + 1;
else ret = *faddrp - (unsigned long) str;
diff --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 7896cf98232d..66f43c906821 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/sched.h"
#include "linux/notifier.h"
@@ -106,7 +105,7 @@ static void c_stop(struct seq_file *m, void *v)
{
}
-struct seq_operations cpuinfo_op = {
+const struct seq_operations cpuinfo_op = {
.start = c_start,
.next = c_next,
.stop = c_stop,
@@ -167,7 +166,7 @@ static char *usage_string =
static int __init uml_version_setup(char *line, int *add)
{
- printf("%s\n", system_utsname.release);
+ printf("%s\n", init_utsname()->release);
exit(0);
return 0;
@@ -278,7 +277,7 @@ static int __init Usage(char *line, int *add)
{
const char **p;
- printf(usage_string, system_utsname.release);
+ printf(usage_string, init_utsname()->release);
p = &__uml_help_start;
while (p < &__uml_help_end) {
printf("%s", *p);
@@ -403,7 +402,7 @@ int linux_main(int argc, char **argv)
/* Reserve up to 4M after the current brk */
uml_reserved = ROUND_4M(brk_start) + (1 << 22);
- setup_machinename(system_utsname.machine);
+ setup_machinename(init_utsname()->machine);
#ifdef CONFIG_CMDLINE_ON_HOST
argv1_begin = argv[1];
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile
index f4bfc4c7ccac..b4183929b32c 100644
--- a/arch/um/os-Linux/Makefile
+++ b/arch/um/os-Linux/Makefile
@@ -4,15 +4,19 @@
#
obj-y = aio.o elf_aux.o file.o helper.o irq.o main.o mem.o process.o sigio.o \
- signal.o start_up.o time.o trap.o tt.o tty.o uaccess.o umid.o tls.o \
+ signal.o start_up.o time.o trap.o tty.o uaccess.o umid.o tls.o \
user_syms.o util.o drivers/ sys-$(SUBARCH)/
obj-$(CONFIG_MODE_SKAS) += skas/
+
+obj-$(CONFIG_MODE_TT) += tt.o
+user-objs-$(CONFIG_MODE_TT) += tt.o
+
obj-$(CONFIG_TTY_LOG) += tty_log.o
user-objs-$(CONFIG_TTY_LOG) += tty_log.o
USER_OBJS := $(user-objs-y) aio.o elf_aux.o file.o helper.o irq.o main.o mem.o \
- process.o sigio.o signal.o start_up.o time.o trap.o tt.o tty.o tls.o \
+ process.o sigio.o signal.o start_up.o time.o trap.o tty.o tls.o \
uaccess.o umid.o util.o
CFLAGS_user_syms.o += -DSUBARCH_$(SUBARCH)
diff --git a/arch/um/os-Linux/drivers/etap.h b/arch/um/os-Linux/drivers/etap.h
index b84f6c4740f7..57ecdaf2f67e 100644
--- a/arch/um/os-Linux/drivers/etap.h
+++ b/arch/um/os-Linux/drivers/etap.h
@@ -13,7 +13,7 @@ struct ethertap_data {
void *dev;
};
-extern struct net_user_info ethertap_user_info;
+extern const struct net_user_info ethertap_user_info;
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c
index 768606bec233..16385e2ada85 100644
--- a/arch/um/os-Linux/drivers/ethertap_kern.c
+++ b/arch/um/os-Linux/drivers/ethertap_kern.c
@@ -65,7 +65,7 @@ static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp)
return(net_send(fd, (*skb)->data, (*skb)->len));
}
-struct net_kern_info ethertap_kern_info = {
+const struct net_kern_info ethertap_kern_info = {
.init = etap_init,
.protocol = eth_protocol,
.read = etap_read,
diff --git a/arch/um/os-Linux/drivers/ethertap_user.c b/arch/um/os-Linux/drivers/ethertap_user.c
index 8f49507e64ef..863981ba1468 100644
--- a/arch/um/os-Linux/drivers/ethertap_user.c
+++ b/arch/um/os-Linux/drivers/ethertap_user.c
@@ -20,6 +20,7 @@
#include "net_user.h"
#include "etap.h"
#include "os.h"
+#include "um_malloc.h"
#define MAX_PACKET ETH_MAX_PACKET
@@ -216,7 +217,7 @@ static void etap_del_addr(unsigned char *addr, unsigned char *netmask,
etap_close_addr(addr, netmask, &pri->control_fd);
}
-struct net_user_info ethertap_user_info = {
+const struct net_user_info ethertap_user_info = {
.init = etap_user_init,
.open = etap_open,
.close = etap_close,
diff --git a/arch/um/os-Linux/drivers/tuntap.h b/arch/um/os-Linux/drivers/tuntap.h
index 25d4a2868814..d3e8d3af6245 100644
--- a/arch/um/os-Linux/drivers/tuntap.h
+++ b/arch/um/os-Linux/drivers/tuntap.h
@@ -16,7 +16,7 @@ struct tuntap_data {
void *dev;
};
-extern struct net_user_info tuntap_user_info;
+extern const struct net_user_info tuntap_user_info;
#endif
diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c
index 190009a6f89c..0edbac63c527 100644
--- a/arch/um/os-Linux/drivers/tuntap_kern.c
+++ b/arch/um/os-Linux/drivers/tuntap_kern.c
@@ -53,7 +53,7 @@ static int tuntap_write(int fd, struct sk_buff **skb,
return(net_write(fd, (*skb)->data, (*skb)->len));
}
-struct net_kern_info tuntap_kern_info = {
+const struct net_kern_info tuntap_kern_info = {
.init = tuntap_init,
.protocol = eth_protocol,
.read = tuntap_read,
diff --git a/arch/um/os-Linux/drivers/tuntap_user.c b/arch/um/os-Linux/drivers/tuntap_user.c
index 87c3aa0252db..e846b23f7558 100644
--- a/arch/um/os-Linux/drivers/tuntap_user.c
+++ b/arch/um/os-Linux/drivers/tuntap_user.c
@@ -205,7 +205,7 @@ static int tuntap_set_mtu(int mtu, void *data)
return(mtu);
}
-struct net_user_info tuntap_user_info = {
+const struct net_user_info tuntap_user_info = {
.init = tuntap_user_init,
.open = tuntap_open,
.close = tuntap_close,
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c
index cd15b9df5b5c..d13299cfa318 100644
--- a/arch/um/os-Linux/helper.c
+++ b/arch/um/os-Linux/helper.c
@@ -35,22 +35,23 @@ static int helper_child(void *arg)
char **argv = data->argv;
int errval;
- if(helper_pause){
+ if (helper_pause){
signal(SIGHUP, helper_hup);
pause();
}
- if(data->pre_exec != NULL)
+ if (data->pre_exec != NULL)
(*data->pre_exec)(data->pre_data);
execvp(argv[0], argv);
errval = -errno;
printk("helper_child - execve of '%s' failed - errno = %d\n", argv[0], errno);
os_write_file(data->fd, &errval, sizeof(errval));
kill(os_getpid(), SIGKILL);
- return(0);
+ return 0;
}
/* Returns either the pid of the child process we run or -E* on failure.
- * XXX The alloc_stack here breaks if this is called in the tracing thread */
+ * XXX The alloc_stack here breaks if this is called in the tracing thread, so
+ * we need to receive a preallocated stack (a local buffer is ok). */
int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
unsigned long *stack_out)
{
@@ -58,20 +59,21 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
unsigned long stack, sp;
int pid, fds[2], ret, n;
- if((stack_out != NULL) && (*stack_out != 0))
+ if ((stack_out != NULL) && (*stack_out != 0))
stack = *stack_out;
- else stack = alloc_stack(0, __cant_sleep());
- if(stack == 0)
+ else
+ stack = alloc_stack(0, __cant_sleep());
+ if (stack == 0)
return -ENOMEM;
ret = os_pipe(fds, 1, 0);
- if(ret < 0){
+ if (ret < 0) {
printk("run_helper : pipe failed, ret = %d\n", -ret);
goto out_free;
}
ret = os_set_exec_close(fds[1], 1);
- if(ret < 0){
+ if (ret < 0) {
printk("run_helper : setting FD_CLOEXEC failed, ret = %d\n",
-ret);
goto out_close;
@@ -83,7 +85,7 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
data.argv = argv;
data.fd = fds[1];
pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data);
- if(pid < 0){
+ if (pid < 0) {
ret = -errno;
printk("run_helper : clone failed, errno = %d\n", errno);
goto out_close;
@@ -95,10 +97,10 @@ int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv,
/* Read the errno value from the child, if the exec failed, or get 0 if
* the exec succeeded because the pipe fd was set as close-on-exec. */
n = os_read_file(fds[0], &ret, sizeof(ret));
- if(n == 0)
+ if (n == 0) {
ret = pid;
- else {
- if(n < 0){
+ } else {
+ if (n < 0) {
printk("run_helper : read on pipe failed, ret = %d\n",
-n);
ret = n;
@@ -112,10 +114,9 @@ out_close:
close(fds[1]);
close(fds[0]);
out_free:
- if(stack_out == NULL)
+ if ((stack_out == NULL) || (*stack_out == 0))
free_stack(stack, 0);
- else *stack_out = stack;
- return(ret);
+ return ret;
}
int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
@@ -125,31 +126,32 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
int pid, status, err;
stack = alloc_stack(stack_order, __cant_sleep());
- if(stack == 0) return(-ENOMEM);
+ if (stack == 0)
+ return -ENOMEM;
sp = stack + (page_size() << stack_order) - sizeof(void *);
pid = clone(proc, (void *) sp, flags | SIGCHLD, arg);
- if(pid < 0){
+ if (pid < 0) {
err = -errno;
printk("run_helper_thread : clone failed, errno = %d\n",
errno);
return err;
}
- if(stack_out == NULL){
+ if (stack_out == NULL) {
CATCH_EINTR(pid = waitpid(pid, &status, 0));
- if(pid < 0){
+ if (pid < 0) {
err = -errno;
printk("run_helper_thread - wait failed, errno = %d\n",
errno);
pid = err;
}
- if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
+ if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0))
printk("run_helper_thread - thread returned status "
"0x%x\n", status);
free_stack(stack, stack_order);
- }
- else *stack_out = stack;
- return(pid);
+ } else
+ *stack_out = stack;
+ return pid;
}
int helper_wait(int pid)
@@ -157,9 +159,9 @@ int helper_wait(int pid)
int ret;
CATCH_EINTR(ret = waitpid(pid, NULL, WNOHANG));
- if(ret < 0){
+ if (ret < 0) {
ret = -errno;
printk("helper_wait : waitpid failed, errno = %d\n", errno);
}
- return(ret);
+ return ret;
}
diff --git a/arch/um/os-Linux/irq.c b/arch/um/os-Linux/irq.c
index a97206df5b52..d46b818c1311 100644
--- a/arch/um/os-Linux/irq.c
+++ b/arch/um/os-Linux/irq.c
@@ -18,6 +18,7 @@
#include "sigio.h"
#include "irq_user.h"
#include "os.h"
+#include "um_malloc.h"
static struct pollfd *pollfds = NULL;
static int pollfds_num = 0;
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c
index d1c5670787dc..685feaab65d2 100644
--- a/arch/um/os-Linux/main.c
+++ b/arch/um/os-Linux/main.c
@@ -23,6 +23,7 @@
#include "choose-mode.h"
#include "uml-config.h"
#include "os.h"
+#include "um_malloc.h"
/* Set in set_stklim, which is called from main and __wrap_malloc.
* __wrap_malloc only calls it if main hasn't started.
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c
index b170b4704dc4..4203681e508d 100644
--- a/arch/um/os-Linux/mem.c
+++ b/arch/um/os-Linux/mem.c
@@ -132,6 +132,9 @@ err:
else if(found < 0)
printf("read returned errno %d\n", -found);
+out:
+ close(fd);
+
return;
found:
@@ -141,11 +144,12 @@ found:
if(strncmp(buf, "tmpfs", strlen("tmpfs"))){
printf("not tmpfs\n");
- return;
+ goto out;
}
printf("OK\n");
default_tmpdir = "/dev/shm";
+ goto out;
}
/*
diff --git a/arch/um/os-Linux/process.c b/arch/um/os-Linux/process.c
index ff203625a4bd..51f0893640a6 100644
--- a/arch/um/os-Linux/process.c
+++ b/arch/um/os-Linux/process.c
@@ -11,6 +11,7 @@
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/mman.h>
+#include <sys/syscall.h>
#include "ptrace_user.h"
#include "os.h"
#include "user.h"
@@ -140,11 +141,9 @@ void os_usr1_process(int pid)
* syscalls, and also breaks with clone(), which does not unshare the TLS.
*/
-inline _syscall0(pid_t, getpid)
-
int os_getpid(void)
{
- return(getpid());
+ return(syscall(__NR_getpid));
}
int os_getpgrp(void)
diff --git a/arch/um/os-Linux/sigio.c b/arch/um/os-Linux/sigio.c
index f6457765b17d..925a65240cfe 100644
--- a/arch/um/os-Linux/sigio.c
+++ b/arch/um/os-Linux/sigio.c
@@ -19,6 +19,7 @@
#include "user_util.h"
#include "sigio.h"
#include "os.h"
+#include "um_malloc.h"
/* Protected by sigio_lock(), also used by sigio_cleanup, which is an
* exitcall.
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 42e3d1ed802c..cb9ab54146cc 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -444,56 +444,22 @@ void map_stub_pages(int fd, unsigned long code,
}
}
-void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
- void (*handler)(int))
+void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
{
- unsigned long flags;
- jmp_buf switch_buf, fork_buf;
-
- *switch_buf_ptr = &switch_buf;
- *fork_buf_ptr = &fork_buf;
-
- /* Somewhat subtle - siglongjmp restores the signal mask before doing
- * the longjmp. This means that when jumping from one stack to another
- * when the target stack has interrupts enabled, an interrupt may occur
- * on the source stack. This is bad when starting up a process because
- * it's not supposed to get timer ticks until it has been scheduled.
- * So, we disable interrupts around the sigsetjmp to ensure that
- * they can't happen until we get back here where they are safe.
- */
- flags = get_signals();
- block_signals();
- if(UML_SETJMP(&fork_buf) == 0)
- new_thread_proc(stack, handler);
-
- remove_sigstack();
-
- set_signals(flags);
+ (*buf)[0].JB_IP = (unsigned long) handler;
+ (*buf)[0].JB_SP = (unsigned long) stack +
+ (PAGE_SIZE << UML_CONFIG_KERNEL_STACK_ORDER) - sizeof(void *);
}
#define INIT_JMP_NEW_THREAD 0
-#define INIT_JMP_REMOVE_SIGSTACK 1
-#define INIT_JMP_CALLBACK 2
-#define INIT_JMP_HALT 3
-#define INIT_JMP_REBOOT 4
-
-void thread_wait(void *sw, void *fb)
-{
- jmp_buf buf, **switch_buf = sw, *fork_buf;
-
- *switch_buf = &buf;
- fork_buf = fb;
- if(UML_SETJMP(&buf) == 0)
- UML_LONGJMP(fork_buf, INIT_JMP_REMOVE_SIGSTACK);
-}
+#define INIT_JMP_CALLBACK 1
+#define INIT_JMP_HALT 2
+#define INIT_JMP_REBOOT 3
-void switch_threads(void *me, void *next)
+void switch_threads(jmp_buf *me, jmp_buf *you)
{
- jmp_buf my_buf, **me_ptr = me, *next_buf = next;
-
- *me_ptr = &my_buf;
- if(UML_SETJMP(&my_buf) == 0)
- UML_LONGJMP(next_buf, 1);
+ if(UML_SETJMP(me) == 0)
+ UML_LONGJMP(you, 1);
}
static jmp_buf initial_jmpbuf;
@@ -503,23 +469,21 @@ static void (*cb_proc)(void *arg);
static void *cb_arg;
static jmp_buf *cb_back;
-int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
+int start_idle_thread(void *stack, jmp_buf *switch_buf)
{
- jmp_buf **switch_buf = switch_buf_ptr;
int n;
set_handler(SIGWINCH, (__sighandler_t) sig_handler,
SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGALRM,
SIGVTALRM, -1);
- *fork_buf_ptr = &initial_jmpbuf;
n = UML_SETJMP(&initial_jmpbuf);
switch(n){
case INIT_JMP_NEW_THREAD:
- new_thread_proc((void *) stack, new_thread_handler);
- break;
- case INIT_JMP_REMOVE_SIGSTACK:
- remove_sigstack();
+ (*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 *);
break;
case INIT_JMP_CALLBACK:
(*cb_proc)(cb_arg);
@@ -534,7 +498,7 @@ int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr)
default:
panic("Bad sigsetjmp return in start_idle_thread - %d\n", n);
}
- UML_LONGJMP(*switch_buf, 1);
+ UML_LONGJMP(switch_buf, 1);
}
void initial_thread_cb_skas(void (*proc)(void *), void *arg)
diff --git a/arch/um/os-Linux/sys-i386/tls.c b/arch/um/os-Linux/sys-i386/tls.c
index 120abbe4e3ce..6e945ab45843 100644
--- a/arch/um/os-Linux/sys-i386/tls.c
+++ b/arch/um/os-Linux/sys-i386/tls.c
@@ -1,10 +1,9 @@
#include <errno.h>
#include <linux/unistd.h>
+#include <sys/syscall.h>
#include "sysdep/tls.h"
#include "user_util.h"
-static _syscall1(int, get_thread_area, user_desc_t *, u_info);
-
/* Checks whether host supports TLS, and sets *tls_min according to the value
* valid on the host.
* i386 host have it == 6; x86_64 host have it == 12, for i386 emulation. */
@@ -17,7 +16,7 @@ void check_host_supports_tls(int *supports_tls, int *tls_min) {
user_desc_t info;
info.entry_number = val[i];
- if (get_thread_area(&info) == 0) {
+ if (syscall(__NR_get_thread_area, &info) == 0) {
*tls_min = val[i];
*supports_tls = 1;
return;
diff --git a/arch/um/os-Linux/time.c b/arch/um/os-Linux/time.c
index 38be096e750f..2115b8beb541 100644
--- a/arch/um/os-Linux/time.c
+++ b/arch/um/os-Linux/time.c
@@ -16,6 +16,7 @@
#include "process.h"
#include "kern_constants.h"
#include "os.h"
+#include "uml-config.h"
int set_interval(int is_virtual)
{
@@ -30,7 +31,7 @@ int set_interval(int is_virtual)
return 0;
}
-#ifdef CONFIG_MODE_TT
+#ifdef UML_CONFIG_MODE_TT
void enable_timer(void)
{
set_interval(1);
diff --git a/arch/um/os-Linux/tls.c b/arch/um/os-Linux/tls.c
index 9cb09a45546b..a2de2580b8af 100644
--- a/arch/um/os-Linux/tls.c
+++ b/arch/um/os-Linux/tls.c
@@ -1,5 +1,6 @@
#include <errno.h>
#include <sys/ptrace.h>
+#include <sys/syscall.h>
#include <asm/ldt.h>
#include "sysdep/tls.h"
#include "uml-config.h"
@@ -48,14 +49,11 @@ int os_get_thread_area(user_desc_t *info, int pid)
#ifdef UML_CONFIG_MODE_TT
#include "linux/unistd.h"
-static _syscall1(int, get_thread_area, user_desc_t *, u_info);
-static _syscall1(int, set_thread_area, user_desc_t *, u_info);
-
int do_set_thread_area_tt(user_desc_t *info)
{
int ret;
- ret = set_thread_area(info);
+ ret = syscall(__NR_set_thread_area,info);
if (ret < 0) {
ret = -errno;
}
@@ -66,7 +64,7 @@ int do_get_thread_area_tt(user_desc_t *info)
{
int ret;
- ret = get_thread_area(info);
+ ret = syscall(__NR_get_thread_area,info);
if (ret < 0) {
ret = -errno;
}
diff --git a/arch/um/os-Linux/tt.c b/arch/um/os-Linux/tt.c
index 5461a065bbb9..3dc3a02d6263 100644
--- a/arch/um/os-Linux/tt.c
+++ b/arch/um/os-Linux/tt.c
@@ -10,7 +10,6 @@
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
-#include <setjmp.h>
#include <sys/time.h>
#include <sys/ptrace.h>
#include <linux/ptrace.h>
diff --git a/arch/um/os-Linux/util.c b/arch/um/os-Linux/util.c
index 3f5b1514e8a7..56b8a50e8bc2 100644
--- a/arch/um/os-Linux/util.c
+++ b/arch/um/os-Linux/util.c
@@ -80,11 +80,18 @@ void setup_machinename(char *machine_out)
struct utsname host;
uname(&host);
-#if defined(UML_CONFIG_UML_X86) && !defined(UML_CONFIG_64BIT)
+#ifdef UML_CONFIG_UML_X86
+# ifndef UML_CONFIG_64BIT
if (!strcmp(host.machine, "x86_64")) {
strcpy(machine_out, "i686");
return;
}
+# else
+ if (!strcmp(host.machine, "i686")) {
+ strcpy(machine_out, "x86_64");
+ return;
+ }
+# endif
#endif
strcpy(machine_out, host.machine);
}
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index 69971b78beaf..e299ee5a753d 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -4,7 +4,6 @@
*/
#include "linux/stddef.h"
-#include "linux/config.h"
#include "linux/sched.h"
#include "linux/slab.h"
#include "linux/types.h"
diff --git a/arch/um/sys-i386/sysrq.c b/arch/um/sys-i386/sysrq.c
index d5244f070539..171b3e9dc867 100644
--- a/arch/um/sys-i386/sysrq.c
+++ b/arch/um/sys-i386/sysrq.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/smp.h"
#include "linux/sched.h"
diff --git a/arch/um/sys-i386/tls.c b/arch/um/sys-i386/tls.c
index 71b9796258ef..643dab585727 100644
--- a/arch/um/sys-i386/tls.c
+++ b/arch/um/sys-i386/tls.c
@@ -3,7 +3,6 @@
* Licensed under the GPL
*/
-#include "linux/config.h"
#include "linux/kernel.h"
#include "linux/sched.h"
#include "linux/slab.h"
diff --git a/arch/um/sys-i386/unmap.c b/arch/um/sys-i386/unmap.c
index 1b0ad0e4adcd..8e55cd5d3d07 100644
--- a/arch/um/sys-i386/unmap.c
+++ b/arch/um/sys-i386/unmap.c
@@ -5,20 +5,17 @@
#include <linux/mman.h>
#include <asm/unistd.h>
+#include <sys/syscall.h>
-static int errno;
-
-static inline _syscall2(int,munmap,void *,start,size_t,len)
-static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
int switcheroo(int fd, int prot, void *from, void *to, int size)
{
- if(munmap(to, size) < 0){
+ if (syscall(__NR_munmap, to, size) < 0){
return(-1);
}
- if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){
+ if (syscall(__NR_mmap2, to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){
return(-1);
}
- if(munmap(from, size) < 0){
+ if (syscall(__NR_munmap, from, size) < 0){
return(-1);
}
return(0);
diff --git a/arch/um/sys-x86_64/ksyms.c b/arch/um/sys-x86_64/ksyms.c
index 859273808203..12c593607c59 100644
--- a/arch/um/sys-x86_64/ksyms.c
+++ b/arch/um/sys-x86_64/ksyms.c
@@ -14,6 +14,3 @@ EXPORT_SYMBOL(__up_wakeup);
/*XXX: we need them because they would be exported by x86_64 */
EXPORT_SYMBOL(__memcpy);
-
-/* Networking helper routines. */
-EXPORT_SYMBOL(ip_compute_csum);
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
index 1c967026c957..652fa34c2cd3 100644
--- a/arch/um/sys-x86_64/stub_segv.c
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -5,7 +5,6 @@
#include <stddef.h>
#include <signal.h>
-#include <linux/compiler.h>
#include <asm/unistd.h>
#include "uml-config.h"
#include "sysdep/sigcontext.h"
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
index 6fce9f45dfdc..73ce4463f70c 100644
--- a/arch/um/sys-x86_64/syscalls.c
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -21,7 +21,7 @@ asmlinkage long sys_uname64(struct new_utsname __user * name)
{
int err;
down_read(&uts_sem);
- err = copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
if (personality(current->personality) == PER_LINUX32)
err |= copy_to_user(&name->machine, "i686", 5);
diff --git a/arch/um/sys-x86_64/sysrq.c b/arch/um/sys-x86_64/sysrq.c
index d0a25af19a5b..ce3e07fcf283 100644
--- a/arch/um/sys-x86_64/sysrq.c
+++ b/arch/um/sys-x86_64/sysrq.c
@@ -16,7 +16,7 @@ void __show_regs(struct pt_regs * regs)
printk("\n");
print_modules();
printk("Pid: %d, comm: %.20s %s %s\n",
- current->pid, current->comm, print_tainted(), system_utsname.release);
+ current->pid, current->comm, print_tainted(), init_utsname()->release);
printk("RIP: %04lx:[<%016lx>] ", PT_REGS_CS(regs) & 0xffff,
PT_REGS_RIP(regs));
printk("\nRSP: %016lx EFLAGS: %08lx\n", PT_REGS_RSP(regs),
diff --git a/arch/um/sys-x86_64/unmap.c b/arch/um/sys-x86_64/unmap.c
index f4a4bffd8a18..57c9286a701b 100644
--- a/arch/um/sys-x86_64/unmap.c
+++ b/arch/um/sys-x86_64/unmap.c
@@ -5,20 +5,17 @@
#include <linux/mman.h>
#include <asm/unistd.h>
+#include <sys/syscall.h>
-static int errno;
-
-static inline _syscall2(int,munmap,void *,start,size_t,len)
-static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
int switcheroo(int fd, int prot, void *from, void *to, int size)
{
- if(munmap(to, size) < 0){
+ if (syscall(__NR_munmap, to, size) < 0){
return(-1);
}
- if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1){
+ if (syscall(__NR_mmap, to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1){
return(-1);
}
- if(munmap(from, size) < 0){
+ if (syscall(__NR_munmap, from, size) < 0){
return(-1);
}
return(0);
diff --git a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S
index d991e4547dbb..8bc521ca081f 100644
--- a/arch/v850/kernel/entry.S
+++ b/arch/v850/kernel/entry.S
@@ -195,7 +195,7 @@
sst.w lp, PTO+PT_GPR(GPR_LP)[ep]; \
type ## _STATE_SAVER
/* Pop a register state pushed by PUSH_STATE, except for the stack pointer,
- from the the stack. */
+ from the stack. */
#define POP_STATE(type) \
mov sp, ep; \
type ## _STATE_RESTORER; \
diff --git a/arch/v850/kernel/memcons.c b/arch/v850/kernel/memcons.c
index 491614c435cd..92f514fdcc79 100644
--- a/arch/v850/kernel/memcons.c
+++ b/arch/v850/kernel/memcons.c
@@ -30,7 +30,7 @@ static DEFINE_SPINLOCK(memcons_lock);
static size_t write (const char *buf, size_t len)
{
- int flags;
+ unsigned long flags;
char *point;
spin_lock_irqsave (memcons_lock, flags);
@@ -104,7 +104,7 @@ int memcons_tty_chars_in_buffer (struct tty_struct *tty)
return 0;
}
-static struct tty_operations ops = {
+static const struct tty_operations ops = {
.open = memcons_tty_open,
.write = memcons_tty_write,
.write_room = memcons_tty_write_room,
diff --git a/arch/v850/kernel/rte_cb_leds.c b/arch/v850/kernel/rte_cb_leds.c
index f654088b2760..996bd4f33ecb 100644
--- a/arch/v850/kernel/rte_cb_leds.c
+++ b/arch/v850/kernel/rte_cb_leds.c
@@ -42,7 +42,7 @@ do { \
len = LED_NUM_DIGITS - pos; \
\
if (len > 0) { \
- int _flags; \
+ unsigned long _flags; \
const char *_end = buf + len; \
img_decl = &leds_image[pos]; \
\
diff --git a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c
index f36b778f1432..35213fa9f7d8 100644
--- a/arch/v850/kernel/rte_mb_a_pci.c
+++ b/arch/v850/kernel/rte_mb_a_pci.c
@@ -365,7 +365,7 @@ static DEFINE_SPINLOCK(mb_sram_lock);
static void *alloc_mb_sram (size_t size)
{
struct mb_sram_free_area *prev, *fa;
- int flags;
+ unsigned long flags;
void *mem = 0;
spin_lock_irqsave (mb_sram_lock, flags);
@@ -406,7 +406,7 @@ static void *alloc_mb_sram (size_t size)
static void free_mb_sram (void *mem, size_t size)
{
struct mb_sram_free_area *prev, *fa, *new_fa;
- int flags;
+ unsigned long flags;
void *end = mem + size;
spin_lock_irqsave (mb_sram_lock, flags);
@@ -517,7 +517,7 @@ static DEFINE_SPINLOCK(dma_mappings_lock);
static struct dma_mapping *new_dma_mapping (size_t size)
{
- int flags;
+ unsigned long flags;
struct dma_mapping *mapping;
void *mb_sram_block = alloc_mb_sram (size);
@@ -575,7 +575,7 @@ static struct dma_mapping *new_dma_mapping (size_t size)
static struct dma_mapping *find_dma_mapping (void *mb_sram_addr)
{
- int flags;
+ unsigned long flags;
struct dma_mapping *mapping;
spin_lock_irqsave (dma_mappings_lock, flags);
@@ -592,7 +592,7 @@ static struct dma_mapping *find_dma_mapping (void *mb_sram_addr)
static struct dma_mapping *deactivate_dma_mapping (void *mb_sram_addr)
{
- int flags;
+ unsigned long flags;
struct dma_mapping *mapping, *prev;
spin_lock_irqsave (dma_mappings_lock, flags);
@@ -622,7 +622,7 @@ static struct dma_mapping *deactivate_dma_mapping (void *mb_sram_addr)
static inline void
free_dma_mapping (struct dma_mapping *mapping)
{
- int flags;
+ unsigned long flags;
free_mb_sram (mapping->mb_sram_addr, mapping->size);
diff --git a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c
index 3975aa02cef8..9973596ae304 100644
--- a/arch/v850/kernel/simcons.c
+++ b/arch/v850/kernel/simcons.c
@@ -77,7 +77,7 @@ int simcons_tty_chars_in_buffer (struct tty_struct *tty)
return 0;
}
-static struct tty_operations ops = {
+static const struct tty_operations ops = {
.open = simcons_tty_open,
.write = simcons_tty_write,
.write_room = simcons_tty_write_room,
diff --git a/arch/v850/kernel/syscalls.c b/arch/v850/kernel/syscalls.c
index 2ec0700fc46b..d2b1fb19d243 100644
--- a/arch/v850/kernel/syscalls.c
+++ b/arch/v850/kernel/syscalls.c
@@ -33,6 +33,7 @@
#include <asm/uaccess.h>
#include <asm/ipc.h>
#include <asm/semaphore.h>
+#include <asm/unistd.h>
/*
* sys_ipc() is the de-multiplexer for the SysV IPC calls..
@@ -194,3 +195,22 @@ unsigned long sys_mmap (unsigned long addr, size_t len,
out:
return err;
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ register char *__a __asm__ ("r6") = filename;
+ register void *__b __asm__ ("r7") = argv;
+ register void *__c __asm__ ("r8") = envp;
+ register unsigned long __syscall __asm__ ("r12") = __NR_execve;
+ register unsigned long __ret __asm__ ("r10");
+ __asm__ __volatile__ ("trap 0"
+ : "=r" (__ret), "=r" (__syscall)
+ : "1" (__syscall), "r" (__a), "r" (__b), "r" (__c)
+ : "r1", "r5", "r11", "r13", "r14",
+ "r15", "r16", "r17", "r18", "r19");
+ return __ret;
+}
diff --git a/arch/v850/kernel/time.c b/arch/v850/kernel/time.c
index a0b46695f186..cd06f47c0ea7 100644
--- a/arch/v850/kernel/time.c
+++ b/arch/v850/kernel/time.c
@@ -10,7 +10,6 @@
* "A Kernel Model for Precision Timekeeping" by Dave Mills
*/
-#include <linux/config.h> /* CONFIG_HEARTBEAT */
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -51,7 +50,7 @@ static irqreturn_t timer_interrupt (int irq, void *dummy, struct pt_regs *regs)
if (mach_tick)
mach_tick ();
- do_timer (regs);
+ do_timer (1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index efe249e7d6b3..010d2265f1cf 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -85,6 +85,9 @@ config ARCH_MAY_HAVE_PC_FDC
bool
default y
+config ARCH_POPULATES_NODE_MAP
+ def_bool y
+
config DMI
bool
default y
@@ -168,6 +171,7 @@ config X86_GOOD_APIC
config MICROCODE
tristate "/dev/cpu/microcode - Intel CPU microcode support"
+ select FW_LOADER
---help---
If you say Y here the 'File systems' section, you will be
able to update the microcode on Intel processors. You will
@@ -183,6 +187,11 @@ config MICROCODE
If you use modprobe or kmod you may also want to add the line
'alias char-major-10-184 microcode' to your /etc/modules.conf file.
+config MICROCODE_OLD_INTERFACE
+ bool
+ depends on MICROCODE
+ default y
+
config X86_MSR
tristate "/dev/cpu/*/msr - Model-specific register support"
help
@@ -301,7 +310,7 @@ config K8_NUMA
help
Enable K8 NUMA node topology detection. You should say Y here if
you have a multi processor AMD K8 system. This uses an old
- method to read the NUMA configurtion directly from the builtin
+ method to read the NUMA configuration directly from the builtin
Northbridge of Opteron. It is recommended to use X86_64_ACPI_NUMA
instead, which also takes priority if both are compiled in.
@@ -358,6 +367,10 @@ config ARCH_FLATMEM_ENABLE
source "mm/Kconfig"
+config MEMORY_HOTPLUG_RESERVE
+ def_bool y
+ depends on (MEMORY_HOTPLUG && DISCONTIGMEM)
+
config HAVE_ARCH_EARLY_PFN_TO_NID
def_bool y
depends on NUMA
@@ -677,7 +690,7 @@ source "arch/x86_64/oprofile/Kconfig"
config KPROBES
bool "Kprobes (EXPERIMENTAL)"
- depends on EXPERIMENTAL && MODULES
+ depends on KALLSYMS && EXPERIMENTAL && MODULES
help
Kprobes allows you to trap at almost any kernel address and
execute a callback function. register_kprobe() establishes
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 1c0f18d4f887..13972148058d 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -54,6 +54,10 @@ endif
cflags-y += $(call cc-option,-funit-at-a-time)
# prevent gcc from generating any FP code by mistake
cflags-y += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
+# this works around some issues with generating unwind tables in older gccs
+# newer gccs do it by default
+cflags-y += -maccumulate-outgoing-args
+
# do binutils support CFI?
cflags-y += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
AFLAGS += $(call as-instr,.cfi_startproc\n.cfi_endproc,-DCONFIG_AS_CFI=1,)
diff --git a/arch/x86_64/boot/video.S b/arch/x86_64/boot/video.S
index 2aa565c136e5..d6ff88f35135 100644
--- a/arch/x86_64/boot/video.S
+++ b/arch/x86_64/boot/video.S
@@ -11,8 +11,6 @@
*
*/
-#include <linux/config.h> /* for CONFIG_VIDEO_* */
-
/* Enable autodetection of SVGA adapters and modes. */
#undef CONFIG_VIDEO_SVGA
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 647610ecb580..0f5d44e86be5 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,11 +1,12 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.18-git5
-# Tue Sep 26 09:30:47 2006
+# Linux kernel version: 2.6.19-rc2-git4
+# Sat Oct 21 03:38:52 2006
#
CONFIG_X86_64=y
CONFIG_64BIT=y
CONFIG_X86=y
+CONFIG_ZONE_DMA32=y
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_SEMAPHORE_SLEEPERS=y
@@ -18,6 +19,7 @@ CONFIG_EARLY_PRINTK=y
CONFIG_GENERIC_ISA_DMA=y
CONFIG_GENERIC_IOMAP=y
CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
CONFIG_DMI=y
CONFIG_AUDIT_ARCH=y
CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -36,9 +38,11 @@ CONFIG_LOCALVERSION=""
CONFIG_LOCALVERSION_AUTO=y
CONFIG_SWAP=y
CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
CONFIG_POSIX_MQUEUE=y
# CONFIG_BSD_PROCESS_ACCT is not set
# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
# CONFIG_AUDIT is not set
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
@@ -46,9 +50,10 @@ CONFIG_IKCONFIG_PROC=y
# CONFIG_RELAY is not set
CONFIG_INITRAMFS_SOURCE=""
CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
# CONFIG_EMBEDDED is not set
CONFIG_UID16=y
-CONFIG_SYSCTL=y
+# CONFIG_SYSCTL_SYSCALL is not set
CONFIG_KALLSYMS=y
CONFIG_KALLSYMS_ALL=y
# CONFIG_KALLSYMS_EXTRA_PASS is not set
@@ -81,6 +86,7 @@ CONFIG_STOP_MACHINE=y
#
# Block layer
#
+CONFIG_BLOCK=y
CONFIG_LBD=y
# CONFIG_BLK_DEV_IO_TRACE is not set
# CONFIG_LSF is not set
@@ -179,6 +185,7 @@ CONFIG_GENERIC_PENDING_IRQ=y
CONFIG_PM=y
# CONFIG_PM_LEGACY is not set
# CONFIG_PM_DEBUG is not set
+# CONFIG_PM_SYSFS_DEPRECATED is not set
CONFIG_SOFTWARE_SUSPEND=y
CONFIG_PM_STD_PARTITION=""
CONFIG_SUSPEND_SMP=y
@@ -250,8 +257,11 @@ CONFIG_PCI=y
CONFIG_PCI_DIRECT=y
CONFIG_PCI_MMCONFIG=y
CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
CONFIG_PCI_MSI=y
+# CONFIG_PCI_MULTITHREAD_PROBE is not set
# CONFIG_PCI_DEBUG is not set
+# CONFIG_HT_IRQ is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -306,6 +316,7 @@ CONFIG_IP_PNP_DHCP=y
# CONFIG_INET_TUNNEL is not set
# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
CONFIG_INET_DIAG=y
CONFIG_INET_TCP_DIAG=y
# CONFIG_TCP_CONG_ADVANCED is not set
@@ -322,9 +333,10 @@ CONFIG_IPV6=y
# CONFIG_INET6_TUNNEL is not set
# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET6_XFRM_MODE_BEET is not set
# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
# CONFIG_IPV6_TUNNEL is not set
-# CONFIG_IPV6_SUBTREES is not set
# CONFIG_IPV6_MULTIPLE_TABLES is not set
# CONFIG_NETWORK_SECMARK is not set
# CONFIG_NETFILTER is not set
@@ -426,6 +438,13 @@ CONFIG_BLK_DEV_INITRD=y
# CONFIG_ATA_OVER_ETH is not set
#
+# Misc devices
+#
+# CONFIG_IBM_ASM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+
+#
# ATA/ATAPI/MFM/RLL support
#
CONFIG_IDE=y
@@ -470,6 +489,7 @@ CONFIG_BLK_DEV_ATIIXP=y
# CONFIG_BLK_DEV_CS5530 is not set
# CONFIG_BLK_DEV_HPT34X is not set
# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
# CONFIG_BLK_DEV_SC1200 is not set
CONFIG_BLK_DEV_PIIX=y
# CONFIG_BLK_DEV_IT821X is not set
@@ -561,6 +581,7 @@ CONFIG_MEGARAID_SAS=y
# CONFIG_SCSI_IPR is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
@@ -602,7 +623,6 @@ CONFIG_SATA_INTEL_COMBINED=y
# CONFIG_PATA_HPT3X3 is not set
# CONFIG_PATA_IT821X is not set
# CONFIG_PATA_JMICRON is not set
-# CONFIG_PATA_LEGACY is not set
# CONFIG_PATA_TRIFLEX is not set
# CONFIG_PATA_MPIIX is not set
# CONFIG_PATA_OLDPIIX is not set
@@ -611,7 +631,6 @@ CONFIG_SATA_INTEL_COMBINED=y
# CONFIG_PATA_OPTI is not set
# CONFIG_PATA_OPTIDMA is not set
# CONFIG_PATA_PDC_OLD is not set
-# CONFIG_PATA_QDI is not set
# CONFIG_PATA_RADISYS is not set
# CONFIG_PATA_RZ1000 is not set
# CONFIG_PATA_SC1200 is not set
@@ -628,6 +647,7 @@ CONFIG_SATA_INTEL_COMBINED=y
CONFIG_MD=y
# CONFIG_BLK_DEV_MD is not set
CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
# CONFIG_DM_CRYPT is not set
# CONFIG_DM_SNAPSHOT is not set
# CONFIG_DM_MIRROR is not set
@@ -816,6 +836,7 @@ CONFIG_NET_POLL_CONTROLLER=y
# Input device support
#
CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
#
# Userland interfaces
@@ -838,6 +859,7 @@ CONFIG_KEYBOARD_ATKBD=y
# CONFIG_KEYBOARD_LKKBD is not set
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
@@ -993,6 +1015,7 @@ CONFIG_I2C_ISA=m
#
# Dallas's 1-wire bus
#
+# CONFIG_W1 is not set
#
# Hardware Monitoring support
@@ -1005,6 +1028,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_K8TEMP is not set
# CONFIG_SENSORS_ASB100 is not set
# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
@@ -1031,6 +1055,7 @@ CONFIG_HWMON=y
# CONFIG_SENSORS_SMSC47M192 is not set
CONFIG_SENSORS_SMSC47B397=m
# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
# CONFIG_SENSORS_VT8231 is not set
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83791D is not set
@@ -1042,15 +1067,9 @@ CONFIG_SENSORS_SMSC47B397=m
# CONFIG_HWMON_DEBUG_CHIP is not set
#
-# Misc devices
-#
-# CONFIG_IBM_ASM is not set
-
-#
# Multimedia devices
#
# CONFIG_VIDEO_DEV is not set
-CONFIG_VIDEO_V4L2=y
#
# Digital Video Broadcasting Devices
@@ -1156,6 +1175,7 @@ CONFIG_USB_STORAGE=y
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_KARMA is not set
# CONFIG_USB_LIBUSUAL is not set
#
@@ -1209,6 +1229,7 @@ CONFIG_USB_MON=y
#
# CONFIG_USB_EMI62 is not set
# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
# CONFIG_USB_AUERSWALD is not set
# CONFIG_USB_RIO500 is not set
# CONFIG_USB_LEGOTOWER is not set
@@ -1216,12 +1237,13 @@ CONFIG_USB_MON=y
# CONFIG_USB_LED is not set
# CONFIG_USB_CYPRESS_CY7C63 is not set
# CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGETKIT is not set
-# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_PHIDGET is not set
# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
# CONFIG_USB_APPLEDISPLAY is not set
# CONFIG_USB_SISUSBVGA is not set
# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
# CONFIG_USB_TEST is not set
#
@@ -1298,6 +1320,7 @@ CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4DEV_FS is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
CONFIG_FS_MBCACHE=y
@@ -1310,6 +1333,7 @@ CONFIG_REISERFS_FS_POSIX_ACL=y
# CONFIG_JFS_FS is not set
CONFIG_FS_POSIX_ACL=y
# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
# CONFIG_OCFS2_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -1320,6 +1344,7 @@ CONFIG_DNOTIFY=y
# CONFIG_AUTOFS_FS is not set
CONFIG_AUTOFS4_FS=y
# CONFIG_FUSE_FS is not set
+CONFIG_GENERIC_ACL=y
#
# CD-ROM/DVD Filesystems
@@ -1344,8 +1369,10 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
CONFIG_SYSFS=y
CONFIG_TMPFS=y
+CONFIG_TMPFS_POSIX_ACL=y
CONFIG_HUGETLBFS=y
CONFIG_HUGETLB_PAGE=y
CONFIG_RAMFS=y
@@ -1458,6 +1485,7 @@ CONFIG_KPROBES=y
#
CONFIG_TRACE_IRQFLAGS_SUPPORT=y
# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_MAGIC_SYSRQ=y
CONFIG_UNUSED_SYMBOLS=y
CONFIG_DEBUG_KERNEL=y
@@ -1478,11 +1506,14 @@ CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_DEBUG_INFO is not set
CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
# CONFIG_FRAME_POINTER is not set
CONFIG_UNWIND_INFO=y
CONFIG_STACK_UNWIND=y
# CONFIG_FORCED_INLINING is not set
+# CONFIG_HEADERS_CHECK is not set
# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_LKDTM is not set
# CONFIG_DEBUG_RODATA is not set
# CONFIG_IOMMU_DEBUG is not set
CONFIG_DEBUG_STACKOVERFLOW=y
diff --git a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
index 2fd5a67fd435..82ef182de6ae 100644
--- a/arch/x86_64/ia32/ia32_binfmt.c
+++ b/arch/x86_64/ia32/ia32_binfmt.c
@@ -6,7 +6,6 @@
* of ugly preprocessor tricks. Talk about very very poor man's inheritance.
*/
#include <linux/types.h>
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/rwsem.h>
#include <linux/sched.h>
diff --git a/arch/x86_64/ia32/ptrace32.c b/arch/x86_64/ia32/ptrace32.c
index d18198ed636b..3a7561d4703e 100644
--- a/arch/x86_64/ia32/ptrace32.c
+++ b/arch/x86_64/ia32/ptrace32.c
@@ -205,9 +205,9 @@ static int getreg32(struct task_struct *child, unsigned regno, u32 *val)
static long ptrace32_siginfo(unsigned request, u32 pid, u32 addr, u32 data)
{
int ret;
- compat_siginfo_t *si32 = (compat_siginfo_t *)compat_ptr(data);
+ compat_siginfo_t __user *si32 = compat_ptr(data);
siginfo_t ssi;
- siginfo_t *si = compat_alloc_user_space(sizeof(siginfo_t));
+ siginfo_t __user *si = compat_alloc_user_space(sizeof(siginfo_t));
if (request == PTRACE_SETSIGINFO) {
memset(&ssi, 0, sizeof(siginfo_t));
ret = copy_siginfo_from_user32(&ssi, si32);
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index b0e82c7947dc..c9bac3af29d6 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -76,6 +76,8 @@
int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
{
+ compat_ino_t ino;
+
typeof(ubuf->st_uid) uid = 0;
typeof(ubuf->st_gid) gid = 0;
SET_UID(uid, kbuf->uid);
@@ -84,9 +86,12 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
return -EOVERFLOW;
if (kbuf->size >= 0x7fffffff)
return -EOVERFLOW;
+ ino = kbuf->ino;
+ if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
+ return -EOVERFLOW;
if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
__put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
- __put_user (kbuf->ino, &ubuf->st_ino) ||
+ __put_user (ino, &ubuf->st_ino) ||
__put_user (kbuf->mode, &ubuf->st_mode) ||
__put_user (kbuf->nlink, &ubuf->st_nlink) ||
__put_user (uid, &ubuf->st_uid) ||
@@ -648,7 +653,7 @@ sys32_pause(void)
}
-#ifdef CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL_SYSCALL
struct sysctl_ia32 {
unsigned int name;
int nlen;
@@ -784,36 +789,36 @@ asmlinkage long sys32_olduname(struct oldold_utsname __user * name)
if (!name)
return -EFAULT;
- if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+ if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
return -EFAULT;
down_read(&uts_sem);
-
- err = __copy_to_user(&name->sysname,&system_utsname.sysname,
+
+ err = __copy_to_user(&name->sysname,&utsname()->sysname,
__OLD_UTS_LEN);
err |= __put_user(0,name->sysname+__OLD_UTS_LEN);
- err |= __copy_to_user(&name->nodename,&system_utsname.nodename,
+ err |= __copy_to_user(&name->nodename,&utsname()->nodename,
__OLD_UTS_LEN);
err |= __put_user(0,name->nodename+__OLD_UTS_LEN);
- err |= __copy_to_user(&name->release,&system_utsname.release,
+ err |= __copy_to_user(&name->release,&utsname()->release,
__OLD_UTS_LEN);
err |= __put_user(0,name->release+__OLD_UTS_LEN);
- err |= __copy_to_user(&name->version,&system_utsname.version,
+ err |= __copy_to_user(&name->version,&utsname()->version,
__OLD_UTS_LEN);
err |= __put_user(0,name->version+__OLD_UTS_LEN);
- {
- char *arch = "x86_64";
- if (personality(current->personality) == PER_LINUX32)
- arch = "i686";
+ {
+ char *arch = "x86_64";
+ if (personality(current->personality) == PER_LINUX32)
+ arch = "i686";
- err |= __copy_to_user(&name->machine,arch,strlen(arch)+1);
- }
-
- up_read(&uts_sem);
-
- err = err ? -EFAULT : 0;
-
- return err;
+ err |= __copy_to_user(&name->machine, arch, strlen(arch)+1);
+ }
+
+ up_read(&uts_sem);
+
+ err = err ? -EFAULT : 0;
+
+ return err;
}
long sys32_uname(struct old_utsname __user * name)
@@ -822,7 +827,7 @@ long sys32_uname(struct old_utsname __user * name)
if (!name)
return -EFAULT;
down_read(&uts_sem);
- err=copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
if (personality(current->personality) == PER_LINUX32)
err |= copy_to_user(&name->machine, "i686", 5);
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 135ff25e6b44..4d9d5ed942b2 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -25,7 +25,6 @@
#include <linux/kernel_stat.h>
#include <linux/sysdev.h>
#include <linux/module.h>
-#include <linux/ioport.h>
#include <asm/atomic.h>
#include <asm/smp.h>
@@ -46,11 +45,6 @@ int apic_calibrate_pmtmr __initdata;
int disable_apic_timer __initdata;
-static struct resource lapic_resource = {
- .name = "Local APIC",
- .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
-};
-
/*
* cpu_mask that denotes the CPUs that needs timer interrupt coming in as
* IPIs in place of local APIC timers
@@ -591,40 +585,6 @@ static int __init detect_init_APIC (void)
return 0;
}
-#ifdef CONFIG_X86_IO_APIC
-static struct resource * __init ioapic_setup_resources(void)
-{
-#define IOAPIC_RESOURCE_NAME_SIZE 11
- unsigned long n;
- struct resource *res;
- char *mem;
- int i;
-
- if (nr_ioapics <= 0)
- return NULL;
-
- n = IOAPIC_RESOURCE_NAME_SIZE + sizeof(struct resource);
- n *= nr_ioapics;
-
- res = alloc_bootmem(n);
-
- if (!res)
- return NULL;
-
- memset(res, 0, n);
- mem = (void *)&res[nr_ioapics];
-
- for (i = 0; i < nr_ioapics; i++) {
- res[i].name = mem;
- res[i].flags = IORESOURCE_MEM | IORESOURCE_BUSY;
- snprintf(mem, IOAPIC_RESOURCE_NAME_SIZE, "IOAPIC %u", i);
- mem += IOAPIC_RESOURCE_NAME_SIZE;
- }
-
- return res;
-}
-#endif
-
void __init init_apic_mappings(void)
{
unsigned long apic_phys;
@@ -644,11 +604,6 @@ void __init init_apic_mappings(void)
apic_mapped = 1;
apic_printk(APIC_VERBOSE,"mapped APIC to %16lx (%16lx)\n", APIC_BASE, apic_phys);
- /* Put local APIC into the resource map. */
- lapic_resource.start = apic_phys;
- lapic_resource.end = lapic_resource.start + PAGE_SIZE - 1;
- insert_resource(&iomem_resource, &lapic_resource);
-
/*
* Fetch the APIC ID of the BSP in case we have a
* default configuration (or the MP table is broken).
@@ -658,9 +613,7 @@ void __init init_apic_mappings(void)
{
unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0;
int i;
- struct resource *ioapic_res;
- ioapic_res = ioapic_setup_resources();
for (i = 0; i < nr_ioapics; i++) {
if (smp_found_config) {
ioapic_phys = mp_ioapics[i].mpc_apicaddr;
@@ -672,13 +625,6 @@ void __init init_apic_mappings(void)
apic_printk(APIC_VERBOSE,"mapped IOAPIC to %016lx (%016lx)\n",
__fix_to_virt(idx), ioapic_phys);
idx++;
-
- if (ioapic_res) {
- ioapic_res->start = ioapic_phys;
- ioapic_res->end = ioapic_phys + (4 * 1024) - 1;
- insert_resource(&iomem_resource, ioapic_res);
- ioapic_res++;
- }
}
}
}
@@ -939,14 +885,14 @@ void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
* value into /proc/profile.
*/
-void smp_local_timer_interrupt(struct pt_regs *regs)
+void smp_local_timer_interrupt(void)
{
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#ifdef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
- main_timer_handler(regs);
+ main_timer_handler();
/*
* We take the 'long' return path, and there every subsystem
* grabs the appropriate locks (kernel lock/ irq lock).
@@ -969,6 +915,8 @@ void smp_local_timer_interrupt(struct pt_regs *regs)
*/
void smp_apic_timer_interrupt(struct pt_regs *regs)
{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+
/*
* the NMI deadlock-detector uses this.
*/
@@ -986,8 +934,9 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
*/
exit_idle();
irq_enter();
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
irq_exit();
+ set_irq_regs(old_regs);
}
/*
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index c0af3828df45..a75c829c2b02 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -54,13 +54,13 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size)
/* various gunk below that needed for SMP startup */
if (addr < 0x8000) {
- *addrp = 0x8000;
+ *addrp = PAGE_ALIGN(0x8000);
return 1;
}
/* direct mapping tables of the kernel */
if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) {
- *addrp = table_end << PAGE_SHIFT;
+ *addrp = PAGE_ALIGN(table_end << PAGE_SHIFT);
return 1;
}
@@ -68,18 +68,18 @@ static inline int bad_addr(unsigned long *addrp, unsigned long size)
#ifdef CONFIG_BLK_DEV_INITRD
if (LOADER_TYPE && INITRD_START && last >= INITRD_START &&
addr < INITRD_START+INITRD_SIZE) {
- *addrp = INITRD_START + INITRD_SIZE;
+ *addrp = PAGE_ALIGN(INITRD_START + INITRD_SIZE);
return 1;
}
#endif
/* kernel code */
- if (last >= __pa_symbol(&_text) && last < __pa_symbol(&_end)) {
- *addrp = __pa_symbol(&_end);
+ if (last >= __pa_symbol(&_text) && addr < __pa_symbol(&_end)) {
+ *addrp = PAGE_ALIGN(__pa_symbol(&_end));
return 1;
}
if (last >= ebda_addr && addr < ebda_addr + ebda_size) {
- *addrp = ebda_addr + ebda_size;
+ *addrp = PAGE_ALIGN(ebda_addr + ebda_size);
return 1;
}
@@ -152,7 +152,7 @@ unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsi
continue;
while (bad_addr(&addr, size) && addr+size <= ei->addr+ei->size)
;
- last = addr + size;
+ last = PAGE_ALIGN(addr) + size;
if (last > ei->addr + ei->size)
continue;
if (last > end)
@@ -162,59 +162,14 @@ unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsi
return -1UL;
}
-/*
- * Free bootmem based on the e820 table for a node.
- */
-void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
-{
- int i;
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
- unsigned long last, addr;
-
- if (ei->type != E820_RAM ||
- ei->addr+ei->size <= start ||
- ei->addr >= end)
- continue;
-
- addr = round_up(ei->addr, PAGE_SIZE);
- if (addr < start)
- addr = start;
-
- last = round_down(ei->addr + ei->size, PAGE_SIZE);
- if (last >= end)
- last = end;
-
- if (last > addr && last-addr >= PAGE_SIZE)
- free_bootmem_node(pgdat, addr, last-addr);
- }
-}
-
/*
* Find the highest page frame number we have available
*/
unsigned long __init e820_end_of_ram(void)
{
- int i;
unsigned long end_pfn = 0;
+ end_pfn = find_max_pfn_with_active_regions();
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
- unsigned long start, end;
-
- start = round_up(ei->addr, PAGE_SIZE);
- end = round_down(ei->addr + ei->size, PAGE_SIZE);
- if (start >= end)
- continue;
- if (ei->type == E820_RAM) {
- if (end > end_pfn<<PAGE_SHIFT)
- end_pfn = end>>PAGE_SHIFT;
- } else {
- if (end > end_pfn_map<<PAGE_SHIFT)
- end_pfn_map = end>>PAGE_SHIFT;
- }
- }
-
if (end_pfn > end_pfn_map)
end_pfn_map = end_pfn;
if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
@@ -224,43 +179,10 @@ unsigned long __init e820_end_of_ram(void)
if (end_pfn > end_pfn_map)
end_pfn = end_pfn_map;
+ printk("end_pfn_map = %lu\n", end_pfn_map);
return end_pfn;
}
-/*
- * Compute how much memory is missing in a range.
- * Unlike the other functions in this file the arguments are in page numbers.
- */
-unsigned long __init
-e820_hole_size(unsigned long start_pfn, unsigned long end_pfn)
-{
- unsigned long ram = 0;
- unsigned long start = start_pfn << PAGE_SHIFT;
- unsigned long end = end_pfn << PAGE_SHIFT;
- int i;
- for (i = 0; i < e820.nr_map; i++) {
- struct e820entry *ei = &e820.map[i];
- unsigned long last, addr;
-
- if (ei->type != E820_RAM ||
- ei->addr+ei->size <= start ||
- ei->addr >= end)
- continue;
-
- addr = round_up(ei->addr, PAGE_SIZE);
- if (addr < start)
- addr = start;
-
- last = round_down(ei->addr + ei->size, PAGE_SIZE);
- if (last >= end)
- last = end;
-
- if (last > addr)
- ram += last - addr;
- }
- return ((end - start) - ram) >> PAGE_SHIFT;
-}
-
/*
* Mark e820 reserved areas as busy for the resource manager.
*/
@@ -342,6 +264,49 @@ void __init e820_mark_nosave_regions(void)
}
}
+/* Walk the e820 map and register active regions within a node */
+void __init
+e820_register_active_regions(int nid, unsigned long start_pfn,
+ unsigned long end_pfn)
+{
+ int i;
+ unsigned long ei_startpfn, ei_endpfn;
+ for (i = 0; i < e820.nr_map; i++) {
+ struct e820entry *ei = &e820.map[i];
+ ei_startpfn = round_up(ei->addr, PAGE_SIZE) >> PAGE_SHIFT;
+ ei_endpfn = round_down(ei->addr + ei->size, PAGE_SIZE)
+ >> PAGE_SHIFT;
+
+ /* Skip map entries smaller than a page */
+ if (ei_startpfn > ei_endpfn)
+ continue;
+
+ /* Check if end_pfn_map should be updated */
+ if (ei->type != E820_RAM && ei_endpfn > end_pfn_map)
+ end_pfn_map = ei_endpfn;
+
+ /* Skip if map is outside the node */
+ if (ei->type != E820_RAM ||
+ ei_endpfn <= start_pfn ||
+ ei_startpfn >= end_pfn)
+ continue;
+
+ /* Check for overlaps */
+ if (ei_startpfn < start_pfn)
+ ei_startpfn = start_pfn;
+ if (ei_endpfn > end_pfn)
+ ei_endpfn = end_pfn;
+
+ /* Obey end_user_pfn to save on memmap */
+ if (ei_startpfn >= end_user_pfn)
+ continue;
+ if (ei_endpfn > end_user_pfn)
+ ei_endpfn = end_user_pfn;
+
+ add_active_range(nid, ei_startpfn, ei_endpfn);
+ }
+}
+
/*
* Add a memory region to the kernel e820 map.
*/
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index 208e38a372c1..2b1245d86258 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -61,10 +61,11 @@ static void nvidia_bugs(void)
static void ati_bugs(void)
{
-#if 1 /* for testing */
- printk("ATI board detected\n");
-#endif
- /* No bugs right now */
+ if (timer_over_8254 == 1) {
+ timer_over_8254 = 0;
+ printk(KERN_INFO
+ "ATI board detected. Disabling timer routing over 8254.\n");
+ }
}
struct chipset {
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 2802524104f3..7d401b00d822 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -315,6 +315,8 @@ tracesys:
LOAD_ARGS ARGOFFSET /* reload args from stack in case ptrace changed it */
RESTORE_REST
cmpq $__NR_syscall_max,%rax
+ movq $-ENOSYS,%rcx
+ cmova %rcx,%rax
ja 1f
movq %r10,%rcx /* fixup for C */
call *sys_call_table(,%rax,8)
@@ -1023,7 +1025,7 @@ ENDPROC(child_rip)
* do_sys_execve asm fallback arguments:
* rdi: name, rsi: argv, rdx: envp, fake frame on the stack
*/
-ENTRY(execve)
+ENTRY(kernel_execve)
CFI_STARTPROC
FAKE_STACK_FRAME $0
SAVE_ALL
@@ -1036,7 +1038,7 @@ ENTRY(execve)
UNFAKE_STACK_FRAME
ret
CFI_ENDPROC
-ENDPROC(execve)
+ENDPROC(kernel_execve)
KPROBE_ENTRY(page_fault)
errorentry do_page_fault
diff --git a/arch/x86_64/kernel/genapic_cluster.c b/arch/x86_64/kernel/genapic_cluster.c
index cdb90e671b88..73d76308b955 100644
--- a/arch/x86_64/kernel/genapic_cluster.c
+++ b/arch/x86_64/kernel/genapic_cluster.c
@@ -63,6 +63,13 @@ static cpumask_t cluster_target_cpus(void)
return cpumask_of_cpu(0);
}
+static cpumask_t cluster_vector_allocation_domain(int cpu)
+{
+ cpumask_t domain = CPU_MASK_NONE;
+ cpu_set(cpu, domain);
+ return domain;
+}
+
static void cluster_send_IPI_mask(cpumask_t mask, int vector)
{
send_IPI_mask_sequence(mask, vector);
@@ -119,6 +126,7 @@ struct genapic apic_cluster = {
.int_delivery_mode = dest_Fixed,
.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
.target_cpus = cluster_target_cpus,
+ .vector_allocation_domain = cluster_vector_allocation_domain,
.apic_id_registered = cluster_apic_id_registered,
.init_apic_ldr = cluster_init_apic_ldr,
.send_IPI_all = cluster_send_IPI_all,
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
index 50ad153eaac4..7c01db8fa9d1 100644
--- a/arch/x86_64/kernel/genapic_flat.c
+++ b/arch/x86_64/kernel/genapic_flat.c
@@ -22,6 +22,20 @@ static cpumask_t flat_target_cpus(void)
return cpu_online_map;
}
+static cpumask_t flat_vector_allocation_domain(int cpu)
+{
+ /* Careful. Some cpus do not strictly honor the set of cpus
+ * specified in the interrupt destination when using lowest
+ * priority interrupt delivery mode.
+ *
+ * In particular there was a hyperthreading cpu observed to
+ * deliver interrupts to the wrong hyperthread when only one
+ * hyperthread was specified in the interrupt desitination.
+ */
+ cpumask_t domain = { { [0] = APIC_ALL_CPUS, } };
+ return domain;
+}
+
/*
* Set up the logical destination ID.
*
@@ -121,6 +135,7 @@ struct genapic apic_flat = {
.int_delivery_mode = dest_LowestPrio,
.int_dest_mode = (APIC_DEST_LOGICAL != 0),
.target_cpus = flat_target_cpus,
+ .vector_allocation_domain = flat_vector_allocation_domain,
.apic_id_registered = flat_apic_id_registered,
.init_apic_ldr = flat_init_apic_ldr,
.send_IPI_all = flat_send_IPI_all,
@@ -138,9 +153,17 @@ struct genapic apic_flat = {
static cpumask_t physflat_target_cpus(void)
{
- return cpumask_of_cpu(0);
+ return cpu_online_map;
}
+static cpumask_t physflat_vector_allocation_domain(int cpu)
+{
+ cpumask_t domain = CPU_MASK_NONE;
+ cpu_set(cpu, domain);
+ return domain;
+}
+
+
static void physflat_send_IPI_mask(cpumask_t cpumask, int vector)
{
send_IPI_mask_sequence(cpumask, vector);
@@ -179,6 +202,7 @@ struct genapic apic_physflat = {
.int_delivery_mode = dest_Fixed,
.int_dest_mode = (APIC_DEST_PHYSICAL != 0),
.target_cpus = physflat_target_cpus,
+ .vector_allocation_domain = physflat_vector_allocation_domain,
.apic_id_registered = flat_apic_id_registered,
.init_apic_ldr = flat_init_apic_ldr,/*not needed, but shouldn't hurt*/
.send_IPI_all = physflat_send_IPI_all,
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 2dd51f364ea2..c4ef801b765b 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -43,17 +43,10 @@
BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
BI(x,c) BI(x,d) BI(x,e) BI(x,f)
-#define BUILD_15_IRQS(x) \
- BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
- BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
- BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
- BI(x,c) BI(x,d) BI(x,e)
-
/*
* ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
* (these are usually mapped to vectors 0x20-0x2f)
*/
-BUILD_16_IRQS(0x0)
/*
* The IO-APIC gives us many more interrupt sources. Most of these
@@ -65,17 +58,12 @@ BUILD_16_IRQS(0x0)
*
* (these are usually mapped into the 0x30-0xff vector range)
*/
- BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
+ BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
-BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
-
-#ifdef CONFIG_PCI_MSI
- BUILD_15_IRQS(0xe)
-#endif
+BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd) BUILD_16_IRQS(0xe) BUILD_16_IRQS(0xf)
#undef BUILD_16_IRQS
-#undef BUILD_15_IRQS
#undef BI
@@ -88,29 +76,15 @@ BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)
-#define IRQLIST_15(x) \
- IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
- IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
- IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
- IRQ(x,c), IRQ(x,d), IRQ(x,e)
-
void (*interrupt[NR_IRQS])(void) = {
- IRQLIST_16(0x0),
-
- IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
+ IRQLIST_16(0x2), IRQLIST_16(0x3),
IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
- IRQLIST_16(0xc), IRQLIST_16(0xd)
-
-#ifdef CONFIG_PCI_MSI
- , IRQLIST_15(0xe)
-#endif
-
+ IRQLIST_16(0xc), IRQLIST_16(0xd), IRQLIST_16(0xe), IRQLIST_16(0xf)
};
#undef IRQ
#undef IRQLIST_16
-#undef IRQLIST_14
/*
* This is the 'legacy' 8259A Programmable Interrupt Controller,
@@ -121,42 +95,15 @@ void (*interrupt[NR_IRQS])(void) = {
* moves to arch independent land
*/
-DEFINE_SPINLOCK(i8259A_lock);
-
static int i8259A_auto_eoi;
-
-static void end_8259A_irq (unsigned int irq)
-{
- if (irq > 256) {
- char var;
- printk("return %p stack %p ti %p\n", __builtin_return_address(0), &var, task_thread_info(current));
-
- BUG();
- }
-
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)) &&
- irq_desc[irq].action)
- enable_8259A_irq(irq);
-}
-
-#define shutdown_8259A_irq disable_8259A_irq
-
+DEFINE_SPINLOCK(i8259A_lock);
static void mask_and_ack_8259A(unsigned int);
-static unsigned int startup_8259A_irq(unsigned int irq)
-{
- enable_8259A_irq(irq);
- return 0; /* never anything pending */
-}
-
-static struct hw_interrupt_type i8259A_irq_type = {
- .typename = "XT-PIC",
- .startup = startup_8259A_irq,
- .shutdown = shutdown_8259A_irq,
- .enable = enable_8259A_irq,
- .disable = disable_8259A_irq,
- .ack = mask_and_ack_8259A,
- .end = end_8259A_irq,
+static struct irq_chip i8259A_chip = {
+ .name = "XT-PIC",
+ .mask = disable_8259A_irq,
+ .unmask = enable_8259A_irq,
+ .mask_ack = mask_and_ack_8259A,
};
/*
@@ -231,7 +178,8 @@ void make_8259A_irq(unsigned int irq)
{
disable_irq_nosync(irq);
io_apic_irqs &= ~(1<<irq);
- irq_desc[irq].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler_name(irq, &i8259A_chip, handle_level_irq,
+ "XT");
enable_irq(irq);
}
@@ -367,9 +315,9 @@ void init_8259A(int auto_eoi)
* in AEOI mode we just have to mask the interrupt
* when acking.
*/
- i8259A_irq_type.ack = disable_8259A_irq;
+ i8259A_chip.mask_ack = disable_8259A_irq;
else
- i8259A_irq_type.ack = mask_and_ack_8259A;
+ i8259A_chip.mask_ack = mask_and_ack_8259A;
udelay(100); /* wait for 8259A to initialize */
@@ -447,6 +395,26 @@ device_initcall(i8259A_init_sysfs);
*/
static struct irqaction irq2 = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL};
+DEFINE_PER_CPU(vector_irq_t, vector_irq) = {
+ [0 ... FIRST_EXTERNAL_VECTOR - 1] = -1,
+ [FIRST_EXTERNAL_VECTOR + 0] = 0,
+ [FIRST_EXTERNAL_VECTOR + 1] = 1,
+ [FIRST_EXTERNAL_VECTOR + 2] = 2,
+ [FIRST_EXTERNAL_VECTOR + 3] = 3,
+ [FIRST_EXTERNAL_VECTOR + 4] = 4,
+ [FIRST_EXTERNAL_VECTOR + 5] = 5,
+ [FIRST_EXTERNAL_VECTOR + 6] = 6,
+ [FIRST_EXTERNAL_VECTOR + 7] = 7,
+ [FIRST_EXTERNAL_VECTOR + 8] = 8,
+ [FIRST_EXTERNAL_VECTOR + 9] = 9,
+ [FIRST_EXTERNAL_VECTOR + 10] = 10,
+ [FIRST_EXTERNAL_VECTOR + 11] = 11,
+ [FIRST_EXTERNAL_VECTOR + 12] = 12,
+ [FIRST_EXTERNAL_VECTOR + 13] = 13,
+ [FIRST_EXTERNAL_VECTOR + 14] = 14,
+ [FIRST_EXTERNAL_VECTOR + 15] = 15,
+ [FIRST_EXTERNAL_VECTOR + 16 ... NR_VECTORS - 1] = -1
+};
void __init init_ISA_irqs (void)
{
@@ -464,12 +432,13 @@ void __init init_ISA_irqs (void)
/*
* 16 old-style INTA-cycle interrupts:
*/
- irq_desc[i].chip = &i8259A_irq_type;
+ set_irq_chip_and_handler_name(i, &i8259A_chip,
+ handle_level_irq, "XT");
} else {
/*
* 'high' PCI IRQs filled in on demand
*/
- irq_desc[i].chip = &no_irq_type;
+ irq_desc[i].chip = &no_irq_chip;
}
}
}
@@ -543,8 +512,6 @@ void __init init_IRQ(void)
*/
for (i = 0; i < (NR_VECTORS - FIRST_EXTERNAL_VECTOR); i++) {
int vector = FIRST_EXTERNAL_VECTOR + i;
- if (i >= NR_IRQS)
- break;
if (vector != IA32_SYSCALL_VECTOR)
set_intr_gate(vector, interrupt[i]);
}
@@ -554,7 +521,7 @@ void __init init_IRQ(void)
* IRQ0 must be given a fixed assignment and initialized,
* because it's used before the IO-APIC is set up.
*/
- set_intr_gate(FIRST_DEVICE_VECTOR, interrupt[0]);
+ __get_cpu_var(vector_irq)[FIRST_DEVICE_VECTOR] = 0;
/*
* The reschedule interrupt is a CPU-to-CPU reschedule-helper
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 0491019d4c8d..b000017e4b5d 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -26,9 +26,12 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
+#include <linux/pci.h>
#include <linux/mc146818rtc.h>
#include <linux/acpi.h>
#include <linux/sysdev.h>
+#include <linux/msi.h>
+#include <linux/htirq.h>
#ifdef CONFIG_ACPI
#include <acpi/acpi_bus.h>
#endif
@@ -41,6 +44,10 @@
#include <asm/acpi.h>
#include <asm/dma.h>
#include <asm/nmi.h>
+#include <asm/msidef.h>
+#include <asm/hypertransport.h>
+
+static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result);
#define __apicdebuginit __init
@@ -50,7 +57,7 @@ static int no_timer_check;
static int disable_timer_pin_1 __initdata;
-int timer_over_8254 __initdata = 0;
+int timer_over_8254 __initdata = 1;
/* Where if anywhere is the i8259 connect in external int mode */
static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
@@ -81,14 +88,6 @@ static struct irq_pin_list {
short apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
-int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
-#ifdef CONFIG_PCI_MSI
-#define vector_to_irq(vector) \
- (platform_legacy_irq(vector) ? vector : vector_irq[vector])
-#else
-#define vector_to_irq(vector) (vector)
-#endif
-
#define __DO_ACTION(R, ACTION, FINAL) \
\
{ \
@@ -139,11 +138,35 @@ static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
}
#ifdef CONFIG_SMP
+static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
+{
+ int apic, pin;
+ struct irq_pin_list *entry = irq_2_pin + irq;
+
+ BUG_ON(irq >= NR_IRQS);
+ for (;;) {
+ unsigned int reg;
+ apic = entry->apic;
+ pin = entry->pin;
+ if (pin == -1)
+ break;
+ io_apic_write(apic, 0x11 + pin*2, dest);
+ reg = io_apic_read(apic, 0x10 + pin*2);
+ reg &= ~0x000000ff;
+ reg |= vector;
+ io_apic_modify(apic, reg);
+ if (!entry->next)
+ break;
+ entry = irq_2_pin + entry->next;
+ }
+}
+
static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
{
unsigned long flags;
unsigned int dest;
cpumask_t tmp;
+ int vector;
cpus_and(tmp, mask, cpu_online_map);
if (cpus_empty(tmp))
@@ -151,7 +174,11 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
cpus_and(mask, tmp, CPU_MASK_ALL);
- dest = cpu_mask_to_apicid(mask);
+ vector = assign_irq_vector(irq, mask, &tmp);
+ if (vector < 0)
+ return;
+
+ dest = cpu_mask_to_apicid(tmp);
/*
* Only the high 8 bits are valid.
@@ -159,14 +186,12 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask)
dest = SET_APIC_LOGICAL_ID(dest);
spin_lock_irqsave(&ioapic_lock, flags);
- __DO_ACTION(1, = dest, )
- set_irq_info(irq, mask);
+ __target_IO_APIC_irq(irq, dest, vector);
+ set_native_irq_info(irq, mask);
spin_unlock_irqrestore(&ioapic_lock, flags);
}
#endif
-static u8 gsi_2_irq[NR_IRQ_VECTORS] = { [0 ... NR_IRQ_VECTORS-1] = 0xFF };
-
/*
* The common case is 1:1 IRQ<->pin mappings. Sometimes there are
* shared ISA-space IRQs, so we have to support them. We are super
@@ -492,64 +517,6 @@ static inline int irq_trigger(int idx)
return MPBIOS_trigger(idx);
}
-static int next_irq = 16;
-
-/*
- * gsi_irq_sharing -- Name overload! "irq" can be either a legacy IRQ
- * in the range 0-15, a linux IRQ in the range 0-223, or a GSI number
- * from ACPI, which can reach 800 in large boxen.
- *
- * Compact the sparse GSI space into a sequential IRQ series and reuse
- * vectors if possible.
- */
-int gsi_irq_sharing(int gsi)
-{
- int i, tries, vector;
-
- BUG_ON(gsi >= NR_IRQ_VECTORS);
-
- if (platform_legacy_irq(gsi))
- return gsi;
-
- if (gsi_2_irq[gsi] != 0xFF)
- return (int)gsi_2_irq[gsi];
-
- tries = NR_IRQS;
- try_again:
- vector = assign_irq_vector(gsi);
-
- /*
- * Sharing vectors means sharing IRQs, so scan irq_vectors for previous
- * use of vector and if found, return that IRQ. However, we never want
- * to share legacy IRQs, which usually have a different trigger mode
- * than PCI.
- */
- for (i = 0; i < NR_IRQS; i++)
- if (IO_APIC_VECTOR(i) == vector)
- break;
- if (platform_legacy_irq(i)) {
- if (--tries >= 0) {
- IO_APIC_VECTOR(i) = 0;
- goto try_again;
- }
- panic("gsi_irq_sharing: didn't find an IRQ using vector 0x%02X for GSI %d", vector, gsi);
- }
- if (i < NR_IRQS) {
- gsi_2_irq[gsi] = i;
- printk(KERN_INFO "GSI %d sharing vector 0x%02X and IRQ %d\n",
- gsi, vector, i);
- return i;
- }
-
- i = next_irq++;
- BUG_ON(i >= NR_IRQS);
- gsi_2_irq[gsi] = i;
- IO_APIC_VECTOR(i) = vector;
- printk(KERN_INFO "GSI %d assigned vector 0x%02X and IRQ %d\n",
- gsi, vector, i);
- return i;
-}
-
static int pin_2_irq(int idx, int apic, int pin)
{
int irq, i;
@@ -571,7 +538,6 @@ static int pin_2_irq(int idx, int apic, int pin)
while (i < apic)
irq += nr_ioapic_registers[i++];
irq += pin;
- irq = gsi_irq_sharing(irq);
}
BUG_ON(irq >= NR_IRQS);
return irq;
@@ -595,46 +561,132 @@ static inline int IO_APIC_irq_trigger(int irq)
}
/* irq_vectors is indexed by the sum of all RTEs in all I/O APICs. */
-u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = { FIRST_DEVICE_VECTOR , 0 };
+static u8 irq_vector[NR_IRQ_VECTORS] __read_mostly = {
+ [0] = FIRST_EXTERNAL_VECTOR + 0,
+ [1] = FIRST_EXTERNAL_VECTOR + 1,
+ [2] = FIRST_EXTERNAL_VECTOR + 2,
+ [3] = FIRST_EXTERNAL_VECTOR + 3,
+ [4] = FIRST_EXTERNAL_VECTOR + 4,
+ [5] = FIRST_EXTERNAL_VECTOR + 5,
+ [6] = FIRST_EXTERNAL_VECTOR + 6,
+ [7] = FIRST_EXTERNAL_VECTOR + 7,
+ [8] = FIRST_EXTERNAL_VECTOR + 8,
+ [9] = FIRST_EXTERNAL_VECTOR + 9,
+ [10] = FIRST_EXTERNAL_VECTOR + 10,
+ [11] = FIRST_EXTERNAL_VECTOR + 11,
+ [12] = FIRST_EXTERNAL_VECTOR + 12,
+ [13] = FIRST_EXTERNAL_VECTOR + 13,
+ [14] = FIRST_EXTERNAL_VECTOR + 14,
+ [15] = FIRST_EXTERNAL_VECTOR + 15,
+};
-int assign_irq_vector(int irq)
+static cpumask_t irq_domain[NR_IRQ_VECTORS] __read_mostly = {
+ [0] = CPU_MASK_ALL,
+ [1] = CPU_MASK_ALL,
+ [2] = CPU_MASK_ALL,
+ [3] = CPU_MASK_ALL,
+ [4] = CPU_MASK_ALL,
+ [5] = CPU_MASK_ALL,
+ [6] = CPU_MASK_ALL,
+ [7] = CPU_MASK_ALL,
+ [8] = CPU_MASK_ALL,
+ [9] = CPU_MASK_ALL,
+ [10] = CPU_MASK_ALL,
+ [11] = CPU_MASK_ALL,
+ [12] = CPU_MASK_ALL,
+ [13] = CPU_MASK_ALL,
+ [14] = CPU_MASK_ALL,
+ [15] = CPU_MASK_ALL,
+};
+
+static int __assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
{
- static int current_vector = FIRST_DEVICE_VECTOR, offset = 0;
- unsigned long flags;
- int vector;
+ /*
+ * NOTE! The local APIC isn't very good at handling
+ * multiple interrupts at the same interrupt level.
+ * As the interrupt level is determined by taking the
+ * vector number and shifting that right by 4, we
+ * want to spread these out a bit so that they don't
+ * all fall in the same interrupt level.
+ *
+ * Also, we've got to be careful not to trash gate
+ * 0x80, because int 0x80 is hm, kind of importantish. ;)
+ */
+ static struct {
+ int vector;
+ int offset;
+ } pos[NR_CPUS] = { [ 0 ... NR_CPUS - 1] = {FIRST_DEVICE_VECTOR, 0} };
+ int old_vector = -1;
+ int cpu;
+
+ BUG_ON((unsigned)irq >= NR_IRQ_VECTORS);
+
+ if (irq_vector[irq] > 0)
+ old_vector = irq_vector[irq];
+ if (old_vector > 0) {
+ cpus_and(*result, irq_domain[irq], mask);
+ if (!cpus_empty(*result))
+ return old_vector;
+ }
- BUG_ON(irq != AUTO_ASSIGN && (unsigned)irq >= NR_IRQ_VECTORS);
+ for_each_cpu_mask(cpu, mask) {
+ cpumask_t domain;
+ int first, new_cpu;
+ int vector, offset;
- spin_lock_irqsave(&vector_lock, flags);
+ domain = vector_allocation_domain(cpu);
+ first = first_cpu(domain);
- if (irq != AUTO_ASSIGN && IO_APIC_VECTOR(irq) > 0) {
- spin_unlock_irqrestore(&vector_lock, flags);
- return IO_APIC_VECTOR(irq);
- }
+ vector = pos[first].vector;
+ offset = pos[first].offset;
next:
- current_vector += 8;
- if (current_vector == IA32_SYSCALL_VECTOR)
- goto next;
-
- if (current_vector >= FIRST_SYSTEM_VECTOR) {
- /* If we run out of vectors on large boxen, must share them. */
- offset = (offset + 1) % 8;
- current_vector = FIRST_DEVICE_VECTOR + offset;
+ vector += 8;
+ if (vector >= FIRST_SYSTEM_VECTOR) {
+ /* If we run out of vectors on large boxen, must share them. */
+ offset = (offset + 1) % 8;
+ vector = FIRST_DEVICE_VECTOR + offset;
+ }
+ if (unlikely(pos[first].vector == vector))
+ continue;
+ if (vector == IA32_SYSCALL_VECTOR)
+ goto next;
+ for_each_cpu_mask(new_cpu, domain)
+ if (per_cpu(vector_irq, new_cpu)[vector] != -1)
+ goto next;
+ /* Found one! */
+ for_each_cpu_mask(new_cpu, domain) {
+ pos[new_cpu].vector = vector;
+ pos[new_cpu].offset = offset;
+ }
+ if (old_vector >= 0) {
+ int old_cpu;
+ for_each_cpu_mask(old_cpu, irq_domain[irq])
+ per_cpu(vector_irq, old_cpu)[old_vector] = -1;
+ }
+ for_each_cpu_mask(new_cpu, domain)
+ per_cpu(vector_irq, new_cpu)[vector] = irq;
+ irq_vector[irq] = vector;
+ irq_domain[irq] = domain;
+ cpus_and(*result, domain, mask);
+ return vector;
}
+ return -ENOSPC;
+}
- vector = current_vector;
- vector_irq[vector] = irq;
- if (irq != AUTO_ASSIGN)
- IO_APIC_VECTOR(irq) = vector;
+static int assign_irq_vector(int irq, cpumask_t mask, cpumask_t *result)
+{
+ int vector;
+ unsigned long flags;
+ spin_lock_irqsave(&vector_lock, flags);
+ vector = __assign_irq_vector(irq, mask, result);
spin_unlock_irqrestore(&vector_lock, flags);
-
return vector;
}
extern void (*interrupt[NR_IRQS])(void);
-static struct hw_interrupt_type ioapic_level_type;
-static struct hw_interrupt_type ioapic_edge_type;
+
+static struct irq_chip ioapic_chip;
#define IOAPIC_AUTO -1
#define IOAPIC_EDGE 0
@@ -642,16 +694,13 @@ static struct hw_interrupt_type ioapic_edge_type;
static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
{
- unsigned idx;
-
- idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
-
if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
trigger == IOAPIC_LEVEL)
- irq_desc[idx].chip = &ioapic_level_type;
+ set_irq_chip_and_handler_name(irq, &ioapic_chip,
+ handle_fasteoi_irq, "fasteoi");
else
- irq_desc[idx].chip = &ioapic_edge_type;
- set_intr_gate(vector, interrupt[idx]);
+ set_irq_chip_and_handler_name(irq, &ioapic_chip,
+ handle_edge_irq, "edge");
}
static void __init setup_IO_APIC_irqs(void)
@@ -701,7 +750,12 @@ static void __init setup_IO_APIC_irqs(void)
continue;
if (IO_APIC_IRQ(irq)) {
- vector = assign_irq_vector(irq);
+ cpumask_t mask;
+ vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
+ if (vector < 0)
+ continue;
+
+ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
entry.vector = vector;
ioapic_register_intr(irq, vector, IOAPIC_AUTO);
@@ -752,7 +806,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
* The timer IRQ doesn't have to know that behind the
* scene we have a 8259A-master in AEOI mode ...
*/
- irq_desc[0].chip = &ioapic_edge_type;
+ set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
/*
* Add it to the IO-APIC irq-routing table:
@@ -868,17 +922,12 @@ void __apicdebuginit print_IO_APIC(void)
);
}
}
- if (use_pci_vector())
- printk(KERN_INFO "Using vector-based indexing\n");
printk(KERN_DEBUG "IRQ to pin mappings:\n");
for (i = 0; i < NR_IRQS; i++) {
struct irq_pin_list *entry = irq_2_pin + i;
if (entry->pin < 0)
continue;
- if (use_pci_vector() && !platform_legacy_irq(i))
- printk(KERN_DEBUG "IRQ%d ", IO_APIC_VECTOR(i));
- else
- printk(KERN_DEBUG "IRQ%d ", i);
+ printk(KERN_DEBUG "IRQ%d ", i);
for (;;) {
printk("-> %d:%d", entry->apic, entry->pin);
if (!entry->next)
@@ -1185,7 +1234,7 @@ static int __init timer_irq_works(void)
* an edge even if it isn't on the 8259A...
*/
-static unsigned int startup_edge_ioapic_irq(unsigned int irq)
+static unsigned int startup_ioapic_irq(unsigned int irq)
{
int was_pending = 0;
unsigned long flags;
@@ -1202,107 +1251,19 @@ static unsigned int startup_edge_ioapic_irq(unsigned int irq)
return was_pending;
}
-/*
- * Once we have recorded IRQ_PENDING already, we can mask the
- * interrupt for real. This prevents IRQ storms from unhandled
- * devices.
- */
-static void ack_edge_ioapic_irq(unsigned int irq)
-{
- move_irq(irq);
- if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
- == (IRQ_PENDING | IRQ_DISABLED))
- mask_IO_APIC_irq(irq);
- ack_APIC_irq();
-}
-
-/*
- * Level triggered interrupts can just be masked,
- * and shutting down and starting up the interrupt
- * is the same as enabling and disabling them -- except
- * with a startup need to return a "was pending" value.
- *
- * Level triggered interrupts are special because we
- * do not touch any IO-APIC register while handling
- * them. We ack the APIC in the end-IRQ handler, not
- * in the start-IRQ-handler. Protection against reentrance
- * from the same interrupt is still provided, both by the
- * generic IRQ layer and by the fact that an unacked local
- * APIC does not accept IRQs.
- */
-static unsigned int startup_level_ioapic_irq (unsigned int irq)
-{
- unmask_IO_APIC_irq(irq);
-
- return 0; /* don't check for pending */
-}
-
-static void end_level_ioapic_irq (unsigned int irq)
-{
- move_irq(irq);
- ack_APIC_irq();
-}
-
-#ifdef CONFIG_PCI_MSI
-static unsigned int startup_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_edge_ioapic_irq(irq);
-}
-
-static void ack_edge_ioapic_vector(unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- ack_edge_ioapic_irq(irq);
-}
-
-static unsigned int startup_level_ioapic_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- return startup_level_ioapic_irq (irq);
-}
-
-static void end_level_ioapic_vector (unsigned int vector)
+static int ioapic_retrigger_irq(unsigned int irq)
{
- int irq = vector_to_irq(vector);
-
- move_native_irq(vector);
- end_level_ioapic_irq(irq);
-}
-
-static void mask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- mask_IO_APIC_irq(irq);
-}
-
-static void unmask_IO_APIC_vector (unsigned int vector)
-{
- int irq = vector_to_irq(vector);
-
- unmask_IO_APIC_irq(irq);
-}
-
-#ifdef CONFIG_SMP
-static void set_ioapic_affinity_vector (unsigned int vector,
- cpumask_t cpu_mask)
-{
- int irq = vector_to_irq(vector);
+ cpumask_t mask;
+ unsigned vector;
+ unsigned long flags;
- set_native_irq_info(vector, cpu_mask);
- set_ioapic_affinity_irq(irq, cpu_mask);
-}
-#endif // CONFIG_SMP
-#endif // CONFIG_PCI_MSI
+ spin_lock_irqsave(&vector_lock, flags);
+ vector = irq_vector[irq];
+ cpus_clear(mask);
+ cpu_set(first_cpu(irq_domain[irq]), mask);
-static int ioapic_retrigger(unsigned int irq)
-{
- send_IPI_self(IO_APIC_VECTOR(irq));
+ send_IPI_mask(mask, vector);
+ spin_unlock_irqrestore(&vector_lock, flags);
return 1;
}
@@ -1316,32 +1277,47 @@ static int ioapic_retrigger(unsigned int irq)
* races.
*/
-static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
- .typename = "IO-APIC-edge",
- .startup = startup_edge_ioapic,
- .shutdown = shutdown_edge_ioapic,
- .enable = enable_edge_ioapic,
- .disable = disable_edge_ioapic,
- .ack = ack_edge_ioapic,
- .end = end_edge_ioapic,
-#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
+static void ack_apic_edge(unsigned int irq)
+{
+ move_native_irq(irq);
+ ack_APIC_irq();
+}
+
+static void ack_apic_level(unsigned int irq)
+{
+ int do_unmask_irq = 0;
+
+#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
+ /* If we are moving the irq we need to mask it */
+ if (unlikely(irq_desc[irq].status & IRQ_MOVE_PENDING)) {
+ do_unmask_irq = 1;
+ mask_IO_APIC_irq(irq);
+ }
#endif
- .retrigger = ioapic_retrigger,
-};
-static struct hw_interrupt_type ioapic_level_type __read_mostly = {
- .typename = "IO-APIC-level",
- .startup = startup_level_ioapic,
- .shutdown = shutdown_level_ioapic,
- .enable = enable_level_ioapic,
- .disable = disable_level_ioapic,
- .ack = mask_and_ack_level_ioapic,
- .end = end_level_ioapic,
+ /*
+ * We must acknowledge the irq before we move it or the acknowledge will
+ * not propogate properly.
+ */
+ ack_APIC_irq();
+
+ /* Now we can move and renable the irq */
+ move_masked_irq(irq);
+ if (unlikely(do_unmask_irq))
+ unmask_IO_APIC_irq(irq);
+}
+
+static struct irq_chip ioapic_chip __read_mostly = {
+ .name = "IO-APIC",
+ .startup = startup_ioapic_irq,
+ .mask = mask_IO_APIC_irq,
+ .unmask = unmask_IO_APIC_irq,
+ .ack = ack_apic_edge,
+ .eoi = ack_apic_level,
#ifdef CONFIG_SMP
- .set_affinity = set_ioapic_affinity,
+ .set_affinity = set_ioapic_affinity_irq,
#endif
- .retrigger = ioapic_retrigger,
+ .retrigger = ioapic_retrigger_irq,
};
static inline void init_IO_APIC_traps(void)
@@ -1361,12 +1337,7 @@ static inline void init_IO_APIC_traps(void)
*/
for (irq = 0; irq < NR_IRQS ; irq++) {
int tmp = irq;
- if (use_pci_vector()) {
- if (!platform_legacy_irq(tmp))
- if ((tmp = vector_to_irq(tmp)) == -1)
- continue;
- }
- if (IO_APIC_IRQ(tmp) && !IO_APIC_VECTOR(tmp)) {
+ if (IO_APIC_IRQ(tmp) && !irq_vector[tmp]) {
/*
* Hmm.. We don't have an entry for this,
* so default to an old-fashioned 8259
@@ -1376,7 +1347,7 @@ static inline void init_IO_APIC_traps(void)
make_8259A_irq(irq);
else
/* Strange. Oh, well.. */
- irq_desc[irq].chip = &no_irq_type;
+ irq_desc[irq].chip = &no_irq_chip;
}
}
}
@@ -1495,8 +1466,6 @@ static inline void unlock_ExtINT_logic(void)
spin_unlock_irqrestore(&ioapic_lock, flags);
}
-int timer_uses_ioapic_pin_0;
-
/*
* This code may look a bit paranoid, but it's supposed to cooperate with
* a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
@@ -1509,13 +1478,13 @@ static inline void check_timer(void)
{
int apic1, pin1, apic2, pin2;
int vector;
+ cpumask_t mask;
/*
* get/set the timer IRQ vector:
*/
disable_8259A_irq(0);
- vector = assign_irq_vector(0);
- set_intr_gate(vector, interrupt[0]);
+ vector = assign_irq_vector(0, TARGET_CPUS, &mask);
/*
* Subtle, code in do_timer_interrupt() expects an AEOI
@@ -1534,9 +1503,6 @@ static inline void check_timer(void)
pin2 = ioapic_i8259.pin;
apic2 = ioapic_i8259.apic;
- if (pin1 == 0)
- timer_uses_ioapic_pin_0 = 1;
-
apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
vector, apic1, pin1, apic2, pin2);
@@ -1740,6 +1706,246 @@ static int __init ioapic_init_sysfs(void)
device_initcall(ioapic_init_sysfs);
+/*
+ * Dynamic irq allocate and deallocation
+ */
+int create_irq(void)
+{
+ /* Allocate an unused irq */
+ int irq;
+ int new;
+ int vector = 0;
+ unsigned long flags;
+ cpumask_t mask;
+
+ irq = -ENOSPC;
+ spin_lock_irqsave(&vector_lock, flags);
+ for (new = (NR_IRQS - 1); new >= 0; new--) {
+ if (platform_legacy_irq(new))
+ continue;
+ if (irq_vector[new] != 0)
+ continue;
+ vector = __assign_irq_vector(new, TARGET_CPUS, &mask);
+ if (likely(vector > 0))
+ irq = new;
+ break;
+ }
+ spin_unlock_irqrestore(&vector_lock, flags);
+
+ if (irq >= 0) {
+ dynamic_irq_init(irq);
+ }
+ return irq;
+}
+
+void destroy_irq(unsigned int irq)
+{
+ unsigned long flags;
+
+ dynamic_irq_cleanup(irq);
+
+ spin_lock_irqsave(&vector_lock, flags);
+ irq_vector[irq] = 0;
+ spin_unlock_irqrestore(&vector_lock, flags);
+}
+
+/*
+ * MSI mesage composition
+ */
+#ifdef CONFIG_PCI_MSI
+static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq, struct msi_msg *msg)
+{
+ int vector;
+ unsigned dest;
+ cpumask_t tmp;
+
+ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
+ if (vector >= 0) {
+ dest = cpu_mask_to_apicid(tmp);
+
+ msg->address_hi = MSI_ADDR_BASE_HI;
+ msg->address_lo =
+ MSI_ADDR_BASE_LO |
+ ((INT_DEST_MODE == 0) ?
+ MSI_ADDR_DEST_MODE_PHYSICAL:
+ MSI_ADDR_DEST_MODE_LOGICAL) |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_ADDR_REDIRECTION_CPU:
+ MSI_ADDR_REDIRECTION_LOWPRI) |
+ MSI_ADDR_DEST_ID(dest);
+
+ msg->data =
+ MSI_DATA_TRIGGER_EDGE |
+ MSI_DATA_LEVEL_ASSERT |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ MSI_DATA_DELIVERY_FIXED:
+ MSI_DATA_DELIVERY_LOWPRI) |
+ MSI_DATA_VECTOR(vector);
+ }
+ return vector;
+}
+
+#ifdef CONFIG_SMP
+static void set_msi_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ struct msi_msg msg;
+ unsigned int dest;
+ cpumask_t tmp;
+ int vector;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+ vector = assign_irq_vector(irq, mask, &tmp);
+ if (vector < 0)
+ return;
+
+ dest = cpu_mask_to_apicid(tmp);
+
+ read_msi_msg(irq, &msg);
+
+ msg.data &= ~MSI_DATA_VECTOR_MASK;
+ msg.data |= MSI_DATA_VECTOR(vector);
+ msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
+ msg.address_lo |= MSI_ADDR_DEST_ID(dest);
+
+ write_msi_msg(irq, &msg);
+ set_native_irq_info(irq, mask);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
+ * which implement the MSI or MSI-X Capability Structure.
+ */
+static struct irq_chip msi_chip = {
+ .name = "PCI-MSI",
+ .unmask = unmask_msi_irq,
+ .mask = mask_msi_irq,
+ .ack = ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = set_msi_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+{
+ struct msi_msg msg;
+ int ret;
+ ret = msi_compose_msg(dev, irq, &msg);
+ if (ret < 0)
+ return ret;
+
+ write_msi_msg(irq, &msg);
+
+ set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
+
+ return 0;
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+ return;
+}
+
+#endif /* CONFIG_PCI_MSI */
+
+/*
+ * Hypertransport interrupt support
+ */
+#ifdef CONFIG_HT_IRQ
+
+#ifdef CONFIG_SMP
+
+static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
+{
+ u32 low, high;
+ low = read_ht_irq_low(irq);
+ high = read_ht_irq_high(irq);
+
+ low &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
+ high &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
+
+ low |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
+ high |= HT_IRQ_HIGH_DEST_ID(dest);
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+}
+
+static void set_ht_irq_affinity(unsigned int irq, cpumask_t mask)
+{
+ unsigned int dest;
+ cpumask_t tmp;
+ int vector;
+
+ cpus_and(tmp, mask, cpu_online_map);
+ if (cpus_empty(tmp))
+ tmp = TARGET_CPUS;
+
+ cpus_and(mask, tmp, CPU_MASK_ALL);
+
+ vector = assign_irq_vector(irq, mask, &tmp);
+ if (vector < 0)
+ return;
+
+ dest = cpu_mask_to_apicid(tmp);
+
+ target_ht_irq(irq, dest, vector & 0xff);
+ set_native_irq_info(irq, mask);
+}
+#endif
+
+static struct irq_chip ht_irq_chip = {
+ .name = "PCI-HT",
+ .mask = mask_ht_irq,
+ .unmask = unmask_ht_irq,
+ .ack = ack_apic_edge,
+#ifdef CONFIG_SMP
+ .set_affinity = set_ht_irq_affinity,
+#endif
+ .retrigger = ioapic_retrigger_irq,
+};
+
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
+{
+ int vector;
+ cpumask_t tmp;
+
+ vector = assign_irq_vector(irq, TARGET_CPUS, &tmp);
+ if (vector >= 0) {
+ u32 low, high;
+ unsigned dest;
+
+ dest = cpu_mask_to_apicid(tmp);
+
+ high = HT_IRQ_HIGH_DEST_ID(dest);
+
+ low = HT_IRQ_LOW_BASE |
+ HT_IRQ_LOW_DEST_ID(dest) |
+ HT_IRQ_LOW_VECTOR(vector) |
+ ((INT_DEST_MODE == 0) ?
+ HT_IRQ_LOW_DM_PHYSICAL :
+ HT_IRQ_LOW_DM_LOGICAL) |
+ HT_IRQ_LOW_RQEOI_EDGE |
+ ((INT_DELIVERY_MODE != dest_LowestPrio) ?
+ HT_IRQ_LOW_MT_FIXED :
+ HT_IRQ_LOW_MT_ARBITRATED);
+
+ write_ht_irq_low(irq, low);
+ write_ht_irq_high(irq, high);
+
+ set_irq_chip_and_handler_name(irq, &ht_irq_chip,
+ handle_edge_irq, "edge");
+ }
+ return vector;
+}
+#endif /* CONFIG_HT_IRQ */
+
/* --------------------------------------------------------------------------
ACPI-based IOAPIC Configuration
-------------------------------------------------------------------------- */
@@ -1765,6 +1971,8 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
{
struct IO_APIC_route_entry entry;
unsigned long flags;
+ int vector;
+ cpumask_t mask;
if (!IO_APIC_IRQ(irq)) {
apic_printk(APIC_QUIET,KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0\n",
@@ -1773,6 +1981,17 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
}
/*
+ * IRQs < 16 are already in the irq_2_pin[] map
+ */
+ if (irq >= 16)
+ add_pin_to_irq(irq, ioapic, pin);
+
+
+ vector = assign_irq_vector(irq, TARGET_CPUS, &mask);
+ if (vector < 0)
+ return vector;
+
+ /*
* Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
* Note that we mask (disable) IRQs now -- these get enabled when the
* corresponding device driver registers for this IRQ.
@@ -1782,19 +2001,11 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
entry.delivery_mode = INT_DELIVERY_MODE;
entry.dest_mode = INT_DEST_MODE;
- entry.dest.logical.logical_dest = cpu_mask_to_apicid(TARGET_CPUS);
+ entry.dest.logical.logical_dest = cpu_mask_to_apicid(mask);
entry.trigger = triggering;
entry.polarity = polarity;
entry.mask = 1; /* Disabled (masked) */
-
- irq = gsi_irq_sharing(irq);
- /*
- * IRQs < 16 are already in the irq_2_pin[] map
- */
- if (irq >= 16)
- add_pin_to_irq(irq, ioapic, pin);
-
- entry.vector = assign_irq_vector(irq);
+ entry.vector = vector & 0xff;
apic_printk(APIC_VERBOSE,KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
"IRQ %d Mode:%i Active:%i)\n", ioapic,
@@ -1809,7 +2020,7 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int triggering, int p
ioapic_write_entry(ioapic, pin, entry);
spin_lock_irqsave(&ioapic_lock, flags);
- set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
+ set_native_irq_info(irq, TARGET_CPUS);
spin_unlock_irqrestore(&ioapic_lock, flags);
return 0;
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index b3677e6ccc6e..e46c55856d40 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -74,7 +74,8 @@ int show_interrupts(struct seq_file *p, void *v)
for_each_online_cpu(j)
seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
- seq_printf(p, " %14s", irq_desc[i].chip->typename);
+ seq_printf(p, " %8s", irq_desc[i].chip->name);
+ seq_printf(p, "-%-8s", irq_desc[i].name);
seq_printf(p, " %s", action->name);
for (action=action->next; action; action = action->next)
@@ -102,24 +103,30 @@ skip:
* handlers).
*/
asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
-{
- /* high bit used in ret_from_ code */
- unsigned irq = ~regs->orig_rax;
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
- if (unlikely(irq >= NR_IRQS)) {
- printk(KERN_EMERG "%s: cannot handle IRQ %d\n",
- __FUNCTION__, irq);
- BUG();
- }
+ /* high bit used in ret_from_ code */
+ unsigned vector = ~regs->orig_rax;
+ unsigned irq;
exit_idle();
irq_enter();
+ irq = __get_cpu_var(vector_irq)[vector];
+
#ifdef CONFIG_DEBUG_STACKOVERFLOW
stack_overflow_check(regs);
#endif
- __do_IRQ(irq, regs);
+
+ if (likely(irq < NR_IRQS))
+ generic_handle_irq(irq);
+ else
+ printk(KERN_EMERG "%s: %d.%d No irq handler for vector\n",
+ __func__, smp_processor_id(), vector);
+
irq_exit();
+ set_irq_regs(old_regs);
return 1;
}
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index ffc73ac72485..ac241567e682 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -270,20 +270,19 @@ void __kprobes arch_prepare_kretprobe(struct kretprobe *rp,
struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)regs->rsp;
- struct kretprobe_instance *ri;
+ struct kretprobe_instance *ri;
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->task = current;
+ if ((ri = get_free_rp_inst(rp)) != NULL) {
+ ri->rp = rp;
+ ri->task = current;
ri->ret_addr = (kprobe_opcode_t *) *sara;
/* Replace the return addr with trampoline addr */
*sara = (unsigned long) &kretprobe_trampoline;
-
- add_rp_inst(ri);
- } else {
- rp->nmissed++;
- }
+ add_rp_inst(ri);
+ } else {
+ rp->nmissed++;
+ }
}
int __kprobes kprobe_handler(struct pt_regs *regs)
@@ -405,14 +404,15 @@ no_kprobe:
*/
int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
- struct kretprobe_instance *ri = NULL;
- struct hlist_head *head;
- struct hlist_node *node, *tmp;
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+ INIT_HLIST_HEAD(&empty_rp);
spin_lock_irqsave(&kretprobe_lock, flags);
- head = kretprobe_inst_table_head(current);
+ head = kretprobe_inst_table_head(current);
/*
* It is possible to have multiple instances associated with a given
@@ -423,20 +423,20 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
* We can handle this because:
* - instances are always inserted at the head of the list
* - when multiple return probes are registered for the same
- * function, the first instance's ret_addr will point to the
+ * function, the first instance's ret_addr will point to the
* real return address, and all the rest will point to
* kretprobe_trampoline
*/
hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task != current)
+ if (ri->task != current)
/* another task is sharing our hash bucket */
- continue;
+ continue;
if (ri->rp && ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_address = (unsigned long)ri->ret_addr;
- recycle_rp_inst(ri);
+ recycle_rp_inst(ri, &empty_rp);
if (orig_ret_address != trampoline_address)
/*
@@ -454,12 +454,16 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
spin_unlock_irqrestore(&kretprobe_lock, flags);
preempt_enable_no_resched();
- /*
- * By returning a non-zero value, we are telling
- * kprobe_handler() that we don't want the post_handler
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we don't want the post_handler
* to run (and have re-enabled preemption)
- */
- return 1;
+ */
+ return 1;
}
/*
diff --git a/arch/x86_64/kernel/mpparse.c b/arch/x86_64/kernel/mpparse.c
index 20e88f4b564b..b147ab19fbd4 100644
--- a/arch/x86_64/kernel/mpparse.c
+++ b/arch/x86_64/kernel/mpparse.c
@@ -152,6 +152,21 @@ static void __init MP_bus_info (struct mpc_config_bus *m)
}
}
+static int bad_ioapic(unsigned long address)
+{
+ if (nr_ioapics >= MAX_IO_APICS) {
+ printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
+ "(found %d)\n", MAX_IO_APICS, nr_ioapics);
+ panic("Recompile kernel with bigger MAX_IO_APICS!\n");
+ }
+ if (!address) {
+ printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
+ " found in table, skipping!\n");
+ return 1;
+ }
+ return 0;
+}
+
static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
{
if (!(m->mpc_flags & MPC_APIC_USABLE))
@@ -159,16 +174,10 @@ static void __init MP_ioapic_info (struct mpc_config_ioapic *m)
printk("I/O APIC #%d at 0x%X.\n",
m->mpc_apicid, m->mpc_apicaddr);
- if (nr_ioapics >= MAX_IO_APICS) {
- printk(KERN_ERR "Max # of I/O APICs (%d) exceeded (found %d).\n",
- MAX_IO_APICS, nr_ioapics);
- panic("Recompile kernel with bigger MAX_IO_APICS!.\n");
- }
- if (!m->mpc_apicaddr) {
- printk(KERN_ERR "WARNING: bogus zero I/O APIC address"
- " found in MP table, skipping!\n");
+
+ if (bad_ioapic(m->mpc_apicaddr))
return;
- }
+
mp_ioapics[nr_ioapics] = *m;
nr_ioapics++;
}
@@ -647,16 +656,8 @@ void __init mp_register_ioapic(u8 id, u32 address, u32 gsi_base)
{
int idx = 0;
- if (nr_ioapics >= MAX_IO_APICS) {
- printk(KERN_ERR "ERROR: Max # of I/O APICs (%d) exceeded "
- "(found %d)\n", MAX_IO_APICS, nr_ioapics);
- panic("Recompile kernel with bigger MAX_IO_APICS!\n");
- }
- if (!address) {
- printk(KERN_ERR "WARNING: Bogus (zero) I/O APIC address"
- " found in MADT table, skipping!\n");
+ if (bad_ioapic(address))
return;
- }
idx = nr_ioapics++;
@@ -789,20 +790,11 @@ void __init mp_config_acpi_legacy_irqs(void)
}
}
-#define MAX_GSI_NUM 4096
-
int mp_register_gsi(u32 gsi, int triggering, int polarity)
{
int ioapic = -1;
int ioapic_pin = 0;
int idx, bit = 0;
- static int pci_irq = 16;
- /*
- * Mapping between Global System Interrupts, which
- * represent all possible interrupts, to the IRQs
- * assigned to actual devices.
- */
- static int gsi_to_irq[MAX_GSI_NUM];
if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC)
return gsi;
@@ -835,42 +827,11 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
if ((1<<bit) & mp_ioapic_routing[ioapic].pin_programmed[idx]) {
Dprintk(KERN_DEBUG "Pin %d-%d already programmed\n",
mp_ioapic_routing[ioapic].apic_id, ioapic_pin);
- return gsi_to_irq[gsi];
+ return gsi;
}
mp_ioapic_routing[ioapic].pin_programmed[idx] |= (1<<bit);
- if (triggering == ACPI_LEVEL_SENSITIVE) {
- /*
- * For PCI devices assign IRQs in order, avoiding gaps
- * due to unused I/O APIC pins.
- */
- int irq = gsi;
- if (gsi < MAX_GSI_NUM) {
- /*
- * Retain the VIA chipset work-around (gsi > 15), but
- * avoid a problem where the 8254 timer (IRQ0) is setup
- * via an override (so it's not on pin 0 of the ioapic),
- * and at the same time, the pin 0 interrupt is a PCI
- * type. The gsi > 15 test could cause these two pins
- * to be shared as IRQ0, and they are not shareable.
- * So test for this condition, and if necessary, avoid
- * the pin collision.
- */
- if (gsi > 15 || (gsi == 0 && !timer_uses_ioapic_pin_0))
- gsi = pci_irq++;
- /*
- * Don't assign IRQ used by ACPI SCI
- */
- if (gsi == acpi_fadt.sci_int)
- gsi = pci_irq++;
- gsi_to_irq[irq] = gsi;
- } else {
- printk(KERN_ERR "GSI %u is too high\n", gsi);
- return gsi;
- }
- }
-
io_apic_set_pci_routing(ioapic, ioapic_pin, gsi,
triggering == ACPI_EDGE_SENSITIVE ? 0 : 1,
polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 4d6fb047952e..7af9cb3e2d99 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -28,6 +28,10 @@
#include <asm/mce.h>
#include <asm/intel_arch_perfmon.h>
+int unknown_nmi_panic;
+int nmi_watchdog_enabled;
+int panic_on_unrecovered_nmi;
+
/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
* evtsel_nmi_owner tracks the ownership of the event selection
* - different performance counters/ event selection may be reserved for
diff --git a/arch/x86_64/kernel/pci-calgary.c b/arch/x86_64/kernel/pci-calgary.c
index cfb09b07ae99..b3296cc2f2f2 100644
--- a/arch/x86_64/kernel/pci-calgary.c
+++ b/arch/x86_64/kernel/pci-calgary.c
@@ -2,8 +2,9 @@
* Derived from arch/powerpc/kernel/iommu.c
*
* Copyright (C) IBM Corporation, 2006
+ * Copyright (C) 2006 Jon Mason <jdmason@kudzu.us>
*
- * Author: Jon Mason <jdmason@us.ibm.com>
+ * Author: Jon Mason <jdmason@kudzu.us>
* Author: Muli Ben-Yehuda <muli@il.ibm.com>
* This program is free software; you can redistribute it and/or modify
@@ -21,7 +22,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -715,7 +715,7 @@ static void calgary_watchdog(unsigned long data)
/* If no error, the agent ID in the CSR is not valid */
if (val32 & CSR_AGENT_MASK) {
- printk(KERN_EMERG "calgary_watchdog: DMA error on bus %d, "
+ printk(KERN_EMERG "calgary_watchdog: DMA error on PHB %#x, "
"CSR = %#x\n", dev->bus->number, val32);
writel(0, target);
@@ -749,7 +749,7 @@ static void __init calgary_enable_translation(struct pci_dev *dev)
val32 = be32_to_cpu(readl(target));
val32 |= PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE;
- printk(KERN_INFO "Calgary: enabling translation on PHB %d\n", busnum);
+ printk(KERN_INFO "Calgary: enabling translation on PHB %#x\n", busnum);
printk(KERN_INFO "Calgary: errant DMAs will now be prevented on this "
"bus.\n");
@@ -779,7 +779,7 @@ static void __init calgary_disable_translation(struct pci_dev *dev)
val32 = be32_to_cpu(readl(target));
val32 &= ~(PHB_TCE_ENABLE | PHB_DAC_DISABLE | PHB_MCSR_ENABLE);
- printk(KERN_INFO "Calgary: disabling translation on PHB %d!\n", busnum);
+ printk(KERN_INFO "Calgary: disabling translation on PHB %#x!\n", busnum);
writel(cpu_to_be32(val32), target);
readl(target); /* flush */
@@ -791,7 +791,16 @@ static inline unsigned int __init locate_register_space(struct pci_dev *dev)
int rionodeid;
u32 address;
- rionodeid = (dev->bus->number % 15 > 4) ? 3 : 2;
+ /*
+ * Each Calgary has four busses. The first four busses (first Calgary)
+ * have RIO node ID 2, then the next four (second Calgary) have RIO
+ * node ID 3, the next four (third Calgary) have node ID 2 again, etc.
+ * We use a gross hack - relying on the dev->bus->number ordering,
+ * modulo 14 - to decide which Calgary a given bus is on. Busses 0, 1,
+ * 2 and 4 are on the first Calgary (id 2), 6, 8, a and c are on the
+ * second (id 3), and then it repeats modulo 14.
+ */
+ rionodeid = (dev->bus->number % 14 > 4) ? 3 : 2;
/*
* register space address calculation as follows:
* FE0MB-8MB*OneBasedChassisNumber+1MB*(RioNodeId-ChassisBase)
@@ -799,7 +808,7 @@ static inline unsigned int __init locate_register_space(struct pci_dev *dev)
* RioNodeId is 2 for first Calgary, 3 for second Calgary
*/
address = START_ADDRESS -
- (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 15)) +
+ (0x800000 * (ONE_BASED_CHASSIS_NUM + dev->bus->number / 14)) +
(0x100000) * (rionodeid - CHASSIS_BASE);
return address;
}
@@ -817,6 +826,8 @@ static int __init calgary_init_one(struct pci_dev *dev)
void __iomem *bbar;
int ret;
+ BUG_ON(dev->bus->number >= MAX_PHB_BUS_NUM);
+
address = locate_register_space(dev);
/* map entire 1MB of Calgary config space */
bbar = ioremap_nocache(address, 1024 * 1024);
@@ -843,10 +854,10 @@ done:
static int __init calgary_init(void)
{
- int i, ret = -ENODEV;
+ int ret = -ENODEV;
struct pci_dev *dev = NULL;
- for (i = 0; i < MAX_PHB_BUS_NUM; i++) {
+ do {
dev = pci_get_device(PCI_VENDOR_ID_IBM,
PCI_DEVICE_ID_IBM_CALGARY,
dev);
@@ -862,12 +873,12 @@ static int __init calgary_init(void)
ret = calgary_init_one(dev);
if (ret)
goto error;
- }
+ } while (1);
return ret;
error:
- for (i--; i >= 0; i--) {
+ do {
dev = pci_find_device_reverse(PCI_VENDOR_ID_IBM,
PCI_DEVICE_ID_IBM_CALGARY,
dev);
@@ -883,7 +894,7 @@ error:
calgary_disable_translation(dev);
calgary_free_bus(dev);
pci_dev_put(dev); /* Undo calgary_init_one()'s pci_dev_get() */
- }
+ } while (1);
return ret;
}
@@ -1053,7 +1064,7 @@ static int __init calgary_parse_options(char *p)
if (bridge < MAX_PHB_BUS_NUM) {
printk(KERN_INFO "Calgary: disabling "
- "translation for PHB 0x%x\n", bridge);
+ "translation for PHB %#x\n", bridge);
bus_info[bridge].translation_disabled = 1;
}
}
diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
index 4dcb671bd19f..f8d857453f8a 100644
--- a/arch/x86_64/kernel/pci-dma.c
+++ b/arch/x86_64/kernel/pci-dma.c
@@ -170,8 +170,20 @@ void dma_free_coherent(struct device *dev, size_t size,
}
EXPORT_SYMBOL(dma_free_coherent);
+static int forbid_dac __read_mostly;
+
int dma_supported(struct device *dev, u64 mask)
{
+#ifdef CONFIG_PCI
+ if (mask > 0xffffffff && forbid_dac > 0) {
+
+
+
+ printk(KERN_INFO "PCI: Disallowing DAC for device %s\n", dev->bus_id);
+ return 0;
+ }
+#endif
+
if (dma_ops->dma_supported)
return dma_ops->dma_supported(dev, mask);
@@ -231,57 +243,64 @@ EXPORT_SYMBOL(dma_set_mask);
allowed overwrite iommu off workarounds for specific chipsets.
soft Use software bounce buffering (default for Intel machines)
noaperture Don't touch the aperture for AGP.
+ allowdac Allow DMA >4GB
+ nodac Forbid DMA >4GB
+ panic Force panic when IOMMU overflows
*/
__init int iommu_setup(char *p)
{
- iommu_merge = 1;
+ iommu_merge = 1;
if (!p)
return -EINVAL;
- while (*p) {
- if (!strncmp(p,"off",3))
- no_iommu = 1;
- /* gart_parse_options has more force support */
- if (!strncmp(p,"force",5))
- force_iommu = 1;
- if (!strncmp(p,"noforce",7)) {
- iommu_merge = 0;
- force_iommu = 0;
- }
-
- if (!strncmp(p, "biomerge",8)) {
- iommu_bio_merge = 4096;
- iommu_merge = 1;
- force_iommu = 1;
- }
- if (!strncmp(p, "panic",5))
- panic_on_overflow = 1;
- if (!strncmp(p, "nopanic",7))
- panic_on_overflow = 0;
- if (!strncmp(p, "merge",5)) {
- iommu_merge = 1;
- force_iommu = 1;
- }
- if (!strncmp(p, "nomerge",7))
- iommu_merge = 0;
- if (!strncmp(p, "forcesac",8))
- iommu_sac_force = 1;
+ while (*p) {
+ if (!strncmp(p,"off",3))
+ no_iommu = 1;
+ /* gart_parse_options has more force support */
+ if (!strncmp(p,"force",5))
+ force_iommu = 1;
+ if (!strncmp(p,"noforce",7)) {
+ iommu_merge = 0;
+ force_iommu = 0;
+ }
+
+ if (!strncmp(p, "biomerge",8)) {
+ iommu_bio_merge = 4096;
+ iommu_merge = 1;
+ force_iommu = 1;
+ }
+ if (!strncmp(p, "panic",5))
+ panic_on_overflow = 1;
+ if (!strncmp(p, "nopanic",7))
+ panic_on_overflow = 0;
+ if (!strncmp(p, "merge",5)) {
+ iommu_merge = 1;
+ force_iommu = 1;
+ }
+ if (!strncmp(p, "nomerge",7))
+ iommu_merge = 0;
+ if (!strncmp(p, "forcesac",8))
+ iommu_sac_force = 1;
+ if (!strncmp(p, "allowdac", 8))
+ forbid_dac = 0;
+ if (!strncmp(p, "nodac", 5))
+ forbid_dac = -1;
#ifdef CONFIG_SWIOTLB
- if (!strncmp(p, "soft",4))
- swiotlb = 1;
+ if (!strncmp(p, "soft",4))
+ swiotlb = 1;
#endif
#ifdef CONFIG_IOMMU
- gart_parse_options(p);
+ gart_parse_options(p);
#endif
- p += strcspn(p, ",");
- if (*p == ',')
- ++p;
- }
- return 0;
+ p += strcspn(p, ",");
+ if (*p == ',')
+ ++p;
+ }
+ return 0;
}
early_param("iommu", iommu_setup);
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index 6a55f87ba97f..697f0aa794b9 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -3,7 +3,8 @@
#include <linux/pci.h>
#include <linux/cache.h>
#include <linux/module.h>
-#include <asm/dma-mapping.h>
+#include <linux/dma-mapping.h>
+
#include <asm/proto.h>
#include <asm/swiotlb.h>
#include <asm/dma.h>
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 458006ae19f3..49f7fac6229e 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -238,20 +238,28 @@ void cpu_idle (void)
* We execute MONITOR against need_resched and enter optimized wait state
* through MWAIT. Whenever someone changes need_resched, we would be woken
* up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
*/
-static void mwait_idle(void)
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
{
- local_irq_enable();
-
- while (!need_resched()) {
+ if (!need_resched()) {
__monitor((void *)&current_thread_info()->flags, 0, 0);
smp_mb();
- if (need_resched())
- break;
- __mwait(0, 0);
+ if (!need_resched())
+ __mwait(eax, ecx);
}
}
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
+static void mwait_idle(void)
+{
+ local_irq_enable();
+ while (!need_resched())
+ mwait_idle_with_hints(0,0);
+}
+
void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
{
static int printed;
@@ -294,9 +302,9 @@ void __show_regs(struct pt_regs * regs)
print_modules();
printk("Pid: %d, comm: %.20s %s %s %.*s\n",
current->pid, current->comm, print_tainted(),
- system_utsname.release,
- (int)strcspn(system_utsname.version, " "),
- system_utsname.version);
+ init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
printk("RIP: %04lx:[<%016lx>] ", regs->cs & 0xffff, regs->rip);
printk_address(regs->rip);
printk("RSP: %04lx:%016lx EFLAGS: %08lx\n", regs->ss, regs->rsp,
@@ -615,6 +623,9 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
prev->gsindex = gsindex;
}
+ /* Must be after DS reload */
+ unlazy_fpu(prev_p);
+
/*
* Switch the PDA and FPU contexts.
*/
@@ -622,10 +633,6 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
write_pda(oldrsp, next->userrsp);
write_pda(pcurrent, next_p);
- /* This must be here to ensure both math_state_restore() and
- kernel_fpu_begin() work consistently.
- And the AMD workaround requires it to be after DS reload. */
- unlazy_fpu(prev_p);
write_pda(kernelstack,
(unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET);
#ifdef CONFIG_CC_STACKPROTECTOR
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index f98e48cae6da..fc944b5e8f4a 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -123,9 +123,6 @@ struct resource standard_io_resources[] = {
.flags = IORESOURCE_BUSY | IORESOURCE_IO }
};
-#define STANDARD_IO_RESOURCES \
- (sizeof standard_io_resources / sizeof standard_io_resources[0])
-
#define IORESOURCE_RAM (IORESOURCE_BUSY | IORESOURCE_MEM)
struct resource data_resource = {
@@ -172,9 +169,6 @@ static struct resource adapter_rom_resources[] = {
.flags = IORESOURCE_ROM }
};
-#define ADAPTER_ROM_RESOURCES \
- (sizeof adapter_rom_resources / sizeof adapter_rom_resources[0])
-
static struct resource video_rom_resource = {
.name = "Video ROM",
.start = 0xc0000,
@@ -245,7 +239,8 @@ static void __init probe_roms(void)
}
/* check for adapter roms on 2k boundaries */
- for (i = 0; i < ADAPTER_ROM_RESOURCES && start < upper; start += 2048) {
+ for (i = 0; i < ARRAY_SIZE(adapter_rom_resources) && start < upper;
+ start += 2048) {
rom = isa_bus_to_virt(start);
if (!romsignature(rom))
continue;
@@ -292,7 +287,8 @@ contig_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
if (bootmap == -1L)
panic("Cannot find bootmem map of size %ld\n",bootmap_size);
bootmap_size = init_bootmem(bootmap >> PAGE_SHIFT, end_pfn);
- e820_bootmem_free(NODE_DATA(0), 0, end_pfn << PAGE_SHIFT);
+ e820_register_active_regions(0, start_pfn, end_pfn);
+ free_bootmem_with_active_regions(0, end_pfn);
reserve_bootmem(bootmap, bootmap_size);
}
#endif
@@ -384,6 +380,7 @@ void __init setup_arch(char **cmdline_p)
finish_e820_parsing();
+ e820_register_active_regions(0, 0, -1UL);
/*
* partially used pages are not usable - thus
* we are rounding upwards:
@@ -414,6 +411,9 @@ void __init setup_arch(char **cmdline_p)
max_pfn = end_pfn;
high_memory = (void *)__va(end_pfn * PAGE_SIZE - 1) + 1;
+ /* Remove active ranges so rediscovery with NUMA-awareness happens */
+ remove_all_active_ranges();
+
#ifdef CONFIG_ACPI_NUMA
/*
* Parse SRAT to discover nodes.
@@ -532,7 +532,7 @@ void __init setup_arch(char **cmdline_p)
{
unsigned i;
/* request I/O space for devices used on all i[345]86 PCs */
- for (i = 0; i < STANDARD_IO_RESOURCES; i++)
+ for (i = 0; i < ARRAY_SIZE(standard_io_resources); i++)
request_resource(&ioport_resource, &standard_io_resources[i]);
}
diff --git a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c
index 6449ea8fe756..76bf7c241fe4 100644
--- a/arch/x86_64/kernel/sys_x86_64.c
+++ b/arch/x86_64/kernel/sys_x86_64.c
@@ -148,7 +148,7 @@ asmlinkage long sys_uname(struct new_utsname __user * name)
{
int err;
down_read(&uts_sem);
- err = copy_to_user(name, &system_utsname, sizeof (*name));
+ err = copy_to_user(name, utsname(), sizeof (*name));
up_read(&uts_sem);
if (personality(current->personality) == PER_LINUX32)
err |= copy_to_user(&name->machine, "i686", 5);
diff --git a/arch/x86_64/kernel/tce.c b/arch/x86_64/kernel/tce.c
index cbabfdf78e06..f61fb8e4f129 100644
--- a/arch/x86_64/kernel/tce.c
+++ b/arch/x86_64/kernel/tce.c
@@ -23,7 +23,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/mm.h>
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index 1c255ee76e7c..1ba5a442ac32 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -77,7 +77,6 @@ unsigned long long monotonic_base;
struct vxtime_data __vxtime __section_vxtime; /* for vsyscalls */
volatile unsigned long __jiffies __section_jiffies = INITIAL_JIFFIES;
-unsigned long __wall_jiffies __section_wall_jiffies = INITIAL_JIFFIES;
struct timespec __xtime __section_xtime;
struct timezone __sys_tz __section_sys_tz;
@@ -119,7 +118,7 @@ unsigned int (*do_gettimeoffset)(void) = do_gettimeoffset_tsc;
void do_gettimeofday(struct timeval *tv)
{
- unsigned long seq, t;
+ unsigned long seq;
unsigned int sec, usec;
do {
@@ -136,10 +135,7 @@ void do_gettimeofday(struct timeval *tv)
be found. Note when you fix it here you need to do the same
in arch/x86_64/kernel/vsyscall.c and export all needed
variables in vmlinux.lds. -AK */
-
- t = (jiffies - wall_jiffies) * USEC_PER_TICK +
- do_gettimeoffset();
- usec += t;
+ usec += do_gettimeoffset();
} while (read_seqretry(&xtime_lock, seq));
@@ -165,8 +161,7 @@ int do_settimeofday(struct timespec *tv)
write_seqlock_irq(&xtime_lock);
- nsec -= do_gettimeoffset() * NSEC_PER_USEC +
- (jiffies - wall_jiffies) * NSEC_PER_TICK;
+ nsec -= do_gettimeoffset() * NSEC_PER_USEC;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -307,20 +302,20 @@ unsigned long long monotonic_clock(void)
}
EXPORT_SYMBOL(monotonic_clock);
-static noinline void handle_lost_ticks(int lost, struct pt_regs *regs)
+static noinline void handle_lost_ticks(int lost)
{
static long lost_count;
static int warned;
if (report_lost_ticks) {
printk(KERN_WARNING "time.c: Lost %d timer tick(s)! ", lost);
- print_symbol("rip %s)\n", regs->rip);
+ print_symbol("rip %s)\n", get_irq_regs()->rip);
}
if (lost_count == 1000 && !warned) {
printk(KERN_WARNING "warning: many lost ticks.\n"
KERN_WARNING "Your time source seems to be instable or "
"some driver is hogging interupts\n");
- print_symbol("rip %s\n", regs->rip);
+ print_symbol("rip %s\n", get_irq_regs()->rip);
if (vxtime.mode == VXTIME_TSC && vxtime.hpet_address) {
printk(KERN_WARNING "Falling back to HPET\n");
if (hpet_use_timer)
@@ -344,7 +339,7 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs)
#endif
}
-void main_timer_handler(struct pt_regs *regs)
+void main_timer_handler(void)
{
static unsigned long rtc_update = 0;
unsigned long tsc;
@@ -415,18 +410,18 @@ void main_timer_handler(struct pt_regs *regs)
(((long) offset << US_SCALE) / vxtime.tsc_quot) - 1;
}
- if (lost > 0) {
- handle_lost_ticks(lost, regs);
- jiffies += lost;
- }
+ if (lost > 0)
+ handle_lost_ticks(lost);
+ else
+ lost = 0;
/*
* Do the timer stuff.
*/
- do_timer(regs);
+ do_timer(lost + 1);
#ifndef CONFIG_SMP
- update_process_times(user_mode(regs));
+ update_process_times(user_mode(get_irq_regs()));
#endif
/*
@@ -436,7 +431,7 @@ void main_timer_handler(struct pt_regs *regs)
*/
if (!using_apic_timer)
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
/*
* If we have an externally synchronized Linux clock, then update CMOS clock
@@ -455,11 +450,11 @@ void main_timer_handler(struct pt_regs *regs)
write_sequnlock(&xtime_lock);
}
-static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
{
if (apic_runs_main_timer > 1)
return IRQ_HANDLED;
- main_timer_handler(regs);
+ main_timer_handler();
if (using_apic_timer)
smp_send_timer_broadcast_ipi();
return IRQ_HANDLED;
@@ -1071,7 +1066,6 @@ static int timer_resume(struct sys_device *dev)
vxtime.last_tsc = get_cycles_sync();
write_sequnlock_irqrestore(&xtime_lock,flags);
jiffies += sleep_length;
- wall_jiffies += sleep_length;
monotonic_base += sleep_length * (NSEC_PER_SEC/HZ);
touch_softlockup_watchdog();
return 0;
@@ -1343,7 +1337,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (call_rtc_interrupt) {
rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));
- rtc_interrupt(rtc_int_flag, dev_id, regs);
+ rtc_interrupt(rtc_int_flag, dev_id);
}
return IRQ_HANDLED;
}
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 01f2a8d254c2..7819022a8db5 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -23,6 +23,7 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
+#include <linux/kallsyms.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/nmi.h>
@@ -115,7 +116,6 @@ static int call_trace = 1;
#endif
#ifdef CONFIG_KALLSYMS
-# include <linux/kallsyms.h>
void printk_address(unsigned long address)
{
unsigned long offset = 0, symsize;
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index d0564f1bcb0b..1283614c9b24 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -17,6 +17,7 @@ PHDRS {
text PT_LOAD FLAGS(5); /* R_E */
data PT_LOAD FLAGS(7); /* RWE */
user PT_LOAD FLAGS(7); /* RWE */
+ data.init PT_LOAD FLAGS(7); /* RWE */
note PT_NOTE FLAGS(4); /* R__ */
}
SECTIONS
@@ -67,13 +68,6 @@ SECTIONS
_edata = .; /* End of data section */
- __bss_start = .; /* BSS */
- .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
- *(.bss.page_aligned)
- *(.bss)
- }
- __bss_stop = .;
-
. = ALIGN(PAGE_SIZE);
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
@@ -108,9 +102,6 @@ SECTIONS
.vgetcpu_mode : AT(VLOAD(.vgetcpu_mode)) { *(.vgetcpu_mode) }
vgetcpu_mode = VVIRT(.vgetcpu_mode);
- .wall_jiffies : AT(VLOAD(.wall_jiffies)) { *(.wall_jiffies) }
- wall_jiffies = VVIRT(.wall_jiffies);
-
.sys_tz : AT(VLOAD(.sys_tz)) { *(.sys_tz) }
sys_tz = VVIRT(.sys_tz);
@@ -141,7 +132,7 @@ SECTIONS
. = ALIGN(8192); /* init_task */
.data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
*(.data.init_task)
- } :data
+ }:data.init
. = ALIGN(4096);
.data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
@@ -229,6 +220,13 @@ SECTIONS
. = ALIGN(4096);
__nosave_end = .;
+ __bss_start = .; /* BSS */
+ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
+ *(.bss.page_aligned)
+ *(.bss)
+ }
+ __bss_stop = .;
+
_end = . ;
/* Sections to be discarded */
diff --git a/arch/x86_64/kernel/vsmp.c b/arch/x86_64/kernel/vsmp.c
index 044e852bd25e..414caf0c5f9a 100644
--- a/arch/x86_64/kernel/vsmp.c
+++ b/arch/x86_64/kernel/vsmp.c
@@ -14,6 +14,7 @@
#include <linux/pci_ids.h>
#include <linux/pci_regs.h>
#include <asm/pci-direct.h>
+#include <asm/io.h>
static int __init vsmp_init(void)
{
diff --git a/arch/x86_64/kernel/vsyscall.c b/arch/x86_64/kernel/vsyscall.c
index ac48c3857ddb..a98b460af6a1 100644
--- a/arch/x86_64/kernel/vsyscall.c
+++ b/arch/x86_64/kernel/vsyscall.c
@@ -66,8 +66,7 @@ static __always_inline void do_vgettimeofday(struct timeval * tv)
sequence = read_seqbegin(&__xtime_lock);
sec = __xtime.tv_sec;
- usec = (__xtime.tv_nsec / 1000) +
- (__jiffies - __wall_jiffies) * (1000000 / HZ);
+ usec = __xtime.tv_nsec / 1000;
if (__vxtime.mode != VXTIME_HPET) {
t = get_cycles_sync();
@@ -155,8 +154,8 @@ vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
We do this here because otherwise user space would do it on
its own in a likely inferior way (no access to jiffies).
If you don't like it pass NULL. */
- if (tcache && tcache->t0 == (j = __jiffies)) {
- p = tcache->t1;
+ if (tcache && tcache->blob[0] == (j = __jiffies)) {
+ p = tcache->blob[1];
} else if (__vgetcpu_mode == VGETCPU_RDTSCP) {
/* Load per CPU data from RDTSCP */
rdtscp(dummy, dummy, p);
@@ -165,8 +164,8 @@ vgetcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache)
asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
}
if (tcache) {
- tcache->t0 = j;
- tcache->t1 = p;
+ tcache->blob[0] = j;
+ tcache->blob[1] = p;
}
if (cpu)
*cpu = p & 0xfff;
diff --git a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c
index c3454af5e3a2..6d77e4797a47 100644
--- a/arch/x86_64/kernel/x8664_ksyms.c
+++ b/arch/x86_64/kernel/x8664_ksyms.c
@@ -1,7 +1,6 @@
/* Exports for assembly files.
All C exports should go in the respective C files. */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/smp.h>
diff --git a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S
index 0ebb03b60e79..727a5d46d2fc 100644
--- a/arch/x86_64/lib/copy_page.S
+++ b/arch/x86_64/lib/copy_page.S
@@ -1,6 +1,5 @@
/* Written 2003 by Andi Kleen, based on a kernel by Evandro Menezes */
-
-#include <linux/config.h>
+
#include <linux/linkage.h>
#include <asm/dwarf2.h>
diff --git a/arch/x86_64/lib/delay.c b/arch/x86_64/lib/delay.c
index b6cd3cca2f45..50be90975d04 100644
--- a/arch/x86_64/lib/delay.c
+++ b/arch/x86_64/lib/delay.c
@@ -8,7 +8,6 @@
* depends wildly on alignment on many x86 processors.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/delay.h>
diff --git a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S
index 967b22fa7d07..0ea0ddc875a7 100644
--- a/arch/x86_64/lib/memcpy.S
+++ b/arch/x86_64/lib/memcpy.S
@@ -1,6 +1,5 @@
/* Copyright 2002 Andi Kleen */
-
-#include <linux/config.h>
+
#include <linux/linkage.h>
#include <asm/dwarf2.h>
#include <asm/cpufeature.h>
diff --git a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S
index 09ed1f6b0eaa..2c5948116bd2 100644
--- a/arch/x86_64/lib/memset.S
+++ b/arch/x86_64/lib/memset.S
@@ -1,6 +1,5 @@
/* Copyright 2002 Andi Kleen, SuSE Labs */
-#include <linux/config.h>
#include <linux/linkage.h>
#include <asm/dwarf2.h>
diff --git a/arch/x86_64/lib/thunk.S b/arch/x86_64/lib/thunk.S
index 0025535cac8d..55e586d352d3 100644
--- a/arch/x86_64/lib/thunk.S
+++ b/arch/x86_64/lib/thunk.S
@@ -5,7 +5,6 @@
* Subject to the GNU public license, v.2. No warranty of any kind.
*/
- #include <linux/config.h>
#include <linux/linkage.h>
#include <asm/dwarf2.h>
#include <asm/calling.h>
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 1a17b0733ab5..3751b4788e28 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -244,7 +244,7 @@ static int is_errata93(struct pt_regs *regs, unsigned long address)
int unhandled_signal(struct task_struct *tsk, int sig)
{
- if (tsk->pid == 1)
+ if (is_init(tsk))
return 1;
if (tsk->ptrace & PT_PTRACED)
return 0;
@@ -464,7 +464,7 @@ good_area:
case PF_PROT: /* read, present */
goto bad_area;
case 0: /* read, not present */
- if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+ if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)))
goto bad_area;
}
@@ -580,7 +580,7 @@ no_context:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
goto again;
}
diff --git a/arch/x86_64/mm/init.c b/arch/x86_64/mm/init.c
index 1e4669fa5734..971dc1181e69 100644
--- a/arch/x86_64/mm/init.c
+++ b/arch/x86_64/mm/init.c
@@ -403,69 +403,18 @@ void __cpuinit zap_low_mappings(int cpu)
__flush_tlb_all();
}
-/* Compute zone sizes for the DMA and DMA32 zones in a node. */
-__init void
-size_zones(unsigned long *z, unsigned long *h,
- unsigned long start_pfn, unsigned long end_pfn)
-{
- int i;
- unsigned long w;
-
- for (i = 0; i < MAX_NR_ZONES; i++)
- z[i] = 0;
-
- if (start_pfn < MAX_DMA_PFN)
- z[ZONE_DMA] = MAX_DMA_PFN - start_pfn;
- if (start_pfn < MAX_DMA32_PFN) {
- unsigned long dma32_pfn = MAX_DMA32_PFN;
- if (dma32_pfn > end_pfn)
- dma32_pfn = end_pfn;
- z[ZONE_DMA32] = dma32_pfn - start_pfn;
- }
- z[ZONE_NORMAL] = end_pfn - start_pfn;
-
- /* Remove lower zones from higher ones. */
- w = 0;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- if (z[i])
- z[i] -= w;
- w += z[i];
- }
-
- /* Compute holes */
- w = start_pfn;
- for (i = 0; i < MAX_NR_ZONES; i++) {
- unsigned long s = w;
- w += z[i];
- h[i] = e820_hole_size(s, w);
- }
-
- /* Add the space pace needed for mem_map to the holes too. */
- for (i = 0; i < MAX_NR_ZONES; i++)
- h[i] += (z[i] * sizeof(struct page)) / PAGE_SIZE;
-
- /* The 16MB DMA zone has the kernel and other misc mappings.
- Account them too */
- if (h[ZONE_DMA]) {
- h[ZONE_DMA] += dma_reserve;
- if (h[ZONE_DMA] >= z[ZONE_DMA]) {
- printk(KERN_WARNING
- "Kernel too large and filling up ZONE_DMA?\n");
- h[ZONE_DMA] = z[ZONE_DMA];
- }
- }
-}
-
#ifndef CONFIG_NUMA
void __init paging_init(void)
{
- unsigned long zones[MAX_NR_ZONES], holes[MAX_NR_ZONES];
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
+ max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
+ max_zone_pfns[ZONE_NORMAL] = end_pfn;
memory_present(0, 0, end_pfn);
sparse_init();
- size_zones(zones, holes, 0, end_pfn);
- free_area_init_node(0, NODE_DATA(0), zones,
- __pa(PAGE_OFFSET) >> PAGE_SHIFT, holes);
+ free_area_init_nodes(max_zone_pfns);
}
#endif
@@ -517,19 +466,6 @@ void online_page(struct page *page)
#ifdef CONFIG_MEMORY_HOTPLUG
/*
- * XXX: memory_add_physaddr_to_nid() is to find node id from physical address
- * via probe interface of sysfs. If acpi notifies hot-add event, then it
- * can tell node id by searching dsdt. But, probe interface doesn't have
- * node id. So, return 0 as node id at this time.
- */
-#ifdef CONFIG_NUMA
-int memory_add_physaddr_to_nid(u64 start)
-{
- return 0;
-}
-#endif
-
-/*
* Memory is added always to NORMAL zone. This means you will never get
* additional DMA/DMA32 memory.
*/
@@ -541,12 +477,12 @@ int arch_add_memory(int nid, u64 start, u64 size)
unsigned long nr_pages = size >> PAGE_SHIFT;
int ret;
+ init_memory_mapping(start, (start + size -1));
+
ret = __add_pages(zone, start_pfn, nr_pages);
if (ret)
goto error;
- init_memory_mapping(start, (start + size -1));
-
return ret;
error:
printk("%s: Problem encountered in __add_pages!\n", __func__);
@@ -560,7 +496,24 @@ int remove_memory(u64 start, u64 size)
}
EXPORT_SYMBOL_GPL(remove_memory);
-#else /* CONFIG_MEMORY_HOTPLUG */
+#ifndef CONFIG_ACPI_NUMA
+int memory_add_physaddr_to_nid(u64 start)
+{
+ return 0;
+}
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+#endif
+
+#ifndef CONFIG_ACPI_NUMA
+int memory_add_physaddr_to_nid(u64 start)
+{
+ return 0;
+}
+#endif
+
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
+#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
/*
* Memory Hotadd without sparsemem. The mem_maps have been allocated in advance,
* just online the pages.
@@ -586,7 +539,7 @@ int __add_pages(struct zone *z, unsigned long start_pfn, unsigned long nr_pages)
}
return err;
}
-#endif /* CONFIG_MEMORY_HOTPLUG */
+#endif
static struct kcore_list kcore_mem, kcore_vmalloc, kcore_kernel, kcore_modules,
kcore_vsyscall;
@@ -608,7 +561,8 @@ void __init mem_init(void)
#else
totalram_pages = free_all_bootmem();
#endif
- reservedpages = end_pfn - totalram_pages - e820_hole_size(0, end_pfn);
+ reservedpages = end_pfn - totalram_pages -
+ absent_pages_in_range(0, end_pfn);
after_bootmem = 1;
@@ -708,8 +662,10 @@ void __init reserve_bootmem_generic(unsigned long phys, unsigned len)
#else
reserve_bootmem(phys, len);
#endif
- if (phys+len <= MAX_DMA_PFN*PAGE_SIZE)
+ if (phys+len <= MAX_DMA_PFN*PAGE_SIZE) {
dma_reserve += len / PAGE_SIZE;
+ set_dma_reserve(dma_reserve);
+ }
}
int kern_addr_valid(unsigned long addr)
diff --git a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
index 45d7d823c3b8..c6e5e8d401a4 100644
--- a/arch/x86_64/mm/ioremap.c
+++ b/arch/x86_64/mm/ioremap.c
@@ -12,117 +12,16 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/pgalloc.h>
#include <asm/fixmap.h>
-#include <asm/cacheflush.h>
#include <asm/tlbflush.h>
+#include <asm/cacheflush.h>
#include <asm/proto.h>
#define ISA_START_ADDRESS 0xa0000
#define ISA_END_ADDRESS 0x100000
-static inline void remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
- unsigned long pfn;
-
- address &= ~PMD_MASK;
- end = address + size;
- if (end > PMD_SIZE)
- end = PMD_SIZE;
- if (address >= end)
- BUG();
- pfn = phys_addr >> PAGE_SHIFT;
- do {
- if (!pte_none(*pte)) {
- printk("remap_area_pte: page already exists\n");
- BUG();
- }
- set_pte(pte, pfn_pte(pfn, __pgprot(_PAGE_PRESENT | _PAGE_RW |
- _PAGE_GLOBAL | _PAGE_DIRTY | _PAGE_ACCESSED | flags)));
- address += PAGE_SIZE;
- pfn++;
- pte++;
- } while (address && (address < end));
-}
-
-static inline int remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PUD_MASK;
- end = address + size;
- if (end > PUD_SIZE)
- end = PUD_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pte_t * pte = pte_alloc_kernel(pmd, address);
- if (!pte)
- return -ENOMEM;
- remap_area_pte(pte, address, end - address, address + phys_addr, flags);
- address = (address + PMD_SIZE) & PMD_MASK;
- pmd++;
- } while (address && (address < end));
- return 0;
-}
-
-static inline int remap_area_pud(pud_t * pud, unsigned long address, unsigned long size,
- unsigned long phys_addr, unsigned long flags)
-{
- unsigned long end;
-
- address &= ~PGDIR_MASK;
- end = address + size;
- if (end > PGDIR_SIZE)
- end = PGDIR_SIZE;
- phys_addr -= address;
- if (address >= end)
- BUG();
- do {
- pmd_t * pmd = pmd_alloc(&init_mm, pud, address);
- if (!pmd)
- return -ENOMEM;
- remap_area_pmd(pmd, address, end - address, address + phys_addr, flags);
- address = (address + PUD_SIZE) & PUD_MASK;
- pud++;
- } while (address && (address < end));
- return 0;
-}
-
-static int remap_area_pages(unsigned long address, unsigned long phys_addr,
- unsigned long size, unsigned long flags)
-{
- int error;
- pgd_t *pgd;
- unsigned long end = address + size;
-
- phys_addr -= address;
- pgd = pgd_offset_k(address);
- flush_cache_all();
- if (address >= end)
- BUG();
- do {
- pud_t *pud;
- pud = pud_alloc(&init_mm, pgd, address);
- error = -ENOMEM;
- if (!pud)
- break;
- if (remap_area_pud(pud, address, end - address,
- phys_addr + address, flags))
- break;
- error = 0;
- address = (address + PGDIR_SIZE) & PGDIR_MASK;
- pgd++;
- } while (address && (address < end));
- flush_tlb_all();
- return error;
-}
-
/*
* Fix up the linear direct mapping of the kernel to avoid cache attribute
* conflicts.
@@ -165,6 +64,7 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
void * addr;
struct vm_struct * area;
unsigned long offset, last_addr;
+ pgprot_t pgprot;
/* Don't allow wraparound or zero size */
last_addr = phys_addr + size - 1;
@@ -194,6 +94,8 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
}
#endif
+ pgprot = __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_GLOBAL
+ | _PAGE_DIRTY | _PAGE_ACCESSED | flags);
/*
* Mappings have to be page-aligned
*/
@@ -209,7 +111,8 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l
return NULL;
area->phys_addr = phys_addr;
addr = area->addr;
- if (remap_area_pages((unsigned long) addr, phys_addr, size, flags)) {
+ if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size,
+ phys_addr, pgprot)) {
remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr));
return NULL;
}
diff --git a/arch/x86_64/mm/k8topology.c b/arch/x86_64/mm/k8topology.c
index 5cf594f9230d..b5b8dba28b4e 100644
--- a/arch/x86_64/mm/k8topology.c
+++ b/arch/x86_64/mm/k8topology.c
@@ -149,6 +149,9 @@ int __init k8_scan_nodes(unsigned long start, unsigned long end)
nodes[nodeid].start = base;
nodes[nodeid].end = limit;
+ e820_register_active_regions(nodeid,
+ nodes[nodeid].start >> PAGE_SHIFT,
+ nodes[nodeid].end >> PAGE_SHIFT);
prevbase = base;
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 322bf45fc36a..2ee2e003606c 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -161,7 +161,7 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
bootmap_start >> PAGE_SHIFT,
start_pfn, end_pfn);
- e820_bootmem_free(NODE_DATA(nodeid), start, end);
+ free_bootmem_with_active_regions(nodeid, end);
reserve_bootmem_node(NODE_DATA(nodeid), nodedata_phys, pgdat_size);
reserve_bootmem_node(NODE_DATA(nodeid), bootmap_start, bootmap_pages<<PAGE_SHIFT);
@@ -175,13 +175,11 @@ void __init setup_node_bootmem(int nodeid, unsigned long start, unsigned long en
void __init setup_node_zones(int nodeid)
{
unsigned long start_pfn, end_pfn, memmapsize, limit;
- unsigned long zones[MAX_NR_ZONES];
- unsigned long holes[MAX_NR_ZONES];
start_pfn = node_start_pfn(nodeid);
end_pfn = node_end_pfn(nodeid);
- Dprintk(KERN_INFO "Setting up node %d %lx-%lx\n",
+ Dprintk(KERN_INFO "Setting up memmap for node %d %lx-%lx\n",
nodeid, start_pfn, end_pfn);
/* Try to allocate mem_map at end to not fill up precious <4GB
@@ -195,10 +193,6 @@ void __init setup_node_zones(int nodeid)
round_down(limit - memmapsize, PAGE_SIZE),
limit);
#endif
-
- size_zones(zones, holes, start_pfn, end_pfn);
- free_area_init_node(nodeid, NODE_DATA(nodeid), zones,
- start_pfn, holes);
}
void __init numa_init_array(void)
@@ -259,8 +253,11 @@ static int __init numa_emulation(unsigned long start_pfn, unsigned long end_pfn)
printk(KERN_ERR "No NUMA hash function found. Emulation disabled.\n");
return -1;
}
- for_each_online_node(i)
+ for_each_online_node(i) {
+ e820_register_active_regions(i, nodes[i].start >> PAGE_SHIFT,
+ nodes[i].end >> PAGE_SHIFT);
setup_node_bootmem(i, nodes[i].start, nodes[i].end);
+ }
numa_init_array();
return 0;
}
@@ -299,6 +296,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
for (i = 0; i < NR_CPUS; i++)
numa_set_node(i, 0);
node_to_cpumask[0] = cpumask_of_cpu(0);
+ e820_register_active_regions(0, start_pfn, end_pfn);
setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
}
@@ -340,12 +338,19 @@ static void __init arch_sparse_init(void)
void __init paging_init(void)
{
int i;
+ unsigned long max_zone_pfns[MAX_NR_ZONES];
+ memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
+ max_zone_pfns[ZONE_DMA] = MAX_DMA_PFN;
+ max_zone_pfns[ZONE_DMA32] = MAX_DMA32_PFN;
+ max_zone_pfns[ZONE_NORMAL] = end_pfn;
arch_sparse_init();
for_each_online_node(i) {
setup_node_zones(i);
}
+
+ free_area_init_nodes(max_zone_pfns);
}
static __init int numa_setup(char *opt)
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index ca10701e7a90..1087e150a218 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -23,22 +23,13 @@
int acpi_numa __initdata;
-#if (defined(CONFIG_ACPI_HOTPLUG_MEMORY) || \
- defined(CONFIG_ACPI_HOTPLUG_MEMORY_MODULE)) \
- && !defined(CONFIG_MEMORY_HOTPLUG)
-#define RESERVE_HOTADD 1
-#endif
-
static struct acpi_table_slit *acpi_slit;
static nodemask_t nodes_parsed __initdata;
static struct bootnode nodes[MAX_NUMNODES] __initdata;
-static struct bootnode nodes_add[MAX_NUMNODES] __initdata;
+static struct bootnode nodes_add[MAX_NUMNODES];
static int found_add_area __initdata;
int hotadd_percent __initdata = 0;
-#ifndef RESERVE_HOTADD
-#define hotadd_percent 0 /* Ignore all settings */
-#endif
/* Too small nodes confuse the VM badly. Usually they result
from BIOS bugs. */
@@ -93,6 +84,7 @@ static __init void bad_srat(void)
apicid_to_node[i] = NUMA_NO_NODE;
for (i = 0; i < MAX_NUMNODES; i++)
nodes_add[i].start = nodes[i].end = 0;
+ remove_all_active_ranges();
}
static __init inline int srat_disabled(void)
@@ -159,7 +151,7 @@ acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
pxm, pa->apic_id, node);
}
-#ifdef RESERVE_HOTADD
+#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
/*
* Protect against too large hotadd areas that would fill up memory.
*/
@@ -175,7 +167,7 @@ static int hotadd_enough_memory(struct bootnode *nd)
if (mem < 0)
return 0;
- allowed = (end_pfn - e820_hole_size(0, end_pfn)) * PAGE_SIZE;
+ allowed = (end_pfn - absent_pages_in_range(0, end_pfn)) * PAGE_SIZE;
allowed = (allowed / 100) * hotadd_percent;
if (allocated + mem > allowed) {
unsigned long range;
@@ -202,15 +194,37 @@ static int hotadd_enough_memory(struct bootnode *nd)
return 1;
}
+static int update_end_of_memory(unsigned long end)
+{
+ found_add_area = 1;
+ if ((end >> PAGE_SHIFT) > end_pfn)
+ end_pfn = end >> PAGE_SHIFT;
+ return 1;
+}
+
+static inline int save_add_info(void)
+{
+ return hotadd_percent > 0;
+}
+#else
+int update_end_of_memory(unsigned long end) {return -1;}
+static int hotadd_enough_memory(struct bootnode *nd) {return 1;}
+#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
+static inline int save_add_info(void) {return 1;}
+#else
+static inline int save_add_info(void) {return 0;}
+#endif
+#endif
/*
- * It is fine to add this area to the nodes data it will be used later
+ * Update nodes_add and decide if to include add are in the zone.
+ * Both SPARSE and RESERVE need nodes_add infomation.
* This code supports one contigious hot add area per node.
*/
static int reserve_hotadd(int node, unsigned long start, unsigned long end)
{
unsigned long s_pfn = start >> PAGE_SHIFT;
unsigned long e_pfn = end >> PAGE_SHIFT;
- int changed = 0;
+ int ret = 0, changed = 0;
struct bootnode *nd = &nodes_add[node];
/* I had some trouble with strange memory hotadd regions breaking
@@ -225,8 +239,10 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
}
/* This check might be a bit too strict, but I'm keeping it for now. */
- if (e820_hole_size(s_pfn, e_pfn) != e_pfn - s_pfn) {
- printk(KERN_ERR "SRAT: Hotplug area has existing memory\n");
+ if (absent_pages_in_range(s_pfn, e_pfn) != e_pfn - s_pfn) {
+ printk(KERN_ERR
+ "SRAT: Hotplug area %lu -> %lu has existing memory\n",
+ s_pfn, e_pfn);
return -1;
}
@@ -237,7 +253,6 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
/* Looks good */
- found_add_area = 1;
if (nd->start == nd->end) {
nd->start = start;
nd->end = end;
@@ -255,14 +270,12 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
}
- if ((nd->end >> PAGE_SHIFT) > end_pfn)
- end_pfn = nd->end >> PAGE_SHIFT;
+ ret = update_end_of_memory(nd->end);
if (changed)
printk(KERN_INFO "SRAT: hot plug zone found %Lx - %Lx\n", nd->start, nd->end);
- return 0;
+ return ret;
}
-#endif
/* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
void __init
@@ -281,7 +294,7 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
}
if (ma->flags.enabled == 0)
return;
- if (ma->flags.hot_pluggable && hotadd_percent == 0)
+ if (ma->flags.hot_pluggable && !save_add_info())
return;
start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
@@ -319,16 +332,18 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
printk(KERN_INFO "SRAT: Node %u PXM %u %Lx-%Lx\n", node, pxm,
nd->start, nd->end);
+ e820_register_active_regions(node, nd->start >> PAGE_SHIFT,
+ nd->end >> PAGE_SHIFT);
+ push_node_boundaries(node, nd->start >> PAGE_SHIFT,
+ nd->end >> PAGE_SHIFT);
-#ifdef RESERVE_HOTADD
- if (ma->flags.hot_pluggable && reserve_hotadd(node, start, end) < 0) {
+ if (ma->flags.hot_pluggable && (reserve_hotadd(node, start, end) < 0)) {
/* Ignore hotadd region. Undo damage */
printk(KERN_NOTICE "SRAT: Hotplug region ignored\n");
*nd = oldnode;
if ((nd->start | nd->end) == 0)
node_clear(node, nodes_parsed);
}
-#endif
}
/* Sanity check to catch more bad SRATs (they are amazingly common).
@@ -343,13 +358,12 @@ static int nodes_cover_memory(void)
unsigned long s = nodes[i].start >> PAGE_SHIFT;
unsigned long e = nodes[i].end >> PAGE_SHIFT;
pxmram += e - s;
- pxmram -= e820_hole_size(s, e);
- pxmram -= nodes_add[i].end - nodes_add[i].start;
+ pxmram -= absent_pages_in_range(s, e);
if ((long)pxmram < 0)
pxmram = 0;
}
- e820ram = end_pfn - e820_hole_size(0, end_pfn);
+ e820ram = end_pfn - absent_pages_in_range(0, end_pfn);
/* We seem to lose 3 pages somewhere. Allow a bit of slack. */
if ((long)(e820ram - pxmram) >= 1*1024*1024) {
printk(KERN_ERR
@@ -452,3 +466,16 @@ int __node_distance(int a, int b)
}
EXPORT_SYMBOL(__node_distance);
+
+int memory_add_physaddr_to_nid(u64 start)
+{
+ int i, ret = 0;
+
+ for_each_node(i)
+ if (nodes_add[i].start <= start && nodes_add[i].end > start)
+ ret = i;
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid);
+
diff --git a/arch/x86_64/pci/Makefile b/arch/x86_64/pci/Makefile
index 1eb18f421edf..149aba05a5b8 100644
--- a/arch/x86_64/pci/Makefile
+++ b/arch/x86_64/pci/Makefile
@@ -3,7 +3,7 @@
#
# Reuse the i386 PCI subsystem
#
-CFLAGS += -Iarch/i386/pci
+EXTRA_CFLAGS += -Iarch/i386/pci
obj-y := i386.o
obj-$(CONFIG_PCI_DIRECT)+= direct.o
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
index 848f173db257..c1e69a1f92a4 100644
--- a/arch/xtensa/Kconfig
+++ b/arch/xtensa/Kconfig
@@ -206,7 +206,7 @@ source "drivers/pci/hotplug/Kconfig"
endmenu
-menu "Exectuable file formats"
+menu "Executable file formats"
# only elf supported
config KCORE_ELF
@@ -241,7 +241,7 @@ menu "Xtensa initrd options"
bool "Embed root filesystem ramdisk into the kernel"
config EMBEDDED_RAMDISK_IMAGE
- string "Filename of gziped ramdisk image"
+ string "Filename of gzipped ramdisk image"
depends on EMBEDDED_RAMDISK
default "ramdisk.gz"
help
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
index d1683cfa19a2..2ea1755a0858 100644
--- a/arch/xtensa/kernel/module.c
+++ b/arch/xtensa/kernel/module.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/kernel/platform.c
+ * arch/xtensa/kernel/module.c
*
* Module support.
*
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
index 1ff82268e8ea..6648fa9d9192 100644
--- a/arch/xtensa/kernel/pci-dma.c
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/pci-dma.c
+ * arch/xtensa/kernel/pci-dma.c
*
* DMA coherent memory allocation.
*
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
index 8709f8249d02..45571ccb72d6 100644
--- a/arch/xtensa/kernel/pci.c
+++ b/arch/xtensa/kernel/pci.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/pcibios.c
+ * arch/xtensa/kernel/pci.c
*
* PCI bios-type initialisation for PCI machines
*
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
index 82684d05910a..c99ab72b41b6 100644
--- a/arch/xtensa/kernel/setup.c
+++ b/arch/xtensa/kernel/setup.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/setup.c
+ * arch/xtensa/kernel/setup.c
*
* 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
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
index 4688ba2db84d..f49cb239e603 100644
--- a/arch/xtensa/kernel/syscalls.c
+++ b/arch/xtensa/kernel/syscalls.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/kernel/syscall.c
+ * arch/xtensa/kernel/syscalls.c
*
* 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
@@ -128,7 +128,7 @@ out:
int sys_uname(struct old_utsname * name)
{
- if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+ if (name && !copy_to_user(name, utsname(), sizeof (*name)))
return 0;
return -EFAULT;
}
@@ -266,3 +266,23 @@ void system_call (struct pt_regs *regs)
regs->areg[2] = res;
do_syscall_trace();
}
+
+/*
+ * Do a system call from kernel instead of calling sys_execve so we
+ * end up with proper pt_regs.
+ */
+int kernel_execve(const char *filename, char *const argv[], char *const envp[])
+{
+ long __res;
+ asm volatile (
+ " mov a5, %2 \n"
+ " mov a4, %4 \n"
+ " mov a3, %3 \n"
+ " movi a2, %1 \n"
+ " syscall \n"
+ " mov %0, a2 \n"
+ : "=a" (__res)
+ : "i" (__NR_execve), "a" (filename), "a" (argv), "a" (envp)
+ : "a2", "a3", "a4", "a5");
+ return __res;
+}
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
index 412ab32de391..37347e369987 100644
--- a/arch/xtensa/kernel/time.c
+++ b/arch/xtensa/kernel/time.c
@@ -26,8 +26,6 @@
#include <asm/platform.h>
-extern volatile unsigned long wall_jiffies;
-
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
@@ -110,7 +108,6 @@ int do_settimeofday(struct timespec *tv)
*/
ccount = get_ccount();
nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC;
- nsec -= (jiffies - wall_jiffies) * CCOUNT_PER_JIFFY * CCOUNT_NSEC;
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
@@ -129,7 +126,7 @@ EXPORT_SYMBOL(do_settimeofday);
void do_gettimeofday(struct timeval *tv)
{
unsigned long flags;
- unsigned long sec, usec, delta, lost, seq;
+ unsigned long sec, usec, delta, seq;
do {
seq = read_seqbegin_irqsave(&xtime_lock, flags);
@@ -137,12 +134,9 @@ void do_gettimeofday(struct timeval *tv)
delta = get_ccount() - last_ccount_stamp;
sec = xtime.tv_sec;
usec = (xtime.tv_nsec / NSEC_PER_USEC);
-
- lost = jiffies - wall_jiffies;
-
} while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
- usec += lost * (1000000UL/HZ) + (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
+ usec += (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
for (; usec >= 1000000; sec++, usec -= 1000000)
;
@@ -175,12 +169,11 @@ again:
last_ccount_stamp = next;
next += CCOUNT_PER_JIFFY;
- do_timer (regs); /* Linux handler in kernel/timer.c */
+ do_timer (1); /* Linux handler in kernel/timer.c */
if (ntp_synced() &&
xtime.tv_sec - last_rtc_update >= 659 &&
- abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ &&
- jiffies - wall_jiffies == 1) {
+ abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ) {
if (platform_set_rtc_time(xtime.tv_sec+1) == 0)
last_rtc_update = xtime.tv_sec+1;
diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c
index 90c790f6123b..a71733ae1193 100644
--- a/arch/xtensa/lib/pci-auto.c
+++ b/arch/xtensa/lib/pci-auto.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/kernel/pci-auto.c
+ * arch/xtensa/lib/pci-auto.c
*
* PCI autoconfiguration library
*
diff --git a/arch/xtensa/lib/usercopy.S b/arch/xtensa/lib/usercopy.S
index 265db2693cbd..4641ef510f0e 100644
--- a/arch/xtensa/lib/usercopy.S
+++ b/arch/xtensa/lib/usercopy.S
@@ -5,10 +5,10 @@
*
* DO NOT COMBINE this function with <arch/xtensa/lib/hal/memcopy.S>.
* It needs to remain separate and distinct. The hal files are part
- * of the the Xtensa link-time HAL, and those files may differ per
+ * of the Xtensa link-time HAL, and those files may differ per
* processor configuration. Patching the kernel for another
* processor configuration includes replacing the hal files, and we
- * could loose the special functionality for accessing user-space
+ * could lose the special functionality for accessing user-space
* memory during such a patch. We sacrifice a little code space here
* in favor to simplify code maintenance.
*
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
index a945a33e85a1..dd0dbec2e57e 100644
--- a/arch/xtensa/mm/fault.c
+++ b/arch/xtensa/mm/fault.c
@@ -144,7 +144,7 @@ bad_area:
*/
out_of_memory:
up_read(&mm->mmap_sem);
- if (current->pid == 1) {
+ if (is_init(current)) {
yield();
down_read(&mm->mmap_sem);
goto survive;
diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c
index 7d28914d11cb..697992738205 100644
--- a/arch/xtensa/mm/pgtable.c
+++ b/arch/xtensa/mm/pgtable.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/mm/fault.c
+ * arch/xtensa/mm/pgtable.c
*
* 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
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
index d3bd3bfc3b3b..0fefb8666874 100644
--- a/arch/xtensa/mm/tlb.c
+++ b/arch/xtensa/mm/tlb.c
@@ -1,5 +1,5 @@
/*
- * arch/xtensa/mm/mmu.c
+ * arch/xtensa/mm/tlb.c
*
* Logic that manipulates the Xtensa MMU. Derived from MIPS.
*
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
index 22d3c571a7bc..5c947cae7520 100644
--- a/arch/xtensa/platform-iss/console.c
+++ b/arch/xtensa/platform-iss/console.c
@@ -191,7 +191,7 @@ static int rs_read_proc(char *page, char **start, off_t off, int count,
}
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c
index d96164e602fe..15d64414bd60 100644
--- a/arch/xtensa/platform-iss/network.c
+++ b/arch/xtensa/platform-iss/network.c
@@ -201,7 +201,7 @@ static void dev_ip_addr(void *d, char *buf, char *bin_buf)
struct net_device *dev = d;
struct in_device *ip = dev->ip_ptr;
struct in_ifaddr *in;
- u32 addr;
+ __be32 addr;
if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) {
printk(KERN_WARNING "Device not assigned an IP address!\n");
diff --git a/block/Kconfig b/block/Kconfig
index b6f5f0a79655..83766a6bdee2 100644
--- a/block/Kconfig
+++ b/block/Kconfig
@@ -1,6 +1,24 @@
#
# Block layer core configuration
#
+config BLOCK
+ bool "Enable the block layer" if EMBEDDED
+ default y
+ help
+ This permits the block layer to be removed from the kernel if it's not
+ needed (on some embedded devices for example). If this option is
+ disabled, then blockdev files will become unusable and some
+ filesystems (such as ext3) will become unavailable.
+
+ This option will also disable SCSI character devices and USB storage
+ since they make use of various block layer definitions and
+ facilities.
+
+ Say Y here unless you know you really don't want to mount disks and
+ suchlike.
+
+if BLOCK
+
#XXX - it makes sense to enable this only for 32-bit subarch's, not for x86_64
#for instance.
config LBD
@@ -33,4 +51,6 @@ config LSF
If unsure, say Y.
+endif
+
source block/Kconfig.iosched
diff --git a/block/Kconfig.iosched b/block/Kconfig.iosched
index 48d090e266fc..903f0d3b6852 100644
--- a/block/Kconfig.iosched
+++ b/block/Kconfig.iosched
@@ -1,3 +1,4 @@
+if BLOCK
menu "IO Schedulers"
@@ -67,3 +68,5 @@ config DEFAULT_IOSCHED
default "noop" if DEFAULT_NOOP
endmenu
+
+endif
diff --git a/block/Makefile b/block/Makefile
index c05de0e0037f..4b84d0d5947b 100644
--- a/block/Makefile
+++ b/block/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel block layer
#
-obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o
+obj-$(CONFIG_BLOCK) := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o
obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o
obj-$(CONFIG_IOSCHED_AS) += as-iosched.o
diff --git a/block/as-iosched.c b/block/as-iosched.c
index 5da56d48fbd3..50b95e4c1425 100644
--- a/block/as-iosched.c
+++ b/block/as-iosched.c
@@ -1,7 +1,7 @@
/*
* Anticipatory & deadline i/o scheduler.
*
- * Copyright (C) 2002 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2002 Jens Axboe <axboe@kernel.dk>
* Nick Piggin <nickpiggin@yahoo.com.au>
*
*/
@@ -14,7 +14,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/compiler.h>
-#include <linux/hash.h>
#include <linux/rbtree.h>
#include <linux/interrupt.h>
@@ -93,9 +92,8 @@ struct as_data {
struct rb_root sort_list[2];
struct list_head fifo_list[2];
- struct as_rq *next_arq[2]; /* next in sort order */
+ struct request *next_rq[2]; /* next in sort order */
sector_t last_sector[2]; /* last REQ_SYNC & REQ_ASYNC sectors */
- struct hlist_head *hash; /* request hash */
unsigned long exit_prob; /* probability a task will exit while
being waited on */
@@ -115,7 +113,6 @@ struct as_data {
int write_batch_count; /* max # of reqs in a write batch */
int current_write_count; /* how many requests left this batch */
int write_batch_idled; /* has the write batch gone idle? */
- mempool_t *arq_pool;
enum anticipation_status antic_status;
unsigned long antic_start; /* jiffies: when it started */
@@ -133,8 +130,6 @@ struct as_data {
unsigned long antic_expire;
};
-#define list_entry_fifo(ptr) list_entry((ptr), struct as_rq, fifo)
-
/*
* per-request data.
*/
@@ -150,40 +145,14 @@ enum arq_state {
AS_RQ_POSTSCHED, /* when they shouldn't be */
};
-struct as_rq {
- /*
- * rbtree index, key is the starting offset
- */
- struct rb_node rb_node;
- sector_t rb_key;
-
- struct request *request;
-
- struct io_context *io_context; /* The submitting task */
-
- /*
- * request hash, key is the ending offset (for back merge lookup)
- */
- struct hlist_node hash;
-
- /*
- * expire fifo
- */
- struct list_head fifo;
- unsigned long expires;
+#define RQ_IOC(rq) ((struct io_context *) (rq)->elevator_private)
+#define RQ_STATE(rq) ((enum arq_state)(rq)->elevator_private2)
+#define RQ_SET_STATE(rq, state) ((rq)->elevator_private2 = (void *) state)
- unsigned int is_sync;
- enum arq_state state;
-};
-
-#define RQ_DATA(rq) ((struct as_rq *) (rq)->elevator_private)
-
-static kmem_cache_t *arq_pool;
-
-static atomic_t ioc_count = ATOMIC_INIT(0);
+static DEFINE_PER_CPU(unsigned long, ioc_count);
static struct completion *ioc_gone;
-static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq);
+static void as_move_to_dispatch(struct as_data *ad, struct request *rq);
static void as_antic_stop(struct as_data *ad);
/*
@@ -194,7 +163,8 @@ static void as_antic_stop(struct as_data *ad);
static void free_as_io_context(struct as_io_context *aic)
{
kfree(aic);
- if (atomic_dec_and_test(&ioc_count) && ioc_gone)
+ elv_ioc_count_dec(ioc_count);
+ if (ioc_gone && !elv_ioc_count_read(ioc_count))
complete(ioc_gone);
}
@@ -230,7 +200,7 @@ static struct as_io_context *alloc_as_io_context(void)
ret->seek_total = 0;
ret->seek_samples = 0;
ret->seek_mean = 0;
- atomic_inc(&ioc_count);
+ elv_ioc_count_inc(ioc_count);
}
return ret;
@@ -240,9 +210,9 @@ static struct as_io_context *alloc_as_io_context(void)
* If the current task has no AS IO context then create one and initialise it.
* Then take a ref on the task's io context and return it.
*/
-static struct io_context *as_get_io_context(void)
+static struct io_context *as_get_io_context(int node)
{
- struct io_context *ioc = get_io_context(GFP_ATOMIC);
+ struct io_context *ioc = get_io_context(GFP_ATOMIC, node);
if (ioc && !ioc->aic) {
ioc->aic = alloc_as_io_context();
if (!ioc->aic) {
@@ -253,194 +223,43 @@ static struct io_context *as_get_io_context(void)
return ioc;
}
-static void as_put_io_context(struct as_rq *arq)
+static void as_put_io_context(struct request *rq)
{
struct as_io_context *aic;
- if (unlikely(!arq->io_context))
+ if (unlikely(!RQ_IOC(rq)))
return;
- aic = arq->io_context->aic;
+ aic = RQ_IOC(rq)->aic;
- if (arq->is_sync == REQ_SYNC && aic) {
+ if (rq_is_sync(rq) && aic) {
spin_lock(&aic->lock);
set_bit(AS_TASK_IORUNNING, &aic->state);
aic->last_end_request = jiffies;
spin_unlock(&aic->lock);
}
- put_io_context(arq->io_context);
-}
-
-/*
- * the back merge hash support functions
- */
-static const int as_hash_shift = 6;
-#define AS_HASH_BLOCK(sec) ((sec) >> 3)
-#define AS_HASH_FN(sec) (hash_long(AS_HASH_BLOCK((sec)), as_hash_shift))
-#define AS_HASH_ENTRIES (1 << as_hash_shift)
-#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
-
-static inline void __as_del_arq_hash(struct as_rq *arq)
-{
- hlist_del_init(&arq->hash);
-}
-
-static inline void as_del_arq_hash(struct as_rq *arq)
-{
- if (!hlist_unhashed(&arq->hash))
- __as_del_arq_hash(arq);
-}
-
-static void as_add_arq_hash(struct as_data *ad, struct as_rq *arq)
-{
- struct request *rq = arq->request;
-
- BUG_ON(!hlist_unhashed(&arq->hash));
-
- hlist_add_head(&arq->hash, &ad->hash[AS_HASH_FN(rq_hash_key(rq))]);
-}
-
-/*
- * move hot entry to front of chain
- */
-static inline void as_hot_arq_hash(struct as_data *ad, struct as_rq *arq)
-{
- struct request *rq = arq->request;
- struct hlist_head *head = &ad->hash[AS_HASH_FN(rq_hash_key(rq))];
-
- if (hlist_unhashed(&arq->hash)) {
- WARN_ON(1);
- return;
- }
-
- if (&arq->hash != head->first) {
- hlist_del(&arq->hash);
- hlist_add_head(&arq->hash, head);
- }
-}
-
-static struct request *as_find_arq_hash(struct as_data *ad, sector_t offset)
-{
- struct hlist_head *hash_list = &ad->hash[AS_HASH_FN(offset)];
- struct hlist_node *entry, *next;
- struct as_rq *arq;
-
- hlist_for_each_entry_safe(arq, entry, next, hash_list, hash) {
- struct request *__rq = arq->request;
-
- BUG_ON(hlist_unhashed(&arq->hash));
-
- if (!rq_mergeable(__rq)) {
- as_del_arq_hash(arq);
- continue;
- }
-
- if (rq_hash_key(__rq) == offset)
- return __rq;
- }
-
- return NULL;
+ put_io_context(RQ_IOC(rq));
}
/*
* rb tree support functions
*/
-#define rb_entry_arq(node) rb_entry((node), struct as_rq, rb_node)
-#define ARQ_RB_ROOT(ad, arq) (&(ad)->sort_list[(arq)->is_sync])
-#define rq_rb_key(rq) (rq)->sector
-
-/*
- * as_find_first_arq finds the first (lowest sector numbered) request
- * for the specified data_dir. Used to sweep back to the start of the disk
- * (1-way elevator) after we process the last (highest sector) request.
- */
-static struct as_rq *as_find_first_arq(struct as_data *ad, int data_dir)
-{
- struct rb_node *n = ad->sort_list[data_dir].rb_node;
-
- if (n == NULL)
- return NULL;
-
- for (;;) {
- if (n->rb_left == NULL)
- return rb_entry_arq(n);
-
- n = n->rb_left;
- }
-}
-
-/*
- * Add the request to the rb tree if it is unique. If there is an alias (an
- * existing request against the same sector), which can happen when using
- * direct IO, then return the alias.
- */
-static struct as_rq *__as_add_arq_rb(struct as_data *ad, struct as_rq *arq)
-{
- struct rb_node **p = &ARQ_RB_ROOT(ad, arq)->rb_node;
- struct rb_node *parent = NULL;
- struct as_rq *__arq;
- struct request *rq = arq->request;
-
- arq->rb_key = rq_rb_key(rq);
-
- while (*p) {
- parent = *p;
- __arq = rb_entry_arq(parent);
-
- if (arq->rb_key < __arq->rb_key)
- p = &(*p)->rb_left;
- else if (arq->rb_key > __arq->rb_key)
- p = &(*p)->rb_right;
- else
- return __arq;
- }
-
- rb_link_node(&arq->rb_node, parent, p);
- rb_insert_color(&arq->rb_node, ARQ_RB_ROOT(ad, arq));
-
- return NULL;
-}
+#define RQ_RB_ROOT(ad, rq) (&(ad)->sort_list[rq_is_sync((rq))])
-static void as_add_arq_rb(struct as_data *ad, struct as_rq *arq)
+static void as_add_rq_rb(struct as_data *ad, struct request *rq)
{
- struct as_rq *alias;
+ struct request *alias;
- while ((unlikely(alias = __as_add_arq_rb(ad, arq)))) {
+ while ((unlikely(alias = elv_rb_add(RQ_RB_ROOT(ad, rq), rq)))) {
as_move_to_dispatch(ad, alias);
as_antic_stop(ad);
}
}
-static inline void as_del_arq_rb(struct as_data *ad, struct as_rq *arq)
-{
- if (!RB_EMPTY_NODE(&arq->rb_node)) {
- WARN_ON(1);
- return;
- }
-
- rb_erase(&arq->rb_node, ARQ_RB_ROOT(ad, arq));
- RB_CLEAR_NODE(&arq->rb_node);
-}
-
-static struct request *
-as_find_arq_rb(struct as_data *ad, sector_t sector, int data_dir)
+static inline void as_del_rq_rb(struct as_data *ad, struct request *rq)
{
- struct rb_node *n = ad->sort_list[data_dir].rb_node;
- struct as_rq *arq;
-
- while (n) {
- arq = rb_entry_arq(n);
-
- if (sector < arq->rb_key)
- n = n->rb_left;
- else if (sector > arq->rb_key)
- n = n->rb_right;
- else
- return arq->request;
- }
-
- return NULL;
+ elv_rb_del(RQ_RB_ROOT(ad, rq), rq);
}
/*
@@ -458,26 +277,26 @@ as_find_arq_rb(struct as_data *ad, sector_t sector, int data_dir)
* as_choose_req selects the preferred one of two requests of the same data_dir
* ignoring time - eg. timeouts, which is the job of as_dispatch_request
*/
-static struct as_rq *
-as_choose_req(struct as_data *ad, struct as_rq *arq1, struct as_rq *arq2)
+static struct request *
+as_choose_req(struct as_data *ad, struct request *rq1, struct request *rq2)
{
int data_dir;
sector_t last, s1, s2, d1, d2;
int r1_wrap=0, r2_wrap=0; /* requests are behind the disk head */
const sector_t maxback = MAXBACK;
- if (arq1 == NULL || arq1 == arq2)
- return arq2;
- if (arq2 == NULL)
- return arq1;
+ if (rq1 == NULL || rq1 == rq2)
+ return rq2;
+ if (rq2 == NULL)
+ return rq1;
- data_dir = arq1->is_sync;
+ data_dir = rq_is_sync(rq1);
last = ad->last_sector[data_dir];
- s1 = arq1->request->sector;
- s2 = arq2->request->sector;
+ s1 = rq1->sector;
+ s2 = rq2->sector;
- BUG_ON(data_dir != arq2->is_sync);
+ BUG_ON(data_dir != rq_is_sync(rq2));
/*
* Strict one way elevator _except_ in the case where we allow
@@ -504,61 +323,58 @@ as_choose_req(struct as_data *ad, struct as_rq *arq1, struct as_rq *arq2)
/* Found required data */
if (!r1_wrap && r2_wrap)
- return arq1;
+ return rq1;
else if (!r2_wrap && r1_wrap)
- return arq2;
+ return rq2;
else if (r1_wrap && r2_wrap) {
/* both behind the head */
if (s1 <= s2)
- return arq1;
+ return rq1;
else
- return arq2;
+ return rq2;
}
/* Both requests in front of the head */
if (d1 < d2)
- return arq1;
+ return rq1;
else if (d2 < d1)
- return arq2;
+ return rq2;
else {
if (s1 >= s2)
- return arq1;
+ return rq1;
else
- return arq2;
+ return rq2;
}
}
/*
- * as_find_next_arq finds the next request after @prev in elevator order.
+ * as_find_next_rq finds the next request after @prev in elevator order.
* this with as_choose_req form the basis for how the scheduler chooses
* what request to process next. Anticipation works on top of this.
*/
-static struct as_rq *as_find_next_arq(struct as_data *ad, struct as_rq *last)
+static struct request *
+as_find_next_rq(struct as_data *ad, struct request *last)
{
- const int data_dir = last->is_sync;
- struct as_rq *ret;
struct rb_node *rbnext = rb_next(&last->rb_node);
struct rb_node *rbprev = rb_prev(&last->rb_node);
- struct as_rq *arq_next, *arq_prev;
+ struct request *next = NULL, *prev = NULL;
- BUG_ON(!RB_EMPTY_NODE(&last->rb_node));
+ BUG_ON(RB_EMPTY_NODE(&last->rb_node));
if (rbprev)
- arq_prev = rb_entry_arq(rbprev);
- else
- arq_prev = NULL;
+ prev = rb_entry_rq(rbprev);
if (rbnext)
- arq_next = rb_entry_arq(rbnext);
+ next = rb_entry_rq(rbnext);
else {
- arq_next = as_find_first_arq(ad, data_dir);
- if (arq_next == last)
- arq_next = NULL;
- }
+ const int data_dir = rq_is_sync(last);
- ret = as_choose_req(ad, arq_next, arq_prev);
+ rbnext = rb_first(&ad->sort_list[data_dir]);
+ if (rbnext && rbnext != &last->rb_node)
+ next = rb_entry_rq(rbnext);
+ }
- return ret;
+ return as_choose_req(ad, next, prev);
}
/*
@@ -712,8 +528,7 @@ static void as_update_seekdist(struct as_data *ad, struct as_io_context *aic,
static void as_update_iohist(struct as_data *ad, struct as_io_context *aic,
struct request *rq)
{
- struct as_rq *arq = RQ_DATA(rq);
- int data_dir = arq->is_sync;
+ int data_dir = rq_is_sync(rq);
unsigned long thinktime = 0;
sector_t seek_dist;
@@ -752,11 +567,11 @@ static void as_update_iohist(struct as_data *ad, struct as_io_context *aic,
* previous one issued.
*/
static int as_close_req(struct as_data *ad, struct as_io_context *aic,
- struct as_rq *arq)
+ struct request *rq)
{
unsigned long delay; /* milliseconds */
sector_t last = ad->last_sector[ad->batch_data_dir];
- sector_t next = arq->request->sector;
+ sector_t next = rq->sector;
sector_t delta; /* acceptable close offset (in sectors) */
sector_t s;
@@ -813,7 +628,7 @@ static int as_close_req(struct as_data *ad, struct as_io_context *aic,
*
* If this task has queued some other IO, do not enter enticipation.
*/
-static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq)
+static int as_can_break_anticipation(struct as_data *ad, struct request *rq)
{
struct io_context *ioc;
struct as_io_context *aic;
@@ -821,7 +636,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq)
ioc = ad->io_context;
BUG_ON(!ioc);
- if (arq && ioc == arq->io_context) {
+ if (rq && ioc == RQ_IOC(rq)) {
/* request from same process */
return 1;
}
@@ -848,7 +663,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq)
return 1;
}
- if (arq && arq->is_sync == REQ_SYNC && as_close_req(ad, aic, arq)) {
+ if (rq && rq_is_sync(rq) && as_close_req(ad, aic, rq)) {
/*
* Found a close request that is not one of ours.
*
@@ -864,7 +679,7 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq)
ad->exit_no_coop = (7*ad->exit_no_coop)/8;
}
- as_update_iohist(ad, aic, arq->request);
+ as_update_iohist(ad, aic, rq);
return 1;
}
@@ -891,10 +706,10 @@ static int as_can_break_anticipation(struct as_data *ad, struct as_rq *arq)
}
/*
- * as_can_anticipate indicates whether we should either run arq
+ * as_can_anticipate indicates whether we should either run rq
* or keep anticipating a better request.
*/
-static int as_can_anticipate(struct as_data *ad, struct as_rq *arq)
+static int as_can_anticipate(struct as_data *ad, struct request *rq)
{
if (!ad->io_context)
/*
@@ -908,7 +723,7 @@ static int as_can_anticipate(struct as_data *ad, struct as_rq *arq)
*/
return 0;
- if (as_can_break_anticipation(ad, arq))
+ if (as_can_break_anticipation(ad, rq))
/*
* This request is a good candidate. Don't keep anticipating,
* run it.
@@ -926,16 +741,16 @@ static int as_can_anticipate(struct as_data *ad, struct as_rq *arq)
}
/*
- * as_update_arq must be called whenever a request (arq) is added to
+ * as_update_rq must be called whenever a request (rq) is added to
* the sort_list. This function keeps caches up to date, and checks if the
* request might be one we are "anticipating"
*/
-static void as_update_arq(struct as_data *ad, struct as_rq *arq)
+static void as_update_rq(struct as_data *ad, struct request *rq)
{
- const int data_dir = arq->is_sync;
+ const int data_dir = rq_is_sync(rq);
- /* keep the next_arq cache up to date */
- ad->next_arq[data_dir] = as_choose_req(ad, arq, ad->next_arq[data_dir]);
+ /* keep the next_rq cache up to date */
+ ad->next_rq[data_dir] = as_choose_req(ad, rq, ad->next_rq[data_dir]);
/*
* have we been anticipating this request?
@@ -944,7 +759,7 @@ static void as_update_arq(struct as_data *ad, struct as_rq *arq)
*/
if (ad->antic_status == ANTIC_WAIT_REQ
|| ad->antic_status == ANTIC_WAIT_NEXT) {
- if (as_can_break_anticipation(ad, arq))
+ if (as_can_break_anticipation(ad, rq))
as_antic_stop(ad);
}
}
@@ -984,12 +799,11 @@ static void update_write_batch(struct as_data *ad)
static void as_completed_request(request_queue_t *q, struct request *rq)
{
struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq = RQ_DATA(rq);
WARN_ON(!list_empty(&rq->queuelist));
- if (arq->state != AS_RQ_REMOVED) {
- printk("arq->state %d\n", arq->state);
+ if (RQ_STATE(rq) != AS_RQ_REMOVED) {
+ printk("rq->state %d\n", RQ_STATE(rq));
WARN_ON(1);
goto out;
}
@@ -1009,14 +823,14 @@ static void as_completed_request(request_queue_t *q, struct request *rq)
* actually serviced. This should help devices with big TCQ windows
* and writeback caches
*/
- if (ad->new_batch && ad->batch_data_dir == arq->is_sync) {
+ if (ad->new_batch && ad->batch_data_dir == rq_is_sync(rq)) {
update_write_batch(ad);
ad->current_batch_expires = jiffies +
ad->batch_expire[REQ_SYNC];
ad->new_batch = 0;
}
- if (ad->io_context == arq->io_context && ad->io_context) {
+ if (ad->io_context == RQ_IOC(rq) && ad->io_context) {
ad->antic_start = jiffies;
ad->ioc_finished = 1;
if (ad->antic_status == ANTIC_WAIT_REQ) {
@@ -1028,9 +842,9 @@ static void as_completed_request(request_queue_t *q, struct request *rq)
}
}
- as_put_io_context(arq);
+ as_put_io_context(rq);
out:
- arq->state = AS_RQ_POSTSCHED;
+ RQ_SET_STATE(rq, AS_RQ_POSTSCHED);
}
/*
@@ -1041,27 +855,27 @@ out:
*/
static void as_remove_queued_request(request_queue_t *q, struct request *rq)
{
- struct as_rq *arq = RQ_DATA(rq);
- const int data_dir = arq->is_sync;
+ const int data_dir = rq_is_sync(rq);
struct as_data *ad = q->elevator->elevator_data;
+ struct io_context *ioc;
- WARN_ON(arq->state != AS_RQ_QUEUED);
+ WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
- if (arq->io_context && arq->io_context->aic) {
- BUG_ON(!atomic_read(&arq->io_context->aic->nr_queued));
- atomic_dec(&arq->io_context->aic->nr_queued);
+ ioc = RQ_IOC(rq);
+ if (ioc && ioc->aic) {
+ BUG_ON(!atomic_read(&ioc->aic->nr_queued));
+ atomic_dec(&ioc->aic->nr_queued);
}
/*
- * Update the "next_arq" cache if we are about to remove its
+ * Update the "next_rq" cache if we are about to remove its
* entry
*/
- if (ad->next_arq[data_dir] == arq)
- ad->next_arq[data_dir] = as_find_next_arq(ad, arq);
+ if (ad->next_rq[data_dir] == rq)
+ ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
- list_del_init(&arq->fifo);
- as_del_arq_hash(arq);
- as_del_arq_rb(ad, arq);
+ rq_fifo_clear(rq);
+ as_del_rq_rb(ad, rq);
}
/*
@@ -1074,7 +888,7 @@ static void as_remove_queued_request(request_queue_t *q, struct request *rq)
*/
static int as_fifo_expired(struct as_data *ad, int adir)
{
- struct as_rq *arq;
+ struct request *rq;
long delta_jif;
delta_jif = jiffies - ad->last_check_fifo[adir];
@@ -1088,9 +902,9 @@ static int as_fifo_expired(struct as_data *ad, int adir)
if (list_empty(&ad->fifo_list[adir]))
return 0;
- arq = list_entry_fifo(ad->fifo_list[adir].next);
+ rq = rq_entry_fifo(ad->fifo_list[adir].next);
- return time_after(jiffies, arq->expires);
+ return time_after(jiffies, rq_fifo_time(rq));
}
/*
@@ -1113,25 +927,25 @@ static inline int as_batch_expired(struct as_data *ad)
/*
* move an entry to dispatch queue
*/
-static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
+static void as_move_to_dispatch(struct as_data *ad, struct request *rq)
{
- struct request *rq = arq->request;
- const int data_dir = arq->is_sync;
+ const int data_dir = rq_is_sync(rq);
- BUG_ON(!RB_EMPTY_NODE(&arq->rb_node));
+ BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
as_antic_stop(ad);
ad->antic_status = ANTIC_OFF;
/*
* This has to be set in order to be correctly updated by
- * as_find_next_arq
+ * as_find_next_rq
*/
ad->last_sector[data_dir] = rq->sector + rq->nr_sectors;
if (data_dir == REQ_SYNC) {
+ struct io_context *ioc = RQ_IOC(rq);
/* In case we have to anticipate after this */
- copy_io_context(&ad->io_context, &arq->io_context);
+ copy_io_context(&ad->io_context, &ioc);
} else {
if (ad->io_context) {
put_io_context(ad->io_context);
@@ -1143,19 +957,19 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
}
ad->ioc_finished = 0;
- ad->next_arq[data_dir] = as_find_next_arq(ad, arq);
+ ad->next_rq[data_dir] = as_find_next_rq(ad, rq);
/*
* take it off the sort and fifo list, add to dispatch queue
*/
as_remove_queued_request(ad->q, rq);
- WARN_ON(arq->state != AS_RQ_QUEUED);
+ WARN_ON(RQ_STATE(rq) != AS_RQ_QUEUED);
elv_dispatch_sort(ad->q, rq);
- arq->state = AS_RQ_DISPATCHED;
- if (arq->io_context && arq->io_context->aic)
- atomic_inc(&arq->io_context->aic->nr_dispatched);
+ RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
+ if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
+ atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
ad->nr_dispatched++;
}
@@ -1167,9 +981,9 @@ static void as_move_to_dispatch(struct as_data *ad, struct as_rq *arq)
static int as_dispatch_request(request_queue_t *q, int force)
{
struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq;
const int reads = !list_empty(&ad->fifo_list[REQ_SYNC]);
const int writes = !list_empty(&ad->fifo_list[REQ_ASYNC]);
+ struct request *rq;
if (unlikely(force)) {
/*
@@ -1185,14 +999,14 @@ static int as_dispatch_request(request_queue_t *q, int force)
ad->changed_batch = 0;
ad->new_batch = 0;
- while (ad->next_arq[REQ_SYNC]) {
- as_move_to_dispatch(ad, ad->next_arq[REQ_SYNC]);
+ while (ad->next_rq[REQ_SYNC]) {
+ as_move_to_dispatch(ad, ad->next_rq[REQ_SYNC]);
dispatched++;
}
ad->last_check_fifo[REQ_SYNC] = jiffies;
- while (ad->next_arq[REQ_ASYNC]) {
- as_move_to_dispatch(ad, ad->next_arq[REQ_ASYNC]);
+ while (ad->next_rq[REQ_ASYNC]) {
+ as_move_to_dispatch(ad, ad->next_rq[REQ_ASYNC]);
dispatched++;
}
ad->last_check_fifo[REQ_ASYNC] = jiffies;
@@ -1216,19 +1030,19 @@ static int as_dispatch_request(request_queue_t *q, int force)
/*
* batch is still running or no reads or no writes
*/
- arq = ad->next_arq[ad->batch_data_dir];
+ rq = ad->next_rq[ad->batch_data_dir];
if (ad->batch_data_dir == REQ_SYNC && ad->antic_expire) {
if (as_fifo_expired(ad, REQ_SYNC))
goto fifo_expired;
- if (as_can_anticipate(ad, arq)) {
+ if (as_can_anticipate(ad, rq)) {
as_antic_waitreq(ad);
return 0;
}
}
- if (arq) {
+ if (rq) {
/* we have a "next request" */
if (reads && !writes)
ad->current_batch_expires =
@@ -1256,7 +1070,7 @@ static int as_dispatch_request(request_queue_t *q, int force)
ad->changed_batch = 1;
}
ad->batch_data_dir = REQ_SYNC;
- arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
+ rq = rq_entry_fifo(ad->fifo_list[REQ_SYNC].next);
ad->last_check_fifo[ad->batch_data_dir] = jiffies;
goto dispatch_request;
}
@@ -1282,7 +1096,7 @@ dispatch_writes:
ad->batch_data_dir = REQ_ASYNC;
ad->current_write_count = ad->write_batch_count;
ad->write_batch_idled = 0;
- arq = ad->next_arq[ad->batch_data_dir];
+ rq = ad->next_rq[ad->batch_data_dir];
goto dispatch_request;
}
@@ -1296,8 +1110,7 @@ dispatch_request:
if (as_fifo_expired(ad, ad->batch_data_dir)) {
fifo_expired:
- arq = list_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
- BUG_ON(arq == NULL);
+ rq = rq_entry_fifo(ad->fifo_list[ad->batch_data_dir].next);
}
if (ad->changed_batch) {
@@ -1316,70 +1129,58 @@ fifo_expired:
}
/*
- * arq is the selected appropriate request.
+ * rq is the selected appropriate request.
*/
- as_move_to_dispatch(ad, arq);
+ as_move_to_dispatch(ad, rq);
return 1;
}
/*
- * add arq to rbtree and fifo
+ * add rq to rbtree and fifo
*/
static void as_add_request(request_queue_t *q, struct request *rq)
{
struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq = RQ_DATA(rq);
int data_dir;
- arq->state = AS_RQ_NEW;
+ RQ_SET_STATE(rq, AS_RQ_NEW);
- if (rq_data_dir(arq->request) == READ
- || (arq->request->flags & REQ_RW_SYNC))
- arq->is_sync = 1;
- else
- arq->is_sync = 0;
- data_dir = arq->is_sync;
+ data_dir = rq_is_sync(rq);
- arq->io_context = as_get_io_context();
+ rq->elevator_private = as_get_io_context(q->node);
- if (arq->io_context) {
- as_update_iohist(ad, arq->io_context->aic, arq->request);
- atomic_inc(&arq->io_context->aic->nr_queued);
+ if (RQ_IOC(rq)) {
+ as_update_iohist(ad, RQ_IOC(rq)->aic, rq);
+ atomic_inc(&RQ_IOC(rq)->aic->nr_queued);
}
- as_add_arq_rb(ad, arq);
- if (rq_mergeable(arq->request))
- as_add_arq_hash(ad, arq);
+ as_add_rq_rb(ad, rq);
/*
* set expire time (only used for reads) and add to fifo list
*/
- arq->expires = jiffies + ad->fifo_expire[data_dir];
- list_add_tail(&arq->fifo, &ad->fifo_list[data_dir]);
+ rq_set_fifo_time(rq, jiffies + ad->fifo_expire[data_dir]);
+ list_add_tail(&rq->queuelist, &ad->fifo_list[data_dir]);
- as_update_arq(ad, arq); /* keep state machine up to date */
- arq->state = AS_RQ_QUEUED;
+ as_update_rq(ad, rq); /* keep state machine up to date */
+ RQ_SET_STATE(rq, AS_RQ_QUEUED);
}
static void as_activate_request(request_queue_t *q, struct request *rq)
{
- struct as_rq *arq = RQ_DATA(rq);
-
- WARN_ON(arq->state != AS_RQ_DISPATCHED);
- arq->state = AS_RQ_REMOVED;
- if (arq->io_context && arq->io_context->aic)
- atomic_dec(&arq->io_context->aic->nr_dispatched);
+ WARN_ON(RQ_STATE(rq) != AS_RQ_DISPATCHED);
+ RQ_SET_STATE(rq, AS_RQ_REMOVED);
+ if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
+ atomic_dec(&RQ_IOC(rq)->aic->nr_dispatched);
}
static void as_deactivate_request(request_queue_t *q, struct request *rq)
{
- struct as_rq *arq = RQ_DATA(rq);
-
- WARN_ON(arq->state != AS_RQ_REMOVED);
- arq->state = AS_RQ_DISPATCHED;
- if (arq->io_context && arq->io_context->aic)
- atomic_inc(&arq->io_context->aic->nr_dispatched);
+ WARN_ON(RQ_STATE(rq) != AS_RQ_REMOVED);
+ RQ_SET_STATE(rq, AS_RQ_DISPATCHED);
+ if (RQ_IOC(rq) && RQ_IOC(rq)->aic)
+ atomic_inc(&RQ_IOC(rq)->aic->nr_dispatched);
}
/*
@@ -1396,93 +1197,35 @@ static int as_queue_empty(request_queue_t *q)
&& list_empty(&ad->fifo_list[REQ_SYNC]);
}
-static struct request *as_former_request(request_queue_t *q,
- struct request *rq)
-{
- struct as_rq *arq = RQ_DATA(rq);
- struct rb_node *rbprev = rb_prev(&arq->rb_node);
- struct request *ret = NULL;
-
- if (rbprev)
- ret = rb_entry_arq(rbprev)->request;
-
- return ret;
-}
-
-static struct request *as_latter_request(request_queue_t *q,
- struct request *rq)
-{
- struct as_rq *arq = RQ_DATA(rq);
- struct rb_node *rbnext = rb_next(&arq->rb_node);
- struct request *ret = NULL;
-
- if (rbnext)
- ret = rb_entry_arq(rbnext)->request;
-
- return ret;
-}
-
static int
as_merge(request_queue_t *q, struct request **req, struct bio *bio)
{
struct as_data *ad = q->elevator->elevator_data;
sector_t rb_key = bio->bi_sector + bio_sectors(bio);
struct request *__rq;
- int ret;
-
- /*
- * see if the merge hash can satisfy a back merge
- */
- __rq = as_find_arq_hash(ad, bio->bi_sector);
- if (__rq) {
- BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
-
- if (elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_BACK_MERGE;
- goto out;
- }
- }
/*
* check for front merge
*/
- __rq = as_find_arq_rb(ad, rb_key, bio_data_dir(bio));
- if (__rq) {
- BUG_ON(rb_key != rq_rb_key(__rq));
-
- if (elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_FRONT_MERGE;
- goto out;
- }
+ __rq = elv_rb_find(&ad->sort_list[bio_data_dir(bio)], rb_key);
+ if (__rq && elv_rq_merge_ok(__rq, bio)) {
+ *req = __rq;
+ return ELEVATOR_FRONT_MERGE;
}
return ELEVATOR_NO_MERGE;
-out:
- if (ret) {
- if (rq_mergeable(__rq))
- as_hot_arq_hash(ad, RQ_DATA(__rq));
- }
- *req = __rq;
- return ret;
}
-static void as_merged_request(request_queue_t *q, struct request *req)
+static void as_merged_request(request_queue_t *q, struct request *req, int type)
{
struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq = RQ_DATA(req);
-
- /*
- * hash always needs to be repositioned, key is end sector
- */
- as_del_arq_hash(arq);
- as_add_arq_hash(ad, arq);
/*
* if the merge was a front merge, we need to reposition request
*/
- if (rq_rb_key(req) != arq->rb_key) {
- as_del_arq_rb(ad, arq);
- as_add_arq_rb(ad, arq);
+ if (type == ELEVATOR_FRONT_MERGE) {
+ as_del_rq_rb(ad, req);
+ as_add_rq_rb(ad, req);
/*
* Note! At this stage of this and the next function, our next
* request may not be optimal - eg the request may have "grown"
@@ -1494,38 +1237,22 @@ static void as_merged_request(request_queue_t *q, struct request *req)
static void as_merged_requests(request_queue_t *q, struct request *req,
struct request *next)
{
- struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq = RQ_DATA(req);
- struct as_rq *anext = RQ_DATA(next);
-
- BUG_ON(!arq);
- BUG_ON(!anext);
-
/*
- * reposition arq (this is the merged request) in hash, and in rbtree
- * in case of a front merge
+ * if next expires before rq, assign its expire time to arq
+ * and move into next position (next will be deleted) in fifo
*/
- as_del_arq_hash(arq);
- as_add_arq_hash(ad, arq);
-
- if (rq_rb_key(req) != arq->rb_key) {
- as_del_arq_rb(ad, arq);
- as_add_arq_rb(ad, arq);
- }
+ if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
+ if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
+ struct io_context *rioc = RQ_IOC(req);
+ struct io_context *nioc = RQ_IOC(next);
- /*
- * if anext expires before arq, assign its expire time to arq
- * and move into anext position (anext will be deleted) in fifo
- */
- if (!list_empty(&arq->fifo) && !list_empty(&anext->fifo)) {
- if (time_before(anext->expires, arq->expires)) {
- list_move(&arq->fifo, &anext->fifo);
- arq->expires = anext->expires;
+ list_move(&req->queuelist, &next->queuelist);
+ rq_set_fifo_time(req, rq_fifo_time(next));
/*
* Don't copy here but swap, because when anext is
* removed below, it must contain the unused context
*/
- swap_io_context(&arq->io_context, &anext->io_context);
+ swap_io_context(&rioc, &nioc);
}
}
@@ -1533,9 +1260,9 @@ static void as_merged_requests(request_queue_t *q, struct request *req,
* kill knowledge of next, this one is a goner
*/
as_remove_queued_request(q, next);
- as_put_io_context(anext);
+ as_put_io_context(next);
- anext->state = AS_RQ_MERGED;
+ RQ_SET_STATE(next, AS_RQ_MERGED);
}
/*
@@ -1553,61 +1280,18 @@ static void as_work_handler(void *data)
unsigned long flags;
spin_lock_irqsave(q->queue_lock, flags);
- if (!as_queue_empty(q))
- q->request_fn(q);
+ blk_start_queueing(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
-static void as_put_request(request_queue_t *q, struct request *rq)
-{
- struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq = RQ_DATA(rq);
-
- if (!arq) {
- WARN_ON(1);
- return;
- }
-
- if (unlikely(arq->state != AS_RQ_POSTSCHED &&
- arq->state != AS_RQ_PRESCHED &&
- arq->state != AS_RQ_MERGED)) {
- printk("arq->state %d\n", arq->state);
- WARN_ON(1);
- }
-
- mempool_free(arq, ad->arq_pool);
- rq->elevator_private = NULL;
-}
-
-static int as_set_request(request_queue_t *q, struct request *rq,
- struct bio *bio, gfp_t gfp_mask)
-{
- struct as_data *ad = q->elevator->elevator_data;
- struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
-
- if (arq) {
- memset(arq, 0, sizeof(*arq));
- RB_CLEAR_NODE(&arq->rb_node);
- arq->request = rq;
- arq->state = AS_RQ_PRESCHED;
- arq->io_context = NULL;
- INIT_HLIST_NODE(&arq->hash);
- INIT_LIST_HEAD(&arq->fifo);
- rq->elevator_private = arq;
- return 0;
- }
-
- return 1;
-}
-
-static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
+static int as_may_queue(request_queue_t *q, int rw)
{
int ret = ELV_MQUEUE_MAY;
struct as_data *ad = q->elevator->elevator_data;
struct io_context *ioc;
if (ad->antic_status == ANTIC_WAIT_REQ ||
ad->antic_status == ANTIC_WAIT_NEXT) {
- ioc = as_get_io_context();
+ ioc = as_get_io_context(q->node);
if (ad->io_context == ioc)
ret = ELV_MQUEUE_MUST;
put_io_context(ioc);
@@ -1626,23 +1310,16 @@ static void as_exit_queue(elevator_t *e)
BUG_ON(!list_empty(&ad->fifo_list[REQ_SYNC]));
BUG_ON(!list_empty(&ad->fifo_list[REQ_ASYNC]));
- mempool_destroy(ad->arq_pool);
put_io_context(ad->io_context);
- kfree(ad->hash);
kfree(ad);
}
/*
- * initialize elevator private data (as_data), and alloc a arq for
- * each request on the free lists
+ * initialize elevator private data (as_data).
*/
static void *as_init_queue(request_queue_t *q, elevator_t *e)
{
struct as_data *ad;
- int i;
-
- if (!arq_pool)
- return NULL;
ad = kmalloc_node(sizeof(*ad), GFP_KERNEL, q->node);
if (!ad)
@@ -1651,30 +1328,12 @@ static void *as_init_queue(request_queue_t *q, elevator_t *e)
ad->q = q; /* Identify what queue the data belongs to */
- ad->hash = kmalloc_node(sizeof(struct hlist_head)*AS_HASH_ENTRIES,
- GFP_KERNEL, q->node);
- if (!ad->hash) {
- kfree(ad);
- return NULL;
- }
-
- ad->arq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
- mempool_free_slab, arq_pool, q->node);
- if (!ad->arq_pool) {
- kfree(ad->hash);
- kfree(ad);
- return NULL;
- }
-
/* anticipatory scheduling helpers */
ad->antic_timer.function = as_antic_timeout;
ad->antic_timer.data = (unsigned long)q;
init_timer(&ad->antic_timer);
INIT_WORK(&ad->antic_work, as_work_handler, q);
- for (i = 0; i < AS_HASH_ENTRIES; i++)
- INIT_HLIST_HEAD(&ad->hash[i]);
-
INIT_LIST_HEAD(&ad->fifo_list[REQ_SYNC]);
INIT_LIST_HEAD(&ad->fifo_list[REQ_ASYNC]);
ad->sort_list[REQ_SYNC] = RB_ROOT;
@@ -1787,10 +1446,8 @@ static struct elevator_type iosched_as = {
.elevator_deactivate_req_fn = as_deactivate_request,
.elevator_queue_empty_fn = as_queue_empty,
.elevator_completed_req_fn = as_completed_request,
- .elevator_former_req_fn = as_former_request,
- .elevator_latter_req_fn = as_latter_request,
- .elevator_set_req_fn = as_set_request,
- .elevator_put_req_fn = as_put_request,
+ .elevator_former_req_fn = elv_rb_former_request,
+ .elevator_latter_req_fn = elv_rb_latter_request,
.elevator_may_queue_fn = as_may_queue,
.elevator_init_fn = as_init_queue,
.elevator_exit_fn = as_exit_queue,
@@ -1806,11 +1463,6 @@ static int __init as_init(void)
{
int ret;
- arq_pool = kmem_cache_create("as_arq", sizeof(struct as_rq),
- 0, 0, NULL, NULL);
- if (!arq_pool)
- return -ENOMEM;
-
ret = elv_register(&iosched_as);
if (!ret) {
/*
@@ -1822,21 +1474,19 @@ static int __init as_init(void)
return 0;
}
- kmem_cache_destroy(arq_pool);
return ret;
}
static void __exit as_exit(void)
{
- DECLARE_COMPLETION(all_gone);
+ DECLARE_COMPLETION_ONSTACK(all_gone);
elv_unregister(&iosched_as);
ioc_gone = &all_gone;
/* ioc_gone's update must be visible before reading ioc_count */
smp_wmb();
- if (atomic_read(&ioc_count))
+ if (elv_ioc_count_read(ioc_count))
wait_for_completion(ioc_gone);
synchronize_rcu();
- kmem_cache_destroy(arq_pool);
}
module_init(as_init);
diff --git a/block/blktrace.c b/block/blktrace.c
index 265f7a830619..135593c8e45b 100644
--- a/block/blktrace.c
+++ b/block/blktrace.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2006 Jens Axboe <axboe@kernel.dk>
*
* 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
@@ -69,7 +69,7 @@ static u32 ddir_act[2] __read_mostly = { BLK_TC_ACT(BLK_TC_READ), BLK_TC_ACT(BLK
/*
* Bio action bits of interest
*/
-static u32 bio_act[5] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD) };
+static u32 bio_act[9] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_ACT(BLK_TC_SYNC), 0, BLK_TC_ACT(BLK_TC_AHEAD), 0, 0, 0, BLK_TC_ACT(BLK_TC_META) };
/*
* More could be added as needed, taking care to increment the decrementer
@@ -81,6 +81,8 @@ static u32 bio_act[5] __read_mostly = { 0, BLK_TC_ACT(BLK_TC_BARRIER), BLK_TC_AC
(((rw) & (1 << BIO_RW_SYNC)) >> (BIO_RW_SYNC - 1))
#define trace_ahead_bit(rw) \
(((rw) & (1 << BIO_RW_AHEAD)) << (2 - BIO_RW_AHEAD))
+#define trace_meta_bit(rw) \
+ (((rw) & (1 << BIO_RW_META)) >> (BIO_RW_META - 3))
/*
* The worker for the various blk_add_trace*() types. Fills out a
@@ -103,6 +105,7 @@ void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
what |= bio_act[trace_barrier_bit(rw)];
what |= bio_act[trace_sync_bit(rw)];
what |= bio_act[trace_ahead_bit(rw)];
+ what |= bio_act[trace_meta_bit(rw)];
pid = tsk->pid;
if (unlikely(act_log_check(bt, what, sector, pid)))
@@ -217,7 +220,7 @@ static int blk_trace_remove(request_queue_t *q)
static int blk_dropped_open(struct inode *inode, struct file *filp)
{
- filp->private_data = inode->u.generic_ip;
+ filp->private_data = inode->i_private;
return 0;
}
@@ -450,8 +453,10 @@ int blk_trace_ioctl(struct block_device *bdev, unsigned cmd, char __user *arg)
**/
void blk_trace_shutdown(request_queue_t *q)
{
- blk_trace_startstop(q, 0);
- blk_trace_remove(q);
+ if (q->blk_trace) {
+ blk_trace_startstop(q, 0);
+ blk_trace_remove(q);
+ }
}
/*
@@ -471,6 +476,9 @@ static void blk_check_time(unsigned long long *t)
*t -= (a + b) / 2;
}
+/*
+ * calibrate our inter-CPU timings
+ */
static void blk_trace_check_cpu_time(void *data)
{
unsigned long long *t;
@@ -488,20 +496,6 @@ static void blk_trace_check_cpu_time(void *data)
put_cpu();
}
-/*
- * Call blk_trace_check_cpu_time() on each CPU to calibrate our inter-CPU
- * timings
- */
-static void blk_trace_calibrate_offsets(void)
-{
- unsigned long flags;
-
- smp_call_function(blk_trace_check_cpu_time, NULL, 1, 1);
- local_irq_save(flags);
- blk_trace_check_cpu_time(NULL);
- local_irq_restore(flags);
-}
-
static void blk_trace_set_ht_offsets(void)
{
#if defined(CONFIG_SCHED_SMT)
@@ -530,7 +524,7 @@ static void blk_trace_set_ht_offsets(void)
static __init int blk_trace_init(void)
{
mutex_init(&blk_tree_mutex);
- blk_trace_calibrate_offsets();
+ on_each_cpu(blk_trace_check_cpu_time, NULL, 1, 1);
blk_trace_set_ht_offsets();
return 0;
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 3a3aee08ec5f..d3d76136f53a 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -4,7 +4,7 @@
* Based on ideas from a previously unfinished io
* scheduler (round robin per-process disk scheduling) and Andrea Arcangeli.
*
- * Copyright (C) 2003 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
*/
#include <linux/module.h>
#include <linux/blkdev.h>
@@ -17,7 +17,6 @@
* tunables
*/
static const int cfq_quantum = 4; /* max queue in one round of service */
-static const int cfq_queued = 8; /* minimum rq allocate limit per-queue*/
static const int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
static const int cfq_back_max = 16 * 1024; /* maximum backwards seek, in KiB */
static const int cfq_back_penalty = 2; /* penalty of a backwards seek */
@@ -32,8 +31,6 @@ static int cfq_slice_idle = HZ / 125;
#define CFQ_KEY_ASYNC (0)
-static DEFINE_SPINLOCK(cfq_exit_lock);
-
/*
* for the hash of cfqq inside the cfqd
*/
@@ -41,37 +38,19 @@ static DEFINE_SPINLOCK(cfq_exit_lock);
#define CFQ_QHASH_ENTRIES (1 << CFQ_QHASH_SHIFT)
#define list_entry_qhash(entry) hlist_entry((entry), struct cfq_queue, cfq_hash)
-/*
- * for the hash of crq inside the cfqq
- */
-#define CFQ_MHASH_SHIFT 6
-#define CFQ_MHASH_BLOCK(sec) ((sec) >> 3)
-#define CFQ_MHASH_ENTRIES (1 << CFQ_MHASH_SHIFT)
-#define CFQ_MHASH_FN(sec) hash_long(CFQ_MHASH_BLOCK(sec), CFQ_MHASH_SHIFT)
-#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
-#define list_entry_hash(ptr) hlist_entry((ptr), struct cfq_rq, hash)
-
#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list)
-#define list_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
-#define RQ_DATA(rq) (rq)->elevator_private
+#define RQ_CIC(rq) ((struct cfq_io_context*)(rq)->elevator_private)
+#define RQ_CFQQ(rq) ((rq)->elevator_private2)
-/*
- * rb-tree defines
- */
-#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node)
-#define rq_rb_key(rq) (rq)->sector
-
-static kmem_cache_t *crq_pool;
static kmem_cache_t *cfq_pool;
static kmem_cache_t *cfq_ioc_pool;
-static atomic_t ioc_count = ATOMIC_INIT(0);
+static DEFINE_PER_CPU(unsigned long, ioc_count);
static struct completion *ioc_gone;
#define CFQ_PRIO_LISTS IOPRIO_BE_NR
#define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
-#define cfq_class_be(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_BE)
#define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
#define ASYNC (0)
@@ -103,29 +82,14 @@ struct cfq_data {
unsigned int busy_queues;
/*
- * non-ordered list of empty cfqq's
- */
- struct list_head empty_list;
-
- /*
* cfqq lookup hash
*/
struct hlist_head *cfq_hash;
- /*
- * global crq hash for all queues
- */
- struct hlist_head *crq_hash;
-
- mempool_t *crq_pool;
-
int rq_in_driver;
int hw_tag;
/*
- * schedule slice state info
- */
- /*
* idle window management
*/
struct timer_list idle_slice_timer;
@@ -141,13 +105,10 @@ struct cfq_data {
sector_t last_sector;
unsigned long last_end_request;
- unsigned int rq_starved;
-
/*
* tunables, see top of file
*/
unsigned int cfq_quantum;
- unsigned int cfq_queued;
unsigned int cfq_fifo_expire[2];
unsigned int cfq_back_penalty;
unsigned int cfq_back_max;
@@ -170,23 +131,24 @@ struct cfq_queue {
struct hlist_node cfq_hash;
/* hash key */
unsigned int key;
- /* on either rr or empty list of cfqd */
+ /* member of the rr/busy/cur/idle cfqd list */
struct list_head cfq_list;
/* sorted list of pending requests */
struct rb_root sort_list;
/* if fifo isn't expired, next request to serve */
- struct cfq_rq *next_crq;
+ struct request *next_rq;
/* requests queued in sort_list */
int queued[2];
/* currently allocated requests */
int allocated[2];
+ /* pending metadata requests */
+ int meta_pending;
/* fifo list of requests in sort_list */
struct list_head fifo;
unsigned long slice_start;
unsigned long slice_end;
unsigned long slice_left;
- unsigned long service_last;
/* number of requests that are on the dispatch list */
int on_dispatch[2];
@@ -199,18 +161,6 @@ struct cfq_queue {
unsigned int flags;
};
-struct cfq_rq {
- struct rb_node rb_node;
- sector_t rb_key;
- struct request *request;
- struct hlist_node hash;
-
- struct cfq_queue *cfq_queue;
- struct cfq_io_context *io_context;
-
- unsigned int crq_flags;
-};
-
enum cfqq_state_flags {
CFQ_CFQQ_FLAG_on_rr = 0,
CFQ_CFQQ_FLAG_wait_request,
@@ -220,6 +170,7 @@ enum cfqq_state_flags {
CFQ_CFQQ_FLAG_fifo_expire,
CFQ_CFQQ_FLAG_idle_window,
CFQ_CFQQ_FLAG_prio_changed,
+ CFQ_CFQQ_FLAG_queue_new,
};
#define CFQ_CFQQ_FNS(name) \
@@ -244,70 +195,14 @@ CFQ_CFQQ_FNS(must_dispatch);
CFQ_CFQQ_FNS(fifo_expire);
CFQ_CFQQ_FNS(idle_window);
CFQ_CFQQ_FNS(prio_changed);
+CFQ_CFQQ_FNS(queue_new);
#undef CFQ_CFQQ_FNS
-enum cfq_rq_state_flags {
- CFQ_CRQ_FLAG_is_sync = 0,
-};
-
-#define CFQ_CRQ_FNS(name) \
-static inline void cfq_mark_crq_##name(struct cfq_rq *crq) \
-{ \
- crq->crq_flags |= (1 << CFQ_CRQ_FLAG_##name); \
-} \
-static inline void cfq_clear_crq_##name(struct cfq_rq *crq) \
-{ \
- crq->crq_flags &= ~(1 << CFQ_CRQ_FLAG_##name); \
-} \
-static inline int cfq_crq_##name(const struct cfq_rq *crq) \
-{ \
- return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \
-}
-
-CFQ_CRQ_FNS(is_sync);
-#undef CFQ_CRQ_FNS
-
static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
-static void cfq_dispatch_insert(request_queue_t *, struct cfq_rq *);
+static void cfq_dispatch_insert(request_queue_t *, struct request *);
static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, unsigned int key, struct task_struct *tsk, gfp_t gfp_mask);
/*
- * lots of deadline iosched dupes, can be abstracted later...
- */
-static inline void cfq_del_crq_hash(struct cfq_rq *crq)
-{
- hlist_del_init(&crq->hash);
-}
-
-static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
-{
- const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request));
-
- hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]);
-}
-
-static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
-{
- struct hlist_head *hash_list = &cfqd->crq_hash[CFQ_MHASH_FN(offset)];
- struct hlist_node *entry, *next;
-
- hlist_for_each_safe(entry, next, hash_list) {
- struct cfq_rq *crq = list_entry_hash(entry);
- struct request *__rq = crq->request;
-
- if (!rq_mergeable(__rq)) {
- cfq_del_crq_hash(crq);
- continue;
- }
-
- if (rq_hash_key(__rq) == offset)
- return __rq;
- }
-
- return NULL;
-}
-
-/*
* scheduler run of queue, if there are requests pending and no one in the
* driver that will restart queueing
*/
@@ -333,12 +228,12 @@ static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
}
/*
- * Lifted from AS - choose which of crq1 and crq2 that is best served now.
+ * Lifted from AS - choose which of rq1 and rq2 that is best served now.
* We choose the request that is closest to the head right now. Distance
* behind the head is penalized and only allowed to a certain extent.
*/
-static struct cfq_rq *
-cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
+static struct request *
+cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2)
{
sector_t last, s1, s2, d1 = 0, d2 = 0;
unsigned long back_max;
@@ -346,18 +241,22 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
#define CFQ_RQ2_WRAP 0x02 /* request 2 wraps */
unsigned wrap = 0; /* bit mask: requests behind the disk head? */
- if (crq1 == NULL || crq1 == crq2)
- return crq2;
- if (crq2 == NULL)
- return crq1;
+ if (rq1 == NULL || rq1 == rq2)
+ return rq2;
+ if (rq2 == NULL)
+ return rq1;
- if (cfq_crq_is_sync(crq1) && !cfq_crq_is_sync(crq2))
- return crq1;
- else if (cfq_crq_is_sync(crq2) && !cfq_crq_is_sync(crq1))
- return crq2;
+ if (rq_is_sync(rq1) && !rq_is_sync(rq2))
+ return rq1;
+ else if (rq_is_sync(rq2) && !rq_is_sync(rq1))
+ return rq2;
+ if (rq_is_meta(rq1) && !rq_is_meta(rq2))
+ return rq1;
+ else if (rq_is_meta(rq2) && !rq_is_meta(rq1))
+ return rq2;
- s1 = crq1->request->sector;
- s2 = crq2->request->sector;
+ s1 = rq1->sector;
+ s2 = rq2->sector;
last = cfqd->last_sector;
@@ -392,23 +291,23 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
* check two variables for all permutations: --> faster!
*/
switch (wrap) {
- case 0: /* common case for CFQ: crq1 and crq2 not wrapped */
+ case 0: /* common case for CFQ: rq1 and rq2 not wrapped */
if (d1 < d2)
- return crq1;
+ return rq1;
else if (d2 < d1)
- return crq2;
+ return rq2;
else {
if (s1 >= s2)
- return crq1;
+ return rq1;
else
- return crq2;
+ return rq2;
}
case CFQ_RQ2_WRAP:
- return crq1;
+ return rq1;
case CFQ_RQ1_WRAP:
- return crq2;
- case (CFQ_RQ1_WRAP|CFQ_RQ2_WRAP): /* both crqs wrapped */
+ return rq2;
+ case (CFQ_RQ1_WRAP|CFQ_RQ2_WRAP): /* both rqs wrapped */
default:
/*
* Since both rqs are wrapped,
@@ -417,50 +316,43 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
* since back seek takes more time than forward.
*/
if (s1 <= s2)
- return crq1;
+ return rq1;
else
- return crq2;
+ return rq2;
}
}
/*
* would be nice to take fifo expire time into account as well
*/
-static struct cfq_rq *
-cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- struct cfq_rq *last)
+static struct request *
+cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct request *last)
{
- struct cfq_rq *crq_next = NULL, *crq_prev = NULL;
- struct rb_node *rbnext, *rbprev;
-
- if (!(rbnext = rb_next(&last->rb_node))) {
- rbnext = rb_first(&cfqq->sort_list);
- if (rbnext == &last->rb_node)
- rbnext = NULL;
- }
+ struct rb_node *rbnext = rb_next(&last->rb_node);
+ struct rb_node *rbprev = rb_prev(&last->rb_node);
+ struct request *next = NULL, *prev = NULL;
- rbprev = rb_prev(&last->rb_node);
+ BUG_ON(RB_EMPTY_NODE(&last->rb_node));
if (rbprev)
- crq_prev = rb_entry_crq(rbprev);
- if (rbnext)
- crq_next = rb_entry_crq(rbnext);
-
- return cfq_choose_req(cfqd, crq_next, crq_prev);
-}
+ prev = rb_entry_rq(rbprev);
-static void cfq_update_next_crq(struct cfq_rq *crq)
-{
- struct cfq_queue *cfqq = crq->cfq_queue;
+ if (rbnext)
+ next = rb_entry_rq(rbnext);
+ else {
+ rbnext = rb_first(&cfqq->sort_list);
+ if (rbnext && rbnext != &last->rb_node)
+ next = rb_entry_rq(rbnext);
+ }
- if (cfqq->next_crq == crq)
- cfqq->next_crq = cfq_find_next_crq(cfqq->cfqd, cfqq, crq);
+ return cfq_choose_req(cfqd, next, prev);
}
static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
{
struct cfq_data *cfqd = cfqq->cfqd;
- struct list_head *list, *entry;
+ struct list_head *list;
BUG_ON(!cfq_cfqq_on_rr(cfqq));
@@ -485,31 +377,26 @@ static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
}
/*
- * if queue was preempted, just add to front to be fair. busy_rr
- * isn't sorted, but insert at the back for fairness.
+ * If this queue was preempted or is new (never been serviced), let
+ * it be added first for fairness but beind other new queues.
+ * Otherwise, just add to the back of the list.
*/
- if (preempted || list == &cfqd->busy_rr) {
- if (preempted)
- list = list->prev;
+ if (preempted || cfq_cfqq_queue_new(cfqq)) {
+ struct list_head *n = list;
+ struct cfq_queue *__cfqq;
- list_add_tail(&cfqq->cfq_list, list);
- return;
- }
+ while (n->next != list) {
+ __cfqq = list_entry_cfqq(n->next);
+ if (!cfq_cfqq_queue_new(__cfqq))
+ break;
- /*
- * sort by when queue was last serviced
- */
- entry = list;
- while ((entry = entry->prev) != list) {
- struct cfq_queue *__cfqq = list_entry_cfqq(entry);
+ n = n->next;
+ }
- if (!__cfqq->service_last)
- break;
- if (time_before(__cfqq->service_last, cfqq->service_last))
- break;
+ list = n;
}
- list_add(&cfqq->cfq_list, entry);
+ list_add_tail(&cfqq->cfq_list, list);
}
/*
@@ -531,7 +418,7 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
BUG_ON(!cfq_cfqq_on_rr(cfqq));
cfq_clear_cfqq_on_rr(cfqq);
- list_move(&cfqq->cfq_list, &cfqd->empty_list);
+ list_del_init(&cfqq->cfq_list);
BUG_ON(!cfqd->busy_queues);
cfqd->busy_queues--;
@@ -540,81 +427,43 @@ cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
/*
* rb tree support functions
*/
-static inline void cfq_del_crq_rb(struct cfq_rq *crq)
+static inline void cfq_del_rq_rb(struct request *rq)
{
- struct cfq_queue *cfqq = crq->cfq_queue;
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
struct cfq_data *cfqd = cfqq->cfqd;
- const int sync = cfq_crq_is_sync(crq);
+ const int sync = rq_is_sync(rq);
BUG_ON(!cfqq->queued[sync]);
cfqq->queued[sync]--;
- cfq_update_next_crq(crq);
-
- rb_erase(&crq->rb_node, &cfqq->sort_list);
+ elv_rb_del(&cfqq->sort_list, rq);
if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list))
cfq_del_cfqq_rr(cfqd, cfqq);
}
-static struct cfq_rq *
-__cfq_add_crq_rb(struct cfq_rq *crq)
+static void cfq_add_rq_rb(struct request *rq)
{
- struct rb_node **p = &crq->cfq_queue->sort_list.rb_node;
- struct rb_node *parent = NULL;
- struct cfq_rq *__crq;
-
- while (*p) {
- parent = *p;
- __crq = rb_entry_crq(parent);
-
- if (crq->rb_key < __crq->rb_key)
- p = &(*p)->rb_left;
- else if (crq->rb_key > __crq->rb_key)
- p = &(*p)->rb_right;
- else
- return __crq;
- }
-
- rb_link_node(&crq->rb_node, parent, p);
- return NULL;
-}
-
-static void cfq_add_crq_rb(struct cfq_rq *crq)
-{
- struct cfq_queue *cfqq = crq->cfq_queue;
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
struct cfq_data *cfqd = cfqq->cfqd;
- struct request *rq = crq->request;
- struct cfq_rq *__alias;
+ struct request *__alias;
- crq->rb_key = rq_rb_key(rq);
- cfqq->queued[cfq_crq_is_sync(crq)]++;
+ cfqq->queued[rq_is_sync(rq)]++;
/*
* looks a little odd, but the first insert might return an alias.
* if that happens, put the alias on the dispatch list
*/
- while ((__alias = __cfq_add_crq_rb(crq)) != NULL)
+ while ((__alias = elv_rb_add(&cfqq->sort_list, rq)) != NULL)
cfq_dispatch_insert(cfqd->queue, __alias);
-
- rb_insert_color(&crq->rb_node, &cfqq->sort_list);
-
- if (!cfq_cfqq_on_rr(cfqq))
- cfq_add_cfqq_rr(cfqd, cfqq);
-
- /*
- * check if this request is a better next-serve candidate
- */
- cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
}
static inline void
-cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
+cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq)
{
- rb_erase(&crq->rb_node, &cfqq->sort_list);
- cfqq->queued[cfq_crq_is_sync(crq)]--;
-
- cfq_add_crq_rb(crq);
+ elv_rb_del(&cfqq->sort_list, rq);
+ cfqq->queued[rq_is_sync(rq)]--;
+ cfq_add_rq_rb(rq);
}
static struct request *
@@ -623,27 +472,14 @@ cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio)
struct task_struct *tsk = current;
pid_t key = cfq_queue_pid(tsk, bio_data_dir(bio));
struct cfq_queue *cfqq;
- struct rb_node *n;
- sector_t sector;
cfqq = cfq_find_cfq_hash(cfqd, key, tsk->ioprio);
- if (!cfqq)
- goto out;
-
- sector = bio->bi_sector + bio_sectors(bio);
- n = cfqq->sort_list.rb_node;
- while (n) {
- struct cfq_rq *crq = rb_entry_crq(n);
+ if (cfqq) {
+ sector_t sector = bio->bi_sector + bio_sectors(bio);
- if (sector < crq->rb_key)
- n = n->rb_left;
- else if (sector > crq->rb_key)
- n = n->rb_right;
- else
- return crq->request;
+ return elv_rb_find(&cfqq->sort_list, sector);
}
-out:
return NULL;
}
@@ -673,11 +509,18 @@ static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
static void cfq_remove_request(struct request *rq)
{
- struct cfq_rq *crq = RQ_DATA(rq);
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
+
+ if (cfqq->next_rq == rq)
+ cfqq->next_rq = cfq_find_next_rq(cfqq->cfqd, cfqq, rq);
list_del_init(&rq->queuelist);
- cfq_del_crq_rb(crq);
- cfq_del_crq_hash(crq);
+ cfq_del_rq_rb(rq);
+
+ if (rq_is_meta(rq)) {
+ WARN_ON(!cfqq->meta_pending);
+ cfqq->meta_pending--;
+ }
}
static int
@@ -685,39 +528,23 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct request *__rq;
- int ret;
-
- __rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
- if (__rq && elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_BACK_MERGE;
- goto out;
- }
__rq = cfq_find_rq_fmerge(cfqd, bio);
if (__rq && elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_FRONT_MERGE;
- goto out;
+ *req = __rq;
+ return ELEVATOR_FRONT_MERGE;
}
return ELEVATOR_NO_MERGE;
-out:
- *req = __rq;
- return ret;
}
-static void cfq_merged_request(request_queue_t *q, struct request *req)
+static void cfq_merged_request(request_queue_t *q, struct request *req,
+ int type)
{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_rq *crq = RQ_DATA(req);
-
- cfq_del_crq_hash(crq);
- cfq_add_crq_hash(cfqd, crq);
-
- if (rq_rb_key(req) != crq->rb_key) {
- struct cfq_queue *cfqq = crq->cfq_queue;
+ if (type == ELEVATOR_FRONT_MERGE) {
+ struct cfq_queue *cfqq = RQ_CFQQ(req);
- cfq_update_next_crq(crq);
- cfq_reposition_crq_rb(cfqq, crq);
+ cfq_reposition_rq_rb(cfqq, req);
}
}
@@ -725,8 +552,6 @@ static void
cfq_merged_requests(request_queue_t *q, struct request *rq,
struct request *next)
{
- cfq_merged_request(q, rq);
-
/*
* reposition in fifo if next is older than rq
*/
@@ -768,13 +593,12 @@ __cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
if (cfq_cfqq_wait_request(cfqq))
del_timer(&cfqd->idle_slice_timer);
- if (!preempted && !cfq_cfqq_dispatched(cfqq)) {
- cfqq->service_last = now;
+ if (!preempted && !cfq_cfqq_dispatched(cfqq))
cfq_schedule_dispatch(cfqd);
- }
cfq_clear_cfqq_must_dispatch(cfqq);
cfq_clear_cfqq_wait_request(cfqq);
+ cfq_clear_cfqq_queue_new(cfqq);
/*
* store what was left of this slice, if the queue idled out
@@ -868,26 +692,25 @@ static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
{
struct cfq_queue *cfqq = NULL;
- /*
- * if current list is non-empty, grab first entry. if it is empty,
- * get next prio level and grab first entry then if any are spliced
- */
- if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1)
+ if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1) {
+ /*
+ * if current list is non-empty, grab first entry. if it is
+ * empty, get next prio level and grab first entry then if any
+ * are spliced
+ */
cfqq = list_entry_cfqq(cfqd->cur_rr.next);
-
- /*
- * If no new queues are available, check if the busy list has some
- * before falling back to idle io.
- */
- if (!cfqq && !list_empty(&cfqd->busy_rr))
+ } else if (!list_empty(&cfqd->busy_rr)) {
+ /*
+ * If no new queues are available, check if the busy list has
+ * some before falling back to idle io.
+ */
cfqq = list_entry_cfqq(cfqd->busy_rr.next);
-
- /*
- * if we have idle queues and no rt or be queues had pending
- * requests, either allow immediate service if the grace period
- * has passed or arm the idle grace timer
- */
- if (!cfqq && !list_empty(&cfqd->idle_rr)) {
+ } else if (!list_empty(&cfqd->idle_rr)) {
+ /*
+ * if we have idle queues and no rt or be queues had pending
+ * requests, either allow immediate service if the grace period
+ * has passed or arm the idle grace timer
+ */
unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
if (time_after_eq(jiffies, end))
@@ -942,16 +765,14 @@ static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
return 1;
}
-static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq)
+static void cfq_dispatch_insert(request_queue_t *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq = crq->cfq_queue;
- struct request *rq;
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
- cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
- cfq_remove_request(crq->request);
- cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
- elv_dispatch_sort(q, crq->request);
+ cfq_remove_request(rq);
+ cfqq->on_dispatch[rq_is_sync(rq)]++;
+ elv_dispatch_sort(q, rq);
rq = list_entry(q->queue_head.prev, struct request, queuelist);
cfqd->last_sector = rq->sector + rq->nr_sectors;
@@ -960,24 +781,23 @@ static void cfq_dispatch_insert(request_queue_t *q, struct cfq_rq *crq)
/*
* return expired entry, or NULL to just start from scratch in rbtree
*/
-static inline struct cfq_rq *cfq_check_fifo(struct cfq_queue *cfqq)
+static inline struct request *cfq_check_fifo(struct cfq_queue *cfqq)
{
struct cfq_data *cfqd = cfqq->cfqd;
struct request *rq;
- struct cfq_rq *crq;
+ int fifo;
if (cfq_cfqq_fifo_expire(cfqq))
return NULL;
+ if (list_empty(&cfqq->fifo))
+ return NULL;
- if (!list_empty(&cfqq->fifo)) {
- int fifo = cfq_cfqq_class_sync(cfqq);
+ fifo = cfq_cfqq_class_sync(cfqq);
+ rq = rq_entry_fifo(cfqq->fifo.next);
- crq = RQ_DATA(list_entry_fifo(cfqq->fifo.next));
- rq = crq->request;
- if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) {
- cfq_mark_cfqq_fifo_expire(cfqq);
- return crq;
- }
+ if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) {
+ cfq_mark_cfqq_fifo_expire(cfqq);
+ return rq;
}
return NULL;
@@ -1063,25 +883,25 @@ __cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list));
do {
- struct cfq_rq *crq;
+ struct request *rq;
/*
* follow expired path, else get first next available
*/
- if ((crq = cfq_check_fifo(cfqq)) == NULL)
- crq = cfqq->next_crq;
+ if ((rq = cfq_check_fifo(cfqq)) == NULL)
+ rq = cfqq->next_rq;
/*
* finally, insert request into driver dispatch list
*/
- cfq_dispatch_insert(cfqd->queue, crq);
+ cfq_dispatch_insert(cfqd->queue, rq);
cfqd->dispatch_slice++;
dispatched++;
if (!cfqd->active_cic) {
- atomic_inc(&crq->io_context->ioc->refcount);
- cfqd->active_cic = crq->io_context;
+ atomic_inc(&RQ_CIC(rq)->ioc->refcount);
+ cfqd->active_cic = RQ_CIC(rq);
}
if (RB_EMPTY_ROOT(&cfqq->sort_list))
@@ -1112,13 +932,12 @@ static int
cfq_forced_dispatch_cfqqs(struct list_head *list)
{
struct cfq_queue *cfqq, *next;
- struct cfq_rq *crq;
int dispatched;
dispatched = 0;
list_for_each_entry_safe(cfqq, next, list, cfq_list) {
- while ((crq = cfqq->next_crq)) {
- cfq_dispatch_insert(cfqq->cfqd->queue, crq);
+ while (cfqq->next_rq) {
+ cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq);
dispatched++;
}
BUG_ON(!list_empty(&cfqq->fifo));
@@ -1194,8 +1013,8 @@ cfq_dispatch_requests(request_queue_t *q, int force)
}
/*
- * task holds one reference to the queue, dropped when task exits. each crq
- * in-flight on this queue also holds a reference, dropped when crq is freed.
+ * task holds one reference to the queue, dropped when task exits. each rq
+ * in-flight on this queue also holds a reference, dropped when rq is freed.
*
* queue lock must be held here.
*/
@@ -1223,7 +1042,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
kmem_cache_free(cfq_pool, cfqq);
}
-static inline struct cfq_queue *
+static struct cfq_queue *
__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
const int hashval)
{
@@ -1260,62 +1079,63 @@ static void cfq_free_io_context(struct io_context *ioc)
freed++;
}
- if (atomic_sub_and_test(freed, &ioc_count) && ioc_gone)
+ elv_ioc_count_mod(ioc_count, -freed);
+
+ if (ioc_gone && !elv_ioc_count_read(ioc_count))
complete(ioc_gone);
}
-static void cfq_trim(struct io_context *ioc)
+static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
- ioc->set_ioprio = NULL;
- cfq_free_io_context(ioc);
+ if (unlikely(cfqq == cfqd->active_queue))
+ __cfq_slice_expired(cfqd, cfqq, 0);
+
+ cfq_put_queue(cfqq);
}
-/*
- * Called with interrupts disabled
- */
-static void cfq_exit_single_io_context(struct cfq_io_context *cic)
+static void __cfq_exit_single_io_context(struct cfq_data *cfqd,
+ struct cfq_io_context *cic)
{
- struct cfq_data *cfqd = cic->key;
- request_queue_t *q;
-
- if (!cfqd)
- return;
-
- q = cfqd->queue;
-
- WARN_ON(!irqs_disabled());
-
- spin_lock(q->queue_lock);
+ list_del_init(&cic->queue_list);
+ smp_wmb();
+ cic->key = NULL;
if (cic->cfqq[ASYNC]) {
- if (unlikely(cic->cfqq[ASYNC] == cfqd->active_queue))
- __cfq_slice_expired(cfqd, cic->cfqq[ASYNC], 0);
- cfq_put_queue(cic->cfqq[ASYNC]);
+ cfq_exit_cfqq(cfqd, cic->cfqq[ASYNC]);
cic->cfqq[ASYNC] = NULL;
}
if (cic->cfqq[SYNC]) {
- if (unlikely(cic->cfqq[SYNC] == cfqd->active_queue))
- __cfq_slice_expired(cfqd, cic->cfqq[SYNC], 0);
- cfq_put_queue(cic->cfqq[SYNC]);
+ cfq_exit_cfqq(cfqd, cic->cfqq[SYNC]);
cic->cfqq[SYNC] = NULL;
}
+}
- cic->key = NULL;
- list_del_init(&cic->queue_list);
- spin_unlock(q->queue_lock);
+
+/*
+ * Called with interrupts disabled
+ */
+static void cfq_exit_single_io_context(struct cfq_io_context *cic)
+{
+ struct cfq_data *cfqd = cic->key;
+
+ if (cfqd) {
+ request_queue_t *q = cfqd->queue;
+
+ spin_lock_irq(q->queue_lock);
+ __cfq_exit_single_io_context(cfqd, cic);
+ spin_unlock_irq(q->queue_lock);
+ }
}
static void cfq_exit_io_context(struct io_context *ioc)
{
struct cfq_io_context *__cic;
- unsigned long flags;
struct rb_node *n;
/*
* put the reference this task is holding to the various queues
*/
- spin_lock_irqsave(&cfq_exit_lock, flags);
n = rb_first(&ioc->cic_root);
while (n != NULL) {
@@ -1324,22 +1144,21 @@ static void cfq_exit_io_context(struct io_context *ioc)
cfq_exit_single_io_context(__cic);
n = rb_next(n);
}
-
- spin_unlock_irqrestore(&cfq_exit_lock, flags);
}
static struct cfq_io_context *
cfq_alloc_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
{
- struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
+ struct cfq_io_context *cic;
+ cic = kmem_cache_alloc_node(cfq_ioc_pool, gfp_mask, cfqd->queue->node);
if (cic) {
memset(cic, 0, sizeof(*cic));
cic->last_end_request = jiffies;
INIT_LIST_HEAD(&cic->queue_list);
cic->dtor = cfq_free_io_context;
cic->exit = cfq_exit_io_context;
- atomic_inc(&ioc_count);
+ elv_ioc_count_inc(ioc_count);
}
return cic;
@@ -1420,15 +1239,12 @@ static inline void changed_ioprio(struct cfq_io_context *cic)
spin_unlock(cfqd->queue->queue_lock);
}
-/*
- * callback from sys_ioprio_set, irqs are disabled
- */
-static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
+static void cfq_ioc_set_ioprio(struct io_context *ioc)
{
struct cfq_io_context *cic;
struct rb_node *n;
- spin_lock(&cfq_exit_lock);
+ ioc->ioprio_changed = 0;
n = rb_first(&ioc->cic_root);
while (n != NULL) {
@@ -1437,10 +1253,6 @@ static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
changed_ioprio(cic);
n = rb_next(n);
}
-
- spin_unlock(&cfq_exit_lock);
-
- return 0;
}
static struct cfq_queue *
@@ -1460,12 +1272,18 @@ retry:
cfqq = new_cfqq;
new_cfqq = NULL;
} else if (gfp_mask & __GFP_WAIT) {
+ /*
+ * Inform the allocator of the fact that we will
+ * just repeat this allocation if it fails, to allow
+ * the allocator to do whatever it needs to attempt to
+ * free memory.
+ */
spin_unlock_irq(cfqd->queue->queue_lock);
- new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+ new_cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask|__GFP_NOFAIL, cfqd->queue->node);
spin_lock_irq(cfqd->queue->queue_lock);
goto retry;
} else {
- cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+ cfqq = kmem_cache_alloc_node(cfq_pool, gfp_mask, cfqd->queue->node);
if (!cfqq)
goto out;
}
@@ -1480,13 +1298,13 @@ retry:
hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
atomic_set(&cfqq->ref, 0);
cfqq->cfqd = cfqd;
- cfqq->service_last = 0;
/*
* set ->slice_left to allow preemption for a new process
*/
cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
cfq_mark_cfqq_idle_window(cfqq);
cfq_mark_cfqq_prio_changed(cfqq);
+ cfq_mark_cfqq_queue_new(cfqq);
cfq_init_prio_data(cfqq);
}
@@ -1502,12 +1320,10 @@ out:
static void
cfq_drop_dead_cic(struct io_context *ioc, struct cfq_io_context *cic)
{
- spin_lock(&cfq_exit_lock);
+ WARN_ON(!list_empty(&cic->queue_list));
rb_erase(&cic->rb_node, &ioc->cic_root);
- list_del_init(&cic->queue_list);
- spin_unlock(&cfq_exit_lock);
kmem_cache_free(cfq_ioc_pool, cic);
- atomic_dec(&ioc_count);
+ elv_ioc_count_dec(ioc_count);
}
static struct cfq_io_context *
@@ -1551,7 +1367,6 @@ cfq_cic_link(struct cfq_data *cfqd, struct io_context *ioc,
cic->ioc = ioc;
cic->key = cfqd;
- ioc->set_ioprio = cfq_ioc_set_ioprio;
restart:
parent = NULL;
p = &ioc->cic_root.rb_node;
@@ -1573,11 +1388,12 @@ restart:
BUG();
}
- spin_lock(&cfq_exit_lock);
rb_link_node(&cic->rb_node, parent, p);
rb_insert_color(&cic->rb_node, &ioc->cic_root);
+
+ spin_lock_irq(cfqd->queue->queue_lock);
list_add(&cic->queue_list, &cfqd->cic_list);
- spin_unlock(&cfq_exit_lock);
+ spin_unlock_irq(cfqd->queue->queue_lock);
}
/*
@@ -1593,7 +1409,7 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
might_sleep_if(gfp_mask & __GFP_WAIT);
- ioc = get_io_context(gfp_mask);
+ ioc = get_io_context(gfp_mask, cfqd->queue->node);
if (!ioc)
return NULL;
@@ -1607,6 +1423,10 @@ cfq_get_io_context(struct cfq_data *cfqd, gfp_t gfp_mask)
cfq_cic_link(cfqd, ioc, cic);
out:
+ smp_read_barrier_depends();
+ if (unlikely(ioc->ioprio_changed))
+ cfq_ioc_set_ioprio(ioc);
+
return cic;
err:
put_io_context(ioc);
@@ -1640,15 +1460,15 @@ cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
static void
cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_io_context *cic,
- struct cfq_rq *crq)
+ struct request *rq)
{
sector_t sdist;
u64 total;
- if (cic->last_request_pos < crq->request->sector)
- sdist = crq->request->sector - cic->last_request_pos;
+ if (cic->last_request_pos < rq->sector)
+ sdist = rq->sector - cic->last_request_pos;
else
- sdist = cic->last_request_pos - crq->request->sector;
+ sdist = cic->last_request_pos - rq->sector;
/*
* Don't allow the seek distance to get too large from the
@@ -1699,7 +1519,7 @@ cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
*/
static int
cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
- struct cfq_rq *crq)
+ struct request *rq)
{
struct cfq_queue *cfqq = cfqd->active_queue;
@@ -1718,7 +1538,17 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
*/
if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
return 0;
- if (cfq_crq_is_sync(crq) && !cfq_cfqq_sync(cfqq))
+ /*
+ * if the new request is sync, but the currently running queue is
+ * not, let the sync request have priority.
+ */
+ if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq))
+ return 1;
+ /*
+ * So both queues are sync. Let the new request get disk time if
+ * it's a metadata request and the current queue is doing regular IO.
+ */
+ if (rq_is_meta(rq) && !cfqq->meta_pending)
return 1;
return 0;
@@ -1730,47 +1560,45 @@ cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
*/
static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
- struct cfq_queue *__cfqq, *next;
-
- list_for_each_entry_safe(__cfqq, next, &cfqd->cur_rr, cfq_list)
- cfq_resort_rr_list(__cfqq, 1);
+ cfq_slice_expired(cfqd, 1);
if (!cfqq->slice_left)
cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
- cfqq->slice_end = cfqq->slice_left + jiffies;
- cfq_slice_expired(cfqd, 1);
- __cfq_set_active_queue(cfqd, cfqq);
-}
-
-/*
- * should really be a ll_rw_blk.c helper
- */
-static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq)
-{
- request_queue_t *q = cfqd->queue;
+ /*
+ * Put the new queue at the front of the of the current list,
+ * so we know that it will be selected next.
+ */
+ BUG_ON(!cfq_cfqq_on_rr(cfqq));
+ list_move(&cfqq->cfq_list, &cfqd->cur_rr);
- if (!blk_queue_plugged(q))
- q->request_fn(q);
- else
- __generic_unplug_device(q);
+ cfqq->slice_end = cfqq->slice_left + jiffies;
}
/*
- * Called when a new fs request (crq) is added (to cfqq). Check if there's
+ * Called when a new fs request (rq) is added (to cfqq). Check if there's
* something we should do about it
*/
static void
-cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- struct cfq_rq *crq)
+cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct request *rq)
{
- struct cfq_io_context *cic = crq->io_context;
+ struct cfq_io_context *cic = RQ_CIC(rq);
+
+ if (rq_is_meta(rq))
+ cfqq->meta_pending++;
+
+ /*
+ * check if this request is a better next-serve candidate)) {
+ */
+ cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq);
+ BUG_ON(!cfqq->next_rq);
/*
* we never wait for an async request and we don't allow preemption
* of an async request. so just return early
*/
- if (!cfq_crq_is_sync(crq)) {
+ if (!rq_is_sync(rq)) {
/*
* sync process issued an async request, if it's waiting
* then expire it and kick rq handling.
@@ -1778,17 +1606,17 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
if (cic == cfqd->active_cic &&
del_timer(&cfqd->idle_slice_timer)) {
cfq_slice_expired(cfqd, 0);
- cfq_start_queueing(cfqd, cfqq);
+ blk_start_queueing(cfqd->queue);
}
return;
}
cfq_update_io_thinktime(cfqd, cic);
- cfq_update_io_seektime(cfqd, cic, crq);
+ cfq_update_io_seektime(cfqd, cic, rq);
cfq_update_idle_window(cfqd, cfqq, cic);
cic->last_queue = jiffies;
- cic->last_request_pos = crq->request->sector + crq->request->nr_sectors;
+ cic->last_request_pos = rq->sector + rq->nr_sectors;
if (cfqq == cfqd->active_queue) {
/*
@@ -1799,9 +1627,9 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
if (cfq_cfqq_wait_request(cfqq)) {
cfq_mark_cfqq_must_dispatch(cfqq);
del_timer(&cfqd->idle_slice_timer);
- cfq_start_queueing(cfqd, cfqq);
+ blk_start_queueing(cfqd->queue);
}
- } else if (cfq_should_preempt(cfqd, cfqq, crq)) {
+ } else if (cfq_should_preempt(cfqd, cfqq, rq)) {
/*
* not the active queue - expire current slice if it is
* idle and has expired it's mean thinktime or this new queue
@@ -1809,34 +1637,32 @@ cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
*/
cfq_preempt_queue(cfqd, cfqq);
cfq_mark_cfqq_must_dispatch(cfqq);
- cfq_start_queueing(cfqd, cfqq);
+ blk_start_queueing(cfqd->queue);
}
}
static void cfq_insert_request(request_queue_t *q, struct request *rq)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_rq *crq = RQ_DATA(rq);
- struct cfq_queue *cfqq = crq->cfq_queue;
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
cfq_init_prio_data(cfqq);
- cfq_add_crq_rb(crq);
+ cfq_add_rq_rb(rq);
- list_add_tail(&rq->queuelist, &cfqq->fifo);
+ if (!cfq_cfqq_on_rr(cfqq))
+ cfq_add_cfqq_rr(cfqd, cfqq);
- if (rq_mergeable(rq))
- cfq_add_crq_hash(cfqd, crq);
+ list_add_tail(&rq->queuelist, &cfqq->fifo);
- cfq_crq_enqueued(cfqd, cfqq, crq);
+ cfq_rq_enqueued(cfqd, cfqq, rq);
}
static void cfq_completed_request(request_queue_t *q, struct request *rq)
{
- struct cfq_rq *crq = RQ_DATA(rq);
- struct cfq_queue *cfqq = crq->cfq_queue;
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
struct cfq_data *cfqd = cfqq->cfqd;
- const int sync = cfq_crq_is_sync(crq);
+ const int sync = rq_is_sync(rq);
unsigned long now;
now = jiffies;
@@ -1849,15 +1675,11 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
if (!cfq_class_idle(cfqq))
cfqd->last_end_request = now;
- if (!cfq_cfqq_dispatched(cfqq)) {
- if (cfq_cfqq_on_rr(cfqq)) {
- cfqq->service_last = now;
- cfq_resort_rr_list(cfqq, 0);
- }
- }
+ if (!cfq_cfqq_dispatched(cfqq) && cfq_cfqq_on_rr(cfqq))
+ cfq_resort_rr_list(cfqq, 0);
if (sync)
- crq->io_context->last_end_request = now;
+ RQ_CIC(rq)->last_end_request = now;
/*
* If this is the active queue, check if it needs to be expired,
@@ -1873,30 +1695,6 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
}
}
-static struct request *
-cfq_former_request(request_queue_t *q, struct request *rq)
-{
- struct cfq_rq *crq = RQ_DATA(rq);
- struct rb_node *rbprev = rb_prev(&crq->rb_node);
-
- if (rbprev)
- return rb_entry_crq(rbprev)->request;
-
- return NULL;
-}
-
-static struct request *
-cfq_latter_request(request_queue_t *q, struct request *rq)
-{
- struct cfq_rq *crq = RQ_DATA(rq);
- struct rb_node *rbnext = rb_next(&crq->rb_node);
-
- if (rbnext)
- return rb_entry_crq(rbnext)->request;
-
- return NULL;
-}
-
/*
* we temporarily boost lower priority queues if they are holding fs exclusive
* resources. they are boosted to normal prio (CLASS_BE/4)
@@ -1933,9 +1731,7 @@ static void cfq_prio_boost(struct cfq_queue *cfqq)
cfq_resort_rr_list(cfqq, 0);
}
-static inline int
-__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
- struct task_struct *task, int rw)
+static inline int __cfq_may_queue(struct cfq_queue *cfqq)
{
if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
!cfq_cfqq_must_alloc_slice(cfqq)) {
@@ -1946,7 +1742,7 @@ __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
return ELV_MQUEUE_MAY;
}
-static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
+static int cfq_may_queue(request_queue_t *q, int rw)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
@@ -1963,48 +1759,30 @@ static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
cfq_init_prio_data(cfqq);
cfq_prio_boost(cfqq);
- return __cfq_may_queue(cfqd, cfqq, tsk, rw);
+ return __cfq_may_queue(cfqq);
}
return ELV_MQUEUE_MAY;
}
-static void cfq_check_waiters(request_queue_t *q, struct cfq_queue *cfqq)
-{
- struct cfq_data *cfqd = q->elevator->elevator_data;
-
- if (unlikely(cfqd->rq_starved)) {
- struct request_list *rl = &q->rq;
-
- smp_mb();
- if (waitqueue_active(&rl->wait[READ]))
- wake_up(&rl->wait[READ]);
- if (waitqueue_active(&rl->wait[WRITE]))
- wake_up(&rl->wait[WRITE]);
- }
-}
-
/*
* queue lock held here
*/
static void cfq_put_request(request_queue_t *q, struct request *rq)
{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_rq *crq = RQ_DATA(rq);
+ struct cfq_queue *cfqq = RQ_CFQQ(rq);
- if (crq) {
- struct cfq_queue *cfqq = crq->cfq_queue;
+ if (cfqq) {
const int rw = rq_data_dir(rq);
BUG_ON(!cfqq->allocated[rw]);
cfqq->allocated[rw]--;
- put_io_context(crq->io_context->ioc);
+ put_io_context(RQ_CIC(rq)->ioc);
- mempool_free(crq, cfqd->crq_pool);
rq->elevator_private = NULL;
+ rq->elevator_private2 = NULL;
- cfq_check_waiters(q, cfqq);
cfq_put_queue(cfqq);
}
}
@@ -2013,8 +1791,7 @@ static void cfq_put_request(request_queue_t *q, struct request *rq)
* Allocate cfq data structures associated with this request.
*/
static int
-cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
- gfp_t gfp_mask)
+cfq_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
struct task_struct *tsk = current;
@@ -2022,7 +1799,6 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
const int rw = rq_data_dir(rq);
pid_t key = cfq_queue_pid(tsk, rw);
struct cfq_queue *cfqq;
- struct cfq_rq *crq;
unsigned long flags;
int is_sync = key != CFQ_KEY_ASYNC;
@@ -2046,42 +1822,18 @@ cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
cfqq->allocated[rw]++;
cfq_clear_cfqq_must_alloc(cfqq);
- cfqd->rq_starved = 0;
atomic_inc(&cfqq->ref);
- spin_unlock_irqrestore(q->queue_lock, flags);
- crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
- if (crq) {
- RB_CLEAR_NODE(&crq->rb_node);
- crq->rb_key = 0;
- crq->request = rq;
- INIT_HLIST_NODE(&crq->hash);
- crq->cfq_queue = cfqq;
- crq->io_context = cic;
-
- if (is_sync)
- cfq_mark_crq_is_sync(crq);
- else
- cfq_clear_crq_is_sync(crq);
+ spin_unlock_irqrestore(q->queue_lock, flags);
- rq->elevator_private = crq;
- return 0;
- }
+ rq->elevator_private = cic;
+ rq->elevator_private2 = cfqq;
+ return 0;
- spin_lock_irqsave(q->queue_lock, flags);
- cfqq->allocated[rw]--;
- if (!(cfqq->allocated[0] + cfqq->allocated[1]))
- cfq_mark_cfqq_must_alloc(cfqq);
- cfq_put_queue(cfqq);
queue_fail:
if (cic)
put_io_context(cic->ioc);
- /*
- * mark us rq allocation starved. we need to kickstart the process
- * ourselves if there are no pending requests that can do it for us.
- * that would be an extremely rare OOM situation
- */
- cfqd->rq_starved = 1;
+
cfq_schedule_dispatch(cfqd);
spin_unlock_irqrestore(q->queue_lock, flags);
return 1;
@@ -2090,27 +1842,10 @@ queue_fail:
static void cfq_kick_queue(void *data)
{
request_queue_t *q = data;
- struct cfq_data *cfqd = q->elevator->elevator_data;
unsigned long flags;
spin_lock_irqsave(q->queue_lock, flags);
-
- if (cfqd->rq_starved) {
- struct request_list *rl = &q->rq;
-
- /*
- * we aren't guaranteed to get a request after this, but we
- * have to be opportunistic
- */
- smp_mb();
- if (waitqueue_active(&rl->wait[READ]))
- wake_up(&rl->wait[READ]);
- if (waitqueue_active(&rl->wait[WRITE]))
- wake_up(&rl->wait[WRITE]);
- }
-
- blk_remove_plug(q);
- q->request_fn(q);
+ blk_start_queueing(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
@@ -2193,7 +1928,6 @@ static void cfq_exit_queue(elevator_t *e)
cfq_shutdown_timer_wq(cfqd);
- spin_lock(&cfq_exit_lock);
spin_lock_irq(q->queue_lock);
if (cfqd->active_queue)
@@ -2203,25 +1937,14 @@ static void cfq_exit_queue(elevator_t *e)
struct cfq_io_context *cic = list_entry(cfqd->cic_list.next,
struct cfq_io_context,
queue_list);
- if (cic->cfqq[ASYNC]) {
- cfq_put_queue(cic->cfqq[ASYNC]);
- cic->cfqq[ASYNC] = NULL;
- }
- if (cic->cfqq[SYNC]) {
- cfq_put_queue(cic->cfqq[SYNC]);
- cic->cfqq[SYNC] = NULL;
- }
- cic->key = NULL;
- list_del_init(&cic->queue_list);
+
+ __cfq_exit_single_io_context(cfqd, cic);
}
spin_unlock_irq(q->queue_lock);
- spin_unlock(&cfq_exit_lock);
cfq_shutdown_timer_wq(cfqd);
- mempool_destroy(cfqd->crq_pool);
- kfree(cfqd->crq_hash);
kfree(cfqd->cfq_hash);
kfree(cfqd);
}
@@ -2231,7 +1954,7 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
struct cfq_data *cfqd;
int i;
- cfqd = kmalloc(sizeof(*cfqd), GFP_KERNEL);
+ cfqd = kmalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node);
if (!cfqd)
return NULL;
@@ -2243,23 +1966,12 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
INIT_LIST_HEAD(&cfqd->busy_rr);
INIT_LIST_HEAD(&cfqd->cur_rr);
INIT_LIST_HEAD(&cfqd->idle_rr);
- INIT_LIST_HEAD(&cfqd->empty_list);
INIT_LIST_HEAD(&cfqd->cic_list);
- cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
- if (!cfqd->crq_hash)
- goto out_crqhash;
-
- cfqd->cfq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL);
+ cfqd->cfq_hash = kmalloc_node(sizeof(struct hlist_head) * CFQ_QHASH_ENTRIES, GFP_KERNEL, q->node);
if (!cfqd->cfq_hash)
- goto out_cfqhash;
-
- cfqd->crq_pool = mempool_create_slab_pool(BLKDEV_MIN_RQ, crq_pool);
- if (!cfqd->crq_pool)
- goto out_crqpool;
+ goto out_free;
- for (i = 0; i < CFQ_MHASH_ENTRIES; i++)
- INIT_HLIST_HEAD(&cfqd->crq_hash[i]);
for (i = 0; i < CFQ_QHASH_ENTRIES; i++)
INIT_HLIST_HEAD(&cfqd->cfq_hash[i]);
@@ -2275,7 +1987,6 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q);
- cfqd->cfq_queued = cfq_queued;
cfqd->cfq_quantum = cfq_quantum;
cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
@@ -2287,19 +1998,13 @@ static void *cfq_init_queue(request_queue_t *q, elevator_t *e)
cfqd->cfq_slice_idle = cfq_slice_idle;
return cfqd;
-out_crqpool:
- kfree(cfqd->cfq_hash);
-out_cfqhash:
- kfree(cfqd->crq_hash);
-out_crqhash:
+out_free:
kfree(cfqd);
return NULL;
}
static void cfq_slab_kill(void)
{
- if (crq_pool)
- kmem_cache_destroy(crq_pool);
if (cfq_pool)
kmem_cache_destroy(cfq_pool);
if (cfq_ioc_pool)
@@ -2308,11 +2013,6 @@ static void cfq_slab_kill(void)
static int __init cfq_slab_setup(void)
{
- crq_pool = kmem_cache_create("crq_pool", sizeof(struct cfq_rq), 0, 0,
- NULL, NULL);
- if (!crq_pool)
- goto fail;
-
cfq_pool = kmem_cache_create("cfq_pool", sizeof(struct cfq_queue), 0, 0,
NULL, NULL);
if (!cfq_pool)
@@ -2358,7 +2058,6 @@ static ssize_t __FUNC(elevator_t *e, char *page) \
return cfq_var_show(__data, (page)); \
}
SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0);
-SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 0);
SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1);
SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1);
SHOW_FUNCTION(cfq_back_seek_max_show, cfqd->cfq_back_max, 0);
@@ -2386,7 +2085,6 @@ static ssize_t __FUNC(elevator_t *e, const char *page, size_t count) \
return ret; \
}
STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0);
-STORE_FUNCTION(cfq_queued_store, &cfqd->cfq_queued, 1, UINT_MAX, 0);
STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1);
STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1);
STORE_FUNCTION(cfq_back_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
@@ -2402,7 +2100,6 @@ STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX,
static struct elv_fs_entry cfq_attrs[] = {
CFQ_ATTR(quantum),
- CFQ_ATTR(queued),
CFQ_ATTR(fifo_expire_sync),
CFQ_ATTR(fifo_expire_async),
CFQ_ATTR(back_seek_max),
@@ -2425,14 +2122,14 @@ static struct elevator_type iosched_cfq = {
.elevator_deactivate_req_fn = cfq_deactivate_request,
.elevator_queue_empty_fn = cfq_queue_empty,
.elevator_completed_req_fn = cfq_completed_request,
- .elevator_former_req_fn = cfq_former_request,
- .elevator_latter_req_fn = cfq_latter_request,
+ .elevator_former_req_fn = elv_rb_former_request,
+ .elevator_latter_req_fn = elv_rb_latter_request,
.elevator_set_req_fn = cfq_set_request,
.elevator_put_req_fn = cfq_put_request,
.elevator_may_queue_fn = cfq_may_queue,
.elevator_init_fn = cfq_init_queue,
.elevator_exit_fn = cfq_exit_queue,
- .trim = cfq_trim,
+ .trim = cfq_free_io_context,
},
.elevator_attrs = cfq_attrs,
.elevator_name = "cfq",
@@ -2463,12 +2160,12 @@ static int __init cfq_init(void)
static void __exit cfq_exit(void)
{
- DECLARE_COMPLETION(all_gone);
+ DECLARE_COMPLETION_ONSTACK(all_gone);
elv_unregister(&iosched_cfq);
ioc_gone = &all_gone;
/* ioc_gone's update must be visible before reading ioc_count */
smp_wmb();
- if (atomic_read(&ioc_count))
+ if (elv_ioc_count_read(ioc_count))
wait_for_completion(ioc_gone);
synchronize_rcu();
cfq_slab_kill();
diff --git a/block/deadline-iosched.c b/block/deadline-iosched.c
index c7ca9f0b6498..b7c5b34cb7b4 100644
--- a/block/deadline-iosched.c
+++ b/block/deadline-iosched.c
@@ -1,7 +1,7 @@
/*
* Deadline i/o scheduler.
*
- * Copyright (C) 2002 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2002 Jens Axboe <axboe@kernel.dk>
*/
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -12,7 +12,6 @@
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/compiler.h>
-#include <linux/hash.h>
#include <linux/rbtree.h>
/*
@@ -24,13 +23,6 @@ static const int writes_starved = 2; /* max times reads can starve a write */
static const int fifo_batch = 16; /* # of sequential requests treated as one
by the above parameters. For throughput. */
-static const int deadline_hash_shift = 5;
-#define DL_HASH_BLOCK(sec) ((sec) >> 3)
-#define DL_HASH_FN(sec) (hash_long(DL_HASH_BLOCK((sec)), deadline_hash_shift))
-#define DL_HASH_ENTRIES (1 << deadline_hash_shift)
-#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
-#define ON_HASH(drq) (!hlist_unhashed(&(drq)->hash))
-
struct deadline_data {
/*
* run time data
@@ -45,8 +37,7 @@ struct deadline_data {
/*
* next in sort order. read, write or both are NULL
*/
- struct deadline_rq *next_drq[2];
- struct hlist_head *hash; /* request hash */
+ struct request *next_rq[2];
unsigned int batching; /* number of sequential requests made */
sector_t last_sector; /* head position */
unsigned int starved; /* times reads have starved writes */
@@ -58,240 +49,69 @@ struct deadline_data {
int fifo_batch;
int writes_starved;
int front_merges;
-
- mempool_t *drq_pool;
};
-/*
- * pre-request data.
- */
-struct deadline_rq {
- /*
- * rbtree index, key is the starting offset
- */
- struct rb_node rb_node;
- sector_t rb_key;
-
- struct request *request;
-
- /*
- * request hash, key is the ending offset (for back merge lookup)
- */
- struct hlist_node hash;
-
- /*
- * expire fifo
- */
- struct list_head fifo;
- unsigned long expires;
-};
-
-static void deadline_move_request(struct deadline_data *dd, struct deadline_rq *drq);
-
-static kmem_cache_t *drq_pool;
-
-#define RQ_DATA(rq) ((struct deadline_rq *) (rq)->elevator_private)
+static void deadline_move_request(struct deadline_data *, struct request *);
-/*
- * the back merge hash support functions
- */
-static inline void __deadline_del_drq_hash(struct deadline_rq *drq)
-{
- hlist_del_init(&drq->hash);
-}
-
-static inline void deadline_del_drq_hash(struct deadline_rq *drq)
-{
- if (ON_HASH(drq))
- __deadline_del_drq_hash(drq);
-}
-
-static inline void
-deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
-{
- struct request *rq = drq->request;
-
- BUG_ON(ON_HASH(drq));
-
- hlist_add_head(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]);
-}
-
-/*
- * move hot entry to front of chain
- */
-static inline void
-deadline_hot_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
-{
- struct request *rq = drq->request;
- struct hlist_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))];
-
- if (ON_HASH(drq) && &drq->hash != head->first) {
- hlist_del(&drq->hash);
- hlist_add_head(&drq->hash, head);
- }
-}
-
-static struct request *
-deadline_find_drq_hash(struct deadline_data *dd, sector_t offset)
-{
- struct hlist_head *hash_list = &dd->hash[DL_HASH_FN(offset)];
- struct hlist_node *entry, *next;
- struct deadline_rq *drq;
-
- hlist_for_each_entry_safe(drq, entry, next, hash_list, hash) {
- struct request *__rq = drq->request;
-
- BUG_ON(!ON_HASH(drq));
-
- if (!rq_mergeable(__rq)) {
- __deadline_del_drq_hash(drq);
- continue;
- }
-
- if (rq_hash_key(__rq) == offset)
- return __rq;
- }
-
- return NULL;
-}
-
-/*
- * rb tree support functions
- */
-#define rb_entry_drq(node) rb_entry((node), struct deadline_rq, rb_node)
-#define DRQ_RB_ROOT(dd, drq) (&(dd)->sort_list[rq_data_dir((drq)->request)])
-#define rq_rb_key(rq) (rq)->sector
-
-static struct deadline_rq *
-__deadline_add_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
-{
- struct rb_node **p = &DRQ_RB_ROOT(dd, drq)->rb_node;
- struct rb_node *parent = NULL;
- struct deadline_rq *__drq;
-
- while (*p) {
- parent = *p;
- __drq = rb_entry_drq(parent);
-
- if (drq->rb_key < __drq->rb_key)
- p = &(*p)->rb_left;
- else if (drq->rb_key > __drq->rb_key)
- p = &(*p)->rb_right;
- else
- return __drq;
- }
-
- rb_link_node(&drq->rb_node, parent, p);
- return NULL;
-}
+#define RQ_RB_ROOT(dd, rq) (&(dd)->sort_list[rq_data_dir((rq))])
static void
-deadline_add_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
+deadline_add_rq_rb(struct deadline_data *dd, struct request *rq)
{
- struct deadline_rq *__alias;
-
- drq->rb_key = rq_rb_key(drq->request);
+ struct rb_root *root = RQ_RB_ROOT(dd, rq);
+ struct request *__alias;
retry:
- __alias = __deadline_add_drq_rb(dd, drq);
- if (!__alias) {
- rb_insert_color(&drq->rb_node, DRQ_RB_ROOT(dd, drq));
- return;
+ __alias = elv_rb_add(root, rq);
+ if (unlikely(__alias)) {
+ deadline_move_request(dd, __alias);
+ goto retry;
}
-
- deadline_move_request(dd, __alias);
- goto retry;
}
static inline void
-deadline_del_drq_rb(struct deadline_data *dd, struct deadline_rq *drq)
+deadline_del_rq_rb(struct deadline_data *dd, struct request *rq)
{
- const int data_dir = rq_data_dir(drq->request);
+ const int data_dir = rq_data_dir(rq);
- if (dd->next_drq[data_dir] == drq) {
- struct rb_node *rbnext = rb_next(&drq->rb_node);
+ if (dd->next_rq[data_dir] == rq) {
+ struct rb_node *rbnext = rb_next(&rq->rb_node);
- dd->next_drq[data_dir] = NULL;
+ dd->next_rq[data_dir] = NULL;
if (rbnext)
- dd->next_drq[data_dir] = rb_entry_drq(rbnext);
- }
-
- BUG_ON(!RB_EMPTY_NODE(&drq->rb_node));
- rb_erase(&drq->rb_node, DRQ_RB_ROOT(dd, drq));
- RB_CLEAR_NODE(&drq->rb_node);
-}
-
-static struct request *
-deadline_find_drq_rb(struct deadline_data *dd, sector_t sector, int data_dir)
-{
- struct rb_node *n = dd->sort_list[data_dir].rb_node;
- struct deadline_rq *drq;
-
- while (n) {
- drq = rb_entry_drq(n);
-
- if (sector < drq->rb_key)
- n = n->rb_left;
- else if (sector > drq->rb_key)
- n = n->rb_right;
- else
- return drq->request;
+ dd->next_rq[data_dir] = rb_entry_rq(rbnext);
}
- return NULL;
+ elv_rb_del(RQ_RB_ROOT(dd, rq), rq);
}
/*
- * deadline_find_first_drq finds the first (lowest sector numbered) request
- * for the specified data_dir. Used to sweep back to the start of the disk
- * (1-way elevator) after we process the last (highest sector) request.
- */
-static struct deadline_rq *
-deadline_find_first_drq(struct deadline_data *dd, int data_dir)
-{
- struct rb_node *n = dd->sort_list[data_dir].rb_node;
-
- for (;;) {
- if (n->rb_left == NULL)
- return rb_entry_drq(n);
-
- n = n->rb_left;
- }
-}
-
-/*
- * add drq to rbtree and fifo
+ * add rq to rbtree and fifo
*/
static void
deadline_add_request(struct request_queue *q, struct request *rq)
{
struct deadline_data *dd = q->elevator->elevator_data;
- struct deadline_rq *drq = RQ_DATA(rq);
+ const int data_dir = rq_data_dir(rq);
- const int data_dir = rq_data_dir(drq->request);
+ deadline_add_rq_rb(dd, rq);
- deadline_add_drq_rb(dd, drq);
/*
* set expire time (only used for reads) and add to fifo list
*/
- drq->expires = jiffies + dd->fifo_expire[data_dir];
- list_add_tail(&drq->fifo, &dd->fifo_list[data_dir]);
-
- if (rq_mergeable(rq))
- deadline_add_drq_hash(dd, drq);
+ rq_set_fifo_time(rq, jiffies + dd->fifo_expire[data_dir]);
+ list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]);
}
/*
- * remove rq from rbtree, fifo, and hash
+ * remove rq from rbtree and fifo.
*/
static void deadline_remove_request(request_queue_t *q, struct request *rq)
{
- struct deadline_rq *drq = RQ_DATA(rq);
struct deadline_data *dd = q->elevator->elevator_data;
- list_del_init(&drq->fifo);
- deadline_del_drq_rb(dd, drq);
- deadline_del_drq_hash(drq);
+ rq_fifo_clear(rq);
+ deadline_del_rq_rb(dd, rq);
}
static int
@@ -302,27 +122,14 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
int ret;
/*
- * see if the merge hash can satisfy a back merge
- */
- __rq = deadline_find_drq_hash(dd, bio->bi_sector);
- if (__rq) {
- BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
-
- if (elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_BACK_MERGE;
- goto out;
- }
- }
-
- /*
* check for front merge
*/
if (dd->front_merges) {
- sector_t rb_key = bio->bi_sector + bio_sectors(bio);
+ sector_t sector = bio->bi_sector + bio_sectors(bio);
- __rq = deadline_find_drq_rb(dd, rb_key, bio_data_dir(bio));
+ __rq = elv_rb_find(&dd->sort_list[bio_data_dir(bio)], sector);
if (__rq) {
- BUG_ON(rb_key != rq_rb_key(__rq));
+ BUG_ON(sector != __rq->sector);
if (elv_rq_merge_ok(__rq, bio)) {
ret = ELEVATOR_FRONT_MERGE;
@@ -333,29 +140,21 @@ deadline_merge(request_queue_t *q, struct request **req, struct bio *bio)
return ELEVATOR_NO_MERGE;
out:
- if (ret)
- deadline_hot_drq_hash(dd, RQ_DATA(__rq));
*req = __rq;
return ret;
}
-static void deadline_merged_request(request_queue_t *q, struct request *req)
+static void deadline_merged_request(request_queue_t *q, struct request *req,
+ int type)
{
struct deadline_data *dd = q->elevator->elevator_data;
- struct deadline_rq *drq = RQ_DATA(req);
-
- /*
- * hash always needs to be repositioned, key is end sector
- */
- deadline_del_drq_hash(drq);
- deadline_add_drq_hash(dd, drq);
/*
* if the merge was a front merge, we need to reposition request
*/
- if (rq_rb_key(req) != drq->rb_key) {
- deadline_del_drq_rb(dd, drq);
- deadline_add_drq_rb(dd, drq);
+ if (type == ELEVATOR_FRONT_MERGE) {
+ elv_rb_del(RQ_RB_ROOT(dd, req), req);
+ deadline_add_rq_rb(dd, req);
}
}
@@ -363,33 +162,14 @@ static void
deadline_merged_requests(request_queue_t *q, struct request *req,
struct request *next)
{
- struct deadline_data *dd = q->elevator->elevator_data;
- struct deadline_rq *drq = RQ_DATA(req);
- struct deadline_rq *dnext = RQ_DATA(next);
-
- BUG_ON(!drq);
- BUG_ON(!dnext);
-
/*
- * reposition drq (this is the merged request) in hash, and in rbtree
- * in case of a front merge
+ * if next expires before rq, assign its expire time to rq
+ * and move into next position (next will be deleted) in fifo
*/
- deadline_del_drq_hash(drq);
- deadline_add_drq_hash(dd, drq);
-
- if (rq_rb_key(req) != drq->rb_key) {
- deadline_del_drq_rb(dd, drq);
- deadline_add_drq_rb(dd, drq);
- }
-
- /*
- * if dnext expires before drq, assign its expire time to drq
- * and move into dnext position (dnext will be deleted) in fifo
- */
- if (!list_empty(&drq->fifo) && !list_empty(&dnext->fifo)) {
- if (time_before(dnext->expires, drq->expires)) {
- list_move(&drq->fifo, &dnext->fifo);
- drq->expires = dnext->expires;
+ if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) {
+ if (time_before(rq_fifo_time(next), rq_fifo_time(req))) {
+ list_move(&req->queuelist, &next->queuelist);
+ rq_set_fifo_time(req, rq_fifo_time(next));
}
}
@@ -403,52 +183,50 @@ deadline_merged_requests(request_queue_t *q, struct request *req,
* move request from sort list to dispatch queue.
*/
static inline void
-deadline_move_to_dispatch(struct deadline_data *dd, struct deadline_rq *drq)
+deadline_move_to_dispatch(struct deadline_data *dd, struct request *rq)
{
- request_queue_t *q = drq->request->q;
+ request_queue_t *q = rq->q;
- deadline_remove_request(q, drq->request);
- elv_dispatch_add_tail(q, drq->request);
+ deadline_remove_request(q, rq);
+ elv_dispatch_add_tail(q, rq);
}
/*
* move an entry to dispatch queue
*/
static void
-deadline_move_request(struct deadline_data *dd, struct deadline_rq *drq)
+deadline_move_request(struct deadline_data *dd, struct request *rq)
{
- const int data_dir = rq_data_dir(drq->request);
- struct rb_node *rbnext = rb_next(&drq->rb_node);
+ const int data_dir = rq_data_dir(rq);
+ struct rb_node *rbnext = rb_next(&rq->rb_node);
- dd->next_drq[READ] = NULL;
- dd->next_drq[WRITE] = NULL;
+ dd->next_rq[READ] = NULL;
+ dd->next_rq[WRITE] = NULL;
if (rbnext)
- dd->next_drq[data_dir] = rb_entry_drq(rbnext);
+ dd->next_rq[data_dir] = rb_entry_rq(rbnext);
- dd->last_sector = drq->request->sector + drq->request->nr_sectors;
+ dd->last_sector = rq->sector + rq->nr_sectors;
/*
* take it off the sort and fifo list, move
* to dispatch queue
*/
- deadline_move_to_dispatch(dd, drq);
+ deadline_move_to_dispatch(dd, rq);
}
-#define list_entry_fifo(ptr) list_entry((ptr), struct deadline_rq, fifo)
-
/*
* deadline_check_fifo returns 0 if there are no expired reads on the fifo,
* 1 otherwise. Requires !list_empty(&dd->fifo_list[data_dir])
*/
static inline int deadline_check_fifo(struct deadline_data *dd, int ddir)
{
- struct deadline_rq *drq = list_entry_fifo(dd->fifo_list[ddir].next);
+ struct request *rq = rq_entry_fifo(dd->fifo_list[ddir].next);
/*
- * drq is expired!
+ * rq is expired!
*/
- if (time_after(jiffies, drq->expires))
+ if (time_after(jiffies, rq_fifo_time(rq)))
return 1;
return 0;
@@ -463,21 +241,21 @@ static int deadline_dispatch_requests(request_queue_t *q, int force)
struct deadline_data *dd = q->elevator->elevator_data;
const int reads = !list_empty(&dd->fifo_list[READ]);
const int writes = !list_empty(&dd->fifo_list[WRITE]);
- struct deadline_rq *drq;
+ struct request *rq;
int data_dir;
/*
* batches are currently reads XOR writes
*/
- if (dd->next_drq[WRITE])
- drq = dd->next_drq[WRITE];
+ if (dd->next_rq[WRITE])
+ rq = dd->next_rq[WRITE];
else
- drq = dd->next_drq[READ];
+ rq = dd->next_rq[READ];
- if (drq) {
+ if (rq) {
/* we have a "next request" */
- if (dd->last_sector != drq->request->sector)
+ if (dd->last_sector != rq->sector)
/* end the batch on a non sequential request */
dd->batching += dd->fifo_batch;
@@ -526,30 +304,33 @@ dispatch_find_request:
if (deadline_check_fifo(dd, data_dir)) {
/* An expired request exists - satisfy it */
dd->batching = 0;
- drq = list_entry_fifo(dd->fifo_list[data_dir].next);
+ rq = rq_entry_fifo(dd->fifo_list[data_dir].next);
- } else if (dd->next_drq[data_dir]) {
+ } else if (dd->next_rq[data_dir]) {
/*
* The last req was the same dir and we have a next request in
* sort order. No expired requests so continue on from here.
*/
- drq = dd->next_drq[data_dir];
+ rq = dd->next_rq[data_dir];
} else {
+ struct rb_node *node;
/*
* The last req was the other direction or we have run out of
* higher-sectored requests. Go back to the lowest sectored
* request (1 way elevator) and start a new batch.
*/
dd->batching = 0;
- drq = deadline_find_first_drq(dd, data_dir);
+ node = rb_first(&dd->sort_list[data_dir]);
+ if (node)
+ rq = rb_entry_rq(node);
}
dispatch_request:
/*
- * drq is the selected appropriate request.
+ * rq is the selected appropriate request.
*/
dd->batching++;
- deadline_move_request(dd, drq);
+ deadline_move_request(dd, rq);
return 1;
}
@@ -562,30 +343,6 @@ static int deadline_queue_empty(request_queue_t *q)
&& list_empty(&dd->fifo_list[READ]);
}
-static struct request *
-deadline_former_request(request_queue_t *q, struct request *rq)
-{
- struct deadline_rq *drq = RQ_DATA(rq);
- struct rb_node *rbprev = rb_prev(&drq->rb_node);
-
- if (rbprev)
- return rb_entry_drq(rbprev)->request;
-
- return NULL;
-}
-
-static struct request *
-deadline_latter_request(request_queue_t *q, struct request *rq)
-{
- struct deadline_rq *drq = RQ_DATA(rq);
- struct rb_node *rbnext = rb_next(&drq->rb_node);
-
- if (rbnext)
- return rb_entry_drq(rbnext)->request;
-
- return NULL;
-}
-
static void deadline_exit_queue(elevator_t *e)
{
struct deadline_data *dd = e->elevator_data;
@@ -593,46 +350,21 @@ static void deadline_exit_queue(elevator_t *e)
BUG_ON(!list_empty(&dd->fifo_list[READ]));
BUG_ON(!list_empty(&dd->fifo_list[WRITE]));
- mempool_destroy(dd->drq_pool);
- kfree(dd->hash);
kfree(dd);
}
/*
- * initialize elevator private data (deadline_data), and alloc a drq for
- * each request on the free lists
+ * initialize elevator private data (deadline_data).
*/
static void *deadline_init_queue(request_queue_t *q, elevator_t *e)
{
struct deadline_data *dd;
- int i;
-
- if (!drq_pool)
- return NULL;
dd = kmalloc_node(sizeof(*dd), GFP_KERNEL, q->node);
if (!dd)
return NULL;
memset(dd, 0, sizeof(*dd));
- dd->hash = kmalloc_node(sizeof(struct hlist_head)*DL_HASH_ENTRIES,
- GFP_KERNEL, q->node);
- if (!dd->hash) {
- kfree(dd);
- return NULL;
- }
-
- dd->drq_pool = mempool_create_node(BLKDEV_MIN_RQ, mempool_alloc_slab,
- mempool_free_slab, drq_pool, q->node);
- if (!dd->drq_pool) {
- kfree(dd->hash);
- kfree(dd);
- return NULL;
- }
-
- for (i = 0; i < DL_HASH_ENTRIES; i++)
- INIT_HLIST_HEAD(&dd->hash[i]);
-
INIT_LIST_HEAD(&dd->fifo_list[READ]);
INIT_LIST_HEAD(&dd->fifo_list[WRITE]);
dd->sort_list[READ] = RB_ROOT;
@@ -645,39 +377,6 @@ static void *deadline_init_queue(request_queue_t *q, elevator_t *e)
return dd;
}
-static void deadline_put_request(request_queue_t *q, struct request *rq)
-{
- struct deadline_data *dd = q->elevator->elevator_data;
- struct deadline_rq *drq = RQ_DATA(rq);
-
- mempool_free(drq, dd->drq_pool);
- rq->elevator_private = NULL;
-}
-
-static int
-deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
- gfp_t gfp_mask)
-{
- struct deadline_data *dd = q->elevator->elevator_data;
- struct deadline_rq *drq;
-
- drq = mempool_alloc(dd->drq_pool, gfp_mask);
- if (drq) {
- memset(drq, 0, sizeof(*drq));
- RB_CLEAR_NODE(&drq->rb_node);
- drq->request = rq;
-
- INIT_HLIST_NODE(&drq->hash);
-
- INIT_LIST_HEAD(&drq->fifo);
-
- rq->elevator_private = drq;
- return 0;
- }
-
- return 1;
-}
-
/*
* sysfs parts below
*/
@@ -757,10 +456,8 @@ static struct elevator_type iosched_deadline = {
.elevator_dispatch_fn = deadline_dispatch_requests,
.elevator_add_req_fn = deadline_add_request,
.elevator_queue_empty_fn = deadline_queue_empty,
- .elevator_former_req_fn = deadline_former_request,
- .elevator_latter_req_fn = deadline_latter_request,
- .elevator_set_req_fn = deadline_set_request,
- .elevator_put_req_fn = deadline_put_request,
+ .elevator_former_req_fn = elv_rb_former_request,
+ .elevator_latter_req_fn = elv_rb_latter_request,
.elevator_init_fn = deadline_init_queue,
.elevator_exit_fn = deadline_exit_queue,
},
@@ -772,24 +469,11 @@ static struct elevator_type iosched_deadline = {
static int __init deadline_init(void)
{
- int ret;
-
- drq_pool = kmem_cache_create("deadline_drq", sizeof(struct deadline_rq),
- 0, 0, NULL, NULL);
-
- if (!drq_pool)
- return -ENOMEM;
-
- ret = elv_register(&iosched_deadline);
- if (ret)
- kmem_cache_destroy(drq_pool);
-
- return ret;
+ return elv_register(&iosched_deadline);
}
static void __exit deadline_exit(void)
{
- kmem_cache_destroy(drq_pool);
elv_unregister(&iosched_deadline);
}
diff --git a/block/elevator.c b/block/elevator.c
index 9b72dc7c8a5c..8ccd163254b8 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
*
- * 30042000 Jens Axboe <axboe@suse.de> :
+ * 30042000 Jens Axboe <axboe@kernel.dk> :
*
* Split the elevator a bit so that it is possible to choose a different
* one or even write a new "plug in". There are three pieces:
@@ -33,6 +33,7 @@
#include <linux/compiler.h>
#include <linux/delay.h>
#include <linux/blktrace_api.h>
+#include <linux/hash.h>
#include <asm/uaccess.h>
@@ -40,6 +41,16 @@ static DEFINE_SPINLOCK(elv_list_lock);
static LIST_HEAD(elv_list);
/*
+ * Merge hash stuff.
+ */
+static const int elv_hash_shift = 6;
+#define ELV_HASH_BLOCK(sec) ((sec) >> 3)
+#define ELV_HASH_FN(sec) (hash_long(ELV_HASH_BLOCK((sec)), elv_hash_shift))
+#define ELV_HASH_ENTRIES (1 << elv_hash_shift)
+#define rq_hash_key(rq) ((rq)->sector + (rq)->nr_sectors)
+#define ELV_ON_HASH(rq) (!hlist_unhashed(&(rq)->hash))
+
+/*
* can we safely merge with this request?
*/
inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
@@ -56,8 +67,7 @@ inline int elv_rq_merge_ok(struct request *rq, struct bio *bio)
/*
* same device and no special stuff set, merge is ok
*/
- if (rq->rq_disk == bio->bi_bdev->bd_disk &&
- !rq->waiting && !rq->special)
+ if (rq->rq_disk == bio->bi_bdev->bd_disk && !rq->special)
return 1;
return 0;
@@ -83,21 +93,18 @@ static inline int elv_try_merge(struct request *__rq, struct bio *bio)
static struct elevator_type *elevator_find(const char *name)
{
- struct elevator_type *e = NULL;
+ struct elevator_type *e;
struct list_head *entry;
list_for_each(entry, &elv_list) {
- struct elevator_type *__e;
- __e = list_entry(entry, struct elevator_type, list);
+ e = list_entry(entry, struct elevator_type, list);
- if (!strcmp(__e->elevator_name, name)) {
- e = __e;
- break;
- }
+ if (!strcmp(e->elevator_name, name))
+ return e;
}
- return e;
+ return NULL;
}
static void elevator_put(struct elevator_type *e)
@@ -151,27 +158,44 @@ __setup("elevator=", elevator_setup);
static struct kobj_type elv_ktype;
-static elevator_t *elevator_alloc(struct elevator_type *e)
-{
- elevator_t *eq = kmalloc(sizeof(elevator_t), GFP_KERNEL);
- if (eq) {
- memset(eq, 0, sizeof(*eq));
- eq->ops = &e->ops;
- eq->elevator_type = e;
- kobject_init(&eq->kobj);
- snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
- eq->kobj.ktype = &elv_ktype;
- mutex_init(&eq->sysfs_lock);
- } else {
- elevator_put(e);
- }
+static elevator_t *elevator_alloc(request_queue_t *q, struct elevator_type *e)
+{
+ elevator_t *eq;
+ int i;
+
+ eq = kmalloc_node(sizeof(elevator_t), GFP_KERNEL, q->node);
+ if (unlikely(!eq))
+ goto err;
+
+ memset(eq, 0, sizeof(*eq));
+ eq->ops = &e->ops;
+ eq->elevator_type = e;
+ kobject_init(&eq->kobj);
+ snprintf(eq->kobj.name, KOBJ_NAME_LEN, "%s", "iosched");
+ eq->kobj.ktype = &elv_ktype;
+ mutex_init(&eq->sysfs_lock);
+
+ eq->hash = kmalloc_node(sizeof(struct hlist_head) * ELV_HASH_ENTRIES,
+ GFP_KERNEL, q->node);
+ if (!eq->hash)
+ goto err;
+
+ for (i = 0; i < ELV_HASH_ENTRIES; i++)
+ INIT_HLIST_HEAD(&eq->hash[i]);
+
return eq;
+err:
+ kfree(eq);
+ elevator_put(e);
+ return NULL;
}
static void elevator_release(struct kobject *kobj)
{
elevator_t *e = container_of(kobj, elevator_t, kobj);
+
elevator_put(e->elevator_type);
+ kfree(e->hash);
kfree(e);
}
@@ -198,7 +222,7 @@ int elevator_init(request_queue_t *q, char *name)
e = elevator_get("noop");
}
- eq = elevator_alloc(e);
+ eq = elevator_alloc(q, e);
if (!eq)
return -ENOMEM;
@@ -212,6 +236,8 @@ int elevator_init(request_queue_t *q, char *name)
return ret;
}
+EXPORT_SYMBOL(elevator_init);
+
void elevator_exit(elevator_t *e)
{
mutex_lock(&e->sysfs_lock);
@@ -223,10 +249,118 @@ void elevator_exit(elevator_t *e)
kobject_put(&e->kobj);
}
+EXPORT_SYMBOL(elevator_exit);
+
+static inline void __elv_rqhash_del(struct request *rq)
+{
+ hlist_del_init(&rq->hash);
+}
+
+static void elv_rqhash_del(request_queue_t *q, struct request *rq)
+{
+ if (ELV_ON_HASH(rq))
+ __elv_rqhash_del(rq);
+}
+
+static void elv_rqhash_add(request_queue_t *q, struct request *rq)
+{
+ elevator_t *e = q->elevator;
+
+ BUG_ON(ELV_ON_HASH(rq));
+ hlist_add_head(&rq->hash, &e->hash[ELV_HASH_FN(rq_hash_key(rq))]);
+}
+
+static void elv_rqhash_reposition(request_queue_t *q, struct request *rq)
+{
+ __elv_rqhash_del(rq);
+ elv_rqhash_add(q, rq);
+}
+
+static struct request *elv_rqhash_find(request_queue_t *q, sector_t offset)
+{
+ elevator_t *e = q->elevator;
+ struct hlist_head *hash_list = &e->hash[ELV_HASH_FN(offset)];
+ struct hlist_node *entry, *next;
+ struct request *rq;
+
+ hlist_for_each_entry_safe(rq, entry, next, hash_list, hash) {
+ BUG_ON(!ELV_ON_HASH(rq));
+
+ if (unlikely(!rq_mergeable(rq))) {
+ __elv_rqhash_del(rq);
+ continue;
+ }
+
+ if (rq_hash_key(rq) == offset)
+ return rq;
+ }
+
+ return NULL;
+}
+
+/*
+ * RB-tree support functions for inserting/lookup/removal of requests
+ * in a sorted RB tree.
+ */
+struct request *elv_rb_add(struct rb_root *root, struct request *rq)
+{
+ struct rb_node **p = &root->rb_node;
+ struct rb_node *parent = NULL;
+ struct request *__rq;
+
+ while (*p) {
+ parent = *p;
+ __rq = rb_entry(parent, struct request, rb_node);
+
+ if (rq->sector < __rq->sector)
+ p = &(*p)->rb_left;
+ else if (rq->sector > __rq->sector)
+ p = &(*p)->rb_right;
+ else
+ return __rq;
+ }
+
+ rb_link_node(&rq->rb_node, parent, p);
+ rb_insert_color(&rq->rb_node, root);
+ return NULL;
+}
+
+EXPORT_SYMBOL(elv_rb_add);
+
+void elv_rb_del(struct rb_root *root, struct request *rq)
+{
+ BUG_ON(RB_EMPTY_NODE(&rq->rb_node));
+ rb_erase(&rq->rb_node, root);
+ RB_CLEAR_NODE(&rq->rb_node);
+}
+
+EXPORT_SYMBOL(elv_rb_del);
+
+struct request *elv_rb_find(struct rb_root *root, sector_t sector)
+{
+ struct rb_node *n = root->rb_node;
+ struct request *rq;
+
+ while (n) {
+ rq = rb_entry(n, struct request, rb_node);
+
+ if (sector < rq->sector)
+ n = n->rb_left;
+ else if (sector > rq->sector)
+ n = n->rb_right;
+ else
+ return rq;
+ }
+
+ return NULL;
+}
+
+EXPORT_SYMBOL(elv_rb_find);
+
/*
* Insert rq into dispatch queue of q. Queue lock must be held on
- * entry. If sort != 0, rq is sort-inserted; otherwise, rq will be
- * appended to the dispatch queue. To be used by specific elevators.
+ * entry. rq is sort insted into the dispatch queue. To be used by
+ * specific elevators.
*/
void elv_dispatch_sort(request_queue_t *q, struct request *rq)
{
@@ -235,6 +369,9 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq)
if (q->last_merge == rq)
q->last_merge = NULL;
+
+ elv_rqhash_del(q, rq);
+
q->nr_sorted--;
boundary = q->end_sector;
@@ -242,7 +379,7 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq)
list_for_each_prev(entry, &q->queue_head) {
struct request *pos = list_entry_rq(entry);
- if (pos->flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
+ if (pos->cmd_flags & (REQ_SOFTBARRIER|REQ_HARDBARRIER|REQ_STARTED))
break;
if (rq->sector >= boundary) {
if (pos->sector < boundary)
@@ -258,11 +395,38 @@ void elv_dispatch_sort(request_queue_t *q, struct request *rq)
list_add(&rq->queuelist, entry);
}
+EXPORT_SYMBOL(elv_dispatch_sort);
+
+/*
+ * Insert rq into dispatch queue of q. Queue lock must be held on
+ * entry. rq is added to the back of the dispatch queue. To be used by
+ * specific elevators.
+ */
+void elv_dispatch_add_tail(struct request_queue *q, struct request *rq)
+{
+ if (q->last_merge == rq)
+ q->last_merge = NULL;
+
+ elv_rqhash_del(q, rq);
+
+ q->nr_sorted--;
+
+ q->end_sector = rq_end_sector(rq);
+ q->boundary_rq = rq;
+ list_add_tail(&rq->queuelist, &q->queue_head);
+}
+
+EXPORT_SYMBOL(elv_dispatch_add_tail);
+
int elv_merge(request_queue_t *q, struct request **req, struct bio *bio)
{
elevator_t *e = q->elevator;
+ struct request *__rq;
int ret;
+ /*
+ * First try one-hit cache.
+ */
if (q->last_merge) {
ret = elv_try_merge(q->last_merge, bio);
if (ret != ELEVATOR_NO_MERGE) {
@@ -271,18 +435,30 @@ int elv_merge(request_queue_t *q, struct request **req, struct bio *bio)
}
}
+ /*
+ * See if our hash lookup can find a potential backmerge.
+ */
+ __rq = elv_rqhash_find(q, bio->bi_sector);
+ if (__rq && elv_rq_merge_ok(__rq, bio)) {
+ *req = __rq;
+ return ELEVATOR_BACK_MERGE;
+ }
+
if (e->ops->elevator_merge_fn)
return e->ops->elevator_merge_fn(q, req, bio);
return ELEVATOR_NO_MERGE;
}
-void elv_merged_request(request_queue_t *q, struct request *rq)
+void elv_merged_request(request_queue_t *q, struct request *rq, int type)
{
elevator_t *e = q->elevator;
if (e->ops->elevator_merged_fn)
- e->ops->elevator_merged_fn(q, rq);
+ e->ops->elevator_merged_fn(q, rq, type);
+
+ if (type == ELEVATOR_BACK_MERGE)
+ elv_rqhash_reposition(q, rq);
q->last_merge = rq;
}
@@ -294,8 +470,11 @@ void elv_merge_requests(request_queue_t *q, struct request *rq,
if (e->ops->elevator_merge_req_fn)
e->ops->elevator_merge_req_fn(q, rq, next);
- q->nr_sorted--;
+ elv_rqhash_reposition(q, rq);
+ elv_rqhash_del(q, next);
+
+ q->nr_sorted--;
q->last_merge = rq;
}
@@ -313,7 +492,7 @@ void elv_requeue_request(request_queue_t *q, struct request *rq)
e->ops->elevator_deactivate_req_fn(q, rq);
}
- rq->flags &= ~REQ_STARTED;
+ rq->cmd_flags &= ~REQ_STARTED;
elv_insert(q, rq, ELEVATOR_INSERT_REQUEUE);
}
@@ -344,13 +523,13 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
switch (where) {
case ELEVATOR_INSERT_FRONT:
- rq->flags |= REQ_SOFTBARRIER;
+ rq->cmd_flags |= REQ_SOFTBARRIER;
list_add(&rq->queuelist, &q->queue_head);
break;
case ELEVATOR_INSERT_BACK:
- rq->flags |= REQ_SOFTBARRIER;
+ rq->cmd_flags |= REQ_SOFTBARRIER;
elv_drain_elevator(q);
list_add_tail(&rq->queuelist, &q->queue_head);
/*
@@ -369,10 +548,14 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
case ELEVATOR_INSERT_SORT:
BUG_ON(!blk_fs_request(rq));
- rq->flags |= REQ_SORTED;
+ rq->cmd_flags |= REQ_SORTED;
q->nr_sorted++;
- if (q->last_merge == NULL && rq_mergeable(rq))
- q->last_merge = rq;
+ if (rq_mergeable(rq)) {
+ elv_rqhash_add(q, rq);
+ if (!q->last_merge)
+ q->last_merge = rq;
+ }
+
/*
* Some ioscheds (cfq) run q->request_fn directly, so
* rq cannot be accessed after calling
@@ -387,7 +570,7 @@ void elv_insert(request_queue_t *q, struct request *rq, int where)
* insertion; otherwise, requests should be requeued
* in ordseq order.
*/
- rq->flags |= REQ_SOFTBARRIER;
+ rq->cmd_flags |= REQ_SOFTBARRIER;
if (q->ordseq == 0) {
list_add(&rq->queuelist, &q->queue_head);
@@ -429,9 +612,9 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
int plug)
{
if (q->ordcolor)
- rq->flags |= REQ_ORDERED_COLOR;
+ rq->cmd_flags |= REQ_ORDERED_COLOR;
- if (rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
+ if (rq->cmd_flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER)) {
/*
* toggle ordered color
*/
@@ -452,7 +635,7 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
q->end_sector = rq_end_sector(rq);
q->boundary_rq = rq;
}
- } else if (!(rq->flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT)
+ } else if (!(rq->cmd_flags & REQ_ELVPRIV) && where == ELEVATOR_INSERT_SORT)
where = ELEVATOR_INSERT_BACK;
if (plug)
@@ -461,6 +644,8 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
elv_insert(q, rq, where);
}
+EXPORT_SYMBOL(__elv_add_request);
+
void elv_add_request(request_queue_t *q, struct request *rq, int where,
int plug)
{
@@ -471,6 +656,8 @@ void elv_add_request(request_queue_t *q, struct request *rq, int where,
spin_unlock_irqrestore(q->queue_lock, flags);
}
+EXPORT_SYMBOL(elv_add_request);
+
static inline struct request *__elv_next_request(request_queue_t *q)
{
struct request *rq;
@@ -493,7 +680,7 @@ struct request *elv_next_request(request_queue_t *q)
int ret;
while ((rq = __elv_next_request(q)) != NULL) {
- if (!(rq->flags & REQ_STARTED)) {
+ if (!(rq->cmd_flags & REQ_STARTED)) {
elevator_t *e = q->elevator;
/*
@@ -510,7 +697,7 @@ struct request *elv_next_request(request_queue_t *q)
* it, a request that has been delayed should
* not be passed by new incoming requests
*/
- rq->flags |= REQ_STARTED;
+ rq->cmd_flags |= REQ_STARTED;
blk_add_trace_rq(q, rq, BLK_TA_ISSUE);
}
@@ -519,7 +706,7 @@ struct request *elv_next_request(request_queue_t *q)
q->boundary_rq = NULL;
}
- if ((rq->flags & REQ_DONTPREP) || !q->prep_rq_fn)
+ if ((rq->cmd_flags & REQ_DONTPREP) || !q->prep_rq_fn)
break;
ret = q->prep_rq_fn(q, rq);
@@ -541,7 +728,7 @@ struct request *elv_next_request(request_queue_t *q)
nr_bytes = rq->data_len;
blkdev_dequeue_request(rq);
- rq->flags |= REQ_QUIET;
+ rq->cmd_flags |= REQ_QUIET;
end_that_request_chunk(rq, 0, nr_bytes);
end_that_request_last(rq, 0);
} else {
@@ -554,9 +741,12 @@ struct request *elv_next_request(request_queue_t *q)
return rq;
}
+EXPORT_SYMBOL(elv_next_request);
+
void elv_dequeue_request(request_queue_t *q, struct request *rq)
{
BUG_ON(list_empty(&rq->queuelist));
+ BUG_ON(ELV_ON_HASH(rq));
list_del_init(&rq->queuelist);
@@ -569,6 +759,8 @@ void elv_dequeue_request(request_queue_t *q, struct request *rq)
q->in_flight++;
}
+EXPORT_SYMBOL(elv_dequeue_request);
+
int elv_queue_empty(request_queue_t *q)
{
elevator_t *e = q->elevator;
@@ -582,6 +774,8 @@ int elv_queue_empty(request_queue_t *q)
return 1;
}
+EXPORT_SYMBOL(elv_queue_empty);
+
struct request *elv_latter_request(request_queue_t *q, struct request *rq)
{
elevator_t *e = q->elevator;
@@ -600,13 +794,12 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
return NULL;
}
-int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
- gfp_t gfp_mask)
+int elv_set_request(request_queue_t *q, struct request *rq, gfp_t gfp_mask)
{
elevator_t *e = q->elevator;
if (e->ops->elevator_set_req_fn)
- return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
+ return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
rq->elevator_private = NULL;
return 0;
@@ -620,12 +813,12 @@ void elv_put_request(request_queue_t *q, struct request *rq)
e->ops->elevator_put_req_fn(q, rq);
}
-int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
+int elv_may_queue(request_queue_t *q, int rw)
{
elevator_t *e = q->elevator;
if (e->ops->elevator_may_queue_fn)
- return e->ops->elevator_may_queue_fn(q, rw, bio);
+ return e->ops->elevator_may_queue_fn(q, rw);
return ELV_MQUEUE_MAY;
}
@@ -792,7 +985,7 @@ static int elevator_switch(request_queue_t *q, struct elevator_type *new_e)
/*
* Allocate new elevator
*/
- e = elevator_alloc(new_e);
+ e = elevator_alloc(q, new_e);
if (!e)
return 0;
@@ -892,7 +1085,7 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
struct list_head *entry;
int len = 0;
- spin_lock_irq(q->queue_lock);
+ spin_lock_irq(&elv_list_lock);
list_for_each(entry, &elv_list) {
struct elevator_type *__e;
@@ -902,17 +1095,32 @@ ssize_t elv_iosched_show(request_queue_t *q, char *name)
else
len += sprintf(name+len, "%s ", __e->elevator_name);
}
- spin_unlock_irq(q->queue_lock);
+ spin_unlock_irq(&elv_list_lock);
len += sprintf(len+name, "\n");
return len;
}
-EXPORT_SYMBOL(elv_dispatch_sort);
-EXPORT_SYMBOL(elv_add_request);
-EXPORT_SYMBOL(__elv_add_request);
-EXPORT_SYMBOL(elv_next_request);
-EXPORT_SYMBOL(elv_dequeue_request);
-EXPORT_SYMBOL(elv_queue_empty);
-EXPORT_SYMBOL(elevator_exit);
-EXPORT_SYMBOL(elevator_init);
+struct request *elv_rb_former_request(request_queue_t *q, struct request *rq)
+{
+ struct rb_node *rbprev = rb_prev(&rq->rb_node);
+
+ if (rbprev)
+ return rb_entry_rq(rbprev);
+
+ return NULL;
+}
+
+EXPORT_SYMBOL(elv_rb_former_request);
+
+struct request *elv_rb_latter_request(request_queue_t *q, struct request *rq)
+{
+ struct rb_node *rbnext = rb_next(&rq->rb_node);
+
+ if (rbnext)
+ return rb_entry_rq(rbnext);
+
+ return NULL;
+}
+
+EXPORT_SYMBOL(elv_rb_latter_request);
diff --git a/block/genhd.c b/block/genhd.c
index 25d1f42568cc..653919d50cd4 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -295,10 +295,15 @@ static struct kobject *base_probe(dev_t dev, int *part, void *data)
static int __init genhd_device_init(void)
{
+ int err;
+
bdev_map = kobj_map_init(base_probe, &block_subsys_lock);
blk_dev_init();
- subsystem_register(&block_subsys);
- return 0;
+ err = subsystem_register(&block_subsys);
+ if (err < 0)
+ printk(KERN_WARNING "%s: subsystem_register error: %d\n",
+ __FUNCTION__, err);
+ return err;
}
subsys_initcall(genhd_device_init);
diff --git a/block/ioctl.c b/block/ioctl.c
index 309760b7e37f..58aab630dfc1 100644
--- a/block/ioctl.c
+++ b/block/ioctl.c
@@ -199,8 +199,8 @@ static int blkdev_locked_ioctl(struct file *file, struct block_device *bdev,
return -ENOIOCTLCMD;
}
-static int blkdev_driver_ioctl(struct inode *inode, struct file *file,
- struct gendisk *disk, unsigned cmd, unsigned long arg)
+int blkdev_driver_ioctl(struct inode *inode, struct file *file,
+ struct gendisk *disk, unsigned cmd, unsigned long arg)
{
int ret;
if (disk->fops->unlocked_ioctl)
@@ -215,6 +215,7 @@ static int blkdev_driver_ioctl(struct inode *inode, struct file *file,
return -ENOTTY;
}
+EXPORT_SYMBOL_GPL(blkdev_driver_ioctl);
int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
unsigned long arg)
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index 9c3a06bcb7ba..136066583c68 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -39,6 +39,7 @@ static void blk_unplug_timeout(unsigned long data);
static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io);
static void init_request_from_bio(struct request *req, struct bio *bio);
static int __make_request(request_queue_t *q, struct bio *bio);
+static struct io_context *current_io_context(gfp_t gfp_flags, int node);
/*
* For the allocated request tables
@@ -55,11 +56,6 @@ static kmem_cache_t *requestq_cachep;
*/
static kmem_cache_t *iocontext_cachep;
-static wait_queue_head_t congestion_wqh[2] = {
- __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
- __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
- };
-
/*
* Controlling structure to kblockd
*/
@@ -111,35 +107,6 @@ static void blk_queue_congestion_threshold(struct request_queue *q)
q->nr_congestion_off = nr;
}
-/*
- * A queue has just exitted congestion. Note this in the global counter of
- * congested queues, and wake up anyone who was waiting for requests to be
- * put back.
- */
-static void clear_queue_congested(request_queue_t *q, int rw)
-{
- enum bdi_state bit;
- wait_queue_head_t *wqh = &congestion_wqh[rw];
-
- bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
- clear_bit(bit, &q->backing_dev_info.state);
- smp_mb__after_clear_bit();
- if (waitqueue_active(wqh))
- wake_up(wqh);
-}
-
-/*
- * A queue has just entered congestion. Flag that in the queue's VM-visible
- * state flags and increment the global gounter of congested queues.
- */
-static void set_queue_congested(request_queue_t *q, int rw)
-{
- enum bdi_state bit;
-
- bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
- set_bit(bit, &q->backing_dev_info.state);
-}
-
/**
* blk_get_backing_dev_info - get the address of a queue's backing_dev_info
* @bdev: device
@@ -158,7 +125,6 @@ struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev)
ret = &q->backing_dev_info;
return ret;
}
-
EXPORT_SYMBOL(blk_get_backing_dev_info);
void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data)
@@ -166,7 +132,6 @@ void blk_queue_activity_fn(request_queue_t *q, activity_fn *fn, void *data)
q->activity_fn = fn;
q->activity_data = data;
}
-
EXPORT_SYMBOL(blk_queue_activity_fn);
/**
@@ -277,19 +242,19 @@ void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
EXPORT_SYMBOL(blk_queue_make_request);
-static inline void rq_init(request_queue_t *q, struct request *rq)
+static void rq_init(request_queue_t *q, struct request *rq)
{
INIT_LIST_HEAD(&rq->queuelist);
INIT_LIST_HEAD(&rq->donelist);
rq->errors = 0;
- rq->rq_status = RQ_ACTIVE;
rq->bio = rq->biotail = NULL;
+ INIT_HLIST_NODE(&rq->hash);
+ RB_CLEAR_NODE(&rq->rb_node);
rq->ioprio = 0;
rq->buffer = NULL;
rq->ref_count = 1;
rq->q = q;
- rq->waiting = NULL;
rq->special = NULL;
rq->data_len = 0;
rq->data = NULL;
@@ -382,8 +347,8 @@ unsigned blk_ordered_req_seq(struct request *rq)
if (rq == &q->post_flush_rq)
return QUEUE_ORDSEQ_POSTFLUSH;
- if ((rq->flags & REQ_ORDERED_COLOR) ==
- (q->orig_bar_rq->flags & REQ_ORDERED_COLOR))
+ if ((rq->cmd_flags & REQ_ORDERED_COLOR) ==
+ (q->orig_bar_rq->cmd_flags & REQ_ORDERED_COLOR))
return QUEUE_ORDSEQ_DRAIN;
else
return QUEUE_ORDSEQ_DONE;
@@ -446,11 +411,11 @@ static void queue_flush(request_queue_t *q, unsigned which)
end_io = post_flush_end_io;
}
+ rq->cmd_flags = REQ_HARDBARRIER;
rq_init(q, rq);
- rq->flags = REQ_HARDBARRIER;
rq->elevator_private = NULL;
+ rq->elevator_private2 = NULL;
rq->rq_disk = q->bar_rq.rq_disk;
- rq->rl = NULL;
rq->end_io = end_io;
q->prepare_flush_fn(q, rq);
@@ -471,11 +436,13 @@ static inline struct request *start_ordered(request_queue_t *q,
blkdev_dequeue_request(rq);
q->orig_bar_rq = rq;
rq = &q->bar_rq;
+ rq->cmd_flags = 0;
rq_init(q, rq);
- rq->flags = bio_data_dir(q->orig_bar_rq->bio);
- rq->flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0;
+ if (bio_data_dir(q->orig_bar_rq->bio) == WRITE)
+ rq->cmd_flags |= REQ_RW;
+ rq->cmd_flags |= q->ordered & QUEUE_ORDERED_FUA ? REQ_FUA : 0;
rq->elevator_private = NULL;
- rq->rl = NULL;
+ rq->elevator_private2 = NULL;
init_request_from_bio(rq, q->orig_bar_rq->bio);
rq->end_io = bar_end_io;
@@ -587,8 +554,8 @@ static int flush_dry_bio_endio(struct bio *bio, unsigned int bytes, int error)
return 0;
}
-static inline int ordered_bio_endio(struct request *rq, struct bio *bio,
- unsigned int nbytes, int error)
+static int ordered_bio_endio(struct request *rq, struct bio *bio,
+ unsigned int nbytes, int error)
{
request_queue_t *q = rq->q;
bio_end_io_t *endio;
@@ -837,12 +804,7 @@ EXPORT_SYMBOL(blk_queue_dma_alignment);
**/
struct request *blk_queue_find_tag(request_queue_t *q, int tag)
{
- struct blk_queue_tag *bqt = q->queue_tags;
-
- if (unlikely(bqt == NULL || tag >= bqt->real_max_depth))
- return NULL;
-
- return bqt->tag_index[tag];
+ return blk_map_queue_find_tag(q->queue_tags, tag);
}
EXPORT_SYMBOL(blk_queue_find_tag);
@@ -1124,7 +1086,7 @@ void blk_queue_end_tag(request_queue_t *q, struct request *rq)
}
list_del_init(&rq->queuelist);
- rq->flags &= ~REQ_QUEUED;
+ rq->cmd_flags &= ~REQ_QUEUED;
rq->tag = -1;
if (unlikely(bqt->tag_index[tag] == NULL))
@@ -1160,7 +1122,7 @@ int blk_queue_start_tag(request_queue_t *q, struct request *rq)
struct blk_queue_tag *bqt = q->queue_tags;
int tag;
- if (unlikely((rq->flags & REQ_QUEUED))) {
+ if (unlikely((rq->cmd_flags & REQ_QUEUED))) {
printk(KERN_ERR
"%s: request %p for device [%s] already tagged %d",
__FUNCTION__, rq,
@@ -1168,13 +1130,18 @@ int blk_queue_start_tag(request_queue_t *q, struct request *rq)
BUG();
}
- tag = find_first_zero_bit(bqt->tag_map, bqt->max_depth);
- if (tag >= bqt->max_depth)
- return 1;
+ /*
+ * Protect against shared tag maps, as we may not have exclusive
+ * access to the tag map.
+ */
+ do {
+ tag = find_first_zero_bit(bqt->tag_map, bqt->max_depth);
+ if (tag >= bqt->max_depth)
+ return 1;
- __set_bit(tag, bqt->tag_map);
+ } while (test_and_set_bit(tag, bqt->tag_map));
- rq->flags |= REQ_QUEUED;
+ rq->cmd_flags |= REQ_QUEUED;
rq->tag = tag;
bqt->tag_index[tag] = rq;
blkdev_dequeue_request(rq);
@@ -1210,65 +1177,31 @@ void blk_queue_invalidate_tags(request_queue_t *q)
printk(KERN_ERR
"%s: bad tag found on list\n", __FUNCTION__);
list_del_init(&rq->queuelist);
- rq->flags &= ~REQ_QUEUED;
+ rq->cmd_flags &= ~REQ_QUEUED;
} else
blk_queue_end_tag(q, rq);
- rq->flags &= ~REQ_STARTED;
+ rq->cmd_flags &= ~REQ_STARTED;
__elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 0);
}
}
EXPORT_SYMBOL(blk_queue_invalidate_tags);
-static const char * const rq_flags[] = {
- "REQ_RW",
- "REQ_FAILFAST",
- "REQ_SORTED",
- "REQ_SOFTBARRIER",
- "REQ_HARDBARRIER",
- "REQ_FUA",
- "REQ_CMD",
- "REQ_NOMERGE",
- "REQ_STARTED",
- "REQ_DONTPREP",
- "REQ_QUEUED",
- "REQ_ELVPRIV",
- "REQ_PC",
- "REQ_BLOCK_PC",
- "REQ_SENSE",
- "REQ_FAILED",
- "REQ_QUIET",
- "REQ_SPECIAL",
- "REQ_DRIVE_CMD",
- "REQ_DRIVE_TASK",
- "REQ_DRIVE_TASKFILE",
- "REQ_PREEMPT",
- "REQ_PM_SUSPEND",
- "REQ_PM_RESUME",
- "REQ_PM_SHUTDOWN",
- "REQ_ORDERED_COLOR",
-};
-
void blk_dump_rq_flags(struct request *rq, char *msg)
{
int bit;
- printk("%s: dev %s: flags = ", msg,
- rq->rq_disk ? rq->rq_disk->disk_name : "?");
- bit = 0;
- do {
- if (rq->flags & (1 << bit))
- printk("%s ", rq_flags[bit]);
- bit++;
- } while (bit < __REQ_NR_BITS);
+ printk("%s: dev %s: type=%x, flags=%x\n", msg,
+ rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type,
+ rq->cmd_flags);
printk("\nsector %llu, nr/cnr %lu/%u\n", (unsigned long long)rq->sector,
rq->nr_sectors,
rq->current_nr_sectors);
printk("bio %p, biotail %p, buffer %p, data %p, len %u\n", rq->bio, rq->biotail, rq->buffer, rq->data, rq->data_len);
- if (rq->flags & (REQ_BLOCK_PC | REQ_PC)) {
+ if (blk_pc_request(rq)) {
printk("cdb: ");
for (bit = 0; bit < sizeof(rq->cmd); bit++)
printk("%02x ", rq->cmd[bit]);
@@ -1441,7 +1374,7 @@ static inline int ll_new_mergeable(request_queue_t *q,
int nr_phys_segs = bio_phys_segments(q, bio);
if (req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
- req->flags |= REQ_NOMERGE;
+ req->cmd_flags |= REQ_NOMERGE;
if (req == q->last_merge)
q->last_merge = NULL;
return 0;
@@ -1464,7 +1397,7 @@ static inline int ll_new_hw_segment(request_queue_t *q,
if (req->nr_hw_segments + nr_hw_segs > q->max_hw_segments
|| req->nr_phys_segments + nr_phys_segs > q->max_phys_segments) {
- req->flags |= REQ_NOMERGE;
+ req->cmd_flags |= REQ_NOMERGE;
if (req == q->last_merge)
q->last_merge = NULL;
return 0;
@@ -1491,7 +1424,7 @@ static int ll_back_merge_fn(request_queue_t *q, struct request *req,
max_sectors = q->max_sectors;
if (req->nr_sectors + bio_sectors(bio) > max_sectors) {
- req->flags |= REQ_NOMERGE;
+ req->cmd_flags |= REQ_NOMERGE;
if (req == q->last_merge)
q->last_merge = NULL;
return 0;
@@ -1530,7 +1463,7 @@ static int ll_front_merge_fn(request_queue_t *q, struct request *req,
if (req->nr_sectors + bio_sectors(bio) > max_sectors) {
- req->flags |= REQ_NOMERGE;
+ req->cmd_flags |= REQ_NOMERGE;
if (req == q->last_merge)
q->last_merge = NULL;
return 0;
@@ -1847,8 +1780,7 @@ static void blk_release_queue(struct kobject *kobj)
if (q->queue_tags)
__blk_queue_free_tags(q);
- if (q->blk_trace)
- blk_trace_shutdown(q);
+ blk_trace_shutdown(q);
kmem_cache_free(requestq_cachep, q);
}
@@ -2030,14 +1962,13 @@ EXPORT_SYMBOL(blk_get_queue);
static inline void blk_free_request(request_queue_t *q, struct request *rq)
{
- if (rq->flags & REQ_ELVPRIV)
+ if (rq->cmd_flags & REQ_ELVPRIV)
elv_put_request(q, rq);
mempool_free(rq, q->rq.rq_pool);
}
-static inline struct request *
-blk_alloc_request(request_queue_t *q, int rw, struct bio *bio,
- int priv, gfp_t gfp_mask)
+static struct request *
+blk_alloc_request(request_queue_t *q, int rw, int priv, gfp_t gfp_mask)
{
struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
@@ -2045,17 +1976,17 @@ blk_alloc_request(request_queue_t *q, int rw, struct bio *bio,
return NULL;
/*
- * first three bits are identical in rq->flags and bio->bi_rw,
+ * first three bits are identical in rq->cmd_flags and bio->bi_rw,
* see bio.h and blkdev.h
*/
- rq->flags = rw;
+ rq->cmd_flags = rw | REQ_ALLOCED;
if (priv) {
- if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) {
+ if (unlikely(elv_set_request(q, rq, gfp_mask))) {
mempool_free(rq, q->rq.rq_pool);
return NULL;
}
- rq->flags |= REQ_ELVPRIV;
+ rq->cmd_flags |= REQ_ELVPRIV;
}
return rq;
@@ -2100,7 +2031,7 @@ static void __freed_request(request_queue_t *q, int rw)
struct request_list *rl = &q->rq;
if (rl->count[rw] < queue_congestion_off_threshold(q))
- clear_queue_congested(q, rw);
+ blk_clear_queue_congested(q, rw);
if (rl->count[rw] + 1 <= q->nr_requests) {
if (waitqueue_active(&rl->wait[rw]))
@@ -2142,13 +2073,13 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
struct io_context *ioc = NULL;
int may_queue, priv;
- may_queue = elv_may_queue(q, rw, bio);
+ may_queue = elv_may_queue(q, rw);
if (may_queue == ELV_MQUEUE_NO)
goto rq_starved;
if (rl->count[rw]+1 >= queue_congestion_on_threshold(q)) {
if (rl->count[rw]+1 >= q->nr_requests) {
- ioc = current_io_context(GFP_ATOMIC);
+ ioc = current_io_context(GFP_ATOMIC, q->node);
/*
* The queue will fill after this allocation, so set
* it as full, and mark this process as "batching".
@@ -2170,7 +2101,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
}
}
}
- set_queue_congested(q, rw);
+ blk_set_queue_congested(q, rw);
}
/*
@@ -2190,7 +2121,7 @@ static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
spin_unlock_irq(q->queue_lock);
- rq = blk_alloc_request(q, rw, bio, priv, gfp_mask);
+ rq = blk_alloc_request(q, rw, priv, gfp_mask);
if (unlikely(!rq)) {
/*
* Allocation failed presumably due to memory. Undo anything
@@ -2226,7 +2157,6 @@ rq_starved:
ioc->nr_batch_requests--;
rq_init(q, rq);
- rq->rl = rl;
blk_add_trace_generic(q, bio, rw, BLK_TA_GETRQ);
out:
@@ -2269,7 +2199,7 @@ static struct request *get_request_wait(request_queue_t *q, int rw,
* up to a big batch of them for a small period time.
* See ioc_batching, ioc_set_batching
*/
- ioc = current_io_context(GFP_NOIO);
+ ioc = current_io_context(GFP_NOIO, q->node);
ioc_set_batching(q, ioc);
spin_lock_irq(q->queue_lock);
@@ -2301,6 +2231,25 @@ struct request *blk_get_request(request_queue_t *q, int rw, gfp_t gfp_mask)
EXPORT_SYMBOL(blk_get_request);
/**
+ * blk_start_queueing - initiate dispatch of requests to device
+ * @q: request queue to kick into gear
+ *
+ * This is basically a helper to remove the need to know whether a queue
+ * is plugged or not if someone just wants to initiate dispatch of requests
+ * for this queue.
+ *
+ * The queue lock must be held with interrupts disabled.
+ */
+void blk_start_queueing(request_queue_t *q)
+{
+ if (!blk_queue_plugged(q))
+ q->request_fn(q);
+ else
+ __generic_unplug_device(q);
+}
+EXPORT_SYMBOL(blk_start_queueing);
+
+/**
* blk_requeue_request - put a request back on queue
* @q: request queue where request should be inserted
* @rq: request to be inserted
@@ -2352,7 +2301,8 @@ void blk_insert_request(request_queue_t *q, struct request *rq,
* must not attempt merges on this) and that it acts as a soft
* barrier
*/
- rq->flags |= REQ_SPECIAL | REQ_SOFTBARRIER;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
+ rq->cmd_flags |= REQ_SOFTBARRIER;
rq->special = data;
@@ -2366,11 +2316,7 @@ void blk_insert_request(request_queue_t *q, struct request *rq,
drive_stat_acct(rq, rq->nr_sectors, 1);
__elv_add_request(q, rq, where, 0);
-
- if (blk_queue_plugged(q))
- __generic_unplug_device(q);
- else
- q->request_fn(q);
+ blk_start_queueing(q);
spin_unlock_irqrestore(q->queue_lock, flags);
}
@@ -2559,7 +2505,7 @@ void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk,
int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK;
rq->rq_disk = bd_disk;
- rq->flags |= REQ_NOMERGE;
+ rq->cmd_flags |= REQ_NOMERGE;
rq->end_io = done;
WARN_ON(irqs_disabled());
spin_lock_irq(q->queue_lock);
@@ -2599,10 +2545,9 @@ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk,
rq->sense_len = 0;
}
- rq->waiting = &wait;
+ rq->end_io_data = &wait;
blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq);
wait_for_completion(&wait);
- rq->waiting = NULL;
if (rq->errors)
err = -EIO;
@@ -2711,8 +2656,6 @@ EXPORT_SYMBOL_GPL(disk_round_stats);
*/
void __blk_put_request(request_queue_t *q, struct request *req)
{
- struct request_list *rl = req->rl;
-
if (unlikely(!q))
return;
if (unlikely(--req->ref_count))
@@ -2720,18 +2663,16 @@ void __blk_put_request(request_queue_t *q, struct request *req)
elv_completed_request(q, req);
- req->rq_status = RQ_INACTIVE;
- req->rl = NULL;
-
/*
* Request may not have originated from ll_rw_blk. if not,
* it didn't come out of our reserved rq pools
*/
- if (rl) {
+ if (req->cmd_flags & REQ_ALLOCED) {
int rw = rq_data_dir(req);
- int priv = req->flags & REQ_ELVPRIV;
+ int priv = req->cmd_flags & REQ_ELVPRIV;
BUG_ON(!list_empty(&req->queuelist));
+ BUG_ON(!hlist_unhashed(&req->hash));
blk_free_request(q, req);
freed_request(q, rw, priv);
@@ -2765,9 +2706,9 @@ EXPORT_SYMBOL(blk_put_request);
*/
void blk_end_sync_rq(struct request *rq, int error)
{
- struct completion *waiting = rq->waiting;
+ struct completion *waiting = rq->end_io_data;
- rq->waiting = NULL;
+ rq->end_io_data = NULL;
__blk_put_request(rq->q, rq);
/*
@@ -2778,41 +2719,6 @@ void blk_end_sync_rq(struct request *rq, int error)
}
EXPORT_SYMBOL(blk_end_sync_rq);
-/**
- * blk_congestion_wait - wait for a queue to become uncongested
- * @rw: READ or WRITE
- * @timeout: timeout in jiffies
- *
- * Waits for up to @timeout jiffies for a queue (any queue) to exit congestion.
- * If no queues are congested then just wait for the next request to be
- * returned.
- */
-long blk_congestion_wait(int rw, long timeout)
-{
- long ret;
- DEFINE_WAIT(wait);
- wait_queue_head_t *wqh = &congestion_wqh[rw];
-
- prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
- ret = io_schedule_timeout(timeout);
- finish_wait(wqh, &wait);
- return ret;
-}
-
-EXPORT_SYMBOL(blk_congestion_wait);
-
-/**
- * blk_congestion_end - wake up sleepers on a congestion queue
- * @rw: READ or WRITE
- */
-void blk_congestion_end(int rw)
-{
- wait_queue_head_t *wqh = &congestion_wqh[rw];
-
- if (waitqueue_active(wqh))
- wake_up(wqh);
-}
-
/*
* Has to be called with the request spinlock acquired
*/
@@ -2830,7 +2736,7 @@ static int attempt_merge(request_queue_t *q, struct request *req,
if (rq_data_dir(req) != rq_data_dir(next)
|| req->rq_disk != next->rq_disk
- || next->waiting || next->special)
+ || next->special)
return 0;
/*
@@ -2891,22 +2797,24 @@ static inline int attempt_front_merge(request_queue_t *q, struct request *rq)
static void init_request_from_bio(struct request *req, struct bio *bio)
{
- req->flags |= REQ_CMD;
+ req->cmd_type = REQ_TYPE_FS;
/*
* inherit FAILFAST from bio (for read-ahead, and explicit FAILFAST)
*/
if (bio_rw_ahead(bio) || bio_failfast(bio))
- req->flags |= REQ_FAILFAST;
+ req->cmd_flags |= REQ_FAILFAST;
/*
* REQ_BARRIER implies no merging, but lets make it explicit
*/
if (unlikely(bio_barrier(bio)))
- req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
+ req->cmd_flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
if (bio_sync(bio))
- req->flags |= REQ_RW_SYNC;
+ req->cmd_flags |= REQ_RW_SYNC;
+ if (bio_rw_meta(bio))
+ req->cmd_flags |= REQ_RW_META;
req->errors = 0;
req->hard_sector = req->sector = bio->bi_sector;
@@ -2915,7 +2823,6 @@ static void init_request_from_bio(struct request *req, struct bio *bio)
req->nr_phys_segments = bio_phys_segments(req->q, bio);
req->nr_hw_segments = bio_hw_segments(req->q, bio);
req->buffer = bio_data(bio); /* see ->buffer comment above */
- req->waiting = NULL;
req->bio = req->biotail = bio;
req->ioprio = bio_prio(bio);
req->rq_disk = bio->bi_bdev->bd_disk;
@@ -2925,17 +2832,11 @@ static void init_request_from_bio(struct request *req, struct bio *bio)
static int __make_request(request_queue_t *q, struct bio *bio)
{
struct request *req;
- int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
- unsigned short prio;
- sector_t sector;
+ int el_ret, nr_sectors, barrier, err;
+ const unsigned short prio = bio_prio(bio);
+ const int sync = bio_sync(bio);
- sector = bio->bi_sector;
nr_sectors = bio_sectors(bio);
- cur_nr_sectors = bio_cur_sectors(bio);
- prio = bio_prio(bio);
-
- rw = bio_data_dir(bio);
- sync = bio_sync(bio);
/*
* low level driver can indicate that it wants pages above a
@@ -2944,8 +2845,6 @@ static int __make_request(request_queue_t *q, struct bio *bio)
*/
blk_queue_bounce(q, &bio);
- spin_lock_prefetch(q->queue_lock);
-
barrier = bio_barrier(bio);
if (unlikely(barrier) && (q->next_ordered == QUEUE_ORDERED_NONE)) {
err = -EOPNOTSUPP;
@@ -2973,7 +2872,7 @@ static int __make_request(request_queue_t *q, struct bio *bio)
req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_back_merge(q, req))
- elv_merged_request(q, req);
+ elv_merged_request(q, req, el_ret);
goto out;
case ELEVATOR_FRONT_MERGE:
@@ -2993,14 +2892,14 @@ static int __make_request(request_queue_t *q, struct bio *bio)
* not touch req->buffer either...
*/
req->buffer = bio_data(bio);
- req->current_nr_sectors = cur_nr_sectors;
- req->hard_cur_sectors = cur_nr_sectors;
- req->sector = req->hard_sector = sector;
+ req->current_nr_sectors = bio_cur_sectors(bio);
+ req->hard_cur_sectors = req->current_nr_sectors;
+ req->sector = req->hard_sector = bio->bi_sector;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_front_merge(q, req))
- elv_merged_request(q, req);
+ elv_merged_request(q, req, el_ret);
goto out;
/* ELV_NO_MERGE: elevator says don't/can't merge. */
@@ -3013,7 +2912,7 @@ get_rq:
* Grab a free request. This is might sleep but can not fail.
* Returns with the queue unlocked.
*/
- req = get_request_wait(q, rw, bio);
+ req = get_request_wait(q, bio_data_dir(bio), bio);
/*
* After dropping the lock and possibly sleeping here, our request
@@ -3307,7 +3206,7 @@ static int __end_that_request_first(struct request *req, int uptodate,
req->errors = 0;
if (!uptodate) {
- if (blk_fs_request(req) && !(req->flags & REQ_QUIET))
+ if (blk_fs_request(req) && !(req->cmd_flags & REQ_QUIET))
printk("end_request: I/O error, dev %s, sector %llu\n",
req->rq_disk ? req->rq_disk->disk_name : "?",
(unsigned long long)req->sector);
@@ -3570,8 +3469,8 @@ EXPORT_SYMBOL(end_request);
void blk_rq_bio_prep(request_queue_t *q, struct request *rq, struct bio *bio)
{
- /* first two bits are identical in rq->flags and bio->bi_rw */
- rq->flags |= (bio->bi_rw & 3);
+ /* first two bits are identical in rq->cmd_flags and bio->bi_rw */
+ rq->cmd_flags |= (bio->bi_rw & 3);
rq->nr_phys_segments = bio_phys_segments(q, bio);
rq->nr_hw_segments = bio_hw_segments(q, bio);
@@ -3659,25 +3558,22 @@ EXPORT_SYMBOL(put_io_context);
/* Called by the exitting task */
void exit_io_context(void)
{
- unsigned long flags;
struct io_context *ioc;
struct cfq_io_context *cic;
- local_irq_save(flags);
task_lock(current);
ioc = current->io_context;
current->io_context = NULL;
- ioc->task = NULL;
task_unlock(current);
- local_irq_restore(flags);
+ ioc->task = NULL;
if (ioc->aic && ioc->aic->exit)
ioc->aic->exit(ioc->aic);
if (ioc->cic_root.rb_node != NULL) {
cic = rb_entry(rb_first(&ioc->cic_root), struct cfq_io_context, rb_node);
cic->exit(ioc);
}
-
+
put_io_context(ioc);
}
@@ -3689,7 +3585,7 @@ void exit_io_context(void)
* but since the current task itself holds a reference, the context can be
* used in general code, so long as it stays within `current` context.
*/
-struct io_context *current_io_context(gfp_t gfp_flags)
+static struct io_context *current_io_context(gfp_t gfp_flags, int node)
{
struct task_struct *tsk = current;
struct io_context *ret;
@@ -3698,11 +3594,11 @@ struct io_context *current_io_context(gfp_t gfp_flags)
if (likely(ret))
return ret;
- ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
+ ret = kmem_cache_alloc_node(iocontext_cachep, gfp_flags, node);
if (ret) {
atomic_set(&ret->refcount, 1);
ret->task = current;
- ret->set_ioprio = NULL;
+ ret->ioprio_changed = 0;
ret->last_waited = jiffies; /* doesn't matter... */
ret->nr_batch_requests = 0; /* because this is 0 */
ret->aic = NULL;
@@ -3722,10 +3618,10 @@ EXPORT_SYMBOL(current_io_context);
*
* This is always called in the context of the task which submitted the I/O.
*/
-struct io_context *get_io_context(gfp_t gfp_flags)
+struct io_context *get_io_context(gfp_t gfp_flags, int node)
{
struct io_context *ret;
- ret = current_io_context(gfp_flags);
+ ret = current_io_context(gfp_flags, node);
if (likely(ret))
atomic_inc(&ret->refcount);
return ret;
@@ -3798,14 +3694,14 @@ queue_requests_store(struct request_queue *q, const char *page, size_t count)
blk_queue_congestion_threshold(q);
if (rl->count[READ] >= queue_congestion_on_threshold(q))
- set_queue_congested(q, READ);
+ blk_set_queue_congested(q, READ);
else if (rl->count[READ] < queue_congestion_off_threshold(q))
- clear_queue_congested(q, READ);
+ blk_clear_queue_congested(q, READ);
if (rl->count[WRITE] >= queue_congestion_on_threshold(q))
- set_queue_congested(q, WRITE);
+ blk_set_queue_congested(q, WRITE);
else if (rl->count[WRITE] < queue_congestion_off_threshold(q))
- clear_queue_congested(q, WRITE);
+ blk_clear_queue_congested(q, WRITE);
if (rl->count[READ] >= q->nr_requests) {
blk_set_queue_full(q, READ);
@@ -3838,9 +3734,6 @@ queue_ra_store(struct request_queue *q, const char *page, size_t count)
ssize_t ret = queue_var_store(&ra_kb, page, count);
spin_lock_irq(q->queue_lock);
- if (ra_kb > (q->max_sectors >> 1))
- ra_kb = (q->max_sectors >> 1);
-
q->backing_dev_info.ra_pages = ra_kb >> (PAGE_CACHE_SHIFT - 10);
spin_unlock_irq(q->queue_lock);
diff --git a/block/noop-iosched.c b/block/noop-iosched.c
index 56a7c620574f..79af43179421 100644
--- a/block/noop-iosched.c
+++ b/block/noop-iosched.c
@@ -69,7 +69,7 @@ static void *noop_init_queue(request_queue_t *q, elevator_t *e)
{
struct noop_data *nd;
- nd = kmalloc(sizeof(*nd), GFP_KERNEL);
+ nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node);
if (!nd)
return NULL;
INIT_LIST_HEAD(&nd->queue);
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index b33eda26e205..2dc326421a24 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -294,7 +294,7 @@ static int sg_io(struct file *file, request_queue_t *q,
rq->sense = sense;
rq->sense_len = 0;
- rq->flags |= REQ_BLOCK_PC;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
bio = rq->bio;
/*
@@ -470,7 +470,7 @@ int sg_scsi_ioctl(struct file *file, struct request_queue *q,
memset(sense, 0, sizeof(sense));
rq->sense = sense;
rq->sense_len = 0;
- rq->flags |= REQ_BLOCK_PC;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
blk_execute_rq(q, disk, rq, 0);
@@ -502,7 +502,7 @@ static int __blk_send_generic(request_queue_t *q, struct gendisk *bd_disk, int c
int err;
rq = blk_get_request(q, WRITE, __GFP_WAIT);
- rq->flags |= REQ_BLOCK_PC;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->data = NULL;
rq->data_len = 0;
rq->timeout = BLK_DEFAULT_TIMEOUT;
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 1e2f39c21180..cbae8392ce11 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -27,7 +27,6 @@ config CRYPTO_HASH
config CRYPTO_MANAGER
tristate "Cryptographic algorithm manager"
select CRYPTO_ALGAPI
- default m
help
Create default cryptographic template instantiations such as
cbc(aes).
@@ -35,6 +34,7 @@ config CRYPTO_MANAGER
config CRYPTO_HMAC
tristate "HMAC support"
select CRYPTO_HASH
+ select CRYPTO_MANAGER
help
HMAC: Keyed-Hashing for Message Authentication (RFC2104).
This is required for IPSec.
@@ -131,6 +131,7 @@ config CRYPTO_TGR192
config CRYPTO_ECB
tristate "ECB support"
select CRYPTO_BLKCIPHER
+ select CRYPTO_MANAGER
default m
help
ECB: Electronic CodeBook mode
@@ -140,6 +141,7 @@ config CRYPTO_ECB
config CRYPTO_CBC
tristate "CBC support"
select CRYPTO_BLKCIPHER
+ select CRYPTO_MANAGER
default m
help
CBC: Cipher Block Chaining mode
diff --git a/crypto/api.c b/crypto/api.c
index 2e84d4b54790..4fb7fa45cb0d 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -331,7 +331,7 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags)
tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
tfm = kzalloc(tfm_size, GFP_KERNEL);
if (tfm == NULL)
- goto out;
+ goto out_err;
tfm->__crt_alg = alg;
@@ -355,6 +355,7 @@ cra_init_failed:
crypto_exit_ops(tfm);
out_free_tfm:
kfree(tfm);
+out_err:
tfm = ERR_PTR(err);
out:
return tfm;
@@ -414,14 +415,14 @@ struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask)
struct crypto_alg *alg;
alg = crypto_alg_mod_lookup(alg_name, type, mask);
- err = PTR_ERR(alg);
- tfm = ERR_PTR(err);
- if (IS_ERR(alg))
+ if (IS_ERR(alg)) {
+ err = PTR_ERR(alg);
goto err;
+ }
tfm = __crypto_alloc_tfm(alg, 0);
if (!IS_ERR(tfm))
- break;
+ return tfm;
crypto_mod_put(alg);
err = PTR_ERR(tfm);
@@ -433,9 +434,9 @@ err:
err = -EINTR;
break;
}
- };
+ }
- return tfm;
+ return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(crypto_alloc_base);
diff --git a/crypto/serpent.c b/crypto/serpent.c
index 465d091cd3ec..2b0a19a44ec5 100644
--- a/crypto/serpent.c
+++ b/crypto/serpent.c
@@ -364,10 +364,10 @@ static void serpent_encrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
const u32
- *k = ctx->expkey,
- *s = (const u32 *)src;
- u32 *d = (u32 *)dst,
- r0, r1, r2, r3, r4;
+ *k = ctx->expkey;
+ const __le32 *s = (const __le32 *)src;
+ __le32 *d = (__le32 *)dst;
+ u32 r0, r1, r2, r3, r4;
/*
* Note: The conversions between u8* and u32* might cause trouble
@@ -423,10 +423,10 @@ static void serpent_decrypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src)
{
struct serpent_ctx *ctx = crypto_tfm_ctx(tfm);
const u32
- *k = ((struct serpent_ctx *)ctx)->expkey,
- *s = (const u32 *)src;
- u32 *d = (u32 *)dst,
- r0, r1, r2, r3, r4;
+ *k = ((struct serpent_ctx *)ctx)->expkey;
+ const __le32 *s = (const __le32 *)src;
+ __le32 *d = (__le32 *)dst;
+ u32 r0, r1, r2, r3, r4;
r0 = le32_to_cpu(s[0]);
r1 = le32_to_cpu(s[1]);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 263e86ddc1a4..f39463418904 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -14,6 +14,10 @@ source "drivers/pnp/Kconfig"
source "drivers/block/Kconfig"
+# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4
+
+source "drivers/misc/Kconfig"
+
source "drivers/ide/Kconfig"
source "drivers/scsi/Kconfig"
@@ -52,8 +56,6 @@ source "drivers/w1/Kconfig"
source "drivers/hwmon/Kconfig"
-source "drivers/misc/Kconfig"
-
source "drivers/mfd/Kconfig"
source "drivers/media/Kconfig"
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index 3dd6b7bb5d35..7fde8f4daebf 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/drivers/block/mfmhd.c
+ * linux/drivers/acorn/block/mfmhd.c
*
* Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (gilbertd@cs.man.ac.uk)
*
@@ -938,7 +938,7 @@ static void do_mfm_request(request_queue_t *q)
mfm_request();
}
-static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs)
+static void mfm_interrupt_handler(int unused, void *dev_id)
{
void (*handler) (void) = do_mfm;
diff --git a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
index c26c08b36829..bdb9c8b78ed8 100644
--- a/drivers/acorn/char/i2c.c
+++ b/drivers/acorn/char/i2c.c
@@ -308,7 +308,6 @@ static struct i2c_algo_bit_data ioc_data = {
.getsda = ioc_getsda,
.getscl = ioc_getscl,
.udelay = 80,
- .mdelay = 80,
.timeout = 100
};
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 56c5ba874623..0f9d4be7ed75 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -253,7 +253,7 @@ config ACPI_CUSTOM_DSDT
depends on !STANDALONE
default n
help
- Thist option is to load a custom ACPI DSDT
+ This option is to load a custom ACPI DSDT
If you don't know what that is, say N.
config ACPI_CUSTOM_DSDT_FILE
@@ -310,7 +310,7 @@ config X86_PM_TIMER
The Power Management Timer is available on all ACPI-capable,
in most cases even if ACPI is unusable or blacklisted.
- This timing source is not affected by powermanagement features
+ This timing source is not affected by power management features
like aggressive processor idling, throttling, frequency and/or
voltage scaling, unlike the commonly used Time Stamp Counter
(TSC) timing source.
@@ -345,7 +345,7 @@ config ACPI_HOTPLUG_MEMORY
Enabling this driver assumes that your platform hardware
and firmware have support for hot-plugging physical memory. If
your system does not support physically adding or ripping out
- memory DIMMs at some platfrom defined granularity (individually
+ memory DIMMs at some platform defined granularity (individually
or as a bank) at runtime, then you need not enable this driver.
If one selects "m," this driver can be loaded using the following
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 1dda370f402b..6bcd9e8e7bcb 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -85,6 +85,8 @@ struct acpi_memory_device {
struct list_head res_list;
};
+static int acpi_hotmem_initialized;
+
static acpi_status
acpi_memory_get_resource(struct acpi_resource *resource, void *context)
{
@@ -238,6 +240,10 @@ static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
num_enabled++;
continue;
}
+
+ if (node < 0)
+ node = memory_add_physaddr_to_nid(info->start_addr);
+
result = add_memory(node, info->start_addr, info->length);
if (result)
continue;
@@ -410,7 +416,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
/* Set the device state */
mem_device->state = MEMORY_POWER_ON_STATE;
- printk(KERN_INFO "%s \n", acpi_device_name(device));
+ printk(KERN_DEBUG "%s \n", acpi_device_name(device));
return result;
}
@@ -434,6 +440,15 @@ static int acpi_memory_device_start (struct acpi_device *device)
struct acpi_memory_device *mem_device;
int result = 0;
+ /*
+ * Early boot code has recognized memory area by EFI/E820.
+ * If DSDT shows these memory devices on boot, hotplug is not necessary
+ * for them. So, it just returns until completion of this driver's
+ * start up.
+ */
+ if (!acpi_hotmem_initialized)
+ return 0;
+
mem_device = acpi_driver_data(device);
if (!acpi_memory_check_device(mem_device)) {
@@ -533,6 +548,7 @@ static int __init acpi_memory_device_init(void)
return -ENODEV;
}
+ acpi_hotmem_initialized = 1;
return 0;
}
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index e9ee4c52a5f6..c7ac9297a204 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -138,6 +138,7 @@ struct asus_hotk {
S2x, //S200 (J1 reported), Victor MP-XP7210
W1N, //W1000N
W5A, //W5A
+ W3V, //W3030V
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
//(Centrino)
END_MODEL
@@ -376,6 +377,17 @@ static struct model_data model_conf[END_MODEL] = {
.display_get = "\\ADVG"},
{
+ .name = "W3V",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .lcd_status = "\\BKLT",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"},
+
+ {
.name = "xxN",
.mt_mled = "MLED",
/* WLED present, but not controlled by ACPI */
@@ -555,11 +567,11 @@ static int
write_led(const char __user * buffer, unsigned long count,
char *ledname, int ledmask, int invert)
{
- int value;
+ int rv, value;
int led_out = 0;
- count = parse_arg(buffer, count, &value);
- if (count > 0)
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0)
led_out = value ? 1 : 0;
hotk->status =
@@ -572,7 +584,7 @@ write_led(const char __user * buffer, unsigned long count,
printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
ledname);
- return count;
+ return rv;
}
/*
@@ -607,20 +619,18 @@ static int
proc_write_ledd(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0) {
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0) {
if (!write_acpi_int
(hotk->handle, hotk->methods->mt_ledd, value, NULL))
printk(KERN_WARNING
"Asus ACPI: LED display write failed\n");
else
hotk->ledd_status = (u32) value;
- } else if (count < 0)
- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
- return count;
+ }
+ return rv;
}
/*
@@ -761,12 +771,12 @@ static int
proc_write_lcd(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0)
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0)
set_lcd_state(value);
- return count;
+ return rv;
}
static int read_brightness(void)
@@ -830,18 +840,15 @@ static int
proc_write_brn(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0) {
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0) {
value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
/* 0 <= value <= 15 */
set_brightness(value);
- } else if (count < 0) {
- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
}
-
- return count;
+ return rv;
}
static void set_display(int value)
@@ -880,15 +887,12 @@ static int
proc_write_disp(struct file *file, const char __user * buffer,
unsigned long count, void *data)
{
- int value;
+ int rv, value;
- count = parse_arg(buffer, count, &value);
- if (count > 0)
+ rv = parse_arg(buffer, count, &value);
+ if (rv > 0)
set_display(value);
- else if (count < 0)
- printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
-
- return count;
+ return rv;
}
typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
@@ -1097,6 +1101,8 @@ static int asus_model_match(char *model)
return A4G;
else if (strncmp(model, "W1N", 3) == 0)
return W1N;
+ else if (strncmp(model, "W3V", 3) == 0)
+ return W3V;
else if (strncmp(model, "W5A", 3) == 0)
return W5A;
else
@@ -1200,9 +1206,10 @@ static int asus_hotk_get_info(void)
hotk->methods->mt_wled = NULL;
/* L5D's WLED is not controlled by ACPI */
else if (strncmp(string, "M2N", 3) == 0 ||
+ strncmp(string, "W3V", 3) == 0 ||
strncmp(string, "S1N", 3) == 0)
hotk->methods->mt_wled = "WLED";
- /* M2N and S1N have a usable WLED */
+ /* M2N, S1N and W3V have a usable WLED */
else if (asus_info) {
if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
hotk->methods->mled_status = NULL;
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 9810e2a55d0a..026e40755cdd 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -64,6 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
static int acpi_battery_add(struct acpi_device *device);
static int acpi_battery_remove(struct acpi_device *device, int type);
+static int acpi_battery_resume(struct acpi_device *device, int status);
static struct acpi_driver acpi_battery_driver = {
.name = ACPI_BATTERY_DRIVER_NAME,
@@ -71,6 +72,7 @@ static struct acpi_driver acpi_battery_driver = {
.ids = ACPI_BATTERY_HID,
.ops = {
.add = acpi_battery_add,
+ .resume = acpi_battery_resume,
.remove = acpi_battery_remove,
},
};
@@ -753,6 +755,18 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
return 0;
}
+/* this is needed to learn about changes made in suspended state */
+static int acpi_battery_resume(struct acpi_device *device, int state)
+{
+ struct acpi_battery *battery;
+
+ if (!device)
+ return -EINVAL;
+
+ battery = device->driver_data;
+ return acpi_battery_check(battery);
+}
+
static int __init acpi_battery_init(void)
{
int result;
diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c
index a01ce6700bfe..4a9b7bf6f44e 100644
--- a/drivers/acpi/cm_sbs.c
+++ b/drivers/acpi/cm_sbs.c
@@ -67,7 +67,7 @@ void acpi_unlock_ac_dir(struct proc_dir_entry *acpi_ac_dir_param)
lock_ac_dir_cnt--;
if (lock_ac_dir_cnt == 0 && acpi_ac_dir_param && acpi_ac_dir) {
remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
- acpi_ac_dir = 0;
+ acpi_ac_dir = NULL;
}
mutex_unlock(&cm_sbs_mutex);
}
@@ -99,7 +99,7 @@ void acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir_param)
if (lock_battery_dir_cnt == 0 && acpi_battery_dir_param
&& acpi_battery_dir) {
remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
- acpi_battery_dir = 0;
+ acpi_battery_dir = NULL;
}
mutex_unlock(&cm_sbs_mutex);
return;
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index e5d796362854..e6d4b084dca2 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -45,206 +45,143 @@ ACPI_MODULE_NAME("acpi_ec")
#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver"
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
#define ACPI_EC_FILE_INFO "info"
+
+/* EC status register */
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
-#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */
-#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
-#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */
-#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
-#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
+
+/* EC commands */
#define ACPI_EC_COMMAND_READ 0x80
#define ACPI_EC_COMMAND_WRITE 0x81
#define ACPI_EC_BURST_ENABLE 0x82
#define ACPI_EC_BURST_DISABLE 0x83
#define ACPI_EC_COMMAND_QUERY 0x84
-#define EC_POLL 0xFF
-#define EC_INTR 0x00
+
+/* EC events */
+enum {
+ ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
+ ACPI_EC_EVENT_IBF_0, /* Input buffer empty */
+};
+
+#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */
+#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
+#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
+#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
+
+enum {
+ EC_INTR = 1, /* Output buffer full */
+ EC_POLL, /* Input buffer empty */
+};
+
static int acpi_ec_remove(struct acpi_device *device, int type);
static int acpi_ec_start(struct acpi_device *device);
static int acpi_ec_stop(struct acpi_device *device, int type);
-static int acpi_ec_intr_add(struct acpi_device *device);
-static int acpi_ec_poll_add(struct acpi_device *device);
+static int acpi_ec_add(struct acpi_device *device);
static struct acpi_driver acpi_ec_driver = {
.name = ACPI_EC_DRIVER_NAME,
.class = ACPI_EC_CLASS,
.ids = ACPI_EC_HID,
.ops = {
- .add = acpi_ec_intr_add,
+ .add = acpi_ec_add,
.remove = acpi_ec_remove,
.start = acpi_ec_start,
.stop = acpi_ec_stop,
},
};
-union acpi_ec {
- struct {
- u32 mode;
- acpi_handle handle;
- unsigned long uid;
- unsigned long gpe_bit;
- struct acpi_generic_address status_addr;
- struct acpi_generic_address command_addr;
- struct acpi_generic_address data_addr;
- unsigned long global_lock;
- } common;
-
- struct {
- u32 mode;
- acpi_handle handle;
- unsigned long uid;
- unsigned long gpe_bit;
- struct acpi_generic_address status_addr;
- struct acpi_generic_address command_addr;
- struct acpi_generic_address data_addr;
- unsigned long global_lock;
- unsigned int expect_event;
- atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
- atomic_t pending_gpe;
- struct semaphore sem;
- wait_queue_head_t wait;
- } intr;
-
- struct {
- u32 mode;
- acpi_handle handle;
- unsigned long uid;
- unsigned long gpe_bit;
- struct acpi_generic_address status_addr;
- struct acpi_generic_address command_addr;
- struct acpi_generic_address data_addr;
- unsigned long global_lock;
- struct semaphore sem;
- } poll;
-};
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event);
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event);
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data);
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data);
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data);
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data);
-static void acpi_ec_gpe_poll_query(void *ec_cxt);
-static void acpi_ec_gpe_intr_query(void *ec_cxt);
-static u32 acpi_ec_gpe_poll_handler(void *data);
-static u32 acpi_ec_gpe_intr_handler(void *data);
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
- u32 Level, void *context, void **retval);
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
- u32 Level, void *context, void **retval);
-
-static int __init acpi_ec_poll_get_real_ecdt(void);
-static int __init acpi_ec_intr_get_real_ecdt(void);
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
-static union acpi_ec *ec_ecdt;
+struct acpi_ec {
+ acpi_handle handle;
+ unsigned long uid;
+ unsigned long gpe_bit;
+ unsigned long command_addr;
+ unsigned long data_addr;
+ unsigned long global_lock;
+ struct semaphore sem;
+ unsigned int expect_event;
+ atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort */
+ wait_queue_head_t wait;
+} *ec_ecdt;
/* External interfaces use first EC only, so remember */
static struct acpi_device *first_ec;
-static int acpi_ec_poll_mode = EC_INTR;
+static int acpi_ec_mode = EC_INTR;
/* --------------------------------------------------------------------------
Transaction Management
-------------------------------------------------------------------------- */
-static u32 acpi_ec_read_status(union acpi_ec *ec)
+static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
{
- u32 status = 0;
-
- acpi_hw_low_level_read(8, &status, &ec->common.status_addr);
- return status;
+ return inb(ec->command_addr);
}
-static int acpi_ec_wait(union acpi_ec *ec, u8 event)
+static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_wait(ec, event);
- else
- return acpi_ec_intr_wait(ec, event);
+ return inb(ec->data_addr);
}
-static int acpi_ec_poll_wait(union acpi_ec *ec, u8 event)
+static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
{
- u32 acpi_ec_status = 0;
- u32 i = ACPI_EC_UDELAY_COUNT;
+ outb(command, ec->command_addr);
+}
- if (!ec)
- return -EINVAL;
+static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
+{
+ outb(data, ec->data_addr);
+}
- /* Poll the EC status register waiting for the event to occur. */
+static int acpi_ec_check_status(u8 status, u8 event)
+{
switch (event) {
- case ACPI_EC_EVENT_OBF:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status,
- &ec->common.status_addr);
- if (acpi_ec_status & ACPI_EC_FLAG_OBF)
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i > 0);
+ case ACPI_EC_EVENT_OBF_1:
+ if (status & ACPI_EC_FLAG_OBF)
+ return 1;
break;
- case ACPI_EC_EVENT_IBE:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status,
- &ec->common.status_addr);
- if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i > 0);
+ case ACPI_EC_EVENT_IBF_0:
+ if (!(status & ACPI_EC_FLAG_IBF))
+ return 1;
break;
default:
- return -EINVAL;
+ break;
}
- return -ETIME;
+ return 0;
}
-static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
-{
- int result = 0;
-
- ec->intr.expect_event = event;
- smp_mb();
+static int acpi_ec_wait(struct acpi_ec *ec, u8 event)
+{
+ int i = (acpi_ec_mode == EC_POLL) ? ACPI_EC_UDELAY_COUNT : 0;
+ long time_left;
- switch (event) {
- case ACPI_EC_EVENT_IBE:
- if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF) {
- ec->intr.expect_event = 0;
- return 0;
- }
- break;
- default:
- break;
+ ec->expect_event = event;
+ if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
+ ec->expect_event = 0;
+ return 0;
}
- result = wait_event_timeout(ec->intr.wait,
- !ec->intr.expect_event,
+ do {
+ if (acpi_ec_mode == EC_POLL) {
+ udelay(ACPI_EC_UDELAY);
+ } else {
+ time_left = wait_event_timeout(ec->wait,
+ !ec->expect_event,
msecs_to_jiffies(ACPI_EC_DELAY));
-
- ec->intr.expect_event = 0;
- smp_mb();
-
- /*
- * Verify that the event in question has actually happened by
- * querying EC status. Do the check even if operation timed-out
- * to make sure that we did not miss interrupt.
- */
- switch (event) {
- case ACPI_EC_EVENT_OBF:
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
+ if (time_left > 0) {
+ ec->expect_event = 0;
+ return 0;
+ }
+ }
+ if (acpi_ec_check_status(acpi_ec_read_status(ec), event)) {
+ ec->expect_event = 0;
return 0;
- break;
+ }
+ } while (--i > 0);
- case ACPI_EC_EVENT_IBE:
- if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
- return 0;
- break;
- }
+ ec->expect_event = 0;
return -ETIME;
}
@@ -254,272 +191,150 @@ static int acpi_ec_intr_wait(union acpi_ec *ec, unsigned int event)
* Note: samsung nv5000 doesn't work with ec burst mode.
* http://bugzilla.kernel.org/show_bug.cgi?id=4980
*/
-int acpi_ec_enter_burst_mode(union acpi_ec *ec)
+int acpi_ec_enter_burst_mode(struct acpi_ec *ec)
{
- u32 tmp = 0;
- int status = 0;
+ u8 tmp = 0;
+ u8 status = 0;
status = acpi_ec_read_status(ec);
if (status != -EINVAL && !(status & ACPI_EC_FLAG_BURST)) {
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
if (status)
goto end;
- acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- acpi_hw_low_level_read(8, &tmp, &ec->common.data_addr);
+ acpi_ec_write_cmd(ec, ACPI_EC_BURST_ENABLE);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+ tmp = acpi_ec_read_data(ec);
if (tmp != 0x90) { /* Burst ACK byte */
return -EINVAL;
}
}
- atomic_set(&ec->intr.leaving_burst, 0);
+ atomic_set(&ec->leaving_burst, 0);
return 0;
- end:
- ACPI_EXCEPTION ((AE_INFO, status, "EC wait, burst mode");
+ end:
+ ACPI_EXCEPTION((AE_INFO, status, "EC wait, burst mode"));
return -1;
}
-int acpi_ec_leave_burst_mode(union acpi_ec *ec)
+int acpi_ec_leave_burst_mode(struct acpi_ec *ec)
{
- int status = 0;
+ u8 status = 0;
status = acpi_ec_read_status(ec);
if (status != -EINVAL && (status & ACPI_EC_FLAG_BURST)){
- status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
if(status)
goto end;
- acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->common.command_addr);
- acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
- }
- atomic_set(&ec->intr.leaving_burst, 1);
+ acpi_ec_write_cmd(ec, ACPI_EC_BURST_DISABLE);
+ acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ }
+ atomic_set(&ec->leaving_burst, 1);
return 0;
-end:
- ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode");
+ end:
+ ACPI_EXCEPTION((AE_INFO, status, "EC leave burst mode"));
return -1;
}
#endif /* ACPI_FUTURE_USAGE */
-static int acpi_ec_read(union acpi_ec *ec, u8 address, u32 * data)
-{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_read(ec, address, data);
- else
- return acpi_ec_intr_read(ec, address, data);
-}
-static int acpi_ec_write(union acpi_ec *ec, u8 address, u8 data)
-{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_write(ec, address, data);
- else
- return acpi_ec_intr_write(ec, address, data);
-}
-static int acpi_ec_poll_read(union acpi_ec *ec, u8 address, u32 * data)
+static int acpi_ec_transaction_unlocked(struct acpi_ec *ec, u8 command,
+ const u8 *wdata, unsigned wdata_len,
+ u8 *rdata, unsigned rdata_len)
{
- acpi_status status = AE_OK;
- int result = 0;
- u32 glk = 0;
+ int result;
+ acpi_ec_write_cmd(ec, command);
- if (!ec || !data)
- return -EINVAL;
-
- *data = 0;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ for (; wdata_len > 0; wdata_len --) {
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if (result)
+ return result;
+ acpi_ec_write_data(ec, *(wdata++));
}
- if (down_interruptible(&ec->poll.sem)) {
- result = -ERESTARTSYS;
- goto end_nosem;
+ if (command == ACPI_EC_COMMAND_WRITE) {
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
+ if (result)
+ return result;
}
-
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
- &ec->common.command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
-
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
- goto end;
-
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
- *data, address));
-
- end:
- up(&ec->poll.sem);
-end_nosem:
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
-
- return result;
-}
-
-static int acpi_ec_poll_write(union acpi_ec *ec, u8 address, u8 data)
-{
- int result = 0;
- acpi_status status = AE_OK;
- u32 glk = 0;
+ for (; rdata_len > 0; rdata_len --) {
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF_1);
+ if (result)
+ return result;
- if (!ec)
- return -EINVAL;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
-
- if (down_interruptible(&ec->poll.sem)) {
- result = -ERESTARTSYS;
- goto end_nosem;
+ *(rdata++) = acpi_ec_read_data(ec);
}
-
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
- &ec->common.command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
-
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
-
- acpi_hw_low_level_write(8, data, &ec->common.data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
- goto end;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
- data, address));
-
- end:
- up(&ec->poll.sem);
-end_nosem:
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
-
- return result;
+ return 0;
}
-static int acpi_ec_intr_read(union acpi_ec *ec, u8 address, u32 * data)
+static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
+ const u8 *wdata, unsigned wdata_len,
+ u8 *rdata, unsigned rdata_len)
{
- int status = 0;
+ int status;
u32 glk;
-
- if (!ec || !data)
+ if (!ec || (wdata_len && !wdata) || (rdata_len && !rdata))
return -EINVAL;
- *data = 0;
+ if (rdata)
+ memset(rdata, 0, rdata_len);
- if (ec->common.global_lock) {
+ if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
return -ENODEV;
}
+ down(&ec->sem);
- WARN_ON(in_interrupt());
- down(&ec->intr.sem);
-
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0);
if (status) {
printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
goto end;
}
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "read EC, IB not empty\n");
- }
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (status) {
- printk(KERN_DEBUG PREFIX "read EC, OB not full\n");
- goto end;
- }
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
- *data, address));
+ status = acpi_ec_transaction_unlocked(ec, command,
+ wdata, wdata_len,
+ rdata, rdata_len);
- end:
- up(&ec->intr.sem);
+end:
+ up(&ec->sem);
- if (ec->common.global_lock)
+ if (ec->global_lock)
acpi_release_global_lock(glk);
return status;
}
-static int acpi_ec_intr_write(union acpi_ec *ec, u8 address, u8 data)
+static int acpi_ec_read(struct acpi_ec *ec, u8 address, u8 *data)
{
- int status = 0;
- u32 glk;
-
-
- if (!ec)
- return -EINVAL;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
-
- WARN_ON(in_interrupt());
- down(&ec->intr.sem);
-
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
- }
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
- }
-
- acpi_hw_low_level_write(8, address, &ec->common.data_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "write EC, IB not empty\n");
- }
-
- acpi_hw_low_level_write(8, data, &ec->common.data_addr);
+ int result;
+ u8 d;
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
- data, address));
-
- up(&ec->intr.sem);
-
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
+ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_READ,
+ &address, 1, &d, 1);
+ *data = d;
+ return result;
+}
- return status;
+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);
}
/*
* Externally callable EC access functions. For now, assume 1 EC only
*/
-int ec_read(u8 addr, u8 * val)
+int ec_read(u8 addr, u8 *val)
{
- union acpi_ec *ec;
+ struct acpi_ec *ec;
int err;
- u32 temp_data;
+ u8 temp_data;
if (!first_ec)
return -ENODEV;
@@ -539,7 +354,7 @@ EXPORT_SYMBOL(ec_read);
int ec_write(u8 addr, u8 val)
{
- union acpi_ec *ec;
+ struct acpi_ec *ec;
int err;
if (!first_ec)
@@ -554,255 +369,106 @@ int ec_write(u8 addr, u8 val)
EXPORT_SYMBOL(ec_write);
-static int acpi_ec_query(union acpi_ec *ec, u32 * data)
-{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_query(ec, data);
- else
- return acpi_ec_intr_query(ec, data);
-}
-static int acpi_ec_poll_query(union acpi_ec *ec, u32 * data)
+extern int ec_transaction(u8 command,
+ const u8 *wdata, unsigned wdata_len,
+ u8 *rdata, unsigned rdata_len)
{
- int result = 0;
- acpi_status status = AE_OK;
- u32 glk = 0;
-
-
- if (!ec || !data)
- return -EINVAL;
-
- *data = 0;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
+ struct acpi_ec *ec;
- /*
- * Query the EC to find out which _Qxx method we need to evaluate.
- * Note that successful completion of the query causes the ACPI_EC_SCI
- * bit to be cleared (and thus clearing the interrupt source).
- */
- if (down_interruptible(&ec->poll.sem)) {
- result = -ERESTARTSYS;
- goto end_nosem;
- }
-
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
- &ec->common.command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
- goto end;
-
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
- if (!*data)
- result = -ENODATA;
+ if (!first_ec)
+ return -ENODEV;
- end:
- up(&ec->poll.sem);
-end_nosem:
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
+ ec = acpi_driver_data(first_ec);
- return result;
+ return acpi_ec_transaction(ec, command, wdata,
+ wdata_len, rdata, rdata_len);
}
-static int acpi_ec_intr_query(union acpi_ec *ec, u32 * data)
-{
- int status = 0;
- u32 glk;
-
- if (!ec || !data)
- return -EINVAL;
- *data = 0;
-
- if (ec->common.global_lock) {
- status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
- if (ACPI_FAILURE(status))
- return -ENODEV;
- }
+EXPORT_SYMBOL(ec_transaction);
- down(&ec->intr.sem);
+static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
+{
+ int result;
+ u8 d;
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (status) {
- printk(KERN_DEBUG PREFIX "query EC, IB not empty\n");
- goto end;
- }
- /*
- * Query the EC to find out which _Qxx method we need to evaluate.
- * Note that successful completion of the query causes the ACPI_EC_SCI
- * bit to be cleared (and thus clearing the interrupt source).
- */
- acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY,
- &ec->common.command_addr);
- status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (status) {
- printk(KERN_DEBUG PREFIX "query EC, OB not full\n");
- goto end;
- }
+ if (!ec || !data)
+ return -EINVAL;
- acpi_hw_low_level_read(8, data, &ec->common.data_addr);
- if (!*data)
- status = -ENODATA;
+ /*
+ * Query the EC to find out which _Qxx method we need to evaluate.
+ * Note that successful completion of the query causes the ACPI_EC_SCI
+ * bit to be cleared (and thus clearing the interrupt source).
+ */
- end:
- up(&ec->intr.sem);
+ result = acpi_ec_transaction(ec, ACPI_EC_COMMAND_QUERY, NULL, 0, &d, 1);
+ if (result)
+ return result;
- if (ec->common.global_lock)
- acpi_release_global_lock(glk);
+ if (!d)
+ return -ENODATA;
- return status;
+ *data = d;
+ return 0;
}
/* --------------------------------------------------------------------------
Event Management
-------------------------------------------------------------------------- */
-union acpi_ec_query_data {
+struct acpi_ec_query_data {
acpi_handle handle;
u8 data;
};
static void acpi_ec_gpe_query(void *ec_cxt)
{
- if (acpi_ec_poll_mode)
- acpi_ec_gpe_poll_query(ec_cxt);
- else
- acpi_ec_gpe_intr_query(ec_cxt);
-}
-
-static void acpi_ec_gpe_poll_query(void *ec_cxt)
-{
- union acpi_ec *ec = (union acpi_ec *)ec_cxt;
- u32 value = 0;
- static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
- const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
-
+ struct acpi_ec *ec = (struct acpi_ec *)ec_cxt;
+ u8 value = 0;
+ static char object_name[8];
- if (!ec_cxt)
+ if (!ec)
goto end;
- if (down_interruptible (&ec->poll.sem)) {
- return;
- }
- acpi_hw_low_level_read(8, &value, &ec->common.command_addr);
- up(&ec->poll.sem);
-
- /* TBD: Implement asynch events!
- * NOTE: All we care about are EC-SCI's. Other EC events are
- * handled via polling (yuck!). This is because some systems
- * treat EC-SCIs as level (versus EDGE!) triggered, preventing
- * a purely interrupt-driven approach (grumble, grumble).
- */
+ value = acpi_ec_read_status(ec);
+
if (!(value & ACPI_EC_FLAG_SCI))
goto end;
if (acpi_ec_query(ec, &value))
goto end;
- object_name[2] = hex[((value >> 4) & 0x0F)];
- object_name[3] = hex[(value & 0x0F)];
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
+ snprintf(object_name, 8, "_Q%2.2X", value);
- acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
- end:
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
-}
-static void acpi_ec_gpe_intr_query(void *ec_cxt)
-{
- union acpi_ec *ec = (union acpi_ec *)ec_cxt;
- u32 value;
- int result = -ENODATA;
- static char object_name[5] = { '_', 'Q', '0', '0', '\0' };
- const char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
- };
+ acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
-
- if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
- result = acpi_ec_query(ec, &value);
-
- if (result)
- goto end;
-
- object_name[2] = hex[((value >> 4) & 0x0F)];
- object_name[3] = hex[(value & 0x0F)];
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
-
- acpi_evaluate_object(ec->common.handle, object_name, NULL, NULL);
end:
- atomic_dec(&ec->intr.pending_gpe);
- return;
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
}
static u32 acpi_ec_gpe_handler(void *data)
{
- if (acpi_ec_poll_mode)
- return acpi_ec_gpe_poll_handler(data);
- else
- return acpi_ec_gpe_intr_handler(data);
-}
-static u32 acpi_ec_gpe_poll_handler(void *data)
-{
acpi_status status = AE_OK;
- union acpi_ec *ec = (union acpi_ec *)data;
-
- if (!ec)
- return ACPI_INTERRUPT_NOT_HANDLED;
-
- acpi_disable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
-
- status = acpi_os_execute(OSL_EC_POLL_HANDLER, acpi_ec_gpe_query, ec);
-
- if (status == AE_OK)
- return ACPI_INTERRUPT_HANDLED;
- else
- return ACPI_INTERRUPT_NOT_HANDLED;
-}
-static u32 acpi_ec_gpe_intr_handler(void *data)
-{
- acpi_status status = AE_OK;
- u32 value;
- union acpi_ec *ec = (union acpi_ec *)data;
-
- if (!ec)
- return ACPI_INTERRUPT_NOT_HANDLED;
+ u8 value;
+ struct acpi_ec *ec = (struct acpi_ec *)data;
- acpi_clear_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+ acpi_clear_gpe(NULL, ec->gpe_bit, ACPI_ISR);
value = acpi_ec_read_status(ec);
- switch (ec->intr.expect_event) {
- case ACPI_EC_EVENT_OBF:
- if (!(value & ACPI_EC_FLAG_OBF))
- break;
- ec->intr.expect_event = 0;
- wake_up(&ec->intr.wait);
- break;
- case ACPI_EC_EVENT_IBE:
- if ((value & ACPI_EC_FLAG_IBF))
- break;
- ec->intr.expect_event = 0;
- wake_up(&ec->intr.wait);
- break;
- default:
- break;
+ if (acpi_ec_mode == EC_INTR) {
+ if (acpi_ec_check_status(value, ec->expect_event)) {
+ ec->expect_event = 0;
+ wake_up(&ec->wait);
+ }
}
if (value & ACPI_EC_FLAG_SCI) {
- atomic_add(1, &ec->intr.pending_gpe);
- status = acpi_os_execute(OSL_EC_BURST_HANDLER,
- acpi_ec_gpe_query, ec);
+ status = acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
return status == AE_OK ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_ISR);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
return status == AE_OK ?
ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
@@ -833,7 +499,7 @@ acpi_ec_space_handler(u32 function,
void *handler_context, void *region_context)
{
int result = 0;
- union acpi_ec *ec = NULL;
+ struct acpi_ec *ec = NULL;
u64 temp = *value;
acpi_integer f_v = 0;
int i = 0;
@@ -843,18 +509,16 @@ acpi_ec_space_handler(u32 function,
return AE_BAD_PARAMETER;
if (bit_width != 8 && acpi_strict) {
- printk(KERN_WARNING PREFIX
- "acpi_ec_space_handler: bit_width should be 8\n");
return AE_BAD_PARAMETER;
}
- ec = (union acpi_ec *)handler_context;
+ ec = (struct acpi_ec *)handler_context;
next_byte:
switch (function) {
case ACPI_READ:
temp = 0;
- result = acpi_ec_read(ec, (u8) address, (u32 *) & temp);
+ result = acpi_ec_read(ec, (u8) address, (u8 *) &temp);
break;
case ACPI_WRITE:
result = acpi_ec_write(ec, (u8) address, (u8) temp);
@@ -905,20 +569,20 @@ static struct proc_dir_entry *acpi_ec_dir;
static int acpi_ec_read_info(struct seq_file *seq, void *offset)
{
- union acpi_ec *ec = (union acpi_ec *)seq->private;
+ struct acpi_ec *ec = (struct acpi_ec *)seq->private;
if (!ec)
goto end;
seq_printf(seq, "gpe bit: 0x%02x\n",
- (u32) ec->common.gpe_bit);
+ (u32) ec->gpe_bit);
seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
- (u32) ec->common.status_addr.address,
- (u32) ec->common.data_addr.address);
+ (u32) ec->command_addr,
+ (u32) ec->data_addr);
seq_printf(seq, "use global lock: %s\n",
- ec->common.global_lock ? "yes" : "no");
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+ ec->global_lock ? "yes" : "no");
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
end:
return 0;
@@ -929,7 +593,7 @@ static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
return single_open(file, acpi_ec_read_info, PDE(inode)->data);
}
-static const struct file_operations acpi_ec_info_ops = {
+static struct file_operations acpi_ec_info_ops = {
.open = acpi_ec_info_open_fs,
.read = seq_read,
.llseek = seq_lseek,
@@ -978,101 +642,35 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_ec_poll_add(struct acpi_device *device)
+static int acpi_ec_add(struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
+ struct acpi_ec *ec = NULL;
if (!device)
return -EINVAL;
- ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+ ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec)
return -ENOMEM;
- memset(ec, 0, sizeof(union acpi_ec));
-
- ec->common.handle = device->handle;
- ec->common.uid = -1;
- init_MUTEX(&ec->poll.sem);
- strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_EC_CLASS);
- acpi_driver_data(device) = ec;
-
- /* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
- &ec->common.global_lock);
-
- /* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
- http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
- if (ec_ecdt) {
- acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
- ACPI_ADR_SPACE_EC,
- &acpi_ec_space_handler);
-
- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
- &acpi_ec_gpe_handler);
-
- kfree(ec_ecdt);
+ memset(ec, 0, sizeof(struct acpi_ec));
+
+ ec->handle = device->handle;
+ ec->uid = -1;
+ init_MUTEX(&ec->sem);
+ if (acpi_ec_mode == EC_INTR) {
+ atomic_set(&ec->leaving_burst, 1);
+ init_waitqueue_head(&ec->wait);
}
-
- /* Get GPE bit assignment (EC events). */
- /* TODO: Add support for _GPE returning a package */
- status =
- acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
- &ec->common.gpe_bit);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit"));
- result = -ENODEV;
- goto end;
- }
-
- result = acpi_ec_add_fs(device);
- if (result)
- goto end;
-
- printk(KERN_INFO PREFIX "%s [%s] (gpe %d) polling mode.\n",
- acpi_device_name(device), acpi_device_bid(device),
- (u32) ec->common.gpe_bit);
-
- if (!first_ec)
- first_ec = device;
-
- end:
- if (result)
- kfree(ec);
-
- return result;
-}
-static int acpi_ec_intr_add(struct acpi_device *device)
-{
- int result = 0;
- acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
-
-
- if (!device)
- return -EINVAL;
-
- ec = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
- if (!ec)
- return -ENOMEM;
- memset(ec, 0, sizeof(union acpi_ec));
-
- ec->common.handle = device->handle;
- ec->common.uid = -1;
- atomic_set(&ec->intr.pending_gpe, 0);
- atomic_set(&ec->intr.leaving_burst, 1);
- init_MUTEX(&ec->intr.sem);
- init_waitqueue_head(&ec->intr.wait);
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec;
/* Use the global lock for all EC transactions? */
- acpi_evaluate_integer(ec->common.handle, "_GLK", NULL,
- &ec->common.global_lock);
+ acpi_evaluate_integer(ec->handle, "_GLK", NULL,
+ &ec->global_lock);
/* XXX we don't test uids, because on some boxes ecdt uid = 0, see:
http://bugzilla.kernel.org/show_bug.cgi?id=6111 */
@@ -1081,7 +679,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
&acpi_ec_gpe_handler);
kfree(ec_ecdt);
@@ -1090,10 +688,10 @@ static int acpi_ec_intr_add(struct acpi_device *device)
/* Get GPE bit assignment (EC events). */
/* TODO: Add support for _GPE returning a package */
status =
- acpi_evaluate_integer(ec->common.handle, "_GPE", NULL,
- &ec->common.gpe_bit);
+ acpi_evaluate_integer(ec->handle, "_GPE", NULL,
+ &ec->gpe_bit);
if (ACPI_FAILURE(status)) {
- printk(KERN_ERR PREFIX "Obtaining GPE bit assignment\n");
+ ACPI_EXCEPTION((AE_INFO, status, "Obtaining GPE bit assignment"));
result = -ENODEV;
goto end;
}
@@ -1102,14 +700,14 @@ static int acpi_ec_intr_add(struct acpi_device *device)
if (result)
goto end;
- printk(KERN_INFO PREFIX "%s [%s] (gpe %d) interrupt mode.\n",
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
acpi_device_name(device), acpi_device_bid(device),
- (u32) ec->common.gpe_bit);
+ (u32) ec->gpe_bit));
if (!first_ec)
first_ec = device;
- end:
+ end:
if (result)
kfree(ec);
@@ -1118,7 +716,7 @@ static int acpi_ec_intr_add(struct acpi_device *device)
static int acpi_ec_remove(struct acpi_device *device, int type)
{
- union acpi_ec *ec = NULL;
+ struct acpi_ec *ec = NULL;
if (!device)
@@ -1136,8 +734,7 @@ static int acpi_ec_remove(struct acpi_device *device, int type)
static acpi_status
acpi_ec_io_ports(struct acpi_resource *resource, void *context)
{
- union acpi_ec *ec = (union acpi_ec *)context;
- struct acpi_generic_address *addr;
+ struct acpi_ec *ec = (struct acpi_ec *)context;
if (resource->type != ACPI_RESOURCE_TYPE_IO) {
return AE_OK;
@@ -1148,26 +745,21 @@ acpi_ec_io_ports(struct acpi_resource *resource, void *context)
* the second address region returned is the status/command
* port.
*/
- if (ec->common.data_addr.register_bit_width == 0) {
- addr = &ec->common.data_addr;
- } else if (ec->common.command_addr.register_bit_width == 0) {
- addr = &ec->common.command_addr;
+ if (ec->data_addr == 0) {
+ ec->data_addr = resource->data.io.minimum;
+ } else if (ec->command_addr == 0) {
+ ec->command_addr = resource->data.io.minimum;
} else {
return AE_CTRL_TERMINATE;
}
- addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
- addr->register_bit_width = 8;
- addr->register_bit_offset = 0;
- addr->address = resource->data.io.minimum;
-
return AE_OK;
}
static int acpi_ec_start(struct acpi_device *device)
{
acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
+ struct acpi_ec *ec = NULL;
if (!device)
@@ -1181,39 +773,35 @@ static int acpi_ec_start(struct acpi_device *device)
/*
* Get I/O port addresses. Convert to GAS format.
*/
- status = acpi_walk_resources(ec->common.handle, METHOD_NAME__CRS,
+ status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
acpi_ec_io_ports, ec);
- if (ACPI_FAILURE(status)
- || ec->common.command_addr.register_bit_width == 0) {
- printk(KERN_ERR PREFIX "Error getting I/O port addresses\n");
+ if (ACPI_FAILURE(status) || ec->command_addr == 0) {
+ ACPI_EXCEPTION((AE_INFO, status,
+ "Error getting I/O port addresses"));
return -ENODEV;
}
- ec->common.status_addr = ec->common.command_addr;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n",
- (u32) ec->common.gpe_bit,
- (u32) ec->common.command_addr.address,
- (u32) ec->common.data_addr.address));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
+ ec->gpe_bit, ec->command_addr, ec->data_addr));
/*
* Install GPE handler
*/
- status = acpi_install_gpe_handler(NULL, ec->common.gpe_bit,
+ status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status)) {
return -ENODEV;
}
- acpi_set_gpe_type(NULL, ec->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec->common.gpe_bit, ACPI_NOT_ISR);
+ acpi_set_gpe_type(NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
- status = acpi_install_address_space_handler(ec->common.handle,
+ status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
&acpi_ec_space_setup, ec);
if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec->gpe_bit,
&acpi_ec_gpe_handler);
return -ENODEV;
}
@@ -1224,7 +812,7 @@ static int acpi_ec_start(struct acpi_device *device)
static int acpi_ec_stop(struct acpi_device *device, int type)
{
acpi_status status = AE_OK;
- union acpi_ec *ec = NULL;
+ struct acpi_ec *ec = NULL;
if (!device)
@@ -1232,14 +820,14 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
ec = acpi_driver_data(device);
- status = acpi_remove_address_space_handler(ec->common.handle,
+ status = acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler);
if (ACPI_FAILURE(status))
return -ENODEV;
status =
- acpi_remove_gpe_handler(NULL, ec->common.gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec->gpe_bit,
&acpi_ec_gpe_handler);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -1251,76 +839,30 @@ static acpi_status __init
acpi_fake_ecdt_callback(acpi_handle handle,
u32 Level, void *context, void **retval)
{
-
- if (acpi_ec_poll_mode)
- return acpi_fake_ecdt_poll_callback(handle,
- Level, context, retval);
- else
- return acpi_fake_ecdt_intr_callback(handle,
- Level, context, retval);
-}
-
-static acpi_status __init
-acpi_fake_ecdt_poll_callback(acpi_handle handle,
- u32 Level, void *context, void **retval)
-{
- acpi_status status;
-
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- acpi_ec_io_ports, ec_ecdt);
- if (ACPI_FAILURE(status))
- return status;
- ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
-
- ec_ecdt->common.uid = -1;
- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
-
- status =
- acpi_evaluate_integer(handle, "_GPE", NULL,
- &ec_ecdt->common.gpe_bit);
- if (ACPI_FAILURE(status))
- return status;
- init_MUTEX(&ec_ecdt->poll.sem);
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.handle = handle;
-
- printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
- (u32) ec_ecdt->common.gpe_bit,
- (u32) ec_ecdt->common.command_addr.address,
- (u32) ec_ecdt->common.data_addr.address);
-
- return AE_CTRL_TERMINATE;
-}
-
-static acpi_status __init
-acpi_fake_ecdt_intr_callback(acpi_handle handle,
- u32 Level, void *context, void **retval)
-{
acpi_status status;
- init_MUTEX(&ec_ecdt->intr.sem);
- init_waitqueue_head(&ec_ecdt->intr.wait);
+ init_MUTEX(&ec_ecdt->sem);
+ if (acpi_ec_mode == EC_INTR) {
+ init_waitqueue_head(&ec_ecdt->wait);
+ }
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
acpi_ec_io_ports, ec_ecdt);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->common.status_addr = ec_ecdt->common.command_addr;
- ec_ecdt->common.uid = -1;
- acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->common.uid);
+ ec_ecdt->uid = -1;
+ acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
status =
acpi_evaluate_integer(handle, "_GPE", NULL,
- &ec_ecdt->common.gpe_bit);
+ &ec_ecdt->gpe_bit);
if (ACPI_FAILURE(status))
return status;
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.handle = handle;
+ ec_ecdt->global_lock = TRUE;
+ ec_ecdt->handle = handle;
- printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
- (u32) ec_ecdt->common.gpe_bit,
- (u32) ec_ecdt->common.command_addr.address,
- (u32) ec_ecdt->common.data_addr.address);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
+ ec_ecdt->gpe_bit, ec_ecdt->command_addr, ec_ecdt->data_addr));
return AE_CTRL_TERMINATE;
}
@@ -1340,14 +882,14 @@ static int __init acpi_ec_fake_ecdt(void)
acpi_status status;
int ret = 0;
- printk(KERN_INFO PREFIX "Try to make an fake ECDT\n");
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Try to make an fake ECDT"));
- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec_ecdt) {
ret = -ENOMEM;
goto error;
}
- memset(ec_ecdt, 0, sizeof(union acpi_ec));
+ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
status = acpi_get_devices(ACPI_EC_HID,
acpi_fake_ecdt_callback, NULL, NULL);
@@ -1355,24 +897,16 @@ static int __init acpi_ec_fake_ecdt(void)
kfree(ec_ecdt);
ec_ecdt = NULL;
ret = -ENODEV;
+ ACPI_EXCEPTION((AE_INFO, status, "Can't make an fake ECDT"));
goto error;
}
return 0;
- error:
- printk(KERN_ERR PREFIX "Can't make an fake ECDT\n");
+ error:
return ret;
}
static int __init acpi_ec_get_real_ecdt(void)
{
- if (acpi_ec_poll_mode)
- return acpi_ec_poll_get_real_ecdt();
- else
- return acpi_ec_intr_get_real_ecdt();
-}
-
-static int __init acpi_ec_poll_get_real_ecdt(void)
-{
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
@@ -1382,80 +916,36 @@ static int __init acpi_ec_poll_get_real_ecdt(void)
if (ACPI_FAILURE(status))
return -ENODEV;
- printk(KERN_INFO PREFIX "Found ECDT\n");
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
/*
* Generate a temporary ec context to use until the namespace is scanned
*/
- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
+ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
if (!ec_ecdt)
return -ENOMEM;
- memset(ec_ecdt, 0, sizeof(union acpi_ec));
-
- ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
- ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
- init_MUTEX(&ec_ecdt->poll.sem);
- /* use the GL just to be safe */
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.uid = ecdt_ptr->uid;
+ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
- status =
- acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
- if (ACPI_FAILURE(status)) {
- goto error;
+ init_MUTEX(&ec_ecdt->sem);
+ if (acpi_ec_mode == EC_INTR) {
+ init_waitqueue_head(&ec_ecdt->wait);
}
-
- return 0;
- error:
- printk(KERN_ERR PREFIX "Could not use ECDT\n");
- kfree(ec_ecdt);
- ec_ecdt = NULL;
-
- return -ENODEV;
-}
-
-static int __init acpi_ec_intr_get_real_ecdt(void)
-{
- acpi_status status;
- struct acpi_table_ecdt *ecdt_ptr;
-
- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
- (struct acpi_table_header **)
- &ecdt_ptr);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- printk(KERN_INFO PREFIX "Found ECDT\n");
-
- /*
- * Generate a temporary ec context to use until the namespace is scanned
- */
- ec_ecdt = kmalloc(sizeof(union acpi_ec), GFP_KERNEL);
- if (!ec_ecdt)
- return -ENOMEM;
- memset(ec_ecdt, 0, sizeof(union acpi_ec));
-
- init_MUTEX(&ec_ecdt->intr.sem);
- init_waitqueue_head(&ec_ecdt->intr.wait);
- ec_ecdt->common.command_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.status_addr = ecdt_ptr->ec_control;
- ec_ecdt->common.data_addr = ecdt_ptr->ec_data;
- ec_ecdt->common.gpe_bit = ecdt_ptr->gpe_bit;
+ ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
+ ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
+ ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
/* use the GL just to be safe */
- ec_ecdt->common.global_lock = TRUE;
- ec_ecdt->common.uid = ecdt_ptr->uid;
+ ec_ecdt->global_lock = TRUE;
+ ec_ecdt->uid = ecdt_ptr->uid;
status =
- acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->common.handle);
+ acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
if (ACPI_FAILURE(status)) {
goto error;
}
return 0;
- error:
- printk(KERN_ERR PREFIX "Could not use ECDT\n");
+ error:
+ ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
kfree(ec_ecdt);
ec_ecdt = NULL;
@@ -1480,14 +970,14 @@ int __init acpi_ec_ecdt_probe(void)
/*
* Install GPE handler
*/
- status = acpi_install_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+ status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec_ecdt);
if (ACPI_FAILURE(status)) {
goto error;
}
- acpi_set_gpe_type(NULL, ec_ecdt->common.gpe_bit, ACPI_GPE_TYPE_RUNTIME);
- acpi_enable_gpe(NULL, ec_ecdt->common.gpe_bit, ACPI_NOT_ISR);
+ acpi_set_gpe_type(NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe(NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
status = acpi_install_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC,
@@ -1495,7 +985,7 @@ int __init acpi_ec_ecdt_probe(void)
&acpi_ec_space_setup,
ec_ecdt);
if (ACPI_FAILURE(status)) {
- acpi_remove_gpe_handler(NULL, ec_ecdt->common.gpe_bit,
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
&acpi_ec_gpe_handler);
goto error;
}
@@ -1503,7 +993,7 @@ int __init acpi_ec_ecdt_probe(void)
return 0;
error:
- printk(KERN_ERR PREFIX "Could not use ECDT\n");
+ ACPI_EXCEPTION((AE_INFO, status, "Could not use ECDT"));
kfree(ec_ecdt);
ec_ecdt = NULL;
@@ -1562,13 +1052,13 @@ static int __init acpi_ec_set_intr_mode(char *str)
return 0;
if (intr) {
- acpi_ec_poll_mode = EC_INTR;
- acpi_ec_driver.ops.add = acpi_ec_intr_add;
+ acpi_ec_mode = EC_INTR;
} else {
- acpi_ec_poll_mode = EC_POLL;
- acpi_ec_driver.ops.add = acpi_ec_poll_add;
+ acpi_ec_mode = EC_POLL;
}
- printk(KERN_INFO PREFIX "EC %s mode.\n", intr ? "interrupt" : "polling");
+ acpi_ec_driver.ops.add = acpi_ec_add;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "EC %s mode.\n", intr ? "interrupt" : "polling"));
+
return 1;
}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 6eef4efddcf6..ee2a10bf9077 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -342,20 +342,8 @@ static u32 acpi_ev_global_lock_handler(void *context)
if (acquired) {
/* Got the lock, now wake all threads waiting for it */
-
acpi_gbl_global_lock_acquired = TRUE;
-
- /* Run the Global Lock thread which will signal all waiting threads */
-
- status =
- acpi_os_execute(OSL_GLOBAL_LOCK_HANDLER,
- acpi_ev_global_lock_thread, context);
- if (ACPI_FAILURE(status)) {
- ACPI_EXCEPTION((AE_INFO, status,
- "Could not queue Global Lock thread"));
-
- return (ACPI_INTERRUPT_NOT_HANDLED);
- }
+ acpi_ev_global_lock_thread(context);
}
return (ACPI_INTERRUPT_HANDLED);
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 5b3c7a85eb9a..203d1359190a 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -225,13 +225,12 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
if (!
(ACPI_STRNCMP
(object_hID.value, PCI_ROOT_HID_STRING,
- sizeof(PCI_ROOT_HID_STRING))
- ||
- !(ACPI_STRNCMP
- (object_hID.value,
- PCI_EXPRESS_ROOT_HID_STRING,
- sizeof(PCI_EXPRESS_ROOT_HID_STRING)))))
- {
+ sizeof(PCI_ROOT_HID_STRING)))
+ ||
+ !(ACPI_STRNCMP
+ (object_hID.value,
+ PCI_EXPRESS_ROOT_HID_STRING,
+ sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
/* Install a handler for this PCI root bridge */
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index 3143f36fcec9..fa58c1edce1e 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -665,8 +665,6 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
/*
* Perform a read first to preserve certain bits (per ACPI spec)
- *
- * Note: This includes SCI_EN, we never want to change this bit
*/
status = acpi_hw_register_read(ACPI_MTX_DO_NOT_LOCK,
ACPI_REGISTER_PM1_CONTROL,
diff --git a/drivers/acpi/i2c_ec.c b/drivers/acpi/i2c_ec.c
index 6809c283ec58..6342e612c203 100644
--- a/drivers/acpi/i2c_ec.c
+++ b/drivers/acpi/i2c_ec.c
@@ -293,7 +293,7 @@ static u32 acpi_ec_smb_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC);
}
-static struct i2c_algorithm acpi_ec_smbus_algorithm = {
+static const struct i2c_algorithm acpi_ec_smbus_algorithm = {
.smbus_xfer = acpi_ec_smb_access,
.functionality = acpi_ec_smb_func,
};
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 15fc12482ba0..003a9876c968 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -1702,13 +1702,11 @@ static struct ibm_struct ibms[] = {
.name = "brightness",
.read = brightness_read,
.write = brightness_write,
- .experimental = 1,
},
{
.name = "volume",
.read = volume_read,
.write = volume_write,
- .experimental = 1,
},
{
.name = "fan",
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
index ec6b7f9ede34..2e17ec75af03 100644
--- a/drivers/acpi/motherboard.c
+++ b/drivers/acpi/motherboard.c
@@ -48,6 +48,12 @@ ACPI_MODULE_NAME("acpi_motherboard")
* the io ports if they really know they can use it, while
* still preventing hotplug PCI devices from using it.
*/
+
+/*
+ * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
+ * and PNP0C02, redundant with acpi_reserve_io_ranges().
+ * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
+ */
static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
{
struct resource *requested_res = NULL;
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 507f051d1cef..c84286cbbe25 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -73,6 +73,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;
acpi_status acpi_os_initialize(void)
{
@@ -91,8 +92,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;
}
@@ -104,6 +106,7 @@ acpi_status acpi_os_terminate(void)
}
destroy_workqueue(kacpid_wq);
+ destroy_workqueue(kacpi_notify_wq);
return AE_OK;
}
@@ -237,7 +240,7 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
return AE_OK;
}
-static irqreturn_t acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t acpi_irq(int irq, void *dev_id)
{
return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
}
@@ -566,10 +569,7 @@ void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
static void acpi_os_execute_deferred(void *context)
{
- struct acpi_os_dpc *dpc = NULL;
-
-
- dpc = (struct acpi_os_dpc *)context;
+ struct acpi_os_dpc *dpc = (struct acpi_os_dpc *)context;
if (!dpc) {
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
return;
@@ -604,14 +604,12 @@ acpi_status acpi_os_execute(acpi_execute_type type,
struct acpi_os_dpc *dpc;
struct work_struct *task;
- 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
@@ -624,26 +622,20 @@ acpi_status acpi_os_execute(acpi_execute_type type,
* from the same memory.
*/
- dpc =
- kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
- GFP_ATOMIC);
+ dpc = kmalloc(sizeof(struct acpi_os_dpc) +
+ sizeof(struct work_struct), GFP_ATOMIC);
if (!dpc)
- return_ACPI_STATUS(AE_NO_MEMORY);
-
+ return AE_NO_MEMORY;
dpc->function = function;
dpc->context = context;
-
task = (void *)(dpc + 1);
INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
-
- if (!queue_work(kacpid_wq, task)) {
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Call to queue_work() failed.\n"));
- kfree(dpc);
+ if (!queue_work((type == OSL_NOTIFY_HANDLER)?
+ kacpi_notify_wq : kacpid_wq, task)) {
status = AE_ERROR;
+ kfree(dpc);
}
-
- return_ACPI_STATUS(status);
+ return status;
}
EXPORT_SYMBOL(acpi_os_execute);
@@ -1079,7 +1071,7 @@ acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
{
- (void)kmem_cache_destroy(cache);
+ kmem_cache_destroy(cache);
return (AE_OK);
}
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 7f3e7e77e794..d53bd9878ca2 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -307,7 +307,7 @@ static int acpi_pci_link_set(struct acpi_pci_link *link, int irq)
if (!link || !irq)
return -EINVAL;
- resource = kmalloc(sizeof(*resource) + 1, GFP_ATOMIC);
+ resource = kmalloc(sizeof(*resource) + 1, irqs_disabled() ? GFP_ATOMIC: GFP_KERNEL);
if (!resource)
return -ENOMEM;
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
index fec225d1b6b7..fe67a8af520e 100644
--- a/drivers/acpi/power.c
+++ b/drivers/acpi/power.c
@@ -216,10 +216,8 @@ static int acpi_power_off_device(acpi_handle handle)
{
int result = 0;
acpi_status status = AE_OK;
- struct acpi_device *device = NULL;
struct acpi_power_resource *resource = NULL;
-
result = acpi_power_get_context(handle, &resource);
if (result)
return result;
@@ -230,13 +228,13 @@ static int acpi_power_off_device(acpi_handle handle)
if (resource->references) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Resource [%s] is still in use, dereferencing\n",
- device->pnp.bus_id));
+ resource->device->pnp.bus_id));
return 0;
}
if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
- device->pnp.bus_id));
+ resource->device->pnp.bus_id));
return 0;
}
@@ -251,8 +249,7 @@ static int acpi_power_off_device(acpi_handle handle)
return -ENOEXEC;
/* Update the power resource's _device_ power state */
- device = resource->device;
- device->power.state = ACPI_STATE_D3;
+ resource->device->power.state = ACPI_STATE_D3;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
resource->name));
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index b13d64415b7a..1908e0d20222 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -519,7 +519,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
static void *processor_device_array[NR_CPUS];
-static int acpi_processor_start(struct acpi_device *device)
+static int __cpuinit acpi_processor_start(struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 71066066d626..65b3f056ad89 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -38,6 +38,7 @@
#include <linux/dmi.h>
#include <linux/moduleparam.h>
#include <linux/sched.h> /* need_resched() */
+#include <linux/latency.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -218,6 +219,23 @@ static void acpi_safe_halt(void)
static atomic_t c3_cpu_count;
+/* Common C-state entry for C2, C3, .. */
+static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
+{
+ if (cstate->space_id == ACPI_CSTATE_FFH) {
+ /* Call into architectural FFH based C-state */
+ acpi_processor_ffh_cstate_enter(cstate);
+ } else {
+ int unused;
+ /* IO port based C-state */
+ inb(cstate->address);
+ /* Dummy wait op - must do something useless after P_LVL2 read
+ because chipsets cannot guarantee that STPCLK# signal
+ gets asserted in time to freeze execution properly. */
+ unused = inl(acpi_fadt.xpm_tmr_blk.address);
+ }
+}
+
static void acpi_processor_idle(void)
{
struct acpi_processor *pr = NULL;
@@ -360,11 +378,7 @@ static void acpi_processor_idle(void)
/* Get start time (ticks) */
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke C2 */
- inb(cx->address);
- /* Dummy wait op - must do something useless after P_LVL2 read
- because chipsets cannot guarantee that STPCLK# signal
- gets asserted in time to freeze execution properly. */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
@@ -400,9 +414,7 @@ static void acpi_processor_idle(void)
/* Get start time (ticks) */
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke C3 */
- inb(cx->address);
- /* Dummy wait op (see above) */
- t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ acpi_cstate_enter(cx);
/* Get end time (ticks) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
if (pr->flags.bm_check) {
@@ -453,7 +465,8 @@ static void acpi_processor_idle(void)
*/
if (cx->promotion.state &&
((cx->promotion.state - pr->power.states) <= max_cstate)) {
- if (sleep_ticks > cx->promotion.threshold.ticks) {
+ if (sleep_ticks > cx->promotion.threshold.ticks &&
+ cx->promotion.state->latency <= system_latency_constraint()) {
cx->promotion.count++;
cx->demotion.count = 0;
if (cx->promotion.count >=
@@ -494,8 +507,10 @@ static void acpi_processor_idle(void)
end:
/*
* Demote if current state exceeds max_cstate
+ * or if the latency of the current state is unacceptable
*/
- if ((pr->power.state - pr->power.states) > max_cstate) {
+ if ((pr->power.state - pr->power.states) > max_cstate ||
+ pr->power.state->latency > system_latency_constraint()) {
if (cx->demotion.state)
next_state = cx->demotion.state;
}
@@ -624,20 +639,16 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
return 0;
}
-static int acpi_processor_get_power_info_default_c1(struct acpi_processor *pr)
+static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
{
-
- /* Zero initialize all the C-states info. */
- memset(pr->power.states, 0, sizeof(pr->power.states));
-
- /* set the first C-State to C1 */
- pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
-
- /* the C0 state only exists as a filler in our array,
- * and all processors need to support C1 */
+ if (!pr->power.states[ACPI_STATE_C1].valid) {
+ /* set the first C-State to C1 */
+ /* all processors need to support C1 */
+ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+ pr->power.states[ACPI_STATE_C1].valid = 1;
+ }
+ /* the C0 state only exists as a filler in our array */
pr->power.states[ACPI_STATE_C0].valid = 1;
- pr->power.states[ACPI_STATE_C1].valid = 1;
-
return 0;
}
@@ -654,12 +665,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
if (nocst)
return -ENODEV;
- current_count = 1;
-
- /* Zero initialize C2 onwards and prepare for fresh CST lookup */
- for (i = 2; i < ACPI_PROCESSOR_MAX_POWER; i++)
- memset(&(pr->power.states[i]), 0,
- sizeof(struct acpi_processor_cx));
+ current_count = 0;
status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
@@ -714,22 +720,39 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
(reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
continue;
- cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
- 0 : reg->address;
-
/* There should be an easy way to extract an integer... */
obj = (union acpi_object *)&(element->package.elements[1]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
cx.type = obj->integer.value;
-
- if ((cx.type != ACPI_STATE_C1) &&
- (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
- continue;
-
- if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
- continue;
+ /*
+ * Some buggy BIOSes won't list C1 in _CST -
+ * Let acpi_processor_get_power_info_default() handle them later
+ */
+ if (i == 1 && cx.type != ACPI_STATE_C1)
+ current_count++;
+
+ cx.address = reg->address;
+ cx.index = current_count + 1;
+
+ cx.space_id = ACPI_CSTATE_SYSTEMIO;
+ if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
+ if (acpi_processor_ffh_cstate_probe
+ (pr->id, &cx, reg) == 0) {
+ cx.space_id = ACPI_CSTATE_FFH;
+ } else if (cx.type != ACPI_STATE_C1) {
+ /*
+ * C1 is a special case where FIXED_HARDWARE
+ * can be handled in non-MWAIT way as well.
+ * In that case, save this _CST entry info.
+ * That is, we retain space_id of SYSTEM_IO for
+ * halt based C1.
+ * Otherwise, ignore this info and continue.
+ */
+ continue;
+ }
+ }
obj = (union acpi_object *)&(element->package.elements[2]);
if (obj->type != ACPI_TYPE_INTEGER)
@@ -934,11 +957,17 @@ static int acpi_processor_get_power_info(struct acpi_processor *pr)
/* NOTE: the idle thread may not be running while calling
* this function */
- /* Adding C1 state */
- acpi_processor_get_power_info_default_c1(pr);
+ /* Zero initialize all the C-states info. */
+ memset(pr->power.states, 0, sizeof(pr->power.states));
+
result = acpi_processor_get_power_info_cst(pr);
if (result == -ENODEV)
- acpi_processor_get_power_info_fadt(pr);
+ result = acpi_processor_get_power_info_fadt(pr);
+
+ if (result)
+ return result;
+
+ acpi_processor_get_power_info_default(pr);
pr->power.count = acpi_processor_power_verify(pr);
@@ -1009,9 +1038,11 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
seq_printf(seq, "active state: C%zd\n"
"max_cstate: C%d\n"
- "bus master activity: %08x\n",
+ "bus master activity: %08x\n"
+ "maximum allowed latency: %d usec\n",
pr->power.state ? pr->power.state - pr->power.states : 0,
- max_cstate, (unsigned)pr->power.bm_activity);
+ max_cstate, (unsigned)pr->power.bm_activity,
+ system_latency_constraint());
seq_puts(seq, "states:\n");
@@ -1077,7 +1108,31 @@ static const struct file_operations acpi_processor_power_fops = {
.release = single_release,
};
-int acpi_processor_power_init(struct acpi_processor *pr,
+#ifdef CONFIG_SMP
+static void smp_callback(void *v)
+{
+ /* we already woke the CPU up, nothing more to do */
+}
+
+/*
+ * This function gets called when a part of the kernel has a new latency
+ * requirement. This means we need to get all processors out of their C-state,
+ * and then recalculate a new suitable C-state. Just do a cross-cpu IPI; that
+ * wakes them all right up.
+ */
+static int acpi_processor_latency_notify(struct notifier_block *b,
+ unsigned long l, void *v)
+{
+ smp_call_function(smp_callback, NULL, 0, 1);
+ return NOTIFY_OK;
+}
+
+static struct notifier_block acpi_processor_latency_notifier = {
+ .notifier_call = acpi_processor_latency_notify,
+};
+#endif
+
+int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device)
{
acpi_status status = 0;
@@ -1093,6 +1148,9 @@ int acpi_processor_power_init(struct acpi_processor *pr,
"ACPI: processor limited to max C-state %d\n",
max_cstate);
first_run++;
+#ifdef CONFIG_SMP
+ register_latency_notifier(&acpi_processor_latency_notifier);
+#endif
}
if (!pr)
@@ -1164,6 +1222,9 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
* copies of pm_idle before proceeding.
*/
cpu_idle_wait();
+#ifdef CONFIG_SMP
+ unregister_latency_notifier(&acpi_processor_latency_notifier);
+#endif
}
return 0;
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index 62bef0b3b614..8908a975e575 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -98,11 +98,11 @@ static int update_info_mode = UPDATE_INFO_MODE;
static int update_time = UPDATE_TIME;
static int update_time2 = UPDATE_TIME2;
-module_param(capacity_mode, int, CAPACITY_UNIT);
-module_param(update_mode, int, UPDATE_MODE);
-module_param(update_info_mode, int, UPDATE_INFO_MODE);
-module_param(update_time, int, UPDATE_TIME);
-module_param(update_time2, int, UPDATE_TIME2);
+module_param(capacity_mode, int, 0);
+module_param(update_mode, int, 0);
+module_param(update_info_mode, int, 0);
+module_param(update_time, int, 0);
+module_param(update_time2, int, 0);
static int acpi_sbs_add(struct acpi_device *device);
static int acpi_sbs_remove(struct acpi_device *device, int type);
@@ -1685,10 +1685,16 @@ static int acpi_sbs_add(struct acpi_device *device)
int acpi_sbs_remove(struct acpi_device *device, int type)
{
- struct acpi_sbs *sbs = (struct acpi_sbs *)acpi_driver_data(device);
+ struct acpi_sbs *sbs = NULL;
int id;
- if (!device || !sbs) {
+ if (!device) {
+ return -EINVAL;
+ }
+
+ sbs = (struct acpi_sbs *)acpi_driver_data(device);
+
+ if (!sbs) {
return -EINVAL;
}
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
index 7856db759af0..11e2d4454e05 100644
--- a/drivers/acpi/tables/tbget.c
+++ b/drivers/acpi/tables/tbget.c
@@ -324,7 +324,7 @@ acpi_tb_get_this_table(struct acpi_pointer *address,
if (header->length < sizeof(struct acpi_table_header)) {
ACPI_ERROR((AE_INFO,
- "Table length (%X) is smaller than minimum (%X)",
+ "Table length (%X) is smaller than minimum (%zX)",
header->length, sizeof(struct acpi_table_header)));
return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
index 0ad3dbb9ebca..86a5fca9b739 100644
--- a/drivers/acpi/tables/tbrsdt.c
+++ b/drivers/acpi/tables/tbrsdt.c
@@ -187,7 +187,7 @@ acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
if (table_ptr->length < sizeof(struct acpi_table_header)) {
ACPI_ERROR((AE_INFO,
- "RSDT/XSDT length (%X) is smaller than minimum (%X)",
+ "RSDT/XSDT length (%X) is smaller than minimum (%zX)",
table_ptr->length,
sizeof(struct acpi_table_header)));
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 99837d932f36..3f4aa0c99ee4 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -311,7 +311,7 @@ config PATA_JMICRON
config PATA_LEGACY
tristate "Legacy ISA PATA support (Experimental)"
- depends on PCI && EXPERIMENTAL
+ depends on ISA && EXPERIMENTAL
help
This option enables support for ISA/VLB bus legacy PATA
ports and allows them to be accessed via the new ATA layer.
@@ -400,6 +400,7 @@ config PATA_PDC_OLD
config PATA_QDI
tristate "QDI VLB PATA support"
+ depends on ISA
help
Support for QDI 6500 and 6580 PATA controllers on VESA local bus.
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 1aabc81d82f1..25929123ffff 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -204,7 +204,7 @@ static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static unsigned int ahci_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t ahci_interrupt (int irq, void *dev_instance);
static void ahci_irq_clear(struct ata_port *ap);
static int ahci_port_start(struct ata_port *ap);
static void ahci_port_stop(struct ata_port *ap);
@@ -299,76 +299,46 @@ static const struct ata_port_info ahci_port_info[] = {
static const struct pci_device_id ahci_pci_tbl[] = {
/* Intel */
- { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH6 */
- { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH6M */
- { PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7 */
- { PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7M */
- { PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7R */
- { PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ULi M5288 */
- { PCI_VENDOR_ID_INTEL, 0x2681, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x2682, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ESB2 */
- { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH7-M DH */
- { PCI_VENDOR_ID_INTEL, 0x2821, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2822, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2824, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8 */
- { PCI_VENDOR_ID_INTEL, 0x2829, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8M */
- { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x2652), board_ahci }, /* ICH6 */
+ { PCI_VDEVICE(INTEL, 0x2653), board_ahci }, /* ICH6M */
+ { PCI_VDEVICE(INTEL, 0x27c1), board_ahci }, /* ICH7 */
+ { PCI_VDEVICE(INTEL, 0x27c5), board_ahci }, /* ICH7M */
+ { PCI_VDEVICE(INTEL, 0x27c3), board_ahci }, /* ICH7R */
+ { PCI_VDEVICE(AL, 0x5288), board_ahci }, /* ULi M5288 */
+ { PCI_VDEVICE(INTEL, 0x2681), board_ahci }, /* ESB2 */
+ { PCI_VDEVICE(INTEL, 0x2682), board_ahci }, /* ESB2 */
+ { PCI_VDEVICE(INTEL, 0x2683), board_ahci }, /* ESB2 */
+ { PCI_VDEVICE(INTEL, 0x27c6), board_ahci }, /* ICH7-M DH */
+ { PCI_VDEVICE(INTEL, 0x2821), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2822), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2824), board_ahci }, /* ICH8 */
+ { PCI_VDEVICE(INTEL, 0x2829), board_ahci }, /* ICH8M */
+ { PCI_VDEVICE(INTEL, 0x282a), board_ahci }, /* ICH8M */
/* JMicron */
- { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB360 */
- { 0x197b, 0x2361, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB361 */
- { 0x197b, 0x2363, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB363 */
- { 0x197b, 0x2365, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB365 */
- { 0x197b, 0x2366, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* JMicron JMB366 */
+ { PCI_VDEVICE(JMICRON, 0x2360), board_ahci }, /* JMicron JMB360 */
+ { PCI_VDEVICE(JMICRON, 0x2361), board_ahci }, /* JMicron JMB361 */
+ { PCI_VDEVICE(JMICRON, 0x2363), board_ahci }, /* JMicron JMB363 */
+ { PCI_VDEVICE(JMICRON, 0x2365), board_ahci }, /* JMicron JMB365 */
+ { PCI_VDEVICE(JMICRON, 0x2366), board_ahci }, /* JMicron JMB366 */
/* ATI */
- { PCI_VENDOR_ID_ATI, 0x4380, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ATI SB600 non-raid */
- { PCI_VENDOR_ID_ATI, 0x4381, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* ATI SB600 raid */
+ { PCI_VDEVICE(ATI, 0x4380), board_ahci }, /* ATI SB600 non-raid */
+ { PCI_VDEVICE(ATI, 0x4381), board_ahci }, /* ATI SB600 raid */
/* VIA */
- { PCI_VENDOR_ID_VIA, 0x3349, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci_vt8251 }, /* VIA VT8251 */
+ { PCI_VDEVICE(VIA, 0x3349), board_ahci_vt8251 }, /* VIA VT8251 */
/* NVIDIA */
- { PCI_VENDOR_ID_NVIDIA, 0x044c, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
- { PCI_VENDOR_ID_NVIDIA, 0x044f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044c), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044d), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044e), board_ahci }, /* MCP65 */
+ { PCI_VDEVICE(NVIDIA, 0x044f), board_ahci }, /* MCP65 */
/* SiS */
- { PCI_VENDOR_ID_SI, 0x1184, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* SiS 966 */
- { PCI_VENDOR_ID_SI, 0x1185, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* SiS 966 */
- { PCI_VENDOR_ID_SI, 0x0186, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_ahci }, /* SiS 968 */
+ { PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x1185), board_ahci }, /* SiS 966 */
+ { PCI_VDEVICE(SI, 0x0186), board_ahci }, /* SiS 968 */
{ } /* terminate list */
};
@@ -1089,7 +1059,7 @@ static void ahci_irq_clear(struct ata_port *ap)
/* TODO */
}
-static irqreturn_t ahci_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t ahci_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ahci_host_priv *hpriv;
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 1d1c30a2fcd0..377425e71391 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -143,7 +143,7 @@ static struct ata_port_operations generic_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index ffa111eea9da..5719704eb0ee 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -643,11 +643,9 @@ static int piix_pata_prereset(struct ata_port *ap)
{
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no])) {
- ata_port_printk(ap, KERN_INFO, "port disabled. ignoring.\n");
- ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->port_no]))
+ return -ENOENT;
+
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 753b0152afd1..83728a9457ad 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -870,7 +870,11 @@ static unsigned int ata_id_xfermask(const u16 *id)
* the PIO timing number for the maximum. Turn it into
* a mask.
*/
- pio_mask = (2 << (id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ;
+ u8 mode = id[ATA_ID_OLD_PIO_MODES] & 0xFF;
+ if (mode < 5) /* Valid PIO range */
+ pio_mask = (2 << mode) - 1;
+ else
+ pio_mask = 1;
/* But wait.. there's more. Design your standards by
* committee and you too can get a free iordy field to
@@ -2340,7 +2344,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
if (status & ATA_BUSY)
ata_port_printk(ap, KERN_WARNING,
- "port is slow to respond, please be patient\n");
+ "port is slow to respond, please be patient "
+ "(Status 0x%x)\n", status);
timeout = timer_start + tmout;
while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
@@ -2350,7 +2355,8 @@ unsigned int ata_busy_sleep (struct ata_port *ap,
if (status & ATA_BUSY) {
ata_port_printk(ap, KERN_ERR, "port failed to respond "
- "(%lu secs)\n", tmout / HZ);
+ "(%lu secs, Status 0x%x)\n",
+ tmout / HZ, status);
return 1;
}
@@ -4855,7 +4861,6 @@ idle_irq:
* ata_interrupt - Default ATA host interrupt handler
* @irq: irq line (unused)
* @dev_instance: pointer to our ata_host information structure
- * @regs: unused
*
* Default interrupt handler for PCI IDE devices. Calls
* ata_host_intr() for each port that is not disabled.
@@ -4867,7 +4872,7 @@ idle_irq:
* IRQ_NONE or IRQ_HANDLED.
*/
-irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+irqreturn_t ata_interrupt (int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int i;
@@ -5453,6 +5458,11 @@ int ata_device_add(const struct ata_probe_ent *ent)
int rc;
DPRINTK("ENTER\n");
+
+ if (ent->irq == 0) {
+ dev_printk(KERN_ERR, dev, "is not available: No interrupt assigned.\n");
+ return 0;
+ }
/* alloc a container for our list of ATA ports (buses) */
host = kzalloc(sizeof(struct ata_host) +
(ent->n_ports * sizeof(void *)), GFP_KERNEL);
@@ -5473,11 +5483,10 @@ int ata_device_add(const struct ata_probe_ent *ent)
int irq_line = ent->irq;
ap = ata_port_add(ent, host, i);
+ host->ports[i] = ap;
if (!ap)
goto err_out;
- host->ports[i] = ap;
-
/* dummy? */
if (ent->dummy_port_mask & (1 << i)) {
ata_port_printk(ap, KERN_INFO, "DUMMY\n");
@@ -5735,7 +5744,7 @@ void ata_host_remove(struct ata_host *host)
/**
* ata_scsi_release - SCSI layer callback hook for host unload
- * @host: libata host to be unloaded
+ * @shost: libata host to be unloaded
*
* Performs all duties necessary to shut down a libata port...
* Kill port kthread, disable port, and release resources.
@@ -5781,6 +5790,7 @@ ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port)
probe_ent->mwdma_mask = port->mwdma_mask;
probe_ent->udma_mask = port->udma_mask;
probe_ent->port_ops = port->port_ops;
+ probe_ent->private_data = port->private_data;
return probe_ent;
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 3fa80f09f2ae..02b2b2787d9b 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1515,7 +1515,11 @@ static int ata_eh_reset(struct ata_port *ap, int classify,
if (prereset) {
rc = prereset(ap);
if (rc) {
- ata_port_printk(ap, KERN_ERR,
+ if (rc == -ENOENT) {
+ ata_port_printk(ap, KERN_DEBUG, "port disabled. ignoring.\n");
+ ap->eh_context.i.action &= ~ATA_EH_RESET_MASK;
+ } else
+ ata_port_printk(ap, KERN_ERR,
"prereset failed (errno=%d)\n", rc);
return rc;
}
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 3986ec8741b4..7af2a4ba4990 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -164,10 +164,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
{
int rc = 0;
u8 scsi_cmd[MAX_COMMAND_SIZE];
- u8 args[4], *argbuf = NULL;
+ u8 args[4], *argbuf = NULL, *sensebuf = NULL;
int argsize = 0;
- struct scsi_sense_hdr sshdr;
enum dma_data_direction data_dir;
+ int cmd_result;
if (arg == NULL)
return -EINVAL;
@@ -175,6 +175,10 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
if (copy_from_user(args, arg, sizeof(args)))
return -EFAULT;
+ sensebuf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_NOIO);
+ if (!sensebuf)
+ return -ENOMEM;
+
memset(scsi_cmd, 0, sizeof(scsi_cmd));
if (args[3]) {
@@ -191,7 +195,7 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
data_dir = DMA_FROM_DEVICE;
} else {
scsi_cmd[1] = (3 << 1); /* Non-data */
- /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */
+ scsi_cmd[2] = 0x20; /* cc but no off.line or data xfer */
data_dir = DMA_NONE;
}
@@ -210,18 +214,46 @@ int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg)
/* Good values for timeout and retries? Values below
from scsi_ioctl_send_command() for default case... */
- if (scsi_execute_req(scsidev, scsi_cmd, data_dir, argbuf, argsize,
- &sshdr, (10*HZ), 5)) {
+ cmd_result = scsi_execute(scsidev, scsi_cmd, data_dir, argbuf, argsize,
+ sensebuf, (10*HZ), 5, 0);
+
+ if (driver_byte(cmd_result) == DRIVER_SENSE) {/* sense data available */
+ u8 *desc = sensebuf + 8;
+ cmd_result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */
+
+ /* If we set cc then ATA pass-through will cause a
+ * check condition even if no error. Filter that. */
+ if (cmd_result & SAM_STAT_CHECK_CONDITION) {
+ struct scsi_sense_hdr sshdr;
+ scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE,
+ &sshdr);
+ if (sshdr.sense_key==0 &&
+ sshdr.asc==0 && sshdr.ascq==0)
+ cmd_result &= ~SAM_STAT_CHECK_CONDITION;
+ }
+
+ /* Send userspace a few ATA registers (same as drivers/ide) */
+ if (sensebuf[0] == 0x72 && /* format is "descriptor" */
+ desc[0] == 0x09 ) { /* code is "ATA Descriptor" */
+ args[0] = desc[13]; /* status */
+ args[1] = desc[3]; /* error */
+ args[2] = desc[5]; /* sector count (0:7) */
+ if (copy_to_user(arg, args, sizeof(args)))
+ rc = -EFAULT;
+ }
+ }
+
+
+ if (cmd_result) {
rc = -EIO;
goto error;
}
- /* Need code to retrieve data from check condition? */
-
if ((argbuf)
&& copy_to_user(arg + sizeof(args), argbuf, argsize))
rc = -EFAULT;
error:
+ kfree(sensebuf);
kfree(argbuf);
return rc;
}
@@ -889,6 +921,7 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
struct ata_device *dev;
+ unsigned long flags;
int max_depth;
if (queue_depth < 1)
@@ -904,6 +937,14 @@ int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
queue_depth = max_depth;
scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
+
+ spin_lock_irqsave(ap->lock, flags);
+ if (queue_depth > 1)
+ dev->flags &= ~ATA_DFLAG_NCQ_OFF;
+ else
+ dev->flags |= ATA_DFLAG_NCQ_OFF;
+ spin_unlock_irqrestore(ap->lock, flags);
+
return queue_depth;
}
@@ -1293,7 +1334,8 @@ static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicm
*/
goto nothing_to_do;
- if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
+ if ((dev->flags & (ATA_DFLAG_PIO | ATA_DFLAG_NCQ_OFF |
+ ATA_DFLAG_NCQ)) == ATA_DFLAG_NCQ) {
/* yay, NCQ */
if (!lba_48_ok(block, n_block))
goto out_of_range;
@@ -3174,7 +3216,7 @@ void ata_scsi_dev_rescan(void *data)
/**
* ata_sas_port_alloc - Allocate port for a SAS attached SATA device
- * @pdev: PCI device that the scsi device is attached to
+ * @host: ATA host container for all SAS ports
* @port_info: Information from low-level host driver
* @shost: SCSI host that the scsi device is attached to
*
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 688bb55e197a..06daaa3736a2 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -828,7 +828,6 @@ ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int
probe_ent->irq = pdev->irq;
probe_ent->irq_flags = IRQF_SHARED;
- probe_ent->private_data = port[0]->private_data;
if (ports & ATA_PORT_PRIMARY) {
probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0);
@@ -878,10 +877,9 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
return NULL;
probe_ent->n_ports = 2;
- probe_ent->private_data = port[0]->private_data;
if (port_mask & ATA_PORT_PRIMARY) {
- probe_ent->irq = 14;
+ probe_ent->irq = ATA_PRIMARY_IRQ;
probe_ent->port[0].cmd_addr = ATA_PRIMARY_CMD;
probe_ent->port[0].altstatus_addr =
probe_ent->port[0].ctl_addr = ATA_PRIMARY_CTL;
@@ -896,9 +894,9 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
if (port_mask & ATA_PORT_SECONDARY) {
if (probe_ent->irq)
- probe_ent->irq2 = 15;
+ probe_ent->irq2 = ATA_SECONDARY_IRQ;
else
- probe_ent->irq = 15;
+ probe_ent->irq = ATA_SECONDARY_IRQ;
probe_ent->port[1].cmd_addr = ATA_SECONDARY_CMD;
probe_ent->port[1].altstatus_addr =
probe_ent->port[1].ctl_addr = ATA_SECONDARY_CTL;
@@ -908,6 +906,8 @@ static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev,
probe_ent->_host_flags |= ATA_HOST_SIMPLEX;
}
ata_std_ports(&probe_ent->port[1]);
+
+ /* FIXME: could be pointing to stack area; must copy */
probe_ent->pinfo2 = port[1];
} else
probe_ent->dummy_port_mask |= ATA_PORT_SECONDARY;
@@ -946,35 +946,21 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
{
struct ata_probe_ent *probe_ent = NULL;
struct ata_port_info *port[2];
- u8 tmp8, mask;
+ u8 mask;
unsigned int legacy_mode = 0;
int disable_dev_on_err = 1;
int rc;
DPRINTK("ENTER\n");
+ BUG_ON(n_ports < 1 || n_ports > 2);
+
port[0] = port_info[0];
if (n_ports > 1)
port[1] = port_info[1];
else
port[1] = port[0];
- if ((port[0]->flags & ATA_FLAG_NO_LEGACY) == 0
- && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
- /* TODO: What if one channel is in native mode ... */
- pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
- mask = (1 << 2) | (1 << 0);
- if ((tmp8 & mask) != mask)
- legacy_mode = (1 << 3);
- }
-
- /* FIXME... */
- if ((!legacy_mode) && (n_ports > 2)) {
- printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n");
- n_ports = 2;
- /* For now */
- }
-
/* FIXME: Really for ATA it isn't safe because the device may be
multi-purpose and we want to leave it alone if it was already
enabled. Secondly for shared use as Arjan says we want refcounting
@@ -987,6 +973,16 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
if (rc)
return rc;
+ if ((pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+ u8 tmp8;
+
+ /* TODO: What if one channel is in native mode ... */
+ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+ mask = (1 << 2) | (1 << 0);
+ if ((tmp8 & mask) != mask)
+ legacy_mode = (1 << 3);
+ }
+
rc = pci_request_regions(pdev, DRV_NAME);
if (rc) {
disable_dev_on_err = 0;
@@ -1039,7 +1035,7 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
goto err_out_regions;
}
- /* FIXME: If we get no DMA mask we should fall back to PIO */
+ /* TODO: If we get no DMA mask we should fall back to PIO */
rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
if (rc)
goto err_out_regions;
@@ -1062,13 +1058,17 @@ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
pci_set_master(pdev);
- /* FIXME: check ata_device_add return */
- ata_device_add(probe_ent);
+ if (!ata_device_add(probe_ent)) {
+ rc = -ENODEV;
+ goto err_out_ent;
+ }
kfree(probe_ent);
return 0;
+err_out_ent:
+ kfree(probe_ent);
err_out_regions:
if (legacy_mode & ATA_PORT_PRIMARY)
release_region(ATA_PRIMARY_CMD, 8);
diff --git a/drivers/ata/pata_ali.c b/drivers/ata/pata_ali.c
index 8448ee6e0eed..1d695df5860a 100644
--- a/drivers/ata/pata_ali.c
+++ b/drivers/ata/pata_ali.c
@@ -34,7 +34,7 @@
#include <linux/dmi.h>
#define DRV_NAME "pata_ali"
-#define DRV_VERSION "0.6.5"
+#define DRV_VERSION "0.6.6"
/*
* Cable special cases
@@ -369,7 +369,7 @@ static struct ata_port_operations ali_early_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -410,7 +410,7 @@ static struct ata_port_operations ali_20_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -448,7 +448,7 @@ static struct ata_port_operations ali_c2_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -485,7 +485,7 @@ static struct ata_port_operations ali_c5_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -630,7 +630,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
pci_read_config_byte(pdev, 0x53, &tmp);
if (rev <= 0x20)
tmp &= ~0x02;
- if (rev == 0xc7)
+ if (rev >= 0xc7)
tmp |= 0x03;
else
tmp |= 0x01; /* CD_ROM enable for DMA */
@@ -644,10 +644,11 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
-static struct pci_device_id ali[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5228), },
- { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229), },
- { 0, },
+static const struct pci_device_id ali[] = {
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5228), },
+ { PCI_VDEVICE(AL, PCI_DEVICE_ID_AL_M5229), },
+
+ { },
};
static struct pci_driver ali_pci_driver = {
diff --git a/drivers/ata/pata_amd.c b/drivers/ata/pata_amd.c
index 3293cf9a7eb5..29234c897118 100644
--- a/drivers/ata/pata_amd.c
+++ b/drivers/ata/pata_amd.c
@@ -25,7 +25,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.2.3"
+#define DRV_VERSION "0.2.4"
/**
* timing_setup - shared timing computation and load
@@ -137,11 +137,8 @@ static int amd_pre_reset(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 ata66;
- if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
+ return -ENOENT;
pci_read_config_byte(pdev, 0x42, &ata66);
if (ata66 & bitmask[ap->port_no])
@@ -167,11 +164,9 @@ static int amd_early_pre_reset(struct ata_port *ap)
{ 0x40, 1, 0x01, 0x01 }
};
- if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &amd_enable_bits[ap->port_no]))
+ return -ENOENT;
+
/* No host side cable detection */
ap->cbl = ATA_CBL_PATA80;
return ata_std_prereset(ap);
@@ -262,12 +257,8 @@ static int nv_pre_reset(struct ata_port *ap) {
u8 ata66;
u16 udma;
- if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
-
+ if (!pci_test_config_bits(pdev, &nv_enable_bits[ap->port_no]))
+ return -ENOENT;
pci_read_config_byte(pdev, 0x52, &ata66);
if (ata66 & bitmask[ap->port_no])
@@ -368,7 +359,7 @@ static struct ata_port_operations amd33_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -402,7 +393,7 @@ static struct ata_port_operations amd66_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -436,7 +427,7 @@ static struct ata_port_operations amd100_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -470,7 +461,7 @@ static struct ata_port_operations amd133_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -504,7 +495,7 @@ static struct ata_port_operations nv100_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -538,7 +529,7 @@ static struct ata_port_operations nv133_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -671,27 +662,28 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
static const struct pci_device_id amd[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_COBRA_7401, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7409, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7411, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_OPUS_7441, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9 },
- { 0, },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_COBRA_7401), 0 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7409), 1 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_VIPER_7411), 3 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_OPUS_7441), 4 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_8111_IDE), 5 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_IDE), 7 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE), 8 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE), 8 },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_CS5536_IDE), 9 },
+
+ { },
};
static struct pci_driver amd_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = amd,
.probe = amd_init_one,
.remove = ata_pci_remove_one
@@ -707,7 +699,6 @@ static void __exit amd_exit(void)
pci_unregister_driver(&amd_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for AMD PATA IDE");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_artop.c b/drivers/ata/pata_artop.c
index d6ef3bf1bac7..690828eb5226 100644
--- a/drivers/ata/pata_artop.c
+++ b/drivers/ata/pata_artop.c
@@ -28,7 +28,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_artop"
-#define DRV_VERSION "0.4.1"
+#define DRV_VERSION "0.4.2"
/*
* The ARTOP has 33 Mhz and "over clocked" timing tables. Until we
@@ -47,11 +47,9 @@ static int artop6210_pre_reset(struct ata_port *ap)
{ 0x4AU, 1U, 0x04UL, 0x04UL }, /* port 1 */
};
- if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
+ return -ENOENT;
+
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -90,11 +88,9 @@ static int artop6260_pre_reset(struct ata_port *ap)
u8 tmp;
/* Odd numbered device ids are the units with enable bits (the -R cards) */
- if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (pdev->device % 1 && !pci_test_config_bits(pdev, &artop_enable_bits[ap->port_no]))
+ return -ENOENT;
+
pci_read_config_byte(pdev, 0x49, &tmp);
if (tmp & (1 >> ap->port_no))
ap->cbl = ATA_CBL_PATA40;
@@ -344,7 +340,7 @@ static const struct ata_port_operations artop6210_ops = {
.bmdma_status = ata_bmdma_status,
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -379,8 +375,6 @@ static const struct ata_port_operations artop6260_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -432,7 +426,7 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &artop6260_ops,
};
struct ata_port_info *port_info[2];
- struct ata_port_info *info;
+ struct ata_port_info *info = NULL;
int ports = 2;
if (!printed_version++)
@@ -476,16 +470,20 @@ static int artop_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
pci_write_config_byte(pdev, 0x4a, (reg & ~0x01) | 0x80);
}
+
+ BUG_ON(info == NULL);
+
port_info[0] = port_info[1] = info;
return ata_pci_init_one(pdev, port_info, ports);
}
static const struct pci_device_id artop_pci_tbl[] = {
- { 0x1191, 0x0005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { 0x1191, 0x0006, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0x1191, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0x1191, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { 0x1191, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VDEVICE(ARTOP, 0x0005), 0 },
+ { PCI_VDEVICE(ARTOP, 0x0006), 1 },
+ { PCI_VDEVICE(ARTOP, 0x0007), 1 },
+ { PCI_VDEVICE(ARTOP, 0x0008), 2 },
+ { PCI_VDEVICE(ARTOP, 0x0009), 2 },
+
{ } /* terminate list */
};
@@ -506,7 +504,6 @@ static void __exit artop_exit(void)
pci_unregister_driver(&artop_pci_driver);
}
-
module_init(artop_init);
module_exit(artop_exit);
diff --git a/drivers/ata/pata_atiixp.c b/drivers/ata/pata_atiixp.c
index 3f78a1e54a75..1ce28d2125f4 100644
--- a/drivers/ata/pata_atiixp.c
+++ b/drivers/ata/pata_atiixp.c
@@ -22,7 +22,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_atiixp"
-#define DRV_VERSION "0.4.2"
+#define DRV_VERSION "0.4.3"
enum {
ATIIXP_IDE_PIO_TIMING = 0x40,
@@ -41,11 +41,9 @@ static int atiixp_pre_reset(struct ata_port *ap)
{ 0x48, 1, 0x08, 0x00 }
};
- if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &atiixp_enable_bits[ap->port_no]))
+ return -ENOENT;
+
ap->cbl = ATA_CBL_PATA80;
return ata_std_prereset(ap);
}
@@ -244,7 +242,7 @@ static struct ata_port_operations atiixp_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -269,12 +267,13 @@ static int atiixp_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id atiixp[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
- { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
- { 0, },
+static const struct pci_device_id atiixp[] = {
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP200_IDE), },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP300_IDE), },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP400_IDE), },
+ { PCI_VDEVICE(ATI, PCI_DEVICE_ID_ATI_IXP600_IDE), },
+
+ { },
};
static struct pci_driver atiixp_pci_driver = {
@@ -295,7 +294,6 @@ static void __exit atiixp_exit(void)
pci_unregister_driver(&atiixp_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for ATI IXP200/300/400");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cmd64x.c b/drivers/ata/pata_cmd64x.c
index abf1bb7bd322..b9bbd1d454bf 100644
--- a/drivers/ata/pata_cmd64x.c
+++ b/drivers/ata/pata_cmd64x.c
@@ -301,7 +301,7 @@ static struct ata_port_operations cmd64x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -335,7 +335,7 @@ static struct ata_port_operations cmd646r1_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -369,7 +369,7 @@ static struct ata_port_operations cmd648_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -468,16 +468,17 @@ static int cmd64x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
-static struct pci_device_id cmd64x[] = {
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_643, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_646, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_648, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_649, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- { 0, },
+static const struct pci_device_id cmd64x[] = {
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_643), 0 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_646), 1 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_648), 4 },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_CMD_649), 5 },
+
+ { },
};
static struct pci_driver cmd64x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = cmd64x,
.probe = cmd64x_init_one,
.remove = ata_pci_remove_one
@@ -488,13 +489,11 @@ static int __init cmd64x_init(void)
return pci_register_driver(&cmd64x_pci_driver);
}
-
static void __exit cmd64x_exit(void)
{
pci_unregister_driver(&cmd64x_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for CMD64x series PATA controllers");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cs5520.c b/drivers/ata/pata_cs5520.c
index 792ce4828510..2cd3c0ff76df 100644
--- a/drivers/ata/pata_cs5520.c
+++ b/drivers/ata/pata_cs5520.c
@@ -193,8 +193,6 @@ static struct ata_port_operations cs5520_port_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -301,10 +299,11 @@ static void __devexit cs5520_remove_one(struct pci_dev *pdev)
/* For now keep DMA off. We can set it for all but A rev CS5510 once the
core ATA code can handle it */
-static struct pci_device_id pata_cs5520[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
- { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
- { 0, },
+static const struct pci_device_id pata_cs5520[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5510), },
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5520), },
+
+ { },
};
static struct pci_driver cs5520_pci_driver = {
@@ -314,7 +313,6 @@ static struct pci_driver cs5520_pci_driver = {
.remove = cs5520_remove_one
};
-
static int __init cs5520_init(void)
{
return pci_register_driver(&cs5520_pci_driver);
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index f3d8a3bc1e78..a07cc81ef791 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -207,7 +207,7 @@ static struct ata_port_operations cs5530_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = cs5530_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -353,13 +353,14 @@ fail_put:
return -ENODEV;
}
-static struct pci_device_id cs5530[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
- { 0, },
+static const struct pci_device_id cs5530[] = {
+ { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_IDE), },
+
+ { },
};
static struct pci_driver cs5530_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = cs5530,
.probe = cs5530_init_one,
.remove = ata_pci_remove_one
@@ -370,13 +371,11 @@ static int __init cs5530_init(void)
return pci_register_driver(&cs5530_pci_driver);
}
-
static void __exit cs5530_exit(void)
{
pci_unregister_driver(&cs5530_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Cyrix/NS/AMD 5530");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cs5535.c b/drivers/ata/pata_cs5535.c
index 69d6b4258724..f8def3f9c618 100644
--- a/drivers/ata/pata_cs5535.c
+++ b/drivers/ata/pata_cs5535.c
@@ -211,7 +211,7 @@ static struct ata_port_operations cs5535_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -257,9 +257,10 @@ static int cs5535_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, ports, 1);
}
-static struct pci_device_id cs5535[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, 0x002D), },
- { 0, },
+static const struct pci_device_id cs5535[] = {
+ { PCI_VDEVICE(NS, 0x002D), },
+
+ { },
};
static struct pci_driver cs5535_pci_driver = {
@@ -274,13 +275,11 @@ static int __init cs5535_init(void)
return pci_register_driver(&cs5535_pci_driver);
}
-
static void __exit cs5535_exit(void)
{
pci_unregister_driver(&cs5535_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox, Jens Altmann, Wolfgan Zuleger, Alexander Kiausch");
MODULE_DESCRIPTION("low-level driver for the NS/AMD 5530");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_cypress.c b/drivers/ata/pata_cypress.c
index fd55474e0d15..247b43608b14 100644
--- a/drivers/ata/pata_cypress.c
+++ b/drivers/ata/pata_cypress.c
@@ -162,7 +162,7 @@ static struct ata_port_operations cy82c693_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -184,8 +184,8 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
};
static struct ata_port_info *port_info[1] = { &info };
- /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2. For the
- moment we don't handle the secondary. FIXME */
+ /* Devfn 1 is the ATA primary. The secondary is magic and on devfn2.
+ For the moment we don't handle the secondary. FIXME */
if (PCI_FUNC(pdev->devfn) != 1)
return -ENODEV;
@@ -193,13 +193,14 @@ static int cy82c693_init_one(struct pci_dev *pdev, const struct pci_device_id *i
return ata_pci_init_one(pdev, port_info, 1);
}
-static struct pci_device_id cy82c693[] = {
- { PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { 0, },
+static const struct pci_device_id cy82c693[] = {
+ { PCI_VDEVICE(CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693), },
+
+ { },
};
static struct pci_driver cy82c693_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = cy82c693,
.probe = cy82c693_init_one,
.remove = ata_pci_remove_one
diff --git a/drivers/ata/pata_efar.c b/drivers/ata/pata_efar.c
index c30bc181304f..ef18c60fe140 100644
--- a/drivers/ata/pata_efar.c
+++ b/drivers/ata/pata_efar.c
@@ -22,7 +22,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_efar"
-#define DRV_VERSION "0.4.1"
+#define DRV_VERSION "0.4.2"
/**
* efar_pre_reset - check for 40/80 pin
@@ -42,11 +42,9 @@ static int efar_pre_reset(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u8 tmp;
- if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &efar_enable_bits[ap->port_no]))
+ return -ENOENT;
+
pci_read_config_byte(pdev, 0x47, &tmp);
if (tmp & (2 >> ap->port_no))
ap->cbl = ATA_CBL_PATA40;
@@ -263,8 +261,6 @@ static const struct ata_port_operations efar_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -309,7 +305,8 @@ static int efar_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
static const struct pci_device_id efar_pci_tbl[] = {
- { 0x1055, 0x9130, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VDEVICE(EFAR, 0x9130), },
+
{ } /* terminate list */
};
@@ -330,7 +327,6 @@ static void __exit efar_exit(void)
pci_unregister_driver(&efar_pci_driver);
}
-
module_init(efar_init);
module_exit(efar_exit);
diff --git a/drivers/ata/pata_hpt366.c b/drivers/ata/pata_hpt366.c
index 94bb1dfc3f19..6d3e4c0f15fe 100644
--- a/drivers/ata/pata_hpt366.c
+++ b/drivers/ata/pata_hpt366.c
@@ -360,7 +360,7 @@ static struct ata_port_operations hpt366_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -429,7 +429,7 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
/* PCI clocking determines the ATA timing values to use */
/* info_hpt366 is safe against re-entry so we can scribble on it */
- switch(reg1 & 0x700) {
+ switch((reg1 & 0x700) >> 8) {
case 5:
info_hpt366.private_data = &hpt366_40;
break;
@@ -444,13 +444,14 @@ static int hpt36x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt36x[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
- { 0, },
+static const struct pci_device_id hpt36x[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+
+ { },
};
static struct pci_driver hpt36x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt36x,
.probe = hpt36x_init_one,
.remove = ata_pci_remove_one
diff --git a/drivers/ata/pata_hpt37x.c b/drivers/ata/pata_hpt37x.c
index 532a7928f803..7350443948c1 100644
--- a/drivers/ata/pata_hpt37x.c
+++ b/drivers/ata/pata_hpt37x.c
@@ -793,7 +793,7 @@ static struct ata_port_operations hpt370_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -832,7 +832,7 @@ static struct ata_port_operations hpt370a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -872,7 +872,7 @@ static struct ata_port_operations hpt372_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -912,7 +912,7 @@ static struct ata_port_operations hpt374_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -1219,17 +1219,18 @@ static int hpt37x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt37x[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT371), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT374), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
- { 0, },
+static const struct pci_device_id hpt37x[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT371), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT374), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
+
+ { },
};
static struct pci_driver hpt37x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt37x,
.probe = hpt37x_init_one,
.remove = ata_pci_remove_one
@@ -1240,13 +1241,11 @@ static int __init hpt37x_init(void)
return pci_register_driver(&hpt37x_pci_driver);
}
-
static void __exit hpt37x_exit(void)
{
pci_unregister_driver(&hpt37x_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Highpoint HPT37x/30x");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_hpt3x2n.c b/drivers/ata/pata_hpt3x2n.c
index 06c8db079b91..58cfb2bc8098 100644
--- a/drivers/ata/pata_hpt3x2n.c
+++ b/drivers/ata/pata_hpt3x2n.c
@@ -372,7 +372,7 @@ static struct ata_port_operations hpt3x2n_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = hpt3x2n_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -560,16 +560,17 @@ static int hpt3x2n_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt3x2n[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT366), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT302), },
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT372N), },
- { 0, },
+static const struct pci_device_id hpt3x2n[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT366), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT302), },
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT372N), },
+
+ { },
};
static struct pci_driver hpt3x2n_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt3x2n,
.probe = hpt3x2n_init_one,
.remove = ata_pci_remove_one
@@ -580,13 +581,11 @@ static int __init hpt3x2n_init(void)
return pci_register_driver(&hpt3x2n_pci_driver);
}
-
static void __exit hpt3x2n_exit(void)
{
pci_unregister_driver(&hpt3x2n_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the Highpoint HPT3x2n/30x");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_hpt3x3.c b/drivers/ata/pata_hpt3x3.c
index 152770133ab1..3334d72e251b 100644
--- a/drivers/ata/pata_hpt3x3.c
+++ b/drivers/ata/pata_hpt3x3.c
@@ -145,7 +145,7 @@ static struct ata_port_operations hpt3x3_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -192,13 +192,14 @@ static int hpt3x3_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id hpt3x3[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_TTI, PCI_DEVICE_ID_TTI_HPT343), },
- { 0, },
+static const struct pci_device_id hpt3x3[] = {
+ { PCI_VDEVICE(TTI, PCI_DEVICE_ID_TTI_HPT343), },
+
+ { },
};
static struct pci_driver hpt3x3_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = hpt3x3,
.probe = hpt3x3_init_one,
.remove = ata_pci_remove_one
diff --git a/drivers/ata/pata_isapnp.c b/drivers/ata/pata_isapnp.c
index 73948c8b7270..640b8b0954f5 100644
--- a/drivers/ata/pata_isapnp.c
+++ b/drivers/ata/pata_isapnp.c
@@ -52,7 +52,7 @@ static struct ata_port_operations isapnp_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
diff --git a/drivers/ata/pata_it821x.c b/drivers/ata/pata_it821x.c
index af39097d8081..18ff3e59a89b 100644
--- a/drivers/ata/pata_it821x.c
+++ b/drivers/ata/pata_it821x.c
@@ -703,7 +703,7 @@ static struct ata_port_operations it821x_smart_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = it821x_smart_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -739,7 +739,7 @@ static struct ata_port_operations it821x_passthru_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = it821x_passthru_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_clear = ata_bmdma_irq_clear,
@@ -808,14 +808,15 @@ static int it821x_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return ata_pci_init_one(pdev, port_info, 2);
}
-static struct pci_device_id it821x[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211), },
- { PCI_DEVICE(PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212), },
- { 0, },
+static const struct pci_device_id it821x[] = {
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8211), },
+ { PCI_VDEVICE(ITE, PCI_DEVICE_ID_ITE_8212), },
+
+ { },
};
static struct pci_driver it821x_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = it821x,
.probe = it821x_init_one,
.remove = ata_pci_remove_one
@@ -826,13 +827,11 @@ static int __init it821x_init(void)
return pci_register_driver(&it821x_pci_driver);
}
-
static void __exit it821x_exit(void)
{
pci_unregister_driver(&it821x_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for the IT8211/IT8212 IDE RAID controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_jmicron.c b/drivers/ata/pata_jmicron.c
index 6832a643a9eb..52a2bdf3c38d 100644
--- a/drivers/ata/pata_jmicron.c
+++ b/drivers/ata/pata_jmicron.c
@@ -51,7 +51,7 @@ static int jmicron_pre_reset(struct ata_port *ap)
/* Check if our port is enabled */
pci_read_config_dword(pdev, 0x40, &control);
if ((control & port_mask) == 0)
- return 0;
+ return -ENOENT;
/* There are two basic mappings. One has the two SATA ports merged
as master/slave and the secondary as PATA, the other has only the
@@ -164,8 +164,7 @@ static const struct ata_port_operations jmicron_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- /* Timeout handling. Special recovery hooks here */
- .eng_timeout = ata_eng_timeout,
+ /* IRQ-related hooks */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -230,11 +229,12 @@ static int jmicron_init_one (struct pci_dev *pdev, const struct pci_device_id *i
}
static const struct pci_device_id jmicron_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
- { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 361},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 363},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 365},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 366},
+ { PCI_VDEVICE(JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 368},
+
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_legacy.c b/drivers/ata/pata_legacy.c
index ad37c220bb2c..10231ef731d1 100644
--- a/drivers/ata/pata_legacy.c
+++ b/drivers/ata/pata_legacy.c
@@ -161,7 +161,7 @@ static struct ata_port_operations simple_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer_noirq,
.irq_handler = ata_interrupt,
@@ -186,7 +186,7 @@ static struct ata_port_operations legacy_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer_noirq,
.irq_handler = ata_interrupt,
@@ -296,7 +296,7 @@ static struct ata_port_operations pdc20230_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = pdc_data_xfer_vlb,
.irq_handler = ata_interrupt,
@@ -348,7 +348,7 @@ static struct ata_port_operations ht6560a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer, /* Check vlb/noirq */
.irq_handler = ata_interrupt,
@@ -411,7 +411,7 @@ static struct ata_port_operations ht6560b_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer, /* FIXME: Check 32bit and noirq */
.irq_handler = ata_interrupt,
@@ -529,7 +529,7 @@ static struct ata_port_operations opti82c611a_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -659,7 +659,7 @@ static struct ata_port_operations opti82c46x_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = opti82c46x_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
diff --git a/drivers/ata/pata_mpiix.c b/drivers/ata/pata_mpiix.c
index 1958c4ed09a8..9dfe3e9abea3 100644
--- a/drivers/ata/pata_mpiix.c
+++ b/drivers/ata/pata_mpiix.c
@@ -18,7 +18,7 @@
* The driver conciously keeps this logic internally to avoid pushing quirky
* PATA history into the clean libata layer.
*
- * Thinkpad specific note: If you boot an MPIIX using thinkpad with a PCMCIA
+ * Thinkpad specific note: If you boot an MPIIX using a thinkpad with a PCMCIA
* hard disk present this driver will not detect it. This is not a bug. In this
* configuration the secondary port of the MPIIX is disabled and the addresses
* are decoded by the PCMCIA bridge and therefore are for a generic IDE driver
@@ -35,7 +35,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_mpiix"
-#define DRV_VERSION "0.7.1"
+#define DRV_VERSION "0.7.2"
enum {
IDETIM = 0x6C, /* IDE control register */
@@ -54,11 +54,8 @@ static int mpiix_pre_reset(struct ata_port *ap)
{ 0x6F, 1, 0x80, 0x80 }
};
- if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &mpiix_enable_bits[ap->port_no]))
+ return -ENOENT;
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -277,11 +274,10 @@ static void __devexit mpiix_remove_one(struct pci_dev *pdev)
dev_set_drvdata(dev, NULL);
}
-
-
static const struct pci_device_id mpiix[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
- { 0, },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_82371MX), },
+
+ { },
};
static struct pci_driver mpiix_pci_driver = {
@@ -296,13 +292,11 @@ static int __init mpiix_init(void)
return pci_register_driver(&mpiix_pci_driver);
}
-
static void __exit mpiix_exit(void)
{
pci_unregister_driver(&mpiix_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Intel MPIIX");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_netcell.c b/drivers/ata/pata_netcell.c
index 16cb254cb973..f5672de99c22 100644
--- a/drivers/ata/pata_netcell.c
+++ b/drivers/ata/pata_netcell.c
@@ -90,8 +90,7 @@ static const struct ata_port_operations netcell_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- /* Timeout handling. Special recovery hooks here */
- .eng_timeout = ata_eng_timeout,
+ /* IRQ-related hooks */
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -143,7 +142,8 @@ static int netcell_init_one (struct pci_dev *pdev, const struct pci_device_id *e
}
static const struct pci_device_id netcell_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+ { PCI_VDEVICE(NETCELL, PCI_DEVICE_ID_REVOLUTION), },
+
{ } /* terminate list */
};
diff --git a/drivers/ata/pata_ns87410.c b/drivers/ata/pata_ns87410.c
index 93d6646d2954..2a3dbeed89b4 100644
--- a/drivers/ata/pata_ns87410.c
+++ b/drivers/ata/pata_ns87410.c
@@ -45,11 +45,8 @@ static int ns87410_pre_reset(struct ata_port *ap)
{ 0x47, 1, 0x08, 0x08 }
};
- if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &ns87410_enable_bits[ap->port_no]))
+ return -ENOENT;
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -179,7 +176,7 @@ static struct ata_port_operations ns87410_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ns87410_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -203,12 +200,13 @@ static int ns87410_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id ns87410[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410), },
- { 0, },
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_87410), },
+
+ { },
};
static struct pci_driver ns87410_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = ns87410,
.probe = ns87410_init_one,
.remove = ata_pci_remove_one
@@ -219,13 +217,11 @@ static int __init ns87410_init(void)
return pci_register_driver(&ns87410_pci_driver);
}
-
static void __exit ns87410_exit(void)
{
pci_unregister_driver(&ns87410_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Nat Semi 87410");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_oldpiix.c b/drivers/ata/pata_oldpiix.c
index 04c618a2664b..fc947dfecd73 100644
--- a/drivers/ata/pata_oldpiix.c
+++ b/drivers/ata/pata_oldpiix.c
@@ -25,7 +25,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_oldpiix"
-#define DRV_VERSION "0.5.1"
+#define DRV_VERSION "0.5.2"
/**
* oldpiix_pre_reset - probe begin
@@ -42,11 +42,8 @@ static int oldpiix_pre_reset(struct ata_port *ap)
{ 0x43U, 1U, 0x80UL, 0x80UL }, /* port 1 */
};
- if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
+ return -ENOENT;
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -306,7 +303,8 @@ static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *e
}
static const struct pci_device_id oldpiix_pci_tbl[] = {
- { PCI_DEVICE(0x8086, 0x1230), },
+ { PCI_VDEVICE(INTEL, 0x1230), },
+
{ } /* terminate list */
};
@@ -327,7 +325,6 @@ static void __exit oldpiix_exit(void)
pci_unregister_driver(&oldpiix_pci_driver);
}
-
module_init(oldpiix_init);
module_exit(oldpiix_exit);
diff --git a/drivers/ata/pata_opti.c b/drivers/ata/pata_opti.c
index c3d01325e0e2..a7320ba15575 100644
--- a/drivers/ata/pata_opti.c
+++ b/drivers/ata/pata_opti.c
@@ -34,7 +34,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_opti"
-#define DRV_VERSION "0.2.4"
+#define DRV_VERSION "0.2.5"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -59,11 +59,9 @@ static int opti_pre_reset(struct ata_port *ap)
{ 0x40, 1, 0x08, 0x00 }
};
- if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &opti_enable_bits[ap->port_no]))
+ return -ENOENT;
+
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -229,7 +227,7 @@ static struct ata_port_operations opti_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -258,13 +256,14 @@ static int opti_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id opti[] = {
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C621, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { 0, },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C621), 0 },
+ { PCI_VDEVICE(OPTI, PCI_DEVICE_ID_OPTI_82C825), 1 },
+
+ { },
};
static struct pci_driver opti_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = opti,
.probe = opti_init_one,
.remove = ata_pci_remove_one
@@ -275,7 +274,6 @@ static int __init opti_init(void)
return pci_register_driver(&opti_pci_driver);
}
-
static void __exit opti_exit(void)
{
pci_unregister_driver(&opti_pci_driver);
diff --git a/drivers/ata/pata_optidma.c b/drivers/ata/pata_optidma.c
index 177a455f4251..c6906b4215de 100644
--- a/drivers/ata/pata_optidma.c
+++ b/drivers/ata/pata_optidma.c
@@ -33,7 +33,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_optidma"
-#define DRV_VERSION "0.2.1"
+#define DRV_VERSION "0.2.2"
enum {
READ_REG = 0, /* index of Read cycle timing register */
@@ -59,11 +59,9 @@ static int optidma_pre_reset(struct ata_port *ap)
0x40, 1, 0x08, 0x00
};
- if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits)) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (ap->port_no && !pci_test_config_bits(pdev, &optidma_enable_bits))
+ return -ENOENT;
+
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -388,7 +386,7 @@ static struct ata_port_operations optidma_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -423,7 +421,7 @@ static struct ata_port_operations optiplus_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -514,12 +512,13 @@ static int optidma_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id optidma[] = {
- { PCI_DEVICE(0x1045, 0xD568), }, /* Opti 82C700 */
- { 0, },
+ { PCI_VDEVICE(OPTI, 0xD568), }, /* Opti 82C700 */
+
+ { },
};
static struct pci_driver optidma_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = optidma,
.probe = optidma_init_one,
.remove = ata_pci_remove_one
@@ -530,13 +529,11 @@ static int __init optidma_init(void)
return pci_register_driver(&optidma_pci_driver);
}
-
static void __exit optidma_exit(void)
{
pci_unregister_driver(&optidma_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Opti Firestar/Firestar Plus");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_pcmcia.c b/drivers/ata/pata_pcmcia.c
index 62b25cda409b..e93ea2702c73 100644
--- a/drivers/ata/pata_pcmcia.c
+++ b/drivers/ata/pata_pcmcia.c
@@ -42,7 +42,7 @@
#define DRV_NAME "pata_pcmcia"
-#define DRV_VERSION "0.2.9"
+#define DRV_VERSION "0.2.11"
/*
* Private data structure to glue stuff together
@@ -87,7 +87,7 @@ static struct ata_port_operations pcmcia_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer_noirq,
.irq_handler = ata_interrupt,
@@ -355,6 +355,8 @@ static struct pcmcia_device_id pcmcia_devices[] = {
PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+ PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 31ab9c886209..d894d9918b1d 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -36,7 +36,7 @@
#include <asm/io.h>
#define DRV_NAME "pata_pdc2027x"
-#define DRV_VERSION "0.74-ac3"
+#define DRV_VERSION "0.74-ac5"
#undef PDC_DEBUG
#ifdef PDC_DEBUG
@@ -108,13 +108,14 @@ static struct pdc2027x_udma_timing {
};
static const struct pci_device_id pdc2027x_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20268, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20269, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20270, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_100 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20271, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20275, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20276, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
- { PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20277, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20268), PDC_UDMA_100 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20269), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20270), PDC_UDMA_100 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20271), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20275), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20276), PDC_UDMA_133 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20277), PDC_UDMA_133 },
+
{ } /* terminate list */
};
@@ -311,10 +312,8 @@ static inline int pdc2027x_port_enabled(struct ata_port *ap)
static int pdc2027x_prereset(struct ata_port *ap)
{
/* Check whether port enabled */
- if (!pdc2027x_port_enabled(ap)) {
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pdc2027x_port_enabled(ap))
+ return -ENOENT;
pdc2027x_cbl_detect(ap);
return ata_std_prereset(ap);
}
diff --git a/drivers/ata/pata_pdc202xx_old.c b/drivers/ata/pata_pdc202xx_old.c
index 48f43432764e..5ba9eb20a6c2 100644
--- a/drivers/ata/pata_pdc202xx_old.c
+++ b/drivers/ata/pata_pdc202xx_old.c
@@ -385,17 +385,18 @@ static int pdc_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 2);
}
-static struct pci_device_id pdc[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2},
- { 0, },
+static const struct pci_device_id pdc[] = {
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20246), 0 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20262), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20263), 1 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20265), 2 },
+ { PCI_VDEVICE(PROMISE, PCI_DEVICE_ID_PROMISE_20267), 2 },
+
+ { },
};
static struct pci_driver pdc_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = pdc,
.probe = pdc_init_one,
.remove = ata_pci_remove_one
@@ -406,13 +407,11 @@ static int __init pdc_init(void)
return pci_register_driver(&pdc_pci_driver);
}
-
static void __exit pdc_exit(void)
{
pci_unregister_driver(&pdc_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Promise 2024x and 20262-20267");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_qdi.c b/drivers/ata/pata_qdi.c
index 35cfdf0ac3f0..2c3cc0ccc606 100644
--- a/drivers/ata/pata_qdi.c
+++ b/drivers/ata/pata_qdi.c
@@ -141,7 +141,7 @@ static void qdi_data_xfer(struct ata_device *adev, unsigned char *buf, unsigned
memcpy(&pad, buf + buflen - slop, slop);
outl(le32_to_cpu(pad), ap->ioaddr.data_addr);
} else {
- pad = cpu_to_le16(inl(ap->ioaddr.data_addr));
+ pad = cpu_to_le32(inl(ap->ioaddr.data_addr));
memcpy(buf + buflen - slop, &pad, slop);
}
}
@@ -184,7 +184,7 @@ static struct ata_port_operations qdi6500_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = qdi_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = qdi_data_xfer,
.irq_handler = ata_interrupt,
@@ -212,7 +212,7 @@ static struct ata_port_operations qdi6580_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = qdi_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = qdi_data_xfer,
.irq_handler = ata_interrupt,
diff --git a/drivers/ata/pata_radisys.c b/drivers/ata/pata_radisys.c
index 277f8411b521..1af83d7694d5 100644
--- a/drivers/ata/pata_radisys.c
+++ b/drivers/ata/pata_radisys.c
@@ -255,8 +255,6 @@ static const struct ata_port_operations radisys_pata_ops = {
.qc_issue = radisys_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -302,7 +300,8 @@ static int radisys_init_one (struct pci_dev *pdev, const struct pci_device_id *e
}
static const struct pci_device_id radisys_pci_tbl[] = {
- { 0x1331, 0x8201, PCI_ANY_ID, PCI_ANY_ID, },
+ { PCI_VDEVICE(RADISYS, 0x8201), },
+
{ } /* terminate list */
};
@@ -323,7 +322,6 @@ static void __exit radisys_exit(void)
pci_unregister_driver(&radisys_pci_driver);
}
-
module_init(radisys_init);
module_exit(radisys_exit);
diff --git a/drivers/ata/pata_rz1000.c b/drivers/ata/pata_rz1000.c
index 3c6d84fd4312..4533b6357d99 100644
--- a/drivers/ata/pata_rz1000.c
+++ b/drivers/ata/pata_rz1000.c
@@ -112,7 +112,7 @@ static struct ata_port_operations rz1000_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.freeze = ata_bmdma_freeze,
@@ -170,20 +170,20 @@ fail:
return -ENODEV;
}
-static struct pci_device_id pata_rz1000[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
- { PCI_DEVICE(PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
- { 0, },
+static const struct pci_device_id pata_rz1000[] = {
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1000), },
+ { PCI_VDEVICE(PCTECH, PCI_DEVICE_ID_PCTECH_RZ1001), },
+
+ { },
};
static struct pci_driver rz1000_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = pata_rz1000,
.probe = rz1000_init_one,
.remove = ata_pci_remove_one
};
-
static int __init rz1000_init(void)
{
return pci_register_driver(&rz1000_pci_driver);
diff --git a/drivers/ata/pata_sc1200.c b/drivers/ata/pata_sc1200.c
index 4166c1a8a9e8..067d9d223e35 100644
--- a/drivers/ata/pata_sc1200.c
+++ b/drivers/ata/pata_sc1200.c
@@ -217,7 +217,7 @@ static struct ata_port_operations sc1200_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = sc1200_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -253,13 +253,14 @@ static int sc1200_init_one(struct pci_dev *dev, const struct pci_device_id *id)
return ata_pci_init_one(dev, port_info, 1);
}
-static struct pci_device_id sc1200[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
- { 0, },
+static const struct pci_device_id sc1200[] = {
+ { PCI_VDEVICE(NS, PCI_DEVICE_ID_NS_SCx200_IDE), },
+
+ { },
};
static struct pci_driver sc1200_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = sc1200,
.probe = sc1200_init_one,
.remove = ata_pci_remove_one
@@ -270,13 +271,11 @@ static int __init sc1200_init(void)
return pci_register_driver(&sc1200_pci_driver);
}
-
static void __exit sc1200_exit(void)
{
pci_unregister_driver(&sc1200_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox, Mark Lord");
MODULE_DESCRIPTION("low-level driver for the NS/AMD SC1200");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c
index af456113c55d..5bbf76ec14a4 100644
--- a/drivers/ata/pata_serverworks.c
+++ b/drivers/ata/pata_serverworks.c
@@ -41,7 +41,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_serverworks"
-#define DRV_VERSION "0.3.6"
+#define DRV_VERSION "0.3.7"
#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */
#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */
@@ -128,7 +128,7 @@ static struct sv_cable_table cable_detect[] = {
{ PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, dell_cable },
{ PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, dell_cable },
{ PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, sun_cable },
- { PCI_DEVICE_ID_SERVERWORKS_OSB4, PCI_ANY_ID, osb4_cable },
+ { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, osb4_cable },
{ PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, csb_cable },
{ PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, csb_cable },
{ PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, csb_cable },
@@ -352,10 +352,12 @@ static struct ata_port_operations serverworks_osb4_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
.port_start = ata_port_start,
.port_stop = ata_port_stop,
.host_stop = ata_host_stop
@@ -385,10 +387,12 @@ static struct ata_port_operations serverworks_csb_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
+ .irq_clear = ata_bmdma_irq_clear,
+
.port_start = ata_port_start,
.port_stop = ata_port_stop,
.host_stop = ata_host_stop
@@ -549,13 +553,14 @@ static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id
return ata_pci_init_one(pdev, port_info, ports);
}
-static struct pci_device_id serverworks[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
- { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
- { 0, },
+static const struct pci_device_id serverworks[] = {
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2},
+ { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2},
+
+ { },
};
static struct pci_driver serverworks_pci_driver = {
@@ -570,13 +575,11 @@ static int __init serverworks_init(void)
return pci_register_driver(&serverworks_pci_driver);
}
-
static void __exit serverworks_exit(void)
{
pci_unregister_driver(&serverworks_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_sil680.c b/drivers/ata/pata_sil680.c
index 8f7db9638d0a..4a2b72b4be8a 100644
--- a/drivers/ata/pata_sil680.c
+++ b/drivers/ata/pata_sil680.c
@@ -251,7 +251,7 @@ static struct ata_port_operations sil680_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -348,12 +348,13 @@ static int sil680_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
static const struct pci_device_id sil680[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_680), },
- { 0, },
+ { PCI_VDEVICE(CMD, PCI_DEVICE_ID_SII_680), },
+
+ { },
};
static struct pci_driver sil680_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = sil680,
.probe = sil680_init_one,
.remove = ata_pci_remove_one
@@ -364,13 +365,11 @@ static int __init sil680_init(void)
return pci_register_driver(&sil680_pci_driver);
}
-
static void __exit sil680_exit(void)
{
pci_unregister_driver(&sil680_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for SI680 PATA");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_sis.c b/drivers/ata/pata_sis.c
index 2e555168b431..b9ffafb4198c 100644
--- a/drivers/ata/pata_sis.c
+++ b/drivers/ata/pata_sis.c
@@ -34,7 +34,7 @@
#include <linux/ata.h>
#define DRV_NAME "pata_sis"
-#define DRV_VERSION "0.4.3"
+#define DRV_VERSION "0.4.4"
struct sis_chipset {
u16 device; /* PCI host ID */
@@ -74,11 +74,9 @@ static int sis_133_pre_reset(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
u16 tmp;
- if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &sis_enable_bits[ap->port_no]))
+ return -ENOENT;
+
/* The top bit of this register is the cable detect bit */
pci_read_config_word(pdev, 0x50 + 2 * ap->port_no, &tmp);
if (tmp & 0x8000)
@@ -575,8 +573,6 @@ static const struct ata_port_operations sis_133_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -610,8 +606,6 @@ static const struct ata_port_operations sis_133_early_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -646,8 +640,6 @@ static const struct ata_port_operations sis_100_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -681,8 +673,6 @@ static const struct ata_port_operations sis_66_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -716,8 +706,6 @@ static const struct ata_port_operations sis_old_ops = {
.qc_issue = ata_qc_issue_prot,
.data_xfer = ata_pio_data_xfer,
- .eng_timeout = ata_eng_timeout,
-
.irq_handler = ata_interrupt,
.irq_clear = ata_bmdma_irq_clear,
@@ -1000,8 +988,9 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
}
static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5513), }, /* SiS 5513 */
- { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x5518), }, /* SiS 5518 */
+ { PCI_VDEVICE(SI, 0x5513), }, /* SiS 5513 */
+ { PCI_VDEVICE(SI, 0x5518), }, /* SiS 5518 */
+
{ }
};
@@ -1022,7 +1011,6 @@ static void __exit sis_exit(void)
pci_unregister_driver(&sis_pci_driver);
}
-
module_init(sis_init);
module_exit(sis_exit);
diff --git a/drivers/ata/pata_sl82c105.c b/drivers/ata/pata_sl82c105.c
index f8499786917a..08a6dc88676f 100644
--- a/drivers/ata/pata_sl82c105.c
+++ b/drivers/ata/pata_sl82c105.c
@@ -19,7 +19,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_sl82c105"
-#define DRV_VERSION "0.2.2"
+#define DRV_VERSION "0.2.3"
enum {
/*
@@ -49,11 +49,8 @@ static int sl82c105_pre_reset(struct ata_port *ap)
};
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- dev_printk(KERN_INFO, &pdev->dev, "port disabled. ignoring.\n");
- return 0;
- }
+ if (ap->port_no && !pci_test_config_bits(pdev, &sl82c105_enable_bits[ap->port_no]))
+ return -ENOENT;
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -264,7 +261,7 @@ static struct ata_port_operations sl82c105_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -354,9 +351,10 @@ static int sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id
return ata_pci_init_one(dev, port_info, 1); /* For now */
}
-static struct pci_device_id sl82c105[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
- { 0, },
+static const struct pci_device_id sl82c105[] = {
+ { PCI_VDEVICE(WINBOND, PCI_DEVICE_ID_WINBOND_82C105), },
+
+ { },
};
static struct pci_driver sl82c105_pci_driver = {
@@ -371,13 +369,11 @@ static int __init sl82c105_init(void)
return pci_register_driver(&sl82c105_pci_driver);
}
-
static void __exit sl82c105_exit(void)
{
pci_unregister_driver(&sl82c105_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Sl82c105");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_triflex.c b/drivers/ata/pata_triflex.c
index 36f788728f3f..9640f80e8b0d 100644
--- a/drivers/ata/pata_triflex.c
+++ b/drivers/ata/pata_triflex.c
@@ -46,13 +46,13 @@
#define DRV_VERSION "0.2.5"
/**
- * triflex_probe_init - probe begin
+ * triflex_prereset - probe begin
* @ap: ATA port
*
* Set up cable type and use generic probe init
*/
-static int triflex_probe_init(struct ata_port *ap)
+static int triflex_prereset(struct ata_port *ap)
{
static const struct pci_bits triflex_enable_bits[] = {
{ 0x80, 1, 0x01, 0x01 },
@@ -61,11 +61,8 @@ static int triflex_probe_init(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &triflex_enable_bits[ap->port_no]))
+ return -ENOENT;
ap->cbl = ATA_CBL_PATA40;
return ata_std_prereset(ap);
}
@@ -74,7 +71,7 @@ static int triflex_probe_init(struct ata_port *ap)
static void triflex_error_handler(struct ata_port *ap)
{
- ata_bmdma_drive_eh(ap, triflex_probe_init, ata_std_softreset, NULL, ata_std_postreset);
+ ata_bmdma_drive_eh(ap, triflex_prereset, ata_std_softreset, NULL, ata_std_postreset);
}
/**
@@ -221,7 +218,7 @@ static struct ata_port_operations triflex_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -251,13 +248,13 @@ static int triflex_init_one(struct pci_dev *dev, const struct pci_device_id *id)
}
static const struct pci_device_id triflex[] = {
- { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { 0, },
+ { PCI_VDEVICE(COMPAQ, PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE), },
+
+ { },
};
static struct pci_driver triflex_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = triflex,
.probe = triflex_init_one,
.remove = ata_pci_remove_one
@@ -268,13 +265,11 @@ static int __init triflex_init(void)
return pci_register_driver(&triflex_pci_driver);
}
-
static void __exit triflex_exit(void)
{
pci_unregister_driver(&triflex_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for Compaq Triflex");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pata_via.c b/drivers/ata/pata_via.c
index 1b2ff133b163..1e7be9eee9c3 100644
--- a/drivers/ata/pata_via.c
+++ b/drivers/ata/pata_via.c
@@ -60,7 +60,7 @@
#include <linux/libata.h>
#define DRV_NAME "pata_via"
-#define DRV_VERSION "0.1.13"
+#define DRV_VERSION "0.1.14"
/*
* The following comes directly from Vojtech Pavlik's ide/pci/via82cxxx
@@ -155,11 +155,8 @@ static int via_pre_reset(struct ata_port *ap)
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
- if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no])) {
- ata_port_disable(ap);
- printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
- return 0;
- }
+ if (!pci_test_config_bits(pdev, &via_enable_bits[ap->port_no]))
+ return -ENOENT;
}
if ((config->flags & VIA_UDMA) >= VIA_UDMA_66)
@@ -325,7 +322,7 @@ static struct ata_port_operations via_port_ops = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer,
.irq_handler = ata_interrupt,
@@ -360,7 +357,7 @@ static struct ata_port_operations via_port_ops_noirq = {
.qc_prep = ata_qc_prep,
.qc_issue = ata_qc_issue_prot,
- .eng_timeout = ata_eng_timeout,
+
.data_xfer = ata_pio_data_xfer_noirq,
.irq_handler = ata_interrupt,
@@ -532,15 +529,16 @@ static int via_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
}
static const struct pci_device_id via[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576_1), },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1), },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_6410), },
- { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
- { 0, },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C576_1), },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C586_1), },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_6410), },
+ { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_SATA_EIDE), },
+
+ { },
};
static struct pci_driver via_pci_driver = {
- .name = DRV_NAME,
+ .name = DRV_NAME,
.id_table = via,
.probe = via_init_one,
.remove = ata_pci_remove_one
@@ -551,13 +549,11 @@ static int __init via_init(void)
return pci_register_driver(&via_pci_driver);
}
-
static void __exit via_exit(void)
{
pci_unregister_driver(&via_pci_driver);
}
-
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("low-level driver for VIA PATA");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/pdc_adma.c b/drivers/ata/pdc_adma.c
index 0e23ecb77bc2..9021e34d2096 100644
--- a/drivers/ata/pdc_adma.c
+++ b/drivers/ata/pdc_adma.c
@@ -124,8 +124,7 @@ struct adma_port_priv {
static int adma_ata_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent);
-static irqreturn_t adma_intr (int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t adma_intr (int irq, void *dev_instance);
static int adma_port_start(struct ata_port *ap);
static void adma_host_stop(struct ata_host *host);
static void adma_port_stop(struct ata_port *ap);
@@ -192,8 +191,7 @@ static struct ata_port_info adma_port_info[] = {
};
static const struct pci_device_id adma_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PDC, 0x1841, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_1841_idx },
+ { PCI_VDEVICE(PDC, 0x1841), board_1841_idx },
{ } /* terminate list */
};
@@ -509,7 +507,7 @@ static inline unsigned int adma_intr_mmio(struct ata_host *host)
return handled;
}
-static irqreturn_t adma_intr(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t adma_intr(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int handled = 0;
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index fdce6e07ecd2..1b8e0eb9e032 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -348,8 +348,7 @@ static void mv_port_stop(struct ata_port *ap);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
-static irqreturn_t mv_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t mv_interrupt(int irq, void *dev_instance);
static void mv_eng_timeout(struct ata_port *ap);
static int mv_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
@@ -463,6 +462,7 @@ static const struct ata_port_operations mv_iie_ops = {
.qc_prep = mv_qc_prep_iie,
.qc_issue = mv_qc_issue,
+ .data_xfer = ata_mmio_data_xfer,
.eng_timeout = mv_eng_timeout,
@@ -532,19 +532,20 @@ static const struct ata_port_info mv_port_info[] = {
};
static const struct pci_device_id mv_pci_tbl[] = {
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5040), 0, 0, chip_504x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5041), 0, 0, chip_504x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5080), 0, 0, chip_5080},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5081), 0, 0, chip_508x},
-
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6040), 0, 0, chip_604x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6041), 0, 0, chip_604x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6042), 0, 0, chip_6042},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6080), 0, 0, chip_608x},
- {PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x6081), 0, 0, chip_608x},
-
- {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, 0x0241), 0, 0, chip_604x},
- {} /* terminate list */
+ { PCI_VDEVICE(MARVELL, 0x5040), chip_504x },
+ { PCI_VDEVICE(MARVELL, 0x5041), chip_504x },
+ { PCI_VDEVICE(MARVELL, 0x5080), chip_5080 },
+ { PCI_VDEVICE(MARVELL, 0x5081), chip_508x },
+
+ { PCI_VDEVICE(MARVELL, 0x6040), chip_604x },
+ { PCI_VDEVICE(MARVELL, 0x6041), chip_604x },
+ { PCI_VDEVICE(MARVELL, 0x6042), chip_6042 },
+ { PCI_VDEVICE(MARVELL, 0x6080), chip_608x },
+ { PCI_VDEVICE(MARVELL, 0x6081), chip_608x },
+
+ { PCI_VDEVICE(ADAPTEC2, 0x0241), chip_604x },
+
+ { } /* terminate list */
};
static struct pci_driver mv_pci_driver = {
@@ -1446,8 +1447,7 @@ static void mv_host_intr(struct ata_host *host, u32 relevant, unsigned int hc)
* This routine holds the host lock while processing pending
* interrupts.
*/
-static irqreturn_t mv_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t mv_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int hc, handled = 0, n_hcs;
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index 8cd730fe5dd3..323b60710806 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -82,12 +82,9 @@ enum {
static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
static void nv_ck804_host_stop(struct ata_host *host);
-static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
-static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
-static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance);
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance);
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
@@ -106,45 +103,32 @@ enum nv_host_type
};
static const struct pci_device_id nv_pci_tbl[] = {
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
- { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA), NFORCE2 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA), NFORCE3 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2), NFORCE3 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2), CK804 },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2), GENERIC },
+ { PCI_VDEVICE(NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045c), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045d), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045e), GENERIC },
+ { PCI_VDEVICE(NVIDIA, 0x045f), GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC },
- { 0, } /* terminate list */
+
+ { } /* terminate list */
};
static struct pci_driver nv_pci_driver = {
@@ -289,8 +273,7 @@ MODULE_LICENSE("GPL");
MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
MODULE_VERSION(DRV_VERSION);
-static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int i;
@@ -370,8 +353,7 @@ static irqreturn_t nv_do_interrupt(struct ata_host *host, u8 irq_stat)
return IRQ_RETVAL(handled);
}
-static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
u8 irq_stat;
@@ -385,8 +367,7 @@ static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
return ret;
}
-static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
u8 irq_stat;
diff --git a/drivers/ata/sata_promise.c b/drivers/ata/sata_promise.c
index d627812ea73d..72eda5160fad 100644
--- a/drivers/ata/sata_promise.c
+++ b/drivers/ata/sata_promise.c
@@ -93,7 +93,7 @@ struct pdc_host_priv {
static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance);
static void pdc_eng_timeout(struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
static void pdc_port_stop(struct ata_port *ap);
@@ -234,49 +234,33 @@ static const struct ata_port_info pdc_port_info[] = {
};
static const struct pci_device_id pdc_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
- { PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2057x },
- { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2057x },
- { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2037x },
-
- { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3515, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20319 },
- { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_40518 },
-
- { PCI_VENDOR_ID_PROMISE, 0x6629, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20619 },
+ { PCI_VDEVICE(PROMISE, 0x3371), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3570), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3571), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3373), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3375), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3376), board_2037x },
+ { PCI_VDEVICE(PROMISE, 0x3574), board_2057x },
+ { PCI_VDEVICE(PROMISE, 0x3d75), board_2057x },
+ { PCI_VDEVICE(PROMISE, 0x3d73), board_2037x },
+
+ { PCI_VDEVICE(PROMISE, 0x3318), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3319), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3515), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3519), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3d17), board_20319 },
+ { PCI_VDEVICE(PROMISE, 0x3d18), board_40518 },
+
+ { PCI_VDEVICE(PROMISE, 0x6629), board_20619 },
/* TODO: remove all associated board_20771 code, as it completely
* duplicates board_2037x code, unless reason for separation can be
* divined.
*/
#if 0
- { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20771 },
+ { PCI_VDEVICE(PROMISE, 0x3570), board_20771 },
#endif
+ { PCI_VDEVICE(PROMISE, 0x3577), board_20771 },
{ } /* terminate list */
};
@@ -377,7 +361,7 @@ static void pdc_sata_phy_reset(struct ata_port *ap)
static void pdc_pata_cbl_detect(struct ata_port *ap)
{
u8 tmp;
- void __iomem *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT + 0x03;
tmp = readb(mmio);
@@ -515,7 +499,7 @@ static void pdc_irq_clear(struct ata_port *ap)
readl(mmio + PDC_INT_SEQMASK);
}
-static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ata_port *ap;
diff --git a/drivers/ata/sata_qstor.c b/drivers/ata/sata_qstor.c
index fa29dfe2a7b5..710909df4eaf 100644
--- a/drivers/ata/sata_qstor.c
+++ b/drivers/ata/sata_qstor.c
@@ -114,7 +114,7 @@ struct qs_port_priv {
static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t qs_intr (int irq, void *dev_instance);
static int qs_port_start(struct ata_port *ap);
static void qs_host_stop(struct ata_host *host);
static void qs_port_stop(struct ata_port *ap);
@@ -185,8 +185,7 @@ static const struct ata_port_info qs_port_info[] = {
};
static const struct pci_device_id qs_ata_pci_tbl[] = {
- { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_2068_idx },
+ { PCI_VDEVICE(PDC, 0x2068), board_2068_idx },
{ } /* terminate list */
};
@@ -455,7 +454,7 @@ static inline unsigned int qs_intr_mmio(struct ata_host *host)
return handled;
}
-static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t qs_intr(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int handled = 0;
diff --git a/drivers/ata/sata_sil.c b/drivers/ata/sata_sil.c
index c63dbabc0cd9..ca8d99312472 100644
--- a/drivers/ata/sata_sil.c
+++ b/drivers/ata/sata_sil.c
@@ -116,20 +116,20 @@ static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void sil_post_set_mode (struct ata_port *ap);
-static irqreturn_t sil_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t sil_interrupt(int irq, void *dev_instance);
static void sil_freeze(struct ata_port *ap);
static void sil_thaw(struct ata_port *ap);
static const struct pci_device_id sil_pci_tbl[] = {
- { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3512 },
- { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
- { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
- { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
- { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_no_sata_irq },
+ { PCI_VDEVICE(CMD, 0x3112), sil_3112 },
+ { PCI_VDEVICE(CMD, 0x0240), sil_3112 },
+ { PCI_VDEVICE(CMD, 0x3512), sil_3512 },
+ { PCI_VDEVICE(CMD, 0x3114), sil_3114 },
+ { PCI_VDEVICE(ATI, 0x436e), sil_3112 },
+ { PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq },
+ { PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq },
+
{ } /* terminate list */
};
@@ -349,7 +349,7 @@ static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
{
- void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
+ void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg);
if (mmio)
writel(val, mmio);
}
@@ -436,8 +436,7 @@ static void sil_host_intr(struct ata_port *ap, u32 bmdma2)
ata_port_freeze(ap);
}
-static irqreturn_t sil_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t sil_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
void __iomem *mmio_base = host->mmio_base;
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index 39cb07baebae..169e200a6a71 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -330,7 +330,7 @@ static void sil24_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
static void sil24_qc_prep(struct ata_queued_cmd *qc);
static unsigned int sil24_qc_issue(struct ata_queued_cmd *qc);
static void sil24_irq_clear(struct ata_port *ap);
-static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t sil24_interrupt(int irq, void *dev_instance);
static void sil24_freeze(struct ata_port *ap);
static void sil24_thaw(struct ata_port *ap);
static void sil24_error_handler(struct ata_port *ap);
@@ -344,11 +344,12 @@ static int sil24_pci_device_resume(struct pci_dev *pdev);
#endif
static const struct pci_device_id sil24_pci_tbl[] = {
- { 0x1095, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
- { 0x8086, 0x3124, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3124 },
- { 0x1095, 0x3132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3132 },
- { 0x1095, 0x3131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
- { 0x1095, 0x3531, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BID_SIL3131 },
+ { PCI_VDEVICE(CMD, 0x3124), BID_SIL3124 },
+ { PCI_VDEVICE(INTEL, 0x3124), BID_SIL3124 },
+ { PCI_VDEVICE(CMD, 0x3132), BID_SIL3132 },
+ { PCI_VDEVICE(CMD, 0x3131), BID_SIL3131 },
+ { PCI_VDEVICE(CMD, 0x3531), BID_SIL3131 },
+
{ } /* terminate list */
};
@@ -869,7 +870,7 @@ static inline void sil24_host_intr(struct ata_port *ap)
slot_stat, ap->active_tag, ap->sactive);
}
-static irqreturn_t sil24_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t sil24_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct sil24_host_priv *hpriv = host->private_data;
diff --git a/drivers/ata/sata_sis.c b/drivers/ata/sata_sis.c
index 18d49fff8dc4..0738f52463a9 100644
--- a/drivers/ata/sata_sis.c
+++ b/drivers/ata/sata_sis.c
@@ -67,13 +67,13 @@ static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id sis_pci_tbl[] = {
- { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
- { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
- { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+ { PCI_VDEVICE(SI, 0x180), sis_180 },
+ { PCI_VDEVICE(SI, 0x181), sis_180 },
+ { PCI_VDEVICE(SI, 0x182), sis_180 },
+
{ } /* terminate list */
};
-
static struct pci_driver sis_pci_driver = {
.name = DRV_NAME,
.id_table = sis_pci_tbl,
diff --git a/drivers/ata/sata_svw.c b/drivers/ata/sata_svw.c
index d6d6658d8328..db32d15b7fa1 100644
--- a/drivers/ata/sata_svw.c
+++ b/drivers/ata/sata_svw.c
@@ -177,7 +177,7 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
struct ata_port *ap = qc->ap;
unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
u8 dmactl;
- void *mmio = (void *) ap->ioaddr.bmdma_addr;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
/* load PRD table addr. */
mb(); /* make sure PRD table writes are visible to controller */
writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
@@ -205,7 +205,7 @@ static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
- void *mmio = (void *) ap->ioaddr.bmdma_addr;
+ void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
u8 dmactl;
/* start host DMA transaction */
@@ -469,15 +469,15 @@ err_out:
* controller
* */
static const struct pci_device_id k2_sata_pci_tbl[] = {
- { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 },
- { 0x1166, 0x024a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
- { 0x1166, 0x024b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0240), 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0241), 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x0242), 8 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024a), 4 },
+ { PCI_VDEVICE(SERVERWORKS, 0x024b), 4 },
+
{ }
};
-
static struct pci_driver k2_sata_pci_driver = {
.name = DRV_NAME,
.id_table = k2_sata_pci_tbl,
@@ -485,19 +485,16 @@ static struct pci_driver k2_sata_pci_driver = {
.remove = ata_pci_remove_one,
};
-
static int __init k2_sata_init(void)
{
return pci_register_driver(&k2_sata_pci_driver);
}
-
static void __exit k2_sata_exit(void)
{
pci_unregister_driver(&k2_sata_pci_driver);
}
-
MODULE_AUTHOR("Benjamin Herrenschmidt");
MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/ata/sata_sx4.c b/drivers/ata/sata_sx4.c
index 091867e10ea3..ae7992de4b08 100644
--- a/drivers/ata/sata_sx4.c
+++ b/drivers/ata/sata_sx4.c
@@ -152,7 +152,7 @@ struct pdc_host_priv {
static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance);
static void pdc_eng_timeout(struct ata_port *ap);
static void pdc_20621_phy_reset (struct ata_port *ap);
static int pdc_port_start(struct ata_port *ap);
@@ -230,12 +230,11 @@ static const struct ata_port_info pdc_port_info[] = {
};
static const struct pci_device_id pdc_sata_pci_tbl[] = {
- { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
- board_20621 },
+ { PCI_VDEVICE(PROMISE, 0x6622), board_20621 },
+
{ } /* terminate list */
};
-
static struct pci_driver pdc_sata_pci_driver = {
.name = DRV_NAME,
.id_table = pdc_sata_pci_tbl,
@@ -789,7 +788,7 @@ static void pdc20621_irq_clear(struct ata_port *ap)
readl(mmio + PDC_20621_SEQMASK);
}
-static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
struct ata_port *ap;
diff --git a/drivers/ata/sata_uli.c b/drivers/ata/sata_uli.c
index dd76f37be182..5c603ca3a50a 100644
--- a/drivers/ata/sata_uli.c
+++ b/drivers/ata/sata_uli.c
@@ -61,13 +61,13 @@ static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static const struct pci_device_id uli_pci_tbl[] = {
- { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
- { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
- { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
+ { PCI_VDEVICE(AL, 0x5289), uli_5289 },
+ { PCI_VDEVICE(AL, 0x5287), uli_5287 },
+ { PCI_VDEVICE(AL, 0x5281), uli_5281 },
+
{ } /* terminate list */
};
-
static struct pci_driver uli_pci_driver = {
.name = DRV_NAME,
.id_table = uli_pci_tbl,
diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c
index a72a2389a11c..f4455a1efe2d 100644
--- a/drivers/ata/sata_via.c
+++ b/drivers/ata/sata_via.c
@@ -77,9 +77,9 @@ static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
static void vt6420_error_handler(struct ata_port *ap);
static const struct pci_device_id svia_pci_tbl[] = {
- { 0x1106, 0x0591, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
- { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
- { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
+ { PCI_VDEVICE(VIA, 0x0591), vt6420 },
+ { PCI_VDEVICE(VIA, 0x3149), vt6420 },
+ { PCI_VDEVICE(VIA, 0x3249), vt6421 },
{ } /* terminate list */
};
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index d0d92f33de54..e654b990b905 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -203,8 +203,7 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
*
* Read the interrupt register and process for the devices that have them pending.
*/
-static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
unsigned int i;
@@ -442,16 +441,15 @@ err_out:
return rc;
}
-
static const struct pci_device_id vsc_sata_pci_tbl[] = {
{ PCI_VENDOR_ID_VITESSE, 0x7174,
PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
{ PCI_VENDOR_ID_INTEL, 0x3200,
PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+
{ } /* terminate list */
};
-
static struct pci_driver vsc_sata_pci_driver = {
.name = DRV_NAME,
.id_table = vsc_sata_pci_tbl,
@@ -459,19 +457,16 @@ static struct pci_driver vsc_sata_pci_driver = {
.remove = ata_pci_remove_one,
};
-
static int __init vsc_sata_init(void)
{
return pci_register_driver(&vsc_sata_pci_driver);
}
-
static void __exit vsc_sata_exit(void)
{
pci_unregister_driver(&vsc_sata_pci_driver);
}
-
MODULE_AUTHOR("Jeremy Higdon");
MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
MODULE_LICENSE("GPL");
diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c
index 6cc93de0b71d..ac2c10822be0 100644
--- a/drivers/atm/adummy.c
+++ b/drivers/atm/adummy.c
@@ -113,15 +113,13 @@ static int __init adummy_init(void)
printk(KERN_ERR "adummy: version %s\n", DRV_VERSION);
- adummy_dev = (struct adummy_dev *) kmalloc(sizeof(struct adummy_dev),
+ adummy_dev = kzalloc(sizeof(struct adummy_dev),
GFP_KERNEL);
if (!adummy_dev) {
- printk(KERN_ERR DEV_LABEL ": kmalloc() failed\n");
+ printk(KERN_ERR DEV_LABEL ": kzalloc() failed\n");
err = -ENOMEM;
goto out;
}
- memset(adummy_dev, 0, sizeof(struct adummy_dev));
-
atm_dev = atm_dev_register(DEV_LABEL, &adummy_ops, -1, NULL);
if (!atm_dev) {
printk(KERN_ERR DEV_LABEL ": atm_dev_register() failed\n");
diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
index 4521a249dd56..323592de047b 100644
--- a/drivers/atm/ambassador.c
+++ b/drivers/atm/ambassador.c
@@ -861,18 +861,11 @@ static inline void interrupts_off (amb_dev * dev) {
/********** interrupt handling **********/
-static irqreturn_t interrupt_handler(int irq, void *dev_id,
- struct pt_regs *pt_regs) {
- amb_dev * dev = (amb_dev *) dev_id;
- (void) pt_regs;
+static irqreturn_t interrupt_handler(int irq, void *dev_id) {
+ amb_dev * dev = dev_id;
PRINTD (DBG_IRQ|DBG_FLOW, "interrupt_handler: %p", dev_id);
- if (!dev_id) {
- PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq);
- return IRQ_NONE;
- }
-
{
u32 interrupt = rd_plain (dev, offsetof(amb_mem, interrupt));
@@ -915,8 +908,8 @@ static irqreturn_t interrupt_handler(int irq, void *dev_id,
/********** make rate (not quite as much fun as Horizon) **********/
-static unsigned int make_rate (unsigned int rate, rounding r,
- u16 * bits, unsigned int * actual) {
+static int make_rate (unsigned int rate, rounding r,
+ u16 * bits, unsigned int * actual) {
unsigned char exp = -1; // hush gcc
unsigned int man = -1; // hush gcc
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index df359a6c14f6..bc1b13c8f5d7 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -1488,7 +1488,7 @@ static void bug_int(struct atm_dev *dev,unsigned long reason)
}
-static irqreturn_t eni_int(int irq,void *dev_id,struct pt_regs *regs)
+static irqreturn_t eni_int(int irq,void *dev_id)
{
struct atm_dev *dev;
struct eni_dev *eni_dev;
diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c
index 38fc054bd671..40ab9b65fae9 100644
--- a/drivers/atm/firestream.c
+++ b/drivers/atm/firestream.c
@@ -1546,7 +1546,7 @@ static void __devexit free_freepool (struct fs_dev *dev, struct freepool *fp)
-static irqreturn_t fs_irq (int irq, void *dev_id, struct pt_regs * pt_regs)
+static irqreturn_t fs_irq (int irq, void *dev_id)
{
int i;
u32 status;
@@ -1784,7 +1784,7 @@ static int __devinit fs_init (struct fs_dev *dev)
write_fs (dev, RAM, (1 << (28 - FS155_VPI_BITS - FS155_VCI_BITS)) - 1);
dev->nchannels = FS155_NR_CHANNELS;
}
- dev->atm_vccs = kmalloc (dev->nchannels * sizeof (struct atm_vcc *),
+ dev->atm_vccs = kcalloc (dev->nchannels, sizeof (struct atm_vcc *),
GFP_KERNEL);
fs_dprintk (FS_DEBUG_ALLOC, "Alloc atmvccs: %p(%Zd)\n",
dev->atm_vccs, dev->nchannels * sizeof (struct atm_vcc *));
@@ -1794,9 +1794,8 @@ static int __devinit fs_init (struct fs_dev *dev)
/* XXX Clean up..... */
return 1;
}
- memset (dev->atm_vccs, 0, dev->nchannels * sizeof (struct atm_vcc *));
- dev->tx_inuse = kmalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
+ dev->tx_inuse = kzalloc (dev->nchannels / 8 /* bits/byte */ , GFP_KERNEL);
fs_dprintk (FS_DEBUG_ALLOC, "Alloc tx_inuse: %p(%d)\n",
dev->atm_vccs, dev->nchannels / 8);
@@ -1805,8 +1804,6 @@ static int __devinit fs_init (struct fs_dev *dev)
/* XXX Clean up..... */
return 1;
}
- memset (dev->tx_inuse, 0, dev->nchannels / 8);
-
/* -- RAS1 : FS155 and 50 differ. Default (0) should be OK for both */
/* -- RAS2 : FS50 only: Default is OK. */
@@ -1893,14 +1890,11 @@ static int __devinit firestream_init_one (struct pci_dev *pci_dev,
if (pci_enable_device(pci_dev))
goto err_out;
- fs_dev = kmalloc (sizeof (struct fs_dev), GFP_KERNEL);
+ fs_dev = kzalloc (sizeof (struct fs_dev), GFP_KERNEL);
fs_dprintk (FS_DEBUG_ALLOC, "Alloc fs-dev: %p(%Zd)\n",
fs_dev, sizeof (struct fs_dev));
if (!fs_dev)
goto err_out;
-
- memset (fs_dev, 0, sizeof (struct fs_dev));
-
atm_dev = atm_dev_register("fs", &ops, -1, NULL);
if (!atm_dev)
goto err_out_free_fs_dev;
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index 98622130de5b..3a7b21ff30a5 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -1328,7 +1328,7 @@ fore200e_irq(struct fore200e* fore200e)
static irqreturn_t
-fore200e_interrupt(int irq, void* dev, struct pt_regs* regs)
+fore200e_interrupt(int irq, void* dev)
{
struct fore200e* fore200e = FORE200E_DEV((struct atm_dev*)dev);
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index f2511b42dba2..c7314a79da0f 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -109,7 +109,7 @@ static int he_open(struct atm_vcc *vcc);
static void he_close(struct atm_vcc *vcc);
static int he_send(struct atm_vcc *vcc, struct sk_buff *skb);
static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void __user *arg);
-static irqreturn_t he_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t he_irq_handler(int irq, void *dev_id);
static void he_tasklet(unsigned long data);
static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page);
static int he_start(struct atm_dev *dev);
@@ -383,14 +383,12 @@ he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
}
pci_set_drvdata(pci_dev, atm_dev);
- he_dev = (struct he_dev *) kmalloc(sizeof(struct he_dev),
+ he_dev = kzalloc(sizeof(struct he_dev),
GFP_KERNEL);
if (!he_dev) {
err = -ENOMEM;
goto init_one_failure;
}
- memset(he_dev, 0, sizeof(struct he_dev));
-
he_dev->pci_dev = pci_dev;
he_dev->atm_dev = atm_dev;
he_dev->atm_dev->dev_data = he_dev;
@@ -2218,7 +2216,7 @@ he_tasklet(unsigned long data)
}
static irqreturn_t
-he_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+he_irq_handler(int irq, void *dev_id)
{
unsigned long flags;
struct he_dev *he_dev = (struct he_dev * )dev_id;
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index d1113e845f95..f59349206dd2 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -1382,24 +1382,13 @@ static inline void rx_data_av_handler (hrz_dev * dev) {
/********** interrupt handler **********/
-static irqreturn_t interrupt_handler(int irq, void *dev_id,
- struct pt_regs *pt_regs) {
+static irqreturn_t interrupt_handler(int irq, void *dev_id) {
hrz_dev * dev = (hrz_dev *) dev_id;
u32 int_source;
unsigned int irq_ok;
- (void) pt_regs;
PRINTD (DBG_FLOW, "interrupt_handler: %p", dev_id);
- if (!dev_id) {
- PRINTD (DBG_IRQ|DBG_ERR, "irq with NULL dev_id: %d", irq);
- return IRQ_NONE;
- }
- if (irq != dev->irq) {
- PRINTD (DBG_IRQ|DBG_ERR, "irq mismatch: %d", irq);
- return IRQ_NONE;
- }
-
// definitely for us
irq_ok = 0;
while ((int_source = rd_regl (dev, INT_SOURCE_REG_OFF)
@@ -2719,7 +2708,7 @@ static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_
goto out_disable;
}
- dev = kmalloc(sizeof(hrz_dev), GFP_KERNEL);
+ dev = kzalloc(sizeof(hrz_dev), GFP_KERNEL);
if (!dev) {
// perhaps we should be nice: deregister all adapters and abort?
PRINTD(DBG_ERR, "out of memory");
@@ -2727,8 +2716,6 @@ static int __devinit hrz_probe(struct pci_dev *pci_dev, const struct pci_device_
goto out_release;
}
- memset(dev, 0, sizeof(hrz_dev));
-
pci_set_drvdata(pci_dev, dev);
// grab IRQ and install handler - move this someplace more sensible
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index b0369bb20f08..87b17c33b3f9 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -642,11 +642,9 @@ alloc_scq(struct idt77252_dev *card, int class)
{
struct scq_info *scq;
- scq = (struct scq_info *) kmalloc(sizeof(struct scq_info), GFP_KERNEL);
+ scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL);
if (!scq)
return NULL;
- memset(scq, 0, sizeof(struct scq_info));
-
scq->base = pci_alloc_consistent(card->pcidev, SCQ_SIZE,
&scq->paddr);
if (scq->base == NULL) {
@@ -2142,11 +2140,9 @@ idt77252_init_est(struct vc_map *vc, int pcr)
{
struct rate_estimator *est;
- est = kmalloc(sizeof(struct rate_estimator), GFP_KERNEL);
+ est = kzalloc(sizeof(struct rate_estimator), GFP_KERNEL);
if (!est)
return NULL;
- memset(est, 0, sizeof(*est));
-
est->maxcps = pcr < 0 ? -pcr : pcr;
est->cps = est->maxcps;
est->avcps = est->cps << 5;
@@ -2451,14 +2447,12 @@ idt77252_open(struct atm_vcc *vcc)
index = VPCI2VC(card, vpi, vci);
if (!card->vcs[index]) {
- card->vcs[index] = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
+ card->vcs[index] = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
if (!card->vcs[index]) {
printk("%s: can't alloc vc in open()\n", card->name);
up(&card->mutex);
return -ENOMEM;
}
- memset(card->vcs[index], 0, sizeof(struct vc_map));
-
card->vcs[index]->card = card;
card->vcs[index]->index = index;
@@ -2780,7 +2774,7 @@ idt77252_collect_stat(struct idt77252_dev *card)
}
static irqreturn_t
-idt77252_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+idt77252_interrupt(int irq, void *dev_id)
{
struct idt77252_dev *card = dev_id;
u32 stat;
@@ -2926,13 +2920,11 @@ open_card_oam(struct idt77252_dev *card)
for (vci = 3; vci < 5; vci++) {
index = VPCI2VC(card, vpi, vci);
- vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
+ vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
if (!vc) {
printk("%s: can't alloc vc\n", card->name);
return -ENOMEM;
}
- memset(vc, 0, sizeof(struct vc_map));
-
vc->index = index;
card->vcs[index] = vc;
@@ -2995,12 +2987,11 @@ open_card_ubr0(struct idt77252_dev *card)
{
struct vc_map *vc;
- vc = kmalloc(sizeof(struct vc_map), GFP_KERNEL);
+ vc = kzalloc(sizeof(struct vc_map), GFP_KERNEL);
if (!vc) {
printk("%s: can't alloc vc\n", card->name);
return -ENOMEM;
}
- memset(vc, 0, sizeof(struct vc_map));
card->vcs[0] = vc;
vc->class = SCHED_UBR0;
@@ -3695,14 +3686,12 @@ idt77252_init_one(struct pci_dev *pcidev, const struct pci_device_id *id)
goto err_out_disable_pdev;
}
- card = kmalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
+ card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
if (!card) {
printk("idt77252-%d: can't allocate private data\n", index);
err = -ENOMEM;
goto err_out_disable_pdev;
}
- memset(card, 0, sizeof(struct idt77252_dev));
-
card->revision = revision;
card->index = index;
card->pcidev = pcidev;
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index f20b0b2c06c6..9ed1c60048f0 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -2195,7 +2195,7 @@ err_out:
return -ENOMEM;
}
-static irqreturn_t ia_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ia_int(int irq, void *dev_id)
{
struct atm_dev *dev;
IADEV *iadev;
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index fe60a59b7fc0..267825501dfe 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -1482,16 +1482,10 @@ static inline void vcc_table_deallocate(const struct lanai_dev *lanai)
static inline struct lanai_vcc *new_lanai_vcc(void)
{
struct lanai_vcc *lvcc;
- lvcc = (struct lanai_vcc *) kmalloc(sizeof(*lvcc), GFP_KERNEL);
+ lvcc = kzalloc(sizeof(*lvcc), GFP_KERNEL);
if (likely(lvcc != NULL)) {
- lvcc->vbase = NULL;
- lvcc->rx.atmvcc = lvcc->tx.atmvcc = NULL;
- lvcc->nref = 0;
- memset(&lvcc->stats, 0, sizeof lvcc->stats);
- lvcc->rx.buf.start = lvcc->tx.buf.start = NULL;
skb_queue_head_init(&lvcc->tx.backlog);
#ifdef DEBUG
- lvcc->tx.unqueue = NULL;
lvcc->vci = -1;
#endif
}
@@ -1896,13 +1890,11 @@ static inline void lanai_int_1(struct lanai_dev *lanai, u32 reason)
reg_write(lanai, ack, IntAck_Reg);
}
-static irqreturn_t lanai_int(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t lanai_int(int irq, void *devid)
{
- struct lanai_dev *lanai = (struct lanai_dev *) devid;
+ struct lanai_dev *lanai = devid;
u32 reason;
- (void) irq; (void) regs; /* unused variables */
-
#ifdef USE_POWERDOWN
/*
* If we're powered down we shouldn't be generating any interrupts -
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index b8036899e56f..632ede552761 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -214,7 +214,7 @@ static void __devinit ns_init_card_error(ns_dev *card, int error);
static scq_info *get_scq(int size, u32 scd);
static void free_scq(scq_info *scq, struct atm_vcc *vcc);
static void push_rxbufs(ns_dev *, struct sk_buff *);
-static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ns_irq_handler(int irq, void *dev_id);
static int ns_open(struct atm_vcc *vcc);
static void ns_close(struct atm_vcc *vcc);
static void fill_tst(ns_dev *card, int n, vc_map *vc);
@@ -1194,7 +1194,7 @@ static void push_rxbufs(ns_dev *card, struct sk_buff *skb)
-static irqreturn_t ns_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ns_irq_handler(int irq, void *dev_id)
{
u32 stat_r;
ns_dev *card;
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 2c65e82f0d6b..7df0f373188e 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -603,9 +603,8 @@ static int start_rx(struct atm_dev *dev)
DPRINTK("start_rx\n");
zatm_dev = ZATM_DEV(dev);
size = sizeof(struct atm_vcc *)*zatm_dev->chans;
- zatm_dev->rx_map = (struct atm_vcc **) kmalloc(size,GFP_KERNEL);
+ zatm_dev->rx_map = kzalloc(size,GFP_KERNEL);
if (!zatm_dev->rx_map) return -ENOMEM;
- memset(zatm_dev->rx_map,0,size);
/* set VPI/VCI split (use all VCIs and give what's left to VPIs) */
zpokel(zatm_dev,(1 << dev->ci_range.vci_bits)-1,uPD98401_VRR);
/* prepare free buffer pools */
@@ -801,6 +800,7 @@ static int alloc_shaper(struct atm_dev *dev,int *pcr,int min,int max,int ubr)
i = m = 1;
zatm_dev->ubr_ref_cnt++;
zatm_dev->ubr = shaper;
+ *pcr = 0;
}
else {
if (min) {
@@ -951,9 +951,8 @@ static int open_tx_first(struct atm_vcc *vcc)
skb_queue_head_init(&zatm_vcc->tx_queue);
init_waitqueue_head(&zatm_vcc->tx_wait);
/* initialize ring */
- zatm_vcc->ring = kmalloc(RING_SIZE,GFP_KERNEL);
+ zatm_vcc->ring = kzalloc(RING_SIZE,GFP_KERNEL);
if (!zatm_vcc->ring) return -ENOMEM;
- memset(zatm_vcc->ring,0,RING_SIZE);
loop = zatm_vcc->ring+RING_ENTRIES*RING_WORDS;
loop[0] = uPD98401_TXPD_V;
loop[1] = loop[2] = 0;
@@ -1013,7 +1012,7 @@ static int start_tx(struct atm_dev *dev)
/*------------------------------- interrupts --------------------------------*/
-static irqreturn_t zatm_int(int irq,void *dev_id,struct pt_regs *regs)
+static irqreturn_t zatm_int(int irq,void *dev_id)
{
struct atm_dev *dev;
struct zatm_dev *zatm_dev;
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index b539e5e75b56..7bbb9eeda235 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -8,7 +8,7 @@ obj-y += power/
obj-$(CONFIG_ISA) += isa.o
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
-obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o
+obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
obj-$(CONFIG_SMP) += topology.o
obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index 12173d16bea7..7d8a7ce73fb3 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -372,19 +372,30 @@ int bus_add_device(struct device * dev)
pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
error = device_add_attrs(bus, dev);
if (error)
- goto out;
+ goto out_put;
error = sysfs_create_link(&bus->devices.kobj,
&dev->kobj, dev->bus_id);
if (error)
- goto out;
+ goto out_id;
error = sysfs_create_link(&dev->kobj,
&dev->bus->subsys.kset.kobj, "subsystem");
if (error)
- goto out;
+ goto out_subsys;
error = sysfs_create_link(&dev->kobj,
&dev->bus->subsys.kset.kobj, "bus");
+ if (error)
+ goto out_deprecated;
}
-out:
+ return 0;
+
+out_deprecated:
+ sysfs_remove_link(&dev->kobj, "subsystem");
+out_subsys:
+ sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
+out_id:
+ device_remove_attrs(bus, dev);
+out_put:
+ put_bus(dev->bus);
return error;
}
@@ -428,8 +439,10 @@ void bus_remove_device(struct device * dev)
sysfs_remove_link(&dev->kobj, "bus");
sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
device_remove_attrs(dev->bus, dev);
- dev->is_registered = 0;
- klist_del(&dev->knode_bus);
+ if (dev->is_registered) {
+ dev->is_registered = 0;
+ klist_del(&dev->knode_bus);
+ }
pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
device_release_driver(dev);
put_bus(dev->bus);
@@ -505,34 +518,36 @@ int bus_add_driver(struct device_driver *drv)
struct bus_type * bus = get_bus(drv->bus);
int error = 0;
- if (bus) {
- pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
- error = kobject_set_name(&drv->kobj, "%s", drv->name);
- if (error)
- goto out_put_bus;
- drv->kobj.kset = &bus->drivers;
- if ((error = kobject_register(&drv->kobj)))
- goto out_put_bus;
-
- error = driver_attach(drv);
- if (error)
- goto out_unregister;
- klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
- module_add_driver(drv->owner, drv);
-
- error = driver_add_attrs(bus, drv);
- if (error) {
- /* How the hell do we get out of this pickle? Give up */
- printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
- __FUNCTION__, drv->name);
- }
- error = add_bind_files(drv);
- if (error) {
- /* Ditto */
- printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
- __FUNCTION__, drv->name);
- }
+ if (!bus)
+ return 0;
+
+ pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
+ error = kobject_set_name(&drv->kobj, "%s", drv->name);
+ if (error)
+ goto out_put_bus;
+ drv->kobj.kset = &bus->drivers;
+ if ((error = kobject_register(&drv->kobj)))
+ goto out_put_bus;
+
+ error = driver_attach(drv);
+ if (error)
+ goto out_unregister;
+ klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
+ module_add_driver(drv->owner, drv);
+
+ error = driver_add_attrs(bus, drv);
+ if (error) {
+ /* How the hell do we get out of this pickle? Give up */
+ printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",
+ __FUNCTION__, drv->name);
}
+ error = add_bind_files(drv);
+ if (error) {
+ /* Ditto */
+ printk(KERN_ERR "%s: add_bind_files(%s) failed\n",
+ __FUNCTION__, drv->name);
+ }
+
return error;
out_unregister:
kobject_unregister(&drv->kobj);
@@ -552,16 +567,17 @@ out_put_bus:
void bus_remove_driver(struct device_driver * drv)
{
- if (drv->bus) {
- remove_bind_files(drv);
- driver_remove_attrs(drv->bus, drv);
- klist_remove(&drv->knode_bus);
- pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
- driver_detach(drv);
- module_remove_driver(drv);
- kobject_unregister(&drv->kobj);
- put_bus(drv->bus);
- }
+ if (!drv->bus)
+ return;
+
+ remove_bind_files(drv);
+ driver_remove_attrs(drv->bus, drv);
+ klist_remove(&drv->knode_bus);
+ pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
+ driver_detach(drv);
+ module_remove_driver(drv);
+ kobject_unregister(&drv->kobj);
+ put_bus(drv->bus);
}
@@ -732,11 +748,15 @@ int bus_register(struct bus_type * bus)
klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
klist_init(&bus->klist_drivers, NULL, NULL);
- bus_add_attrs(bus);
+ retval = bus_add_attrs(bus);
+ if (retval)
+ goto bus_attrs_fail;
pr_debug("bus type '%s' registered\n", bus->name);
return 0;
+bus_attrs_fail:
+ kset_unregister(&bus->drivers);
bus_drivers_fail:
kset_unregister(&bus->devices);
bus_devices_fail:
diff --git a/drivers/base/class.c b/drivers/base/class.c
index b06b0e2b9c62..0ff267a248db 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -228,7 +228,7 @@ error:
/**
* class_destroy - destroys a struct class structure
- * @cs: pointer to the struct class that is to be destroyed
+ * @cls: pointer to the struct class that is to be destroyed
*
* Note, the pointer to be destroyed must have been created with a call
* to class_create().
@@ -562,7 +562,10 @@ int class_device_add(struct class_device *class_dev)
goto out2;
/* add the needed attributes to this device */
- sysfs_create_link(&class_dev->kobj, &parent_class->subsys.kset.kobj, "subsystem");
+ error = sysfs_create_link(&class_dev->kobj,
+ &parent_class->subsys.kset.kobj, "subsystem");
+ if (error)
+ goto out3;
class_dev->uevent_attr.attr.name = "uevent";
class_dev->uevent_attr.attr.mode = S_IWUSR;
class_dev->uevent_attr.attr.owner = parent_class->owner;
@@ -658,9 +661,9 @@ int class_device_register(struct class_device *class_dev)
/**
* class_device_create - creates a class device and registers it with sysfs
- * @cs: pointer to the struct class that this device should be registered to.
+ * @cls: pointer to the struct class that this device should be registered to.
* @parent: pointer to the parent struct class_device of this new device, if any.
- * @dev: the dev_t for the char device to be added.
+ * @devt: the dev_t for the char device to be added.
* @device: a pointer to a struct device that is assiociated with this class device.
* @fmt: string for the class device's name
*
@@ -766,7 +769,7 @@ void class_device_unregister(struct class_device *class_dev)
/**
* class_device_destroy - removes a class device that was created with class_device_create()
* @cls: the pointer to the struct class that this device was registered * with.
- * @dev: the dev_t of the device that was previously registered.
+ * @devt: the dev_t of the device that was previously registered.
*
* This call unregisters and cleans up a class device that was created with a
* call to class_device_create()
diff --git a/drivers/base/core.c b/drivers/base/core.c
index b224bb43ff63..68ad11af22b4 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -44,7 +44,7 @@ const char *dev_driver_string(struct device *dev)
return dev->driver ? dev->driver->name :
(dev->bus ? dev->bus->name : "");
}
-EXPORT_SYMBOL_GPL(dev_driver_string);
+EXPORT_SYMBOL(dev_driver_string);
#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
@@ -433,14 +433,16 @@ int device_add(struct device *dev)
if (dev->driver)
dev->uevent_attr.attr.owner = dev->driver->owner;
dev->uevent_attr.store = store_uevent;
- device_create_file(dev, &dev->uevent_attr);
+ error = device_create_file(dev, &dev->uevent_attr);
+ if (error)
+ goto attrError;
if (MAJOR(dev->devt)) {
struct device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) {
error = -ENOMEM;
- goto PMError;
+ goto ueventattrError;
}
attr->attr.name = "dev";
attr->attr.mode = S_IRUGO;
@@ -450,7 +452,7 @@ int device_add(struct device *dev)
error = device_create_file(dev, attr);
if (error) {
kfree(attr);
- goto attrError;
+ goto ueventattrError;
}
dev->devt_attr = attr;
@@ -477,7 +479,8 @@ int device_add(struct device *dev)
if ((error = bus_add_device(dev)))
goto BusError;
kobject_uevent(&dev->kobj, KOBJ_ADD);
- bus_attach_device(dev);
+ if ((error = bus_attach_device(dev)))
+ goto AttachError;
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
@@ -496,6 +499,8 @@ int device_add(struct device *dev)
kfree(class_name);
put_device(dev);
return error;
+ AttachError:
+ bus_remove_device(dev);
BusError:
device_pm_remove(dev);
PMError:
@@ -507,6 +512,8 @@ int device_add(struct device *dev)
device_remove_file(dev, dev->devt_attr);
kfree(dev->devt_attr);
}
+ ueventattrError:
+ device_remove_file(dev, &dev->uevent_attr);
attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
@@ -805,8 +812,10 @@ int device_rename(struct device *dev, char *new_name)
if (dev->class) {
old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
- if (!old_symlink_name)
- return -ENOMEM;
+ if (!old_symlink_name) {
+ error = -ENOMEM;
+ goto out_free_old_class;
+ }
strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
}
@@ -830,9 +839,10 @@ int device_rename(struct device *dev, char *new_name)
}
put_device(dev);
- kfree(old_class_name);
kfree(new_class_name);
kfree(old_symlink_name);
+ out_free_old_class:
+ kfree(old_class_name);
return error;
}
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index b5f43c3e44fa..db01b95a47a5 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -171,6 +171,8 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
drv->bus->name, dev->bus_id, drv->name);
data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
data->drv = drv;
data->dev = dev;
@@ -178,7 +180,7 @@ int driver_probe_device(struct device_driver * drv, struct device * dev)
probe_task = kthread_run(really_probe, data,
"probe-%s", dev->bus_id);
if (IS_ERR(probe_task))
- ret = PTR_ERR(probe_task);
+ ret = really_probe(data);
} else
ret = really_probe(data);
diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c
index 33c5cce1560b..b2efbd4cf710 100644
--- a/drivers/base/dmapool.c
+++ b/drivers/base/dmapool.c
@@ -141,11 +141,20 @@ dma_pool_create (const char *name, struct device *dev,
init_waitqueue_head (&retval->waitq);
if (dev) {
+ int ret;
+
down (&pools_lock);
if (list_empty (&dev->dma_pools))
- device_create_file (dev, &dev_attr_pools);
+ ret = device_create_file (dev, &dev_attr_pools);
+ else
+ ret = 0;
/* note: not currently insisting "name" be unique */
- list_add (&retval->pools, &dev->dma_pools);
+ if (!ret)
+ list_add (&retval->pools, &dev->dma_pools);
+ else {
+ kfree(retval);
+ retval = NULL;
+ }
up (&pools_lock);
} else
INIT_LIST_HEAD (&retval->pools);
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 5d6c011183f5..14615694ae9a 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -16,6 +16,7 @@
#include <linux/interrupt.h>
#include <linux/bitops.h>
#include <linux/mutex.h>
+#include <linux/kthread.h>
#include <linux/firmware.h>
#include "base.h"
@@ -511,7 +512,6 @@ request_firmware_work_func(void *arg)
WARN_ON(1);
return 0;
}
- daemonize("%s/%s", "firmware", fw_work->name);
ret = _request_firmware(&fw, fw_work->name, fw_work->device,
fw_work->uevent);
if (ret < 0)
@@ -546,9 +546,9 @@ request_firmware_nowait(
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context))
{
+ struct task_struct *task;
struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
GFP_ATOMIC);
- int ret;
if (!fw_work)
return -ENOMEM;
@@ -566,14 +566,14 @@ request_firmware_nowait(
.uevent = uevent,
};
- ret = kernel_thread(request_firmware_work_func, fw_work,
- CLONE_FS | CLONE_FILES);
+ task = kthread_run(request_firmware_work_func, fw_work,
+ "firmware/%s", name);
- if (ret < 0) {
+ if (IS_ERR(task)) {
fw_work->cont(NULL, fw_work->context);
module_put(fw_work->module);
kfree(fw_work);
- return ret;
+ return PTR_ERR(task);
}
return 0;
}
@@ -602,7 +602,7 @@ firmware_class_exit(void)
class_unregister(&firmware_class);
}
-module_init(firmware_class_init);
+fs_initcall(firmware_class_init);
module_exit(firmware_class_exit);
EXPORT_SYMBOL(release_firmware);
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
index 3ef9d514b916..28dccb730af9 100644
--- a/drivers/base/topology.c
+++ b/drivers/base/topology.c
@@ -97,8 +97,7 @@ static struct attribute_group topology_attr_group = {
/* Add/Remove cpu_topology interface for CPU device */
static int __cpuinit topology_add_dev(struct sys_device * sys_dev)
{
- sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
- return 0;
+ return sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
}
static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index a360215dbce7..742d07403101 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -770,7 +770,7 @@ static void DAC960_P_QueueCommand(DAC960_Command_T *Command)
static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
{
DAC960_Controller_T *Controller = Command->Controller;
- DECLARE_COMPLETION(Completion);
+ DECLARE_COMPLETION_ONSTACK(Completion);
unsigned long flags;
Command->Completion = &Completion;
@@ -2698,8 +2698,7 @@ DAC960_DetectController(struct pci_dev *PCI_Device,
{
struct DAC960_privdata *privdata =
(struct DAC960_privdata *)entry->driver_data;
- irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *) =
- privdata->InterruptHandler;
+ irq_handler_t InterruptHandler = privdata->InterruptHandler;
unsigned int MemoryWindowSize = privdata->MemoryWindowSize;
DAC960_Controller_T *Controller = NULL;
unsigned char DeviceFunction = PCI_Device->devfn;
@@ -3331,7 +3330,7 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_
Command->DmaDirection = PCI_DMA_TODEVICE;
Command->CommandType = DAC960_WriteCommand;
}
- Command->Completion = Request->waiting;
+ Command->Completion = Request->end_io_data;
Command->LogicalDriveNumber = (long)Request->rq_disk->private_data;
Command->BlockNumber = Request->sector;
Command->BlockCount = Request->nr_sectors;
@@ -5253,10 +5252,9 @@ static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
*/
static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- struct pt_regs *InterruptRegisters)
+ void *DeviceIdentifier)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ DAC960_Controller_T *Controller = DeviceIdentifier;
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
DAC960_V2_StatusMailbox_T *NextStatusMailbox;
unsigned long flags;
@@ -5295,10 +5293,9 @@ static irqreturn_t DAC960_GEM_InterruptHandler(int IRQ_Channel,
*/
static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- struct pt_regs *InterruptRegisters)
+ void *DeviceIdentifier)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ DAC960_Controller_T *Controller = DeviceIdentifier;
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
DAC960_V2_StatusMailbox_T *NextStatusMailbox;
unsigned long flags;
@@ -5338,10 +5335,9 @@ static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel,
*/
static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- struct pt_regs *InterruptRegisters)
+ void *DeviceIdentifier)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ DAC960_Controller_T *Controller = DeviceIdentifier;
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
DAC960_V2_StatusMailbox_T *NextStatusMailbox;
unsigned long flags;
@@ -5381,10 +5377,9 @@ static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel,
*/
static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- struct pt_regs *InterruptRegisters)
+ void *DeviceIdentifier)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ DAC960_Controller_T *Controller = DeviceIdentifier;
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
DAC960_V1_StatusMailbox_T *NextStatusMailbox;
unsigned long flags;
@@ -5420,10 +5415,9 @@ static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel,
*/
static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- struct pt_regs *InterruptRegisters)
+ void *DeviceIdentifier)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ DAC960_Controller_T *Controller = DeviceIdentifier;
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
DAC960_V1_StatusMailbox_T *NextStatusMailbox;
unsigned long flags;
@@ -5459,10 +5453,9 @@ static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel,
*/
static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- struct pt_regs *InterruptRegisters)
+ void *DeviceIdentifier)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ DAC960_Controller_T *Controller = DeviceIdentifier;
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
unsigned long flags;
@@ -5498,10 +5491,9 @@ static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel,
*/
static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel,
- void *DeviceIdentifier,
- struct pt_regs *InterruptRegisters)
+ void *DeviceIdentifier)
{
- DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+ DAC960_Controller_T *Controller = DeviceIdentifier;
void __iomem *ControllerBaseAddress = Controller->BaseAddress;
unsigned long flags;
diff --git a/drivers/block/DAC960.h b/drivers/block/DAC960.h
index a82f37f749a5..6148073532b2 100644
--- a/drivers/block/DAC960.h
+++ b/drivers/block/DAC960.h
@@ -71,7 +71,7 @@
Define a Boolean data type.
*/
-typedef enum { false, true } __attribute__ ((packed)) boolean;
+typedef bool boolean;
/*
@@ -2175,7 +2175,7 @@ static char
struct DAC960_privdata {
DAC960_HardwareType_T HardwareType;
DAC960_FirmwareType_T FirmwareType;
- irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *);
+ irq_handler_t InterruptHandler;
unsigned int MemoryWindowSize;
};
@@ -4379,8 +4379,8 @@ static inline void DAC960_P_To_PD_TranslateEnquiry(void *Enquiry)
static inline void DAC960_P_To_PD_TranslateDeviceState(void *DeviceState)
{
memcpy(DeviceState + 2, DeviceState + 3, 1);
- memcpy(DeviceState + 4, DeviceState + 5, 2);
- memcpy(DeviceState + 6, DeviceState + 8, 4);
+ memmove(DeviceState + 4, DeviceState + 5, 2);
+ memmove(DeviceState + 6, DeviceState + 8, 4);
}
static inline
@@ -4412,12 +4412,12 @@ static void DAC960_FinalizeController(DAC960_Controller_T *);
static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *);
static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *);
static void DAC960_RequestFunction(struct request_queue *);
-static irqreturn_t DAC960_BA_InterruptHandler(int, void *, struct pt_regs *);
-static irqreturn_t DAC960_LP_InterruptHandler(int, void *, struct pt_regs *);
-static irqreturn_t DAC960_LA_InterruptHandler(int, void *, struct pt_regs *);
-static irqreturn_t DAC960_PG_InterruptHandler(int, void *, struct pt_regs *);
-static irqreturn_t DAC960_PD_InterruptHandler(int, void *, struct pt_regs *);
-static irqreturn_t DAC960_P_InterruptHandler(int, void *, struct pt_regs *);
+static irqreturn_t DAC960_BA_InterruptHandler(int, void *);
+static irqreturn_t DAC960_LP_InterruptHandler(int, void *);
+static irqreturn_t DAC960_LA_InterruptHandler(int, void *);
+static irqreturn_t DAC960_PG_InterruptHandler(int, void *);
+static irqreturn_t DAC960_PD_InterruptHandler(int, void *);
+static irqreturn_t DAC960_P_InterruptHandler(int, void *);
static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
static void DAC960_MonitoringTimerFunction(unsigned long);
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index b5382cedf0c0..17dc22282e14 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -2,6 +2,8 @@
# Block device driver configuration
#
+if BLOCK
+
menu "Block devices"
config BLK_DEV_FD
@@ -205,8 +207,7 @@ config BLK_DEV_UMEM
module will be called umem.
The umem driver has not yet been allocated a MAJOR number, so
- one is chosen dynamically. Use "devfs" or look in /proc/devices
- for the device number
+ one is chosen dynamically.
config BLK_DEV_UBD
bool "Virtual block device"
@@ -405,7 +406,7 @@ config BLK_DEV_RAM_BLOCKSIZE
depends on BLK_DEV_RAM
default "1024"
help
- The default value is 1024 kilobytes. PAGE_SIZE is a much more
+ The default value is 1024 bytes. PAGE_SIZE is a much more
efficient choice however. The default is kept to ensure initrd
setups function - apparently needed by the rd_load_image routine
that supposes the filesystem in the image uses a 1024 blocksize.
@@ -468,3 +469,5 @@ config ATA_OVER_ETH
devices like the Coraid EtherDrive (R) Storage Blade.
endmenu
+
+endif
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 0b80fbb8dbfd..706cdc6a69ec 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -346,7 +346,7 @@ static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int
rwflag, int enable);
static int acsi_reqsense( char *buffer, int targ, int lun);
static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struct *aip);
-static irqreturn_t acsi_interrupt (int irq, void *data, struct pt_regs *fp);
+static irqreturn_t acsi_interrupt (int irq, void *data);
static void unexpected_acsi_interrupt( void );
static void bad_rw_intr( void );
static void read_intr( void );
@@ -726,7 +726,7 @@ static void acsi_print_error(const unsigned char *errblk, struct acsi_info_struc
*
*******************************************************************/
-static irqreturn_t acsi_interrupt(int irq, void *data, struct pt_regs *fp )
+static irqreturn_t acsi_interrupt(int irq, void *data )
{ void (*acsi_irq_handler)(void) = do_acsi;
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index 4030a8fd1187..8e41c87b026e 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -246,7 +246,7 @@ static int slm_getstats( char *buffer, int device );
static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t
*ppos );
static void start_print( int device );
-static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp);
+static irqreturn_t slm_interrupt(int irc, void *data);
static void slm_test_ready( unsigned long dummy );
static void set_dma_addr( unsigned long paddr );
static unsigned long get_dma_addr( void );
@@ -452,7 +452,7 @@ static void start_print( int device )
/* Only called when an error happened or at the end of a page */
-static irqreturn_t slm_interrupt(int irc, void *data, struct pt_regs *fp)
+static irqreturn_t slm_interrupt(int irc, void *data)
{ unsigned long addr;
int stat;
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 2641597c6549..5d6562171533 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -209,7 +209,7 @@ static int fd_device[4] = { 0, 0, 0, 0 };
/* Milliseconds timer */
-static irqreturn_t ms_isr(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t ms_isr(int irq, void *dummy)
{
ms_busy = -1;
wake_up(&ms_wait);
@@ -560,7 +560,7 @@ static unsigned long fd_get_drive_id(int drive)
return (id);
}
-static irqreturn_t fd_block_done(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t fd_block_done(int irq, void *dummy)
{
if (block_flag)
custom.dsklen = 0x4000;
@@ -1709,10 +1709,13 @@ static struct kobject *floppy_find(dev_t dev, int *part, void *data)
return get_disk(unit[drive].gendisk);
}
-int __init amiga_floppy_init(void)
+static int __init amiga_floppy_init(void)
{
int i, ret;
+ if (!MACH_IS_AMIGA)
+ return -ENXIO;
+
if (!AMIGAHW_PRESENT(AMI_FLOPPY))
return -ENXIO;
@@ -1809,15 +1812,9 @@ out_blkdev:
return ret;
}
+module_init(amiga_floppy_init);
#ifdef MODULE
-int init_module(void)
-{
- if (!MACH_IS_AMIGA)
- return -ENXIO;
- return amiga_floppy_init();
-}
-
#if 0 /* not safe to unload */
void cleanup_module(void)
{
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index 6eebcb7be97e..6d111228cfac 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
-#define VERSION "22"
+/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
+#define VERSION "32"
#define AOE_MAJOR 152
#define DEVICE_NAME "aoe"
@@ -65,7 +65,7 @@ struct aoe_atahdr {
struct aoe_cfghdr {
__be16 bufcnt;
__be16 fwver;
- unsigned char res;
+ unsigned char scnt;
unsigned char aoeccmd;
unsigned char cslen[2];
};
@@ -78,12 +78,14 @@ enum {
DEVFL_GDALLOC = (1<<4), /* need to alloc gendisk */
DEVFL_PAUSE = (1<<5),
DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */
+ DEVFL_MAXBCNT = (1<<7), /* d->maxbcnt is not changeable */
+ DEVFL_KICKME = (1<<8),
BUFFL_FAIL = 1,
};
enum {
- MAXATADATA = 1024,
+ DEFAULTBCNT = 2 * 512, /* 2 sectors */
NPERSHELF = 16, /* number of slots per shelf address */
FREETAG = -1,
MIN_BUFS = 8,
@@ -107,11 +109,9 @@ struct frame {
ulong waited;
struct buf *buf;
char *bufaddr;
- int writedatalen;
- int ndata;
-
- /* largest possible */
- unsigned char data[sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr)];
+ ulong bcnt;
+ sector_t lba;
+ struct sk_buff *skb;
};
struct aoedev {
@@ -121,9 +121,12 @@ struct aoedev {
ulong sysminor;
ulong aoemajor;
ulong aoeminor;
- ulong nopen; /* (bd_openers isn't available without sleeping) */
- ulong rttavg; /* round trip average of requests/responses */
+ u16 nopen; /* (bd_openers isn't available without sleeping) */
+ u16 lasttag; /* last tag sent */
+ u16 rttavg; /* round trip average of requests/responses */
+ u16 mintimer;
u16 fw_ver; /* version of blade's firmware */
+ u16 maxbcnt;
struct work_struct work;/* disk create work struct */
struct gendisk *gd;
request_queue_t blkq;
@@ -137,8 +140,8 @@ struct aoedev {
mempool_t *bufpool; /* for deadlock-free Buf allocation */
struct list_head bufq; /* queue of bios to work on */
struct buf *inprocess; /* the one we're currently working on */
- ulong lasttag; /* last tag sent */
- ulong nframes; /* number of frames below */
+ ushort lostjumbo;
+ ushort nframes; /* number of frames below */
struct frame *frames;
};
@@ -157,6 +160,7 @@ void aoecmd_cfg(ushort aoemajor, unsigned char aoeminor);
void aoecmd_ata_rsp(struct sk_buff *);
void aoecmd_cfg_rsp(struct sk_buff *);
void aoecmd_sleepwork(void *vp);
+struct sk_buff *new_skb(ulong);
int aoedev_init(void);
void aoedev_exit(void);
diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c
index 393b86a3dbf8..d433f27e0ce2 100644
--- a/drivers/block/aoe/aoeblk.c
+++ b/drivers/block/aoe/aoeblk.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoeblk.c
* block device routines
@@ -14,7 +14,6 @@
static kmem_cache_t *buf_pool_cache;
-/* add attributes for our block devices in sysfs */
static ssize_t aoedisk_show_state(struct gendisk * disk, char *page)
{
struct aoedev *d = disk->private_data;
@@ -64,21 +63,26 @@ static struct disk_attribute disk_attr_fwver = {
.show = aoedisk_show_fwver
};
-static void
+static struct attribute *aoe_attrs[] = {
+ &disk_attr_state.attr,
+ &disk_attr_mac.attr,
+ &disk_attr_netif.attr,
+ &disk_attr_fwver.attr,
+};
+
+static const struct attribute_group attr_group = {
+ .attrs = aoe_attrs,
+};
+
+static int
aoedisk_add_sysfs(struct aoedev *d)
{
- sysfs_create_file(&d->gd->kobj, &disk_attr_state.attr);
- sysfs_create_file(&d->gd->kobj, &disk_attr_mac.attr);
- sysfs_create_file(&d->gd->kobj, &disk_attr_netif.attr);
- sysfs_create_file(&d->gd->kobj, &disk_attr_fwver.attr);
+ return sysfs_create_group(&d->gd->kobj, &attr_group);
}
void
aoedisk_rm_sysfs(struct aoedev *d)
{
- sysfs_remove_link(&d->gd->kobj, "state");
- sysfs_remove_link(&d->gd->kobj, "mac");
- sysfs_remove_link(&d->gd->kobj, "netif");
- sysfs_remove_link(&d->gd->kobj, "firmware-version");
+ sysfs_remove_group(&d->gd->kobj, &attr_group);
}
static int
@@ -132,8 +136,7 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
d = bio->bi_bdev->bd_disk->private_data;
buf = mempool_alloc(d->bufpool, GFP_NOIO);
if (buf == NULL) {
- printk(KERN_INFO "aoe: aoeblk_make_request: buf allocation "
- "failure\n");
+ printk(KERN_INFO "aoe: buf allocation failure\n");
bio_endio(bio, bio->bi_size, -ENOMEM);
return 0;
}
@@ -143,14 +146,15 @@ aoeblk_make_request(request_queue_t *q, struct bio *bio)
buf->bio = bio;
buf->resid = bio->bi_size;
buf->sector = bio->bi_sector;
- buf->bv = buf->bio->bi_io_vec;
+ buf->bv = &bio->bi_io_vec[bio->bi_idx];
+ WARN_ON(buf->bv->bv_len == 0);
buf->bv_resid = buf->bv->bv_len;
buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
spin_lock_irqsave(&d->lock, flags);
if ((d->flags & DEVFL_UP) == 0) {
- printk(KERN_INFO "aoe: aoeblk_make_request: device %ld.%ld is not up\n",
+ printk(KERN_INFO "aoe: device %ld.%ld is not up\n",
d->aoemajor, d->aoeminor);
spin_unlock_irqrestore(&d->lock, flags);
mempool_free(buf, d->bufpool);
@@ -176,7 +180,7 @@ aoeblk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
struct aoedev *d = bdev->bd_disk->private_data;
if ((d->flags & DEVFL_UP) == 0) {
- printk(KERN_ERR "aoe: aoeblk_ioctl: disk not up\n");
+ printk(KERN_ERR "aoe: disk not up\n");
return -ENODEV;
}
@@ -203,8 +207,8 @@ aoeblk_gdalloc(void *vp)
gd = alloc_disk(AOE_PARTITIONS);
if (gd == NULL) {
- printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate disk "
- "structure for %ld.%ld\n", d->aoemajor, d->aoeminor);
+ printk(KERN_ERR "aoe: cannot allocate disk structure for %ld.%ld\n",
+ d->aoemajor, d->aoeminor);
spin_lock_irqsave(&d->lock, flags);
d->flags &= ~DEVFL_GDALLOC;
spin_unlock_irqrestore(&d->lock, flags);
@@ -213,8 +217,8 @@ aoeblk_gdalloc(void *vp)
d->bufpool = mempool_create_slab_pool(MIN_BUFS, buf_pool_cache);
if (d->bufpool == NULL) {
- printk(KERN_ERR "aoe: aoeblk_gdalloc: cannot allocate bufpool "
- "for %ld.%ld\n", d->aoemajor, d->aoeminor);
+ printk(KERN_ERR "aoe: cannot allocate bufpool for %ld.%ld\n",
+ d->aoemajor, d->aoeminor);
put_disk(gd);
spin_lock_irqsave(&d->lock, flags);
d->flags &= ~DEVFL_GDALLOC;
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index 1bc1cf9603f1..e22b4c9520a9 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoechr.c
* AoE character device driver
@@ -15,7 +15,6 @@ enum {
MINOR_INTERFACES,
MINOR_REVALIDATE,
MSGSZ = 2048,
- NARGS = 10,
NMSG = 100, /* message backlog to retain */
};
@@ -56,9 +55,8 @@ static int
interfaces(const char __user *str, size_t size)
{
if (set_aoe_iflist(str, size)) {
- printk(KERN_CRIT
- "%s: could not set interface list: %s\n",
- __FUNCTION__, "too many interfaces");
+ printk(KERN_ERR
+ "aoe: could not set interface list: too many interfaces\n");
return -EINVAL;
}
return 0;
@@ -81,8 +79,7 @@ revalidate(const char __user *str, size_t size)
/* should be e%d.%d format */
n = sscanf(buf, "e%d.%d", &major, &minor);
if (n != 2) {
- printk(KERN_ERR "aoe: %s: invalid device specification\n",
- __FUNCTION__);
+ printk(KERN_ERR "aoe: invalid device specification\n");
return -EINVAL;
}
d = aoedev_by_aoeaddr(major, minor);
@@ -90,6 +87,7 @@ revalidate(const char __user *str, size_t size)
return -EINVAL;
spin_lock_irqsave(&d->lock, flags);
+ d->flags &= ~DEVFL_MAXBCNT;
d->flags |= DEVFL_PAUSE;
spin_unlock_irqrestore(&d->lock, flags);
aoecmd_cfg(major, minor);
@@ -116,7 +114,7 @@ bail: spin_unlock_irqrestore(&emsgs_lock, flags);
mp = kmalloc(n, GFP_ATOMIC);
if (mp == NULL) {
- printk(KERN_CRIT "aoe: aoechr_error: allocation failure, len=%ld\n", n);
+ printk(KERN_ERR "aoe: allocation failure, len=%ld\n", n);
goto bail;
}
@@ -141,7 +139,7 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp
switch ((unsigned long) filp->private_data) {
default:
- printk(KERN_INFO "aoe: aoechr_write: can't write to that file.\n");
+ printk(KERN_INFO "aoe: can't write to that file.\n");
break;
case MINOR_DISCOVER:
ret = discover();
@@ -250,7 +248,7 @@ aoechr_init(void)
n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
if (n < 0) {
- printk(KERN_ERR "aoe: aoechr_init: can't register char device\n");
+ printk(KERN_ERR "aoe: can't register char device\n");
return n;
}
sema_init(&emsgs_sema, 0);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 39da28d344fe..8a13b1af8bab 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoecmd.c
* Filesystem request handling methods
@@ -15,17 +15,19 @@
#define TIMERTICK (HZ / 10)
#define MINTIMER (2 * TIMERTICK)
#define MAXTIMER (HZ << 1)
-#define MAXWAIT (60 * 3) /* After MAXWAIT seconds, give up and fail dev */
-static struct sk_buff *
-new_skb(struct net_device *if_dev, ulong len)
+static int aoe_deadsecs = 60 * 3;
+module_param(aoe_deadsecs, int, 0644);
+MODULE_PARM_DESC(aoe_deadsecs, "After aoe_deadsecs seconds, give up and fail dev.");
+
+struct sk_buff *
+new_skb(ulong len)
{
struct sk_buff *skb;
skb = alloc_skb(len, GFP_ATOMIC);
if (skb) {
skb->nh.raw = skb->mac.raw = skb->data;
- skb->dev = if_dev;
skb->protocol = __constant_htons(ETH_P_AOE);
skb->priority = 0;
skb_put(skb, len);
@@ -40,29 +42,6 @@ new_skb(struct net_device *if_dev, ulong len)
return skb;
}
-static struct sk_buff *
-skb_prepare(struct aoedev *d, struct frame *f)
-{
- struct sk_buff *skb;
- char *p;
-
- skb = new_skb(d->ifp, f->ndata + f->writedatalen);
- if (!skb) {
- printk(KERN_INFO "aoe: skb_prepare: failure to allocate skb\n");
- return NULL;
- }
-
- p = skb->mac.raw;
- memcpy(p, f->data, f->ndata);
-
- if (f->writedatalen) {
- p += sizeof(struct aoe_hdr) + sizeof(struct aoe_atahdr);
- memcpy(p, f->bufaddr, f->writedatalen);
- }
-
- return skb;
-}
-
static struct frame *
getframe(struct aoedev *d, int tag)
{
@@ -107,6 +86,17 @@ aoehdr_atainit(struct aoedev *d, struct aoe_hdr *h)
return host_tag;
}
+static inline void
+put_lba(struct aoe_atahdr *ah, sector_t lba)
+{
+ ah->lba0 = lba;
+ ah->lba1 = lba >>= 8;
+ ah->lba2 = lba >>= 8;
+ ah->lba3 = lba >>= 8;
+ ah->lba4 = lba >>= 8;
+ ah->lba5 = lba >>= 8;
+}
+
static void
aoecmd_ata_rw(struct aoedev *d, struct frame *f)
{
@@ -125,29 +115,27 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
sector = buf->sector;
bcnt = buf->bv_resid;
- if (bcnt > MAXATADATA)
- bcnt = MAXATADATA;
+ if (bcnt > d->maxbcnt)
+ bcnt = d->maxbcnt;
/* initialize the headers & frame */
- h = (struct aoe_hdr *) f->data;
+ skb = f->skb;
+ h = (struct aoe_hdr *) skb->mac.raw;
ah = (struct aoe_atahdr *) (h+1);
- f->ndata = sizeof *h + sizeof *ah;
- memset(h, 0, f->ndata);
+ skb->len = sizeof *h + sizeof *ah;
+ memset(h, 0, ETH_ZLEN);
f->tag = aoehdr_atainit(d, h);
f->waited = 0;
f->buf = buf;
f->bufaddr = buf->bufaddr;
+ f->bcnt = bcnt;
+ f->lba = sector;
/* set up ata header */
ah->scnt = bcnt >> 9;
- ah->lba0 = sector;
- ah->lba1 = sector >>= 8;
- ah->lba2 = sector >>= 8;
- ah->lba3 = sector >>= 8;
+ put_lba(ah, sector);
if (d->flags & DEVFL_EXT) {
ah->aflags |= AOEAFL_EXT;
- ah->lba4 = sector >>= 8;
- ah->lba5 = sector >>= 8;
} else {
extbit = 0;
ah->lba3 &= 0x0f;
@@ -155,11 +143,14 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
}
if (bio_data_dir(buf->bio) == WRITE) {
+ skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
+ offset_in_page(f->bufaddr), bcnt);
ah->aflags |= AOEAFL_WRITE;
- f->writedatalen = bcnt;
+ skb->len += bcnt;
+ skb->data_len = bcnt;
} else {
+ skb->len = ETH_ZLEN;
writebit = 0;
- f->writedatalen = 0;
}
ah->cmdstat = WIN_READ | writebit | extbit;
@@ -168,26 +159,27 @@ aoecmd_ata_rw(struct aoedev *d, struct frame *f)
buf->nframesout += 1;
buf->bufaddr += bcnt;
buf->bv_resid -= bcnt;
-/* printk(KERN_INFO "aoe: bv_resid=%ld\n", buf->bv_resid); */
+/* printk(KERN_DEBUG "aoe: bv_resid=%ld\n", buf->bv_resid); */
buf->resid -= bcnt;
buf->sector += bcnt >> 9;
if (buf->resid == 0) {
d->inprocess = NULL;
} else if (buf->bv_resid == 0) {
buf->bv++;
+ WARN_ON(buf->bv->bv_len == 0);
buf->bv_resid = buf->bv->bv_len;
buf->bufaddr = page_address(buf->bv->bv_page) + buf->bv->bv_offset;
}
- skb = skb_prepare(d, f);
- if (skb) {
- skb->next = NULL;
- if (d->sendq_hd)
- d->sendq_tl->next = skb;
- else
- d->sendq_hd = skb;
- d->sendq_tl = skb;
- }
+ skb->dev = d->ifp;
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+ if (d->sendq_hd)
+ d->sendq_tl->next = skb;
+ else
+ d->sendq_hd = skb;
+ d->sendq_tl = skb;
}
/* some callers cannot sleep, and they can call this function,
@@ -209,11 +201,12 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
if (!is_aoe_netif(ifp))
continue;
- skb = new_skb(ifp, sizeof *h + sizeof *ch);
+ skb = new_skb(sizeof *h + sizeof *ch);
if (skb == NULL) {
- printk(KERN_INFO "aoe: aoecmd_cfg: skb alloc failure\n");
+ printk(KERN_INFO "aoe: skb alloc failure\n");
continue;
}
+ skb->dev = ifp;
if (sl_tail == NULL)
sl_tail = skb;
h = (struct aoe_hdr *) skb->mac.raw;
@@ -237,6 +230,29 @@ aoecmd_cfg_pkts(ushort aoemajor, unsigned char aoeminor, struct sk_buff **tail)
return sl;
}
+static struct frame *
+freeframe(struct aoedev *d)
+{
+ struct frame *f, *e;
+ int n = 0;
+
+ f = d->frames;
+ e = f + d->nframes;
+ for (; f<e; f++) {
+ if (f->tag != FREETAG)
+ continue;
+ if (atomic_read(&skb_shinfo(f->skb)->dataref) == 1) {
+ skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
+ return f;
+ }
+ n++;
+ }
+ if (n == d->nframes) /* wait for network layer */
+ d->flags |= DEVFL_KICKME;
+
+ return NULL;
+}
+
/* enters with d->lock held */
void
aoecmd_work(struct aoedev *d)
@@ -252,7 +268,7 @@ aoecmd_work(struct aoedev *d)
}
loop:
- f = getframe(d, FREETAG);
+ f = freeframe(d);
if (f == NULL)
return;
if (d->inprocess == NULL) {
@@ -260,7 +276,7 @@ loop:
return;
buf = container_of(d->bufq.next, struct buf, bufs);
list_del(d->bufq.next);
-/*printk(KERN_INFO "aoecmd_work: bi_size=%ld\n", buf->bio->bi_size); */
+/*printk(KERN_DEBUG "aoe: bi_size=%ld\n", buf->bio->bi_size); */
d->inprocess = buf;
}
aoecmd_ata_rw(d, f);
@@ -272,6 +288,7 @@ rexmit(struct aoedev *d, struct frame *f)
{
struct sk_buff *skb;
struct aoe_hdr *h;
+ struct aoe_atahdr *ah;
char buf[128];
u32 n;
@@ -283,21 +300,41 @@ rexmit(struct aoedev *d, struct frame *f)
d->aoemajor, d->aoeminor, f->tag, jiffies, n);
aoechr_error(buf);
- h = (struct aoe_hdr *) f->data;
+ skb = f->skb;
+ h = (struct aoe_hdr *) skb->mac.raw;
+ ah = (struct aoe_atahdr *) (h+1);
f->tag = n;
h->tag = cpu_to_be32(n);
memcpy(h->dst, d->addr, sizeof h->dst);
memcpy(h->src, d->ifp->dev_addr, sizeof h->src);
- skb = skb_prepare(d, f);
- if (skb) {
- skb->next = NULL;
- if (d->sendq_hd)
- d->sendq_tl->next = skb;
- else
- d->sendq_hd = skb;
- d->sendq_tl = skb;
+ n = DEFAULTBCNT / 512;
+ if (ah->scnt > n) {
+ ah->scnt = n;
+ if (ah->aflags & AOEAFL_WRITE) {
+ skb_fill_page_desc(skb, 0, virt_to_page(f->bufaddr),
+ offset_in_page(f->bufaddr), DEFAULTBCNT);
+ skb->len = sizeof *h + sizeof *ah + DEFAULTBCNT;
+ skb->data_len = DEFAULTBCNT;
+ }
+ if (++d->lostjumbo > (d->nframes << 1))
+ if (d->maxbcnt != DEFAULTBCNT) {
+ printk(KERN_INFO "aoe: e%ld.%ld: too many lost jumbo on %s - using 1KB frames.\n",
+ d->aoemajor, d->aoeminor, d->ifp->name);
+ d->maxbcnt = DEFAULTBCNT;
+ d->flags |= DEVFL_MAXBCNT;
+ }
}
+
+ skb->dev = d->ifp;
+ skb = skb_clone(skb, GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+ if (d->sendq_hd)
+ d->sendq_tl->next = skb;
+ else
+ d->sendq_hd = skb;
+ d->sendq_tl = skb;
}
static int
@@ -340,13 +377,17 @@ rexmit_timer(ulong vp)
if (f->tag != FREETAG && tsince(f->tag) >= timeout) {
n = f->waited += timeout;
n /= HZ;
- if (n > MAXWAIT) { /* waited too long. device failure. */
+ if (n > aoe_deadsecs) { /* waited too long for response */
aoedev_downdev(d);
break;
}
rexmit(d, f);
}
}
+ if (d->flags & DEVFL_KICKME) {
+ d->flags &= ~DEVFL_KICKME;
+ aoecmd_work(d);
+ }
sl = d->sendq_hd;
d->sendq_hd = d->sendq_tl = NULL;
@@ -431,8 +472,8 @@ ataid_complete(struct aoedev *d, unsigned char *id)
}
if (d->ssize != ssize)
- printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu "
- "sectors\n", (unsigned long long)mac_addr(d->addr),
+ printk(KERN_INFO "aoe: %012llx e%lu.%lu v%04x has %llu sectors\n",
+ (unsigned long long)mac_addr(d->addr),
d->aoemajor, d->aoeminor,
d->fw_ver, (long long)ssize);
d->ssize = ssize;
@@ -442,11 +483,9 @@ ataid_complete(struct aoedev *d, unsigned char *id)
d->flags |= DEVFL_NEWSIZE;
} else {
if (d->flags & DEVFL_GDALLOC) {
- printk(KERN_INFO "aoe: %s: %s e%lu.%lu, %s\n",
- __FUNCTION__,
- "can't schedule work for",
+ printk(KERN_ERR "aoe: can't schedule work for e%lu.%lu, %s\n",
d->aoemajor, d->aoeminor,
- "it's already on! (This really shouldn't happen).\n");
+ "it's already on! This shouldn't happen.\n");
return;
}
d->flags |= DEVFL_GDALLOC;
@@ -460,8 +499,15 @@ calc_rttavg(struct aoedev *d, int rtt)
register long n;
n = rtt;
- if (n < MINTIMER)
- n = MINTIMER;
+ if (n < 0) {
+ n = -rtt;
+ if (n < MINTIMER)
+ n = MINTIMER;
+ else if (n > MAXTIMER)
+ n = MAXTIMER;
+ d->mintimer += (n - d->mintimer) >> 1;
+ } else if (n < d->mintimer)
+ n = d->mintimer;
else if (n > MAXTIMER)
n = MAXTIMER;
@@ -474,7 +520,7 @@ void
aoecmd_ata_rsp(struct sk_buff *skb)
{
struct aoedev *d;
- struct aoe_hdr *hin;
+ struct aoe_hdr *hin, *hout;
struct aoe_atahdr *ahin, *ahout;
struct frame *f;
struct buf *buf;
@@ -497,8 +543,10 @@ aoecmd_ata_rsp(struct sk_buff *skb)
spin_lock_irqsave(&d->lock, flags);
- f = getframe(d, be32_to_cpu(hin->tag));
+ n = be32_to_cpu(hin->tag);
+ f = getframe(d, n);
if (f == NULL) {
+ calc_rttavg(d, -tsince(n));
spin_unlock_irqrestore(&d->lock, flags);
snprintf(ebuf, sizeof ebuf,
"%15s e%d.%d tag=%08x@%08lx\n",
@@ -514,26 +562,27 @@ aoecmd_ata_rsp(struct sk_buff *skb)
calc_rttavg(d, tsince(f->tag));
ahin = (struct aoe_atahdr *) (hin+1);
- ahout = (struct aoe_atahdr *) (f->data + sizeof(struct aoe_hdr));
+ hout = (struct aoe_hdr *) f->skb->mac.raw;
+ ahout = (struct aoe_atahdr *) (hout+1);
buf = f->buf;
if (ahout->cmdstat == WIN_IDENTIFY)
d->flags &= ~DEVFL_PAUSE;
if (ahin->cmdstat & 0xa9) { /* these bits cleared on success */
- printk(KERN_CRIT "aoe: aoecmd_ata_rsp: ata error cmd=%2.2Xh "
- "stat=%2.2Xh from e%ld.%ld\n",
+ printk(KERN_ERR
+ "aoe: ata error cmd=%2.2Xh stat=%2.2Xh from e%ld.%ld\n",
ahout->cmdstat, ahin->cmdstat,
d->aoemajor, d->aoeminor);
if (buf)
buf->flags |= BUFFL_FAIL;
} else {
+ n = ahout->scnt << 9;
switch (ahout->cmdstat) {
case WIN_READ:
case WIN_READ_EXT:
- n = ahout->scnt << 9;
if (skb->len - sizeof *hin - sizeof *ahin < n) {
- printk(KERN_CRIT "aoe: aoecmd_ata_rsp: runt "
- "ata data size in read. skb->len=%d\n",
+ printk(KERN_ERR
+ "aoe: runt data size in read. skb->len=%d\n",
skb->len);
/* fail frame f? just returning will rexmit. */
spin_unlock_irqrestore(&d->lock, flags);
@@ -542,22 +591,49 @@ aoecmd_ata_rsp(struct sk_buff *skb)
memcpy(f->bufaddr, ahin+1, n);
case WIN_WRITE:
case WIN_WRITE_EXT:
+ if (f->bcnt -= n) {
+ skb = f->skb;
+ f->bufaddr += n;
+ put_lba(ahout, f->lba += ahout->scnt);
+ n = f->bcnt;
+ if (n > DEFAULTBCNT)
+ n = DEFAULTBCNT;
+ ahout->scnt = n >> 9;
+ if (ahout->aflags & AOEAFL_WRITE) {
+ skb_fill_page_desc(skb, 0,
+ virt_to_page(f->bufaddr),
+ offset_in_page(f->bufaddr), n);
+ skb->len = sizeof *hout + sizeof *ahout + n;
+ skb->data_len = n;
+ }
+ f->tag = newtag(d);
+ hout->tag = cpu_to_be32(f->tag);
+ skb->dev = d->ifp;
+ skb = skb_clone(skb, GFP_ATOMIC);
+ spin_unlock_irqrestore(&d->lock, flags);
+ if (skb)
+ aoenet_xmit(skb);
+ return;
+ }
+ if (n > DEFAULTBCNT)
+ d->lostjumbo = 0;
break;
case WIN_IDENTIFY:
if (skb->len - sizeof *hin - sizeof *ahin < 512) {
- printk(KERN_INFO "aoe: aoecmd_ata_rsp: runt data size "
- "in ataid. skb->len=%d\n", skb->len);
+ printk(KERN_INFO
+ "aoe: runt data size in ataid. skb->len=%d\n",
+ skb->len);
spin_unlock_irqrestore(&d->lock, flags);
return;
}
ataid_complete(d, (char *) (ahin+1));
break;
default:
- printk(KERN_INFO "aoe: aoecmd_ata_rsp: unrecognized "
- "outbound ata command %2.2Xh for %d.%d\n",
- ahout->cmdstat,
- be16_to_cpu(hin->major),
- hin->minor);
+ printk(KERN_INFO
+ "aoe: unrecognized ata command %2.2Xh for %d.%d\n",
+ ahout->cmdstat,
+ be16_to_cpu(hin->major),
+ hin->minor);
}
}
@@ -612,33 +688,32 @@ aoecmd_ata_id(struct aoedev *d)
struct frame *f;
struct sk_buff *skb;
- f = getframe(d, FREETAG);
+ f = freeframe(d);
if (f == NULL) {
- printk(KERN_CRIT "aoe: aoecmd_ata_id: can't get a frame. "
- "This shouldn't happen.\n");
+ printk(KERN_ERR "aoe: can't get a frame. This shouldn't happen.\n");
return NULL;
}
/* initialize the headers & frame */
- h = (struct aoe_hdr *) f->data;
+ skb = f->skb;
+ h = (struct aoe_hdr *) skb->mac.raw;
ah = (struct aoe_atahdr *) (h+1);
- f->ndata = sizeof *h + sizeof *ah;
- memset(h, 0, f->ndata);
+ skb->len = ETH_ZLEN;
+ memset(h, 0, ETH_ZLEN);
f->tag = aoehdr_atainit(d, h);
f->waited = 0;
- f->writedatalen = 0;
/* set up ata header */
ah->scnt = 1;
ah->cmdstat = WIN_IDENTIFY;
ah->lba3 = 0xa0;
- skb = skb_prepare(d, f);
+ skb->dev = d->ifp;
d->rttavg = MAXTIMER;
d->timer.function = rexmit_timer;
- return skb;
+ return skb_clone(skb, GFP_ATOMIC);
}
void
@@ -648,9 +723,9 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
struct aoe_hdr *h;
struct aoe_cfghdr *ch;
ulong flags, sysminor, aoemajor;
- u16 bufcnt;
struct sk_buff *sl;
enum { MAXFRAMES = 16 };
+ u16 n;
h = (struct aoe_hdr *) skb->mac.raw;
ch = (struct aoe_cfghdr *) (h+1);
@@ -661,26 +736,25 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
*/
aoemajor = be16_to_cpu(h->major);
if (aoemajor == 0xfff) {
- printk(KERN_CRIT "aoe: aoecmd_cfg_rsp: Warning: shelf "
- "address is all ones. Check shelf dip switches\n");
+ printk(KERN_ERR "aoe: Warning: shelf address is all ones. "
+ "Check shelf dip switches.\n");
return;
}
sysminor = SYSMINOR(aoemajor, h->minor);
if (sysminor * AOE_PARTITIONS + AOE_PARTITIONS > MINORMASK) {
- printk(KERN_INFO
- "aoe: e%ld.%d: minor number too large\n",
+ printk(KERN_INFO "aoe: e%ld.%d: minor number too large\n",
aoemajor, (int) h->minor);
return;
}
- bufcnt = be16_to_cpu(ch->bufcnt);
- if (bufcnt > MAXFRAMES) /* keep it reasonable */
- bufcnt = MAXFRAMES;
+ n = be16_to_cpu(ch->bufcnt);
+ if (n > MAXFRAMES) /* keep it reasonable */
+ n = MAXFRAMES;
- d = aoedev_by_sysminor_m(sysminor, bufcnt);
+ d = aoedev_by_sysminor_m(sysminor, n);
if (d == NULL) {
- printk(KERN_INFO "aoe: aoecmd_cfg_rsp: device sysminor_m failure\n");
+ printk(KERN_INFO "aoe: device sysminor_m failure\n");
return;
}
@@ -689,6 +763,20 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
/* permit device to migrate mac and network interface */
d->ifp = skb->dev;
memcpy(d->addr, h->src, sizeof d->addr);
+ if (!(d->flags & DEVFL_MAXBCNT)) {
+ n = d->ifp->mtu;
+ n -= sizeof (struct aoe_hdr) + sizeof (struct aoe_atahdr);
+ n /= 512;
+ if (n > ch->scnt)
+ n = ch->scnt;
+ n = n ? n * 512 : DEFAULTBCNT;
+ if (n != d->maxbcnt) {
+ printk(KERN_INFO
+ "aoe: e%ld.%ld: setting %d byte data frames on %s\n",
+ d->aoemajor, d->aoeminor, n, d->ifp->name);
+ d->maxbcnt = n;
+ }
+ }
/* don't change users' perspective */
if (d->nopen && !(d->flags & DEVFL_PAUSE)) {
@@ -696,6 +784,7 @@ aoecmd_cfg_rsp(struct sk_buff *skb)
return;
}
d->flags |= DEVFL_PAUSE; /* force pause */
+ d->mintimer = MINTIMER;
d->fw_ver = be16_to_cpu(ch->fwver);
/* check for already outstanding ataid */
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index ed4258a62df5..6125921bbec4 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoedev.c
* AoE device utility functions; maintains device list.
@@ -20,11 +20,8 @@ aoedev_isbusy(struct aoedev *d)
f = d->frames;
e = f + d->nframes;
do {
- if (f->tag != FREETAG) {
- printk(KERN_DEBUG "aoe: %ld.%ld isbusy\n",
- d->aoemajor, d->aoeminor);
+ if (f->tag != FREETAG)
return 1;
- }
} while (++f < e);
return 0;
@@ -66,22 +63,32 @@ aoedev_newdev(ulong nframes)
struct frame *f, *e;
d = kzalloc(sizeof *d, GFP_ATOMIC);
- if (d == NULL)
- return NULL;
f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
- if (f == NULL) {
- kfree(d);
+ switch (!d || !f) {
+ case 0:
+ d->nframes = nframes;
+ d->frames = f;
+ e = f + nframes;
+ for (; f<e; f++) {
+ f->tag = FREETAG;
+ f->skb = new_skb(ETH_ZLEN);
+ if (!f->skb)
+ break;
+ }
+ if (f == e)
+ break;
+ while (f > d->frames) {
+ f--;
+ dev_kfree_skb(f->skb);
+ }
+ default:
+ if (f)
+ kfree(f);
+ if (d)
+ kfree(d);
return NULL;
}
-
INIT_WORK(&d->work, aoecmd_sleepwork, d);
-
- d->nframes = nframes;
- d->frames = f;
- e = f + nframes;
- for (; f<e; f++)
- f->tag = FREETAG;
-
spin_lock_init(&d->lock);
init_timer(&d->timer);
d->timer.data = (ulong) d;
@@ -114,6 +121,7 @@ aoedev_downdev(struct aoedev *d)
mempool_free(buf, d->bufpool);
bio_endio(bio, bio->bi_size, -EIO);
}
+ skb_shinfo(f->skb)->nr_frags = f->skb->data_len = 0;
}
d->inprocess = NULL;
@@ -148,7 +156,7 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt)
d = aoedev_newdev(bufcnt);
if (d == NULL) {
spin_unlock_irqrestore(&devlist_lock, flags);
- printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
+ printk(KERN_INFO "aoe: aoedev_newdev failure.\n");
return NULL;
}
d->sysminor = sysminor;
@@ -163,11 +171,19 @@ aoedev_by_sysminor_m(ulong sysminor, ulong bufcnt)
static void
aoedev_freedev(struct aoedev *d)
{
+ struct frame *f, *e;
+
if (d->gd) {
aoedisk_rm_sysfs(d);
del_gendisk(d->gd);
put_disk(d->gd);
}
+ f = d->frames;
+ e = f + d->nframes;
+ for (; f<e; f++) {
+ skb_shinfo(f->skb)->nr_frags = 0;
+ dev_kfree_skb(f->skb);
+ }
kfree(d->frames);
if (d->bufpool)
mempool_destroy(d->bufpool);
diff --git a/drivers/block/aoe/aoemain.c b/drivers/block/aoe/aoemain.c
index de08491ebe66..a04b7d613299 100644
--- a/drivers/block/aoe/aoemain.c
+++ b/drivers/block/aoe/aoemain.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoemain.c
* Module initialization routines, discover timer
@@ -84,13 +84,11 @@ aoe_init(void)
goto net_fail;
ret = register_blkdev(AOE_MAJOR, DEVICE_NAME);
if (ret < 0) {
- printk(KERN_ERR "aoe: aoeblk_init: can't register major\n");
+ printk(KERN_ERR "aoe: can't register major\n");
goto blkreg_fail;
}
- printk(KERN_INFO
- "aoe: aoe_init: AoE v%s initialised.\n",
- VERSION);
+ printk(KERN_INFO "aoe: AoE v%s initialised.\n", VERSION);
discover_timer(TINIT);
return 0;
@@ -103,7 +101,7 @@ aoe_init(void)
chr_fail:
aoedev_exit();
- printk(KERN_INFO "aoe: aoe_init: initialisation failure.\n");
+ printk(KERN_INFO "aoe: initialisation failure.\n");
return ret;
}
diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c
index c1434ed11880..9626e0f5da9d 100644
--- a/drivers/block/aoe/aoenet.c
+++ b/drivers/block/aoe/aoenet.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2004 Coraid, Inc. See COPYING for GPL terms. */
+/* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */
/*
* aoenet.c
* Ethernet portion of AoE driver
@@ -74,7 +74,7 @@ set_aoe_iflist(const char __user *user_str, size_t size)
return -EINVAL;
if (copy_from_user(aoe_iflist, user_str, size)) {
- printk(KERN_INFO "aoe: %s: copy from user failed\n", __FUNCTION__);
+ printk(KERN_INFO "aoe: copy from user failed\n");
return -EFAULT;
}
aoe_iflist[size] = 0x00;
@@ -132,8 +132,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
if (n > NECODES)
n = 0;
if (net_ratelimit())
- printk(KERN_ERR "aoe: aoenet_rcv: error packet from %d.%d; "
- "ecode=%d '%s'\n",
+ printk(KERN_ERR "aoe: error packet from %d.%d; ecode=%d '%s'\n",
be16_to_cpu(h->major), h->minor,
h->err, aoe_errlist[n]);
goto exit;
@@ -147,7 +146,7 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
aoecmd_cfg_rsp(skb);
break;
default:
- printk(KERN_INFO "aoe: aoenet_rcv: unknown cmd %d\n", h->cmd);
+ printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd);
}
exit:
dev_kfree_skb(skb);
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index c39650920bdf..14d6b9492750 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -342,7 +342,7 @@ static void fd_select_drive( int drive );
static void fd_deselect( void );
static void fd_motor_off_timer( unsigned long dummy );
static void check_change( unsigned long dummy );
-static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t floppy_irq (int irq, void *dummy);
static void fd_error( void );
static int do_format(int drive, int type, struct atari_format_descr *desc);
static void do_fd_action( int drive );
@@ -573,7 +573,7 @@ static inline void copy_buffer(void *from, void *to)
static void (*FloppyIRQHandler)( int status ) = NULL;
-static irqreturn_t floppy_irq (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t floppy_irq (int irq, void *dummy)
{
unsigned char status;
void (*handler)( int );
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index 2cd3391ff878..bc6602606fb5 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/config.h> /* CONFIG_PROC_FS */
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/types.h>
@@ -131,7 +130,7 @@ static struct board_type products[] = {
static ctlr_info_t *hba[MAX_CTLR];
static void do_cciss_request(request_queue_t *q);
-static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t do_cciss_intr(int irq, void *dev_id);
static int cciss_open(struct inode *inode, struct file *filep);
static int cciss_release(struct inode *inode, struct file *filep);
static int cciss_ioctl(struct inode *inode, struct file *filep,
@@ -144,13 +143,13 @@ static int rebuild_lun_table(ctlr_info_t *h, struct gendisk *del_disk);
static int deregister_disk(struct gendisk *disk, drive_info_struct *drv,
int clear_all);
-static void cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
- int withirq, unsigned int *total_size,
- unsigned int *block_size);
-static void cciss_geometry_inquiry(int ctlr, int logvol, int withirq,
- unsigned int total_size,
- unsigned int block_size,
- InquiryData_struct *inq_buff,
+static void cciss_read_capacity(int ctlr, int logvol, int withirq,
+ sector_t *total_size, unsigned int *block_size);
+static void cciss_read_capacity_16(int ctlr, int logvol, int withirq,
+ sector_t *total_size, unsigned int *block_size);
+static void cciss_geometry_inquiry(int ctlr, int logvol,
+ int withirq, sector_t total_size,
+ unsigned int block_size, InquiryData_struct *inq_buff,
drive_info_struct *drv);
static void cciss_getgeometry(int cntl_num);
static void __devinit cciss_interrupt_mode(ctlr_info_t *, struct pci_dev *,
@@ -879,7 +878,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
char *buff = NULL;
u64bit temp64;
unsigned long flags;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
if (!arg)
return -EINVAL;
@@ -997,7 +996,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
BYTE sg_used = 0;
int status = 0;
int i;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
__u32 left;
__u32 sz;
BYTE __user *data_ptr;
@@ -1229,7 +1228,6 @@ static inline void complete_buffers(struct bio *bio, int status)
int nr_sectors = bio_sectors(bio);
bio->bi_next = NULL;
- blk_finished_io(len);
bio_endio(bio, nr_sectors << 9, status ? 0 : -EIO);
bio = xbh;
}
@@ -1326,10 +1324,9 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
{
ctlr_info_t *h = hba[ctlr];
struct gendisk *disk;
- ReadCapdata_struct *size_buff = NULL;
InquiryData_struct *inq_buff = NULL;
unsigned int block_size;
- unsigned int total_size;
+ sector_t total_size;
unsigned long flags = 0;
int ret = 0;
@@ -1348,15 +1345,25 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
return;
/* Get information about the disk and modify the driver structure */
- size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL)
- goto mem_msg;
inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
if (inq_buff == NULL)
goto mem_msg;
- cciss_read_capacity(ctlr, drv_index, size_buff, 1,
+ cciss_read_capacity(ctlr, drv_index, 1,
&total_size, &block_size);
+
+ /* total size = last LBA + 1 */
+ /* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */
+ /* so we assume this volume this must be >2TB in size */
+ if (total_size == (__u32) 0) {
+ cciss_read_capacity_16(ctlr, drv_index, 1,
+ &total_size, &block_size);
+ h->cciss_read = CCISS_READ_16;
+ h->cciss_write = CCISS_WRITE_16;
+ } else {
+ h->cciss_read = CCISS_READ_10;
+ h->cciss_write = CCISS_WRITE_10;
+ }
cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
inq_buff, &h->drv[drv_index]);
@@ -1392,7 +1399,6 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
}
freeret:
- kfree(size_buff);
kfree(inq_buff);
return;
mem_msg:
@@ -1717,6 +1723,22 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
c->Request.Timeout = 0;
c->Request.CDB[0] = cmd;
break;
+ case CCISS_READ_CAPACITY_16:
+ c->Header.LUN.LogDev.VolId = h->drv[log_unit].LunID;
+ c->Header.LUN.LogDev.Mode = 1;
+ c->Request.CDBLen = 16;
+ c->Request.Type.Attribute = ATTR_SIMPLE;
+ c->Request.Type.Direction = XFER_READ;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = cmd;
+ c->Request.CDB[1] = 0x10;
+ c->Request.CDB[10] = (size >> 24) & 0xFF;
+ c->Request.CDB[11] = (size >> 16) & 0xFF;
+ c->Request.CDB[12] = (size >> 8) & 0xFF;
+ c->Request.CDB[13] = size & 0xFF;
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = cmd;
+ break;
case CCISS_CACHE_FLUSH:
c->Request.CDBLen = 12;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1750,6 +1772,7 @@ static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff, size_
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
c->Request.CDB[0] = cmd; /* reset */
c->Request.CDB[1] = 0x04; /* reset a LUN */
+ break;
case 3: /* No-Op message */
c->Request.CDBLen = 1;
c->Request.Type.Attribute = ATTR_SIMPLE;
@@ -1792,7 +1815,7 @@ static int sendcmd_withirq(__u8 cmd,
u64bit buff_dma_handle;
unsigned long flags;
int return_status;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
if ((c = cmd_alloc(h, 0)) == NULL)
return -ENOMEM;
@@ -1893,12 +1916,14 @@ static int sendcmd_withirq(__u8 cmd,
}
static void cciss_geometry_inquiry(int ctlr, int logvol,
- int withirq, unsigned int total_size,
+ int withirq, sector_t total_size,
unsigned int block_size,
InquiryData_struct *inq_buff,
drive_info_struct *drv)
{
int return_code;
+ unsigned long t;
+
memset(inq_buff, 0, sizeof(InquiryData_struct));
if (withirq)
return_code = sendcmd_withirq(CISS_INQUIRY, ctlr,
@@ -1913,59 +1938,98 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
printk(KERN_WARNING
"cciss: reading geometry failed, volume "
"does not support reading geometry\n");
- drv->block_size = block_size;
- drv->nr_blocks = total_size;
drv->heads = 255;
drv->sectors = 32; // Sectors per track
- drv->cylinders = total_size / 255 / 32;
} else {
- unsigned int t;
-
- drv->block_size = block_size;
- drv->nr_blocks = total_size;
drv->heads = inq_buff->data_byte[6];
drv->sectors = inq_buff->data_byte[7];
drv->cylinders = (inq_buff->data_byte[4] & 0xff) << 8;
drv->cylinders += inq_buff->data_byte[5];
drv->raid_level = inq_buff->data_byte[8];
- t = drv->heads * drv->sectors;
- if (t > 1) {
- drv->cylinders = total_size / t;
- }
+ }
+ drv->block_size = block_size;
+ drv->nr_blocks = total_size;
+ t = drv->heads * drv->sectors;
+ if (t > 1) {
+ unsigned rem = sector_div(total_size, t);
+ if (rem)
+ total_size++;
+ drv->cylinders = total_size;
}
} else { /* Get geometry failed */
printk(KERN_WARNING "cciss: reading geometry failed\n");
}
- printk(KERN_INFO " heads= %d, sectors= %d, cylinders= %d\n\n",
+ printk(KERN_INFO " heads=%d, sectors=%d, cylinders=%d\n\n",
drv->heads, drv->sectors, drv->cylinders);
}
static void
-cciss_read_capacity(int ctlr, int logvol, ReadCapdata_struct *buf,
- int withirq, unsigned int *total_size,
+cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
unsigned int *block_size)
{
+ ReadCapdata_struct *buf;
int return_code;
- memset(buf, 0, sizeof(*buf));
+ buf = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_WARNING "cciss: out of memory\n");
+ return;
+ }
+ memset(buf, 0, sizeof(ReadCapdata_struct));
if (withirq)
return_code = sendcmd_withirq(CCISS_READ_CAPACITY,
- ctlr, buf, sizeof(*buf), 1,
- logvol, 0, TYPE_CMD);
+ ctlr, buf, sizeof(ReadCapdata_struct),
+ 1, logvol, 0, TYPE_CMD);
else
return_code = sendcmd(CCISS_READ_CAPACITY,
- ctlr, buf, sizeof(*buf), 1, logvol, 0,
- NULL, TYPE_CMD);
+ ctlr, buf, sizeof(ReadCapdata_struct),
+ 1, logvol, 0, NULL, TYPE_CMD);
+ if (return_code == IO_OK) {
+ *total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1;
+ *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
+ } else { /* read capacity command failed */
+ printk(KERN_WARNING "cciss: read capacity failed\n");
+ *total_size = 0;
+ *block_size = BLOCK_SIZE;
+ }
+ if (*total_size != (__u32) 0)
+ printk(KERN_INFO " blocks= %lld block_size= %d\n",
+ *total_size, *block_size);
+ kfree(buf);
+ return;
+}
+
+static void
+cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, unsigned int *block_size)
+{
+ ReadCapdata_struct_16 *buf;
+ int return_code;
+ buf = kmalloc(sizeof(ReadCapdata_struct_16), GFP_KERNEL);
+ if (buf == NULL) {
+ printk(KERN_WARNING "cciss: out of memory\n");
+ return;
+ }
+ memset(buf, 0, sizeof(ReadCapdata_struct_16));
+ if (withirq) {
+ return_code = sendcmd_withirq(CCISS_READ_CAPACITY_16,
+ ctlr, buf, sizeof(ReadCapdata_struct_16),
+ 1, logvol, 0, TYPE_CMD);
+ }
+ else {
+ return_code = sendcmd(CCISS_READ_CAPACITY_16,
+ ctlr, buf, sizeof(ReadCapdata_struct_16),
+ 1, logvol, 0, NULL, TYPE_CMD);
+ }
if (return_code == IO_OK) {
- *total_size =
- be32_to_cpu(*((__be32 *) & buf->total_size[0])) + 1;
- *block_size = be32_to_cpu(*((__be32 *) & buf->block_size[0]));
+ *total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1;
+ *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
} else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n");
*total_size = 0;
*block_size = BLOCK_SIZE;
}
- printk(KERN_INFO " blocks= %u block_size= %d\n",
+ printk(KERN_INFO " blocks= %lld block_size= %d\n",
*total_size, *block_size);
+ kfree(buf);
return;
}
@@ -1976,8 +2040,7 @@ static int cciss_revalidate(struct gendisk *disk)
int logvol;
int FOUND = 0;
unsigned int block_size;
- unsigned int total_size;
- ReadCapdata_struct *size_buff = NULL;
+ sector_t total_size;
InquiryData_struct *inq_buff = NULL;
for (logvol = 0; logvol < CISS_MAX_LUN; logvol++) {
@@ -1990,27 +2053,24 @@ static int cciss_revalidate(struct gendisk *disk)
if (!FOUND)
return 1;
- size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL) {
- printk(KERN_WARNING "cciss: out of memory\n");
- return 1;
- }
inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
if (inq_buff == NULL) {
printk(KERN_WARNING "cciss: out of memory\n");
- kfree(size_buff);
return 1;
}
-
- cciss_read_capacity(h->ctlr, logvol, size_buff, 1, &total_size,
- &block_size);
+ if (h->cciss_read == CCISS_READ_10) {
+ cciss_read_capacity(h->ctlr, logvol, 1,
+ &total_size, &block_size);
+ } else {
+ cciss_read_capacity_16(h->ctlr, logvol, 1,
+ &total_size, &block_size);
+ }
cciss_geometry_inquiry(h->ctlr, logvol, 1, total_size, block_size,
inq_buff, drv);
blk_queue_hardsect_size(drv->queue, drv->block_size);
set_capacity(disk, drv->nr_blocks);
- kfree(size_buff);
kfree(inq_buff);
return 0;
}
@@ -2236,7 +2296,7 @@ static int sendcmd(__u8 cmd, int ctlr, void *buff, size_t size, unsigned int use
#ifdef CONFIG_CISS_SCSI_TAPE
/* if we saved some commands for later, process them now. */
if (info_p->scsi_rejects.ncompletions > 0)
- do_cciss_intr(0, info_p, NULL);
+ do_cciss_intr(0, info_p);
#endif
cmd_free(info_p, c, 1);
return status;
@@ -2419,7 +2479,8 @@ static void do_cciss_request(request_queue_t *q)
{
ctlr_info_t *h = q->queuedata;
CommandList_struct *c;
- int start_blk, seg;
+ sector_t start_blk;
+ int seg;
struct request *creq;
u64bit temp64;
struct scatterlist tmp_sg[MAXSGENTRIES];
@@ -2463,10 +2524,10 @@ static void do_cciss_request(request_queue_t *q)
c->Request.Type.Type = TYPE_CMD; // It is a command.
c->Request.Type.Attribute = ATTR_SIMPLE;
c->Request.Type.Direction =
- (rq_data_dir(creq) == READ) ? XFER_READ : XFER_WRITE;
+ (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
c->Request.Timeout = 0; // Don't time out
c->Request.CDB[0] =
- (rq_data_dir(creq) == READ) ? CCISS_READ : CCISS_WRITE;
+ (rq_data_dir(creq) == READ) ? h->cciss_read : h->cciss_write;
start_blk = creq->sector;
#ifdef CCISS_DEBUG
printk(KERN_DEBUG "ciss: sector =%d nr_sectors=%d\n", (int)creq->sector,
@@ -2500,15 +2561,33 @@ static void do_cciss_request(request_queue_t *q)
#endif /* CCISS_DEBUG */
c->Header.SGList = c->Header.SGTotal = seg;
- c->Request.CDB[1] = 0;
- c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
- c->Request.CDB[3] = (start_blk >> 16) & 0xff;
- c->Request.CDB[4] = (start_blk >> 8) & 0xff;
- c->Request.CDB[5] = start_blk & 0xff;
- c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
- c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
- c->Request.CDB[8] = creq->nr_sectors & 0xff;
- c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+ if(h->cciss_read == CCISS_READ_10) {
+ c->Request.CDB[1] = 0;
+ c->Request.CDB[2] = (start_blk >> 24) & 0xff; //MSB
+ c->Request.CDB[3] = (start_blk >> 16) & 0xff;
+ c->Request.CDB[4] = (start_blk >> 8) & 0xff;
+ c->Request.CDB[5] = start_blk & 0xff;
+ c->Request.CDB[6] = 0; // (sect >> 24) & 0xff; MSB
+ c->Request.CDB[7] = (creq->nr_sectors >> 8) & 0xff;
+ c->Request.CDB[8] = creq->nr_sectors & 0xff;
+ c->Request.CDB[9] = c->Request.CDB[11] = c->Request.CDB[12] = 0;
+ } else {
+ c->Request.CDBLen = 16;
+ c->Request.CDB[1]= 0;
+ c->Request.CDB[2]= (start_blk >> 56) & 0xff; //MSB
+ c->Request.CDB[3]= (start_blk >> 48) & 0xff;
+ c->Request.CDB[4]= (start_blk >> 40) & 0xff;
+ c->Request.CDB[5]= (start_blk >> 32) & 0xff;
+ c->Request.CDB[6]= (start_blk >> 24) & 0xff;
+ c->Request.CDB[7]= (start_blk >> 16) & 0xff;
+ c->Request.CDB[8]= (start_blk >> 8) & 0xff;
+ c->Request.CDB[9]= start_blk & 0xff;
+ c->Request.CDB[10]= (creq->nr_sectors >> 24) & 0xff;
+ c->Request.CDB[11]= (creq->nr_sectors >> 16) & 0xff;
+ c->Request.CDB[12]= (creq->nr_sectors >> 8) & 0xff;
+ c->Request.CDB[13]= creq->nr_sectors & 0xff;
+ c->Request.CDB[14] = c->Request.CDB[15] = 0;
+ }
spin_lock_irq(q->queue_lock);
@@ -2518,9 +2597,9 @@ static void do_cciss_request(request_queue_t *q)
h->maxQsinceinit = h->Qdepth;
goto queue;
- full:
+full:
blk_stop_queue(q);
- startio:
+startio:
/* We will already have the driver lock here so not need
* to lock it.
*/
@@ -2569,7 +2648,7 @@ static inline long interrupt_not_for_us(ctlr_info_t *h)
#endif
}
-static irqreturn_t do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_cciss_intr(int irq, void *dev_id)
{
ctlr_info_t *h = dev_id;
CommandList_struct *c;
@@ -2948,31 +3027,23 @@ static int cciss_pci_init(ctlr_info_t *c, struct pci_dev *pdev)
static void cciss_getgeometry(int cntl_num)
{
ReportLunData_struct *ld_buff;
- ReadCapdata_struct *size_buff;
InquiryData_struct *inq_buff;
int return_code;
int i;
int listlength = 0;
__u32 lunid = 0;
int block_size;
- int total_size;
+ sector_t total_size;
ld_buff = kzalloc(sizeof(ReportLunData_struct), GFP_KERNEL);
if (ld_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
return;
}
- size_buff = kmalloc(sizeof(ReadCapdata_struct), GFP_KERNEL);
- if (size_buff == NULL) {
- printk(KERN_ERR "cciss: out of memory\n");
- kfree(ld_buff);
- return;
- }
inq_buff = kmalloc(sizeof(InquiryData_struct), GFP_KERNEL);
if (inq_buff == NULL) {
printk(KERN_ERR "cciss: out of memory\n");
kfree(ld_buff);
- kfree(size_buff);
return;
}
/* Get the firmware version */
@@ -3027,7 +3098,6 @@ static void cciss_getgeometry(int cntl_num)
#endif /* CCISS_DEBUG */
hba[cntl_num]->highest_lun = hba[cntl_num]->num_luns - 1;
-// for(i=0; i< hba[cntl_num]->num_luns; i++)
for (i = 0; i < CISS_MAX_LUN; i++) {
if (i < hba[cntl_num]->num_luns) {
lunid = (0xff & (unsigned int)(ld_buff->LUN[i][3]))
@@ -3046,8 +3116,26 @@ static void cciss_getgeometry(int cntl_num)
ld_buff->LUN[i][2], ld_buff->LUN[i][3],
hba[cntl_num]->drv[i].LunID);
#endif /* CCISS_DEBUG */
- cciss_read_capacity(cntl_num, i, size_buff, 0,
+
+ /* testing to see if 16-byte CDBs are already being used */
+ if(hba[cntl_num]->cciss_read == CCISS_READ_16) {
+ cciss_read_capacity_16(cntl_num, i, 0,
&total_size, &block_size);
+ goto geo_inq;
+ }
+ cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size);
+
+ /* total_size = last LBA + 1 */
+ if(total_size == (__u32) 0) {
+ cciss_read_capacity_16(cntl_num, i, 0,
+ &total_size, &block_size);
+ hba[cntl_num]->cciss_read = CCISS_READ_16;
+ hba[cntl_num]->cciss_write = CCISS_WRITE_16;
+ } else {
+ hba[cntl_num]->cciss_read = CCISS_READ_10;
+ hba[cntl_num]->cciss_write = CCISS_WRITE_10;
+ }
+geo_inq:
cciss_geometry_inquiry(cntl_num, i, 0, total_size,
block_size, inq_buff,
&hba[cntl_num]->drv[i]);
@@ -3057,7 +3145,6 @@ static void cciss_getgeometry(int cntl_num)
}
}
kfree(ld_buff);
- kfree(size_buff);
kfree(inq_buff);
}
diff --git a/drivers/block/cciss.h b/drivers/block/cciss.h
index 868e0d862b0d..562235c1445a 100644
--- a/drivers/block/cciss.h
+++ b/drivers/block/cciss.h
@@ -76,6 +76,9 @@ struct ctlr_info
unsigned int intr[4];
unsigned int msix_vector;
unsigned int msi_vector;
+ BYTE cciss_read;
+ BYTE cciss_write;
+ BYTE cciss_read_capacity;
// information about each logical volume
drive_info_struct drv[CISS_MAX_LUN];
diff --git a/drivers/block/cciss_cmd.h b/drivers/block/cciss_cmd.h
index 53fea549ba8b..4af7c4c0c7af 100644
--- a/drivers/block/cciss_cmd.h
+++ b/drivers/block/cciss_cmd.h
@@ -118,11 +118,34 @@ typedef struct _ReadCapdata_struct
BYTE block_size[4]; // Size of blocks in bytes
} ReadCapdata_struct;
-// 12 byte commands not implemented in firmware yet.
-// #define CCISS_READ 0xa8 // Read(12)
-// #define CCISS_WRITE 0xaa // Write(12)
- #define CCISS_READ 0x28 // Read(10)
- #define CCISS_WRITE 0x2a // Write(10)
+#define CCISS_READ_CAPACITY_16 0x9e /* Read Capacity 16 */
+
+/* service action to differentiate a 16 byte read capacity from
+ other commands that use the 0x9e SCSI op code */
+
+#define CCISS_READ_CAPACITY_16_SERVICE_ACT 0x10
+
+typedef struct _ReadCapdata_struct_16
+{
+ BYTE total_size[8]; /* Total size in blocks */
+ BYTE block_size[4]; /* Size of blocks in bytes */
+ BYTE prot_en:1; /* protection enable bit */
+ BYTE rto_en:1; /* reference tag own enable bit */
+ BYTE reserved:6; /* reserved bits */
+ BYTE reserved2[18]; /* reserved bytes per spec */
+} ReadCapdata_struct_16;
+
+/* Define the supported read/write commands for cciss based controllers */
+
+#define CCISS_READ_10 0x28 /* Read(10) */
+#define CCISS_WRITE_10 0x2a /* Write(10) */
+#define CCISS_READ_16 0x88 /* Read(16) */
+#define CCISS_WRITE_16 0x8a /* Write(16) */
+
+/* Define the CDB lengths supported by cciss based controllers */
+
+#define CDB_LEN10 10
+#define CDB_LEN16 16
// BMIC commands
#define BMIC_READ 0x26
diff --git a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
index 05f79d7393f7..bb15051ffbe0 100644
--- a/drivers/block/cciss_scsi.c
+++ b/drivers/block/cciss_scsi.c
@@ -766,7 +766,7 @@ cciss_scsi_do_simple_cmd(ctlr_info_t *c,
int direction)
{
unsigned long flags;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
cp->cmd_type = CMD_IOCTL_PEND; // treat this like an ioctl
cp->scsi_cmd = NULL;
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 78082edc14b4..570d2f049323 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -19,7 +19,6 @@
* Questions/Comments/Bugfixes to iss_storagedev@hp.com
*
*/
-#include <linux/config.h> /* CONFIG_PROC_FS */
#include <linux/module.h>
#include <linux/types.h>
#include <linux/pci.h>
@@ -170,7 +169,7 @@ static inline cmdlist_t *removeQ(cmdlist_t **Qptr, cmdlist_t *c);
static inline void complete_buffers(struct bio *bio, int ok);
static inline void complete_command(cmdlist_t *cmd, int timeout);
-static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t do_ida_intr(int irq, void *dev_id);
static void ida_timer(unsigned long tdata);
static int ida_revalidate(struct gendisk *disk);
static int revalidate_allvol(ctlr_info_t *host);
@@ -989,7 +988,6 @@ static inline void complete_buffers(struct bio *bio, int ok)
xbh = bio->bi_next;
bio->bi_next = NULL;
- blk_finished_io(nr_sectors);
bio_endio(bio, nr_sectors << 9, ok ? 0 : -EIO);
bio = xbh;
@@ -1044,7 +1042,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
* Find the command on the completion queue, remove it, tell the OS and
* try to queue up more IO
*/
-static irqreturn_t do_ida_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_ida_intr(int irq, void *dev_id)
{
ctlr_info_t *h = dev_id;
cmdlist_t *c;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index ad1d7065a1b2..9e6d3a87cbe3 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -221,7 +221,7 @@ static DEFINE_SPINLOCK(floppy_lock);
static struct completion device_release;
static unsigned short virtual_dma_port = 0x3f0;
-irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t floppy_interrupt(int irq, void *dev_id);
static int set_dor(int fdc, char mask, char data);
#define K_64 0x10000 /* 64KB */
@@ -1726,7 +1726,7 @@ static void print_result(char *message, int inr)
}
/* interrupt handler. Note that this can be called externally on the Sparc */
-irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t floppy_interrupt(int irq, void *dev_id)
{
void (*handler) (void) = do_floppy;
int do_print;
@@ -2991,8 +2991,8 @@ static void do_fd_request(request_queue_t * q)
if (usage_count == 0) {
printk("warning: usage count=0, current_req=%p exiting\n",
current_req);
- printk("sect=%ld flags=%lx\n", (long)current_req->sector,
- current_req->flags);
+ printk("sect=%ld type=%x flags=%x\n", (long)current_req->sector,
+ current_req->cmd_type, current_req->cmd_flags);
return;
}
if (test_bit(0, &fdc_busy)) {
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 7b3b94ddddcc..beab6d2643cb 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -66,12 +66,14 @@
#include <linux/swap.h>
#include <linux/slab.h>
#include <linux/loop.h>
+#include <linux/compat.h>
#include <linux/suspend.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h> /* for invalidate_bdev() */
#include <linux/completion.h>
#include <linux/highmem.h>
#include <linux/gfp.h>
+#include <linux/kthread.h>
#include <asm/uaccess.h>
@@ -293,7 +295,7 @@ fail:
* and do_lo_send_write().
*/
static int __do_lo_send_write(struct file *file,
- u8 __user *buf, const int len, loff_t pos)
+ u8 *buf, const int len, loff_t pos)
{
ssize_t bw;
mm_segment_t old_fs = get_fs();
@@ -322,7 +324,7 @@ static int do_lo_send_direct_write(struct loop_device *lo,
struct bio_vec *bvec, int bsize, loff_t pos, struct page *page)
{
ssize_t bw = __do_lo_send_write(lo->lo_backing_file,
- (u8 __user *)kmap(bvec->bv_page) + bvec->bv_offset,
+ kmap(bvec->bv_page) + bvec->bv_offset,
bvec->bv_len, pos);
kunmap(bvec->bv_page);
cond_resched();
@@ -349,7 +351,7 @@ static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec,
bvec->bv_offset, bvec->bv_len, pos >> 9);
if (likely(!ret))
return __do_lo_send_write(lo->lo_backing_file,
- (u8 __user *)page_address(page), bvec->bv_len,
+ page_address(page), bvec->bv_len,
pos);
printk(KERN_ERR "loop: Transfer error at byte offset %llu, "
"length %i.\n", (unsigned long long)pos, bvec->bv_len);
@@ -522,15 +524,12 @@ static int loop_make_request(request_queue_t *q, struct bio *old_bio)
goto out;
if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY)))
goto out;
- lo->lo_pending++;
loop_add_bio(lo, old_bio);
+ wake_up(&lo->lo_event);
spin_unlock_irq(&lo->lo_lock);
- complete(&lo->lo_bh_done);
return 0;
out:
- if (lo->lo_pending == 0)
- complete(&lo->lo_bh_done);
spin_unlock_irq(&lo->lo_lock);
bio_io_error(old_bio, old_bio->bi_size);
return 0;
@@ -570,14 +569,18 @@ static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
* to avoid blocking in our make_request_fn. it also does loop decrypting
* on reads for block backed loop, as that is too heavy to do from
* b_end_io context where irqs may be disabled.
+ *
+ * Loop explanation: loop_clr_fd() sets lo_state to Lo_rundown before
+ * calling kthread_stop(). Therefore once kthread_should_stop() is
+ * true, make_request will not place any more requests. Therefore
+ * once kthread_should_stop() is true and lo_bio is NULL, we are
+ * done with the loop.
*/
static int loop_thread(void *data)
{
struct loop_device *lo = data;
struct bio *bio;
- daemonize("loop%d", lo->lo_number);
-
/*
* loop can be used in an encrypted device,
* hence, it mustn't be stopped at all
@@ -587,47 +590,21 @@ static int loop_thread(void *data)
set_user_nice(current, -20);
- lo->lo_state = Lo_bound;
- lo->lo_pending = 1;
+ while (!kthread_should_stop() || lo->lo_bio) {
- /*
- * complete it, we are running
- */
- complete(&lo->lo_done);
-
- for (;;) {
- int pending;
+ wait_event_interruptible(lo->lo_event,
+ lo->lo_bio || kthread_should_stop());
- if (wait_for_completion_interruptible(&lo->lo_bh_done))
+ if (!lo->lo_bio)
continue;
-
spin_lock_irq(&lo->lo_lock);
-
- /*
- * could be completed because of tear-down, not pending work
- */
- if (unlikely(!lo->lo_pending)) {
- spin_unlock_irq(&lo->lo_lock);
- break;
- }
-
bio = loop_get_bio(lo);
- lo->lo_pending--;
- pending = lo->lo_pending;
spin_unlock_irq(&lo->lo_lock);
BUG_ON(!bio);
loop_handle_bio(lo, bio);
-
- /*
- * upped both for pending work and tear-down, lo_pending
- * will hit zero then
- */
- if (unlikely(!pending))
- break;
}
- complete(&lo->lo_done);
return 0;
}
@@ -662,7 +639,8 @@ static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
lo->lo_backing_file = file;
- lo->lo_blocksize = mapping->host->i_blksize;
+ lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ?
+ mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
lo->old_gfp_mask = mapping_gfp_mask(mapping);
mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
complete(&p->wait);
@@ -794,7 +772,9 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
lo_flags |= LO_FLAGS_READ_ONLY;
- lo_blocksize = inode->i_blksize;
+ lo_blocksize = S_ISBLK(inode->i_mode) ?
+ inode->i_bdev->bd_block_size : PAGE_SIZE;
+
error = 0;
} else {
goto out_putf;
@@ -837,12 +817,26 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file,
set_blocksize(bdev, lo_blocksize);
- error = kernel_thread(loop_thread, lo, CLONE_KERNEL);
- if (error < 0)
- goto out_putf;
- wait_for_completion(&lo->lo_done);
+ lo->lo_thread = kthread_create(loop_thread, lo, "loop%d",
+ lo->lo_number);
+ if (IS_ERR(lo->lo_thread)) {
+ error = PTR_ERR(lo->lo_thread);
+ goto out_clr;
+ }
+ lo->lo_state = Lo_bound;
+ wake_up_process(lo->lo_thread);
return 0;
+out_clr:
+ lo->lo_thread = NULL;
+ lo->lo_device = NULL;
+ lo->lo_backing_file = NULL;
+ lo->lo_flags = 0;
+ set_capacity(disks[lo->lo_number], 0);
+ invalidate_bdev(bdev, 0);
+ bd_set_size(bdev, 0);
+ mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
+ lo->lo_state = Lo_unbound;
out_putf:
fput(file);
out:
@@ -904,12 +898,9 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
spin_lock_irq(&lo->lo_lock);
lo->lo_state = Lo_rundown;
- lo->lo_pending--;
- if (!lo->lo_pending)
- complete(&lo->lo_bh_done);
spin_unlock_irq(&lo->lo_lock);
- wait_for_completion(&lo->lo_done);
+ kthread_stop(lo->lo_thread);
lo->lo_backing_file = NULL;
@@ -922,6 +913,7 @@ static int loop_clr_fd(struct loop_device *lo, struct block_device *bdev)
lo->lo_sizelimit = 0;
lo->lo_encrypt_key_size = 0;
lo->lo_flags = 0;
+ lo->lo_thread = NULL;
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1174,6 +1166,162 @@ static int lo_ioctl(struct inode * inode, struct file * file,
return err;
}
+#ifdef CONFIG_COMPAT
+struct compat_loop_info {
+ compat_int_t lo_number; /* ioctl r/o */
+ compat_dev_t lo_device; /* ioctl r/o */
+ compat_ulong_t lo_inode; /* ioctl r/o */
+ compat_dev_t lo_rdevice; /* ioctl r/o */
+ compat_int_t lo_offset;
+ compat_int_t lo_encrypt_type;
+ compat_int_t lo_encrypt_key_size; /* ioctl w/o */
+ compat_int_t lo_flags; /* ioctl r/o */
+ char lo_name[LO_NAME_SIZE];
+ unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
+ compat_ulong_t lo_init[2];
+ char reserved[4];
+};
+
+/*
+ * Transfer 32-bit compatibility structure in userspace to 64-bit loop info
+ * - noinlined to reduce stack space usage in main part of driver
+ */
+static noinline int
+loop_info64_from_compat(const struct compat_loop_info __user *arg,
+ struct loop_info64 *info64)
+{
+ struct compat_loop_info info;
+
+ if (copy_from_user(&info, arg, sizeof(info)))
+ return -EFAULT;
+
+ memset(info64, 0, sizeof(*info64));
+ info64->lo_number = info.lo_number;
+ info64->lo_device = info.lo_device;
+ info64->lo_inode = info.lo_inode;
+ info64->lo_rdevice = info.lo_rdevice;
+ info64->lo_offset = info.lo_offset;
+ info64->lo_sizelimit = 0;
+ info64->lo_encrypt_type = info.lo_encrypt_type;
+ info64->lo_encrypt_key_size = info.lo_encrypt_key_size;
+ info64->lo_flags = info.lo_flags;
+ info64->lo_init[0] = info.lo_init[0];
+ info64->lo_init[1] = info.lo_init[1];
+ if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
+ memcpy(info64->lo_crypt_name, info.lo_name, LO_NAME_SIZE);
+ else
+ memcpy(info64->lo_file_name, info.lo_name, LO_NAME_SIZE);
+ memcpy(info64->lo_encrypt_key, info.lo_encrypt_key, LO_KEY_SIZE);
+ return 0;
+}
+
+/*
+ * Transfer 64-bit loop info to 32-bit compatibility structure in userspace
+ * - noinlined to reduce stack space usage in main part of driver
+ */
+static noinline int
+loop_info64_to_compat(const struct loop_info64 *info64,
+ struct compat_loop_info __user *arg)
+{
+ struct compat_loop_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.lo_number = info64->lo_number;
+ info.lo_device = info64->lo_device;
+ info.lo_inode = info64->lo_inode;
+ info.lo_rdevice = info64->lo_rdevice;
+ info.lo_offset = info64->lo_offset;
+ info.lo_encrypt_type = info64->lo_encrypt_type;
+ info.lo_encrypt_key_size = info64->lo_encrypt_key_size;
+ info.lo_flags = info64->lo_flags;
+ info.lo_init[0] = info64->lo_init[0];
+ info.lo_init[1] = info64->lo_init[1];
+ if (info.lo_encrypt_type == LO_CRYPT_CRYPTOAPI)
+ memcpy(info.lo_name, info64->lo_crypt_name, LO_NAME_SIZE);
+ else
+ memcpy(info.lo_name, info64->lo_file_name, LO_NAME_SIZE);
+ memcpy(info.lo_encrypt_key, info64->lo_encrypt_key, LO_KEY_SIZE);
+
+ /* error in case values were truncated */
+ if (info.lo_device != info64->lo_device ||
+ info.lo_rdevice != info64->lo_rdevice ||
+ info.lo_inode != info64->lo_inode ||
+ info.lo_offset != info64->lo_offset ||
+ info.lo_init[0] != info64->lo_init[0] ||
+ info.lo_init[1] != info64->lo_init[1])
+ return -EOVERFLOW;
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+}
+
+static int
+loop_set_status_compat(struct loop_device *lo,
+ const struct compat_loop_info __user *arg)
+{
+ struct loop_info64 info64;
+ int ret;
+
+ ret = loop_info64_from_compat(arg, &info64);
+ if (ret < 0)
+ return ret;
+ return loop_set_status(lo, &info64);
+}
+
+static int
+loop_get_status_compat(struct loop_device *lo,
+ struct compat_loop_info __user *arg)
+{
+ struct loop_info64 info64;
+ int err = 0;
+
+ if (!arg)
+ err = -EINVAL;
+ if (!err)
+ err = loop_get_status(lo, &info64);
+ if (!err)
+ err = loop_info64_to_compat(&info64, arg);
+ return err;
+}
+
+static long lo_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
+ int err;
+
+ lock_kernel();
+ switch(cmd) {
+ case LOOP_SET_STATUS:
+ mutex_lock(&lo->lo_ctl_mutex);
+ err = loop_set_status_compat(
+ lo, (const struct compat_loop_info __user *) arg);
+ mutex_unlock(&lo->lo_ctl_mutex);
+ break;
+ case LOOP_GET_STATUS:
+ mutex_lock(&lo->lo_ctl_mutex);
+ err = loop_get_status_compat(
+ lo, (struct compat_loop_info __user *) arg);
+ mutex_unlock(&lo->lo_ctl_mutex);
+ break;
+ case LOOP_CLR_FD:
+ case LOOP_GET_STATUS64:
+ case LOOP_SET_STATUS64:
+ arg = (unsigned long) compat_ptr(arg);
+ case LOOP_SET_FD:
+ case LOOP_CHANGE_FD:
+ err = lo_ioctl(inode, file, cmd, arg);
+ break;
+ default:
+ err = -ENOIOCTLCMD;
+ break;
+ }
+ unlock_kernel();
+ return err;
+}
+#endif
+
static int lo_open(struct inode *inode, struct file *file)
{
struct loop_device *lo = inode->i_bdev->bd_disk->private_data;
@@ -1201,6 +1349,9 @@ static struct block_device_operations lo_fops = {
.open = lo_open,
.release = lo_release,
.ioctl = lo_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lo_compat_ioctl,
+#endif
};
/*
@@ -1284,9 +1435,9 @@ static int __init loop_init(void)
if (!lo->lo_queue)
goto out_mem4;
mutex_init(&lo->lo_ctl_mutex);
- init_completion(&lo->lo_done);
- init_completion(&lo->lo_bh_done);
lo->lo_number = i;
+ lo->lo_thread = NULL;
+ init_waitqueue_head(&lo->lo_event);
spin_lock_init(&lo->lo_lock);
disk->major = LOOP_MAJOR;
disk->first_minor = i;
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index bdbade9a5cf5..9d1035e8d9d8 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -407,10 +407,10 @@ static void do_nbd_request(request_queue_t * q)
struct nbd_device *lo;
blkdev_dequeue_request(req);
- dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%lx)\n",
- req->rq_disk->disk_name, req, req->flags);
+ dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
+ req->rq_disk->disk_name, req, req->cmd_type);
- if (!(req->flags & REQ_CMD))
+ if (!blk_fs_request(req))
goto error_out;
lo = req->rq_disk->private_data;
@@ -489,7 +489,7 @@ static int nbd_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case NBD_DISCONNECT:
printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);
- sreq.flags = REQ_SPECIAL;
+ sreq.cmd_type = REQ_TYPE_SPECIAL;
nbd_cmd(&sreq) = NBD_CMD_DISC;
/*
* Set these to sane values in case server implementation
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 2403721f9db1..40a11e567970 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -437,7 +437,7 @@ static char *pd_buf; /* buffer for request in progress */
static enum action do_pd_io_start(void)
{
- if (pd_req->flags & REQ_SPECIAL) {
+ if (blk_special_request(pd_req)) {
phase = pd_special;
return pd_special();
}
@@ -713,20 +713,18 @@ static void do_pd_request(request_queue_t * q)
static int pd_special_command(struct pd_unit *disk,
enum action (*func)(struct pd_unit *disk))
{
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
struct request rq;
int err = 0;
memset(&rq, 0, sizeof(rq));
rq.errors = 0;
- rq.rq_status = RQ_ACTIVE;
rq.rq_disk = disk->gd;
rq.ref_count = 1;
- rq.waiting = &wait;
+ rq.end_io_data = &wait;
rq.end_io = blk_end_sync_rq;
blk_insert_request(disk->gd->queue, &rq, 0, func);
wait_for_completion(&wait);
- rq.waiting = NULL;
if (rq.errors)
err = -EIO;
blk_put_request(&rq);
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 451b996bba91..f2904f67af47 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -62,6 +62,8 @@
#include <asm/uaccess.h>
+#define DRIVER_NAME "pktcdvd"
+
#if PACKET_DEBUG
#define DPRINTK(fmt, args...) printk(KERN_NOTICE fmt, ##args)
#else
@@ -80,7 +82,7 @@
static struct pktcdvd_device *pkt_devs[MAX_WRITERS];
static struct proc_dir_entry *pkt_proc;
-static int pkt_major;
+static int pktdev_major;
static struct mutex ctl_mutex; /* Serialize open/close/setup/teardown */
static mempool_t *psd_pool;
@@ -89,7 +91,7 @@ static void pkt_bio_finished(struct pktcdvd_device *pd)
{
BUG_ON(atomic_read(&pd->cdrw.pending_bios) <= 0);
if (atomic_dec_and_test(&pd->cdrw.pending_bios)) {
- VPRINTK("pktcdvd: queue empty\n");
+ VPRINTK(DRIVER_NAME": queue empty\n");
atomic_set(&pd->iosched.attention, 1);
wake_up(&pd->wqueue);
}
@@ -348,7 +350,7 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
char sense[SCSI_SENSE_BUFFERSIZE];
request_queue_t *q;
struct request *rq;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
int err = 0;
q = bdev_get_queue(pd->bdev);
@@ -365,17 +367,17 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
rq->sense = sense;
memset(sense, 0, sizeof(sense));
rq->sense_len = 0;
- rq->flags |= REQ_BLOCK_PC | REQ_HARDBARRIER;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->cmd_flags |= REQ_HARDBARRIER;
if (cgc->quiet)
- rq->flags |= REQ_QUIET;
+ rq->cmd_flags |= REQ_QUIET;
memcpy(rq->cmd, cgc->cmd, CDROM_PACKET_SIZE);
if (sizeof(rq->cmd) > CDROM_PACKET_SIZE)
memset(rq->cmd + CDROM_PACKET_SIZE, 0, sizeof(rq->cmd) - CDROM_PACKET_SIZE);
rq->cmd_len = COMMAND_SIZE(rq->cmd[0]);
rq->ref_count++;
- rq->flags |= REQ_NOMERGE;
- rq->waiting = &wait;
+ rq->end_io_data = &wait;
rq->end_io = blk_end_sync_rq;
elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
generic_unplug_device(q);
@@ -400,7 +402,7 @@ static void pkt_dump_sense(struct packet_command *cgc)
int i;
struct request_sense *sense = cgc->sense;
- printk("pktcdvd:");
+ printk(DRIVER_NAME":");
for (i = 0; i < CDROM_PACKET_SIZE; i++)
printk(" %02x", cgc->cmd[i]);
printk(" - ");
@@ -528,7 +530,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
need_write_seek = 0;
if (need_write_seek && reads_queued) {
if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- VPRINTK("pktcdvd: write, waiting\n");
+ VPRINTK(DRIVER_NAME": write, waiting\n");
break;
}
pkt_flush_cache(pd);
@@ -537,7 +539,7 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
} else {
if (!reads_queued && writes_queued) {
if (atomic_read(&pd->cdrw.pending_bios) > 0) {
- VPRINTK("pktcdvd: read, waiting\n");
+ VPRINTK(DRIVER_NAME": read, waiting\n");
break;
}
pd->iosched.writing = 1;
@@ -600,7 +602,7 @@ static int pkt_set_segment_merging(struct pktcdvd_device *pd, request_queue_t *q
set_bit(PACKET_MERGE_SEGS, &pd->flags);
return 0;
} else {
- printk("pktcdvd: cdrom max_phys_segments too small\n");
+ printk(DRIVER_NAME": cdrom max_phys_segments too small\n");
return -EIO;
}
}
@@ -1049,7 +1051,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
for (f = 0; f < pkt->frames; f++)
if (!bio_add_page(pkt->w_bio, bvec[f].bv_page, CD_FRAMESIZE, bvec[f].bv_offset))
BUG();
- VPRINTK("pktcdvd: vcnt=%d\n", pkt->w_bio->bi_vcnt);
+ VPRINTK(DRIVER_NAME": vcnt=%d\n", pkt->w_bio->bi_vcnt);
atomic_set(&pkt->io_wait, 1);
pkt->w_bio->bi_rw = WRITE;
@@ -1286,7 +1288,7 @@ work_to_do:
static void pkt_print_settings(struct pktcdvd_device *pd)
{
- printk("pktcdvd: %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
+ printk(DRIVER_NAME": %s packets, ", pd->settings.fp ? "Fixed" : "Variable");
printk("%u blocks, ", pd->settings.size >> 2);
printk("Mode-%c disc\n", pd->settings.block_mode == 8 ? '1' : '2');
}
@@ -1471,7 +1473,7 @@ static int pkt_set_write_settings(struct pktcdvd_device *pd)
/*
* paranoia
*/
- printk("pktcdvd: write mode wrong %d\n", wp->data_block_type);
+ printk(DRIVER_NAME": write mode wrong %d\n", wp->data_block_type);
return 1;
}
wp->packet_size = cpu_to_be32(pd->settings.size >> 2);
@@ -1515,7 +1517,7 @@ static int pkt_writable_track(struct pktcdvd_device *pd, track_information *ti)
if (ti->rt == 1 && ti->blank == 0)
return 1;
- printk("pktcdvd: bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
+ printk(DRIVER_NAME": bad state %d-%d-%d\n", ti->rt, ti->blank, ti->packet);
return 0;
}
@@ -1533,7 +1535,7 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
case 0x12: /* DVD-RAM */
return 1;
default:
- VPRINTK("pktcdvd: Wrong disc profile (%x)\n", pd->mmc3_profile);
+ VPRINTK(DRIVER_NAME": Wrong disc profile (%x)\n", pd->mmc3_profile);
return 0;
}
@@ -1542,22 +1544,22 @@ static int pkt_writable_disc(struct pktcdvd_device *pd, disc_information *di)
* but i'm not sure, should we leave this to user apps? probably.
*/
if (di->disc_type == 0xff) {
- printk("pktcdvd: Unknown disc. No track?\n");
+ printk(DRIVER_NAME": Unknown disc. No track?\n");
return 0;
}
if (di->disc_type != 0x20 && di->disc_type != 0) {
- printk("pktcdvd: Wrong disc type (%x)\n", di->disc_type);
+ printk(DRIVER_NAME": Wrong disc type (%x)\n", di->disc_type);
return 0;
}
if (di->erasable == 0) {
- printk("pktcdvd: Disc not erasable\n");
+ printk(DRIVER_NAME": Disc not erasable\n");
return 0;
}
if (di->border_status == PACKET_SESSION_RESERVED) {
- printk("pktcdvd: Can't write to last track (reserved)\n");
+ printk(DRIVER_NAME": Can't write to last track (reserved)\n");
return 0;
}
@@ -1593,12 +1595,12 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
track = 1; /* (di.last_track_msb << 8) | di.last_track_lsb; */
if ((ret = pkt_get_track_info(pd, track, 1, &ti))) {
- printk("pktcdvd: failed get_track\n");
+ printk(DRIVER_NAME": failed get_track\n");
return ret;
}
if (!pkt_writable_track(pd, &ti)) {
- printk("pktcdvd: can't write to this track\n");
+ printk(DRIVER_NAME": can't write to this track\n");
return -EROFS;
}
@@ -1608,11 +1610,11 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
*/
pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
if (pd->settings.size == 0) {
- printk("pktcdvd: detected zero packet size!\n");
+ printk(DRIVER_NAME": detected zero packet size!\n");
return -ENXIO;
}
if (pd->settings.size > PACKET_MAX_SECTORS) {
- printk("pktcdvd: packet size is too big\n");
+ printk(DRIVER_NAME": packet size is too big\n");
return -EROFS;
}
pd->settings.fp = ti.fp;
@@ -1654,7 +1656,7 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
pd->settings.block_mode = PACKET_BLOCK_MODE2;
break;
default:
- printk("pktcdvd: unknown data mode\n");
+ printk(DRIVER_NAME": unknown data mode\n");
return -EROFS;
}
return 0;
@@ -1688,10 +1690,10 @@ static int pkt_write_caching(struct pktcdvd_device *pd, int set)
cgc.buflen = cgc.cmd[8] = 2 + ((buf[0] << 8) | (buf[1] & 0xff));
ret = pkt_mode_select(pd, &cgc);
if (ret) {
- printk("pktcdvd: write caching control failed\n");
+ printk(DRIVER_NAME": write caching control failed\n");
pkt_dump_sense(&cgc);
} else if (!ret && set)
- printk("pktcdvd: enabled write caching on %s\n", pd->name);
+ printk(DRIVER_NAME": enabled write caching on %s\n", pd->name);
return ret;
}
@@ -1805,11 +1807,11 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
}
if (!buf[6] & 0x40) {
- printk("pktcdvd: Disc type is not CD-RW\n");
+ printk(DRIVER_NAME": Disc type is not CD-RW\n");
return 1;
}
if (!buf[6] & 0x4) {
- printk("pktcdvd: A1 values on media are not valid, maybe not CDRW?\n");
+ printk(DRIVER_NAME": A1 values on media are not valid, maybe not CDRW?\n");
return 1;
}
@@ -1829,14 +1831,14 @@ static int pkt_media_speed(struct pktcdvd_device *pd, unsigned *speed)
*speed = us_clv_to_speed[sp];
break;
default:
- printk("pktcdvd: Unknown disc sub-type %d\n",st);
+ printk(DRIVER_NAME": Unknown disc sub-type %d\n",st);
return 1;
}
if (*speed) {
- printk("pktcdvd: Max. media speed: %d\n",*speed);
+ printk(DRIVER_NAME": Max. media speed: %d\n",*speed);
return 0;
} else {
- printk("pktcdvd: Unknown speed %d for sub-type %d\n",sp,st);
+ printk(DRIVER_NAME": Unknown speed %d for sub-type %d\n",sp,st);
return 1;
}
}
@@ -1847,7 +1849,7 @@ static int pkt_perform_opc(struct pktcdvd_device *pd)
struct request_sense sense;
int ret;
- VPRINTK("pktcdvd: Performing OPC\n");
+ VPRINTK(DRIVER_NAME": Performing OPC\n");
init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
cgc.sense = &sense;
@@ -1865,12 +1867,12 @@ static int pkt_open_write(struct pktcdvd_device *pd)
unsigned int write_speed, media_write_speed, read_speed;
if ((ret = pkt_probe_settings(pd))) {
- VPRINTK("pktcdvd: %s failed probe\n", pd->name);
+ VPRINTK(DRIVER_NAME": %s failed probe\n", pd->name);
return ret;
}
if ((ret = pkt_set_write_settings(pd))) {
- DPRINTK("pktcdvd: %s failed saving write settings\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s failed saving write settings\n", pd->name);
return -EIO;
}
@@ -1882,26 +1884,26 @@ static int pkt_open_write(struct pktcdvd_device *pd)
case 0x13: /* DVD-RW */
case 0x1a: /* DVD+RW */
case 0x12: /* DVD-RAM */
- DPRINTK("pktcdvd: write speed %ukB/s\n", write_speed);
+ DPRINTK(DRIVER_NAME": write speed %ukB/s\n", write_speed);
break;
default:
if ((ret = pkt_media_speed(pd, &media_write_speed)))
media_write_speed = 16;
write_speed = min(write_speed, media_write_speed * 177);
- DPRINTK("pktcdvd: write speed %ux\n", write_speed / 176);
+ DPRINTK(DRIVER_NAME": write speed %ux\n", write_speed / 176);
break;
}
read_speed = write_speed;
if ((ret = pkt_set_speed(pd, write_speed, read_speed))) {
- DPRINTK("pktcdvd: %s couldn't set write speed\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s couldn't set write speed\n", pd->name);
return -EIO;
}
pd->write_speed = write_speed;
pd->read_speed = read_speed;
if ((ret = pkt_perform_opc(pd))) {
- DPRINTK("pktcdvd: %s Optimum Power Calibration failed\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s Optimum Power Calibration failed\n", pd->name);
}
return 0;
@@ -1929,7 +1931,7 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
goto out_putdev;
if ((ret = pkt_get_last_written(pd, &lba))) {
- printk("pktcdvd: pkt_get_last_written failed\n");
+ printk(DRIVER_NAME": pkt_get_last_written failed\n");
goto out_unclaim;
}
@@ -1959,11 +1961,11 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
if (write) {
if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
- printk("pktcdvd: not enough memory for buffers\n");
+ printk(DRIVER_NAME": not enough memory for buffers\n");
ret = -ENOMEM;
goto out_unclaim;
}
- printk("pktcdvd: %lukB available on disc\n", lba << 1);
+ printk(DRIVER_NAME": %lukB available on disc\n", lba << 1);
}
return 0;
@@ -1983,7 +1985,7 @@ out:
static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
{
if (flush && pkt_flush_cache(pd))
- DPRINTK("pktcdvd: %s not flushing cache\n", pd->name);
+ DPRINTK(DRIVER_NAME": %s not flushing cache\n", pd->name);
pkt_lock_door(pd, 0);
@@ -2006,7 +2008,7 @@ static int pkt_open(struct inode *inode, struct file *file)
struct pktcdvd_device *pd = NULL;
int ret;
- VPRINTK("pktcdvd: entering open\n");
+ VPRINTK(DRIVER_NAME": entering open\n");
mutex_lock(&ctl_mutex);
pd = pkt_find_dev_from_minor(iminor(inode));
@@ -2040,7 +2042,7 @@ static int pkt_open(struct inode *inode, struct file *file)
out_dec:
pd->refcnt--;
out:
- VPRINTK("pktcdvd: failed open (%d)\n", ret);
+ VPRINTK(DRIVER_NAME": failed open (%d)\n", ret);
mutex_unlock(&ctl_mutex);
return ret;
}
@@ -2088,7 +2090,7 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
pd = q->queuedata;
if (!pd) {
- printk("pktcdvd: %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
+ printk(DRIVER_NAME": %s incorrect request queue\n", bdevname(bio->bi_bdev, b));
goto end_io;
}
@@ -2110,13 +2112,13 @@ static int pkt_make_request(request_queue_t *q, struct bio *bio)
}
if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
- printk("pktcdvd: WRITE for ro device %s (%llu)\n",
+ printk(DRIVER_NAME": WRITE for ro device %s (%llu)\n",
pd->name, (unsigned long long)bio->bi_sector);
goto end_io;
}
if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
- printk("pktcdvd: wrong bio size\n");
+ printk(DRIVER_NAME": wrong bio size\n");
goto end_io;
}
@@ -2319,7 +2321,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
struct block_device *bdev;
if (pd->pkt_dev == dev) {
- printk("pktcdvd: Recursive setup not allowed\n");
+ printk(DRIVER_NAME": Recursive setup not allowed\n");
return -EBUSY;
}
for (i = 0; i < MAX_WRITERS; i++) {
@@ -2327,11 +2329,11 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
if (!pd2)
continue;
if (pd2->bdev->bd_dev == dev) {
- printk("pktcdvd: %s already setup\n", bdevname(pd2->bdev, b));
+ printk(DRIVER_NAME": %s already setup\n", bdevname(pd2->bdev, b));
return -EBUSY;
}
if (pd2->pkt_dev == dev) {
- printk("pktcdvd: Can't chain pktcdvd devices\n");
+ printk(DRIVER_NAME": Can't chain pktcdvd devices\n");
return -EBUSY;
}
}
@@ -2354,7 +2356,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
atomic_set(&pd->cdrw.pending_bios, 0);
pd->cdrw.thread = kthread_run(kcdrwd, pd, "%s", pd->name);
if (IS_ERR(pd->cdrw.thread)) {
- printk("pktcdvd: can't start kernel thread\n");
+ printk(DRIVER_NAME": can't start kernel thread\n");
ret = -ENOMEM;
goto out_mem;
}
@@ -2364,7 +2366,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
proc->data = pd;
proc->proc_fops = &pkt_proc_fops;
}
- DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
+ DPRINTK(DRIVER_NAME": writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
return 0;
out_mem:
@@ -2401,7 +2403,7 @@ static int pkt_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
return blkdev_ioctl(pd->bdev->bd_inode, file, cmd, arg);
default:
- VPRINTK("pktcdvd: Unknown ioctl for %s (%x)\n", pd->name, cmd);
+ VPRINTK(DRIVER_NAME": Unknown ioctl for %s (%x)\n", pd->name, cmd);
return -ENOTTY;
}
@@ -2446,7 +2448,7 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
if (!pkt_devs[idx])
break;
if (idx == MAX_WRITERS) {
- printk("pktcdvd: max %d writers supported\n", MAX_WRITERS);
+ printk(DRIVER_NAME": max %d writers supported\n", MAX_WRITERS);
return -EBUSY;
}
@@ -2470,15 +2472,15 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
spin_lock_init(&pd->lock);
spin_lock_init(&pd->iosched.lock);
- sprintf(pd->name, "pktcdvd%d", idx);
+ sprintf(pd->name, DRIVER_NAME"%d", idx);
init_waitqueue_head(&pd->wqueue);
pd->bio_queue = RB_ROOT;
- disk->major = pkt_major;
+ disk->major = pktdev_major;
disk->first_minor = idx;
disk->fops = &pktcdvd_ops;
disk->flags = GENHD_FL_REMOVABLE;
- sprintf(disk->disk_name, "pktcdvd%d", idx);
+ sprintf(disk->disk_name, DRIVER_NAME"%d", idx);
disk->private_data = pd;
disk->queue = blk_alloc_queue(GFP_KERNEL);
if (!disk->queue)
@@ -2520,7 +2522,7 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
break;
}
if (idx == MAX_WRITERS) {
- DPRINTK("pktcdvd: dev not setup\n");
+ DPRINTK(DRIVER_NAME": dev not setup\n");
return -ENXIO;
}
@@ -2533,7 +2535,7 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
blkdev_put(pd->bdev);
remove_proc_entry(pd->name, pkt_proc);
- DPRINTK("pktcdvd: writer %s unmapped\n", pd->name);
+ DPRINTK(DRIVER_NAME": writer %s unmapped\n", pd->name);
del_gendisk(pd->disk);
blk_cleanup_queue(pd->disk->queue);
@@ -2610,7 +2612,7 @@ static struct file_operations pkt_ctl_fops = {
static struct miscdevice pkt_misc = {
.minor = MISC_DYNAMIC_MINOR,
- .name = "pktcdvd",
+ .name = DRIVER_NAME,
.fops = &pkt_ctl_fops
};
@@ -2623,28 +2625,28 @@ static int __init pkt_init(void)
if (!psd_pool)
return -ENOMEM;
- ret = register_blkdev(pkt_major, "pktcdvd");
+ ret = register_blkdev(pktdev_major, DRIVER_NAME);
if (ret < 0) {
- printk("pktcdvd: Unable to register block device\n");
+ printk(DRIVER_NAME": Unable to register block device\n");
goto out2;
}
- if (!pkt_major)
- pkt_major = ret;
+ if (!pktdev_major)
+ pktdev_major = ret;
ret = misc_register(&pkt_misc);
if (ret) {
- printk("pktcdvd: Unable to register misc device\n");
+ printk(DRIVER_NAME": Unable to register misc device\n");
goto out;
}
mutex_init(&ctl_mutex);
- pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
+ pkt_proc = proc_mkdir(DRIVER_NAME, proc_root_driver);
return 0;
out:
- unregister_blkdev(pkt_major, "pktcdvd");
+ unregister_blkdev(pktdev_major, DRIVER_NAME);
out2:
mempool_destroy(psd_pool);
return ret;
@@ -2652,9 +2654,9 @@ out2:
static void __exit pkt_exit(void)
{
- remove_proc_entry("pktcdvd", proc_root_driver);
+ remove_proc_entry(DRIVER_NAME, proc_root_driver);
misc_deregister(&pkt_misc);
- unregister_blkdev(pkt_major, "pktcdvd");
+ unregister_blkdev(pktdev_major, DRIVER_NAME);
mempool_destroy(psd_pool);
}
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 5537974fb242..688a4fb0dc99 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -75,8 +75,7 @@ static int ps2esdi_out_cmd_blk(u_short * cmd_blk);
static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode);
-static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id);
static void (*current_int_handler) (u_int) = NULL;
static void ps2esdi_normal_interrupt_handler(u_int);
static void ps2esdi_initial_reset_int_handler(u_int);
@@ -687,8 +686,7 @@ static void ps2esdi_prep_dma(char *buffer, u_short length, u_char dma_xmode)
-static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t ps2esdi_interrupt_handler(int irq, void *dev_id)
{
u_int int_ret_code;
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index a3f64bfe6b58..485aa87e9bcd 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -432,6 +432,12 @@ static int __init rd_init(void)
rd_disks[i] = alloc_disk(1);
if (!rd_disks[i])
goto out;
+
+ rd_queue[i] = blk_alloc_queue(GFP_KERNEL);
+ if (!rd_queue[i]) {
+ put_disk(rd_disks[i]);
+ goto out;
+ }
}
if (register_blkdev(RAMDISK_MAJOR, "ramdisk")) {
@@ -442,10 +448,6 @@ static int __init rd_init(void)
for (i = 0; i < CONFIG_BLK_DEV_RAM_COUNT; i++) {
struct gendisk *disk = rd_disks[i];
- rd_queue[i] = blk_alloc_queue(GFP_KERNEL);
- if (!rd_queue[i])
- goto out_queue;
-
blk_queue_make_request(rd_queue[i], &rd_make_request);
blk_queue_hardsect_size(rd_queue[i], rd_blocksize);
@@ -466,8 +468,6 @@ static int __init rd_init(void)
CONFIG_BLK_DEV_RAM_COUNT, rd_size, rd_blocksize);
return 0;
-out_queue:
- unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
out:
while (i--) {
put_disk(rd_disks[i]);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index cc42e762396f..1a65979f1f0f 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -238,8 +238,8 @@ static void scan_timeout(unsigned long data);
static void seek_timeout(unsigned long data);
static void settle_timeout(unsigned long data);
static void xfer_timeout(unsigned long data);
-static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-/*static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs);*/
+static irqreturn_t swim3_interrupt(int irq, void *dev_id);
+/*static void fd_dma_interrupt(int irq, void *dev_id);*/
static int grab_drive(struct floppy_state *fs, enum swim_state state,
int interruptible);
static void release_drive(struct floppy_state *fs);
@@ -319,8 +319,8 @@ static void start_request(struct floppy_state *fs)
printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
req->rq_disk->disk_name, req->cmd,
(long)req->sector, req->nr_sectors, req->buffer);
- printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n",
- req->rq_status, req->errors, req->current_nr_sectors);
+ printk(" errors=%d current_nr_sectors=%ld\n",
+ req->errors, req->current_nr_sectors);
#endif
if (req->sector < 0 || req->sector >= fs->total_secs) {
@@ -624,7 +624,7 @@ static void xfer_timeout(unsigned long data)
start_request(fs);
}
-static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t swim3_interrupt(int irq, void *dev_id)
{
struct floppy_state *fs = (struct floppy_state *) dev_id;
struct swim3 __iomem *sw = fs->swim3;
@@ -636,7 +636,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
intr = in_8(&sw->intr);
err = (intr & ERROR_INTR)? in_8(&sw->error): 0;
if ((intr & ERROR_INTR) && fs->state != do_transfer)
- printk(KERN_ERR "swim3_interrupt, state=%d, dir=%lx, intr=%x, err=%x\n",
+ printk(KERN_ERR "swim3_interrupt, state=%d, dir=%x, intr=%x, err=%x\n",
fs->state, rq_data_dir(fd_req), intr, err);
switch (fs->state) {
case locating:
@@ -742,7 +742,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if ((stat & ACTIVE) == 0 || resid != 0) {
/* musta been an error */
printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
- printk(KERN_ERR " state=%d, dir=%lx, intr=%x, err=%x\n",
+ printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n",
fs->state, rq_data_dir(fd_req), intr, err);
end_request(fd_req, 0);
fs->state = idle;
@@ -777,7 +777,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
/*
-static void fd_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void fd_dma_interrupt(int irq, void *dev_id)
{
}
*/
diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
index 89e3c2f8b776..ed7b06cf3e68 100644
--- a/drivers/block/swim_iop.c
+++ b/drivers/block/swim_iop.c
@@ -94,7 +94,7 @@ static char *drive_names[7] = {
int swimiop_init(void);
static void swimiop_init_request(struct swim_iop_req *);
static int swimiop_send_request(struct swim_iop_req *);
-static void swimiop_receive(struct iop_msg *, struct pt_regs *);
+static void swimiop_receive(struct iop_msg *);
static void swimiop_status_update(int, struct swim_drvstatus *);
static int swimiop_eject(struct floppy_state *fs);
@@ -257,7 +257,7 @@ static int swimiop_send_request(struct swim_iop_req *req)
* 2. An unsolicited message was received from the IOP.
*/
-void swimiop_receive(struct iop_msg *msg, struct pt_regs *regs)
+void swimiop_receive(struct iop_msg *msg)
{
struct swim_iop_req *req;
struct swimmsg_status *sm;
@@ -529,8 +529,8 @@ static void start_request(struct floppy_state *fs)
printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
CURRENT->rq_disk->disk_name, CURRENT->cmd,
CURRENT->sector, CURRENT->nr_sectors, CURRENT->buffer);
- printk(" rq_status=%d errors=%d current_nr_sectors=%ld\n",
- CURRENT->rq_status, CURRENT->errors, CURRENT->current_nr_sectors);
+ printk(" errors=%d current_nr_sectors=%ld\n",
+ CURRENT->errors, CURRENT->current_nr_sectors);
#endif
if (CURRENT->sector < 0 || CURRENT->sector >= fs->total_secs) {
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index c6beee18a07c..47d6975268ff 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -1200,7 +1200,7 @@ static inline void carm_handle_responses(struct carm_host *host)
host->resp_idx += work;
}
-static irqreturn_t carm_interrupt(int irq, void *__host, struct pt_regs *regs)
+static irqreturn_t carm_interrupt(int irq, void *__host)
{
struct carm_host *host = __host;
void __iomem *mmio;
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index d62b49fbf10c..0d5c73f07265 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -358,11 +358,11 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
struct ub_scsi_cmd *cmd, struct ub_request *urq);
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_end_rq(struct request *rq, int uptodate);
+static void ub_end_rq(struct request *rq, unsigned int status);
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
struct ub_request *urq, struct ub_scsi_cmd *cmd);
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
-static void ub_urb_complete(struct urb *urb, struct pt_regs *pt);
+static void ub_urb_complete(struct urb *urb);
static void ub_scsi_action(unsigned long _dev);
static void ub_scsi_dispatch(struct ub_dev *sc);
static void ub_scsi_urb_compl(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
@@ -639,9 +639,15 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
struct ub_request *urq;
int n_elem;
- if (atomic_read(&sc->poison) || lun->changed) {
+ if (atomic_read(&sc->poison)) {
+ blkdev_dequeue_request(rq);
+ ub_end_rq(rq, DID_NO_CONNECT << 16);
+ return 0;
+ }
+
+ if (lun->changed && !blk_pc_request(rq)) {
blkdev_dequeue_request(rq);
- ub_end_rq(rq, 0);
+ ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
return 0;
}
@@ -693,7 +699,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
drop:
ub_put_cmd(lun, cmd);
- ub_end_rq(rq, 0);
+ ub_end_rq(rq, DID_ERROR << 16);
return 0;
}
@@ -761,47 +767,53 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
struct ub_lun *lun = cmd->lun;
struct ub_request *urq = cmd->back;
struct request *rq;
- int uptodate;
+ unsigned int scsi_status;
rq = urq->rq;
if (cmd->error == 0) {
- uptodate = 1;
-
if (blk_pc_request(rq)) {
if (cmd->act_len >= rq->data_len)
rq->data_len = 0;
else
rq->data_len -= cmd->act_len;
}
+ scsi_status = 0;
} else {
- uptodate = 0;
-
if (blk_pc_request(rq)) {
/* UB_SENSE_SIZE is smaller than SCSI_SENSE_BUFFERSIZE */
memcpy(rq->sense, sc->top_sense, UB_SENSE_SIZE);
rq->sense_len = UB_SENSE_SIZE;
if (sc->top_sense[0] != 0)
- rq->errors = SAM_STAT_CHECK_CONDITION;
+ scsi_status = SAM_STAT_CHECK_CONDITION;
else
- rq->errors = DID_ERROR << 16;
+ scsi_status = DID_ERROR << 16;
} else {
if (cmd->error == -EIO) {
if (ub_rw_cmd_retry(sc, lun, urq, cmd) == 0)
return;
}
+ scsi_status = SAM_STAT_CHECK_CONDITION;
}
}
urq->rq = NULL;
ub_put_cmd(lun, cmd);
- ub_end_rq(rq, uptodate);
+ ub_end_rq(rq, scsi_status);
blk_start_queue(lun->disk->queue);
}
-static void ub_end_rq(struct request *rq, int uptodate)
+static void ub_end_rq(struct request *rq, unsigned int scsi_status)
{
+ int uptodate;
+
+ if (scsi_status == 0) {
+ uptodate = 1;
+ } else {
+ uptodate = 0;
+ rq->errors = scsi_status;
+ }
end_that_request_first(rq, uptodate, rq->hard_nr_sectors);
end_that_request_last(rq, uptodate);
}
@@ -947,7 +959,7 @@ static void ub_urb_timeout(unsigned long arg)
* the sc->lock taken) and from an interrupt (while we do NOT have
* the sc->lock taken). Therefore, bounce this off to a tasklet.
*/
-static void ub_urb_complete(struct urb *urb, struct pt_regs *pt)
+static void ub_urb_complete(struct urb *urb)
{
struct ub_dev *sc = urb->context;
@@ -1911,7 +1923,7 @@ err_alloc:
/*
*/
-static void ub_probe_urb_complete(struct urb *urb, struct pt_regs *pt)
+static void ub_probe_urb_complete(struct urb *urb)
{
struct completion *cop = urb->context;
complete(cop);
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 5d8925bd9045..30f16bd83650 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -552,7 +552,8 @@ static void process_page(unsigned long data)
static int mm_make_request(request_queue_t *q, struct bio *bio)
{
struct cardinfo *card = q->queuedata;
- pr_debug("mm_make_request %ld %d\n", bh->b_rsector, bh->b_size);
+ pr_debug("mm_make_request %llu %u\n",
+ (unsigned long long)bio->bi_sector, bio->bi_size);
bio->bi_phys_segments = bio->bi_idx; /* count of completed segments*/
spin_lock_irq(&card->lock);
@@ -570,7 +571,7 @@ static int mm_make_request(request_queue_t *q, struct bio *bio)
-- mm_interrupt
-----------------------------------------------------------------------------------
*/
-static irqreturn_t mm_interrupt(int irq, void *__card, struct pt_regs *regs)
+static irqreturn_t mm_interrupt(int irq, void *__card)
{
struct cardinfo *card = (struct cardinfo *) __card;
unsigned int dma_status;
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index e828e4cbd3e1..0d97b7eb818a 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -48,9 +48,9 @@
#include <linux/blkdev.h>
#include <linux/blkpg.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <asm/system.h>
-#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
@@ -313,7 +313,7 @@ static void do_xd_request (request_queue_t * q)
int res = 0;
int retry;
- if (!(req->flags & REQ_CMD)) {
+ if (!blk_fs_request(req)) {
end_request(req, 0);
continue;
}
@@ -462,8 +462,7 @@ static void xd_recalibrate (u_char drive)
}
/* xd_interrupt_handler: interrupt service routine */
-static irqreturn_t xd_interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t xd_interrupt_handler(int irq, void *dev_id)
{
if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
#ifdef DEBUG_OTHER
diff --git a/drivers/block/xd.h b/drivers/block/xd.h
index 71ac2e3dffc8..82e090fea957 100644
--- a/drivers/block/xd.h
+++ b/drivers/block/xd.h
@@ -109,8 +109,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsi
static int xd_readwrite (u_char operation,XD_INFO *disk,char *buffer,u_int block,u_int count);
static void xd_recalibrate (u_char drive);
-static irqreturn_t xd_interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t xd_interrupt_handler(int irq, void *dev_id);
static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count);
static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control);
static void xd_watchdog (unsigned long unused);
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 82ddbdd7bd4b..7cc2685ca84a 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -329,7 +329,7 @@ static struct kobject *z2_find(dev_t dev, int *part, void *data)
static struct request_queue *z2_queue;
-int __init
+static int __init
z2_init(void)
{
int ret;
@@ -370,26 +370,7 @@ err:
return ret;
}
-#if defined(MODULE)
-
-MODULE_LICENSE("GPL");
-
-int
-init_module( void )
-{
- int error;
-
- error = z2_init();
- if ( error == 0 )
- {
- printk( KERN_INFO DEVICE_NAME ": loaded as module\n" );
- }
-
- return error;
-}
-
-void
-cleanup_module( void )
+static void __exit z2_exit(void)
{
int i, j;
blk_unregister_region(MKDEV(Z2RAM_MAJOR, 0), 256);
@@ -425,4 +406,7 @@ cleanup_module( void )
return;
}
-#endif
+
+module_init(z2_init);
+module_exit(z2_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c
index 13ba729cdd57..516751754aa9 100644
--- a/drivers/bluetooth/bcm203x.c
+++ b/drivers/bluetooth/bcm203x.c
@@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
-#include <linux/timer.h>
#include <linux/device.h>
#include <linux/firmware.h>
@@ -43,7 +42,7 @@
#define BT_DBG(D...)
#endif
-#define VERSION "1.0"
+#define VERSION "1.1"
static int ignore = 0;
@@ -72,7 +71,7 @@ struct bcm203x_data {
unsigned long state;
- struct timer_list timer;
+ struct work_struct work;
struct urb *urb;
unsigned char *buffer;
@@ -82,7 +81,7 @@ struct bcm203x_data {
unsigned int fw_sent;
};
-static void bcm203x_complete(struct urb *urb, struct pt_regs *regs)
+static void bcm203x_complete(struct urb *urb)
{
struct bcm203x_data *data = urb->context;
struct usb_device *udev = urb->dev;
@@ -105,7 +104,7 @@ static void bcm203x_complete(struct urb *urb, struct pt_regs *regs)
data->state = BCM203X_SELECT_MEMORY;
- mod_timer(&data->timer, jiffies + (HZ / 10));
+ schedule_work(&data->work);
break;
case BCM203X_SELECT_MEMORY:
@@ -158,9 +157,9 @@ static void bcm203x_complete(struct urb *urb, struct pt_regs *regs)
}
}
-static void bcm203x_timer(unsigned long user_data)
+static void bcm203x_work(void *user_data)
{
- struct bcm203x_data *data = (struct bcm203x_data *) user_data;
+ struct bcm203x_data *data = user_data;
if (usb_submit_urb(data->urb, GFP_ATOMIC) < 0)
BT_ERR("Can't submit URB");
@@ -247,13 +246,11 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id
release_firmware(firmware);
- init_timer(&data->timer);
- data->timer.function = bcm203x_timer;
- data->timer.data = (unsigned long) data;
+ INIT_WORK(&data->work, bcm203x_work, (void *) data);
usb_set_intfdata(intf, data);
- mod_timer(&data->timer, jiffies + HZ);
+ schedule_work(&data->work);
return 0;
}
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index 23f96213f4ac..31ade991aa91 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -2,7 +2,7 @@
*
* AVM BlueFRITZ! USB driver
*
- * Copyright (C) 2003 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2003-2006 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -59,7 +59,6 @@ static struct usb_device_id bfusb_table[] = {
MODULE_DEVICE_TABLE(usb, bfusb_table);
-
#define BFUSB_MAX_BLOCK_SIZE 256
#define BFUSB_BLOCK_TIMEOUT 3000
@@ -70,7 +69,7 @@ MODULE_DEVICE_TABLE(usb, bfusb_table);
#define BFUSB_MAX_BULK_TX 2
#define BFUSB_MAX_BULK_RX 2
-struct bfusb {
+struct bfusb_data {
struct hci_dev *hdev;
unsigned long state;
@@ -92,137 +91,136 @@ struct bfusb {
struct sk_buff_head completed_q;
};
-struct bfusb_scb {
+struct bfusb_data_scb {
struct urb *urb;
};
-static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs);
-static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs);
+static void bfusb_tx_complete(struct urb *urb);
+static void bfusb_rx_complete(struct urb *urb);
-static struct urb *bfusb_get_completed(struct bfusb *bfusb)
+static struct urb *bfusb_get_completed(struct bfusb_data *data)
{
struct sk_buff *skb;
struct urb *urb = NULL;
- BT_DBG("bfusb %p", bfusb);
+ BT_DBG("bfusb %p", data);
- skb = skb_dequeue(&bfusb->completed_q);
+ skb = skb_dequeue(&data->completed_q);
if (skb) {
- urb = ((struct bfusb_scb *) skb->cb)->urb;
+ urb = ((struct bfusb_data_scb *) skb->cb)->urb;
kfree_skb(skb);
}
return urb;
}
-static void bfusb_unlink_urbs(struct bfusb *bfusb)
+static void bfusb_unlink_urbs(struct bfusb_data *data)
{
struct sk_buff *skb;
struct urb *urb;
- BT_DBG("bfusb %p", bfusb);
+ BT_DBG("bfusb %p", data);
- while ((skb = skb_dequeue(&bfusb->pending_q))) {
- urb = ((struct bfusb_scb *) skb->cb)->urb;
+ while ((skb = skb_dequeue(&data->pending_q))) {
+ urb = ((struct bfusb_data_scb *) skb->cb)->urb;
usb_kill_urb(urb);
- skb_queue_tail(&bfusb->completed_q, skb);
+ skb_queue_tail(&data->completed_q, skb);
}
- while ((urb = bfusb_get_completed(bfusb)))
+ while ((urb = bfusb_get_completed(data)))
usb_free_urb(urb);
}
-
-static int bfusb_send_bulk(struct bfusb *bfusb, struct sk_buff *skb)
+static int bfusb_send_bulk(struct bfusb_data *data, struct sk_buff *skb)
{
- struct bfusb_scb *scb = (void *) skb->cb;
- struct urb *urb = bfusb_get_completed(bfusb);
+ struct bfusb_data_scb *scb = (void *) skb->cb;
+ struct urb *urb = bfusb_get_completed(data);
int err, pipe;
- BT_DBG("bfusb %p skb %p len %d", bfusb, skb, skb->len);
+ BT_DBG("bfusb %p skb %p len %d", data, skb, skb->len);
if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
return -ENOMEM;
- pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
+ pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
- usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, skb->len,
+ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, skb->len,
bfusb_tx_complete, skb);
scb->urb = urb;
- skb_queue_tail(&bfusb->pending_q, skb);
+ skb_queue_tail(&data->pending_q, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk tx submit failed urb %p err %d",
- bfusb->hdev->name, urb, err);
- skb_unlink(skb, &bfusb->pending_q);
+ data->hdev->name, urb, err);
+ skb_unlink(skb, &data->pending_q);
usb_free_urb(urb);
} else
- atomic_inc(&bfusb->pending_tx);
+ atomic_inc(&data->pending_tx);
return err;
}
-static void bfusb_tx_wakeup(struct bfusb *bfusb)
+static void bfusb_tx_wakeup(struct bfusb_data *data)
{
struct sk_buff *skb;
- BT_DBG("bfusb %p", bfusb);
+ BT_DBG("bfusb %p", data);
- if (test_and_set_bit(BFUSB_TX_PROCESS, &bfusb->state)) {
- set_bit(BFUSB_TX_WAKEUP, &bfusb->state);
+ if (test_and_set_bit(BFUSB_TX_PROCESS, &data->state)) {
+ set_bit(BFUSB_TX_WAKEUP, &data->state);
return;
}
do {
- clear_bit(BFUSB_TX_WAKEUP, &bfusb->state);
+ clear_bit(BFUSB_TX_WAKEUP, &data->state);
- while ((atomic_read(&bfusb->pending_tx) < BFUSB_MAX_BULK_TX) &&
- (skb = skb_dequeue(&bfusb->transmit_q))) {
- if (bfusb_send_bulk(bfusb, skb) < 0) {
- skb_queue_head(&bfusb->transmit_q, skb);
+ while ((atomic_read(&data->pending_tx) < BFUSB_MAX_BULK_TX) &&
+ (skb = skb_dequeue(&data->transmit_q))) {
+ if (bfusb_send_bulk(data, skb) < 0) {
+ skb_queue_head(&data->transmit_q, skb);
break;
}
}
- } while (test_bit(BFUSB_TX_WAKEUP, &bfusb->state));
+ } while (test_bit(BFUSB_TX_WAKEUP, &data->state));
- clear_bit(BFUSB_TX_PROCESS, &bfusb->state);
+ clear_bit(BFUSB_TX_PROCESS, &data->state);
}
-static void bfusb_tx_complete(struct urb *urb, struct pt_regs *regs)
+static void bfusb_tx_complete(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct bfusb *bfusb = (struct bfusb *) skb->dev;
+ struct bfusb_data *data = (struct bfusb_data *) skb->dev;
- BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
+ BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len);
- atomic_dec(&bfusb->pending_tx);
+ atomic_dec(&data->pending_tx);
- if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
+ if (!test_bit(HCI_RUNNING, &data->hdev->flags))
return;
if (!urb->status)
- bfusb->hdev->stat.byte_tx += skb->len;
+ data->hdev->stat.byte_tx += skb->len;
else
- bfusb->hdev->stat.err_tx++;
+ data->hdev->stat.err_tx++;
- read_lock(&bfusb->lock);
+ read_lock(&data->lock);
- skb_unlink(skb, &bfusb->pending_q);
- skb_queue_tail(&bfusb->completed_q, skb);
+ skb_unlink(skb, &data->pending_q);
+ skb_queue_tail(&data->completed_q, skb);
- bfusb_tx_wakeup(bfusb);
+ bfusb_tx_wakeup(data);
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
}
-static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
+static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb)
{
- struct bfusb_scb *scb;
+ struct bfusb_data_scb *scb;
struct sk_buff *skb;
int err, pipe, size = HCI_MAX_FRAME_SIZE + 32;
@@ -231,28 +229,29 @@ static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC)))
return -ENOMEM;
- if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) {
+ skb = bt_skb_alloc(size, GFP_ATOMIC);
+ if (!skb) {
usb_free_urb(urb);
return -ENOMEM;
}
- skb->dev = (void *) bfusb;
+ skb->dev = (void *) data;
- scb = (struct bfusb_scb *) skb->cb;
+ scb = (struct bfusb_data_scb *) skb->cb;
scb->urb = urb;
- pipe = usb_rcvbulkpipe(bfusb->udev, bfusb->bulk_in_ep);
+ pipe = usb_rcvbulkpipe(data->udev, data->bulk_in_ep);
- usb_fill_bulk_urb(urb, bfusb->udev, pipe, skb->data, size,
+ usb_fill_bulk_urb(urb, data->udev, pipe, skb->data, size,
bfusb_rx_complete, skb);
- skb_queue_tail(&bfusb->pending_q, skb);
+ skb_queue_tail(&data->pending_q, skb);
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk rx submit failed urb %p err %d",
- bfusb->hdev->name, urb, err);
- skb_unlink(skb, &bfusb->pending_q);
+ data->hdev->name, urb, err);
+ skb_unlink(skb, &data->pending_q);
kfree_skb(skb);
usb_free_urb(urb);
}
@@ -260,15 +259,15 @@ static int bfusb_rx_submit(struct bfusb *bfusb, struct urb *urb)
return err;
}
-static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *data, int len)
+static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned char *buf, int len)
{
- BT_DBG("bfusb %p hdr 0x%02x data %p len %d", bfusb, hdr, data, len);
+ BT_DBG("bfusb %p hdr 0x%02x data %p len %d", data, hdr, buf, len);
if (hdr & 0x10) {
- BT_ERR("%s error in block", bfusb->hdev->name);
- if (bfusb->reassembly)
- kfree_skb(bfusb->reassembly);
- bfusb->reassembly = NULL;
+ BT_ERR("%s error in block", data->hdev->name);
+ if (data->reassembly)
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
return -EIO;
}
@@ -277,46 +276,46 @@ static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *
unsigned char pkt_type;
int pkt_len = 0;
- if (bfusb->reassembly) {
- BT_ERR("%s unexpected start block", bfusb->hdev->name);
- kfree_skb(bfusb->reassembly);
- bfusb->reassembly = NULL;
+ if (data->reassembly) {
+ BT_ERR("%s unexpected start block", data->hdev->name);
+ kfree_skb(data->reassembly);
+ data->reassembly = NULL;
}
if (len < 1) {
- BT_ERR("%s no packet type found", bfusb->hdev->name);
+ BT_ERR("%s no packet type found", data->hdev->name);
return -EPROTO;
}
- pkt_type = *data++; len--;
+ pkt_type = *buf++; len--;
switch (pkt_type) {
case HCI_EVENT_PKT:
if (len >= HCI_EVENT_HDR_SIZE) {
- struct hci_event_hdr *hdr = (struct hci_event_hdr *) data;
+ struct hci_event_hdr *hdr = (struct hci_event_hdr *) buf;
pkt_len = HCI_EVENT_HDR_SIZE + hdr->plen;
} else {
- BT_ERR("%s event block is too short", bfusb->hdev->name);
+ BT_ERR("%s event block is too short", data->hdev->name);
return -EILSEQ;
}
break;
case HCI_ACLDATA_PKT:
if (len >= HCI_ACL_HDR_SIZE) {
- struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) data;
+ struct hci_acl_hdr *hdr = (struct hci_acl_hdr *) buf;
pkt_len = HCI_ACL_HDR_SIZE + __le16_to_cpu(hdr->dlen);
} else {
- BT_ERR("%s data block is too short", bfusb->hdev->name);
+ BT_ERR("%s data block is too short", data->hdev->name);
return -EILSEQ;
}
break;
case HCI_SCODATA_PKT:
if (len >= HCI_SCO_HDR_SIZE) {
- struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) data;
+ struct hci_sco_hdr *hdr = (struct hci_sco_hdr *) buf;
pkt_len = HCI_SCO_HDR_SIZE + hdr->dlen;
} else {
- BT_ERR("%s audio block is too short", bfusb->hdev->name);
+ BT_ERR("%s audio block is too short", data->hdev->name);
return -EILSEQ;
}
break;
@@ -324,51 +323,51 @@ static inline int bfusb_recv_block(struct bfusb *bfusb, int hdr, unsigned char *
skb = bt_skb_alloc(pkt_len, GFP_ATOMIC);
if (!skb) {
- BT_ERR("%s no memory for the packet", bfusb->hdev->name);
+ BT_ERR("%s no memory for the packet", data->hdev->name);
return -ENOMEM;
}
- skb->dev = (void *) bfusb->hdev;
+ skb->dev = (void *) data->hdev;
bt_cb(skb)->pkt_type = pkt_type;
- bfusb->reassembly = skb;
+ data->reassembly = skb;
} else {
- if (!bfusb->reassembly) {
- BT_ERR("%s unexpected continuation block", bfusb->hdev->name);
+ if (!data->reassembly) {
+ BT_ERR("%s unexpected continuation block", data->hdev->name);
return -EIO;
}
}
if (len > 0)
- memcpy(skb_put(bfusb->reassembly, len), data, len);
+ memcpy(skb_put(data->reassembly, len), buf, len);
if (hdr & 0x08) {
- hci_recv_frame(bfusb->reassembly);
- bfusb->reassembly = NULL;
+ hci_recv_frame(data->reassembly);
+ data->reassembly = NULL;
}
return 0;
}
-static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs)
+static void bfusb_rx_complete(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
- struct bfusb *bfusb = (struct bfusb *) skb->dev;
+ struct bfusb_data *data = (struct bfusb_data *) skb->dev;
unsigned char *buf = urb->transfer_buffer;
int count = urb->actual_length;
int err, hdr, len;
BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len);
- read_lock(&bfusb->lock);
+ read_lock(&data->lock);
- if (!test_bit(HCI_RUNNING, &bfusb->hdev->flags))
+ if (!test_bit(HCI_RUNNING, &data->hdev->flags))
goto unlock;
if (urb->status || !count)
goto resubmit;
- bfusb->hdev->stat.byte_rx += count;
+ data->hdev->stat.byte_rx += count;
skb_put(skb, count);
@@ -387,90 +386,89 @@ static void bfusb_rx_complete(struct urb *urb, struct pt_regs *regs)
if (count < len) {
BT_ERR("%s block extends over URB buffer ranges",
- bfusb->hdev->name);
+ data->hdev->name);
}
if ((hdr & 0xe1) == 0xc1)
- bfusb_recv_block(bfusb, hdr, buf, len);
+ bfusb_recv_block(data, hdr, buf, len);
count -= len;
buf += len;
}
- skb_unlink(skb, &bfusb->pending_q);
+ skb_unlink(skb, &data->pending_q);
kfree_skb(skb);
- bfusb_rx_submit(bfusb, urb);
+ bfusb_rx_submit(data, urb);
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
return;
resubmit:
- urb->dev = bfusb->udev;
+ urb->dev = data->udev;
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err) {
BT_ERR("%s bulk resubmit failed urb %p err %d",
- bfusb->hdev->name, urb, err);
+ data->hdev->name, urb, err);
}
unlock:
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
}
-
static int bfusb_open(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
unsigned long flags;
int i, err;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
if (test_and_set_bit(HCI_RUNNING, &hdev->flags))
return 0;
- write_lock_irqsave(&bfusb->lock, flags);
+ write_lock_irqsave(&data->lock, flags);
- err = bfusb_rx_submit(bfusb, NULL);
+ err = bfusb_rx_submit(data, NULL);
if (!err) {
for (i = 1; i < BFUSB_MAX_BULK_RX; i++)
- bfusb_rx_submit(bfusb, NULL);
+ bfusb_rx_submit(data, NULL);
} else {
clear_bit(HCI_RUNNING, &hdev->flags);
}
- write_unlock_irqrestore(&bfusb->lock, flags);
+ write_unlock_irqrestore(&data->lock, flags);
return err;
}
static int bfusb_flush(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
- skb_queue_purge(&bfusb->transmit_q);
+ skb_queue_purge(&data->transmit_q);
return 0;
}
static int bfusb_close(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
unsigned long flags;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- write_lock_irqsave(&bfusb->lock, flags);
- write_unlock_irqrestore(&bfusb->lock, flags);
+ write_lock_irqsave(&data->lock, flags);
+ write_unlock_irqrestore(&data->lock, flags);
- bfusb_unlink_urbs(bfusb);
+ bfusb_unlink_urbs(data);
bfusb_flush(hdev);
return 0;
@@ -479,7 +477,7 @@ static int bfusb_close(struct hci_dev *hdev)
static int bfusb_send_frame(struct sk_buff *skb)
{
struct hci_dev *hdev = (struct hci_dev *) skb->dev;
- struct bfusb *bfusb;
+ struct bfusb_data *data;
struct sk_buff *nskb;
unsigned char buf[3];
int sent = 0, size, count;
@@ -494,7 +492,7 @@ static int bfusb_send_frame(struct sk_buff *skb)
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
- bfusb = (struct bfusb *) hdev->driver_data;
+ data = hdev->driver_data;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
@@ -514,12 +512,13 @@ static int bfusb_send_frame(struct sk_buff *skb)
count = skb->len;
/* Max HCI frame size seems to be 1511 + 1 */
- if (!(nskb = bt_skb_alloc(count + 32, GFP_ATOMIC))) {
+ nskb = bt_skb_alloc(count + 32, GFP_ATOMIC);
+ if (!nskb) {
BT_ERR("Can't allocate memory for new packet");
return -ENOMEM;
}
- nskb->dev = (void *) bfusb;
+ nskb->dev = (void *) data;
while (count) {
size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE);
@@ -536,18 +535,18 @@ static int bfusb_send_frame(struct sk_buff *skb)
}
/* Don't send frame with multiple size of bulk max packet */
- if ((nskb->len % bfusb->bulk_pkt_size) == 0) {
+ if ((nskb->len % data->bulk_pkt_size) == 0) {
buf[0] = 0xdd;
buf[1] = 0x00;
memcpy(skb_put(nskb, 2), buf, 2);
}
- read_lock(&bfusb->lock);
+ read_lock(&data->lock);
- skb_queue_tail(&bfusb->transmit_q, nskb);
- bfusb_tx_wakeup(bfusb);
+ skb_queue_tail(&data->transmit_q, nskb);
+ bfusb_tx_wakeup(data);
- read_unlock(&bfusb->lock);
+ read_unlock(&data->lock);
kfree_skb(skb);
@@ -556,11 +555,11 @@ static int bfusb_send_frame(struct sk_buff *skb)
static void bfusb_destruct(struct hci_dev *hdev)
{
- struct bfusb *bfusb = (struct bfusb *) hdev->driver_data;
+ struct bfusb_data *data = hdev->driver_data;
- BT_DBG("hdev %p bfusb %p", hdev, bfusb);
+ BT_DBG("hdev %p bfusb %p", hdev, data);
- kfree(bfusb);
+ kfree(data);
}
static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg)
@@ -568,25 +567,24 @@ static int bfusb_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg
return -ENOIOCTLCMD;
}
-
-static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int count)
+static int bfusb_load_firmware(struct bfusb_data *data, unsigned char *firmware, int count)
{
unsigned char *buf;
int err, pipe, len, size, sent = 0;
- BT_DBG("bfusb %p udev %p", bfusb, bfusb->udev);
+ BT_DBG("bfusb %p udev %p", data, data->udev);
BT_INFO("BlueFRITZ! USB loading firmware");
- pipe = usb_sndctrlpipe(bfusb->udev, 0);
+ pipe = usb_sndctrlpipe(data->udev, 0);
- if (usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ if (usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
0, 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT) < 0) {
BT_ERR("Can't change to loading configuration");
return -EBUSY;
}
- bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
+ data->udev->toggle[0] = data->udev->toggle[1] = 0;
buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
if (!buf) {
@@ -594,14 +592,14 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
return -ENOMEM;
}
- pipe = usb_sndbulkpipe(bfusb->udev, bfusb->bulk_out_ep);
+ pipe = usb_sndbulkpipe(data->udev, data->bulk_out_ep);
while (count) {
size = min_t(uint, count, BFUSB_MAX_BLOCK_SIZE + 3);
memcpy(buf, firmware + sent, size);
- err = usb_bulk_msg(bfusb->udev, pipe, buf, size,
+ err = usb_bulk_msg(data->udev, pipe, buf, size,
&len, BFUSB_BLOCK_TIMEOUT);
if (err || (len != size)) {
@@ -613,21 +611,23 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
count -= size;
}
- if ((err = usb_bulk_msg(bfusb->udev, pipe, NULL, 0,
- &len, BFUSB_BLOCK_TIMEOUT)) < 0) {
+ err = usb_bulk_msg(data->udev, pipe, NULL, 0,
+ &len, BFUSB_BLOCK_TIMEOUT);
+ if (err < 0) {
BT_ERR("Error in null packet request");
goto error;
}
- pipe = usb_sndctrlpipe(bfusb->udev, 0);
+ pipe = usb_sndctrlpipe(data->udev, 0);
- if ((err = usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
- 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT)) < 0) {
+ err = usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ 0, 2, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ if (err < 0) {
BT_ERR("Can't change to running configuration");
goto error;
}
- bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
+ data->udev->toggle[0] = data->udev->toggle[1] = 0;
BT_INFO("BlueFRITZ! USB device ready");
@@ -637,9 +637,9 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
error:
kfree(buf);
- pipe = usb_sndctrlpipe(bfusb->udev, 0);
+ pipe = usb_sndctrlpipe(data->udev, 0);
- usb_control_msg(bfusb->udev, pipe, USB_REQ_SET_CONFIGURATION,
+ usb_control_msg(data->udev, pipe, USB_REQ_SET_CONFIGURATION,
0, 0, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
return err;
@@ -652,7 +652,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
struct usb_host_endpoint *bulk_out_ep;
struct usb_host_endpoint *bulk_in_ep;
struct hci_dev *hdev;
- struct bfusb *bfusb;
+ struct bfusb_data *data;
BT_DBG("intf %p id %p", intf, id);
@@ -672,23 +672,24 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
}
/* Initialize control structure and load firmware */
- if (!(bfusb = kzalloc(sizeof(struct bfusb), GFP_KERNEL))) {
+ data = kzalloc(sizeof(struct bfusb_data), GFP_KERNEL);
+ if (!data) {
BT_ERR("Can't allocate memory for control structure");
goto done;
}
- bfusb->udev = udev;
- bfusb->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
- bfusb->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
- bfusb->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
+ data->udev = udev;
+ data->bulk_in_ep = bulk_in_ep->desc.bEndpointAddress;
+ data->bulk_out_ep = bulk_out_ep->desc.bEndpointAddress;
+ data->bulk_pkt_size = le16_to_cpu(bulk_out_ep->desc.wMaxPacketSize);
- rwlock_init(&bfusb->lock);
+ rwlock_init(&data->lock);
- bfusb->reassembly = NULL;
+ data->reassembly = NULL;
- skb_queue_head_init(&bfusb->transmit_q);
- skb_queue_head_init(&bfusb->pending_q);
- skb_queue_head_init(&bfusb->completed_q);
+ skb_queue_head_init(&data->transmit_q);
+ skb_queue_head_init(&data->pending_q);
+ skb_queue_head_init(&data->completed_q);
if (request_firmware(&firmware, "bfubase.frm", &udev->dev) < 0) {
BT_ERR("Firmware request failed");
@@ -697,7 +698,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
BT_DBG("firmware data %p size %d", firmware->data, firmware->size);
- if (bfusb_load_firmware(bfusb, firmware->data, firmware->size) < 0) {
+ if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) {
BT_ERR("Firmware loading failed");
goto release;
}
@@ -711,10 +712,10 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
goto error;
}
- bfusb->hdev = hdev;
+ data->hdev = hdev;
hdev->type = HCI_USB;
- hdev->driver_data = bfusb;
+ hdev->driver_data = data;
SET_HCIDEV_DEV(hdev, &intf->dev);
hdev->open = bfusb_open;
@@ -732,7 +733,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
goto error;
}
- usb_set_intfdata(intf, bfusb);
+ usb_set_intfdata(intf, data);
return 0;
@@ -740,7 +741,7 @@ release:
release_firmware(firmware);
error:
- kfree(bfusb);
+ kfree(data);
done:
return -EIO;
@@ -748,8 +749,8 @@ done:
static void bfusb_disconnect(struct usb_interface *intf)
{
- struct bfusb *bfusb = usb_get_intfdata(intf);
- struct hci_dev *hdev = bfusb->hdev;
+ struct bfusb_data *data = usb_get_intfdata(intf);
+ struct hci_dev *hdev = data->hdev;
BT_DBG("intf %p", intf);
@@ -779,7 +780,8 @@ static int __init bfusb_init(void)
BT_INFO("BlueFRITZ! USB driver ver %s", VERSION);
- if ((err = usb_register(&bfusb_driver)) < 0)
+ err = usb_register(&bfusb_driver);
+ if (err < 0)
BT_ERR("Failed to register BlueFRITZ! USB driver");
return err;
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 8eebf9ca3786..845b8680032a 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -497,7 +497,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
}
-static irqreturn_t bluecard_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+static irqreturn_t bluecard_interrupt(int irq, void *dev_inst)
{
bluecard_info_t *info = dev_inst;
unsigned int iobase;
diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c
index e0231dc2cb1a..9fca6513562d 100644
--- a/drivers/bluetooth/bpa10x.c
+++ b/drivers/bluetooth/bpa10x.c
@@ -263,7 +263,7 @@ static void bpa10x_wakeup(struct bpa10x_data *data)
}
}
-static void bpa10x_complete(struct urb *urb, struct pt_regs *regs)
+static void bpa10x_complete(struct urb *urb)
{
struct bpa10x_data *data = urb->context;
unsigned char *buf = urb->transfer_buffer;
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index df7bb016df49..3a96a0babc6a 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -338,7 +338,7 @@ static void bt3c_receive(bt3c_info_t *info)
}
-static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
{
bt3c_info_t *info = dev_inst;
unsigned int iobase;
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index 746ccca97f6f..3b29086b7c3f 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -288,7 +288,7 @@ static void btuart_receive(btuart_info_t *info)
}
-static irqreturn_t btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+static irqreturn_t btuart_interrupt(int irq, void *dev_inst)
{
btuart_info_t *info = dev_inst;
unsigned int iobase;
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 0e99def8a1e3..07eafbc5dc3a 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -291,7 +291,7 @@ static void dtl1_receive(dtl1_info_t *info)
}
-static irqreturn_t dtl1_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
+static irqreturn_t dtl1_interrupt(int irq, void *dev_inst)
{
dtl1_info_t *info = dev_inst;
unsigned int iobase;
@@ -711,6 +711,7 @@ static void dtl1_release(struct pcmcia_device *link)
static struct pcmcia_device_id dtl1_ids[] = {
PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
+ PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-4", 0xe1bfdd64, 0x9102bc82),
PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
PCMCIA_DEVICE_PROD_ID12("Socket", "CF+ Personal Network Card", 0xb38bcc2e, 0xe732bae3),
PCMCIA_DEVICE_NULL
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 93ba25b7ea32..420b645c4c9f 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -241,15 +241,11 @@ static int hci_uart_send_frame(struct sk_buff *skb)
static void hci_uart_destruct(struct hci_dev *hdev)
{
- struct hci_uart *hu;
-
if (!hdev)
return;
BT_DBG("%s", hdev->name);
-
- hu = (struct hci_uart *) hdev->driver_data;
- kfree(hu);
+ kfree(hdev->driver_data);
}
/* ------ LDISC part ------ */
@@ -272,7 +268,7 @@ static int hci_uart_tty_open(struct tty_struct *tty)
return -EEXIST;
if (!(hu = kzalloc(sizeof(struct hci_uart), GFP_KERNEL))) {
- BT_ERR("Can't allocate controll structure");
+ BT_ERR("Can't allocate control structure");
return -ENFILE;
}
@@ -360,7 +356,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
*
* Return Value: None
*/
-static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
{
struct hci_uart *hu = (void *)tty->disc_data;
@@ -375,7 +371,8 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char
hu->hdev->stat.byte_rx += count;
spin_unlock(&hu->rx_lock);
- if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver->unthrottle)
+ if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
+ tty->driver->unthrottle)
tty->driver->unthrottle(tty);
}
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index e2d4beac7420..fdea58ae16b2 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -96,6 +96,9 @@ static struct usb_device_id bluetooth_ids[] = {
/* Ericsson with non-standard id */
{ USB_DEVICE(0x0bdb, 0x1002) },
+ /* Canyon CN-BTU1 with HID interfaces */
+ { USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET },
+
{ } /* Terminating entry */
};
@@ -115,6 +118,9 @@ static struct usb_device_id blacklist_ids[] = {
/* IBM/Lenovo ThinkPad with Broadcom chip */
{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_WRONG_SCO_MTU },
+ /* ANYCOM Bluetooth USB-200 and USB-250 */
+ { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET },
+
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{ USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET },
@@ -173,8 +179,8 @@ static struct _urb *_urb_dequeue(struct _urb_queue *q)
return _urb;
}
-static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs);
-static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs);
+static void hci_usb_rx_complete(struct urb *urb);
+static void hci_usb_tx_complete(struct urb *urb);
#define __pending_tx(husb, type) (&husb->pending_tx[type-1])
#define __pending_q(husb, type) (&husb->pending_q[type-1])
@@ -729,7 +735,7 @@ static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int c
return 0;
}
-static void hci_usb_rx_complete(struct urb *urb, struct pt_regs *regs)
+static void hci_usb_rx_complete(struct urb *urb)
{
struct _urb *_urb = container_of(urb, struct _urb, urb);
struct hci_usb *husb = (void *) urb->context;
@@ -783,7 +789,7 @@ unlock:
read_unlock(&husb->completion_lock);
}
-static void hci_usb_tx_complete(struct urb *urb, struct pt_regs *regs)
+static void hci_usb_tx_complete(struct urb *urb)
{
struct _urb *_urb = container_of(urb, struct _urb, urb);
struct hci_usb *husb = (void *) urb->context;
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index aac67a3a6019..a278d98a9151 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -2,9 +2,9 @@
*
* Bluetooth virtual HCI driver
*
- * Copyright (C) 2000-2001 Qualcomm Incorporated
- * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
- * Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
+ * Copyright (C) 2000-2001 Qualcomm Incorporated
+ * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2004-2006 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
@@ -72,21 +72,21 @@ static int vhci_open_dev(struct hci_dev *hdev)
static int vhci_close_dev(struct hci_dev *hdev)
{
- struct vhci_data *vhci = hdev->driver_data;
+ struct vhci_data *data = hdev->driver_data;
if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags))
return 0;
- skb_queue_purge(&vhci->readq);
+ skb_queue_purge(&data->readq);
return 0;
}
static int vhci_flush(struct hci_dev *hdev)
{
- struct vhci_data *vhci = hdev->driver_data;
+ struct vhci_data *data = hdev->driver_data;
- skb_queue_purge(&vhci->readq);
+ skb_queue_purge(&data->readq);
return 0;
}
@@ -94,7 +94,7 @@ static int vhci_flush(struct hci_dev *hdev)
static int vhci_send_frame(struct sk_buff *skb)
{
struct hci_dev* hdev = (struct hci_dev *) skb->dev;
- struct vhci_data *vhci;
+ struct vhci_data *data;
if (!hdev) {
BT_ERR("Frame for unknown HCI device (hdev=NULL)");
@@ -104,15 +104,15 @@ static int vhci_send_frame(struct sk_buff *skb)
if (!test_bit(HCI_RUNNING, &hdev->flags))
return -EBUSY;
- vhci = hdev->driver_data;
+ data = hdev->driver_data;
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
- skb_queue_tail(&vhci->readq, skb);
+ skb_queue_tail(&data->readq, skb);
- if (vhci->flags & VHCI_FASYNC)
- kill_fasync(&vhci->fasync, SIGIO, POLL_IN);
+ if (data->flags & VHCI_FASYNC)
+ kill_fasync(&data->fasync, SIGIO, POLL_IN);
- wake_up_interruptible(&vhci->read_wait);
+ wake_up_interruptible(&data->read_wait);
return 0;
}
@@ -122,7 +122,7 @@ static void vhci_destruct(struct hci_dev *hdev)
kfree(hdev->driver_data);
}
-static inline ssize_t vhci_get_user(struct vhci_data *vhci,
+static inline ssize_t vhci_get_user(struct vhci_data *data,
const char __user *buf, size_t count)
{
struct sk_buff *skb;
@@ -139,7 +139,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *vhci,
return -EFAULT;
}
- skb->dev = (void *) vhci->hdev;
+ skb->dev = (void *) data->hdev;
bt_cb(skb)->pkt_type = *((__u8 *) skb->data);
skb_pull(skb, 1);
@@ -148,7 +148,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *vhci,
return count;
}
-static inline ssize_t vhci_put_user(struct vhci_data *vhci,
+static inline ssize_t vhci_put_user(struct vhci_data *data,
struct sk_buff *skb, char __user *buf, int count)
{
char __user *ptr = buf;
@@ -161,42 +161,43 @@ static inline ssize_t vhci_put_user(struct vhci_data *vhci,
total += len;
- vhci->hdev->stat.byte_tx += len;
+ data->hdev->stat.byte_tx += len;
switch (bt_cb(skb)->pkt_type) {
case HCI_COMMAND_PKT:
- vhci->hdev->stat.cmd_tx++;
+ data->hdev->stat.cmd_tx++;
break;
case HCI_ACLDATA_PKT:
- vhci->hdev->stat.acl_tx++;
+ data->hdev->stat.acl_tx++;
break;
case HCI_SCODATA_PKT:
- vhci->hdev->stat.cmd_tx++;
+ data->hdev->stat.cmd_tx++;
break;
};
return total;
}
-static loff_t vhci_llseek(struct file * file, loff_t offset, int origin)
+static loff_t vhci_llseek(struct file *file, loff_t offset, int origin)
{
return -ESPIPE;
}
-static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, loff_t *pos)
+static ssize_t vhci_read(struct file *file,
+ char __user *buf, size_t count, loff_t *pos)
{
DECLARE_WAITQUEUE(wait, current);
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
struct sk_buff *skb;
ssize_t ret = 0;
- add_wait_queue(&vhci->read_wait, &wait);
+ add_wait_queue(&data->read_wait, &wait);
while (count) {
set_current_state(TASK_INTERRUPTIBLE);
- skb = skb_dequeue(&vhci->readq);
+ skb = skb_dequeue(&data->readq);
if (!skb) {
if (file->f_flags & O_NONBLOCK) {
ret = -EAGAIN;
@@ -213,7 +214,7 @@ static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, lo
}
if (access_ok(VERIFY_WRITE, buf, count))
- ret = vhci_put_user(vhci, skb, buf, count);
+ ret = vhci_put_user(data, skb, buf, count);
else
ret = -EFAULT;
@@ -221,7 +222,7 @@ static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, lo
break;
}
set_current_state(TASK_RUNNING);
- remove_wait_queue(&vhci->read_wait, &wait);
+ remove_wait_queue(&data->read_wait, &wait);
return ret;
}
@@ -229,21 +230,21 @@ static ssize_t vhci_read(struct file * file, char __user * buf, size_t count, lo
static ssize_t vhci_write(struct file *file,
const char __user *buf, size_t count, loff_t *pos)
{
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
if (!access_ok(VERIFY_READ, buf, count))
return -EFAULT;
- return vhci_get_user(vhci, buf, count);
+ return vhci_get_user(data, buf, count);
}
static unsigned int vhci_poll(struct file *file, poll_table *wait)
{
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
- poll_wait(file, &vhci->read_wait, wait);
+ poll_wait(file, &data->read_wait, wait);
- if (!skb_queue_empty(&vhci->readq))
+ if (!skb_queue_empty(&data->readq))
return POLLIN | POLLRDNORM;
return POLLOUT | POLLWRNORM;
@@ -257,26 +258,26 @@ static int vhci_ioctl(struct inode *inode, struct file *file,
static int vhci_open(struct inode *inode, struct file *file)
{
- struct vhci_data *vhci;
+ struct vhci_data *data;
struct hci_dev *hdev;
- vhci = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
- if (!vhci)
+ data = kzalloc(sizeof(struct vhci_data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
- skb_queue_head_init(&vhci->readq);
- init_waitqueue_head(&vhci->read_wait);
+ skb_queue_head_init(&data->readq);
+ init_waitqueue_head(&data->read_wait);
hdev = hci_alloc_dev();
if (!hdev) {
- kfree(vhci);
+ kfree(data);
return -ENOMEM;
}
- vhci->hdev = hdev;
+ data->hdev = hdev;
- hdev->type = HCI_VHCI;
- hdev->driver_data = vhci;
+ hdev->type = HCI_VIRTUAL;
+ hdev->driver_data = data;
hdev->open = vhci_open_dev;
hdev->close = vhci_close_dev;
@@ -288,20 +289,20 @@ static int vhci_open(struct inode *inode, struct file *file)
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
- kfree(vhci);
+ kfree(data);
hci_free_dev(hdev);
return -EBUSY;
}
- file->private_data = vhci;
+ file->private_data = data;
return nonseekable_open(inode, file);
}
static int vhci_release(struct inode *inode, struct file *file)
{
- struct vhci_data *vhci = file->private_data;
- struct hci_dev *hdev = vhci->hdev;
+ struct vhci_data *data = file->private_data;
+ struct hci_dev *hdev = data->hdev;
if (hci_unregister_dev(hdev) < 0) {
BT_ERR("Can't unregister HCI device %s", hdev->name);
@@ -316,17 +317,17 @@ static int vhci_release(struct inode *inode, struct file *file)
static int vhci_fasync(int fd, struct file *file, int on)
{
- struct vhci_data *vhci = file->private_data;
+ struct vhci_data *data = file->private_data;
int err;
- err = fasync_helper(fd, file, on, &vhci->fasync);
+ err = fasync_helper(fd, file, on, &data->fasync);
if (err < 0)
return err;
if (on)
- vhci->flags |= VHCI_FASYNC;
+ data->flags |= VHCI_FASYNC;
else
- vhci->flags &= ~VHCI_FASYNC;
+ data->flags &= ~VHCI_FASYNC;
return 0;
}
diff --git a/drivers/cdrom/Kconfig b/drivers/cdrom/Kconfig
index ff5652d40619..4b12e9031fb3 100644
--- a/drivers/cdrom/Kconfig
+++ b/drivers/cdrom/Kconfig
@@ -3,7 +3,7 @@
#
menu "Old CD-ROM drivers (not SCSI, not IDE)"
- depends on ISA
+ depends on ISA && BLOCK
config CD_NO_IDESCSI
bool "Support non-SCSI/IDE/ATAPI CDROM drives"
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c
index d239cf8b20bd..7ea0f48f8fa6 100644
--- a/drivers/cdrom/cdrom.c
+++ b/drivers/cdrom/cdrom.c
@@ -1,4 +1,4 @@
-/* linux/drivers/cdrom/cdrom.c.
+/* linux/drivers/cdrom/cdrom.c
Copyright (c) 1996, 1997 David A. van Leeuwen.
Copyright (c) 1997, 1998 Erik Andersen <andersee@debian.org>
Copyright (c) 1998, 1999 Jens Axboe <axboe@image.dk>
@@ -703,7 +703,7 @@ static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
{
struct packet_command cgc;
char buffer[16];
- __u16 *feature_code;
+ __be16 *feature_code;
int ret;
init_cdrom_command(&cgc, buffer, sizeof(buffer), CGC_DATA_READ);
@@ -716,7 +716,7 @@ static int cdrom_has_defect_mgt(struct cdrom_device_info *cdi)
if ((ret = cdi->ops->generic_packet(cdi, &cgc)))
return ret;
- feature_code = (__u16 *) &buffer[sizeof(struct feature_header)];
+ feature_code = (__be16 *) &buffer[sizeof(struct feature_header)];
if (be16_to_cpu(*feature_code) == CDF_HWDM)
return 0;
@@ -2129,7 +2129,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
rq->cmd[9] = 0xf8;
rq->cmd_len = 12;
- rq->flags |= REQ_BLOCK_PC;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = 60 * HZ;
bio = rq->bio;
@@ -2963,7 +2963,7 @@ static int mmc_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
how much data is available for transfer. buffer[1] is
unfortunately ambigious and the only reliable way seem
to be to simply skip over the block descriptor... */
- offset = 8 + be16_to_cpu(*(unsigned short *)(buffer+6));
+ offset = 8 + be16_to_cpu(*(__be16 *)(buffer+6));
if (offset + 16 > sizeof(buffer))
return -E2BIG;
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 37bdb0163f0d..2157c58755e0 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -513,7 +513,7 @@ static inline void write_cmd(unsigned char cmd)
outb(cmd, sony_cd_cmd_reg);
}
-static irqreturn_t cdu31a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cdu31a_interrupt(int irq, void *dev_id)
{
unsigned char val;
@@ -1338,8 +1338,10 @@ static void do_cdu31a_request(request_queue_t * q)
}
/* WTF??? */
- if (!(req->flags & REQ_CMD))
+ if (!blk_fs_request(req)) {
+ end_request(req, 0);
continue;
+ }
if (rq_data_dir(req) == WRITE) {
end_request(req, 0);
continue;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index 9b05ddd23141..e6d8e9ededea 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -359,7 +359,7 @@ static struct tasklet_struct cm206_tasklet;
as there seems so reason for this to happen.
*/
-static irqreturn_t cm206_interrupt(int sig, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cm206_interrupt(int sig, void *dev_id)
{
volatile ush fool;
cd->intr_ds = inw(r_data_status); /* resets data_ready, data_error,
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index dcd1ab684f3e..f574962f4288 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -845,15 +845,11 @@ static void mcdx_delay(struct s_drive_stuff *stuff, long jifs)
}
}
-static irqreturn_t mcdx_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mcdx_intr(int irq, void *dev_id)
{
struct s_drive_stuff *stuffp = dev_id;
unsigned char b;
- if (stuffp == NULL) {
- xwarn("mcdx: no device for intr %d\n", irq);
- return IRQ_NONE;
- }
#ifdef AK2
if (!stuffp->busy && stuffp->pending)
stuffp->int_err = 1;
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index 30ab56258a92..f77ada933ea0 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -322,7 +322,7 @@ disable_interrupts(void)
}
static irqreturn_t
-cdu535_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+cdu535_interrupt(int irq, void *dev_id)
{
disable_interrupts();
if (waitqueue_active(&cdu535_irq_wait)) {
diff --git a/drivers/char/.gitignore b/drivers/char/.gitignore
index 73dfdcebfbba..83683a2d8e6a 100644
--- a/drivers/char/.gitignore
+++ b/drivers/char/.gitignore
@@ -1,3 +1,2 @@
consolemap_deftbl.c
defkeymap.c
-qtronixmap.c
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 52ea94b891f5..39a9f8cc6412 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -371,36 +371,6 @@ config AU1000_SERIAL_CONSOLE
If you have an Alchemy AU1000 processor (MIPS based) and you want
to use a console on a serial port, say Y. Otherwise, say N.
-config QTRONIX_KEYBOARD
- bool "Enable Qtronix 990P Keyboard Support"
- depends on IT8712
- help
- Images of Qtronix keyboards are at
- <http://www.qtronix.com/keyboard.html>.
-
-config IT8172_CIR
- bool
- depends on QTRONIX_KEYBOARD
- default y
-
-config IT8172_SCR0
- bool "Enable Smart Card Reader 0 Support "
- depends on IT8712
- help
- Say Y here to support smart-card reader 0 (SCR0) on the Integrated
- Technology Express, Inc. ITE8172 SBC. Vendor page at
- <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
- board at <http://www.mvista.com/partners/semiconductor/ite.html>.
-
-config IT8172_SCR1
- bool "Enable Smart Card Reader 1 Support "
- depends on IT8712
- help
- Say Y here to support smart-card reader 1 (SCR1) on the Integrated
- Technology Express, Inc. ITE8172 SBC. Vendor page at
- <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
- board at <http://www.mvista.com/partners/semiconductor/ite.html>.
-
config A2232
tristate "Commodore A2232 serial support (EXPERIMENTAL)"
depends on EXPERIMENTAL && ZORRO && BROKEN_ON_SMP
@@ -439,6 +409,14 @@ config SGI_MBCS
If you have an SGI Altix with an attached SABrick
say Y or M here, otherwise say N.
+config MSPEC
+ tristate "Memory special operations driver"
+ depends on IA64
+ help
+ If you have an ia64 and you want to enable memory special
+ operations support (formerly known as fetchop), say Y here,
+ otherwise say N.
+
source "drivers/serial/Kconfig"
config UNIX98_PTYS
@@ -739,7 +717,7 @@ config NVRAM
config RTC
tristate "Enhanced Real Time Clock Support"
- depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM
+ depends on !PPC && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM && !SUPERH
---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
@@ -823,14 +801,6 @@ config DS1302
will get access to the real time clock (or hardware clock) built
into your computer.
-config S3C2410_RTC
- bool "S3C2410 RTC Driver"
- depends on ARCH_S3C2410
- help
- RTC (Realtime Clock) driver for the clock inbuilt into the
- Samsung S3C2410. This can provide periodic interrupt rates
- from 1Hz to 64Hz for user programs, and wakeup from Alarm.
-
config COBALT_LCD
bool "Support for Cobalt LCD"
depends on MIPS_COBALT
@@ -1006,6 +976,7 @@ config GPIO_VR41XX
config RAW_DRIVER
tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)"
+ depends on BLOCK
help
The raw driver permits block devices to be bound to /dev/raw/rawN.
Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
@@ -1075,7 +1046,7 @@ source "drivers/char/tpm/Kconfig"
config TELCLOCK
tristate "Telecom clock driver for MPBL0010 ATCA SBC"
- depends on EXPERIMENTAL
+ depends on EXPERIMENTAL && X86
default n
help
The telecom clock device is specific to the MPBL0010 ATCA computer and
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 8c6dfc621520..777cad045094 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
+obj-$(CONFIG_MSPEC) += mspec.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
obj-$(CONFIG_VIOCONS) += viocons.o
obj-$(CONFIG_VIOTAPE) += viotape.o
@@ -68,7 +69,6 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
obj-$(CONFIG_SGI_DS1286) += ds1286.o
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
obj-$(CONFIG_DS1302) += ds1302.o
-obj-$(CONFIG_S3C2410_RTC) += s3c2410-rtc.o
ifeq ($(CONFIG_GENERIC_NVRAM),y)
obj-$(CONFIG_NVRAM) += generic_nvram.o
else
@@ -102,7 +102,7 @@ obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o
obj-$(CONFIG_TCG_TPM) += tpm/
# Files generated that shall be removed upon make clean
-clean-files := consolemap_deftbl.c defkeymap.c qtronixmap.c
+clean-files := consolemap_deftbl.c defkeymap.c
quiet_cmd_conmk = CONMK $@
cmd_conmk = scripts/conmakehash $< > $@
@@ -112,8 +112,6 @@ $(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE)
$(obj)/defkeymap.o: $(obj)/defkeymap.c
-$(obj)/qtronixmap.o: $(obj)/qtronixmap.c
-
# Uncomment if you're changing the keymap and have an appropriate
# loadkeys version for the map. By default, we'll use the shipped
# versions.
@@ -121,7 +119,7 @@ $(obj)/qtronixmap.o: $(obj)/qtronixmap.c
ifdef GENERATE_KEYMAP
-$(obj)/defkeymap.c $(obj)/qtronixmap.c: $(obj)/%.c: $(src)/%.map
+$(obj)/defkeymap.c $(obj)/%.c: $(src)/%.map
loadkeys --mktable $< > $@.tmp
sed -e 's/^static *//' $@.tmp > $@
rm $@.tmp
diff --git a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
index 22f8cf218cc6..c603bf291580 100644
--- a/drivers/char/agp/Kconfig
+++ b/drivers/char/agp/Kconfig
@@ -1,6 +1,6 @@
config AGP
tristate "/dev/agpgart (AGP Support)"
- depends on ALPHA || IA64 || PPC || X86
+ depends on ALPHA || IA64 || PARISC || PPC || X86
depends on PCI
---help---
AGP (Accelerated Graphics Port) is a bus system mainly used to
@@ -122,6 +122,14 @@ config AGP_HP_ZX1
This option gives you AGP GART support for the HP ZX1 chipset
for IA64 processors.
+config AGP_PARISC
+ tristate "HP Quicksilver AGP support"
+ depends on AGP && PARISC && 64BIT
+ help
+ This option gives you AGP GART support for the HP Quicksilver
+ AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000
+ workstation...)
+
config AGP_ALPHA_CORE
tristate "Alpha AGP support"
depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL)
diff --git a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
index d33a22f2fa0b..3e581603d0a8 100644
--- a/drivers/char/agp/Makefile
+++ b/drivers/char/agp/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_AGP_AMD64) += amd64-agp.o
obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o
obj-$(CONFIG_AGP_EFFICEON) += efficeon-agp.o
obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o
+obj-$(CONFIG_AGP_PARISC) += parisc-agp.o
obj-$(CONFIG_AGP_I460) += i460-agp.o
obj-$(CONFIG_AGP_INTEL) += intel-agp.o
obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o
diff --git a/drivers/char/agp/parisc-agp.c b/drivers/char/agp/parisc-agp.c
new file mode 100644
index 000000000000..17c50b0f83f0
--- /dev/null
+++ b/drivers/char/agp/parisc-agp.c
@@ -0,0 +1,416 @@
+/*
+ * HP Quicksilver AGP GART routines
+ *
+ * Copyright (c) 2006, Kyle McMartin <kyle@parisc-linux.org>
+ *
+ * Based on drivers/char/agpgart/hp-agp.c which is
+ * (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
+ * Bjorn Helgaas <bjorn.helgaas@hp.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/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/klist.h>
+#include <linux/agp_backend.h>
+
+#include <asm-parisc/parisc-device.h>
+#include <asm-parisc/ropes.h>
+
+#include "agp.h"
+
+#define DRVNAME "quicksilver"
+#define DRVPFX DRVNAME ": "
+
+#ifndef log2
+#define log2(x) ffz(~(x))
+#endif
+
+#define AGP8X_MODE_BIT 3
+#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
+
+static struct _parisc_agp_info {
+ void __iomem *ioc_regs;
+ void __iomem *lba_regs;
+
+ int lba_cap_offset;
+
+ u64 *gatt;
+ u64 gatt_entries;
+
+ u64 gart_base;
+ u64 gart_size;
+
+ int io_page_size;
+ int io_pages_per_kpage;
+} parisc_agp_info;
+
+static struct gatt_mask parisc_agp_masks[] =
+{
+ {
+ .mask = SBA_PDIR_VALID_BIT,
+ .type = 0
+ }
+};
+
+static struct aper_size_info_fixed parisc_agp_sizes[] =
+{
+ {0, 0, 0}, /* filled in by parisc_agp_fetch_size() */
+};
+
+static int
+parisc_agp_fetch_size(void)
+{
+ int size;
+
+ size = parisc_agp_info.gart_size / MB(1);
+ parisc_agp_sizes[0].size = size;
+ agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
+
+ return size;
+}
+
+static int
+parisc_agp_configure(void)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+
+ agp_bridge->gart_bus_addr = info->gart_base;
+ agp_bridge->capndx = info->lba_cap_offset;
+ agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
+
+ return 0;
+}
+
+static void
+parisc_agp_tlbflush(struct agp_memory *mem)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+
+ writeq(info->gart_base | log2(info->gart_size), info->ioc_regs+IOC_PCOM);
+ readq(info->ioc_regs+IOC_PCOM); /* flush */
+}
+
+static int
+parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+ int i;
+
+ for (i = 0; i < info->gatt_entries; i++) {
+ info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
+ }
+
+ return 0;
+}
+
+static int
+parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+
+ info->gatt[0] = SBA_AGPGART_COOKIE;
+
+ return 0;
+}
+
+static int
+parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+ int i, k;
+ off_t j, io_pg_start;
+ int io_pg_count;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+
+ io_pg_start = info->io_pages_per_kpage * pg_start;
+ io_pg_count = info->io_pages_per_kpage * mem->page_count;
+ if ((io_pg_start + io_pg_count) > info->gatt_entries) {
+ return -EINVAL;
+ }
+
+ j = io_pg_start;
+ while (j < (io_pg_start + io_pg_count)) {
+ if (info->gatt[j])
+ return -EBUSY;
+ j++;
+ }
+
+ if (mem->is_flushed == FALSE) {
+ global_cache_flush();
+ mem->is_flushed = TRUE;
+ }
+
+ for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
+ unsigned long paddr;
+
+ paddr = mem->memory[i];
+ for (k = 0;
+ k < info->io_pages_per_kpage;
+ k++, j++, paddr += info->io_page_size) {
+ info->gatt[j] =
+ agp_bridge->driver->mask_memory(agp_bridge,
+ paddr, type);
+ }
+ }
+
+ agp_bridge->driver->tlb_flush(mem);
+
+ return 0;
+}
+
+static int
+parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+ int i, io_pg_start, io_pg_count;
+
+ if (type != 0 || mem->type != 0) {
+ return -EINVAL;
+ }
+
+ io_pg_start = info->io_pages_per_kpage * pg_start;
+ io_pg_count = info->io_pages_per_kpage * mem->page_count;
+ for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
+ info->gatt[i] = agp_bridge->scratch_page;
+ }
+
+ agp_bridge->driver->tlb_flush(mem);
+ return 0;
+}
+
+static unsigned long
+parisc_agp_mask_memory(struct agp_bridge_data *bridge,
+ unsigned long addr, int type)
+{
+ return SBA_PDIR_VALID_BIT | addr;
+}
+
+static void
+parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+ u32 command;
+
+ command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
+
+ command = agp_collect_device_status(bridge, mode, command);
+ command |= 0x00000100;
+
+ writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
+
+ agp_device_command(command, (mode & AGP8X_MODE) != 0);
+}
+
+struct agp_bridge_driver parisc_agp_driver = {
+ .owner = THIS_MODULE,
+ .size_type = FIXED_APER_SIZE,
+ .configure = parisc_agp_configure,
+ .fetch_size = parisc_agp_fetch_size,
+ .tlb_flush = parisc_agp_tlbflush,
+ .mask_memory = parisc_agp_mask_memory,
+ .masks = parisc_agp_masks,
+ .agp_enable = parisc_agp_enable,
+ .cache_flush = global_cache_flush,
+ .create_gatt_table = parisc_agp_create_gatt_table,
+ .free_gatt_table = parisc_agp_free_gatt_table,
+ .insert_memory = parisc_agp_insert_memory,
+ .remove_memory = parisc_agp_remove_memory,
+ .alloc_by_type = agp_generic_alloc_by_type,
+ .free_by_type = agp_generic_free_by_type,
+ .agp_alloc_page = agp_generic_alloc_page,
+ .agp_destroy_page = agp_generic_destroy_page,
+ .cant_use_aperture = 1,
+};
+
+static int __init
+agp_ioc_init(void __iomem *ioc_regs)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+ u64 *iova_base, *io_pdir, io_tlb_ps;
+ int io_tlb_shift;
+
+ printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
+
+ info->ioc_regs = ioc_regs;
+
+ io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
+ switch (io_tlb_ps) {
+ case 0: io_tlb_shift = 12; break;
+ case 1: io_tlb_shift = 13; break;
+ case 2: io_tlb_shift = 14; break;
+ case 3: io_tlb_shift = 16; break;
+ default:
+ printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
+ "configuration 0x%llx\n", io_tlb_ps);
+ info->gatt = NULL;
+ info->gatt_entries = 0;
+ return -ENODEV;
+ }
+ info->io_page_size = 1 << io_tlb_shift;
+ info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
+
+ iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
+ info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
+
+ info->gart_size = PLUTO_GART_SIZE;
+ info->gatt_entries = info->gart_size / info->io_page_size;
+
+ io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
+ info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
+
+ if (info->gatt[0] != SBA_AGPGART_COOKIE) {
+ info->gatt = NULL;
+ info->gatt_entries = 0;
+ printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
+ "GART disabled\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int
+lba_find_capability(int cap)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+ u16 status;
+ u8 pos, id;
+ int ttl = 48;
+
+ status = readw(info->lba_regs + PCI_STATUS);
+ if (!(status & PCI_STATUS_CAP_LIST))
+ return 0;
+ pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
+ while (ttl-- && pos >= 0x40) {
+ pos &= ~3;
+ id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
+ if (id == 0xff)
+ break;
+ if (id == cap)
+ return pos;
+ pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
+ }
+ return 0;
+}
+
+static int __init
+agp_lba_init(void __iomem *lba_hpa)
+{
+ struct _parisc_agp_info *info = &parisc_agp_info;
+ int cap;
+
+ info->lba_regs = lba_hpa;
+ info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
+
+ cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
+ if (cap != PCI_CAP_ID_AGP) {
+ printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
+ cap, info->lba_cap_offset);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int __init
+parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
+{
+ struct pci_dev *fake_bridge_dev = NULL;
+ struct agp_bridge_data *bridge;
+ int error = 0;
+
+ fake_bridge_dev = kmalloc(sizeof (struct pci_dev), GFP_KERNEL);
+ if (!fake_bridge_dev) {
+ error = -ENOMEM;
+ goto fail;
+ }
+
+ error = agp_ioc_init(ioc_hpa);
+ if (error)
+ goto fail;
+
+ error = agp_lba_init(lba_hpa);
+ if (error)
+ goto fail;
+
+ bridge = agp_alloc_bridge();
+ if (!bridge) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ bridge->driver = &parisc_agp_driver;
+
+ fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
+ fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
+ bridge->dev = fake_bridge_dev;
+
+ error = agp_add_bridge(bridge);
+
+fail:
+ return error;
+}
+
+static struct device *next_device(struct klist_iter *i) {
+ struct klist_node * n = klist_next(i);
+ return n ? container_of(n, struct device, knode_parent) : NULL;
+}
+
+static int
+parisc_agp_init(void)
+{
+ extern struct sba_device *sba_list;
+
+ int err = -1;
+ struct parisc_device *sba = NULL, *lba = NULL;
+ struct lba_device *lbadev = NULL;
+ struct device *dev = NULL;
+ struct klist_iter i;
+
+ if (!sba_list)
+ goto out;
+
+ /* Find our parent Pluto */
+ sba = sba_list->dev;
+ if (!IS_PLUTO(sba)) {
+ printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
+ goto out;
+ }
+
+ /* Now search our Pluto for our precious AGP device... */
+ klist_iter_init(&sba->dev.klist_children, &i);
+ while ((dev = next_device(&i))) {
+ struct parisc_device *padev = to_parisc_device(dev);
+ if (IS_QUICKSILVER(padev))
+ lba = padev;
+ }
+ klist_iter_exit(&i);
+
+ if (!lba) {
+ printk(KERN_INFO DRVPFX "No AGP devices found.\n");
+ goto out;
+ }
+
+ lbadev = parisc_get_drvdata(lba);
+
+ /* w00t, let's go find our cookies... */
+ parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
+
+ return 0;
+
+out:
+ return err;
+}
+
+module_init(parisc_agp_init);
+
+MODULE_AUTHOR("Kyle McMartin <kyle@parisc-linux.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 9d6713a93ed7..66086fa2d59a 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -112,17 +112,6 @@ static struct serial_state rs_table[1];
#define NR_PORTS ARRAY_SIZE(rs_table)
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-
#include <asm/uaccess.h>
#define serial_isroot() (capable(CAP_SYS_ADMIN))
@@ -458,7 +447,7 @@ static void check_modem_status(struct async_struct *info)
}
}
-static irqreturn_t ser_vbl_int( int irq, void *data, struct pt_regs *regs)
+static irqreturn_t ser_vbl_int( int irq, void *data)
{
/* vbl is just a periodic interrupt we tie into to update modem status */
struct async_struct * info = IRQ_ports;
@@ -471,7 +460,7 @@ static irqreturn_t ser_vbl_int( int irq, void *data, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t ser_rx_int(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ser_rx_int(int irq, void *dev_id)
{
struct async_struct * info;
@@ -491,7 +480,7 @@ static irqreturn_t ser_rx_int(int irq, void *dev_id, struct pt_regs * regs)
return IRQ_HANDLED;
}
-static irqreturn_t ser_tx_int(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ser_tx_int(int irq, void *dev_id)
{
struct async_struct * info;
@@ -912,7 +901,7 @@ static int rs_write(struct tty_struct * tty, const unsigned char *buf, int count
if (serial_paranoia_check(info, tty->name, "rs_write"))
return 0;
- if (!info->xmit.buf || !tmp_buf)
+ if (!info->xmit.buf)
return 0;
local_save_flags(flags);
@@ -1778,7 +1767,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
{
struct async_struct *info;
int retval, line;
- unsigned long page;
line = tty->index;
if ((line < 0) || (line >= NR_PORTS)) {
@@ -1798,17 +1786,6 @@ static int rs_open(struct tty_struct *tty, struct file * filp)
#endif
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page) {
- return -ENOMEM;
- }
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
-
/*
* If the port is the middle of closing, bail out now
*/
@@ -1958,7 +1935,7 @@ static void show_serial_version(void)
}
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
@@ -2090,11 +2067,6 @@ static __exit void rs_exit(void)
kfree(info);
}
- if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
- tmp_buf = NULL;
- }
-
release_mem_region(CUSTOM_PHYSADDR+0x30, 4);
}
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 10a389dafd60..1f0b752e5de1 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -110,7 +110,7 @@ static ssize_t ac_read (struct file *, char __user *, size_t, loff_t *);
static ssize_t ac_write (struct file *, const char __user *, size_t, loff_t *);
static int ac_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
-static irqreturn_t ac_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t ac_interrupt(int, void *);
static const struct file_operations ac_fops = {
.owner = THIS_MODULE,
@@ -617,7 +617,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_
}
}
-static irqreturn_t ac_interrupt(int vec, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t ac_interrupt(int vec, void *dev_instance)
{
unsigned int i;
unsigned int FlagInt;
diff --git a/drivers/char/briq_panel.c b/drivers/char/briq_panel.c
index b8c22255f6ad..9f8082f8dd29 100644
--- a/drivers/char/briq_panel.c
+++ b/drivers/char/briq_panel.c
@@ -11,7 +11,6 @@
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/timer.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/wait.h>
#include <linux/string.h>
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index c1c67281750d..e608dadece2f 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -748,18 +748,6 @@ static struct cyclades_port cy_port[NR_PORTS];
static int cy_next_channel; /* next minor available */
/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open. This buffer is
- * allocated when the first cy_open occurs.
- */
-static unsigned char *tmp_buf;
-
-/*
* This is used to look up the divisor speeds and the timeouts
* We're normally limited to 15 distinct baud rates. The extra
* are accessed via settings in info->flags.
@@ -1069,7 +1057,7 @@ detect_isa_irq(void __iomem *address)
received, out buffer empty, modem change, etc.
*/
static irqreturn_t
-cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+cyy_interrupt(int irq, void *dev_id)
{
struct tty_struct *tty;
int status;
@@ -1814,7 +1802,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
#ifdef CONFIG_CYZ_INTR
static irqreturn_t
-cyz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+cyz_interrupt(int irq, void *dev_id)
{
struct cyclades_card *cinfo;
@@ -2466,7 +2454,6 @@ cy_open(struct tty_struct *tty, struct file * filp)
{
struct cyclades_port *info;
int retval, line;
- unsigned long page;
line = tty->index;
if ((line < 0) || (NR_PORTS <= line)){
@@ -2545,15 +2532,6 @@ cy_open(struct tty_struct *tty, struct file * filp)
printk("cyc:cy_open (%d): incrementing count to %d\n",
current->pid, info->count);
#endif
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
/*
* If the port is the middle of closing, bail out now
@@ -2832,7 +2810,7 @@ cy_write(struct tty_struct * tty, const unsigned char *buf, int count)
return 0;
}
- if (!info->xmit_buf || !tmp_buf)
+ if (!info->xmit_buf)
return 0;
CY_LOCK(info, flags);
@@ -5205,7 +5183,7 @@ done:
extra ports are ignored.
*/
-static struct tty_operations cy_ops = {
+static const struct tty_operations cy_ops = {
.open = cy_open,
.close = cy_close,
.write = cy_write,
@@ -5490,10 +5468,6 @@ cy_cleanup_module(void)
#endif
}
}
- if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
- tmp_buf = NULL;
- }
} /* cy_cleanup_module */
module_init(cy_init);
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index 5278c388d3e7..ef833a1c27eb 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -60,7 +60,9 @@ config DRM_I830
Choose this option if you have a system that has Intel 830M, 845G,
852GM, 855GM or 865G integrated graphics. If M is selected, the
module will be called i830. AGP support is required for this driver
- to work. This driver will eventually be replaced by the i915 one.
+ to work. This driver is used by the older X releases X.org 6.7 and
+ XFree86 4.3. If unsure, build this and i915 as modules and the X server
+ will load the correct one.
config DRM_I915
tristate "i915 driver"
@@ -68,8 +70,9 @@ config DRM_I915
Choose this option if you have a system that has Intel 830M, 845G,
852GM, 855GM 865G or 915G integrated graphics. If M is selected, the
module will be called i915. AGP support is required for this driver
- to work. This driver will eventually replace the I830 driver, when
- later release of X start to use the new DDX and DRI.
+ to work. This driver is used by the Intel driver in X.org 6.8 and
+ XFree86 4.4 and above. If unsure, build this and i830 as modules and
+ the X server will load the correct one.
endchoice
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index 9d180c42816c..3ad0f648c6b2 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -6,7 +6,7 @@ drm-objs := drm_auth.o drm_bufs.o drm_context.o drm_dma.o drm_drawable.o \
drm_drv.o drm_fops.o drm_ioctl.o drm_irq.o \
drm_lock.o drm_memory.o drm_proc.o drm_stub.o drm_vm.o \
drm_agpsupport.o drm_scatter.o ati_pcigart.o drm_pci.o \
- drm_sysfs.o
+ drm_sysfs.o drm_hashtab.o drm_sman.o drm_mm.o
tdfx-objs := tdfx_drv.o
r128-objs := r128_drv.o r128_cce.o r128_state.o r128_irq.o
@@ -16,9 +16,9 @@ i830-objs := i830_drv.o i830_dma.o i830_irq.o
i915-objs := i915_drv.o i915_dma.o i915_irq.o i915_mem.o
radeon-objs := radeon_drv.o radeon_cp.o radeon_state.o radeon_mem.o radeon_irq.o r300_cmdbuf.o
ffb-objs := ffb_drv.o ffb_context.o
-sis-objs := sis_drv.o sis_ds.o sis_mm.o
+sis-objs := sis_drv.o sis_mm.o
savage-objs := savage_drv.o savage_bci.o savage_state.o
-via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
+via-objs := via_irq.o via_drv.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o via_dmablit.o
ifeq ($(CONFIG_COMPAT),y)
drm-objs += drm_ioc32.o
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index d2a56182bc35..7690a59ace04 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -79,6 +79,7 @@
#define __OS_HAS_MTRR (defined(CONFIG_MTRR))
#include "drm_os_linux.h"
+#include "drm_hashtab.h"
/***********************************************************************/
/** \name DRM template customization defaults */
@@ -104,7 +105,7 @@
#define DRM_DEBUG_CODE 2 /**< Include debugging code if > 1, then
also include looping detection. */
-#define DRM_HASH_SIZE 16 /**< Size of key hash table. Must be power of 2. */
+#define DRM_MAGIC_HASH_ORDER 4 /**< Size of key hash table. Must be power of 2. */
#define DRM_KERNEL_CONTEXT 0 /**< Change drm_resctx if changed */
#define DRM_RESERVED_CONTEXTS 1 /**< Change drm_resctx if changed */
#define DRM_LOOPING_LIMIT 5000000
@@ -134,19 +135,12 @@
#define DRM_MEM_CTXBITMAP 18
#define DRM_MEM_STUB 19
#define DRM_MEM_SGLISTS 20
-#define DRM_MEM_CTXLIST 21
+#define DRM_MEM_CTXLIST 21
+#define DRM_MEM_MM 22
+#define DRM_MEM_HASHTAB 23
#define DRM_MAX_CTXBITMAP (PAGE_SIZE * 8)
-
-/*@}*/
-
-/***********************************************************************/
-/** \name Backward compatibility section */
-/*@{*/
-
-#define DRM_RPR_ARG(vma) vma,
-
-#define VM_OFFSET(vma) ((vma)->vm_pgoff << PAGE_SHIFT)
+#define DRM_MAP_HASH_OFFSET 0x10000000
/*@}*/
@@ -211,8 +205,6 @@
/*@{*/
#define DRM_ARRAY_SIZE(x) ARRAY_SIZE(x)
-#define DRM_MIN(a,b) min(a,b)
-#define DRM_MAX(a,b) max(a,b)
#define DRM_LEFTCOUNT(x) (((x)->rp + (x)->count - (x)->wp) % ((x)->count + 1))
#define DRM_BUFCOUNT(x) ((x)->count - DRM_LEFTCOUNT(x))
@@ -286,7 +278,8 @@ typedef struct drm_devstate {
} drm_devstate_t;
typedef struct drm_magic_entry {
- drm_magic_t magic;
+ drm_hash_item_t hash_item;
+ struct list_head head;
struct drm_file *priv;
struct drm_magic_entry *next;
} drm_magic_entry_t;
@@ -493,6 +486,7 @@ typedef struct drm_sigdata {
*/
typedef struct drm_map_list {
struct list_head head; /**< list head */
+ drm_hash_item_t hash;
drm_map_t *map; /**< mapping */
unsigned int user_token;
} drm_map_list_t;
@@ -527,6 +521,22 @@ typedef struct ati_pcigart_info {
drm_local_map_t mapping;
} drm_ati_pcigart_info;
+/*
+ * Generic memory manager structs
+ */
+typedef struct drm_mm_node {
+ struct list_head fl_entry;
+ struct list_head ml_entry;
+ int free;
+ unsigned long start;
+ unsigned long size;
+ void *private;
+} drm_mm_node_t;
+
+typedef struct drm_mm {
+ drm_mm_node_t root_node;
+} drm_mm_t;
+
/**
* DRM driver structure. This structure represent the common code for
* a family of cards. There will one drm_device for each card present
@@ -646,13 +656,15 @@ typedef struct drm_device {
/*@{ */
drm_file_t *file_first; /**< file list head */
drm_file_t *file_last; /**< file list tail */
- drm_magic_head_t magiclist[DRM_HASH_SIZE]; /**< magic hash table */
+ drm_open_hash_t magiclist; /**< magic hash table */
+ struct list_head magicfree;
/*@} */
/** \name Memory management */
/*@{ */
drm_map_list_t *maplist; /**< Linked list of regions */
int map_count; /**< Number of mappable regions */
+ drm_open_hash_t map_hash; /**< User token hash table for maps */
/** \name Context handle management */
/*@{ */
@@ -711,10 +723,8 @@ typedef struct drm_device {
drm_agp_head_t *agp; /**< AGP data */
struct pci_dev *pdev; /**< PCI device structure */
- int pci_domain; /**< PCI bus domain number */
- int pci_bus; /**< PCI bus number */
- int pci_slot; /**< PCI slot number */
- int pci_func; /**< PCI function number */
+ int pci_vendor; /**< PCI vendor id */
+ int pci_device; /**< PCI device id */
#ifdef __alpha__
struct pci_controller *hose;
#endif
@@ -736,6 +746,12 @@ static __inline__ int drm_core_check_feature(struct drm_device *dev,
return ((dev->driver->driver_features & feature) ? 1 : 0);
}
+#ifdef __alpha__
+#define drm_get_pci_domain(dev) dev->hose->bus->number
+#else
+#define drm_get_pci_domain(dev) 0
+#endif
+
#if __OS_HAS_AGP
static inline int drm_core_has_AGP(struct drm_device *dev)
{
@@ -1011,6 +1027,18 @@ extern struct class_device *drm_sysfs_device_add(struct class *cs,
drm_head_t *head);
extern void drm_sysfs_device_remove(struct class_device *class_dev);
+/*
+ * Basic memory manager support (drm_mm.c)
+ */
+extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
+ unsigned long size,
+ unsigned alignment);
+extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
+ unsigned alignment, int best_match);
+extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
+extern void drm_mm_takedown(drm_mm_t *mm);
+
/* Inline replacements for DRM_IOREMAP macros */
static __inline__ void drm_core_ioremap(struct drm_map *map,
struct drm_device *dev)
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index 2a37586a7ee8..c7b19d35bcd6 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -36,20 +36,6 @@
#include "drmP.h"
/**
- * Generate a hash key from a magic.
- *
- * \param magic magic.
- * \return hash key.
- *
- * The key is the modulus of the hash table size, #DRM_HASH_SIZE, which must be
- * a power of 2.
- */
-static int drm_hash_magic(drm_magic_t magic)
-{
- return magic & (DRM_HASH_SIZE - 1);
-}
-
-/**
* Find the file with the given magic number.
*
* \param dev DRM device.
@@ -63,14 +49,12 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
{
drm_file_t *retval = NULL;
drm_magic_entry_t *pt;
- int hash = drm_hash_magic(magic);
+ drm_hash_item_t *hash;
mutex_lock(&dev->struct_mutex);
- for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
- if (pt->magic == magic) {
- retval = pt->priv;
- break;
- }
+ if (!drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+ pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+ retval = pt->priv;
}
mutex_unlock(&dev->struct_mutex);
return retval;
@@ -90,28 +74,20 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
drm_magic_t magic)
{
- int hash;
drm_magic_entry_t *entry;
DRM_DEBUG("%d\n", magic);
- hash = drm_hash_magic(magic);
entry = drm_alloc(sizeof(*entry), DRM_MEM_MAGIC);
if (!entry)
return -ENOMEM;
memset(entry, 0, sizeof(*entry));
- entry->magic = magic;
entry->priv = priv;
- entry->next = NULL;
+ entry->hash_item.key = (unsigned long)magic;
mutex_lock(&dev->struct_mutex);
- if (dev->magiclist[hash].tail) {
- dev->magiclist[hash].tail->next = entry;
- dev->magiclist[hash].tail = entry;
- } else {
- dev->magiclist[hash].head = entry;
- dev->magiclist[hash].tail = entry;
- }
+ drm_ht_insert_item(&dev->magiclist, &entry->hash_item);
+ list_add_tail(&entry->head, &dev->magicfree);
mutex_unlock(&dev->struct_mutex);
return 0;
@@ -128,34 +104,24 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
*/
static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
{
- drm_magic_entry_t *prev = NULL;
drm_magic_entry_t *pt;
- int hash;
+ drm_hash_item_t *hash;
DRM_DEBUG("%d\n", magic);
- hash = drm_hash_magic(magic);
mutex_lock(&dev->struct_mutex);
- for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
- if (pt->magic == magic) {
- if (dev->magiclist[hash].head == pt) {
- dev->magiclist[hash].head = pt->next;
- }
- if (dev->magiclist[hash].tail == pt) {
- dev->magiclist[hash].tail = prev;
- }
- if (prev) {
- prev->next = pt->next;
- }
- mutex_unlock(&dev->struct_mutex);
- return 0;
- }
+ if (drm_ht_find_item(&dev->magiclist, (unsigned long)magic, &hash)) {
+ mutex_unlock(&dev->struct_mutex);
+ return -EINVAL;
}
+ pt = drm_hash_entry(hash, drm_magic_entry_t, hash_item);
+ drm_ht_remove_item(&dev->magiclist, hash);
+ list_del(&pt->head);
mutex_unlock(&dev->struct_mutex);
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
- return -EINVAL;
+ return 0;
}
/**
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 006b06d29727..029baea33b62 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -65,43 +65,29 @@ static drm_map_list_t *drm_find_matching_map(drm_device_t *dev,
return NULL;
}
-/*
- * Used to allocate 32-bit handles for mappings.
- */
-#define START_RANGE 0x10000000
-#define END_RANGE 0x40000000
-
-#ifdef _LP64
-static __inline__ unsigned int HandleID(unsigned long lhandle,
- drm_device_t *dev)
+static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
+ unsigned long user_token, int hashed_handle)
{
- static unsigned int map32_handle = START_RANGE;
- unsigned int hash;
-
- if (lhandle & 0xffffffff00000000) {
- hash = map32_handle;
- map32_handle += PAGE_SIZE;
- if (map32_handle > END_RANGE)
- map32_handle = START_RANGE;
- } else
- hash = lhandle;
-
- while (1) {
- drm_map_list_t *_entry;
- list_for_each_entry(_entry, &dev->maplist->head, head) {
- if (_entry->user_token == hash)
- break;
- }
- if (&_entry->head == &dev->maplist->head)
- return hash;
+ int use_hashed_handle;
+#if (BITS_PER_LONG == 64)
+ use_hashed_handle = ((user_token & 0xFFFFFFFF00000000UL) || hashed_handle);
+#elif (BITS_PER_LONG == 32)
+ use_hashed_handle = hashed_handle;
+#else
+#error Unsupported long size. Neither 64 nor 32 bits.
+#endif
- hash += PAGE_SIZE;
- map32_handle += PAGE_SIZE;
+ if (!use_hashed_handle) {
+ int ret;
+ hash->key = user_token;
+ ret = drm_ht_insert_item(&dev->map_hash, hash);
+ if (ret != -EINVAL)
+ return ret;
}
+ return drm_ht_just_insert_please(&dev->map_hash, hash,
+ user_token, 32 - PAGE_SHIFT - 3,
+ PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
}
-#else
-# define HandleID(x,dev) (unsigned int)(x)
-#endif
/**
* Ioctl to specify a range of memory that is available for mapping by a non-root process.
@@ -123,6 +109,8 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
drm_map_t *map;
drm_map_list_t *list;
drm_dma_handle_t *dmah;
+ unsigned long user_token;
+ int ret;
map = drm_alloc(sizeof(*map), DRM_MEM_MAPS);
if (!map)
@@ -257,11 +245,20 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
mutex_lock(&dev->struct_mutex);
list_add(&list->head, &dev->maplist->head);
+
/* Assign a 32-bit handle */
/* We do it here so that dev->struct_mutex protects the increment */
- list->user_token = HandleID(map->type == _DRM_SHM
- ? (unsigned long)map->handle
- : map->offset, dev);
+ user_token = (map->type == _DRM_SHM) ? (unsigned long)map->handle :
+ map->offset;
+ ret = drm_map_handle(dev, &list->hash, user_token, 0);
+ if (ret) {
+ drm_free(map, sizeof(*map), DRM_MEM_MAPS);
+ drm_free(list, sizeof(*list), DRM_MEM_MAPS);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
+
+ list->user_token = list->hash.key;
mutex_unlock(&dev->struct_mutex);
*maplist = list;
@@ -346,6 +343,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
if (r_list->map == map) {
list_del(list);
+ drm_ht_remove_key(&dev->map_hash, r_list->user_token);
drm_free(list, sizeof(*list), DRM_MEM_MAPS);
break;
}
@@ -441,8 +439,10 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
return -EINVAL;
}
- if (!map)
+ if (!map) {
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
+ }
/* Register and framebuffer maps are permanent */
if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 3c0b882a8e72..b366c5b1bd16 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -118,7 +118,7 @@ static drm_ioctl_desc_t drm_ioctls[] = {
[DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK)] = {drm_wait_vblank, 0},
};
-#define DRIVER_IOCTL_COUNT DRM_ARRAY_SIZE( drm_ioctls )
+#define DRIVER_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
/**
* Take down the DRM device.
@@ -155,12 +155,13 @@ int drm_lastclose(drm_device_t * dev)
del_timer(&dev->timer);
/* Clear pid list */
- for (i = 0; i < DRM_HASH_SIZE; i++) {
- for (pt = dev->magiclist[i].head; pt; pt = next) {
- next = pt->next;
+ if (dev->magicfree.next) {
+ list_for_each_entry_safe(pt, next, &dev->magicfree, head) {
+ list_del(&pt->head);
+ drm_ht_remove_item(&dev->magiclist, &pt->hash_item);
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
}
- dev->magiclist[i].head = dev->magiclist[i].tail = NULL;
+ drm_ht_remove(&dev->magiclist);
}
/* Clear AGP information */
@@ -299,6 +300,7 @@ static void drm_cleanup(drm_device_t * dev)
if (dev->maplist) {
drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
dev->maplist = NULL;
+ drm_ht_remove(&dev->map_hash);
}
drm_ctxbitmap_cleanup(dev);
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index b7f7951c4587..898f47dafec0 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -53,6 +53,8 @@ static int drm_setup(drm_device_t * dev)
return ret;
}
+ dev->magicfree.next = NULL;
+
/* prebuild the SAREA */
i = drm_addmap(dev, 0, SAREA_MAX, _DRM_SHM, _DRM_CONTAINS_LOCK, &map);
if (i != 0)
@@ -69,13 +71,11 @@ static int drm_setup(drm_device_t * dev)
return i;
}
- for (i = 0; i < DRM_ARRAY_SIZE(dev->counts); i++)
+ for (i = 0; i < ARRAY_SIZE(dev->counts); i++)
atomic_set(&dev->counts[i], 0);
- for (i = 0; i < DRM_HASH_SIZE; i++) {
- dev->magiclist[i].head = NULL;
- dev->magiclist[i].tail = NULL;
- }
+ drm_ht_create(&dev->magiclist, DRM_MAGIC_HASH_ORDER);
+ INIT_LIST_HEAD(&dev->magicfree);
dev->ctxlist = drm_alloc(sizeof(*dev->ctxlist), DRM_MEM_CTXLIST);
if (dev->ctxlist == NULL)
diff --git a/drivers/char/drm/drm_hashtab.c b/drivers/char/drm/drm_hashtab.c
new file mode 100644
index 000000000000..a0b2d6802ae4
--- /dev/null
+++ b/drivers/char/drm/drm_hashtab.c
@@ -0,0 +1,190 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND. USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple open hash tab implementation.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+#include "drm_hashtab.h"
+#include <linux/hash.h>
+
+int drm_ht_create(drm_open_hash_t *ht, unsigned int order)
+{
+ unsigned int i;
+
+ ht->size = 1 << order;
+ ht->order = order;
+ ht->fill = 0;
+ ht->table = vmalloc(ht->size*sizeof(*ht->table));
+ if (!ht->table) {
+ DRM_ERROR("Out of memory for hash table\n");
+ return -ENOMEM;
+ }
+ for (i=0; i< ht->size; ++i) {
+ INIT_HLIST_HEAD(&ht->table[i]);
+ }
+ return 0;
+}
+
+void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key)
+{
+ drm_hash_item_t *entry;
+ struct hlist_head *h_list;
+ struct hlist_node *list;
+ unsigned int hashed_key;
+ int count = 0;
+
+ hashed_key = hash_long(key, ht->order);
+ DRM_DEBUG("Key is 0x%08lx, Hashed key is 0x%08x\n", key, hashed_key);
+ h_list = &ht->table[hashed_key];
+ hlist_for_each(list, h_list) {
+ entry = hlist_entry(list, drm_hash_item_t, head);
+ DRM_DEBUG("count %d, key: 0x%08lx\n", count++, entry->key);
+ }
+}
+
+static struct hlist_node *drm_ht_find_key(drm_open_hash_t *ht,
+ unsigned long key)
+{
+ drm_hash_item_t *entry;
+ struct hlist_head *h_list;
+ struct hlist_node *list;
+ unsigned int hashed_key;
+
+ hashed_key = hash_long(key, ht->order);
+ h_list = &ht->table[hashed_key];
+ hlist_for_each(list, h_list) {
+ entry = hlist_entry(list, drm_hash_item_t, head);
+ if (entry->key == key)
+ return list;
+ if (entry->key > key)
+ break;
+ }
+ return NULL;
+}
+
+
+int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+{
+ drm_hash_item_t *entry;
+ struct hlist_head *h_list;
+ struct hlist_node *list, *parent;
+ unsigned int hashed_key;
+ unsigned long key = item->key;
+
+ hashed_key = hash_long(key, ht->order);
+ h_list = &ht->table[hashed_key];
+ parent = NULL;
+ hlist_for_each(list, h_list) {
+ entry = hlist_entry(list, drm_hash_item_t, head);
+ if (entry->key == key)
+ return -EINVAL;
+ if (entry->key > key)
+ break;
+ parent = list;
+ }
+ if (parent) {
+ hlist_add_after(parent, &item->head);
+ } else {
+ hlist_add_head(&item->head, h_list);
+ }
+ return 0;
+}
+
+/*
+ * Just insert an item and return any "bits" bit key that hasn't been
+ * used before.
+ */
+int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+ unsigned long seed, int bits, int shift,
+ unsigned long add)
+{
+ int ret;
+ unsigned long mask = (1 << bits) - 1;
+ unsigned long first, unshifted_key;
+
+ unshifted_key = hash_long(seed, bits);
+ first = unshifted_key;
+ do {
+ item->key = (unshifted_key << shift) + add;
+ ret = drm_ht_insert_item(ht, item);
+ if (ret)
+ unshifted_key = (unshifted_key + 1) & mask;
+ } while(ret && (unshifted_key != first));
+
+ if (ret) {
+ DRM_ERROR("Available key bit space exhausted\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key,
+ drm_hash_item_t **item)
+{
+ struct hlist_node *list;
+
+ list = drm_ht_find_key(ht, key);
+ if (!list)
+ return -EINVAL;
+
+ *item = hlist_entry(list, drm_hash_item_t, head);
+ return 0;
+}
+
+int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key)
+{
+ struct hlist_node *list;
+
+ list = drm_ht_find_key(ht, key);
+ if (list) {
+ hlist_del_init(list);
+ ht->fill--;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item)
+{
+ hlist_del_init(&item->head);
+ ht->fill--;
+ return 0;
+}
+
+void drm_ht_remove(drm_open_hash_t *ht)
+{
+ if (ht->table) {
+ vfree(ht->table);
+ ht->table = NULL;
+ }
+}
+
diff --git a/drivers/char/drm/drm_hashtab.h b/drivers/char/drm/drm_hashtab.h
new file mode 100644
index 000000000000..40afec05bff8
--- /dev/null
+++ b/drivers/char/drm/drm_hashtab.h
@@ -0,0 +1,67 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismack, ND. USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple open hash tab implementation.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef DRM_HASHTAB_H
+#define DRM_HASHTAB_H
+
+#define drm_hash_entry(_ptr, _type, _member) container_of(_ptr, _type, _member)
+
+typedef struct drm_hash_item{
+ struct hlist_node head;
+ unsigned long key;
+} drm_hash_item_t;
+
+typedef struct drm_open_hash{
+ unsigned int size;
+ unsigned int order;
+ unsigned int fill;
+ struct hlist_head *table;
+} drm_open_hash_t;
+
+
+extern int drm_ht_create(drm_open_hash_t *ht, unsigned int order);
+extern int drm_ht_insert_item(drm_open_hash_t *ht, drm_hash_item_t *item);
+extern int drm_ht_just_insert_please(drm_open_hash_t *ht, drm_hash_item_t *item,
+ unsigned long seed, int bits, int shift,
+ unsigned long add);
+extern int drm_ht_find_item(drm_open_hash_t *ht, unsigned long key, drm_hash_item_t **item);
+
+extern void drm_ht_verbose_list(drm_open_hash_t *ht, unsigned long key);
+extern int drm_ht_remove_key(drm_open_hash_t *ht, unsigned long key);
+extern int drm_ht_remove_item(drm_open_hash_t *ht, drm_hash_item_t *item);
+extern void drm_ht_remove(drm_open_hash_t *ht);
+
+
+#endif
+
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
index e9e2db18952d..d4f874520082 100644
--- a/drivers/char/drm/drm_ioc32.c
+++ b/drivers/char/drm/drm_ioc32.c
@@ -1051,7 +1051,7 @@ long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
drm_ioctl_compat_t *fn;
int ret;
- if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls))
+ if (nr >= ARRAY_SIZE(drm_compat_ioctls))
return -ENOTTY;
fn = drm_compat_ioctls[nr];
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
index 555f323b8a32..565895547d75 100644
--- a/drivers/char/drm/drm_ioctl.c
+++ b/drivers/char/drm/drm_ioctl.c
@@ -127,9 +127,10 @@ int drm_setunique(struct inode *inode, struct file *filp,
domain = bus >> 8;
bus &= 0xff;
- if ((domain != dev->pci_domain) ||
- (bus != dev->pci_bus) ||
- (slot != dev->pci_slot) || (func != dev->pci_func))
+ if ((domain != drm_get_pci_domain(dev)) ||
+ (bus != dev->pdev->bus->number) ||
+ (slot != PCI_SLOT(dev->pdev->devfn)) ||
+ (func != PCI_FUNC(dev->pdev->devfn)))
return -EINVAL;
return 0;
@@ -140,15 +141,17 @@ static int drm_set_busid(drm_device_t * dev)
int len;
if (dev->unique != NULL)
- return EBUSY;
+ return 0;
dev->unique_len = 40;
dev->unique = drm_alloc(dev->unique_len + 1, DRM_MEM_DRIVER);
if (dev->unique == NULL)
- return ENOMEM;
+ return -ENOMEM;
len = snprintf(dev->unique, dev->unique_len, "pci:%04x:%02x:%02x.%d",
- dev->pci_domain, dev->pci_bus, dev->pci_slot, dev->pci_func);
+ drm_get_pci_domain(dev), dev->pdev->bus->number,
+ PCI_SLOT(dev->pdev->devfn),
+ PCI_FUNC(dev->pdev->devfn));
if (len > dev->unique_len)
DRM_ERROR("Unique buffer overflowed\n");
@@ -157,7 +160,7 @@ static int drm_set_busid(drm_device_t * dev)
drm_alloc(strlen(dev->driver->pci_driver.name) + dev->unique_len +
2, DRM_MEM_DRIVER);
if (dev->devname == NULL)
- return ENOMEM;
+ return -ENOMEM;
sprintf(dev->devname, "%s@%s", dev->driver->pci_driver.name,
dev->unique);
@@ -330,27 +333,32 @@ int drm_setversion(DRM_IOCTL_ARGS)
drm_set_version_t retv;
int if_version;
drm_set_version_t __user *argp = (void __user *)data;
+ int ret;
- DRM_COPY_FROM_USER_IOCTL(sv, argp, sizeof(sv));
+ if (copy_from_user(&sv, argp, sizeof(sv)))
+ return -EFAULT;
retv.drm_di_major = DRM_IF_MAJOR;
retv.drm_di_minor = DRM_IF_MINOR;
retv.drm_dd_major = dev->driver->major;
retv.drm_dd_minor = dev->driver->minor;
- DRM_COPY_TO_USER_IOCTL(argp, retv, sizeof(sv));
+ if (copy_to_user(argp, &retv, sizeof(retv)))
+ return -EFAULT;
if (sv.drm_di_major != -1) {
if (sv.drm_di_major != DRM_IF_MAJOR ||
sv.drm_di_minor < 0 || sv.drm_di_minor > DRM_IF_MINOR)
- return EINVAL;
+ return -EINVAL;
if_version = DRM_IF_VERSION(sv.drm_di_major, sv.drm_di_minor);
- dev->if_version = DRM_MAX(if_version, dev->if_version);
+ dev->if_version = max(if_version, dev->if_version);
if (sv.drm_di_minor >= 1) {
/*
* Version 1.1 includes tying of DRM to specific device
*/
- drm_set_busid(dev);
+ ret = drm_set_busid(dev);
+ if (ret)
+ return ret;
}
}
@@ -358,7 +366,7 @@ int drm_setversion(DRM_IOCTL_ARGS)
if (sv.drm_dd_major != dev->driver->major ||
sv.drm_dd_minor < 0
|| sv.drm_dd_minor > dev->driver->minor)
- return EINVAL;
+ return -EINVAL;
if (dev->driver->set_version)
dev->driver->set_version(dev, &sv);
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index ebdb7182c4fd..4553a3a1e496 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -64,9 +64,9 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
if (copy_from_user(&p, argp, sizeof(p)))
return -EFAULT;
- if ((p.busnum >> 8) != dev->pci_domain ||
- (p.busnum & 0xff) != dev->pci_bus ||
- p.devnum != dev->pci_slot || p.funcnum != dev->pci_func)
+ if ((p.busnum >> 8) != drm_get_pci_domain(dev) ||
+ (p.busnum & 0xff) != dev->pdev->bus->number ||
+ p.devnum != PCI_SLOT(dev->pdev->devfn) || p.funcnum != PCI_FUNC(dev->pdev->devfn))
return -EINVAL;
p.irq = dev->irq;
@@ -255,7 +255,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
if (!dev->irq)
return -EINVAL;
- DRM_COPY_FROM_USER_IOCTL(vblwait, argp, sizeof(vblwait));
+ if (copy_from_user(&vblwait, argp, sizeof(vblwait)))
+ return -EFAULT;
switch (vblwait.request.type & ~_DRM_VBLANK_FLAGS_MASK) {
case _DRM_VBLANK_RELATIVE:
@@ -329,7 +330,8 @@ int drm_wait_vblank(DRM_IOCTL_ARGS)
}
done:
- DRM_COPY_TO_USER_IOCTL(argp, vblwait, sizeof(vblwait));
+ if (copy_to_user(argp, &vblwait, sizeof(vblwait)))
+ return -EFAULT;
return ret;
}
diff --git a/drivers/char/drm/drm_mm.c b/drivers/char/drm/drm_mm.c
new file mode 100644
index 000000000000..617526bd5b0c
--- /dev/null
+++ b/drivers/char/drm/drm_mm.c
@@ -0,0 +1,201 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+
+/*
+ * Generic simple memory manager implementation. Intended to be used as a base
+ * class implementation for more advanced memory managers.
+ *
+ * Note that the algorithm used is quite simple and there might be substantial
+ * performance gains if a smarter free list is implemented. Currently it is just an
+ * unordered stack of free regions. This could easily be improved if an RB-tree
+ * is used instead. At least if we expect heavy fragmentation.
+ *
+ * Aligned allocations can also see improvement.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drmP.h"
+
+drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
+ unsigned long size, unsigned alignment)
+{
+
+ drm_mm_node_t *child;
+
+ if (alignment)
+ size += alignment - 1;
+
+ if (parent->size == size) {
+ list_del_init(&parent->fl_entry);
+ parent->free = 0;
+ return parent;
+ } else {
+ child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return NULL;
+
+ INIT_LIST_HEAD(&child->ml_entry);
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ child->free = 0;
+ child->size = size;
+ child->start = parent->start;
+
+ list_add_tail(&child->ml_entry, &parent->ml_entry);
+ parent->size -= size;
+ parent->start += size;
+ }
+ return child;
+}
+
+/*
+ * Put a block. Merge with the previous and / or next block if they are free.
+ * Otherwise add to the free stack.
+ */
+
+void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+{
+
+ drm_mm_node_t *list_root = &mm->root_node;
+ struct list_head *cur_head = &cur->ml_entry;
+ struct list_head *root_head = &list_root->ml_entry;
+ drm_mm_node_t *prev_node = NULL;
+ drm_mm_node_t *next_node;
+
+ int merged = 0;
+
+ if (cur_head->prev != root_head) {
+ prev_node = list_entry(cur_head->prev, drm_mm_node_t, ml_entry);
+ if (prev_node->free) {
+ prev_node->size += cur->size;
+ merged = 1;
+ }
+ }
+ if (cur_head->next != root_head) {
+ next_node = list_entry(cur_head->next, drm_mm_node_t, ml_entry);
+ if (next_node->free) {
+ if (merged) {
+ prev_node->size += next_node->size;
+ list_del(&next_node->ml_entry);
+ list_del(&next_node->fl_entry);
+ drm_free(next_node, sizeof(*next_node),
+ DRM_MEM_MM);
+ } else {
+ next_node->size += cur->size;
+ next_node->start = cur->start;
+ merged = 1;
+ }
+ }
+ }
+ if (!merged) {
+ cur->free = 1;
+ list_add(&cur->fl_entry, &list_root->fl_entry);
+ } else {
+ list_del(&cur->ml_entry);
+ drm_free(cur, sizeof(*cur), DRM_MEM_MM);
+ }
+}
+
+drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
+ unsigned long size,
+ unsigned alignment, int best_match)
+{
+ struct list_head *list;
+ const struct list_head *free_stack = &mm->root_node.fl_entry;
+ drm_mm_node_t *entry;
+ drm_mm_node_t *best;
+ unsigned long best_size;
+
+ best = NULL;
+ best_size = ~0UL;
+
+ if (alignment)
+ size += alignment - 1;
+
+ list_for_each(list, free_stack) {
+ entry = list_entry(list, drm_mm_node_t, fl_entry);
+ if (entry->size >= size) {
+ if (!best_match)
+ return entry;
+ if (size < best_size) {
+ best = entry;
+ best_size = entry->size;
+ }
+ }
+ }
+
+ return best;
+}
+
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+ drm_mm_node_t *child;
+
+ INIT_LIST_HEAD(&mm->root_node.ml_entry);
+ INIT_LIST_HEAD(&mm->root_node.fl_entry);
+ child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
+ if (!child)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&child->ml_entry);
+ INIT_LIST_HEAD(&child->fl_entry);
+
+ child->start = start;
+ child->size = size;
+ child->free = 1;
+
+ list_add(&child->fl_entry, &mm->root_node.fl_entry);
+ list_add(&child->ml_entry, &mm->root_node.ml_entry);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(drm_mm_init);
+
+void drm_mm_takedown(drm_mm_t * mm)
+{
+ struct list_head *bnode = mm->root_node.fl_entry.next;
+ drm_mm_node_t *entry;
+
+ entry = list_entry(bnode, drm_mm_node_t, fl_entry);
+
+ if (entry->ml_entry.next != &mm->root_node.ml_entry ||
+ entry->fl_entry.next != &mm->root_node.fl_entry) {
+ DRM_ERROR("Memory manager not clean. Delaying takedown\n");
+ return;
+ }
+
+ list_del(&entry->fl_entry);
+ list_del(&entry->ml_entry);
+
+ drm_free(entry, sizeof(*entry), DRM_MEM_MM);
+}
+
+EXPORT_SYMBOL(drm_mm_takedown);
diff --git a/drivers/char/drm/drm_os_linux.h b/drivers/char/drm/drm_os_linux.h
index 695115d70382..2908b72daa6e 100644
--- a/drivers/char/drm/drm_os_linux.h
+++ b/drivers/char/drm/drm_os_linux.h
@@ -38,7 +38,7 @@
drm_device_t *dev = priv->head->dev
/** IRQ handler arguments and return type and values */
-#define DRM_IRQ_ARGS int irq, void *arg, struct pt_regs *regs
+#define DRM_IRQ_ARGS int irq, void *arg
/** AGP types */
#if __OS_HAS_AGP
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index b1bb3c7b568d..09398d5fbd3f 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -3,13 +3,13 @@
Please contact dri-devel@lists.sf.net to add new cards to this list
*/
#define radeon_PCI_IDS \
- {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
- {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
- {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
+ {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x3152, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x3154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x3E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x3E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP}, \
+ {0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
{0x1002, 0x4145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
{0x1002, 0x4146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
@@ -25,35 +25,35 @@
{0x1002, 0x4154, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
{0x1002, 0x4155, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
{0x1002, 0x4156, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350}, \
- {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
+ {0x1002, 0x4237, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP}, \
{0x1002, 0x4242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
{0x1002, 0x4243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
- {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+ {0x1002, 0x4336, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4337, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4437, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
{0x1002, 0x4966, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
{0x1002, 0x4967, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250}, \
- {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|CHIP_IS_MOBILITY}, \
+ {0x1002, 0x4A48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A4D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A4E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A4F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4A54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4B49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4B4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4B4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4B4C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x4C57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4C58, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV200|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4C59, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4C5A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4C64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4C66, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4C67, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV250|RADEON_IS_MOBILITY}, \
{0x1002, 0x4E44, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
{0x1002, 0x4E45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
{0x1002, 0x4E46, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
@@ -62,16 +62,16 @@
{0x1002, 0x4E49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
{0x1002, 0x4E4A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
{0x1002, 0x4E4B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R350}, \
- {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
- {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|CHIP_IS_MOBILITY}, \
- {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
- {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
- {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
- {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|CHIP_SINGLE_CRTC}, \
+ {0x1002, 0x4E50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4E51, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4E52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4E53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4E54, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x4E56, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+ {0x1002, 0x5145, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+ {0x1002, 0x5146, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
+ {0x1002, 0x5147, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R100|RADEON_SINGLE_CRTC}, \
{0x1002, 0x5148, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
{0x1002, 0x514C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
{0x1002, 0x514D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R200}, \
@@ -80,59 +80,59 @@
{0x1002, 0x5159, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
{0x1002, 0x515A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
{0x1002, 0x515E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
- {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
- {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
- {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_IS_MOBILITY}, \
- {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP}, \
- {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY}, \
+ {0x1002, 0x5460, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5462, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5464, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5548, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5549, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x554A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x554B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x554C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x554D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x554E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x554F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5550, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5551, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5552, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5554, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x564A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x564B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x564F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP}, \
+ {0x1002, 0x5835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY}, \
{0x1002, 0x5960, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5961, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5962, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5964, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5965, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280}, \
{0x1002, 0x5969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV100}, \
- {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
- {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|CHIP_IS_MOBILITY}, \
- {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_NEW_MEMMAP}, \
- {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|CHIP_IS_IGP|CHIP_IS_MOBILITY|CHIP_NEW_MEMMAP}, \
+ {0x1002, 0x5b60, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5b62, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5b63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5b64, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5b65, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV380|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5c61, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5c63, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV280|RADEON_IS_MOBILITY}, \
+ {0x1002, 0x5d48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d49, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d50, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d52, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5d57, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R420|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5e48, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5e4a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5e4b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5e4c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5e4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x5e4f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV410|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
+ {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0, 0, 0}
#define r128_PCI_IDS \
@@ -209,6 +209,7 @@
{0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1039, 0x5300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1039, 0x6300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1039, 0x6330, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \
{0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
@@ -227,6 +228,10 @@
{0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
#define i810_PCI_IDS \
@@ -285,5 +290,9 @@
{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2972, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2982, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x2992, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x29a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 362a270af0f1..62d5fe15f046 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
vma->vm_flags & VM_LOCKED ? 'l' : '-',
vma->vm_flags & VM_IO ? 'i' : '-',
- VM_OFFSET(vma));
+ vma->vm_pgoff << PAGE_SHIFT);
#if defined(__i386__)
pgprot = pgprot_val(vma->vm_page_prot);
diff --git a/drivers/char/drm/drm_sman.c b/drivers/char/drm/drm_sman.c
new file mode 100644
index 000000000000..425c82336ee0
--- /dev/null
+++ b/drivers/char/drm/drm_sman.c
@@ -0,0 +1,352 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck., ND., USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * THE 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple memory manager interface that keeps track on allocate regions on a
+ * per "owner" basis. All regions associated with an "owner" can be released
+ * with a simple call. Typically if the "owner" exists. The owner is any
+ * "unsigned long" identifier. Can typically be a pointer to a file private
+ * struct or a context identifier.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#include "drm_sman.h"
+
+typedef struct drm_owner_item {
+ drm_hash_item_t owner_hash;
+ struct list_head sman_list;
+ struct list_head mem_blocks;
+} drm_owner_item_t;
+
+void drm_sman_takedown(drm_sman_t * sman)
+{
+ drm_ht_remove(&sman->user_hash_tab);
+ drm_ht_remove(&sman->owner_hash_tab);
+ if (sman->mm)
+ drm_free(sman->mm, sman->num_managers * sizeof(*sman->mm),
+ DRM_MEM_MM);
+}
+
+EXPORT_SYMBOL(drm_sman_takedown);
+
+int
+drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+ unsigned int user_order, unsigned int owner_order)
+{
+ int ret = 0;
+
+ sman->mm = (drm_sman_mm_t *) drm_calloc(num_managers, sizeof(*sman->mm),
+ DRM_MEM_MM);
+ if (!sman->mm) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ sman->num_managers = num_managers;
+ INIT_LIST_HEAD(&sman->owner_items);
+ ret = drm_ht_create(&sman->owner_hash_tab, owner_order);
+ if (ret)
+ goto out1;
+ ret = drm_ht_create(&sman->user_hash_tab, user_order);
+ if (!ret)
+ goto out;
+
+ drm_ht_remove(&sman->owner_hash_tab);
+out1:
+ drm_free(sman->mm, num_managers * sizeof(*sman->mm), DRM_MEM_MM);
+out:
+ return ret;
+}
+
+EXPORT_SYMBOL(drm_sman_init);
+
+static void *drm_sman_mm_allocate(void *private, unsigned long size,
+ unsigned alignment)
+{
+ drm_mm_t *mm = (drm_mm_t *) private;
+ drm_mm_node_t *tmp;
+
+ tmp = drm_mm_search_free(mm, size, alignment, 1);
+ if (!tmp) {
+ return NULL;
+ }
+ tmp = drm_mm_get_block(tmp, size, alignment);
+ return tmp;
+}
+
+static void drm_sman_mm_free(void *private, void *ref)
+{
+ drm_mm_t *mm = (drm_mm_t *) private;
+ drm_mm_node_t *node = (drm_mm_node_t *) ref;
+
+ drm_mm_put_block(mm, node);
+}
+
+static void drm_sman_mm_destroy(void *private)
+{
+ drm_mm_t *mm = (drm_mm_t *) private;
+ drm_mm_takedown(mm);
+ drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+}
+
+static unsigned long drm_sman_mm_offset(void *private, void *ref)
+{
+ drm_mm_node_t *node = (drm_mm_node_t *) ref;
+ return node->start;
+}
+
+int
+drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+ unsigned long start, unsigned long size)
+{
+ drm_sman_mm_t *sman_mm;
+ drm_mm_t *mm;
+ int ret;
+
+ BUG_ON(manager >= sman->num_managers);
+
+ sman_mm = &sman->mm[manager];
+ mm = drm_calloc(1, sizeof(*mm), DRM_MEM_MM);
+ if (!mm) {
+ return -ENOMEM;
+ }
+ sman_mm->private = mm;
+ ret = drm_mm_init(mm, start, size);
+
+ if (ret) {
+ drm_free(mm, sizeof(*mm), DRM_MEM_MM);
+ return ret;
+ }
+
+ sman_mm->allocate = drm_sman_mm_allocate;
+ sman_mm->free = drm_sman_mm_free;
+ sman_mm->destroy = drm_sman_mm_destroy;
+ sman_mm->offset = drm_sman_mm_offset;
+
+ return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_set_range);
+
+int
+drm_sman_set_manager(drm_sman_t * sman, unsigned int manager,
+ drm_sman_mm_t * allocator)
+{
+ BUG_ON(manager >= sman->num_managers);
+ sman->mm[manager] = *allocator;
+
+ return 0;
+}
+
+static drm_owner_item_t *drm_sman_get_owner_item(drm_sman_t * sman,
+ unsigned long owner)
+{
+ int ret;
+ drm_hash_item_t *owner_hash_item;
+ drm_owner_item_t *owner_item;
+
+ ret = drm_ht_find_item(&sman->owner_hash_tab, owner, &owner_hash_item);
+ if (!ret) {
+ return drm_hash_entry(owner_hash_item, drm_owner_item_t,
+ owner_hash);
+ }
+
+ owner_item = drm_calloc(1, sizeof(*owner_item), DRM_MEM_MM);
+ if (!owner_item)
+ goto out;
+
+ INIT_LIST_HEAD(&owner_item->mem_blocks);
+ owner_item->owner_hash.key = owner;
+ if (drm_ht_insert_item(&sman->owner_hash_tab, &owner_item->owner_hash))
+ goto out1;
+
+ list_add_tail(&owner_item->sman_list, &sman->owner_items);
+ return owner_item;
+
+out1:
+ drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
+out:
+ return NULL;
+}
+
+drm_memblock_item_t *drm_sman_alloc(drm_sman_t *sman, unsigned int manager,
+ unsigned long size, unsigned alignment,
+ unsigned long owner)
+{
+ void *tmp;
+ drm_sman_mm_t *sman_mm;
+ drm_owner_item_t *owner_item;
+ drm_memblock_item_t *memblock;
+
+ BUG_ON(manager >= sman->num_managers);
+
+ sman_mm = &sman->mm[manager];
+ tmp = sman_mm->allocate(sman_mm->private, size, alignment);
+
+ if (!tmp) {
+ return NULL;
+ }
+
+ memblock = drm_calloc(1, sizeof(*memblock), DRM_MEM_MM);
+
+ if (!memblock)
+ goto out;
+
+ memblock->mm_info = tmp;
+ memblock->mm = sman_mm;
+ memblock->sman = sman;
+
+ if (drm_ht_just_insert_please
+ (&sman->user_hash_tab, &memblock->user_hash,
+ (unsigned long)memblock, 32, 0, 0))
+ goto out1;
+
+ owner_item = drm_sman_get_owner_item(sman, owner);
+ if (!owner_item)
+ goto out2;
+
+ list_add_tail(&memblock->owner_list, &owner_item->mem_blocks);
+
+ return memblock;
+
+out2:
+ drm_ht_remove_item(&sman->user_hash_tab, &memblock->user_hash);
+out1:
+ drm_free(memblock, sizeof(*memblock), DRM_MEM_MM);
+out:
+ sman_mm->free(sman_mm->private, tmp);
+
+ return NULL;
+}
+
+EXPORT_SYMBOL(drm_sman_alloc);
+
+static void drm_sman_free(drm_memblock_item_t *item)
+{
+ drm_sman_t *sman = item->sman;
+
+ list_del(&item->owner_list);
+ drm_ht_remove_item(&sman->user_hash_tab, &item->user_hash);
+ item->mm->free(item->mm->private, item->mm_info);
+ drm_free(item, sizeof(*item), DRM_MEM_MM);
+}
+
+int drm_sman_free_key(drm_sman_t *sman, unsigned int key)
+{
+ drm_hash_item_t *hash_item;
+ drm_memblock_item_t *memblock_item;
+
+ if (drm_ht_find_item(&sman->user_hash_tab, key, &hash_item))
+ return -EINVAL;
+
+ memblock_item = drm_hash_entry(hash_item, drm_memblock_item_t, user_hash);
+ drm_sman_free(memblock_item);
+ return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_free_key);
+
+static void drm_sman_remove_owner(drm_sman_t *sman,
+ drm_owner_item_t *owner_item)
+{
+ list_del(&owner_item->sman_list);
+ drm_ht_remove_item(&sman->owner_hash_tab, &owner_item->owner_hash);
+ drm_free(owner_item, sizeof(*owner_item), DRM_MEM_MM);
+}
+
+int drm_sman_owner_clean(drm_sman_t *sman, unsigned long owner)
+{
+
+ drm_hash_item_t *hash_item;
+ drm_owner_item_t *owner_item;
+
+ if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+ return -1;
+ }
+
+ owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
+ if (owner_item->mem_blocks.next == &owner_item->mem_blocks) {
+ drm_sman_remove_owner(sman, owner_item);
+ return -1;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL(drm_sman_owner_clean);
+
+static void drm_sman_do_owner_cleanup(drm_sman_t *sman,
+ drm_owner_item_t *owner_item)
+{
+ drm_memblock_item_t *entry, *next;
+
+ list_for_each_entry_safe(entry, next, &owner_item->mem_blocks,
+ owner_list) {
+ drm_sman_free(entry);
+ }
+ drm_sman_remove_owner(sman, owner_item);
+}
+
+void drm_sman_owner_cleanup(drm_sman_t *sman, unsigned long owner)
+{
+
+ drm_hash_item_t *hash_item;
+ drm_owner_item_t *owner_item;
+
+ if (drm_ht_find_item(&sman->owner_hash_tab, owner, &hash_item)) {
+
+ return;
+ }
+
+ owner_item = drm_hash_entry(hash_item, drm_owner_item_t, owner_hash);
+ drm_sman_do_owner_cleanup(sman, owner_item);
+}
+
+EXPORT_SYMBOL(drm_sman_owner_cleanup);
+
+void drm_sman_cleanup(drm_sman_t *sman)
+{
+ drm_owner_item_t *entry, *next;
+ unsigned int i;
+ drm_sman_mm_t *sman_mm;
+
+ list_for_each_entry_safe(entry, next, &sman->owner_items, sman_list) {
+ drm_sman_do_owner_cleanup(sman, entry);
+ }
+ if (sman->mm) {
+ for (i = 0; i < sman->num_managers; ++i) {
+ sman_mm = &sman->mm[i];
+ if (sman_mm->private) {
+ sman_mm->destroy(sman_mm->private);
+ sman_mm->private = NULL;
+ }
+ }
+ }
+}
+
+EXPORT_SYMBOL(drm_sman_cleanup);
diff --git a/drivers/char/drm/drm_sman.h b/drivers/char/drm/drm_sman.h
new file mode 100644
index 000000000000..ddc732a1bf27
--- /dev/null
+++ b/drivers/char/drm/drm_sman.h
@@ -0,0 +1,176 @@
+/**************************************************************************
+ *
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ *
+ **************************************************************************/
+/*
+ * Simple memory MANager interface that keeps track on allocate regions on a
+ * per "owner" basis. All regions associated with an "owner" can be released
+ * with a simple call. Typically if the "owner" exists. The owner is any
+ * "unsigned long" identifier. Can typically be a pointer to a file private
+ * struct or a context identifier.
+ *
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
+#ifndef DRM_SMAN_H
+#define DRM_SMAN_H
+
+#include "drmP.h"
+#include "drm_hashtab.h"
+
+/*
+ * A class that is an abstration of a simple memory allocator.
+ * The sman implementation provides a default such allocator
+ * using the drm_mm.c implementation. But the user can replace it.
+ * See the SiS implementation, which may use the SiS FB kernel module
+ * for memory management.
+ */
+
+typedef struct drm_sman_mm {
+ /* private info. If allocated, needs to be destroyed by the destroy
+ function */
+ void *private;
+
+ /* Allocate a memory block with given size and alignment.
+ Return an opaque reference to the memory block */
+
+ void *(*allocate) (void *private, unsigned long size,
+ unsigned alignment);
+
+ /* Free a memory block. "ref" is the opaque reference that we got from
+ the "alloc" function */
+
+ void (*free) (void *private, void *ref);
+
+ /* Free all resources associated with this allocator */
+
+ void (*destroy) (void *private);
+
+ /* Return a memory offset from the opaque reference returned from the
+ "alloc" function */
+
+ unsigned long (*offset) (void *private, void *ref);
+} drm_sman_mm_t;
+
+typedef struct drm_memblock_item {
+ struct list_head owner_list;
+ drm_hash_item_t user_hash;
+ void *mm_info;
+ drm_sman_mm_t *mm;
+ struct drm_sman *sman;
+} drm_memblock_item_t;
+
+typedef struct drm_sman {
+ drm_sman_mm_t *mm;
+ int num_managers;
+ drm_open_hash_t owner_hash_tab;
+ drm_open_hash_t user_hash_tab;
+ struct list_head owner_items;
+} drm_sman_t;
+
+/*
+ * Take down a memory manager. This function should only be called after a
+ * successful init and after a call to drm_sman_cleanup.
+ */
+
+extern void drm_sman_takedown(drm_sman_t * sman);
+
+/*
+ * Allocate structures for a manager.
+ * num_managers are the number of memory pools to manage. (VRAM, AGP, ....)
+ * user_order is the log2 of the number of buckets in the user hash table.
+ * set this to approximately log2 of the max number of memory regions
+ * that will be allocated for _all_ pools together.
+ * owner_order is the log2 of the number of buckets in the owner hash table.
+ * set this to approximately log2 of
+ * the number of client file connections that will
+ * be using the manager.
+ *
+ */
+
+extern int drm_sman_init(drm_sman_t * sman, unsigned int num_managers,
+ unsigned int user_order, unsigned int owner_order);
+
+/*
+ * Initialize a drm_mm.c allocator. Should be called only once for each
+ * manager unless a customized allogator is used.
+ */
+
+extern int drm_sman_set_range(drm_sman_t * sman, unsigned int manager,
+ unsigned long start, unsigned long size);
+
+/*
+ * Initialize a customized allocator for one of the managers.
+ * (See the SiS module). The object pointed to by "allocator" is copied,
+ * so it can be destroyed after this call.
+ */
+
+extern int drm_sman_set_manager(drm_sman_t * sman, unsigned int mananger,
+ drm_sman_mm_t * allocator);
+
+/*
+ * Allocate a memory block. Aligment is not implemented yet.
+ */
+
+extern drm_memblock_item_t *drm_sman_alloc(drm_sman_t * sman,
+ unsigned int manager,
+ unsigned long size,
+ unsigned alignment,
+ unsigned long owner);
+/*
+ * Free a memory block identified by its user hash key.
+ */
+
+extern int drm_sman_free_key(drm_sman_t * sman, unsigned int key);
+
+/*
+ * returns 1 iff there are no stale memory blocks associated with this owner.
+ * Typically called to determine if we need to idle the hardware and call
+ * drm_sman_owner_cleanup. If there are no stale memory blocks, it removes all
+ * resources associated with owner.
+ */
+
+extern int drm_sman_owner_clean(drm_sman_t * sman, unsigned long owner);
+
+/*
+ * Frees all stale memory blocks associated with this owner. Note that this
+ * requires that the hardware is finished with all blocks, so the graphics engine
+ * should be idled before this call is made. This function also frees
+ * any resources associated with "owner" and should be called when owner
+ * is not going to be referenced anymore.
+ */
+
+extern void drm_sman_owner_cleanup(drm_sman_t * sman, unsigned long owner);
+
+/*
+ * Frees all stale memory blocks associated with the memory manager.
+ * See idling above.
+ */
+
+extern void drm_sman_cleanup(drm_sman_t * sman);
+
+#endif
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 9a842a36bb27..7b1d4e8659ba 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -65,22 +65,22 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
mutex_init(&dev->ctxlist_mutex);
dev->pdev = pdev;
+ dev->pci_device = pdev->device;
+ dev->pci_vendor = pdev->vendor;
#ifdef __alpha__
dev->hose = pdev->sysdata;
- dev->pci_domain = dev->hose->bus->number;
-#else
- dev->pci_domain = 0;
#endif
- dev->pci_bus = pdev->bus->number;
- dev->pci_slot = PCI_SLOT(pdev->devfn);
- dev->pci_func = PCI_FUNC(pdev->devfn);
dev->irq = pdev->irq;
dev->maplist = drm_calloc(1, sizeof(*dev->maplist), DRM_MEM_MAPS);
if (dev->maplist == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&dev->maplist->head);
+ if (drm_ht_create(&dev->map_hash, 12)) {
+ drm_free(dev->maplist, sizeof(*dev->maplist), DRM_MEM_MAPS);
+ return -ENOMEM;
+ }
/* the DRM has 6 basic counters */
dev->counters = 6;
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index ffd0800ed601..b40ae438f531 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -59,7 +59,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
drm_device_t *dev = priv->head->dev;
drm_map_t *map = NULL;
drm_map_list_t *r_list;
- struct list_head *list;
+ drm_hash_item_t *hash;
/*
* Find the right map
@@ -70,14 +70,11 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
if (!dev->agp || !dev->agp->cant_use_aperture)
goto vm_nopage_error;
- list_for_each(list, &dev->maplist->head) {
- r_list = list_entry(list, drm_map_list_t, head);
- map = r_list->map;
- if (!map)
- continue;
- if (r_list->user_token == VM_OFFSET(vma))
- break;
- }
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+ goto vm_nopage_error;
+
+ r_list = drm_hash_entry(hash, drm_map_list_t, hash);
+ map = r_list->map;
if (map && map->type == _DRM_AGP) {
unsigned long offset = address - vma->vm_start;
@@ -467,7 +464,7 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
dev = priv->head->dev;
dma = dev->dma;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+ vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
/* Length must match exact page count */
if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -521,12 +518,11 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
drm_map_t *map = NULL;
- drm_map_list_t *r_list;
unsigned long offset = 0;
- struct list_head *list;
+ drm_hash_item_t *hash;
DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
- vma->vm_start, vma->vm_end, VM_OFFSET(vma));
+ vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
if (!priv->authenticated)
return -EACCES;
@@ -535,7 +531,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
* the AGP mapped at physical address 0
* --BenH.
*/
- if (!VM_OFFSET(vma)
+ if (!(vma->vm_pgoff << PAGE_SHIFT)
#if __OS_HAS_AGP
&& (!dev->agp
|| dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -543,23 +539,12 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
)
return drm_mmap_dma(filp, vma);
- /* A sequential search of a linked list is
- fine here because: 1) there will only be
- about 5-10 entries in the list and, 2) a
- DRI client only has to do this mapping
- once, so it doesn't have to be optimized
- for performance, even if the list was a
- bit longer. */
- list_for_each(list, &dev->maplist->head) {
-
- r_list = list_entry(list, drm_map_list_t, head);
- map = r_list->map;
- if (!map)
- continue;
- if (r_list->user_token == VM_OFFSET(vma))
- break;
+ if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+ DRM_ERROR("Could not find map\n");
+ return -EINVAL;
}
+ map = drm_hash_entry(hash, drm_map_list_t, hash)->map;
if (!map || ((map->flags & _DRM_RESTRICTED) && !capable(CAP_SYS_ADMIN)))
return -EPERM;
@@ -620,7 +605,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
offset = dev->driver->get_reg_ofs(dev);
#ifdef __sparc__
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- if (io_remap_pfn_range(DRM_RPR_ARG(vma) vma->vm_start,
+ if (io_remap_pfn_range(vma, vma->vm_start,
(map->offset + offset) >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
vma->vm_page_prot))
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index c658dde3633b..fa2de70f7401 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -106,7 +106,7 @@ static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
unlock_kernel();
if (io_remap_pfn_range(vma, vma->vm_start,
- VM_OFFSET(vma) >> PAGE_SHIFT,
+ vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
@@ -141,10 +141,10 @@ static int i810_map_buffer(drm_buf_t * buf, struct file *filp)
MAP_SHARED, buf->bus_address);
dev_priv->mmap_buffer = NULL;
filp->f_op = old_fops;
- if ((unsigned long)buf_priv->virtual > -1024UL) {
+ if (IS_ERR(buf_priv->virtual)) {
/* Real error */
DRM_ERROR("mmap error\n");
- retcode = (signed int)buf_priv->virtual;
+ retcode = PTR_ERR(buf_priv->virtual);
buf_priv->virtual = NULL;
}
up_write(&current->mm->mmap_sem);
@@ -808,7 +808,7 @@ static void i810_dma_dispatch_vertex(drm_device_t * dev,
((GFX_OP_PRIMITIVE | prim | ((used / 4) - 2)));
if (used & 4) {
- *(u32 *) ((u32) buf_priv->kernel_virtual + used) = 0;
+ *(u32 *) ((char *) buf_priv->kernel_virtual + used) = 0;
used += 4;
}
@@ -1166,7 +1166,7 @@ static void i810_dma_dispatch_mc(drm_device_t * dev, drm_buf_t * buf, int used,
if (buf_priv->currently_mapped == I810_BUF_MAPPED) {
if (used & 4) {
- *(u32 *) ((u32) buf_priv->virtual + used) = 0;
+ *(u32 *) ((char *) buf_priv->virtual + used) = 0;
used += 4;
}
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index b0f815d8cea8..4f0e5746ab33 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -108,7 +108,7 @@ static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
unlock_kernel();
if (io_remap_pfn_range(vma, vma->vm_start,
- VM_OFFSET(vma) >> PAGE_SHIFT,
+ vma->vm_pgoff,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
@@ -146,7 +146,7 @@ static int i830_map_buffer(drm_buf_t * buf, struct file *filp)
if (IS_ERR((void *)virtual)) { /* ugh */
/* Real error */
DRM_ERROR("mmap error\n");
- retcode = virtual;
+ retcode = PTR_ERR((void *)virtual);
buf_priv->virtual = NULL;
} else {
buf_priv->virtual = (void __user *)virtual;
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index a94233bdbc0e..fb7913ff5286 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -31,6 +31,11 @@
#include "i915_drm.h"
#include "i915_drv.h"
+#define IS_I965G(dev) (dev->pci_device == 0x2972 || \
+ dev->pci_device == 0x2982 || \
+ dev->pci_device == 0x2992 || \
+ dev->pci_device == 0x29A2)
+
/* Really want an OS-independent resettable timer. Would like to have
* this loop run for (eg) 3 sec, but have the timer reset every time
* the head pointer changes, so that EBUSY only happens if the ring
@@ -255,7 +260,7 @@ static int i915_dma_init(DRM_IOCTL_ARGS)
retcode = i915_dma_resume(dev);
break;
default:
- retcode = -EINVAL;
+ retcode = DRM_ERR(EINVAL);
break;
}
@@ -347,7 +352,7 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
return DRM_ERR(EINVAL);
- BEGIN_LP_RING(((dwords+1)&~1));
+ BEGIN_LP_RING((dwords+1)&~1);
for (i = 0; i < dwords;) {
int cmd, sz;
@@ -386,7 +391,7 @@ static int i915_emit_box(drm_device_t * dev,
RING_LOCALS;
if (DRM_COPY_FROM_USER_UNCHECKED(&box, &boxes[i], sizeof(box))) {
- return EFAULT;
+ return DRM_ERR(EFAULT);
}
if (box.y2 <= box.y1 || box.x2 <= box.x1 || box.y2 <= 0 || box.x2 <= 0) {
@@ -395,24 +400,40 @@ static int i915_emit_box(drm_device_t * dev,
return DRM_ERR(EINVAL);
}
- BEGIN_LP_RING(6);
- OUT_RING(GFX_OP_DRAWRECT_INFO);
- OUT_RING(DR1);
- OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
- OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
- OUT_RING(DR4);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ if (IS_I965G(dev)) {
+ BEGIN_LP_RING(4);
+ OUT_RING(GFX_OP_DRAWRECT_INFO_I965);
+ OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+ OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+ OUT_RING(DR4);
+ ADVANCE_LP_RING();
+ } else {
+ BEGIN_LP_RING(6);
+ OUT_RING(GFX_OP_DRAWRECT_INFO);
+ OUT_RING(DR1);
+ OUT_RING((box.x1 & 0xffff) | (box.y1 << 16));
+ OUT_RING(((box.x2 - 1) & 0xffff) | ((box.y2 - 1) << 16));
+ OUT_RING(DR4);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+ }
return 0;
}
+/* XXX: Emitting the counter should really be moved to part of the IRQ
+ * emit. For now, do it in both places:
+ */
+
static void i915_emit_breadcrumb(drm_device_t *dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
- dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+ dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
+
+ if (dev_priv->counter > 0x7FFFFFFFUL)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
BEGIN_LP_RING(4);
OUT_RING(CMD_STORE_DWORD_IDX);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 5aa3e0e3bb45..6af83e613f27 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -98,6 +98,12 @@ typedef struct _drm_i915_sarea {
int rotated_size;
int rotated_pitch;
int virtualX, virtualY;
+
+ unsigned int front_tiled;
+ unsigned int back_tiled;
+ unsigned int depth_tiled;
+ unsigned int rotated_tiled;
+ unsigned int rotated2_tiled;
} drm_i915_sarea_t;
/* Flags for perf_boxes
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index 2d565031c002..fdc2bf192714 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -146,9 +146,9 @@ extern void i915_mem_release(drm_device_t * dev,
#define BEGIN_LP_RING(n) do { \
if (I915_VERBOSE) \
DRM_DEBUG("BEGIN_LP_RING(%d) in %s\n", \
- n, __FUNCTION__); \
- if (dev_priv->ring.space < n*4) \
- i915_wait_ring(dev, n*4, __FUNCTION__); \
+ (n), __FUNCTION__); \
+ if (dev_priv->ring.space < (n)*4) \
+ i915_wait_ring(dev, (n)*4, __FUNCTION__); \
outcount = 0; \
outring = dev_priv->ring.tail; \
ringmask = dev_priv->ring.tail_mask; \
@@ -157,7 +157,7 @@ extern void i915_mem_release(drm_device_t * dev,
#define OUT_RING(n) do { \
if (I915_VERBOSE) DRM_DEBUG(" OUT_RING %x\n", (int)(n)); \
- *(volatile unsigned int *)(virt + outring) = n; \
+ *(volatile unsigned int *)(virt + outring) = (n); \
outcount++; \
outring += 4; \
outring &= ringmask; \
@@ -254,6 +254,8 @@ extern int i915_wait_ring(drm_device_t * dev, int n, const char *caller);
#define GFX_OP_DESTBUFFER_VARS ((0x3<<29)|(0x1d<<24)|(0x85<<16)|0x0)
#define GFX_OP_DRAWRECT_INFO ((0x3<<29)|(0x1d<<24)|(0x80<<16)|(0x3))
+#define GFX_OP_DRAWRECT_INFO_I965 ((0x7900<<16)|0x2)
+
#define MI_BATCH_BUFFER ((0x30<<23)|1)
#define MI_BATCH_BUFFER_START (0x31<<23)
#define MI_BATCH_BUFFER_END (0xA<<23)
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index cd96cfa430db..0d4a162aa385 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -71,21 +71,27 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
static int i915_emit_irq(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
- u32 ret;
RING_LOCALS;
i915_kernel_lost_context(dev);
DRM_DEBUG("%s\n", __FUNCTION__);
- ret = dev_priv->counter;
+ dev_priv->sarea_priv->last_enqueue = ++dev_priv->counter;
- BEGIN_LP_RING(2);
+ if (dev_priv->counter > 0x7FFFFFFFUL)
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter = 1;
+
+ BEGIN_LP_RING(6);
+ OUT_RING(CMD_STORE_DWORD_IDX);
+ OUT_RING(20);
+ OUT_RING(dev_priv->counter);
+ OUT_RING(0);
OUT_RING(0);
OUT_RING(GFX_OP_USER_INTERRUPT);
ADVANCE_LP_RING();
-
- return ret;
+
+ return dev_priv->counter;
}
static int i915_wait_irq(drm_device_t * dev, int irq_nr)
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 5ad43ba7b5aa..5ed965688293 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -864,13 +864,13 @@ static int radeon_do_pixcache_flush(drm_radeon_private_t * dev_priv)
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
- tmp = RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT);
- tmp |= RADEON_RB2D_DC_FLUSH_ALL;
- RADEON_WRITE(RADEON_RB2D_DSTCACHE_CTLSTAT, tmp);
+ tmp = RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT);
+ tmp |= RADEON_RB3D_DC_FLUSH_ALL;
+ RADEON_WRITE(RADEON_RB3D_DSTCACHE_CTLSTAT, tmp);
for (i = 0; i < dev_priv->usec_timeout; i++) {
- if (!(RADEON_READ(RADEON_RB2D_DSTCACHE_CTLSTAT)
- & RADEON_RB2D_DC_BUSY)) {
+ if (!(RADEON_READ(RADEON_RB3D_DSTCACHE_CTLSTAT)
+ & RADEON_RB3D_DC_BUSY)) {
return 0;
}
DRM_UDELAY(1);
@@ -1130,7 +1130,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
| (dev_priv->fb_location >> 16));
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP) {
+ if (dev_priv->flags & RADEON_IS_AGP) {
RADEON_WRITE(RADEON_AGP_BASE, (unsigned int)dev->agp->base);
RADEON_WRITE(RADEON_MC_AGP_LOCATION,
(((dev_priv->gart_vm_start - 1 +
@@ -1158,7 +1158,7 @@ static void radeon_cp_init_ring_buffer(drm_device_t * dev,
dev_priv->ring.tail = cur_read_ptr;
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP) {
+ if (dev_priv->flags & RADEON_IS_AGP) {
RADEON_WRITE(RADEON_CP_RB_RPTR_ADDR,
dev_priv->ring_rptr->offset
- dev->agp->base + dev_priv->gart_vm_start);
@@ -1258,6 +1258,13 @@ static void radeon_test_writeback(drm_radeon_private_t * dev_priv)
dev_priv->writeback_works = 0;
DRM_INFO("writeback forced off\n");
}
+
+ if (!dev_priv->writeback_works) {
+ /* Disable writeback to avoid unnecessary bus master transfer */
+ RADEON_WRITE(RADEON_CP_RB_CNTL, RADEON_READ(RADEON_CP_RB_CNTL) |
+ RADEON_RB_NO_UPDATE);
+ RADEON_WRITE(RADEON_SCRATCH_UMSK, 0);
+ }
}
/* Enable or disable PCI-E GART on the chip */
@@ -1295,7 +1302,7 @@ static void radeon_set_pcigart(drm_radeon_private_t * dev_priv, int on)
{
u32 tmp;
- if (dev_priv->flags & CHIP_IS_PCIE) {
+ if (dev_priv->flags & RADEON_IS_PCIE) {
radeon_set_pciegart(dev_priv, on);
return;
}
@@ -1333,20 +1340,22 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
DRM_DEBUG("\n");
/* if we require new memory map but we don't have it fail */
- if ((dev_priv->flags & CHIP_NEW_MEMMAP) && !dev_priv->new_memmap)
- {
- DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX\n");
+ if ((dev_priv->flags & RADEON_NEW_MEMMAP) && !dev_priv->new_memmap) {
+ DRM_ERROR("Cannot initialise DRM on this card\nThis card requires a new X.org DDX for 3D\n");
radeon_do_cleanup_cp(dev);
return DRM_ERR(EINVAL);
}
- if (init->is_pci && (dev_priv->flags & CHIP_IS_AGP))
- {
+ if (init->is_pci && (dev_priv->flags & RADEON_IS_AGP)) {
DRM_DEBUG("Forcing AGP card to PCI mode\n");
- dev_priv->flags &= ~CHIP_IS_AGP;
+ dev_priv->flags &= ~RADEON_IS_AGP;
+ } else if (!(dev_priv->flags & (RADEON_IS_AGP | RADEON_IS_PCI | RADEON_IS_PCIE))
+ && !init->is_pci) {
+ DRM_DEBUG("Restoring AGP flag\n");
+ dev_priv->flags |= RADEON_IS_AGP;
}
- if ((!(dev_priv->flags & CHIP_IS_AGP)) && !dev->sg) {
+ if ((!(dev_priv->flags & RADEON_IS_AGP)) && !dev->sg) {
DRM_ERROR("PCI GART memory not allocated!\n");
radeon_do_cleanup_cp(dev);
return DRM_ERR(EINVAL);
@@ -1489,7 +1498,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
init->sarea_priv_offset);
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP) {
+ if (dev_priv->flags & RADEON_IS_AGP) {
drm_core_ioremap(dev_priv->cp_ring, dev);
drm_core_ioremap(dev_priv->ring_rptr, dev);
drm_core_ioremap(dev->agp_buffer_map, dev);
@@ -1548,7 +1557,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
* align it down.
*/
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP) {
+ if (dev_priv->flags & RADEON_IS_AGP) {
base = dev->agp->base;
/* Check if valid */
if ((base + dev_priv->gart_size) > dev_priv->fb_location &&
@@ -1578,7 +1587,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
}
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP)
+ if (dev_priv->flags & RADEON_IS_AGP)
dev_priv->gart_buffers_offset = (dev->agp_buffer_map->offset
- dev->agp->base
+ dev_priv->gart_vm_start);
@@ -1604,7 +1613,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
dev_priv->ring.high_mark = RADEON_RING_HIGH_MARK;
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP) {
+ if (dev_priv->flags & RADEON_IS_AGP) {
/* Turn off PCI GART */
radeon_set_pcigart(dev_priv, 0);
} else
@@ -1624,7 +1633,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
dev_priv->gart_info.mapping.handle;
dev_priv->gart_info.is_pcie =
- !!(dev_priv->flags & CHIP_IS_PCIE);
+ !!(dev_priv->flags & RADEON_IS_PCIE);
dev_priv->gart_info.gart_table_location =
DRM_ATI_GART_FB;
@@ -1636,7 +1645,7 @@ static int radeon_do_init_cp(drm_device_t * dev, drm_radeon_init_t * init)
DRM_ATI_GART_MAIN;
dev_priv->gart_info.addr = NULL;
dev_priv->gart_info.bus_addr = 0;
- if (dev_priv->flags & CHIP_IS_PCIE) {
+ if (dev_priv->flags & RADEON_IS_PCIE) {
DRM_ERROR
("Cannot use PCI Express without GART in FB memory\n");
radeon_do_cleanup_cp(dev);
@@ -1678,7 +1687,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev)
drm_irq_uninstall(dev);
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP) {
+ if (dev_priv->flags & RADEON_IS_AGP) {
if (dev_priv->cp_ring != NULL) {
drm_core_ioremapfree(dev_priv->cp_ring, dev);
dev_priv->cp_ring = NULL;
@@ -1733,7 +1742,7 @@ static int radeon_do_resume_cp(drm_device_t * dev)
DRM_DEBUG("Starting radeon_do_resume_cp()\n");
#if __OS_HAS_AGP
- if (dev_priv->flags & CHIP_IS_AGP) {
+ if (dev_priv->flags & RADEON_IS_AGP) {
/* Turn off PCI GART */
radeon_set_pcigart(dev_priv, 0);
} else
@@ -2177,13 +2186,15 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = (void *)dev_priv;
dev_priv->flags = flags;
- switch (flags & CHIP_FAMILY_MASK) {
+ switch (flags & RADEON_FAMILY_MASK) {
case CHIP_R100:
case CHIP_RV200:
case CHIP_R200:
case CHIP_R300:
+ case CHIP_R350:
case CHIP_R420:
- dev_priv->flags |= CHIP_HAS_HIERZ;
+ case CHIP_RV410:
+ dev_priv->flags |= RADEON_HAS_HIERZ;
break;
default:
/* all other chips have no hierarchical z buffer */
@@ -2191,13 +2202,14 @@ int radeon_driver_load(struct drm_device *dev, unsigned long flags)
}
if (drm_device_is_agp(dev))
- dev_priv->flags |= CHIP_IS_AGP;
-
- if (drm_device_is_pcie(dev))
- dev_priv->flags |= CHIP_IS_PCIE;
+ dev_priv->flags |= RADEON_IS_AGP;
+ else if (drm_device_is_pcie(dev))
+ dev_priv->flags |= RADEON_IS_PCIE;
+ else
+ dev_priv->flags |= RADEON_IS_PCI;
DRM_DEBUG("%s card detected\n",
- ((dev_priv->flags & CHIP_IS_AGP) ? "AGP" : (((dev_priv->flags & CHIP_IS_PCIE) ? "PCIE" : "PCI"))));
+ ((dev_priv->flags & RADEON_IS_AGP) ? "AGP" : (((dev_priv->flags & RADEON_IS_PCIE) ? "PCIE" : "PCI"))));
return ret;
}
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index eb985c2a31e9..2eb652ec6745 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -44,7 +44,7 @@ module_param_named(no_wb, radeon_no_wb, int, 0444);
static int dri_library_name(struct drm_device *dev, char *buf)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
- int family = dev_priv->flags & CHIP_FAMILY_MASK;
+ int family = dev_priv->flags & RADEON_FAMILY_MASK;
return snprintf(buf, PAGE_SIZE, "%s\n",
(family < CHIP_R200) ? "radeon" :
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index e5a256f5429c..f45cd7f147a5 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -133,15 +133,16 @@ enum radeon_cp_microcode_version {
* Chip flags
*/
enum radeon_chip_flags {
- CHIP_FAMILY_MASK = 0x0000ffffUL,
- CHIP_FLAGS_MASK = 0xffff0000UL,
- CHIP_IS_MOBILITY = 0x00010000UL,
- CHIP_IS_IGP = 0x00020000UL,
- CHIP_SINGLE_CRTC = 0x00040000UL,
- CHIP_IS_AGP = 0x00080000UL,
- CHIP_HAS_HIERZ = 0x00100000UL,
- CHIP_IS_PCIE = 0x00200000UL,
- CHIP_NEW_MEMMAP = 0x00400000UL,
+ RADEON_FAMILY_MASK = 0x0000ffffUL,
+ RADEON_FLAGS_MASK = 0xffff0000UL,
+ RADEON_IS_MOBILITY = 0x00010000UL,
+ RADEON_IS_IGP = 0x00020000UL,
+ RADEON_SINGLE_CRTC = 0x00040000UL,
+ RADEON_IS_AGP = 0x00080000UL,
+ RADEON_HAS_HIERZ = 0x00100000UL,
+ RADEON_IS_PCIE = 0x00200000UL,
+ RADEON_NEW_MEMMAP = 0x00400000UL,
+ RADEON_IS_PCI = 0x00800000UL,
};
#define GET_RING_HEAD(dev_priv) (dev_priv->writeback_works ? \
@@ -424,6 +425,8 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_RB3D_COLOROFFSET 0x1c40
#define RADEON_RB3D_COLORPITCH 0x1c48
+#define RADEON_SRC_X_Y 0x1590
+
#define RADEON_DP_GUI_MASTER_CNTL 0x146c
# define RADEON_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0)
# define RADEON_GMC_DST_PITCH_OFFSET_CNTL (1 << 1)
@@ -441,6 +444,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
# define RADEON_ROP3_S 0x00cc0000
# define RADEON_ROP3_P 0x00f00000
#define RADEON_DP_WRITE_MASK 0x16cc
+#define RADEON_SRC_PITCH_OFFSET 0x1428
#define RADEON_DST_PITCH_OFFSET 0x142c
#define RADEON_DST_PITCH_OFFSET_C 0x1c80
# define RADEON_DST_TILE_LINEAR (0 << 30)
@@ -545,6 +549,11 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
# define RADEON_RB3D_ZC_FREE (1 << 2)
# define RADEON_RB3D_ZC_FLUSH_ALL 0x5
# define RADEON_RB3D_ZC_BUSY (1 << 31)
+#define RADEON_RB3D_DSTCACHE_CTLSTAT 0x325c
+# define RADEON_RB3D_DC_FLUSH (3 << 0)
+# define RADEON_RB3D_DC_FREE (3 << 2)
+# define RADEON_RB3D_DC_FLUSH_ALL 0xf
+# define RADEON_RB3D_DC_BUSY (1 << 31)
#define RADEON_RB3D_ZSTENCILCNTL 0x1c2c
# define RADEON_Z_TEST_MASK (7 << 4)
# define RADEON_Z_TEST_ALWAYS (7 << 4)
@@ -681,6 +690,7 @@ extern int r300_do_cp_cmdbuf(drm_device_t * dev, DRMFILE filp,
#define RADEON_CP_RB_BASE 0x0700
#define RADEON_CP_RB_CNTL 0x0704
# define RADEON_BUF_SWAP_32BIT (2 << 16)
+# define RADEON_RB_NO_UPDATE (1 << 27)
#define RADEON_CP_RB_RPTR_ADDR 0x070c
#define RADEON_CP_RB_RPTR 0x0710
#define RADEON_CP_RB_WPTR 0x0714
@@ -986,13 +996,13 @@ do { \
} while (0)
#define RADEON_FLUSH_CACHE() do { \
- OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \
- OUT_RING( RADEON_RB2D_DC_FLUSH ); \
+ OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
+ OUT_RING( RADEON_RB3D_DC_FLUSH ); \
} while (0)
#define RADEON_PURGE_CACHE() do { \
- OUT_RING( CP_PACKET0( RADEON_RB2D_DSTCACHE_CTLSTAT, 0 ) ); \
- OUT_RING( RADEON_RB2D_DC_FLUSH_ALL ); \
+ OUT_RING( CP_PACKET0( RADEON_RB3D_DSTCACHE_CTLSTAT, 0 ) ); \
+ OUT_RING( RADEON_RB3D_DC_FLUSH_ALL ); \
} while (0)
#define RADEON_FLUSH_ZCACHE() do { \
diff --git a/drivers/char/drm/radeon_state.c b/drivers/char/drm/radeon_state.c
index 39a7f685e3fd..feac5f005d47 100644
--- a/drivers/char/drm/radeon_state.c
+++ b/drivers/char/drm/radeon_state.c
@@ -42,7 +42,11 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
drm_file_t * filp_priv,
u32 *offset)
{
- u32 off = *offset;
+ u64 off = *offset;
+ u32 fb_start = dev_priv->fb_location;
+ u32 fb_end = fb_start + dev_priv->fb_size - 1;
+ u32 gart_start = dev_priv->gart_vm_start;
+ u32 gart_end = gart_start + dev_priv->gart_size - 1;
struct drm_radeon_driver_file_fields *radeon_priv;
/* Hrm ... the story of the offset ... So this function converts
@@ -62,10 +66,8 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
/* First, the best case, the offset already lands in either the
* framebuffer or the GART mapped space
*/
- if ((off >= dev_priv->fb_location &&
- off < (dev_priv->fb_location + dev_priv->fb_size)) ||
- (off >= dev_priv->gart_vm_start &&
- off < (dev_priv->gart_vm_start + dev_priv->gart_size)))
+ if ((off >= fb_start && off <= fb_end) ||
+ (off >= gart_start && off <= gart_end))
return 0;
/* Ok, that didn't happen... now check if we have a zero based
@@ -78,16 +80,13 @@ static __inline__ int radeon_check_and_fixup_offset(drm_radeon_private_t *
}
/* Finally, assume we aimed at a GART offset if beyond the fb */
- if (off > (dev_priv->fb_location + dev_priv->fb_size))
- off = off - (dev_priv->fb_location + dev_priv->fb_size) +
- dev_priv->gart_vm_start;
+ if (off > fb_end)
+ off = off - fb_end - 1 + gart_start;
/* Now recheck and fail if out of bounds */
- if ((off >= dev_priv->fb_location &&
- off < (dev_priv->fb_location + dev_priv->fb_size)) ||
- (off >= dev_priv->gart_vm_start &&
- off < (dev_priv->gart_vm_start + dev_priv->gart_size))) {
- DRM_DEBUG("offset fixed up to 0x%x\n", off);
+ if ((off >= fb_start && off <= fb_end) ||
+ (off >= gart_start && off <= gart_end)) {
+ DRM_DEBUG("offset fixed up to 0x%x\n", (unsigned int)off);
*offset = off;
return 0;
}
@@ -869,7 +868,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
*/
dev_priv->sarea_priv->ctx_owner = 0;
- if ((dev_priv->flags & CHIP_HAS_HIERZ)
+ if ((dev_priv->flags & RADEON_HAS_HIERZ)
&& (flags & RADEON_USE_HIERZ)) {
/* FIXME : reverse engineer that for Rx00 cards */
/* FIXME : the mask supposedly contains low-res z values. So can't set
@@ -914,7 +913,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
for (i = 0; i < nbox; i++) {
int tileoffset, nrtilesx, nrtilesy, j;
/* it looks like r200 needs rv-style clears, at least if hierz is not enabled? */
- if ((dev_priv->flags & CHIP_HAS_HIERZ)
+ if ((dev_priv->flags & RADEON_HAS_HIERZ)
&& !(dev_priv->microcode_version == UCODE_R200)) {
/* FIXME : figure this out for r200 (when hierz is enabled). Or
maybe r200 actually doesn't need to put the low-res z value into
@@ -998,7 +997,7 @@ static void radeon_cp_dispatch_clear(drm_device_t * dev,
}
/* TODO don't always clear all hi-level z tiles */
- if ((dev_priv->flags & CHIP_HAS_HIERZ)
+ if ((dev_priv->flags & RADEON_HAS_HIERZ)
&& (dev_priv->microcode_version == UCODE_R200)
&& (flags & RADEON_USE_HIERZ))
/* r100 and cards without hierarchical z-buffer have no high-level z-buffer */
@@ -1270,9 +1269,9 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
DRM_DEBUG("dispatch swap %d,%d-%d,%d\n", x, y, w, h);
- BEGIN_RING(7);
+ BEGIN_RING(9);
- OUT_RING(CP_PACKET3(RADEON_CNTL_BITBLT_MULTI, 5));
+ OUT_RING(CP_PACKET0(RADEON_DP_GUI_MASTER_CNTL, 0));
OUT_RING(RADEON_GMC_SRC_PITCH_OFFSET_CNTL |
RADEON_GMC_DST_PITCH_OFFSET_CNTL |
RADEON_GMC_BRUSH_NONE |
@@ -1284,6 +1283,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
/* Make this work even if front & back are flipped:
*/
+ OUT_RING(CP_PACKET0(RADEON_SRC_PITCH_OFFSET, 1));
if (dev_priv->current_page == 0) {
OUT_RING(dev_priv->back_pitch_offset);
OUT_RING(dev_priv->front_pitch_offset);
@@ -1292,6 +1292,7 @@ static void radeon_cp_dispatch_swap(drm_device_t * dev)
OUT_RING(dev_priv->back_pitch_offset);
}
+ OUT_RING(CP_PACKET0(RADEON_SRC_X_Y, 2));
OUT_RING((x << 16) | y);
OUT_RING((x << 16) | y);
OUT_RING((w << 16) | h);
@@ -2987,16 +2988,21 @@ static int radeon_cp_getparam(DRM_IOCTL_ARGS)
case RADEON_PARAM_GART_TEX_HANDLE:
value = dev_priv->gart_textures_offset;
break;
-
+ case RADEON_PARAM_SCRATCH_OFFSET:
+ if (!dev_priv->writeback_works)
+ return DRM_ERR(EINVAL);
+ value = RADEON_SCRATCH_REG_OFFSET;
+ break;
case RADEON_PARAM_CARD_TYPE:
- if (dev_priv->flags & CHIP_IS_PCIE)
+ if (dev_priv->flags & RADEON_IS_PCIE)
value = RADEON_CARD_PCIE;
- else if (dev_priv->flags & CHIP_IS_AGP)
+ else if (dev_priv->flags & RADEON_IS_AGP)
value = RADEON_CARD_AGP;
else
value = RADEON_CARD_PCI;
break;
default:
+ DRM_DEBUG("Invalid parameter %d\n", param.param);
return DRM_ERR(EINVAL);
}
diff --git a/drivers/char/drm/sis_drv.c b/drivers/char/drm/sis_drv.c
index 5e9dc86f2956..3d5b3218b6ff 100644
--- a/drivers/char/drm/sis_drv.c
+++ b/drivers/char/drm/sis_drv.c
@@ -35,11 +35,44 @@ static struct pci_device_id pciidlist[] = {
sisdrv_PCI_IDS
};
+static int sis_driver_load(drm_device_t *dev, unsigned long chipset)
+{
+ drm_sis_private_t *dev_priv;
+ int ret;
+
+ dev_priv = drm_calloc(1, sizeof(drm_sis_private_t), DRM_MEM_DRIVER);
+ if (dev_priv == NULL)
+ return DRM_ERR(ENOMEM);
+
+ dev->dev_private = (void *)dev_priv;
+ dev_priv->chipset = chipset;
+ ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
+ if (ret) {
+ drm_free(dev_priv, sizeof(dev_priv), DRM_MEM_DRIVER);
+ }
+
+ return ret;
+}
+
+static int sis_driver_unload(drm_device_t *dev)
+{
+ drm_sis_private_t *dev_priv = dev->dev_private;
+
+ drm_sman_takedown(&dev_priv->sman);
+ drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+
+ return 0;
+}
+
static struct drm_driver driver = {
.driver_features = DRIVER_USE_AGP | DRIVER_USE_MTRR,
- .context_ctor = sis_init_context,
- .context_dtor = sis_final_context,
- .reclaim_buffers = drm_core_reclaim_buffers,
+ .load = sis_driver_load,
+ .unload = sis_driver_unload,
+ .context_dtor = NULL,
+ .dma_quiescent = sis_idle,
+ .reclaim_buffers = NULL,
+ .reclaim_buffers_locked = sis_reclaim_buffers_locked,
+ .lastclose = sis_lastclose,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = sis_ioctls,
diff --git a/drivers/char/drm/sis_drv.h b/drivers/char/drm/sis_drv.h
index e218e5269503..2b8d6f6ed7c0 100644
--- a/drivers/char/drm/sis_drv.h
+++ b/drivers/char/drm/sis_drv.h
@@ -31,23 +31,39 @@
/* General customization:
*/
-#define DRIVER_AUTHOR "SIS"
+#define DRIVER_AUTHOR "SIS, Tungsten Graphics"
#define DRIVER_NAME "sis"
#define DRIVER_DESC "SIS 300/630/540"
-#define DRIVER_DATE "20030826"
+#define DRIVER_DATE "20060704"
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 1
-#define DRIVER_PATCHLEVEL 0
+#define DRIVER_MINOR 2
+#define DRIVER_PATCHLEVEL 1
-#include "sis_ds.h"
+enum sis_family {
+ SIS_OTHER = 0,
+ SIS_CHIP_315 = 1,
+};
+
+#include "drm_sman.h"
+
+#define SIS_BASE (dev_priv->mmio)
+#define SIS_READ(reg) DRM_READ32(SIS_BASE, reg);
+#define SIS_WRITE(reg, val) DRM_WRITE32(SIS_BASE, reg, val);
typedef struct drm_sis_private {
- memHeap_t *AGPHeap;
- memHeap_t *FBHeap;
+ drm_local_map_t *mmio;
+ unsigned int idle_fault;
+ drm_sman_t sman;
+ unsigned int chipset;
+ int vram_initialized;
+ int agp_initialized;
+ unsigned long vram_offset;
+ unsigned long agp_offset;
} drm_sis_private_t;
-extern int sis_init_context(drm_device_t * dev, int context);
-extern int sis_final_context(drm_device_t * dev, int context);
+extern int sis_idle(drm_device_t *dev);
+extern void sis_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
+extern void sis_lastclose(drm_device_t *dev);
extern drm_ioctl_desc_t sis_ioctls[];
extern int sis_max_ioctl;
diff --git a/drivers/char/drm/sis_ds.c b/drivers/char/drm/sis_ds.c
deleted file mode 100644
index 2e485d482943..000000000000
--- a/drivers/char/drm/sis_ds.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/* sis_ds.c -- Private header for Direct Rendering Manager -*- linux-c -*-
- * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
- *
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Sung-Ching Lin <sclin@sis.com.tw>
- *
- */
-
-#include "drmP.h"
-#include "drm.h"
-#include "sis_ds.h"
-
-/* Set Data Structure, not check repeated value
- * temporarily used
- */
-
-set_t *setInit(void)
-{
- int i;
- set_t *set;
-
- set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
- if (set != NULL) {
- for (i = 0; i < SET_SIZE; i++) {
- set->list[i].free_next = i + 1;
- set->list[i].alloc_next = -1;
- }
- set->list[SET_SIZE - 1].free_next = -1;
- set->free = 0;
- set->alloc = -1;
- set->trace = -1;
- }
- return set;
-}
-
-int setAdd(set_t * set, ITEM_TYPE item)
-{
- int free = set->free;
-
- if (free != -1) {
- set->list[free].val = item;
- set->free = set->list[free].free_next;
- } else {
- return 0;
- }
-
- set->list[free].alloc_next = set->alloc;
- set->alloc = free;
- set->list[free].free_next = -1;
-
- return 1;
-}
-
-int setDel(set_t * set, ITEM_TYPE item)
-{
- int alloc = set->alloc;
- int prev = -1;
-
- while (alloc != -1) {
- if (set->list[alloc].val == item) {
- if (prev != -1)
- set->list[prev].alloc_next =
- set->list[alloc].alloc_next;
- else
- set->alloc = set->list[alloc].alloc_next;
- break;
- }
- prev = alloc;
- alloc = set->list[alloc].alloc_next;
- }
-
- if (alloc == -1)
- return 0;
-
- set->list[alloc].free_next = set->free;
- set->free = alloc;
- set->list[alloc].alloc_next = -1;
-
- return 1;
-}
-
-/* setFirst -> setAdd -> setNext is wrong */
-
-int setFirst(set_t * set, ITEM_TYPE * item)
-{
- if (set->alloc == -1)
- return 0;
-
- *item = set->list[set->alloc].val;
- set->trace = set->list[set->alloc].alloc_next;
-
- return 1;
-}
-
-int setNext(set_t * set, ITEM_TYPE * item)
-{
- if (set->trace == -1)
- return 0;
-
- *item = set->list[set->trace].val;
- set->trace = set->list[set->trace].alloc_next;
-
- return 1;
-}
-
-int setDestroy(set_t * set)
-{
- drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
-
- return 1;
-}
-
-/*
- * GLX Hardware Device Driver common code
- * Copyright (C) 1999 Wittawat Yamwong
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
- * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#define ISFREE(bptr) ((bptr)->free)
-
-memHeap_t *mmInit(int ofs, int size)
-{
- PMemBlock blocks;
-
- if (size <= 0)
- return NULL;
-
- blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
- if (blocks != NULL) {
- blocks->ofs = ofs;
- blocks->size = size;
- blocks->free = 1;
- return (memHeap_t *) blocks;
- } else
- return NULL;
-}
-
-/* Checks if a pointer 'b' is part of the heap 'heap' */
-int mmBlockInHeap(memHeap_t * heap, PMemBlock b)
-{
- TMemBlock *p;
-
- if (heap == NULL || b == NULL)
- return 0;
-
- p = heap;
- while (p != NULL && p != b) {
- p = p->next;
- }
- if (p == b)
- return 1;
- else
- return 0;
-}
-
-static TMemBlock *SliceBlock(TMemBlock * p,
- int startofs, int size,
- int reserved, int alignment)
-{
- TMemBlock *newblock;
-
- /* break left */
- if (startofs > p->ofs) {
- newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
- DRM_MEM_DRIVER);
- newblock->ofs = startofs;
- newblock->size = p->size - (startofs - p->ofs);
- newblock->free = 1;
- newblock->next = p->next;
- p->size -= newblock->size;
- p->next = newblock;
- p = newblock;
- }
-
- /* break right */
- if (size < p->size) {
- newblock = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
- DRM_MEM_DRIVER);
- newblock->ofs = startofs + size;
- newblock->size = p->size - size;
- newblock->free = 1;
- newblock->next = p->next;
- p->size = size;
- p->next = newblock;
- }
-
- /* p = middle block */
- p->align = alignment;
- p->free = 0;
- p->reserved = reserved;
- return p;
-}
-
-PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch)
-{
- int mask, startofs, endofs;
- TMemBlock *p;
-
- if (heap == NULL || align2 < 0 || size <= 0)
- return NULL;
-
- mask = (1 << align2) - 1;
- startofs = 0;
- p = (TMemBlock *) heap;
- while (p != NULL) {
- if (ISFREE(p)) {
- startofs = (p->ofs + mask) & ~mask;
- if (startofs < startSearch) {
- startofs = startSearch;
- }
- endofs = startofs + size;
- if (endofs <= (p->ofs + p->size))
- break;
- }
- p = p->next;
- }
- if (p == NULL)
- return NULL;
- p = SliceBlock(p, startofs, size, 0, mask + 1);
- p->heap = heap;
- return p;
-}
-
-static __inline__ int Join2Blocks(TMemBlock * p)
-{
- if (p->free && p->next && p->next->free) {
- TMemBlock *q = p->next;
- p->size += q->size;
- p->next = q->next;
- drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
- return 1;
- }
- return 0;
-}
-
-int mmFreeMem(PMemBlock b)
-{
- TMemBlock *p, *prev;
-
- if (b == NULL)
- return 0;
- if (b->heap == NULL)
- return -1;
-
- p = b->heap;
- prev = NULL;
- while (p != NULL && p != b) {
- prev = p;
- p = p->next;
- }
- if (p == NULL || p->free || p->reserved)
- return -1;
-
- p->free = 1;
- Join2Blocks(p);
- if (prev)
- Join2Blocks(prev);
- return 0;
-}
diff --git a/drivers/char/drm/sis_ds.h b/drivers/char/drm/sis_ds.h
deleted file mode 100644
index 94f2b4728b63..000000000000
--- a/drivers/char/drm/sis_ds.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/* sis_ds.h -- Private header for Direct Rendering Manager -*- linux-c -*-
- * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
- */
-/*
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- * Sung-Ching Lin <sclin@sis.com.tw>
- *
- */
-
-#ifndef __SIS_DS_H__
-#define __SIS_DS_H__
-
-/* Set Data Structure */
-
-#define SET_SIZE 5000
-
-typedef unsigned long ITEM_TYPE;
-
-typedef struct {
- ITEM_TYPE val;
- int alloc_next, free_next;
-} list_item_t;
-
-typedef struct {
- int alloc;
- int free;
- int trace;
- list_item_t list[SET_SIZE];
-} set_t;
-
-set_t *setInit(void);
-int setAdd(set_t * set, ITEM_TYPE item);
-int setDel(set_t * set, ITEM_TYPE item);
-int setFirst(set_t * set, ITEM_TYPE * item);
-int setNext(set_t * set, ITEM_TYPE * item);
-int setDestroy(set_t * set);
-
-/*
- * GLX Hardware Device Driver common code
- * Copyright (C) 1999 Wittawat Yamwong
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
- * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
- * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
- * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
- * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-struct mem_block_t {
- struct mem_block_t *next;
- struct mem_block_t *heap;
- int ofs, size;
- int align;
- unsigned int free:1;
- unsigned int reserved:1;
-};
-typedef struct mem_block_t TMemBlock;
-typedef struct mem_block_t *PMemBlock;
-
-/* a heap is just the first block in a chain */
-typedef struct mem_block_t memHeap_t;
-
-static __inline__ int mmBlockSize(PMemBlock b)
-{
- return b->size;
-}
-
-static __inline__ int mmOffset(PMemBlock b)
-{
- return b->ofs;
-}
-
-static __inline__ void mmMarkReserved(PMemBlock b)
-{
- b->reserved = 1;
-}
-
-/*
- * input: total size in bytes
- * return: a heap pointer if OK, NULL if error
- */
-memHeap_t *mmInit(int ofs, int size);
-
-/*
- * Allocate 'size' bytes with 2^align2 bytes alignment,
- * restrict the search to free memory after 'startSearch'
- * depth and back buffers should be in different 4mb banks
- * to get better page hits if possible
- * input: size = size of block
- * align2 = 2^align2 bytes alignment
- * startSearch = linear offset from start of heap to begin search
- * return: pointer to the allocated block, 0 if error
- */
-PMemBlock mmAllocMem(memHeap_t * heap, int size, int align2, int startSearch);
-
-/*
- * Returns 1 if the block 'b' is part of the heap 'heap'
- */
-int mmBlockInHeap(PMemBlock heap, PMemBlock b);
-
-/*
- * Free block starts at offset
- * input: pointer to a block
- * return: 0 if OK, -1 if error
- */
-int mmFreeMem(PMemBlock b);
-
-/* For debuging purpose. */
-void mmDumpMemInfo(memHeap_t * mmInit);
-
-#endif /* __SIS_DS_H__ */
diff --git a/drivers/char/drm/sis_mm.c b/drivers/char/drm/sis_mm.c
index 5e9936bc307f..d26f5dbb7853 100644
--- a/drivers/char/drm/sis_mm.c
+++ b/drivers/char/drm/sis_mm.c
@@ -1,414 +1,348 @@
-/* sis_mm.c -- Private header for Direct Rendering Manager -*- linux-c -*-
- * Created: Mon Jan 4 10:05:05 1999 by sclin@sis.com.tw
+/**************************************************************************
*
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
+ * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA.
+ * All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
*
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+ * USE OR OTHER DEALINGS IN THE SOFTWARE.
*
- * Authors:
- * Sung-Ching Lin <sclin@sis.com.tw>
*
+ **************************************************************************/
+
+/*
+ * Authors:
+ * Thomas Hellström <thomas-at-tungstengraphics-dot-com>
*/
#include "drmP.h"
#include "sis_drm.h"
#include "sis_drv.h"
-#include "sis_ds.h"
-#if defined(__linux__) && defined(CONFIG_FB_SIS)
+
#include <video/sisfb.h>
-#endif
-#define MAX_CONTEXT 100
#define VIDEO_TYPE 0
#define AGP_TYPE 1
-typedef struct {
- int used;
- int context;
- set_t *sets[2]; /* 0 for video, 1 for AGP */
-} sis_context_t;
-static sis_context_t global_ppriv[MAX_CONTEXT];
+#if defined(CONFIG_FB_SIS)
+/* fb management via fb device */
-static int add_alloc_set(int context, int type, unsigned int val)
-{
- int i, retval = 0;
+#define SIS_MM_ALIGN_SHIFT 0
+#define SIS_MM_ALIGN_MASK 0
- for (i = 0; i < MAX_CONTEXT; i++) {
- if (global_ppriv[i].used && global_ppriv[i].context == context) {
- retval = setAdd(global_ppriv[i].sets[type], val);
- break;
- }
- }
- return retval;
-}
-
-static int del_alloc_set(int context, int type, unsigned int val)
+static void *sis_sman_mm_allocate(void *private, unsigned long size,
+ unsigned alignment)
{
- int i, retval = 0;
+ struct sis_memreq req;
- for (i = 0; i < MAX_CONTEXT; i++) {
- if (global_ppriv[i].used && global_ppriv[i].context == context) {
- retval = setDel(global_ppriv[i].sets[type], val);
- break;
- }
- }
- return retval;
+ req.size = size;
+ sis_malloc(&req);
+ if (req.size == 0)
+ return NULL;
+ else
+ return (void *)~req.offset;
}
-/* fb management via fb device */
-#if defined(__linux__) && defined(CONFIG_FB_SIS)
-
-static int sis_fb_init(DRM_IOCTL_ARGS)
+static void sis_sman_mm_free(void *private, void *ref)
{
- return 0;
+ sis_free(~((unsigned long)ref));
}
-static int sis_fb_alloc(DRM_IOCTL_ARGS)
+static void sis_sman_mm_destroy(void *private)
{
- drm_sis_mem_t fb;
- struct sis_memreq req;
- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
- int retval = 0;
-
- DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
-
- req.size = fb.size;
- sis_malloc(&req);
- if (req.offset) {
- /* TODO */
- fb.offset = req.offset;
- fb.free = req.offset;
- if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
- DRM_DEBUG("adding to allocation set fails\n");
- sis_free(req.offset);
- retval = DRM_ERR(EINVAL);
- }
- } else {
- fb.offset = 0;
- fb.size = 0;
- fb.free = 0;
- }
-
- DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
-
- DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, req.offset);
-
- return retval;
+ ;
}
-static int sis_fb_free(DRM_IOCTL_ARGS)
+static unsigned long sis_sman_mm_offset(void *private, void *ref)
{
- drm_sis_mem_t fb;
- int retval = 0;
-
- DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
-
- if (!fb.free)
- return DRM_ERR(EINVAL);
+ return ~((unsigned long)ref);
+}
- if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
- retval = DRM_ERR(EINVAL);
- sis_free(fb.free);
+#else /* CONFIG_FB_SIS */
- DRM_DEBUG("free fb, offset = 0x%lx\n", fb.free);
+#define SIS_MM_ALIGN_SHIFT 4
+#define SIS_MM_ALIGN_MASK ( (1 << SIS_MM_ALIGN_SHIFT) - 1)
- return retval;
-}
+#endif /* CONFIG_FB_SIS */
-#else
-
-/* Called by the X Server to initialize the FB heap. Allocations will fail
- * unless this is called. Offset is the beginning of the heap from the
- * framebuffer offset (MaxXFBMem in XFree86).
- *
- * Memory layout according to Thomas Winischofer:
- * |------------------|DDDDDDDDDDDDDDDDDDDDDDDDDDDDD|HHHH|CCCCCCCCCCC|
- *
- * X driver/sisfb HW- Command-
- * framebuffer memory DRI heap Cursor queue
- */
static int sis_fb_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_fb_t fb;
+ int ret;
DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_fb_t __user *) data, sizeof(fb));
- if (dev_priv == NULL) {
- dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
- DRM_MEM_DRIVER);
- dev_priv = dev->dev_private;
- if (dev_priv == NULL)
- return ENOMEM;
+ mutex_lock(&dev->struct_mutex);
+#if defined(CONFIG_FB_SIS)
+ {
+ drm_sman_mm_t sman_mm;
+ sman_mm.private = (void *)0xFFFFFFFF;
+ sman_mm.allocate = sis_sman_mm_allocate;
+ sman_mm.free = sis_sman_mm_free;
+ sman_mm.destroy = sis_sman_mm_destroy;
+ sman_mm.offset = sis_sman_mm_offset;
+ ret =
+ drm_sman_set_manager(&dev_priv->sman, VIDEO_TYPE, &sman_mm);
}
+#else
+ ret = drm_sman_set_range(&dev_priv->sman, VIDEO_TYPE, 0,
+ fb.size >> SIS_MM_ALIGN_SHIFT);
+#endif
- if (dev_priv->FBHeap != NULL)
- return DRM_ERR(EINVAL);
+ if (ret) {
+ DRM_ERROR("VRAM memory manager initialisation error\n");
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
- dev_priv->FBHeap = mmInit(fb.offset, fb.size);
+ dev_priv->vram_initialized = 1;
+ dev_priv->vram_offset = fb.offset;
+ mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
return 0;
}
-static int sis_fb_alloc(DRM_IOCTL_ARGS)
+static int sis_drm_alloc(drm_device_t * dev, drm_file_t * priv,
+ unsigned long data, int pool)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
- drm_sis_mem_t fb;
- PMemBlock block;
+ drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *) data;
+ drm_sis_mem_t mem;
int retval = 0;
+ drm_memblock_item_t *item;
+
+ DRM_COPY_FROM_USER_IOCTL(mem, argp, sizeof(mem));
- if (dev_priv == NULL || dev_priv->FBHeap == NULL)
+ mutex_lock(&dev->struct_mutex);
+
+ if (0 == ((pool == 0) ? dev_priv->vram_initialized :
+ dev_priv->agp_initialized)) {
+ DRM_ERROR
+ ("Attempt to allocate from uninitialized memory manager.\n");
return DRM_ERR(EINVAL);
+ }
- DRM_COPY_FROM_USER_IOCTL(fb, argp, sizeof(fb));
-
- block = mmAllocMem(dev_priv->FBHeap, fb.size, 0, 0);
- if (block) {
- /* TODO */
- fb.offset = block->ofs;
- fb.free = (unsigned long)block;
- if (!add_alloc_set(fb.context, VIDEO_TYPE, fb.free)) {
- DRM_DEBUG("adding to allocation set fails\n");
- mmFreeMem((PMemBlock) fb.free);
- retval = DRM_ERR(EINVAL);
- }
+ mem.size = (mem.size + SIS_MM_ALIGN_MASK) >> SIS_MM_ALIGN_SHIFT;
+ item = drm_sman_alloc(&dev_priv->sman, pool, mem.size, 0,
+ (unsigned long)priv);
+
+ mutex_unlock(&dev->struct_mutex);
+ if (item) {
+ mem.offset = ((pool == 0) ?
+ dev_priv->vram_offset : dev_priv->agp_offset) +
+ (item->mm->
+ offset(item->mm, item->mm_info) << SIS_MM_ALIGN_SHIFT);
+ mem.free = item->user_hash.key;
+ mem.size = mem.size << SIS_MM_ALIGN_SHIFT;
} else {
- fb.offset = 0;
- fb.size = 0;
- fb.free = 0;
+ mem.offset = 0;
+ mem.size = 0;
+ mem.free = 0;
+ retval = DRM_ERR(ENOMEM);
}
- DRM_COPY_TO_USER_IOCTL(argp, fb, sizeof(fb));
+ DRM_COPY_TO_USER_IOCTL(argp, mem, sizeof(mem));
- DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size, fb.offset);
+ DRM_DEBUG("alloc %d, size = %d, offset = %d\n", pool, mem.size,
+ mem.offset);
return retval;
}
-static int sis_fb_free(DRM_IOCTL_ARGS)
+static int sis_drm_free(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t fb;
+ drm_sis_mem_t mem;
+ int ret;
- if (dev_priv == NULL || dev_priv->FBHeap == NULL)
- return DRM_ERR(EINVAL);
+ DRM_COPY_FROM_USER_IOCTL(mem, (drm_sis_mem_t __user *) data,
+ sizeof(mem));
- DRM_COPY_FROM_USER_IOCTL(fb, (drm_sis_mem_t __user *) data, sizeof(fb));
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_sman_free_key(&dev_priv->sman, mem.free);
+ mutex_unlock(&dev->struct_mutex);
+ DRM_DEBUG("free = 0x%lx\n", mem.free);
- if (!mmBlockInHeap(dev_priv->FBHeap, (PMemBlock) fb.free))
- return DRM_ERR(EINVAL);
-
- if (!del_alloc_set(fb.context, VIDEO_TYPE, fb.free))
- return DRM_ERR(EINVAL);
- mmFreeMem((PMemBlock) fb.free);
-
- DRM_DEBUG("free fb, free = 0x%lx\n", fb.free);
-
- return 0;
+ return ret;
}
-#endif
-
-/* agp memory management */
+static int sis_fb_alloc(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ return sis_drm_alloc(dev, priv, data, VIDEO_TYPE);
+}
static int sis_ioctl_agp_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
drm_sis_agp_t agp;
-
- if (dev_priv == NULL) {
- dev->dev_private = drm_calloc(1, sizeof(drm_sis_private_t),
- DRM_MEM_DRIVER);
- dev_priv = dev->dev_private;
- if (dev_priv == NULL)
- return ENOMEM;
- }
-
- if (dev_priv->AGPHeap != NULL)
- return DRM_ERR(EINVAL);
+ int ret;
+ dev_priv = dev->dev_private;
DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_agp_t __user *) data,
sizeof(agp));
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_sman_set_range(&dev_priv->sman, AGP_TYPE, 0,
+ agp.size >> SIS_MM_ALIGN_SHIFT);
+
+ if (ret) {
+ DRM_ERROR("AGP memory manager initialisation error\n");
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
- dev_priv->AGPHeap = mmInit(agp.offset, agp.size);
+ dev_priv->agp_initialized = 1;
+ dev_priv->agp_offset = agp.offset;
+ mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
-
return 0;
}
static int sis_ioctl_agp_alloc(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
- drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t __user *argp = (drm_sis_mem_t __user *)data;
- drm_sis_mem_t agp;
- PMemBlock block;
- int retval = 0;
- if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
- return DRM_ERR(EINVAL);
+ return sis_drm_alloc(dev, priv, data, AGP_TYPE);
+}
- DRM_COPY_FROM_USER_IOCTL(agp, argp, sizeof(agp));
-
- block = mmAllocMem(dev_priv->AGPHeap, agp.size, 0, 0);
- if (block) {
- /* TODO */
- agp.offset = block->ofs;
- agp.free = (unsigned long)block;
- if (!add_alloc_set(agp.context, AGP_TYPE, agp.free)) {
- DRM_DEBUG("adding to allocation set fails\n");
- mmFreeMem((PMemBlock) agp.free);
- retval = -1;
+static drm_local_map_t *sis_reg_init(drm_device_t *dev)
+{
+ drm_map_list_t *entry;
+ drm_local_map_t *map;
+
+ list_for_each_entry(entry, &dev->maplist->head, head) {
+ map = entry->map;
+ if (!map)
+ continue;
+ if (map->type == _DRM_REGISTERS) {
+ return map;
}
- } else {
- agp.offset = 0;
- agp.size = 0;
- agp.free = 0;
}
-
- DRM_COPY_TO_USER_IOCTL(argp, agp, sizeof(agp));
-
- DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size, agp.offset);
-
- return retval;
+ return NULL;
}
-static int sis_ioctl_agp_free(DRM_IOCTL_ARGS)
+int sis_idle(drm_device_t *dev)
{
- DRM_DEVICE;
drm_sis_private_t *dev_priv = dev->dev_private;
- drm_sis_mem_t agp;
-
- if (dev_priv == NULL || dev_priv->AGPHeap == NULL)
- return DRM_ERR(EINVAL);
+ uint32_t idle_reg;
+ unsigned long end;
+ int i;
- DRM_COPY_FROM_USER_IOCTL(agp, (drm_sis_mem_t __user *) data,
- sizeof(agp));
+ if (dev_priv->idle_fault)
+ return 0;
- if (!mmBlockInHeap(dev_priv->AGPHeap, (PMemBlock) agp.free))
- return DRM_ERR(EINVAL);
+ if (dev_priv->mmio == NULL) {
+ dev_priv->mmio = sis_reg_init(dev);
+ if (dev_priv->mmio == NULL) {
+ DRM_ERROR("Could not find register map.\n");
+ return 0;
+ }
+ }
+
+ /*
+ * Implement a device switch here if needed
+ */
+
+ if (dev_priv->chipset != SIS_CHIP_315)
+ return 0;
+
+ /*
+ * Timeout after 3 seconds. We cannot use DRM_WAIT_ON here
+ * because its polling frequency is too low.
+ */
+
+ end = jiffies + (DRM_HZ * 3);
+
+ for (i=0; i<4; ++i) {
+ do {
+ idle_reg = SIS_READ(0x85cc);
+ } while ( !time_after_eq(jiffies, end) &&
+ ((idle_reg & 0x80000000) != 0x80000000));
+ }
- mmFreeMem((PMemBlock) agp.free);
- if (!del_alloc_set(agp.context, AGP_TYPE, agp.free))
- return DRM_ERR(EINVAL);
+ if (time_after_eq(jiffies, end)) {
+ DRM_ERROR("Graphics engine idle timeout. "
+ "Disabling idle check\n");
+ dev_priv->idle_fault = 1;
+ }
- DRM_DEBUG("free agp, free = 0x%lx\n", agp.free);
+ /*
+ * The caller never sees an error code. It gets trapped
+ * in libdrm.
+ */
return 0;
}
-int sis_init_context(struct drm_device *dev, int context)
-{
- int i;
- for (i = 0; i < MAX_CONTEXT; i++) {
- if (global_ppriv[i].used &&
- (global_ppriv[i].context == context))
- break;
- }
+void sis_lastclose(struct drm_device *dev)
+{
+ drm_sis_private_t *dev_priv = dev->dev_private;
- if (i >= MAX_CONTEXT) {
- for (i = 0; i < MAX_CONTEXT; i++) {
- if (!global_ppriv[i].used) {
- global_ppriv[i].context = context;
- global_ppriv[i].used = 1;
- global_ppriv[i].sets[0] = setInit();
- global_ppriv[i].sets[1] = setInit();
- DRM_DEBUG("init allocation set, socket=%d, "
- "context = %d\n", i, context);
- break;
- }
- }
- if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
- (global_ppriv[i].sets[1] == NULL)) {
- return 0;
- }
- }
+ if (!dev_priv)
+ return;
- return 1;
+ mutex_lock(&dev->struct_mutex);
+ drm_sman_cleanup(&dev_priv->sman);
+ dev_priv->vram_initialized = 0;
+ dev_priv->agp_initialized = 0;
+ dev_priv->mmio = NULL;
+ mutex_unlock(&dev->struct_mutex);
}
-int sis_final_context(struct drm_device *dev, int context)
+void sis_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
{
- int i;
+ drm_sis_private_t *dev_priv = dev->dev_private;
+ drm_file_t *priv = filp->private_data;
- for (i = 0; i < MAX_CONTEXT; i++) {
- if (global_ppriv[i].used &&
- (global_ppriv[i].context == context))
- break;
+ mutex_lock(&dev->struct_mutex);
+ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+ mutex_unlock(&dev->struct_mutex);
+ return;
}
- if (i < MAX_CONTEXT) {
- set_t *set;
- ITEM_TYPE item;
- int retval;
-
- DRM_DEBUG("find socket %d, context = %d\n", i, context);
-
- /* Video Memory */
- set = global_ppriv[i].sets[0];
- retval = setFirst(set, &item);
- while (retval) {
- DRM_DEBUG("free video memory 0x%lx\n", item);
-#if defined(__linux__) && defined(CONFIG_FB_SIS)
- sis_free(item);
-#else
- mmFreeMem((PMemBlock) item);
-#endif
- retval = setNext(set, &item);
- }
- setDestroy(set);
-
- /* AGP Memory */
- set = global_ppriv[i].sets[1];
- retval = setFirst(set, &item);
- while (retval) {
- DRM_DEBUG("free agp memory 0x%lx\n", item);
- mmFreeMem((PMemBlock) item);
- retval = setNext(set, &item);
- }
- setDestroy(set);
-
- global_ppriv[i].used = 0;
+ if (dev->driver->dma_quiescent) {
+ dev->driver->dma_quiescent(dev);
}
- return 1;
+ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+ mutex_unlock(&dev->struct_mutex);
+ return;
}
drm_ioctl_desc_t sis_ioctls[] = {
[DRM_IOCTL_NR(DRM_SIS_FB_ALLOC)] = {sis_fb_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_fb_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] = {sis_ioctl_agp_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
+ [DRM_IOCTL_NR(DRM_SIS_FB_FREE)] = {sis_drm_free, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_SIS_AGP_INIT)] =
+ {sis_ioctl_agp_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY},
[DRM_IOCTL_NR(DRM_SIS_AGP_ALLOC)] = {sis_ioctl_agp_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_ioctl_agp_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] = {sis_fb_init, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}
+ [DRM_IOCTL_NR(DRM_SIS_AGP_FREE)] = {sis_drm_free, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_SIS_FB_INIT)] =
+ {sis_fb_init, DRM_AUTH | DRM_MASTER | DRM_ROOT_ONLY}
};
int sis_max_ioctl = DRM_ARRAY_SIZE(sis_ioctls);
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 78a81a4a99c5..60c1695db300 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -41,9 +41,9 @@
#include <linux/pagemap.h>
-#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
-#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
-#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
+#define VIA_PGDN(x) (((unsigned long)(x)) & PAGE_MASK)
+#define VIA_PGOFF(x) (((unsigned long)(x)) & ~PAGE_MASK)
+#define VIA_PFN(x) ((unsigned long)(x) >> PAGE_SHIFT)
typedef struct _drm_via_descriptor {
uint32_t mem_addr;
@@ -121,19 +121,19 @@ via_map_blit_for_device(struct pci_dev *pdev,
while (line_len > 0) {
- remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
+ remaining_len = min(PAGE_SIZE-VIA_PGOFF(cur_mem), line_len);
line_len -= remaining_len;
if (mode == 1) {
- desc_ptr->mem_addr =
+ desc_ptr->mem_addr =
dma_map_page(&pdev->dev,
vsg->pages[VIA_PFN(cur_mem) -
VIA_PFN(first_addr)],
VIA_PGOFF(cur_mem), remaining_len,
vsg->direction);
- desc_ptr->dev_addr = cur_fb;
+ desc_ptr->dev_addr = cur_fb;
- desc_ptr->size = remaining_len;
+ desc_ptr->size = remaining_len;
desc_ptr->next = (uint32_t) next;
next = dma_map_single(&pdev->dev, desc_ptr, sizeof(*desc_ptr),
DMA_TO_DEVICE);
@@ -162,7 +162,7 @@ via_map_blit_for_device(struct pci_dev *pdev,
/*
* Function that frees up all resources for a blit. It is usable even if the
- * blit info has only be partially built as long as the status enum is consistent
+ * blit info has only been partially built as long as the status enum is consistent
* with the actual status of the used resources.
*/
@@ -238,8 +238,11 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
return DRM_ERR(ENOMEM);
memset(vsg->pages, 0, sizeof(struct page *) * vsg->num_pages);
down_read(&current->mm->mmap_sem);
- ret = get_user_pages(current, current->mm, (unsigned long) xfer->mem_addr,
- vsg->num_pages, vsg->direction, 0, vsg->pages, NULL);
+ ret = get_user_pages(current, current->mm,
+ (unsigned long)xfer->mem_addr,
+ vsg->num_pages,
+ (vsg->direction == DMA_FROM_DEVICE),
+ 0, vsg->pages, NULL);
up_read(&current->mm->mmap_sem);
if (ret != vsg->num_pages) {
@@ -475,9 +478,15 @@ via_dmablit_timer(unsigned long data)
if (!timer_pending(&blitq->poll_timer)) {
blitq->poll_timer.expires = jiffies+1;
add_timer(&blitq->poll_timer);
- }
- via_dmablit_handler(dev, engine, 0);
+ /*
+ * Rerun handler to delete timer if engines are off, and
+ * to shorten abort latency. This is a little nasty.
+ */
+
+ via_dmablit_handler(dev, engine, 0);
+
+ }
}
@@ -597,15 +606,27 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *
* (Not a big limitation anyway.)
*/
- if (((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) ||
- (xfer->mem_stride > 2048*4)) {
+ if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) {
DRM_ERROR("Too large system memory stride. Stride: %d, "
"Length: %d\n", xfer->mem_stride, xfer->line_length);
return DRM_ERR(EINVAL);
}
- if (xfer->num_lines > 2048) {
- DRM_ERROR("Too many PCI DMA bitblt lines.\n");
+ if ((xfer->mem_stride == xfer->line_length) &&
+ (xfer->fb_stride == xfer->line_length)) {
+ xfer->mem_stride *= xfer->num_lines;
+ xfer->line_length = xfer->mem_stride;
+ xfer->fb_stride = xfer->mem_stride;
+ xfer->num_lines = 1;
+ }
+
+ /*
+ * Don't lock an arbitrary large number of pages, since that causes a
+ * DOS security hole.
+ */
+
+ if (xfer->num_lines > 2048 || (xfer->num_lines*xfer->mem_stride > (2048*2048*4))) {
+ DRM_ERROR("Too large PCI DMA bitblt.\n");
return DRM_ERR(EINVAL);
}
@@ -628,16 +649,17 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *
#ifdef VIA_BUGFREE
if ((((unsigned long)xfer->mem_addr & 3) != ((unsigned long)xfer->fb_addr & 3)) ||
- ((xfer->mem_stride & 3) != (xfer->fb_stride & 3))) {
+ ((xfer->num_lines > 1) && ((xfer->mem_stride & 3) != (xfer->fb_stride & 3)))) {
DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return DRM_ERR(EINVAL);
+ return DRM_ERR(EINVAL);
}
#else
if ((((unsigned long)xfer->mem_addr & 15) ||
- ((unsigned long)xfer->fb_addr & 3)) || (xfer->mem_stride & 15) ||
- (xfer->fb_stride & 3)) {
+ ((unsigned long)xfer->fb_addr & 3)) ||
+ ((xfer->num_lines > 1) &&
+ ((xfer->mem_stride & 15) || (xfer->fb_stride & 3)))) {
DRM_ERROR("Invalid DRM bitblt alignment.\n");
- return DRM_ERR(EINVAL);
+ return DRM_ERR(EINVAL);
}
#endif
@@ -715,7 +737,7 @@ via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer)
drm_via_private_t *dev_priv = (drm_via_private_t *)dev->dev_private;
drm_via_sg_info_t *vsg;
drm_via_blitq_t *blitq;
- int ret;
+ int ret;
int engine;
unsigned long irqsave;
@@ -756,7 +778,7 @@ via_dmablit(drm_device_t *dev, drm_via_dmablit_t *xfer)
/*
* Sync on a previously submitted blit. Note that the X server use signals extensively, and
- * that there is a very big proability that this IOCTL will be interrupted by a signal. In that
+ * that there is a very big probability that this IOCTL will be interrupted by a signal. In that
* case it returns with -EAGAIN for the signal to be delivered.
* The caller should then reissue the IOCTL. This is similar to what is being done for drmGetLock().
*/
diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h
index 47f0b5b26379..e4ee97d7156f 100644
--- a/drivers/char/drm/via_drm.h
+++ b/drivers/char/drm/via_drm.h
@@ -250,6 +250,12 @@ typedef struct drm_via_blitsync {
unsigned engine;
} drm_via_blitsync_t;
+/* - * Below,"flags" is currently unused but will be used for possible future
+ * extensions like kernel space bounce buffers for bad alignments and
+ * blit engine busy-wait polling for better latency in the absence of
+ * interrupts.
+ */
+
typedef struct drm_via_dmablit {
uint32_t num_lines;
uint32_t line_length;
@@ -260,7 +266,7 @@ typedef struct drm_via_dmablit {
unsigned char *mem_addr;
uint32_t mem_stride;
- int bounce_buffer;
+ uint32_t flags;
int to_fb;
drm_via_blitsync_t sync;
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
index b3d364d793d7..bb9dde8b1911 100644
--- a/drivers/char/drm/via_drv.c
+++ b/drivers/char/drm/via_drv.c
@@ -43,7 +43,6 @@ static struct drm_driver driver = {
DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
.load = via_driver_load,
.unload = via_driver_unload,
- .context_ctor = via_init_context,
.context_dtor = via_final_context,
.vblank_wait = via_driver_vblank_wait,
.irq_preinstall = via_driver_irq_preinstall,
@@ -53,6 +52,8 @@ static struct drm_driver driver = {
.dma_quiescent = via_driver_dma_quiescent,
.dri_library_name = dri_library_name,
.reclaim_buffers = drm_core_reclaim_buffers,
+ .reclaim_buffers_locked = via_reclaim_buffers_locked,
+ .lastclose = via_lastclose,
.get_map_ofs = drm_core_get_map_ofs,
.get_reg_ofs = drm_core_get_reg_ofs,
.ioctls = via_ioctls,
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index 52bcc7b1ba45..d21b5b75da0f 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -24,15 +24,16 @@
#ifndef _VIA_DRV_H_
#define _VIA_DRV_H_
+#include "drm_sman.h"
#define DRIVER_AUTHOR "Various"
#define DRIVER_NAME "via"
#define DRIVER_DESC "VIA Unichrome / Pro"
-#define DRIVER_DATE "20051116"
+#define DRIVER_DATE "20060529"
#define DRIVER_MAJOR 2
-#define DRIVER_MINOR 7
-#define DRIVER_PATCHLEVEL 4
+#define DRIVER_MINOR 10
+#define DRIVER_PATCHLEVEL 0
#include "via_verifier.h"
@@ -85,6 +86,12 @@ typedef struct drm_via_private {
uint32_t irq_enable_mask;
uint32_t irq_pending_mask;
int *irq_map;
+ unsigned int idle_fault;
+ drm_sman_t sman;
+ int vram_initialized;
+ int agp_initialized;
+ unsigned long vram_offset;
+ unsigned long agp_offset;
drm_via_blitq_t blit_queues[VIA_NUM_BLIT_ENGINES];
} drm_via_private_t;
@@ -135,6 +142,9 @@ extern void via_init_futex(drm_via_private_t * dev_priv);
extern void via_cleanup_futex(drm_via_private_t * dev_priv);
extern void via_release_futex(drm_via_private_t * dev_priv, int context);
+extern void via_reclaim_buffers_locked(drm_device_t *dev, struct file *filp);
+extern void via_lastclose(drm_device_t *dev);
+
extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
extern void via_init_dmablit(drm_device_t *dev);
diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c
deleted file mode 100644
index 9429736b3b96..000000000000
--- a/drivers/char/drm/via_ds.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#include "drmP.h"
-
-#include "via_ds.h"
-extern unsigned int VIA_DEBUG;
-
-set_t *via_setInit(void)
-{
- int i;
- set_t *set;
- set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
- for (i = 0; i < SET_SIZE; i++) {
- set->list[i].free_next = i + 1;
- set->list[i].alloc_next = -1;
- }
- set->list[SET_SIZE - 1].free_next = -1;
- set->free = 0;
- set->alloc = -1;
- set->trace = -1;
- return set;
-}
-
-int via_setAdd(set_t * set, ITEM_TYPE item)
-{
- int free = set->free;
- if (free != -1) {
- set->list[free].val = item;
- set->free = set->list[free].free_next;
- } else {
- return 0;
- }
- set->list[free].alloc_next = set->alloc;
- set->alloc = free;
- set->list[free].free_next = -1;
- return 1;
-}
-
-int via_setDel(set_t * set, ITEM_TYPE item)
-{
- int alloc = set->alloc;
- int prev = -1;
-
- while (alloc != -1) {
- if (set->list[alloc].val == item) {
- if (prev != -1)
- set->list[prev].alloc_next =
- set->list[alloc].alloc_next;
- else
- set->alloc = set->list[alloc].alloc_next;
- break;
- }
- prev = alloc;
- alloc = set->list[alloc].alloc_next;
- }
-
- if (alloc == -1)
- return 0;
-
- set->list[alloc].free_next = set->free;
- set->free = alloc;
- set->list[alloc].alloc_next = -1;
-
- return 1;
-}
-
-/* setFirst -> setAdd -> setNext is wrong */
-
-int via_setFirst(set_t * set, ITEM_TYPE * item)
-{
- if (set->alloc == -1)
- return 0;
-
- *item = set->list[set->alloc].val;
- set->trace = set->list[set->alloc].alloc_next;
-
- return 1;
-}
-
-int via_setNext(set_t * set, ITEM_TYPE * item)
-{
- if (set->trace == -1)
- return 0;
-
- *item = set->list[set->trace].val;
- set->trace = set->list[set->trace].alloc_next;
-
- return 1;
-}
-
-int via_setDestroy(set_t * set)
-{
- drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
-
- return 1;
-}
-
-#define ISFREE(bptr) ((bptr)->free)
-
-#define fprintf(fmt, arg...) do{}while(0)
-
-memHeap_t *via_mmInit(int ofs, int size)
-{
- PMemBlock blocks;
-
- if (size <= 0)
- return NULL;
-
- blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
-
- if (blocks) {
- blocks->ofs = ofs;
- blocks->size = size;
- blocks->free = 1;
- return (memHeap_t *) blocks;
- } else
- return NULL;
-}
-
-static TMemBlock *SliceBlock(TMemBlock * p,
- int startofs, int size,
- int reserved, int alignment)
-{
- TMemBlock *newblock;
-
- /* break left */
- if (startofs > p->ofs) {
- newblock =
- (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
- DRM_MEM_DRIVER);
- newblock->ofs = startofs;
- newblock->size = p->size - (startofs - p->ofs);
- newblock->free = 1;
- newblock->next = p->next;
- p->size -= newblock->size;
- p->next = newblock;
- p = newblock;
- }
-
- /* break right */
- if (size < p->size) {
- newblock =
- (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
- DRM_MEM_DRIVER);
- newblock->ofs = startofs + size;
- newblock->size = p->size - size;
- newblock->free = 1;
- newblock->next = p->next;
- p->size = size;
- p->next = newblock;
- }
-
- /* p = middle block */
- p->align = alignment;
- p->free = 0;
- p->reserved = reserved;
- return p;
-}
-
-PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
- int startSearch)
-{
- int mask, startofs, endofs;
- TMemBlock *p;
-
- if (!heap || align2 < 0 || size <= 0)
- return NULL;
-
- mask = (1 << align2) - 1;
- startofs = 0;
- p = (TMemBlock *) heap;
-
- while (p) {
- if (ISFREE(p)) {
- startofs = (p->ofs + mask) & ~mask;
-
- if (startofs < startSearch)
- startofs = startSearch;
-
- endofs = startofs + size;
-
- if (endofs <= (p->ofs + p->size))
- break;
- }
-
- p = p->next;
- }
-
- if (!p)
- return NULL;
-
- p = SliceBlock(p, startofs, size, 0, mask + 1);
- p->heap = heap;
-
- return p;
-}
-
-static __inline__ int Join2Blocks(TMemBlock * p)
-{
- if (p->free && p->next && p->next->free) {
- TMemBlock *q = p->next;
- p->size += q->size;
- p->next = q->next;
- drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
-
- return 1;
- }
-
- return 0;
-}
-
-int via_mmFreeMem(PMemBlock b)
-{
- TMemBlock *p, *prev;
-
- if (!b)
- return 0;
-
- if (!b->heap) {
- fprintf(stderr, "no heap\n");
-
- return -1;
- }
-
- p = b->heap;
- prev = NULL;
-
- while (p && p != b) {
- prev = p;
- p = p->next;
- }
-
- if (!p || p->free || p->reserved) {
- if (!p)
- fprintf(stderr, "block not found in heap\n");
- else if (p->free)
- fprintf(stderr, "block already free\n");
- else
- fprintf(stderr, "block is reserved\n");
-
- return -1;
- }
-
- p->free = 1;
- Join2Blocks(p);
-
- if (prev)
- Join2Blocks(prev);
-
- return 0;
-}
diff --git a/drivers/char/drm/via_ds.h b/drivers/char/drm/via_ds.h
deleted file mode 100644
index d2bb9f37ca38..000000000000
--- a/drivers/char/drm/via_ds.h
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
- * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
- * All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sub license,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial portions
- * of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-#ifndef _via_ds_h_
-#define _via_ds_h_
-
-#include "drmP.h"
-
-/* Set Data Structure */
-#define SET_SIZE 5000
-typedef unsigned long ITEM_TYPE;
-
-typedef struct {
- ITEM_TYPE val;
- int alloc_next, free_next;
-} list_item_t;
-
-typedef struct {
- int alloc;
- int free;
- int trace;
- list_item_t list[SET_SIZE];
-} set_t;
-
-set_t *via_setInit(void);
-int via_setAdd(set_t * set, ITEM_TYPE item);
-int via_setDel(set_t * set, ITEM_TYPE item);
-int via_setFirst(set_t * set, ITEM_TYPE * item);
-int via_setNext(set_t * set, ITEM_TYPE * item);
-int via_setDestroy(set_t * set);
-
-#endif
-
-#ifndef MM_INC
-#define MM_INC
-
-struct mem_block_t {
- struct mem_block_t *next;
- struct mem_block_t *heap;
- int ofs, size;
- int align;
- unsigned int free:1;
- unsigned int reserved:1;
-};
-typedef struct mem_block_t TMemBlock;
-typedef struct mem_block_t *PMemBlock;
-
-/* a heap is just the first block in a chain */
-typedef struct mem_block_t memHeap_t;
-
-static __inline__ int mmBlockSize(PMemBlock b)
-{
- return b->size;
-}
-
-static __inline__ int mmOffset(PMemBlock b)
-{
- return b->ofs;
-}
-
-static __inline__ void mmMarkReserved(PMemBlock b)
-{
- b->reserved = 1;
-}
-
-/*
- * input: total size in bytes
- * return: a heap pointer if OK, NULL if error
- */
-memHeap_t *via_mmInit(int ofs, int size);
-
-PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
- int startSearch);
-
-/*
- * Free block starts at offset
- * input: pointer to a block
- * return: 0 if OK, -1 if error
- */
-int via_mmFreeMem(PMemBlock b);
-
-#endif
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
index c6a08e96285b..782011e0a58d 100644
--- a/drivers/char/drm/via_map.c
+++ b/drivers/char/drm/via_map.c
@@ -98,6 +98,7 @@ int via_map_init(DRM_IOCTL_ARGS)
int via_driver_load(drm_device_t *dev, unsigned long chipset)
{
drm_via_private_t *dev_priv;
+ int ret = 0;
dev_priv = drm_calloc(1, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
if (dev_priv == NULL)
@@ -108,13 +109,19 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
if (chipset == VIA_PRO_GROUP_A)
dev_priv->pro_group_a = 1;
- return 0;
+ ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
+ if (ret) {
+ drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER);
+ }
+ return ret;
}
int via_driver_unload(drm_device_t *dev)
{
drm_via_private_t *dev_priv = dev->dev_private;
+ drm_sman_takedown(&dev_priv->sman);
+
drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
return 0;
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
index 33e0cb12e4c3..2fcf0577a7aa 100644
--- a/drivers/char/drm/via_mm.c
+++ b/drivers/char/drm/via_mm.c
@@ -1,6 +1,6 @@
/*
- * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
- * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2006 Tungsten Graphics Inc., Bismarck, ND., USA.
+ * All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -16,347 +16,194 @@
* 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 NON-INFRINGEMENT. IN NO EVENT SHALL
- * VIA, S3 GRAPHICS, AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * THE AUTHORS OR COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
+/*
+ * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com>
+ */
+
#include "drmP.h"
#include "via_drm.h"
#include "via_drv.h"
-#include "via_ds.h"
-#include "via_mm.h"
-
-#define MAX_CONTEXT 100
-
-typedef struct {
- int used;
- int context;
- set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System */
-} via_context_t;
-
-static via_context_t global_ppriv[MAX_CONTEXT];
+#include "drm_sman.h"
-static int via_agp_alloc(drm_via_mem_t * mem);
-static int via_agp_free(drm_via_mem_t * mem);
-static int via_fb_alloc(drm_via_mem_t * mem);
-static int via_fb_free(drm_via_mem_t * mem);
-
-static int add_alloc_set(int context, int type, unsigned long val)
-{
- int i, retval = 0;
-
- for (i = 0; i < MAX_CONTEXT; i++) {
- if (global_ppriv[i].used && global_ppriv[i].context == context) {
- retval = via_setAdd(global_ppriv[i].sets[type], val);
- break;
- }
- }
-
- return retval;
-}
-
-static int del_alloc_set(int context, int type, unsigned long val)
-{
- int i, retval = 0;
-
- for (i = 0; i < MAX_CONTEXT; i++)
- if (global_ppriv[i].used && global_ppriv[i].context == context) {
- retval = via_setDel(global_ppriv[i].sets[type], val);
- break;
- }
-
- return retval;
-}
-
-/* agp memory management */
-static memHeap_t *AgpHeap = NULL;
+#define VIA_MM_ALIGN_SHIFT 4
+#define VIA_MM_ALIGN_MASK ( (1 << VIA_MM_ALIGN_SHIFT) - 1)
int via_agp_init(DRM_IOCTL_ARGS)
{
+ DRM_DEVICE;
drm_via_agp_t agp;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ int ret;
DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t __user *) data,
sizeof(agp));
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_AGP, 0,
+ agp.size >> VIA_MM_ALIGN_SHIFT);
+
+ if (ret) {
+ DRM_ERROR("AGP memory manager initialisation error\n");
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
- AgpHeap = via_mmInit(agp.offset, agp.size);
-
- DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset,
- (unsigned long)agp.size);
+ dev_priv->agp_initialized = 1;
+ dev_priv->agp_offset = agp.offset;
+ mutex_unlock(&dev->struct_mutex);
+ DRM_DEBUG("offset = %u, size = %u", agp.offset, agp.size);
return 0;
}
-/* fb memory management */
-static memHeap_t *FBHeap = NULL;
-
int via_fb_init(DRM_IOCTL_ARGS)
{
+ DRM_DEVICE;
drm_via_fb_t fb;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ int ret;
DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t __user *) data, sizeof(fb));
- FBHeap = via_mmInit(fb.offset, fb.size);
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_sman_set_range(&dev_priv->sman, VIA_MEM_VIDEO, 0,
+ fb.size >> VIA_MM_ALIGN_SHIFT);
- DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset,
- (unsigned long)fb.size);
+ if (ret) {
+ DRM_ERROR("VRAM memory manager initialisation error\n");
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
+ }
- return 0;
-}
+ dev_priv->vram_initialized = 1;
+ dev_priv->vram_offset = fb.offset;
-int via_init_context(struct drm_device *dev, int context)
-{
- int i;
-
- for (i = 0; i < MAX_CONTEXT; i++)
- if (global_ppriv[i].used &&
- (global_ppriv[i].context == context))
- break;
-
- if (i >= MAX_CONTEXT) {
- for (i = 0; i < MAX_CONTEXT; i++) {
- if (!global_ppriv[i].used) {
- global_ppriv[i].context = context;
- global_ppriv[i].used = 1;
- global_ppriv[i].sets[0] = via_setInit();
- global_ppriv[i].sets[1] = via_setInit();
- DRM_DEBUG("init allocation set, socket=%d,"
- " context = %d\n", i, context);
- break;
- }
- }
-
- if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
- (global_ppriv[i].sets[1] == NULL)) {
- return 0;
- }
- }
+ mutex_unlock(&dev->struct_mutex);
+ DRM_DEBUG("offset = %u, size = %u", fb.offset, fb.size);
+
+ return 0;
- return 1;
}
int via_final_context(struct drm_device *dev, int context)
{
- int i;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- for (i = 0; i < MAX_CONTEXT; i++)
- if (global_ppriv[i].used &&
- (global_ppriv[i].context == context))
- break;
-
- if (i < MAX_CONTEXT) {
- set_t *set;
- ITEM_TYPE item;
- int retval;
-
- DRM_DEBUG("find socket %d, context = %d\n", i, context);
-
- /* Video Memory */
- set = global_ppriv[i].sets[0];
- retval = via_setFirst(set, &item);
- while (retval) {
- DRM_DEBUG("free video memory 0x%lx\n", item);
- via_mmFreeMem((PMemBlock) item);
- retval = via_setNext(set, &item);
- }
- via_setDestroy(set);
-
- /* AGP Memory */
- set = global_ppriv[i].sets[1];
- retval = via_setFirst(set, &item);
- while (retval) {
- DRM_DEBUG("free agp memory 0x%lx\n", item);
- via_mmFreeMem((PMemBlock) item);
- retval = via_setNext(set, &item);
- }
- via_setDestroy(set);
- global_ppriv[i].used = 0;
- }
via_release_futex(dev_priv, context);
-#if defined(__linux__)
/* Linux specific until context tracking code gets ported to BSD */
/* Last context, perform cleanup */
if (dev->ctx_count == 1 && dev->dev_private) {
DRM_DEBUG("Last Context\n");
if (dev->irq)
drm_irq_uninstall(dev);
-
via_cleanup_futex(dev_priv);
via_do_cleanup_map(dev);
}
-#endif
-
return 1;
}
+void via_lastclose(struct drm_device *dev)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+
+ if (!dev_priv)
+ return;
+
+ mutex_lock(&dev->struct_mutex);
+ drm_sman_cleanup(&dev_priv->sman);
+ dev_priv->vram_initialized = 0;
+ dev_priv->agp_initialized = 0;
+ mutex_unlock(&dev->struct_mutex);
+}
+
int via_mem_alloc(DRM_IOCTL_ARGS)
{
+ DRM_DEVICE;
+
drm_via_mem_t mem;
+ int retval = 0;
+ drm_memblock_item_t *item;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ unsigned long tmpSize;
DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
sizeof(mem));
- switch (mem.type) {
- case VIA_MEM_VIDEO:
- if (via_fb_alloc(&mem) < 0)
- return -EFAULT;
- DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
- sizeof(mem));
- return 0;
- case VIA_MEM_AGP:
- if (via_agp_alloc(&mem) < 0)
- return -EFAULT;
- DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem,
- sizeof(mem));
- return 0;
+ if (mem.type > VIA_MEM_AGP) {
+ DRM_ERROR("Unknown memory type allocation\n");
+ return DRM_ERR(EINVAL);
}
-
- return -EFAULT;
-}
-
-static int via_fb_alloc(drm_via_mem_t * mem)
-{
- drm_via_mm_t fb;
- PMemBlock block;
- int retval = 0;
-
- if (!FBHeap)
- return -1;
-
- fb.size = mem->size;
- fb.context = mem->context;
-
- block = via_mmAllocMem(FBHeap, fb.size, 5, 0);
- if (block) {
- fb.offset = block->ofs;
- fb.free = (unsigned long)block;
- if (!add_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) {
- DRM_DEBUG("adding to allocation set fails\n");
- via_mmFreeMem((PMemBlock) fb.free);
- retval = -1;
- }
- } else {
- fb.offset = 0;
- fb.size = 0;
- fb.free = 0;
- retval = -1;
+ mutex_lock(&dev->struct_mutex);
+ if (0 == ((mem.type == VIA_MEM_VIDEO) ? dev_priv->vram_initialized :
+ dev_priv->agp_initialized)) {
+ DRM_ERROR
+ ("Attempt to allocate from uninitialized memory manager.\n");
+ mutex_unlock(&dev->struct_mutex);
+ return DRM_ERR(EINVAL);
}
- mem->offset = fb.offset;
- mem->index = fb.free;
-
- DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size,
- (int)fb.offset);
-
- return retval;
-}
-
-static int via_agp_alloc(drm_via_mem_t * mem)
-{
- drm_via_mm_t agp;
- PMemBlock block;
- int retval = 0;
-
- if (!AgpHeap)
- return -1;
-
- agp.size = mem->size;
- agp.context = mem->context;
-
- block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);
- if (block) {
- agp.offset = block->ofs;
- agp.free = (unsigned long)block;
- if (!add_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) {
- DRM_DEBUG("adding to allocation set fails\n");
- via_mmFreeMem((PMemBlock) agp.free);
- retval = -1;
- }
+ tmpSize = (mem.size + VIA_MM_ALIGN_MASK) >> VIA_MM_ALIGN_SHIFT;
+ item = drm_sman_alloc(&dev_priv->sman, mem.type, tmpSize, 0,
+ (unsigned long)priv);
+ mutex_unlock(&dev->struct_mutex);
+ if (item) {
+ mem.offset = ((mem.type == VIA_MEM_VIDEO) ?
+ dev_priv->vram_offset : dev_priv->agp_offset) +
+ (item->mm->
+ offset(item->mm, item->mm_info) << VIA_MM_ALIGN_SHIFT);
+ mem.index = item->user_hash.key;
} else {
- agp.offset = 0;
- agp.size = 0;
- agp.free = 0;
+ mem.offset = 0;
+ mem.size = 0;
+ mem.index = 0;
+ DRM_DEBUG("Video memory allocation failed\n");
+ retval = DRM_ERR(ENOMEM);
}
+ DRM_COPY_TO_USER_IOCTL((drm_via_mem_t __user *) data, mem, sizeof(mem));
- mem->offset = agp.offset;
- mem->index = agp.free;
-
- DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size,
- (unsigned int)agp.offset);
return retval;
}
int via_mem_free(DRM_IOCTL_ARGS)
{
+ DRM_DEVICE;
+ drm_via_private_t *dev_priv = dev->dev_private;
drm_via_mem_t mem;
+ int ret;
DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t __user *) data,
sizeof(mem));
- switch (mem.type) {
+ mutex_lock(&dev->struct_mutex);
+ ret = drm_sman_free_key(&dev_priv->sman, mem.index);
+ mutex_unlock(&dev->struct_mutex);
+ DRM_DEBUG("free = 0x%lx\n", mem.index);
- case VIA_MEM_VIDEO:
- if (via_fb_free(&mem) == 0)
- return 0;
- break;
- case VIA_MEM_AGP:
- if (via_agp_free(&mem) == 0)
- return 0;
- break;
- }
-
- return -EFAULT;
+ return ret;
}
-static int via_fb_free(drm_via_mem_t * mem)
-{
- drm_via_mm_t fb;
- int retval = 0;
-
- if (!FBHeap) {
- return -1;
- }
-
- fb.free = mem->index;
- fb.context = mem->context;
-
- if (!fb.free) {
- return -1;
-
- }
-
- via_mmFreeMem((PMemBlock) fb.free);
-
- if (!del_alloc_set(fb.context, VIA_MEM_VIDEO, fb.free)) {
- retval = -1;
- }
-
- DRM_DEBUG("free fb, free = %ld\n", fb.free);
- return retval;
-}
-
-static int via_agp_free(drm_via_mem_t * mem)
+void via_reclaim_buffers_locked(drm_device_t * dev, struct file *filp)
{
- drm_via_mm_t agp;
-
- int retval = 0;
+ drm_via_private_t *dev_priv = dev->dev_private;
+ drm_file_t *priv = filp->private_data;
- agp.free = mem->index;
- agp.context = mem->context;
-
- if (!agp.free)
- return -1;
-
- via_mmFreeMem((PMemBlock) agp.free);
-
- if (!del_alloc_set(agp.context, VIA_MEM_AGP, agp.free)) {
- retval = -1;
+ mutex_lock(&dev->struct_mutex);
+ if (drm_sman_owner_clean(&dev_priv->sman, (unsigned long)priv)) {
+ mutex_unlock(&dev->struct_mutex);
+ return;
}
- DRM_DEBUG("free agp, free = %ld\n", agp.free);
+ if (dev->driver->dma_quiescent) {
+ dev->driver->dma_quiescent(dev);
+ }
- return retval;
+ drm_sman_owner_cleanup(&dev_priv->sman, (unsigned long)priv);
+ mutex_unlock(&dev->struct_mutex);
+ return;
}
diff --git a/drivers/char/ds1286.c b/drivers/char/ds1286.c
index 21c8229f5443..6d58b0370802 100644
--- a/drivers/char/ds1286.c
+++ b/drivers/char/ds1286.c
@@ -104,7 +104,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case RTC_AIE_OFF: /* Mask alarm int. enab. bit */
{
- unsigned int flags;
+ unsigned long flags;
unsigned char val;
if (!capable(CAP_SYS_TIME))
@@ -120,7 +120,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
}
case RTC_AIE_ON: /* Allow alarm interrupts. */
{
- unsigned int flags;
+ unsigned long flags;
unsigned char val;
if (!capable(CAP_SYS_TIME))
@@ -136,7 +136,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
}
case RTC_WIE_OFF: /* Mask watchdog int. enab. bit */
{
- unsigned int flags;
+ unsigned long flags;
unsigned char val;
if (!capable(CAP_SYS_TIME))
@@ -152,7 +152,7 @@ static int ds1286_ioctl(struct inode *inode, struct file *file,
}
case RTC_WIE_ON: /* Allow watchdog interrupts. */
{
- unsigned int flags;
+ unsigned long flags;
unsigned char val;
if (!capable(CAP_SYS_TIME))
@@ -434,7 +434,7 @@ static inline unsigned char ds1286_is_updating(void)
static void ds1286_get_time(struct rtc_time *rtc_tm)
{
unsigned char save_control;
- unsigned int flags;
+ unsigned long flags;
unsigned long uip_watchdog = jiffies;
/*
@@ -494,7 +494,8 @@ static int ds1286_set_time(struct rtc_time *rtc_tm)
{
unsigned char mon, day, hrs, min, sec, leap_yr;
unsigned char save_control;
- unsigned int yrs, flags;
+ unsigned int yrs;
+ unsigned long flags;
yrs = rtc_tm->tm_year + 1900;
@@ -552,7 +553,7 @@ static int ds1286_set_time(struct rtc_time *rtc_tm)
static void ds1286_get_alm_time(struct rtc_time *alm_tm)
{
unsigned char cmd;
- unsigned int flags;
+ unsigned long flags;
/*
* Only the values that we read from the RTC are set. That
diff --git a/drivers/char/ec3104_keyb.c b/drivers/char/ec3104_keyb.c
index abac18b1871c..77f58ed6d59a 100644
--- a/drivers/char/ec3104_keyb.c
+++ b/drivers/char/ec3104_keyb.c
@@ -370,7 +370,7 @@ static void e5_receive(struct e5_struct *k)
}
}
-static void ec3104_keyb_interrupt(int irq, void *data, struct pt_regs *regs)
+static void ec3104_keyb_interrupt(int irq, void *data)
{
struct e5_struct *k = &ec3104_keyb;
u8 msr, lsr;
diff --git a/drivers/char/epca.c b/drivers/char/epca.c
index 86d290e9f307..706733c0b36a 100644
--- a/drivers/char/epca.c
+++ b/drivers/char/epca.c
@@ -1113,11 +1113,8 @@ static void __exit epca_module_exit(void)
ch = card_ptr[crd];
for (count = 0; count < bd->numports; count++, ch++)
{ /* Begin for each port */
- if (ch) {
- if (ch->tty)
- tty_hangup(ch->tty);
- kfree(ch->tmp_buf);
- }
+ if (ch && ch->tty)
+ tty_hangup(ch->tty);
} /* End for each port */
} /* End for each card */
pci_unregister_driver (&epca_driver);
@@ -1125,7 +1122,7 @@ static void __exit epca_module_exit(void)
module_exit(epca_module_exit);
-static struct tty_operations pc_ops = {
+static const struct tty_operations pc_ops = {
.open = pc_open,
.close = pc_close,
.write = pc_write,
@@ -1160,6 +1157,7 @@ static int __init pc_init(void)
int crd;
struct board_info *bd;
unsigned char board_id = 0;
+ int err = -ENOMEM;
int pci_boards_found, pci_count;
@@ -1167,13 +1165,11 @@ static int __init pc_init(void)
pc_driver = alloc_tty_driver(MAX_ALLOC);
if (!pc_driver)
- return -ENOMEM;
+ goto out1;
pc_info = alloc_tty_driver(MAX_ALLOC);
- if (!pc_info) {
- put_tty_driver(pc_driver);
- return -ENOMEM;
- }
+ if (!pc_info)
+ goto out2;
/* -----------------------------------------------------------------------
If epca_setup has not been ran by LILO set num_cards to defaults; copy
@@ -1373,11 +1369,17 @@ static int __init pc_init(void)
} /* End for each card */
- if (tty_register_driver(pc_driver))
- panic("Couldn't register Digi PC/ driver");
+ err = tty_register_driver(pc_driver);
+ if (err) {
+ printk(KERN_ERR "Couldn't register Digi PC/ driver");
+ goto out3;
+ }
- if (tty_register_driver(pc_info))
- panic("Couldn't register Digi PC/ info ");
+ err = tty_register_driver(pc_info);
+ if (err) {
+ printk(KERN_ERR "Couldn't register Digi PC/ info ");
+ goto out4;
+ }
/* -------------------------------------------------------------------
Start up the poller to check for events on all enabled boards
@@ -1388,6 +1390,15 @@ static int __init pc_init(void)
mod_timer(&epca_timer, jiffies + HZ/25);
return 0;
+out4:
+ tty_unregister_driver(pc_driver);
+out3:
+ put_tty_driver(pc_info);
+out2:
+ put_tty_driver(pc_driver);
+out1:
+ return err;
+
} /* End pc_init */
/* ------------------ Begin post_fep_init ---------------------- */
@@ -1635,16 +1646,6 @@ static void post_fep_init(unsigned int crd)
init_waitqueue_head(&ch->close_wait);
spin_unlock_irqrestore(&epca_lock, flags);
-
- ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);
- if (!ch->tmp_buf) {
- printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);
- release_region((int)bd->port, 4);
- while(i-- > 0)
- kfree((ch--)->tmp_buf);
- return;
- } else
- memset((void *)ch->tmp_buf,0,ch->txbufsize);
} /* End for each port */
printk(KERN_INFO
diff --git a/drivers/char/epca.h b/drivers/char/epca.h
index 456d6c8f94a8..a297238cd3ba 100644
--- a/drivers/char/epca.h
+++ b/drivers/char/epca.h
@@ -130,7 +130,6 @@ struct channel
unsigned long c_oflag;
unsigned char __iomem *txptr;
unsigned char __iomem *rxptr;
- unsigned char *tmp_buf;
struct board_info *board;
struct board_chan __iomem *brdchan;
struct digi_struct digiext;
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index afcd83d9984b..15a4ea896328 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -615,8 +615,7 @@ static inline void check_modem_status(struct esp_struct *info)
/*
* This is the serial driver's interrupt routine
*/
-static irqreturn_t rs_interrupt_single(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t rs_interrupt_single(int irq, void *dev_id)
{
struct esp_struct * info;
unsigned err_status;
@@ -2376,7 +2375,7 @@ static inline int autoconfig(struct esp_struct * info)
return (port_detected);
}
-static struct tty_operations esp_ops = {
+static const struct tty_operations esp_ops = {
.open = esp_open,
.close = rs_close,
.write = rs_write,
diff --git a/drivers/char/ftape/lowlevel/fdc-io.c b/drivers/char/ftape/lowlevel/fdc-io.c
index 65c9d2ec60bd..bbcf918f056f 100644
--- a/drivers/char/ftape/lowlevel/fdc-io.c
+++ b/drivers/char/ftape/lowlevel/fdc-io.c
@@ -26,7 +26,6 @@
* Linux.
*/
-#include <linux/config.h> /* for CONFIG_FT_* */
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/ioport.h>
@@ -1244,7 +1243,7 @@ static int fdc_config(void)
TRACE_EXIT 0;
}
-static irqreturn_t ftape_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ftape_interrupt(int irq, void *dev_id)
{
void (*handler) (void) = *fdc.hook;
int handled = 0;
diff --git a/drivers/char/ftape/zftape/zftape-rw.c b/drivers/char/ftape/zftape/zftape-rw.c
index a61ef50f3dfc..dab634686885 100644
--- a/drivers/char/ftape/zftape/zftape-rw.c
+++ b/drivers/char/ftape/zftape/zftape-rw.c
@@ -24,7 +24,6 @@
* zftape.
*/
-#include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */
#include <linux/errno.h>
#include <linux/mm.h>
diff --git a/drivers/char/ftape/zftape/zftape-rw.h b/drivers/char/ftape/zftape/zftape-rw.h
index 14c07f086575..1ceec22b60bd 100644
--- a/drivers/char/ftape/zftape/zftape-rw.h
+++ b/drivers/char/ftape/zftape/zftape-rw.h
@@ -28,7 +28,6 @@
*
*/
-#include <linux/config.h> /* for CONFIG_ZFT_DFLT_BLK_SZ */
#include "../zftape/zftape-buffers.h"
#define SEGMENTS_PER_TAPE (ft_segments_per_track * ft_tracks_per_tape)
diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c
index 5e59c0b42731..87127e49c0db 100644
--- a/drivers/char/generic_serial.c
+++ b/drivers/char/generic_serial.c
@@ -33,8 +33,6 @@
#define DEBUG
-static char * tmp_buf;
-
static int gs_debug;
#ifdef DEBUG
@@ -205,7 +203,7 @@ int gs_write(struct tty_struct * tty,
if (!tty) return -EIO;
port = tty->driver_data;
- if (!port || !port->xmit_buf || !tmp_buf)
+ if (!port || !port->xmit_buf)
return -EIO;
local_save_flags(flags);
@@ -746,11 +744,9 @@ void gs_set_termios (struct tty_struct * tty,
gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp);
}
-#if 0
/* This is an optimization that is only allowed for dumb cards */
/* Smart cards require knowledge of iflags and oflags too: that
might change hardware cooking mode.... */
-#endif
if (old_termios) {
if( (tiosp->c_iflag == old_termios->c_iflag)
&& (tiosp->c_oflag == old_termios->c_oflag)
@@ -774,14 +770,7 @@ void gs_set_termios (struct tty_struct * tty,
if(!memcmp(tiosp->c_cc, old_termios->c_cc, NCC)) printk("c_cc changed\n");
}
- baudrate = tiosp->c_cflag & CBAUD;
- if (baudrate & CBAUDEX) {
- baudrate &= ~CBAUDEX;
- if ((baudrate < 1) || (baudrate > 4))
- tiosp->c_cflag &= ~CBAUDEX;
- else
- baudrate += 15;
- }
+ baudrate = tty_get_baud_rate(tty);
baudrate = gs_baudrates[baudrate];
if ((tiosp->c_cflag & CBAUD) == B38400) {
@@ -846,24 +835,9 @@ void gs_set_termios (struct tty_struct * tty,
int gs_init_port(struct gs_port *port)
{
unsigned long flags;
- unsigned long page;
func_enter ();
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- spin_lock_irqsave (&port->driver_lock, flags); /* Don't expect this to make a difference. */
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- spin_unlock_irqrestore (&port->driver_lock, flags);
- if (!tmp_buf) {
- func_exit ();
- return -ENOMEM;
- }
- }
-
if (port->flags & ASYNC_INITIALIZED) {
func_exit ();
return 0;
diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c
index d69f2ad9a67d..1aa93a752a9c 100644
--- a/drivers/char/hangcheck-timer.c
+++ b/drivers/char/hangcheck-timer.c
@@ -159,7 +159,7 @@ static void hangcheck_fire(unsigned long data)
if (hangcheck_dump_tasks) {
printk(KERN_CRIT "Hangcheck: Task state:\n");
#ifdef CONFIG_MAGIC_SYSRQ
- handle_sysrq('t', NULL, NULL);
+ handle_sysrq('t', NULL);
#endif /* CONFIG_MAGIC_SYSRQ */
}
if (hangcheck_reboot) {
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 58b0eb581114..091a11cd878c 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -116,7 +116,7 @@ static inline void writeq(unsigned long long v, void __iomem *addr)
}
#endif
-static irqreturn_t hpet_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t hpet_interrupt(int irq, void *data)
{
struct hpet_dev *devp;
unsigned long isr;
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index a76d2c40dd5e..9902ffad3b12 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -294,7 +294,7 @@ static int hvc_poll(struct hvc_struct *hp);
* NOTE: This API isn't used if the console adapter doesn't support interrupts.
* In this case the console is poll driven.
*/
-static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
{
/* if hvc_poll request a repoll, then kick the hvcd thread */
if (hvc_poll(dev_instance))
@@ -621,7 +621,7 @@ static int hvc_poll(struct hvc_struct *hp)
sysrq_pressed = 1;
continue;
} else if (sysrq_pressed) {
- handle_sysrq(buf[i], NULL, tty);
+ handle_sysrq(buf[i], tty);
sysrq_pressed = 0;
continue;
}
@@ -696,7 +696,7 @@ int khvcd(void *unused)
return 0;
}
-static struct tty_operations hvc_ops = {
+static const struct tty_operations hvc_ops = {
.open = hvc_open,
.close = hvc_close,
.write = hvc_write,
diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c
index 4747729459c7..f144a947bd17 100644
--- a/drivers/char/hvc_iseries.c
+++ b/drivers/char/hvc_iseries.c
@@ -29,6 +29,7 @@
#include <asm/hvconsole.h>
#include <asm/vio.h>
#include <asm/prom.h>
+#include <asm/firmware.h>
#include <asm/iseries/vio.h>
#include <asm/iseries/hv_call.h>
#include <asm/iseries/hv_lp_config.h>
@@ -153,9 +154,7 @@ static int put_chars(uint32_t vtermno, const char *buf, int count)
spin_lock_irqsave(&consolelock, flags);
if (viochar_is_console(pi) && !viopath_isactive(pi->lp)) {
- spin_lock_irqsave(&consoleloglock, flags);
HvCall_writeLogBuffer(buf, count);
- spin_unlock_irqrestore(&consoleloglock, flags);
sent = count;
goto done;
}
@@ -171,11 +170,8 @@ static int put_chars(uint32_t vtermno, const char *buf, int count)
len = (count > VIOCHAR_MAX_DATA) ? VIOCHAR_MAX_DATA : count;
- if (viochar_is_console(pi)) {
- spin_lock_irqsave(&consoleloglock, flags);
+ if (viochar_is_console(pi))
HvCall_writeLogBuffer(buf, len);
- spin_unlock_irqrestore(&consoleloglock, flags);
- }
init_data_event(viochar, pi->lp);
@@ -493,6 +489,9 @@ static int hvc_vio_init(void)
atomic_t wait_flag;
int rc;
+ if (!firmware_has_feature(FW_FEATURE_ISERIES))
+ return -EIO;
+
/* +2 for fudge */
rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
@@ -567,7 +566,7 @@ static int hvc_find_vtys(void)
for (vty = of_find_node_by_name(NULL, "vty"); vty != NULL;
vty = of_find_node_by_name(vty, "vty")) {
- uint32_t *vtermno;
+ const uint32_t *vtermno;
/* We have statically defined space for only a certain number
* of console adapters.
@@ -576,7 +575,7 @@ static int hvc_find_vtys(void)
(num_found >= VTTY_PORTS))
break;
- vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+ vtermno = get_property(vty, "reg", NULL);
if (!vtermno)
continue;
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
index cc95941148fb..f9c00844d2bf 100644
--- a/drivers/char/hvc_vio.c
+++ b/drivers/char/hvc_vio.c
@@ -35,6 +35,7 @@
#include <asm/hvconsole.h>
#include <asm/vio.h>
#include <asm/prom.h>
+#include <asm/firmware.h>
#include "hvc_console.h"
@@ -120,6 +121,9 @@ static int hvc_vio_init(void)
{
int rc;
+ if (firmware_has_feature(FW_FEATURE_ISERIES))
+ return -EIO;
+
/* Register as a vio device to receive callbacks */
rc = vio_register_driver(&hvc_vio_driver);
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index 4589ff302b07..8728255c9463 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -313,8 +313,7 @@ static DEFINE_SPINLOCK(hvcs_structs_lock);
static void hvcs_unthrottle(struct tty_struct *tty);
static void hvcs_throttle(struct tty_struct *tty);
-static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance);
static int hvcs_write(struct tty_struct *tty,
const unsigned char *buf, int count);
@@ -387,8 +386,7 @@ static void hvcs_throttle(struct tty_struct *tty)
* handler taking any further interrupts because they are disabled which means
* the hvcs_struct will always be valid in this handler.
*/
-static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t hvcs_handle_interrupt(int irq, void *dev_instance)
{
struct hvcs_struct *hvcsd = dev_instance;
@@ -1306,7 +1304,7 @@ static int hvcs_chars_in_buffer(struct tty_struct *tty)
return hvcsd->chars_in_buffer;
}
-static struct tty_operations hvcs_ops = {
+static const struct tty_operations hvcs_ops = {
.open = hvcs_open,
.close = hvcs_close,
.hangup = hvcs_hangup,
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index a89a95fb5e40..2cf63e7305a3 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -406,7 +406,7 @@ static void hvsi_insert_chars(struct hvsi_struct *hp, const char *buf, int len)
hp->sysrq = 1;
continue;
} else if (hp->sysrq) {
- handle_sysrq(c, NULL, hp->tty);
+ handle_sysrq(c, hp->tty);
hp->sysrq = 0;
continue;
}
@@ -555,7 +555,7 @@ static void hvsi_send_overflow(struct hvsi_struct *hp)
* must get all pending data because we only get an irq on empty->non-empty
* transition
*/
-static irqreturn_t hvsi_interrupt(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t hvsi_interrupt(int irq, void *arg)
{
struct hvsi_struct *hp = (struct hvsi_struct *)arg;
struct tty_struct *flip;
@@ -616,7 +616,7 @@ static int __init poll_for_state(struct hvsi_struct *hp, int state)
unsigned long end_jiffies = jiffies + HVSI_TIMEOUT;
for (;;) {
- hvsi_interrupt(hp->virq, (void *)hp, NULL); /* get pending data */
+ hvsi_interrupt(hp->virq, (void *)hp); /* get pending data */
if (hp->state == state)
return 0;
@@ -1130,7 +1130,7 @@ static int hvsi_tiocmset(struct tty_struct *tty, struct file *file,
}
-static struct tty_operations hvsi_ops = {
+static const struct tty_operations hvsi_ops = {
.open = hvsi_open,
.close = hvsi_close,
.write = hvsi_write,
diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c
index ccd7e7102234..8efbc9c0e545 100644
--- a/drivers/char/hw_random/intel-rng.c
+++ b/drivers/char/hw_random/intel-rng.c
@@ -50,6 +50,43 @@
#define INTEL_RNG_ADDR_LEN 3
/*
+ * LPC bridge PCI config space registers
+ */
+#define FWH_DEC_EN1_REG_OLD 0xe3
+#define FWH_DEC_EN1_REG_NEW 0xd9 /* high byte of 16-bit register */
+#define FWH_F8_EN_MASK 0x80
+
+#define BIOS_CNTL_REG_OLD 0x4e
+#define BIOS_CNTL_REG_NEW 0xdc
+#define BIOS_CNTL_WRITE_ENABLE_MASK 0x01
+#define BIOS_CNTL_LOCK_ENABLE_MASK 0x02
+
+/*
+ * Magic address at which Intel Firmware Hubs get accessed
+ */
+#define INTEL_FWH_ADDR 0xffff0000
+#define INTEL_FWH_ADDR_LEN 2
+
+/*
+ * Intel Firmware Hub command codes (write to any address inside the device)
+ */
+#define INTEL_FWH_RESET_CMD 0xff /* aka READ_ARRAY */
+#define INTEL_FWH_READ_ID_CMD 0x90
+
+/*
+ * Intel Firmware Hub Read ID command result addresses
+ */
+#define INTEL_FWH_MANUFACTURER_CODE_ADDRESS 0x000000
+#define INTEL_FWH_DEVICE_CODE_ADDRESS 0x000001
+
+/*
+ * Intel Firmware Hub Read ID command result values
+ */
+#define INTEL_FWH_MANUFACTURER_CODE 0x89
+#define INTEL_FWH_DEVICE_CODE_8M 0xac
+#define INTEL_FWH_DEVICE_CODE_4M 0xad
+
+/*
* Data for PCI driver interface
*
* This data only exists for exporting the supported
@@ -58,12 +95,50 @@
* want to register another driver on the same PCI id.
*/
static const struct pci_device_id pci_tbl[] = {
- { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
+/* AA
+ { 0x8086, 0x2418, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AA */
+/* AB
+ { 0x8086, 0x2428, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2420, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* AB */
+/* ??
+ { 0x8086, 0x2430, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+/* BAM, CAM, DBM, FBM, GxM
+ { 0x8086, 0x2448, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x244c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BAM */
+ { 0x8086, 0x248c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CAM */
+ { 0x8086, 0x24cc, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DBM */
+ { 0x8086, 0x2641, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* FBM */
+ { 0x8086, 0x27b9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM */
+ { 0x8086, 0x27bd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* GxM DH */
+/* BA, CA, DB, Ex, 6300, Fx, 631x/632x, Gx
+ { 0x8086, 0x244e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2440, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* BA */
+ { 0x8086, 0x2480, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CA */
+ { 0x8086, 0x24c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* DB */
+ { 0x8086, 0x24d0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ex */
+ { 0x8086, 0x25a1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 6300 */
+ { 0x8086, 0x2640, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Fx */
+ { 0x8086, 0x2670, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2671, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2672, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2673, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2674, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2675, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2676, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2677, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2678, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x2679, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x267f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* 631x/632x */
+ { 0x8086, 0x27b8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Gx */
+/* E
+ { 0x8086, 0x245e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, */
+ { 0x8086, 0x2450, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* E */
{ 0, }, /* terminate list */
};
MODULE_DEVICE_TABLE(pci, pci_tbl);
@@ -138,22 +213,115 @@ static struct hwrng intel_rng = {
};
+#ifdef CONFIG_SMP
+static char __initdata waitflag;
+
+static void __init intel_init_wait(void *unused)
+{
+ while (waitflag)
+ cpu_relax();
+}
+#endif
+
static int __init mod_init(void)
{
int err = -ENODEV;
+ unsigned i;
+ struct pci_dev *dev = NULL;
void __iomem *mem;
- u8 hw_status;
+ unsigned long flags;
+ u8 bios_cntl_off, fwh_dec_en1_off;
+ u8 bios_cntl_val = 0xff, fwh_dec_en1_val = 0xff;
+ u8 hw_status, mfc, dvc;
- if (!pci_dev_present(pci_tbl))
+ for (i = 0; !dev && pci_tbl[i].vendor; ++i)
+ dev = pci_get_device(pci_tbl[i].vendor, pci_tbl[i].device, NULL);
+
+ if (!dev)
goto out; /* Device not found. */
+ /* Check for Intel 82802 */
+ if (dev->device < 0x2640) {
+ fwh_dec_en1_off = FWH_DEC_EN1_REG_OLD;
+ bios_cntl_off = BIOS_CNTL_REG_OLD;
+ } else {
+ fwh_dec_en1_off = FWH_DEC_EN1_REG_NEW;
+ bios_cntl_off = BIOS_CNTL_REG_NEW;
+ }
+
+ pci_read_config_byte(dev, fwh_dec_en1_off, &fwh_dec_en1_val);
+ pci_read_config_byte(dev, bios_cntl_off, &bios_cntl_val);
+
+ mem = ioremap_nocache(INTEL_FWH_ADDR, INTEL_FWH_ADDR_LEN);
+ if (mem == NULL) {
+ pci_dev_put(dev);
+ err = -EBUSY;
+ goto out;
+ }
+
+ /*
+ * Since the BIOS code/data is going to disappear from its normal
+ * location with the Read ID command, all activity on the system
+ * must be stopped until the state is back to normal.
+ */
+#ifdef CONFIG_SMP
+ set_mb(waitflag, 1);
+ if (smp_call_function(intel_init_wait, NULL, 1, 0) != 0) {
+ set_mb(waitflag, 0);
+ pci_dev_put(dev);
+ printk(KERN_ERR PFX "cannot run on all processors\n");
+ err = -EAGAIN;
+ goto err_unmap;
+ }
+#endif
+ local_irq_save(flags);
+
+ if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(dev,
+ fwh_dec_en1_off,
+ fwh_dec_en1_val | FWH_F8_EN_MASK);
+ if (!(bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+ pci_write_config_byte(dev,
+ bios_cntl_off,
+ bios_cntl_val | BIOS_CNTL_WRITE_ENABLE_MASK);
+
+ writeb(INTEL_FWH_RESET_CMD, mem);
+ writeb(INTEL_FWH_READ_ID_CMD, mem);
+ mfc = readb(mem + INTEL_FWH_MANUFACTURER_CODE_ADDRESS);
+ dvc = readb(mem + INTEL_FWH_DEVICE_CODE_ADDRESS);
+ writeb(INTEL_FWH_RESET_CMD, mem);
+
+ if (!(bios_cntl_val &
+ (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)))
+ pci_write_config_byte(dev, bios_cntl_off, bios_cntl_val);
+ if (!(fwh_dec_en1_val & FWH_F8_EN_MASK))
+ pci_write_config_byte(dev, fwh_dec_en1_off, fwh_dec_en1_val);
+
+ local_irq_restore(flags);
+#ifdef CONFIG_SMP
+ /* Tell other CPUs to resume. */
+ set_mb(waitflag, 0);
+#endif
+
+ iounmap(mem);
+ pci_dev_put(dev);
+
+ if (mfc != INTEL_FWH_MANUFACTURER_CODE ||
+ (dvc != INTEL_FWH_DEVICE_CODE_8M &&
+ dvc != INTEL_FWH_DEVICE_CODE_4M)) {
+ printk(KERN_ERR PFX "FWH not detected\n");
+ err = -ENODEV;
+ goto out;
+ }
+
err = -ENOMEM;
mem = ioremap(INTEL_RNG_ADDR, INTEL_RNG_ADDR_LEN);
if (!mem)
goto out;
intel_rng.priv = (unsigned long)mem;
- /* Check for Intel 82802 */
+ /* Check for Random Number Generator */
err = -ENODEV;
hw_status = hwstatus_get(mem);
if ((hw_status & INTEL_RNG_PRESENT) == 0)
diff --git a/drivers/char/hw_random/ixp4xx-rng.c b/drivers/char/hw_random/ixp4xx-rng.c
index ef71022423c9..c9caff57db85 100644
--- a/drivers/char/hw_random/ixp4xx-rng.c
+++ b/drivers/char/hw_random/ixp4xx-rng.c
@@ -1,5 +1,5 @@
/*
- * drivers/char/rng/ixp4xx-rng.c
+ * drivers/char/hw_random/ixp4xx-rng.c
*
* RNG driver for Intel IXP4xx family of NPUs
*
@@ -15,7 +15,6 @@
*/
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c
index a01d796d1eeb..e13dd1892bfd 100644
--- a/drivers/char/hw_random/omap-rng.c
+++ b/drivers/char/hw_random/omap-rng.c
@@ -1,5 +1,5 @@
/*
- * driver/char/hw_random/omap-rng.c
+ * drivers/char/hw_random/omap-rng.c
*
* RNG driver for TI OMAP CPU family
*
diff --git a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c
index fc944d375be7..54d93f0345e8 100644
--- a/drivers/char/ip2/i2lib.c
+++ b/drivers/char/ip2/i2lib.c
@@ -1007,7 +1007,7 @@ i2InputAvailable(i2ChanStrPtr pCh)
// applications that one cannot break out of.
//******************************************************************************
static int
-i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user )
+i2Output(i2ChanStrPtr pCh, const char *pSource, int count)
{
i2eBordStrPtr pB;
unsigned char *pInsert;
@@ -1020,7 +1020,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user )
int bailout = 10;
- ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, user );
+ ip2trace (CHANN, ITRC_OUTPUT, ITRC_ENTER, 2, count, 0 );
// Ensure channel structure seems real
if ( !i2Validate ( pCh ) )
@@ -1087,12 +1087,7 @@ i2Output(i2ChanStrPtr pCh, const char *pSource, int count, int user )
DATA_COUNT_OF(pInsert) = amountToMove;
// Move the data
- if ( user ) {
- rc = copy_from_user((char*)(DATA_OF(pInsert)), pSource,
- amountToMove );
- } else {
- memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );
- }
+ memcpy( (char*)(DATA_OF(pInsert)), pSource, amountToMove );
// Adjust pointers and indices
pSource += amountToMove;
pCh->Obuf_char_count += amountToMove;
diff --git a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h
index 952e113ccd8a..e559e9bac06d 100644
--- a/drivers/char/ip2/i2lib.h
+++ b/drivers/char/ip2/i2lib.h
@@ -332,7 +332,7 @@ static int i2QueueCommands(int, i2ChanStrPtr, int, int, cmdSyntaxPtr,...);
static int i2GetStatus(i2ChanStrPtr, int);
static int i2Input(i2ChanStrPtr);
static int i2InputFlush(i2ChanStrPtr);
-static int i2Output(i2ChanStrPtr, const char *, int, int);
+static int i2Output(i2ChanStrPtr, const char *, int);
static int i2OutputFree(i2ChanStrPtr);
static int i2ServiceBoard(i2eBordStrPtr);
static void i2DrainOutput(i2ChanStrPtr, int);
diff --git a/drivers/char/ip2/ip2main.c b/drivers/char/ip2/ip2main.c
index 7907ae88c2f4..a3f32d46d2f8 100644
--- a/drivers/char/ip2/ip2main.c
+++ b/drivers/char/ip2/ip2main.c
@@ -190,7 +190,7 @@ static int ip2_tiocmset(struct tty_struct *tty, struct file *file,
static void set_irq(int, int);
static void ip2_interrupt_bh(i2eBordStrPtr pB);
-static irqreturn_t ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t ip2_interrupt(int irq, void *dev_id);
static void ip2_poll(unsigned long arg);
static inline void service_all_boards(void);
static void do_input(void *p);
@@ -436,6 +436,7 @@ cleanup_module(void)
#ifdef CONFIG_PCI
if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) {
pci_disable_device(ip2config.pci_dev[i]);
+ pci_dev_put(ip2config.pci_dev[i]);
ip2config.pci_dev[i] = NULL;
}
#endif
@@ -457,7 +458,7 @@ cleanup_module(void)
}
#endif /* MODULE */
-static struct tty_operations ip2_ops = {
+static const struct tty_operations ip2_ops = {
.open = ip2_open,
.close = ip2_close,
.write = ip2_write,
@@ -505,6 +506,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
static int loaded;
i2eBordStrPtr pB = NULL;
int rc = -1;
+ static struct pci_dev *pci_dev_i = NULL;
ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_ENTER, 0 );
@@ -588,8 +590,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
case PCI:
#ifdef CONFIG_PCI
{
- struct pci_dev *pci_dev_i = NULL;
- pci_dev_i = pci_find_device(PCI_VENDOR_ID_COMPUTONE,
+ pci_dev_i = pci_get_device(PCI_VENDOR_ID_COMPUTONE,
PCI_DEVICE_ID_COMPUTONE_IP2EX, pci_dev_i);
if (pci_dev_i != NULL) {
unsigned int addr;
@@ -600,7 +601,7 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
break;
}
ip2config.type[i] = PCI;
- ip2config.pci_dev[i] = pci_dev_i;
+ ip2config.pci_dev[i] = pci_dev_get(pci_dev_i);
status =
pci_read_config_dword(pci_dev_i, PCI_BASE_ADDRESS_1, &addr);
if ( addr & 1 ) {
@@ -641,6 +642,9 @@ ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize)
break;
} /* switch */
} /* for */
+ if (pci_dev_i)
+ pci_dev_put(pci_dev_i);
+
for ( i = 0; i < IP2_MAX_BOARDS; ++i ) {
if ( ip2config.addr[i] ) {
pB = kmalloc( sizeof(i2eBordStr), GFP_KERNEL);
@@ -775,8 +779,6 @@ retry:
ip2trace (ITRC_NO_PORT, ITRC_INIT, ITRC_RETURN, 0 );
goto out;
-out_class:
- class_destroy(ip2_class);
out_chrdev:
unregister_chrdev(IP2_IPL_MAJOR, "ip2");
out:
@@ -1152,10 +1154,9 @@ ip2_interrupt_bh(i2eBordStrPtr pB)
/******************************************************************************/
-/* Function: ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs) */
+/* Function: ip2_interrupt(int irq, void *dev_id) */
/* Parameters: irq - interrupt number */
/* pointer to optional device ID structure */
-/* pointer to register structure */
/* Returns: Nothing */
/* */
/* Description: */
@@ -1171,7 +1172,7 @@ ip2_interrupt_bh(i2eBordStrPtr pB)
/* */
/******************************************************************************/
static irqreturn_t
-ip2_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+ip2_interrupt(int irq, void *dev_id)
{
int i;
i2eBordStrPtr pB;
@@ -1235,7 +1236,7 @@ ip2_poll(unsigned long arg)
// Just polled boards, IRQ = 0 will hit all non-interrupt boards.
// It will NOT poll boards handled by hard interrupts.
// The issue of queued BH interrups is handled in ip2_interrupt().
- ip2_interrupt(0, NULL, NULL);
+ ip2_interrupt(0, NULL);
PollTimer.expires = POLL_TIMEOUT;
add_timer( &PollTimer );
@@ -1703,7 +1704,7 @@ ip2_write( PTTY tty, const unsigned char *pData, int count)
/* This is the actual move bit. Make sure it does what we need!!!!! */
WRITE_LOCK_IRQSAVE(&pCh->Pbuf_spinlock,flags);
- bytesSent = i2Output( pCh, pData, count, 0 );
+ bytesSent = i2Output( pCh, pData, count);
WRITE_UNLOCK_IRQRESTORE(&pCh->Pbuf_spinlock,flags);
ip2trace (CHANN, ITRC_WRITE, ITRC_RETURN, 1, bytesSent );
@@ -1763,7 +1764,7 @@ ip2_flush_chars( PTTY tty )
//
// We may need to restart i2Output if it does not fullfill this request
//
- strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff, 0 );
+ strip = i2Output( pCh, pCh->Pbuf, pCh->Pbuf_stuff);
if ( strip != pCh->Pbuf_stuff ) {
memmove( pCh->Pbuf, &pCh->Pbuf[strip], pCh->Pbuf_stuff - strip );
}
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 68d7c61a864e..81fcf0ce21d1 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -377,7 +377,8 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
- rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd);
+ rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
+ IPMI_CHAN_ALL);
break;
}
@@ -390,7 +391,36 @@ static int ipmi_ioctl(struct inode *inode,
break;
}
- rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd);
+ rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
+ IPMI_CHAN_ALL);
+ break;
+ }
+
+ case IPMICTL_REGISTER_FOR_CMD_CHANS:
+ {
+ struct ipmi_cmdspec_chans val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_register_for_cmd(priv->user, val.netfn, val.cmd,
+ val.chans);
+ break;
+ }
+
+ case IPMICTL_UNREGISTER_FOR_CMD_CHANS:
+ {
+ struct ipmi_cmdspec_chans val;
+
+ if (copy_from_user(&val, arg, sizeof(val))) {
+ rv = -EFAULT;
+ break;
+ }
+
+ rv = ipmi_unregister_for_cmd(priv->user, val.netfn, val.cmd,
+ val.chans);
break;
}
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 843d34c8627c..34a4fd13fa81 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -96,6 +96,7 @@ struct cmd_rcvr
ipmi_user_t user;
unsigned char netfn;
unsigned char cmd;
+ unsigned int chans;
/*
* This is used to form a linked lised during mass deletion.
@@ -953,24 +954,41 @@ int ipmi_set_gets_events(ipmi_user_t user, int val)
static struct cmd_rcvr *find_cmd_rcvr(ipmi_smi_t intf,
unsigned char netfn,
- unsigned char cmd)
+ unsigned char cmd,
+ unsigned char chan)
{
struct cmd_rcvr *rcvr;
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
- if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd))
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
+ && (rcvr->chans & (1 << chan)))
return rcvr;
}
return NULL;
}
+static int is_cmd_rcvr_exclusive(ipmi_smi_t intf,
+ unsigned char netfn,
+ unsigned char cmd,
+ unsigned int chans)
+{
+ struct cmd_rcvr *rcvr;
+
+ list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
+ if ((rcvr->netfn == netfn) && (rcvr->cmd == cmd)
+ && (rcvr->chans & chans))
+ return 0;
+ }
+ return 1;
+}
+
int ipmi_register_for_cmd(ipmi_user_t user,
unsigned char netfn,
- unsigned char cmd)
+ unsigned char cmd,
+ unsigned int chans)
{
ipmi_smi_t intf = user->intf;
struct cmd_rcvr *rcvr;
- struct cmd_rcvr *entry;
int rv = 0;
@@ -979,12 +997,12 @@ int ipmi_register_for_cmd(ipmi_user_t user,
return -ENOMEM;
rcvr->cmd = cmd;
rcvr->netfn = netfn;
+ rcvr->chans = chans;
rcvr->user = user;
mutex_lock(&intf->cmd_rcvrs_mutex);
/* Make sure the command/netfn is not already registered. */
- entry = find_cmd_rcvr(intf, netfn, cmd);
- if (entry) {
+ if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
rv = -EBUSY;
goto out_unlock;
}
@@ -1001,24 +1019,39 @@ int ipmi_register_for_cmd(ipmi_user_t user,
int ipmi_unregister_for_cmd(ipmi_user_t user,
unsigned char netfn,
- unsigned char cmd)
+ unsigned char cmd,
+ unsigned int chans)
{
ipmi_smi_t intf = user->intf;
struct cmd_rcvr *rcvr;
+ struct cmd_rcvr *rcvrs = NULL;
+ int i, rv = -ENOENT;
mutex_lock(&intf->cmd_rcvrs_mutex);
- /* Make sure the command/netfn is not already registered. */
- rcvr = find_cmd_rcvr(intf, netfn, cmd);
- if ((rcvr) && (rcvr->user == user)) {
- list_del_rcu(&rcvr->link);
- mutex_unlock(&intf->cmd_rcvrs_mutex);
- synchronize_rcu();
+ for (i = 0; i < IPMI_NUM_CHANNELS; i++) {
+ if (((1 << i) & chans) == 0)
+ continue;
+ rcvr = find_cmd_rcvr(intf, netfn, cmd, i);
+ if (rcvr == NULL)
+ continue;
+ if (rcvr->user == user) {
+ rv = 0;
+ rcvr->chans &= ~chans;
+ if (rcvr->chans == 0) {
+ list_del_rcu(&rcvr->link);
+ rcvr->next = rcvrs;
+ rcvrs = rcvr;
+ }
+ }
+ }
+ mutex_unlock(&intf->cmd_rcvrs_mutex);
+ synchronize_rcu();
+ while (rcvrs) {
+ rcvr = rcvrs;
+ rcvrs = rcvr->next;
kfree(rcvr);
- return 0;
- } else {
- mutex_unlock(&intf->cmd_rcvrs_mutex);
- return -ENOENT;
}
+ return rv;
}
void ipmi_user_set_run_to_completion(ipmi_user_t user, int val)
@@ -1895,13 +1928,8 @@ static ssize_t guid_show(struct device *dev, struct device_attribute *attr,
(long long) bmc->guid[8]);
}
-static void
-cleanup_bmc_device(struct kref *ref)
+static void remove_files(struct bmc_device *bmc)
{
- struct bmc_device *bmc;
-
- bmc = container_of(ref, struct bmc_device, refcount);
-
device_remove_file(&bmc->dev->dev,
&bmc->device_id_attr);
device_remove_file(&bmc->dev->dev,
@@ -1918,12 +1946,23 @@ cleanup_bmc_device(struct kref *ref)
&bmc->manufacturer_id_attr);
device_remove_file(&bmc->dev->dev,
&bmc->product_id_attr);
+
if (bmc->id.aux_firmware_revision_set)
device_remove_file(&bmc->dev->dev,
&bmc->aux_firmware_rev_attr);
if (bmc->guid_set)
device_remove_file(&bmc->dev->dev,
&bmc->guid_attr);
+}
+
+static void
+cleanup_bmc_device(struct kref *ref)
+{
+ struct bmc_device *bmc;
+
+ bmc = container_of(ref, struct bmc_device, refcount);
+
+ remove_files(bmc);
platform_device_unregister(bmc->dev);
kfree(bmc);
}
@@ -1944,6 +1983,79 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf)
mutex_unlock(&ipmidriver_mutex);
}
+static int create_files(struct bmc_device *bmc)
+{
+ int err;
+
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->device_id_attr);
+ if (err) goto out;
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->provides_dev_sdrs_attr);
+ if (err) goto out_devid;
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->revision_attr);
+ if (err) goto out_sdrs;
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->firmware_rev_attr);
+ if (err) goto out_rev;
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->version_attr);
+ if (err) goto out_firm;
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->add_dev_support_attr);
+ if (err) goto out_version;
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->manufacturer_id_attr);
+ if (err) goto out_add_dev;
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->product_id_attr);
+ if (err) goto out_manu;
+ if (bmc->id.aux_firmware_revision_set) {
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->aux_firmware_rev_attr);
+ if (err) goto out_prod_id;
+ }
+ if (bmc->guid_set) {
+ err = device_create_file(&bmc->dev->dev,
+ &bmc->guid_attr);
+ if (err) goto out_aux_firm;
+ }
+
+ return 0;
+
+out_aux_firm:
+ if (bmc->id.aux_firmware_revision_set)
+ device_remove_file(&bmc->dev->dev,
+ &bmc->aux_firmware_rev_attr);
+out_prod_id:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->product_id_attr);
+out_manu:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->manufacturer_id_attr);
+out_add_dev:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->add_dev_support_attr);
+out_version:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->version_attr);
+out_firm:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->firmware_rev_attr);
+out_rev:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->revision_attr);
+out_sdrs:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->provides_dev_sdrs_attr);
+out_devid:
+ device_remove_file(&bmc->dev->dev,
+ &bmc->device_id_attr);
+out:
+ return err;
+}
+
static int ipmi_bmc_register(ipmi_smi_t intf)
{
int rv;
@@ -2018,7 +2130,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf)
bmc->provides_dev_sdrs_attr.attr.mode = S_IRUGO;
bmc->provides_dev_sdrs_attr.show = provides_dev_sdrs_show;
-
bmc->revision_attr.attr.name = "revision";
bmc->revision_attr.attr.owner = THIS_MODULE;
bmc->revision_attr.attr.mode = S_IRUGO;
@@ -2060,28 +2171,14 @@ static int ipmi_bmc_register(ipmi_smi_t intf)
bmc->aux_firmware_rev_attr.attr.mode = S_IRUGO;
bmc->aux_firmware_rev_attr.show = aux_firmware_rev_show;
- device_create_file(&bmc->dev->dev,
- &bmc->device_id_attr);
- device_create_file(&bmc->dev->dev,
- &bmc->provides_dev_sdrs_attr);
- device_create_file(&bmc->dev->dev,
- &bmc->revision_attr);
- device_create_file(&bmc->dev->dev,
- &bmc->firmware_rev_attr);
- device_create_file(&bmc->dev->dev,
- &bmc->version_attr);
- device_create_file(&bmc->dev->dev,
- &bmc->add_dev_support_attr);
- device_create_file(&bmc->dev->dev,
- &bmc->manufacturer_id_attr);
- device_create_file(&bmc->dev->dev,
- &bmc->product_id_attr);
- if (bmc->id.aux_firmware_revision_set)
- device_create_file(&bmc->dev->dev,
- &bmc->aux_firmware_rev_attr);
- if (bmc->guid_set)
- device_create_file(&bmc->dev->dev,
- &bmc->guid_attr);
+ rv = create_files(bmc);
+ if (rv) {
+ mutex_lock(&ipmidriver_mutex);
+ platform_device_unregister(bmc->dev);
+ mutex_unlock(&ipmidriver_mutex);
+
+ return rv;
+ }
printk(KERN_INFO
"ipmi: Found new BMC (man_id: 0x%6.6x, "
@@ -2548,6 +2645,7 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
int rv = 0;
unsigned char netfn;
unsigned char cmd;
+ unsigned char chan;
ipmi_user_t user = NULL;
struct ipmi_ipmb_addr *ipmb_addr;
struct ipmi_recv_msg *recv_msg;
@@ -2568,9 +2666,10 @@ static int handle_ipmb_get_msg_cmd(ipmi_smi_t intf,
netfn = msg->rsp[4] >> 2;
cmd = msg->rsp[8];
+ chan = msg->rsp[3] & 0xf;
rcu_read_lock();
- rcvr = find_cmd_rcvr(intf, netfn, cmd);
+ rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
if (rcvr) {
user = rcvr->user;
kref_get(&user->refcount);
@@ -2728,6 +2827,7 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
int rv = 0;
unsigned char netfn;
unsigned char cmd;
+ unsigned char chan;
ipmi_user_t user = NULL;
struct ipmi_lan_addr *lan_addr;
struct ipmi_recv_msg *recv_msg;
@@ -2748,9 +2848,10 @@ static int handle_lan_get_msg_cmd(ipmi_smi_t intf,
netfn = msg->rsp[6] >> 2;
cmd = msg->rsp[10];
+ chan = msg->rsp[3] & 0xf;
rcu_read_lock();
- rcvr = find_cmd_rcvr(intf, netfn, cmd);
+ rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
if (rcvr) {
user = rcvr->user;
kref_get(&user->refcount);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index abca98beac14..e5cfb1fa47d1 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -217,6 +217,11 @@ struct smi_info
struct list_head link;
};
+#define SI_MAX_PARMS 4
+
+static int force_kipmid[SI_MAX_PARMS];
+static int num_force_kipmid;
+
static int try_smi_init(struct smi_info *smi);
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
@@ -867,7 +872,7 @@ static void smi_timeout(unsigned long data)
add_timer(&(smi_info->si_timer));
}
-static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t si_irq_handler(int irq, void *data)
{
struct smi_info *smi_info = data;
unsigned long flags;
@@ -894,20 +899,21 @@ static irqreturn_t si_irq_handler(int irq, void *data, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t si_bt_irq_handler(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t si_bt_irq_handler(int irq, void *data)
{
struct smi_info *smi_info = data;
/* We need to clear the IRQ flag for the BT interface. */
smi_info->io.outputb(&smi_info->io, IPMI_BT_INTMASK_REG,
IPMI_BT_INTMASK_CLEAR_IRQ_BIT
| IPMI_BT_INTMASK_ENABLE_IRQ_BIT);
- return si_irq_handler(irq, data, regs);
+ return si_irq_handler(irq, data);
}
static int smi_start_processing(void *send_info,
ipmi_smi_t intf)
{
struct smi_info *new_smi = send_info;
+ int enable = 0;
new_smi->intf = intf;
@@ -916,7 +922,19 @@ static int smi_start_processing(void *send_info,
new_smi->last_timeout_jiffies = jiffies;
mod_timer(&new_smi->si_timer, jiffies + SI_TIMEOUT_JIFFIES);
- if (new_smi->si_type != SI_BT) {
+ /*
+ * Check if the user forcefully enabled the daemon.
+ */
+ if (new_smi->intf_num < num_force_kipmid)
+ enable = force_kipmid[new_smi->intf_num];
+ /*
+ * The BT interface is efficient enough to not need a thread,
+ * and there is no need for a thread if we have interrupts.
+ */
+ else if ((new_smi->si_type != SI_BT) && (!new_smi->irq))
+ enable = 1;
+
+ if (enable) {
new_smi->thread = kthread_run(ipmi_thread, new_smi,
"kipmi%d", new_smi->intf_num);
if (IS_ERR(new_smi->thread)) {
@@ -944,7 +962,6 @@ static struct ipmi_smi_handlers handlers =
/* There can be 4 IO ports passed in (with or without IRQs), 4 addresses,
a default IO port, and 1 ACPI/SPMI address. That sets SI_MAX_DRIVERS */
-#define SI_MAX_PARMS 4
static LIST_HEAD(smi_infos);
static DEFINE_MUTEX(smi_infos_lock);
static int smi_num; /* Used to sequence the SMIs */
@@ -1017,6 +1034,10 @@ MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for"
" the controller. Normally this is 0x20, but can be"
" overridden by this parm. This is an array indexed"
" by interface number.");
+module_param_array(force_kipmid, int, &num_force_kipmid, 0);
+MODULE_PARM_DESC(force_kipmid, "Force the kipmi daemon to be enabled (1) or"
+ " disabled(0). Normally the IPMI driver auto-detects"
+ " this, but the value may be overridden by this parm.");
#define IPMI_IO_ADDR_SPACE 0
@@ -1730,6 +1751,7 @@ static void __devinit dmi_find_bmc(void)
int rv;
while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev))) {
+ memset(&data, 0, sizeof(data));
rv = decode_dmi((struct dmi_header *) dev->device_data, &data);
if (!rv)
try_init_dmi(&data);
@@ -1767,7 +1789,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
- return ENOMEM;
+ return -ENOMEM;
info->addr_source = "PCI";
@@ -1788,7 +1810,7 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
kfree(info);
printk(KERN_INFO "ipmi_si: %s: Unknown IPMI type: %d\n",
pci_name(pdev), class_type);
- return ENOMEM;
+ return -ENOMEM;
}
rv = pci_enable_device(pdev);
diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c
index accaaf1a6b69..73f759eaa5a6 100644
--- a/drivers/char/ipmi/ipmi_watchdog.c
+++ b/drivers/char/ipmi/ipmi_watchdog.c
@@ -903,7 +903,7 @@ static void ipmi_register_watchdog(int ipmi_intf)
#ifdef HAVE_NMI_HANDLER
static int
-ipmi_nmi(void *dev_id, struct pt_regs *regs, int cpu, int handled)
+ipmi_nmi(void *dev_id, int cpu, int handled)
{
/* If we are not expecting a timeout, ignore it. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 913be23e0a24..e9e9bf31c369 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -546,7 +546,7 @@ static void isicom_bottomhalf(void *data)
* Main interrupt handler routine
*/
-static irqreturn_t isicom_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t isicom_interrupt(int irq, void *dev_id)
{
struct isi_board *card = dev_id;
struct isi_port *port;
@@ -1550,7 +1550,7 @@ static void isicom_unregister_ioregion(struct pci_dev *pdev)
board->base = 0;
}
-static struct tty_operations isicom_ops = {
+static const struct tty_operations isicom_ops = {
.open = isicom_open,
.close = isicom_close,
.write = isicom_write,
@@ -1756,9 +1756,12 @@ static int __devinit load_firmware(struct pci_dev *pdev,
if (retval)
goto end;
+ retval = -EIO;
+
for (frame = (struct stframe *)fw->data;
frame < (struct stframe *)(fw->data + fw->size);
- frame++) {
+ frame = (struct stframe *)((u8 *)(frame + 1) +
+ frame->count)) {
if (WaitTillCardIsFree(base))
goto errrelfw;
@@ -1797,23 +1800,12 @@ static int __devinit load_firmware(struct pci_dev *pdev,
}
}
- retval = -EIO;
-
- if (WaitTillCardIsFree(base))
- goto errrelfw;
-
- outw(0xf2, base);
- outw(0x800, base);
- outw(0x0, base);
- outw(0x0, base);
- InterruptTheCard(base);
- outw(0x0, base + 0x4); /* for ISI4608 cards */
-
/* XXX: should we test it by reading it back and comparing with original like
* in load firmware package? */
- for (frame = (struct stframe*)fw->data;
- frame < (struct stframe*)(fw->data + fw->size);
- frame++) {
+ for (frame = (struct stframe *)fw->data;
+ frame < (struct stframe *)(fw->data + fw->size);
+ frame = (struct stframe *)((u8 *)(frame + 1) +
+ frame->count)) {
if (WaitTillCardIsFree(base))
goto errrelfw;
@@ -1863,6 +1855,17 @@ static int __devinit load_firmware(struct pci_dev *pdev,
}
}
+ /* xfer ctrl */
+ if (WaitTillCardIsFree(base))
+ goto errrelfw;
+
+ outw(0xf2, base);
+ outw(0x800, base);
+ outw(0x0, base);
+ outw(0x0, base);
+ InterruptTheCard(base);
+ outw(0x0, base + 0x4); /* for ISI4608 cards */
+
board->status |= FIRMWARE_LOADED;
retval = 0;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 8c09997cc3d6..ffdf9df1a67a 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -612,16 +612,6 @@ MODULE_DEVICE_TABLE(pci, istallion_pci_tbl);
#define MINOR2BRD(min) (((min) & 0xc0) >> 6)
#define MINOR2PORT(min) ((min) & 0x3f)
-/*
- * Define a baud rate table that converts termios baud rate selector
- * into the actual baud rate value. All baud rate calculations are based
- * on the actual baud rate required.
- */
-static unsigned int stli_baudrates[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 230400, 460800, 921600
-};
-
/*****************************************************************************/
/*
@@ -696,37 +686,37 @@ static stlibrd_t *stli_allocbrd(void);
static void stli_ecpinit(stlibrd_t *brdp);
static void stli_ecpenable(stlibrd_t *brdp);
static void stli_ecpdisable(stlibrd_t *brdp);
-static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_ecpreset(stlibrd_t *brdp);
static void stli_ecpintr(stlibrd_t *brdp);
static void stli_ecpeiinit(stlibrd_t *brdp);
static void stli_ecpeienable(stlibrd_t *brdp);
static void stli_ecpeidisable(stlibrd_t *brdp);
-static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_ecpeireset(stlibrd_t *brdp);
static void stli_ecpmcenable(stlibrd_t *brdp);
static void stli_ecpmcdisable(stlibrd_t *brdp);
-static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_ecpmcreset(stlibrd_t *brdp);
static void stli_ecppciinit(stlibrd_t *brdp);
-static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_ecppcireset(stlibrd_t *brdp);
static void stli_onbinit(stlibrd_t *brdp);
static void stli_onbenable(stlibrd_t *brdp);
static void stli_onbdisable(stlibrd_t *brdp);
-static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_onbreset(stlibrd_t *brdp);
static void stli_onbeinit(stlibrd_t *brdp);
static void stli_onbeenable(stlibrd_t *brdp);
static void stli_onbedisable(stlibrd_t *brdp);
-static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_onbereset(stlibrd_t *brdp);
static void stli_bbyinit(stlibrd_t *brdp);
-static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_bbyreset(stlibrd_t *brdp);
static void stli_stalinit(stlibrd_t *brdp);
-static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
+static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line);
static void stli_stalreset(stlibrd_t *brdp);
static stliport_t *stli_getport(int brdnr, int panelnr, int portnr);
@@ -1576,7 +1566,7 @@ static void stli_flushchars(struct tty_struct *tty)
len = MIN(len, cooksize);
count = 0;
- shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset);
+ shbuf = EBRDGETMEMPTR(brdp, portp->txoffset);
buf = stli_txcookbuf;
while (len > 0) {
@@ -2747,15 +2737,7 @@ static void stli_mkasyport(stliport_t *portp, asyport_t *pp, struct termios *tio
/*
* Start of by setting the baud, char size, parity and stop bit info.
*/
- pp->baudout = tiosp->c_cflag & CBAUD;
- if (pp->baudout & CBAUDEX) {
- pp->baudout &= ~CBAUDEX;
- if ((pp->baudout < 1) || (pp->baudout > 4))
- tiosp->c_cflag &= ~CBAUDEX;
- else
- pp->baudout += 15;
- }
- pp->baudout = stli_baudrates[pp->baudout];
+ pp->baudout = tty_get_baud_rate(portp->tty);
if ((tiosp->c_cflag & CBAUD) == B38400) {
if ((portp->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
pp->baudout = 57600;
@@ -2966,9 +2948,9 @@ static void stli_ecpdisable(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
+ void __iomem *ptr;
unsigned char val;
if (offset > brdp->memsize) {
@@ -3040,9 +3022,9 @@ static void stli_ecpeidisable(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpeigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
+ void __iomem *ptr;
unsigned char val;
if (offset > brdp->memsize) {
@@ -3092,9 +3074,9 @@ static void stli_ecpmcdisable(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecpmcgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
+ void __iomem *ptr;
unsigned char val;
if (offset > brdp->memsize) {
@@ -3137,9 +3119,9 @@ static void stli_ecppciinit(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_ecppcigetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
+ void __iomem *ptr;
unsigned char val;
if (offset > brdp->memsize) {
@@ -3203,9 +3185,9 @@ static void stli_onbdisable(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_onbgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
+ void __iomem *ptr;
if (offset > brdp->memsize) {
printk(KERN_ERR "STALLION: shared memory pointer=%x out of "
@@ -3268,9 +3250,9 @@ static void stli_onbedisable(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_onbegetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
+ void __iomem *ptr;
unsigned char val;
if (offset > brdp->memsize) {
@@ -3318,9 +3300,9 @@ static void stli_bbyinit(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_bbygetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
- void *ptr;
+ void __iomem *ptr;
unsigned char val;
BUG_ON(offset > brdp->memsize);
@@ -3355,7 +3337,7 @@ static void stli_stalinit(stlibrd_t *brdp)
/*****************************************************************************/
-static char *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
+static void __iomem *stli_stalgetmemptr(stlibrd_t *brdp, unsigned long offset, int line)
{
BUG_ON(offset > brdp->memsize);
return brdp->membase + (offset % STAL_PAGESIZE);
@@ -3894,7 +3876,7 @@ static int stli_eisamemprobe(stlibrd_t *brdp)
continue;
if (brdp->brdtype == BRD_ECPE) {
- ecpsigp = (cdkecpsig_t __iomem *) stli_ecpeigetmemptr(brdp,
+ ecpsigp = stli_ecpeigetmemptr(brdp,
CDK_SIGADDR, __LINE__);
memcpy_fromio(&ecpsig, ecpsigp, sizeof(cdkecpsig_t));
if (ecpsig.magic == cpu_to_le32(ECP_MAGIC))
@@ -4202,7 +4184,7 @@ static int stli_initbrds(void)
static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, loff_t *offp)
{
unsigned long flags;
- void *memptr;
+ void __iomem *memptr;
stlibrd_t *brdp;
int brdnr, size, n;
void *p;
@@ -4232,7 +4214,7 @@ static ssize_t stli_memread(struct file *fp, char __user *buf, size_t count, lof
while (size > 0) {
spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- memptr = (void *) EBRDGETMEMPTR(brdp, off);
+ memptr = EBRDGETMEMPTR(brdp, off);
n = MIN(size, (brdp->pagesize - (((unsigned long) off) % brdp->pagesize)));
n = MIN(n, PAGE_SIZE);
memcpy_fromio(p, memptr, n);
@@ -4265,7 +4247,7 @@ out:
static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t count, loff_t *offp)
{
unsigned long flags;
- void *memptr;
+ void __iomem *memptr;
stlibrd_t *brdp;
char __user *chbuf;
int brdnr, size, n;
@@ -4305,7 +4287,7 @@ static ssize_t stli_memwrite(struct file *fp, const char __user *buf, size_t cou
}
spin_lock_irqsave(&brd_lock, flags);
EBRDENABLE(brdp);
- memptr = (void *) EBRDGETMEMPTR(brdp, off);
+ memptr = EBRDGETMEMPTR(brdp, off);
memcpy_toio(memptr, p, n);
EBRDDISABLE(brdp);
spin_unlock_irqrestore(&brd_lock, flags);
@@ -4654,7 +4636,7 @@ static int stli_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, un
return rc;
}
-static struct tty_operations stli_ops = {
+static const struct tty_operations stli_ops = {
.open = stli_open,
.close = stli_close,
.write = stli_write,
diff --git a/drivers/char/ite_gpio.c b/drivers/char/ite_gpio.c
deleted file mode 100644
index cde562d70c4f..000000000000
--- a/drivers/char/ite_gpio.c
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * FILE NAME ite_gpio.c
- *
- * BRIEF MODULE DESCRIPTION
- * API for ITE GPIO device.
- * Driver for ITE GPIO device.
- *
- * Author: MontaVista Software, Inc. <source@mvista.com>
- * Hai-Pao Fan <haipao@mvista.com>
- *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/miscdevice.h>
-#include <linux/init.h>
-#include <linux/ioport.h>
-#include <asm/uaccess.h>
-#include <asm/addrspace.h>
-#include <asm/it8172/it8172_int.h>
-#include <linux/sched.h>
-#include <linux/ite_gpio.h>
-
-#define ite_gpio_base 0x14013800
-
-#define ITE_GPADR (*(volatile __u8 *)(0x14013800 + KSEG1))
-#define ITE_GPBDR (*(volatile __u8 *)(0x14013808 + KSEG1))
-#define ITE_GPCDR (*(volatile __u8 *)(0x14013810 + KSEG1))
-#define ITE_GPACR (*(volatile __u16 *)(0x14013802 + KSEG1))
-#define ITE_GPBCR (*(volatile __u16 *)(0x1401380a + KSEG1))
-#define ITE_GPCCR (*(volatile __u16 *)(0x14013812 + KSEG1))
-#define ITE_GPAICR (*(volatile __u16 *)(0x14013804 + KSEG1))
-#define ITE_GPBICR (*(volatile __u16 *)(0x1401380c + KSEG1))
-#define ITE_GPCICR (*(volatile __u16 *)(0x14013814 + KSEG1))
-#define ITE_GPAISR (*(volatile __u8 *)(0x14013806 + KSEG1))
-#define ITE_GPBISR (*(volatile __u8 *)(0x1401380e + KSEG1))
-#define ITE_GPCISR (*(volatile __u8 *)(0x14013816 + KSEG1))
-#define ITE_GCR (*(volatile __u8 *)(0x14013818 + KSEG1))
-
-#define MAX_GPIO_LINE 21
-static int ite_gpio_irq=IT8172_GPIO_IRQ;
-
-static long ite_irq_counter[MAX_GPIO_LINE];
-wait_queue_head_t ite_gpio_wait[MAX_GPIO_LINE];
-static int ite_gpio_irq_pending[MAX_GPIO_LINE];
-
-static int ite_gpio_debug=0;
-#define DEB(x) if (ite_gpio_debug>=1) x
-
-int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data)
-{
- DEB(printk("ite_gpio_in mask=0x%x\n",mask));
-
- switch (device) {
- case ITE_GPIO_PORTA:
- ITE_GPACR = (__u16)mask; /* 0xffff */
- *data = ITE_GPADR;
- break;
- case ITE_GPIO_PORTB:
- ITE_GPBCR = (__u16)mask; /* 0xffff */
- *data = ITE_GPBDR;
- break;
- case ITE_GPIO_PORTC:
- ITE_GPCCR = (__u16)mask; /* 0x03ff */
- *data = ITE_GPCDR;
- break;
- default:
- return -EFAULT;
- }
-
- return 0;
-}
-
-
-int ite_gpio_out(__u32 device, __u32 mask, __u32 data)
-{
- switch (device) {
- case ITE_GPIO_PORTA:
- ITE_GPACR = (__u16)mask; /* 0x5555 */
- ITE_GPADR = (__u8)data;
- break;
- case ITE_GPIO_PORTB:
- ITE_GPBCR = (__u16)mask; /* 0x5555 */
- ITE_GPBDR = (__u8)data;
- break;
- case ITE_GPIO_PORTC:
- ITE_GPCCR = (__u16)mask; /* 0x0155 */
- ITE_GPCDR = (__u8)data;
- break;
- default:
- return -EFAULT;
- }
-
- return 0;
-}
-
-int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data)
-{
- switch (device) {
- case ITE_GPIO_PORTA:
- ITE_GPAICR = (ITE_GPAICR & ~mask) | (data & mask);
- break;
- case ITE_GPIO_PORTB:
- ITE_GPBICR = (ITE_GPBICR & ~mask) | (data & mask);
- break;
- case ITE_GPIO_PORTC:
- ITE_GPCICR = (ITE_GPCICR & ~mask) | (data & mask);
- break;
- default:
- return -EFAULT;
- }
-
- return 0;
-}
-
-int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data)
-{
- int ret=-1;
-
- if ((MAX_GPIO_LINE > *data) && (*data >= 0))
- ret=ite_gpio_irq_pending[*data];
-
- DEB(printk("ite_gpio_in_status %d ret=%d\n",*data, ret));
-
- switch (device) {
- case ITE_GPIO_PORTA:
- *data = ITE_GPAISR & mask;
- break;
- case ITE_GPIO_PORTB:
- *data = ITE_GPBISR & mask;
- break;
- case ITE_GPIO_PORTC:
- *data = ITE_GPCISR & mask;
- break;
- default:
- return -EFAULT;
- }
-
- return ret;
-}
-
-int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data)
-{
- switch (device) {
- case ITE_GPIO_PORTA:
- ITE_GPAISR = (ITE_GPAISR & ~mask) | (data & mask);
- break;
- case ITE_GPIO_PORTB:
- ITE_GPBISR = (ITE_GPBISR & ~mask) | (data & mask);
- break;
- case ITE_GPIO_PORTC:
- ITE_GPCISR = (ITE_GPCISR & ~mask) | (data & mask);
- break;
- default:
- return -EFAULT;
- }
-
- return 0;
-}
-
-int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data)
-{
- ITE_GCR = (ITE_GCR & ~mask) | (data & mask);
-
- return 0;
-}
-
-int ite_gpio_int_wait (__u32 device, __u32 mask, __u32 data)
-{
- int i,line=0, ret=0;
- unsigned long flags;
-
- switch (device) {
- case ITE_GPIO_PORTA:
- line = data & mask;
- break;
- case ITE_GPIO_PORTB:
- line = (data & mask) <<8;
- break;
- case ITE_GPIO_PORTC:
- line = (data & mask) <<16;
- break;
- }
- for (i=MAX_GPIO_LINE-1; i >= 0; i--) {
- if ( (line) & (1 << i))
- break;
- }
-
- DEB(printk("wait device=0x%d mask=0x%x data=0x%x index %d\n",
- device, mask, data, i));
-
- if (line & ~(1<<i))
- return -EFAULT;
-
- if (ite_gpio_irq_pending[i]==1)
- return -EFAULT;
-
- save_flags (flags);
- cli();
- ite_gpio_irq_pending[i] = 1;
- ret = interruptible_sleep_on_timeout(&ite_gpio_wait[i], 3*HZ);
- restore_flags (flags);
- ite_gpio_irq_pending[i] = 0;
-
- return ret;
-}
-
-EXPORT_SYMBOL(ite_gpio_in);
-EXPORT_SYMBOL(ite_gpio_out);
-EXPORT_SYMBOL(ite_gpio_int_ctrl);
-EXPORT_SYMBOL(ite_gpio_in_status);
-EXPORT_SYMBOL(ite_gpio_out_status);
-EXPORT_SYMBOL(ite_gpio_gen_ctrl);
-EXPORT_SYMBOL(ite_gpio_int_wait);
-
-static int ite_gpio_open(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-
-static int ite_gpio_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-
-static int ite_gpio_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- static struct ite_gpio_ioctl_data ioctl_data;
-
- if (copy_from_user(&ioctl_data, (struct ite_gpio_ioctl_data *)arg,
- sizeof(ioctl_data)))
- return -EFAULT;
- if ((ioctl_data.device < ITE_GPIO_PORTA) ||
- (ioctl_data.device > ITE_GPIO_PORTC) )
- return -EFAULT;
-
- switch(cmd) {
- case ITE_GPIO_IN:
- if (ite_gpio_in(ioctl_data.device, ioctl_data.mask,
- &ioctl_data.data))
- return -EFAULT;
-
- if (copy_to_user((struct ite_gpio_ioctl_data *)arg,
- &ioctl_data, sizeof(ioctl_data)))
- return -EFAULT;
- break;
-
- case ITE_GPIO_OUT:
- return ite_gpio_out(ioctl_data.device,
- ioctl_data.mask, ioctl_data.data);
- break;
-
- case ITE_GPIO_INT_CTRL:
- return ite_gpio_int_ctrl(ioctl_data.device,
- ioctl_data.mask, ioctl_data.data);
- break;
-
- case ITE_GPIO_IN_STATUS:
- if (ite_gpio_in_status(ioctl_data.device, ioctl_data.mask,
- &ioctl_data.data))
- return -EFAULT;
- if (copy_to_user((struct ite_gpio_ioctl_data *)arg,
- &ioctl_data, sizeof(ioctl_data)))
- return -EFAULT;
- break;
-
- case ITE_GPIO_OUT_STATUS:
- return ite_gpio_out_status(ioctl_data.device,
- ioctl_data.mask, ioctl_data.data);
- break;
-
- case ITE_GPIO_GEN_CTRL:
- return ite_gpio_gen_ctrl(ioctl_data.device,
- ioctl_data.mask, ioctl_data.data);
- break;
-
- case ITE_GPIO_INT_WAIT:
- return ite_gpio_int_wait(ioctl_data.device,
- ioctl_data.mask, ioctl_data.data);
- break;
-
- default:
- return -ENOIOCTLCMD;
-
- }
-
- return 0;
-}
-
-static void ite_gpio_irq_handler(int this_irq, void *dev_id,
- struct pt_regs *regs)
-{
- int i,line;
-
- line = ITE_GPCISR & 0x1f;
- for (i=4; i >=0; i--) {
- if ( line & (1 << i)) {
- ++ite_irq_counter[i+16];
- ite_gpio_irq_pending[i+16] = 2;
- wake_up_interruptible(&ite_gpio_wait[i+16]);
-
-DEB(printk("interrupt 0x%x %d\n", &ite_gpio_wait[i+16], i+16));
-
- ITE_GPCISR = ITE_GPCISR & (1<<i);
- return;
- }
- }
- line = ITE_GPBISR;
- for (i=7; i >= 0; i--) {
- if ( line & (1 << i)) {
- ++ite_irq_counter[i+8];
- ite_gpio_irq_pending[i+8] = 2;
- wake_up_interruptible(&ite_gpio_wait[i+8]);
-
-DEB(printk("interrupt 0x%x %d\n",ITE_GPBISR, i+8));
-
- ITE_GPBISR = ITE_GPBISR & (1<<i);
- return;
- }
- }
- line = ITE_GPAISR;
- for (i=7; i >= 0; i--) {
- if ( line & (1 << i)) {
- ++ite_irq_counter[i];
- ite_gpio_irq_pending[i] = 2;
- wake_up_interruptible(&ite_gpio_wait[i]);
-
-DEB(printk("interrupt 0x%x %d\n",ITE_GPAISR, i));
-
- ITE_GPAISR = ITE_GPAISR & (1<<i);
- return;
- }
- }
-}
-
-static const struct file_operations ite_gpio_fops = {
- .owner = THIS_MODULE,
- .ioctl = ite_gpio_ioctl,
- .open = ite_gpio_open,
- .release = ite_gpio_release,
-};
-
-static struct miscdevice ite_gpio_miscdev = {
- MISC_DYNAMIC_MINOR,
- "ite_gpio",
- &ite_gpio_fops
-};
-
-int __init ite_gpio_init(void)
-{
- int i;
-
- if (misc_register(&ite_gpio_miscdev))
- return -ENODEV;
-
- if (!request_region(ite_gpio_base, 0x1c, "ITE GPIO"))
- {
- misc_deregister(&ite_gpio_miscdev);
- return -EIO;
- }
-
- /* initialize registers */
- ITE_GPACR = 0xffff;
- ITE_GPBCR = 0xffff;
- ITE_GPCCR = 0xffff;
- ITE_GPAICR = 0x00ff;
- ITE_GPBICR = 0x00ff;
- ITE_GPCICR = 0x00ff;
- ITE_GCR = 0;
-
- for (i = 0; i < MAX_GPIO_LINE; i++) {
- ite_gpio_irq_pending[i]=0;
- init_waitqueue_head(&ite_gpio_wait[i]);
- }
-
- if (request_irq(ite_gpio_irq, ite_gpio_irq_handler, IRQF_SHARED, "gpio", 0) < 0) {
- misc_deregister(&ite_gpio_miscdev);
- release_region(ite_gpio_base, 0x1c);
- return 0;
- }
-
- printk("GPIO at 0x%x (irq = %d)\n", ite_gpio_base, ite_gpio_irq);
-
- return 0;
-}
-
-static void __exit ite_gpio_exit(void)
-{
- misc_deregister(&ite_gpio_miscdev);
-}
-
-module_init(ite_gpio_init);
-module_exit(ite_gpio_exit);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 3e90aac37510..20b6c8b30248 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -32,6 +32,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/irq.h>
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
@@ -77,7 +78,7 @@ void compute_shiftstate(void);
k_slock, k_dead2, k_brl, k_ignore
typedef void (k_handler_fn)(struct vc_data *vc, unsigned char value,
- char up_flag, struct pt_regs *regs);
+ char up_flag);
static k_handler_fn K_HANDLERS;
static k_handler_fn *k_handler[16] = { K_HANDLERS };
@@ -88,7 +89,7 @@ static k_handler_fn *k_handler[16] = { K_HANDLERS };
fn_boot_it, fn_caps_on, fn_compose, fn_SAK,\
fn_dec_console, fn_inc_console, fn_spawn_con, fn_bare_num
-typedef void (fn_handler_fn)(struct vc_data *vc, struct pt_regs *regs);
+typedef void (fn_handler_fn)(struct vc_data *vc);
static fn_handler_fn FN_HANDLERS;
static fn_handler_fn *fn_handler[] = { FN_HANDLERS };
@@ -108,7 +109,11 @@ const int NR_TYPES = ARRAY_SIZE(max_vals);
struct kbd_struct kbd_table[MAX_NR_CONSOLES];
static struct kbd_struct *kbd = kbd_table;
-int spawnpid, spawnsig;
+struct vt_spawn_console vt_spawn_con = {
+ .lock = SPIN_LOCK_UNLOCKED,
+ .pid = NULL,
+ .sig = 0,
+};
/*
* Variables exported for vt.c
@@ -424,7 +429,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch)
/*
* Special function handlers
*/
-static void fn_enter(struct vc_data *vc, struct pt_regs *regs)
+static void fn_enter(struct vc_data *vc)
{
if (diacr) {
if (kbd->kbdmode == VC_UNICODE)
@@ -438,27 +443,28 @@ static void fn_enter(struct vc_data *vc, struct pt_regs *regs)
put_queue(vc, 10);
}
-static void fn_caps_toggle(struct vc_data *vc, struct pt_regs *regs)
+static void fn_caps_toggle(struct vc_data *vc)
{
if (rep)
return;
chg_vc_kbd_led(kbd, VC_CAPSLOCK);
}
-static void fn_caps_on(struct vc_data *vc, struct pt_regs *regs)
+static void fn_caps_on(struct vc_data *vc)
{
if (rep)
return;
set_vc_kbd_led(kbd, VC_CAPSLOCK);
}
-static void fn_show_ptregs(struct vc_data *vc, struct pt_regs *regs)
+static void fn_show_ptregs(struct vc_data *vc)
{
+ struct pt_regs *regs = get_irq_regs();
if (regs)
show_regs(regs);
}
-static void fn_hold(struct vc_data *vc, struct pt_regs *regs)
+static void fn_hold(struct vc_data *vc)
{
struct tty_struct *tty = vc->vc_tty;
@@ -476,12 +482,12 @@ static void fn_hold(struct vc_data *vc, struct pt_regs *regs)
stop_tty(tty);
}
-static void fn_num(struct vc_data *vc, struct pt_regs *regs)
+static void fn_num(struct vc_data *vc)
{
if (vc_kbd_mode(kbd,VC_APPLIC))
applkey(vc, 'P', 1);
else
- fn_bare_num(vc, regs);
+ fn_bare_num(vc);
}
/*
@@ -490,19 +496,19 @@ static void fn_num(struct vc_data *vc, struct pt_regs *regs)
* Bind this to NumLock if you prefer that the NumLock key always
* changes the NumLock flag.
*/
-static void fn_bare_num(struct vc_data *vc, struct pt_regs *regs)
+static void fn_bare_num(struct vc_data *vc)
{
if (!rep)
chg_vc_kbd_led(kbd, VC_NUMLOCK);
}
-static void fn_lastcons(struct vc_data *vc, struct pt_regs *regs)
+static void fn_lastcons(struct vc_data *vc)
{
/* switch to the last used console, ChN */
set_console(last_console);
}
-static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs)
+static void fn_dec_console(struct vc_data *vc)
{
int i, cur = fg_console;
@@ -519,7 +525,7 @@ static void fn_dec_console(struct vc_data *vc, struct pt_regs *regs)
set_console(i);
}
-static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs)
+static void fn_inc_console(struct vc_data *vc)
{
int i, cur = fg_console;
@@ -536,7 +542,7 @@ static void fn_inc_console(struct vc_data *vc, struct pt_regs *regs)
set_console(i);
}
-static void fn_send_intr(struct vc_data *vc, struct pt_regs *regs)
+static void fn_send_intr(struct vc_data *vc)
{
struct tty_struct *tty = vc->vc_tty;
@@ -546,44 +552,48 @@ static void fn_send_intr(struct vc_data *vc, struct pt_regs *regs)
con_schedule_flip(tty);
}
-static void fn_scroll_forw(struct vc_data *vc, struct pt_regs *regs)
+static void fn_scroll_forw(struct vc_data *vc)
{
scrollfront(vc, 0);
}
-static void fn_scroll_back(struct vc_data *vc, struct pt_regs *regs)
+static void fn_scroll_back(struct vc_data *vc)
{
scrollback(vc, 0);
}
-static void fn_show_mem(struct vc_data *vc, struct pt_regs *regs)
+static void fn_show_mem(struct vc_data *vc)
{
show_mem();
}
-static void fn_show_state(struct vc_data *vc, struct pt_regs *regs)
+static void fn_show_state(struct vc_data *vc)
{
show_state();
}
-static void fn_boot_it(struct vc_data *vc, struct pt_regs *regs)
+static void fn_boot_it(struct vc_data *vc)
{
ctrl_alt_del();
}
-static void fn_compose(struct vc_data *vc, struct pt_regs *regs)
+static void fn_compose(struct vc_data *vc)
{
dead_key_next = 1;
}
-static void fn_spawn_con(struct vc_data *vc, struct pt_regs *regs)
+static void fn_spawn_con(struct vc_data *vc)
{
- if (spawnpid)
- if (kill_proc(spawnpid, spawnsig, 1))
- spawnpid = 0;
+ spin_lock(&vt_spawn_con.lock);
+ if (vt_spawn_con.pid)
+ if (kill_pid(vt_spawn_con.pid, vt_spawn_con.sig, 1)) {
+ put_pid(vt_spawn_con.pid);
+ vt_spawn_con.pid = NULL;
+ }
+ spin_unlock(&vt_spawn_con.lock);
}
-static void fn_SAK(struct vc_data *vc, struct pt_regs *regs)
+static void fn_SAK(struct vc_data *vc)
{
struct tty_struct *tty = vc->vc_tty;
@@ -596,7 +606,7 @@ static void fn_SAK(struct vc_data *vc, struct pt_regs *regs)
reset_vc(vc);
}
-static void fn_null(struct vc_data *vc, struct pt_regs *regs)
+static void fn_null(struct vc_data *vc)
{
compute_shiftstate();
}
@@ -604,11 +614,11 @@ static void fn_null(struct vc_data *vc, struct pt_regs *regs)
/*
* Special key handlers
*/
-static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_ignore(struct vc_data *vc, unsigned char value, char up_flag)
{
}
-static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_spec(struct vc_data *vc, unsigned char value, char up_flag)
{
if (up_flag)
return;
@@ -618,15 +628,15 @@ static void k_spec(struct vc_data *vc, unsigned char value, char up_flag, struct
kbd->kbdmode == VC_MEDIUMRAW) &&
value != KVAL(K_SAK))
return; /* SAK is allowed even in raw mode */
- fn_handler[value](vc, regs);
+ fn_handler[value](vc);
}
-static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_lowercase(struct vc_data *vc, unsigned char value, char up_flag)
{
printk(KERN_ERR "keyboard.c: k_lowercase was called - impossible\n");
}
-static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs)
+static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag)
{
if (up_flag)
return; /* no action, if this is a key release */
@@ -650,41 +660,41 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag, stru
* dead keys modifying the same character. Very useful
* for Vietnamese.
*/
-static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag, struct pt_regs *regs)
+static void k_deadunicode(struct vc_data *vc, unsigned int value, char up_flag)
{
if (up_flag)
return;
diacr = (diacr ? handle_diacr(vc, value) : value);
}
-static void k_self(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_self(struct vc_data *vc, unsigned char value, char up_flag)
{
- k_unicode(vc, value, up_flag, regs);
+ k_unicode(vc, value, up_flag);
}
-static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_dead2(struct vc_data *vc, unsigned char value, char up_flag)
{
- k_deadunicode(vc, value, up_flag, regs);
+ k_deadunicode(vc, value, up_flag);
}
/*
* Obsolete - for backwards compatibility only
*/
-static void k_dead(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_dead(struct vc_data *vc, unsigned char value, char up_flag)
{
static const unsigned char ret_diacr[NR_DEAD] = {'`', '\'', '^', '~', '"', ',' };
value = ret_diacr[value];
- k_deadunicode(vc, value, up_flag, regs);
+ k_deadunicode(vc, value, up_flag);
}
-static void k_cons(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_cons(struct vc_data *vc, unsigned char value, char up_flag)
{
if (up_flag)
return;
set_console(value);
}
-static void k_fn(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_fn(struct vc_data *vc, unsigned char value, char up_flag)
{
unsigned v;
@@ -698,7 +708,7 @@ static void k_fn(struct vc_data *vc, unsigned char value, char up_flag, struct p
printk(KERN_ERR "k_fn called with value=%d\n", value);
}
-static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_cur(struct vc_data *vc, unsigned char value, char up_flag)
{
static const char *cur_chars = "BDCA";
@@ -707,7 +717,7 @@ static void k_cur(struct vc_data *vc, unsigned char value, char up_flag, struct
applkey(vc, cur_chars[value], vc_kbd_mode(kbd, VC_CKMODE));
}
-static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_pad(struct vc_data *vc, unsigned char value, char up_flag)
{
static const char pad_chars[] = "0123456789+-*/\015,.?()#";
static const char app_map[] = "pqrstuvwxylSRQMnnmPQS";
@@ -725,34 +735,34 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct
switch (value) {
case KVAL(K_PCOMMA):
case KVAL(K_PDOT):
- k_fn(vc, KVAL(K_REMOVE), 0, regs);
+ k_fn(vc, KVAL(K_REMOVE), 0);
return;
case KVAL(K_P0):
- k_fn(vc, KVAL(K_INSERT), 0, regs);
+ k_fn(vc, KVAL(K_INSERT), 0);
return;
case KVAL(K_P1):
- k_fn(vc, KVAL(K_SELECT), 0, regs);
+ k_fn(vc, KVAL(K_SELECT), 0);
return;
case KVAL(K_P2):
- k_cur(vc, KVAL(K_DOWN), 0, regs);
+ k_cur(vc, KVAL(K_DOWN), 0);
return;
case KVAL(K_P3):
- k_fn(vc, KVAL(K_PGDN), 0, regs);
+ k_fn(vc, KVAL(K_PGDN), 0);
return;
case KVAL(K_P4):
- k_cur(vc, KVAL(K_LEFT), 0, regs);
+ k_cur(vc, KVAL(K_LEFT), 0);
return;
case KVAL(K_P6):
- k_cur(vc, KVAL(K_RIGHT), 0, regs);
+ k_cur(vc, KVAL(K_RIGHT), 0);
return;
case KVAL(K_P7):
- k_fn(vc, KVAL(K_FIND), 0, regs);
+ k_fn(vc, KVAL(K_FIND), 0);
return;
case KVAL(K_P8):
- k_cur(vc, KVAL(K_UP), 0, regs);
+ k_cur(vc, KVAL(K_UP), 0);
return;
case KVAL(K_P9):
- k_fn(vc, KVAL(K_PGUP), 0, regs);
+ k_fn(vc, KVAL(K_PGUP), 0);
return;
case KVAL(K_P5):
applkey(vc, 'G', vc_kbd_mode(kbd, VC_APPLIC));
@@ -764,7 +774,7 @@ static void k_pad(struct vc_data *vc, unsigned char value, char up_flag, struct
put_queue(vc, 10);
}
-static void k_shift(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_shift(struct vc_data *vc, unsigned char value, char up_flag)
{
int old_state = shift_state;
@@ -805,7 +815,7 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag, struc
}
}
-static void k_meta(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_meta(struct vc_data *vc, unsigned char value, char up_flag)
{
if (up_flag)
return;
@@ -817,7 +827,7 @@ static void k_meta(struct vc_data *vc, unsigned char value, char up_flag, struct
put_queue(vc, value | 0x80);
}
-static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag)
{
int base;
@@ -839,16 +849,16 @@ static void k_ascii(struct vc_data *vc, unsigned char value, char up_flag, struc
npadch = npadch * base + value;
}
-static void k_lock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_lock(struct vc_data *vc, unsigned char value, char up_flag)
{
if (up_flag || rep)
return;
chg_vc_kbd_lock(kbd, value);
}
-static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_slock(struct vc_data *vc, unsigned char value, char up_flag)
{
- k_shift(vc, value, up_flag, regs);
+ k_shift(vc, value, up_flag);
if (up_flag || rep)
return;
chg_vc_kbd_slock(kbd, value);
@@ -868,25 +878,25 @@ static unsigned brl_nbchords = 1;
MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
module_param(brl_nbchords, uint, 0644);
-static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag, struct pt_regs *regs)
+static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag)
{
static unsigned long chords;
static unsigned committed;
if (!brl_nbchords)
- k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag, regs);
+ k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag);
else {
committed |= pattern;
chords++;
if (chords == brl_nbchords) {
- k_unicode(vc, BRL_UC_ROW | committed, up_flag, regs);
+ k_unicode(vc, BRL_UC_ROW | committed, up_flag);
chords = 0;
committed = 0;
}
}
}
-static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
+static void k_brl(struct vc_data *vc, unsigned char value, char up_flag)
{
static unsigned pressed,committing;
static unsigned long releasestart;
@@ -898,7 +908,7 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct
}
if (!value) {
- k_unicode(vc, BRL_UC_ROW, up_flag, regs);
+ k_unicode(vc, BRL_UC_ROW, up_flag);
return;
}
@@ -915,13 +925,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct
pressed &= ~(1 << (value - 1));
if (!pressed) {
if (committing) {
- k_brlcommit(vc, committing, 0, regs);
+ k_brlcommit(vc, committing, 0);
committing = 0;
}
}
} else {
if (committing) {
- k_brlcommit(vc, committing, 0, regs);
+ k_brlcommit(vc, committing, 0);
committing = 0;
}
pressed &= ~(1 << (value - 1));
@@ -1125,8 +1135,7 @@ static void kbd_rawcode(unsigned char data)
put_queue(vc, data);
}
-static void kbd_keycode(unsigned int keycode, int down,
- int hw_raw, struct pt_regs *regs)
+static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
{
struct vc_data *vc = vc_cons[fg_console].d;
unsigned short keysym, *key_map;
@@ -1173,7 +1182,7 @@ static void kbd_keycode(unsigned int keycode, int down,
if (sysrq_down && !down && keycode == sysrq_alt_use)
sysrq_down = 0;
if (sysrq_down && down && !rep) {
- handle_sysrq(kbd_sysrq_xlate[keycode], regs, tty);
+ handle_sysrq(kbd_sysrq_xlate[keycode], tty);
return;
}
#endif
@@ -1259,7 +1268,7 @@ static void kbd_keycode(unsigned int keycode, int down,
}
}
- (*k_handler[type])(vc, keysym & 0xff, !down, regs);
+ (*k_handler[type])(vc, keysym & 0xff, !down);
if (type != KT_SLOCK)
kbd->slockstate = 0;
@@ -1271,7 +1280,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
if (event_type == EV_MSC && event_code == MSC_RAW && HW_RAW(handle->dev))
kbd_rawcode(value);
if (event_type == EV_KEY)
- kbd_keycode(event_code, value, HW_RAW(handle->dev), handle->dev->regs);
+ kbd_keycode(event_code, value, HW_RAW(handle->dev));
tasklet_schedule(&keyboard_tasklet);
do_poke_blanked_console = 1;
schedule_console_callback();
@@ -1285,7 +1294,7 @@ static void kbd_event(struct input_handle *handle, unsigned int event_type,
*/
static struct input_handle *kbd_connect(struct input_handler *handler,
struct input_dev *dev,
- struct input_device_id *id)
+ const struct input_device_id *id)
{
struct input_handle *handle;
int i;
@@ -1334,7 +1343,7 @@ static void kbd_start(struct input_handle *handle)
tasklet_enable(&keyboard_tasklet);
}
-static struct input_device_id kbd_ids[] = {
+static const struct input_device_id kbd_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT(EV_KEY) },
@@ -1362,6 +1371,7 @@ static struct input_handler kbd_handler = {
int __init kbd_init(void)
{
int i;
+ int error;
for (i = 0; i < MAX_NR_CONSOLES; i++) {
kbd_table[i].ledflagstate = KBD_DEFLEDS;
@@ -1373,7 +1383,9 @@ int __init kbd_init(void)
kbd_table[i].kbdmode = VC_XLATE;
}
- input_register_handler(&kbd_handler);
+ error = input_register_handler(&kbd_handler);
+ if (error)
+ return error;
tasklet_enable(&keyboard_tasklet);
tasklet_schedule(&keyboard_tasklet);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index f875fda3b089..1ecea7d448f1 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -906,7 +906,7 @@ static int __init lp_init (void)
lp_class = class_create(THIS_MODULE, "printer");
if (IS_ERR(lp_class)) {
err = PTR_ERR(lp_class);
- goto out_devfs;
+ goto out_reg;
}
if (parport_register_driver (&lp_driver)) {
@@ -927,7 +927,7 @@ static int __init lp_init (void)
out_class:
class_destroy(lp_class);
-out_devfs:
+out_reg:
unregister_chrdev(LP_MAJOR, "lp");
return err;
}
diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c
index 0385650f6077..0afb7ba999cf 100644
--- a/drivers/char/mbcs.c
+++ b/drivers/char/mbcs.c
@@ -22,6 +22,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/mm.h>
+#include <linux/fs.h>
#include <linux/uio.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -447,15 +448,15 @@ loff_t mbcs_sram_llseek(struct file * filp, loff_t off, int whence)
loff_t newpos;
switch (whence) {
- case 0: /* SEEK_SET */
+ case SEEK_SET:
newpos = off;
break;
- case 1: /* SEEK_CUR */
+ case SEEK_CUR:
newpos = filp->f_pos + off;
break;
- case 2: /* SEEK_END */
+ case SEEK_END:
newpos = MBCS_SRAM_SIZE + off;
break;
@@ -515,11 +516,10 @@ int mbcs_gscr_mmap(struct file *fp, struct vm_area_struct *vma)
* mbcs_completion_intr_handler - Primary completion handler.
* @irq: irq
* @arg: soft struct for device
- * @ep: regs
*
*/
static irqreturn_t
-mbcs_completion_intr_handler(int irq, void *arg, struct pt_regs *ep)
+mbcs_completion_intr_handler(int irq, void *arg)
{
struct mbcs_soft *soft = (struct mbcs_soft *)arg;
void *mmr_base;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 917b20402664..55473371b7c6 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -26,6 +26,7 @@
#include <linux/backing-dev.h>
#include <linux/bootmem.h>
#include <linux/pipe_fs_i.h>
+#include <linux/pfn.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -238,6 +239,32 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
}
#endif
+#ifndef CONFIG_MMU
+static unsigned long get_unmapped_area_mem(struct file *file,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ if (!valid_mmap_phys_addr_range(pgoff, len))
+ return (unsigned long) -EINVAL;
+ return pgoff;
+}
+
+/* can't do an in-place private mapping if there's no MMU */
+static inline int private_mapping_ok(struct vm_area_struct *vma)
+{
+ return vma->vm_flags & VM_MAYSHARE;
+}
+#else
+#define get_unmapped_area_mem NULL
+
+static inline int private_mapping_ok(struct vm_area_struct *vma)
+{
+ return 1;
+}
+#endif
+
static int mmap_mem(struct file * file, struct vm_area_struct * vma)
{
size_t size = vma->vm_end - vma->vm_start;
@@ -245,6 +272,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
return -EINVAL;
+ if (!private_mapping_ok(vma))
+ return -ENOSYS;
+
vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
size,
vma->vm_page_prot);
@@ -263,8 +293,8 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
{
unsigned long pfn;
- /* Turn a kernel-virtual address into a physical page frame */
- pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
+ /* Turn a pfn offset into an absolute pfn */
+ pfn = PFN_DOWN(virt_to_phys((void *)PAGE_OFFSET)) + vma->vm_pgoff;
/*
* RED-PEN: on some architectures there is more mapped memory
@@ -522,7 +552,7 @@ static ssize_t write_kmem(struct file * file, const char __user * buf,
return virtr + wrote;
}
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
static ssize_t read_port(struct file * file, char __user * buf,
size_t count, loff_t *ppos)
{
@@ -782,6 +812,7 @@ static const struct file_operations mem_fops = {
.write = write_mem,
.mmap = mmap_mem,
.open = open_mem,
+ .get_unmapped_area = get_unmapped_area_mem,
};
static const struct file_operations kmem_fops = {
@@ -790,6 +821,7 @@ static const struct file_operations kmem_fops = {
.write = write_kmem,
.mmap = mmap_kmem,
.open = open_kmem,
+ .get_unmapped_area = get_unmapped_area_mem,
};
static const struct file_operations null_fops = {
@@ -799,7 +831,7 @@ static const struct file_operations null_fops = {
.splice_write = splice_write_null,
};
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
static const struct file_operations port_fops = {
.llseek = memory_lseek,
.read = read_port,
@@ -815,6 +847,10 @@ static const struct file_operations zero_fops = {
.mmap = mmap_zero,
};
+/*
+ * capabilities for /dev/zero
+ * - permits private mappings, "copies" are taken of the source of zeros
+ */
static struct backing_dev_info zero_bdi = {
.capabilities = BDI_CAP_MAP_COPY,
};
@@ -862,14 +898,18 @@ static int memory_open(struct inode * inode, struct file * filp)
switch (iminor(inode)) {
case 1:
filp->f_op = &mem_fops;
+ filp->f_mapping->backing_dev_info =
+ &directly_mappable_cdev_bdi;
break;
case 2:
filp->f_op = &kmem_fops;
+ filp->f_mapping->backing_dev_info =
+ &directly_mappable_cdev_bdi;
break;
case 3:
filp->f_op = &null_fops;
break;
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
case 4:
filp->f_op = &port_fops;
break;
@@ -916,7 +956,7 @@ static const struct {
{1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
{2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
{3, "null", S_IRUGO | S_IWUGO, &null_fops},
-#if defined(CONFIG_ISA) || !defined(__mc68000__)
+#if (defined(CONFIG_ISA) || defined(CONFIG_PCI)) && !defined(__mc68000__)
{4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
#endif
{5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c
index 1f0f2b6dae26..22b9905c1e52 100644
--- a/drivers/char/mmtimer.c
+++ b/drivers/char/mmtimer.c
@@ -422,7 +422,6 @@ static int inline reschedule_periodic_timer(mmtimer_t *x)
* mmtimer_interrupt - timer interrupt handler
* @irq: irq received
* @dev_id: device the irq came from
- * @regs: register state upon receipt of the interrupt
*
* Called when one of the comarators matches the counter, This
* routine will send signals to processes that have requested
@@ -433,7 +432,7 @@ static int inline reschedule_periodic_timer(mmtimer_t *x)
* registers.
*/
static irqreturn_t
-mmtimer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+mmtimer_interrupt(int irq, void *dev_id)
{
int i;
unsigned long expires = 0;
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index a369dd6877d8..96cb1f07332b 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -130,6 +130,7 @@ static moxa_isa_board_conf moxa_isa_boards[] =
typedef struct _moxa_pci_devinfo {
ushort busNum;
ushort devNum;
+ struct pci_dev *pdev;
} moxa_pci_devinfo;
typedef struct _moxa_board_conf {
@@ -260,7 +261,7 @@ static void MoxaPortEnable(int);
static void MoxaPortDisable(int);
static long MoxaPortGetMaxBaud(int);
static long MoxaPortSetBaud(int, long);
-static int MoxaPortSetTermio(int, struct termios *);
+static int MoxaPortSetTermio(int, struct termios *, speed_t);
static int MoxaPortGetLineOut(int, int *, int *);
static void MoxaPortLineCtrl(int, int, int);
static void MoxaPortFlowCtrl(int, int, int, int, int, int);
@@ -281,7 +282,7 @@ static int moxa_get_serial_info(struct moxa_str *, struct serial_struct __user *
static int moxa_set_serial_info(struct moxa_str *, struct serial_struct __user *);
static void MoxaSetFifo(int port, int enable);
-static struct tty_operations moxa_ops = {
+static const struct tty_operations moxa_ops = {
.open = moxa_open,
.close = moxa_close,
.write = moxa_write,
@@ -324,6 +325,9 @@ static int moxa_get_PCI_conf(struct pci_dev *p, int board_type, moxa_board_conf
board->busType = MOXA_BUS_TYPE_PCI;
board->pciInfo.busNum = p->bus->number;
board->pciInfo.devNum = p->devfn >> 3;
+ board->pciInfo.pdev = p;
+ /* don't lose the reference in the next pci_get_device iteration */
+ pci_dev_get(p);
return (0);
}
@@ -493,6 +497,11 @@ static void __exit moxa_exit(void)
if (tty_unregister_driver(moxaDriver))
printk("Couldn't unregister MOXA Intellio family serial driver\n");
put_tty_driver(moxaDriver);
+
+ for (i = 0; i < MAX_BOARDS; i++)
+ if (moxa_boards[i].busType == MOXA_BUS_TYPE_PCI)
+ pci_dev_put(moxa_boards[i].pciInfo.pdev);
+
if (verbose)
printk("Done\n");
}
@@ -986,7 +995,7 @@ static void set_tty_param(struct tty_struct *tty)
if (ts->c_iflag & IXANY)
xany = 1;
MoxaPortFlowCtrl(ch->port, rts, cts, txflow, rxflow, xany);
- MoxaPortSetTermio(ch->port, ts);
+ MoxaPortSetTermio(ch->port, ts, tty_get_baud_rate(tty));
}
static int block_till_ready(struct tty_struct *tty, struct file *filp,
@@ -1900,9 +1909,10 @@ int MoxaPortsOfCard(int cardno)
*
* Function 12: Configure the port.
* Syntax:
- * int MoxaPortSetTermio(int port, struct termios *termio);
+ * int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud);
* int port : port number (0 - 127)
* struct termios * termio : termio structure pointer
+ * speed_t baud : baud rate
*
* return: -1 : this port is invalid or termio == NULL
* 0 : setting O.K.
@@ -2182,11 +2192,10 @@ long MoxaPortSetBaud(int port, long baud)
return (baud);
}
-int MoxaPortSetTermio(int port, struct termios *termio)
+int MoxaPortSetTermio(int port, struct termios *termio, speed_t baud)
{
void __iomem *ofsAddr;
tcflag_t cflag;
- long baud;
tcflag_t mode = 0;
if (moxaChkPort[port] == 0 || termio == 0)
@@ -2222,77 +2231,9 @@ int MoxaPortSetTermio(int port, struct termios *termio)
moxafunc(ofsAddr, FC_SetDataMode, (ushort) mode);
- cflag &= (CBAUD | CBAUDEX);
-#ifndef B921600
-#define B921600 (B460800+1)
-#endif
- switch (cflag) {
- case B921600:
- baud = 921600L;
- break;
- case B460800:
- baud = 460800L;
- break;
- case B230400:
- baud = 230400L;
- break;
- case B115200:
- baud = 115200L;
- break;
- case B57600:
- baud = 57600L;
- break;
- case B38400:
- baud = 38400L;
- break;
- case B19200:
- baud = 19200L;
- break;
- case B9600:
- baud = 9600L;
- break;
- case B4800:
- baud = 4800L;
- break;
- case B2400:
- baud = 2400L;
- break;
- case B1800:
- baud = 1800L;
- break;
- case B1200:
- baud = 1200L;
- break;
- case B600:
- baud = 600L;
- break;
- case B300:
- baud = 300L;
- break;
- case B200:
- baud = 200L;
- break;
- case B150:
- baud = 150L;
- break;
- case B134:
- baud = 134L;
- break;
- case B110:
- baud = 110L;
- break;
- case B75:
- baud = 75L;
- break;
- case B50:
- baud = 50L;
- break;
- default:
- baud = 0;
- }
if ((moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_ISA) ||
(moxa_boards[port / MAX_PORTS_PER_BOARD].boardType == MOXA_BOARD_C320_PCI)) {
- if (baud == 921600L)
+ if (baud >= 921600L)
return (-1);
}
MoxaPortSetBaud(port, baud);
diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c
new file mode 100644
index 000000000000..5c0dec39cf6c
--- /dev/null
+++ b/drivers/char/mspec.c
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2001-2006 Silicon Graphics, Inc. All rights
+ * reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ */
+
+/*
+ * SN Platform Special Memory (mspec) Support
+ *
+ * This driver exports the SN special memory (mspec) facility to user
+ * processes.
+ * There are three types of memory made available thru this driver:
+ * fetchops, uncached and cached.
+ *
+ * Fetchops are atomic memory operations that are implemented in the
+ * memory controller on SGI SN hardware.
+ *
+ * Uncached are used for memory write combining feature of the ia64
+ * cpu.
+ *
+ * Cached are used for areas of memory that are used as cached addresses
+ * on our partition and used as uncached addresses from other partitions.
+ * Due to a design constraint of the SN2 Shub, you can not have processors
+ * on the same FSB perform both a cached and uncached reference to the
+ * same cache line. These special memory cached regions prevent the
+ * kernel from ever dropping in a TLB entry and therefore prevent the
+ * processor from ever speculating a cache line from this page.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/spinlock.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/numa.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/atomic.h>
+#include <asm/tlbflush.h>
+#include <asm/uncached.h>
+#include <asm/sn/addrs.h>
+#include <asm/sn/arch.h>
+#include <asm/sn/mspec.h>
+#include <asm/sn/sn_cpuid.h>
+#include <asm/sn/io.h>
+#include <asm/sn/bte.h>
+#include <asm/sn/shubio.h>
+
+
+#define FETCHOP_ID "SGI Fetchop,"
+#define CACHED_ID "Cached,"
+#define UNCACHED_ID "Uncached"
+#define REVISION "4.0"
+#define MSPEC_BASENAME "mspec"
+
+/*
+ * Page types allocated by the device.
+ */
+enum {
+ MSPEC_FETCHOP = 1,
+ MSPEC_CACHED,
+ MSPEC_UNCACHED
+};
+
+static int is_sn2;
+
+/*
+ * One of these structures is allocated when an mspec region is mmaped. The
+ * structure is pointed to by the vma->vm_private_data field in the vma struct.
+ * This structure is used to record the addresses of the mspec pages.
+ */
+struct vma_data {
+ atomic_t refcnt; /* Number of vmas sharing the data. */
+ spinlock_t lock; /* Serialize access to the vma. */
+ int count; /* Number of pages allocated. */
+ int type; /* Type of pages allocated. */
+ unsigned long maddr[0]; /* Array of MSPEC addresses. */
+};
+
+/* used on shub2 to clear FOP cache in the HUB */
+static unsigned long scratch_page[MAX_NUMNODES];
+#define SH2_AMO_CACHE_ENTRIES 4
+
+static inline int
+mspec_zero_block(unsigned long addr, int len)
+{
+ int status;
+
+ if (is_sn2) {
+ if (is_shub2()) {
+ int nid;
+ void *p;
+ int i;
+
+ nid = nasid_to_cnodeid(get_node_number(__pa(addr)));
+ p = (void *)TO_AMO(scratch_page[nid]);
+
+ for (i=0; i < SH2_AMO_CACHE_ENTRIES; i++) {
+ FETCHOP_LOAD_OP(p, FETCHOP_LOAD);
+ p += FETCHOP_VAR_SIZE;
+ }
+ }
+
+ status = bte_copy(0, addr & ~__IA64_UNCACHED_OFFSET, len,
+ BTE_WACQUIRE | BTE_ZERO_FILL, NULL);
+ } else {
+ memset((char *) addr, 0, len);
+ status = 0;
+ }
+ return status;
+}
+
+/*
+ * mspec_open
+ *
+ * Called when a device mapping is created by a means other than mmap
+ * (via fork, etc.). Increments the reference count on the underlying
+ * mspec data so it is not freed prematurely.
+ */
+static void
+mspec_open(struct vm_area_struct *vma)
+{
+ struct vma_data *vdata;
+
+ vdata = vma->vm_private_data;
+ atomic_inc(&vdata->refcnt);
+}
+
+/*
+ * mspec_close
+ *
+ * Called when unmapping a device mapping. Frees all mspec pages
+ * belonging to the vma.
+ */
+static void
+mspec_close(struct vm_area_struct *vma)
+{
+ struct vma_data *vdata;
+ int i, pages, result, vdata_size;
+
+ vdata = vma->vm_private_data;
+ if (!atomic_dec_and_test(&vdata->refcnt))
+ return;
+
+ pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
+ for (i = 0; i < pages; i++) {
+ if (vdata->maddr[i] == 0)
+ continue;
+ /*
+ * Clear the page before sticking it back
+ * into the pool.
+ */
+ result = mspec_zero_block(vdata->maddr[i], PAGE_SIZE);
+ if (!result)
+ uncached_free_page(vdata->maddr[i]);
+ else
+ printk(KERN_WARNING "mspec_close(): "
+ "failed to zero page %i\n",
+ result);
+ }
+
+ if (vdata_size <= PAGE_SIZE)
+ kfree(vdata);
+ else
+ vfree(vdata);
+}
+
+
+/*
+ * mspec_nopfn
+ *
+ * Creates a mspec page and maps it to user space.
+ */
+static unsigned long
+mspec_nopfn(struct vm_area_struct *vma, unsigned long address)
+{
+ unsigned long paddr, maddr;
+ unsigned long pfn;
+ int index;
+ struct vma_data *vdata = vma->vm_private_data;
+
+ index = (address - vma->vm_start) >> PAGE_SHIFT;
+ maddr = (volatile unsigned long) vdata->maddr[index];
+ if (maddr == 0) {
+ maddr = uncached_alloc_page(numa_node_id());
+ if (maddr == 0)
+ return NOPFN_OOM;
+
+ spin_lock(&vdata->lock);
+ if (vdata->maddr[index] == 0) {
+ vdata->count++;
+ vdata->maddr[index] = maddr;
+ } else {
+ uncached_free_page(maddr);
+ maddr = vdata->maddr[index];
+ }
+ spin_unlock(&vdata->lock);
+ }
+
+ if (vdata->type == MSPEC_FETCHOP)
+ paddr = TO_AMO(maddr);
+ else
+ paddr = __pa(TO_CAC(maddr));
+
+ pfn = paddr >> PAGE_SHIFT;
+
+ return pfn;
+}
+
+static struct vm_operations_struct mspec_vm_ops = {
+ .open = mspec_open,
+ .close = mspec_close,
+ .nopfn = mspec_nopfn
+};
+
+/*
+ * mspec_mmap
+ *
+ * Called when mmaping the device. Initializes the vma with a fault handler
+ * and private data structure necessary to allocate, track, and free the
+ * underlying pages.
+ */
+static int
+mspec_mmap(struct file *file, struct vm_area_struct *vma, int type)
+{
+ struct vma_data *vdata;
+ int pages, vdata_size;
+
+ if (vma->vm_pgoff != 0)
+ return -EINVAL;
+
+ if ((vma->vm_flags & VM_SHARED) == 0)
+ return -EINVAL;
+
+ if ((vma->vm_flags & VM_WRITE) == 0)
+ return -EPERM;
+
+ pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
+ vdata_size = sizeof(struct vma_data) + pages * sizeof(long);
+ if (vdata_size <= PAGE_SIZE)
+ vdata = kmalloc(vdata_size, GFP_KERNEL);
+ else
+ vdata = vmalloc(vdata_size);
+ if (!vdata)
+ return -ENOMEM;
+ memset(vdata, 0, vdata_size);
+
+ vdata->type = type;
+ spin_lock_init(&vdata->lock);
+ vdata->refcnt = ATOMIC_INIT(1);
+ vma->vm_private_data = vdata;
+
+ vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED | VM_PFNMAP);
+ if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED)
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+ vma->vm_ops = &mspec_vm_ops;
+
+ return 0;
+}
+
+static int
+fetchop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return mspec_mmap(file, vma, MSPEC_FETCHOP);
+}
+
+static int
+cached_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return mspec_mmap(file, vma, MSPEC_CACHED);
+}
+
+static int
+uncached_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ return mspec_mmap(file, vma, MSPEC_UNCACHED);
+}
+
+static struct file_operations fetchop_fops = {
+ .owner = THIS_MODULE,
+ .mmap = fetchop_mmap
+};
+
+static struct miscdevice fetchop_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "sgi_fetchop",
+ .fops = &fetchop_fops
+};
+
+static struct file_operations cached_fops = {
+ .owner = THIS_MODULE,
+ .mmap = cached_mmap
+};
+
+static struct miscdevice cached_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mspec_cached",
+ .fops = &cached_fops
+};
+
+static struct file_operations uncached_fops = {
+ .owner = THIS_MODULE,
+ .mmap = uncached_mmap
+};
+
+static struct miscdevice uncached_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "mspec_uncached",
+ .fops = &uncached_fops
+};
+
+/*
+ * mspec_init
+ *
+ * Called at boot time to initialize the mspec facility.
+ */
+static int __init
+mspec_init(void)
+{
+ int ret;
+ int nid;
+
+ /*
+ * The fetchop device only works on SN2 hardware, uncached and cached
+ * memory drivers should both be valid on all ia64 hardware
+ */
+ if (ia64_platform_is("sn2")) {
+ is_sn2 = 1;
+ if (is_shub2()) {
+ ret = -ENOMEM;
+ for_each_online_node(nid) {
+ int actual_nid;
+ int nasid;
+ unsigned long phys;
+
+ scratch_page[nid] = uncached_alloc_page(nid);
+ if (scratch_page[nid] == 0)
+ goto free_scratch_pages;
+ phys = __pa(scratch_page[nid]);
+ nasid = get_node_number(phys);
+ actual_nid = nasid_to_cnodeid(nasid);
+ if (actual_nid != nid)
+ goto free_scratch_pages;
+ }
+ }
+
+ ret = misc_register(&fetchop_miscdev);
+ if (ret) {
+ printk(KERN_ERR
+ "%s: failed to register device %i\n",
+ FETCHOP_ID, ret);
+ goto free_scratch_pages;
+ }
+ }
+ ret = misc_register(&cached_miscdev);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device %i\n",
+ CACHED_ID, ret);
+ if (is_sn2)
+ misc_deregister(&fetchop_miscdev);
+ goto free_scratch_pages;
+ }
+ ret = misc_register(&uncached_miscdev);
+ if (ret) {
+ printk(KERN_ERR "%s: failed to register device %i\n",
+ UNCACHED_ID, ret);
+ misc_deregister(&cached_miscdev);
+ if (is_sn2)
+ misc_deregister(&fetchop_miscdev);
+ goto free_scratch_pages;
+ }
+
+ printk(KERN_INFO "%s %s initialized devices: %s %s %s\n",
+ MSPEC_BASENAME, REVISION, is_sn2 ? FETCHOP_ID : "",
+ CACHED_ID, UNCACHED_ID);
+
+ return 0;
+
+ free_scratch_pages:
+ for_each_node(nid) {
+ if (scratch_page[nid] != 0)
+ uncached_free_page(scratch_page[nid]);
+ }
+ return ret;
+}
+
+static void __exit
+mspec_exit(void)
+{
+ int nid;
+
+ misc_deregister(&uncached_miscdev);
+ misc_deregister(&cached_miscdev);
+ if (is_sn2) {
+ misc_deregister(&fetchop_miscdev);
+
+ for_each_node(nid) {
+ if (scratch_page[nid] != 0)
+ uncached_free_page(scratch_page[nid]);
+ }
+ }
+}
+
+module_init(mspec_init);
+module_exit(mspec_exit);
+
+MODULE_AUTHOR("Silicon Graphics, Inc. <linux-altix@sgi.com>");
+MODULE_DESCRIPTION("Driver for SGI SN special memory operations");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/mwave/README b/drivers/char/mwave/README
index 70f8d19fb79f..480251fc78e2 100644
--- a/drivers/char/mwave/README
+++ b/drivers/char/mwave/README
@@ -41,10 +41,7 @@ Example to enable the 3780i DSP using ttyS1 resources:
Accessing the driver
--------------------
-You must also create a node for the driver. Without devfs:
+You must also create a node for the driver:
mkdir -p /dev/modems
mknod --mode=660 /dev/modems/mwave c 10 219
-With devfs:
- mkdir -p /dev/modems
- ln -s ../misc/mwave /dev/modems/mwave
diff --git a/drivers/char/mwave/mwavedd.c b/drivers/char/mwave/mwavedd.c
index 39a2e661ff55..8d14823b0514 100644
--- a/drivers/char/mwave/mwavedd.c
+++ b/drivers/char/mwave/mwavedd.c
@@ -297,7 +297,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
" ipcnum %x, usIntCount %x\n",
ipcnum,
pDrvData->IPCs[ipcnum].usIntCount);
- if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
+ if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_GET_IPC: Error:"
@@ -355,7 +355,7 @@ static int mwave_ioctl(struct inode *inode, struct file *file,
"mwavedd::mwave_ioctl IOCTL_MW_UNREGISTER_IPC"
" ipcnum %x\n",
ipcnum);
- if (ipcnum > ARRAY_SIZE(pDrvData->IPCs)) {
+ if (ipcnum >= ARRAY_SIZE(pDrvData->IPCs)) {
PRINTK_ERROR(KERN_ERR_MWAVE
"mwavedd::mwave_ioctl:"
" IOCTL_MW_UNREGISTER_IPC:"
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index cc3e54dd7234..f282976daaac 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -95,14 +95,14 @@ static void EnableSRAM(THINKPAD_BD_DATA * pBDData)
}
-static irqreturn_t UartInterrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t UartInterrupt(int irq, void *dev_id)
{
PRINTK_3(TRACE_TP3780I,
"tp3780i::UartInterrupt entry irq %x dev_id %p\n", irq, dev_id);
return IRQ_HANDLED;
}
-static irqreturn_t DspInterrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t DspInterrupt(int irq, void *dev_id)
{
pMWAVE_DEVICE_DATA pDrvData = &mwave_s_mdd;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pDrvData->rBDData.rDspSettings;
diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c
index 556abd3e0d07..048d91142c17 100644
--- a/drivers/char/mxser.c
+++ b/drivers/char/mxser.c
@@ -407,7 +407,7 @@ static void mxser_stop(struct tty_struct *);
static void mxser_start(struct tty_struct *);
static void mxser_hangup(struct tty_struct *);
static void mxser_rs_break(struct tty_struct *, int);
-static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t mxser_interrupt(int, void *);
static void mxser_receive_chars(struct mxser_struct *, int *);
static void mxser_transmit_chars(struct mxser_struct *);
static void mxser_check_modem_status(struct mxser_struct *, int);
@@ -453,7 +453,7 @@ static int CheckIsMoxaMust(int io)
/* above is modified by Victor Yu. 08-15-2002 */
-static struct tty_operations mxser_ops = {
+static const struct tty_operations mxser_ops = {
.open = mxser_open,
.close = mxser_close,
.write = mxser_write,
@@ -1916,7 +1916,7 @@ static void mxser_rs_break(struct tty_struct *tty, int break_state)
/*
* This is the serial driver's generic interrupt routine
*/
-static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mxser_interrupt(int irq, void *dev_id)
{
int status, iir, i;
struct mxser_struct *info;
@@ -2554,71 +2554,7 @@ static int mxser_change_speed(struct mxser_struct *info, struct termios *old_ter
#define B921600 (B460800 +1)
#endif
if (mxser_set_baud_method[info->port] == 0) {
- switch (cflag & (CBAUD | CBAUDEX)) {
- case B921600:
- baud = 921600;
- break;
- case B460800:
- baud = 460800;
- break;
- case B230400:
- baud = 230400;
- break;
- case B115200:
- baud = 115200;
- break;
- case B57600:
- baud = 57600;
- break;
- case B38400:
- baud = 38400;
- break;
- case B19200:
- baud = 19200;
- break;
- case B9600:
- baud = 9600;
- break;
- case B4800:
- baud = 4800;
- break;
- case B2400:
- baud = 2400;
- break;
- case B1800:
- baud = 1800;
- break;
- case B1200:
- baud = 1200;
- break;
- case B600:
- baud = 600;
- break;
- case B300:
- baud = 300;
- break;
- case B200:
- baud = 200;
- break;
- case B150:
- baud = 150;
- break;
- case B134:
- baud = 134;
- break;
- case B110:
- baud = 110;
- break;
- case B75:
- baud = 75;
- break;
- case B50:
- baud = 50;
- break;
- default:
- baud = 0;
- break;
- }
+ baud = tty_get_baud_rate(info->tty);
mxser_set_baud(info, baud);
}
diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c
index 7719bd75810b..4d47d79bcea7 100644
--- a/drivers/char/nsc_gpio.c
+++ b/drivers/char/nsc_gpio.c
@@ -7,7 +7,6 @@
Copyright (c) 2005 Jim Cromie <jim.cromie@gmail.com>
*/
-#include <linux/config.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
index 7c57ebfa8640..2d264971d839 100644
--- a/drivers/char/nwbutton.c
+++ b/drivers/char/nwbutton.c
@@ -127,9 +127,8 @@ static void button_consume_callbacks (int bpcount)
static void button_sequence_finished (unsigned long parameters)
{
#ifdef CONFIG_NWBUTTON_REBOOT /* Reboot using button is enabled */
- if (button_press_count == reboot_count) {
- kill_proc (1, SIGINT, 1); /* Ask init to reboot us */
- }
+ if (button_press_count == reboot_count)
+ kill_cad_pid(SIGINT, 1); /* Ask init to reboot us */
#endif /* CONFIG_NWBUTTON_REBOOT */
button_consume_callbacks (button_press_count);
bcount = sprintf (button_output_buffer, "%d\n", button_press_count);
@@ -145,7 +144,7 @@ static void button_sequence_finished (unsigned long parameters)
* increments the counter.
*/
-static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t button_handler (int irq, void *dev_id)
{
if (button_press_count) {
del_timer (&button_timer);
diff --git a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h
index ddb7b928dcbb..c3ebc16ce8a7 100644
--- a/drivers/char/nwbutton.h
+++ b/drivers/char/nwbutton.h
@@ -25,7 +25,7 @@ struct button_callback {
/* Function prototypes: */
static void button_sequence_finished (unsigned long parameters);
-static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t button_handler (int irq, void *dev_id);
int button_init (void);
int button_add_callback (void (*callback) (void), int count);
int button_del_callback (void (*callback) (void));
diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c
index 84e5a68635f1..ecfaf180e5bd 100644
--- a/drivers/char/pc8736x_gpio.c
+++ b/drivers/char/pc8736x_gpio.c
@@ -188,16 +188,6 @@ static void pc8736x_gpio_set(unsigned minor, int val)
pc8736x_gpio_shadow[port] = val;
}
-static void pc8736x_gpio_set_high(unsigned index)
-{
- pc8736x_gpio_set(index, 1);
-}
-
-static void pc8736x_gpio_set_low(unsigned index)
-{
- pc8736x_gpio_set(index, 0);
-}
-
static int pc8736x_gpio_current(unsigned minor)
{
int port, bit;
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 00f574cbb0d4..1a0bc30b79d1 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -35,7 +35,6 @@
#define MAX_DEVICE_COUNT 4
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -57,7 +56,6 @@
#include <linux/netdevice.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <asm/serial.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
@@ -418,7 +416,7 @@ static void rx_reset_buffers(MGSLPC_INFO *info);
static int rx_alloc_buffers(MGSLPC_INFO *info);
static void rx_free_buffers(MGSLPC_INFO *info);
-static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t mgslpc_isr(int irq, void *dev_id);
/*
* Bottom half interrupt handlers
@@ -1236,9 +1234,8 @@ static void ri_change(MGSLPC_INFO *info)
*
* irq interrupt number that caused interrupt
* dev_id device ID supplied during interrupt registration
- * regs interrupted processor context
*/
-static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t mgslpc_isr(int irq, void *dev_id)
{
MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id;
unsigned short isr;
@@ -3010,7 +3007,7 @@ static struct pcmcia_driver mgslpc_driver = {
.resume = mgslpc_resume,
};
-static struct tty_operations mgslpc_ops = {
+static const struct tty_operations mgslpc_ops = {
.open = mgslpc_open,
.close = mgslpc_close,
.write = mgslpc_write,
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 520d2cf82bc0..efc485edad1c 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -269,7 +269,7 @@ static ssize_t pp_write (struct file * file, const char __user * buf,
return bytes_written;
}
-static void pp_irq (int irq, void * private, struct pt_regs * unused)
+static void pp_irq (int irq, void * private)
{
struct pp_struct * pp = (struct pp_struct *) private;
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 34dd4c38110e..80d3eedd7f96 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -224,7 +224,7 @@ static void pty_set_termios(struct tty_struct *tty, struct termios *old_termios)
tty->termios->c_cflag |= (CS8 | CREAD);
}
-static struct tty_operations pty_ops = {
+static const struct tty_operations pty_ops = {
.open = pty_open,
.close = pty_close,
.write = pty_write,
diff --git a/drivers/char/qtronix.c b/drivers/char/qtronix.c
deleted file mode 100644
index 9d134e98d2a0..000000000000
--- a/drivers/char/qtronix.c
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * Qtronix 990P infrared keyboard driver.
- *
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.com
- *
- *
- * The bottom portion of this driver was take from
- * pc_keyb.c Please see that file for copyrights.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-
-/*
- * NOTE:
- *
- * This driver has only been tested with the Consumer IR
- * port of the ITE 8172 system controller.
- *
- * You do not need this driver if you are using the ps/2 or
- * USB adapter that the keyboard ships with. You only need
- * this driver if your board has a IR port and the keyboard
- * data is being sent directly to the IR. In that case,
- * you also need some low-level IR support. See it8172_cir.c.
- *
- */
-
-#ifdef CONFIG_QTRONIX_KEYBOARD
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/kernel.h>
-
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_int.h>
-#include <asm/it8172/it8172_cir.h>
-
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/init.h>
-#include <linux/kbd_ll.h>
-#include <linux/delay.h>
-#include <linux/poll.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/kbd_kern.h>
-#include <linux/smp_lock.h>
-#include <asm/io.h>
-#include <linux/pc_keyb.h>
-
-#include <asm/keyboard.h>
-#include <linux/bitops.h>
-#include <asm/uaccess.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#define leading1 0
-#define leading2 0xF
-
-#define KBD_CIR_PORT 0
-#define AUX_RECONNECT 170 /* scancode when ps2 device is plugged (back) in */
-
-static int data_index;
-struct cir_port *cir;
-static unsigned char kbdbytes[5];
-static unsigned char cir_data[32]; /* we only need 16 chars */
-
-static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs);
-static int handle_data(unsigned char *p_data);
-static inline void handle_mouse_event(unsigned char scancode);
-static inline void handle_keyboard_event(unsigned char scancode, int down);
-static int __init psaux_init(void);
-
-static struct aux_queue *queue; /* Mouse data buffer. */
-static int aux_count = 0;
-
-/*
- * Keys accessed through the 'Fn' key
- * The Fn key does not produce a key-up sequence. So, the first
- * time the user presses it, it will be key-down event. The key
- * stays down until the user presses it again.
- */
-#define NUM_FN_KEYS 56
-static unsigned char fn_keys[NUM_FN_KEYS] = {
- 0,0,0,0,0,0,0,0, /* 0 7 */
- 8,9,10,93,0,0,0,0, /* 8 15 */
- 0,0,0,0,0,0,0,5, /* 16 23 */
- 6,7,91,0,0,0,0,0, /* 24 31 */
- 0,0,0,0,0,2,3,4, /* 32 39 */
- 92,0,0,0,0,0,0,0, /* 40 47 */
- 0,0,0,0,11,0,94,95 /* 48 55 */
-
-};
-
-void __init init_qtronix_990P_kbd(void)
-{
- int retval;
-
- cir = (struct cir_port *)kmalloc(sizeof(struct cir_port), GFP_KERNEL);
- if (!cir) {
- printk("Unable to initialize Qtronix keyboard\n");
- return;
- }
-
- /*
- * revisit
- * this should be programmable, somehow by the, by the user.
- */
- cir->port = KBD_CIR_PORT;
- cir->baud_rate = 0x1d;
- cir->rdwos = 0;
- cir->rxdcr = 0x3;
- cir->hcfs = 0;
- cir->fifo_tl = 0;
- cir->cfq = 0x1d;
- cir_port_init(cir);
-
- retval = request_irq(IT8172_CIR0_IRQ, kbd_int_handler,
- (unsigned long )(IRQF_DISABLED|IRQF_SHARED),
- (const char *)"Qtronix IR Keyboard", (void *)cir);
-
- if (retval) {
- printk("unable to allocate cir %d irq %d\n",
- cir->port, IT8172_CIR0_IRQ);
- }
-#ifdef CONFIG_PSMOUSE
- psaux_init();
-#endif
-}
-
-static inline unsigned char BitReverse(unsigned short key)
-{
- unsigned char rkey = 0;
- rkey |= (key & 0x1) << 7;
- rkey |= (key & 0x2) << 5;
- rkey |= (key & 0x4) << 3;
- rkey |= (key & 0x8) << 1;
- rkey |= (key & 0x10) >> 1;
- rkey |= (key & 0x20) >> 3;
- rkey |= (key & 0x40) >> 5;
- rkey |= (key & 0x80) >> 7;
- return rkey;
-
-}
-
-
-static inline u_int8_t UpperByte(u_int8_t data)
-{
- return (data >> 4);
-}
-
-
-static inline u_int8_t LowerByte(u_int8_t data)
-{
- return (data & 0xF);
-}
-
-
-int CheckSumOk(u_int8_t byte1, u_int8_t byte2,
- u_int8_t byte3, u_int8_t byte4, u_int8_t byte5)
-{
- u_int8_t CheckSum;
-
- CheckSum = (byte1 & 0x0F) + byte2 + byte3 + byte4 + byte5;
- if ( LowerByte(UpperByte(CheckSum) + LowerByte(CheckSum)) != UpperByte(byte1) )
- return 0;
- else
- return 1;
-}
-
-
-static void kbd_int_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct cir_port *cir;
- int j;
- unsigned char int_status;
-
- cir = (struct cir_port *)dev_id;
- int_status = get_int_status(cir);
- if (int_status & 0x4) {
- clear_fifo(cir);
- return;
- }
-
- while (cir_get_rx_count(cir)) {
-
- cir_data[data_index] = cir_read_data(cir);
-
- if (data_index == 0) {/* expecting first byte */
- if (cir_data[data_index] != leading1) {
- //printk("!leading byte %x\n", cir_data[data_index]);
- set_rx_active(cir);
- clear_fifo(cir);
- continue;
- }
- }
- if (data_index == 1) {
- if ((cir_data[data_index] & 0xf) != leading2) {
- set_rx_active(cir);
- data_index = 0; /* start over */
- clear_fifo(cir);
- continue;
- }
- }
-
- if ( (cir_data[data_index] == 0xff)) { /* last byte */
- //printk("data_index %d\n", data_index);
- set_rx_active(cir);
-#if 0
- for (j=0; j<=data_index; j++) {
- printk("rx_data %d: %x\n", j, cir_data[j]);
- }
-#endif
- data_index = 0;
- handle_data(cir_data);
- return;
- }
- else if (data_index>16) {
- set_rx_active(cir);
-#if 0
- printk("warning: data_index %d\n", data_index);
- for (j=0; j<=data_index; j++) {
- printk("rx_data %d: %x\n", j, cir_data[j]);
- }
-#endif
- data_index = 0;
- clear_fifo(cir);
- return;
- }
- data_index++;
- }
-}
-
-
-#define NUM_KBD_BYTES 5
-static int handle_data(unsigned char *p_data)
-{
- u_int32_t bit_bucket;
- u_int32_t i, j;
- u_int32_t got_bits, next_byte;
- int down = 0;
-
- /* Reorganize the bit stream */
- for (i=0; i<16; i++)
- p_data[i] = BitReverse(~p_data[i]);
-
- /*
- * We've already previously checked that p_data[0]
- * is equal to leading1 and that (p_data[1] & 0xf)
- * is equal to leading2. These twelve bits are the
- * leader code. We can now throw them away (the 12
- * bits) and continue parsing the stream.
- */
- bit_bucket = p_data[1] << 12;
- got_bits = 4;
- next_byte = 2;
-
- /*
- * Process four bits at a time
- */
- for (i=0; i<NUM_KBD_BYTES; i++) {
-
- kbdbytes[i]=0;
-
- for (j=0; j<8; j++) /* 8 bits per byte */
- {
- if (got_bits < 4) {
- bit_bucket |= (p_data[next_byte++] << (8 - got_bits));
- got_bits += 8;
- }
-
- if ((bit_bucket & 0xF000) == 0x8000) {
- /* Convert 1000b to 1 */
- kbdbytes[i] = 0x80 | (kbdbytes[i] >> 1);
- got_bits -= 4;
- bit_bucket = bit_bucket << 4;
- }
- else if ((bit_bucket & 0xC000) == 0x8000) {
- /* Convert 10b to 0 */
- kbdbytes[i] = kbdbytes[i] >> 1;
- got_bits -= 2;
- bit_bucket = bit_bucket << 2;
- }
- else {
- /* bad serial stream */
- return 1;
- }
-
- if (next_byte > 16) {
- //printk("error: too many bytes\n");
- return 1;
- }
- }
- }
-
-
- if (!CheckSumOk(kbdbytes[0], kbdbytes[1],
- kbdbytes[2], kbdbytes[3], kbdbytes[4])) {
- //printk("checksum failed\n");
- return 1;
- }
-
- if (kbdbytes[1] & 0x08) {
- //printk("m: %x %x %x\n", kbdbytes[1], kbdbytes[2], kbdbytes[3]);
- handle_mouse_event(kbdbytes[1]);
- handle_mouse_event(kbdbytes[2]);
- handle_mouse_event(kbdbytes[3]);
- }
- else {
- if (kbdbytes[2] == 0) down = 1;
-#if 0
- if (down)
- printk("down %d\n", kbdbytes[3]);
- else
- printk("up %d\n", kbdbytes[3]);
-#endif
- handle_keyboard_event(kbdbytes[3], down);
- }
- return 0;
-}
-
-
-DEFINE_SPINLOCK(kbd_controller_lock);
-static unsigned char handle_kbd_event(void);
-
-
-int kbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
- printk("kbd_setkeycode scancode %x keycode %x\n", scancode, keycode);
- return 0;
-}
-
-int kbd_getkeycode(unsigned int scancode)
-{
- return scancode;
-}
-
-
-int kbd_translate(unsigned char scancode, unsigned char *keycode,
- char raw_mode)
-{
- static int prev_scancode = 0;
-
- if (scancode == 0x00 || scancode == 0xff) {
- prev_scancode = 0;
- return 0;
- }
-
- /* todo */
- if (!prev_scancode && scancode == 160) { /* Fn key down */
- //printk("Fn key down\n");
- prev_scancode = 160;
- return 0;
- }
- else if (prev_scancode && scancode == 160) { /* Fn key up */
- //printk("Fn key up\n");
- prev_scancode = 0;
- return 0;
- }
-
- /* todo */
- if (prev_scancode == 160) {
- if (scancode <= NUM_FN_KEYS) {
- *keycode = fn_keys[scancode];
- //printk("fn keycode %d\n", *keycode);
- }
- else
- return 0;
- }
- else if (scancode <= 127) {
- *keycode = scancode;
- }
- else
- return 0;
-
-
- return 1;
-}
-
-char kbd_unexpected_up(unsigned char keycode)
-{
- //printk("kbd_unexpected_up\n");
- return 0;
-}
-
-static unsigned char kbd_exists = 1;
-
-static inline void handle_keyboard_event(unsigned char scancode, int down)
-{
- kbd_exists = 1;
- handle_scancode(scancode, down);
- tasklet_schedule(&keyboard_tasklet);
-}
-
-
-void kbd_leds(unsigned char leds)
-{
-}
-
-/* dummy */
-void kbd_init_hw(void)
-{
-}
-
-
-
-static inline void handle_mouse_event(unsigned char scancode)
-{
- if(scancode == AUX_RECONNECT){
- queue->head = queue->tail = 0; /* Flush input queue */
- // __aux_write_ack(AUX_ENABLE_DEV); /* ping the mouse :) */
- return;
- }
-
- if (aux_count) {
- int head = queue->head;
-
- queue->buf[head] = scancode;
- head = (head + 1) & (AUX_BUF_SIZE-1);
- if (head != queue->tail) {
- queue->head = head;
- kill_fasync(&queue->fasync, SIGIO, POLL_IN);
- wake_up_interruptible(&queue->proc_list);
- }
- }
-}
-
-static unsigned char get_from_queue(void)
-{
- unsigned char result;
- unsigned long flags;
-
- spin_lock_irqsave(&kbd_controller_lock, flags);
- result = queue->buf[queue->tail];
- queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
- spin_unlock_irqrestore(&kbd_controller_lock, flags);
- return result;
-}
-
-
-static inline int queue_empty(void)
-{
- return queue->head == queue->tail;
-}
-
-static int fasync_aux(int fd, struct file *filp, int on)
-{
- int retval;
-
- //printk("fasync_aux\n");
- retval = fasync_helper(fd, filp, on, &queue->fasync);
- if (retval < 0)
- return retval;
- return 0;
-}
-
-
-/*
- * Random magic cookie for the aux device
- */
-#define AUX_DEV ((void *)queue)
-
-static int release_aux(struct inode * inode, struct file * file)
-{
- fasync_aux(-1, file, 0);
- aux_count--;
- return 0;
-}
-
-static int open_aux(struct inode * inode, struct file * file)
-{
- if (aux_count++) {
- return 0;
- }
- queue->head = queue->tail = 0; /* Flush input queue */
- return 0;
-}
-
-/*
- * Put bytes from input queue to buffer.
- */
-
-static ssize_t read_aux(struct file * file, char * buffer,
- size_t count, loff_t *ppos)
-{
- DECLARE_WAITQUEUE(wait, current);
- ssize_t i = count;
- unsigned char c;
-
- if (queue_empty()) {
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
- add_wait_queue(&queue->proc_list, &wait);
-repeat:
- set_current_state(TASK_INTERRUPTIBLE);
- if (queue_empty() && !signal_pending(current)) {
- schedule();
- goto repeat;
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&queue->proc_list, &wait);
- }
- while (i > 0 && !queue_empty()) {
- c = get_from_queue();
- put_user(c, buffer++);
- i--;
- }
- if (count-i) {
- struct inode *inode = file->f_dentry->d_inode;
- inode->i_atime = current_fs_time(inode->i_sb);
- return count-i;
- }
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/*
- * Write to the aux device.
- */
-
-static ssize_t write_aux(struct file * file, const char * buffer,
- size_t count, loff_t *ppos)
-{
- /*
- * The ITE boards this was tested on did not have the
- * transmit wires connected.
- */
- return count;
-}
-
-static unsigned int aux_poll(struct file *file, poll_table * wait)
-{
- poll_wait(file, &queue->proc_list, wait);
- if (!queue_empty())
- return POLLIN | POLLRDNORM;
- return 0;
-}
-
-struct file_operations psaux_fops = {
- .read = read_aux,
- .write = write_aux,
- .poll = aux_poll,
- .open = open_aux,
- .release = release_aux,
- .fasync = fasync_aux,
-};
-
-/*
- * Initialize driver.
- */
-static struct miscdevice psaux_mouse = {
- PSMOUSE_MINOR, "psaux", &psaux_fops
-};
-
-static int __init psaux_init(void)
-{
- int retval;
-
- retval = misc_register(&psaux_mouse);
- if(retval < 0)
- return retval;
-
- queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
- if (!queue) {
- misc_deregister(&psaux_mouse);
- return -ENOMEM;
- }
-
- memset(queue, 0, sizeof(*queue));
- queue->head = queue->tail = 0;
- init_waitqueue_head(&queue->proc_list);
-
- return 0;
-}
-module_init(init_qtronix_990P_kbd);
-#endif
diff --git a/drivers/char/qtronixmap.c_shipped b/drivers/char/qtronixmap.c_shipped
deleted file mode 100644
index 1e2b92b7d57a..000000000000
--- a/drivers/char/qtronixmap.c_shipped
+++ /dev/null
@@ -1,265 +0,0 @@
-
-/* Do not edit this file! It was automatically generated by */
-/* loadkeys --mktable defkeymap.map > defkeymap.c */
-
-#include <linux/types.h>
-#include <linux/keyboard.h>
-#include <linux/kd.h>
-
-u_short plain_map[NR_KEYS] = {
- 0xf200, 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
- 0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf200, 0xf07f,
- 0xf009, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75,
- 0xfb69, 0xfb6f, 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf207, 0xfb61,
- 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c,
- 0xf03b, 0xf027, 0xf060, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78,
- 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f,
- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200,
- 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
- 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
-};
-
-u_short shift_map[NR_KEYS] = {
- 0xf200, 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e,
- 0xf026, 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf200, 0xf07f,
- 0xf009, 0xfb51, 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55,
- 0xfb49, 0xfb4f, 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf207, 0xfb41,
- 0xfb53, 0xfb44, 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c,
- 0xf03a, 0xf022, 0xf07e, 0xf201, 0xf700, 0xf200, 0xfb5a, 0xfb58,
- 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f,
- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf020, 0xf703, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf20b, 0xf20a, 0xf200,
- 0xf200, 0xf602, 0xf213, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf01b, 0xf200,
- 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, 0xf111,
- 0xf112, 0xf113, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
-};
-
-u_short altgr_map[NR_KEYS] = {
- 0xf200, 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200,
- 0xf07b, 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75,
- 0xfb69, 0xfb6f, 0xfb70, 0xf200, 0xf200, 0xf200, 0xf207, 0xfb61,
- 0xfb73, 0xfb64, 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c,
- 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xfb7a, 0xfb78,
- 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
- 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, 0xf513,
- 0xf514, 0xf515, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
-};
-
-u_short ctrl_map[NR_KEYS] = {
- 0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
- 0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf008,
- 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015,
- 0xf009, 0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf01c, 0xf207, 0xf001,
- 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c,
- 0xf007, 0xf000, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018,
- 0xf003, 0xf016, 0xf002, 0xf00e, 0xf20e, 0xf07f, 0xf200, 0xf200,
- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf000, 0xf703, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
- 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, 0xf107,
- 0xf108, 0xf109, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
-};
-
-u_short shift_ctrl_map[NR_KEYS] = {
- 0xf200, 0xf200, 0xf200, 0xf000, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015,
- 0xf009, 0xf00f, 0xf010, 0xf200, 0xf200, 0xf200, 0xf207, 0xf001,
- 0xf013, 0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c,
- 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf01a, 0xf018,
- 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
-};
-
-u_short alt_map[NR_KEYS] = {
- 0xf200, 0xf81b, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836,
- 0xf837, 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf200, 0xf87f,
- 0xf809, 0xf871, 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875,
- 0xf869, 0xf86f, 0xf870, 0xf85b, 0xf85d, 0xf85c, 0xf207, 0xf861,
- 0xf873, 0xf864, 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf83b,
- 0xf827, 0xf860, 0xf200, 0xf80d, 0xf700, 0xf200, 0xf87a, 0xf878,
- 0xf863, 0xf876, 0xf862, 0xf82c, 0xf82e, 0xf82f, 0xf200, 0xf200,
- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf820, 0xf703, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf210,
- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
- 0xf200, 0xf211, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
- 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
- 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
-};
-
-u_short ctrl_alt_map[NR_KEYS] = {
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815,
- 0xf809, 0xf80f, 0xf810, 0xf200, 0xf200, 0xf200, 0xf207, 0xf801,
- 0xf813, 0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c,
- 0xf200, 0xf200, 0xf200, 0xf201, 0xf700, 0xf200, 0xf81a, 0xf818,
- 0xf803, 0xf816, 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf700, 0xf702, 0xf200, 0xf703, 0xf200, 0xf703, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf601,
- 0xf200, 0xf200, 0xf200, 0xf603, 0xf600, 0xf118, 0xf119, 0xf200,
- 0xf200, 0xf602, 0xf208, 0xf02d, 0xf02b, 0xf30c, 0xf02e, 0xf30d,
- 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
- 0xf200, 0xf200, 0xf200, 0xf117, 0xf600, 0xf200, 0xf200, 0xf200,
- 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, 0xf507,
- 0xf508, 0xf509, 0xf200, 0xf200, 0xf200, 0xf200, 0xf11d, 0xf200,
-};
-
-ushort *key_maps[MAX_NR_KEYMAPS] = {
- plain_map, shift_map, altgr_map, 0,
- ctrl_map, shift_ctrl_map, 0, 0,
- alt_map, 0, 0, 0,
- ctrl_alt_map, 0
-};
-
-unsigned int keymap_count = 7;
-
-
-/*
- * Philosophy: most people do not define more strings, but they who do
- * often want quite a lot of string space. So, we statically allocate
- * the default and allocate dynamically in chunks of 512 bytes.
- */
-
-char func_buf[] = {
- '\033', '[', '[', 'A', 0,
- '\033', '[', '[', 'B', 0,
- '\033', '[', '[', 'C', 0,
- '\033', '[', '[', 'D', 0,
- '\033', '[', '[', 'E', 0,
- '\033', '[', '1', '7', '~', 0,
- '\033', '[', '1', '8', '~', 0,
- '\033', '[', '1', '9', '~', 0,
- '\033', '[', '2', '0', '~', 0,
- '\033', '[', '2', '1', '~', 0,
- '\033', '[', '2', '3', '~', 0,
- '\033', '[', '2', '4', '~', 0,
- '\033', '[', '2', '5', '~', 0,
- '\033', '[', '2', '6', '~', 0,
- '\033', '[', '2', '8', '~', 0,
- '\033', '[', '2', '9', '~', 0,
- '\033', '[', '3', '1', '~', 0,
- '\033', '[', '3', '2', '~', 0,
- '\033', '[', '3', '3', '~', 0,
- '\033', '[', '3', '4', '~', 0,
- '\033', '[', '1', '~', 0,
- '\033', '[', '2', '~', 0,
- '\033', '[', '3', '~', 0,
- '\033', '[', '4', '~', 0,
- '\033', '[', '5', '~', 0,
- '\033', '[', '6', '~', 0,
- '\033', '[', 'M', 0,
- '\033', '[', 'P', 0,
-};
-
-
-char *funcbufptr = func_buf;
-int funcbufsize = sizeof(func_buf);
-int funcbufleft = 0; /* space left */
-
-char *func_table[MAX_NR_FUNC] = {
- func_buf + 0,
- func_buf + 5,
- func_buf + 10,
- func_buf + 15,
- func_buf + 20,
- func_buf + 25,
- func_buf + 31,
- func_buf + 37,
- func_buf + 43,
- func_buf + 49,
- func_buf + 55,
- func_buf + 61,
- func_buf + 67,
- func_buf + 73,
- func_buf + 79,
- func_buf + 85,
- func_buf + 91,
- func_buf + 97,
- func_buf + 103,
- func_buf + 109,
- func_buf + 115,
- func_buf + 120,
- func_buf + 125,
- func_buf + 130,
- func_buf + 135,
- func_buf + 140,
- func_buf + 145,
- 0,
- 0,
- func_buf + 149,
- 0,
-};
-
-struct kbdiacr accent_table[MAX_DIACR] = {
- {'`', 'A', 'À'}, {'`', 'a', 'à'},
- {'\'', 'A', 'Á'}, {'\'', 'a', 'á'},
- {'^', 'A', 'Â'}, {'^', 'a', 'â'},
- {'~', 'A', 'Ã'}, {'~', 'a', 'ã'},
- {'"', 'A', 'Ä'}, {'"', 'a', 'ä'},
- {'O', 'A', 'Å'}, {'o', 'a', 'å'},
- {'0', 'A', 'Å'}, {'0', 'a', 'å'},
- {'A', 'A', 'Å'}, {'a', 'a', 'å'},
- {'A', 'E', 'Æ'}, {'a', 'e', 'æ'},
- {',', 'C', 'Ç'}, {',', 'c', 'ç'},
- {'`', 'E', 'È'}, {'`', 'e', 'è'},
- {'\'', 'E', 'É'}, {'\'', 'e', 'é'},
- {'^', 'E', 'Ê'}, {'^', 'e', 'ê'},
- {'"', 'E', 'Ë'}, {'"', 'e', 'ë'},
- {'`', 'I', 'Ì'}, {'`', 'i', 'ì'},
- {'\'', 'I', 'Í'}, {'\'', 'i', 'í'},
- {'^', 'I', 'Î'}, {'^', 'i', 'î'},
- {'"', 'I', 'Ï'}, {'"', 'i', 'ï'},
- {'-', 'D', 'Ð'}, {'-', 'd', 'ð'},
- {'~', 'N', 'Ñ'}, {'~', 'n', 'ñ'},
- {'`', 'O', 'Ò'}, {'`', 'o', 'ò'},
- {'\'', 'O', 'Ó'}, {'\'', 'o', 'ó'},
- {'^', 'O', 'Ô'}, {'^', 'o', 'ô'},
- {'~', 'O', 'Õ'}, {'~', 'o', 'õ'},
- {'"', 'O', 'Ö'}, {'"', 'o', 'ö'},
- {'/', 'O', 'Ø'}, {'/', 'o', 'ø'},
- {'`', 'U', 'Ù'}, {'`', 'u', 'ù'},
- {'\'', 'U', 'Ú'}, {'\'', 'u', 'ú'},
- {'^', 'U', 'Û'}, {'^', 'u', 'û'},
- {'"', 'U', 'Ü'}, {'"', 'u', 'ü'},
- {'\'', 'Y', 'Ý'}, {'\'', 'y', 'ý'},
- {'T', 'H', 'Þ'}, {'t', 'h', 'þ'},
- {'s', 's', 'ß'}, {'"', 'y', 'ÿ'},
- {'s', 'z', 'ß'}, {'i', 'j', 'ÿ'},
-};
-
-unsigned int accent_table_size = 68;
diff --git a/drivers/char/qtronixmap.map b/drivers/char/qtronixmap.map
deleted file mode 100644
index 8d1ff5c1e281..000000000000
--- a/drivers/char/qtronixmap.map
+++ /dev/null
@@ -1,287 +0,0 @@
-# Default kernel keymap. This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# Change the above line into
-# keymaps 0-2,4-6,8,12
-# in case you want the entries
-# altgr control keycode 83 = Boot
-# altgr control keycode 111 = Boot
-# below.
-#
-# In fact AltGr is used very little, and one more keymap can
-# be saved by mapping AltGr to Alt (and adapting a few entries):
-# keycode 100 = Alt
-#
-keycode 1 = grave asciitilde
- alt keycode 1 = Meta_Escape
-keycode 2 = one exclam
- alt keycode 2 = Meta_one
-keycode 3 = two at at
- control keycode 3 = nul
- shift control keycode 3 = nul
- alt keycode 3 = Meta_two
-keycode 4 = three numbersign
- control keycode 4 = Escape
- alt keycode 4 = Meta_three
-keycode 5 = four dollar dollar
- control keycode 5 = Control_backslash
- alt keycode 5 = Meta_four
-keycode 6 = five percent
- control keycode 6 = Control_bracketright
- alt keycode 6 = Meta_five
-keycode 7 = six asciicircum
- control keycode 7 = Control_asciicircum
- alt keycode 7 = Meta_six
-keycode 8 = seven ampersand braceleft
- control keycode 8 = Control_underscore
- alt keycode 8 = Meta_seven
-keycode 9 = eight asterisk bracketleft
- control keycode 9 = Delete
- alt keycode 9 = Meta_eight
-keycode 10 = nine parenleft bracketright
- alt keycode 10 = Meta_nine
-keycode 11 = zero parenright braceright
- alt keycode 11 = Meta_zero
-keycode 12 = minus underscore backslash
- control keycode 12 = Control_underscore
- shift control keycode 12 = Control_underscore
- alt keycode 12 = Meta_minus
-keycode 13 = equal plus
- alt keycode 13 = Meta_equal
-keycode 15 = Delete Delete
- control keycode 15 = BackSpace
- alt keycode 15 = Meta_Delete
-keycode 16 = Tab Tab
- alt keycode 16 = Meta_Tab
-keycode 17 = q
-keycode 18 = w
-keycode 19 = e
-keycode 20 = r
-keycode 21 = t
-keycode 22 = y
-keycode 23 = u
-keycode 24 = i
-keycode 25 = o
-keycode 26 = p
-keycode 27 = bracketleft braceleft
- control keycode 27 = Escape
- alt keycode 27 = Meta_bracketleft
-keycode 28 = bracketright braceright
- control keycode 28 = Control_bracketright
- alt keycode 28 = Meta_bracketright
-keycode 29 = backslash bar
- control keycode 29 = Control_backslash
- alt keycode 29 = Meta_backslash
-keycode 30 = Caps_Lock
-keycode 31 = a
-keycode 32 = s
-keycode 33 = d
-keycode 34 = f
-keycode 35 = g
-keycode 36 = h
-keycode 37 = j
-keycode 38 = k
-keycode 39 = l
-keycode 40 = semicolon colon
- alt keycode 39 = Meta_semicolon
-keycode 41 = apostrophe quotedbl
- control keycode 40 = Control_g
- alt keycode 40 = Meta_apostrophe
-keycode 42 = grave asciitilde
- control keycode 41 = nul
- alt keycode 41 = Meta_grave
-keycode 43 = Return
- alt keycode 43 = Meta_Control_m
-keycode 44 = Shift
-keycode 46 = z
-keycode 47 = x
-keycode 48 = c
-keycode 49 = v
-keycode 50 = b
-keycode 51 = n
-keycode 52 = m
-keycode 53 = comma less
- alt keycode 51 = Meta_comma
-keycode 54 = period greater
- control keycode 52 = Compose
- alt keycode 52 = Meta_period
-keycode 55 = slash question
- control keycode 53 = Delete
- alt keycode 53 = Meta_slash
-keycode 57 = Shift
-keycode 58 = Control
-keycode 60 = Alt
-keycode 61 = space space
- control keycode 61 = nul
- alt keycode 61 = Meta_space
-keycode 62 = Alt
-
-keycode 75 = Insert
-keycode 76 = Delete
-
-keycode 83 = Up
-keycode 84 = Down
-
-keycode 85 = Prior
- shift keycode 85 = Scroll_Backward
-keycode 86 = Next
- shift keycode 86 = Scroll_Forward
-keycode 89 = Right
- alt keycode 89 = Incr_Console
-keycode 79 = Left
- alt keycode 79 = Decr_Console
-
-keycode 90 = Num_Lock
- shift keycode 90 = Bare_Num_Lock
-
-keycode 91 = minus
-keycode 92 = plus
-keycode 93 = KP_Multiply
-keycode 94 = period
-keycode 95 = KP_Divide
-
-keycode 107 = Select
-keycode 108 = Down
-
-keycode 110 = Escape Escape
- alt keycode 1 = Meta_Escape
-
-keycode 112 = F1 F11 Console_13
- control keycode 112 = F1
- alt keycode 112 = Console_1
- control alt keycode 112 = Console_1
-keycode 113 = F2 F12 Console_14
- control keycode 113 = F2
- alt keycode 113 = Console_2
- control alt keycode 113 = Console_2
-keycode 114 = F3 F13 Console_15
- control keycode 114 = F3
- alt keycode 114 = Console_3
- control alt keycode 114 = Console_3
-keycode 115 = F4 F14 Console_16
- control keycode 115 = F4
- alt keycode 115 = Console_4
- control alt keycode 115 = Console_4
-keycode 116 = F5 F15 Console_17
- control keycode 116 = F5
- alt keycode 116 = Console_5
- control alt keycode 116 = Console_5
-keycode 117 = F6 F16 Console_18
- control keycode 117 = F6
- alt keycode 117 = Console_6
- control alt keycode 117 = Console_6
-keycode 118 = F7 F17 Console_19
- control keycode 118 = F7
- alt keycode 118 = Console_7
- control alt keycode 118 = Console_7
-keycode 119 = F8 F18 Console_20
- control keycode 119 = F8
- alt keycode 119 = Console_8
- control alt keycode 119 = Console_8
-keycode 120 = F9 F19 Console_21
- control keycode 120 = F9
- alt keycode 120 = Console_9
- control alt keycode 120 = Console_9
-keycode 121 = F10 F20 Console_22
- control keycode 121 = F10
- alt keycode 121 = Console_10
- control alt keycode 121 = Console_10
-
-keycode 126 = Pause
-
-
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 4c3a5ca9d8f7..eb6b13f4211a 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -645,6 +645,7 @@ void add_input_randomness(unsigned int type, unsigned int code,
add_timer_randomness(&input_timer_state,
(type << 4) ^ code ^ (code >> 4) ^ value);
}
+EXPORT_SYMBOL_GPL(add_input_randomness);
void add_interrupt_randomness(int irq)
{
@@ -655,6 +656,7 @@ void add_interrupt_randomness(int irq)
add_timer_randomness(irq_timer_state[irq], 0x100 + irq);
}
+#ifdef CONFIG_BLOCK
void add_disk_randomness(struct gendisk *disk)
{
if (!disk || !disk->random)
@@ -667,6 +669,7 @@ void add_disk_randomness(struct gendisk *disk)
}
EXPORT_SYMBOL(add_disk_randomness);
+#endif
#define EXTRACT_SIZE 10
@@ -887,8 +890,8 @@ static void init_std_data(struct entropy_store *r)
do_gettimeofday(&tv);
add_entropy_words(r, (__u32 *)&tv, sizeof(tv)/4);
- add_entropy_words(r, (__u32 *)&system_utsname,
- sizeof(system_utsname)/4);
+ add_entropy_words(r, (__u32 *)utsname(),
+ sizeof(*(utsname()))/4);
}
static int __init rand_initialize(void)
@@ -918,6 +921,7 @@ void rand_initialize_irq(int irq)
}
}
+#ifdef CONFIG_BLOCK
void rand_initialize_disk(struct gendisk *disk)
{
struct timer_rand_state *state;
@@ -932,6 +936,7 @@ void rand_initialize_disk(struct gendisk *disk)
disk->random = state;
}
}
+#endif
static ssize_t
random_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index 579868af4a54..89b718e326e5 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -238,39 +238,14 @@ out:
return err;
}
-static ssize_t raw_file_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct iovec local_iov = {
- .iov_base = (char __user *)buf,
- .iov_len = count
- };
-
- return generic_file_write_nolock(file, &local_iov, 1, ppos);
-}
-
-static ssize_t raw_file_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
-{
- struct iovec local_iov = {
- .iov_base = (char __user *)buf,
- .iov_len = count
- };
-
- return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
-}
-
-
static const struct file_operations raw_fops = {
- .read = generic_file_read,
+ .read = do_sync_read,
.aio_read = generic_file_aio_read,
- .write = raw_file_write,
- .aio_write = raw_file_aio_write,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write_nolock,
.open = raw_open,
.release= raw_release,
.ioctl = raw_ioctl,
- .readv = generic_file_readv,
- .writev = generic_file_writev,
.owner = THIS_MODULE,
};
@@ -288,31 +263,34 @@ static struct cdev raw_cdev = {
static int __init raw_init(void)
{
dev_t dev = MKDEV(RAW_MAJOR, 0);
+ int ret;
- if (register_chrdev_region(dev, MAX_RAW_MINORS, "raw"))
+ ret = register_chrdev_region(dev, MAX_RAW_MINORS, "raw");
+ if (ret)
goto error;
cdev_init(&raw_cdev, &raw_fops);
- if (cdev_add(&raw_cdev, dev, MAX_RAW_MINORS)) {
+ ret = cdev_add(&raw_cdev, dev, MAX_RAW_MINORS);
+ if (ret) {
kobject_put(&raw_cdev.kobj);
- unregister_chrdev_region(dev, MAX_RAW_MINORS);
- goto error;
+ goto error_region;
}
raw_class = class_create(THIS_MODULE, "raw");
if (IS_ERR(raw_class)) {
printk(KERN_ERR "Error creating raw class.\n");
cdev_del(&raw_cdev);
- unregister_chrdev_region(dev, MAX_RAW_MINORS);
- goto error;
+ ret = PTR_ERR(raw_class);
+ goto error_region;
}
class_device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
return 0;
+error_region:
+ unregister_chrdev_region(dev, MAX_RAW_MINORS);
error:
- printk(KERN_ERR "error register raw device\n");
- return 1;
+ return ret;
}
static void __exit raw_exit(void)
diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h
index 6b039186856d..9e7283bd81a0 100644
--- a/drivers/char/rio/func.h
+++ b/drivers/char/rio/func.h
@@ -88,7 +88,7 @@ void RIOHostReset(unsigned int, struct DpRam __iomem *, unsigned int);
/* riointr.c */
void RIOTxEnable(char *);
-void RIOServiceHost(struct rio_info *, struct Host *, int);
+void RIOServiceHost(struct rio_info *, struct Host *);
int riotproc(struct rio_info *, struct ttystatics *, int, int);
/* rioparam.c */
diff --git a/drivers/char/rio/host.h b/drivers/char/rio/host.h
index ee2ddea7a63a..23d0681fe491 100644
--- a/drivers/char/rio/host.h
+++ b/drivers/char/rio/host.h
@@ -44,6 +44,7 @@
** the host.
*/
struct Host {
+ struct pci_dev *pdev;
unsigned char Type; /* RIO_EISA, RIO_MCA, ... */
unsigned char Ivec; /* POLLED or ivec number */
unsigned char Mode; /* Control stuff */
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 3fa80aaf4527..7ac68cb3bedd 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -363,12 +363,12 @@ static void rio_reset_interrupt(struct Host *HostP)
}
-static irqreturn_t rio_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t rio_interrupt(int irq, void *ptr)
{
struct Host *HostP;
func_enter();
- HostP = (struct Host *) ptr; /* &p->RIOHosts[(long)ptr]; */
+ HostP = ptr; /* &p->RIOHosts[(long)ptr]; */
rio_dprintk(RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
/* AAargh! The order in which to do these things is essential and
@@ -402,7 +402,7 @@ static irqreturn_t rio_interrupt(int irq, void *ptr, struct pt_regs *regs)
return IRQ_HANDLED;
}
- RIOServiceHost(p, HostP, irq);
+ RIOServiceHost(p, HostP);
rio_dprintk(RIO_DEBUG_IFLOW, "riointr() doing host %p type %d\n", ptr, HostP->Type);
@@ -417,7 +417,7 @@ static void rio_pollfunc(unsigned long data)
{
func_enter();
- rio_interrupt(0, &p->RIOHosts[data], NULL);
+ rio_interrupt(0, &p->RIOHosts[data]);
p->RIOHosts[data].timer.expires = jiffies + rio_poll;
add_timer(&p->RIOHosts[data].timer);
@@ -727,7 +727,7 @@ static struct vpd_prom *get_VPD_PROM(struct Host *hp)
return &vpdp;
}
-static struct tty_operations rio_ops = {
+static const struct tty_operations rio_ops = {
.open = riotopen,
.close = gs_close,
.write = gs_write,
@@ -1017,6 +1017,10 @@ static int __init rio_init(void)
rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
fix_rio_pci(pdev);
+
+ p->RIOHosts[p->RIONumHosts].pdev = pdev;
+ pci_dev_get(pdev);
+
p->RIOLastPCISearch = 0;
p->RIONumHosts++;
found++;
@@ -1066,6 +1070,9 @@ static int __init rio_init(void)
((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
+ p->RIOHosts[p->RIONumHosts].pdev = pdev;
+ pci_dev_get(pdev);
+
p->RIOLastPCISearch = 0;
p->RIONumHosts++;
found++;
@@ -1181,6 +1188,8 @@ static void __exit rio_exit(void)
}
/* It is safe/allowed to del_timer a non-active timer */
del_timer(&hp->timer);
+ if (hp->Type == RIO_PCI)
+ pci_dev_put(hp->pdev);
}
if (misc_deregister(&rio_fw_device) < 0) {
diff --git a/drivers/char/rio/rioctrl.c b/drivers/char/rio/rioctrl.c
index 052e8120a471..7ce77619707c 100644
--- a/drivers/char/rio/rioctrl.c
+++ b/drivers/char/rio/rioctrl.c
@@ -662,7 +662,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
p->RIOError.Error = COPYIN_FAILED;
return -EFAULT;
}
- if (portStats.port >= RIO_PORTS) {
+ if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
return -ENXIO;
}
@@ -702,7 +702,7 @@ int riocontrol(struct rio_info *p, dev_t dev, int cmd, unsigned long arg, int su
p->RIOError.Error = COPYIN_FAILED;
return -EFAULT;
}
- if (portStats.port >= RIO_PORTS) {
+ if (portStats.port < 0 || portStats.port >= RIO_PORTS) {
p->RIOError.Error = PORT_NUMBER_OUT_OF_RANGE;
return -ENXIO;
}
diff --git a/drivers/char/rio/riointr.c b/drivers/char/rio/riointr.c
index 0bd09040a5c0..eeda40c5e189 100644
--- a/drivers/char/rio/riointr.c
+++ b/drivers/char/rio/riointr.c
@@ -181,7 +181,7 @@ static int RupIntr;
static int RxIntr;
static int TxIntr;
-void RIOServiceHost(struct rio_info *p, struct Host *HostP, int From)
+void RIOServiceHost(struct rio_info *p, struct Host *HostP)
{
rio_spin_lock(&HostP->HostLock);
if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c
index f1c94f771af5..5ab32b38f45a 100644
--- a/drivers/char/riscom8.c
+++ b/drivers/char/riscom8.c
@@ -81,7 +81,6 @@
static struct riscom_board * IRQ_to_board[16];
static struct tty_driver *riscom_driver;
-static unsigned char * tmp_buf;
static unsigned long baud_table[] = {
0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
@@ -551,7 +550,7 @@ static inline void rc_check_modem(struct riscom_board const * bp)
}
/* The main interrupt processing routine */
-static irqreturn_t rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+static irqreturn_t rc_interrupt(int irq, void * dev_id)
{
unsigned char status;
unsigned char ack;
@@ -560,11 +559,10 @@ static irqreturn_t rc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
int handled = 0;
bp = IRQ_to_board[irq];
-
- if (!bp || !(bp->flags & RC_BOARD_ACTIVE)) {
+
+ if (!(bp->flags & RC_BOARD_ACTIVE))
return IRQ_NONE;
- }
-
+
while ((++loop < 16) && ((status = ~(rc_in(bp, RC_BSR))) &
(RC_BSR_TOUT | RC_BSR_TINT |
RC_BSR_MINT | RC_BSR_RINT))) {
@@ -675,26 +673,12 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
port->COR2 = 0;
port->MSVR = MSVR_RTS;
- baud = C_BAUD(tty);
-
- if (baud & CBAUDEX) {
- baud &= ~CBAUDEX;
- if (baud < 1 || baud > 2)
- port->tty->termios->c_cflag &= ~CBAUDEX;
- else
- baud += 15;
- }
- if (baud == 15) {
- if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- baud ++;
- if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- baud += 2;
- }
+ baud = tty_get_baud_rate(tty);
/* Select port on the board */
rc_out(bp, CD180_CAR, port_No(port));
- if (!baud_table[baud]) {
+ if (!baud) {
/* Drop DTR & exit */
bp->DTR |= (1u << port_No(port));
rc_out(bp, RC_DTR, bp->DTR);
@@ -710,7 +694,7 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
*/
/* Set baud rate for port */
- tmp = (((RC_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
+ tmp = (((RC_OSCFREQ + baud/2) / baud +
CD180_TPC/2) / CD180_TPC);
rc_out(bp, CD180_RBPRH, (tmp >> 8) & 0xff);
@@ -718,7 +702,7 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port)
rc_out(bp, CD180_RBPRL, tmp & 0xff);
rc_out(bp, CD180_TBPRL, tmp & 0xff);
- baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */
+ baud = (baud + 5) / 10; /* Estimated CPS */
/* Two timer ticks seems enough to wakeup something like SLIP driver */
tmp = ((baud + HZ/2) / HZ) * 2 - CD180_NFIFO;
@@ -1138,7 +1122,7 @@ static int rc_write(struct tty_struct * tty,
bp = port_Board(port);
- if (!tty || !port->xmit_buf || !tmp_buf)
+ if (!tty || !port->xmit_buf)
return 0;
save_flags(flags);
@@ -1597,7 +1581,7 @@ static void do_softint(void *private_)
}
}
-static struct tty_operations riscom_ops = {
+static const struct tty_operations riscom_ops = {
.open = rc_open,
.close = rc_close,
.write = rc_write,
@@ -1626,11 +1610,6 @@ static inline int rc_init_drivers(void)
if (!riscom_driver)
return -ENOMEM;
- if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
- printk(KERN_ERR "rc: Couldn't get free page.\n");
- put_tty_driver(riscom_driver);
- return 1;
- }
memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
riscom_driver->owner = THIS_MODULE;
riscom_driver->name = "ttyL";
@@ -1643,7 +1622,6 @@ static inline int rc_init_drivers(void)
riscom_driver->flags = TTY_DRIVER_REAL_RAW;
tty_set_operations(riscom_driver, &riscom_ops);
if ((error = tty_register_driver(riscom_driver))) {
- free_page((unsigned long)tmp_buf);
put_tty_driver(riscom_driver);
printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
"error = %d\n",
@@ -1671,7 +1649,6 @@ static void rc_release_drivers(void)
save_flags(flags);
cli();
- free_page((unsigned long)tmp_buf);
tty_unregister_driver(riscom_driver);
put_tty_driver(riscom_driver);
restore_flags(flags);
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 0ac131881322..bac80056f7e0 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -2334,7 +2334,7 @@ static int __init init_ISA(int i)
return (1);
}
-static struct tty_operations rocket_ops = {
+static const struct tty_operations rocket_ops = {
.open = rp_open,
.close = rp_close,
.write = rp_write,
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index ab6429b4a84e..66a7385bc34a 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -35,13 +35,13 @@
* 1.09a Pete Zaitcev: Sun SPARC
* 1.09b Jeff Garzik: Modularize, init cleanup
* 1.09c Jeff Garzik: SMP cleanup
- * 1.10 Paul Barton-Davis: add support for async I/O
+ * 1.10 Paul Barton-Davis: add support for async I/O
* 1.10a Andrea Arcangeli: Alpha updates
* 1.10b Andrew Morton: SMP lock fix
* 1.10c Cesar Barros: SMP locking fixes and cleanup
* 1.10d Paul Gortmaker: delete paranoia check in rtc_exit
* 1.10e Maciej W. Rozycki: Handle DECstation's year weirdness.
- * 1.11 Takashi Iwai: Kernel access functions
+ * 1.11 Takashi Iwai: Kernel access functions
* rtc_register/rtc_unregister/rtc_control
* 1.11a Daniele Bellucci: Audit create_proc_read_entry in rtc_init
* 1.12 Venkatesh Pallipadi: Hooks for emulating rtc on HPET base-timer
@@ -113,9 +113,9 @@ static int rtc_has_irq = 1;
#define hpet_set_rtc_irq_bit(arg) 0
#define hpet_rtc_timer_init() do { } while (0)
#define hpet_rtc_dropped_irq() 0
-static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) {return 0;}
+static inline irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) {return 0;}
#else
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
#endif
/*
@@ -229,7 +229,7 @@ static inline unsigned char rtc_is_updating(void)
* (See ./arch/XXXX/kernel/time.c for the set_rtc_mmss() function.)
*/
-irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t rtc_interrupt(int irq, void *dev_id)
{
/*
* Can be an alarm interrupt, update complete interrupt,
@@ -915,7 +915,7 @@ static const struct file_operations rtc_proc_fops = {
};
#if defined(RTC_IRQ) && !defined(__sparc__)
-static irqreturn_t (*rtc_int_handler_ptr)(int irq, void *dev_id, struct pt_regs *regs);
+static irq_handler_t rtc_int_handler_ptr;
#endif
static int __init rtc_init(void)
@@ -1262,10 +1262,8 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
* Once the read clears, read the RTC time (again via ioctl). Easy.
*/
- while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100) {
- barrier();
+ while (rtc_is_updating() != 0 && jiffies - uip_watchdog < 2*HZ/100)
cpu_relax();
- }
/*
* Only the values that we read from the RTC are set. We leave
diff --git a/drivers/char/s3c2410-rtc.c b/drivers/char/s3c2410-rtc.c
deleted file mode 100644
index 5458ef1634e5..000000000000
--- a/drivers/char/s3c2410-rtc.c
+++ /dev/null
@@ -1,591 +0,0 @@
-/* drivers/char/s3c2410_rtc.c
- *
- * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
- * http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 Internal RTC Driver
- *
- * Changelog:
- * 08-Nov-2004 BJD Initial creation
- * 12-Nov-2004 BJD Added periodic IRQ and PM code
- * 22-Nov-2004 BJD Sign-test on alarm code to check for <0
- * 10-Mar-2005 LCVR Changed S3C2410_VA_RTC to S3C24XX_VA_RTC
-*/
-
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/rtc.h>
-#include <linux/bcd.h>
-#include <linux/clk.h>
-
-#include <asm/hardware.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/rtc.h>
-
-#include <asm/mach/time.h>
-
-#include <asm/arch/regs-rtc.h>
-
-/* need this for the RTC_AF definitions */
-#include <linux/mc146818rtc.h>
-
-#undef S3C24XX_VA_RTC
-#define S3C24XX_VA_RTC s3c2410_rtc_base
-
-static struct resource *s3c2410_rtc_mem;
-
-static void __iomem *s3c2410_rtc_base;
-static int s3c2410_rtc_alarmno = NO_IRQ;
-static int s3c2410_rtc_tickno = NO_IRQ;
-static int s3c2410_rtc_freq = 1;
-
-static DEFINE_SPINLOCK(s3c2410_rtc_pie_lock);
-
-/* IRQ Handlers */
-
-static irqreturn_t s3c2410_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
-{
- rtc_update(1, RTC_AF | RTC_IRQF);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t s3c2410_rtc_tickirq(int irq, void *id, struct pt_regs *r)
-{
- rtc_update(1, RTC_PF | RTC_IRQF);
- return IRQ_HANDLED;
-}
-
-/* Update control registers */
-static void s3c2410_rtc_setaie(int to)
-{
- unsigned int tmp;
-
- pr_debug("%s: aie=%d\n", __FUNCTION__, to);
-
- tmp = readb(S3C2410_RTCALM);
-
- if (to)
- tmp |= S3C2410_RTCALM_ALMEN;
- else
- tmp &= ~S3C2410_RTCALM_ALMEN;
-
-
- writeb(tmp, S3C2410_RTCALM);
-}
-
-static void s3c2410_rtc_setpie(int to)
-{
- unsigned int tmp;
-
- pr_debug("%s: pie=%d\n", __FUNCTION__, to);
-
- spin_lock_irq(&s3c2410_rtc_pie_lock);
- tmp = readb(S3C2410_TICNT) & ~S3C2410_TICNT_ENABLE;
-
- if (to)
- tmp |= S3C2410_TICNT_ENABLE;
-
- writeb(tmp, S3C2410_TICNT);
- spin_unlock_irq(&s3c2410_rtc_pie_lock);
-}
-
-static void s3c2410_rtc_setfreq(int freq)
-{
- unsigned int tmp;
-
- spin_lock_irq(&s3c2410_rtc_pie_lock);
- tmp = readb(S3C2410_TICNT) & S3C2410_TICNT_ENABLE;
-
- s3c2410_rtc_freq = freq;
-
- tmp |= (128 / freq)-1;
-
- writeb(tmp, S3C2410_TICNT);
- spin_unlock_irq(&s3c2410_rtc_pie_lock);
-}
-
-/* Time read/write */
-
-static int s3c2410_rtc_gettime(struct rtc_time *rtc_tm)
-{
- unsigned int have_retried = 0;
-
- retry_get_time:
- rtc_tm->tm_min = readb(S3C2410_RTCMIN);
- rtc_tm->tm_hour = readb(S3C2410_RTCHOUR);
- rtc_tm->tm_mday = readb(S3C2410_RTCDATE);
- rtc_tm->tm_mon = readb(S3C2410_RTCMON);
- rtc_tm->tm_year = readb(S3C2410_RTCYEAR);
- rtc_tm->tm_sec = readb(S3C2410_RTCSEC);
-
- /* the only way to work out wether the system was mid-update
- * when we read it is to check the second counter, and if it
- * is zero, then we re-try the entire read
- */
-
- if (rtc_tm->tm_sec == 0 && !have_retried) {
- have_retried = 1;
- goto retry_get_time;
- }
-
- pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n",
- rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
- rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
-
- BCD_TO_BIN(rtc_tm->tm_sec);
- BCD_TO_BIN(rtc_tm->tm_min);
- BCD_TO_BIN(rtc_tm->tm_hour);
- BCD_TO_BIN(rtc_tm->tm_mday);
- BCD_TO_BIN(rtc_tm->tm_mon);
- BCD_TO_BIN(rtc_tm->tm_year);
-
- rtc_tm->tm_year += 100;
- rtc_tm->tm_mon -= 1;
-
- return 0;
-}
-
-
-static int s3c2410_rtc_settime(struct rtc_time *tm)
-{
- /* the rtc gets round the y2k problem by just not supporting it */
-
- if (tm->tm_year < 100)
- return -EINVAL;
-
- writeb(BIN2BCD(tm->tm_sec), S3C2410_RTCSEC);
- writeb(BIN2BCD(tm->tm_min), S3C2410_RTCMIN);
- writeb(BIN2BCD(tm->tm_hour), S3C2410_RTCHOUR);
- writeb(BIN2BCD(tm->tm_mday), S3C2410_RTCDATE);
- writeb(BIN2BCD(tm->tm_mon + 1), S3C2410_RTCMON);
- writeb(BIN2BCD(tm->tm_year - 100), S3C2410_RTCYEAR);
-
- return 0;
-}
-
-static int s3c2410_rtc_getalarm(struct rtc_wkalrm *alrm)
-{
- struct rtc_time *alm_tm = &alrm->time;
- unsigned int alm_en;
-
- alm_tm->tm_sec = readb(S3C2410_ALMSEC);
- alm_tm->tm_min = readb(S3C2410_ALMMIN);
- alm_tm->tm_hour = readb(S3C2410_ALMHOUR);
- alm_tm->tm_mon = readb(S3C2410_ALMMON);
- alm_tm->tm_mday = readb(S3C2410_ALMDATE);
- alm_tm->tm_year = readb(S3C2410_ALMYEAR);
-
- alm_en = readb(S3C2410_RTCALM);
-
- pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",
- alm_en,
- alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
- alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
-
-
- /* decode the alarm enable field */
-
- if (alm_en & S3C2410_RTCALM_SECEN) {
- BCD_TO_BIN(alm_tm->tm_sec);
- } else {
- alm_tm->tm_sec = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_MINEN) {
- BCD_TO_BIN(alm_tm->tm_min);
- } else {
- alm_tm->tm_min = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_HOUREN) {
- BCD_TO_BIN(alm_tm->tm_hour);
- } else {
- alm_tm->tm_hour = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_DAYEN) {
- BCD_TO_BIN(alm_tm->tm_mday);
- } else {
- alm_tm->tm_mday = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_MONEN) {
- BCD_TO_BIN(alm_tm->tm_mon);
- alm_tm->tm_mon -= 1;
- } else {
- alm_tm->tm_mon = 0xff;
- }
-
- if (alm_en & S3C2410_RTCALM_YEAREN) {
- BCD_TO_BIN(alm_tm->tm_year);
- } else {
- alm_tm->tm_year = 0xffff;
- }
-
- /* todo - set alrm->enabled ? */
-
- return 0;
-}
-
-static int s3c2410_rtc_setalarm(struct rtc_wkalrm *alrm)
-{
- struct rtc_time *tm = &alrm->time;
- unsigned int alrm_en;
-
- pr_debug("s3c2410_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",
- alrm->enabled,
- tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,
- tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec);
-
- if (alrm->enabled || 1) {
- alrm_en = readb(S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
- writeb(0x00, S3C2410_RTCALM);
-
- if (tm->tm_sec < 60 && tm->tm_sec >= 0) {
- alrm_en |= S3C2410_RTCALM_SECEN;
- writeb(BIN2BCD(tm->tm_sec), S3C2410_ALMSEC);
- }
-
- if (tm->tm_min < 60 && tm->tm_min >= 0) {
- alrm_en |= S3C2410_RTCALM_MINEN;
- writeb(BIN2BCD(tm->tm_min), S3C2410_ALMMIN);
- }
-
- if (tm->tm_hour < 24 && tm->tm_hour >= 0) {
- alrm_en |= S3C2410_RTCALM_HOUREN;
- writeb(BIN2BCD(tm->tm_hour), S3C2410_ALMHOUR);
- }
-
- pr_debug("setting S3C2410_RTCALM to %08x\n", alrm_en);
-
- writeb(alrm_en, S3C2410_RTCALM);
- enable_irq_wake(s3c2410_rtc_alarmno);
- } else {
- alrm_en = readb(S3C2410_RTCALM);
- alrm_en &= ~S3C2410_RTCALM_ALMEN;
- writeb(alrm_en, S3C2410_RTCALM);
- disable_irq_wake(s3c2410_rtc_alarmno);
- }
-
- return 0;
-}
-
-static int s3c2410_rtc_ioctl(unsigned int cmd, unsigned long arg)
-{
- switch (cmd) {
- case RTC_AIE_OFF:
- case RTC_AIE_ON:
- s3c2410_rtc_setaie((cmd == RTC_AIE_ON) ? 1 : 0);
- return 0;
-
- case RTC_PIE_OFF:
- case RTC_PIE_ON:
- s3c2410_rtc_setpie((cmd == RTC_PIE_ON) ? 1 : 0);
- return 0;
-
- case RTC_IRQP_READ:
- return put_user(s3c2410_rtc_freq, (unsigned long __user *)arg);
-
- case RTC_IRQP_SET:
- if (arg < 1 || arg > 64)
- return -EINVAL;
-
- if (!capable(CAP_SYS_RESOURCE))
- return -EACCES;
-
- /* check for power of 2 */
-
- if ((arg & (arg-1)) != 0)
- return -EINVAL;
-
- pr_debug("s3c2410_rtc: setting frequency %ld\n", arg);
-
- s3c2410_rtc_setfreq(arg);
- return 0;
-
- case RTC_UIE_ON:
- case RTC_UIE_OFF:
- return -EINVAL;
- }
-
- return -EINVAL;
-}
-
-static int s3c2410_rtc_proc(char *buf)
-{
- unsigned int rtcalm = readb(S3C2410_RTCALM);
- unsigned int ticnt = readb (S3C2410_TICNT);
- char *p = buf;
-
- p += sprintf(p, "alarm_IRQ\t: %s\n",
- (rtcalm & S3C2410_RTCALM_ALMEN) ? "yes" : "no" );
- p += sprintf(p, "periodic_IRQ\t: %s\n",
- (ticnt & S3C2410_TICNT_ENABLE) ? "yes" : "no" );
- p += sprintf(p, "periodic_freq\t: %d\n", s3c2410_rtc_freq);
-
- return p - buf;
-}
-
-static int s3c2410_rtc_open(void)
-{
- int ret;
-
- ret = request_irq(s3c2410_rtc_alarmno, s3c2410_rtc_alarmirq,
- IRQF_DISABLED, "s3c2410-rtc alarm", NULL);
-
- if (ret)
- printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_alarmno);
-
- ret = request_irq(s3c2410_rtc_tickno, s3c2410_rtc_tickirq,
- IRQF_DISABLED, "s3c2410-rtc tick", NULL);
-
- if (ret) {
- printk(KERN_ERR "IRQ%d already in use\n", s3c2410_rtc_tickno);
- goto tick_err;
- }
-
- return ret;
-
- tick_err:
- free_irq(s3c2410_rtc_alarmno, NULL);
- return ret;
-}
-
-static void s3c2410_rtc_release(void)
-{
- /* do not clear AIE here, it may be needed for wake */
-
- s3c2410_rtc_setpie(0);
- free_irq(s3c2410_rtc_alarmno, NULL);
- free_irq(s3c2410_rtc_tickno, NULL);
-}
-
-static struct rtc_ops s3c2410_rtcops = {
- .owner = THIS_MODULE,
- .open = s3c2410_rtc_open,
- .release = s3c2410_rtc_release,
- .ioctl = s3c2410_rtc_ioctl,
- .read_time = s3c2410_rtc_gettime,
- .set_time = s3c2410_rtc_settime,
- .read_alarm = s3c2410_rtc_getalarm,
- .set_alarm = s3c2410_rtc_setalarm,
- .proc = s3c2410_rtc_proc,
-};
-
-static void s3c2410_rtc_enable(struct platform_device *pdev, int en)
-{
- unsigned int tmp;
-
- if (s3c2410_rtc_base == NULL)
- return;
-
- if (!en) {
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp & ~S3C2410_RTCCON_RTCEN, S3C2410_RTCCON);
-
- tmp = readb(S3C2410_TICNT);
- writeb(tmp & ~S3C2410_TICNT_ENABLE, S3C2410_TICNT);
- } else {
- /* re-enable the device, and check it is ok */
-
- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_RTCEN) == 0){
- dev_info(&pdev->dev, "rtc disabled, re-enabling\n");
-
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp | S3C2410_RTCCON_RTCEN , S3C2410_RTCCON);
- }
-
- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CNTSEL)){
- dev_info(&pdev->dev, "removing S3C2410_RTCCON_CNTSEL\n");
-
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp& ~S3C2410_RTCCON_CNTSEL , S3C2410_RTCCON);
- }
-
- if ((readb(S3C2410_RTCCON) & S3C2410_RTCCON_CLKRST)){
- dev_info(&pdev->dev, "removing S3C2410_RTCCON_CLKRST\n");
-
- tmp = readb(S3C2410_RTCCON);
- writeb(tmp & ~S3C2410_RTCCON_CLKRST, S3C2410_RTCCON);
- }
- }
-}
-
-static int s3c2410_rtc_remove(struct platform_device *dev)
-{
- unregister_rtc(&s3c2410_rtcops);
-
- s3c2410_rtc_setpie(0);
- s3c2410_rtc_setaie(0);
-
- if (s3c2410_rtc_mem != NULL) {
- pr_debug("s3c2410_rtc: releasing s3c2410_rtc_mem\n");
- iounmap(s3c2410_rtc_base);
- release_resource(s3c2410_rtc_mem);
- kfree(s3c2410_rtc_mem);
- }
-
- return 0;
-}
-
-static int s3c2410_rtc_probe(struct platform_device *pdev)
-{
- struct resource *res;
- int ret;
-
- pr_debug("%s: probe=%p\n", __FUNCTION__, pdev);
-
- /* find the IRQs */
-
- s3c2410_rtc_tickno = platform_get_irq(pdev, 1);
- if (s3c2410_rtc_tickno < 0) {
- dev_err(&pdev->dev, "no irq for rtc tick\n");
- return -ENOENT;
- }
-
- s3c2410_rtc_alarmno = platform_get_irq(pdev, 0);
- if (s3c2410_rtc_alarmno < 0) {
- dev_err(&pdev->dev, "no irq for alarm\n");
- return -ENOENT;
- }
-
- pr_debug("s3c2410_rtc: tick irq %d, alarm irq %d\n",
- s3c2410_rtc_tickno, s3c2410_rtc_alarmno);
-
- /* get the memory region */
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to get memory region resource\n");
- return -ENOENT;
- }
-
- s3c2410_rtc_mem = request_mem_region(res->start, res->end-res->start+1,
- pdev->name);
-
- if (s3c2410_rtc_mem == NULL) {
- dev_err(&pdev->dev, "failed to reserve memory region\n");
- ret = -ENOENT;
- goto exit_err;
- }
-
- s3c2410_rtc_base = ioremap(res->start, res->end - res->start + 1);
- if (s3c2410_rtc_base == NULL) {
- dev_err(&pdev->dev, "failed ioremap()\n");
- ret = -EINVAL;
- goto exit_err;
- }
-
- s3c2410_rtc_mem = res;
- pr_debug("s3c2410_rtc_base=%p\n", s3c2410_rtc_base);
-
- pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
-
- /* check to see if everything is setup correctly */
-
- s3c2410_rtc_enable(pdev, 1);
-
- pr_debug("s3c2410_rtc: RTCCON=%02x\n", readb(S3C2410_RTCCON));
-
- s3c2410_rtc_setfreq(s3c2410_rtc_freq);
-
- /* register RTC and exit */
-
- register_rtc(&s3c2410_rtcops);
- return 0;
-
- exit_err:
- dev_err(&pdev->dev, "error %d during initialisation\n", ret);
-
- return ret;
-}
-
-#ifdef CONFIG_PM
-
-/* S3C2410 RTC Power management control */
-
-static struct timespec s3c2410_rtc_delta;
-
-static int ticnt_save;
-
-static int s3c2410_rtc_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
- /* save TICNT for anyone using periodic interrupts */
-
- ticnt_save = readb(S3C2410_TICNT);
-
- /* calculate time delta for suspend */
-
- s3c2410_rtc_gettime(&tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- save_time_delta(&s3c2410_rtc_delta, &time);
- s3c2410_rtc_enable(pdev, 0);
-
- return 0;
-}
-
-static int s3c2410_rtc_resume(struct platform_device *pdev)
-{
- struct rtc_time tm;
- struct timespec time;
-
- time.tv_nsec = 0;
-
- s3c2410_rtc_enable(pdev, 1);
- s3c2410_rtc_gettime(&tm);
- rtc_tm_to_time(&tm, &time.tv_sec);
- restore_time_delta(&s3c2410_rtc_delta, &time);
-
- writeb(ticnt_save, S3C2410_TICNT);
- return 0;
-}
-#else
-#define s3c2410_rtc_suspend NULL
-#define s3c2410_rtc_resume NULL
-#endif
-
-static struct platform_driver s3c2410_rtcdrv = {
- .probe = s3c2410_rtc_probe,
- .remove = s3c2410_rtc_remove,
- .suspend = s3c2410_rtc_suspend,
- .resume = s3c2410_rtc_resume,
- .driver = {
- .name = "s3c2410-rtc",
- .owner = THIS_MODULE,
- },
-};
-
-static char __initdata banner[] = "S3C2410 RTC, (c) 2004 Simtec Electronics\n";
-
-static int __init s3c2410_rtc_init(void)
-{
- printk(banner);
- return platform_driver_register(&s3c2410_rtcdrv);
-}
-
-static void __exit s3c2410_rtc_exit(void)
-{
- platform_driver_unregister(&s3c2410_rtcdrv);
-}
-
-module_init(s3c2410_rtc_init);
-module_exit(s3c2410_rtc_exit);
-
-MODULE_DESCRIPTION("S3C24XX RTC Driver");
-MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c
index b956c7babd18..99e5272e3c53 100644
--- a/drivers/char/scx200_gpio.c
+++ b/drivers/char/scx200_gpio.c
@@ -44,7 +44,7 @@ struct nsc_gpio_ops scx200_gpio_ops = {
.gpio_change = scx200_gpio_change,
.gpio_current = scx200_gpio_current
};
-EXPORT_SYMBOL(scx200_gpio_ops);
+EXPORT_SYMBOL_GPL(scx200_gpio_ops);
static int scx200_gpio_open(struct inode *inode, struct file *file)
{
@@ -69,7 +69,7 @@ static const struct file_operations scx200_gpio_fileops = {
.release = scx200_gpio_release,
};
-struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */
+static struct cdev scx200_gpio_cdev; /* use 1 cdev for all pins */
static int __init scx200_gpio_init(void)
{
diff --git a/drivers/char/selection.c b/drivers/char/selection.c
index 71093a9fc462..74cff839c857 100644
--- a/drivers/char/selection.c
+++ b/drivers/char/selection.c
@@ -33,7 +33,7 @@ extern void poke_blanked_console(void);
/* Variables for selection control. */
/* Use a dynamic buffer, instead of static (Dec 1994) */
-struct vc_data *sel_cons; /* must not be disallocated */
+struct vc_data *sel_cons; /* must not be deallocated */
static volatile int sel_start = -1; /* cleared by clear_selection */
static int sel_end;
static int sel_buffer_lth;
diff --git a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
index 510bd3e0e88b..4217d38caef9 100644
--- a/drivers/char/ser_a2232.c
+++ b/drivers/char/ser_a2232.c
@@ -111,7 +111,7 @@
/***************************** Prototypes ***************************/
/* The interrupt service routine */
-static irqreturn_t a2232_vbl_inter(int irq, void *data, struct pt_regs *fp);
+static irqreturn_t a2232_vbl_inter(int irq, void *data);
/* Initialize the port structures */
static void a2232_init_portstructs(void);
/* Initialize and register TTY drivers. */
@@ -504,7 +504,7 @@ static int a2232_open(struct tty_struct * tty, struct file * filp)
}
/*** END OF FUNCTIONS EXPECTED BY TTY DRIVER STRUCTS ***/
-static irqreturn_t a2232_vbl_inter(int irq, void *data, struct pt_regs *fp)
+static irqreturn_t a2232_vbl_inter(int irq, void *data)
{
#if A2232_IOBUFLEN != 256
#error "Re-Implement a2232_vbl_inter()!"
@@ -661,7 +661,7 @@ static void a2232_init_portstructs(void)
}
}
-static struct tty_operations a2232_ops = {
+static const struct tty_operations a2232_ops = {
.open = a2232_open,
.close = gs_close,
.write = gs_write,
diff --git a/drivers/char/serial167.c b/drivers/char/serial167.c
index 21a710cb4bba..3af7f0958c5d 100644
--- a/drivers/char/serial167.c
+++ b/drivers/char/serial167.c
@@ -62,6 +62,7 @@
#include <linux/console.h>
#include <linux/module.h>
#include <linux/bitops.h>
+#include <linux/tty_flip.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -119,17 +120,6 @@ struct cyclades_port cy_port[] = {
#define NR_PORTS ARRAY_SIZE(cy_port)
/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf = 0;
-
-/*
* This is used to look up the divisor speeds and the timeouts
* We're normally limited to 15 distinct baud rates. The extra
* are accessed via settings in info->flags.
@@ -381,7 +371,7 @@ cy_sched_event(struct cyclades_port *info, int event)
received, out buffer empty, modem change, etc.
*/
static irqreturn_t
-cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+cd2401_rxerr_interrupt(int irq, void *dev_id)
{
struct tty_struct *tty;
struct cyclades_port *info;
@@ -438,8 +428,9 @@ cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp)
overflowing, we still loose
the next incoming character.
*/
- tty_insert_flip_char(tty, data, TTY_NORMAL);
- }
+ if (tty_buffer_request_room(tty, 1) != 0){
+ tty_insert_flip_char(tty, data, TTY_FRAME);
+ }
/* These two conditions may imply */
/* a normal read should be done. */
/* else if(data & CyTIMEOUT) */
@@ -448,21 +439,21 @@ cd2401_rxerr_interrupt(int irq, void *dev_id, struct pt_regs *fp)
tty_insert_flip_char(tty, 0, TTY_NORMAL);
}
}else{
- tty_insert_flip_char(tty, data, TTY_NORMAL);
+ tty_insert_flip_char(tty, data, TTY_NORMAL);
}
}else{
/* there was a software buffer overrun
and nothing could be done about it!!! */
}
}
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_schedule_flip(tty);
/* end of service */
base_addr[CyREOIR] = rfoc ? 0 : CyNOTRANS;
return IRQ_HANDLED;
} /* cy_rxerr_interrupt */
static irqreturn_t
-cd2401_modem_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+cd2401_modem_interrupt(int irq, void *dev_id)
{
struct cyclades_port *info;
volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
@@ -517,7 +508,7 @@ cd2401_modem_interrupt(int irq, void *dev_id, struct pt_regs *fp)
} /* cy_modem_interrupt */
static irqreturn_t
-cd2401_tx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+cd2401_tx_interrupt(int irq, void *dev_id)
{
struct cyclades_port *info;
volatile unsigned char *base_addr = (unsigned char *)BASE_ADDR;
@@ -637,7 +628,7 @@ cd2401_tx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
} /* cy_tx_interrupt */
static irqreturn_t
-cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+cd2401_rx_interrupt(int irq, void *dev_id)
{
struct tty_struct *tty;
struct cyclades_port *info;
@@ -646,6 +637,7 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
char data;
int char_count;
int save_cnt;
+ int len;
/* determine the channel and change to that context */
channel = (u_short ) (base_addr[CyLICR] >> 2);
@@ -678,14 +670,15 @@ cd2401_rx_interrupt(int irq, void *dev_id, struct pt_regs *fp)
info->mon.char_max = char_count;
info->mon.char_last = char_count;
#endif
- while(char_count--){
+ len = tty_buffer_request_room(tty, char_count);
+ while(len--){
data = base_addr[CyRDR];
tty_insert_flip_char(tty, data, TTY_NORMAL);
#ifdef CYCLOM_16Y_HACK
udelay(10L);
#endif
}
- schedule_delayed_work(&tty->flip.work, 1);
+ tty_schedule_flip(tty);
}
/* end of service */
base_addr[CyREOIR] = save_cnt ? 0 : CyNOTRANS;
@@ -846,7 +839,7 @@ shutdown(struct cyclades_port * info)
local_irq_save(flags);
if (info->xmit_buf){
free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
+ info->xmit_buf = NULL;
}
base_addr[CyCAR] = (u_char)channel;
@@ -1132,7 +1125,7 @@ cy_put_char(struct tty_struct *tty, unsigned char ch)
if (serial_paranoia_check(info, tty->name, "cy_put_char"))
return;
- if (!tty || !info->xmit_buf)
+ if (!info->xmit_buf)
return;
local_irq_save(flags);
@@ -1198,7 +1191,7 @@ cy_write(struct tty_struct * tty,
return 0;
}
- if (!tty || !info->xmit_buf || !tmp_buf){
+ if (!info->xmit_buf){
return 0;
}
@@ -1361,7 +1354,7 @@ cy_unthrottle(struct tty_struct * tty)
static int
get_serial_info(struct cyclades_port * info,
- struct serial_struct * retinfo)
+ struct serial_struct __user * retinfo)
{
struct serial_struct tmp;
@@ -1383,7 +1376,7 @@ get_serial_info(struct cyclades_port * info,
static int
set_serial_info(struct cyclades_port * info,
- struct serial_struct * new_info)
+ struct serial_struct __user * new_info)
{
struct serial_struct new_serial;
struct cyclades_port old_info;
@@ -1433,7 +1426,6 @@ cy_tiocmget(struct tty_struct *tty, struct file *file)
volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
unsigned long flags;
unsigned char status;
- unsigned int result;
channel = info->line;
@@ -1457,7 +1449,6 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
int channel;
volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
unsigned long flags;
- unsigned int arg;
channel = info->line;
@@ -1512,7 +1503,7 @@ send_break( struct cyclades_port * info, int duration)
} /* send_break */
static int
-get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
+get_mon_info(struct cyclades_port * info, struct cyclades_monitor __user * mon)
{
if (copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)))
@@ -1525,7 +1516,7 @@ get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon)
}
static int
-set_threshold(struct cyclades_port * info, unsigned long *arg)
+set_threshold(struct cyclades_port * info, unsigned long __user *arg)
{
volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
unsigned long value;
@@ -1542,7 +1533,7 @@ set_threshold(struct cyclades_port * info, unsigned long *arg)
}
static int
-get_threshold(struct cyclades_port * info, unsigned long *value)
+get_threshold(struct cyclades_port * info, unsigned long __user *value)
{
volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
int channel;
@@ -1555,7 +1546,7 @@ get_threshold(struct cyclades_port * info, unsigned long *value)
}
static int
-set_default_threshold(struct cyclades_port * info, unsigned long *arg)
+set_default_threshold(struct cyclades_port * info, unsigned long __user *arg)
{
unsigned long value;
@@ -1567,13 +1558,13 @@ set_default_threshold(struct cyclades_port * info, unsigned long *arg)
}
static int
-get_default_threshold(struct cyclades_port * info, unsigned long *value)
+get_default_threshold(struct cyclades_port * info, unsigned long __user *value)
{
return put_user(info->default_threshold,value);
}
static int
-set_timeout(struct cyclades_port * info, unsigned long *arg)
+set_timeout(struct cyclades_port * info, unsigned long __user *arg)
{
volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
int channel;
@@ -1590,7 +1581,7 @@ set_timeout(struct cyclades_port * info, unsigned long *arg)
}
static int
-get_timeout(struct cyclades_port * info, unsigned long *value)
+get_timeout(struct cyclades_port * info, unsigned long __user *value)
{
volatile unsigned char *base_addr = (u_char *)BASE_ADDR;
int channel;
@@ -1610,7 +1601,7 @@ set_default_timeout(struct cyclades_port * info, unsigned long value)
}
static int
-get_default_timeout(struct cyclades_port * info, unsigned long *value)
+get_default_timeout(struct cyclades_port * info, unsigned long __user *value)
{
return put_user(info->default_timeout,value);
}
@@ -1622,6 +1613,7 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
unsigned long val;
struct cyclades_port * info = (struct cyclades_port *)tty->driver_data;
int ret_val = 0;
+ void __user *argp = (void __user *)arg;
#ifdef SERIAL_DEBUG_OTHER
printk("cy_ioctl %s, cmd = %x arg = %lx\n", tty->name, cmd, arg); /* */
@@ -1629,28 +1621,28 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
switch (cmd) {
case CYGETMON:
- ret_val = get_mon_info(info, (struct cyclades_monitor *)arg);
+ ret_val = get_mon_info(info, argp);
break;
case CYGETTHRESH:
- ret_val = get_threshold(info, (unsigned long *)arg);
+ ret_val = get_threshold(info, argp);
break;
case CYSETTHRESH:
- ret_val = set_threshold(info, (unsigned long *)arg);
+ ret_val = set_threshold(info, argp);
break;
case CYGETDEFTHRESH:
- ret_val = get_default_threshold(info, (unsigned long *)arg);
+ ret_val = get_default_threshold(info, argp);
break;
case CYSETDEFTHRESH:
- ret_val = set_default_threshold(info, (unsigned long *)arg);
+ ret_val = set_default_threshold(info, argp);
break;
case CYGETTIMEOUT:
- ret_val = get_timeout(info, (unsigned long *)arg);
+ ret_val = get_timeout(info, argp);
break;
case CYSETTIMEOUT:
- ret_val = set_timeout(info, (unsigned long *)arg);
+ ret_val = set_timeout(info, argp);
break;
case CYGETDEFTIMEOUT:
- ret_val = get_default_timeout(info, (unsigned long *)arg);
+ ret_val = get_default_timeout(info, argp);
break;
case CYSETDEFTIMEOUT:
ret_val = set_default_timeout(info, (unsigned long)arg);
@@ -1673,21 +1665,20 @@ cy_ioctl(struct tty_struct *tty, struct file * file,
/* The following commands are incompletely implemented!!! */
case TIOCGSOFTCAR:
- ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+ ret_val = put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *) argp);
break;
case TIOCSSOFTCAR:
- ret_val = get_user(val, (unsigned long *) arg);
+ ret_val = get_user(val, (unsigned long __user *) argp);
if (ret_val)
break;
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) | (val ? CLOCAL : 0));
break;
case TIOCGSERIAL:
- ret_val = get_serial_info(info, (struct serial_struct *) arg);
+ ret_val = get_serial_info(info, argp);
break;
case TIOCSSERIAL:
- ret_val = set_serial_info(info,
- (struct serial_struct *) arg);
+ ret_val = set_serial_info(info, argp);
break;
default:
ret_val = -ENOIOCTLCMD;
@@ -1782,7 +1773,7 @@ cy_close(struct tty_struct * tty, struct file * filp)
tty->driver->flush_buffer(tty);
tty_ldisc_flush(tty);
info->event = 0;
- info->tty = 0;
+ info->tty = NULL;
if (info->blocked_open) {
if (info->close_delay) {
msleep_interruptible(jiffies_to_msecs(info->close_delay));
@@ -1983,13 +1974,6 @@ cy_open(struct tty_struct *tty, struct file * filp)
tty->driver_data = info;
info->tty = tty;
- if (!tmp_buf) {
- tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (!tmp_buf){
- return -ENOMEM;
- }
- }
-
/*
* Start up serial port
*/
@@ -2158,7 +2142,7 @@ mvme167_serial_console_setup(int cflag)
rcor >> 5, rbpr);
} /* serial_console_init */
-static struct tty_operations cy_ops = {
+static const struct tty_operations cy_ops = {
.open = cy_open,
.close = cy_close,
.write = cy_write,
@@ -2266,7 +2250,7 @@ scrn[1] = '\0';
info->card = index;
info->line = port_num;
info->flags = STD_COM_FLAGS;
- info->tty = 0;
+ info->tty = NULL;
info->xmit_fifo_size = 12;
info->cor1 = CyPARITY_NONE|Cy_8_BITS;
info->cor2 = CyETC;
diff --git a/drivers/char/snsc.c b/drivers/char/snsc.c
index 07e0b75f2338..52753e723eaa 100644
--- a/drivers/char/snsc.c
+++ b/drivers/char/snsc.c
@@ -34,7 +34,7 @@
#define SCDRV_TIMEOUT 1000
static irqreturn_t
-scdrv_interrupt(int irq, void *subch_data, struct pt_regs *regs)
+scdrv_interrupt(int irq, void *subch_data)
{
struct subch_data_s *sd = subch_data;
unsigned long flags;
diff --git a/drivers/char/snsc_event.c b/drivers/char/snsc_event.c
index d12d4f629cec..2f56e8c54897 100644
--- a/drivers/char/snsc_event.c
+++ b/drivers/char/snsc_event.c
@@ -36,7 +36,7 @@ DECLARE_TASKLET(sn_sysctl_event, scdrv_event, 0);
* destination.
*/
static irqreturn_t
-scdrv_event_interrupt(int irq, void *subch_data, struct pt_regs *regs)
+scdrv_event_interrupt(int irq, void *subch_data)
{
struct subch_data_s *sd = subch_data;
unsigned long flags;
@@ -220,7 +220,7 @@ scdrv_dispatch_event(char *event, int len)
" Sending SIGPWR to init...\n");
/* give a SIGPWR signal to init proc */
- kill_proc(1, SIGPWR, 0);
+ kill_cad_pid(SIGPWR, 0);
} else {
/* print to system log */
printk("%s|$(0x%x)%s\n", severity, esp_code, desc);
diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c
index d4e434d694b7..c084149153de 100644
--- a/drivers/char/sonypi.c
+++ b/drivers/char/sonypi.c
@@ -826,7 +826,7 @@ static void sonypi_report_input_event(u8 event)
}
/* Interrupt handler: some event is available */
-static irqreturn_t sonypi_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sonypi_irq(int irq, void *dev_id)
{
u8 v1, v2, event = 0;
int i, j;
diff --git a/drivers/char/specialix.c b/drivers/char/specialix.c
index a1d303f9a33d..7e1bd9562c2a 100644
--- a/drivers/char/specialix.c
+++ b/drivers/char/specialix.c
@@ -182,12 +182,6 @@ static int sx_poll = HZ;
#define RS_EVENT_WRITE_WAKEUP 0
static struct tty_driver *specialix_driver;
-static unsigned char * tmp_buf;
-
-static unsigned long baud_table[] = {
- 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
- 9600, 19200, 38400, 57600, 115200, 0,
-};
static struct specialix_board sx_board[SX_NBOARD] = {
{ 0, SX_IOBASE1, 9, },
@@ -201,7 +195,7 @@ static struct specialix_port sx_port[SX_NBOARD * SX_NPORT];
#ifdef SPECIALIX_TIMER
static struct timer_list missed_irq_timer;
-static irqreturn_t sx_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static irqreturn_t sx_interrupt(int irq, void * dev_id);
#endif
@@ -898,7 +892,7 @@ static inline void sx_check_modem(struct specialix_board * bp)
/* The main interrupt processing routine */
-static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sx_interrupt(int irq, void *dev_id)
{
unsigned char status;
unsigned char ack;
@@ -913,7 +907,7 @@ static irqreturn_t sx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock_irqsave(&bp->lock, flags);
dprintk (SX_DEBUG_FLOW, "enter %s port %d room: %ld\n", __FUNCTION__, port_No(sx_get_port(bp, "INT")), SERIAL_XMIT_SIZE - sx_get_port(bp, "ITN")->xmit_cnt - 1);
- if (!bp || !(bp->flags & SX_BOARD_ACTIVE)) {
+ if (!(bp->flags & SX_BOARD_ACTIVE)) {
dprintk (SX_DEBUG_IRQ, "sx: False interrupt. irq %d.\n", irq);
spin_unlock_irqrestore(&bp->lock, flags);
func_exit();
@@ -1087,24 +1081,16 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
port->MSVR = (sx_in(bp, CD186x_MSVR) & MSVR_RTS);
spin_unlock_irqrestore(&bp->lock, flags);
dprintk (SX_DEBUG_TERMIOS, "sx: got MSVR=%02x.\n", port->MSVR);
- baud = C_BAUD(tty);
+ baud = tty_get_baud_rate(tty);
- if (baud & CBAUDEX) {
- baud &= ~CBAUDEX;
- if (baud < 1 || baud > 2)
- port->tty->termios->c_cflag &= ~CBAUDEX;
- else
- baud += 15;
- }
- if (baud == 15) {
+ if (baud == 38400) {
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
- baud ++;
+ baud = 57600;
if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
- baud += 2;
+ baud = 115200;
}
-
- if (!baud_table[baud]) {
+ if (!baud) {
/* Drop DTR & exit */
dprintk (SX_DEBUG_TERMIOS, "Dropping DTR... Hmm....\n");
if (!SX_CRTSCTS (tty)) {
@@ -1134,7 +1120,7 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
"This is an untested option, please be carefull.\n",
port_No (port), tmp);
else
- tmp = (((SX_OSCFREQ + baud_table[baud]/2) / baud_table[baud] +
+ tmp = (((SX_OSCFREQ + baud/2) / baud +
CD186x_TPC/2) / CD186x_TPC);
if ((tmp < 0x10) && time_before(again, jiffies)) {
@@ -1159,11 +1145,9 @@ static void sx_change_speed(struct specialix_board *bp, struct specialix_port *p
sx_out(bp, CD186x_RBPRL, tmp & 0xff);
sx_out(bp, CD186x_TBPRL, tmp & 0xff);
spin_unlock_irqrestore(&bp->lock, flags);
- if (port->custom_divisor) {
+ if (port->custom_divisor)
baud = (SX_OSCFREQ + port->custom_divisor/2) / port->custom_divisor;
- baud = ( baud + 5 ) / 10;
- } else
- baud = (baud_table[baud] + 5) / 10; /* Estimated CPS */
+ baud = (baud + 5) / 10; /* Estimated CPS */
/* Two timer ticks seems enough to wakeup something like SLIP driver */
tmp = ((baud + HZ/2) / HZ) * 2 - CD186x_NFIFO;
@@ -1682,7 +1666,7 @@ static int sx_write(struct tty_struct * tty,
bp = port_Board(port);
- if (!port->xmit_buf || !tmp_buf) {
+ if (!port->xmit_buf) {
func_exit();
return 0;
}
@@ -2372,7 +2356,7 @@ static void do_softint(void *private_)
func_exit();
}
-static struct tty_operations sx_ops = {
+static const struct tty_operations sx_ops = {
.open = sx_open,
.close = sx_close,
.write = sx_write,
@@ -2406,12 +2390,6 @@ static int sx_init_drivers(void)
return 1;
}
- if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {
- printk(KERN_ERR "sx: Couldn't get free page.\n");
- put_tty_driver(specialix_driver);
- func_exit();
- return 1;
- }
specialix_driver->owner = THIS_MODULE;
specialix_driver->name = "ttyW";
specialix_driver->major = SPECIALIX_NORMAL_MAJOR;
@@ -2425,7 +2403,6 @@ static int sx_init_drivers(void)
if ((error = tty_register_driver(specialix_driver))) {
put_tty_driver(specialix_driver);
- free_page((unsigned long)tmp_buf);
printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",
error);
func_exit();
@@ -2451,7 +2428,6 @@ static void sx_release_drivers(void)
{
func_enter();
- free_page((unsigned long)tmp_buf);
tty_unregister_driver(specialix_driver);
put_tty_driver(specialix_driver);
func_exit();
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index 3beb2203d24b..522e88e395cc 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -1927,13 +1927,12 @@ stl_readdone:
* calls off to the approrpriate board interrupt handlers.
*/
-static irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t stl_intr(int irq, void *dev_id)
{
stlbrd_t *brdp = (stlbrd_t *) dev_id;
#ifdef DEBUG
- printk("stl_intr(brdp=%x,irq=%d,regs=%x)\n", (int) brdp, irq,
- (int) regs);
+ printk("stl_intr(brdp=%x,irq=%d)\n", (int) brdp, irq);
#endif
return IRQ_RETVAL((* brdp->isr)(brdp));
@@ -2993,7 +2992,7 @@ static int stl_memioctl(struct inode *ip, struct file *fp, unsigned int cmd, uns
return(rc);
}
-static struct tty_operations stl_ops = {
+static const struct tty_operations stl_ops = {
.open = stl_open,
.close = stl_close,
.write = stl_write,
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index e1cd2bc4b1e4..cc10af08cb05 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -203,9 +203,7 @@
#define RCS_ID "$Id: sx.c,v 1.33 2000/03/08 10:01:02 wolff, pvdl Exp $"
#define RCS_REV "$Revision: 1.33 $"
-
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kdev_t.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -1194,7 +1192,7 @@ static inline void sx_check_modem_signals (struct sx_port *port)
* Small, elegant, clear.
*/
-static irqreturn_t sx_interrupt (int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sx_interrupt (int irq, void *ptr)
{
struct sx_board *board = ptr;
struct sx_port *port;
@@ -1302,7 +1300,7 @@ static void sx_pollfunc (unsigned long data)
func_enter ();
- sx_interrupt (0, board, NULL);
+ sx_interrupt (0, board);
init_timer(&board->timer);
@@ -2226,7 +2224,7 @@ static int probe_si (struct sx_board *board)
return 1;
}
-static struct tty_operations sx_ops = {
+static const struct tty_operations sx_ops = {
.break_ctl = sx_break,
.open = sx_open,
.close = gs_close,
@@ -2604,7 +2602,7 @@ static void __exit sx_exit (void)
}
}
if (misc_deregister(&sx_fw_device) < 0) {
- printk (KERN_INFO "sx: couldn't deregister firmware loader devic\n");
+ printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
}
sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
if (sx_initialized)
diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c
index 78b1b1a2732b..06784adcc35c 100644
--- a/drivers/char/synclink.c
+++ b/drivers/char/synclink.c
@@ -63,7 +63,6 @@
#define MAX_PCI_DEVICES 10
#define MAX_TOTAL_DEVICES 20
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
@@ -87,7 +86,6 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
-#include <asm/serial.h>
#include <linux/delay.h>
#include <linux/ioctl.h>
@@ -135,8 +133,8 @@ static MGSL_PARAMS default_params = {
};
#define SHARED_MEM_ADDRESS_SIZE 0x40000
-#define BUFFERLISTSIZE (PAGE_SIZE)
-#define DMABUFFERSIZE (PAGE_SIZE)
+#define BUFFERLISTSIZE 4096
+#define DMABUFFERSIZE 4096
#define MAXRXFRAMES 7
typedef struct _DMABUFFERENTRY
@@ -1700,11 +1698,10 @@ static void mgsl_isr_transmit_dma( struct mgsl_struct *info )
*
* irq interrupt number that caused interrupt
* dev_id device ID supplied during interrupt registration
- * regs interrupted processor context
*
* Return Value: None
*/
-static irqreturn_t mgsl_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t mgsl_interrupt(int irq, void *dev_id)
{
struct mgsl_struct * info;
u16 UscVector;
@@ -4360,7 +4357,7 @@ static struct mgsl_struct* mgsl_allocate_device(void)
} /* end of mgsl_allocate_device()*/
-static struct tty_operations mgsl_ops = {
+static const struct tty_operations mgsl_ops = {
.open = mgsl_open,
.close = mgsl_close,
.write = mgsl_write,
diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c
index 2f07b085536b..d4334c79f8d4 100644
--- a/drivers/char/synclink_gt.c
+++ b/drivers/char/synclink_gt.c
@@ -1,5 +1,5 @@
/*
- * $Id: synclink_gt.c,v 4.25 2006/02/06 21:20:33 paulkf Exp $
+ * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $
*
* Device driver for Microgate SyncLink GT serial adapters.
*
@@ -91,12 +91,12 @@
* module identification
*/
static char *driver_name = "SyncLink GT";
-static char *driver_version = "$Revision: 4.25 $";
+static char *driver_version = "$Revision: 4.36 $";
static char *tty_driver_name = "synclink_gt";
static char *tty_dev_prefix = "ttySLG";
MODULE_LICENSE("GPL");
#define MGSL_MAGIC 0x5401
-#define MAX_DEVICES 12
+#define MAX_DEVICES 32
static struct pci_device_id pci_table[] = {
{PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
@@ -461,7 +461,7 @@ static int adapter_test(struct slgt_info *info);
static void reset_adapter(struct slgt_info *info);
static void reset_port(struct slgt_info *info);
static void async_mode(struct slgt_info *info);
-static void hdlc_mode(struct slgt_info *info);
+static void sync_mode(struct slgt_info *info);
static void rx_stop(struct slgt_info *info);
static void rx_start(struct slgt_info *info);
@@ -491,7 +491,7 @@ static void isr_serial(struct slgt_info *info);
static void isr_rdma(struct slgt_info *info);
static void isr_txeom(struct slgt_info *info, unsigned short status);
static void isr_tdma(struct slgt_info *info);
-static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t slgt_interrupt(int irq, void *dev_id);
static int alloc_dma_bufs(struct slgt_info *info);
static void free_dma_bufs(struct slgt_info *info);
@@ -881,7 +881,9 @@ static int write(struct tty_struct *tty,
if (!count)
goto cleanup;
- if (info->params.mode == MGSL_MODE_RAW) {
+ if (info->params.mode == MGSL_MODE_RAW ||
+ info->params.mode == MGSL_MODE_MONOSYNC ||
+ info->params.mode == MGSL_MODE_BISYNC) {
unsigned int bufs_needed = (count/DMABUFSIZE);
unsigned int bufs_free = free_tbuf_count(info);
if (count % DMABUFSIZE)
@@ -1897,6 +1899,8 @@ static void bh_handler(void* context)
while(rx_get_frame(info));
break;
case MGSL_MODE_RAW:
+ case MGSL_MODE_MONOSYNC:
+ case MGSL_MODE_BISYNC:
while(rx_get_buf(info));
break;
}
@@ -2213,9 +2217,8 @@ static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int
*
* irq interrupt number
* dev_id device ID supplied during interrupt registration
- * regs interrupted processor context
*/
-static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t slgt_interrupt(int irq, void *dev_id)
{
struct slgt_info *info;
unsigned int gsr;
@@ -2362,10 +2365,9 @@ static void program_hw(struct slgt_info *info)
rx_stop(info);
tx_stop(info);
- if (info->params.mode == MGSL_MODE_HDLC ||
- info->params.mode == MGSL_MODE_RAW ||
+ if (info->params.mode != MGSL_MODE_ASYNC ||
info->netcount)
- hdlc_mode(info);
+ sync_mode(info);
else
async_mode(info);
@@ -2564,6 +2566,10 @@ static int rx_enable(struct slgt_info *info, int enable)
if (enable) {
if (!info->rx_enabled)
rx_start(info);
+ else if (enable == 2) {
+ /* force hunt mode (write 1 to RCR[3]) */
+ wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3);
+ }
} else {
if (info->rx_enabled)
rx_stop(info);
@@ -3434,7 +3440,7 @@ static void __devexit remove_one(struct pci_dev *dev)
{
}
-static struct tty_operations ops = {
+static const struct tty_operations ops = {
.open = open,
.close = close,
.write = write,
@@ -3748,7 +3754,7 @@ static void tx_start(struct slgt_info *info)
{
if (!info->tx_enabled) {
wr_reg16(info, TCR,
- (unsigned short)(rd_reg16(info, TCR) | BIT1));
+ (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2));
info->tx_enabled = TRUE;
}
@@ -3775,13 +3781,18 @@ static void tx_start(struct slgt_info *info)
tdma_reset(info);
/* set 1st descriptor address */
wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
- if (info->params.mode == MGSL_MODE_RAW)
+ switch(info->params.mode) {
+ case MGSL_MODE_RAW:
+ case MGSL_MODE_MONOSYNC:
+ case MGSL_MODE_BISYNC:
wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
- else
+ break;
+ default:
wr_reg32(info, TDCSR, BIT0); /* DMA enable */
+ }
}
- if (info->params.mode != MGSL_MODE_RAW) {
+ if (info->params.mode == MGSL_MODE_HDLC) {
info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
add_timer(&info->tx_timer);
}
@@ -3814,7 +3825,6 @@ static void tx_stop(struct slgt_info *info)
/* reset and disable transmitter */
val = rd_reg16(info, TCR) & ~BIT1; /* clear enable bit */
wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
- wr_reg16(info, TCR, val); /* clear reset */
slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
@@ -3982,7 +3992,7 @@ static void async_mode(struct slgt_info *info)
enable_loopback(info);
}
-static void hdlc_mode(struct slgt_info *info)
+static void sync_mode(struct slgt_info *info)
{
unsigned short val;
@@ -3992,7 +4002,7 @@ static void hdlc_mode(struct slgt_info *info)
/* TCR (tx control)
*
- * 15..13 mode, 000=HDLC 001=raw sync
+ * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
* 12..10 encoding
* 09 CRC enable
* 08 CRC32
@@ -4006,8 +4016,11 @@ static void hdlc_mode(struct slgt_info *info)
*/
val = 0;
- if (info->params.mode == MGSL_MODE_RAW)
- val |= BIT13;
+ switch(info->params.mode) {
+ case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
+ case MGSL_MODE_BISYNC: val |= BIT15; break;
+ case MGSL_MODE_RAW: val |= BIT13; break;
+ }
if (info->if_mode & MGSL_INTERFACE_RTS_EN)
val |= BIT7;
@@ -4058,7 +4071,7 @@ static void hdlc_mode(struct slgt_info *info)
/* RCR (rx control)
*
- * 15..13 mode, 000=HDLC 001=raw sync
+ * 15..13 mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
* 12..10 encoding
* 09 CRC enable
* 08 CRC32
@@ -4069,8 +4082,11 @@ static void hdlc_mode(struct slgt_info *info)
*/
val = 0;
- if (info->params.mode == MGSL_MODE_RAW)
- val |= BIT13;
+ switch(info->params.mode) {
+ case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
+ case MGSL_MODE_BISYNC: val |= BIT15; break;
+ case MGSL_MODE_RAW: val |= BIT13; break;
+ }
switch(info->params.encoding)
{
@@ -4309,10 +4325,15 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
while(!done) {
/* reset current buffer for reuse */
info->rbufs[i].status = 0;
- if (info->params.mode == MGSL_MODE_RAW)
+ switch(info->params.mode) {
+ case MGSL_MODE_RAW:
+ case MGSL_MODE_MONOSYNC:
+ case MGSL_MODE_BISYNC:
set_desc_count(info->rbufs[i], info->raw_rx_size);
- else
+ break;
+ default:
set_desc_count(info->rbufs[i], DMABUFSIZE);
+ }
if (i == last)
done = 1;
@@ -4477,13 +4498,24 @@ cleanup:
static int rx_get_buf(struct slgt_info *info)
{
unsigned int i = info->rbuf_current;
+ unsigned int count;
if (!desc_complete(info->rbufs[i]))
return 0;
- DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx");
- DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i])));
- ldisc_receive_buf(info->tty, info->rbufs[i].buf,
- info->flag_buf, desc_count(info->rbufs[i]));
+ count = desc_count(info->rbufs[i]);
+ switch(info->params.mode) {
+ case MGSL_MODE_MONOSYNC:
+ case MGSL_MODE_BISYNC:
+ /* ignore residue in byte synchronous modes */
+ if (desc_residue(info->rbufs[i]))
+ count--;
+ break;
+ }
+ DBGDATA(info, info->rbufs[i].buf, count, "rx");
+ DBGINFO(("rx_get_buf size=%d\n", count));
+ if (count)
+ ldisc_receive_buf(info->tty, info->rbufs[i].buf,
+ info->flag_buf, count);
free_rbufs(info, i, i);
return 1;
}
@@ -4549,8 +4581,13 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
size -= count;
buf += count;
- if (!size && info->params.mode != MGSL_MODE_RAW)
- set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */
+ /*
+ * set EOF bit for last buffer of HDLC frame or
+ * for every buffer in raw mode
+ */
+ if ((!size && info->params.mode == MGSL_MODE_HDLC) ||
+ info->params.mode == MGSL_MODE_RAW)
+ set_desc_eof(*d, 1);
else
set_desc_eof(*d, 0);
diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
index 66f3754fbbdf..3e932b681371 100644
--- a/drivers/char/synclinkmp.c
+++ b/drivers/char/synclinkmp.c
@@ -2596,8 +2596,7 @@ void isr_io_pin( SLMP_INFO *info, u16 status )
* dev_id device ID supplied during interrupt registration
* regs interrupted processor context
*/
-static irqreturn_t synclinkmp_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t synclinkmp_interrupt(int irq, void *dev_id)
{
SLMP_INFO * info;
unsigned char status, status0, status1=0;
@@ -3929,7 +3928,7 @@ void device_init(int adapter_num, struct pci_dev *pdev)
}
}
-static struct tty_operations ops = {
+static const struct tty_operations ops = {
.open = open,
.close = close,
.write = write,
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index ee3ca8f1768e..5f49280779fb 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -35,14 +35,15 @@
#include <linux/vt_kern.h>
#include <linux/workqueue.h>
#include <linux/kexec.h>
+#include <linux/irq.h>
#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
/* Whether we react on sysrq keys or just ignore them */
int sysrq_enabled = 1;
-static void sysrq_handle_loglevel(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_loglevel(int key, struct tty_struct *tty)
{
int i;
i = key - '0';
@@ -58,8 +59,7 @@ static struct sysrq_key_op sysrq_loglevel_op = {
};
#ifdef CONFIG_VT
-static void sysrq_handle_SAK(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_SAK(int key, struct tty_struct *tty)
{
if (tty)
do_SAK(tty);
@@ -76,8 +76,7 @@ static struct sysrq_key_op sysrq_SAK_op = {
#endif
#ifdef CONFIG_VT
-static void sysrq_handle_unraw(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_unraw(int key, struct tty_struct *tty)
{
struct kbd_struct *kbd = &kbd_table[fg_console];
@@ -95,10 +94,9 @@ static struct sysrq_key_op sysrq_unraw_op = {
#endif /* CONFIG_VT */
#ifdef CONFIG_KEXEC
-static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_crashdump(int key, struct tty_struct *tty)
{
- crash_kexec(pt_regs);
+ crash_kexec(get_irq_regs());
}
static struct sysrq_key_op sysrq_crashdump_op = {
.handler = sysrq_handle_crashdump,
@@ -110,9 +108,9 @@ static struct sysrq_key_op sysrq_crashdump_op = {
#define sysrq_crashdump_op (*(struct sysrq_key_op *)0)
#endif
-static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_reboot(int key, struct tty_struct *tty)
{
+ lockdep_off();
local_irq_enable();
emergency_restart();
}
@@ -123,8 +121,7 @@ static struct sysrq_key_op sysrq_reboot_op = {
.enable_mask = SYSRQ_ENABLE_BOOT,
};
-static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_sync(int key, struct tty_struct *tty)
{
emergency_sync();
}
@@ -135,8 +132,7 @@ static struct sysrq_key_op sysrq_sync_op = {
.enable_mask = SYSRQ_ENABLE_SYNC,
};
-static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_mountro(int key, struct tty_struct *tty)
{
emergency_remount();
}
@@ -148,8 +144,7 @@ static struct sysrq_key_op sysrq_mountro_op = {
};
#ifdef CONFIG_LOCKDEP
-static void sysrq_handle_showlocks(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_showlocks(int key, struct tty_struct *tty)
{
debug_show_all_locks();
}
@@ -163,11 +158,11 @@ static struct sysrq_key_op sysrq_showlocks_op = {
#define sysrq_showlocks_op (*(struct sysrq_key_op *)0)
#endif
-static void sysrq_handle_showregs(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_showregs(int key, struct tty_struct *tty)
{
- if (pt_regs)
- show_regs(pt_regs);
+ struct pt_regs *regs = get_irq_regs();
+ if (regs)
+ show_regs(regs);
}
static struct sysrq_key_op sysrq_showregs_op = {
.handler = sysrq_handle_showregs,
@@ -176,8 +171,7 @@ static struct sysrq_key_op sysrq_showregs_op = {
.enable_mask = SYSRQ_ENABLE_DUMP,
};
-static void sysrq_handle_showstate(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_showstate(int key, struct tty_struct *tty)
{
show_state();
}
@@ -188,8 +182,7 @@ static struct sysrq_key_op sysrq_showstate_op = {
.enable_mask = SYSRQ_ENABLE_DUMP,
};
-static void sysrq_handle_showmem(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_showmem(int key, struct tty_struct *tty)
{
show_mem();
}
@@ -208,14 +201,13 @@ static void send_sig_all(int sig)
struct task_struct *p;
for_each_process(p) {
- if (p->mm && p->pid != 1)
+ if (p->mm && !is_init(p))
/* Not swapper, init nor kernel thread */
force_sig(sig, p);
}
}
-static void sysrq_handle_term(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_term(int key, struct tty_struct *tty)
{
send_sig_all(SIGTERM);
console_loglevel = 8;
@@ -235,8 +227,7 @@ static void moom_callback(void *ignored)
static DECLARE_WORK(moom_work, moom_callback, NULL);
-static void sysrq_handle_moom(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_moom(int key, struct tty_struct *tty)
{
schedule_work(&moom_work);
}
@@ -246,8 +237,7 @@ static struct sysrq_key_op sysrq_moom_op = {
.action_msg = "Manual OOM execution",
};
-static void sysrq_handle_kill(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_kill(int key, struct tty_struct *tty)
{
send_sig_all(SIGKILL);
console_loglevel = 8;
@@ -259,8 +249,7 @@ static struct sysrq_key_op sysrq_kill_op = {
.enable_mask = SYSRQ_ENABLE_SIGNAL,
};
-static void sysrq_handle_unrt(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void sysrq_handle_unrt(int key, struct tty_struct *tty)
{
normalize_rt_tasks();
}
@@ -360,8 +349,7 @@ static void __sysrq_put_key_op(int key, struct sysrq_key_op *op_p)
* This is the non-locking version of handle_sysrq. It must/can only be called
* by sysrq key handlers, as they are inside of the lock
*/
-void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty,
- int check_mask)
+void __handle_sysrq(int key, struct tty_struct *tty, int check_mask)
{
struct sysrq_key_op *op_p;
int orig_log_level;
@@ -383,7 +371,7 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty,
(sysrq_enabled & op_p->enable_mask)) {
printk("%s\n", op_p->action_msg);
console_loglevel = orig_log_level;
- op_p->handler(key, pt_regs, tty);
+ op_p->handler(key, tty);
} else {
printk("This sysrq operation is disabled.\n");
}
@@ -412,11 +400,11 @@ void __handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty,
* This function is called by the keyboard handler when SysRq is pressed
* and any other keycode arrives.
*/
-void handle_sysrq(int key, struct pt_regs *pt_regs, struct tty_struct *tty)
+void handle_sysrq(int key, struct tty_struct *tty)
{
if (!sysrq_enabled)
return;
- __handle_sysrq(key, pt_regs, tty, 1);
+ __handle_sysrq(key, tty, 1);
}
EXPORT_SYMBOL(handle_sysrq);
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index d30dc09dbbc9..9df0ca1be0e3 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -224,14 +224,16 @@ probe_ti_parallel(int minor)
{
int i;
int seq[] = { 0x00, 0x20, 0x10, 0x30 };
+ int data;
for (i = 3; i >= 0; i--) {
outbyte(3, minor);
outbyte(i, minor);
udelay(delay);
+ data = inbyte(minor) & 0x30;
pr_debug("tipar: Probing -> %i: 0x%02x 0x%02x\n", i,
- data & 0x30, seq[i]);
- if ((inbyte(minor) & 0x30) != seq[i]) {
+ data, seq[i]);
+ if (data != seq[i]) {
outbyte(3, minor);
return -1;
}
diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c
index d2c5ba4e83b8..2444a0e24b31 100644
--- a/drivers/char/tlclk.c
+++ b/drivers/char/tlclk.c
@@ -193,7 +193,7 @@ static DEFINE_SPINLOCK(event_lock);
static int tlclk_major = TLCLK_MAJOR;
-static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t tlclk_interrupt(int irq, void *dev_id);
static DECLARE_WAIT_QUEUE_HEAD(wq);
@@ -856,7 +856,7 @@ static void switchover_timeout(unsigned long data)
wake_up(&wq);
}
-static irqreturn_t tlclk_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tlclk_interrupt(int irq, void *dev_id)
{
unsigned long flags;
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index a082a2e34252..6ad2d3bb945c 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -1153,7 +1153,14 @@ struct tpm_chip *tpm_register_hardware(struct device *dev, const struct tpm_vend
spin_unlock(&driver_lock);
- sysfs_create_group(&dev->kobj, chip->vendor.attr_group);
+ if (sysfs_create_group(&dev->kobj, chip->vendor.attr_group)) {
+ list_del(&chip->list);
+ put_device(dev);
+ clear_bit(chip->dev_num, dev_mask);
+ kfree(chip);
+ kfree(devname);
+ return NULL;
+ }
chip->bios_dir = tpm_bios_log_setup(devname);
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index ad8ffe49256f..1ab0896070be 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -184,7 +184,9 @@ static int __init init_atmel(void)
unsigned long base;
struct tpm_chip *chip;
- driver_register(&atml_drv);
+ rc = driver_register(&atml_drv);
+ if (rc)
+ return rc;
if ((iobase = atmel_get_base_addr(&base, &region_size)) == NULL) {
rc = -ENODEV;
@@ -195,10 +197,8 @@ static int __init init_atmel(void)
(atmel_request_region
(tpm_atmel.base, region_size, "tpm_atmel0") == NULL) ? 0 : 1;
-
- if (IS_ERR
- (pdev =
- platform_device_register_simple("tpm_atmel", -1, NULL, 0))) {
+ pdev = platform_device_register_simple("tpm_atmel", -1, NULL, 0);
+ if (IS_ERR(pdev)) {
rc = PTR_ERR(pdev);
goto err_rel_reg;
}
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 26287aace87d..608f73071bef 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -284,7 +284,7 @@ static struct device_driver nsc_drv = {
static int __init init_nsc(void)
{
int rc = 0;
- int lo, hi;
+ int lo, hi, err;
int nscAddrBase = TPM_ADDR;
struct tpm_chip *chip;
unsigned long base;
@@ -297,7 +297,9 @@ static int __init init_nsc(void)
return -ENODEV;
}
- driver_register(&nsc_drv);
+ err = driver_register(&nsc_drv);
+ if (err)
+ return err;
hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index ee7ac6f43c65..483f3f60013c 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -377,7 +377,7 @@ static struct tpm_vendor_specific tpm_tis = {
.fops = &tis_ops,},
};
-static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tis_int_probe(int irq, void *dev_id)
{
struct tpm_chip *chip = (struct tpm_chip *) dev_id;
u32 interrupt;
@@ -397,7 +397,7 @@ static irqreturn_t tis_int_probe(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t tis_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tis_int_handler(int irq, void *dev_id)
{
struct tpm_chip *chip = (struct tpm_chip *) dev_id;
u32 interrupt;
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index bb0d9199e994..e90ea39c7c4b 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -129,6 +129,7 @@ LIST_HEAD(tty_drivers); /* linked list of tty drivers */
/* Semaphore to protect creating and releasing a tty. This is shared with
vt.c for deeply disgusting hack reasons */
DEFINE_MUTEX(tty_mutex);
+EXPORT_SYMBOL(tty_mutex);
#ifdef CONFIG_UNIX98_PTYS
extern struct tty_driver *ptm_driver; /* Unix98 pty masters; for /dev/ptmx */
@@ -160,17 +161,11 @@ static void release_mem(struct tty_struct *tty, int idx);
* been initialized in any way but has been zeroed
*
* Locking: none
- * FIXME: use kzalloc
*/
static struct tty_struct *alloc_tty_struct(void)
{
- struct tty_struct *tty;
-
- tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
- if (tty)
- memset(tty, 0, sizeof(struct tty_struct));
- return tty;
+ return kzalloc(sizeof(struct tty_struct), GFP_KERNEL);
}
static void tty_buffer_free_all(struct tty_struct *);
@@ -483,10 +478,9 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
tb->used += space;
copied += space;
chars += space;
- }
- /* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
- while (unlikely(size > copied));
+ /* There is a small chance that we need to split the data over
+ several buffers. If this is the case we must loop */
+ } while (unlikely(size > copied));
return copied;
}
EXPORT_SYMBOL(tty_insert_flip_string);
@@ -521,10 +515,9 @@ int tty_insert_flip_string_flags(struct tty_struct *tty,
copied += space;
chars += space;
flags += space;
- }
- /* There is a small chance that we need to split the data over
- several buffers. If this is the case we must loop */
- while (unlikely(size > copied));
+ /* There is a small chance that we need to split the data over
+ several buffers. If this is the case we must loop */
+ } while (unlikely(size > copied));
return copied;
}
EXPORT_SYMBOL(tty_insert_flip_string_flags);
@@ -626,9 +619,9 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
{
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_line = num;
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
}
/*
@@ -1346,9 +1339,9 @@ static void do_tty_hangup(void *data)
*/
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
{
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
*tty->termios = tty->driver->init_termios;
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
}
/* Defer ldisc switch */
@@ -2072,8 +2065,9 @@ fail_no_mem:
/* call the tty release_mem routine to clean out this slot */
release_mem_out:
- printk(KERN_INFO "init_dev: ldisc open failed, "
- "clearing slot %d\n", idx);
+ if (printk_ratelimit())
+ printk(KERN_INFO "init_dev: ldisc open failed, "
+ "clearing slot %d\n", idx);
release_mem(tty, idx);
goto end_init;
}
@@ -2726,6 +2720,8 @@ static int tty_fasync(int fd, struct file * filp, int on)
* Locking:
* Called functions take tty_ldisc_lock
* current->signal->tty check is safe without locks
+ *
+ * FIXME: may race normal receive processing
*/
static int tiocsti(struct tty_struct *tty, char __user *p)
@@ -2748,18 +2744,21 @@ static int tiocsti(struct tty_struct *tty, char __user *p)
* @tty; tty
* @arg: user buffer for result
*
- * Copies the kernel idea of the window size into the user buffer. No
- * locking is done.
+ * Copies the kernel idea of the window size into the user buffer.
*
- * FIXME: Returning random values racing a window size set is wrong
- * should lock here against that
+ * Locking: tty->termios_sem is taken to ensure the winsize data
+ * is consistent.
*/
static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
{
- if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
- return -EFAULT;
- return 0;
+ int err;
+
+ mutex_lock(&tty->termios_mutex);
+ err = copy_to_user(arg, &tty->winsize, sizeof(*arg));
+ mutex_unlock(&tty->termios_mutex);
+
+ return err ? -EFAULT: 0;
}
/**
@@ -2772,12 +2771,11 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
* actually has driver level meaning and triggers a VC resize.
*
* Locking:
- * The console_sem is used to ensure we do not try and resize
- * the console twice at once.
- * FIXME: Two racing size sets may leave the console and kernel
- * parameters disagreeing. Is this exploitable ?
- * FIXME: Random values racing a window size get is wrong
- * should lock here against that
+ * Called function use the console_sem is used to ensure we do
+ * not try and resize the console twice at once.
+ * The tty->termios_sem is used to ensure we don't double
+ * resize and get confused. Lock order - tty->termios.sem before
+ * console sem
*/
static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
@@ -2787,17 +2785,18 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
+
+ mutex_lock(&tty->termios_mutex);
if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
- return 0;
+ goto done;
+
#ifdef CONFIG_VT
if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
- int rc;
-
- acquire_console_sem();
- rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row);
- release_console_sem();
- if (rc)
- return -ENXIO;
+ if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col,
+ tmp_ws.ws_row)) {
+ mutex_unlock(&tty->termios_mutex);
+ return -ENXIO;
+ }
}
#endif
if (tty->pgrp > 0)
@@ -2806,6 +2805,8 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
kill_pg(real_tty->pgrp, SIGWINCH, 1);
tty->winsize = tmp_ws;
real_tty->winsize = tmp_ws;
+done:
+ mutex_unlock(&tty->termios_mutex);
return 0;
}
@@ -2880,9 +2881,7 @@ static int fionbio(struct file *file, int __user *p)
* Locking:
* Takes tasklist lock internally to walk sessions
* Takes task_lock() when updating signal->tty
- *
- * FIXME: tty_mutex is needed to protect signal->tty references.
- * FIXME: why task_lock on the signal->tty reference ??
+ * Takes tty_mutex() to protect tty instance
*
*/
@@ -2917,9 +2916,11 @@ static int tiocsctty(struct tty_struct *tty, int arg)
} else
return -EPERM;
}
+ mutex_lock(&tty_mutex);
task_lock(current);
current->signal->tty = tty;
task_unlock(current);
+ mutex_unlock(&tty_mutex);
current->signal->tty_old_pgrp = 0;
tty->session = current->signal->session;
tty->pgrp = process_group(current);
@@ -2959,8 +2960,6 @@ static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t
* permitted where the tty session is our session.
*
* Locking: None
- *
- * FIXME: current->signal->tty referencing is unsafe.
*/
static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
@@ -3039,19 +3038,20 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
* timed break functionality.
*
* Locking:
- * None
+ * atomic_write_lock serializes
*
- * FIXME:
- * What if two overlap
*/
static int send_break(struct tty_struct *tty, unsigned int duration)
{
+ if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ return -EINTR;
tty->driver->break_ctl(tty, -1);
if (!signal_pending(current)) {
msleep_interruptible(duration);
}
tty->driver->break_ctl(tty, 0);
+ mutex_unlock(&tty->atomic_write_lock);
if (signal_pending(current))
return -EINTR;
return 0;
@@ -3144,6 +3144,8 @@ int tty_ioctl(struct inode * inode, struct file * file,
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
return -EINVAL;
+ /* CHECKME: is this safe as one end closes ? */
+
real_tty = tty;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -3580,7 +3582,7 @@ static void initialize_tty_struct(struct tty_struct *tty)
tty_buffer_init(tty);
INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
init_MUTEX(&tty->buf.pty_sem);
- init_MUTEX(&tty->termios_sem);
+ mutex_init(&tty->termios_mutex);
init_waitqueue_head(&tty->write_wait);
init_waitqueue_head(&tty->read_wait);
INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
@@ -3678,7 +3680,8 @@ void put_tty_driver(struct tty_driver *driver)
kfree(driver);
}
-void tty_set_operations(struct tty_driver *driver, struct tty_operations *op)
+void tty_set_operations(struct tty_driver *driver,
+ const struct tty_operations *op)
{
driver->open = op->open;
driver->close = op->close;
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 4ad47d321bd4..3b6fa7b0be8b 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -20,6 +20,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/bitops.h>
+#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -131,7 +132,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
/* FIXME: we need to decide on some locking/ordering semantics
for the set_termios notification eventually */
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
*tty->termios = *new_termios;
unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
@@ -176,7 +177,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios
(ld->set_termios)(tty, &old_termios);
tty_ldisc_deref(ld);
}
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
}
/**
@@ -284,13 +285,13 @@ static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
{
struct sgttyb tmp;
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
tmp.sg_ispeed = 0;
tmp.sg_ospeed = 0;
tmp.sg_erase = tty->termios->c_cc[VERASE];
tmp.sg_kill = tty->termios->c_cc[VKILL];
tmp.sg_flags = get_sgflags(tty);
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
@@ -345,12 +346,12 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
return -EFAULT;
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
termios = *tty->termios;
termios.c_cc[VERASE] = tmp.sg_erase;
termios.c_cc[VKILL] = tmp.sg_kill;
set_sgflags(&termios, tmp.sg_flags);
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
change_termios(tty, &termios);
return 0;
}
@@ -422,24 +423,28 @@ static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
*
* Send a high priority character to the tty even if stopped
*
- * Locking: none
- *
- * FIXME: overlapping calls with start/stop tty lose state of tty
+ * Locking: none for xchar method, write ordering for write method.
*/
-static void send_prio_char(struct tty_struct *tty, char ch)
+static int send_prio_char(struct tty_struct *tty, char ch)
{
int was_stopped = tty->stopped;
if (tty->driver->send_xchar) {
tty->driver->send_xchar(tty, ch);
- return;
+ return 0;
}
+
+ if (mutex_lock_interruptible(&tty->atomic_write_lock))
+ return -ERESTARTSYS;
+
if (was_stopped)
start_tty(tty);
tty->driver->write(tty, &ch, 1);
if (was_stopped)
stop_tty(tty);
+ mutex_unlock(&tty->atomic_write_lock);
+ return 0;
}
int n_tty_ioctl(struct tty_struct * tty, struct file * file,
@@ -513,11 +518,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
break;
case TCIOFF:
if (STOP_CHAR(tty) != __DISABLED_CHAR)
- send_prio_char(tty, STOP_CHAR(tty));
+ return send_prio_char(tty, STOP_CHAR(tty));
break;
case TCION:
if (START_CHAR(tty) != __DISABLED_CHAR)
- send_prio_char(tty, START_CHAR(tty));
+ return send_prio_char(tty, START_CHAR(tty));
break;
default:
return -EINVAL;
@@ -592,11 +597,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
case TIOCSSOFTCAR:
if (get_user(arg, (unsigned int __user *) arg))
return -EFAULT;
- down(&tty->termios_sem);
+ mutex_lock(&tty->termios_mutex);
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
- up(&tty->termios_sem);
+ mutex_unlock(&tty->termios_mutex);
return 0;
default:
return -ENOIOCTLCMD;
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index a9247b5213d5..bd7a98c6ea7a 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -474,14 +474,15 @@ static const struct file_operations vcs_fops = {
static struct class *vc_class;
-void vcs_make_devfs(struct tty_struct *tty)
+void vcs_make_sysfs(struct tty_struct *tty)
{
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 1),
NULL, "vcs%u", tty->index + 1);
class_device_create(vc_class, NULL, MKDEV(VCS_MAJOR, tty->index + 129),
NULL, "vcsa%u", tty->index + 1);
}
-void vcs_remove_devfs(struct tty_struct *tty)
+
+void vcs_remove_sysfs(struct tty_struct *tty)
{
class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 1));
class_device_destroy(vc_class, MKDEV(VCS_MAJOR, tty->index + 129));
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
index f3efeaf2826e..6d2e314860df 100644
--- a/drivers/char/viocons.c
+++ b/drivers/char/viocons.c
@@ -947,7 +947,7 @@ static void vioHandleData(struct HvLpEvent *event)
*/
continue;
} else if (vio_sysrq_pressed) {
- handle_sysrq(cevent->data[index], NULL, tty);
+ handle_sysrq(cevent->data[index], tty);
vio_sysrq_pressed = 0;
/*
* continue because we don't want to add
@@ -1047,7 +1047,7 @@ static int send_open(HvLpIndex remoteLp, void *sem)
0, 0, 0, 0);
}
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
.open = viotty_open,
.close = viotty_close,
.write = viotty_write,
diff --git a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
index bfe5ea948f6a..d0b94dd1af6d 100644
--- a/drivers/char/vme_scc.c
+++ b/drivers/char/vme_scc.c
@@ -81,10 +81,10 @@ static int scc_ioctl(struct tty_struct * tty, struct file * filp,
unsigned int cmd, unsigned long arg);
static void scc_throttle(struct tty_struct *tty);
static void scc_unthrottle(struct tty_struct *tty);
-static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp);
-static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp);
-static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp);
-static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp);
+static irqreturn_t scc_tx_int(int irq, void *data);
+static irqreturn_t scc_rx_int(int irq, void *data);
+static irqreturn_t scc_stat_int(int irq, void *data);
+static irqreturn_t scc_spcond_int(int irq, void *data);
static void scc_setsignals(struct scc_port *port, int dtr, int rts);
static void scc_break_ctl(struct tty_struct *tty, int break_state);
@@ -113,7 +113,7 @@ static struct real_driver scc_real_driver = {
};
-static struct tty_operations scc_ops = {
+static const struct tty_operations scc_ops = {
.open = scc_open,
.close = gs_close,
.write = gs_write,
@@ -419,7 +419,7 @@ module_init(vme_scc_init);
* Interrupt handlers
*--------------------------------------------------------------------------*/
-static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp)
+static irqreturn_t scc_rx_int(int irq, void *data)
{
unsigned char ch;
struct scc_port *port = data;
@@ -440,7 +440,7 @@ static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp)
*/
if (SCCread(INT_PENDING_REG) &
(port->channel == CHANNEL_A ? IPR_A_RX : IPR_B_RX)) {
- scc_spcond_int (irq, data, fp);
+ scc_spcond_int (irq, data);
return IRQ_HANDLED;
}
@@ -451,7 +451,7 @@ static irqreturn_t scc_rx_int(int irq, void *data, struct pt_regs *fp)
}
-static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp)
+static irqreturn_t scc_spcond_int(int irq, void *data)
{
struct scc_port *port = data;
struct tty_struct *tty = port->gs.tty;
@@ -496,7 +496,7 @@ static irqreturn_t scc_spcond_int(int irq, void *data, struct pt_regs *fp)
}
-static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp)
+static irqreturn_t scc_tx_int(int irq, void *data)
{
struct scc_port *port = data;
SCC_ACCESS_INIT(port);
@@ -538,7 +538,7 @@ static irqreturn_t scc_tx_int(int irq, void *data, struct pt_regs *fp)
}
-static irqreturn_t scc_stat_int(int irq, void *data, struct pt_regs *fp)
+static irqreturn_t scc_stat_int(int irq, void *data)
{
struct scc_port *port = data;
unsigned channel = port->channel;
@@ -593,7 +593,7 @@ static void scc_enable_tx_interrupts(void *ptr)
local_irq_save(flags);
SCCmod(INT_AND_DMA_REG, 0xff, IDR_TX_INT_ENAB);
/* restart the transmitter */
- scc_tx_int (0, port, 0);
+ scc_tx_int (0, port);
local_irq_restore(flags);
}
diff --git a/drivers/char/vr41xx_giu.c b/drivers/char/vr41xx_giu.c
index 8116a47b80f4..8e7949305171 100644
--- a/drivers/char/vr41xx_giu.c
+++ b/drivers/char/vr41xx_giu.c
@@ -221,7 +221,7 @@ static struct hw_interrupt_type giuint_high_irq_type = {
.end = end_giuint_high_irq,
};
-static int giu_get_irq(unsigned int irq, struct pt_regs *regs)
+static int giu_get_irq(unsigned int irq)
{
uint16_t pendl, pendh, maskl, maskh;
int i;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index da7e66a2a38b..8e4413f6fbaf 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -63,6 +63,13 @@
*
* Removed console_lock, enabled interrupts across all console operations
* 13 March 2001, Andrew Morton
+ *
+ * Fixed UTF-8 mode so alternate charset modes always work according
+ * to control sequences interpreted in do_con_trol function
+ * preserving backward VT100 semigraphics compatibility,
+ * malformed UTF sequences represented as sequences of replacement glyphs,
+ * original codes or '?' as a last resort if replacement glyph is undefined
+ * by Adam Tla/lka <atlka@pg.gda.pl>, Aug 2006
*/
#include <linux/module.h>
@@ -99,7 +106,8 @@
#define MAX_NR_CON_DRIVER 16
#define CON_DRIVER_FLAG_MODULE 1
-#define CON_DRIVER_FLAG_INIT 2
+#define CON_DRIVER_FLAG_INIT 2
+#define CON_DRIVER_FLAG_ATTR 4
struct con_driver {
const struct consw *con;
@@ -128,16 +136,8 @@ const struct consw *conswitchp;
#define DEFAULT_BELL_PITCH 750
#define DEFAULT_BELL_DURATION (HZ/8)
-extern void vcs_make_devfs(struct tty_struct *tty);
-extern void vcs_remove_devfs(struct tty_struct *tty);
-
-extern void console_map_init(void);
-#ifdef CONFIG_PROM_CONSOLE
-extern void prom_con_init(void);
-#endif
-#ifdef CONFIG_MDA_CONSOLE
-extern int mda_console_init(void);
-#endif
+extern void vcs_make_sysfs(struct tty_struct *tty);
+extern void vcs_remove_sysfs(struct tty_struct *tty);
struct vc vc_cons [MAX_NR_CONSOLES];
@@ -730,7 +730,8 @@ int vc_allocate(unsigned int currcons) /* return 0 on success */
visual_init(vc, currcons, 1);
if (!*vc->vc_uni_pagedir_loc)
con_set_default_unimap(vc);
- vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
+ if (!vc->vc_kmalloced)
+ vc->vc_screenbuf = kmalloc(vc->vc_screenbuf_size, GFP_KERNEL);
if (!vc->vc_screenbuf) {
kfree(vc);
vc_cons[currcons].d = NULL;
@@ -878,14 +879,24 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
return err;
}
+int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
+{
+ int rc;
+
+ acquire_console_sem();
+ rc = vc_resize(vc, cols, lines);
+ release_console_sem();
+ return rc;
+}
-void vc_disallocate(unsigned int currcons)
+void vc_deallocate(unsigned int currcons)
{
WARN_CONSOLE_UNLOCKED();
if (vc_cons_allocated(currcons)) {
struct vc_data *vc = vc_cons[currcons].d;
vc->vc_sw->con_deinit(vc);
+ put_pid(vc->vt_pid);
module_put(vc->vc_sw->owner);
if (vc->vc_kmalloced)
kfree(vc->vc_screenbuf);
@@ -2005,17 +2016,23 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
/* Do no translation at all in control states */
if (vc->vc_state != ESnormal) {
tc = c;
- } else if (vc->vc_utf) {
+ } else if (vc->vc_utf && !vc->vc_disp_ctrl) {
/* Combine UTF-8 into Unicode */
- /* Incomplete characters silently ignored */
+ /* Malformed sequences as sequences of replacement glyphs */
+rescan_last_byte:
if(c > 0x7f) {
- if (vc->vc_utf_count > 0 && (c & 0xc0) == 0x80) {
- vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
- vc->vc_utf_count--;
- if (vc->vc_utf_count == 0)
- tc = c = vc->vc_utf_char;
- else continue;
+ if (vc->vc_utf_count) {
+ if ((c & 0xc0) == 0x80) {
+ vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
+ if (--vc->vc_utf_count) {
+ vc->vc_npar++;
+ continue;
+ }
+ tc = c = vc->vc_utf_char;
+ } else
+ goto replacement_glyph;
} else {
+ vc->vc_npar = 0;
if ((c & 0xe0) == 0xc0) {
vc->vc_utf_count = 1;
vc->vc_utf_char = (c & 0x1f);
@@ -2032,14 +2049,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
vc->vc_utf_count = 5;
vc->vc_utf_char = (c & 0x01);
} else
- vc->vc_utf_count = 0;
+ goto replacement_glyph;
continue;
}
} else {
+ if (vc->vc_utf_count)
+ goto replacement_glyph;
tc = c;
- vc->vc_utf_count = 0;
}
- } else { /* no utf */
+ } else { /* no utf or alternate charset mode */
tc = vc->vc_translate[vc->vc_toggle_meta ? (c | 0x80) : c];
}
@@ -2054,31 +2072,33 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
* direct-to-font zone in UTF-8 mode.
*/
ok = tc && (c >= 32 ||
- (!vc->vc_utf && !(((vc->vc_disp_ctrl ? CTRL_ALWAYS
- : CTRL_ACTION) >> c) & 1)))
+ !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
+ vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
&& (c != 127 || vc->vc_disp_ctrl)
&& (c != 128+27);
if (vc->vc_state == ESnormal && ok) {
/* Now try to find out how to display it */
tc = conv_uni_to_pc(vc, tc);
- if ( tc == -4 ) {
+ if (tc & ~charmask) {
+ if ( tc == -4 ) {
/* If we got -4 (not found) then see if we have
defined a replacement character (U+FFFD) */
- tc = conv_uni_to_pc(vc, 0xfffd);
-
- /* One reason for the -4 can be that we just
- did a clear_unimap();
- try at least to show something. */
- if (tc == -4)
- tc = c;
- } else if ( tc == -3 ) {
- /* Bad hash table -- hope for the best */
- tc = c;
- }
- if (tc & ~charmask)
- continue; /* Conversion failed */
+replacement_glyph:
+ tc = conv_uni_to_pc(vc, 0xfffd);
+ if (!(tc & ~charmask))
+ goto display_glyph;
+ } else if ( tc != -3 )
+ continue; /* nothing to display */
+ /* no hash table or no replacement --
+ * hope for the best */
+ if ( c & ~charmask )
+ tc = '?';
+ else
+ tc = c;
+ }
+display_glyph:
if (vc->vc_need_wrap || vc->vc_decim)
FLUSH
if (vc->vc_need_wrap) {
@@ -2102,6 +2122,15 @@ static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int co
vc->vc_x++;
draw_to = (vc->vc_pos += 2);
}
+ if (vc->vc_utf_count) {
+ if (vc->vc_npar) {
+ vc->vc_npar--;
+ goto display_glyph;
+ }
+ vc->vc_utf_count = 0;
+ c = orig;
+ goto rescan_last_byte;
+ }
continue;
}
FLUSH
@@ -2498,7 +2527,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
}
release_console_sem();
- vcs_make_devfs(tty);
+ vcs_make_sysfs(tty);
return ret;
}
}
@@ -2511,7 +2540,7 @@ static int con_open(struct tty_struct *tty, struct file *filp)
* and taking a ref against the tty while we're in the process of forgetting
* about it and cleaning things up.
*
- * This is because vcs_remove_devfs() can sleep and will drop the BKL.
+ * This is because vcs_remove_sysfs() can sleep and will drop the BKL.
*/
static void con_close(struct tty_struct *tty, struct file *filp)
{
@@ -2524,7 +2553,7 @@ static void con_close(struct tty_struct *tty, struct file *filp)
vc->vc_tty = NULL;
tty->driver_data = NULL;
release_console_sem();
- vcs_remove_devfs(tty);
+ vcs_remove_sysfs(tty);
mutex_unlock(&tty_mutex);
/*
* tty_mutex is released, but we still hold BKL, so there is
@@ -2639,7 +2668,7 @@ static int __init con_init(void)
}
console_initcall(con_init);
-static struct tty_operations con_ops = {
+static const struct tty_operations con_ops = {
.open = con_open,
.close = con_close,
.write = con_write,
@@ -3034,22 +3063,37 @@ static struct class_device_attribute class_device_attrs[] = {
static int vtconsole_init_class_device(struct con_driver *con)
{
int i;
+ int error = 0;
+ con->flag |= CON_DRIVER_FLAG_ATTR;
class_set_devdata(con->class_dev, con);
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_create_file(con->class_dev,
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
+ error = class_device_create_file(con->class_dev,
&class_device_attrs[i]);
+ if (error)
+ break;
+ }
- return 0;
+ if (error) {
+ while (--i >= 0)
+ class_device_remove_file(con->class_dev,
+ &class_device_attrs[i]);
+ con->flag &= ~CON_DRIVER_FLAG_ATTR;
+ }
+
+ return error;
}
static void vtconsole_deinit_class_device(struct con_driver *con)
{
int i;
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_remove_file(con->class_dev,
- &class_device_attrs[i]);
+ if (con->flag & CON_DRIVER_FLAG_ATTR) {
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_remove_file(con->class_dev,
+ &class_device_attrs[i]);
+ con->flag &= ~CON_DRIVER_FLAG_ATTR;
+ }
}
/**
@@ -3148,6 +3192,7 @@ int register_con_driver(const struct consw *csw, int first, int last)
} else {
vtconsole_init_class_device(con_driver);
}
+
err:
release_console_sem();
module_put(owner);
@@ -3765,6 +3810,7 @@ EXPORT_SYMBOL(default_blu);
EXPORT_SYMBOL(update_region);
EXPORT_SYMBOL(redraw_screen);
EXPORT_SYMBOL(vc_resize);
+EXPORT_SYMBOL(vc_lock_resize);
EXPORT_SYMBOL(fg_console);
EXPORT_SYMBOL(console_blank_hook);
EXPORT_SYMBOL(console_blanked);
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index a5628a8b6620..ac5d60edbafa 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -96,7 +96,7 @@ do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, int perm, struct kbd_str
if (!perm)
return -EPERM;
if (!i && v == K_NOSUCHMAP) {
- /* disallocate map */
+ /* deallocate map */
key_map = key_maps[s];
if (s && key_map) {
key_maps[s] = NULL;
@@ -645,13 +645,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
*/
case KDSIGACCEPT:
{
- extern int spawnpid, spawnsig;
if (!perm || !capable(CAP_KILL))
return -EPERM;
if (!valid_signal(arg) || arg < 1 || arg == SIGKILL)
return -EINVAL;
- spawnpid = current->pid;
- spawnsig = arg;
+
+ spin_lock_irq(&vt_spawn_con.lock);
+ put_pid(vt_spawn_con.pid);
+ vt_spawn_con.pid = get_pid(task_pid(current));
+ vt_spawn_con.sig = arg;
+ spin_unlock_irq(&vt_spawn_con.lock);
return 0;
}
@@ -669,7 +672,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
vc->vt_mode.frsig = 0;
- vc->vt_pid = current->pid;
+ put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current))));
/* no switch is required -- saw@shade.msu.ru */
vc->vt_newvt = -1;
release_console_sem();
@@ -819,20 +822,20 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (arg > MAX_NR_CONSOLES)
return -ENXIO;
if (arg == 0) {
- /* disallocate all unused consoles, but leave 0 */
+ /* deallocate all unused consoles, but leave 0 */
acquire_console_sem();
for (i=1; i<MAX_NR_CONSOLES; i++)
if (! VT_BUSY(i))
- vc_disallocate(i);
+ vc_deallocate(i);
release_console_sem();
} else {
- /* disallocate a single console, if possible */
+ /* deallocate a single console, if possible */
arg--;
if (VT_BUSY(arg))
return -EBUSY;
if (arg) { /* leave 0 */
acquire_console_sem();
- vc_disallocate(arg);
+ vc_deallocate(arg);
release_console_sem();
}
}
@@ -847,11 +850,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (get_user(ll, &vtsizes->v_rows) ||
get_user(cc, &vtsizes->v_cols))
return -EFAULT;
- for (i = 0; i < MAX_NR_CONSOLES; i++) {
- acquire_console_sem();
- vc_resize(vc_cons[i].d, cc, ll);
- release_console_sem();
- }
+ for (i = 0; i < MAX_NR_CONSOLES; i++)
+ vc_lock_resize(vc_cons[i].d, cc, ll);
return 0;
}
@@ -1063,7 +1063,7 @@ void reset_vc(struct vc_data *vc)
vc->vt_mode.relsig = 0;
vc->vt_mode.acqsig = 0;
vc->vt_mode.frsig = 0;
- vc->vt_pid = -1;
+ put_pid(xchg(&vc->vt_pid, NULL));
vc->vt_newvt = -1;
if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
reset_palette(vc);
@@ -1114,7 +1114,7 @@ static void complete_change_console(struct vc_data *vc)
* tell us if the process has gone or something else
* is awry
*/
- if (kill_proc(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
+ if (kill_pid(vc->vt_pid, vc->vt_mode.acqsig, 1) != 0) {
/*
* The controlling process has died, so we revert back to
* normal operation. In this case, we'll also change back
@@ -1174,7 +1174,7 @@ void change_console(struct vc_data *new_vc)
* tell us if the process has gone or something else
* is awry
*/
- if (kill_proc(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
+ if (kill_pid(vc->vt_pid, vc->vt_mode.relsig, 1) == 0) {
/*
* It worked. Mark the vt to switch to and
* return. The process needs to send us a
diff --git a/drivers/char/watchdog/Kconfig b/drivers/char/watchdog/Kconfig
index fff89c2d88fd..89e46d6dfc4e 100644
--- a/drivers/char/watchdog/Kconfig
+++ b/drivers/char/watchdog/Kconfig
@@ -165,6 +165,24 @@ config EP93XX_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called ep93xx_wdt.
+config OMAP_WATCHDOG
+ tristate "OMAP Watchdog"
+ depends on WATCHDOG && (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
+ help
+ Say Y here if to include support for the watchdog timer
+ in the PNX4008 processor.
+ This driver can be built as a module by choosing M. The module
+ will be called pnx4008_wdt.
+
+ Say N if you are unsure.
+
# X86 (i386 + ia64 + x86_64) Architecture
config ACQUIRE_WDT
@@ -298,6 +316,27 @@ config I8XX_TCO
To compile this driver as a module, choose M here: the
module will be called i8xx_tco.
+config ITCO_WDT
+ tristate "Intel TCO Timer/Watchdog (EXPERIMENTAL)"
+ depends on WATCHDOG && (X86 || IA64) && PCI && EXPERIMENTAL
+ ---help---
+ Hardware driver for the intel TCO timer based watchdog devices.
+ These drivers are included in the Intel 82801 I/O Controller
+ Hub family 'from ICH0 up to ICH7) and in the Intel 6300ESB
+ controller hub.
+
+ 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 iTCO_wdt.
+
config SC1200_WDT
tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
depends on WATCHDOG && X86
@@ -510,6 +549,14 @@ config SH_WDT
To compile this driver as a module, choose M here: the
module will be called shwdt.
+config SH_WDT_MMAP
+ bool "Allow mmap of SH WDT"
+ default n
+ depends on SH_WDT
+ help
+ If you say Y here, user applications will be able to mmap the
+ WDT/CPG registers.
+#
# SPARC64 Architecture
config WATCHDOG_CP1XXX
diff --git a/drivers/char/watchdog/Makefile b/drivers/char/watchdog/Makefile
index 6ab77b61a643..7f70abad465a 100644
--- a/drivers/char/watchdog/Makefile
+++ b/drivers/char/watchdog/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o
# ARM Architecture
obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o
+obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
obj-$(CONFIG_21285_WATCHDOG) += wdt285.o
obj-$(CONFIG_977_WATCHDOG) += wdt977.o
obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
@@ -32,6 +33,7 @@ obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o
obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o
obj-$(CONFIG_MPCORE_WATCHDOG) += mpcore_wdt.o
obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o
+obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o
# X86 (i386 + ia64 + x86_64) Architecture
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
@@ -45,6 +47,7 @@ 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
obj-$(CONFIG_SC1200_WDT) += sc1200wdt.o
obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o
obj-$(CONFIG_60XX_WDT) += sbc60xxwdt.o
diff --git a/drivers/char/watchdog/acquirewdt.c b/drivers/char/watchdog/acquirewdt.c
index c77fe3cf2852..154d67e591e5 100644
--- a/drivers/char/watchdog/acquirewdt.c
+++ b/drivers/char/watchdog/acquirewdt.c
@@ -183,7 +183,7 @@ static int acq_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/advantechwdt.c b/drivers/char/watchdog/advantechwdt.c
index 8069be445edc..9d732769ba01 100644
--- a/drivers/char/watchdog/advantechwdt.c
+++ b/drivers/char/watchdog/advantechwdt.c
@@ -176,7 +176,7 @@ advwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/alim1535_wdt.c b/drivers/char/watchdog/alim1535_wdt.c
index c5c94e4c9495..01b0d132ee41 100644
--- a/drivers/char/watchdog/alim1535_wdt.c
+++ b/drivers/char/watchdog/alim1535_wdt.c
@@ -236,7 +236,7 @@ static int ali_ioctl(struct inode *inode, struct file *file,
return put_user(timeout, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
@@ -330,17 +330,20 @@ static int __init ali_find_watchdog(void)
u32 wdog;
/* Check for a 1535 series bridge */
- pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
+ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x1535, NULL);
if(pdev == NULL)
return -ENODEV;
+ pci_dev_put(pdev);
/* Check for the a 7101 PMU */
- pdev = pci_find_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
+ pdev = pci_get_device(PCI_VENDOR_ID_AL, 0x7101, NULL);
if(pdev == NULL)
return -ENODEV;
- if(pci_enable_device(pdev))
+ if(pci_enable_device(pdev)) {
+ pci_dev_put(pdev);
return -EIO;
+ }
ali_pci = pdev;
@@ -447,6 +450,7 @@ static void __exit watchdog_exit(void)
/* Deregister */
unregister_reboot_notifier(&ali_notifier);
misc_deregister(&ali_miscdev);
+ pci_dev_put(ali_pci);
}
module_init(watchdog_init);
diff --git a/drivers/char/watchdog/alim7101_wdt.c b/drivers/char/watchdog/alim7101_wdt.c
index ffd7684f999b..bf25d0a55a99 100644
--- a/drivers/char/watchdog/alim7101_wdt.c
+++ b/drivers/char/watchdog/alim7101_wdt.c
@@ -77,7 +77,8 @@ static struct pci_dev *alim7101_pmu;
static int nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __stringify(CONFIG_WATCHDOG_NOWAYOUT) ")");
/*
* Whack the dog
@@ -277,7 +278,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
case WDIOC_GETTIMEOUT:
return put_user(timeout, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
@@ -333,6 +334,7 @@ static void __exit alim7101_wdt_unload(void)
/* Deregister */
misc_deregister(&wdt_miscdev);
unregister_reboot_notifier(&wdt_notifier);
+ pci_dev_put(alim7101_pmu);
}
static int __init alim7101_wdt_init(void)
@@ -342,7 +344,8 @@ static int __init alim7101_wdt_init(void)
char tmp;
printk(KERN_INFO PFX "Steve Hill <steve@navaho.co.uk>.\n");
- alim7101_pmu = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,NULL);
+ alim7101_pmu = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+ NULL);
if (!alim7101_pmu) {
printk(KERN_INFO PFX "ALi M7101 PMU not present - WDT not set\n");
return -EBUSY;
@@ -351,21 +354,23 @@ static int __init alim7101_wdt_init(void)
/* Set the WDT in the PMU to 1 second */
pci_write_config_byte(alim7101_pmu, ALI_7101_WDT, 0x02);
- ali1543_south = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
+ ali1543_south = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ NULL);
if (!ali1543_south) {
printk(KERN_INFO PFX "ALi 1543 South-Bridge not present - WDT not set\n");
- return -EBUSY;
+ goto err_out;
}
pci_read_config_byte(ali1543_south, 0x5e, &tmp);
+ pci_dev_put(ali1543_south);
if ((tmp & 0x1e) == 0x00) {
if (!use_gpio) {
printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
- return -EBUSY;
+ goto err_out;
}
nowayout = 1;
} else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
- return -EBUSY;
+ goto err_out;
}
if(timeout < 1 || timeout > 3600) /* arbitrary upper limit */
@@ -404,12 +409,23 @@ static int __init alim7101_wdt_init(void)
err_out_miscdev:
misc_deregister(&wdt_miscdev);
err_out:
+ pci_dev_put(alim7101_pmu);
return rc;
}
module_init(alim7101_wdt_init);
module_exit(alim7101_wdt_unload);
+static struct pci_device_id alim7101_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, alim7101_pci_tbl);
+
MODULE_AUTHOR("Steve Hill");
MODULE_DESCRIPTION("ALi M7101 PMU Computer Watchdog Timer driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/watchdog/at91_wdt.c b/drivers/char/watchdog/at91_wdt.c
index cc266715ea32..4e7a1145e78f 100644
--- a/drivers/char/watchdog/at91_wdt.c
+++ b/drivers/char/watchdog/at91_wdt.c
@@ -168,7 +168,7 @@ static int at91_wdt_ioctl(struct inode *inode, struct file *file,
return 0;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/booke_wdt.c b/drivers/char/watchdog/booke_wdt.c
index e3cefc538b40..488902231cc2 100644
--- a/drivers/char/watchdog/booke_wdt.c
+++ b/drivers/char/watchdog/booke_wdt.c
@@ -125,7 +125,7 @@ static int booke_wdt_ioctl (struct inode *inode, struct file *file,
return -EINVAL;
return 0;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c
index 04c7e49918db..00bdabb90f27 100644
--- a/drivers/char/watchdog/cpu5wdt.c
+++ b/drivers/char/watchdog/cpu5wdt.c
@@ -183,7 +183,7 @@ static int cpu5wdt_ioctl(struct inode *inode, struct file *file, unsigned int cm
}
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/ep93xx_wdt.c b/drivers/char/watchdog/ep93xx_wdt.c
index 77c8a955ae9e..01cf123b1616 100644
--- a/drivers/char/watchdog/ep93xx_wdt.c
+++ b/drivers/char/watchdog/ep93xx_wdt.c
@@ -144,7 +144,7 @@ static int
ep93xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
switch (cmd) {
case WDIOC_GETSUPPORT:
diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c
index 62dbccb2f6df..e228d6e173ce 100644
--- a/drivers/char/watchdog/eurotechwdt.c
+++ b/drivers/char/watchdog/eurotechwdt.c
@@ -153,7 +153,7 @@ static void eurwdt_activate_timer(void)
* Kernel methods.
*/
-static irqreturn_t eurwdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t eurwdt_interrupt(int irq, void *dev_id)
{
printk(KERN_CRIT "timeout WDT timeout\n");
@@ -240,7 +240,7 @@ static int eurwdt_ioctl(struct inode *inode, struct file *file,
switch(cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
diff --git a/drivers/char/watchdog/i6300esb.c b/drivers/char/watchdog/i6300esb.c
index 870539eabbf3..fb64df4d7c87 100644
--- a/drivers/char/watchdog/i6300esb.c
+++ b/drivers/char/watchdog/i6300esb.c
@@ -315,7 +315,7 @@ static int esb_ioctl (struct inode *inode, struct file *file,
return put_user(heartbeat, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
index 8385dd36eefe..e0627d79707b 100644
--- a/drivers/char/watchdog/i8xx_tco.c
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -356,7 +356,7 @@ static int i8xx_tco_ioctl (struct inode *inode, struct file *file,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
@@ -406,18 +406,18 @@ static struct notifier_block i8xx_tco_notifier = {
* want to register another driver on the same PCI id.
*/
static struct pci_device_id i8xx_tco_pci_tbl[] = {
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, },
- { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, },
- { 0, }, /* End of list */
+ { 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);
@@ -434,12 +434,11 @@ static unsigned char __init i8xx_tco_getdevice (void)
* Find the PCI device
*/
- while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ for_each_pci_dev(dev)
if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
i8xx_tco_pci = dev;
break;
}
- }
if (i8xx_tco_pci) {
/*
@@ -454,6 +453,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
/* 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;
}
@@ -465,6 +465,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
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 */
}
}
@@ -476,6 +477,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
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);
@@ -542,6 +544,7 @@ unreg_notifier:
unreg_region:
release_region (TCOBASE, 0x10);
out:
+ pci_dev_put(i8xx_tco_pci);
return ret;
}
@@ -555,6 +558,8 @@ static void __exit watchdog_cleanup (void)
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);
diff --git a/drivers/char/watchdog/iTCO_wdt.c b/drivers/char/watchdog/iTCO_wdt.c
new file mode 100644
index 000000000000..aaac94db0d8b
--- /dev/null
+++ b/drivers/char/watchdog/iTCO_wdt.c
@@ -0,0 +1,734 @@
+/*
+ * intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
+ *
+ * (c) Copyright 2006 Wim Van Sebroeck <wim@iguana.be>.
+ *
+ * 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 Wim Van Sebroeck nor Iguana vzw. admit liability nor
+ * provide warranty for any of this software. This material is
+ * provided "AS-IS" and at no charge.
+ *
+ * The TCO watchdog 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,
+ * 82801FB (ICH6) : document number 301473-002, 301474-007,
+ * 82801FR (ICH6R) : document number 301473-002, 301474-007,
+ * 82801FBM (ICH6-M) : document number 301473-002, 301474-007,
+ * 82801FW (ICH6W) : document number 301473-001, 301474-007,
+ * 82801FRW (ICH6RW) : document number 301473-001, 301474-007,
+ * 82801GB (ICH7) : document number 307013-002, 307014-009,
+ * 82801GR (ICH7R) : document number 307013-002, 307014-009,
+ * 82801GDH (ICH7DH) : document number 307013-002, 307014-009,
+ * 82801GBM (ICH7-M) : document number 307013-002, 307014-009,
+ * 82801GHM (ICH7-M DH) : document number 307013-002, 307014-009,
+ * 6300ESB (6300ESB) : document number 300641-003
+ */
+
+/*
+ * Includes, defines, variables, module parameters, ...
+ */
+
+/* Module and version information */
+#define DRV_NAME "iTCO_wdt"
+#define DRV_VERSION "1.00"
+#define DRV_RELDATE "30-Jul-2006"
+#define PFX DRV_NAME ": "
+
+/* Includes */
+#include <linux/module.h> /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h> /* For standard types (like size_t) */
+#include <linux/errno.h> /* For the -ENODEV/... values */
+#include <linux/kernel.h> /* For printk/panic/... */
+#include <linux/miscdevice.h> /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h> /* For the watchdog specific items */
+#include <linux/init.h> /* For __init/__exit/... */
+#include <linux/fs.h> /* For file operations */
+#include <linux/platform_device.h> /* For platform_driver framework */
+#include <linux/pci.h> /* For pci functions */
+#include <linux/ioport.h> /* For io-port access */
+#include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */
+
+#include <asm/uaccess.h> /* For copy_to_user/put_user/... */
+#include <asm/io.h> /* For inb/outb/... */
+
+/* TCO related info */
+enum iTCO_chipsets {
+ TCO_ICH = 0, /* ICH */
+ TCO_ICH0, /* ICH0 */
+ TCO_ICH2, /* ICH2 */
+ TCO_ICH2M, /* ICH2-M */
+ TCO_ICH3, /* ICH3-S */
+ TCO_ICH3M, /* ICH3-M */
+ TCO_ICH4, /* ICH4 */
+ TCO_ICH4M, /* ICH4-M */
+ TCO_CICH, /* C-ICH */
+ TCO_ICH5, /* ICH5 & ICH5R */
+ TCO_6300ESB, /* 6300ESB */
+ TCO_ICH6, /* ICH6 & ICH6R */
+ TCO_ICH6M, /* ICH6-M */
+ TCO_ICH6W, /* ICH6W & ICH6RW */
+ TCO_ICH7, /* ICH7 & ICH7R */
+ TCO_ICH7M, /* ICH7-M */
+ TCO_ICH7MDH, /* ICH7-M DH */
+};
+
+static struct {
+ char *name;
+ unsigned int iTCO_version;
+} iTCO_chipset_info[] __devinitdata = {
+ {"ICH", 1},
+ {"ICH0", 1},
+ {"ICH2", 1},
+ {"ICH2-M", 1},
+ {"ICH3-S", 1},
+ {"ICH3-M", 1},
+ {"ICH4", 1},
+ {"ICH4-M", 1},
+ {"C-ICH", 1},
+ {"ICH5 or ICH5R", 1},
+ {"6300ESB", 1},
+ {"ICH6 or ICH6R", 2},
+ {"ICH6-M", 2},
+ {"ICH6W or ICH6RW", 2},
+ {"ICH7 or ICH7R", 2},
+ {"ICH7-M", 2},
+ {"ICH7-M DH", 2},
+ {NULL,0}
+};
+
+/*
+ * This data only exists for exporting the supported PCI ids
+ * via MODULE_DEVICE_TABLE. We do not actually register a
+ * pci_driver, because the I/O Controller Hub has also other
+ * functions that probably will be registered by other drivers.
+ */
+static struct pci_device_id iTCO_wdt_pci_tbl[] = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH0 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_10, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH2M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH3M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH4M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801E_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_CICH },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH5 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_6300ESB },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH6W },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7 },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7M },
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TCO_ICH7MDH },
+ { 0, }, /* End of list */
+};
+MODULE_DEVICE_TABLE (pci, iTCO_wdt_pci_tbl);
+
+/* Address definitions for the TCO */
+#define TCOBASE iTCO_wdt_private.ACPIBASE + 0x60 /* TCO base address */
+#define SMI_EN iTCO_wdt_private.ACPIBASE + 0x30 /* SMI Control and Enable Register */
+
+#define TCO_RLD TCOBASE + 0x00 /* TCO Timer Reload and Current Value */
+#define TCOv1_TMR TCOBASE + 0x01 /* TCOv1 Timer Initial Value */
+#define TCO_DAT_IN TCOBASE + 0x02 /* TCO Data In Register */
+#define TCO_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 TCOv2_TMR TCOBASE + 0x12 /* TCOv2 Timer Initial Value */
+
+/* internal variables */
+static unsigned long is_active;
+static char expect_release;
+static struct { /* this is private data for the iTCO_wdt device */
+ unsigned int iTCO_version; /* TCO version/generation */
+ unsigned long ACPIBASE; /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */
+ unsigned long __iomem *gcs; /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2) */
+ spinlock_t io_lock; /* the lock for io operations */
+ struct pci_dev *pdev; /* the PCI-device */
+} iTCO_wdt_private;
+
+static struct platform_device *iTCO_wdt_platform_device; /* the watchdog platform device */
+
+/* module parameters */
+#define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */
+static int heartbeat = WATCHDOG_HEARTBEAT; /* in seconds */
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (2<heartbeat<39 (TCO v1) or 613 (TCO v2), 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=CONFIG_WATCHDOG_NOWAYOUT)");
+
+/*
+ * Some TCO specific functions
+ */
+
+static inline unsigned int seconds_to_ticks(int seconds)
+{
+ /* the internal timer is stored as ticks which decrement
+ * every 0.6 seconds */
+ return (seconds * 10) / 6;
+}
+
+static void iTCO_wdt_set_NO_REBOOT_bit(void)
+{
+ u32 val32;
+
+ /* Set the NO_REBOOT bit: this disables reboots */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ val32 = readl(iTCO_wdt_private.gcs);
+ val32 |= 0x00000020;
+ writel(val32, iTCO_wdt_private.gcs);
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+ val32 |= 0x00000002;
+ pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+ }
+}
+
+static int iTCO_wdt_unset_NO_REBOOT_bit(void)
+{
+ int ret = 0;
+ u32 val32;
+
+ /* Unset the NO_REBOOT bit: this enables reboots */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ val32 = readl(iTCO_wdt_private.gcs);
+ val32 &= 0xffffffdf;
+ writel(val32, iTCO_wdt_private.gcs);
+
+ val32 = readl(iTCO_wdt_private.gcs);
+ if (val32 & 0x00000020)
+ ret = -EIO;
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+ val32 &= 0xfffffffd;
+ pci_write_config_dword(iTCO_wdt_private.pdev, 0xd4, val32);
+
+ pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
+ if (val32 & 0x00000002)
+ ret = -EIO;
+ }
+
+ return ret; /* returns: 0 = OK, -EIO = Error */
+}
+
+static int iTCO_wdt_start(void)
+{
+ unsigned int val;
+
+ spin_lock(&iTCO_wdt_private.io_lock);
+
+ /* disable chipset's NO_REBOOT bit */
+ if (iTCO_wdt_unset_NO_REBOOT_bit()) {
+ printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+ return -EIO;
+ }
+
+ /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */
+ val = inw(TCO1_CNT);
+ val &= 0xf7ff;
+ outw(val, TCO1_CNT);
+ val = inw(TCO1_CNT);
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if (val & 0x0800)
+ return -1;
+ return 0;
+}
+
+static int iTCO_wdt_stop(void)
+{
+ unsigned int val;
+
+ spin_lock(&iTCO_wdt_private.io_lock);
+
+ /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */
+ val = inw(TCO1_CNT);
+ val |= 0x0800;
+ outw(val, TCO1_CNT);
+ val = inw(TCO1_CNT);
+
+ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+ iTCO_wdt_set_NO_REBOOT_bit();
+
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if ((val & 0x0800) == 0)
+ return -1;
+ return 0;
+}
+
+static int iTCO_wdt_keepalive(void)
+{
+ spin_lock(&iTCO_wdt_private.io_lock);
+
+ /* Reload the timer by writing to the TCO Timer Counter register */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ outw(0x01, TCO_RLD);
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ outb(0x01, TCO_RLD);
+ }
+
+ spin_unlock(&iTCO_wdt_private.io_lock);
+ return 0;
+}
+
+static int iTCO_wdt_set_heartbeat(int t)
+{
+ unsigned int val16;
+ unsigned char val8;
+ unsigned int tmrval;
+
+ tmrval = seconds_to_ticks(t);
+ /* from the specs: */
+ /* "Values of 0h-3h are ignored and should not be attempted" */
+ if (tmrval < 0x04)
+ return -EINVAL;
+ if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
+ ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
+ return -EINVAL;
+
+ /* Write new heartbeat to watchdog */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val16 = inw(TCOv2_TMR);
+ val16 &= 0xfc00;
+ val16 |= tmrval;
+ outw(val16, TCOv2_TMR);
+ val16 = inw(TCOv2_TMR);
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if ((val16 & 0x3ff) != tmrval)
+ return -EINVAL;
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val8 = inb(TCOv1_TMR);
+ val8 &= 0xc0;
+ val8 |= (tmrval & 0xff);
+ outb(val8, TCOv1_TMR);
+ val8 = inb(TCOv1_TMR);
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ if ((val8 & 0x3f) != tmrval)
+ return -EINVAL;
+ }
+
+ heartbeat = t;
+ return 0;
+}
+
+static int iTCO_wdt_get_timeleft (int *time_left)
+{
+ unsigned int val16;
+ unsigned char val8;
+
+ /* read the TCO Timer */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val16 = inw(TCO_RLD);
+ val16 &= 0x3ff;
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ *time_left = (val16 * 6) / 10;
+ } else if (iTCO_wdt_private.iTCO_version == 1) {
+ spin_lock(&iTCO_wdt_private.io_lock);
+ val8 = inb(TCO_RLD);
+ val8 &= 0x3f;
+ spin_unlock(&iTCO_wdt_private.io_lock);
+
+ *time_left = (val8 * 6) / 10;
+ }
+ return 0;
+}
+
+/*
+ * /dev/watchdog handling
+ */
+
+static int iTCO_wdt_open (struct inode *inode, struct file *file)
+{
+ /* /dev/watchdog can only be opened once */
+ if (test_and_set_bit(0, &is_active))
+ return -EBUSY;
+
+ /*
+ * Reload and activate timer
+ */
+ iTCO_wdt_keepalive();
+ iTCO_wdt_start();
+ return nonseekable_open(inode, file);
+}
+
+static int iTCO_wdt_release (struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer.
+ */
+ if (expect_release == 42) {
+ iTCO_wdt_stop();
+ } else {
+ printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ iTCO_wdt_keepalive();
+ }
+ clear_bit(0, &is_active);
+ expect_release = 0;
+ return 0;
+}
+
+static ssize_t iTCO_wdt_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... */
+ expect_release = 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')
+ expect_release = 42;
+ }
+ }
+
+ /* someone wrote to us, we should reload the timer */
+ iTCO_wdt_keepalive();
+ }
+ return len;
+}
+
+static int iTCO_wdt_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 = DRV_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:
+ iTCO_wdt_keepalive();
+ return 0;
+
+ case WDIOC_SETOPTIONS:
+ {
+ if (get_user(new_options, p))
+ return -EFAULT;
+
+ if (new_options & WDIOS_DISABLECARD) {
+ iTCO_wdt_stop();
+ retval = 0;
+ }
+
+ if (new_options & WDIOS_ENABLECARD) {
+ iTCO_wdt_keepalive();
+ iTCO_wdt_start();
+ retval = 0;
+ }
+
+ return retval;
+ }
+
+ case WDIOC_SETTIMEOUT:
+ {
+ if (get_user(new_heartbeat, p))
+ return -EFAULT;
+
+ if (iTCO_wdt_set_heartbeat(new_heartbeat))
+ return -EINVAL;
+
+ iTCO_wdt_keepalive();
+ /* Fall */
+ }
+
+ case WDIOC_GETTIMEOUT:
+ return put_user(heartbeat, p);
+
+ case WDIOC_GETTIMELEFT:
+ {
+ if (iTCO_wdt_get_timeleft(&time_left))
+ return -EINVAL;
+
+ return put_user(time_left, p);
+ }
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+/*
+ * Kernel Interfaces
+ */
+
+static struct file_operations iTCO_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = iTCO_wdt_write,
+ .ioctl = iTCO_wdt_ioctl,
+ .open = iTCO_wdt_open,
+ .release = iTCO_wdt_release,
+};
+
+static struct miscdevice iTCO_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &iTCO_wdt_fops,
+};
+
+/*
+ * Init & exit routines
+ */
+
+static int iTCO_wdt_init(struct pci_dev *pdev, const struct pci_device_id *ent, struct platform_device *dev)
+{
+ int ret;
+ u32 base_address;
+ unsigned long RCBA;
+ unsigned long val32;
+
+ /*
+ * Find the ACPI/PM 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_dword(pdev, 0x40, &base_address);
+ base_address &= 0x00007f80;
+ if (base_address == 0x00000000) {
+ /* Something's wrong here, ACPIBASE has to be set */
+ printk(KERN_ERR PFX "failed to get TCOBASE address\n");
+ pci_dev_put(pdev);
+ return -ENODEV;
+ }
+ iTCO_wdt_private.iTCO_version = iTCO_chipset_info[ent->driver_data].iTCO_version;
+ iTCO_wdt_private.ACPIBASE = base_address;
+ iTCO_wdt_private.pdev = pdev;
+
+ /* Get the Memory-Mapped GCS register, we need it for the NO_REBOOT flag (TCO v2) */
+ /* To get access to it you have to read RCBA from PCI Config space 0xf0
+ and use it as base. GCS = RCBA + ICH6_GCS(0x3410). */
+ if (iTCO_wdt_private.iTCO_version == 2) {
+ pci_read_config_dword(pdev, 0xf0, &base_address);
+ RCBA = base_address & 0xffffc000;
+ iTCO_wdt_private.gcs = ioremap((RCBA + 0x3410),4);
+ }
+
+ /* Check chipset's NO_REBOOT bit */
+ if (iTCO_wdt_unset_NO_REBOOT_bit()) {
+ printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, reboot disabled by hardware\n");
+ ret = -ENODEV; /* Cannot reset NO_REBOOT bit */
+ goto out;
+ }
+
+ /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
+ iTCO_wdt_set_NO_REBOOT_bit();
+
+ /* Set the TCO_EN bit in SMI_EN register */
+ if (!request_region(SMI_EN, 4, "iTCO_wdt")) {
+ printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n",
+ SMI_EN );
+ ret = -EIO;
+ goto out;
+ }
+ val32 = inl(SMI_EN);
+ val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */
+ outl(val32, SMI_EN);
+ release_region(SMI_EN, 4);
+
+ /* The TCO I/O registers reside in a 32-byte range pointed to by the TCOBASE value */
+ if (!request_region (TCOBASE, 0x20, "iTCO_wdt")) {
+ printk (KERN_ERR PFX "I/O address 0x%04lx already in use\n",
+ TCOBASE);
+ ret = -EIO;
+ goto out;
+ }
+
+ printk(KERN_INFO PFX "Found a %s TCO device (Version=%d, TCOBASE=0x%04lx)\n",
+ iTCO_chipset_info[ent->driver_data].name,
+ iTCO_chipset_info[ent->driver_data].iTCO_version,
+ TCOBASE);
+
+ /* Clear out the (probably old) status */
+ outb(0, TCO1_STS);
+ outb(3, TCO2_STS);
+
+ /* Make sure the watchdog is not running */
+ iTCO_wdt_stop();
+
+ /* Check that the heartbeat value is within it's range ; if not reset to the default */
+ if (iTCO_wdt_set_heartbeat(heartbeat)) {
+ iTCO_wdt_set_heartbeat(WATCHDOG_HEARTBEAT);
+ printk(KERN_INFO PFX "heartbeat value must be 2<heartbeat<39 (TCO v1) or 613 (TCO v2), using %d\n",
+ heartbeat);
+ }
+
+ ret = misc_register(&iTCO_wdt_miscdev);
+ if (ret != 0) {
+ printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n",
+ WATCHDOG_MINOR, ret);
+ goto unreg_region;
+ }
+
+ printk (KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n",
+ heartbeat, nowayout);
+
+ return 0;
+
+unreg_region:
+ release_region (TCOBASE, 0x20);
+out:
+ if (iTCO_wdt_private.iTCO_version == 2)
+ iounmap(iTCO_wdt_private.gcs);
+ pci_dev_put(iTCO_wdt_private.pdev);
+ iTCO_wdt_private.ACPIBASE = 0;
+ return ret;
+}
+
+static void iTCO_wdt_cleanup(void)
+{
+ /* Stop the timer before we leave */
+ if (!nowayout)
+ iTCO_wdt_stop();
+
+ /* Deregister */
+ misc_deregister(&iTCO_wdt_miscdev);
+ release_region(TCOBASE, 0x20);
+ if (iTCO_wdt_private.iTCO_version == 2)
+ iounmap(iTCO_wdt_private.gcs);
+ pci_dev_put(iTCO_wdt_private.pdev);
+ iTCO_wdt_private.ACPIBASE = 0;
+}
+
+static int iTCO_wdt_probe(struct platform_device *dev)
+{
+ int found = 0;
+ struct pci_dev *pdev = NULL;
+ const struct pci_device_id *ent;
+
+ spin_lock_init(&iTCO_wdt_private.io_lock);
+
+ for_each_pci_dev(pdev) {
+ ent = pci_match_id(iTCO_wdt_pci_tbl, pdev);
+ if (ent) {
+ if (!(iTCO_wdt_init(pdev, ent, dev))) {
+ found++;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ printk(KERN_INFO PFX "No card detected\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int iTCO_wdt_remove(struct platform_device *dev)
+{
+ if (iTCO_wdt_private.ACPIBASE)
+ iTCO_wdt_cleanup();
+
+ return 0;
+}
+
+static void iTCO_wdt_shutdown(struct platform_device *dev)
+{
+ iTCO_wdt_stop();
+}
+
+#define iTCO_wdt_suspend NULL
+#define iTCO_wdt_resume NULL
+
+static struct platform_driver iTCO_wdt_driver = {
+ .probe = iTCO_wdt_probe,
+ .remove = iTCO_wdt_remove,
+ .shutdown = iTCO_wdt_shutdown,
+ .suspend = iTCO_wdt_suspend,
+ .resume = iTCO_wdt_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRV_NAME,
+ },
+};
+
+static int __init iTCO_wdt_init_module(void)
+{
+ int err;
+
+ printk(KERN_INFO PFX "Intel TCO WatchDog Timer Driver v%s (%s)\n",
+ DRV_VERSION, DRV_RELDATE);
+
+ err = platform_driver_register(&iTCO_wdt_driver);
+ if (err)
+ return err;
+
+ iTCO_wdt_platform_device = platform_device_register_simple(DRV_NAME, -1, NULL, 0);
+ if (IS_ERR(iTCO_wdt_platform_device)) {
+ err = PTR_ERR(iTCO_wdt_platform_device);
+ goto unreg_platform_driver;
+ }
+
+ return 0;
+
+unreg_platform_driver:
+ platform_driver_unregister(&iTCO_wdt_driver);
+ return err;
+}
+
+static void __exit iTCO_wdt_cleanup_module(void)
+{
+ platform_device_unregister(iTCO_wdt_platform_device);
+ platform_driver_unregister(&iTCO_wdt_driver);
+ printk(KERN_INFO PFX "Watchdog Module Unloaded.\n");
+}
+
+module_init(iTCO_wdt_init_module);
+module_exit(iTCO_wdt_cleanup_module);
+
+MODULE_AUTHOR("Wim Van Sebroeck <wim@iguana.be>");
+MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/ib700wdt.c b/drivers/char/watchdog/ib700wdt.c
index fd95f7327798..c1ed209a138c 100644
--- a/drivers/char/watchdog/ib700wdt.c
+++ b/drivers/char/watchdog/ib700wdt.c
@@ -199,7 +199,7 @@ ibwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c
index 26ceee7a4df0..dd6760f1a23b 100644
--- a/drivers/char/watchdog/ibmasr.c
+++ b/drivers/char/watchdog/ibmasr.c
@@ -295,7 +295,7 @@ static int asr_ioctl(struct inode *inode, struct file *file,
}
}
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
static int asr_open(struct inode *inode, struct file *file)
diff --git a/drivers/char/watchdog/indydog.c b/drivers/char/watchdog/indydog.c
index dacc1c20a310..0bc239308989 100644
--- a/drivers/char/watchdog/indydog.c
+++ b/drivers/char/watchdog/indydog.c
@@ -112,7 +112,7 @@ static int indydog_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user((struct watchdog_info *)arg,
&ident, sizeof(ident)))
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
index 692908819e26..fd955dbd588c 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -1,5 +1,5 @@
/*
- * drivers/watchdog/ixp2000_wdt.c
+ * drivers/char/watchdog/ixp2000_wdt.c
*
* Watchdog driver for Intel IXP2000 network processors
*
@@ -107,7 +107,7 @@ static int
ixp2000_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
int time;
switch (cmd) {
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
index 9db5cf2c38c3..5864bb865cfe 100644
--- a/drivers/char/watchdog/ixp4xx_wdt.c
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -1,5 +1,5 @@
/*
- * drivers/watchdog/ixp4xx_wdt.c
+ * drivers/char/watchdog/ixp4xx_wdt.c
*
* Watchdog driver for Intel IXP4xx network processors
*
@@ -102,7 +102,7 @@ static int
ixp4xx_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
int time;
switch (cmd) {
diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c
index 23734e07fb22..276577d08fba 100644
--- a/drivers/char/watchdog/machzwd.c
+++ b/drivers/char/watchdog/machzwd.c
@@ -329,7 +329,7 @@ static int zf_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
@@ -426,8 +426,7 @@ static int __init zf_init(void)
printk(KERN_INFO PFX ": MachZ ZF-Logic Watchdog driver initializing.\n");
ret = zf_get_ZFL_version();
- printk("%#x\n", ret);
- if((!ret) || (ret != 0xffff)){
+ if ((!ret) || (ret == 0xffff)) {
printk(KERN_WARNING PFX ": no ZF-Logic found\n");
return -ENODEV;
}
diff --git a/drivers/char/watchdog/mixcomwd.c b/drivers/char/watchdog/mixcomwd.c
index ae943324d251..c2dac0aa1d62 100644
--- a/drivers/char/watchdog/mixcomwd.c
+++ b/drivers/char/watchdog/mixcomwd.c
@@ -185,7 +185,7 @@ static int mixcomwd_ioctl(struct inode *inode, struct file *file,
mixcomwd_ping();
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/mpc83xx_wdt.c b/drivers/char/watchdog/mpc83xx_wdt.c
index a480903ee1a5..18ca752e2f90 100644
--- a/drivers/char/watchdog/mpc83xx_wdt.c
+++ b/drivers/char/watchdog/mpc83xx_wdt.c
@@ -125,7 +125,7 @@ static int mpc83xx_wdt_ioctl(struct inode *inode, struct file *file,
case WDIOC_GETTIMEOUT:
return put_user(timeout_sec, p);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/mpc8xx_wdt.c b/drivers/char/watchdog/mpc8xx_wdt.c
index 35dd9e6e1140..8aaed10dd499 100644
--- a/drivers/char/watchdog/mpc8xx_wdt.c
+++ b/drivers/char/watchdog/mpc8xx_wdt.c
@@ -126,7 +126,7 @@ static int mpc8xx_wdt_ioctl(struct inode *inode, struct file *file,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
diff --git a/drivers/char/watchdog/mpcore_wdt.c b/drivers/char/watchdog/mpcore_wdt.c
index 54b3c56ead0d..3404a9c67f08 100644
--- a/drivers/char/watchdog/mpcore_wdt.c
+++ b/drivers/char/watchdog/mpcore_wdt.c
@@ -64,7 +64,7 @@ MODULE_PARM_DESC(mpcore_noboot, "MPcore watchdog action, set to 1 to ignore rebo
* This is the interrupt handler. Note that we only use this
* in testing mode, so don't actually do a reboot here.
*/
-static irqreturn_t mpcore_wdt_fire(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t mpcore_wdt_fire(int irq, void *arg)
{
struct mpcore_wdt *wdt = arg;
@@ -221,7 +221,7 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
} uarg;
if (_IOC_DIR(cmd) && _IOC_SIZE(cmd) > sizeof(uarg))
- return -ENOIOCTLCMD;
+ return -ENOTTY;
if (_IOC_DIR(cmd) & _IOC_WRITE) {
ret = copy_from_user(&uarg, (void __user *)arg, _IOC_SIZE(cmd));
@@ -271,7 +271,7 @@ static int mpcore_wdt_ioctl(struct inode *inode, struct file *file,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
if (ret == 0 && _IOC_DIR(cmd) & _IOC_READ) {
diff --git a/drivers/char/watchdog/mv64x60_wdt.c b/drivers/char/watchdog/mv64x60_wdt.c
index 5c8fab345b40..b887cdb01334 100644
--- a/drivers/char/watchdog/mv64x60_wdt.c
+++ b/drivers/char/watchdog/mv64x60_wdt.c
@@ -160,7 +160,7 @@ static int mv64x60_wdt_ioctl(struct inode *inode, struct file *file,
break;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
diff --git a/drivers/char/watchdog/omap_wdt.c b/drivers/char/watchdog/omap_wdt.c
new file mode 100644
index 000000000000..5dbd7dc2936f
--- /dev/null
+++ b/drivers/char/watchdog/omap_wdt.c
@@ -0,0 +1,390 @@
+/*
+ * linux/drivers/char/watchdog/omap_wdt.c
+ *
+ * Watchdog driver for the TI OMAP 16xx & 24xx 32KHz (non-secure) watchdog
+ *
+ * Author: MontaVista Software, Inc.
+ * <gdavis@mvista.com> or <source@mvista.com>
+ *
+ * 2003 (c) MontaVista Software, Inc. This file is licensed under the
+ * terms of the GNU General Public License version 2. This program is
+ * licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ *
+ * History:
+ *
+ * 20030527: George G. Davis <gdavis@mvista.com>
+ * Initially based on linux-2.4.19-rmk7-pxa1/drivers/char/sa1100_wdt.c
+ * (c) Copyright 2000 Oleg Drokin <green@crimea.edu>
+ * Based on SoftDog driver by Alan Cox <alan@redhat.com>
+ *
+ * Copyright (c) 2004 Texas Instruments.
+ * 1. Modified to support OMAP1610 32-KHz watchdog timer
+ * 2. Ported to 2.6 kernel
+ *
+ * Copyright (c) 2005 David Brownell
+ * Use the driver model and standard identifiers; handle bigger timeouts.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/reboot.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/moduleparam.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/hardware.h>
+#include <asm/bitops.h>
+
+#include <asm/arch/prcm.h>
+
+#include "omap_wdt.h"
+
+static unsigned timer_margin;
+module_param(timer_margin, uint, 0);
+MODULE_PARM_DESC(timer_margin, "initial watchdog timeout (in seconds)");
+
+static int omap_wdt_users;
+static struct clk *armwdt_ck = NULL;
+static struct clk *mpu_wdt_ick = NULL;
+static struct clk *mpu_wdt_fck = NULL;
+
+static unsigned int wdt_trgr_pattern = 0x1234;
+
+static void omap_wdt_ping(void)
+{
+ /* wait for posted write to complete */
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ cpu_relax();
+ wdt_trgr_pattern = ~wdt_trgr_pattern;
+ omap_writel(wdt_trgr_pattern, (OMAP_WATCHDOG_TGR));
+ /* wait for posted write to complete */
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x08)
+ cpu_relax();
+ /* reloaded WCRR from WLDR */
+}
+
+static void omap_wdt_enable(void)
+{
+ /* Sequence to enable the watchdog */
+ omap_writel(0xBBBB, OMAP_WATCHDOG_SPR);
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ cpu_relax();
+ omap_writel(0x4444, OMAP_WATCHDOG_SPR);
+ while ((omap_readl(OMAP_WATCHDOG_WPS)) & 0x10)
+ cpu_relax();
+}
+
+static void omap_wdt_disable(void)
+{
+ /* sequence required to disable watchdog */
+ omap_writel(0xAAAA, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ cpu_relax();
+ omap_writel(0x5555, OMAP_WATCHDOG_SPR); /* TIMER_MODE */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x10)
+ cpu_relax();
+}
+
+static void omap_wdt_adjust_timeout(unsigned new_timeout)
+{
+ if (new_timeout < TIMER_MARGIN_MIN)
+ new_timeout = TIMER_MARGIN_DEFAULT;
+ if (new_timeout > TIMER_MARGIN_MAX)
+ new_timeout = TIMER_MARGIN_MAX;
+ timer_margin = new_timeout;
+}
+
+static void omap_wdt_set_timeout(void)
+{
+ u32 pre_margin = GET_WLDR_VAL(timer_margin);
+
+ /* just count up at 32 KHz */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ cpu_relax();
+ omap_writel(pre_margin, OMAP_WATCHDOG_LDR);
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x04)
+ cpu_relax();
+}
+
+/*
+ * Allow only one task to hold it open
+ */
+
+static int omap_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(1, (unsigned long *)&omap_wdt_users))
+ return -EBUSY;
+
+ if (cpu_is_omap16xx())
+ clk_enable(armwdt_ck); /* Enable the clock */
+
+ if (cpu_is_omap24xx()) {
+ clk_enable(mpu_wdt_ick); /* Enable the interface clock */
+ clk_enable(mpu_wdt_fck); /* Enable the functional clock */
+ }
+
+ /* initialize prescaler */
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ cpu_relax();
+ omap_writel((1 << 5) | (PTV << 2), OMAP_WATCHDOG_CNTRL);
+ while (omap_readl(OMAP_WATCHDOG_WPS) & 0x01)
+ cpu_relax();
+
+ omap_wdt_set_timeout();
+ omap_wdt_enable();
+ return 0;
+}
+
+static int omap_wdt_release(struct inode *inode, struct file *file)
+{
+ /*
+ * Shut off the timer unless NOWAYOUT is defined.
+ */
+#ifndef CONFIG_WATCHDOG_NOWAYOUT
+ omap_wdt_disable();
+
+ if (cpu_is_omap16xx()) {
+ clk_disable(armwdt_ck); /* Disable the clock */
+ clk_put(armwdt_ck);
+ armwdt_ck = NULL;
+ }
+
+ if (cpu_is_omap24xx()) {
+ clk_disable(mpu_wdt_ick); /* Disable the clock */
+ clk_disable(mpu_wdt_fck); /* Disable the clock */
+ clk_put(mpu_wdt_ick);
+ clk_put(mpu_wdt_fck);
+ mpu_wdt_ick = NULL;
+ mpu_wdt_fck = NULL;
+ }
+#else
+ printk(KERN_CRIT "omap_wdt: Unexpected close, not stopping!\n");
+#endif
+ omap_wdt_users = 0;
+ return 0;
+}
+
+static ssize_t
+omap_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ /* Refresh LOAD_TIME. */
+ if (len)
+ omap_wdt_ping();
+ return len;
+}
+
+static int
+omap_wdt_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int new_margin;
+ static struct watchdog_info ident = {
+ .identity = "OMAP Watchdog",
+ .options = WDIOF_SETTIMEOUT,
+ .firmware_version = 0,
+ };
+
+ switch (cmd) {
+ default:
+ return -ENOIOCTLCMD;
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info __user *)arg, &ident,
+ sizeof(ident));
+ case WDIOC_GETSTATUS:
+ return put_user(0, (int __user *)arg);
+ case WDIOC_GETBOOTSTATUS:
+ if (cpu_is_omap16xx())
+ return put_user(omap_readw(ARM_SYSST),
+ (int __user *)arg);
+ if (cpu_is_omap24xx())
+ return put_user(omap_prcm_get_reset_sources(),
+ (int __user *)arg);
+ case WDIOC_KEEPALIVE:
+ omap_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int __user *)arg))
+ return -EFAULT;
+ omap_wdt_adjust_timeout(new_margin);
+
+ omap_wdt_disable();
+ omap_wdt_set_timeout();
+ omap_wdt_enable();
+
+ omap_wdt_ping();
+ /* Fall */
+ case WDIOC_GETTIMEOUT:
+ return put_user(timer_margin, (int __user *)arg);
+ }
+}
+
+static struct file_operations omap_wdt_fops = {
+ .owner = THIS_MODULE,
+ .write = omap_wdt_write,
+ .ioctl = omap_wdt_ioctl,
+ .open = omap_wdt_open,
+ .release = omap_wdt_release,
+};
+
+static struct miscdevice omap_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &omap_wdt_fops
+};
+
+static int __init omap_wdt_probe(struct platform_device *pdev)
+{
+ struct resource *res, *mem;
+ int ret;
+
+ /* reserve static register mappings */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENOENT;
+
+ mem = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+ if (mem == NULL)
+ return -EBUSY;
+
+ platform_set_drvdata(pdev, mem);
+
+ omap_wdt_users = 0;
+
+ if (cpu_is_omap16xx()) {
+ armwdt_ck = clk_get(&pdev->dev, "armwdt_ck");
+ if (IS_ERR(armwdt_ck)) {
+ ret = PTR_ERR(armwdt_ck);
+ armwdt_ck = NULL;
+ goto fail;
+ }
+ }
+
+ if (cpu_is_omap24xx()) {
+ mpu_wdt_ick = clk_get(&pdev->dev, "mpu_wdt_ick");
+ if (IS_ERR(mpu_wdt_ick)) {
+ ret = PTR_ERR(mpu_wdt_ick);
+ mpu_wdt_ick = NULL;
+ goto fail;
+ }
+ mpu_wdt_fck = clk_get(&pdev->dev, "mpu_wdt_fck");
+ if (IS_ERR(mpu_wdt_fck)) {
+ ret = PTR_ERR(mpu_wdt_fck);
+ mpu_wdt_fck = NULL;
+ goto fail;
+ }
+ }
+
+ omap_wdt_disable();
+ omap_wdt_adjust_timeout(timer_margin);
+
+ omap_wdt_miscdev.dev = &pdev->dev;
+ ret = misc_register(&omap_wdt_miscdev);
+ if (ret)
+ goto fail;
+
+ pr_info("OMAP Watchdog Timer: initial timeout %d sec\n", timer_margin);
+
+ /* autogate OCP interface clock */
+ omap_writel(0x01, OMAP_WATCHDOG_SYS_CONFIG);
+ return 0;
+
+fail:
+ if (armwdt_ck)
+ clk_put(armwdt_ck);
+ if (mpu_wdt_ick)
+ clk_put(mpu_wdt_ick);
+ if (mpu_wdt_fck)
+ clk_put(mpu_wdt_fck);
+ release_resource(mem);
+ return ret;
+}
+
+static void omap_wdt_shutdown(struct platform_device *pdev)
+{
+ omap_wdt_disable();
+}
+
+static int omap_wdt_remove(struct platform_device *pdev)
+{
+ struct resource *mem = platform_get_drvdata(pdev);
+ misc_deregister(&omap_wdt_miscdev);
+ release_resource(mem);
+ if (armwdt_ck)
+ clk_put(armwdt_ck);
+ if (mpu_wdt_ick)
+ clk_put(mpu_wdt_ick);
+ if (mpu_wdt_fck)
+ clk_put(mpu_wdt_fck);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* REVISIT ... not clear this is the best way to handle system suspend; and
+ * it's very inappropriate for selective device suspend (e.g. suspending this
+ * through sysfs rather than by stopping the watchdog daemon). Also, this
+ * may not play well enough with NOWAYOUT...
+ */
+
+static int omap_wdt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ if (omap_wdt_users)
+ omap_wdt_disable();
+ return 0;
+}
+
+static int omap_wdt_resume(struct platform_device *pdev)
+{
+ if (omap_wdt_users) {
+ omap_wdt_enable();
+ omap_wdt_ping();
+ }
+ return 0;
+}
+
+#else
+#define omap_wdt_suspend NULL
+#define omap_wdt_resume NULL
+#endif
+
+static struct platform_driver omap_wdt_driver = {
+ .probe = omap_wdt_probe,
+ .remove = omap_wdt_remove,
+ .shutdown = omap_wdt_shutdown,
+ .suspend = omap_wdt_suspend,
+ .resume = omap_wdt_resume,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "omap_wdt",
+ },
+};
+
+static int __init omap_wdt_init(void)
+{
+ return platform_driver_register(&omap_wdt_driver);
+}
+
+static void __exit omap_wdt_exit(void)
+{
+ platform_driver_unregister(&omap_wdt_driver);
+}
+
+module_init(omap_wdt_init);
+module_exit(omap_wdt_exit);
+
+MODULE_AUTHOR("George G. Davis");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/omap_wdt.h b/drivers/char/watchdog/omap_wdt.h
new file mode 100644
index 000000000000..52a532a5114a
--- /dev/null
+++ b/drivers/char/watchdog/omap_wdt.h
@@ -0,0 +1,64 @@
+/*
+ * linux/drivers/char/watchdog/omap_wdt.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ * OMAP Watchdog timer register definitions
+ *
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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.
+ */
+
+#ifndef _OMAP_WATCHDOG_H
+#define _OMAP_WATCHDOG_H
+
+#define OMAP1610_WATCHDOG_BASE 0xfffeb000
+#define OMAP2420_WATCHDOG_BASE 0x48022000 /*WDT Timer 2 */
+
+#ifdef CONFIG_ARCH_OMAP24XX
+#define OMAP_WATCHDOG_BASE OMAP2420_WATCHDOG_BASE
+#else
+#define OMAP_WATCHDOG_BASE OMAP1610_WATCHDOG_BASE
+#define RM_RSTST_WKUP 0
+#endif
+
+#define OMAP_WATCHDOG_REV (OMAP_WATCHDOG_BASE + 0x00)
+#define OMAP_WATCHDOG_SYS_CONFIG (OMAP_WATCHDOG_BASE + 0x10)
+#define OMAP_WATCHDOG_STATUS (OMAP_WATCHDOG_BASE + 0x14)
+#define OMAP_WATCHDOG_CNTRL (OMAP_WATCHDOG_BASE + 0x24)
+#define OMAP_WATCHDOG_CRR (OMAP_WATCHDOG_BASE + 0x28)
+#define OMAP_WATCHDOG_LDR (OMAP_WATCHDOG_BASE + 0x2c)
+#define OMAP_WATCHDOG_TGR (OMAP_WATCHDOG_BASE + 0x30)
+#define OMAP_WATCHDOG_WPS (OMAP_WATCHDOG_BASE + 0x34)
+#define OMAP_WATCHDOG_SPR (OMAP_WATCHDOG_BASE + 0x48)
+
+/* Using the prescaler, the OMAP watchdog could go for many
+ * months before firing. These limits work without scaling,
+ * with the 60 second default assumed by most tools and docs.
+ */
+#define TIMER_MARGIN_MAX (24 * 60 * 60) /* 1 day */
+#define TIMER_MARGIN_DEFAULT 60 /* 60 secs */
+#define TIMER_MARGIN_MIN 1
+
+#define PTV 0 /* prescale */
+#define GET_WLDR_VAL(secs) (0xffffffff - ((secs) * (32768/(1<<PTV))) + 1)
+
+#endif /* _OMAP_WATCHDOG_H */
diff --git a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
index cd7d1b6a5d9f..8e1e6e48e0a7 100644
--- a/drivers/char/watchdog/pcwd.c
+++ b/drivers/char/watchdog/pcwd.c
@@ -49,7 +49,6 @@
* More info available at http://www.berkprod.com/ or http://www.pcwatchdog.com/
*/
-#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
#include <linux/types.h> /* For standard types (like size_t) */
@@ -572,7 +571,7 @@ static int pcwd_ioctl(struct inode *inode, struct file *file,
switch(cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident)))
diff --git a/drivers/char/watchdog/pcwd_pci.c b/drivers/char/watchdog/pcwd_pci.c
index c7cfd6dbfe1b..f4872c871063 100644
--- a/drivers/char/watchdog/pcwd_pci.c
+++ b/drivers/char/watchdog/pcwd_pci.c
@@ -31,7 +31,6 @@
* Includes, defines, variables, module parameters, ...
*/
-#include <linux/config.h> /* For CONFIG_WATCHDOG_NOWAYOUT/... */
#include <linux/module.h> /* For module specific items */
#include <linux/moduleparam.h> /* For new moduleparam's */
#include <linux/types.h> /* For standard types (like size_t) */
@@ -541,7 +540,7 @@ static int pcipcwd_ioctl(struct inode *inode, struct file *file,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/pcwd_usb.c b/drivers/char/watchdog/pcwd_usb.c
index b7ae73dcdd08..bda45334d802 100644
--- a/drivers/char/watchdog/pcwd_usb.c
+++ b/drivers/char/watchdog/pcwd_usb.c
@@ -158,7 +158,7 @@ static struct usb_driver usb_pcwd_driver = {
};
-static void usb_pcwd_intr_done(struct urb *urb, struct pt_regs *regs)
+static void usb_pcwd_intr_done(struct urb *urb)
{
struct usb_pcwd_private *usb_pcwd = (struct usb_pcwd_private *)urb->context;
unsigned char *data = usb_pcwd->intr_buffer;
@@ -445,7 +445,7 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/pnx4008_wdt.c b/drivers/char/watchdog/pnx4008_wdt.c
new file mode 100644
index 000000000000..3a55fc6abcd8
--- /dev/null
+++ b/drivers/char/watchdog/pnx4008_wdt.c
@@ -0,0 +1,361 @@
+/*
+ * drivers/char/watchdog/pnx4008_wdt.c
+ *
+ * Watchdog driver for PNX4008 board
+ *
+ * Authors: Dmitry Chigirev <source@mvista.com>,
+ * Vitaly Wool <vitalywool@gmail.com>
+ * Based on sa1100 driver,
+ * Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
+ *
+ * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/spinlock.h>
+
+#include <asm/hardware.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+#define MODULE_NAME "PNX4008-WDT: "
+
+/* WatchDog Timer - Chapter 23 Page 207 */
+
+#define DEFAULT_HEARTBEAT 19
+#define MAX_HEARTBEAT 60
+
+/* Watchdog timer register set definition */
+#define WDTIM_INT(p) ((p) + 0x0)
+#define WDTIM_CTRL(p) ((p) + 0x4)
+#define WDTIM_COUNTER(p) ((p) + 0x8)
+#define WDTIM_MCTRL(p) ((p) + 0xC)
+#define WDTIM_MATCH0(p) ((p) + 0x10)
+#define WDTIM_EMR(p) ((p) + 0x14)
+#define WDTIM_PULSE(p) ((p) + 0x18)
+#define WDTIM_RES(p) ((p) + 0x1C)
+
+/* WDTIM_INT bit definitions */
+#define MATCH_INT 1
+
+/* WDTIM_CTRL bit definitions */
+#define COUNT_ENAB 1
+#define RESET_COUNT (1<<1)
+#define DEBUG_EN (1<<2)
+
+/* WDTIM_MCTRL bit definitions */
+#define MR0_INT 1
+#undef RESET_COUNT0
+#define RESET_COUNT0 (1<<2)
+#define STOP_COUNT0 (1<<2)
+#define M_RES1 (1<<3)
+#define M_RES2 (1<<4)
+#define RESFRC1 (1<<5)
+#define RESFRC2 (1<<6)
+
+/* WDTIM_EMR bit definitions */
+#define EXT_MATCH0 1
+#define MATCH_OUTPUT_HIGH (2<<4) /*a MATCH_CTRL setting */
+
+/* WDTIM_RES bit definitions */
+#define WDOG_RESET 1 /* read only */
+
+#define WDOG_COUNTER_RATE 13000000 /*the counter clock is 13 MHz fixed */
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+static int heartbeat = DEFAULT_HEARTBEAT;
+
+static spinlock_t io_lock;
+static unsigned long wdt_status;
+#define WDT_IN_USE 0
+#define WDT_OK_TO_CLOSE 1
+#define WDT_REGION_INITED 2
+#define WDT_DEVICE_INITED 3
+
+static unsigned long boot_status;
+
+static struct resource *wdt_mem;
+static void __iomem *wdt_base;
+struct clk *wdt_clk;
+
+static void wdt_enable(void)
+{
+ spin_lock(&io_lock);
+
+ if (wdt_clk)
+ clk_set_rate(wdt_clk, 1);
+
+ /* stop counter, initiate counter reset */
+ __raw_writel(RESET_COUNT, WDTIM_CTRL(wdt_base));
+ /*wait for reset to complete. 100% guarantee event */
+ while (__raw_readl(WDTIM_COUNTER(wdt_base)))
+ cpu_relax();
+ /* internal and external reset, stop after that */
+ __raw_writel(M_RES2 | STOP_COUNT0 | RESET_COUNT0,
+ WDTIM_MCTRL(wdt_base));
+ /* configure match output */
+ __raw_writel(MATCH_OUTPUT_HIGH, WDTIM_EMR(wdt_base));
+ /* clear interrupt, just in case */
+ __raw_writel(MATCH_INT, WDTIM_INT(wdt_base));
+ /* the longest pulse period 65541/(13*10^6) seconds ~ 5 ms. */
+ __raw_writel(0xFFFF, WDTIM_PULSE(wdt_base));
+ __raw_writel(heartbeat * WDOG_COUNTER_RATE, WDTIM_MATCH0(wdt_base));
+ /*enable counter, stop when debugger active */
+ __raw_writel(COUNT_ENAB | DEBUG_EN, WDTIM_CTRL(wdt_base));
+
+ spin_unlock(&io_lock);
+}
+
+static void wdt_disable(void)
+{
+ spin_lock(&io_lock);
+
+ __raw_writel(0, WDTIM_CTRL(wdt_base)); /*stop counter */
+ if (wdt_clk)
+ clk_set_rate(wdt_clk, 0);
+
+ spin_unlock(&io_lock);
+}
+
+static int pnx4008_wdt_open(struct inode *inode, struct file *file)
+{
+ if (test_and_set_bit(WDT_IN_USE, &wdt_status))
+ return -EBUSY;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ wdt_enable();
+
+ return nonseekable_open(inode, file);
+}
+
+static ssize_t
+pnx4008_wdt_write(struct file *file, const char *data, size_t len,
+ loff_t * ppos)
+{
+ /* Can't seek (pwrite) on this device */
+ if (ppos != &file->f_pos)
+ return -ESPIPE;
+
+ if (len) {
+ if (!nowayout) {
+ size_t i;
+
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ for (i = 0; i != len; i++) {
+ char c;
+
+ if (get_user(c, data + i))
+ return -EFAULT;
+ if (c == 'V')
+ set_bit(WDT_OK_TO_CLOSE, &wdt_status);
+ }
+ }
+ wdt_enable();
+ }
+
+ return len;
+}
+
+static struct watchdog_info ident = {
+ .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
+ WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .identity = "PNX4008 Watchdog",
+};
+
+static int
+pnx4008_wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret = -ENOTTY;
+ int time;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ ret = copy_to_user((struct watchdog_info *)arg, &ident,
+ sizeof(ident)) ? -EFAULT : 0;
+ break;
+
+ case WDIOC_GETSTATUS:
+ ret = put_user(0, (int *)arg);
+ break;
+
+ case WDIOC_GETBOOTSTATUS:
+ ret = put_user(boot_status, (int *)arg);
+ break;
+
+ case WDIOC_SETTIMEOUT:
+ ret = get_user(time, (int *)arg);
+ if (ret)
+ break;
+
+ if (time <= 0 || time > MAX_HEARTBEAT) {
+ ret = -EINVAL;
+ break;
+ }
+
+ heartbeat = time;
+ wdt_enable();
+ /* Fall through */
+
+ case WDIOC_GETTIMEOUT:
+ ret = put_user(heartbeat, (int *)arg);
+ break;
+
+ case WDIOC_KEEPALIVE:
+ wdt_enable();
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int pnx4008_wdt_release(struct inode *inode, struct file *file)
+{
+ if (!test_bit(WDT_OK_TO_CLOSE, &wdt_status))
+ printk(KERN_WARNING "WATCHDOG: Device closed unexpectdly\n");
+
+ wdt_disable();
+ clear_bit(WDT_IN_USE, &wdt_status);
+ clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
+
+ return 0;
+}
+
+static struct file_operations pnx4008_wdt_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .write = pnx4008_wdt_write,
+ .ioctl = pnx4008_wdt_ioctl,
+ .open = pnx4008_wdt_open,
+ .release = pnx4008_wdt_release,
+};
+
+static struct miscdevice pnx4008_wdt_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &pnx4008_wdt_fops,
+};
+
+static int pnx4008_wdt_probe(struct platform_device *pdev)
+{
+ int ret = 0, size;
+ struct resource *res;
+
+ spin_lock_init(&io_lock);
+
+ if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
+ heartbeat = DEFAULT_HEARTBEAT;
+
+ printk(KERN_INFO MODULE_NAME
+ "PNX4008 Watchdog Timer: heartbeat %d sec\n", heartbeat);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ printk(KERN_INFO MODULE_NAME
+ "failed to get memory region resouce\n");
+ return -ENOENT;
+ }
+
+ size = res->end - res->start + 1;
+ wdt_mem = request_mem_region(res->start, size, pdev->name);
+
+ if (wdt_mem == NULL) {
+ printk(KERN_INFO MODULE_NAME "failed to get memory region\n");
+ return -ENOENT;
+ }
+ wdt_base = (void __iomem *)IO_ADDRESS(res->start);
+
+ wdt_clk = clk_get(&pdev->dev, "wdt_ck");
+ if (!wdt_clk) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ goto out;
+ } else
+ clk_set_rate(wdt_clk, 1);
+
+ ret = misc_register(&pnx4008_wdt_miscdev);
+ if (ret < 0) {
+ printk(KERN_ERR MODULE_NAME "cannot register misc device\n");
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ clk_set_rate(wdt_clk, 0);
+ } else {
+ boot_status = (__raw_readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ?
+ WDIOF_CARDRESET : 0;
+ wdt_disable(); /*disable for now */
+ set_bit(WDT_DEVICE_INITED, &wdt_status);
+ }
+
+out:
+ return ret;
+}
+
+static int pnx4008_wdt_remove(struct platform_device *pdev)
+{
+ misc_deregister(&pnx4008_wdt_miscdev);
+ if (wdt_clk) {
+ clk_set_rate(wdt_clk, 0);
+ clk_put(wdt_clk);
+ wdt_clk = NULL;
+ }
+ if (wdt_mem) {
+ release_resource(wdt_mem);
+ kfree(wdt_mem);
+ wdt_mem = NULL;
+ }
+ return 0;
+}
+
+static struct platform_driver platform_wdt_driver = {
+ .driver = {
+ .name = "watchdog",
+ },
+ .probe = pnx4008_wdt_probe,
+ .remove = pnx4008_wdt_remove,
+};
+
+static int __init pnx4008_wdt_init(void)
+{
+ return platform_driver_register(&platform_wdt_driver);
+}
+
+static void __exit pnx4008_wdt_exit(void)
+{
+ return platform_driver_unregister(&platform_wdt_driver);
+}
+
+module_init(pnx4008_wdt_init);
+module_exit(pnx4008_wdt_exit);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PNX4008 Watchdog Driver");
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat,
+ "Watchdog heartbeat period in seconds from 1 to "
+ __MODULE_STRING(MAX_HEARTBEAT) ", default "
+ __MODULE_STRING(DEFAULT_HEARTBEAT));
+
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout,
+ "Set to 1 to keep watchdog running after device release");
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
diff --git a/drivers/char/watchdog/s3c2410_wdt.c b/drivers/char/watchdog/s3c2410_wdt.c
index be978e8ed754..68b1ca976d53 100644
--- a/drivers/char/watchdog/s3c2410_wdt.c
+++ b/drivers/char/watchdog/s3c2410_wdt.c
@@ -62,7 +62,7 @@
#define CONFIG_S3C2410_WATCHDOG_ATBOOT (0)
#define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME (15)
-static int nowayout = WATCHDOG_NOWAYOUT;
+static int nowayout = WATCHDOG_NOWAYOUT;
static int tmr_margin = CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME;
static int tmr_atboot = CONFIG_S3C2410_WATCHDOG_ATBOOT;
static int soft_noboot = 0;
@@ -213,11 +213,10 @@ static int s3c2410wdt_open(struct inode *inode, struct file *file)
if(down_trylock(&open_lock))
return -EBUSY;
- if (nowayout) {
+ if (nowayout)
__module_get(THIS_MODULE);
- } else {
- allow_close = CLOSE_STATE_ALLOW;
- }
+
+ allow_close = CLOSE_STATE_NOT;
/* start the timer */
s3c2410wdt_start();
@@ -230,6 +229,7 @@ static int s3c2410wdt_release(struct inode *inode, struct file *file)
* Shut off the timer.
* Lock it in if it's a module and we set nowayout
*/
+
if (allow_close == CLOSE_STATE_ALLOW) {
s3c2410wdt_stop();
} else {
@@ -288,7 +288,7 @@ static int s3c2410wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &s3c2410_wdt_ident,
@@ -336,8 +336,7 @@ static struct miscdevice s3c2410wdt_miscdev = {
/* interrupt handler code */
-static irqreturn_t s3c2410wdt_irq(int irqno, void *param,
- struct pt_regs *regs)
+static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
{
printk(KERN_INFO PFX "Watchdog timer expired!\n");
diff --git a/drivers/char/watchdog/sa1100_wdt.c b/drivers/char/watchdog/sa1100_wdt.c
index 1fc16d995788..33c1137f17d6 100644
--- a/drivers/char/watchdog/sa1100_wdt.c
+++ b/drivers/char/watchdog/sa1100_wdt.c
@@ -90,7 +90,7 @@ static struct watchdog_info ident = {
static int sa1100dog_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
int time;
void __user *argp = (void __user *)arg;
int __user *p = argp;
diff --git a/drivers/char/watchdog/sbc60xxwdt.c b/drivers/char/watchdog/sbc60xxwdt.c
index 4663c2fd53cd..c7b2045bc76b 100644
--- a/drivers/char/watchdog/sbc60xxwdt.c
+++ b/drivers/char/watchdog/sbc60xxwdt.c
@@ -235,7 +235,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
index bfc475dabe6d..8882b427d24f 100644
--- a/drivers/char/watchdog/sbc_epx_c3.c
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -141,7 +141,7 @@ static int epx_c3_ioctl(struct inode *inode, struct file *file,
return retval;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/sc1200wdt.c b/drivers/char/watchdog/sc1200wdt.c
index 7c3cf293a5af..d8d0f28e0acf 100644
--- a/drivers/char/watchdog/sc1200wdt.c
+++ b/drivers/char/watchdog/sc1200wdt.c
@@ -180,7 +180,7 @@ static int sc1200wdt_ioctl(struct inode *inode, struct file *file, unsigned int
switch (cmd) {
default:
- return -ENOIOCTLCMD; /* Keep Pavel Machek amused ;) */
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if (copy_to_user(argp, &ident, sizeof ident))
diff --git a/drivers/char/watchdog/sc520_wdt.c b/drivers/char/watchdog/sc520_wdt.c
index 2c7c9db71be8..caec37ba750a 100644
--- a/drivers/char/watchdog/sc520_wdt.c
+++ b/drivers/char/watchdog/sc520_wdt.c
@@ -290,7 +290,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
diff --git a/drivers/char/watchdog/scx200_wdt.c b/drivers/char/watchdog/scx200_wdt.c
index c561299a5537..fc0e0347f9d2 100644
--- a/drivers/char/watchdog/scx200_wdt.c
+++ b/drivers/char/watchdog/scx200_wdt.c
@@ -166,7 +166,7 @@ static int scx200_wdt_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
if(copy_to_user(argp, &ident, sizeof(ident)))
return -EFAULT;
diff --git a/drivers/char/watchdog/shwdt.c b/drivers/char/watchdog/shwdt.c
index 1355038f1044..dc403629aeb3 100644
--- a/drivers/char/watchdog/shwdt.c
+++ b/drivers/char/watchdog/shwdt.c
@@ -27,7 +27,7 @@
#include <linux/notifier.h>
#include <linux/ioport.h>
#include <linux/fs.h>
-
+#include <linux/mm.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/watchdog.h>
@@ -125,7 +125,6 @@ static void sh_wdt_start(void)
/**
* sh_wdt_stop - Stop the Watchdog
- *
* Stops the watchdog.
*/
static void sh_wdt_stop(void)
@@ -141,22 +140,20 @@ static void sh_wdt_stop(void)
/**
* sh_wdt_keepalive - Keep the Userspace Watchdog Alive
- *
* The Userspace watchdog got a KeepAlive: schedule the next heartbeat.
*/
-static void sh_wdt_keepalive(void)
+static inline void sh_wdt_keepalive(void)
{
next_heartbeat = jiffies + (heartbeat * HZ);
}
/**
* sh_wdt_set_heartbeat - Set the Userspace Watchdog heartbeat
- *
* Set the Userspace Watchdog heartbeat
*/
static int sh_wdt_set_heartbeat(int t)
{
- if ((t < 1) || (t > 3600)) /* arbitrary upper limit */
+ if (unlikely((t < 1) || (t > 3600))) /* arbitrary upper limit */
return -EINVAL;
heartbeat = t;
@@ -165,7 +162,6 @@ static int sh_wdt_set_heartbeat(int t)
/**
* sh_wdt_ping - Ping the Watchdog
- *
* @data: Unused
*
* Clears overflow bit, resets timer counter.
@@ -182,14 +178,13 @@ static void sh_wdt_ping(unsigned long data)
sh_wdt_write_cnt(0);
mod_timer(&timer, next_ping_period(clock_division_ratio));
- } else {
- printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n");
- }
+ } else
+ printk(KERN_WARNING PFX "Heartbeat lost! Will not ping "
+ "the watchdog\n");
}
/**
* sh_wdt_open - Open the Device
- *
* @inode: inode of device
* @file: file handle of device
*
@@ -209,7 +204,6 @@ static int sh_wdt_open(struct inode *inode, struct file *file)
/**
* sh_wdt_close - Close the Device
- *
* @inode: inode of device
* @file: file handle of device
*
@@ -220,7 +214,8 @@ static int sh_wdt_close(struct inode *inode, struct file *file)
if (shwdt_expect_close == 42) {
sh_wdt_stop();
} else {
- printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n");
+ printk(KERN_CRIT PFX "Unexpected close, not "
+ "stopping watchdog!\n");
sh_wdt_keepalive();
}
@@ -232,7 +227,6 @@ static int sh_wdt_close(struct inode *inode, struct file *file)
/**
* sh_wdt_write - Write to Device
- *
* @file: file handle of device
* @buf: buffer to write
* @count: length of buffer
@@ -264,8 +258,56 @@ static ssize_t sh_wdt_write(struct file *file, const char *buf,
}
/**
- * sh_wdt_ioctl - Query Device
+ * sh_wdt_mmap - map WDT/CPG registers into userspace
+ * @file: file structure for the device
+ * @vma: VMA to map the registers into
+ *
+ * A simple mmap() implementation for the corner cases where the counter
+ * needs to be mapped in userspace directly. Due to the relatively small
+ * size of the area, neighbouring registers not necessarily tied to the
+ * CPG will also be accessible through the register page, so this remains
+ * configurable for users that really know what they're doing.
*
+ * Additionaly, the register page maps in the CPG register base relative
+ * to the nearest page-aligned boundary, which requires that userspace do
+ * the appropriate CPU subtype math for calculating the page offset for
+ * the counter value.
+ */
+static int sh_wdt_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ int ret = -ENOSYS;
+
+#ifdef CONFIG_SH_WDT_MMAP
+ unsigned long addr;
+
+ /* Only support the simple cases where we map in a register page. */
+ if (((vma->vm_end - vma->vm_start) != PAGE_SIZE) || vma->vm_pgoff)
+ return -EINVAL;
+
+ /*
+ * Pick WTCNT as the start, it's usually the first register after the
+ * FRQCR, and neither one are generally page-aligned out of the box.
+ */
+ addr = WTCNT & ~(PAGE_SIZE - 1);
+
+ vma->vm_flags |= VM_IO;
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (io_remap_pfn_range(vma, vma->vm_start, addr >> PAGE_SHIFT,
+ PAGE_SIZE, vma->vm_page_prot)) {
+ printk(KERN_ERR PFX "%s: io_remap_pfn_range failed\n",
+ __FUNCTION__);
+ return -EAGAIN;
+ }
+
+ ret = 0;
+#endif
+
+ return ret;
+}
+
+/**
+ * sh_wdt_ioctl - Query Device
* @inode: inode of device
* @file: file handle of device
* @cmd: watchdog command
@@ -318,7 +360,7 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file,
return retval;
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
@@ -326,7 +368,6 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file,
/**
* sh_wdt_notify_sys - Notifier Handler
- *
* @this: notifier block
* @code: notifier event
* @unused: unused
@@ -337,9 +378,8 @@ static int sh_wdt_ioctl(struct inode *inode, struct file *file,
static int sh_wdt_notify_sys(struct notifier_block *this,
unsigned long code, void *unused)
{
- if (code == SYS_DOWN || code == SYS_HALT) {
+ if (code == SYS_DOWN || code == SYS_HALT)
sh_wdt_stop();
- }
return NOTIFY_DONE;
}
@@ -351,10 +391,12 @@ static const struct file_operations sh_wdt_fops = {
.ioctl = sh_wdt_ioctl,
.open = sh_wdt_open,
.release = sh_wdt_close,
+ .mmap = sh_wdt_mmap,
};
static struct watchdog_info sh_wdt_info = {
- .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE,
+ .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
+ WDIOF_MAGICCLOSE,
.firmware_version = 1,
.identity = "SH WDT",
};
@@ -371,7 +413,6 @@ static struct miscdevice sh_wdt_miscdev = {
/**
* sh_wdt_init - Initialize module
- *
* Registers the device and notifier handler. Actual device
* initialization is handled by sh_wdt_open().
*/
@@ -381,15 +422,15 @@ static int __init sh_wdt_init(void)
if ((clock_division_ratio < 0x5) || (clock_division_ratio > 0x7)) {
clock_division_ratio = WTCSR_CKS_4096;
- printk(KERN_INFO PFX "clock_division_ratio value must be 0x5<=x<=0x7, using %d\n",
- clock_division_ratio);
+ printk(KERN_INFO PFX "clock_division_ratio value must "
+ "be 0x5<=x<=0x7, using %d\n", clock_division_ratio);
}
- if (sh_wdt_set_heartbeat(heartbeat))
- {
+ rc = sh_wdt_set_heartbeat(heartbeat);
+ if (unlikely(rc)) {
heartbeat = WATCHDOG_HEARTBEAT;
- printk(KERN_INFO PFX "heartbeat value must be 1<=x<=3600, using %d\n",
- heartbeat);
+ printk(KERN_INFO PFX "heartbeat value must "
+ "be 1<=x<=3600, using %d\n", heartbeat);
}
init_timer(&timer);
@@ -397,15 +438,16 @@ static int __init sh_wdt_init(void)
timer.data = 0;
rc = register_reboot_notifier(&sh_wdt_notifier);
- if (rc) {
- printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n", rc);
+ if (unlikely(rc)) {
+ printk(KERN_ERR PFX "Can't register reboot notifier (err=%d)\n",
+ rc);
return rc;
}
rc = misc_register(&sh_wdt_miscdev);
- if (rc) {
- printk(KERN_ERR PFX "Can't register miscdev on minor=%d (err=%d)\n",
- sh_wdt_miscdev.minor, rc);
+ if (unlikely(rc)) {
+ printk(KERN_ERR PFX "Can't register miscdev on "
+ "minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc);
unregister_reboot_notifier(&sh_wdt_notifier);
return rc;
}
@@ -418,7 +460,6 @@ static int __init sh_wdt_init(void)
/**
* sh_wdt_exit - Deinitialize module
- *
* Unregisters the device and notifier handler. Actual device
* deinitialization is handled by sh_wdt_close().
*/
@@ -434,14 +475,13 @@ MODULE_LICENSE("GPL");
MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
module_param(clock_division_ratio, int, 0);
-MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). Defaults to 0x7.");
+MODULE_PARM_DESC(clock_division_ratio, "Clock division ratio. Valid ranges are from 0x5 (1.31ms) to 0x7 (5.25ms). (default=" __MODULE_STRING(clock_division_ratio) ")");
module_param(heartbeat, int, 0);
MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (1<=heartbeat<=3600, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
module_init(sh_wdt_init);
module_exit(sh_wdt_exit);
-
diff --git a/drivers/char/watchdog/softdog.c b/drivers/char/watchdog/softdog.c
index ef8da517545a..4067e1f8a368 100644
--- a/drivers/char/watchdog/softdog.c
+++ b/drivers/char/watchdog/softdog.c
@@ -203,7 +203,7 @@ static int softdog_ioctl(struct inode *inode, struct file *file,
};
switch (cmd) {
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident,
sizeof(ident)) ? -EFAULT : 0;
diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c
index 13f16d41c2fd..b4adc527e687 100644
--- a/drivers/char/watchdog/w83627hf_wdt.c
+++ b/drivers/char/watchdog/w83627hf_wdt.c
@@ -223,7 +223,7 @@ wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/w83877f_wdt.c b/drivers/char/watchdog/w83877f_wdt.c
index ccf6c0915945..b0e5f84d6baf 100644
--- a/drivers/char/watchdog/w83877f_wdt.c
+++ b/drivers/char/watchdog/w83877f_wdt.c
@@ -252,7 +252,7 @@ static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
case WDIOC_GETSTATUS:
diff --git a/drivers/char/watchdog/w83977f_wdt.c b/drivers/char/watchdog/w83977f_wdt.c
index 98f4e17db70a..2c8d5d8bd4e8 100644
--- a/drivers/char/watchdog/w83977f_wdt.c
+++ b/drivers/char/watchdog/w83977f_wdt.c
@@ -393,7 +393,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident, sizeof(ident)) ? -EFAULT : 0;
diff --git a/drivers/char/watchdog/wafer5823wdt.c b/drivers/char/watchdog/wafer5823wdt.c
index 2bb6a9d6ad28..163e028ef9ed 100644
--- a/drivers/char/watchdog/wafer5823wdt.c
+++ b/drivers/char/watchdog/wafer5823wdt.c
@@ -174,7 +174,7 @@ static int wafwdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
return 0;
}
diff --git a/drivers/char/watchdog/wdrtas.c b/drivers/char/watchdog/wdrtas.c
index 5c38cdf41731..1d64e277567d 100644
--- a/drivers/char/watchdog/wdrtas.c
+++ b/drivers/char/watchdog/wdrtas.c
@@ -385,7 +385,7 @@ wdrtas_ioctl(struct inode *inode, struct file *file,
return put_user(wdrtas_interval, argp);
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
}
}
diff --git a/drivers/char/watchdog/wdt.c b/drivers/char/watchdog/wdt.c
index 70be81e39a61..517fbd8643f8 100644
--- a/drivers/char/watchdog/wdt.c
+++ b/drivers/char/watchdog/wdt.c
@@ -225,14 +225,13 @@ static int wdt_get_temperature(int *temperature)
* wdt_interrupt:
* @irq: Interrupt number
* @dev_id: Unused as we don't allow multiple devices.
- * @regs: Unused.
*
* Handle an interrupt from the board. These are raised when the status
* map changes in what the board considers an interesting way. That means
* a failure condition occurring.
*/
-static irqreturn_t wdt_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wdt_interrupt(int irq, void *dev_id)
{
/*
* Read the status register see what is up and
@@ -341,7 +340,7 @@ static int wdt_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
diff --git a/drivers/char/watchdog/wdt285.c b/drivers/char/watchdog/wdt285.c
index 6555fb844f23..e4cf661dc890 100644
--- a/drivers/char/watchdog/wdt285.c
+++ b/drivers/char/watchdog/wdt285.c
@@ -46,7 +46,7 @@ static unsigned long timer_alive;
/*
* If the timer expires..
*/
-static void watchdog_fire(int irq, void *dev_id, struct pt_regs *regs)
+static void watchdog_fire(int irq, void *dev_id)
{
printk(KERN_CRIT "Watchdog: Would Reboot.\n");
*CSR_TIMER4_CNTL = 0;
@@ -137,7 +137,7 @@ watchdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
unsigned int new_margin;
- int ret = -ENOIOCTLCMD;
+ int ret = -ENOTTY;
switch(cmd) {
case WDIOC_GETSUPPORT:
diff --git a/drivers/char/watchdog/wdt977.c b/drivers/char/watchdog/wdt977.c
index a0935bc775f8..6253041b235b 100644
--- a/drivers/char/watchdog/wdt977.c
+++ b/drivers/char/watchdog/wdt977.c
@@ -361,7 +361,7 @@ static int wdt977_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(uarg.ident, &ident,
diff --git a/drivers/char/watchdog/wdt_pci.c b/drivers/char/watchdog/wdt_pci.c
index 5918ca2c9c35..ce1261c5cbce 100644
--- a/drivers/char/watchdog/wdt_pci.c
+++ b/drivers/char/watchdog/wdt_pci.c
@@ -270,14 +270,13 @@ static int wdtpci_get_temperature(int *temperature)
* wdtpci_interrupt:
* @irq: Interrupt number
* @dev_id: Unused as we don't allow multiple devices.
- * @regs: Unused.
*
* Handle an interrupt from the board. These are raised when the status
* map changes in what the board considers an interesting way. That means
* a failure condition occurring.
*/
-static irqreturn_t wdtpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
{
/*
* Read the status register see what is up and
@@ -386,7 +385,7 @@ static int wdtpci_ioctl(struct inode *inode, struct file *file, unsigned int cmd
switch(cmd)
{
default:
- return -ENOIOCTLCMD;
+ return -ENOTTY;
case WDIOC_GETSUPPORT:
return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
diff --git a/drivers/clocksource/acpi_pm.c b/drivers/clocksource/acpi_pm.c
index 7ad3be8c0f49..7fcb77a9d011 100644
--- a/drivers/clocksource/acpi_pm.c
+++ b/drivers/clocksource/acpi_pm.c
@@ -54,8 +54,8 @@ static cycle_t acpi_pm_read_verified(void)
v1 = read_pmtmr();
v2 = read_pmtmr();
v3 = read_pmtmr();
- } while ((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
- || (v3 > v1 && v3 < v2));
+ } while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
+ || (v3 > v1 && v3 < v2)));
return (cycle_t)v2;
}
@@ -138,6 +138,8 @@ static void __devinit acpi_pm_check_graylist(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0,
acpi_pm_check_graylist);
+DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_LE,
+ acpi_pm_check_graylist);
#endif
diff --git a/drivers/clocksource/scx200_hrt.c b/drivers/clocksource/scx200_hrt.c
index d418b8297211..22915cc46ba7 100644
--- a/drivers/clocksource/scx200_hrt.c
+++ b/drivers/clocksource/scx200_hrt.c
@@ -63,7 +63,7 @@ static struct clocksource cs_hrt = {
static int __init init_hrt_clocksource(void)
{
- /* Make sure scx200 has initializedd the configuration block */
+ /* Make sure scx200 has initialized the configuration block */
if (!scx200_cb_present())
return -ENODEV;
@@ -76,7 +76,7 @@ static int __init init_hrt_clocksource(void)
}
/* write timer config */
- outb(HR_TMEN | (mhz27) ? HR_TMCLKSEL : 0,
+ outb(HR_TMEN | (mhz27 ? HR_TMCLKSEL : 0),
scx200_cb_base + SCx200_TMCNFG_OFFSET);
if (mhz27) {
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index d35a9f06ab7b..86e69b7f9122 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -52,8 +52,14 @@ static void handle_update(void *data);
* The mutex locks both lists.
*/
static BLOCKING_NOTIFIER_HEAD(cpufreq_policy_notifier_list);
-static BLOCKING_NOTIFIER_HEAD(cpufreq_transition_notifier_list);
+static struct srcu_notifier_head cpufreq_transition_notifier_list;
+static int __init init_cpufreq_transition_notifier_list(void)
+{
+ srcu_init_notifier_head(&cpufreq_transition_notifier_list);
+ return 0;
+}
+core_initcall(init_cpufreq_transition_notifier_list);
static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX (cpufreq_governor_mutex);
@@ -262,14 +268,14 @@ void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state)
freqs->old = policy->cur;
}
}
- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_PRECHANGE, freqs);
adjust_jiffies(CPUFREQ_PRECHANGE, freqs);
break;
case CPUFREQ_POSTCHANGE:
adjust_jiffies(CPUFREQ_POSTCHANGE, freqs);
- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_POSTCHANGE, freqs);
if (likely(policy) && likely(policy->cpu == freqs->cpu))
policy->cur = freqs->new;
@@ -994,7 +1000,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
unsigned int cur_freq = 0;
struct cpufreq_policy *cpu_policy;
- dprintk("resuming cpu %u\n", cpu);
+ dprintk("suspending cpu %u\n", cpu);
if (!cpu_online(cpu))
return 0;
@@ -1049,7 +1055,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- blocking_notifier_call_chain(&cpufreq_transition_notifier_list,
+ srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
CPUFREQ_SUSPENDCHANGE, &freqs);
adjust_jiffies(CPUFREQ_SUSPENDCHANGE, &freqs);
@@ -1130,7 +1136,7 @@ static int cpufreq_resume(struct sys_device * sysdev)
freqs.old = cpu_policy->cur;
freqs.new = cur_freq;
- blocking_notifier_call_chain(
+ srcu_notifier_call_chain(
&cpufreq_transition_notifier_list,
CPUFREQ_RESUMECHANGE, &freqs);
adjust_jiffies(CPUFREQ_RESUMECHANGE, &freqs);
@@ -1176,7 +1182,7 @@ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list)
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
- ret = blocking_notifier_chain_register(
+ ret = srcu_notifier_chain_register(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
@@ -1208,7 +1214,7 @@ int cpufreq_unregister_notifier(struct notifier_block *nb, unsigned int list)
switch (list) {
case CPUFREQ_TRANSITION_NOTIFIER:
- ret = blocking_notifier_chain_unregister(
+ ret = srcu_notifier_chain_unregister(
&cpufreq_transition_notifier_list, nb);
break;
case CPUFREQ_POLICY_NOTIFIER:
diff --git a/drivers/dma/ioatdma.c b/drivers/dma/ioatdma.c
index dbd4d6c3698e..0358419a0e48 100644
--- a/drivers/dma/ioatdma.c
+++ b/drivers/dma/ioatdma.c
@@ -80,7 +80,7 @@ static int enumerate_dma_channels(struct ioat_device *device)
static struct ioat_desc_sw *ioat_dma_alloc_descriptor(
struct ioat_dma_chan *ioat_chan,
- int flags)
+ gfp_t flags)
{
struct ioat_dma_descriptor *desc;
struct ioat_desc_sw *desc_sw;
@@ -563,7 +563,7 @@ static struct pci_driver ioat_pci_drv = {
.remove = __devexit_p(ioat_remove),
};
-static irqreturn_t ioat_do_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t ioat_do_interrupt(int irq, void *data)
{
struct ioat_device *instance = data;
unsigned long attnstatus;
@@ -686,7 +686,7 @@ static int __devinit ioat_probe(struct pci_dev *pdev,
{
int err;
unsigned long mmio_start, mmio_len;
- void *reg_base;
+ void __iomem *reg_base;
struct ioat_device *device;
err = pci_enable_device(pdev);
diff --git a/drivers/dma/ioatdma.h b/drivers/dma/ioatdma.h
index a5d3b3644160..62b26a9be4c9 100644
--- a/drivers/dma/ioatdma.h
+++ b/drivers/dma/ioatdma.h
@@ -44,7 +44,7 @@ extern struct list_head dma_client_list;
struct ioat_device {
struct pci_dev *pdev;
- void *reg_base;
+ void __iomem *reg_base;
struct pci_pool *dma_pool;
struct pci_pool *completion_pool;
@@ -73,7 +73,7 @@ struct ioat_device {
struct ioat_dma_chan {
- void *reg_base;
+ void __iomem *reg_base;
dma_cookie_t completed_cookie;
unsigned long last_completion;
diff --git a/drivers/eisa/eisa-bus.c b/drivers/eisa/eisa-bus.c
index 6078e2f58817..d944647c82c2 100644
--- a/drivers/eisa/eisa-bus.c
+++ b/drivers/eisa/eisa-bus.c
@@ -128,9 +128,23 @@ static int eisa_bus_match (struct device *dev, struct device_driver *drv)
return 0;
}
+static int eisa_bus_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct eisa_device *edev = to_eisa_device(dev);
+ int i = 0;
+ int length = 0;
+
+ add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "MODALIAS=" EISA_DEVICE_MODALIAS_FMT, edev->id.sig);
+ envp[i] = NULL;
+ return 0;
+}
+
struct bus_type eisa_bus_type = {
.name = "eisa",
.match = eisa_bus_match,
+ .uevent = eisa_bus_uevent,
};
int eisa_driver_register (struct eisa_driver *edrv)
@@ -160,6 +174,14 @@ static ssize_t eisa_show_state (struct device *dev, struct device_attribute *att
static DEVICE_ATTR(enabled, S_IRUGO, eisa_show_state, NULL);
+static ssize_t eisa_show_modalias (struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct eisa_device *edev = to_eisa_device (dev);
+ return sprintf (buf, EISA_DEVICE_MODALIAS_FMT "\n", edev->id.sig);
+}
+
+static DEVICE_ATTR(modalias, S_IRUGO, eisa_show_modalias, NULL);
+
static int __init eisa_init_device (struct eisa_root_device *root,
struct eisa_device *edev,
int slot)
@@ -204,13 +226,26 @@ static int __init eisa_init_device (struct eisa_root_device *root,
static int __init eisa_register_device (struct eisa_device *edev)
{
- if (device_register (&edev->dev))
- return -1;
+ int rc = device_register (&edev->dev);
+ if (rc)
+ return rc;
- device_create_file (&edev->dev, &dev_attr_signature);
- device_create_file (&edev->dev, &dev_attr_enabled);
+ rc = device_create_file (&edev->dev, &dev_attr_signature);
+ if (rc) goto err_devreg;
+ rc = device_create_file (&edev->dev, &dev_attr_enabled);
+ if (rc) goto err_sig;
+ rc = device_create_file (&edev->dev, &dev_attr_modalias);
+ if (rc) goto err_enab;
return 0;
+
+err_enab:
+ device_remove_file (&edev->dev, &dev_attr_enabled);
+err_sig:
+ device_remove_file (&edev->dev, &dev_attr_signature);
+err_devreg:
+ device_unregister(&edev->dev);
+ return rc;
}
static int __init eisa_request_resources (struct eisa_root_device *root,
diff --git a/drivers/fc4/fc.c b/drivers/fc4/fc.c
index 1a159e8843ca..22d17474755f 100644
--- a/drivers/fc4/fc.c
+++ b/drivers/fc4/fc.c
@@ -974,7 +974,6 @@ int fcp_scsi_dev_reset(Scsi_Cmnd *SCpnt)
*/
fc->rst_pkt->device->host->eh_action = &sem;
- fc->rst_pkt->request->rq_status = RQ_SCSI_BUSY;
fc->rst_pkt->done = fcp_scsi_reset_done;
diff --git a/drivers/fc4/soc.c b/drivers/fc4/soc.c
index 3b07e0ca81cd..b09dfc78e5a2 100644
--- a/drivers/fc4/soc.c
+++ b/drivers/fc4/soc.c
@@ -334,7 +334,7 @@ update_out:
}
}
-static irqreturn_t soc_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t soc_intr(int irq, void *dev_id)
{
u32 cmd;
unsigned long flags;
diff --git a/drivers/fc4/socal.c b/drivers/fc4/socal.c
index 2b75edc5859d..a6b1ae256e16 100644
--- a/drivers/fc4/socal.c
+++ b/drivers/fc4/socal.c
@@ -404,7 +404,7 @@ update_out:
}
}
-static irqreturn_t socal_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t socal_intr(int irq, void *dev_id)
{
u32 cmd;
unsigned long flags;
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig
index 731c3d5da0dc..88f462122a30 100644
--- a/drivers/firmware/Kconfig
+++ b/drivers/firmware/Kconfig
@@ -64,7 +64,7 @@ config DELL_RBU
help
Say m if you want to have the option of updating the BIOS for your
DELL system. Note you need a Dell OpenManage or Dell Update package (DUP)
- supporting application to comunicate with the BIOS regarding the new
+ supporting application to communicate with the BIOS regarding the new
image for the image update to take effect.
See <file:Documentation/dell_rbu.txt> for more details on the driver.
diff --git a/drivers/firmware/dcdbas.c b/drivers/firmware/dcdbas.c
index 339f405ff708..1865b56fb141 100644
--- a/drivers/firmware/dcdbas.c
+++ b/drivers/firmware/dcdbas.c
@@ -8,7 +8,7 @@
*
* See Documentation/dcdbas.txt for more information.
*
- * Copyright (C) 1995-2005 Dell Inc.
+ * Copyright (C) 1995-2006 Dell Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License v2.0 as published by
@@ -40,7 +40,7 @@
#include "dcdbas.h"
#define DRIVER_NAME "dcdbas"
-#define DRIVER_VERSION "5.6.0-2"
+#define DRIVER_VERSION "5.6.0-3.2"
#define DRIVER_DESCRIPTION "Dell Systems Management Base Driver"
static struct platform_device *dcdbas_pdev;
@@ -175,6 +175,9 @@ static ssize_t smi_data_write(struct kobject *kobj, char *buf, loff_t pos,
{
ssize_t ret;
+ if ((pos + count) > MAX_SMI_DATA_BUF_SIZE)
+ return -EINVAL;
+
mutex_lock(&smi_data_lock);
ret = smi_data_buf_realloc(pos + count);
@@ -559,7 +562,7 @@ static int __devinit dcdbas_probe(struct platform_device *dev)
while (--i >= 0)
sysfs_remove_bin_file(&dev->dev.kobj,
dcdbas_bin_attrs[i]);
- sysfs_create_group(&dev->dev.kobj, &dcdbas_attr_group);
+ sysfs_remove_group(&dev->dev.kobj, &dcdbas_attr_group);
return error;
}
}
diff --git a/drivers/firmware/dell_rbu.c b/drivers/firmware/dell_rbu.c
index 23b086685453..08b161798443 100644
--- a/drivers/firmware/dell_rbu.c
+++ b/drivers/firmware/dell_rbu.c
@@ -227,7 +227,7 @@ static int packetize_data(void *data, size_t length)
int packet_length;
u8 *temp;
u8 *end = (u8 *) data + length;
- pr_debug("packetize_data: data length %d\n", length);
+ pr_debug("packetize_data: data length %zd\n", length);
if (!rbu_data.packetsize) {
printk(KERN_WARNING
"dell_rbu: packetsize not specified\n");
@@ -249,7 +249,7 @@ static int packetize_data(void *data, size_t length)
if ((rc = create_packet(temp, packet_length)))
return rc;
- pr_debug("%lu:%lu\n", temp, (end - temp));
+ pr_debug("%p:%td\n", temp, (end - temp));
temp += packet_length;
}
@@ -718,14 +718,27 @@ static int __init dcdrbu_init(void)
return -EIO;
}
- sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
- sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
- sysfs_create_bin_file(&rbu_device->dev.kobj,
+ rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
+ if (rc)
+ goto out_devreg;
+ rc = sysfs_create_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
+ if (rc)
+ goto out_data;
+ rc = sysfs_create_bin_file(&rbu_device->dev.kobj,
&rbu_packet_size_attr);
+ if (rc)
+ goto out_imtype;
rbu_data.entry_created = 0;
- return rc;
+ return 0;
+out_imtype:
+ sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_image_type_attr);
+out_data:
+ sysfs_remove_bin_file(&rbu_device->dev.kobj, &rbu_data_attr);
+out_devreg:
+ platform_device_unregister(rbu_device);
+ return rc;
}
static __exit void dcdrbu_exit(void)
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index b9e3886d9e16..37deee6c0c1c 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -123,6 +123,26 @@ static void __init dmi_save_devices(struct dmi_header *dm)
dev->type = *d++ & 0x7f;
dev->name = dmi_string(dm, *d);
dev->device_data = NULL;
+ list_add(&dev->list, &dmi_devices);
+ }
+}
+
+static void __init dmi_save_oem_strings_devices(struct dmi_header *dm)
+{
+ int i, count = *(u8 *)(dm + 1);
+ struct dmi_device *dev;
+
+ for (i = 1; i <= count; i++) {
+ dev = dmi_alloc(sizeof(*dev));
+ if (!dev) {
+ printk(KERN_ERR
+ "dmi_save_oem_strings_devices: out of memory.\n");
+ break;
+ }
+
+ dev->type = DMI_DEV_TYPE_OEM_STRING;
+ dev->name = dmi_string(dm, i);
+ dev->device_data = NULL;
list_add(&dev->list, &dmi_devices);
}
@@ -181,6 +201,9 @@ static void __init dmi_decode(struct dmi_header *dm)
case 10: /* Onboard Devices Information */
dmi_save_devices(dm);
break;
+ case 11: /* OEM Strings */
+ dmi_save_oem_strings_devices(dm);
+ break;
case 38: /* IPMI Device Information */
dmi_save_ipmi_device(dm);
}
@@ -303,6 +326,26 @@ char *dmi_get_system_info(int field)
}
EXPORT_SYMBOL(dmi_get_system_info);
+
+/**
+ * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information.
+ * @str: Case sensitive Name
+ */
+int dmi_name_in_vendors(char *str)
+{
+ static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR,
+ DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR,
+ DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE };
+ int i;
+ for (i = 0; fields[i] != DMI_NONE; i++) {
+ int f = fields[i];
+ if (dmi_ident[f] && strstr(dmi_ident[f], str))
+ return 1;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dmi_name_in_vendors);
+
/**
* dmi_find_device - find onboard device by type/name
* @type: device type or %DMI_DEV_TYPE_ANY to match all device types
diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c
index b4502ed65793..5c261e1f92b2 100644
--- a/drivers/firmware/edd.c
+++ b/drivers/firmware/edd.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/i386/kernel/edd.c
+ * linux/drivers/firmware/edd.c
* Copyright (C) 2002, 2003, 2004 Dell Inc.
* by Matt Domsch <Matt_Domsch@dell.com>
* disk signature by Matt Domsch, Andrew Wilks, and Sandeep K. Shandilya
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index 8ebce1c03ad7..5ab5e393b882 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -639,7 +639,12 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
kobject_set_name(&new_efivar->kobj, "%s", short_name);
kobj_set_kset_s(new_efivar, vars_subsys);
- kobject_register(&new_efivar->kobj);
+ i = kobject_register(&new_efivar->kobj);
+ if (i) {
+ kfree(short_name);
+ kfree(new_efivar);
+ return 1;
+ }
kfree(short_name);
short_name = NULL;
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 0e31a0c496e8..e76d91906c99 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -53,7 +53,7 @@ config SENSORS_ADM1021
config SENSORS_ADM1025
tristate "Analog Devices ADM1025 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select HWMON_VID
help
If you say yes here you get support for Analog Devices ADM1025
@@ -94,6 +94,18 @@ config SENSORS_ADM9240
This driver can also be built as a module. If so, the module
will be called adm9240.
+config SENSORS_K8TEMP
+ tristate "AMD Athlon64/FX or Opteron temperature sensor"
+ depends on HWMON && X86 && PCI && EXPERIMENTAL
+ help
+ If you say yes here you get support for the temperature
+ sensor(s) inside your CPU. Supported is whole AMD K8
+ microarchitecture. Please note that you will need at least
+ lm-sensors 2.10.1 for proper userspace support.
+
+ This driver can also be built as a module. If so, the module
+ will be called k8temp.
+
config SENSORS_ASB100
tristate "Asus ASB100 Bach"
depends on HWMON && I2C && EXPERIMENTAL
@@ -121,7 +133,7 @@ config SENSORS_ATXP1
config SENSORS_DS1621
tristate "Dallas Semiconductor DS1621 and DS1625"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for Dallas Semiconductor
DS1621 and DS1625 sensor chips.
@@ -141,7 +153,7 @@ config SENSORS_F71805F
config SENSORS_FSCHER
tristate "FSC Hermes"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Hermes sensor chips.
@@ -151,7 +163,7 @@ config SENSORS_FSCHER
config SENSORS_FSCPOS
tristate "FSC Poseidon"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for Fujitsu Siemens
Computers Poseidon sensor chips.
@@ -171,7 +183,7 @@ config SENSORS_GL518SM
config SENSORS_GL520SM
tristate "Genesys Logic GL520SM"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select HWMON_VID
help
If you say yes here you get support for Genesys Logic GL520SM
@@ -186,15 +198,15 @@ config SENSORS_IT87
select I2C_ISA
select HWMON_VID
help
- If you say yes here you get support for ITE IT87xx sensor chips
- and clones: SiS960.
+ If you say yes here you get support for ITE IT8705F, IT8712F,
+ IT8716F and IT8718F sensor chips, and the SiS960 clone.
This driver can also be built as a module. If so, the module
will be called it87.
config SENSORS_LM63
tristate "National Semiconductor LM63"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for the National Semiconductor
LM63 remote diode digital temperature sensor with integrated fan
@@ -231,7 +243,7 @@ config SENSORS_LM75
config SENSORS_LM77
tristate "National Semiconductor LM77"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for National Semiconductor LM77
sensor chips.
@@ -241,7 +253,7 @@ config SENSORS_LM77
config SENSORS_LM78
tristate "National Semiconductor LM78 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select I2C_ISA
select HWMON_VID
help
@@ -284,7 +296,7 @@ config SENSORS_LM85
config SENSORS_LM87
tristate "National Semiconductor LM87"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select HWMON_VID
help
If you say yes here you get support for National Semiconductor LM87
@@ -309,7 +321,7 @@ config SENSORS_LM90
config SENSORS_LM92
tristate "National Semiconductor LM92 and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for National Semiconductor LM92
and Maxim MAX6635 sensor chips.
@@ -319,7 +331,7 @@ config SENSORS_LM92
config SENSORS_MAX1619
tristate "Maxim MAX1619 sensor chip"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
help
If you say yes here you get support for MAX1619 sensor chip.
@@ -354,13 +366,13 @@ config SENSORS_SIS5595
config SENSORS_SMSC47M1
tristate "SMSC LPC47M10x and compatibles"
- depends on HWMON && I2C && EXPERIMENTAL
+ depends on HWMON && I2C
select I2C_ISA
help
If you say yes here you get support for the integrated fan
monitoring and control capabilities of the SMSC LPC47B27x,
- LPC47M10x, LPC47M13x, LPC47M14x, LPC47M15x, LPC47M192 and
- LPC47M997 chips.
+ LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x,
+ LPC47M192 and LPC47M997 chips.
The temperature and voltage sensor features of the LPC47M192
and LPC47M997 are supported by another driver, select also
@@ -407,8 +419,19 @@ config SENSORS_VIA686A
This driver can also be built as a module. If so, the module
will be called via686a.
+config SENSORS_VT1211
+ tristate "VIA VT1211"
+ depends on HWMON && EXPERIMENTAL
+ select HWMON_VID
+ help
+ If you say yes here then you get support for hardware monitoring
+ features of the VIA VT1211 Super-I/O chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called vt1211.
+
config SENSORS_VT8231
- tristate "VT8231"
+ tristate "VIA VT8231"
depends on HWMON && I2C && PCI && EXPERIMENTAL
select HWMON_VID
select I2C_ISA
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 31415843a91a..af01cc64f7d2 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
obj-$(CONFIG_SENSORS_HDAPS) += hdaps.o
obj-$(CONFIG_SENSORS_IT87) += it87.o
+obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o
obj-$(CONFIG_SENSORS_LM63) += lm63.o
obj-$(CONFIG_SENSORS_LM70) += lm70.o
obj-$(CONFIG_SENSORS_LM75) += lm75.o
@@ -45,6 +46,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
+obj-$(CONFIG_SENSORS_VT1211) += vt1211.o
obj-$(CONFIG_SENSORS_VT8231) += vt8231.o
obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
diff --git a/drivers/hwmon/abituguru.c b/drivers/hwmon/abituguru.c
index 35ad1b032726..e5cb0fdab9b1 100644
--- a/drivers/hwmon/abituguru.c
+++ b/drivers/hwmon/abituguru.c
@@ -1354,13 +1354,39 @@ LEAVE_UPDATE:
return NULL;
}
+#ifdef CONFIG_PM
+static int abituguru_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct abituguru_data *data = platform_get_drvdata(pdev);
+ /* make sure all communications with the uguru are done and no new
+ ones are started */
+ mutex_lock(&data->update_lock);
+ return 0;
+}
+
+static int abituguru_resume(struct platform_device *pdev)
+{
+ struct abituguru_data *data = platform_get_drvdata(pdev);
+ /* See if the uGuru is still ready */
+ if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT)
+ data->uguru_ready = 0;
+ mutex_unlock(&data->update_lock);
+ return 0;
+}
+#else
+#define abituguru_suspend NULL
+#define abituguru_resume NULL
+#endif /* CONFIG_PM */
+
static struct platform_driver abituguru_driver = {
.driver = {
.owner = THIS_MODULE,
.name = ABIT_UGURU_NAME,
},
- .probe = abituguru_probe,
- .remove = __devexit_p(abituguru_remove),
+ .probe = abituguru_probe,
+ .remove = __devexit_p(abituguru_remove),
+ .suspend = abituguru_suspend,
+ .resume = abituguru_resume,
};
static int __init abituguru_detect(void)
diff --git a/drivers/hwmon/adm1021.c b/drivers/hwmon/adm1021.c
index 2b6e74dd4a82..c466329b2ef4 100644
--- a/drivers/hwmon/adm1021.c
+++ b/drivers/hwmon/adm1021.c
@@ -190,6 +190,21 @@ static int adm1021_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1021_detect);
}
+static struct attribute *adm1021_attributes[] = {
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group adm1021_group = {
+ .attrs = adm1021_attributes,
+};
+
static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i;
@@ -287,22 +302,19 @@ static int adm1021_detect(struct i2c_adapter *adapter, int address, int kind)
adm1021_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1021_group)))
+ goto error2;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto error2;
+ goto error3;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+error3:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1021_group);
error2:
i2c_detach_client(new_client);
error1:
@@ -326,6 +338,7 @@ static int adm1021_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1021_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/adm1025.c b/drivers/hwmon/adm1025.c
index a4c859c9fbf8..8c562885b54b 100644
--- a/drivers/hwmon/adm1025.c
+++ b/drivers/hwmon/adm1025.c
@@ -315,6 +315,49 @@ static int adm1025_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1025_detect);
}
+static struct attribute *adm1025_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ NULL
+};
+
+static const struct attribute_group adm1025_group = {
+ .attrs = adm1025_attributes,
+};
+
+static struct attribute *adm1025_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ NULL
+};
+
+static const struct attribute_group adm1025_group_opt = {
+ .attrs = adm1025_attributes_opt,
+};
+
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
@@ -415,46 +458,31 @@ static int adm1025_detect(struct i2c_adapter *adapter, int address, int kind)
adm1025_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1025_group)))
goto exit_detach;
- }
-
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_vrm);
/* Pin 11 is either in4 (+12V) or VID4 */
if (!(config & 0x20)) {
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto exit_remove;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
}
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1025_group);
+ sysfs_remove_group(&new_client->dev.kobj, &adm1025_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -511,6 +539,8 @@ static int adm1025_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1025_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1025_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/adm1026.c b/drivers/hwmon/adm1026.c
index 6d4f8b8d358e..b4618b2705f7 100644
--- a/drivers/hwmon/adm1026.c
+++ b/drivers/hwmon/adm1026.c
@@ -323,15 +323,6 @@ static int adm1026_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1026_detect);
}
-static int adm1026_detach_client(struct i2c_client *client)
-{
- struct adm1026_data *data = i2c_get_clientdata(client);
- hwmon_device_unregister(data->class_dev);
- i2c_detach_client(client);
- kfree(data);
- return 0;
-}
-
static int adm1026_read_value(struct i2c_client *client, u8 reg)
{
int res;
@@ -1450,6 +1441,135 @@ static DEVICE_ATTR(temp1_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
static DEVICE_ATTR(temp2_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
static DEVICE_ATTR(temp3_auto_point2_pwm, S_IRUGO, show_auto_pwm_max, NULL);
+static struct attribute *adm1026_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_in9_input.dev_attr.attr,
+ &sensor_dev_attr_in9_max.dev_attr.attr,
+ &sensor_dev_attr_in9_min.dev_attr.attr,
+ &sensor_dev_attr_in10_input.dev_attr.attr,
+ &sensor_dev_attr_in10_max.dev_attr.attr,
+ &sensor_dev_attr_in10_min.dev_attr.attr,
+ &sensor_dev_attr_in11_input.dev_attr.attr,
+ &sensor_dev_attr_in11_max.dev_attr.attr,
+ &sensor_dev_attr_in11_min.dev_attr.attr,
+ &sensor_dev_attr_in12_input.dev_attr.attr,
+ &sensor_dev_attr_in12_max.dev_attr.attr,
+ &sensor_dev_attr_in12_min.dev_attr.attr,
+ &sensor_dev_attr_in13_input.dev_attr.attr,
+ &sensor_dev_attr_in13_max.dev_attr.attr,
+ &sensor_dev_attr_in13_min.dev_attr.attr,
+ &sensor_dev_attr_in14_input.dev_attr.attr,
+ &sensor_dev_attr_in14_max.dev_attr.attr,
+ &sensor_dev_attr_in14_min.dev_attr.attr,
+ &sensor_dev_attr_in15_input.dev_attr.attr,
+ &sensor_dev_attr_in15_max.dev_attr.attr,
+ &sensor_dev_attr_in15_min.dev_attr.attr,
+ &sensor_dev_attr_in16_input.dev_attr.attr,
+ &sensor_dev_attr_in16_max.dev_attr.attr,
+ &sensor_dev_attr_in16_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_div.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_div.dev_attr.attr,
+ &sensor_dev_attr_fan5_min.dev_attr.attr,
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_div.dev_attr.attr,
+ &sensor_dev_attr_fan6_min.dev_attr.attr,
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_div.dev_attr.attr,
+ &sensor_dev_attr_fan7_min.dev_attr.attr,
+ &sensor_dev_attr_fan8_input.dev_attr.attr,
+ &sensor_dev_attr_fan8_div.dev_attr.attr,
+ &sensor_dev_attr_fan8_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_offset.dev_attr.attr,
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &dev_attr_temp1_crit_enable.attr,
+ &dev_attr_temp2_crit_enable.attr,
+ &dev_attr_temp3_crit_enable.attr,
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_alarm_mask.attr,
+ &dev_attr_gpio.attr,
+ &dev_attr_gpio_mask.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm3.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm2_enable.attr,
+ &dev_attr_pwm3_enable.attr,
+ &dev_attr_temp1_auto_point1_pwm.attr,
+ &dev_attr_temp2_auto_point1_pwm.attr,
+ &dev_attr_temp3_auto_point1_pwm.attr,
+ &dev_attr_temp1_auto_point2_pwm.attr,
+ &dev_attr_temp2_auto_point2_pwm.attr,
+ &dev_attr_temp3_auto_point2_pwm.attr,
+ &dev_attr_analog_out.attr,
+ NULL
+};
+
+static const struct attribute_group adm1026_group = {
+ .attrs = adm1026_attributes,
+};
+
static int adm1026_detect(struct i2c_adapter *adapter, int address,
int kind)
{
@@ -1554,145 +1674,20 @@ static int adm1026_detect(struct i2c_adapter *adapter, int address,
adm1026_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1026_group)))
+ goto exitdetach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exitdetach;
+ goto exitremove;
}
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in9_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in9_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in9_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in10_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in10_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in10_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in11_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in11_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in11_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in12_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in12_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in12_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in13_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in13_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in13_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in14_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in14_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in14_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in15_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in15_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in15_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in16_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in16_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in16_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan4_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan5_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan6_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan7_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan8_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_offset.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_offset.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_offset.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_auto_point1_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_auto_point1_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_auto_point1_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_auto_point1_temp_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_auto_point1_temp_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_auto_point1_temp_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_auto_point2_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_auto_point2_temp.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_auto_point2_temp.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_crit.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_crit.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_enable);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit_enable);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit_enable);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_vrm);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_alarm_mask);
- device_create_file(&new_client->dev, &dev_attr_gpio);
- device_create_file(&new_client->dev, &dev_attr_gpio_mask);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_pwm3);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_point1_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_point1_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_point1_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_point2_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_point2_pwm);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_point2_pwm);
- device_create_file(&new_client->dev, &dev_attr_analog_out);
return 0;
/* Error out and cleanup code */
+exitremove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1026_group);
exitdetach:
i2c_detach_client(new_client);
exitfree:
@@ -1700,6 +1695,17 @@ exitfree:
exit:
return err;
}
+
+static int adm1026_detach_client(struct i2c_client *client)
+{
+ struct adm1026_data *data = i2c_get_clientdata(client);
+ hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1026_group);
+ i2c_detach_client(client);
+ kfree(data);
+ return 0;
+}
+
static int __init sm_adm1026_init(void)
{
return i2c_add_driver(&adm1026_driver);
diff --git a/drivers/hwmon/adm1031.c b/drivers/hwmon/adm1031.c
index 3bf2da621aed..122683fc91d0 100644
--- a/drivers/hwmon/adm1031.c
+++ b/drivers/hwmon/adm1031.c
@@ -730,6 +730,61 @@ static int adm1031_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, adm1031_detect);
}
+static struct attribute *adm1031_attributes[] = {
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_auto_fan1_channel.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_crit.attr,
+
+ &dev_attr_auto_temp1_off.attr,
+ &dev_attr_auto_temp1_min.attr,
+ &dev_attr_auto_temp1_max.attr,
+
+ &dev_attr_auto_temp2_off.attr,
+ &dev_attr_auto_temp2_min.attr,
+ &dev_attr_auto_temp2_max.attr,
+
+ &dev_attr_auto_fan1_min_pwm.attr,
+
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group adm1031_group = {
+ .attrs = adm1031_attributes,
+};
+
+static struct attribute *adm1031_attributes_opt[] = {
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_auto_fan2_channel.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_min.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_crit.attr,
+ &dev_attr_auto_temp3_off.attr,
+ &dev_attr_auto_temp3_min.attr,
+ &dev_attr_auto_temp3_max.attr,
+ &dev_attr_auto_fan2_min_pwm.attr,
+ NULL
+};
+
+static const struct attribute_group adm1031_group_opt = {
+ .attrs = adm1031_attributes_opt,
+};
+
/* This function is called by i2c_probe */
static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -789,57 +844,26 @@ static int adm1031_detect(struct i2c_adapter *adapter, int address, int kind)
adm1031_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm1031_group)))
goto exit_detach;
- }
-
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_auto_fan1_channel);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
-
- device_create_file(&new_client->dev, &dev_attr_auto_temp1_off);
- device_create_file(&new_client->dev, &dev_attr_auto_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_auto_temp1_max);
-
- device_create_file(&new_client->dev, &dev_attr_auto_temp2_off);
- device_create_file(&new_client->dev, &dev_attr_auto_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_auto_temp2_max);
-
- device_create_file(&new_client->dev, &dev_attr_auto_fan1_min_pwm);
-
- device_create_file(&new_client->dev, &dev_attr_alarms);
if (kind == adm1031) {
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev,
- &dev_attr_auto_fan2_channel);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
- device_create_file(&new_client->dev, &dev_attr_auto_temp3_off);
- device_create_file(&new_client->dev, &dev_attr_auto_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_auto_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_auto_fan2_min_pwm);
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &adm1031_group_opt)))
+ goto exit_remove;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
}
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm1031_group);
+ sysfs_remove_group(&new_client->dev.kobj, &adm1031_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -854,6 +878,8 @@ static int adm1031_detach_client(struct i2c_client *client)
int ret;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm1031_group);
+ sysfs_remove_group(&client->dev.kobj, &adm1031_group_opt);
if ((ret = i2c_detach_client(client)) != 0) {
return ret;
}
diff --git a/drivers/hwmon/adm9240.c b/drivers/hwmon/adm9240.c
index 43f6991b588c..aad594adf0c7 100644
--- a/drivers/hwmon/adm9240.c
+++ b/drivers/hwmon/adm9240.c
@@ -5,7 +5,7 @@
* Copyright (C) 1999 Frodo Looijaard <frodol@dds.nl>
* Philip Edelbrock <phil@netroedge.com>
* Copyright (C) 2003 Michiel Rook <michiel@grendelproject.nl>
- * Copyright (C) 2005 Grant Coady <gcoady@gmail.com> with valuable
+ * Copyright (C) 2005 Grant Coady <gcoady.lk@gmail.com> with valuable
* guidance from Jean Delvare
*
* Driver supports Analog Devices ADM9240
@@ -465,6 +465,45 @@ static ssize_t chassis_clear(struct device *dev,
}
static DEVICE_ATTR(chassis_clear, S_IWUSR, NULL, chassis_clear);
+static struct attribute *adm9240_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &dev_attr_temp1_input.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_aout_output.attr,
+ &dev_attr_chassis_clear.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group adm9240_group = {
+ .attrs = adm9240_attributes,
+};
+
/*** sensor chip detect and driver install ***/
@@ -548,72 +587,19 @@ static int adm9240_detect(struct i2c_adapter *adapter, int address, int kind)
adm9240_init_client(new_client);
/* populate sysfs filesystem */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &adm9240_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan2_div.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_aout_output);
- device_create_file(&new_client->dev, &dev_attr_chassis_clear);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
-
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &adm9240_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -635,6 +621,7 @@ static int adm9240_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &adm9240_group);
if ((err = i2c_detach_client(client)))
return err;
@@ -787,7 +774,7 @@ static void __exit sensors_adm9240_exit(void)
}
MODULE_AUTHOR("Michiel Rook <michiel@grendelproject.nl>, "
- "Grant Coady <gcoady@gmail.com> and others");
+ "Grant Coady <gcoady.lk@gmail.com> and others");
MODULE_DESCRIPTION("ADM9240/DS1780/LM81 driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/asb100.c b/drivers/hwmon/asb100.c
index facc1ccb8338..57b1c7b7ac3f 100644
--- a/drivers/hwmon/asb100.c
+++ b/drivers/hwmon/asb100.c
@@ -298,12 +298,6 @@ sysfs_in(4);
sysfs_in(5);
sysfs_in(6);
-#define device_create_file_in(client, offset) do { \
- device_create_file(&client->dev, &dev_attr_in##offset##_input); \
- device_create_file(&client->dev, &dev_attr_in##offset##_min); \
- device_create_file(&client->dev, &dev_attr_in##offset##_max); \
-} while (0)
-
/* 3 Fans */
static ssize_t show_fan(struct device *dev, char *buf, int nr)
{
@@ -421,12 +415,6 @@ sysfs_fan(1);
sysfs_fan(2);
sysfs_fan(3);
-#define device_create_file_fan(client, offset) do { \
- device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
-} while (0)
-
/* 4 Temp. Sensors */
static int sprintf_temp_from_reg(u16 reg, char *buf, int nr)
{
@@ -515,12 +503,6 @@ sysfs_temp(3);
sysfs_temp(4);
/* VID */
-#define device_create_file_temp(client, num) do { \
- device_create_file(&client->dev, &dev_attr_temp##num##_input); \
- device_create_file(&client->dev, &dev_attr_temp##num##_max); \
- device_create_file(&client->dev, &dev_attr_temp##num##_max_hyst); \
-} while (0)
-
static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct asb100_data *data = asb100_update_device(dev);
@@ -528,8 +510,6 @@ static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid)
/* VRM */
static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
@@ -549,8 +529,6 @@ static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const
/* Alarms */
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm);
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -559,8 +537,6 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms)
/* 1 PWM */
static ssize_t show_pwm1(struct device *dev, struct device_attribute *attr, char *buf)
@@ -607,10 +583,65 @@ static ssize_t set_pwm_enable1(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, show_pwm1, set_pwm1);
static DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
show_pwm_enable1, set_pwm_enable1);
-#define device_create_file_pwm1(client) do { \
- device_create_file(&new_client->dev, &dev_attr_pwm1); \
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable); \
-} while (0)
+
+static struct attribute *asb100_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan3_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_max_hyst.attr,
+ &dev_attr_temp4_input.attr,
+ &dev_attr_temp4_max.attr,
+ &dev_attr_temp4_max_hyst.attr,
+
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
+
+ NULL
+};
+
+static const struct attribute_group asb100_group = {
+ .attrs = asb100_attributes,
+};
/* This function is called when:
asb100_driver is inserted (when this module is loaded), for each
@@ -810,38 +841,19 @@ static int asb100_detect(struct i2c_adapter *adapter, int address, int kind)
data->fan_min[2] = asb100_read_value(new_client, ASB100_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &asb100_group)))
+ goto ERROR3;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto ERROR3;
+ goto ERROR4;
}
- device_create_file_in(new_client, 0);
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- device_create_file_in(new_client, 4);
- device_create_file_in(new_client, 5);
- device_create_file_in(new_client, 6);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- device_create_file_temp(new_client, 3);
- device_create_file_temp(new_client, 4);
-
- device_create_file_vid(new_client);
- device_create_file_vrm(new_client);
-
- device_create_file_alarms(new_client);
-
- device_create_file_pwm1(new_client);
-
return 0;
+ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &asb100_group);
ERROR3:
i2c_detach_client(data->lm75[1]);
i2c_detach_client(data->lm75[0]);
@@ -861,8 +873,10 @@ static int asb100_detach_client(struct i2c_client *client)
int err;
/* main client */
- if (data)
+ if (data) {
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &asb100_group);
+ }
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/atxp1.c b/drivers/hwmon/atxp1.c
index 728a1e8b9190..0ccdd0750c44 100644
--- a/drivers/hwmon/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -27,6 +27,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
@@ -116,8 +117,7 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
{
struct atxp1_data *data;
struct i2c_client *client;
- char vid;
- char cvid;
+ int vid, cvid;
unsigned int vcore;
client = to_i2c_client(dev);
@@ -251,6 +251,17 @@ static ssize_t atxp1_storegpio2(struct device *dev, struct device_attribute *att
*/
static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
+static struct attribute *atxp1_attributes[] = {
+ &dev_attr_gpio1.attr,
+ &dev_attr_gpio2.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group atxp1_group = {
+ .attrs = atxp1_attributes,
+};
+
static int atxp1_attach_adapter(struct i2c_adapter *adapter)
{
@@ -320,21 +331,23 @@ static int atxp1_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_free;
}
+ /* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_gpio1);
- device_create_file(&new_client->dev, &dev_attr_gpio2);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
-
dev_info(&new_client->dev, "Using VRM: %d.%d\n",
data->vrm / 10, data->vrm % 10);
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -349,6 +362,7 @@ static int atxp1_detach_client(struct i2c_client * client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &atxp1_group);
err = i2c_detach_client(client);
diff --git a/drivers/hwmon/ds1621.c b/drivers/hwmon/ds1621.c
index 478eb4bb8570..c849c0c6ee9c 100644
--- a/drivers/hwmon/ds1621.c
+++ b/drivers/hwmon/ds1621.c
@@ -29,6 +29,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include "lm75.h"
/* Addresses to scan */
@@ -178,6 +179,18 @@ static DEVICE_ATTR(temp1_input, S_IRUGO , show_temp, NULL);
static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO , show_temp_min, set_temp_min);
static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static struct attribute *ds1621_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group ds1621_group = {
+ .attrs = ds1621_attributes,
+};
+
static int ds1621_attach_adapter(struct i2c_adapter *adapter)
{
@@ -253,21 +266,19 @@ static int ds1621_detect(struct i2c_adapter *adapter, int address,
ds1621_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &ds1621_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
-
return 0;
-/* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
+ exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &ds1621_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -282,6 +293,7 @@ static int ds1621_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &ds1621_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/f71805f.c b/drivers/hwmon/f71805f.c
index fd72440faf76..de17a72149d9 100644
--- a/drivers/hwmon/f71805f.c
+++ b/drivers/hwmon/f71805f.c
@@ -1,7 +1,7 @@
/*
* f71805f.c - driver for the Fintek F71805F/FG Super-I/O chip integrated
* hardware monitoring features
- * Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.org>
*
* The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates
* complete hardware monitoring features: voltage, fan and temperature
@@ -31,6 +31,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
static struct platform_device *pdev;
@@ -147,7 +148,7 @@ struct f71805f_data {
u8 temp_high[3];
u8 temp_hyst[3];
u8 temp_mode;
- u8 alarms[3];
+ unsigned long alarms;
};
static inline long in_from_reg(u8 reg)
@@ -311,10 +312,9 @@ static struct f71805f_data *f71805f_update_device(struct device *dev)
data->temp[nr] = f71805f_read8(data,
F71805F_REG_TEMP(nr));
}
- for (nr = 0; nr < 3; nr++) {
- data->alarms[nr] = f71805f_read8(data,
- F71805F_REG_STATUS(nr));
- }
+ data->alarms = f71805f_read8(data, F71805F_REG_STATUS(0))
+ + (f71805f_read8(data, F71805F_REG_STATUS(1)) << 8)
+ + (f71805f_read8(data, F71805F_REG_STATUS(2)) << 16);
data->last_updated = jiffies;
data->valid = 1;
@@ -557,8 +557,7 @@ static ssize_t show_alarms_in(struct device *dev, struct device_attribute
{
struct f71805f_data *data = f71805f_update_device(dev);
- return sprintf(buf, "%d\n", data->alarms[0] |
- ((data->alarms[1] & 0x01) << 8));
+ return sprintf(buf, "%lu\n", data->alarms & 0x1ff);
}
static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
@@ -566,7 +565,7 @@ static ssize_t show_alarms_fan(struct device *dev, struct device_attribute
{
struct f71805f_data *data = f71805f_update_device(dev);
- return sprintf(buf, "%d\n", data->alarms[2] & 0x07);
+ return sprintf(buf, "%lu\n", (data->alarms >> 16) & 0x07);
}
static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
@@ -574,7 +573,17 @@ static ssize_t show_alarms_temp(struct device *dev, struct device_attribute
{
struct f71805f_data *data = f71805f_update_device(dev);
- return sprintf(buf, "%d\n", (data->alarms[1] >> 3) & 0x07);
+ return sprintf(buf, "%lu\n", (data->alarms >> 11) & 0x07);
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct f71805f_data *data = f71805f_update_device(dev);
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%lu\n", (data->alarms >> bitnr) & 1);
}
static ssize_t show_name(struct device *dev, struct device_attribute
@@ -585,88 +594,189 @@ static ssize_t show_name(struct device *dev, struct device_attribute
return sprintf(buf, "%s\n", data->name);
}
-static struct device_attribute f71805f_dev_attr[] = {
- __ATTR(in0_input, S_IRUGO, show_in0, NULL),
- __ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max),
- __ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min),
- __ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL),
- __ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL),
- __ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL),
- __ATTR(name, S_IRUGO, show_name, NULL),
+static DEVICE_ATTR(in0_input, S_IRUGO, show_in0, NULL);
+static DEVICE_ATTR(in0_max, S_IRUGO| S_IWUSR, show_in0_max, set_in0_max);
+static DEVICE_ATTR(in0_min, S_IRUGO| S_IWUSR, show_in0_min, set_in0_min);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in1_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 1);
+static SENSOR_DEVICE_ATTR(in1_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in2_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 2);
+static SENSOR_DEVICE_ATTR(in2_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in3_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 3);
+static SENSOR_DEVICE_ATTR(in3_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in4_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 4);
+static SENSOR_DEVICE_ATTR(in4_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in5_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 5);
+static SENSOR_DEVICE_ATTR(in5_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in6_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 6);
+static SENSOR_DEVICE_ATTR(in6_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in7_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 7);
+static SENSOR_DEVICE_ATTR(in7_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in8_max, S_IRUGO | S_IWUSR,
+ show_in_max, set_in_max, 8);
+static SENSOR_DEVICE_ATTR(in8_min, S_IRUGO | S_IWUSR,
+ show_in_min, set_in_min, 8);
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR,
+ show_fan_min, set_fan_min, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IRUGO | S_IWUSR,
+ show_fan_min, set_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IRUGO | S_IWUSR,
+ show_fan_min, set_fan_min, 2);
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR,
+ show_temp_max, set_temp_max, 0);
+static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp_hyst, set_temp_hyst, 0);
+static SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR,
+ show_temp_max, set_temp_max, 1);
+static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp_hyst, set_temp_hyst, 1);
+static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO | S_IWUSR,
+ show_temp_max, set_temp_max, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp_hyst, set_temp_hyst, 2);
+static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2);
+
+static SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 11);
+static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 16);
+static SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 17);
+static SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 18);
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_alarms_in, NULL);
+static DEVICE_ATTR(alarms_fan, S_IRUGO, show_alarms_fan, NULL);
+static DEVICE_ATTR(alarms_temp, S_IRUGO, show_alarms_temp, NULL);
+
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct attribute *f71805f_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in0_min.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp1_type.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
+
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+ &sensor_dev_attr_in8_alarm.dev_attr.attr,
+ &dev_attr_alarms_in.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &dev_attr_alarms_temp.attr,
+ &dev_attr_alarms_fan.attr,
+
+ &dev_attr_name.attr,
+ NULL
};
-static struct sensor_device_attribute f71805f_sensor_attr[] = {
- SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
- SENSOR_ATTR(in1_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 1),
- SENSOR_ATTR(in1_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 1),
- SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
- SENSOR_ATTR(in2_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 2),
- SENSOR_ATTR(in2_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 2),
- SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
- SENSOR_ATTR(in3_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 3),
- SENSOR_ATTR(in3_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 3),
- SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
- SENSOR_ATTR(in4_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 4),
- SENSOR_ATTR(in4_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 4),
- SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
- SENSOR_ATTR(in5_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 5),
- SENSOR_ATTR(in5_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 5),
- SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
- SENSOR_ATTR(in6_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 6),
- SENSOR_ATTR(in6_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 6),
- SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
- SENSOR_ATTR(in7_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 7),
- SENSOR_ATTR(in7_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 7),
- SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
- SENSOR_ATTR(in8_max, S_IRUGO | S_IWUSR,
- show_in_max, set_in_max, 8),
- SENSOR_ATTR(in8_min, S_IRUGO | S_IWUSR,
- show_in_min, set_in_min, 8),
-
- SENSOR_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0),
- SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR,
- show_temp_max, set_temp_max, 0),
- SENSOR_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR,
- show_temp_hyst, set_temp_hyst, 0),
- SENSOR_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0),
- SENSOR_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1),
- SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR,
- show_temp_max, set_temp_max, 1),
- SENSOR_ATTR(temp2_max_hyst, S_IRUGO | S_IWUSR,
- show_temp_hyst, set_temp_hyst, 1),
- SENSOR_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1),
- SENSOR_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2),
- SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR,
- show_temp_max, set_temp_max, 2),
- SENSOR_ATTR(temp3_max_hyst, S_IRUGO | S_IWUSR,
- show_temp_hyst, set_temp_hyst, 2),
- SENSOR_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2),
+static const struct attribute_group f71805f_group = {
+ .attrs = f71805f_attributes,
};
-static struct sensor_device_attribute f71805f_fan_attr[] = {
- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0),
- SENSOR_ATTR(fan1_min, S_IRUGO | S_IWUSR,
- show_fan_min, set_fan_min, 0),
- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1),
- SENSOR_ATTR(fan2_min, S_IRUGO | S_IWUSR,
- show_fan_min, set_fan_min, 1),
- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2),
- SENSOR_ATTR(fan3_min, S_IRUGO | S_IWUSR,
- show_fan_min, set_fan_min, 2),
+static struct attribute *f71805f_attributes_fan[3][4] = {
+ {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group f71805f_group_fan[3] = {
+ { .attrs = f71805f_attributes_fan[0] },
+ { .attrs = f71805f_attributes_fan[1] },
+ { .attrs = f71805f_attributes_fan[2] },
};
/*
@@ -714,43 +824,35 @@ static int __devinit f71805f_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- data->class_dev = hwmon_device_register(&pdev->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
- goto exit_free;
- }
-
/* Initialize the F71805F chip */
f71805f_init_device(data);
/* Register sysfs interface files */
- for (i = 0; i < ARRAY_SIZE(f71805f_dev_attr); i++) {
- err = device_create_file(&pdev->dev, &f71805f_dev_attr[i]);
- if (err)
- goto exit_class;
- }
- for (i = 0; i < ARRAY_SIZE(f71805f_sensor_attr); i++) {
- err = device_create_file(&pdev->dev,
- &f71805f_sensor_attr[i].dev_attr);
- if (err)
- goto exit_class;
- }
- for (i = 0; i < ARRAY_SIZE(f71805f_fan_attr); i++) {
- if (!(data->fan_enabled & (1 << (i / 2))))
+ if ((err = sysfs_create_group(&pdev->dev.kobj, &f71805f_group)))
+ goto exit_free;
+ for (i = 0; i < 3; i++) {
+ if (!(data->fan_enabled & (1 << i)))
continue;
- err = device_create_file(&pdev->dev,
- &f71805f_fan_attr[i].dev_attr);
- if (err)
- goto exit_class;
+ if ((err = sysfs_create_group(&pdev->dev.kobj,
+ &f71805f_group_fan[i])))
+ goto exit_remove_files;
+ }
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ dev_err(&pdev->dev, "Class registration failed (%d)\n", err);
+ goto exit_remove_files;
}
return 0;
-exit_class:
- dev_err(&pdev->dev, "Sysfs interface creation failed\n");
- hwmon_device_unregister(data->class_dev);
+exit_remove_files:
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
+ for (i = 0; i < 3; i++)
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
exit_free:
+ platform_set_drvdata(pdev, NULL);
kfree(data);
exit:
return err;
@@ -759,9 +861,13 @@ exit:
static int __devexit f71805f_remove(struct platform_device *pdev)
{
struct f71805f_data *data = platform_get_drvdata(pdev);
+ int i;
platform_set_drvdata(pdev, NULL);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group);
+ for (i = 0; i < 3; i++)
+ sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_fan[i]);
kfree(data);
return 0;
diff --git a/drivers/hwmon/fscher.c b/drivers/hwmon/fscher.c
index 6bc76b407636..19717752cfca 100644
--- a/drivers/hwmon/fscher.c
+++ b/drivers/hwmon/fscher.c
@@ -34,6 +34,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -240,47 +241,45 @@ sysfs_alarms(FSCHER_REG_EVENTS)
sysfs_control(FSCHER_REG_CONTROL)
sysfs_watchdog(FSCHER_REG_WDOG_CONTROL, FSCHER_REG_WDOG_STATE, FSCHER_REG_WDOG_PRESET)
-#define device_create_file_fan(client, offset) \
-do { \
- device_create_file(&client->dev, &dev_attr_fan##offset##_status); \
- device_create_file(&client->dev, &dev_attr_pwm##offset); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
- device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
-} while (0)
-
-#define device_create_file_temp(client, offset) \
-do { \
- device_create_file(&client->dev, &dev_attr_temp##offset##_status); \
- device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
-} while (0)
-
-#define device_create_file_in(client, offset) \
-do { \
- device_create_file(&client->dev, &dev_attr_in##offset##_input); \
-} while (0)
-
-#define device_create_file_revision(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_revision); \
-} while (0)
-
-#define device_create_file_alarms(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_alarms); \
-} while (0)
-
-#define device_create_file_control(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_control); \
-} while (0)
-
-#define device_create_file_watchdog(client) \
-do { \
- device_create_file(&client->dev, &dev_attr_watchdog_status); \
- device_create_file(&client->dev, &dev_attr_watchdog_control); \
- device_create_file(&client->dev, &dev_attr_watchdog_preset); \
-} while (0)
-
+static struct attribute *fscher_attributes[] = {
+ &dev_attr_revision.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_control.attr,
+
+ &dev_attr_watchdog_status.attr,
+ &dev_attr_watchdog_control.attr,
+ &dev_attr_watchdog_preset.attr,
+
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+
+ &dev_attr_fan1_status.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_fan2_status.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_fan3_status.attr,
+ &dev_attr_fan3_div.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_pwm3.attr,
+
+ &dev_attr_temp1_status.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_status.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_status.attr,
+ &dev_attr_temp3_input.attr,
+ NULL
+};
+
+static const struct attribute_group fscher_group = {
+ .attrs = fscher_attributes,
+};
+
/*
* Real code
*/
@@ -342,31 +341,19 @@ static int fscher_detect(struct i2c_adapter *adapter, int address, int kind)
fscher_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &fscher_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file_revision(new_client);
- device_create_file_alarms(new_client);
- device_create_file_control(new_client);
- device_create_file_watchdog(new_client);
-
- device_create_file_in(new_client, 0);
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- device_create_file_temp(new_client, 3);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &fscher_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -381,6 +368,7 @@ static int fscher_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &fscher_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/fscpos.c b/drivers/hwmon/fscpos.c
index 6dc4846b9eeb..ea506a77f9c9 100644
--- a/drivers/hwmon/fscpos.c
+++ b/drivers/hwmon/fscpos.c
@@ -38,6 +38,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -432,6 +433,44 @@ static DEVICE_ATTR(in0_input, S_IRUGO, show_volt_12, NULL);
static DEVICE_ATTR(in1_input, S_IRUGO, show_volt_5, NULL);
static DEVICE_ATTR(in2_input, S_IRUGO, show_volt_batt, NULL);
+static struct attribute *fscpos_attributes[] = {
+ &dev_attr_event.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+
+ &dev_attr_wdog_control.attr,
+ &dev_attr_wdog_preset.attr,
+ &dev_attr_wdog_state.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_status.attr,
+ &dev_attr_temp1_reset.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_status.attr,
+ &dev_attr_temp2_reset.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_status.attr,
+ &dev_attr_temp3_reset.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_status.attr,
+ &dev_attr_fan1_ripple.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_status.attr,
+ &dev_attr_fan2_ripple.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_status.attr,
+ &dev_attr_fan3_ripple.attr,
+ NULL
+};
+
+static const struct attribute_group fscpos_group = {
+ .attrs = fscpos_attributes,
+};
+
static int fscpos_attach_adapter(struct i2c_adapter *adapter)
{
if (!(adapter->class & I2C_CLASS_HWMON))
@@ -497,42 +536,19 @@ static int fscpos_detect(struct i2c_adapter *adapter, int address, int kind)
dev_info(&new_client->dev, "Found fscpos chip, rev %u\n", data->revision);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &fscpos_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_event);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_wdog_control);
- device_create_file(&new_client->dev, &dev_attr_wdog_preset);
- device_create_file(&new_client->dev, &dev_attr_wdog_state);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_status);
- device_create_file(&new_client->dev, &dev_attr_temp1_reset);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_status);
- device_create_file(&new_client->dev, &dev_attr_temp2_reset);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_status);
- device_create_file(&new_client->dev, &dev_attr_temp3_reset);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_status);
- device_create_file(&new_client->dev, &dev_attr_fan1_ripple);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_status);
- device_create_file(&new_client->dev, &dev_attr_fan2_ripple);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_fan3_input);
- device_create_file(&new_client->dev, &dev_attr_fan3_status);
- device_create_file(&new_client->dev, &dev_attr_fan3_ripple);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &fscpos_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -547,6 +563,7 @@ static int fscpos_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &fscpos_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/gl518sm.c b/drivers/hwmon/gl518sm.c
index 6606aabdb49d..c103640455a3 100644
--- a/drivers/hwmon/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
@@ -44,6 +44,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -340,6 +341,42 @@ static DEVICE_ATTR(beep_enable, S_IWUSR|S_IRUGO,
static DEVICE_ATTR(beep_mask, S_IWUSR|S_IRUGO,
show_beep_mask, set_beep_mask);
+static struct attribute *gl518_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+
+ &dev_attr_fan1_auto.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+ NULL
+};
+
+static const struct attribute_group gl518_group = {
+ .attrs = gl518_attributes,
+};
+
/*
* Real code
*/
@@ -420,43 +457,19 @@ static int gl518_detect(struct i2c_adapter *adapter, int address, int kind)
gl518_init_client((struct i2c_client *) new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &gl518_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_fan1_auto);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_beep_enable);
- device_create_file(&new_client->dev, &dev_attr_beep_mask);
-
return 0;
-/* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
-
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &gl518_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -490,6 +503,7 @@ static int gl518_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &gl518_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/gl520sm.c b/drivers/hwmon/gl520sm.c
index 14e810f3c2c0..ebe7b9aaa916 100644
--- a/drivers/hwmon/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
@@ -30,6 +30,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/* Type of the extra sensor */
static unsigned short extra_sensor_type;
@@ -190,55 +191,29 @@ static DEVICE_ATTR(type##item, S_IRUGO, get_##type##0##item, NULL);
#define sysfs_vid(n) \
sysfs_ro_n(cpu, n, _vid, GL520_REG_VID_INPUT)
-#define device_create_file_vid(client, n) \
-device_create_file(&client->dev, &dev_attr_cpu##n##_vid)
-
#define sysfs_in(n) \
sysfs_ro_n(in, n, _input, GL520_REG_IN##n##INPUT) \
sysfs_rw_n(in, n, _min, GL520_REG_IN##n##_MIN) \
sysfs_rw_n(in, n, _max, GL520_REG_IN##n##_MAX) \
-#define device_create_file_in(client, n) \
-({device_create_file(&client->dev, &dev_attr_in##n##_input); \
-device_create_file(&client->dev, &dev_attr_in##n##_min); \
-device_create_file(&client->dev, &dev_attr_in##n##_max);})
-
#define sysfs_fan(n) \
sysfs_ro_n(fan, n, _input, GL520_REG_FAN_INPUT) \
sysfs_rw_n(fan, n, _min, GL520_REG_FAN_MIN) \
sysfs_rw_n(fan, n, _div, GL520_REG_FAN_DIV)
-#define device_create_file_fan(client, n) \
-({device_create_file(&client->dev, &dev_attr_fan##n##_input); \
-device_create_file(&client->dev, &dev_attr_fan##n##_min); \
-device_create_file(&client->dev, &dev_attr_fan##n##_div);})
-
#define sysfs_fan_off(n) \
sysfs_rw_n(fan, n, _off, GL520_REG_FAN_OFF) \
-#define device_create_file_fan_off(client, n) \
-device_create_file(&client->dev, &dev_attr_fan##n##_off)
-
#define sysfs_temp(n) \
sysfs_ro_n(temp, n, _input, GL520_REG_TEMP##n##_INPUT) \
sysfs_rw_n(temp, n, _max, GL520_REG_TEMP##n##_MAX) \
sysfs_rw_n(temp, n, _max_hyst, GL520_REG_TEMP##n##_MAX_HYST)
-#define device_create_file_temp(client, n) \
-({device_create_file(&client->dev, &dev_attr_temp##n##_input); \
-device_create_file(&client->dev, &dev_attr_temp##n##_max); \
-device_create_file(&client->dev, &dev_attr_temp##n##_max_hyst);})
-
#define sysfs_alarms() \
sysfs_ro(alarms, , GL520_REG_ALARMS) \
sysfs_rw(beep_enable, , GL520_REG_BEEP_ENABLE) \
sysfs_rw(beep_mask, , GL520_REG_BEEP_MASK)
-#define device_create_file_alarms(client) \
-({device_create_file(&client->dev, &dev_attr_alarms); \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask);})
-
sysfs_vid(0)
@@ -511,6 +486,59 @@ static ssize_t set_beep_mask(struct i2c_client *client, struct gl520_data *data,
return count;
}
+static struct attribute *gl520_attributes[] = {
+ &dev_attr_cpu0_vid.attr,
+
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan1_off.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+ NULL
+};
+
+static const struct attribute_group gl520_group = {
+ .attrs = gl520_attributes,
+};
+
+static struct attribute *gl520_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ NULL
+};
+
+static const struct attribute_group gl520_group_opt = {
+ .attrs = gl520_attributes_opt,
+};
+
/*
* Real code
@@ -572,33 +600,39 @@ static int gl520_detect(struct i2c_adapter *adapter, int address, int kind)
gl520_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &gl520_group)))
goto exit_detach;
- }
-
- device_create_file_vid(new_client, 0);
- device_create_file_in(new_client, 0);
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- if (!data->two_temps)
- device_create_file_in(new_client, 4);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan_off(new_client, 1);
+ if (data->two_temps) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp2_max_hyst)))
+ goto exit_remove_files;
+ } else {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto exit_remove_files;
+ }
- device_create_file_temp(new_client, 1);
- if (data->two_temps)
- device_create_file_temp(new_client, 2);
- device_create_file_alarms(new_client);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &gl520_group);
+ sysfs_remove_group(&new_client->dev.kobj, &gl520_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -652,6 +686,8 @@ static int gl520_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group);
+ sysfs_remove_group(&client->dev.kobj, &gl520_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/hdaps.c b/drivers/hwmon/hdaps.c
index 42b632889dd8..26be4ea8a38a 100644
--- a/drivers/hwmon/hdaps.c
+++ b/drivers/hwmon/hdaps.c
@@ -537,6 +537,7 @@ static int __init hdaps_init(void)
HDAPS_DMI_MATCH_NORMAL("ThinkPad T42"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad T43"),
HDAPS_DMI_MATCH_LENOVO("ThinkPad T60p"),
+ HDAPS_DMI_MATCH_LENOVO("ThinkPad T60"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X40"),
HDAPS_DMI_MATCH_NORMAL("ThinkPad X41"),
HDAPS_DMI_MATCH_LENOVO("ThinkPad X60"),
@@ -587,7 +588,9 @@ static int __init hdaps_init(void)
input_set_abs_params(hdaps_idev, ABS_Y,
-256, 256, HDAPS_INPUT_FUZZ, HDAPS_INPUT_FLAT);
- input_register_device(hdaps_idev);
+ ret = input_register_device(hdaps_idev);
+ if (ret)
+ goto out_idev;
/* start up our timer for the input device */
init_timer(&hdaps_timer);
@@ -598,6 +601,8 @@ static int __init hdaps_init(void)
printk(KERN_INFO "hdaps: driver successfully loaded.\n");
return 0;
+out_idev:
+ input_free_device(hdaps_idev);
out_group:
sysfs_remove_group(&pdev->dev.kobj, &hdaps_attribute_group);
out_device:
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 06df92b3ee49..323ef06719c1 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -4,10 +4,12 @@
Supports: IT8705F Super I/O chip w/LPC interface
IT8712F Super I/O chip w/LPC interface & SMBus
+ IT8716F Super I/O chip w/LPC interface
+ IT8718F Super I/O chip w/LPC interface
Sis950 A clone of the IT8705F
Copyright (C) 2001 Chris Gauthron <chrisg@0-in.com>
- Largely inspired by lm78.c of the same package
+ Copyright (C) 2005-2006 Jean Delvare <khali@linux-fr.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
@@ -24,13 +26,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-/*
- djg@pdp8.net David Gesswein 7/18/01
- Modified to fix bug with not all alarms enabled.
- Added ability to read battery voltage and select temperature sensor
- type at module load time.
-*/
-
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -42,6 +37,7 @@
#include <linux/hwmon-vid.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
@@ -50,12 +46,13 @@ static unsigned short normal_i2c[] = { 0x2d, I2C_CLIENT_END };
static unsigned short isa_address;
/* Insmod parameters */
-I2C_CLIENT_INSMOD_2(it87, it8712);
+I2C_CLIENT_INSMOD_4(it87, it8712, it8716, it8718);
#define REG 0x2e /* The register to read/write */
#define DEV 0x07 /* Register: Logical device select */
#define VAL 0x2f /* The value to read/write */
#define PME 0x04 /* The device with the fan registers in it */
+#define GPIO 0x07 /* The device with the IT8718F VID value in it */
#define DEVID 0x20 /* Register: Device ID */
#define DEVREV 0x22 /* Register: Device Revision */
@@ -77,10 +74,10 @@ static int superio_inw(int reg)
}
static inline void
-superio_select(void)
+superio_select(int ldn)
{
outb(DEV, REG);
- outb(PME, VAL);
+ outb(ldn, VAL);
}
static inline void
@@ -99,20 +96,27 @@ superio_exit(void)
outb(0x02, VAL);
}
+/* Logical device 4 registers */
#define IT8712F_DEVID 0x8712
#define IT8705F_DEVID 0x8705
+#define IT8716F_DEVID 0x8716
+#define IT8718F_DEVID 0x8718
#define IT87_ACT_REG 0x30
#define IT87_BASE_REG 0x60
+/* Logical device 7 registers (IT8712F and later) */
+#define IT87_SIO_PINX2_REG 0x2c /* Pin selection */
+#define IT87_SIO_VID_REG 0xfc /* VID value */
+
/* Update battery voltage after every reading if true */
static int update_vbat;
/* Not all BIOSes properly configure the PWM registers */
static int fix_pwm_polarity;
-/* Chip Type */
-
+/* Values read from Super-I/O config space */
static u16 chip_type;
+static u8 vid_value;
/* Many IT87 constants specified below */
@@ -131,13 +135,21 @@ static u16 chip_type;
#define IT87_REG_ALARM2 0x02
#define IT87_REG_ALARM3 0x03
+/* The IT8718F has the VID value in a different register, in Super-I/O
+ configuration space. */
#define IT87_REG_VID 0x0a
+/* Warning: register 0x0b is used for something completely different in
+ new chips/revisions. I suspect only 16-bit tachometer mode will work
+ for these. */
#define IT87_REG_FAN_DIV 0x0b
+#define IT87_REG_FAN_16BIT 0x0c
/* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
#define IT87_REG_FAN(nr) (0x0d + (nr))
#define IT87_REG_FAN_MIN(nr) (0x10 + (nr))
+#define IT87_REG_FANX(nr) (0x18 + (nr))
+#define IT87_REG_FANX_MIN(nr) (0x1b + (nr))
#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
#define IT87_REG_PWM(nr) (0x15 + (nr))
@@ -169,7 +181,16 @@ static inline u8 FAN_TO_REG(long rpm, int div)
254);
}
+static inline u16 FAN16_TO_REG(long rpm)
+{
+ if (rpm == 0)
+ return 0xffff;
+ return SENSORS_LIMIT((1350000 + rpm) / (rpm * 2), 1, 0xfffe);
+}
+
#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div)))
+/* The divider is fixed to 2 in 16-bit mode */
+#define FAN16_FROM_REG(val) ((val)==0?-1:(val)==0xffff?0:1350000/((val)*2))
#define TEMP_TO_REG(val) (SENSORS_LIMIT(((val)<0?(((val)-500)/1000):\
((val)+500)/1000),-128,127))
@@ -181,7 +202,7 @@ static inline u8 FAN_TO_REG(long rpm, int div)
static int DIV_TO_REG(int val)
{
int answer = 0;
- while ((val >>= 1) != 0)
+ while (answer < 7 && (val >>= 1))
answer++;
return answer;
}
@@ -203,10 +224,11 @@ struct it87_data {
unsigned long last_updated; /* In jiffies */
u8 in[9]; /* Register value */
- u8 in_max[9]; /* Register value */
- u8 in_min[9]; /* Register value */
- u8 fan[3]; /* Register value */
- u8 fan_min[3]; /* Register value */
+ u8 in_max[8]; /* Register value */
+ u8 in_min[8]; /* Register value */
+ u8 has_fan; /* Bitfield, fans enabled */
+ u16 fan[3]; /* Register values, possibly combined */
+ u16 fan_min[3]; /* Register values, possibly combined */
u8 temp[3]; /* Register value */
u8 temp_high[3]; /* Register value */
u8 temp_low[3]; /* Register value */
@@ -243,6 +265,7 @@ static struct i2c_driver it87_driver = {
static struct i2c_driver it87_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "it87-isa",
},
.attach_adapter = it87_isa_attach_adapter,
@@ -544,15 +567,15 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
struct i2c_client *client = to_i2c_client(dev);
struct it87_data *data = i2c_get_clientdata(client);
- int val = simple_strtol(buf, NULL, 10);
- int i, min[3];
+ unsigned long val = simple_strtoul(buf, NULL, 10);
+ int min;
u8 old;
mutex_lock(&data->update_lock);
old = it87_read_value(client, IT87_REG_FAN_DIV);
- for (i = 0; i < 3; i++)
- min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i]));
+ /* Save fan min limit */
+ min = FAN_FROM_REG(data->fan_min[nr], DIV_FROM_REG(data->fan_div[nr]));
switch (nr) {
case 0:
@@ -572,10 +595,10 @@ static ssize_t set_fan_div(struct device *dev, struct device_attribute *attr,
val |= 0x1 << 6;
it87_write_value(client, IT87_REG_FAN_DIV, val);
- for (i = 0; i < 3; i++) {
- data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i]));
- it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]);
- }
+ /* Restore fan min limit */
+ data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));
+ it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
+
mutex_unlock(&data->update_lock);
return count;
}
@@ -656,6 +679,59 @@ show_pwm_offset(1);
show_pwm_offset(2);
show_pwm_offset(3);
+/* A different set of callbacks for 16-bit fans */
+static ssize_t show_fan16(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct it87_data *data = it87_update_device(dev);
+ return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan[nr]));
+}
+
+static ssize_t show_fan16_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct it87_data *data = it87_update_device(dev);
+ return sprintf(buf, "%d\n", FAN16_FROM_REG(data->fan_min[nr]));
+}
+
+static ssize_t set_fan16_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ struct i2c_client *client = to_i2c_client(dev);
+ struct it87_data *data = i2c_get_clientdata(client);
+ int val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ data->fan_min[nr] = FAN16_TO_REG(val);
+ it87_write_value(client, IT87_REG_FAN_MIN(nr),
+ data->fan_min[nr] & 0xff);
+ it87_write_value(client, IT87_REG_FANX_MIN(nr),
+ data->fan_min[nr] >> 8);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* We want to use the same sysfs file names as 8-bit fans, but we need
+ different variable names, so we have to use SENSOR_ATTR instead of
+ SENSOR_DEVICE_ATTR. */
+#define show_fan16_offset(offset) \
+static struct sensor_device_attribute sensor_dev_attr_fan##offset##_input16 \
+ = SENSOR_ATTR(fan##offset##_input, S_IRUGO, \
+ show_fan16, NULL, offset - 1); \
+static struct sensor_device_attribute sensor_dev_attr_fan##offset##_min16 \
+ = SENSOR_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \
+ show_fan16_min, set_fan16_min, offset - 1)
+
+show_fan16_offset(1);
+show_fan16_offset(2);
+show_fan16_offset(3);
+
/* Alarms */
static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -683,8 +759,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm)
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -693,8 +767,88 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid)
+
+static struct attribute *it87_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_type.dev_attr.attr,
+ &sensor_dev_attr_temp2_type.dev_attr.attr,
+ &sensor_dev_attr_temp3_type.dev_attr.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group it87_group = {
+ .attrs = it87_attributes,
+};
+
+static struct attribute *it87_attributes_opt[] = {
+ &sensor_dev_attr_fan1_input16.dev_attr.attr,
+ &sensor_dev_attr_fan1_min16.dev_attr.attr,
+ &sensor_dev_attr_fan2_input16.dev_attr.attr,
+ &sensor_dev_attr_fan2_min16.dev_attr.attr,
+ &sensor_dev_attr_fan3_input16.dev_attr.attr,
+ &sensor_dev_attr_fan3_min16.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
+ NULL
+};
+
+static const struct attribute_group it87_group_opt = {
+ .attrs = it87_attributes_opt,
+};
/* This function is called when:
* it87_driver is inserted (when this module is loaded), for each
@@ -720,10 +874,12 @@ static int __init it87_find(unsigned short *address)
superio_enter();
chip_type = superio_inw(DEVID);
if (chip_type != IT8712F_DEVID
+ && chip_type != IT8716F_DEVID
+ && chip_type != IT8718F_DEVID
&& chip_type != IT8705F_DEVID)
goto exit;
- superio_select();
+ superio_select(PME);
if (!(superio_inb(IT87_ACT_REG) & 0x01)) {
pr_info("it87: Device not activated, skipping\n");
goto exit;
@@ -739,6 +895,21 @@ static int __init it87_find(unsigned short *address)
pr_info("it87: Found IT%04xF chip at 0x%x, revision %d\n",
chip_type, *address, superio_inb(DEVREV) & 0x0f);
+ /* Read GPIO config and VID value from LDN 7 (GPIO) */
+ if (chip_type != IT8705F_DEVID) {
+ int reg;
+
+ superio_select(GPIO);
+ if (chip_type == it8718)
+ vid_value = superio_inb(IT87_SIO_VID_REG);
+
+ reg = superio_inb(IT87_SIO_PINX2_REG);
+ if (reg & (1 << 0))
+ pr_info("it87: in3 is VCC (+5V)\n");
+ if (reg & (1 << 1))
+ pr_info("it87: in7 is VCCH (+5V Stand-By)\n");
+ }
+
exit:
superio_exit();
return err;
@@ -799,8 +970,19 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
i = it87_read_value(new_client, IT87_REG_CHIPID);
if (i == 0x90) {
kind = it87;
- if ((is_isa) && (chip_type == IT8712F_DEVID))
- kind = it8712;
+ if (is_isa) {
+ switch (chip_type) {
+ case IT8712F_DEVID:
+ kind = it8712;
+ break;
+ case IT8716F_DEVID:
+ kind = it8716;
+ break;
+ case IT8718F_DEVID:
+ kind = it8718;
+ break;
+ }
+ }
}
else {
if (kind == 0)
@@ -817,6 +999,10 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
name = "it87";
} else if (kind == it8712) {
name = "it8712";
+ } else if (kind == it8716) {
+ name = "it8716";
+ } else if (kind == it8718) {
+ name = "it8718";
}
/* Fill in the remaining client fields and put it into the global list */
@@ -841,76 +1027,103 @@ static int it87_detect(struct i2c_adapter *adapter, int address, int kind)
it87_init_client(new_client, data);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &it87_group)))
goto ERROR3;
+
+ /* Do not create fan files for disabled fans */
+ if (data->type == it8716 || data->type == it8718) {
+ /* 16-bit tachometers */
+ if (data->has_fan & (1 << 0)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_input16.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_min16.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 1)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_input16.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_min16.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 2)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_input16.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_min16.dev_attr)))
+ goto ERROR4;
+ }
+ } else {
+ /* 8-bit tachometers with clock divider */
+ if (data->has_fan & (1 << 0)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_input.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_min.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan1_div.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 1)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_input.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_min.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan2_div.dev_attr)))
+ goto ERROR4;
+ }
+ if (data->has_fan & (1 << 2)) {
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_input.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_min.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_fan3_div.dev_attr)))
+ goto ERROR4;
+ }
}
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in8_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in6_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_in7_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_max.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp1_type.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp2_type.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_temp3_type.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_input.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_min.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan2_div.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_fan3_div.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_alarms);
if (enable_pwm_interface) {
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm1_enable.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm2_enable.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm3_enable.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm1.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm2.dev_attr);
- device_create_file(&new_client->dev, &sensor_dev_attr_pwm3.dev_attr);
+ if ((err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm1_enable.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm2_enable.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm3_enable.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm1.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm2.dev_attr))
+ || (err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_pwm3.dev_attr)))
+ goto ERROR4;
}
- if (data->type == it8712) {
+ if (data->type == it8712 || data->type == it8716
+ || data->type == it8718) {
data->vrm = vid_which_vrm();
- device_create_file_vrm(new_client);
- device_create_file_vid(new_client);
+ /* VID reading from Super-I/O config space if available */
+ data->vid = vid_value;
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_vrm))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_cpu0_vid)))
+ goto ERROR4;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
}
return 0;
+ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &it87_group);
+ sysfs_remove_group(&new_client->dev.kobj, &it87_group_opt);
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -928,6 +1141,8 @@ static int it87_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &it87_group);
+ sysfs_remove_group(&client->dev.kobj, &it87_group_opt);
if ((err = i2c_detach_client(client)))
return err;
@@ -1044,6 +1259,22 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
data->manual_pwm_ctl[i] = 0xff;
}
+ /* Some chips seem to have default value 0xff for all limit
+ * registers. For low voltage limits it makes no sense and triggers
+ * alarms, so change to 0 instead. For high temperature limits, it
+ * means -1 degree C, which surprisingly doesn't trigger an alarm,
+ * but is still confusing, so change to 127 degrees C. */
+ for (i = 0; i < 8; i++) {
+ tmp = it87_read_value(client, IT87_REG_VIN_MIN(i));
+ if (tmp == 0xff)
+ it87_write_value(client, IT87_REG_VIN_MIN(i), 0);
+ }
+ for (i = 0; i < 3; i++) {
+ tmp = it87_read_value(client, IT87_REG_TEMP_HIGH(i));
+ if (tmp == 0xff)
+ it87_write_value(client, IT87_REG_TEMP_HIGH(i), 127);
+ }
+
/* Check if temperature channnels are reset manually or by some reason */
tmp = it87_read_value(client, IT87_REG_TEMP_ENABLE);
if ((tmp & 0x3f) == 0) {
@@ -1067,6 +1298,18 @@ static void it87_init_client(struct i2c_client *client, struct it87_data *data)
data->fan_main_ctrl |= 0x70;
it87_write_value(client, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);
}
+ data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
+
+ /* Set tachometers to 16-bit mode if needed */
+ if (data->type == it8716 || data->type == it8718) {
+ tmp = it87_read_value(client, IT87_REG_FAN_16BIT);
+ if (~tmp & 0x07 & data->has_fan) {
+ dev_dbg(&client->dev,
+ "Setting fan1-3 to 16-bit mode\n");
+ it87_write_value(client, IT87_REG_FAN_16BIT,
+ tmp | 0x07);
+ }
+ }
/* Set current fan mode registers and the default settings for the
* other mode registers */
@@ -1117,18 +1360,26 @@ static struct it87_data *it87_update_device(struct device *dev)
data->in_max[i] =
it87_read_value(client, IT87_REG_VIN_MAX(i));
}
+ /* in8 (battery) has no limit registers */
data->in[8] =
it87_read_value(client, IT87_REG_VIN(8));
- /* Temperature sensor doesn't have limit registers, set
- to min and max value */
- data->in_min[8] = 0;
- data->in_max[8] = 255;
for (i = 0; i < 3; i++) {
- data->fan[i] =
- it87_read_value(client, IT87_REG_FAN(i));
+ /* Skip disabled fans */
+ if (!(data->has_fan & (1 << i)))
+ continue;
+
data->fan_min[i] =
it87_read_value(client, IT87_REG_FAN_MIN(i));
+ data->fan[i] = it87_read_value(client,
+ IT87_REG_FAN(i));
+ /* Add high byte if in 16-bit mode */
+ if (data->type == it8716 || data->type == it8718) {
+ data->fan[i] |= it87_read_value(client,
+ IT87_REG_FANX(i)) << 8;
+ data->fan_min[i] |= it87_read_value(client,
+ IT87_REG_FANX_MIN(i)) << 8;
+ }
}
for (i = 0; i < 3; i++) {
data->temp[i] =
@@ -1139,10 +1390,14 @@ static struct it87_data *it87_update_device(struct device *dev)
it87_read_value(client, IT87_REG_TEMP_LOW(i));
}
- i = it87_read_value(client, IT87_REG_FAN_DIV);
- data->fan_div[0] = i & 0x07;
- data->fan_div[1] = (i >> 3) & 0x07;
- data->fan_div[2] = (i & 0x40) ? 3 : 1;
+ /* Newer chips don't have clock dividers */
+ if ((data->has_fan & 0x07) && data->type != it8716
+ && data->type != it8718) {
+ i = it87_read_value(client, IT87_REG_FAN_DIV);
+ data->fan_div[0] = i & 0x07;
+ data->fan_div[1] = (i >> 3) & 0x07;
+ data->fan_div[2] = (i & 0x40) ? 3 : 1;
+ }
data->alarms =
it87_read_value(client, IT87_REG_ALARM1) |
@@ -1152,9 +1407,11 @@ static struct it87_data *it87_update_device(struct device *dev)
data->sensor = it87_read_value(client, IT87_REG_TEMP_ENABLE);
/* The 8705 does not have VID capability */
- if (data->type == it8712) {
+ if (data->type == it8712 || data->type == it8716) {
data->vid = it87_read_value(client, IT87_REG_VID);
- data->vid &= 0x1f;
+ /* The older IT8712F revisions had only 5 VID pins,
+ but we assume it is always safe to read 6 bits. */
+ data->vid &= 0x3f;
}
data->last_updated = jiffies;
data->valid = 1;
@@ -1192,8 +1449,9 @@ static void __exit sm_it87_exit(void)
}
-MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>");
-MODULE_DESCRIPTION("IT8705F, IT8712F, Sis950 driver");
+MODULE_AUTHOR("Chris Gauthron <chrisg@0-in.com>, "
+ "Jean Delvare <khali@linux-fr.org>");
+MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F, SiS950 driver");
module_param(update_vbat, bool, 0);
MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
module_param(fix_pwm_polarity, bool, 0);
diff --git a/drivers/hwmon/k8temp.c b/drivers/hwmon/k8temp.c
new file mode 100644
index 000000000000..f58b64ed09e3
--- /dev/null
+++ b/drivers/hwmon/k8temp.c
@@ -0,0 +1,294 @@
+/*
+ * k8temp.c - Linux kernel module for hardware monitoring
+ *
+ * Copyright (C) 2006 Rudolf Marek <r.marek@sh.cvut.cz>
+ *
+ * Inspired from the w83785 and amd756 drivers.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/pci.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+
+#define TEMP_FROM_REG(val) (((((val) >> 16) & 0xff) - 49) * 1000)
+#define REG_TEMP 0xe4
+#define SEL_PLACE 0x40
+#define SEL_CORE 0x04
+
+struct k8temp_data {
+ struct class_device *class_dev;
+ struct mutex update_lock;
+ const char *name;
+ char valid; /* zero until following fields are valid */
+ unsigned long last_updated; /* in jiffies */
+
+ /* registers values */
+ u8 sensorsp; /* sensor presence bits - SEL_CORE & SEL_PLACE */
+ u32 temp[2][2]; /* core, place */
+};
+
+static struct k8temp_data *k8temp_update_device(struct device *dev)
+{
+ struct k8temp_data *data = dev_get_drvdata(dev);
+ struct pci_dev *pdev = to_pci_dev(dev);
+ u8 tmp;
+
+ mutex_lock(&data->update_lock);
+
+ if (!data->valid
+ || time_after(jiffies, data->last_updated + HZ)) {
+ pci_read_config_byte(pdev, REG_TEMP, &tmp);
+ tmp &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP, &data->temp[0][0]);
+
+ if (data->sensorsp & SEL_PLACE) {
+ tmp |= SEL_PLACE; /* Select sensor 1, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP,
+ &data->temp[0][1]);
+ }
+
+ if (data->sensorsp & SEL_CORE) {
+ tmp &= ~SEL_PLACE; /* Select sensor 0, core1 */
+ tmp |= SEL_CORE;
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP,
+ &data->temp[1][0]);
+
+ if (data->sensorsp & SEL_PLACE) {
+ tmp |= SEL_PLACE; /* Select sensor 1, core1 */
+ pci_write_config_byte(pdev, REG_TEMP, tmp);
+ pci_read_config_dword(pdev, REG_TEMP,
+ &data->temp[1][1]);
+ }
+ }
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+ return data;
+}
+
+/*
+ * Sysfs stuff
+ */
+
+static ssize_t show_name(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct k8temp_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+
+
+static ssize_t show_temp(struct device *dev,
+ struct device_attribute *devattr, char *buf)
+{
+ struct sensor_device_attribute_2 *attr =
+ to_sensor_dev_attr_2(devattr);
+ int core = attr->nr;
+ int place = attr->index;
+ struct k8temp_data *data = k8temp_update_device(dev);
+
+ return sprintf(buf, "%d\n",
+ TEMP_FROM_REG(data->temp[core][place]));
+}
+
+/* core, place */
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 1, 1);
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
+
+static struct pci_device_id k8temp_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },
+ { 0 },
+};
+
+MODULE_DEVICE_TABLE(pci, k8temp_ids);
+
+static int __devinit k8temp_probe(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ int err;
+ u8 scfg;
+ u32 temp;
+ struct k8temp_data *data;
+ u32 cpuid = cpuid_eax(1);
+
+ /* this feature should be available since SH-C0 core */
+ if ((cpuid == 0xf40) || (cpuid == 0xf50) || (cpuid == 0xf51)) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ if (!(data = kzalloc(sizeof(struct k8temp_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pci_read_config_byte(pdev, REG_TEMP, &scfg);
+ scfg &= ~(SEL_PLACE | SEL_CORE); /* Select sensor 0, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+ pci_read_config_byte(pdev, REG_TEMP, &scfg);
+
+ if (scfg & (SEL_PLACE | SEL_CORE)) {
+ dev_err(&pdev->dev, "Configuration bit(s) stuck at 1!\n");
+ err = -ENODEV;
+ goto exit_free;
+ }
+
+ scfg |= (SEL_PLACE | SEL_CORE);
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+
+ /* now we know if we can change core and/or sensor */
+ pci_read_config_byte(pdev, REG_TEMP, &data->sensorsp);
+
+ if (data->sensorsp & SEL_PLACE) {
+ scfg &= ~SEL_CORE; /* Select sensor 1, core0 */
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+ pci_read_config_dword(pdev, REG_TEMP, &temp);
+ scfg |= SEL_CORE; /* prepare for next selection */
+ if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
+ data->sensorsp &= ~SEL_PLACE;
+ }
+
+ if (data->sensorsp & SEL_CORE) {
+ scfg &= ~SEL_PLACE; /* Select sensor 0, core1 */
+ pci_write_config_byte(pdev, REG_TEMP, scfg);
+ pci_read_config_dword(pdev, REG_TEMP, &temp);
+ if (!((temp >> 16) & 0xff)) /* if temp is 0 -49C is not likely */
+ data->sensorsp &= ~SEL_CORE;
+ }
+
+ data->name = "k8temp";
+ mutex_init(&data->update_lock);
+ dev_set_drvdata(&pdev->dev, data);
+
+ /* Register sysfs hooks */
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ /* sensor can be changed and reports something */
+ if (data->sensorsp & SEL_PLACE) {
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ /* core can be changed and reports something */
+ if (data->sensorsp & SEL_CORE) {
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+ if (err)
+ goto exit_remove;
+ if (data->sensorsp & SEL_PLACE)
+ err = device_create_file(&pdev->dev,
+ &sensor_dev_attr_temp4_input.
+ dev_attr);
+ if (err)
+ goto exit_remove;
+ }
+
+ err = device_create_file(&pdev->dev, &dev_attr_name);
+ if (err)
+ goto exit_remove;
+
+ data->class_dev = hwmon_device_register(&pdev->dev);
+
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
+
+ return 0;
+
+exit_remove:
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp4_input.dev_attr);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+exit_free:
+ dev_set_drvdata(&pdev->dev, NULL);
+ kfree(data);
+exit:
+ return err;
+}
+
+static void __devexit k8temp_remove(struct pci_dev *pdev)
+{
+ struct k8temp_data *data = dev_get_drvdata(&pdev->dev);
+
+ hwmon_device_unregister(data->class_dev);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp2_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp3_input.dev_attr);
+ device_remove_file(&pdev->dev,
+ &sensor_dev_attr_temp4_input.dev_attr);
+ device_remove_file(&pdev->dev, &dev_attr_name);
+ dev_set_drvdata(&pdev->dev, NULL);
+ kfree(data);
+}
+
+static struct pci_driver k8temp_driver = {
+ .name = "k8temp",
+ .id_table = k8temp_ids,
+ .probe = k8temp_probe,
+ .remove = __devexit_p(k8temp_remove),
+};
+
+static int __init k8temp_init(void)
+{
+ return pci_register_driver(&k8temp_driver);
+}
+
+static void __exit k8temp_exit(void)
+{
+ pci_unregister_driver(&k8temp_driver);
+}
+
+MODULE_AUTHOR("Rudolf Marek <r.marek@sh.cvut.cz>");
+MODULE_DESCRIPTION("AMD K8 core temperature monitor");
+MODULE_LICENSE("GPL");
+
+module_init(k8temp_init)
+module_exit(k8temp_exit)
diff --git a/drivers/hwmon/lm63.c b/drivers/hwmon/lm63.c
index 071f0fc6adec..d69f3cf07122 100644
--- a/drivers/hwmon/lm63.c
+++ b/drivers/hwmon/lm63.c
@@ -1,7 +1,7 @@
/*
* lm63.c - driver for the National Semiconductor LM63 temperature sensor
* with integrated fan control
- * Copyright (C) 2004-2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2006 Jean Delvare <khali@linux-fr.org>
* Based on the lm90 driver.
*
* The LM63 is a sensor chip made by National Semiconductor. It measures
@@ -46,6 +46,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -330,6 +331,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
return sprintf(buf, "%u\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute *devattr,
+ char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm63_data *data = lm63_update_device(dev);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%u\n", (data->alarms >> bitnr) & 1);
+}
+
static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0);
static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan,
set_fan, 1);
@@ -350,8 +361,52 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp8, NULL, 2);
static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp2_crit_hyst,
set_temp2_crit_hyst);
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(fan1_min_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *lm63_attributes[] = {
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &dev_attr_temp2_crit_hyst.attr,
+
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group lm63_group = {
+ .attrs = lm63_attributes,
+};
+
+static struct attribute *lm63_attributes_fan1[] = {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+
+ &sensor_dev_attr_fan1_min_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lm63_group_fan1 = {
+ .attrs = lm63_attributes_fan1,
+};
+
/*
* Real code
*/
@@ -438,37 +493,26 @@ static int lm63_detect(struct i2c_adapter *adapter, int address, int kind)
lm63_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm63_group)))
goto exit_detach;
+ if (data->config & 0x04) { /* tachometer enabled */
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm63_group_fan1)))
+ goto exit_remove_files;
}
- if (data->config & 0x04) { /* tachometer enabled */
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_fan1_min.dev_attr);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &lm63_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm63_group_fan1);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -518,6 +562,8 @@ static int lm63_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm63_group);
+ sysfs_remove_group(&client->dev.kobj, &lm63_group_fan1);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index fc25b90ec24a..7c65b8bb6d72 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -112,6 +112,18 @@ static int lm75_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm75_detect);
}
+static struct attribute *lm75_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm75_group = {
+ .attrs = lm75_attributes,
+};
+
/* This function is called by i2c_probe */
static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -199,18 +211,19 @@ static int lm75_detect(struct i2c_adapter *adapter, int address, int kind)
lm75_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm75_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
-
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm75_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -223,6 +236,7 @@ static int lm75_detach_client(struct i2c_client *client)
{
struct lm75_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm75_group);
i2c_detach_client(client);
kfree(data);
return 0;
diff --git a/drivers/hwmon/lm77.c b/drivers/hwmon/lm77.c
index 459cc977380a..dd969f1e8415 100644
--- a/drivers/hwmon/lm77.c
+++ b/drivers/hwmon/lm77.c
@@ -212,6 +212,23 @@ static int lm77_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm77_detect);
}
+static struct attribute *lm77_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_crit_hyst.attr,
+ &dev_attr_temp1_min_hyst.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm77_group = {
+ .attrs = lm77_attributes,
+};
+
/* This function is called by i2c_probe */
static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -317,22 +334,19 @@ static int lm77_detect(struct i2c_adapter *adapter, int address, int kind)
lm77_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm77_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm77_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -345,6 +359,7 @@ static int lm77_detach_client(struct i2c_client *client)
{
struct lm77_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm77_group);
i2c_detach_client(client);
kfree(data);
return 0;
diff --git a/drivers/hwmon/lm78.c b/drivers/hwmon/lm78.c
index a6ce7abf8602..73bc2ffc598d 100644
--- a/drivers/hwmon/lm78.c
+++ b/drivers/hwmon/lm78.c
@@ -175,6 +175,7 @@ static struct i2c_driver lm78_driver = {
static struct i2c_driver lm78_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "lm78-isa",
},
.attach_adapter = lm78_isa_attach_adapter,
@@ -481,6 +482,50 @@ static int lm78_isa_attach_adapter(struct i2c_adapter *adapter)
return lm78_detect(adapter, isa_address, -1);
}
+static struct attribute *lm78_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan3_div.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_cpu0_vid.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm78_group = {
+ .attrs = lm78_attributes,
+};
+
/* This function is called by i2c_probe */
static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
{
@@ -615,50 +660,19 @@ static int lm78_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm78_group)))
+ goto ERROR3;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto ERROR3;
+ goto ERROR4;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_fan3_input);
- device_create_file(&new_client->dev, &dev_attr_fan3_min);
- device_create_file(&new_client->dev, &dev_attr_fan3_div);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
-
return 0;
+ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &lm78_group);
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -676,6 +690,7 @@ static int lm78_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm78_group);
if ((err = i2c_detach_client(client)))
return err;
@@ -800,18 +815,18 @@ static int __init sm_lm78_init(void)
if (res)
return res;
- res = i2c_isa_add_driver(&lm78_isa_driver);
- if (res) {
- i2c_del_driver(&lm78_driver);
- return res;
- }
+ /* Don't exit if this one fails, we still want the I2C variants
+ to work! */
+ if (i2c_isa_add_driver(&lm78_isa_driver))
+ isa_address = 0;
return 0;
}
static void __exit sm_lm78_exit(void)
{
- i2c_isa_del_driver(&lm78_isa_driver);
+ if (isa_address)
+ i2c_isa_del_driver(&lm78_isa_driver);
i2c_del_driver(&lm78_driver);
}
diff --git a/drivers/hwmon/lm80.c b/drivers/hwmon/lm80.c
index b4ccdfc01203..064516d824ad 100644
--- a/drivers/hwmon/lm80.c
+++ b/drivers/hwmon/lm80.c
@@ -394,6 +394,48 @@ static int lm80_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm80_detect);
}
+static struct attribute *lm80_attributes[] = {
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_max.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_div.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp1_crit_hyst.attr,
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm80_group = {
+ .attrs = lm80_attributes,
+};
+
static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i, cur;
@@ -452,48 +494,19 @@ static int lm80_detect(struct i2c_adapter *adapter, int address, int kind)
data->fan_min[1] = lm80_read_value(new_client, LM80_REG_FAN_MIN(2));
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm80_group)))
+ goto error_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto error_detach;
+ goto error_remove;
}
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+error_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm80_group);
error_detach:
i2c_detach_client(new_client);
error_free:
@@ -508,7 +521,7 @@ static int lm80_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
-
+ sysfs_remove_group(&client->dev.kobj, &lm80_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm83.c b/drivers/hwmon/lm83.c
index 2137d7879df6..feb87b41e986 100644
--- a/drivers/hwmon/lm83.c
+++ b/drivers/hwmon/lm83.c
@@ -1,7 +1,7 @@
/*
* lm83.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
*
* Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
* a sensor chip made by National Semiconductor. It reports up to four
@@ -40,6 +40,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -191,6 +192,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
return sprintf(buf, "%d\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm83_data *data = lm83_update_device(dev);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1);
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2);
@@ -208,8 +219,64 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp, NULL, 8);
static SENSOR_DEVICE_ATTR(temp3_crit, S_IWUSR | S_IRUGO, show_temp,
set_temp, 8);
static SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp, NULL, 8);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp3_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 8);
+static SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, show_alarm, NULL, 9);
+static SENSOR_DEVICE_ATTR(temp4_input_fault, S_IRUGO, show_alarm, NULL, 10);
+static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_alarm, NULL, 12);
+static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 13);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 15);
+/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *lm83_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group lm83_group = {
+ .attrs = lm83_attributes,
+};
+
+static struct attribute *lm83_attributes_opt[] = {
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit.dev_attr.attr,
+
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group lm83_group_opt = {
+ .attrs = lm83_attributes_opt,
+};
+
/*
* Real code
*/
@@ -318,59 +385,32 @@ static int lm83_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_free;
/*
- * Initialize the LM83 chip
- * (Nothing to do for this one.)
- */
-
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- goto exit_detach;
- }
-
- /*
+ * Register sysfs hooks
* The LM82 can only monitor one external diode which is
* at the same register as the LM83 temp3 entry - so we
* declare 1 and 3 common, and then 2 and 4 only for the LM83.
*/
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_input.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_max.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp3_crit.dev_attr);
-
- device_create_file(&new_client->dev, &dev_attr_alarms);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm83_group)))
+ goto exit_detach;
if (kind == lm83) {
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_input.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_max.dev_attr);
-
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp4_crit.dev_attr);
+ if ((err = sysfs_create_group(&new_client->dev.kobj,
+ &lm83_group_opt)))
+ goto exit_remove_files;
+ }
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &lm83_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm83_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -385,6 +425,8 @@ static int lm83_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm83_group);
+ sysfs_remove_group(&client->dev.kobj, &lm83_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm85.c b/drivers/hwmon/lm85.c
index 342e9663119d..2c3293cf69d1 100644
--- a/drivers/hwmon/lm85.c
+++ b/drivers/hwmon/lm85.c
@@ -1025,6 +1025,89 @@ static int lm85_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm85_detect);
}
+static struct attribute *lm85_attributes[] = {
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan4_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan4_min.attr,
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm3.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm2_enable.attr,
+ &dev_attr_pwm3_enable.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp3_min.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_pwm1_auto_channels.attr,
+ &dev_attr_pwm2_auto_channels.attr,
+ &dev_attr_pwm3_auto_channels.attr,
+ &dev_attr_pwm1_auto_pwm_min.attr,
+ &dev_attr_pwm2_auto_pwm_min.attr,
+ &dev_attr_pwm3_auto_pwm_min.attr,
+ &dev_attr_pwm1_auto_pwm_minctl.attr,
+ &dev_attr_pwm2_auto_pwm_minctl.attr,
+ &dev_attr_pwm3_auto_pwm_minctl.attr,
+ &dev_attr_pwm1_auto_pwm_freq.attr,
+ &dev_attr_pwm2_auto_pwm_freq.attr,
+ &dev_attr_pwm3_auto_pwm_freq.attr,
+ &dev_attr_temp1_auto_temp_off.attr,
+ &dev_attr_temp2_auto_temp_off.attr,
+ &dev_attr_temp3_auto_temp_off.attr,
+ &dev_attr_temp1_auto_temp_min.attr,
+ &dev_attr_temp2_auto_temp_min.attr,
+ &dev_attr_temp3_auto_temp_min.attr,
+ &dev_attr_temp1_auto_temp_max.attr,
+ &dev_attr_temp2_auto_temp_max.attr,
+ &dev_attr_temp3_auto_temp_max.attr,
+ &dev_attr_temp1_auto_temp_crit.attr,
+ &dev_attr_temp2_auto_temp_crit.attr,
+ &dev_attr_temp3_auto_temp_crit.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm85_group = {
+ .attrs = lm85_attributes,
+};
+
+static struct attribute *lm85_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm85_group_opt = {
+ .attrs = lm85_attributes_opt,
+};
+
static int lm85_detect(struct i2c_adapter *adapter, int address,
int kind)
{
@@ -1163,87 +1246,33 @@ static int lm85_detect(struct i2c_adapter *adapter, int address,
lm85_init_client(new_client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm85_group)))
goto ERROR2;
- }
-
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan3_input);
- device_create_file(&new_client->dev, &dev_attr_fan4_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan3_min);
- device_create_file(&new_client->dev, &dev_attr_fan4_min);
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_pwm3);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
- device_create_file(&new_client->dev, &dev_attr_pwm3_enable);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_vrm);
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_channels);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_channels);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_channels);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_min);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_min);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_min);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_minctl);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_minctl);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_minctl);
- device_create_file(&new_client->dev, &dev_attr_pwm1_auto_pwm_freq);
- device_create_file(&new_client->dev, &dev_attr_pwm2_auto_pwm_freq);
- device_create_file(&new_client->dev, &dev_attr_pwm3_auto_pwm_freq);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_off);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_off);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_off);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_auto_temp_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_auto_temp_crit);
- device_create_file(&new_client->dev, &dev_attr_temp3_auto_temp_crit);
/* The ADT7463 has an optional VRM 10 mode where pin 21 is used
as a sixth digital VID input rather than an analog input. */
data->vid = lm85_read_value(new_client, LM85_REG_VID);
- if (!(kind == adt7463 && (data->vid & 0x80))) {
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
+ if (!(kind == adt7463 && (data->vid & 0x80)))
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto ERROR3;
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
}
return 0;
/* Error out and cleanup code */
+ ERROR3:
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm85_group_opt);
ERROR2:
i2c_detach_client(new_client);
ERROR1:
@@ -1256,6 +1285,8 @@ static int lm85_detach_client(struct i2c_client *client)
{
struct lm85_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm85_group);
+ sysfs_remove_group(&client->dev.kobj, &lm85_group_opt);
i2c_detach_client(client);
kfree(data);
return 0;
diff --git a/drivers/hwmon/lm87.c b/drivers/hwmon/lm87.c
index e6c1b638c971..3ce825489e34 100644
--- a/drivers/hwmon/lm87.c
+++ b/drivers/hwmon/lm87.c
@@ -542,6 +542,78 @@ static int lm87_attach_adapter(struct i2c_adapter *adapter)
return i2c_probe(adapter, &addr_data, lm87_detect);
}
+static struct attribute *lm87_attributes[] = {
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_crit.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_aout_output.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm87_group = {
+ .attrs = lm87_attributes,
+};
+
+static struct attribute *lm87_attributes_opt[] = {
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+
+ &dev_attr_in7_input.attr,
+ &dev_attr_in7_min.attr,
+ &dev_attr_in7_max.attr,
+
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_min.attr,
+ &dev_attr_temp3_crit.attr,
+
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm87_group_opt = {
+ .attrs = lm87_attributes_opt,
+};
+
/*
* The following function does more than just detection. If detection
* succeeds, it also registers the new chip.
@@ -609,77 +681,90 @@ static int lm87_detect(struct i2c_adapter *adapter, int address, int kind)
data->in_scale[7] = 1875;
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm87_group)))
goto exit_detach;
- }
-
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
if (data->channel & CHAN_NO_FAN(0)) {
- device_create_file(&new_client->dev, &dev_attr_in6_input);
- device_create_file(&new_client->dev, &dev_attr_in6_min);
- device_create_file(&new_client->dev, &dev_attr_in6_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in6_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_max)))
+ goto exit_remove;
} else {
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_div)))
+ goto exit_remove;
}
+
if (data->channel & CHAN_NO_FAN(1)) {
- device_create_file(&new_client->dev, &dev_attr_in7_input);
- device_create_file(&new_client->dev, &dev_attr_in7_min);
- device_create_file(&new_client->dev, &dev_attr_in7_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in7_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in7_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in7_max)))
+ goto exit_remove;
} else {
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_div)))
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
-
if (data->channel & CHAN_TEMP3) {
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_min);
- device_create_file(&new_client->dev, &dev_attr_temp3_crit);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_crit)))
+ goto exit_remove;
} else {
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in5_input);
- device_create_file(&new_client->dev, &dev_attr_in5_min);
- device_create_file(&new_client->dev, &dev_attr_in5_max);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in0_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in0_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in0_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_max)))
+ goto exit_remove;
}
if (!(data->channel & CHAN_NO_VID)) {
- device_create_file(&new_client->dev, &dev_attr_cpu0_vid);
- device_create_file(&new_client->dev, &dev_attr_vrm);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_cpu0_vid))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_vrm)))
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_alarms);
- device_create_file(&new_client->dev, &dev_attr_aout_output);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm87_group);
+ sysfs_remove_group(&new_client->dev.kobj, &lm87_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -732,6 +817,8 @@ static int lm87_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm87_group);
+ sysfs_remove_group(&client->dev.kobj, &lm87_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm90.c b/drivers/hwmon/lm90.c
index d9eeaf7585bd..6882ce75feee 100644
--- a/drivers/hwmon/lm90.c
+++ b/drivers/hwmon/lm90.c
@@ -1,7 +1,7 @@
/*
* lm90.c - Part of lm_sensors, Linux kernel modules for hardware
* monitoring
- * Copyright (C) 2003-2005 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2006 Jean Delvare <khali@linux-fr.org>
*
* Based on the lm83 driver. The LM90 is a sensor chip made by National
* Semiconductor. It reports up to two temperatures (its own plus up to
@@ -79,6 +79,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/*
* Addresses to scan
@@ -327,6 +328,16 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *dummy,
return sprintf(buf, "%d\n", data->alarms);
}
+static ssize_t show_alarm(struct device *dev, struct device_attribute
+ *devattr, char *buf)
+{
+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
+ struct lm90_data *data = lm90_update_device(dev);
+ int bitnr = attr->index;
+
+ return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
+}
+
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp8, NULL, 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
@@ -344,8 +355,45 @@ static SENSOR_DEVICE_ATTR(temp2_crit, S_IWUSR | S_IRUGO, show_temp8,
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IWUSR | S_IRUGO, show_temphyst,
set_temphyst, 3);
static SENSOR_DEVICE_ATTR(temp2_crit_hyst, S_IRUGO, show_temphyst, NULL, 4);
+
+/* Individual alarm files */
+static SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, show_alarm, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, show_alarm, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_input_fault, S_IRUGO, show_alarm, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_alarm, NULL, 3);
+static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_alarm, NULL, 4);
+static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_alarm, NULL, 5);
+static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_alarm, NULL, 6);
+/* Raw alarm file for compatibility */
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *lm90_attributes[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group lm90_group = {
+ .attrs = lm90_attributes,
+};
+
/* pec used for ADM1032 only */
static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
char *buf)
@@ -569,39 +617,25 @@ static int lm90_detect(struct i2c_adapter *adapter, int address, int kind)
lm90_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm90_group)))
+ goto exit_detach;
+ if (new_client->flags & I2C_CLIENT_PEC) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pec)))
+ goto exit_remove_files;
+ }
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_crit_hyst.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp2_crit_hyst.dev_attr);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
- if (new_client->flags & I2C_CLIENT_PEC)
- device_create_file(&new_client->dev, &dev_attr_pec);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &lm90_group);
+ device_remove_file(&new_client->dev, &dev_attr_pec);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -634,6 +668,8 @@ static int lm90_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm90_group);
+ device_remove_file(&client->dev, &dev_attr_pec);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/lm92.c b/drivers/hwmon/lm92.c
index 197f77226dc4..30b536333f14 100644
--- a/drivers/hwmon/lm92.c
+++ b/drivers/hwmon/lm92.c
@@ -288,6 +288,23 @@ static int max6635_check(struct i2c_client *client)
return 1;
}
+static struct attribute *lm92_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_crit.attr,
+ &dev_attr_temp1_crit_hyst.attr,
+ &dev_attr_temp1_min.attr,
+ &dev_attr_temp1_min_hyst.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_alarms.attr,
+
+ NULL
+};
+
+static const struct attribute_group lm92_group = {
+ .attrs = lm92_attributes,
+};
+
/* The following function does more than just detection. If detection
succeeds, it also registers the new chip. */
static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -359,23 +376,19 @@ static int lm92_detect(struct i2c_adapter *adapter, int address, int kind)
lm92_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &lm92_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit);
- device_create_file(&new_client->dev, &dev_attr_temp1_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_min);
- device_create_file(&new_client->dev, &dev_attr_temp1_min_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+exit_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &lm92_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -397,6 +410,7 @@ static int lm92_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &lm92_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/max1619.c b/drivers/hwmon/max1619.c
index b4135b5971f4..2f58f651f03a 100644
--- a/drivers/hwmon/max1619.c
+++ b/drivers/hwmon/max1619.c
@@ -34,6 +34,7 @@
#include <linux/hwmon.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
static unsigned short normal_i2c[] = { 0x18, 0x19, 0x1a,
0x29, 0x2a, 0x2b,
@@ -172,6 +173,22 @@ static DEVICE_ATTR(temp2_crit_hyst, S_IWUSR | S_IRUGO, show_temp_hyst2,
set_temp_hyst2);
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *max1619_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_min.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_crit.attr,
+ &dev_attr_temp2_crit_hyst.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group max1619_group = {
+ .attrs = max1619_attributes,
+};
+
/*
* Real code
*/
@@ -273,22 +290,19 @@ static int max1619_detect(struct i2c_adapter *adapter, int address, int kind)
max1619_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &max1619_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_min);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit);
- device_create_file(&new_client->dev, &dev_attr_temp2_crit_hyst);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &max1619_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -318,6 +332,7 @@ static int max1619_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &max1619_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/pc87360.c b/drivers/hwmon/pc87360.c
index ae05e483a778..3b8b81984ad4 100644
--- a/drivers/hwmon/pc87360.c
+++ b/drivers/hwmon/pc87360.c
@@ -238,6 +238,7 @@ static struct pc87360_data *pc87360_update_device(struct device *dev);
static struct i2c_driver pc87360_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "pc87360",
},
.attach_adapter = pc87360_detect,
@@ -327,6 +328,12 @@ static struct sensor_device_attribute fan_min[] = {
SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2),
};
+#define FAN_UNIT_ATTRS(X) \
+ &fan_input[X].dev_attr.attr, \
+ &fan_status[X].dev_attr.attr, \
+ &fan_div[X].dev_attr.attr, \
+ &fan_min[X].dev_attr.attr
+
static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -359,6 +366,19 @@ static struct sensor_device_attribute pwm[] = {
SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2),
};
+static struct attribute * pc8736x_fan_attr_array[] = {
+ FAN_UNIT_ATTRS(0),
+ FAN_UNIT_ATTRS(1),
+ FAN_UNIT_ATTRS(2),
+ &pwm[0].dev_attr.attr,
+ &pwm[1].dev_attr.attr,
+ &pwm[2].dev_attr.attr,
+ NULL
+};
+static const struct attribute_group pc8736x_fan_group = {
+ .attrs = pc8736x_fan_attr_array,
+};
+
static ssize_t show_in_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -471,6 +491,61 @@ static struct sensor_device_attribute in_max[] = {
SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10),
};
+#define VIN_UNIT_ATTRS(X) \
+ &in_input[X].dev_attr.attr, \
+ &in_status[X].dev_attr.attr, \
+ &in_min[X].dev_attr.attr, \
+ &in_max[X].dev_attr.attr
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
+}
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->vrm);
+}
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct pc87360_data *data = i2c_get_clientdata(client);
+ data->vrm = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
+
+static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pc87360_data *data = pc87360_update_device(dev);
+ return sprintf(buf, "%u\n", data->in_alarms);
+}
+static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+
+static struct attribute *pc8736x_vin_attr_array[] = {
+ VIN_UNIT_ATTRS(0),
+ VIN_UNIT_ATTRS(1),
+ VIN_UNIT_ATTRS(2),
+ VIN_UNIT_ATTRS(3),
+ VIN_UNIT_ATTRS(4),
+ VIN_UNIT_ATTRS(5),
+ VIN_UNIT_ATTRS(6),
+ VIN_UNIT_ATTRS(7),
+ VIN_UNIT_ATTRS(8),
+ VIN_UNIT_ATTRS(9),
+ VIN_UNIT_ATTRS(10),
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms_in.attr,
+ NULL
+};
+static const struct attribute_group pc8736x_vin_group = {
+ .attrs = pc8736x_vin_attr_array,
+};
+
static ssize_t show_therm_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
@@ -589,33 +664,22 @@ static struct sensor_device_attribute therm_crit[] = {
show_therm_crit, set_therm_crit, 2+11),
};
-static ssize_t show_vid(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pc87360_data *data = pc87360_update_device(dev);
- return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm));
-}
-static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL);
-
-static ssize_t show_vrm(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pc87360_data *data = pc87360_update_device(dev);
- return sprintf(buf, "%u\n", data->vrm);
-}
-static ssize_t set_vrm(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct pc87360_data *data = i2c_get_clientdata(client);
- data->vrm = simple_strtoul(buf, NULL, 10);
- return count;
-}
-static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm);
-
-static ssize_t show_in_alarms(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct pc87360_data *data = pc87360_update_device(dev);
- return sprintf(buf, "%u\n", data->in_alarms);
-}
-static DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL);
+#define THERM_UNIT_ATTRS(X) \
+ &therm_input[X].dev_attr.attr, \
+ &therm_status[X].dev_attr.attr, \
+ &therm_min[X].dev_attr.attr, \
+ &therm_max[X].dev_attr.attr, \
+ &therm_crit[X].dev_attr.attr
+
+static struct attribute * pc8736x_therm_attr_array[] = {
+ THERM_UNIT_ATTRS(0),
+ THERM_UNIT_ATTRS(1),
+ THERM_UNIT_ATTRS(2),
+ NULL
+};
+static const struct attribute_group pc8736x_therm_group = {
+ .attrs = pc8736x_therm_attr_array,
+};
static ssize_t show_temp_input(struct device *dev, struct device_attribute *devattr, char *buf)
{
@@ -735,6 +799,25 @@ static ssize_t show_temp_alarms(struct device *dev, struct device_attribute *att
}
static DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL);
+#define TEMP_UNIT_ATTRS(X) \
+ &temp_input[X].dev_attr.attr, \
+ &temp_status[X].dev_attr.attr, \
+ &temp_min[X].dev_attr.attr, \
+ &temp_max[X].dev_attr.attr, \
+ &temp_crit[X].dev_attr.attr
+
+static struct attribute * pc8736x_temp_attr_array[] = {
+ TEMP_UNIT_ATTRS(0),
+ TEMP_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(2),
+ /* include the few miscellaneous atts here */
+ &dev_attr_alarms_temp.attr,
+ NULL
+};
+static const struct attribute_group pc8736x_temp_group = {
+ .attrs = pc8736x_temp_attr_array,
+};
+
/*
* Device detection, registration and update
*/
@@ -935,60 +1018,69 @@ static int pc87360_detect(struct i2c_adapter *adapter)
pc87360_init_client(client, use_thermistors);
}
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ /* Register all-or-nothing sysfs groups */
+
+ if (data->innr &&
+ (err = sysfs_create_group(&client->dev.kobj,
+ &pc8736x_vin_group)))
goto ERROR3;
- }
- if (data->innr) {
- for (i = 0; i < 11; i++) {
- device_create_file(dev, &in_input[i].dev_attr);
- device_create_file(dev, &in_min[i].dev_attr);
- device_create_file(dev, &in_max[i].dev_attr);
- device_create_file(dev, &in_status[i].dev_attr);
- }
- device_create_file(dev, &dev_attr_cpu0_vid);
- device_create_file(dev, &dev_attr_vrm);
- device_create_file(dev, &dev_attr_alarms_in);
- }
+ if (data->innr == 14 &&
+ (err = sysfs_create_group(&client->dev.kobj,
+ &pc8736x_therm_group)))
+ goto ERROR3;
+
+ /* create device attr-files for varying sysfs groups */
if (data->tempnr) {
for (i = 0; i < data->tempnr; i++) {
- device_create_file(dev, &temp_input[i].dev_attr);
- device_create_file(dev, &temp_min[i].dev_attr);
- device_create_file(dev, &temp_max[i].dev_attr);
- device_create_file(dev, &temp_crit[i].dev_attr);
- device_create_file(dev, &temp_status[i].dev_attr);
- }
- device_create_file(dev, &dev_attr_alarms_temp);
- }
-
- if (data->innr == 14) {
- for (i = 0; i < 3; i++) {
- device_create_file(dev, &therm_input[i].dev_attr);
- device_create_file(dev, &therm_min[i].dev_attr);
- device_create_file(dev, &therm_max[i].dev_attr);
- device_create_file(dev, &therm_crit[i].dev_attr);
- device_create_file(dev, &therm_status[i].dev_attr);
+ if ((err = device_create_file(dev,
+ &temp_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_min[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_max[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_crit[i].dev_attr))
+ || (err = device_create_file(dev,
+ &temp_status[i].dev_attr)))
+ goto ERROR3;
}
+ if ((err = device_create_file(dev, &dev_attr_alarms_temp)))
+ goto ERROR3;
}
for (i = 0; i < data->fannr; i++) {
- if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {
- device_create_file(dev, &fan_input[i].dev_attr);
- device_create_file(dev, &fan_min[i].dev_attr);
- device_create_file(dev, &fan_div[i].dev_attr);
- device_create_file(dev, &fan_status[i].dev_attr);
- }
- if (FAN_CONFIG_CONTROL(data->fan_conf, i))
- device_create_file(dev, &pwm[i].dev_attr);
+ if (FAN_CONFIG_MONITOR(data->fan_conf, i)
+ && ((err = device_create_file(dev,
+ &fan_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &fan_min[i].dev_attr))
+ || (err = device_create_file(dev,
+ &fan_div[i].dev_attr))
+ || (err = device_create_file(dev,
+ &fan_status[i].dev_attr))))
+ goto ERROR3;
+
+ if (FAN_CONFIG_CONTROL(data->fan_conf, i)
+ && (err = device_create_file(dev, &pwm[i].dev_attr)))
+ goto ERROR3;
}
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR3;
+ }
return 0;
ERROR3:
+ /* can still remove groups whose members were added individually */
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
+
i2c_detach_client(client);
ERROR2:
for (i = 0; i < 3; i++) {
@@ -1008,6 +1100,11 @@ static int pc87360_detach_client(struct i2c_client *client)
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_temp_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_fan_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_therm_group);
+ sysfs_remove_group(&client->dev.kobj, &pc8736x_vin_group);
+
if ((i = i2c_detach_client(client)))
return i;
diff --git a/drivers/hwmon/sis5595.c b/drivers/hwmon/sis5595.c
index 063f71c5f07e..95a4b5d9eaf2 100644
--- a/drivers/hwmon/sis5595.c
+++ b/drivers/hwmon/sis5595.c
@@ -61,6 +61,7 @@
#include <linux/init.h>
#include <linux/jiffies.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
@@ -200,6 +201,7 @@ static void sis5595_init_client(struct i2c_client *client);
static struct i2c_driver sis5595_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "sis5595",
},
.attach_adapter = sis5595_detect,
@@ -472,6 +474,50 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
return sprintf(buf, "%d\n", data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+
+static struct attribute *sis5595_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group sis5595_group = {
+ .attrs = sis5595_attributes,
+};
+
+static struct attribute *sis5595_attributes_opt[] = {
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ NULL
+};
+
+static const struct attribute_group sis5595_group_opt = {
+ .attrs = sis5595_attributes_opt,
+};
/* This is called when the module is loaded */
static int sis5595_detect(struct i2c_adapter *adapter)
@@ -565,43 +611,37 @@ static int sis5595_detect(struct i2c_adapter *adapter)
}
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &sis5595_group)))
+ goto exit_detach;
+ if (data->maxins == 4) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in4_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in4_max)))
+ goto exit_remove_files;
+ } else {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_temp1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp1_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp1_max_hyst)))
+ goto exit_remove_files;
+ }
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- if (data->maxins == 4) {
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- }
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_alarms);
- if (data->maxins == 3) {
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- }
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&new_client->dev.kobj, &sis5595_group_opt);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -618,6 +658,8 @@ static int sis5595_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &sis5595_group);
+ sysfs_remove_group(&client->dev.kobj, &sis5595_group_opt);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index b6086186d225..72b0e2d8650c 100644
--- a/drivers/hwmon/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
@@ -176,9 +176,6 @@ sysfs_temp(2);
sysfs_temp(3);
sysfs_temp(4);
-#define device_create_file_temp(client, num) \
- device_create_file(&client->dev, &dev_attr_temp##num##_input)
-
/* FAN: 1 RPM/bit
REG: count of 90kHz pulses / revolution */
static int fan_from_reg(u16 reg)
@@ -205,8 +202,22 @@ sysfs_fan(2);
sysfs_fan(3);
sysfs_fan(4);
-#define device_create_file_fan(client, num) \
- device_create_file(&client->dev, &dev_attr_fan##num##_input)
+static struct attribute *smsc47b397_attributes[] = {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp4_input.attr,
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan4_input.attr,
+
+ NULL
+};
+
+static const struct attribute_group smsc47b397_group = {
+ .attrs = smsc47b397_attributes,
+};
static int smsc47b397_detach_client(struct i2c_client *client)
{
@@ -214,6 +225,7 @@ static int smsc47b397_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &smsc47b397_group);
if ((err = i2c_detach_client(client)))
return err;
@@ -228,6 +240,7 @@ static int smsc47b397_detect(struct i2c_adapter *adapter);
static struct i2c_driver smsc47b397_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "smsc47b397",
},
.attach_adapter = smsc47b397_detect,
@@ -267,24 +280,19 @@ static int smsc47b397_detect(struct i2c_adapter *adapter)
if ((err = i2c_attach_client(new_client)))
goto error_free;
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &smsc47b397_group)))
+ goto error_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto error_detach;
+ goto error_remove;
}
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- device_create_file_temp(new_client, 3);
- device_create_file_temp(new_client, 4);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
- device_create_file_fan(new_client, 4);
-
return 0;
+error_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &smsc47b397_group);
error_detach:
i2c_detach_client(new_client);
error_free:
diff --git a/drivers/hwmon/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 825e8f72698f..beb881c4b2e8 100644
--- a/drivers/hwmon/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
@@ -2,8 +2,8 @@
smsc47m1.c - Part of lm_sensors, Linux kernel modules
for hardware monitoring
- Supports the SMSC LPC47B27x, LPC47M10x, LPC47M13x, LPC47M14x,
- LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
+ Supports the SMSC LPC47B27x, LPC47M10x, LPC47M112, LPC47M13x,
+ LPC47M14x, LPC47M15x, LPC47M192 and LPC47M997 Super-I/O chips.
Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
@@ -35,6 +35,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
/* Address is autodetected, there is no default value */
@@ -128,6 +129,7 @@ static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,
static struct i2c_driver smsc47m1_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "smsc47m1",
},
.attach_adapter = smsc47m1_detect,
@@ -346,6 +348,30 @@ fan_present(2);
static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);
+/* Almost all sysfs files may or may not be created depending on the chip
+ setup so we create them individually. It is still convenient to define a
+ group to remove them all at once. */
+static struct attribute *smsc47m1_attributes[] = {
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm1_enable.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm2_enable.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group smsc47m1_group = {
+ .attrs = smsc47m1_attributes,
+};
+
static int __init smsc47m1_find(unsigned short *addr)
{
u8 val;
@@ -354,8 +380,8 @@ static int __init smsc47m1_find(unsigned short *addr)
val = superio_inb(SUPERIO_REG_DEVID);
/*
- * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id
- * 0x5F) and LPC47B27x (device id 0x51) have fan control.
+ * SMSC LPC47M10x/LPC47M112/LPC47M13x (device id 0x59), LPC47M14x
+ * (device id 0x5F) and LPC47B27x (device id 0x51) have fan control.
* The LPC47M15x and LPC47M192 chips "with hardware monitoring block"
* can do much more besides (device id 0x60).
* The LPC47M997 is undocumented, but seems to be compatible with
@@ -364,7 +390,8 @@ static int __init smsc47m1_find(unsigned short *addr)
if (val == 0x51)
printk(KERN_INFO "smsc47m1: Found SMSC LPC47B27x\n");
else if (val == 0x59)
- printk(KERN_INFO "smsc47m1: Found SMSC LPC47M10x/LPC47M13x\n");
+ printk(KERN_INFO "smsc47m1: Found SMSC "
+ "LPC47M10x/LPC47M112/LPC47M13x\n");
else if (val == 0x5F)
printk(KERN_INFO "smsc47m1: Found SMSC LPC47M14x\n");
else if (val == 0x60)
@@ -428,7 +455,8 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)
== 0x04;
if (!(fan1 || fan2 || pwm1 || pwm2)) {
- dev_warn(&new_client->dev, "Device is not configured, will not use\n");
+ dev_warn(&adapter->dev, "Device at 0x%x is not configured, "
+ "will not use\n", new_client->addr);
err = -ENODEV;
goto error_free;
}
@@ -445,46 +473,62 @@ static int smsc47m1_detect(struct i2c_adapter *adapter)
smsc47m1_update_device(&new_client->dev, 1);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- goto error_detach;
- }
-
if (fan1) {
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan1_div)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "
"skipping\n");
if (fan2) {
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan2_div)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "
"skipping\n");
if (pwm1) {
- device_create_file(&new_client->dev, &dev_attr_pwm1);
- device_create_file(&new_client->dev, &dev_attr_pwm1_enable);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pwm1))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_pwm1_enable)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "
"skipping\n");
if (pwm2) {
- device_create_file(&new_client->dev, &dev_attr_pwm2);
- device_create_file(&new_client->dev, &dev_attr_pwm2_enable);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pwm2))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_pwm2_enable)))
+ goto error_remove_files;
} else
dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "
"skipping\n");
- device_create_file(&new_client->dev, &dev_attr_alarms);
+ if ((err = device_create_file(&new_client->dev, &dev_attr_alarms)))
+ goto error_remove_files;
+
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto error_remove_files;
+ }
return 0;
-error_detach:
+error_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &smsc47m1_group);
i2c_detach_client(new_client);
error_free:
kfree(data);
@@ -499,6 +543,7 @@ static int smsc47m1_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m1_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/smsc47m192.c b/drivers/hwmon/smsc47m192.c
index bdc4570acf9a..a6833f437395 100644
--- a/drivers/hwmon/smsc47m192.c
+++ b/drivers/hwmon/smsc47m192.c
@@ -30,6 +30,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/hwmon-vid.h>
#include <linux/err.h>
+#include <linux/sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, I2C_CLIENT_END };
@@ -370,6 +371,75 @@ static SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 0x0200);
static SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 0x0400);
static SENSOR_DEVICE_ATTR(in7_alarm, S_IRUGO, show_alarm, NULL, 0x0800);
+static struct attribute *smsc47m192_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_alarm.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_alarm.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_alarm.dev_attr.attr,
+
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_offset.dev_attr.attr,
+ &sensor_dev_attr_temp1_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_offset.dev_attr.attr,
+ &sensor_dev_attr_temp2_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_input_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &sensor_dev_attr_temp3_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_input_fault.dev_attr.attr,
+
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ NULL
+};
+
+static const struct attribute_group smsc47m192_group = {
+ .attrs = smsc47m192_attributes,
+};
+
+static struct attribute *smsc47m192_attributes_in4[] = {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group smsc47m192_group_in4 = {
+ .attrs = smsc47m192_attributes_in4,
+};
+
/* This function is called when:
* smsc47m192_driver is inserted (when this module is loaded), for each
available adapter
@@ -471,80 +541,28 @@ static int smsc47m192_detect(struct i2c_adapter *adapter, int address,
smsc47m192_init_client(client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&client->dev.kobj, &smsc47m192_group)))
goto exit_detach;
- }
-
- device_create_file(&client->dev, &sensor_dev_attr_in0_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in0_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in0_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in0_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in1_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in2_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in3_alarm.dev_attr);
/* Pin 110 is either in4 (+12V) or VID4 */
config = i2c_smbus_read_byte_data(client, SMSC47M192_REG_CONFIG);
if (!(config & 0x20)) {
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_input.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_max.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_in4_alarm.dev_attr);
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &smsc47m192_group_in4)))
+ goto exit_remove_files;
+ }
+
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
- device_create_file(&client->dev, &sensor_dev_attr_in5_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in5_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in5_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in5_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in6_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_in7_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp1_offset.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp1_alarm.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp2_offset.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp2_alarm.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp2_input_fault.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_max.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_min.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp3_offset.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_temp3_alarm.dev_attr);
- device_create_file(&client->dev,
- &sensor_dev_attr_temp3_input_fault.dev_attr);
- device_create_file(&client->dev, &dev_attr_cpu0_vid);
- device_create_file(&client->dev, &dev_attr_vrm);
return 0;
+exit_remove_files:
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
exit_detach:
i2c_detach_client(client);
exit_free:
@@ -559,6 +577,8 @@ static int smsc47m192_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group);
+ sysfs_remove_group(&client->dev.kobj, &smsc47m192_group_in4);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/via686a.c b/drivers/hwmon/via686a.c
index 166298f1f190..f8acada0537a 100644
--- a/drivers/hwmon/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -40,6 +40,7 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
@@ -570,10 +571,53 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr, ch
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *via686a_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_max.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ &dev_attr_temp3_max_hyst.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group via686a_group = {
+ .attrs = via686a_attributes,
+};
+
/* The driver. I choose to use type i2c_driver, as at is identical to both
smbus_driver and isa_driver, and clients could be of either kind */
static struct i2c_driver via686a_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "via686a",
},
.attach_adapter = via686a_detect,
@@ -649,46 +693,19 @@ static int via686a_detect(struct i2c_adapter *adapter)
via686a_init_client(new_client);
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &via686a_group)))
+ goto exit_detach;
+
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove_files;
}
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
- device_create_file(&new_client->dev, &dev_attr_in2_input);
- device_create_file(&new_client->dev, &dev_attr_in3_input);
- device_create_file(&new_client->dev, &dev_attr_in4_input);
- device_create_file(&new_client->dev, &dev_attr_in0_min);
- device_create_file(&new_client->dev, &dev_attr_in1_min);
- device_create_file(&new_client->dev, &dev_attr_in2_min);
- device_create_file(&new_client->dev, &dev_attr_in3_min);
- device_create_file(&new_client->dev, &dev_attr_in4_min);
- device_create_file(&new_client->dev, &dev_attr_in0_max);
- device_create_file(&new_client->dev, &dev_attr_in1_max);
- device_create_file(&new_client->dev, &dev_attr_in2_max);
- device_create_file(&new_client->dev, &dev_attr_in3_max);
- device_create_file(&new_client->dev, &dev_attr_in4_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_input);
- device_create_file(&new_client->dev, &dev_attr_temp2_input);
- device_create_file(&new_client->dev, &dev_attr_temp3_input);
- device_create_file(&new_client->dev, &dev_attr_temp1_max);
- device_create_file(&new_client->dev, &dev_attr_temp2_max);
- device_create_file(&new_client->dev, &dev_attr_temp3_max);
- device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp2_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_temp3_max_hyst);
- device_create_file(&new_client->dev, &dev_attr_fan1_input);
- device_create_file(&new_client->dev, &dev_attr_fan2_input);
- device_create_file(&new_client->dev, &dev_attr_fan1_min);
- device_create_file(&new_client->dev, &dev_attr_fan2_min);
- device_create_file(&new_client->dev, &dev_attr_fan1_div);
- device_create_file(&new_client->dev, &dev_attr_fan2_div);
- device_create_file(&new_client->dev, &dev_attr_alarms);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&new_client->dev.kobj, &via686a_group);
exit_detach:
i2c_detach_client(new_client);
exit_free:
@@ -704,6 +721,7 @@ static int via686a_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &via686a_group);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/vt1211.c b/drivers/hwmon/vt1211.c
new file mode 100644
index 000000000000..25cc56003d7a
--- /dev/null
+++ b/drivers/hwmon/vt1211.c
@@ -0,0 +1,1355 @@
+/*
+ * vt1211.c - driver for the VIA VT1211 Super-I/O chip integrated hardware
+ * monitoring features
+ * Copyright (C) 2006 Juerg Haefliger <juergh@gmail.com>
+ *
+ * This driver is based on the driver for kernel 2.4 by Mark D. Studebaker
+ * and its port to kernel 2.6 by Lars Ekman.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/hwmon-vid.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <asm/io.h>
+
+static int uch_config = -1;
+module_param(uch_config, int, 0);
+MODULE_PARM_DESC(uch_config, "Initialize the universal channel configuration");
+
+static int int_mode = -1;
+module_param(int_mode, int, 0);
+MODULE_PARM_DESC(int_mode, "Force the temperature interrupt mode");
+
+static struct platform_device *pdev;
+
+#define DRVNAME "vt1211"
+
+/* ---------------------------------------------------------------------
+ * Registers
+ *
+ * The sensors are defined as follows.
+ *
+ * Sensor Voltage Mode Temp Mode Notes (from the datasheet)
+ * -------- ------------ --------- --------------------------
+ * Reading 1 temp1 Intel thermal diode
+ * Reading 3 temp2 Internal thermal diode
+ * UCH1/Reading2 in0 temp3 NTC type thermistor
+ * UCH2 in1 temp4 +2.5V
+ * UCH3 in2 temp5 VccP
+ * UCH4 in3 temp6 +5V
+ * UCH5 in4 temp7 +12V
+ * 3.3V in5 Internal VDD (+3.3V)
+ *
+ * --------------------------------------------------------------------- */
+
+/* Voltages (in) numbered 0-5 (ix) */
+#define VT1211_REG_IN(ix) (0x21 + (ix))
+#define VT1211_REG_IN_MIN(ix) ((ix) == 0 ? 0x3e : 0x2a + 2 * (ix))
+#define VT1211_REG_IN_MAX(ix) ((ix) == 0 ? 0x3d : 0x29 + 2 * (ix))
+
+/* Temperatures (temp) numbered 0-6 (ix) */
+static u8 regtemp[] = {0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25};
+static u8 regtempmax[] = {0x39, 0x1d, 0x3d, 0x2b, 0x2d, 0x2f, 0x31};
+static u8 regtemphyst[] = {0x3a, 0x1e, 0x3e, 0x2c, 0x2e, 0x30, 0x32};
+
+/* Fans numbered 0-1 (ix) */
+#define VT1211_REG_FAN(ix) (0x29 + (ix))
+#define VT1211_REG_FAN_MIN(ix) (0x3b + (ix))
+#define VT1211_REG_FAN_DIV 0x47
+
+/* PWMs numbered 0-1 (ix) */
+/* Auto points numbered 0-3 (ap) */
+#define VT1211_REG_PWM(ix) (0x60 + (ix))
+#define VT1211_REG_PWM_CLK 0x50
+#define VT1211_REG_PWM_CTL 0x51
+#define VT1211_REG_PWM_AUTO_TEMP(ap) (0x55 - (ap))
+#define VT1211_REG_PWM_AUTO_PWM(ix, ap) (0x58 + 2 * (ix) - (ap))
+
+/* Miscellaneous registers */
+#define VT1211_REG_CONFIG 0x40
+#define VT1211_REG_ALARM1 0x41
+#define VT1211_REG_ALARM2 0x42
+#define VT1211_REG_VID 0x45
+#define VT1211_REG_UCH_CONFIG 0x4a
+#define VT1211_REG_TEMP1_CONFIG 0x4b
+#define VT1211_REG_TEMP2_CONFIG 0x4c
+
+/* In, temp & fan alarm bits */
+static const u8 bitalarmin[] = {11, 0, 1, 3, 8, 2, 9};
+static const u8 bitalarmtemp[] = {4, 15, 11, 0, 1, 3, 8};
+static const u8 bitalarmfan[] = {6, 7};
+
+/* ---------------------------------------------------------------------
+ * Data structures and manipulation thereof
+ * --------------------------------------------------------------------- */
+
+struct vt1211_data {
+ unsigned short addr;
+ const char *name;
+ struct class_device *class_dev;
+
+ struct mutex update_lock;
+ char valid; /* !=0 if following fields are valid */
+ unsigned long last_updated; /* In jiffies */
+
+ /* Register values */
+ u8 in[6];
+ u8 in_max[6];
+ u8 in_min[6];
+ u8 temp[7];
+ u8 temp_max[7];
+ u8 temp_hyst[7];
+ u8 fan[2];
+ u8 fan_min[2];
+ u8 fan_div[2];
+ u8 fan_ctl;
+ u8 pwm[2];
+ u8 pwm_ctl[2];
+ u8 pwm_clk;
+ u8 pwm_auto_temp[4];
+ u8 pwm_auto_pwm[2][4];
+ u8 vid; /* Read once at init time */
+ u8 vrm;
+ u8 uch_config; /* Read once at init time */
+ u16 alarms;
+};
+
+/* ix = [0-5] */
+#define ISVOLT(ix, uch_config) ((ix) > 4 ? 1 : \
+ !(((uch_config) >> ((ix) + 2)) & 1))
+
+/* ix = [0-6] */
+#define ISTEMP(ix, uch_config) ((ix) < 2 ? 1 : \
+ ((uch_config) >> (ix)) & 1)
+
+/* in5 (ix = 5) is special. It's the internal 3.3V so it's scaled in the
+ driver according to the VT1211 BIOS porting guide */
+#define IN_FROM_REG(ix, reg) ((reg) < 3 ? 0 : (ix) == 5 ? \
+ (((reg) - 3) * 15882 + 479) / 958 : \
+ (((reg) - 3) * 10000 + 479) / 958)
+#define IN_TO_REG(ix, val) (SENSORS_LIMIT((ix) == 5 ? \
+ ((val) * 958 + 7941) / 15882 + 3 : \
+ ((val) * 958 + 5000) / 10000 + 3, 0, 255))
+
+/* temp1 (ix = 0) is an intel thermal diode which is scaled in user space.
+ temp2 (ix = 1) is the internal temp diode so it's scaled in the driver
+ according to some measurements that I took on an EPIA M10000.
+ temp3-7 are thermistor based so the driver returns the voltage measured at
+ the pin (range 0V - 2.2V). */
+#define TEMP_FROM_REG(ix, reg) ((ix) == 0 ? (reg) * 1000 : \
+ (ix) == 1 ? (reg) < 51 ? 0 : \
+ ((reg) - 51) * 1000 : \
+ ((253 - (reg)) * 2200 + 105) / 210)
+#define TEMP_TO_REG(ix, val) SENSORS_LIMIT( \
+ ((ix) == 0 ? ((val) + 500) / 1000 : \
+ (ix) == 1 ? ((val) + 500) / 1000 + 51 : \
+ 253 - ((val) * 210 + 1100) / 2200), 0, 255)
+
+#define DIV_FROM_REG(reg) (1 << (reg))
+
+#define RPM_FROM_REG(reg, div) (((reg) == 0) || ((reg) == 255) ? 0 : \
+ 1310720 / (reg) / DIV_FROM_REG(div))
+#define RPM_TO_REG(val, div) ((val) == 0 ? 255 : \
+ SENSORS_LIMIT((1310720 / (val) / \
+ DIV_FROM_REG(div)), 1, 254))
+
+/* ---------------------------------------------------------------------
+ * Super-I/O constants and functions
+ * --------------------------------------------------------------------- */
+
+/* Configuration & data index port registers */
+#define SIO_REG_CIP 0x2e
+#define SIO_REG_DIP 0x2f
+
+/* Configuration registers */
+#define SIO_VT1211_LDN 0x07 /* logical device number */
+#define SIO_VT1211_DEVID 0x20 /* device ID */
+#define SIO_VT1211_DEVREV 0x21 /* device revision */
+#define SIO_VT1211_ACTIVE 0x30 /* HW monitor active */
+#define SIO_VT1211_BADDR 0x60 /* base I/O address */
+#define SIO_VT1211_ID 0x3c /* VT1211 device ID */
+
+/* VT1211 logical device numbers */
+#define SIO_VT1211_LDN_HWMON 0x0b /* HW monitor */
+
+static inline void superio_outb(int reg, int val)
+{
+ outb(reg, SIO_REG_CIP);
+ outb(val, SIO_REG_DIP);
+}
+
+static inline int superio_inb(int reg)
+{
+ outb(reg, SIO_REG_CIP);
+ return inb(SIO_REG_DIP);
+}
+
+static inline void superio_select(int ldn)
+{
+ outb(SIO_VT1211_LDN, SIO_REG_CIP);
+ outb(ldn, SIO_REG_DIP);
+}
+
+static inline void superio_enter(void)
+{
+ outb(0x87, SIO_REG_CIP);
+ outb(0x87, SIO_REG_CIP);
+}
+
+static inline void superio_exit(void)
+{
+ outb(0xaa, SIO_REG_CIP);
+}
+
+/* ---------------------------------------------------------------------
+ * Device I/O access
+ * --------------------------------------------------------------------- */
+
+static inline u8 vt1211_read8(struct vt1211_data *data, u8 reg)
+{
+ return inb(data->addr + reg);
+}
+
+static inline void vt1211_write8(struct vt1211_data *data, u8 reg, u8 val)
+{
+ outb(val, data->addr + reg);
+}
+
+static struct vt1211_data *vt1211_update_device(struct device *dev)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ int ix, val;
+
+ mutex_lock(&data->update_lock);
+
+ /* registers cache is refreshed after 1 second */
+ if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
+ /* read VID */
+ data->vid = vt1211_read8(data, VT1211_REG_VID) & 0x1f;
+
+ /* voltage (in) registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->in); ix++) {
+ if (ISVOLT(ix, data->uch_config)) {
+ data->in[ix] = vt1211_read8(data,
+ VT1211_REG_IN(ix));
+ data->in_min[ix] = vt1211_read8(data,
+ VT1211_REG_IN_MIN(ix));
+ data->in_max[ix] = vt1211_read8(data,
+ VT1211_REG_IN_MAX(ix));
+ }
+ }
+
+ /* temp registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->temp); ix++) {
+ if (ISTEMP(ix, data->uch_config)) {
+ data->temp[ix] = vt1211_read8(data,
+ regtemp[ix]);
+ data->temp_max[ix] = vt1211_read8(data,
+ regtempmax[ix]);
+ data->temp_hyst[ix] = vt1211_read8(data,
+ regtemphyst[ix]);
+ }
+ }
+
+ /* fan & pwm registers */
+ for (ix = 0; ix < ARRAY_SIZE(data->fan); ix++) {
+ data->fan[ix] = vt1211_read8(data,
+ VT1211_REG_FAN(ix));
+ data->fan_min[ix] = vt1211_read8(data,
+ VT1211_REG_FAN_MIN(ix));
+ data->pwm[ix] = vt1211_read8(data,
+ VT1211_REG_PWM(ix));
+ }
+ val = vt1211_read8(data, VT1211_REG_FAN_DIV);
+ data->fan_div[0] = (val >> 4) & 3;
+ data->fan_div[1] = (val >> 6) & 3;
+ data->fan_ctl = val & 0xf;
+
+ val = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = val & 0xf;
+ data->pwm_ctl[1] = (val >> 4) & 0xf;
+
+ data->pwm_clk = vt1211_read8(data, VT1211_REG_PWM_CLK);
+
+ /* pwm & temp auto point registers */
+ data->pwm_auto_pwm[0][1] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(0, 1));
+ data->pwm_auto_pwm[0][2] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(0, 2));
+ data->pwm_auto_pwm[1][1] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(1, 1));
+ data->pwm_auto_pwm[1][2] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_PWM(1, 2));
+ for (ix = 0; ix < ARRAY_SIZE(data->pwm_auto_temp); ix++) {
+ data->pwm_auto_temp[ix] = vt1211_read8(data,
+ VT1211_REG_PWM_AUTO_TEMP(ix));
+ }
+
+ /* alarm registers */
+ data->alarms = (vt1211_read8(data, VT1211_REG_ALARM2) << 8) |
+ vt1211_read8(data, VT1211_REG_ALARM1);
+
+ data->last_updated = jiffies;
+ data->valid = 1;
+ }
+
+ mutex_unlock(&data->update_lock);
+
+ return data;
+}
+
+/* ---------------------------------------------------------------------
+ * Voltage sysfs interfaces
+ * ix = [0-5]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_IN_INPUT 0
+#define SHOW_SET_IN_MIN 1
+#define SHOW_SET_IN_MAX 2
+#define SHOW_IN_ALARM 3
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_IN_INPUT:
+ res = IN_FROM_REG(ix, data->in[ix]);
+ break;
+ case SHOW_SET_IN_MIN:
+ res = IN_FROM_REG(ix, data->in_min[ix]);
+ break;
+ case SHOW_SET_IN_MAX:
+ res = IN_FROM_REG(ix, data->in_max[ix]);
+ break;
+ case SHOW_IN_ALARM:
+ res = (data->alarms >> bitalarmin[ix]) & 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SHOW_SET_IN_MIN:
+ data->in_min[ix] = IN_TO_REG(ix, val);
+ vt1211_write8(data, VT1211_REG_IN_MIN(ix), data->in_min[ix]);
+ break;
+ case SHOW_SET_IN_MAX:
+ data->in_max[ix] = IN_TO_REG(ix, val);
+ vt1211_write8(data, VT1211_REG_IN_MAX(ix), data->in_max[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Temperature sysfs interfaces
+ * ix = [0-6]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_TEMP_INPUT 0
+#define SHOW_SET_TEMP_MAX 1
+#define SHOW_SET_TEMP_MAX_HYST 2
+#define SHOW_TEMP_ALARM 3
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_TEMP_INPUT:
+ res = TEMP_FROM_REG(ix, data->temp[ix]);
+ break;
+ case SHOW_SET_TEMP_MAX:
+ res = TEMP_FROM_REG(ix, data->temp_max[ix]);
+ break;
+ case SHOW_SET_TEMP_MAX_HYST:
+ res = TEMP_FROM_REG(ix, data->temp_hyst[ix]);
+ break;
+ case SHOW_TEMP_ALARM:
+ res = (data->alarms >> bitalarmtemp[ix]) & 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ mutex_lock(&data->update_lock);
+ switch (fn) {
+ case SHOW_SET_TEMP_MAX:
+ data->temp_max[ix] = TEMP_TO_REG(ix, val);
+ vt1211_write8(data, regtempmax[ix],
+ data->temp_max[ix]);
+ break;
+ case SHOW_SET_TEMP_MAX_HYST:
+ data->temp_hyst[ix] = TEMP_TO_REG(ix, val);
+ vt1211_write8(data, regtemphyst[ix],
+ data->temp_hyst[ix]);
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Fan sysfs interfaces
+ * ix = [0-1]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_FAN_INPUT 0
+#define SHOW_SET_FAN_MIN 1
+#define SHOW_SET_FAN_DIV 2
+#define SHOW_FAN_ALARM 3
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_FAN_INPUT:
+ res = RPM_FROM_REG(data->fan[ix], data->fan_div[ix]);
+ break;
+ case SHOW_SET_FAN_MIN:
+ res = RPM_FROM_REG(data->fan_min[ix], data->fan_div[ix]);
+ break;
+ case SHOW_SET_FAN_DIV:
+ res = DIV_FROM_REG(data->fan_div[ix]);
+ break;
+ case SHOW_FAN_ALARM:
+ res = (data->alarms >> bitalarmfan[ix]) & 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_fan(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+ int reg;
+
+ mutex_lock(&data->update_lock);
+
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
+ data->fan_div[0] = (reg >> 4) & 3;
+ data->fan_div[1] = (reg >> 6) & 3;
+ data->fan_ctl = reg & 0xf;
+
+ switch (fn) {
+ case SHOW_SET_FAN_MIN:
+ data->fan_min[ix] = RPM_TO_REG(val, data->fan_div[ix]);
+ vt1211_write8(data, VT1211_REG_FAN_MIN(ix),
+ data->fan_min[ix]);
+ break;
+ case SHOW_SET_FAN_DIV:
+ switch (val) {
+ case 1: data->fan_div[ix] = 0; break;
+ case 2: data->fan_div[ix] = 1; break;
+ case 4: data->fan_div[ix] = 2; break;
+ case 8: data->fan_div[ix] = 3; break;
+ default:
+ count = -EINVAL;
+ dev_warn(dev, "fan div value %ld not "
+ "supported. Choose one of 1, 2, "
+ "4, or 8.\n", val);
+ goto EXIT;
+ }
+ vt1211_write8(data, VT1211_REG_FAN_DIV,
+ ((data->fan_div[1] << 6) |
+ (data->fan_div[0] << 4) |
+ data->fan_ctl));
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+EXIT:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM sysfs interfaces
+ * ix = [0-1]
+ * --------------------------------------------------------------------- */
+
+#define SHOW_PWM 0
+#define SHOW_SET_PWM_ENABLE 1
+#define SHOW_SET_PWM_FREQ 2
+#define SHOW_SET_PWM_AUTO_CHANNELS_TEMP 3
+
+static ssize_t show_pwm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ int res;
+
+ switch (fn) {
+ case SHOW_PWM:
+ res = data->pwm[ix];
+ break;
+ case SHOW_SET_PWM_ENABLE:
+ res = ((data->pwm_ctl[ix] >> 3) & 1) ? 2 : 0;
+ break;
+ case SHOW_SET_PWM_FREQ:
+ res = 90000 >> (data->pwm_clk & 7);
+ break;
+ case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
+ res = (data->pwm_ctl[ix] & 7) + 1;
+ break;
+ default:
+ res = 0;
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+ return sprintf(buf, "%d\n", res);
+}
+
+static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int fn = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+ int tmp, reg;
+
+ mutex_lock(&data->update_lock);
+
+ switch (fn) {
+ case SHOW_SET_PWM_ENABLE:
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_FAN_DIV);
+ data->fan_div[0] = (reg >> 4) & 3;
+ data->fan_div[1] = (reg >> 6) & 3;
+ data->fan_ctl = reg & 0xf;
+ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = reg & 0xf;
+ data->pwm_ctl[1] = (reg >> 4) & 0xf;
+ switch (val) {
+ case 0:
+ data->pwm_ctl[ix] &= 7;
+ /* disable SmartGuardian if both PWM outputs are
+ * disabled */
+ if ((data->pwm_ctl[ix ^ 1] & 1) == 0) {
+ data->fan_ctl &= 0xe;
+ }
+ break;
+ case 2:
+ data->pwm_ctl[ix] |= 8;
+ data->fan_ctl |= 1;
+ break;
+ default:
+ count = -EINVAL;
+ dev_warn(dev, "pwm mode %ld not supported. "
+ "Choose one of 0 or 2.\n", val);
+ goto EXIT;
+ }
+ vt1211_write8(data, VT1211_REG_PWM_CTL,
+ ((data->pwm_ctl[1] << 4) |
+ data->pwm_ctl[0]));
+ vt1211_write8(data, VT1211_REG_FAN_DIV,
+ ((data->fan_div[1] << 6) |
+ (data->fan_div[0] << 4) |
+ data->fan_ctl));
+ break;
+ case SHOW_SET_PWM_FREQ:
+ val = 135000 / SENSORS_LIMIT(val, 135000 >> 7, 135000);
+ /* calculate tmp = log2(val) */
+ tmp = 0;
+ for (val >>= 1; val > 0; val >>= 1) {
+ tmp++;
+ }
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_PWM_CLK);
+ data->pwm_clk = (reg & 0xf8) | tmp;
+ vt1211_write8(data, VT1211_REG_PWM_CLK, data->pwm_clk);
+ break;
+ case SHOW_SET_PWM_AUTO_CHANNELS_TEMP:
+ if ((val < 1) || (val > 7)) {
+ count = -EINVAL;
+ dev_warn(dev, "temp channel %ld not supported. "
+ "Choose a value between 1 and 7.\n", val);
+ goto EXIT;
+ }
+ if (!ISTEMP(val - 1, data->uch_config)) {
+ count = -EINVAL;
+ dev_warn(dev, "temp channel %ld is not available.\n",
+ val);
+ goto EXIT;
+ }
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = reg & 0xf;
+ data->pwm_ctl[1] = (reg >> 4) & 0xf;
+ data->pwm_ctl[ix] = (data->pwm_ctl[ix] & 8) | (val - 1);
+ vt1211_write8(data, VT1211_REG_PWM_CTL,
+ ((data->pwm_ctl[1] << 4) | data->pwm_ctl[0]));
+ break;
+ default:
+ dev_dbg(dev, "Unknown attr fetch (%d)\n", fn);
+ }
+
+EXIT:
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * PWM auto point definitions
+ * ix = [0-1]
+ * ap = [0-3]
+ * --------------------------------------------------------------------- */
+
+/*
+ * pwm[ix+1]_auto_point[ap+1]_temp mapping table:
+ * Note that there is only a single set of temp auto points that controls both
+ * PWM controllers. We still create 2 sets of sysfs files to make it look
+ * more consistent even though they map to the same registers.
+ *
+ * ix ap : description
+ * -------------------
+ * 0 0 : pwm1/2 off temperature (pwm_auto_temp[0])
+ * 0 1 : pwm1/2 low speed temperature (pwm_auto_temp[1])
+ * 0 2 : pwm1/2 high speed temperature (pwm_auto_temp[2])
+ * 0 3 : pwm1/2 full speed temperature (pwm_auto_temp[3])
+ * 1 0 : pwm1/2 off temperature (pwm_auto_temp[0])
+ * 1 1 : pwm1/2 low speed temperature (pwm_auto_temp[1])
+ * 1 2 : pwm1/2 high speed temperature (pwm_auto_temp[2])
+ * 1 3 : pwm1/2 full speed temperature (pwm_auto_temp[3])
+ */
+
+static ssize_t show_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+
+ return sprintf(buf, "%d\n", TEMP_FROM_REG(data->pwm_ctl[ix] & 7,
+ data->pwm_auto_temp[ap]));
+}
+
+static ssize_t set_pwm_auto_point_temp(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+ int reg;
+
+ mutex_lock(&data->update_lock);
+
+ /* sync the data cache */
+ reg = vt1211_read8(data, VT1211_REG_PWM_CTL);
+ data->pwm_ctl[0] = reg & 0xf;
+ data->pwm_ctl[1] = (reg >> 4) & 0xf;
+
+ data->pwm_auto_temp[ap] = TEMP_TO_REG(data->pwm_ctl[ix] & 7, val);
+ vt1211_write8(data, VT1211_REG_PWM_AUTO_TEMP(ap),
+ data->pwm_auto_temp[ap]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/*
+ * pwm[ix+1]_auto_point[ap+1]_pwm mapping table:
+ * Note that the PWM auto points 0 & 3 are hard-wired in the VT1211 and can't
+ * be changed.
+ *
+ * ix ap : description
+ * -------------------
+ * 0 0 : pwm1 off (pwm_auto_pwm[0][0], hard-wired to 0)
+ * 0 1 : pwm1 low speed duty cycle (pwm_auto_pwm[0][1])
+ * 0 2 : pwm1 high speed duty cycle (pwm_auto_pwm[0][2])
+ * 0 3 : pwm1 full speed (pwm_auto_pwm[0][3], hard-wired to 255)
+ * 1 0 : pwm2 off (pwm_auto_pwm[1][0], hard-wired to 0)
+ * 1 1 : pwm2 low speed duty cycle (pwm_auto_pwm[1][1])
+ * 1 2 : pwm2 high speed duty cycle (pwm_auto_pwm[1][2])
+ * 1 3 : pwm2 full speed (pwm_auto_pwm[1][3], hard-wired to 255)
+*/
+
+static ssize_t show_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+
+ return sprintf(buf, "%d\n", data->pwm_auto_pwm[ix][ap]);
+}
+
+static ssize_t set_pwm_auto_point_pwm(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sensor_attr_2 =
+ to_sensor_dev_attr_2(attr);
+ int ix = sensor_attr_2->index;
+ int ap = sensor_attr_2->nr;
+ long val = simple_strtol(buf, NULL, 10);
+
+ if ((val < 0) || (val > 255)) {
+ dev_err(dev, "pwm value %ld is out of range. "
+ "Choose a value between 0 and 255." , val);
+ return -EINVAL;
+ }
+
+ mutex_lock(&data->update_lock);
+ data->pwm_auto_pwm[ix][ap] = val;
+ vt1211_write8(data, VT1211_REG_PWM_AUTO_PWM(ix, ap),
+ data->pwm_auto_pwm[ix][ap]);
+ mutex_unlock(&data->update_lock);
+
+ return count;
+}
+
+/* ---------------------------------------------------------------------
+ * Miscellaneous sysfs interfaces (VRM, VID, name, and (legacy) alarms)
+ * --------------------------------------------------------------------- */
+
+static ssize_t show_vrm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", data->vrm);
+}
+
+static ssize_t set_vrm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+ long val = simple_strtol(buf, NULL, 10);
+
+ data->vrm = val;
+
+ return count;
+}
+
+static ssize_t show_vid(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
+}
+
+static ssize_t show_name(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vt1211_data *data = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%s\n", data->name);
+}
+
+static ssize_t show_alarms(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct vt1211_data *data = vt1211_update_device(dev);
+
+ return sprintf(buf, "%d\n", data->alarms);
+}
+
+/* ---------------------------------------------------------------------
+ * Device attribute structs
+ * --------------------------------------------------------------------- */
+
+#define SENSOR_ATTR_IN_INPUT(ix) \
+ SENSOR_ATTR_2(in##ix##_input, S_IRUGO, \
+ show_in, NULL, SHOW_IN_INPUT, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_input[] = {
+ SENSOR_ATTR_IN_INPUT(0),
+ SENSOR_ATTR_IN_INPUT(1),
+ SENSOR_ATTR_IN_INPUT(2),
+ SENSOR_ATTR_IN_INPUT(3),
+ SENSOR_ATTR_IN_INPUT(4),
+ SENSOR_ATTR_IN_INPUT(5),
+};
+
+#define SENSOR_ATTR_IN_MIN(ix) \
+ SENSOR_ATTR_2(in##ix##_min, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SHOW_SET_IN_MIN, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_min[] = {
+ SENSOR_ATTR_IN_MIN(0),
+ SENSOR_ATTR_IN_MIN(1),
+ SENSOR_ATTR_IN_MIN(2),
+ SENSOR_ATTR_IN_MIN(3),
+ SENSOR_ATTR_IN_MIN(4),
+ SENSOR_ATTR_IN_MIN(5),
+};
+
+#define SENSOR_ATTR_IN_MAX(ix) \
+ SENSOR_ATTR_2(in##ix##_max, S_IRUGO | S_IWUSR, \
+ show_in, set_in, SHOW_SET_IN_MAX, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_max[] = {
+ SENSOR_ATTR_IN_MAX(0),
+ SENSOR_ATTR_IN_MAX(1),
+ SENSOR_ATTR_IN_MAX(2),
+ SENSOR_ATTR_IN_MAX(3),
+ SENSOR_ATTR_IN_MAX(4),
+ SENSOR_ATTR_IN_MAX(5),
+};
+
+#define SENSOR_ATTR_IN_ALARM(ix) \
+ SENSOR_ATTR_2(in##ix##_alarm, S_IRUGO, \
+ show_in, NULL, SHOW_IN_ALARM, ix)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_in_alarm[] = {
+ SENSOR_ATTR_IN_ALARM(0),
+ SENSOR_ATTR_IN_ALARM(1),
+ SENSOR_ATTR_IN_ALARM(2),
+ SENSOR_ATTR_IN_ALARM(3),
+ SENSOR_ATTR_IN_ALARM(4),
+ SENSOR_ATTR_IN_ALARM(5),
+};
+
+#define SENSOR_ATTR_TEMP_INPUT(ix) \
+ SENSOR_ATTR_2(temp##ix##_input, S_IRUGO, \
+ show_temp, NULL, SHOW_TEMP_INPUT, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_input[] = {
+ SENSOR_ATTR_TEMP_INPUT(1),
+ SENSOR_ATTR_TEMP_INPUT(2),
+ SENSOR_ATTR_TEMP_INPUT(3),
+ SENSOR_ATTR_TEMP_INPUT(4),
+ SENSOR_ATTR_TEMP_INPUT(5),
+ SENSOR_ATTR_TEMP_INPUT(6),
+ SENSOR_ATTR_TEMP_INPUT(7),
+};
+
+#define SENSOR_ATTR_TEMP_MAX(ix) \
+ SENSOR_ATTR_2(temp##ix##_max, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SHOW_SET_TEMP_MAX, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_max[] = {
+ SENSOR_ATTR_TEMP_MAX(1),
+ SENSOR_ATTR_TEMP_MAX(2),
+ SENSOR_ATTR_TEMP_MAX(3),
+ SENSOR_ATTR_TEMP_MAX(4),
+ SENSOR_ATTR_TEMP_MAX(5),
+ SENSOR_ATTR_TEMP_MAX(6),
+ SENSOR_ATTR_TEMP_MAX(7),
+};
+
+#define SENSOR_ATTR_TEMP_MAX_HYST(ix) \
+ SENSOR_ATTR_2(temp##ix##_max_hyst, S_IRUGO | S_IWUSR, \
+ show_temp, set_temp, SHOW_SET_TEMP_MAX_HYST, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_max_hyst[] = {
+ SENSOR_ATTR_TEMP_MAX_HYST(1),
+ SENSOR_ATTR_TEMP_MAX_HYST(2),
+ SENSOR_ATTR_TEMP_MAX_HYST(3),
+ SENSOR_ATTR_TEMP_MAX_HYST(4),
+ SENSOR_ATTR_TEMP_MAX_HYST(5),
+ SENSOR_ATTR_TEMP_MAX_HYST(6),
+ SENSOR_ATTR_TEMP_MAX_HYST(7),
+};
+
+#define SENSOR_ATTR_TEMP_ALARM(ix) \
+ SENSOR_ATTR_2(temp##ix##_alarm, S_IRUGO, \
+ show_temp, NULL, SHOW_TEMP_ALARM, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_temp_alarm[] = {
+ SENSOR_ATTR_TEMP_ALARM(1),
+ SENSOR_ATTR_TEMP_ALARM(2),
+ SENSOR_ATTR_TEMP_ALARM(3),
+ SENSOR_ATTR_TEMP_ALARM(4),
+ SENSOR_ATTR_TEMP_ALARM(5),
+ SENSOR_ATTR_TEMP_ALARM(6),
+ SENSOR_ATTR_TEMP_ALARM(7),
+};
+
+#define SENSOR_ATTR_FAN(ix) \
+ SENSOR_ATTR_2(fan##ix##_input, S_IRUGO, \
+ show_fan, NULL, SHOW_FAN_INPUT, ix-1), \
+ SENSOR_ATTR_2(fan##ix##_min, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SHOW_SET_FAN_MIN, ix-1), \
+ SENSOR_ATTR_2(fan##ix##_div, S_IRUGO | S_IWUSR, \
+ show_fan, set_fan, SHOW_SET_FAN_DIV, ix-1), \
+ SENSOR_ATTR_2(fan##ix##_alarm, S_IRUGO, \
+ show_fan, NULL, SHOW_FAN_ALARM, ix-1)
+
+#define SENSOR_ATTR_PWM(ix) \
+ SENSOR_ATTR_2(pwm##ix, S_IRUGO, \
+ show_pwm, NULL, SHOW_PWM, ix-1), \
+ SENSOR_ATTR_2(pwm##ix##_enable, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SHOW_SET_PWM_ENABLE, ix-1), \
+ SENSOR_ATTR_2(pwm##ix##_auto_channels_temp, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SHOW_SET_PWM_AUTO_CHANNELS_TEMP, ix-1)
+
+#define SENSOR_ATTR_PWM_FREQ(ix) \
+ SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO | S_IWUSR, \
+ show_pwm, set_pwm, SHOW_SET_PWM_FREQ, ix-1)
+
+#define SENSOR_ATTR_PWM_FREQ_RO(ix) \
+ SENSOR_ATTR_2(pwm##ix##_freq, S_IRUGO, \
+ show_pwm, NULL, SHOW_SET_PWM_FREQ, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO | S_IWUSR, \
+ show_pwm_auto_point_temp, set_pwm_auto_point_temp, \
+ ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_temp, S_IRUGO, \
+ show_pwm_auto_point_temp, NULL, \
+ ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_PWM(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO | S_IWUSR, \
+ show_pwm_auto_point_pwm, set_pwm_auto_point_pwm, \
+ ap-1, ix-1)
+
+#define SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(ix, ap) \
+ SENSOR_ATTR_2(pwm##ix##_auto_point##ap##_pwm, S_IRUGO, \
+ show_pwm_auto_point_pwm, NULL, \
+ ap-1, ix-1)
+
+static struct sensor_device_attribute_2 vt1211_sysfs_fan_pwm[] = {
+ SENSOR_ATTR_FAN(1),
+ SENSOR_ATTR_FAN(2),
+ SENSOR_ATTR_PWM(1),
+ SENSOR_ATTR_PWM(2),
+ SENSOR_ATTR_PWM_FREQ(1),
+ SENSOR_ATTR_PWM_FREQ_RO(2),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP(1, 4),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_TEMP_RO(2, 4),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(1, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(1, 4),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 1),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 2),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM(2, 3),
+ SENSOR_ATTR_PWM_AUTO_POINT_PWM_RO(2, 4),
+};
+
+static struct device_attribute vt1211_sysfs_misc[] = {
+ __ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm),
+ __ATTR(cpu0_vid, S_IRUGO, show_vid, NULL),
+ __ATTR(name, S_IRUGO, show_name, NULL),
+ __ATTR(alarms, S_IRUGO, show_alarms, NULL),
+};
+
+/* ---------------------------------------------------------------------
+ * Device registration and initialization
+ * --------------------------------------------------------------------- */
+
+static void __devinit vt1211_init_device(struct vt1211_data *data)
+{
+ /* set VRM */
+ data->vrm = vid_which_vrm();
+
+ /* Read (and initialize) UCH config */
+ data->uch_config = vt1211_read8(data, VT1211_REG_UCH_CONFIG);
+ if (uch_config > -1) {
+ data->uch_config = (data->uch_config & 0x83) |
+ (uch_config << 2);
+ vt1211_write8(data, VT1211_REG_UCH_CONFIG, data->uch_config);
+ }
+
+ /* Initialize the interrupt mode (if request at module load time).
+ * The VT1211 implements 3 different modes for clearing interrupts:
+ * 0: Clear INT when status register is read. Regenerate INT as long
+ * as temp stays above hysteresis limit.
+ * 1: Clear INT when status register is read. DON'T regenerate INT
+ * until temp falls below hysteresis limit and exceeds hot limit
+ * again.
+ * 2: Clear INT when temp falls below max limit.
+ *
+ * The driver only allows to force mode 0 since that's the only one
+ * that makes sense for 'sensors' */
+ if (int_mode == 0) {
+ vt1211_write8(data, VT1211_REG_TEMP1_CONFIG, 0);
+ vt1211_write8(data, VT1211_REG_TEMP2_CONFIG, 0);
+ }
+
+ /* Fill in some hard wired values into our data struct */
+ data->pwm_auto_pwm[0][3] = 255;
+ data->pwm_auto_pwm[1][3] = 255;
+}
+
+static void vt1211_remove_sysfs(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {
+ device_remove_file(dev,
+ &vt1211_sysfs_in_input[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_in_min[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_in_max[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_in_alarm[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_input[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_max[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_max_hyst[i].dev_attr);
+ device_remove_file(dev,
+ &vt1211_sysfs_temp_alarm[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
+ device_remove_file(dev,
+ &vt1211_sysfs_fan_pwm[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
+ device_remove_file(dev, &vt1211_sysfs_misc[i]);
+ }
+}
+
+static int __devinit vt1211_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct vt1211_data *data;
+ struct resource *res;
+ int i, err;
+
+ if (!(data = kzalloc(sizeof(struct vt1211_data), GFP_KERNEL))) {
+ err = -ENOMEM;
+ dev_err(dev, "Out of memory\n");
+ goto EXIT;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ data->addr = res->start;
+ data->name = DRVNAME;
+ mutex_init(&data->update_lock);
+
+ platform_set_drvdata(pdev, data);
+
+ /* Initialize the VT1211 chip */
+ vt1211_init_device(data);
+
+ /* Create sysfs interface files */
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_in_input); i++) {
+ if (ISVOLT(i, data->uch_config)) {
+ if ((err = device_create_file(dev,
+ &vt1211_sysfs_in_input[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_in_min[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_in_max[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_in_alarm[i].dev_attr))) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_temp_input); i++) {
+ if (ISTEMP(i, data->uch_config)) {
+ if ((err = device_create_file(dev,
+ &vt1211_sysfs_temp_input[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_temp_max[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_temp_max_hyst[i].dev_attr)) ||
+ (err = device_create_file(dev,
+ &vt1211_sysfs_temp_alarm[i].dev_attr))) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_fan_pwm); i++) {
+ err = device_create_file(dev,
+ &vt1211_sysfs_fan_pwm[i].dev_attr);
+ if (err) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+ for (i = 0; i < ARRAY_SIZE(vt1211_sysfs_misc); i++) {
+ err = device_create_file(dev,
+ &vt1211_sysfs_misc[i]);
+ if (err) {
+ goto EXIT_DEV_REMOVE;
+ }
+ }
+
+ /* Register device */
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ dev_err(dev, "Class registration failed (%d)\n", err);
+ goto EXIT_DEV_REMOVE_SILENT;
+ }
+
+ return 0;
+
+EXIT_DEV_REMOVE:
+ dev_err(dev, "Sysfs interface creation failed (%d)\n", err);
+EXIT_DEV_REMOVE_SILENT:
+ vt1211_remove_sysfs(pdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+EXIT:
+ return err;
+}
+
+static int __devexit vt1211_remove(struct platform_device *pdev)
+{
+ struct vt1211_data *data = platform_get_drvdata(pdev);
+
+ hwmon_device_unregister(data->class_dev);
+ vt1211_remove_sysfs(pdev);
+ platform_set_drvdata(pdev, NULL);
+ kfree(data);
+
+ return 0;
+}
+
+static struct platform_driver vt1211_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+ .probe = vt1211_probe,
+ .remove = __devexit_p(vt1211_remove),
+};
+
+static int __init vt1211_device_add(unsigned short address)
+{
+ struct resource res = {
+ .start = address,
+ .end = address + 0x7f,
+ .flags = IORESOURCE_IO,
+ };
+ int err;
+
+ pdev = platform_device_alloc(DRVNAME, address);
+ if (!pdev) {
+ err = -ENOMEM;
+ printk(KERN_ERR DRVNAME ": Device allocation failed (%d)\n",
+ err);
+ goto EXIT;
+ }
+
+ res.name = pdev->name;
+ err = platform_device_add_resources(pdev, &res, 1);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device resource addition failed "
+ "(%d)\n", err);
+ goto EXIT_DEV_PUT;
+ }
+
+ err = platform_device_add(pdev);
+ if (err) {
+ printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
+ err);
+ goto EXIT_DEV_PUT;
+ }
+
+ return 0;
+
+EXIT_DEV_PUT:
+ platform_device_put(pdev);
+EXIT:
+ return err;
+}
+
+static int __init vt1211_find(unsigned short *address)
+{
+ int err = -ENODEV;
+
+ superio_enter();
+
+ if (superio_inb(SIO_VT1211_DEVID) != SIO_VT1211_ID) {
+ goto EXIT;
+ }
+
+ superio_select(SIO_VT1211_LDN_HWMON);
+
+ if ((superio_inb(SIO_VT1211_ACTIVE) & 1) == 0) {
+ printk(KERN_WARNING DRVNAME ": HW monitor is disabled, "
+ "skipping\n");
+ goto EXIT;
+ }
+
+ *address = ((superio_inb(SIO_VT1211_BADDR) << 8) |
+ (superio_inb(SIO_VT1211_BADDR + 1))) & 0xff00;
+ if (*address == 0) {
+ printk(KERN_WARNING DRVNAME ": Base address is not set, "
+ "skipping\n");
+ goto EXIT;
+ }
+
+ err = 0;
+ printk(KERN_INFO DRVNAME ": Found VT1211 chip at 0x%04x, "
+ "revision %u\n", *address, superio_inb(SIO_VT1211_DEVREV));
+
+EXIT:
+ superio_exit();
+ return err;
+}
+
+static int __init vt1211_init(void)
+{
+ int err;
+ unsigned short address = 0;
+
+ err = vt1211_find(&address);
+ if (err) {
+ goto EXIT;
+ }
+
+ if ((uch_config < -1) || (uch_config > 31)) {
+ err = -EINVAL;
+ printk(KERN_WARNING DRVNAME ": Invalid UCH configuration %d. "
+ "Choose a value between 0 and 31.\n", uch_config);
+ goto EXIT;
+ }
+
+ if ((int_mode < -1) || (int_mode > 0)) {
+ err = -EINVAL;
+ printk(KERN_WARNING DRVNAME ": Invalid interrupt mode %d. "
+ "Only mode 0 is supported.\n", int_mode);
+ goto EXIT;
+ }
+
+ err = platform_driver_register(&vt1211_driver);
+ if (err) {
+ goto EXIT;
+ }
+
+ /* Sets global pdev as a side effect */
+ err = vt1211_device_add(address);
+ if (err) {
+ goto EXIT_DRV_UNREGISTER;
+ }
+
+ return 0;
+
+EXIT_DRV_UNREGISTER:
+ platform_driver_unregister(&vt1211_driver);
+EXIT:
+ return err;
+}
+
+static void __exit vt1211_exit(void)
+{
+ platform_device_unregister(pdev);
+ platform_driver_unregister(&vt1211_driver);
+}
+
+MODULE_AUTHOR("Juerg Haefliger <juergh@gmail.com>");
+MODULE_DESCRIPTION("VT1211 sensors");
+MODULE_LICENSE("GPL");
+
+module_init(vt1211_init);
+module_exit(vt1211_exit);
diff --git a/drivers/hwmon/vt8231.c b/drivers/hwmon/vt8231.c
index 686f3deb3093..93f93d4fb8ae 100644
--- a/drivers/hwmon/vt8231.c
+++ b/drivers/hwmon/vt8231.c
@@ -451,37 +451,6 @@ define_temperature_sysfs(4);
define_temperature_sysfs(5);
define_temperature_sysfs(6);
-#define CFG_INFO_TEMP(id) { &sensor_dev_attr_temp##id##_input.dev_attr, \
- &sensor_dev_attr_temp##id##_max_hyst.dev_attr, \
- &sensor_dev_attr_temp##id##_max.dev_attr }
-#define CFG_INFO_VOLT(id) { &sensor_dev_attr_in##id##_input.dev_attr, \
- &sensor_dev_attr_in##id##_min.dev_attr, \
- &sensor_dev_attr_in##id##_max.dev_attr }
-
-struct str_device_attr_table {
- struct device_attribute *input;
- struct device_attribute *min;
- struct device_attribute *max;
-};
-
-static struct str_device_attr_table cfg_info_temp[] = {
- { &dev_attr_temp1_input, &dev_attr_temp1_max_hyst, &dev_attr_temp1_max },
- CFG_INFO_TEMP(2),
- CFG_INFO_TEMP(3),
- CFG_INFO_TEMP(4),
- CFG_INFO_TEMP(5),
- CFG_INFO_TEMP(6)
-};
-
-static struct str_device_attr_table cfg_info_volt[] = {
- CFG_INFO_VOLT(0),
- CFG_INFO_VOLT(1),
- CFG_INFO_VOLT(2),
- CFG_INFO_VOLT(3),
- CFG_INFO_VOLT(4),
- { &dev_attr_in5_input, &dev_attr_in5_min, &dev_attr_in5_max }
-};
-
/* Fans */
static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -585,8 +554,110 @@ static ssize_t show_alarms(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL);
+static struct attribute *vt8231_attributes_temps[6][4] = {
+ {
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp1_max.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group vt8231_group_temps[6] = {
+ { .attrs = vt8231_attributes_temps[0] },
+ { .attrs = vt8231_attributes_temps[1] },
+ { .attrs = vt8231_attributes_temps[2] },
+ { .attrs = vt8231_attributes_temps[3] },
+ { .attrs = vt8231_attributes_temps[4] },
+ { .attrs = vt8231_attributes_temps[5] },
+};
+
+static struct attribute *vt8231_attributes_volts[6][4] = {
+ {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ NULL
+ }, {
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group vt8231_group_volts[6] = {
+ { .attrs = vt8231_attributes_volts[0] },
+ { .attrs = vt8231_attributes_volts[1] },
+ { .attrs = vt8231_attributes_volts[2] },
+ { .attrs = vt8231_attributes_volts[3] },
+ { .attrs = vt8231_attributes_volts[4] },
+ { .attrs = vt8231_attributes_volts[5] },
+};
+
+static struct attribute *vt8231_attributes[] = {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ NULL
+};
+
+static const struct attribute_group vt8231_group = {
+ .attrs = vt8231_attributes,
+};
+
static struct i2c_driver vt8231_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "vt8231",
},
.attach_adapter = vt8231_detect,
@@ -670,43 +741,43 @@ int vt8231_detect(struct i2c_adapter *adapter)
vt8231_init_client(client);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&client->dev.kobj, &vt8231_group)))
goto exit_detach;
- }
/* Must update device information to find out the config field */
data->uch_config = vt8231_read_value(client, VT8231_REG_UCH_CONFIG);
- for (i = 0; i < ARRAY_SIZE(cfg_info_temp); i++) {
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++) {
if (ISTEMP(i, data->uch_config)) {
- device_create_file(&client->dev,
- cfg_info_temp[i].input);
- device_create_file(&client->dev, cfg_info_temp[i].max);
- device_create_file(&client->dev, cfg_info_temp[i].min);
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &vt8231_group_temps[i])))
+ goto exit_remove_files;
}
}
- for (i = 0; i < ARRAY_SIZE(cfg_info_volt); i++) {
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++) {
if (ISVOLT(i, data->uch_config)) {
- device_create_file(&client->dev,
- cfg_info_volt[i].input);
- device_create_file(&client->dev, cfg_info_volt[i].max);
- device_create_file(&client->dev, cfg_info_volt[i].min);
+ if ((err = sysfs_create_group(&client->dev.kobj,
+ &vt8231_group_volts[i])))
+ goto exit_remove_files;
}
}
- device_create_file(&client->dev, &sensor_dev_attr_fan1_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan2_input.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan1_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan2_min.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan1_div.dev_attr);
- device_create_file(&client->dev, &sensor_dev_attr_fan2_div.dev_attr);
-
- device_create_file(&client->dev, &dev_attr_alarms);
+ data->class_dev = hwmon_device_register(&client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
+ }
return 0;
+exit_remove_files:
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group);
exit_detach:
i2c_detach_client(client);
exit_free:
@@ -719,10 +790,18 @@ exit_release:
static int vt8231_detach_client(struct i2c_client *client)
{
struct vt8231_data *data = i2c_get_clientdata(client);
- int err;
+ int err, i;
hwmon_device_unregister(data->class_dev);
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_volts); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_volts[i]);
+
+ for (i = 0; i < ARRAY_SIZE(vt8231_group_temps); i++)
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group_temps[i]);
+
+ sysfs_remove_group(&client->dev.kobj, &vt8231_group);
+
if ((err = i2c_detach_client(client))) {
return err;
}
diff --git a/drivers/hwmon/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 40301bc6ce18..2257806d0102 100644
--- a/drivers/hwmon/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
@@ -2,6 +2,9 @@
w83627ehf - Driver for the hardware monitoring functionality of
the Winbond W83627EHF Super-I/O chip
Copyright (C) 2005 Jean Delvare <khali@linux-fr.org>
+ Copyright (C) 2006 Yuan Mu (Winbond),
+ Rudolf Marek <r.marek@sh.cvut.cz>
+ David Hubbard <david.c.hubbard@gmail.com>
Shamelessly ripped from the w83627hf driver
Copyright (C) 2003 Mark Studebaker
@@ -29,8 +32,8 @@
Supports the following chips:
- Chip #vin #fan #pwm #temp chip_id man_id
- w83627ehf 10 5 - 3 0x88 0x5ca3
+ Chip #vin #fan #pwm #temp chip_id man_id
+ w83627ehf 10 5 4 3 0x88,0xa1 0x5ca3
*/
#include <linux/module.h>
@@ -145,10 +148,44 @@ static const u16 W83627EHF_REG_TEMP_CONFIG[] = { 0x152, 0x252 };
#define W83627EHF_REG_ALARM2 0x45A
#define W83627EHF_REG_ALARM3 0x45B
+/* SmartFan registers */
+/* DC or PWM output fan configuration */
+static const u8 W83627EHF_REG_PWM_ENABLE[] = {
+ 0x04, /* SYS FAN0 output mode and PWM mode */
+ 0x04, /* CPU FAN0 output mode and PWM mode */
+ 0x12, /* AUX FAN mode */
+ 0x62, /* CPU fan1 mode */
+};
+
+static const u8 W83627EHF_PWM_MODE_SHIFT[] = { 0, 1, 0, 6 };
+static const u8 W83627EHF_PWM_ENABLE_SHIFT[] = { 2, 4, 1, 4 };
+
+/* FAN Duty Cycle, be used to control */
+static const u8 W83627EHF_REG_PWM[] = { 0x01, 0x03, 0x11, 0x61 };
+static const u8 W83627EHF_REG_TARGET[] = { 0x05, 0x06, 0x13, 0x63 };
+static const u8 W83627EHF_REG_TOLERANCE[] = { 0x07, 0x07, 0x14, 0x62 };
+
+
+/* Advanced Fan control, some values are common for all fans */
+static const u8 W83627EHF_REG_FAN_MIN_OUTPUT[] = { 0x08, 0x09, 0x15, 0x64 };
+static const u8 W83627EHF_REG_FAN_STOP_TIME[] = { 0x0C, 0x0D, 0x17, 0x66 };
+
/*
* Conversions
*/
+/* 1 is PWM mode, output in ms */
+static inline unsigned int step_time_from_reg(u8 reg, u8 mode)
+{
+ return mode ? 100 * reg : 400 * reg;
+}
+
+static inline u8 step_time_to_reg(unsigned int msec, u8 mode)
+{
+ return SENSORS_LIMIT((mode ? (msec + 50) / 100 :
+ (msec + 200) / 400), 1, 255);
+}
+
static inline unsigned int
fan_from_reg(u8 reg, unsigned int div)
{
@@ -170,12 +207,12 @@ temp1_from_reg(s8 reg)
}
static inline s8
-temp1_to_reg(int temp)
+temp1_to_reg(int temp, int min, int max)
{
- if (temp <= -128000)
- return -128;
- if (temp >= 127000)
- return 127;
+ if (temp <= min)
+ return min / 1000;
+ if (temp >= max)
+ return max / 1000;
if (temp < 0)
return (temp - 500) / 1000;
return (temp + 500) / 1000;
@@ -223,6 +260,16 @@ struct w83627ehf_data {
s16 temp_max[2];
s16 temp_max_hyst[2];
u32 alarms;
+
+ u8 pwm_mode[4]; /* 0->DC variable voltage, 1->PWM variable duty cycle */
+ u8 pwm_enable[4]; /* 1->manual
+ 2->thermal cruise (also called SmartFan I) */
+ u8 pwm[4];
+ u8 target_temp[4];
+ u8 tolerance[4];
+
+ u8 fan_min_output[4]; /* minimum fan speed */
+ u8 fan_stop_time[4];
};
static inline int is_word_sized(u16 reg)
@@ -307,6 +354,8 @@ static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
case 0:
reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0xcf)
| ((data->fan_div[0] & 0x03) << 4);
+ /* fan5 input control bit is write only, compute the value */
+ reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xdf)
| ((data->fan_div[0] & 0x04) << 3);
@@ -315,6 +364,8 @@ static void w83627ehf_write_fan_div(struct i2c_client *client, int nr)
case 1:
reg = (w83627ehf_read_value(client, W83627EHF_REG_FANDIV1) & 0x3f)
| ((data->fan_div[1] & 0x03) << 6);
+ /* fan5 input control bit is write only, compute the value */
+ reg |= (data->has_fan & (1 << 4)) ? 1 : 0;
w83627ehf_write_value(client, W83627EHF_REG_FANDIV1, reg);
reg = (w83627ehf_read_value(client, W83627EHF_REG_VBAT) & 0xbf)
| ((data->fan_div[1] & 0x04) << 4);
@@ -349,6 +400,7 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct w83627ehf_data *data = i2c_get_clientdata(client);
+ int pwmcfg = 0, tolerance = 0; /* shut up the compiler */
int i;
mutex_lock(&data->update_lock);
@@ -416,6 +468,34 @@ static struct w83627ehf_data *w83627ehf_update_device(struct device *dev)
}
}
+ for (i = 0; i < 4; i++) {
+ /* pwmcfg, tolarance mapped for i=0, i=1 to same reg */
+ if (i != 1) {
+ pwmcfg = w83627ehf_read_value(client,
+ W83627EHF_REG_PWM_ENABLE[i]);
+ tolerance = w83627ehf_read_value(client,
+ W83627EHF_REG_TOLERANCE[i]);
+ }
+ data->pwm_mode[i] =
+ ((pwmcfg >> W83627EHF_PWM_MODE_SHIFT[i]) & 1)
+ ? 0 : 1;
+ data->pwm_enable[i] =
+ ((pwmcfg >> W83627EHF_PWM_ENABLE_SHIFT[i])
+ & 3) + 1;
+ data->pwm[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_PWM[i]);
+ data->fan_min_output[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN_MIN_OUTPUT[i]);
+ data->fan_stop_time[i] = w83627ehf_read_value(client,
+ W83627EHF_REG_FAN_STOP_TIME[i]);
+ data->target_temp[i] =
+ w83627ehf_read_value(client,
+ W83627EHF_REG_TARGET[i]) &
+ (data->pwm_mode[i] == 1 ? 0x7f : 0xff);
+ data->tolerance[i] = (tolerance >> (i == 1 ? 4 : 0))
+ & 0x0f;
+ }
+
/* Measured temperatures and limits */
data->temp1 = w83627ehf_read_value(client,
W83627EHF_REG_TEMP1);
@@ -546,14 +626,6 @@ static struct sensor_device_attribute sda_in_max[] = {
SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 9),
};
-static void device_create_file_in(struct device *dev, int i)
-{
- device_create_file(dev, &sda_in_input[i].dev_attr);
- device_create_file(dev, &sda_in_alarm[i].dev_attr);
- device_create_file(dev, &sda_in_min[i].dev_attr);
- device_create_file(dev, &sda_in_max[i].dev_attr);
-}
-
#define show_fan_reg(reg) \
static ssize_t \
show_##reg(struct device *dev, struct device_attribute *attr, \
@@ -681,14 +753,6 @@ static struct sensor_device_attribute sda_fan_div[] = {
SENSOR_ATTR(fan5_div, S_IRUGO, show_fan_div, NULL, 4),
};
-static void device_create_file_fan(struct device *dev, int i)
-{
- device_create_file(dev, &sda_fan_input[i].dev_attr);
- device_create_file(dev, &sda_fan_alarm[i].dev_attr);
- device_create_file(dev, &sda_fan_div[i].dev_attr);
- device_create_file(dev, &sda_fan_min[i].dev_attr);
-}
-
#define show_temp1_reg(reg) \
static ssize_t \
show_##reg(struct device *dev, struct device_attribute *attr, \
@@ -711,7 +775,7 @@ store_temp1_##reg(struct device *dev, struct device_attribute *attr, \
u32 val = simple_strtoul(buf, NULL, 10); \
\
mutex_lock(&data->update_lock); \
- data->temp1_##reg = temp1_to_reg(val); \
+ data->temp1_##reg = temp1_to_reg(val, -128000, 127000); \
w83627ehf_write_value(client, W83627EHF_REG_TEMP1_##REG, \
data->temp1_##reg); \
mutex_unlock(&data->update_lock); \
@@ -777,10 +841,309 @@ static struct sensor_device_attribute sda_temp[] = {
SENSOR_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 13),
};
+#define show_pwm_reg(reg) \
+static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", data->reg[nr]); \
+}
+
+show_pwm_reg(pwm_mode)
+show_pwm_reg(pwm_enable)
+show_pwm_reg(pwm)
+
+static ssize_t
+store_pwm_mode(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u16 reg;
+
+ if (val > 1)
+ return -EINVAL;
+ mutex_lock(&data->update_lock);
+ reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ data->pwm_mode[nr] = val;
+ reg &= ~(1 << W83627EHF_PWM_MODE_SHIFT[nr]);
+ if (!val)
+ reg |= 1 << W83627EHF_PWM_MODE_SHIFT[nr];
+ w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_pwm(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 0, 255);
+
+ mutex_lock(&data->update_lock);
+ data->pwm[nr] = val;
+ w83627ehf_write_value(client, W83627EHF_REG_PWM[nr], val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_pwm_enable(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u32 val = simple_strtoul(buf, NULL, 10);
+ u16 reg;
+
+ if (!val || (val > 2)) /* only modes 1 and 2 are supported */
+ return -EINVAL;
+ mutex_lock(&data->update_lock);
+ reg = w83627ehf_read_value(client, W83627EHF_REG_PWM_ENABLE[nr]);
+ data->pwm_enable[nr] = val;
+ reg &= ~(0x03 << W83627EHF_PWM_ENABLE_SHIFT[nr]);
+ reg |= (val - 1) << W83627EHF_PWM_ENABLE_SHIFT[nr];
+ w83627ehf_write_value(client, W83627EHF_REG_PWM_ENABLE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+
+#define show_tol_temp(reg) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", temp1_from_reg(data->reg[nr])); \
+}
+
+show_tol_temp(tolerance)
+show_tol_temp(target_temp)
+
+static ssize_t
+store_target_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 127000);
+
+ mutex_lock(&data->update_lock);
+ data->target_temp[nr] = val;
+ w83627ehf_write_value(client, W83627EHF_REG_TARGET[nr], val);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static ssize_t
+store_tolerance(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct w83627ehf_data *data = i2c_get_clientdata(client);
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
+ int nr = sensor_attr->index;
+ u16 reg;
+ /* Limit the temp to 0C - 15C */
+ u8 val = temp1_to_reg(simple_strtoul(buf, NULL, 10), 0, 15000);
+
+ mutex_lock(&data->update_lock);
+ reg = w83627ehf_read_value(client, W83627EHF_REG_TOLERANCE[nr]);
+ data->tolerance[nr] = val;
+ if (nr == 1)
+ reg = (reg & 0x0f) | (val << 4);
+ else
+ reg = (reg & 0xf0) | val;
+ w83627ehf_write_value(client, W83627EHF_REG_TOLERANCE[nr], reg);
+ mutex_unlock(&data->update_lock);
+ return count;
+}
+
+static struct sensor_device_attribute sda_pwm[] = {
+ SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
+ SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
+ SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
+ SENSOR_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 3),
+};
+
+static struct sensor_device_attribute sda_pwm_mode[] = {
+ SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 0),
+ SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 1),
+ SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 2),
+ SENSOR_ATTR(pwm4_mode, S_IWUSR | S_IRUGO, show_pwm_mode,
+ store_pwm_mode, 3),
+};
+
+static struct sensor_device_attribute sda_pwm_enable[] = {
+ SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 0),
+ SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 1),
+ SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 2),
+ SENSOR_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_enable,
+ store_pwm_enable, 3),
+};
+
+static struct sensor_device_attribute sda_target_temp[] = {
+ SENSOR_ATTR(pwm1_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 0),
+ SENSOR_ATTR(pwm2_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 1),
+ SENSOR_ATTR(pwm3_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 2),
+ SENSOR_ATTR(pwm4_target, S_IWUSR | S_IRUGO, show_target_temp,
+ store_target_temp, 3),
+};
+
+static struct sensor_device_attribute sda_tolerance[] = {
+ SENSOR_ATTR(pwm1_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 0),
+ SENSOR_ATTR(pwm2_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 1),
+ SENSOR_ATTR(pwm3_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 2),
+ SENSOR_ATTR(pwm4_tolerance, S_IWUSR | S_IRUGO, show_tolerance,
+ store_tolerance, 3),
+};
+
+/* Smart Fan registers */
+
+#define fan_functions(reg, REG) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", data->reg[nr]); \
+}\
+static ssize_t \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{\
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ u32 val = SENSORS_LIMIT(simple_strtoul(buf, NULL, 10), 1, 255); \
+ mutex_lock(&data->update_lock); \
+ data->reg[nr] = val; \
+ w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ mutex_unlock(&data->update_lock); \
+ return count; \
+}
+
+fan_functions(fan_min_output, FAN_MIN_OUTPUT)
+
+#define fan_time_functions(reg, REG) \
+static ssize_t show_##reg(struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct w83627ehf_data *data = w83627ehf_update_device(dev); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ return sprintf(buf, "%d\n", \
+ step_time_from_reg(data->reg[nr], data->pwm_mode[nr])); \
+} \
+\
+static ssize_t \
+store_##reg(struct device *dev, struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct i2c_client *client = to_i2c_client(dev); \
+ struct w83627ehf_data *data = i2c_get_clientdata(client); \
+ struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr); \
+ int nr = sensor_attr->index; \
+ u8 val = step_time_to_reg(simple_strtoul(buf, NULL, 10), \
+ data->pwm_mode[nr]); \
+ mutex_lock(&data->update_lock); \
+ data->reg[nr] = val; \
+ w83627ehf_write_value(client, W83627EHF_REG_##REG[nr], val); \
+ mutex_unlock(&data->update_lock); \
+ return count; \
+} \
+
+fan_time_functions(fan_stop_time, FAN_STOP_TIME)
+
+
+static struct sensor_device_attribute sda_sf3_arrays_fan4[] = {
+ SENSOR_ATTR(pwm4_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 3),
+ SENSOR_ATTR(pwm4_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 3),
+};
+
+static struct sensor_device_attribute sda_sf3_arrays[] = {
+ SENSOR_ATTR(pwm1_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 0),
+ SENSOR_ATTR(pwm2_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 1),
+ SENSOR_ATTR(pwm3_stop_time, S_IWUSR | S_IRUGO, show_fan_stop_time,
+ store_fan_stop_time, 2),
+ SENSOR_ATTR(pwm1_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 0),
+ SENSOR_ATTR(pwm2_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 1),
+ SENSOR_ATTR(pwm3_min_output, S_IWUSR | S_IRUGO, show_fan_min_output,
+ store_fan_min_output, 2),
+};
+
/*
* Driver and client management
*/
+static void w83627ehf_device_remove_files(struct device *dev)
+{
+ /* some entries in the following arrays may not have been used in
+ * device_create_file(), but device_remove_file() will ignore them */
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
+ device_remove_file(dev, &sda_sf3_arrays[i].dev_attr);
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++)
+ device_remove_file(dev, &sda_sf3_arrays_fan4[i].dev_attr);
+ for (i = 0; i < 10; i++) {
+ device_remove_file(dev, &sda_in_input[i].dev_attr);
+ device_remove_file(dev, &sda_in_alarm[i].dev_attr);
+ device_remove_file(dev, &sda_in_min[i].dev_attr);
+ device_remove_file(dev, &sda_in_max[i].dev_attr);
+ }
+ for (i = 0; i < 5; i++) {
+ device_remove_file(dev, &sda_fan_input[i].dev_attr);
+ device_remove_file(dev, &sda_fan_alarm[i].dev_attr);
+ device_remove_file(dev, &sda_fan_div[i].dev_attr);
+ device_remove_file(dev, &sda_fan_min[i].dev_attr);
+ }
+ for (i = 0; i < 4; i++) {
+ device_remove_file(dev, &sda_pwm[i].dev_attr);
+ device_remove_file(dev, &sda_pwm_mode[i].dev_attr);
+ device_remove_file(dev, &sda_pwm_enable[i].dev_attr);
+ device_remove_file(dev, &sda_target_temp[i].dev_attr);
+ device_remove_file(dev, &sda_tolerance[i].dev_attr);
+ }
+ for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
+ device_remove_file(dev, &sda_temp[i].dev_attr);
+}
+
static struct i2c_driver w83627ehf_driver;
static void w83627ehf_init_client(struct i2c_client *client)
@@ -810,6 +1173,7 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
struct i2c_client *client;
struct w83627ehf_data *data;
struct device *dev;
+ u8 fan4pin, fan5pin;
int i, err = 0;
if (!request_region(address + REGION_OFFSET, REGION_LENGTH,
@@ -848,35 +1212,90 @@ static int w83627ehf_detect(struct i2c_adapter *adapter)
data->fan_min[i] = w83627ehf_read_value(client,
W83627EHF_REG_FAN_MIN[i]);
+ /* fan4 and fan5 share some pins with the GPIO and serial flash */
+
+ superio_enter();
+ fan5pin = superio_inb(0x24) & 0x2;
+ fan4pin = superio_inb(0x29) & 0x6;
+ superio_exit();
+
/* It looks like fan4 and fan5 pins can be alternatively used
- as fan on/off switches */
+ as fan on/off switches, but fan5 control is write only :/
+ We assume that if the serial interface is disabled, designers
+ connected fan5 as input unless they are emitting log 1, which
+ is not the default. */
+
data->has_fan = 0x07; /* fan1, fan2 and fan3 */
i = w83627ehf_read_value(client, W83627EHF_REG_FANDIV1);
- if (i & (1 << 2))
+ if ((i & (1 << 2)) && (!fan4pin))
data->has_fan |= (1 << 3);
- if (i & (1 << 0))
+ if (!(i & (1 << 1)) && (!fan5pin))
data->has_fan |= (1 << 4);
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
- goto exit_detach;
- }
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays); i++)
+ if ((err = device_create_file(dev,
+ &sda_sf3_arrays[i].dev_attr)))
+ goto exit_remove;
+
+ /* if fan4 is enabled create the sf3 files for it */
+ if (data->has_fan & (1 << 3))
+ for (i = 0; i < ARRAY_SIZE(sda_sf3_arrays_fan4); i++) {
+ if ((err = device_create_file(dev,
+ &sda_sf3_arrays_fan4[i].dev_attr)))
+ goto exit_remove;
+ }
for (i = 0; i < 10; i++)
- device_create_file_in(dev, i);
+ if ((err = device_create_file(dev, &sda_in_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_in_alarm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_in_min[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_in_max[i].dev_attr)))
+ goto exit_remove;
for (i = 0; i < 5; i++) {
- if (data->has_fan & (1 << i))
- device_create_file_fan(dev, i);
+ if (data->has_fan & (1 << i)) {
+ if ((err = device_create_file(dev,
+ &sda_fan_input[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_fan_alarm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_fan_div[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_fan_min[i].dev_attr)))
+ goto exit_remove;
+ if (i < 4 && /* w83627ehf only has 4 pwm */
+ ((err = device_create_file(dev,
+ &sda_pwm[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_pwm_mode[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_pwm_enable[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_target_temp[i].dev_attr))
+ || (err = device_create_file(dev,
+ &sda_tolerance[i].dev_attr))))
+ goto exit_remove;
+ }
}
+
for (i = 0; i < ARRAY_SIZE(sda_temp); i++)
- device_create_file(dev, &sda_temp[i].dev_attr);
+ if ((err = device_create_file(dev, &sda_temp[i].dev_attr)))
+ goto exit_remove;
+
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove;
+ }
return 0;
-exit_detach:
+exit_remove:
+ w83627ehf_device_remove_files(dev);
i2c_detach_client(client);
exit_free:
kfree(data);
@@ -892,6 +1311,7 @@ static int w83627ehf_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
+ w83627ehf_device_remove_files(&client->dev);
if ((err = i2c_detach_client(client)))
return err;
@@ -903,6 +1323,7 @@ static int w83627ehf_detach_client(struct i2c_client *client)
static struct i2c_driver w83627ehf_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "w83627ehf",
},
.attach_adapter = w83627ehf_detect,
diff --git a/drivers/hwmon/w83627hf.c b/drivers/hwmon/w83627hf.c
index 79368d53c363..dfdc29c77123 100644
--- a/drivers/hwmon/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
@@ -339,6 +339,7 @@ static void w83627hf_init_client(struct i2c_client *client);
static struct i2c_driver w83627hf_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "w83627hf",
},
.attach_adapter = w83627hf_detect,
@@ -511,13 +512,6 @@ static DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR,
static DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR,
show_regs_in_max0, store_regs_in_max0);
-#define device_create_file_in(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_in##offset##_input); \
-device_create_file(&client->dev, &dev_attr_in##offset##_min); \
-device_create_file(&client->dev, &dev_attr_in##offset##_max); \
-} while (0)
-
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -575,12 +569,6 @@ sysfs_fan_min_offset(2);
sysfs_fan_offset(3);
sysfs_fan_min_offset(3);
-#define device_create_file_fan(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
-device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
-} while (0)
-
#define show_temp_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -655,13 +643,6 @@ sysfs_temp_offsets(1);
sysfs_temp_offsets(2);
sysfs_temp_offsets(3);
-#define device_create_file_temp(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
-} while (0)
-
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -669,8 +650,6 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid)
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -691,8 +670,6 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
return count;
}
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm)
static ssize_t
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -701,8 +678,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) data->alarms);
}
static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms)
#define show_beep_reg(REG, reg) \
static ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \
@@ -765,12 +740,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \
sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
-#define device_create_file_beep(client) \
-do { \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask); \
-} while (0)
-
static ssize_t
show_fan_div_reg(struct device *dev, char *buf, int nr)
{
@@ -836,11 +805,6 @@ sysfs_fan_div(1);
sysfs_fan_div(2);
sysfs_fan_div(3);
-#define device_create_file_fan_div(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
-} while (0)
-
static ssize_t
show_pwm_reg(struct device *dev, char *buf, int nr)
{
@@ -895,11 +859,6 @@ sysfs_pwm(1);
sysfs_pwm(2);
sysfs_pwm(3);
-#define device_create_file_pwm(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset); \
-} while (0)
-
static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
@@ -971,12 +930,6 @@ sysfs_sensor(1);
sysfs_sensor(2);
sysfs_sensor(3);
-#define device_create_file_sensor(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
-} while (0)
-
-
static int __init w83627hf_find(int sioaddr, unsigned short *addr)
{
u16 val;
@@ -1008,6 +961,85 @@ static int __init w83627hf_find(int sioaddr, unsigned short *addr)
return 0;
}
+static struct attribute *w83627hf_attributes[] = {
+ &dev_attr_in0_input.attr,
+ &dev_attr_in0_min.attr,
+ &dev_attr_in0_max.attr,
+ &dev_attr_in2_input.attr,
+ &dev_attr_in2_min.attr,
+ &dev_attr_in2_max.attr,
+ &dev_attr_in3_input.attr,
+ &dev_attr_in3_min.attr,
+ &dev_attr_in3_max.attr,
+ &dev_attr_in4_input.attr,
+ &dev_attr_in4_min.attr,
+ &dev_attr_in4_max.attr,
+ &dev_attr_in7_input.attr,
+ &dev_attr_in7_min.attr,
+ &dev_attr_in7_max.attr,
+ &dev_attr_in8_input.attr,
+ &dev_attr_in8_min.attr,
+ &dev_attr_in8_max.attr,
+
+ &dev_attr_fan1_input.attr,
+ &dev_attr_fan1_min.attr,
+ &dev_attr_fan1_div.attr,
+ &dev_attr_fan2_input.attr,
+ &dev_attr_fan2_min.attr,
+ &dev_attr_fan2_div.attr,
+
+ &dev_attr_temp1_input.attr,
+ &dev_attr_temp1_max.attr,
+ &dev_attr_temp1_max_hyst.attr,
+ &dev_attr_temp1_type.attr,
+ &dev_attr_temp2_input.attr,
+ &dev_attr_temp2_max.attr,
+ &dev_attr_temp2_max_hyst.attr,
+ &dev_attr_temp2_type.attr,
+
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_enable.attr,
+ &dev_attr_beep_mask.attr,
+
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+
+ NULL
+};
+
+static const struct attribute_group w83627hf_group = {
+ .attrs = w83627hf_attributes,
+};
+
+static struct attribute *w83627hf_attributes_opt[] = {
+ &dev_attr_in1_input.attr,
+ &dev_attr_in1_min.attr,
+ &dev_attr_in1_max.attr,
+ &dev_attr_in5_input.attr,
+ &dev_attr_in5_min.attr,
+ &dev_attr_in5_max.attr,
+ &dev_attr_in6_input.attr,
+ &dev_attr_in6_min.attr,
+ &dev_attr_in6_max.attr,
+
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_min.attr,
+ &dev_attr_fan3_div.attr,
+
+ &dev_attr_temp3_input.attr,
+ &dev_attr_temp3_max.attr,
+ &dev_attr_temp3_max_hyst.attr,
+ &dev_attr_temp3_type.attr,
+
+ &dev_attr_pwm3.attr,
+
+ NULL
+};
+
+static const struct attribute_group w83627hf_group_opt = {
+ .attrs = w83627hf_attributes_opt,
+};
+
static int w83627hf_detect(struct i2c_adapter *adapter)
{
int val, kind;
@@ -1107,62 +1139,72 @@ static int w83627hf_detect(struct i2c_adapter *adapter)
data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2));
data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3));
- /* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ /* Register common device attributes */
+ if ((err = sysfs_create_group(&new_client->dev.kobj, &w83627hf_group)))
goto ERROR3;
- }
-
- device_create_file_in(new_client, 0);
- if (kind != w83697hf)
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- device_create_file_in(new_client, 4);
- if (kind == w83627hf || kind == w83697hf) {
- device_create_file_in(new_client, 5);
- device_create_file_in(new_client, 6);
- }
- device_create_file_in(new_client, 7);
- device_create_file_in(new_client, 8);
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- if (kind != w83697hf)
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- if (kind != w83697hf)
- device_create_file_temp(new_client, 3);
- if (kind != w83697hf && data->vid != 0xff) {
- device_create_file_vid(new_client);
- device_create_file_vrm(new_client);
- }
+ /* Register chip-specific device attributes */
+ if (kind == w83627hf || kind == w83697hf)
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in5_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in5_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in6_max)))
+ goto ERROR4;
- device_create_file_fan_div(new_client, 1);
- device_create_file_fan_div(new_client, 2);
if (kind != w83697hf)
- device_create_file_fan_div(new_client, 3);
-
- device_create_file_alarms(new_client);
-
- device_create_file_beep(new_client);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in1_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in1_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_in1_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_min))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_fan3_div))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_input))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_max_hyst))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_temp3_type)))
+ goto ERROR4;
+
+ if (kind != w83697hf && data->vid != 0xff)
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_cpu0_vid))
+ || (err = device_create_file(&new_client->dev,
+ &dev_attr_vrm)))
+ goto ERROR4;
- device_create_file_pwm(new_client, 1);
- device_create_file_pwm(new_client, 2);
if (kind == w83627thf || kind == w83637hf || kind == w83687thf)
- device_create_file_pwm(new_client, 3);
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_pwm3)))
+ goto ERROR4;
- device_create_file_sensor(new_client, 1);
- device_create_file_sensor(new_client, 2);
- if (kind != w83697hf)
- device_create_file_sensor(new_client, 3);
+ data->class_dev = hwmon_device_register(&new_client->dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
+ }
return 0;
+ ERROR4:
+ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group);
+ sysfs_remove_group(&new_client->dev.kobj, &w83627hf_group_opt);
ERROR3:
i2c_detach_client(new_client);
ERROR2:
@@ -1180,6 +1222,9 @@ static int w83627hf_detach_client(struct i2c_client *client)
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83627hf_group);
+ sysfs_remove_group(&client->dev.kobj, &w83627hf_group_opt);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/w83781d.c b/drivers/hwmon/w83781d.c
index 7be469ed0f8f..1232171c3aad 100644
--- a/drivers/hwmon/w83781d.c
+++ b/drivers/hwmon/w83781d.c
@@ -41,6 +41,7 @@
#include <linux/i2c-isa.h>
#include <linux/hwmon.h>
#include <linux/hwmon-vid.h>
+#include <linux/sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <asm/io.h>
@@ -288,6 +289,7 @@ static struct i2c_driver w83781d_driver = {
static struct i2c_driver w83781d_isa_driver = {
.driver = {
+ .owner = THIS_MODULE,
.name = "w83781d-isa",
},
.attach_adapter = w83781d_isa_attach_adapter,
@@ -359,13 +361,6 @@ sysfs_in_offsets(6);
sysfs_in_offsets(7);
sysfs_in_offsets(8);
-#define device_create_file_in(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_in##offset##_input); \
-device_create_file(&client->dev, &dev_attr_in##offset##_min); \
-device_create_file(&client->dev, &dev_attr_in##offset##_max); \
-} while (0)
-
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -420,12 +415,6 @@ sysfs_fan_min_offset(2);
sysfs_fan_offset(3);
sysfs_fan_min_offset(3);
-#define device_create_file_fan(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_input); \
-device_create_file(&client->dev, &dev_attr_fan##offset##_min); \
-} while (0)
-
#define show_temp_reg(reg) \
static ssize_t show_##reg (struct device *dev, char *buf, int nr) \
{ \
@@ -496,13 +485,6 @@ sysfs_temp_offsets(1);
sysfs_temp_offsets(2);
sysfs_temp_offsets(3);
-#define device_create_file_temp(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_input); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max); \
-device_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \
-} while (0)
-
static ssize_t
show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -510,10 +492,8 @@ show_vid_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm));
}
-static
-DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
-#define device_create_file_vid(client) \
-device_create_file(&client->dev, &dev_attr_cpu0_vid);
+static DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL);
+
static ssize_t
show_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -534,10 +514,8 @@ store_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf
return count;
}
-static
-DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
-#define device_create_file_vrm(client) \
-device_create_file(&client->dev, &dev_attr_vrm);
+static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+
static ssize_t
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -545,10 +523,8 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%u\n", data->alarms);
}
-static
-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-#define device_create_file_alarms(client) \
-device_create_file(&client->dev, &dev_attr_alarms);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+
static ssize_t show_beep_mask (struct device *dev, struct device_attribute *attr, char *buf)
{
struct w83781d_data *data = w83781d_update_device(dev);
@@ -614,12 +590,6 @@ static DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, show_regs_beep_##reg, store_re
sysfs_beep(ENABLE, enable);
sysfs_beep(MASK, mask);
-#define device_create_file_beep(client) \
-do { \
-device_create_file(&client->dev, &dev_attr_beep_enable); \
-device_create_file(&client->dev, &dev_attr_beep_mask); \
-} while (0)
-
static ssize_t
show_fan_div_reg(struct device *dev, char *buf, int nr)
{
@@ -685,11 +655,6 @@ sysfs_fan_div(1);
sysfs_fan_div(2);
sysfs_fan_div(3);
-#define device_create_file_fan_div(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_fan##offset##_div); \
-} while (0)
-
static ssize_t
show_pwm_reg(struct device *dev, char *buf, int nr)
{
@@ -786,16 +751,6 @@ sysfs_pwmenable(2); /* only PWM2 can be enabled/disabled */
sysfs_pwm(3);
sysfs_pwm(4);
-#define device_create_file_pwm(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset); \
-} while (0)
-
-#define device_create_file_pwmenable(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_pwm##offset##_enable); \
-} while (0)
-
static ssize_t
show_sensor_reg(struct device *dev, char *buf, int nr)
{
@@ -864,11 +819,6 @@ sysfs_sensor(1);
sysfs_sensor(2);
sysfs_sensor(3);
-#define device_create_file_sensor(client, offset) \
-do { \
-device_create_file(&client->dev, &dev_attr_temp##offset##_type); \
-} while (0)
-
/* This function is called when:
* w83781d_driver is inserted (when this module is loaded), for each
available adapter
@@ -993,11 +943,69 @@ ERROR_SC_0:
return err;
}
+#define IN_UNIT_ATTRS(X) \
+ &dev_attr_in##X##_input.attr, \
+ &dev_attr_in##X##_min.attr, \
+ &dev_attr_in##X##_max.attr
+
+#define FAN_UNIT_ATTRS(X) \
+ &dev_attr_fan##X##_input.attr, \
+ &dev_attr_fan##X##_min.attr, \
+ &dev_attr_fan##X##_div.attr
+
+#define TEMP_UNIT_ATTRS(X) \
+ &dev_attr_temp##X##_input.attr, \
+ &dev_attr_temp##X##_max.attr, \
+ &dev_attr_temp##X##_max_hyst.attr
+
+static struct attribute* w83781d_attributes[] = {
+ IN_UNIT_ATTRS(0),
+ IN_UNIT_ATTRS(2),
+ IN_UNIT_ATTRS(3),
+ IN_UNIT_ATTRS(4),
+ IN_UNIT_ATTRS(5),
+ IN_UNIT_ATTRS(6),
+ FAN_UNIT_ATTRS(1),
+ FAN_UNIT_ATTRS(2),
+ FAN_UNIT_ATTRS(3),
+ TEMP_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(2),
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_beep_mask.attr,
+ &dev_attr_beep_enable.attr,
+ NULL
+};
+static const struct attribute_group w83781d_group = {
+ .attrs = w83781d_attributes,
+};
+
+static struct attribute *w83781d_attributes_opt[] = {
+ IN_UNIT_ATTRS(1),
+ IN_UNIT_ATTRS(7),
+ IN_UNIT_ATTRS(8),
+ TEMP_UNIT_ATTRS(3),
+ &dev_attr_pwm1.attr,
+ &dev_attr_pwm2.attr,
+ &dev_attr_pwm2_enable.attr,
+ &dev_attr_pwm3.attr,
+ &dev_attr_pwm4.attr,
+ &dev_attr_temp1_type.attr,
+ &dev_attr_temp2_type.attr,
+ &dev_attr_temp3_type.attr,
+ NULL
+};
+static const struct attribute_group w83781d_group_opt = {
+ .attrs = w83781d_attributes_opt,
+};
+
static int
w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
{
int i = 0, val1 = 0, val2;
- struct i2c_client *new_client;
+ struct i2c_client *client;
+ struct device *dev;
struct w83781d_data *data;
int err;
const char *client_name = "";
@@ -1074,13 +1082,14 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
goto ERROR1;
}
- new_client = &data->client;
- i2c_set_clientdata(new_client, data);
- new_client->addr = address;
+ client = &data->client;
+ i2c_set_clientdata(client, data);
+ client->addr = address;
mutex_init(&data->lock);
- new_client->adapter = adapter;
- new_client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
- new_client->flags = 0;
+ client->adapter = adapter;
+ client->driver = is_isa ? &w83781d_isa_driver : &w83781d_driver;
+ client->flags = 0;
+ dev = &client->dev;
/* Now, we do the remaining detection. */
@@ -1089,20 +1098,20 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
force_*=... parameter, and the Winbond will be reset to the right
bank. */
if (kind < 0) {
- if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) {
- dev_dbg(&new_client->dev, "Detection failed at step "
- "3\n");
+ if (w83781d_read_value(client, W83781D_REG_CONFIG) & 0x80) {
+ dev_dbg(&adapter->dev, "Detection of w83781d chip "
+ "failed at step 3\n");
err = -ENODEV;
goto ERROR2;
}
- val1 = w83781d_read_value(new_client, W83781D_REG_BANK);
- val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
+ val1 = w83781d_read_value(client, W83781D_REG_BANK);
+ val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
/* Check for Winbond or Asus ID if in bank 0 */
if ((!(val1 & 0x07)) &&
(((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))
|| ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {
- dev_dbg(&new_client->dev, "Detection failed at step "
- "4\n");
+ dev_dbg(&adapter->dev, "Detection of w83781d chip "
+ "failed at step 4\n");
err = -ENODEV;
goto ERROR2;
}
@@ -1111,9 +1120,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||
((val1 & 0x80) && (val2 == 0x5c)))) {
if (w83781d_read_value
- (new_client, W83781D_REG_I2C_ADDR) != address) {
- dev_dbg(&new_client->dev, "Detection failed "
- "at step 5\n");
+ (client, W83781D_REG_I2C_ADDR) != address) {
+ dev_dbg(&adapter->dev, "Detection of w83781d "
+ "chip failed at step 5\n");
err = -ENODEV;
goto ERROR2;
}
@@ -1122,27 +1131,26 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
/* We have either had a force parameter, or we have already detected the
Winbond. Put it now into bank 0 and Vendor ID High Byte */
- w83781d_write_value(new_client, W83781D_REG_BANK,
- (w83781d_read_value(new_client,
- W83781D_REG_BANK) & 0x78) |
- 0x80);
+ w83781d_write_value(client, W83781D_REG_BANK,
+ (w83781d_read_value(client, W83781D_REG_BANK)
+ & 0x78) | 0x80);
/* Determine the chip type. */
if (kind <= 0) {
/* get vendor ID */
- val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);
+ val2 = w83781d_read_value(client, W83781D_REG_CHIPMAN);
if (val2 == 0x5c)
vendid = winbond;
else if (val2 == 0x12)
vendid = asus;
else {
- dev_dbg(&new_client->dev, "Chip was made by neither "
- "Winbond nor Asus?\n");
+ dev_dbg(&adapter->dev, "w83781d chip vendor is "
+ "neither Winbond nor Asus\n");
err = -ENODEV;
goto ERROR2;
}
- val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID);
+ val1 = w83781d_read_value(client, W83781D_REG_WCHIPID);
if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)
kind = w83781d;
else if (val1 == 0x30 && vendid == winbond)
@@ -1156,10 +1164,9 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
kind = as99127f;
else {
if (kind == 0)
- dev_warn(&new_client->dev, "Ignoring 'force' "
+ dev_warn(&adapter->dev, "Ignoring 'force' "
"parameter for unknown chip at "
- "adapter %d, address 0x%02x\n",
- i2c_adapter_id(adapter), address);
+ "address 0x%02x\n", address);
err = -EINVAL;
goto ERROR2;
}
@@ -1178,20 +1185,20 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Fill in the remaining client fields and put into the global list */
- strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
+ strlcpy(client->name, client_name, I2C_NAME_SIZE);
data->type = kind;
data->valid = 0;
mutex_init(&data->update_lock);
/* Tell the I2C layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
+ if ((err = i2c_attach_client(client)))
goto ERROR2;
/* attach secondary i2c lm75-like clients */
if (!is_isa) {
if ((err = w83781d_detect_subclients(adapter, address,
- kind, new_client)))
+ kind, client)))
goto ERROR3;
} else {
data->lm75[0] = NULL;
@@ -1199,11 +1206,11 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Initialize the chip */
- w83781d_init_client(new_client);
+ w83781d_init_client(client);
/* A few vars need to be filled upon startup */
for (i = 1; i <= 3; i++) {
- data->fan_min[i - 1] = w83781d_read_value(new_client,
+ data->fan_min[i - 1] = w83781d_read_value(client,
W83781D_REG_FAN_MIN(i));
}
if (kind != w83781d && kind != as99127f)
@@ -1211,65 +1218,68 @@ w83781d_detect(struct i2c_adapter *adapter, int address, int kind)
data->pwmenable[i] = 1;
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(&new_client->dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&dev->kobj, &w83781d_group)))
goto ERROR4;
- }
- device_create_file_in(new_client, 0);
- if (kind != w83783s)
- device_create_file_in(new_client, 1);
- device_create_file_in(new_client, 2);
- device_create_file_in(new_client, 3);
- device_create_file_in(new_client, 4);
- device_create_file_in(new_client, 5);
- device_create_file_in(new_client, 6);
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev, &dev_attr_in1_input))
+ || (err = device_create_file(dev, &dev_attr_in1_min))
+ || (err = device_create_file(dev, &dev_attr_in1_max)))
+ goto ERROR4;
+ }
if (kind != as99127f && kind != w83781d && kind != w83783s) {
- device_create_file_in(new_client, 7);
- device_create_file_in(new_client, 8);
+ if ((err = device_create_file(dev, &dev_attr_in7_input))
+ || (err = device_create_file(dev, &dev_attr_in7_min))
+ || (err = device_create_file(dev, &dev_attr_in7_max))
+ || (err = device_create_file(dev, &dev_attr_in8_input))
+ || (err = device_create_file(dev, &dev_attr_in8_min))
+ || (err = device_create_file(dev, &dev_attr_in8_max)))
+ goto ERROR4;
+ }
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev, &dev_attr_temp3_input))
+ || (err = device_create_file(dev, &dev_attr_temp3_max))
+ || (err = device_create_file(dev,
+ &dev_attr_temp3_max_hyst)))
+ goto ERROR4;
}
-
- device_create_file_fan(new_client, 1);
- device_create_file_fan(new_client, 2);
- device_create_file_fan(new_client, 3);
-
- device_create_file_temp(new_client, 1);
- device_create_file_temp(new_client, 2);
- if (kind != w83783s)
- device_create_file_temp(new_client, 3);
-
- device_create_file_vid(new_client);
- device_create_file_vrm(new_client);
-
- device_create_file_fan_div(new_client, 1);
- device_create_file_fan_div(new_client, 2);
- device_create_file_fan_div(new_client, 3);
-
- device_create_file_alarms(new_client);
-
- device_create_file_beep(new_client);
if (kind != w83781d && kind != as99127f) {
- device_create_file_pwm(new_client, 1);
- device_create_file_pwm(new_client, 2);
- device_create_file_pwmenable(new_client, 2);
+ if ((err = device_create_file(dev, &dev_attr_pwm1))
+ || (err = device_create_file(dev, &dev_attr_pwm2))
+ || (err = device_create_file(dev, &dev_attr_pwm2_enable)))
+ goto ERROR4;
}
if (kind == w83782d && !is_isa) {
- device_create_file_pwm(new_client, 3);
- device_create_file_pwm(new_client, 4);
+ if ((err = device_create_file(dev, &dev_attr_pwm3))
+ || (err = device_create_file(dev, &dev_attr_pwm4)))
+ goto ERROR4;
}
if (kind != as99127f && kind != w83781d) {
- device_create_file_sensor(new_client, 1);
- device_create_file_sensor(new_client, 2);
- if (kind != w83783s)
- device_create_file_sensor(new_client, 3);
+ if ((err = device_create_file(dev, &dev_attr_temp1_type))
+ || (err = device_create_file(dev,
+ &dev_attr_temp2_type)))
+ goto ERROR4;
+ if (kind != w83783s) {
+ if ((err = device_create_file(dev,
+ &dev_attr_temp3_type)))
+ goto ERROR4;
+ }
+ }
+
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto ERROR4;
}
return 0;
ERROR4:
+ sysfs_remove_group(&dev->kobj, &w83781d_group);
+ sysfs_remove_group(&dev->kobj, &w83781d_group_opt);
+
if (data->lm75[1]) {
i2c_detach_client(data->lm75[1]);
kfree(data->lm75[1]);
@@ -1279,7 +1289,7 @@ ERROR4:
kfree(data->lm75[0]);
}
ERROR3:
- i2c_detach_client(new_client);
+ i2c_detach_client(client);
ERROR2:
kfree(data);
ERROR1:
@@ -1296,9 +1306,11 @@ w83781d_detach_client(struct i2c_client *client)
int err;
/* main client */
- if (data)
+ if (data) {
hwmon_device_unregister(data->class_dev);
-
+ sysfs_remove_group(&client->dev.kobj, &w83781d_group);
+ sysfs_remove_group(&client->dev.kobj, &w83781d_group_opt);
+ }
if (i2c_is_isa_client(client))
release_region(client->addr, W83781D_EXTENT);
@@ -1675,11 +1687,10 @@ sensors_w83781d_init(void)
if (res)
return res;
- res = i2c_isa_add_driver(&w83781d_isa_driver);
- if (res) {
- i2c_del_driver(&w83781d_driver);
- return res;
- }
+ /* Don't exit if this one fails, we still want the I2C variants
+ to work! */
+ if (i2c_isa_add_driver(&w83781d_isa_driver))
+ isa_address = 0;
return 0;
}
@@ -1687,7 +1698,8 @@ sensors_w83781d_init(void)
static void __exit
sensors_w83781d_exit(void)
{
- i2c_isa_del_driver(&w83781d_isa_driver);
+ if (isa_address)
+ i2c_isa_del_driver(&w83781d_isa_driver);
i2c_del_driver(&w83781d_driver);
}
diff --git a/drivers/hwmon/w83791d.c b/drivers/hwmon/w83791d.c
index eec43abd57fb..9e5f885368b4 100644
--- a/drivers/hwmon/w83791d.c
+++ b/drivers/hwmon/w83791d.c
@@ -27,12 +27,11 @@
The w83791d chip appears to be part way between the 83781d and the
83792d. Thus, this file is derived from both the w83792d.c and
- w83781d.c files, but its output is more along the lines of the
- 83781d (which means there are no changes to the user-mode sensors
- program which treats the 83791d as an 83781d).
+ w83781d.c files.
+
+ The w83791g chip is the same as the w83791d but lead-free.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -747,6 +746,52 @@ static ssize_t store_vrm_reg(struct device *dev,
static DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg);
+#define IN_UNIT_ATTRS(X) \
+ &sda_in_input[X].dev_attr.attr, \
+ &sda_in_min[X].dev_attr.attr, \
+ &sda_in_max[X].dev_attr.attr
+
+#define FAN_UNIT_ATTRS(X) \
+ &sda_fan_input[X].dev_attr.attr, \
+ &sda_fan_min[X].dev_attr.attr, \
+ &sda_fan_div[X].dev_attr.attr
+
+#define TEMP_UNIT_ATTRS(X) \
+ &sda_temp_input[X].dev_attr.attr, \
+ &sda_temp_max[X].dev_attr.attr, \
+ &sda_temp_max_hyst[X].dev_attr.attr
+
+static struct attribute *w83791d_attributes[] = {
+ IN_UNIT_ATTRS(0),
+ IN_UNIT_ATTRS(1),
+ IN_UNIT_ATTRS(2),
+ IN_UNIT_ATTRS(3),
+ IN_UNIT_ATTRS(4),
+ IN_UNIT_ATTRS(5),
+ IN_UNIT_ATTRS(6),
+ IN_UNIT_ATTRS(7),
+ IN_UNIT_ATTRS(8),
+ IN_UNIT_ATTRS(9),
+ FAN_UNIT_ATTRS(0),
+ FAN_UNIT_ATTRS(1),
+ FAN_UNIT_ATTRS(2),
+ FAN_UNIT_ATTRS(3),
+ FAN_UNIT_ATTRS(4),
+ TEMP_UNIT_ATTRS(0),
+ TEMP_UNIT_ATTRS(1),
+ TEMP_UNIT_ATTRS(2),
+ &dev_attr_alarms.attr,
+ &sda_beep_ctrl[0].dev_attr.attr,
+ &sda_beep_ctrl[1].dev_attr.attr,
+ &dev_attr_cpu0_vid.attr,
+ &dev_attr_vrm.attr,
+ NULL
+};
+
+static const struct attribute_group w83791d_group = {
+ .attrs = w83791d_attributes,
+};
+
/* This function is called when:
* w83791d_driver is inserted (when this module is loaded), for each
available adapter
@@ -968,41 +1013,20 @@ static int w83791d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
+ if ((err = sysfs_create_group(&client->dev.kobj, &w83791d_group)))
+ goto error3;
+
+ /* Everything is ready, now register the working device */
data->class_dev = hwmon_device_register(dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto error3;
- }
-
- for (i = 0; i < NUMBER_OF_VIN; i++) {
- device_create_file(dev, &sda_in_input[i].dev_attr);
- device_create_file(dev, &sda_in_min[i].dev_attr);
- device_create_file(dev, &sda_in_max[i].dev_attr);
+ goto error4;
}
- for (i = 0; i < NUMBER_OF_FANIN; i++) {
- device_create_file(dev, &sda_fan_input[i].dev_attr);
- device_create_file(dev, &sda_fan_div[i].dev_attr);
- device_create_file(dev, &sda_fan_min[i].dev_attr);
- }
-
- for (i = 0; i < NUMBER_OF_TEMPIN; i++) {
- device_create_file(dev, &sda_temp_input[i].dev_attr);
- device_create_file(dev, &sda_temp_max[i].dev_attr);
- device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
- }
-
- device_create_file(dev, &dev_attr_alarms);
-
- for (i = 0; i < ARRAY_SIZE(sda_beep_ctrl); i++) {
- device_create_file(dev, &sda_beep_ctrl[i].dev_attr);
- }
-
- device_create_file(dev, &dev_attr_cpu0_vid);
- device_create_file(dev, &dev_attr_vrm);
-
return 0;
+error4:
+ sysfs_remove_group(&client->dev.kobj, &w83791d_group);
error3:
if (data->lm75[0] != NULL) {
i2c_detach_client(data->lm75[0]);
@@ -1026,8 +1050,10 @@ static int w83791d_detach_client(struct i2c_client *client)
int err;
/* main client */
- if (data)
+ if (data) {
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83791d_group);
+ }
if ((err = i2c_detach_client(client)))
return err;
@@ -1172,6 +1198,7 @@ static struct w83791d_data *w83791d_update_device(struct device *dev)
(w83791d_read(client, W83791D_REG_BEEP_CTRL[1]) << 8) +
(w83791d_read(client, W83791D_REG_BEEP_CTRL[2]) << 16);
+ /* Extract global beep enable flag */
data->beep_enable =
(data->beep_mask >> GLOBAL_BEEP_ENABLE_SHIFT) & 0x01;
diff --git a/drivers/hwmon/w83792d.c b/drivers/hwmon/w83792d.c
index 7576ec9426a3..4e108262576f 100644
--- a/drivers/hwmon/w83792d.c
+++ b/drivers/hwmon/w83792d.c
@@ -43,6 +43,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/err.h>
#include <linux/mutex.h>
+#include <linux/sysfs.h>
/* Addresses to scan */
static unsigned short normal_i2c[] = { 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END };
@@ -381,41 +382,6 @@ static ssize_t store_in_##reg (struct device *dev, \
store_in_reg(MIN, min);
store_in_reg(MAX, max);
-static struct sensor_device_attribute sda_in_input[] = {
- SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0),
- SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1),
- SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2),
- SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3),
- SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4),
- SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5),
- SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6),
- SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7),
- SENSOR_ATTR(in8_input, S_IRUGO, show_in, NULL, 8),
-};
-static struct sensor_device_attribute sda_in_min[] = {
- SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 0),
- SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 1),
- SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 2),
- SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 3),
- SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 4),
- SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 5),
- SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 6),
- SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 7),
- SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, store_in_min, 8),
-};
-static struct sensor_device_attribute sda_in_max[] = {
- SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 0),
- SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 1),
- SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 2),
- SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 3),
- SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 4),
- SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 5),
- SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 6),
- SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 7),
- SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, store_in_max, 8),
-};
-
-
#define show_fan_reg(reg) \
static ssize_t show_##reg (struct device *dev, struct device_attribute *attr, \
char *buf) \
@@ -499,35 +465,6 @@ store_fan_div(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_fan_input[] = {
- SENSOR_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1),
- SENSOR_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2),
- SENSOR_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3),
- SENSOR_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4),
- SENSOR_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5),
- SENSOR_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6),
- SENSOR_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7),
-};
-static struct sensor_device_attribute sda_fan_min[] = {
- SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 1),
- SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 2),
- SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 3),
- SENSOR_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 4),
- SENSOR_ATTR(fan5_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 5),
- SENSOR_ATTR(fan6_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 6),
- SENSOR_ATTR(fan7_min, S_IWUSR | S_IRUGO, show_fan_min, store_fan_min, 7),
-};
-static struct sensor_device_attribute sda_fan_div[] = {
- SENSOR_ATTR(fan1_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 1),
- SENSOR_ATTR(fan2_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 2),
- SENSOR_ATTR(fan3_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 3),
- SENSOR_ATTR(fan4_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 4),
- SENSOR_ATTR(fan5_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 5),
- SENSOR_ATTR(fan6_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 6),
- SENSOR_ATTR(fan7_div, S_IWUSR | S_IRUGO, show_fan_div, store_fan_div, 7),
-};
-
-
/* read/write the temperature1, includes measured value and limits */
static ssize_t show_temp1(struct device *dev, struct device_attribute *attr,
@@ -595,24 +532,6 @@ static ssize_t store_temp23(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute_2 sda_temp_input[] = {
- SENSOR_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0),
- SENSOR_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0),
- SENSOR_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0),
-};
-
-static struct sensor_device_attribute_2 sda_temp_max[] = {
- SENSOR_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 1),
- SENSOR_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 2),
- SENSOR_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 2),
-};
-
-static struct sensor_device_attribute_2 sda_temp_max_hyst[] = {
- SENSOR_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR, show_temp1, store_temp1, 0, 2),
- SENSOR_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 0, 4),
- SENSOR_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR, show_temp23, store_temp23, 1, 4),
-};
-
/* get reatime status of all sensors items: voltage, temp, fan */
static ssize_t
show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
@@ -621,9 +540,6 @@ show_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%d\n", data->alarms);
}
-static
-DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
-
static ssize_t
show_pwm(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -715,21 +631,6 @@ store_pwmenable(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_pwm[] = {
- SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0),
- SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1),
- SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2),
-};
-static struct sensor_device_attribute sda_pwm_enable[] = {
- SENSOR_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
- show_pwmenable, store_pwmenable, 1),
- SENSOR_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
- show_pwmenable, store_pwmenable, 2),
- SENSOR_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
- show_pwmenable, store_pwmenable, 3),
-};
-
-
static ssize_t
show_pwm_mode(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -767,16 +668,6 @@ store_pwm_mode(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_pwm_mode[] = {
- SENSOR_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 0),
- SENSOR_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 1),
- SENSOR_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
- show_pwm_mode, store_pwm_mode, 2),
-};
-
-
static ssize_t
show_regs_chassis(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -785,8 +676,6 @@ show_regs_chassis(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%d\n", data->chassis);
}
-static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
-
static ssize_t
show_chassis_clear(struct device *dev, struct device_attribute *attr, char *buf)
{
@@ -815,9 +704,6 @@ store_chassis_clear(struct device *dev, struct device_attribute *attr,
return count;
}
-static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
- show_chassis_clear, store_chassis_clear);
-
/* For Smart Fan I / Thermal Cruise */
static ssize_t
show_thermal_cruise(struct device *dev, struct device_attribute *attr,
@@ -853,15 +739,6 @@ store_thermal_cruise(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_thermal_cruise[] = {
- SENSOR_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
- show_thermal_cruise, store_thermal_cruise, 1),
- SENSOR_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
- show_thermal_cruise, store_thermal_cruise, 2),
- SENSOR_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
- show_thermal_cruise, store_thermal_cruise, 3),
-};
-
/* For Smart Fan I/Thermal Cruise and Smart Fan II */
static ssize_t
show_tolerance(struct device *dev, struct device_attribute *attr,
@@ -901,15 +778,6 @@ store_tolerance(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute sda_tolerance[] = {
- SENSOR_ATTR(tolerance1, S_IWUSR | S_IRUGO,
- show_tolerance, store_tolerance, 1),
- SENSOR_ATTR(tolerance2, S_IWUSR | S_IRUGO,
- show_tolerance, store_tolerance, 2),
- SENSOR_ATTR(tolerance3, S_IWUSR | S_IRUGO,
- show_tolerance, store_tolerance, 3),
-};
-
/* For Smart Fan II */
static ssize_t
show_sf2_point(struct device *dev, struct device_attribute *attr,
@@ -946,36 +814,6 @@ store_sf2_point(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute_2 sda_sf2_point[] = {
- SENSOR_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 1, 1),
- SENSOR_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 2, 1),
- SENSOR_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 3, 1),
- SENSOR_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 4, 1),
-
- SENSOR_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 1, 2),
- SENSOR_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 2, 2),
- SENSOR_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 3, 2),
- SENSOR_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 4, 2),
-
- SENSOR_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 1, 3),
- SENSOR_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 2, 3),
- SENSOR_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 3, 3),
- SENSOR_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
- show_sf2_point, store_sf2_point, 4, 3),
-};
-
-
static ssize_t
show_sf2_level(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -1016,29 +854,6 @@ store_sf2_level(struct device *dev, struct device_attribute *attr,
return count;
}
-static struct sensor_device_attribute_2 sda_sf2_level[] = {
- SENSOR_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 1, 1),
- SENSOR_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 2, 1),
- SENSOR_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 3, 1),
-
- SENSOR_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 1, 2),
- SENSOR_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 2, 2),
- SENSOR_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 3, 2),
-
- SENSOR_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 1, 3),
- SENSOR_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 2, 3),
- SENSOR_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
- show_sf2_level, store_sf2_level, 3, 3),
-};
-
/* This function is called when:
* w83792d_driver is inserted (when this module is loaded), for each
available adapter
@@ -1139,12 +954,297 @@ ERROR_SC_0:
return err;
}
-static void device_create_file_fan(struct device *dev, int i)
-{
- device_create_file(dev, &sda_fan_input[i].dev_attr);
- device_create_file(dev, &sda_fan_div[i].dev_attr);
- device_create_file(dev, &sda_fan_min[i].dev_attr);
-}
+static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, show_in, NULL, 0);
+static SENSOR_DEVICE_ATTR(in1_input, S_IRUGO, show_in, NULL, 1);
+static SENSOR_DEVICE_ATTR(in2_input, S_IRUGO, show_in, NULL, 2);
+static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_in, NULL, 3);
+static SENSOR_DEVICE_ATTR(in4_input, S_IRUGO, show_in, NULL, 4);
+static SENSOR_DEVICE_ATTR(in5_input, S_IRUGO, show_in, NULL, 5);
+static SENSOR_DEVICE_ATTR(in6_input, S_IRUGO, show_in, NULL, 6);
+static SENSOR_DEVICE_ATTR(in7_input, S_IRUGO, show_in, NULL, 7);
+static SENSOR_DEVICE_ATTR(in8_input, S_IRUGO, show_in, NULL, 8);
+static SENSOR_DEVICE_ATTR(in0_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 0);
+static SENSOR_DEVICE_ATTR(in1_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 1);
+static SENSOR_DEVICE_ATTR(in2_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 2);
+static SENSOR_DEVICE_ATTR(in3_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 3);
+static SENSOR_DEVICE_ATTR(in4_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 4);
+static SENSOR_DEVICE_ATTR(in5_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 5);
+static SENSOR_DEVICE_ATTR(in6_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 6);
+static SENSOR_DEVICE_ATTR(in7_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 7);
+static SENSOR_DEVICE_ATTR(in8_min, S_IWUSR | S_IRUGO,
+ show_in_min, store_in_min, 8);
+static SENSOR_DEVICE_ATTR(in0_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 0);
+static SENSOR_DEVICE_ATTR(in1_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 1);
+static SENSOR_DEVICE_ATTR(in2_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 2);
+static SENSOR_DEVICE_ATTR(in3_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 3);
+static SENSOR_DEVICE_ATTR(in4_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 4);
+static SENSOR_DEVICE_ATTR(in5_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 5);
+static SENSOR_DEVICE_ATTR(in6_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 6);
+static SENSOR_DEVICE_ATTR(in7_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 7);
+static SENSOR_DEVICE_ATTR(in8_max, S_IWUSR | S_IRUGO,
+ show_in_max, store_in_max, 8);
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp1, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp23, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp23, NULL, 1, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR,
+ show_temp1, store_temp1, 0, 1);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp23,
+ store_temp23, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp23,
+ store_temp23, 1, 2);
+static SENSOR_DEVICE_ATTR_2(temp1_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp1, store_temp1, 0, 2);
+static SENSOR_DEVICE_ATTR_2(temp2_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 0, 4);
+static SENSOR_DEVICE_ATTR_2(temp3_max_hyst, S_IRUGO | S_IWUSR,
+ show_temp23, store_temp23, 1, 4);
+static DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL);
+static DEVICE_ATTR(chassis, S_IRUGO, show_regs_chassis, NULL);
+static DEVICE_ATTR(chassis_clear, S_IRUGO | S_IWUSR,
+ show_chassis_clear, store_chassis_clear);
+static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 0);
+static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 1);
+static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, store_pwm, 2);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO,
+ show_pwmenable, store_pwmenable, 1);
+static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO,
+ show_pwmenable, store_pwmenable, 2);
+static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO,
+ show_pwmenable, store_pwmenable, 3);
+static SENSOR_DEVICE_ATTR(pwm1_mode, S_IWUSR | S_IRUGO,
+ show_pwm_mode, store_pwm_mode, 0);
+static SENSOR_DEVICE_ATTR(pwm2_mode, S_IWUSR | S_IRUGO,
+ show_pwm_mode, store_pwm_mode, 1);
+static SENSOR_DEVICE_ATTR(pwm3_mode, S_IWUSR | S_IRUGO,
+ show_pwm_mode, store_pwm_mode, 2);
+static SENSOR_DEVICE_ATTR(tolerance1, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 1);
+static SENSOR_DEVICE_ATTR(tolerance2, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 2);
+static SENSOR_DEVICE_ATTR(tolerance3, S_IWUSR | S_IRUGO,
+ show_tolerance, store_tolerance, 3);
+static SENSOR_DEVICE_ATTR(thermal_cruise1, S_IWUSR | S_IRUGO,
+ show_thermal_cruise, store_thermal_cruise, 1);
+static SENSOR_DEVICE_ATTR(thermal_cruise2, S_IWUSR | S_IRUGO,
+ show_thermal_cruise, store_thermal_cruise, 2);
+static SENSOR_DEVICE_ATTR(thermal_cruise3, S_IWUSR | S_IRUGO,
+ show_thermal_cruise, store_thermal_cruise, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 1, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 2, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 3, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 4, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 1, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 2, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 3, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 4, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_point1_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 1, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point2_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 2, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point3_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 3, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_point4_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_point, store_sf2_point, 4, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 1, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 2, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan1, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 3, 1);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 1, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 2, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan2, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 3, 2);
+static SENSOR_DEVICE_ATTR_2(sf2_level1_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 1, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level2_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 2, 3);
+static SENSOR_DEVICE_ATTR_2(sf2_level3_fan3, S_IRUGO | S_IWUSR,
+ show_sf2_level, store_sf2_level, 3, 3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 1);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 2);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 3);
+static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 4);
+static SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan, NULL, 5);
+static SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan, NULL, 6);
+static SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan, NULL, 7);
+static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 1);
+static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 2);
+static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 3);
+static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 4);
+static SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 5);
+static SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 6);
+static SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO,
+ show_fan_min, store_fan_min, 7);
+static SENSOR_DEVICE_ATTR(fan1_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 1);
+static SENSOR_DEVICE_ATTR(fan2_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 2);
+static SENSOR_DEVICE_ATTR(fan3_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 3);
+static SENSOR_DEVICE_ATTR(fan4_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 4);
+static SENSOR_DEVICE_ATTR(fan5_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 5);
+static SENSOR_DEVICE_ATTR(fan6_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 6);
+static SENSOR_DEVICE_ATTR(fan7_div, S_IWUSR | S_IRUGO,
+ show_fan_div, store_fan_div, 7);
+
+static struct attribute *w83792d_attributes_fan[4][4] = {
+ {
+ &sensor_dev_attr_fan4_input.dev_attr.attr,
+ &sensor_dev_attr_fan4_min.dev_attr.attr,
+ &sensor_dev_attr_fan4_div.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan5_input.dev_attr.attr,
+ &sensor_dev_attr_fan5_min.dev_attr.attr,
+ &sensor_dev_attr_fan5_div.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan6_input.dev_attr.attr,
+ &sensor_dev_attr_fan6_min.dev_attr.attr,
+ &sensor_dev_attr_fan6_div.dev_attr.attr,
+ NULL
+ }, {
+ &sensor_dev_attr_fan7_input.dev_attr.attr,
+ &sensor_dev_attr_fan7_min.dev_attr.attr,
+ &sensor_dev_attr_fan7_div.dev_attr.attr,
+ NULL
+ }
+};
+
+static const struct attribute_group w83792d_group_fan[4] = {
+ { .attrs = w83792d_attributes_fan[0] },
+ { .attrs = w83792d_attributes_fan[1] },
+ { .attrs = w83792d_attributes_fan[2] },
+ { .attrs = w83792d_attributes_fan[3] },
+};
+
+static struct attribute *w83792d_attributes[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in1_input.dev_attr.attr,
+ &sensor_dev_attr_in1_max.dev_attr.attr,
+ &sensor_dev_attr_in1_min.dev_attr.attr,
+ &sensor_dev_attr_in2_input.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in3_input.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in4_input.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in5_input.dev_attr.attr,
+ &sensor_dev_attr_in5_max.dev_attr.attr,
+ &sensor_dev_attr_in5_min.dev_attr.attr,
+ &sensor_dev_attr_in6_input.dev_attr.attr,
+ &sensor_dev_attr_in6_max.dev_attr.attr,
+ &sensor_dev_attr_in6_min.dev_attr.attr,
+ &sensor_dev_attr_in7_input.dev_attr.attr,
+ &sensor_dev_attr_in7_max.dev_attr.attr,
+ &sensor_dev_attr_in7_min.dev_attr.attr,
+ &sensor_dev_attr_in8_input.dev_attr.attr,
+ &sensor_dev_attr_in8_max.dev_attr.attr,
+ &sensor_dev_attr_in8_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp2_input.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp3_input.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm2.dev_attr.attr,
+ &sensor_dev_attr_pwm2_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm2_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3.dev_attr.attr,
+ &sensor_dev_attr_pwm3_mode.dev_attr.attr,
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &dev_attr_alarms.attr,
+ &dev_attr_chassis.attr,
+ &dev_attr_chassis_clear.attr,
+ &sensor_dev_attr_tolerance1.dev_attr.attr,
+ &sensor_dev_attr_thermal_cruise1.dev_attr.attr,
+ &sensor_dev_attr_tolerance2.dev_attr.attr,
+ &sensor_dev_attr_thermal_cruise2.dev_attr.attr,
+ &sensor_dev_attr_tolerance3.dev_attr.attr,
+ &sensor_dev_attr_thermal_cruise3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point1_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point2_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point3_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point4_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_point1_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point2_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point3_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point4_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_point1_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point2_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point3_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_point4_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_level1_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_level2_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_level3_fan1.dev_attr.attr,
+ &sensor_dev_attr_sf2_level1_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_level2_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_level3_fan2.dev_attr.attr,
+ &sensor_dev_attr_sf2_level1_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_level2_fan3.dev_attr.attr,
+ &sensor_dev_attr_sf2_level3_fan3.dev_attr.attr,
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_div.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_div.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_div.dev_attr.attr,
+ NULL
+};
+
+static const struct attribute_group w83792d_group = {
+ .attrs = w83792d_attributes,
+};
static int
w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
@@ -1268,59 +1368,46 @@ w83792d_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* Register sysfs hooks */
- data->class_dev = hwmon_device_register(dev);
- if (IS_ERR(data->class_dev)) {
- err = PTR_ERR(data->class_dev);
+ if ((err = sysfs_create_group(&dev->kobj, &w83792d_group)))
goto ERROR3;
- }
- for (i = 0; i < 9; i++) {
- device_create_file(dev, &sda_in_input[i].dev_attr);
- device_create_file(dev, &sda_in_max[i].dev_attr);
- device_create_file(dev, &sda_in_min[i].dev_attr);
- }
- for (i = 0; i < 3; i++)
- device_create_file_fan(dev, i);
/* Read GPIO enable register to check if pins for fan 4,5 are used as
GPIO */
val1 = w83792d_read_value(client, W83792D_REG_GPIO_EN);
+
if (!(val1 & 0x40))
- device_create_file_fan(dev, 3);
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[0])))
+ goto exit_remove_files;
+
if (!(val1 & 0x20))
- device_create_file_fan(dev, 4);
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[1])))
+ goto exit_remove_files;
val1 = w83792d_read_value(client, W83792D_REG_PIN);
if (val1 & 0x40)
- device_create_file_fan(dev, 5);
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[2])))
+ goto exit_remove_files;
+
if (val1 & 0x04)
- device_create_file_fan(dev, 6);
-
- for (i = 0; i < 3; i++) {
- device_create_file(dev, &sda_temp_input[i].dev_attr);
- device_create_file(dev, &sda_temp_max[i].dev_attr);
- device_create_file(dev, &sda_temp_max_hyst[i].dev_attr);
- device_create_file(dev, &sda_thermal_cruise[i].dev_attr);
- device_create_file(dev, &sda_tolerance[i].dev_attr);
- }
+ if ((err = sysfs_create_group(&dev->kobj,
+ &w83792d_group_fan[3])))
+ goto exit_remove_files;
- for (i = 0; i < ARRAY_SIZE(sda_pwm); i++) {
- device_create_file(dev, &sda_pwm[i].dev_attr);
- device_create_file(dev, &sda_pwm_enable[i].dev_attr);
- device_create_file(dev, &sda_pwm_mode[i].dev_attr);
+ data->class_dev = hwmon_device_register(dev);
+ if (IS_ERR(data->class_dev)) {
+ err = PTR_ERR(data->class_dev);
+ goto exit_remove_files;
}
- device_create_file(dev, &dev_attr_alarms);
- device_create_file(dev, &dev_attr_chassis);
- device_create_file(dev, &dev_attr_chassis_clear);
-
- for (i = 0; i < ARRAY_SIZE(sda_sf2_point); i++)
- device_create_file(dev, &sda_sf2_point[i].dev_attr);
-
- for (i = 0; i < ARRAY_SIZE(sda_sf2_level); i++)
- device_create_file(dev, &sda_sf2_level[i].dev_attr);
-
return 0;
+exit_remove_files:
+ sysfs_remove_group(&dev->kobj, &w83792d_group);
+ for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
+ sysfs_remove_group(&dev->kobj, &w83792d_group_fan[i]);
ERROR3:
if (data->lm75[0] != NULL) {
i2c_detach_client(data->lm75[0]);
@@ -1342,11 +1429,16 @@ static int
w83792d_detach_client(struct i2c_client *client)
{
struct w83792d_data *data = i2c_get_clientdata(client);
- int err;
+ int err, i;
/* main client */
- if (data)
+ if (data) {
hwmon_device_unregister(data->class_dev);
+ sysfs_remove_group(&client->dev.kobj, &w83792d_group);
+ for (i = 0; i < ARRAY_SIZE(w83792d_group_fan); i++)
+ sysfs_remove_group(&client->dev.kobj,
+ &w83792d_group_fan[i]);
+ }
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/hwmon/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 3f2bac125fb1..a3fcace412f0 100644
--- a/drivers/hwmon/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
@@ -236,21 +236,30 @@ static int w83l785ts_detect(struct i2c_adapter *adapter, int address, int kind)
* Nothing yet, assume it is already started.
*/
+ err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ if (err)
+ goto exit_remove;
+
+ err = device_create_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
+ if (err)
+ goto exit_remove;
+
/* Register sysfs hooks */
data->class_dev = hwmon_device_register(&new_client->dev);
if (IS_ERR(data->class_dev)) {
err = PTR_ERR(data->class_dev);
- goto exit_detach;
+ goto exit_remove;
}
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_input.dev_attr);
- device_create_file(&new_client->dev,
- &sensor_dev_attr_temp1_max.dev_attr);
-
return 0;
-exit_detach:
+exit_remove:
+ device_remove_file(&new_client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&new_client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
i2c_detach_client(new_client);
exit_free:
kfree(data);
@@ -264,7 +273,10 @@ static int w83l785ts_detach_client(struct i2c_client *client)
int err;
hwmon_device_unregister(data->class_dev);
-
+ device_remove_file(&client->dev,
+ &sensor_dev_attr_temp1_input.dev_attr);
+ device_remove_file(&client->dev,
+ &sensor_dev_attr_temp1_max.dev_attr);
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 24383afdda76..11935f66fcd8 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -1,5 +1,5 @@
#
-# Character device configuration
+# I2C subsystem configuration
#
menu "I2C support"
diff --git a/drivers/i2c/algos/Kconfig b/drivers/i2c/algos/Kconfig
index 30408015d231..c034820615bb 100644
--- a/drivers/i2c/algos/Kconfig
+++ b/drivers/i2c/algos/Kconfig
@@ -53,12 +53,6 @@ config I2C_ALGO8XX
tristate "MPC8xx CPM I2C interface"
depends on 8xx && I2C
-config I2C_ALGO_SIBYTE
- tristate "SiByte SMBus interface"
- depends on SIBYTE_SB1xxx_SOC && I2C
- help
- Supports the SiByte SOC on-chip I2C interfaces (2 channels).
-
config I2C_ALGO_SGI
tristate "I2C SGI interfaces"
depends on I2C && (SGI_IP22 || SGI_IP32 || X86_VISWS)
diff --git a/drivers/i2c/algos/Makefile b/drivers/i2c/algos/Makefile
index 867fe1f67401..208be04a3dbd 100644
--- a/drivers/i2c/algos/Makefile
+++ b/drivers/i2c/algos/Makefile
@@ -6,7 +6,6 @@ obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o
obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o
obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o
obj-$(CONFIG_I2C_ALGOITE) += i2c-algo-ite.o
-obj-$(CONFIG_I2C_ALGO_SIBYTE) += i2c-algo-sibyte.o
obj-$(CONFIG_I2C_ALGO_SGI) += i2c-algo-sgi.o
ifeq ($(CONFIG_I2C_DEBUG_ALGO),y)
diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c
index ab230c033f99..21c36bfb5e6b 100644
--- a/drivers/i2c/algos/i2c-algo-bit.c
+++ b/drivers/i2c/algos/i2c-algo-bit.c
@@ -76,17 +76,15 @@ static inline void scllo(struct i2c_algo_bit_data *adap)
* Raise scl line, and do checking for delays. This is necessary for slower
* devices.
*/
-static inline int sclhi(struct i2c_algo_bit_data *adap)
+static int sclhi(struct i2c_algo_bit_data *adap)
{
unsigned long start;
setscl(adap,1);
/* Not all adapters have scl sense line... */
- if (adap->getscl == NULL ) {
- udelay(adap->udelay);
- return 0;
- }
+ if (!adap->getscl)
+ goto done;
start=jiffies;
while (! getscl(adap) ) {
@@ -101,6 +99,8 @@ static inline int sclhi(struct i2c_algo_bit_data *adap)
cond_resched();
}
DEBSTAT(printk(KERN_DEBUG "needed %ld jiffies\n", jiffies-start));
+
+done:
udelay(adap->udelay);
return 0;
}
@@ -121,7 +121,6 @@ static void i2c_repstart(struct i2c_algo_bit_data *adap)
DEBPROTO(printk(" Sr "));
setsda(adap,1);
sclhi(adap);
- udelay(adap->udelay);
sdalo(adap);
scllo(adap);
@@ -306,7 +305,7 @@ bailout:
* 0 chip did not answer
* -x transmission error
*/
-static inline int try_address(struct i2c_adapter *i2c_adap,
+static int try_address(struct i2c_adapter *i2c_adap,
unsigned char addr, int retries)
{
struct i2c_algo_bit_data *adap = i2c_adap->algo_data;
@@ -354,15 +353,11 @@ static int sendbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
return (retval<0)? retval : -EFAULT;
/* got a better one ?? */
}
-#if 0
- /* from asm/delay.h */
- __delay(adap->mdelay * (loops_per_sec / 1000) );
-#endif
}
return wrcount;
}
-static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
int inval;
int rdcount=0; /* counts bytes read */
@@ -412,7 +407,7 @@ static inline int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
* -x an error occurred (like: -EREMOTEIO if the device did not answer, or
* -ETIMEDOUT, for example if the lines are stuck...)
*/
-static inline int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
+static int bit_doAddress(struct i2c_adapter *i2c_adap, struct i2c_msg *msg)
{
unsigned short flags = msg->flags;
unsigned short nak_ok = msg->flags & I2C_M_IGNORE_NAK;
@@ -517,7 +512,7 @@ static u32 bit_func(struct i2c_adapter *adap)
/* -----exported algorithm data: ------------------------------------- */
-static struct i2c_algorithm i2c_bit_algo = {
+static const struct i2c_algorithm i2c_bit_algo = {
.master_xfer = bit_xfer,
.functionality = bit_func,
};
diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c
index b88a6fcf7bd0..9081c9fbcd29 100644
--- a/drivers/i2c/algos/i2c-algo-pca.c
+++ b/drivers/i2c/algos/i2c-algo-pca.c
@@ -355,7 +355,7 @@ static int pca_init(struct i2c_algo_pca_data *adap)
return 0;
}
-static struct i2c_algorithm pca_algo = {
+static const struct i2c_algorithm pca_algo = {
.master_xfer = pca_xfer,
.functionality = pca_func,
};
diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c
index 5b24930adb5a..3b2003398966 100644
--- a/drivers/i2c/algos/i2c-algo-pcf.c
+++ b/drivers/i2c/algos/i2c-algo-pcf.c
@@ -458,7 +458,7 @@ static u32 pcf_func(struct i2c_adapter *adap)
/* -----exported algorithm data: ------------------------------------- */
-static struct i2c_algorithm pcf_algo = {
+static const struct i2c_algorithm pcf_algo = {
.master_xfer = pcf_xfer,
.functionality = pcf_func,
};
diff --git a/drivers/i2c/algos/i2c-algo-sgi.c b/drivers/i2c/algos/i2c-algo-sgi.c
index 932c4fa86c73..490d99997fd0 100644
--- a/drivers/i2c/algos/i2c-algo-sgi.c
+++ b/drivers/i2c/algos/i2c-algo-sgi.c
@@ -157,7 +157,7 @@ static u32 sgi_func(struct i2c_adapter *adap)
return I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm sgi_algo = {
+static const struct i2c_algorithm sgi_algo = {
.master_xfer = sgi_xfer,
.functionality = sgi_func,
};
diff --git a/drivers/i2c/algos/i2c-algo-sibyte.c b/drivers/i2c/algos/i2c-algo-sibyte.c
deleted file mode 100644
index 32d41c6fac0f..000000000000
--- a/drivers/i2c/algos/i2c-algo-sibyte.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/* ------------------------------------------------------------------------- */
-/* i2c-algo-sibyte.c i2c driver algorithms for bit-shift adapters */
-/* ------------------------------------------------------------------------- */
-/* Copyright (C) 2001,2002,2003 Broadcom Corporation
- Copyright (C) 1995-2000 Simon G. Vogl
-
- 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-/* ------------------------------------------------------------------------- */
-
-/* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi> and even
- Frodo Looijaard <frodol@dds.nl>. */
-
-/* Ported for SiByte SOCs by Broadcom Corporation. */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/sibyte/sb1250_regs.h>
-#include <asm/sibyte/sb1250_smbus.h>
-
-#include <linux/i2c.h>
-#include <linux/i2c-algo-sibyte.h>
-
-/* ----- global defines ----------------------------------------------- */
-#define SMB_CSR(a,r) ((long)(a->reg_base + r))
-
-/* ----- global variables --------------------------------------------- */
-
-/* module parameters:
- */
-static int bit_scan; /* have a look at what's hanging 'round */
-
-
-static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int size, union i2c_smbus_data * data)
-{
- struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
- int data_bytes = 0;
- int error;
-
- while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- switch (size) {
- case I2C_SMBUS_QUICK:
- csr_out32((V_SMB_ADDR(addr) | (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
- V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
- break;
- case I2C_SMBUS_BYTE:
- if (read_write == I2C_SMBUS_READ) {
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
- SMB_CSR(adap, R_SMB_START));
- data_bytes = 1;
- } else {
- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
- SMB_CSR(adap, R_SMB_START));
- }
- break;
- case I2C_SMBUS_BYTE_DATA:
- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
- if (read_write == I2C_SMBUS_READ) {
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
- SMB_CSR(adap, R_SMB_START));
- data_bytes = 1;
- } else {
- csr_out32(V_SMB_LB(data->byte), SMB_CSR(adap, R_SMB_DATA));
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
- SMB_CSR(adap, R_SMB_START));
- }
- break;
- case I2C_SMBUS_WORD_DATA:
- csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
- if (read_write == I2C_SMBUS_READ) {
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
- SMB_CSR(adap, R_SMB_START));
- data_bytes = 2;
- } else {
- csr_out32(V_SMB_LB(data->word & 0xff), SMB_CSR(adap, R_SMB_DATA));
- csr_out32(V_SMB_MB(data->word >> 8), SMB_CSR(adap, R_SMB_DATA));
- csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
- SMB_CSR(adap, R_SMB_START));
- }
- break;
- default:
- return -1; /* XXXKW better error code? */
- }
-
- while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
- ;
-
- error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
- if (error & M_SMB_ERROR) {
- /* Clear error bit by writing a 1 */
- csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
- return -1; /* XXXKW better error code? */
- }
-
- if (data_bytes == 1)
- data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
- if (data_bytes == 2)
- data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
-
- return 0;
-}
-
-static int algo_control(struct i2c_adapter *adapter,
- unsigned int cmd, unsigned long arg)
-{
- return 0;
-}
-
-static u32 bit_func(struct i2c_adapter *adap)
-{
- return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
- I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
-}
-
-
-/* -----exported algorithm data: ------------------------------------- */
-
-static struct i2c_algorithm i2c_sibyte_algo = {
- .smbus_xfer = smbus_xfer,
- .algo_control = algo_control, /* ioctl */
- .functionality = bit_func,
-};
-
-/*
- * registering functions to load algorithms at runtime
- */
-int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
-{
- int i;
- struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
-
- /* register new adapter to i2c module... */
- i2c_adap->algo = &i2c_sibyte_algo;
-
- /* Set the frequency to 100 kHz */
- csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
- csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
-
- /* scan bus */
- if (bit_scan) {
- union i2c_smbus_data data;
- int rc;
- printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
- i2c_adap->name);
- for (i = 0x00; i < 0x7f; i++) {
- /* XXXKW is this a realistic probe? */
- rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
- I2C_SMBUS_BYTE_DATA, &data);
- if (!rc) {
- printk("(%02x)",i);
- } else
- printk(".");
- }
- printk("\n");
- }
-
- return i2c_add_adapter(i2c_adap);
-}
-
-
-int i2c_sibyte_del_bus(struct i2c_adapter *adap)
-{
- int res;
-
- if ((res = i2c_del_adapter(adap)) < 0)
- return res;
-
- return 0;
-}
-
-int __init i2c_algo_sibyte_init (void)
-{
- printk("i2c-algo-sibyte.o: i2c SiByte algorithm module\n");
- return 0;
-}
-
-
-EXPORT_SYMBOL(i2c_sibyte_add_bus);
-EXPORT_SYMBOL(i2c_sibyte_del_bus);
-
-#ifdef MODULE
-MODULE_AUTHOR("Kip Walker, Broadcom Corp.");
-MODULE_DESCRIPTION("SiByte I2C-Bus algorithm");
-module_param(bit_scan, int, 0);
-MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
-MODULE_LICENSE("GPL");
-
-int init_module(void)
-{
- return i2c_algo_sibyte_init();
-}
-
-void cleanup_module(void)
-{
-}
-#endif
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 884320e70403..510816c16da3 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -75,11 +75,11 @@ config I2C_AMD8111
will be called i2c-amd8111.
config I2C_AU1550
- tristate "Au1550 SMBus interface"
- depends on I2C && SOC_AU1550
+ tristate "Au1550/Au1200 SMBus interface"
+ depends on I2C && (SOC_AU1550 || SOC_AU1200)
help
If you say yes to this option, support will be included for the
- Au1550 SMBus interface.
+ Au1550 and Au1200 SMBus interface.
This driver can also be built as a module. If so, the module
will be called i2c-au1550.
@@ -196,7 +196,7 @@ config I2C_IBM_IIC
config I2C_IOP3XX
tristate "Intel IOP3xx and IXP4xx on-chip I2C interface"
- depends on (ARCH_IOP3XX || ARCH_IXP4XX) && I2C
+ depends on (ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX) && I2C
help
Say Y here if you want to use the IIC bus controller on
the Intel IOP3xx I/O Processors or IXP4xx Network Processors.
@@ -287,6 +287,16 @@ config I2C_OCORES
This driver can also be built as a module. If so, the module
will be called i2c-ocores.
+config I2C_OMAP
+ tristate "OMAP I2C adapter"
+ depends on I2C && ARCH_OMAP
+ default y if MACH_OMAP_H3 || MACH_OMAP_OSK
+ help
+ If you say yes to this option, support will be included for the
+ I2C interface on the Texas Instruments OMAP1/2 family of processors.
+ Like OMAP1510/1610/1710/5912 and OMAP242x.
+ For details see http://www.ti.com/omap.
+
config I2C_PARPORT
tristate "Parallel port adapter"
depends on I2C && PARPORT
@@ -323,10 +333,10 @@ config I2C_PARPORT_LIGHT
This driver is a light version of i2c-parport. It doesn't depend
on the parport driver, and uses direct I/O access instead. This
- might be prefered on embedded systems where wasting memory for
+ might be preferred on embedded systems where wasting memory for
the clean but heavy parport handling is not an option. The
drawback is a reduced portability and the impossibility to
- dasiy-chain other parallel port devices.
+ daisy-chain other parallel port devices.
Don't say Y here if you said Y or M to i2c-parport. Saying M to
both is possible but both modules should not be loaded at the same
@@ -482,19 +492,19 @@ config I2C_VIA
will be called i2c-via.
config I2C_VIAPRO
- tristate "VIA 82C596/82C686/823x"
+ tristate "VIA 82C596/82C686/82xx"
depends on I2C && PCI
help
If you say yes to this option, support will be included for the VIA
- 82C596/82C686/823x I2C interfaces. Specifically, the following
+ 82C596/82C686/82xx I2C interfaces. Specifically, the following
chipsets are supported:
- 82C596A/B
- 82C686A/B
- 8231
- 8233
- 8233A
- 8235
- 8237
+ VT82C596A/B
+ VT82C686A/B
+ VT8231
+ VT8233/A
+ VT8235
+ VT8237R/A
+ VT8251
This driver can also be built as a module. If so, the module
will be called i2c-viapro.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index ac56df53155b..493c87289b62 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o
obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o
obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o
+obj-$(CONFIG_I2C_OMAP) += i2c-omap.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o
diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c
index d3ef46aeeb3c..e75d339a3481 100644
--- a/drivers/i2c/busses/i2c-ali1535.c
+++ b/drivers/i2c/busses/i2c-ali1535.c
@@ -468,7 +468,7 @@ static u32 ali1535_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = ali1535_access,
.functionality = ali1535_func,
};
diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c
index e6f63208fc4a..33fbb47100a3 100644
--- a/drivers/i2c/busses/i2c-ali1563.c
+++ b/drivers/i2c/busses/i2c-ali1563.c
@@ -367,7 +367,7 @@ static void ali1563_shutdown(struct pci_dev *dev)
release_region(ali1563_smba,ALI1563_SMB_IOSIZE);
}
-static struct i2c_algorithm ali1563_algorithm = {
+static const struct i2c_algorithm ali1563_algorithm = {
.smbus_xfer = ali1563_access,
.functionality = ali1563_func,
};
diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
index 7a5c0941dbc1..3f11b6e1a341 100644
--- a/drivers/i2c/busses/i2c-ali15x3.c
+++ b/drivers/i2c/busses/i2c-ali15x3.c
@@ -463,7 +463,7 @@ static u32 ali15x3_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = ali15x3_access,
.functionality = ali15x3_func,
};
diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
index 1750dedaf4b5..2d21afdc5b1c 100644
--- a/drivers/i2c/busses/i2c-amd756.c
+++ b/drivers/i2c/busses/i2c-amd756.c
@@ -294,7 +294,7 @@ static u32 amd756_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = amd756_access,
.functionality = amd756_func,
};
diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
index e5ef560e686a..0fbc7186c91a 100644
--- a/drivers/i2c/busses/i2c-amd8111.c
+++ b/drivers/i2c/busses/i2c-amd8111.c
@@ -316,7 +316,7 @@ static u32 amd8111_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_I2C_BLOCK | I2C_FUNC_SMBUS_HWPEC_CALC;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = amd8111_access,
.functionality = amd8111_func,
};
diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c
index d06edce03bf4..d7e7c359fc36 100644
--- a/drivers/i2c/busses/i2c-au1550.c
+++ b/drivers/i2c/busses/i2c-au1550.c
@@ -34,8 +34,7 @@
#include <linux/errno.h>
#include <linux/i2c.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-pb1x00/pb1550.h>
+#include <asm/mach-au1x00/au1xxx.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#include "i2c-au1550.h"
@@ -118,13 +117,19 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd)
/* Reset the FIFOs, clear events.
*/
- sp->psc_smbpcr = PSC_SMBPCR_DC;
+ stat = sp->psc_smbstat;
sp->psc_smbevnt = PSC_SMBEVNT_ALLCLR;
au_sync();
- do {
- stat = sp->psc_smbpcr;
+
+ if (!(stat & PSC_SMBSTAT_TE) || !(stat & PSC_SMBSTAT_RE)) {
+ sp->psc_smbpcr = PSC_SMBPCR_DC;
au_sync();
- } while ((stat & PSC_SMBPCR_DC) != 0);
+ do {
+ stat = sp->psc_smbpcr;
+ au_sync();
+ } while ((stat & PSC_SMBPCR_DC) != 0);
+ udelay(50);
+ }
/* Write out the i2c chip address and specify operation
*/
@@ -279,10 +284,10 @@ au1550_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
static u32
au1550_func(struct i2c_adapter *adap)
{
- return I2C_FUNC_I2C;
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm au1550_algo = {
+static const struct i2c_algorithm au1550_algo = {
.master_xfer = au1550_xfer,
.functionality = au1550_func,
};
diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c
index 59f8308c2356..a591fe685f06 100644
--- a/drivers/i2c/busses/i2c-elektor.c
+++ b/drivers/i2c/busses/i2c-elektor.c
@@ -131,7 +131,7 @@ static void pcf_isa_waitforpin(void) {
}
-static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
+static irqreturn_t pcf_isa_handler(int this_irq, void *dev_id) {
spin_lock(&lock);
pcf_pending = 1;
spin_unlock(&lock);
@@ -196,7 +196,6 @@ static struct i2c_algo_pcf_data pcf_isa_data = {
.getclock = pcf_isa_getclock,
.waitforpin = pcf_isa_waitforpin,
.udelay = 10,
- .mdelay = 10,
.timeout = 100,
};
diff --git a/drivers/i2c/busses/i2c-hydra.c b/drivers/i2c/busses/i2c-hydra.c
index e0cb3b0f92fa..457d48a0ab9d 100644
--- a/drivers/i2c/busses/i2c-hydra.c
+++ b/drivers/i2c/busses/i2c-hydra.c
@@ -99,7 +99,6 @@ static struct i2c_algo_bit_data hydra_bit_data = {
.getsda = hydra_bit_getsda,
.getscl = hydra_bit_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = HZ
};
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 7be1d0a3e8f8..bbb2fbee836f 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -434,7 +434,7 @@ static u32 i801_func(struct i2c_adapter *adapter)
| (isich4 ? I2C_FUNC_SMBUS_HWPEC_CALC : 0);
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = i801_access,
.functionality = i801_func,
};
diff --git a/drivers/i2c/busses/i2c-i810.c b/drivers/i2c/busses/i2c-i810.c
index 748be30f2bae..b66fb6bb1870 100644
--- a/drivers/i2c/busses/i2c-i810.c
+++ b/drivers/i2c/busses/i2c-i810.c
@@ -166,7 +166,6 @@ static struct i2c_algo_bit_data i810_i2c_bit_data = {
.getsda = bit_i810i2c_getsda,
.getscl = bit_i810i2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT,
};
@@ -182,7 +181,6 @@ static struct i2c_algo_bit_data i810_ddc_bit_data = {
.getsda = bit_i810ddc_getsda,
.getscl = bit_i810ddc_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT,
};
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 0599bbd65d93..781a99c1647a 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -1,5 +1,5 @@
/*
- * drivers/i2c/i2c-ibm_iic.c
+ * drivers/i2c/busses/i2c-ibm_iic.c
*
* Support for the IIC peripheral on IBM PPC 4xx
*
@@ -320,7 +320,7 @@ err:
/*
* IIC interrupt handler
*/
-static irqreturn_t iic_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t iic_handler(int irq, void *dev_id)
{
struct ibm_iic_private* dev = (struct ibm_iic_private*)dev_id;
volatile struct iic_regs __iomem *iic = dev->vaddr;
@@ -625,7 +625,7 @@ static u32 iic_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
}
-static struct i2c_algorithm iic_algo = {
+static const struct i2c_algorithm iic_algo = {
.master_xfer = iic_xfer,
.functionality = iic_func
};
diff --git a/drivers/i2c/busses/i2c-ibm_iic.h b/drivers/i2c/busses/i2c-ibm_iic.h
index 2b3219d00e92..59d7b437f7ff 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.h
+++ b/drivers/i2c/busses/i2c-ibm_iic.h
@@ -1,5 +1,5 @@
/*
- * drivers/i2c/i2c-ibm_iic.h
+ * drivers/i2c/busses/i2c-ibm_iic.h
*
* Support for the IIC peripheral on IBM PPC 4xx
*
diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c
index 48c56939c861..d108ab4974cc 100644
--- a/drivers/i2c/busses/i2c-iop3xx.c
+++ b/drivers/i2c/busses/i2c-iop3xx.c
@@ -82,14 +82,16 @@ iop3xx_i2c_enable(struct i2c_algo_iop3xx_data *iop3xx_adap)
/*
* Every time unit enable is asserted, GPOD needs to be cleared
- * on IOP321 to avoid data corruption on the bus.
+ * on IOP3XX to avoid data corruption on the bus.
*/
-#ifdef CONFIG_ARCH_IOP321
-#define IOP321_GPOD_I2C0 0x00c0 /* clear these bits to enable ch0 */
-#define IOP321_GPOD_I2C1 0x0030 /* clear these bits to enable ch1 */
-
- *IOP321_GPOD &= (iop3xx_adap->id == 0) ? ~IOP321_GPOD_I2C0 :
- ~IOP321_GPOD_I2C1;
+#ifdef CONFIG_PLAT_IOP
+ if (iop3xx_adap->id == 0) {
+ gpio_line_set(IOP3XX_GPIO_LINE(7), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(6), GPIO_LOW);
+ } else {
+ gpio_line_set(IOP3XX_GPIO_LINE(5), GPIO_LOW);
+ gpio_line_set(IOP3XX_GPIO_LINE(4), GPIO_LOW);
+ }
#endif
/* NB SR bits not same position as CR IE bits :-( */
iop3xx_adap->SR_enabled =
@@ -118,7 +120,7 @@ iop3xx_i2c_transaction_cleanup(struct i2c_algo_iop3xx_data *iop3xx_adap)
* Then it passes the SR flags of interest to BH via adap data
*/
static irqreturn_t
-iop3xx_i2c_irq_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+iop3xx_i2c_irq_handler(int this_irq, void *dev_id)
{
struct i2c_algo_iop3xx_data *iop3xx_adap = dev_id;
u32 sr = __raw_readl(iop3xx_adap->ioaddr + SR_OFFSET);
@@ -401,7 +403,7 @@ iop3xx_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm iop3xx_i2c_algo = {
+static const struct i2c_algorithm iop3xx_i2c_algo = {
.master_xfer = iop3xx_i2c_master_xfer,
.algo_control = iop3xx_i2c_algo_control,
.functionality = iop3xx_i2c_func,
diff --git a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
index c3e1d3e888d7..8ed59a2dff53 100644
--- a/drivers/i2c/busses/i2c-isa.c
+++ b/drivers/i2c/busses/i2c-isa.c
@@ -43,7 +43,7 @@
static u32 isa_func(struct i2c_adapter *adapter);
/* This is the actual algorithm we define */
-static struct i2c_algorithm isa_algorithm = {
+static const struct i2c_algorithm isa_algorithm = {
.functionality = isa_func,
};
@@ -89,9 +89,14 @@ int i2c_isa_add_driver(struct i2c_driver *driver)
dev_dbg(&isa_adapter.dev, "Driver %s registered\n", driver->driver.name);
/* Now look for clients */
- driver->attach_adapter(&isa_adapter);
-
- return 0;
+ res = driver->attach_adapter(&isa_adapter);
+ if (res) {
+ dev_dbg(&isa_adapter.dev,
+ "Driver %s failed to attach adapter, unregistering\n",
+ driver->driver.name);
+ driver_unregister(&driver->driver);
+ }
+ return res;
}
int i2c_isa_del_driver(struct i2c_driver *driver)
@@ -125,6 +130,8 @@ int i2c_isa_del_driver(struct i2c_driver *driver)
static int __init i2c_isa_init(void)
{
+ int err;
+
mutex_init(&isa_adapter.clist_lock);
INIT_LIST_HEAD(&isa_adapter.clients);
@@ -133,8 +140,16 @@ static int __init i2c_isa_init(void)
sprintf(isa_adapter.dev.bus_id, "i2c-%d", isa_adapter.nr);
isa_adapter.dev.driver = &i2c_adapter_driver;
isa_adapter.dev.release = &i2c_adapter_dev_release;
- device_register(&isa_adapter.dev);
- device_create_file(&isa_adapter.dev, &dev_attr_name);
+ err = device_register(&isa_adapter.dev);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to register device\n");
+ goto exit;
+ }
+ err = device_create_file(&isa_adapter.dev, &dev_attr_name);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to create name file\n");
+ goto exit_unregister;
+ }
/* Add this adapter to the i2c_adapter class */
memset(&isa_adapter.class_dev, 0x00, sizeof(struct class_device));
@@ -142,11 +157,24 @@ static int __init i2c_isa_init(void)
isa_adapter.class_dev.class = &i2c_adapter_class;
strlcpy(isa_adapter.class_dev.class_id, isa_adapter.dev.bus_id,
BUS_ID_SIZE);
- class_device_register(&isa_adapter.class_dev);
+ err = class_device_register(&isa_adapter.class_dev);
+ if (err) {
+ printk(KERN_ERR "i2c-isa: Failed to register class device\n");
+ goto exit_remove_name;
+ }
dev_dbg(&isa_adapter.dev, "%s registered\n", isa_adapter.name);
return 0;
+
+exit_remove_name:
+ device_remove_file(&isa_adapter.dev, &dev_attr_name);
+exit_unregister:
+ init_completion(&isa_adapter.dev_released); /* Needed? */
+ device_unregister(&isa_adapter.dev);
+ wait_for_completion(&isa_adapter.dev_released);
+exit:
+ return err;
}
static void __exit i2c_isa_exit(void)
diff --git a/drivers/i2c/busses/i2c-ite.c b/drivers/i2c/busses/i2c-ite.c
index d82e6dae8407..f7d71869b3b9 100644
--- a/drivers/i2c/busses/i2c-ite.c
+++ b/drivers/i2c/busses/i2c-ite.c
@@ -109,7 +109,7 @@ static int iic_ite_getclock(void *data)
static void iic_ite_waitforpin(void) {
DEFINE_WAIT(wait);
int timeout = 2;
- long flags;
+ unsigned long flags;
/* If interrupts are enabled (which they are), then put the process to
* sleep. This process will be awakened by two events -- either the
@@ -140,8 +140,7 @@ static void iic_ite_waitforpin(void) {
}
-static irqreturn_t iic_ite_handler(int this_irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t iic_ite_handler(int this_irq, void *dev_id)
{
spin_lock(&lock);
iic_pending = 1;
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index cd6f45d186ab..dd3f4cd3aa68 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -114,7 +114,6 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
drv_data->algo_data.getsda = ixp2000_bit_getsda;
drv_data->algo_data.getscl = ixp2000_bit_getscl;
drv_data->algo_data.udelay = 6;
- drv_data->algo_data.mdelay = 6;
drv_data->algo_data.timeout = 100;
drv_data->adapter.id = I2C_HW_B_IXP2000,
diff --git a/drivers/i2c/busses/i2c-ixp4xx.c b/drivers/i2c/busses/i2c-ixp4xx.c
index 2ed07112d683..1ce01fb0ac09 100644
--- a/drivers/i2c/busses/i2c-ixp4xx.c
+++ b/drivers/i2c/busses/i2c-ixp4xx.c
@@ -1,5 +1,5 @@
/*
- * drivers/i2c/i2c-adap-ixp4xx.c
+ * drivers/i2c/busses/i2c-ixp4xx.c
*
* Intel's IXP4xx XScale NPU chipsets (IXP420, 421, 422, 425) do not have
* an on board I2C controller but provide 16 GPIO pins that are often
@@ -122,7 +122,6 @@ static int ixp4xx_i2c_probe(struct platform_device *plat_dev)
drv_data->algo_data.getsda = ixp4xx_bit_getsda;
drv_data->algo_data.getscl = ixp4xx_bit_getscl;
drv_data->algo_data.udelay = 10;
- drv_data->algo_data.mdelay = 10;
drv_data->algo_data.timeout = 100;
drv_data->adapter.id = I2C_HW_B_IXP4XX;
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 377ab40944b8..ee65aa1be13a 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -63,7 +63,7 @@ static __inline__ void writeccr(struct mpc_i2c *i2c, u32 x)
writeb(x, i2c->base + MPC_I2C_CR);
}
-static irqreturn_t mpc_i2c_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
{
struct mpc_i2c *i2c = dev_id;
if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
@@ -272,7 +272,7 @@ static u32 mpc_functionality(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm mpc_algo = {
+static const struct i2c_algorithm mpc_algo = {
.master_xfer = mpc_xfer,
.functionality = mpc_functionality,
};
diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c
index ac5cde1bbd2b..bbc8e3a7ff55 100644
--- a/drivers/i2c/busses/i2c-mv64xxx.c
+++ b/drivers/i2c/busses/i2c-mv64xxx.c
@@ -278,7 +278,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
}
static int
-mv64xxx_i2c_intr(int irq, void *dev_id, struct pt_regs *regs)
+mv64xxx_i2c_intr(int irq, void *dev_id)
{
struct mv64xxx_i2c_data *drv_data = dev_id;
unsigned long flags;
@@ -431,7 +431,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
return num;
}
-static struct i2c_algorithm mv64xxx_i2c_algo = {
+static const struct i2c_algorithm mv64xxx_i2c_algo = {
.master_xfer = mv64xxx_i2c_xfer,
.functionality = mv64xxx_i2c_functionality,
};
diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c
index 604b49e22df1..e0292e414ab2 100644
--- a/drivers/i2c/busses/i2c-nforce2.c
+++ b/drivers/i2c/busses/i2c-nforce2.c
@@ -109,7 +109,7 @@ static s32 nforce2_access(struct i2c_adapter *adap, u16 addr,
static u32 nforce2_func(struct i2c_adapter *adapter);
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = nforce2_access,
.functionality = nforce2_func,
};
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 592824087c49..f28a76d1c0af 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -9,7 +9,6 @@
* kind, whether express or implied.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
@@ -144,7 +143,7 @@ static void ocores_process(struct ocores_i2c *i2c)
}
}
-static irqreturn_t ocores_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ocores_isr(int irq, void *dev_id)
{
struct ocores_i2c *i2c = dev_id;
@@ -199,7 +198,7 @@ static u32 ocores_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm ocores_algorithm = {
+static const struct i2c_algorithm ocores_algorithm = {
.master_xfer = ocores_xfer,
.functionality = ocores_func,
};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
new file mode 100644
index 000000000000..dec04da0455c
--- /dev/null
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -0,0 +1,676 @@
+/*
+ * TI OMAP I2C master mode driver
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Copyright (C) 2004 Texas Instruments.
+ *
+ * Updated to work with multiple I2C interfaces on 24xx by
+ * Tony Lindgren <tony@atomide.com> and Imre Deak <imre.deak@nokia.com>
+ * Copyright (C) 2005 Nokia Corporation
+ *
+ * Cleaned up 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
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+
+/* timeout waiting for the controller to respond */
+#define OMAP_I2C_TIMEOUT (msecs_to_jiffies(1000))
+
+#define OMAP_I2C_REV_REG 0x00
+#define OMAP_I2C_IE_REG 0x04
+#define OMAP_I2C_STAT_REG 0x08
+#define OMAP_I2C_IV_REG 0x0c
+#define OMAP_I2C_SYSS_REG 0x10
+#define OMAP_I2C_BUF_REG 0x14
+#define OMAP_I2C_CNT_REG 0x18
+#define OMAP_I2C_DATA_REG 0x1c
+#define OMAP_I2C_SYSC_REG 0x20
+#define OMAP_I2C_CON_REG 0x24
+#define OMAP_I2C_OA_REG 0x28
+#define OMAP_I2C_SA_REG 0x2c
+#define OMAP_I2C_PSC_REG 0x30
+#define OMAP_I2C_SCLL_REG 0x34
+#define OMAP_I2C_SCLH_REG 0x38
+#define OMAP_I2C_SYSTEST_REG 0x3c
+
+/* I2C Interrupt Enable Register (OMAP_I2C_IE): */
+#define OMAP_I2C_IE_XRDY (1 << 4) /* TX data ready int enable */
+#define OMAP_I2C_IE_RRDY (1 << 3) /* RX data ready int enable */
+#define OMAP_I2C_IE_ARDY (1 << 2) /* Access ready int enable */
+#define OMAP_I2C_IE_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_IE_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Status Register (OMAP_I2C_STAT): */
+#define OMAP_I2C_STAT_SBD (1 << 15) /* Single byte data */
+#define OMAP_I2C_STAT_BB (1 << 12) /* Bus busy */
+#define OMAP_I2C_STAT_ROVR (1 << 11) /* Receive overrun */
+#define OMAP_I2C_STAT_XUDF (1 << 10) /* Transmit underflow */
+#define OMAP_I2C_STAT_AAS (1 << 9) /* Address as slave */
+#define OMAP_I2C_STAT_AD0 (1 << 8) /* Address zero */
+#define OMAP_I2C_STAT_XRDY (1 << 4) /* Transmit data ready */
+#define OMAP_I2C_STAT_RRDY (1 << 3) /* Receive data ready */
+#define OMAP_I2C_STAT_ARDY (1 << 2) /* Register access ready */
+#define OMAP_I2C_STAT_NACK (1 << 1) /* No ack interrupt enable */
+#define OMAP_I2C_STAT_AL (1 << 0) /* Arbitration lost int ena */
+
+/* I2C Buffer Configuration Register (OMAP_I2C_BUF): */
+#define OMAP_I2C_BUF_RDMA_EN (1 << 15) /* RX DMA channel enable */
+#define OMAP_I2C_BUF_XDMA_EN (1 << 7) /* TX DMA channel enable */
+
+/* I2C Configuration Register (OMAP_I2C_CON): */
+#define OMAP_I2C_CON_EN (1 << 15) /* I2C module enable */
+#define OMAP_I2C_CON_BE (1 << 14) /* Big endian mode */
+#define OMAP_I2C_CON_STB (1 << 11) /* Start byte mode (master) */
+#define OMAP_I2C_CON_MST (1 << 10) /* Master/slave mode */
+#define OMAP_I2C_CON_TRX (1 << 9) /* TX/RX mode (master only) */
+#define OMAP_I2C_CON_XA (1 << 8) /* Expand address */
+#define OMAP_I2C_CON_RM (1 << 2) /* Repeat mode (master only) */
+#define OMAP_I2C_CON_STP (1 << 1) /* Stop cond (master only) */
+#define OMAP_I2C_CON_STT (1 << 0) /* Start condition (master) */
+
+/* I2C System Test Register (OMAP_I2C_SYSTEST): */
+#ifdef DEBUG
+#define OMAP_I2C_SYSTEST_ST_EN (1 << 15) /* System test enable */
+#define OMAP_I2C_SYSTEST_FREE (1 << 14) /* Free running mode */
+#define OMAP_I2C_SYSTEST_TMODE_MASK (3 << 12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_TMODE_SHIFT (12) /* Test mode select */
+#define OMAP_I2C_SYSTEST_SCL_I (1 << 3) /* SCL line sense in */
+#define OMAP_I2C_SYSTEST_SCL_O (1 << 2) /* SCL line drive out */
+#define OMAP_I2C_SYSTEST_SDA_I (1 << 1) /* SDA line sense in */
+#define OMAP_I2C_SYSTEST_SDA_O (1 << 0) /* SDA line drive out */
+#endif
+
+/* I2C System Status register (OMAP_I2C_SYSS): */
+#define OMAP_I2C_SYSS_RDONE (1 << 0) /* Reset Done */
+
+/* I2C System Configuration Register (OMAP_I2C_SYSC): */
+#define OMAP_I2C_SYSC_SRST (1 << 1) /* Soft Reset */
+
+/* REVISIT: Use platform_data instead of module parameters */
+/* Fast Mode = 400 kHz, Standard = 100 kHz */
+static int clock = 100; /* Default: 100 kHz */
+module_param(clock, int, 0);
+MODULE_PARM_DESC(clock, "Set I2C clock in kHz: 400=fast mode (default == 100)");
+
+struct omap_i2c_dev {
+ struct device *dev;
+ void __iomem *base; /* virtual */
+ int irq;
+ struct clk *iclk; /* Interface clock */
+ struct clk *fclk; /* Functional clock */
+ struct completion cmd_complete;
+ struct resource *ioarea;
+ u16 cmd_err;
+ u8 *buf;
+ size_t buf_len;
+ struct i2c_adapter adapter;
+ unsigned rev1:1;
+};
+
+static inline void omap_i2c_write_reg(struct omap_i2c_dev *i2c_dev,
+ int reg, u16 val)
+{
+ __raw_writew(val, i2c_dev->base + reg);
+}
+
+static inline u16 omap_i2c_read_reg(struct omap_i2c_dev *i2c_dev, int reg)
+{
+ return __raw_readw(i2c_dev->base + reg);
+}
+
+static int omap_i2c_get_clocks(struct omap_i2c_dev *dev)
+{
+ if (cpu_is_omap16xx() || cpu_is_omap24xx()) {
+ dev->iclk = clk_get(dev->dev, "i2c_ick");
+ if (IS_ERR(dev->iclk)) {
+ dev->iclk = NULL;
+ return -ENODEV;
+ }
+ }
+
+ dev->fclk = clk_get(dev->dev, "i2c_fck");
+ if (IS_ERR(dev->fclk)) {
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+ dev->fclk = NULL;
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void omap_i2c_put_clocks(struct omap_i2c_dev *dev)
+{
+ clk_put(dev->fclk);
+ dev->fclk = NULL;
+ if (dev->iclk != NULL) {
+ clk_put(dev->iclk);
+ dev->iclk = NULL;
+ }
+}
+
+static void omap_i2c_enable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_enable(dev->iclk);
+ clk_enable(dev->fclk);
+}
+
+static void omap_i2c_disable_clocks(struct omap_i2c_dev *dev)
+{
+ if (dev->iclk != NULL)
+ clk_disable(dev->iclk);
+ clk_disable(dev->fclk);
+}
+
+static int omap_i2c_init(struct omap_i2c_dev *dev)
+{
+ u16 psc = 0;
+ unsigned long fclk_rate = 12000000;
+ unsigned long timeout;
+
+ if (!dev->rev1) {
+ omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, OMAP_I2C_SYSC_SRST);
+ /* For some reason we need to set the EN bit before the
+ * reset done bit gets set. */
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+ while (!(omap_i2c_read_reg(dev, OMAP_I2C_SYSS_REG) &
+ OMAP_I2C_SYSS_RDONE)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting"
+ "for controller reset\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+
+ if (cpu_class_is_omap1()) {
+ struct clk *armxor_ck;
+
+ armxor_ck = clk_get(NULL, "armxor_ck");
+ if (IS_ERR(armxor_ck))
+ dev_warn(dev->dev, "Could not get armxor_ck\n");
+ else {
+ fclk_rate = clk_get_rate(armxor_ck);
+ clk_put(armxor_ck);
+ }
+ /* TRM for 5912 says the I2C clock must be prescaled to be
+ * between 7 - 12 MHz. The XOR input clock is typically
+ * 12, 13 or 19.2 MHz. So we should have code that produces:
+ *
+ * XOR MHz Divider Prescaler
+ * 12 1 0
+ * 13 2 1
+ * 19.2 2 1
+ */
+ if (fclk_rate > 16000000)
+ psc = (fclk_rate + 8000000) / 12000000;
+ }
+
+ /* Setup clock prescaler to obtain approx 12MHz I2C module clock: */
+ omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, psc);
+
+ /* Program desired operating rate */
+ fclk_rate /= (psc + 1) * 1000;
+ if (psc > 2)
+ psc = 2;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+ omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG,
+ fclk_rate / (clock * 2) - 7 + psc);
+
+ /* Take the I2C module out of reset: */
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
+
+ /* Enable interrupts */
+ omap_i2c_write_reg(dev, OMAP_I2C_IE_REG,
+ (OMAP_I2C_IE_XRDY | OMAP_I2C_IE_RRDY |
+ OMAP_I2C_IE_ARDY | OMAP_I2C_IE_NACK |
+ OMAP_I2C_IE_AL));
+ return 0;
+}
+
+/*
+ * Waiting on Bus Busy
+ */
+static int omap_i2c_wait_for_bb(struct omap_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + OMAP_I2C_TIMEOUT;
+ while (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG) & OMAP_I2C_STAT_BB) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+
+ return 0;
+}
+
+/*
+ * Low level master read/write transaction.
+ */
+static int omap_i2c_xfer_msg(struct i2c_adapter *adap,
+ struct i2c_msg *msg, int stop)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int r;
+ u16 w;
+
+ dev_dbg(dev->dev, "addr: 0x%04x, len: %d, flags: 0x%x, stop: %d\n",
+ msg->addr, msg->len, msg->flags, stop);
+
+ if (msg->len == 0)
+ return -EINVAL;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_SA_REG, msg->addr);
+
+ /* REVISIT: Could the STB bit of I2C_CON be used with probing? */
+ dev->buf = msg->buf;
+ dev->buf_len = msg->len;
+
+ omap_i2c_write_reg(dev, OMAP_I2C_CNT_REG, dev->buf_len);
+
+ init_completion(&dev->cmd_complete);
+ dev->cmd_err = 0;
+
+ w = OMAP_I2C_CON_EN | OMAP_I2C_CON_MST | OMAP_I2C_CON_STT;
+ if (msg->flags & I2C_M_TEN)
+ w |= OMAP_I2C_CON_XA;
+ if (!(msg->flags & I2C_M_RD))
+ w |= OMAP_I2C_CON_TRX;
+ if (stop)
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+
+ r = wait_for_completion_interruptible_timeout(&dev->cmd_complete,
+ OMAP_I2C_TIMEOUT);
+ dev->buf_len = 0;
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ dev_err(dev->dev, "controller timed out\n");
+ omap_i2c_init(dev);
+ return -ETIMEDOUT;
+ }
+
+ if (likely(!dev->cmd_err))
+ return 0;
+
+ /* We have an error */
+ if (dev->cmd_err & (OMAP_I2C_STAT_AL | OMAP_I2C_STAT_ROVR |
+ OMAP_I2C_STAT_XUDF)) {
+ omap_i2c_init(dev);
+ return -EIO;
+ }
+
+ if (dev->cmd_err & OMAP_I2C_STAT_NACK) {
+ if (msg->flags & I2C_M_IGNORE_NAK)
+ return 0;
+ if (stop) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_CON_REG);
+ w |= OMAP_I2C_CON_STP;
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, w);
+ }
+ return -EREMOTEIO;
+ }
+ return -EIO;
+}
+
+
+/*
+ * Prepare controller for a transaction and call omap_i2c_xfer_msg
+ * to do the work during IRQ processing.
+ */
+static int
+omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
+{
+ struct omap_i2c_dev *dev = i2c_get_adapdata(adap);
+ int i;
+ int r;
+
+ omap_i2c_enable_clocks(dev);
+
+ /* REVISIT: initialize and use adap->retries. This is an optional
+ * feature */
+ if ((r = omap_i2c_wait_for_bb(dev)) < 0)
+ goto out;
+
+ for (i = 0; i < num; i++) {
+ r = omap_i2c_xfer_msg(adap, &msgs[i], (i == (num - 1)));
+ if (r != 0)
+ break;
+ }
+
+ if (r == 0)
+ r = num;
+out:
+ omap_i2c_disable_clocks(dev);
+ return r;
+}
+
+static u32
+omap_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static inline void
+omap_i2c_complete_cmd(struct omap_i2c_dev *dev, u16 err)
+{
+ dev->cmd_err |= err;
+ complete(&dev->cmd_complete);
+}
+
+static inline void
+omap_i2c_ack_stat(struct omap_i2c_dev *dev, u16 stat)
+{
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+}
+
+static irqreturn_t
+omap_i2c_rev1_isr(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 iv, w;
+
+ iv = omap_i2c_read_reg(dev, OMAP_I2C_IV_REG);
+ switch (iv) {
+ case 0x00: /* None */
+ break;
+ case 0x01: /* Arbitration lost */
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ break;
+ case 0x02: /* No acknowledgement */
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_STP);
+ break;
+ case 0x03: /* Register access ready */
+ omap_i2c_complete_cmd(dev, 0);
+ break;
+ case 0x04: /* Receive data ready */
+ if (dev->buf_len) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data requested\n");
+ break;
+ case 0x05: /* Transmit data ready */
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no data to send\n");
+ break;
+ default:
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t
+omap_i2c_isr(int this_irq, void *dev_id)
+{
+ struct omap_i2c_dev *dev = dev_id;
+ u16 bits;
+ u16 stat, w;
+ int count = 0;
+
+ bits = omap_i2c_read_reg(dev, OMAP_I2C_IE_REG);
+ while ((stat = (omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG))) & bits) {
+ dev_dbg(dev->dev, "IRQ (ISR = 0x%04x)\n", stat);
+ if (count++ == 100) {
+ dev_warn(dev->dev, "Too much work in one IRQ\n");
+ break;
+ }
+
+ omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
+
+ if (stat & OMAP_I2C_STAT_ARDY) {
+ omap_i2c_complete_cmd(dev, 0);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_RRDY) {
+ w = omap_i2c_read_reg(dev, OMAP_I2C_DATA_REG);
+ if (dev->buf_len) {
+ *dev->buf++ = w;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ *dev->buf++ = w >> 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "RRDY IRQ while no data"
+ "requested\n");
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_RRDY);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_XRDY) {
+ w = 0;
+ if (dev->buf_len) {
+ w = *dev->buf++;
+ dev->buf_len--;
+ if (dev->buf_len) {
+ w |= *dev->buf++ << 8;
+ dev->buf_len--;
+ }
+ } else
+ dev_err(dev->dev, "XRDY IRQ while no"
+ "data to send\n");
+ omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
+ omap_i2c_ack_stat(dev, OMAP_I2C_STAT_XRDY);
+ continue;
+ }
+ if (stat & OMAP_I2C_STAT_ROVR) {
+ dev_err(dev->dev, "Receive overrun\n");
+ dev->cmd_err |= OMAP_I2C_STAT_ROVR;
+ }
+ if (stat & OMAP_I2C_STAT_XUDF) {
+ dev_err(dev->dev, "Transmit overflow\n");
+ dev->cmd_err |= OMAP_I2C_STAT_XUDF;
+ }
+ if (stat & OMAP_I2C_STAT_NACK) {
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_NACK);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+ OMAP_I2C_CON_STP);
+ }
+ if (stat & OMAP_I2C_STAT_AL) {
+ dev_err(dev->dev, "Arbitration lost\n");
+ omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_AL);
+ }
+ }
+
+ return count ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static const struct i2c_algorithm omap_i2c_algo = {
+ .master_xfer = omap_i2c_xfer,
+ .functionality = omap_i2c_func,
+};
+
+static int
+omap_i2c_probe(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *mem, *irq, *ioarea;
+ int r;
+
+ /* NOTE: driver uses the static register mapping */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!mem) {
+ dev_err(&pdev->dev, "no mem resource?\n");
+ return -ENODEV;
+ }
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return -ENODEV;
+ }
+
+ ioarea = request_mem_region(mem->start, (mem->end - mem->start) + 1,
+ pdev->name);
+ if (!ioarea) {
+ dev_err(&pdev->dev, "I2C region already claimed\n");
+ return -EBUSY;
+ }
+
+ if (clock > 200)
+ clock = 400; /* Fast mode */
+ else
+ clock = 100; /* Standard mode */
+
+ dev = kzalloc(sizeof(struct omap_i2c_dev), GFP_KERNEL);
+ if (!dev) {
+ r = -ENOMEM;
+ goto err_release_region;
+ }
+
+ dev->dev = &pdev->dev;
+ dev->irq = irq->start;
+ dev->base = (void __iomem *) IO_ADDRESS(mem->start);
+ platform_set_drvdata(pdev, dev);
+
+ if ((r = omap_i2c_get_clocks(dev)) != 0)
+ goto err_free_mem;
+
+ omap_i2c_enable_clocks(dev);
+
+ if (cpu_is_omap15xx())
+ dev->rev1 = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) < 0x20;
+
+ /* reset ASAP, clearing any IRQs */
+ omap_i2c_init(dev);
+
+ r = request_irq(dev->irq, dev->rev1 ? omap_i2c_rev1_isr : omap_i2c_isr,
+ 0, pdev->name, dev);
+
+ if (r) {
+ dev_err(dev->dev, "failure requesting irq %i\n", dev->irq);
+ goto err_unuse_clocks;
+ }
+ r = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG) & 0xff;
+ dev_info(dev->dev, "bus %d rev%d.%d at %d kHz\n",
+ pdev->id, r >> 4, r & 0xf, clock);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strncpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
+ adap->algo = &omap_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+
+ /* i2c device drivers may be active on return from add_adapter() */
+ r = i2c_add_adapter(adap);
+ if (r) {
+ dev_err(dev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ omap_i2c_disable_clocks(dev);
+
+ return 0;
+
+err_free_irq:
+ free_irq(dev->irq, dev);
+err_unuse_clocks:
+ omap_i2c_disable_clocks(dev);
+ omap_i2c_put_clocks(dev);
+err_free_mem:
+ platform_set_drvdata(pdev, NULL);
+ kfree(dev);
+err_release_region:
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+
+ return r;
+}
+
+static int
+omap_i2c_remove(struct platform_device *pdev)
+{
+ struct omap_i2c_dev *dev = platform_get_drvdata(pdev);
+ struct resource *mem;
+
+ platform_set_drvdata(pdev, NULL);
+
+ free_irq(dev->irq, dev);
+ i2c_del_adapter(&dev->adapter);
+ omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
+ omap_i2c_put_clocks(dev);
+ kfree(dev);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(mem->start, (mem->end - mem->start) + 1);
+ return 0;
+}
+
+static struct platform_driver omap_i2c_driver = {
+ .probe = omap_i2c_probe,
+ .remove = omap_i2c_remove,
+ .driver = {
+ .name = "i2c_omap",
+ .owner = THIS_MODULE,
+ },
+};
+
+/* I2C may be needed to bring up other drivers */
+static int __init
+omap_i2c_init_driver(void)
+{
+ return platform_driver_register(&omap_i2c_driver);
+}
+subsys_initcall(omap_i2c_init_driver);
+
+static void __exit omap_i2c_exit_driver(void)
+{
+ platform_driver_unregister(&omap_i2c_driver);
+}
+module_exit(omap_i2c_exit_driver);
+
+MODULE_AUTHOR("MontaVista Software, Inc. (and others)");
+MODULE_DESCRIPTION("TI OMAP I2C bus adapter");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index e09ebbb2f9f0..5eb2bd294fd9 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -103,7 +103,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
.getsda = parport_getsda,
.getscl = parport_getscl,
.udelay = 50,
- .mdelay = 50,
.timeout = HZ,
};
diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c
index 934bd55bae15..48a829431c7b 100644
--- a/drivers/i2c/busses/i2c-parport.c
+++ b/drivers/i2c/busses/i2c-parport.c
@@ -138,7 +138,6 @@ static struct i2c_algo_bit_data parport_algo_data = {
.getsda = parport_getsda,
.getscl = parport_getscl,
.udelay = 60,
- .mdelay = 60,
.timeout = HZ,
};
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index d9b4ddbad7e0..407840b6a260 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -99,7 +99,7 @@ static int pca_isa_waitforinterrupt(struct i2c_algo_pca_data *adap)
return ret;
}
-static irqreturn_t pca_handler(int this_irq, void *dev_id, struct pt_regs *regs) {
+static irqreturn_t pca_handler(int this_irq, void *dev_id) {
wake_up_interruptible(&pca_wait);
return IRQ_HANDLED;
}
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 8f2f65b793b9..30c7a1b38cbd 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -376,7 +376,7 @@ static u32 piix4_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = piix4_access,
.functionality = piix4_func,
};
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index d658d9107955..648d55533d87 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -175,16 +175,16 @@ static u32 i2c_powermac_func(struct i2c_adapter * adapter)
}
/* For now, we only handle smbus */
-static struct i2c_algorithm i2c_powermac_algorithm = {
+static const struct i2c_algorithm i2c_powermac_algorithm = {
.smbus_xfer = i2c_powermac_smbus_xfer,
.master_xfer = i2c_powermac_master_xfer,
.functionality = i2c_powermac_func,
};
-static int i2c_powermac_remove(struct device *dev)
+static int i2c_powermac_remove(struct platform_device *dev)
{
- struct i2c_adapter *adapter = dev_get_drvdata(dev);
+ struct i2c_adapter *adapter = platform_get_drvdata(dev);
struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter);
int rc;
@@ -195,16 +195,16 @@ static int i2c_powermac_remove(struct device *dev)
if (rc)
printk("i2c-powermac.c: Failed to remove bus %s !\n",
adapter->name);
- dev_set_drvdata(dev, NULL);
+ platform_set_drvdata(dev, NULL);
kfree(adapter);
return 0;
}
-static int i2c_powermac_probe(struct device *dev)
+static int __devexit i2c_powermac_probe(struct platform_device *dev)
{
- struct pmac_i2c_bus *bus = dev->platform_data;
+ struct pmac_i2c_bus *bus = dev->dev.platform_data;
struct device_node *parent = NULL;
struct i2c_adapter *adapter;
char name[32];
@@ -246,11 +246,11 @@ static int i2c_powermac_probe(struct device *dev)
printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n");
return -ENOMEM;
}
- dev_set_drvdata(dev, adapter);
+ platform_set_drvdata(dev, adapter);
strcpy(adapter->name, name);
adapter->algo = &i2c_powermac_algorithm;
i2c_set_adapdata(adapter, bus);
- adapter->dev.parent = dev;
+ adapter->dev.parent = &dev->dev;
pmac_i2c_attach_adapter(bus, adapter);
rc = i2c_add_adapter(adapter);
if (rc) {
@@ -265,23 +265,25 @@ static int i2c_powermac_probe(struct device *dev)
}
-static struct device_driver i2c_powermac_driver = {
- .name = "i2c-powermac",
- .bus = &platform_bus_type,
+static struct platform_driver i2c_powermac_driver = {
.probe = i2c_powermac_probe,
- .remove = i2c_powermac_remove,
+ .remove = __devexit_p(i2c_powermac_remove),
+ .driver = {
+ .name = "i2c-powermac",
+ .bus = &platform_bus_type,
+ },
};
static int __init i2c_powermac_init(void)
{
- driver_register(&i2c_powermac_driver);
+ platform_driver_register(&i2c_powermac_driver);
return 0;
}
static void __exit i2c_powermac_cleanup(void)
{
- driver_unregister(&i2c_powermac_driver);
+ platform_driver_unregister(&i2c_powermac_driver);
}
module_init(i2c_powermac_init);
diff --git a/drivers/i2c/busses/i2c-prosavage.c b/drivers/i2c/busses/i2c-prosavage.c
index 9479525892e3..7745e21874a8 100644
--- a/drivers/i2c/busses/i2c-prosavage.c
+++ b/drivers/i2c/busses/i2c-prosavage.c
@@ -180,7 +180,6 @@ static int i2c_register_bus(struct pci_dev *dev, struct s_i2c_bus *p, void __iom
p->algo.getsda = bit_s3via_getsda;
p->algo.getscl = bit_s3via_getscl;
p->algo.udelay = CYCLE_DELAY;
- p->algo.mdelay = CYCLE_DELAY;
p->algo.timeout = TIMEOUT;
p->algo.data = p;
p->mmvga = mmvga;
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c
index ee114b48face..81050d3c9b21 100644
--- a/drivers/i2c/busses/i2c-pxa.c
+++ b/drivers/i2c/busses/i2c-pxa.c
@@ -850,7 +850,7 @@ static void i2c_pxa_irq_rxfull(struct pxa_i2c *i2c, u32 isr)
ICR = icr;
}
-static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id)
{
struct pxa_i2c *i2c = dev_id;
u32 isr = ISR;
@@ -926,7 +926,7 @@ static u32 i2c_pxa_functionality(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
-static struct i2c_algorithm i2c_pxa_algorithm = {
+static const struct i2c_algorithm i2c_pxa_algorithm = {
.master_xfer = i2c_pxa_xfer,
.functionality = i2c_pxa_functionality,
};
diff --git a/drivers/i2c/busses/i2c-rpx.c b/drivers/i2c/busses/i2c-rpx.c
index 0ebec3c1a54e..8764df06f51d 100644
--- a/drivers/i2c/busses/i2c-rpx.c
+++ b/drivers/i2c/busses/i2c-rpx.c
@@ -55,10 +55,10 @@ rpx_iic_init(struct i2c_algo_8xx_data *data)
data->i2c = (i2c8xx_t *)&(((immap_t *)IMAP_ADDR)->im_i2c);
}
-static int rpx_install_isr(int irq, void (*func)(void *, void *), void *data)
+static int rpx_install_isr(int irq, void (*func)(void *), void *data)
{
/* install interrupt handler */
- cpm_install_handler(irq, (void (*)(void *, struct pt_regs *)) func, data);
+ cpm_install_handler(irq, func, data);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index 5d2950e91fc5..4ca6de209b8b 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -423,8 +423,7 @@ static int i2s_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat)
* top level IRQ servicing routine
*/
-static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
{
struct s3c24xx_i2c *i2c = dev_id;
unsigned long status;
@@ -566,7 +565,7 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap)
/* i2c bus registration info */
-static struct i2c_algorithm s3c24xx_i2c_algorithm = {
+static const struct i2c_algorithm s3c24xx_i2c_algorithm = {
.master_xfer = s3c24xx_i2c_xfer,
.functionality = s3c24xx_i2c_func,
};
diff --git a/drivers/i2c/busses/i2c-savage4.c b/drivers/i2c/busses/i2c-savage4.c
index 0c8518298e4d..209f47ea1750 100644
--- a/drivers/i2c/busses/i2c-savage4.c
+++ b/drivers/i2c/busses/i2c-savage4.c
@@ -140,7 +140,6 @@ static struct i2c_algo_bit_data sav_i2c_bit_data = {
.getsda = bit_savi2c_getsda,
.getscl = bit_savi2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c
index fa503ed9f86d..0ca599d3b402 100644
--- a/drivers/i2c/busses/i2c-sibyte.c
+++ b/drivers/i2c/busses/i2c-sibyte.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2004 Steven J. Hill
* Copyright (C) 2001,2002,2003 Broadcom Corporation
+ * Copyright (C) 1995-2000 Simon G. Vogl
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -17,11 +18,162 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/i2c-algo-sibyte.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <asm/io.h>
#include <asm/sibyte/sb1250_regs.h>
#include <asm/sibyte/sb1250_smbus.h>
+
+struct i2c_algo_sibyte_data {
+ void *data; /* private data */
+ int bus; /* which bus */
+ void *reg_base; /* CSR base */
+};
+
+/* ----- global defines ----------------------------------------------- */
+#define SMB_CSR(a,r) ((long)(a->reg_base + r))
+
+/* ----- global variables --------------------------------------------- */
+
+/* module parameters:
+ */
+static int bit_scan; /* have a look at what's hanging 'round */
+module_param(bit_scan, int, 0);
+MODULE_PARM_DESC(bit_scan, "Scan for active chips on the bus");
+
+
+static int smbus_xfer(struct i2c_adapter *i2c_adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size, union i2c_smbus_data * data)
+{
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+ int data_bytes = 0;
+ int error;
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ switch (size) {
+ case I2C_SMBUS_QUICK:
+ csr_out32((V_SMB_ADDR(addr) |
+ (read_write == I2C_SMBUS_READ ? M_SMB_QDATA : 0) |
+ V_SMB_TT_QUICKCMD), SMB_CSR(adap, R_SMB_START));
+ break;
+ case I2C_SMBUS_BYTE:
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_BYTE_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD1BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 1;
+ } else {
+ csr_out32(V_SMB_LB(data->byte),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ case I2C_SMBUS_WORD_DATA:
+ csr_out32(V_SMB_CMD(command), SMB_CSR(adap, R_SMB_CMD));
+ if (read_write == I2C_SMBUS_READ) {
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_CMD_RD2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ data_bytes = 2;
+ } else {
+ csr_out32(V_SMB_LB(data->word & 0xff),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32(V_SMB_MB(data->word >> 8),
+ SMB_CSR(adap, R_SMB_DATA));
+ csr_out32((V_SMB_ADDR(addr) | V_SMB_TT_WR2BYTE),
+ SMB_CSR(adap, R_SMB_START));
+ }
+ break;
+ default:
+ return -1; /* XXXKW better error code? */
+ }
+
+ while (csr_in32(SMB_CSR(adap, R_SMB_STATUS)) & M_SMB_BUSY)
+ ;
+
+ error = csr_in32(SMB_CSR(adap, R_SMB_STATUS));
+ if (error & M_SMB_ERROR) {
+ /* Clear error bit by writing a 1 */
+ csr_out32(M_SMB_ERROR, SMB_CSR(adap, R_SMB_STATUS));
+ return -1; /* XXXKW better error code? */
+ }
+
+ if (data_bytes == 1)
+ data->byte = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xff;
+ if (data_bytes == 2)
+ data->word = csr_in32(SMB_CSR(adap, R_SMB_DATA)) & 0xffff;
+
+ return 0;
+}
+
+static u32 bit_func(struct i2c_adapter *adap)
+{
+ return (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+ I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA);
+}
+
+
+/* -----exported algorithm data: ------------------------------------- */
+
+static const struct i2c_algorithm i2c_sibyte_algo = {
+ .smbus_xfer = smbus_xfer,
+ .functionality = bit_func,
+};
+
+/*
+ * registering functions to load algorithms at runtime
+ */
+int i2c_sibyte_add_bus(struct i2c_adapter *i2c_adap, int speed)
+{
+ int i;
+ struct i2c_algo_sibyte_data *adap = i2c_adap->algo_data;
+
+ /* register new adapter to i2c module... */
+ i2c_adap->algo = &i2c_sibyte_algo;
+
+ /* Set the frequency to 100 kHz */
+ csr_out32(speed, SMB_CSR(adap,R_SMB_FREQ));
+ csr_out32(0, SMB_CSR(adap,R_SMB_CONTROL));
+
+ /* scan bus */
+ if (bit_scan) {
+ union i2c_smbus_data data;
+ int rc;
+ printk(KERN_INFO " i2c-algo-sibyte.o: scanning bus %s.\n",
+ i2c_adap->name);
+ for (i = 0x00; i < 0x7f; i++) {
+ /* XXXKW is this a realistic probe? */
+ rc = smbus_xfer(i2c_adap, i, 0, I2C_SMBUS_READ, 0,
+ I2C_SMBUS_BYTE_DATA, &data);
+ if (!rc) {
+ printk("(%02x)",i);
+ } else
+ printk(".");
+ }
+ printk("\n");
+ }
+
+ return i2c_add_adapter(i2c_adap);
+}
+
+
static struct i2c_algo_sibyte_data sibyte_board_data[2] = {
{ NULL, 0, (void *) (CKSEG1+A_SMB_BASE(0)) },
{ NULL, 1, (void *) (CKSEG1+A_SMB_BASE(1)) }
@@ -58,13 +210,13 @@ static int __init i2c_sibyte_init(void)
static void __exit i2c_sibyte_exit(void)
{
- i2c_sibyte_del_bus(&sibyte_board_adapter[0]);
- i2c_sibyte_del_bus(&sibyte_board_adapter[1]);
+ i2c_del_adapter(&sibyte_board_adapter[0]);
+ i2c_del_adapter(&sibyte_board_adapter[1]);
}
module_init(i2c_sibyte_init);
module_exit(i2c_sibyte_exit);
-MODULE_AUTHOR("Kip Walker <kwalker@broadcom.com>, Steven J. Hill <sjhill@realitydiluted.com>");
+MODULE_AUTHOR("Kip Walker (Broadcom Corp.), Steven J. Hill <sjhill@realitydiluted.com>");
MODULE_DESCRIPTION("SMBus adapter routines for SiByte boards");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index b57ab74d23ec..38bbfd840b6b 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -358,7 +358,7 @@ static u32 sis5595_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis5595_access,
.functionality = sis5595_func,
};
diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c
index acb75e282414..dec0bafb52ab 100644
--- a/drivers/i2c/busses/i2c-sis630.c
+++ b/drivers/i2c/busses/i2c-sis630.c
@@ -450,7 +450,7 @@ exit:
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis630_access,
.functionality = sis630_func,
};
diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
index 1a73c0532fc7..7fd07fbac336 100644
--- a/drivers/i2c/busses/i2c-sis96x.c
+++ b/drivers/i2c/busses/i2c-sis96x.c
@@ -242,7 +242,7 @@ static u32 sis96x_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_PROC_CALL;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = sis96x_access,
.functionality = sis96x_func,
};
diff --git a/drivers/i2c/busses/i2c-stub.c b/drivers/i2c/busses/i2c-stub.c
index 73f481e93a36..a54adc50d162 100644
--- a/drivers/i2c/busses/i2c-stub.c
+++ b/drivers/i2c/busses/i2c-stub.c
@@ -27,6 +27,10 @@
#include <linux/errno.h>
#include <linux/i2c.h>
+static unsigned short chip_addr;
+module_param(chip_addr, ushort, S_IRUGO);
+MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
+
static u8 stub_pointer;
static u8 stub_bytes[256];
static u16 stub_words[256];
@@ -37,6 +41,9 @@ static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
{
s32 ret;
+ if (addr != chip_addr)
+ return -ENODEV;
+
switch (size) {
case I2C_SMBUS_QUICK:
@@ -108,7 +115,7 @@ static u32 stub_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.functionality = stub_func,
.smbus_xfer = stub_xfer,
};
@@ -122,7 +129,17 @@ static struct i2c_adapter stub_adapter = {
static int __init i2c_stub_init(void)
{
- printk(KERN_INFO "i2c-stub loaded\n");
+ if (!chip_addr) {
+ printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
+ return -ENODEV;
+ }
+ if (chip_addr < 0x03 || chip_addr > 0x77) {
+ printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
+ chip_addr);
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
return i2c_add_adapter(&stub_adapter);
}
diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c
index 484bbacfce6b..910e200ad500 100644
--- a/drivers/i2c/busses/i2c-via.c
+++ b/drivers/i2c/busses/i2c-via.c
@@ -81,7 +81,6 @@ static struct i2c_algo_bit_data bit_data = {
.getsda = bit_via_getsda,
.getscl = bit_via_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = HZ
};
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 47e52bf2c5ec..efc6bbf0cc0a 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -34,6 +34,8 @@
VT8233A 0x3147 yes?
VT8235 0x3177 yes
VT8237R 0x3227 yes
+ VT8237A 0x3337 yes
+ VT8251 0x3287 yes
Note: we assume there can only be one device, with one SMBus interface.
*/
@@ -297,7 +299,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
return func;
}
-static struct i2c_algorithm smbus_algorithm = {
+static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = vt596_access,
.functionality = vt596_func,
};
@@ -381,7 +383,9 @@ found:
dev_dbg(&pdev->dev, "VT596_smba = 0x%X\n", vt596_smba);
switch (pdev->device) {
+ case PCI_DEVICE_ID_VIA_8251:
case PCI_DEVICE_ID_VIA_8237:
+ case PCI_DEVICE_ID_VIA_8237A:
case PCI_DEVICE_ID_VIA_8235:
case PCI_DEVICE_ID_VIA_8233A:
case PCI_DEVICE_ID_VIA_8233_0:
@@ -432,8 +436,12 @@ static struct pci_device_id vt596_ids[] = {
.driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237),
.driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237A),
+ .driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4),
.driver_data = SMBBA1 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8251),
+ .driver_data = SMBBA3 },
{ 0, }
};
diff --git a/drivers/i2c/busses/i2c-voodoo3.c b/drivers/i2c/busses/i2c-voodoo3.c
index b675773b0cc1..6c8d25183382 100644
--- a/drivers/i2c/busses/i2c-voodoo3.c
+++ b/drivers/i2c/busses/i2c-voodoo3.c
@@ -160,7 +160,6 @@ static struct i2c_algo_bit_data voo_i2c_bit_data = {
.getsda = bit_vooi2c_getsda,
.getscl = bit_vooi2c_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
@@ -177,7 +176,6 @@ static struct i2c_algo_bit_data voo_ddc_bit_data = {
.getsda = bit_vooddc_getsda,
.getscl = bit_vooddc_getscl,
.udelay = CYCLE_DELAY,
- .mdelay = CYCLE_DELAY,
.timeout = TIMEOUT
};
diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c
index eae9e81be375..32aab0d34ee9 100644
--- a/drivers/i2c/busses/scx200_acb.c
+++ b/drivers/i2c/busses/scx200_acb.c
@@ -383,7 +383,7 @@ static u32 scx200_acb_func(struct i2c_adapter *adapter)
}
/* For now, we only handle combined mode (smbus) */
-static struct i2c_algorithm scx200_acb_algorithm = {
+static const struct i2c_algorithm scx200_acb_algorithm = {
.smbus_xfer = scx200_acb_smbus_xfer,
.functionality = scx200_acb_func,
};
diff --git a/drivers/i2c/busses/scx200_i2c.c b/drivers/i2c/busses/scx200_i2c.c
index cb3ef5ac99fd..8ddbae4fafe6 100644
--- a/drivers/i2c/busses/scx200_i2c.c
+++ b/drivers/i2c/busses/scx200_i2c.c
@@ -1,4 +1,4 @@
-/* linux/drivers/i2c/scx200_i2c.c
+/* linux/drivers/i2c/busses/scx200_i2c.c
Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com>
@@ -71,12 +71,12 @@ static int scx200_i2c_getsda(void *data)
*/
static struct i2c_algo_bit_data scx200_i2c_data = {
- NULL,
- scx200_i2c_setsda,
- scx200_i2c_setscl,
- scx200_i2c_getsda,
- scx200_i2c_getscl,
- 10, 10, 100, /* waits, timeout */
+ .setsda = scx200_i2c_setsda,
+ .setscl = scx200_i2c_setscl,
+ .getsda = scx200_i2c_getsda,
+ .getscl = scx200_i2c_getscl,
+ .udelay = 10,
+ .timeout = 100,
};
static struct i2c_adapter scx200_i2c_ops = {
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index 13c108269a6d..cec3a0c3894d 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -209,10 +209,14 @@ static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
}
/* create the sysfs eeprom file */
- sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
+ err = sysfs_create_bin_file(&new_client->dev.kobj, &eeprom_attr);
+ if (err)
+ goto exit_detach;
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
@@ -223,6 +227,8 @@ static int eeprom_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
+
err = i2c_detach_client(client);
if (err)
return err;
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index f92505b94c61..ccdf3e90862b 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -30,7 +30,7 @@
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
@@ -669,7 +669,7 @@ pulldown:
dump_regs(isp, "otg->isp1301");
}
-static irqreturn_t omap_otg_irq(int irq, void *_isp, struct pt_regs *regs)
+static irqreturn_t omap_otg_irq(int irq, void *_isp)
{
u16 otg_irq = OTG_IRQ_SRC_REG;
u32 otg_ctrl;
@@ -1181,7 +1181,7 @@ isp1301_work(void *data)
isp->working = 0;
}
-static irqreturn_t isp1301_irq(int irq, void *isp, struct pt_regs *regs)
+static irqreturn_t isp1301_irq(int irq, void *isp)
{
isp1301_defer_work(isp, WORK_UPDATE_OTG);
return IRQ_HANDLED;
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index 88d2ddee4490..76645c142977 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -199,8 +199,7 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
mutex_init(&data->update_lock);
/* Init fake client data */
- /* set the client data to the i2c_client so that it will get freed */
- i2c_set_clientdata(fake_client, fake_client);
+ i2c_set_clientdata(fake_client, NULL);
fake_client->addr = address | 1;
fake_client->adapter = adapter;
fake_client->driver = &max6875_driver;
@@ -214,13 +213,17 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
goto exit_kfree2;
if ((err = i2c_attach_client(fake_client)) != 0)
- goto exit_detach;
+ goto exit_detach1;
- sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
+ err = sysfs_create_bin_file(&real_client->dev.kobj, &user_eeprom_attr);
+ if (err)
+ goto exit_detach2;
return 0;
-exit_detach:
+exit_detach2:
+ i2c_detach_client(fake_client);
+exit_detach1:
i2c_detach_client(real_client);
exit_kfree2:
kfree(fake_client);
@@ -229,14 +232,24 @@ exit_kfree1:
return err;
}
+/* Will be called for both the real client and the fake client */
static int max6875_detach_client(struct i2c_client *client)
{
int err;
+ struct max6875_data *data = i2c_get_clientdata(client);
+
+ /* data is NULL for the fake client */
+ if (data)
+ sysfs_remove_bin_file(&client->dev.kobj, &user_eeprom_attr);
err = i2c_detach_client(client);
if (err)
return err;
- kfree(i2c_get_clientdata(client));
+
+ if (data) /* real client */
+ kfree(data);
+ else /* fake client */
+ kfree(client);
return 0;
}
diff --git a/drivers/i2c/chips/pca9539.c b/drivers/i2c/chips/pca9539.c
index cb22280cdd27..f43c4e79b55e 100644
--- a/drivers/i2c/chips/pca9539.c
+++ b/drivers/i2c/chips/pca9539.c
@@ -148,11 +148,16 @@ static int pca9539_detect(struct i2c_adapter *adapter, int address, int kind)
if ((err = i2c_attach_client(new_client)))
goto exit_kfree;
- /* Register sysfs hooks (don't care about failure) */
- sysfs_create_group(&new_client->dev.kobj, &pca9539_defattr_group);
+ /* Register sysfs hooks */
+ err = sysfs_create_group(&new_client->dev.kobj,
+ &pca9539_defattr_group);
+ if (err)
+ goto exit_detach;
return 0;
+exit_detach:
+ i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
@@ -163,6 +168,8 @@ static int pca9539_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_group(&client->dev.kobj, &pca9539_defattr_group);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c
index c3e6449c4481..32b25427eaba 100644
--- a/drivers/i2c/chips/pcf8574.c
+++ b/drivers/i2c/chips/pcf8574.c
@@ -105,6 +105,16 @@ static ssize_t set_write(struct device *dev, struct device_attribute *attr, cons
static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
+static struct attribute *pcf8574_attributes[] = {
+ &dev_attr_read.attr,
+ &dev_attr_write.attr,
+ NULL
+};
+
+static const struct attribute_group pcf8574_attr_group = {
+ .attrs = pcf8574_attributes,
+};
+
/*
* Real code
*/
@@ -166,13 +176,13 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind)
pcf8574_init_client(new_client);
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_read);
- device_create_file(&new_client->dev, &dev_attr_write);
+ err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group);
+ if (err)
+ goto exit_detach;
return 0;
-/* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
-
+ exit_detach:
+ i2c_detach_client(new_client);
exit_free:
kfree(data);
exit:
@@ -183,6 +193,8 @@ static int pcf8574_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/chips/pcf8591.c b/drivers/i2c/chips/pcf8591.c
index 925a6b371fd2..4dc36376eb32 100644
--- a/drivers/i2c/chips/pcf8591.c
+++ b/drivers/i2c/chips/pcf8591.c
@@ -158,6 +158,28 @@ static ssize_t set_out0_enable(struct device *dev, struct device_attribute *attr
static DEVICE_ATTR(out0_enable, S_IWUSR | S_IRUGO,
show_out0_enable, set_out0_enable);
+static struct attribute *pcf8591_attributes[] = {
+ &dev_attr_out0_enable.attr,
+ &dev_attr_out0_output.attr,
+ &dev_attr_in0_input.attr,
+ &dev_attr_in1_input.attr,
+ NULL
+};
+
+static const struct attribute_group pcf8591_attr_group = {
+ .attrs = pcf8591_attributes,
+};
+
+static struct attribute *pcf8591_attributes_opt[] = {
+ &dev_attr_in2_input.attr,
+ &dev_attr_in3_input.attr,
+ NULL
+};
+
+static const struct attribute_group pcf8591_attr_group_opt = {
+ .attrs = pcf8591_attributes_opt,
+};
+
/*
* Real code
*/
@@ -211,24 +233,31 @@ static int pcf8591_detect(struct i2c_adapter *adapter, int address, int kind)
pcf8591_init_client(new_client);
/* Register sysfs hooks */
- device_create_file(&new_client->dev, &dev_attr_out0_enable);
- device_create_file(&new_client->dev, &dev_attr_out0_output);
- device_create_file(&new_client->dev, &dev_attr_in0_input);
- device_create_file(&new_client->dev, &dev_attr_in1_input);
+ err = sysfs_create_group(&new_client->dev.kobj, &pcf8591_attr_group);
+ if (err)
+ goto exit_detach;
/* Register input2 if not in "two differential inputs" mode */
- if (input_mode != 3 )
- device_create_file(&new_client->dev, &dev_attr_in2_input);
-
+ if (input_mode != 3) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in2_input)))
+ goto exit_sysfs_remove;
+ }
+
/* Register input3 only in "four single ended inputs" mode */
- if (input_mode == 0)
- device_create_file(&new_client->dev, &dev_attr_in3_input);
-
+ if (input_mode == 0) {
+ if ((err = device_create_file(&new_client->dev,
+ &dev_attr_in3_input)))
+ goto exit_sysfs_remove;
+ }
+
return 0;
-
- /* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
+exit_sysfs_remove:
+ sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group_opt);
+ sysfs_remove_group(&new_client->dev.kobj, &pcf8591_attr_group);
+exit_detach:
+ i2c_detach_client(new_client);
exit_kfree:
kfree(data);
exit:
@@ -239,6 +268,9 @@ static int pcf8591_detach_client(struct i2c_client *client)
{
int err;
+ sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group_opt);
+ sysfs_remove_group(&client->dev.kobj, &pcf8591_attr_group);
+
if ((err = i2c_detach_client(client)))
return err;
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index 0be6fd6a267d..60bef94cd25f 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -305,7 +305,7 @@ static int dbg_show(struct seq_file *s, void *_)
static int dbg_tps_open(struct inode *inode, struct file *file)
{
- return single_open(file, dbg_show, inode->u.generic_ip);
+ return single_open(file, dbg_show, inode->i_private);
}
static struct file_operations debug_fops = {
@@ -446,7 +446,7 @@ static void tps65010_work(void *_tps)
mutex_unlock(&tps->lock);
}
-static irqreturn_t tps65010_irq(int irq, void *_tps, struct pt_regs *regs)
+static irqreturn_t tps65010_irq(int irq, void *_tps)
{
struct tps65010 *tps = _tps;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 9cb277d6aa48..7ca81f42d14b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -183,15 +183,21 @@ int i2c_add_adapter(struct i2c_adapter *adap)
sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
adap->dev.driver = &i2c_adapter_driver;
adap->dev.release = &i2c_adapter_dev_release;
- device_register(&adap->dev);
- device_create_file(&adap->dev, &dev_attr_name);
+ res = device_register(&adap->dev);
+ if (res)
+ goto out_list;
+ res = device_create_file(&adap->dev, &dev_attr_name);
+ if (res)
+ goto out_unregister;
/* Add this adapter to the i2c_adapter class */
memset(&adap->class_dev, 0x00, sizeof(struct class_device));
adap->class_dev.dev = &adap->dev;
adap->class_dev.class = &i2c_adapter_class;
strlcpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
- class_device_register(&adap->class_dev);
+ res = class_device_register(&adap->class_dev);
+ if (res)
+ goto out_remove_name;
dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name);
@@ -206,6 +212,17 @@ int i2c_add_adapter(struct i2c_adapter *adap)
out_unlock:
mutex_unlock(&core_lists);
return res;
+
+out_remove_name:
+ device_remove_file(&adap->dev, &dev_attr_name);
+out_unregister:
+ init_completion(&adap->dev_released); /* Needed? */
+ device_unregister(&adap->dev);
+ wait_for_completion(&adap->dev_released);
+out_list:
+ list_del(&adap->list);
+ idr_remove(&i2c_adapter_idr, adap->nr);
+ goto out_unlock;
}
@@ -394,23 +411,15 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
int i2c_attach_client(struct i2c_client *client)
{
struct i2c_adapter *adapter = client->adapter;
+ int res = 0;
mutex_lock(&adapter->clist_lock);
if (__i2c_check_addr(client->adapter, client->addr)) {
- mutex_unlock(&adapter->clist_lock);
- return -EBUSY;
+ res = -EBUSY;
+ goto out_unlock;
}
list_add_tail(&client->list,&adapter->clients);
- mutex_unlock(&adapter->clist_lock);
- if (adapter->client_register) {
- if (adapter->client_register(client)) {
- dev_dbg(&adapter->dev, "client_register "
- "failed for client [%s] at 0x%02x\n",
- client->name, client->addr);
- }
- }
-
client->usage_count = 0;
client->dev.parent = &client->adapter->dev;
@@ -422,10 +431,35 @@ int i2c_attach_client(struct i2c_client *client)
"%d-%04x", i2c_adapter_id(adapter), client->addr);
dev_dbg(&adapter->dev, "client [%s] registered with bus id %s\n",
client->name, client->dev.bus_id);
- device_register(&client->dev);
- device_create_file(&client->dev, &dev_attr_client_name);
-
+ res = device_register(&client->dev);
+ if (res)
+ goto out_list;
+ res = device_create_file(&client->dev, &dev_attr_client_name);
+ if (res)
+ goto out_unregister;
+ mutex_unlock(&adapter->clist_lock);
+
+ if (adapter->client_register) {
+ if (adapter->client_register(client)) {
+ dev_dbg(&adapter->dev, "client_register "
+ "failed for client [%s] at 0x%02x\n",
+ client->name, client->addr);
+ }
+ }
+
return 0;
+
+out_unregister:
+ init_completion(&client->released); /* Needed? */
+ device_unregister(&client->dev);
+ wait_for_completion(&client->released);
+out_list:
+ list_del(&client->list);
+ dev_err(&adapter->dev, "Failed to attach i2c client %s at 0x%02x "
+ "(%d)\n", client->name, client->addr, res);
+out_unlock:
+ mutex_unlock(&adapter->clist_lock);
+ return res;
}
@@ -674,11 +708,16 @@ static int i2c_probe_address(struct i2c_adapter *adapter, int addr, int kind,
/* Finally call the custom detection function */
err = found_proc(adapter, addr, kind);
-
/* -ENODEV can be returned if there is a chip at the given address
but it isn't supported by this chip driver. We catch it here as
this isn't an error. */
- return (err == -ENODEV) ? 0 : err;
+ if (err == -ENODEV)
+ err = 0;
+
+ if (err)
+ dev_warn(&adapter->dev, "Client creation failed at 0x%x (%d)\n",
+ addr, err);
+ return err;
}
int i2c_probe(struct i2c_adapter *adapter,
@@ -868,7 +907,7 @@ s32 i2c_smbus_read_byte(struct i2c_client *client)
I2C_SMBUS_READ,0,I2C_SMBUS_BYTE, &data))
return -1;
else
- return 0x0FF & data.byte;
+ return data.byte;
}
s32 i2c_smbus_write_byte(struct i2c_client *client, u8 value)
@@ -884,7 +923,7 @@ s32 i2c_smbus_read_byte_data(struct i2c_client *client, u8 command)
I2C_SMBUS_READ,command, I2C_SMBUS_BYTE_DATA,&data))
return -1;
else
- return 0x0FF & data.byte;
+ return data.byte;
}
s32 i2c_smbus_write_byte_data(struct i2c_client *client, u8 command, u8 value)
@@ -903,7 +942,7 @@ s32 i2c_smbus_read_word_data(struct i2c_client *client, u8 command)
I2C_SMBUS_READ,command, I2C_SMBUS_WORD_DATA, &data))
return -1;
else
- return 0x0FFFF & data.word;
+ return data.word;
}
s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
@@ -1006,7 +1045,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
else {
msg[0].len=3;
msgbuf0[1] = data->word & 0xff;
- msgbuf0[2] = (data->word >> 8) & 0xff;
+ msgbuf0[2] = data->word >> 8;
}
break;
case I2C_SMBUS_PROC_CALL:
@@ -1015,7 +1054,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
msg[0].len = 3;
msg[1].len = 2;
msgbuf0[1] = data->word & 0xff;
- msgbuf0[2] = (data->word >> 8) & 0xff;
+ msgbuf0[2] = data->word >> 8;
break;
case I2C_SMBUS_BLOCK_DATA:
if (read_write == I2C_SMBUS_READ) {
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 58ccddd5c237..3f869033ed70 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -32,43 +32,35 @@
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/list.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
-#include <linux/platform_device.h>
#include <asm/uaccess.h>
-static struct i2c_client i2cdev_client_template;
+static struct i2c_driver i2cdev_driver;
struct i2c_dev {
- int minor;
+ struct list_head list;
struct i2c_adapter *adap;
struct class_device *class_dev;
};
-#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
#define I2C_MINORS 256
-static struct i2c_dev *i2c_dev_array[I2C_MINORS];
-static DEFINE_SPINLOCK(i2c_dev_array_lock);
+static LIST_HEAD(i2c_dev_list);
+static DEFINE_SPINLOCK(i2c_dev_list_lock);
static struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
{
struct i2c_dev *i2c_dev;
- spin_lock(&i2c_dev_array_lock);
- i2c_dev = i2c_dev_array[index];
- spin_unlock(&i2c_dev_array_lock);
- return i2c_dev;
-}
-
-static struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
-{
- struct i2c_dev *i2c_dev = NULL;
-
- spin_lock(&i2c_dev_array_lock);
- if ((i2c_dev_array[adap->nr]) &&
- (i2c_dev_array[adap->nr]->adap == adap))
- i2c_dev = i2c_dev_array[adap->nr];
- spin_unlock(&i2c_dev_array_lock);
+ spin_lock(&i2c_dev_list_lock);
+ list_for_each_entry(i2c_dev, &i2c_dev_list, list) {
+ if (i2c_dev->adap->nr == index)
+ goto found;
+ }
+ i2c_dev = NULL;
+found:
+ spin_unlock(&i2c_dev_list_lock);
return i2c_dev;
}
@@ -76,30 +68,28 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
+ if (adap->nr >= I2C_MINORS) {
+ printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n",
+ adap->nr);
+ return ERR_PTR(-ENODEV);
+ }
+
i2c_dev = kzalloc(sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
return ERR_PTR(-ENOMEM);
+ i2c_dev->adap = adap;
- spin_lock(&i2c_dev_array_lock);
- if (i2c_dev_array[adap->nr]) {
- spin_unlock(&i2c_dev_array_lock);
- dev_err(&adap->dev, "i2c-dev already has a device assigned to this adapter\n");
- goto error;
- }
- i2c_dev->minor = adap->nr;
- i2c_dev_array[adap->nr] = i2c_dev;
- spin_unlock(&i2c_dev_array_lock);
+ spin_lock(&i2c_dev_list_lock);
+ list_add_tail(&i2c_dev->list, &i2c_dev_list);
+ spin_unlock(&i2c_dev_list_lock);
return i2c_dev;
-error:
- kfree(i2c_dev);
- return ERR_PTR(-ENODEV);
}
static void return_i2c_dev(struct i2c_dev *i2c_dev)
{
- spin_lock(&i2c_dev_array_lock);
- i2c_dev_array[i2c_dev->minor] = NULL;
- spin_unlock(&i2c_dev_array_lock);
+ spin_lock(&i2c_dev_list_lock);
+ list_del(&i2c_dev->list);
+ spin_unlock(&i2c_dev_list_lock);
}
static ssize_t show_adapter_name(struct class_device *class_dev, char *buf)
@@ -375,12 +365,13 @@ static int i2cdev_open(struct inode *inode, struct file *file)
if (!adap)
return -ENODEV;
- client = kmalloc(sizeof(*client), GFP_KERNEL);
+ client = kzalloc(sizeof(*client), GFP_KERNEL);
if (!client) {
i2c_put_adapter(adap);
return -ENOMEM;
}
- memcpy(client, &i2cdev_client_template, sizeof(*client));
+ snprintf(client->name, I2C_NAME_SIZE, "i2c-dev %d", adap->nr);
+ client->driver = &i2cdev_driver;
/* registered with adapter, passed as client to user */
client->adapter = adap;
@@ -415,41 +406,47 @@ static struct class *i2c_dev_class;
static int i2cdev_attach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
- struct device *dev;
+ int res;
i2c_dev = get_free_i2c_dev(adap);
if (IS_ERR(i2c_dev))
return PTR_ERR(i2c_dev);
- pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
- adap->name, i2c_dev->minor);
-
/* register this i2c device with the driver core */
- i2c_dev->adap = adap;
- dev = &adap->dev;
i2c_dev->class_dev = class_device_create(i2c_dev_class, NULL,
- MKDEV(I2C_MAJOR, i2c_dev->minor),
- dev, "i2c-%d", i2c_dev->minor);
- if (!i2c_dev->class_dev)
+ MKDEV(I2C_MAJOR, adap->nr),
+ &adap->dev, "i2c-%d",
+ adap->nr);
+ if (!i2c_dev->class_dev) {
+ res = -ENODEV;
goto error;
- class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
+ }
+ res = class_device_create_file(i2c_dev->class_dev, &class_device_attr_name);
+ if (res)
+ goto error_destroy;
+
+ pr_debug("i2c-dev: adapter [%s] registered as minor %d\n",
+ adap->name, adap->nr);
return 0;
+error_destroy:
+ class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
error:
return_i2c_dev(i2c_dev);
kfree(i2c_dev);
- return -ENODEV;
+ return res;
}
static int i2cdev_detach_adapter(struct i2c_adapter *adap)
{
struct i2c_dev *i2c_dev;
- i2c_dev = i2c_dev_get_by_adapter(adap);
- if (!i2c_dev)
- return -ENODEV;
+ i2c_dev = i2c_dev_get_by_minor(adap->nr);
+ if (!i2c_dev) /* attach_adapter must have failed */
+ return 0;
+ class_device_remove_file(i2c_dev->class_dev, &class_device_attr_name);
return_i2c_dev(i2c_dev);
- class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, i2c_dev->minor));
+ class_device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
kfree(i2c_dev);
pr_debug("i2c-dev: adapter [%s] unregistered\n", adap->name);
@@ -471,12 +468,6 @@ static struct i2c_driver i2cdev_driver = {
.detach_client = i2cdev_detach_client,
};
-static struct i2c_client i2cdev_client_template = {
- .name = "I2C /dev entry",
- .addr = -1,
- .driver = &i2cdev_driver,
-};
-
static int __init i2c_dev_init(void)
{
int res;
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index b6fb167e20f6..0c68d0f0d8e5 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -4,6 +4,8 @@
# Andre Hedrick <andre@linux-ide.org>
#
+if BLOCK
+
menu "ATA/ATAPI/MFM/RLL support"
config IDE
@@ -54,7 +56,7 @@ if IDE
config IDE_MAX_HWIFS
int "Max IDE interfaces"
- depends on ALPHA || SUPERH || IA64
+ depends on ALPHA || SUPERH || IA64 || EMBEDDED
default 4
help
This is the maximum number of IDE hardware interfaces that will
@@ -592,6 +594,12 @@ config BLK_DEV_HPT366
ide-probe at boot. It is reported to support DVD II drives, by the
manufacturer.
+config BLK_DEV_JMICRON
+ tristate "JMicron JMB36x support"
+ help
+ Basic support for the JMicron ATA controllers. For full support
+ use the libata drivers.
+
config BLK_DEV_SC1200
tristate "National SCx200 chipset support"
help
@@ -606,15 +614,6 @@ config BLK_DEV_PIIX
the kernel to change PIO, DMA and UDMA speeds and to configure
the chip to optimum performance.
-config BLK_DEV_IT8172
- bool "IT8172 IDE support"
- depends on (MIPS_ITE8172 || MIPS_IVR)
- help
- Say Y here to support the on-board IDE controller on the Integrated
- Technology Express, Inc. ITE8172 SBC. Vendor page at
- <http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
- board at <http://www.mvista.com/partners/semiconductor/ite.html>.
-
config BLK_DEV_IT821X
tristate "IT821X IDE support"
help
@@ -1082,3 +1081,5 @@ config BLK_DEV_HD
endif
endmenu
+
+endif
diff --git a/drivers/ide/h8300/ide-h8300.c b/drivers/ide/h8300/ide-h8300.c
index 15955996a1f3..608ca871744b 100644
--- a/drivers/ide/h8300/ide-h8300.c
+++ b/drivers/ide/h8300/ide-h8300.c
@@ -1,5 +1,5 @@
/*
- * drivers/ide/ide-h8300.c
+ * drivers/ide/h8300/ide-h8300.c
* H8/300 generic IDE interface
*/
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 654d4cd09847..bddfebdf91d8 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -372,7 +372,7 @@ static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
{
int log = 0;
- if (!sense || !rq || (rq->flags & REQ_QUIET))
+ if (!sense || !rq || (rq->cmd_flags & REQ_QUIET))
return 0;
switch (sense->sense_key) {
@@ -597,7 +597,7 @@ static void cdrom_prepare_request(ide_drive_t *drive, struct request *rq)
struct cdrom_info *cd = drive->driver_data;
ide_init_drive_cmd(rq);
- rq->flags = REQ_PC;
+ rq->cmd_type = REQ_TYPE_ATA_PC;
rq->rq_disk = cd->disk;
}
@@ -617,7 +617,7 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
rq->cmd[0] = GPCMD_REQUEST_SENSE;
rq->cmd[4] = rq->data_len = 18;
- rq->flags = REQ_SENSE;
+ rq->cmd_type = REQ_TYPE_SENSE;
/* NOTE! Save the failed command in "rq->buffer" */
rq->buffer = (void *) failed_command;
@@ -630,10 +630,10 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
struct request *rq = HWGROUP(drive)->rq;
int nsectors = rq->hard_cur_sectors;
- if ((rq->flags & REQ_SENSE) && uptodate) {
+ if (blk_sense_request(rq) && uptodate) {
/*
- * For REQ_SENSE, "rq->buffer" points to the original failed
- * request
+ * For REQ_TYPE_SENSE, "rq->buffer" points to the original
+ * failed request
*/
struct request *failed = (struct request *) rq->buffer;
struct cdrom_info *info = drive->driver_data;
@@ -706,17 +706,17 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
return 1;
}
- if (rq->flags & REQ_SENSE) {
+ if (blk_sense_request(rq)) {
/* We got an error trying to get sense info
from the drive (probably while trying
to recover from a former error). Just give up. */
- rq->flags |= REQ_FAILED;
+ rq->cmd_flags |= REQ_FAILED;
cdrom_end_request(drive, 0);
ide_error(drive, "request sense failure", stat);
return 1;
- } else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
+ } else if (blk_pc_request(rq) || rq->cmd_type == REQ_TYPE_ATA_PC) {
/* All other functions, except for READ. */
unsigned long flags;
@@ -724,7 +724,7 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
* if we have an error, pass back CHECK_CONDITION as the
* scsi status byte
*/
- if ((rq->flags & REQ_BLOCK_PC) && !rq->errors)
+ if (!rq->errors)
rq->errors = SAM_STAT_CHECK_CONDITION;
/* Check for tray open. */
@@ -735,12 +735,12 @@ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret)
cdrom_saw_media_change (drive);
/*printk("%s: media changed\n",drive->name);*/
return 0;
- } else if (!(rq->flags & REQ_QUIET)) {
+ } else if (!(rq->cmd_flags & REQ_QUIET)) {
/* Otherwise, print an error. */
ide_dump_status(drive, "packet command error", stat);
}
- rq->flags |= REQ_FAILED;
+ rq->cmd_flags |= REQ_FAILED;
/*
* instead of playing games with moving completions around,
@@ -881,7 +881,7 @@ static int cdrom_timer_expiry(ide_drive_t *drive)
wait = ATAPI_WAIT_PC;
break;
default:
- if (!(rq->flags & REQ_QUIET))
+ if (!(rq->cmd_flags & REQ_QUIET))
printk(KERN_INFO "ide-cd: cmd 0x%x timed out\n", rq->cmd[0]);
wait = 0;
break;
@@ -1124,7 +1124,7 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
if (rq->current_nr_sectors > 0) {
printk (KERN_ERR "%s: cdrom_read_intr: data underrun (%d blocks)\n",
drive->name, rq->current_nr_sectors);
- rq->flags |= REQ_FAILED;
+ rq->cmd_flags |= REQ_FAILED;
cdrom_end_request(drive, 0);
} else
cdrom_end_request(drive, 1);
@@ -1456,7 +1456,7 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
printk ("%s: cdrom_pc_intr: data underrun %d\n",
drive->name, pc->buflen);
*/
- rq->flags |= REQ_FAILED;
+ rq->cmd_flags |= REQ_FAILED;
cdrom_end_request(drive, 0);
}
return ide_stopped;
@@ -1509,7 +1509,7 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
rq->data += thislen;
rq->data_len -= thislen;
- if (rq->flags & REQ_SENSE)
+ if (blk_sense_request(rq))
rq->sense_len += thislen;
} else {
confused:
@@ -1517,7 +1517,7 @@ confused:
"appears confused (ireason = 0x%02x). "
"Trying to recover by ending request.\n",
drive->name, ireason);
- rq->flags |= REQ_FAILED;
+ rq->cmd_flags |= REQ_FAILED;
cdrom_end_request(drive, 0);
return ide_stopped;
}
@@ -1546,7 +1546,7 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
struct cdrom_info *info = drive->driver_data;
info->dma = 0;
- rq->flags &= ~REQ_FAILED;
+ rq->cmd_flags &= ~REQ_FAILED;
len = rq->data_len;
/* Start sending the command to the drive. */
@@ -1558,7 +1558,7 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
{
struct request_sense sense;
int retries = 10;
- unsigned int flags = rq->flags;
+ unsigned int flags = rq->cmd_flags;
if (rq->sense == NULL)
rq->sense = &sense;
@@ -1567,14 +1567,14 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
do {
int error;
unsigned long time = jiffies;
- rq->flags = flags;
+ rq->cmd_flags = flags;
error = ide_do_drive_cmd(drive, rq, ide_wait);
time = jiffies - time;
/* FIXME: we should probably abort/retry or something
* in case of failure */
- if (rq->flags & REQ_FAILED) {
+ if (rq->cmd_flags & REQ_FAILED) {
/* The request failed. Retry if it was due to a unit
attention status
(usually means media was changed). */
@@ -1596,10 +1596,10 @@ static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
}
/* End of retry loop. */
- } while ((rq->flags & REQ_FAILED) && retries >= 0);
+ } while ((rq->cmd_flags & REQ_FAILED) && retries >= 0);
/* Return an error if the command failed. */
- return (rq->flags & REQ_FAILED) ? -EIO : 0;
+ return (rq->cmd_flags & REQ_FAILED) ? -EIO : 0;
}
/*
@@ -1963,7 +1963,7 @@ static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
{
struct cdrom_info *info = drive->driver_data;
- rq->flags |= REQ_QUIET;
+ rq->cmd_flags |= REQ_QUIET;
info->dma = 0;
@@ -2023,11 +2023,12 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
}
info->last_block = block;
return action;
- } else if (rq->flags & (REQ_PC | REQ_SENSE)) {
+ } else if (rq->cmd_type == REQ_TYPE_SENSE ||
+ rq->cmd_type == REQ_TYPE_ATA_PC) {
return cdrom_do_packet_command(drive);
- } else if (rq->flags & REQ_BLOCK_PC) {
+ } else if (blk_pc_request(rq)) {
return cdrom_do_block_pc(drive, rq);
- } else if (rq->flags & REQ_SPECIAL) {
+ } else if (blk_special_request(rq)) {
/*
* right now this can only be a reset...
*/
@@ -2105,7 +2106,7 @@ static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
req.sense = sense;
req.cmd[0] = GPCMD_TEST_UNIT_READY;
- req.flags |= REQ_QUIET;
+ req.cmd_flags |= REQ_QUIET;
#if ! STANDARD_ATAPI
/* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
@@ -2207,7 +2208,7 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
req.data = (char *)&capbuf;
req.data_len = sizeof(capbuf);
- req.flags |= REQ_QUIET;
+ req.cmd_flags |= REQ_QUIET;
stat = cdrom_queue_packet_command(drive, &req);
if (stat == 0) {
@@ -2230,7 +2231,7 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
req.sense = sense;
req.data = buf;
req.data_len = buflen;
- req.flags |= REQ_QUIET;
+ req.cmd_flags |= REQ_QUIET;
req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
req.cmd[6] = trackno;
req.cmd[7] = (buflen >> 8);
@@ -2531,7 +2532,7 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
req.timeout = cgc->timeout;
if (cgc->quiet)
- req.flags |= REQ_QUIET;
+ req.cmd_flags |= REQ_QUIET;
req.sense = cgc->sense;
cgc->stat = cdrom_queue_packet_command(drive, &req);
@@ -2629,7 +2630,8 @@ int ide_cdrom_reset (struct cdrom_device_info *cdi)
int ret;
cdrom_prepare_request(drive, &req);
- req.flags = REQ_SPECIAL | REQ_QUIET;
+ req.cmd_type = REQ_TYPE_SPECIAL;
+ req.cmd_flags = REQ_QUIET;
ret = ide_do_drive_cmd(drive, &req, ide_wait);
/*
@@ -3116,9 +3118,9 @@ static int ide_cdrom_prep_pc(struct request *rq)
static int ide_cdrom_prep_fn(request_queue_t *q, struct request *rq)
{
- if (rq->flags & REQ_CMD)
+ if (blk_fs_request(rq))
return ide_cdrom_prep_fs(q, rq);
- else if (rq->flags & REQ_BLOCK_PC)
+ else if (blk_pc_request(rq))
return ide_cdrom_prep_pc(rq);
return 0;
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 7cf3eb023521..0a05a377d66a 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -699,7 +699,8 @@ static void idedisk_prepare_flush(request_queue_t *q, struct request *rq)
rq->cmd[0] = WIN_FLUSH_CACHE;
- rq->flags |= REQ_DRIVE_TASK;
+ rq->cmd_type = REQ_TYPE_ATA_TASK;
+ rq->cmd_flags |= REQ_SOFTBARRIER;
rq->buffer = rq->cmd;
}
@@ -740,7 +741,7 @@ static int set_multcount(ide_drive_t *drive, int arg)
if (drive->special.b.set_multmode)
return -EBUSY;
ide_init_drive_cmd (&rq);
- rq.flags = REQ_DRIVE_CMD;
+ rq.cmd_type = REQ_TYPE_ATA_CMD;
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
(void) ide_do_drive_cmd (drive, &rq, ide_wait);
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 7c3a13e1cf64..56efed6742d4 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -145,14 +145,12 @@ int ide_in_drive_list(struct hd_driveid *id, const struct drive_list_entry *driv
{
for ( ; drive_table->id_model ; drive_table++)
if ((!strcmp(drive_table->id_model, id->model)) &&
- ((strstr(drive_table->id_firmware, id->fw_rev)) ||
+ ((strstr(id->fw_rev, drive_table->id_firmware)) ||
(!strcmp(drive_table->id_firmware, "ALL"))))
return 1;
return 0;
}
-EXPORT_SYMBOL_GPL(ide_in_drive_list);
-
/**
* ide_dma_intr - IDE DMA interrupt handler
* @drive: the drive the interrupt is for
@@ -205,7 +203,7 @@ int ide_build_sglist(ide_drive_t *drive, struct request *rq)
ide_hwif_t *hwif = HWIF(drive);
struct scatterlist *sg = hwif->sg_table;
- BUG_ON((rq->flags & REQ_DRIVE_TASKFILE) && rq->nr_sectors > 256);
+ BUG_ON((rq->cmd_type == REQ_TYPE_ATA_TASKFILE) && rq->nr_sectors > 256);
ide_map_sg(drive, rq);
@@ -798,26 +796,23 @@ static int ide_release_dma_engine(ide_hwif_t *hwif)
static int ide_release_iomio_dma(ide_hwif_t *hwif)
{
- if ((hwif->dma_extra) && (hwif->channel == 0))
- release_region((hwif->dma_base + 16), hwif->dma_extra);
release_region(hwif->dma_base, 8);
- if (hwif->dma_base2)
- release_region(hwif->dma_base, 8);
+ if (hwif->extra_ports)
+ release_region(hwif->extra_base, hwif->extra_ports);
return 1;
}
/*
* Needed for allowing full modular support of ide-driver
*/
-int ide_release_dma (ide_hwif_t *hwif)
+int ide_release_dma(ide_hwif_t *hwif)
{
+ ide_release_dma_engine(hwif);
+
if (hwif->mmio == 2)
return 1;
- if (hwif->chipset == ide_etrax100)
- return 1;
-
- ide_release_dma_engine(hwif);
- return ide_release_iomio_dma(hwif);
+ else
+ return ide_release_iomio_dma(hwif);
}
static int ide_allocate_dma_engine(ide_hwif_t *hwif)
@@ -829,10 +824,9 @@ static int ide_allocate_dma_engine(ide_hwif_t *hwif)
if (hwif->dmatable_cpu)
return 0;
- printk(KERN_ERR "%s: -- Error, unable to allocate%s DMA table(s).\n",
- hwif->cds->name, !hwif->dmatable_cpu ? " CPU" : "");
+ printk(KERN_ERR "%s: -- Error, unable to allocate DMA table.\n",
+ hwif->cds->name);
- ide_release_dma_engine(hwif);
return 1;
}
@@ -840,9 +834,7 @@ static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned in
{
printk(KERN_INFO " %s: MMIO-DMA ", hwif->name);
- hwif->dma_base = base;
- if (hwif->cds->extra && hwif->channel == 0)
- hwif->dma_extra = hwif->cds->extra;
+ hwif->dma_base = base;
if(hwif->mate)
hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
@@ -854,29 +846,33 @@ static int ide_mapped_mmio_dma(ide_hwif_t *hwif, unsigned long base, unsigned in
static int ide_iomio_dma(ide_hwif_t *hwif, unsigned long base, unsigned int ports)
{
printk(KERN_INFO " %s: BM-DMA at 0x%04lx-0x%04lx",
- hwif->name, base, base + ports - 1);
+ hwif->name, base, base + ports - 1);
+
if (!request_region(base, ports, hwif->name)) {
printk(" -- Error, ports in use.\n");
return 1;
}
+
hwif->dma_base = base;
- if ((hwif->cds->extra) && (hwif->channel == 0)) {
- request_region(base+16, hwif->cds->extra, hwif->cds->name);
- hwif->dma_extra = hwif->cds->extra;
+
+ if (hwif->cds->extra) {
+ hwif->extra_base = base + (hwif->channel ? 8 : 16);
+
+ if (!hwif->mate || !hwif->mate->extra_ports) {
+ if (!request_region(hwif->extra_base,
+ hwif->cds->extra, hwif->cds->name)) {
+ printk(" -- Error, extra ports in use.\n");
+ release_region(base, ports);
+ return 1;
+ }
+ hwif->extra_ports = hwif->cds->extra;
+ }
}
-
+
if(hwif->mate)
- hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base : base;
+ hwif->dma_master = (hwif->channel) ? hwif->mate->dma_base:base;
else
hwif->dma_master = base;
- if (hwif->dma_base2) {
- if (!request_region(hwif->dma_base2, ports, hwif->name))
- {
- printk(" -- Error, secondary ports in use.\n");
- release_region(base, ports);
- return 1;
- }
- }
return 0;
}
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index adbe9f76a505..8ccee9c769f8 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -588,7 +588,7 @@ static int idefloppy_do_end_request(ide_drive_t *drive, int uptodate, int nsecs)
/* Why does this happen? */
if (!rq)
return 0;
- if (!(rq->flags & REQ_SPECIAL)) { //if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
+ if (!blk_special_request(rq)) {
/* our real local end request function */
ide_end_request(drive, uptodate, nsecs);
return 0;
@@ -689,7 +689,7 @@ static void idefloppy_queue_pc_head (ide_drive_t *drive,idefloppy_pc_t *pc,struc
ide_init_drive_cmd(rq);
rq->buffer = (char *) pc;
- rq->flags = REQ_SPECIAL; //rq->cmd = IDEFLOPPY_PC_RQ;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
rq->rq_disk = floppy->disk;
(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}
@@ -1250,7 +1250,7 @@ static void idefloppy_create_rw_cmd (idefloppy_floppy_t *floppy, idefloppy_pc_t
pc->callback = &idefloppy_rw_callback;
pc->rq = rq;
pc->b_count = cmd == READ ? 0 : rq->bio->bi_size;
- if (rq->flags & REQ_RW)
+ if (rq->cmd_flags & REQ_RW)
set_bit(PC_WRITING, &pc->flags);
pc->buffer = NULL;
pc->request_transfer = pc->buffer_size = blocks * floppy->block_size;
@@ -1281,8 +1281,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
idefloppy_pc_t *pc;
unsigned long block = (unsigned long)block_s;
- debug_log(KERN_INFO "rq_status: %d, dev: %s, flags: %lx, errors: %d\n",
- rq->rq_status,
+ debug_log(KERN_INFO "dev: %s, flags: %lx, errors: %d\n",
rq->rq_disk ? rq->rq_disk->disk_name : "?",
rq->flags, rq->errors);
debug_log(KERN_INFO "sector: %ld, nr_sectors: %ld, "
@@ -1303,7 +1302,7 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
idefloppy_do_end_request(drive, 0, 0);
return ide_stopped;
}
- if (rq->flags & REQ_CMD) {
+ if (blk_fs_request(rq)) {
if (((long)rq->sector % floppy->bs_factor) ||
(rq->nr_sectors % floppy->bs_factor)) {
printk("%s: unsupported r/w request size\n",
@@ -1313,9 +1312,9 @@ static ide_startstop_t idefloppy_do_request (ide_drive_t *drive, struct request
}
pc = idefloppy_next_pc_storage(drive);
idefloppy_create_rw_cmd(floppy, pc, rq, block);
- } else if (rq->flags & REQ_SPECIAL) {
+ } else if (blk_special_request(rq)) {
pc = (idefloppy_pc_t *) rq->buffer;
- } else if (rq->flags & REQ_BLOCK_PC) {
+ } else if (blk_pc_request(rq)) {
pc = idefloppy_next_pc_storage(drive);
if (idefloppy_blockpc_cmd(floppy, pc, rq)) {
idefloppy_do_end_request(drive, 0, 0);
@@ -1343,7 +1342,7 @@ static int idefloppy_queue_pc_tail (ide_drive_t *drive,idefloppy_pc_t *pc)
ide_init_drive_cmd (&rq);
rq.buffer = (char *) pc;
- rq.flags = REQ_SPECIAL; // rq.cmd = IDEFLOPPY_PC_RQ;
+ rq.cmd_type = REQ_TYPE_SPECIAL;
rq.rq_disk = floppy->disk;
return ide_do_drive_cmd(drive, &rq, ide_wait);
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index fb6795236e76..2614f41b5074 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -59,8 +59,6 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
{
int ret = 1;
- BUG_ON(!(rq->flags & REQ_STARTED));
-
/*
* if failfast is set on a request, override number of sectors and
* complete the whole request right now
@@ -82,7 +80,8 @@ static int __ide_end_request(ide_drive_t *drive, struct request *rq,
if (!end_that_request_first(rq, uptodate, nr_sectors)) {
add_disk_randomness(rq->rq_disk);
- blkdev_dequeue_request(rq);
+ if (!list_empty(&rq->queuelist))
+ blkdev_dequeue_request(rq);
HWGROUP(drive)->rq = NULL;
end_that_request_last(rq, uptodate);
ret = 0;
@@ -135,13 +134,14 @@ enum {
ide_pm_flush_cache = ide_pm_state_start_suspend,
idedisk_pm_standby,
- idedisk_pm_idle = ide_pm_state_start_resume,
+ idedisk_pm_restore_pio = ide_pm_state_start_resume,
+ idedisk_pm_idle,
ide_pm_restore_dma,
};
static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 stat, u8 error)
{
- struct request_pm_state *pm = rq->end_io_data;
+ struct request_pm_state *pm = rq->data;
if (drive->media != ide_disk)
return;
@@ -156,7 +156,10 @@ static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 s
case idedisk_pm_standby: /* Suspend step 2 (standby) complete */
pm->pm_step = ide_pm_state_completed;
break;
- case idedisk_pm_idle: /* Resume step 1 (idle) complete */
+ case idedisk_pm_restore_pio: /* Resume step 1 complete */
+ pm->pm_step = idedisk_pm_idle;
+ break;
+ case idedisk_pm_idle: /* Resume step 2 (idle) complete */
pm->pm_step = ide_pm_restore_dma;
break;
}
@@ -164,14 +167,17 @@ static void ide_complete_power_step(ide_drive_t *drive, struct request *rq, u8 s
static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *rq)
{
- struct request_pm_state *pm = rq->end_io_data;
+ struct request_pm_state *pm = rq->data;
ide_task_t *args = rq->special;
memset(args, 0, sizeof(*args));
if (drive->media != ide_disk) {
- /* skip idedisk_pm_idle for ATAPI devices */
- if (pm->pm_step == idedisk_pm_idle)
+ /*
+ * 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;
}
@@ -198,13 +204,19 @@ static ide_startstop_t ide_start_power_step(ide_drive_t *drive, struct request *
args->handler = &task_no_data_intr;
return do_rw_taskfile(drive, args);
- case idedisk_pm_idle: /* Resume step 1 (idle) */
+ 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);
+ return ide_stopped;
+
+ case idedisk_pm_idle: /* Resume step 2 (idle) */
args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;
args->command_type = IDE_DRIVE_TASK_NO_DATA;
args->handler = task_no_data_intr;
return do_rw_taskfile(drive, args);
- case ide_pm_restore_dma: /* Resume step 2 (restore DMA) */
+ case ide_pm_restore_dma: /* Resume step 3 (restore DMA) */
/*
* Right now, all we do is call hwif->ide_dma_check(drive),
* we could be smarter and check for current xfer_speed
@@ -244,7 +256,7 @@ int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq,
spin_lock_irqsave(&ide_lock, flags);
- BUG_ON(!(rq->flags & REQ_STARTED));
+ BUG_ON(!blk_rq_started(rq));
/*
* if failfast is set on a request, override number of sectors and
@@ -366,7 +378,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
rq = HWGROUP(drive)->rq;
spin_unlock_irqrestore(&ide_lock, flags);
- if (rq->flags & REQ_DRIVE_CMD) {
+ if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
u8 *args = (u8 *) rq->buffer;
if (rq->errors == 0)
rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
@@ -376,7 +388,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
args[1] = err;
args[2] = hwif->INB(IDE_NSECTOR_REG);
}
- } else if (rq->flags & REQ_DRIVE_TASK) {
+ } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
u8 *args = (u8 *) rq->buffer;
if (rq->errors == 0)
rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
@@ -390,7 +402,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
args[5] = hwif->INB(IDE_HCYL_REG);
args[6] = hwif->INB(IDE_SELECT_REG);
}
- } else if (rq->flags & REQ_DRIVE_TASKFILE) {
+ } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
ide_task_t *args = (ide_task_t *) rq->special;
if (rq->errors == 0)
rq->errors = !OK_STAT(stat,READY_STAT,BAD_STAT);
@@ -421,7 +433,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
}
}
} else if (blk_pm_request(rq)) {
- struct request_pm_state *pm = rq->end_io_data;
+ struct request_pm_state *pm = rq->data;
#ifdef DEBUG_PM
printk("%s: complete_power_step(step: %d, stat: %x, err: %x)\n",
drive->name, rq->pm->pm_step, stat, err);
@@ -587,7 +599,7 @@ ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
return ide_stopped;
/* retry only "normal" I/O: */
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+ if (!blk_fs_request(rq)) {
rq->errors = 1;
ide_end_drive_cmd(drive, stat, err);
return ide_stopped;
@@ -638,7 +650,7 @@ ide_startstop_t ide_abort(ide_drive_t *drive, const char *msg)
return ide_stopped;
/* retry only "normal" I/O: */
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK | REQ_DRIVE_TASKFILE)) {
+ if (!blk_fs_request(rq)) {
rq->errors = 1;
ide_end_drive_cmd(drive, BUSY_STAT, 0);
return ide_stopped;
@@ -808,7 +820,7 @@ void ide_map_sg(ide_drive_t *drive, struct request *rq)
if (hwif->sg_mapped) /* needed by ide-scsi */
return;
- if ((rq->flags & REQ_DRIVE_TASKFILE) == 0) {
+ if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) {
hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
} else {
sg_init_one(sg, rq->buffer, rq->nr_sectors * SECTOR_SIZE);
@@ -844,7 +856,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
struct request *rq)
{
ide_hwif_t *hwif = HWIF(drive);
- if (rq->flags & REQ_DRIVE_TASKFILE) {
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
ide_task_t *args = rq->special;
if (!args)
@@ -866,7 +878,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
if (args->tf_out_flags.all != 0)
return flagged_taskfile(drive, args);
return do_rw_taskfile(drive, args);
- } else if (rq->flags & REQ_DRIVE_TASK) {
+ } else if (rq->cmd_type == REQ_TYPE_ATA_TASK) {
u8 *args = rq->buffer;
u8 sel;
@@ -892,7 +904,7 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
hwif->OUTB(sel, IDE_SELECT_REG);
ide_cmd(drive, args[0], args[2], &drive_cmd_intr);
return ide_started;
- } else if (rq->flags & REQ_DRIVE_CMD) {
+ } else if (rq->cmd_type == REQ_TYPE_ATA_CMD) {
u8 *args = rq->buffer;
if (!args)
@@ -933,7 +945,7 @@ done:
static void ide_check_pm_state(ide_drive_t *drive, struct request *rq)
{
- struct request_pm_state *pm = rq->end_io_data;
+ struct request_pm_state *pm = rq->data;
if (blk_pm_suspend_request(rq) &&
pm->pm_step == ide_pm_state_start_suspend)
@@ -980,7 +992,7 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
ide_startstop_t startstop;
sector_t block;
- BUG_ON(!(rq->flags & REQ_STARTED));
+ BUG_ON(!blk_rq_started(rq));
#ifdef DEBUG
printk("%s: start_request: current=0x%08lx\n",
@@ -1013,12 +1025,12 @@ static ide_startstop_t start_request (ide_drive_t *drive, struct request *rq)
if (!drive->special.all) {
ide_driver_t *drv;
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK))
- return execute_drive_cmd(drive, rq);
- else if (rq->flags & REQ_DRIVE_TASKFILE)
+ if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
+ rq->cmd_type == REQ_TYPE_ATA_TASK ||
+ rq->cmd_type == REQ_TYPE_ATA_TASKFILE)
return execute_drive_cmd(drive, rq);
else if (blk_pm_request(rq)) {
- struct request_pm_state *pm = rq->end_io_data;
+ struct request_pm_state *pm = rq->data;
#ifdef DEBUG_PM
printk("%s: start_power_step(step: %d)\n",
drive->name, rq->pm->pm_step);
@@ -1264,7 +1276,7 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
* We count how many times we loop here to make sure we service
* all drives in the hwgroup without looping for ever
*/
- if (drive->blocked && !blk_pm_request(rq) && !(rq->flags & REQ_PREEMPT)) {
+ if (drive->blocked && !blk_pm_request(rq) && !(rq->cmd_flags & REQ_PREEMPT)) {
drive = drive->next ? drive->next : hwgroup->drive;
if (loops++ < 4 && !blk_queue_plugged(drive->queue))
goto again;
@@ -1346,6 +1358,10 @@ static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
* make sure request is sane
*/
rq = HWGROUP(drive)->rq;
+
+ if (!rq)
+ goto out;
+
HWGROUP(drive)->rq = NULL;
rq->errors = 0;
@@ -1546,7 +1562,7 @@ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup)
* on the hwgroup and the process begins again.
*/
-irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t ide_intr (int irq, void *dev_id)
{
unsigned long flags;
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
@@ -1670,7 +1686,7 @@ irqreturn_t ide_intr (int irq, void *dev_id, struct pt_regs *regs)
void ide_init_drive_cmd (struct request *rq)
{
memset(rq, 0, sizeof(*rq));
- rq->flags = REQ_DRIVE_CMD;
+ rq->cmd_type = REQ_TYPE_ATA_CMD;
rq->ref_count = 1;
}
@@ -1710,7 +1726,6 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
int must_wait = (action == ide_wait || action == ide_head_wait);
rq->errors = 0;
- rq->rq_status = RQ_ACTIVE;
/*
* we need to hold an extra reference to request for safe inspection
@@ -1718,7 +1733,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
*/
if (must_wait) {
rq->ref_count++;
- rq->waiting = &wait;
+ rq->end_io_data = &wait;
rq->end_io = blk_end_sync_rq;
}
@@ -1727,7 +1742,7 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
hwgroup->rq = NULL;
if (action == ide_preempt || action == ide_head_wait) {
where = ELEVATOR_INSERT_FRONT;
- rq->flags |= REQ_PREEMPT;
+ rq->cmd_flags |= REQ_PREEMPT;
}
__elv_add_request(drive->queue, rq, where, 0);
ide_do_request(hwgroup, IDE_NO_IRQ);
@@ -1736,7 +1751,6 @@ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t actio
err = 0;
if (must_wait) {
wait_for_completion(&wait);
- rq->waiting = NULL;
if (rq->errors)
err = -EIO;
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 77703acaec17..badde6331775 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -998,6 +998,7 @@ static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive)
}
/* done polling */
hwgroup->polling = 0;
+ hwgroup->resetting = 0;
return ide_stopped;
}
@@ -1057,6 +1058,7 @@ static ide_startstop_t reset_pollfunc (ide_drive_t *drive)
}
}
hwgroup->polling = 0; /* done polling */
+ hwgroup->resetting = 0; /* done reset attempt */
return ide_stopped;
}
@@ -1143,6 +1145,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
/* For an ATAPI device, first try an ATAPI SRST. */
if (drive->media != ide_disk && !do_not_try_atapi) {
+ hwgroup->resetting = 1;
pre_reset(drive);
SELECT_DRIVE(drive);
udelay (20);
@@ -1168,6 +1171,7 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
return ide_stopped;
}
+ hwgroup->resetting = 1;
/*
* Note that we also set nIEN while resetting the device,
* to mask unwanted interrupts from the interface during the reset.
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 1feff23487d4..8237d89eec6e 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -71,75 +71,96 @@ EXPORT_SYMBOL(ide_xfer_verbose);
/**
* ide_dma_speed - compute DMA speed
* @drive: drive
- * @mode; intended mode
+ * @mode: modes available
*
* Checks the drive capabilities and returns the speed to use
- * for the transfer. Returns -1 if the requested mode is unknown
- * (eg PIO)
+ * 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;
- switch(mode) {
- case 0x04:
- if ((id->dma_ultra & 0x0040) &&
- (id->dma_ultra & hwif->ultra_mask))
- { speed = XFER_UDMA_6; break; }
- case 0x03:
- if ((id->dma_ultra & 0x0020) &&
- (id->dma_ultra & hwif->ultra_mask))
- { speed = XFER_UDMA_5; break; }
- case 0x02:
- if ((id->dma_ultra & 0x0010) &&
- (id->dma_ultra & hwif->ultra_mask))
- { speed = XFER_UDMA_4; break; }
- if ((id->dma_ultra & 0x0008) &&
- (id->dma_ultra & hwif->ultra_mask))
- { speed = XFER_UDMA_3; break; }
- case 0x01:
- if ((id->dma_ultra & 0x0004) &&
- (id->dma_ultra & hwif->ultra_mask))
- { speed = XFER_UDMA_2; break; }
- if ((id->dma_ultra & 0x0002) &&
- (id->dma_ultra & hwif->ultra_mask))
- { speed = XFER_UDMA_1; break; }
- if ((id->dma_ultra & 0x0001) &&
- (id->dma_ultra & hwif->ultra_mask))
- { speed = XFER_UDMA_0; break; }
- case 0x00:
- if ((id->dma_mword & 0x0004) &&
- (id->dma_mword & hwif->mwdma_mask))
- { speed = XFER_MW_DMA_2; break; }
- if ((id->dma_mword & 0x0002) &&
- (id->dma_mword & hwif->mwdma_mask))
- { speed = XFER_MW_DMA_1; break; }
- if ((id->dma_mword & 0x0001) &&
- (id->dma_mword & hwif->mwdma_mask))
- { speed = XFER_MW_DMA_0; break; }
- if ((id->dma_1word & 0x0004) &&
- (id->dma_1word & hwif->swdma_mask))
- { speed = XFER_SW_DMA_2; break; }
- if ((id->dma_1word & 0x0002) &&
- (id->dma_1word & hwif->swdma_mask))
- { speed = XFER_SW_DMA_1; break; }
- if ((id->dma_1word & 0x0001) &&
- (id->dma_1word & hwif->swdma_mask))
- { speed = XFER_SW_DMA_0; break; }
- }
+ /* 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;
-// printk("%s: %s: mode 0x%02x, speed 0x%02x\n",
-// __FUNCTION__, drive->name, mode, speed);
+ 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);
@@ -456,13 +477,14 @@ static void ide_dump_opcode(ide_drive_t *drive)
spin_unlock(&ide_lock);
if (!rq)
return;
- if (rq->flags & (REQ_DRIVE_CMD | REQ_DRIVE_TASK)) {
+ if (rq->cmd_type == REQ_TYPE_ATA_CMD ||
+ rq->cmd_type == REQ_TYPE_ATA_TASK) {
char *args = rq->buffer;
if (args) {
opcode = args[0];
found = 1;
}
- } else if (rq->flags & REQ_DRIVE_TASKFILE) {
+ } else if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
ide_task_t *args = rq->special;
if (args) {
task_struct_t *tf = (task_struct_t *) args->tfRegister;
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 9cadf0106c6c..dad9c47ebb69 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -623,6 +623,8 @@ static void hwif_release_dev (struct device *dev)
static void hwif_register (ide_hwif_t *hwif)
{
+ int ret;
+
/* register with global device tree */
strlcpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
hwif->gendev.driver_data = hwif;
@@ -634,7 +636,10 @@ static void hwif_register (ide_hwif_t *hwif)
hwif->gendev.parent = NULL;
}
hwif->gendev.release = hwif_release_dev;
- device_register(&hwif->gendev);
+ ret = device_register(&hwif->gendev);
+ if (ret < 0)
+ printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
+ __FUNCTION__, ret);
}
static int wait_hwif_ready(ide_hwif_t *hwif)
@@ -884,13 +889,19 @@ int probe_hwif_init_with_fixup(ide_hwif_t *hwif, void (*fixup)(ide_hwif_t *hwif)
if (hwif->present) {
u16 unit = 0;
+ int ret;
+
for (unit = 0; unit < MAX_DRIVES; ++unit) {
ide_drive_t *drive = &hwif->drives[unit];
/* For now don't attach absent drives, we may
want them on default or a new "empty" class
for hotplug reprobing ? */
if (drive->present) {
- device_register(&drive->gendev);
+ ret = device_register(&drive->gendev);
+ if (ret < 0)
+ printk(KERN_WARNING "IDE: %s: "
+ "device_register error: %d\n",
+ __FUNCTION__, ret);
}
}
}
@@ -1409,8 +1420,14 @@ int ideprobe_init (void)
if (hwif->chipset == ide_unknown || hwif->chipset == ide_forced)
hwif->chipset = ide_generic;
for (unit = 0; unit < MAX_DRIVES; ++unit)
- if (hwif->drives[unit].present)
- device_register(&hwif->drives[unit].gendev);
+ if (hwif->drives[unit].present) {
+ int ret = device_register(
+ &hwif->drives[unit].gendev);
+ if (ret < 0)
+ printk(KERN_WARNING "IDE: %s: "
+ "device_register error: %d\n",
+ __FUNCTION__, ret);
+ }
}
}
return 0;
diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
index 41b74b13a00c..aa049dab3d95 100644
--- a/drivers/ide/ide-proc.c
+++ b/drivers/ide/ide-proc.c
@@ -326,15 +326,24 @@ static int ide_replace_subdriver(ide_drive_t *drive, const char *driver)
{
struct device *dev = &drive->gendev;
int ret = 1;
+ int err;
down_write(&dev->bus->subsys.rwsem);
device_release_driver(dev);
/* FIXME: device can still be in use by previous driver */
strlcpy(drive->driver_req, driver, sizeof(drive->driver_req));
- device_attach(dev);
+ err = device_attach(dev);
+ if (err < 0)
+ printk(KERN_WARNING "IDE: %s: device_attach error: %d\n",
+ __FUNCTION__, err);
drive->driver_req[0] = 0;
- if (dev->driver == NULL)
- device_attach(dev);
+ if (dev->driver == NULL) {
+ err = device_attach(dev);
+ if (err < 0)
+ printk(KERN_WARNING
+ "IDE: %s: device_attach(2) error: %d\n",
+ __FUNCTION__, err);
+ }
if (dev->driver && !strcmp(dev->driver->name, driver))
ret = 0;
up_write(&dev->bus->subsys.rwsem);
@@ -526,7 +535,12 @@ static int proc_print_driver(struct device_driver *drv, void *data)
static int ide_drivers_show(struct seq_file *s, void *p)
{
- bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
+ int err;
+
+ err = bus_for_each_drv(&ide_bus_type, NULL, s, proc_print_driver);
+ if (err < 0)
+ printk(KERN_WARNING "IDE: %s: bus_for_each_drv error: %d\n",
+ __FUNCTION__, err);
return 0;
}
diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
index 7067ab997927..e2f4bb549063 100644
--- a/drivers/ide/ide-tape.c
+++ b/drivers/ide/ide-tape.c
@@ -1776,7 +1776,7 @@ static void idetape_create_request_sense_cmd (idetape_pc_t *pc)
static void idetape_init_rq(struct request *rq, u8 cmd)
{
memset(rq, 0, sizeof(*rq));
- rq->flags = REQ_SPECIAL;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
rq->cmd[0] = cmd;
}
@@ -2423,8 +2423,8 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
#if IDETAPE_DEBUG_LOG
#if 0
if (tape->debug_level >= 5)
- printk(KERN_INFO "ide-tape: rq_status: %d, "
- "dev: %s, cmd: %ld, errors: %d\n", rq->rq_status,
+ printk(KERN_INFO "ide-tape: %d, "
+ "dev: %s, cmd: %ld, errors: %d\n",
rq->rq_disk->disk_name, rq->cmd[0], rq->errors);
#endif
if (tape->debug_level >= 2)
@@ -2433,12 +2433,12 @@ static ide_startstop_t idetape_do_request(ide_drive_t *drive,
rq->sector, rq->nr_sectors, rq->current_nr_sectors);
#endif /* IDETAPE_DEBUG_LOG */
- if ((rq->flags & REQ_SPECIAL) == 0) {
+ if (!blk_special_request(rq)) {
/*
* We do not support buffer cache originated requests.
*/
printk(KERN_NOTICE "ide-tape: %s: Unsupported request in "
- "request queue (%ld)\n", drive->name, rq->flags);
+ "request queue (%d)\n", drive->name, rq->cmd_type);
ide_end_request(drive, 0, 0);
return ide_stopped;
}
@@ -2764,16 +2764,16 @@ static void idetape_add_stage_tail (ide_drive_t *drive,idetape_stage_t *stage)
*/
static void idetape_wait_for_request (ide_drive_t *drive, struct request *rq)
{
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
idetape_tape_t *tape = drive->driver_data;
#if IDETAPE_DEBUG_BUGS
- if (rq == NULL || (rq->flags & REQ_SPECIAL) == 0) {
+ if (rq == NULL || !blk_special_request(rq)) {
printk (KERN_ERR "ide-tape: bug: Trying to sleep on non-valid request\n");
return;
}
#endif /* IDETAPE_DEBUG_BUGS */
- rq->waiting = &wait;
+ rq->end_io_data = &wait;
rq->end_io = blk_end_sync_rq;
spin_unlock_irq(&tape->spinlock);
wait_for_completion(&wait);
diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c
index 97a9244312fc..30175c7688e8 100644
--- a/drivers/ide/ide-taskfile.c
+++ b/drivers/ide/ide-taskfile.c
@@ -363,7 +363,7 @@ static ide_startstop_t task_error(ide_drive_t *drive, struct request *rq,
static void task_end_request(ide_drive_t *drive, struct request *rq, u8 stat)
{
- if (rq->flags & REQ_DRIVE_TASKFILE) {
+ if (rq->cmd_type == REQ_TYPE_ATA_TASKFILE) {
ide_task_t *task = rq->special;
if (task->tf_out_flags.all) {
@@ -474,7 +474,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
struct request rq;
memset(&rq, 0, sizeof(rq));
- rq.flags = REQ_DRIVE_TASKFILE;
+ rq.cmd_type = REQ_TYPE_ATA_TASKFILE;
rq.buffer = buf;
/*
@@ -499,7 +499,7 @@ static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long
rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;
if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
- rq.flags |= REQ_RW;
+ rq.cmd_flags |= REQ_RW;
}
rq.special = args;
@@ -524,8 +524,8 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
task_ioreg_t *hobsptr = args.hobRegister;
int err = 0;
int tasksize = sizeof(struct ide_task_request_s);
- int taskin = 0;
- int taskout = 0;
+ unsigned int taskin = 0;
+ unsigned int taskout = 0;
u8 io_32bit = drive->io_32bit;
char __user *buf = (char __user *)arg;
@@ -538,8 +538,13 @@ int ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg)
return -EFAULT;
}
- taskout = (int) req_task->out_size;
- taskin = (int) req_task->in_size;
+ taskout = req_task->out_size;
+ taskin = req_task->in_size;
+
+ if (taskin > 65536 || taskout > 65536) {
+ err = -EINVAL;
+ goto abort;
+ }
if (taskout) {
int outtotal = tasksize;
@@ -737,7 +742,7 @@ static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf)
struct request rq;
ide_init_drive_cmd(&rq);
- rq.flags = REQ_DRIVE_TASK;
+ rq.cmd_type = REQ_TYPE_ATA_TASK;
rq.buffer = buf;
return ide_do_drive_cmd(drive, &rq, ide_wait);
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index 9c8468de1a75..287a66201150 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -450,7 +450,7 @@ void ide_hwif_release_regions(ide_hwif_t *hwif)
* @hwif: hwif to update
* @tmp_hwif: template
*
- * Restore hwif to a previous state by copying most settngs
+ * Restore hwif to a previous state by copying most settings
* from the template.
*/
@@ -539,9 +539,10 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
hwif->dma_vendor3 = tmp_hwif->dma_vendor3;
hwif->dma_prdtable = tmp_hwif->dma_prdtable;
- hwif->dma_extra = tmp_hwif->dma_extra;
hwif->config_data = tmp_hwif->config_data;
hwif->select_data = tmp_hwif->select_data;
+ hwif->extra_base = tmp_hwif->extra_base;
+ hwif->extra_ports = tmp_hwif->extra_ports;
hwif->autodma = tmp_hwif->autodma;
hwif->udma_four = tmp_hwif->udma_four;
hwif->no_dsc = tmp_hwif->no_dsc;
@@ -550,7 +551,7 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
}
/**
- * ide_unregister - free an ide interface
+ * ide_unregister - free an IDE interface
* @index: index of interface (will change soon to a pointer)
*
* Perform the final unregister of an IDE interface. At the moment
@@ -563,8 +564,8 @@ static void ide_hwif_restore(ide_hwif_t *hwif, ide_hwif_t *tmp_hwif)
* deadlocking the IDE layer. The shutdown callback is called
* before we take the lock and free resources. It is up to the
* caller to be sure there is no pending I/O here, and that
- * the interfce will not be reopened (present/vanishing locking
- * isnt yet done btw). After we commit to the final kill we
+ * the interface will not be reopened (present/vanishing locking
+ * isn't yet done BTW). After we commit to the final kill we
* call the cleanup callback with the ide locks held.
*
* Unregister restores the hwif structures to the default state.
@@ -674,6 +675,9 @@ void ide_unregister(unsigned int index)
hwif->dma_status = 0;
hwif->dma_vendor3 = 0;
hwif->dma_prdtable = 0;
+
+ hwif->extra_base = 0;
+ hwif->extra_ports = 0;
}
/* copy original settings */
@@ -1217,9 +1221,9 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
- rq.flags = REQ_PM_SUSPEND;
+ rq.cmd_type = REQ_TYPE_PM_SUSPEND;
rq.special = &args;
- rq.end_io_data = &rqpm;
+ rq.data = &rqpm;
rqpm.pm_step = ide_pm_state_start_suspend;
if (mesg.event == PM_EVENT_PRETHAW)
mesg.event = PM_EVENT_FREEZE;
@@ -1238,9 +1242,9 @@ static int generic_ide_resume(struct device *dev)
memset(&rq, 0, sizeof(rq));
memset(&rqpm, 0, sizeof(rqpm));
memset(&args, 0, sizeof(args));
- rq.flags = REQ_PM_RESUME;
+ rq.cmd_type = REQ_TYPE_PM_RESUME;
rq.special = &args;
- rq.end_io_data = &rqpm;
+ rq.data = &rqpm;
rqpm.pm_step = ide_pm_state_start_resume;
rqpm.pm_state = PM_EVENT_ON;
@@ -1360,6 +1364,11 @@ int generic_ide_ioctl(ide_drive_t *drive, struct file *file, struct block_device
spin_lock_irqsave(&ide_lock, flags);
+ if (HWGROUP(drive)->resetting) {
+ spin_unlock_irqrestore(&ide_lock, flags);
+ return -EBUSY;
+ }
+
ide_abort(drive, "drive reset");
BUG_ON(HWGROUP(drive)->handler);
@@ -1993,10 +2002,16 @@ EXPORT_SYMBOL_GPL(ide_bus_type);
*/
static int __init ide_init(void)
{
+ int ret;
+
printk(KERN_INFO "Uniform Multi-Platform E-IDE driver " REVISION "\n");
system_bus_speed = ide_system_bus_speed();
- bus_register(&ide_bus_type);
+ ret = bus_register(&ide_bus_type);
+ if (ret < 0) {
+ printk(KERN_WARNING "IDE: bus_register error: %d\n", ret);
+ return ret;
+ }
init_ide_data();
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index aebecd8f51cc..b1d5291531b7 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -626,7 +626,7 @@ repeat:
req->rq_disk->disk_name, (req->cmd == READ)?"read":"writ",
cyl, head, sec, nsect, req->buffer);
#endif
- if (req->flags & REQ_CMD) {
+ if (blk_fs_request(req)) {
switch (rq_data_dir(req)) {
case READ:
hd_out(disk,nsect,sec,head,cyl,WIN_READ,&read_intr);
@@ -673,7 +673,7 @@ static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
* be forgotten about...
*/
-static irqreturn_t hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hd_interrupt(int irq, void *dev_id)
{
void (*handler)(void) = do_hd;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index 602797a44208..bef4759f70e5 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -120,7 +120,7 @@ static int ide_probe(struct pcmcia_device *link)
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
link->io.IOAddrLines = 3;
- link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+ link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->conf.Attributes = CONF_ENABLE_IRQ;
link->conf.IntType = INT_MEMORY_AND_IO;
@@ -398,12 +398,17 @@ static struct pcmcia_device_id ide_ids[] = {
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("M-Systems", "CF500", 0x7ed2ad87, 0x7a13045c),
PCMCIA_DEVICE_PROD_ID2("NinjaATA-", 0xebe0bd79),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
+ PCMCIA_DEVICE_PROD_ID12("SEAGATE", "ST1", 0x87c1b330, 0xe1f30883),
+ PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "04/05/06", 0x43d74cb4, 0x6a22777d),
+ PCMCIA_DEVICE_PROD_ID12("SMI VENDOR", "SMI PRODUCT", 0x30896c92, 0x703cc5f6),
PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
PCMCIA_DEVICE_PROD_ID1("TRANSCEND 512M ", 0xd0909443),
+ PCMCIA_DEVICE_PROD_ID12("TRANSCEND", "TS4GCF120", 0x709b1bf1, 0xf54a91c8),
PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
PCMCIA_DEVICE_PROD_ID12("STI", "Flash 5.0", 0xbf2df18d, 0x8cb57a0e),
diff --git a/drivers/ide/legacy/macide.c b/drivers/ide/legacy/macide.c
index d655da749144..b1730d7e414c 100644
--- a/drivers/ide/legacy/macide.c
+++ b/drivers/ide/legacy/macide.c
@@ -78,7 +78,7 @@ int macide_ack_intr(ide_hwif_t* hwif)
}
#ifdef CONFIG_BLK_DEV_MAC_MEDIABAY
-static void macide_mediabay_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void macide_mediabay_interrupt(int irq, void *dev_id)
{
int state = baboon->mb_status & 0x04;
diff --git a/drivers/ide/mips/swarm.c b/drivers/ide/mips/swarm.c
index 66f6064f4640..09c9e7936b0d 100644
--- a/drivers/ide/mips/swarm.c
+++ b/drivers/ide/mips/swarm.c
@@ -4,6 +4,7 @@
* Author: Manish Lachwani, mlachwani@mvista.com
* Copyright (C) 2004 MIPS Technologies, Inc. All rights reserved.
* Author: Maciej W. Rozycki <macro@mips.com>
+ * Copyright (c) 2006 Maciej W. Rozycki
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -127,6 +128,7 @@ static int __devinit swarm_ide_probe(struct device *dev)
memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
hwif->irq = hwif->hw.irq;
+ probe_hwif_init(hwif);
dev_set_drvdata(dev, hwif);
return 0;
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index f35d684edc25..fef08960aa4c 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -12,8 +12,8 @@ obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o
obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o
-obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o
obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
+obj-$(CONFIG_BLK_DEV_JMICRON) += jmicron.o
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
diff --git a/drivers/ide/pci/atiixp.c b/drivers/ide/pci/atiixp.c
index a574de5f0835..d55b938b1aeb 100644
--- a/drivers/ide/pci/atiixp.c
+++ b/drivers/ide/pci/atiixp.c
@@ -318,6 +318,20 @@ static void __devinit init_hwif_atiixp(ide_hwif_t *hwif)
hwif->drives[0].autodma = hwif->autodma;
}
+static void __devinit init_hwif_sb600_legacy(ide_hwif_t *hwif)
+{
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ if (!noautodma)
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+}
+
static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
{ /* 0 */
.name = "ATIIXP",
@@ -326,6 +340,12 @@ static ide_pci_device_t atiixp_pci_info[] __devinitdata = {
.autodma = AUTODMA,
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
.bootable = ON_BOARD,
+ },{ /* 1 */
+ .name = "ATI SB600 SATA Legacy IDE",
+ .init_hwif = init_hwif_sb600_legacy,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
}
};
@@ -348,6 +368,7 @@ static struct pci_device_id atiixp_pci_tbl[] = {
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
{ PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP600_SATA, PCI_ANY_ID, PCI_ANY_ID, (PCI_CLASS_STORAGE_IDE<<8)|0x8a, 0xffff05, 1},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, atiixp_pci_tbl);
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 380bb28c7c54..ae405fa32236 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -222,23 +222,23 @@ static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const ch
unsigned long flags;
dev = NULL;
- while ((dev = pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
+ while ((dev = pci_get_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) {
switch (dev->device) {
case PCI_DEVICE_ID_CYRIX_PCI_MASTER:
- master_0 = dev;
+ master_0 = pci_dev_get(dev);
break;
case PCI_DEVICE_ID_CYRIX_5530_LEGACY:
- cs5530_0 = dev;
+ cs5530_0 = pci_dev_get(dev);
break;
}
}
if (!master_0) {
printk(KERN_ERR "%s: unable to locate PCI MASTER function\n", name);
- return 0;
+ goto out;
}
if (!cs5530_0) {
printk(KERN_ERR "%s: unable to locate CS5530 LEGACY function\n", name);
- return 0;
+ goto out;
}
spin_lock_irqsave(&ide_lock, flags);
@@ -296,6 +296,9 @@ static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const ch
spin_unlock_irqrestore(&ide_lock, flags);
+out:
+ pci_dev_put(master_0);
+ pci_dev_put(cs5530_0);
return 0;
}
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 120929fbe7a3..64330c459bd4 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -281,7 +281,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
/* select primary or secondary channel */
if (hwif->index > 0) { /* drive is on the secondary channel */
- dev = pci_find_slot(dev->bus->number, dev->devfn+1);
+ dev = pci_get_slot(dev->bus, dev->devfn+1);
if (!dev) {
printk(KERN_ERR "%s: tune_drive: "
"Cannot find secondary interface!\n",
@@ -500,8 +500,9 @@ static int __devinit cy82c693_init_one(struct pci_dev *dev, const struct pci_dev
Function 1 is primary IDE channel, function 2 - secondary. */
if ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE &&
PCI_FUNC(dev->devfn) == 1) {
- dev2 = pci_find_slot(dev->bus->number, dev->devfn + 1);
+ dev2 = pci_get_slot(dev->bus, dev->devfn + 1);
ret = ide_setup_pci_devices(dev, dev2, d);
+ /* We leak pci refs here but thats ok - we can't be unloaded */
}
return ret;
}
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 78810ba982e9..ad418ce882ca 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -23,7 +23,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -41,15 +40,21 @@
static int ide_generic_all; /* Set to claim all devices */
+/*
+ * the module_param_named() was added for the modular case
+ * the __setup() is left as compatibility for existing setups
+ */
#ifndef MODULE
static int __init ide_generic_all_on(char *unused)
{
ide_generic_all = 1;
- printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
+ printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.");
return 1;
}
__setup("all-generic-ide", ide_generic_all_on);
#endif
+module_param_named(all_generic_ide, ide_generic_all, bool, 0444);
+MODULE_PARM_DESC(all_generic_ide, "IDE generic will claim all unknown PCI IDE storage controllers.");
static void __devinit init_hwif_generic (ide_hwif_t *hwif)
{
@@ -245,10 +250,12 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
if (dev->vendor == PCI_VENDOR_ID_JMICRON && PCI_FUNC(dev->devfn) != 1)
goto out;
- pci_read_config_word(dev, PCI_COMMAND, &command);
- if (!(command & PCI_COMMAND_IO)) {
- printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
- goto out;
+ if (dev->vendor != PCI_VENDOR_ID_JMICRON) {
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (!(command & PCI_COMMAND_IO)) {
+ printk(KERN_INFO "Skipping disabled %s IDE controller.\n", d->name);
+ goto out;
+ }
}
ret = ide_setup_pci_device(dev, d);
out:
diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
deleted file mode 100644
index 0fc89fafad65..000000000000
--- a/drivers/ide/pci/it8172.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * IT8172 IDE controller support
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/hdreg.h>
-#include <linux/ide.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/io.h>
-#include <asm/it8172/it8172_int.h>
-
-/*
- * Prototypes
- */
-static u8 it8172_ratemask (ide_drive_t *drive)
-{
- return 1;
-}
-
-static void it8172_tune_drive (ide_drive_t *drive, u8 pio)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct pci_dev *dev = hwif->pci_dev;
- int is_slave = (&hwif->drives[1] == drive);
- unsigned long flags;
- u16 drive_enables;
- u32 drive_timing;
-
- pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
- spin_lock_irqsave(&ide_lock, flags);
- pci_read_config_word(dev, 0x40, &drive_enables);
- pci_read_config_dword(dev, 0x44, &drive_timing);
-
- /*
- * FIX! The DIOR/DIOW pulse width and recovery times in port 0x44
- * are being left at the default values of 8 PCI clocks (242 nsec
- * for a 33 MHz clock). These can be safely shortened at higher
- * PIO modes. The DIOR/DIOW pulse width and recovery times only
- * apply to PIO modes, not to the DMA modes.
- */
-
- /*
- * Enable port 0x44. The IT8172G spec is confused; it calls
- * this register the "Slave IDE Timing Register", but in fact,
- * it controls timing for both master and slave drives.
- */
- drive_enables |= 0x4000;
-
- if (is_slave) {
- drive_enables &= 0xc006;
- if (pio > 1)
- /* enable prefetch and IORDY sample-point */
- drive_enables |= 0x0060;
- } else {
- drive_enables &= 0xc060;
- if (pio > 1)
- /* enable prefetch and IORDY sample-point */
- drive_enables |= 0x0006;
- }
-
- pci_write_config_word(dev, 0x40, drive_enables);
- spin_unlock_irqrestore(&ide_lock, flags);
-}
-
-static u8 it8172_dma_2_pio (u8 xfer_rate)
-{
- switch(xfer_rate) {
- case XFER_UDMA_5:
- case XFER_UDMA_4:
- case XFER_UDMA_3:
- case XFER_UDMA_2:
- case XFER_UDMA_1:
- case XFER_UDMA_0:
- case XFER_MW_DMA_2:
- case XFER_PIO_4:
- return 4;
- case XFER_MW_DMA_1:
- case XFER_PIO_3:
- return 3;
- case XFER_SW_DMA_2:
- case XFER_PIO_2:
- return 2;
- case XFER_MW_DMA_0:
- case XFER_SW_DMA_1:
- case XFER_SW_DMA_0:
- case XFER_PIO_1:
- case XFER_PIO_0:
- case XFER_PIO_SLOW:
- default:
- return 0;
- }
-}
-
-static int it8172_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(it8172_ratemask(drive), xferspeed);
- int a_speed = 3 << (drive->dn * 4);
- int u_flag = 1 << drive->dn;
- int u_speed = 0;
- u8 reg48, reg4a;
-
- pci_read_config_byte(dev, 0x48, &reg48);
- pci_read_config_byte(dev, 0x4a, &reg4a);
-
- /*
- * Setting the DMA cycle time to 2 or 3 PCI clocks (60 and 91 nsec
- * at 33 MHz PCI clock) seems to cause BadCRC errors during DMA
- * transfers on some drives, even though both numbers meet the minimum
- * ATAPI-4 spec of 73 and 54 nsec for UDMA 1 and 2 respectively.
- * So the faster times are just commented out here. The good news is
- * that the slower cycle time has very little affect on transfer
- * performance.
- */
-
- switch(speed) {
- case XFER_UDMA_4:
- case XFER_UDMA_2: //u_speed = 2 << (drive->dn * 4); break;
- case XFER_UDMA_5:
- case XFER_UDMA_3:
- case XFER_UDMA_1: //u_speed = 1 << (drive->dn * 4); break;
- case XFER_UDMA_0: u_speed = 0 << (drive->dn * 4); break;
- case XFER_MW_DMA_2:
- case XFER_MW_DMA_1:
- case XFER_MW_DMA_0:
- case XFER_SW_DMA_2: break;
- case XFER_PIO_4:
- case XFER_PIO_3:
- case XFER_PIO_2:
- case XFER_PIO_0: break;
- default: return -1;
- }
-
- if (speed >= XFER_UDMA_0) {
- pci_write_config_byte(dev, 0x48, reg48 | u_flag);
- reg4a &= ~a_speed;
- pci_write_config_byte(dev, 0x4a, reg4a | u_speed);
- } else {
- pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
- pci_write_config_byte(dev, 0x4a, reg4a & ~a_speed);
- }
-
- it8172_tune_drive(drive, it8172_dma_2_pio(speed));
- return (ide_config_drive_speed(drive, speed));
-}
-
-static int it8172_config_chipset_for_dma (ide_drive_t *drive)
-{
- u8 speed = ide_dma_speed(drive, it8172_ratemask(drive));
-
- if (!(speed)) {
- u8 tspeed = ide_get_best_pio_mode(drive, 255, 4, NULL);
- speed = it8172_dma_2_pio(XFER_PIO_0 + tspeed);
- }
-
- (void) it8172_tune_chipset(drive, speed);
- return ide_dma_enable(drive);
-}
-
-static int it8172_config_drive_xfer_rate (ide_drive_t *drive)
-{
- ide_hwif_t *hwif = HWIF(drive);
- struct hd_driveid *id = drive->id;
-
- drive->init_speed = 0;
-
- if (id && (id->capability & 1) && drive->autodma) {
-
- if (ide_use_dma(drive)) {
- if (it8172_config_chipset_for_dma(drive))
- return hwif->ide_dma_on(drive);
- }
-
- goto fast_ata_pio;
-
- } else if ((id->capability & 8) || (id->field_valid & 2)) {
-fast_ata_pio:
- it8172_tune_drive(drive, 5);
- return hwif->ide_dma_off_quietly(drive);
- }
- /* IORDY not supported */
- return 0;
-}
-
-static unsigned int __devinit init_chipset_it8172 (struct pci_dev *dev, const char *name)
-{
- unsigned char progif;
-
- /*
- * Place both IDE interfaces into PCI "native" mode
- */
- pci_read_config_byte(dev, PCI_CLASS_PROG, &progif);
- pci_write_config_byte(dev, PCI_CLASS_PROG, progif | 0x05);
-
- return IT8172_IDE_IRQ;
-}
-
-
-static void __devinit init_hwif_it8172 (ide_hwif_t *hwif)
-{
- struct pci_dev* dev = hwif->pci_dev;
- unsigned long cmdBase, ctrlBase;
-
- hwif->autodma = 0;
- hwif->tuneproc = &it8172_tune_drive;
- hwif->speedproc = &it8172_tune_chipset;
-
- cmdBase = dev->resource[0].start;
- ctrlBase = dev->resource[1].start;
-
- ide_init_hwif_ports(&hwif->hw, cmdBase, ctrlBase | 2, NULL);
- memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->io_ports));
- hwif->noprobe = 0;
-
- if (!hwif->dma_base) {
- hwif->drives[0].autotune = 1;
- hwif->drives[1].autotune = 1;
- return;
- }
-
- hwif->atapi_dma = 1;
- hwif->ultra_mask = 0x07;
- hwif->mwdma_mask = 0x06;
- hwif->swdma_mask = 0x04;
-
- hwif->ide_dma_check = &it8172_config_drive_xfer_rate;
- if (!noautodma)
- hwif->autodma = 1;
- hwif->drives[0].autodma = hwif->autodma;
- hwif->drives[1].autodma = hwif->autodma;
-}
-
-static ide_pci_device_t it8172_chipsets[] __devinitdata = {
- { /* 0 */
- .name = "IT8172G",
- .init_chipset = init_chipset_it8172,
- .init_hwif = init_hwif_it8172,
- .channels = 2,
- .autodma = AUTODMA,
- .enablebits = {{0x00,0x00,0x00}, {0x40,0x00,0x01}},
- .bootable = ON_BOARD,
- }
-};
-
-static int __devinit it8172_init_one(struct pci_dev *dev, const struct pci_device_id *id)
-{
- if ((!(PCI_FUNC(dev->devfn) & 1) ||
- (!((dev->class >> 8) == PCI_CLASS_STORAGE_IDE))))
- return -ENODEV; /* IT8172 is more than an IDE controller */
- return ide_setup_pci_device(dev, &it8172_chipsets[id->driver_data]);
-}
-
-static struct pci_device_id it8172_pci_tbl[] = {
- { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { 0, },
-};
-MODULE_DEVICE_TABLE(pci, it8172_pci_tbl);
-
-static struct pci_driver driver = {
- .name = "IT8172_IDE",
- .id_table = it8172_pci_tbl,
- .probe = it8172_init_one,
-};
-
-static int it8172_ide_init(void)
-{
- return ide_pci_register_driver(&driver);
-}
-
-module_init(it8172_ide_init);
-
-MODULE_AUTHOR("SteveL@mvista.com");
-MODULE_DESCRIPTION("PCI driver module for ITE 8172 IDE");
-MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/jmicron.c b/drivers/ide/pci/jmicron.c
new file mode 100644
index 000000000000..c1cec236ecf0
--- /dev/null
+++ b/drivers/ide/pci/jmicron.c
@@ -0,0 +1,268 @@
+
+/*
+ * Copyright (C) 2006 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+typedef enum {
+ PORT_PATA0 = 0,
+ PORT_PATA1 = 1,
+ 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
+ *
+ * Return 1 if the cable is 80pin
+ */
+
+static int __devinit ata66_jmicron(ide_hwif_t *hwif)
+{
+ struct pci_dev *pdev = hwif->pci_dev;
+
+ u32 control;
+ u32 control5;
+
+ int port = hwif->channel;
+ port_type port_map[2];
+
+ pci_read_config_dword(pdev, 0x40, &control);
+
+ /* There are two basic mappings. One has the two SATA ports merged
+ as master/slave and the secondary as PATA, the other has only the
+ SATA port mapped */
+ if (control & (1 << 23)) {
+ port_map[0] = PORT_SATA;
+ port_map[1] = PORT_PATA0;
+ } else {
+ port_map[0] = PORT_SATA;
+ port_map[1] = PORT_SATA;
+ }
+
+ /* The 365/366 may have this bit set to map the second PATA port
+ as the internal primary channel */
+ pci_read_config_dword(pdev, 0x80, &control5);
+ if (control5 & (1<<24))
+ port_map[0] = PORT_PATA1;
+
+ /* The two ports may then be logically swapped by the firmware */
+ if (control & (1 << 22))
+ port = port ^ 1;
+
+ /*
+ * Now we know which physical port we are talking about we can
+ * actually do our cable checking etc. Thankfully we don't need
+ * to do the plumbing for other cases.
+ */
+ switch (port_map[port])
+ {
+ case PORT_PATA0:
+ if (control & (1 << 3)) /* 40/80 pin primary */
+ return 1;
+ return 0;
+ case PORT_PATA1:
+ if (control5 & (1 << 19)) /* 40/80 pin secondary */
+ return 0;
+ return 1;
+ case PORT_SATA:
+ return 1;
+ }
+}
+
+static void jmicron_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ return;
+}
+
+/**
+ * config_jmicron_chipset_for_pio - set drive timings
+ * @drive: drive to tune
+ * @speed we want
+ *
+ */
+
+static void config_jmicron_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ u8 speed = XFER_PIO_0 + ide_get_best_pio_mode(drive, 255, 5, NULL);
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * jmicron_tune_chipset - set controller timings
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * As the JMicron snoops for timings all we actually need to do is
+ * make sure we don't set an invalid mode. We do need to honour
+ * the cable detect here.
+ */
+
+static int jmicron_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+
+ u8 speed = ide_rate_filter(jmicron_ratemask(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));
+
+ config_jmicron_chipset_for_pio(drive, !speed);
+ 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
+ *
+ * As the JMicron snoops for timings all we actually need to do is
+ * make sure we don't set an invalid mode.
+ */
+
+static int jmicron_config_drive_for_dma (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+ config_jmicron_chipset_for_pio(drive, 1);
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ * init_hwif_jmicron - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * Minimal set up is required for the Jmicron hardware.
+ */
+
+static void __devinit init_hwif_jmicron(ide_hwif_t *hwif)
+{
+ hwif->speedproc = &jmicron_tune_chipset;
+ hwif->tuneproc = &jmicron_tuneproc;
+
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ goto fallback;
+
+ hwif->atapi_dma = 1;
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+
+ hwif->ide_dma_check = &jmicron_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66_jmicron(hwif);
+
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+ return;
+fallback:
+ hwif->autodma = 0;
+ return;
+}
+
+#define DECLARE_JMB_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_hwif = init_hwif_jmicron, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .bootable = ON_BOARD, \
+ .enablebits = { {0x40, 1, 1}, {0x40, 0x10, 0x10} }, \
+ }
+
+static ide_pci_device_t jmicron_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_JMB_DEV("JMB361"),
+ /* 1 */ DECLARE_JMB_DEV("JMB363"),
+ /* 2 */ DECLARE_JMB_DEV("JMB365"),
+ /* 3 */ DECLARE_JMB_DEV("JMB366"),
+ /* 4 */ DECLARE_JMB_DEV("JMB368"),
+};
+
+/**
+ * jmicron_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds a Jmicron controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit jmicron_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_setup_pci_device(dev, &jmicron_chipsets[id->driver_data]);
+ return 0;
+}
+
+static struct pci_device_id jmicron_pci_tbl[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB361), 0},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB363), 1},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB365), 2},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB366), 3},
+ { PCI_DEVICE(PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB368), 4},
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, jmicron_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "JMicron IDE",
+ .id_table = jmicron_pci_tbl,
+ .probe = jmicron_init_one,
+};
+
+static int __init jmicron_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(jmicron_ide_init);
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the JMicron in legacy modes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index b46022a11bef..184cdacddeb6 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -154,7 +154,8 @@ static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
u8 AP, BP, CP, DP;
u8 TA = 0, TB = 0, TC = 0;
- if ((drive->media != ide_disk) && (speed < XFER_SW_DMA_0))
+ if (drive->media != ide_disk &&
+ drive->media != ide_cdrom && speed < XFER_SW_DMA_0)
return -1;
pci_read_config_dword(dev, drive_pci, &drive_conf);
@@ -330,14 +331,12 @@ static int config_chipset_for_dma (ide_drive_t *drive)
chipset_is_set:
- if (drive->media == ide_disk) {
- pci_read_config_byte(dev, (drive_pci), &AP);
- if (id->capability & 4) /* IORDY_EN */
- pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
- pci_read_config_byte(dev, (drive_pci), &AP);
- if (drive->media == ide_disk) /* PREFETCH_EN */
- pci_write_config_byte(dev, (drive_pci), AP|PREFETCH_EN);
- }
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ if (id->capability & 4) /* IORDY_EN */
+ pci_write_config_byte(dev, (drive_pci), AP|IORDY_EN);
+ pci_read_config_byte(dev, (drive_pci), &AP);
+ 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));
@@ -385,7 +384,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
{
if (drive->current_speed > XFER_UDMA_2)
pdc_old_enable_66MHz_clock(drive->hwif);
- if (drive->addressing == 1) {
+ if (drive->media != ide_disk || drive->addressing == 1) {
struct request *rq = HWGROUP(drive)->rq;
ide_hwif_t *hwif = HWIF(drive);
unsigned long high_16 = hwif->dma_master;
@@ -405,7 +404,7 @@ static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
static int pdc202xx_old_ide_dma_end(ide_drive_t *drive)
{
- if (drive->addressing == 1) {
+ if (drive->media != ide_disk || drive->addressing == 1) {
ide_hwif_t *hwif = HWIF(drive);
unsigned long high_16 = hwif->dma_master;
unsigned long atapi_reg = high_16 + (hwif->channel ? 0x24 : 0x20);
@@ -519,6 +518,7 @@ static void __devinit init_hwif_pdc202xx(ide_hwif_t *hwif)
hwif->ultra_mask = 0x3f;
hwif->mwdma_mask = 0x07;
hwif->swdma_mask = 0x07;
+ hwif->atapi_dma = 1;
hwif->err_stops_fifo = 1;
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index 50332ddd5ddb..cdc3aab9ebcb 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -222,13 +222,15 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
u16 master_data;
u8 slave_data;
static DEFINE_SPINLOCK(tune_lock);
+ int control = 0;
/* ISP RTC */
- u8 timings[][2] = { { 0, 0 },
- { 0, 0 },
- { 1, 0 },
- { 2, 1 },
- { 2, 3 }, };
+ static const u8 timings[][2]= {
+ { 0, 0 },
+ { 0, 0 },
+ { 1, 0 },
+ { 2, 1 },
+ { 2, 3 }, };
pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
@@ -239,19 +241,30 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
*/
spin_lock_irqsave(&tune_lock, flags);
pci_read_config_word(dev, master_port, &master_data);
+
+ if (pio >= 2)
+ control |= 1; /* Programmable timing on */
+ if (drive->media == ide_disk)
+ control |= 4; /* Prefetch, post write */
+ if (pio >= 3)
+ control |= 2; /* IORDY */
if (is_slave) {
master_data = master_data | 0x4000;
- if (pio > 1)
+ if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | 0x0070;
+ master_data = master_data | (control << 4);
+ } else {
+ master_data &= ~0x0070;
+ }
pci_read_config_byte(dev, slave_port, &slave_data);
slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
} else {
master_data = master_data & 0xccf8;
- if (pio > 1)
+ if (pio > 1) {
/* enable PPE, IE and TIME */
- master_data = master_data | 0x0007;
+ master_data = master_data | control;
+ }
master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
}
pci_write_config_word(dev, master_port, master_data);
@@ -615,7 +628,7 @@ static void __devinit piix_check_450nx(void)
struct pci_dev *pdev = NULL;
u16 cfg;
u8 rev;
- while((pdev=pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
+ while((pdev=pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82454NX, pdev))!=NULL)
{
/* Look for 450NX PXB. Check for problem configurations
A PCI quirk checks bit 6 already */
diff --git a/drivers/ide/pci/rz1000.c b/drivers/ide/pci/rz1000.c
index 608cd7609072..5f6950c2d1d1 100644
--- a/drivers/ide/pci/rz1000.c
+++ b/drivers/ide/pci/rz1000.c
@@ -17,7 +17,6 @@
#undef REALLY_SLOW_IO /* most systems can safely undef this */
-#include <linux/config.h> /* for CONFIG_BLK_DEV_IDEPCI */
#include <linux/types.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index fc2b5496b6d2..ff80937d94dd 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -323,6 +323,7 @@ static void sc1200_tuneproc (ide_drive_t *drive, byte pio) /* mode=255 means "au
}
}
+#ifdef CONFIG_PM
static ide_hwif_t *lookup_pci_dev (ide_hwif_t *prev, struct pci_dev *dev)
{
int h;
@@ -451,6 +452,7 @@ static int sc1200_resume (struct pci_dev *dev)
}
return 0;
}
+#endif
/*
* This gets invoked by the IDE driver once for each channel,
@@ -499,8 +501,10 @@ static struct pci_driver driver = {
.name = "SC1200_IDE",
.id_table = sc1200_pci_tbl,
.probe = sc1200_init_one,
+#ifdef CONFIG_PM
.suspend = sc1200_suspend,
.resume = sc1200_resume,
+#endif
};
static int sc1200_ide_init(void)
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index f063d954236c..057548d07205 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -359,7 +359,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
/* OSB4 : South Bridge and IDE */
if (dev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) {
- isa_dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+ isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL);
if (isa_dev) {
pci_read_config_dword(isa_dev, 0x64, &reg);
@@ -380,7 +380,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
if (!(PCI_FUNC(dev->devfn) & 1)) {
struct pci_dev * findev = NULL;
u32 reg4c = 0;
- findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL);
if (findev) {
pci_read_config_dword(findev, 0x4C, &reg4c);
@@ -388,6 +388,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
reg4c |= 0x00000040;
reg4c |= 0x00000020;
pci_write_config_dword(findev, 0x4C, reg4c);
+ pci_dev_put(findev);
}
outb_p(0x06, 0x0c00);
dev->irq = inb_p(0x0c01);
@@ -395,12 +396,13 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
struct pci_dev * findev = NULL;
u8 reg41 = 0;
- findev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS,
+ findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS,
PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL);
if (findev) {
pci_read_config_byte(findev, 0x41, &reg41);
reg41 &= ~0x40;
pci_write_config_byte(findev, 0x41, reg41);
+ pci_dev_put(findev);
}
/*
* This is a device pin issue on CSB6.
diff --git a/drivers/ide/pci/sgiioc4.c b/drivers/ide/pci/sgiioc4.c
index d8a0d87df734..244f7eb7006d 100644
--- a/drivers/ide/pci/sgiioc4.c
+++ b/drivers/ide/pci/sgiioc4.c
@@ -220,7 +220,7 @@ sgiioc4_ide_dma_end(ide_drive_t * drive)
ide_hwif_t *hwif = HWIF(drive);
u64 dma_base = hwif->dma_base;
int dma_stat = 0;
- unsigned long *ending_dma = (unsigned long *) hwif->dma_base2;
+ unsigned long *ending_dma = ide_get_hwifdata(hwif);
hwif->OUTL(IOC4_S_DMA_STOP, dma_base + IOC4_DMA_CTRL * 4);
@@ -369,6 +369,7 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
{
void __iomem *virt_dma_base;
int num_ports = sizeof (ioc4_dma_regs_t);
+ void *pad;
printk(KERN_INFO "%s: BM-DMA at 0x%04lx-0x%04lx\n", hwif->name,
dma_base, dma_base + num_ports - 1);
@@ -400,17 +401,14 @@ ide_dma_sgiioc4(ide_hwif_t * hwif, unsigned long dma_base)
hwif->sg_max_nents = IOC4_PRD_ENTRIES;
- hwif->dma_base2 = (unsigned long)
- pci_alloc_consistent(hwif->pci_dev,
- IOC4_IDE_CACHELINE_SIZE,
- (dma_addr_t *) &(hwif->dma_status));
+ pad = pci_alloc_consistent(hwif->pci_dev, IOC4_IDE_CACHELINE_SIZE,
+ (dma_addr_t *) &(hwif->dma_status));
- if (!hwif->dma_base2)
- goto dma_base2alloc_failure;
-
- return;
+ if (pad) {
+ ide_set_hwifdata(hwif, pad);
+ return;
+ }
-dma_base2alloc_failure:
pci_free_consistent(hwif->pci_dev,
IOC4_PRD_ENTRIES * IOC4_PRD_BYTES,
hwif->dmatable_cpu, hwif->dmatable_dma);
@@ -476,7 +474,7 @@ sgiioc4_configure_for_dma(int dma_direction, ide_drive_t * drive)
hwif->OUTL(dma_addr, dma_base + IOC4_DMA_PTR_L * 4);
/* Address of the Ending DMA */
- memset((unsigned int *) hwif->dma_base2, 0, IOC4_IDE_CACHELINE_SIZE);
+ memset(ide_get_hwifdata(hwif), 0, IOC4_IDE_CACHELINE_SIZE);
ending_dma_addr = cpu_to_le32(hwif->dma_status);
hwif->OUTL(ending_dma_addr, dma_base + IOC4_DMA_END_ADDR * 4);
@@ -776,7 +774,7 @@ ioc4_ide_exit(void)
ioc4_unregister_submodule(&ioc4_ide_submodule);
}
-module_init(ioc4_ide_init);
+late_initcall(ioc4_ide_init); /* Call only after IDE init is done */
module_exit(ioc4_ide_exit);
MODULE_AUTHOR("Aniket Malatpure/Jeremy Higdon");
diff --git a/drivers/ide/pci/siimage.c b/drivers/ide/pci/siimage.c
index 20b392948f36..697f566fb90a 100644
--- a/drivers/ide/pci/siimage.c
+++ b/drivers/ide/pci/siimage.c
@@ -898,7 +898,6 @@ static void __devinit init_mmio_iops_siimage(ide_hwif_t *hwif)
base = (unsigned long) addr;
hwif->dma_base = base + (ch ? 0x08 : 0x00);
- hwif->dma_base2 = base + (ch ? 0x18 : 0x10);
hwif->mmio = 2;
}
diff --git a/drivers/ide/pci/sis5513.c b/drivers/ide/pci/sis5513.c
index f03196c5db37..92edf76bd7ad 100644
--- a/drivers/ide/pci/sis5513.c
+++ b/drivers/ide/pci/sis5513.c
@@ -739,7 +739,7 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
for (i = 0; i < ARRAY_SIZE(SiSHostChipInfo) && !chipset_family; i++) {
- host = pci_find_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL);
+ host = pci_get_device(PCI_VENDOR_ID_SI, SiSHostChipInfo[i].host_id, NULL);
if (!host)
continue;
@@ -753,6 +753,7 @@ static unsigned int __devinit init_chipset_sis5513 (struct pci_dev *dev, const c
if (hostrev >= 0x30)
chipset_family = ATA_100a;
}
+ pci_dev_put(host);
printk(KERN_INFO "SIS5513: %s %s controller\n",
SiSHostChipInfo[i].name, chipset_capability[chipset_family]);
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 9b7589e8e93e..2af634d7acf4 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -248,7 +248,7 @@ static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
u8 t;
for (via_config = via_isa_bridges; via_config->id; via_config++)
- if ((*isa = pci_find_device(PCI_VENDOR_ID_VIA +
+ if ((*isa = pci_get_device(PCI_VENDOR_ID_VIA +
!!(via_config->flags & VIA_BAD_ID),
via_config->id, NULL))) {
@@ -256,6 +256,7 @@ static struct via_isa_bridge *via_config_find(struct pci_dev **isa)
if (t >= via_config->rev_min &&
t <= via_config->rev_max)
break;
+ pci_dev_put(*isa);
}
return via_config;
@@ -283,6 +284,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
via_config = via_config_find(&isa);
if (!via_config->id) {
printk(KERN_WARNING "VP_IDE: Unknown VIA SouthBridge, disabling DMA.\n");
+ pci_dev_put(isa);
return -ENODEV;
}
@@ -361,6 +363,7 @@ static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const
via_dma[via_config->flags & VIA_UDMA],
pci_name(dev));
+ pci_dev_put(isa);
return 0;
}
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 31ad79f52df7..91c5344a945d 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/ide/ide-pmac.c
+ * linux/drivers/ide/ppc/pmac.c
*
* Support for IDE interfaces on PowerMacs.
* These IDE interfaces are memory-mapped and have a DBDMA channel
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index eb0945284acc..0719b6484824 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -101,7 +101,7 @@ static ide_hwif_t *ide_match_hwif(unsigned long io_base, u8 bootable, const char
return hwif; /* pick an unused entry */
}
}
- for (h = 0; h < 2; ++h) {
+ for (h = 0; h < 2 && h < MAX_HWIFS; ++h) {
hwif = ide_hwifs + h;
if (hwif->chipset == ide_unknown)
return hwif; /* pick an unused entry */
@@ -795,24 +795,6 @@ int __ide_pci_register_driver(struct pci_driver *driver, struct module *module)
EXPORT_SYMBOL_GPL(__ide_pci_register_driver);
/**
- * ide_unregister_pci_driver - unregister an IDE driver
- * @driver: driver to remove
- *
- * Unregister a currently installed IDE driver. Returns are the same
- * as for pci_unregister_driver
- */
-
-void ide_pci_unregister_driver(struct pci_driver *driver)
-{
- if(!pre_init)
- pci_unregister_driver(driver);
- else
- list_del(&driver->node);
-}
-
-EXPORT_SYMBOL_GPL(ide_pci_unregister_driver);
-
-/**
* ide_scan_pcidev - find an IDE driver for a device
* @dev: PCI device to check
*
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 186737539cf5..672b92ef9f21 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -120,12 +120,19 @@ config IEEE1394_VIDEO1394
this option only if you have an IEEE 1394 video device connected to
an OHCI-1394 card.
+comment "SBP-2 support (for storage devices) requires SCSI"
+ depends on IEEE1394 && SCSI=n
+
config IEEE1394_SBP2
tristate "SBP-2 support (Harddisks etc.)"
depends on IEEE1394 && SCSI && (PCI || BROKEN)
help
- This option enables you to use SBP-2 devices connected to your IEEE
- 1394 bus. SBP-2 devices include harddrives and DVD devices.
+ This option enables you to use SBP-2 devices connected to an IEEE
+ 1394 bus. SBP-2 devices include storage devices like harddisks and
+ DVD drives, also some other FireWire devices like scanners.
+
+ You should also enable support for disks, CD-ROMs, etc. in the SCSI
+ configuration section.
config IEEE1394_SBP2_PHYS_DMA
bool "Enable replacement for physical DMA in SBP2"
@@ -133,7 +140,7 @@ config IEEE1394_SBP2_PHYS_DMA
help
This builds sbp2 for use with non-OHCI host adapters which do not
support physical DMA or for when ohci1394 is run with phys_dma=0.
- Physical DMA is data movement without assistence of the drivers'
+ Physical DMA is data movement without assistance of the drivers'
interrupt handlers. This option includes the interrupt handlers
that are required in absence of this hardware feature.
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index 149573db91c5..ab0c80f61b9d 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -17,11 +17,13 @@
*
*/
-#include <linux/string.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/param.h>
#include <linux/spinlock.h>
+#include <linux/string.h>
#include "csr1212.h"
#include "ieee1394_types.h"
@@ -149,31 +151,18 @@ static void host_reset(struct hpsb_host *host)
/*
* HI == seconds (bits 0:2)
- * LO == fraction units of 1/8000 of a second, as per 1394 (bits 19:31)
- *
- * Convert to units and then to HZ, for comparison to jiffies.
- *
- * By default this will end up being 800 units, or 100ms (125usec per
- * unit).
+ * LO == fractions of a second in units of 125usec (bits 19:31)
*
- * NOTE: The spec says 1/8000, but also says we can compute based on 1/8192
- * like CSR specifies. Should make our math less complex.
+ * Convert SPLIT_TIMEOUT to jiffies.
+ * The default and minimum as per 1394a-2000 clause 8.3.2.2.6 is 100ms.
*/
static inline void calculate_expire(struct csr_control *csr)
{
- unsigned long units;
-
- /* Take the seconds, and convert to units */
- units = (unsigned long)(csr->split_timeout_hi & 0x07) << 13;
-
- /* Add in the fractional units */
- units += (unsigned long)(csr->split_timeout_lo >> 19);
-
- /* Convert to jiffies */
- csr->expire = (unsigned long)(units * HZ) >> 13UL;
+ unsigned long usecs =
+ (csr->split_timeout_hi & 0x07) * USEC_PER_SEC +
+ (csr->split_timeout_lo >> 19) * 125L;
- /* Just to keep from rounding low */
- csr->expire++;
+ csr->expire = usecs_to_jiffies(usecs > 100000L ? usecs : 100000L);
HPSB_VERBOSE("CSR: setting expire to %lu, HZ=%u", csr->expire, HZ);
}
diff --git a/drivers/ieee1394/csr.h b/drivers/ieee1394/csr.h
index ea9aa4f53ab6..f11546550d84 100644
--- a/drivers/ieee1394/csr.h
+++ b/drivers/ieee1394/csr.h
@@ -1,75 +1,73 @@
-
#ifndef _IEEE1394_CSR_H
#define _IEEE1394_CSR_H
-#ifdef CONFIG_PREEMPT
-#include <linux/sched.h>
-#endif
+#include <linux/spinlock_types.h>
#include "csr1212.h"
+#include "ieee1394_types.h"
-#define CSR_REGISTER_BASE 0xfffff0000000ULL
+#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 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
/* IEEE 1394 bus specific Configuration ROM Key IDs */
#define IEEE1394_KV_ID_POWER_REQUIREMENTS (0x30)
-/* IEEE 1394 Bus Inforamation Block specifics */
+/* IEEE 1394 Bus Information Block specifics */
#define CSR_BUS_INFO_SIZE (5 * sizeof(quadlet_t))
-#define CSR_IRMC_SHIFT 31
-#define CSR_CMC_SHIFT 30
-#define CSR_ISC_SHIFT 29
-#define CSR_BMC_SHIFT 28
-#define CSR_PMC_SHIFT 27
-#define CSR_CYC_CLK_ACC_SHIFT 16
-#define CSR_MAX_REC_SHIFT 12
-#define CSR_MAX_ROM_SHIFT 8
-#define CSR_GENERATION_SHIFT 4
+#define CSR_IRMC_SHIFT 31
+#define CSR_CMC_SHIFT 30
+#define CSR_ISC_SHIFT 29
+#define CSR_BMC_SHIFT 28
+#define CSR_PMC_SHIFT 27
+#define CSR_CYC_CLK_ACC_SHIFT 16
+#define CSR_MAX_REC_SHIFT 12
+#define CSR_MAX_ROM_SHIFT 8
+#define CSR_GENERATION_SHIFT 4
#define CSR_SET_BUS_INFO_GENERATION(csr, gen) \
((csr)->bus_info_data[2] = \
cpu_to_be32((be32_to_cpu((csr)->bus_info_data[2]) & \
- ~(0xf << CSR_GENERATION_SHIFT)) | \
+ ~(0xf << CSR_GENERATION_SHIFT)) | \
(gen) << CSR_GENERATION_SHIFT))
struct csr_control {
- spinlock_t lock;
-
- quadlet_t state;
- quadlet_t node_ids;
- quadlet_t split_timeout_hi, split_timeout_lo;
- unsigned long expire; // Calculated from split_timeout
- quadlet_t cycle_time;
- quadlet_t bus_time;
- quadlet_t bus_manager_id;
- quadlet_t bandwidth_available;
- quadlet_t channels_available_hi, channels_available_lo;
+ spinlock_t lock;
+
+ quadlet_t state;
+ quadlet_t node_ids;
+ quadlet_t split_timeout_hi, split_timeout_lo;
+ unsigned long expire; /* Calculated from split_timeout */
+ quadlet_t cycle_time;
+ quadlet_t bus_time;
+ quadlet_t bus_manager_id;
+ quadlet_t bandwidth_available;
+ quadlet_t channels_available_hi, channels_available_lo;
quadlet_t broadcast_channel;
/* Bus Info */
@@ -84,8 +82,8 @@ struct csr_control {
struct csr1212_csr *rom;
- quadlet_t topology_map[256];
- quadlet_t speed_map[1024];
+ quadlet_t topology_map[256];
+ quadlet_t speed_map[1024];
};
extern struct csr1212_bus_ops csr_bus_ops;
@@ -93,4 +91,9 @@ extern struct csr1212_bus_ops csr_bus_ops;
int init_csr(void);
void cleanup_csr(void);
+/* hpsb_update_config_rom() is deprecated */
+struct hpsb_host;
+int hpsb_update_config_rom(struct hpsb_host *host, const quadlet_t *new_rom,
+ size_t size, unsigned char rom_version);
+
#endif /* _IEEE1394_CSR_H */
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
index ca5167de707d..c68f328e1a29 100644
--- a/drivers/ieee1394/dma.c
+++ b/drivers/ieee1394/dma.c
@@ -7,10 +7,13 @@
* directory of the kernel sources for details.
*/
+#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/vmalloc.h>
+#include <linux/pci.h>
#include <linux/slab.h>
-#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <asm/scatterlist.h>
+
#include "dma.h"
/* dma_prog_region */
diff --git a/drivers/ieee1394/dma.h b/drivers/ieee1394/dma.h
index 061550a6fb99..a1682aba71c7 100644
--- a/drivers/ieee1394/dma.h
+++ b/drivers/ieee1394/dma.h
@@ -10,69 +10,91 @@
#ifndef IEEE1394_DMA_H
#define IEEE1394_DMA_H
-#include <linux/pci.h>
-#include <asm/scatterlist.h>
-
-/* struct dma_prog_region
-
- a small, physically-contiguous DMA buffer with random-access,
- synchronous usage characteristics
-*/
-
+#include <asm/types.h>
+
+struct pci_dev;
+struct scatterlist;
+struct vm_area_struct;
+
+/**
+ * struct dma_prog_region - small contiguous DMA buffer
+ * @kvirt: kernel virtual address
+ * @dev: PCI device
+ * @n_pages: number of kernel pages
+ * @bus_addr: base bus address
+ *
+ * a small, physically contiguous DMA buffer with random-access, synchronous
+ * usage characteristics
+ */
struct dma_prog_region {
- unsigned char *kvirt; /* kernel virtual address */
- struct pci_dev *dev; /* PCI device */
- unsigned int n_pages; /* # of kernel pages */
- dma_addr_t bus_addr; /* base bus address */
+ unsigned char *kvirt;
+ struct pci_dev *dev;
+ unsigned int n_pages;
+ dma_addr_t bus_addr;
};
/* clear out all fields but do not allocate any memory */
void dma_prog_region_init(struct dma_prog_region *prog);
-int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes, struct pci_dev *dev);
+int dma_prog_region_alloc(struct dma_prog_region *prog, unsigned long n_bytes,
+ struct pci_dev *dev);
void dma_prog_region_free(struct dma_prog_region *prog);
-static inline dma_addr_t dma_prog_region_offset_to_bus(struct dma_prog_region *prog, unsigned long offset)
+static inline dma_addr_t dma_prog_region_offset_to_bus(
+ struct dma_prog_region *prog, unsigned long offset)
{
return prog->bus_addr + offset;
}
-/* struct dma_region
-
- a large, non-physically-contiguous DMA buffer with streaming,
- asynchronous usage characteristics
-*/
-
+/**
+ * struct dma_region - large non-contiguous DMA buffer
+ * @virt: kernel virtual address
+ * @dev: PCI device
+ * @n_pages: number of kernel pages
+ * @n_dma_pages: number of IOMMU pages
+ * @sglist: IOMMU mapping
+ * @direction: PCI_DMA_TODEVICE, etc.
+ *
+ * a large, non-physically-contiguous DMA buffer with streaming, asynchronous
+ * usage characteristics
+ */
struct dma_region {
- unsigned char *kvirt; /* kernel virtual address */
- struct pci_dev *dev; /* PCI device */
- unsigned int n_pages; /* # of kernel pages */
- unsigned int n_dma_pages; /* # of IOMMU pages */
- struct scatterlist *sglist; /* IOMMU mapping */
- int direction; /* PCI_DMA_TODEVICE, etc */
+ unsigned char *kvirt;
+ struct pci_dev *dev;
+ unsigned int n_pages;
+ unsigned int n_dma_pages;
+ struct scatterlist *sglist;
+ int direction;
};
/* clear out all fields but do not allocate anything */
void dma_region_init(struct dma_region *dma);
/* allocate the buffer and map it to the IOMMU */
-int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes, struct pci_dev *dev, int direction);
+int dma_region_alloc(struct dma_region *dma, unsigned long n_bytes,
+ struct pci_dev *dev, int direction);
/* unmap and free the buffer */
void dma_region_free(struct dma_region *dma);
/* sync the CPU's view of the buffer */
-void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset, unsigned long len);
+void dma_region_sync_for_cpu(struct dma_region *dma, unsigned long offset,
+ unsigned long len);
+
/* sync the IO bus' view of the buffer */
-void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset, unsigned long len);
+void dma_region_sync_for_device(struct dma_region *dma, unsigned long offset,
+ unsigned long len);
/* map the buffer into a user space process */
-int dma_region_mmap(struct dma_region *dma, struct file *file, struct vm_area_struct *vma);
+int dma_region_mmap(struct dma_region *dma, struct file *file,
+ struct vm_area_struct *vma);
/* macro to index into a DMA region (or dma_prog_region) */
-#define dma_region_i(_dma, _type, _index) ( ((_type*) ((_dma)->kvirt)) + (_index) )
+#define dma_region_i(_dma, _type, _index) \
+ ( ((_type*) ((_dma)->kvirt)) + (_index) )
/* return the DMA bus address of the byte with the given offset
- relative to the beginning of the dma_region */
-dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset);
+ * relative to the beginning of the dma_region */
+dma_addr_t dma_region_offset_to_bus(struct dma_region *dma,
+ unsigned long offset);
#endif /* IEEE1394_DMA_H */
diff --git a/drivers/ieee1394/dv1394-private.h b/drivers/ieee1394/dv1394-private.h
index 80b5ac7fe383..7d1d2845b420 100644
--- a/drivers/ieee1394/dv1394-private.h
+++ b/drivers/ieee1394/dv1394-private.h
@@ -460,7 +460,7 @@ struct video_card {
int dma_running;
/*
- 3) the sleeping semaphore 'sem' - this is used from process context only,
+ 3) the sleeping mutex 'mtx' - this is used from process context only,
to serialize various operations on the video_card. Even though only one
open() is allowed, we still need to prevent multiple threads of execution
from entering calls like read, write, ioctl, etc.
@@ -468,9 +468,9 @@ struct video_card {
I honestly can't think of a good reason to use dv1394 from several threads
at once, but we need to serialize anyway to prevent oopses =).
- NOTE: if you need both spinlock and sem, take sem first to avoid deadlock!
+ NOTE: if you need both spinlock and mtx, take mtx first to avoid deadlock!
*/
- struct semaphore sem;
+ struct mutex mtx;
/* people waiting for buffer space, please form a line here... */
wait_queue_head_t waitq;
diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
index 87532dd43374..6c72f04b2b5d 100644
--- a/drivers/ieee1394/dv1394.c
+++ b/drivers/ieee1394/dv1394.c
@@ -95,6 +95,7 @@
#include <linux/fs.h>
#include <linux/poll.h>
#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/bitops.h>
#include <asm/byteorder.h>
#include <asm/atomic.h>
@@ -110,15 +111,15 @@
#include <linux/compat.h>
#include <linux/cdev.h>
+#include "dv1394.h"
+#include "dv1394-private.h"
+#include "highlevel.h"
+#include "hosts.h"
#include "ieee1394.h"
+#include "ieee1394_core.h"
+#include "ieee1394_hotplug.h"
#include "ieee1394_types.h"
#include "nodemgr.h"
-#include "hosts.h"
-#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "dv1394.h"
-#include "dv1394-private.h"
-
#include "ohci1394.h"
/* DEBUG LEVELS:
@@ -136,13 +137,13 @@
#if DV1394_DEBUG_LEVEL >= 2
#define irq_printk( args... ) printk( args )
#else
-#define irq_printk( args... )
+#define irq_printk( args... ) do {} while (0)
#endif
#if DV1394_DEBUG_LEVEL >= 1
#define debug_printk( args... ) printk( args)
#else
-#define debug_printk( args... )
+#define debug_printk( args... ) do {} while (0)
#endif
/* issue a dummy PCI read to force the preceding write
@@ -247,7 +248,7 @@ static void frame_delete(struct frame *f)
Frame_prepare() must be called OUTSIDE the video->spinlock.
However, frame_prepare() must still be serialized, so
- it should be called WITH the video->sem taken.
+ it should be called WITH the video->mtx taken.
*/
static void frame_prepare(struct video_card *video, unsigned int this_frame)
@@ -1271,7 +1272,7 @@ static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
int retval = -EINVAL;
/* serialize mmap */
- down(&video->sem);
+ mutex_lock(&video->mtx);
if ( ! video_card_initialized(video) ) {
retval = do_dv1394_init_default(video);
@@ -1281,7 +1282,7 @@ static int dv1394_mmap(struct file *file, struct vm_area_struct *vma)
retval = dma_region_mmap(&video->dv_buf, file, vma);
out:
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return retval;
}
@@ -1337,17 +1338,17 @@ static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t
/* serialize this to prevent multi-threaded mayhem */
if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&video->sem))
+ if (!mutex_trylock(&video->mtx))
return -EAGAIN;
} else {
- if (down_interruptible(&video->sem))
+ if (mutex_lock_interruptible(&video->mtx))
return -ERESTARTSYS;
}
if ( !video_card_initialized(video) ) {
ret = do_dv1394_init_default(video);
if (ret) {
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
}
@@ -1418,7 +1419,7 @@ static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t
remove_wait_queue(&video->waitq, &wait);
set_current_state(TASK_RUNNING);
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
@@ -1434,17 +1435,17 @@ static ssize_t dv1394_read(struct file *file, char __user *buffer, size_t count
/* serialize this to prevent multi-threaded mayhem */
if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&video->sem))
+ if (!mutex_trylock(&video->mtx))
return -EAGAIN;
} else {
- if (down_interruptible(&video->sem))
+ if (mutex_lock_interruptible(&video->mtx))
return -ERESTARTSYS;
}
if ( !video_card_initialized(video) ) {
ret = do_dv1394_init_default(video);
if (ret) {
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
video->continuity_counter = -1;
@@ -1526,7 +1527,7 @@ static ssize_t dv1394_read(struct file *file, char __user *buffer, size_t count
remove_wait_queue(&video->waitq, &wait);
set_current_state(TASK_RUNNING);
- up(&video->sem);
+ mutex_unlock(&video->mtx);
return ret;
}
@@ -1547,12 +1548,12 @@ static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* serialize this to prevent multi-threaded mayhem */
if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&video->sem)) {
+ if (!mutex_trylock(&video->mtx)) {
unlock_kernel();
return -EAGAIN;
}
} else {
- if (down_interruptible(&video->sem)) {
+ if (mutex_lock_interruptible(&video->mtx)) {
unlock_kernel();
return -ERESTARTSYS;
}
@@ -1778,7 +1779,7 @@ static long dv1394_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
out:
- up(&video->sem);
+ mutex_unlock(&video->mtx);
unlock_kernel();
return ret;
}
@@ -2253,7 +2254,7 @@ static int dv1394_init(struct ti_ohci *ohci, enum pal_or_ntsc format, enum modes
clear_bit(0, &video->open);
spin_lock_init(&video->spinlock);
video->dma_running = 0;
- init_MUTEX(&video->sem);
+ mutex_init(&video->mtx);
init_waitqueue_head(&video->waitq);
video->fasync = NULL;
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 2d5b57be98c3..8a7b8fab6238 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -64,19 +64,19 @@
#include <linux/ethtool.h>
#include <asm/uaccess.h>
#include <asm/delay.h>
-#include <asm/semaphore.h>
#include <net/arp.h>
+#include "config_roms.h"
#include "csr1212.h"
-#include "ieee1394_types.h"
+#include "eth1394.h"
+#include "highlevel.h"
+#include "ieee1394.h"
#include "ieee1394_core.h"
+#include "ieee1394_hotplug.h"
#include "ieee1394_transactions.h"
-#include "ieee1394.h"
-#include "highlevel.h"
+#include "ieee1394_types.h"
#include "iso.h"
#include "nodemgr.h"
-#include "eth1394.h"
-#include "config_roms.h"
#define ETH1394_PRINT_G(level, fmt, args...) \
printk(level "%s: " fmt, driver_name, ## args)
diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h
index e119fb87e5b5..50f2dd2c7e20 100644
--- a/drivers/ieee1394/highlevel.h
+++ b/drivers/ieee1394/highlevel.h
@@ -1,60 +1,61 @@
-
#ifndef IEEE1394_HIGHLEVEL_H
#define IEEE1394_HIGHLEVEL_H
+#include <linux/list.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
-struct hpsb_address_serve {
- struct list_head host_list; /* per host list */
+struct module;
- struct list_head hl_list; /* hpsb_highlevel list */
+#include "ieee1394_types.h"
- struct hpsb_address_ops *op;
+struct hpsb_host;
+/* internal to ieee1394 core */
+struct hpsb_address_serve {
+ struct list_head host_list; /* per host list */
+ struct list_head hl_list; /* hpsb_highlevel list */
+ struct hpsb_address_ops *op;
struct hpsb_host *host;
-
- /* first address handled and first address behind, quadlet aligned */
- u64 start, end;
+ u64 start; /* first address handled, quadlet aligned */
+ u64 end; /* first address behind, quadlet aligned */
};
-
-/*
- * The above structs are internal to highlevel driver handling. Only the
- * following structures are of interest to actual highlevel drivers.
- */
+/* Only the following structures are of interest to actual highlevel drivers. */
struct hpsb_highlevel {
struct module *owner;
const char *name;
- /* Any of the following pointers can legally be NULL, except for
- * iso_receive which can only be NULL when you don't request
- * channels. */
+ /* Any of the following pointers can legally be NULL, except for
+ * iso_receive which can only be NULL when you don't request
+ * channels. */
- /* New host initialized. Will also be called during
- * hpsb_register_highlevel for all hosts already installed. */
- void (*add_host) (struct hpsb_host *host);
+ /* New host initialized. Will also be called during
+ * hpsb_register_highlevel for all hosts already installed. */
+ void (*add_host)(struct hpsb_host *host);
- /* Host about to be removed. Will also be called during
- * hpsb_unregister_highlevel once for each host. */
- void (*remove_host) (struct hpsb_host *host);
+ /* Host about to be removed. Will also be called during
+ * hpsb_unregister_highlevel once for each host. */
+ void (*remove_host)(struct hpsb_host *host);
- /* Host experienced bus reset with possible configuration changes.
+ /* Host experienced bus reset with possible configuration changes.
* Note that this one may occur during interrupt/bottom half handling.
* You can not expect to be able to do stock hpsb_reads. */
- void (*host_reset) (struct hpsb_host *host);
+ void (*host_reset)(struct hpsb_host *host);
- /* An isochronous packet was received. Channel contains the channel
- * number for your convenience, it is also contained in the included
- * packet header (first quadlet, CRCs are missing). You may get called
- * for channel/host combinations you did not request. */
- void (*iso_receive) (struct hpsb_host *host, int channel,
- quadlet_t *data, size_t length);
+ /* An isochronous packet was received. Channel contains the channel
+ * number for your convenience, it is also contained in the included
+ * packet header (first quadlet, CRCs are missing). You may get called
+ * for channel/host combinations you did not request. */
+ void (*iso_receive)(struct hpsb_host *host, int channel,
+ quadlet_t *data, size_t length);
- /* A write request was received on either the FCP_COMMAND (direction =
- * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
- * contains the cts field (first byte of data). */
- void (*fcp_request) (struct hpsb_host *host, int nodeid, int direction,
- int cts, u8 *data, size_t length);
+ /* A write request was received on either the FCP_COMMAND (direction =
+ * 0) or the FCP_RESPONSE (direction = 1) register. The cts arg
+ * contains the cts field (first byte of data). */
+ void (*fcp_request)(struct hpsb_host *host, int nodeid, int direction,
+ int cts, u8 *data, size_t length);
/* These are initialized by the subsystem when the
* hpsb_higlevel is registered. */
@@ -67,61 +68,62 @@ struct hpsb_highlevel {
};
struct hpsb_address_ops {
- /*
- * Null function pointers will make the respective operation complete
- * with RCODE_TYPE_ERROR. Makes for easy to implement read-only
- * registers (just leave everything but read NULL).
- *
- * All functions shall return appropriate IEEE 1394 rcodes.
- */
-
- /* These functions have to implement block reads for themselves. */
- /* These functions either return a response code
- or a negative number. In the first case a response will be generated; in the
- later case, no response will be sent and the driver, that handled the request
- will send the response itself
- */
- int (*read) (struct hpsb_host *host, int nodeid, quadlet_t *buffer,
- u64 addr, size_t length, u16 flags);
- int (*write) (struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 flags);
-
- /* Lock transactions: write results of ext_tcode operation into
- * *store. */
- int (*lock) (struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
- int (*lock64) (struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
+ /*
+ * Null function pointers will make the respective operation complete
+ * with RCODE_TYPE_ERROR. Makes for easy to implement read-only
+ * registers (just leave everything but read NULL).
+ *
+ * All functions shall return appropriate IEEE 1394 rcodes.
+ */
+
+ /* These functions have to implement block reads for themselves.
+ *
+ * These functions either return a response code or a negative number.
+ * In the first case a response will be generated. In the latter case,
+ * no response will be sent and the driver which handled the request
+ * will send the response itself. */
+ int (*read)(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+ u64 addr, size_t length, u16 flags);
+ int (*write)(struct hpsb_host *host, int nodeid, int destid,
+ quadlet_t *data, u64 addr, size_t length, u16 flags);
+
+ /* Lock transactions: write results of ext_tcode operation into
+ * *store. */
+ int (*lock)(struct hpsb_host *host, int nodeid, quadlet_t *store,
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
+ u16 flags);
+ int (*lock64)(struct hpsb_host *host, int nodeid, octlet_t *store,
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
+ u16 flags);
};
-
void highlevel_add_host(struct hpsb_host *host);
void highlevel_remove_host(struct hpsb_host *host);
void highlevel_host_reset(struct hpsb_host *host);
-
-/* these functions are called to handle transactions. They are called, when
- a packet arrives. The flags argument contains the second word of the first header
- quadlet of the incoming packet (containing transaction label, retry code,
- transaction code and priority). These functions either return a response code
- or a negative number. In the first case a response will be generated; in the
- later case, no response will be sent and the driver, that handled the request
- will send the response itself.
-*/
-int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
- u64 addr, unsigned int length, u16 flags);
-int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
- void *data, u64 addr, unsigned int length, u16 flags);
+/*
+ * These functions are called to handle transactions. They are called when a
+ * packet arrives. The flags argument contains the second word of the first
+ * header quadlet of the incoming packet (containing transaction label, retry
+ * code, transaction code and priority). These functions either return a
+ * response code or a negative number. In the first case a response will be
+ * generated. In the latter case, no response will be sent and the driver which
+ * handled the request will send the response itself.
+ */
+int highlevel_read(struct hpsb_host *host, int nodeid, void *data, u64 addr,
+ unsigned int length, u16 flags);
+int highlevel_write(struct hpsb_host *host, int nodeid, int destid, void *data,
+ u64 addr, unsigned int length, u16 flags);
int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
- u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
+ u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode,
+ u16 flags);
int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
- u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
+ u64 addr, octlet_t data, octlet_t arg, int ext_tcode,
+ u16 flags);
-void highlevel_iso_receive(struct hpsb_host *host, void *data,
- size_t length);
+void highlevel_iso_receive(struct hpsb_host *host, void *data, size_t length);
void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
- void *data, size_t length);
-
+ void *data, size_t length);
/*
* Register highlevel driver. The name pointer has to stay valid at all times
@@ -132,13 +134,15 @@ void hpsb_unregister_highlevel(struct hpsb_highlevel *hl);
/*
* Register handlers for host address spaces. Start and end are 48 bit pointers
- * and have to be quadlet aligned (end points to the first address behind the
- * handled addresses. This function can be called multiple times for a single
- * hpsb_highlevel to implement sparse register sets. The requested region must
- * not overlap any previously allocated region, otherwise registering will fail.
+ * and have to be quadlet aligned. Argument "end" points to the first address
+ * behind the handled addresses. This function can be called multiple times for
+ * a single hpsb_highlevel to implement sparse register sets. The requested
+ * region must not overlap any previously allocated region, otherwise
+ * registering will fail.
*
- * It returns true for successful allocation. There is no unregister function,
- * all address spaces are deallocated together with the hpsb_highlevel.
+ * It returns true for successful allocation. Address spaces can be
+ * unregistered with hpsb_unregister_addrspace. All remaining address spaces
+ * are automatically deallocated together with the hpsb_highlevel.
*/
u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
struct hpsb_host *host,
@@ -146,20 +150,18 @@ u64 hpsb_allocate_and_register_addrspace(struct hpsb_highlevel *hl,
u64 size, u64 alignment,
u64 start, u64 end);
int hpsb_register_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- struct hpsb_address_ops *ops, u64 start, u64 end);
-
+ struct hpsb_address_ops *ops, u64 start, u64 end);
int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, struct hpsb_host *host,
- u64 start);
+ u64 start);
/*
* Enable or disable receving a certain isochronous channel through the
* iso_receive op.
*/
int hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
- unsigned int channel);
+ unsigned int channel);
void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
- unsigned int channel);
-
+ unsigned int channel);
/* Retrieve a hostinfo pointer bound to this driver/host */
void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
@@ -172,19 +174,24 @@ void *hpsb_create_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
void hpsb_destroy_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host);
/* Set an alternate lookup key for the hostinfo bound to this driver/host */
-void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host, unsigned long key);
+void hpsb_set_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ unsigned long key);
-/* Retrieve the alternate lookup key for the hostinfo bound to this driver/host */
-unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host);
+/* Retrieve the alternate lookup key for the hostinfo bound to this
+ * driver/host */
+unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl,
+ struct hpsb_host *host);
/* Retrieve a hostinfo pointer bound to this driver using its alternate key */
void *hpsb_get_hostinfo_bykey(struct hpsb_highlevel *hl, unsigned long key);
/* Set the hostinfo pointer to something useful. Usually follows a call to
* hpsb_create_hostinfo, where the size is 0. */
-int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host, void *data);
+int hpsb_set_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host,
+ void *data);
/* Retrieve hpsb_host using a highlevel handle and a key */
-struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl, unsigned long key);
+struct hpsb_host *hpsb_get_host_bykey(struct hpsb_highlevel *hl,
+ unsigned long key);
#endif /* IEEE1394_HIGHLEVEL_H */
diff --git a/drivers/ieee1394/hosts.c b/drivers/ieee1394/hosts.c
index 4feead4a35c5..d90a3a1898c0 100644
--- a/drivers/ieee1394/hosts.c
+++ b/drivers/ieee1394/hosts.c
@@ -90,6 +90,16 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
return 0;
}
+/*
+ * The pending_packet_queue is special in that it's processed
+ * from hardirq context too (such as hpsb_bus_reset()). Hence
+ * split the lock class from the usual networking skb-head
+ * lock class by using a separate key for it:
+ */
+static struct lock_class_key pending_packet_queue_key;
+
+static DEFINE_MUTEX(host_num_alloc);
+
/**
* hpsb_alloc_host - allocate a new host controller.
* @drv: the driver that will manage the host controller
@@ -105,16 +115,6 @@ static int alloc_hostnum_cb(struct hpsb_host *host, void *__data)
* Return Value: a pointer to the &hpsb_host if successful, %NULL if
* no memory was available.
*/
-static DEFINE_MUTEX(host_num_alloc);
-
-/*
- * The pending_packet_queue is special in that it's processed
- * from hardirq context too (such as hpsb_bus_reset()). Hence
- * split the lock class from the usual networking skb-head
- * lock class by using a separate key for it:
- */
-static struct lock_class_key pending_packet_queue_key;
-
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
struct device *dev)
{
@@ -143,9 +143,6 @@ struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
for (i = 2; i < 16; i++)
h->csr.gen_timestamp[i] = jiffies - 60 * HZ;
- for (i = 0; i < ARRAY_SIZE(h->tpool); i++)
- HPSB_TPOOL_INIT(&h->tpool[i]);
-
atomic_set(&h->generation, 0);
INIT_WORK(&h->delayed_reset, delayed_reset_bus, h);
diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h
index 9ad4b2463077..bc6dbfadb891 100644
--- a/drivers/ieee1394/hosts.h
+++ b/drivers/ieee1394/hosts.h
@@ -2,17 +2,19 @@
#define _IEEE1394_HOSTS_H
#include <linux/device.h>
-#include <linux/wait.h>
#include <linux/list.h>
-#include <linux/timer.h>
#include <linux/skbuff.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
-#include <asm/semaphore.h>
+struct pci_dev;
+struct module;
#include "ieee1394_types.h"
#include "csr.h"
-
struct hpsb_packet;
struct hpsb_iso;
@@ -33,7 +35,6 @@ struct hpsb_host {
int node_count; /* number of identified nodes on this bus */
int selfid_count; /* total number of SelfIDs received */
int nodes_active; /* number of nodes with active link layer */
- u8 speed[ALL_NODES]; /* speed between each node and local node */
nodeid_t node_id; /* node ID of this host */
nodeid_t irm_id; /* ID of this bus' isochronous resource manager */
@@ -53,31 +54,29 @@ struct hpsb_host {
int reset_retries;
quadlet_t *topology_map;
u8 *speed_map;
- struct csr_control csr;
-
- /* Per node tlabel pool allocation */
- struct hpsb_tlabel_pool tpool[ALL_NODES];
+ int id;
struct hpsb_host_driver *driver;
-
struct pci_dev *pdev;
-
- int id;
-
struct device device;
struct class_device class_dev;
int update_config_rom;
struct work_struct delayed_reset;
-
unsigned int config_roms;
struct list_head addr_space;
u64 low_addr_space; /* upper bound of physical DMA area */
u64 middle_addr_space; /* upper bound of posted write area */
-};
+ u8 speed[ALL_NODES]; /* speed between each node and local node */
+
+ /* per node tlabel allocation */
+ u8 next_tl[ALL_NODES];
+ struct { DECLARE_BITMAP(map, 64); } tl_pool[ALL_NODES];
+ struct csr_control csr;
+};
enum devctl_cmd {
/* Host is requested to reset its bus and cancel all outstanding async
@@ -112,7 +111,7 @@ enum devctl_cmd {
enum isoctl_cmd {
/* rawiso API - see iso.h for the meanings of these commands
- (they correspond exactly to the hpsb_iso_* API functions)
+ * (they correspond exactly to the hpsb_iso_* API functions)
* INIT = allocate resources
* START = begin transmission/reception
* STOP = halt transmission/reception
@@ -160,7 +159,8 @@ struct hpsb_host_driver {
/* The hardware driver may optionally support a function that is used
* to set the hardware ConfigROM if the hardware supports handling
* reads to the ConfigROM on its own. */
- void (*set_hw_config_rom) (struct hpsb_host *host, quadlet_t *config_rom);
+ void (*set_hw_config_rom)(struct hpsb_host *host,
+ quadlet_t *config_rom);
/* This function shall implement packet transmission based on
* packet->type. It shall CRC both parts of the packet (unless
@@ -170,20 +170,21 @@ struct hpsb_host_driver {
* called. Return 0 on success, negative errno on failure.
* NOTE: The function must be callable in interrupt context.
*/
- int (*transmit_packet) (struct hpsb_host *host,
- struct hpsb_packet *packet);
+ int (*transmit_packet)(struct hpsb_host *host,
+ struct hpsb_packet *packet);
/* This function requests miscellanous services from the driver, see
* above for command codes and expected actions. Return -1 for unknown
* command, though that should never happen.
*/
- int (*devctl) (struct hpsb_host *host, enum devctl_cmd command, int arg);
+ int (*devctl)(struct hpsb_host *host, enum devctl_cmd command, int arg);
/* ISO transmission/reception functions. Return 0 on success, -1
* (or -EXXX errno code) on failure. If the low-level driver does not
* support the new ISO API, set isoctl to NULL.
*/
- int (*isoctl) (struct hpsb_iso *iso, enum isoctl_cmd command, unsigned long arg);
+ int (*isoctl)(struct hpsb_iso *iso, enum isoctl_cmd command,
+ unsigned long arg);
/* This function is mainly to redirect local CSR reads/locks to the iso
* management registers (bus manager id, bandwidth available, channels
@@ -196,19 +197,11 @@ struct hpsb_host_driver {
quadlet_t data, quadlet_t compare);
};
-
struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra,
struct device *dev);
int hpsb_add_host(struct hpsb_host *host);
void hpsb_remove_host(struct hpsb_host *h);
-/* The following 2 functions are deprecated and will be removed when the
- * raw1394/libraw1394 update is complete. */
-int hpsb_update_config_rom(struct hpsb_host *host,
- const quadlet_t *new_rom, size_t size, unsigned char rom_version);
-int hpsb_get_config_rom(struct hpsb_host *host, quadlet_t *buffer,
- size_t buffersize, size_t *rom_size, unsigned char *rom_version);
-
/* Updates the configuration rom image of a host. rom_version must be the
* current version, otherwise it will fail with return value -1. If this
* host does not support config-rom-update, it will return -EINVAL.
diff --git a/drivers/ieee1394/ieee1394-ioctl.h b/drivers/ieee1394/ieee1394-ioctl.h
index 156703986348..8f207508ed1d 100644
--- a/drivers/ieee1394/ieee1394-ioctl.h
+++ b/drivers/ieee1394/ieee1394-ioctl.h
@@ -1,5 +1,7 @@
-/* Base file for all ieee1394 ioctl's. Linux-1394 has allocated base '#'
- * with a range of 0x00-0x3f. */
+/*
+ * Base file for all ieee1394 ioctl's.
+ * Linux-1394 has allocated base '#' with a range of 0x00-0x3f.
+ */
#ifndef __IEEE1394_IOCTL_H
#define __IEEE1394_IOCTL_H
@@ -96,8 +98,7 @@
_IOW ('#', 0x27, struct raw1394_iso_packets)
#define RAW1394_IOC_ISO_XMIT_SYNC \
_IO ('#', 0x28)
-#define RAW1394_IOC_ISO_RECV_FLUSH \
+#define RAW1394_IOC_ISO_RECV_FLUSH \
_IO ('#', 0x29)
-
#endif /* __IEEE1394_IOCTL_H */
diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h
index 936d776de00a..40492074c013 100644
--- a/drivers/ieee1394/ieee1394.h
+++ b/drivers/ieee1394/ieee1394.h
@@ -5,77 +5,78 @@
#ifndef _IEEE1394_IEEE1394_H
#define _IEEE1394_IEEE1394_H
-#define TCODE_WRITEQ 0x0
-#define TCODE_WRITEB 0x1
-#define TCODE_WRITE_RESPONSE 0x2
-#define TCODE_READQ 0x4
-#define TCODE_READB 0x5
-#define TCODE_READQ_RESPONSE 0x6
-#define TCODE_READB_RESPONSE 0x7
-#define TCODE_CYCLE_START 0x8
-#define TCODE_LOCK_REQUEST 0x9
-#define TCODE_ISO_DATA 0xa
-#define TCODE_STREAM_DATA 0xa
-#define TCODE_LOCK_RESPONSE 0xb
-
-#define RCODE_COMPLETE 0x0
-#define RCODE_CONFLICT_ERROR 0x4
-#define RCODE_DATA_ERROR 0x5
-#define RCODE_TYPE_ERROR 0x6
-#define RCODE_ADDRESS_ERROR 0x7
-
-#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 ACK_COMPLETE 0x1
-#define ACK_PENDING 0x2
-#define ACK_BUSY_X 0x4
-#define ACK_BUSY_A 0x5
-#define ACK_BUSY_B 0x6
-#define ACK_TARDY 0xb
-#define ACK_CONFLICT_ERROR 0xc
-#define ACK_DATA_ERROR 0xd
-#define ACK_TYPE_ERROR 0xe
-#define ACK_ADDRESS_ERROR 0xf
+#define TCODE_WRITEQ 0x0
+#define TCODE_WRITEB 0x1
+#define TCODE_WRITE_RESPONSE 0x2
+#define TCODE_READQ 0x4
+#define TCODE_READB 0x5
+#define TCODE_READQ_RESPONSE 0x6
+#define TCODE_READB_RESPONSE 0x7
+#define TCODE_CYCLE_START 0x8
+#define TCODE_LOCK_REQUEST 0x9
+#define TCODE_ISO_DATA 0xa
+#define TCODE_STREAM_DATA 0xa
+#define TCODE_LOCK_RESPONSE 0xb
+
+#define RCODE_COMPLETE 0x0
+#define RCODE_CONFLICT_ERROR 0x4
+#define RCODE_DATA_ERROR 0x5
+#define RCODE_TYPE_ERROR 0x6
+#define RCODE_ADDRESS_ERROR 0x7
+
+#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 ACK_COMPLETE 0x1
+#define ACK_PENDING 0x2
+#define ACK_BUSY_X 0x4
+#define ACK_BUSY_A 0x5
+#define ACK_BUSY_B 0x6
+#define ACK_TARDY 0xb
+#define ACK_CONFLICT_ERROR 0xc
+#define ACK_DATA_ERROR 0xd
+#define ACK_TYPE_ERROR 0xe
+#define ACK_ADDRESS_ERROR 0xf
/* Non-standard "ACK codes" for internal use */
-#define ACKX_NONE (-1)
-#define ACKX_SEND_ERROR (-2)
-#define ACKX_ABORTED (-3)
-#define ACKX_TIMEOUT (-4)
-
-
-#define IEEE1394_SPEED_100 0x00
-#define IEEE1394_SPEED_200 0x01
-#define IEEE1394_SPEED_400 0x02
-#define IEEE1394_SPEED_800 0x03
-#define IEEE1394_SPEED_1600 0x04
-#define IEEE1394_SPEED_3200 0x05
+#define ACKX_NONE (-1)
+#define ACKX_SEND_ERROR (-2)
+#define ACKX_ABORTED (-3)
+#define ACKX_TIMEOUT (-4)
+
+#define IEEE1394_SPEED_100 0x00
+#define IEEE1394_SPEED_200 0x01
+#define IEEE1394_SPEED_400 0x02
+#define IEEE1394_SPEED_800 0x03
+#define IEEE1394_SPEED_1600 0x04
+#define IEEE1394_SPEED_3200 0x05
+
/* The current highest tested speed supported by the subsystem */
-#define IEEE1394_SPEED_MAX IEEE1394_SPEED_800
+#define IEEE1394_SPEED_MAX IEEE1394_SPEED_800
/* Maps speed values above to a string representation */
extern const char *hpsb_speedto_str[];
-
/* 1394a cable PHY packets */
-#define SELFID_PWRCL_NO_POWER 0x0
-#define SELFID_PWRCL_PROVIDE_15W 0x1
-#define SELFID_PWRCL_PROVIDE_30W 0x2
-#define SELFID_PWRCL_PROVIDE_45W 0x3
-#define SELFID_PWRCL_USE_1W 0x4
-#define SELFID_PWRCL_USE_3W 0x5
-#define SELFID_PWRCL_USE_6W 0x6
-#define SELFID_PWRCL_USE_10W 0x7
-
-#define SELFID_PORT_CHILD 0x3
-#define SELFID_PORT_PARENT 0x2
-#define SELFID_PORT_NCONN 0x1
-#define SELFID_PORT_NONE 0x0
+#define SELFID_PWRCL_NO_POWER 0x0
+#define SELFID_PWRCL_PROVIDE_15W 0x1
+#define SELFID_PWRCL_PROVIDE_30W 0x2
+#define SELFID_PWRCL_PROVIDE_45W 0x3
+#define SELFID_PWRCL_USE_1W 0x4
+#define SELFID_PWRCL_USE_3W 0x5
+#define SELFID_PWRCL_USE_6W 0x6
+#define SELFID_PWRCL_USE_10W 0x7
+
+#define SELFID_PORT_CHILD 0x3
+#define SELFID_PORT_PARENT 0x2
+#define SELFID_PORT_NCONN 0x1
+#define SELFID_PORT_NONE 0x0
+
+#define SELFID_SPEED_UNKNOWN 0x3 /* 1394b PHY */
#define PHYPACKET_LINKON 0x40000000
#define PHYPACKET_PHYCONFIG_R 0x00800000
@@ -91,76 +92,76 @@ extern const char *hpsb_speedto_str[];
#define EXTPHYPACKET_TYPEMASK 0xC0FC0000
-#define PHYPACKET_PORT_SHIFT 24
-#define PHYPACKET_GAPCOUNT_SHIFT 16
+#define PHYPACKET_PORT_SHIFT 24
+#define PHYPACKET_GAPCOUNT_SHIFT 16
/* 1394a PHY register map bitmasks */
-#define PHY_00_PHYSICAL_ID 0xFC
-#define PHY_00_R 0x02 /* Root */
-#define PHY_00_PS 0x01 /* Power Status*/
-#define PHY_01_RHB 0x80 /* Root Hold-Off */
-#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
-#define PHY_01_GAP_COUNT 0x3F
-#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
-#define PHY_02_TOTAL_PORTS 0x1F
-#define PHY_03_MAX_SPEED 0xE0
-#define PHY_03_DELAY 0x0F
-#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
-#define PHY_04_CONTENDER 0x40
-#define PHY_04_JITTER 0x38
-#define PHY_04_PWR_CLASS 0x07 /* Power Class */
-#define PHY_05_WATCHDOG 0x80
-#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
-#define PHY_05_LOOP 0x20 /* Loop Detect */
-#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
-#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
-#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
-#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
-#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
+#define PHY_00_PHYSICAL_ID 0xFC
+#define PHY_00_R 0x02 /* Root */
+#define PHY_00_PS 0x01 /* Power Status*/
+#define PHY_01_RHB 0x80 /* Root Hold-Off */
+#define PHY_01_IBR 0x80 /* Initiate Bus Reset */
+#define PHY_01_GAP_COUNT 0x3F
+#define PHY_02_EXTENDED 0xE0 /* 0x7 for 1394a-compliant PHY */
+#define PHY_02_TOTAL_PORTS 0x1F
+#define PHY_03_MAX_SPEED 0xE0
+#define PHY_03_DELAY 0x0F
+#define PHY_04_LCTRL 0x80 /* Link Active Report Control */
+#define PHY_04_CONTENDER 0x40
+#define PHY_04_JITTER 0x38
+#define PHY_04_PWR_CLASS 0x07 /* Power Class */
+#define PHY_05_WATCHDOG 0x80
+#define PHY_05_ISBR 0x40 /* Initiate Short Bus Reset */
+#define PHY_05_LOOP 0x20 /* Loop Detect */
+#define PHY_05_PWR_FAIL 0x10 /* Cable Power Failure Detect */
+#define PHY_05_TIMEOUT 0x08 /* Arbitration State Machine Timeout */
+#define PHY_05_PORT_EVENT 0x04 /* Port Event Detect */
+#define PHY_05_ENAB_ACCEL 0x02 /* Enable Arbitration Acceleration */
+#define PHY_05_ENAB_MULTI 0x01 /* Ena. Multispeed Packet Concatenation */
#include <asm/byteorder.h>
#ifdef __BIG_ENDIAN_BITFIELD
struct selfid {
- u32 packet_identifier:2; /* always binary 10 */
- u32 phy_id:6;
- /* byte */
- u32 extended:1; /* if true is struct ext_selfid */
- u32 link_active:1;
- u32 gap_count:6;
- /* byte */
- u32 speed:2;
- u32 phy_delay:2;
- u32 contender:1;
- u32 power_class:3;
- /* byte */
- u32 port0:2;
- u32 port1:2;
- u32 port2:2;
- u32 initiated_reset:1;
- u32 more_packets:1;
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if true is struct ext_selfid */
+ u32 link_active:1;
+ u32 gap_count:6;
+ /* byte */
+ u32 speed:2;
+ u32 phy_delay:2;
+ u32 contender:1;
+ u32 power_class:3;
+ /* byte */
+ u32 port0:2;
+ u32 port1:2;
+ u32 port2:2;
+ u32 initiated_reset:1;
+ u32 more_packets:1;
} __attribute__((packed));
struct ext_selfid {
- u32 packet_identifier:2; /* always binary 10 */
- u32 phy_id:6;
- /* byte */
- u32 extended:1; /* if false is struct selfid */
- u32 seq_nr:3;
- u32 reserved:2;
- u32 porta:2;
- /* byte */
- u32 portb:2;
- u32 portc:2;
- u32 portd:2;
- u32 porte:2;
- /* byte */
- u32 portf:2;
- u32 portg:2;
- u32 porth:2;
- u32 reserved2:1;
- u32 more_packets:1;
+ u32 packet_identifier:2; /* always binary 10 */
+ u32 phy_id:6;
+ /* byte */
+ u32 extended:1; /* if false is struct selfid */
+ u32 seq_nr:3;
+ u32 reserved:2;
+ u32 porta:2;
+ /* byte */
+ u32 portb:2;
+ u32 portc:2;
+ u32 portd:2;
+ u32 porte:2;
+ /* byte */
+ u32 portf:2;
+ u32 portg:2;
+ u32 porth:2;
+ u32 reserved2:1;
+ u32 more_packets:1;
} __attribute__((packed));
#elif defined __LITTLE_ENDIAN_BITFIELD /* __BIG_ENDIAN_BITFIELD */
@@ -171,49 +172,48 @@ struct ext_selfid {
*/
struct selfid {
- u32 phy_id:6;
- u32 packet_identifier:2; /* always binary 10 */
- /* byte */
- u32 gap_count:6;
- u32 link_active:1;
- u32 extended:1; /* if true is struct ext_selfid */
- /* byte */
- u32 power_class:3;
- u32 contender:1;
- u32 phy_delay:2;
- u32 speed:2;
- /* byte */
- u32 more_packets:1;
- u32 initiated_reset:1;
- u32 port2:2;
- u32 port1:2;
- u32 port0:2;
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 gap_count:6;
+ u32 link_active:1;
+ u32 extended:1; /* if true is struct ext_selfid */
+ /* byte */
+ u32 power_class:3;
+ u32 contender:1;
+ u32 phy_delay:2;
+ u32 speed:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 initiated_reset:1;
+ u32 port2:2;
+ u32 port1:2;
+ u32 port0:2;
} __attribute__((packed));
struct ext_selfid {
- u32 phy_id:6;
- u32 packet_identifier:2; /* always binary 10 */
- /* byte */
- u32 porta:2;
- u32 reserved:2;
- u32 seq_nr:3;
- u32 extended:1; /* if false is struct selfid */
- /* byte */
- u32 porte:2;
- u32 portd:2;
- u32 portc:2;
- u32 portb:2;
- /* byte */
- u32 more_packets:1;
- u32 reserved2:1;
- u32 porth:2;
- u32 portg:2;
- u32 portf:2;
+ u32 phy_id:6;
+ u32 packet_identifier:2; /* always binary 10 */
+ /* byte */
+ u32 porta:2;
+ u32 reserved:2;
+ u32 seq_nr:3;
+ u32 extended:1; /* if false is struct selfid */
+ /* byte */
+ u32 porte:2;
+ u32 portd:2;
+ u32 portc:2;
+ u32 portb:2;
+ /* byte */
+ u32 more_packets:1;
+ u32 reserved2:1;
+ u32 porth:2;
+ u32 portg:2;
+ u32 portf:2;
} __attribute__((packed));
#else
#error What? PDP endian?
#endif /* __BIG_ENDIAN_BITFIELD */
-
#endif /* _IEEE1394_IEEE1394_H */
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index f43739c5cab2..5fccf9f7a1d2 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -35,7 +35,6 @@
#include <linux/kthread.h>
#include <asm/byteorder.h>
-#include <asm/semaphore.h>
#include "ieee1394_types.h"
#include "ieee1394.h"
@@ -86,7 +85,7 @@ static void dump_packet(const char *text, quadlet_t *data, int size, int speed)
printk("\n");
}
#else
-#define dump_packet(a,b,c,d)
+#define dump_packet(a,b,c,d) do {} while (0)
#endif
static void abort_requests(struct hpsb_host *host);
@@ -355,10 +354,12 @@ static void build_speed_map(struct hpsb_host *host, int nodecount)
}
}
+#if SELFID_SPEED_UNKNOWN != IEEE1394_SPEED_MAX
/* assume maximum speed for 1394b PHYs, nodemgr will correct it */
for (n = 0; n < nodecount; n++)
- if (speedcap[n] == 3)
+ if (speedcap[n] == SELFID_SPEED_UNKNOWN)
speedcap[n] = IEEE1394_SPEED_MAX;
+#endif
}
@@ -1169,7 +1170,7 @@ static void __exit ieee1394_cleanup(void)
unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
}
-module_init(ieee1394_init);
+fs_initcall(ieee1394_init); /* same as ohci1394 */
module_exit(ieee1394_cleanup);
/* Exported symbols */
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index 0ecbf335c64f..af4a78a8ef3b 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -1,12 +1,15 @@
-
#ifndef _IEEE1394_CORE_H
#define _IEEE1394_CORE_H
-#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/types.h>
#include <asm/atomic.h>
-#include <asm/semaphore.h>
-#include "hosts.h"
+#include "hosts.h"
+#include "ieee1394_types.h"
struct hpsb_packet {
/* This struct is basically read-only for hosts with the exception of
@@ -58,7 +61,6 @@ struct hpsb_packet {
size_t header_size;
size_t data_size;
-
struct hpsb_host *host;
unsigned int generation;
@@ -80,7 +82,7 @@ struct hpsb_packet {
/* Set a task for when a packet completes */
void hpsb_set_packet_complete_task(struct hpsb_packet *packet,
- void (*routine)(void *), void *data);
+ void (*routine)(void *), void *data);
static inline struct hpsb_packet *driver_packet(struct list_head *l)
{
@@ -92,7 +94,6 @@ void abort_timedouts(unsigned long __opaque);
struct hpsb_packet *hpsb_alloc_packet(size_t data_size);
void hpsb_free_packet(struct hpsb_packet *packet);
-
/*
* Generation counter for the complete 1394 subsystem. Generation gets
* incremented on every change in the subsystem (e.g. bus reset).
@@ -204,10 +205,14 @@ void hpsb_packet_received(struct hpsb_host *host, quadlet_t *data, size_t size,
#define IEEE1394_MINOR_BLOCK_EXPERIMENTAL 15
#define IEEE1394_CORE_DEV MKDEV(IEEE1394_MAJOR, 0)
-#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16)
-#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
-#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_DV1394 * 16)
-#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
+#define IEEE1394_RAW1394_DEV MKDEV(IEEE1394_MAJOR, \
+ IEEE1394_MINOR_BLOCK_RAW1394 * 16)
+#define IEEE1394_VIDEO1394_DEV MKDEV(IEEE1394_MAJOR, \
+ IEEE1394_MINOR_BLOCK_VIDEO1394 * 16)
+#define IEEE1394_DV1394_DEV MKDEV(IEEE1394_MAJOR, \
+ IEEE1394_MINOR_BLOCK_DV1394 * 16)
+#define IEEE1394_EXPERIMENTAL_DEV MKDEV(IEEE1394_MAJOR, \
+ IEEE1394_MINOR_BLOCK_EXPERIMENTAL * 16)
/* return the index (within a minor number block) of a file */
static inline unsigned char ieee1394_file_to_instance(struct file *file)
@@ -223,4 +228,3 @@ extern struct class hpsb_host_class;
extern struct class *hpsb_protocol_class;
#endif /* _IEEE1394_CORE_H */
-
diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h
index 5be70d31b007..dd5500ed8322 100644
--- a/drivers/ieee1394/ieee1394_hotplug.h
+++ b/drivers/ieee1394/ieee1394_hotplug.h
@@ -1,33 +1,19 @@
#ifndef _IEEE1394_HOTPLUG_H
#define _IEEE1394_HOTPLUG_H
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mod_devicetable.h>
-
/* Unit spec id and sw version entry for some protocols */
#define AVC_UNIT_SPEC_ID_ENTRY 0x0000A02D
#define AVC_SW_VERSION_ENTRY 0x00010001
#define CAMERA_UNIT_SPEC_ID_ENTRY 0x0000A02D
#define CAMERA_SW_VERSION_ENTRY 0x00000100
-/* Check to make sure this all isn't already defined */
-#ifndef IEEE1394_MATCH_VENDOR_ID
-
-#define IEEE1394_MATCH_VENDOR_ID 0x0001
-#define IEEE1394_MATCH_MODEL_ID 0x0002
-#define IEEE1394_MATCH_SPECIFIER_ID 0x0004
-#define IEEE1394_MATCH_VERSION 0x0008
-
-struct ieee1394_device_id {
- u32 match_flags;
- u32 vendor_id;
- u32 model_id;
- u32 specifier_id;
- u32 version;
- void *driver_data;
-};
-
-#endif
+/* /include/linux/mod_devicetable.h defines:
+ * IEEE1394_MATCH_VENDOR_ID
+ * IEEE1394_MATCH_MODEL_ID
+ * IEEE1394_MATCH_SPECIFIER_ID
+ * IEEE1394_MATCH_VERSION
+ * struct ieee1394_device_id
+ */
+#include <linux/mod_devicetable.h>
#endif /* _IEEE1394_HOTPLUG_H */
diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c
index a114b91d606d..0833fc9f50c4 100644
--- a/drivers/ieee1394/ieee1394_transactions.c
+++ b/drivers/ieee1394/ieee1394_transactions.c
@@ -9,19 +9,17 @@
* directory of the kernel sources for details.
*/
-#include <linux/sched.h>
#include <linux/bitops.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+#include <asm/bug.h>
#include <asm/errno.h>
#include "ieee1394.h"
#include "ieee1394_types.h"
#include "hosts.h"
#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "nodemgr.h"
#include "ieee1394_transactions.h"
#define PREP_ASYNC_HEAD_ADDRESS(tc) \
@@ -31,6 +29,13 @@
packet->header[1] = (packet->host->node_id << 16) | (addr >> 32); \
packet->header[2] = addr & 0xffffffff
+#ifndef HPSB_DEBUG_TLABELS
+static
+#endif
+spinlock_t hpsb_tlabel_lock = SPIN_LOCK_UNLOCKED;
+
+static DECLARE_WAIT_QUEUE_HEAD(tlabel_wq);
+
static void fill_async_readquad(struct hpsb_packet *packet, u64 addr)
{
PREP_ASYNC_HEAD_ADDRESS(TCODE_READQ);
@@ -114,9 +119,41 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
packet->tcode = TCODE_ISO_DATA;
}
+/* same as hpsb_get_tlabel, except that it returns immediately */
+static int hpsb_get_tlabel_atomic(struct hpsb_packet *packet)
+{
+ unsigned long flags, *tp;
+ u8 *next;
+ int tlabel, n = NODEID_TO_NODE(packet->node_id);
+
+ /* Broadcast transactions are complete once the request has been sent.
+ * Use the same transaction label for all broadcast transactions. */
+ if (unlikely(n == ALL_NODES)) {
+ packet->tlabel = 0;
+ return 0;
+ }
+ tp = packet->host->tl_pool[n].map;
+ next = &packet->host->next_tl[n];
+
+ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
+ tlabel = find_next_zero_bit(tp, 64, *next);
+ if (tlabel > 63)
+ tlabel = find_first_zero_bit(tp, 64);
+ if (tlabel > 63) {
+ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+ return -EAGAIN;
+ }
+ __set_bit(tlabel, tp);
+ *next = (tlabel + 1) & 63;
+ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+
+ packet->tlabel = tlabel;
+ return 0;
+}
+
/**
* hpsb_get_tlabel - allocate a transaction label
- * @packet: the packet who's tlabel/tpool we set
+ * @packet: the packet whose tlabel and tl_pool we set
*
* Every asynchronous transaction on the 1394 bus needs a transaction
* label to match the response to the request. This label has to be
@@ -130,42 +167,25 @@ static void fill_async_stream_packet(struct hpsb_packet *packet, int length,
* Return value: Zero on success, otherwise non-zero. A non-zero return
* generally means there are no available tlabels. If this is called out
* of interrupt or atomic context, then it will sleep until can return a
- * tlabel.
+ * tlabel or a signal is received.
*/
int hpsb_get_tlabel(struct hpsb_packet *packet)
{
- unsigned long flags;
- struct hpsb_tlabel_pool *tp;
- int n = NODEID_TO_NODE(packet->node_id);
-
- if (unlikely(n == ALL_NODES))
- return 0;
- tp = &packet->host->tpool[n];
-
- if (irqs_disabled() || in_atomic()) {
- if (down_trylock(&tp->count))
- return 1;
- } else {
- down(&tp->count);
- }
-
- spin_lock_irqsave(&tp->lock, flags);
-
- packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next);
- if (packet->tlabel > 63)
- packet->tlabel = find_first_zero_bit(tp->pool, 64);
- tp->next = (packet->tlabel + 1) % 64;
- /* Should _never_ happen */
- BUG_ON(test_and_set_bit(packet->tlabel, tp->pool));
- tp->allocations++;
- spin_unlock_irqrestore(&tp->lock, flags);
-
- return 0;
+ if (irqs_disabled() || in_atomic())
+ return hpsb_get_tlabel_atomic(packet);
+
+ /* NB: The macro wait_event_interruptible() is called with a condition
+ * argument with side effect. This is only possible because the side
+ * effect does not occur until the condition became true, and
+ * wait_event_interruptible() won't evaluate the condition again after
+ * that. */
+ return wait_event_interruptible(tlabel_wq,
+ !hpsb_get_tlabel_atomic(packet));
}
/**
* hpsb_free_tlabel - free an allocated transaction label
- * @packet: packet whos tlabel/tpool needs to be cleared
+ * @packet: packet whose tlabel and tl_pool needs to be cleared
*
* Frees the transaction label allocated with hpsb_get_tlabel(). The
* tlabel has to be freed after the transaction is complete (i.e. response
@@ -176,21 +196,20 @@ int hpsb_get_tlabel(struct hpsb_packet *packet)
*/
void hpsb_free_tlabel(struct hpsb_packet *packet)
{
- unsigned long flags;
- struct hpsb_tlabel_pool *tp;
- int n = NODEID_TO_NODE(packet->node_id);
+ unsigned long flags, *tp;
+ int tlabel, n = NODEID_TO_NODE(packet->node_id);
if (unlikely(n == ALL_NODES))
return;
- tp = &packet->host->tpool[n];
+ tp = packet->host->tl_pool[n].map;
+ tlabel = packet->tlabel;
+ BUG_ON(tlabel > 63 || tlabel < 0);
- BUG_ON(packet->tlabel > 63 || packet->tlabel < 0);
+ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
+ BUG_ON(!__test_and_clear_bit(tlabel, tp));
+ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
- spin_lock_irqsave(&tp->lock, flags);
- BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool));
- spin_unlock_irqrestore(&tp->lock, flags);
-
- up(&tp->count);
+ wake_up_interruptible(&tlabel_wq);
}
int hpsb_packet_success(struct hpsb_packet *packet)
@@ -214,7 +233,7 @@ int hpsb_packet_success(struct hpsb_packet *packet)
packet->node_id);
return -EAGAIN;
}
- HPSB_PANIC("reached unreachable code 1 in %s", __FUNCTION__);
+ BUG();
case ACK_BUSY_X:
case ACK_BUSY_A:
@@ -261,8 +280,7 @@ int hpsb_packet_success(struct hpsb_packet *packet)
packet->ack_code, packet->node_id, packet->tcode);
return -EAGAIN;
}
-
- HPSB_PANIC("reached unreachable code 2 in %s", __FUNCTION__);
+ BUG();
}
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
diff --git a/drivers/ieee1394/ieee1394_transactions.h b/drivers/ieee1394/ieee1394_transactions.h
index 45ba784fe6da..c1369c41469b 100644
--- a/drivers/ieee1394/ieee1394_transactions.h
+++ b/drivers/ieee1394/ieee1394_transactions.h
@@ -1,32 +1,32 @@
#ifndef _IEEE1394_TRANSACTIONS_H
#define _IEEE1394_TRANSACTIONS_H
-#include "ieee1394_core.h"
+#include <linux/types.h>
+#include "ieee1394_types.h"
+
+struct hpsb_packet;
+struct hpsb_host;
-/*
- * Get and free transaction labels.
- */
int hpsb_get_tlabel(struct hpsb_packet *packet);
void hpsb_free_tlabel(struct hpsb_packet *packet);
-
struct hpsb_packet *hpsb_make_readpacket(struct hpsb_host *host, nodeid_t node,
u64 addr, size_t length);
struct hpsb_packet *hpsb_make_lockpacket(struct hpsb_host *host, nodeid_t node,
- u64 addr, int extcode, quadlet_t *data,
+ u64 addr, int extcode, quadlet_t *data,
quadlet_t arg);
-struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host, nodeid_t node,
- u64 addr, int extcode, octlet_t *data,
- octlet_t arg);
-struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host,
- quadlet_t data) ;
-struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host,
- int length, int channel,
- int tag, int sync);
-struct hpsb_packet *hpsb_make_writepacket (struct hpsb_host *host, nodeid_t node,
- u64 addr, quadlet_t *buffer, size_t length);
+struct hpsb_packet *hpsb_make_lock64packet(struct hpsb_host *host,
+ nodeid_t node, u64 addr, int extcode,
+ octlet_t *data, octlet_t arg);
+struct hpsb_packet *hpsb_make_phypacket(struct hpsb_host *host, quadlet_t data);
+struct hpsb_packet *hpsb_make_isopacket(struct hpsb_host *host, int length,
+ int channel, int tag, int sync);
+struct hpsb_packet *hpsb_make_writepacket(struct hpsb_host *host,
+ nodeid_t node, u64 addr,
+ quadlet_t *buffer, size_t length);
struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
- int length, int channel, int tag, int sync);
+ int length, int channel, int tag,
+ int sync);
/*
* hpsb_packet_success - Make sense of the ack and reply codes and
@@ -40,9 +40,8 @@ struct hpsb_packet *hpsb_make_streampacket(struct hpsb_host *host, u8 *buffer,
*/
int hpsb_packet_success(struct hpsb_packet *packet);
-
/*
- * The generic read, write and lock functions. All recognize the local node ID
+ * The generic read and write functions. All recognize the local node ID
* and act accordingly. Read and write automatically use quadlet commands if
* length == 4 and and block commands otherwise (however, they do not yet
* support lengths that are not a multiple of 4). You must explicitly specifiy
@@ -54,4 +53,8 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
u64 addr, quadlet_t *buffer, size_t length);
+#ifdef HPSB_DEBUG_TLABELS
+extern spinlock_t hpsb_tlabel_lock;
+#endif
+
#endif /* _IEEE1394_TRANSACTIONS_H */
diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h
index 3165609ec1ec..9803aaa15be0 100644
--- a/drivers/ieee1394/ieee1394_types.h
+++ b/drivers/ieee1394/ieee1394_types.h
@@ -1,37 +1,11 @@
-
#ifndef _IEEE1394_TYPES_H
#define _IEEE1394_TYPES_H
#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
#include <linux/string.h>
-
-#include <asm/semaphore.h>
+#include <linux/types.h>
#include <asm/byteorder.h>
-
-/* Transaction Label handling */
-struct hpsb_tlabel_pool {
- DECLARE_BITMAP(pool, 64);
- spinlock_t lock;
- u8 next;
- u32 allocations;
- struct semaphore count;
-};
-
-#define HPSB_TPOOL_INIT(_tp) \
-do { \
- bitmap_zero((_tp)->pool, 64); \
- spin_lock_init(&(_tp)->lock); \
- (_tp)->next = 0; \
- (_tp)->allocations = 0; \
- sema_init(&(_tp)->count, 63); \
-} while (0)
-
-
typedef u32 quadlet_t;
typedef u64 octlet_t;
typedef u16 nodeid_t;
@@ -54,46 +28,40 @@ typedef u16 arm_length_t;
#define NODE_BUS_ARGS(__host, __nodeid) \
__host->id, NODEID_TO_NODE(__nodeid), NODEID_TO_BUS(__nodeid)
-#define HPSB_PRINT(level, fmt, args...) printk(level "ieee1394: " fmt "\n" , ## args)
+#define HPSB_PRINT(level, fmt, args...) \
+ printk(level "ieee1394: " fmt "\n" , ## args)
-#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
-#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
-#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
-#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
-#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
+#define HPSB_DEBUG(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
+#define HPSB_INFO(fmt, args...) HPSB_PRINT(KERN_INFO, fmt , ## args)
+#define HPSB_NOTICE(fmt, args...) HPSB_PRINT(KERN_NOTICE, fmt , ## args)
+#define HPSB_WARN(fmt, args...) HPSB_PRINT(KERN_WARNING, fmt , ## args)
+#define HPSB_ERR(fmt, args...) HPSB_PRINT(KERN_ERR, fmt , ## args)
#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
+#define HPSB_VERBOSE(fmt, args...) HPSB_PRINT(KERN_DEBUG, fmt , ## args)
+#define HPSB_DEBUG_TLABELS
#else
-#define HPSB_VERBOSE(fmt, args...)
+#define HPSB_VERBOSE(fmt, args...) do {} while (0)
#endif
-#define HPSB_PANIC(fmt, args...) panic("ieee1394: " fmt "\n" , ## args)
-
-#define HPSB_TRACE() HPSB_PRINT(KERN_INFO, "TRACE - %s, %s(), line %d", __FILE__, __FUNCTION__, __LINE__)
-
-
#ifdef __BIG_ENDIAN
-static __inline__ void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
+static inline void *memcpy_le32(u32 *dest, const u32 *__src, size_t count)
{
- void *tmp = dest;
+ void *tmp = dest;
u32 *src = (u32 *)__src;
- count /= 4;
-
- while (count--) {
- *dest++ = swab32p(src++);
- }
-
- return tmp;
+ count /= 4;
+ while (count--)
+ *dest++ = swab32p(src++);
+ return tmp;
}
#else
static __inline__ void *memcpy_le32(u32 *dest, const u32 *src, size_t count)
{
- return memcpy(dest, src, count);
+ return memcpy(dest, src, count);
}
#endif /* __BIG_ENDIAN */
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
index f26680ebef7c..08bd15d2a7b6 100644
--- a/drivers/ieee1394/iso.c
+++ b/drivers/ieee1394/iso.c
@@ -9,8 +9,11 @@
* directory of the kernel sources for details.
*/
-#include <linux/slab.h>
+#include <linux/pci.h>
#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "hosts.h"
#include "iso.h"
void hpsb_iso_stop(struct hpsb_iso *iso)
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
index 3efc60b33a88..1210a97e8685 100644
--- a/drivers/ieee1394/iso.h
+++ b/drivers/ieee1394/iso.h
@@ -12,33 +12,40 @@
#ifndef IEEE1394_ISO_H
#define IEEE1394_ISO_H
-#include "hosts.h"
+#include <linux/spinlock_types.h>
+#include <asm/atomic.h>
+#include <asm/types.h>
+
#include "dma.h"
-/* high-level ISO interface */
+struct hpsb_host;
-/* This API sends and receives isochronous packets on a large,
- virtually-contiguous kernel memory buffer. The buffer may be mapped
- into a user-space process for zero-copy transmission and reception.
+/* high-level ISO interface */
- There are no explicit boundaries between packets in the buffer. A
- packet may be transmitted or received at any location. However,
- low-level drivers may impose certain restrictions on alignment or
- size of packets. (e.g. in OHCI no packet may cross a page boundary,
- and packets should be quadlet-aligned)
-*/
+/*
+ * This API sends and receives isochronous packets on a large,
+ * virtually-contiguous kernel memory buffer. The buffer may be mapped
+ * into a user-space process for zero-copy transmission and reception.
+ *
+ * There are no explicit boundaries between packets in the buffer. A
+ * packet may be transmitted or received at any location. However,
+ * low-level drivers may impose certain restrictions on alignment or
+ * size of packets. (e.g. in OHCI no packet may cross a page boundary,
+ * and packets should be quadlet-aligned)
+ */
/* Packet descriptor - the API maintains a ring buffer of these packet
- descriptors in kernel memory (hpsb_iso.infos[]). */
-
+ * descriptors in kernel memory (hpsb_iso.infos[]). */
struct hpsb_iso_packet_info {
/* offset of data payload relative to the first byte of the buffer */
__u32 offset;
- /* length of the data payload, in bytes (not including the isochronous header) */
+ /* length of the data payload, in bytes (not including the isochronous
+ * header) */
__u16 len;
- /* (recv only) the cycle number (mod 8000) on which the packet was received */
+ /* (recv only) the cycle number (mod 8000) on which the packet was
+ * received */
__u16 cycle;
/* (recv only) channel on which the packet was received */
@@ -48,12 +55,10 @@ struct hpsb_iso_packet_info {
__u8 tag;
__u8 sy;
- /*
- * length in bytes of the packet including header/trailer.
- * MUST be at structure end, since the first part of this structure is also
- * defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is copied to
- * userspace and is accessed there through libraw1394.
- */
+ /* length in bytes of the packet including header/trailer.
+ * MUST be at structure end, since the first part of this structure is
+ * also defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is
+ * copied to userspace and is accessed there through libraw1394. */
__u16 total_len;
};
@@ -75,8 +80,8 @@ struct hpsb_iso {
void *hostdata;
/* a function to be called (from interrupt context) after
- outgoing packets have been sent, or incoming packets have
- arrived */
+ * outgoing packets have been sent, or incoming packets have
+ * arrived */
void (*callback)(struct hpsb_iso*);
/* wait for buffer space */
@@ -88,7 +93,7 @@ struct hpsb_iso {
/* greatest # of packets between interrupts - controls
- the maximum latency of the buffer */
+ * the maximum latency of the buffer */
int irq_interval;
/* the buffer for packet data payloads */
@@ -112,8 +117,8 @@ struct hpsb_iso {
int pkt_dma;
/* how many packets, starting at first_packet:
- (transmit) are ready to be filled with data
- (receive) contain received data */
+ * (transmit) are ready to be filled with data
+ * (receive) contain received data */
int n_ready_packets;
/* how many times the buffer has overflowed or underflowed */
@@ -134,7 +139,7 @@ struct hpsb_iso {
int start_cycle;
/* cycle at which next packet will be transmitted,
- -1 if not known */
+ * -1 if not known */
int xmit_cycle;
/* ringbuffer of packet descriptors in regular kernel memory
@@ -170,25 +175,30 @@ int hpsb_iso_recv_unlisten_channel(struct hpsb_iso *iso, unsigned char channel);
int hpsb_iso_recv_set_channel_mask(struct hpsb_iso *iso, u64 mask);
/* start/stop DMA */
-int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle, int prebuffer);
-int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle, int tag_mask, int sync);
+int hpsb_iso_xmit_start(struct hpsb_iso *iso, int start_on_cycle,
+ int prebuffer);
+int hpsb_iso_recv_start(struct hpsb_iso *iso, int start_on_cycle,
+ int tag_mask, int sync);
void hpsb_iso_stop(struct hpsb_iso *iso);
/* deallocate buffer and DMA context */
void hpsb_iso_shutdown(struct hpsb_iso *iso);
-/* queue a packet for transmission. 'offset' is relative to the beginning of the
- DMA buffer, where the packet's data payload should already have been placed */
-int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len, u8 tag, u8 sy);
+/* queue a packet for transmission.
+ * 'offset' is relative to the beginning of the DMA buffer, where the packet's
+ * data payload should already have been placed. */
+int hpsb_iso_xmit_queue_packet(struct hpsb_iso *iso, u32 offset, u16 len,
+ u8 tag, u8 sy);
/* wait until all queued packets have been transmitted to the bus */
int hpsb_iso_xmit_sync(struct hpsb_iso *iso);
/* N packets have been read out of the buffer, re-use the buffer space */
-int hpsb_iso_recv_release_packets(struct hpsb_iso *recv, unsigned int n_packets);
+int hpsb_iso_recv_release_packets(struct hpsb_iso *recv,
+ unsigned int n_packets);
/* check for arrival of new packets immediately (even if irq_interval
- has not yet been reached) */
+ * has not yet been reached) */
int hpsb_iso_recv_flush(struct hpsb_iso *iso);
/* returns # of packets ready to send or receive */
@@ -197,14 +207,15 @@ int hpsb_iso_n_ready(struct hpsb_iso *iso);
/* the following are callbacks available to low-level drivers */
/* call after a packet has been transmitted to the bus (interrupt context is OK)
- 'cycle' is the _exact_ cycle the packet was sent on
- 'error' should be non-zero if some sort of error occurred when sending the packet
-*/
+ * 'cycle' is the _exact_ cycle the packet was sent on
+ * 'error' should be non-zero if some sort of error occurred when sending the
+ * packet */
void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
/* call after a packet has been received (interrupt context OK) */
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
- u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy);
+ u16 total_len, u16 cycle, u8 channel, u8 tag,
+ u8 sy);
/* call to wake waiting processes after buffer space has opened up. */
void hpsb_iso_wake(struct hpsb_iso *iso);
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index d541b508a159..8e7b83f84485 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -12,26 +12,23 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/kmod.h>
-#include <linux/completion.h>
#include <linux/delay.h>
-#include <linux/pci.h>
+#include <linux/kthread.h>
#include <linux/moduleparam.h>
#include <asm/atomic.h>
-#include "ieee1394_types.h"
+#include "csr.h"
+#include "highlevel.h"
+#include "hosts.h"
#include "ieee1394.h"
#include "ieee1394_core.h"
-#include "hosts.h"
+#include "ieee1394_hotplug.h"
+#include "ieee1394_types.h"
#include "ieee1394_transactions.h"
-#include "highlevel.h"
-#include "csr.h"
#include "nodemgr.h"
static int ignore_drivers;
-module_param(ignore_drivers, int, 0444);
+module_param(ignore_drivers, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
struct nodemgr_csr_info {
@@ -71,7 +68,7 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr,
u8 i, *speed, old_speed, good_speed;
int ret;
- speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid);
+ speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]);
old_speed = *speed;
good_speed = IEEE1394_SPEED_MAX + 1;
@@ -161,16 +158,12 @@ static struct csr1212_bus_ops nodemgr_csr_ops = {
* but now we are much simpler because of the LDM.
*/
-static DECLARE_MUTEX(nodemgr_serialize);
+static DEFINE_MUTEX(nodemgr_serialize);
struct host_info {
struct hpsb_host *host;
struct list_head list;
- struct completion exited;
- struct semaphore reset_sem;
- int pid;
- char daemon_name[15];
- int kill_me;
+ struct task_struct *thread;
};
static int nodemgr_bus_match(struct device * dev, struct device_driver * drv);
@@ -334,34 +327,44 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribut
static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
-/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically
- * here, therefore displayed values may be occasionally wrong. */
-static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf)
+#ifdef HPSB_DEBUG_TLABELS
+static ssize_t fw_show_ne_tlabels_free(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
- return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64));
-}
-static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
+ unsigned long flags;
+ unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
+ int tf;
+ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
+ tf = 64 - bitmap_weight(tp, 64);
+ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
-static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf)
-{
- struct node_entry *ne = container_of(dev, struct node_entry, device);
- return sprintf(buf, "%u\n", ne->tpool->allocations);
+ return sprintf(buf, "%d\n", tf);
}
-static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL);
+static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
-static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t fw_show_ne_tlabels_mask(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct node_entry *ne = container_of(dev, struct node_entry, device);
+ unsigned long flags;
+ unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map;
+ u64 tm;
+
+ spin_lock_irqsave(&hpsb_tlabel_lock, flags);
#if (BITS_PER_LONG <= 32)
- return sprintf(buf, "0x%08lx%08lx\n", ne->tpool->pool[0], ne->tpool->pool[1]);
+ tm = ((u64)tp[0] << 32) + tp[1];
#else
- return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]);
+ tm = tp[0];
#endif
+ spin_unlock_irqrestore(&hpsb_tlabel_lock, flags);
+
+ return sprintf(buf, "0x%016llx\n", tm);
}
static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL);
+#endif /* HPSB_DEBUG_TLABELS */
static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
@@ -408,26 +411,11 @@ static ssize_t fw_get_destroy_node(struct bus_type *bus, char *buf)
}
static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node);
-static int nodemgr_rescan_bus_thread(void *__unused)
-{
- /* No userlevel access needed */
- daemonize("kfwrescan");
-
- bus_rescan_devices(&ieee1394_bus_type);
-
- return 0;
-}
static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count)
{
- int state = simple_strtoul(buf, NULL, 10);
-
- /* Don't wait for this, or care about errors. Root could do
- * something stupid and spawn this a lot of times, but that's
- * root's fault. */
- if (state == 1)
- kernel_thread(nodemgr_rescan_bus_thread, NULL, CLONE_KERNEL);
-
+ if (simple_strtoul(buf, NULL, 10) == 1)
+ bus_rescan_devices(&ieee1394_bus_type);
return count;
}
static ssize_t fw_get_rescan(struct bus_type *bus, char *buf)
@@ -483,9 +471,10 @@ static struct device_attribute *const fw_ne_attrs[] = {
&dev_attr_ne_vendor_id,
&dev_attr_ne_nodeid,
&dev_attr_bus_options,
+#ifdef HPSB_DEBUG_TLABELS
&dev_attr_tlabels_free,
- &dev_attr_tlabels_allocations,
&dev_attr_tlabels_mask,
+#endif
};
@@ -804,8 +793,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr
if (!ne)
return NULL;
- ne->tpool = &host->tpool[nodeid & NODE_MASK];
-
ne->host = host;
ne->nodeid = nodeid;
ne->generation = generation;
@@ -1251,6 +1238,7 @@ static void nodemgr_node_scan_one(struct host_info *hi,
octlet_t guid;
struct csr1212_csr *csr;
struct nodemgr_csr_info *ci;
+ u8 *speed;
ci = kmalloc(sizeof(*ci), GFP_KERNEL);
if (!ci)
@@ -1259,8 +1247,12 @@ static void nodemgr_node_scan_one(struct host_info *hi,
ci->host = host;
ci->nodeid = nodeid;
ci->generation = generation;
- ci->speed_unverified =
- host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100;
+
+ /* Prepare for speed probe which occurs when reading the ROM */
+ speed = &(host->speed[NODEID_TO_NODE(nodeid)]);
+ if (*speed > host->csr.lnk_spd)
+ *speed = host->csr.lnk_spd;
+ ci->speed_unverified = *speed > IEEE1394_SPEED_100;
/* We need to detect when the ConfigROM's generation has changed,
* so we only update the node's info when it needs to be. */
@@ -1300,8 +1292,6 @@ static void nodemgr_node_scan_one(struct host_info *hi,
nodemgr_create_node(guid, csr, hi, nodeid, generation);
else
nodemgr_update_node(ne, csr, hi, nodeid, generation);
-
- return;
}
@@ -1326,6 +1316,7 @@ static void nodemgr_node_scan(struct host_info *hi, int generation)
}
+/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */
static void nodemgr_suspend_ne(struct node_entry *ne)
{
struct class_device *cdev;
@@ -1361,6 +1352,7 @@ static void nodemgr_resume_ne(struct node_entry *ne)
ne->in_limbo = 0;
device_remove_file(&ne->device, &dev_attr_ne_in_limbo);
+ down_read(&nodemgr_ud_class.subsys.rwsem);
down_read(&ne->device.bus->subsys.rwsem);
list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
ud = container_of(cdev, struct unit_directory, class_dev);
@@ -1372,21 +1364,21 @@ static void nodemgr_resume_ne(struct node_entry *ne)
ud->device.driver->resume(&ud->device);
}
up_read(&ne->device.bus->subsys.rwsem);
+ up_read(&nodemgr_ud_class.subsys.rwsem);
HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]",
NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid);
}
+/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */
static void nodemgr_update_pdrv(struct node_entry *ne)
{
struct unit_directory *ud;
struct hpsb_protocol_driver *pdrv;
- struct class *class = &nodemgr_ud_class;
struct class_device *cdev;
- down_read(&class->subsys.rwsem);
- list_for_each_entry(cdev, &class->children, node) {
+ list_for_each_entry(cdev, &nodemgr_ud_class.children, node) {
ud = container_of(cdev, struct unit_directory, class_dev);
if (ud->ne != ne || !ud->device.driver)
continue;
@@ -1399,7 +1391,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne)
up_write(&ud->device.bus->subsys.rwsem);
}
}
- up_read(&class->subsys.rwsem);
}
@@ -1430,6 +1421,8 @@ static void nodemgr_irm_write_bc(struct node_entry *ne, int generation)
}
+/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader because the
+ * calls to nodemgr_update_pdrv() and nodemgr_suspend_ne() here require it. */
static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation)
{
struct device *dev;
@@ -1492,9 +1485,8 @@ static void nodemgr_node_probe(struct host_info *hi, int generation)
/* If we had a bus reset while we were scanning the bus, it is
* possible that we did not probe all nodes. In that case, we
* skip the clean up for now, since we could remove nodes that
- * were still on the bus. The bus reset increased hi->reset_sem,
- * so there's a bus scan pending which will do the clean up
- * eventually.
+ * were still on the bus. Another bus scan is pending which will
+ * do the clean up eventually.
*
* Now let's tell the bus to rescan our devices. This may seem
* like overhead, but the driver-model core will only scan a
@@ -1622,41 +1614,37 @@ static int nodemgr_host_thread(void *__hi)
{
struct host_info *hi = (struct host_info *)__hi;
struct hpsb_host *host = hi->host;
- int reset_cycles = 0;
-
- /* No userlevel access needed */
- daemonize(hi->daemon_name);
+ unsigned int g, generation = 0;
+ int i, reset_cycles = 0;
/* Setup our device-model entries */
nodemgr_create_host_dev_files(host);
- /* Sit and wait for a signal to probe the nodes on the bus. This
- * happens when we get a bus reset. */
- while (1) {
- unsigned int generation = 0;
- int i;
+ for (;;) {
+ /* Sleep until next bus reset */
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (get_hpsb_generation(host) == generation)
+ schedule();
+ __set_current_state(TASK_RUNNING);
+
+ /* Thread may have been woken up to freeze or to exit */
+ if (try_to_freeze())
+ continue;
+ if (kthread_should_stop())
+ goto exit;
- if (down_interruptible(&hi->reset_sem) ||
- down_interruptible(&nodemgr_serialize)) {
+ if (mutex_lock_interruptible(&nodemgr_serialize)) {
if (try_to_freeze())
continue;
- printk("NodeMgr: received unexpected signal?!\n" );
- break;
- }
-
- if (hi->kill_me) {
- up(&nodemgr_serialize);
- break;
+ goto exit;
}
/* Pause for 1/4 second in 1/16 second intervals,
* to make sure things settle down. */
+ g = get_hpsb_generation(host);
for (i = 0; i < 4 ; i++) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (msleep_interruptible(63)) {
- up(&nodemgr_serialize);
- goto caught_signal;
- }
+ if (msleep_interruptible(63) || kthread_should_stop())
+ goto unlock_exit;
/* Now get the generation in which the node ID's we collect
* are valid. During the bus scan we will use this generation
@@ -1667,20 +1655,14 @@ static int nodemgr_host_thread(void *__hi)
/* If we get a reset before we are done waiting, then
* start the the waiting over again */
- while (!down_trylock(&hi->reset_sem))
- i = 0;
-
- /* Check the kill_me again */
- if (hi->kill_me) {
- up(&nodemgr_serialize);
- goto caught_signal;
- }
+ if (generation != g)
+ g = generation, i = 0;
}
if (!nodemgr_check_irm_capability(host, reset_cycles) ||
!nodemgr_do_irm_duties(host, reset_cycles)) {
reset_cycles++;
- up(&nodemgr_serialize);
+ mutex_unlock(&nodemgr_serialize);
continue;
}
reset_cycles = 0;
@@ -1698,13 +1680,13 @@ static int nodemgr_host_thread(void *__hi)
/* Update some of our sysfs symlinks */
nodemgr_update_host_dev_links(host);
- up(&nodemgr_serialize);
+ mutex_unlock(&nodemgr_serialize);
}
-
-caught_signal:
+unlock_exit:
+ mutex_unlock(&nodemgr_serialize);
+exit:
HPSB_VERBOSE("NodeMgr: Exiting thread");
-
- complete_and_exit(&hi->exited, 0);
+ return 0;
}
int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *))
@@ -1764,41 +1746,27 @@ static void nodemgr_add_host(struct hpsb_host *host)
struct host_info *hi;
hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi));
-
if (!hi) {
- HPSB_ERR ("NodeMgr: out of memory in add host");
+ HPSB_ERR("NodeMgr: out of memory in add host");
return;
}
-
hi->host = host;
- init_completion(&hi->exited);
- sema_init(&hi->reset_sem, 0);
-
- sprintf(hi->daemon_name, "knodemgrd_%d", host->id);
-
- hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_KERNEL);
-
- if (hi->pid < 0) {
- HPSB_ERR ("NodeMgr: failed to start %s thread for %s",
- hi->daemon_name, host->driver->name);
+ hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d",
+ host->id);
+ if (IS_ERR(hi->thread)) {
+ HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id);
hpsb_destroy_hostinfo(&nodemgr_highlevel, host);
- return;
}
-
- return;
}
static void nodemgr_host_reset(struct hpsb_host *host)
{
struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
- if (hi != NULL) {
- HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name);
- up(&hi->reset_sem);
- } else
- HPSB_ERR ("NodeMgr: could not process reset of unused host");
-
- return;
+ if (hi) {
+ HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id);
+ wake_up_process(hi->thread);
+ }
}
static void nodemgr_remove_host(struct hpsb_host *host)
@@ -1806,18 +1774,9 @@ static void nodemgr_remove_host(struct hpsb_host *host)
struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host);
if (hi) {
- if (hi->pid >= 0) {
- hi->kill_me = 1;
- mb();
- up(&hi->reset_sem);
- wait_for_completion(&hi->exited);
- nodemgr_remove_host_dev(&host->device);
- }
- } else
- HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",
- host->driver->name);
-
- return;
+ kthread_stop(hi->thread);
+ nodemgr_remove_host_dev(&host->device);
+ }
}
static struct hpsb_highlevel nodemgr_highlevel = {
diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h
index 0b26616e16c3..0e1e7d930783 100644
--- a/drivers/ieee1394/nodemgr.h
+++ b/drivers/ieee1394/nodemgr.h
@@ -21,9 +21,15 @@
#define _IEEE1394_NODEMGR_H
#include <linux/device.h>
-#include "csr1212.h"
+#include <asm/types.h>
+
#include "ieee1394_core.h"
-#include "ieee1394_hotplug.h"
+#include "ieee1394_types.h"
+
+struct csr1212_csr;
+struct csr1212_keyval;
+struct hpsb_host;
+struct ieee1394_device_id;
/* '1' '3' '9' '4' in ASCII */
#define IEEE1394_BUSID_MAGIC __constant_cpu_to_be32(0x31333934)
@@ -44,7 +50,6 @@ struct bus_options {
u16 max_rec; /* Maximum packet size node can receive */
};
-
#define UNIT_DIRECTORY_VENDOR_ID 0x01
#define UNIT_DIRECTORY_MODEL_ID 0x02
#define UNIT_DIRECTORY_SPECIFIER_ID 0x04
@@ -59,8 +64,8 @@ struct bus_options {
* unit directory for each of these protocols.
*/
struct unit_directory {
- struct node_entry *ne; /* The node which this directory belongs to */
- octlet_t address; /* Address of the unit directory on the node */
+ struct node_entry *ne; /* The node which this directory belongs to */
+ octlet_t address; /* Address of the unit directory on the node */
u8 flags; /* Indicates which entries were read */
quadlet_t vendor_id;
@@ -79,11 +84,10 @@ struct unit_directory {
int length; /* Number of quadlets */
struct device device;
-
struct class_device class_dev;
struct csr1212_keyval *ud_kv;
- u32 lun; /* logical unit number immediate value */
+ u32 lun; /* logical unit number immediate value */
};
struct node_entry {
@@ -103,10 +107,8 @@ struct node_entry {
const char *vendor_oui;
u32 capabilities;
- struct hpsb_tlabel_pool *tpool;
struct device device;
-
struct class_device class_dev;
/* Means this node is not attached anymore */
@@ -153,8 +155,8 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne)
/*
* This will fill in the given, pre-initialised hpsb_packet with the current
* information from the node entry (host, node ID, generation number). It will
- * return false if the node owning the GUID is not accessible (and not modify the
- * hpsb_packet) and return true otherwise.
+ * return false if the node owning the GUID is not accessible (and not modify
+ * the hpsb_packet) and return true otherwise.
*
* Note that packet sending may still fail in hpsb_send_packet if a bus reset
* happens while you are trying to set up the packet (due to obsolete generation
@@ -170,16 +172,13 @@ int hpsb_node_write(struct node_entry *ne, u64 addr,
int hpsb_node_lock(struct node_entry *ne, u64 addr,
int extcode, quadlet_t *data, quadlet_t arg);
-
/* Iterate the hosts, calling a given function with supplied data for each
* host. */
int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *));
-
int init_ieee1394_nodemgr(void);
void cleanup_ieee1394_nodemgr(void);
-
/* The template for a host device */
extern struct device nodemgr_dev_template_host;
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 448df2773377..dea13525df88 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -136,7 +136,7 @@
#define DBGMSG(fmt, args...) \
printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
#else
-#define DBGMSG(fmt, args...)
+#define DBGMSG(fmt, args...) do {} while (0)
#endif
#ifdef CONFIG_IEEE1394_OHCI_DMA_DEBUG
@@ -148,8 +148,8 @@ printk(KERN_INFO "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->
--global_outstanding_dmas, ## args)
static int global_outstanding_dmas = 0;
#else
-#define OHCI_DMA_ALLOC(fmt, args...)
-#define OHCI_DMA_FREE(fmt, args...)
+#define OHCI_DMA_ALLOC(fmt, args...) do {} while (0)
+#define OHCI_DMA_FREE(fmt, args...) do {} while (0)
#endif
/* print general (card independent) information */
@@ -181,36 +181,35 @@ static int alloc_dma_trm_ctx(struct ti_ohci *ohci, struct dma_trm_ctx *d,
static void ohci1394_pci_remove(struct pci_dev *pdev);
#ifndef __LITTLE_ENDIAN
-static unsigned hdr_sizes[] =
-{
+const static size_t hdr_sizes[] = {
3, /* TCODE_WRITEQ */
4, /* TCODE_WRITEB */
3, /* TCODE_WRITE_RESPONSE */
- 0, /* ??? */
+ 0, /* reserved */
3, /* TCODE_READQ */
4, /* TCODE_READB */
3, /* TCODE_READQ_RESPONSE */
4, /* TCODE_READB_RESPONSE */
- 1, /* TCODE_CYCLE_START (???) */
+ 1, /* TCODE_CYCLE_START */
4, /* TCODE_LOCK_REQUEST */
2, /* TCODE_ISO_DATA */
4, /* TCODE_LOCK_RESPONSE */
+ /* rest is reserved or link-internal */
};
-/* Swap headers */
-static inline void packet_swab(quadlet_t *data, int tcode)
+static inline void header_le32_to_cpu(quadlet_t *data, unsigned char tcode)
{
- size_t size = hdr_sizes[tcode];
+ size_t size;
- if (tcode > TCODE_LOCK_RESPONSE || hdr_sizes[tcode] == 0)
+ if (unlikely(tcode >= ARRAY_SIZE(hdr_sizes)))
return;
+ size = hdr_sizes[tcode];
while (size--)
- data[size] = swab32(data[size]);
+ data[size] = le32_to_cpu(data[size]);
}
#else
-/* Don't waste cycles on same sex byte swaps */
-#define packet_swab(w,x)
+#define header_le32_to_cpu(w,x) do {} while (0)
#endif /* !LITTLE_ENDIAN */
/***********************************
@@ -701,7 +700,7 @@ static void insert_packet(struct ti_ohci *ohci,
d->prg_cpu[idx]->data[2] = packet->header[2];
d->prg_cpu[idx]->data[3] = packet->header[3];
}
- packet_swab(d->prg_cpu[idx]->data, packet->tcode);
+ header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
}
if (packet->data_size) { /* block transmit */
@@ -777,7 +776,7 @@ static void insert_packet(struct ti_ohci *ohci,
d->prg_cpu[idx]->data[0] = packet->speed_code<<16 |
(packet->header[0] & 0xFFFF);
d->prg_cpu[idx]->data[1] = packet->header[0] & 0xFFFF0000;
- packet_swab(d->prg_cpu[idx]->data, packet->tcode);
+ header_le32_to_cpu(d->prg_cpu[idx]->data, packet->tcode);
d->prg_cpu[idx]->begin.control =
cpu_to_le32(DMA_CTL_OUTPUT_MORE |
@@ -2302,8 +2301,7 @@ static void ohci_schedule_iso_tasklets(struct ti_ohci *ohci,
spin_unlock_irqrestore(&ohci->iso_tasklet_list_lock, flags);
}
-static irqreturn_t ohci_irq_handler(int irq, void *dev_id,
- struct pt_regs *regs_are_unused)
+static irqreturn_t ohci_irq_handler(int irq, void *dev_id)
{
quadlet_t event, node_id;
struct ti_ohci *ohci = (struct ti_ohci *)dev_id;
@@ -2598,8 +2596,9 @@ static const int TCODE_SIZE[16] = {20, 0, 16, -1, 16, 20, 20, 0,
* Determine the length of a packet in the buffer
* Optimization suggested by Pascal Drolet <pascal.drolet@informission.ca>
*/
-static __inline__ int packet_length(struct dma_rcv_ctx *d, int idx, quadlet_t *buf_ptr,
- int offset, unsigned char tcode, int noswap)
+static inline int packet_length(struct dma_rcv_ctx *d, int idx,
+ quadlet_t *buf_ptr, int offset,
+ unsigned char tcode, int noswap)
{
int length = -1;
@@ -2730,7 +2729,7 @@ static void dma_rcv_tasklet (unsigned long data)
* bus reset. We always ignore it. */
if (tcode != OHCI1394_TCODE_PHY) {
if (!ohci->no_swap_incoming)
- packet_swab(d->spb, tcode);
+ header_le32_to_cpu(d->spb, tcode);
DBGMSG("Packet received from node"
" %d ack=0x%02X spd=%d tcode=0x%X"
" length=%d ctx=%d tlabel=%d",
@@ -2738,7 +2737,7 @@ static void dma_rcv_tasklet (unsigned long data)
(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f,
(cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>21)&0x3,
tcode, length, d->ctx,
- (cond_le32_to_cpu(d->spb[0], ohci->no_swap_incoming)>>10)&0x3f);
+ (d->spb[0]>>10)&0x3f);
ack = (((cond_le32_to_cpu(d->spb[length/4-1], ohci->no_swap_incoming)>>16)&0x1f)
== 0x11) ? 1 : 0;
@@ -3529,9 +3528,10 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
put_device(dev);
}
-
+#ifdef CONFIG_PM
static int ohci1394_pci_resume (struct pci_dev *pdev)
{
+/* PowerMac resume code comes first */
#ifdef CONFIG_PPC_PMAC
if (machine_is(powermac)) {
struct device_node *of_node;
@@ -3543,17 +3543,23 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
}
#endif /* CONFIG_PPC_PMAC */
+ pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
- pci_enable_device(pdev);
-
- return 0;
+ return pci_enable_device(pdev);
}
-
static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
{
- pci_save_state(pdev);
+ int err;
+
+ err = pci_save_state(pdev);
+ if (err)
+ goto out;
+ err = pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ if (err)
+ goto out;
+/* PowerMac suspend code comes last */
#ifdef CONFIG_PPC_PMAC
if (machine_is(powermac)) {
struct device_node *of_node;
@@ -3563,11 +3569,11 @@ static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
if (of_node)
pmac_call_feature(PMAC_FTR_1394_ENABLE, of_node, 0, 0);
}
-#endif
-
- return 0;
+#endif /* CONFIG_PPC_PMAC */
+out:
+ return err;
}
-
+#endif /* CONFIG_PM */
#define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10)
@@ -3590,8 +3596,10 @@ static struct pci_driver ohci1394_pci_driver = {
.id_table = ohci1394_pci_tbl,
.probe = ohci1394_pci_probe,
.remove = ohci1394_pci_remove,
+#ifdef CONFIG_PM
.resume = ohci1394_pci_resume,
.suspend = ohci1394_pci_suspend,
+#endif
};
/***********************************
@@ -3718,5 +3726,7 @@ static int __init ohci1394_init(void)
return pci_register_driver(&ohci1394_pci_driver);
}
-module_init(ohci1394_init);
+/* Register before most other device drivers.
+ * Useful for remote debugging via physical DMA, e.g. using firescope. */
+fs_initcall(ohci1394_init);
module_exit(ohci1394_cleanup);
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index e6f41238f5e8..0a7412e27eb4 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -137,7 +137,6 @@ static struct i2c_algo_bit_data bit_data = {
.getsda = bit_getsda,
.getscl = bit_getscl,
.udelay = 5,
- .mdelay = 5,
.timeout = 100,
};
@@ -840,8 +839,7 @@ static int lynx_devctl(struct hpsb_host *host, enum devctl_cmd cmd, int arg)
********************************************************/
-static irqreturn_t lynx_irq_handler(int irq, void *dev_id,
- struct pt_regs *regs_are_unused)
+static irqreturn_t lynx_irq_handler(int irq, void *dev_id)
{
struct ti_lynx *lynx = (struct ti_lynx *)dev_id;
struct hpsb_host *host = lynx->host;
diff --git a/drivers/ieee1394/raw1394-private.h b/drivers/ieee1394/raw1394-private.h
index c93587be9cab..c7731d1bcd89 100644
--- a/drivers/ieee1394/raw1394-private.h
+++ b/drivers/ieee1394/raw1394-private.h
@@ -29,9 +29,8 @@ struct file_info {
struct list_head req_pending;
struct list_head req_complete;
- struct semaphore complete_sem;
spinlock_t reqlists_lock;
- wait_queue_head_t poll_wait_complete;
+ wait_queue_head_t wait_complete;
struct list_head addr_list;
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 571ea68c0cf2..5ec4f5eb6b19 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -44,14 +44,15 @@
#include <linux/compat.h>
#include "csr1212.h"
+#include "highlevel.h"
+#include "hosts.h"
#include "ieee1394.h"
-#include "ieee1394_types.h"
#include "ieee1394_core.h"
-#include "nodemgr.h"
-#include "hosts.h"
-#include "highlevel.h"
-#include "iso.h"
+#include "ieee1394_hotplug.h"
#include "ieee1394_transactions.h"
+#include "ieee1394_types.h"
+#include "iso.h"
+#include "nodemgr.h"
#include "raw1394.h"
#include "raw1394-private.h"
@@ -66,7 +67,7 @@
#define DBGMSG(fmt, args...) \
printk(KERN_INFO "raw1394:" fmt "\n" , ## args)
#else
-#define DBGMSG(fmt, args...)
+#define DBGMSG(fmt, args...) do {} while (0)
#endif
static LIST_HEAD(host_info_list);
@@ -132,10 +133,9 @@ static void free_pending_request(struct pending_request *req)
static void __queue_complete_req(struct pending_request *req)
{
struct file_info *fi = req->file_info;
- list_move_tail(&req->list, &fi->req_complete);
- up(&fi->complete_sem);
- wake_up_interruptible(&fi->poll_wait_complete);
+ list_move_tail(&req->list, &fi->req_complete);
+ wake_up(&fi->wait_complete);
}
static void queue_complete_req(struct pending_request *req)
@@ -463,13 +463,36 @@ raw1394_compat_read(const char __user *buf, struct raw1394_request *r)
#endif
+/* get next completed request (caller must hold fi->reqlists_lock) */
+static inline struct pending_request *__next_complete_req(struct file_info *fi)
+{
+ struct list_head *lh;
+ struct pending_request *req = NULL;
+
+ if (!list_empty(&fi->req_complete)) {
+ lh = fi->req_complete.next;
+ list_del(lh);
+ req = list_entry(lh, struct pending_request, list);
+ }
+ return req;
+}
+
+/* atomically get next completed request */
+static struct pending_request *next_complete_req(struct file_info *fi)
+{
+ unsigned long flags;
+ struct pending_request *req;
+
+ spin_lock_irqsave(&fi->reqlists_lock, flags);
+ req = __next_complete_req(fi);
+ spin_unlock_irqrestore(&fi->reqlists_lock, flags);
+ return req;
+}
static ssize_t raw1394_read(struct file *file, char __user * buffer,
size_t count, loff_t * offset_is_ignored)
{
- unsigned long flags;
struct file_info *fi = (struct file_info *)file->private_data;
- struct list_head *lh;
struct pending_request *req;
ssize_t ret;
@@ -487,22 +510,21 @@ static ssize_t raw1394_read(struct file *file, char __user * buffer,
}
if (file->f_flags & O_NONBLOCK) {
- if (down_trylock(&fi->complete_sem)) {
+ if (!(req = next_complete_req(fi)))
return -EAGAIN;
- }
} else {
- if (down_interruptible(&fi->complete_sem)) {
+ /*
+ * NB: We call the macro wait_event_interruptible() with a
+ * condition argument with side effect. This is only possible
+ * because the side effect does not occur until the condition
+ * became true, and wait_event_interruptible() won't evaluate
+ * the condition again after that.
+ */
+ if (wait_event_interruptible(fi->wait_complete,
+ (req = next_complete_req(fi))))
return -ERESTARTSYS;
- }
}
- spin_lock_irqsave(&fi->reqlists_lock, flags);
- lh = fi->req_complete.next;
- list_del(lh);
- spin_unlock_irqrestore(&fi->reqlists_lock, flags);
-
- req = list_entry(lh, struct pending_request, list);
-
if (req->req.length) {
if (copy_to_user(int2ptr(req->req.recvb), req->data,
req->req.length)) {
@@ -1752,6 +1774,7 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
addr->notification_options |= addr->client_transactions;
addr->recvb = req->req.recvb;
addr->rec_length = (u16) ((req->req.misc >> 16) & 0xFFFF);
+
spin_lock_irqsave(&host_info_lock, flags);
hi = find_host_info(fi->host);
same_host = 0;
@@ -1777,9 +1800,9 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
}
if (same_host) {
/* addressrange occupied by same host */
+ spin_unlock_irqrestore(&host_info_lock, flags);
vfree(addr->addr_space_buffer);
kfree(addr);
- spin_unlock_irqrestore(&host_info_lock, flags);
return (-EALREADY);
}
/* another host with valid address-entry containing same addressrange */
@@ -1807,6 +1830,8 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
}
}
}
+ spin_unlock_irqrestore(&host_info_lock, flags);
+
if (another_host) {
DBGMSG("another hosts entry is valid -> SUCCESS");
if (copy_to_user(int2ptr(req->req.recvb),
@@ -1815,11 +1840,11 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
" address-range-entry is invalid -> EFAULT !!!\n");
vfree(addr->addr_space_buffer);
kfree(addr);
- spin_unlock_irqrestore(&host_info_lock, flags);
return (-EFAULT);
}
free_pending_request(req); /* immediate success or fail */
/* INSERT ENTRY */
+ spin_lock_irqsave(&host_info_lock, flags);
list_add_tail(&addr->addr_list, &fi->addr_list);
spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request);
@@ -1830,15 +1855,15 @@ static int arm_register(struct file_info *fi, struct pending_request *req)
req->req.address + req->req.length);
if (retval) {
/* INSERT ENTRY */
+ spin_lock_irqsave(&host_info_lock, flags);
list_add_tail(&addr->addr_list, &fi->addr_list);
+ spin_unlock_irqrestore(&host_info_lock, flags);
} else {
DBGMSG("arm_register failed errno: %d \n", retval);
vfree(addr->addr_space_buffer);
kfree(addr);
- spin_unlock_irqrestore(&host_info_lock, flags);
return (-EALREADY);
}
- spin_unlock_irqrestore(&host_info_lock, flags);
free_pending_request(req); /* immediate success or fail */
return sizeof(struct raw1394_request);
}
@@ -1904,10 +1929,10 @@ static int arm_unregister(struct file_info *fi, struct pending_request *req)
if (another_host) {
DBGMSG("delete entry from list -> success");
list_del(&addr->addr_list);
+ spin_unlock_irqrestore(&host_info_lock, flags);
vfree(addr->addr_space_buffer);
kfree(addr);
free_pending_request(req); /* immediate success or fail */
- spin_unlock_irqrestore(&host_info_lock, flags);
return sizeof(struct raw1394_request);
}
retval =
@@ -1949,23 +1974,19 @@ static int arm_get_buf(struct file_info *fi, struct pending_request *req)
(arm_addr->end > req->req.address)) {
if (req->req.address + req->req.length <= arm_addr->end) {
offset = req->req.address - arm_addr->start;
+ spin_unlock_irqrestore(&host_info_lock, flags);
DBGMSG
("arm_get_buf copy_to_user( %08X, %p, %u )",
(u32) req->req.recvb,
arm_addr->addr_space_buffer + offset,
(u32) req->req.length);
-
if (copy_to_user
(int2ptr(req->req.recvb),
arm_addr->addr_space_buffer + offset,
- req->req.length)) {
- spin_unlock_irqrestore(&host_info_lock,
- flags);
+ req->req.length))
return (-EFAULT);
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
/* We have to free the request, because we
* queue no response, and therefore nobody
* will free it. */
@@ -2005,24 +2026,23 @@ static int arm_set_buf(struct file_info *fi, struct pending_request *req)
(arm_addr->end > req->req.address)) {
if (req->req.address + req->req.length <= arm_addr->end) {
offset = req->req.address - arm_addr->start;
+ spin_unlock_irqrestore(&host_info_lock, flags);
DBGMSG
("arm_set_buf copy_from_user( %p, %08X, %u )",
arm_addr->addr_space_buffer + offset,
(u32) req->req.sendb,
(u32) req->req.length);
-
if (copy_from_user
(arm_addr->addr_space_buffer + offset,
int2ptr(req->req.sendb),
- req->req.length)) {
- spin_unlock_irqrestore(&host_info_lock,
- flags);
+ req->req.length))
return (-EFAULT);
- }
- spin_unlock_irqrestore(&host_info_lock, flags);
- free_pending_request(req); /* we have to free the request, because we queue no response, and therefore nobody will free it */
+ /* We have to free the request, because we
+ * queue no response, and therefore nobody
+ * will free it. */
+ free_pending_request(req);
return sizeof(struct raw1394_request);
} else {
DBGMSG("arm_set_buf request exceeded mapping");
@@ -2744,7 +2764,7 @@ static unsigned int raw1394_poll(struct file *file, poll_table * pt)
unsigned int mask = POLLOUT | POLLWRNORM;
unsigned long flags;
- poll_wait(file, &fi->poll_wait_complete, pt);
+ poll_wait(file, &fi->wait_complete, pt);
spin_lock_irqsave(&fi->reqlists_lock, flags);
if (!list_empty(&fi->req_complete)) {
@@ -2769,9 +2789,8 @@ static int raw1394_open(struct inode *inode, struct file *file)
fi->state = opened;
INIT_LIST_HEAD(&fi->req_pending);
INIT_LIST_HEAD(&fi->req_complete);
- sema_init(&fi->complete_sem, 0);
spin_lock_init(&fi->reqlists_lock);
- init_waitqueue_head(&fi->poll_wait_complete);
+ init_waitqueue_head(&fi->wait_complete);
INIT_LIST_HEAD(&fi->addr_list);
file->private_data = fi;
@@ -2784,7 +2803,7 @@ static int raw1394_release(struct inode *inode, struct file *file)
struct file_info *fi = file->private_data;
struct list_head *lh;
struct pending_request *req;
- int done = 0, i, fail = 0;
+ int i, fail;
int retval = 0;
struct list_head *entry;
struct arm_addr *addr = NULL;
@@ -2864,25 +2883,28 @@ static int raw1394_release(struct inode *inode, struct file *file)
"error(s) occurred \n");
}
- while (!done) {
+ for (;;) {
+ /* This locked section guarantees that neither
+ * complete nor pending requests exist once i!=0 */
spin_lock_irqsave(&fi->reqlists_lock, flags);
-
- while (!list_empty(&fi->req_complete)) {
- lh = fi->req_complete.next;
- list_del(lh);
-
- req = list_entry(lh, struct pending_request, list);
-
+ while ((req = __next_complete_req(fi)))
free_pending_request(req);
- }
-
- if (list_empty(&fi->req_pending))
- done = 1;
+ i = list_empty(&fi->req_pending);
spin_unlock_irqrestore(&fi->reqlists_lock, flags);
- if (!done)
- down_interruptible(&fi->complete_sem);
+ if (i)
+ break;
+ /*
+ * Sleep until more requests can be freed.
+ *
+ * NB: We call the macro wait_event() with a condition argument
+ * with side effect. This is only possible because the side
+ * effect does not occur until the condition became true, and
+ * wait_event() won't evaluate the condition again after that.
+ */
+ wait_event(fi->wait_complete, (req = next_complete_req(fi)));
+ free_pending_request(req);
}
/* Remove any sub-trees left by user space programs */
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index b08755e2e68f..6986ac188281 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -38,31 +38,36 @@
* but the code needs additional debugging.
*/
+#include <linux/blkdev.h>
+#include <linux/compiler.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/gfp.h>
+#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/string.h>
-#include <linux/stringify.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/fs.h>
-#include <linux/poll.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/blkdev.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/stringify.h>
+#include <linux/types.h>
+#include <linux/wait.h>
-#include <asm/current.h>
-#include <asm/uaccess.h>
-#include <asm/io.h>
#include <asm/byteorder.h>
-#include <asm/atomic.h>
-#include <asm/system.h>
+#include <asm/errno.h>
+#include <asm/param.h>
#include <asm/scatterlist.h>
+#include <asm/system.h>
+#include <asm/types.h>
+
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+#include <asm/io.h> /* for bus_to_virt */
+#endif
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -71,13 +76,14 @@
#include <scsi/scsi_host.h>
#include "csr1212.h"
+#include "highlevel.h"
+#include "hosts.h"
#include "ieee1394.h"
-#include "ieee1394_types.h"
#include "ieee1394_core.h"
-#include "nodemgr.h"
-#include "hosts.h"
-#include "highlevel.h"
+#include "ieee1394_hotplug.h"
#include "ieee1394_transactions.h"
+#include "ieee1394_types.h"
+#include "nodemgr.h"
#include "sbp2.h"
/*
@@ -173,11 +179,6 @@ MODULE_PARM_DESC(workarounds, "Work around device bugs (default = 0"
", override internal blacklist = " __stringify(SBP2_WORKAROUND_OVERRIDE)
", or a combination)");
-/* legacy parameter */
-static int force_inquiry_hack;
-module_param(force_inquiry_hack, int, 0644);
-MODULE_PARM_DESC(force_inquiry_hack, "Deprecated, use 'workarounds'");
-
/*
* Export information about protocols/devices supported by this driver.
*/
@@ -208,9 +209,9 @@ static u32 global_outstanding_command_orbs = 0;
#define outstanding_orb_incr global_outstanding_command_orbs++
#define outstanding_orb_decr global_outstanding_command_orbs--
#else
-#define SBP2_ORB_DEBUG(fmt, args...)
-#define outstanding_orb_incr
-#define outstanding_orb_decr
+#define SBP2_ORB_DEBUG(fmt, args...) do {} while (0)
+#define outstanding_orb_incr do {} while (0)
+#define outstanding_orb_decr do {} while (0)
#endif
#ifdef CONFIG_IEEE1394_SBP2_DEBUG_DMA
@@ -222,8 +223,8 @@ static u32 global_outstanding_command_orbs = 0;
--global_outstanding_dmas, ## args)
static u32 global_outstanding_dmas = 0;
#else
-#define SBP2_DMA_ALLOC(fmt, args...)
-#define SBP2_DMA_FREE(fmt, args...)
+#define SBP2_DMA_ALLOC(fmt, args...) do {} while (0)
+#define SBP2_DMA_FREE(fmt, args...) do {} while (0)
#endif
#if CONFIG_IEEE1394_SBP2_DEBUG >= 2
@@ -237,7 +238,7 @@ static u32 global_outstanding_dmas = 0;
#define SBP2_NOTICE(fmt, args...) HPSB_NOTICE("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args)
#else
-#define SBP2_DEBUG(fmt, args...)
+#define SBP2_DEBUG(fmt, args...) do {} while (0)
#define SBP2_INFO(fmt, args...) HPSB_INFO("sbp2: "fmt, ## args)
#define SBP2_NOTICE(fmt, args...) HPSB_NOTICE("sbp2: "fmt, ## args)
#define SBP2_WARN(fmt, args...) HPSB_WARN("sbp2: "fmt, ## args)
@@ -356,7 +357,7 @@ static const struct {
/*
* Converts a buffer from be32 to cpu byte ordering. Length is in bytes.
*/
-static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
+static inline void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
{
u32 *temp = buffer;
@@ -369,7 +370,7 @@ static __inline__ void sbp2util_be32_to_cpu_buffer(void *buffer, int length)
/*
* Converts a buffer from cpu to be32 byte ordering. Length is in bytes.
*/
-static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
+static inline void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
{
u32 *temp = buffer;
@@ -380,8 +381,8 @@ static __inline__ void sbp2util_cpu_to_be32_buffer(void *buffer, int length)
}
#else /* BIG_ENDIAN */
/* Why waste the cpu cycles? */
-#define sbp2util_be32_to_cpu_buffer(x,y)
-#define sbp2util_cpu_to_be32_buffer(x,y)
+#define sbp2util_be32_to_cpu_buffer(x,y) do {} while (0)
+#define sbp2util_cpu_to_be32_buffer(x,y) do {} while (0)
#endif
#ifdef CONFIG_IEEE1394_SBP2_PACKET_DUMP
@@ -417,24 +418,26 @@ static void sbp2util_packet_dump(void *buffer, int length, char *dump_name,
return;
}
#else
-#define sbp2util_packet_dump(w,x,y,z)
+#define sbp2util_packet_dump(w,x,y,z) do {} while (0)
#endif
+static DECLARE_WAIT_QUEUE_HEAD(access_wq);
+
/*
- * Goofy routine that basically does a down_timeout function.
+ * Waits for completion of an SBP-2 access request.
+ * Returns nonzero if timed out or prematurely interrupted.
*/
-static int sbp2util_down_timeout(atomic_t *done, int timeout)
+static int sbp2util_access_timeout(struct scsi_id_instance_data *scsi_id,
+ int timeout)
{
- int i;
+ long leftover = wait_event_interruptible_timeout(
+ access_wq, scsi_id->access_complete, timeout);
- for (i = timeout; (i > 0 && atomic_read(done) == 0); i-= HZ/10) {
- if (msleep_interruptible(100)) /* 100ms */
- return 1;
- }
- return (i > 0) ? 0 : 1;
+ scsi_id->access_complete = 0;
+ return leftover <= 0;
}
-/* Free's an allocated packet */
+/* Frees an allocated packet */
static void sbp2_free_packet(struct hpsb_packet *packet)
{
hpsb_free_tlabel(packet);
@@ -468,6 +471,44 @@ static int sbp2util_node_write_no_wait(struct node_entry *ne, u64 addr,
return 0;
}
+static void sbp2util_notify_fetch_agent(struct scsi_id_instance_data *scsi_id,
+ u64 offset, quadlet_t *data, size_t len)
+{
+ /*
+ * There is a small window after a bus reset within which the node
+ * entry's generation is current but the reconnect wasn't completed.
+ */
+ if (unlikely(atomic_read(&scsi_id->state) == SBP2LU_STATE_IN_RESET))
+ return;
+
+ if (hpsb_node_write(scsi_id->ne,
+ scsi_id->sbp2_command_block_agent_addr + offset,
+ data, len))
+ SBP2_ERR("sbp2util_notify_fetch_agent failed.");
+ /*
+ * Now accept new SCSI commands, unless a bus reset happended during
+ * hpsb_node_write.
+ */
+ if (likely(atomic_read(&scsi_id->state) != SBP2LU_STATE_IN_RESET))
+ scsi_unblock_requests(scsi_id->scsi_host);
+}
+
+static void sbp2util_write_orb_pointer(void *p)
+{
+ quadlet_t data[2];
+
+ data[0] = ORB_SET_NODE_ID(
+ ((struct scsi_id_instance_data *)p)->hi->host->node_id);
+ data[1] = ((struct scsi_id_instance_data *)p)->last_orb_dma;
+ sbp2util_cpu_to_be32_buffer(data, 8);
+ sbp2util_notify_fetch_agent(p, SBP2_ORB_POINTER_OFFSET, data, 8);
+}
+
+static void sbp2util_write_doorbell(void *p)
+{
+ sbp2util_notify_fetch_agent(p, SBP2_DOORBELL_OFFSET, NULL, 4);
+}
+
/*
* This function is called to create a pool of command orbs used for
* command processing. It is called when a new sbp2 device is detected.
@@ -492,7 +533,7 @@ static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_i
command->command_orb_dma =
pci_map_single(hi->host->pdev, &command->command_orb,
sizeof(struct sbp2_command_orb),
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_TODEVICE);
SBP2_DMA_ALLOC("single command orb DMA");
command->sge_dma =
pci_map_single(hi->host->pdev,
@@ -525,7 +566,7 @@ static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_
/* Release our generic DMA's */
pci_unmap_single(host->pdev, command->command_orb_dma,
sizeof(struct sbp2_command_orb),
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_TODEVICE);
SBP2_DMA_FREE("single command orb DMA");
pci_unmap_single(host->pdev, command->sge_dma,
sizeof(command->scatter_gather_element),
@@ -715,6 +756,7 @@ static int sbp2_remove(struct device *dev)
sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT);
/* scsi_remove_device() will trigger shutdown functions of SCSI
* highlevel drivers which would deadlock if blocked. */
+ atomic_set(&scsi_id->state, SBP2LU_STATE_IN_SHUTDOWN);
scsi_unblock_requests(scsi_id->scsi_host);
}
sdev = scsi_id->sdev;
@@ -766,10 +808,12 @@ static int sbp2_update(struct unit_directory *ud)
*/
sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
- /* Make sure we unblock requests (since this is likely after a bus
- * reset). */
- scsi_unblock_requests(scsi_id->scsi_host);
-
+ /* Accept new commands unless there was another bus reset in the
+ * meantime. */
+ if (hpsb_node_entry_valid(scsi_id->ne)) {
+ atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
+ scsi_unblock_requests(scsi_id->scsi_host);
+ }
return 0;
}
@@ -794,11 +838,12 @@ static struct scsi_id_instance_data *sbp2_alloc_device(struct unit_directory *ud
scsi_id->speed_code = IEEE1394_SPEED_100;
scsi_id->max_payload_size = sbp2_speedto_max_payload[IEEE1394_SPEED_100];
scsi_id->status_fifo_addr = CSR1212_INVALID_ADDR_SPACE;
- atomic_set(&scsi_id->sbp2_login_complete, 0);
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
INIT_LIST_HEAD(&scsi_id->scsi_list);
spin_lock_init(&scsi_id->sbp2_command_orb_lock);
+ atomic_set(&scsi_id->state, SBP2LU_STATE_RUNNING);
+ INIT_WORK(&scsi_id->protocol_work, NULL, NULL);
ud->device.driver_data = scsi_id;
@@ -881,11 +926,14 @@ static void sbp2_host_reset(struct hpsb_host *host)
struct scsi_id_instance_data *scsi_id;
hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
-
- if (hi) {
- list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
+ if (!hi)
+ return;
+ list_for_each_entry(scsi_id, &hi->scsi_ids, scsi_list)
+ if (likely(atomic_read(&scsi_id->state) !=
+ SBP2LU_STATE_IN_SHUTDOWN)) {
+ atomic_set(&scsi_id->state, SBP2LU_STATE_IN_RESET);
scsi_block_requests(scsi_id->scsi_host);
- }
+ }
}
/*
@@ -970,8 +1018,7 @@ static int sbp2_start_device(struct scsi_id_instance_data *scsi_id)
* connected to the sbp2 device being removed. That host would
* have a certain amount of time to relogin before the sbp2 device
* allows someone else to login instead. One second makes sense. */
- msleep_interruptible(1000);
- if (signal_pending(current)) {
+ if (msleep_interruptible(1000)) {
sbp2_remove_device(scsi_id);
return -EINTR;
}
@@ -1036,7 +1083,7 @@ static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
scsi_remove_host(scsi_id->scsi_host);
scsi_host_put(scsi_id->scsi_host);
}
-
+ flush_scheduled_work();
sbp2util_remove_command_orb_pool(scsi_id);
list_del(&scsi_id->scsi_list);
@@ -1182,17 +1229,14 @@ static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
"sbp2 query logins orb", scsi_id->query_logins_orb_dma);
memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
data[0] = ORB_SET_NODE_ID(hi->host->node_id);
data[1] = scsi_id->query_logins_orb_dma;
sbp2util_cpu_to_be32_buffer(data, 8);
- atomic_set(&scsi_id->sbp2_login_complete, 0);
-
hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
+ if (sbp2util_access_timeout(scsi_id, 2*HZ)) {
SBP2_INFO("Error querying logins to SBP-2 device - timed out");
return -EIO;
}
@@ -1202,11 +1246,8 @@ static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
return -EIO;
}
- if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
- STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
- STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
-
- SBP2_INFO("Error querying logins to SBP-2 device - timed out");
+ if (STATUS_TEST_RDS(scsi_id->status_block.ORB_offset_hi_misc)) {
+ SBP2_INFO("Error querying logins to SBP-2 device - failed");
return -EIO;
}
@@ -1278,21 +1319,18 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
"sbp2 login orb", scsi_id->login_orb_dma);
memset(scsi_id->login_response, 0, sizeof(struct sbp2_login_response));
- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
data[0] = ORB_SET_NODE_ID(hi->host->node_id);
data[1] = scsi_id->login_orb_dma;
sbp2util_cpu_to_be32_buffer(data, 8);
- atomic_set(&scsi_id->sbp2_login_complete, 0);
-
hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
/*
* Wait for login status (up to 20 seconds)...
*/
- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 20*HZ)) {
- SBP2_ERR("Error logging into SBP-2 device - login timed-out");
+ if (sbp2util_access_timeout(scsi_id, 20*HZ)) {
+ SBP2_ERR("Error logging into SBP-2 device - timed out");
return -EIO;
}
@@ -1300,18 +1338,12 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
* Sanity. Make sure status returned matches login orb.
*/
if (scsi_id->status_block.ORB_offset_lo != scsi_id->login_orb_dma) {
- SBP2_ERR("Error logging into SBP-2 device - login timed-out");
+ SBP2_ERR("Error logging into SBP-2 device - timed out");
return -EIO;
}
- /*
- * Check status
- */
- if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
- STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
- STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
-
- SBP2_ERR("Error logging into SBP-2 device - login failed");
+ if (STATUS_TEST_RDS(scsi_id->status_block.ORB_offset_hi_misc)) {
+ SBP2_ERR("Error logging into SBP-2 device - failed");
return -EIO;
}
@@ -1335,9 +1367,7 @@ static int sbp2_login_device(struct scsi_id_instance_data *scsi_id)
scsi_id->sbp2_command_block_agent_addr &= 0x0000ffffffffffffULL;
SBP2_INFO("Logged into SBP-2 device");
-
return 0;
-
}
/*
@@ -1387,21 +1417,17 @@ static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id)
data[1] = scsi_id->logout_orb_dma;
sbp2util_cpu_to_be32_buffer(data, 8);
- atomic_set(&scsi_id->sbp2_login_complete, 0);
-
error = hpsb_node_write(scsi_id->ne,
scsi_id->sbp2_management_agent_addr, data, 8);
if (error)
return error;
/* Wait for device to logout...1 second. */
- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ))
+ if (sbp2util_access_timeout(scsi_id, HZ))
return -EIO;
SBP2_INFO("Logged out of SBP-2 device");
-
return 0;
-
}
/*
@@ -1445,20 +1471,10 @@ static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
sbp2util_packet_dump(scsi_id->reconnect_orb, sizeof(struct sbp2_reconnect_orb),
"sbp2 reconnect orb", scsi_id->reconnect_orb_dma);
- /*
- * Initialize status fifo
- */
- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
-
- /*
- * Ok, let's write to the target's management agent register
- */
data[0] = ORB_SET_NODE_ID(hi->host->node_id);
data[1] = scsi_id->reconnect_orb_dma;
sbp2util_cpu_to_be32_buffer(data, 8);
- atomic_set(&scsi_id->sbp2_login_complete, 0);
-
error = hpsb_node_write(scsi_id->ne,
scsi_id->sbp2_management_agent_addr, data, 8);
if (error)
@@ -1467,8 +1483,8 @@ static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
/*
* Wait for reconnect status (up to 1 second)...
*/
- if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, HZ)) {
- SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
+ if (sbp2util_access_timeout(scsi_id, HZ)) {
+ SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
return -EIO;
}
@@ -1476,25 +1492,17 @@ static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
* Sanity. Make sure status returned matches reconnect orb.
*/
if (scsi_id->status_block.ORB_offset_lo != scsi_id->reconnect_orb_dma) {
- SBP2_ERR("Error reconnecting to SBP-2 device - reconnect timed-out");
+ SBP2_ERR("Error reconnecting to SBP-2 device - timed out");
return -EIO;
}
- /*
- * Check status
- */
- if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
- STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
- STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
-
- SBP2_ERR("Error reconnecting to SBP-2 device - reconnect failed");
+ if (STATUS_TEST_RDS(scsi_id->status_block.ORB_offset_hi_misc)) {
+ SBP2_ERR("Error reconnecting to SBP-2 device - failed");
return -EIO;
}
HPSB_DEBUG("Reconnected to SBP-2 device");
-
return 0;
-
}
/*
@@ -1592,11 +1600,6 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
}
workarounds = sbp2_default_workarounds;
- if (force_inquiry_hack) {
- SBP2_WARN("force_inquiry_hack is deprecated. "
- "Use parameter 'workarounds' instead.");
- workarounds |= SBP2_WORKAROUND_INQUIRY_36;
- }
if (!(workarounds & SBP2_WORKAROUND_OVERRIDE))
for (i = 0; i < ARRAY_SIZE(sbp2_workarounds_table); i++) {
@@ -1705,9 +1708,14 @@ static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait)
quadlet_t data;
u64 addr;
int retval;
+ unsigned long flags;
SBP2_DEBUG_ENTER();
+ cancel_delayed_work(&scsi_id->protocol_work);
+ if (wait)
+ flush_scheduled_work();
+
data = ntohl(SBP2_AGENT_RESET_DATA);
addr = scsi_id->sbp2_command_block_agent_addr + SBP2_AGENT_RESET_OFFSET;
@@ -1724,7 +1732,9 @@ static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait)
/*
* Need to make sure orb pointer is written on next command
*/
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
scsi_id->last_orb = NULL;
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return 0;
}
@@ -1961,13 +1971,17 @@ static void sbp2_create_command_orb(struct scsi_id_instance_data *scsi_id,
/*
* This function is called in order to begin a regular SBP-2 command.
*/
-static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
+static void sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
struct sbp2_command_info *command)
{
struct sbp2scsi_host_info *hi = scsi_id->hi;
struct sbp2_command_orb *command_orb = &command->command_orb;
- struct node_entry *ne = scsi_id->ne;
- u64 addr;
+ struct sbp2_command_orb *last_orb;
+ dma_addr_t last_orb_dma;
+ u64 addr = scsi_id->sbp2_command_block_agent_addr;
+ quadlet_t data[2];
+ size_t length;
+ unsigned long flags;
outstanding_orb_incr;
SBP2_ORB_DEBUG("sending command orb %p, total orbs = %x",
@@ -1975,73 +1989,70 @@ static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
pci_dma_sync_single_for_device(hi->host->pdev, command->command_orb_dma,
sizeof(struct sbp2_command_orb),
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_TODEVICE);
pci_dma_sync_single_for_device(hi->host->pdev, command->sge_dma,
sizeof(command->scatter_gather_element),
PCI_DMA_BIDIRECTIONAL);
/*
* Check to see if there are any previous orbs to use
*/
- if (scsi_id->last_orb == NULL) {
- quadlet_t data[2];
-
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
+ last_orb = scsi_id->last_orb;
+ last_orb_dma = scsi_id->last_orb_dma;
+ if (!last_orb) {
/*
- * Ok, let's write to the target's management agent register
+ * last_orb == NULL means: We know that the target's fetch agent
+ * is not active right now.
*/
- addr = scsi_id->sbp2_command_block_agent_addr + SBP2_ORB_POINTER_OFFSET;
+ addr += SBP2_ORB_POINTER_OFFSET;
data[0] = ORB_SET_NODE_ID(hi->host->node_id);
data[1] = command->command_orb_dma;
sbp2util_cpu_to_be32_buffer(data, 8);
-
- SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);
-
- if (sbp2util_node_write_no_wait(ne, addr, data, 8) < 0) {
- SBP2_ERR("sbp2util_node_write_no_wait failed.\n");
- return -EIO;
- }
-
- SBP2_ORB_DEBUG("write command agent complete");
-
- scsi_id->last_orb = command_orb;
- scsi_id->last_orb_dma = command->command_orb_dma;
-
+ length = 8;
} else {
- quadlet_t data;
-
/*
- * We have an orb already sent (maybe or maybe not
- * processed) that we can append this orb to. So do so,
- * and ring the doorbell. Have to be very careful
- * modifying these next orb pointers, as they are accessed
- * both by the sbp2 device and us.
+ * last_orb != NULL means: We know that the target's fetch agent
+ * is (very probably) not dead or in reset state right now.
+ * We have an ORB already sent that we can append a new one to.
+ * The target's fetch agent may or may not have read this
+ * previous ORB yet.
*/
- scsi_id->last_orb->next_ORB_lo =
- cpu_to_be32(command->command_orb_dma);
+ pci_dma_sync_single_for_cpu(hi->host->pdev, last_orb_dma,
+ sizeof(struct sbp2_command_orb),
+ PCI_DMA_TODEVICE);
+ last_orb->next_ORB_lo = cpu_to_be32(command->command_orb_dma);
+ wmb();
/* Tells hardware that this pointer is valid */
- scsi_id->last_orb->next_ORB_hi = 0x0;
- pci_dma_sync_single_for_device(hi->host->pdev,
- scsi_id->last_orb_dma,
+ last_orb->next_ORB_hi = 0;
+ pci_dma_sync_single_for_device(hi->host->pdev, last_orb_dma,
sizeof(struct sbp2_command_orb),
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_TODEVICE);
+ addr += SBP2_DOORBELL_OFFSET;
+ data[0] = 0;
+ length = 4;
+ }
+ scsi_id->last_orb = command_orb;
+ scsi_id->last_orb_dma = command->command_orb_dma;
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
+ SBP2_ORB_DEBUG("write to %s register, command orb %p",
+ last_orb ? "DOORBELL" : "ORB_POINTER", command_orb);
+ if (sbp2util_node_write_no_wait(scsi_id->ne, addr, data, length)) {
/*
- * Ring the doorbell
+ * sbp2util_node_write_no_wait failed. We certainly ran out
+ * of transaction labels, perhaps just because there were no
+ * context switches which gave khpsbpkt a chance to collect
+ * free tlabels. Try again in non-atomic context. If necessary,
+ * the workqueue job will sleep to guaranteedly get a tlabel.
+ * We do not accept new commands until the job is over.
*/
- data = cpu_to_be32(command->command_orb_dma);
- addr = scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET;
-
- SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb);
-
- if (sbp2util_node_write_no_wait(ne, addr, &data, 4) < 0) {
- SBP2_ERR("sbp2util_node_write_no_wait failed");
- return -EIO;
- }
-
- scsi_id->last_orb = command_orb;
- scsi_id->last_orb_dma = command->command_orb_dma;
-
+ scsi_block_requests(scsi_id->scsi_host);
+ PREPARE_WORK(&scsi_id->protocol_work,
+ last_orb ? sbp2util_write_doorbell:
+ sbp2util_write_orb_pointer,
+ scsi_id);
+ schedule_work(&scsi_id->protocol_work);
}
- return 0;
}
/*
@@ -2078,11 +2089,6 @@ static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
"sbp2 command orb", command->command_orb_dma);
/*
- * Initialize status fifo
- */
- memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
-
- /*
* Link up the orb, and ring the doorbell if needed
*/
sbp2_link_orb_command(scsi_id, command);
@@ -2123,12 +2129,14 @@ static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense
/*
* This function deals with status writes from the SBP-2 device
*/
-static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, size_t length, u16 fl)
+static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid,
+ int destid, quadlet_t *data, u64 addr,
+ size_t length, u16 fl)
{
struct sbp2scsi_host_info *hi;
struct scsi_id_instance_data *scsi_id = NULL, *scsi_id_tmp;
struct scsi_cmnd *SCpnt = NULL;
+ struct sbp2_status_block *sb;
u32 scsi_status = SBP2_SCSI_STATUS_GOOD;
struct sbp2_command_info *command;
unsigned long flags;
@@ -2137,18 +2145,19 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
sbp2util_packet_dump(data, length, "sbp2 status write by device", (u32)addr);
- if (!host) {
+ if (unlikely(length < 8 || length > sizeof(struct sbp2_status_block))) {
+ SBP2_ERR("Wrong size of status block");
+ return RCODE_ADDRESS_ERROR;
+ }
+ if (unlikely(!host)) {
SBP2_ERR("host is NULL - this is bad!");
return RCODE_ADDRESS_ERROR;
}
-
hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
-
- if (!hi) {
+ if (unlikely(!hi)) {
SBP2_ERR("host info is NULL - this is bad!");
return RCODE_ADDRESS_ERROR;
}
-
/*
* Find our scsi_id structure by looking at the status fifo address
* written to by the sbp2 device.
@@ -2160,32 +2169,35 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
break;
}
}
-
- if (!scsi_id) {
+ if (unlikely(!scsi_id)) {
SBP2_ERR("scsi_id is NULL - device is gone?");
return RCODE_ADDRESS_ERROR;
}
/*
- * Put response into scsi_id status fifo...
+ * Put response into scsi_id status fifo buffer. The first two bytes
+ * come in big endian bit order. Often the target writes only a
+ * truncated status block, minimally the first two quadlets. The rest
+ * is implied to be zeros.
*/
- memcpy(&scsi_id->status_block, data, length);
+ sb = &scsi_id->status_block;
+ memset(sb->command_set_dependent, 0, sizeof(sb->command_set_dependent));
+ memcpy(sb, data, length);
+ sbp2util_be32_to_cpu_buffer(sb, 8);
/*
- * Byte swap first two quadlets (8 bytes) of status for processing
+ * Ignore unsolicited status. Handle command ORB status.
*/
- sbp2util_be32_to_cpu_buffer(&scsi_id->status_block, 8);
-
- /*
- * Handle command ORB status here if necessary. First, need to match status with command.
- */
- command = sbp2util_find_command_for_orb(scsi_id, scsi_id->status_block.ORB_offset_lo);
+ if (unlikely(STATUS_GET_SRC(sb->ORB_offset_hi_misc) == 2))
+ command = NULL;
+ else
+ command = sbp2util_find_command_for_orb(scsi_id,
+ sb->ORB_offset_lo);
if (command) {
-
SBP2_DEBUG("Found status for command ORB");
pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
sizeof(struct sbp2_command_orb),
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_TODEVICE);
pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
sizeof(command->scatter_gather_element),
PCI_DMA_BIDIRECTIONAL);
@@ -2194,7 +2206,12 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
outstanding_orb_decr;
/*
- * Matched status with command, now grab scsi command pointers and check status
+ * Matched status with command, now grab scsi command pointers
+ * and check status.
+ */
+ /*
+ * FIXME: If the src field in the status is 1, the ORB DMA must
+ * not be reused until status for a subsequent ORB is received.
*/
SCpnt = command->Current_SCpnt;
spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
@@ -2202,61 +2219,64 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
if (SCpnt) {
-
+ u32 h = sb->ORB_offset_hi_misc;
+ u32 r = STATUS_GET_RESP(h);
+
+ if (r != RESP_STATUS_REQUEST_COMPLETE) {
+ SBP2_WARN("resp 0x%x, sbp_status 0x%x",
+ r, STATUS_GET_SBP_STATUS(h));
+ scsi_status =
+ r == RESP_STATUS_TRANSPORT_FAILURE ?
+ SBP2_SCSI_STATUS_BUSY :
+ SBP2_SCSI_STATUS_COMMAND_TERMINATED;
+ }
/*
- * See if the target stored any scsi status information
+ * See if the target stored any scsi status information.
*/
- if (STATUS_GET_LENGTH(scsi_id->status_block.ORB_offset_hi_misc) > 1) {
- /*
- * Translate SBP-2 status to SCSI sense data
- */
+ if (STATUS_GET_LEN(h) > 1) {
SBP2_DEBUG("CHECK CONDITION");
- scsi_status = sbp2_status_to_sense_data((unchar *)&scsi_id->status_block, SCpnt->sense_buffer);
+ scsi_status = sbp2_status_to_sense_data(
+ (unchar *)sb, SCpnt->sense_buffer);
}
-
/*
- * Check to see if the dead bit is set. If so, we'll have to initiate
- * a fetch agent reset.
+ * Check to see if the dead bit is set. If so, we'll
+ * have to initiate a fetch agent reset.
*/
- if (STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc)) {
-
- /*
- * Initiate a fetch agent reset.
- */
- SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
+ if (STATUS_TEST_DEAD(h)) {
+ SBP2_DEBUG("Dead bit set - "
+ "initiating fetch agent reset");
sbp2_agent_reset(scsi_id, 0);
}
-
SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
}
/*
- * Check here to see if there are no commands in-use. If there are none, we can
- * null out last orb so that next time around we write directly to the orb pointer...
- * Quick start saves one 1394 bus transaction.
+ * Check here to see if there are no commands in-use. If there
+ * are none, we know that the fetch agent left the active state
+ * _and_ that we did not reactivate it yet. Therefore clear
+ * last_orb so that next time we write directly to the
+ * ORB_POINTER register. That way the fetch agent does not need
+ * to refetch the next_ORB.
*/
spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
- if (list_empty(&scsi_id->sbp2_command_orb_inuse)) {
+ if (list_empty(&scsi_id->sbp2_command_orb_inuse))
scsi_id->last_orb = NULL;
- }
spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
} else {
-
/*
* It's probably a login/logout/reconnect status.
*/
- if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
- (scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
- (scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
- (scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
- atomic_set(&scsi_id->sbp2_login_complete, 1);
+ if ((sb->ORB_offset_lo == scsi_id->reconnect_orb_dma) ||
+ (sb->ORB_offset_lo == scsi_id->login_orb_dma) ||
+ (sb->ORB_offset_lo == scsi_id->query_logins_orb_dma) ||
+ (sb->ORB_offset_lo == scsi_id->logout_orb_dma)) {
+ scsi_id->access_complete = 1;
+ wake_up_interruptible(&access_wq);
}
}
if (SCpnt) {
-
- /* Complete the SCSI command. */
SBP2_DEBUG("Completing SCSI command");
sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt,
command->Current_done);
@@ -2372,7 +2392,7 @@ static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id
command = list_entry(lh, struct sbp2_command_info, list);
pci_dma_sync_single_for_cpu(hi->host->pdev, command->command_orb_dma,
sizeof(struct sbp2_command_orb),
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_TODEVICE);
pci_dma_sync_single_for_cpu(hi->host->pdev, command->sge_dma,
sizeof(command->scatter_gather_element),
PCI_DMA_BIDIRECTIONAL);
@@ -2495,6 +2515,7 @@ static int sbp2scsi_slave_alloc(struct scsi_device *sdev)
(struct scsi_id_instance_data *)sdev->host->hostdata[0];
scsi_id->sdev = sdev;
+ sdev->allow_restart = 1;
if (scsi_id->workarounds & SBP2_WORKAROUND_INQUIRY_36)
sdev->inquiry_len = 36;
@@ -2508,16 +2529,12 @@ static int sbp2scsi_slave_configure(struct scsi_device *sdev)
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
sdev->use_10_for_rw = 1;
- sdev->use_10_for_ms = 1;
if (sdev->type == TYPE_DISK &&
scsi_id->workarounds & SBP2_WORKAROUND_MODE_SENSE_8)
sdev->skip_ms_page_8 = 1;
if (scsi_id->workarounds & SBP2_WORKAROUND_FIX_CAPACITY)
sdev->fix_capacity = 1;
- if (scsi_id->ne->guid_vendor_id == 0x0010b9 && /* Maxtor's OUI */
- (sdev->type == TYPE_DISK || sdev->type == TYPE_RBC))
- sdev->allow_restart = 1;
return 0;
}
@@ -2555,7 +2572,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
pci_dma_sync_single_for_cpu(hi->host->pdev,
command->command_orb_dma,
sizeof(struct sbp2_command_orb),
- PCI_DMA_BIDIRECTIONAL);
+ PCI_DMA_TODEVICE);
pci_dma_sync_single_for_cpu(hi->host->pdev,
command->sge_dma,
sizeof(command->scatter_gather_element),
@@ -2571,7 +2588,7 @@ static int sbp2scsi_abort(struct scsi_cmnd *SCpnt)
/*
* Initiate a fetch agent reset.
*/
- sbp2_agent_reset(scsi_id, 0);
+ sbp2_agent_reset(scsi_id, 1);
sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
}
@@ -2590,7 +2607,7 @@ static int sbp2scsi_reset(struct scsi_cmnd *SCpnt)
if (sbp2util_node_is_available(scsi_id)) {
SBP2_ERR("Generating sbp2 fetch agent reset");
- sbp2_agent_reset(scsi_id, 0);
+ sbp2_agent_reset(scsi_id, 1);
}
return SUCCESS;
diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
index b22ce1aa8fe4..abbe48e646c3 100644
--- a/drivers/ieee1394/sbp2.h
+++ b/drivers/ieee1394/sbp2.h
@@ -46,8 +46,8 @@
#define ORB_SET_DIRECTION(value) ((value & 0x1) << 27)
struct sbp2_command_orb {
- volatile u32 next_ORB_hi;
- volatile u32 next_ORB_lo;
+ u32 next_ORB_hi;
+ u32 next_ORB_lo;
u32 data_descriptor_hi;
u32 data_descriptor_lo;
u32 misc;
@@ -180,12 +180,14 @@ struct sbp2_unrestricted_page_table {
#define SBP2_SCSI_STATUS_SELECTION_TIMEOUT 0xff
-#define STATUS_GET_ORB_OFFSET_HI(value) (value & 0xffff)
-#define STATUS_GET_SBP_STATUS(value) ((value >> 16) & 0xff)
-#define STATUS_GET_LENGTH(value) ((value >> 24) & 0x7)
-#define STATUS_GET_DEAD_BIT(value) ((value >> 27) & 0x1)
-#define STATUS_GET_RESP(value) ((value >> 28) & 0x3)
-#define STATUS_GET_SRC(value) ((value >> 30) & 0x3)
+#define STATUS_GET_SRC(value) (((value) >> 30) & 0x3)
+#define STATUS_GET_RESP(value) (((value) >> 28) & 0x3)
+#define STATUS_GET_LEN(value) (((value) >> 24) & 0x7)
+#define STATUS_GET_SBP_STATUS(value) (((value) >> 16) & 0xff)
+#define STATUS_GET_ORB_OFFSET_HI(value) ((value) & 0x0000ffff)
+#define STATUS_TEST_DEAD(value) ((value) & 0x08000000)
+/* test 'resp' | 'dead' | 'sbp2_status' */
+#define STATUS_TEST_RDS(value) ((value) & 0x38ff0000)
struct sbp2_status_block {
u32 ORB_offset_hi_misc;
@@ -318,9 +320,9 @@ struct scsi_id_instance_data {
u64 status_fifo_addr;
/*
- * Variable used for logins, reconnects, logouts, query logins
+ * Waitqueue flag for logins, reconnects, logouts, query logins
*/
- atomic_t sbp2_login_complete;
+ int access_complete:1;
/*
* Pool of command orbs, so we can have more than overlapped command per id
@@ -344,6 +346,16 @@ struct scsi_id_instance_data {
/* Device specific workarounds/brokeness */
unsigned workarounds;
+
+ atomic_t state;
+ struct work_struct protocol_work;
+};
+
+/* For use in scsi_id_instance_data.state */
+enum sbp2lu_state_types {
+ SBP2LU_STATE_RUNNING, /* all normal */
+ SBP2LU_STATE_IN_RESET, /* between bus reset and reconnect */
+ SBP2LU_STATE_IN_SHUTDOWN /* when sbp2_remove was called */
};
/* Sbp2 host data structure (one per IEEE1394 host) */
@@ -390,11 +402,6 @@ static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id);
static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
quadlet_t *data, u64 addr, size_t length, u16 flags);
static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait);
-static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
- struct sbp2_command_info *command);
-static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
- struct scsi_cmnd *SCpnt,
- void (*done)(struct scsi_cmnd *));
static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status,
unchar *sense_data);
static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id,
diff --git a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
index c6e3f02bc6d7..9bc65059cc69 100644
--- a/drivers/ieee1394/video1394.c
+++ b/drivers/ieee1394/video1394.c
@@ -49,16 +49,16 @@
#include <linux/compat.h>
#include <linux/cdev.h>
-#include "ieee1394.h"
-#include "ieee1394_types.h"
+#include "dma.h"
+#include "highlevel.h"
#include "hosts.h"
+#include "ieee1394.h"
#include "ieee1394_core.h"
-#include "highlevel.h"
-#include "video1394.h"
+#include "ieee1394_hotplug.h"
+#include "ieee1394_types.h"
#include "nodemgr.h"
-#include "dma.h"
-
#include "ohci1394.h"
+#include "video1394.h"
#define ISO_CHANNELS 64
@@ -129,7 +129,7 @@ struct file_ctx {
#define DBGMSG(card, fmt, args...) \
printk(KERN_INFO "video1394_%d: " fmt "\n" , card , ## args)
#else
-#define DBGMSG(card, fmt, args...)
+#define DBGMSG(card, fmt, args...) do {} while (0)
#endif
/* print general (card independent) information */
@@ -1181,7 +1181,8 @@ static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
lock_kernel();
if (ctx->current_ctx == NULL) {
- PRINT(KERN_ERR, ctx->ohci->host->id, "Current iso context not set");
+ PRINT(KERN_ERR, ctx->ohci->host->id,
+ "Current iso context not set");
} else
res = dma_region_mmap(&ctx->current_ctx->dma, file, vma);
unlock_kernel();
@@ -1189,6 +1190,40 @@ static int video1394_mmap(struct file *file, struct vm_area_struct *vma)
return res;
}
+static unsigned int video1394_poll(struct file *file, poll_table *pt)
+{
+ struct file_ctx *ctx;
+ unsigned int mask = 0;
+ unsigned long flags;
+ struct dma_iso_ctx *d;
+ int i;
+
+ lock_kernel();
+ ctx = file->private_data;
+ d = ctx->current_ctx;
+ if (d == NULL) {
+ PRINT(KERN_ERR, ctx->ohci->host->id,
+ "Current iso context not set");
+ mask = POLLERR;
+ goto done;
+ }
+
+ poll_wait(file, &d->waitq, pt);
+
+ spin_lock_irqsave(&d->lock, flags);
+ for (i = 0; i < d->num_desc; i++) {
+ if (d->buffer_status[i] == VIDEO1394_BUFFER_READY) {
+ mask |= POLLIN | POLLRDNORM;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&d->lock, flags);
+done:
+ unlock_kernel();
+
+ return mask;
+}
+
static int video1394_open(struct inode *inode, struct file *file)
{
int i = ieee1394_file_to_instance(file);
@@ -1257,6 +1292,7 @@ static struct file_operations video1394_fops=
#ifdef CONFIG_COMPAT
.compat_ioctl = video1394_compat_ioctl,
#endif
+ .poll = video1394_poll,
.mmap = video1394_mmap,
.open = video1394_open,
.release = video1394_release
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c
index 9cbf09e2052f..60d3fbdd216c 100644
--- a/drivers/infiniband/core/addr.c
+++ b/drivers/infiniband/core/addr.c
@@ -86,7 +86,7 @@ EXPORT_SYMBOL(rdma_copy_addr);
int rdma_translate_ip(struct sockaddr *addr, struct rdma_dev_addr *dev_addr)
{
struct net_device *dev;
- u32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ __be32 ip = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
int ret;
dev = ip_dev_find(ip);
@@ -239,7 +239,7 @@ static int addr_resolve_local(struct sockaddr_in *src_in,
{
struct net_device *dev;
u32 src_ip = src_in->sin_addr.s_addr;
- u32 dst_ip = dst_in->sin_addr.s_addr;
+ __be32 dst_ip = dst_in->sin_addr.s_addr;
int ret;
dev = ip_dev_find(dst_ip);
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index f35fcc4c0638..25b1018a476c 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -75,6 +75,7 @@ static struct ib_cm {
struct rb_root remote_sidr_table;
struct idr local_id_table;
__be32 random_id_operand;
+ struct list_head timewait_list;
struct workqueue_struct *wq;
} cm;
@@ -112,6 +113,7 @@ struct cm_work {
struct cm_timewait_info {
struct cm_work work; /* Must be first. */
+ struct list_head list;
struct rb_node remote_qp_node;
struct rb_node remote_id_node;
__be64 remote_ca_guid;
@@ -647,13 +649,6 @@ static inline int cm_convert_to_ms(int iba_time)
static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
{
- unsigned long flags;
-
- if (!timewait_info->inserted_remote_id &&
- !timewait_info->inserted_remote_qp)
- return;
-
- spin_lock_irqsave(&cm.lock, flags);
if (timewait_info->inserted_remote_id) {
rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table);
timewait_info->inserted_remote_id = 0;
@@ -663,7 +658,6 @@ static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);
timewait_info->inserted_remote_qp = 0;
}
- spin_unlock_irqrestore(&cm.lock, flags);
}
static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id)
@@ -684,8 +678,12 @@ static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id)
static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
{
int wait_time;
+ unsigned long flags;
+ spin_lock_irqsave(&cm.lock, flags);
cm_cleanup_timewait(cm_id_priv->timewait_info);
+ list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list);
+ spin_unlock_irqrestore(&cm.lock, flags);
/*
* The cm_id could be destroyed by the user before we exit timewait.
@@ -701,9 +699,13 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
{
+ unsigned long flags;
+
cm_id_priv->id.state = IB_CM_IDLE;
if (cm_id_priv->timewait_info) {
+ spin_lock_irqsave(&cm.lock, flags);
cm_cleanup_timewait(cm_id_priv->timewait_info);
+ spin_unlock_irqrestore(&cm.lock, flags);
kfree(cm_id_priv->timewait_info);
cm_id_priv->timewait_info = NULL;
}
@@ -1307,6 +1309,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
if (timewait_info) {
cur_cm_id_priv = cm_get_id(timewait_info->work.local_id,
timewait_info->work.remote_id);
+ cm_cleanup_timewait(cm_id_priv->timewait_info);
spin_unlock_irqrestore(&cm.lock, flags);
if (cur_cm_id_priv) {
cm_dup_req_handler(work, cur_cm_id_priv);
@@ -1315,7 +1318,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
cm_issue_rej(work->port, work->mad_recv_wc,
IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ,
NULL, 0);
- goto error;
+ listen_cm_id_priv = NULL;
+ goto out;
}
/* Find matching listen request. */
@@ -1323,21 +1327,20 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
req_msg->service_id,
req_msg->private_data);
if (!listen_cm_id_priv) {
+ cm_cleanup_timewait(cm_id_priv->timewait_info);
spin_unlock_irqrestore(&cm.lock, flags);
cm_issue_rej(work->port, work->mad_recv_wc,
IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
NULL, 0);
- goto error;
+ goto out;
}
atomic_inc(&listen_cm_id_priv->refcount);
atomic_inc(&cm_id_priv->refcount);
cm_id_priv->id.state = IB_CM_REQ_RCVD;
atomic_inc(&cm_id_priv->work_count);
spin_unlock_irqrestore(&cm.lock, flags);
+out:
return listen_cm_id_priv;
-
-error: cm_cleanup_timewait(cm_id_priv->timewait_info);
- return NULL;
}
static int cm_req_handler(struct cm_work *work)
@@ -1899,6 +1902,32 @@ out: spin_unlock_irqrestore(&cm_id_priv->lock, flags);
}
EXPORT_SYMBOL(ib_send_cm_drep);
+static int cm_issue_drep(struct cm_port *port,
+ struct ib_mad_recv_wc *mad_recv_wc)
+{
+ struct ib_mad_send_buf *msg = NULL;
+ struct cm_dreq_msg *dreq_msg;
+ struct cm_drep_msg *drep_msg;
+ int ret;
+
+ ret = cm_alloc_response_msg(port, mad_recv_wc, &msg);
+ if (ret)
+ return ret;
+
+ dreq_msg = (struct cm_dreq_msg *) mad_recv_wc->recv_buf.mad;
+ drep_msg = (struct cm_drep_msg *) msg->mad;
+
+ cm_format_mad_hdr(&drep_msg->hdr, CM_DREP_ATTR_ID, dreq_msg->hdr.tid);
+ drep_msg->remote_comm_id = dreq_msg->local_comm_id;
+ drep_msg->local_comm_id = dreq_msg->remote_comm_id;
+
+ ret = ib_post_send_mad(msg, NULL);
+ if (ret)
+ cm_free_msg(msg);
+
+ return ret;
+}
+
static int cm_dreq_handler(struct cm_work *work)
{
struct cm_id_private *cm_id_priv;
@@ -1910,8 +1939,10 @@ static int cm_dreq_handler(struct cm_work *work)
dreq_msg = (struct cm_dreq_msg *)work->mad_recv_wc->recv_buf.mad;
cm_id_priv = cm_acquire_id(dreq_msg->remote_comm_id,
dreq_msg->local_comm_id);
- if (!cm_id_priv)
+ if (!cm_id_priv) {
+ cm_issue_drep(work->port, work->mad_recv_wc);
return -EINVAL;
+ }
work->cm_event.private_data = &dreq_msg->private_data;
@@ -2601,28 +2632,29 @@ static int cm_timewait_handler(struct cm_work *work)
{
struct cm_timewait_info *timewait_info;
struct cm_id_private *cm_id_priv;
- unsigned long flags;
int ret;
timewait_info = (struct cm_timewait_info *)work;
- cm_cleanup_timewait(timewait_info);
+ spin_lock_irq(&cm.lock);
+ list_del(&timewait_info->list);
+ spin_unlock_irq(&cm.lock);
cm_id_priv = cm_acquire_id(timewait_info->work.local_id,
timewait_info->work.remote_id);
if (!cm_id_priv)
return -EINVAL;
- spin_lock_irqsave(&cm_id_priv->lock, flags);
+ spin_lock_irq(&cm_id_priv->lock);
if (cm_id_priv->id.state != IB_CM_TIMEWAIT ||
cm_id_priv->remote_qpn != timewait_info->remote_qpn) {
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
goto out;
}
cm_id_priv->id.state = IB_CM_IDLE;
ret = atomic_inc_and_test(&cm_id_priv->work_count);
if (!ret)
list_add_tail(&work->list, &cm_id_priv->work_list);
- spin_unlock_irqrestore(&cm_id_priv->lock, flags);
+ spin_unlock_irq(&cm_id_priv->lock);
if (ret)
cm_process_work(cm_id_priv, work);
@@ -3374,6 +3406,7 @@ static int __init ib_cm_init(void)
idr_init(&cm.local_id_table);
get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand);
idr_pre_get(&cm.local_id_table, GFP_KERNEL);
+ INIT_LIST_HEAD(&cm.timewait_list);
cm.wq = create_workqueue("ib_cm");
if (!cm.wq)
@@ -3391,7 +3424,20 @@ error:
static void __exit ib_cm_cleanup(void)
{
+ struct cm_timewait_info *timewait_info, *tmp;
+
+ spin_lock_irq(&cm.lock);
+ list_for_each_entry(timewait_info, &cm.timewait_list, list)
+ cancel_delayed_work(&timewait_info->work.work);
+ spin_unlock_irq(&cm.lock);
+
destroy_workqueue(cm.wq);
+
+ list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) {
+ list_del(&timewait_info->list);
+ kfree(timewait_info);
+ }
+
ib_unregister_client(&cm_client);
idr_destroy(&cm.local_id_table);
}
diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c
index 1178bd434d1b..9ae4f3a67c70 100644
--- a/drivers/infiniband/core/cma.c
+++ b/drivers/infiniband/core/cma.c
@@ -874,23 +874,25 @@ static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id,
__u16 port;
u8 ip_ver;
+ if (cma_get_net_info(ib_event->private_data, listen_id->ps,
+ &ip_ver, &port, &src, &dst))
+ goto err;
+
id = rdma_create_id(listen_id->event_handler, listen_id->context,
listen_id->ps);
if (IS_ERR(id))
- return NULL;
+ goto err;
+
+ cma_save_net_info(&id->route.addr, &listen_id->route.addr,
+ ip_ver, port, src, dst);
rt = &id->route;
rt->num_paths = ib_event->param.req_rcvd.alternate_path ? 2 : 1;
- rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths, GFP_KERNEL);
+ rt->path_rec = kmalloc(sizeof *rt->path_rec * rt->num_paths,
+ GFP_KERNEL);
if (!rt->path_rec)
- goto err;
+ goto destroy_id;
- if (cma_get_net_info(ib_event->private_data, listen_id->ps,
- &ip_ver, &port, &src, &dst))
- goto err;
-
- cma_save_net_info(&id->route.addr, &listen_id->route.addr,
- ip_ver, port, src, dst);
rt->path_rec[0] = *ib_event->param.req_rcvd.primary_path;
if (rt->num_paths == 2)
rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path;
@@ -903,8 +905,10 @@ static struct rdma_id_private *cma_new_id(struct rdma_cm_id *listen_id,
id_priv = container_of(id, struct rdma_id_private, id);
id_priv->state = CMA_CONNECT;
return id_priv;
-err:
+
+destroy_id:
rdma_destroy_id(id);
+err:
return NULL;
}
@@ -932,6 +936,7 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event)
mutex_unlock(&lock);
if (ret) {
ret = -ENODEV;
+ cma_exch(conn_id, CMA_DESTROYING);
cma_release_remove(conn_id);
rdma_destroy_id(&conn_id->id);
goto out;
@@ -1307,6 +1312,7 @@ static void cma_query_handler(int status, struct ib_sa_path_rec *path_rec,
work->old_state = CMA_ROUTE_QUERY;
work->new_state = CMA_ADDR_RESOLVED;
work->event.event = RDMA_CM_EVENT_ROUTE_ERROR;
+ work->event.status = status;
}
queue_work(cma_wq, &work->work);
@@ -1862,6 +1868,11 @@ static int cma_connect_ib(struct rdma_id_private *id_priv,
ret = ib_send_cm_req(id_priv->cm_id.ib, &req);
out:
+ if (ret && !IS_ERR(id_priv->cm_id.ib)) {
+ ib_destroy_cm_id(id_priv->cm_id.ib);
+ id_priv->cm_id.ib = NULL;
+ }
+
kfree(private_data);
return ret;
}
@@ -1889,10 +1900,8 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
cm_id->remote_addr = *sin;
ret = cma_modify_qp_rtr(&id_priv->id);
- if (ret) {
- iw_destroy_cm_id(cm_id);
- return ret;
- }
+ if (ret)
+ goto out;
iw_param.ord = conn_param->initiator_depth;
iw_param.ird = conn_param->responder_resources;
@@ -1904,6 +1913,10 @@ static int cma_connect_iw(struct rdma_id_private *id_priv,
iw_param.qpn = conn_param->qp_num;
ret = iw_cm_connect(cm_id, &iw_param);
out:
+ if (ret && !IS_ERR(cm_id)) {
+ iw_destroy_cm_id(cm_id);
+ id_priv->cm_id.iw = NULL;
+ }
return ret;
}
@@ -2142,12 +2155,9 @@ static int cma_remove_id_dev(struct rdma_id_private *id_priv)
static void cma_process_remove(struct cma_device *cma_dev)
{
- struct list_head remove_list;
struct rdma_id_private *id_priv;
int ret;
- INIT_LIST_HEAD(&remove_list);
-
mutex_lock(&lock);
while (!list_empty(&cma_dev->id_list)) {
id_priv = list_entry(cma_dev->id_list.next,
@@ -2158,8 +2168,7 @@ static void cma_process_remove(struct cma_device *cma_dev)
continue;
}
- list_del(&id_priv->list);
- list_add_tail(&id_priv->list, &remove_list);
+ list_del_init(&id_priv->list);
atomic_inc(&id_priv->refcount);
mutex_unlock(&lock);
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c
index 082f03c158f0..493f4c65c7a2 100644
--- a/drivers/infiniband/core/mad.c
+++ b/drivers/infiniband/core/mad.c
@@ -2987,10 +2987,7 @@ error1:
static void __exit ib_mad_cleanup_module(void)
{
ib_unregister_client(&mad_client);
-
- if (kmem_cache_destroy(ib_mad_cache)) {
- printk(KERN_DEBUG PFX "Failed to destroy ib_mad cache\n");
- }
+ kmem_cache_destroy(ib_mad_cache);
}
module_init(ib_mad_init_module);
diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/infiniband/hw/amso1100/c2.c
index 9e9120f36019..9e7bd94b958a 100644
--- a/drivers/infiniband/hw/amso1100/c2.c
+++ b/drivers/infiniband/hw/amso1100/c2.c
@@ -72,7 +72,7 @@ static int c2_down(struct net_device *netdev);
static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static void c2_tx_interrupt(struct net_device *netdev);
static void c2_rx_interrupt(struct net_device *netdev);
-static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t c2_interrupt(int irq, void *dev_id);
static void c2_tx_timeout(struct net_device *netdev);
static int c2_change_mtu(struct net_device *netdev, int new_mtu);
static void c2_reset(struct c2_port *c2_port);
@@ -544,7 +544,7 @@ static void c2_rx_interrupt(struct net_device *netdev)
/*
* Handle netisr0 TX & RX interrupts.
*/
-static irqreturn_t c2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t c2_interrupt(int irq, void *dev_id)
{
unsigned int netisr0, dmaisr;
int handled = 0;
@@ -1243,7 +1243,7 @@ static struct pci_driver c2_pci_driver = {
static int __init c2_init_module(void)
{
- return pci_module_init(&c2_pci_driver);
+ return pci_register_driver(&c2_pci_driver);
}
static void __exit c2_exit_module(void)
diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/infiniband/hw/amso1100/c2_ae.c
index 08f46c83a3a4..a31439bd3b67 100644
--- a/drivers/infiniband/hw/amso1100/c2_ae.c
+++ b/drivers/infiniband/hw/amso1100/c2_ae.c
@@ -66,7 +66,6 @@ static int c2_convert_cm_status(u32 c2_status)
}
}
-#ifdef DEBUG
static const char* to_event_str(int event)
{
static const char* event_str[] = {
@@ -144,7 +143,6 @@ static const char *to_qp_state_str(int state)
return "<invalid QP state>";
};
}
-#endif
void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
{
@@ -197,7 +195,7 @@ void c2_ae_event(struct c2_dev *c2dev, u32 mq_index)
"resource=%x, qp_state=%s\n",
__FUNCTION__,
to_event_str(event_id),
- be64_to_cpu(wr->ae.ae_generic.user_context),
+ (unsigned long long) be64_to_cpu(wr->ae.ae_generic.user_context),
be32_to_cpu(wr->ae.ae_generic.resource_type),
be32_to_cpu(wr->ae.ae_generic.resource),
to_qp_state_str(be32_to_cpu(wr->ae.ae_generic.qp_state)));
diff --git a/drivers/infiniband/hw/amso1100/c2_alloc.c b/drivers/infiniband/hw/amso1100/c2_alloc.c
index 1d2529992c0c..028a60bbfca9 100644
--- a/drivers/infiniband/hw/amso1100/c2_alloc.c
+++ b/drivers/infiniband/hw/amso1100/c2_alloc.c
@@ -115,7 +115,7 @@ u16 *c2_alloc_mqsp(struct c2_dev *c2dev, struct sp_chunk *head,
((unsigned long) &(head->shared_ptr[mqsp]) -
(unsigned long) head);
pr_debug("%s addr %p dma_addr %llx\n", __FUNCTION__,
- &(head->shared_ptr[mqsp]), (u64)*dma_addr);
+ &(head->shared_ptr[mqsp]), (unsigned long long) *dma_addr);
return &(head->shared_ptr[mqsp]);
}
return NULL;
diff --git a/drivers/infiniband/hw/amso1100/c2_cm.c b/drivers/infiniband/hw/amso1100/c2_cm.c
index 485254efdd1e..75b93e9b8810 100644
--- a/drivers/infiniband/hw/amso1100/c2_cm.c
+++ b/drivers/infiniband/hw/amso1100/c2_cm.c
@@ -302,7 +302,7 @@ int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
vq_req = vq_req_alloc(c2dev);
if (!vq_req) {
err = -ENOMEM;
- goto bail1;
+ goto bail0;
}
vq_req->qp = qp;
vq_req->cm_id = cm_id;
@@ -311,7 +311,7 @@ int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);
if (!wr) {
err = -ENOMEM;
- goto bail2;
+ goto bail1;
}
/* Build the WR */
@@ -331,7 +331,7 @@ int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
/* Validate private_data length */
if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {
err = -EINVAL;
- goto bail2;
+ goto bail1;
}
if (iw_param->private_data) {
@@ -348,19 +348,19 @@ int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
err = vq_send_wr(c2dev, (union c2wr *) wr);
if (err) {
vq_req_put(c2dev, vq_req);
- goto bail2;
+ goto bail1;
}
/* Wait for reply from adapter */
err = vq_wait_for_reply(c2dev, vq_req);
if (err)
- goto bail2;
+ goto bail1;
/* Check that reply is present */
reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg;
if (!reply) {
err = -ENOMEM;
- goto bail2;
+ goto bail1;
}
err = c2_errno(reply);
@@ -368,9 +368,8 @@ int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)
if (!err)
c2_set_qp_state(qp, C2_QP_STATE_RTS);
- bail2:
- kfree(wr);
bail1:
+ kfree(wr);
vq_req_free(c2dev, vq_req);
bail0:
if (err) {
diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c
index dd6af551108b..da98d9f71429 100644
--- a/drivers/infiniband/hw/amso1100/c2_provider.c
+++ b/drivers/infiniband/hw/amso1100/c2_provider.c
@@ -390,14 +390,18 @@ static struct ib_mr *c2_reg_phys_mr(struct ib_pd *ib_pd,
}
mr = kmalloc(sizeof(*mr), GFP_KERNEL);
- if (!mr)
+ if (!mr) {
+ vfree(page_list);
return ERR_PTR(-ENOMEM);
+ }
mr->pd = to_c2pd(ib_pd);
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,
- *iova_start, page_list[0], page_list[pbl_depth-1]);
+ (unsigned long long) *iova_start,
+ (unsigned long long) page_list[0],
+ (unsigned long long) page_list[pbl_depth-1]);
err = c2_nsmr_register_phys_kern(to_c2dev(ib_pd->device), page_list,
(1 << page_shift), pbl_depth,
total_len, 0, iova_start,
diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/infiniband/hw/amso1100/c2_qp.c
index 12261132b077..5bcf697aa335 100644
--- a/drivers/infiniband/hw/amso1100/c2_qp.c
+++ b/drivers/infiniband/hw/amso1100/c2_qp.c
@@ -35,6 +35,8 @@
*
*/
+#include <linux/delay.h>
+
#include "c2.h"
#include "c2_vq.h"
#include "c2_status.h"
@@ -705,10 +707,8 @@ static inline void c2_activity(struct c2_dev *c2dev, u32 mq_index, u16 shared)
* cannot get on the bus and the card and system hang in a
* deadlock -- thus the need for this code. [TOT]
*/
- while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(0);
- }
+ while (readl(c2dev->regs + PCI_BAR0_ADAPTER_HINT) & 0x80000000)
+ udelay(10);
__raw_writel(C2_HINT_MAKE(mq_index, shared),
c2dev->regs + PCI_BAR0_ADAPTER_HINT);
@@ -766,6 +766,7 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
struct c2_dev *c2dev = to_c2dev(ibqp->device);
struct c2_qp *qp = to_c2qp(ibqp);
union c2wr wr;
+ unsigned long lock_flags;
int err = 0;
u32 flags;
@@ -881,8 +882,10 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
/*
* Post the puppy!
*/
+ spin_lock_irqsave(&qp->lock, lock_flags);
err = qp_wr_post(&qp->sq_mq, &wr, qp, msg_size);
if (err) {
+ spin_unlock_irqrestore(&qp->lock, lock_flags);
break;
}
@@ -890,6 +893,7 @@ int c2_post_send(struct ib_qp *ibqp, struct ib_send_wr *ib_wr,
* Enqueue mq index to activity FIFO.
*/
c2_activity(c2dev, qp->sq_mq.index, qp->sq_mq.hint_count);
+ spin_unlock_irqrestore(&qp->lock, lock_flags);
ib_wr = ib_wr->next;
}
@@ -905,6 +909,7 @@ int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
struct c2_dev *c2dev = to_c2dev(ibqp->device);
struct c2_qp *qp = to_c2qp(ibqp);
union c2wr wr;
+ unsigned long lock_flags;
int err = 0;
if (qp->state > IB_QPS_RTS)
@@ -945,8 +950,10 @@ int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
break;
}
+ spin_lock_irqsave(&qp->lock, lock_flags);
err = qp_wr_post(&qp->rq_mq, &wr, qp, qp->rq_mq.msg_size);
if (err) {
+ spin_unlock_irqrestore(&qp->lock, lock_flags);
break;
}
@@ -954,6 +961,7 @@ int c2_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *ib_wr,
* Enqueue mq index to activity FIFO
*/
c2_activity(c2dev, qp->rq_mq.index, qp->rq_mq.hint_count);
+ spin_unlock_irqrestore(&qp->lock, lock_flags);
ib_wr = ib_wr->next;
}
diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/infiniband/hw/amso1100/c2_rnic.c
index f49a32b7a8f6..30409e179606 100644
--- a/drivers/infiniband/hw/amso1100/c2_rnic.c
+++ b/drivers/infiniband/hw/amso1100/c2_rnic.c
@@ -150,8 +150,8 @@ static int c2_rnic_query(struct c2_dev *c2dev, struct ib_device_attr *props)
(struct c2wr_rnic_query_rep *) (unsigned long) (vq_req->reply_msg);
if (!reply)
err = -ENOMEM;
-
- err = c2_errno(reply);
+ else
+ err = c2_errno(reply);
if (err)
goto bail2;
@@ -527,7 +527,7 @@ int c2_rnic_init(struct c2_dev *c2dev)
DMA_FROM_DEVICE);
pci_unmap_addr_set(&c2dev->rep_vq, mapping, c2dev->rep_vq.host_dma);
pr_debug("%s rep_vq va %p dma %llx\n", __FUNCTION__, q1_pages,
- (u64)c2dev->rep_vq.host_dma);
+ (unsigned long long) c2dev->rep_vq.host_dma);
c2_mq_rep_init(&c2dev->rep_vq,
1,
qsize,
@@ -550,7 +550,7 @@ int c2_rnic_init(struct c2_dev *c2dev)
DMA_FROM_DEVICE);
pci_unmap_addr_set(&c2dev->aeq, mapping, c2dev->aeq.host_dma);
pr_debug("%s aeq va %p dma %llx\n", __FUNCTION__, q1_pages,
- (u64)c2dev->rep_vq.host_dma);
+ (unsigned long long) c2dev->rep_vq.host_dma);
c2_mq_rep_init(&c2dev->aeq,
2,
qsize,
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index 2a65b5be1979..048cc443d1e7 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -360,7 +360,7 @@ static inline void reset_eq_pending(struct ehca_cq *cq)
return;
}
-irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t ehca_interrupt_neq(int irq, void *dev_id)
{
struct ehca_shca *shca = (struct ehca_shca*)dev_id;
@@ -393,7 +393,7 @@ void ehca_tasklet_neq(unsigned long data)
return;
}
-irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t ehca_interrupt_eq(int irq, void *dev_id)
{
struct ehca_shca *shca = (struct ehca_shca*)dev_id;
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.h b/drivers/infiniband/hw/ehca/ehca_irq.h
index 85bf1fe16fe4..be579cc0adf6 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.h
+++ b/drivers/infiniband/hw/ehca/ehca_irq.h
@@ -51,10 +51,10 @@ struct ehca_shca;
int ehca_error_data(struct ehca_shca *shca, void *data, u64 resource);
-irqreturn_t ehca_interrupt_neq(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t ehca_interrupt_neq(int irq, void *dev_id);
void ehca_tasklet_neq(unsigned long data);
-irqreturn_t ehca_interrupt_eq(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t ehca_interrupt_eq(int irq, void *dev_id);
void ehca_tasklet_eq(unsigned long data);
struct ehca_cpu_comp_task {
diff --git a/drivers/infiniband/hw/ehca/ehca_main.c b/drivers/infiniband/hw/ehca/ehca_main.c
index 2380994418a5..024d511c4b58 100644
--- a/drivers/infiniband/hw/ehca/ehca_main.c
+++ b/drivers/infiniband/hw/ehca/ehca_main.c
@@ -49,7 +49,7 @@
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0016");
+MODULE_VERSION("SVNEHCA_0017");
int ehca_open_aqp1 = 0;
int ehca_debug_level = 0;
@@ -239,7 +239,7 @@ init_node_guid1:
return ret;
}
-int ehca_register_device(struct ehca_shca *shca)
+int ehca_init_device(struct ehca_shca *shca)
{
int ret;
@@ -317,11 +317,6 @@ int ehca_register_device(struct ehca_shca *shca)
/* shca->ib_device.process_mad = ehca_process_mad; */
shca->ib_device.mmap = ehca_mmap;
- ret = ib_register_device(&shca->ib_device);
- if (ret)
- ehca_err(&shca->ib_device,
- "ib_register_device() failed ret=%x", ret);
-
return ret;
}
@@ -561,9 +556,9 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
goto probe1;
}
- ret = ehca_register_device(shca);
+ ret = ehca_init_device(shca);
if (ret) {
- ehca_gen_err("Cannot register Infiniband device");
+ ehca_gen_err("Cannot init ehca device struct");
goto probe1;
}
@@ -571,7 +566,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
ret = ehca_create_eq(shca, &shca->eq, EHCA_EQ, 2048);
if (ret) {
ehca_err(&shca->ib_device, "Cannot create EQ.");
- goto probe2;
+ goto probe1;
}
ret = ehca_create_eq(shca, &shca->neq, EHCA_NEQ, 513);
@@ -600,6 +595,13 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
goto probe5;
}
+ ret = ib_register_device(&shca->ib_device);
+ if (ret) {
+ ehca_err(&shca->ib_device,
+ "ib_register_device() failed ret=%x", ret);
+ goto probe6;
+ }
+
/* create AQP1 for port 1 */
if (ehca_open_aqp1 == 1) {
shca->sport[0].port_state = IB_PORT_DOWN;
@@ -607,7 +609,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
if (ret) {
ehca_err(&shca->ib_device,
"Cannot create AQP1 for port 1.");
- goto probe6;
+ goto probe7;
}
}
@@ -618,7 +620,7 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
if (ret) {
ehca_err(&shca->ib_device,
"Cannot create AQP1 for port 2.");
- goto probe7;
+ goto probe8;
}
}
@@ -630,12 +632,15 @@ static int __devinit ehca_probe(struct ibmebus_dev *dev,
return 0;
-probe7:
+probe8:
ret = ehca_destroy_aqp1(&shca->sport[0]);
if (ret)
ehca_err(&shca->ib_device,
"Cannot destroy AQP1 for port 1. ret=%x", ret);
+probe7:
+ ib_unregister_device(&shca->ib_device);
+
probe6:
ret = ehca_dereg_internal_maxmr(shca);
if (ret)
@@ -660,9 +665,6 @@ probe3:
ehca_err(&shca->ib_device,
"Cannot destroy EQ. ret=%x", ret);
-probe2:
- ib_unregister_device(&shca->ib_device);
-
probe1:
ib_dealloc_device(&shca->ib_device);
@@ -750,7 +752,7 @@ int __init ehca_module_init(void)
int ret;
printk(KERN_INFO "eHCA Infiniband Device Driver "
- "(Rel.: SVNEHCA_0016)\n");
+ "(Rel.: SVNEHCA_0017)\n");
idr_init(&ehca_qp_idr);
idr_init(&ehca_cq_idr);
spin_lock_init(&ehca_qp_idr_lock);
diff --git a/drivers/infiniband/hw/ehca/ehca_tools.h b/drivers/infiniband/hw/ehca/ehca_tools.h
index 9f56bb846d93..809da3ef706b 100644
--- a/drivers/infiniband/hw/ehca/ehca_tools.h
+++ b/drivers/infiniband/hw/ehca/ehca_tools.h
@@ -117,7 +117,7 @@ extern int ehca_debug_level;
unsigned int l = (unsigned int)(len); \
unsigned char *deb = (unsigned char*)(adr); \
for (x = 0; x < l; x += 16) { \
- printk("EHCA_DMP:%s" format \
+ printk("EHCA_DMP:%s " format \
" adr=%p ofs=%04x %016lx %016lx\n", \
__FUNCTION__, ##args, deb, x, \
*((u64 *)&deb[0]), *((u64 *)&deb[8])); \
diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/infiniband/hw/ipath/ipath_common.h
index f577905e3aca..54139d398181 100644
--- a/drivers/infiniband/hw/ipath/ipath_common.h
+++ b/drivers/infiniband/hw/ipath/ipath_common.h
@@ -141,8 +141,9 @@ struct infinipath_stats {
* packets if ipath not configured, etc.)
*/
__u64 sps_krdrops;
+ __u64 sps_txeparity; /* PIO buffer parity error, recovered */
/* pad for future growth */
- __u64 __sps_pad[46];
+ __u64 __sps_pad[45];
};
/*
@@ -185,6 +186,9 @@ typedef enum _ipath_ureg {
#define IPATH_RUNTIME_PCIE 0x2
#define IPATH_RUNTIME_FORCE_WC_ORDER 0x4
#define IPATH_RUNTIME_RCVHDR_COPY 0x8
+#define IPATH_RUNTIME_MASTER 0x10
+#define IPATH_RUNTIME_PBC_REWRITE 0x20
+#define IPATH_RUNTIME_LOOSE_DMA_ALIGN 0x40
/*
* This structure is returned by ipath_userinit() immediately after
@@ -202,7 +206,8 @@ struct ipath_base_info {
/* version of software, for feature checking. */
__u32 spi_sw_version;
/* InfiniPath port assigned, goes into sent packets */
- __u32 spi_port;
+ __u16 spi_port;
+ __u16 spi_subport;
/*
* IB MTU, packets IB data must be less than this.
* The MTU is in bytes, and will be a multiple of 4 bytes.
@@ -218,7 +223,7 @@ struct ipath_base_info {
__u32 spi_tidcnt;
/* size of the TID Eager list in infinipath, in entries */
__u32 spi_tidegrcnt;
- /* size of a single receive header queue entry. */
+ /* size of a single receive header queue entry in words. */
__u32 spi_rcvhdrent_size;
/*
* Count of receive header queue entries allocated.
@@ -310,6 +315,12 @@ struct ipath_base_info {
__u32 spi_filler_for_align;
/* address of readonly memory copy of the rcvhdrq tail register. */
__u64 spi_rcvhdr_tailaddr;
+
+ /* shared memory pages for subports if IPATH_RUNTIME_MASTER is set */
+ __u64 spi_subport_uregbase;
+ __u64 spi_subport_rcvegrbuf;
+ __u64 spi_subport_rcvhdr_base;
+
} __attribute__ ((aligned(8)));
@@ -328,12 +339,12 @@ struct ipath_base_info {
/*
* Minor version differences are always compatible
- * a within a major version, however if if user software is larger
+ * a within a major version, however if user software is larger
* than driver software, some new features and/or structure fields
* may not be implemented; the user code must deal with this if it
- * cares, or it must abort after initialization reports the difference
+ * cares, or it must abort after initialization reports the difference.
*/
-#define IPATH_USER_SWMINOR 2
+#define IPATH_USER_SWMINOR 3
#define IPATH_USER_SWVERSION ((IPATH_USER_SWMAJOR<<16) | IPATH_USER_SWMINOR)
@@ -379,7 +390,16 @@ struct ipath_user_info {
*/
__u32 spu_rcvhdrsize;
- __u64 spu_unused; /* kept for compatible layout */
+ /*
+ * If two or more processes wish to share a port, each process
+ * must set the spu_subport_cnt and spu_subport_id to the same
+ * values. The only restriction on the spu_subport_id is that
+ * it be unique for a given node.
+ */
+ __u16 spu_subport_cnt;
+ __u16 spu_subport_id;
+
+ __u32 spu_unused; /* kept for compatible layout */
/*
* address of struct base_info to write to
@@ -392,19 +412,25 @@ struct ipath_user_info {
#define IPATH_CMD_MIN 16
-#define IPATH_CMD_USER_INIT 16 /* set up userspace */
+#define __IPATH_CMD_USER_INIT 16 /* old set up userspace (for old user code) */
#define IPATH_CMD_PORT_INFO 17 /* find out what resources we got */
#define IPATH_CMD_RECV_CTRL 18 /* control receipt of packets */
#define IPATH_CMD_TID_UPDATE 19 /* update expected TID entries */
#define IPATH_CMD_TID_FREE 20 /* free expected TID entries */
#define IPATH_CMD_SET_PART_KEY 21 /* add partition key */
+#define IPATH_CMD_SLAVE_INFO 22 /* return info on slave processes */
+#define IPATH_CMD_ASSIGN_PORT 23 /* allocate HCA and port */
+#define IPATH_CMD_USER_INIT 24 /* set up userspace */
-#define IPATH_CMD_MAX 21
+#define IPATH_CMD_MAX 24
struct ipath_port_info {
__u32 num_active; /* number of active units */
__u32 unit; /* unit (chip) assigned to caller */
- __u32 port; /* port on unit assigned to caller */
+ __u16 port; /* port on unit assigned to caller */
+ __u16 subport; /* subport on unit assigned to caller */
+ __u16 num_ports; /* number of ports available on unit */
+ __u16 num_subports; /* number of subport slaves opened on port */
};
struct ipath_tid_info {
@@ -435,6 +461,8 @@ struct ipath_cmd {
__u32 recv_ctrl;
/* partition key to set */
__u16 part_key;
+ /* user address of __u32 bitmask of active slaves */
+ __u64 slave_mask_addr;
} cmd;
};
@@ -596,6 +624,10 @@ struct infinipath_counters {
/* K_PktFlags bits */
#define INFINIPATH_KPF_INTR 0x1
+#define INFINIPATH_KPF_SUBPORT_MASK 0x3
+#define INFINIPATH_KPF_SUBPORT_SHIFT 1
+
+#define INFINIPATH_MAX_SUBPORT 4
/* SendPIO per-buffer control */
#define INFINIPATH_SP_TEST 0x40
@@ -610,7 +642,7 @@ struct ipath_header {
/*
* Version - 4 bits, Port - 4 bits, TID - 10 bits and Offset -
* 14 bits before ECO change ~28 Dec 03. After that, Vers 4,
- * Port 3, TID 11, offset 14.
+ * Port 4, TID 11, offset 13.
*/
__le32 ver_port_tid_offset;
__le16 chksum;
diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/infiniband/hw/ipath/ipath_cq.c
index 049221bc590e..87462e0cb4d2 100644
--- a/drivers/infiniband/hw/ipath/ipath_cq.c
+++ b/drivers/infiniband/hw/ipath/ipath_cq.c
@@ -46,7 +46,7 @@
*/
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
{
- struct ipath_cq_wc *wc = cq->queue;
+ struct ipath_cq_wc *wc;
unsigned long flags;
u32 head;
u32 next;
@@ -57,6 +57,7 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
* Note that the head pointer might be writable by user processes.
* Take care to verify it is a sane value.
*/
+ wc = cq->queue;
head = wc->head;
if (head >= (unsigned) cq->ibcq.cqe) {
head = cq->ibcq.cqe;
@@ -109,21 +110,27 @@ void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int solicited)
int ipath_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry)
{
struct ipath_cq *cq = to_icq(ibcq);
- struct ipath_cq_wc *wc = cq->queue;
+ struct ipath_cq_wc *wc;
unsigned long flags;
int npolled;
+ u32 tail;
spin_lock_irqsave(&cq->lock, flags);
+ wc = cq->queue;
+ tail = wc->tail;
+ if (tail > (u32) cq->ibcq.cqe)
+ tail = (u32) cq->ibcq.cqe;
for (npolled = 0; npolled < num_entries; ++npolled, ++entry) {
- if (wc->tail == wc->head)
+ if (tail == wc->head)
break;
- *entry = wc->queue[wc->tail];
- if (wc->tail >= cq->ibcq.cqe)
- wc->tail = 0;
+ *entry = wc->queue[tail];
+ if (tail >= cq->ibcq.cqe)
+ tail = 0;
else
- wc->tail++;
+ tail++;
}
+ wc->tail = tail;
spin_unlock_irqrestore(&cq->lock, flags);
@@ -177,11 +184,6 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
goto done;
}
- if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
- ret = ERR_PTR(-ENOMEM);
- goto done;
- }
-
/* Allocate the completion queue structure. */
cq = kmalloc(sizeof(*cq), GFP_KERNEL);
if (!cq) {
@@ -237,6 +239,16 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
} else
cq->ip = NULL;
+ spin_lock(&dev->n_cqs_lock);
+ if (dev->n_cqs_allocated == ib_ipath_max_cqs) {
+ spin_unlock(&dev->n_cqs_lock);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_wc;
+ }
+
+ dev->n_cqs_allocated++;
+ spin_unlock(&dev->n_cqs_lock);
+
/*
* ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe.
* The number of entries should be >= the number requested or return
@@ -253,7 +265,6 @@ struct ib_cq *ipath_create_cq(struct ib_device *ibdev, int entries,
ret = &cq->ibcq;
- dev->n_cqs_allocated++;
goto done;
bail_wc:
@@ -280,7 +291,9 @@ int ipath_destroy_cq(struct ib_cq *ibcq)
struct ipath_cq *cq = to_icq(ibcq);
tasklet_kill(&cq->comptask);
+ spin_lock(&dev->n_cqs_lock);
dev->n_cqs_allocated--;
+ spin_unlock(&dev->n_cqs_lock);
if (cq->ip)
kref_put(&cq->ip->ref, ipath_release_mmap_info);
else
@@ -316,10 +329,16 @@ int ipath_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify notify)
return 0;
}
+/**
+ * ipath_resize_cq - change the size of the CQ
+ * @ibcq: the completion queue
+ *
+ * Returns 0 for success.
+ */
int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
{
struct ipath_cq *cq = to_icq(ibcq);
- struct ipath_cq_wc *old_wc = cq->queue;
+ struct ipath_cq_wc *old_wc;
struct ipath_cq_wc *wc;
u32 head, tail, n;
int ret;
@@ -355,6 +374,7 @@ int ipath_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata)
* Make sure head and tail are sane since they
* might be user writable.
*/
+ old_wc = cq->queue;
head = old_wc->head;
if (head > (u32) cq->ibcq.cqe)
head = (u32) cq->ibcq.cqe;
diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/infiniband/hw/ipath/ipath_diag.c
index 29958b6e0214..28c087b824c2 100644
--- a/drivers/infiniband/hw/ipath/ipath_diag.c
+++ b/drivers/infiniband/hw/ipath/ipath_diag.c
@@ -67,19 +67,54 @@ static struct file_operations diag_file_ops = {
.release = ipath_diag_release
};
+static ssize_t ipath_diagpkt_write(struct file *fp,
+ const char __user *data,
+ size_t count, loff_t *off);
+
+static struct file_operations diagpkt_file_ops = {
+ .owner = THIS_MODULE,
+ .write = ipath_diagpkt_write,
+};
+
+static atomic_t diagpkt_count = ATOMIC_INIT(0);
+static struct cdev *diagpkt_cdev;
+static struct class_device *diagpkt_class_dev;
+
int ipath_diag_add(struct ipath_devdata *dd)
{
char name[16];
+ int ret = 0;
+
+ if (atomic_inc_return(&diagpkt_count) == 1) {
+ ret = ipath_cdev_init(IPATH_DIAGPKT_MINOR,
+ "ipath_diagpkt", &diagpkt_file_ops,
+ &diagpkt_cdev, &diagpkt_class_dev);
+
+ if (ret) {
+ ipath_dev_err(dd, "Couldn't create ipath_diagpkt "
+ "device: %d", ret);
+ goto done;
+ }
+ }
snprintf(name, sizeof(name), "ipath_diag%d", dd->ipath_unit);
- return ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
- &diag_file_ops, &dd->diag_cdev,
- &dd->diag_class_dev);
+ ret = ipath_cdev_init(IPATH_DIAG_MINOR_BASE + dd->ipath_unit, name,
+ &diag_file_ops, &dd->diag_cdev,
+ &dd->diag_class_dev);
+ if (ret)
+ ipath_dev_err(dd, "Couldn't create %s device: %d",
+ name, ret);
+
+done:
+ return ret;
}
void ipath_diag_remove(struct ipath_devdata *dd)
{
+ if (atomic_dec_and_test(&diagpkt_count))
+ ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev);
+
ipath_cdev_cleanup(&dd->diag_cdev, &dd->diag_class_dev);
}
@@ -275,30 +310,6 @@ bail:
return ret;
}
-static ssize_t ipath_diagpkt_write(struct file *fp,
- const char __user *data,
- size_t count, loff_t *off);
-
-static struct file_operations diagpkt_file_ops = {
- .owner = THIS_MODULE,
- .write = ipath_diagpkt_write,
-};
-
-static struct cdev *diagpkt_cdev;
-static struct class_device *diagpkt_class_dev;
-
-int __init ipath_diagpkt_add(void)
-{
- return ipath_cdev_init(IPATH_DIAGPKT_MINOR,
- "ipath_diagpkt", &diagpkt_file_ops,
- &diagpkt_cdev, &diagpkt_class_dev);
-}
-
-void __exit ipath_diagpkt_remove(void)
-{
- ipath_cdev_cleanup(&diagpkt_cdev, &diagpkt_class_dev);
-}
-
/**
* ipath_diagpkt_write - write an IB packet
* @fp: the diag data device file pointer
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index 2108466c7e33..b4ffaa7bcbb7 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -95,16 +95,6 @@ const char *ipath_ibcstatus_str[] = {
"RecovIdle",
};
-/*
- * These variables are initialized in the chip-specific files
- * but are defined here.
- */
-u16 ipath_gpio_sda_num, ipath_gpio_scl_num;
-u64 ipath_gpio_sda, ipath_gpio_scl;
-u64 infinipath_i_bitsextant;
-ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
-u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask;
-
static void __devexit ipath_remove_one(struct pci_dev *);
static int __devinit ipath_init_one(struct pci_dev *,
const struct pci_device_id *);
@@ -527,28 +517,146 @@ bail:
return ret;
}
+static void __devexit cleanup_device(struct ipath_devdata *dd)
+{
+ int port;
+
+ ipath_shutdown_device(dd);
+
+ if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
+ /* can't do anything more with chip; needs re-init */
+ *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
+ if (dd->ipath_kregbase) {
+ /*
+ * if we haven't already cleaned up before these are
+ * to ensure any register reads/writes "fail" until
+ * re-init
+ */
+ dd->ipath_kregbase = NULL;
+ dd->ipath_uregbase = 0;
+ dd->ipath_sregbase = 0;
+ dd->ipath_cregbase = 0;
+ dd->ipath_kregsize = 0;
+ }
+ ipath_disable_wc(dd);
+ }
+
+ if (dd->ipath_pioavailregs_dma) {
+ dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
+ (void *) dd->ipath_pioavailregs_dma,
+ dd->ipath_pioavailregs_phys);
+ dd->ipath_pioavailregs_dma = NULL;
+ }
+ if (dd->ipath_dummy_hdrq) {
+ dma_free_coherent(&dd->pcidev->dev,
+ dd->ipath_pd[0]->port_rcvhdrq_size,
+ dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
+ dd->ipath_dummy_hdrq = NULL;
+ }
+
+ if (dd->ipath_pageshadow) {
+ struct page **tmpp = dd->ipath_pageshadow;
+ dma_addr_t *tmpd = dd->ipath_physshadow;
+ int i, cnt = 0;
+
+ ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
+ "locked\n");
+ for (port = 0; port < dd->ipath_cfgports; port++) {
+ int port_tidbase = port * dd->ipath_rcvtidcnt;
+ int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
+ for (i = port_tidbase; i < maxtid; i++) {
+ if (!tmpp[i])
+ continue;
+ pci_unmap_page(dd->pcidev, tmpd[i],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
+ ipath_release_user_pages(&tmpp[i], 1);
+ tmpp[i] = NULL;
+ cnt++;
+ }
+ }
+ if (cnt) {
+ ipath_stats.sps_pageunlocks += cnt;
+ ipath_cdbg(VERBOSE, "There were still %u expTID "
+ "entries locked\n", cnt);
+ }
+ if (ipath_stats.sps_pagelocks ||
+ ipath_stats.sps_pageunlocks)
+ ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
+ "unlocked via ipath_m{un}lock\n",
+ (unsigned long long)
+ ipath_stats.sps_pagelocks,
+ (unsigned long long)
+ ipath_stats.sps_pageunlocks);
+
+ ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
+ dd->ipath_pageshadow);
+ vfree(dd->ipath_pageshadow);
+ dd->ipath_pageshadow = NULL;
+ }
+
+ /*
+ * free any resources still in use (usually just kernel ports)
+ * at unload; we do for portcnt, not cfgports, because cfgports
+ * could have changed while we were loaded.
+ */
+ for (port = 0; port < dd->ipath_portcnt; port++) {
+ struct ipath_portdata *pd = dd->ipath_pd[port];
+ dd->ipath_pd[port] = NULL;
+ ipath_free_pddata(dd, pd);
+ }
+ kfree(dd->ipath_pd);
+ /*
+ * debuggability, in case some cleanup path tries to use it
+ * after this
+ */
+ dd->ipath_pd = NULL;
+}
+
static void __devexit ipath_remove_one(struct pci_dev *pdev)
{
- struct ipath_devdata *dd;
+ struct ipath_devdata *dd = pci_get_drvdata(pdev);
- ipath_cdbg(VERBOSE, "removing, pdev=%p\n", pdev);
- if (!pdev)
- return;
+ ipath_cdbg(VERBOSE, "removing, pdev=%p, dd=%p\n", pdev, dd);
+
+ if (dd->verbs_dev)
+ ipath_unregister_ib_device(dd->verbs_dev);
- dd = pci_get_drvdata(pdev);
- ipath_unregister_ib_device(dd->verbs_dev);
ipath_diag_remove(dd);
ipath_user_remove(dd);
ipathfs_remove_device(dd);
ipath_device_remove_group(&pdev->dev, dd);
+
ipath_cdbg(VERBOSE, "Releasing pci memory regions, dd %p, "
"unit %u\n", dd, (u32) dd->ipath_unit);
- if (dd->ipath_kregbase) {
- ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n",
- dd->ipath_kregbase);
- iounmap((volatile void __iomem *) dd->ipath_kregbase);
- dd->ipath_kregbase = NULL;
- }
+
+ cleanup_device(dd);
+
+ /*
+ * turn off rcv, send, and interrupts for all ports, all drivers
+ * should also hard reset the chip here?
+ * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
+ * for all versions of the driver, if they were allocated
+ */
+ if (pdev->irq) {
+ ipath_cdbg(VERBOSE,
+ "unit %u free_irq of irq %x\n",
+ dd->ipath_unit, pdev->irq);
+ free_irq(pdev->irq, dd);
+ } else
+ ipath_dbg("irq is 0, not doing free_irq "
+ "for unit %u\n", dd->ipath_unit);
+ /*
+ * we check for NULL here, because it's outside
+ * the kregbase check, and we need to call it
+ * after the free_irq. Thus it's possible that
+ * the function pointers were never initialized.
+ */
+ if (dd->ipath_f_cleanup)
+ /* clean up chip-specific stuff */
+ dd->ipath_f_cleanup(dd);
+
+ ipath_cdbg(VERBOSE, "Unmapping kregbase %p\n", dd->ipath_kregbase);
+ iounmap((volatile void __iomem *) dd->ipath_kregbase);
pci_release_regions(pdev);
ipath_cdbg(VERBOSE, "calling pci_disable_device\n");
pci_disable_device(pdev);
@@ -760,8 +868,8 @@ static void get_rhf_errstring(u32 err, char *msg, size_t len)
static inline void *ipath_get_egrbuf(struct ipath_devdata *dd, u32 bufnum,
int err)
{
- return dd->ipath_port0_skbs ?
- (void *)dd->ipath_port0_skbs[bufnum]->data : NULL;
+ return dd->ipath_port0_skbinfo ?
+ (void *) dd->ipath_port0_skbinfo[bufnum].skb->data : NULL;
}
/**
@@ -783,31 +891,34 @@ struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd,
*/
/*
- * We need 4 extra bytes for unaligned transfer copying
+ * We need 2 extra bytes for ipath_ether data sent in the
+ * key header. In order to keep everything dword aligned,
+ * we'll reserve 4 bytes.
*/
+ len = dd->ipath_ibmaxlen + 4;
+
if (dd->ipath_flags & IPATH_4BYTE_TID) {
- /* we need a 4KB multiple alignment, and there is no way
+ /* We need a 2KB multiple alignment, and there is no way
* to do it except to allocate extra and then skb_reserve
* enough to bring it up to the right alignment.
*/
- len = dd->ipath_ibmaxlen + 4 + (1 << 11) - 1;
+ len += 2047;
}
- else
- len = dd->ipath_ibmaxlen + 4;
+
skb = __dev_alloc_skb(len, gfp_mask);
if (!skb) {
ipath_dev_err(dd, "Failed to allocate skbuff, length %u\n",
len);
goto bail;
}
+
+ skb_reserve(skb, 4);
+
if (dd->ipath_flags & IPATH_4BYTE_TID) {
- u32 una = ((1 << 11) - 1) & (unsigned long)(skb->data + 4);
+ u32 una = (unsigned long)skb->data & 2047;
if (una)
- skb_reserve(skb, 4 + (1 << 11) - una);
- else
- skb_reserve(skb, 4);
- } else
- skb_reserve(skb, 4);
+ skb_reserve(skb, 2048 - una);
+ }
bail:
return skb;
@@ -1326,6 +1437,9 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
"for port %u rcvhdrqtailaddr failed\n",
pd->port_port);
ret = -ENOMEM;
+ dma_free_coherent(&dd->pcidev->dev, amt,
+ pd->port_rcvhdrq, pd->port_rcvhdrq_phys);
+ pd->port_rcvhdrq = NULL;
goto bail;
}
pd->port_rcvhdrqtailaddr_phys = phys_hdrqtail;
@@ -1347,12 +1461,13 @@ int ipath_create_rcvhdrq(struct ipath_devdata *dd,
ipath_cdbg(VERBOSE, "reuse port %d rcvhdrq @%p %llx phys; "
"hdrtailaddr@%p %llx physical\n",
pd->port_port, pd->port_rcvhdrq,
- pd->port_rcvhdrq_phys, pd->port_rcvhdrtail_kvaddr,
- (unsigned long long)pd->port_rcvhdrqtailaddr_phys);
+ (unsigned long long) pd->port_rcvhdrq_phys,
+ pd->port_rcvhdrtail_kvaddr, (unsigned long long)
+ pd->port_rcvhdrqtailaddr_phys);
/* clear for security and sanity on each use */
memset(pd->port_rcvhdrq, 0, pd->port_rcvhdrq_size);
- memset((void *)pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
+ memset(pd->port_rcvhdrtail_kvaddr, 0, PAGE_SIZE);
/*
* tell chip each time we init it, even if we are re-using previous
@@ -1805,7 +1920,7 @@ void ipath_free_pddata(struct ipath_devdata *dd, struct ipath_portdata *pd)
pd->port_rcvhdrq = NULL;
if (pd->port_rcvhdrtail_kvaddr) {
dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
- (void *)pd->port_rcvhdrtail_kvaddr,
+ pd->port_rcvhdrtail_kvaddr,
pd->port_rcvhdrqtailaddr_phys);
pd->port_rcvhdrtail_kvaddr = NULL;
}
@@ -1824,24 +1939,32 @@ void ipath_free_pddata(struct ipath_devdata *dd, struct ipath_portdata *pd)
dma_free_coherent(&dd->pcidev->dev, size,
base, pd->port_rcvegrbuf_phys[e]);
}
- vfree(pd->port_rcvegrbuf);
+ kfree(pd->port_rcvegrbuf);
pd->port_rcvegrbuf = NULL;
- vfree(pd->port_rcvegrbuf_phys);
+ kfree(pd->port_rcvegrbuf_phys);
pd->port_rcvegrbuf_phys = NULL;
pd->port_rcvegrbuf_chunks = 0;
- } else if (pd->port_port == 0 && dd->ipath_port0_skbs) {
+ } else if (pd->port_port == 0 && dd->ipath_port0_skbinfo) {
unsigned e;
- struct sk_buff **skbs = dd->ipath_port0_skbs;
+ struct ipath_skbinfo *skbinfo = dd->ipath_port0_skbinfo;
- dd->ipath_port0_skbs = NULL;
- ipath_cdbg(VERBOSE, "free closed port %d ipath_port0_skbs "
- "@ %p\n", pd->port_port, skbs);
+ dd->ipath_port0_skbinfo = NULL;
+ ipath_cdbg(VERBOSE, "free closed port %d "
+ "ipath_port0_skbinfo @ %p\n", pd->port_port,
+ skbinfo);
for (e = 0; e < dd->ipath_rcvegrcnt; e++)
- if (skbs[e])
- dev_kfree_skb(skbs[e]);
- vfree(skbs);
+ if (skbinfo[e].skb) {
+ pci_unmap_single(dd->pcidev, skbinfo[e].phys,
+ dd->ipath_ibmaxlen,
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(skbinfo[e].skb);
+ }
+ vfree(skbinfo);
}
kfree(pd->port_tid_pg_list);
+ vfree(pd->subport_uregbase);
+ vfree(pd->subport_rcvegrbuf);
+ vfree(pd->subport_rcvhdr_base);
kfree(pd);
}
@@ -1882,18 +2005,8 @@ static int __init infinipath_init(void)
goto bail_group;
}
- ret = ipath_diagpkt_add();
- if (ret < 0) {
- printk(KERN_ERR IPATH_DRV_NAME ": Unable to create "
- "diag data device: error %d\n", -ret);
- goto bail_ipathfs;
- }
-
goto bail;
-bail_ipathfs:
- ipath_exit_ipathfs();
-
bail_group:
ipath_driver_remove_group(&ipath_driver.driver);
@@ -1907,150 +2020,12 @@ bail:
return ret;
}
-static void cleanup_device(struct ipath_devdata *dd)
-{
- int port;
-
- ipath_shutdown_device(dd);
-
- if (*dd->ipath_statusp & IPATH_STATUS_CHIP_PRESENT) {
- /* can't do anything more with chip; needs re-init */
- *dd->ipath_statusp &= ~IPATH_STATUS_CHIP_PRESENT;
- if (dd->ipath_kregbase) {
- /*
- * if we haven't already cleaned up before these are
- * to ensure any register reads/writes "fail" until
- * re-init
- */
- dd->ipath_kregbase = NULL;
- dd->ipath_uregbase = 0;
- dd->ipath_sregbase = 0;
- dd->ipath_cregbase = 0;
- dd->ipath_kregsize = 0;
- }
- ipath_disable_wc(dd);
- }
-
- if (dd->ipath_pioavailregs_dma) {
- dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE,
- (void *) dd->ipath_pioavailregs_dma,
- dd->ipath_pioavailregs_phys);
- dd->ipath_pioavailregs_dma = NULL;
- }
- if (dd->ipath_dummy_hdrq) {
- dma_free_coherent(&dd->pcidev->dev,
- dd->ipath_pd[0]->port_rcvhdrq_size,
- dd->ipath_dummy_hdrq, dd->ipath_dummy_hdrq_phys);
- dd->ipath_dummy_hdrq = NULL;
- }
-
- if (dd->ipath_pageshadow) {
- struct page **tmpp = dd->ipath_pageshadow;
- int i, cnt = 0;
-
- ipath_cdbg(VERBOSE, "Unlocking any expTID pages still "
- "locked\n");
- for (port = 0; port < dd->ipath_cfgports; port++) {
- int port_tidbase = port * dd->ipath_rcvtidcnt;
- int maxtid = port_tidbase + dd->ipath_rcvtidcnt;
- for (i = port_tidbase; i < maxtid; i++) {
- if (!tmpp[i])
- continue;
- ipath_release_user_pages(&tmpp[i], 1);
- tmpp[i] = NULL;
- cnt++;
- }
- }
- if (cnt) {
- ipath_stats.sps_pageunlocks += cnt;
- ipath_cdbg(VERBOSE, "There were still %u expTID "
- "entries locked\n", cnt);
- }
- if (ipath_stats.sps_pagelocks ||
- ipath_stats.sps_pageunlocks)
- ipath_cdbg(VERBOSE, "%llu pages locked, %llu "
- "unlocked via ipath_m{un}lock\n",
- (unsigned long long)
- ipath_stats.sps_pagelocks,
- (unsigned long long)
- ipath_stats.sps_pageunlocks);
-
- ipath_cdbg(VERBOSE, "Free shadow page tid array at %p\n",
- dd->ipath_pageshadow);
- vfree(dd->ipath_pageshadow);
- dd->ipath_pageshadow = NULL;
- }
-
- /*
- * free any resources still in use (usually just kernel ports)
- * at unload; we do for portcnt, not cfgports, because cfgports
- * could have changed while we were loaded.
- */
- for (port = 0; port < dd->ipath_portcnt; port++) {
- struct ipath_portdata *pd = dd->ipath_pd[port];
- dd->ipath_pd[port] = NULL;
- ipath_free_pddata(dd, pd);
- }
- kfree(dd->ipath_pd);
- /*
- * debuggability, in case some cleanup path tries to use it
- * after this
- */
- dd->ipath_pd = NULL;
-}
-
static void __exit infinipath_cleanup(void)
{
- struct ipath_devdata *dd, *tmp;
- unsigned long flags;
-
- ipath_diagpkt_remove();
-
ipath_exit_ipathfs();
ipath_driver_remove_group(&ipath_driver.driver);
- spin_lock_irqsave(&ipath_devs_lock, flags);
-
- /*
- * turn off rcv, send, and interrupts for all ports, all drivers
- * should also hard reset the chip here?
- * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs
- * for all versions of the driver, if they were allocated
- */
- list_for_each_entry_safe(dd, tmp, &ipath_dev_list, ipath_list) {
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
- if (dd->ipath_kregbase)
- cleanup_device(dd);
-
- if (dd->pcidev) {
- if (dd->pcidev->irq) {
- ipath_cdbg(VERBOSE,
- "unit %u free_irq of irq %x\n",
- dd->ipath_unit, dd->pcidev->irq);
- free_irq(dd->pcidev->irq, dd);
- } else
- ipath_dbg("irq is 0, not doing free_irq "
- "for unit %u\n", dd->ipath_unit);
-
- /*
- * we check for NULL here, because it's outside
- * the kregbase check, and we need to call it
- * after the free_irq. Thus it's possible that
- * the function pointers were never initialized.
- */
- if (dd->ipath_f_cleanup)
- /* clean up chip-specific stuff */
- dd->ipath_f_cleanup(dd);
-
- dd->pcidev = NULL;
- }
- spin_lock_irqsave(&ipath_devs_lock, flags);
- }
-
- spin_unlock_irqrestore(&ipath_devs_lock, flags);
-
ipath_cdbg(VERBOSE, "Unregistering pci driver\n");
pci_unregister_driver(&ipath_driver);
diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/infiniband/hw/ipath/ipath_eeprom.c
index 3313356ab93a..a4019a6b7560 100644
--- a/drivers/infiniband/hw/ipath/ipath_eeprom.c
+++ b/drivers/infiniband/hw/ipath/ipath_eeprom.c
@@ -100,9 +100,9 @@ static int i2c_gpio_set(struct ipath_devdata *dd,
gpioval = &dd->ipath_gpio_out;
read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
if (line == i2c_line_scl)
- mask = ipath_gpio_scl;
+ mask = dd->ipath_gpio_scl;
else
- mask = ipath_gpio_sda;
+ mask = dd->ipath_gpio_sda;
if (new_line_state == i2c_line_high)
/* tri-state the output rather than force high */
@@ -119,12 +119,12 @@ static int i2c_gpio_set(struct ipath_devdata *dd,
write_val = 0x0UL;
if (line == i2c_line_scl) {
- write_val <<= ipath_gpio_scl_num;
- *gpioval = *gpioval & ~(1UL << ipath_gpio_scl_num);
+ write_val <<= dd->ipath_gpio_scl_num;
+ *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_scl_num);
*gpioval |= write_val;
} else {
- write_val <<= ipath_gpio_sda_num;
- *gpioval = *gpioval & ~(1UL << ipath_gpio_sda_num);
+ write_val <<= dd->ipath_gpio_sda_num;
+ *gpioval = *gpioval & ~(1UL << dd->ipath_gpio_sda_num);
*gpioval |= write_val;
}
ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval);
@@ -157,9 +157,9 @@ static int i2c_gpio_get(struct ipath_devdata *dd,
read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl);
/* config line to be an input */
if (line == i2c_line_scl)
- mask = ipath_gpio_scl;
+ mask = dd->ipath_gpio_scl;
else
- mask = ipath_gpio_sda;
+ mask = dd->ipath_gpio_sda;
write_val = read_val & ~mask;
ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, write_val);
read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus);
@@ -187,6 +187,7 @@ bail:
static void i2c_wait_for_writes(struct ipath_devdata *dd)
{
(void)ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch);
+ rmb();
}
static void scl_out(struct ipath_devdata *dd, u8 bit)
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 29930e22318e..a9ddc6911f66 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -41,6 +41,12 @@
#include "ipath_kernel.h"
#include "ipath_common.h"
+/*
+ * mmap64 doesn't allow all 64 bits for 32-bit applications
+ * so only use the low 43 bits.
+ */
+#define MMAP64_MASK 0x7FFFFFFFFFFUL
+
static int ipath_open(struct inode *, struct file *);
static int ipath_close(struct inode *, struct file *);
static ssize_t ipath_write(struct file *, const char __user *, size_t,
@@ -57,18 +63,35 @@ static struct file_operations ipath_file_ops = {
.mmap = ipath_mmap
};
-static int ipath_get_base_info(struct ipath_portdata *pd,
+static int ipath_get_base_info(struct file *fp,
void __user *ubase, size_t ubase_size)
{
+ struct ipath_portdata *pd = port_fp(fp);
int ret = 0;
struct ipath_base_info *kinfo = NULL;
struct ipath_devdata *dd = pd->port_dd;
+ unsigned subport_cnt;
+ int shared, master;
+ size_t sz;
+
+ subport_cnt = pd->port_subport_cnt;
+ if (!subport_cnt) {
+ shared = 0;
+ master = 0;
+ subport_cnt = 1;
+ } else {
+ shared = 1;
+ master = !subport_fp(fp);
+ }
- if (ubase_size < sizeof(*kinfo)) {
+ sz = sizeof(*kinfo);
+ /* If port sharing is not requested, allow the old size structure */
+ if (!shared)
+ sz -= 3 * sizeof(u64);
+ if (ubase_size < sz) {
ipath_cdbg(PROC,
- "Base size %lu, need %lu (version mismatch?)\n",
- (unsigned long) ubase_size,
- (unsigned long) sizeof(*kinfo));
+ "Base size %zu, need %zu (version mismatch?)\n",
+ ubase_size, sz);
ret = -EINVAL;
goto bail;
}
@@ -95,7 +118,9 @@ static int ipath_get_base_info(struct ipath_portdata *pd,
kinfo->spi_rcv_egrperchunk = pd->port_rcvegrbufs_perchunk;
kinfo->spi_rcv_egrchunksize = kinfo->spi_rcv_egrbuftotlen /
pd->port_rcvegrbuf_chunks;
- kinfo->spi_tidcnt = dd->ipath_rcvtidcnt;
+ kinfo->spi_tidcnt = dd->ipath_rcvtidcnt / subport_cnt;
+ if (master)
+ kinfo->spi_tidcnt += dd->ipath_rcvtidcnt % subport_cnt;
/*
* for this use, may be ipath_cfgports summed over all chips that
* are are configured and present
@@ -118,31 +143,75 @@ static int ipath_get_base_info(struct ipath_portdata *pd,
* page_address() macro worked, but in 2.6.11, even that returns the
* full 64 bit address (upper bits all 1's). So far, using the
* physical addresses (or chip offsets, for chip mapping) works, but
- * no doubt some future kernel release will chang that, and we'll be
- * on to yet another method of dealing with this
+ * no doubt some future kernel release will change that, and we'll be
+ * on to yet another method of dealing with this.
*/
kinfo->spi_rcvhdr_base = (u64) pd->port_rcvhdrq_phys;
- kinfo->spi_rcvhdr_tailaddr = (u64)pd->port_rcvhdrqtailaddr_phys;
+ kinfo->spi_rcvhdr_tailaddr = (u64) pd->port_rcvhdrqtailaddr_phys;
kinfo->spi_rcv_egrbufs = (u64) pd->port_rcvegr_phys;
kinfo->spi_pioavailaddr = (u64) dd->ipath_pioavailregs_phys;
kinfo->spi_status = (u64) kinfo->spi_pioavailaddr +
(void *) dd->ipath_statusp -
(void *) dd->ipath_pioavailregs_dma;
- kinfo->spi_piobufbase = (u64) pd->port_piobufs;
- kinfo->__spi_uregbase =
- dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+ if (!shared) {
+ kinfo->spi_piocnt = dd->ipath_pbufsport;
+ kinfo->spi_piobufbase = (u64) pd->port_piobufs;
+ kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
+ dd->ipath_palign * pd->port_port;
+ } else if (master) {
+ kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
+ (dd->ipath_pbufsport % subport_cnt);
+ /* Master's PIO buffers are after all the slave's */
+ kinfo->spi_piobufbase = (u64) pd->port_piobufs +
+ dd->ipath_palign *
+ (dd->ipath_pbufsport - kinfo->spi_piocnt);
+ kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
+ dd->ipath_palign * pd->port_port;
+ } else {
+ unsigned slave = subport_fp(fp) - 1;
+
+ kinfo->spi_piocnt = dd->ipath_pbufsport / subport_cnt;
+ kinfo->spi_piobufbase = (u64) pd->port_piobufs +
+ dd->ipath_palign * kinfo->spi_piocnt * slave;
+ kinfo->__spi_uregbase = ((u64) pd->subport_uregbase +
+ PAGE_SIZE * slave) & MMAP64_MASK;
- kinfo->spi_pioindex = dd->ipath_pbufsport * (pd->port_port - 1);
- kinfo->spi_piocnt = dd->ipath_pbufsport;
+ kinfo->spi_rcvhdr_base = ((u64) pd->subport_rcvhdr_base +
+ pd->port_rcvhdrq_size * slave) & MMAP64_MASK;
+ kinfo->spi_rcvhdr_tailaddr =
+ (u64) pd->port_rcvhdrqtailaddr_phys & MMAP64_MASK;
+ kinfo->spi_rcv_egrbufs = ((u64) pd->subport_rcvegrbuf +
+ dd->ipath_rcvegrcnt * dd->ipath_rcvegrbufsize * slave) &
+ MMAP64_MASK;
+ }
+
+ kinfo->spi_pioindex = (kinfo->spi_piobufbase - dd->ipath_piobufbase) /
+ dd->ipath_palign;
kinfo->spi_pioalign = dd->ipath_palign;
kinfo->spi_qpair = IPATH_KD_QP;
kinfo->spi_piosize = dd->ipath_ibmaxlen;
kinfo->spi_mtu = dd->ipath_ibmaxlen; /* maxlen, not ibmtu */
kinfo->spi_port = pd->port_port;
+ kinfo->spi_subport = subport_fp(fp);
kinfo->spi_sw_version = IPATH_KERN_SWVERSION;
kinfo->spi_hw_version = dd->ipath_revision;
+ if (master) {
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_MASTER;
+ kinfo->spi_subport_uregbase =
+ (u64) pd->subport_uregbase & MMAP64_MASK;
+ kinfo->spi_subport_rcvegrbuf =
+ (u64) pd->subport_rcvegrbuf & MMAP64_MASK;
+ kinfo->spi_subport_rcvhdr_base =
+ (u64) pd->subport_rcvhdr_base & MMAP64_MASK;
+ ipath_cdbg(PROC, "port %u flags %x %llx %llx %llx\n",
+ kinfo->spi_port, kinfo->spi_runtime_flags,
+ (unsigned long long) kinfo->spi_subport_uregbase,
+ (unsigned long long) kinfo->spi_subport_rcvegrbuf,
+ (unsigned long long) kinfo->spi_subport_rcvhdr_base);
+ }
+
if (copy_to_user(ubase, kinfo, sizeof(*kinfo)))
ret = -EFAULT;
@@ -154,6 +223,7 @@ bail:
/**
* ipath_tid_update - update a port TID
* @pd: the port
+ * @fp: the ipath device file
* @ti: the TID information
*
* The new implementation as of Oct 2004 is that the driver assigns
@@ -176,11 +246,11 @@ bail:
* virtually contiguous pages, that should change to improve
* performance.
*/
-static int ipath_tid_update(struct ipath_portdata *pd,
+static int ipath_tid_update(struct ipath_portdata *pd, struct file *fp,
const struct ipath_tid_info *ti)
{
int ret = 0, ntids;
- u32 tid, porttid, cnt, i, tidcnt;
+ u32 tid, porttid, cnt, i, tidcnt, tidoff;
u16 *tidlist;
struct ipath_devdata *dd = pd->port_dd;
u64 physaddr;
@@ -188,6 +258,7 @@ static int ipath_tid_update(struct ipath_portdata *pd,
u64 __iomem *tidbase;
unsigned long tidmap[8];
struct page **pagep = NULL;
+ unsigned subport = subport_fp(fp);
if (!dd->ipath_pageshadow) {
ret = -ENOMEM;
@@ -204,20 +275,34 @@ static int ipath_tid_update(struct ipath_portdata *pd,
ret = -EFAULT;
goto done;
}
- tidcnt = dd->ipath_rcvtidcnt;
- if (cnt >= tidcnt) {
+ porttid = pd->port_port * dd->ipath_rcvtidcnt;
+ if (!pd->port_subport_cnt) {
+ tidcnt = dd->ipath_rcvtidcnt;
+ tid = pd->port_tidcursor;
+ tidoff = 0;
+ } else if (!subport) {
+ tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
+ (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
+ tidoff = dd->ipath_rcvtidcnt - tidcnt;
+ porttid += tidoff;
+ tid = tidcursor_fp(fp);
+ } else {
+ tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
+ tidoff = tidcnt * (subport - 1);
+ porttid += tidoff;
+ tid = tidcursor_fp(fp);
+ }
+ if (cnt > tidcnt) {
/* make sure it all fits in port_tid_pg_list */
dev_info(&dd->pcidev->dev, "Process tried to allocate %u "
"TIDs, only trying max (%u)\n", cnt, tidcnt);
cnt = tidcnt;
}
- pagep = (struct page **)pd->port_tid_pg_list;
- tidlist = (u16 *) (&pagep[cnt]);
+ pagep = &((struct page **) pd->port_tid_pg_list)[tidoff];
+ tidlist = &((u16 *) &pagep[dd->ipath_rcvtidcnt])[tidoff];
memset(tidmap, 0, sizeof(tidmap));
- tid = pd->port_tidcursor;
/* before decrement; chip actual # */
- porttid = pd->port_port * tidcnt;
ntids = tidcnt;
tidbase = (u64 __iomem *) (((char __iomem *) dd->ipath_kregbase) +
dd->ipath_rcvtidbase +
@@ -274,16 +359,19 @@ static int ipath_tid_update(struct ipath_portdata *pd,
ret = -ENOMEM;
break;
}
- tidlist[i] = tid;
+ tidlist[i] = tid + tidoff;
ipath_cdbg(VERBOSE, "Updating idx %u to TID %u, "
- "vaddr %lx\n", i, tid, vaddr);
+ "vaddr %lx\n", i, tid + tidoff, vaddr);
/* we "know" system pages and TID pages are same size */
dd->ipath_pageshadow[porttid + tid] = pagep[i];
+ dd->ipath_physshadow[porttid + tid] = ipath_map_page(
+ dd->pcidev, pagep[i], 0, PAGE_SIZE,
+ PCI_DMA_FROMDEVICE);
/*
* don't need atomic or it's overhead
*/
__set_bit(tid, tidmap);
- physaddr = page_to_phys(pagep[i]);
+ physaddr = dd->ipath_physshadow[porttid + tid];
ipath_stats.sps_pagelocks++;
ipath_cdbg(VERBOSE,
"TID %u, vaddr %lx, physaddr %llx pgp %p\n",
@@ -317,6 +405,9 @@ static int ipath_tid_update(struct ipath_portdata *pd,
tid);
dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
dd->ipath_tidinvalid);
+ pci_unmap_page(dd->pcidev,
+ dd->ipath_physshadow[porttid + tid],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
dd->ipath_pageshadow[porttid + tid] = NULL;
ipath_stats.sps_pageunlocks++;
}
@@ -341,7 +432,10 @@ static int ipath_tid_update(struct ipath_portdata *pd,
}
if (tid == tidcnt)
tid = 0;
- pd->port_tidcursor = tid;
+ if (!pd->port_subport_cnt)
+ pd->port_tidcursor = tid;
+ else
+ tidcursor_fp(fp) = tid;
}
done:
@@ -354,6 +448,7 @@ done:
/**
* ipath_tid_free - free a port TID
* @pd: the port
+ * @subport: the subport
* @ti: the TID info
*
* right now we are unlocking one page at a time, but since
@@ -367,7 +462,7 @@ done:
* they pass in to us.
*/
-static int ipath_tid_free(struct ipath_portdata *pd,
+static int ipath_tid_free(struct ipath_portdata *pd, unsigned subport,
const struct ipath_tid_info *ti)
{
int ret = 0;
@@ -388,11 +483,20 @@ static int ipath_tid_free(struct ipath_portdata *pd,
}
porttid = pd->port_port * dd->ipath_rcvtidcnt;
+ if (!pd->port_subport_cnt)
+ tidcnt = dd->ipath_rcvtidcnt;
+ else if (!subport) {
+ tidcnt = (dd->ipath_rcvtidcnt / pd->port_subport_cnt) +
+ (dd->ipath_rcvtidcnt % pd->port_subport_cnt);
+ porttid += dd->ipath_rcvtidcnt - tidcnt;
+ } else {
+ tidcnt = dd->ipath_rcvtidcnt / pd->port_subport_cnt;
+ porttid += tidcnt * (subport - 1);
+ }
tidbase = (u64 __iomem *) ((char __iomem *)(dd->ipath_kregbase) +
dd->ipath_rcvtidbase +
porttid * sizeof(*tidbase));
- tidcnt = dd->ipath_rcvtidcnt;
limit = sizeof(tidmap) * BITS_PER_BYTE;
if (limit > tidcnt)
/* just in case size changes in future */
@@ -417,6 +521,9 @@ static int ipath_tid_free(struct ipath_portdata *pd,
pd->port_pid, tid);
dd->ipath_f_put_tid(dd, &tidbase[tid], 1,
dd->ipath_tidinvalid);
+ pci_unmap_page(dd->pcidev,
+ dd->ipath_physshadow[porttid + tid],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
ipath_release_user_pages(
&dd->ipath_pageshadow[porttid + tid], 1);
dd->ipath_pageshadow[porttid + tid] = NULL;
@@ -581,20 +688,24 @@ bail:
/**
* ipath_manage_rcvq - manage a port's receive queue
* @pd: the port
+ * @subport: the subport
* @start_stop: action to carry out
*
* start_stop == 0 disables receive on the port, for use in queue
* overflow conditions. start_stop==1 re-enables, to be used to
* re-init the software copy of the head register
*/
-static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop)
+static int ipath_manage_rcvq(struct ipath_portdata *pd, unsigned subport,
+ int start_stop)
{
struct ipath_devdata *dd = pd->port_dd;
u64 tval;
- ipath_cdbg(PROC, "%sabling rcv for unit %u port %u\n",
+ ipath_cdbg(PROC, "%sabling rcv for unit %u port %u:%u\n",
start_stop ? "en" : "dis", dd->ipath_unit,
- pd->port_port);
+ pd->port_port, subport);
+ if (subport)
+ goto bail;
/* atomically clear receive enable port. */
if (start_stop) {
/*
@@ -609,7 +720,7 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop)
* updated and correct itself, even in the face of software
* bugs.
*/
- *pd->port_rcvhdrtail_kvaddr = 0;
+ *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0;
set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
&dd->ipath_rcvctrl);
} else
@@ -630,6 +741,7 @@ static int ipath_manage_rcvq(struct ipath_portdata *pd, int start_stop)
tval = ipath_read_ureg32(dd, ur_rcvhdrtail, pd->port_port);
}
/* always; new head should be equal to new tail; see above */
+bail:
return 0;
}
@@ -687,6 +799,36 @@ static void ipath_clean_part_key(struct ipath_portdata *pd,
}
}
+/*
+ * Initialize the port data with the receive buffer sizes
+ * so this can be done while the master port is locked.
+ * Otherwise, there is a race with a slave opening the port
+ * and seeing these fields uninitialized.
+ */
+static void init_user_egr_sizes(struct ipath_portdata *pd)
+{
+ struct ipath_devdata *dd = pd->port_dd;
+ unsigned egrperchunk, egrcnt, size;
+
+ /*
+ * to avoid wasting a lot of memory, we allocate 32KB chunks of
+ * physically contiguous memory, advance through it until used up
+ * and then allocate more. Of course, we need memory to store those
+ * extra pointers, now. Started out with 256KB, but under heavy
+ * memory pressure (creating large files and then copying them over
+ * NFS while doing lots of MPI jobs), we hit some allocation
+ * failures, even though we can sleep... (2.6.10) Still get
+ * failures at 64K. 32K is the lowest we can go without wasting
+ * additional memory.
+ */
+ size = 0x8000;
+ egrperchunk = size / dd->ipath_rcvegrbufsize;
+ egrcnt = dd->ipath_rcvegrcnt;
+ pd->port_rcvegrbuf_chunks = (egrcnt + egrperchunk - 1) / egrperchunk;
+ pd->port_rcvegrbufs_perchunk = egrperchunk;
+ pd->port_rcvegrbuf_size = size;
+}
+
/**
* ipath_create_user_egr - allocate eager TID buffers
* @pd: the port to allocate TID buffers for
@@ -702,7 +844,7 @@ static void ipath_clean_part_key(struct ipath_portdata *pd,
static int ipath_create_user_egr(struct ipath_portdata *pd)
{
struct ipath_devdata *dd = pd->port_dd;
- unsigned e, egrcnt, alloced, egrperchunk, chunk, egrsize, egroff;
+ unsigned e, egrcnt, egrperchunk, chunk, egrsize, egroff;
size_t size;
int ret;
gfp_t gfp_flags;
@@ -722,31 +864,18 @@ static int ipath_create_user_egr(struct ipath_portdata *pd)
ipath_cdbg(VERBOSE, "Allocating %d egr buffers, at egrtid "
"offset %x, egrsize %u\n", egrcnt, egroff, egrsize);
- /*
- * to avoid wasting a lot of memory, we allocate 32KB chunks of
- * physically contiguous memory, advance through it until used up
- * and then allocate more. Of course, we need memory to store those
- * extra pointers, now. Started out with 256KB, but under heavy
- * memory pressure (creating large files and then copying them over
- * NFS while doing lots of MPI jobs), we hit some allocation
- * failures, even though we can sleep... (2.6.10) Still get
- * failures at 64K. 32K is the lowest we can go without wasting
- * additional memory.
- */
- size = 0x8000;
- alloced = ALIGN(egrsize * egrcnt, size);
- egrperchunk = size / egrsize;
- chunk = (egrcnt + egrperchunk - 1) / egrperchunk;
- pd->port_rcvegrbuf_chunks = chunk;
- pd->port_rcvegrbufs_perchunk = egrperchunk;
- pd->port_rcvegrbuf_size = size;
- pd->port_rcvegrbuf = vmalloc(chunk * sizeof(pd->port_rcvegrbuf[0]));
+ chunk = pd->port_rcvegrbuf_chunks;
+ egrperchunk = pd->port_rcvegrbufs_perchunk;
+ size = pd->port_rcvegrbuf_size;
+ pd->port_rcvegrbuf = kmalloc(chunk * sizeof(pd->port_rcvegrbuf[0]),
+ GFP_KERNEL);
if (!pd->port_rcvegrbuf) {
ret = -ENOMEM;
goto bail;
}
pd->port_rcvegrbuf_phys =
- vmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0]));
+ kmalloc(chunk * sizeof(pd->port_rcvegrbuf_phys[0]),
+ GFP_KERNEL);
if (!pd->port_rcvegrbuf_phys) {
ret = -ENOMEM;
goto bail_rcvegrbuf;
@@ -791,105 +920,23 @@ bail_rcvegrbuf_phys:
pd->port_rcvegrbuf_phys[e]);
}
- vfree(pd->port_rcvegrbuf_phys);
+ kfree(pd->port_rcvegrbuf_phys);
pd->port_rcvegrbuf_phys = NULL;
bail_rcvegrbuf:
- vfree(pd->port_rcvegrbuf);
+ kfree(pd->port_rcvegrbuf);
pd->port_rcvegrbuf = NULL;
bail:
return ret;
}
-static int ipath_do_user_init(struct ipath_portdata *pd,
- const struct ipath_user_info *uinfo)
-{
- int ret = 0;
- struct ipath_devdata *dd = pd->port_dd;
- u32 head32;
-
- /* for now, if major version is different, bail */
- if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) {
- dev_info(&dd->pcidev->dev,
- "User major version %d not same as driver "
- "major %d\n", uinfo->spu_userversion >> 16,
- IPATH_USER_SWMAJOR);
- ret = -ENODEV;
- goto done;
- }
-
- if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR)
- ipath_dbg("User minor version %d not same as driver "
- "minor %d\n", uinfo->spu_userversion & 0xffff,
- IPATH_USER_SWMINOR);
-
- if (uinfo->spu_rcvhdrsize) {
- ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize);
- if (ret)
- goto done;
- }
-
- /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
-
- /* for right now, kernel piobufs are at end, so port 1 is at 0 */
- pd->port_piobufs = dd->ipath_piobufbase +
- dd->ipath_pbufsport * (pd->port_port -
- 1) * dd->ipath_palign;
- ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
- pd->port_port, pd->port_piobufs);
-
- /*
- * Now allocate the rcvhdr Q and eager TIDs; skip the TID
- * array for time being. If pd->port_port > chip-supported,
- * we need to do extra stuff here to handle by handling overflow
- * through port 0, someday
- */
- ret = ipath_create_rcvhdrq(dd, pd);
- if (!ret)
- ret = ipath_create_user_egr(pd);
- if (ret)
- goto done;
-
- /*
- * set the eager head register for this port to the current values
- * of the tail pointers, since we don't know if they were
- * updated on last use of the port.
- */
- head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
- ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
- dd->ipath_lastegrheads[pd->port_port] = -1;
- dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
- ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
- pd->port_port, head32);
- pd->port_tidcursor = 0; /* start at beginning after open */
- /*
- * now enable the port; the tail registers will be written to memory
- * by the chip as soon as it sees the write to
- * dd->ipath_kregs->kr_rcvctrl. The update only happens on
- * transition from 0 to 1, so clear it first, then set it as part of
- * enabling the port. This will (very briefly) affect any other
- * open ports, but it shouldn't be long enough to be an issue.
- * We explictly set the in-memory copy to 0 beforehand, so we don't
- * have to wait to be sure the DMA update has happened.
- */
- *pd->port_rcvhdrtail_kvaddr = 0ULL;
- set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
- &dd->ipath_rcvctrl);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
- dd->ipath_rcvctrl);
-done:
- return ret;
-}
-
/* common code for the mappings on dma_alloc_coherent mem */
static int ipath_mmap_mem(struct vm_area_struct *vma,
- struct ipath_portdata *pd, unsigned len,
- int write_ok, dma_addr_t addr, char *what)
+ struct ipath_portdata *pd, unsigned len, int write_ok,
+ void *kvaddr, char *what)
{
struct ipath_devdata *dd = pd->port_dd;
- unsigned pfn = (unsigned long)addr >> PAGE_SHIFT;
+ unsigned long pfn;
int ret;
if ((vma->vm_end - vma->vm_start) > len) {
@@ -912,17 +959,17 @@ static int ipath_mmap_mem(struct vm_area_struct *vma,
vma->vm_flags &= ~VM_MAYWRITE;
}
+ pfn = virt_to_phys(kvaddr) >> PAGE_SHIFT;
ret = remap_pfn_range(vma, vma->vm_start, pfn,
len, vma->vm_page_prot);
if (ret)
- dev_info(&dd->pcidev->dev,
- "%s port%u mmap of %lx, %x bytes r%c failed: %d\n",
- what, pd->port_port, (unsigned long)addr, len,
- write_ok?'w':'o', ret);
+ dev_info(&dd->pcidev->dev, "%s port%u mmap of %lx, %x "
+ "bytes r%c failed: %d\n", what, pd->port_port,
+ pfn, len, write_ok?'w':'o', ret);
else
- ipath_cdbg(VERBOSE, "%s port%u mmaped %lx, %x bytes r%c\n",
- what, pd->port_port, (unsigned long)addr, len,
- write_ok?'w':'o');
+ ipath_cdbg(VERBOSE, "%s port%u mmaped %lx, %x bytes "
+ "r%c\n", what, pd->port_port, pfn, len,
+ write_ok?'w':'o');
bail:
return ret;
}
@@ -957,7 +1004,8 @@ static int mmap_ureg(struct vm_area_struct *vma, struct ipath_devdata *dd,
static int mmap_piobufs(struct vm_area_struct *vma,
struct ipath_devdata *dd,
- struct ipath_portdata *pd)
+ struct ipath_portdata *pd,
+ unsigned piobufs, unsigned piocnt)
{
unsigned long phys;
int ret;
@@ -968,16 +1016,15 @@ static int mmap_piobufs(struct vm_area_struct *vma,
* process data, and catches users who might try to read the i/o
* space due to a bug.
*/
- if ((vma->vm_end - vma->vm_start) >
- (dd->ipath_pbufsport * dd->ipath_palign)) {
+ if ((vma->vm_end - vma->vm_start) > (piocnt * dd->ipath_palign)) {
dev_info(&dd->pcidev->dev, "FAIL mmap piobufs: "
"reqlen %lx > PAGE\n",
vma->vm_end - vma->vm_start);
- ret = -EFAULT;
+ ret = -EINVAL;
goto bail;
}
- phys = dd->ipath_physaddr + pd->port_piobufs;
+ phys = dd->ipath_physaddr + piobufs;
/*
* Don't mark this as non-cached, or we don't get the
@@ -1011,7 +1058,7 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
struct ipath_devdata *dd = pd->port_dd;
unsigned long start, size;
size_t total_size, i;
- dma_addr_t *phys;
+ unsigned long pfn;
int ret;
size = pd->port_rcvegrbuf_size;
@@ -1021,7 +1068,7 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
"reqlen %lx > actual %lx\n",
vma->vm_end - vma->vm_start,
(unsigned long) total_size);
- ret = -EFAULT;
+ ret = -EINVAL;
goto bail;
}
@@ -1035,11 +1082,11 @@ static int mmap_rcvegrbufs(struct vm_area_struct *vma,
vma->vm_flags &= ~VM_MAYWRITE;
start = vma->vm_start;
- phys = pd->port_rcvegrbuf_phys;
for (i = 0; i < pd->port_rcvegrbuf_chunks; i++, start += size) {
- ret = remap_pfn_range(vma, start, phys[i] >> PAGE_SHIFT,
- size, vma->vm_page_prot);
+ pfn = virt_to_phys(pd->port_rcvegrbuf[i]) >> PAGE_SHIFT;
+ ret = remap_pfn_range(vma, start, pfn, size,
+ vma->vm_page_prot);
if (ret < 0)
goto bail;
}
@@ -1049,6 +1096,122 @@ bail:
return ret;
}
+/*
+ * ipath_file_vma_nopage - handle a VMA page fault.
+ */
+static struct page *ipath_file_vma_nopage(struct vm_area_struct *vma,
+ unsigned long address, int *type)
+{
+ unsigned long offset = address - vma->vm_start;
+ struct page *page = NOPAGE_SIGBUS;
+ void *pageptr;
+
+ /*
+ * Convert the vmalloc address into a struct page.
+ */
+ pageptr = (void *)(offset + (vma->vm_pgoff << PAGE_SHIFT));
+ page = vmalloc_to_page(pageptr);
+ if (!page)
+ goto out;
+
+ /* Increment the reference count. */
+ get_page(page);
+ if (type)
+ *type = VM_FAULT_MINOR;
+out:
+ return page;
+}
+
+static struct vm_operations_struct ipath_file_vm_ops = {
+ .nopage = ipath_file_vma_nopage,
+};
+
+static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
+ struct ipath_portdata *pd, unsigned subport)
+{
+ unsigned long len;
+ struct ipath_devdata *dd;
+ void *addr;
+ size_t size;
+ int ret;
+
+ /* If the port is not shared, all addresses should be physical */
+ if (!pd->port_subport_cnt) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ dd = pd->port_dd;
+ size = pd->port_rcvegrbuf_chunks * pd->port_rcvegrbuf_size;
+
+ /*
+ * Master has all the slave uregbase, rcvhdrq, and
+ * rcvegrbufs mmapped.
+ */
+ if (subport == 0) {
+ unsigned num_slaves = pd->port_subport_cnt - 1;
+
+ if (pgaddr == ((u64) pd->subport_uregbase & MMAP64_MASK)) {
+ addr = pd->subport_uregbase;
+ size = PAGE_SIZE * num_slaves;
+ } else if (pgaddr == ((u64) pd->subport_rcvhdr_base &
+ MMAP64_MASK)) {
+ addr = pd->subport_rcvhdr_base;
+ size = pd->port_rcvhdrq_size * num_slaves;
+ } else if (pgaddr == ((u64) pd->subport_rcvegrbuf &
+ MMAP64_MASK)) {
+ addr = pd->subport_rcvegrbuf;
+ size *= num_slaves;
+ } else {
+ ret = -EINVAL;
+ goto bail;
+ }
+ } else if (pgaddr == (((u64) pd->subport_uregbase +
+ PAGE_SIZE * (subport - 1)) & MMAP64_MASK)) {
+ addr = pd->subport_uregbase + PAGE_SIZE * (subport - 1);
+ size = PAGE_SIZE;
+ } else if (pgaddr == (((u64) pd->subport_rcvhdr_base +
+ pd->port_rcvhdrq_size * (subport - 1)) &
+ MMAP64_MASK)) {
+ addr = pd->subport_rcvhdr_base +
+ pd->port_rcvhdrq_size * (subport - 1);
+ size = pd->port_rcvhdrq_size;
+ } else if (pgaddr == (((u64) pd->subport_rcvegrbuf +
+ size * (subport - 1)) & MMAP64_MASK)) {
+ addr = pd->subport_rcvegrbuf + size * (subport - 1);
+ /* rcvegrbufs are read-only on the slave */
+ if (vma->vm_flags & VM_WRITE) {
+ dev_info(&dd->pcidev->dev,
+ "Can't map eager buffers as "
+ "writable (flags=%lx)\n", vma->vm_flags);
+ ret = -EPERM;
+ goto bail;
+ }
+ /*
+ * Don't allow permission to later change to writeable
+ * with mprotect.
+ */
+ vma->vm_flags &= ~VM_MAYWRITE;
+ } else {
+ ret = -EINVAL;
+ goto bail;
+ }
+ len = vma->vm_end - vma->vm_start;
+ if (len > size) {
+ ipath_cdbg(MM, "FAIL: reqlen %lx > %zx\n", len, size);
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ vma->vm_pgoff = (unsigned long) addr >> PAGE_SHIFT;
+ vma->vm_ops = &ipath_file_vm_ops;
+ vma->vm_flags |= VM_RESERVED | VM_DONTEXPAND;
+ ret = 0;
+
+bail:
+ return ret;
+}
+
/**
* ipath_mmap - mmap various structures into user space
* @fp: the file pointer
@@ -1064,73 +1227,99 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
struct ipath_portdata *pd;
struct ipath_devdata *dd;
u64 pgaddr, ureg;
+ unsigned piobufs, piocnt;
int ret;
pd = port_fp(fp);
+ if (!pd) {
+ ret = -EINVAL;
+ goto bail;
+ }
dd = pd->port_dd;
/*
* This is the ipath_do_user_init() code, mapping the shared buffers
* into the user process. The address referred to by vm_pgoff is the
- * virtual, not physical, address; we only do one mmap for each
- * space mapped.
+ * file offset passed via mmap(). For shared ports, this is the
+ * kernel vmalloc() address of the pages to share with the master.
+ * For non-shared or master ports, this is a physical address.
+ * We only do one mmap for each space mapped.
*/
pgaddr = vma->vm_pgoff << PAGE_SHIFT;
/*
- * Must fit in 40 bits for our hardware; some checked elsewhere,
- * but we'll be paranoid. Check for 0 is mostly in case one of the
- * allocations failed, but user called mmap anyway. We want to catch
- * that before it can match.
+ * Check for 0 in case one of the allocations failed, but user
+ * called mmap anyway.
*/
- if (!pgaddr || pgaddr >= (1ULL<<40)) {
- ipath_dev_err(dd, "Bad phys addr %llx, start %lx, end %lx\n",
- (unsigned long long)pgaddr, vma->vm_start, vma->vm_end);
- return -EINVAL;
+ if (!pgaddr) {
+ ret = -EINVAL;
+ goto bail;
}
- /* just the offset of the port user registers, not physical addr */
- ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
-
- ipath_cdbg(MM, "ushare: pgaddr %llx vm_start=%lx, vmlen %lx\n",
+ ipath_cdbg(MM, "pgaddr %llx vm_start=%lx len %lx port %u:%u:%u\n",
(unsigned long long) pgaddr, vma->vm_start,
- vma->vm_end - vma->vm_start);
+ vma->vm_end - vma->vm_start, dd->ipath_unit,
+ pd->port_port, subport_fp(fp));
- if (vma->vm_start & (PAGE_SIZE-1)) {
- ipath_dev_err(dd,
- "vm_start not aligned: %lx, end=%lx phys %lx\n",
- vma->vm_start, vma->vm_end, (unsigned long)pgaddr);
- ret = -EINVAL;
+ /*
+ * Physical addresses must fit in 40 bits for our hardware.
+ * Check for kernel virtual addresses first, anything else must
+ * match a HW or memory address.
+ */
+ if (pgaddr >= (1ULL<<40)) {
+ ret = mmap_kvaddr(vma, pgaddr, pd, subport_fp(fp));
+ goto bail;
}
- else if (pgaddr == ureg)
+
+ if (!pd->port_subport_cnt) {
+ /* port is not shared */
+ ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+ piocnt = dd->ipath_pbufsport;
+ piobufs = pd->port_piobufs;
+ } else if (!subport_fp(fp)) {
+ /* caller is the master */
+ ureg = dd->ipath_uregbase + dd->ipath_palign * pd->port_port;
+ piocnt = (dd->ipath_pbufsport / pd->port_subport_cnt) +
+ (dd->ipath_pbufsport % pd->port_subport_cnt);
+ piobufs = pd->port_piobufs +
+ dd->ipath_palign * (dd->ipath_pbufsport - piocnt);
+ } else {
+ unsigned slave = subport_fp(fp) - 1;
+
+ /* caller is a slave */
+ ureg = 0;
+ piocnt = dd->ipath_pbufsport / pd->port_subport_cnt;
+ piobufs = pd->port_piobufs + dd->ipath_palign * piocnt * slave;
+ }
+
+ if (pgaddr == ureg)
ret = mmap_ureg(vma, dd, ureg);
- else if (pgaddr == pd->port_piobufs)
- ret = mmap_piobufs(vma, dd, pd);
- else if (pgaddr == (u64) pd->port_rcvegr_phys)
+ else if (pgaddr == piobufs)
+ ret = mmap_piobufs(vma, dd, pd, piobufs, piocnt);
+ else if (pgaddr == dd->ipath_pioavailregs_phys)
+ /* in-memory copy of pioavail registers */
+ ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
+ (void *) dd->ipath_pioavailregs_dma,
+ "pioavail registers");
+ else if (subport_fp(fp))
+ /* Subports don't mmap the physical receive buffers */
+ ret = -EINVAL;
+ else if (pgaddr == pd->port_rcvegr_phys)
ret = mmap_rcvegrbufs(vma, pd);
- else if (pgaddr == (u64) pd->port_rcvhdrq_phys) {
+ else if (pgaddr == (u64) pd->port_rcvhdrq_phys)
/*
* The rcvhdrq itself; readonly except on HT (so have
* to allow writable mapping), multiple pages, contiguous
* from an i/o perspective.
*/
- unsigned total_size =
- ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize
- * sizeof(u32), PAGE_SIZE);
- ret = ipath_mmap_mem(vma, pd, total_size, 1,
- pd->port_rcvhdrq_phys,
+ ret = ipath_mmap_mem(vma, pd, pd->port_rcvhdrq_size, 1,
+ pd->port_rcvhdrq,
"rcvhdrq");
- }
- else if (pgaddr == (u64)pd->port_rcvhdrqtailaddr_phys)
+ else if (pgaddr == (u64) pd->port_rcvhdrqtailaddr_phys)
/* in-memory copy of rcvhdrq tail register */
ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
- pd->port_rcvhdrqtailaddr_phys,
+ pd->port_rcvhdrtail_kvaddr,
"rcvhdrq tail");
- else if (pgaddr == dd->ipath_pioavailregs_phys)
- /* in-memory copy of pioavail registers */
- ret = ipath_mmap_mem(vma, pd, PAGE_SIZE, 0,
- dd->ipath_pioavailregs_phys,
- "pioavail registers");
else
ret = -EINVAL;
@@ -1138,9 +1327,10 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
if (ret < 0)
dev_info(&dd->pcidev->dev,
- "Failure %d on addr %lx, off %lx\n",
- -ret, vma->vm_start, vma->vm_pgoff);
-
+ "Failure %d on off %llx len %lx\n",
+ -ret, (unsigned long long)pgaddr,
+ vma->vm_end - vma->vm_start);
+bail:
return ret;
}
@@ -1154,6 +1344,8 @@ static unsigned int ipath_poll(struct file *fp,
struct ipath_devdata *dd;
pd = port_fp(fp);
+ if (!pd)
+ goto bail;
dd = pd->port_dd;
bit = pd->port_port + INFINIPATH_R_INTRAVAIL_SHIFT;
@@ -1176,7 +1368,7 @@ static unsigned int ipath_poll(struct file *fp,
if (tail == head) {
set_bit(IPATH_PORT_WAITING_RCV, &pd->port_flag);
- if(dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
+ if (dd->ipath_rhdrhead_intr_off) /* arm rcv interrupt */
(void)ipath_write_ureg(dd, ur_rcvhdrhead,
dd->ipath_rhdrhead_intr_off
| head, pd->port_port);
@@ -1200,18 +1392,80 @@ static unsigned int ipath_poll(struct file *fp,
ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
dd->ipath_rcvctrl);
+bail:
return pollflag;
}
+static int init_subports(struct ipath_devdata *dd,
+ struct ipath_portdata *pd,
+ const struct ipath_user_info *uinfo)
+{
+ int ret = 0;
+ unsigned num_slaves;
+ size_t size;
+
+ /* Old user binaries don't know about subports */
+ if ((uinfo->spu_userversion & 0xffff) != IPATH_USER_SWMINOR)
+ goto bail;
+ /*
+ * If the user is requesting zero or one port,
+ * skip the subport allocation.
+ */
+ if (uinfo->spu_subport_cnt <= 1)
+ goto bail;
+ if (uinfo->spu_subport_cnt > 4) {
+ ret = -EINVAL;
+ goto bail;
+ }
+
+ num_slaves = uinfo->spu_subport_cnt - 1;
+ pd->subport_uregbase = vmalloc(PAGE_SIZE * num_slaves);
+ if (!pd->subport_uregbase) {
+ ret = -ENOMEM;
+ goto bail;
+ }
+ /* Note: pd->port_rcvhdrq_size isn't initialized yet. */
+ size = ALIGN(dd->ipath_rcvhdrcnt * dd->ipath_rcvhdrentsize *
+ sizeof(u32), PAGE_SIZE) * num_slaves;
+ pd->subport_rcvhdr_base = vmalloc(size);
+ if (!pd->subport_rcvhdr_base) {
+ ret = -ENOMEM;
+ goto bail_ureg;
+ }
+
+ pd->subport_rcvegrbuf = vmalloc(pd->port_rcvegrbuf_chunks *
+ pd->port_rcvegrbuf_size *
+ num_slaves);
+ if (!pd->subport_rcvegrbuf) {
+ ret = -ENOMEM;
+ goto bail_rhdr;
+ }
+
+ pd->port_subport_cnt = uinfo->spu_subport_cnt;
+ pd->port_subport_id = uinfo->spu_subport_id;
+ pd->active_slaves = 1;
+ goto bail;
+
+bail_rhdr:
+ vfree(pd->subport_rcvhdr_base);
+bail_ureg:
+ vfree(pd->subport_uregbase);
+ pd->subport_uregbase = NULL;
+bail:
+ return ret;
+}
+
static int try_alloc_port(struct ipath_devdata *dd, int port,
- struct file *fp)
+ struct file *fp,
+ const struct ipath_user_info *uinfo)
{
+ struct ipath_portdata *pd;
int ret;
- if (!dd->ipath_pd[port]) {
- void *p, *ptmp;
+ if (!(pd = dd->ipath_pd[port])) {
+ void *ptmp;
- p = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL);
+ pd = kzalloc(sizeof(struct ipath_portdata), GFP_KERNEL);
/*
* Allocate memory for use in ipath_tid_update() just once
@@ -1221,34 +1475,36 @@ static int try_alloc_port(struct ipath_devdata *dd, int port,
ptmp = kmalloc(dd->ipath_rcvtidcnt * sizeof(u16) +
dd->ipath_rcvtidcnt * sizeof(struct page **),
GFP_KERNEL);
- if (!p || !ptmp) {
+ if (!pd || !ptmp) {
ipath_dev_err(dd, "Unable to allocate portdata "
"memory, failing open\n");
ret = -ENOMEM;
- kfree(p);
+ kfree(pd);
kfree(ptmp);
goto bail;
}
- dd->ipath_pd[port] = p;
+ dd->ipath_pd[port] = pd;
dd->ipath_pd[port]->port_port = port;
dd->ipath_pd[port]->port_dd = dd;
dd->ipath_pd[port]->port_tid_pg_list = ptmp;
init_waitqueue_head(&dd->ipath_pd[port]->port_wait);
}
- if (!dd->ipath_pd[port]->port_cnt) {
- dd->ipath_pd[port]->port_cnt = 1;
- fp->private_data = (void *) dd->ipath_pd[port];
+ if (!pd->port_cnt) {
+ pd->userversion = uinfo->spu_userversion;
+ init_user_egr_sizes(pd);
+ if ((ret = init_subports(dd, pd, uinfo)) != 0)
+ goto bail;
ipath_cdbg(PROC, "%s[%u] opened unit:port %u:%u\n",
current->comm, current->pid, dd->ipath_unit,
port);
- dd->ipath_pd[port]->port_pid = current->pid;
- strncpy(dd->ipath_pd[port]->port_comm, current->comm,
- sizeof(dd->ipath_pd[port]->port_comm));
+ pd->port_cnt = 1;
+ port_fp(fp) = pd;
+ pd->port_pid = current->pid;
+ strncpy(pd->port_comm, current->comm, sizeof(pd->port_comm));
ipath_stats.sps_ports++;
ret = 0;
- goto bail;
- }
- ret = -EBUSY;
+ } else
+ ret = -EBUSY;
bail:
return ret;
@@ -1264,7 +1520,8 @@ static inline int usable(struct ipath_devdata *dd)
| IPATH_LINKUNK));
}
-static int find_free_port(int unit, struct file *fp)
+static int find_free_port(int unit, struct file *fp,
+ const struct ipath_user_info *uinfo)
{
struct ipath_devdata *dd = ipath_lookup(unit);
int ret, i;
@@ -1279,8 +1536,8 @@ static int find_free_port(int unit, struct file *fp)
goto bail;
}
- for (i = 0; i < dd->ipath_cfgports; i++) {
- ret = try_alloc_port(dd, i, fp);
+ for (i = 1; i < dd->ipath_cfgports; i++) {
+ ret = try_alloc_port(dd, i, fp, uinfo);
if (ret != -EBUSY)
goto bail;
}
@@ -1290,13 +1547,14 @@ bail:
return ret;
}
-static int find_best_unit(struct file *fp)
+static int find_best_unit(struct file *fp,
+ const struct ipath_user_info *uinfo)
{
int ret = 0, i, prefunit = -1, devmax;
int maxofallports, npresent, nup;
int ndev;
- (void) ipath_count_units(&npresent, &nup, &maxofallports);
+ devmax = ipath_count_units(&npresent, &nup, &maxofallports);
/*
* This code is present to allow a knowledgeable person to
@@ -1343,8 +1601,6 @@ static int find_best_unit(struct file *fp)
if (prefunit != -1)
devmax = prefunit + 1;
- else
- devmax = ipath_count_units(NULL, NULL, NULL);
recheck:
for (i = 1; i < maxofallports; i++) {
for (ndev = prefunit != -1 ? prefunit : 0; ndev < devmax;
@@ -1359,7 +1615,7 @@ recheck:
* next.
*/
continue;
- ret = try_alloc_port(dd, i, fp);
+ ret = try_alloc_port(dd, i, fp, uinfo);
if (!ret)
goto done;
}
@@ -1395,22 +1651,183 @@ done:
return ret;
}
+static int find_shared_port(struct file *fp,
+ const struct ipath_user_info *uinfo)
+{
+ int devmax, ndev, i;
+ int ret = 0;
+
+ devmax = ipath_count_units(NULL, NULL, NULL);
+
+ for (ndev = 0; ndev < devmax; ndev++) {
+ struct ipath_devdata *dd = ipath_lookup(ndev);
+
+ if (!dd)
+ continue;
+ for (i = 1; i < dd->ipath_cfgports; i++) {
+ struct ipath_portdata *pd = dd->ipath_pd[i];
+
+ /* Skip ports which are not yet open */
+ if (!pd || !pd->port_cnt)
+ continue;
+ /* Skip port if it doesn't match the requested one */
+ if (pd->port_subport_id != uinfo->spu_subport_id)
+ continue;
+ /* Verify the sharing process matches the master */
+ if (pd->port_subport_cnt != uinfo->spu_subport_cnt ||
+ pd->userversion != uinfo->spu_userversion ||
+ pd->port_cnt >= pd->port_subport_cnt) {
+ ret = -EINVAL;
+ goto done;
+ }
+ port_fp(fp) = pd;
+ subport_fp(fp) = pd->port_cnt++;
+ tidcursor_fp(fp) = 0;
+ pd->active_slaves |= 1 << subport_fp(fp);
+ ipath_cdbg(PROC,
+ "%s[%u] %u sharing %s[%u] unit:port %u:%u\n",
+ current->comm, current->pid,
+ subport_fp(fp),
+ pd->port_comm, pd->port_pid,
+ dd->ipath_unit, pd->port_port);
+ ret = 1;
+ goto done;
+ }
+ }
+
+done:
+ return ret;
+}
+
static int ipath_open(struct inode *in, struct file *fp)
{
- int ret, user_minor;
+ /* The real work is performed later in ipath_assign_port() */
+ fp->private_data = kzalloc(sizeof(struct ipath_filedata), GFP_KERNEL);
+ return fp->private_data ? 0 : -ENOMEM;
+}
+
+
+/* Get port early, so can set affinity prior to memory allocation */
+static int ipath_assign_port(struct file *fp,
+ const struct ipath_user_info *uinfo)
+{
+ int ret;
+ int i_minor;
+ unsigned swminor;
+
+ /* Check to be sure we haven't already initialized this file */
+ if (port_fp(fp)) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* for now, if major version is different, bail */
+ if ((uinfo->spu_userversion >> 16) != IPATH_USER_SWMAJOR) {
+ ipath_dbg("User major version %d not same as driver "
+ "major %d\n", uinfo->spu_userversion >> 16,
+ IPATH_USER_SWMAJOR);
+ ret = -ENODEV;
+ goto done;
+ }
+
+ swminor = uinfo->spu_userversion & 0xffff;
+ if (swminor != IPATH_USER_SWMINOR)
+ ipath_dbg("User minor version %d not same as driver "
+ "minor %d\n", swminor, IPATH_USER_SWMINOR);
mutex_lock(&ipath_mutex);
- user_minor = iminor(in) - IPATH_USER_MINOR_BASE;
+ if (swminor == IPATH_USER_SWMINOR && uinfo->spu_subport_cnt &&
+ (ret = find_shared_port(fp, uinfo))) {
+ mutex_unlock(&ipath_mutex);
+ if (ret > 0)
+ ret = 0;
+ goto done;
+ }
+
+ i_minor = iminor(fp->f_dentry->d_inode) - IPATH_USER_MINOR_BASE;
ipath_cdbg(VERBOSE, "open on dev %lx (minor %d)\n",
- (long)in->i_rdev, user_minor);
+ (long)fp->f_dentry->d_inode->i_rdev, i_minor);
- if (user_minor)
- ret = find_free_port(user_minor - 1, fp);
+ if (i_minor)
+ ret = find_free_port(i_minor - 1, fp, uinfo);
else
- ret = find_best_unit(fp);
+ ret = find_best_unit(fp, uinfo);
mutex_unlock(&ipath_mutex);
+
+done:
+ return ret;
+}
+
+
+static int ipath_do_user_init(struct file *fp,
+ const struct ipath_user_info *uinfo)
+{
+ int ret;
+ struct ipath_portdata *pd;
+ struct ipath_devdata *dd;
+ u32 head32;
+
+ pd = port_fp(fp);
+ dd = pd->port_dd;
+
+ if (uinfo->spu_rcvhdrsize) {
+ ret = ipath_setrcvhdrsize(dd, uinfo->spu_rcvhdrsize);
+ if (ret)
+ goto done;
+ }
+
+ /* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
+
+ /* for right now, kernel piobufs are at end, so port 1 is at 0 */
+ pd->port_piobufs = dd->ipath_piobufbase +
+ dd->ipath_pbufsport * (pd->port_port - 1) * dd->ipath_palign;
+ ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
+ pd->port_port, pd->port_piobufs);
+
+ /*
+ * Now allocate the rcvhdr Q and eager TIDs; skip the TID
+ * array for time being. If pd->port_port > chip-supported,
+ * we need to do extra stuff here to handle by handling overflow
+ * through port 0, someday
+ */
+ ret = ipath_create_rcvhdrq(dd, pd);
+ if (!ret)
+ ret = ipath_create_user_egr(pd);
+ if (ret)
+ goto done;
+
+ /*
+ * set the eager head register for this port to the current values
+ * of the tail pointers, since we don't know if they were
+ * updated on last use of the port.
+ */
+ head32 = ipath_read_ureg32(dd, ur_rcvegrindextail, pd->port_port);
+ ipath_write_ureg(dd, ur_rcvegrindexhead, head32, pd->port_port);
+ dd->ipath_lastegrheads[pd->port_port] = -1;
+ dd->ipath_lastrcvhdrqtails[pd->port_port] = -1;
+ ipath_cdbg(VERBOSE, "Wrote port%d egrhead %x from tail regs\n",
+ pd->port_port, head32);
+ pd->port_tidcursor = 0; /* start at beginning after open */
+ /*
+ * now enable the port; the tail registers will be written to memory
+ * by the chip as soon as it sees the write to
+ * dd->ipath_kregs->kr_rcvctrl. The update only happens on
+ * transition from 0 to 1, so clear it first, then set it as part of
+ * enabling the port. This will (very briefly) affect any other
+ * open ports, but it shouldn't be long enough to be an issue.
+ * We explictly set the in-memory copy to 0 beforehand, so we don't
+ * have to wait to be sure the DMA update has happened.
+ */
+ *(volatile u64 *)pd->port_rcvhdrtail_kvaddr = 0ULL;
+ set_bit(INFINIPATH_R_PORTENABLE_SHIFT + pd->port_port,
+ &dd->ipath_rcvctrl);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl & ~INFINIPATH_R_TAILUPD);
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_rcvctrl,
+ dd->ipath_rcvctrl);
+done:
return ret;
}
@@ -1433,6 +1850,8 @@ static void unlock_expected_tids(struct ipath_portdata *pd)
if (!dd->ipath_pageshadow[i])
continue;
+ pci_unmap_page(dd->pcidev, dd->ipath_physshadow[i],
+ PAGE_SIZE, PCI_DMA_FROMDEVICE);
ipath_release_user_pages_on_close(&dd->ipath_pageshadow[i],
1);
dd->ipath_pageshadow[i] = NULL;
@@ -1453,6 +1872,7 @@ static void unlock_expected_tids(struct ipath_portdata *pd)
static int ipath_close(struct inode *in, struct file *fp)
{
int ret = 0;
+ struct ipath_filedata *fd;
struct ipath_portdata *pd;
struct ipath_devdata *dd;
unsigned port;
@@ -1462,9 +1882,24 @@ static int ipath_close(struct inode *in, struct file *fp)
mutex_lock(&ipath_mutex);
- pd = port_fp(fp);
- port = pd->port_port;
+ fd = (struct ipath_filedata *) fp->private_data;
fp->private_data = NULL;
+ pd = fd->pd;
+ if (!pd) {
+ mutex_unlock(&ipath_mutex);
+ goto bail;
+ }
+ if (--pd->port_cnt) {
+ /*
+ * XXX If the master closes the port before the slave(s),
+ * revoke the mmap for the eager receive queue so
+ * the slave(s) don't wait for receive data forever.
+ */
+ pd->active_slaves &= ~(1 << fd->subport);
+ mutex_unlock(&ipath_mutex);
+ goto bail;
+ }
+ port = pd->port_port;
dd = pd->port_dd;
if (pd->port_hdrqfull) {
@@ -1503,8 +1938,6 @@ static int ipath_close(struct inode *in, struct file *fp)
/* clean up the pkeys for this port user */
ipath_clean_part_key(pd, dd);
-
-
/*
* be paranoid, and never write 0's to these, just use an
* unused part of the port 0 tail page. Of course,
@@ -1523,39 +1956,49 @@ static int ipath_close(struct inode *in, struct file *fp)
i = dd->ipath_pbufsport * (port - 1);
ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
+ dd->ipath_f_clear_tids(dd, pd->port_port);
+
if (dd->ipath_pageshadow)
unlock_expected_tids(pd);
ipath_stats.sps_ports--;
ipath_cdbg(PROC, "%s[%u] closed port %u:%u\n",
pd->port_comm, pd->port_pid,
dd->ipath_unit, port);
-
- dd->ipath_f_clear_tids(dd, pd->port_port);
}
- pd->port_cnt = 0;
pd->port_pid = 0;
-
dd->ipath_pd[pd->port_port] = NULL; /* before releasing mutex */
mutex_unlock(&ipath_mutex);
ipath_free_pddata(dd, pd); /* after releasing the mutex */
+bail:
+ kfree(fd);
return ret;
}
-static int ipath_port_info(struct ipath_portdata *pd,
+static int ipath_port_info(struct ipath_portdata *pd, u16 subport,
struct ipath_port_info __user *uinfo)
{
struct ipath_port_info info;
int nup;
int ret;
+ size_t sz;
(void) ipath_count_units(NULL, &nup, NULL);
info.num_active = nup;
info.unit = pd->port_dd->ipath_unit;
info.port = pd->port_port;
+ info.subport = subport;
+ /* Don't return new fields if old library opened the port. */
+ if ((pd->userversion & 0xffff) == IPATH_USER_SWMINOR) {
+ /* Number of user ports available for this device. */
+ info.num_ports = pd->port_dd->ipath_cfgports - 1;
+ info.num_subports = pd->port_subport_cnt;
+ sz = sizeof(info);
+ } else
+ sz = sizeof(info) - 2 * sizeof(u16);
- if (copy_to_user(uinfo, &info, sizeof(info))) {
+ if (copy_to_user(uinfo, &info, sz)) {
ret = -EFAULT;
goto bail;
}
@@ -1565,6 +2008,16 @@ bail:
return ret;
}
+static int ipath_get_slave_info(struct ipath_portdata *pd,
+ void __user *slave_mask_addr)
+{
+ int ret = 0;
+
+ if (copy_to_user(slave_mask_addr, &pd->active_slaves, sizeof(u32)))
+ ret = -EFAULT;
+ return ret;
+}
+
static ssize_t ipath_write(struct file *fp, const char __user *data,
size_t count, loff_t *off)
{
@@ -1591,6 +2044,8 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
consumed = sizeof(cmd.type);
switch (cmd.type) {
+ case IPATH_CMD_ASSIGN_PORT:
+ case __IPATH_CMD_USER_INIT:
case IPATH_CMD_USER_INIT:
copy = sizeof(cmd.cmd.user_info);
dest = &cmd.cmd.user_info;
@@ -1617,6 +2072,11 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
dest = &cmd.cmd.part_key;
src = &ucmd->cmd.part_key;
break;
+ case IPATH_CMD_SLAVE_INFO:
+ copy = sizeof(cmd.cmd.slave_mask_addr);
+ dest = &cmd.cmd.slave_mask_addr;
+ src = &ucmd->cmd.slave_mask_addr;
+ break;
default:
ret = -EINVAL;
goto bail;
@@ -1634,34 +2094,55 @@ static ssize_t ipath_write(struct file *fp, const char __user *data,
consumed += copy;
pd = port_fp(fp);
+ if (!pd && cmd.type != __IPATH_CMD_USER_INIT &&
+ cmd.type != IPATH_CMD_ASSIGN_PORT) {
+ ret = -EINVAL;
+ goto bail;
+ }
switch (cmd.type) {
+ case IPATH_CMD_ASSIGN_PORT:
+ ret = ipath_assign_port(fp, &cmd.cmd.user_info);
+ if (ret)
+ goto bail;
+ break;
+ case __IPATH_CMD_USER_INIT:
+ /* backwards compatibility, get port first */
+ ret = ipath_assign_port(fp, &cmd.cmd.user_info);
+ if (ret)
+ goto bail;
+ /* and fall through to current version. */
case IPATH_CMD_USER_INIT:
- ret = ipath_do_user_init(pd, &cmd.cmd.user_info);
- if (ret < 0)
+ ret = ipath_do_user_init(fp, &cmd.cmd.user_info);
+ if (ret)
goto bail;
ret = ipath_get_base_info(
- pd, (void __user *) (unsigned long)
+ fp, (void __user *) (unsigned long)
cmd.cmd.user_info.spu_base_info,
cmd.cmd.user_info.spu_base_info_size);
break;
case IPATH_CMD_RECV_CTRL:
- ret = ipath_manage_rcvq(pd, cmd.cmd.recv_ctrl);
+ ret = ipath_manage_rcvq(pd, subport_fp(fp), cmd.cmd.recv_ctrl);
break;
case IPATH_CMD_PORT_INFO:
- ret = ipath_port_info(pd,
+ ret = ipath_port_info(pd, subport_fp(fp),
(struct ipath_port_info __user *)
(unsigned long) cmd.cmd.port_info);
break;
case IPATH_CMD_TID_UPDATE:
- ret = ipath_tid_update(pd, &cmd.cmd.tid_info);
+ ret = ipath_tid_update(pd, fp, &cmd.cmd.tid_info);
break;
case IPATH_CMD_TID_FREE:
- ret = ipath_tid_free(pd, &cmd.cmd.tid_info);
+ ret = ipath_tid_free(pd, subport_fp(fp), &cmd.cmd.tid_info);
break;
case IPATH_CMD_SET_PART_KEY:
ret = ipath_set_part_key(pd, cmd.cmd.part_key);
break;
+ case IPATH_CMD_SLAVE_INFO:
+ ret = ipath_get_slave_info(pd,
+ (void __user *) (unsigned long)
+ cmd.cmd.slave_mask_addr);
+ break;
}
if (ret >= 0)
@@ -1858,4 +2339,3 @@ void ipath_user_remove(struct ipath_devdata *dd)
bail:
return;
}
-
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index a5eb30a06a5c..d9ff283f725e 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -61,14 +61,13 @@ static int ipathfs_mknod(struct inode *dir, struct dentry *dentry,
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->u.generic_ip = data;
+ inode->i_private = data;
if ((mode & S_IFMT) == S_IFDIR) {
inode->i_op = &simple_dir_inode_operations;
- inode->i_nlink++;
- dir->i_nlink++;
+ inc_nlink(inode);
+ inc_nlink(dir);
}
inode->i_fop = fops;
@@ -119,7 +118,7 @@ static ssize_t atomic_counters_read(struct file *file, char __user *buf,
u16 i;
struct ipath_devdata *dd;
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
for (i = 0; i < NUM_COUNTERS; i++)
counters[i] = ipath_snap_cntr(dd, i);
@@ -139,7 +138,7 @@ static ssize_t atomic_node_info_read(struct file *file, char __user *buf,
struct ipath_devdata *dd;
u64 guid;
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
guid = be64_to_cpu(dd->ipath_guid);
@@ -178,7 +177,7 @@ static ssize_t atomic_port_info_read(struct file *file, char __user *buf,
u32 tmp, tmp2;
struct ipath_devdata *dd;
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
/* so we only initialize non-zero fields. */
memset(portinfo, 0, sizeof portinfo);
@@ -325,7 +324,7 @@ static ssize_t flash_read(struct file *file, char __user *buf,
goto bail;
}
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
if (ipath_eeprom_read(dd, pos, tmp, count)) {
ipath_dev_err(dd, "failed to read from flash\n");
ret = -ENXIO;
@@ -357,19 +356,16 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
pos = *ppos;
- if ( pos < 0) {
+ if (pos != 0) {
ret = -EINVAL;
goto bail;
}
- if (pos >= sizeof(struct ipath_flash)) {
- ret = 0;
+ if (count != sizeof(struct ipath_flash)) {
+ ret = -EINVAL;
goto bail;
}
- if (count > sizeof(struct ipath_flash) - pos)
- count = sizeof(struct ipath_flash) - pos;
-
tmp = kmalloc(count, GFP_KERNEL);
if (!tmp) {
ret = -ENOMEM;
@@ -381,7 +377,7 @@ static ssize_t flash_write(struct file *file, const char __user *buf,
goto bail_tmp;
}
- dd = file->f_dentry->d_inode->u.generic_ip;
+ dd = file->f_dentry->d_inode->i_private;
if (ipath_eeprom_write(dd, pos, tmp, count)) {
ret = -ENXIO;
ipath_dev_err(dd, "failed to write to flash\n");
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/infiniband/hw/ipath/ipath_iba6110.c
index bf2455a6d562..9e4e8d4c6e20 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6110.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6110.c
@@ -252,8 +252,8 @@ static const struct ipath_cregs ipath_ht_cregs = {
};
/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK 0x1FF
-#define INFINIPATH_I_RCVAVAIL_MASK 0x1FF
+#define INFINIPATH_I_RCVURG_MASK ((1U<<9)-1)
+#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<9)-1)
/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
#define INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT 0
@@ -338,7 +338,7 @@ static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
if (crcbits) {
u16 ctrl0, ctrl1;
snprintf(bitsmsg, sizeof bitsmsg,
- "[HT%s lane %s CRC (%llx); ignore till reload]",
+ "[HT%s lane %s CRC (%llx); powercycle to completely clear]",
!(crcbits & _IPATH_HTLINK1_CRCBITS) ?
"0 (A)" : (!(crcbits & _IPATH_HTLINK0_CRCBITS)
? "1 (B)" : "0+1 (A+B)"),
@@ -389,17 +389,28 @@ static void hwerr_crcbits(struct ipath_devdata *dd, ipath_err_t hwerrs,
_IPATH_HTLINK1_CRCBITS)));
}
+/* 6110 specific hardware errors... */
+static const struct ipath_hwerror_msgs ipath_6110_hwerror_msgs[] = {
+ INFINIPATH_HWE_MSG(HTCBUSIREQPARITYERR, "HTC Ireq Parity"),
+ INFINIPATH_HWE_MSG(HTCBUSTREQPARITYERR, "HTC Treq Parity"),
+ INFINIPATH_HWE_MSG(HTCBUSTRESPPARITYERR, "HTC Tresp Parity"),
+ INFINIPATH_HWE_MSG(HTCMISCERR5, "HT core Misc5"),
+ INFINIPATH_HWE_MSG(HTCMISCERR6, "HT core Misc6"),
+ INFINIPATH_HWE_MSG(HTCMISCERR7, "HT core Misc7"),
+ INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
+ INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
+};
+
/**
- * ipath_ht_handle_hwerrors - display hardware errors
+ * ipath_ht_handle_hwerrors - display hardware errors.
* @dd: the infinipath device
* @msg: the output buffer
* @msgl: the size of the output buffer
*
- * Use same msg buffer as regular errors to avoid
- * excessive stack use. Most hardware errors are catastrophic, but for
- * right now, we'll print them and continue.
- * We reuse the same message buffer as ipath_handle_errors() to avoid
- * excessive stack usage.
+ * Use same msg buffer as regular errors to avoid excessive stack
+ * use. Most hardware errors are catastrophic, but for right now,
+ * we'll print them and continue. We reuse the same message buffer as
+ * ipath_handle_errors() to avoid excessive stack usage.
*/
static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
size_t msgl)
@@ -440,19 +451,49 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
* make sure we get this much out, unless told to be quiet,
* or it's occurred within the last 5 seconds
*/
- if ((hwerrs & ~dd->ipath_lasthwerror) ||
+ if ((hwerrs & ~(dd->ipath_lasthwerror |
+ ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) ||
(ipath_debug & __IPATH_VERBDBG))
dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
"(cleared)\n", (unsigned long long) hwerrs);
dd->ipath_lasthwerror |= hwerrs;
- if (hwerrs & ~infinipath_hwe_bitsextant)
+ if (hwerrs & ~dd->ipath_hwe_bitsextant)
ipath_dev_err(dd, "hwerror interrupt with unknown errors "
"%llx set\n", (unsigned long long)
- (hwerrs & ~infinipath_hwe_bitsextant));
+ (hwerrs & ~dd->ipath_hwe_bitsextant));
ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
if (ctrl & INFINIPATH_C_FREEZEMODE) {
+ /*
+ * parity errors in send memory are recoverable,
+ * just cancel the send (if indicated in * sendbuffererror),
+ * count the occurrence, unfreeze (if no other handled
+ * hardware error bits are set), and continue. They can
+ * occur if a processor speculative read is done to the PIO
+ * buffer while we are sending a packet, for example.
+ */
+ if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
+ ipath_stats.sps_txeparity++;
+ ipath_dbg("Recovering from TXE parity error (%llu), "
+ "hwerrstatus=%llx\n",
+ (unsigned long long) ipath_stats.sps_txeparity,
+ (unsigned long long) hwerrs);
+ ipath_disarm_senderrbufs(dd);
+ hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
+ if (!hwerrs) { /* else leave in freeze mode */
+ ipath_write_kreg(dd,
+ dd->ipath_kregs->kr_control,
+ dd->ipath_control);
+ return;
+ }
+ }
if (hwerrs) {
/*
* if any set that we aren't ignoring; only
@@ -499,44 +540,16 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
bits);
strlcat(msg, bitsmsg, msgl);
}
- if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
- if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
- if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
- strlcat(msg, "[IB2IPATH Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
- strlcat(msg, "[IPATH2IB Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCBUSIREQPARITYERR)
- strlcat(msg, "[HTC Ireq Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCBUSTREQPARITYERR)
- strlcat(msg, "[HTC Treq Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCBUSTRESPPARITYERR)
- strlcat(msg, "[HTC Tresp Parity]", msgl);
+
+ ipath_format_hwerrors(hwerrs,
+ ipath_6110_hwerror_msgs,
+ sizeof(ipath_6110_hwerror_msgs) /
+ sizeof(ipath_6110_hwerror_msgs[0]),
+ msg, msgl);
if (hwerrs & (_IPATH_HTLINK0_CRCBITS | _IPATH_HTLINK1_CRCBITS))
hwerr_crcbits(dd, hwerrs, msg, msgl);
- if (hwerrs & INFINIPATH_HWE_HTCMISCERR5)
- strlcat(msg, "[HT core Misc5]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCMISCERR6)
- strlcat(msg, "[HT core Misc6]", msgl);
- if (hwerrs & INFINIPATH_HWE_HTCMISCERR7)
- strlcat(msg, "[HT core Misc7]", msgl);
if (hwerrs & INFINIPATH_HWE_MEMBISTFAILED) {
strlcat(msg, "[Memory BIST test failed, InfiniPath hardware unusable]",
msgl);
@@ -573,11 +586,6 @@ static void ipath_ht_handle_hwerrors(struct ipath_devdata *dd, char *msg,
dd->ipath_hwerrmask);
}
- if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
- strlcat(msg, "[Rx Dsync]", msgl);
- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
- strlcat(msg, "[SerDes PLL]", msgl);
-
ipath_dev_err(dd, "%s hardware error\n", msg);
if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg)
/*
@@ -742,7 +750,6 @@ static int ipath_setup_ht_reset(struct ipath_devdata *dd)
return 0;
}
-#define HT_CAPABILITY_ID 0x08 /* HT capabilities not defined in kernel */
#define HT_INTR_DISC_CONFIG 0x80 /* HT interrupt and discovery cap */
#define HT_INTR_REG_INDEX 2 /* intconfig requires indirect accesses */
@@ -973,7 +980,7 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
* do this early, before we ever enable errors or hardware errors,
* mostly to avoid causing the chip to enter freeze mode.
*/
- pos = pci_find_capability(pdev, HT_CAPABILITY_ID);
+ pos = pci_find_capability(pdev, PCI_CAP_ID_HT);
if (!pos) {
ipath_dev_err(dd, "Couldn't find HyperTransport "
"capability; no interrupts\n");
@@ -996,7 +1003,7 @@ static int ipath_setup_ht_config(struct ipath_devdata *dd,
else if (cap_type == HT_INTR_DISC_CONFIG)
ihandler = set_int_handler(dd, pdev, pos);
} while ((pos = pci_find_next_capability(pdev, pos,
- HT_CAPABILITY_ID)));
+ PCI_CAP_ID_HT)));
if (!ihandler) {
ipath_dev_err(dd, "Couldn't find interrupt handler in "
@@ -1081,21 +1088,21 @@ static void ipath_setup_ht_setextled(struct ipath_devdata *dd,
ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, extctl);
}
-static void ipath_init_ht_variables(void)
+static void ipath_init_ht_variables(struct ipath_devdata *dd)
{
- ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
- ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
- ipath_gpio_sda = IPATH_GPIO_SDA;
- ipath_gpio_scl = IPATH_GPIO_SCL;
+ dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+ dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+ dd->ipath_gpio_sda = IPATH_GPIO_SDA;
+ dd->ipath_gpio_scl = IPATH_GPIO_SCL;
- infinipath_i_bitsextant =
+ dd->ipath_i_bitsextant =
(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
(INFINIPATH_I_RCVAVAIL_MASK <<
INFINIPATH_I_RCVAVAIL_SHIFT) |
INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
- infinipath_e_bitsextant =
+ dd->ipath_e_bitsextant =
INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
@@ -1113,7 +1120,7 @@ static void ipath_init_ht_variables(void)
INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
INFINIPATH_E_HARDWARE;
- infinipath_hwe_bitsextant =
+ dd->ipath_hwe_bitsextant =
(INFINIPATH_HWE_HTCMEMPARITYERR_MASK <<
INFINIPATH_HWE_HTCMEMPARITYERR_SHIFT) |
(INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
@@ -1142,8 +1149,8 @@ static void ipath_init_ht_variables(void)
INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
- infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
- infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+ dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+ dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
}
/**
@@ -1608,5 +1615,5 @@ void ipath_init_iba6110_funcs(struct ipath_devdata *dd)
* do very early init that is needed before ipath_f_bus is
* called
*/
- ipath_init_ht_variables();
+ ipath_init_ht_variables(dd);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_iba6120.c b/drivers/infiniband/hw/ipath/ipath_iba6120.c
index d86516d23df6..a72ab9de386a 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba6120.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba6120.c
@@ -263,8 +263,8 @@ static const struct ipath_cregs ipath_pe_cregs = {
};
/* kr_intstatus, kr_intclear, kr_intmask bits */
-#define INFINIPATH_I_RCVURG_MASK 0x1F
-#define INFINIPATH_I_RCVAVAIL_MASK 0x1F
+#define INFINIPATH_I_RCVURG_MASK ((1U<<5)-1)
+#define INFINIPATH_I_RCVAVAIL_MASK ((1U<<5)-1)
/* kr_hwerrclear, kr_hwerrmask, kr_hwerrstatus, bits */
#define INFINIPATH_HWE_PCIEMEMPARITYERR_MASK 0x000000000000003fULL
@@ -294,6 +294,33 @@ static const struct ipath_cregs ipath_pe_cregs = {
#define IPATH_GPIO_SCL (1ULL << \
(_IPATH_GPIO_SCL_NUM+INFINIPATH_EXTC_GPIOOE_SHIFT))
+/*
+ * Rev2 silicon allows suppressing check for ArmLaunch errors.
+ * this can speed up short packet sends on systems that do
+ * not guaranteee write-order.
+ */
+#define INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR (1ULL<<63)
+
+/* 6120 specific hardware errors... */
+static const struct ipath_hwerror_msgs ipath_6120_hwerror_msgs[] = {
+ INFINIPATH_HWE_MSG(PCIEPOISONEDTLP, "PCIe Poisoned TLP"),
+ INFINIPATH_HWE_MSG(PCIECPLTIMEOUT, "PCIe completion timeout"),
+ /*
+ * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
+ * parity or memory parity error failures, because most likely we
+ * won't be able to talk to the core of the chip. Nonetheless, we
+ * might see them, if they are in parts of the PCIe core that aren't
+ * essential.
+ */
+ INFINIPATH_HWE_MSG(PCIE1PLLFAILED, "PCIePLL1"),
+ INFINIPATH_HWE_MSG(PCIE0PLLFAILED, "PCIePLL0"),
+ INFINIPATH_HWE_MSG(PCIEBUSPARITYXTLH, "PCIe XTLH core parity"),
+ INFINIPATH_HWE_MSG(PCIEBUSPARITYXADM, "PCIe ADM TX core parity"),
+ INFINIPATH_HWE_MSG(PCIEBUSPARITYRADM, "PCIe ADM RX core parity"),
+ INFINIPATH_HWE_MSG(RXDSYNCMEMPARITYERR, "Rx Dsync"),
+ INFINIPATH_HWE_MSG(SERDESPLLFAILED, "SerDes PLL"),
+};
+
/**
* ipath_pe_handle_hwerrors - display hardware errors.
* @dd: the infinipath device
@@ -343,19 +370,49 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
* make sure we get this much out, unless told to be quiet,
* or it's occurred within the last 5 seconds
*/
- if ((hwerrs & ~dd->ipath_lasthwerror) ||
+ if ((hwerrs & ~(dd->ipath_lasthwerror |
+ ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT))) ||
(ipath_debug & __IPATH_VERBDBG))
dev_info(&dd->pcidev->dev, "Hardware error: hwerr=0x%llx "
"(cleared)\n", (unsigned long long) hwerrs);
dd->ipath_lasthwerror |= hwerrs;
- if (hwerrs & ~infinipath_hwe_bitsextant)
+ if (hwerrs & ~dd->ipath_hwe_bitsextant)
ipath_dev_err(dd, "hwerror interrupt with unknown errors "
"%llx set\n", (unsigned long long)
- (hwerrs & ~infinipath_hwe_bitsextant));
+ (hwerrs & ~dd->ipath_hwe_bitsextant));
ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
if (ctrl & INFINIPATH_C_FREEZEMODE) {
+ /*
+ * parity errors in send memory are recoverable,
+ * just cancel the send (if indicated in * sendbuffererror),
+ * count the occurrence, unfreeze (if no other handled
+ * hardware error bits are set), and continue. They can
+ * occur if a processor speculative read is done to the PIO
+ * buffer while we are sending a packet, for example.
+ */
+ if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
+ ipath_stats.sps_txeparity++;
+ ipath_dbg("Recovering from TXE parity error (%llu), "
+ "hwerrstatus=%llx\n",
+ (unsigned long long) ipath_stats.sps_txeparity,
+ (unsigned long long) hwerrs);
+ ipath_disarm_senderrbufs(dd);
+ hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
+ INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
+ << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
+ if (!hwerrs) { /* else leave in freeze mode */
+ ipath_write_kreg(dd,
+ dd->ipath_kregs->kr_control,
+ dd->ipath_control);
+ return;
+ }
+ }
if (hwerrs) {
/*
* if any set that we aren't ignoring only make the
@@ -379,9 +436,8 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
} else {
ipath_dbg("Clearing freezemode on ignored hardware "
"error\n");
- ctrl &= ~INFINIPATH_C_FREEZEMODE;
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
- ctrl);
+ dd->ipath_control);
}
}
@@ -396,24 +452,13 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
ipath_write_kreg(dd, dd->ipath_kregs->kr_hwerrmask,
dd->ipath_hwerrmask);
}
- if (hwerrs & (INFINIPATH_HWE_RXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_RXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[RXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
- if (hwerrs & (INFINIPATH_HWE_TXEMEMPARITYERR_MASK
- << INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT)) {
- bits = (u32) ((hwerrs >>
- INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) &
- INFINIPATH_HWE_TXEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof bitsmsg, "[TXE Parity Errs %x] ",
- bits);
- strlcat(msg, bitsmsg, msgl);
- }
+
+ ipath_format_hwerrors(hwerrs,
+ ipath_6120_hwerror_msgs,
+ sizeof(ipath_6120_hwerror_msgs)/
+ sizeof(ipath_6120_hwerror_msgs[0]),
+ msg, msgl);
+
if (hwerrs & (INFINIPATH_HWE_PCIEMEMPARITYERR_MASK
<< INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT)) {
bits = (u32) ((hwerrs >>
@@ -423,10 +468,6 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
"[PCIe Mem Parity Errs %x] ", bits);
strlcat(msg, bitsmsg, msgl);
}
- if (hwerrs & INFINIPATH_HWE_IBCBUSTOSPCPARITYERR)
- strlcat(msg, "[IB2IPATH Parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_IBCBUSFRSPCPARITYERR)
- strlcat(msg, "[IPATH2IB Parity]", msgl);
#define _IPATH_PLL_FAIL (INFINIPATH_HWE_COREPLL_FBSLIP | \
INFINIPATH_HWE_COREPLL_RFSLIP )
@@ -452,34 +493,6 @@ static void ipath_pe_handle_hwerrors(struct ipath_devdata *dd, char *msg,
dd->ipath_hwerrmask);
}
- if (hwerrs & INFINIPATH_HWE_PCIEPOISONEDTLP)
- strlcat(msg, "[PCIe Poisoned TLP]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIECPLTIMEOUT)
- strlcat(msg, "[PCIe completion timeout]", msgl);
-
- /*
- * In practice, it's unlikely wthat we'll see PCIe PLL, or bus
- * parity or memory parity error failures, because most likely we
- * won't be able to talk to the core of the chip. Nonetheless, we
- * might see them, if they are in parts of the PCIe core that aren't
- * essential.
- */
- if (hwerrs & INFINIPATH_HWE_PCIE1PLLFAILED)
- strlcat(msg, "[PCIePLL1]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIE0PLLFAILED)
- strlcat(msg, "[PCIePLL0]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXTLH)
- strlcat(msg, "[PCIe XTLH core parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYXADM)
- strlcat(msg, "[PCIe ADM TX core parity]", msgl);
- if (hwerrs & INFINIPATH_HWE_PCIEBUSPARITYRADM)
- strlcat(msg, "[PCIe ADM RX core parity]", msgl);
-
- if (hwerrs & INFINIPATH_HWE_RXDSYNCMEMPARITYERR)
- strlcat(msg, "[Rx Dsync]", msgl);
- if (hwerrs & INFINIPATH_HWE_SERDESPLLFAILED)
- strlcat(msg, "[SerDes PLL]", msgl);
-
ipath_dev_err(dd, "%s hardware error\n", msg);
if (isfatal && !ipath_diag_inuse && dd->ipath_freezemsg) {
/*
@@ -525,6 +538,9 @@ static int ipath_pe_boardname(struct ipath_devdata *dd, char *name,
case 5:
n = "InfiniPath_QMH7140";
break;
+ case 6:
+ n = "InfiniPath_QLE7142";
+ break;
default:
ipath_dev_err(dd,
"Don't yet know about board with ID %u\n",
@@ -571,9 +587,12 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
if (!dd->ipath_boardrev) // no PLL for Emulator
val &= ~INFINIPATH_HWE_SERDESPLLFAILED;
- /* workaround bug 9460 in internal interface bus parity checking */
- val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
-
+ if (dd->ipath_minrev < 2) {
+ /* workaround bug 9460 in internal interface bus parity
+ * checking. Fixed (HW bug 9490) in Rev2.
+ */
+ val &= ~INFINIPATH_HWE_PCIEBUSPARITYRADM;
+ }
dd->ipath_hwerrmask = val;
}
@@ -583,8 +602,8 @@ static void ipath_pe_init_hwerrors(struct ipath_devdata *dd)
*/
static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
{
- u64 val, tmp, config1;
- int ret = 0, change = 0;
+ u64 val, tmp, config1, prev_val;
+ int ret = 0;
ipath_dbg("Trying to bringup serdes\n");
@@ -641,6 +660,7 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_xgxsconfig);
+ prev_val = val;
if (((val >> INFINIPATH_XGXS_MDIOADDR_SHIFT) &
INFINIPATH_XGXS_MDIOADDR_MASK) != 3) {
val &=
@@ -648,11 +668,9 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
INFINIPATH_XGXS_MDIOADDR_SHIFT);
/* MDIO address 3 */
val |= 3ULL << INFINIPATH_XGXS_MDIOADDR_SHIFT;
- change = 1;
}
if (val & INFINIPATH_XGXS_RESET) {
val &= ~INFINIPATH_XGXS_RESET;
- change = 1;
}
if (((val >> INFINIPATH_XGXS_RX_POL_SHIFT) &
INFINIPATH_XGXS_RX_POL_MASK) != dd->ipath_rx_pol_inv ) {
@@ -661,9 +679,19 @@ static int ipath_pe_bringup_serdes(struct ipath_devdata *dd)
INFINIPATH_XGXS_RX_POL_SHIFT);
val |= dd->ipath_rx_pol_inv <<
INFINIPATH_XGXS_RX_POL_SHIFT;
- change = 1;
}
- if (change)
+ if (dd->ipath_minrev >= 2) {
+ /* Rev 2. can tolerate multiple writes to PBC, and
+ * allowing them can provide lower latency on some
+ * CPUs, but this feature is off by default, only
+ * turned on by setting D63 of XGXSconfig reg.
+ * May want to make this conditional more
+ * fine-grained in future. This is not exactly
+ * related to XGXS, but where the bit ended up.
+ */
+ val |= INFINIPATH_XGXS_SUPPRESS_ARMLAUNCH_ERR;
+ }
+ if (val != prev_val)
ipath_write_kreg(dd, dd->ipath_kregs->kr_xgxsconfig, val);
val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_serdesconfig0);
@@ -717,9 +745,25 @@ static void ipath_pe_quiet_serdes(struct ipath_devdata *dd)
ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val);
}
-/* this is not yet needed on this chip, so just return 0. */
static int ipath_pe_intconfig(struct ipath_devdata *dd)
{
+ u64 val;
+ u32 chiprev;
+
+ /*
+ * If the chip supports added error indication via GPIO pins,
+ * enable interrupts on those bits so the interrupt routine
+ * can count the events. Also set flag so interrupt routine
+ * can know they are expected.
+ */
+ chiprev = dd->ipath_revision >> INFINIPATH_R_CHIPREVMINOR_SHIFT;
+ if ((chiprev & INFINIPATH_R_CHIPREVMINOR_MASK) > 1) {
+ /* Rev2+ reports extra errors via internal GPIO pins */
+ dd->ipath_flags |= IPATH_GPIO_ERRINTRS;
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
+ val |= IPATH_GPIO_ERRINTR_MASK;
+ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
+ }
return 0;
}
@@ -853,21 +897,23 @@ static int ipath_setup_pe_config(struct ipath_devdata *dd,
return 0;
}
-static void ipath_init_pe_variables(void)
+static void ipath_init_pe_variables(struct ipath_devdata *dd)
{
/*
* bits for selecting i2c direction and values,
* used for I2C serial flash
*/
- ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
- ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
- ipath_gpio_sda = IPATH_GPIO_SDA;
- ipath_gpio_scl = IPATH_GPIO_SCL;
+ dd->ipath_gpio_sda_num = _IPATH_GPIO_SDA_NUM;
+ dd->ipath_gpio_scl_num = _IPATH_GPIO_SCL_NUM;
+ dd->ipath_gpio_sda = IPATH_GPIO_SDA;
+ dd->ipath_gpio_scl = IPATH_GPIO_SCL;
/* variables for sanity checking interrupt and errors */
- infinipath_hwe_bitsextant =
+ dd->ipath_hwe_bitsextant =
(INFINIPATH_HWE_RXEMEMPARITYERR_MASK <<
INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) |
+ (INFINIPATH_HWE_TXEMEMPARITYERR_MASK <<
+ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) |
(INFINIPATH_HWE_PCIEMEMPARITYERR_MASK <<
INFINIPATH_HWE_PCIEMEMPARITYERR_SHIFT) |
INFINIPATH_HWE_PCIE1PLLFAILED |
@@ -883,13 +929,13 @@ static void ipath_init_pe_variables(void)
INFINIPATH_HWE_SERDESPLLFAILED |
INFINIPATH_HWE_IBCBUSTOSPCPARITYERR |
INFINIPATH_HWE_IBCBUSFRSPCPARITYERR;
- infinipath_i_bitsextant =
+ dd->ipath_i_bitsextant =
(INFINIPATH_I_RCVURG_MASK << INFINIPATH_I_RCVURG_SHIFT) |
(INFINIPATH_I_RCVAVAIL_MASK <<
INFINIPATH_I_RCVAVAIL_SHIFT) |
INFINIPATH_I_ERROR | INFINIPATH_I_SPIOSENT |
INFINIPATH_I_SPIOBUFAVAIL | INFINIPATH_I_GPIO;
- infinipath_e_bitsextant =
+ dd->ipath_e_bitsextant =
INFINIPATH_E_RFORMATERR | INFINIPATH_E_RVCRC |
INFINIPATH_E_RICRC | INFINIPATH_E_RMINPKTLEN |
INFINIPATH_E_RMAXPKTLEN | INFINIPATH_E_RLONGPKTLEN |
@@ -907,8 +953,8 @@ static void ipath_init_pe_variables(void)
INFINIPATH_E_INVALIDADDR | INFINIPATH_E_RESET |
INFINIPATH_E_HARDWARE;
- infinipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
- infinipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
+ dd->ipath_i_rcvavail_mask = INFINIPATH_I_RCVAVAIL_MASK;
+ dd->ipath_i_rcvurg_mask = INFINIPATH_I_RCVURG_MASK;
}
/* setup the MSI stuff again after a reset. I'd like to just call
@@ -1082,6 +1128,45 @@ static void ipath_pe_put_tid(struct ipath_devdata *dd, u64 __iomem *tidptr,
mmiowb();
spin_unlock_irqrestore(&dd->ipath_tid_lock, flags);
}
+/**
+ * ipath_pe_put_tid_2 - write a TID in chip, Revision 2 or higher
+ * @dd: the infinipath device
+ * @tidptr: pointer to the expected TID (in chip) to udpate
+ * @tidtype: 0 for eager, 1 for expected
+ * @pa: physical address of in memory buffer; ipath_tidinvalid if freeing
+ *
+ * This exists as a separate routine to allow for selection of the
+ * appropriate "flavor". The static calls in cleanup just use the
+ * revision-agnostic form, as they are not performance critical.
+ */
+static void ipath_pe_put_tid_2(struct ipath_devdata *dd, u64 __iomem *tidptr,
+ u32 type, unsigned long pa)
+{
+ u32 __iomem *tidp32 = (u32 __iomem *)tidptr;
+
+ if (pa != dd->ipath_tidinvalid) {
+ if (pa & ((1U << 11) - 1)) {
+ dev_info(&dd->pcidev->dev, "BUG: physaddr %lx "
+ "not 2KB aligned!\n", pa);
+ return;
+ }
+ pa >>= 11;
+ /* paranoia check */
+ if (pa & (7<<29))
+ ipath_dev_err(dd,
+ "BUG: Physical page address 0x%lx "
+ "has bits set in 31-29\n", pa);
+
+ if (type == 0)
+ pa |= dd->ipath_tidtemplate;
+ else /* for now, always full 4KB page */
+ pa |= 2 << 29;
+ }
+ if (dd->ipath_kregbase)
+ writel(pa, tidp32);
+ mmiowb();
+}
+
/**
* ipath_pe_clear_tid - clear all TID entries for a port, expected and eager
@@ -1203,7 +1288,7 @@ int __attribute__((weak)) ipath_unordered_wc(void)
/**
* ipath_init_pe_get_base_info - set chip-specific flags for user code
- * @dd: the infinipath device
+ * @pd: the infinipath port
* @kbase: ipath_base_info pointer
*
* We set the PCIE flag because the lower bandwidth on PCIe vs
@@ -1212,6 +1297,7 @@ int __attribute__((weak)) ipath_unordered_wc(void)
static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
{
struct ipath_base_info *kinfo = kbase;
+ struct ipath_devdata *dd;
if (ipath_unordered_wc()) {
kinfo->spi_runtime_flags |= IPATH_RUNTIME_FORCE_WC_ORDER;
@@ -1220,8 +1306,20 @@ static int ipath_pe_get_base_info(struct ipath_portdata *pd, void *kbase)
else
ipath_cdbg(PROC, "Not Intel processor, WC ordered\n");
- kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
+ if (pd == NULL)
+ goto done;
+ dd = pd->port_dd;
+
+ if (dd != NULL && dd->ipath_minrev >= 2) {
+ ipath_cdbg(PROC, "IBA6120 Rev2, allow multiple PBC write\n");
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PBC_REWRITE;
+ ipath_cdbg(PROC, "IBA6120 Rev2, allow loose DMA alignment\n");
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_LOOSE_DMA_ALIGN;
+ }
+
+done:
+ kinfo->spi_runtime_flags |= IPATH_RUNTIME_PCIE;
return 0;
}
@@ -1244,7 +1342,10 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
dd->ipath_f_quiet_serdes = ipath_pe_quiet_serdes;
dd->ipath_f_bringup_serdes = ipath_pe_bringup_serdes;
dd->ipath_f_clear_tids = ipath_pe_clear_tids;
- dd->ipath_f_put_tid = ipath_pe_put_tid;
+ if (dd->ipath_minrev >= 2)
+ dd->ipath_f_put_tid = ipath_pe_put_tid_2;
+ else
+ dd->ipath_f_put_tid = ipath_pe_put_tid;
dd->ipath_f_cleanup = ipath_setup_pe_cleanup;
dd->ipath_f_setextled = ipath_setup_pe_setextled;
dd->ipath_f_get_base_info = ipath_pe_get_base_info;
@@ -1259,6 +1360,6 @@ void ipath_init_iba6120_funcs(struct ipath_devdata *dd)
dd->ipath_kregs = &ipath_pe_kregs;
dd->ipath_cregs = &ipath_pe_cregs;
- ipath_init_pe_variables();
+ ipath_init_pe_variables(dd);
}
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 44669dc2e22d..d819cca524cd 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -88,13 +88,13 @@ MODULE_PARM_DESC(kpiobufs, "Set number of PIO buffers for driver");
static int create_port0_egr(struct ipath_devdata *dd)
{
unsigned e, egrcnt;
- struct sk_buff **skbs;
+ struct ipath_skbinfo *skbinfo;
int ret;
egrcnt = dd->ipath_rcvegrcnt;
- skbs = vmalloc(sizeof(*dd->ipath_port0_skbs) * egrcnt);
- if (skbs == NULL) {
+ skbinfo = vmalloc(sizeof(*dd->ipath_port0_skbinfo) * egrcnt);
+ if (skbinfo == NULL) {
ipath_dev_err(dd, "allocation error for eager TID "
"skb array\n");
ret = -ENOMEM;
@@ -109,13 +109,13 @@ static int create_port0_egr(struct ipath_devdata *dd)
* 4 bytes so that the data buffer stays word aligned.
* See ipath_kreceive() for more details.
*/
- skbs[e] = ipath_alloc_skb(dd, GFP_KERNEL);
- if (!skbs[e]) {
+ skbinfo[e].skb = ipath_alloc_skb(dd, GFP_KERNEL);
+ if (!skbinfo[e].skb) {
ipath_dev_err(dd, "SKB allocation error for "
"eager TID %u\n", e);
while (e != 0)
- dev_kfree_skb(skbs[--e]);
- vfree(skbs);
+ dev_kfree_skb(skbinfo[--e].skb);
+ vfree(skbinfo);
ret = -ENOMEM;
goto bail;
}
@@ -124,14 +124,17 @@ static int create_port0_egr(struct ipath_devdata *dd)
* After loop above, so we can test non-NULL to see if ready
* to use at receive, etc.
*/
- dd->ipath_port0_skbs = skbs;
+ dd->ipath_port0_skbinfo = skbinfo;
for (e = 0; e < egrcnt; e++) {
- unsigned long phys =
- virt_to_phys(dd->ipath_port0_skbs[e]->data);
+ dd->ipath_port0_skbinfo[e].phys =
+ ipath_map_single(dd->pcidev,
+ dd->ipath_port0_skbinfo[e].skb->data,
+ dd->ipath_ibmaxlen, PCI_DMA_FROMDEVICE);
dd->ipath_f_put_tid(dd, e + (u64 __iomem *)
((char __iomem *) dd->ipath_kregbase +
- dd->ipath_rcvegrbase), 0, phys);
+ dd->ipath_rcvegrbase), 0,
+ dd->ipath_port0_skbinfo[e].phys);
}
ret = 0;
@@ -432,16 +435,33 @@ done:
*/
static void init_shadow_tids(struct ipath_devdata *dd)
{
- dd->ipath_pageshadow = (struct page **)
- vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ struct page **pages;
+ dma_addr_t *addrs;
+
+ pages = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
sizeof(struct page *));
- if (!dd->ipath_pageshadow)
+ if (!pages) {
ipath_dev_err(dd, "failed to allocate shadow page * "
"array, no expected sends!\n");
- else
- memset(dd->ipath_pageshadow, 0,
- dd->ipath_cfgports * dd->ipath_rcvtidcnt *
- sizeof(struct page *));
+ dd->ipath_pageshadow = NULL;
+ return;
+ }
+
+ addrs = vmalloc(dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ sizeof(dma_addr_t));
+ if (!addrs) {
+ ipath_dev_err(dd, "failed to allocate shadow dma handle "
+ "array, no expected sends!\n");
+ vfree(dd->ipath_pageshadow);
+ dd->ipath_pageshadow = NULL;
+ return;
+ }
+
+ memset(pages, 0, dd->ipath_cfgports * dd->ipath_rcvtidcnt *
+ sizeof(struct page *));
+
+ dd->ipath_pageshadow = pages;
+ dd->ipath_physshadow = addrs;
}
static void enable_chip(struct ipath_devdata *dd,
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 49bf7bb15b04..d9079ee12030 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -37,6 +37,50 @@
#include "ipath_verbs.h"
#include "ipath_common.h"
+/*
+ * Called when we might have an error that is specific to a particular
+ * PIO buffer, and may need to cancel that buffer, so it can be re-used.
+ */
+void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
+{
+ u32 piobcnt;
+ unsigned long sbuf[4];
+ /*
+ * it's possible that sendbuffererror could have bits set; might
+ * have already done this as a result of hardware error handling
+ */
+ piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
+ /* read these before writing errorclear */
+ sbuf[0] = ipath_read_kreg64(
+ dd, dd->ipath_kregs->kr_sendbuffererror);
+ sbuf[1] = ipath_read_kreg64(
+ dd, dd->ipath_kregs->kr_sendbuffererror + 1);
+ if (piobcnt > 128) {
+ sbuf[2] = ipath_read_kreg64(
+ dd, dd->ipath_kregs->kr_sendbuffererror + 2);
+ sbuf[3] = ipath_read_kreg64(
+ dd, dd->ipath_kregs->kr_sendbuffererror + 3);
+ }
+
+ if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
+ int i;
+ if (ipath_debug & (__IPATH_PKTDBG|__IPATH_DBG)) {
+ __IPATH_DBG_WHICH(__IPATH_PKTDBG|__IPATH_DBG,
+ "SendbufErrs %lx %lx", sbuf[0],
+ sbuf[1]);
+ if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128)
+ printk(" %lx %lx ", sbuf[2], sbuf[3]);
+ printk("\n");
+ }
+
+ for (i = 0; i < piobcnt; i++)
+ if (test_bit(i, sbuf))
+ ipath_disarm_piobufs(dd, i, 1);
+ dd->ipath_lastcancel = jiffies+3; /* no armlaunch for a bit */
+ }
+}
+
+
/* These are all rcv-related errors which we want to count for stats */
#define E_SUM_PKTERRS \
(INFINIPATH_E_RHDRLEN | INFINIPATH_E_RBADTID | \
@@ -68,53 +112,9 @@
static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
{
- unsigned long sbuf[4];
u64 ignore_this_time = 0;
- u32 piobcnt;
- /* if possible that sendbuffererror could be valid */
- piobcnt = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
- /* read these before writing errorclear */
- sbuf[0] = ipath_read_kreg64(
- dd, dd->ipath_kregs->kr_sendbuffererror);
- sbuf[1] = ipath_read_kreg64(
- dd, dd->ipath_kregs->kr_sendbuffererror + 1);
- if (piobcnt > 128) {
- sbuf[2] = ipath_read_kreg64(
- dd, dd->ipath_kregs->kr_sendbuffererror + 2);
- sbuf[3] = ipath_read_kreg64(
- dd, dd->ipath_kregs->kr_sendbuffererror + 3);
- }
-
- if (sbuf[0] || sbuf[1] || (piobcnt > 128 && (sbuf[2] || sbuf[3]))) {
- int i;
-
- ipath_cdbg(PKT, "SendbufErrs %lx %lx ", sbuf[0], sbuf[1]);
- if (ipath_debug & __IPATH_PKTDBG && piobcnt > 128)
- printk("%lx %lx ", sbuf[2], sbuf[3]);
- for (i = 0; i < piobcnt; i++) {
- if (test_bit(i, sbuf)) {
- u32 __iomem *piobuf;
- if (i < dd->ipath_piobcnt2k)
- piobuf = (u32 __iomem *)
- (dd->ipath_pio2kbase +
- i * dd->ipath_palign);
- else
- piobuf = (u32 __iomem *)
- (dd->ipath_pio4kbase +
- (i - dd->ipath_piobcnt2k) *
- dd->ipath_4kalign);
-
- ipath_cdbg(PKT,
- "PIObuf[%u] @%p pbc is %x; ",
- i, piobuf, readl(piobuf));
-
- ipath_disarm_piobufs(dd, i, 1);
- }
- }
- if (ipath_debug & __IPATH_PKTDBG)
- printk("\n");
- }
+ ipath_disarm_senderrbufs(dd);
if ((errs & E_SUM_LINK_PKTERRS) &&
!(dd->ipath_flags & IPATH_LINKACTIVE)) {
/*
@@ -132,6 +132,82 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
return ignore_this_time;
}
+/* generic hw error messages... */
+#define INFINIPATH_HWE_TXEMEMPARITYERR_MSG(a) \
+ { \
+ .mask = ( INFINIPATH_HWE_TXEMEMPARITYERR_##a << \
+ INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT ), \
+ .msg = "TXE " #a " Memory Parity" \
+ }
+#define INFINIPATH_HWE_RXEMEMPARITYERR_MSG(a) \
+ { \
+ .mask = ( INFINIPATH_HWE_RXEMEMPARITYERR_##a << \
+ INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT ), \
+ .msg = "RXE " #a " Memory Parity" \
+ }
+
+static const struct ipath_hwerror_msgs ipath_generic_hwerror_msgs[] = {
+ INFINIPATH_HWE_MSG(IBCBUSFRSPCPARITYERR, "IPATH2IB Parity"),
+ INFINIPATH_HWE_MSG(IBCBUSTOSPCPARITYERR, "IB2IPATH Parity"),
+
+ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOBUF),
+ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOPBC),
+ INFINIPATH_HWE_TXEMEMPARITYERR_MSG(PIOLAUNCHFIFO),
+
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(RCVBUF),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(LOOKUPQ),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EAGERTID),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(EXPTID),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(FLAGBUF),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(DATAINFO),
+ INFINIPATH_HWE_RXEMEMPARITYERR_MSG(HDRINFO),
+};
+
+/**
+ * ipath_format_hwmsg - format a single hwerror message
+ * @msg message buffer
+ * @msgl length of message buffer
+ * @hwmsg message to add to message buffer
+ */
+static void ipath_format_hwmsg(char *msg, size_t msgl, const char *hwmsg)
+{
+ strlcat(msg, "[", msgl);
+ strlcat(msg, hwmsg, msgl);
+ strlcat(msg, "]", msgl);
+}
+
+/**
+ * ipath_format_hwerrors - format hardware error messages for display
+ * @hwerrs hardware errors bit vector
+ * @hwerrmsgs hardware error descriptions
+ * @nhwerrmsgs number of hwerrmsgs
+ * @msg message buffer
+ * @msgl message buffer length
+ */
+void ipath_format_hwerrors(u64 hwerrs,
+ const struct ipath_hwerror_msgs *hwerrmsgs,
+ size_t nhwerrmsgs,
+ char *msg, size_t msgl)
+{
+ int i;
+ const int glen =
+ sizeof(ipath_generic_hwerror_msgs) /
+ sizeof(ipath_generic_hwerror_msgs[0]);
+
+ for (i=0; i<glen; i++) {
+ if (hwerrs & ipath_generic_hwerror_msgs[i].mask) {
+ ipath_format_hwmsg(msg, msgl,
+ ipath_generic_hwerror_msgs[i].msg);
+ }
+ }
+
+ for (i=0; i<nhwerrmsgs; i++) {
+ if (hwerrs & hwerrmsgs[i].mask) {
+ ipath_format_hwmsg(msg, msgl, hwerrmsgs[i].msg);
+ }
+ }
+}
+
/* return the strings for the most common link states */
static char *ib_linkstate(u32 linkstate)
{
@@ -404,10 +480,10 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
dd->ipath_f_handle_hwerrors(dd, msg, sizeof msg);
}
- if (!noprint && (errs & ~infinipath_e_bitsextant))
+ if (!noprint && (errs & ~dd->ipath_e_bitsextant))
ipath_dev_err(dd, "error interrupt with unknown errors "
"%llx set\n", (unsigned long long)
- (errs & ~infinipath_e_bitsextant));
+ (errs & ~dd->ipath_e_bitsextant));
if (errs & E_SUM_ERRS)
ignore_this_time = handle_e_sum_errs(dd, errs);
@@ -478,6 +554,14 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
~(INFINIPATH_E_HARDWARE |
INFINIPATH_E_IBSTATUSCHANGED);
}
+
+ /* likely due to cancel, so suppress */
+ if ((errs & (INFINIPATH_E_SPKTLEN | INFINIPATH_E_SPIOARMLAUNCH)) &&
+ dd->ipath_lastcancel > jiffies) {
+ ipath_dbg("Suppressed armlaunch/spktlen after error send cancel\n");
+ errs &= ~(INFINIPATH_E_SPIOARMLAUNCH | INFINIPATH_E_SPKTLEN);
+ }
+
if (!errs)
return 0;
@@ -529,7 +613,7 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* don't report same point multiple times,
* except kernel
*/
- tl = (u32) * pd->port_rcvhdrtail_kvaddr;
+ tl = *(u64 *) pd->port_rcvhdrtail_kvaddr;
if (tl == dd->ipath_lastrcvhdrqtails[i])
continue;
hd = ipath_read_ureg32(dd, ur_rcvhdrhead,
@@ -729,9 +813,9 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
int rcvdint = 0;
portr = ((istat >> INFINIPATH_I_RCVAVAIL_SHIFT) &
- infinipath_i_rcvavail_mask)
+ dd->ipath_i_rcvavail_mask)
| ((istat >> INFINIPATH_I_RCVURG_SHIFT) &
- infinipath_i_rcvurg_mask);
+ dd->ipath_i_rcvurg_mask);
for (i = 1; i < dd->ipath_cfgports; i++) {
struct ipath_portdata *pd = dd->ipath_pd[i];
if (portr & (1 << i) && pd && pd->port_cnt &&
@@ -755,7 +839,7 @@ static void handle_urcv(struct ipath_devdata *dd, u32 istat)
}
}
-irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
+irqreturn_t ipath_intr(int irq, void *data)
{
struct ipath_devdata *dd = data;
u32 istat, chk0rcv = 0;
@@ -808,7 +892,7 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
if (oldhead != curtail) {
if (dd->ipath_flags & IPATH_GPIO_INTR) {
ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
- (u64) (1 << 2));
+ (u64) (1 << IPATH_GPIO_PORT0_BIT));
istat = port0rbits | INFINIPATH_I_GPIO;
}
else
@@ -838,10 +922,10 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
if (unexpected)
unexpected = 0;
- if (unlikely(istat & ~infinipath_i_bitsextant))
+ if (unlikely(istat & ~dd->ipath_i_bitsextant))
ipath_dev_err(dd,
"interrupt with unknown interrupts %x set\n",
- istat & (u32) ~ infinipath_i_bitsextant);
+ istat & (u32) ~ dd->ipath_i_bitsextant);
else
ipath_cdbg(VERBOSE, "intr stat=0x%x\n", istat);
@@ -867,26 +951,80 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
if (istat & INFINIPATH_I_GPIO) {
/*
- * Packets are available in the port 0 rcv queue.
- * Eventually this needs to be generalized to check
- * IPATH_GPIO_INTR, and the specific GPIO bit, if
- * GPIO interrupts are used for anything else.
+ * GPIO interrupts fall in two broad classes:
+ * GPIO_2 indicates (on some HT4xx boards) that a packet
+ * has arrived for Port 0. Checking for this
+ * is controlled by flag IPATH_GPIO_INTR.
+ * GPIO_3..5 on IBA6120 Rev2 chips indicate errors
+ * that we need to count. Checking for this
+ * is controlled by flag IPATH_GPIO_ERRINTRS.
*/
- if (unlikely(!(dd->ipath_flags & IPATH_GPIO_INTR))) {
- u32 gpiostatus;
- gpiostatus = ipath_read_kreg32(
- dd, dd->ipath_kregs->kr_gpio_status);
- ipath_dbg("Unexpected GPIO interrupt bits %x\n",
- gpiostatus);
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
- gpiostatus);
+ u32 gpiostatus;
+ u32 to_clear = 0;
+
+ gpiostatus = ipath_read_kreg32(
+ dd, dd->ipath_kregs->kr_gpio_status);
+ /* First the error-counter case.
+ */
+ if ((gpiostatus & IPATH_GPIO_ERRINTR_MASK) &&
+ (dd->ipath_flags & IPATH_GPIO_ERRINTRS)) {
+ /* want to clear the bits we see asserted. */
+ to_clear |= (gpiostatus & IPATH_GPIO_ERRINTR_MASK);
+
+ /*
+ * Count appropriately, clear bits out of our copy,
+ * as they have been "handled".
+ */
+ if (gpiostatus & (1 << IPATH_GPIO_RXUVL_BIT)) {
+ ipath_dbg("FlowCtl on UnsupVL\n");
+ dd->ipath_rxfc_unsupvl_errs++;
+ }
+ if (gpiostatus & (1 << IPATH_GPIO_OVRUN_BIT)) {
+ ipath_dbg("Overrun Threshold exceeded\n");
+ dd->ipath_overrun_thresh_errs++;
+ }
+ if (gpiostatus & (1 << IPATH_GPIO_LLI_BIT)) {
+ ipath_dbg("Local Link Integrity error\n");
+ dd->ipath_lli_errs++;
+ }
+ gpiostatus &= ~IPATH_GPIO_ERRINTR_MASK;
}
- else {
- /* Clear GPIO status bit 2 */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
- (u64) (1 << 2));
+ /* Now the Port0 Receive case */
+ if ((gpiostatus & (1 << IPATH_GPIO_PORT0_BIT)) &&
+ (dd->ipath_flags & IPATH_GPIO_INTR)) {
+ /*
+ * GPIO status bit 2 is set, and we expected it.
+ * clear it and indicate in p0bits.
+ * This probably only happens if a Port0 pkt
+ * arrives at _just_ the wrong time, and we
+ * handle that by seting chk0rcv;
+ */
+ to_clear |= (1 << IPATH_GPIO_PORT0_BIT);
+ gpiostatus &= ~(1 << IPATH_GPIO_PORT0_BIT);
chk0rcv = 1;
}
+ if (unlikely(gpiostatus)) {
+ /*
+ * Some unexpected bits remain. If they could have
+ * caused the interrupt, complain and clear.
+ * MEA: this is almost certainly non-ideal.
+ * we should look into auto-disable of unexpected
+ * GPIO interrupts, possibly on a "three strikes"
+ * basis.
+ */
+ u32 mask;
+ mask = ipath_read_kreg32(
+ dd, dd->ipath_kregs->kr_gpio_mask);
+ if (mask & gpiostatus) {
+ ipath_dbg("Unexpected GPIO IRQ bits %x\n",
+ gpiostatus & mask);
+ to_clear |= (gpiostatus & mask);
+ }
+ }
+ if (to_clear) {
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_clear,
+ (u64) to_clear);
+ }
}
chk0rcv |= istat & port0rbits;
@@ -911,9 +1049,9 @@ irqreturn_t ipath_intr(int irq, void *data, struct pt_regs *regs)
istat &= ~port0rbits;
}
- if (istat & ((infinipath_i_rcvavail_mask <<
+ if (istat & ((dd->ipath_i_rcvavail_mask <<
INFINIPATH_I_RCVAVAIL_SHIFT)
- | (infinipath_i_rcvurg_mask <<
+ | (dd->ipath_i_rcvurg_mask <<
INFINIPATH_I_RCVURG_SHIFT)))
handle_urcv(dd, istat);
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index a8a56276ff1d..06d5020a2f60 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -39,6 +39,8 @@
*/
#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include "ipath_common.h"
@@ -62,7 +64,7 @@ struct ipath_portdata {
/* rcvhdrq base, needs mmap before useful */
void *port_rcvhdrq;
/* kernel virtual address where hdrqtail is updated */
- volatile __le64 *port_rcvhdrtail_kvaddr;
+ void *port_rcvhdrtail_kvaddr;
/*
* temp buffer for expected send setup, allocated at open, instead
* of each setup call
@@ -79,8 +81,8 @@ struct ipath_portdata {
dma_addr_t port_rcvhdrq_phys;
dma_addr_t port_rcvhdrqtailaddr_phys;
/*
- * number of opens on this instance (0 or 1; ignoring forks, dup,
- * etc. for now)
+ * number of opens (including slave subports) on this instance
+ * (ignoring forks, dup, etc. for now)
*/
int port_cnt;
/*
@@ -89,6 +91,10 @@ struct ipath_portdata {
*/
/* instead of calculating it */
unsigned port_port;
+ /* non-zero if port is being shared. */
+ u16 port_subport_cnt;
+ /* non-zero if port is being shared. */
+ u16 port_subport_id;
/* chip offset of PIO buffers for this port */
u32 port_piobufs;
/* how many alloc_pages() chunks in port_rcvegrbuf_pages */
@@ -121,6 +127,16 @@ struct ipath_portdata {
u16 port_pkeys[4];
/* so file ops can get at unit */
struct ipath_devdata *port_dd;
+ /* A page of memory for rcvhdrhead, rcvegrhead, rcvegrtail * N */
+ void *subport_uregbase;
+ /* An array of pages for the eager receive buffers * N */
+ void *subport_rcvegrbuf;
+ /* An array of pages for the eager header queue entries * N */
+ void *subport_rcvhdr_base;
+ /* The version of the library which opened this port */
+ u32 userversion;
+ /* Bitmask of active slaves */
+ u32 active_slaves;
};
struct sk_buff;
@@ -132,6 +148,11 @@ struct _ipath_layer {
void *l_arg;
};
+struct ipath_skbinfo {
+ struct sk_buff *skb;
+ dma_addr_t phys;
+};
+
struct ipath_devdata {
struct list_head ipath_list;
@@ -154,7 +175,7 @@ struct ipath_devdata {
/* ipath_cfgports pointers */
struct ipath_portdata **ipath_pd;
/* sk_buffs used by port 0 eager receive queue */
- struct sk_buff **ipath_port0_skbs;
+ struct ipath_skbinfo *ipath_port0_skbinfo;
/* kvirt address of 1st 2k pio buffer */
void __iomem *ipath_pio2kbase;
/* kvirt address of 1st 4k pio buffer */
@@ -315,12 +336,16 @@ struct ipath_devdata {
u8 ipath_ht_slave_off;
/* for write combining settings */
unsigned long ipath_wc_cookie;
+ unsigned long ipath_wc_base;
+ unsigned long ipath_wc_len;
/* ref count for each pkey */
atomic_t ipath_pkeyrefs[4];
/* shadow copy of all exptids physaddr; used only by funcsim */
u64 *ipath_tidsimshadow;
/* shadow copy of struct page *'s for exp tid pages */
struct page **ipath_pageshadow;
+ /* shadow copy of dma handles for exp tid pages */
+ dma_addr_t *ipath_physshadow;
/* lock to workaround chip bug 9437 */
spinlock_t ipath_tid_lock;
@@ -402,6 +427,9 @@ struct ipath_devdata {
unsigned long ipath_rcvctrl;
/* shadow kr_sendctrl */
unsigned long ipath_sendctrl;
+ /* ports waiting for PIOavail intr */
+ unsigned long ipath_portpiowait;
+ unsigned long ipath_lastcancel; /* to not count armlaunch after cancel */
/* value we put in kr_rcvhdrcnt */
u32 ipath_rcvhdrcnt;
@@ -465,8 +493,6 @@ struct ipath_devdata {
u32 ipath_htwidth;
/* HT speed (200,400,800,1000) from HT config */
u32 ipath_htspeed;
- /* ports waiting for PIOavail intr */
- unsigned long ipath_portpiowait;
/*
* number of sequential ibcstatus change for polling active/quiet
* (i.e., link not coming up).
@@ -510,8 +536,47 @@ struct ipath_devdata {
u32 ipath_lli_counter;
/* local link integrity errors */
u32 ipath_lli_errors;
+ /*
+ * Above counts only cases where _successive_ LocalLinkIntegrity
+ * errors were seen in the receive headers of kern-packets.
+ * Below are the three (monotonically increasing) counters
+ * maintained via GPIO interrupts on iba6120-rev2.
+ */
+ u32 ipath_rxfc_unsupvl_errs;
+ u32 ipath_overrun_thresh_errs;
+ u32 ipath_lli_errs;
+
+ /*
+ * Not all devices managed by a driver instance are the same
+ * type, so these fields must be per-device.
+ */
+ u64 ipath_i_bitsextant;
+ ipath_err_t ipath_e_bitsextant;
+ ipath_err_t ipath_hwe_bitsextant;
+
+ /*
+ * Below should be computable from number of ports,
+ * since they are never modified.
+ */
+ u32 ipath_i_rcvavail_mask;
+ u32 ipath_i_rcvurg_mask;
+
+ /*
+ * Register bits for selecting i2c direction and values, used for
+ * I2C serial flash.
+ */
+ u16 ipath_gpio_sda_num;
+ u16 ipath_gpio_scl_num;
+ u64 ipath_gpio_sda;
+ u64 ipath_gpio_scl;
};
+/* Private data for file operations */
+struct ipath_filedata {
+ struct ipath_portdata *pd;
+ unsigned subport;
+ unsigned tidcursor;
+};
extern struct list_head ipath_dev_list;
extern spinlock_t ipath_devs_lock;
extern struct ipath_devdata *ipath_lookup(int unit);
@@ -521,6 +586,7 @@ int ipath_enable_wc(struct ipath_devdata *dd);
void ipath_disable_wc(struct ipath_devdata *dd);
int ipath_count_units(int *npresentp, int *nupp, u32 *maxportsp);
void ipath_shutdown_device(struct ipath_devdata *);
+void ipath_disarm_senderrbufs(struct ipath_devdata *);
struct file_operations;
int ipath_cdev_init(int minor, char *name, struct file_operations *fops,
@@ -540,7 +606,7 @@ struct sk_buff *ipath_alloc_skb(struct ipath_devdata *dd, gfp_t);
extern int ipath_diag_inuse;
-irqreturn_t ipath_intr(int irq, void *devid, struct pt_regs *regs);
+irqreturn_t ipath_intr(int irq, void *devid);
void ipath_decode_err(char *buf, size_t blen, ipath_err_t err);
#if __IPATH_INFO || __IPATH_DBG
extern const char *ipath_ibcstatus_str[];
@@ -572,7 +638,11 @@ int ipath_set_lid(struct ipath_devdata *, u32, u8);
int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
/* for use in system calls, where we want to know device type, etc. */
-#define port_fp(fp) ((struct ipath_portdata *) (fp)->private_data)
+#define port_fp(fp) ((struct ipath_filedata *)(fp)->private_data)->pd
+#define subport_fp(fp) \
+ ((struct ipath_filedata *)(fp)->private_data)->subport
+#define tidcursor_fp(fp) \
+ ((struct ipath_filedata *)(fp)->private_data)->tidcursor
/*
* values for ipath_flags
@@ -612,6 +682,15 @@ int ipath_set_rx_pol_inv(struct ipath_devdata *dd, u8 new_pol_inv);
/* can miss port0 rx interrupts */
#define IPATH_POLL_RX_INTR 0x40000
#define IPATH_DISABLED 0x80000 /* administratively disabled */
+ /* Use GPIO interrupts for new counters */
+#define IPATH_GPIO_ERRINTRS 0x100000
+
+/* Bits in GPIO for the added interrupts */
+#define IPATH_GPIO_PORT0_BIT 2
+#define IPATH_GPIO_RXUVL_BIT 3
+#define IPATH_GPIO_OVRUN_BIT 4
+#define IPATH_GPIO_LLI_BIT 5
+#define IPATH_GPIO_ERRINTR_MASK 0x38
/* portdata flag bit offsets */
/* waiting for a packet to arrive */
@@ -790,15 +869,19 @@ int ipath_device_create_group(struct device *, struct ipath_devdata *);
void ipath_device_remove_group(struct device *, struct ipath_devdata *);
int ipath_expose_reset(struct device *);
-int ipath_diagpkt_add(void);
-void ipath_diagpkt_remove(void);
-
int ipath_init_ipathfs(void);
void ipath_exit_ipathfs(void);
int ipathfs_add_device(struct ipath_devdata *);
int ipathfs_remove_device(struct ipath_devdata *);
/*
+ * dma_addr wrappers - all 0's invalid for hw
+ */
+dma_addr_t ipath_map_page(struct pci_dev *, struct page *, unsigned long,
+ size_t, int);
+dma_addr_t ipath_map_single(struct pci_dev *, void *, size_t, int);
+
+/*
* Flush write combining store buffers (if present) and perform a write
* barrier.
*/
@@ -855,4 +938,20 @@ extern struct mutex ipath_mutex;
#endif /* _IPATH_DEBUGGING */
+/*
+ * this is used for formatting hw error messages...
+ */
+struct ipath_hwerror_msgs {
+ u64 mask;
+ const char *msg;
+};
+
+#define INFINIPATH_HWE_MSG(a, b) { .mask = INFINIPATH_HWE_##a, .msg = b }
+
+/* in ipath_intr.c... */
+void ipath_format_hwerrors(u64 hwerrs,
+ const struct ipath_hwerror_msgs *hwerrmsgs,
+ size_t nhwerrmsgs,
+ char *msg, size_t lmsg);
+
#endif /* _IPATH_KERNEL_H */
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c
index ba1b93226caa..9a6cbd05adcd 100644
--- a/drivers/infiniband/hw/ipath/ipath_keys.c
+++ b/drivers/infiniband/hw/ipath/ipath_keys.c
@@ -118,9 +118,10 @@ void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey)
* Check the IB SGE for validity and initialize our internal version
* of it.
*/
-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
+int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
struct ib_sge *sge, int acc)
{
+ struct ipath_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
struct ipath_mregion *mr;
unsigned n, m;
size_t off;
@@ -140,7 +141,8 @@ int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
goto bail;
}
mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];
- if (unlikely(mr == NULL || mr->lkey != sge->lkey)) {
+ if (unlikely(mr == NULL || mr->lkey != sge->lkey ||
+ qp->ibqp.pd != mr->pd)) {
ret = 0;
goto bail;
}
@@ -188,9 +190,10 @@ bail:
*
* Return 1 if successful, otherwise 0.
*/
-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
+int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
u32 len, u64 vaddr, u32 rkey, int acc)
{
+ struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ipath_lkey_table *rkt = &dev->lk_table;
struct ipath_sge *sge = &ss->sge;
struct ipath_mregion *mr;
@@ -214,7 +217,8 @@ int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
}
mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
- if (unlikely(mr == NULL || mr->lkey != rkey)) {
+ if (unlikely(mr == NULL || mr->lkey != rkey ||
+ qp->ibqp.pd != mr->pd)) {
ret = 0;
goto bail;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/infiniband/hw/ipath/ipath_mad.c
index 72d1db89db8f..25908b02fbe5 100644
--- a/drivers/infiniband/hw/ipath/ipath_mad.c
+++ b/drivers/infiniband/hw/ipath/ipath_mad.c
@@ -87,7 +87,8 @@ static int recv_subn_get_nodeinfo(struct ib_smp *smp,
struct ipath_devdata *dd = to_idev(ibdev)->dd;
u32 vendor, majrev, minrev;
- if (smp->attr_mod)
+ /* GUID 0 is illegal */
+ if (smp->attr_mod || (dd->ipath_guid == 0))
smp->status |= IB_SMP_INVALID_FIELD;
nip->base_version = 1;
@@ -131,10 +132,15 @@ static int recv_subn_get_guidinfo(struct ib_smp *smp,
* We only support one GUID for now. If this changes, the
* portinfo.guid_cap field needs to be updated too.
*/
- if (startgx == 0)
- /* The first is a copy of the read-only HW GUID. */
- *p = to_idev(ibdev)->dd->ipath_guid;
- else
+ if (startgx == 0) {
+ __be64 g = to_idev(ibdev)->dd->ipath_guid;
+ if (g == 0)
+ /* GUID 0 is illegal */
+ smp->status |= IB_SMP_INVALID_FIELD;
+ else
+ /* The first is a copy of the read-only HW GUID. */
+ *p = g;
+ } else
smp->status |= IB_SMP_INVALID_FIELD;
return reply(smp);
diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/infiniband/hw/ipath/ipath_mmap.c
index 11b7378ff214..a82157db4689 100644
--- a/drivers/infiniband/hw/ipath/ipath_mmap.c
+++ b/drivers/infiniband/hw/ipath/ipath_mmap.c
@@ -30,7 +30,6 @@
* SOFTWARE.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/infiniband/hw/ipath/ipath_mr.c
index b36f6fb3e37a..a0673c1eef71 100644
--- a/drivers/infiniband/hw/ipath/ipath_mr.c
+++ b/drivers/infiniband/hw/ipath/ipath_mr.c
@@ -138,6 +138,7 @@ struct ib_mr *ipath_reg_phys_mr(struct ib_pd *pd,
goto bail;
}
+ mr->mr.pd = pd;
mr->mr.user_base = *iova_start;
mr->mr.iova = *iova_start;
mr->mr.length = 0;
@@ -197,6 +198,7 @@ struct ib_mr *ipath_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
goto bail;
}
+ mr->mr.pd = pd;
mr->mr.user_base = region->user_base;
mr->mr.iova = region->virt_base;
mr->mr.length = region->length;
@@ -289,6 +291,7 @@ struct ib_fmr *ipath_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
* Resources are allocated but no valid mapping (RKEY can't be
* used).
*/
+ fmr->mr.pd = pd;
fmr->mr.user_base = 0;
fmr->mr.iova = 0;
fmr->mr.length = 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/infiniband/hw/ipath/ipath_qp.c
index 224b0f40767f..46c1c89bf6ae 100644
--- a/drivers/infiniband/hw/ipath/ipath_qp.c
+++ b/drivers/infiniband/hw/ipath/ipath_qp.c
@@ -335,6 +335,7 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
qp->r_ack_state = IB_OPCODE_RC_ACKNOWLEDGE;
qp->r_nak_state = 0;
+ qp->r_wrid_valid = 0;
qp->s_rnr_timeout = 0;
qp->s_head = 0;
qp->s_tail = 0;
@@ -342,6 +343,7 @@ static void ipath_reset_qp(struct ipath_qp *qp)
qp->s_last = 0;
qp->s_ssn = 1;
qp->s_lsn = 0;
+ qp->s_wait_credit = 0;
if (qp->r_rq.wq) {
qp->r_rq.wq->head = 0;
qp->r_rq.wq->tail = 0;
@@ -352,12 +354,13 @@ static void ipath_reset_qp(struct ipath_qp *qp)
/**
* ipath_error_qp - put a QP into an error state
* @qp: the QP to put into an error state
+ * @err: the receive completion error to signal if a RWQE is active
*
* Flushes both send and receive work queues.
* QP s_lock should be held and interrupts disabled.
*/
-void ipath_error_qp(struct ipath_qp *qp)
+void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
{
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
struct ib_wc wc;
@@ -373,7 +376,6 @@ void ipath_error_qp(struct ipath_qp *qp)
list_del_init(&qp->piowait);
spin_unlock(&dev->pending_lock);
- wc.status = IB_WC_WR_FLUSH_ERR;
wc.vendor_err = 0;
wc.byte_len = 0;
wc.imm_data = 0;
@@ -385,6 +387,12 @@ void ipath_error_qp(struct ipath_qp *qp)
wc.sl = 0;
wc.dlid_path_bits = 0;
wc.port_num = 0;
+ if (qp->r_wrid_valid) {
+ qp->r_wrid_valid = 0;
+ wc.status = err;
+ ipath_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 1);
+ }
+ wc.status = IB_WC_WR_FLUSH_ERR;
while (qp->s_last != qp->s_head) {
struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
@@ -501,7 +509,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
break;
case IB_QPS_ERR:
- ipath_error_qp(qp);
+ ipath_error_qp(qp, IB_WC_GENERAL_ERR);
break;
default:
@@ -516,7 +524,7 @@ int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
qp->remote_qpn = attr->dest_qp_num;
if (attr_mask & IB_QP_SQ_PSN) {
- qp->s_next_psn = attr->sq_psn;
+ qp->s_psn = qp->s_next_psn = attr->sq_psn;
qp->s_last_psn = qp->s_next_psn - 1;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index a08654042c03..ce6038743c5c 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -201,6 +201,18 @@ int ipath_make_rc_req(struct ipath_qp *qp,
qp->s_rnr_timeout)
goto done;
+ /* Limit the number of packets sent without an ACK. */
+ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT) > 0) {
+ qp->s_wait_credit = 1;
+ dev->n_rc_stalls++;
+ spin_lock(&dev->pending_lock);
+ if (list_empty(&qp->timerwait))
+ list_add_tail(&qp->timerwait,
+ &dev->pending[dev->pending_index]);
+ spin_unlock(&dev->pending_lock);
+ goto done;
+ }
+
/* header size in 32-bit words LRH+BTH = (8+12)/4. */
hwords = 5;
bth0 = 0;
@@ -221,7 +233,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
/* Check if send work queue is empty. */
if (qp->s_tail == qp->s_head)
goto done;
- qp->s_psn = wqe->psn = qp->s_next_psn;
+ wqe->psn = qp->s_next_psn;
newreq = 1;
}
/*
@@ -229,10 +241,7 @@ int ipath_make_rc_req(struct ipath_qp *qp,
* original work request since we may need to resend
* it.
*/
- qp->s_sge.sge = wqe->sg_list[0];
- qp->s_sge.sg_list = wqe->sg_list + 1;
- qp->s_sge.num_sge = wqe->wr.num_sge;
- qp->s_len = len = wqe->length;
+ len = wqe->length;
ss = &qp->s_sge;
bth2 = 0;
switch (wqe->wr.opcode) {
@@ -356,14 +365,23 @@ int ipath_make_rc_req(struct ipath_qp *qp,
default:
goto done;
}
+ qp->s_sge.sge = wqe->sg_list[0];
+ qp->s_sge.sg_list = wqe->sg_list + 1;
+ qp->s_sge.num_sge = wqe->wr.num_sge;
+ qp->s_len = wqe->length;
if (newreq) {
qp->s_tail++;
if (qp->s_tail >= qp->s_size)
qp->s_tail = 0;
}
- bth2 |= qp->s_psn++ & IPATH_PSN_MASK;
- if ((int)(qp->s_psn - qp->s_next_psn) > 0)
- qp->s_next_psn = qp->s_psn;
+ bth2 |= qp->s_psn & IPATH_PSN_MASK;
+ if (wqe->wr.opcode == IB_WR_RDMA_READ)
+ qp->s_psn = wqe->lpsn + 1;
+ else {
+ qp->s_psn++;
+ if ((int)(qp->s_psn - qp->s_next_psn) > 0)
+ qp->s_next_psn = qp->s_psn;
+ }
/*
* Put the QP on the pending list so lost ACKs will cause
* a retry. More than one request can be pending so the
@@ -393,12 +411,6 @@ int ipath_make_rc_req(struct ipath_qp *qp,
ss = &qp->s_sge;
len = qp->s_len;
if (len > pmtu) {
- /*
- * Request an ACK every 1/2 MB to avoid retransmit
- * timeouts.
- */
- if (((wqe->length - len) % (512 * 1024)) == 0)
- bth2 |= 1 << 31;
len = pmtu;
break;
}
@@ -435,12 +447,6 @@ int ipath_make_rc_req(struct ipath_qp *qp,
ss = &qp->s_sge;
len = qp->s_len;
if (len > pmtu) {
- /*
- * Request an ACK every 1/2 MB to avoid retransmit
- * timeouts.
- */
- if (((wqe->length - len) % (512 * 1024)) == 0)
- bth2 |= 1 << 31;
len = pmtu;
break;
}
@@ -498,6 +504,8 @@ int ipath_make_rc_req(struct ipath_qp *qp,
*/
goto done;
}
+ if (ipath_cmp24(qp->s_psn, qp->s_last_psn + IPATH_PSN_CREDIT - 1) >= 0)
+ bth2 |= 1 << 31; /* Request ACK. */
qp->s_len -= len;
qp->s_hdrwords = hwords;
qp->s_cur_sge = ss;
@@ -688,13 +696,6 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
struct ipath_swqe *wqe = get_swqe_ptr(qp, qp->s_last);
struct ipath_ibdev *dev;
- /*
- * If there are no requests pending, we are done.
- */
- if (ipath_cmp24(psn, qp->s_next_psn) >= 0 ||
- qp->s_last == qp->s_tail)
- goto done;
-
if (qp->s_retry == 0) {
wc->wr_id = wqe->wr.wr_id;
wc->status = IB_WC_RETRY_EXC_ERR;
@@ -729,14 +730,21 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
dev->n_rc_resends += (int)qp->s_psn - (int)psn;
reset_psn(qp, psn);
-
-done:
tasklet_hi_schedule(&qp->s_task);
bail:
return;
}
+static inline void update_last_psn(struct ipath_qp *qp, u32 psn)
+{
+ if (qp->s_wait_credit) {
+ qp->s_wait_credit = 0;
+ tasklet_hi_schedule(&qp->s_task);
+ }
+ qp->s_last_psn = psn;
+}
+
/**
* do_rc_ack - process an incoming RC ACK
* @qp: the QP the ACK came in on
@@ -754,6 +762,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
struct ib_wc wc;
struct ipath_swqe *wqe;
int ret = 0;
+ u32 ack_psn;
/*
* Remove the QP from the timeout queue (or RNR timeout queue).
@@ -766,26 +775,26 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
list_del_init(&qp->timerwait);
spin_unlock(&dev->pending_lock);
+ /* Nothing is pending to ACK/NAK. */
+ if (unlikely(qp->s_last == qp->s_tail))
+ goto bail;
+
/*
* Note that NAKs implicitly ACK outstanding SEND and RDMA write
* requests and implicitly NAK RDMA read and atomic requests issued
* before the NAK'ed request. The MSN won't include the NAK'ed
* request but will include an ACK'ed request(s).
*/
+ ack_psn = psn;
+ if (aeth >> 29)
+ ack_psn--;
wqe = get_swqe_ptr(qp, qp->s_last);
- /* Nothing is pending to ACK/NAK. */
- if (qp->s_last == qp->s_tail)
- goto bail;
-
/*
* The MSN might be for a later WQE than the PSN indicates so
* only complete WQEs that the PSN finishes.
*/
- while (ipath_cmp24(psn, wqe->lpsn) >= 0) {
- /* If we are ACKing a WQE, the MSN should be >= the SSN. */
- if (ipath_cmp24(aeth, wqe->ssn) < 0)
- break;
+ while (ipath_cmp24(ack_psn, wqe->lpsn) >= 0) {
/*
* If this request is a RDMA read or atomic, and the ACK is
* for a later operation, this ACK NAKs the RDMA read or
@@ -796,7 +805,8 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* is sent but before the response is received.
*/
if ((wqe->wr.opcode == IB_WR_RDMA_READ &&
- opcode != OP(RDMA_READ_RESPONSE_LAST)) ||
+ (opcode != OP(RDMA_READ_RESPONSE_LAST) ||
+ ipath_cmp24(ack_psn, wqe->lpsn) != 0)) ||
((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) &&
(opcode != OP(ATOMIC_ACKNOWLEDGE) ||
@@ -805,7 +815,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
* The last valid PSN seen is the previous
* request's.
*/
- qp->s_last_psn = wqe->psn - 1;
+ update_last_psn(qp, wqe->psn - 1);
/* Retry this request. */
ipath_restart_rc(qp, wqe->psn, &wc);
/*
@@ -814,6 +824,10 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
*/
goto bail;
}
+ if (wqe->wr.opcode == IB_WR_RDMA_READ ||
+ wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP ||
+ wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)
+ tasklet_hi_schedule(&qp->s_task);
/* Post a send completion queue entry if requested. */
if (!test_bit(IPATH_S_SIGNAL_REQ_WR, &qp->s_flags) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
@@ -864,7 +878,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
ipath_get_credit(qp, aeth);
qp->s_rnr_retry = qp->s_rnr_retry_cnt;
qp->s_retry = qp->s_retry_cnt;
- qp->s_last_psn = psn;
+ update_last_psn(qp, psn);
ret = 1;
goto bail;
@@ -883,7 +897,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
goto bail;
/* The last valid PSN is the previous PSN. */
- qp->s_last_psn = psn - 1;
+ update_last_psn(qp, psn - 1);
dev->n_rc_resends += (int)qp->s_psn - (int)psn;
@@ -898,7 +912,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
case 3: /* NAK */
/* The last valid PSN seen is the previous request's. */
if (qp->s_last != qp->s_tail)
- qp->s_last_psn = wqe->psn - 1;
+ update_last_psn(qp, wqe->psn - 1);
switch ((aeth >> IPATH_AETH_CREDIT_SHIFT) &
IPATH_AETH_CREDIT_MASK) {
case 0: /* PSN sequence error */
@@ -1044,7 +1058,8 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
/* no AETH, no ACK */
if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
dev->n_rdma_seq++;
- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ if (qp->s_last != qp->s_tail)
+ ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
goto ack_done;
}
rdma_read:
@@ -1071,7 +1086,7 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
* since we don't want s_sge modified.
*/
qp->s_len -= pmtu;
- qp->s_last_psn = psn;
+ update_last_psn(qp, psn);
spin_unlock_irqrestore(&qp->s_lock, flags);
ipath_copy_sge(&qp->s_sge, data, pmtu);
goto bail;
@@ -1080,7 +1095,8 @@ static inline void ipath_rc_rcv_resp(struct ipath_ibdev *dev,
/* ACKs READ req. */
if (unlikely(ipath_cmp24(psn, qp->s_last_psn + 1))) {
dev->n_rdma_seq++;
- ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
+ if (qp->s_last != qp->s_tail)
+ ipath_restart_rc(qp, qp->s_last_psn + 1, &wc);
goto ack_done;
}
/* FALLTHROUGH */
@@ -1223,7 +1239,7 @@ static inline int ipath_rc_rcv_error(struct ipath_ibdev *dev,
* Address range must be a subset of the original
* request and start on pmtu boundaries.
*/
- ok = ipath_rkey_ok(dev, &qp->s_rdma_sge,
+ ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
qp->s_rdma_len, vaddr, rkey,
IB_ACCESS_REMOTE_READ);
if (unlikely(!ok)) {
@@ -1282,6 +1298,14 @@ done:
return 1;
}
+static void ipath_rc_error(struct ipath_qp *qp, enum ib_wc_status err)
+{
+ spin_lock_irq(&qp->s_lock);
+ qp->state = IB_QPS_ERR;
+ ipath_error_qp(qp, err);
+ spin_unlock_irq(&qp->s_lock);
+}
+
/**
* ipath_rc_rcv - process an incoming RC packet
* @dev: the device this packet came in on
@@ -1309,6 +1333,10 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
struct ib_reth *reth;
int header_in_data;
+ /* Validate the SLID. See Ch. 9.6.1.5 */
+ if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
+ goto done;
+
/* Check for GRH */
if (!has_grh) {
ohdr = &hdr->u.oth;
@@ -1370,8 +1398,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
*/
if (qp->r_ack_state >= OP(COMPARE_SWAP))
goto send_ack;
- /* XXX Flush WQEs */
- qp->state = IB_QPS_ERR;
+ ipath_rc_error(qp, IB_WC_REM_INV_REQ_ERR);
qp->r_ack_state = OP(SEND_ONLY);
qp->r_nak_state = IB_NAK_INVALID_REQUEST;
qp->r_ack_psn = qp->r_psn;
@@ -1477,9 +1504,9 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
goto nack_inv;
ipath_copy_sge(&qp->r_sge, data, tlen);
qp->r_msn++;
- if (opcode == OP(RDMA_WRITE_LAST) ||
- opcode == OP(RDMA_WRITE_ONLY))
+ if (!qp->r_wrid_valid)
break;
+ qp->r_wrid_valid = 0;
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = IB_WC_RECV;
@@ -1517,7 +1544,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int ok;
/* Check rkey & NAK */
- ok = ipath_rkey_ok(dev, &qp->r_sge,
+ ok = ipath_rkey_ok(qp, &qp->r_sge,
qp->r_len, vaddr, rkey,
IB_ACCESS_REMOTE_WRITE);
if (unlikely(!ok))
@@ -1559,7 +1586,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int ok;
/* Check rkey & NAK */
- ok = ipath_rkey_ok(dev, &qp->s_rdma_sge,
+ ok = ipath_rkey_ok(qp, &qp->s_rdma_sge,
qp->s_rdma_len, vaddr, rkey,
IB_ACCESS_REMOTE_READ);
if (unlikely(!ok)) {
@@ -1618,7 +1645,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
goto nack_inv;
rkey = be32_to_cpu(ateth->rkey);
/* Check rkey & NAK */
- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge,
+ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge,
sizeof(u64), vaddr, rkey,
IB_ACCESS_REMOTE_ATOMIC)))
goto nack_acc;
@@ -1670,8 +1697,7 @@ nack_acc:
* is pending though.
*/
if (qp->r_ack_state < OP(COMPARE_SWAP)) {
- /* XXX Flush WQEs */
- qp->state = IB_QPS_ERR;
+ ipath_rc_error(qp, IB_WC_REM_ACCESS_ERR);
qp->r_ack_state = OP(RDMA_WRITE_ONLY);
qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR;
qp->r_ack_psn = qp->r_psn;
diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/infiniband/hw/ipath/ipath_registers.h
index 6e23b3d632b8..dffc76016d3c 100644
--- a/drivers/infiniband/hw/ipath/ipath_registers.h
+++ b/drivers/infiniband/hw/ipath/ipath_registers.h
@@ -134,10 +134,24 @@
#define INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT 40
#define INFINIPATH_HWE_RXEMEMPARITYERR_MASK 0x7FULL
#define INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT 44
-#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR 0x0000000400000000ULL
-#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL
#define INFINIPATH_HWE_IBCBUSTOSPCPARITYERR 0x4000000000000000ULL
#define INFINIPATH_HWE_IBCBUSFRSPCPARITYERR 0x8000000000000000ULL
+/* txe mem parity errors (shift by INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT) */
+#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF 0x1ULL
+#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC 0x2ULL
+#define INFINIPATH_HWE_TXEMEMPARITYERR_PIOLAUNCHFIFO 0x4ULL
+/* rxe mem parity errors (shift by INFINIPATH_HWE_RXEMEMPARITYERR_SHIFT) */
+#define INFINIPATH_HWE_RXEMEMPARITYERR_RCVBUF 0x01ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_LOOKUPQ 0x02ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_EAGERTID 0x04ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_EXPTID 0x08ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_FLAGBUF 0x10ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_DATAINFO 0x20ULL
+#define INFINIPATH_HWE_RXEMEMPARITYERR_HDRINFO 0x40ULL
+/* waldo specific -- find the rest in ipath_6110.c */
+#define INFINIPATH_HWE_RXDSYNCMEMPARITYERR 0x0000000400000000ULL
+/* monty specific -- find the rest in ipath_6120.c */
+#define INFINIPATH_HWE_MEMBISTFAILED 0x0040000000000000ULL
/* kr_hwdiagctrl bits */
#define INFINIPATH_DC_FORCETXEMEMPARITYERR_MASK 0xFULL
@@ -209,9 +223,9 @@
/* combination link status states that we use with some frequency */
#define IPATH_IBSTATE_MASK ((INFINIPATH_IBCS_LINKTRAININGSTATE_MASK \
- << INFINIPATH_IBCS_LINKSTATE_SHIFT) | \
+ << INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT) | \
(INFINIPATH_IBCS_LINKSTATE_MASK \
- <<INFINIPATH_IBCS_LINKTRAININGSTATE_SHIFT))
+ <<INFINIPATH_IBCS_LINKSTATE_SHIFT))
#define IPATH_IBSTATE_INIT ((INFINIPATH_IBCS_L_STATE_INIT \
<< INFINIPATH_IBCS_LINKSTATE_SHIFT) | \
(INFINIPATH_IBCS_LT_STATE_LINKUP \
@@ -302,6 +316,17 @@
typedef u64 ipath_err_t;
+/* The following change with the type of device, so
+ * need to be part of the ipath_devdata struct, or
+ * we could have problems plugging in devices of
+ * different types (e.g. one HT, one PCIE)
+ * in one system, to be managed by one driver.
+ * On the other hand, this file is may also be included
+ * by other code, so leave the declarations here
+ * temporarily. Minor footprint issue if common-model
+ * linker used, none if C89+ linker used.
+ */
+
/* mask of defined bits for various registers */
extern u64 infinipath_i_bitsextant;
extern ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
@@ -310,13 +335,6 @@ extern ipath_err_t infinipath_e_bitsextant, infinipath_hwe_bitsextant;
extern u32 infinipath_i_rcvavail_mask, infinipath_i_rcvurg_mask;
/*
- * register bits for selecting i2c direction and values, used for I2C serial
- * flash
- */
-extern u16 ipath_gpio_sda_num, ipath_gpio_scl_num;
-extern u64 ipath_gpio_sda, ipath_gpio_scl;
-
-/*
* These are the infinipath general register numbers (not offsets).
* The kernel registers are used directly, those beyond the kernel
* registers are calculated from one of the base registers. The use of
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 5c1da2d25e03..f7530512045d 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -108,7 +108,6 @@ void ipath_insert_rnr_queue(struct ipath_qp *qp)
static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
{
- struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
int user = to_ipd(qp->ibqp.pd)->user;
int i, j, ret;
struct ib_wc wc;
@@ -119,8 +118,7 @@ static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe)
continue;
/* Check LKEY */
if ((user && wqe->sg_list[i].lkey == 0) ||
- !ipath_lkey_ok(&dev->lk_table,
- &qp->r_sg_list[j], &wqe->sg_list[i],
+ !ipath_lkey_ok(qp, &qp->r_sg_list[j], &wqe->sg_list[i],
IB_ACCESS_LOCAL_WRITE))
goto bad_lkey;
qp->r_len += wqe->sg_list[i].length;
@@ -231,6 +229,7 @@ int ipath_get_rwqe(struct ipath_qp *qp, int wr_id_only)
}
}
spin_unlock_irqrestore(&rq->lock, flags);
+ qp->r_wrid_valid = 1;
bail:
return ret;
@@ -326,7 +325,7 @@ again:
case IB_WR_RDMA_WRITE:
if (wqe->length == 0)
break;
- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, wqe->length,
+ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, wqe->length,
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
IB_ACCESS_REMOTE_WRITE))) {
@@ -350,7 +349,7 @@ again:
break;
case IB_WR_RDMA_READ:
- if (unlikely(!ipath_rkey_ok(dev, &sqp->s_sge, wqe->length,
+ if (unlikely(!ipath_rkey_ok(qp, &sqp->s_sge, wqe->length,
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
IB_ACCESS_REMOTE_READ)))
@@ -365,7 +364,7 @@ again:
case IB_WR_ATOMIC_CMP_AND_SWP:
case IB_WR_ATOMIC_FETCH_AND_ADD:
- if (unlikely(!ipath_rkey_ok(dev, &qp->r_sge, sizeof(u64),
+ if (unlikely(!ipath_rkey_ok(qp, &qp->r_sge, sizeof(u64),
wqe->wr.wr.rdma.remote_addr,
wqe->wr.wr.rdma.rkey,
IB_ACCESS_REMOTE_ATOMIC)))
@@ -575,8 +574,7 @@ int ipath_post_ruc_send(struct ipath_qp *qp, struct ib_send_wr *wr)
}
if (wr->sg_list[i].length == 0)
continue;
- if (!ipath_lkey_ok(&to_idev(qp->ibqp.device)->lk_table,
- &wqe->sg_list[j], &wr->sg_list[i],
+ if (!ipath_lkey_ok(qp, &wqe->sg_list[j], &wr->sg_list[i],
acc)) {
spin_unlock_irqrestore(&qp->s_lock, flags);
ret = -EINVAL;
diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/infiniband/hw/ipath/ipath_srq.c
index 941e866d9517..94033503400c 100644
--- a/drivers/infiniband/hw/ipath/ipath_srq.c
+++ b/drivers/infiniband/hw/ipath/ipath_srq.c
@@ -104,11 +104,6 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
u32 sz;
struct ib_srq *ret;
- if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
- ret = ERR_PTR(-ENOMEM);
- goto done;
- }
-
if (srq_init_attr->attr.max_wr == 0) {
ret = ERR_PTR(-EINVAL);
goto done;
@@ -180,10 +175,17 @@ struct ib_srq *ipath_create_srq(struct ib_pd *ibpd,
spin_lock_init(&srq->rq.lock);
srq->rq.wq->head = 0;
srq->rq.wq->tail = 0;
- srq->rq.max_sge = srq_init_attr->attr.max_sge;
srq->limit = srq_init_attr->attr.srq_limit;
- dev->n_srqs_allocated++;
+ spin_lock(&dev->n_srqs_lock);
+ if (dev->n_srqs_allocated == ib_ipath_max_srqs) {
+ spin_unlock(&dev->n_srqs_lock);
+ ret = ERR_PTR(-ENOMEM);
+ goto bail_wq;
+ }
+
+ dev->n_srqs_allocated++;
+ spin_unlock(&dev->n_srqs_lock);
ret = &srq->ibsrq;
goto done;
@@ -351,8 +353,13 @@ int ipath_destroy_srq(struct ib_srq *ibsrq)
struct ipath_srq *srq = to_isrq(ibsrq);
struct ipath_ibdev *dev = to_idev(ibsrq->device);
+ spin_lock(&dev->n_srqs_lock);
dev->n_srqs_allocated--;
- vfree(srq->rq.wq);
+ spin_unlock(&dev->n_srqs_lock);
+ if (srq->ip)
+ kref_put(&srq->ip->ref, ipath_release_mmap_info);
+ else
+ vfree(srq->rq.wq);
kfree(srq);
return 0;
diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/infiniband/hw/ipath/ipath_sysfs.c
index e299148c4b68..182de34f9f47 100644
--- a/drivers/infiniband/hw/ipath/ipath_sysfs.c
+++ b/drivers/infiniband/hw/ipath/ipath_sysfs.c
@@ -257,7 +257,7 @@ static ssize_t store_guid(struct device *dev,
struct ipath_devdata *dd = dev_get_drvdata(dev);
ssize_t ret;
unsigned short guid[8];
- __be64 nguid;
+ __be64 new_guid;
u8 *ng;
int i;
@@ -266,7 +266,7 @@ static ssize_t store_guid(struct device *dev,
&guid[4], &guid[5], &guid[6], &guid[7]) != 8)
goto invalid;
- ng = (u8 *) &nguid;
+ ng = (u8 *) &new_guid;
for (i = 0; i < 8; i++) {
if (guid[i] > 0xff)
@@ -274,7 +274,10 @@ static ssize_t store_guid(struct device *dev,
ng[i] = guid[i];
}
- dd->ipath_guid = nguid;
+ if (new_guid == 0)
+ goto invalid;
+
+ dd->ipath_guid = new_guid;
dd->ipath_nguid = 1;
ret = strlen(buf);
@@ -297,6 +300,16 @@ static ssize_t show_nguid(struct device *dev,
return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_nguid);
}
+static ssize_t show_nports(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ipath_devdata *dd = dev_get_drvdata(dev);
+
+ /* Return the number of user ports available. */
+ return scnprintf(buf, PAGE_SIZE, "%u\n", dd->ipath_cfgports - 1);
+}
+
static ssize_t show_serial(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -608,6 +621,7 @@ static DEVICE_ATTR(mlid, S_IWUSR | S_IRUGO, show_mlid, store_mlid);
static DEVICE_ATTR(mtu, S_IWUSR | S_IRUGO, show_mtu, store_mtu);
static DEVICE_ATTR(enabled, S_IWUSR | S_IRUGO, show_enabled, store_enabled);
static DEVICE_ATTR(nguid, S_IRUGO, show_nguid, NULL);
+static DEVICE_ATTR(nports, S_IRUGO, show_nports, NULL);
static DEVICE_ATTR(reset, S_IWUSR, NULL, store_reset);
static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
static DEVICE_ATTR(status, S_IRUGO, show_status, NULL);
@@ -623,6 +637,7 @@ static struct attribute *dev_attributes[] = {
&dev_attr_mlid.attr,
&dev_attr_mtu.attr,
&dev_attr_nguid.attr,
+ &dev_attr_nports.attr,
&dev_attr_serial.attr,
&dev_attr_status.attr,
&dev_attr_status_str.attr,
diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/infiniband/hw/ipath/ipath_uc.c
index 0fd3cded16ba..e636cfd67a82 100644
--- a/drivers/infiniband/hw/ipath/ipath_uc.c
+++ b/drivers/infiniband/hw/ipath/ipath_uc.c
@@ -246,6 +246,10 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
struct ib_reth *reth;
int header_in_data;
+ /* Validate the SLID. See Ch. 9.6.1.5 */
+ if (unlikely(be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid))
+ goto done;
+
/* Check for GRH */
if (!has_grh) {
ohdr = &hdr->u.oth;
@@ -440,7 +444,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
int ok;
/* Check rkey */
- ok = ipath_rkey_ok(dev, &qp->r_sge, qp->r_len,
+ ok = ipath_rkey_ok(qp, &qp->r_sge, qp->r_len,
vaddr, rkey,
IB_ACCESS_REMOTE_WRITE);
if (unlikely(!ok)) {
diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/infiniband/hw/ipath/ipath_ud.c
index 6991d1d74e3c..49f1102af8b3 100644
--- a/drivers/infiniband/hw/ipath/ipath_ud.c
+++ b/drivers/infiniband/hw/ipath/ipath_ud.c
@@ -39,7 +39,6 @@
static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
u32 *lengthp, struct ipath_sge_state *ss)
{
- struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
int user = to_ipd(qp->ibqp.pd)->user;
int i, j, ret;
struct ib_wc wc;
@@ -50,8 +49,7 @@ static int init_sge(struct ipath_qp *qp, struct ipath_rwqe *wqe,
continue;
/* Check LKEY */
if ((user && wqe->sg_list[i].lkey == 0) ||
- !ipath_lkey_ok(&dev->lk_table,
- j ? &ss->sg_list[j - 1] : &ss->sge,
+ !ipath_lkey_ok(qp, j ? &ss->sg_list[j - 1] : &ss->sge,
&wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE))
goto bad_lkey;
*lengthp += wqe->sg_list[i].length;
@@ -343,7 +341,7 @@ int ipath_post_ud_send(struct ipath_qp *qp, struct ib_send_wr *wr)
if (wr->sg_list[i].length == 0)
continue;
- if (!ipath_lkey_ok(&dev->lk_table, ss.num_sge ?
+ if (!ipath_lkey_ok(qp, ss.num_sge ?
sg_list + ss.num_sge - 1 : &ss.sge,
&wr->sg_list[i], 0)) {
ret = -EINVAL;
diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/infiniband/hw/ipath/ipath_user_pages.c
index e32fca9faf80..413754b1d8a2 100644
--- a/drivers/infiniband/hw/ipath/ipath_user_pages.c
+++ b/drivers/infiniband/hw/ipath/ipath_user_pages.c
@@ -90,6 +90,62 @@ bail:
}
/**
+ * ipath_map_page - a safety wrapper around pci_map_page()
+ *
+ * A dma_addr of all 0's is interpreted by the chip as "disabled".
+ * Unfortunately, it can also be a valid dma_addr returned on some
+ * architectures.
+ *
+ * The powerpc iommu assigns dma_addrs in ascending order, so we don't
+ * have to bother with retries or mapping a dummy page to insure we
+ * don't just get the same mapping again.
+ *
+ * I'm sure we won't be so lucky with other iommu's, so FIXME.
+ */
+dma_addr_t ipath_map_page(struct pci_dev *hwdev, struct page *page,
+ unsigned long offset, size_t size, int direction)
+{
+ dma_addr_t phys;
+
+ phys = pci_map_page(hwdev, page, offset, size, direction);
+
+ if (phys == 0) {
+ pci_unmap_page(hwdev, phys, size, direction);
+ phys = pci_map_page(hwdev, page, offset, size, direction);
+ /*
+ * FIXME: If we get 0 again, we should keep this page,
+ * map another, then free the 0 page.
+ */
+ }
+
+ return phys;
+}
+
+/**
+ * ipath_map_single - a safety wrapper around pci_map_single()
+ *
+ * Same idea as ipath_map_page().
+ */
+dma_addr_t ipath_map_single(struct pci_dev *hwdev, void *ptr, size_t size,
+ int direction)
+{
+ dma_addr_t phys;
+
+ phys = pci_map_single(hwdev, ptr, size, direction);
+
+ if (phys == 0) {
+ pci_unmap_single(hwdev, phys, size, direction);
+ phys = pci_map_single(hwdev, ptr, size, direction);
+ /*
+ * FIXME: If we get 0 again, we should keep this page,
+ * map another, then free the 0 page.
+ */
+ }
+
+ return phys;
+}
+
+/**
* ipath_get_user_pages - lock user pages into memory
* @start_page: the start page
* @num_pages: the number of pages
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index b8381c5e72bd..a5456108dbad 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -898,7 +898,8 @@ int ipath_get_counters(struct ipath_devdata *dd,
ipath_snap_cntr(dd, dd->ipath_cregs->cr_erricrccnt) +
ipath_snap_cntr(dd, dd->ipath_cregs->cr_errvcrccnt) +
ipath_snap_cntr(dd, dd->ipath_cregs->cr_errlpcrccnt) +
- ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt);
+ ipath_snap_cntr(dd, dd->ipath_cregs->cr_badformatcnt) +
+ dd->ipath_rxfc_unsupvl_errs;
cntrs->port_rcv_remphys_errors =
ipath_snap_cntr(dd, dd->ipath_cregs->cr_rcvebpcnt);
cntrs->port_xmit_discards =
@@ -911,8 +912,10 @@ int ipath_get_counters(struct ipath_devdata *dd,
ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktsendcnt);
cntrs->port_rcv_packets =
ipath_snap_cntr(dd, dd->ipath_cregs->cr_pktrcvcnt);
- cntrs->local_link_integrity_errors = dd->ipath_lli_errors;
- cntrs->excessive_buffer_overrun_errors = 0; /* XXX */
+ cntrs->local_link_integrity_errors =
+ (dd->ipath_flags & IPATH_GPIO_ERRINTRS) ?
+ dd->ipath_lli_errs : dd->ipath_lli_errors;
+ cntrs->excessive_buffer_overrun_errors = dd->ipath_overrun_thresh_errs;
ret = 0;
@@ -1199,6 +1202,7 @@ static struct ib_ah *ipath_create_ah(struct ib_pd *pd,
struct ipath_ah *ah;
struct ib_ah *ret;
struct ipath_ibdev *dev = to_idev(pd->device);
+ unsigned long flags;
/* A multicast address requires a GRH (see ch. 8.4.1). */
if (ah_attr->dlid >= IPATH_MULTICAST_LID_BASE &&
@@ -1225,16 +1229,16 @@ static struct ib_ah *ipath_create_ah(struct ib_pd *pd,
goto bail;
}
- spin_lock(&dev->n_ahs_lock);
+ spin_lock_irqsave(&dev->n_ahs_lock, flags);
if (dev->n_ahs_allocated == ib_ipath_max_ahs) {
- spin_unlock(&dev->n_ahs_lock);
+ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
kfree(ah);
ret = ERR_PTR(-ENOMEM);
goto bail;
}
dev->n_ahs_allocated++;
- spin_unlock(&dev->n_ahs_lock);
+ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
/* ib_create_ah() will initialize ah->ibah. */
ah->attr = *ah_attr;
@@ -1255,10 +1259,11 @@ static int ipath_destroy_ah(struct ib_ah *ibah)
{
struct ipath_ibdev *dev = to_idev(ibah->device);
struct ipath_ah *ah = to_iah(ibah);
+ unsigned long flags;
- spin_lock(&dev->n_ahs_lock);
+ spin_lock_irqsave(&dev->n_ahs_lock, flags);
dev->n_ahs_allocated--;
- spin_unlock(&dev->n_ahs_lock);
+ spin_unlock_irqrestore(&dev->n_ahs_lock, flags);
kfree(ah);
@@ -1380,11 +1385,13 @@ static int enable_timer(struct ipath_devdata *dd)
* processing.
*/
if (dd->ipath_flags & IPATH_GPIO_INTR) {
+ u64 val;
ipath_write_kreg(dd, dd->ipath_kregs->kr_debugportselect,
0x2074076542310ULL);
/* Enable GPIO bit 2 interrupt */
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask,
- (u64) (1 << 2));
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
+ val |= (u64) (1 << IPATH_GPIO_PORT0_BIT);
+ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
}
init_timer(&dd->verbs_timer);
@@ -1399,8 +1406,17 @@ static int enable_timer(struct ipath_devdata *dd)
static int disable_timer(struct ipath_devdata *dd)
{
/* Disable GPIO bit 2 interrupt */
- if (dd->ipath_flags & IPATH_GPIO_INTR)
- ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_mask, 0);
+ if (dd->ipath_flags & IPATH_GPIO_INTR) {
+ u64 val;
+ /* Disable GPIO bit 2 interrupt */
+ val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_mask);
+ val &= ~((u64) (1 << IPATH_GPIO_PORT0_BIT));
+ ipath_write_kreg( dd, dd->ipath_kregs->kr_gpio_mask, val);
+ /*
+ * We might want to undo changes to debugportselect,
+ * but how?
+ */
+ }
del_timer_sync(&dd->verbs_timer);
@@ -1585,7 +1601,7 @@ int ipath_register_ib_device(struct ipath_devdata *dd)
dev->mmap = ipath_mmap;
snprintf(dev->node_desc, sizeof(dev->node_desc),
- IPATH_IDSTR " %s", system_utsname.nodename);
+ IPATH_IDSTR " %s", init_utsname()->nodename);
ret = ib_register_device(dev);
if (ret)
@@ -1683,6 +1699,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf)
"RC OTH NAKs %d\n"
"RC timeouts %d\n"
"RC RDMA dup %d\n"
+ "RC stalls %d\n"
"piobuf wait %d\n"
"no piobuf %d\n"
"PKT drops %d\n"
@@ -1690,7 +1707,7 @@ static ssize_t show_stats(struct class_device *cdev, char *buf)
dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks,
dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks,
dev->n_other_naks, dev->n_timeouts,
- dev->n_rdma_dup_busy, dev->n_piowait,
+ dev->n_rdma_dup_busy, dev->n_rc_stalls, dev->n_piowait,
dev->n_no_piobuf, dev->n_pkt_drops, dev->n_wqe_errs);
for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) {
const struct ipath_opcode_stats *si = &dev->opstats[i];
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/infiniband/hw/ipath/ipath_verbs.h
index 09bbb3f9a217..8039f6e5f0c8 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.h
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.h
@@ -220,6 +220,7 @@ struct ipath_segarray {
};
struct ipath_mregion {
+ struct ib_pd *pd; /* shares refcnt of ibmr.pd */
u64 user_base; /* User's address for this region */
u64 iova; /* IB start address of this region */
size_t length;
@@ -364,12 +365,14 @@ struct ipath_qp {
u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */
u8 r_reuse_sge; /* for UC receive errors */
u8 r_sge_inx; /* current index into sg_list */
+ u8 r_wrid_valid; /* r_wrid set but CQ entry not yet made */
u8 qp_access_flags;
u8 s_max_sge; /* size of s_wq->sg_list */
u8 s_retry_cnt; /* number of times to retry */
u8 s_rnr_retry_cnt;
u8 s_retry; /* requester retry counter */
u8 s_rnr_retry; /* requester RNR retry counter */
+ u8 s_wait_credit; /* limit number of unacked packets sent */
u8 s_pkey_index; /* PKEY index to use */
u8 timeout; /* Timeout for this QP */
enum ib_mtu path_mtu;
@@ -393,6 +396,8 @@ struct ipath_qp {
#define IPATH_S_BUSY 0
#define IPATH_S_SIGNAL_REQ_WR 1
+#define IPATH_PSN_CREDIT 2048
+
/*
* Since struct ipath_swqe is not a fixed size, we can't simply index into
* struct ipath_qp.s_wq. This function does the array index computation.
@@ -521,6 +526,7 @@ struct ipath_ibdev {
u32 n_rnr_naks;
u32 n_other_naks;
u32 n_timeouts;
+ u32 n_rc_stalls;
u32 n_pkt_drops;
u32 n_vl15_dropped;
u32 n_wqe_errs;
@@ -634,6 +640,8 @@ struct ib_qp *ipath_create_qp(struct ib_pd *ibpd,
int ipath_destroy_qp(struct ib_qp *ibqp);
+void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err);
+
int ipath_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
int attr_mask, struct ib_udata *udata);
@@ -653,12 +661,6 @@ int ipath_verbs_send(struct ipath_devdata *dd, u32 hdrwords,
void ipath_cq_enter(struct ipath_cq *cq, struct ib_wc *entry, int sig);
-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
- u32 len, u64 vaddr, u32 rkey, int acc);
-
-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
- struct ib_sge *sge, int acc);
-
void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length);
void ipath_skip_sge(struct ipath_sge_state *ss, u32 length);
@@ -683,10 +685,10 @@ int ipath_alloc_lkey(struct ipath_lkey_table *rkt,
void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey);
-int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
+int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
struct ib_sge *sge, int acc);
-int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
+int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
u32 len, u64 vaddr, u32 rkey, int acc);
int ipath_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
index 036fde662aa9..0095bb70f34e 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
@@ -38,13 +38,23 @@
#include "ipath_kernel.h"
/**
- * ipath_unordered_wc - indicate whether write combining is ordered
+ * ipath_enable_wc - enable write combining for MMIO writes to the device
+ * @dd: infinipath device
*
- * PowerPC systems (at least those in the 970 processor family)
- * write partially filled store buffers in address order, but will write
- * completely filled store buffers in "random" order, and therefore must
- * have serialization for correctness with current InfiniPath chips.
+ * Nothing to do on PowerPC, so just return without error.
+ */
+int ipath_enable_wc(struct ipath_devdata *dd)
+{
+ return 0;
+}
+
+/**
+ * ipath_unordered_wc - indicate whether write combining is unordered
*
+ * Because our performance depends on our ability to do write
+ * combining mmio writes in the most efficient way, we need to
+ * know if we are on a processor that may reorder stores when
+ * write combining.
*/
int ipath_unordered_wc(void)
{
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
index f8f9e2e8cbdd..04696e62da87 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
@@ -123,6 +123,8 @@ int ipath_enable_wc(struct ipath_devdata *dd)
ipath_cdbg(VERBOSE, "Set mtrr for chip to WC, "
"cookie is %d\n", cookie);
dd->ipath_wc_cookie = cookie;
+ dd->ipath_wc_base = (unsigned long) pioaddr;
+ dd->ipath_wc_len = (unsigned long) piolen;
}
}
@@ -136,9 +138,16 @@ int ipath_enable_wc(struct ipath_devdata *dd)
void ipath_disable_wc(struct ipath_devdata *dd)
{
if (dd->ipath_wc_cookie) {
+ int r;
ipath_cdbg(VERBOSE, "undoing WCCOMB on pio buffers\n");
- mtrr_del(dd->ipath_wc_cookie, 0, 0);
- dd->ipath_wc_cookie = 0;
+ r = mtrr_del(dd->ipath_wc_cookie, dd->ipath_wc_base,
+ dd->ipath_wc_len);
+ if (r < 0)
+ dev_info(&dd->pcidev->dev,
+ "mtrr_del(%lx, %lx, %lx) failed: %d\n",
+ dd->ipath_wc_cookie, dd->ipath_wc_base,
+ dd->ipath_wc_len, r);
+ dd->ipath_wc_cookie = 0; /* even on failure */
}
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index e393681ba7d4..149b36901239 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -39,6 +39,8 @@
#include <linux/init.h>
#include <linux/hardirq.h>
+#include <asm/io.h>
+
#include <rdma/ib_pack.h>
#include "mthca_dev.h"
@@ -210,6 +212,11 @@ static inline void update_cons_index(struct mthca_dev *dev, struct mthca_cq *cq,
mthca_write64(doorbell,
dev->kar + MTHCA_CQ_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+ /*
+ * Make sure doorbells don't leak out of CQ spinlock
+ * and reach the HCA out of order:
+ */
+ mmiowb();
}
}
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index a29b1b6d82b1..e284e0613a94 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -405,7 +405,7 @@ static int mthca_eq_int(struct mthca_dev *dev, struct mthca_eq *eq)
return eqes_found;
}
-static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
+static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr)
{
struct mthca_dev *dev = dev_ptr;
u32 ecr;
@@ -432,8 +432,7 @@ static irqreturn_t mthca_tavor_interrupt(int irq, void *dev_ptr, struct pt_regs
return IRQ_HANDLED;
}
-static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr,
- struct pt_regs *regs)
+static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr)
{
struct mthca_eq *eq = eq_ptr;
struct mthca_dev *dev = eq->dev;
@@ -446,7 +445,7 @@ static irqreturn_t mthca_tavor_msi_x_interrupt(int irq, void *eq_ptr,
return IRQ_HANDLED;
}
-static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr, struct pt_regs *regs)
+static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr)
{
struct mthca_dev *dev = dev_ptr;
int work = 0;
@@ -467,8 +466,7 @@ static irqreturn_t mthca_arbel_interrupt(int irq, void *dev_ptr, struct pt_regs
return IRQ_RETVAL(work);
}
-static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr,
- struct pt_regs *regs)
+static irqreturn_t mthca_arbel_msi_x_interrupt(int irq, void *eq_ptr)
{
struct mthca_eq *eq = eq_ptr;
struct mthca_dev *dev = eq->dev;
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 981fe2eebdfa..fc67f780581b 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -179,6 +179,8 @@ static int mthca_query_port(struct ib_device *ibdev,
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);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index 5e5c58b9920b..6a7822e0fc19 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -39,6 +39,8 @@
#include <linux/string.h>
#include <linux/slab.h>
+#include <asm/io.h>
+
#include <rdma/ib_verbs.h>
#include <rdma/ib_cache.h>
#include <rdma/ib_pack.h>
@@ -1732,6 +1734,11 @@ out:
mthca_write64(doorbell,
dev->kar + MTHCA_SEND_DOORBELL,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
+ /*
+ * Make sure doorbells don't leak out of SQ spinlock
+ * and reach the HCA out of order:
+ */
+ mmiowb();
}
qp->sq.next_ind = ind;
@@ -1851,6 +1858,12 @@ out:
qp->rq.next_ind = ind;
qp->rq.head += nreq;
+ /*
+ * Make sure doorbells don't leak out of RQ spinlock and reach
+ * the HCA out of order:
+ */
+ mmiowb();
+
spin_unlock_irqrestore(&qp->rq.lock, flags);
return err;
}
@@ -2112,6 +2125,12 @@ out:
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
+ /*
+ * Make sure doorbells don't leak out of SQ spinlock and reach
+ * the HCA out of order:
+ */
+ mmiowb();
+
spin_unlock_irqrestore(&qp->sq.lock, flags);
return err;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_srq.c b/drivers/infiniband/hw/mthca/mthca_srq.c
index 0f316c87bf64..f5d7677d1079 100644
--- a/drivers/infiniband/hw/mthca/mthca_srq.c
+++ b/drivers/infiniband/hw/mthca/mthca_srq.c
@@ -35,6 +35,8 @@
#include <linux/slab.h>
#include <linux/string.h>
+#include <asm/io.h>
+
#include "mthca_dev.h"
#include "mthca_cmd.h"
#include "mthca_memfree.h"
@@ -201,6 +203,8 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
if (mthca_is_memfree(dev))
srq->max = roundup_pow_of_two(srq->max + 1);
+ else
+ srq->max = srq->max + 1;
ds = max(64UL,
roundup_pow_of_two(sizeof (struct mthca_next_seg) +
@@ -277,7 +281,7 @@ int mthca_alloc_srq(struct mthca_dev *dev, struct mthca_pd *pd,
srq->first_free = 0;
srq->last_free = srq->max - 1;
- attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+ attr->max_wr = srq->max - 1;
attr->max_sge = srq->max_gs;
return 0;
@@ -413,7 +417,7 @@ int mthca_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *srq_attr)
srq_attr->srq_limit = be16_to_cpu(tavor_ctx->limit_watermark);
}
- srq_attr->max_wr = (mthca_is_memfree(dev)) ? srq->max - 1 : srq->max;
+ srq_attr->max_wr = srq->max - 1;
srq_attr->max_sge = srq->max_gs;
out:
@@ -593,6 +597,12 @@ int mthca_tavor_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
MTHCA_GET_DOORBELL_LOCK(&dev->doorbell_lock));
}
+ /*
+ * Make sure doorbells don't leak out of SRQ spinlock and
+ * reach the HCA out of order:
+ */
+ mmiowb();
+
spin_unlock_irqrestore(&srq->lock, flags);
return err;
}
diff --git a/drivers/infiniband/ulp/ipoib/Kconfig b/drivers/infiniband/ulp/ipoib/Kconfig
index d74653d7de1c..c75322d820d4 100644
--- a/drivers/infiniband/ulp/ipoib/Kconfig
+++ b/drivers/infiniband/ulp/ipoib/Kconfig
@@ -26,7 +26,7 @@ config INFINIBAND_IPOIB_DEBUG_DATA
bool "IP-over-InfiniBand data path debugging"
depends on INFINIBAND_IPOIB_DEBUG
---help---
- This option compiles debugging code into the the data path
+ This option compiles debugging code into the data path
of the IPoIB driver. The output can be turned on via the
data_debug_level module parameter; however, even with output
turned off, this debugging code will have some performance
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_fs.c b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
index 5dde380e8dbe..f1cb83688b31 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_fs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_fs.c
@@ -141,7 +141,7 @@ static int ipoib_mcg_open(struct inode *inode, struct file *file)
return ret;
seq = file->private_data;
- seq->private = inode->u.generic_ip;
+ seq->private = inode->i_private;
return 0;
}
@@ -247,7 +247,7 @@ static int ipoib_path_open(struct inode *inode, struct file *file)
return ret;
seq = file->private_data;
- seq->private = inode->u.generic_ip;
+ seq->private = inode->i_private;
return 0;
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index f426a69d9a43..8bf5e9ec7c95 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -355,6 +355,11 @@ void ipoib_send(struct net_device *dev, struct sk_buff *skb,
tx_req->skb = skb;
addr = dma_map_single(priv->ca->dma_device, skb->data, skb->len,
DMA_TO_DEVICE);
+ if (unlikely(dma_mapping_error(addr))) {
+ ++priv->stats.tx_errors;
+ dev_kfree_skb_any(skb);
+ return;
+ }
pci_unmap_addr_set(tx_req, mapping, addr);
if (unlikely(post_send(priv, priv->tx_head & (ipoib_sendq_size - 1),
diff --git a/drivers/infiniband/ulp/iser/Kconfig b/drivers/infiniband/ulp/iser/Kconfig
index 365a1b5f19e0..aecbb9083f0c 100644
--- a/drivers/infiniband/ulp/iser/Kconfig
+++ b/drivers/infiniband/ulp/iser/Kconfig
@@ -1,11 +1,12 @@
config INFINIBAND_ISER
- tristate "ISCSI RDMA Protocol"
+ tristate "iSCSI Extensions for RDMA (iSER)"
depends on INFINIBAND && SCSI && INET
select SCSI_ISCSI_ATTRS
---help---
- Support for the ISCSI RDMA Protocol over InfiniBand. This
- allows you to access storage devices that speak ISER/ISCSI
- over InfiniBand.
+ Support for the iSCSI Extensions for RDMA (iSER) Protocol
+ over InfiniBand. This allows you to access storage devices
+ that speak iSCSI over iSER over InfiniBand.
- The ISER protocol is defined by IETF.
- See <http://www.ietf.org/>.
+ The iSER protocol is defined by IETF.
+ See <http://www.ietf.org/internet-drafts/draft-ietf-ips-iser-05.txt>
+ and <http://www.infinibandta.org/members/spec/iser_annex_060418.pdf>
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index 2a14fe2e3226..eb6f98d82289 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -317,6 +317,8 @@ iscsi_iser_conn_destroy(struct iscsi_cls_conn *cls_conn)
struct iscsi_iser_conn *iser_conn = conn->dd_data;
iscsi_conn_teardown(cls_conn);
+ if (iser_conn->ib_conn)
+ iser_conn->ib_conn->iser_conn = NULL;
kfree(iser_conn);
}
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 2cf9ae0def1c..9c53916f28c2 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -192,7 +192,7 @@ struct iser_regd_buf {
struct iser_dto {
struct iscsi_iser_cmd_task *ctask;
- struct iscsi_iser_conn *conn;
+ struct iser_conn *ib_conn;
int notify_enable;
/* vector of registered buffers */
@@ -355,4 +355,11 @@ int iser_post_send(struct iser_desc *tx_desc);
int iser_conn_state_comp(struct iser_conn *ib_conn,
enum iser_ib_conn_state comp);
+
+int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+ struct iser_data_buf *data,
+ enum iser_data_dir iser_dir,
+ enum dma_data_direction dma_dir);
+
+void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask);
#endif
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index ccf56f6f7236..9b3d79c796c8 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -66,42 +66,6 @@ static void iser_dto_add_regd_buff(struct iser_dto *dto,
dto->regd_vector_len++;
}
-static int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
- struct iser_data_buf *data,
- enum iser_data_dir iser_dir,
- enum dma_data_direction dma_dir)
-{
- struct device *dma_device;
-
- iser_ctask->dir[iser_dir] = 1;
- dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
-
- data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
- if (data->dma_nents == 0) {
- iser_err("dma_map_sg failed!!!\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
-{
- struct device *dma_device;
- struct iser_data_buf *data;
-
- dma_device = iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
-
- if (iser_ctask->dir[ISER_DIR_IN]) {
- data = &iser_ctask->data[ISER_DIR_IN];
- dma_unmap_sg(dma_device, data->buf, data->size, DMA_FROM_DEVICE);
- }
-
- if (iser_ctask->dir[ISER_DIR_OUT]) {
- data = &iser_ctask->data[ISER_DIR_OUT];
- dma_unmap_sg(dma_device, data->buf, data->size, DMA_TO_DEVICE);
- }
-}
-
/* Register user buffer memory and initialize passive rdma
* dto descriptor. Total data size is stored in
* iser_ctask->data[ISER_DIR_IN].data_len
@@ -249,7 +213,7 @@ static int iser_post_receive_control(struct iscsi_conn *conn)
}
recv_dto = &rx_desc->dto;
- recv_dto->conn = iser_conn;
+ recv_dto->ib_conn = iser_conn->ib_conn;
recv_dto->regd_vector_len = 0;
regd_hdr = &rx_desc->hdr_regd_buf;
@@ -296,7 +260,7 @@ static void iser_create_send_desc(struct iscsi_iser_conn *iser_conn,
regd_hdr->virt_addr = tx_desc; /* == &tx_desc->iser_header */
regd_hdr->data_size = ISER_TOTAL_HEADERS_LEN;
- send_dto->conn = iser_conn;
+ send_dto->ib_conn = iser_conn->ib_conn;
send_dto->notify_enable = 1;
send_dto->regd_vector_len = 0;
@@ -588,7 +552,7 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
unsigned long dto_xfer_len)
{
struct iser_dto *dto = &rx_desc->dto;
- struct iscsi_iser_conn *conn = dto->conn;
+ struct iscsi_iser_conn *conn = dto->ib_conn->iser_conn;
struct iscsi_session *session = conn->iscsi_conn->session;
struct iscsi_cmd_task *ctask;
struct iscsi_iser_cmd_task *iser_ctask;
@@ -641,7 +605,8 @@ void iser_rcv_completion(struct iser_desc *rx_desc,
void iser_snd_completion(struct iser_desc *tx_desc)
{
struct iser_dto *dto = &tx_desc->dto;
- struct iscsi_iser_conn *iser_conn = dto->conn;
+ struct iser_conn *ib_conn = dto->ib_conn;
+ struct iscsi_iser_conn *iser_conn = ib_conn->iser_conn;
struct iscsi_conn *conn = iser_conn->iscsi_conn;
struct iscsi_mgmt_task *mtask;
@@ -652,7 +617,7 @@ void iser_snd_completion(struct iser_desc *tx_desc)
if (tx_desc->type == ISCSI_TX_DATAOUT)
kmem_cache_free(ig.desc_cache, tx_desc);
- atomic_dec(&iser_conn->ib_conn->post_send_buf_count);
+ atomic_dec(&ib_conn->post_send_buf_count);
write_lock(conn->recv_lock);
if (conn->suspend_tx) {
@@ -698,14 +663,19 @@ void iser_ctask_rdma_init(struct iscsi_iser_cmd_task *iser_ctask)
void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask)
{
int deferred;
+ int is_rdma_aligned = 1;
/* if we were reading, copy back to unaligned sglist,
* anyway dma_unmap and free the copy
*/
- if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL)
+ if (iser_ctask->data_copy[ISER_DIR_IN].copy_buf != NULL) {
+ is_rdma_aligned = 0;
iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_IN);
- if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL)
+ }
+ if (iser_ctask->data_copy[ISER_DIR_OUT].copy_buf != NULL) {
+ is_rdma_aligned = 0;
iser_finalize_rdma_unaligned_sg(iser_ctask, ISER_DIR_OUT);
+ }
if (iser_ctask->dir[ISER_DIR_IN]) {
deferred = iser_regd_buff_release
@@ -725,7 +695,9 @@ void iser_ctask_rdma_finalize(struct iscsi_iser_cmd_task *iser_ctask)
}
}
- iser_dma_unmap_task_data(iser_ctask);
+ /* if the data was unaligned, it was already unmapped and then copied */
+ if (is_rdma_aligned)
+ iser_dma_unmap_task_data(iser_ctask);
}
void iser_dto_buffs_release(struct iser_dto *dto)
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index d0b03f426581..0606744c3f84 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -369,6 +369,44 @@ static void iser_page_vec_build(struct iser_data_buf *data,
}
}
+int iser_dma_map_task_data(struct iscsi_iser_cmd_task *iser_ctask,
+ struct iser_data_buf *data,
+ enum iser_data_dir iser_dir,
+ enum dma_data_direction dma_dir)
+{
+ struct device *dma_device;
+
+ iser_ctask->dir[iser_dir] = 1;
+ dma_device =
+ iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+ data->dma_nents = dma_map_sg(dma_device, data->buf, data->size, dma_dir);
+ if (data->dma_nents == 0) {
+ iser_err("dma_map_sg failed!!!\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+void iser_dma_unmap_task_data(struct iscsi_iser_cmd_task *iser_ctask)
+{
+ struct device *dma_device;
+ struct iser_data_buf *data;
+
+ dma_device =
+ iser_ctask->iser_conn->ib_conn->device->ib_device->dma_device;
+
+ if (iser_ctask->dir[ISER_DIR_IN]) {
+ data = &iser_ctask->data[ISER_DIR_IN];
+ dma_unmap_sg(dma_device, data->buf, data->size, DMA_FROM_DEVICE);
+ }
+
+ if (iser_ctask->dir[ISER_DIR_OUT]) {
+ data = &iser_ctask->data[ISER_DIR_OUT];
+ dma_unmap_sg(dma_device, data->buf, data->size, DMA_TO_DEVICE);
+ }
+}
+
/**
* iser_reg_rdma_mem - Registers memory intended for RDMA,
* obtaining rkey and va
@@ -394,6 +432,10 @@ int iser_reg_rdma_mem(struct iscsi_iser_cmd_task *iser_ctask,
iser_err("rdma alignment violation %d/%d aligned\n",
aligned_len, mem->size);
iser_data_buf_dump(mem);
+
+ /* unmap the command data before accessing it */
+ iser_dma_unmap_task_data(iser_ctask);
+
/* allocate copy buf, if we are writing, copy the */
/* unaligned scatterlist, dma map the copy */
if (iser_start_rdma_unaligned_sg(iser_ctask, cmd_dir) != 0)
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index ecdca7fc1e4c..18a000034996 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -571,6 +571,8 @@ void iser_conn_release(struct iser_conn *ib_conn)
/* on EVENT_ADDR_ERROR there's no device yet for this conn */
if (device != NULL)
iser_device_try_release(device);
+ if (ib_conn->iser_conn)
+ ib_conn->iser_conn->ib_conn = NULL;
kfree(ib_conn);
}
@@ -694,7 +696,7 @@ int iser_post_recv(struct iser_desc *rx_desc)
struct iser_dto *recv_dto = &rx_desc->dto;
/* Retrieve conn */
- ib_conn = recv_dto->conn->ib_conn;
+ ib_conn = recv_dto->ib_conn;
iser_dto_to_iov(recv_dto, iov, 2);
@@ -727,7 +729,7 @@ int iser_post_send(struct iser_desc *tx_desc)
struct iser_conn *ib_conn;
struct iser_dto *dto = &tx_desc->dto;
- ib_conn = dto->conn->ib_conn;
+ ib_conn = dto->ib_conn;
iser_dto_to_iov(dto, iov, MAX_REGD_BUF_VECTOR_LEN);
@@ -774,7 +776,7 @@ static void iser_comp_error_worker(void *data)
static void iser_handle_comp_error(struct iser_desc *desc)
{
struct iser_dto *dto = &desc->dto;
- struct iser_conn *ib_conn = dto->conn->ib_conn;
+ struct iser_conn *ib_conn = dto->ib_conn;
iser_dto_buffs_release(dto);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 44b9e5be6687..4b09147f438f 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -343,29 +343,32 @@ static int srp_send_req(struct srp_target_port *target)
*/
if (target->io_class == SRP_REV10_IB_IO_CLASS) {
memcpy(req->priv.initiator_port_id,
- target->srp_host->initiator_port_id + 8, 8);
+ &target->path.sgid.global.interface_id, 8);
memcpy(req->priv.initiator_port_id + 8,
- target->srp_host->initiator_port_id, 8);
+ &target->initiator_ext, 8);
memcpy(req->priv.target_port_id, &target->ioc_guid, 8);
memcpy(req->priv.target_port_id + 8, &target->id_ext, 8);
} else {
memcpy(req->priv.initiator_port_id,
- target->srp_host->initiator_port_id, 16);
+ &target->initiator_ext, 8);
+ memcpy(req->priv.initiator_port_id + 8,
+ &target->path.sgid.global.interface_id, 8);
memcpy(req->priv.target_port_id, &target->id_ext, 8);
memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8);
}
/*
* Topspin/Cisco SRP targets will reject our login unless we
- * zero out the first 8 bytes of our initiator port ID. The
- * second 8 bytes must be our local node GUID, but we always
- * use that anyway.
+ * zero out the first 8 bytes of our initiator port ID and set
+ * the second 8 bytes to the local node GUID.
*/
if (topspin_workarounds && !memcmp(&target->ioc_guid, topspin_oui, 3)) {
printk(KERN_DEBUG PFX "Topspin/Cisco initiator port ID workaround "
"activated for target GUID %016llx\n",
(unsigned long long) be64_to_cpu(target->ioc_guid));
memset(req->priv.initiator_port_id, 0, 8);
+ memcpy(req->priv.initiator_port_id + 8,
+ &target->srp_host->dev->dev->node_guid, 8);
}
status = ib_send_cm_req(target->cm_id, &req->param);
@@ -1553,6 +1556,7 @@ enum {
SRP_OPT_MAX_SECT = 1 << 5,
SRP_OPT_MAX_CMD_PER_LUN = 1 << 6,
SRP_OPT_IO_CLASS = 1 << 7,
+ SRP_OPT_INITIATOR_EXT = 1 << 8,
SRP_OPT_ALL = (SRP_OPT_ID_EXT |
SRP_OPT_IOC_GUID |
SRP_OPT_DGID |
@@ -1569,6 +1573,7 @@ static match_table_t srp_opt_tokens = {
{ SRP_OPT_MAX_SECT, "max_sect=%d" },
{ SRP_OPT_MAX_CMD_PER_LUN, "max_cmd_per_lun=%d" },
{ SRP_OPT_IO_CLASS, "io_class=%x" },
+ { SRP_OPT_INITIATOR_EXT, "initiator_ext=%s" },
{ SRP_OPT_ERR, NULL }
};
@@ -1668,6 +1673,12 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
target->io_class = token;
break;
+ case SRP_OPT_INITIATOR_EXT:
+ p = match_strdup(args);
+ target->initiator_ext = cpu_to_be64(simple_strtoull(p, NULL, 16));
+ kfree(p);
+ break;
+
default:
printk(KERN_WARNING PFX "unknown parameter or missing value "
"'%s' in target creation request\n", p);
@@ -1708,7 +1719,6 @@ static ssize_t srp_create_target(struct class_device *class_dev,
target_host->max_lun = SRP_MAX_LUN;
target = host_to_target(target_host);
- memset(target, 0, sizeof *target);
target->io_class = SRP_REV16A_IB_IO_CLASS;
target->scsi_host = target_host;
@@ -1815,9 +1825,6 @@ static struct srp_host *srp_add_port(struct srp_device *device, u8 port)
host->dev = device;
host->port = port;
- host->initiator_port_id[7] = port;
- memcpy(host->initiator_port_id + 8, &device->dev->node_guid, 8);
-
host->class_dev.class = &srp_class;
host->class_dev.dev = device->dev->dma_device;
snprintf(host->class_dev.class_id, BUS_ID_SIZE, "srp-%s-%d",
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index 5b581fb8eb0d..d4e35ef51374 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -91,7 +91,6 @@ struct srp_device {
};
struct srp_host {
- u8 initiator_port_id[16];
struct srp_device *dev;
u8 port;
struct class_device class_dev;
@@ -122,6 +121,7 @@ struct srp_target_port {
__be64 id_ext;
__be64 ioc_guid;
__be64 service_id;
+ __be64 initiator_ext;
u16 io_class;
struct srp_host *srp_host;
struct Scsi_Host *scsi_host;
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig
index 58223b5d842a..96232313b1b9 100644
--- a/drivers/input/Kconfig
+++ b/drivers/input/Kconfig
@@ -24,6 +24,20 @@ config INPUT
if INPUT
+config INPUT_FF_MEMLESS
+ tristate "Support for memoryless force-feedback devices"
+ default n
+ ---help---
+ Say Y here if you have memoryless force-feedback input device
+ such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual
+ Power 2, or similar. You will also need to enable hardware-specific
+ driver.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ff-memless.
+
comment "Userland interfaces"
config INPUT_MOUSEDEV
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 1a6ff4982f30..a005b1df5f1a 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -4,7 +4,11 @@
# Each configuration option enables a list of files.
-obj-$(CONFIG_INPUT) += input.o
+obj-$(CONFIG_INPUT) += input-core.o
+input-core-objs := input.o ff-core.o
+
+obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
+
obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
diff --git a/drivers/input/evbug.c b/drivers/input/evbug.c
index 07358fb51b82..5a9653c3128a 100644
--- a/drivers/input/evbug.c
+++ b/drivers/input/evbug.c
@@ -42,10 +42,12 @@ static char evbug_name[] = "evbug";
static void evbug_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
- printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n", handle->dev->phys, type, code, value);
+ printk(KERN_DEBUG "evbug.c: Event. Dev: %s, Type: %d, Code: %d, Value: %d\n",
+ handle->dev->phys, type, code, value);
}
-static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
+static struct input_handle *evbug_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct input_handle *handle;
@@ -72,7 +74,7 @@ static void evbug_disconnect(struct input_handle *handle)
kfree(handle);
}
-static struct input_device_id evbug_ids[] = {
+static const struct input_device_id evbug_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
@@ -89,8 +91,7 @@ static struct input_handler evbug_handler = {
static int __init evbug_init(void)
{
- input_register_handler(&evbug_handler);
- return 0;
+ return input_register_handler(&evbug_handler);
}
static void __exit evbug_exit(void)
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 4bf48188cc91..6439f378f6cc 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -391,8 +391,10 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
struct evdev *evdev = list->evdev;
struct input_dev *dev = evdev->handle.dev;
struct input_absinfo abs;
+ struct ff_effect effect;
int __user *ip = (int __user *)p;
int i, t, u, v;
+ int error;
if (!evdev->exist)
return -ENODEV;
@@ -460,27 +462,22 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
return 0;
case EVIOCSFF:
- if (dev->upload_effect) {
- struct ff_effect effect;
- int err;
-
- if (copy_from_user(&effect, p, sizeof(effect)))
- return -EFAULT;
- err = dev->upload_effect(dev, &effect);
- if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
- return -EFAULT;
- return err;
- } else
- return -ENOSYS;
+ if (copy_from_user(&effect, p, sizeof(effect)))
+ return -EFAULT;
- case EVIOCRMFF:
- if (!dev->erase_effect)
- return -ENOSYS;
+ error = input_ff_upload(dev, &effect, file);
- return dev->erase_effect(dev, (int)(unsigned long) p);
+ if (put_user(effect.id, &(((struct ff_effect __user *)p)->id)))
+ return -EFAULT;
+
+ return error;
+
+ case EVIOCRMFF:
+ return input_ff_erase(dev, (int)(unsigned long) p, file);
case EVIOCGEFFECTS:
- if (put_user(dev->ff_effects_max, ip))
+ i = test_bit(EV_FF, dev->evbit) ? dev->ff->max_effects : 0;
+ if (put_user(i, ip))
return -EFAULT;
return 0;
@@ -604,7 +601,7 @@ static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned lon
}
#endif
-static struct file_operations evdev_fops = {
+static const struct file_operations evdev_fops = {
.owner = THIS_MODULE,
.read = evdev_read,
.write = evdev_write,
@@ -619,7 +616,8 @@ static struct file_operations evdev_fops = {
.flush = evdev_flush
};
-static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
+static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct evdev *evdev;
struct class_device *cdev;
@@ -669,6 +667,7 @@ static void evdev_disconnect(struct input_handle *handle)
evdev->exist = 0;
if (evdev->open) {
+ input_flush_device(handle, NULL);
input_close_device(handle);
wake_up_interruptible(&evdev->wait);
list_for_each_entry(list, &evdev->list, node)
@@ -677,7 +676,7 @@ static void evdev_disconnect(struct input_handle *handle)
evdev_free(evdev);
}
-static struct input_device_id evdev_ids[] = {
+static const struct input_device_id evdev_ids[] = {
{ .driver_info = 1 }, /* Matches all devices */
{ }, /* Terminating zero entry */
};
@@ -696,8 +695,7 @@ static struct input_handler evdev_handler = {
static int __init evdev_init(void)
{
- input_register_handler(&evdev_handler);
- return 0;
+ return input_register_handler(&evdev_handler);
}
static void __exit evdev_exit(void)
diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c
new file mode 100644
index 000000000000..35656cadc914
--- /dev/null
+++ b/drivers/input/ff-core.c
@@ -0,0 +1,367 @@
+/*
+ * Force feedback support for Linux input subsystem
+ *
+ * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com>
+ * Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * 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
+ */
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("ff-core: " format "\n", ## arg)
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+/*
+ * Check that the effect_id is a valid effect and whether the user
+ * is the owner
+ */
+static int check_effect_access(struct ff_device *ff, int effect_id,
+ struct file *file)
+{
+ if (effect_id < 0 || effect_id >= ff->max_effects ||
+ !ff->effect_owners[effect_id])
+ return -EINVAL;
+
+ if (file && ff->effect_owners[effect_id] != file)
+ return -EACCES;
+
+ return 0;
+}
+
+/*
+ * Checks whether 2 effects can be combined together
+ */
+static inline int check_effects_compatible(struct ff_effect *e1,
+ struct ff_effect *e2)
+{
+ return e1->type == e2->type &&
+ (e1->type != FF_PERIODIC ||
+ e1->u.periodic.waveform == e2->u.periodic.waveform);
+}
+
+/*
+ * Convert an effect into compatible one
+ */
+static int compat_effect(struct ff_device *ff, struct ff_effect *effect)
+{
+ int magnitude;
+
+ switch (effect->type) {
+ case FF_RUMBLE:
+ if (!test_bit(FF_PERIODIC, ff->ffbit))
+ return -EINVAL;
+
+ /*
+ * calculate manginude of sine wave as average of rumble's
+ * 2/3 of strong magnitude and 1/3 of weak magnitude
+ */
+ magnitude = effect->u.rumble.strong_magnitude / 3 +
+ effect->u.rumble.weak_magnitude / 6;
+
+ effect->type = FF_PERIODIC;
+ effect->u.periodic.waveform = FF_SINE;
+ effect->u.periodic.period = 50;
+ effect->u.periodic.magnitude = max(magnitude, 0x7fff);
+ effect->u.periodic.offset = 0;
+ effect->u.periodic.phase = 0;
+ effect->u.periodic.envelope.attack_length = 0;
+ effect->u.periodic.envelope.attack_level = 0;
+ effect->u.periodic.envelope.fade_length = 0;
+ effect->u.periodic.envelope.fade_level = 0;
+
+ return 0;
+
+ default:
+ /* Let driver handle conversion */
+ return 0;
+ }
+}
+
+/**
+ * input_ff_upload() - upload effect into force-feedback device
+ * @dev: input device
+ * @effect: effect to be uploaded
+ * @file: owner of the effect
+ */
+int input_ff_upload(struct input_dev *dev, struct ff_effect *effect,
+ struct file *file)
+{
+ struct ff_device *ff = dev->ff;
+ struct ff_effect *old;
+ int ret = 0;
+ int id;
+
+ if (!test_bit(EV_FF, dev->evbit))
+ return -ENOSYS;
+
+ if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX ||
+ !test_bit(effect->type, dev->ffbit)) {
+ debug("invalid or not supported effect type in upload");
+ return -EINVAL;
+ }
+
+ if (effect->type == FF_PERIODIC &&
+ (effect->u.periodic.waveform < FF_WAVEFORM_MIN ||
+ effect->u.periodic.waveform > FF_WAVEFORM_MAX ||
+ !test_bit(effect->u.periodic.waveform, dev->ffbit))) {
+ debug("invalid or not supported wave form in upload");
+ return -EINVAL;
+ }
+
+ if (!test_bit(effect->type, ff->ffbit)) {
+ ret = compat_effect(ff, effect);
+ if (ret)
+ return ret;
+ }
+
+ mutex_lock(&ff->mutex);
+
+ if (effect->id == -1) {
+ for (id = 0; id < ff->max_effects; id++)
+ if (!ff->effect_owners[id])
+ break;
+
+ if (id >= ff->max_effects) {
+ ret = -ENOSPC;
+ goto out;
+ }
+
+ effect->id = id;
+ old = NULL;
+
+ } else {
+ id = effect->id;
+
+ ret = check_effect_access(ff, id, file);
+ if (ret)
+ goto out;
+
+ old = &ff->effects[id];
+
+ if (!check_effects_compatible(effect, old)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ ret = ff->upload(dev, effect, old);
+ if (ret)
+ goto out;
+
+ ff->effects[id] = *effect;
+ ff->effect_owners[id] = file;
+
+ out:
+ mutex_unlock(&ff->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(input_ff_upload);
+
+/*
+ * Erases the effect if the requester is also the effect owner. The mutex
+ * should already be locked before calling this function.
+ */
+static int erase_effect(struct input_dev *dev, int effect_id,
+ struct file *file)
+{
+ struct ff_device *ff = dev->ff;
+ int error;
+
+ error = check_effect_access(ff, effect_id, file);
+ if (error)
+ return error;
+
+ ff->playback(dev, effect_id, 0);
+
+ if (ff->erase) {
+ error = ff->erase(dev, effect_id);
+ if (error)
+ return error;
+ }
+
+ ff->effect_owners[effect_id] = NULL;
+
+ return 0;
+}
+
+/**
+ * input_ff_erase - erase an effect from device
+ * @dev: input device to erase effect from
+ * @effect_id: id of the ffect to be erased
+ * @file: purported owner of the request
+ *
+ * This function erases a force-feedback effect from specified device.
+ * The effect will only be erased if it was uploaded through the same
+ * file handle that is requesting erase.
+ */
+int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file)
+{
+ struct ff_device *ff = dev->ff;
+ int ret;
+
+ if (!test_bit(EV_FF, dev->evbit))
+ return -ENOSYS;
+
+ mutex_lock(&ff->mutex);
+ ret = erase_effect(dev, effect_id, file);
+ mutex_unlock(&ff->mutex);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(input_ff_erase);
+
+/*
+ * flush_effects - erase all effects owned by a file handle
+ */
+static int flush_effects(struct input_dev *dev, struct file *file)
+{
+ struct ff_device *ff = dev->ff;
+ int i;
+
+ debug("flushing now");
+
+ mutex_lock(&ff->mutex);
+
+ for (i = 0; i < ff->max_effects; i++)
+ erase_effect(dev, i, file);
+
+ mutex_unlock(&ff->mutex);
+
+ return 0;
+}
+
+/**
+ * input_ff_event() - generic handler for force-feedback events
+ * @dev: input device to send the effect to
+ * @type: event type (anything but EV_FF is ignored)
+ * @code: event code
+ * @value: event value
+ */
+int input_ff_event(struct input_dev *dev, unsigned int type,
+ unsigned int code, int value)
+{
+ struct ff_device *ff = dev->ff;
+
+ if (type != EV_FF)
+ return 0;
+
+ mutex_lock(&ff->mutex);
+
+ switch (code) {
+ case FF_GAIN:
+ if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffff)
+ break;
+
+ ff->set_gain(dev, value);
+ break;
+
+ case FF_AUTOCENTER:
+ if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffff)
+ break;
+
+ ff->set_autocenter(dev, value);
+ break;
+
+ default:
+ ff->playback(dev, code, value);
+ break;
+ }
+
+ mutex_unlock(&ff->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(input_ff_event);
+
+/**
+ * input_ff_create() - create force-feedback device
+ * @dev: input device supporting force-feedback
+ * @max_effects: maximum number of effects supported by the device
+ *
+ * This function allocates all necessary memory for a force feedback
+ * portion of an input device and installs all default handlers.
+ * @dev->ffbit should be already set up before calling this function.
+ * Once ff device is created you need to setup its upload, erase,
+ * playback and other handlers before registering input device
+ */
+int input_ff_create(struct input_dev *dev, int max_effects)
+{
+ struct ff_device *ff;
+ int i;
+
+ if (!max_effects) {
+ printk(KERN_ERR
+ "ff-core: cannot allocate device without any effects\n");
+ return -EINVAL;
+ }
+
+ ff = kzalloc(sizeof(struct ff_device) +
+ max_effects * sizeof(struct file *), GFP_KERNEL);
+ if (!ff)
+ return -ENOMEM;
+
+ ff->effects = kcalloc(max_effects, sizeof(struct ff_effect),
+ GFP_KERNEL);
+ if (!ff->effects) {
+ kfree(ff);
+ return -ENOMEM;
+ }
+
+ ff->max_effects = max_effects;
+ mutex_init(&ff->mutex);
+
+ dev->ff = ff;
+ dev->flush = flush_effects;
+ dev->event = input_ff_event;
+ set_bit(EV_FF, dev->evbit);
+
+ /* Copy "true" bits into ff device bitmap */
+ for (i = 0; i <= FF_MAX; i++)
+ if (test_bit(i, dev->ffbit))
+ set_bit(i, ff->ffbit);
+
+ /* we can emulate RUMBLE with periodic effects */
+ if (test_bit(FF_PERIODIC, ff->ffbit))
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(input_ff_create);
+
+/**
+ * input_ff_free() - frees force feedback portion of input device
+ * @dev: input device supporintg force feedback
+ *
+ * This function is only needed in error path as input core will
+ * automatically free force feedback structures when device is
+ * destroyed.
+ */
+void input_ff_destroy(struct input_dev *dev)
+{
+ clear_bit(EV_FF, dev->evbit);
+ if (dev->ff) {
+ if (dev->ff->destroy)
+ dev->ff->destroy(dev->ff);
+ kfree(dev->ff->private);
+ kfree(dev->ff);
+ dev->ff = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(input_ff_destroy);
diff --git a/drivers/input/ff-memless.c b/drivers/input/ff-memless.c
new file mode 100644
index 000000000000..cd8b7297e6df
--- /dev/null
+++ b/drivers/input/ff-memless.c
@@ -0,0 +1,515 @@
+/*
+ * Force feedback support for memoryless devices
+ *
+ * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com>
+ * Copyright (c) 2006 Dmitry Torokhov <dtor@mail.ru>
+ */
+
+/*
+ * 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
+ */
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("ff-memless: " format "\n", ## arg)
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+#include "fixp-arith.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Anssi Hannula <anssi.hannula@gmail.com>");
+MODULE_DESCRIPTION("Force feedback support for memoryless devices");
+
+/* Number of effects handled with memoryless devices */
+#define FF_MEMLESS_EFFECTS 16
+
+/* Envelope update interval in ms */
+#define FF_ENVELOPE_INTERVAL 50
+
+#define FF_EFFECT_STARTED 0
+#define FF_EFFECT_PLAYING 1
+#define FF_EFFECT_ABORTING 2
+
+struct ml_effect_state {
+ struct ff_effect *effect;
+ unsigned long flags; /* effect state (STARTED, PLAYING, etc) */
+ int count; /* loop count of the effect */
+ unsigned long play_at; /* start time */
+ unsigned long stop_at; /* stop time */
+ unsigned long adj_at; /* last time the effect was sent */
+};
+
+struct ml_device {
+ void *private;
+ struct ml_effect_state states[FF_MEMLESS_EFFECTS];
+ int gain;
+ struct timer_list timer;
+ spinlock_t timer_lock;
+ struct input_dev *dev;
+
+ int (*play_effect)(struct input_dev *dev, void *data,
+ struct ff_effect *effect);
+};
+
+static const struct ff_envelope *get_envelope(const struct ff_effect *effect)
+{
+ static const struct ff_envelope empty_envelope;
+
+ switch (effect->type) {
+ case FF_PERIODIC:
+ return &effect->u.periodic.envelope;
+ case FF_CONSTANT:
+ return &effect->u.constant.envelope;
+ default:
+ return &empty_envelope;
+ }
+}
+
+/*
+ * Check for the next time envelope requires an update on memoryless devices
+ */
+static unsigned long calculate_next_time(struct ml_effect_state *state)
+{
+ const struct ff_envelope *envelope = get_envelope(state->effect);
+ unsigned long attack_stop, fade_start, next_fade;
+
+ if (envelope->attack_length) {
+ attack_stop = state->play_at +
+ msecs_to_jiffies(envelope->attack_length);
+ if (time_before(state->adj_at, attack_stop))
+ return state->adj_at +
+ msecs_to_jiffies(FF_ENVELOPE_INTERVAL);
+ }
+
+ if (state->effect->replay.length) {
+ if (envelope->fade_length) {
+ /* check when fading should start */
+ fade_start = state->stop_at -
+ msecs_to_jiffies(envelope->fade_length);
+
+ if (time_before(state->adj_at, fade_start))
+ return fade_start;
+
+ /* already fading, advance to next checkpoint */
+ next_fade = state->adj_at +
+ msecs_to_jiffies(FF_ENVELOPE_INTERVAL);
+ if (time_before(next_fade, state->stop_at))
+ return next_fade;
+ }
+
+ return state->stop_at;
+ }
+
+ return state->play_at;
+}
+
+static void ml_schedule_timer(struct ml_device *ml)
+{
+ struct ml_effect_state *state;
+ unsigned long now = jiffies;
+ unsigned long earliest = 0;
+ unsigned long next_at;
+ int events = 0;
+ int i;
+
+ debug("calculating next timer");
+
+ for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
+
+ state = &ml->states[i];
+
+ if (!test_bit(FF_EFFECT_STARTED, &state->flags))
+ continue;
+
+ if (test_bit(FF_EFFECT_PLAYING, &state->flags))
+ next_at = calculate_next_time(state);
+ else
+ next_at = state->play_at;
+
+ if (time_before_eq(now, next_at) &&
+ (++events == 1 || time_before(next_at, earliest)))
+ earliest = next_at;
+ }
+
+ if (!events) {
+ debug("no actions");
+ del_timer(&ml->timer);
+ } else {
+ debug("timer set");
+ mod_timer(&ml->timer, earliest);
+ }
+}
+
+/*
+ * Apply an envelope to a value
+ */
+static int apply_envelope(struct ml_effect_state *state, int value,
+ struct ff_envelope *envelope)
+{
+ struct ff_effect *effect = state->effect;
+ unsigned long now = jiffies;
+ int time_from_level;
+ int time_of_envelope;
+ int envelope_level;
+ int difference;
+
+ if (envelope->attack_length &&
+ time_before(now,
+ state->play_at + msecs_to_jiffies(envelope->attack_length))) {
+ debug("value = 0x%x, attack_level = 0x%x", value,
+ envelope->attack_level);
+ time_from_level = jiffies_to_msecs(now - state->play_at);
+ time_of_envelope = envelope->attack_length;
+ envelope_level = min_t(__s16, envelope->attack_level, 0x7fff);
+
+ } else if (envelope->fade_length && effect->replay.length &&
+ time_after(now,
+ state->stop_at - msecs_to_jiffies(envelope->fade_length)) &&
+ time_before(now, state->stop_at)) {
+ time_from_level = jiffies_to_msecs(state->stop_at - now);
+ time_of_envelope = envelope->fade_length;
+ envelope_level = min_t(__s16, envelope->fade_level, 0x7fff);
+ } else
+ return value;
+
+ difference = abs(value) - envelope_level;
+
+ debug("difference = %d", difference);
+ debug("time_from_level = 0x%x", time_from_level);
+ debug("time_of_envelope = 0x%x", time_of_envelope);
+
+ difference = difference * time_from_level / time_of_envelope;
+
+ debug("difference = %d", difference);
+
+ return value < 0 ?
+ -(difference + envelope_level) : (difference + envelope_level);
+}
+
+/*
+ * Return the type the effect has to be converted into (memless devices)
+ */
+static int get_compatible_type(struct ff_device *ff, int effect_type)
+{
+
+ if (test_bit(effect_type, ff->ffbit))
+ return effect_type;
+
+ if (effect_type == FF_PERIODIC && test_bit(FF_RUMBLE, ff->ffbit))
+ return FF_RUMBLE;
+
+ printk(KERN_ERR
+ "ff-memless: invalid type in get_compatible_type()\n");
+
+ return 0;
+}
+
+/*
+ * Combine two effects and apply gain.
+ */
+static void ml_combine_effects(struct ff_effect *effect,
+ struct ml_effect_state *state,
+ int gain)
+{
+ struct ff_effect *new = state->effect;
+ unsigned int strong, weak, i;
+ int x, y;
+ fixp_t level;
+
+ switch (new->type) {
+ case FF_CONSTANT:
+ i = new->direction * 360 / 0xffff;
+ level = fixp_new16(apply_envelope(state,
+ new->u.constant.level,
+ &new->u.constant.envelope));
+ x = fixp_mult(fixp_sin(i), level) * gain / 0xffff;
+ y = fixp_mult(-fixp_cos(i), level) * gain / 0xffff;
+ /*
+ * here we abuse ff_ramp to hold x and y of constant force
+ * If in future any driver wants something else than x and y
+ * in s8, this should be changed to something more generic
+ */
+ effect->u.ramp.start_level =
+ max(min(effect->u.ramp.start_level + x, 0x7f), -0x80);
+ effect->u.ramp.end_level =
+ max(min(effect->u.ramp.end_level + y, 0x7f), -0x80);
+ break;
+
+ case FF_RUMBLE:
+ strong = new->u.rumble.strong_magnitude * gain / 0xffff;
+ weak = new->u.rumble.weak_magnitude * gain / 0xffff;
+ effect->u.rumble.strong_magnitude =
+ min(strong + effect->u.rumble.strong_magnitude,
+ 0xffffU);
+ effect->u.rumble.weak_magnitude =
+ min(weak + effect->u.rumble.weak_magnitude, 0xffffU);
+ break;
+
+ case FF_PERIODIC:
+ i = apply_envelope(state, abs(new->u.periodic.magnitude),
+ &new->u.periodic.envelope);
+
+ /* here we also scale it 0x7fff => 0xffff */
+ i = i * gain / 0x7fff;
+
+ effect->u.rumble.strong_magnitude =
+ min(i + effect->u.rumble.strong_magnitude, 0xffffU);
+ effect->u.rumble.weak_magnitude =
+ min(i + effect->u.rumble.weak_magnitude, 0xffffU);
+ break;
+
+ default:
+ printk(KERN_ERR "ff-memless: invalid type in ml_combine_effects()\n");
+ break;
+ }
+
+}
+
+
+/*
+ * Because memoryless devices have only one effect per effect type active
+ * at one time we have to combine multiple effects into one
+ */
+static int ml_get_combo_effect(struct ml_device *ml,
+ unsigned long *effect_handled,
+ struct ff_effect *combo_effect)
+{
+ struct ff_effect *effect;
+ struct ml_effect_state *state;
+ int effect_type;
+ int i;
+
+ memset(combo_effect, 0, sizeof(struct ff_effect));
+
+ for (i = 0; i < FF_MEMLESS_EFFECTS; i++) {
+ if (__test_and_set_bit(i, effect_handled))
+ continue;
+
+ state = &ml->states[i];
+ effect = state->effect;
+
+ if (!test_bit(FF_EFFECT_STARTED, &state->flags))
+ continue;
+
+ if (time_before(jiffies, state->play_at))
+ continue;
+
+ /*
+ * here we have started effects that are either
+ * currently playing (and may need be aborted)
+ * or need to start playing.
+ */
+ effect_type = get_compatible_type(ml->dev->ff, effect->type);
+ if (combo_effect->type != effect_type) {
+ if (combo_effect->type != 0) {
+ __clear_bit(i, effect_handled);
+ continue;
+ }
+ combo_effect->type = effect_type;
+ }
+
+ if (__test_and_clear_bit(FF_EFFECT_ABORTING, &state->flags)) {
+ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
+ __clear_bit(FF_EFFECT_STARTED, &state->flags);
+ } else if (effect->replay.length &&
+ time_after_eq(jiffies, state->stop_at)) {
+
+ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
+
+ if (--state->count <= 0) {
+ __clear_bit(FF_EFFECT_STARTED, &state->flags);
+ } else {
+ state->play_at = jiffies +
+ msecs_to_jiffies(effect->replay.delay);
+ state->stop_at = state->play_at +
+ msecs_to_jiffies(effect->replay.length);
+ }
+ } else {
+ __set_bit(FF_EFFECT_PLAYING, &state->flags);
+ state->adj_at = jiffies;
+ ml_combine_effects(combo_effect, state, ml->gain);
+ }
+ }
+
+ return combo_effect->type != 0;
+}
+
+static void ml_play_effects(struct ml_device *ml)
+{
+ struct ff_effect effect;
+ DECLARE_BITMAP(handled_bm, FF_MEMLESS_EFFECTS);
+
+ memset(handled_bm, 0, sizeof(handled_bm));
+
+ while (ml_get_combo_effect(ml, handled_bm, &effect))
+ ml->play_effect(ml->dev, ml->private, &effect);
+
+ ml_schedule_timer(ml);
+}
+
+static void ml_effect_timer(unsigned long timer_data)
+{
+ struct input_dev *dev = (struct input_dev *)timer_data;
+ struct ml_device *ml = dev->ff->private;
+
+ debug("timer: updating effects");
+
+ spin_lock(&ml->timer_lock);
+ ml_play_effects(ml);
+ spin_unlock(&ml->timer_lock);
+}
+
+static void ml_ff_set_gain(struct input_dev *dev, u16 gain)
+{
+ struct ml_device *ml = dev->ff->private;
+ int i;
+
+ spin_lock_bh(&ml->timer_lock);
+
+ ml->gain = gain;
+
+ for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
+ __clear_bit(FF_EFFECT_PLAYING, &ml->states[i].flags);
+
+ ml_play_effects(ml);
+
+ spin_unlock_bh(&ml->timer_lock);
+}
+
+static int ml_ff_playback(struct input_dev *dev, int effect_id, int value)
+{
+ struct ml_device *ml = dev->ff->private;
+ struct ml_effect_state *state = &ml->states[effect_id];
+
+ spin_lock_bh(&ml->timer_lock);
+
+ if (value > 0) {
+ debug("initiated play");
+
+ __set_bit(FF_EFFECT_STARTED, &state->flags);
+ state->count = value;
+ state->play_at = jiffies +
+ msecs_to_jiffies(state->effect->replay.delay);
+ state->stop_at = state->play_at +
+ msecs_to_jiffies(state->effect->replay.length);
+ state->adj_at = state->play_at;
+
+ ml_schedule_timer(ml);
+
+ } else {
+ debug("initiated stop");
+
+ if (test_bit(FF_EFFECT_PLAYING, &state->flags))
+ __set_bit(FF_EFFECT_ABORTING, &state->flags);
+ else
+ __clear_bit(FF_EFFECT_STARTED, &state->flags);
+
+ ml_play_effects(ml);
+ }
+
+ spin_unlock_bh(&ml->timer_lock);
+
+ return 0;
+}
+
+static int ml_ff_upload(struct input_dev *dev,
+ struct ff_effect *effect, struct ff_effect *old)
+{
+ struct ml_device *ml = dev->ff->private;
+ struct ml_effect_state *state = &ml->states[effect->id];
+
+ spin_lock_bh(&ml->timer_lock);
+
+ if (test_bit(FF_EFFECT_STARTED, &state->flags)) {
+ __clear_bit(FF_EFFECT_PLAYING, &state->flags);
+ state->play_at = jiffies +
+ msecs_to_jiffies(state->effect->replay.delay);
+ state->stop_at = state->play_at +
+ msecs_to_jiffies(state->effect->replay.length);
+ state->adj_at = state->play_at;
+ ml_schedule_timer(ml);
+ }
+
+ spin_unlock_bh(&ml->timer_lock);
+
+ return 0;
+}
+
+static void ml_ff_destroy(struct ff_device *ff)
+{
+ struct ml_device *ml = ff->private;
+
+ kfree(ml->private);
+}
+
+/**
+ * input_ff_create_memless() - create memoryless FF device
+ * @dev: input device supporting force-feedback
+ * @data: driver-specific data to be passed into @play_effect
+ * @play_effect: driver-specific method for playing FF effect
+ */
+int input_ff_create_memless(struct input_dev *dev, void *data,
+ int (*play_effect)(struct input_dev *, void *, struct ff_effect *))
+{
+ struct ml_device *ml;
+ struct ff_device *ff;
+ int error;
+ int i;
+
+ ml = kzalloc(sizeof(struct ml_device), GFP_KERNEL);
+ if (!ml)
+ return -ENOMEM;
+
+ ml->dev = dev;
+ ml->private = data;
+ ml->play_effect = play_effect;
+ ml->gain = 0xffff;
+ spin_lock_init(&ml->timer_lock);
+ setup_timer(&ml->timer, ml_effect_timer, (unsigned long)dev);
+
+ set_bit(FF_GAIN, dev->ffbit);
+
+ error = input_ff_create(dev, FF_MEMLESS_EFFECTS);
+ if (error) {
+ kfree(ml);
+ return error;
+ }
+
+ ff = dev->ff;
+ ff->private = ml;
+ ff->upload = ml_ff_upload;
+ ff->playback = ml_ff_playback;
+ ff->set_gain = ml_ff_set_gain;
+ ff->destroy = ml_ff_destroy;
+
+ /* we can emulate periodic effects with RUMBLE */
+ if (test_bit(FF_RUMBLE, ff->ffbit)) {
+ set_bit(FF_PERIODIC, dev->ffbit);
+ set_bit(FF_SINE, dev->ffbit);
+ set_bit(FF_TRIANGLE, dev->ffbit);
+ set_bit(FF_SQUARE, dev->ffbit);
+ }
+
+ for (i = 0; i < FF_MEMLESS_EFFECTS; i++)
+ ml->states[i].effect = &ff->effects[i];
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(input_ff_create_memless);
diff --git a/drivers/usb/input/fixp-arith.h b/drivers/input/fixp-arith.h
index ed3d2da0c485..ed3d2da0c485 100644
--- a/drivers/usb/input/fixp-arith.h
+++ b/drivers/input/fixp-arith.h
diff --git a/drivers/input/gameport/fm801-gp.c b/drivers/input/gameport/fm801-gp.c
index 90de5afe03c2..1dec00e20dbc 100644
--- a/drivers/input/gameport/fm801-gp.c
+++ b/drivers/input/gameport/fm801-gp.c
@@ -82,17 +82,19 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
{
struct fm801_gp *gp;
struct gameport *port;
+ int error;
gp = kzalloc(sizeof(struct fm801_gp), GFP_KERNEL);
port = gameport_allocate_port();
if (!gp || !port) {
printk(KERN_ERR "fm801-gp: Memory allocation failed\n");
- kfree(gp);
- gameport_free_port(port);
- return -ENOMEM;
+ error = -ENOMEM;
+ goto err_out_free;
}
- pci_enable_device(pci);
+ error = pci_enable_device(pci);
+ if (error)
+ goto err_out_free;
port->open = fm801_gp_open;
#ifdef HAVE_COOKED
@@ -108,9 +110,8 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
if (!gp->res_port) {
printk(KERN_DEBUG "fm801-gp: unable to grab region 0x%x-0x%x\n",
port->io, port->io + 0x0f);
- gameport_free_port(port);
- kfree(gp);
- return -EBUSY;
+ error = -EBUSY;
+ goto err_out_disable_dev;
}
pci_set_drvdata(pci, gp);
@@ -119,6 +120,13 @@ static int __devinit fm801_gp_probe(struct pci_dev *pci, const struct pci_device
gameport_register_port(port);
return 0;
+
+ err_out_disable_dev:
+ pci_disable_device(pci);
+ err_out_free:
+ gameport_free_port(port);
+ kfree(gp);
+ return error;
}
static void __devexit fm801_gp_remove(struct pci_dev *pci)
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index 3f47ae55c6f3..a0af97efe6ac 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -191,6 +191,8 @@ static void gameport_run_poll_handler(unsigned long d)
static void gameport_bind_driver(struct gameport *gameport, struct gameport_driver *drv)
{
+ int error;
+
down_write(&gameport_bus.subsys.rwsem);
gameport->dev.driver = &drv->driver;
@@ -198,8 +200,20 @@ static void gameport_bind_driver(struct gameport *gameport, struct gameport_driv
gameport->dev.driver = NULL;
goto out;
}
- device_bind_driver(&gameport->dev);
-out:
+
+ error = device_bind_driver(&gameport->dev);
+ if (error) {
+ printk(KERN_WARNING
+ "gameport: device_bind_driver() failed "
+ "for %s (%s) and %s, error: %d\n",
+ gameport->phys, gameport->name,
+ drv->description, error);
+ drv->disconnect(gameport);
+ gameport->dev.driver = NULL;
+ goto out;
+ }
+
+ out:
up_write(&gameport_bus.subsys.rwsem);
}
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 9cb4b9a54f01..1c8c8a5bc4a9 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -176,6 +176,10 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in
break;
case EV_FF:
+
+ if (value < 0)
+ return;
+
if (dev->event)
dev->event(dev, type, code, value);
break;
@@ -309,7 +313,8 @@ static void input_link_handle(struct input_handle *handle)
if (i != NBITS(max)) \
continue;
-static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev)
+static const struct input_device_id *input_match_device(const struct input_device_id *id,
+ struct input_dev *dev)
{
int i;
@@ -762,7 +767,9 @@ static void input_dev_release(struct class_device *class_dev)
{
struct input_dev *dev = to_input_dev(class_dev);
+ input_ff_destroy(dev);
kfree(dev);
+
module_put(THIS_MODULE);
}
@@ -899,12 +906,13 @@ struct input_dev *input_allocate_device(void)
dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL);
if (dev) {
- dev->dynalloc = 1;
dev->cdev.class = &input_class;
class_device_initialize(&dev->cdev);
mutex_init(&dev->mutex);
INIT_LIST_HEAD(&dev->h_list);
INIT_LIST_HEAD(&dev->node);
+
+ __module_get(THIS_MODULE);
}
return dev;
@@ -929,17 +937,10 @@ int input_register_device(struct input_dev *dev)
static atomic_t input_no = ATOMIC_INIT(0);
struct input_handle *handle;
struct input_handler *handler;
- struct input_device_id *id;
+ const struct input_device_id *id;
const char *path;
int error;
- if (!dev->dynalloc) {
- printk(KERN_WARNING "input: device %s is statically allocated, will not register\n"
- "Please convert to input_allocate_device() or contact dtor_core@ameritech.net\n",
- dev->name ? dev->name : "<Unknown>");
- return -EINVAL;
- }
-
set_bit(EV_SYN, dev->evbit);
/*
@@ -955,10 +956,8 @@ int input_register_device(struct input_dev *dev)
dev->rep[REP_PERIOD] = 33;
}
- INIT_LIST_HEAD(&dev->h_list);
list_add_tail(&dev->node, &input_dev_list);
- dev->cdev.class = &input_class;
snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
@@ -978,8 +977,6 @@ int input_register_device(struct input_dev *dev)
if (error)
goto fail3;
- __module_get(THIS_MODULE);
-
path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);
printk(KERN_INFO "input: %s as %s\n",
dev->name ? dev->name : "Unspecified device", path ? path : "N/A");
@@ -1008,9 +1005,12 @@ EXPORT_SYMBOL(input_register_device);
void input_unregister_device(struct input_dev *dev)
{
struct list_head *node, *next;
+ int code;
- if (!dev)
- return;
+ for (code = 0; code <= KEY_MAX; code++)
+ if (test_bit(code, dev->key))
+ input_report_key(dev, code, 0);
+ input_sync(dev);
del_timer_sync(&dev->timer);
@@ -1037,19 +1037,20 @@ void input_unregister_device(struct input_dev *dev)
}
EXPORT_SYMBOL(input_unregister_device);
-void input_register_handler(struct input_handler *handler)
+int input_register_handler(struct input_handler *handler)
{
struct input_dev *dev;
struct input_handle *handle;
- struct input_device_id *id;
-
- if (!handler)
- return;
+ const struct input_device_id *id;
INIT_LIST_HEAD(&handler->h_list);
- if (handler->fops != NULL)
+ if (handler->fops != NULL) {
+ if (input_table[handler->minor >> 5])
+ return -EBUSY;
+
input_table[handler->minor >> 5] = handler;
+ }
list_add_tail(&handler->node, &input_handler_list);
@@ -1063,6 +1064,7 @@ void input_register_handler(struct input_handler *handler)
}
input_wakeup_procfs_readers();
+ return 0;
}
EXPORT_SYMBOL(input_register_handler);
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index d67157513bf7..9f3529ad3fda 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -451,7 +451,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
}
}
-static struct file_operations joydev_fops = {
+static const struct file_operations joydev_fops = {
.owner = THIS_MODULE,
.read = joydev_read,
.write = joydev_write,
@@ -465,7 +465,8 @@ static struct file_operations joydev_fops = {
.fasync = joydev_fasync,
};
-static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
+static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct joydev *joydev;
struct class_device *cdev;
@@ -562,7 +563,7 @@ static void joydev_disconnect(struct input_handle *handle)
joydev_free(joydev);
}
-static struct input_device_id joydev_blacklist[] = {
+static const struct input_device_id joydev_blacklist[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) },
@@ -571,7 +572,7 @@ static struct input_device_id joydev_blacklist[] = {
{ } /* Terminating entry */
};
-static struct input_device_id joydev_ids[] = {
+static const struct input_device_id joydev_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_ABS) },
@@ -605,8 +606,7 @@ static struct input_handler joydev_handler = {
static int __init joydev_init(void)
{
- input_register_handler(&joydev_handler);
- return 0;
+ return input_register_handler(&joydev_handler);
}
static void __exit joydev_exit(void)
diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig
index 67519ef0ef95..271263443c37 100644
--- a/drivers/input/joystick/Kconfig
+++ b/drivers/input/joystick/Kconfig
@@ -32,7 +32,7 @@ config JOYSTICK_ANALOG
module will be called analog.
config JOYSTICK_A3D
- tristate "Assasin 3D and MadCatz Panther devices"
+ tristate "Assassin 3D and MadCatz Panther devices"
select GAMEPORT
help
Say Y here if you have an FPGaming or MadCatz controller using the
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index 7249d324297b..650acf3a30b7 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -57,7 +57,7 @@ static DEFINE_MUTEX(amijoy_mutex);
static struct input_dev *amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
-static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t amijoy_interrupt(int irq, void *dummy)
{
int i, data = 0, button = 0;
@@ -69,8 +69,6 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
case 1: data = ~amiga_custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
}
- input_regs(amijoy_dev[i], fp);
-
input_report_key(amijoy_dev[i], BTN_TRIGGER, button);
input_report_abs(amijoy_dev[i], ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1));
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c
index 50c90765aee1..8fb0c19cc60e 100644
--- a/drivers/input/joystick/iforce/iforce-ff.c
+++ b/drivers/input/joystick/iforce/iforce-ff.c
@@ -165,19 +165,19 @@ static int make_condition_modifier(struct iforce* iforce,
data[0] = LO(mod_chunk->start);
data[1] = HI(mod_chunk->start);
- data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */
- data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */
+ data[2] = (100 * rk) >> 15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */
+ data[3] = (100 * lk) >> 15; /* This code is incorrect on cpus lacking arith shift */
- center = (500*center)>>15;
+ center = (500 * center) >> 15;
data[4] = LO(center);
data[5] = HI(center);
- db = (1000*db)>>16;
+ db = (1000 * db) >> 16;
data[6] = LO(db);
data[7] = HI(db);
- data[8] = (100*rsat)>>16;
- data[9] = (100*lsat)>>16;
+ data[8] = (100 * rsat) >> 16;
+ data[9] = (100 * lsat) >> 16;
iforce_send_packet(iforce, FF_CMD_CONDITION, data);
iforce_dump_packet("condition", FF_CMD_CONDITION, data);
@@ -188,6 +188,7 @@ static int make_condition_modifier(struct iforce* iforce,
static unsigned char find_button(struct iforce *iforce, signed short button)
{
int i;
+
for (i = 1; iforce->type->btn[i] >= 0; i++)
if (iforce->type->btn[i] == button)
return i + 1;
@@ -198,19 +199,17 @@ static unsigned char find_button(struct iforce *iforce, signed short button)
* Analyse the changes in an effect, and tell if we need to send an condition
* parameter packet
*/
-static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new)
+static int need_condition_modifier(struct ff_effect *old, struct ff_effect *new)
{
- int id = new->id;
- struct ff_effect* old = &iforce->core_effects[id].effect;
- int ret=0;
+ int ret = 0;
int i;
if (new->type != FF_SPRING && new->type != FF_FRICTION) {
printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n");
- return FALSE;
+ return 0;
}
- for(i=0; i<2; i++) {
+ for (i = 0; i < 2; i++) {
ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation
|| old->u.condition[i].left_saturation != new->u.condition[i].left_saturation
|| old->u.condition[i].right_coeff != new->u.condition[i].right_coeff
@@ -225,35 +224,29 @@ static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new)
* Analyse the changes in an effect, and tell if we need to send a magnitude
* parameter packet
*/
-static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect)
+static int need_magnitude_modifier(struct ff_effect *old, struct ff_effect *effect)
{
- int id = effect->id;
- struct ff_effect* old = &iforce->core_effects[id].effect;
-
if (effect->type != FF_CONSTANT) {
printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
- return FALSE;
+ return 0;
}
- return (old->u.constant.level != effect->u.constant.level);
+ return old->u.constant.level != effect->u.constant.level;
}
/*
* Analyse the changes in an effect, and tell if we need to send an envelope
* parameter packet
*/
-static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect)
+static int need_envelope_modifier(struct ff_effect *old, struct ff_effect *effect)
{
- int id = effect->id;
- struct ff_effect* old = &iforce->core_effects[id].effect;
-
switch (effect->type) {
case FF_CONSTANT:
if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length
|| old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level
|| old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length
|| old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level)
- return TRUE;
+ return 1;
break;
case FF_PERIODIC:
@@ -261,30 +254,26 @@ static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effec
|| old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level
|| old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length
|| old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level)
- return TRUE;
+ return 1;
break;
default:
printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n");
}
- return FALSE;
+ return 0;
}
/*
* Analyse the changes in an effect, and tell if we need to send a periodic
* parameter effect
*/
-static int need_period_modifier(struct iforce* iforce, struct ff_effect* new)
+static int need_period_modifier(struct ff_effect *old, struct ff_effect *new)
{
- int id = new->id;
- struct ff_effect* old = &iforce->core_effects[id].effect;
-
if (new->type != FF_PERIODIC) {
- printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n");
- return FALSE;
+ printk(KERN_WARNING "iforce.c: bad effect type in need_period_modifier\n");
+ return 0;
}
-
return (old->u.periodic.period != new->u.periodic.period
|| old->u.periodic.magnitude != new->u.periodic.magnitude
|| old->u.periodic.offset != new->u.periodic.offset
@@ -295,19 +284,16 @@ static int need_period_modifier(struct iforce* iforce, struct ff_effect* new)
* Analyse the changes in an effect, and tell if we need to send an effect
* packet
*/
-static int need_core(struct iforce* iforce, struct ff_effect* new)
+static int need_core(struct ff_effect *old, struct ff_effect *new)
{
- int id = new->id;
- struct ff_effect* old = &iforce->core_effects[id].effect;
-
if (old->direction != new->direction
|| old->trigger.button != new->trigger.button
|| old->trigger.interval != new->trigger.interval
|| old->replay.length != new->replay.length
|| old->replay.delay != new->replay.delay)
- return TRUE;
+ return 1;
- return FALSE;
+ return 0;
}
/*
* Send the part common to all effects to the device
@@ -360,7 +346,7 @@ static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2,
* Upload a periodic effect to the device
* See also iforce_upload_constant.
*/
-int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update)
+int iforce_upload_periodic(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old)
{
u8 wave_code;
int core_id = effect->id;
@@ -371,23 +357,25 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int
int param2_err = 1;
int core_err = 0;
- if (!is_update || need_period_modifier(iforce, effect)) {
+ if (!old || need_period_modifier(old, effect)) {
param1_err = make_period_modifier(iforce, mod1_chunk,
- is_update,
+ old != NULL,
effect->u.periodic.magnitude, effect->u.periodic.offset,
effect->u.periodic.period, effect->u.periodic.phase);
- if (param1_err) return param1_err;
+ if (param1_err)
+ return param1_err;
set_bit(FF_MOD1_IS_USED, core_effect->flags);
}
- if (!is_update || need_envelope_modifier(iforce, effect)) {
+ if (!old || need_envelope_modifier(old, effect)) {
param2_err = make_envelope_modifier(iforce, mod2_chunk,
- is_update,
+ old !=NULL,
effect->u.periodic.envelope.attack_length,
effect->u.periodic.envelope.attack_level,
effect->u.periodic.envelope.fade_length,
effect->u.periodic.envelope.fade_level);
- if (param2_err) return param2_err;
+ if (param2_err)
+ return param2_err;
set_bit(FF_MOD2_IS_USED, core_effect->flags);
}
@@ -400,7 +388,7 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int
default: wave_code = 0x20; break;
}
- if (!is_update || need_core(iforce, effect)) {
+ if (!old || need_core(old, effect)) {
core_err = make_core(iforce, effect->id,
mod1_chunk->start,
mod2_chunk->start,
@@ -429,7 +417,7 @@ int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int
* 0 Ok, effect created or updated
* 1 effect did not change since last upload, and no packet was therefore sent
*/
-int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update)
+int iforce_upload_constant(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old)
{
int core_id = effect->id;
struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
@@ -439,26 +427,28 @@ int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int
int param2_err = 1;
int core_err = 0;
- if (!is_update || need_magnitude_modifier(iforce, effect)) {
+ if (!old || need_magnitude_modifier(old, effect)) {
param1_err = make_magnitude_modifier(iforce, mod1_chunk,
- is_update,
+ old != NULL,
effect->u.constant.level);
- if (param1_err) return param1_err;
+ if (param1_err)
+ return param1_err;
set_bit(FF_MOD1_IS_USED, core_effect->flags);
}
- if (!is_update || need_envelope_modifier(iforce, effect)) {
+ if (!old || need_envelope_modifier(old, effect)) {
param2_err = make_envelope_modifier(iforce, mod2_chunk,
- is_update,
+ old != NULL,
effect->u.constant.envelope.attack_length,
effect->u.constant.envelope.attack_level,
effect->u.constant.envelope.fade_length,
effect->u.constant.envelope.fade_level);
- if (param2_err) return param2_err;
+ if (param2_err)
+ return param2_err;
set_bit(FF_MOD2_IS_USED, core_effect->flags);
}
- if (!is_update || need_core(iforce, effect)) {
+ if (!old || need_core(old, effect)) {
core_err = make_core(iforce, effect->id,
mod1_chunk->start,
mod2_chunk->start,
@@ -483,7 +473,7 @@ int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int
/*
* Upload an condition effect. Those are for example friction, inertia, springs...
*/
-int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update)
+int iforce_upload_condition(struct iforce *iforce, struct ff_effect *effect, struct ff_effect *old)
{
int core_id = effect->id;
struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
@@ -494,37 +484,39 @@ int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int
int core_err = 0;
switch (effect->type) {
- case FF_SPRING: type = 0x40; break;
- case FF_DAMPER: type = 0x41; break;
+ case FF_SPRING: type = 0x40; break;
+ case FF_DAMPER: type = 0x41; break;
default: return -1;
}
- if (!is_update || need_condition_modifier(iforce, effect)) {
+ if (!old || need_condition_modifier(old, effect)) {
param_err = make_condition_modifier(iforce, mod1_chunk,
- is_update,
+ old != NULL,
effect->u.condition[0].right_saturation,
effect->u.condition[0].left_saturation,
effect->u.condition[0].right_coeff,
effect->u.condition[0].left_coeff,
effect->u.condition[0].deadband,
effect->u.condition[0].center);
- if (param_err) return param_err;
+ if (param_err)
+ return param_err;
set_bit(FF_MOD1_IS_USED, core_effect->flags);
param_err = make_condition_modifier(iforce, mod2_chunk,
- is_update,
+ old != NULL,
effect->u.condition[1].right_saturation,
effect->u.condition[1].left_saturation,
effect->u.condition[1].right_coeff,
effect->u.condition[1].left_coeff,
effect->u.condition[1].deadband,
effect->u.condition[1].center);
- if (param_err) return param_err;
+ if (param_err)
+ return param_err;
set_bit(FF_MOD2_IS_USED, core_effect->flags);
}
- if (!is_update || need_core(iforce, effect)) {
+ if (!old || need_core(old, effect)) {
core_err = make_core(iforce, effect->id,
mod1_chunk->start, mod2_chunk->start,
type, 0xc0,
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index b4914e7231f8..24c684bc6337 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -83,103 +83,57 @@ static struct iforce_device iforce_device[] = {
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
};
-
-
-static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+static int iforce_playback(struct input_dev *dev, int effect_id, int value)
{
struct iforce* iforce = dev->private;
- unsigned char data[3];
-
- if (type != EV_FF)
- return -1;
-
- switch (code) {
-
- case FF_GAIN:
-
- data[0] = value >> 9;
- iforce_send_packet(iforce, FF_CMD_GAIN, data);
-
- return 0;
-
- case FF_AUTOCENTER:
+ struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
- data[0] = 0x03;
- data[1] = value >> 9;
- iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
+ if (value > 0)
+ set_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);
+ else
+ clear_bit(FF_CORE_SHOULD_PLAY, core_effect->flags);
- data[0] = 0x04;
- data[1] = 0x01;
- iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
+ iforce_control_playback(iforce, effect_id, value);
+ return 0;
+}
- return 0;
+static void iforce_set_gain(struct input_dev *dev, u16 gain)
+{
+ struct iforce* iforce = dev->private;
+ unsigned char data[3];
- default: /* Play or stop an effect */
+ data[0] = gain >> 9;
+ iforce_send_packet(iforce, FF_CMD_GAIN, data);
+}
- if (!CHECK_OWNERSHIP(code, iforce)) {
- return -1;
- }
- if (value > 0) {
- set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
- }
- else {
- clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags);
- }
+static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+ struct iforce* iforce = dev->private;
+ unsigned char data[3];
- iforce_control_playback(iforce, code, value);
- return 0;
- }
+ data[0] = 0x03;
+ data[1] = magnitude >> 9;
+ iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
- return -1;
+ data[0] = 0x04;
+ data[1] = 0x01;
+ iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data);
}
/*
* Function called when an ioctl is performed on the event dev entry.
* It uploads an effect to the device
*/
-static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
+static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{
struct iforce* iforce = dev->private;
- int id;
+ struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id];
int ret;
- int is_update;
-
-/* Check this effect type is supported by this device */
- if (!test_bit(effect->type, iforce->dev->ffbit))
- return -EINVAL;
-
-/*
- * If we want to create a new effect, get a free id
- */
- if (effect->id == -1) {
-
- for (id = 0; id < FF_EFFECTS_MAX; ++id)
- if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags))
- break;
-
- if (id == FF_EFFECTS_MAX || id >= iforce->dev->ff_effects_max)
- return -ENOMEM;
-
- effect->id = id;
- iforce->core_effects[id].owner = current->pid;
- iforce->core_effects[id].flags[0] = (1 << FF_CORE_IS_USED); /* Only IS_USED bit must be set */
-
- is_update = FALSE;
- }
- else {
- /* We want to update an effect */
- if (!CHECK_OWNERSHIP(effect->id, iforce))
- return -EACCES;
-
- /* Parameter type cannot be updated */
- if (effect->type != iforce->core_effects[effect->id].effect.type)
- return -EINVAL;
+ if (__test_and_set_bit(FF_CORE_IS_USED, core_effect->flags)) {
/* Check the effect is not already being updated */
- if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags))
+ if (test_bit(FF_CORE_UPDATE, core_effect->flags))
return -EAGAIN;
-
- is_update = TRUE;
}
/*
@@ -188,28 +142,28 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
switch (effect->type) {
case FF_PERIODIC:
- ret = iforce_upload_periodic(iforce, effect, is_update);
+ ret = iforce_upload_periodic(iforce, effect, old);
break;
case FF_CONSTANT:
- ret = iforce_upload_constant(iforce, effect, is_update);
+ ret = iforce_upload_constant(iforce, effect, old);
break;
case FF_SPRING:
case FF_DAMPER:
- ret = iforce_upload_condition(iforce, effect, is_update);
+ ret = iforce_upload_condition(iforce, effect, old);
break;
default:
return -EINVAL;
}
+
if (ret == 0) {
/* A packet was sent, forbid new updates until we are notified
* that the packet was updated
*/
- set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags);
+ set_bit(FF_CORE_UPDATE, core_effect->flags);
}
- iforce->core_effects[effect->id].effect = *effect;
return ret;
}
@@ -219,20 +173,9 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
*/
static int iforce_erase_effect(struct input_dev *dev, int effect_id)
{
- struct iforce* iforce = dev->private;
+ struct iforce *iforce = dev->private;
+ struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
int err = 0;
- struct iforce_core_effect* core_effect;
-
- if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
- return -EINVAL;
-
- core_effect = &iforce->core_effects[effect_id];
-
- /* Check who is trying to erase this effect */
- if (core_effect->owner != current->pid) {
- printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, core_effect->owner);
- return -EACCES;
- }
if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
err = release_resource(&core_effect->mod1_chunk);
@@ -240,7 +183,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id)
if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
err = release_resource(&core_effect->mod2_chunk);
- /*TODO: remember to change that if more FF_MOD* bits are added */
+ /* TODO: remember to change that if more FF_MOD* bits are added */
core_effect->flags[0] = 0;
return err;
@@ -260,52 +203,31 @@ static int iforce_open(struct input_dev *dev)
#endif
}
- /* Enable force feedback */
- iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");
+ if (test_bit(EV_FF, dev->evbit)) {
+ /* Enable force feedback */
+ iforce_send_packet(iforce, FF_CMD_ENABLE, "\004");
+ }
return 0;
}
-static int iforce_flush(struct input_dev *dev, struct file *file)
+static void iforce_release(struct input_dev *dev)
{
struct iforce *iforce = dev->private;
int i;
- /* Erase all effects this process owns */
- for (i=0; i<dev->ff_effects_max; ++i) {
-
- if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
- current->pid == iforce->core_effects[i].owner) {
-
- /* Stop effect */
- input_report_ff(dev, i, 0);
-
- /* Free ressources assigned to effect */
- if (iforce_erase_effect(dev, i)) {
- printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i);
+ if (test_bit(EV_FF, dev->evbit)) {
+ /* Check: no effects should be present in memory */
+ for (i = 0; i < dev->ff->max_effects; i++) {
+ if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) {
+ printk(KERN_WARNING "iforce_release: Device still owns effects\n");
+ break;
}
}
+ /* Disable force feedback playback */
+ iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
}
- return 0;
-}
-
-static void iforce_release(struct input_dev *dev)
-{
- struct iforce *iforce = dev->private;
- int i;
-
- /* Check: no effect should be present in memory */
- for (i=0; i<dev->ff_effects_max; ++i) {
- if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags))
- break;
- }
- if (i<dev->ff_effects_max) {
- printk(KERN_WARNING "iforce_release: Device still owns effects\n");
- }
-
- /* Disable force feedback playback */
- iforce_send_packet(iforce, FF_CMD_ENABLE, "\001");
switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
@@ -342,8 +264,10 @@ void iforce_delete_device(struct iforce *iforce)
int iforce_init_device(struct iforce *iforce)
{
struct input_dev *input_dev;
+ struct ff_device *ff;
unsigned char c[] = "CEOV";
- int i;
+ int i, error;
+ int ff_effects = 0;
input_dev = input_allocate_device();
if (!input_dev)
@@ -378,11 +302,6 @@ int iforce_init_device(struct iforce *iforce)
input_dev->name = "Unknown I-Force device";
input_dev->open = iforce_open;
input_dev->close = iforce_release;
- input_dev->flush = iforce_flush;
- input_dev->event = iforce_input_event;
- input_dev->upload_effect = iforce_upload_effect;
- input_dev->erase_effect = iforce_erase_effect;
- input_dev->ff_effects_max = 10;
/*
* On-device memory allocation.
@@ -430,15 +349,15 @@ int iforce_init_device(struct iforce *iforce)
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n");
if (!iforce_get_id_packet(iforce, "N"))
- iforce->dev->ff_effects_max = iforce->edata[1];
+ ff_effects = iforce->edata[1];
else
printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n");
/* Check if the device can store more effects than the driver can really handle */
- if (iforce->dev->ff_effects_max > FF_EFFECTS_MAX) {
- printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n",
- iforce->dev->ff_effects_max, FF_EFFECTS_MAX);
- iforce->dev->ff_effects_max = FF_EFFECTS_MAX;
+ if (ff_effects > IFORCE_EFFECTS_MAX) {
+ printk(KERN_WARNING "iforce: Limiting number of effects to %d (device reports %d)\n",
+ IFORCE_EFFECTS_MAX, ff_effects);
+ ff_effects = IFORCE_EFFECTS_MAX;
}
/*
@@ -472,12 +391,10 @@ int iforce_init_device(struct iforce *iforce)
* Set input device bitfields and ranges.
*/
- input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS);
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF_STATUS);
- for (i = 0; iforce->type->btn[i] >= 0; i++) {
- signed short t = iforce->type->btn[i];
- set_bit(t, input_dev->keybit);
- }
+ for (i = 0; iforce->type->btn[i] >= 0; i++)
+ set_bit(iforce->type->btn[i], input_dev->keybit);
set_bit(BTN_DEAD, input_dev->keybit);
for (i = 0; iforce->type->abs[i] >= 0; i++) {
@@ -516,9 +433,24 @@ int iforce_init_device(struct iforce *iforce)
}
}
- for (i = 0; iforce->type->ff[i] >= 0; i++)
- set_bit(iforce->type->ff[i], input_dev->ffbit);
+ if (ff_effects) {
+ for (i = 0; iforce->type->ff[i] >= 0; i++)
+ set_bit(iforce->type->ff[i], input_dev->ffbit);
+
+ error = input_ff_create(input_dev, ff_effects);
+ if (error) {
+ input_free_device(input_dev);
+ return error;
+ }
+
+ ff = input_dev->ff;
+ ff->upload = iforce_upload_effect;
+ ff->erase = iforce_erase_effect;
+ ff->set_gain = iforce_set_gain;
+ ff->set_autocenter = iforce_set_autocenter;
+ ff->playback = iforce_playback;
+ }
/*
* Register input device.
*/
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c
index 76cb1f88f4e8..808f05932a6f 100644
--- a/drivers/input/joystick/iforce/iforce-packets.c
+++ b/drivers/input/joystick/iforce/iforce-packets.c
@@ -140,7 +140,10 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
{
int i;
- for (i = 0; i < iforce->dev->ff_effects_max; ++i) {
+ if (!iforce->dev->ff)
+ return 0;
+
+ for (i = 0; i < iforce->dev->ff->max_effects; ++i) {
if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) &&
(iforce->core_effects[i].mod1_chunk.start == addr ||
iforce->core_effects[i].mod2_chunk.start == addr)) {
@@ -152,7 +155,7 @@ static int mark_core_as_ready(struct iforce *iforce, unsigned short addr)
return -1;
}
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs)
+void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
{
struct input_dev *dev = iforce->dev;
int i;
@@ -180,9 +183,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
case 0x01: /* joystick position data */
case 0x03: /* wheel position data */
-
- input_regs(dev, regs);
-
if (HI(cmd) == 1) {
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
@@ -221,7 +221,6 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
break;
case 0x02: /* status report */
- input_regs(dev, regs);
input_report_key(dev, BTN_DEAD, data[0] & 0x02);
input_sync(dev);
@@ -229,19 +228,17 @@ void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data,
i = data[1] & 0x7f;
if (data[1] & 0x80) {
if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
- /* Report play event */
- input_report_ff_status(dev, i, FF_STATUS_PLAYING);
+ /* Report play event */
+ input_report_ff_status(dev, i, FF_STATUS_PLAYING);
}
- }
- else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
+ } else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) {
/* Report stop event */
input_report_ff_status(dev, i, FF_STATUS_STOPPED);
}
if (LO(cmd) > 3) {
int j;
- for (j=3; j<LO(cmd); j+=2) {
+ for (j = 3; j < LO(cmd); j += 2)
mark_core_as_ready(iforce, data[j] | (data[j+1]<<8));
- }
}
break;
}
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c
index 64a78c515484..ca08f45c2040 100644
--- a/drivers/input/joystick/iforce/iforce-serio.c
+++ b/drivers/input/joystick/iforce/iforce-serio.c
@@ -81,7 +81,7 @@ static void iforce_serio_write_wakeup(struct serio *serio)
}
static irqreturn_t iforce_serio_irq(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct iforce *iforce = serio_get_drvdata(serio);
@@ -115,7 +115,7 @@ static irqreturn_t iforce_serio_irq(struct serio *serio,
}
if (iforce->idx == iforce->len) {
- iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data, regs);
+ iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
iforce->pkt = 0;
iforce->id = 0;
iforce->len = 0;
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index fe79d158456d..105112fb7b57 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -74,7 +74,7 @@ void iforce_usb_xmit(struct iforce *iforce)
spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
-static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs)
+static void iforce_usb_irq(struct urb *urb)
{
struct iforce *iforce = urb->context;
int status;
@@ -96,7 +96,7 @@ static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs)
}
iforce_process_packet(iforce,
- (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs);
+ (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
@@ -105,7 +105,7 @@ exit:
__FUNCTION__, status);
}
-static void iforce_usb_out(struct urb *urb, struct pt_regs *regs)
+static void iforce_usb_out(struct urb *urb)
{
struct iforce *iforce = urb->context;
@@ -119,7 +119,7 @@ static void iforce_usb_out(struct urb *urb, struct pt_regs *regs)
wake_up(&iforce->wait);
}
-static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs)
+static void iforce_usb_ctrl(struct urb *urb)
{
struct iforce *iforce = urb->context;
if (urb->status) return;
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h
index e9924d6f01b3..ffaeaefa1a42 100644
--- a/drivers/input/joystick/iforce/iforce.h
+++ b/drivers/input/joystick/iforce/iforce.h
@@ -51,10 +51,7 @@
#define IFORCE_232 1
#define IFORCE_USB 2
-#define FALSE 0
-#define TRUE 1
-
-#define FF_EFFECTS_MAX 32
+#define IFORCE_EFFECTS_MAX 32
/* Each force feedback effect is made of one core effect, which can be
* associated to at most to effect modifiers
@@ -67,24 +64,11 @@
#define FF_CORE_UPDATE 5 /* Effect is being updated */
#define FF_MODCORE_MAX 5
-#define CHECK_OWNERSHIP(i, iforce) \
- ((i) < FF_EFFECTS_MAX && i >= 0 && \
- test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \
- (current->pid == 0 || \
- (iforce)->core_effects[(i)].owner == current->pid))
-
struct iforce_core_effect {
/* Information about where modifiers are stored in the device's memory */
struct resource mod1_chunk;
struct resource mod2_chunk;
unsigned long flags[NBITS(FF_MODCORE_MAX)];
- pid_t owner;
- /* Used to keep track of parameters of an effect. They are needed
- * to know what parts of an effect changed in an update operation.
- * We try to send only parameter packets if possible, as sending
- * effect parameter requires the effect to be stoped and restarted
- */
- struct ff_effect effect;
};
#define FF_CMD_EFFECT 0x010e
@@ -145,7 +129,7 @@ struct iforce {
/* Force Feedback */
wait_queue_head_t wait;
struct resource device_memory;
- struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
+ struct iforce_core_effect core_effects[IFORCE_EFFECTS_MAX];
struct mutex mem_mutex;
};
@@ -176,15 +160,15 @@ void iforce_delete_device(struct iforce *iforce);
/* iforce-packets.c */
int iforce_control_playback(struct iforce*, u16 id, unsigned int);
-void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs);
+void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data);
int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data);
void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ;
int iforce_get_id_packet(struct iforce *iforce, char *packet);
/* iforce-ff.c */
-int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update);
-int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update);
-int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update);
+int iforce_upload_periodic(struct iforce *, struct ff_effect *, struct ff_effect *);
+int iforce_upload_constant(struct iforce *, struct ff_effect *, struct ff_effect *);
+int iforce_upload_condition(struct iforce *, struct ff_effect *, struct ff_effect *);
/* Public variables */
extern struct serio_driver iforce_serio_drv;
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
index 168b1061a03b..e3d19444ba2e 100644
--- a/drivers/input/joystick/magellan.c
+++ b/drivers/input/joystick/magellan.c
@@ -82,7 +82,7 @@ static int magellan_crunch_nibbles(unsigned char *data, int count)
return 0;
}
-static void magellan_process_packet(struct magellan* magellan, struct pt_regs *regs)
+static void magellan_process_packet(struct magellan* magellan)
{
struct input_dev *dev = magellan->dev;
unsigned char *data = magellan->data;
@@ -90,8 +90,6 @@ static void magellan_process_packet(struct magellan* magellan, struct pt_regs *r
if (!magellan->idx) return;
- input_regs(dev, regs);
-
switch (magellan->data[0]) {
case 'd': /* Axis data */
@@ -115,12 +113,12 @@ static void magellan_process_packet(struct magellan* magellan, struct pt_regs *r
}
static irqreturn_t magellan_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct magellan* magellan = serio_get_drvdata(serio);
if (data == '\r') {
- magellan_process_packet(magellan, regs);
+ magellan_process_packet(magellan);
magellan->idx = 0;
} else {
if (magellan->idx < MAGELLAN_MAX_LENGTH)
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index 7a19ee052972..2a9808cf826f 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -82,7 +82,7 @@ struct spaceball {
* SpaceBall.
*/
-static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs *regs)
+static void spaceball_process_packet(struct spaceball* spaceball)
{
struct input_dev *dev = spaceball->dev;
unsigned char *data = spaceball->data;
@@ -90,8 +90,6 @@ static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs
if (spaceball->idx < 2) return;
- input_regs(dev, regs);
-
switch (spaceball->data[0]) {
case 'D': /* Ball data */
@@ -151,13 +149,13 @@ static void spaceball_process_packet(struct spaceball* spaceball, struct pt_regs
*/
static irqreturn_t spaceball_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct spaceball *spaceball = serio_get_drvdata(serio);
switch (data) {
case 0xd:
- spaceball_process_packet(spaceball, regs);
+ spaceball_process_packet(spaceball);
spaceball->idx = 0;
spaceball->escape = 0;
break;
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 3e2782e79834..c4db0247c5fb 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -74,7 +74,7 @@ static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive
* SpaceOrb.
*/
-static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *regs)
+static void spaceorb_process_packet(struct spaceorb *spaceorb)
{
struct input_dev *dev = spaceorb->dev;
unsigned char *data = spaceorb->data;
@@ -86,8 +86,6 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r
for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
if (c) return;
- input_regs(dev, regs);
-
switch (data[0]) {
case 'R': /* Reset packet */
@@ -131,12 +129,12 @@ static void spaceorb_process_packet(struct spaceorb *spaceorb, struct pt_regs *r
}
static irqreturn_t spaceorb_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct spaceorb* spaceorb = serio_get_drvdata(serio);
if (~data & 0x80) {
- if (spaceorb->idx) spaceorb_process_packet(spaceorb, regs);
+ if (spaceorb->idx) spaceorb_process_packet(spaceorb);
spaceorb->idx = 0;
}
if (spaceorb->idx < SPACEORB_MAX_LENGTH)
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
index 011ec4858e15..1ffb03223311 100644
--- a/drivers/input/joystick/stinger.c
+++ b/drivers/input/joystick/stinger.c
@@ -64,15 +64,13 @@ struct stinger {
* Stinger. It updates the data accordingly.
*/
-static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs)
+static void stinger_process_packet(struct stinger *stinger)
{
struct input_dev *dev = stinger->dev;
unsigned char *data = stinger->data;
if (!stinger->idx) return;
- input_regs(dev, regs);
-
input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5));
input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4));
input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3));
@@ -99,7 +97,7 @@ static void stinger_process_packet(struct stinger *stinger, struct pt_regs *regs
*/
static irqreturn_t stinger_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct stinger *stinger = serio_get_drvdata(serio);
@@ -109,7 +107,7 @@ static irqreturn_t stinger_interrupt(struct serio *serio,
stinger->data[stinger->idx++] = data;
if (stinger->idx == 4) {
- stinger_process_packet(stinger, regs);
+ stinger_process_packet(stinger);
stinger->idx = 0;
}
diff --git a/drivers/input/joystick/twidjoy.c b/drivers/input/joystick/twidjoy.c
index 076f237d9654..49085df2d631 100644
--- a/drivers/input/joystick/twidjoy.c
+++ b/drivers/input/joystick/twidjoy.c
@@ -104,7 +104,7 @@ struct twidjoy {
* Twiddler. It updates the data accordingly.
*/
-static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs)
+static void twidjoy_process_packet(struct twidjoy *twidjoy)
{
struct input_dev *dev = twidjoy->dev;
unsigned char *data = twidjoy->data;
@@ -113,8 +113,6 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs
button_bits = ((data[1] & 0x7f) << 7) | (data[0] & 0x7f);
- input_regs(dev, regs);
-
for (bp = twidjoy_buttons; bp->bitmask; bp++) {
int value = (button_bits & (bp->bitmask << bp->bitshift)) >> bp->bitshift;
int i;
@@ -141,7 +139,7 @@ static void twidjoy_process_packet(struct twidjoy *twidjoy, struct pt_regs *regs
* packet processing routine.
*/
-static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs)
+static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
{
struct twidjoy *twidjoy = serio_get_drvdata(serio);
@@ -158,7 +156,7 @@ static irqreturn_t twidjoy_interrupt(struct serio *serio, unsigned char data, un
twidjoy->data[twidjoy->idx++] = data;
if (twidjoy->idx == TWIDJOY_MAX_LENGTH) {
- twidjoy_process_packet(twidjoy, regs);
+ twidjoy_process_packet(twidjoy);
twidjoy->idx = 0;
}
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
index f9c1a03214eb..35edea1ab955 100644
--- a/drivers/input/joystick/warrior.c
+++ b/drivers/input/joystick/warrior.c
@@ -64,15 +64,13 @@ struct warrior {
* Warrior. It updates the data accordingly.
*/
-static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs)
+static void warrior_process_packet(struct warrior *warrior)
{
struct input_dev *dev = warrior->dev;
unsigned char *data = warrior->data;
if (!warrior->idx) return;
- input_regs(dev, regs);
-
switch ((data[0] >> 4) & 7) {
case 1: /* Button data */
input_report_key(dev, BTN_TRIGGER, data[3] & 1);
@@ -101,12 +99,12 @@ static void warrior_process_packet(struct warrior *warrior, struct pt_regs *regs
*/
static irqreturn_t warrior_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct warrior *warrior = serio_get_drvdata(serio);
if (data & 0x80) {
- if (warrior->idx) warrior_process_packet(warrior, regs);
+ if (warrior->idx) warrior_process_packet(warrior);
warrior->idx = 0;
warrior->len = warrior_lengths[(data >> 4) & 7];
}
@@ -115,7 +113,7 @@ static irqreturn_t warrior_interrupt(struct serio *serio,
warrior->data[warrior->idx++] = data;
if (warrior->idx == warrior->len) {
- if (warrior->idx) warrior_process_packet(warrior, regs);
+ if (warrior->idx) warrior_process_packet(warrior);
warrior->idx = 0;
warrior->len = 0;
}
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a9dda56f62c4..81a333f73010 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -121,6 +121,17 @@ config KEYBOARD_NEWTON
To compile this driver as a module, choose M here: the
module will be called newtonkbd.
+config KEYBOARD_STOWAWAY
+ tristate "Stowaway keyboard"
+ select SERIO
+ help
+ Say Y here if you have a Stowaway keyboard on a serial port.
+ Stowaway compatible keyboards like Dicota Input-PDA keyboard
+ are also supported by this driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called stowaway.
+
config KEYBOARD_CORGI
tristate "Corgi keyboard"
depends on PXA_SHARPSL
@@ -155,7 +166,7 @@ config KEYBOARD_AMIGA
config KEYBOARD_HIL_OLD
tristate "HP HIL keyboard support (simple driver)"
- depends on GSC
+ depends on GSC || HP300
default y
help
The "Human Interface Loop" is a older, 8-channel USB-like
@@ -166,13 +177,13 @@ config KEYBOARD_HIL_OLD
However, it has been thoroughly tested and is stable.
If you want full HIL support including support for multiple
- keyboards, mices and tablets, you have to enable the
+ keyboards, mice, and tablets, you have to enable the
"HP System Device Controller i8042 Support" in the input/serio
submenu.
config KEYBOARD_HIL
tristate "HP HIL keyboard support"
- depends on GSC
+ depends on GSC || HP300
default y
select HP_SDC
select HIL_MLC
@@ -183,4 +194,13 @@ config KEYBOARD_HIL
This driver implements support for HIL-keyboards attached
to your machine, so normally you should say Y here.
+config KEYBOARD_OMAP
+ tristate "TI OMAP keypad support"
+ depends on (ARCH_OMAP1 || ARCH_OMAP2)
+ help
+ Say Y here if you want to use the OMAP keypad.
+
+ To compile this driver as a module, choose M here: the
+ module will be called omap-keypad.
+
endif
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index 2708167ba175..4c79e7bc9d06 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,8 +11,10 @@ obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o
obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
+obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
+obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
diff --git a/drivers/input/keyboard/amikbd.c b/drivers/input/keyboard/amikbd.c
index f1f9db9d282c..8abdbd0ee8f9 100644
--- a/drivers/input/keyboard/amikbd.c
+++ b/drivers/input/keyboard/amikbd.c
@@ -158,7 +158,7 @@ static const char *amikbd_messages[8] = {
static struct input_dev *amikbd_dev;
-static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t amikbd_interrupt(int irq, void *dummy)
{
unsigned char scancode, down;
@@ -171,8 +171,6 @@ static irqreturn_t amikbd_interrupt(int irq, void *dummy, struct pt_regs *fp)
scancode >>= 1;
if (scancode < 0x78) { /* scancodes < 0x78 are keys */
- input_regs(amikbd_dev, fp);
-
if (scancode == 98) { /* CapsLock is a toggle switch key on Amiga */
input_report_key(amikbd_dev, scancode, 1);
input_report_key(amikbd_dev, scancode, 0);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index a86afd0a5ef1..cbb93669d1ce 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -221,6 +221,7 @@ struct atkbd {
unsigned long xl_bit;
unsigned int last;
unsigned long time;
+ unsigned long err_count;
struct work_struct event_work;
struct mutex event_mutex;
@@ -234,11 +235,13 @@ static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t
#define ATKBD_DEFINE_ATTR(_name) \
static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \
-static ssize_t atkbd_do_show_##_name(struct device *d, struct device_attribute *attr, char *b) \
+static ssize_t atkbd_do_show_##_name(struct device *d, \
+ struct device_attribute *attr, char *b) \
{ \
return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
} \
-static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *attr, const char *b, size_t s) \
+static ssize_t atkbd_do_set_##_name(struct device *d, \
+ struct device_attribute *attr, const char *b, size_t s) \
{ \
return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
} \
@@ -251,6 +254,32 @@ ATKBD_DEFINE_ATTR(set);
ATKBD_DEFINE_ATTR(softrepeat);
ATKBD_DEFINE_ATTR(softraw);
+#define ATKBD_DEFINE_RO_ATTR(_name) \
+static ssize_t atkbd_show_##_name(struct atkbd *, char *); \
+static ssize_t atkbd_do_show_##_name(struct device *d, \
+ struct device_attribute *attr, char *b) \
+{ \
+ return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \
+} \
+static struct device_attribute atkbd_attr_##_name = \
+ __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL);
+
+ATKBD_DEFINE_RO_ATTR(err_count);
+
+static struct attribute *atkbd_attributes[] = {
+ &atkbd_attr_extra.attr,
+ &atkbd_attr_scroll.attr,
+ &atkbd_attr_set.attr,
+ &atkbd_attr_softrepeat.attr,
+ &atkbd_attr_softraw.attr,
+ &atkbd_attr_err_count.attr,
+ NULL
+};
+
+static struct attribute_group atkbd_attribute_group = {
+ .attrs = atkbd_attributes,
+};
+
static const unsigned int xl_table[] = {
ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK,
ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL,
@@ -318,7 +347,7 @@ static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code
*/
static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
- unsigned int flags, struct pt_regs *regs)
+ unsigned int flags)
{
struct atkbd *atkbd = serio_get_drvdata(serio);
struct input_dev *dev = atkbd->dev;
@@ -396,7 +425,10 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
add_release_event = 1;
break;
case ATKBD_RET_ERR:
+ atkbd->err_count++;
+#ifdef ATKBD_DEBUG
printk(KERN_DEBUG "atkbd.c: Keyboard on %s reports too many keys pressed.\n", serio->phys);
+#endif
goto out;
}
@@ -458,7 +490,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2;
}
- input_regs(dev, regs);
input_event(dev, EV_KEY, keycode, value);
input_sync(dev);
@@ -469,7 +500,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
}
if (atkbd->scroll) {
- input_regs(dev, regs);
if (click != -1)
input_report_key(dev, BTN_MIDDLE, click);
input_report_rel(dev, REL_WHEEL, scroll);
@@ -652,9 +682,7 @@ static int atkbd_probe(struct atkbd *atkbd)
return 0;
}
- if (param[0] != 0xab && param[0] != 0xac && /* Regular and NCD Sun keyboards */
- param[0] != 0x2b && param[0] != 0x5d && /* Trust keyboard, raw and translated */
- param[0] != 0x60 && param[0] != 0x47) /* NMB SGI keyboard, raw and translated */
+ if (!ps2_is_keyboard_id(param[0]))
return -1;
atkbd->id = (param[0] << 8) | param[1];
@@ -790,12 +818,7 @@ static void atkbd_disconnect(struct serio *serio)
synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */
flush_scheduled_work();
- device_remove_file(&serio->dev, &atkbd_attr_extra);
- device_remove_file(&serio->dev, &atkbd_attr_scroll);
- device_remove_file(&serio->dev, &atkbd_attr_set);
- device_remove_file(&serio->dev, &atkbd_attr_softrepeat);
- device_remove_file(&serio->dev, &atkbd_attr_softraw);
-
+ sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
input_unregister_device(atkbd->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
@@ -965,11 +988,7 @@ static int atkbd_connect(struct serio *serio, struct serio_driver *drv)
atkbd_set_keycode_table(atkbd);
atkbd_set_device_attrs(atkbd);
- device_create_file(&serio->dev, &atkbd_attr_extra);
- device_create_file(&serio->dev, &atkbd_attr_scroll);
- device_create_file(&serio->dev, &atkbd_attr_set);
- device_create_file(&serio->dev, &atkbd_attr_softrepeat);
- device_create_file(&serio->dev, &atkbd_attr_softraw);
+ sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group);
atkbd_enable(atkbd);
@@ -1263,6 +1282,11 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co
return count;
}
+static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
+{
+ return sprintf(buf, "%lu\n", atkbd->err_count);
+}
+
static int __init atkbd_init(void)
{
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 1e03153b9bca..befdd6006b50 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -129,7 +129,7 @@ static inline void corgikbd_reset_col(int col)
*/
/* Scan the hardware keyboard and push any changes up through the input layer */
-static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs *regs)
+static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data)
{
unsigned int row, col, rowd;
unsigned long flags;
@@ -140,9 +140,6 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs
spin_lock_irqsave(&corgikbd_data->lock, flags);
- if (regs)
- input_regs(corgikbd_data->input, regs);
-
num_pressed = 0;
for (col = 0; col < KB_COLS; col++) {
/*
@@ -191,14 +188,14 @@ static void corgikbd_scankeyboard(struct corgikbd *corgikbd_data, struct pt_regs
/*
* corgi keyboard interrupt handler.
*/
-static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t corgikbd_interrupt(int irq, void *dev_id)
{
struct corgikbd *corgikbd_data = dev_id;
if (!timer_pending(&corgikbd_data->timer)) {
/** wait chattering delay **/
udelay(20);
- corgikbd_scankeyboard(corgikbd_data, regs);
+ corgikbd_scankeyboard(corgikbd_data);
}
return IRQ_HANDLED;
@@ -210,7 +207,7 @@ static irqreturn_t corgikbd_interrupt(int irq, void *dev_id, struct pt_regs *reg
static void corgikbd_timer_callback(unsigned long data)
{
struct corgikbd *corgikbd_data = (struct corgikbd *) data;
- corgikbd_scankeyboard(corgikbd_data, NULL);
+ corgikbd_scankeyboard(corgikbd_data);
}
/*
diff --git a/drivers/input/keyboard/hil_kbd.c b/drivers/input/keyboard/hil_kbd.c
index 2e4abdc26367..e774dd31e99b 100644
--- a/drivers/input/keyboard/hil_kbd.c
+++ b/drivers/input/keyboard/hil_kbd.c
@@ -198,7 +198,7 @@ static void hil_kbd_process_err(struct hil_kbd *kbd) {
}
static irqreturn_t hil_kbd_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct hil_kbd *kbd;
hil_packet packet;
@@ -328,7 +328,7 @@ static int hil_kbd_connect(struct serio *serio, struct serio_driver *drv)
kbd->dev->id.vendor = PCI_VENDOR_ID_HP;
kbd->dev->id.product = 0x0001; /* TODO: get from kbd->rsc */
kbd->dev->id.version = 0x0100; /* TODO: get from kbd->rsc */
- kbd->dev->dev = &serio->dev;
+ kbd->dev->cdev.dev = &serio->dev;
for (i = 0; i < 128; i++) {
set_bit(hil_kbd_set1[i], kbd->dev->keybit);
diff --git a/drivers/input/keyboard/hilkbd.c b/drivers/input/keyboard/hilkbd.c
index d22c7c624296..54bc569db4b0 100644
--- a/drivers/input/keyboard/hilkbd.c
+++ b/drivers/input/keyboard/hilkbd.c
@@ -150,7 +150,7 @@ static inline void handle_data(unsigned char s, unsigned char c)
/*
* Handle HIL interrupts.
*/
-static irqreturn_t hil_interrupt(int irq, void *handle, struct pt_regs *regs)
+static irqreturn_t hil_interrupt(int irq, void *handle)
{
unsigned char s, c;
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 5174224cadb4..708d5a1bc3d2 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -453,8 +453,7 @@ lkkbd_detection_done (struct lkkbd *lk)
* is received.
*/
static irqreturn_t
-lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
- struct pt_regs *regs)
+lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
{
struct lkkbd *lk = serio_get_drvdata (serio);
int i;
@@ -473,7 +472,6 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
switch (data) {
case LK_ALL_KEYS_UP:
- input_regs (lk->dev, regs);
for (i = 0; i < ARRAY_SIZE (lkkbd_keycode); i++)
if (lk->keycode[i] != KEY_RESERVED)
input_report_key (lk->dev, lk->keycode[i], 0);
@@ -501,7 +499,6 @@ lkkbd_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
default:
if (lk->keycode[data] != KEY_RESERVED) {
- input_regs (lk->dev, regs);
if (!test_bit (lk->keycode[data], lk->dev->key))
input_report_key (lk->dev, lk->keycode[data], 1);
else
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index 83906f80ba21..5788dbc317bb 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -126,7 +126,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
*/
/* Scan the hardware keyboard and push any changes up through the input layer */
-static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd)
{
unsigned int row, col, rowd, scancode;
unsigned long flags;
@@ -135,8 +135,6 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
spin_lock_irqsave(&locomokbd->lock, flags);
- input_regs(locomokbd->input, regs);
-
locomokbd_charge_all(membase);
num_pressed = 0;
@@ -171,13 +169,13 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
/*
* LoCoMo keyboard interrupt handler.
*/
-static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t locomokbd_interrupt(int irq, void *dev_id)
{
struct locomokbd *locomokbd = dev_id;
/** wait chattering delay **/
udelay(100);
- locomokbd_scankeyboard(locomokbd, regs);
+ locomokbd_scankeyboard(locomokbd);
return IRQ_HANDLED;
}
@@ -188,7 +186,7 @@ static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *re
static void locomokbd_timer_callback(unsigned long data)
{
struct locomokbd *locomokbd = (struct locomokbd *) data;
- locomokbd_scankeyboard(locomokbd, NULL);
+ locomokbd_scankeyboard(locomokbd);
}
static int locomokbd_probe(struct locomo_dev *dev)
diff --git a/drivers/input/keyboard/newtonkbd.c b/drivers/input/keyboard/newtonkbd.c
index 40a3f551247e..9282e4e082bd 100644
--- a/drivers/input/keyboard/newtonkbd.c
+++ b/drivers/input/keyboard/newtonkbd.c
@@ -65,13 +65,12 @@ struct nkbd {
};
static irqreturn_t nkbd_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct nkbd *nkbd = serio_get_drvdata(serio);
/* invalid scan codes are probably the init sequence, so we ignore them */
if (nkbd->keycode[data & NKBD_KEY]) {
- input_regs(nkbd->dev, regs);
input_report_key(nkbd->dev, nkbd->keycode[data & NKBD_KEY], data & NKBD_PRESS);
input_sync(nkbd->dev);
}
diff --git a/drivers/input/keyboard/omap-keypad.c b/drivers/input/keyboard/omap-keypad.c
new file mode 100644
index 000000000000..5680a6d95b2b
--- /dev/null
+++ b/drivers/input/keyboard/omap-keypad.c
@@ -0,0 +1,491 @@
+/*
+ * linux/drivers/input/keyboard/omap-keypad.c
+ *
+ * OMAP Keypad Driver
+ *
+ * Copyright (C) 2003 Nokia Corporation
+ * Written by Timo Teräs <ext-timo.teras@nokia.com>
+ *
+ * Added support for H2 & H3 Keypad
+ * Copyright (C) 2004 Texas Instruments
+ *
+ * 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/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/mutex.h>
+#include <linux/errno.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/keypad.h>
+#include <asm/arch/menelaus.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/arch/mux.h>
+
+#undef NEW_BOARD_LEARNING_MODE
+
+static void omap_kp_tasklet(unsigned long);
+static void omap_kp_timer(unsigned long);
+
+static unsigned char keypad_state[8];
+static DEFINE_MUTEX(kp_enable_mutex);
+static int kp_enable = 1;
+static int kp_cur_group = -1;
+
+struct omap_kp {
+ struct input_dev *input;
+ struct timer_list timer;
+ int irq;
+ unsigned int rows;
+ unsigned int cols;
+ unsigned long delay;
+ unsigned int debounce;
+};
+
+DECLARE_TASKLET_DISABLED(kp_tasklet, omap_kp_tasklet, 0);
+
+static int *keymap;
+static unsigned int *row_gpios;
+static unsigned int *col_gpios;
+
+#ifdef CONFIG_ARCH_OMAP2
+static void set_col_gpio_val(struct omap_kp *omap_kp, u8 value)
+{
+ int col;
+ for (col = 0; col < omap_kp->cols; col++) {
+ if (value & (1 << col))
+ omap_set_gpio_dataout(col_gpios[col], 1);
+ else
+ omap_set_gpio_dataout(col_gpios[col], 0);
+ }
+}
+
+static u8 get_row_gpio_val(struct omap_kp *omap_kp)
+{
+ int row;
+ u8 value = 0;
+
+ for (row = 0; row < omap_kp->rows; row++) {
+ if (omap_get_gpio_datain(row_gpios[row]))
+ value |= (1 << row);
+ }
+ return value;
+}
+#else
+#define set_col_gpio_val(x, y) do {} while (0)
+#define get_row_gpio_val(x) 0
+#endif
+
+static irqreturn_t omap_kp_interrupt(int irq, void *dev_id)
+{
+ struct omap_kp *omap_kp = dev_id;
+
+ /* disable keyboard interrupt and schedule for handling */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->rows; i++)
+ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+ } else
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ tasklet_schedule(&kp_tasklet);
+
+ return IRQ_HANDLED;
+}
+
+static void omap_kp_timer(unsigned long data)
+{
+ tasklet_schedule(&kp_tasklet);
+}
+
+static void omap_kp_scan_keypad(struct omap_kp *omap_kp, unsigned char *state)
+{
+ int col = 0;
+
+ /* read the keypad status */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->rows; i++)
+ disable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+
+ /* read the keypad status */
+ for (col = 0; col < omap_kp->cols; col++) {
+ set_col_gpio_val(omap_kp, ~(1 << col));
+ state[col] = ~(get_row_gpio_val(omap_kp)) & 0x3f;
+ }
+ set_col_gpio_val(omap_kp, 0);
+
+ } else {
+ /* disable keyboard interrupt and schedule for handling */
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ /* read the keypad status */
+ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+ for (col = 0; col < omap_kp->cols; col++) {
+ omap_writew(~(1 << col) & 0xff,
+ OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+
+ udelay(omap_kp->delay);
+
+ state[col] = ~omap_readw(OMAP_MPUIO_BASE +
+ OMAP_MPUIO_KBR_LATCH) & 0xff;
+ }
+ omap_writew(0x00, OMAP_MPUIO_BASE + OMAP_MPUIO_KBC);
+ udelay(2);
+ }
+}
+
+static inline int omap_kp_find_key(int col, int row)
+{
+ int i, key;
+
+ key = KEY(col, row, 0);
+ for (i = 0; keymap[i] != 0; i++)
+ if ((keymap[i] & 0xff000000) == key)
+ return keymap[i] & 0x00ffffff;
+ return -1;
+}
+
+static void omap_kp_tasklet(unsigned long data)
+{
+ struct omap_kp *omap_kp_data = (struct omap_kp *) data;
+ unsigned char new_state[8], changed, key_down = 0;
+ int col, row;
+ int spurious = 0;
+
+ /* check for any changes */
+ omap_kp_scan_keypad(omap_kp_data, new_state);
+
+ /* check for changes and print those */
+ for (col = 0; col < omap_kp_data->cols; col++) {
+ changed = new_state[col] ^ keypad_state[col];
+ key_down |= new_state[col];
+ if (changed == 0)
+ continue;
+
+ for (row = 0; row < omap_kp_data->rows; row++) {
+ int key;
+ if (!(changed & (1 << row)))
+ continue;
+#ifdef NEW_BOARD_LEARNING_MODE
+ printk(KERN_INFO "omap-keypad: key %d-%d %s\n", col,
+ row, (new_state[col] & (1 << row)) ?
+ "pressed" : "released");
+#else
+ key = omap_kp_find_key(col, row);
+ if (key < 0) {
+ printk(KERN_WARNING
+ "omap-keypad: Spurious key event %d-%d\n",
+ col, row);
+ /* We scan again after a couple of seconds */
+ spurious = 1;
+ continue;
+ }
+
+ if (!(kp_cur_group == (key & GROUP_MASK) ||
+ kp_cur_group == -1))
+ continue;
+
+ kp_cur_group = key & GROUP_MASK;
+ input_report_key(omap_kp_data->input, key & ~GROUP_MASK,
+ new_state[col] & (1 << row));
+#endif
+ }
+ }
+ memcpy(keypad_state, new_state, sizeof(keypad_state));
+
+ if (key_down) {
+ int delay = HZ / 20;
+ /* some key is pressed - keep irq disabled and use timer
+ * to poll the keypad */
+ if (spurious)
+ delay = 2 * HZ;
+ mod_timer(&omap_kp_data->timer, jiffies + delay);
+ } else {
+ /* enable interrupts */
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp_data->rows; i++)
+ enable_irq(OMAP_GPIO_IRQ(row_gpios[i]));
+ } else {
+ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ kp_cur_group = -1;
+ }
+ }
+}
+
+static ssize_t omap_kp_enable_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%u\n", kp_enable);
+}
+
+static ssize_t omap_kp_enable_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int state;
+
+ if (sscanf(buf, "%u", &state) != 1)
+ return -EINVAL;
+
+ if ((state != 1) && (state != 0))
+ return -EINVAL;
+
+ mutex_lock(&kp_enable_mutex);
+ if (state != kp_enable) {
+ if (state)
+ enable_irq(INT_KEYBOARD);
+ else
+ disable_irq(INT_KEYBOARD);
+ kp_enable = state;
+ }
+ mutex_unlock(&kp_enable_mutex);
+
+ return strnlen(buf, count);
+}
+
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, omap_kp_enable_show, omap_kp_enable_store);
+
+#ifdef CONFIG_PM
+static int omap_kp_suspend(struct platform_device *dev, pm_message_t state)
+{
+ /* Nothing yet */
+
+ return 0;
+}
+
+static int omap_kp_resume(struct platform_device *dev)
+{
+ /* Nothing yet */
+
+ return 0;
+}
+#else
+#define omap_kp_suspend NULL
+#define omap_kp_resume NULL
+#endif
+
+static int __init omap_kp_probe(struct platform_device *pdev)
+{
+ struct omap_kp *omap_kp;
+ struct input_dev *input_dev;
+ struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
+ int i, col_idx, row_idx, irq_idx, ret;
+
+ if (!pdata->rows || !pdata->cols || !pdata->keymap) {
+ printk(KERN_ERR "No rows, cols or keymap from pdata\n");
+ return -EINVAL;
+ }
+
+ omap_kp = kzalloc(sizeof(struct omap_kp), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!omap_kp || !input_dev) {
+ kfree(omap_kp);
+ input_free_device(input_dev);
+ return -ENOMEM;
+ }
+
+ platform_set_drvdata(pdev, omap_kp);
+
+ omap_kp->input = input_dev;
+
+ /* Disable the interrupt for the MPUIO keyboard */
+ if (!cpu_is_omap24xx())
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+
+ keymap = pdata->keymap;
+
+ if (pdata->rep)
+ set_bit(EV_REP, input_dev->evbit);
+
+ if (pdata->delay)
+ omap_kp->delay = pdata->delay;
+
+ if (pdata->row_gpios && pdata->col_gpios) {
+ row_gpios = pdata->row_gpios;
+ col_gpios = pdata->col_gpios;
+ }
+
+ omap_kp->rows = pdata->rows;
+ omap_kp->cols = pdata->cols;
+
+ if (cpu_is_omap24xx()) {
+ /* Cols: outputs */
+ for (col_idx = 0; col_idx < omap_kp->cols; col_idx++) {
+ if (omap_request_gpio(col_gpios[col_idx]) < 0) {
+ printk(KERN_ERR "Failed to request"
+ "GPIO%d for keypad\n",
+ col_gpios[col_idx]);
+ goto err1;
+ }
+ omap_set_gpio_direction(col_gpios[col_idx], 0);
+ }
+ /* Rows: inputs */
+ for (row_idx = 0; row_idx < omap_kp->rows; row_idx++) {
+ if (omap_request_gpio(row_gpios[row_idx]) < 0) {
+ printk(KERN_ERR "Failed to request"
+ "GPIO%d for keypad\n",
+ row_gpios[row_idx]);
+ goto err2;
+ }
+ omap_set_gpio_direction(row_gpios[row_idx], 1);
+ }
+ }
+
+ setup_timer(&omap_kp->timer, omap_kp_timer, (unsigned long)omap_kp);
+
+ /* get the irq and init timer*/
+ tasklet_enable(&kp_tasklet);
+ kp_tasklet.data = (unsigned long) omap_kp;
+
+ ret = device_create_file(&pdev->dev, &dev_attr_enable);
+ if (ret < 0)
+ goto err2;
+
+ /* setup input device */
+ set_bit(EV_KEY, input_dev->evbit);
+ for (i = 0; keymap[i] != 0; i++)
+ set_bit(keymap[i] & KEY_MAX, input_dev->keybit);
+ input_dev->name = "omap-keypad";
+ input_dev->phys = "omap-keypad/input0";
+ input_dev->cdev.dev = &pdev->dev;
+ input_dev->private = omap_kp;
+
+ input_dev->id.bustype = BUS_HOST;
+ input_dev->id.vendor = 0x0001;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+
+ input_dev->keycode = keymap;
+ input_dev->keycodesize = sizeof(unsigned int);
+ input_dev->keycodemax = pdata->keymapsize;
+
+ ret = input_register_device(omap_kp->input);
+ if (ret < 0) {
+ printk(KERN_ERR "Unable to register omap-keypad input device\n");
+ goto err3;
+ }
+
+ if (pdata->dbounce)
+ omap_writew(0xff, OMAP_MPUIO_BASE + OMAP_MPUIO_GPIO_DEBOUNCING);
+
+ /* scan current status and enable interrupt */
+ omap_kp_scan_keypad(omap_kp, keypad_state);
+ if (!cpu_is_omap24xx()) {
+ omap_kp->irq = platform_get_irq(pdev, 0);
+ if (omap_kp->irq >= 0) {
+ if (request_irq(omap_kp->irq, omap_kp_interrupt, 0,
+ "omap-keypad", omap_kp) < 0)
+ goto err4;
+ }
+ omap_writew(0, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ } else {
+ for (irq_idx = 0; irq_idx < omap_kp->rows; irq_idx++) {
+ if (request_irq(OMAP_GPIO_IRQ(row_gpios[irq_idx]),
+ omap_kp_interrupt,
+ IRQF_TRIGGER_FALLING,
+ "omap-keypad", omap_kp) < 0)
+ goto err5;
+ }
+ }
+ return 0;
+err5:
+ for (i = irq_idx-1; i >=0; i--)
+ free_irq(row_gpios[i], 0);
+err4:
+ input_unregister_device(omap_kp->input);
+ input_dev = NULL;
+err3:
+ device_remove_file(&pdev->dev, &dev_attr_enable);
+err2:
+ for (i = row_idx-1; i >=0; i--)
+ omap_free_gpio(row_gpios[i]);
+err1:
+ for (i = col_idx-1; i >=0; i--)
+ omap_free_gpio(col_gpios[i]);
+
+ kfree(omap_kp);
+ input_free_device(input_dev);
+
+ return -EINVAL;
+}
+
+static int omap_kp_remove(struct platform_device *pdev)
+{
+ struct omap_kp *omap_kp = platform_get_drvdata(pdev);
+
+ /* disable keypad interrupt handling */
+ tasklet_disable(&kp_tasklet);
+ if (cpu_is_omap24xx()) {
+ int i;
+ for (i = 0; i < omap_kp->cols; i++)
+ omap_free_gpio(col_gpios[i]);
+ for (i = 0; i < omap_kp->rows; i++) {
+ omap_free_gpio(row_gpios[i]);
+ free_irq(OMAP_GPIO_IRQ(row_gpios[i]), 0);
+ }
+ } else {
+ omap_writew(1, OMAP_MPUIO_BASE + OMAP_MPUIO_KBD_MASKIT);
+ free_irq(omap_kp->irq, 0);
+ }
+
+ del_timer_sync(&omap_kp->timer);
+ tasklet_kill(&kp_tasklet);
+
+ /* unregister everything */
+ input_unregister_device(omap_kp->input);
+
+ kfree(omap_kp);
+
+ return 0;
+}
+
+static struct platform_driver omap_kp_driver = {
+ .probe = omap_kp_probe,
+ .remove = omap_kp_remove,
+ .suspend = omap_kp_suspend,
+ .resume = omap_kp_resume,
+ .driver = {
+ .name = "omap-keypad",
+ },
+};
+
+static int __devinit omap_kp_init(void)
+{
+ printk(KERN_INFO "OMAP Keypad Driver\n");
+ return platform_driver_register(&omap_kp_driver);
+}
+
+static void __exit omap_kp_exit(void)
+{
+ platform_driver_unregister(&omap_kp_driver);
+}
+
+module_init(omap_kp_init);
+module_exit(omap_kp_exit);
+
+MODULE_AUTHOR("Timo Teräs");
+MODULE_DESCRIPTION("OMAP Keypad Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c
index e385710233f4..28b2748e82d0 100644
--- a/drivers/input/keyboard/spitzkbd.c
+++ b/drivers/input/keyboard/spitzkbd.c
@@ -176,7 +176,7 @@ static inline int spitzkbd_get_row_status(int col)
*/
/* Scan the hardware keyboard and push any changes up through the input layer */
-static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs *regs)
+static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data)
{
unsigned int row, col, rowd;
unsigned long flags;
@@ -187,8 +187,6 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs
spin_lock_irqsave(&spitzkbd_data->lock, flags);
- input_regs(spitzkbd_data->input, regs);
-
num_pressed = 0;
for (col = 0; col < KB_COLS; col++) {
/*
@@ -239,14 +237,14 @@ static void spitzkbd_scankeyboard(struct spitzkbd *spitzkbd_data, struct pt_regs
/*
* spitz keyboard interrupt handler.
*/
-static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t spitzkbd_interrupt(int irq, void *dev_id)
{
struct spitzkbd *spitzkbd_data = dev_id;
if (!timer_pending(&spitzkbd_data->timer)) {
/** wait chattering delay **/
udelay(20);
- spitzkbd_scankeyboard(spitzkbd_data, regs);
+ spitzkbd_scankeyboard(spitzkbd_data);
}
return IRQ_HANDLED;
@@ -259,7 +257,7 @@ static void spitzkbd_timer_callback(unsigned long data)
{
struct spitzkbd *spitzkbd_data = (struct spitzkbd *) data;
- spitzkbd_scankeyboard(spitzkbd_data, NULL);
+ spitzkbd_scankeyboard(spitzkbd_data);
}
/*
@@ -267,7 +265,7 @@ static void spitzkbd_timer_callback(unsigned long data)
* We debounce the switches and pass them to the input system.
*/
-static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t spitzkbd_hinge_isr(int irq, void *dev_id)
{
struct spitzkbd *spitzkbd_data = dev_id;
diff --git a/drivers/input/keyboard/stowaway.c b/drivers/input/keyboard/stowaway.c
new file mode 100644
index 000000000000..e60937d17b1c
--- /dev/null
+++ b/drivers/input/keyboard/stowaway.c
@@ -0,0 +1,186 @@
+/*
+ * Stowaway keyboard driver for Linux
+ */
+
+/*
+ * Copyright (c) 2006 Marek Vasut
+ *
+ * Based on Newton keyboard driver for Linux
+ * by Justin Cormack
+ */
+
+/*
+ * 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
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <marek.vasut@gmail.com>, or by paper mail:
+ * Marek Vasut, Liskovecka 559, Frydek-Mistek, 738 01 Czech Republic
+ */
+
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+
+#define DRIVER_DESC "Stowaway keyboard driver"
+
+MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+#define SKBD_KEY_MASK 0x7f
+#define SKBD_RELEASE 0x80
+
+static unsigned char skbd_keycode[128] = {
+ KEY_1, KEY_2, KEY_3, KEY_Z, KEY_4, KEY_5, KEY_6, KEY_7,
+ 0, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_Y, KEY_GRAVE,
+ KEY_X, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_H, KEY_SPACE,
+ KEY_CAPSLOCK, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0,
+ 0, 0, 0, KEY_LEFTALT, 0, 0, 0, 0,
+ 0, 0, 0, 0, KEY_C, KEY_V, KEY_B, KEY_N,
+ KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_HOME, KEY_8, KEY_9, KEY_0, KEY_ESC,
+ KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_BACKSLASH, KEY_END, KEY_U, KEY_I, KEY_O, KEY_P,
+ KEY_APOSTROPHE, KEY_ENTER, KEY_PAGEUP,0, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON,
+ KEY_SLASH, KEY_UP, KEY_PAGEDOWN, 0,KEY_M, KEY_COMMA, KEY_DOT, KEY_INSERT,
+ KEY_DELETE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0,
+ KEY_LEFTSHIFT, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7,
+ KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 0, 0, 0
+};
+
+struct skbd {
+ unsigned char keycode[128];
+ struct input_dev *dev;
+ struct serio *serio;
+ char phys[32];
+};
+
+static irqreturn_t skbd_interrupt(struct serio *serio, unsigned char data,
+ unsigned int flags)
+{
+ struct skbd *skbd = serio_get_drvdata(serio);
+ struct input_dev *dev = skbd->dev;
+
+ if (skbd->keycode[data & SKBD_KEY_MASK]) {
+ input_report_key(dev, skbd->keycode[data & SKBD_KEY_MASK],
+ !(data & SKBD_RELEASE));
+ input_sync(dev);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int skbd_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct skbd *skbd;
+ struct input_dev *input_dev;
+ int err = -ENOMEM;
+ int i;
+
+ skbd = kzalloc(sizeof(struct skbd), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!skbd || !input_dev)
+ goto fail1;
+
+ skbd->serio = serio;
+ skbd->dev = input_dev;
+ snprintf(skbd->phys, sizeof(skbd->phys), "%s/input0", serio->phys);
+ memcpy(skbd->keycode, skbd_keycode, sizeof(skbd->keycode));
+
+ input_dev->name = "Stowaway Keyboard";
+ input_dev->phys = skbd->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_STOWAWAY;
+ input_dev->id.product = 0x0001;
+ input_dev->id.version = 0x0100;
+ input_dev->cdev.dev = &serio->dev;
+ input_dev->private = skbd;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+ input_dev->keycode = skbd->keycode;
+ input_dev->keycodesize = sizeof(unsigned char);
+ input_dev->keycodemax = ARRAY_SIZE(skbd_keycode);
+ for (i = 0; i < ARRAY_SIZE(skbd_keycode); i++)
+ set_bit(skbd_keycode[i], input_dev->keybit);
+ clear_bit(0, input_dev->keybit);
+
+ serio_set_drvdata(serio, skbd);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(skbd->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(skbd);
+ return err;
+}
+
+static void skbd_disconnect(struct serio *serio)
+{
+ struct skbd *skbd = serio_get_drvdata(serio);
+
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_unregister_device(skbd->dev);
+ kfree(skbd);
+}
+
+static struct serio_device_id skbd_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_STOWAWAY,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, skbd_serio_ids);
+
+static struct serio_driver skbd_drv = {
+ .driver = {
+ .name = "stowaway",
+ },
+ .description = DRIVER_DESC,
+ .id_table = skbd_serio_ids,
+ .interrupt = skbd_interrupt,
+ .connect = skbd_connect,
+ .disconnect = skbd_disconnect,
+};
+
+static int __init skbd_init(void)
+{
+ serio_register_driver(&skbd_drv);
+ return 0;
+}
+
+static void __exit skbd_exit(void)
+{
+ serio_unregister_driver(&skbd_drv);
+}
+
+module_init(skbd_init);
+module_exit(skbd_exit);
diff --git a/drivers/input/keyboard/sunkbd.c b/drivers/input/keyboard/sunkbd.c
index 9dbd7b85686d..cac4781103c3 100644
--- a/drivers/input/keyboard/sunkbd.c
+++ b/drivers/input/keyboard/sunkbd.c
@@ -94,7 +94,7 @@ struct sunkbd {
*/
static irqreturn_t sunkbd_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct sunkbd* sunkbd = serio_get_drvdata(serio);
@@ -129,7 +129,6 @@ static irqreturn_t sunkbd_interrupt(struct serio *serio,
break;
if (sunkbd->keycode[data & SUNKBD_KEY]) {
- input_regs(sunkbd->dev, regs);
input_report_key(sunkbd->dev, sunkbd->keycode[data & SUNKBD_KEY], !(data & SUNKBD_RELEASE));
input_sync(sunkbd->dev);
} else {
diff --git a/drivers/input/keyboard/xtkbd.c b/drivers/input/keyboard/xtkbd.c
index 0821d53cf0c1..8c11dc935454 100644
--- a/drivers/input/keyboard/xtkbd.c
+++ b/drivers/input/keyboard/xtkbd.c
@@ -64,7 +64,7 @@ struct xtkbd {
};
static irqreturn_t xtkbd_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct xtkbd *xtkbd = serio_get_drvdata(serio);
@@ -75,7 +75,6 @@ static irqreturn_t xtkbd_interrupt(struct serio *serio,
default:
if (xtkbd->keycode[data & XTKBD_KEY]) {
- input_regs(xtkbd->dev, regs);
input_report_key(xtkbd->dev, xtkbd->keycode[data & XTKBD_KEY], !(data & XTKBD_RELEASE));
input_sync(xtkbd->dev);
} else {
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index a6dfc7455733..ba0e88c64e1e 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -73,7 +73,7 @@ config INPUT_UINPUT
config HP_SDC_RTC
tristate "HP SDC Real Time Clock"
- depends on GSC
+ depends on GSC || HP300
select HP_SDC
help
Say Y here if you want to support the built-in real time clock
diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c
index 1be963961c15..ab4da79ee560 100644
--- a/drivers/input/misc/hp_sdc_rtc.c
+++ b/drivers/input/misc/hp_sdc_rtc.c
@@ -60,7 +60,7 @@ static struct fasync_struct *hp_sdc_rtc_async_queue;
static DECLARE_WAIT_QUEUE_HEAD(hp_sdc_rtc_wait);
-static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
+static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos);
static int hp_sdc_rtc_ioctl(struct inode *inode, struct file *file,
@@ -385,14 +385,14 @@ static int hp_sdc_rtc_set_i8042timer (struct timeval *setto, uint8_t setcmd)
return 0;
}
-static ssize_t hp_sdc_rtc_read(struct file *file, char *buf,
+static ssize_t hp_sdc_rtc_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos) {
ssize_t retval;
if (count < sizeof(unsigned long))
return -EINVAL;
- retval = put_user(68, (unsigned long *)buf);
+ retval = put_user(68, (unsigned long __user *)buf);
return retval;
}
@@ -696,7 +696,7 @@ static int __init hp_sdc_rtc_init(void)
if ((ret = hp_sdc_request_timer_irq(&hp_sdc_rtc_isr)))
return ret;
misc_register(&hp_sdc_rtc_dev);
- create_proc_read_entry ("driver/rtc", 0, 0,
+ create_proc_read_entry ("driver/rtc", 0, NULL,
hp_sdc_rtc_read_proc, NULL);
printk(KERN_INFO "HP i8042 SDC + MSM-58321 RTC support loaded "
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
index 805b636e73d9..105c6fc27823 100644
--- a/drivers/input/misc/ixp4xx-beeper.c
+++ b/drivers/input/misc/ixp4xx-beeper.c
@@ -79,7 +79,7 @@ static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned
return 0;
}
-static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
{
/* clear interrupt */
*IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index d723e9ad7c41..9516439b7c78 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -20,6 +20,9 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
+ * 0.3 09/04/2006 (Anssi Hannula <anssi.hannula@gmail.com>)
+ * - updated ff support for the changes in kernel interface
+ * - added MODULE_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>)
* - added force feedback support
* - added UI_SET_PHYS
@@ -107,18 +110,31 @@ static int uinput_request_submit(struct input_dev *dev, struct uinput_request *r
return request->retval;
}
-static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect)
+static void uinput_dev_set_gain(struct input_dev *dev, u16 gain)
+{
+ uinput_dev_event(dev, EV_FF, FF_GAIN, gain);
+}
+
+static void uinput_dev_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+ uinput_dev_event(dev, EV_FF, FF_AUTOCENTER, magnitude);
+}
+
+static int uinput_dev_playback(struct input_dev *dev, int effect_id, int value)
+{
+ return uinput_dev_event(dev, EV_FF, effect_id, value);
+}
+
+static int uinput_dev_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{
struct uinput_request request;
int retval;
- if (!test_bit(EV_FF, dev->evbit))
- return -ENOSYS;
-
request.id = -1;
init_completion(&request.done);
request.code = UI_FF_UPLOAD;
- request.u.effect = effect;
+ request.u.upload.effect = effect;
+ request.u.upload.old = old;
retval = uinput_request_reserve_slot(dev->private, &request);
if (!retval)
@@ -168,6 +184,7 @@ static void uinput_destroy_device(struct uinput_device *udev)
static int uinput_create_device(struct uinput_device *udev)
{
+ struct input_dev *dev = udev->dev;
int error;
if (udev->state != UIST_SETUP_COMPLETE) {
@@ -175,15 +192,29 @@ static int uinput_create_device(struct uinput_device *udev)
return -EINVAL;
}
- error = input_register_device(udev->dev);
- if (error) {
- uinput_destroy_device(udev);
- return error;
+ if (udev->ff_effects_max) {
+ error = input_ff_create(dev, udev->ff_effects_max);
+ if (error)
+ goto fail1;
+
+ dev->ff->upload = uinput_dev_upload_effect;
+ dev->ff->erase = uinput_dev_erase_effect;
+ dev->ff->playback = uinput_dev_playback;
+ dev->ff->set_gain = uinput_dev_set_gain;
+ dev->ff->set_autocenter = uinput_dev_set_autocenter;
}
+ error = input_register_device(udev->dev);
+ if (error)
+ goto fail2;
+
udev->state = UIST_CREATED;
return 0;
+
+ fail2: input_ff_destroy(dev);
+ fail1: uinput_destroy_device(udev);
+ return error;
}
static int uinput_open(struct inode *inode, struct file *file)
@@ -243,8 +274,6 @@ static int uinput_allocate_device(struct uinput_device *udev)
return -ENOMEM;
udev->dev->event = uinput_dev_event;
- udev->dev->upload_effect = uinput_dev_upload_effect;
- udev->dev->erase_effect = uinput_dev_erase_effect;
udev->dev->private = udev;
return 0;
@@ -278,6 +307,8 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
goto exit;
}
+ udev->ff_effects_max = user_dev->ff_effects_max;
+
size = strnlen(user_dev->name, UINPUT_MAX_NAME_SIZE) + 1;
if (!size) {
retval = -EINVAL;
@@ -296,7 +327,6 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
dev->id.vendor = user_dev->id.vendor;
dev->id.product = user_dev->id.product;
dev->id.version = user_dev->id.version;
- dev->ff_effects_max = user_dev->ff_effects_max;
size = sizeof(int) * (ABS_MAX + 1);
memcpy(dev->absmax, user_dev->absmax, size);
@@ -525,12 +555,17 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
req = uinput_request_find(udev, ff_up.request_id);
- if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
+ if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
retval = -EINVAL;
break;
}
ff_up.retval = 0;
- memcpy(&ff_up.effect, req->u.effect, sizeof(struct ff_effect));
+ memcpy(&ff_up.effect, req->u.upload.effect, sizeof(struct ff_effect));
+ if (req->u.upload.old)
+ memcpy(&ff_up.old, req->u.upload.old, sizeof(struct ff_effect));
+ else
+ memset(&ff_up.old, 0, sizeof(struct ff_effect));
+
if (copy_to_user(p, &ff_up, sizeof(ff_up))) {
retval = -EFAULT;
break;
@@ -561,12 +596,11 @@ static long uinput_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
break;
}
req = uinput_request_find(udev, ff_up.request_id);
- if (!(req && req->code == UI_FF_UPLOAD && req->u.effect)) {
+ if (!(req && req->code == UI_FF_UPLOAD && req->u.upload.effect)) {
retval = -EINVAL;
break;
}
req->retval = ff_up.retval;
- memcpy(req->u.effect, &ff_up.effect, sizeof(struct ff_effect));
uinput_request_done(udev, req);
break;
@@ -622,6 +656,7 @@ static void __exit uinput_exit(void)
MODULE_AUTHOR("Aristeu Sergio Rozanski Filho");
MODULE_DESCRIPTION("User level driver support for input subsystem");
MODULE_LICENSE("GPL");
+MODULE_VERSION("0.3");
module_init(uinput_init);
module_exit(uinput_exit);
diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c
index de0f46dd9692..7b9d1c1da41a 100644
--- a/drivers/input/misc/wistron_btns.c
+++ b/drivers/input/misc/wistron_btns.c
@@ -17,7 +17,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
*/
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/dmi.h>
#include <linux/init.h>
#include <linux/input.h>
@@ -248,13 +248,10 @@ static int __init dmi_matched(struct dmi_system_id *dmi)
keymap = dmi->driver_data;
for (key = keymap; key->type != KE_END; key++) {
- if (key->type == KE_WIFI) {
+ if (key->type == KE_WIFI)
have_wifi = 1;
- break;
- } else if (key->type == KE_BLUETOOTH) {
+ else if (key->type == KE_BLUETOOTH)
have_bluetooth = 1;
- break;
- }
}
return 1;
}
@@ -389,7 +386,16 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
.driver_data = keymap_acer_travelmate_240
},
- {
+ {
+ .callback = dmi_matched,
+ .ident = "Acer TravelMate 2424NWXCi",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
+ },
+ .driver_data = keymap_acer_travelmate_240
+ },
+ {
.callback = dmi_matched,
.ident = "AOpen 1559AS",
.matches = {
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index f15ccf781688..35d998c3e578 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -119,7 +119,7 @@ config MOUSE_VSXXXAA
config MOUSE_HIL
tristate "HIL pointers (mice etc)."
- depends on GSC
+ depends on GSC || HP300
select HP_SDC
select HIL_MLC
help
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 070d75330afd..4e71a66fc7fc 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -36,7 +36,7 @@
#define ALPS_PASS 0x20
#define ALPS_FW_BK_2 0x40
-static struct alps_model_info alps_model_data[] = {
+static const struct alps_model_info alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
{ { 0x53, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
{ { 0x53, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
@@ -76,7 +76,7 @@ static struct alps_model_info alps_model_data[] = {
* on a dualpoint, etc.
*/
-static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
+static void alps_process_packet(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
@@ -85,8 +85,6 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
int x, y, z, ges, fin, left, right, middle;
int back = 0, forward = 0;
- input_regs(dev, regs);
-
if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */
input_report_key(dev2, BTN_LEFT, packet[0] & 1);
input_report_key(dev2, BTN_RIGHT, packet[0] & 2);
@@ -181,13 +179,13 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
input_sync(dev);
}
-static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
if (psmouse->pktcnt == 3) {
- alps_process_packet(psmouse, regs);
+ alps_process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
return PSMOUSE_GOOD_DATA;
@@ -202,17 +200,17 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse, struct pt_regs *
return PSMOUSE_BAD_DATA;
if (psmouse->pktcnt == 6) {
- alps_process_packet(psmouse, regs);
+ alps_process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
return PSMOUSE_GOOD_DATA;
}
-static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
+static const struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *version)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
+ static const unsigned char rates[] = { 0, 10, 20, 40, 60, 80, 100, 200 };
unsigned char param[4];
int i;
@@ -504,7 +502,7 @@ init_fail:
int alps_detect(struct psmouse *psmouse, int set_properties)
{
int version;
- struct alps_model_info *model;
+ const struct alps_model_info *model;
if (!(model = alps_get_model(psmouse, &version)))
return -1;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index e428f8d5d12e..69db7325a494 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -25,7 +25,7 @@ struct alps_data {
struct input_dev *dev2; /* Relative device */
char name[32]; /* Name */
char phys[32]; /* Phys */
- struct alps_model_info *i; /* Info */
+ const struct alps_model_info *i;/* Info */
int prev_fin; /* Finger bit from previous packet */
};
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index c8b2cc9f184c..599a7b2dc519 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
static int amimouse_lastx, amimouse_lasty;
static struct input_dev *amimouse_dev;
-static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t amimouse_interrupt(int irq, void *dummy)
{
unsigned short joy0dat, potgor;
int nx, ny, dx, dy;
@@ -59,8 +59,6 @@ static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
potgor = amiga_custom.potgor;
- input_regs(amimouse_dev, fp);
-
input_report_rel(amimouse_dev, REL_X, dx);
input_report_rel(amimouse_dev, REL_Y, dy);
diff --git a/drivers/input/mouse/hil_ptr.c b/drivers/input/mouse/hil_ptr.c
index 69f02178c528..4f2b503c1ac7 100644
--- a/drivers/input/mouse/hil_ptr.c
+++ b/drivers/input/mouse/hil_ptr.c
@@ -190,7 +190,7 @@ static void hil_ptr_process_err(struct hil_ptr *ptr) {
}
static irqreturn_t hil_ptr_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct hil_ptr *ptr;
hil_packet packet;
@@ -375,7 +375,7 @@ static int hil_ptr_connect(struct serio *serio, struct serio_driver *driver)
ptr->dev->id.vendor = PCI_VENDOR_ID_HP;
ptr->dev->id.product = 0x0001; /* TODO: get from ptr->rsc */
ptr->dev->id.version = 0x0100; /* TODO: get from ptr->rsc */
- ptr->dev->dev = &serio->dev;
+ ptr->dev->cdev.dev = &serio->dev;
input_register_device(ptr->dev);
printk(KERN_INFO "input: %s (%s), ID: %d\n",
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index 50f1fed10be4..e1252fa9a107 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -88,15 +88,13 @@ __obsolete_setup("inport_irq=");
static struct input_dev *inport_dev;
-static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t inport_interrupt(int irq, void *dev_id)
{
unsigned char buttons;
outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
outb(INPORT_MODE_HOLD | INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
- input_regs(inport_dev, regs);
-
outb(INPORT_REG_X, INPORT_CONTROL_PORT);
input_report_rel(inport_dev, REL_X, inb(INPORT_DATA_PORT));
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
index c14395ba7980..c57e8853b949 100644
--- a/drivers/input/mouse/lifebook.c
+++ b/drivers/input/mouse/lifebook.c
@@ -62,7 +62,7 @@ static struct dmi_system_id lifebook_dmi_table[] = {
};
-static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse)
{
unsigned char *packet = psmouse->packet;
struct input_dev *dev = psmouse->dev;
@@ -70,8 +70,6 @@ static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_re
if (psmouse->pktcnt != 3)
return PSMOUSE_GOOD_DATA;
- input_regs(dev, regs);
-
/* calculate X and Y */
if ((packet[0] & 0x08) == 0x00) {
input_report_abs(dev, ABS_X,
@@ -115,13 +113,15 @@ static int lifebook_absolute_mode(struct psmouse *psmouse)
static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
- unsigned char params[] = { 0, 1, 2, 2, 3 };
+ static const unsigned char params[] = { 0, 1, 2, 2, 3 };
+ unsigned char p;
if (resolution == 0 || resolution > 400)
resolution = 400;
- ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
- psmouse->resolution = 50 << params[resolution / 100];
+ p = params[resolution / 100];
+ ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
+ psmouse->resolution = 50 << p;
}
static void lifebook_disconnect(struct psmouse *psmouse)
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index 9c7ce38806d7..8e9c2f3d69a8 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -79,7 +79,7 @@ __obsolete_setup("logibm_irq=");
static struct input_dev *logibm_dev;
-static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t logibm_interrupt(int irq, void *dev_id)
{
char dx, dy;
unsigned char buttons;
@@ -95,7 +95,6 @@ static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dy |= (buttons & 0xf) << 4;
buttons = ~buttons >> 5;
- input_regs(logibm_dev, regs);
input_report_rel(logibm_dev, REL_X, dx);
input_report_rel(logibm_dev, REL_Y, dy);
input_report_key(logibm_dev, BTN_RIGHT, buttons & 1);
diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c
index 54b696cfe1e3..8a4f862709e7 100644
--- a/drivers/input/mouse/logips2pp.c
+++ b/drivers/input/mouse/logips2pp.c
@@ -30,16 +30,16 @@
#define PS2PP_NAV_BTN 0x20
struct ps2pp_info {
- const int model;
- unsigned const int kind;
- unsigned const int features;
+ u8 model;
+ u8 kind;
+ u16 features;
};
/*
* Process a PS2++ or PS2T++ packet.
*/
-static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
@@ -51,8 +51,6 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse, struct pt_regs
* Full packet accumulated, process it
*/
- input_regs(dev, regs);
-
if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) {
/* Logitech extended packet */
@@ -199,9 +197,9 @@ static void ps2pp_disconnect(struct psmouse *psmouse)
device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr);
}
-static struct ps2pp_info *get_model_info(unsigned char model)
+static const struct ps2pp_info *get_model_info(unsigned char model)
{
- static struct ps2pp_info ps2pp_list[] = {
+ static const struct ps2pp_info ps2pp_list[] = {
{ 12, 0, PS2PP_SIDE_BTN},
{ 13, 0, 0 },
{ 15, PS2PP_KIND_MX, /* MX1000 */
@@ -215,6 +213,7 @@ static struct ps2pp_info *get_model_info(unsigned char model)
{ 51, 0, 0 },
{ 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL },
{ 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL },
+ { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */
{ 61, PS2PP_KIND_MX, /* MX700 */
PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN |
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
@@ -244,12 +243,11 @@ static struct ps2pp_info *get_model_info(unsigned char model)
PS2PP_EXTRA_BTN | PS2PP_NAV_BTN },
{ 114, PS2PP_KIND_MX, /* MX310 */
PS2PP_WHEEL | PS2PP_SIDE_BTN |
- PS2PP_TASK_BTN | PS2PP_EXTRA_BTN },
- { }
+ PS2PP_TASK_BTN | PS2PP_EXTRA_BTN }
};
int i;
- for (i = 0; ps2pp_list[i].model; i++)
+ for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++)
if (model == ps2pp_list[i].model)
return &ps2pp_list[i];
@@ -261,7 +259,8 @@ static struct ps2pp_info *get_model_info(unsigned char model)
* Set up input device's properties based on the detected mouse model.
*/
-static void ps2pp_set_model_properties(struct psmouse *psmouse, struct ps2pp_info *model_info,
+static void ps2pp_set_model_properties(struct psmouse *psmouse,
+ const struct ps2pp_info *model_info,
int using_ps2pp)
{
struct input_dev *input_dev = psmouse->dev;
@@ -327,7 +326,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[4];
unsigned char model, buttons;
- struct ps2pp_info *model_info;
+ const struct ps2pp_info *model_info;
int use_ps2pp = 0;
param[0] = 0;
@@ -349,7 +348,7 @@ int ps2pp_init(struct psmouse *psmouse, int set_properties)
/*
* Do Logitech PS2++ / PS2T++ magic init.
*/
- if (model == 97) { /* Touch Pad 3 */
+ if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */
/* Unprotect RAM */
param[0] = 0x11; param[1] = 0x04; param[2] = 0x68;
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index d284ea712151..8c075aa7223b 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -57,7 +57,7 @@ static struct input_dev *pc110pad_dev;
static int pc110pad_data[3];
static int pc110pad_count;
-static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t pc110pad_interrupt(int irq, void *ptr)
{
int value = inb_p(pc110pad_io);
int handshake = inb_p(pc110pad_io + 2);
@@ -71,7 +71,6 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
if (pc110pad_count < 3)
return IRQ_HANDLED;
- input_regs(pc110pad_dev, regs);
input_report_key(pc110pad_dev, BTN_TOUCH,
pc110pad_data[0] & 0x01);
input_report_abs(pc110pad_dev, ABS_X,
@@ -91,9 +90,9 @@ static void pc110pad_close(struct input_dev *dev)
static int pc110pad_open(struct input_dev *dev)
{
- pc110pad_interrupt(0, NULL, NULL);
- pc110pad_interrupt(0, NULL, NULL);
- pc110pad_interrupt(0, NULL, NULL);
+ pc110pad_interrupt(0, NULL);
+ pc110pad_interrupt(0, NULL);
+ pc110pad_interrupt(0, NULL);
outb(PC110PAD_ON, pc110pad_io + 2);
pc110pad_count = 0;
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 343afa38f4c2..6f9b2c7cc9c2 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -112,8 +112,8 @@ static struct workqueue_struct *kpsmoused_wq;
struct psmouse_protocol {
enum psmouse_type type;
- char *name;
- char *alias;
+ const char *name;
+ const char *alias;
int maxproto;
int (*detect)(struct psmouse *, int);
int (*init)(struct psmouse *);
@@ -124,7 +124,7 @@ struct psmouse_protocol {
* relevant events to the input module once full packet has arrived.
*/
-static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
@@ -136,8 +136,6 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse, struct pt_reg
* Full packet accumulated, process it
*/
- input_regs(dev, regs);
-
/*
* Scroll wheel on IntelliMice, scroll buttons on NetMice
*/
@@ -231,9 +229,9 @@ static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_st
* by calling corresponding protocol handler.
*/
-static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static int psmouse_handle_byte(struct psmouse *psmouse)
{
- psmouse_ret_t rc = psmouse->protocol_handler(psmouse, regs);
+ psmouse_ret_t rc = psmouse->protocol_handler(psmouse);
switch (rc) {
case PSMOUSE_BAD_DATA:
@@ -271,7 +269,7 @@ static int psmouse_handle_byte(struct psmouse *psmouse, struct pt_regs *regs)
*/
static irqreturn_t psmouse_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct psmouse *psmouse = serio_get_drvdata(serio);
@@ -327,7 +325,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
* Not a new device, try processing first byte normally
*/
psmouse->pktcnt = 1;
- if (psmouse_handle_byte(psmouse, regs))
+ if (psmouse_handle_byte(psmouse))
goto out;
psmouse->packet[psmouse->pktcnt++] = data;
@@ -346,7 +344,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
}
psmouse->last = jiffies;
- psmouse_handle_byte(psmouse, regs);
+ psmouse_handle_byte(psmouse);
out:
return IRQ_HANDLED;
@@ -507,15 +505,17 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[2];
- unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20, 0 };
+ static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 };
int i;
param[0] = 10;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
param[0] = 0;
ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES);
- for (i = 0; seq[i]; i++)
- ps2_command(ps2dev, seq + i, PSMOUSE_CMD_SETRATE);
+ for (i = 0; i < ARRAY_SIZE(seq); i++) {
+ param[0] = seq[i];
+ ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE);
+ }
ps2_command(ps2dev, param, PSMOUSE_CMD_GETID);
if (param[0] != 2)
@@ -652,7 +652,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_PS2;
}
-static struct psmouse_protocol psmouse_protocols[] = {
+static const struct psmouse_protocol psmouse_protocols[] = {
{
.type = PSMOUSE_PS2,
.name = "PS/2",
@@ -726,7 +726,7 @@ static struct psmouse_protocol psmouse_protocols[] = {
},
};
-static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
{
int i;
@@ -738,9 +738,9 @@ static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
return &psmouse_protocols[0];
}
-static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
+static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
{
- struct psmouse_protocol *p;
+ const struct psmouse_protocol *p;
int i;
for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
@@ -795,13 +795,15 @@ static int psmouse_probe(struct psmouse *psmouse)
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
{
- unsigned char params[] = { 0, 1, 2, 2, 3 };
+ static const unsigned char params[] = { 0, 1, 2, 2, 3 };
+ unsigned char p;
if (resolution == 0 || resolution > 200)
resolution = 200;
- ps2_command(&psmouse->ps2dev, &params[resolution / 50], PSMOUSE_CMD_SETRES);
- psmouse->resolution = 25 << params[resolution / 50];
+ p = params[resolution / 50];
+ ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES);
+ psmouse->resolution = 25 << p;
}
/*
@@ -810,12 +812,14 @@ void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution)
static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate)
{
- unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
+ static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 };
+ unsigned char r;
int i = 0;
while (rates[i] > rate) i++;
- ps2_command(&psmouse->ps2dev, &rates[i], PSMOUSE_CMD_SETRATE);
- psmouse->rate = rates[i];
+ r = rates[i];
+ ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE);
+ psmouse->rate = r;
}
/*
@@ -934,7 +938,7 @@ static void psmouse_resync(void *p)
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
for (i = 0; i < psmouse->pktsize; i++) {
psmouse->pktcnt++;
- rc = psmouse->protocol_handler(psmouse, NULL);
+ rc = psmouse->protocol_handler(psmouse);
if (rc != PSMOUSE_GOOD_DATA)
break;
}
@@ -1031,7 +1035,7 @@ static void psmouse_disconnect(struct serio *serio)
mutex_unlock(&psmouse_mutex);
}
-static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
+static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto)
{
struct input_dev *input_dev = psmouse->dev;
@@ -1362,7 +1366,7 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
struct serio *serio = psmouse->ps2dev.serio;
struct psmouse *parent = NULL;
struct input_dev *new_dev;
- struct psmouse_protocol *proto;
+ const struct psmouse_protocol *proto;
int retry = 0;
if (!(proto = psmouse_protocol_by_name(buf, count)))
@@ -1459,7 +1463,7 @@ static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data,
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
{
- struct psmouse_protocol *proto;
+ const struct psmouse_protocol *proto;
if (!val)
return -EINVAL;
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 4d9107fba6a1..1b74cae8a556 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -62,7 +62,7 @@ struct psmouse {
unsigned int resync_time;
unsigned int smartscroll; /* Logitech only */
- psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse, struct pt_regs *regs);
+ psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse);
void (*set_rate)(struct psmouse *psmouse, unsigned int rate);
void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 872b30bf7aad..ea0468569610 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -36,7 +36,7 @@ MODULE_LICENSE("GPL");
static short rpcmouse_lastx, rpcmouse_lasty;
static struct input_dev *rpcmouse_dev;
-static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpcmouse_irq(int irq, void *dev_id)
{
struct input_dev *dev = dev_id;
short x, y, dx, dy, b;
@@ -51,8 +51,6 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
rpcmouse_lastx = x;
rpcmouse_lasty = y;
- input_regs(dev, regs);
-
input_report_rel(dev, REL_X, dx);
input_report_rel(dev, REL_Y, -dy);
diff --git a/drivers/input/mouse/sermouse.c b/drivers/input/mouse/sermouse.c
index 0023501a5b63..2a272c5daf08 100644
--- a/drivers/input/mouse/sermouse.c
+++ b/drivers/input/mouse/sermouse.c
@@ -42,7 +42,7 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-static char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
+static const char *sermouse_protocols[] = { "None", "Mouse Systems Mouse", "Sun Mouse", "Microsoft Mouse",
"Logitech M+ Mouse", "Microsoft MZ Mouse", "Logitech MZ+ Mouse",
"Logitech MZ++ Mouse"};
@@ -61,13 +61,11 @@ struct sermouse {
* second, which is as good as a PS/2 or USB mouse.
*/
-static void sermouse_process_msc(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
+static void sermouse_process_msc(struct sermouse *sermouse, signed char data)
{
struct input_dev *dev = sermouse->dev;
signed char *buf = sermouse->buf;
- input_regs(dev, regs);
-
switch (sermouse->count) {
case 0:
@@ -104,15 +102,13 @@ static void sermouse_process_msc(struct sermouse *sermouse, signed char data, st
* standard 3-byte packets and 1200 bps.
*/
-static void sermouse_process_ms(struct sermouse *sermouse, signed char data, struct pt_regs *regs)
+static void sermouse_process_ms(struct sermouse *sermouse, signed char data)
{
struct input_dev *dev = sermouse->dev;
signed char *buf = sermouse->buf;
if (data & 0x40) sermouse->count = 0;
- input_regs(dev, regs);
-
switch (sermouse->count) {
case 0:
@@ -206,7 +202,7 @@ static void sermouse_process_ms(struct sermouse *sermouse, signed char data, str
*/
static irqreturn_t sermouse_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct sermouse *sermouse = serio_get_drvdata(serio);
@@ -214,9 +210,9 @@ static irqreturn_t sermouse_interrupt(struct serio *serio,
sermouse->last = jiffies;
if (sermouse->type > SERIO_SUN)
- sermouse_process_ms(sermouse, data, regs);
+ sermouse_process_ms(sermouse, data);
else
- sermouse_process_msc(sermouse, data, regs);
+ sermouse_process_msc(sermouse, data);
return IRQ_HANDLED;
}
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index ad5d0a85e960..49ac696d6cff 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -216,13 +216,13 @@ static void synaptics_pass_pt_packet(struct serio *ptport, unsigned char *packet
struct psmouse *child = serio_get_drvdata(ptport);
if (child && child->state == PSMOUSE_ACTIVATED) {
- serio_interrupt(ptport, packet[1], 0, NULL);
- serio_interrupt(ptport, packet[4], 0, NULL);
- serio_interrupt(ptport, packet[5], 0, NULL);
+ serio_interrupt(ptport, packet[1], 0);
+ serio_interrupt(ptport, packet[4], 0);
+ serio_interrupt(ptport, packet[5], 0);
if (child->pktsize == 4)
- serio_interrupt(ptport, packet[2], 0, NULL);
+ serio_interrupt(ptport, packet[2], 0);
} else
- serio_interrupt(ptport, packet[1], 0, NULL);
+ serio_interrupt(ptport, packet[1], 0);
}
static void synaptics_pt_activate(struct psmouse *psmouse)
@@ -430,11 +430,11 @@ static void synaptics_process_packet(struct psmouse *psmouse)
static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned char pkt_type)
{
- static unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
- static unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
- static unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
- static unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
- static unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
+ static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 };
+ static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 };
+ static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 };
+ static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 };
+ static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 };
if (idx < 0 || idx > 4)
return 0;
@@ -469,13 +469,10 @@ static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse)
return SYN_NEWABS_STRICT;
}
-static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse)
{
- struct input_dev *dev = psmouse->dev;
struct synaptics_data *priv = psmouse->private;
- input_regs(dev, regs);
-
if (psmouse->pktcnt >= 6) { /* Full packet received */
if (unlikely(priv->pkt_type == SYN_NEWABS))
priv->pkt_type = synaptics_detect_pkt_type(psmouse);
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index 47edcfd022ba..ffdb50eee93d 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -211,7 +211,7 @@ vsxxxaa_smells_like_packet (struct vsxxxaa *mouse, unsigned char type, size_t le
}
static void
-vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
+vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse)
{
struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf;
@@ -258,7 +258,6 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
/*
* Report what we've found so far...
*/
- input_regs (dev, regs);
input_report_key (dev, BTN_LEFT, left);
input_report_key (dev, BTN_MIDDLE, middle);
input_report_key (dev, BTN_RIGHT, right);
@@ -269,7 +268,7 @@ vsxxxaa_handle_REL_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
}
static void
-vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
+vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse)
{
struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf;
@@ -312,7 +311,6 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
/*
* Report what we've found so far...
*/
- input_regs (dev, regs);
input_report_key (dev, BTN_LEFT, left);
input_report_key (dev, BTN_MIDDLE, middle);
input_report_key (dev, BTN_RIGHT, right);
@@ -323,7 +321,7 @@ vsxxxaa_handle_ABS_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
}
static void
-vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
+vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse)
{
struct input_dev *dev = mouse->dev;
unsigned char *buf = mouse->buf;
@@ -367,7 +365,6 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
if (error <= 0x1f) {
/* No (serious) error. Report buttons */
- input_regs (dev, regs);
input_report_key (dev, BTN_LEFT, left);
input_report_key (dev, BTN_MIDDLE, middle);
input_report_key (dev, BTN_RIGHT, right);
@@ -395,7 +392,7 @@ vsxxxaa_handle_POR_packet (struct vsxxxaa *mouse, struct pt_regs *regs)
}
static void
-vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
+vsxxxaa_parse_buffer (struct vsxxxaa *mouse)
{
unsigned char *buf = mouse->buf;
int stray_bytes;
@@ -432,7 +429,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
continue;
}
- vsxxxaa_handle_REL_packet (mouse, regs);
+ vsxxxaa_handle_REL_packet (mouse);
continue; /* More to parse? */
}
@@ -446,7 +443,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
continue;
}
- vsxxxaa_handle_ABS_packet (mouse, regs);
+ vsxxxaa_handle_ABS_packet (mouse);
continue; /* More to parse? */
}
@@ -460,7 +457,7 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
continue;
}
- vsxxxaa_handle_POR_packet (mouse, regs);
+ vsxxxaa_handle_POR_packet (mouse);
continue; /* More to parse? */
}
@@ -469,13 +466,12 @@ vsxxxaa_parse_buffer (struct vsxxxaa *mouse, struct pt_regs *regs)
}
static irqreturn_t
-vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags,
- struct pt_regs *regs)
+vsxxxaa_interrupt (struct serio *serio, unsigned char data, unsigned int flags)
{
struct vsxxxaa *mouse = serio_get_drvdata (serio);
vsxxxaa_queue_byte (mouse, data);
- vsxxxaa_parse_buffer (mouse, regs);
+ vsxxxaa_parse_buffer (mouse);
return IRQ_HANDLED;
}
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 1f851acab30d..a22a74a2a3dc 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -614,7 +614,7 @@ static unsigned int mousedev_poll(struct file *file, poll_table *wait)
(list->mousedev->exist ? 0 : (POLLHUP | POLLERR));
}
-static struct file_operations mousedev_fops = {
+static const struct file_operations mousedev_fops = {
.owner = THIS_MODULE,
.read = mousedev_read,
.write = mousedev_write,
@@ -624,7 +624,8 @@ static struct file_operations mousedev_fops = {
.fasync = mousedev_fasync,
};
-static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id)
+static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev,
+ const struct input_device_id *id)
{
struct mousedev *mousedev;
struct class_device *cdev;
@@ -688,7 +689,7 @@ static void mousedev_disconnect(struct input_handle *handle)
}
}
-static struct input_device_id mousedev_ids[] = {
+static const struct input_device_id mousedev_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
@@ -737,7 +738,12 @@ static int psaux_registered;
static int __init mousedev_init(void)
{
- input_register_handler(&mousedev_handler);
+ struct class_device *cdev;
+ int error;
+
+ error = input_register_handler(&mousedev_handler);
+ if (error)
+ return error;
memset(&mousedev_mix, 0, sizeof(struct mousedev));
INIT_LIST_HEAD(&mousedev_mix.list);
@@ -746,12 +752,20 @@ static int __init mousedev_init(void)
mousedev_mix.exist = 1;
mousedev_mix.minor = MOUSEDEV_MIX;
- class_device_create(&input_class, NULL,
+ cdev = class_device_create(&input_class, NULL,
MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX), NULL, "mice");
+ if (IS_ERR(cdev)) {
+ input_unregister_handler(&mousedev_handler);
+ return PTR_ERR(cdev);
+ }
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
- if (!(psaux_registered = !misc_register(&psaux_mouse)))
- printk(KERN_WARNING "mice: could not misc_register the device\n");
+ error = misc_register(&psaux_mouse);
+ if (error)
+ printk(KERN_WARNING "mice: could not register psaux device, "
+ "error: %d\n", error);
+ else
+ psaux_registered = 1;
#endif
printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n");
diff --git a/drivers/input/power.c b/drivers/input/power.c
index 51a519e24b6d..ee82464a2fa7 100644
--- a/drivers/input/power.c
+++ b/drivers/input/power.c
@@ -98,7 +98,7 @@ static void power_event(struct input_handle *handle, unsigned int type,
static struct input_handle *power_connect(struct input_handler *handler,
struct input_dev *dev,
- struct input_device_id *id)
+ const struct input_device_id *id)
{
struct input_handle *handle;
@@ -120,7 +120,7 @@ static void power_disconnect(struct input_handle *handle)
kfree(handle);
}
-static struct input_device_id power_ids[] = {
+static const struct input_device_id power_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT(EV_KEY) },
@@ -150,8 +150,7 @@ static struct input_handler power_handler = {
static int __init power_init(void)
{
- input_register_handler(&power_handler);
- return 0;
+ return input_register_handler(&power_handler);
}
static void __exit power_exit(void)
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index 98acf170252c..adef447f23ea 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -112,12 +112,12 @@ config SERIO_GSCPS2
config HP_SDC
tristate "HP System Device Controller i8042 Support"
- depends on GSC && SERIO
+ depends on (GSC || HP300) && SERIO
default y
---help---
- This option enables supports for the the "System Device
+ This option enables support for the "System Device
Controller", an i8042 carrying microcode to manage a
- few miscellanous devices on some Hewlett Packard systems.
+ few miscellaneous devices on some Hewlett Packard systems.
The SDC itself contains a 10ms resolution timer/clock capable
of delivering interrupts on a periodic and one-shot basis.
The SDC may also be connected to a battery-backed real-time
diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
index 3df5eedf8f31..5a7b49c35539 100644
--- a/drivers/input/serio/ambakmi.c
+++ b/drivers/input/serio/ambakmi.c
@@ -37,14 +37,14 @@ struct amba_kmi_port {
unsigned int open;
};
-static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t amba_kmi_int(int irq, void *dev_id)
{
struct amba_kmi_port *kmi = dev_id;
unsigned int status = readb(KMIIR);
int handled = IRQ_NONE;
while (status & KMIIR_RXINTR) {
- serio_interrupt(kmi->io, readb(KMIDATA), 0, regs);
+ serio_interrupt(kmi->io, readb(KMIDATA), 0);
status = readb(KMIIR);
handled = IRQ_HANDLED;
}
diff --git a/drivers/input/serio/ct82c710.c b/drivers/input/serio/ct82c710.c
index bc6e87add093..0d35018c23a9 100644
--- a/drivers/input/serio/ct82c710.c
+++ b/drivers/input/serio/ct82c710.c
@@ -71,9 +71,9 @@ static struct resource ct82c710_iores;
* is waiting in the 82C710.
*/
-static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ct82c710_interrupt(int cpl, void *dev_id)
{
- return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0, regs);
+ return serio_interrupt(ct82c710_port, inb(CT82C710_DATA), 0);
}
/*
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index cde036a92168..74f14e097789 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -82,7 +82,7 @@ MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
#define GSC_ID_MOUSE 1
-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs);
+static irqreturn_t gscps2_interrupt(int irq, void *dev);
#define BUFFER_SIZE 0x0f
@@ -166,7 +166,7 @@ static inline int gscps2_writeb_output(struct gscps2port *ps2port, u8 data)
/* make sure any received data is returned as fast as possible */
/* this is important e.g. when we set the LEDs on the keyboard */
- gscps2_interrupt(0, NULL, NULL);
+ gscps2_interrupt(0, NULL);
return 1;
}
@@ -226,7 +226,7 @@ static LIST_HEAD(ps2port_list);
* later.
*/
-static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t gscps2_interrupt(int irq, void *dev)
{
struct gscps2port *ps2port;
@@ -267,7 +267,7 @@ static irqreturn_t gscps2_interrupt(int irq, void *dev, struct pt_regs *regs)
rxflags = ((status & GSC_STAT_TERR) ? SERIO_TIMEOUT : 0 ) |
((status & GSC_STAT_PERR) ? SERIO_PARITY : 0 );
- serio_interrupt(ps2port->port, data, rxflags, regs);
+ serio_interrupt(ps2port->port, data, rxflags);
} /* while() */
@@ -306,7 +306,7 @@ static int gscps2_open(struct serio *port)
/* enable it */
gscps2_enable(ps2port, ENABLE);
- gscps2_interrupt(0, NULL, NULL);
+ gscps2_interrupt(0, NULL);
return 0;
}
diff --git a/drivers/input/serio/hil_mlc.c b/drivers/input/serio/hil_mlc.c
index bbbe15e21904..49e11e2c1d5d 100644
--- a/drivers/input/serio/hil_mlc.c
+++ b/drivers/input/serio/hil_mlc.c
@@ -162,10 +162,10 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
if (did != (p & HIL_PKT_ADDR_MASK) >> 8) {
if (drv == NULL || drv->interrupt == NULL) goto skip;
- drv->interrupt(serio, 0, 0, NULL);
- drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
- drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL);
- drv->interrupt(serio, HIL_CMD_POL + cnt, 0, NULL);
+ drv->interrupt(serio, 0, 0);
+ drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
+ drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
+ drv->interrupt(serio, HIL_CMD_POL + cnt, 0);
skip:
did = (p & HIL_PKT_ADDR_MASK) >> 8;
serio = did ? mlc->serio[mlc->di_map[did-1]] : NULL;
@@ -174,10 +174,10 @@ static void hil_mlc_send_polls(hil_mlc *mlc) {
}
cnt++; i++;
if (drv == NULL || drv->interrupt == NULL) continue;
- drv->interrupt(serio, (p >> 24), 0, NULL);
- drv->interrupt(serio, (p >> 16) & 0xff, 0, NULL);
- drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0, NULL);
- drv->interrupt(serio, p & 0xff, 0, NULL);
+ drv->interrupt(serio, (p >> 24), 0);
+ drv->interrupt(serio, (p >> 16) & 0xff, 0);
+ drv->interrupt(serio, (p >> 8) & ~HIL_PKT_ADDR_MASK, 0);
+ drv->interrupt(serio, p & 0xff, 0);
}
}
@@ -391,23 +391,23 @@ static int hilse_operate(hil_mlc *mlc, int repoll) {
}
#define FUNC(funct, funct_arg, zero_rc, neg_rc, pos_rc) \
-{ HILSE_FUNC, { func: &funct }, funct_arg, zero_rc, neg_rc, pos_rc },
+{ HILSE_FUNC, { .func = funct }, funct_arg, zero_rc, neg_rc, pos_rc },
#define OUT(pack) \
-{ HILSE_OUT, { packet: pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 },
+{ HILSE_OUT, { .packet = pack }, 0, HILSEN_NEXT, HILSEN_DOZE, 0 },
#define CTS \
-{ HILSE_CTS, { packet: 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 },
+{ HILSE_CTS, { .packet = 0 }, 0, HILSEN_NEXT | HILSEN_SCHED | HILSEN_BREAK, HILSEN_DOZE, 0 },
#define EXPECT(comp, to, got, got_wrong, timed_out) \
-{ HILSE_EXPECT, { packet: comp }, to, got, got_wrong, timed_out },
+{ HILSE_EXPECT, { .packet = comp }, to, got, got_wrong, timed_out },
#define EXPECT_LAST(comp, to, got, got_wrong, timed_out) \
-{ HILSE_EXPECT_LAST, { packet: comp }, to, got, got_wrong, timed_out },
+{ HILSE_EXPECT_LAST, { .packet = comp }, to, got, got_wrong, timed_out },
#define EXPECT_DISC(comp, to, got, got_wrong, timed_out) \
-{ HILSE_EXPECT_DISC, { packet: comp }, to, got, got_wrong, timed_out },
+{ HILSE_EXPECT_DISC, { .packet = comp }, to, got, got_wrong, timed_out },
#define IN(to, got, got_error, timed_out) \
-{ HILSE_IN, { packet: 0 }, to, got, got_error, timed_out },
+{ HILSE_IN, { .packet = 0 }, to, got, got_error, timed_out },
#define OUT_DISC(pack) \
-{ HILSE_OUT_DISC, { packet: pack }, 0, 0, 0, 0 },
+{ HILSE_OUT_DISC, { .packet = pack }, 0, 0, 0, 0 },
#define OUT_LAST(pack) \
-{ HILSE_OUT_LAST, { packet: pack }, 0, 0, 0, 0 },
+{ HILSE_OUT_LAST, { .packet = pack }, 0, 0, 0, 0 },
struct hilse_node hil_mlc_se[HILSEN_END] = {
@@ -780,16 +780,16 @@ static int hil_mlc_serio_write(struct serio *serio, unsigned char c) {
while ((last != idx) && (*last == 0)) last--;
while (idx != last) {
- drv->interrupt(serio, 0, 0, NULL);
- drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
- drv->interrupt(serio, 0, 0, NULL);
- drv->interrupt(serio, *idx, 0, NULL);
+ drv->interrupt(serio, 0, 0);
+ drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
+ drv->interrupt(serio, 0, 0);
+ drv->interrupt(serio, *idx, 0);
idx++;
}
- drv->interrupt(serio, 0, 0, NULL);
- drv->interrupt(serio, HIL_ERR_INT >> 16, 0, NULL);
- drv->interrupt(serio, HIL_PKT_CMD >> 8, 0, NULL);
- drv->interrupt(serio, *idx, 0, NULL);
+ drv->interrupt(serio, 0, 0);
+ drv->interrupt(serio, HIL_ERR_INT >> 16, 0);
+ drv->interrupt(serio, HIL_PKT_CMD >> 8, 0);
+ drv->interrupt(serio, *idx, 0);
mlc->serio_oidx[map->didx] = 0;
mlc->serio_opacket[map->didx] = 0;
diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c
index a10348bb25e9..9907ad3bea23 100644
--- a/drivers/input/serio/hp_sdc.c
+++ b/drivers/input/serio/hp_sdc.c
@@ -202,7 +202,7 @@ static void hp_sdc_take (int irq, void *dev_id, uint8_t status, uint8_t data) {
}
}
-static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) {
+static irqreturn_t hp_sdc_isr(int irq, void *dev_id) {
uint8_t status, data;
status = hp_sdc_status_in8();
@@ -253,7 +253,7 @@ static irqreturn_t hp_sdc_isr(int irq, void *dev_id, struct pt_regs * regs) {
}
-static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id, struct pt_regs * regs) {
+static irqreturn_t hp_sdc_nmisr(int irq, void *dev_id) {
int status;
status = hp_sdc_status_in8();
@@ -310,7 +310,7 @@ static void hp_sdc_tasklet(unsigned long foo) {
* in tasklet/bh context.
*/
if (curr->act.irqhook)
- curr->act.irqhook(0, 0, 0, 0);
+ curr->act.irqhook(0, NULL, 0, 0);
}
curr->actidx = curr->idx;
curr->idx++;
@@ -525,7 +525,7 @@ actdone:
up(curr->act.semaphore);
}
else if (act & HP_SDC_ACT_CALLBACK) {
- curr->act.irqhook(0,0,0,0);
+ curr->act.irqhook(0,NULL,0,0);
}
if (curr->idx >= curr->endidx) { /* This transaction is over. */
if (act & HP_SDC_ACT_DEALLOC) kfree(curr);
diff --git a/drivers/input/serio/i8042-io.h b/drivers/input/serio/i8042-io.h
index cc21914fbc72..3b4e13b9ce1b 100644
--- a/drivers/input/serio/i8042-io.h
+++ b/drivers/input/serio/i8042-io.h
@@ -67,25 +67,22 @@ static inline int i8042_platform_init(void)
* On some platforms touching the i8042 data register region can do really
* bad things. Because of this the region is always reserved on such boxes.
*/
-#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__) && !defined(CONFIG_PPC_MERGE)
- if (!request_region(I8042_DATA_REG, 16, "i8042"))
- return -EBUSY;
-#endif
-
- i8042_reset = 1;
-
#if defined(CONFIG_PPC_MERGE)
if (check_legacy_ioport(I8042_DATA_REG))
- return -EBUSY;
+ return -ENODEV;
+#endif
+#if !defined(__sh__) && !defined(__alpha__) && !defined(__mips__)
if (!request_region(I8042_DATA_REG, 16, "i8042"))
return -EBUSY;
#endif
+
+ i8042_reset = 1;
return 0;
}
static inline void i8042_platform_exit(void)
{
-#if !defined(__sh__) && !defined(__alpha__) && !defined(CONFIG_PPC64)
+#if !defined(__sh__) && !defined(__alpha__)
release_region(I8042_DATA_REG, 16);
#endif
}
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index f606e96bc2f4..8738edda6610 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -160,6 +160,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
},
},
{
+ .ident = "Toshiba Equium A110",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "EQUIUM A110"),
+ },
+ },
+ {
.ident = "Alienware Sentia",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ALIENWARE"),
@@ -180,6 +187,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FS115B"),
},
},
+ {
+ .ident = "Amoi M636/A737",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Amoi Electronics CO.,LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "M636/A737 platform"),
+ },
+ },
{ }
};
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 06a3f25657dd..7e3141f37e32 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -90,47 +90,26 @@ static DEFINE_SPINLOCK(i8042_lock);
struct i8042_port {
struct serio *serio;
int irq;
- unsigned char disable;
- unsigned char irqen;
unsigned char exists;
signed char mux;
- char name[8];
};
#define I8042_KBD_PORT_NO 0
#define I8042_AUX_PORT_NO 1
#define I8042_MUX_PORT_NO 2
#define I8042_NUM_PORTS (I8042_NUM_MUX_PORTS + 2)
-static struct i8042_port i8042_ports[I8042_NUM_PORTS] = {
- {
- .disable = I8042_CTR_KBDDIS,
- .irqen = I8042_CTR_KBDINT,
- .mux = -1,
- .name = "KBD",
- },
- {
- .disable = I8042_CTR_AUXDIS,
- .irqen = I8042_CTR_AUXINT,
- .mux = -1,
- .name = "AUX",
- }
-};
+
+static struct i8042_port i8042_ports[I8042_NUM_PORTS];
static unsigned char i8042_initial_ctr;
static unsigned char i8042_ctr;
-static unsigned char i8042_mux_open;
static unsigned char i8042_mux_present;
-static struct timer_list i8042_timer;
+static unsigned char i8042_kbd_irq_registered;
+static unsigned char i8042_aux_irq_registered;
+static unsigned char i8042_suppress_kbd_ack;
static struct platform_device *i8042_platform_device;
-
-/*
- * Shared IRQ's require a device pointer, but this driver doesn't support
- * multiple devices
- */
-#define i8042_request_irq_cookie (&i8042_timer)
-
-static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t i8042_interrupt(int irq, void *dev_id);
/*
* The i8042_wait_read() and i8042_wait_write functions wait for the i8042 to
@@ -141,6 +120,7 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int i8042_wait_read(void)
{
int i = 0;
+
while ((~i8042_read_status() & I8042_STR_OBF) && (i < I8042_CTL_TIMEOUT)) {
udelay(50);
i++;
@@ -151,6 +131,7 @@ static int i8042_wait_read(void)
static int i8042_wait_write(void)
{
int i = 0;
+
while ((i8042_read_status() & I8042_STR_IBF) && (i < I8042_CTL_TIMEOUT)) {
udelay(50);
i++;
@@ -192,48 +173,57 @@ static int i8042_flush(void)
* encoded in bits 8-11 of the command number.
*/
-static int i8042_command(unsigned char *param, int command)
+static int __i8042_command(unsigned char *param, int command)
{
- unsigned long flags;
- int i, retval, auxerr = 0;
+ int i, error;
if (i8042_noloop && command == I8042_CMD_AUX_LOOP)
return -1;
- spin_lock_irqsave(&i8042_lock, flags);
-
- if ((retval = i8042_wait_write()))
- goto out;
+ error = i8042_wait_write();
+ if (error)
+ return error;
dbg("%02x -> i8042 (command)", command & 0xff);
i8042_write_command(command & 0xff);
for (i = 0; i < ((command >> 12) & 0xf); i++) {
- if ((retval = i8042_wait_write()))
- goto out;
+ error = i8042_wait_write();
+ if (error)
+ return error;
dbg("%02x -> i8042 (parameter)", param[i]);
i8042_write_data(param[i]);
}
for (i = 0; i < ((command >> 8) & 0xf); i++) {
- if ((retval = i8042_wait_read()))
- goto out;
+ error = i8042_wait_read();
+ if (error) {
+ dbg(" -- i8042 (timeout)");
+ return error;
+ }
if (command == I8042_CMD_AUX_LOOP &&
!(i8042_read_status() & I8042_STR_AUXDATA)) {
- retval = auxerr = -1;
- goto out;
+ dbg(" -- i8042 (auxerr)");
+ return -1;
}
param[i] = i8042_read_data();
dbg("%02x <- i8042 (return)", param[i]);
}
- if (retval)
- dbg(" -- i8042 (%s)", auxerr ? "auxerr" : "timeout");
+ return 0;
+}
- out:
+static int i8042_command(unsigned char *param, int command)
+{
+ unsigned long flags;
+ int retval;
+
+ spin_lock_irqsave(&i8042_lock, flags);
+ retval = __i8042_command(param, command);
spin_unlock_irqrestore(&i8042_lock, flags);
+
return retval;
}
@@ -248,7 +238,7 @@ static int i8042_kbd_write(struct serio *port, unsigned char c)
spin_lock_irqsave(&i8042_lock, flags);
- if(!(retval = i8042_wait_write())) {
+ if (!(retval = i8042_wait_write())) {
dbg("%02x -> i8042 (kbd-data)", c);
i8042_write_data(c);
}
@@ -282,105 +272,11 @@ static int i8042_aux_write(struct serio *serio, unsigned char c)
* characters later.
*/
- i8042_interrupt(0, NULL, NULL);
+ i8042_interrupt(0, NULL);
return retval;
}
/*
- * i8042_activate_port() enables port on a chip.
- */
-
-static int i8042_activate_port(struct i8042_port *port)
-{
- if (!port->serio)
- return -1;
-
- i8042_flush();
-
- /*
- * Enable port again here because it is disabled if we are
- * resuming (normally it is enabled already).
- */
- i8042_ctr &= ~port->disable;
-
- i8042_ctr |= port->irqen;
-
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- i8042_ctr &= ~port->irqen;
- return -1;
- }
-
- return 0;
-}
-
-
-/*
- * i8042_open() is called when a port is open by the higher layer.
- * It allocates the interrupt and calls i8042_enable_port.
- */
-
-static int i8042_open(struct serio *serio)
-{
- struct i8042_port *port = serio->port_data;
-
- if (port->mux != -1)
- if (i8042_mux_open++)
- return 0;
-
- if (request_irq(port->irq, i8042_interrupt,
- IRQF_SHARED, "i8042", i8042_request_irq_cookie)) {
- printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", port->irq, port->name);
- goto irq_fail;
- }
-
- if (i8042_activate_port(port)) {
- printk(KERN_ERR "i8042.c: Can't activate %s, unregistering the port\n", port->name);
- goto activate_fail;
- }
-
- i8042_interrupt(0, NULL, NULL);
-
- return 0;
-
- activate_fail:
- free_irq(port->irq, i8042_request_irq_cookie);
-
- irq_fail:
- serio_unregister_port_delayed(serio);
-
- return -1;
-}
-
-/*
- * i8042_close() frees the interrupt, so that it can possibly be used
- * by another driver. We never know - if the user doesn't have a mouse,
- * the BIOS could have used the AUX interrupt for PCI.
- */
-
-static void i8042_close(struct serio *serio)
-{
- struct i8042_port *port = serio->port_data;
-
- if (port->mux != -1)
- if (--i8042_mux_open)
- return;
-
- i8042_ctr &= ~port->irqen;
-
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_WARNING "i8042.c: Can't write CTR while closing %s.\n", port->name);
-/*
- * We still want to continue and free IRQ so if more data keeps coming in
- * kernel will just ignore the irq.
- */
- }
-
- free_irq(port->irq, i8042_request_irq_cookie);
-
- i8042_flush();
-}
-
-/*
* i8042_start() is called by serio core when port is about to finish
* registering. It will mark port as existing so i8042_interrupt can
* start sending data through it.
@@ -414,16 +310,14 @@ static void i8042_stop(struct serio *serio)
* to the upper layers.
*/
-static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i8042_interrupt(int irq, void *dev_id)
{
struct i8042_port *port;
unsigned long flags;
unsigned char str, data;
unsigned int dfl;
unsigned int port_no;
- int ret;
-
- mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
+ int ret = 1;
spin_lock_irqsave(&i8042_lock, flags);
str = i8042_read_status();
@@ -480,20 +374,78 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id, struct pt_regs *regs)
port = &i8042_ports[port_no];
- dbg("%02x <- i8042 (interrupt, %s, %d%s%s)",
- data, port->name, irq,
+ dbg("%02x <- i8042 (interrupt, %d, %d%s%s)",
+ data, port_no, irq,
dfl & SERIO_PARITY ? ", bad parity" : "",
dfl & SERIO_TIMEOUT ? ", timeout" : "");
+ if (unlikely(i8042_suppress_kbd_ack))
+ if (port_no == I8042_KBD_PORT_NO &&
+ (data == 0xfa || data == 0xfe)) {
+ i8042_suppress_kbd_ack = 0;
+ goto out;
+ }
+
if (likely(port->exists))
- serio_interrupt(port->serio, data, dfl, regs);
+ serio_interrupt(port->serio, data, dfl);
- ret = 1;
out:
return IRQ_RETVAL(ret);
}
/*
+ * i8042_enable_kbd_port enables keybaord port on chip
+ */
+
+static int i8042_enable_kbd_port(void)
+{
+ i8042_ctr &= ~I8042_CTR_KBDDIS;
+ i8042_ctr |= I8042_CTR_KBDINT;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042.c: Failed to enable KBD port.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * i8042_enable_aux_port enables AUX (mouse) port on chip
+ */
+
+static int i8042_enable_aux_port(void)
+{
+ i8042_ctr &= ~I8042_CTR_AUXDIS;
+ i8042_ctr |= I8042_CTR_AUXINT;
+
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042.c: Failed to enable AUX port.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * i8042_enable_mux_ports enables 4 individual AUX ports after
+ * the controller has been switched into Multiplexed mode
+ */
+
+static int i8042_enable_mux_ports(void)
+{
+ unsigned char param;
+ int i;
+
+ for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
+ i8042_command(&param, I8042_CMD_MUX_PFX + i);
+ i8042_command(&param, I8042_CMD_AUX_ENABLE);
+ }
+
+ return i8042_enable_aux_port();
+}
+
+/*
* i8042_set_mux_mode checks whether the controller has an active
* multiplexor and puts the chip into Multiplexed (1) or Legacy (0) mode.
*/
@@ -510,8 +462,7 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
/*
* Internal loopback test - send three bytes, they should come back from the
- * mouse interface, the last should be version. Note that we negate mouseport
- * command responses for the i8042_check_aux() routine.
+ * mouse interface, the last should be version.
*/
param = 0xf0;
@@ -530,67 +481,67 @@ static int i8042_set_mux_mode(unsigned int mode, unsigned char *mux_version)
return 0;
}
-
/*
- * i8042_enable_mux_ports enables 4 individual AUX ports after
- * the controller has been switched into Multiplexed mode
+ * i8042_check_mux() checks whether the controller supports the PS/2 Active
+ * Multiplexing specification by Synaptics, Phoenix, Insyde and
+ * LCS/Telegraphics.
*/
-static int i8042_enable_mux_ports(void)
+static int __devinit i8042_check_mux(void)
{
- unsigned char param;
- int i;
+ unsigned char mux_version;
+
+ if (i8042_set_mux_mode(1, &mux_version))
+ return -1;
+
/*
- * Disable all muxed ports by disabling AUX.
+ * Workaround for interference with USB Legacy emulation
+ * that causes a v10.12 MUX to be found.
*/
+ if (mux_version == 0xAC)
+ return -1;
+
+ printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
+ (mux_version >> 4) & 0xf, mux_version & 0xf);
+/*
+ * Disable all muxed ports by disabling AUX.
+ */
i8042_ctr |= I8042_CTR_AUXDIS;
i8042_ctr &= ~I8042_CTR_AUXINT;
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Failed to disable AUX port, can't use MUX.\n");
- return -1;
+ return -EIO;
}
-/*
- * Enable all muxed ports.
- */
-
- for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
- i8042_command(&param, I8042_CMD_MUX_PFX + i);
- i8042_command(&param, I8042_CMD_AUX_ENABLE);
- }
+ i8042_mux_present = 1;
return 0;
}
-
/*
- * i8042_check_mux() checks whether the controller supports the PS/2 Active
- * Multiplexing specification by Synaptics, Phoenix, Insyde and
- * LCS/Telegraphics.
+ * The following is used to test AUX IRQ delivery.
*/
+static struct completion i8042_aux_irq_delivered __devinitdata;
+static int i8042_irq_being_tested __devinitdata;
-static int __devinit i8042_check_mux(void)
+static irqreturn_t __devinit i8042_aux_test_irq(int irq, void *dev_id)
{
- unsigned char mux_version;
-
- if (i8042_set_mux_mode(1, &mux_version))
- return -1;
-
- /* Workaround for interference with USB Legacy emulation */
- /* that causes a v10.12 MUX to be found. */
- if (mux_version == 0xAC)
- return -1;
-
- printk(KERN_INFO "i8042.c: Detected active multiplexing controller, rev %d.%d.\n",
- (mux_version >> 4) & 0xf, mux_version & 0xf);
+ unsigned long flags;
+ unsigned char str, data;
- if (i8042_enable_mux_ports())
- return -1;
+ spin_lock_irqsave(&i8042_lock, flags);
+ str = i8042_read_status();
+ if (str & I8042_STR_OBF) {
+ data = i8042_read_data();
+ if (i8042_irq_being_tested &&
+ data == 0xa5 && (str & I8042_STR_AUXDATA))
+ complete(&i8042_aux_irq_delivered);
+ }
+ spin_unlock_irqrestore(&i8042_lock, flags);
- i8042_mux_present = 1;
- return 0;
+ return IRQ_HANDLED;
}
@@ -601,18 +552,10 @@ static int __devinit i8042_check_mux(void)
static int __devinit i8042_check_aux(void)
{
+ int retval = -1;
+ int irq_registered = 0;
+ unsigned long flags;
unsigned char param;
- static int i8042_check_aux_cookie;
-
-/*
- * Check if AUX irq is available. If it isn't, then there is no point
- * in trying to detect AUX presence.
- */
-
- if (request_irq(i8042_ports[I8042_AUX_PORT_NO].irq, i8042_interrupt,
- IRQF_SHARED, "i8042", &i8042_check_aux_cookie))
- return -1;
- free_irq(i8042_ports[I8042_AUX_PORT_NO].irq, &i8042_check_aux_cookie);
/*
* Get rid of bytes in the queue.
@@ -637,9 +580,9 @@ static int __devinit i8042_check_aux(void)
* AUX ports, we test for this only when the LOOP command failed.
*/
- if (i8042_command(&param, I8042_CMD_AUX_TEST)
- || (param && param != 0xfa && param != 0xff))
- return -1;
+ if (i8042_command(&param, I8042_CMD_AUX_TEST) ||
+ (param && param != 0xfa && param != 0xff))
+ return -1;
}
/*
@@ -659,54 +602,80 @@ static int __devinit i8042_check_aux(void)
return -1;
/*
- * Disable the interface.
+ * Test AUX IRQ delivery to make sure BIOS did not grab the IRQ and
+ * used it for a PCI card or somethig else.
*/
- i8042_ctr |= I8042_CTR_AUXDIS;
- i8042_ctr &= ~I8042_CTR_AUXINT;
+ if (i8042_noloop) {
+/*
+ * Without LOOP command we can't test AUX IRQ delivery. Assume the port
+ * is working and hope we are right.
+ */
+ retval = 0;
+ goto out;
+ }
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
- return -1;
+ if (request_irq(I8042_AUX_IRQ, i8042_aux_test_irq, IRQF_SHARED,
+ "i8042", i8042_platform_device))
+ goto out;
- return 0;
-}
+ irq_registered = 1;
+ if (i8042_enable_aux_port())
+ goto out;
+
+ spin_lock_irqsave(&i8042_lock, flags);
+ init_completion(&i8042_aux_irq_delivered);
+ i8042_irq_being_tested = 1;
+
+ param = 0xa5;
+ retval = __i8042_command(&param, I8042_CMD_AUX_LOOP & 0xf0ff);
+
+ spin_unlock_irqrestore(&i8042_lock, flags);
+
+ if (retval)
+ goto out;
+
+ if (wait_for_completion_timeout(&i8042_aux_irq_delivered,
+ msecs_to_jiffies(250)) == 0) {
/*
- * i8042_port_register() marks the device as existing,
- * registers it, and reports to the user.
+ * AUX IRQ was never delivered so we need to flush the controller to
+ * get rid of the byte we put there; otherwise keyboard may not work.
*/
+ i8042_flush();
+ retval = -1;
+ }
-static int __devinit i8042_port_register(struct i8042_port *port)
-{
- i8042_ctr &= ~port->disable;
+ out:
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_WARNING "i8042.c: Can't write CTR while registering.\n");
- kfree(port->serio);
- port->serio = NULL;
- i8042_ctr |= port->disable;
- return -EIO;
- }
+/*
+ * Disable the interface.
+ */
- printk(KERN_INFO "serio: i8042 %s port at %#lx,%#lx irq %d\n",
- port->name,
- (unsigned long) I8042_DATA_REG,
- (unsigned long) I8042_COMMAND_REG,
- port->irq);
+ i8042_ctr |= I8042_CTR_AUXDIS;
+ i8042_ctr &= ~I8042_CTR_AUXINT;
- serio_register_port(port->serio);
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+ retval = -1;
- return 0;
-}
+ if (irq_registered)
+ free_irq(I8042_AUX_IRQ, i8042_platform_device);
+ return retval;
+}
-static void i8042_timer_func(unsigned long data)
+static int i8042_controller_check(void)
{
- i8042_interrupt(0, NULL, NULL);
+ if (i8042_flush() == I8042_BUFFER_SIZE) {
+ printk(KERN_ERR "i8042.c: No controller found.\n");
+ return -ENODEV;
+ }
+
+ return 0;
}
-static int i8042_ctl_test(void)
+static int i8042_controller_selftest(void)
{
unsigned char param;
@@ -715,13 +684,13 @@ static int i8042_ctl_test(void)
if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
printk(KERN_ERR "i8042.c: i8042 controller self test timeout.\n");
- return -1;
+ return -ENODEV;
}
if (param != I8042_RET_CTL_TEST) {
printk(KERN_ERR "i8042.c: i8042 controller selftest failed. (%#x != %#x)\n",
param, I8042_RET_CTL_TEST);
- return -1;
+ return -EIO;
}
return 0;
@@ -738,25 +707,12 @@ static int i8042_controller_init(void)
unsigned long flags;
/*
- * Test the i8042. We need to know if it thinks it's working correctly
- * before doing anything else.
- */
-
- if (i8042_flush() == I8042_BUFFER_SIZE) {
- printk(KERN_ERR "i8042.c: No controller found.\n");
- return -1;
- }
-
- if (i8042_ctl_test())
- return -1;
-
-/*
* Save the CTR for restoral on unload / reboot.
*/
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) {
printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n");
- return -1;
+ return -EIO;
}
i8042_initial_ctr = i8042_ctr;
@@ -805,7 +761,7 @@ static int i8042_controller_init(void)
if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
printk(KERN_ERR "i8042.c: Can't write CTR while initializing i8042.\n");
- return -1;
+ return -EIO;
}
return 0;
@@ -813,15 +769,12 @@ static int i8042_controller_init(void)
/*
- * Reset the controller.
+ * Reset the controller and reset CRT to the original value set by BIOS.
*/
+
static void i8042_controller_reset(void)
{
-/*
- * Reset the controller if requested.
- */
-
- i8042_ctl_test();
+ i8042_flush();
/*
* Disable MUX mode if present.
@@ -831,12 +784,16 @@ static void i8042_controller_reset(void)
i8042_set_mux_mode(0, NULL);
/*
- * Restore the original control register setting.
+ * Reset the controller if requested.
*/
- i8042_ctr = i8042_initial_ctr;
+ i8042_controller_selftest();
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
+/*
+ * Restore the original control register setting.
+ */
+
+ if (i8042_command(&i8042_initial_ctr, I8042_CMD_CTL_WCTR))
printk(KERN_WARNING "i8042.c: Can't restore CTR.\n");
}
@@ -850,14 +807,12 @@ static void i8042_controller_cleanup(void)
{
int i;
- i8042_flush();
-
/*
* Reset anything that is connected to the ports.
*/
for (i = 0; i < I8042_NUM_PORTS; i++)
- if (i8042_ports[i].exists)
+ if (i8042_ports[i].serio)
serio_cleanup(i8042_ports[i].serio);
i8042_controller_reset();
@@ -894,11 +849,13 @@ static long i8042_panic_blink(long count)
led ^= 0x01 | 0x04;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
+ i8042_suppress_kbd_ack = 1;
i8042_write_data(0xed); /* set leds */
DELAY;
while (i8042_read_status() & I8042_STR_IBF)
DELAY;
DELAY;
+ i8042_suppress_kbd_ack = 1;
i8042_write_data(led);
DELAY;
last_blink = count;
@@ -913,8 +870,7 @@ static long i8042_panic_blink(long count)
static int i8042_suspend(struct platform_device *dev, pm_message_t state)
{
- del_timer_sync(&i8042_timer);
- i8042_controller_reset();
+ i8042_controller_cleanup();
return 0;
}
@@ -926,33 +882,39 @@ static int i8042_suspend(struct platform_device *dev, pm_message_t state)
static int i8042_resume(struct platform_device *dev)
{
- int i;
+ int error;
- if (i8042_ctl_test())
- return -1;
+ error = i8042_controller_check();
+ if (error)
+ return error;
- if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
- printk(KERN_ERR "i8042: Can't write CTR\n");
- return -1;
- }
-
- if (i8042_mux_present)
- if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
- printk(KERN_WARNING "i8042: failed to resume active multiplexor, mouse won't work.\n");
+ error = i8042_controller_selftest();
+ if (error)
+ return error;
/*
- * Activate all ports.
+ * Restore pre-resume CTR value and disable all ports
*/
- for (i = 0; i < I8042_NUM_PORTS; i++)
- i8042_activate_port(&i8042_ports[i]);
+ i8042_ctr |= I8042_CTR_AUXDIS | I8042_CTR_KBDDIS;
+ i8042_ctr &= ~(I8042_CTR_AUXINT | I8042_CTR_KBDINT);
+ if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR)) {
+ printk(KERN_ERR "i8042: Can't write CTR to resume\n");
+ return -EIO;
+ }
-/*
- * Restart timer (for polling "stuck" data)
- */
- mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
+ if (i8042_mux_present) {
+ if (i8042_set_mux_mode(1, NULL) || i8042_enable_mux_ports())
+ printk(KERN_WARNING
+ "i8042: failed to resume active multiplexor, "
+ "mouse won't work.\n");
+ } else if (i8042_ports[I8042_AUX_PORT_NO].serio)
+ i8042_enable_aux_port();
- panic_blink = i8042_panic_blink;
+ if (i8042_ports[I8042_KBD_PORT_NO].serio)
+ i8042_enable_kbd_port();
+
+ i8042_interrupt(0, NULL);
return 0;
}
@@ -978,24 +940,24 @@ static int __devinit i8042_create_kbd_port(void)
serio->id.type = i8042_direct ? SERIO_8042 : SERIO_8042_XL;
serio->write = i8042_dumbkbd ? NULL : i8042_kbd_write;
- serio->open = i8042_open;
- serio->close = i8042_close;
serio->start = i8042_start;
serio->stop = i8042_stop;
serio->port_data = port;
serio->dev.parent = &i8042_platform_device->dev;
- strlcpy(serio->name, "i8042 Kbd Port", sizeof(serio->name));
+ strlcpy(serio->name, "i8042 KBD port", sizeof(serio->name));
strlcpy(serio->phys, I8042_KBD_PHYS_DESC, sizeof(serio->phys));
port->serio = serio;
+ port->irq = I8042_KBD_IRQ;
- return i8042_port_register(port);
+ return 0;
}
-static int __devinit i8042_create_aux_port(void)
+static int __devinit i8042_create_aux_port(int idx)
{
struct serio *serio;
- struct i8042_port *port = &i8042_ports[I8042_AUX_PORT_NO];
+ int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
+ struct i8042_port *port = &i8042_ports[port_no];
serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
if (!serio)
@@ -1003,111 +965,191 @@ static int __devinit i8042_create_aux_port(void)
serio->id.type = SERIO_8042;
serio->write = i8042_aux_write;
- serio->open = i8042_open;
- serio->close = i8042_close;
serio->start = i8042_start;
serio->stop = i8042_stop;
serio->port_data = port;
serio->dev.parent = &i8042_platform_device->dev;
- strlcpy(serio->name, "i8042 Aux Port", sizeof(serio->name));
- strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
+ if (idx < 0) {
+ strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
+ strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
+ } else {
+ snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
+ snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
+ }
port->serio = serio;
+ port->mux = idx;
+ port->irq = I8042_AUX_IRQ;
- return i8042_port_register(port);
+ return 0;
}
-static int __devinit i8042_create_mux_port(int index)
+static void __devinit i8042_free_kbd_port(void)
{
- struct serio *serio;
- struct i8042_port *port = &i8042_ports[I8042_MUX_PORT_NO + index];
+ kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
+ i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
+}
- serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
- if (!serio)
- return -ENOMEM;
+static void __devinit i8042_free_aux_ports(void)
+{
+ int i;
- serio->id.type = SERIO_8042;
- serio->write = i8042_aux_write;
- serio->open = i8042_open;
- serio->close = i8042_close;
- serio->start = i8042_start;
- serio->stop = i8042_stop;
- serio->port_data = port;
- serio->dev.parent = &i8042_platform_device->dev;
- snprintf(serio->name, sizeof(serio->name), "i8042 Aux-%d Port", index);
- snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, index + 1);
+ for (i = I8042_AUX_PORT_NO; i < I8042_NUM_PORTS; i++) {
+ kfree(i8042_ports[i].serio);
+ i8042_ports[i].serio = NULL;
+ }
+}
- *port = i8042_ports[I8042_AUX_PORT_NO];
- port->exists = 0;
- snprintf(port->name, sizeof(port->name), "AUX%d", index);
- port->mux = index;
- port->serio = serio;
+static void __devinit i8042_register_ports(void)
+{
+ int i;
- return i8042_port_register(port);
+ for (i = 0; i < I8042_NUM_PORTS; i++) {
+ if (i8042_ports[i].serio) {
+ printk(KERN_INFO "serio: %s at %#lx,%#lx irq %d\n",
+ i8042_ports[i].serio->name,
+ (unsigned long) I8042_DATA_REG,
+ (unsigned long) I8042_COMMAND_REG,
+ i8042_ports[i].irq);
+ serio_register_port(i8042_ports[i].serio);
+ }
+ }
}
-static int __devinit i8042_probe(struct platform_device *dev)
+static void __devinit i8042_unregister_ports(void)
{
- int i, have_ports = 0;
- int err;
+ int i;
+
+ for (i = 0; i < I8042_NUM_PORTS; i++) {
+ if (i8042_ports[i].serio) {
+ serio_unregister_port(i8042_ports[i].serio);
+ i8042_ports[i].serio = NULL;
+ }
+ }
+}
- init_timer(&i8042_timer);
- i8042_timer.function = i8042_timer_func;
+static void i8042_free_irqs(void)
+{
+ if (i8042_aux_irq_registered)
+ free_irq(I8042_AUX_IRQ, i8042_platform_device);
+ if (i8042_kbd_irq_registered)
+ free_irq(I8042_KBD_IRQ, i8042_platform_device);
+
+ i8042_aux_irq_registered = i8042_kbd_irq_registered = 0;
+}
+
+static int __devinit i8042_setup_aux(void)
+{
+ int (*aux_enable)(void);
+ int error;
+ int i;
- if (i8042_controller_init())
+ if (i8042_check_aux())
return -ENODEV;
- if (!i8042_noaux && !i8042_check_aux()) {
- if (!i8042_nomux && !i8042_check_mux()) {
- for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
- err = i8042_create_mux_port(i);
- if (err)
- goto err_unregister_ports;
- }
- } else {
- err = i8042_create_aux_port();
- if (err)
- goto err_unregister_ports;
+ if (i8042_nomux || i8042_check_mux()) {
+ error = i8042_create_aux_port(-1);
+ if (error)
+ goto err_free_ports;
+ aux_enable = i8042_enable_aux_port;
+ } else {
+ for (i = 0; i < I8042_NUM_MUX_PORTS; i++) {
+ error = i8042_create_aux_port(i);
+ if (error)
+ goto err_free_ports;
}
- have_ports = 1;
+ aux_enable = i8042_enable_mux_ports;
}
- if (!i8042_nokbd) {
- err = i8042_create_kbd_port();
- if (err)
- goto err_unregister_ports;
- have_ports = 1;
- }
+ error = request_irq(I8042_AUX_IRQ, i8042_interrupt, IRQF_SHARED,
+ "i8042", i8042_platform_device);
+ if (error)
+ goto err_free_ports;
- if (!have_ports) {
- err = -ENODEV;
- goto err_controller_cleanup;
- }
+ if (aux_enable())
+ goto err_free_irq;
- mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
+ i8042_aux_irq_registered = 1;
return 0;
- err_unregister_ports:
- for (i = 0; i < I8042_NUM_PORTS; i++)
- if (i8042_ports[i].serio)
- serio_unregister_port(i8042_ports[i].serio);
- err_controller_cleanup:
- i8042_controller_cleanup();
+ err_free_irq:
+ free_irq(I8042_AUX_IRQ, i8042_platform_device);
+ err_free_ports:
+ i8042_free_aux_ports();
+ return error;
+}
- return err;
+static int __devinit i8042_setup_kbd(void)
+{
+ int error;
+
+ error = i8042_create_kbd_port();
+ if (error)
+ return error;
+
+ error = request_irq(I8042_KBD_IRQ, i8042_interrupt, IRQF_SHARED,
+ "i8042", i8042_platform_device);
+ if (error)
+ goto err_free_port;
+
+ error = i8042_enable_kbd_port();
+ if (error)
+ goto err_free_irq;
+
+ i8042_kbd_irq_registered = 1;
+ return 0;
+
+ err_free_irq:
+ free_irq(I8042_KBD_IRQ, i8042_platform_device);
+ err_free_port:
+ i8042_free_kbd_port();
+ return error;
}
-static int __devexit i8042_remove(struct platform_device *dev)
+static int __devinit i8042_probe(struct platform_device *dev)
{
- int i;
+ int error;
- i8042_controller_cleanup();
+ error = i8042_controller_selftest();
+ if (error)
+ return error;
- for (i = 0; i < I8042_NUM_PORTS; i++)
- if (i8042_ports[i].exists)
- serio_unregister_port(i8042_ports[i].serio);
+ error = i8042_controller_init();
+ if (error)
+ return error;
+
+ if (!i8042_noaux) {
+ error = i8042_setup_aux();
+ if (error && error != -ENODEV && error != -EBUSY)
+ goto out_fail;
+ }
+
+ if (!i8042_nokbd) {
+ error = i8042_setup_kbd();
+ if (error)
+ goto out_fail;
+ }
- del_timer_sync(&i8042_timer);
+/*
+ * Ok, everything is ready, let's register all serio ports
+ */
+ i8042_register_ports();
+
+ return 0;
+
+ out_fail:
+ i8042_free_aux_ports(); /* in case KBD failed but AUX not */
+ i8042_free_irqs();
+ i8042_controller_reset();
+
+ return error;
+}
+
+static int __devexit i8042_remove(struct platform_device *dev)
+{
+ i8042_unregister_ports();
+ i8042_free_irqs();
+ i8042_controller_reset();
return 0;
}
@@ -1134,8 +1176,9 @@ static int __init i8042_init(void)
if (err)
return err;
- i8042_ports[I8042_AUX_PORT_NO].irq = I8042_AUX_IRQ;
- i8042_ports[I8042_KBD_PORT_NO].irq = I8042_KBD_IRQ;
+ err = i8042_controller_check();
+ if (err)
+ goto err_platform_exit;
err = platform_driver_register(&i8042_driver);
if (err)
@@ -1151,6 +1194,8 @@ static int __init i8042_init(void)
if (err)
goto err_free_device;
+ panic_blink = i8042_panic_blink;
+
return 0;
err_free_device:
@@ -1167,7 +1212,6 @@ static void __exit i8042_exit(void)
{
platform_device_unregister(i8042_platform_device);
platform_driver_unregister(&i8042_driver);
-
i8042_platform_exit();
panic_blink = NULL;
diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h
index af526ab9ec04..b3eb7a72d961 100644
--- a/drivers/input/serio/i8042.h
+++ b/drivers/input/serio/i8042.h
@@ -37,15 +37,6 @@
#define I8042_CTL_TIMEOUT 10000
/*
- * When the device isn't opened and it's interrupts aren't used, we poll it at
- * regular intervals to see if any characters arrived. If yes, we can start
- * probing for any mouse / keyboard connected. This is the period of the
- * polling.
- */
-
-#define I8042_POLL_PERIOD HZ/20
-
-/*
* Status register bits.
*/
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index ed202f2f251a..e5b1b60757bb 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -27,15 +27,6 @@ MODULE_AUTHOR("Dmitry Torokhov <dtor@mail.ru>");
MODULE_DESCRIPTION("PS/2 driver library");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(ps2_init);
-EXPORT_SYMBOL(ps2_sendbyte);
-EXPORT_SYMBOL(ps2_drain);
-EXPORT_SYMBOL(ps2_command);
-EXPORT_SYMBOL(ps2_schedule_command);
-EXPORT_SYMBOL(ps2_handle_ack);
-EXPORT_SYMBOL(ps2_handle_response);
-EXPORT_SYMBOL(ps2_cmd_aborted);
-
/* Work structure to schedule execution of a command */
struct ps2work {
struct work_struct work;
@@ -71,6 +62,7 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
return -ps2dev->nak;
}
+EXPORT_SYMBOL(ps2_sendbyte);
/*
* ps2_drain() waits for device to transmit requested number of bytes
@@ -96,15 +88,16 @@ void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
msecs_to_jiffies(timeout));
mutex_unlock(&ps2dev->cmd_mutex);
}
+EXPORT_SYMBOL(ps2_drain);
/*
* ps2_is_keyboard_id() checks received ID byte against the list of
* known keyboard IDs.
*/
-static inline int ps2_is_keyboard_id(char id_byte)
+int ps2_is_keyboard_id(char id_byte)
{
- static char keyboard_ids[] = {
+ const static char keyboard_ids[] = {
0xab, /* Regular keyboards */
0xac, /* NCD Sun keyboard */
0x2b, /* Trust keyboard, translated */
@@ -115,6 +108,7 @@ static inline int ps2_is_keyboard_id(char id_byte)
return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
}
+EXPORT_SYMBOL(ps2_is_keyboard_id);
/*
* ps2_adjust_timeout() is called after receiving 1st byte of command
@@ -139,6 +133,19 @@ static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
case PS2_CMD_GETID:
/*
+ * Microsoft Natural Elite keyboard responds to
+ * the GET ID command as it were a mouse, with
+ * a single byte. Fail the command so atkbd will
+ * use alternative probe to detect it.
+ */
+ if (ps2dev->cmdbuf[1] == 0xaa) {
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = 0;
+ serio_continue_rx(ps2dev->serio);
+ timeout = 0;
+ }
+
+ /*
* If device behind the port is not a keyboard there
* won't be 2nd byte of ID response.
*/
@@ -182,7 +189,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
return -1;
}
- mutex_lock_nested(&ps2dev->cmd_mutex, SINGLE_DEPTH_NESTING);
+ mutex_lock(&ps2dev->cmd_mutex);
serio_pause_rx(ps2dev->serio);
ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0;
@@ -237,6 +244,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
mutex_unlock(&ps2dev->cmd_mutex);
return rc;
}
+EXPORT_SYMBOL(ps2_command);
/*
* ps2_execute_scheduled_command() sends a command, previously scheduled by
@@ -279,6 +287,7 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman
return 0;
}
+EXPORT_SYMBOL(ps2_schedule_command);
/*
* ps2_init() initializes ps2dev structure
@@ -287,9 +296,11 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman
void ps2_init(struct ps2dev *ps2dev, struct serio *serio)
{
mutex_init(&ps2dev->cmd_mutex);
+ lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth);
init_waitqueue_head(&ps2dev->wait);
ps2dev->serio = serio;
}
+EXPORT_SYMBOL(ps2_init);
/*
* ps2_handle_ack() is supposed to be used in interrupt handler
@@ -335,6 +346,7 @@ int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data)
return 1;
}
+EXPORT_SYMBOL(ps2_handle_ack);
/*
* ps2_handle_response() is supposed to be used in interrupt handler
@@ -360,6 +372,7 @@ int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data)
return 1;
}
+EXPORT_SYMBOL(ps2_handle_response);
void ps2_cmd_aborted(struct ps2dev *ps2dev)
{
@@ -371,4 +384,4 @@ void ps2_cmd_aborted(struct ps2dev *ps2dev)
ps2dev->flags = 0;
}
-
+EXPORT_SYMBOL(ps2_cmd_aborted);
diff --git a/drivers/input/serio/maceps2.c b/drivers/input/serio/maceps2.c
index f08a5d0cd5fa..558200e96d0f 100644
--- a/drivers/input/serio/maceps2.c
+++ b/drivers/input/serio/maceps2.c
@@ -72,8 +72,7 @@ static int maceps2_write(struct serio *dev, unsigned char val)
return -1;
}
-static irqreturn_t maceps2_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t maceps2_interrupt(int irq, void *dev_id)
{
struct serio *dev = dev_id;
struct mace_ps2port *port = ((struct maceps2_data *)dev->port_data)->port;
@@ -81,7 +80,7 @@ static irqreturn_t maceps2_interrupt(int irq, void *dev_id,
if (port->status & PS2_STATUS_RX_FULL) {
byte = port->rx;
- serio_interrupt(dev, byte & 0xff, 0, regs);
+ serio_interrupt(dev, byte & 0xff, 0);
}
return IRQ_HANDLED;
diff --git a/drivers/input/serio/parkbd.c b/drivers/input/serio/parkbd.c
index a5c1fb3a4a51..688610e86a3e 100644
--- a/drivers/input/serio/parkbd.c
+++ b/drivers/input/serio/parkbd.c
@@ -102,7 +102,7 @@ static int parkbd_write(struct serio *port, unsigned char c)
return 0;
}
-static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void parkbd_interrupt(int irq, void *dev_id)
{
if (parkbd_writing) {
@@ -134,7 +134,7 @@ static void parkbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
parkbd_buffer |= (parkbd_readlines() >> 1) << parkbd_counter++;
if (parkbd_counter == parkbd_mode + 10)
- serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0, regs);
+ serio_interrupt(parkbd_port, (parkbd_buffer >> (2 - parkbd_mode)) & 0xff, 0);
}
parkbd_last = jiffies;
diff --git a/drivers/input/serio/pcips2.c b/drivers/input/serio/pcips2.c
index fb727c665253..ea5e3c6ddb62 100644
--- a/drivers/input/serio/pcips2.c
+++ b/drivers/input/serio/pcips2.c
@@ -58,7 +58,7 @@ static int pcips2_write(struct serio *io, unsigned char val)
return 0;
}
-static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t pcips2_interrupt(int irq, void *devid)
{
struct pcips2_data *ps2if = devid;
unsigned char status, scancode;
@@ -80,7 +80,7 @@ static irqreturn_t pcips2_interrupt(int irq, void *devid, struct pt_regs *regs)
if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY;
- serio_interrupt(ps2if->io, scancode, flag, regs);
+ serio_interrupt(ps2if->io, scancode, flag);
} while (1);
return IRQ_RETVAL(handled);
}
diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c
index d3827c5fe119..cb89aff2e160 100644
--- a/drivers/input/serio/q40kbd.c
+++ b/drivers/input/serio/q40kbd.c
@@ -53,14 +53,14 @@ DEFINE_SPINLOCK(q40kbd_lock);
static struct serio *q40kbd_port;
static struct platform_device *q40kbd_device;
-static irqreturn_t q40kbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t q40kbd_interrupt(int irq, void *dev_id)
{
unsigned long flags;
spin_lock_irqsave(&q40kbd_lock, flags);
if (Q40_IRQ_KEYB_MASK & master_inb(INTERRUPT_REG))
- serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0, regs);
+ serio_interrupt(q40kbd_port, master_inb(KEYCODE_REG), 0);
master_outb(-1, KEYBOARD_UNLOCK_REG);
diff --git a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
index 513d37fc1acf..49f84315cb32 100644
--- a/drivers/input/serio/rpckbd.c
+++ b/drivers/input/serio/rpckbd.c
@@ -56,7 +56,7 @@ static int rpckbd_write(struct serio *port, unsigned char val)
return 0;
}
-static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpckbd_rx(int irq, void *dev_id)
{
struct serio *port = dev_id;
unsigned int byte;
@@ -65,13 +65,13 @@ static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
byte = iomd_readb(IOMD_KARTRX);
- serio_interrupt(port, byte, 0, regs);
+ serio_interrupt(port, byte, 0);
handled = IRQ_HANDLED;
}
return handled;
}
-static irqreturn_t rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpckbd_tx(int irq, void *dev_id)
{
return IRQ_HANDLED;
}
diff --git a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
index ebd9976fc811..559508795af1 100644
--- a/drivers/input/serio/sa1111ps2.c
+++ b/drivers/input/serio/sa1111ps2.c
@@ -40,7 +40,7 @@ struct ps2if {
* at the most one, but we loop for safety. If there was a
* framing error, we have to manually clear the status.
*/
-static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ps2_rxint(int irq, void *dev_id)
{
struct ps2if *ps2if = dev_id;
unsigned int scancode, flag, status;
@@ -58,7 +58,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
if (hweight8(scancode) & 1)
flag ^= SERIO_PARITY;
- serio_interrupt(ps2if->io, scancode, flag, regs);
+ serio_interrupt(ps2if->io, scancode, flag);
status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
}
@@ -69,7 +69,7 @@ static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
/*
* Completion of ps2 write
*/
-static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ps2_txint(int irq, void *dev_id)
{
struct ps2if *ps2if = dev_id;
unsigned int status;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 3e76ad71c9a0..211943f85cb6 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -118,6 +118,8 @@ static int serio_match_port(const struct serio_device_id *ids, struct serio *ser
static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
{
+ int error;
+
down_write(&serio_bus.subsys.rwsem);
if (serio_match_port(drv->id_table, serio)) {
@@ -126,9 +128,19 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
serio->dev.driver = NULL;
goto out;
}
- device_bind_driver(&serio->dev);
+ error = device_bind_driver(&serio->dev);
+ if (error) {
+ printk(KERN_WARNING
+ "serio: device_bind_driver() failed "
+ "for %s (%s) and %s, error: %d\n",
+ serio->phys, serio->name,
+ drv->description, error);
+ serio_disconnect_driver(serio);
+ serio->dev.driver = NULL;
+ goto out;
+ }
}
-out:
+ out:
up_write(&serio_bus.subsys.rwsem);
}
@@ -538,8 +550,12 @@ static void serio_init_port(struct serio *serio)
"serio%ld", (long)atomic_inc_return(&serio_no) - 1);
serio->dev.bus = &serio_bus;
serio->dev.release = serio_release_port;
- if (serio->parent)
+ if (serio->parent) {
serio->dev.parent = &serio->parent->dev;
+ serio->depth = serio->parent->depth + 1;
+ } else
+ serio->depth = 0;
+ lockdep_set_subclass(&serio->lock, serio->depth);
}
/*
@@ -911,7 +927,7 @@ void serio_close(struct serio *serio)
}
irqreturn_t serio_interrupt(struct serio *serio,
- unsigned char data, unsigned int dfl, struct pt_regs *regs)
+ unsigned char data, unsigned int dfl)
{
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
@@ -919,7 +935,7 @@ irqreturn_t serio_interrupt(struct serio *serio,
spin_lock_irqsave(&serio->lock, flags);
if (likely(serio->drv)) {
- ret = serio->drv->interrupt(serio, data, dfl, regs);
+ ret = serio->drv->interrupt(serio, data, dfl);
} else if (!dfl && serio->registered) {
serio_rescan(serio);
ret = IRQ_HANDLED;
diff --git a/drivers/input/serio/serio_raw.c b/drivers/input/serio/serio_raw.c
index 71a8eea816cb..ba2a2035d648 100644
--- a/drivers/input/serio/serio_raw.c
+++ b/drivers/input/serio/serio_raw.c
@@ -250,7 +250,7 @@ static struct file_operations serio_raw_fops = {
*********************************************************************/
static irqreturn_t serio_raw_interrupt(struct serio *serio, unsigned char data,
- unsigned int dfl, struct pt_regs *regs)
+ unsigned int dfl)
{
struct serio_raw *serio_raw = serio_get_drvdata(serio);
struct serio_raw_list *list;
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
index 54a680cc704d..e1a3a79ab3f9 100644
--- a/drivers/input/serio/serport.c
+++ b/drivers/input/serio/serport.c
@@ -117,9 +117,6 @@ static void serport_ldisc_close(struct tty_struct *tty)
* serport_ldisc_receive() is called by the low level tty driver when characters
* are ready for us. We forward the characters, one by one to the 'interrupt'
* routine.
- *
- * FIXME: We should get pt_regs from the tty layer and forward them to
- * serio_interrupt here.
*/
static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
@@ -134,7 +131,7 @@ static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *c
goto out;
for (i = 0; i < count; i++)
- serio_interrupt(serport->serio, cp[i], 0, NULL);
+ serio_interrupt(serport->serio, cp[i], 0);
out:
spin_unlock_irqrestore(&serport->lock, flags);
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
index b1b14f8d4dd6..9418bbe47072 100644
--- a/drivers/input/touchscreen/Kconfig
+++ b/drivers/input/touchscreen/Kconfig
@@ -108,4 +108,40 @@ config TOUCHSCREEN_HP600
To compile this driver as a module, choose M here: the
module will be called hp680_ts_input.
+config TOUCHSCREEN_PENMOUNT
+ tristate "Penmount serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Penmount serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called penmount.
+
+config TOUCHSCREEN_TOUCHRIGHT
+ tristate "Touchright serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Touchright serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called touchright.
+
+config TOUCHSCREEN_TOUCHWIN
+ tristate "Touchwin serial touchscreen"
+ select SERIO
+ help
+ Say Y here if you have a Touchwin serial touchscreen connected to
+ your system.
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called touchwin.
+
endif
diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
index 5e5557c43121..1abb8f10d608 100644
--- a/drivers/input/touchscreen/Makefile
+++ b/drivers/input/touchscreen/Makefile
@@ -12,3 +12,6 @@ obj-$(CONFIG_TOUCHSCREEN_ELO) += elo.o
obj-$(CONFIG_TOUCHSCREEN_MTOUCH) += mtouch.o
obj-$(CONFIG_TOUCHSCREEN_MK712) += mk712.o
obj-$(CONFIG_TOUCHSCREEN_HP600) += hp680_ts_input.o
+obj-$(CONFIG_TOUCHSCREEN_PENMOUNT) += penmount.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o
+obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index 66e411badf70..f56d6a0f0624 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -487,7 +487,7 @@ static void ads7846_timer(unsigned long handle)
spin_unlock_irq(&ts->lock);
}
-static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs)
+static irqreturn_t ads7846_irq(int irq, void *handle)
{
struct ads7846 *ts = handle;
unsigned long flags;
diff --git a/drivers/input/touchscreen/corgi_ts.c b/drivers/input/touchscreen/corgi_ts.c
index 9b66271d3ba8..66121f6a89ad 100644
--- a/drivers/input/touchscreen/corgi_ts.c
+++ b/drivers/input/touchscreen/corgi_ts.c
@@ -173,7 +173,7 @@ static int read_xydata(struct corgi_ts *corgi_ts)
return 1;
}
-static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
+static void new_data(struct corgi_ts *corgi_ts)
{
if (corgi_ts->power_mode != PWR_MODE_ACTIVE)
return;
@@ -181,7 +181,6 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
if (!corgi_ts->tc.pressure && corgi_ts->pendown == 0)
return;
- input_regs(corgi_ts->input, regs);
input_report_abs(corgi_ts->input, ABS_X, corgi_ts->tc.x);
input_report_abs(corgi_ts->input, ABS_Y, corgi_ts->tc.y);
input_report_abs(corgi_ts->input, ABS_PRESSURE, corgi_ts->tc.pressure);
@@ -189,14 +188,14 @@ static void new_data(struct corgi_ts *corgi_ts, struct pt_regs *regs)
input_sync(corgi_ts->input);
}
-static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_regs *regs)
+static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer)
{
if ((GPLR(IRQ_TO_GPIO(corgi_ts->irq_gpio)) & GPIO_bit(IRQ_TO_GPIO(corgi_ts->irq_gpio))) == 0) {
/* Disable Interrupt */
set_irq_type(corgi_ts->irq_gpio, IRQT_NOEDGE);
if (read_xydata(corgi_ts)) {
corgi_ts->pendown = 1;
- new_data(corgi_ts, regs);
+ new_data(corgi_ts);
}
mod_timer(&corgi_ts->timer, jiffies + HZ / 100);
} else {
@@ -208,7 +207,7 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_
if (corgi_ts->pendown) {
corgi_ts->tc.pressure = 0;
- new_data(corgi_ts, regs);
+ new_data(corgi_ts);
}
/* Enable Falling Edge */
@@ -220,13 +219,13 @@ static void ts_interrupt_main(struct corgi_ts *corgi_ts, int isTimer, struct pt_
static void corgi_ts_timer(unsigned long data)
{
struct corgi_ts *corgits_data = (struct corgi_ts *) data;
- ts_interrupt_main(corgits_data, 1, NULL);
+ ts_interrupt_main(corgits_data, 1);
}
-static irqreturn_t ts_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ts_interrupt(int irq, void *dev_id)
{
struct corgi_ts *corgits_data = dev_id;
- ts_interrupt_main(corgits_data, 0, regs);
+ ts_interrupt_main(corgits_data, 0);
return IRQ_HANDLED;
}
@@ -238,7 +237,7 @@ static int corgits_suspend(struct platform_device *dev, pm_message_t state)
if (corgi_ts->pendown) {
del_timer_sync(&corgi_ts->timer);
corgi_ts->tc.pressure = 0;
- new_data(corgi_ts, NULL);
+ new_data(corgi_ts);
corgi_ts->pendown = 0;
}
corgi_ts->power_mode = PWR_MODE_SUSPEND;
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index c86a2eb310fd..913e1b73bb0e 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -23,6 +23,7 @@
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/init.h>
+#include <linux/ctype.h>
#define DRIVER_DESC "Elo serial touchscreen driver"
@@ -34,7 +35,19 @@ MODULE_LICENSE("GPL");
* Definitions & global arrays.
*/
-#define ELO_MAX_LENGTH 10
+#define ELO_MAX_LENGTH 10
+
+#define ELO10_PACKET_LEN 8
+#define ELO10_TOUCH 0x03
+#define ELO10_PRESSURE 0x80
+
+#define ELO10_LEAD_BYTE 'U'
+
+#define ELO10_ID_CMD 'i'
+
+#define ELO10_TOUCH_PACKET 'T'
+#define ELO10_ACK_PACKET 'A'
+#define ELI10_ID_PACKET 'I'
/*
* Per-touchscreen data.
@@ -43,51 +56,66 @@ MODULE_LICENSE("GPL");
struct elo {
struct input_dev *dev;
struct serio *serio;
+ struct mutex cmd_mutex;
+ struct completion cmd_done;
int id;
int idx;
+ unsigned char expected_packet;
unsigned char csum;
unsigned char data[ELO_MAX_LENGTH];
+ unsigned char response[ELO10_PACKET_LEN];
char phys[32];
};
-static void elo_process_data_10(struct elo* elo, unsigned char data, struct pt_regs *regs)
+static void elo_process_data_10(struct elo *elo, unsigned char data)
{
struct input_dev *dev = elo->dev;
- elo->csum += elo->data[elo->idx] = data;
-
+ elo->data[elo->idx] = data;
switch (elo->idx++) {
-
case 0:
- if (data != 'U') {
+ elo->csum = 0xaa;
+ if (data != ELO10_LEAD_BYTE) {
+ pr_debug("elo: unsynchronized data: 0x%02x\n", data);
elo->idx = 0;
- elo->csum = 0;
- }
- break;
-
- case 1:
- if (data != 'T') {
- elo->idx = 0;
- elo->csum = 0;
}
break;
case 9:
- if (elo->csum) {
- input_regs(dev, regs);
+ elo->idx = 0;
+ if (data != elo->csum) {
+ pr_debug("elo: bad checksum: 0x%02x, expected 0x%02x\n",
+ data, elo->csum);
+ break;
+ }
+ if (elo->data[1] != elo->expected_packet) {
+ if (elo->data[1] != ELO10_TOUCH_PACKET)
+ pr_debug("elo: unexpected packet: 0x%02x\n",
+ elo->data[1]);
+ break;
+ }
+ if (likely(elo->data[1] == ELO10_TOUCH_PACKET)) {
input_report_abs(dev, ABS_X, (elo->data[4] << 8) | elo->data[3]);
input_report_abs(dev, ABS_Y, (elo->data[6] << 8) | elo->data[5]);
- input_report_abs(dev, ABS_PRESSURE, (elo->data[8] << 8) | elo->data[7]);
- input_report_key(dev, BTN_TOUCH, elo->data[8] || elo->data[7]);
+ if (elo->data[2] & ELO10_PRESSURE)
+ input_report_abs(dev, ABS_PRESSURE,
+ (elo->data[8] << 8) | elo->data[7]);
+ input_report_key(dev, BTN_TOUCH, elo->data[2] & ELO10_TOUCH);
input_sync(dev);
+ } else if (elo->data[1] == ELO10_ACK_PACKET) {
+ if (elo->data[2] == '0')
+ elo->expected_packet = ELO10_TOUCH_PACKET;
+ complete(&elo->cmd_done);
+ } else {
+ memcpy(elo->response, &elo->data[1], ELO10_PACKET_LEN);
+ elo->expected_packet = ELO10_ACK_PACKET;
}
- elo->idx = 0;
- elo->csum = 0;
break;
}
+ elo->csum += data;
}
-static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_regs *regs)
+static void elo_process_data_6(struct elo *elo, unsigned char data)
{
struct input_dev *dev = elo->dev;
@@ -105,7 +133,6 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re
break;
}
- input_regs(dev, regs);
input_report_abs(dev, ABS_X, ((elo->data[0] & 0x3f) << 6) | (elo->data[1] & 0x3f));
input_report_abs(dev, ABS_Y, ((elo->data[2] & 0x3f) << 6) | (elo->data[3] & 0x3f));
@@ -135,7 +162,7 @@ static void elo_process_data_6(struct elo* elo, unsigned char data, struct pt_re
}
}
-static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_regs *regs)
+static void elo_process_data_3(struct elo *elo, unsigned char data)
{
struct input_dev *dev = elo->dev;
@@ -148,7 +175,6 @@ static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_re
elo->idx = 0;
break;
case 2:
- input_regs(dev, regs);
input_report_key(dev, BTN_TOUCH, !(elo->data[1] & 0x80));
input_report_abs(dev, ABS_X, elo->data[1]);
input_report_abs(dev, ABS_Y, elo->data[2]);
@@ -159,39 +185,103 @@ static void elo_process_data_3(struct elo* elo, unsigned char data, struct pt_re
}
static irqreturn_t elo_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
- struct elo* elo = serio_get_drvdata(serio);
+ struct elo *elo = serio_get_drvdata(serio);
switch(elo->id) {
case 0:
- elo_process_data_10(elo, data, regs);
+ elo_process_data_10(elo, data);
break;
case 1:
case 2:
- elo_process_data_6(elo, data, regs);
+ elo_process_data_6(elo, data);
break;
case 3:
- elo_process_data_3(elo, data, regs);
+ elo_process_data_3(elo, data);
break;
}
return IRQ_HANDLED;
}
+static int elo_command_10(struct elo *elo, unsigned char *packet)
+{
+ int rc = -1;
+ int i;
+ unsigned char csum = 0xaa + ELO10_LEAD_BYTE;
+
+ mutex_lock(&elo->cmd_mutex);
+
+ serio_pause_rx(elo->serio);
+ elo->expected_packet = toupper(packet[0]);
+ init_completion(&elo->cmd_done);
+ serio_continue_rx(elo->serio);
+
+ if (serio_write(elo->serio, ELO10_LEAD_BYTE))
+ goto out;
+
+ for (i = 0; i < ELO10_PACKET_LEN; i++) {
+ csum += packet[i];
+ if (serio_write(elo->serio, packet[i]))
+ goto out;
+ }
+
+ if (serio_write(elo->serio, csum))
+ goto out;
+
+ wait_for_completion_timeout(&elo->cmd_done, HZ);
+
+ if (elo->expected_packet == ELO10_TOUCH_PACKET) {
+ /* We are back in reporting mode, the command was ACKed */
+ memcpy(packet, elo->response, ELO10_PACKET_LEN);
+ rc = 0;
+ }
+
+ out:
+ mutex_unlock(&elo->cmd_mutex);
+ return rc;
+}
+
+static int elo_setup_10(struct elo *elo)
+{
+ static const char *elo_types[] = { "Accu", "Dura", "Intelli", "Carroll" };
+ struct input_dev *dev = elo->dev;
+ unsigned char packet[ELO10_PACKET_LEN] = { ELO10_ID_CMD };
+
+ if (elo_command_10(elo, packet))
+ return -1;
+
+ dev->id.version = (packet[5] << 8) | packet[4];
+
+ input_set_abs_params(dev, ABS_X, 96, 4000, 0, 0);
+ input_set_abs_params(dev, ABS_Y, 96, 4000, 0, 0);
+ if (packet[3] & ELO10_PRESSURE)
+ input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0);
+
+ printk(KERN_INFO "elo: %sTouch touchscreen, fw: %02x.%02x, "
+ "features: %x02x, controller: 0x%02x\n",
+ elo_types[(packet[1] -'0') & 0x03],
+ packet[5], packet[4], packet[3], packet[7]);
+
+ return 0;
+}
+
/*
* elo_disconnect() is the opposite of elo_connect()
*/
static void elo_disconnect(struct serio *serio)
{
- struct elo* elo = serio_get_drvdata(serio);
+ struct elo *elo = serio_get_drvdata(serio);
+ input_get_device(elo->dev);
input_unregister_device(elo->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
+ input_put_device(elo->dev);
kfree(elo);
}
@@ -211,12 +301,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_dev = input_allocate_device();
if (!elo || !input_dev) {
err = -ENOMEM;
- goto fail;
+ goto fail1;
}
elo->serio = serio;
elo->id = serio->id.id;
elo->dev = input_dev;
+ elo->expected_packet = ELO10_TOUCH_PACKET;
+ mutex_init(&elo->cmd_mutex);
+ init_completion(&elo->cmd_done);
snprintf(elo->phys, sizeof(elo->phys), "%s/input0", serio->phys);
input_dev->private = elo;
@@ -231,12 +324,17 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ serio_set_drvdata(serio, elo);
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
switch (elo->id) {
case 0: /* 10-byte protocol */
- input_set_abs_params(input_dev, ABS_X, 96, 4000, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 96, 4000, 0, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, 255, 0, 0);
+ if (elo_setup_10(elo))
+ goto fail3;
+
break;
case 1: /* 6-byte protocol */
@@ -253,17 +351,15 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
break;
}
- serio_set_drvdata(serio, elo);
-
- err = serio_open(serio, drv);
+ err = input_register_device(elo->dev);
if (err)
- goto fail;
+ goto fail3;
- input_register_device(elo->dev);
return 0;
- fail: serio_set_drvdata(serio, NULL);
- input_free_device(input_dev);
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
kfree(elo);
return err;
}
diff --git a/drivers/input/touchscreen/gunze.c b/drivers/input/touchscreen/gunze.c
index b769b21973b7..817c2198933d 100644
--- a/drivers/input/touchscreen/gunze.c
+++ b/drivers/input/touchscreen/gunze.c
@@ -60,7 +60,7 @@ struct gunze {
char phys[32];
};
-static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs)
+static void gunze_process_packet(struct gunze* gunze)
{
struct input_dev *dev = gunze->dev;
@@ -70,7 +70,6 @@ static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs)
return;
}
- input_regs(dev, regs);
input_report_abs(dev, ABS_X, simple_strtoul(gunze->data + 1, NULL, 10));
input_report_abs(dev, ABS_Y, 1024 - simple_strtoul(gunze->data + 6, NULL, 10));
input_report_key(dev, BTN_TOUCH, gunze->data[0] == 'T');
@@ -78,12 +77,12 @@ static void gunze_process_packet(struct gunze* gunze, struct pt_regs *regs)
}
static irqreturn_t gunze_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct gunze* gunze = serio_get_drvdata(serio);
if (data == '\r') {
- gunze_process_packet(gunze, regs);
+ gunze_process_packet(gunze);
gunze->idx = 0;
} else {
if (gunze->idx < GUNZE_MAX_LENGTH)
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index e2b910018773..d9e61ee05ea9 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -106,19 +106,18 @@ struct h3600_dev {
char phys[32];
};
-static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t action_button_handler(int irq, void *dev_id)
{
int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
- input_regs(dev, regs);
input_report_key(dev, KEY_ENTER, down);
input_sync(dev);
return IRQ_HANDLED;
}
-static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t npower_button_handler(int irq, void *dev_id)
{
int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
@@ -127,7 +126,6 @@ static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *
* This interrupt is only called when we release the key. So we have
* to fake a key press.
*/
- input_regs(dev, regs);
input_report_key(dev, KEY_SUSPEND, 1);
input_report_key(dev, KEY_SUSPEND, down);
input_sync(dev);
@@ -165,14 +163,12 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
* packets. Some packets coming from serial are not touchscreen related. In
* this case we send them off to be processed elsewhere.
*/
-static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
+static void h3600ts_process_packet(struct h3600_dev *ts)
{
struct input_dev *dev = ts->dev;
static int touched = 0;
int key, down = 0;
- input_regs(dev, regs);
-
switch (ts->event) {
/*
Buttons - returned as a single byte
@@ -301,7 +297,7 @@ static int state;
#define STATE_EOF 3 /* state where we decode checksum or EOF */
static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
- unsigned int flags, struct pt_regs *regs)
+ unsigned int flags)
{
struct h3600_dev *ts = serio_get_drvdata(serio);
@@ -333,7 +329,7 @@ static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
case STATE_EOF:
state = STATE_SOF;
if (data == CHAR_EOF || data == ts->chksum)
- h3600ts_process_packet(ts, regs);
+ h3600ts_process_packet(ts);
break;
default:
printk("Error3\n");
diff --git a/drivers/input/touchscreen/hp680_ts_input.c b/drivers/input/touchscreen/hp680_ts_input.c
index fa97e0f79e7e..e31c6c55b2e2 100644
--- a/drivers/input/touchscreen/hp680_ts_input.c
+++ b/drivers/input/touchscreen/hp680_ts_input.c
@@ -15,7 +15,6 @@
#define HP680_TS_ABS_Y_MIN 80
#define HP680_TS_ABS_Y_MAX 910
-#define SCPCR 0xa4000116
#define PHDR 0xa400012e
#define SCPDR 0xa4000136
@@ -67,7 +66,7 @@ static void do_softint(void *data)
enable_irq(HP680_TS_IRQ);
}
-static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t hp680_ts_interrupt(int irq, void *dev)
{
disable_irq_nosync(irq);
schedule_delayed_work(&work, HZ / 20);
@@ -77,19 +76,6 @@ static irqreturn_t hp680_ts_interrupt(int irq, void *dev, struct pt_regs *regs)
static int __init hp680_ts_init(void)
{
- u8 scpdr;
- u16 scpcr;
-
- scpdr = ctrl_inb(SCPDR);
- scpdr |= SCPDR_TS_SCAN_X | SCPDR_TS_SCAN_Y;
- scpdr &= ~SCPDR_TS_SCAN_ENABLE;
- ctrl_outb(scpdr, SCPDR);
-
- scpcr = ctrl_inw(SCPCR);
- scpcr &= ~SCPCR_TS_MASK;
- scpcr |= SCPCR_TS_ENABLE;
- ctrl_outw(scpcr, SCPCR);
-
hp680_ts_dev = input_allocate_device();
if (!hp680_ts_dev)
return -ENOMEM;
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index 3226830eea08..4cbcaa6a71e5 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -80,7 +80,7 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
static struct input_dev *mk712_dev;
static DEFINE_SPINLOCK(mk712_lock);
-static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mk712_interrupt(int irq, void *dev_id)
{
unsigned char status;
static int debounce = 1;
@@ -88,7 +88,6 @@ static irqreturn_t mk712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static unsigned short last_y;
spin_lock(&mk712_lock);
- input_regs(mk712_dev, regs);
status = inb(mk712_io + MK712_STATUS);
diff --git a/drivers/input/touchscreen/mtouch.c b/drivers/input/touchscreen/mtouch.c
index 8647a905df80..3b4c61664b63 100644
--- a/drivers/input/touchscreen/mtouch.c
+++ b/drivers/input/touchscreen/mtouch.c
@@ -63,12 +63,11 @@ struct mtouch {
char phys[32];
};
-static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *regs)
+static void mtouch_process_format_tablet(struct mtouch *mtouch)
{
struct input_dev *dev = mtouch->dev;
if (MTOUCH_FORMAT_TABLET_LENGTH == ++mtouch->idx) {
- input_regs(dev, regs);
input_report_abs(dev, ABS_X, MTOUCH_GET_XC(mtouch->data));
input_report_abs(dev, ABS_Y, MTOUCH_MAX_YC - MTOUCH_GET_YC(mtouch->data));
input_report_key(dev, BTN_TOUCH, MTOUCH_GET_TOUCHED(mtouch->data));
@@ -78,7 +77,7 @@ static void mtouch_process_format_tablet(struct mtouch *mtouch, struct pt_regs *
}
}
-static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs)
+static void mtouch_process_response(struct mtouch *mtouch)
{
if (MTOUCH_RESPONSE_END_BYTE == mtouch->data[mtouch->idx++]) {
/* FIXME - process response */
@@ -90,16 +89,16 @@ static void mtouch_process_response(struct mtouch *mtouch, struct pt_regs *regs)
}
static irqreturn_t mtouch_interrupt(struct serio *serio,
- unsigned char data, unsigned int flags, struct pt_regs *regs)
+ unsigned char data, unsigned int flags)
{
struct mtouch* mtouch = serio_get_drvdata(serio);
mtouch->data[mtouch->idx] = data;
if (MTOUCH_FORMAT_TABLET_STATUS_BIT & mtouch->data[0])
- mtouch_process_format_tablet(mtouch, regs);
+ mtouch_process_format_tablet(mtouch);
else if (MTOUCH_RESPONSE_BEGIN_BYTE == mtouch->data[0])
- mtouch_process_response(mtouch, regs);
+ mtouch_process_response(mtouch);
else
printk(KERN_DEBUG "mtouch.c: unknown/unsynchronized data from device, byte %x\n",mtouch->data[0]);
diff --git a/drivers/input/touchscreen/penmount.c b/drivers/input/touchscreen/penmount.c
new file mode 100644
index 000000000000..6c7d0c2c76cc
--- /dev/null
+++ b/drivers/input/touchscreen/penmount.c
@@ -0,0 +1,184 @@
+/*
+ * Penmount serial touchscreen driver
+ *
+ * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
+ *
+ * Based on ELO driver (drivers/input/touchscreen/elo.c)
+ * Copyright (c) 2004 Vojtech Pavlik
+ */
+
+/*
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC "Penmount serial touchscreen driver"
+
+MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define PM_MAX_LENGTH 5
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct pm {
+ struct input_dev *dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[PM_MAX_LENGTH];
+ char phys[32];
+};
+
+static irqreturn_t pm_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct pm *pm = serio_get_drvdata(serio);
+ struct input_dev *dev = pm->dev;
+
+ pm->data[pm->idx] = data;
+
+ if (pm->data[0] & 0x80) {
+ if (PM_MAX_LENGTH == ++pm->idx) {
+ input_report_abs(dev, ABS_X, pm->data[2] * 128 + pm->data[1]);
+ input_report_abs(dev, ABS_Y, pm->data[4] * 128 + pm->data[3]);
+ input_report_key(dev, BTN_TOUCH, !!(pm->data[0] & 0x40));
+ input_sync(dev);
+ pm->idx = 0;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * pm_disconnect() is the opposite of pm_connect()
+ */
+
+static void pm_disconnect(struct serio *serio)
+{
+ struct pm *pm = serio_get_drvdata(serio);
+
+ input_get_device(pm->dev);
+ input_unregister_device(pm->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_put_device(pm->dev);
+ kfree(pm);
+}
+
+/*
+ * pm_connect() is the routine that is called when someone adds a
+ * new serio device that supports Gunze protocol and registers it as
+ * an input device.
+ */
+
+static int pm_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct pm *pm;
+ struct input_dev *input_dev;
+ int err;
+
+ pm = kzalloc(sizeof(struct pm), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!pm || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ pm->serio = serio;
+ pm->dev = input_dev;
+ snprintf(pm->phys, sizeof(pm->phys), "%s/input0", serio->phys);
+
+ input_dev->private = pm;
+ input_dev->name = "Penmount Serial TouchScreen";
+ input_dev->phys = pm->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_PENMOUNT;
+ input_dev->id.product = 0;
+ input_dev->id.version = 0x0100;
+ input_dev->cdev.dev = &serio->dev;
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ input_set_abs_params(pm->dev, ABS_X, 0, 0x3ff, 0, 0);
+ input_set_abs_params(pm->dev, ABS_Y, 0, 0x3ff, 0, 0);
+
+ serio_set_drvdata(serio, pm);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(pm->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(pm);
+ return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id pm_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_PENMOUNT,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, pm_serio_ids);
+
+static struct serio_driver pm_drv = {
+ .driver = {
+ .name = "penmountlpc",
+ },
+ .description = DRIVER_DESC,
+ .id_table = pm_serio_ids,
+ .interrupt = pm_interrupt,
+ .connect = pm_connect,
+ .disconnect = pm_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init pm_init(void)
+{
+ serio_register_driver(&pm_drv);
+ return 0;
+}
+
+static void __exit pm_exit(void)
+{
+ serio_unregister_driver(&pm_drv);
+}
+
+module_init(pm_init);
+module_exit(pm_exit);
diff --git a/drivers/input/touchscreen/touchright.c b/drivers/input/touchscreen/touchright.c
new file mode 100644
index 000000000000..c74f74e57af0
--- /dev/null
+++ b/drivers/input/touchscreen/touchright.c
@@ -0,0 +1,195 @@
+/*
+ * Touchright serial touchscreen driver
+ *
+ * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
+ *
+ * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
+ * Copyright (c) 2004 Vojtech Pavlik
+ * and Dan Streetman <ddstreet@ieee.org>
+ */
+
+/*
+ * 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/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC "Touchright serial touchscreen driver"
+
+MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define TR_FORMAT_TOUCH_BIT 0x01
+#define TR_FORMAT_STATUS_BYTE 0x40
+#define TR_FORMAT_STATUS_MASK ~TR_FORMAT_TOUCH_BIT
+
+#define TR_LENGTH 5
+
+#define TR_MIN_XC 0
+#define TR_MAX_XC 0x1ff
+#define TR_MIN_YC 0
+#define TR_MAX_YC 0x1ff
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct tr {
+ struct input_dev *dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[TR_LENGTH];
+ char phys[32];
+};
+
+static irqreturn_t tr_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct tr *tr = serio_get_drvdata(serio);
+ struct input_dev *dev = tr->dev;
+
+ tr->data[tr->idx] = data;
+
+ if ((tr->data[0] & TR_FORMAT_STATUS_MASK) == TR_FORMAT_STATUS_BYTE) {
+ if (++tr->idx == TR_LENGTH) {
+ input_report_abs(dev, ABS_X,
+ (tr->data[1] << 5) | (tr->data[2] >> 1));
+ input_report_abs(dev, ABS_Y,
+ (tr->data[3] << 5) | (tr->data[4] >> 1));
+ input_report_key(dev, BTN_TOUCH,
+ tr->data[0] & TR_FORMAT_TOUCH_BIT);
+ input_sync(dev);
+ tr->idx = 0;
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * tr_disconnect() is the opposite of tr_connect()
+ */
+
+static void tr_disconnect(struct serio *serio)
+{
+ struct tr *tr = serio_get_drvdata(serio);
+
+ input_get_device(tr->dev);
+ input_unregister_device(tr->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_put_device(tr->dev);
+ kfree(tr);
+}
+
+/*
+ * tr_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Touchright protocol and registers it as
+ * an input device.
+ */
+
+static int tr_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct tr *tr;
+ struct input_dev *input_dev;
+ int err;
+
+ tr = kzalloc(sizeof(struct tr), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!tr || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ tr->serio = serio;
+ tr->dev = input_dev;
+ snprintf(tr->phys, sizeof(tr->phys), "%s/input0", serio->phys);
+
+ input_dev->private = tr;
+ input_dev->name = "Touchright Serial TouchScreen";
+ input_dev->phys = tr->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_TOUCHRIGHT;
+ input_dev->id.product = 0;
+ input_dev->id.version = 0x0100;
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ input_set_abs_params(tr->dev, ABS_X, TR_MIN_XC, TR_MAX_XC, 0, 0);
+ input_set_abs_params(tr->dev, ABS_Y, TR_MIN_YC, TR_MAX_YC, 0, 0);
+
+ serio_set_drvdata(serio, tr);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(tr->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(tr);
+ return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id tr_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_TOUCHRIGHT,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, tr_serio_ids);
+
+static struct serio_driver tr_drv = {
+ .driver = {
+ .name = "touchright",
+ },
+ .description = DRIVER_DESC,
+ .id_table = tr_serio_ids,
+ .interrupt = tr_interrupt,
+ .connect = tr_connect,
+ .disconnect = tr_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init tr_init(void)
+{
+ serio_register_driver(&tr_drv);
+ return 0;
+}
+
+static void __exit tr_exit(void)
+{
+ serio_unregister_driver(&tr_drv);
+}
+
+module_init(tr_init);
+module_exit(tr_exit);
diff --git a/drivers/input/touchscreen/touchwin.c b/drivers/input/touchscreen/touchwin.c
new file mode 100644
index 000000000000..9911820fa2fe
--- /dev/null
+++ b/drivers/input/touchscreen/touchwin.c
@@ -0,0 +1,202 @@
+/*
+ * Touchwindow serial touchscreen driver
+ *
+ * Copyright (c) 2006 Rick Koch <n1gp@hotmail.com>
+ *
+ * Based on MicroTouch driver (drivers/input/touchscreen/mtouch.c)
+ * Copyright (c) 2004 Vojtech Pavlik
+ * and Dan Streetman <ddstreet@ieee.org>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * 2005/02/19 Rick Koch:
+ * The Touchwindow I used is made by Edmark Corp. and
+ * constantly outputs a stream of 0's unless it is touched.
+ * It then outputs 3 bytes: X, Y, and a copy of Y.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+#define DRIVER_DESC "Touchwindow serial touchscreen driver"
+
+MODULE_AUTHOR("Rick Koch <n1gp@hotmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define TW_LENGTH 3
+
+#define TW_MIN_XC 0
+#define TW_MAX_XC 0xff
+#define TW_MIN_YC 0
+#define TW_MAX_YC 0xff
+
+/*
+ * Per-touchscreen data.
+ */
+
+struct tw {
+ struct input_dev *dev;
+ struct serio *serio;
+ int idx;
+ int touched;
+ unsigned char data[TW_LENGTH];
+ char phys[32];
+};
+
+static irqreturn_t tw_interrupt(struct serio *serio,
+ unsigned char data, unsigned int flags)
+{
+ struct tw *tw = serio_get_drvdata(serio);
+ struct input_dev *dev = tw->dev;
+
+ if (data) { /* touch */
+ tw->touched = 1;
+ tw->data[tw->idx++] = data;
+ /* verify length and that the two Y's are the same */
+ if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) {
+ input_report_abs(dev, ABS_X, tw->data[0]);
+ input_report_abs(dev, ABS_Y, tw->data[1]);
+ input_report_key(dev, BTN_TOUCH, 1);
+ input_sync(dev);
+ tw->idx = 0;
+ }
+ } else if (tw->touched) { /* untouch */
+ input_report_key(dev, BTN_TOUCH, 0);
+ input_sync(dev);
+ tw->idx = 0;
+ tw->touched = 0;
+ }
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * tw_disconnect() is the opposite of tw_connect()
+ */
+
+static void tw_disconnect(struct serio *serio)
+{
+ struct tw *tw = serio_get_drvdata(serio);
+
+ input_get_device(tw->dev);
+ input_unregister_device(tw->dev);
+ serio_close(serio);
+ serio_set_drvdata(serio, NULL);
+ input_put_device(tw->dev);
+ kfree(tw);
+}
+
+/*
+ * tw_connect() is the routine that is called when someone adds a
+ * new serio device that supports the Touchwin protocol and registers it as
+ * an input device.
+ */
+
+static int tw_connect(struct serio *serio, struct serio_driver *drv)
+{
+ struct tw *tw;
+ struct input_dev *input_dev;
+ int err;
+
+ tw = kzalloc(sizeof(struct tw), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!tw || !input_dev) {
+ err = -ENOMEM;
+ goto fail1;
+ }
+
+ tw->serio = serio;
+ tw->dev = input_dev;
+ snprintf(tw->phys, sizeof(tw->phys), "%s/input0", serio->phys);
+
+ input_dev->private = tw;
+ input_dev->name = "Touchwindow Serial TouchScreen";
+ input_dev->phys = tw->phys;
+ input_dev->id.bustype = BUS_RS232;
+ input_dev->id.vendor = SERIO_TOUCHWIN;
+ input_dev->id.product = 0;
+ input_dev->id.version = 0x0100;
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ input_set_abs_params(tw->dev, ABS_X, TW_MIN_XC, TW_MAX_XC, 0, 0);
+ input_set_abs_params(tw->dev, ABS_Y, TW_MIN_YC, TW_MAX_YC, 0, 0);
+
+ serio_set_drvdata(serio, tw);
+
+ err = serio_open(serio, drv);
+ if (err)
+ goto fail2;
+
+ err = input_register_device(tw->dev);
+ if (err)
+ goto fail3;
+
+ return 0;
+
+ fail3: serio_close(serio);
+ fail2: serio_set_drvdata(serio, NULL);
+ fail1: input_free_device(input_dev);
+ kfree(tw);
+ return err;
+}
+
+/*
+ * The serio driver structure.
+ */
+
+static struct serio_device_id tw_serio_ids[] = {
+ {
+ .type = SERIO_RS232,
+ .proto = SERIO_TOUCHWIN,
+ .id = SERIO_ANY,
+ .extra = SERIO_ANY,
+ },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(serio, tw_serio_ids);
+
+static struct serio_driver tw_drv = {
+ .driver = {
+ .name = "touchwin",
+ },
+ .description = DRIVER_DESC,
+ .id_table = tw_serio_ids,
+ .interrupt = tw_interrupt,
+ .connect = tw_connect,
+ .disconnect = tw_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+static int __init tw_init(void)
+{
+ serio_register_driver(&tw_drv);
+ return 0;
+}
+
+static void __exit tw_exit(void)
+{
+ serio_unregister_driver(&tw_drv);
+}
+
+module_init(tw_init);
+module_exit(tw_exit);
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index 00e3929c6288..a730c461227f 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -135,8 +135,6 @@ struct tsdev_list {
#define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration)
#define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration)
-static struct input_handler tsdev_handler;
-
static struct tsdev *tsdev_table[TSDEV_MINORS/2];
static int tsdev_fasync(int fd, struct file *file, int on)
@@ -263,7 +261,7 @@ static int tsdev_ioctl(struct inode *inode, struct file *file,
return retval;
}
-static struct file_operations tsdev_fops = {
+static const struct file_operations tsdev_fops = {
.owner = THIS_MODULE,
.open = tsdev_open,
.release = tsdev_release,
@@ -370,7 +368,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
static struct input_handle *tsdev_connect(struct input_handler *handler,
struct input_dev *dev,
- struct input_device_id *id)
+ const struct input_device_id *id)
{
struct tsdev *tsdev;
struct class_device *cdev;
@@ -443,7 +441,7 @@ static void tsdev_disconnect(struct input_handle *handle)
tsdev_free(tsdev);
}
-static struct input_device_id tsdev_ids[] = {
+static const struct input_device_id tsdev_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_REL) },
@@ -481,9 +479,7 @@ static struct input_handler tsdev_handler = {
static int __init tsdev_init(void)
{
- input_register_handler(&tsdev_handler);
- printk(KERN_INFO "ts: Compaq touchscreen protocol output\n");
- return 0;
+ return input_register_handler(&tsdev_handler);
}
static void __exit tsdev_exit(void)
diff --git a/drivers/isdn/act2000/act2000_isa.c b/drivers/isdn/act2000/act2000_isa.c
index bc98d77c5ecd..3cac23739344 100644
--- a/drivers/isdn/act2000/act2000_isa.c
+++ b/drivers/isdn/act2000/act2000_isa.c
@@ -16,8 +16,6 @@
#include "act2000_isa.h"
#include "capi.h"
-static act2000_card *irq2card_map[16];
-
/*
* Reset Controller, then try to read the Card's signature.
+ Return:
@@ -63,16 +61,11 @@ act2000_isa_detect(unsigned short portbase)
}
static irqreturn_t
-act2000_isa_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+act2000_isa_interrupt(int irq, void *dev_id)
{
- act2000_card *card = irq2card_map[irq];
+ act2000_card *card = dev_id;
u_char istatus;
- if (!card) {
- printk(KERN_WARNING
- "act2000: Spurious interrupt!\n");
- return IRQ_NONE;
- }
istatus = (inb(ISA_PORT_ISR) & 0x07);
if (istatus & ISA_ISR_OUT) {
/* RX fifo has data */
@@ -139,17 +132,15 @@ int
act2000_isa_config_irq(act2000_card * card, short irq)
{
if (card->flags & ACT2000_FLAGS_IVALID) {
- free_irq(card->irq, NULL);
- irq2card_map[card->irq] = NULL;
+ free_irq(card->irq, card);
}
card->flags &= ~ACT2000_FLAGS_IVALID;
outb(ISA_COR_IRQOFF, ISA_PORT_COR);
if (!irq)
return 0;
- if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, NULL)) {
+ if (!request_irq(irq, &act2000_isa_interrupt, 0, card->regname, card)) {
card->irq = irq;
- irq2card_map[card->irq] = card;
card->flags |= ACT2000_FLAGS_IVALID;
printk(KERN_WARNING
"act2000: Could not request irq %d\n",irq);
@@ -188,10 +179,9 @@ act2000_isa_release(act2000_card * card)
unsigned long flags;
spin_lock_irqsave(&card->lock, flags);
- if (card->flags & ACT2000_FLAGS_IVALID) {
- free_irq(card->irq, NULL);
- irq2card_map[card->irq] = NULL;
- }
+ if (card->flags & ACT2000_FLAGS_IVALID)
+ free_irq(card->irq, card);
+
card->flags &= ~ACT2000_FLAGS_IVALID;
if (card->flags & ACT2000_FLAGS_PVALID)
release_region(card->port, ISA_REGION);
diff --git a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
index 669f76393b5a..11844bbfe933 100644
--- a/drivers/isdn/capi/capi.c
+++ b/drivers/isdn/capi/capi.c
@@ -1298,7 +1298,7 @@ static int capinc_tty_read_proc(char *page, char **start, off_t off,
static struct tty_driver *capinc_tty_driver;
-static struct tty_operations capinc_ops = {
+static const struct tty_operations capinc_ops = {
.open = capinc_tty_open,
.close = capinc_tty_close,
.write = capinc_tty_write,
diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c
index d10c8b82e6aa..b6f9476c0501 100644
--- a/drivers/isdn/capi/capidrv.c
+++ b/drivers/isdn/capi/capidrv.c
@@ -1907,7 +1907,8 @@ static int if_readstat(u8 __user *buf, int len, int id, int channel)
}
for (p=buf, count=0; count < len; p++, count++) {
- put_user(*card->q931_read++, p);
+ if (put_user(*card->q931_read++, p))
+ return -EFAULT;
if (card->q931_read > card->q931_end)
card->q931_read = card->q931_buf;
}
diff --git a/drivers/isdn/capi/capifs.c b/drivers/isdn/capi/capifs.c
index 9ea6bd0ddc35..2dd1b57b0ba4 100644
--- a/drivers/isdn/capi/capifs.c
+++ b/drivers/isdn/capi/capifs.c
@@ -104,7 +104,6 @@ capifs_fill_super(struct super_block *s, void *data, int silent)
inode->i_ino = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
- inode->i_blksize = 1024;
inode->i_uid = inode->i_gid = 0;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &simple_dir_inode_operations;
@@ -149,7 +148,6 @@ void capifs_new_ncci(unsigned int number, dev_t device)
if (!inode)
return;
inode->i_ino = number+2;
- inode->i_blksize = 1024;
inode->i_uid = config.setuid ? config.uid : current->fsuid;
inode->i_gid = config.setgid ? config.gid : current->fsgid;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c
index 3845defd4901..0c937325a1b3 100644
--- a/drivers/isdn/gigaset/bas-gigaset.c
+++ b/drivers/isdn/gigaset/bas-gigaset.c
@@ -192,7 +192,7 @@ static char *get_usb_statmsg(int status)
return "bit stuffing error, timeout, or unknown USB error";
case -EILSEQ:
return "CRC mismatch, timeout, or unknown USB error";
- case -ETIMEDOUT:
+ case -ETIME:
return "timed out";
case -EPIPE:
return "endpoint stalled";
@@ -454,7 +454,7 @@ inline static int update_basstate(struct bas_cardstate *ucs,
* urb USB request block
* urb->context = inbuf structure for controller state
*/
-static void read_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+static void read_ctrl_callback(struct urb *urb)
{
struct inbuf_t *inbuf = urb->context;
struct cardstate *cs = inbuf->cs;
@@ -596,7 +596,7 @@ static int atread_submit(struct cardstate *cs, int timeout)
* urb USB request block
* urb->context = controller state structure
*/
-static void read_int_callback(struct urb *urb, struct pt_regs *regs)
+static void read_int_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
struct bas_cardstate *ucs = cs->hw.bas;
@@ -762,7 +762,7 @@ resubmit:
* urb USB request block of completed request
* urb->context = bc_state structure
*/
-static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
+static void read_iso_callback(struct urb *urb)
{
struct bc_state *bcs;
struct bas_bc_state *ubc;
@@ -827,7 +827,7 @@ static void read_iso_callback(struct urb *urb, struct pt_regs *regs)
* urb USB request block of completed request
* urb->context = isow_urbctx_t structure
*/
-static void write_iso_callback(struct urb *urb, struct pt_regs *regs)
+static void write_iso_callback(struct urb *urb)
{
struct isow_urbctx_t *ucx;
struct bas_bc_state *ubc;
@@ -1415,7 +1415,7 @@ static void req_timeout(unsigned long data)
* urb USB request block of completed request
* urb->context = hardware specific controller state structure
*/
-static void write_ctrl_callback(struct urb *urb, struct pt_regs *regs)
+static void write_ctrl_callback(struct urb *urb)
{
struct bas_cardstate *ucs = urb->context;
int rc;
@@ -1661,7 +1661,7 @@ static void complete_cb(struct cardstate *cs)
* urb USB request block of completed request
* urb->context = controller state structure
*/
-static void write_command_callback(struct urb *urb, struct pt_regs *regs)
+static void write_command_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
struct bas_cardstate *ucs = cs->hw.bas;
diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c
index bd2e4267528e..596f3aebe2f7 100644
--- a/drivers/isdn/gigaset/interface.c
+++ b/drivers/isdn/gigaset/interface.c
@@ -134,7 +134,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file,
static int if_write(struct tty_struct *tty,
const unsigned char *buf, int count);
-static struct tty_operations if_ops = {
+static const struct tty_operations if_ops = {
.open = if_open,
.close = if_close,
.ioctl = if_ioctl,
diff --git a/drivers/isdn/gigaset/proc.c b/drivers/isdn/gigaset/proc.c
index 9ae3a7f3e7b3..9ad840e95dbe 100644
--- a/drivers/isdn/gigaset/proc.c
+++ b/drivers/isdn/gigaset/proc.c
@@ -83,5 +83,6 @@ void gigaset_init_dev_sysfs(struct cardstate *cs)
return;
gig_dbg(DEBUG_INIT, "setting up sysfs");
- class_device_create_file(cs->class, &class_device_attr_cidmode);
+ if (class_device_create_file(cs->class, &class_device_attr_cidmode))
+ dev_err(cs->dev, "could not create sysfs attribute\n");
}
diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c
index 6e05d9d4a51a..4ffa9eb1c28e 100644
--- a/drivers/isdn/gigaset/usb-gigaset.c
+++ b/drivers/isdn/gigaset/usb-gigaset.c
@@ -362,7 +362,7 @@ static void gigaset_modem_fill(unsigned long data)
*
* It is called if the data was received from the device.
*/
-static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
+static void gigaset_read_int_callback(struct urb *urb)
{
struct inbuf_t *inbuf = urb->context;
struct cardstate *cs = inbuf->cs;
@@ -420,7 +420,7 @@ static void gigaset_read_int_callback(struct urb *urb, struct pt_regs *regs)
/* This callback routine is called when data was transmitted to the device. */
-static void gigaset_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void gigaset_write_bulk_callback(struct urb *urb)
{
struct cardstate *cs = urb->context;
unsigned long flags;
diff --git a/drivers/isdn/hardware/avm/avmcard.h b/drivers/isdn/hardware/avm/avmcard.h
index 3b431723c7cb..d964f07e4a56 100644
--- a/drivers/isdn/hardware/avm/avmcard.h
+++ b/drivers/isdn/hardware/avm/avmcard.h
@@ -554,7 +554,7 @@ void b1_register_appl(struct capi_ctr *ctrl, u16 appl,
void b1_release_appl(struct capi_ctr *ctrl, u16 appl);
u16 b1_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
void b1_parse_version(avmctrl_info *card);
-irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
+irqreturn_t b1_interrupt(int interrupt, void *devptr);
int b1ctl_read_proc(char *page, char **start, off_t off,
int count, int *eof, struct capi_ctr *ctrl);
@@ -567,7 +567,7 @@ void avmcard_dma_free(avmcard_dmainfo *);
int b1pciv4_detect(avmcard *card);
int t1pci_detect(avmcard *card);
void b1dma_reset(avmcard *card);
-irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs);
+irqreturn_t b1dma_interrupt(int interrupt, void *devptr);
int b1dma_load_firmware(struct capi_ctr *ctrl, capiloaddata *data);
void b1dma_reset_ctr(struct capi_ctr *ctrl);
diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c
index 0c7061d55027..da2729247713 100644
--- a/drivers/isdn/hardware/avm/b1.c
+++ b/drivers/isdn/hardware/avm/b1.c
@@ -485,7 +485,7 @@ void b1_parse_version(avmctrl_info *cinfo)
/* ------------------------------------------------------------- */
-irqreturn_t b1_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+irqreturn_t b1_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
avmctrl_info *cinfo = &card->ctrlinfo[0];
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index a4beeb46c859..ddd47cdfdb1f 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -628,7 +628,7 @@ static void b1dma_handle_interrupt(avmcard *card)
spin_unlock(&card->lock);
}
-irqreturn_t b1dma_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+irqreturn_t b1dma_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index 6c3d5f5f1f4b..2a3eb38f0ebb 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -713,7 +713,7 @@ static irqreturn_t c4_handle_interrupt(avmcard *card)
return IRQ_HANDLED;
}
-static irqreturn_t c4_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+static irqreturn_t c4_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
index 5a2f854d55b5..e47c60b0a8ec 100644
--- a/drivers/isdn/hardware/avm/t1isa.c
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -131,7 +131,7 @@ static int t1_detectandinit(unsigned int base, unsigned irq, int cardnr)
return 0;
}
-static irqreturn_t t1isa_interrupt(int interrupt, void *devptr, struct pt_regs *regs)
+static irqreturn_t t1isa_interrupt(int interrupt, void *devptr)
{
avmcard *card = devptr;
avmctrl_info *cinfo = &card->ctrlinfo[0];
diff --git a/drivers/isdn/hardware/eicon/Kconfig b/drivers/isdn/hardware/eicon/Kconfig
index 51e66bc64208..01d4afd9d843 100644
--- a/drivers/isdn/hardware/eicon/Kconfig
+++ b/drivers/isdn/hardware/eicon/Kconfig
@@ -47,7 +47,7 @@ config ISDN_DIVAS_MAINT
tristate "DIVA Maint driver support"
depends on ISDN_DIVAS && m
help
- Enable Divas Maintainance driver.
+ Enable Divas Maintenance driver.
endmenu
diff --git a/drivers/isdn/hardware/eicon/diva.c b/drivers/isdn/hardware/eicon/diva.c
index 8ab8027f33c0..ffa2afa77c2f 100644
--- a/drivers/isdn/hardware/eicon/diva.c
+++ b/drivers/isdn/hardware/eicon/diva.c
@@ -71,8 +71,6 @@ DivaIdiReqFunc(29)
DivaIdiReqFunc(30)
DivaIdiReqFunc(31)
-struct pt_regs;
-
/*
** LOCALS
*/
@@ -515,7 +513,7 @@ diva_xdi_read(void *adapter, void *os_handle, void __user *dst,
}
-irqreturn_t diva_os_irq_wrapper(int irq, void *context, struct pt_regs *regs)
+irqreturn_t diva_os_irq_wrapper(int irq, void *context)
{
diva_os_xdi_adapter_t *a = (diva_os_xdi_adapter_t *) context;
diva_xdi_clear_interrupts_proc_t clear_int_proc;
diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
index b7dadba13e82..dae2e83dd5e8 100644
--- a/drivers/isdn/hardware/eicon/divasmain.c
+++ b/drivers/isdn/hardware/eicon/divasmain.c
@@ -58,8 +58,7 @@ static char *DRIVERLNAME = "divas";
static char *DEVNAME = "Divas";
char *DRIVERRELEASE_DIVAS = "2.0";
-extern irqreturn_t diva_os_irq_wrapper(int irq, void *context,
- struct pt_regs *regs);
+extern irqreturn_t diva_os_irq_wrapper(int irq, void *context);
extern int create_divas_proc(void);
extern void remove_divas_proc(void);
extern void diva_get_vserial_number(PISDN_ADAPTER IoAdapter, char *buf);
diff --git a/drivers/isdn/hardware/eicon/dsp_defs.h b/drivers/isdn/hardware/eicon/dsp_defs.h
index b44950e06f32..fec1e381a688 100644
--- a/drivers/isdn/hardware/eicon/dsp_defs.h
+++ b/drivers/isdn/hardware/eicon/dsp_defs.h
@@ -34,9 +34,6 @@
*
* I/O functions returns -1 on error, 0 on EOF
*/
-#define OS_SEEK_SET 0
-#define OS_SEEK_CUR 1
-#define OS_SEEK_END 2
struct _OsFileHandle_;
typedef long ( * OsFileIo) (struct _OsFileHandle_ *handle,
void *buffer,
diff --git a/drivers/isdn/hisax/Kconfig b/drivers/isdn/hisax/Kconfig
index 6dfc94122dd9..eb57a988e048 100644
--- a/drivers/isdn/hisax/Kconfig
+++ b/drivers/isdn/hisax/Kconfig
@@ -321,7 +321,7 @@ config HISAX_HFC_PCI
help
This enables HiSax support for the HFC-S PCI 2BDS0 based cards.
- For more informations see under
+ For more information see under
<file:Documentation/isdn/README.hfc-pci>.
config HISAX_W6692
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
index 8ae08c41c853..bec59010bc66 100644
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -733,7 +733,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
wByteAMD(cs, 0x21, 0x82);
wByteAMD(cs, 0x21, 0x02);
spin_unlock_irqrestore(&cs->lock, flags);
- cs->irq_func(cs->irq, cs, NULL);
+ cs->irq_func(cs->irq, cs);
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: dbusy_timer_handler: Transmitter reset");
diff --git a/drivers/isdn/hisax/amd7930_fn.h b/drivers/isdn/hisax/amd7930_fn.h
index e039c3a0f2a2..1f4d80c5e5a6 100644
--- a/drivers/isdn/hisax/amd7930_fn.h
+++ b/drivers/isdn/hisax/amd7930_fn.h
@@ -1,4 +1,4 @@
-/* 2001/10/02
+/* drivers/isdn/hisax/amd7930_fn.h
*
* gerdes_amd7930.h Header-file included by
* gerdes_amd7930.c
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index 93ff941c48f1..61e69e9c4aa9 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -156,7 +156,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+asuscom_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
@@ -194,7 +194,7 @@ asuscom_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
static irqreturn_t
-asuscom_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+asuscom_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
diff --git a/drivers/isdn/hisax/avm_a1.c b/drivers/isdn/hisax/avm_a1.c
index 729e906bdc61..d9028e9b9b8f 100644
--- a/drivers/isdn/hisax/avm_a1.c
+++ b/drivers/isdn/hisax/avm_a1.c
@@ -101,7 +101,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+avm_a1_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
diff --git a/drivers/isdn/hisax/avm_a1p.c b/drivers/isdn/hisax/avm_a1p.c
index 574e252dfa43..c87fa3f9b298 100644
--- a/drivers/isdn/hisax/avm_a1p.c
+++ b/drivers/isdn/hisax/avm_a1p.c
@@ -140,7 +140,7 @@ WriteHSCXfifo(struct IsdnCardState *cs, int hscx, u_char * data, int size)
#include "hscx_irq.c"
static irqreturn_t
-avm_a1p_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+avm_a1p_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 369afd3a3a4b..b04a178e5021 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -651,7 +651,7 @@ inithdlc(struct IsdnCardState *cs)
}
static irqreturn_t
-avm_pcipnp_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+avm_pcipnp_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_long flags;
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index 87a630128a6c..871310d56a6e 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -125,7 +125,7 @@ WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
#include "jade_irq.c"
static irqreturn_t
-bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+bkm_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val = 0;
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index dae090a9a489..340310645346 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -140,7 +140,7 @@ set_ipac_active(struct IsdnCardState *cs, u_int active)
#include "hscx_irq.c"
static irqreturn_t
-bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+bkm_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index e10350360f2f..785b08554fca 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -631,7 +631,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
count = cs->status_end - cs->status_read + 1;
if (count >= len)
count = len;
- copy_to_user(p, cs->status_read, count);
+ if (copy_to_user(p, cs->status_read, count))
+ return -EFAULT;
cs->status_read += count;
if (cs->status_read > cs->status_end)
cs->status_read = cs->status_buf;
@@ -642,7 +643,8 @@ static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
cnt = HISAX_STATUS_BUFSIZE;
else
cnt = count;
- copy_to_user(p, cs->status_read, cnt);
+ if (copy_to_user(p, cs->status_read, cnt))
+ return -EFAULT;
p += cnt;
cs->status_read += cnt % HISAX_STATUS_BUFSIZE;
count -= cnt;
@@ -1721,11 +1723,11 @@ static void hisax_b_l1l2(struct hisax_if *ifc, int pr, void *arg)
hisax_b_sched_event(bcs, B_RCVBUFREADY);
break;
case PH_DATA | CONFIRM:
- bcs->tx_cnt -= (int) arg;
+ bcs->tx_cnt -= (long)arg;
if (test_bit(FLG_LLI_L1WAKEUP,&bcs->st->lli.flag)) {
u_long flags;
spin_lock_irqsave(&bcs->aclock, flags);
- bcs->ackcnt += (int) arg;
+ bcs->ackcnt += (long)arg;
spin_unlock_irqrestore(&bcs->aclock, flags);
schedule_event(bcs, B_ACKPENDING);
}
@@ -1789,7 +1791,7 @@ static void hisax_b_l2l1(struct PStack *st, int pr, void *arg)
switch (pr) {
case PH_ACTIVATE | REQUEST:
- B_L2L1(b_if, pr, (void *) st->l1.mode);
+ B_L2L1(b_if, pr, (void *)(unsigned long)st->l1.mode);
break;
case PH_DATA | REQUEST:
case PH_PULL | INDICATION:
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index e294fa3918f3..3dacfff93f5f 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -289,7 +289,7 @@ MemWriteHSCX_IPACX(struct IsdnCardState *cs, int hscx, u_char offset, u_char val
#include "hscx_irq.c"
static irqreturn_t
-diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+diva_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
@@ -319,7 +319,7 @@ diva_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
static irqreturn_t
-diva_irq_ipac_isa(int intno, void *dev_id, struct pt_regs *regs)
+diva_irq_ipac_isa(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista,val;
@@ -630,7 +630,7 @@ Memhscx_int_main(struct IsdnCardState *cs, u_char val)
}
static irqreturn_t
-diva_irq_ipac_pci(int intno, void *dev_id, struct pt_regs *regs)
+diva_irq_ipac_pci(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista,val;
@@ -685,7 +685,7 @@ Start_IPACPCI:
}
static irqreturn_t
-diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
+diva_irq_ipacx_pci(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
@@ -716,8 +716,10 @@ release_io_diva(struct IsdnCardState *cs)
*cfg = 0; /* disable INT0/1 */
*cfg = 2; /* reset pending INT0 */
- iounmap((void *)cs->hw.diva.cfg_reg);
- iounmap((void *)cs->hw.diva.pci_cfg);
+ if (cs->hw.diva.cfg_reg)
+ iounmap((void *)cs->hw.diva.cfg_reg);
+ if (cs->hw.diva.pci_cfg)
+ iounmap((void *)cs->hw.diva.pci_cfg);
return;
} else if (cs->subtyp != DIVA_IPAC_ISA) {
del_timer(&cs->hw.diva.tl);
@@ -734,6 +736,23 @@ release_io_diva(struct IsdnCardState *cs)
}
static void
+iounmap_diva(struct IsdnCardState *cs)
+{
+ if ((cs->subtyp == DIVA_IPAC_PCI) || (cs->subtyp == DIVA_IPACX_PCI)) {
+ if (cs->hw.diva.cfg_reg) {
+ iounmap((void *)cs->hw.diva.cfg_reg);
+ cs->hw.diva.cfg_reg = 0;
+ }
+ if (cs->hw.diva.pci_cfg) {
+ iounmap((void *)cs->hw.diva.pci_cfg);
+ cs->hw.diva.pci_cfg = 0;
+ }
+ }
+
+ return;
+}
+
+static void
reset_diva(struct IsdnCardState *cs)
{
if (cs->subtyp == DIVA_IPAC_ISA) {
@@ -1069,11 +1088,13 @@ setup_diva(struct IsdnCard *card)
if (!cs->irq) {
printk(KERN_WARNING "Diva: No IRQ for PCI card found\n");
+ iounmap_diva(cs);
return(0);
}
if (!cs->hw.diva.cfg_reg) {
printk(KERN_WARNING "Diva: No IO-Adr for PCI card found\n");
+ iounmap_diva(cs);
return(0);
}
cs->irq_flags |= IRQF_SHARED;
@@ -1123,6 +1144,7 @@ ready:
CardType[card->typ],
cs->hw.diva.cfg_reg,
cs->hw.diva.cfg_reg + bytecnt);
+ iounmap_diva(cs);
return (0);
}
}
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 3b3e318f6076..fab3e4ea0595 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -282,7 +282,7 @@ TimerRun(struct IsdnCardState *cs)
#include "hscx_irq.c"
static irqreturn_t
-elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+elsa_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_long flags;
@@ -361,7 +361,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
static irqreturn_t
-elsa_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+elsa_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_long flags;
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index 76c7d29d1b2f..b45de9d408d1 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -240,7 +240,7 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
}
static irqreturn_t
-enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+enpci_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
unsigned char s0val, s1val, ir;
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index fe2937267777..3efa719b6d29 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -243,7 +243,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+gazel_interrupt(int intno, void *dev_id)
{
#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
@@ -274,7 +274,7 @@ gazel_interrupt(int intno, void *dev_id, struct pt_regs *regs)
static irqreturn_t
-gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+gazel_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val;
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
index 3a5ca8a68fc4..d852c9d998b2 100644
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -424,7 +424,7 @@ bch_l2l1(struct hisax_if *ifc, int pr, void *arg)
struct hfc4s8s_btype *bch = ifc->priv;
struct hfc4s8s_l1 *l1 = bch->l1p;
struct sk_buff *skb = (struct sk_buff *) arg;
- int mode = (int) arg;
+ long mode = (long) arg;
u_long flags;
switch (pr) {
@@ -914,7 +914,7 @@ tx_d_frame(struct hfc4s8s_l1 *l1p)
struct sk_buff *skb;
u_char f1, f2;
u_char *cp;
- int cnt;
+ long cnt;
if (l1p->l1_state != 7)
return;
@@ -980,7 +980,8 @@ tx_b_frame(struct hfc4s8s_btype *bch)
struct sk_buff *skb;
struct hfc4s8s_l1 *l1 = bch->l1p;
u_char *cp;
- int cnt, max, hdlc_num, ack_len = 0;
+ int cnt, max, hdlc_num;
+ long ack_len = 0;
if (!l1->enabled || (bch->mode == L1_MODE_NULL))
return;
@@ -1267,7 +1268,7 @@ hfc4s8s_bh(hfc4s8s_hw * hw)
/* interrupt handler */
/*********************/
static irqreturn_t
-hfc4s8s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+hfc4s8s_interrupt(int intno, void *dev_id)
{
hfc4s8s_hw *hw = dev_id;
u_char b, ovr;
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index 1df60ca9481f..93f60b563515 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -931,7 +931,7 @@ receive_emsg(struct IsdnCardState *cs)
/* Interrupt handler */
/*********************/
static irqreturn_t
-hfcpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+hfcpci_interrupt(int intno, void *dev_id)
{
u_long flags;
struct IsdnCardState *cs = dev_id;
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index f27c1608a3a7..954d1536db1f 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -691,7 +691,7 @@ receive_emsg(struct IsdnCardState *cs)
/* Interrupt handler */
/*********************/
static irqreturn_t
-hfcsx_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+hfcsx_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char exval;
@@ -970,7 +970,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg)
break;
case (HW_TESTLOOP | REQUEST):
spin_lock_irqsave(&cs->lock, flags);
- switch ((int) arg) {
+ switch ((long) arg) {
case (1):
Write_hfc(cs, HFCSX_B1_SSL, 0x80); /* tx slot */
Write_hfc(cs, HFCSX_B1_RSL, 0x80); /* rx slot */
@@ -986,7 +986,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg)
default:
spin_unlock_irqrestore(&cs->lock, flags);
if (cs->debug & L1_DEB_WARN)
- debugl1(cs, "hfcsx_l1hw loop invalid %4x", (int) arg);
+ debugl1(cs, "hfcsx_l1hw loop invalid %4lx", arg);
return;
}
cs->hw.hfcsx.trm |= 0x80; /* enable IOM-loop */
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index b5e571a52694..7105b043add8 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -276,7 +276,7 @@ control_action_handler(hfcusb_data * hfc, int reg, int val, int action)
/* control completion routine handling background control cmds */
/***************************************************************/
static void
-ctrl_complete(struct urb *urb, struct pt_regs *regs)
+ctrl_complete(struct urb *urb)
{
hfcusb_data *hfc = (hfcusb_data *) urb->context;
ctrl_buft *buf;
@@ -603,7 +603,7 @@ static int iso_packets[8] =
/* transmit completion routine for all ISO tx fifos */
/*****************************************************/
static void
-tx_iso_complete(struct urb *urb, struct pt_regs *regs)
+tx_iso_complete(struct urb *urb)
{
iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
usb_fifo *fifo = context_iso_urb->owner_fifo;
@@ -696,7 +696,7 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs)
fifo->delete_flg = TRUE;
fifo->hif->l1l2(fifo->hif,
PH_DATA | CONFIRM,
- (void *) fifo->skbuff->
+ (void *) (unsigned long) fifo->skbuff->
truesize);
if (fifo->skbuff && fifo->delete_flg) {
dev_kfree_skb_any(fifo->skbuff);
@@ -726,7 +726,7 @@ tx_iso_complete(struct urb *urb, struct pt_regs *regs)
/* receive completion routine for all ISO tx fifos */
/*****************************************************/
static void
-rx_iso_complete(struct urb *urb, struct pt_regs *regs)
+rx_iso_complete(struct urb *urb)
{
iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context;
usb_fifo *fifo = context_iso_urb->owner_fifo;
@@ -919,7 +919,7 @@ collect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish)
/* receive completion routine for all rx fifos */
/***********************************************/
static void
-rx_complete(struct urb *urb, struct pt_regs *regs)
+rx_complete(struct urb *urb)
{
int len;
int status;
@@ -1144,7 +1144,7 @@ hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
set_hfcmode(hfc,
(fifo->fifonum ==
HFCUSB_B1_TX) ? 0 : 1,
- (int) arg);
+ (long) arg);
fifo->hif->l1l2(fifo->hif,
PH_ACTIVATE | INDICATION,
NULL);
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
index ec52c1a7c22a..6349367ed480 100644
--- a/drivers/isdn/hisax/hfc_usb.h
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -137,11 +137,11 @@ static struct hfcusb_symbolic_list urb_errlist[] = {
{-ENXIO, "URB already queued"},
{-EFBIG, "Too much ISO frames requested"},
{-ENOSR, "Buffer error (overrun)"},
- {-EPIPE, "Specified endpoint is stalled (device not responding)"},
+ {-EPIPE, "Specified endpoint is stalled"},
{-EOVERFLOW, "Babble (bad cable?)"},
{-EPROTO, "Bit-stuff error (bad cable?)"},
- {-EILSEQ, "CRC/Timeout"},
- {-ETIMEDOUT, "NAK (device does not respond)"},
+ {-EILSEQ, "CRC or missing token"},
+ {-ETIME, "Device did not respond"},
{-ESHUTDOWN, "Device unplugged"},
{-1, NULL}
};
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index 4e7f472877e9..57670dc5034d 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -21,7 +21,7 @@ extern const char *CardType[];
static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
static irqreturn_t
-hfcs_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+hfcs_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, stat;
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 75920aa0a3c5..159c5896061e 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -941,7 +941,7 @@ struct IsdnCardState {
int (*cardmsg) (struct IsdnCardState *, int, void *);
void (*setstack_d) (struct PStack *, struct IsdnCardState *);
void (*DC_Close) (struct IsdnCardState *);
- int (*irq_func) (int, void *, struct pt_regs *);
+ int (*irq_func) (int, void *);
int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *);
struct Channel channel[2+MAX_WAITING_CALLS];
struct BCState bcs[2+MAX_WAITING_CALLS];
@@ -1316,7 +1316,18 @@ void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
void iecpy(u_char * dest, u_char * iestart, int ieoffset);
#endif /* __KERNEL__ */
-#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
+/*
+ * Busywait delay for `jiffs' jiffies
+ */
+#define HZDELAY(jiffs) do { \
+ int tout = jiffs; \
+ \
+ while (tout--) { \
+ int loops = USEC_PER_SEC / HZ; \
+ while (loops--) \
+ udelay(1); \
+ } \
+ } while (0)
int ll_run(struct IsdnCardState *cs, int addfeatures);
int CallcNew(void);
diff --git a/drivers/isdn/hisax/hisax_fcpcipnp.c b/drivers/isdn/hisax/hisax_fcpcipnp.c
index 1d7cf3bd6aa3..f6db55a752c4 100644
--- a/drivers/isdn/hisax/hisax_fcpcipnp.c
+++ b/drivers/isdn/hisax/hisax_fcpcipnp.c
@@ -546,7 +546,7 @@ static inline void hdlc_xpr_irq(struct fritz_bcs *bcs)
}
bcs->tx_cnt = 0;
bcs->tx_skb = NULL;
- B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+ B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long)skb->truesize);
dev_kfree_skb_irq(skb);
}
@@ -635,7 +635,7 @@ static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
hdlc_fill_fifo(bcs);
break;
case PH_ACTIVATE | REQUEST:
- mode = (int) arg;
+ mode = (long) arg;
DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
modehdlc(bcs, mode);
B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
@@ -651,7 +651,7 @@ static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
// ----------------------------------------------------------------------
static irqreturn_t
-fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
+fcpci2_irq(int intno, void *dev)
{
struct fritz_adapter *adapter = dev;
unsigned char val;
@@ -671,7 +671,7 @@ fcpci2_irq(int intno, void *dev, struct pt_regs *regs)
}
static irqreturn_t
-fcpci_irq(int intno, void *dev, struct pt_regs *regs)
+fcpci_irq(int intno, void *dev)
{
struct fritz_adapter *adapter = dev;
unsigned char sval;
@@ -998,18 +998,15 @@ static int __init hisax_fcpcipnp_init(void)
retval = pci_register_driver(&fcpci_driver);
if (retval)
- goto out;
+ return retval;
#ifdef __ISAPNP__
retval = pnp_register_driver(&fcpnp_driver);
- if (retval < 0)
- goto out_unregister_pci;
+ if (retval < 0) {
+ pci_unregister_driver(&fcpci_driver);
+ return retval;
+ }
#endif
return 0;
-
- out_unregister_pci:
- pci_unregister_driver(&fcpci_driver);
- out:
- return retval;
}
static void __exit hisax_fcpcipnp_exit(void)
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index 2cf7b665609e..da706925d54d 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -608,7 +608,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, ICC_CMDR, 0x01); /* Transmitter reset */
- cs->irq_func(cs->irq, cs, NULL);
+ cs->irq_func(cs->irq, cs);
}
}
}
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index 565b7892c267..282f349408bc 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -609,7 +609,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
debugl1(cs, "D-Channel Busy no skb");
}
cs->writeisac(cs, ISAC_CMDR, 0x01); /* Transmitter reset */
- cs->irq_func(cs->irq, cs, NULL);
+ cs->irq_func(cs->irq, cs);
}
}
}
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
index 715a1a8cd694..55de06953540 100644
--- a/drivers/isdn/hisax/isurf.c
+++ b/drivers/isdn/hisax/isurf.c
@@ -83,7 +83,7 @@ WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
}
static irqreturn_t
-isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+isurf_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index 39717506c678..252d79de5e5e 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -125,7 +125,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+ix1micro_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
index 8c82519593a8..a81d175d9f64 100644
--- a/drivers/isdn/hisax/mic.c
+++ b/drivers/isdn/hisax/mic.c
@@ -120,7 +120,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+mic_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/netjet.h b/drivers/isdn/hisax/netjet.h
index 1080508f3c6a..4d89d3ea4173 100644
--- a/drivers/isdn/hisax/netjet.h
+++ b/drivers/isdn/hisax/netjet.h
@@ -66,7 +66,7 @@ void read_tiger(struct IsdnCardState *cs);
void write_tiger(struct IsdnCardState *cs);
void netjet_fill_dma(struct BCState *bcs);
-void netjet_interrupt(int intno, void *dev_id, struct pt_regs *regs);
+void netjet_interrupt(int intno, void *dev_id);
void inittiger(struct IsdnCardState *cs);
void release_io_netjet(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index 489022bdef7b..e5918c6fe73d 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -13,7 +13,6 @@
*
*/
-
#include <linux/init.h>
#include "hisax.h"
#include "isac.h"
@@ -45,33 +44,31 @@ static const char *niccy_revision = "$Revision: 1.21.2.4 $";
#define PCI_IRQ_DISABLE 0xff0000
#define PCI_IRQ_ASSERT 0x800000
-static inline u_char
-readreg(unsigned int ale, unsigned int adr, u_char off)
+static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
byteout(ale, off);
ret = bytein(adr);
- return (ret);
+ return ret;
}
-static inline void
-readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+static inline void readfifo(unsigned int ale, unsigned int adr, u_char off,
+ u_char *data, int size)
{
byteout(ale, off);
insb(adr, data, size);
}
-
-static inline void
-writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
+static inline void writereg(unsigned int ale, unsigned int adr, u_char off,
+ u_char data)
{
byteout(ale, off);
byteout(adr, data);
}
-static inline void
-writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
+static inline void writefifo(unsigned int ale, unsigned int adr, u_char off,
+ u_char *data, int size)
{
byteout(ale, off);
outsb(adr, data, size);
@@ -79,39 +76,34 @@ writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int siz
/* Interface functions */
-static u_char
-ReadISAC(struct IsdnCardState *cs, u_char offset)
+static u_char ReadISAC(struct IsdnCardState *cs, u_char offset)
{
- return (readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset));
+ return readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset);
}
-static void
-WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
+static void WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, offset, value);
}
-static void
-ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+static void ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
readfifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
}
-static void
-WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
+static void WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
writefifo(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, 0, data, size);
}
-static u_char
-ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
+static u_char ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
- return (readreg(cs->hw.niccy.hscx_ale,
- cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0)));
+ return readreg(cs->hw.niccy.hscx_ale,
+ cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0));
}
-static void
-WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
+static void WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset,
+ u_char value)
{
writereg(cs->hw.niccy.hscx_ale,
cs->hw.niccy.hscx, offset + (hscx ? 0x40 : 0), value);
@@ -130,8 +122,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
-static irqreturn_t
-niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t niccy_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
@@ -141,21 +132,23 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if (cs->subtyp == NICCY_PCI) {
int ival;
ival = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
- if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
+ if (!(ival & PCI_IRQ_ASSERT)) { /* IRQ not for us (shared) */
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
outl(ival, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
}
- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
- Start_HSCX:
+ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
+ HSCX_ISTA + 0x40);
+Start_HSCX:
if (val)
hscx_int_main(cs, val);
val = readreg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_ISTA);
- Start_ISAC:
+Start_ISAC:
if (val)
isac_interrupt(cs, val);
- val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_ISTA + 0x40);
+ val = readreg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx,
+ HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
@@ -168,21 +161,21 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
goto Start_ISAC;
}
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0xFF);
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0xFF);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,
+ 0xFF);
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.niccy.isac_ale, cs->hw.niccy.isac, ISAC_MASK, 0);
writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK, 0);
- writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40, 0);
+ writereg(cs->hw.niccy.hscx_ale, cs->hw.niccy.hscx, HSCX_MASK + 0x40,0);
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
-static void
-release_io_niccy(struct IsdnCardState *cs)
+static void release_io_niccy(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
int val;
-
+
val = inl(cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
val &= PCI_IRQ_DISABLE;
outl(val, cs->hw.niccy.cfg_reg + PCI_IRQ_CTRL_REG);
@@ -194,8 +187,7 @@ release_io_niccy(struct IsdnCardState *cs)
}
}
-static void
-niccy_reset(struct IsdnCardState *cs)
+static void niccy_reset(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
int val;
@@ -207,29 +199,28 @@ niccy_reset(struct IsdnCardState *cs)
inithscxisac(cs, 3);
}
-static int
-niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
+static int niccy_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
switch (mt) {
- case CARD_RESET:
- spin_lock_irqsave(&cs->lock, flags);
- niccy_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return(0);
- case CARD_RELEASE:
- release_io_niccy(cs);
- return(0);
- case CARD_INIT:
- spin_lock_irqsave(&cs->lock, flags);
- niccy_reset(cs);
- spin_unlock_irqrestore(&cs->lock, flags);
- return(0);
- case CARD_TEST:
- return(0);
+ case CARD_RESET:
+ spin_lock_irqsave(&cs->lock, flags);
+ niccy_reset(cs);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return 0;
+ case CARD_RELEASE:
+ release_io_niccy(cs);
+ return 0;
+ case CARD_INIT:
+ spin_lock_irqsave(&cs->lock, flags);
+ niccy_reset(cs);
+ spin_unlock_irqrestore(&cs->lock, flags);
+ return 0;
+ case CARD_TEST:
+ return 0;
}
- return(0);
+ return 0;
}
static struct pci_dev *niccy_dev __devinitdata = NULL;
@@ -237,8 +228,7 @@ static struct pci_dev *niccy_dev __devinitdata = NULL;
static struct pnp_card *pnp_c __devinitdata = NULL;
#endif
-int __devinit
-setup_niccy(struct IsdnCard *card)
+int __devinit setup_niccy(struct IsdnCard *card)
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
@@ -246,40 +236,44 @@ setup_niccy(struct IsdnCard *card)
strcpy(tmp, niccy_revision);
printk(KERN_INFO "HiSax: Niccy driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_NICCY)
- return (0);
+ return 0;
#ifdef __ISAPNP__
if (!card->para[1] && isapnp_present()) {
struct pnp_dev *pnp_d = NULL;
int err;
- if ((pnp_c = pnp_find_card(
- ISAPNP_VENDOR('S', 'D', 'A'),
- ISAPNP_FUNCTION(0x0150), pnp_c))) {
- if (!(pnp_d = pnp_find_dev(pnp_c,
- ISAPNP_VENDOR('S', 'D', 'A'),
- ISAPNP_FUNCTION(0x0150), pnp_d))) {
- printk(KERN_ERR "NiccyPnP: PnP error card found, no device\n");
- return (0);
+ pnp_c = pnp_find_card(ISAPNP_VENDOR('S', 'D', 'A'),
+ ISAPNP_FUNCTION(0x0150), pnp_c);
+ if (pnp_c) {
+ pnp_d = pnp_find_dev(pnp_c,
+ ISAPNP_VENDOR('S', 'D', 'A'),
+ ISAPNP_FUNCTION(0x0150), pnp_d);
+ if (!pnp_d) {
+ printk(KERN_ERR "NiccyPnP: PnP error card "
+ "found, no device\n");
+ return 0;
}
pnp_disable_dev(pnp_d);
err = pnp_activate_dev(pnp_d);
- if (err<0) {
- printk(KERN_WARNING "%s: pnp_activate_dev ret(%d)\n",
- __FUNCTION__, err);
- return(0);
+ if (err < 0) {
+ printk(KERN_WARNING "%s: pnp_activate_dev "
+ "ret(%d)\n", __FUNCTION__, err);
+ return 0;
}
card->para[1] = pnp_port_start(pnp_d, 0);
card->para[2] = pnp_port_start(pnp_d, 1);
card->para[0] = pnp_irq(pnp_d, 0);
- if (!card->para[0] || !card->para[1] || !card->para[2]) {
- printk(KERN_ERR "NiccyPnP:some resources are missing %ld/%lx/%lx\n",
- card->para[0], card->para[1], card->para[2]);
+ if (!card->para[0] || !card->para[1] ||
+ !card->para[2]) {
+ printk(KERN_ERR "NiccyPnP:some resources are "
+ "missing %ld/%lx/%lx\n",
+ card->para[0], card->para[1],
+ card->para[2]);
pnp_disable_dev(pnp_d);
- return(0);
+ return 0;
}
- } else {
+ } else
printk(KERN_INFO "NiccyPnP: no ISAPnP card found\n");
- }
}
#endif
if (card->para[1]) {
@@ -291,50 +285,51 @@ setup_niccy(struct IsdnCard *card)
cs->subtyp = NICCY_PNP;
cs->irq = card->para[0];
if (!request_region(cs->hw.niccy.isac, 2, "niccy data")) {
- printk(KERN_WARNING
- "HiSax: %s data port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.niccy.isac,
- cs->hw.niccy.isac + 1);
- return (0);
+ printk(KERN_WARNING "HiSax: %s data port %x-%x "
+ "already in use\n", CardType[card->typ],
+ cs->hw.niccy.isac, cs->hw.niccy.isac + 1);
+ return 0;
}
if (!request_region(cs->hw.niccy.isac_ale, 2, "niccy addr")) {
- printk(KERN_WARNING
- "HiSax: %s address port %x-%x already in use\n",
- CardType[card->typ],
+ printk(KERN_WARNING "HiSax: %s address port %x-%x "
+ "already in use\n", CardType[card->typ],
cs->hw.niccy.isac_ale,
cs->hw.niccy.isac_ale + 1);
release_region(cs->hw.niccy.isac, 2);
- return (0);
+ return 0;
}
} else {
#ifdef CONFIG_PCI
u_int pci_ioaddr;
cs->subtyp = 0;
if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
- PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
+ PCI_DEVICE_ID_SATSAGEM_NICCY,
+ niccy_dev))) {
if (pci_enable_device(niccy_dev))
- return(0);
+ return 0;
/* get IRQ */
if (!niccy_dev->irq) {
- printk(KERN_WARNING "Niccy: No IRQ for PCI card found\n");
- return(0);
+ printk(KERN_WARNING
+ "Niccy: No IRQ for PCI card found\n");
+ return 0;
}
cs->irq = niccy_dev->irq;
cs->hw.niccy.cfg_reg = pci_resource_start(niccy_dev, 0);
if (!cs->hw.niccy.cfg_reg) {
- printk(KERN_WARNING "Niccy: No IO-Adr for PCI cfg found\n");
- return(0);
+ printk(KERN_WARNING
+ "Niccy: No IO-Adr for PCI cfg found\n");
+ return 0;
}
pci_ioaddr = pci_resource_start(niccy_dev, 1);
if (!pci_ioaddr) {
- printk(KERN_WARNING "Niccy: No IO-Adr for PCI card found\n");
- return(0);
+ printk(KERN_WARNING
+ "Niccy: No IO-Adr for PCI card found\n");
+ return 0;
}
cs->subtyp = NICCY_PCI;
} else {
printk(KERN_WARNING "Niccy: No PCI card found\n");
- return(0);
+ return 0;
}
cs->irq_flags |= IRQF_SHARED;
cs->hw.niccy.isac = pci_ioaddr + ISAC_PCI_DATA;
@@ -343,29 +338,28 @@ setup_niccy(struct IsdnCard *card)
cs->hw.niccy.hscx_ale = pci_ioaddr + HSCX_PCI_ADDR;
if (!request_region(cs->hw.niccy.isac, 4, "niccy")) {
printk(KERN_WARNING
- "HiSax: %s data port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.niccy.isac,
- cs->hw.niccy.isac + 4);
- return (0);
+ "HiSax: %s data port %x-%x already in use\n",
+ CardType[card->typ],
+ cs->hw.niccy.isac, cs->hw.niccy.isac + 4);
+ return 0;
}
if (!request_region(cs->hw.niccy.cfg_reg, 0x40, "niccy pci")) {
printk(KERN_WARNING
"HiSax: %s pci port %x-%x already in use\n",
- CardType[card->typ],
- cs->hw.niccy.cfg_reg,
- cs->hw.niccy.cfg_reg + 0x40);
+ CardType[card->typ],
+ cs->hw.niccy.cfg_reg,
+ cs->hw.niccy.cfg_reg + 0x40);
release_region(cs->hw.niccy.isac, 4);
- return (0);
+ return 0;
}
#else
printk(KERN_WARNING "Niccy: io0 0 and NO_PCI_BIOS\n");
printk(KERN_WARNING "Niccy: unable to config NICCY PCI\n");
- return (0);
-#endif /* CONFIG_PCI */
+ return 0;
+#endif /* CONFIG_PCI */
}
printk(KERN_INFO "HiSax: %s %s config irq:%d data:0x%X ale:0x%X\n",
- CardType[cs->typ], (cs->subtyp==1) ? "PnP":"PCI",
+ CardType[cs->typ], (cs->subtyp == 1) ? "PnP" : "PCI",
cs->irq, cs->hw.niccy.isac, cs->hw.niccy.isac_ale);
setup_isac(cs);
cs->readisac = &ReadISAC;
@@ -379,10 +373,10 @@ setup_niccy(struct IsdnCard *card)
cs->irq_func = &niccy_interrupt;
ISACVersion(cs, "Niccy:");
if (HscxVersion(cs, "Niccy:")) {
- printk(KERN_WARNING
- "Niccy: wrong HSCX versions check IO address\n");
+ printk(KERN_WARNING "Niccy: wrong HSCX versions check IO "
+ "address\n");
release_io_niccy(cs);
- return (0);
+ return 0;
}
- return (1);
+ return 1;
}
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index 80025fd890f4..c09ffb135330 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -26,7 +26,7 @@ static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value
}
static irqreturn_t
-netjet_s_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+netjet_s_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, s1val, s0val;
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index 37497162d539..8202cf34ecae 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -26,7 +26,7 @@ static void dummywr(struct IsdnCardState *cs, int chan, u_char off, u_char value
}
static irqreturn_t
-netjet_u_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+netjet_u_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, sval;
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
index e76042d323ea..150ef68b4ae2 100644
--- a/drivers/isdn/hisax/s0box.c
+++ b/drivers/isdn/hisax/s0box.c
@@ -141,7 +141,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+s0box_interrupt(int intno, void *dev_id)
{
#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
index d943d365890b..c99b16690fb3 100644
--- a/drivers/isdn/hisax/saphir.c
+++ b/drivers/isdn/hisax/saphir.c
@@ -117,7 +117,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+saphir_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 8d8e8a299892..9522141f4351 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -260,7 +260,7 @@ WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+sedlbauer_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
@@ -306,7 +306,7 @@ sedlbauer_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
static irqreturn_t
-sedlbauer_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
+sedlbauer_interrupt_ipac(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 5;
@@ -353,7 +353,7 @@ Start_IPAC:
}
static irqreturn_t
-sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
+sedlbauer_interrupt_isar(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index a49b694eb730..02209500b3b7 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -99,7 +99,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+sportster_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/st5481_b.c b/drivers/isdn/hisax/st5481_b.c
index 22fd5db18d48..75d0f248e4ee 100644
--- a/drivers/isdn/hisax/st5481_b.c
+++ b/drivers/isdn/hisax/st5481_b.c
@@ -86,7 +86,7 @@ static void usb_b_out(struct st5481_bcs *bcs,int buf_nr)
if (!skb->len) {
// Frame sent
b_out->tx_skb = NULL;
- B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize);
+ B_L1L2(bcs, PH_DATA | CONFIRM, (void *)(unsigned long) skb->truesize);
dev_kfree_skb_any(skb);
/* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */
@@ -161,7 +161,7 @@ static void led_blink(struct st5481_adapter *adapter)
st5481_usb_device_ctrl_msg(adapter, GPIO_OUT, leds, NULL, NULL);
}
-static void usb_b_out_complete(struct urb *urb, struct pt_regs *regs)
+static void usb_b_out_complete(struct urb *urb)
{
struct st5481_bcs *bcs = urb->context;
struct st5481_b_out *b_out = &bcs->b_out;
@@ -350,7 +350,7 @@ void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
{
struct st5481_bcs *bcs = ifc->priv;
struct sk_buff *skb = arg;
- int mode;
+ long mode;
DBG(4, "");
@@ -360,8 +360,8 @@ void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg)
bcs->b_out.tx_skb = skb;
break;
case PH_ACTIVATE | REQUEST:
- mode = (int) arg;
- DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode);
+ mode = (long) arg;
+ DBG(4,"B%d,PH_ACTIVATE_REQUEST %ld", bcs->channel + 1, mode);
st5481B_mode(bcs, mode);
B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL);
break;
diff --git a/drivers/isdn/hisax/st5481_d.c b/drivers/isdn/hisax/st5481_d.c
index 493dc94992e5..1d8c2618366c 100644
--- a/drivers/isdn/hisax/st5481_d.c
+++ b/drivers/isdn/hisax/st5481_d.c
@@ -370,11 +370,11 @@ static void fifo_reseted(void *context)
FsmEvent(&adapter->d_out.fsm, EV_DOUT_RESETED, NULL);
}
-static void usb_d_out_complete(struct urb *urb, struct pt_regs *regs)
+static void usb_d_out_complete(struct urb *urb)
{
struct st5481_adapter *adapter = urb->context;
struct st5481_d_out *d_out = &adapter->d_out;
- int buf_nr;
+ long buf_nr;
DBG(2, "");
@@ -546,7 +546,7 @@ static void dout_reseted(struct FsmInst *fsm, int event, void *arg)
static void dout_complete(struct FsmInst *fsm, int event, void *arg)
{
struct st5481_adapter *adapter = fsm->userdata;
- int buf_nr = (int) arg;
+ long buf_nr = (long) arg;
usb_d_out(adapter, buf_nr);
}
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
index b096b64b0253..ff1595122048 100644
--- a/drivers/isdn/hisax/st5481_usb.c
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -125,7 +125,7 @@ void st5481_ph_command(struct st5481_adapter *adapter, unsigned int command)
* Call the user provided completion routine and try
* to send the next request.
*/
-static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs)
+static void usb_ctrl_complete(struct urb *urb)
{
struct st5481_adapter *adapter = urb->context;
struct st5481_ctrl *ctrl = &adapter->ctrl;
@@ -179,7 +179,7 @@ static void usb_ctrl_complete(struct urb *urb, struct pt_regs *regs)
* Decode the register values and schedule a private event.
* Called at interrupt.
*/
-static void usb_int_complete(struct urb *urb, struct pt_regs *regs)
+static void usb_int_complete(struct urb *urb)
{
u8 *data = urb->transfer_buffer;
u8 irqbyte;
@@ -483,7 +483,7 @@ void st5481_release_isocpipes(struct urb* urb[2])
* called 50 times per second with 20 ISOC descriptors.
* Called at interrupt.
*/
-static void usb_in_complete(struct urb *urb, struct pt_regs *regs)
+static void usb_in_complete(struct urb *urb)
{
struct st5481_in *in = urb->context;
unsigned char *ptr;
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index e94dc6f5bd62..0909662b7458 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -157,7 +157,7 @@ WriteHFC(struct IsdnCardState *cs, int data, u_char reg, u_char value)
}
static irqreturn_t
-TeleInt_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+TeleInt_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index f94af0930a17..48581335f43c 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -144,7 +144,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+teles0_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val;
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index 5cb712437da4..6a5e379e0774 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -101,7 +101,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+teles3_interrupt(int intno, void *dev_id)
{
#define MAXCOUNT 5
struct IsdnCardState *cs = dev_id;
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index dca446865f24..d09f6d033f15 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -226,7 +226,7 @@ WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
#include "hscx_irq.c"
static irqreturn_t
-telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+telespci_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char hval, ival;
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index 0595293b8659..1655341797a9 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -400,7 +400,7 @@ W6692B_interrupt(struct IsdnCardState *cs, u_char bchan)
}
static irqreturn_t
-W6692_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+W6692_interrupt(int intno, void *dev_id)
{
struct IsdnCardState *cs = dev_id;
u_char val, exval, v1;
@@ -715,7 +715,7 @@ dbusy_timer_handler(struct IsdnCardState *cs)
}
cs->writeW6692(cs, W_D_CMDR, W_D_CMDR_XRST); /* Transmitter reset */
spin_unlock_irqrestore(&cs->lock, flags);
- cs->irq_func(cs->irq, cs, NULL);
+ cs->irq_func(cs->irq, cs);
return;
}
}
diff --git a/drivers/isdn/hysdn/boardergo.c b/drivers/isdn/hysdn/boardergo.c
index 73afebdf80bd..82e42a80dc4b 100644
--- a/drivers/isdn/hysdn/boardergo.c
+++ b/drivers/isdn/hysdn/boardergo.c
@@ -33,7 +33,7 @@
/* The cards interrupt handler. Called from system */
/***************************************************/
static irqreturn_t
-ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
+ergo_interrupt(int intno, void *dev_id)
{
hysdn_card *card = dev_id; /* parameter from irq */
tErgDpram *dpr;
@@ -45,11 +45,10 @@ ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
if (!card->irq_enabled)
return IRQ_NONE; /* other device interrupting or irq switched off */
- save_flags(flags);
- cli(); /* no further irqs allowed */
+ spin_lock_irqsave(&card->hysdn_lock, flags); /* no further irqs allowed */
if (!(bytein(card->iobase + PCI9050_INTR_REG) & PCI9050_INTR_REG_STAT1)) {
- restore_flags(flags); /* restore old state */
+ spin_unlock_irqrestore(&card->hysdn_lock, flags); /* restore old state */
return IRQ_NONE; /* no interrupt requested by E1 */
}
/* clear any pending ints on the board */
@@ -61,7 +60,7 @@ ergo_interrupt(int intno, void *dev_id, struct pt_regs *regs)
/* start kernel task immediately after leaving all interrupts */
if (!card->hw_lock)
schedule_work(&card->irq_queue);
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
return IRQ_HANDLED;
} /* ergo_interrupt */
@@ -83,10 +82,9 @@ ergo_irq_bh(hysdn_card * card)
dpr = card->dpram; /* point to DPRAM */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->hysdn_lock, flags);
if (card->hw_lock) {
- restore_flags(flags); /* hardware currently unavailable */
+ spin_unlock_irqrestore(&card->hysdn_lock, flags); /* hardware currently unavailable */
return;
}
card->hw_lock = 1; /* we now lock the hardware */
@@ -120,7 +118,7 @@ ergo_irq_bh(hysdn_card * card)
card->hw_lock = 0; /* free hardware again */
} while (again); /* until nothing more to do */
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
} /* ergo_irq_bh */
@@ -137,8 +135,7 @@ ergo_stopcard(hysdn_card * card)
#ifdef CONFIG_HYSDN_CAPI
hycapi_capi_stop(card);
#endif /* CONFIG_HYSDN_CAPI */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->hysdn_lock, flags);
val = bytein(card->iobase + PCI9050_INTR_REG); /* get actual value */
val &= ~(PCI9050_INTR_REG_ENPCI | PCI9050_INTR_REG_EN1); /* mask irq */
byteout(card->iobase + PCI9050_INTR_REG, val);
@@ -147,7 +144,7 @@ ergo_stopcard(hysdn_card * card)
card->state = CARD_STATE_UNUSED;
card->err_log_state = ERRLOG_STATE_OFF; /* currently no log active */
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
} /* ergo_stopcard */
/**************************************************************************/
@@ -162,12 +159,11 @@ ergo_set_errlog_state(hysdn_card * card, int on)
card->err_log_state = ERRLOG_STATE_OFF; /* must be off */
return;
}
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->hysdn_lock, flags);
if (((card->err_log_state == ERRLOG_STATE_OFF) && !on) ||
((card->err_log_state == ERRLOG_STATE_ON) && on)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
return; /* nothing to do */
}
if (on)
@@ -175,7 +171,7 @@ ergo_set_errlog_state(hysdn_card * card, int on)
else
card->err_log_state = ERRLOG_STATE_STOP; /* request stop */
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
schedule_work(&card->irq_queue);
} /* ergo_set_errlog_state */
@@ -356,8 +352,7 @@ ergo_waitpofready(struct HYSDN_CARD *card)
if (card->debug_flags & LOG_POF_RECORD)
hysdn_addlog(card, "ERGO: pof boot success");
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->hysdn_lock, flags);
card->state = CARD_STATE_RUN; /* now card is running */
/* enable the cards interrupt */
@@ -370,7 +365,7 @@ ergo_waitpofready(struct HYSDN_CARD *card)
dpr->ToHyInt = 1;
dpr->ToPcInt = 1; /* interrupt to E1 for all cards */
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
if ((hynet_enable & (1 << card->myid))
&& (i = hysdn_net_create(card)))
{
@@ -408,7 +403,7 @@ ergo_releasehardware(hysdn_card * card)
free_irq(card->irq, card); /* release interrupt */
release_region(card->iobase + PCI9050_INTR_REG, 1); /* release all io ports */
release_region(card->iobase + PCI9050_USER_IO, 1);
- vfree(card->dpram);
+ iounmap(card->dpram);
card->dpram = NULL; /* release shared mem */
} /* ergo_releasehardware */
@@ -448,6 +443,7 @@ ergo_inithardware(hysdn_card * card)
card->waitpofready = ergo_waitpofready;
card->set_errlog_state = ergo_set_errlog_state;
INIT_WORK(&card->irq_queue, (void *) (void *) ergo_irq_bh, card);
+ card->hysdn_lock = SPIN_LOCK_UNLOCKED;
return (0);
} /* ergo_inithardware */
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
index 461e831592dd..729df4089385 100644
--- a/drivers/isdn/hysdn/hysdn_defs.h
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -188,6 +188,8 @@ typedef struct HYSDN_CARD {
/* init and deinit stopcard for booting, too */
void (*stopcard) (struct HYSDN_CARD *);
void (*releasehardware) (struct HYSDN_CARD *);
+
+ spinlock_t hysdn_lock;
#ifdef CONFIG_HYSDN_CAPI
struct hycapictrl_info {
char cardname[32];
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index c4301e8338ef..fcd49920b220 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -116,8 +116,7 @@ put_log_buffer(hysdn_card * card, char *cp)
strcpy(ib->log_start, cp); /* set output string */
ib->next = NULL;
ib->proc_ctrl = pd; /* point to own control structure */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->hysdn_lock, flags);
ib->usage_cnt = pd->if_used;
if (!pd->log_head)
pd->log_head = ib; /* new head */
@@ -125,7 +124,7 @@ put_log_buffer(hysdn_card * card, char *cp)
pd->log_tail->next = ib; /* follows existing messages */
pd->log_tail = ib; /* new tail */
i = pd->del_lock++; /* get lock state */
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
/* delete old entrys */
if (!i)
@@ -270,14 +269,13 @@ hysdn_log_open(struct inode *ino, struct file *filep)
} else if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) {
/* read access -> log/debug read */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->hysdn_lock, flags);
pd->if_used++;
if (pd->log_head)
filep->private_data = &pd->log_tail->next;
else
filep->private_data = &pd->log_head;
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
} else { /* simultaneous read/write access forbidden ! */
unlock_kernel();
return (-EPERM); /* no permission this time */
@@ -301,7 +299,7 @@ hysdn_log_close(struct inode *ino, struct file *filep)
hysdn_card *card;
int retval = 0;
unsigned long flags;
-
+ spinlock_t hysdn_lock = SPIN_LOCK_UNLOCKED;
lock_kernel();
if ((filep->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_WRITE) {
@@ -311,8 +309,7 @@ hysdn_log_close(struct inode *ino, struct file *filep)
/* read access -> log/debug read, mark one further file as closed */
pd = NULL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&hysdn_lock, flags);
inf = *((struct log_data **) filep->private_data); /* get first log entry */
if (inf)
pd = (struct procdata *) inf->proc_ctrl; /* still entries there */
@@ -335,7 +332,7 @@ hysdn_log_close(struct inode *ino, struct file *filep)
inf->usage_cnt--; /* decrement usage count for buffers */
inf = inf->next;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&hysdn_lock, flags);
if (pd)
if (pd->if_used <= 0) /* delete buffers if last file closed */
diff --git a/drivers/isdn/hysdn/hysdn_sched.c b/drivers/isdn/hysdn/hysdn_sched.c
index 1c0d54ac12ab..1fadf0133e9b 100644
--- a/drivers/isdn/hysdn/hysdn_sched.c
+++ b/drivers/isdn/hysdn/hysdn_sched.c
@@ -155,8 +155,7 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan)
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg chan=%d len=%d", chan, strlen(line) + 1);
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->hysdn_lock, flags);
while (card->async_busy) {
sti();
@@ -165,7 +164,7 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan)
msleep_interruptible(20); /* Timeout 20ms */
if (!--cnt) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
return (-ERR_ASYNC_TIME); /* timed out */
}
cli();
@@ -194,13 +193,13 @@ hysdn_tx_cfgline(hysdn_card *card, unsigned char *line, unsigned short chan)
msleep_interruptible(20); /* Timeout 20ms */
if (!--cnt) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
return (-ERR_ASYNC_TIME); /* timed out */
}
cli();
} /* wait for buffer to become free again */
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->hysdn_lock, flags);
if (card->debug_flags & LOG_SCHED_ASYN)
hysdn_addlog(card, "async tx-cfg data send");
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index c3d79eef9e32..69aee2602aa6 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -1134,9 +1134,12 @@ isdn_read(struct file *file, char __user *buf, size_t count, loff_t * off)
if (dev->drv[drvidx]->interface->readstat) {
if (count > dev->drv[drvidx]->stavail)
count = dev->drv[drvidx]->stavail;
- len = dev->drv[drvidx]->interface->
- readstat(buf, count, drvidx,
- isdn_minor2chan(minor));
+ len = dev->drv[drvidx]->interface->readstat(buf, count,
+ drvidx, isdn_minor2chan(minor));
+ if (len < 0) {
+ retval = len;
+ goto out;
+ }
} else {
len = 0;
}
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index 43da8ae1b2ad..1f8d6ae66b41 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -1614,8 +1614,8 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp)
struct sk_buff *skb;
unsigned char *p;
struct in_device *in_dev = NULL;
- u32 addr = 0; /* local ipv4 address */
- u32 mask = 0; /* local netmask */
+ __be32 addr = 0; /* local ipv4 address */
+ __be32 mask = 0; /* local netmask */
if ((in_dev = lp->netdev->dev.ip_ptr) != NULL) {
/* take primary(first) address of interface */
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index 9ab66e8960d5..2b91bb07fc7f 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -1860,7 +1860,7 @@ modem_write_profile(atemu * m)
send_sig(SIGIO, dev->profd, 1);
}
-static struct tty_operations modem_ops = {
+static const struct tty_operations modem_ops = {
.open = isdn_tty_open,
.close = isdn_tty_close,
.write = isdn_tty_write,
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 6649f8bc9951..730bbd07ebc7 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -1010,7 +1010,8 @@ icn_readstatus(u_char __user *buf, int len, icn_card * card)
for (p = buf, count = 0; count < len; p++, count++) {
if (card->msg_buf_read == card->msg_buf_write)
return count;
- put_user(*card->msg_buf_read++, p);
+ if (put_user(*card->msg_buf_read++, p))
+ return -EFAULT;
if (card->msg_buf_read > card->msg_buf_end)
card->msg_buf_read = card->msg_buf;
}
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index fabbd461603e..c3ae2edaf6fa 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -100,12 +100,11 @@ isdnloop_pollbchan(unsigned long data)
isdnloop_bchan_send(card, 1);
if (card->flags & (ISDNLOOP_FLAGS_B1ACTIVE | ISDNLOOP_FLAGS_B2ACTIVE)) {
/* schedule b-channel polling again */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
add_timer(&card->rb_timer);
card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
} else
card->flags &= ~ISDNLOOP_FLAGS_RBTIMER;
}
@@ -281,8 +280,7 @@ isdnloop_putmsg(isdnloop_card * card, unsigned char c)
{
ulong flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
*card->msg_buf_write++ = (c == 0xff) ? '\n' : c;
if (card->msg_buf_write == card->msg_buf_read) {
if (++card->msg_buf_read > card->msg_buf_end)
@@ -290,7 +288,7 @@ isdnloop_putmsg(isdnloop_card * card, unsigned char c)
}
if (card->msg_buf_write > card->msg_buf_end)
card->msg_buf_write = card->msg_buf;
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
/*
@@ -372,21 +370,19 @@ isdnloop_polldchan(unsigned long data)
if (!(card->flags & ISDNLOOP_FLAGS_RBTIMER)) {
/* schedule b-channel polling */
card->flags |= ISDNLOOP_FLAGS_RBTIMER;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
del_timer(&card->rb_timer);
card->rb_timer.function = isdnloop_pollbchan;
card->rb_timer.data = (unsigned long) card;
card->rb_timer.expires = jiffies + ISDNLOOP_TIMER_BCREAD;
add_timer(&card->rb_timer);
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
/* schedule again */
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
card->st_timer.expires = jiffies + ISDNLOOP_TIMER_DCREAD;
add_timer(&card->st_timer);
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
/*
@@ -416,8 +412,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card)
return 0;
if (card->sndcount[channel] > ISDNLOOP_MAX_SQUEUE)
return 0;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
nskb = dev_alloc_skb(skb->len);
if (nskb) {
memcpy(skb_put(nskb, len), skb->data, len);
@@ -426,7 +421,7 @@ isdnloop_sendbuf(int channel, struct sk_buff *skb, isdnloop_card * card)
} else
len = 0;
card->sndcount[channel] += len;
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
return len;
}
@@ -451,7 +446,8 @@ isdnloop_readstatus(u_char __user *buf, int len, isdnloop_card * card)
for (p = buf, count = 0; count < len; p++, count++) {
if (card->msg_buf_read == card->msg_buf_write)
return count;
- put_user(*card->msg_buf_read++, p);
+ if (put_user(*card->msg_buf_read++, p))
+ return -EFAULT;
if (card->msg_buf_read > card->msg_buf_end)
card->msg_buf_read = card->msg_buf;
}
@@ -576,8 +572,7 @@ isdnloop_atimeout(isdnloop_card * card, int ch)
unsigned long flags;
char buf[60];
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
if (card->rcard) {
isdnloop_fake(card->rcard[ch], "DDIS_I", card->rch[ch] + 1);
card->rcard[ch]->rcard[card->rch[ch]] = NULL;
@@ -587,7 +582,7 @@ isdnloop_atimeout(isdnloop_card * card, int ch)
/* No user responding */
sprintf(buf, "CAU%s", isdnloop_unicause(card, 1, 3));
isdnloop_fake(card, buf, ch + 1);
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
/*
@@ -622,8 +617,7 @@ isdnloop_start_ctimer(isdnloop_card * card, int ch)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
init_timer(&card->c_timer[ch]);
card->c_timer[ch].expires = jiffies + ISDNLOOP_TIMER_ALERTWAIT;
if (ch)
@@ -632,7 +626,7 @@ isdnloop_start_ctimer(isdnloop_card * card, int ch)
card->c_timer[ch].function = isdnloop_atimeout0;
card->c_timer[ch].data = (unsigned long) card;
add_timer(&card->c_timer[ch]);
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
/*
@@ -647,10 +641,9 @@ isdnloop_kill_ctimer(isdnloop_card * card, int ch)
{
unsigned long flags;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
del_timer(&card->c_timer[ch]);
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
static u_char si2bit[] =
@@ -706,13 +699,12 @@ isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd)
}
}
if (num_match) {
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
/* channel idle? */
if (!(cc->rcard[ch])) {
/* Check SI */
if (!(si2bit[cmd->parm.setup.si1] & cc->sil[ch])) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
return 3;
}
/* ch is idle, si and number matches */
@@ -720,10 +712,10 @@ isdnloop_try_call(isdnloop_card * card, char *p, int lch, isdn_ctrl * cmd)
cc->rch[ch] = lch;
card->rcard[lch] = cc;
card->rch[lch] = ch;
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
return 0;
} else {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
/* num matches, but busy */
if (ch == 1)
return 1;
@@ -1027,8 +1019,7 @@ isdnloop_stopcard(isdnloop_card * card)
unsigned long flags;
isdn_ctrl cmd;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
if (card->flags & ISDNLOOP_FLAGS_RUNNING) {
card->flags &= ~ISDNLOOP_FLAGS_RUNNING;
del_timer(&card->st_timer);
@@ -1039,7 +1030,7 @@ isdnloop_stopcard(isdnloop_card * card)
cmd.driver = card->myid;
card->interface.statcallb(&cmd);
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
/*
@@ -1078,18 +1069,17 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp)
return -EBUSY;
if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))
return -EFAULT;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&card->isdnloop_lock, flags);
switch (sdef.ptype) {
case ISDN_PTYPE_EURO:
if (isdnloop_fake(card, "DRV1.23EC-Q.931-CAPI-CNS-BASIS-20.02.96",
-1)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
return -ENOMEM;
}
card->sil[0] = card->sil[1] = 4;
if (isdnloop_fake(card, "TEI OK", 0)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
return -ENOMEM;
}
for (i = 0; i < 3; i++)
@@ -1098,12 +1088,12 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp)
case ISDN_PTYPE_1TR6:
if (isdnloop_fake(card, "DRV1.04TC-1TR6-CAPI-CNS-BASIS-29.11.95",
-1)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
return -ENOMEM;
}
card->sil[0] = card->sil[1] = 4;
if (isdnloop_fake(card, "TEI OK", 0)) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
return -ENOMEM;
}
strcpy(card->s0num[0], sdef.num[0]);
@@ -1111,7 +1101,7 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp)
card->s0num[2][0] = '\0';
break;
default:
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
printk(KERN_WARNING "isdnloop: Illegal D-channel protocol %d\n",
sdef.ptype);
return -EINVAL;
@@ -1122,7 +1112,7 @@ isdnloop_start(isdnloop_card * card, isdnloop_sdef * sdefp)
card->st_timer.data = (unsigned long) card;
add_timer(&card->st_timer);
card->flags |= ISDNLOOP_FLAGS_RUNNING;
- restore_flags(flags);
+ spin_unlock_irqrestore(&card->isdnloop_lock, flags);
return 0;
}
@@ -1472,6 +1462,7 @@ isdnloop_initcard(char *id)
skb_queue_head_init(&card->bqueue[i]);
}
skb_queue_head_init(&card->dqueue);
+ card->isdnloop_lock = SPIN_LOCK_UNLOCKED;
card->next = cards;
cards = card;
if (!register_isdn(&card->interface)) {
diff --git a/drivers/isdn/isdnloop/isdnloop.h b/drivers/isdn/isdnloop/isdnloop.h
index d699fe53e1c3..0d458a86f529 100644
--- a/drivers/isdn/isdnloop/isdnloop.h
+++ b/drivers/isdn/isdnloop/isdnloop.h
@@ -94,6 +94,7 @@ typedef struct isdnloop_card {
struct sk_buff_head
bqueue[ISDNLOOP_BCH]; /* B-Channel queues */
struct sk_buff_head dqueue; /* D-Channel queue */
+ spinlock_t isdnloop_lock;
} isdnloop_card;
/*
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index 94f21486bb24..6ead5e1508b7 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -725,23 +725,27 @@ static int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
if (stat_st < stat_end)
{
- copy_to_user(buf, statbuf + stat_st, len);
+ if (copy_to_user(buf, statbuf + stat_st, len))
+ return -EFAULT;
stat_st += len;
}
else
{
if (len > STATBUF_LEN - stat_st)
{
- copy_to_user(buf, statbuf + stat_st,
- STATBUF_LEN - stat_st);
- copy_to_user(buf, statbuf,
- len - (STATBUF_LEN - stat_st));
+ if (copy_to_user(buf, statbuf + stat_st,
+ STATBUF_LEN - stat_st))
+ return -EFAULT;
+ if (copy_to_user(buf, statbuf,
+ len - (STATBUF_LEN - stat_st)))
+ return -EFAULT;
stat_st = len - (STATBUF_LEN - stat_st);
}
else
{
- copy_to_user(buf, statbuf + stat_st, len);
+ if (copy_to_user(buf, statbuf + stat_st, len))
+ return -EFAULT;
stat_st += len;
diff --git a/drivers/isdn/pcbit/layer2.c b/drivers/isdn/pcbit/layer2.c
index ba766930f088..937fd2120381 100644
--- a/drivers/isdn/pcbit/layer2.c
+++ b/drivers/isdn/pcbit/layer2.c
@@ -311,6 +311,7 @@ pcbit_deliver(void *data)
dev->read_queue = frame->next;
spin_unlock_irqrestore(&dev->lock, flags);
+ msg = 0;
SET_MSG_CPU(msg, 0);
SET_MSG_PROC(msg, 0);
SET_MSG_CMD(msg, frame->skb->data[2]);
@@ -512,7 +513,7 @@ pcbit_firmware_bug(struct pcbit_dev *dev)
}
irqreturn_t
-pcbit_irq_handler(int interrupt, void *devptr, struct pt_regs *regs)
+pcbit_irq_handler(int interrupt, void *devptr)
{
struct pcbit_dev *dev;
u_char info,
diff --git a/drivers/isdn/pcbit/layer2.h b/drivers/isdn/pcbit/layer2.h
index 0d99da3a3e2b..2ac295e1a6e5 100644
--- a/drivers/isdn/pcbit/layer2.h
+++ b/drivers/isdn/pcbit/layer2.h
@@ -124,7 +124,7 @@ struct frame_buf {
extern int pcbit_l2_write(struct pcbit_dev * dev, ulong msg, ushort refnum,
struct sk_buff *skb, unsigned short hdr_len);
-extern irqreturn_t pcbit_irq_handler(int interrupt, void *, struct pt_regs *regs);
+extern irqreturn_t pcbit_irq_handler(int interrupt, void *);
extern struct pcbit_dev * dev_pcbit[MAX_PCBIT_CARDS];
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
index b4b24335f716..04b8a58f03b5 100644
--- a/drivers/isdn/sc/command.c
+++ b/drivers/isdn/sc/command.c
@@ -103,9 +103,6 @@ int command(isdn_ctrl *cmd)
return -ENODEV;
}
- pr_debug("%s: Received %s command from Link Layer\n",
- sc_adapter[card]->devicename, commands[cmd->command]);
-
/*
* Dispatch the command
*/
@@ -118,7 +115,7 @@ int command(isdn_ctrl *cmd)
memcpy(&cmdptr, cmd->parm.num, sizeof(unsigned long));
if (copy_from_user(&ioc, (scs_ioctl __user *)cmdptr,
sizeof(scs_ioctl))) {
- pr_debug("%s: Failed to verify user space 0x%x\n",
+ pr_debug("%s: Failed to verify user space 0x%lx\n",
sc_adapter[card]->devicename, cmdptr);
return -EFAULT;
}
@@ -195,7 +192,7 @@ static int dial(int card, unsigned long channel, setup_parm setup)
strlen(Phone),
(unsigned int *) Phone);
- pr_debug("%s: Dialing %s on channel %d\n",
+ pr_debug("%s: Dialing %s on channel %lu\n",
sc_adapter[card]->devicename, Phone, channel+1);
return status;
@@ -217,7 +214,7 @@ static int answer(int card, unsigned long channel)
}
indicate_status(card, ISDN_STAT_BCONN,channel,NULL);
- pr_debug("%s: Answered incoming call on channel %s\n",
+ pr_debug("%s: Answered incoming call on channel %lu\n",
sc_adapter[card]->devicename, channel+1);
return 0;
}
@@ -240,7 +237,7 @@ static int hangup(int card, unsigned long channel)
(unsigned char) channel+1,
0,
NULL);
- pr_debug("%s: Sent HANGUP message to channel %d\n",
+ pr_debug("%s: Sent HANGUP message to channel %lu\n",
sc_adapter[card]->devicename, channel+1);
return status;
}
@@ -260,9 +257,6 @@ static int setl2(int card, unsigned long arg)
protocol = arg >> 8;
channel = arg & 0xff;
sc_adapter[card]->channel[channel].l2_proto = protocol;
- pr_debug("%s: Level 2 protocol for channel %d set to %s from %d\n",
- sc_adapter[card]->devicename, channel+1,
- l2protos[sc_adapter[card]->channel[channel].l2_proto],protocol);
/*
* check that the adapter is also set to the correct protocol
@@ -293,8 +287,6 @@ static int setl3(int card, unsigned long channel)
}
sc_adapter[card]->channel[channel].l3_proto = protocol;
- pr_debug("%s: Level 3 protocol for channel %d set to %s\n",
- sc_adapter[card]->devicename, channel+1, l3protos[protocol]);
return 0;
}
@@ -311,7 +303,7 @@ static int acceptb(int card, unsigned long channel)
return -ENOBUFS;
}
- pr_debug("%s: B-Channel connection accepted on channel %d\n",
+ pr_debug("%s: B-Channel connection accepted on channel %lu\n",
sc_adapter[card]->devicename, channel+1);
indicate_status(card, ISDN_STAT_BCONN, channel, NULL);
return 0;
@@ -326,7 +318,7 @@ static int clreaz(int card, unsigned long arg)
strcpy(sc_adapter[card]->channel[arg].eazlist, "");
sc_adapter[card]->channel[arg].eazclear = 1;
- pr_debug("%s: EAZ List cleared for channel %d\n",
+ pr_debug("%s: EAZ List cleared for channel %lu\n",
sc_adapter[card]->devicename, arg+1);
return 0;
}
@@ -340,7 +332,7 @@ static int seteaz(int card, unsigned long arg, char *num)
strcpy(sc_adapter[card]->channel[arg].eazlist, num);
sc_adapter[card]->channel[arg].eazclear = 0;
- pr_debug("%s: EAZ list for channel %d set to: %s\n",
+ pr_debug("%s: EAZ list for channel %lu set to: %s\n",
sc_adapter[card]->devicename, arg+1,
sc_adapter[card]->channel[arg].eazlist);
return 0;
diff --git a/drivers/isdn/sc/event.c b/drivers/isdn/sc/event.c
index 5b8c7c1a7663..57367325ef04 100644
--- a/drivers/isdn/sc/event.c
+++ b/drivers/isdn/sc/event.c
@@ -45,8 +45,10 @@ int indicate_status(int card, int event,ulong Channel,char *Data)
{
isdn_ctrl cmd;
+#ifdef DEBUG
pr_debug("%s: Indicating event %s on Channel %d\n",
sc_adapter[card]->devicename, events[event-256], Channel);
+#endif
if (Data != NULL){
pr_debug("%s: Event data: %s\n", sc_adapter[card]->devicename,
Data);
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index a627e68023f6..06c9872e8c6a 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -35,7 +35,7 @@ module_param_array(irq, int, NULL, 0);
module_param_array(ram, int, NULL, 0);
module_param(do_reset, bool, 0);
-extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *);
+extern irqreturn_t interrupt_handler(int, void *);
extern int sndpkt(int, int, int, struct sk_buff *);
extern int command(isdn_ctrl *);
extern int indicate_status(int, int, ulong, char*);
@@ -98,13 +98,14 @@ static int __init sc_init(void)
* Confirm the I/O Address with a test
*/
if(io[b] == 0) {
- pr_debug("I/O Address 0x%x is in use.\n");
+ pr_debug("I/O Address invalid.\n");
continue;
}
outb(0x18, io[b] + 0x400 * EXP_PAGE0);
if(inb(io[b] + 0x400 * EXP_PAGE0) != 0x18) {
- pr_debug("I/O Base 0x%x fails test\n");
+ pr_debug("I/O Base 0x%x fails test\n",
+ io[b] + 0x400 * EXP_PAGE0);
continue;
}
}
@@ -158,8 +159,8 @@ static int __init sc_init(void)
outb(0xFF, io[b] + RESET_OFFSET);
msleep_interruptible(10000);
}
- pr_debug("RAM Base for board %d is 0x%x, %s probe\n", b, ram[b],
- ram[b] == 0 ? "will" : "won't");
+ pr_debug("RAM Base for board %d is 0x%lx, %s probe\n", b,
+ ram[b], ram[b] == 0 ? "will" : "won't");
if(ram[b]) {
/*
@@ -168,7 +169,7 @@ static int __init sc_init(void)
* board model
*/
if(request_region(ram[b], SRAM_PAGESIZE, "sc test")) {
- pr_debug("request_region for RAM base 0x%x succeeded\n", ram[b]);
+ pr_debug("request_region for RAM base 0x%lx succeeded\n", ram[b]);
model = identify_board(ram[b], io[b]);
release_region(ram[b], SRAM_PAGESIZE);
}
@@ -204,7 +205,7 @@ static int __init sc_init(void)
* Nope, there was no place in RAM for the
* board, or it couldn't be identified
*/
- pr_debug("Failed to find an adapter at 0x%x\n", ram[b]);
+ pr_debug("Failed to find an adapter at 0x%lx\n", ram[b]);
continue;
}
@@ -451,7 +452,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
HWConfig_pl hwci;
int x;
- pr_debug("Attempting to identify adapter @ 0x%x io 0x%x\n",
+ pr_debug("Attempting to identify adapter @ 0x%lx io 0x%x\n",
rambase, iobase);
/*
@@ -490,7 +491,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
outb(PRI_BASEPG_VAL, pgport);
msleep_interruptible(1000);
sig = readl(rambase + SIG_OFFSET);
- pr_debug("Looking for a signature, got 0x%x\n", sig);
+ pr_debug("Looking for a signature, got 0x%lx\n", sig);
if(sig == SIGNATURE)
return PRI_BOARD;
@@ -500,7 +501,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
outb(BRI_BASEPG_VAL, pgport);
msleep_interruptible(1000);
sig = readl(rambase + SIG_OFFSET);
- pr_debug("Looking for a signature, got 0x%x\n", sig);
+ pr_debug("Looking for a signature, got 0x%lx\n", sig);
if(sig == SIGNATURE)
return BRI_BOARD;
@@ -510,7 +511,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
* Try to spot a card
*/
sig = readl(rambase + SIG_OFFSET);
- pr_debug("Looking for a signature, got 0x%x\n", sig);
+ pr_debug("Looking for a signature, got 0x%lx\n", sig);
if(sig != SIGNATURE)
return -1;
@@ -540,7 +541,7 @@ static int identify_board(unsigned long rambase, unsigned int iobase)
memcpy_fromio(&rcvmsg, &(dpm->rsp_queue[dpm->rsp_tail]), MSG_LEN);
pr_debug("Got HWConfig response, status = 0x%x\n", rcvmsg.rsp_status);
memcpy(&hwci, &(rcvmsg.msg_data.HWCresponse), sizeof(HWConfig_pl));
- pr_debug("Hardware Config: Interface: %s, RAM Size: %d, Serial: %s\n"
+ pr_debug("Hardware Config: Interface: %s, RAM Size: %ld, Serial: %s\n"
" Part: %s, Rev: %s\n",
hwci.st_u_sense ? "S/T" : "U", hwci.ram_size,
hwci.serial_no, hwci.part_no, hwci.rev_no);
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
index 8631d338d69a..cd17de18cb76 100644
--- a/drivers/isdn/sc/interrupt.c
+++ b/drivers/isdn/sc/interrupt.c
@@ -45,7 +45,7 @@ static int get_card_from_irq(int irq)
/*
*
*/
-irqreturn_t interrupt_handler(int interrupt, void *cardptr, struct pt_regs *regs)
+irqreturn_t interrupt_handler(int interrupt, void *cardptr)
{
RspMessage rcvmsg;
@@ -91,7 +91,7 @@ irqreturn_t interrupt_handler(int interrupt, void *cardptr, struct pt_regs *regs
*/
if (IS_CE_MESSAGE(rcvmsg, Lnk, 1, Read))
{
- pr_debug("%s: Received packet 0x%x bytes long at 0x%x\n",
+ pr_debug("%s: Received packet 0x%x bytes long at 0x%lx\n",
sc_adapter[card]->devicename,
rcvmsg.msg_data.response.msg_len,
rcvmsg.msg_data.response.buff_offset);
diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
index f50defc38ae5..1e04676b016b 100644
--- a/drivers/isdn/sc/packet.c
+++ b/drivers/isdn/sc/packet.c
@@ -44,7 +44,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
return -ENODEV;
}
- pr_debug("%s: sndpkt: frst = 0x%x nxt = %d f = %d n = %d\n",
+ pr_debug("%s: sndpkt: frst = 0x%lx nxt = %d f = %d n = %d\n",
sc_adapter[card]->devicename,
sc_adapter[card]->channel[channel].first_sendbuf,
sc_adapter[card]->channel[channel].next_sendbuf,
@@ -66,7 +66,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
ReqLnkWrite.buff_offset = sc_adapter[card]->channel[channel].next_sendbuf *
BUFFER_SIZE + sc_adapter[card]->channel[channel].first_sendbuf;
ReqLnkWrite.msg_len = data->len; /* sk_buff size */
- pr_debug("%s: writing %d bytes to buffer offset 0x%x\n",
+ pr_debug("%s: writing %d bytes to buffer offset 0x%lx\n",
sc_adapter[card]->devicename,
ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset);
memcpy_toshmem(card, (char *)ReqLnkWrite.buff_offset, data->data, ReqLnkWrite.msg_len);
@@ -74,7 +74,7 @@ int sndpkt(int devId, int channel, struct sk_buff *data)
/*
* sendmessage
*/
- pr_debug("%s: sndpkt size=%d, buf_offset=0x%x buf_indx=%d\n",
+ pr_debug("%s: sndpkt size=%d, buf_offset=0x%lx buf_indx=%d\n",
sc_adapter[card]->devicename,
ReqLnkWrite.msg_len, ReqLnkWrite.buff_offset,
sc_adapter[card]->channel[channel].next_sendbuf);
@@ -124,7 +124,7 @@ void rcvpkt(int card, RspMessage *rcvmsg)
return;
}
skb_put(skb, rcvmsg->msg_data.response.msg_len);
- pr_debug("%s: getting data from offset: 0x%x\n",
+ pr_debug("%s: getting data from offset: 0x%lx\n",
sc_adapter[card]->devicename,
rcvmsg->msg_data.response.buff_offset);
memcpy_fromshmem(card,
@@ -143,7 +143,7 @@ void rcvpkt(int card, RspMessage *rcvmsg)
/* memset_shmem(card, rcvmsg->msg_data.response.buff_offset, 0, BUFFER_SIZE); */
newll.buff_offset = rcvmsg->msg_data.response.buff_offset;
newll.msg_len = BUFFER_SIZE;
- pr_debug("%s: recycled buffer at offset 0x%x size %d\n",
+ pr_debug("%s: recycled buffer at offset 0x%lx size %d\n",
sc_adapter[card]->devicename,
newll.buff_offset, newll.msg_len);
sendmessage(card, CEPID, ceReqTypeLnk, ceReqClass1, ceReqLnkRead,
@@ -186,7 +186,7 @@ int setup_buffers(int card, int c)
sc_adapter[card]->channel[c-1].num_sendbufs = nBuffers / 2;
sc_adapter[card]->channel[c-1].free_sendbufs = nBuffers / 2;
sc_adapter[card]->channel[c-1].next_sendbuf = 0;
- pr_debug("%s: send buffer setup complete: first=0x%x n=%d f=%d, nxt=%d\n",
+ pr_debug("%s: send buffer setup complete: first=0x%lx n=%d f=%d, nxt=%d\n",
sc_adapter[card]->devicename,
sc_adapter[card]->channel[c-1].first_sendbuf,
sc_adapter[card]->channel[c-1].num_sendbufs,
@@ -203,7 +203,7 @@ int setup_buffers(int card, int c)
((sc_adapter[card]->channel[c-1].first_sendbuf +
(nBuffers / 2) * buffer_size) + (buffer_size * i));
RcvBuffOffset.msg_len = buffer_size;
- pr_debug("%s: adding RcvBuffer #%d offset=0x%x sz=%d bufsz:%d\n",
+ pr_debug("%s: adding RcvBuffer #%d offset=0x%lx sz=%d bufsz:%d\n",
sc_adapter[card]->devicename,
i + 1, RcvBuffOffset.buff_offset,
RcvBuffOffset.msg_len,buffer_size);
diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
index 24854826ca45..6f58862992db 100644
--- a/drivers/isdn/sc/shmem.c
+++ b/drivers/isdn/sc/shmem.c
@@ -61,7 +61,7 @@ void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
- pr_debug("%s: copying %d bytes from %#x to %#x\n",
+ pr_debug("%s: copying %d bytes from %#lx to %#lx\n",
sc_adapter[card]->devicename, n,
(unsigned long) src,
sc_adapter[card]->rambase + ((unsigned long) dest %0x4000));
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
index aced19aac5a2..f43282be0ada 100644
--- a/drivers/isdn/sc/timer.c
+++ b/drivers/isdn/sc/timer.c
@@ -76,7 +76,7 @@ void check_reset(unsigned long data)
if (sc_adapter[card]->StartOnReset)
startproc(card);
} else {
- pr_debug("%s: No signature yet, waiting another %d jiffies.\n",
+ pr_debug("%s: No signature yet, waiting another %lu jiffies.\n",
sc_adapter[card]->devicename, CHECKRESET_TIME);
mod_timer(&sc_adapter[card]->reset_timer, jiffies+CHECKRESET_TIME);
spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index d424b4452028..3c1711210e38 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -91,6 +91,8 @@ EXPORT_SYMBOL_GPL(led_classdev_resume);
*/
int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
{
+ int rc;
+
led_cdev->class_dev = class_device_create(leds_class, NULL, 0,
parent, "%s", led_cdev->name);
if (unlikely(IS_ERR(led_cdev->class_dev)))
@@ -99,8 +101,10 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
class_set_devdata(led_cdev->class_dev, led_cdev);
/* register the attributes */
- class_device_create_file(led_cdev->class_dev,
- &class_device_attr_brightness);
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_brightness);
+ if (rc)
+ goto err_out;
/* add to the list of leds */
write_lock(&leds_list_lock);
@@ -110,22 +114,34 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
#ifdef CONFIG_LEDS_TRIGGERS
rwlock_init(&led_cdev->trigger_lock);
- led_trigger_set_default(led_cdev);
+ rc = class_device_create_file(led_cdev->class_dev,
+ &class_device_attr_trigger);
+ if (rc)
+ goto err_out_led_list;
- class_device_create_file(led_cdev->class_dev,
- &class_device_attr_trigger);
+ led_trigger_set_default(led_cdev);
#endif
printk(KERN_INFO "Registered led device: %s\n",
led_cdev->class_dev->class_id);
return 0;
+
+#ifdef CONFIG_LEDS_TRIGGERS
+err_out_led_list:
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_brightness);
+ list_del(&led_cdev->node);
+#endif
+err_out:
+ class_device_unregister(led_cdev->class_dev);
+ return rc;
}
EXPORT_SYMBOL_GPL(led_classdev_register);
/**
* led_classdev_unregister - unregisters a object of led_properties class.
- * @led_cdev: the led device to unreigister
+ * @led_cdev: the led device to unregister
*
* Unregisters a previously registered via led_classdev_register object.
*/
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
index 47f0ff196328..454fb0901f82 100644
--- a/drivers/leds/led-triggers.c
+++ b/drivers/leds/led-triggers.c
@@ -125,6 +125,7 @@ void led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trigger)
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
if (led_cdev->trigger->deactivate)
led_cdev->trigger->deactivate(led_cdev);
+ led_set_brightness(led_cdev, LED_OFF);
}
if (trigger) {
write_lock_irqsave(&trigger->leddev_list_lock, flags);
diff --git a/drivers/leds/leds-ams-delta.c b/drivers/leds/leds-ams-delta.c
index e9f06116c4d7..599878c8e714 100644
--- a/drivers/leds/leds-ams-delta.c
+++ b/drivers/leds/leds-ams-delta.c
@@ -8,7 +8,6 @@
* published by the Free Software Foundation.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
index 3b87951aa555..6f2d449ba983 100644
--- a/drivers/leds/leds-locomo.c
+++ b/drivers/leds/leds-locomo.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/leds/locomo.c
+ * linux/drivers/leds/leds-locomo.c
*
* Copyright (C) 2005 John Lenz <lenz@cs.wisc.edu>
*
diff --git a/drivers/leds/leds-net48xx.c b/drivers/leds/leds-net48xx.c
index 713c4a8aa77d..45ba3d45bcb8 100644
--- a/drivers/leds/leds-net48xx.c
+++ b/drivers/leds/leds-net48xx.c
@@ -16,6 +16,7 @@
#include <linux/leds.h>
#include <linux/err.h>
#include <asm/io.h>
+#include <linux/nsc_gpio.h>
#include <linux/scx200_gpio.h>
#define DRVNAME "net48xx-led"
@@ -26,10 +27,7 @@ static struct platform_device *pdev;
static void net48xx_error_led_set(struct led_classdev *led_cdev,
enum led_brightness value)
{
- if (value)
- scx200_gpio_set_high(NET48XX_ERROR_LED_GPIO);
- else
- scx200_gpio_set_low(NET48XX_ERROR_LED_GPIO);
+ scx200_gpio_ops.gpio_set(NET48XX_ERROR_LED_GPIO, value ? 1 : 0);
}
static struct led_classdev net48xx_error_led = {
@@ -81,7 +79,8 @@ static int __init net48xx_led_init(void)
{
int ret;
- if (!scx200_gpio_present()) {
+ /* small hack, but scx200_gpio doesn't set .dev if the probe fails */
+ if (!scx200_gpio_ops.dev) {
ret = -ENODEV;
goto out;
}
diff --git a/drivers/leds/ledtrig-timer.c b/drivers/leds/ledtrig-timer.c
index 179c2876b541..29a8818a32ec 100644
--- a/drivers/leds/ledtrig-timer.c
+++ b/drivers/leds/ledtrig-timer.c
@@ -123,6 +123,7 @@ static CLASS_DEVICE_ATTR(delay_off, 0644, led_delay_off_show,
static void timer_trig_activate(struct led_classdev *led_cdev)
{
struct timer_trig_data *timer_data;
+ int rc;
timer_data = kzalloc(sizeof(struct timer_trig_data), GFP_KERNEL);
if (!timer_data)
@@ -134,10 +135,21 @@ static void timer_trig_activate(struct led_classdev *led_cdev)
timer_data->timer.function = led_timer_function;
timer_data->timer.data = (unsigned long) led_cdev;
- class_device_create_file(led_cdev->class_dev,
+ rc = class_device_create_file(led_cdev->class_dev,
&class_device_attr_delay_on);
- class_device_create_file(led_cdev->class_dev,
+ if (rc) goto err_out;
+ rc = class_device_create_file(led_cdev->class_dev,
&class_device_attr_delay_off);
+ if (rc) goto err_out_delayon;
+
+ return;
+
+err_out_delayon:
+ class_device_remove_file(led_cdev->class_dev,
+ &class_device_attr_delay_on);
+err_out:
+ led_cdev->trigger_data = NULL;
+ kfree(timer_data);
}
static void timer_trig_deactivate(struct led_classdev *led_cdev)
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index d5d649f5ccdb..7f8477d3a661 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -186,7 +186,7 @@ config THERM_ADT746X
depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64
help
This driver provides some thermostat and fan control for the
- iBook G4, and the ATI based aluminium PowerBooks, allowing slighlty
+ iBook G4, and the ATI based aluminium PowerBooks, allowing slightly
better fan behaviour by default, and some manual control.
config THERM_PM72
diff --git a/drivers/macintosh/adb-iop.c b/drivers/macintosh/adb-iop.c
index d56d400b6aaa..17ef5d3c01b4 100644
--- a/drivers/macintosh/adb-iop.c
+++ b/drivers/macintosh/adb-iop.c
@@ -30,7 +30,7 @@
/*#define DEBUG_ADB_IOP*/
-extern void iop_ism_irq(int, void *, struct pt_regs *);
+extern void iop_ism_irq(int, void *);
static struct adb_request *current_req;
static struct adb_request *last_req;
@@ -78,7 +78,7 @@ static void adb_iop_end_req(struct adb_request *req, int state)
* This will be called when a packet has been successfully sent.
*/
-static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs)
+static void adb_iop_complete(struct iop_msg *msg)
{
struct adb_request *req;
uint flags;
@@ -100,7 +100,7 @@ static void adb_iop_complete(struct iop_msg *msg, struct pt_regs *regs)
* commands or autopoll packets) are received.
*/
-static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
+static void adb_iop_listen(struct iop_msg *msg)
{
struct adb_iopmsg *amsg = (struct adb_iopmsg *) msg->message;
struct adb_request *req;
@@ -143,7 +143,7 @@ static void adb_iop_listen(struct iop_msg *msg, struct pt_regs *regs)
req->reply_len = amsg->count + 1;
memcpy(req->reply, &amsg->cmd, req->reply_len);
} else {
- adb_input(&amsg->cmd, amsg->count + 1, regs,
+ adb_input(&amsg->cmd, amsg->count + 1,
amsg->flags & ADB_IOP_AUTOPOLL);
}
memcpy(msg->reply, msg->message, IOP_MSG_LEN);
@@ -266,7 +266,7 @@ int adb_iop_autopoll(int devs)
void adb_iop_poll(void)
{
if (adb_iop_state == idle) adb_iop_start();
- iop_ism_irq(0, (void *) ADB_IOP, NULL);
+ iop_ism_irq(0, (void *) ADB_IOP);
}
int adb_iop_reset_bus(void)
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 360f93f6fcdb..be0bd34ff6f9 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -103,7 +103,7 @@ static void adbdev_init(void);
static int try_handler_change(int, int);
static struct adb_handler {
- void (*handler)(unsigned char *, int, struct pt_regs *, int);
+ void (*handler)(unsigned char *, int, int);
int original_address;
int handler_id;
int busy;
@@ -522,7 +522,7 @@ bail:
the handler_id id it doesn't match. */
int
adb_register(int default_id, int handler_id, struct adb_ids *ids,
- void (*handler)(unsigned char *, int, struct pt_regs *, int))
+ void (*handler)(unsigned char *, int, int))
{
int i;
@@ -570,13 +570,13 @@ adb_unregister(int index)
}
void
-adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
+adb_input(unsigned char *buf, int nb, int autopoll)
{
int i, id;
static int dump_adb_input = 0;
unsigned long flags;
- void (*handler)(unsigned char *, int, struct pt_regs *, int);
+ void (*handler)(unsigned char *, int, int);
/* We skip keystrokes and mouse moves when the sleep process
* has been started. We stop autopoll, but this is another security
@@ -597,7 +597,7 @@ adb_input(unsigned char *buf, int nb, struct pt_regs *regs, int autopoll)
adb_handler[id].busy = 1;
write_unlock_irqrestore(&adb_handler_lock, flags);
if (handler != NULL) {
- (*handler)(buf, nb, regs, autopoll);
+ (*handler)(buf, nb, autopoll);
wmb();
adb_handler[id].busy = 0;
}
diff --git a/drivers/macintosh/adbhid.c b/drivers/macintosh/adbhid.c
index efd51e01c06e..5066e7a8ea9c 100644
--- a/drivers/macintosh/adbhid.c
+++ b/drivers/macintosh/adbhid.c
@@ -1,5 +1,5 @@
/*
- * drivers/input/adbhid.c
+ * drivers/macintosh/adbhid.c
*
* ADB HID driver for Power Macintosh computers.
*
@@ -222,7 +222,7 @@ static struct adbhid *adbhid[16];
static void adbhid_probe(void);
-static void adbhid_input_keycode(int, int, int, struct pt_regs *);
+static void adbhid_input_keycode(int, int, int);
static void init_trackpad(int id);
static void init_trackball(int id);
@@ -253,7 +253,7 @@ static struct adb_ids buttons_ids;
#define ADBMOUSE_MACALLY2 9 /* MacAlly 2-button mouse */
static void
-adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll)
+adbhid_keyboard_input(unsigned char *data, int nb, int apoll)
{
int id = (data[0] >> 4) & 0x0f;
@@ -266,13 +266,13 @@ adbhid_keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apo
/* first check this is from register 0 */
if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
return; /* ignore it */
- adbhid_input_keycode(id, data[1], 0, regs);
+ adbhid_input_keycode(id, data[1], 0);
if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
- adbhid_input_keycode(id, data[2], 0, regs);
+ adbhid_input_keycode(id, data[2], 0);
}
static void
-adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
+adbhid_input_keycode(int id, int keycode, int repeat)
{
struct adbhid *ahid = adbhid[id];
int up_flag;
@@ -282,7 +282,6 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
switch (keycode) {
case ADB_KEY_CAPSLOCK: /* Generate down/up events for CapsLock everytime. */
- input_regs(ahid->input, regs);
input_report_key(ahid->input, KEY_CAPSLOCK, 1);
input_report_key(ahid->input, KEY_CAPSLOCK, 0);
input_sync(ahid->input);
@@ -338,7 +337,6 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
}
if (adbhid[id]->keycode[keycode]) {
- input_regs(adbhid[id]->input, regs);
input_report_key(adbhid[id]->input,
adbhid[id]->keycode[keycode], !up_flag);
input_sync(adbhid[id]->input);
@@ -349,7 +347,7 @@ adbhid_input_keycode(int id, int keycode, int repeat, struct pt_regs *regs)
}
static void
-adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+adbhid_mouse_input(unsigned char *data, int nb, int autopoll)
{
int id = (data[0] >> 4) & 0x0f;
@@ -432,8 +430,6 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo
break;
}
- input_regs(adbhid[id]->input, regs);
-
input_report_key(adbhid[id]->input, BTN_LEFT, !((data[1] >> 7) & 1));
input_report_key(adbhid[id]->input, BTN_MIDDLE, !((data[2] >> 7) & 1));
@@ -449,7 +445,7 @@ adbhid_mouse_input(unsigned char *data, int nb, struct pt_regs *regs, int autopo
}
static void
-adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
+adbhid_buttons_input(unsigned char *data, int nb, int autopoll)
{
int id = (data[0] >> 4) & 0x0f;
@@ -458,8 +454,6 @@ adbhid_buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int auto
return;
}
- input_regs(adbhid[id]->input, regs);
-
switch (adbhid[id]->original_handler_id) {
default:
case 0x02: /* Adjustable keyboard button device */
diff --git a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
index 4b08852c35ee..797cef72258f 100644
--- a/drivers/macintosh/macio-adb.c
+++ b/drivers/macintosh/macio-adb.c
@@ -64,7 +64,7 @@ static DEFINE_SPINLOCK(macio_lock);
static int macio_probe(void);
static int macio_init(void);
-static irqreturn_t macio_adb_interrupt(int irq, void *arg, struct pt_regs *regs);
+static irqreturn_t macio_adb_interrupt(int irq, void *arg);
static int macio_send_request(struct adb_request *req, int sync);
static int macio_adb_autopoll(int devs);
static void macio_adb_poll(void);
@@ -189,8 +189,7 @@ static int macio_send_request(struct adb_request *req, int sync)
return 0;
}
-static irqreturn_t macio_adb_interrupt(int irq, void *arg,
- struct pt_regs *regs)
+static irqreturn_t macio_adb_interrupt(int irq, void *arg)
{
int i, n, err;
struct adb_request *req = NULL;
@@ -260,7 +259,7 @@ static irqreturn_t macio_adb_interrupt(int irq, void *arg,
(*done)(req);
}
if (ibuf_len)
- adb_input(ibuf, ibuf_len, regs, autopoll);
+ adb_input(ibuf, ibuf_len, autopoll);
return IRQ_RETVAL(handled);
}
@@ -271,6 +270,6 @@ static void macio_adb_poll(void)
local_irq_save(flags);
if (in_8(&adb->intr.r) != 0)
- macio_adb_interrupt(0, NULL, NULL);
+ macio_adb_interrupt(0, NULL);
local_irq_restore(flags);
}
diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c
index 090e40fc5013..ade25b3fbb35 100644
--- a/drivers/macintosh/smu.c
+++ b/drivers/macintosh/smu.c
@@ -145,7 +145,7 @@ static void smu_start_cmd(void)
}
-static irqreturn_t smu_db_intr(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t smu_db_intr(int irq, void *arg)
{
unsigned long flags;
struct smu_cmd *cmd;
@@ -224,7 +224,7 @@ static irqreturn_t smu_db_intr(int irq, void *arg, struct pt_regs *regs)
}
-static irqreturn_t smu_msg_intr(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t smu_msg_intr(int irq, void *arg)
{
/* I don't quite know what to do with this one, we seem to never
* receive it, so I suspect we have to arm it someway in the SMU
@@ -309,7 +309,7 @@ void smu_poll(void)
gpio = pmac_do_feature_call(PMAC_FTR_READ_GPIO, NULL, smu->doorbell);
if ((gpio & 7) == 7)
- smu_db_intr(smu->db_irq, smu, NULL);
+ smu_db_intr(smu->db_irq, smu);
}
EXPORT_SYMBOL(smu_poll);
@@ -870,7 +870,7 @@ int smu_queue_i2c(struct smu_i2c_cmd *cmd)
static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
{
- DECLARE_COMPLETION(comp);
+ DECLARE_COMPLETION_ONSTACK(comp);
unsigned int chunk;
struct smu_cmd cmd;
int rc;
@@ -917,7 +917,7 @@ static int smu_read_datablock(u8 *dest, unsigned int addr, unsigned int len)
static struct smu_sdbp_header *smu_create_sdb_partition(int id)
{
- DECLARE_COMPLETION(comp);
+ DECLARE_COMPLETION_ONSTACK(comp);
struct smu_simple_cmd cmd;
unsigned int addr, len, tlen;
struct smu_sdbp_header *hdr;
diff --git a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
index 7512d1c15207..df66291b1322 100644
--- a/drivers/macintosh/via-cuda.c
+++ b/drivers/macintosh/via-cuda.c
@@ -98,8 +98,8 @@ static int cuda_reset_adb_bus(void);
static int cuda_init_via(void);
static void cuda_start(void);
-static irqreturn_t cuda_interrupt(int irq, void *arg, struct pt_regs *regs);
-static void cuda_input(unsigned char *buf, int nb, struct pt_regs *regs);
+static irqreturn_t cuda_interrupt(int irq, void *arg);
+static void cuda_input(unsigned char *buf, int nb);
void cuda_poll(void);
static int cuda_write(struct adb_request *req);
@@ -437,12 +437,12 @@ cuda_poll(void)
* disable_irq(), would that work on m68k ? --BenH
*/
local_irq_save(flags);
- cuda_interrupt(0, NULL, NULL);
+ cuda_interrupt(0, NULL);
local_irq_restore(flags);
}
static irqreturn_t
-cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
+cuda_interrupt(int irq, void *arg)
{
int status;
struct adb_request *req = NULL;
@@ -594,12 +594,12 @@ cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
(*done)(req);
}
if (ibuf_len)
- cuda_input(ibuf, ibuf_len, regs);
+ cuda_input(ibuf, ibuf_len);
return IRQ_HANDLED;
}
static void
-cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
+cuda_input(unsigned char *buf, int nb)
{
int i;
@@ -615,7 +615,7 @@ cuda_input(unsigned char *buf, int nb, struct pt_regs *regs)
}
#endif /* CONFIG_XMON */
#ifdef CONFIG_ADB
- adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
+ adb_input(buf+2, nb-2, buf[1] & 0x40);
#endif /* CONFIG_ADB */
break;
diff --git a/drivers/macintosh/via-macii.c b/drivers/macintosh/via-macii.c
index 2a2ffe060169..5d88d5b0ad99 100644
--- a/drivers/macintosh/via-macii.c
+++ b/drivers/macintosh/via-macii.c
@@ -77,7 +77,7 @@ static volatile unsigned char *via;
static int macii_init_via(void);
static void macii_start(void);
-static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs);
+static irqreturn_t macii_interrupt(int irq, void *arg);
static void macii_retransmit(int);
static void macii_queue_poll(void);
@@ -295,7 +295,7 @@ static void macii_poll(void)
unsigned long flags;
local_irq_save(flags);
- if (via[IFR] & SR_INT) macii_interrupt(0, NULL, NULL);
+ if (via[IFR] & SR_INT) macii_interrupt(0, NULL);
local_irq_restore(flags);
}
@@ -410,7 +410,7 @@ static void macii_start(void)
* Note: As of 21/10/97, the MacII ADB part works including timeout detection
* and retransmit (Talk to the last active device).
*/
-static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t macii_interrupt(int irq, void *arg)
{
int x, adbdir;
unsigned long flags;
@@ -602,8 +602,7 @@ static irqreturn_t macii_interrupt(int irq, void *arg, struct pt_regs *regs)
current_req = req->next;
if (req->done) (*req->done)(req);
} else {
- adb_input(reply_buf, reply_ptr - reply_buf,
- regs, 0);
+ adb_input(reply_buf, reply_ptr - reply_buf, 0);
}
/*
diff --git a/drivers/macintosh/via-maciisi.c b/drivers/macintosh/via-maciisi.c
index 0129fcc3b183..1f0aa5dc9aa5 100644
--- a/drivers/macintosh/via-maciisi.c
+++ b/drivers/macintosh/via-maciisi.c
@@ -84,8 +84,8 @@ static int maciisi_init(void);
static int maciisi_send_request(struct adb_request* req, int sync);
static void maciisi_sync(struct adb_request *req);
static int maciisi_write(struct adb_request* req);
-static irqreturn_t maciisi_interrupt(int irq, void* arg, struct pt_regs* regs);
-static void maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs);
+static irqreturn_t maciisi_interrupt(int irq, void* arg);
+static void maciisi_input(unsigned char *buf, int nb);
static int maciisi_init_via(void);
static void maciisi_poll(void);
static int maciisi_start(void);
@@ -421,7 +421,7 @@ maciisi_poll(void)
local_irq_save(flags);
if (via[IFR] & SR_INT) {
- maciisi_interrupt(0, NULL, NULL);
+ maciisi_interrupt(0, NULL);
}
else /* avoid calling this function too quickly in a loop */
udelay(ADB_DELAY);
@@ -433,7 +433,7 @@ maciisi_poll(void)
register is either full or empty. In practice, I have no idea what
it means :( */
static irqreturn_t
-maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
+maciisi_interrupt(int irq, void* arg)
{
int status;
struct adb_request *req;
@@ -612,7 +612,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
/* Obviously, we got it */
reading_reply = 0;
} else {
- maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf, regs);
+ maciisi_input(maciisi_rbuf, reply_ptr - maciisi_rbuf);
}
maciisi_state = idle;
status = via[B] & (TIP|TREQ);
@@ -657,7 +657,7 @@ maciisi_interrupt(int irq, void* arg, struct pt_regs* regs)
}
static void
-maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs)
+maciisi_input(unsigned char *buf, int nb)
{
#ifdef DEBUG_MACIISI_ADB
int i;
@@ -665,7 +665,7 @@ maciisi_input(unsigned char *buf, int nb, struct pt_regs *regs)
switch (buf[0]) {
case ADB_PACKET:
- adb_input(buf+2, nb-2, regs, buf[1] & 0x40);
+ adb_input(buf+2, nb-2, buf[1] & 0x40);
break;
default:
#ifdef DEBUG_MACIISI_ADB
diff --git a/drivers/macintosh/via-pmu-backlight.c b/drivers/macintosh/via-pmu-backlight.c
index a82f313d9dc9..6c29fe727c0f 100644
--- a/drivers/macintosh/via-pmu-backlight.c
+++ b/drivers/macintosh/via-pmu-backlight.c
@@ -16,7 +16,7 @@
#define MAX_PMU_LEVEL 0xFF
static struct backlight_properties pmu_backlight_data;
-static spinlock_t pmu_backlight_lock;
+static DEFINE_SPINLOCK(pmu_backlight_lock);
static int sleeping;
static u8 bl_curve[FB_BACKLIGHT_LEVELS];
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index dda03985dcf5..e63ea1c1f3c1 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -191,8 +191,8 @@ static int pmu_adb_reset_bus(void);
static int init_pmu(void);
static void pmu_start(void);
-static irqreturn_t via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
-static irqreturn_t gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
+static irqreturn_t via_pmu_interrupt(int irq, void *arg);
+static irqreturn_t gpio1_interrupt(int irq, void *arg);
static int proc_get_info(char *page, char **start, off_t off,
int count, int *eof, void *data);
static int proc_get_irqstats(char *page, char **start, off_t off,
@@ -336,8 +336,10 @@ int __init find_via_pmu(void)
if (gaddr != OF_BAD_ADDR)
gpio_reg = ioremap(gaddr, 0x10);
}
- if (gpio_reg == NULL)
+ if (gpio_reg == NULL) {
printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
+ goto fail_gpio;
+ }
} else
pmu_kind = PMU_UNKNOWN;
@@ -365,6 +367,9 @@ int __init find_via_pmu(void)
return 1;
fail:
of_node_put(vias);
+ iounmap(gpio_reg);
+ gpio_reg = NULL;
+ fail_gpio:
vias = NULL;
return 0;
}
@@ -550,7 +555,7 @@ init_pmu(void)
}
if (pmu_state == idle)
adb_int_pending = 1;
- via_pmu_interrupt(0, NULL, NULL);
+ via_pmu_interrupt(0, NULL);
udelay(10);
}
@@ -1210,7 +1215,7 @@ pmu_poll(void)
return;
if (disable_poll)
return;
- via_pmu_interrupt(0, NULL, NULL);
+ via_pmu_interrupt(0, NULL);
}
void
@@ -1223,7 +1228,7 @@ pmu_poll_adb(void)
/* Kicks ADB read when PMU is suspended */
adb_int_pending = 1;
do {
- via_pmu_interrupt(0, NULL, NULL);
+ via_pmu_interrupt(0, NULL);
} while (pmu_suspended && (adb_int_pending || pmu_state != idle
|| req_awaiting_reply));
}
@@ -1234,7 +1239,7 @@ pmu_wait_complete(struct adb_request *req)
if (!via)
return;
while((pmu_state != idle && pmu_state != locked) || !req->complete)
- via_pmu_interrupt(0, NULL, NULL);
+ via_pmu_interrupt(0, NULL);
}
/* This function loops until the PMU is idle and prevents it from
@@ -1263,7 +1268,7 @@ pmu_suspend(void)
spin_unlock_irqrestore(&pmu_lock, flags);
if (req_awaiting_reply)
adb_int_pending = 1;
- via_pmu_interrupt(0, NULL, NULL);
+ via_pmu_interrupt(0, NULL);
spin_lock_irqsave(&pmu_lock, flags);
if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
#ifdef SUSPEND_USES_PMU
@@ -1313,7 +1318,7 @@ pmu_resume(void)
/* Interrupt data could be the result data from an ADB cmd */
static void
-pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+pmu_handle_data(unsigned char *data, int len)
{
unsigned char ints, pirq;
int i = 0;
@@ -1388,7 +1393,7 @@ next:
if (!(pmu_kind == PMU_OHARE_BASED && len == 4
&& data[1] == 0x2c && data[3] == 0xff
&& (data[2] & ~1) == 0xf4))
- adb_input(data+1, len-1, regs, 1);
+ adb_input(data+1, len-1, 1);
#endif /* CONFIG_ADB */
}
}
@@ -1426,7 +1431,7 @@ next:
}
static struct adb_request*
-pmu_sr_intr(struct pt_regs *regs)
+pmu_sr_intr(void)
{
struct adb_request *req;
int bite = 0;
@@ -1532,7 +1537,7 @@ pmu_sr_intr(struct pt_regs *regs)
}
static irqreturn_t
-via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+via_pmu_interrupt(int irq, void *arg)
{
unsigned long flags;
int intr;
@@ -1562,7 +1567,7 @@ via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
pmu_irq_stats[0]++;
}
if (intr & SR_INT) {
- req = pmu_sr_intr(regs);
+ req = pmu_sr_intr();
if (req)
break;
}
@@ -1608,7 +1613,7 @@ no_free_slot:
/* Deal with interrupt datas outside of the lock */
if (int_data >= 0) {
- pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs);
+ pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data]);
spin_lock_irqsave(&pmu_lock, flags);
++disable_poll;
int_data_state[int_data] = int_data_empty;
@@ -1633,7 +1638,7 @@ pmu_unlock(void)
static irqreturn_t
-gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
+gpio1_interrupt(int irq, void *arg)
{
unsigned long flags;
@@ -1646,7 +1651,7 @@ gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
pmu_irq_stats[1]++;
adb_int_pending = 1;
spin_unlock_irqrestore(&pmu_lock, flags);
- via_pmu_interrupt(0, NULL, NULL);
+ via_pmu_interrupt(0, NULL);
return IRQ_HANDLED;
}
return IRQ_NONE;
@@ -1827,7 +1832,7 @@ pbook_alloc_pci_save(void)
struct pci_dev *pd = NULL;
npci = 0;
- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
++npci;
}
if (npci == 0)
@@ -1857,9 +1862,11 @@ pbook_pci_save(void)
if (ps == NULL)
return;
- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
- if (npci-- == 0)
+ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ if (npci-- == 0) {
+ pci_dev_put(pd);
return;
+ }
#ifndef HACKED_PCI_SAVE
pci_read_config_word(pd, PCI_COMMAND, &ps->command);
pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
@@ -1887,11 +1894,13 @@ pbook_pci_restore(void)
int npci = pbook_npci_saves;
int j;
- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
#ifdef HACKED_PCI_SAVE
int i;
- if (npci-- == 0)
+ if (npci-- == 0) {
+ pci_dev_put(pd);
return;
+ }
ps++;
for (i=2;i<16;i++)
pci_write_config_dword(pd, i<<4, ps->config[i]);
@@ -2107,7 +2116,7 @@ pmac_wakeup_devices(void)
/* Force a poll of ADB interrupts */
adb_int_pending = 1;
- via_pmu_interrupt(0, NULL, NULL);
+ via_pmu_interrupt(0, NULL);
/* Restart jiffies & scheduling */
wakeup_decrementer();
diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c
index 35b70323e7e3..d9986f3a3fbf 100644
--- a/drivers/macintosh/via-pmu68k.c
+++ b/drivers/macintosh/via-pmu68k.c
@@ -107,7 +107,7 @@ BLOCKING_NOTIFIER_HEAD(sleep_notifier_list);
static int pmu_probe(void);
static int pmu_init(void);
static void pmu_start(void);
-static irqreturn_t pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
+static irqreturn_t pmu_interrupt(int irq, void *arg);
static int pmu_send_request(struct adb_request *req, int sync);
static int pmu_autopoll(int devs);
void pmu_poll(void);
@@ -118,8 +118,7 @@ static void pmu_start(void);
static void send_byte(int x);
static void recv_byte(void);
static void pmu_done(struct adb_request *req);
-static void pmu_handle_data(unsigned char *data, int len,
- struct pt_regs *regs);
+static void pmu_handle_data(unsigned char *data, int len);
static void set_volume(int level);
static void pmu_enable_backlight(int on);
static void pmu_set_brightness(int level);
@@ -222,7 +221,7 @@ pmu_init(void)
}
if (pmu_state == idle) {
adb_int_pending = 1;
- pmu_interrupt(0, NULL, NULL);
+ pmu_interrupt(0, NULL);
}
pmu_poll();
udelay(10);
@@ -563,17 +562,17 @@ pmu_poll(void)
local_irq_save(flags);
if (via1[IFR] & SR_INT) {
via1[IFR] = SR_INT;
- pmu_interrupt(IRQ_MAC_ADB_SR, NULL, NULL);
+ pmu_interrupt(IRQ_MAC_ADB_SR, NULL);
}
if (via1[IFR] & CB1_INT) {
via1[IFR] = CB1_INT;
- pmu_interrupt(IRQ_MAC_ADB_CL, NULL, NULL);
+ pmu_interrupt(IRQ_MAC_ADB_CL, NULL);
}
local_irq_restore(flags);
}
static irqreturn_t
-pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+pmu_interrupt(int irq, void *dev_id)
{
struct adb_request *req;
int timeout, bite = 0; /* to prevent compiler warning */
@@ -657,7 +656,7 @@ pmu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (pmu_state == reading_intr) {
- pmu_handle_data(interrupt_data, data_index, regs);
+ pmu_handle_data(interrupt_data, data_index);
} else {
req = current_req;
current_req = req->next;
@@ -701,7 +700,7 @@ pmu_done(struct adb_request *req)
/* Interrupt data could be the result data from an ADB cmd */
static void
-pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+pmu_handle_data(unsigned char *data, int len)
{
static int show_pmu_ints = 1;
@@ -726,7 +725,7 @@ pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
}
pmu_done(req);
} else {
- adb_input(data+1, len-1, regs, 1);
+ adb_input(data+1, len-1, 1);
}
} else {
if (data[0] == 0x08 && len == 3) {
@@ -843,7 +842,7 @@ pbook_pci_save(void)
struct pci_save *ps;
npci = 0;
- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL)
+ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL)
++npci;
n_pbook_pci_saves = npci;
if (npci == 0)
@@ -854,7 +853,7 @@ pbook_pci_save(void)
return;
pd = NULL;
- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
pci_read_config_word(pd, PCI_COMMAND, &ps->command);
pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat);
pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr);
@@ -871,7 +870,7 @@ pbook_pci_restore(void)
struct pci_dev *pd = NULL;
int j;
- while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
+ while ((pd = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) {
if (ps->command == 0)
continue;
pci_read_config_word(pd, PCI_COMMAND, &cmd);
diff --git a/drivers/macintosh/windfarm_pm112.c b/drivers/macintosh/windfarm_pm112.c
index ef66bf2778ec..fa4b13f89369 100644
--- a/drivers/macintosh/windfarm_pm112.c
+++ b/drivers/macintosh/windfarm_pm112.c
@@ -650,24 +650,26 @@ static struct notifier_block pm112_events = {
.notifier_call = pm112_wf_notify,
};
-static int wf_pm112_probe(struct device *dev)
+static int wf_pm112_probe(struct platform_device *dev)
{
wf_register_client(&pm112_events);
return 0;
}
-static int wf_pm112_remove(struct device *dev)
+static int __devexit wf_pm112_remove(struct platform_device *dev)
{
wf_unregister_client(&pm112_events);
/* should release all sensors and controls */
return 0;
}
-static struct device_driver wf_pm112_driver = {
- .name = "windfarm",
- .bus = &platform_bus_type,
+static struct platform_driver wf_pm112_driver = {
.probe = wf_pm112_probe,
- .remove = wf_pm112_remove,
+ .remove = __devexit_p(wf_pm112_remove),
+ .driver = {
+ .name = "windfarm",
+ .bus = &platform_bus_type,
+ },
};
static int __init wf_pm112_init(void)
@@ -683,13 +685,13 @@ static int __init wf_pm112_init(void)
++nr_cores;
printk(KERN_INFO "windfarm: initializing for dual-core desktop G5\n");
- driver_register(&wf_pm112_driver);
+ platform_driver_register(&wf_pm112_driver);
return 0;
}
static void __exit wf_pm112_exit(void)
{
- driver_unregister(&wf_pm112_driver);
+ platform_driver_unregister(&wf_pm112_driver);
}
module_init(wf_pm112_init);
diff --git a/drivers/macintosh/windfarm_pm81.c b/drivers/macintosh/windfarm_pm81.c
index 2ff546e4c92f..2a944851b8e1 100644
--- a/drivers/macintosh/windfarm_pm81.c
+++ b/drivers/macintosh/windfarm_pm81.c
@@ -131,8 +131,6 @@
static int wf_smu_mach_model; /* machine model id */
-static struct device *wf_smu_dev;
-
/* Controls & sensors */
static struct wf_sensor *sensor_cpu_power;
static struct wf_sensor *sensor_cpu_temp;
@@ -717,16 +715,14 @@ static int wf_init_pm(void)
return 0;
}
-static int wf_smu_probe(struct device *ddev)
+static int wf_smu_probe(struct platform_device *ddev)
{
- wf_smu_dev = ddev;
-
wf_register_client(&wf_smu_events);
return 0;
}
-static int wf_smu_remove(struct device *ddev)
+static int __devexit wf_smu_remove(struct platform_device *ddev)
{
wf_unregister_client(&wf_smu_events);
@@ -766,16 +762,16 @@ static int wf_smu_remove(struct device *ddev)
if (wf_smu_cpu_fans)
kfree(wf_smu_cpu_fans);
- wf_smu_dev = NULL;
-
return 0;
}
-static struct device_driver wf_smu_driver = {
- .name = "windfarm",
- .bus = &platform_bus_type,
+static struct platform_driver wf_smu_driver = {
.probe = wf_smu_probe,
- .remove = wf_smu_remove,
+ .remove = __devexit_p(wf_smu_remove),
+ .driver = {
+ .name = "windfarm",
+ .bus = &platform_bus_type,
+ },
};
@@ -794,7 +790,7 @@ static int __init wf_smu_init(void)
request_module("windfarm_lm75_sensor");
#endif /* MODULE */
- driver_register(&wf_smu_driver);
+ platform_driver_register(&wf_smu_driver);
}
return rc;
@@ -803,7 +799,7 @@ static int __init wf_smu_init(void)
static void __exit wf_smu_exit(void)
{
- driver_unregister(&wf_smu_driver);
+ platform_driver_unregister(&wf_smu_driver);
}
diff --git a/drivers/macintosh/windfarm_pm91.c b/drivers/macintosh/windfarm_pm91.c
index 59e9ffe37c39..9961a67b4f85 100644
--- a/drivers/macintosh/windfarm_pm91.c
+++ b/drivers/macintosh/windfarm_pm91.c
@@ -63,8 +63,6 @@
*/
#undef HACKED_OVERTEMP
-static struct device *wf_smu_dev;
-
/* Controls & sensors */
static struct wf_sensor *sensor_cpu_power;
static struct wf_sensor *sensor_cpu_temp;
@@ -641,16 +639,14 @@ static int wf_init_pm(void)
return 0;
}
-static int wf_smu_probe(struct device *ddev)
+static int wf_smu_probe(struct platform_device *ddev)
{
- wf_smu_dev = ddev;
-
wf_register_client(&wf_smu_events);
return 0;
}
-static int wf_smu_remove(struct device *ddev)
+static int __devexit wf_smu_remove(struct platform_device *ddev)
{
wf_unregister_client(&wf_smu_events);
@@ -698,16 +694,16 @@ static int wf_smu_remove(struct device *ddev)
if (wf_smu_cpu_fans)
kfree(wf_smu_cpu_fans);
- wf_smu_dev = NULL;
-
return 0;
}
-static struct device_driver wf_smu_driver = {
- .name = "windfarm",
- .bus = &platform_bus_type,
+static struct platform_driver wf_smu_driver = {
.probe = wf_smu_probe,
- .remove = wf_smu_remove,
+ .remove = __devexit_p(wf_smu_remove),
+ .driver = {
+ .name = "windfarm",
+ .bus = &platform_bus_type,
+ },
};
@@ -725,7 +721,7 @@ static int __init wf_smu_init(void)
request_module("windfarm_lm75_sensor");
#endif /* MODULE */
- driver_register(&wf_smu_driver);
+ platform_driver_register(&wf_smu_driver);
}
return rc;
@@ -734,7 +730,7 @@ static int __init wf_smu_init(void)
static void __exit wf_smu_exit(void)
{
- driver_unregister(&wf_smu_driver);
+ platform_driver_unregister(&wf_smu_driver);
}
diff --git a/drivers/macintosh/windfarm_smu_controls.c b/drivers/macintosh/windfarm_smu_controls.c
index bff1f372f188..31b750d61206 100644
--- a/drivers/macintosh/windfarm_smu_controls.c
+++ b/drivers/macintosh/windfarm_smu_controls.c
@@ -56,7 +56,7 @@ static int smu_set_fan(int pwm, u8 id, u16 value)
{
struct smu_cmd cmd;
u8 buffer[16];
- DECLARE_COMPLETION(comp);
+ DECLARE_COMPLETION_ONSTACK(comp);
int rc;
/* Fill SMU command structure */
diff --git a/drivers/macintosh/windfarm_smu_sat.c b/drivers/macintosh/windfarm_smu_sat.c
index aceb61d9fbc8..83f79de7174b 100644
--- a/drivers/macintosh/windfarm_smu_sat.c
+++ b/drivers/macintosh/windfarm_smu_sat.c
@@ -397,12 +397,7 @@ static int wf_sat_detach(struct i2c_client *client)
static int __init sat_sensors_init(void)
{
- int err;
-
- err = i2c_add_driver(&wf_sat_driver);
- if (err < 0)
- return err;
- return 0;
+ return i2c_add_driver(&wf_sat_driver);
}
static void __exit sat_sensors_exit(void)
diff --git a/drivers/macintosh/windfarm_smu_sensors.c b/drivers/macintosh/windfarm_smu_sensors.c
index defe9922ebd1..01b4c50143dd 100644
--- a/drivers/macintosh/windfarm_smu_sensors.c
+++ b/drivers/macintosh/windfarm_smu_sensors.c
@@ -67,7 +67,7 @@ static void smu_ads_release(struct wf_sensor *sr)
static int smu_read_adc(u8 id, s32 *value)
{
struct smu_simple_cmd cmd;
- DECLARE_COMPLETION(comp);
+ DECLARE_COMPLETION_ONSTACK(comp);
int rc;
rc = smu_queue_simple(&cmd, SMU_CMD_READ_ADC, 1,
diff --git a/drivers/mca/mca-bus.c b/drivers/mca/mca-bus.c
index 09baa43b2599..da862e4632dd 100644
--- a/drivers/mca/mca-bus.c
+++ b/drivers/mca/mca-bus.c
@@ -100,6 +100,7 @@ static DEVICE_ATTR(pos, S_IRUGO, mca_show_pos, NULL);
int __init mca_register_device(int bus, struct mca_device *mca_dev)
{
struct mca_bus *mca_bus = mca_root_busses[bus];
+ int rc;
mca_dev->dev.parent = &mca_bus->dev;
mca_dev->dev.bus = &mca_bus_type;
@@ -108,13 +109,23 @@ int __init mca_register_device(int bus, struct mca_device *mca_dev)
mca_dev->dev.dma_mask = &mca_dev->dma_mask;
mca_dev->dev.coherent_dma_mask = mca_dev->dma_mask;
- if (device_register(&mca_dev->dev))
- return 0;
+ rc = device_register(&mca_dev->dev);
+ if (rc)
+ goto err_out;
- device_create_file(&mca_dev->dev, &dev_attr_id);
- device_create_file(&mca_dev->dev, &dev_attr_pos);
+ rc = device_create_file(&mca_dev->dev, &dev_attr_id);
+ if (rc) goto err_out_devreg;
+ rc = device_create_file(&mca_dev->dev, &dev_attr_pos);
+ if (rc) goto err_out_id;
return 1;
+
+err_out_id:
+ device_remove_file(&mca_dev->dev, &dev_attr_id);
+err_out_devreg:
+ device_unregister(&mca_dev->dev);
+err_out:
+ return 0;
}
/* */
@@ -130,13 +141,16 @@ struct mca_bus * __devinit mca_attach_bus(int bus)
return NULL;
}
- mca_bus = kmalloc(sizeof(struct mca_bus), GFP_KERNEL);
+ mca_bus = kzalloc(sizeof(struct mca_bus), GFP_KERNEL);
if (!mca_bus)
return NULL;
- memset(mca_bus, 0, sizeof(struct mca_bus));
+
sprintf(mca_bus->dev.bus_id,"mca%d",bus);
sprintf(mca_bus->name,"Host %s MCA Bridge", bus ? "Secondary" : "Primary");
- device_register(&mca_bus->dev);
+ if (device_register(&mca_bus->dev)) {
+ kfree(mca_bus);
+ return NULL;
+ }
mca_root_busses[bus] = mca_bus;
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index bf869ed03eed..c92c1521546d 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -2,6 +2,8 @@
# Block device driver configuration
#
+if BLOCK
+
menu "Multi-device support (RAID and LVM)"
config MD
@@ -136,16 +138,16 @@ config MD_RAID456
If unsure, say Y.
config MD_RAID5_RESHAPE
- bool "Support adding drives to a raid-5 array (experimental)"
- depends on MD_RAID456 && EXPERIMENTAL
+ bool "Support adding drives to a raid-5 array"
+ depends on MD_RAID456
+ default y
---help---
A RAID-5 set can be expanded by adding extra drives. This
requires "restriping" the array which means (almost) every
block must be written to a different place.
This option allows such restriping to be done while the array
- is online. However it is still EXPERIMENTAL code. It should
- work, but please be sure that you have backups.
+ is online.
You will need mdadm version 2.4.1 or later to use this
feature safely. During the early stage of reshape there is
@@ -162,6 +164,8 @@ config MD_RAID5_RESHAPE
There should be enough spares already present to make the new
array workable.
+ If unsure, say Y.
+
config MD_MULTIPATH
tristate "Multipath I/O support"
depends on BLK_DEV_MD
@@ -199,6 +203,14 @@ config BLK_DEV_DM
If unsure, say N.
+config DM_DEBUG
+ boolean "Device mapper debugging support"
+ depends on BLK_DEV_DM && EXPERIMENTAL
+ ---help---
+ Enable this for messages that may help debug device-mapper problems.
+
+ If unsure, say N.
+
config DM_CRYPT
tristate "Crypt target support"
depends on BLK_DEV_DM && EXPERIMENTAL
@@ -251,3 +263,4 @@ config DM_MULTIPATH_EMC
endmenu
+endif
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index ecc56765d949..d6f614738bbd 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -536,7 +536,7 @@ static int bitmap_read_sb(struct bitmap *bitmap)
printk(KERN_INFO "%s: bitmap file is out of date (%llu < %llu) "
"-- forcing full recovery\n", bmname(bitmap), events,
(unsigned long long) bitmap->mddev->events);
- sb->state |= BITMAP_STALE;
+ sb->state |= cpu_to_le32(BITMAP_STALE);
}
success:
/* assign fields using values from superblock */
@@ -544,11 +544,11 @@ success:
bitmap->daemon_sleep = daemon_sleep;
bitmap->daemon_lastrun = jiffies;
bitmap->max_write_behind = write_behind;
- bitmap->flags |= sb->state;
+ bitmap->flags |= le32_to_cpu(sb->state);
if (le32_to_cpu(sb->version) == BITMAP_MAJOR_HOSTENDIAN)
bitmap->flags |= BITMAP_HOSTENDIAN;
bitmap->events_cleared = le64_to_cpu(sb->events_cleared);
- if (sb->state & BITMAP_STALE)
+ if (sb->state & cpu_to_le32(BITMAP_STALE))
bitmap->events_cleared = bitmap->mddev->events;
err = 0;
out:
@@ -578,9 +578,9 @@ static void bitmap_mask_state(struct bitmap *bitmap, enum bitmap_state bits,
spin_unlock_irqrestore(&bitmap->lock, flags);
sb = (bitmap_super_t *)kmap_atomic(bitmap->sb_page, KM_USER0);
switch (op) {
- case MASK_SET: sb->state |= bits;
+ case MASK_SET: sb->state |= cpu_to_le32(bits);
break;
- case MASK_UNSET: sb->state &= ~bits;
+ case MASK_UNSET: sb->state &= cpu_to_le32(~bits);
break;
default: BUG();
}
@@ -613,6 +613,7 @@ static inline unsigned long file_page_offset(unsigned long chunk)
static inline struct page *filemap_get_page(struct bitmap *bitmap,
unsigned long chunk)
{
+ if (file_page_index(chunk) >= bitmap->file_pages) return NULL;
return bitmap->filemap[file_page_index(chunk) - file_page_index(0)];
}
@@ -739,6 +740,7 @@ static void bitmap_file_set_bit(struct bitmap *bitmap, sector_t block)
}
page = filemap_get_page(bitmap, chunk);
+ if (!page) return;
bit = file_page_offset(chunk);
/* set the bit */
@@ -1322,6 +1324,18 @@ static void bitmap_set_memory_bits(struct bitmap *bitmap, sector_t offset, int n
}
+/* dirty the memory and file bits for bitmap chunks "s" to "e" */
+void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e)
+{
+ unsigned long chunk;
+
+ for (chunk = s; chunk <= e; chunk++) {
+ sector_t sec = chunk << CHUNK_BLOCK_SHIFT(bitmap);
+ bitmap_set_memory_bits(bitmap, sec, 1);
+ bitmap_file_set_bit(bitmap, sec);
+ }
+}
+
/*
* flush out any pending updates
*/
@@ -1399,7 +1413,7 @@ int bitmap_create(mddev_t *mddev)
int err;
sector_t start;
- BUG_ON(sizeof(bitmap_super_t) != 256);
+ BUILD_BUG_ON(sizeof(bitmap_super_t) != 256);
if (!file && !mddev->bitmap_offset) /* bitmap disabled, nothing to do */
return 0;
@@ -1430,8 +1444,7 @@ int bitmap_create(mddev_t *mddev)
if (err)
goto error;
- bitmap->chunkshift = find_first_bit(&bitmap->chunksize,
- sizeof(bitmap->chunksize));
+ bitmap->chunkshift = ffz(~bitmap->chunksize);
/* now that chunksize and chunkshift are set, we can use these macros */
chunks = (blocks + CHUNK_BLOCK_RATIO(bitmap) - 1) /
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index bdbd34993a80..a625576fdeeb 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003 Christophe Saout <christophe@saout.de>
* Copyright (C) 2004 Clemens Fruhwirth <clemens@endorphin.org>
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
*
* This file is released under the GPL.
*/
@@ -15,6 +16,7 @@
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/workqueue.h>
+#include <linux/backing-dev.h>
#include <asm/atomic.h>
#include <linux/scatterlist.h>
#include <asm/page.h>
@@ -22,17 +24,19 @@
#include "dm.h"
#define DM_MSG_PREFIX "crypt"
+#define MESG_STR(x) x, sizeof(x)
/*
* per bio private data
*/
struct crypt_io {
struct dm_target *target;
- struct bio *bio;
+ struct bio *base_bio;
struct bio *first_clone;
struct work_struct work;
atomic_t pending;
int error;
+ int post_process;
};
/*
@@ -63,6 +67,7 @@ struct crypt_iv_operations {
* Crypt: maps a linear range of a block device
* and encrypts / decrypts at the same time.
*/
+enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
struct crypt_config {
struct dm_dev *dev;
sector_t start;
@@ -73,6 +78,7 @@ struct crypt_config {
*/
mempool_t *io_pool;
mempool_t *page_pool;
+ struct bio_set *bs;
/*
* crypto related data
@@ -86,11 +92,12 @@ struct crypt_config {
char cipher[CRYPTO_MAX_ALG_NAME];
char chainmode[CRYPTO_MAX_ALG_NAME];
struct crypto_blkcipher *tfm;
+ unsigned long flags;
unsigned int key_size;
u8 key[0];
};
-#define MIN_IOS 256
+#define MIN_IOS 16
#define MIN_POOL_PAGES 32
#define MIN_BIO_PAGES 8
@@ -306,6 +313,14 @@ static int crypt_convert(struct crypt_config *cc,
return r;
}
+ static void dm_crypt_bio_destructor(struct bio *bio)
+ {
+ struct crypt_io *io = bio->bi_private;
+ struct crypt_config *cc = io->target->private;
+
+ bio_free(bio, cc->bs);
+ }
+
/*
* Generate a new unfragmented bio with the given size
* This should never violate the device limitations
@@ -315,34 +330,33 @@ static struct bio *
crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
struct bio *base_bio, unsigned int *bio_vec_idx)
{
- struct bio *bio;
+ struct bio *clone;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
unsigned int i;
- /*
- * Use __GFP_NOMEMALLOC to tell the VM to act less aggressively and
- * to fail earlier. This is not necessary but increases throughput.
- * FIXME: Is this really intelligent?
- */
- if (base_bio)
- bio = bio_clone(base_bio, GFP_NOIO|__GFP_NOMEMALLOC);
- else
- bio = bio_alloc(GFP_NOIO|__GFP_NOMEMALLOC, nr_iovecs);
- if (!bio)
+ 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);
+
+ if (!clone)
return NULL;
+ clone->bi_destructor = dm_crypt_bio_destructor;
+
/* if the last bio was not complete, continue where that one ended */
- bio->bi_idx = *bio_vec_idx;
- bio->bi_vcnt = *bio_vec_idx;
- bio->bi_size = 0;
- bio->bi_flags &= ~(1 << BIO_SEG_VALID);
+ clone->bi_idx = *bio_vec_idx;
+ clone->bi_vcnt = *bio_vec_idx;
+ clone->bi_size = 0;
+ clone->bi_flags &= ~(1 << BIO_SEG_VALID);
- /* bio->bi_idx pages have already been allocated */
- size -= bio->bi_idx * PAGE_SIZE;
+ /* clone->bi_idx pages have already been allocated */
+ size -= clone->bi_idx * PAGE_SIZE;
- for(i = bio->bi_idx; i < nr_iovecs; i++) {
- struct bio_vec *bv = bio_iovec_idx(bio, i);
+ for (i = clone->bi_idx; i < nr_iovecs; i++) {
+ struct bio_vec *bv = bio_iovec_idx(clone, i);
bv->bv_page = mempool_alloc(cc->page_pool, gfp_mask);
if (!bv->bv_page)
@@ -353,7 +367,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 - bio->bi_idx) == (MIN_BIO_PAGES - 1))
+ if ((i - clone->bi_idx) == (MIN_BIO_PAGES - 1))
gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
bv->bv_offset = 0;
@@ -362,13 +376,13 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
else
bv->bv_len = size;
- bio->bi_size += bv->bv_len;
- bio->bi_vcnt++;
+ clone->bi_size += bv->bv_len;
+ clone->bi_vcnt++;
size -= bv->bv_len;
}
- if (!bio->bi_size) {
- bio_put(bio);
+ if (!clone->bi_size) {
+ bio_put(clone);
return NULL;
}
@@ -376,13 +390,13 @@ crypt_alloc_buffer(struct crypt_config *cc, unsigned int size,
* Remember the last bio_vec allocated to be able
* to correctly continue after the splitting.
*/
- *bio_vec_idx = bio->bi_vcnt;
+ *bio_vec_idx = clone->bi_vcnt;
- return bio;
+ return clone;
}
static void crypt_free_buffer_pages(struct crypt_config *cc,
- struct bio *bio, unsigned int bytes)
+ struct bio *clone, unsigned int bytes)
{
unsigned int i, start, end;
struct bio_vec *bv;
@@ -396,19 +410,19 @@ static void crypt_free_buffer_pages(struct crypt_config *cc,
* A fix to the bi_idx issue in the kernel is in the works, so
* we will hopefully be able to revert to the cleaner solution soon.
*/
- i = bio->bi_vcnt - 1;
- bv = bio_iovec_idx(bio, i);
- end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - bio->bi_size;
+ i = clone->bi_vcnt - 1;
+ bv = bio_iovec_idx(clone, i);
+ end = (i << PAGE_SHIFT) + (bv->bv_offset + bv->bv_len) - clone->bi_size;
start = end - bytes;
start >>= PAGE_SHIFT;
- if (!bio->bi_size)
- end = bio->bi_vcnt;
+ if (!clone->bi_size)
+ end = clone->bi_vcnt;
else
end >>= PAGE_SHIFT;
- for(i = start; i < end; i++) {
- bv = bio_iovec_idx(bio, i);
+ for (i = start; i < end; i++) {
+ bv = bio_iovec_idx(clone, i);
BUG_ON(!bv->bv_page);
mempool_free(bv->bv_page, cc->page_pool);
bv->bv_page = NULL;
@@ -432,7 +446,7 @@ static void dec_pending(struct crypt_io *io, int error)
if (io->first_clone)
bio_put(io->first_clone);
- bio_endio(io->bio, io->bio->bi_size, io->error);
+ bio_endio(io->base_bio, io->base_bio->bi_size, io->error);
mempool_free(io, cc->io_pool);
}
@@ -441,29 +455,179 @@ static void dec_pending(struct crypt_io *io, int error)
* kcryptd:
*
* Needed because it would be very unwise to do decryption in an
- * interrupt context, so bios returning from read requests get
- * queued here.
+ * interrupt context.
*/
static struct workqueue_struct *_kcryptd_workqueue;
+static void kcryptd_do_work(void *data);
-static void kcryptd_do_work(void *data)
+static void kcryptd_queue_io(struct crypt_io *io)
{
- struct crypt_io *io = (struct crypt_io *) data;
- struct crypt_config *cc = (struct crypt_config *) io->target->private;
+ INIT_WORK(&io->work, kcryptd_do_work, io);
+ queue_work(_kcryptd_workqueue, &io->work);
+}
+
+static int crypt_endio(struct bio *clone, unsigned int done, int error)
+{
+ struct crypt_io *io = clone->bi_private;
+ struct crypt_config *cc = io->target->private;
+ unsigned read_io = bio_data_dir(clone) == READ;
+
+ /*
+ * free the processed pages, even if
+ * it's only a partially completed write
+ */
+ if (!read_io)
+ crypt_free_buffer_pages(cc, clone, done);
+
+ /* keep going - not finished yet */
+ if (unlikely(clone->bi_size))
+ return 1;
+
+ if (!read_io)
+ goto out;
+
+ if (unlikely(!bio_flagged(clone, BIO_UPTODATE))) {
+ error = -EIO;
+ goto out;
+ }
+
+ bio_put(clone);
+ io->post_process = 1;
+ kcryptd_queue_io(io);
+ return 0;
+
+out:
+ bio_put(clone);
+ dec_pending(io, error);
+ return error;
+}
+
+static void clone_init(struct crypt_io *io, struct bio *clone)
+{
+ struct crypt_config *cc = io->target->private;
+
+ clone->bi_private = io;
+ clone->bi_end_io = crypt_endio;
+ clone->bi_bdev = cc->dev->bdev;
+ clone->bi_rw = io->base_bio->bi_rw;
+}
+
+static void process_read(struct crypt_io *io)
+{
+ struct crypt_config *cc = io->target->private;
+ struct bio *base_bio = io->base_bio;
+ struct bio *clone;
+ sector_t sector = base_bio->bi_sector - io->target->begin;
+
+ atomic_inc(&io->pending);
+
+ /*
+ * The block layer might modify the bvec array, so always
+ * copy the required bvecs because we need the original
+ * one in order to decrypt the whole bio data *afterwards*.
+ */
+ clone = bio_alloc_bioset(GFP_NOIO, bio_segments(base_bio), cc->bs);
+ if (unlikely(!clone)) {
+ dec_pending(io, -ENOMEM);
+ return;
+ }
+
+ 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;
+ clone->bi_sector = cc->start + sector;
+ memcpy(clone->bi_io_vec, bio_iovec(base_bio),
+ sizeof(struct bio_vec) * clone->bi_vcnt);
+
+ generic_make_request(clone);
+}
+
+static void process_write(struct crypt_io *io)
+{
+ struct crypt_config *cc = io->target->private;
+ struct bio *base_bio = io->base_bio;
+ struct bio *clone;
struct convert_context ctx;
- int r;
+ unsigned remaining = base_bio->bi_size;
+ sector_t sector = base_bio->bi_sector - io->target->begin;
+ unsigned bvec_idx = 0;
+
+ atomic_inc(&io->pending);
+
+ crypt_convert_init(cc, &ctx, NULL, base_bio, sector, 1);
+
+ /*
+ * The allocated buffers can be smaller than the whole bio,
+ * 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);
+ if (unlikely(!clone)) {
+ dec_pending(io, -ENOMEM);
+ return;
+ }
+
+ ctx.bio_out = clone;
+
+ if (unlikely(crypt_convert(cc, &ctx) < 0)) {
+ crypt_free_buffer_pages(cc, clone, clone->bi_size);
+ bio_put(clone);
+ dec_pending(io, -EIO);
+ return;
+ }
- crypt_convert_init(cc, &ctx, io->bio, io->bio,
- io->bio->bi_sector - io->target->begin, 0);
- r = crypt_convert(cc, &ctx);
+ 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;
+ }
+
+ remaining -= clone->bi_size;
+ sector += bio_sectors(clone);
- dec_pending(io, r);
+ /* prevent bio_put of first_clone */
+ if (remaining)
+ atomic_inc(&io->pending);
+
+ generic_make_request(clone);
+
+ /* out of memory -> run queues */
+ if (remaining)
+ congestion_wait(bio_data_dir(clone), HZ/100);
+ }
}
-static void kcryptd_queue_io(struct crypt_io *io)
+static void process_read_endio(struct crypt_io *io)
{
- INIT_WORK(&io->work, kcryptd_do_work, io);
- queue_work(_kcryptd_workqueue, &io->work);
+ struct crypt_config *cc = io->target->private;
+ struct convert_context ctx;
+
+ crypt_convert_init(cc, &ctx, io->base_bio, io->base_bio,
+ io->base_bio->bi_sector - io->target->begin, 0);
+
+ dec_pending(io, crypt_convert(cc, &ctx));
+}
+
+static void kcryptd_do_work(void *data)
+{
+ struct crypt_io *io = data;
+
+ if (io->post_process)
+ process_read_endio(io);
+ else if (bio_data_dir(io->base_bio) == READ)
+ process_read(io);
+ else
+ process_write(io);
}
/*
@@ -477,7 +641,7 @@ static int crypt_decode_key(u8 *key, char *hex, unsigned int size)
buffer[2] = '\0';
- for(i = 0; i < size; i++) {
+ for (i = 0; i < size; i++) {
buffer[0] = *hex++;
buffer[1] = *hex++;
@@ -500,13 +664,38 @@ static void crypt_encode_key(char *hex, u8 *key, unsigned int size)
{
unsigned int i;
- for(i = 0; i < size; i++) {
+ for (i = 0; i < size; i++) {
sprintf(hex, "%02x", *key);
hex += 2;
key++;
}
}
+static int crypt_set_key(struct crypt_config *cc, char *key)
+{
+ unsigned key_size = strlen(key) >> 1;
+
+ if (cc->key_size && cc->key_size != key_size)
+ return -EINVAL;
+
+ cc->key_size = key_size; /* initial settings */
+
+ if ((!key_size && strcmp(key, "-")) ||
+ (key_size && crypt_decode_key(cc->key, key, key_size) < 0))
+ return -EINVAL;
+
+ set_bit(DM_CRYPT_KEY_VALID, &cc->flags);
+
+ return 0;
+}
+
+static int crypt_wipe_key(struct crypt_config *cc)
+{
+ clear_bit(DM_CRYPT_KEY_VALID, &cc->flags);
+ memset(&cc->key, 0, cc->key_size * sizeof(u8));
+ return 0;
+}
+
/*
* Construct an encryption mapping:
* <cipher> <key> <iv_offset> <dev_path> <start>
@@ -539,16 +728,14 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
key_size = strlen(argv[1]) >> 1;
- cc = kmalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
+ cc = kzalloc(sizeof(*cc) + key_size * sizeof(u8), GFP_KERNEL);
if (cc == NULL) {
ti->error =
"Cannot allocate transparent encryption context";
return -ENOMEM;
}
- cc->key_size = key_size;
- if ((!key_size && strcmp(argv[1], "-") != 0) ||
- (key_size && crypt_decode_key(cc->key, argv[1], key_size) < 0)) {
+ if (crypt_set_key(cc, argv[1])) {
ti->error = "Error decoding key";
goto bad1;
}
@@ -626,6 +813,12 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad4;
}
+ cc->bs = bioset_create(MIN_IOS, MIN_IOS, 4);
+ if (!cc->bs) {
+ ti->error = "Cannot allocate crypt bioset";
+ goto bad_bs;
+ }
+
if (crypto_blkcipher_setkey(tfm, cc->key, key_size) < 0) {
ti->error = "Error setting key";
goto bad5;
@@ -665,6 +858,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
return 0;
bad5:
+ bioset_free(cc->bs);
+bad_bs:
mempool_destroy(cc->page_pool);
bad4:
mempool_destroy(cc->io_pool);
@@ -684,6 +879,7 @@ static void crypt_dtr(struct dm_target *ti)
{
struct crypt_config *cc = (struct crypt_config *) ti->private;
+ bioset_free(cc->bs);
mempool_destroy(cc->page_pool);
mempool_destroy(cc->io_pool);
@@ -698,147 +894,21 @@ static void crypt_dtr(struct dm_target *ti)
kfree(cc);
}
-static int crypt_endio(struct bio *bio, unsigned int done, int error)
-{
- struct crypt_io *io = (struct crypt_io *) bio->bi_private;
- struct crypt_config *cc = (struct crypt_config *) io->target->private;
-
- if (bio_data_dir(bio) == WRITE) {
- /*
- * free the processed pages, even if
- * it's only a partially completed write
- */
- crypt_free_buffer_pages(cc, bio, done);
- }
-
- if (bio->bi_size)
- return 1;
-
- bio_put(bio);
-
- /*
- * successful reads are decrypted by the worker thread
- */
- if ((bio_data_dir(bio) == READ)
- && bio_flagged(bio, BIO_UPTODATE)) {
- kcryptd_queue_io(io);
- return 0;
- }
-
- dec_pending(io, error);
- return error;
-}
-
-static inline struct bio *
-crypt_clone(struct crypt_config *cc, struct crypt_io *io, struct bio *bio,
- sector_t sector, unsigned int *bvec_idx,
- struct convert_context *ctx)
-{
- struct bio *clone;
-
- if (bio_data_dir(bio) == WRITE) {
- clone = crypt_alloc_buffer(cc, bio->bi_size,
- io->first_clone, bvec_idx);
- if (clone) {
- ctx->bio_out = clone;
- if (crypt_convert(cc, ctx) < 0) {
- crypt_free_buffer_pages(cc, clone,
- clone->bi_size);
- bio_put(clone);
- return NULL;
- }
- }
- } else {
- /*
- * The block layer might modify the bvec array, so always
- * copy the required bvecs because we need the original
- * one in order to decrypt the whole bio data *afterwards*.
- */
- clone = bio_alloc(GFP_NOIO, bio_segments(bio));
- if (clone) {
- clone->bi_idx = 0;
- clone->bi_vcnt = bio_segments(bio);
- clone->bi_size = bio->bi_size;
- memcpy(clone->bi_io_vec, bio_iovec(bio),
- sizeof(struct bio_vec) * clone->bi_vcnt);
- }
- }
-
- if (!clone)
- return NULL;
-
- clone->bi_private = io;
- clone->bi_end_io = crypt_endio;
- clone->bi_bdev = cc->dev->bdev;
- clone->bi_sector = cc->start + sector;
- clone->bi_rw = bio->bi_rw;
-
- return clone;
-}
-
static int crypt_map(struct dm_target *ti, struct bio *bio,
union map_info *map_context)
{
- struct crypt_config *cc = (struct crypt_config *) ti->private;
- struct crypt_io *io = mempool_alloc(cc->io_pool, GFP_NOIO);
- struct convert_context ctx;
- struct bio *clone;
- unsigned int remaining = bio->bi_size;
- sector_t sector = bio->bi_sector - ti->begin;
- unsigned int bvec_idx = 0;
+ struct crypt_config *cc = ti->private;
+ struct crypt_io *io;
+ io = mempool_alloc(cc->io_pool, GFP_NOIO);
io->target = ti;
- io->bio = bio;
+ io->base_bio = bio;
io->first_clone = NULL;
- io->error = 0;
- atomic_set(&io->pending, 1); /* hold a reference */
-
- if (bio_data_dir(bio) == WRITE)
- crypt_convert_init(cc, &ctx, NULL, bio, sector, 1);
+ io->error = io->post_process = 0;
+ atomic_set(&io->pending, 0);
+ kcryptd_queue_io(io);
- /*
- * The allocated buffers can be smaller than the whole bio,
- * so repeat the whole process until all the data can be handled.
- */
- while (remaining) {
- clone = crypt_clone(cc, io, bio, sector, &bvec_idx, &ctx);
- if (!clone)
- goto cleanup;
-
- 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;
- }
- atomic_inc(&io->pending);
-
- remaining -= clone->bi_size;
- sector += bio_sectors(clone);
-
- generic_make_request(clone);
-
- /* out of memory -> run queues */
- if (remaining)
- blk_congestion_wait(bio_data_dir(clone), HZ/100);
- }
-
- /* drop reference, clones could have returned before we reach this */
- dec_pending(io, 0);
return 0;
-
-cleanup:
- if (io->first_clone) {
- dec_pending(io, -ENOMEM);
- return 0;
- }
-
- /* if no bio has been dispatched yet, we can directly return the error */
- mempool_free(io, cc->io_pool);
- return -ENOMEM;
}
static int crypt_status(struct dm_target *ti, status_type_t type,
@@ -883,14 +953,71 @@ static int crypt_status(struct dm_target *ti, status_type_t type,
return 0;
}
+static void crypt_postsuspend(struct dm_target *ti)
+{
+ struct crypt_config *cc = ti->private;
+
+ set_bit(DM_CRYPT_SUSPENDED, &cc->flags);
+}
+
+static int crypt_preresume(struct dm_target *ti)
+{
+ struct crypt_config *cc = ti->private;
+
+ if (!test_bit(DM_CRYPT_KEY_VALID, &cc->flags)) {
+ DMERR("aborting resume - crypt key is not set.");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static void crypt_resume(struct dm_target *ti)
+{
+ struct crypt_config *cc = ti->private;
+
+ clear_bit(DM_CRYPT_SUSPENDED, &cc->flags);
+}
+
+/* Message interface
+ * key set <key>
+ * key wipe
+ */
+static int crypt_message(struct dm_target *ti, unsigned argc, char **argv)
+{
+ struct crypt_config *cc = ti->private;
+
+ if (argc < 2)
+ goto error;
+
+ if (!strnicmp(argv[0], MESG_STR("key"))) {
+ if (!test_bit(DM_CRYPT_SUSPENDED, &cc->flags)) {
+ DMWARN("not suspended during key manipulation.");
+ return -EINVAL;
+ }
+ if (argc == 3 && !strnicmp(argv[1], MESG_STR("set")))
+ return crypt_set_key(cc, argv[2]);
+ if (argc == 2 && !strnicmp(argv[1], MESG_STR("wipe")))
+ return crypt_wipe_key(cc);
+ }
+
+error:
+ DMWARN("unrecognised message received.");
+ return -EINVAL;
+}
+
static struct target_type crypt_target = {
.name = "crypt",
- .version= {1, 1, 0},
+ .version= {1, 3, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
.map = crypt_map,
.status = crypt_status,
+ .postsuspend = crypt_postsuspend,
+ .preresume = crypt_preresume,
+ .resume = crypt_resume,
+ .message = crypt_message,
};
static int __init dm_crypt_init(void)
diff --git a/drivers/md/dm-emc.c b/drivers/md/dm-emc.c
index 2a374ccb30dd..2b2d45d7baaa 100644
--- a/drivers/md/dm-emc.c
+++ b/drivers/md/dm-emc.c
@@ -126,7 +126,8 @@ static struct request *get_failover_req(struct emc_handler *h,
memset(&rq->cmd, 0, BLK_MAX_CDB);
rq->timeout = EMC_FAILOVER_TIMEOUT;
- rq->flags |= (REQ_BLOCK_PC | REQ_FAILFAST | REQ_NOMERGE);
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
+ rq->cmd_flags |= REQ_FAILFAST | REQ_NOMERGE;
return rq;
}
diff --git a/drivers/md/dm-exception-store.c b/drivers/md/dm-exception-store.c
index d12379b5cdb5..99cdffa7fbfe 100644
--- a/drivers/md/dm-exception-store.c
+++ b/drivers/md/dm-exception-store.c
@@ -17,6 +17,7 @@
#include <linux/slab.h>
#define DM_MSG_PREFIX "snapshots"
+#define DM_CHUNK_SIZE_DEFAULT_SECTORS 32 /* 16KB */
/*-----------------------------------------------------------------
* Persistent snapshots, by persistent we mean that the snapshot
@@ -150,6 +151,7 @@ static int alloc_area(struct pstore *ps)
static void free_area(struct pstore *ps)
{
vfree(ps->area);
+ ps->area = NULL;
}
/*
@@ -198,48 +200,79 @@ static int read_header(struct pstore *ps, int *new_snapshot)
int r;
struct disk_header *dh;
chunk_t chunk_size;
+ int chunk_size_supplied = 1;
- r = chunk_io(ps, 0, READ);
+ /*
+ * Use default chunk size (or hardsect_size, if larger) if none supplied
+ */
+ if (!ps->snap->chunk_size) {
+ ps->snap->chunk_size = max(DM_CHUNK_SIZE_DEFAULT_SECTORS,
+ bdev_hardsect_size(ps->snap->cow->bdev) >> 9);
+ ps->snap->chunk_mask = ps->snap->chunk_size - 1;
+ ps->snap->chunk_shift = ffs(ps->snap->chunk_size) - 1;
+ chunk_size_supplied = 0;
+ }
+
+ r = dm_io_get(sectors_to_pages(ps->snap->chunk_size));
if (r)
return r;
+ r = alloc_area(ps);
+ if (r)
+ goto bad1;
+
+ r = chunk_io(ps, 0, READ);
+ if (r)
+ goto bad2;
+
dh = (struct disk_header *) ps->area;
if (le32_to_cpu(dh->magic) == 0) {
*new_snapshot = 1;
+ return 0;
+ }
- } else if (le32_to_cpu(dh->magic) == SNAP_MAGIC) {
- *new_snapshot = 0;
- ps->valid = le32_to_cpu(dh->valid);
- ps->version = le32_to_cpu(dh->version);
- chunk_size = le32_to_cpu(dh->chunk_size);
- if (ps->snap->chunk_size != chunk_size) {
- DMWARN("chunk size %llu in device metadata overrides "
- "table chunk size of %llu.",
- (unsigned long long)chunk_size,
- (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 = alloc_area(ps);
- if (r)
- return r;
-
- r = dm_io_get(sectors_to_pages(chunk_size));
- if (r)
- return r;
- }
- } else {
- DMWARN("Invalid/corrupt snapshot");
+ if (le32_to_cpu(dh->magic) != SNAP_MAGIC) {
+ DMWARN("Invalid or corrupt snapshot");
r = -ENXIO;
+ goto bad2;
}
+ *new_snapshot = 0;
+ ps->valid = le32_to_cpu(dh->valid);
+ ps->version = le32_to_cpu(dh->version);
+ chunk_size = le32_to_cpu(dh->chunk_size);
+
+ if (!chunk_size_supplied || ps->snap->chunk_size == chunk_size)
+ return 0;
+
+ DMWARN("chunk size %llu in device metadata overrides "
+ "table chunk size of %llu.",
+ (unsigned long long)chunk_size,
+ (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));
+ if (r)
+ return r;
+
+ r = alloc_area(ps);
+ if (r)
+ goto bad1;
+
+ return 0;
+
+bad2:
+ free_area(ps);
+bad1:
+ dm_io_put(sectors_to_pages(ps->snap->chunk_size));
return r;
}
@@ -263,42 +296,29 @@ static int write_header(struct pstore *ps)
*/
static struct disk_exception *get_exception(struct pstore *ps, uint32_t index)
{
- if (index >= ps->exceptions_per_area)
- return NULL;
+ BUG_ON(index >= ps->exceptions_per_area);
return ((struct disk_exception *) ps->area) + index;
}
-static int read_exception(struct pstore *ps,
- uint32_t index, struct disk_exception *result)
+static void read_exception(struct pstore *ps,
+ uint32_t index, struct disk_exception *result)
{
- struct disk_exception *e;
-
- e = get_exception(ps, index);
- if (!e)
- return -EINVAL;
+ struct disk_exception *e = get_exception(ps, index);
/* copy it */
result->old_chunk = le64_to_cpu(e->old_chunk);
result->new_chunk = le64_to_cpu(e->new_chunk);
-
- return 0;
}
-static int write_exception(struct pstore *ps,
- uint32_t index, struct disk_exception *de)
+static void write_exception(struct pstore *ps,
+ uint32_t index, struct disk_exception *de)
{
- struct disk_exception *e;
-
- e = get_exception(ps, index);
- if (!e)
- return -EINVAL;
+ struct disk_exception *e = get_exception(ps, index);
/* copy it */
e->old_chunk = cpu_to_le64(de->old_chunk);
e->new_chunk = cpu_to_le64(de->new_chunk);
-
- return 0;
}
/*
@@ -316,10 +336,7 @@ static int insert_exceptions(struct pstore *ps, int *full)
*full = 1;
for (i = 0; i < ps->exceptions_per_area; i++) {
- r = read_exception(ps, i, &de);
-
- if (r)
- return r;
+ read_exception(ps, i, &de);
/*
* If the new_chunk is pointing at the start of
@@ -519,6 +536,16 @@ static void persistent_commit(struct exception_store *store,
if (r)
ps->valid = 0;
+ /*
+ * Have we completely filled the current area ?
+ */
+ if (ps->current_committed == ps->exceptions_per_area) {
+ ps->current_committed = 0;
+ r = zero_area(ps, ps->current_area + 1);
+ if (r)
+ ps->valid = 0;
+ }
+
for (i = 0; i < ps->callback_count; i++) {
cb = ps->callbacks + i;
cb->callback(cb->context, r == 0 ? 1 : 0);
@@ -526,16 +553,6 @@ static void persistent_commit(struct exception_store *store,
ps->callback_count = 0;
}
-
- /*
- * Have we completely filled the current area ?
- */
- if (ps->current_committed == ps->exceptions_per_area) {
- ps->current_committed = 0;
- r = zero_area(ps, ps->current_area + 1);
- if (r)
- ps->valid = 0;
- }
}
static void persistent_drop(struct exception_store *store)
@@ -547,32 +564,22 @@ static void persistent_drop(struct exception_store *store)
DMWARN("write header failed");
}
-int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
+int dm_create_persistent(struct exception_store *store)
{
- int r;
struct pstore *ps;
- r = dm_io_get(sectors_to_pages(chunk_size));
- if (r)
- return r;
-
/* allocate the pstore */
ps = kmalloc(sizeof(*ps), GFP_KERNEL);
- if (!ps) {
- r = -ENOMEM;
- goto bad;
- }
+ if (!ps)
+ return -ENOMEM;
ps->snap = store->snap;
ps->valid = 1;
ps->version = SNAPSHOT_DISK_VERSION;
+ ps->area = NULL;
ps->next_free = 2; /* skipping the header and first area */
ps->current_committed = 0;
- r = alloc_area(ps);
- if (r)
- goto bad;
-
ps->callback_count = 0;
atomic_set(&ps->pending_count, 0);
ps->callbacks = NULL;
@@ -586,13 +593,6 @@ int dm_create_persistent(struct exception_store *store, uint32_t chunk_size)
store->context = ps;
return 0;
-
- bad:
- dm_io_put(sectors_to_pages(chunk_size));
- if (ps && ps->area)
- free_area(ps);
- kfree(ps);
- return r;
}
/*-----------------------------------------------------------------
@@ -642,18 +642,16 @@ static void transient_fraction_full(struct exception_store *store,
*denominator = get_dev_size(store->snap->cow->bdev);
}
-int dm_create_transient(struct exception_store *store,
- struct dm_snapshot *s, int blocksize)
+int dm_create_transient(struct exception_store *store)
{
struct transient_c *tc;
- memset(store, 0, sizeof(*store));
store->destroy = transient_destroy;
store->read_metadata = transient_read_metadata;
store->prepare_exception = transient_prepare;
store->commit_exception = transient_commit;
+ store->drop_snapshot = NULL;
store->fraction_full = transient_fraction_full;
- store->snap = s;
tc = kmalloc(sizeof(struct transient_c), GFP_KERNEL);
if (!tc)
diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c
index 47b3c62bbdb8..00234909b3db 100644
--- a/drivers/md/dm-linear.c
+++ b/drivers/md/dm-linear.c
@@ -98,14 +98,31 @@ static int linear_status(struct dm_target *ti, status_type_t type,
return 0;
}
+static int linear_ioctl(struct dm_target *ti, struct inode *inode,
+ struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct linear_c *lc = (struct linear_c *) ti->private;
+ struct block_device *bdev = lc->dev->bdev;
+ struct file fake_file = {};
+ struct dentry fake_dentry = {};
+
+ fake_file.f_mode = lc->dev->mode;
+ fake_file.f_dentry = &fake_dentry;
+ fake_dentry.d_inode = bdev->bd_inode;
+
+ return blkdev_driver_ioctl(bdev->bd_inode, &fake_file, bdev->bd_disk, cmd, arg);
+}
+
static struct target_type linear_target = {
.name = "linear",
- .version= {1, 0, 1},
+ .version= {1, 0, 2},
.module = THIS_MODULE,
.ctr = linear_ctr,
.dtr = linear_dtr,
.map = linear_map,
.status = linear_status,
+ .ioctl = linear_ioctl,
};
int __init dm_linear_init(void)
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 93f701ea87bc..d754e0bc6e90 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -114,12 +114,10 @@ static void trigger_event(void *data);
static struct pgpath *alloc_pgpath(void)
{
- struct pgpath *pgpath = kmalloc(sizeof(*pgpath), GFP_KERNEL);
+ struct pgpath *pgpath = kzalloc(sizeof(*pgpath), GFP_KERNEL);
- if (pgpath) {
- memset(pgpath, 0, sizeof(*pgpath));
+ if (pgpath)
pgpath->path.is_active = 1;
- }
return pgpath;
}
@@ -133,12 +131,10 @@ static struct priority_group *alloc_priority_group(void)
{
struct priority_group *pg;
- pg = kmalloc(sizeof(*pg), GFP_KERNEL);
- if (!pg)
- return NULL;
+ pg = kzalloc(sizeof(*pg), GFP_KERNEL);
- memset(pg, 0, sizeof(*pg));
- INIT_LIST_HEAD(&pg->pgpaths);
+ if (pg)
+ INIT_LIST_HEAD(&pg->pgpaths);
return pg;
}
@@ -168,13 +164,12 @@ static void free_priority_group(struct priority_group *pg,
kfree(pg);
}
-static struct multipath *alloc_multipath(void)
+static struct multipath *alloc_multipath(struct dm_target *ti)
{
struct multipath *m;
- m = kmalloc(sizeof(*m), GFP_KERNEL);
+ m = kzalloc(sizeof(*m), GFP_KERNEL);
if (m) {
- memset(m, 0, sizeof(*m));
INIT_LIST_HEAD(&m->priority_groups);
spin_lock_init(&m->lock);
m->queue_io = 1;
@@ -185,6 +180,8 @@ static struct multipath *alloc_multipath(void)
kfree(m);
return NULL;
}
+ m->ti = ti;
+ ti->private = m;
}
return m;
@@ -557,8 +554,7 @@ static struct pgpath *parse_path(struct arg_set *as, struct path_selector *ps,
}
static struct priority_group *parse_priority_group(struct arg_set *as,
- struct multipath *m,
- struct dm_target *ti)
+ struct multipath *m)
{
static struct param _params[] = {
{1, 1024, "invalid number of paths"},
@@ -568,6 +564,7 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
int r;
unsigned i, nr_selector_args, nr_params;
struct priority_group *pg;
+ struct dm_target *ti = m->ti;
if (as->argc < 2) {
as->argc = 0;
@@ -624,12 +621,12 @@ static struct priority_group *parse_priority_group(struct arg_set *as,
return NULL;
}
-static int parse_hw_handler(struct arg_set *as, struct multipath *m,
- struct dm_target *ti)
+static int parse_hw_handler(struct arg_set *as, struct multipath *m)
{
int r;
struct hw_handler_type *hwht;
unsigned hw_argc;
+ struct dm_target *ti = m->ti;
static struct param _params[] = {
{0, 1024, "invalid number of hardware handler args"},
@@ -661,11 +658,11 @@ static int parse_hw_handler(struct arg_set *as, struct multipath *m,
return 0;
}
-static int parse_features(struct arg_set *as, struct multipath *m,
- struct dm_target *ti)
+static int parse_features(struct arg_set *as, struct multipath *m)
{
int r;
unsigned argc;
+ struct dm_target *ti = m->ti;
static struct param _params[] = {
{0, 1, "invalid number of feature args"},
@@ -704,19 +701,17 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
as.argc = argc;
as.argv = argv;
- m = alloc_multipath();
+ m = alloc_multipath(ti);
if (!m) {
ti->error = "can't allocate multipath";
return -EINVAL;
}
- m->ti = ti;
-
- r = parse_features(&as, m, ti);
+ r = parse_features(&as, m);
if (r)
goto bad;
- r = parse_hw_handler(&as, m, ti);
+ r = parse_hw_handler(&as, m);
if (r)
goto bad;
@@ -732,7 +727,7 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
while (as.argc) {
struct priority_group *pg;
- pg = parse_priority_group(&as, m, ti);
+ pg = parse_priority_group(&as, m);
if (!pg) {
r = -EINVAL;
goto bad;
@@ -752,8 +747,6 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
goto bad;
}
- ti->private = m;
-
return 0;
bad:
@@ -1266,12 +1259,47 @@ error:
return -EINVAL;
}
+static int multipath_ioctl(struct dm_target *ti, struct inode *inode,
+ struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct multipath *m = (struct multipath *) ti->private;
+ struct block_device *bdev = NULL;
+ unsigned long flags;
+ struct file fake_file = {};
+ struct dentry fake_dentry = {};
+ int r = 0;
+
+ fake_file.f_dentry = &fake_dentry;
+
+ spin_lock_irqsave(&m->lock, flags);
+
+ if (!m->current_pgpath)
+ __choose_pgpath(m);
+
+ if (m->current_pgpath) {
+ bdev = m->current_pgpath->path.dev->bdev;
+ fake_dentry.d_inode = bdev->bd_inode;
+ fake_file.f_mode = m->current_pgpath->path.dev->mode;
+ }
+
+ if (m->queue_io)
+ r = -EAGAIN;
+ else if (!bdev)
+ r = -EIO;
+
+ spin_unlock_irqrestore(&m->lock, flags);
+
+ return r ? : blkdev_driver_ioctl(bdev->bd_inode, &fake_file,
+ bdev->bd_disk, cmd, arg);
+}
+
/*-----------------------------------------------------------------
* Module setup
*---------------------------------------------------------------*/
static struct target_type multipath_target = {
.name = "multipath",
- .version = {1, 0, 4},
+ .version = {1, 0, 5},
.module = THIS_MODULE,
.ctr = multipath_ctr,
.dtr = multipath_dtr,
@@ -1281,6 +1309,7 @@ static struct target_type multipath_target = {
.resume = multipath_resume,
.status = multipath_status,
.message = multipath_message,
+ .ioctl = multipath_ioctl,
};
static int __init dm_multipath_init(void)
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index c54de989eb00..659224cb7c53 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1213,9 +1213,9 @@ static int mirror_status(struct dm_target *ti, status_type_t type,
break;
case STATUSTYPE_TABLE:
- DMEMIT("%d ", ms->nr_mirrors);
+ DMEMIT("%d", ms->nr_mirrors);
for (m = 0; m < ms->nr_mirrors; m++)
- DMEMIT("%s %llu ", ms->mirror[m].dev->name,
+ DMEMIT(" %s %llu", ms->mirror[m].dev->name,
(unsigned long long)ms->mirror[m].offset);
}
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 1d0fafda0f76..5281e0094072 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -39,6 +39,9 @@
*/
#define SNAPSHOT_PAGES 256
+struct workqueue_struct *ksnapd;
+static void flush_queued_bios(void *data);
+
struct pending_exception {
struct exception e;
@@ -56,7 +59,7 @@ struct pending_exception {
/*
* The primary pending_exception is the one that holds
- * the sibling_count and the list of origin_bios for a
+ * the ref_count and the list of origin_bios for a
* group of pending_exceptions. It is always last to get freed.
* These fields get set up when writing to the origin.
*/
@@ -69,7 +72,7 @@ struct pending_exception {
* the sibling concerned and not pe->primary_pe->snap->lock unless
* they are the same.
*/
- atomic_t sibling_count;
+ atomic_t ref_count;
/* Pointer back to snapshot context */
struct dm_snapshot *snap;
@@ -387,15 +390,46 @@ static inline ulong round_up(ulong n, ulong size)
return (n + size) & ~size;
}
-static void read_snapshot_metadata(struct dm_snapshot *s)
+static int set_chunk_size(struct dm_snapshot *s, const char *chunk_size_arg,
+ char **error)
{
- if (s->store.read_metadata(&s->store)) {
- down_write(&s->lock);
- s->valid = 0;
- up_write(&s->lock);
+ unsigned long chunk_size;
+ char *value;
+
+ chunk_size = simple_strtoul(chunk_size_arg, &value, 10);
+ if (*chunk_size_arg == '\0' || *value != '\0') {
+ *error = "Invalid chunk size";
+ return -EINVAL;
+ }
+
+ if (!chunk_size) {
+ s->chunk_size = s->chunk_mask = s->chunk_shift = 0;
+ return 0;
+ }
+
+ /*
+ * Chunk size must be multiple of page size. Silently
+ * round up if it's not.
+ */
+ chunk_size = round_up(chunk_size, PAGE_SIZE >> 9);
+
+ /* Check chunk_size is a power of 2 */
+ if (chunk_size & (chunk_size - 1)) {
+ *error = "Chunk size is not a power of 2";
+ return -EINVAL;
+ }
- dm_table_event(s->table);
+ /* Validate the chunk size against the device block size */
+ if (chunk_size % (bdev_hardsect_size(s->cow->bdev) >> 9)) {
+ *error = "Chunk size is not a multiple of device blocksize";
+ return -EINVAL;
}
+
+ s->chunk_size = chunk_size;
+ s->chunk_mask = chunk_size - 1;
+ s->chunk_shift = ffs(chunk_size) - 1;
+
+ return 0;
}
/*
@@ -404,15 +438,12 @@ static void read_snapshot_metadata(struct dm_snapshot *s)
static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
{
struct dm_snapshot *s;
- unsigned long chunk_size;
int r = -EINVAL;
char persistent;
char *origin_path;
char *cow_path;
- char *value;
- int blocksize;
- if (argc < 4) {
+ if (argc != 4) {
ti->error = "requires exactly 4 arguments";
r = -EINVAL;
goto bad1;
@@ -428,13 +459,6 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad1;
}
- chunk_size = simple_strtoul(argv[3], &value, 10);
- if (chunk_size == 0 || value == NULL) {
- ti->error = "Invalid chunk size";
- r = -EINVAL;
- goto bad1;
- }
-
s = kmalloc(sizeof(*s), GFP_KERNEL);
if (s == NULL) {
ti->error = "Cannot allocate snapshot context private "
@@ -457,36 +481,17 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad2;
}
- /*
- * Chunk size must be multiple of page size. Silently
- * round up if it's not.
- */
- chunk_size = round_up(chunk_size, PAGE_SIZE >> 9);
-
- /* Validate the chunk size against the device block size */
- blocksize = s->cow->bdev->bd_disk->queue->hardsect_size;
- if (chunk_size % (blocksize >> 9)) {
- ti->error = "Chunk size is not a multiple of device blocksize";
- r = -EINVAL;
- goto bad3;
- }
-
- /* Check chunk_size is a power of 2 */
- if (chunk_size & (chunk_size - 1)) {
- ti->error = "Chunk size is not a power of 2";
- r = -EINVAL;
+ r = set_chunk_size(s, argv[3], &ti->error);
+ if (r)
goto bad3;
- }
- s->chunk_size = chunk_size;
- s->chunk_mask = chunk_size - 1;
s->type = persistent;
- s->chunk_shift = ffs(chunk_size) - 1;
s->valid = 1;
s->active = 0;
s->last_percent = 0;
init_rwsem(&s->lock);
+ spin_lock_init(&s->pe_lock);
s->table = ti->table;
/* Allocate hash table for COW data */
@@ -496,16 +501,12 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad3;
}
- /*
- * Check the persistent flag - done here because we need the iobuf
- * to check the LV header
- */
s->store.snap = s;
if (persistent == 'P')
- r = dm_create_persistent(&s->store, chunk_size);
+ r = dm_create_persistent(&s->store);
else
- r = dm_create_transient(&s->store, s, blocksize);
+ r = dm_create_transient(&s->store);
if (r) {
ti->error = "Couldn't create exception store";
@@ -520,7 +521,14 @@ static int snapshot_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
/* Metadata must only be loaded into one table at once */
- read_snapshot_metadata(s);
+ r = s->store.read_metadata(&s->store);
+ if (r) {
+ ti->error = "Failed to read snapshot metadata";
+ goto bad6;
+ }
+
+ bio_list_init(&s->queued_bios);
+ INIT_WORK(&s->queued_bios_work, flush_queued_bios, s);
/* Add snapshot to the list of snapshots for this origin */
/* Exceptions aren't triggered till snapshot_resume() is called */
@@ -560,6 +568,8 @@ static void snapshot_dtr(struct dm_target *ti)
{
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
+ flush_workqueue(ksnapd);
+
/* Prevent further origin writes from using this snapshot. */
/* After this returns there can be no new kcopyd jobs. */
unregister_snapshot(s);
@@ -593,6 +603,19 @@ static void flush_bios(struct bio *bio)
}
}
+static void flush_queued_bios(void *data)
+{
+ struct dm_snapshot *s = (struct dm_snapshot *) data;
+ struct bio *queued_bios;
+ unsigned long flags;
+
+ spin_lock_irqsave(&s->pe_lock, flags);
+ queued_bios = bio_list_get(&s->queued_bios);
+ spin_unlock_irqrestore(&s->pe_lock, flags);
+
+ flush_bios(queued_bios);
+}
+
/*
* Error a list of buffers.
*/
@@ -608,28 +631,7 @@ static void error_bios(struct bio *bio)
}
}
-static inline void error_snapshot_bios(struct pending_exception *pe)
-{
- error_bios(bio_list_get(&pe->snapshot_bios));
-}
-
-static struct bio *__flush_bios(struct pending_exception *pe)
-{
- /*
- * If this pe is involved in a write to the origin and
- * it is the last sibling to complete then release
- * the bios for the original write to the origin.
- */
-
- if (pe->primary_pe &&
- atomic_dec_and_test(&pe->primary_pe->sibling_count))
- return bio_list_get(&pe->primary_pe->origin_bios);
-
- return NULL;
-}
-
-static void __invalidate_snapshot(struct dm_snapshot *s,
- struct pending_exception *pe, int err)
+static void __invalidate_snapshot(struct dm_snapshot *s, int err)
{
if (!s->valid)
return;
@@ -639,9 +641,6 @@ static void __invalidate_snapshot(struct dm_snapshot *s,
else if (err == -ENOMEM)
DMERR("Invalidating snapshot: Unable to allocate exception.");
- if (pe)
- remove_exception(&pe->e);
-
if (s->store.drop_snapshot)
s->store.drop_snapshot(&s->store);
@@ -650,78 +649,95 @@ static void __invalidate_snapshot(struct dm_snapshot *s,
dm_table_event(s->table);
}
+static void get_pending_exception(struct pending_exception *pe)
+{
+ atomic_inc(&pe->ref_count);
+}
+
+static struct bio *put_pending_exception(struct pending_exception *pe)
+{
+ struct pending_exception *primary_pe;
+ struct bio *origin_bios = NULL;
+
+ primary_pe = pe->primary_pe;
+
+ /*
+ * If this pe is involved in a write to the origin and
+ * it is the last sibling to complete then release
+ * the bios for the original write to the origin.
+ */
+ if (primary_pe &&
+ atomic_dec_and_test(&primary_pe->ref_count))
+ origin_bios = bio_list_get(&primary_pe->origin_bios);
+
+ /*
+ * Free the pe if it's not linked to an origin write or if
+ * it's not itself a primary pe.
+ */
+ if (!primary_pe || primary_pe != pe)
+ free_pending_exception(pe);
+
+ /*
+ * Free the primary pe if nothing references it.
+ */
+ if (primary_pe && !atomic_read(&primary_pe->ref_count))
+ free_pending_exception(primary_pe);
+
+ return origin_bios;
+}
+
static void pending_complete(struct pending_exception *pe, int success)
{
struct exception *e;
- struct pending_exception *primary_pe;
struct dm_snapshot *s = pe->snap;
- struct bio *flush = NULL;
+ struct bio *origin_bios = NULL;
+ struct bio *snapshot_bios = NULL;
+ int error = 0;
if (!success) {
/* Read/write error - snapshot is unusable */
down_write(&s->lock);
- __invalidate_snapshot(s, pe, -EIO);
- flush = __flush_bios(pe);
- up_write(&s->lock);
-
- error_snapshot_bios(pe);
+ __invalidate_snapshot(s, -EIO);
+ error = 1;
goto out;
}
e = alloc_exception();
if (!e) {
down_write(&s->lock);
- __invalidate_snapshot(s, pe, -ENOMEM);
- flush = __flush_bios(pe);
- up_write(&s->lock);
-
- error_snapshot_bios(pe);
+ __invalidate_snapshot(s, -ENOMEM);
+ error = 1;
goto out;
}
*e = pe->e;
- /*
- * Add a proper exception, and remove the
- * in-flight exception from the list.
- */
down_write(&s->lock);
if (!s->valid) {
- flush = __flush_bios(pe);
- up_write(&s->lock);
-
free_exception(e);
-
- error_snapshot_bios(pe);
+ error = 1;
goto out;
}
+ /*
+ * Add a proper exception, and remove the
+ * in-flight exception from the list.
+ */
insert_exception(&s->complete, e);
+
+ out:
remove_exception(&pe->e);
- flush = __flush_bios(pe);
+ snapshot_bios = bio_list_get(&pe->snapshot_bios);
+ origin_bios = put_pending_exception(pe);
up_write(&s->lock);
/* Submit any pending write bios */
- flush_bios(bio_list_get(&pe->snapshot_bios));
-
- out:
- primary_pe = pe->primary_pe;
-
- /*
- * Free the pe if it's not linked to an origin write or if
- * it's not itself a primary pe.
- */
- if (!primary_pe || primary_pe != pe)
- free_pending_exception(pe);
-
- /*
- * Free the primary pe if nothing references it.
- */
- if (primary_pe && !atomic_read(&primary_pe->sibling_count))
- free_pending_exception(primary_pe);
+ if (error)
+ error_bios(snapshot_bios);
+ else
+ flush_bios(snapshot_bios);
- if (flush)
- flush_bios(flush);
+ flush_bios(origin_bios);
}
static void commit_callback(void *context, int success)
@@ -822,7 +838,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
bio_list_init(&pe->origin_bios);
bio_list_init(&pe->snapshot_bios);
pe->primary_pe = NULL;
- atomic_set(&pe->sibling_count, 1);
+ atomic_set(&pe->ref_count, 0);
pe->snap = s;
pe->started = 0;
@@ -831,6 +847,7 @@ __find_pending_exception(struct dm_snapshot *s, struct bio *bio)
return NULL;
}
+ get_pending_exception(pe);
insert_exception(&s->pending, &pe->e);
out:
@@ -850,7 +867,6 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
{
struct exception *e;
struct dm_snapshot *s = (struct dm_snapshot *) ti->private;
- int copy_needed = 0;
int r = 1;
chunk_t chunk;
struct pending_exception *pe = NULL;
@@ -865,32 +881,31 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
if (unlikely(bio_barrier(bio)))
return -EOPNOTSUPP;
+ /* FIXME: should only take write lock if we need
+ * to copy an exception */
+ down_write(&s->lock);
+
+ if (!s->valid) {
+ r = -EIO;
+ goto out_unlock;
+ }
+
+ /* If the block is already remapped - use that, else remap it */
+ e = lookup_exception(&s->complete, chunk);
+ if (e) {
+ remap_exception(s, e, bio);
+ goto out_unlock;
+ }
+
/*
* Write to snapshot - higher level takes care of RW/RO
* flags so we should only get this if we are
* writeable.
*/
if (bio_rw(bio) == WRITE) {
-
- /* FIXME: should only take write lock if we need
- * to copy an exception */
- down_write(&s->lock);
-
- if (!s->valid) {
- r = -EIO;
- goto out_unlock;
- }
-
- /* If the block is already remapped - use that, else remap it */
- e = lookup_exception(&s->complete, chunk);
- if (e) {
- remap_exception(s, e, bio);
- goto out_unlock;
- }
-
pe = __find_pending_exception(s, bio);
if (!pe) {
- __invalidate_snapshot(s, pe, -ENOMEM);
+ __invalidate_snapshot(s, -ENOMEM);
r = -EIO;
goto out_unlock;
}
@@ -898,45 +913,27 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
remap_exception(s, &pe->e, bio);
bio_list_add(&pe->snapshot_bios, bio);
+ r = 0;
+
if (!pe->started) {
/* this is protected by snap->lock */
pe->started = 1;
- copy_needed = 1;
- }
-
- r = 0;
-
- out_unlock:
- up_write(&s->lock);
-
- if (copy_needed)
+ up_write(&s->lock);
start_copy(pe);
- } else {
+ goto out;
+ }
+ } else
/*
* FIXME: this read path scares me because we
* always use the origin when we have a pending
* exception. However I can't think of a
* situation where this is wrong - ejt.
*/
+ bio->bi_bdev = s->origin->bdev;
- /* Do reads */
- down_read(&s->lock);
-
- if (!s->valid) {
- up_read(&s->lock);
- return -EIO;
- }
-
- /* See if it it has been remapped */
- e = lookup_exception(&s->complete, chunk);
- if (e)
- remap_exception(s, e, bio);
- else
- bio->bi_bdev = s->origin->bdev;
-
- up_read(&s->lock);
- }
-
+ out_unlock:
+ up_write(&s->lock);
+ out:
return r;
}
@@ -1025,7 +1022,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
* is already remapped in this snapshot
* and trigger an exception if not.
*
- * sibling_count is initialised to 1 so pending_complete()
+ * ref_count is initialised to 1 so pending_complete()
* won't destroy the primary_pe while we're inside this loop.
*/
e = lookup_exception(&snap->complete, chunk);
@@ -1034,7 +1031,7 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
pe = __find_pending_exception(snap, bio);
if (!pe) {
- __invalidate_snapshot(snap, pe, ENOMEM);
+ __invalidate_snapshot(snap, -ENOMEM);
goto next_snapshot;
}
@@ -1056,8 +1053,8 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
}
if (!pe->primary_pe) {
- atomic_inc(&primary_pe->sibling_count);
pe->primary_pe = primary_pe;
+ get_pending_exception(primary_pe);
}
if (!pe->started) {
@@ -1070,20 +1067,20 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
}
if (!primary_pe)
- goto out;
+ return r;
/*
* If this is the first time we're processing this chunk and
- * sibling_count is now 1 it means all the pending exceptions
+ * ref_count is now 1 it means all the pending exceptions
* got completed while we were in the loop above, so it falls to
* us here to remove the primary_pe and submit any origin_bios.
*/
- if (first && atomic_dec_and_test(&primary_pe->sibling_count)) {
+ if (first && atomic_dec_and_test(&primary_pe->ref_count)) {
flush_bios(bio_list_get(&primary_pe->origin_bios));
free_pending_exception(primary_pe);
/* If we got here, pe_queue is necessarily empty. */
- goto out;
+ return r;
}
/*
@@ -1092,7 +1089,6 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
list_for_each_entry_safe(pe, next_pe, &pe_queue, list)
start_copy(pe);
- out:
return r;
}
@@ -1205,7 +1201,7 @@ static int origin_status(struct dm_target *ti, status_type_t type, char *result,
static struct target_type origin_target = {
.name = "snapshot-origin",
- .version = {1, 4, 0},
+ .version = {1, 5, 0},
.module = THIS_MODULE,
.ctr = origin_ctr,
.dtr = origin_dtr,
@@ -1216,7 +1212,7 @@ static struct target_type origin_target = {
static struct target_type snapshot_target = {
.name = "snapshot",
- .version = {1, 4, 0},
+ .version = {1, 5, 0},
.module = THIS_MODULE,
.ctr = snapshot_ctr,
.dtr = snapshot_dtr,
@@ -1275,8 +1271,17 @@ static int __init dm_snapshot_init(void)
goto bad5;
}
+ ksnapd = create_singlethread_workqueue("ksnapd");
+ if (!ksnapd) {
+ DMERR("Failed to create ksnapd workqueue.");
+ r = -ENOMEM;
+ goto bad6;
+ }
+
return 0;
+ bad6:
+ mempool_destroy(pending_pool);
bad5:
kmem_cache_destroy(pending_cache);
bad4:
@@ -1294,6 +1299,8 @@ static void __exit dm_snapshot_exit(void)
{
int r;
+ destroy_workqueue(ksnapd);
+
r = dm_unregister_target(&snapshot_target);
if (r)
DMERR("snapshot unregister failed %d", r);
diff --git a/drivers/md/dm-snap.h b/drivers/md/dm-snap.h
index fdec1e2dc871..15fa2ae6cdc2 100644
--- a/drivers/md/dm-snap.h
+++ b/drivers/md/dm-snap.h
@@ -10,7 +10,9 @@
#define DM_SNAPSHOT_H
#include "dm.h"
+#include "dm-bio-list.h"
#include <linux/blkdev.h>
+#include <linux/workqueue.h>
struct exception_table {
uint32_t hash_mask;
@@ -112,10 +114,20 @@ struct dm_snapshot {
struct exception_table pending;
struct exception_table complete;
+ /*
+ * pe_lock protects all pending_exception operations and access
+ * as well as the snapshot_bios list.
+ */
+ spinlock_t pe_lock;
+
/* The on disk metadata handler */
struct exception_store store;
struct kcopyd_client *kcopyd_client;
+
+ /* Queue of snapshot writes for ksnapd to flush */
+ struct bio_list queued_bios;
+ struct work_struct queued_bios_work;
};
/*
@@ -128,10 +140,9 @@ int dm_add_exception(struct dm_snapshot *s, chunk_t old, chunk_t new);
* Constructor and destructor for the default persistent
* store.
*/
-int dm_create_persistent(struct exception_store *store, uint32_t chunk_size);
+int dm_create_persistent(struct exception_store *store);
-int dm_create_transient(struct exception_store *store,
- struct dm_snapshot *s, int blocksize);
+int dm_create_transient(struct exception_store *store);
/*
* Return the number of sectors in the device.
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 75fe9493e6af..05befa91807a 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -522,56 +522,61 @@ static int __table_get_device(struct dm_table *t, struct dm_target *ti,
return 0;
}
-
-int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
- sector_t len, int mode, struct dm_dev **result)
+void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev)
{
- int r = __table_get_device(ti->table, ti, path,
- start, len, mode, result);
- if (!r) {
- request_queue_t *q = bdev_get_queue((*result)->bdev);
- struct io_restrictions *rs = &ti->limits;
-
- /*
- * Combine the device limits low.
- *
- * FIXME: if we move an io_restriction struct
- * into q this would just be a call to
- * combine_restrictions_low()
- */
+ request_queue_t *q = bdev_get_queue(bdev);
+ struct io_restrictions *rs = &ti->limits;
+
+ /*
+ * Combine the device limits low.
+ *
+ * FIXME: if we move an io_restriction struct
+ * into q this would just be a call to
+ * combine_restrictions_low()
+ */
+ rs->max_sectors =
+ min_not_zero(rs->max_sectors, q->max_sectors);
+
+ /* FIXME: Device-Mapper on top of RAID-0 breaks because DM
+ * currently doesn't honor MD's merge_bvec_fn routine.
+ * In this case, we'll force DM to use PAGE_SIZE or
+ * smaller I/O, just to be safe. A better fix is in the
+ * works, but add this for the time being so it will at
+ * least operate correctly.
+ */
+ if (q->merge_bvec_fn)
rs->max_sectors =
- min_not_zero(rs->max_sectors, q->max_sectors);
+ min_not_zero(rs->max_sectors,
+ (unsigned int) (PAGE_SIZE >> 9));
- /* FIXME: Device-Mapper on top of RAID-0 breaks because DM
- * currently doesn't honor MD's merge_bvec_fn routine.
- * In this case, we'll force DM to use PAGE_SIZE or
- * smaller I/O, just to be safe. A better fix is in the
- * works, but add this for the time being so it will at
- * least operate correctly.
- */
- if (q->merge_bvec_fn)
- rs->max_sectors =
- min_not_zero(rs->max_sectors,
- (unsigned int) (PAGE_SIZE >> 9));
+ rs->max_phys_segments =
+ min_not_zero(rs->max_phys_segments,
+ q->max_phys_segments);
- rs->max_phys_segments =
- min_not_zero(rs->max_phys_segments,
- q->max_phys_segments);
+ rs->max_hw_segments =
+ min_not_zero(rs->max_hw_segments, q->max_hw_segments);
- rs->max_hw_segments =
- min_not_zero(rs->max_hw_segments, q->max_hw_segments);
+ rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size);
- rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size);
+ rs->max_segment_size =
+ min_not_zero(rs->max_segment_size, q->max_segment_size);
- rs->max_segment_size =
- min_not_zero(rs->max_segment_size, q->max_segment_size);
+ rs->seg_boundary_mask =
+ min_not_zero(rs->seg_boundary_mask,
+ q->seg_boundary_mask);
- rs->seg_boundary_mask =
- min_not_zero(rs->seg_boundary_mask,
- q->seg_boundary_mask);
+ rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+}
+EXPORT_SYMBOL_GPL(dm_set_device_limits);
- rs->no_cluster |= !test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
- }
+int dm_get_device(struct dm_target *ti, const char *path, sector_t start,
+ sector_t len, int mode, struct dm_dev **result)
+{
+ int r = __table_get_device(ti->table, ti, path,
+ start, len, mode, result);
+
+ if (!r)
+ dm_set_device_limits(ti, (*result)->bdev);
return r;
}
@@ -939,9 +944,20 @@ void dm_table_postsuspend_targets(struct dm_table *t)
return suspend_targets(t, 1);
}
-void dm_table_resume_targets(struct dm_table *t)
+int dm_table_resume_targets(struct dm_table *t)
{
- int i;
+ int i, r = 0;
+
+ for (i = 0; i < t->num_targets; i++) {
+ struct dm_target *ti = t->targets + i;
+
+ if (!ti->type->preresume)
+ continue;
+
+ r = ti->type->preresume(ti);
+ if (r)
+ return r;
+ }
for (i = 0; i < t->num_targets; i++) {
struct dm_target *ti = t->targets + i;
@@ -949,6 +965,8 @@ void dm_table_resume_targets(struct dm_table *t)
if (ti->type->resume)
ti->type->resume(ti);
}
+
+ return 0;
}
int dm_table_any_congested(struct dm_table *t, int bdi_bits)
@@ -983,6 +1001,11 @@ int dm_table_flush_all(struct dm_table *t)
{
struct list_head *d, *devices = dm_table_get_devices(t);
int ret = 0;
+ unsigned i;
+
+ for (i = 0; i < t->num_targets; i++)
+ if (t->targets[i].type->flush)
+ t->targets[i].type->flush(&t->targets[i]);
for (d = devices->next; d != devices; d = d->next) {
struct dm_dev *dd = list_entry(d, struct dm_dev, list);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index c99bf9f01759..b5764a86c8b5 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -20,6 +20,7 @@
#include <linux/idr.h>
#include <linux/hdreg.h>
#include <linux/blktrace_api.h>
+#include <linux/smp_lock.h>
#define DM_MSG_PREFIX "core"
@@ -101,6 +102,8 @@ struct mapped_device {
mempool_t *io_pool;
mempool_t *tio_pool;
+ struct bio_set *bs;
+
/*
* Event handling.
*/
@@ -121,16 +124,10 @@ struct mapped_device {
static kmem_cache_t *_io_cache;
static kmem_cache_t *_tio_cache;
-static struct bio_set *dm_set;
-
static int __init local_init(void)
{
int r;
- dm_set = bioset_create(16, 16, 4);
- if (!dm_set)
- return -ENOMEM;
-
/* allocate a slab for the dm_ios */
_io_cache = kmem_cache_create("dm_io",
sizeof(struct dm_io), 0, 0, NULL, NULL);
@@ -164,8 +161,6 @@ static void local_exit(void)
kmem_cache_destroy(_tio_cache);
kmem_cache_destroy(_io_cache);
- bioset_free(dm_set);
-
if (unregister_blkdev(_major, _name) < 0)
DMERR("unregister_blkdev failed");
@@ -288,6 +283,45 @@ static int dm_blk_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return dm_get_geometry(md, geo);
}
+static int dm_blk_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mapped_device *md;
+ struct dm_table *map;
+ struct dm_target *tgt;
+ int r = -ENOTTY;
+
+ /* We don't really need this lock, but we do need 'inode'. */
+ unlock_kernel();
+
+ md = inode->i_bdev->bd_disk->private_data;
+
+ map = dm_get_table(md);
+
+ if (!map || !dm_table_get_size(map))
+ goto out;
+
+ /* We only support devices that have a single target */
+ if (dm_table_get_num_targets(map) != 1)
+ goto out;
+
+ tgt = dm_table_get_target(map, 0);
+
+ if (dm_suspended(md)) {
+ r = -EAGAIN;
+ goto out;
+ }
+
+ if (tgt->type->ioctl)
+ r = tgt->type->ioctl(tgt, inode, file, cmd, arg);
+
+out:
+ dm_table_put(map);
+
+ lock_kernel();
+ return r;
+}
+
static inline struct dm_io *alloc_io(struct mapped_device *md)
{
return mempool_alloc(md->io_pool, GFP_NOIO);
@@ -435,7 +469,7 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
{
int r = 0;
struct target_io *tio = bio->bi_private;
- struct dm_io *io = tio->io;
+ struct mapped_device *md = tio->io->md;
dm_endio_fn endio = tio->ti->type->end_io;
if (bio->bi_size)
@@ -454,9 +488,15 @@ static int clone_endio(struct bio *bio, unsigned int done, int error)
return 1;
}
- free_tio(io->md, tio);
- dec_pending(io, error);
+ dec_pending(tio->io, error);
+
+ /*
+ * Store md for cleanup instead of tio which is about to get freed.
+ */
+ bio->bi_private = md->bs;
+
bio_put(bio);
+ free_tio(md, tio);
return r;
}
@@ -485,6 +525,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
{
int r;
sector_t sector;
+ struct mapped_device *md;
/*
* Sanity checks.
@@ -514,10 +555,14 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
else if (r < 0) {
/* error the io and bail out */
- struct dm_io *io = tio->io;
- free_tio(tio->io->md, tio);
- dec_pending(io, r);
+ md = tio->io->md;
+ dec_pending(tio->io, r);
+ /*
+ * Store bio_set for cleanup.
+ */
+ clone->bi_private = md->bs;
bio_put(clone);
+ free_tio(md, tio);
}
}
@@ -533,7 +578,9 @@ struct clone_info {
static void dm_bio_destructor(struct bio *bio)
{
- bio_free(bio, dm_set);
+ struct bio_set *bs = bio->bi_private;
+
+ bio_free(bio, bs);
}
/*
@@ -541,12 +588,12 @@ static void dm_bio_destructor(struct bio *bio)
*/
static struct bio *split_bvec(struct bio *bio, sector_t sector,
unsigned short idx, unsigned int offset,
- unsigned int len)
+ unsigned int len, struct bio_set *bs)
{
struct bio *clone;
struct bio_vec *bv = bio->bi_io_vec + idx;
- clone = bio_alloc_bioset(GFP_NOIO, 1, dm_set);
+ clone = bio_alloc_bioset(GFP_NOIO, 1, bs);
clone->bi_destructor = dm_bio_destructor;
*clone->bi_io_vec = *bv;
@@ -566,11 +613,13 @@ static struct bio *split_bvec(struct bio *bio, sector_t sector,
*/
static struct bio *clone_bio(struct bio *bio, sector_t sector,
unsigned short idx, unsigned short bv_count,
- unsigned int len)
+ unsigned int len, struct bio_set *bs)
{
struct bio *clone;
- clone = bio_clone(bio, GFP_NOIO);
+ clone = bio_alloc_bioset(GFP_NOIO, bio->bi_max_vecs, bs);
+ __bio_clone(clone, bio);
+ clone->bi_destructor = dm_bio_destructor;
clone->bi_sector = sector;
clone->bi_idx = idx;
clone->bi_vcnt = idx + bv_count;
@@ -601,7 +650,8 @@ static void __clone_and_map(struct clone_info *ci)
* the remaining io with a single clone.
*/
clone = clone_bio(bio, ci->sector, ci->idx,
- bio->bi_vcnt - ci->idx, ci->sector_count);
+ bio->bi_vcnt - ci->idx, ci->sector_count,
+ ci->md->bs);
__map_bio(ti, clone, tio);
ci->sector_count = 0;
@@ -624,7 +674,8 @@ static void __clone_and_map(struct clone_info *ci)
len += bv_len;
}
- clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len);
+ clone = clone_bio(bio, ci->sector, ci->idx, i - ci->idx, len,
+ ci->md->bs);
__map_bio(ti, clone, tio);
ci->sector += len;
@@ -653,7 +704,8 @@ static void __clone_and_map(struct clone_info *ci)
len = min(remaining, max);
clone = split_bvec(bio, ci->sector, ci->idx,
- bv->bv_offset + offset, len);
+ bv->bv_offset + offset, len,
+ ci->md->bs);
__map_bio(ti, clone, tio);
@@ -903,7 +955,7 @@ static struct mapped_device *alloc_dev(int minor)
md->queue = blk_alloc_queue(GFP_KERNEL);
if (!md->queue)
- goto bad1;
+ goto bad1_free_minor;
md->queue->queuedata = md;
md->queue->backing_dev_info.congested_fn = dm_any_congested;
@@ -921,6 +973,10 @@ static struct mapped_device *alloc_dev(int minor)
if (!md->tio_pool)
goto bad3;
+ md->bs = bioset_create(16, 16, 4);
+ if (!md->bs)
+ goto bad_no_bioset;
+
md->disk = alloc_disk(1);
if (!md->disk)
goto bad4;
@@ -948,11 +1004,14 @@ static struct mapped_device *alloc_dev(int minor)
return md;
bad4:
+ bioset_free(md->bs);
+ bad_no_bioset:
mempool_destroy(md->tio_pool);
bad3:
mempool_destroy(md->io_pool);
bad2:
blk_cleanup_queue(md->queue);
+ bad1_free_minor:
free_minor(minor);
bad1:
module_put(THIS_MODULE);
@@ -971,6 +1030,7 @@ static void free_dev(struct mapped_device *md)
}
mempool_destroy(md->tio_pool);
mempool_destroy(md->io_pool);
+ bioset_free(md->bs);
del_gendisk(md->disk);
free_minor(minor);
@@ -1319,7 +1379,9 @@ int dm_resume(struct mapped_device *md)
if (!map || !dm_table_get_size(map))
goto out;
- dm_table_resume_targets(map);
+ r = dm_table_resume_targets(map);
+ if (r)
+ goto out;
down_write(&md->io_lock);
clear_bit(DMF_BLOCK_IO, &md->flags);
@@ -1337,6 +1399,8 @@ int dm_resume(struct mapped_device *md)
dm_table_unplug_all(map);
+ kobject_uevent(&md->disk->kobj, KOBJ_CHANGE);
+
r = 0;
out:
@@ -1377,6 +1441,7 @@ int dm_suspended(struct mapped_device *md)
static struct block_device_operations dm_blk_dops = {
.open = dm_blk_open,
.release = dm_blk_close,
+ .ioctl = dm_blk_ioctl,
.getgeo = dm_blk_getgeo,
.owner = THIS_MODULE
};
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 3c03c0ecab7e..a48ec5e3c1f4 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -21,6 +21,11 @@
#define DMERR(f, arg...) printk(KERN_ERR DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
#define DMWARN(f, arg...) printk(KERN_WARNING DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
#define DMINFO(f, arg...) printk(KERN_INFO DM_NAME ": " DM_MSG_PREFIX ": " f "\n", ## arg)
+#ifdef CONFIG_DM_DEBUG
+# define DMDEBUG(f, arg...) printk(KERN_DEBUG DM_NAME ": " DM_MSG_PREFIX " DEBUG: " f "\n", ## arg)
+#else
+# define DMDEBUG(f, arg...) do {} while (0)
+#endif
#define DMEMIT(x...) sz += ((sz >= maxlen) ? \
0 : scnprintf(result + sz, maxlen - sz, x))
@@ -52,7 +57,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q);
struct list_head *dm_table_get_devices(struct dm_table *t);
void dm_table_presuspend_targets(struct dm_table *t);
void dm_table_postsuspend_targets(struct dm_table *t);
-void dm_table_resume_targets(struct dm_table *t);
+int dm_table_resume_targets(struct dm_table *t);
int dm_table_any_congested(struct dm_table *t, int bdi_bits);
void dm_table_unplug_all(struct dm_table *t);
int dm_table_flush_all(struct dm_table *t);
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index b99c19c7eb22..c625ddb8833d 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -111,6 +111,19 @@ static int linear_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
+static int linear_congested(void *data, int bits)
+{
+ mddev_t *mddev = data;
+ linear_conf_t *conf = mddev_to_conf(mddev);
+ int i, ret = 0;
+
+ for (i = 0; i < mddev->raid_disks && !ret ; i++) {
+ request_queue_t *q = bdev_get_queue(conf->disks[i].rdev->bdev);
+ ret |= bdi_congested(&q->backing_dev_info, bits);
+ }
+ return ret;
+}
+
static linear_conf_t *linear_conf(mddev_t *mddev, int raid_disks)
{
linear_conf_t *conf;
@@ -269,6 +282,8 @@ static int linear_run (mddev_t *mddev)
blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
mddev->queue->unplug_fn = linear_unplug;
mddev->queue->issue_flush_fn = linear_issue_flush;
+ mddev->queue->backing_dev_info.congested_fn = linear_congested;
+ mddev->queue->backing_dev_info.congested_data = mddev;
return 0;
}
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 8dbab2ef3885..7daa7b1e145f 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -389,8 +389,12 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error)
if (bio->bi_size)
return 1;
- if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags))
+ if (error || !test_bit(BIO_UPTODATE, &bio->bi_flags)) {
+ printk("md: super_written gets error=%d, uptodate=%d\n",
+ error, test_bit(BIO_UPTODATE, &bio->bi_flags));
+ WARN_ON(test_bit(BIO_UPTODATE, &bio->bi_flags));
md_error(mddev, rdev);
+ }
if (atomic_dec_and_test(&mddev->pending_writes))
wake_up(&mddev->sb_wait);
@@ -970,12 +974,13 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
* version 1 superblock
*/
-static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
+static __le32 calc_sb_1_csum(struct mdp_superblock_1 * sb)
{
- unsigned int disk_csum, csum;
+ __le32 disk_csum;
+ u32 csum;
unsigned long long newcsum;
int size = 256 + le32_to_cpu(sb->max_dev)*2;
- unsigned int *isuper = (unsigned int*)sb;
+ __le32 *isuper = (__le32*)sb;
int i;
disk_csum = sb->sb_csum;
@@ -985,7 +990,7 @@ static unsigned int calc_sb_1_csum(struct mdp_superblock_1 * sb)
newcsum += le32_to_cpu(*isuper++);
if (size == 2)
- newcsum += le16_to_cpu(*(unsigned short*) isuper);
+ newcsum += le16_to_cpu(*(__le16*) isuper);
csum = (newcsum & 0xffffffff) + (newcsum >> 32);
sb->sb_csum = disk_csum;
@@ -1102,7 +1107,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
if (le32_to_cpu(sb->chunksize))
rdev->size &= ~((sector_t)le32_to_cpu(sb->chunksize)/2 - 1);
- if (le32_to_cpu(sb->size) > rdev->size*2)
+ if (le64_to_cpu(sb->size) > rdev->size*2)
return -EINVAL;
return ret;
}
@@ -1224,7 +1229,7 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
else
sb->resync_offset = cpu_to_le64(0);
- sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors);
+ sb->cnt_corrected_read = cpu_to_le32(atomic_read(&rdev->corrected_errors));
sb->raid_disks = cpu_to_le32(mddev->raid_disks);
sb->size = cpu_to_le64(mddev->size<<1);
@@ -1587,7 +1592,7 @@ static void sync_sbs(mddev_t * mddev, int nospares)
}
}
-void md_update_sb(mddev_t * mddev)
+static void md_update_sb(mddev_t * mddev, int force_change)
{
int err;
struct list_head *tmp;
@@ -1598,7 +1603,18 @@ void md_update_sb(mddev_t * mddev)
repeat:
spin_lock_irq(&mddev->write_lock);
- if (mddev->degraded && mddev->sb_dirty == 3)
+ set_bit(MD_CHANGE_PENDING, &mddev->flags);
+ if (test_and_clear_bit(MD_CHANGE_DEVS, &mddev->flags))
+ force_change = 1;
+ if (test_and_clear_bit(MD_CHANGE_CLEAN, &mddev->flags))
+ /* just a clean<-> dirty transition, possibly leave spares alone,
+ * though if events isn't the right even/odd, we will have to do
+ * spares after all
+ */
+ nospares = 1;
+ if (force_change)
+ nospares = 0;
+ if (mddev->degraded)
/* If the array is degraded, then skipping spares is both
* dangerous and fairly pointless.
* Dangerous because a device that was removed from the array
@@ -1608,20 +1624,14 @@ repeat:
* then a recovery will happen and soon that array won't
* be degraded any more and the spare can go back to sleep then.
*/
- mddev->sb_dirty = 1;
+ nospares = 0;
sync_req = mddev->in_sync;
mddev->utime = get_seconds();
- if (mddev->sb_dirty == 3)
- /* just a clean<-> dirty transition, possibly leave spares alone,
- * though if events isn't the right even/odd, we will have to do
- * spares after all
- */
- nospares = 1;
/* If this is just a dirty<->clean transition, and the array is clean
* and 'events' is odd, we can roll back to the previous clean state */
- if (mddev->sb_dirty == 3
+ if (nospares
&& (mddev->in_sync && mddev->recovery_cp == MaxSector)
&& (mddev->events & 1))
mddev->events--;
@@ -1652,7 +1662,6 @@ repeat:
MD_BUG();
mddev->events --;
}
- mddev->sb_dirty = 2;
sync_sbs(mddev, nospares);
/*
@@ -1660,7 +1669,7 @@ repeat:
* nonpersistent superblocks
*/
if (!mddev->persistent) {
- mddev->sb_dirty = 0;
+ clear_bit(MD_CHANGE_PENDING, &mddev->flags);
spin_unlock_irq(&mddev->write_lock);
wake_up(&mddev->sb_wait);
return;
@@ -1697,20 +1706,20 @@ repeat:
break;
}
md_super_wait(mddev);
- /* if there was a failure, sb_dirty was set to 1, and we re-write super */
+ /* if there was a failure, MD_CHANGE_DEVS was set, and we re-write super */
spin_lock_irq(&mddev->write_lock);
- if (mddev->in_sync != sync_req|| mddev->sb_dirty == 1) {
+ if (mddev->in_sync != sync_req ||
+ test_bit(MD_CHANGE_DEVS, &mddev->flags)) {
/* have to write it out again */
spin_unlock_irq(&mddev->write_lock);
goto repeat;
}
- mddev->sb_dirty = 0;
+ clear_bit(MD_CHANGE_PENDING, &mddev->flags);
spin_unlock_irq(&mddev->write_lock);
wake_up(&mddev->sb_wait);
}
-EXPORT_SYMBOL_GPL(md_update_sb);
/* words written to sysfs files may, or my not, be \n terminated.
* We want to accept with case. For this we use cmd_match.
@@ -1783,7 +1792,7 @@ state_store(mdk_rdev_t *rdev, const char *buf, size_t len)
else {
mddev_t *mddev = rdev->mddev;
kick_rdev_from_array(rdev);
- md_update_sb(mddev);
+ md_update_sb(mddev, 1);
md_new_event(mddev);
err = 0;
}
@@ -2426,7 +2435,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
spin_lock_irq(&mddev->write_lock);
if (atomic_read(&mddev->writes_pending) == 0) {
mddev->in_sync = 1;
- mddev->sb_dirty = 1;
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
}
spin_unlock_irq(&mddev->write_lock);
} else {
@@ -2438,7 +2447,7 @@ array_state_store(mddev_t *mddev, const char *buf, size_t len)
case active:
if (mddev->pers) {
restart_array(mddev);
- mddev->sb_dirty = 0;
+ clear_bit(MD_CHANGE_CLEAN, &mddev->flags);
wake_up(&mddev->sb_wait);
err = 0;
} else {
@@ -2520,6 +2529,36 @@ static struct md_sysfs_entry md_new_device =
__ATTR(new_dev, S_IWUSR, null_show, new_dev_store);
static ssize_t
+bitmap_store(mddev_t *mddev, const char *buf, size_t len)
+{
+ char *end;
+ unsigned long chunk, end_chunk;
+
+ if (!mddev->bitmap)
+ goto out;
+ /* buf should be <chunk> <chunk> ... or <chunk>-<chunk> ... (range) */
+ while (*buf) {
+ chunk = end_chunk = simple_strtoul(buf, &end, 0);
+ if (buf == end) break;
+ if (*end == '-') { /* range */
+ buf = end + 1;
+ end_chunk = simple_strtoul(buf, &end, 0);
+ if (buf == end) break;
+ }
+ if (*end && !isspace(*end)) break;
+ bitmap_dirty_bits(mddev->bitmap, chunk, end_chunk);
+ buf = end;
+ while (isspace(*buf)) buf++;
+ }
+ bitmap_unplug(mddev->bitmap); /* flush the bits to disk */
+out:
+ return len;
+}
+
+static struct md_sysfs_entry md_bitmap =
+__ATTR(bitmap_set_bits, S_IWUSR, null_show, bitmap_store);
+
+static ssize_t
size_show(mddev_t *mddev, char *page)
{
return sprintf(page, "%llu\n", (unsigned long long)mddev->size);
@@ -2543,7 +2582,7 @@ size_store(mddev_t *mddev, const char *buf, size_t len)
if (mddev->pers) {
err = update_size(mddev, size);
- md_update_sb(mddev);
+ md_update_sb(mddev, 1);
} else {
if (mddev->size == 0 ||
mddev->size > size)
@@ -2839,6 +2878,7 @@ static struct attribute *md_redundancy_attrs[] = {
&md_sync_completed.attr,
&md_suspend_lo.attr,
&md_suspend_hi.attr,
+ &md_bitmap.attr,
NULL,
};
static struct attribute_group md_redundancy_group = {
@@ -3111,8 +3151,8 @@ static int do_md_run(mddev_t * mddev)
set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
- if (mddev->sb_dirty)
- md_update_sb(mddev);
+ if (mddev->flags)
+ md_update_sb(mddev, 0);
set_capacity(disk, mddev->array_size<<1);
@@ -3275,10 +3315,10 @@ static int do_md_stop(mddev_t * mddev, int mode)
if (mddev->ro)
mddev->ro = 0;
}
- if (!mddev->in_sync || mddev->sb_dirty) {
+ if (!mddev->in_sync || mddev->flags) {
/* mark array as shutdown cleanly */
mddev->in_sync = 1;
- md_update_sb(mddev);
+ md_update_sb(mddev, 1);
}
if (mode == 1)
set_disk_ro(disk, 1);
@@ -3374,6 +3414,7 @@ static void autorun_devices(int part)
printk(KERN_INFO "md: autorun ...\n");
while (!list_empty(&pending_raid_disks)) {
+ int unit;
dev_t dev;
LIST_HEAD(candidates);
rdev0 = list_entry(pending_raid_disks.next,
@@ -3393,16 +3434,19 @@ static void autorun_devices(int part)
* mostly sane superblocks. It's time to allocate the
* mddev.
*/
- if (rdev0->preferred_minor < 0 || rdev0->preferred_minor >= MAX_MD_DEVS) {
+ if (part) {
+ dev = MKDEV(mdp_major,
+ rdev0->preferred_minor << MdpMinorShift);
+ unit = MINOR(dev) >> MdpMinorShift;
+ } else {
+ dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
+ unit = MINOR(dev);
+ }
+ if (rdev0->preferred_minor != unit) {
printk(KERN_INFO "md: unit number in %s is bad: %d\n",
bdevname(rdev0->bdev, b), rdev0->preferred_minor);
break;
}
- if (part)
- dev = MKDEV(mdp_major,
- rdev0->preferred_minor << MdpMinorShift);
- else
- dev = MKDEV(MD_MAJOR, rdev0->preferred_minor);
md_probe(dev, NULL, NULL);
mddev = mddev_find(dev);
@@ -3440,67 +3484,6 @@ static void autorun_devices(int part)
printk(KERN_INFO "md: ... autorun DONE.\n");
}
-/*
- * import RAID devices based on one partition
- * if possible, the array gets run as well.
- */
-
-static int autostart_array(dev_t startdev)
-{
- char b[BDEVNAME_SIZE];
- int err = -EINVAL, i;
- mdp_super_t *sb = NULL;
- mdk_rdev_t *start_rdev = NULL, *rdev;
-
- start_rdev = md_import_device(startdev, 0, 0);
- if (IS_ERR(start_rdev))
- return err;
-
-
- /* NOTE: this can only work for 0.90.0 superblocks */
- sb = (mdp_super_t*)page_address(start_rdev->sb_page);
- if (sb->major_version != 0 ||
- sb->minor_version != 90 ) {
- printk(KERN_WARNING "md: can only autostart 0.90.0 arrays\n");
- export_rdev(start_rdev);
- return err;
- }
-
- if (test_bit(Faulty, &start_rdev->flags)) {
- printk(KERN_WARNING
- "md: can not autostart based on faulty %s!\n",
- bdevname(start_rdev->bdev,b));
- export_rdev(start_rdev);
- return err;
- }
- list_add(&start_rdev->same_set, &pending_raid_disks);
-
- for (i = 0; i < MD_SB_DISKS; i++) {
- mdp_disk_t *desc = sb->disks + i;
- dev_t dev = MKDEV(desc->major, desc->minor);
-
- if (!dev)
- continue;
- if (dev == startdev)
- continue;
- if (MAJOR(dev) != desc->major || MINOR(dev) != desc->minor)
- continue;
- rdev = md_import_device(dev, 0, 0);
- if (IS_ERR(rdev))
- continue;
-
- list_add(&rdev->same_set, &pending_raid_disks);
- }
-
- /*
- * possibly return codes
- */
- autorun_devices(0);
- return 0;
-
-}
-
-
static int get_version(void __user * arg)
{
mdu_version_t ver;
@@ -3808,7 +3791,7 @@ static int hot_remove_disk(mddev_t * mddev, dev_t dev)
goto busy;
kick_rdev_from_array(rdev);
- md_update_sb(mddev);
+ md_update_sb(mddev, 1);
md_new_event(mddev);
return 0;
@@ -3867,6 +3850,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
}
clear_bit(In_sync, &rdev->flags);
rdev->desc_nr = -1;
+ rdev->saved_raid_disk = -1;
err = bind_rdev_to_array(rdev, mddev);
if (err)
goto abort_export;
@@ -3885,7 +3869,7 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
rdev->raid_disk = -1;
- md_update_sb(mddev);
+ md_update_sb(mddev, 1);
/*
* Kick recovery, maybe this spare has to be added to the
@@ -4016,7 +4000,8 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
mddev->max_disks = MD_SB_DISKS;
- mddev->sb_dirty = 1;
+ mddev->flags = 0;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
mddev->default_bitmap_offset = MD_SB_BYTES >> 9;
mddev->bitmap_offset = 0;
@@ -4185,7 +4170,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
mddev->bitmap_offset = 0;
}
}
- md_update_sb(mddev);
+ md_update_sb(mddev, 1);
return rv;
}
@@ -4259,27 +4244,6 @@ static int md_ioctl(struct inode *inode, struct file *file,
goto abort;
}
-
- if (cmd == START_ARRAY) {
- /* START_ARRAY doesn't need to lock the array as autostart_array
- * does the locking, and it could even be a different array
- */
- static int cnt = 3;
- if (cnt > 0 ) {
- printk(KERN_WARNING
- "md: %s(pid %d) used deprecated START_ARRAY ioctl. "
- "This will not be supported beyond July 2006\n",
- current->comm, current->pid);
- cnt--;
- }
- err = autostart_array(new_decode_dev(arg));
- if (err) {
- printk(KERN_WARNING "md: autostart failed!\n");
- goto abort;
- }
- goto done;
- }
-
err = mddev_lock(mddev);
if (err) {
printk(KERN_INFO
@@ -4476,8 +4440,7 @@ static int md_release(struct inode *inode, struct file * file)
{
mddev_t *mddev = inode->i_bdev->bd_disk->private_data;
- if (!mddev)
- BUG();
+ BUG_ON(!mddev);
mddev_put(mddev);
return 0;
@@ -4687,9 +4650,11 @@ static void status_resync(struct seq_file *seq, mddev_t * mddev)
seq_printf(seq, " %s =%3u.%u%% (%llu/%llu)",
(test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)?
"reshape" :
- (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
- "resync" : "recovery")),
- per_milli/10, per_milli % 10,
+ (test_bit(MD_RECOVERY_CHECK, &mddev->recovery)?
+ "check" :
+ (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) ?
+ "resync" : "recovery"))),
+ per_milli/10, per_milli % 10,
(unsigned long long) resync,
(unsigned long long) max_blocks);
@@ -4948,6 +4913,7 @@ static unsigned int mdstat_poll(struct file *filp, poll_table *wait)
}
static struct file_operations md_seq_fops = {
+ .owner = THIS_MODULE,
.open = md_seq_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -5042,12 +5008,12 @@ void md_write_start(mddev_t *mddev, struct bio *bi)
spin_lock_irq(&mddev->write_lock);
if (mddev->in_sync) {
mddev->in_sync = 0;
- mddev->sb_dirty = 3;
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
md_wakeup_thread(mddev->thread);
}
spin_unlock_irq(&mddev->write_lock);
}
- wait_event(mddev->sb_wait, mddev->sb_dirty==0);
+ wait_event(mddev->sb_wait, mddev->flags==0);
}
void md_write_end(mddev_t *mddev)
@@ -5078,6 +5044,7 @@ void md_do_sync(mddev_t *mddev)
int skipped = 0;
struct list_head *rtmp;
mdk_rdev_t *rdev;
+ char *desc;
/* just incase thread restarts... */
if (test_bit(MD_RECOVERY_DONE, &mddev->recovery))
@@ -5085,6 +5052,18 @@ void md_do_sync(mddev_t *mddev)
if (mddev->ro) /* never try to sync a read-only array */
return;
+ if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
+ if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+ desc = "data-check";
+ else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ desc = "requested-resync";
+ else
+ desc = "resync";
+ } else if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ desc = "reshape";
+ else
+ desc = "recovery";
+
/* we overload curr_resync somewhat here.
* 0 == not engaged in resync at all
* 2 == checking that there is no conflict with another sync
@@ -5128,10 +5107,10 @@ void md_do_sync(mddev_t *mddev)
prepare_to_wait(&resync_wait, &wq, TASK_UNINTERRUPTIBLE);
if (!kthread_should_stop() &&
mddev2->curr_resync >= mddev->curr_resync) {
- printk(KERN_INFO "md: delaying resync of %s"
- " until %s has finished resync (they"
+ printk(KERN_INFO "md: delaying %s of %s"
+ " until %s has finished (they"
" share one or more physical units)\n",
- mdname(mddev), mdname(mddev2));
+ desc, mdname(mddev), mdname(mddev2));
mddev_put(mddev2);
schedule();
finish_wait(&resync_wait, &wq);
@@ -5167,12 +5146,12 @@ void md_do_sync(mddev_t *mddev)
j = rdev->recovery_offset;
}
- printk(KERN_INFO "md: syncing RAID array %s\n", mdname(mddev));
- printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed:"
- " %d KB/sec/disc.\n", speed_min(mddev));
+ printk(KERN_INFO "md: %s of RAID array %s\n", desc, mdname(mddev));
+ printk(KERN_INFO "md: minimum _guaranteed_ speed:"
+ " %d KB/sec/disk.\n", speed_min(mddev));
printk(KERN_INFO "md: using maximum available idle IO bandwidth "
- "(but not more than %d KB/sec) for reconstruction.\n",
- speed_max(mddev));
+ "(but not more than %d KB/sec) for %s.\n",
+ speed_max(mddev), desc);
is_mddev_idle(mddev); /* this also initializes IO event counters */
@@ -5198,8 +5177,8 @@ void md_do_sync(mddev_t *mddev)
if (j>2) {
printk(KERN_INFO
- "md: resuming recovery of %s from checkpoint.\n",
- mdname(mddev));
+ "md: resuming %s of %s from checkpoint.\n",
+ desc, mdname(mddev));
mddev->curr_resync = j;
}
@@ -5282,7 +5261,7 @@ void md_do_sync(mddev_t *mddev)
}
}
}
- printk(KERN_INFO "md: %s: sync done.\n",mdname(mddev));
+ printk(KERN_INFO "md: %s: %s done.\n",mdname(mddev), desc);
/*
* this also signals 'finished resyncing' to md_stop
*/
@@ -5302,8 +5281,8 @@ void md_do_sync(mddev_t *mddev)
if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
if (mddev->curr_resync >= mddev->recovery_cp) {
printk(KERN_INFO
- "md: checkpointing recovery of %s.\n",
- mdname(mddev));
+ "md: checkpointing %s of %s.\n",
+ desc, mdname(mddev));
mddev->recovery_cp = mddev->curr_resync;
}
} else
@@ -5317,7 +5296,6 @@ void md_do_sync(mddev_t *mddev)
!test_bit(In_sync, &rdev->flags) &&
rdev->recovery_offset < mddev->curr_resync)
rdev->recovery_offset = mddev->curr_resync;
- mddev->sb_dirty = 1;
}
}
@@ -5374,7 +5352,7 @@ void md_check_recovery(mddev_t *mddev)
}
if ( ! (
- mddev->sb_dirty ||
+ mddev->flags ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery) ||
test_bit(MD_RECOVERY_DONE, &mddev->recovery) ||
(mddev->safemode == 1) ||
@@ -5390,14 +5368,14 @@ void md_check_recovery(mddev_t *mddev)
if (mddev->safemode && !atomic_read(&mddev->writes_pending) &&
!mddev->in_sync && mddev->recovery_cp == MaxSector) {
mddev->in_sync = 1;
- mddev->sb_dirty = 3;
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
}
if (mddev->safemode == 1)
mddev->safemode = 0;
spin_unlock_irq(&mddev->write_lock);
- if (mddev->sb_dirty)
- md_update_sb(mddev);
+ if (mddev->flags)
+ md_update_sb(mddev, 0);
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) &&
@@ -5416,7 +5394,7 @@ void md_check_recovery(mddev_t *mddev)
/* activate any spares */
mddev->pers->spare_active(mddev);
}
- md_update_sb(mddev);
+ md_update_sb(mddev, 1);
/* if array is no-longer degraded, then any saved_raid_disk
* information must be scrapped
@@ -5556,22 +5534,15 @@ static void md_geninit(void)
static int __init md_init(void)
{
- printk(KERN_INFO "md: md driver %d.%d.%d MAX_MD_DEVS=%d,"
- " MD_SB_DISKS=%d\n",
- MD_MAJOR_VERSION, MD_MINOR_VERSION,
- MD_PATCHLEVEL_VERSION, MAX_MD_DEVS, MD_SB_DISKS);
- printk(KERN_INFO "md: bitmap version %d.%d\n", BITMAP_MAJOR_HI,
- BITMAP_MINOR);
-
if (register_blkdev(MAJOR_NR, "md"))
return -1;
if ((mdp_major=register_blkdev(0, "mdp"))<=0) {
unregister_blkdev(MAJOR_NR, "md");
return -1;
}
- blk_register_region(MKDEV(MAJOR_NR, 0), MAX_MD_DEVS, THIS_MODULE,
- md_probe, NULL, NULL);
- blk_register_region(MKDEV(mdp_major, 0), MAX_MD_DEVS<<MdpMinorShift, THIS_MODULE,
+ blk_register_region(MKDEV(MAJOR_NR, 0), 1UL<<MINORBITS, THIS_MODULE,
+ md_probe, NULL, NULL);
+ blk_register_region(MKDEV(mdp_major, 0), 1UL<<MINORBITS, THIS_MODULE,
md_probe, NULL, NULL);
register_reboot_notifier(&md_notifier);
@@ -5630,8 +5601,8 @@ static __exit void md_exit(void)
mddev_t *mddev;
struct list_head *tmp;
- blk_unregister_region(MKDEV(MAJOR_NR,0), MAX_MD_DEVS);
- blk_unregister_region(MKDEV(mdp_major,0), MAX_MD_DEVS << MdpMinorShift);
+ blk_unregister_region(MKDEV(MAJOR_NR,0), 1U << MINORBITS);
+ blk_unregister_region(MKDEV(mdp_major,0), 1U << MINORBITS);
unregister_blkdev(MAJOR_NR,"md");
unregister_blkdev(mdp_major, "mdp");
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 1cc9de44ce86..a6260f0e3b9e 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -228,6 +228,28 @@ static int multipath_issue_flush(request_queue_t *q, struct gendisk *disk,
rcu_read_unlock();
return ret;
}
+static int multipath_congested(void *data, int bits)
+{
+ mddev_t *mddev = data;
+ multipath_conf_t *conf = mddev_to_conf(mddev);
+ int i, ret = 0;
+
+ rcu_read_lock();
+ for (i = 0; i < mddev->raid_disks ; i++) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->multipaths[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
+ request_queue_t *q = bdev_get_queue(rdev->bdev);
+
+ ret |= bdi_congested(&q->backing_dev_info, bits);
+ /* Just like multipath_map, we just check the
+ * first available device
+ */
+ break;
+ }
+ }
+ rcu_read_unlock();
+ return ret;
+}
/*
* Careful, this can execute in IRQ contexts as well!
@@ -253,7 +275,7 @@ static void multipath_error (mddev_t *mddev, mdk_rdev_t *rdev)
char b[BDEVNAME_SIZE];
clear_bit(In_sync, &rdev->flags);
set_bit(Faulty, &rdev->flags);
- mddev->sb_dirty = 1;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
conf->working_disks--;
printk(KERN_ALERT "multipath: IO failure on %s,"
" disabling IO path. \n Operation continuing"
@@ -470,7 +492,6 @@ static int multipath_run (mddev_t *mddev)
}
conf->raid_disks = mddev->raid_disks;
- mddev->sb_dirty = 1;
conf->mddev = mddev;
spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
@@ -480,7 +501,7 @@ static int multipath_run (mddev_t *mddev)
mdname(mddev));
goto out_free_conf;
}
- mddev->degraded = conf->raid_disks = conf->working_disks;
+ mddev->degraded = conf->raid_disks - conf->working_disks;
conf->pool = mempool_create_kzalloc_pool(NR_RESERVED_BUFS,
sizeof(struct multipath_bh));
@@ -510,6 +531,8 @@ static int multipath_run (mddev_t *mddev)
mddev->queue->unplug_fn = multipath_unplug;
mddev->queue->issue_flush_fn = multipath_issue_flush;
+ mddev->queue->backing_dev_info.congested_fn = multipath_congested;
+ mddev->queue->backing_dev_info.congested_data = mddev;
return 0;
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index cb8c6317e4e5..dfe32149ad3a 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -60,6 +60,21 @@ static int raid0_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
+static int raid0_congested(void *data, int bits)
+{
+ mddev_t *mddev = data;
+ raid0_conf_t *conf = mddev_to_conf(mddev);
+ mdk_rdev_t **devlist = conf->strip_zone[0].dev;
+ int i, ret = 0;
+
+ for (i = 0; i < mddev->raid_disks && !ret ; i++) {
+ request_queue_t *q = bdev_get_queue(devlist[i]->bdev);
+
+ ret |= bdi_congested(&q->backing_dev_info, bits);
+ }
+ return ret;
+}
+
static int create_strip_zones (mddev_t *mddev)
{
@@ -236,6 +251,8 @@ static int create_strip_zones (mddev_t *mddev)
mddev->queue->unplug_fn = raid0_unplug;
mddev->queue->issue_flush_fn = raid0_issue_flush;
+ mddev->queue->backing_dev_info.congested_fn = raid0_congested;
+ mddev->queue->backing_dev_info.congested_data = mddev;
printk("raid0: done.\n");
return 0;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 3b4d69c05623..dc9d2def0270 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -271,7 +271,7 @@ static int raid1_end_read_request(struct bio *bio, unsigned int bytes_done, int
*/
update_head_pos(mirror, r1_bio);
- if (uptodate || conf->working_disks <= 1) {
+ 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
@@ -601,6 +601,32 @@ static int raid1_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
+static int raid1_congested(void *data, int bits)
+{
+ mddev_t *mddev = data;
+ conf_t *conf = mddev_to_conf(mddev);
+ int i, ret = 0;
+
+ rcu_read_lock();
+ for (i = 0; i < mddev->raid_disks; i++) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
+ request_queue_t *q = bdev_get_queue(rdev->bdev);
+
+ /* Note the '|| 1' - when read_balance prefers
+ * non-congested targets, it can be removed
+ */
+ if ((bits & (1<<BDI_write_congested)) || 1)
+ ret |= bdi_congested(&q->backing_dev_info, bits);
+ else
+ ret &= bdi_congested(&q->backing_dev_info, bits);
+ }
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+
/* Barriers....
* Sometimes we need to suspend IO while we do something else,
* either some resync/recovery, or reconfigure the array.
@@ -929,7 +955,7 @@ static void status(struct seq_file *seq, mddev_t *mddev)
int i;
seq_printf(seq, " [%d/%d] [", conf->raid_disks,
- conf->working_disks);
+ conf->raid_disks - mddev->degraded);
rcu_read_lock();
for (i = 0; i < conf->raid_disks; i++) {
mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
@@ -953,26 +979,27 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* else mark the drive as failed
*/
if (test_bit(In_sync, &rdev->flags)
- && conf->working_disks == 1)
+ && (conf->raid_disks - mddev->degraded) == 1)
/*
* Don't fail the drive, act as though we were just a
* normal single drive
*/
return;
- if (test_bit(In_sync, &rdev->flags)) {
+ if (test_and_clear_bit(In_sync, &rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded++;
- conf->working_disks--;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
/*
* if recovery is running, make sure it aborts.
*/
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
}
- clear_bit(In_sync, &rdev->flags);
set_bit(Faulty, &rdev->flags);
- mddev->sb_dirty = 1;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n"
" Operation continuing on %d devices\n",
- bdevname(rdev->bdev,b), conf->working_disks);
+ bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
}
static void print_conf(conf_t *conf)
@@ -984,7 +1011,7 @@ static void print_conf(conf_t *conf)
printk("(!conf)\n");
return;
}
- printk(" --- wd:%d rd:%d\n", conf->working_disks,
+ printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
conf->raid_disks);
rcu_read_lock();
@@ -1023,10 +1050,11 @@ static int raid1_spare_active(mddev_t *mddev)
mdk_rdev_t *rdev = conf->mirrors[i].rdev;
if (rdev
&& !test_bit(Faulty, &rdev->flags)
- && !test_bit(In_sync, &rdev->flags)) {
- conf->working_disks++;
+ && !test_and_set_bit(In_sync, &rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded--;
- set_bit(In_sync, &rdev->flags);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
}
}
@@ -1368,6 +1396,95 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
* 3. Performs writes following reads for array syncronising.
*/
+static void fix_read_error(conf_t *conf, int read_disk,
+ sector_t sect, int sectors)
+{
+ mddev_t *mddev = conf->mddev;
+ while(sectors) {
+ int s = sectors;
+ int d = read_disk;
+ int success = 0;
+ int start;
+ mdk_rdev_t *rdev;
+
+ if (s > (PAGE_SIZE>>9))
+ s = PAGE_SIZE >> 9;
+
+ do {
+ /* Note: no rcu protection needed here
+ * as this is synchronous in the raid1d thread
+ * which is the thread that might remove
+ * a device. If raid1d ever becomes multi-threaded....
+ */
+ rdev = conf->mirrors[d].rdev;
+ if (rdev &&
+ test_bit(In_sync, &rdev->flags) &&
+ sync_page_io(rdev->bdev,
+ sect + rdev->data_offset,
+ s<<9,
+ conf->tmppage, READ))
+ success = 1;
+ else {
+ d++;
+ if (d == conf->raid_disks)
+ d = 0;
+ }
+ } while (!success && d != read_disk);
+
+ if (!success) {
+ /* Cannot read from anywhere -- bye bye array */
+ md_error(mddev, conf->mirrors[read_disk].rdev);
+ break;
+ }
+ /* write it back and re-read */
+ start = d;
+ while (d != read_disk) {
+ if (d==0)
+ d = conf->raid_disks;
+ d--;
+ rdev = conf->mirrors[d].rdev;
+ if (rdev &&
+ test_bit(In_sync, &rdev->flags)) {
+ if (sync_page_io(rdev->bdev,
+ sect + rdev->data_offset,
+ s<<9, conf->tmppage, WRITE)
+ == 0)
+ /* Well, this device is dead */
+ md_error(mddev, rdev);
+ }
+ }
+ d = start;
+ while (d != read_disk) {
+ char b[BDEVNAME_SIZE];
+ if (d==0)
+ d = conf->raid_disks;
+ d--;
+ rdev = conf->mirrors[d].rdev;
+ if (rdev &&
+ test_bit(In_sync, &rdev->flags)) {
+ if (sync_page_io(rdev->bdev,
+ sect + rdev->data_offset,
+ s<<9, conf->tmppage, READ)
+ == 0)
+ /* Well, this device is dead */
+ md_error(mddev, rdev);
+ else {
+ atomic_add(s, &rdev->corrected_errors);
+ printk(KERN_INFO
+ "raid1:%s: read error corrected "
+ "(%d sectors at %llu on %s)\n",
+ mdname(mddev), s,
+ (unsigned long long)sect +
+ rdev->data_offset,
+ bdevname(rdev->bdev, b));
+ }
+ }
+ }
+ sectors -= s;
+ sect += s;
+ }
+}
+
static void raid1d(mddev_t *mddev)
{
r1bio_t *r1_bio;
@@ -1460,86 +1577,14 @@ static void raid1d(mddev_t *mddev)
* This is all done synchronously while the array is
* frozen
*/
- sector_t sect = r1_bio->sector;
- int sectors = r1_bio->sectors;
- freeze_array(conf);
- if (mddev->ro == 0) while(sectors) {
- int s = sectors;
- int d = r1_bio->read_disk;
- int success = 0;
-
- if (s > (PAGE_SIZE>>9))
- s = PAGE_SIZE >> 9;
-
- do {
- /* Note: no rcu protection needed here
- * as this is synchronous in the raid1d thread
- * which is the thread that might remove
- * a device. If raid1d ever becomes multi-threaded....
- */
- rdev = conf->mirrors[d].rdev;
- if (rdev &&
- test_bit(In_sync, &rdev->flags) &&
- sync_page_io(rdev->bdev,
- sect + rdev->data_offset,
- s<<9,
- conf->tmppage, READ))
- success = 1;
- else {
- d++;
- if (d == conf->raid_disks)
- d = 0;
- }
- } while (!success && d != r1_bio->read_disk);
-
- if (success) {
- /* write it back and re-read */
- int start = d;
- while (d != r1_bio->read_disk) {
- if (d==0)
- d = conf->raid_disks;
- d--;
- rdev = conf->mirrors[d].rdev;
- if (rdev &&
- test_bit(In_sync, &rdev->flags)) {
- if (sync_page_io(rdev->bdev,
- sect + rdev->data_offset,
- s<<9, conf->tmppage, WRITE) == 0)
- /* Well, this device is dead */
- md_error(mddev, rdev);
- }
- }
- d = start;
- while (d != r1_bio->read_disk) {
- if (d==0)
- d = conf->raid_disks;
- d--;
- rdev = conf->mirrors[d].rdev;
- if (rdev &&
- test_bit(In_sync, &rdev->flags)) {
- if (sync_page_io(rdev->bdev,
- sect + rdev->data_offset,
- s<<9, conf->tmppage, READ) == 0)
- /* Well, this device is dead */
- md_error(mddev, rdev);
- else {
- atomic_add(s, &rdev->corrected_errors);
- printk(KERN_INFO "raid1:%s: read error corrected (%d sectors at %llu on %s)\n",
- mdname(mddev), s, (unsigned long long)(sect + rdev->data_offset), bdevname(rdev->bdev, b));
- }
- }
- }
- } else {
- /* Cannot read from anywhere -- bye bye array */
- md_error(mddev, conf->mirrors[r1_bio->read_disk].rdev);
- break;
- }
- sectors -= s;
- sect += s;
+ if (mddev->ro == 0) {
+ freeze_array(conf);
+ fix_read_error(conf, r1_bio->read_disk,
+ r1_bio->sector,
+ r1_bio->sectors);
+ unfreeze_array(conf);
}
- unfreeze_array(conf);
-
bio = r1_bio->bios[r1_bio->read_disk];
if ((disk=read_balance(conf, r1_bio)) == -1) {
printk(KERN_ALERT "raid1: %s: unrecoverable I/O"
@@ -1884,15 +1929,11 @@ static int run(mddev_t *mddev)
blk_queue_max_sectors(mddev->queue, PAGE_SIZE>>9);
disk->head_position = 0;
- if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
- conf->working_disks++;
}
conf->raid_disks = mddev->raid_disks;
conf->mddev = mddev;
spin_lock_init(&conf->device_lock);
INIT_LIST_HEAD(&conf->retry_list);
- if (conf->working_disks == 1)
- mddev->recovery_cp = MaxSector;
spin_lock_init(&conf->resync_lock);
init_waitqueue_head(&conf->wait_barrier);
@@ -1900,11 +1941,6 @@ static int run(mddev_t *mddev)
bio_list_init(&conf->pending_bio_list);
bio_list_init(&conf->flushing_bio_list);
- if (!conf->working_disks) {
- printk(KERN_ERR "raid1: no operational mirrors for %s\n",
- mdname(mddev));
- goto out_free_conf;
- }
mddev->degraded = 0;
for (i = 0; i < conf->raid_disks; i++) {
@@ -1917,6 +1953,13 @@ static int run(mddev_t *mddev)
mddev->degraded++;
}
}
+ if (mddev->degraded == conf->raid_disks) {
+ printk(KERN_ERR "raid1: no operational mirrors for %s\n",
+ mdname(mddev));
+ goto out_free_conf;
+ }
+ if (conf->raid_disks - mddev->degraded == 1)
+ mddev->recovery_cp = MaxSector;
/*
* find the first working one and use it as a starting point
@@ -1948,6 +1991,8 @@ static int run(mddev_t *mddev)
mddev->queue->unplug_fn = raid1_unplug;
mddev->queue->issue_flush_fn = raid1_issue_flush;
+ mddev->queue->backing_dev_info.congested_fn = raid1_congested;
+ mddev->queue->backing_dev_info.congested_data = mddev;
return 0;
@@ -2035,7 +2080,7 @@ static int raid1_reshape(mddev_t *mddev)
mirror_info_t *newmirrors;
conf_t *conf = mddev_to_conf(mddev);
int cnt, raid_disks;
-
+ unsigned long flags;
int d, d2;
/* Cannot change chunk_size, layout, or level */
@@ -2094,7 +2139,9 @@ static int raid1_reshape(mddev_t *mddev)
kfree(conf->poolinfo);
conf->poolinfo = newpoolinfo;
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded += (raid_disks - conf->raid_disks);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
conf->raid_disks = mddev->raid_disks = raid_disks;
mddev->delta_disks = 0;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 016ddb831c9b..74f17a9a6ebb 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -648,6 +648,26 @@ static int raid10_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
+static int raid10_congested(void *data, int bits)
+{
+ mddev_t *mddev = data;
+ conf_t *conf = mddev_to_conf(mddev);
+ int i, ret = 0;
+
+ rcu_read_lock();
+ for (i = 0; i < mddev->raid_disks && ret == 0; i++) {
+ mdk_rdev_t *rdev = rcu_dereference(conf->mirrors[i].rdev);
+ if (rdev && !test_bit(Faulty, &rdev->flags)) {
+ request_queue_t *q = bdev_get_queue(rdev->bdev);
+
+ ret |= bdi_congested(&q->backing_dev_info, bits);
+ }
+ }
+ rcu_read_unlock();
+ return ret;
+}
+
+
/* Barriers....
* Sometimes we need to suspend IO while we do something else,
* either some resync/recovery, or reconfigure the array.
@@ -921,7 +941,7 @@ static void status(struct seq_file *seq, mddev_t *mddev)
seq_printf(seq, " %d far-copies", conf->far_copies);
}
seq_printf(seq, " [%d/%d] [", conf->raid_disks,
- conf->working_disks);
+ conf->raid_disks - mddev->degraded);
for (i = 0; i < conf->raid_disks; i++)
seq_printf(seq, "%s",
conf->mirrors[i].rdev &&
@@ -941,7 +961,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* else mark the drive as failed
*/
if (test_bit(In_sync, &rdev->flags)
- && conf->working_disks == 1)
+ && conf->raid_disks-mddev->degraded == 1)
/*
* Don't fail the drive, just return an IO error.
* The test should really be more sophisticated than
@@ -950,20 +970,21 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
* really dead" tests...
*/
return;
- if (test_bit(In_sync, &rdev->flags)) {
+ if (test_and_clear_bit(In_sync, &rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded++;
- conf->working_disks--;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
/*
* if recovery is running, make sure it aborts.
*/
set_bit(MD_RECOVERY_ERR, &mddev->recovery);
}
- clear_bit(In_sync, &rdev->flags);
set_bit(Faulty, &rdev->flags);
- mddev->sb_dirty = 1;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
printk(KERN_ALERT "raid10: Disk failure on %s, disabling device. \n"
" Operation continuing on %d devices\n",
- bdevname(rdev->bdev,b), conf->working_disks);
+ bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
}
static void print_conf(conf_t *conf)
@@ -976,7 +997,7 @@ static void print_conf(conf_t *conf)
printk("(!conf)\n");
return;
}
- printk(" --- wd:%d rd:%d\n", conf->working_disks,
+ printk(" --- wd:%d rd:%d\n", conf->raid_disks - conf->mddev->degraded,
conf->raid_disks);
for (i = 0; i < conf->raid_disks; i++) {
@@ -1034,10 +1055,11 @@ static int raid10_spare_active(mddev_t *mddev)
tmp = conf->mirrors + i;
if (tmp->rdev
&& !test_bit(Faulty, &tmp->rdev->flags)
- && !test_bit(In_sync, &tmp->rdev->flags)) {
- conf->working_disks++;
+ && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded--;
- set_bit(In_sync, &tmp->rdev->flags);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
}
}
@@ -1350,9 +1372,119 @@ static void recovery_request_write(mddev_t *mddev, r10bio_t *r10_bio)
*
* 1. Retries failed read operations on working mirrors.
* 2. Updates the raid superblock when problems encounter.
- * 3. Performs writes following reads for array syncronising.
+ * 3. Performs writes following reads for array synchronising.
*/
+static void fix_read_error(conf_t *conf, mddev_t *mddev, r10bio_t *r10_bio)
+{
+ int sect = 0; /* Offset from r10_bio->sector */
+ int sectors = r10_bio->sectors;
+ mdk_rdev_t*rdev;
+ while(sectors) {
+ int s = sectors;
+ int sl = r10_bio->read_slot;
+ int success = 0;
+ int start;
+
+ if (s > (PAGE_SIZE>>9))
+ s = PAGE_SIZE >> 9;
+
+ rcu_read_lock();
+ do {
+ int d = r10_bio->devs[sl].devnum;
+ rdev = rcu_dereference(conf->mirrors[d].rdev);
+ if (rdev &&
+ test_bit(In_sync, &rdev->flags)) {
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+ success = sync_page_io(rdev->bdev,
+ r10_bio->devs[sl].addr +
+ sect + rdev->data_offset,
+ s<<9,
+ conf->tmppage, READ);
+ rdev_dec_pending(rdev, mddev);
+ rcu_read_lock();
+ if (success)
+ break;
+ }
+ sl++;
+ if (sl == conf->copies)
+ sl = 0;
+ } while (!success && sl != r10_bio->read_slot);
+ rcu_read_unlock();
+
+ if (!success) {
+ /* Cannot read from anywhere -- bye bye array */
+ int dn = r10_bio->devs[r10_bio->read_slot].devnum;
+ md_error(mddev, conf->mirrors[dn].rdev);
+ break;
+ }
+
+ start = sl;
+ /* write it back and re-read */
+ rcu_read_lock();
+ while (sl != r10_bio->read_slot) {
+ int d;
+ if (sl==0)
+ sl = conf->copies;
+ sl--;
+ d = r10_bio->devs[sl].devnum;
+ rdev = rcu_dereference(conf->mirrors[d].rdev);
+ if (rdev &&
+ test_bit(In_sync, &rdev->flags)) {
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+ atomic_add(s, &rdev->corrected_errors);
+ if (sync_page_io(rdev->bdev,
+ r10_bio->devs[sl].addr +
+ sect + rdev->data_offset,
+ s<<9, conf->tmppage, WRITE)
+ == 0)
+ /* Well, this device is dead */
+ md_error(mddev, rdev);
+ rdev_dec_pending(rdev, mddev);
+ rcu_read_lock();
+ }
+ }
+ sl = start;
+ while (sl != r10_bio->read_slot) {
+ int d;
+ if (sl==0)
+ sl = conf->copies;
+ sl--;
+ d = r10_bio->devs[sl].devnum;
+ rdev = rcu_dereference(conf->mirrors[d].rdev);
+ if (rdev &&
+ test_bit(In_sync, &rdev->flags)) {
+ char b[BDEVNAME_SIZE];
+ atomic_inc(&rdev->nr_pending);
+ rcu_read_unlock();
+ if (sync_page_io(rdev->bdev,
+ r10_bio->devs[sl].addr +
+ sect + rdev->data_offset,
+ s<<9, conf->tmppage, READ) == 0)
+ /* Well, this device is dead */
+ md_error(mddev, rdev);
+ else
+ printk(KERN_INFO
+ "raid10:%s: read error corrected"
+ " (%d sectors at %llu on %s)\n",
+ mdname(mddev), s,
+ (unsigned long long)sect+
+ rdev->data_offset,
+ bdevname(rdev->bdev, b));
+
+ rdev_dec_pending(rdev, mddev);
+ rcu_read_lock();
+ }
+ }
+ rcu_read_unlock();
+
+ sectors -= s;
+ sect += s;
+ }
+}
+
static void raid10d(mddev_t *mddev)
{
r10bio_t *r10_bio;
@@ -1413,105 +1545,12 @@ static void raid10d(mddev_t *mddev)
* This is all done synchronously while the array is
* frozen.
*/
- int sect = 0; /* Offset from r10_bio->sector */
- int sectors = r10_bio->sectors;
- freeze_array(conf);
- if (mddev->ro == 0) while(sectors) {
- int s = sectors;
- int sl = r10_bio->read_slot;
- int success = 0;
-
- if (s > (PAGE_SIZE>>9))
- s = PAGE_SIZE >> 9;
-
- rcu_read_lock();
- do {
- int d = r10_bio->devs[sl].devnum;
- rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev &&
- test_bit(In_sync, &rdev->flags)) {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- success = sync_page_io(rdev->bdev,
- r10_bio->devs[sl].addr +
- sect + rdev->data_offset,
- s<<9,
- conf->tmppage, READ);
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- if (success)
- break;
- }
- sl++;
- if (sl == conf->copies)
- sl = 0;
- } while (!success && sl != r10_bio->read_slot);
- rcu_read_unlock();
-
- if (success) {
- int start = sl;
- /* write it back and re-read */
- rcu_read_lock();
- while (sl != r10_bio->read_slot) {
- int d;
- if (sl==0)
- sl = conf->copies;
- sl--;
- d = r10_bio->devs[sl].devnum;
- rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev &&
- test_bit(In_sync, &rdev->flags)) {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- atomic_add(s, &rdev->corrected_errors);
- if (sync_page_io(rdev->bdev,
- r10_bio->devs[sl].addr +
- sect + rdev->data_offset,
- s<<9, conf->tmppage, WRITE) == 0)
- /* Well, this device is dead */
- md_error(mddev, rdev);
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- sl = start;
- while (sl != r10_bio->read_slot) {
- int d;
- if (sl==0)
- sl = conf->copies;
- sl--;
- d = r10_bio->devs[sl].devnum;
- rdev = rcu_dereference(conf->mirrors[d].rdev);
- if (rdev &&
- test_bit(In_sync, &rdev->flags)) {
- atomic_inc(&rdev->nr_pending);
- rcu_read_unlock();
- if (sync_page_io(rdev->bdev,
- r10_bio->devs[sl].addr +
- sect + rdev->data_offset,
- s<<9, conf->tmppage, READ) == 0)
- /* Well, this device is dead */
- md_error(mddev, rdev);
- else
- printk(KERN_INFO "raid10:%s: read error corrected (%d sectors at %llu on %s)\n",
- mdname(mddev), s, (unsigned long long)(sect+rdev->data_offset), bdevname(rdev->bdev, b));
-
- rdev_dec_pending(rdev, mddev);
- rcu_read_lock();
- }
- }
- rcu_read_unlock();
- } else {
- /* Cannot read from anywhere -- bye bye array */
- md_error(mddev, conf->mirrors[r10_bio->devs[r10_bio->read_slot].devnum].rdev);
- break;
- }
- sectors -= s;
- sect += s;
+ if (mddev->ro == 0) {
+ freeze_array(conf);
+ fix_read_error(conf, mddev, r10_bio);
+ unfreeze_array(conf);
}
- unfreeze_array(conf);
-
bio = r10_bio->devs[r10_bio->read_slot].bio;
r10_bio->devs[r10_bio->read_slot].bio =
mddev->ro ? IO_BLOCKED : NULL;
@@ -2018,8 +2057,6 @@ static int run(mddev_t *mddev)
mddev->queue->max_sectors = (PAGE_SIZE>>9);
disk->head_position = 0;
- if (!test_bit(Faulty, &rdev->flags) && test_bit(In_sync, &rdev->flags))
- conf->working_disks++;
}
conf->raid_disks = mddev->raid_disks;
conf->mddev = mddev;
@@ -2042,7 +2079,7 @@ static int run(mddev_t *mddev)
disk = conf->mirrors + i;
if (!disk->rdev ||
- !test_bit(In_sync, &rdev->flags)) {
+ !test_bit(In_sync, &disk->rdev->flags)) {
disk->head_position = 0;
mddev->degraded++;
}
@@ -2077,6 +2114,8 @@ static int run(mddev_t *mddev)
mddev->queue->unplug_fn = raid10_unplug;
mddev->queue->issue_flush_fn = raid10_issue_flush;
+ mddev->queue->backing_dev_info.congested_fn = raid10_congested;
+ mddev->queue->backing_dev_info.congested_data = mddev;
/* Calculate max read-ahead size.
* We need to readahead at least twice a whole stripe....
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 450066007160..e14f45780720 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -636,7 +636,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
struct stripe_head *sh = bi->bi_private;
raid5_conf_t *conf = sh->raid_conf;
int disks = sh->disks, i;
- unsigned long flags;
int uptodate = test_bit(BIO_UPTODATE, &bi->bi_flags);
if (bi->bi_size)
@@ -654,7 +653,6 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
return 0;
}
- spin_lock_irqsave(&conf->device_lock, flags);
if (!uptodate)
md_error(conf->mddev, conf->disks[i].rdev);
@@ -662,8 +660,7 @@ static int raid5_end_write_request (struct bio *bi, unsigned int bytes_done,
clear_bit(R5_LOCKED, &sh->dev[i].flags);
set_bit(STRIPE_HANDLE, &sh->state);
- __release_stripe(conf, sh);
- spin_unlock_irqrestore(&conf->device_lock, flags);
+ release_stripe(sh);
return 0;
}
@@ -696,12 +693,12 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
PRINTK("raid5: error called\n");
if (!test_bit(Faulty, &rdev->flags)) {
- mddev->sb_dirty = 1;
- if (test_bit(In_sync, &rdev->flags)) {
- conf->working_disks--;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ if (test_and_clear_bit(In_sync, &rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded++;
- conf->failed_disks++;
- clear_bit(In_sync, &rdev->flags);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
/*
* if recovery was running, make sure it aborts.
*/
@@ -711,7 +708,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
printk (KERN_ALERT
"raid5: Disk failure on %s, disabling device."
" Operation continuing on %d devices\n",
- bdevname(rdev->bdev,b), conf->working_disks);
+ bdevname(rdev->bdev,b), conf->raid_disks - mddev->degraded);
}
}
@@ -1108,7 +1105,7 @@ static void compute_parity6(struct stripe_head *sh, int method)
if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
wake_up(&conf->wait_for_overlap);
- if (sh->dev[i].written) BUG();
+ BUG_ON(sh->dev[i].written);
sh->dev[i].written = chosen;
}
break;
@@ -1353,10 +1350,9 @@ static int page_is_zero(struct page *p)
static int stripe_to_pdidx(sector_t stripe, raid5_conf_t *conf, int disks)
{
int sectors_per_chunk = conf->chunk_size >> 9;
- sector_t x = stripe;
int pd_idx, dd_idx;
- int chunk_offset = sector_div(x, sectors_per_chunk);
- stripe = x;
+ int chunk_offset = sector_div(stripe, sectors_per_chunk);
+
raid5_compute_sector(stripe*(disks-1)*sectors_per_chunk
+ chunk_offset, disks, disks-1, &dd_idx, &pd_idx, conf);
return pd_idx;
@@ -2597,6 +2593,24 @@ static int raid5_issue_flush(request_queue_t *q, struct gendisk *disk,
return ret;
}
+static int raid5_congested(void *data, int bits)
+{
+ mddev_t *mddev = data;
+ raid5_conf_t *conf = mddev_to_conf(mddev);
+
+ /* No difference between reads and writes. Just check
+ * how busy the stripe_cache is
+ */
+ if (conf->inactive_blocked)
+ return 1;
+ if (conf->quiesce)
+ return 1;
+ if (list_empty_careful(&conf->inactive_list))
+ return 1;
+
+ return 0;
+}
+
static int make_request(request_queue_t *q, struct bio * bi)
{
mddev_t *mddev = q->queuedata;
@@ -2781,9 +2795,9 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped
wait_event(conf->wait_for_overlap,
atomic_read(&conf->reshape_stripes)==0);
mddev->reshape_position = conf->expand_progress;
- mddev->sb_dirty = 1;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
md_wakeup_thread(mddev->thread);
- wait_event(mddev->sb_wait, mddev->sb_dirty == 0 ||
+ wait_event(mddev->sb_wait, mddev->flags == 0 ||
kthread_should_stop());
spin_lock_irq(&conf->device_lock);
conf->expand_lo = mddev->reshape_position;
@@ -3074,6 +3088,7 @@ static int run(mddev_t *mddev)
mdk_rdev_t *rdev;
struct disk_info *disk;
struct list_head *tmp;
+ int working_disks = 0;
if (mddev->level != 5 && mddev->level != 4 && mddev->level != 6) {
printk(KERN_ERR "raid5: %s: raid level not set to 4/5/6 (%d)\n",
@@ -3176,14 +3191,14 @@ static int run(mddev_t *mddev)
printk(KERN_INFO "raid5: device %s operational as raid"
" disk %d\n", bdevname(rdev->bdev,b),
raid_disk);
- conf->working_disks++;
+ working_disks++;
}
}
/*
* 0 for a fully functional array, 1 or 2 for a degraded array.
*/
- mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks;
+ mddev->degraded = conf->raid_disks - working_disks;
conf->mddev = mddev;
conf->chunk_size = mddev->chunk_size;
conf->level = mddev->level;
@@ -3218,7 +3233,7 @@ static int run(mddev_t *mddev)
if (mddev->degraded > conf->max_degraded) {
printk(KERN_ERR "raid5: not enough operational devices for %s"
" (%d/%d failed)\n",
- mdname(mddev), conf->failed_disks, conf->raid_disks);
+ mdname(mddev), mddev->degraded, conf->raid_disks);
goto abort;
}
@@ -3299,6 +3314,9 @@ static int run(mddev_t *mddev)
mddev->queue->unplug_fn = raid5_unplug_device;
mddev->queue->issue_flush_fn = raid5_issue_flush;
+ mddev->queue->backing_dev_info.congested_fn = raid5_congested;
+ mddev->queue->backing_dev_info.congested_data = mddev;
+
mddev->array_size = mddev->size * (conf->previous_raid_disks -
conf->max_degraded);
@@ -3375,7 +3393,7 @@ static void status (struct seq_file *seq, mddev_t *mddev)
int i;
seq_printf (seq, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout);
- seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->working_disks);
+ seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded);
for (i = 0; i < conf->raid_disks; i++)
seq_printf (seq, "%s",
conf->disks[i].rdev &&
@@ -3397,8 +3415,8 @@ static void print_raid5_conf (raid5_conf_t *conf)
printk("(conf==NULL)\n");
return;
}
- printk(" --- rd:%d wd:%d fd:%d\n", conf->raid_disks,
- conf->working_disks, conf->failed_disks);
+ printk(" --- rd:%d wd:%d\n", conf->raid_disks,
+ conf->raid_disks - conf->mddev->degraded);
for (i = 0; i < conf->raid_disks; i++) {
char b[BDEVNAME_SIZE];
@@ -3420,11 +3438,11 @@ static int raid5_spare_active(mddev_t *mddev)
tmp = conf->disks + i;
if (tmp->rdev
&& !test_bit(Faulty, &tmp->rdev->flags)
- && !test_bit(In_sync, &tmp->rdev->flags)) {
+ && !test_and_set_bit(In_sync, &tmp->rdev->flags)) {
+ unsigned long flags;
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded--;
- conf->failed_disks--;
- conf->working_disks++;
- set_bit(In_sync, &tmp->rdev->flags);
+ spin_unlock_irqrestore(&conf->device_lock, flags);
}
}
print_raid5_conf(conf);
@@ -3560,6 +3578,7 @@ static int raid5_start_reshape(mddev_t *mddev)
struct list_head *rtmp;
int spares = 0;
int added_devices = 0;
+ unsigned long flags;
if (mddev->degraded ||
test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
@@ -3593,7 +3612,6 @@ static int raid5_start_reshape(mddev_t *mddev)
if (raid5_add_disk(mddev, rdev)) {
char nm[20];
set_bit(In_sync, &rdev->flags);
- conf->working_disks++;
added_devices++;
rdev->recovery_offset = 0;
sprintf(nm, "rd%d", rdev->raid_disk);
@@ -3602,10 +3620,12 @@ static int raid5_start_reshape(mddev_t *mddev)
break;
}
+ spin_lock_irqsave(&conf->device_lock, flags);
mddev->degraded = (conf->raid_disks - conf->previous_raid_disks) - added_devices;
+ spin_unlock_irqrestore(&conf->device_lock, flags);
mddev->raid_disks = conf->raid_disks;
mddev->reshape_position = 0;
- mddev->sb_dirty = 1;
+ set_bit(MD_CHANGE_DEVS, &mddev->flags);
clear_bit(MD_RECOVERY_SYNC, &mddev->recovery);
clear_bit(MD_RECOVERY_CHECK, &mddev->recovery);
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index ed4aa4e7912c..9f7e1fe8c97e 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -54,6 +54,7 @@ config VIDEO_V4L1_COMPAT
config VIDEO_V4L2
bool
+ depends on VIDEO_DEV
default y
source "drivers/media/video/Kconfig"
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index 1a04db4552da..f33e5d973413 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -4,7 +4,6 @@ config VIDEO_SAA7146
config VIDEO_SAA7146_VV
tristate
- select VIDEO_V4L2
select VIDEO_BUF
select VIDEO_VIDEOBUF
select VIDEO_SAA7146
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index ca98d9478947..db753443587a 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -32,6 +32,37 @@ IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE] = {
EXPORT_SYMBOL_GPL(ir_codes_empty);
+/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
+IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE] = {
+ /* numeric */
+ [ 0x00 ] = KEY_0,
+ [ 0x01 ] = KEY_1,
+ [ 0x02 ] = KEY_2,
+ [ 0x03 ] = KEY_3,
+ [ 0x04 ] = KEY_4,
+ [ 0x05 ] = KEY_5,
+ [ 0x06 ] = KEY_6,
+ [ 0x07 ] = KEY_7,
+ [ 0x08 ] = KEY_8,
+ [ 0x09 ] = KEY_9,
+
+ [ 0x5c ] = KEY_POWER, /* power */
+ [ 0x20 ] = KEY_F, /* full screen */
+ [ 0x0f ] = KEY_BACKSPACE, /* recall */
+ [ 0x1b ] = KEY_ENTER, /* mute */
+ [ 0x41 ] = KEY_RECORD, /* record */
+ [ 0x43 ] = KEY_STOP, /* stop */
+ [ 0x16 ] = KEY_S,
+ [ 0x1a ] = KEY_Q, /* off */
+ [ 0x2e ] = KEY_RED,
+ [ 0x1f ] = KEY_DOWN, /* channel - */
+ [ 0x1c ] = KEY_UP, /* channel + */
+ [ 0x10 ] = KEY_LEFT, /* volume - */
+ [ 0x1e ] = KEY_RIGHT, /* volume + */
+ [ 0x14 ] = KEY_F1,
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_proteus_2309);
/* Matt Jesson <dvb@jesson.eclipse.co.uk */
IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
[ 0x28 ] = KEY_0, //'0' / 'enter'
@@ -1473,3 +1504,51 @@ IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE] = {
};
EXPORT_SYMBOL_GPL(ir_codes_npgtech);
+
+/* Norwood Micro (non-Pro) TV Tuner
+ By Peter Naulls <peter@chocky.org>
+ Key comments are the functions given in the manual */
+IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 0x20 ] = KEY_0,
+ [ 0x21 ] = KEY_1,
+ [ 0x22 ] = KEY_2,
+ [ 0x23 ] = KEY_3,
+ [ 0x24 ] = KEY_4,
+ [ 0x25 ] = KEY_5,
+ [ 0x26 ] = KEY_6,
+ [ 0x27 ] = KEY_7,
+ [ 0x28 ] = KEY_8,
+ [ 0x29 ] = KEY_9,
+
+ [ 0x78 ] = KEY_TUNER, /* Video Source */
+ [ 0x2c ] = KEY_EXIT, /* Open/Close software */
+ [ 0x2a ] = KEY_SELECT, /* 2 Digit Select */
+ [ 0x69 ] = KEY_AGAIN, /* Recall */
+
+ [ 0x32 ] = KEY_BRIGHTNESSUP, /* Brightness increase */
+ [ 0x33 ] = KEY_BRIGHTNESSDOWN, /* Brightness decrease */
+ [ 0x6b ] = KEY_KPPLUS, /* (not named >>>>>) */
+ [ 0x6c ] = KEY_KPMINUS, /* (not named <<<<<) */
+
+ [ 0x2d ] = KEY_MUTE, /* Mute */
+ [ 0x30 ] = KEY_VOLUMEUP, /* Volume up */
+ [ 0x31 ] = KEY_VOLUMEDOWN, /* Volume down */
+ [ 0x60 ] = KEY_CHANNELUP, /* Channel up */
+ [ 0x61 ] = KEY_CHANNELDOWN, /* Channel down */
+
+ [ 0x3f ] = KEY_RECORD, /* Record */
+ [ 0x37 ] = KEY_PLAY, /* Play */
+ [ 0x36 ] = KEY_PAUSE, /* Pause */
+ [ 0x2b ] = KEY_STOP, /* Stop */
+ [ 0x67 ] = KEY_FASTFORWARD, /* Foward */
+ [ 0x66 ] = KEY_REWIND, /* Rewind */
+ [ 0x3e ] = KEY_SEARCH, /* Auto Scan */
+ [ 0x2e ] = KEY_CAMERA, /* Capture Video */
+ [ 0x6d ] = KEY_MENU, /* Show/Hide Control */
+ [ 0x2f ] = KEY_ZOOM, /* Full Screen */
+ [ 0x34 ] = KEY_RADIO, /* FM */
+ [ 0x65 ] = KEY_POWER, /* Computer power */
+};
+
+EXPORT_SYMBOL_GPL(ir_codes_norwood);
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index b88451e33c09..86cbdbcf9d7d 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -230,7 +230,7 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt
/********************************************************************************/
/* interrupt handler */
-static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t interrupt_hw(int irq, void *dev_id)
{
struct saa7146_dev *dev = dev_id;
u32 isr = 0;
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 0027acc5b8e9..d867a6a9e430 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -455,7 +455,6 @@ static void vv_callback(struct saa7146_dev *dev, unsigned long status)
static struct video_device device_template =
{
- .hardware = VID_HARDWARE_SAA7146,
.fops = &video_fops,
.minor = -1,
};
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 49a06fc54c51..a0dcd59da76e 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -2,13 +2,13 @@ config DVB_B2C2_FLEXCOP
tristate "Technisat/B2C2 FlexCopII(b) and FlexCopIII adapters"
depends on DVB_CORE && I2C
select DVB_PLL
- select DVB_STV0299
- select DVB_MT352
- select DVB_MT312
- select DVB_NXT200X
- select DVB_STV0297
- select DVB_BCM3510
- select DVB_LGDT330X
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_MT312 if !DVB_FE_CUSTOMISE
+ select DVB_NXT200X if !DVB_FE_CUSTOMISE
+ select DVB_STV0297 if !DVB_FE_CUSTOMISE
+ select DVB_BCM3510 if !DVB_FE_CUSTOMISE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
help
Support for the digital TV receiver chip made by B2C2 Inc. included in
Technisats PCI cards and USB boxes.
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 3be87c72e37b..b8ba87863457 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -505,7 +505,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
struct dvb_frontend_ops *ops;
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
- if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
+ if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
ops = &fc->fe->ops;
ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
@@ -519,36 +519,36 @@ int flexcop_frontend_init(struct flexcop_device *fc)
info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
} else
/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
- if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
+ if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
fc->dev_type = FC_AIR_DVB;
fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
} else
/* try the air atsc 2nd generation (nxt2002) */
- if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
+ if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC2;
- dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv);
+ dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
/* try the air atsc 3nd generation (lgdt3303) */
- if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
+ if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC3;
fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
} else
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
- if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
+ if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_AIR_ATSC1;
info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
} else
/* try the cable dvb (stv0297) */
- if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
+ if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
fc->dev_type = FC_CABLE;
fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
} else
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
- if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
+ if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
ops = &fc->fe->ops;
ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
@@ -571,9 +571,7 @@ int flexcop_frontend_init(struct flexcop_device *fc)
} else {
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!");
- ops = &fc->fe->ops;
- if (ops->release != NULL)
- ops->release(fc->fe);
+ dvb_frontend_detach(fc->fe);
fc->fe = NULL;
return -EINVAL;
}
@@ -584,8 +582,10 @@ int flexcop_frontend_init(struct flexcop_device *fc)
void flexcop_frontend_exit(struct flexcop_device *fc)
{
- if (fc->init_state & FC_STATE_FE_INIT)
+ if (fc->init_state & FC_STATE_FE_INIT) {
dvb_unregister_frontend(fc->fe);
+ dvb_frontend_detach(fc->fe);
+ }
fc->init_state &= ~FC_STATE_FE_INIT;
}
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index eb2e6432c8c2..06893243f3d4 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -122,7 +122,7 @@ static void flexcop_pci_irq_check_work(void *data)
/* When PID filtering is turned on, we use the timer IRQ, because small amounts
* of data need to be passed to the user space instantly as well. When PID
* filtering is turned off, we use the page-change-IRQ */
-static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t flexcop_pci_isr(int irq, void *dev_id)
{
struct flexcop_pci *fc_pci = dev_id;
struct flexcop_device *fc = fc_pci->fc_dev;
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 515954f96c9a..2853ea1bdaf1 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -328,7 +328,7 @@ static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, in
fc_usb->tmp_buffer_length = l;
}
-static void flexcop_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+static void flexcop_usb_urb_complete(struct urb *urb)
{
struct flexcop_usb *fc_usb = urb->context;
int i;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index 7d0ee1ab2903..ae2ff5dc238d 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -2,13 +2,13 @@ config DVB_BT8XX
tristate "BT8xx based PCI cards"
depends on DVB_CORE && PCI && I2C && VIDEO_BT848
select DVB_PLL
- select DVB_MT352
- select DVB_SP887X
- select DVB_NXT6000
- select DVB_CX24110
- select DVB_OR51211
- select DVB_LGDT330X
- select DVB_ZL10353
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_SP887X if !DVB_FE_CUSTOMISE
+ select DVB_NXT6000 if !DVB_FE_CUSTOMISE
+ select DVB_CX24110 if !DVB_FE_CUSTOMISE
+ select DVB_OR51211 if !DVB_FE_CUSTOMISE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select FW_LOADER
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c
index 755822ee6e9b..329a51c18562 100644
--- a/drivers/media/dvb/bt8xx/bt878.c
+++ b/drivers/media/dvb/bt8xx/bt878.c
@@ -266,7 +266,7 @@ EXPORT_SYMBOL(bt878_stop);
/* Interrupt service routine */
/*****************************/
-static irqreturn_t bt878_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bt878_irq(int irq, void *dev_id)
{
u32 stat, astat, mask;
int count;
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 06ac899a9a26..9f72b7000c08 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1715,6 +1715,15 @@ static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_paramet
static void dst_release(struct dvb_frontend *fe)
{
struct dst_state *state = fe->demodulator_priv;
+ if (state->dst_ca) {
+ dvb_unregister_device(state->dst_ca);
+#ifdef CONFIG_DVB_CORE_ATTACH
+ symbol_put(dst_ca_attach);
+#endif
+ }
+#ifdef CONFIG_DVB_CORE_ATTACH
+ symbol_put(dst_attach);
+#endif
kfree(state);
}
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index fa923b9b346e..240ad084fa78 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -699,12 +699,17 @@ static struct dvb_device dvbdev_ca = {
.fops = &dst_ca_fops
};
-int dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
+struct dvb_device *dst_ca_attach(struct dst_state *dst, struct dvb_adapter *dvb_adapter)
{
struct dvb_device *dvbdev;
+
dprintk(verbose, DST_CA_ERROR, 1, "registering DST-CA device");
- dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA);
- return 0;
+ if (dvb_register_device(dvb_adapter, &dvbdev, &dvbdev_ca, dst, DVB_DEVICE_CA) == 0) {
+ dst->dst_ca = dvbdev;
+ return dst->dst_ca;
+ }
+
+ return NULL;
}
EXPORT_SYMBOL(dst_ca_attach);
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 0677b047b3a7..3bf084f2e522 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -140,6 +140,7 @@ struct dst_state {
char *tuner_name;
struct mutex dst_mutex;
u8 fw_name[8];
+ struct dvb_device *dst_ca;
};
struct tuner_types {
@@ -178,7 +179,7 @@ int write_dst(struct dst_state *state, u8 * data, u8 len);
int read_dst(struct dst_state *state, u8 * ret, u8 len);
u8 dst_check_sum(u8 * buf, u32 len);
struct dst_state* dst_attach(struct dst_state* state, struct dvb_adapter *dvb_adapter);
-int dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
+struct dvb_device *dst_ca_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter);
int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh, int delay);
int dst_command(struct dst_state* state, u8 * data, u8 len);
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index b715b972d2fc..14e69a736eda 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -67,7 +67,7 @@ static void dvb_bt8xx_task(unsigned long data)
static int dvb_bt8xx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct dvb_demux*dvbdmx = dvbdmxfeed->demux;
struct dvb_bt8xx_card *card = dvbdmx->priv;
int rc;
@@ -595,15 +595,14 @@ static void lgdt330x_reset(struct dvb_bt8xx_card *bt)
static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
{
- int ret;
struct dst_state* state = NULL;
switch(type) {
case BTTV_BOARD_DVICO_DVBT_LITE:
- card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter);
+ card->fe = dvb_attach(mt352_attach, &thomson_dtt7579_config, card->i2c_adapter);
if (card->fe == NULL)
- card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config,
+ card->fe = dvb_attach(zl10353_attach, &thomson_dtt7579_zl10353_config,
card->i2c_adapter);
if (card->fe != NULL) {
@@ -615,7 +614,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE:
lgdt330x_reset(card);
- card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter);
+ card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params;
dprintk ("dvb_bt8xx: lgdt330x detected\n");
@@ -630,7 +629,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
/* Old Nebula (marked (c)2003 on high profile pci card) has nxt6000 demod */
digitv_alps_tded4_reset(card);
- card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter);
+ card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params;
dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n");
@@ -639,7 +638,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
/* New Nebula (marked (c)2005 on low profile pci card) has mt352 demod */
digitv_alps_tded4_reset(card);
- card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter);
+ card->fe = dvb_attach(mt352_attach, &digitv_alps_tded4_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs;
@@ -648,14 +647,14 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
break;
case BTTV_BOARD_AVDVBT_761:
- card->fe = sp887x_attach(&microtune_mt7202dtf_config, card->i2c_adapter);
+ card->fe = dvb_attach(sp887x_attach, &microtune_mt7202dtf_config, card->i2c_adapter);
if (card->fe) {
card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params;
}
break;
case BTTV_BOARD_AVDVBT_771:
- card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
+ card->fe = dvb_attach(mt352_attach, &advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter);
if (card->fe != NULL) {
card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs;
card->fe->ops.info.frequency_min = 174000000;
@@ -666,26 +665,29 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
case BTTV_BOARD_TWINHAN_DST:
/* DST is not a frontend driver !!! */
state = (struct dst_state *) kmalloc(sizeof (struct dst_state), GFP_KERNEL);
+ if (!state) {
+ printk("dvb_bt8xx: No memory\n");
+ break;
+ }
/* Setup the Card */
state->config = &dst_config;
state->i2c = card->i2c_adapter;
state->bt = card->bt;
-
+ state->dst_ca = NULL;
/* DST is not a frontend, attaching the ASIC */
- if ((dst_attach(state, &card->dvb_adapter)) == NULL) {
+ if (dvb_attach(dst_attach, state, &card->dvb_adapter) == NULL) {
printk("%s: Could not find a Twinhan DST.\n", __FUNCTION__);
break;
}
- card->fe = &state->frontend;
-
/* Attach other DST peripherals if any */
/* Conditional Access device */
+ card->fe = &state->frontend;
if (state->dst_hw_cap & DST_TYPE_HAS_CA)
- ret = dst_ca_attach(state, &card->dvb_adapter);
+ dvb_attach(dst_ca_attach, state, &card->dvb_adapter);
break;
case BTTV_BOARD_PINNACLESAT:
- card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter);
+ card->fe = dvb_attach(cx24110_attach, &pctvsat_config, card->i2c_adapter);
if (card->fe) {
card->fe->ops.tuner_ops.init = pinnsat_tuner_init;
card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep;
@@ -694,7 +696,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
break;
case BTTV_BOARD_PC_HDTV:
- card->fe = or51211_attach(&or51211_config, card->i2c_adapter);
+ card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
break;
}
@@ -707,8 +709,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
else
if (dvb_register_frontend(&card->dvb_adapter, card->fe)) {
printk("dvb-bt8xx: Frontend registration failed!\n");
- if (card->fe->ops.release)
- card->fe->ops.release(card->fe);
+ dvb_frontend_detach(card->fe);
card->fe = NULL;
}
}
@@ -925,8 +926,10 @@ static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
dvb_dmxdev_release(&card->dmxdev);
dvb_dmx_release(&card->demux);
- if (card->fe)
+ if (card->fe) {
dvb_unregister_frontend(card->fe);
+ dvb_frontend_detach(card->fe);
+ }
dvb_unregister_adapter(&card->dvb_adapter);
kfree(card);
diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig
index b5cdd57ec6f5..3d778c5aba68 100644
--- a/drivers/media/dvb/cinergyT2/Kconfig
+++ b/drivers/media/dvb/cinergyT2/Kconfig
@@ -56,7 +56,7 @@ config DVB_CINERGYT2_QUERY_INTERVAL
measurements.
Please keep in mind that these updates cause traffic on the tuner
- control bus and thus may or may not affect receiption sensitivity.
+ control bus and thus may or may not affect reception sensitivity.
The default value should be a safe choice for common applications.
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 410fa6d620ff..ff7d4f56ced3 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -238,7 +238,7 @@ static void cinergyt2_sleep (struct cinergyt2 *cinergyt2, int sleep)
cinergyt2->sleeping = sleep;
}
-static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs);
+static void cinergyt2_stream_irq (struct urb *urb);
static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb *urb)
{
@@ -258,7 +258,7 @@ static int cinergyt2_submit_stream_urb (struct cinergyt2 *cinergyt2, struct urb
return err;
}
-static void cinergyt2_stream_irq (struct urb *urb, struct pt_regs *regs)
+static void cinergyt2_stream_irq (struct urb *urb)
{
struct cinergyt2 *cinergyt2 = urb->context;
diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig
index 12ee912a5705..1990eda10c46 100644
--- a/drivers/media/dvb/dvb-core/Kconfig
+++ b/drivers/media/dvb/dvb-core/Kconfig
@@ -9,3 +9,16 @@ config DVB_CORE
in-kernel drivers will select this automatically if needed.
If unsure say N.
+config DVB_CORE_ATTACH
+ bool "Load and attach frontend modules as needed"
+ depends on DVB_CORE
+ depends on MODULES
+ help
+ Remove the static dependency of DVB card drivers on all
+ frontend modules for all possible card variants. Instead,
+ allow the card drivers to only load the frontend modules
+ they require. This saves several KBytes of memory.
+
+ Note: You will need module-init-tools v3.2 or later for this feature.
+
+ If unsure say Y.
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 57b34cda99f5..53304e6991ac 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1014,6 +1014,13 @@ static int dvb_frontend_open(struct inode *inode, struct file *file)
if ((ret = dvb_generic_open (inode, file)) < 0)
return ret;
+ if (fe->ops.ts_bus_ctrl) {
+ if ((ret = fe->ops.ts_bus_ctrl (fe, 1)) < 0) {
+ dvb_generic_release (inode, file);
+ return ret;
+ }
+ }
+
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
/* normal tune mode when opened R/W */
@@ -1043,6 +1050,9 @@ static int dvb_frontend_release(struct inode *inode, struct file *file)
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
fepriv->release_jiffies = jiffies;
+ if (fe->ops.ts_bus_ctrl)
+ fe->ops.ts_bus_ctrl (fe, 0);
+
return dvb_generic_release (inode, file);
}
@@ -1105,18 +1115,42 @@ int dvb_unregister_frontend(struct dvb_frontend* fe)
mutex_lock(&frontend_mutex);
dvb_unregister_device (fepriv->dvbdev);
dvb_frontend_stop (fe);
- if (fe->ops.tuner_ops.release) {
- fe->ops.tuner_ops.release(fe);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
- }
- if (fe->ops.release)
- fe->ops.release(fe);
- else
- printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name);
+
/* fe is invalid now */
kfree(fepriv);
mutex_unlock(&frontend_mutex);
return 0;
}
EXPORT_SYMBOL(dvb_unregister_frontend);
+
+#ifdef CONFIG_DVB_CORE_ATTACH
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+ void *ptr;
+
+ if (fe->ops.release_sec) {
+ fe->ops.release_sec(fe);
+ symbol_put_addr(fe->ops.release_sec);
+ }
+ if (fe->ops.tuner_ops.release) {
+ fe->ops.tuner_ops.release(fe);
+ symbol_put_addr(fe->ops.tuner_ops.release);
+ }
+ ptr = (void*)fe->ops.release;
+ if (ptr) {
+ fe->ops.release(fe);
+ symbol_put_addr(ptr);
+ }
+}
+#else
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+ if (fe->ops.release_sec)
+ fe->ops.release_sec(fe);
+ if (fe->ops.tuner_ops.release)
+ fe->ops.tuner_ops.release(fe);
+ if (fe->ops.release)
+ fe->ops.release(fe);
+}
+#endif
+EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index 2887e2b862a4..f233d78bc364 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -92,10 +92,13 @@ struct dvb_frontend_ops {
struct dvb_frontend_info info;
void (*release)(struct dvb_frontend* fe);
+ void (*release_sec)(struct dvb_frontend* fe);
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
+ int (*write)(struct dvb_frontend* fe, u8* buf, int len);
+
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params,
@@ -126,6 +129,7 @@ struct dvb_frontend_ops {
int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+ int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
struct dvb_tuner_ops tuner_ops;
};
@@ -147,7 +151,7 @@ struct dvb_frontend {
void* demodulator_priv;
void* tuner_priv;
void* frontend_priv;
- void* misc_priv;
+ void* sec_priv;
};
extern int dvb_register_frontend(struct dvb_adapter* dvb,
@@ -155,6 +159,8 @@ extern int dvb_register_frontend(struct dvb_adapter* dvb,
extern int dvb_unregister_frontend(struct dvb_frontend* fe);
+extern void dvb_frontend_detach(struct dvb_frontend* fe);
+
extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
index c972fe014c58..9878183ba3f0 100644
--- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
+++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
@@ -26,7 +26,6 @@
-#define __KERNEL_SYSCALLS__
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
index 7a7f75fd168c..620e7887b3d3 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.h
+++ b/drivers/media/dvb/dvb-core/dvbdev.h
@@ -102,4 +102,26 @@ extern int dvb_usercopy(struct inode *inode, struct file *file,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg));
+/** generic DVB attach function. */
+#ifdef CONFIG_DVB_CORE_ATTACH
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+ void *__r = NULL; \
+ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+ if (__a) { \
+ __r = (void *) __a(ARGS); \
+ if (__r == NULL) \
+ symbol_put(FUNCTION); \
+ } else { \
+ printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
+ } \
+ __r; \
+})
+
+#else
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+ FUNCTION(ARGS); \
+})
+
+#endif
+
#endif /* #ifndef _DVBDEV_H_ */
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index 75824b77198a..2cc5caa26a0a 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -26,6 +26,7 @@ config DVB_USB_A800
tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
depends on DVB_USB
select DVB_DIB3000MC
+ select DVB_TUNER_MT2060
help
Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
@@ -33,24 +34,13 @@ config DVB_USB_DIBUSB_MB
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
depends on DVB_USB
select DVB_DIB3000MB
+ select DVB_TUNER_MT2060
help
Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
- Devices supported by this driver:
- Artec T1 USB1.1 boxes
- Avermedia AverTV DVBT USB1.1
- Compro Videomate DVB-U2000 - DVB-T USB
- DiBcom USB1.1 reference devices (non-public)
- Grandtec DVB-T USB
- Hama DVB-T USB1.1-Box
- KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
- TwinhanDTV Magic Box (VP7041e)
- TwinhanDTV USB-Ter (VP7041)
- Ultima Electronic/Artec T1 USB TVBOX
-
- The VP7041 seems to be identical to "CTS Portable" (Chinese
- Television System).
+ For an up-to-date list of devices supported by this driver, have a look
+ on the Linux-DVB Wiki at www.linuxtv.org.
Say Y if you own such a device and want to use it. You should build it as
a module.
@@ -65,13 +55,30 @@ config DVB_USB_DIBUSB_MC
tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
depends on DVB_USB
select DVB_DIB3000MC
+ select DVB_TUNER_MT2060
help
- Support for 2.0 DVB-T receivers based on reference designs made by
+ Support for USB2.0 DVB-T receivers based on reference designs made by
DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
- Devices supported by this driver:
- Artec T1 USB2.0 boxes
- DiBcom USB2.0 reference devices (non-public)
+ For an up-to-date list of devices supported by this driver, have a look
+ on the Linux-DVB Wiki at www.linuxtv.org.
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+
+config DVB_USB_DIB0700
+ tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ select DVB_TUNER_MT2060
+ help
+ Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The
+ USB bridge is also present in devices having the DiB7700 DVB-T-USB
+ silicon. This chip can be found in devices offered by Hauppauge,
+ Avermedia and other big and small companies.
+
+ For an up-to-date list of devices supported by this driver, have a look
+ on the Linux-DVB Wiki at www.linuxtv.org.
Say Y if you own such a device and want to use it. You should build it as
a module.
@@ -80,16 +87,17 @@ config DVB_USB_UMT_010
tristate "HanfTek UMT-010 DVB-T USB2.0 support"
depends on DVB_USB
select DVB_DIB3000MC
+ select DVB_TUNER_MT2060
help
Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
config DVB_USB_CXUSB
tristate "Conexant USB2.0 hybrid reference design support"
depends on DVB_USB
- select DVB_CX22702
- select DVB_LGDT330X
- select DVB_MT352
- select DVB_ZL10353
+ select DVB_CX22702 if !DVB_FE_CUSTOMISE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
@@ -101,8 +109,8 @@ config DVB_USB_CXUSB
config DVB_USB_DIGITV
tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
depends on DVB_USB
- select DVB_NXT6000
- select DVB_MT352
+ select DVB_NXT6000 if !DVB_FE_CUSTOMISE
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
help
Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
@@ -145,6 +153,7 @@ config DVB_USB_NOVA_T_USB2
tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
depends on DVB_USB
select DVB_DIB3000MC
+ select DVB_TUNER_MT2060
help
Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 9643f56c7fe9..e239107998e5 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -1,4 +1,4 @@
-dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o
+dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o
obj-$(CONFIG_DVB_USB) += dvb-usb.o
dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
@@ -36,4 +36,7 @@ obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
dvb-usb-cxusb-objs = cxusb.o
obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
+dvb-usb-dib0700-objs = dib0700_core.o dib0700_devices.o
+obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o
+
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index ce44aa6bbb83..2ed3eb62d787 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -26,6 +26,14 @@ static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
return 0;
}
+/* assure to put cold to 0 for iManufacturer == 1 */
+static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc, int *cold)
+{
+ *cold = udev->descriptor.iManufacturer != 1;
+ return 0;
+}
+
static struct dvb_usb_rc_key a800_rc_keys[] = {
{ 0x02, 0x01, KEY_PROG1 }, /* SOURCE */
{ 0x02, 0x00, KEY_POWER }, /* POWER */
@@ -81,7 +89,7 @@ static int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
}
/* USB Driver stuff */
-static struct dvb_usb_properties a800_properties;
+static struct dvb_usb_device_properties a800_properties;
static int a800_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -97,34 +105,27 @@ static struct usb_device_id a800_table [] = {
};
MODULE_DEVICE_TABLE (usb, a800_table);
-static struct dvb_usb_properties a800_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 32,
+static struct dvb_usb_device_properties a800_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
-
.firmware = "dvb-usb-avertv-a800-02.fw",
- .size_of_priv = sizeof(struct dibusb_state),
-
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
- .power_ctrl = a800_power_ctrl,
+
.frontend_attach = dibusb_dib3000mc_frontend_attach,
.tuner_attach = dibusb_dib3000mc_tuner_attach,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = a800_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(a800_rc_keys),
- .rc_query = a800_rc_query,
-
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
@@ -134,6 +135,21 @@ static struct dvb_usb_properties a800_properties = {
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ },
+ },
+
+ .power_ctrl = a800_power_ctrl,
+ .identify_state = a800_identify_state,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = a800_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(a800_rc_keys),
+ .rc_query = a800_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
{ "AVerMedia AverTV DVB-T USB 2.0 (A800)",
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index ae23bdde42a8..43f39069ef34 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -161,13 +161,13 @@ static int cxusb_bluebird_power_ctrl(struct dvb_usb_device *d, int onoff)
return 0;
}
-static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
u8 buf[2] = { 0x03, 0x00 };
if (onoff)
- cxusb_ctrl_msg(d,CMD_STREAMING_ON, buf, 2, NULL, 0);
+ cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, buf, 2, NULL, 0);
else
- cxusb_ctrl_msg(d,CMD_STREAMING_OFF, NULL, 0, NULL, 0);
+ cxusb_ctrl_msg(adap->dev, CMD_STREAMING_OFF, NULL, 0, NULL, 0);
return 0;
}
@@ -327,8 +327,8 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe)
static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *fep)
{
- struct dvb_usb_device *d = fe->dvb->priv;
- return lg_h06xf_pll_set(fe, &d->i2c_adap, fep);
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ return lg_h06xf_pll_set(fe, &adap->dev->i2c_adap, fep);
}
static struct cx22702_config cxusb_cx22702_config = {
@@ -349,6 +349,7 @@ static struct mt352_config cxusb_dee1601_config = {
static struct zl10353_config cxusb_zl10353_dee1601_config = {
.demod_address = 0x0f,
+ .parallel_ts = 1,
};
static struct mt352_config cxusb_mt352_config = {
@@ -358,98 +359,99 @@ static struct mt352_config cxusb_mt352_config = {
};
/* Callbacks for DVB USB */
-static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
- d->pll_addr = 0x61;
- memcpy(d->pll_init, bpll, 4);
- d->pll_desc = &dvb_pll_fmd1216me;
+ adap->pll_addr = 0x61;
+ memcpy(adap->pll_init, bpll, 4);
+ adap->pll_desc = &dvb_pll_fmd1216me;
- d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+ adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
return 0;
}
-static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_dee1601_tuner_attach(struct dvb_usb_adapter *adap)
{
- d->pll_addr = 0x61;
- d->pll_desc = &dvb_pll_thomson_dtt7579;
- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ adap->pll_addr = 0x61;
+ adap->pll_desc = &dvb_pll_thomson_dtt7579;
+ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
-static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_lgz201_tuner_attach(struct dvb_usb_adapter *adap)
{
- d->pll_addr = 0x61;
- d->pll_desc = &dvb_pll_lg_z201;
- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ adap->pll_addr = 0x61;
+ adap->pll_desc = &dvb_pll_lg_z201;
+ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
-static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
{
- d->pll_addr = 0x60;
- d->pll_desc = &dvb_pll_thomson_dtt7579;
- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ adap->pll_addr = 0x60;
+ adap->pll_desc = &dvb_pll_thomson_dtt7579;
+ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
-static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d)
+static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_adapter *adap)
{
- d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
+ adap->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params;
return 0;
}
-static int cxusb_cx22702_frontend_attach(struct dvb_usb_device *d)
+static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap)
{
u8 b;
- if (usb_set_interface(d->udev,0,6) < 0)
+ if (usb_set_interface(adap->dev->udev, 0, 6) < 0)
err("set interface failed");
- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, &b, 1);
+ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, &b, 1);
- if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
+ if ((adap->fe = dvb_attach(cx22702_attach, &cxusb_cx22702_config, &adap->dev->i2c_adap)) != NULL)
return 0;
return -EIO;
}
-static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_device *d)
+static int cxusb_lgdt3303_frontend_attach(struct dvb_usb_adapter *adap)
{
- if (usb_set_interface(d->udev,0,7) < 0)
+ if (usb_set_interface(adap->dev->udev, 0, 7) < 0)
err("set interface failed");
- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
- if ((d->fe = lgdt330x_attach(&cxusb_lgdt3303_config, &d->i2c_adap)) != NULL)
+ if ((adap->fe = dvb_attach(lgdt330x_attach, &cxusb_lgdt3303_config, &adap->dev->i2c_adap)) != NULL)
return 0;
return -EIO;
}
-static int cxusb_mt352_frontend_attach(struct dvb_usb_device *d)
-{ /* used in both lgz201 and th7579 */
- if (usb_set_interface(d->udev,0,0) < 0)
+static int cxusb_mt352_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ /* used in both lgz201 and th7579 */
+ if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
err("set interface failed");
- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
- if ((d->fe = mt352_attach(&cxusb_mt352_config, &d->i2c_adap)) != NULL)
+ if ((adap->fe = dvb_attach(mt352_attach, &cxusb_mt352_config, &adap->dev->i2c_adap)) != NULL)
return 0;
return -EIO;
}
-static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d)
+static int cxusb_dee1601_frontend_attach(struct dvb_usb_adapter *adap)
{
- if (usb_set_interface(d->udev,0,0) < 0)
+ if (usb_set_interface(adap->dev->udev, 0, 0) < 0)
err("set interface failed");
- cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0);
+ cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0);
- if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) ||
- ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL))
+ if (((adap->fe = dvb_attach(mt352_attach, &cxusb_dee1601_config, &adap->dev->i2c_adap)) != NULL) ||
+ ((adap->fe = dvb_attach(zl10353_attach, &cxusb_zl10353_dee1601_config, &adap->dev->i2c_adap)) != NULL))
return 0;
return -EIO;
@@ -479,11 +481,11 @@ static int bluebird_patch_dvico_firmware_download(struct usb_device *udev, const
}
/* DVB USB Driver stuff */
-static struct dvb_usb_properties cxusb_medion_properties;
-static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties;
-static struct dvb_usb_properties cxusb_bluebird_dee1601_properties;
-static struct dvb_usb_properties cxusb_bluebird_lgz201_properties;
-static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties;
+static struct dvb_usb_device_properties cxusb_medion_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties;
+static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties;
static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -503,36 +505,36 @@ static struct usb_device_id cxusb_table [] = {
{ USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DEE1601_WARM) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_COLD) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LGZ201_WARM) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_COLD) },
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_TH7579_WARM) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD) },
- { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD) },
+ { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
-static struct dvb_usb_properties cxusb_medion_properties = {
+static struct dvb_usb_device_properties cxusb_medion_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.size_of_priv = sizeof(struct cxusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_power_ctrl,
.frontend_attach = cxusb_cx22702_frontend_attach,
.tuner_attach = cxusb_fmd1216me_tuner_attach,
-
- .i2c_algo = &cxusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 5,
.endpoint = 0x02,
.u = {
@@ -542,6 +544,14 @@ static struct dvb_usb_properties cxusb_medion_properties = {
}
},
+ },
+ },
+ .power_ctrl = cxusb_power_ctrl,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
.num_device_descs = 1,
.devices = {
{ "Medion MD95700 (MDUSBTV-HYBRID)",
@@ -551,7 +561,7 @@ static struct dvb_usb_properties cxusb_medion_properties = {
}
};
-static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
+static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
@@ -562,22 +572,16 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
.size_of_priv = sizeof(struct cxusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_lgdt3303_frontend_attach,
.tuner_attach = cxusb_lgdt3303_tuner_attach,
- .i2c_algo = &cxusb_i2c_algo,
-
- .rc_interval = 100,
- .rc_key_map = dvico_portable_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
- .rc_query = cxusb_rc_query,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 5,
.endpoint = 0x02,
.u = {
@@ -586,6 +590,19 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
}
}
},
+ },
+ },
+
+ .power_ctrl = cxusb_bluebird_power_ctrl,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .rc_interval = 100,
+ .rc_key_map = dvico_portable_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
+ .rc_query = cxusb_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
@@ -596,7 +613,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = {
}
};
-static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
+static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
@@ -607,22 +624,15 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
.size_of_priv = sizeof(struct cxusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_dee1601_frontend_attach,
.tuner_attach = cxusb_dee1601_tuner_attach,
-
- .i2c_algo = &cxusb_i2c_algo,
-
- .rc_interval = 150,
- .rc_key_map = dvico_mce_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
- .rc_query = cxusb_rc_query,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 5,
.endpoint = 0x04,
.u = {
@@ -631,8 +641,21 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
}
}
},
+ },
+ },
+
+ .power_ctrl = cxusb_bluebird_power_ctrl,
- .num_device_descs = 2,
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .rc_interval = 150,
+ .rc_key_map = dvico_mce_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys),
+ .rc_query = cxusb_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 3,
.devices = {
{ "DViCO FusionHDTV DVB-T Dual USB",
{ &cxusb_table[3], NULL },
@@ -642,10 +665,14 @@ static struct dvb_usb_properties cxusb_bluebird_dee1601_properties = {
{ &cxusb_table[9], NULL },
{ &cxusb_table[10], NULL },
},
+ { "DViCO FusionHDTV DVB-T Dual Digital 2",
+ { &cxusb_table[11], NULL },
+ { &cxusb_table[12], NULL },
+ },
}
};
-static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = {
+static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
@@ -656,22 +683,16 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = {
.size_of_priv = sizeof(struct cxusb_state),
+ .num_adapters = 2,
+ .adapter = {
+ {
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_mt352_frontend_attach,
.tuner_attach = cxusb_lgz201_tuner_attach,
- .i2c_algo = &cxusb_i2c_algo,
-
- .rc_interval = 100,
- .rc_key_map = dvico_portable_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
- .rc_query = cxusb_rc_query,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 5,
.endpoint = 0x04,
.u = {
@@ -680,7 +701,18 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = {
}
}
},
+ },
+ },
+ .power_ctrl = cxusb_bluebird_power_ctrl,
+
+ .i2c_algo = &cxusb_i2c_algo,
+ .rc_interval = 100,
+ .rc_key_map = dvico_portable_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
+ .rc_query = cxusb_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
{ "DViCO FusionHDTV DVB-T USB (LGZ201)",
@@ -690,7 +722,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgz201_properties = {
}
};
-static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = {
+static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = DEVICE_SPECIFIC,
@@ -701,22 +733,16 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = {
.size_of_priv = sizeof(struct cxusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
.streaming_ctrl = cxusb_streaming_ctrl,
- .power_ctrl = cxusb_bluebird_power_ctrl,
.frontend_attach = cxusb_mt352_frontend_attach,
.tuner_attach = cxusb_dtt7579_tuner_attach,
- .i2c_algo = &cxusb_i2c_algo,
-
- .rc_interval = 100,
- .rc_key_map = dvico_portable_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
- .rc_query = cxusb_rc_query,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 5,
.endpoint = 0x04,
.u = {
@@ -725,6 +751,18 @@ static struct dvb_usb_properties cxusb_bluebird_dtt7579_properties = {
}
}
},
+ },
+ },
+ .power_ctrl = cxusb_bluebird_power_ctrl,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .rc_interval = 100,
+ .rc_key_map = dvico_portable_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dvico_portable_rc_keys),
+ .rc_query = cxusb_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
new file mode 100644
index 000000000000..ac84347f9d4c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -0,0 +1,49 @@
+/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
+ *
+ * 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, version 2.
+ *
+ * Copyright (C) 2005-6 DiBcom, SA
+ */
+#ifndef _DIB0700_H_
+#define _DIB0700_H_
+
+#define DVB_USB_LOG_PREFIX "dib0700"
+#include "dvb-usb.h"
+
+#include "dib07x0.h"
+
+extern int dvb_usb_dib0700_debug;
+#define deb_info(args...) dprintk(dvb_usb_dib0700_debug,0x01,args)
+#define deb_fw(args...) dprintk(dvb_usb_dib0700_debug,0x02,args)
+#define deb_fwdata(args...) dprintk(dvb_usb_dib0700_debug,0x04,args)
+#define deb_data(args...) dprintk(dvb_usb_dib0700_debug,0x08,args)
+
+#define REQUEST_I2C_READ 0x2
+#define REQUEST_I2C_WRITE 0x3
+#define REQUEST_POLL_RC 0x4
+#define REQUEST_JUMPRAM 0x8
+#define REQUEST_SET_GPIO 0xC
+#define REQUEST_ENABLE_VIDEO 0xF
+ // 1 Byte: 4MSB(1 = enable streaming, 0 = disable streaming) 4LSB(Video Mode: 0 = MPEG2 188Bytes, 1 = Analog)
+ // 2 Byte: MPEG2 mode: 4MSB(1 = Master Mode, 0 = Slave Mode) 4LSB(Channel 1 = bit0, Channel 2 = bit1)
+ // 2 Byte: Analog mode: 4MSB(0 = 625 lines, 1 = 525 lines) 4LSB( " " )
+
+struct dib0700_state {
+ u8 channel_state;
+ u16 mt2060_if1[2];
+};
+
+extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val);
+extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
+extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
+extern struct i2c_algorithm dib0700_i2c_algo;
+extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc, int *cold);
+
+extern int dib0700_device_count;
+extern struct dvb_usb_device_properties dib0700_devices[];
+extern struct usb_device_id dib0700_usb_id_table[];
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
new file mode 100644
index 000000000000..dca6c6985661
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -0,0 +1,279 @@
+/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
+ *
+ * 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, version 2.
+ *
+ * Copyright (C) 2005-6 DiBcom, SA
+ */
+#include "dib0700.h"
+
+/* debug */
+int dvb_usb_dib0700_debug;
+module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
+
+/* expecting rx buffer: request data[0] data[1] ... data[2] */
+static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
+{
+ int status;
+
+ deb_data(">>> ");
+ debug_dump(tx,txlen,deb_data);
+
+ status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
+ tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
+ USB_CTRL_GET_TIMEOUT);
+
+ if (status != txlen)
+ deb_data("ep 0 write error (status = %d, len: %d)\n",status,txlen);
+
+ return status < 0 ? status : 0;
+}
+
+/* expecting tx buffer: request data[0] ... data[n] (n <= 4) */
+static int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen)
+{
+ u16 index, value;
+ int status;
+
+ if (txlen < 2) {
+ err("tx buffer length is smaller than 2. Makes no sense.");
+ return -EINVAL;
+ }
+ if (txlen > 4) {
+ err("tx buffer length is larger than 4. Not supported.");
+ return -EINVAL;
+ }
+
+ deb_data(">>> ");
+ debug_dump(tx,txlen,deb_data);
+
+ value = ((txlen - 2) << 8) | tx[1];
+ index = 0;
+ if (txlen > 2)
+ index |= (tx[2] << 8);
+ if (txlen > 3)
+ index |= tx[3];
+
+ /* think about swapping here */
+ value = le16_to_cpu(value);
+ index = le16_to_cpu(index);
+
+ status = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev,0), tx[0],
+ USB_TYPE_VENDOR | USB_DIR_IN, value, index, rx, rxlen,
+ USB_CTRL_GET_TIMEOUT);
+
+ if (status < 0)
+ deb_info("ep 0 read error (status = %d)\n",status);
+
+ deb_data("<<< ");
+ debug_dump(rx,rxlen,deb_data);
+
+ return status; /* length in case of success */
+}
+
+int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
+{
+ u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
+ return dib0700_ctrl_wr(d,buf,3);
+}
+
+/*
+ * I2C master xfer function
+ */
+static int dib0700_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i,len;
+ u8 buf[255];
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ for (i = 0; i < num; i++) {
+ /* fill in the address */
+ buf[1] = (msg[i].addr << 1);
+ /* fill the buffer */
+ memcpy(&buf[2], msg[i].buf, msg[i].len);
+
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ buf[0] = REQUEST_I2C_READ;
+ buf[1] |= 1;
+
+ /* special thing in the current firmware: when length is zero the read-failed */
+ if ((len = dib0700_ctrl_rd(d, buf, msg[i].len + 2, msg[i+1].buf, msg[i+1].len)) <= 0) {
+ deb_info("I2C read failed on address %x\n", msg[i].addr);
+ break;
+ }
+
+ msg[i+1].len = len;
+
+ i++;
+ } else {
+ buf[0] = REQUEST_I2C_WRITE;
+ if (dib0700_ctrl_wr(d, buf, msg[i].len + 2) < 0)
+ break;
+ }
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 dib0700_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm dib0700_i2c_algo = {
+ .master_xfer = dib0700_i2c_xfer,
+ .functionality = dib0700_i2c_func,
+};
+
+int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc, int *cold)
+{
+ u8 buf[3] = { REQUEST_SET_GPIO, 4, (GPIO_IN << 7) | (0 << 6) }; // GPIO4 is save - used for I2C
+ *cold = usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+ buf[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, buf, 3, USB_CTRL_GET_TIMEOUT) != 3;
+
+ deb_info("cold: %d\n", *cold);
+ return 0;
+}
+
+static int dib0700_jumpram(struct usb_device *udev, u32 address)
+{
+ int ret, actlen;
+ u8 buf[8] = { REQUEST_JUMPRAM, 0, 0, 0,
+ (address >> 24) & 0xff,
+ (address >> 16) & 0xff,
+ (address >> 8) & 0xff,
+ address & 0xff };
+
+ if ((ret = usb_bulk_msg(udev, usb_sndbulkpipe(udev, 0x01),buf,8,&actlen,1000)) < 0) {
+ deb_fw("jumpram to 0x%x failed\n",address);
+ return ret;
+ }
+ if (actlen != 8) {
+ deb_fw("jumpram to 0x%x failed\n",address);
+ return -EIO;
+ }
+ return 0;
+}
+
+int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw)
+{
+ struct hexline hx;
+ int pos = 0, ret, act_len;
+
+ u8 buf[260];
+
+ while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
+ deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
+
+ buf[0] = hx.len;
+ buf[1] = (hx.addr >> 8) & 0xff;
+ buf[2] = hx.addr & 0xff;
+ buf[3] = hx.type;
+ memcpy(&buf[4],hx.data,hx.len);
+ buf[4+hx.len] = hx.chk;
+
+ ret = usb_bulk_msg(udev,
+ usb_sndbulkpipe(udev, 0x01),
+ buf,
+ hx.len + 5,
+ &act_len,
+ 1000);
+
+ if (ret < 0) {
+ err("firmware download failed at %d with %d",pos,ret);
+ return ret;
+ }
+ }
+
+ if (ret == 0) {
+ /* start the firmware */
+ if ((ret = dib0700_jumpram(udev, 0x70000000)) == 0) {
+ info("firmware started successfully.");
+ msleep(100);
+ }
+ } else
+ ret = -EIO;
+
+ return ret;
+}
+
+int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct dib0700_state *st = adap->dev->priv;
+ u8 b[4];
+
+ b[0] = REQUEST_ENABLE_VIDEO;
+ b[1] = 0x00;
+ b[2] = (0x01 << 4); /* Master mode */
+ b[3] = 0x00;
+
+ deb_info("modifying (%d) streaming state for %d\n", onoff, adap->id);
+
+ if (onoff)
+ st->channel_state |= 1 << adap->id;
+ else
+ st->channel_state &= ~(1 << adap->id);
+
+ b[2] |= st->channel_state;
+
+ if (st->channel_state) /* if at least one channel is active */
+ b[1] = (0x01 << 4) | 0x00;
+
+ deb_info("data for streaming: %x %x\n",b[1],b[2]);
+
+ return dib0700_ctrl_wr(adap->dev, b, 4);
+}
+
+static int dib0700_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ int i;
+
+ for (i = 0; i < dib0700_device_count; i++)
+ if (dvb_usb_device_init(intf, &dib0700_devices[i], THIS_MODULE, NULL) == 0)
+ return 0;
+
+ return -ENODEV;
+}
+
+static struct usb_driver dib0700_driver = {
+ .name = "dvb_usb_dib0700",
+ .probe = dib0700_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = dib0700_usb_id_table,
+};
+
+/* module stuff */
+static int __init dib0700_module_init(void)
+{
+ int result;
+ info("loaded with support for %d different device-types", dib0700_device_count);
+ if ((result = usb_register(&dib0700_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit dib0700_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&dib0700_driver);
+}
+
+module_init (dib0700_module_init);
+module_exit (dib0700_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for devices based on DiBcom DiB0700 - USB bridge");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
new file mode 100644
index 000000000000..e473bfed226b
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -0,0 +1,212 @@
+/* Linux driver for devices based on the DiBcom DiB0700 USB bridge
+ *
+ * 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, version 2.
+ *
+ * Copyright (C) 2005-6 DiBcom, SA
+ */
+#include "dib0700.h"
+
+#include "dib3000mc.h"
+#include "mt2060.h"
+
+static int force_lna_activation;
+module_param(force_lna_activation, int, 0644);
+MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), "
+ "if applicable for the device (default: 0=automatic/off).");
+
+/* Hauppauge Nova-T 500
+ * has a LNA on GPIO0 which is enabled by setting 1 */
+static struct mt2060_config bristol_mt2060_config[2] = {
+ {
+ .i2c_address = 0x60,
+ .clock_out = 3,
+ }, {
+ .i2c_address = 0x61,
+ }
+};
+
+static struct dibx000_agc_config bristol_dib3000p_mt2060_agc_config = {
+ .band_caps = BAND_VHF | BAND_UHF,
+ .setup = (1 << 8) | (5 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (2 << 0),
+
+ .agc1_max = 42598,
+ .agc1_min = 17694,
+ .agc2_max = 45875,
+ .agc2_min = 0,
+
+ .agc1_pt1 = 0,
+ .agc1_pt2 = 59,
+
+ .agc1_slope1 = 0,
+ .agc1_slope2 = 69,
+
+ .agc2_pt1 = 0,
+ .agc2_pt2 = 59,
+
+ .agc2_slope1 = 111,
+ .agc2_slope2 = 28,
+};
+
+static struct dib3000mc_config bristol_dib3000mc_config[2] = {
+ { .agc = &bristol_dib3000p_mt2060_agc_config,
+ .max_time = 0x196,
+ .ln_adc_level = 0x1cc7,
+ .output_mpeg2_in_188_bytes = 1,
+ },
+ { .agc = &bristol_dib3000p_mt2060_agc_config,
+ .max_time = 0x196,
+ .ln_adc_level = 0x1cc7,
+ .output_mpeg2_in_188_bytes = 1,
+ }
+};
+
+static int bristol_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_state *st = adap->dev->priv;
+ if (adap->id == 0) {
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
+
+ if (force_lna_activation)
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+ else
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 0);
+
+ if (dib3000mc_i2c_enumeration(&adap->dev->i2c_adap, 2, DEFAULT_DIB3000P_I2C_ADDRESS, bristol_dib3000mc_config) != 0) {
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
+ return -ENODEV;
+ }
+ }
+ st->mt2060_if1[adap->id] = 1220;
+ return (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap,
+ (10 + adap->id) << 1, &bristol_dib3000mc_config[adap->id])) == NULL ? -ENODEV : 0;
+}
+
+static int bristol_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dib0700_state *st = adap->dev->priv;
+ struct i2c_adapter *tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
+ return dvb_attach(mt2060_attach,adap->fe, tun_i2c, &bristol_mt2060_config[adap->id],
+ st->mt2060_if1[adap->id]) == NULL ? -ENODEV : 0;
+}
+
+/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
+/*
+static struct mt2060_config stk7000p_mt2060_config = {
+ 0x60
+};
+*/
+
+static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ /* unless there is no real power management in DVB - we leave the device on GPIO6 */
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); msleep(10);
+
+// adap->fe = dib7000m_attach(&adap->dev->i2c_adap, &stk7700p_dib7000m_config, 18);
+ return 0;
+}
+
+static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap)
+{
+// tun_i2c = dib7000m_get_tuner_i2c_master(adap->fe, 1);
+// return mt2060_attach(adap->fe, tun_i2c, &stk3000p_mt2060_config, if1);
+ return 0;
+}
+
+struct usb_device_id dib0700_usb_id_table[] = {
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
+ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
+
+#define DIB0700_DEFAULT_DEVICE_PROPERTIES \
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER, \
+ .usb_ctrl = DEVICE_SPECIFIC, \
+ .firmware = "dvb-usb-dib0700-01.fw", \
+ .download_firmware = dib0700_download_firmware, \
+ .no_reconnect = 1, \
+ .size_of_priv = sizeof(struct dib0700_state), \
+ .i2c_algo = &dib0700_i2c_algo, \
+ .identify_state = dib0700_identify_state
+
+#define DIB0700_DEFAULT_STREAMING_CONFIG(ep) \
+ .streaming_ctrl = dib0700_streaming_ctrl, \
+ .stream = { \
+ .type = USB_BULK, \
+ .count = 4, \
+ .endpoint = ep, \
+ .u = { \
+ .bulk = { \
+ .buffersize = 39480, \
+ } \
+ } \
+ }
+
+struct dvb_usb_device_properties dib0700_devices[] = {
+ {
+ DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .frontend_attach = stk7700p_frontend_attach,
+ .tuner_attach = stk7700p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+ },
+ },
+
+ .num_device_descs = 3,
+ .devices = {
+ { "DiBcom STK7700P reference design",
+ { &dib0700_usb_id_table[0], NULL },
+ { NULL },
+ },
+ { "Hauppauge Nova-T Stick",
+ { &dib0700_usb_id_table[3], NULL },
+ { NULL },
+ },
+ { "AVerMedia AVerTV DVB-T Volar",
+ { &dib0700_usb_id_table[4], NULL },
+ { NULL },
+ },
+ }
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .frontend_attach = bristol_frontend_attach,
+ .tuner_attach = bristol_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+ }, {
+ .frontend_attach = bristol_frontend_attach,
+ .tuner_attach = bristol_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge Nova-T 500 Dual DVB-T",
+ { &dib0700_usb_id_table[1], &dib0700_usb_id_table[2], NULL },
+ { NULL },
+ },
+ }
+ }
+};
+
+int dib0700_device_count = ARRAY_SIZE(dib0700_devices);
diff --git a/drivers/media/dvb/dvb-usb/dib07x0.h b/drivers/media/dvb/dvb-usb/dib07x0.h
new file mode 100644
index 000000000000..7e62c1018520
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dib07x0.h
@@ -0,0 +1,21 @@
+#ifndef _DIB07X0_H_
+#define _DIB07X0_H_
+
+enum dib07x0_gpios {
+ GPIO0 = 0,
+ GPIO1 = 2,
+ GPIO2 = 3,
+ GPIO3 = 4,
+ GPIO4 = 5,
+ GPIO5 = 6,
+ GPIO6 = 8,
+ GPIO7 = 10,
+ GPIO8 = 11,
+ GPIO9 = 14,
+ GPIO10 = 15,
+};
+
+#define GPIO_IN 0
+#define GPIO_OUT 1
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index abd75b4a350d..5143e426d283 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -18,12 +18,12 @@ MODULE_LICENSE("GPL");
#define deb_info(args...) dprintk(debug,0x01,args)
/* common stuff used by the different dibusb modules */
-int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+int dibusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
- if (d->priv != NULL) {
- struct dibusb_state *st = d->priv;
+ if (adap->priv != NULL) {
+ struct dibusb_state *st = adap->priv;
if (st->ops.fifo_ctrl != NULL)
- if (st->ops.fifo_ctrl(d->fe,onoff)) {
+ if (st->ops.fifo_ctrl(adap->fe,onoff)) {
err("error while controlling the fifo of the demod.");
return -ENODEV;
}
@@ -32,23 +32,23 @@ int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
}
EXPORT_SYMBOL(dibusb_streaming_ctrl);
-int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
+int dibusb_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
{
- if (d->priv != NULL) {
- struct dibusb_state *st = d->priv;
+ if (adap->priv != NULL) {
+ struct dibusb_state *st = adap->priv;
if (st->ops.pid_ctrl != NULL)
- st->ops.pid_ctrl(d->fe,index,pid,onoff);
+ st->ops.pid_ctrl(adap->fe,index,pid,onoff);
}
return 0;
}
EXPORT_SYMBOL(dibusb_pid_filter);
-int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff)
+int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
- if (d->priv != NULL) {
- struct dibusb_state *st = d->priv;
+ if (adap->priv != NULL) {
+ struct dibusb_state *st = adap->priv;
if (st->ops.pid_parse != NULL)
- if (st->ops.pid_parse(d->fe,onoff) < 0)
+ if (st->ops.pid_parse(adap->fe,onoff) < 0)
err("could not handle pid_parser");
}
return 0;
@@ -68,24 +68,24 @@ int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
}
EXPORT_SYMBOL(dibusb_power_ctrl);
-int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
u8 b[3] = { 0 };
int ret;
- if ((ret = dibusb_streaming_ctrl(d,onoff)) < 0)
+ if ((ret = dibusb_streaming_ctrl(adap,onoff)) < 0)
return ret;
if (onoff) {
b[0] = DIBUSB_REQ_SET_STREAMING_MODE;
b[1] = 0x00;
- if ((ret = dvb_usb_generic_write(d,b,2)) < 0)
+ if ((ret = dvb_usb_generic_write(adap->dev,b,2)) < 0)
return ret;
}
b[0] = DIBUSB_REQ_SET_IOCTL;
b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
- return dvb_usb_generic_write(d,b,3);
+ return dvb_usb_generic_write(adap->dev,b,3);
}
EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
@@ -131,9 +131,6 @@ static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num
if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
return -EAGAIN;
- if (num > 2)
- warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
for (i = 0; i < num; i++) {
/* write/read request */
if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
@@ -168,31 +165,143 @@ int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
}
EXPORT_SYMBOL(dibusb_read_eeprom_byte);
-int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
+/* 3000MC/P stuff */
+// Config Adjacent channels Perf -cal22
+static struct dibx000_agc_config dib3000p_mt2060_agc_config = {
+ .band_caps = BAND_VHF | BAND_UHF,
+ .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
+
+ .agc1_max = 48497,
+ .agc1_min = 23593,
+ .agc2_max = 46531,
+ .agc2_min = 24904,
+
+ .agc1_pt1 = 0x65,
+ .agc1_pt2 = 0x69,
+
+ .agc1_slope1 = 0x51,
+ .agc1_slope2 = 0x27,
+
+ .agc2_pt1 = 0,
+ .agc2_pt2 = 0x33,
+
+ .agc2_slope1 = 0x35,
+ .agc2_slope2 = 0x37,
+};
+
+static struct dib3000mc_config stk3000p_dib3000p_config = {
+ &dib3000p_mt2060_agc_config,
+
+ .max_time = 0x196,
+ .ln_adc_level = 0x1cc7,
+
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_command1 = 1,
+ .agc_command2 = 1,
+};
+
+static struct dibx000_agc_config dib3000p_panasonic_agc_config = {
+ .band_caps = BAND_VHF | BAND_UHF,
+ .setup = (1 << 8) | (5 << 5) | (1 << 4) | (1 << 3) | (0 << 2) | (2 << 0),
+
+ .agc1_max = 56361,
+ .agc1_min = 22282,
+ .agc2_max = 47841,
+ .agc2_min = 36045,
+
+ .agc1_pt1 = 0x3b,
+ .agc1_pt2 = 0x6b,
+
+ .agc1_slope1 = 0x55,
+ .agc1_slope2 = 0x1d,
+
+ .agc2_pt1 = 0,
+ .agc2_pt2 = 0x0a,
+
+ .agc2_slope1 = 0x95,
+ .agc2_slope2 = 0x1e,
+};
+
+static struct dib3000mc_config mod3000p_dib3000p_config = {
+ &dib3000p_panasonic_agc_config,
+
+ .max_time = 0x51,
+ .ln_adc_level = 0x1cc7,
+
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_command1 = 1,
+ .agc_command2 = 1,
+};
+
+int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *adap)
{
- struct dib3000_config demod_cfg;
- struct dibusb_state *st = d->priv;
-
- for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
- if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
- d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
- d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
- return 0;
+ if ((adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000P_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL ||
+ (adap->fe = dvb_attach(dib3000mc_attach, &adap->dev->i2c_adap, DEFAULT_DIB3000MC_I2C_ADDRESS, &mod3000p_dib3000p_config)) != NULL) {
+ if (adap->priv != NULL) {
+ struct dibusb_state *st = adap->priv;
+ st->ops.pid_parse = dib3000mc_pid_parse;
+ st->ops.pid_ctrl = dib3000mc_pid_control;
}
-
+ return 0;
+ }
return -ENODEV;
}
EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
-int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
-{
- d->pll_addr = 0x60;
- d->pll_desc = &dvb_pll_env57h1xd5;
+static struct mt2060_config stk3000p_mt2060_config = {
+ 0x60
+};
- d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+int dibusb_dib3000mc_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct dibusb_state *st = adap->priv;
+ u8 a,b;
+ u16 if1 = 1220;
+ struct i2c_adapter *tun_i2c;
+
+ // First IF calibration for Liteon Sticks
+ if (adap->dev->udev->descriptor.idVendor == USB_VID_LITEON &&
+ adap->dev->udev->descriptor.idProduct == USB_PID_LITEON_DVB_T_WARM) {
+
+ dibusb_read_eeprom_byte(adap->dev,0x7E,&a);
+ dibusb_read_eeprom_byte(adap->dev,0x7F,&b);
+
+ if (a == 0x00)
+ if1 += b;
+ else if (a == 0x80)
+ if1 -= b;
+ else
+ warn("LITE-ON DVB-T: Strange IF1 calibration :%2X %2X\n", a, b);
+
+ } else if (adap->dev->udev->descriptor.idVendor == USB_VID_DIBCOM &&
+ adap->dev->udev->descriptor.idProduct == USB_PID_DIBCOM_MOD3001_WARM) {
+ u8 desc;
+ dibusb_read_eeprom_byte(adap->dev, 7, &desc);
+ if (desc == 2) {
+ a = 127;
+ do {
+ dibusb_read_eeprom_byte(adap->dev, a, &desc);
+ a--;
+ } while (a > 7 && (desc == 0xff || desc == 0x00));
+ if (desc & 0x80)
+ if1 -= (0xff - desc);
+ else
+ if1 += desc;
+ }
+ }
+ tun_i2c = dib3000mc_get_tuner_i2c_master(adap->fe, 1);
+ if (dvb_attach(mt2060_attach, adap->fe, tun_i2c, &stk3000p_mt2060_config, if1) == NULL) {
+ /* not found - use panasonic pll parameters */
+ if (dvb_attach(dvb_pll_attach, adap->fe, 0x60, tun_i2c, &dvb_pll_env57h1xd5) == NULL)
+ return -ENOMEM;
+ } else {
+ st->mt2060_present = 1;
+ /* set the correct parameters for the dib3000p */
+ dib3000mc_set_config(adap->fe, &stk3000p_dib3000p_config);
+ }
return 0;
}
EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
@@ -267,6 +376,67 @@ struct dvb_usb_rc_key dibusb_rc_keys[] = {
{ 0x86, 0x1e, KEY_DOWN },
{ 0x86, 0x1f, KEY_LEFT },
{ 0x86, 0x1b, KEY_RIGHT },
+
+ /* Key codes for the DiBcom MOD3000 remote. */
+ { 0x80, 0x00, KEY_MUTE },
+ { 0x80, 0x01, KEY_TEXT },
+ { 0x80, 0x02, KEY_HOME },
+ { 0x80, 0x03, KEY_POWER },
+
+ { 0x80, 0x04, KEY_RED },
+ { 0x80, 0x05, KEY_GREEN },
+ { 0x80, 0x06, KEY_YELLOW },
+ { 0x80, 0x07, KEY_BLUE },
+
+ { 0x80, 0x08, KEY_DVD },
+ { 0x80, 0x09, KEY_AUDIO },
+ { 0x80, 0x0a, KEY_MEDIA }, /* Pictures */
+ { 0x80, 0x0b, KEY_VIDEO },
+
+ { 0x80, 0x0c, KEY_BACK },
+ { 0x80, 0x0d, KEY_UP },
+ { 0x80, 0x0e, KEY_RADIO },
+ { 0x80, 0x0f, KEY_EPG },
+
+ { 0x80, 0x10, KEY_LEFT },
+ { 0x80, 0x11, KEY_OK },
+ { 0x80, 0x12, KEY_RIGHT },
+ { 0x80, 0x13, KEY_UNKNOWN }, /* SAP */
+
+ { 0x80, 0x14, KEY_TV },
+ { 0x80, 0x15, KEY_DOWN },
+ { 0x80, 0x16, KEY_MENU }, /* DVD Menu */
+ { 0x80, 0x17, KEY_LAST },
+
+ { 0x80, 0x18, KEY_RECORD },
+ { 0x80, 0x19, KEY_STOP },
+ { 0x80, 0x1a, KEY_PAUSE },
+ { 0x80, 0x1b, KEY_PLAY },
+
+ { 0x80, 0x1c, KEY_PREVIOUS },
+ { 0x80, 0x1d, KEY_REWIND },
+ { 0x80, 0x1e, KEY_FASTFORWARD },
+ { 0x80, 0x1f, KEY_NEXT},
+
+ { 0x80, 0x40, KEY_1 },
+ { 0x80, 0x41, KEY_2 },
+ { 0x80, 0x42, KEY_3 },
+ { 0x80, 0x43, KEY_CHANNELUP },
+
+ { 0x80, 0x44, KEY_4 },
+ { 0x80, 0x45, KEY_5 },
+ { 0x80, 0x46, KEY_6 },
+ { 0x80, 0x47, KEY_CHANNELDOWN },
+
+ { 0x80, 0x48, KEY_7 },
+ { 0x80, 0x49, KEY_8 },
+ { 0x80, 0x4a, KEY_9 },
+ { 0x80, 0x4b, KEY_VOLUMEUP },
+
+ { 0x80, 0x4c, KEY_CLEAR },
+ { 0x80, 0x4d, KEY_0 },
+ { 0x80, 0x4e, KEY_ENTER },
+ { 0x80, 0x4f, KEY_VOLUMEDOWN },
};
EXPORT_SYMBOL(dibusb_rc_keys);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index f4c45f386ebc..4fe363e48352 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -14,35 +14,35 @@
*/
#include "dibusb.h"
-static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
+static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dib3000_config demod_cfg;
- struct dibusb_state *st = d->priv;
+ struct dibusb_state *st = adap->priv;
demod_cfg.demod_address = 0x8;
- if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) {
- d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
- d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+ if ((adap->fe = dib3000mb_attach(&demod_cfg,&adap->dev->i2c_adap,&st->ops)) == NULL)
return -ENODEV;
- }
- d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+ adap->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c;
+ adap->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c;
+
+ adap->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
return 0;
}
-static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d)
+static int dibusb_thomson_tuner_attach(struct dvb_usb_adapter *adap)
{
- d->pll_addr = 0x61;
- d->pll_desc = &dvb_pll_tua6010xs;
+ adap->pll_addr = 0x61;
+ adap->pll_desc = &dvb_pll_tua6010xs;
return 0;
}
/* Some of the Artec 1.1 device aren't equipped with the default tuner
* (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures
* this out. */
-static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
+static int dibusb_tuner_probe_and_attach(struct dvb_usb_adapter *adap)
{
u8 b[2] = { 0,0 }, b2[1];
int ret = 0;
@@ -54,36 +54,36 @@ static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
/* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
msg[0].addr = msg[1].addr = 0x60;
- if (d->tuner_pass_ctrl)
- d->tuner_pass_ctrl(d->fe,1,msg[0].addr);
+ if (adap->tuner_pass_ctrl)
+ adap->tuner_pass_ctrl(adap->fe,1,msg[0].addr);
- if (i2c_transfer (&d->i2c_adap, msg, 2) != 2) {
+ if (i2c_transfer(&adap->dev->i2c_adap, msg, 2) != 2) {
err("tuner i2c write failed.");
ret = -EREMOTEIO;
}
- if (d->tuner_pass_ctrl)
- d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
+ if (adap->tuner_pass_ctrl)
+ adap->tuner_pass_ctrl(adap->fe,0,msg[0].addr);
if (b2[0] == 0xfe) {
info("This device has the Thomson Cable onboard. Which is default.");
- dibusb_thomson_tuner_attach(d);
+ dibusb_thomson_tuner_attach(adap);
} else {
u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
info("This device has the Panasonic ENV77H11D5 onboard.");
- d->pll_addr = 0x60;
- memcpy(d->pll_init,bpll,4);
- d->pll_desc = &dvb_pll_tda665x;
+ adap->pll_addr = 0x60;
+ memcpy(adap->pll_init,bpll,4);
+ adap->pll_desc = &dvb_pll_tda665x;
}
return ret;
}
/* USB Driver stuff */
-static struct dvb_usb_properties dibusb1_1_properties;
-static struct dvb_usb_properties dibusb1_1_an2235_properties;
-static struct dvb_usb_properties dibusb2_0b_properties;
-static struct dvb_usb_properties artec_t1_usb2_properties;
+static struct dvb_usb_device_properties dibusb1_1_properties;
+static struct dvb_usb_device_properties dibusb1_1_an2235_properties;
+static struct dvb_usb_device_properties dibusb2_0b_properties;
+static struct dvb_usb_device_properties artec_t1_usb2_properties;
static int dibusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -150,34 +150,28 @@ static struct usb_device_id dibusb_dib3000mb_table [] = {
};
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
-static struct dvb_usb_properties dibusb1_1_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 16,
+static struct dvb_usb_device_properties dibusb1_1_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_AN2135,
.firmware = "dvb-usb-dibusb-5.0.0.11.fw",
- .size_of_priv = sizeof(struct dibusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 16,
.streaming_ctrl = dibusb_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
- .power_ctrl = dibusb_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
.tuner_attach = dibusb_tuner_probe_and_attach,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = dibusb_rc_keys,
- .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
-
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
@@ -186,6 +180,20 @@ static struct dvb_usb_properties dibusb1_1_properties = {
}
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ }
+ },
+
+ .power_ctrl = dibusb_power_ctrl,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 9,
.devices = {
@@ -228,34 +236,27 @@ static struct dvb_usb_properties dibusb1_1_properties = {
}
};
-static struct dvb_usb_properties dibusb1_1_an2235_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 16,
-
+static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_AN2235,
.firmware = "dvb-usb-dibusb-an2235-01.fw",
- .size_of_priv = sizeof(struct dibusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_ADAP_HAS_PID_FILTER,
+ .pid_filter_count = 16,
.streaming_ctrl = dibusb_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
- .power_ctrl = dibusb_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
.tuner_attach = dibusb_tuner_probe_and_attach,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = dibusb_rc_keys,
- .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
-
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
@@ -264,6 +265,19 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
}
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ },
+ },
+ .power_ctrl = dibusb_power_ctrl,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
.num_device_descs = 2,
@@ -272,8 +286,8 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
#endif
.devices = {
{ "Artec T1 USB1.1 TVBOX with AN2235",
- { &dibusb_dib3000mb_table[20], NULL },
{ &dibusb_dib3000mb_table[21], NULL },
+ { &dibusb_dib3000mb_table[22], NULL },
},
#ifdef CONFIG_DVB_USB_DIBUSB_MB_FAULTY
{ "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
@@ -285,34 +299,27 @@ static struct dvb_usb_properties dibusb1_1_an2235_properties = {
}
};
-static struct dvb_usb_properties dibusb2_0b_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 16,
+static struct dvb_usb_device_properties dibusb2_0b_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-adstech-usb2-02.fw",
- .size_of_priv = sizeof(struct dibusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 16,
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
- .power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
.tuner_attach = dibusb_thomson_tuner_attach,
-
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = dibusb_rc_keys,
- .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
-
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
@@ -321,6 +328,19 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
}
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ }
+ },
+ .power_ctrl = dibusb2_0_power_ctrl,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 2,
.devices = {
@@ -336,34 +356,27 @@ static struct dvb_usb_properties dibusb2_0b_properties = {
}
};
-static struct dvb_usb_properties artec_t1_usb2_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 16,
+static struct dvb_usb_device_properties artec_t1_usb2_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
- .size_of_priv = sizeof(struct dibusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 16,
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
- .power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mb_frontend_attach,
.tuner_attach = dibusb_tuner_probe_and_attach,
-
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = dibusb_rc_keys,
- .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
-
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
@@ -372,6 +385,19 @@ static struct dvb_usb_properties artec_t1_usb2_properties = {
}
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ }
+ },
+ .power_ctrl = dibusb2_0_power_ctrl,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index 55802fba3c29..a0fd37efc04b 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -15,7 +15,7 @@
#include "dibusb.h"
/* USB Driver stuff */
-static struct dvb_usb_properties dibusb_mc_properties;
+static struct dvb_usb_device_properties dibusb_mc_properties;
static int dibusb_mc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -28,37 +28,41 @@ static struct usb_device_id dibusb_dib3000mc_table [] = {
/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) },
/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) },
/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+/* 03 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_WARM) }, // ( ? )
+/* 04 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_COLD) },
+/* 05 */ { USB_DEVICE(USB_VID_LITEON, USB_PID_LITEON_DVB_T_WARM) },
+/* 06 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_COLD) },
+/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_DIGIVOX_MINI_SL_WARM) },
+/* 08 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_COLD) },
+/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB2_WARM) },
+/* 10 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_COLD) },
+/* 11 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14_WARM) },
+/* 12 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_COLD) },
+/* 13 */ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_WARM) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
-static struct dvb_usb_properties dibusb_mc_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 32,
+static struct dvb_usb_device_properties dibusb_mc_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-dibusb-6.0.0.8.fw",
- .size_of_priv = sizeof(struct dibusb_state),
-
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
- .power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mc_frontend_attach,
.tuner_attach = dibusb_dib3000mc_tuner_attach,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = dibusb_rc_keys,
- .rc_key_map_size = 63, /* FIXME */
- .rc_query = dibusb_rc_query,
-
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
@@ -67,17 +71,52 @@ static struct dvb_usb_properties dibusb_mc_properties = {
}
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ }
+ },
+ .power_ctrl = dibusb2_0_power_ctrl,
- .num_device_descs = 2,
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 111, /* FIXME */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 7,
.devices = {
{ "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
{ &dibusb_dib3000mc_table[0], NULL },
{ &dibusb_dib3000mc_table[1], NULL },
},
- { "Artec T1 USB2.0 TVBOX (please report the warm ID)",
+ { "Artec T1 USB2.0 TVBOX (please check the warm ID)",
{ &dibusb_dib3000mc_table[2], NULL },
- { NULL },
+ { &dibusb_dib3000mc_table[3], NULL },
+ },
+ { "LITE-ON USB2.0 DVB-T Tuner",
+ /* Also rebranded as Intuix S800, Toshiba */
+ { &dibusb_dib3000mc_table[4], NULL },
+ { &dibusb_dib3000mc_table[5], NULL },
+ },
+ { "MSI Digivox Mini SL",
+ { &dibusb_dib3000mc_table[6], NULL },
+ { &dibusb_dib3000mc_table[7], NULL },
+ },
+ { "GRAND - USB2.0 DVB-T adapter",
+ { &dibusb_dib3000mc_table[8], NULL },
+ { &dibusb_dib3000mc_table[9], NULL },
+ },
+ { "Artec T14 - USB2.0 DVB-T",
+ { &dibusb_dib3000mc_table[10], NULL },
+ { &dibusb_dib3000mc_table[11], NULL },
+ },
+ { "Leadtek - USB2.0 Winfast DTV dongle",
+ { &dibusb_dib3000mc_table[12], NULL },
+ { &dibusb_dib3000mc_table[13], NULL },
},
+ { NULL },
}
};
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 2d99d05c7eab..b60781032742 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -17,6 +17,8 @@
#include "dvb-usb.h"
#include "dib3000.h"
+#include "dib3000mc.h"
+#include "mt2060.h"
/*
* protocol of all dibusb related devices
@@ -96,7 +98,10 @@
struct dibusb_state {
struct dib_fe_xfer_ops ops;
+ int mt2060_present;
+};
+struct dibusb_device_state {
/* for RC5 remote control */
int old_toggle;
int last_repeat_count;
@@ -104,14 +109,15 @@ struct dibusb_state {
extern struct i2c_algorithm dibusb_i2c_algo;
-extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *);
-extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *);
+extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_adapter *);
+extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_adapter *);
+
+extern int dibusb_streaming_ctrl(struct dvb_usb_adapter *, int);
+extern int dibusb_pid_filter(struct dvb_usb_adapter *, int, u16, int);
+extern int dibusb_pid_filter_ctrl(struct dvb_usb_adapter *, int);
+extern int dibusb2_0_streaming_ctrl(struct dvb_usb_adapter *, int);
-extern int dibusb_streaming_ctrl(struct dvb_usb_device *, int);
-extern int dibusb_pid_filter(struct dvb_usb_device *, int, u16, int);
-extern int dibusb_pid_filter_ctrl(struct dvb_usb_device *, int);
extern int dibusb_power_ctrl(struct dvb_usb_device *, int);
-extern int dibusb2_0_streaming_ctrl(struct dvb_usb_device *, int);
extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
#define DEFAULT_RC_INTERVAL 150
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index c14d9efb48fd..8fb34375c1fb 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -83,7 +83,7 @@ static struct i2c_algorithm digitv_i2c_algo = {
/* Callbacks for DVB USB */
static int digitv_identify_state (struct usb_device *udev, struct
- dvb_usb_properties *props, struct dvb_usb_device_description **desc,
+ dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
int *cold)
{
*cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
@@ -116,59 +116,129 @@ static struct mt352_config digitv_mt352_config = {
static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
- struct dvb_usb_device *d = fe->dvb->priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
u8 b[5];
dvb_usb_tuner_calc_regs(fe,fep,b, 5);
- return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0);
+ return digitv_ctrl_msg(adap->dev, USB_WRITE_TUNER, 0, &b[1], 4, NULL, 0);
}
static struct nxt6000_config digitv_nxt6000_config = {
.clock_inversion = 1,
};
-static int digitv_frontend_attach(struct dvb_usb_device *d)
+static int digitv_frontend_attach(struct dvb_usb_adapter *adap)
{
- if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) {
- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ if ((adap->fe = dvb_attach(mt352_attach, &digitv_mt352_config, &adap->dev->i2c_adap)) != NULL) {
+ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
- if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
- d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
+ if ((adap->fe = dvb_attach(nxt6000_attach, &digitv_nxt6000_config, &adap->dev->i2c_adap)) != NULL) {
+ adap->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params;
return 0;
}
return -EIO;
}
-static int digitv_tuner_attach(struct dvb_usb_device *d)
+static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
{
- d->pll_addr = 0x60;
- d->pll_desc = &dvb_pll_tded4;
+ adap->pll_addr = 0x60;
+ adap->pll_desc = &dvb_pll_tded4;
return 0;
}
static struct dvb_usb_rc_key digitv_rc_keys[] = {
- { 0x00, 0x16, KEY_POWER }, /* dummy key */
+ { 0x5f, 0x55, KEY_0 },
+ { 0x6f, 0x55, KEY_1 },
+ { 0x9f, 0x55, KEY_2 },
+ { 0xaf, 0x55, KEY_3 },
+ { 0x5f, 0x56, KEY_4 },
+ { 0x6f, 0x56, KEY_5 },
+ { 0x9f, 0x56, KEY_6 },
+ { 0xaf, 0x56, KEY_7 },
+ { 0x5f, 0x59, KEY_8 },
+ { 0x6f, 0x59, KEY_9 },
+ { 0x9f, 0x59, KEY_TV },
+ { 0xaf, 0x59, KEY_AUX },
+ { 0x5f, 0x5a, KEY_DVD },
+ { 0x6f, 0x5a, KEY_POWER },
+ { 0x9f, 0x5a, KEY_MHP }, /* labelled 'Picture' */
+ { 0xaf, 0x5a, KEY_AUDIO },
+ { 0x5f, 0x65, KEY_INFO },
+ { 0x6f, 0x65, KEY_F13 }, /* 16:9 */
+ { 0x9f, 0x65, KEY_F14 }, /* 14:9 */
+ { 0xaf, 0x65, KEY_EPG },
+ { 0x5f, 0x66, KEY_EXIT },
+ { 0x6f, 0x66, KEY_MENU },
+ { 0x9f, 0x66, KEY_UP },
+ { 0xaf, 0x66, KEY_DOWN },
+ { 0x5f, 0x69, KEY_LEFT },
+ { 0x6f, 0x69, KEY_RIGHT },
+ { 0x9f, 0x69, KEY_ENTER },
+ { 0xaf, 0x69, KEY_CHANNELUP },
+ { 0x5f, 0x6a, KEY_CHANNELDOWN },
+ { 0x6f, 0x6a, KEY_VOLUMEUP },
+ { 0x9f, 0x6a, KEY_VOLUMEDOWN },
+ { 0xaf, 0x6a, KEY_RED },
+ { 0x5f, 0x95, KEY_GREEN },
+ { 0x6f, 0x95, KEY_YELLOW },
+ { 0x9f, 0x95, KEY_BLUE },
+ { 0xaf, 0x95, KEY_SUBTITLE },
+ { 0x5f, 0x96, KEY_F15 }, /* AD */
+ { 0x6f, 0x96, KEY_TEXT },
+ { 0x9f, 0x96, KEY_MUTE },
+ { 0xaf, 0x96, KEY_REWIND },
+ { 0x5f, 0x99, KEY_STOP },
+ { 0x6f, 0x99, KEY_PLAY },
+ { 0x9f, 0x99, KEY_FASTFORWARD },
+ { 0xaf, 0x99, KEY_F16 }, /* chapter */
+ { 0x5f, 0x9a, KEY_PAUSE },
+ { 0x6f, 0x9a, KEY_PLAY },
+ { 0x9f, 0x9a, KEY_RECORD },
+ { 0xaf, 0x9a, KEY_F17 }, /* picture in picture */
+ { 0x5f, 0xa5, KEY_KPPLUS }, /* zoom in */
+ { 0x6f, 0xa5, KEY_KPMINUS }, /* zoom out */
+ { 0x9f, 0xa5, KEY_F18 }, /* capture */
+ { 0xaf, 0xa5, KEY_F19 }, /* web */
+ { 0x5f, 0xa6, KEY_EMAIL },
+ { 0x6f, 0xa6, KEY_PHONE },
+ { 0x9f, 0xa6, KEY_PC },
};
-/* TODO is it really the NEC protocol ? */
static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
+ int i;
u8 key[5];
+ u8 b[4] = { 0 };
+
+ *event = 0;
+ *state = REMOTE_NO_KEY_PRESSED;
digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
- /* TODO state, maybe it is VV ? */
+
+ /* Tell the device we've read the remote. Not sure how necessary
+ this is, but the Nebula SDK does it. */
+ digitv_ctrl_msg(d,USB_WRITE_REMOTE,0,b,4,NULL,0);
+
+ /* if something is inside the buffer, simulate key press */
if (key[1] != 0)
- key[0] = 0x01; /* if something is inside the buffer, simulate key press */
+ {
+ for (i = 0; i < d->props.rc_key_map_size; i++) {
+ if (d->props.rc_key_map[i].custom == key[1] &&
+ d->props.rc_key_map[i].data == key[2]) {
+ *event = d->props.rc_key_map[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ return 0;
+ }
+ }
+ }
- /* call the universal NEC remote processor, to find out the key's state and event */
- dvb_usb_nec_rc_key_to_event(d,key,event,state);
if (key[0] != 0)
deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
return 0;
}
/* DVB USB Driver stuff */
-static struct dvb_usb_properties digitv_properties;
+static struct dvb_usb_device_properties digitv_properties;
static int digitv_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -195,30 +265,21 @@ static struct usb_device_id digitv_table [] = {
};
MODULE_DEVICE_TABLE (usb, digitv_table);
-static struct dvb_usb_properties digitv_properties = {
+static struct dvb_usb_device_properties digitv_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-digitv-02.fw",
- .size_of_priv = 0,
-
+ .num_adapters = 1,
+ .adapter = {
+ {
.frontend_attach = digitv_frontend_attach,
.tuner_attach = digitv_tuner_attach,
- .rc_interval = 1000,
- .rc_key_map = digitv_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(digitv_rc_keys),
- .rc_query = digitv_rc_query,
-
- .identify_state = digitv_identify_state,
-
- .i2c_algo = &digitv_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
@@ -227,6 +288,18 @@ static struct dvb_usb_properties digitv_properties = {
}
}
},
+ }
+ },
+ .identify_state = digitv_identify_state,
+
+ .rc_interval = 1000,
+ .rc_key_map = digitv_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(digitv_rc_keys),
+ .rc_query = digitv_rc_query,
+
+ .i2c_algo = &digitv_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index 70afcfd141ca..fa43a41d753b 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -28,19 +28,19 @@ static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
return 0;
}
-static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+static int dtt200u_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
u8 b_streaming[2] = { SET_STREAMING, onoff };
u8 b_rst_pid = RESET_PID_FILTER;
- dvb_usb_generic_write(d,b_streaming,2);
+ dvb_usb_generic_write(adap->dev, b_streaming, 2);
if (onoff == 0)
- dvb_usb_generic_write(d,&b_rst_pid,1);
+ dvb_usb_generic_write(adap->dev, &b_rst_pid, 1);
return 0;
}
-static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
+static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid, int onoff)
{
u8 b_pid[4];
pid = onoff ? pid : 0;
@@ -50,7 +50,7 @@ static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int
b_pid[2] = pid & 0xff;
b_pid[3] = (pid >> 8) & 0x1f;
- return dvb_usb_generic_write(d,b_pid,4);
+ return dvb_usb_generic_write(adap->dev, b_pid, 4);
}
/* remote control */
@@ -86,21 +86,23 @@ static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
-static int dtt200u_frontend_attach(struct dvb_usb_device *d)
+static int dtt200u_frontend_attach(struct dvb_usb_adapter *adap)
{
- d->fe = dtt200u_fe_attach(d);
+ adap->fe = dtt200u_fe_attach(adap->dev);
return 0;
}
-static struct dvb_usb_properties dtt200u_properties;
-static struct dvb_usb_properties wt220u_properties;
-static struct dvb_usb_properties wt220u_zl0353_properties;
+static struct dvb_usb_device_properties dtt200u_properties;
+static struct dvb_usb_device_properties wt220u_fc_properties;
+static struct dvb_usb_device_properties wt220u_properties;
+static struct dvb_usb_device_properties wt220u_zl0353_properties;
static int dtt200u_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE,NULL) == 0 ||
+ dvb_usb_device_init(intf,&wt220u_fc_properties,THIS_MODULE,NULL) == 0 ||
dvb_usb_device_init(intf,&wt220u_zl0353_properties,THIS_MODULE,NULL) == 0)
return 0;
@@ -114,32 +116,29 @@ static struct usb_device_id dtt200u_usb_table [] = {
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) },
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_COLD) },
{ USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZL0353_WARM) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_COLD) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_FC_WARM) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_ZAP250_COLD) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
-static struct dvb_usb_properties dtt200u_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
- .pid_filter_count = 15,
-
+static struct dvb_usb_device_properties dtt200u_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-dtt200u-01.fw",
- .power_ctrl = dtt200u_power_ctrl,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+ .pid_filter_count = 15,
+
.streaming_ctrl = dtt200u_streaming_ctrl,
.pid_filter = dtt200u_pid_filter,
.frontend_attach = dtt200u_frontend_attach,
-
- .rc_interval = 300,
- .rc_key_map = dtt200u_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
- .rc_query = dtt200u_rc_query,
-
- .generic_bulk_ctrl_endpoint = 0x01,
-
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
@@ -148,6 +147,16 @@ static struct dvb_usb_properties dtt200u_properties = {
}
}
},
+ }
+ },
+ .power_ctrl = dtt200u_power_ctrl,
+
+ .rc_interval = 300,
+ .rc_key_map = dtt200u_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+ .rc_query = dtt200u_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
@@ -159,28 +168,22 @@ static struct dvb_usb_properties dtt200u_properties = {
}
};
-static struct dvb_usb_properties wt220u_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
- .pid_filter_count = 15,
-
+static struct dvb_usb_device_properties wt220u_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-wt220u-02.fw",
- .power_ctrl = dtt200u_power_ctrl,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+ .pid_filter_count = 15,
+
.streaming_ctrl = dtt200u_streaming_ctrl,
.pid_filter = dtt200u_pid_filter,
.frontend_attach = dtt200u_frontend_attach,
-
- .rc_interval = 300,
- .rc_key_map = dtt200u_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
- .rc_query = dtt200u_rc_query,
-
- .generic_bulk_ctrl_endpoint = 0x01,
-
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
@@ -189,28 +192,54 @@ static struct dvb_usb_properties wt220u_properties = {
}
}
},
+ }
+ },
+ .power_ctrl = dtt200u_power_ctrl,
+
+ .rc_interval = 300,
+ .rc_key_map = dtt200u_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+ .rc_query = dtt200u_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
{ .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
- .cold_ids = { &dtt200u_usb_table[2], NULL },
+ .cold_ids = { &dtt200u_usb_table[2], &dtt200u_usb_table[8], NULL },
.warm_ids = { &dtt200u_usb_table[3], NULL },
},
{ NULL },
}
};
-static struct dvb_usb_properties wt220u_zl0353_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
- .pid_filter_count = 15,
-
+static struct dvb_usb_device_properties wt220u_fc_properties = {
.usb_ctrl = CYPRESS_FX2,
- .firmware = "dvb-usb-wt220u-zl0353-01.fw",
+ .firmware = "dvb-usb-wt220u-fc03.fw",
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+ .pid_filter_count = 15,
- .power_ctrl = dtt200u_power_ctrl,
.streaming_ctrl = dtt200u_streaming_ctrl,
.pid_filter = dtt200u_pid_filter,
.frontend_attach = dtt200u_frontend_attach,
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+ }
+ },
+ .power_ctrl = dtt200u_power_ctrl,
.rc_interval = 300,
.rc_key_map = dtt200u_rc_keys,
@@ -219,9 +248,32 @@ static struct dvb_usb_properties wt220u_zl0353_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "WideView WT-220U PenType Receiver (Typhoon/Freecom)",
+ .cold_ids = { &dtt200u_usb_table[6], NULL },
+ .warm_ids = { &dtt200u_usb_table[7], NULL },
+ },
+ { NULL },
+ }
+};
+
+static struct dvb_usb_device_properties wt220u_zl0353_properties = {
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-wt220u-zl0353-01.fw",
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_NEED_PID_FILTERING,
+ .pid_filter_count = 15,
+
+ .streaming_ctrl = dtt200u_streaming_ctrl,
+ .pid_filter = dtt200u_pid_filter,
+ .frontend_attach = dtt200u_frontend_attach,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
@@ -230,6 +282,16 @@ static struct dvb_usb_properties wt220u_zl0353_properties = {
}
}
},
+ }
+ },
+ .power_ctrl = dtt200u_power_ctrl,
+
+ .rc_interval = 300,
+ .rc_key_map = dtt200u_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+ .rc_query = dtt200u_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
@@ -271,6 +333,6 @@ module_init(dtt200u_usb_module_init);
module_exit(dtt200u_usb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
-MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon/Club3D DVB-T USB2.0 devices");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
index a3460bf2d9fa..35ab68f6dcf6 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-common.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
@@ -14,31 +14,36 @@
extern int dvb_usb_debug;
extern int dvb_usb_disable_rc_polling;
-#define deb_info(args...) dprintk(dvb_usb_debug,0x01,args)
-#define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args)
-#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args)
-#define deb_ts(args...) dprintk(dvb_usb_debug,0x08,args)
-#define deb_err(args...) dprintk(dvb_usb_debug,0x10,args)
-#define deb_rc(args...) dprintk(dvb_usb_debug,0x20,args)
-#define deb_fw(args...) dprintk(dvb_usb_debug,0x40,args)
-#define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args)
+#define deb_info(args...) dprintk(dvb_usb_debug,0x001,args)
+#define deb_xfer(args...) dprintk(dvb_usb_debug,0x002,args)
+#define deb_pll(args...) dprintk(dvb_usb_debug,0x004,args)
+#define deb_ts(args...) dprintk(dvb_usb_debug,0x008,args)
+#define deb_err(args...) dprintk(dvb_usb_debug,0x010,args)
+#define deb_rc(args...) dprintk(dvb_usb_debug,0x020,args)
+#define deb_fw(args...) dprintk(dvb_usb_debug,0x040,args)
+#define deb_mem(args...) dprintk(dvb_usb_debug,0x080,args)
+#define deb_uxfer(args...) dprintk(dvb_usb_debug,0x100,args)
/* commonly used methods */
-extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_properties *);
+extern int dvb_usb_download_firmware(struct usb_device *, struct dvb_usb_device_properties *);
-extern int dvb_usb_urb_submit(struct dvb_usb_device *);
-extern int dvb_usb_urb_kill(struct dvb_usb_device *);
-extern int dvb_usb_urb_init(struct dvb_usb_device *);
-extern int dvb_usb_urb_exit(struct dvb_usb_device *);
+extern int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff);
+
+extern int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props);
+extern int usb_urb_exit(struct usb_data_stream *stream);
+extern int usb_urb_submit(struct usb_data_stream *stream);
+extern int usb_urb_kill(struct usb_data_stream *stream);
+
+extern int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap);
extern int dvb_usb_i2c_init(struct dvb_usb_device *);
extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
-extern int dvb_usb_dvb_init(struct dvb_usb_device *);
-extern int dvb_usb_dvb_exit(struct dvb_usb_device *);
-
-extern int dvb_usb_fe_init(struct dvb_usb_device *);
-extern int dvb_usb_fe_exit(struct dvb_usb_device *);
+extern int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap);
+extern int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap);
extern int dvb_usb_remote_init(struct dvb_usb_device *);
extern int dvb_usb_remote_exit(struct dvb_usb_device *);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
index ec631708c394..4561a672da92 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -1,6 +1,6 @@
/* dvb-usb-dvb.c is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for initializing and handling the
@@ -8,55 +8,55 @@
*/
#include "dvb-usb-common.h"
+/* does the complete input transfer handling */
static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
{
- struct dvb_usb_device *d = dvbdmxfeed->demux->priv;
+ struct dvb_usb_adapter *adap = dvbdmxfeed->demux->priv;
int newfeedcount,ret;
- if (d == NULL)
+ if (adap == NULL)
return -ENODEV;
- newfeedcount = d->feedcount + (onoff ? 1 : -1);
+ newfeedcount = adap->feedcount + (onoff ? 1 : -1);
- /*
- * stop feed before setting a new pid if there will be no pid anymore
- */
+ /* stop feed before setting a new pid if there will be no pid anymore */
if (newfeedcount == 0) {
deb_ts("stop feeding\n");
- dvb_usb_urb_kill(d);
+ usb_urb_kill(&adap->stream);
- if (d->props.streaming_ctrl != NULL)
- if ((ret = d->props.streaming_ctrl(d,0)))
+ if (adap->props.streaming_ctrl != NULL)
+ if ((ret = adap->props.streaming_ctrl(adap,0)))
err("error while stopping stream.");
-
}
- d->feedcount = newfeedcount;
+ adap->feedcount = newfeedcount;
/* activate the pid on the device specific pid_filter */
- deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
- if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
- d->pid_filtering &&
- d->props.pid_filter != NULL)
- d->props.pid_filter(d,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+ deb_ts("setting pid (%s): %5d %04x at index %d '%s'\n",adap->pid_filtering ?
+ "yes" : "no", dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ?
+ "on" : "off");
+ if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->pid_filtering &&
+ adap->props.pid_filter != NULL)
+ adap->props.pid_filter(adap, dvbdmxfeed->index, dvbdmxfeed->pid,onoff);
/* start the feed if this was the first feed and there is still a feed
* for reception.
*/
- if (d->feedcount == onoff && d->feedcount > 0) {
+ if (adap->feedcount == onoff && adap->feedcount > 0) {
deb_ts("submitting all URBs\n");
- dvb_usb_urb_submit(d);
+ usb_urb_submit(&adap->stream);
deb_ts("controlling pid parser\n");
- if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
- d->props.caps & DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF &&
- d->props.pid_filter_ctrl != NULL)
- if (d->props.pid_filter_ctrl(d,d->pid_filtering) < 0)
+ if (adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER &&
+ adap->props.caps & DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF &&
+ adap->props.pid_filter_ctrl != NULL)
+ if (adap->props.pid_filter_ctrl(adap,adap->pid_filtering) < 0)
err("could not handle pid_parser");
deb_ts("start feeding\n");
- if (d->props.streaming_ctrl != NULL)
- if (d->props.streaming_ctrl(d,1)) {
+ if (adap->props.streaming_ctrl != NULL)
+ if (adap->props.streaming_ctrl(adap,1)) {
err("error while enabling fifo.");
return -ENODEV;
}
@@ -77,134 +77,130 @@ static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
return dvb_usb_ctrl_feed(dvbdmxfeed,0);
}
-int dvb_usb_dvb_init(struct dvb_usb_device *d)
+int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap)
{
int ret;
- if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
- d->owner, &d->udev->dev)) < 0) {
+ if ((ret = dvb_register_adapter(&adap->dvb_adap, adap->dev->desc->name,
+ adap->dev->owner, &adap->dev->udev->dev)) < 0) {
deb_info("dvb_register_adapter failed: error %d", ret);
goto err;
}
- d->dvb_adap.priv = d;
-
- if (d->props.read_mac_address) {
- if (d->props.read_mac_address(d,d->dvb_adap.proposed_mac) == 0)
- info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",d->dvb_adap.proposed_mac[0],
- d->dvb_adap.proposed_mac[1],d->dvb_adap.proposed_mac[2],
- d->dvb_adap.proposed_mac[3],d->dvb_adap.proposed_mac[4],
- d->dvb_adap.proposed_mac[5]);
+ adap->dvb_adap.priv = adap;
+
+ if (adap->dev->props.read_mac_address) {
+ if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0)
+ info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0],
+ adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2],
+ adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4],
+ adap->dvb_adap.proposed_mac[5]);
else
err("MAC address reading failed.");
}
- d->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
- d->demux.priv = d;
+ adap->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ adap->demux.priv = adap;
- d->demux.feednum = d->demux.filternum = d->max_feed_count;
- d->demux.start_feed = dvb_usb_start_feed;
- d->demux.stop_feed = dvb_usb_stop_feed;
- d->demux.write_to_decoder = NULL;
- if ((ret = dvb_dmx_init(&d->demux)) < 0) {
+ adap->demux.feednum = adap->demux.filternum = adap->max_feed_count;
+ adap->demux.start_feed = dvb_usb_start_feed;
+ adap->demux.stop_feed = dvb_usb_stop_feed;
+ adap->demux.write_to_decoder = NULL;
+ if ((ret = dvb_dmx_init(&adap->demux)) < 0) {
err("dvb_dmx_init failed: error %d",ret);
goto err_dmx;
}
- d->dmxdev.filternum = d->demux.filternum;
- d->dmxdev.demux = &d->demux.dmx;
- d->dmxdev.capabilities = 0;
- if ((ret = dvb_dmxdev_init(&d->dmxdev, &d->dvb_adap)) < 0) {
+ adap->dmxdev.filternum = adap->demux.filternum;
+ adap->dmxdev.demux = &adap->demux.dmx;
+ adap->dmxdev.capabilities = 0;
+ if ((ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap)) < 0) {
err("dvb_dmxdev_init failed: error %d",ret);
goto err_dmx_dev;
}
- dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
+ dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
- d->state |= DVB_USB_STATE_DVB;
+ adap->state |= DVB_USB_ADAP_STATE_DVB;
return 0;
err_dmx_dev:
- dvb_dmx_release(&d->demux);
+ dvb_dmx_release(&adap->demux);
err_dmx:
- dvb_unregister_adapter(&d->dvb_adap);
+ dvb_unregister_adapter(&adap->dvb_adap);
err:
return ret;
}
-int dvb_usb_dvb_exit(struct dvb_usb_device *d)
+int dvb_usb_adapter_dvb_exit(struct dvb_usb_adapter *adap)
{
- if (d->state & DVB_USB_STATE_DVB) {
+ if (adap->state & DVB_USB_ADAP_STATE_DVB) {
deb_info("unregistering DVB part\n");
- dvb_net_release(&d->dvb_net);
- d->demux.dmx.close(&d->demux.dmx);
- dvb_dmxdev_release(&d->dmxdev);
- dvb_dmx_release(&d->demux);
- dvb_unregister_adapter(&d->dvb_adap);
- d->state &= ~DVB_USB_STATE_DVB;
+ dvb_net_release(&adap->dvb_net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ dvb_unregister_adapter(&adap->dvb_adap);
+ adap->state &= ~DVB_USB_ADAP_STATE_DVB;
}
return 0;
}
static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
{
- struct dvb_usb_device *d = fe->dvb->priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
- if (d->props.power_ctrl)
- d->props.power_ctrl(d,1);
+ dvb_usb_device_power_ctrl(adap->dev, 1);
- if (d->fe_init)
- d->fe_init(fe);
+ if (adap->fe_init)
+ adap->fe_init(fe);
return 0;
}
static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
{
- struct dvb_usb_device *d = fe->dvb->priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
- if (d->fe_sleep)
- d->fe_sleep(fe);
+ if (adap->fe_sleep)
+ adap->fe_sleep(fe);
- if (d->props.power_ctrl)
- d->props.power_ctrl(d,0);
-
- return 0;
+ return dvb_usb_device_power_ctrl(adap->dev, 0);
}
-int dvb_usb_fe_init(struct dvb_usb_device* d)
+int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap)
{
- if (d->props.frontend_attach == NULL) {
- err("strange '%s' doesn't want to attach a frontend.",d->desc->name);
+ if (adap->props.frontend_attach == NULL) {
+ err("strange: '%s' #%d doesn't want to attach a frontend.",adap->dev->desc->name, adap->id);
return 0;
}
- d->props.frontend_attach(d);
-
/* re-assign sleep and wakeup functions */
- if (d->fe != NULL) {
- d->fe_init = d->fe->ops.init; d->fe->ops.init = dvb_usb_fe_wakeup;
- d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep;
+ if (adap->props.frontend_attach(adap) == 0 && adap->fe != NULL) {
+ adap->fe_init = adap->fe->ops.init; adap->fe->ops.init = dvb_usb_fe_wakeup;
+ adap->fe_sleep = adap->fe->ops.sleep; adap->fe->ops.sleep = dvb_usb_fe_sleep;
- if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
err("Frontend registration failed.");
- if (d->fe->ops.release)
- d->fe->ops.release(d->fe);
- d->fe = NULL;
+ dvb_frontend_detach(adap->fe);
+ adap->fe = NULL;
return -ENODEV;
}
- } else
- err("no frontend was attached by '%s'",d->desc->name);
- if (d->props.tuner_attach != NULL)
- d->props.tuner_attach(d);
+ /* only attach the tuner if the demod is there */
+ if (adap->props.tuner_attach != NULL)
+ adap->props.tuner_attach(adap);
+ } else
+ err("no frontend was attached by '%s'",adap->dev->desc->name);
return 0;
}
-int dvb_usb_fe_exit(struct dvb_usb_device *d)
+int dvb_usb_adapter_frontend_exit(struct dvb_usb_adapter *adap)
{
- if (d->fe != NULL)
- dvb_unregister_frontend(d->fe);
+ if (adap->fe != NULL) {
+ dvb_unregister_frontend(adap->fe);
+ dvb_frontend_detach(adap->fe);
+ }
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
index 9222b0a81f74..e1112e39fb63 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
@@ -1,6 +1,6 @@
/* dvb-usb-firmware.c is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
@@ -24,9 +24,6 @@ static struct usb_cypress_controller cypress[] = {
{ .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
};
-static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
- int *pos);
-
/*
* load a firmware packet to the device
*/
@@ -78,7 +75,7 @@ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw
}
EXPORT_SYMBOL(usb_cypress_load_firmware);
-int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties *props)
+int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_properties *props)
{
int ret;
const struct firmware *fw = NULL;
@@ -115,7 +112,7 @@ int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_properties
return ret;
}
-static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
+int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
int *pos)
{
u8 *b = (u8 *) &fw->data[*pos];
@@ -146,3 +143,4 @@ static int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx,
return *pos;
}
+EXPORT_SYMBOL(dvb_usb_get_hexline);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index 6b611a725093..55ba020386c9 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -1,6 +1,6 @@
/* dvb-usb-i2c.c is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* This file contains functions for (de-)initializing an I2C adapter.
@@ -48,48 +48,48 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d)
int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe)
{
- struct dvb_usb_device *d = fe->dvb->priv;
- struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = adap->pll_init, .len = 4 };
int ret = 0;
/* if pll_desc is not used */
- if (d->pll_desc == NULL)
+ if (adap->pll_desc == NULL)
return 0;
- if (d->tuner_pass_ctrl)
- d->tuner_pass_ctrl(fe,1,d->pll_addr);
+ if (adap->tuner_pass_ctrl)
+ adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
- deb_pll("pll init: %x\n",d->pll_addr);
- deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
- d->pll_init[2],d->pll_init[3]);
+ deb_pll("pll init: %x\n",adap->pll_addr);
+ deb_pll("pll-buf: %x %x %x %x\n",adap->pll_init[0], adap->pll_init[1],
+ adap->pll_init[2], adap->pll_init[3]);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
+ if (i2c_transfer (&adap->dev->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_init.");
ret = -EREMOTEIO;
}
msleep(1);
- if (d->tuner_pass_ctrl)
- d->tuner_pass_ctrl(fe,0,d->pll_addr);
+ if (adap->tuner_pass_ctrl)
+ adap->tuner_pass_ctrl(fe,0,adap->pll_addr);
return ret;
}
EXPORT_SYMBOL(dvb_usb_tuner_init_i2c);
int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len)
{
- struct dvb_usb_device *d = fe->dvb->priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
if (buf_len != 5)
return -EINVAL;
- if (d->pll_desc == NULL)
+ if (adap->pll_desc == NULL)
return 0;
- deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
+ deb_pll("pll addr: %x, freq: %d %p\n",adap->pll_addr, fep->frequency, adap->pll_desc);
- b[0] = d->pll_addr;
- dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
+ b[0] = adap->pll_addr;
+ dvb_pll_configure(adap->pll_desc, &b[1], fep->frequency, fep->u.ofdm.bandwidth);
deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
@@ -99,26 +99,27 @@ EXPORT_SYMBOL(dvb_usb_tuner_calc_regs);
int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
{
- struct dvb_usb_device *d = fe->dvb->priv;
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
int ret = 0;
u8 b[5];
- struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
+ struct i2c_msg msg = { .addr = adap->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
dvb_usb_tuner_calc_regs(fe,fep,b,5);
- if (d->tuner_pass_ctrl)
- d->tuner_pass_ctrl(fe,1,d->pll_addr);
+ if (adap->tuner_pass_ctrl)
+ adap->tuner_pass_ctrl(fe, 1, adap->pll_addr);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
+
+ if (i2c_transfer(&adap->dev->i2c_adap, &msg, 1) != 1) {
err("tuner i2c write failed for pll_set.");
ret = -EREMOTEIO;
}
msleep(1);
- if (d->tuner_pass_ctrl)
- d->tuner_pass_ctrl(fe,0,d->pll_addr);
+ if (adap->tuner_pass_ctrl)
+ adap->tuner_pass_ctrl(fe, 0, adap->pll_addr);
return ret;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 95698918bc11..4d6b069536ce 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -10,51 +10,52 @@
#define _DVB_USB_IDS_H_
/* Vendor IDs */
-#define USB_VID_ADSTECH 0x06e1
-#define USB_VID_ANCHOR 0x0547
-#define USB_VID_WIDEVIEW 0x14aa
-#define USB_VID_AVERMEDIA 0x07ca
-#define USB_VID_COMPRO 0x185b
-#define USB_VID_COMPRO_UNK 0x145f
-#define USB_VID_CYPRESS 0x04b4
-#define USB_VID_DIBCOM 0x10b8
-#define USB_VID_DVICO 0x0fe9
-#define USB_VID_EMPIA 0xeb1a
-#define USB_VID_GRANDTEC 0x5032
-#define USB_VID_HANFTEK 0x15f4
-#define USB_VID_HAUPPAUGE 0x2040
-#define USB_VID_HYPER_PALTEK 0x1025
-#define USB_VID_KWORLD 0xeb2a
-#define USB_VID_KYE 0x0458
-#define USB_VID_MEDION 0x1660
-#define USB_VID_PINNACLE 0x2304
-#define USB_VID_VISIONPLUS 0x13d3
-#define USB_VID_TWINHAN 0x1822
-#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
-#define USB_VID_GENPIX 0x09c0
+#define USB_VID_ADSTECH 0x06e1
+#define USB_VID_ANCHOR 0x0547
+#define USB_VID_AVERMEDIA 0x07ca
+#define USB_VID_COMPRO 0x185b
+#define USB_VID_COMPRO_UNK 0x145f
+#define USB_VID_CYPRESS 0x04b4
+#define USB_VID_DIBCOM 0x10b8
+#define USB_VID_DVICO 0x0fe9
+#define USB_VID_EMPIA 0xeb1a
+#define USB_VID_GENPIX 0x09c0
+#define USB_VID_GRANDTEC 0x5032
+#define USB_VID_HANFTEK 0x15f4
+#define USB_VID_HAUPPAUGE 0x2040
+#define USB_VID_HYPER_PALTEK 0x1025
+#define USB_VID_KWORLD 0xeb2a
+#define USB_VID_KYE 0x0458
+#define USB_VID_LEADTEK 0x0413
+#define USB_VID_LITEON 0x04ca
+#define USB_VID_MEDION 0x1660
+#define USB_VID_PINNACLE 0x2304
+#define USB_VID_VISIONPLUS 0x13d3
+#define USB_VID_TWINHAN 0x1822
+#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+#define USB_VID_WIDEVIEW 0x14aa
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
#define USB_PID_ADSTECH_USB2_WARM 0xa334
-#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
-#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
-#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
-#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801
-#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
-#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
-#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
-#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
+#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
+#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
+#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801
+#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
+#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
+#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
+#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
#define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064
-#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
+#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065
#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
-#define USB_PID_DIBCOM_STK7700 0x1e14
-#define USB_PID_DIBCOM_STK7700_REENUM 0x1e15
-#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
-#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
-#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
+#define USB_PID_DIBCOM_STK7700P 0x1e14
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
+#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
@@ -69,25 +70,34 @@
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
-#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
-#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
-#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
-#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
-#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
-#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
-#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
-#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
+#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
+#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
+#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
+#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_WARM 0x810a
+#define USB_PID_ARTEC_T14_COLD 0x810b
+#define USB_PID_ARTEC_T14_WARM 0x810c
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
+#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
+#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
+#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
+#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
#define USB_PID_DTT200U_COLD 0x0201
#define USB_PID_DTT200U_WARM 0x0301
-#define USB_PID_WT220U_COLD 0x0222
-#define USB_PID_WT220U_WARM 0x0221
+#define USB_PID_WT220U_ZAP250_COLD 0x0220
+#define USB_PID_WT220U_COLD 0x0222
+#define USB_PID_WT220U_WARM 0x0221
+#define USB_PID_WT220U_FC_COLD 0x0225
+#define USB_PID_WT220U_FC_WARM 0x0226
#define USB_PID_WT220U_ZL0353_COLD 0x022a
#define USB_PID_WT220U_ZL0353_WARM 0x022b
-#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
-#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
+#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
+#define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941
+#define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050
+#define USB_PID_AVERMEDIA_VOLAR 0x1234
#define USB_PID_NEBULA_DIGITV 0x0201
#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD 0xd500
@@ -96,15 +106,26 @@
#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM 0xdb01
#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD 0xdb10
#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM 0xdb11
-#define USB_PID_DVICO_BLUEBIRD_DEE1601_COLD 0xdb50
-#define USB_PID_DVICO_BLUEBIRD_DEE1601_WARM 0xdb51
-#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_COLD 0xdb54
-#define USB_PID_DIGITALNOW_BLUEBIRD_DEE1601_WARM 0xdb55
+#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD 0xdb50
+#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM 0xdb51
+#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58
+#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM 0xdb55
#define USB_PID_MEDION_MD95700 0x0932
#define USB_PID_KYE_DVB_T_COLD 0x701e
#define USB_PID_KYE_DVB_T_WARM 0x701f
-#define USB_PID_PCTV_200E 0x020e
-#define USB_PID_PCTV_400E 0x020f
-#define USB_PID_GENPIX_8PSK_COLD 0x0200
-#define USB_PID_GENPIX_8PSK_WARM 0x0201
+#define USB_PID_PCTV_200E 0x020e
+#define USB_PID_PCTV_400E 0x020f
+#define USB_PID_LITEON_DVB_T_COLD 0xf000
+#define USB_PID_LITEON_DVB_T_WARM 0xf001
+#define USB_PID_DIGIVOX_MINI_SL_COLD 0xe360
+#define USB_PID_DIGIVOX_MINI_SL_WARM 0xe361
+#define USB_PID_GRANDTEC_DVBT_USB2_COLD 0x0bc6
+#define USB_PID_GRANDTEC_DVBT_USB2_WARM 0x0bc7
+#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
+#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
+#define USB_PID_GENPIX_8PSK_COLD 0x0200
+#define USB_PID_GENPIX_8PSK_WARM 0x0201
+
#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index a1705ecb9a54..ffdde83d1e77 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -3,7 +3,7 @@
*
* dvb-usb-init.c
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.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
@@ -16,21 +16,105 @@
/* debug */
int dvb_usb_debug;
module_param_named(debug,dvb_usb_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS);
int dvb_usb_disable_rc_polling;
module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
+static int dvb_usb_force_pid_filter_usage;
+module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
+MODULE_PARM_DESC(disable_rc_polling, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+
+static int dvb_usb_adapter_init(struct dvb_usb_device *d)
+{
+ struct dvb_usb_adapter *adap;
+ int ret,n;
+
+ for (n = 0; n < d->props.num_adapters; n++) {
+ adap = &d->adapter[n];
+ adap->dev = d;
+ adap->id = n;
+
+ memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
+
+/* speed - when running at FULL speed we need a HW PID filter */
+ if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
+ err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
+ return -ENODEV;
+ }
+
+ if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
+ (adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
+ info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
+ adap->pid_filtering = 1;
+ adap->max_feed_count = adap->props.pid_filter_count;
+ } else {
+ info("will pass the complete MPEG2 transport stream to the software demuxer.");
+ adap->pid_filtering = 0;
+ adap->max_feed_count = 255;
+ }
+
+ if (!adap->pid_filtering &&
+ dvb_usb_force_pid_filter_usage &&
+ adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) {
+ info("pid filter enabled by module option.");
+ adap->pid_filtering = 1;
+ adap->max_feed_count = adap->props.pid_filter_count;
+ }
+
+ if (adap->props.size_of_priv > 0) {
+ adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
+ if (adap->priv == NULL) {
+ err("no memory for priv for adapter %d.",n);
+ return -ENOMEM;
+ }
+ }
+
+ if ((ret = dvb_usb_adapter_stream_init(adap)) ||
+ (ret = dvb_usb_adapter_dvb_init(adap)) ||
+ (ret = dvb_usb_adapter_frontend_init(adap))) {
+ return ret;
+ }
+
+ d->num_adapters_initialized++;
+ d->state |= DVB_USB_STATE_DVB;
+ }
+
+ /*
+ * when reloading the driver w/o replugging the device
+ * sometimes a timeout occures, this helps
+ */
+ if (d->props.generic_bulk_ctrl_endpoint != 0) {
+ usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+ }
+
+ return 0;
+}
+
+static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
+{
+ int n;
+ for (n = 0; n < d->num_adapters_initialized; n++) {
+ dvb_usb_adapter_frontend_exit(&d->adapter[n]);
+ dvb_usb_adapter_dvb_exit(&d->adapter[n]);
+ dvb_usb_adapter_stream_exit(&d->adapter[n]);
+ kfree(d->adapter[n].priv);
+ }
+ d->num_adapters_initialized = 0;
+ d->state &= ~DVB_USB_STATE_DVB;
+ return 0;
+}
+
+
/* general initialization functions */
static int dvb_usb_exit(struct dvb_usb_device *d)
{
deb_info("state before exiting everything: %x\n",d->state);
dvb_usb_remote_exit(d);
- dvb_usb_fe_exit(d);
+ dvb_usb_adapter_exit(d);
dvb_usb_i2c_exit(d);
- dvb_usb_dvb_exit(d);
- dvb_usb_urb_exit(d);
deb_info("state should be zero now: %x\n",d->state);
d->state = DVB_USB_STATE_INIT;
kfree(d->priv);
@@ -47,32 +131,19 @@ static int dvb_usb_init(struct dvb_usb_device *d)
d->state = DVB_USB_STATE_INIT;
-/* check the capabilities and set appropriate variables */
-
-/* speed - when running at FULL speed we need a HW PID filter */
- if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) {
- err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
- return -ENODEV;
- }
-
- if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) ||
- (d->props.caps & DVB_USB_NEED_PID_FILTERING)) {
- info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count);
- d->pid_filtering = 1;
- d->max_feed_count = d->props.pid_filter_count;
- } else {
- info("will pass the complete MPEG2 transport stream to the software demuxer.");
- d->pid_filtering = 0;
- d->max_feed_count = 255;
+ if (d->props.size_of_priv > 0) {
+ d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
+ if (d->priv == NULL) {
+ err("no memory for priv in 'struct dvb_usb_device'");
+ return -ENOMEM;
+ }
}
- if (d->props.power_ctrl)
- d->props.power_ctrl(d,1);
+/* check the capabilities and set appropriate variables */
+ dvb_usb_device_power_ctrl(d, 1);
- if ((ret = dvb_usb_urb_init(d)) ||
- (ret = dvb_usb_dvb_init(d)) ||
- (ret = dvb_usb_i2c_init(d)) ||
- (ret = dvb_usb_fe_init(d))) {
+ if ((ret = dvb_usb_i2c_init(d)) ||
+ (ret = dvb_usb_adapter_init(d))) {
dvb_usb_exit(d);
return ret;
}
@@ -80,14 +151,13 @@ static int dvb_usb_init(struct dvb_usb_device *d)
if ((ret = dvb_usb_remote_init(d)))
err("could not initialize remote control.");
- if (d->props.power_ctrl)
- d->props.power_ctrl(d,0);
+ dvb_usb_device_power_ctrl(d, 0);
return 0;
}
/* determine the name and the state of the just found USB device */
-static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_properties *props, int *cold)
+static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
{
int i,j;
struct dvb_usb_device_description *desc = NULL;
@@ -125,11 +195,25 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
return desc;
}
+int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ if (onoff)
+ d->powered++;
+ else
+ d->powered--;
+
+ if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
+ deb_info("power control: %d\n", onoff);
+ if (d->props.power_ctrl)
+ return d->props.power_ctrl(d, onoff);
+ }
+ return 0;
+}
+
/*
* USB
*/
-
-int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
+int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_device_properties
*props, struct module *owner,struct dvb_usb_device **du)
{
struct usb_device *udev = interface_to_usbdev(intf);
@@ -149,7 +233,7 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
if (cold) {
info("found a '%s' in cold state, will try to load a firmware",desc->name);
ret = dvb_usb_download_firmware(udev,props);
- if (!props->no_reconnect)
+ if (!props->no_reconnect || ret != 0)
return ret;
}
@@ -161,19 +245,10 @@ int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties
}
d->udev = udev;
- memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+ memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
d->desc = desc;
d->owner = owner;
- if (d->props.size_of_priv > 0) {
- d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
- if (d->priv == NULL) {
- err("no memory for priv in 'struct dvb_usb_device'");
- kfree(d);
- return -ENOMEM;
- }
- }
-
usb_set_intfdata(intf, d);
if (du != NULL)
@@ -204,7 +279,7 @@ void dvb_usb_device_exit(struct usb_interface *intf)
}
EXPORT_SYMBOL(dvb_usb_device_exit);
-MODULE_VERSION("0.3");
+MODULE_VERSION("1.0");
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index e5c6d9835e06..0a3a0b6c2350 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -1,11 +1,12 @@
/* dvb-usb-remote.c is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * 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.
*/
#include "dvb-usb-common.h"
+#include <linux/usb/input.h>
/* Remote-control poll function - called every dib->rc_query_interval ms to see
* whether the remote control has received anything.
@@ -96,7 +97,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
return 0;
usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
- strlcpy(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
d->rc_input_dev = input_allocate_device();
if (!d->rc_input_dev)
@@ -107,6 +108,8 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
d->rc_input_dev->keycodemax = KEY_MAX;
d->rc_input_dev->name = "IR-receiver inside an USB DVB receiver";
d->rc_input_dev->phys = d->rc_phys;
+ usb_to_input_id(d->udev, &d->rc_input_dev->id);
+ d->rc_input_dev->cdev.dev = &d->udev->dev;
/* set the bits for the keys */
deb_rc("key map size: %d\n", d->props.rc_key_map_size);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
index 9002f35aa952..5cef12a07f72 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -1,9 +1,9 @@
/* dvb-usb-urb.c is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
- * This file contains functions for initializing and handling the
+ * This file keeps functions for initializing and handling the
* USB and URB stuff.
*/
#include "dvb-usb-common.h"
@@ -64,261 +64,32 @@ int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
}
EXPORT_SYMBOL(dvb_usb_generic_write);
-
-/* URB stuff for streaming */
-static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
-{
- struct dvb_usb_device *d = urb->context;
- int ptype = usb_pipetype(urb->pipe);
- int i;
- u8 *b;
-
- deb_ts("'%s' urb completed. feedcount: %d, status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
- ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", d->feedcount,
- urb->status,urb->actual_length,urb->transfer_buffer_length,
- urb->number_of_packets,urb->error_count);
-
- switch (urb->status) {
- case 0: /* success */
- case -ETIMEDOUT: /* NAK */
- break;
- case -ECONNRESET: /* kill */
- case -ENOENT:
- case -ESHUTDOWN:
- return;
- default: /* error */
- deb_ts("urb completition error %d.", urb->status);
- break;
- }
-
- if (d->feedcount > 0) {
- if (d->state & DVB_USB_STATE_DVB) {
- switch (ptype) {
- case PIPE_ISOCHRONOUS:
- b = (u8 *) urb->transfer_buffer;
- for (i = 0; i < urb->number_of_packets; i++) {
- if (urb->iso_frame_desc[i].status != 0)
- deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
- else if (urb->iso_frame_desc[i].actual_length > 0) {
- dvb_dmx_swfilter(&d->demux,b + urb->iso_frame_desc[i].offset,
- urb->iso_frame_desc[i].actual_length);
- }
- urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = 0;
- }
- debug_dump(b,20,deb_ts);
- break;
- case PIPE_BULK:
- if (urb->actual_length > 0)
- dvb_dmx_swfilter(&d->demux, (u8 *) urb->transfer_buffer,urb->actual_length);
- break;
- default:
- err("unkown endpoint type in completition handler.");
- return;
- }
- }
- }
-
- usb_submit_urb(urb,GFP_ATOMIC);
-}
-
-int dvb_usb_urb_kill(struct dvb_usb_device *d)
-{
- int i;
- for (i = 0; i < d->urbs_submitted; i++) {
- deb_ts("killing URB no. %d.\n",i);
-
- /* stop the URB */
- usb_kill_urb(d->urb_list[i]);
- }
- d->urbs_submitted = 0;
- return 0;
-}
-
-int dvb_usb_urb_submit(struct dvb_usb_device *d)
-{
- int i,ret;
- for (i = 0; i < d->urbs_initialized; i++) {
- deb_ts("submitting URB no. %d\n",i);
- if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) {
- err("could not submit URB no. %d - get them all back",i);
- dvb_usb_urb_kill(d);
- return ret;
- }
- d->urbs_submitted++;
- }
- return 0;
-}
-
-static int dvb_usb_free_stream_buffers(struct dvb_usb_device *d)
-{
- if (d->state & DVB_USB_STATE_URB_BUF) {
- while (d->buf_num) {
- d->buf_num--;
- deb_mem("freeing buffer %d\n",d->buf_num);
- usb_buffer_free(d->udev, d->buf_size,
- d->buf_list[d->buf_num], d->dma_addr[d->buf_num]);
- }
- kfree(d->buf_list);
- kfree(d->dma_addr);
- }
-
- d->state &= ~DVB_USB_STATE_URB_BUF;
-
- return 0;
-}
-
-static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, unsigned long size)
-{
- d->buf_num = 0;
- d->buf_size = size;
-
- deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
-
- if ((d->buf_list = kcalloc(num, sizeof(u8 *), GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- if ((d->dma_addr = kcalloc(num, sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) {
- kfree(d->buf_list);
- return -ENOMEM;
- }
-
- d->state |= DVB_USB_STATE_URB_BUF;
-
- for (d->buf_num = 0; d->buf_num < num; d->buf_num++) {
- deb_mem("allocating buffer %d\n",d->buf_num);
- if (( d->buf_list[d->buf_num] =
- usb_buffer_alloc(d->udev, size, SLAB_ATOMIC,
- &d->dma_addr[d->buf_num]) ) == NULL) {
- deb_mem("not enough memory for urb-buffer allocation.\n");
- dvb_usb_free_stream_buffers(d);
- return -ENOMEM;
- }
- deb_mem("buffer %d: %p (dma: %llu)\n",
- d->buf_num, d->buf_list[d->buf_num],
- (unsigned long long)d->dma_addr[d->buf_num]);
- memset(d->buf_list[d->buf_num],0,size);
- }
- deb_mem("allocation successful\n");
-
- return 0;
-}
-
-static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
+static void dvb_usb_data_complete(struct usb_data_stream *stream, u8 *buffer, size_t length)
{
- int i;
-
- if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
- d->props.urb.u.bulk.buffersize)) < 0)
- return i;
-
- /* allocate the URBs */
- for (i = 0; i < d->props.urb.count; i++) {
- if ((d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- usb_fill_bulk_urb( d->urb_list[i], d->udev,
- usb_rcvbulkpipe(d->udev,d->props.urb.endpoint),
- d->buf_list[i],
- d->props.urb.u.bulk.buffersize,
- dvb_usb_urb_complete, d);
-
- d->urb_list[i]->transfer_flags = 0;
- d->urbs_initialized++;
- }
- return 0;
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+ dvb_dmx_swfilter(&adap->demux, buffer, length);
}
-static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d)
+static void dvb_usb_data_complete_204(struct usb_data_stream *stream, u8 *buffer, size_t length)
{
- int i,j;
-
- if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
- d->props.urb.u.isoc.framesize*d->props.urb.u.isoc.framesperurb)) < 0)
- return i;
-
- /* allocate the URBs */
- for (i = 0; i < d->props.urb.count; i++) {
- struct urb *urb;
- int frame_offset = 0;
- if ((d->urb_list[i] =
- usb_alloc_urb(d->props.urb.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
- return -ENOMEM;
-
- urb = d->urb_list[i];
-
- urb->dev = d->udev;
- urb->context = d;
- urb->complete = dvb_usb_urb_complete;
- urb->pipe = usb_rcvisocpipe(d->udev,d->props.urb.endpoint);
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- urb->interval = d->props.urb.u.isoc.interval;
- urb->number_of_packets = d->props.urb.u.isoc.framesperurb;
- urb->transfer_buffer_length = d->buf_size;
- urb->transfer_buffer = d->buf_list[i];
- urb->transfer_dma = d->dma_addr[i];
-
- for (j = 0; j < d->props.urb.u.isoc.framesperurb; j++) {
- urb->iso_frame_desc[j].offset = frame_offset;
- urb->iso_frame_desc[j].length = d->props.urb.u.isoc.framesize;
- frame_offset += d->props.urb.u.isoc.framesize;
- }
-
- d->urbs_initialized++;
- }
- return 0;
-
+ struct dvb_usb_adapter *adap = stream->user_priv;
+ if (adap->feedcount > 0 && adap->state & DVB_USB_ADAP_STATE_DVB)
+ dvb_dmx_swfilter_204(&adap->demux, buffer, length);
}
-int dvb_usb_urb_init(struct dvb_usb_device *d)
+int dvb_usb_adapter_stream_init(struct dvb_usb_adapter *adap)
{
- /*
- * when reloading the driver w/o replugging the device
- * sometimes a timeout occures, this helps
- */
- if (d->props.generic_bulk_ctrl_endpoint != 0) {
- usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
- usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
- }
- usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.urb.endpoint));
-
- /* allocate the array for the data transfer URBs */
- d->urb_list = kzalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL);
- if (d->urb_list == NULL)
- return -ENOMEM;
- d->state |= DVB_USB_STATE_URB_LIST;
-
- switch (d->props.urb.type) {
- case DVB_USB_BULK:
- return dvb_usb_bulk_urb_init(d);
- case DVB_USB_ISOC:
- return dvb_usb_isoc_urb_init(d);
- default:
- err("unkown URB-type for data transfer.");
- return -EINVAL;
- }
+ adap->stream.udev = adap->dev->udev;
+ if (adap->props.caps & DVB_USB_ADAP_RECEIVES_204_BYTE_TS)
+ adap->stream.complete = dvb_usb_data_complete_204;
+ else
+ adap->stream.complete = dvb_usb_data_complete;
+ adap->stream.user_priv = adap;
+ return usb_urb_init(&adap->stream, &adap->props.stream);
}
-int dvb_usb_urb_exit(struct dvb_usb_device *d)
+int dvb_usb_adapter_stream_exit(struct dvb_usb_adapter *adap)
{
- int i;
-
- dvb_usb_urb_kill(d);
-
- if (d->state & DVB_USB_STATE_URB_LIST) {
- for (i = 0; i < d->urbs_initialized; i++) {
- if (d->urb_list[i] != NULL) {
- deb_mem("freeing URB no. %d.\n",i);
- /* free the URBs */
- usb_free_urb(d->urb_list[i]);
- }
- }
- d->urbs_initialized = 0;
- /* free the urb array */
- kfree(d->urb_list);
- d->state &= ~DVB_USB_STATE_URB_LIST;
- }
-
- dvb_usb_free_stream_buffers(d);
- return 0;
+ return usb_urb_exit(&adap->stream);
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 97f8ea962438..376c45a8e779 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -1,9 +1,11 @@
/* dvb-usb.h is part of the DVB USB library.
*
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
* see dvb-usb-init.c for copyright information.
*
* the headerfile, all dvb-usb-drivers have to include.
+ *
+ * TODO: clean-up the structures for unused fields and update the comments
*/
#ifndef __DVB_USB_H__
#define __DVB_USB_H__
@@ -84,36 +86,84 @@ struct dvb_usb_rc_key {
};
struct dvb_usb_device;
+struct dvb_usb_adapter;
+struct usb_data_stream;
+
+/**
+ * Properties of USB streaming - TODO this structure should be somewhere else
+ * describes the kind of USB transfer used for data-streaming.
+ * (BULK or ISOC)
+ */
+struct usb_data_stream_properties {
+#define USB_BULK 1
+#define USB_ISOC 2
+ int type;
+ int count;
+ int endpoint;
+
+ union {
+ struct {
+ int buffersize; /* per URB */
+ } bulk;
+ struct {
+ int framesperurb;
+ int framesize;
+ int interval;
+ } isoc;
+ } u;
+};
/**
- * struct dvb_usb_properties - properties of a dvb-usb-device
+ * struct dvb_usb_adapter_properties - properties of a dvb-usb-adapter.
+ * A DVB-USB-Adapter is basically a dvb_adapter which is present on a USB-device.
* @caps: capabilities of the DVB USB device.
* @pid_filter_count: number of PID filter position in the optional hardware
* PID-filter.
- *
+ * @streaming_crtl: called to start and stop the MPEG2-TS streaming of the
+ * device (not URB submitting/killing).
+ * @pid_filter_ctrl: called to en/disable the PID filter, if any.
+ * @pid_filter: called to set/unset a PID for filtering.
+ * @frontend_attach: called to attach the possible frontends (fill fe-field
+ * of struct dvb_usb_device).
+ * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
+ * pll_desc and pll_init_buf of struct dvb_usb_device).
+ * @stream: configuration of the USB streaming
+ */
+struct dvb_usb_adapter_properties {
+#define DVB_USB_ADAP_HAS_PID_FILTER 0x01
+#define DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_ADAP_NEED_PID_FILTERING 0x04
+#define DVB_USB_ADAP_RECEIVES_204_BYTE_TS 0x08
+ int caps;
+ int pid_filter_count;
+
+ int (*streaming_ctrl) (struct dvb_usb_adapter *, int);
+ int (*pid_filter_ctrl) (struct dvb_usb_adapter *, int);
+ int (*pid_filter) (struct dvb_usb_adapter *, int, u16, int);
+
+ int (*frontend_attach) (struct dvb_usb_adapter *);
+ int (*tuner_attach) (struct dvb_usb_adapter *);
+
+ struct usb_data_stream_properties stream;
+
+ int size_of_priv;
+};
+
+/**
+ * struct dvb_usb_device_properties - properties of a dvb-usb-device
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware
* download.
* @firmware: name of the firmware file.
* @download_firmware: called to download the firmware when the usb_ctrl is
* DEVICE_SPECIFIC.
* @no_reconnect: device doesn't do a reconnect after downloading the firmware,
- so do the warm initialization right after it
-
+ * so do the warm initialization right after it
+ *
* @size_of_priv: how many bytes shall be allocated for the private field
* of struct dvb_usb_device.
*
* @power_ctrl: called to enable/disable power of the device.
- * @streaming_crtl: called to start and stop the MPEG2-TS streaming of the
- * device (not URB submitting/killing).
- * @pid_filter_ctrl: called to en/disable the PID filter, if any.
- * @pid_filter: called to set/unset a PID for filtering.
- *
* @read_mac_address: called to read the MAC address of the device.
- *
- * @frontend_attach: called to attach the possible frontends (fill fe-field
- * of struct dvb_usb_device).
- * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
- * pll_desc and pll_init_buf of struct dvb_usb_device).
* @identify_state: called to determine the state (cold or warm), when it
* is not distinguishable by the USB IDs.
*
@@ -130,50 +180,40 @@ struct dvb_usb_device;
* is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
* helper functions.
*
- * @urb: describes the kind of USB transfer used for MPEG2-TS-streaming.
- * (BULK or ISOC)
- *
* @num_device_descs: number of struct dvb_usb_device_description in @devices
* @devices: array of struct dvb_usb_device_description compatibles with these
* properties.
*/
-struct dvb_usb_properties {
+#define MAX_NO_OF_ADAPTER_PER_DEVICE 2
+struct dvb_usb_device_properties {
-#define DVB_USB_HAS_PID_FILTER 0x01
-#define DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF 0x02
-#define DVB_USB_NEED_PID_FILTERING 0x04
-#define DVB_USB_IS_AN_I2C_ADAPTER 0x08
+#define DVB_USB_IS_AN_I2C_ADAPTER 0x01
int caps;
- int pid_filter_count;
#define DEVICE_SPECIFIC 0
#define CYPRESS_AN2135 1
#define CYPRESS_AN2235 2
#define CYPRESS_FX2 3
- int usb_ctrl;
+ int usb_ctrl;
+ int (*download_firmware) (struct usb_device *, const struct firmware *);
const char firmware[FIRMWARE_NAME_MAX];
- int (*download_firmware) (struct usb_device *, const struct firmware *);
- int no_reconnect;
+ int no_reconnect;
int size_of_priv;
- int (*power_ctrl) (struct dvb_usb_device *, int);
- int (*streaming_ctrl) (struct dvb_usb_device *, int);
- int (*pid_filter_ctrl) (struct dvb_usb_device *, int);
- int (*pid_filter) (struct dvb_usb_device *, int, u16, int);
+ int num_adapters;
+ struct dvb_usb_adapter_properties adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
+ int (*power_ctrl) (struct dvb_usb_device *, int);
int (*read_mac_address) (struct dvb_usb_device *, u8 []);
- int (*frontend_attach) (struct dvb_usb_device *);
- int (*tuner_attach) (struct dvb_usb_device *);
-
- int (*identify_state) (struct usb_device *, struct dvb_usb_properties *,
+ int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *,
struct dvb_usb_device_description **, int *);
/* remote control properties */
#define REMOTE_NO_KEY_PRESSED 0x00
#define REMOTE_KEY_PRESSED 0x01
#define REMOTE_KEY_REPEAT 0x02
- struct dvb_usb_rc_key *rc_key_map;
+ struct dvb_usb_rc_key *rc_key_map;
int rc_key_map_size;
int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
int rc_interval;
@@ -182,40 +222,12 @@ struct dvb_usb_properties {
int generic_bulk_ctrl_endpoint;
- struct {
-#define DVB_USB_BULK 1
-#define DVB_USB_ISOC 2
- int type;
- int count;
- int endpoint;
-
- union {
- struct {
- int buffersize; /* per URB */
- } bulk;
- struct {
- int framesperurb;
- int framesize;
- int interval;
- } isoc;
- } u;
- } urb;
-
int num_device_descs;
struct dvb_usb_device_description devices[9];
};
-
/**
- * struct dvb_usb_device - object of a DVB USB device
- * @props: copy of the struct dvb_usb_properties this device belongs to.
- * @desc: pointer to the device's struct dvb_usb_device_description.
- * @state: initialization and runtime state of the device.
- *
- * @udev: pointer to the device's struct usb_device.
- * @urb_list: array of dynamically allocated struct urb for the MPEG2-TS-
- * streaming.
- *
+ * struct usb_data_stream - generic object of an USB stream
* @buf_num: number of buffer allocated.
* @buf_size: size of each buffer in buf_list.
* @buf_list: array containing all allocate buffers for streaming.
@@ -223,18 +235,40 @@ struct dvb_usb_properties {
*
* @urbs_initialized: number of URBs initialized.
* @urbs_submitted: number of URBs submitted.
+ */
+#define MAX_NO_URBS_FOR_DATA_STREAM 10
+struct usb_data_stream {
+ struct usb_device *udev;
+ struct usb_data_stream_properties props;
+
+#define USB_STATE_INIT 0x00
+#define USB_STATE_URB_BUF 0x01
+ int state;
+
+ void (*complete) (struct usb_data_stream *, u8 *, size_t);
+
+ struct urb *urb_list[MAX_NO_URBS_FOR_DATA_STREAM];
+ int buf_num;
+ unsigned long buf_size;
+ u8 *buf_list[MAX_NO_URBS_FOR_DATA_STREAM];
+ dma_addr_t dma_addr[MAX_NO_URBS_FOR_DATA_STREAM];
+
+ int urbs_initialized;
+ int urbs_submitted;
+
+ void *user_priv;
+};
+
+/**
+ * struct dvb_usb_adapter - a DVB adapter on a USB device
+ * @id: index of this adapter (starting with 0).
*
* @feedcount: number of reqested feeds (used for streaming-activation)
* @pid_filtering: is hardware pid_filtering used or not.
*
- * @usb_mutex: semaphore of USB control messages (reading needs two messages)
- * @i2c_mutex: semaphore for i2c-transfers
- *
- * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
* @pll_addr: I2C address of the tuner for programming
* @pll_init: array containing the initialization buffer
* @pll_desc: pointer to the appropriate struct dvb_pll_desc
- *
* @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
*
* @dvb_adap: device's dvb_adapter.
@@ -244,8 +278,62 @@ struct dvb_usb_properties {
* @dvb_frontend: device's frontend.
* @max_feed_count: how many feeds can be handled simultaneously by this
* device
+ *
+ * @fe_init: rerouted frontend-init (wakeup) function.
* @fe_sleep: rerouted frontend-sleep function.
- * @fe_init: rerouted frontend-init (wakeup) function.
+ *
+ * @stream: the usb data stream.
+ */
+struct dvb_usb_adapter {
+ struct dvb_usb_device *dev;
+ struct dvb_usb_adapter_properties props;
+
+#define DVB_USB_ADAP_STATE_INIT 0x000
+#define DVB_USB_ADAP_STATE_DVB 0x001
+ int state;
+
+ u8 id;
+
+ int feedcount;
+ int pid_filtering;
+
+ /* tuner programming information */
+ u8 pll_addr;
+ u8 pll_init[4];
+ struct dvb_pll_desc *pll_desc;
+ int (*tuner_pass_ctrl) (struct dvb_frontend *, int, u8);
+
+ /* dvb */
+ struct dvb_adapter dvb_adap;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net dvb_net;
+ struct dvb_frontend *fe;
+ int max_feed_count;
+
+ int (*fe_init) (struct dvb_frontend *);
+ int (*fe_sleep) (struct dvb_frontend *);
+
+ struct usb_data_stream stream;
+
+ void *priv;
+};
+
+/**
+ * struct dvb_usb_device - object of a DVB USB device
+ * @props: copy of the struct dvb_usb_properties this device belongs to.
+ * @desc: pointer to the device's struct dvb_usb_device_description.
+ * @state: initialization and runtime state of the device.
+ *
+ * @powered: indicated whether the device is power or not.
+ * Powered is in/decremented for each call to modify the state.
+ * @udev: pointer to the device's struct usb_device.
+ *
+ * @usb_mutex: semaphore of USB control messages (reading needs two messages)
+ * @i2c_mutex: semaphore for i2c-transfers
+ *
+ * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
+ *
* @rc_input_dev: input device for the remote control.
* @rc_query_work: struct work_struct frequent rc queries
* @last_event: last triggered event
@@ -255,32 +343,18 @@ struct dvb_usb_properties {
* in size_of_priv of dvb_usb_properties).
*/
struct dvb_usb_device {
- struct dvb_usb_properties props;
+ struct dvb_usb_device_properties props;
struct dvb_usb_device_description *desc;
-#define DVB_USB_STATE_INIT 0x000
-#define DVB_USB_STATE_URB_LIST 0x001
-#define DVB_USB_STATE_URB_BUF 0x002
-#define DVB_USB_STATE_DVB 0x004
-#define DVB_USB_STATE_I2C 0x008
-#define DVB_USB_STATE_REMOTE 0x010
-#define DVB_USB_STATE_URB_SUBMIT 0x020
- int state;
-
- /* usb */
struct usb_device *udev;
- struct urb **urb_list;
- int buf_num;
- unsigned long buf_size;
- u8 **buf_list;
- dma_addr_t *dma_addr;
-
- int urbs_initialized;
- int urbs_submitted;
+#define DVB_USB_STATE_INIT 0x000
+#define DVB_USB_STATE_I2C 0x001
+#define DVB_USB_STATE_DVB 0x002
+#define DVB_USB_STATE_REMOTE 0x004
+ int state;
- int feedcount;
- int pid_filtering;
+ int powered;
/* locking */
struct mutex usb_mutex;
@@ -289,22 +363,8 @@ struct dvb_usb_device {
struct mutex i2c_mutex;
struct i2c_adapter i2c_adap;
- /* tuner programming information */
- u8 pll_addr;
- u8 pll_init[4];
- struct dvb_pll_desc *pll_desc;
- int (*tuner_pass_ctrl)(struct dvb_frontend *, int, u8);
-
- /* dvb */
- struct dvb_adapter dvb_adap;
- struct dmxdev dmxdev;
- struct dvb_demux demux;
- struct dvb_net dvb_net;
- struct dvb_frontend* fe;
- int max_feed_count;
-
- int (*fe_sleep) (struct dvb_frontend *);
- int (*fe_init) (struct dvb_frontend *);
+ int num_adapters_initialized;
+ struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
/* remote control */
struct input_dev *rc_input_dev;
@@ -318,7 +378,7 @@ struct dvb_usb_device {
void *priv;
};
-extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *, struct dvb_usb_device **);
+extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_device_properties *, struct module *, struct dvb_usb_device **);
extern void dvb_usb_device_exit(struct usb_interface *);
/* the generic read/write method for device control */
@@ -342,5 +402,7 @@ struct hexline {
u8 chk;
};
extern int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw, int type);
+extern int dvb_usb_get_hexline(const struct firmware *fw, struct hexline *hx, int *pos);
+
#endif
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 9a98f3fdae31..7375eb20166d 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -161,19 +161,18 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
}
-static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+static int gp8psk_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
{
- return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0);
+ return gp8psk_usb_out_op(adap->dev, ARM_TRANSFER, onoff, 0 , NULL, 0);
}
-static int gp8psk_frontend_attach(struct dvb_usb_device *d)
+static int gp8psk_frontend_attach(struct dvb_usb_adapter *adap)
{
- d->fe = gp8psk_fe_attach(d);
-
+ adap->fe = gp8psk_fe_attach(adap->dev);
return 0;
}
-static struct dvb_usb_properties gp8psk_properties;
+static struct dvb_usb_device_properties gp8psk_properties;
static int gp8psk_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -188,20 +187,18 @@ static struct usb_device_id gp8psk_usb_table [] = {
};
MODULE_DEVICE_TABLE(usb, gp8psk_usb_table);
-static struct dvb_usb_properties gp8psk_properties = {
- .caps = 0,
-
+static struct dvb_usb_device_properties gp8psk_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-gp8psk-01.fw",
+ .num_adapters = 1,
+ .adapter = {
+ {
.streaming_ctrl = gp8psk_streaming_ctrl,
- .power_ctrl = gp8psk_power_ctrl,
.frontend_attach = gp8psk_frontend_attach,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x82,
.u = {
@@ -210,6 +207,11 @@ static struct dvb_usb_properties gp8psk_properties = {
}
}
},
+ }
+ },
+ .power_ctrl = gp8psk_power_ctrl,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
.devices = {
@@ -217,7 +219,7 @@ static struct dvb_usb_properties gp8psk_properties = {
.cold_ids = { &gp8psk_usb_table[0], NULL },
.warm_ids = { &gp8psk_usb_table[1], NULL },
},
- { 0 },
+ { NULL },
}
};
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index 412039d8dbae..a58874c790b2 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -75,7 +75,7 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
u16 raw;
int i;
- struct dibusb_state *st = d->priv;
+ struct dibusb_device_state *st = d->priv;
dvb_usb_generic_rw(d,cmd,2,key,5,0);
@@ -135,7 +135,7 @@ static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
}
/* USB Driver stuff */
-static struct dvb_usb_properties nova_t_properties;
+static struct dvb_usb_device_properties nova_t_properties;
static int nova_t_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -151,34 +151,27 @@ static struct usb_device_id nova_t_table [] = {
};
MODULE_DEVICE_TABLE(usb, nova_t_table);
-static struct dvb_usb_properties nova_t_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
- .pid_filter_count = 32,
+static struct dvb_usb_device_properties nova_t_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
- .firmware = "dvb-usb-nova-t-usb2-01.fw",
+ .firmware = "dvb-usb-nova-t-usb2-02.fw",
- .size_of_priv = sizeof(struct dibusb_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
.streaming_ctrl = dibusb2_0_streaming_ctrl,
.pid_filter = dibusb_pid_filter,
.pid_filter_ctrl = dibusb_pid_filter_ctrl,
- .power_ctrl = dibusb2_0_power_ctrl,
.frontend_attach = dibusb_dib3000mc_frontend_attach,
.tuner_attach = dibusb_dib3000mc_tuner_attach,
- .read_mac_address = nova_t_read_mac_address,
-
- .rc_interval = 100,
- .rc_key_map = haupp_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(haupp_rc_keys),
- .rc_query = nova_t_rc_query,
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x06,
.u = {
@@ -188,6 +181,23 @@ static struct dvb_usb_properties nova_t_properties = {
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ }
+ },
+ .size_of_priv = sizeof(struct dibusb_device_state),
+
+ .power_ctrl = dibusb2_0_power_ctrl,
+ .read_mac_address = nova_t_read_mac_address,
+
+ .rc_interval = 100,
+ .rc_key_map = haupp_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(haupp_rc_keys),
+ .rc_query = nova_t_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
.num_device_descs = 1,
.devices = {
{ "Hauppauge WinTV-NOVA-T usb2",
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
index 97d74da0dad8..f9941ea88b3e 100644
--- a/drivers/media/dvb/dvb-usb/umt-010.c
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -50,7 +50,7 @@ static int umt_mt352_demod_init(struct dvb_frontend *fe)
return 0;
}
-static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
+static int umt_mt352_frontend_attach(struct dvb_usb_adapter *adap)
{
struct mt352_config umt_config;
@@ -58,21 +58,21 @@ static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
umt_config.demod_init = umt_mt352_demod_init;
umt_config.demod_address = 0xf;
- d->fe = mt352_attach(&umt_config, &d->i2c_adap);
+ adap->fe = dvb_attach(mt352_attach, &umt_config, &adap->dev->i2c_adap);
return 0;
}
-static int umt_tuner_attach (struct dvb_usb_device *d)
+static int umt_tuner_attach (struct dvb_usb_adapter *adap)
{
- d->pll_addr = 0x61;
- d->pll_desc = &dvb_pll_tua6034;
- d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
+ adap->pll_addr = 0x61;
+ adap->pll_desc = &dvb_pll_tua6034;
+ adap->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs;
return 0;
}
/* USB Driver stuff */
-static struct dvb_usb_properties umt_properties;
+static struct dvb_usb_device_properties umt_properties;
static int umt_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -90,25 +90,22 @@ static struct usb_device_id umt_table [] = {
};
MODULE_DEVICE_TABLE (usb, umt_table);
-static struct dvb_usb_properties umt_properties = {
+static struct dvb_usb_device_properties umt_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-umt-010-02.fw",
- .size_of_priv = sizeof(struct dibusb_state),
-
+ .num_adapters = 1,
+ .adapter = {
+ {
.streaming_ctrl = dibusb2_0_streaming_ctrl,
- .power_ctrl = dibusb_power_ctrl,
.frontend_attach = umt_mt352_frontend_attach,
.tuner_attach = umt_tuner_attach,
- .i2c_algo = &dibusb_i2c_algo,
-
- .generic_bulk_ctrl_endpoint = 0x01,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 20,
.endpoint = 0x06,
.u = {
@@ -118,6 +115,15 @@ static struct dvb_usb_properties umt_properties = {
}
},
+ .size_of_priv = sizeof(struct dibusb_state),
+ }
+ },
+ .power_ctrl = dibusb_power_ctrl,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
.num_device_descs = 1,
.devices = {
{ "Hanftek UMT-010 DVB-T USB2.0",
diff --git a/drivers/media/dvb/dvb-usb/usb-urb.c b/drivers/media/dvb/dvb-usb/usb-urb.c
new file mode 100644
index 000000000000..78035ee824ca
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/usb-urb.c
@@ -0,0 +1,243 @@
+/* usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-6 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file keeps functions for initializing and handling the
+ * BULK and ISOC USB data transfers in a generic way.
+ * Can be used for DVB-only and also, that's the plan, for
+ * Hybrid USB devices (analog and DVB).
+ */
+#include "dvb-usb-common.h"
+
+/* URB stuff for streaming */
+static void usb_urb_complete(struct urb *urb)
+{
+ struct usb_data_stream *stream = urb->context;
+ int ptype = usb_pipetype(urb->pipe);
+ int i;
+ u8 *b;
+
+ deb_uxfer("'%s' urb completed. status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
+ ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk",
+ urb->status,urb->actual_length,urb->transfer_buffer_length,
+ urb->number_of_packets,urb->error_count);
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ deb_ts("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ b = (u8 *) urb->transfer_buffer;
+ switch (ptype) {
+ case PIPE_ISOCHRONOUS:
+ for (i = 0; i < urb->number_of_packets; i++) {
+
+ if (urb->iso_frame_desc[i].status != 0)
+ deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
+ else if (urb->iso_frame_desc[i].actual_length > 0)
+ stream->complete(stream, b + urb->iso_frame_desc[i].offset, urb->iso_frame_desc[i].actual_length);
+
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ debug_dump(b,20,deb_uxfer);
+ break;
+ case PIPE_BULK:
+ if (urb->actual_length > 0)
+ stream->complete(stream, b, urb->actual_length);
+ break;
+ default:
+ err("unkown endpoint type in completition handler.");
+ return;
+ }
+ usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+int usb_urb_kill(struct usb_data_stream *stream)
+{
+ int i;
+ for (i = 0; i < stream->urbs_submitted; i++) {
+ deb_ts("killing URB no. %d.\n",i);
+
+ /* stop the URB */
+ usb_kill_urb(stream->urb_list[i]);
+ }
+ stream->urbs_submitted = 0;
+ return 0;
+}
+
+int usb_urb_submit(struct usb_data_stream *stream)
+{
+ int i,ret;
+ for (i = 0; i < stream->urbs_initialized; i++) {
+ deb_ts("submitting URB no. %d\n",i);
+ if ((ret = usb_submit_urb(stream->urb_list[i],GFP_ATOMIC))) {
+ err("could not submit URB no. %d - get them all back",i);
+ usb_urb_kill(stream);
+ return ret;
+ }
+ stream->urbs_submitted++;
+ }
+ return 0;
+}
+
+static int usb_free_stream_buffers(struct usb_data_stream *stream)
+{
+ if (stream->state & USB_STATE_URB_BUF) {
+ while (stream->buf_num) {
+ stream->buf_num--;
+ deb_mem("freeing buffer %d\n",stream->buf_num);
+ usb_buffer_free(stream->udev, stream->buf_size,
+ stream->buf_list[stream->buf_num], stream->dma_addr[stream->buf_num]);
+ }
+ }
+
+ stream->state &= ~USB_STATE_URB_BUF;
+
+ return 0;
+}
+
+static int usb_allocate_stream_buffers(struct usb_data_stream *stream, int num, unsigned long size)
+{
+ stream->buf_num = 0;
+ stream->buf_size = size;
+
+ deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
+
+ for (stream->buf_num = 0; stream->buf_num < num; stream->buf_num++) {
+ deb_mem("allocating buffer %d\n",stream->buf_num);
+ if (( stream->buf_list[stream->buf_num] =
+ usb_buffer_alloc(stream->udev, size, SLAB_ATOMIC,
+ &stream->dma_addr[stream->buf_num]) ) == NULL) {
+ deb_mem("not enough memory for urb-buffer allocation.\n");
+ usb_free_stream_buffers(stream);
+ return -ENOMEM;
+ }
+ deb_mem("buffer %d: %p (dma: %Lu)\n",
+ stream->buf_num,
+stream->buf_list[stream->buf_num], (long long)stream->dma_addr[stream->buf_num]);
+ memset(stream->buf_list[stream->buf_num],0,size);
+ stream->state |= USB_STATE_URB_BUF;
+ }
+ deb_mem("allocation successful\n");
+
+ return 0;
+}
+
+static int usb_bulk_urb_init(struct usb_data_stream *stream)
+{
+ int i;
+
+ if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
+ stream->props.u.bulk.buffersize)) < 0)
+ return i;
+
+ /* allocate the URBs */
+ for (i = 0; i < stream->props.count; i++) {
+ if ((stream->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ usb_fill_bulk_urb( stream->urb_list[i], stream->udev,
+ usb_rcvbulkpipe(stream->udev,stream->props.endpoint),
+ stream->buf_list[i],
+ stream->props.u.bulk.buffersize,
+ usb_urb_complete, stream);
+
+ stream->urb_list[i]->transfer_flags = 0;
+ stream->urbs_initialized++;
+ }
+ return 0;
+}
+
+static int usb_isoc_urb_init(struct usb_data_stream *stream)
+{
+ int i,j;
+
+ if ((i = usb_allocate_stream_buffers(stream,stream->props.count,
+ stream->props.u.isoc.framesize*stream->props.u.isoc.framesperurb)) < 0)
+ return i;
+
+ /* allocate the URBs */
+ for (i = 0; i < stream->props.count; i++) {
+ struct urb *urb;
+ int frame_offset = 0;
+ if ((stream->urb_list[i] =
+ usb_alloc_urb(stream->props.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ urb = stream->urb_list[i];
+
+ urb->dev = stream->udev;
+ urb->context = stream;
+ urb->complete = usb_urb_complete;
+ urb->pipe = usb_rcvisocpipe(stream->udev,stream->props.endpoint);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = stream->props.u.isoc.interval;
+ urb->number_of_packets = stream->props.u.isoc.framesperurb;
+ urb->transfer_buffer_length = stream->buf_size;
+ urb->transfer_buffer = stream->buf_list[i];
+ urb->transfer_dma = stream->dma_addr[i];
+
+ for (j = 0; j < stream->props.u.isoc.framesperurb; j++) {
+ urb->iso_frame_desc[j].offset = frame_offset;
+ urb->iso_frame_desc[j].length = stream->props.u.isoc.framesize;
+ frame_offset += stream->props.u.isoc.framesize;
+ }
+
+ stream->urbs_initialized++;
+ }
+ return 0;
+}
+
+int usb_urb_init(struct usb_data_stream *stream, struct usb_data_stream_properties *props)
+{
+ if (stream == NULL || props == NULL)
+ return -EINVAL;
+
+ memcpy(&stream->props, props, sizeof(*props));
+
+ usb_clear_halt(stream->udev,usb_rcvbulkpipe(stream->udev,stream->props.endpoint));
+
+ if (stream->complete == NULL) {
+ err("there is no data callback - this doesn't make sense.");
+ return -EINVAL;
+ }
+
+ switch (stream->props.type) {
+ case USB_BULK:
+ return usb_bulk_urb_init(stream);
+ case USB_ISOC:
+ return usb_isoc_urb_init(stream);
+ default:
+ err("unkown URB-type for data transfer.");
+ return -EINVAL;
+ }
+}
+
+int usb_urb_exit(struct usb_data_stream *stream)
+{
+ int i;
+
+ usb_urb_kill(stream);
+
+ for (i = 0; i < stream->urbs_initialized; i++) {
+ if (stream->urb_list[i] != NULL) {
+ deb_mem("freeing URB no. %d.\n",i);
+ /* free the URBs */
+ usb_free_urb(stream->urb_list[i]);
+ }
+ }
+ stream->urbs_initialized = 0;
+
+ usb_free_stream_buffers(stream);
+ return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c
index d4da494132ec..3ecb2e0ce80f 100644
--- a/drivers/media/dvb/dvb-usb/vp702x-fe.c
+++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c
@@ -24,6 +24,8 @@ struct vp702x_fe_state {
struct dvb_frontend fe;
struct dvb_usb_device *d;
+ struct dvb_frontend_ops ops;
+
fe_sec_voltage_t voltage;
fe_sec_tone_mode_t tone_mode;
@@ -72,9 +74,6 @@ static int vp702x_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
else
*status = 0;
- deb_fe("real state: %x\n",*status);
- *status = 0x1f;
-
if (*status & FE_HAS_LOCK)
st->status_check_interval = 1000;
else
@@ -171,8 +170,6 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
st->status_check_interval = 250;
st->next_status_check = jiffies;
- vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
- msleep(30);
vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
if (ibuf[2] == 0 && ibuf[3] == 0)
@@ -183,6 +180,20 @@ static int vp702x_fe_set_frontend(struct dvb_frontend* fe,
return 0;
}
+static int vp702x_fe_init(struct dvb_frontend *fe)
+{
+ struct vp702x_fe_state *st = fe->demodulator_priv;
+ deb_fe("%s\n",__FUNCTION__);
+ vp702x_usb_in_op(st->d, RESET_TUNER, 0, 0, NULL, 0);
+ return 0;
+}
+
+static int vp702x_fe_sleep(struct dvb_frontend *fe)
+{
+ deb_fe("%s\n",__FUNCTION__);
+ return 0;
+}
+
static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
@@ -193,8 +204,8 @@ static int vp702x_fe_get_frontend(struct dvb_frontend* fe,
static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
struct dvb_diseqc_master_cmd *m)
{
- struct vp702x_fe_state *st = fe->demodulator_priv;
- u8 cmd[8],ibuf[10];
+ //struct vp702x_fe_state *st = fe->demodulator_priv;
+ u8 cmd[8];//,ibuf[10];
memset(cmd,0,8);
deb_fe("%s\n",__FUNCTION__);
@@ -207,12 +218,12 @@ static int vp702x_fe_send_diseqc_msg (struct dvb_frontend* fe,
memcpy(&cmd[3], m->msg, m->msg_len);
cmd[7] = vp702x_chksum(cmd,0,7);
- vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
+// vp702x_usb_inout_op(st->d,cmd,8,ibuf,10,100);
- if (ibuf[2] == 0 && ibuf[3] == 0)
- deb_fe("diseqc cmd failed.\n");
- else
- deb_fe("diseqc cmd succeeded.\n");
+// if (ibuf[2] == 0 && ibuf[3] == 0)
+// deb_fe("diseqc cmd failed.\n");
+// else
+// deb_fe("diseqc cmd succeeded.\n");
return 0;
}
@@ -318,8 +329,8 @@ static struct dvb_frontend_ops vp702x_fe_ops = {
},
.release = vp702x_fe_release,
- .init = NULL,
- .sleep = NULL,
+ .init = vp702x_fe_init,
+ .sleep = vp702x_fe_sleep,
.set_frontend = vp702x_fe_set_frontend,
.get_frontend = vp702x_fe_get_frontend,
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index b2f098a2d5f7..02bd61aaac66 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -22,50 +22,54 @@ module_param_named(debug,dvb_usb_vp702x_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
struct vp702x_state {
- u8 pid_table[17]; /* [16] controls the pid_table state */
+ int pid_filter_count;
+ int pid_filter_can_bypass;
+ u8 pid_filter_state;
+};
+
+struct vp702x_device_state {
+ u8 power_state;
};
/* check for mutex FIXME */
int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
{
- int ret = 0,try = 0;
+ int ret = -1;
- while (ret >= 0 && ret != blen && try < 3) {
ret = usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev,0),
req,
USB_TYPE_VENDOR | USB_DIR_IN,
value,index,b,blen,
2000);
- deb_info("reading number %d (ret: %d)\n",try,ret);
- try++;
- }
- if (ret < 0 || ret != blen) {
- warn("usb in operation failed.");
+ if (ret < 0) {
+ warn("usb in operation failed. (%d)", ret);
ret = -EIO;
} else
ret = 0;
- deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+
+ deb_xfer("in: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
debug_dump(b,blen,deb_xfer);
return ret;
}
-static int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
+int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value,
u16 index, u8 *b, int blen)
{
- deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index);
+ int ret;
+ deb_xfer("out: req. %02x, val: %04x, ind: %04x, buffer: ",req,value,index);
debug_dump(b,blen,deb_xfer);
- if (usb_control_msg(d->udev,
+ if ((ret = usb_control_msg(d->udev,
usb_sndctrlpipe(d->udev,0),
req,
USB_TYPE_VENDOR | USB_DIR_OUT,
value,index,b,blen,
- 2000) != blen) {
- warn("usb out operation failed.");
+ 2000)) != blen) {
+ warn("usb out operation failed. (%d)",ret);
return -EIO;
} else
return 0;
@@ -78,12 +82,10 @@ int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int il
if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
return ret;
- if ((ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen)) < 0)
- goto unlock;
+ ret = vp702x_usb_out_op(d,REQUEST_OUT,0,0,o,olen);
msleep(msec);
ret = vp702x_usb_in_op(d,REQUEST_IN,0,0,i,ilen);
-unlock:
mutex_unlock(&d->usb_mutex);
return ret;
@@ -108,29 +110,65 @@ static int vp702x_usb_inout_cmd(struct dvb_usb_device *d, u8 cmd, u8 *o,
return ret;
}
-static int vp702x_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
+static int vp702x_set_pld_mode(struct dvb_usb_adapter *adap, u8 bypass)
+{
+ u8 buf[16] = { 0 };
+ return vp702x_usb_in_op(adap->dev, 0xe0, (bypass << 8) | 0x0e, 0, buf, 16);
+}
+
+static int vp702x_set_pld_state(struct dvb_usb_adapter *adap, u8 state)
+{
+ u8 buf[16] = { 0 };
+ return vp702x_usb_in_op(adap->dev, 0xe0, (state << 8) | 0x0f, 0, buf, 16);
+}
+
+static int vp702x_set_pid(struct dvb_usb_adapter *adap, u16 pid, u8 id, int onoff)
{
- struct vp702x_state *st = d->priv;
- u8 buf[9];
-
- if (onoff) {
- st->pid_table[16] |= 1 << index;
- st->pid_table[index*2] = (pid >> 8) & 0xff;
- st->pid_table[index*2+1] = pid & 0xff;
- } else {
- st->pid_table[16] &= ~(1 << index);
- st->pid_table[index*2] = st->pid_table[index*2+1] = 0;
+ struct vp702x_state *st = adap->priv;
+ u8 buf[16] = { 0 };
+
+ if (onoff)
+ st->pid_filter_state |= (1 << id);
+ else {
+ st->pid_filter_state &= ~(1 << id);
+ pid = 0xffff;
}
- return vp702x_usb_inout_cmd(d,SET_PID_FILTER,st->pid_table,17,buf,9,10);
+ id = 0x10 + id*2;
+
+ vp702x_set_pld_state(adap, st->pid_filter_state);
+ vp702x_usb_in_op(adap->dev, 0xe0, (((pid >> 8) & 0xff) << 8) | (id), 0, buf, 16);
+ vp702x_usb_in_op(adap->dev, 0xe0, (((pid ) & 0xff) << 8) | (id+1), 0, buf, 16);
+ return 0;
}
-static int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
+
+static int vp702x_init_pid_filter(struct dvb_usb_adapter *adap)
{
- vp702x_usb_in_op(d,RESET_TUNER,0,0,NULL,0);
+ struct vp702x_state *st = adap->priv;
+ int i;
+ u8 b[10] = { 0 };
+
+ st->pid_filter_count = 8;
+ st->pid_filter_can_bypass = 1;
+ st->pid_filter_state = 0x00;
+
+ vp702x_set_pld_mode(adap, 1); // bypass
+
+ for (i = 0; i < st->pid_filter_count; i++)
+ vp702x_set_pid(adap, 0xffff, i, 1);
- vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0);
- return vp702x_usb_in_op(d,SET_TUNER_POWER_REQ,0,onoff,NULL,0);
+ vp702x_usb_in_op(adap->dev, 0xb5, 3, 0, b, 10);
+ vp702x_usb_in_op(adap->dev, 0xb5, 0, 0, b, 10);
+ vp702x_usb_in_op(adap->dev, 0xb5, 1, 0, b, 10);
+
+ //vp702x_set_pld_mode(d, 0); // filter
+ return 0;
+}
+
+static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ return 0;
}
/* keys for the enclosed remote control */
@@ -166,74 +204,83 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
+int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ struct vp702x_device_state *st = d->priv;
+
+ if (st->power_state == 0 && onoff)
+ vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
+ else if (st->power_state == 1 && onoff == 0)
+ vp702x_usb_out_op(d, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
+
+ st->power_state = onoff;
+
+ return 0;
+}
+
static int vp702x_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
{
- u8 macb[9];
- if (vp702x_usb_inout_cmd(d, GET_MAC_ADDRESS, NULL, 0, macb, 9, 10))
- return -EIO;
- memcpy(mac,&macb[3],6);
+ u8 i;
+ for (i = 6; i < 12; i++)
+ vp702x_usb_in_op(d, READ_EEPROM_REQ, i, 1, &mac[i - 6], 1);
return 0;
}
-static int vp702x_frontend_attach(struct dvb_usb_device *d)
+static int vp702x_frontend_attach(struct dvb_usb_adapter *adap)
{
- u8 buf[9] = { 0 };
+ u8 buf[10] = { 0 };
+
+ vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 0, 7, NULL, 0);
- if (vp702x_usb_inout_cmd(d, GET_SYSTEM_STRING, NULL, 0, buf, 9, 10))
+ if (vp702x_usb_inout_cmd(adap->dev, GET_SYSTEM_STRING, NULL, 0, buf, 10, 10))
return -EIO;
- buf[8] = '\0';
+ buf[9] = '\0';
info("system string: %s",&buf[1]);
- d->fe = vp702x_fe_attach(d);
+ vp702x_init_pid_filter(adap);
+
+ adap->fe = vp702x_fe_attach(adap->dev);
+ vp702x_usb_out_op(adap->dev, SET_TUNER_POWER_REQ, 1, 7, NULL, 0);
+
return 0;
}
-static struct dvb_usb_properties vp702x_properties;
+static struct dvb_usb_device_properties vp702x_properties;
static int vp702x_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- struct usb_device *udev = interface_to_usbdev(intf);
-
- usb_clear_halt(udev,usb_sndctrlpipe(udev,0));
- usb_clear_halt(udev,usb_rcvctrlpipe(udev,0));
-
return dvb_usb_device_init(intf,&vp702x_properties,THIS_MODULE,NULL);
}
static struct usb_device_id vp702x_usb_table [] = {
{ USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_COLD) },
- { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7021_WARM) },
- { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
- { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
+// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_COLD) },
+// { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7020_WARM) },
{ 0 },
};
MODULE_DEVICE_TABLE(usb, vp702x_usb_table);
-static struct dvb_usb_properties vp702x_properties = {
- .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
- .pid_filter_count = 8, /* !!! */
-
+static struct dvb_usb_device_properties vp702x_properties = {
.usb_ctrl = CYPRESS_FX2,
- .firmware = "dvb-usb-vp702x-01.fw",
+ .firmware = "dvb-usb-vp702x-02.fw",
+ .no_reconnect = 1,
- .pid_filter = vp702x_pid_filter,
- .power_ctrl = vp702x_power_ctrl,
- .frontend_attach = vp702x_frontend_attach,
- .read_mac_address = vp702x_read_mac_addr,
+ .size_of_priv = sizeof(struct vp702x_device_state),
- .rc_key_map = vp702x_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys),
- .rc_interval = 400,
- .rc_query = vp702x_rc_query,
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_RECEIVES_204_BYTE_TS,
- .size_of_priv = sizeof(struct vp702x_state),
+ .streaming_ctrl = vp702x_streaming_ctrl,
+ .frontend_attach = vp702x_frontend_attach,
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
- .count = 7,
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
.endpoint = 0x02,
.u = {
.bulk = {
@@ -241,24 +288,33 @@ static struct dvb_usb_properties vp702x_properties = {
}
}
},
+ .size_of_priv = sizeof(struct vp702x_state),
+ }
+ },
+ .read_mac_address = vp702x_read_mac_addr,
+
+ .rc_key_map = vp702x_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(vp702x_rc_keys),
+ .rc_interval = 400,
+ .rc_query = vp702x_rc_query,
- .num_device_descs = 2,
+ .num_device_descs = 1,
.devices = {
{ .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7021)",
.cold_ids = { &vp702x_usb_table[0], NULL },
- .warm_ids = { &vp702x_usb_table[1], NULL },
+ .warm_ids = { NULL },
},
- { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
+/* { .name = "TwinhanDTV StarBox DVB-S USB2.0 (VP7020)",
.cold_ids = { &vp702x_usb_table[2], NULL },
.warm_ids = { &vp702x_usb_table[3], NULL },
},
- { 0 },
+*/ { NULL },
}
};
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver vp702x_usb_driver = {
- .name = "dvb-usb-vp702x",
+ .name = "dvb_usb_vp702x",
.probe = vp702x_usb_probe,
.disconnect = dvb_usb_device_exit,
.id_table = vp702x_usb_table,
@@ -287,5 +343,5 @@ module_exit(vp702x_usb_module_exit);
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
MODULE_DESCRIPTION("Driver for Twinhan StarBox DVB-S USB2.0 and clones");
-MODULE_VERSION("1.0-alpha");
+MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/vp702x.h b/drivers/media/dvb/dvb-usb/vp702x.h
index c2f97f96c21f..25a9dee4c824 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.h
+++ b/drivers/media/dvb/dvb-usb/vp702x.h
@@ -102,5 +102,7 @@ extern struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d);
extern int vp702x_usb_inout_op(struct dvb_usb_device *d, u8 *o, int olen, u8 *i, int ilen, int msec);
extern int vp702x_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int vp702x_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen);
+extern int vp702x_power_ctrl(struct dvb_usb_device *d, int onoff);
#endif
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 8ea3834a6cf8..b4cf002703a7 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -169,31 +169,31 @@ static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
}
-static int vp7045_frontend_attach(struct dvb_usb_device *d)
+static int vp7045_frontend_attach(struct dvb_usb_adapter *adap)
{
u8 buf[255] = { 0 };
- vp7045_usb_op(d,VENDOR_STRING_READ,NULL,0,buf,20,0);
+ vp7045_usb_op(adap->dev,VENDOR_STRING_READ,NULL,0,buf,20,0);
buf[10] = '\0';
deb_info("firmware says: %s ",buf);
- vp7045_usb_op(d,PRODUCT_STRING_READ,NULL,0,buf,20,0);
+ vp7045_usb_op(adap->dev,PRODUCT_STRING_READ,NULL,0,buf,20,0);
buf[10] = '\0';
deb_info("%s ",buf);
- vp7045_usb_op(d,FW_VERSION_READ,NULL,0,buf,20,0);
+ vp7045_usb_op(adap->dev,FW_VERSION_READ,NULL,0,buf,20,0);
buf[10] = '\0';
deb_info("v%s\n",buf);
/* Dump the EEPROM */
/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
- d->fe = vp7045_fe_attach(d);
+ adap->fe = vp7045_fe_attach(adap->dev);
return 0;
}
-static struct dvb_usb_properties vp7045_properties;
+static struct dvb_usb_device_properties vp7045_properties;
static int vp7045_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -210,24 +210,17 @@ static struct usb_device_id vp7045_usb_table [] = {
};
MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
-static struct dvb_usb_properties vp7045_properties = {
- .caps = 0,
-
+static struct dvb_usb_device_properties vp7045_properties = {
.usb_ctrl = CYPRESS_FX2,
.firmware = "dvb-usb-vp7045-01.fw",
- .power_ctrl = vp7045_power_ctrl,
+ .num_adapters = 1,
+ .adapter = {
+ {
.frontend_attach = vp7045_frontend_attach,
- .read_mac_address = vp7045_read_mac_addr,
-
- .rc_interval = 400,
- .rc_key_map = vp7045_rc_keys,
- .rc_key_map_size = ARRAY_SIZE(vp7045_rc_keys),
- .rc_query = vp7045_rc_query,
-
/* parameter for the MPEG2-data transfer */
- .urb = {
- .type = DVB_USB_BULK,
+ .stream = {
+ .type = USB_BULK,
.count = 7,
.endpoint = 0x02,
.u = {
@@ -236,6 +229,15 @@ static struct dvb_usb_properties vp7045_properties = {
}
}
},
+ }
+ },
+ .power_ctrl = vp7045_power_ctrl,
+ .read_mac_address = vp7045_read_mac_addr,
+
+ .rc_interval = 400,
+ .rc_key_map = vp7045_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(vp7045_rc_keys),
+ .rc_query = vp7045_rc_query,
.num_device_descs = 2,
.devices = {
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index db978555b1eb..080fa257a0bc 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -1,48 +1,73 @@
menu "Customise DVB Frontends"
depends on DVB_CORE
+config DVB_FE_CUSTOMISE
+ bool "Customise the frontend modules to build"
+ default N
+ help
+ This allows the user to deselect frontend drivers unnecessary
+ for their hardware from the build. Use this option with care
+ as deselecting frontends which are in fact necessary will result
+ in DVB devices which cannot be tuned due to lack of driver support.
+
+ If unsure say N.
+
comment "DVB-S (satellite) frontends"
depends on DVB_CORE
config DVB_STV0299
tristate "ST STV0299 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_CX24110
tristate "Conexant CX24110 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_CX24123
tristate "Conexant CX24123 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_TDA8083
tristate "Philips TDA8083 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_MT312
tristate "Zarlink VP310/MT312 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_VES1X93
tristate "VLSI VES1893 or VES1993 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
config DVB_S5H1420
tristate "Samsung S5H1420 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
+config DVB_TDA10086
+ tristate "Philips TDA10086 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-S tuner module. Say Y when you want to support this frontend.
@@ -52,6 +77,7 @@ comment "DVB-T (terrestrial) frontends"
config DVB_SP8870
tristate "Spase sp8870 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -64,6 +90,7 @@ config DVB_SP8870
config DVB_SP887X
tristate "Spase sp887x based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -76,24 +103,28 @@ config DVB_SP887X
config DVB_CX22700
tristate "Conexant CX22700 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_CX22702
tristate "Conexant cx22702 demodulator (OFDM)"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_L64781
tristate "LSI L64781"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_TDA1004X
tristate "Philips TDA10045H/TDA10046H based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
A DVB-T tuner module. Say Y when you want to support this frontend.
@@ -107,24 +138,28 @@ config DVB_TDA1004X
config DVB_NXT6000
tristate "NxtWave Communications NXT6000 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_MT352
tristate "Zarlink MT352 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_ZL10353
tristate "Zarlink ZL10353 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Say Y when you want to support this frontend.
config DVB_DIB3000MB
tristate "DiBcom 3000M-B"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
@@ -132,6 +167,7 @@ config DVB_DIB3000MB
config DVB_DIB3000MC
tristate "DiBcom 3000P/M-C"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
@@ -142,18 +178,21 @@ comment "DVB-C (cable) frontends"
config DVB_VES1820
tristate "VLSI VES1820 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_TDA10021
tristate "Philips TDA10021 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-C tuner module. Say Y when you want to support this frontend.
config DVB_STV0297
tristate "ST STV0297 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
A DVB-C tuner module. Say Y when you want to support this frontend.
@@ -163,6 +202,7 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends"
config DVB_NXT200X
tristate "NxtWave Communications NXT2002/NXT2004 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
@@ -177,6 +217,7 @@ config DVB_NXT200X
config DVB_OR51211
tristate "Oren OR51211 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
An ATSC 8VSB tuner module. Say Y when you want to support this frontend.
@@ -189,6 +230,7 @@ config DVB_OR51211
config DVB_OR51132
tristate "Oren OR51132 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
@@ -204,6 +246,7 @@ config DVB_OR51132
config DVB_BCM3510
tristate "Broadcom BCM3510"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
select FW_LOADER
help
An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
@@ -212,28 +255,52 @@ config DVB_BCM3510
config DVB_LGDT330X
tristate "LG Electronics LGDT3302/LGDT3303 based"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
-
-comment "Miscellaneous devices"
+comment "Tuners/PLL support"
depends on DVB_CORE
config DVB_PLL
tristate
depends on DVB_CORE && I2C
+config DVB_TDA826X
+ tristate "Philips TDA826X silicon tuner"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-S silicon tuner module. Say Y when you want to support this tuner.
+
+config DVB_TUNER_MT2060
+ tristate "Microtune MT2060 silicon IF tuner"
+ help
+ A driver for the silicon IF tuner MT2060 from Microtune.
+
+comment "Miscellaneous devices"
+ depends on DVB_CORE
+
config DVB_LNBP21
tristate "LNBP21 SEC controller"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
An SEC control chip.
config DVB_ISL6421
tristate "ISL6421 SEC controller"
depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
help
An SEC control chip.
+config DVB_TUA6100
+ tristate "TUA6100 PLL"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVBS PLL chip.
+
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 0e4880b6db14..dce9cf0c75c0 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -11,8 +11,8 @@ obj-$(CONFIG_DVB_CX22700) += cx22700.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
-obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o dib3000-common.o
-obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dib3000-common.o
+obj-$(CONFIG_DVB_DIB3000MB) += dib3000mb.o
+obj-$(CONFIG_DVB_DIB3000MC) += dib3000mc.o dibx000_common.o
obj-$(CONFIG_DVB_MT312) += mt312.o
obj-$(CONFIG_DVB_VES1820) += ves1820.o
obj-$(CONFIG_DVB_VES1X93) += ves1x93.o
@@ -33,3 +33,7 @@ obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
+obj-$(CONFIG_DVB_TDA10086) += tda10086.o
+obj-$(CONFIG_DVB_TDA826X) += tda826x.o
+obj-$(CONFIG_DVB_TUNER_MT2060) += mt2060.o
+obj-$(CONFIG_DVB_TUA6100) += tua6100.o
diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h
index 80f5d0953d02..6dfa839a7022 100644
--- a/drivers/media/dvb/frontends/bcm3510.h
+++ b/drivers/media/dvb/frontends/bcm3510.h
@@ -34,7 +34,16 @@ struct bcm3510_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
+#if defined(CONFIG_DVB_BCM3510) || defined(CONFIG_DVB_BCM3510_MODULE)
extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_BCM3510
#endif
diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h
index dcd8979c1a15..10286cc29fb4 100644
--- a/drivers/media/dvb/frontends/cx22700.h
+++ b/drivers/media/dvb/frontends/cx22700.h
@@ -31,7 +31,16 @@ struct cx22700_config
u8 demod_address;
};
+#if defined(CONFIG_DVB_CX22700) || defined(CONFIG_DVB_CX22700_MODULE)
extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx22700_attach(const struct cx22700_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_CX22700
#endif // CX22700_H
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 4106d46c957f..335219ebce2d 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -399,7 +399,9 @@ static int cx22702_read_signal_strength(struct dvb_frontend* fe, u16* signal_str
{
struct cx22702_state* state = fe->demodulator_priv;
- *signal_strength = cx22702_readreg (state, 0x23);
+ u16 rs_ber = 0;
+ rs_ber = cx22702_readreg (state, 0x23);
+ *signal_strength = (rs_ber << 8) | rs_ber;
return 0;
}
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 7f2f241e5d44..bc217ddf02c0 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -41,7 +41,16 @@ struct cx22702_config
u8 output_mode;
};
+#if defined(CONFIG_DVB_CX22702) || defined(CONFIG_DVB_CX22702_MODULE)
extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_CX22702
#endif // CX22702_H
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index ce3c7398bac9..ae96395217a2 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -1,4 +1,4 @@
-/*
+ /*
cx24110 - Single Chip Satellite Channel Receiver driver module
Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@htp-tel.de> based on
@@ -311,16 +311,17 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
}
-int cx24110_pll_write (struct dvb_frontend* fe, u32 data)
+static int _cx24110_pll_write (struct dvb_frontend* fe, u8 *buf, int len)
{
struct cx24110_state *state = fe->demodulator_priv;
+ if (len != 3)
+ return -EINVAL;
+
/* tuner data is 21 bits long, must be left-aligned in data */
/* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
/* FIXME (low): add error handling, avoid infinite loops if HW fails... */
- dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
-
cx24110_writereg(state,0x6d,0x30); /* auto mode at 62kHz */
cx24110_writereg(state,0x70,0x15); /* auto mode 21 bits */
@@ -329,19 +330,19 @@ int cx24110_pll_write (struct dvb_frontend* fe, u32 data)
cx24110_writereg(state,0x72,0);
/* write the topmost 8 bits */
- cx24110_writereg(state,0x72,(data>>24)&0xff);
+ cx24110_writereg(state,0x72,buf[0]);
/* wait for the send to be completed */
while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
;
/* send another 8 bytes */
- cx24110_writereg(state,0x72,(data>>16)&0xff);
+ cx24110_writereg(state,0x72,buf[1]);
while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
;
/* and the topmost 5 bits of this byte */
- cx24110_writereg(state,0x72,(data>>8)&0xff);
+ cx24110_writereg(state,0x72,buf[2]);
while ((cx24110_readreg(state,0x6d)&0xc0)==0x80)
;
@@ -642,6 +643,7 @@ static struct dvb_frontend_ops cx24110_ops = {
.release = cx24110_release,
.init = cx24110_initfe,
+ .write = _cx24110_pll_write,
.set_frontend = cx24110_set_frontend,
.get_frontend = cx24110_get_frontend,
.read_status = cx24110_read_status,
@@ -664,4 +666,3 @@ MODULE_AUTHOR("Peter Hettkamp");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(cx24110_attach);
-EXPORT_SYMBOL(cx24110_pll_write);
diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h
index b354a64e0e74..c9d5ae250ebb 100644
--- a/drivers/media/dvb/frontends/cx24110.h
+++ b/drivers/media/dvb/frontends/cx24110.h
@@ -33,9 +33,24 @@ struct cx24110_config
u8 demod_address;
};
+static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) {
+ int r = 0;
+ u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)};
+ if (fe->ops.write)
+ r = fe->ops.write(fe, buf, 3);
+ return r;
+}
+
+#if defined(CONFIG_DVB_CX24110) || defined(CONFIG_DVB_CX24110_MODULE)
extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
struct i2c_adapter* i2c);
-
-extern int cx24110_pll_write(struct dvb_frontend* fe, u32 data);
+#else
+static inline struct dvb_frontend* cx24110_attach(const struct cx24110_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_CX24110
#endif // CX24110_H
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index 274a87b7a5d5..a356d28fc3bb 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -45,9 +45,6 @@ struct cx24123_state
struct dvb_frontend frontend;
- u32 lastber;
- u16 snr;
-
/* Some PLL specifics for tuning */
u32 VCAarg;
u32 VGAarg;
@@ -194,7 +191,7 @@ static struct {
{0x06, 0x31}, /* MPEG (default) */
{0x0b, 0x00}, /* Freq search start point (default) */
{0x0c, 0x00}, /* Demodulator sample gain (default) */
- {0x0d, 0x02}, /* Frequency search range = Fsymbol / 4 (default) */
+ {0x0d, 0x7f}, /* Force driver to shift until the maximum (+-10 MHz) */
{0x0e, 0x03}, /* Default non-inverted, FEC 3/4 (default) */
{0x0f, 0xfe}, /* FEC search mask (all supported codes) */
{0x10, 0x01}, /* Default search inversion, no repeat (default) */
@@ -223,8 +220,9 @@ static struct {
{0x44, 0x00}, /* Constellation (default) */
{0x45, 0x00}, /* Symbol count (default) */
{0x46, 0x0d}, /* Symbol rate estimator on (default) */
- {0x56, 0x41}, /* Various (default) */
+ {0x56, 0xc1}, /* Error Counter = Viterbi BER */
{0x57, 0xff}, /* Error Counter Window (default) */
+ {0x5c, 0x20}, /* Acquisition AFC Expiration window (default is 0x10) */
{0x67, 0x83}, /* Non-DCII symbol clock */
};
@@ -321,6 +319,12 @@ static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
if ( (fec < FEC_NONE) || (fec > FEC_AUTO) )
fec = FEC_AUTO;
+ /* Set the soft decision threshold */
+ if(fec == FEC_1_2)
+ cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) | 0x01);
+ else
+ cx24123_writereg(state, 0x43, cx24123_readreg(state, 0x43) & ~0x01);
+
switch (fec) {
case FEC_1_2:
dprintk("%s: set FEC to 1/2\n",__FUNCTION__);
@@ -549,8 +553,8 @@ static int cx24123_pll_calculate(struct dvb_frontend* fe, struct dvb_frontend_pa
ndiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) / 32) & 0x1ff;
adiv = ( ((p->frequency * vco_div * 10) / (2 * XTAL / 1000)) % 32) & 0x1f;
- if (adiv == 0)
- ndiv++;
+ if (adiv == 0 && ndiv > 0)
+ ndiv--;
/* control bits 11, refdiv 11, charge pump polarity 1, charge pump current, ndiv, adiv */
state->pllarg = (3 << 19) | (3 << 17) | (1 << 16) | (pump << 14) | (ndiv << 5) | adiv;
@@ -657,6 +661,10 @@ static int cx24123_initfe(struct dvb_frontend* fe)
for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++)
cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data);
+ /* Set the LNB polarity */
+ if(state->config->lnb_polarity)
+ cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02);
+
return 0;
}
@@ -674,6 +682,9 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
case SEC_VOLTAGE_18:
dprintk("%s: setting voltage 18V\n", __FUNCTION__);
return cx24123_writereg(state, 0x29, val | 0x80);
+ case SEC_VOLTAGE_OFF:
+ /* already handled in cx88-dvb */
+ return 0;
default:
return -EINVAL;
};
@@ -776,13 +787,15 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
if (lock & 0x01)
*status |= FE_HAS_SIGNAL;
if (sync & 0x02)
- *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_CARRIER; /* Phase locked */
if (sync & 0x04)
*status |= FE_HAS_VITERBI;
+
+ /* Reed-Solomon Status */
if (sync & 0x08)
*status |= FE_HAS_SYNC;
if (sync & 0x80)
- *status |= FE_HAS_LOCK;
+ *status |= FE_HAS_LOCK; /*Full Sync */
return 0;
}
@@ -795,29 +808,13 @@ static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
{
struct cx24123_state *state = fe->demodulator_priv;
- state->lastber =
- ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+ /* The true bit error rate is this value divided by
+ the window size (set as 256 * 255) */
+ *ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
(cx24123_readreg(state, 0x1d) << 8 |
- cx24123_readreg(state, 0x1e));
-
- /* Do the signal quality processing here, it's derived from the BER. */
- /* Scale the BER from a 24bit to a SNR 16 bit where higher = better */
- if (state->lastber < 5000)
- state->snr = 655*100;
- else if ( (state->lastber >= 5000) && (state->lastber < 55000) )
- state->snr = 655*90;
- else if ( (state->lastber >= 55000) && (state->lastber < 150000) )
- state->snr = 655*80;
- else if ( (state->lastber >= 150000) && (state->lastber < 250000) )
- state->snr = 655*70;
- else if ( (state->lastber >= 250000) && (state->lastber < 450000) )
- state->snr = 655*65;
- else
- state->snr = 0;
-
- dprintk("%s: BER = %d, S/N index = %d\n",__FUNCTION__,state->lastber, state->snr);
+ cx24123_readreg(state, 0x1e));
- *ber = state->lastber;
+ dprintk("%s: BER = %d\n",__FUNCTION__,*ber);
return 0;
}
@@ -825,6 +822,7 @@ static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
{
struct cx24123_state *state = fe->demodulator_priv;
+
*signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
dprintk("%s: Signal strength = %d\n",__FUNCTION__,*signal_strength);
@@ -835,19 +833,13 @@ static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_str
static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
{
struct cx24123_state *state = fe->demodulator_priv;
- *snr = state->snr;
-
- dprintk("%s: read S/N index = %d\n",__FUNCTION__,*snr);
- return 0;
-}
+ /* Inverted raw Es/N0 count, totally bogus but better than the
+ BER threshold. */
+ *snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
+ (u16)cx24123_readreg(state, 0x19));
-static int cx24123_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
-{
- struct cx24123_state *state = fe->demodulator_priv;
- *ucblocks = state->lastber;
-
- dprintk("%s: ucblocks (ber) = %d\n",__FUNCTION__,*ucblocks);
+ dprintk("%s: read S/N index = %d\n",__FUNCTION__,*snr);
return 0;
}
@@ -922,6 +914,29 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
return 0;
}
+static int cx24123_tune(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* params,
+ unsigned int mode_flags,
+ int *delay,
+ fe_status_t *status)
+{
+ int retval = 0;
+
+ if (params != NULL)
+ retval = cx24123_set_frontend(fe, params);
+
+ if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+ cx24123_read_status(fe, status);
+ *delay = HZ/10;
+
+ return retval;
+}
+
+static int cx24123_get_algo(struct dvb_frontend *fe)
+{
+ return 1; //FE_ALGO_HW
+}
+
static void cx24123_release(struct dvb_frontend* fe)
{
struct cx24123_state* state = fe->demodulator_priv;
@@ -949,8 +964,6 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- state->lastber = 0;
- state->snr = 0;
state->VCAarg = 0;
state->VGAarg = 0;
state->bandselectarg = 0;
@@ -1003,11 +1016,12 @@ static struct dvb_frontend_ops cx24123_ops = {
.read_ber = cx24123_read_ber,
.read_signal_strength = cx24123_read_signal_strength,
.read_snr = cx24123_read_snr,
- .read_ucblocks = cx24123_read_ucblocks,
.diseqc_send_master_cmd = cx24123_send_diseqc_msg,
.diseqc_send_burst = cx24123_diseqc_send_burst,
.set_tone = cx24123_set_tone,
.set_voltage = cx24123_set_voltage,
+ .tune = cx24123_tune,
+ .get_frontend_algo = cx24123_get_algo,
};
module_param(debug, int, 0644);
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 9606f825935c..57a1dae1dc40 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -30,9 +30,21 @@ struct cx24123_config
/* Need to set device param for start_dma */
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+
+ /* 0 = LNB voltage normal, 1 = LNB voltage inverted */
+ int lnb_polarity;
};
+#if defined(CONFIG_DVB_CX24123) || defined(CONFIG_DVB_CX24123_MODULE)
extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_CX24123
#endif /* CX24123_H */
diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c
deleted file mode 100644
index 1a4f1f7c228a..000000000000
--- a/drivers/media/dvb/frontends/dib3000-common.c
+++ /dev/null
@@ -1,83 +0,0 @@
-#include "dib3000-common.h"
-
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
-#endif
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_i2c(args...) dprintk(0x02,args)
-#define deb_srch(args...) dprintk(0x04,args)
-
-
-int dib3000_read_reg(struct dib3000_state *state, u16 reg)
-{
- u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
- u8 rb[2];
- struct i2c_msg msg[] = {
- { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 },
- { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
- };
-
- if (i2c_transfer(state->i2c, msg, 2) != 2)
- deb_i2c("i2c read error\n");
-
- deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
- (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
-
- return (rb[0] << 8) | rb[1];
-}
-
-int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
-{
- u8 b[] = {
- (reg >> 8) & 0xff, reg & 0xff,
- (val >> 8) & 0xff, val & 0xff,
- };
- struct i2c_msg msg[] = {
- { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
- };
- deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
-
- return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
-}
-
-int dib3000_search_status(u16 irq,u16 lock)
-{
- if (irq & 0x02) {
- if (lock & 0x01) {
- deb_srch("auto search succeeded\n");
- return 1; // auto search succeeded
- } else {
- deb_srch("auto search not successful\n");
- return 0; // auto search failed
- }
- } else if (irq & 0x01) {
- deb_srch("auto search failed\n");
- return 0; // auto search failed
- }
- return -1; // try again
-}
-
-/* for auto search */
-u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
- { /* fft */
- { /* gua */
- { 0, 1 }, /* 0 0 { 0,1 } */
- { 3, 9 }, /* 0 1 { 0,1 } */
- },
- {
- { 2, 5 }, /* 1 0 { 0,1 } */
- { 6, 11 }, /* 1 1 { 0,1 } */
- }
- };
-
-MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
-MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(dib3000_seq);
-
-EXPORT_SYMBOL(dib3000_read_reg);
-EXPORT_SYMBOL(dib3000_write_reg);
-EXPORT_SYMBOL(dib3000_search_status);
diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h
deleted file mode 100644
index be1c0d3e1389..000000000000
--- a/drivers/media/dvb/frontends/dib3000-common.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * .h-files for the common use of the frontend drivers made by DiBcom
- * DiBcom 3000M-B/C, 3000P
- *
- * DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * based on GPL code from DibCom, which has
- *
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- * 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, version 2.
- *
- * Acknowledgements
- *
- * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- * sources, on which this driver (and the dvb-dibusb) are based.
- *
- * see Documentation/dvb/README.dibusb for more information
- *
- */
-
-#ifndef DIB3000_COMMON_H
-#define DIB3000_COMMON_H
-
-#include "dvb_frontend.h"
-#include "dib3000.h"
-
-/* info and err, taken from usb.h, if there is anything available like by default. */
-#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
-
-/* frontend state */
-struct dib3000_state {
- struct i2c_adapter* i2c;
-
-/* configuration settings */
- struct dib3000_config config;
-
- struct dvb_frontend frontend;
- int timing_offset;
- int timing_offset_comp_done;
-
- fe_bandwidth_t last_tuned_bw;
- u32 last_tuned_freq;
-};
-
-/* commonly used methods by the dib3000mb/mc/p frontend */
-extern int dib3000_read_reg(struct dib3000_state *state, u16 reg);
-extern int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val);
-
-extern int dib3000_search_status(u16 irq,u16 lock);
-
-/* handy shortcuts */
-#define rd(reg) dib3000_read_reg(state,reg)
-
-#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
- { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
-
-#define wr_foreach(a,v) { int i; \
- if (sizeof(a) != sizeof(v)) \
- err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
- for (i=0; i < sizeof(a)/sizeof(u16); i++) \
- wr(a[i],v[i]); \
- }
-
-#define set_or(reg,val) wr(reg,rd(reg) | val)
-
-#define set_and(reg,val) wr(reg,rd(reg) & val)
-
-
-/* debug */
-
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define dprintk(level,args...) \
- do { if ((debug & level)) { printk(args); } } while (0)
-#else
-#define dprintk(args...) do { } while (0)
-#endif
-
-/* mask for enabling a specific pid for the pid_filter */
-#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
-
-/* common values for tuning */
-#define DIB3000_ALPHA_0 ( 0)
-#define DIB3000_ALPHA_1 ( 1)
-#define DIB3000_ALPHA_2 ( 2)
-#define DIB3000_ALPHA_4 ( 4)
-
-#define DIB3000_CONSTELLATION_QPSK ( 0)
-#define DIB3000_CONSTELLATION_16QAM ( 1)
-#define DIB3000_CONSTELLATION_64QAM ( 2)
-
-#define DIB3000_GUARD_TIME_1_32 ( 0)
-#define DIB3000_GUARD_TIME_1_16 ( 1)
-#define DIB3000_GUARD_TIME_1_8 ( 2)
-#define DIB3000_GUARD_TIME_1_4 ( 3)
-
-#define DIB3000_TRANSMISSION_MODE_2K ( 0)
-#define DIB3000_TRANSMISSION_MODE_8K ( 1)
-
-#define DIB3000_SELECT_LP ( 0)
-#define DIB3000_SELECT_HP ( 1)
-
-#define DIB3000_FEC_1_2 ( 1)
-#define DIB3000_FEC_2_3 ( 2)
-#define DIB3000_FEC_3_4 ( 3)
-#define DIB3000_FEC_5_6 ( 5)
-#define DIB3000_FEC_7_8 ( 7)
-
-#define DIB3000_HRCH_OFF ( 0)
-#define DIB3000_HRCH_ON ( 1)
-
-#define DIB3000_DDS_INVERSION_OFF ( 0)
-#define DIB3000_DDS_INVERSION_ON ( 1)
-
-#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8))
-#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7)))
-
-/* for auto search */
-extern u16 dib3000_seq[2][2][2];
-
-#define DIB3000_REG_MANUFACTOR_ID ( 1025)
-#define DIB3000_I2C_ID_DIBCOM (0x01b3)
-
-#define DIB3000_REG_DEVICE_ID ( 1026)
-#define DIB3000MB_DEVICE_ID (0x3000)
-#define DIB3000MC_DEVICE_ID (0x3001)
-#define DIB3000P_DEVICE_ID (0x3002)
-
-#endif // DIB3000_COMMON_H
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index ec927628d273..0caac3f0f279 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -41,9 +41,16 @@ struct dib_fe_xfer_ops
int (*tuner_pass_ctrl)(struct dvb_frontend *fe, int onoff, u8 pll_ctrl);
};
+#if defined(CONFIG_DVB_DIB3000MB) || defined(CONFIG_DVB_DIB3000MB_MODULE)
extern struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
+#else
+static inline struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config,
+ struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_DIB3000MB
-extern struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
- struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops);
#endif // DIB3000_H
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index 5302e11883a2..adbabfdb04a9 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -29,9 +29,10 @@
#include <linux/string.h>
#include <linux/slab.h>
-#include "dib3000-common.h"
-#include "dib3000mb_priv.h"
+#include "dvb_frontend.h"
+
#include "dib3000.h"
+#include "dib3000mb_priv.h"
/* Version information */
#define DRIVER_VERSION "0.1"
@@ -44,10 +45,81 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
#endif
#define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...) dprintk(0x02,args)
+#define deb_srch(args...) dprintk(0x04,args)
+#define deb_info(args...) dprintk(0x01,args)
#define deb_xfer(args...) dprintk(0x02,args)
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
+#endif
+
+static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
+{
+ u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
+ u8 rb[2];
+ struct i2c_msg msg[] = {
+ { .addr = state->config.demod_address, .flags = 0, .buf = wb, .len = 2 },
+ { .addr = state->config.demod_address, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+ };
+
+ if (i2c_transfer(state->i2c, msg, 2) != 2)
+ deb_i2c("i2c read error\n");
+
+ deb_i2c("reading i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,
+ (rb[0] << 8) | rb[1],(rb[0] << 8) | rb[1]);
+
+ return (rb[0] << 8) | rb[1];
+}
+
+static int dib3000_write_reg(struct dib3000_state *state, u16 reg, u16 val)
+{
+ u8 b[] = {
+ (reg >> 8) & 0xff, reg & 0xff,
+ (val >> 8) & 0xff, val & 0xff,
+ };
+ struct i2c_msg msg[] = {
+ { .addr = state->config.demod_address, .flags = 0, .buf = b, .len = 4 }
+ };
+ deb_i2c("writing i2c bus (reg: %5d 0x%04x, val: %5d 0x%04x)\n",reg,reg,val,val);
+
+ return i2c_transfer(state->i2c,msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+static int dib3000_search_status(u16 irq,u16 lock)
+{
+ if (irq & 0x02) {
+ if (lock & 0x01) {
+ deb_srch("auto search succeeded\n");
+ return 1; // auto search succeeded
+ } else {
+ deb_srch("auto search not successful\n");
+ return 0; // auto search failed
+ }
+ } else if (irq & 0x01) {
+ deb_srch("auto search failed\n");
+ return 0; // auto search failed
+ }
+ return -1; // try again
+}
+
+/* for auto search */
+static u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
+ { /* fft */
+ { /* gua */
+ { 0, 1 }, /* 0 0 { 0,1 } */
+ { 3, 9 }, /* 0 1 { 0,1 } */
+ },
+ {
+ { 2, 5 }, /* 1 0 { 0,1 } */
+ { 6, 11 }, /* 1 1 { 0,1 } */
+ }
+ };
+
static int dib3000mb_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep);
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
index 999b19047816..1a12747fdc91 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -13,6 +13,99 @@
#ifndef __DIB3000MB_PRIV_H_INCLUDED__
#define __DIB3000MB_PRIV_H_INCLUDED__
+/* info and err, taken from usb.h, if there is anything available like by default. */
+#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg)
+
+/* handy shortcuts */
+#define rd(reg) dib3000_read_reg(state,reg)
+
+#define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \
+ { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; }
+
+#define wr_foreach(a,v) { int i; \
+ if (sizeof(a) != sizeof(v)) \
+ err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\
+ for (i=0; i < sizeof(a)/sizeof(u16); i++) \
+ wr(a[i],v[i]); \
+ }
+
+#define set_or(reg,val) wr(reg,rd(reg) | val)
+
+#define set_and(reg,val) wr(reg,rd(reg) & val)
+
+/* debug */
+
+#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#define dprintk(level,args...) \
+ do { if ((debug & level)) { printk(args); } } while (0)
+#else
+#define dprintk(args...) do { } while (0)
+#endif
+
+/* mask for enabling a specific pid for the pid_filter */
+#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
+
+/* common values for tuning */
+#define DIB3000_ALPHA_0 ( 0)
+#define DIB3000_ALPHA_1 ( 1)
+#define DIB3000_ALPHA_2 ( 2)
+#define DIB3000_ALPHA_4 ( 4)
+
+#define DIB3000_CONSTELLATION_QPSK ( 0)
+#define DIB3000_CONSTELLATION_16QAM ( 1)
+#define DIB3000_CONSTELLATION_64QAM ( 2)
+
+#define DIB3000_GUARD_TIME_1_32 ( 0)
+#define DIB3000_GUARD_TIME_1_16 ( 1)
+#define DIB3000_GUARD_TIME_1_8 ( 2)
+#define DIB3000_GUARD_TIME_1_4 ( 3)
+
+#define DIB3000_TRANSMISSION_MODE_2K ( 0)
+#define DIB3000_TRANSMISSION_MODE_8K ( 1)
+
+#define DIB3000_SELECT_LP ( 0)
+#define DIB3000_SELECT_HP ( 1)
+
+#define DIB3000_FEC_1_2 ( 1)
+#define DIB3000_FEC_2_3 ( 2)
+#define DIB3000_FEC_3_4 ( 3)
+#define DIB3000_FEC_5_6 ( 5)
+#define DIB3000_FEC_7_8 ( 7)
+
+#define DIB3000_HRCH_OFF ( 0)
+#define DIB3000_HRCH_ON ( 1)
+
+#define DIB3000_DDS_INVERSION_OFF ( 0)
+#define DIB3000_DDS_INVERSION_ON ( 1)
+
+#define DIB3000_TUNER_WRITE_ENABLE(a) (0xffff & (a << 8))
+#define DIB3000_TUNER_WRITE_DISABLE(a) (0xffff & ((a << 8) | (1 << 7)))
+
+#define DIB3000_REG_MANUFACTOR_ID ( 1025)
+#define DIB3000_I2C_ID_DIBCOM (0x01b3)
+
+#define DIB3000_REG_DEVICE_ID ( 1026)
+#define DIB3000MB_DEVICE_ID (0x3000)
+#define DIB3000MC_DEVICE_ID (0x3001)
+#define DIB3000P_DEVICE_ID (0x3002)
+
+/* frontend state */
+struct dib3000_state {
+ struct i2c_adapter* i2c;
+
+/* configuration settings */
+ struct dib3000_config config;
+
+ struct dvb_frontend frontend;
+ int timing_offset;
+ int timing_offset_comp_done;
+
+ fe_bandwidth_t last_tuned_bw;
+ u32 last_tuned_freq;
+};
+
/* register addresses and some of their default values */
/* restart subsystems */
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 98673474a140..3561a777568c 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -1,725 +1,727 @@
/*
- * Frontend driver for mobile DVB-T demodulator DiBcom 3000P/M-C
- * DiBcom (http://www.dibcom.fr/)
+ * Driver for DiBcom DiB3000MC/P-demodulator.
*
+ * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
* Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
*
- * based on GPL code from DiBCom, which has
+ * This code is partially based on the previous dib3000mc.c .
*
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- * This program is free software; you can redistribute it and/or
+ * 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, version 2.
- *
- * Acknowledgements
- *
- * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- * sources, on which this driver (and the dvb-dibusb) are based.
- *
- * see Documentation/dvb/README.dibusb for more information
- *
*/
+
#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-
-#include "dib3000-common.h"
-#include "dib3000mc_priv.h"
-#include "dib3000.h"
-
-/* Version information */
-#define DRIVER_VERSION "0.1"
-#define DRIVER_DESC "DiBcom 3000M-C DVB-T demodulator"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
+#include <linux/i2c.h>
+//#include <linux/init.h>
+//#include <linux/delay.h>
+//#include <linux/string.h>
+//#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+
+#include "dib3000mc.h"
+
static int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=stat (|-able)).");
-#endif
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_xfer(args...) dprintk(0x02,args)
-#define deb_setf(args...) dprintk(0x04,args)
-#define deb_getf(args...) dprintk(0x08,args)
-#define deb_stat(args...) dprintk(0x10,args)
-
-static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
- fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); } } while (0)
+
+struct dib3000mc_state {
+ struct dvb_frontend demod;
+ struct dib3000mc_config *cfg;
+
+ u8 i2c_addr;
+ struct i2c_adapter *i2c_adap;
+
+ struct dibx000_i2c_master i2c_master;
+
+ u32 timf;
+
+ fe_bandwidth_t current_bandwidth;
+
+ u16 dev_id;
+};
+
+static u16 dib3000mc_read_word(struct dib3000mc_state *state, u16 reg)
{
- switch (transmission_mode) {
- case TRANSMISSION_MODE_2K:
- wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[0]);
- break;
- case TRANSMISSION_MODE_8K:
- wr_foreach(dib3000mc_reg_fft,dib3000mc_fft_modes[1]);
- break;
- default:
- break;
- }
+ u8 wb[2] = { (reg >> 8) | 0x80, reg & 0xff };
+ u8 rb[2];
+ struct i2c_msg msg[2] = {
+ { .addr = state->i2c_addr >> 1, .flags = 0, .buf = wb, .len = 2 },
+ { .addr = state->i2c_addr >> 1, .flags = I2C_M_RD, .buf = rb, .len = 2 },
+ };
- switch (bandwidth) {
-/* case BANDWIDTH_5_MHZ:
- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[0]);
- break; */
- case BANDWIDTH_6_MHZ:
- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[1]);
- break;
- case BANDWIDTH_7_MHZ:
- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[2]);
- break;
- case BANDWIDTH_8_MHZ:
- wr_foreach(dib3000mc_reg_impulse_noise,dib3000mc_impluse_noise[3]);
- break;
- default:
- break;
- }
+ if (i2c_transfer(state->i2c_adap, msg, 2) != 2)
+ dprintk("i2c read error on %d\n",reg);
- switch (mode) {
- case 0: /* no impulse */ /* fall through */
- wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[0]);
- break;
- case 1: /* new algo */
- wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[1]);
- set_or(DIB3000MC_REG_IMP_NOISE_55,DIB3000MC_IMP_NEW_ALGO(0)); /* gives 1<<10 */
- break;
- default: /* old algo */
- wr_foreach(dib3000mc_reg_imp_noise_ctl,dib3000mc_imp_noise_ctl[3]);
- break;
- }
- return 0;
+ return (rb[0] << 8) | rb[1];
}
-static int dib3000mc_set_timing(struct dib3000_state *state, int upd_offset,
- fe_transmit_mode_t fft, fe_bandwidth_t bw)
+static int dib3000mc_write_word(struct dib3000mc_state *state, u16 reg, u16 val)
{
- u16 timf_msb,timf_lsb;
- s32 tim_offset,tim_sgn;
- u64 comp1,comp2,comp=0;
+ u8 b[4] = {
+ (reg >> 8) & 0xff, reg & 0xff,
+ (val >> 8) & 0xff, val & 0xff,
+ };
+ struct i2c_msg msg = {
+ .addr = state->i2c_addr >> 1, .flags = 0, .buf = b, .len = 4
+ };
+ return i2c_transfer(state->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
- switch (bw) {
- case BANDWIDTH_8_MHZ: comp = DIB3000MC_CLOCK_REF*8; break;
- case BANDWIDTH_7_MHZ: comp = DIB3000MC_CLOCK_REF*7; break;
- case BANDWIDTH_6_MHZ: comp = DIB3000MC_CLOCK_REF*6; break;
- default: err("unknown bandwidth (%d)",bw); break;
+
+static int dib3000mc_identify(struct dib3000mc_state *state)
+{
+ u16 value;
+ if ((value = dib3000mc_read_word(state, 1025)) != 0x01b3) {
+ dprintk("-E- DiB3000MC/P: wrong Vendor ID (read=0x%x)\n",value);
+ return -EREMOTEIO;
}
- timf_msb = (comp >> 16) & 0xff;
- timf_lsb = (comp & 0xffff);
-
- // Update the timing offset ;
- if (upd_offset > 0) {
- if (!state->timing_offset_comp_done) {
- msleep(200);
- state->timing_offset_comp_done = 1;
- }
- tim_offset = rd(DIB3000MC_REG_TIMING_OFFS_MSB);
- if ((tim_offset & 0x2000) == 0x2000)
- tim_offset |= 0xC000;
- if (fft == TRANSMISSION_MODE_2K)
- tim_offset <<= 2;
- state->timing_offset += tim_offset;
+
+ value = dib3000mc_read_word(state, 1026);
+ if (value != 0x3001 && value != 0x3002) {
+ dprintk("-E- DiB3000MC/P: wrong Device ID (%x)\n",value);
+ return -EREMOTEIO;
}
+ state->dev_id = value;
+
+ dprintk("-I- found DiB3000MC/P: %x\n",state->dev_id);
+
+ return 0;
+}
- tim_offset = state->timing_offset;
- if (tim_offset < 0) {
- tim_sgn = 1;
- tim_offset = -tim_offset;
+static int dib3000mc_set_timing(struct dib3000mc_state *state, s16 nfft, u8 bw, u8 update_offset)
+{
+ u32 timf;
+
+ if (state->timf == 0) {
+ timf = 1384402; // default value for 8MHz
+ if (update_offset)
+ msleep(200); // first time we do an update
} else
- tim_sgn = 0;
+ timf = state->timf;
- comp1 = (u32)tim_offset * (u32)timf_lsb ;
- comp2 = (u32)tim_offset * (u32)timf_msb ;
- comp = ((comp1 >> 16) + comp2) >> 7;
+ timf *= (BW_INDEX_TO_KHZ(bw) / 1000);
- if (tim_sgn == 0)
- comp = (u32)(timf_msb << 16) + (u32) timf_lsb + comp;
- else
- comp = (u32)(timf_msb << 16) + (u32) timf_lsb - comp ;
+ if (update_offset) {
+ s16 tim_offs = dib3000mc_read_word(state, 416);
+
+ if (tim_offs & 0x2000)
+ tim_offs -= 0x4000;
+
+ if (nfft == 0)
+ tim_offs *= 4;
+
+ timf += tim_offs;
+ state->timf = timf / (BW_INDEX_TO_KHZ(bw) / 1000);
+ }
+
+ dprintk("timf: %d\n", timf);
- timf_msb = (comp >> 16) & 0xff;
- timf_lsb = comp & 0xffff;
+ dib3000mc_write_word(state, 23, timf >> 16);
+ dib3000mc_write_word(state, 24, timf & 0xffff);
- wr(DIB3000MC_REG_TIMING_FREQ_MSB,timf_msb);
- wr(DIB3000MC_REG_TIMING_FREQ_LSB,timf_lsb);
return 0;
}
-static int dib3000mc_init_auto_scan(struct dib3000_state *state, fe_bandwidth_t bw, int boost)
+static int dib3000mc_setup_pwm_state(struct dib3000mc_state *state)
{
- if (boost) {
- wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_ON);
+ u16 reg_51, reg_52 = state->cfg->agc->setup & 0xfefb;
+ if (state->cfg->pwm3_inversion) {
+ reg_51 = (2 << 14) | (0 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
+ reg_52 |= (1 << 2);
} else {
- wr(DIB3000MC_REG_SCAN_BOOST,DIB3000MC_SCAN_BOOST_OFF);
- }
- switch (bw) {
- case BANDWIDTH_8_MHZ:
- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
- break;
- case BANDWIDTH_7_MHZ:
- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_7mhz);
- break;
- case BANDWIDTH_6_MHZ:
- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_6mhz);
- break;
-/* case BANDWIDTH_5_MHZ:
- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_5mhz);
- break;*/
- case BANDWIDTH_AUTO:
- return -EOPNOTSUPP;
- default:
- err("unknown bandwidth value (%d).",bw);
- return -EINVAL;
- }
- if (boost) {
- u32 timeout = (rd(DIB3000MC_REG_BW_TIMOUT_MSB) << 16) +
- rd(DIB3000MC_REG_BW_TIMOUT_LSB);
- timeout *= 85; timeout >>= 7;
- wr(DIB3000MC_REG_BW_TIMOUT_MSB,(timeout >> 16) & 0xffff);
- wr(DIB3000MC_REG_BW_TIMOUT_LSB,timeout & 0xffff);
+ reg_51 = (2 << 14) | (4 << 10) | (7 << 6) | (2 << 2) | (2 << 0);
+ reg_52 |= (1 << 8);
}
+ dib3000mc_write_word(state, 51, reg_51);
+ dib3000mc_write_word(state, 52, reg_52);
+
+ if (state->cfg->use_pwm3)
+ dib3000mc_write_word(state, 245, (1 << 3) | (1 << 0));
+ else
+ dib3000mc_write_word(state, 245, 0);
+
+ dib3000mc_write_word(state, 1040, 0x3);
return 0;
}
-static int dib3000mc_set_adp_cfg(struct dib3000_state *state, fe_modulation_t con)
+static int dib3000mc_set_output_mode(struct dib3000mc_state *state, int mode)
{
- switch (con) {
- case QAM_64:
- wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[2]);
- break;
- case QAM_16:
- wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[1]);
- break;
- case QPSK:
- wr_foreach(dib3000mc_reg_adp_cfg,dib3000mc_adp_cfg[0]);
- break;
- case QAM_AUTO:
+ int ret = 0;
+ u16 fifo_threshold = 1792;
+ u16 outreg = 0;
+ u16 outmode = 0;
+ u16 elecout = 1;
+ u16 smo_reg = dib3000mc_read_word(state, 206) & 0x0010; /* keep the pid_parse bit */
+
+ dprintk("-I- Setting output mode for demod %p to %d\n",
+ &state->demod, mode);
+
+ switch (mode) {
+ case OUTMODE_HIGH_Z: // disable
+ elecout = 0;
+ break;
+ case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock
+ outmode = 0;
+ break;
+ case OUTMODE_MPEG2_PAR_CONT_CLK: // STBs with parallel continues clock
+ outmode = 1;
+ break;
+ case OUTMODE_MPEG2_SERIAL: // STBs with serial input
+ outmode = 2;
+ break;
+ case OUTMODE_MPEG2_FIFO: // e.g. USB feeding
+ elecout = 3;
+ /*ADDR @ 206 :
+ P_smo_error_discard [1;6:6] = 0
+ P_smo_rs_discard [1;5:5] = 0
+ P_smo_pid_parse [1;4:4] = 0
+ P_smo_fifo_flush [1;3:3] = 0
+ P_smo_mode [2;2:1] = 11
+ P_smo_ovf_prot [1;0:0] = 0
+ */
+ smo_reg |= 3 << 1;
+ fifo_threshold = 512;
+ outmode = 5;
+ break;
+ case OUTMODE_DIVERSITY:
+ outmode = 4;
+ elecout = 1;
break;
default:
- warn("unkown constellation.");
+ dprintk("Unhandled output_mode passed to be set for demod %p\n",&state->demod);
+ outmode = 0;
break;
}
- return 0;
+
+ if ((state->cfg->output_mpeg2_in_188_bytes))
+ smo_reg |= (1 << 5); // P_smo_rs_discard [1;5:5] = 1
+
+ outreg = dib3000mc_read_word(state, 244) & 0x07FF;
+ outreg |= (outmode << 11);
+ ret |= dib3000mc_write_word(state, 244, outreg);
+ ret |= dib3000mc_write_word(state, 206, smo_reg); /*smo_ mode*/
+ ret |= dib3000mc_write_word(state, 207, fifo_threshold); /* synchronous fread */
+ ret |= dib3000mc_write_word(state, 1040, elecout); /* P_out_cfg */
+ return ret;
}
-static int dib3000mc_set_general_cfg(struct dib3000_state *state, struct dvb_frontend_parameters *fep, int *auto_val)
+static int dib3000mc_set_bandwidth(struct dvb_frontend *demod, u8 bw)
{
- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
- fe_code_rate_t fe_cr = FEC_NONE;
- u8 fft=0, guard=0, qam=0, alpha=0, sel_hp=0, cr=0, hrch=0;
- int seq;
-
- switch (ofdm->transmission_mode) {
- case TRANSMISSION_MODE_2K: fft = DIB3000_TRANSMISSION_MODE_2K; break;
- case TRANSMISSION_MODE_8K: fft = DIB3000_TRANSMISSION_MODE_8K; break;
- case TRANSMISSION_MODE_AUTO: break;
- default: return -EINVAL;
- }
- switch (ofdm->guard_interval) {
- case GUARD_INTERVAL_1_32: guard = DIB3000_GUARD_TIME_1_32; break;
- case GUARD_INTERVAL_1_16: guard = DIB3000_GUARD_TIME_1_16; break;
- case GUARD_INTERVAL_1_8: guard = DIB3000_GUARD_TIME_1_8; break;
- case GUARD_INTERVAL_1_4: guard = DIB3000_GUARD_TIME_1_4; break;
- case GUARD_INTERVAL_AUTO: break;
- default: return -EINVAL;
- }
- switch (ofdm->constellation) {
- case QPSK: qam = DIB3000_CONSTELLATION_QPSK; break;
- case QAM_16: qam = DIB3000_CONSTELLATION_16QAM; break;
- case QAM_64: qam = DIB3000_CONSTELLATION_64QAM; break;
- case QAM_AUTO: break;
- default: return -EINVAL;
- }
- switch (ofdm->hierarchy_information) {
- case HIERARCHY_NONE: /* fall through */
- case HIERARCHY_1: alpha = DIB3000_ALPHA_1; break;
- case HIERARCHY_2: alpha = DIB3000_ALPHA_2; break;
- case HIERARCHY_4: alpha = DIB3000_ALPHA_4; break;
- case HIERARCHY_AUTO: break;
- default: return -EINVAL;
- }
- if (ofdm->hierarchy_information == HIERARCHY_NONE) {
- hrch = DIB3000_HRCH_OFF;
- sel_hp = DIB3000_SELECT_HP;
- fe_cr = ofdm->code_rate_HP;
- } else if (ofdm->hierarchy_information != HIERARCHY_AUTO) {
- hrch = DIB3000_HRCH_ON;
- sel_hp = DIB3000_SELECT_LP;
- fe_cr = ofdm->code_rate_LP;
- }
- switch (fe_cr) {
- case FEC_1_2: cr = DIB3000_FEC_1_2; break;
- case FEC_2_3: cr = DIB3000_FEC_2_3; break;
- case FEC_3_4: cr = DIB3000_FEC_3_4; break;
- case FEC_5_6: cr = DIB3000_FEC_5_6; break;
- case FEC_7_8: cr = DIB3000_FEC_7_8; break;
- case FEC_NONE: break;
- case FEC_AUTO: break;
- default: return -EINVAL;
- }
+ struct dib3000mc_state *state = demod->demodulator_priv;
+ u16 bw_cfg[6] = { 0 };
+ u16 imp_bw_cfg[3] = { 0 };
+ u16 reg;
- wr(DIB3000MC_REG_DEMOD_PARM,DIB3000MC_DEMOD_PARM(alpha,qam,guard,fft));
- wr(DIB3000MC_REG_HRCH_PARM,DIB3000MC_HRCH_PARM(sel_hp,cr,hrch));
+/* settings here are for 27.7MHz */
+ switch (bw) {
+ case BANDWIDTH_8_MHZ:
+ bw_cfg[0] = 0x0019; bw_cfg[1] = 0x5c30; bw_cfg[2] = 0x0054; bw_cfg[3] = 0x88a0; bw_cfg[4] = 0x01a6; bw_cfg[5] = 0xab20;
+ imp_bw_cfg[0] = 0x04db; imp_bw_cfg[1] = 0x00db; imp_bw_cfg[2] = 0x00b7;
+ break;
- switch (fep->inversion) {
- case INVERSION_OFF:
- wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
+ case BANDWIDTH_7_MHZ:
+ bw_cfg[0] = 0x001c; bw_cfg[1] = 0xfba5; bw_cfg[2] = 0x0060; bw_cfg[3] = 0x9c25; bw_cfg[4] = 0x01e3; bw_cfg[5] = 0x0cb7;
+ imp_bw_cfg[0] = 0x04c0; imp_bw_cfg[1] = 0x00c0; imp_bw_cfg[2] = 0x00a0;
break;
- case INVERSION_AUTO: /* fall through */
- case INVERSION_ON:
- wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_ON);
+
+ case BANDWIDTH_6_MHZ:
+ bw_cfg[0] = 0x0021; bw_cfg[1] = 0xd040; bw_cfg[2] = 0x0070; bw_cfg[3] = 0xb62b; bw_cfg[4] = 0x0233; bw_cfg[5] = 0x8ed5;
+ imp_bw_cfg[0] = 0x04a5; imp_bw_cfg[1] = 0x00a5; imp_bw_cfg[2] = 0x0089;
break;
- default:
- return -EINVAL;
+
+ case 255 /* BANDWIDTH_5_MHZ */:
+ bw_cfg[0] = 0x0028; bw_cfg[1] = 0x9380; bw_cfg[2] = 0x0087; bw_cfg[3] = 0x4100; bw_cfg[4] = 0x02a4; bw_cfg[5] = 0x4500;
+ imp_bw_cfg[0] = 0x0489; imp_bw_cfg[1] = 0x0089; imp_bw_cfg[2] = 0x0072;
+ break;
+
+ default: return -EINVAL;
}
- seq = dib3000_seq
- [ofdm->transmission_mode == TRANSMISSION_MODE_AUTO]
- [ofdm->guard_interval == GUARD_INTERVAL_AUTO]
- [fep->inversion == INVERSION_AUTO];
-
- deb_setf("seq? %d\n", seq);
- wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS(seq,1));
- *auto_val = ofdm->constellation == QAM_AUTO ||
- ofdm->hierarchy_information == HIERARCHY_AUTO ||
- ofdm->guard_interval == GUARD_INTERVAL_AUTO ||
- ofdm->transmission_mode == TRANSMISSION_MODE_AUTO ||
- fe_cr == FEC_AUTO ||
- fep->inversion == INVERSION_AUTO;
+ for (reg = 6; reg < 12; reg++)
+ dib3000mc_write_word(state, reg, bw_cfg[reg - 6]);
+ dib3000mc_write_word(state, 12, 0x0000);
+ dib3000mc_write_word(state, 13, 0x03e8);
+ dib3000mc_write_word(state, 14, 0x0000);
+ dib3000mc_write_word(state, 15, 0x03f2);
+ dib3000mc_write_word(state, 16, 0x0001);
+ dib3000mc_write_word(state, 17, 0xb0d0);
+ // P_sec_len
+ dib3000mc_write_word(state, 18, 0x0393);
+ dib3000mc_write_word(state, 19, 0x8700);
+
+ for (reg = 55; reg < 58; reg++)
+ dib3000mc_write_word(state, reg, imp_bw_cfg[reg - 55]);
+
+ // Timing configuration
+ dib3000mc_set_timing(state, 0, bw, 0);
+
return 0;
}
-static int dib3000mc_get_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep)
+static u16 impulse_noise_val[29] =
+
{
- struct dib3000_state* state = fe->demodulator_priv;
- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
- fe_code_rate_t *cr;
- u16 tps_val,cr_val;
- int inv_test1,inv_test2;
- u32 dds_val, threshold = 0x1000000;
-
- if (!(rd(DIB3000MC_REG_LOCK_507) & DIB3000MC_LOCK_507))
- return 0;
-
- dds_val = (rd(DIB3000MC_REG_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_DDS_FREQ_LSB);
- deb_getf("DDS_FREQ: %6x\n",dds_val);
- if (dds_val < threshold)
- inv_test1 = 0;
- else if (dds_val == threshold)
- inv_test1 = 1;
- else
- inv_test1 = 2;
-
- dds_val = (rd(DIB3000MC_REG_SET_DDS_FREQ_MSB) << 16) + rd(DIB3000MC_REG_SET_DDS_FREQ_LSB);
- deb_getf("DDS_SET_FREQ: %6x\n",dds_val);
- if (dds_val < threshold)
- inv_test2 = 0;
- else if (dds_val == threshold)
- inv_test2 = 1;
+ 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c, 0x3ffe, 0x7f3,
+ 0x2d94, 0x76, 0x53d, 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3, 0x3feb, 0x7d2,
+ 0x365e, 0x76, 0x48c, 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0000, 0xd
+};
+
+static void dib3000mc_set_impulse_noise(struct dib3000mc_state *state, u8 mode, s16 nfft)
+{
+ u16 i;
+ for (i = 58; i < 87; i++)
+ dib3000mc_write_word(state, i, impulse_noise_val[i-58]);
+
+ if (nfft == 1) {
+ dib3000mc_write_word(state, 58, 0x3b);
+ dib3000mc_write_word(state, 84, 0x00);
+ dib3000mc_write_word(state, 85, 0x8200);
+ }
+
+ dib3000mc_write_word(state, 34, 0x1294);
+ dib3000mc_write_word(state, 35, 0x1ff8);
+ if (mode == 1)
+ dib3000mc_write_word(state, 55, dib3000mc_read_word(state, 55) | (1 << 10));
+}
+
+static int dib3000mc_init(struct dvb_frontend *demod)
+{
+ struct dib3000mc_state *state = demod->demodulator_priv;
+ struct dibx000_agc_config *agc = state->cfg->agc;
+
+ // Restart Configuration
+ dib3000mc_write_word(state, 1027, 0x8000);
+ dib3000mc_write_word(state, 1027, 0x0000);
+
+ // power up the demod + mobility configuration
+ dib3000mc_write_word(state, 140, 0x0000);
+ dib3000mc_write_word(state, 1031, 0);
+
+ if (state->cfg->mobile_mode) {
+ dib3000mc_write_word(state, 139, 0x0000);
+ dib3000mc_write_word(state, 141, 0x0000);
+ dib3000mc_write_word(state, 175, 0x0002);
+ dib3000mc_write_word(state, 1032, 0x0000);
+ } else {
+ dib3000mc_write_word(state, 139, 0x0001);
+ dib3000mc_write_word(state, 141, 0x0000);
+ dib3000mc_write_word(state, 175, 0x0000);
+ dib3000mc_write_word(state, 1032, 0x012C);
+ }
+ dib3000mc_write_word(state, 1033, 0x0000);
+
+ // P_clk_cfg
+ dib3000mc_write_word(state, 1037, 0x3130);
+
+ // other configurations
+
+ // P_ctrl_sfreq
+ dib3000mc_write_word(state, 33, (5 << 0));
+ dib3000mc_write_word(state, 88, (1 << 10) | (0x10 << 0));
+
+ // Phase noise control
+ // P_fft_phacor_inh, P_fft_phacor_cpe, P_fft_powrange
+ dib3000mc_write_word(state, 99, (1 << 9) | (0x20 << 0));
+
+ if (state->cfg->phase_noise_mode == 0)
+ dib3000mc_write_word(state, 111, 0x00);
else
- inv_test2 = 2;
+ dib3000mc_write_word(state, 111, 0x02);
+
+ // P_agc_global
+ dib3000mc_write_word(state, 50, 0x8000);
+
+ // agc setup misc
+ dib3000mc_setup_pwm_state(state);
+
+ // P_agc_counter_lock
+ dib3000mc_write_word(state, 53, 0x87);
+ // P_agc_counter_unlock
+ dib3000mc_write_word(state, 54, 0x87);
+
+ /* agc */
+ dib3000mc_write_word(state, 36, state->cfg->max_time);
+ dib3000mc_write_word(state, 37, (state->cfg->agc_command1 << 13) | (state->cfg->agc_command2 << 12) | (0x1d << 0));
+ dib3000mc_write_word(state, 38, state->cfg->pwm3_value);
+ dib3000mc_write_word(state, 39, state->cfg->ln_adc_level);
+
+ // set_agc_loop_Bw
+ dib3000mc_write_word(state, 40, 0x0179);
+ dib3000mc_write_word(state, 41, 0x03f0);
+
+ dib3000mc_write_word(state, 42, agc->agc1_max);
+ dib3000mc_write_word(state, 43, agc->agc1_min);
+ dib3000mc_write_word(state, 44, agc->agc2_max);
+ dib3000mc_write_word(state, 45, agc->agc2_min);
+ dib3000mc_write_word(state, 46, (agc->agc1_pt1 << 8) | agc->agc1_pt2);
+ dib3000mc_write_word(state, 47, (agc->agc1_slope1 << 8) | agc->agc1_slope2);
+ dib3000mc_write_word(state, 48, (agc->agc2_pt1 << 8) | agc->agc2_pt2);
+ dib3000mc_write_word(state, 49, (agc->agc2_slope1 << 8) | agc->agc2_slope2);
+
+// Begin: TimeOut registers
+ // P_pha3_thres
+ dib3000mc_write_word(state, 110, 3277);
+ // P_timf_alpha = 6, P_corm_alpha = 6, P_corm_thres = 0x80
+ dib3000mc_write_word(state, 26, 0x6680);
+ // lock_mask0
+ dib3000mc_write_word(state, 1, 4);
+ // lock_mask1
+ dib3000mc_write_word(state, 2, 4);
+ // lock_mask2
+ dib3000mc_write_word(state, 3, 0x1000);
+ // P_search_maxtrial=1
+ dib3000mc_write_word(state, 5, 1);
+
+ dib3000mc_set_bandwidth(&state->demod, BANDWIDTH_8_MHZ);
+
+ // div_lock_mask
+ dib3000mc_write_word(state, 4, 0x814);
+
+ dib3000mc_write_word(state, 21, (1 << 9) | 0x164);
+ dib3000mc_write_word(state, 22, 0x463d);
+
+ // Spurious rm cfg
+ // P_cspu_regul, P_cspu_win_cut
+ dib3000mc_write_word(state, 120, 0x200f);
+ // P_adp_selec_monit
+ dib3000mc_write_word(state, 134, 0);
+
+ // Fec cfg
+ dib3000mc_write_word(state, 195, 0x10);
+
+ // diversity register: P_dvsy_sync_wait..
+ dib3000mc_write_word(state, 180, 0x2FF0);
+
+ // Impulse noise configuration
+ dib3000mc_set_impulse_noise(state, 0, 1);
+
+ // output mode set-up
+ dib3000mc_set_output_mode(state, OUTMODE_HIGH_Z);
+
+ /* close the i2c-gate */
+ dib3000mc_write_word(state, 769, (1 << 7) );
- fep->inversion =
- ((inv_test2 == 2) && (inv_test1==1 || inv_test1==0)) ||
- ((inv_test2 == 0) && (inv_test1==1 || inv_test1==2)) ?
- INVERSION_ON : INVERSION_OFF;
+ return 0;
+}
- deb_getf("inversion %d %d, %d\n", inv_test2, inv_test1, fep->inversion);
+static int dib3000mc_sleep(struct dvb_frontend *demod)
+{
+ struct dib3000mc_state *state = demod->demodulator_priv;
- fep->frequency = state->last_tuned_freq;
- fep->u.ofdm.bandwidth= state->last_tuned_bw;
+ dib3000mc_write_word(state, 1031, 0xFFFF);
+ dib3000mc_write_word(state, 1032, 0xFFFF);
+ dib3000mc_write_word(state, 1033, 0xFFF0);
- tps_val = rd(DIB3000MC_REG_TUNING_PARM);
+ return 0;
+}
- switch (DIB3000MC_TP_QAM(tps_val)) {
- case DIB3000_CONSTELLATION_QPSK:
- deb_getf("QPSK ");
- ofdm->constellation = QPSK;
- break;
- case DIB3000_CONSTELLATION_16QAM:
- deb_getf("QAM16 ");
- ofdm->constellation = QAM_16;
+static void dib3000mc_set_adp_cfg(struct dib3000mc_state *state, s16 qam)
+{
+ u16 cfg[4] = { 0 },reg;
+ switch (qam) {
+ case 0:
+ cfg[0] = 0x099a; cfg[1] = 0x7fae; cfg[2] = 0x0333; cfg[3] = 0x7ff0;
break;
- case DIB3000_CONSTELLATION_64QAM:
- deb_getf("QAM64 ");
- ofdm->constellation = QAM_64;
+ case 1:
+ cfg[0] = 0x023d; cfg[1] = 0x7fdf; cfg[2] = 0x00a4; cfg[3] = 0x7ff0;
break;
- default:
- err("Unexpected constellation returned by TPS (%d)", tps_val);
+ case 2:
+ cfg[0] = 0x0148; cfg[1] = 0x7ff0; cfg[2] = 0x00a4; cfg[3] = 0x7ff8;
break;
}
+ for (reg = 129; reg < 133; reg++)
+ dib3000mc_write_word(state, reg, cfg[reg - 129]);
+}
- if (DIB3000MC_TP_HRCH(tps_val)) {
- deb_getf("HRCH ON ");
- cr = &ofdm->code_rate_LP;
- ofdm->code_rate_HP = FEC_NONE;
- switch (DIB3000MC_TP_ALPHA(tps_val)) {
- case DIB3000_ALPHA_0:
- deb_getf("HIERARCHY_NONE ");
- ofdm->hierarchy_information = HIERARCHY_NONE;
- break;
- case DIB3000_ALPHA_1:
- deb_getf("HIERARCHY_1 ");
- ofdm->hierarchy_information = HIERARCHY_1;
- break;
- case DIB3000_ALPHA_2:
- deb_getf("HIERARCHY_2 ");
- ofdm->hierarchy_information = HIERARCHY_2;
- break;
- case DIB3000_ALPHA_4:
- deb_getf("HIERARCHY_4 ");
- ofdm->hierarchy_information = HIERARCHY_4;
- break;
- default:
- err("Unexpected ALPHA value returned by TPS (%d)", tps_val);
- break;
- }
- cr_val = DIB3000MC_TP_FEC_CR_LP(tps_val);
- } else {
- deb_getf("HRCH OFF ");
- cr = &ofdm->code_rate_HP;
- ofdm->code_rate_LP = FEC_NONE;
- ofdm->hierarchy_information = HIERARCHY_NONE;
- cr_val = DIB3000MC_TP_FEC_CR_HP(tps_val);
- }
+static void dib3000mc_set_channel_cfg(struct dib3000mc_state *state, struct dibx000_ofdm_channel *chan, u16 seq)
+{
+ u16 tmp;
- switch (cr_val) {
- case DIB3000_FEC_1_2:
- deb_getf("FEC_1_2 ");
- *cr = FEC_1_2;
- break;
- case DIB3000_FEC_2_3:
- deb_getf("FEC_2_3 ");
- *cr = FEC_2_3;
- break;
- case DIB3000_FEC_3_4:
- deb_getf("FEC_3_4 ");
- *cr = FEC_3_4;
- break;
- case DIB3000_FEC_5_6:
- deb_getf("FEC_5_6 ");
- *cr = FEC_4_5;
- break;
- case DIB3000_FEC_7_8:
- deb_getf("FEC_7_8 ");
- *cr = FEC_7_8;
- break;
- default:
- err("Unexpected FEC returned by TPS (%d)", tps_val);
- break;
- }
+ dib3000mc_set_timing(state, chan->nfft, chan->Bw, 0);
- switch (DIB3000MC_TP_GUARD(tps_val)) {
- case DIB3000_GUARD_TIME_1_32:
- deb_getf("GUARD_INTERVAL_1_32 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_32;
- break;
- case DIB3000_GUARD_TIME_1_16:
- deb_getf("GUARD_INTERVAL_1_16 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_16;
- break;
- case DIB3000_GUARD_TIME_1_8:
- deb_getf("GUARD_INTERVAL_1_8 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_8;
- break;
- case DIB3000_GUARD_TIME_1_4:
- deb_getf("GUARD_INTERVAL_1_4 ");
- ofdm->guard_interval = GUARD_INTERVAL_1_4;
- break;
- default:
- err("Unexpected Guard Time returned by TPS (%d)", tps_val);
- break;
- }
+// if (boost)
+// dib3000mc_write_word(state, 100, (11 << 6) + 6);
+// else
+ dib3000mc_write_word(state, 100, (16 << 6) + 9);
- switch (DIB3000MC_TP_FFT(tps_val)) {
- case DIB3000_TRANSMISSION_MODE_2K:
- deb_getf("TRANSMISSION_MODE_2K ");
- ofdm->transmission_mode = TRANSMISSION_MODE_2K;
- break;
- case DIB3000_TRANSMISSION_MODE_8K:
- deb_getf("TRANSMISSION_MODE_8K ");
- ofdm->transmission_mode = TRANSMISSION_MODE_8K;
- break;
- default:
- err("unexpected transmission mode return by TPS (%d)", tps_val);
- break;
- }
- deb_getf("\n");
+ dib3000mc_write_word(state, 1027, 0x0800);
+ dib3000mc_write_word(state, 1027, 0x0000);
- return 0;
+ //Default cfg isi offset adp
+ dib3000mc_write_word(state, 26, 0x6680);
+ dib3000mc_write_word(state, 29, 0x1273);
+ dib3000mc_write_word(state, 33, 5);
+ dib3000mc_set_adp_cfg(state, 1);
+ dib3000mc_write_word(state, 133, 15564);
+
+ dib3000mc_write_word(state, 12 , 0x0);
+ dib3000mc_write_word(state, 13 , 0x3e8);
+ dib3000mc_write_word(state, 14 , 0x0);
+ dib3000mc_write_word(state, 15 , 0x3f2);
+
+ dib3000mc_write_word(state, 93,0);
+ dib3000mc_write_word(state, 94,0);
+ dib3000mc_write_word(state, 95,0);
+ dib3000mc_write_word(state, 96,0);
+ dib3000mc_write_word(state, 97,0);
+ dib3000mc_write_word(state, 98,0);
+
+ dib3000mc_set_impulse_noise(state, 0, chan->nfft);
+
+ tmp = ((chan->nfft & 0x1) << 7) | (chan->guard << 5) | (chan->nqam << 3) | chan->vit_alpha;
+ dib3000mc_write_word(state, 0, tmp);
+
+ dib3000mc_write_word(state, 5, seq);
+
+ tmp = (chan->vit_hrch << 4) | (chan->vit_select_hp);
+ if (!chan->vit_hrch || (chan->vit_hrch && chan->vit_select_hp))
+ tmp |= chan->vit_code_rate_hp << 1;
+ else
+ tmp |= chan->vit_code_rate_lp << 1;
+ dib3000mc_write_word(state, 181, tmp);
+
+ // diversity synchro delay
+ tmp = dib3000mc_read_word(state, 180) & 0x000f;
+ tmp |= ((chan->nfft == 0) ? 64 : 256) * ((1 << (chan->guard)) * 3 / 2) << 4; // add 50% SFN margin
+ dib3000mc_write_word(state, 180, tmp);
+
+ // restart demod
+ tmp = dib3000mc_read_word(state, 0);
+ dib3000mc_write_word(state, 0, tmp | (1 << 9));
+ dib3000mc_write_word(state, 0, tmp);
+
+ msleep(30);
+
+ dib3000mc_set_impulse_noise(state, state->cfg->impulse_noise_mode, chan->nfft);
}
-static int dib3000mc_set_frontend(struct dvb_frontend* fe,
- struct dvb_frontend_parameters *fep, int tuner)
+static int dib3000mc_autosearch_start(struct dvb_frontend *demod, struct dibx000_ofdm_channel *chan)
{
- struct dib3000_state* state = fe->demodulator_priv;
- struct dvb_ofdm_parameters *ofdm = &fep->u.ofdm;
- int search_state,auto_val;
- u16 val;
+ struct dib3000mc_state *state = demod->demodulator_priv;
+ u16 reg;
+// u32 val;
+ struct dibx000_ofdm_channel fchan;
- if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */
- fe->ops.tuner_ops.set_params(fe, fep);
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
-
- state->last_tuned_freq = fep->frequency;
- // if (!scanboost) {
- dib3000mc_set_timing(state,0,ofdm->transmission_mode,ofdm->bandwidth);
- dib3000mc_init_auto_scan(state, ofdm->bandwidth, 0);
- state->last_tuned_bw = ofdm->bandwidth;
-
- wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_AGC);
- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
-
- /* Default cfg isi offset adp */
- wr_foreach(dib3000mc_reg_offset,dib3000mc_offset[0]);
-
- wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT | DIB3000MC_ISI_INHIBIT);
- dib3000mc_set_adp_cfg(state,ofdm->constellation);
- wr(DIB3000MC_REG_UNK_133,DIB3000MC_UNK_133);
-
- wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
- /* power smoothing */
- if (ofdm->bandwidth != BANDWIDTH_8_MHZ) {
- wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[0]);
- } else {
- wr_foreach(dib3000mc_reg_bw,dib3000mc_bw[3]);
- }
- auto_val = 0;
- dib3000mc_set_general_cfg(state,fep,&auto_val);
- dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
-
- val = rd(DIB3000MC_REG_DEMOD_PARM);
- wr(DIB3000MC_REG_DEMOD_PARM,val|DIB3000MC_DEMOD_RST_DEMOD_ON);
- wr(DIB3000MC_REG_DEMOD_PARM,val);
- // }
- msleep(70);
-
- /* something has to be auto searched */
- if (auto_val) {
- int as_count=0;
-
- deb_setf("autosearch enabled.\n");
-
- val = rd(DIB3000MC_REG_DEMOD_PARM);
- wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
- wr(DIB3000MC_REG_DEMOD_PARM,val);
-
- while ((search_state = dib3000_search_status(
- rd(DIB3000MC_REG_AS_IRQ),1)) < 0 && as_count++ < 100)
- msleep(10);
-
- deb_info("search_state after autosearch %d after %d checks\n",search_state,as_count);
-
- if (search_state == 1) {
- struct dvb_frontend_parameters feps;
- if (dib3000mc_get_frontend(fe, &feps) == 0) {
- deb_setf("reading tuning data from frontend succeeded.\n");
- return dib3000mc_set_frontend(fe, &feps, 0);
- }
- }
- } else {
- dib3000mc_set_impulse_noise(state,0,ofdm->transmission_mode,ofdm->bandwidth);
- wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
- dib3000mc_set_adp_cfg(state,ofdm->constellation);
-
- /* set_offset_cfg */
- wr_foreach(dib3000mc_reg_offset,
- dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
- }
- } else { /* second call, after autosearch (fka: set_WithKnownParams) */
-// dib3000mc_set_timing(state,1,ofdm->transmission_mode,ofdm->bandwidth);
+ INIT_OFDM_CHANNEL(&fchan);
+ fchan = *chan;
- auto_val = 0;
- dib3000mc_set_general_cfg(state,fep,&auto_val);
- if (auto_val)
- deb_info("auto_val is true, even though an auto search was already performed.\n");
- dib3000mc_set_impulse_noise(state,0,ofdm->constellation,ofdm->bandwidth);
+ /* a channel for autosearch */
+ reg = 0;
+ if (chan->nfft == -1 && chan->guard == -1) reg = 7;
+ if (chan->nfft == -1 && chan->guard != -1) reg = 2;
+ if (chan->nfft != -1 && chan->guard == -1) reg = 3;
- val = rd(DIB3000MC_REG_DEMOD_PARM);
- wr(DIB3000MC_REG_DEMOD_PARM,val | DIB3000MC_DEMOD_RST_AUTO_SRCH_ON);
- wr(DIB3000MC_REG_DEMOD_PARM,val);
+ fchan.nfft = 1; fchan.guard = 0; fchan.nqam = 2;
+ fchan.vit_alpha = 1; fchan.vit_code_rate_hp = 2; fchan.vit_code_rate_lp = 2;
+ fchan.vit_hrch = 0; fchan.vit_select_hp = 1;
- msleep(30);
+ dib3000mc_set_channel_cfg(state, &fchan, reg);
+
+ reg = dib3000mc_read_word(state, 0);
+ dib3000mc_write_word(state, 0, reg | (1 << 8));
+ dib3000mc_read_word(state, 511);
+ dib3000mc_write_word(state, 0, reg);
- wr(DIB3000MC_REG_ISI,DIB3000MC_ISI_DEFAULT|DIB3000MC_ISI_ACTIVATE);
- dib3000mc_set_adp_cfg(state,ofdm->constellation);
- wr_foreach(dib3000mc_reg_offset,
- dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
- }
return 0;
}
-static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
+static int dib3000mc_autosearch_is_irq(struct dvb_frontend *demod)
{
- struct dib3000_state *state = fe->demodulator_priv;
- deb_info("init start\n");
+ struct dib3000mc_state *state = demod->demodulator_priv;
+ u16 irq_pending = dib3000mc_read_word(state, 511);
- state->timing_offset = 0;
- state->timing_offset_comp_done = 0;
+ if (irq_pending & 0x1) // failed
+ return 1;
- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_CONFIG);
- wr(DIB3000MC_REG_RESTART,DIB3000MC_RESTART_OFF);
- wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_UP);
- wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_PUP_MOBILE);
- wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_UP);
- wr(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_INIT);
+ if (irq_pending & 0x2) // succeeded
+ return 2;
- wr(DIB3000MC_REG_RST_UNC,DIB3000MC_RST_UNC_OFF);
- wr(DIB3000MC_REG_UNK_19,DIB3000MC_UNK_19);
+ return 0; // still pending
+}
- wr(33,5);
- wr(36,81);
- wr(DIB3000MC_REG_UNK_88,DIB3000MC_UNK_88);
+static int dib3000mc_tune(struct dvb_frontend *demod, struct dibx000_ofdm_channel *ch)
+{
+ struct dib3000mc_state *state = demod->demodulator_priv;
- wr(DIB3000MC_REG_UNK_99,DIB3000MC_UNK_99);
- wr(DIB3000MC_REG_UNK_111,DIB3000MC_UNK_111_PH_N_MODE_0); /* phase noise algo off */
+ // ** configure demod **
+ dib3000mc_set_channel_cfg(state, ch, 0);
- /* mobile mode - portable reception */
- wr_foreach(dib3000mc_reg_mobile_mode,dib3000mc_mobile_mode[1]);
+ // activates isi
+ dib3000mc_write_word(state, 29, 0x1073);
-/* TUNER_PANASONIC_ENV57H12D5: */
- wr_foreach(dib3000mc_reg_agc_bandwidth,dib3000mc_agc_bandwidth);
- wr_foreach(dib3000mc_reg_agc_bandwidth_general,dib3000mc_agc_bandwidth_general);
- wr_foreach(dib3000mc_reg_agc,dib3000mc_agc_tuner[1]);
+ dib3000mc_set_adp_cfg(state, (u8)ch->nqam);
- wr(DIB3000MC_REG_UNK_110,DIB3000MC_UNK_110);
- wr(26,0x6680);
- wr(DIB3000MC_REG_UNK_1,DIB3000MC_UNK_1);
- wr(DIB3000MC_REG_UNK_2,DIB3000MC_UNK_2);
- wr(DIB3000MC_REG_UNK_3,DIB3000MC_UNK_3);
- wr(DIB3000MC_REG_SEQ_TPS,DIB3000MC_SEQ_TPS_DEFAULT);
+ if (ch->nfft == 1) {
+ dib3000mc_write_word(state, 26, 38528);
+ dib3000mc_write_word(state, 33, 8);
+ } else {
+ dib3000mc_write_word(state, 26, 30336);
+ dib3000mc_write_word(state, 33, 6);
+ }
- wr_foreach(dib3000mc_reg_bandwidth,dib3000mc_bandwidth_8mhz);
- wr_foreach(dib3000mc_reg_bandwidth_general,dib3000mc_bandwidth_general);
+ if (dib3000mc_read_word(state, 509) & 0x80)
+ dib3000mc_set_timing(state, ch->nfft, ch->Bw, 1);
- wr(DIB3000MC_REG_UNK_4,DIB3000MC_UNK_4);
+ return 0;
+}
- wr(DIB3000MC_REG_SET_DDS_FREQ_MSB,DIB3000MC_DDS_FREQ_MSB_INV_OFF);
- wr(DIB3000MC_REG_SET_DDS_FREQ_LSB,DIB3000MC_DDS_FREQ_LSB);
+struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating)
+{
+ struct dib3000mc_state *st = demod->demodulator_priv;
+ return dibx000_get_i2c_adapter(&st->i2c_master, DIBX000_I2C_INTERFACE_TUNER, gating);
+}
- dib3000mc_set_timing(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
-// wr_foreach(dib3000mc_reg_timing_freq,dib3000mc_timing_freq[3]);
+EXPORT_SYMBOL(dib3000mc_get_tuner_i2c_master);
- wr(DIB3000MC_REG_UNK_120,DIB3000MC_UNK_120);
- wr(DIB3000MC_REG_UNK_134,DIB3000MC_UNK_134);
- wr(DIB3000MC_REG_FEC_CFG,DIB3000MC_FEC_CFG);
+static int dib3000mc_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ u16 tps = dib3000mc_read_word(state,458);
- wr(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
+ fep->inversion = INVERSION_AUTO;
- dib3000mc_set_impulse_noise(state,0,TRANSMISSION_MODE_8K,BANDWIDTH_8_MHZ);
+ fep->u.ofdm.bandwidth = state->current_bandwidth;
-/* output mode control, just the MPEG2_SLAVE */
-// set_or(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
- wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_SLAVE);
- wr(DIB3000MC_REG_SMO_MODE,DIB3000MC_SMO_MODE_SLAVE);
- wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_SLAVE);
- wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_SLAVE);
+ switch ((tps >> 8) & 0x1) {
+ case 0: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_2K; break;
+ case 1: fep->u.ofdm.transmission_mode = TRANSMISSION_MODE_8K; break;
+ }
-/* MPEG2_PARALLEL_CONTINUOUS_CLOCK
- wr(DIB3000MC_REG_OUTMODE,
- DIB3000MC_SET_OUTMODE(DIB3000MC_OM_PAR_CONT_CLK,
- rd(DIB3000MC_REG_OUTMODE)));
+ switch (tps & 0x3) {
+ case 0: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_32; break;
+ case 1: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_16; break;
+ case 2: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_8; break;
+ case 3: fep->u.ofdm.guard_interval = GUARD_INTERVAL_1_4; break;
+ }
- wr(DIB3000MC_REG_SMO_MODE,
- DIB3000MC_SMO_MODE_DEFAULT |
- DIB3000MC_SMO_MODE_188);
+ switch ((tps >> 13) & 0x3) {
+ case 0: fep->u.ofdm.constellation = QPSK; break;
+ case 1: fep->u.ofdm.constellation = QAM_16; break;
+ case 2:
+ default: fep->u.ofdm.constellation = QAM_64; break;
+ }
- wr(DIB3000MC_REG_FIFO_THRESHOLD,DIB3000MC_FIFO_THRESHOLD_DEFAULT);
- wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
-*/
+ /* as long as the frontend_param structure is fixed for hierarchical transmission I refuse to use it */
+ /* (tps >> 12) & 0x1 == hrch is used, (tps >> 9) & 0x7 == alpha */
-/* diversity */
- wr(DIB3000MC_REG_DIVERSITY1,DIB3000MC_DIVERSITY1_DEFAULT);
- wr(DIB3000MC_REG_DIVERSITY2,DIB3000MC_DIVERSITY2_DEFAULT);
+ fep->u.ofdm.hierarchy_information = HIERARCHY_NONE;
+ switch ((tps >> 5) & 0x7) {
+ case 1: fep->u.ofdm.code_rate_HP = FEC_1_2; break;
+ case 2: fep->u.ofdm.code_rate_HP = FEC_2_3; break;
+ case 3: fep->u.ofdm.code_rate_HP = FEC_3_4; break;
+ case 5: fep->u.ofdm.code_rate_HP = FEC_5_6; break;
+ case 7:
+ default: fep->u.ofdm.code_rate_HP = FEC_7_8; break;
- set_and(DIB3000MC_REG_DIVERSITY3,DIB3000MC_DIVERSITY3_IN_OFF);
+ }
- set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
+ switch ((tps >> 2) & 0x7) {
+ case 1: fep->u.ofdm.code_rate_LP = FEC_1_2; break;
+ case 2: fep->u.ofdm.code_rate_LP = FEC_2_3; break;
+ case 3: fep->u.ofdm.code_rate_LP = FEC_3_4; break;
+ case 5: fep->u.ofdm.code_rate_LP = FEC_5_6; break;
+ case 7:
+ default: fep->u.ofdm.code_rate_LP = FEC_7_8; break;
+ }
- deb_info("init end\n");
return 0;
}
-static int dib3000mc_read_status(struct dvb_frontend* fe, fe_status_t *stat)
+
+static int dib3000mc_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
{
- struct dib3000_state* state = fe->demodulator_priv;
- u16 lock = rd(DIB3000MC_REG_LOCKING);
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ struct dibx000_ofdm_channel ch;
+
+ INIT_OFDM_CHANNEL(&ch);
+ FEP2DIB(fep,&ch);
+
+ state->current_bandwidth = fep->u.ofdm.bandwidth;
+ dib3000mc_set_bandwidth(fe, fep->u.ofdm.bandwidth);
+
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fep);
+ msleep(100);
+ }
+
+ if (fep->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ||
+ fep->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ||
+ fep->u.ofdm.constellation == QAM_AUTO ||
+ fep->u.ofdm.code_rate_HP == FEC_AUTO) {
+ int i = 100, found;
+
+ dib3000mc_autosearch_start(fe, &ch);
+ do {
+ msleep(1);
+ found = dib3000mc_autosearch_is_irq(fe);
+ } while (found == 0 && i--);
+
+ dprintk("autosearch returns: %d\n",found);
+ if (found == 0 || found == 1)
+ return 0; // no channel found
+
+ dib3000mc_get_frontend(fe, fep);
+ FEP2DIB(fep,&ch);
+ }
+
+ /* make this a config parameter */
+ dib3000mc_set_output_mode(state, OUTMODE_MPEG2_FIFO);
+
+ return dib3000mc_tune(fe, &ch);
+}
+
+static int dib3000mc_read_status(struct dvb_frontend *fe, fe_status_t *stat)
+{
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ u16 lock = dib3000mc_read_word(state, 509);
*stat = 0;
- if (DIB3000MC_AGC_LOCK(lock))
+
+ if (lock & 0x8000)
*stat |= FE_HAS_SIGNAL;
- if (DIB3000MC_CARRIER_LOCK(lock))
+ if (lock & 0x3000)
*stat |= FE_HAS_CARRIER;
- if (DIB3000MC_TPS_LOCK(lock))
+ if (lock & 0x0100)
*stat |= FE_HAS_VITERBI;
- if (DIB3000MC_MPEG_SYNC_LOCK(lock))
- *stat |= (FE_HAS_SYNC | FE_HAS_LOCK);
-
- deb_stat("actual status is %2x fifo_level: %x,244: %x, 206: %x, 207: %x, 1040: %x\n",*stat,rd(510),rd(244),rd(206),rd(207),rd(1040));
+ if (lock & 0x0010)
+ *stat |= FE_HAS_SYNC;
+ if (lock & 0x0008)
+ *stat |= FE_HAS_LOCK;
return 0;
}
-static int dib3000mc_read_ber(struct dvb_frontend* fe, u32 *ber)
+static int dib3000mc_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- struct dib3000_state* state = fe->demodulator_priv;
- *ber = ((rd(DIB3000MC_REG_BER_MSB) << 16) | rd(DIB3000MC_REG_BER_LSB));
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ *ber = (dib3000mc_read_word(state, 500) << 16) | dib3000mc_read_word(state, 501);
return 0;
}
-static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+static int dib3000mc_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
{
- struct dib3000_state* state = fe->demodulator_priv;
-
- *unc = rd(DIB3000MC_REG_PACKET_ERRORS);
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ *unc = dib3000mc_read_word(state, 508);
return 0;
}
-/* see dib3000mb.c for calculation comments */
-static int dib3000mc_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+static int dib3000mc_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
- struct dib3000_state* state = fe->demodulator_priv;
- u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB);
- *strength = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
-
- deb_stat("signal: mantisse = %d, exponent = %d\n",(*strength >> 8) & 0xff, *strength & 0xff);
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ u16 val = dib3000mc_read_word(state, 392);
+ *strength = 65535 - val;
return 0;
}
-/* see dib3000mb.c for calculation comments */
static int dib3000mc_read_snr(struct dvb_frontend* fe, u16 *snr)
{
- struct dib3000_state* state = fe->demodulator_priv;
- u16 val = rd(DIB3000MC_REG_SIGNAL_NOISE_LSB),
- val2 = rd(DIB3000MC_REG_SIGNAL_NOISE_MSB);
- u16 sig,noise;
-
- sig = (((val >> 6) & 0xff) << 8) + (val & 0x3f);
- noise = (((val >> 4) & 0xff) << 8) + ((val & 0xf) << 2) + ((val2 >> 14) & 0x3);
- if (noise == 0)
- *snr = 0xffff;
- else
- *snr = (u16) sig/noise;
-
- deb_stat("signal: mantisse = %d, exponent = %d\n",(sig >> 8) & 0xff, sig & 0xff);
- deb_stat("noise: mantisse = %d, exponent = %d\n",(noise >> 8) & 0xff, noise & 0xff);
- deb_stat("snr: %d\n",*snr);
- return 0;
-}
-
-static int dib3000mc_sleep(struct dvb_frontend* fe)
-{
- struct dib3000_state* state = fe->demodulator_priv;
-
- set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_PWR_DOWN);
- wr(DIB3000MC_REG_CLK_CFG_1,DIB3000MC_CLK_CFG_1_POWER_DOWN);
- wr(DIB3000MC_REG_CLK_CFG_2,DIB3000MC_CLK_CFG_2_POWER_DOWN);
- wr(DIB3000MC_REG_CLK_CFG_3,DIB3000MC_CLK_CFG_3_POWER_DOWN);
+ *snr = 0x0000;
return 0;
}
@@ -729,185 +731,145 @@ static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fr
return 0;
}
-static int dib3000mc_fe_init_nonmobile(struct dvb_frontend* fe)
+static void dib3000mc_release(struct dvb_frontend *fe)
{
- return dib3000mc_fe_init(fe, 0);
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ dibx000_exit_i2c_master(&state->i2c_master);
+ kfree(state);
}
-static int dib3000mc_set_frontend_and_tuner(struct dvb_frontend* fe, struct dvb_frontend_parameters *fep)
+int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff)
{
- return dib3000mc_set_frontend(fe, fep, 1);
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ dib3000mc_write_word(state, 212 + index, onoff ? (1 << 13) | pid : 0);
+ return 0;
}
+EXPORT_SYMBOL(dib3000mc_pid_control);
-static void dib3000mc_release(struct dvb_frontend* fe)
+int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
{
- struct dib3000_state *state = fe->demodulator_priv;
- kfree(state);
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ u16 tmp = dib3000mc_read_word(state, 206) & ~(1 << 4);
+ tmp |= (onoff << 4);
+ return dib3000mc_write_word(state, 206, tmp);
}
+EXPORT_SYMBOL(dib3000mc_pid_parse);
-/* pid filter and transfer stuff */
-static int dib3000mc_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
+void dib3000mc_set_config(struct dvb_frontend *fe, struct dib3000mc_config *cfg)
{
- struct dib3000_state *state = fe->demodulator_priv;
- pid = (onoff ? pid | DIB3000_ACTIVATE_PID_FILTERING : 0);
- wr(index+DIB3000MC_REG_FIRST_PID,pid);
- return 0;
+ struct dib3000mc_state *state = fe->demodulator_priv;
+ state->cfg = cfg;
}
+EXPORT_SYMBOL(dib3000mc_set_config);
-static int dib3000mc_fifo_control(struct dvb_frontend *fe, int onoff)
+int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[])
{
- struct dib3000_state *state = fe->demodulator_priv;
- u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
+ struct dib3000mc_state st = { .i2c_adap = i2c };
+ int k;
+ u8 new_addr;
+
+ static u8 DIB3000MC_I2C_ADDRESS[] = {20,22,24,26};
+
+ for (k = no_of_demods-1; k >= 0; k--) {
+ st.cfg = &cfg[k];
+
+ /* designated i2c address */
+ new_addr = DIB3000MC_I2C_ADDRESS[k];
+ st.i2c_addr = new_addr;
+ if (dib3000mc_identify(&st) != 0) {
+ st.i2c_addr = default_addr;
+ if (dib3000mc_identify(&st) != 0) {
+ dprintk("-E- DiB3000P/MC #%d: not identified\n", k);
+ return -ENODEV;
+ }
+ }
- deb_xfer("%s fifo\n",onoff ? "enabling" : "disabling");
+ dib3000mc_set_output_mode(&st, OUTMODE_MPEG2_PAR_CONT_CLK);
- if (onoff) {
- deb_xfer("%d %x\n",tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
- wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_FIFO_UNFLUSH);
- } else {
- deb_xfer("%d %x\n",tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
- wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_FIFO_FLUSH);
+ // set new i2c address and force divstr (Bit 1) to value 0 (Bit 0)
+ dib3000mc_write_word(&st, 1024, (new_addr << 3) | 0x1);
+ st.i2c_addr = new_addr;
}
- return 0;
-}
-static int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff)
-{
- struct dib3000_state *state = fe->demodulator_priv;
- u16 tmp = rd(DIB3000MC_REG_SMO_MODE);
-
- deb_xfer("%s pid parsing\n",onoff ? "enabling" : "disabling");
+ for (k = 0; k < no_of_demods; k++) {
+ st.cfg = &cfg[k];
+ st.i2c_addr = DIB3000MC_I2C_ADDRESS[k];
- if (onoff) {
- wr(DIB3000MC_REG_SMO_MODE,tmp | DIB3000MC_SMO_MODE_PID_PARSE);
- } else {
- wr(DIB3000MC_REG_SMO_MODE,tmp & DIB3000MC_SMO_MODE_NO_PID_PARSE);
- }
- return 0;
-}
+ dib3000mc_write_word(&st, 1024, st.i2c_addr << 3);
-static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr)
-{
- struct dib3000_state *state = fe->demodulator_priv;
- if (onoff) {
- wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_ENABLE(pll_addr));
- } else {
- wr(DIB3000MC_REG_TUNER, DIB3000_TUNER_WRITE_DISABLE(pll_addr));
+ /* turn off data output */
+ dib3000mc_set_output_mode(&st, OUTMODE_HIGH_Z);
}
return 0;
}
-
-static int dib3000mc_demod_init(struct dib3000_state *state)
-{
- u16 default_addr = 0x0a;
- /* first init */
- if (state->config.demod_address != default_addr) {
- deb_info("initializing the demod the first time. Setting demod addr to 0x%x\n",default_addr);
- wr(DIB3000MC_REG_ELEC_OUT,DIB3000MC_ELEC_OUT_DIV_OUT_ON);
- wr(DIB3000MC_REG_OUTMODE,DIB3000MC_OM_PAR_CONT_CLK);
-
- wr(DIB3000MC_REG_RST_I2C_ADDR,
- DIB3000MC_DEMOD_ADDR(default_addr) |
- DIB3000MC_DEMOD_ADDR_ON);
-
- state->config.demod_address = default_addr;
-
- wr(DIB3000MC_REG_RST_I2C_ADDR,
- DIB3000MC_DEMOD_ADDR(default_addr));
- } else
- deb_info("demod is already initialized. Demod addr: 0x%x\n",state->config.demod_address);
- return 0;
-}
-
+EXPORT_SYMBOL(dib3000mc_i2c_enumeration);
static struct dvb_frontend_ops dib3000mc_ops;
-struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config,
- struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops)
+struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
{
- struct dib3000_state* state = NULL;
- u16 devid;
+ struct dvb_frontend *demod;
+ struct dib3000mc_state *st;
+ st = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
+ if (st == NULL)
+ return NULL;
- /* allocate memory for the internal state */
- state = kzalloc(sizeof(struct dib3000_state), GFP_KERNEL);
- if (state == NULL)
- goto error;
+ st->cfg = cfg;
+ st->i2c_adap = i2c_adap;
+ st->i2c_addr = i2c_addr;
- /* setup the state */
- state->i2c = i2c;
- memcpy(&state->config,config,sizeof(struct dib3000_config));
+ demod = &st->demod;
+ demod->demodulator_priv = st;
+ memcpy(&st->demod.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
- /* check for the correct demod */
- if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM)
+ if (dib3000mc_identify(st) != 0)
goto error;
- devid = rd(DIB3000_REG_DEVICE_ID);
- if (devid != DIB3000MC_DEVICE_ID && devid != DIB3000P_DEVICE_ID)
- goto error;
+ dibx000_init_i2c_master(&st->i2c_master, DIB3000MC, st->i2c_adap, st->i2c_addr);
- switch (devid) {
- case DIB3000MC_DEVICE_ID:
- info("Found a DiBcom 3000M-C, interesting...");
- break;
- case DIB3000P_DEVICE_ID:
- info("Found a DiBcom 3000P.");
- break;
- }
-
- /* create dvb_frontend */
- memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
-
- /* set the xfer operations */
- xfer_ops->pid_parse = dib3000mc_pid_parse;
- xfer_ops->fifo_ctrl = dib3000mc_fifo_control;
- xfer_ops->pid_ctrl = dib3000mc_pid_control;
- xfer_ops->tuner_pass_ctrl = dib3000mc_tuner_pass_ctrl;
+ dib3000mc_write_word(st, 1037, 0x3130);
- dib3000mc_demod_init(state);
-
- return &state->frontend;
+ return demod;
error:
- kfree(state);
+ kfree(st);
return NULL;
}
EXPORT_SYMBOL(dib3000mc_attach);
static struct dvb_frontend_ops dib3000mc_ops = {
-
.info = {
- .name = "DiBcom 3000P/M-C DVB-T",
- .type = FE_OFDM,
- .frequency_min = 44250000,
- .frequency_max = 867250000,
- .frequency_stepsize = 62500,
+ .name = "DiBcom 3000MC/P",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 62500,
.caps = FE_CAN_INVERSION_AUTO |
- FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
- FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_RECOVER |
- FE_CAN_HIERARCHY_AUTO,
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
},
- .release = dib3000mc_release,
+ .release = dib3000mc_release,
- .init = dib3000mc_fe_init_nonmobile,
- .sleep = dib3000mc_sleep,
+ .init = dib3000mc_init,
+ .sleep = dib3000mc_sleep,
- .set_frontend = dib3000mc_set_frontend_and_tuner,
- .get_frontend = dib3000mc_get_frontend,
- .get_tune_settings = dib3000mc_fe_get_tune_settings,
+ .set_frontend = dib3000mc_set_frontend,
+ .get_tune_settings = dib3000mc_fe_get_tune_settings,
+ .get_frontend = dib3000mc_get_frontend,
- .read_status = dib3000mc_read_status,
- .read_ber = dib3000mc_read_ber,
+ .read_status = dib3000mc_read_status,
+ .read_ber = dib3000mc_read_ber,
.read_signal_strength = dib3000mc_read_signal_strength,
- .read_snr = dib3000mc_read_snr,
- .read_ucblocks = dib3000mc_read_unc_blocks,
+ .read_snr = dib3000mc_read_snr,
+ .read_ucblocks = dib3000mc_read_unc_blocks,
};
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Driver for the DiBcom 3000MC/P COFDM demodulator");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dib3000mc.h b/drivers/media/dvb/frontends/dib3000mc.h
new file mode 100644
index 000000000000..0d6fdef77538
--- /dev/null
+++ b/drivers/media/dvb/frontends/dib3000mc.h
@@ -0,0 +1,61 @@
+/*
+ * Driver for DiBcom DiB3000MC/P-demodulator.
+ *
+ * Copyright (C) 2004-6 DiBcom (http://www.dibcom.fr/)
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher\@desy.de)
+ *
+ * This code is partially based on the previous dib3000mc.c .
+ *
+ * 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, version 2.
+ */
+#ifndef DIB3000MC_H
+#define DIB3000MC_H
+
+#include "dibx000_common.h"
+
+struct dib3000mc_config {
+ struct dibx000_agc_config *agc;
+
+ u8 phase_noise_mode;
+ u8 impulse_noise_mode;
+
+ u8 pwm3_inversion;
+ u8 use_pwm3;
+ u16 pwm3_value;
+
+ u16 max_time;
+ u16 ln_adc_level;
+
+ u8 agc_command1 :1;
+ u8 agc_command2 :1;
+
+ u8 mobile_mode;
+
+ u8 output_mpeg2_in_188_bytes;
+};
+
+#define DEFAULT_DIB3000MC_I2C_ADDRESS 16
+#define DEFAULT_DIB3000P_I2C_ADDRESS 24
+
+#if defined(CONFIG_DVB_DIB3000MC) || defined(CONFIG_DVB_DIB3000MC_MODULE)
+extern struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg);
+#else
+static inline struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_DIB3000MC
+
+extern int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib3000mc_config cfg[]);
+
+extern struct i2c_adapter * dib3000mc_get_tuner_i2c_master(struct dvb_frontend *demod, int gating);
+
+extern int dib3000mc_pid_control(struct dvb_frontend *fe, int index, int pid,int onoff);
+extern int dib3000mc_pid_parse(struct dvb_frontend *fe, int onoff);
+
+extern void dib3000mc_set_config(struct dvb_frontend *, struct dib3000mc_config *);
+
+#endif
diff --git a/drivers/media/dvb/frontends/dib3000mc_priv.h b/drivers/media/dvb/frontends/dib3000mc_priv.h
deleted file mode 100644
index 2930aac7591b..000000000000
--- a/drivers/media/dvb/frontends/dib3000mc_priv.h
+++ /dev/null
@@ -1,428 +0,0 @@
-/*
- * dib3000mc_priv.h
- *
- * Copyright (C) 2004 Patrick Boettcher (patrick.boettcher@desy.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, version 2.
- *
- * for more information see dib3000mc.c .
- */
-
-#ifndef __DIB3000MC_PRIV_H__
-#define __DIB3000MC_PRIV_H__
-
-/*
- * Demodulator parameters
- * reg: 0 1 1 1 11 11 111
- * | | | | | |
- * | | | | | +-- alpha (000=0, 001=1, 010=2, 100=4)
- * | | | | +----- constellation (00=QPSK, 01=16QAM, 10=64QAM)
- * | | | +-------- guard (00=1/32, 01=1/16, 10=1/8, 11=1/4)
- * | | +----------- transmission mode (0=2k, 1=8k)
- * | |
- * | +-------------- restart autosearch for parameters
- * +---------------- restart the demodulator
- * reg: 181 1 111 1
- * | | |
- * | | +- FEC applies for HP or LP (0=LP, 1=HP)
- * | +---- FEC rate (001=1/2, 010=2/3, 011=3/4, 101=5/6, 111=7/8)
- * +------- hierarchy on (0=no, 1=yes)
- */
-
-/* demodulator tuning parameter and restart options */
-#define DIB3000MC_REG_DEMOD_PARM ( 0)
-#define DIB3000MC_DEMOD_PARM(a,c,g,t) ( \
- (0x7 & a) | \
- ((0x3 & c) << 3) | \
- ((0x3 & g) << 5) | \
- ((0x1 & t) << 7) )
-#define DIB3000MC_DEMOD_RST_AUTO_SRCH_ON (1 << 8)
-#define DIB3000MC_DEMOD_RST_AUTO_SRCH_OFF (0 << 8)
-#define DIB3000MC_DEMOD_RST_DEMOD_ON (1 << 9)
-#define DIB3000MC_DEMOD_RST_DEMOD_OFF (0 << 9)
-
-/* register for hierarchy parameters */
-#define DIB3000MC_REG_HRCH_PARM ( 181)
-#define DIB3000MC_HRCH_PARM(s,f,h) ( \
- (0x1 & s) | \
- ((0x7 & f) << 1) | \
- ((0x1 & h) << 4) )
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_1 ( 1)
-#define DIB3000MC_UNK_1 ( 0x04)
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_2 ( 2)
-#define DIB3000MC_UNK_2 ( 0x04)
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_3 ( 3)
-#define DIB3000MC_UNK_3 (0x1000)
-
-#define DIB3000MC_REG_UNK_4 ( 4)
-#define DIB3000MC_UNK_4 (0x0814)
-
-/* timeout ??? */
-#define DIB3000MC_REG_SEQ_TPS ( 5)
-#define DIB3000MC_SEQ_TPS_DEFAULT ( 1)
-#define DIB3000MC_SEQ_TPS(s,t) ( \
- ((s & 0x0f) << 4) | \
- ((t & 0x01) << 8) )
-#define DIB3000MC_IS_TPS(v) ((v << 8) & 0x1)
-#define DIB3000MC_IS_AS(v) ((v >> 4) & 0xf)
-
-/* parameters for the bandwidth */
-#define DIB3000MC_REG_BW_TIMOUT_MSB ( 6)
-#define DIB3000MC_REG_BW_TIMOUT_LSB ( 7)
-
-static u16 dib3000mc_reg_bandwidth[] = { 6,7,8,9,10,11,16,17 };
-
-/*static u16 dib3000mc_bandwidth_5mhz[] =
- { 0x28, 0x9380, 0x87, 0x4100, 0x2a4, 0x4500, 0x1, 0xb0d0 };*/
-
-static u16 dib3000mc_bandwidth_6mhz[] =
- { 0x21, 0xd040, 0x70, 0xb62b, 0x233, 0x8ed5, 0x1, 0xb0d0 };
-
-static u16 dib3000mc_bandwidth_7mhz[] =
- { 0x1c, 0xfba5, 0x60, 0x9c25, 0x1e3, 0x0cb7, 0x1, 0xb0d0 };
-
-static u16 dib3000mc_bandwidth_8mhz[] =
- { 0x19, 0x5c30, 0x54, 0x88a0, 0x1a6, 0xab20, 0x1, 0xb0d0 };
-
-static u16 dib3000mc_reg_bandwidth_general[] = { 12,13,14,15 };
-static u16 dib3000mc_bandwidth_general[] = { 0x0000, 0x03e8, 0x0000, 0x03f2 };
-
-/* lock mask */
-#define DIB3000MC_REG_LOCK_MASK ( 15)
-#define DIB3000MC_ACTIVATE_LOCK_MASK (0x0800)
-
-/* reset the uncorrected packet count (??? do it 5 times) */
-#define DIB3000MC_REG_RST_UNC ( 18)
-#define DIB3000MC_RST_UNC_ON ( 1)
-#define DIB3000MC_RST_UNC_OFF ( 0)
-
-#define DIB3000MC_REG_UNK_19 ( 19)
-#define DIB3000MC_UNK_19 ( 0)
-
-/* DDS frequency value (IF position) and inversion bit */
-#define DIB3000MC_REG_INVERSION ( 21)
-#define DIB3000MC_REG_SET_DDS_FREQ_MSB ( 21)
-#define DIB3000MC_DDS_FREQ_MSB_INV_OFF (0x0164)
-#define DIB3000MC_DDS_FREQ_MSB_INV_ON (0x0364)
-
-#define DIB3000MC_REG_SET_DDS_FREQ_LSB ( 22)
-#define DIB3000MC_DDS_FREQ_LSB (0x463d)
-
-/* timing frequencies setting */
-#define DIB3000MC_REG_TIMING_FREQ_MSB ( 23)
-#define DIB3000MC_REG_TIMING_FREQ_LSB ( 24)
-#define DIB3000MC_CLOCK_REF (0x151fd1)
-
-//static u16 dib3000mc_reg_timing_freq[] = { 23,24 };
-
-//static u16 dib3000mc_timing_freq[][2] = {
-// { 0x69, 0x9f18 }, /* 5 MHz */
-// { 0x7e ,0xbee9 }, /* 6 MHz */
-// { 0x93 ,0xdebb }, /* 7 MHz */
-// { 0xa8 ,0xfe8c }, /* 8 MHz */
-//};
-
-/* timeout ??? */
-static u16 dib3000mc_reg_offset[] = { 26,33 };
-
-static u16 dib3000mc_offset[][2] = {
- { 26240, 5 }, /* default */
- { 30336, 6 }, /* 8K */
- { 38528, 8 }, /* 2K */
-};
-
-#define DIB3000MC_REG_ISI ( 29)
-#define DIB3000MC_ISI_DEFAULT (0x1073)
-#define DIB3000MC_ISI_ACTIVATE (0x0000)
-#define DIB3000MC_ISI_INHIBIT (0x0200)
-
-/* impulse noise control */
-static u16 dib3000mc_reg_imp_noise_ctl[] = { 34,35 };
-
-static u16 dib3000mc_imp_noise_ctl[][2] = {
- { 0x1294, 0x1ff8 }, /* mode 0 */
- { 0x1294, 0x1ff8 }, /* mode 1 */
- { 0x1294, 0x1ff8 }, /* mode 2 */
- { 0x1294, 0x1ff8 }, /* mode 3 */
- { 0x1294, 0x1ff8 }, /* mode 4 */
-};
-
-/* AGC registers */
-static u16 dib3000mc_reg_agc[] = {
- 36,37,38,39,42,43,44,45,46,47,48,49
-};
-
-static u16 dib3000mc_agc_tuner[][12] = {
- { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xcf5c, 0x6666,
- 0xbae1, 0xa148, 0x3b5e, 0x3c1c, 0x001a, 0x2019
- }, /* TUNER_PANASONIC_ENV77H04D5, */
-
- { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xdc29, 0x570a,
- 0xbae1, 0x8ccd, 0x3b6d, 0x551d, 0x000a, 0x951e
- }, /* TUNER_PANASONIC_ENV57H13D5, TUNER_PANASONIC_ENV57H12D5 */
-
- { 0x0051, 0x301d, 0x0000, 0x1cc7, 0xffff, 0xffff,
- 0xffff, 0x0000, 0xfdfd, 0x4040, 0x00fd, 0x4040
- }, /* TUNER_SAMSUNG_DTOS333IH102, TUNER_RFAGCIN_UNKNOWN */
-
- { 0x0196, 0x301d, 0x0000, 0x1cc7, 0xbd71, 0x5c29,
- 0xb5c3, 0x6148, 0x6569, 0x5127, 0x0033, 0x3537
- }, /* TUNER_PROVIDER_X */
- /* TODO TUNER_PANASONIC_ENV57H10D8, TUNER_PANASONIC_ENV57H11D8 */
-};
-
-/* AGC loop bandwidth */
-static u16 dib3000mc_reg_agc_bandwidth[] = { 40,41 };
-static u16 dib3000mc_agc_bandwidth[] = { 0x119,0x330 };
-
-static u16 dib3000mc_reg_agc_bandwidth_general[] = { 50,51,52,53,54 };
-static u16 dib3000mc_agc_bandwidth_general[] =
- { 0x8000, 0x91ca, 0x01ba, 0x0087, 0x0087 };
-
-#define DIB3000MC_REG_IMP_NOISE_55 ( 55)
-#define DIB3000MC_IMP_NEW_ALGO(w) (w | (1<<10))
-
-/* Impulse noise params */
-static u16 dib3000mc_reg_impulse_noise[] = { 55,56,57 };
-static u16 dib3000mc_impluse_noise[][3] = {
- { 0x489, 0x89, 0x72 }, /* 5 MHz */
- { 0x4a5, 0xa5, 0x89 }, /* 6 MHz */
- { 0x4c0, 0xc0, 0xa0 }, /* 7 MHz */
- { 0x4db, 0xdb, 0xb7 }, /* 8 Mhz */
-};
-
-static u16 dib3000mc_reg_fft[] = {
- 58,59,60,61,62,63,64,65,66,67,68,69,
- 70,71,72,73,74,75,76,77,78,79,80,81,
- 82,83,84,85,86
-};
-
-static u16 dib3000mc_fft_modes[][29] = {
- { 0x38, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
- 0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
- 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
- 0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
- 0x3ffe, 0x5b3, 0x3feb, 0x76, 0x0, 0xd
- }, /* fft mode 0 */
- { 0x3b, 0x6d9, 0x3f28, 0x7a7, 0x3a74, 0x196, 0x32a, 0x48c,
- 0x3ffe, 0x7f3, 0x2d94, 0x76, 0x53d,
- 0x3ff8, 0x7e3, 0x3320, 0x76, 0x5b3,
- 0x3feb, 0x7d2, 0x365e, 0x76, 0x48c,
- 0x3ffe, 0x5b3, 0x3feb, 0x0, 0x8200, 0xd
- }, /* fft mode 1 */
-};
-
-#define DIB3000MC_REG_UNK_88 ( 88)
-#define DIB3000MC_UNK_88 (0x0410)
-
-static u16 dib3000mc_reg_bw[] = { 93,94,95,96,97,98 };
-static u16 dib3000mc_bw[][6] = {
- { 0,0,0,0,0,0 }, /* 5 MHz */
- { 0,0,0,0,0,0 }, /* 6 MHz */
- { 0,0,0,0,0,0 }, /* 7 MHz */
- { 0x20, 0x21, 0x20, 0x23, 0x20, 0x27 }, /* 8 MHz */
-};
-
-
-/* phase noise control */
-#define DIB3000MC_REG_UNK_99 ( 99)
-#define DIB3000MC_UNK_99 (0x0220)
-
-#define DIB3000MC_REG_SCAN_BOOST ( 100)
-#define DIB3000MC_SCAN_BOOST_ON ((11 << 6) + 6)
-#define DIB3000MC_SCAN_BOOST_OFF ((16 << 6) + 9)
-
-/* timeout ??? */
-#define DIB3000MC_REG_UNK_110 ( 110)
-#define DIB3000MC_UNK_110 ( 3277)
-
-#define DIB3000MC_REG_UNK_111 ( 111)
-#define DIB3000MC_UNK_111_PH_N_MODE_0 ( 0)
-#define DIB3000MC_UNK_111_PH_N_MODE_1 (1 << 1)
-
-/* superious rm config */
-#define DIB3000MC_REG_UNK_120 ( 120)
-#define DIB3000MC_UNK_120 ( 8207)
-
-#define DIB3000MC_REG_UNK_133 ( 133)
-#define DIB3000MC_UNK_133 ( 15564)
-
-#define DIB3000MC_REG_UNK_134 ( 134)
-#define DIB3000MC_UNK_134 ( 0)
-
-/* adapter config for constellation */
-static u16 dib3000mc_reg_adp_cfg[] = { 129, 130, 131, 132 };
-
-static u16 dib3000mc_adp_cfg[][4] = {
- { 0x99a, 0x7fae, 0x333, 0x7ff0 }, /* QPSK */
- { 0x23d, 0x7fdf, 0x0a4, 0x7ff0 }, /* 16-QAM */
- { 0x148, 0x7ff0, 0x0a4, 0x7ff8 }, /* 64-QAM */
-};
-
-static u16 dib3000mc_reg_mobile_mode[] = { 139, 140, 141, 175, 1032 };
-
-static u16 dib3000mc_mobile_mode[][5] = {
- { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* fixed */
- { 0x01, 0x0, 0x0, 0x00, 0x12c }, /* portable */
- { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* mobile */
- { 0x00, 0x0, 0x0, 0x02, 0x000 }, /* auto */
-};
-
-#define DIB3000MC_REG_DIVERSITY1 ( 177)
-#define DIB3000MC_DIVERSITY1_DEFAULT ( 1)
-
-#define DIB3000MC_REG_DIVERSITY2 ( 178)
-#define DIB3000MC_DIVERSITY2_DEFAULT ( 1)
-
-#define DIB3000MC_REG_DIVERSITY3 ( 180)
-#define DIB3000MC_DIVERSITY3_IN_OFF (0xfff0)
-#define DIB3000MC_DIVERSITY3_IN_ON (0xfff6)
-
-#define DIB3000MC_REG_FEC_CFG ( 195)
-#define DIB3000MC_FEC_CFG ( 0x10)
-
-/*
- * reg 206, output mode
- * 1111 1111
- * |||| ||||
- * |||| |||+- unk
- * |||| ||+-- unk
- * |||| |+--- unk (on by default)
- * |||| +---- fifo_ctrl (1 = inhibit (flushed), 0 = active (unflushed))
- * |||+------ pid_parse (1 = enabled, 0 = disabled)
- * ||+------- outp_188 (1 = TS packet size 188, 0 = packet size 204)
- * |+-------- unk
- * +--------- unk
- */
-
-#define DIB3000MC_REG_SMO_MODE ( 206)
-#define DIB3000MC_SMO_MODE_DEFAULT (1 << 2)
-#define DIB3000MC_SMO_MODE_FIFO_FLUSH (1 << 3)
-#define DIB3000MC_SMO_MODE_FIFO_UNFLUSH (0xfff7)
-#define DIB3000MC_SMO_MODE_PID_PARSE (1 << 4)
-#define DIB3000MC_SMO_MODE_NO_PID_PARSE (0xffef)
-#define DIB3000MC_SMO_MODE_188 (1 << 5)
-#define DIB3000MC_SMO_MODE_SLAVE (DIB3000MC_SMO_MODE_DEFAULT | \
- DIB3000MC_SMO_MODE_188 | DIB3000MC_SMO_MODE_PID_PARSE | (1<<1))
-
-#define DIB3000MC_REG_FIFO_THRESHOLD ( 207)
-#define DIB3000MC_FIFO_THRESHOLD_DEFAULT ( 1792)
-#define DIB3000MC_FIFO_THRESHOLD_SLAVE ( 512)
-/*
- * pidfilter
- * it is not a hardware pidfilter but a filter which drops all pids
- * except the ones set. When connected to USB1.1 bandwidth this is important.
- * DiB3000P/M-C can filter up to 32 PIDs
- */
-#define DIB3000MC_REG_FIRST_PID ( 212)
-#define DIB3000MC_NUM_PIDS ( 32)
-
-#define DIB3000MC_REG_OUTMODE ( 244)
-#define DIB3000MC_OM_PARALLEL_GATED_CLK ( 0)
-#define DIB3000MC_OM_PAR_CONT_CLK (1 << 11)
-#define DIB3000MC_OM_SERIAL (2 << 11)
-#define DIB3000MC_OM_DIVOUT_ON (4 << 11)
-#define DIB3000MC_OM_SLAVE (DIB3000MC_OM_DIVOUT_ON | DIB3000MC_OM_PAR_CONT_CLK)
-
-#define DIB3000MC_REG_RF_POWER ( 392)
-
-#define DIB3000MC_REG_FFT_POSITION ( 407)
-
-#define DIB3000MC_REG_DDS_FREQ_MSB ( 414)
-#define DIB3000MC_REG_DDS_FREQ_LSB ( 415)
-
-#define DIB3000MC_REG_TIMING_OFFS_MSB ( 416)
-#define DIB3000MC_REG_TIMING_OFFS_LSB ( 417)
-
-#define DIB3000MC_REG_TUNING_PARM ( 458)
-#define DIB3000MC_TP_QAM(v) ((v >> 13) & 0x03)
-#define DIB3000MC_TP_HRCH(v) ((v >> 12) & 0x01)
-#define DIB3000MC_TP_ALPHA(v) ((v >> 9) & 0x07)
-#define DIB3000MC_TP_FFT(v) ((v >> 8) & 0x01)
-#define DIB3000MC_TP_FEC_CR_HP(v) ((v >> 5) & 0x07)
-#define DIB3000MC_TP_FEC_CR_LP(v) ((v >> 2) & 0x07)
-#define DIB3000MC_TP_GUARD(v) (v & 0x03)
-
-#define DIB3000MC_REG_SIGNAL_NOISE_MSB ( 483)
-#define DIB3000MC_REG_SIGNAL_NOISE_LSB ( 484)
-
-#define DIB3000MC_REG_MER ( 485)
-
-#define DIB3000MC_REG_BER_MSB ( 500)
-#define DIB3000MC_REG_BER_LSB ( 501)
-
-#define DIB3000MC_REG_PACKET_ERRORS ( 503)
-
-#define DIB3000MC_REG_PACKET_ERROR_COUNT ( 506)
-
-#define DIB3000MC_REG_LOCK_507 ( 507)
-#define DIB3000MC_LOCK_507 (0x0002) // ? name correct ?
-
-#define DIB3000MC_REG_LOCKING ( 509)
-#define DIB3000MC_AGC_LOCK(v) (v & 0x8000)
-#define DIB3000MC_CARRIER_LOCK(v) (v & 0x2000)
-#define DIB3000MC_MPEG_SYNC_LOCK(v) (v & 0x0080)
-#define DIB3000MC_MPEG_DATA_LOCK(v) (v & 0x0040)
-#define DIB3000MC_TPS_LOCK(v) (v & 0x0004)
-
-#define DIB3000MC_REG_AS_IRQ ( 511)
-#define DIB3000MC_AS_IRQ_SUCCESS (1 << 1)
-#define DIB3000MC_AS_IRQ_FAIL ( 1)
-
-#define DIB3000MC_REG_TUNER ( 769)
-
-#define DIB3000MC_REG_RST_I2C_ADDR ( 1024)
-#define DIB3000MC_DEMOD_ADDR_ON ( 1)
-#define DIB3000MC_DEMOD_ADDR(a) ((a << 4) & 0x03F0)
-
-#define DIB3000MC_REG_RESTART ( 1027)
-#define DIB3000MC_RESTART_OFF (0x0000)
-#define DIB3000MC_RESTART_AGC (0x0800)
-#define DIB3000MC_RESTART_CONFIG (0x8000)
-
-#define DIB3000MC_REG_RESTART_VIT ( 1028)
-#define DIB3000MC_RESTART_VIT_OFF ( 0)
-#define DIB3000MC_RESTART_VIT_ON ( 1)
-
-#define DIB3000MC_REG_CLK_CFG_1 ( 1031)
-#define DIB3000MC_CLK_CFG_1_POWER_UP ( 0)
-#define DIB3000MC_CLK_CFG_1_POWER_DOWN (0xffff)
-
-#define DIB3000MC_REG_CLK_CFG_2 ( 1032)
-#define DIB3000MC_CLK_CFG_2_PUP_FIXED (0x012c)
-#define DIB3000MC_CLK_CFG_2_PUP_PORT (0x0104)
-#define DIB3000MC_CLK_CFG_2_PUP_MOBILE (0x0000)
-#define DIB3000MC_CLK_CFG_2_POWER_DOWN (0xffff)
-
-#define DIB3000MC_REG_CLK_CFG_3 ( 1033)
-#define DIB3000MC_CLK_CFG_3_POWER_UP ( 0)
-#define DIB3000MC_CLK_CFG_3_POWER_DOWN (0xfff5)
-
-#define DIB3000MC_REG_CLK_CFG_7 ( 1037)
-#define DIB3000MC_CLK_CFG_7_INIT ( 12592)
-#define DIB3000MC_CLK_CFG_7_POWER_UP (~0x0003)
-#define DIB3000MC_CLK_CFG_7_PWR_DOWN (0x0003)
-#define DIB3000MC_CLK_CFG_7_DIV_IN_OFF (1 << 8)
-
-/* was commented out ??? */
-#define DIB3000MC_REG_CLK_CFG_8 ( 1038)
-#define DIB3000MC_CLK_CFG_8_POWER_UP (0x160c)
-
-#define DIB3000MC_REG_CLK_CFG_9 ( 1039)
-#define DIB3000MC_CLK_CFG_9_POWER_UP ( 0)
-
-/* also clock ??? */
-#define DIB3000MC_REG_ELEC_OUT ( 1040)
-#define DIB3000MC_ELEC_OUT_HIGH_Z ( 0)
-#define DIB3000MC_ELEC_OUT_DIV_OUT_ON ( 1)
-#define DIB3000MC_ELEC_OUT_SLAVE ( 3)
-
-#endif
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
new file mode 100644
index 000000000000..a18c8f45a2ee
--- /dev/null
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -0,0 +1,152 @@
+#include <linux/i2c.h>
+
+#include "dibx000_common.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+
+#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); } } while (0)
+
+static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+{
+ u8 b[4] = {
+ (reg >> 8) & 0xff, reg & 0xff,
+ (val >> 8) & 0xff, val & 0xff,
+ };
+ struct i2c_msg msg = {
+ .addr = mst->i2c_addr, .flags = 0, .buf = b, .len = 4
+ };
+ return i2c_transfer(mst->i2c_adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
+}
+
+
+static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf)
+{
+ if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) {
+ dprintk("selecting interface: %d\n",intf);
+ mst->selected_interface = intf;
+ return dibx000_write_word(mst, mst->base_reg + 4, intf);
+ }
+ return 0;
+}
+
+static int dibx000_i2c_gate_ctrl(struct dibx000_i2c_master *mst, u8 tx[4], u8 addr, int onoff)
+{
+ u16 val;
+
+
+ if (onoff)
+ val = addr << 8; // bit 7 = use master or not, if 0, the gate is open
+ else
+ val = 1 << 7;
+
+ if (mst->device_rev > DIB7000)
+ val <<= 1;
+
+ tx[0] = (((mst->base_reg + 1) >> 8) & 0xff);
+ tx[1] = ( (mst->base_reg + 1) & 0xff);
+ tx[2] = val >> 8;
+ tx[3] = val & 0xff;
+
+ return 0;
+}
+
+static u32 dibx000_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+ struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
+ struct i2c_msg m[2 + num];
+ u8 tx_open[4], tx_close[4];
+
+ memset(m,0, sizeof(struct i2c_msg) * (2 + num));
+
+ dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
+
+ dibx000_i2c_gate_ctrl(mst, tx_open, msg[0].addr, 1);
+ m[0].addr = mst->i2c_addr;
+ m[0].buf = tx_open;
+ m[0].len = 4;
+
+ memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
+
+ dibx000_i2c_gate_ctrl(mst, tx_close, 0, 0);
+ m[num+1].addr = mst->i2c_addr;
+ m[num+1].buf = tx_close;
+ m[num+1].len = 4;
+
+ return i2c_transfer(mst->i2c_adap, m, 2+num) == 2 + num ? num : -EIO;
+}
+
+static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
+ .master_xfer = dibx000_i2c_gated_tuner_xfer,
+ .functionality = dibx000_i2c_func,
+};
+
+struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating)
+{
+ struct i2c_adapter *i2c = NULL;
+
+ switch (intf) {
+ case DIBX000_I2C_INTERFACE_TUNER:
+ if (gating)
+ i2c = &mst->gated_tuner_i2c_adap;
+ break;
+ default:
+ printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n");
+ break;
+ }
+
+ return i2c;
+}
+EXPORT_SYMBOL(dibx000_get_i2c_adapter);
+
+static int i2c_adapter_init(struct i2c_adapter *i2c_adap, struct i2c_algorithm *algo, const char name[I2C_NAME_SIZE], struct dibx000_i2c_master *mst)
+{
+ strncpy(i2c_adap->name, name, I2C_NAME_SIZE);
+ i2c_adap->class = I2C_CLASS_TV_DIGITAL,
+ i2c_adap->algo = algo;
+ i2c_adap->algo_data = NULL;
+ i2c_set_adapdata(i2c_adap, mst);
+ if (i2c_add_adapter(i2c_adap) < 0)
+ return -ENODEV;
+ return 0;
+}
+
+int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr)
+{
+ u8 tx[4];
+ struct i2c_msg m = { .addr = i2c_addr >> 1, .buf = tx, .len = 4 };
+
+ mst->device_rev = device_rev;
+ mst->i2c_adap = i2c_adap;
+ mst->i2c_addr = i2c_addr >> 1;
+
+ if (device_rev == DIB7000P)
+ mst->base_reg = 1024;
+ else
+ mst->base_reg = 768;
+
+ if (i2c_adapter_init(&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, "DiBX000 tuner I2C bus", mst) != 0)
+ printk(KERN_ERR "DiBX000: could not initialize the tuner i2c_adapter\n");
+
+ /* initialize the i2c-master by closing the gate */
+ dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
+
+ return i2c_transfer(i2c_adap, &m, 1) == 1;
+}
+EXPORT_SYMBOL(dibx000_init_i2c_master);
+
+void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst)
+{
+ i2c_del_adapter(&mst->gated_tuner_i2c_adap);
+}
+EXPORT_SYMBOL(dibx000_exit_i2c_master);
+
+MODULE_AUTHOR("Patrick Boettcher <pboettcher@dibcom.fr>");
+MODULE_DESCRIPTION("Common function the DiBcom demodulator family");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
new file mode 100644
index 000000000000..bb0c65f8aee8
--- /dev/null
+++ b/drivers/media/dvb/frontends/dibx000_common.h
@@ -0,0 +1,166 @@
+#ifndef DIBX000_COMMON_H
+#define DIBX000_COMMON_H
+
+enum dibx000_i2c_interface {
+ DIBX000_I2C_INTERFACE_TUNER = 0,
+ DIBX000_I2C_INTERFACE_GPIO_1_2 = 1,
+ DIBX000_I2C_INTERFACE_GPIO_3_4 = 2
+};
+
+struct dibx000_i2c_master {
+#define DIB3000MC 1
+#define DIB7000 2
+#define DIB7000P 11
+#define DIB7000MC 12
+ u16 device_rev;
+
+ enum dibx000_i2c_interface selected_interface;
+
+// struct i2c_adapter tuner_i2c_adap;
+ struct i2c_adapter gated_tuner_i2c_adap;
+
+ struct i2c_adapter *i2c_adap;
+ u8 i2c_addr;
+
+ u16 base_reg;
+};
+
+extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, struct i2c_adapter *i2c_adap, u8 i2c_addr);
+extern struct i2c_adapter * dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf, int gating);
+extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst);
+
+#define BAND_LBAND 0x01
+#define BAND_UHF 0x02
+#define BAND_VHF 0x04
+
+struct dibx000_agc_config {
+ /* defines the capabilities of this AGC-setting - using the BAND_-defines*/
+ u8 band_caps;
+
+ u16 setup;
+
+ u16 inv_gain;
+ u16 time_stabiliz;
+
+ u8 alpha_level;
+ u16 thlock;
+
+ u8 wbd_inv;
+ u16 wbd_ref;
+ u8 wbd_sel;
+ u8 wbd_alpha;
+
+ u16 agc1_max;
+ u16 agc1_min;
+ u16 agc2_max;
+ u16 agc2_min;
+
+ u8 agc1_pt1;
+ u8 agc1_pt2;
+ u8 agc1_pt3;
+
+ u8 agc1_slope1;
+ u8 agc1_slope2;
+
+ u8 agc2_pt1;
+ u8 agc2_pt2;
+
+ u8 agc2_slope1;
+ u8 agc2_slope2;
+
+ u8 alpha_mant;
+ u8 alpha_exp;
+
+ u8 beta_mant;
+ u8 beta_exp;
+
+ u8 perform_agc_softsplit;
+
+ struct {
+ u16 min;
+ u16 max;
+ u16 min_thres;
+ u16 max_thres;
+ } split;
+};
+
+struct dibx000_bandwidth_config {
+ u32 internal;
+ u32 sampling;
+
+ u8 pll_prediv;
+ u8 pll_ratio;
+ u8 pll_range;
+ u8 pll_reset;
+ u8 pll_bypass;
+
+ u8 enable_refdiv;
+ u8 bypclk_div;
+ u8 IO_CLK_en_core;
+ u8 ADClkSrc;
+ u8 modulo;
+
+ u16 sad_cfg;
+
+ u32 ifreq;
+ u32 timf;
+};
+
+enum dibx000_adc_states {
+ DIBX000_SLOW_ADC_ON = 0,
+ DIBX000_SLOW_ADC_OFF,
+ DIBX000_ADC_ON,
+ DIBX000_ADC_OFF,
+ DIBX000_VBG_ENABLE,
+ DIBX000_VBG_DISABLE,
+};
+
+#define BW_INDEX_TO_KHZ(v) ( (v) == BANDWIDTH_8_MHZ ? 8000 : \
+ (v) == BANDWIDTH_7_MHZ ? 7000 : \
+ (v) == BANDWIDTH_6_MHZ ? 6000 : 8000 )
+
+/* Chip output mode. */
+#define OUTMODE_HIGH_Z 0
+#define OUTMODE_MPEG2_PAR_GATED_CLK 1
+#define OUTMODE_MPEG2_PAR_CONT_CLK 2
+#define OUTMODE_MPEG2_SERIAL 7
+#define OUTMODE_DIVERSITY 4
+#define OUTMODE_MPEG2_FIFO 5
+
+/* I hope I can get rid of the following kludge in the near future */
+struct dibx000_ofdm_channel {
+ u8 Bw;
+ s16 nfft;
+ s16 guard;
+ s16 nqam;
+ s16 vit_hrch;
+ s16 vit_select_hp;
+ s16 vit_alpha;
+ s16 vit_code_rate_hp;
+ s16 vit_code_rate_lp;
+};
+
+#define FEP2DIB(fep,ch) \
+ (ch)->Bw = (fep)->u.ofdm.bandwidth; \
+ (ch)->nfft = (fep)->u.ofdm.transmission_mode == TRANSMISSION_MODE_AUTO ? -1 : (fep)->u.ofdm.transmission_mode; \
+ (ch)->guard = (fep)->u.ofdm.guard_interval == GUARD_INTERVAL_AUTO ? -1 : (fep)->u.ofdm.guard_interval; \
+ (ch)->nqam = (fep)->u.ofdm.constellation == QAM_AUTO ? -1 : (fep)->u.ofdm.constellation == QAM_64 ? 2 : (fep)->u.ofdm.constellation; \
+ (ch)->vit_hrch = 0; /* linux-dvb is not prepared for HIERARCHICAL TRANSMISSION */ \
+ (ch)->vit_select_hp = 1; \
+ (ch)->vit_alpha = 1; \
+ (ch)->vit_code_rate_hp = (fep)->u.ofdm.code_rate_HP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_HP; \
+ (ch)->vit_code_rate_lp = (fep)->u.ofdm.code_rate_LP == FEC_AUTO ? -1 : (fep)->u.ofdm.code_rate_LP;
+
+#define INIT_OFDM_CHANNEL(ch) do {\
+ (ch)->Bw = 0; \
+ (ch)->nfft = -1; \
+ (ch)->guard = -1; \
+ (ch)->nqam = -1; \
+ (ch)->vit_hrch = -1; \
+ (ch)->vit_select_hp = -1; \
+ (ch)->vit_alpha = -1; \
+ (ch)->vit_code_rate_hp = -1; \
+ (ch)->vit_code_rate_lp = -1; \
+} while (0)
+
+#endif
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 2be33f27c69f..b7e7108ee5b3 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -493,6 +493,9 @@ static int dvb_pll_sleep(struct dvb_frontend *fe)
int i;
int result;
+ if (priv->i2c == NULL)
+ return -EINVAL;
+
for (i = 0; i < priv->pll_desc->count; i++) {
if (priv->pll_desc->entries[i].limit == 0)
break;
@@ -611,7 +614,7 @@ static struct dvb_tuner_ops dvb_pll_tuner_ops = {
.get_bandwidth = dvb_pll_get_bandwidth,
};
-int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
+struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc)
{
u8 b1 [] = { 0 };
struct i2c_msg msg = { .addr = pll_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 };
@@ -624,14 +627,14 @@ int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2
ret = i2c_transfer (i2c, &msg, 1);
if (ret != 1)
- return -1;
+ return NULL;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}
priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL);
if (priv == NULL)
- return -ENOMEM;
+ return NULL;
priv->pll_i2c_address = pll_addr;
priv->i2c = i2c;
@@ -643,7 +646,7 @@ int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2
fe->ops.tuner_ops.info.frequency_min = desc->max;
fe->tuner_priv = priv;
- return 0;
+ return fe;
}
EXPORT_SYMBOL(dvb_pll_attach);
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index 66361cd18807..ed5ac5a361ae 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -57,8 +57,8 @@ extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
* @param pll_addr i2c address of the PLL (if used).
* @param i2c i2c adapter to use (set to NULL if not used).
* @param desc dvb_pll_desc to use.
- * @return 0 on success, nonzero on failure.
+ * @return Frontend pointer on success, NULL on failure
*/
-extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
+extern struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc);
#endif
diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c
index 58c34db31071..ef319369ec26 100644
--- a/drivers/media/dvb/frontends/isl6421.c
+++ b/drivers/media/dvb/frontends/isl6421.c
@@ -42,12 +42,11 @@ struct isl6421 {
u8 override_and;
struct i2c_adapter *i2c;
u8 i2c_addr;
- void (*release_chain)(struct dvb_frontend* fe);
};
static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
- struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
.buf = &isl6421->config,
.len = sizeof(isl6421->config) };
@@ -75,7 +74,7 @@ static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage
static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
{
- struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
+ struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv;
struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0,
.buf = &isl6421->config,
.len = sizeof(isl6421->config) };
@@ -93,31 +92,26 @@ static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
static void isl6421_release(struct dvb_frontend *fe)
{
- struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv;
-
/* power off */
isl6421_set_voltage(fe, SEC_VOLTAGE_OFF);
- /* free data & call next release routine */
- fe->ops.release = isl6421->release_chain;
- kfree(fe->misc_priv);
- fe->misc_priv = NULL;
- if (fe->ops.release)
- fe->ops.release(fe);
+ /* free */
+ kfree(fe->sec_priv);
+ fe->sec_priv = NULL;
}
-int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
u8 override_set, u8 override_clear)
{
struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL);
if (!isl6421)
- return -ENOMEM;
+ return NULL;
/* default configuration */
isl6421->config = ISL6421_ISEL1;
isl6421->i2c = i2c;
isl6421->i2c_addr = i2c_addr;
- fe->misc_priv = isl6421;
+ fe->sec_priv = isl6421;
/* bits which should be forced to '1' */
isl6421->override_or = override_set;
@@ -128,19 +122,17 @@ int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr
/* detect if it is present or not */
if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) {
kfree(isl6421);
- fe->misc_priv = NULL;
- return -EIO;
+ return NULL;
}
/* install release callback */
- isl6421->release_chain = fe->ops.release;
- fe->ops.release = isl6421_release;
+ fe->ops.release_sec = isl6421_release;
/* override frontend ops */
fe->ops.set_voltage = isl6421_set_voltage;
fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage;
- return 0;
+ return fe;
}
EXPORT_SYMBOL(isl6421_attach);
diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h
index 675f80a19b99..1916e3eb2df3 100644
--- a/drivers/media/dvb/frontends/isl6421.h
+++ b/drivers/media/dvb/frontends/isl6421.h
@@ -39,8 +39,17 @@
#define ISL6421_ISEL1 0x20
#define ISL6421_DCL 0x40
+#if defined(CONFIG_DVB_ISL6421) || defined(CONFIG_DVB_ISL6421_MODULE)
/* override_set and override_clear control which system register bits (above) to always set & clear */
-extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+extern struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_ISL6421
#endif
diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h
index 83b8bc210274..21ba4a230760 100644
--- a/drivers/media/dvb/frontends/l64781.h
+++ b/drivers/media/dvb/frontends/l64781.h
@@ -31,8 +31,16 @@ struct l64781_config
u8 demod_address;
};
-
+#if defined(CONFIG_DVB_L64781) || defined(CONFIG_DVB_L64781_MODULE)
extern struct dvb_frontend* l64781_attach(const struct l64781_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* l64781_attach(const struct l64781_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_L64781
#endif // L64781_H
diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h
index bad903c6f0f8..3f96b485584c 100644
--- a/drivers/media/dvb/frontends/lgdt330x.h
+++ b/drivers/media/dvb/frontends/lgdt330x.h
@@ -52,8 +52,17 @@ struct lgdt330x_config
int clock_polarity_flip;
};
+#if defined(CONFIG_DVB_LGDT330X) || defined(CONFIG_DVB_LGDT330X_MODULE)
extern struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_LGDT330X
#endif /* LGDT330X_H */
diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c
index e933edc8dd29..2d2f58c26226 100644
--- a/drivers/media/dvb/frontends/lnbp21.c
+++ b/drivers/media/dvb/frontends/lnbp21.c
@@ -40,12 +40,11 @@ struct lnbp21 {
u8 override_or;
u8 override_and;
struct i2c_adapter *i2c;
- void (*release_chain)(struct dvb_frontend* fe);
};
static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
struct i2c_msg msg = { .addr = 0x08, .flags = 0,
.buf = &lnbp21->config,
.len = sizeof(lnbp21->config) };
@@ -73,7 +72,7 @@ static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
+ struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
struct i2c_msg msg = { .addr = 0x08, .flags = 0,
.buf = &lnbp21->config,
.len = sizeof(lnbp21->config) };
@@ -91,29 +90,24 @@ static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
static void lnbp21_release(struct dvb_frontend *fe)
{
- struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv;
-
/* LNBP power off */
lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
- /* free data & call next release routine */
- fe->ops.release = lnbp21->release_chain;
- kfree(fe->misc_priv);
- fe->misc_priv = NULL;
- if (fe->ops.release)
- fe->ops.release(fe);
+ /* free data */
+ kfree(fe->sec_priv);
+ fe->sec_priv = NULL;
}
-int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
{
struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
if (!lnbp21)
- return -ENOMEM;
+ return NULL;
/* default configuration */
lnbp21->config = LNBP21_ISEL;
lnbp21->i2c = i2c;
- fe->misc_priv = lnbp21;
+ fe->sec_priv = lnbp21;
/* bits which should be forced to '1' */
lnbp21->override_or = override_set;
@@ -124,19 +118,17 @@ int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_
/* detect if it is present or not */
if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
kfree(lnbp21);
- fe->misc_priv = NULL;
- return -EIO;
+ return NULL;
}
/* install release callback */
- lnbp21->release_chain = fe->ops.release;
- fe->ops.release = lnbp21_release;
+ fe->ops.release_sec = lnbp21_release;
/* override frontend ops */
fe->ops.set_voltage = lnbp21_set_voltage;
fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
- return 0;
+ return fe;
}
EXPORT_SYMBOL(lnbp21_attach);
diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h
index 047a4ab68c01..1fe1dd179312 100644
--- a/drivers/media/dvb/frontends/lnbp21.h
+++ b/drivers/media/dvb/frontends/lnbp21.h
@@ -39,7 +39,15 @@
#include <linux/dvb/frontend.h>
+#if defined(CONFIG_DVB_LNBP21) || defined(CONFIG_DVB_LNBP21_MODULE)
/* override_set and override_clear control which system register bits (above) to always set & clear */
-extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
+extern struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_LNBP21
-#endif
+#endif // _LNBP21_H
diff --git a/drivers/media/dvb/frontends/mt2060.c b/drivers/media/dvb/frontends/mt2060.c
new file mode 100644
index 000000000000..450fad8d9b65
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2060.c
@@ -0,0 +1,370 @@
+/*
+ * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ * Copyright (c) 2006 Olivier DANET <odanet@caramail.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+/* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "mt2060.h"
+#include "mt2060_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0)
+
+// Reads a single register
+static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val)
+{
+ struct i2c_msg msg[2] = {
+ { .addr = priv->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 },
+ };
+
+ if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+ printk(KERN_WARNING "mt2060 I2C read failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Writes a single register
+static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2
+ };
+
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mt2060 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Writes a set of consecutive registers
+static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len)
+{
+ struct i2c_msg msg = {
+ .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len
+ };
+ if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+// Initialisation sequences
+// LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49
+static u8 mt2060_config1[] = {
+ REG_LO1C1,
+ 0x3F, 0x74, 0x00, 0x08, 0x93
+};
+
+// FMCG=2, GP2=0, GP1=0
+static u8 mt2060_config2[] = {
+ REG_MISC_CTRL,
+ 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42
+};
+
+// VGAG=3, V1CSE=1
+
+#ifdef MT2060_SPURCHECK
+/* The function below calculates the frequency offset between the output frequency if2
+ and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */
+static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2)
+{
+ int I,J;
+ int dia,diamin,diff;
+ diamin=1000000;
+ for (I = 1; I < 10; I++) {
+ J = ((2*I*lo1)/lo2+1)/2;
+ diff = I*(int)lo1-J*(int)lo2;
+ if (diff < 0) diff=-diff;
+ dia = (diff-(int)if2);
+ if (dia < 0) dia=-dia;
+ if (diamin > dia) diamin=dia;
+ }
+ return diamin;
+}
+
+#define BANDWIDTH 4000 // kHz
+
+/* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */
+static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2)
+{
+ u32 Spur,Sp1,Sp2;
+ int I,J;
+ I=0;
+ J=1000;
+
+ Spur=mt2060_spurcalc(lo1,lo2,if2);
+ if (Spur < BANDWIDTH) {
+ /* Potential spurs detected */
+ dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)",
+ (int)lo1,(int)lo2);
+ I=1000;
+ Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2);
+ Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2);
+
+ if (Sp1 < Sp2) {
+ J=-J; I=-I; Spur=Sp2;
+ } else
+ Spur=Sp1;
+
+ while (Spur < BANDWIDTH) {
+ I += J;
+ Spur = mt2060_spurcalc(lo1+I,lo2+I,if2);
+ }
+ dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)",
+ (int)(lo1+I),(int)(lo2+I));
+ }
+ return I;
+}
+#endif
+
+#define IF2 36150 // IF2 frequency = 36.150 MHz
+#define FREF 16000 // Quartz oscillator 16 MHz
+
+static int mt2060_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct mt2060_priv *priv;
+ int ret=0;
+ int i=0;
+ u32 freq;
+ u8 lnaband;
+ u32 f_lo1,f_lo2;
+ u32 div1,num1,div2,num2;
+ u8 b[8];
+ u32 if1;
+
+ priv = fe->tuner_priv;
+
+ if1 = priv->if1_freq;
+ b[0] = REG_LO1B1;
+ b[1] = 0xFF;
+
+ mt2060_writeregs(priv,b,2);
+
+ freq = params->frequency / 1000; // Hz -> kHz
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ? params->u.ofdm.bandwidth : 0;
+
+ f_lo1 = freq + if1 * 1000;
+ f_lo1 = (f_lo1 / 250) * 250;
+ f_lo2 = f_lo1 - freq - IF2;
+ // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise
+ f_lo2 = ((f_lo2 + 25) / 50) * 50;
+ priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000,
+
+#ifdef MT2060_SPURCHECK
+ // LO-related spurs detection and correction
+ num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2);
+ f_lo1 += num1;
+ f_lo2 += num1;
+#endif
+ //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 )
+ num1 = f_lo1 / (FREF / 64);
+ div1 = num1 / 64;
+ num1 &= 0x3f;
+
+ // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 )
+ num2 = f_lo2 * 64 / (FREF / 128);
+ div2 = num2 / 8192;
+ num2 &= 0x1fff;
+
+ if (freq <= 95000) lnaband = 0xB0; else
+ if (freq <= 180000) lnaband = 0xA0; else
+ if (freq <= 260000) lnaband = 0x90; else
+ if (freq <= 335000) lnaband = 0x80; else
+ if (freq <= 425000) lnaband = 0x70; else
+ if (freq <= 480000) lnaband = 0x60; else
+ if (freq <= 570000) lnaband = 0x50; else
+ if (freq <= 645000) lnaband = 0x40; else
+ if (freq <= 730000) lnaband = 0x30; else
+ if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10;
+
+ b[0] = REG_LO1C1;
+ b[1] = lnaband | ((num1 >>2) & 0x0F);
+ b[2] = div1;
+ b[3] = (num2 & 0x0F) | ((num1 & 3) << 4);
+ b[4] = num2 >> 4;
+ b[5] = ((num2 >>12) & 1) | (div2 << 1);
+
+ dprintk("IF1: %dMHz",(int)if1);
+ dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2);
+ dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2);
+ dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]);
+
+ mt2060_writeregs(priv,b,6);
+
+ //Waits for pll lock or timeout
+ i = 0;
+ do {
+ mt2060_readreg(priv,REG_LO_STATUS,b);
+ if ((b[0] & 0x88)==0x88)
+ break;
+ msleep(4);
+ i++;
+ } while (i<10);
+
+ return ret;
+}
+
+static void mt2060_calibrate(struct mt2060_priv *priv)
+{
+ u8 b = 0;
+ int i = 0;
+
+ if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1)))
+ return;
+ if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2)))
+ return;
+
+ /* initialize the clock output */
+ mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+
+ do {
+ b |= (1 << 6); // FM1SS;
+ mt2060_writereg(priv, REG_LO2C1,b);
+ msleep(20);
+
+ if (i == 0) {
+ b |= (1 << 7); // FM1CA;
+ mt2060_writereg(priv, REG_LO2C1,b);
+ b &= ~(1 << 7); // FM1CA;
+ msleep(20);
+ }
+
+ b &= ~(1 << 6); // FM1SS
+ mt2060_writereg(priv, REG_LO2C1,b);
+
+ msleep(20);
+ i++;
+ } while (i < 9);
+
+ i = 0;
+ while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0)
+ msleep(20);
+
+ if (i < 10) {
+ mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :)
+ dprintk("calibration was successful: %d", (int)priv->fmfreq);
+ } else
+ dprintk("FMCAL timed out");
+}
+
+static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct mt2060_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static int mt2060_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct mt2060_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
+static int mt2060_init(struct dvb_frontend *fe)
+{
+ struct mt2060_priv *priv = fe->tuner_priv;
+ return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x33);
+}
+
+static int mt2060_sleep(struct dvb_frontend *fe)
+{
+ struct mt2060_priv *priv = fe->tuner_priv;
+ return mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30);
+}
+
+static int mt2060_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops mt2060_tuner_ops = {
+ .info = {
+ .name = "Microtune MT2060",
+ .frequency_min = 48000000,
+ .frequency_max = 860000000,
+ .frequency_step = 50000,
+ },
+
+ .release = mt2060_release,
+
+ .init = mt2060_init,
+ .sleep = mt2060_sleep,
+
+ .set_params = mt2060_set_params,
+ .get_frequency = mt2060_get_frequency,
+ .get_bandwidth = mt2060_get_bandwidth
+};
+
+/* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */
+struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1)
+{
+ struct mt2060_priv *priv = NULL;
+ u8 id = 0;
+
+ priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+ priv->if1_freq = if1;
+
+ if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) {
+ kfree(priv);
+ return NULL;
+ }
+
+ if (id != PART_REV) {
+ kfree(priv);
+ return NULL;
+ }
+ printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1);
+ memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+
+ mt2060_calibrate(priv);
+
+ return fe;
+}
+EXPORT_SYMBOL(mt2060_attach);
+
+MODULE_AUTHOR("Olivier DANET");
+MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mt2060.h b/drivers/media/dvb/frontends/mt2060.h
new file mode 100644
index 000000000000..34a37c2b556f
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2060.h
@@ -0,0 +1,35 @@
+/*
+ * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ * Copyright (c) 2006 Olivier DANET <odanet@caramail.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MT2060_H
+#define MT2060_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct mt2060_config {
+ u8 i2c_address;
+ u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */
+};
+
+extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1);
+
+#endif
diff --git a/drivers/media/dvb/frontends/mt2060_priv.h b/drivers/media/dvb/frontends/mt2060_priv.h
new file mode 100644
index 000000000000..5eaccdefd0b0
--- /dev/null
+++ b/drivers/media/dvb/frontends/mt2060_priv.h
@@ -0,0 +1,105 @@
+/*
+ * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner"
+ *
+ * Copyright (c) 2006 Olivier DANET <odanet@caramail.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., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef MT2060_PRIV_H
+#define MT2060_PRIV_H
+
+// Uncomment the #define below to enable spurs checking. The results where quite unconvincing.
+// #define MT2060_SPURCHECK
+
+/* This driver is based on the information available in the datasheet of the
+ "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map :
+
+ I2C Address : 0x60
+
+ Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults )
+ --------------------------------------------------------------------------------
+ 00 | [ PART ] | [ REV ] | R = 0x63
+ 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F
+ 02 | [ DIV1 ] | RW = 0x74
+ 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00
+ 04 | NUM2(11:4) ] | RW = 0x08
+ 05 | [ DIV2 ] |NUM2(12)| RW = 0x93
+ 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R
+ 07 | [ FMF ] | R
+ 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R
+ 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20
+ 0A | ??
+ 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30
+ 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF
+ 0D | 1 | 0 | [ V1CS ] | RW = 0xB0
+ 0E | ??
+ 0F | ??
+ 10 | ??
+ 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42
+
+ PART : Part code : 6 for MT2060
+ REV : Revision code : 3 for current revision
+ LNABAND : Input frequency range : ( See code for details )
+ NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details )
+ FM1CA : Calibration Start Bit
+ FM1SS : Calibration Single Step bit
+ L1LK : LO1 Lock Detect
+ TAD1 : Tune Line ADC ( ? )
+ L2LK : LO2 Lock Detect
+ TAD2 : Tune Line ADC ( ? )
+ FMF : Estimated first IF Center frequency Offset ( ? )
+ FM1CAL : Calibration done bit
+ TEMP : On chip temperature sensor
+ FMCG : Mixer 1 Cap Gain ( ? )
+ GP01 / GP02 : Programmable digital outputs. Unconnected pins ?
+ V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? )
+ V1CS : LO1 Capacitor Selection Value ( ? )
+ LOTO : LO Timeout ( ? )
+ VGAG : Tuner Output gain
+*/
+
+#define I2C_ADDRESS 0x60
+
+#define REG_PART_REV 0
+#define REG_LO1C1 1
+#define REG_LO1C2 2
+#define REG_LO2C1 3
+#define REG_LO2C2 4
+#define REG_LO2C3 5
+#define REG_LO_STATUS 6
+#define REG_FM_FREQ 7
+#define REG_MISC_STAT 8
+#define REG_MISC_CTRL 9
+#define REG_RESERVED_A 0x0A
+#define REG_VGAG 0x0B
+#define REG_LO1B1 0x0C
+#define REG_LO1B2 0x0D
+#define REG_LOTO 0x11
+
+#define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips
+
+struct mt2060_priv {
+ struct mt2060_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 frequency;
+ u32 bandwidth;
+ u16 if1_freq;
+ u8 fmfreq;
+};
+
+#endif
diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h
index 666a1bd1c244..7112fb4d58ac 100644
--- a/drivers/media/dvb/frontends/mt312.h
+++ b/drivers/media/dvb/frontends/mt312.h
@@ -34,8 +34,16 @@ struct mt312_config
u8 demod_address;
};
+#if defined(CONFIG_DVB_MT312) || defined(CONFIG_DVB_MT312_MODULE)
struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
struct i2c_adapter* i2c);
-
+#else
+static inline struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_MT312
#endif // MT312_H
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index 5de7376c94ce..87e31ca7e108 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -70,7 +70,7 @@ static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
-int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+static int _mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
{
int err,i;
for (i=0; i < ilen-1; i++)
@@ -107,7 +107,7 @@ static int mt352_sleep(struct dvb_frontend* fe)
{
static u8 mt352_softdown[] = { CLOCK_CTL, 0x20, 0x08 };
- mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
+ _mt352_write(fe, mt352_softdown, sizeof(mt352_softdown));
return 0;
}
@@ -293,14 +293,14 @@ static int mt352_set_parameters(struct dvb_frontend* fe,
fe->ops.i2c_gate_ctrl(fe, 0);
}
- mt352_write(fe, buf, 8);
- mt352_write(fe, fsm_go, 2);
+ _mt352_write(fe, buf, 8);
+ _mt352_write(fe, fsm_go, 2);
} else {
if (fe->ops.tuner_ops.calc_regs) {
fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5);
buf[8] <<= 1;
- mt352_write(fe, buf, sizeof(buf));
- mt352_write(fe, tuner_go, 2);
+ _mt352_write(fe, buf, sizeof(buf));
+ _mt352_write(fe, tuner_go, 2);
}
}
@@ -522,7 +522,7 @@ static int mt352_init(struct dvb_frontend* fe)
(mt352_read_register(state, CONFIG) & 0x20) == 0) {
/* Do a "hard" reset */
- mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
+ _mt352_write(fe, mt352_reset_attach, sizeof(mt352_reset_attach));
return state->config.demod_init(fe);
}
@@ -585,6 +585,7 @@ static struct dvb_frontend_ops mt352_ops = {
.init = mt352_init,
.sleep = mt352_sleep,
+ .write = _mt352_write,
.set_frontend = mt352_set_parameters,
.get_frontend = mt352_get_parameters,
@@ -605,4 +606,3 @@ MODULE_AUTHOR("Holger Waechtler, Daniel Mack, Antonio Mancuso");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(mt352_attach);
-EXPORT_SYMBOL(mt352_write);
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 9e7ff4b8fe5f..0035c2e2d7c2 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -51,9 +51,23 @@ struct mt352_config
int (*demod_init)(struct dvb_frontend* fe);
};
+#if defined(CONFIG_DVB_MT352) || defined(CONFIG_DVB_MT352_MODULE)
extern struct dvb_frontend* mt352_attach(const struct mt352_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* mt352_attach(const struct mt352_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_MT352
-extern int mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen);
+static inline int mt352_write(struct dvb_frontend *fe, u8 *buf, int len) {
+ int r = 0;
+ if (fe->ops.write)
+ r = fe->ops.write(fe, buf, len);
+ return r;
+}
#endif // MT352_H
diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h
index 34d61735845b..2eb220e98062 100644
--- a/drivers/media/dvb/frontends/nxt200x.h
+++ b/drivers/media/dvb/frontends/nxt200x.h
@@ -45,8 +45,17 @@ struct nxt200x_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
+#if defined(CONFIG_DVB_NXT200X) || defined(CONFIG_DVB_NXT200X_MODULE)
extern struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_NXT200X
#endif /* NXT200X_H */
diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h
index 117031d11708..9397393a6bd1 100644
--- a/drivers/media/dvb/frontends/nxt6000.h
+++ b/drivers/media/dvb/frontends/nxt6000.h
@@ -33,7 +33,16 @@ struct nxt6000_config
u8 clock_inversion:1;
};
+#if defined(CONFIG_DVB_NXT6000) || defined(CONFIG_DVB_NXT6000_MODULE)
extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_NXT6000
#endif // NXT6000_H
diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h
index 89658883abf5..9718be4fb835 100644
--- a/drivers/media/dvb/frontends/or51132.h
+++ b/drivers/media/dvb/frontends/or51132.h
@@ -34,8 +34,17 @@ struct or51132_config
int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
};
+#if defined(CONFIG_DVB_OR51132) || defined(CONFIG_DVB_OR51132_MODULE)
extern struct dvb_frontend* or51132_attach(const struct or51132_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* or51132_attach(const struct or51132_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_OR51132
#endif // OR51132_H
diff --git a/drivers/media/dvb/frontends/or51211.h b/drivers/media/dvb/frontends/or51211.h
index 13a5a3afbf8b..10a5419f9e00 100644
--- a/drivers/media/dvb/frontends/or51211.h
+++ b/drivers/media/dvb/frontends/or51211.h
@@ -37,8 +37,17 @@ struct or51211_config
void (*sleep)(struct dvb_frontend * fe);
};
+#if defined(CONFIG_DVB_OR51211) || defined(CONFIG_DVB_OR51211_MODULE)
extern struct dvb_frontend* or51211_attach(const struct or51211_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* or51211_attach(const struct or51211_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_OR51211
#endif // OR51211_H
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
index 4e39015fa67e..efc54d7f3c55 100644
--- a/drivers/media/dvb/frontends/s5h1420.h
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -34,7 +34,16 @@ struct s5h1420_config
u8 invert:1;
};
+#if defined(CONFIG_DVB_S5H1420) || defined(CONFIG_DVB_S5H1420_MODULE)
extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_S5H1420
#endif // S5H1420_H
diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h
index 93afbb969d6b..4cf27d3b10f2 100644
--- a/drivers/media/dvb/frontends/sp8870.h
+++ b/drivers/media/dvb/frontends/sp8870.h
@@ -35,7 +35,16 @@ struct sp8870_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
+#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_SP8870
#endif // SP8870_H
diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h
index c44b0ebdf1e2..cab7ea644dfa 100644
--- a/drivers/media/dvb/frontends/sp887x.h
+++ b/drivers/media/dvb/frontends/sp887x.h
@@ -17,7 +17,16 @@ struct sp887x_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
+#if defined(CONFIG_DVB_SP887X) || defined(CONFIG_DVB_SP887X_MODULE)
extern struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* sp887x_attach(const struct sp887x_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_SP887X
#endif // SP887X_H
diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h
index 1da5384fb985..760b80db43a5 100644
--- a/drivers/media/dvb/frontends/stv0297.h
+++ b/drivers/media/dvb/frontends/stv0297.h
@@ -42,7 +42,16 @@ struct stv0297_config
u8 stop_during_read:1;
};
+#if defined(CONFIG_DVB_STV0297) || defined(CONFIG_DVB_STV0297_MODULE)
extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* stv0297_attach(const struct stv0297_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_STV0297
#endif // STV0297_H
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 96648a75440d..93483769eca8 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -92,11 +92,14 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data)
+int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct stv0299_state* state = fe->demodulator_priv;
- return stv0299_writeregI(state, reg, data);
+ if (len != 2)
+ return -EINVAL;
+
+ return stv0299_writeregI(state, buf[0], buf[1]);
}
static u8 stv0299_readreg (struct stv0299_state* state, u8 reg)
@@ -694,6 +697,7 @@ static struct dvb_frontend_ops stv0299_ops = {
.init = stv0299_init,
.sleep = stv0299_sleep,
+ .write = stv0299_write,
.i2c_gate_ctrl = stv0299_i2c_gate_ctrl,
.set_frontend = stv0299_set_frontend,
@@ -724,5 +728,4 @@ MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, "
"Andreas Oberritter, Andrew de Quincey, Kenneth Aafly");
MODULE_LICENSE("GPL");
-EXPORT_SYMBOL(stv0299_writereg);
EXPORT_SYMBOL(stv0299_attach);
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 1504828e4232..7ef25207081d 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -89,9 +89,24 @@ struct stv0299_config
int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio);
};
-extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data);
-
+#if defined(CONFIG_DVB_STV0299) || defined(CONFIG_DVB_STV0299_MODULE)
extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* stv0299_attach(const struct stv0299_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_STV0299
+
+static inline int stv0299_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+ int r = 0;
+ u8 buf[] = {reg, val};
+ if (fe->ops.write)
+ r = fe->ops.write(fe, buf, 2);
+ return r;
+}
#endif // STV0299_H
diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c
index 9cbd164aa281..dca89171be1f 100644
--- a/drivers/media/dvb/frontends/tda10021.c
+++ b/drivers/media/dvb/frontends/tda10021.c
@@ -72,7 +72,7 @@ static u8 tda10021_inittab[0x40]=
0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
};
-static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
+static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
{
u8 buf[] = { reg, data };
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
@@ -88,14 +88,6 @@ static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data)
-{
- struct tda10021_state* state = fe->demodulator_priv;
-
- return tda10021_writereg(state, reg, data);
-}
-EXPORT_SYMBOL(tda10021_write_byte);
-
static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
{
u8 b0 [] = { reg };
@@ -149,8 +141,8 @@ static int tda10021_setup_reg0 (struct tda10021_state* state, u8 reg0,
else if (INVERSION_OFF == inversion)
DISABLE_INVERSION(reg0);
- tda10021_writereg (state, 0x00, reg0 & 0xfe);
- tda10021_writereg (state, 0x00, reg0 | 0x01);
+ _tda10021_writereg (state, 0x00, reg0 & 0xfe);
+ _tda10021_writereg (state, 0x00, reg0 | 0x01);
state->reg0 = reg0;
return 0;
@@ -198,17 +190,27 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
NDEC = (NDEC << 6) | tda10021_inittab[0x03];
- tda10021_writereg (state, 0x03, NDEC);
- tda10021_writereg (state, 0x0a, BDR&0xff);
- tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
- tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
+ _tda10021_writereg (state, 0x03, NDEC);
+ _tda10021_writereg (state, 0x0a, BDR&0xff);
+ _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
+ _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
- tda10021_writereg (state, 0x0d, BDRI);
- tda10021_writereg (state, 0x0e, SFIL);
+ _tda10021_writereg (state, 0x0d, BDRI);
+ _tda10021_writereg (state, 0x0e, SFIL);
return 0;
}
+int tda10021_write(struct dvb_frontend* fe, u8 *buf, int len)
+{
+ struct tda10021_state* state = fe->demodulator_priv;
+
+ if (len != 2)
+ return -EINVAL;
+
+ return _tda10021_writereg(state, buf[0], buf[1]);
+}
+
static int tda10021_init (struct dvb_frontend *fe)
{
struct tda10021_state* state = fe->demodulator_priv;
@@ -216,12 +218,12 @@ static int tda10021_init (struct dvb_frontend *fe)
dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
- //tda10021_writereg (fe, 0, 0);
+ //_tda10021_writereg (fe, 0, 0);
for (i=0; i<tda10021_inittab_size; i++)
- tda10021_writereg (state, i, tda10021_inittab[i]);
+ _tda10021_writereg (state, i, tda10021_inittab[i]);
- tda10021_writereg (state, 0x34, state->pwm);
+ _tda10021_writereg (state, 0x34, state->pwm);
//Comment by markus
//0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
@@ -230,7 +232,7 @@ static int tda10021_init (struct dvb_frontend *fe)
//0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
//Activate PLL
- tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
+ _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
return 0;
}
@@ -264,12 +266,12 @@ static int tda10021_set_parameters (struct dvb_frontend *fe,
}
tda10021_set_symbolrate (state, p->u.qam.symbol_rate);
- tda10021_writereg (state, 0x34, state->pwm);
+ _tda10021_writereg (state, 0x34, state->pwm);
- tda10021_writereg (state, 0x01, reg0x01[qam]);
- tda10021_writereg (state, 0x05, reg0x05[qam]);
- tda10021_writereg (state, 0x08, reg0x08[qam]);
- tda10021_writereg (state, 0x09, reg0x09[qam]);
+ _tda10021_writereg (state, 0x01, reg0x01[qam]);
+ _tda10021_writereg (state, 0x05, reg0x05[qam]);
+ _tda10021_writereg (state, 0x08, reg0x08[qam]);
+ _tda10021_writereg (state, 0x09, reg0x09[qam]);
tda10021_setup_reg0 (state, reg0x00[qam], p->inversion);
@@ -342,8 +344,8 @@ static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
*ucblocks = 0xffffffff;
/* reset uncorrected block counter */
- tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
- tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
+ _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
+ _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
return 0;
}
@@ -392,8 +394,8 @@ static int tda10021_sleep(struct dvb_frontend* fe)
{
struct tda10021_state* state = fe->demodulator_priv;
- tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
- tda10021_writereg (state, 0x00, 0x80); /* standby */
+ _tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
+ _tda10021_writereg (state, 0x00, 0x80); /* standby */
return 0;
}
@@ -459,6 +461,7 @@ static struct dvb_frontend_ops tda10021_ops = {
.init = tda10021_init,
.sleep = tda10021_sleep,
+ .write = tda10021_write,
.i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
.set_frontend = tda10021_set_parameters,
diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h
index b1df4259bee9..d68ae20c8412 100644
--- a/drivers/media/dvb/frontends/tda10021.h
+++ b/drivers/media/dvb/frontends/tda10021.h
@@ -32,9 +32,24 @@ struct tda10021_config
u8 demod_address;
};
+#if defined(CONFIG_DVB_TDA10021) || defined(CONFIG_DVB_TDA10021_MODULE)
extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
struct i2c_adapter* i2c, u8 pwm);
-
-extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data);
+#else
+static inline struct dvb_frontend* tda10021_attach(const struct tda10021_config* config,
+ struct i2c_adapter* i2c, u8 pwm)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TDA10021
+
+static inline int tda10021_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+ int r = 0;
+ u8 buf[] = {reg, val};
+ if (fe->ops.write)
+ r = fe->ops.write(fe, buf, 2);
+ return r;
+}
#endif // TDA10021_H
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 59a2ed614fca..11e0dca9a2d7 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -579,11 +579,14 @@ static int tda1004x_decode_fec(int tdafec)
return -1;
}
-int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data)
+int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
{
struct tda1004x_state* state = fe->demodulator_priv;
- return tda1004x_write_byteI(state, reg, data);
+ if (len != 2)
+ return -EINVAL;
+
+ return tda1004x_write_byteI(state, buf[0], buf[1]);
}
static int tda10045_init(struct dvb_frontend* fe)
@@ -1216,6 +1219,7 @@ static struct dvb_frontend_ops tda10045_ops = {
.init = tda10045_init,
.sleep = tda1004x_sleep,
+ .write = tda1004x_write,
.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
@@ -1274,6 +1278,7 @@ static struct dvb_frontend_ops tda10046_ops = {
.init = tda10046_init,
.sleep = tda1004x_sleep,
+ .write = tda1004x_write,
.i2c_gate_ctrl = tda1004x_i2c_gate_ctrl,
.set_frontend = tda1004x_set_fe,
@@ -1323,4 +1328,3 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(tda10045_attach);
EXPORT_SYMBOL(tda10046_attach);
-EXPORT_SYMBOL(tda1004x_write_byte);
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index b877b23ed734..e28fca05734c 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -71,12 +71,33 @@ struct tda1004x_config
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
+#if defined(CONFIG_DVB_TDA1004X) || defined(CONFIG_DVB_TDA1004X_MODULE)
extern struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
struct i2c_adapter* i2c);
extern struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
struct i2c_adapter* i2c);
-
-extern int tda1004x_write_byte(struct dvb_frontend* fe, int reg, int data);
+#else
+static inline struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+static inline struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TDA1004X
+
+static inline int tda1004x_writereg(struct dvb_frontend *fe, u8 reg, u8 val) {
+ int r = 0;
+ u8 buf[] = {reg, val};
+ if (fe->ops.write)
+ r = fe->ops.write(fe, buf, 2);
+ return r;
+}
#endif // TDA1004X_H
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
new file mode 100644
index 000000000000..7456b0b9976b
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -0,0 +1,740 @@
+ /*
+ Driver for Philips tda10086 DVBS Demodulator
+
+ (c) 2006 Andrew de Quincey
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "tda10086.h"
+
+#define SACLK 96000000
+
+struct tda10086_state {
+ struct i2c_adapter* i2c;
+ const struct tda10086_config* config;
+ struct dvb_frontend frontend;
+
+ /* private demod data */
+ u32 frequency;
+ u32 symbol_rate;
+};
+
+static int debug = 0;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "tda10086: " args); \
+ } while (0)
+
+static int tda10086_write_byte(struct tda10086_state *state, int reg, int data)
+{
+ int ret;
+ u8 b0[] = { reg, data };
+ struct i2c_msg msg = { .flags = 0, .buf = b0, .len = 2 };
+
+ msg.addr = state->config->demod_address;
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
+ __FUNCTION__, reg, data, ret);
+
+ return (ret != 1) ? ret : 0;
+}
+
+static int tda10086_read_byte(struct tda10086_state *state, int reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+ struct i2c_msg msg[] = {{ .flags = 0, .buf = b0, .len = 1 },
+ { .flags = I2C_M_RD, .buf = b1, .len = 1 }};
+
+ msg[0].addr = state->config->demod_address;
+ msg[1].addr = state->config->demod_address;
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2) {
+ dprintk("%s: error reg=0x%x, ret=%i\n", __FUNCTION__, reg,
+ ret);
+ return ret;
+ }
+
+ return b1[0];
+}
+
+static int tda10086_write_mask(struct tda10086_state *state, int reg, int mask, int data)
+{
+ int val;
+
+ // read a byte and check
+ val = tda10086_read_byte(state, reg);
+ if (val < 0)
+ return val;
+
+ // mask if off
+ val = val & ~mask;
+ val |= data & 0xff;
+
+ // write it out again
+ return tda10086_write_byte(state, reg, val);
+}
+
+static int tda10086_init(struct dvb_frontend* fe)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ // reset
+ tda10086_write_byte(state, 0x00, 0x00);
+ msleep(10);
+
+ // misc setup
+ tda10086_write_byte(state, 0x01, 0x94);
+ tda10086_write_byte(state, 0x02, 0x35); // NOTE: TT drivers appear to disable CSWP
+ tda10086_write_byte(state, 0x03, 0x64);
+ tda10086_write_byte(state, 0x04, 0x43);
+ tda10086_write_byte(state, 0x0c, 0x0c);
+ tda10086_write_byte(state, 0x1b, 0xb0); // noise threshold
+ tda10086_write_byte(state, 0x20, 0x89); // misc
+ tda10086_write_byte(state, 0x30, 0x04); // acquisition period length
+ tda10086_write_byte(state, 0x32, 0x00); // irq off
+ tda10086_write_byte(state, 0x31, 0x56); // setup AFC
+
+ // setup PLL (assumes 16Mhz XIN)
+ tda10086_write_byte(state, 0x55, 0x2c); // misc PLL setup
+ tda10086_write_byte(state, 0x3a, 0x0b); // M=12
+ tda10086_write_byte(state, 0x3b, 0x01); // P=2
+ tda10086_write_mask(state, 0x55, 0x20, 0x00); // powerup PLL
+
+ // setup TS interface
+ tda10086_write_byte(state, 0x11, 0x81);
+ tda10086_write_byte(state, 0x12, 0x81);
+ tda10086_write_byte(state, 0x19, 0x40); // parallel mode A + MSBFIRST
+ tda10086_write_byte(state, 0x56, 0x80); // powerdown WPLL - unused in the mode we use
+ tda10086_write_byte(state, 0x57, 0x08); // bypass WPLL - unused in the mode we use
+ tda10086_write_byte(state, 0x10, 0x2a);
+
+ // setup ADC
+ tda10086_write_byte(state, 0x58, 0x61); // ADC setup
+ tda10086_write_mask(state, 0x58, 0x01, 0x00); // powerup ADC
+
+ // setup AGC
+ tda10086_write_byte(state, 0x05, 0x0B);
+ tda10086_write_byte(state, 0x37, 0x63);
+ tda10086_write_byte(state, 0x3f, 0x03); // NOTE: flydvb uses 0x0a and varies it
+ tda10086_write_byte(state, 0x40, 0x64);
+ tda10086_write_byte(state, 0x41, 0x4f);
+ tda10086_write_byte(state, 0x42, 0x43);
+
+ // setup viterbi
+ tda10086_write_byte(state, 0x1a, 0x11); // VBER 10^6, DVB, QPSK
+
+ // setup carrier recovery
+ tda10086_write_byte(state, 0x3d, 0x80);
+
+ // setup SEC
+ tda10086_write_byte(state, 0x36, 0x00); // all SEC off
+ tda10086_write_byte(state, 0x34, (((1<<19) * (22000/1000)) / (SACLK/1000))); // } tone frequency
+ tda10086_write_byte(state, 0x35, (((1<<19) * (22000/1000)) / (SACLK/1000)) >> 8); // }
+
+ return 0;
+}
+
+static void tda10086_diseqc_wait(struct tda10086_state *state)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(200);
+ while (!(tda10086_read_byte(state, 0x50) & 0x01)) {
+ if(time_after(jiffies, timeout)) {
+ printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__);
+ break;
+ }
+ msleep(10);
+ }
+}
+
+static int tda10086_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ switch(tone) {
+ case SEC_TONE_OFF:
+ tda10086_write_byte(state, 0x36, 0x00);
+ break;
+
+ case SEC_TONE_ON:
+ tda10086_write_byte(state, 0x36, 0x01);
+ break;
+ }
+
+ return 0;
+}
+
+static int tda10086_send_master_cmd (struct dvb_frontend* fe,
+ struct dvb_diseqc_master_cmd* cmd)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+ int i;
+ u8 oldval;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (cmd->msg_len > 6)
+ return -EINVAL;
+ oldval = tda10086_read_byte(state, 0x36);
+
+ for(i=0; i< cmd->msg_len; i++) {
+ tda10086_write_byte(state, 0x48+i, cmd->msg[i]);
+ }
+ tda10086_write_byte(state, 0x36, 0x08 | ((cmd->msg_len + 1) << 4));
+
+ tda10086_diseqc_wait(state);
+
+ tda10086_write_byte(state, 0x36, oldval);
+
+ return 0;
+}
+
+static int tda10086_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+ u8 oldval = tda10086_read_byte(state, 0x36);
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ switch(minicmd) {
+ case SEC_MINI_A:
+ tda10086_write_byte(state, 0x36, 0x04);
+ break;
+
+ case SEC_MINI_B:
+ tda10086_write_byte(state, 0x36, 0x06);
+ break;
+ }
+
+ tda10086_diseqc_wait(state);
+
+ tda10086_write_byte(state, 0x36, oldval);
+
+ return 0;
+}
+
+static int tda10086_set_inversion(struct tda10086_state *state,
+ struct dvb_frontend_parameters *fe_params)
+{
+ u8 invval = 0x80;
+
+ dprintk ("%s %i %i\n", __FUNCTION__, fe_params->inversion, state->config->invert);
+
+ switch(fe_params->inversion) {
+ case INVERSION_OFF:
+ if (state->config->invert)
+ invval = 0x40;
+ break;
+ case INVERSION_ON:
+ if (!state->config->invert)
+ invval = 0x40;
+ break;
+ case INVERSION_AUTO:
+ invval = 0x00;
+ break;
+ }
+ tda10086_write_mask(state, 0x0c, 0xc0, invval);
+
+ return 0;
+}
+
+static int tda10086_set_symbol_rate(struct tda10086_state *state,
+ struct dvb_frontend_parameters *fe_params)
+{
+ u8 dfn = 0;
+ u8 afs = 0;
+ u8 byp = 0;
+ u8 reg37 = 0x43;
+ u8 reg42 = 0x43;
+ u64 big;
+ u32 tmp;
+ u32 bdr;
+ u32 bdri;
+ u32 symbol_rate = fe_params->u.qpsk.symbol_rate;
+
+ dprintk ("%s %i\n", __FUNCTION__, symbol_rate);
+
+ // setup the decimation and anti-aliasing filters..
+ if (symbol_rate < (u32) (SACLK * 0.0137)) {
+ dfn=4;
+ afs=1;
+ } else if (symbol_rate < (u32) (SACLK * 0.0208)) {
+ dfn=4;
+ afs=0;
+ } else if (symbol_rate < (u32) (SACLK * 0.0270)) {
+ dfn=3;
+ afs=1;
+ } else if (symbol_rate < (u32) (SACLK * 0.0416)) {
+ dfn=3;
+ afs=0;
+ } else if (symbol_rate < (u32) (SACLK * 0.0550)) {
+ dfn=2;
+ afs=1;
+ } else if (symbol_rate < (u32) (SACLK * 0.0833)) {
+ dfn=2;
+ afs=0;
+ } else if (symbol_rate < (u32) (SACLK * 0.1100)) {
+ dfn=1;
+ afs=1;
+ } else if (symbol_rate < (u32) (SACLK * 0.1666)) {
+ dfn=1;
+ afs=0;
+ } else if (symbol_rate < (u32) (SACLK * 0.2200)) {
+ dfn=0;
+ afs=1;
+ } else if (symbol_rate < (u32) (SACLK * 0.3333)) {
+ dfn=0;
+ afs=0;
+ } else {
+ reg37 = 0x63;
+ reg42 = 0x4f;
+ byp=1;
+ }
+
+ // calculate BDR
+ big = (1ULL<<21) * ((u64) symbol_rate/1000ULL) * (1ULL<<dfn);
+ big += ((SACLK/1000ULL)-1ULL);
+ do_div(big, (SACLK/1000ULL));
+ bdr = big & 0xfffff;
+
+ // calculate BDRI
+ tmp = (1<<dfn)*(symbol_rate/1000);
+ bdri = ((32 * (SACLK/1000)) + (tmp-1)) / tmp;
+
+ tda10086_write_byte(state, 0x21, (afs << 7) | dfn);
+ tda10086_write_mask(state, 0x20, 0x08, byp << 3);
+ tda10086_write_byte(state, 0x06, bdr);
+ tda10086_write_byte(state, 0x07, bdr >> 8);
+ tda10086_write_byte(state, 0x08, bdr >> 16);
+ tda10086_write_byte(state, 0x09, bdri);
+ tda10086_write_byte(state, 0x37, reg37);
+ tda10086_write_byte(state, 0x42, reg42);
+
+ return 0;
+}
+
+static int tda10086_set_fec(struct tda10086_state *state,
+ struct dvb_frontend_parameters *fe_params)
+{
+ u8 fecval;
+
+ dprintk ("%s %i\n", __FUNCTION__, fe_params->u.qpsk.fec_inner);
+
+ switch(fe_params->u.qpsk.fec_inner) {
+ case FEC_1_2:
+ fecval = 0x00;
+ break;
+ case FEC_2_3:
+ fecval = 0x01;
+ break;
+ case FEC_3_4:
+ fecval = 0x02;
+ break;
+ case FEC_4_5:
+ fecval = 0x03;
+ break;
+ case FEC_5_6:
+ fecval = 0x04;
+ break;
+ case FEC_6_7:
+ fecval = 0x05;
+ break;
+ case FEC_7_8:
+ fecval = 0x06;
+ break;
+ case FEC_8_9:
+ fecval = 0x07;
+ break;
+ case FEC_AUTO:
+ fecval = 0x08;
+ break;
+ default:
+ return -1;
+ }
+ tda10086_write_byte(state, 0x0d, fecval);
+
+ return 0;
+}
+
+static int tda10086_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fe_params)
+{
+ struct tda10086_state *state = fe->demodulator_priv;
+ int ret;
+ u32 freq = 0;
+ int freqoff;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ // set params
+ if (fe->ops.tuner_ops.set_params) {
+ fe->ops.tuner_ops.set_params(fe, fe_params);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (fe->ops.tuner_ops.get_frequency)
+ fe->ops.tuner_ops.get_frequency(fe, &freq);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ // calcluate the frequency offset (in *Hz* not kHz)
+ freqoff = fe_params->frequency - freq;
+ freqoff = ((1<<16) * freqoff) / (SACLK/1000);
+ tda10086_write_byte(state, 0x3d, 0x80 | ((freqoff >> 8) & 0x7f));
+ tda10086_write_byte(state, 0x3e, freqoff);
+
+ if ((ret = tda10086_set_inversion(state, fe_params)) < 0)
+ return ret;
+ if ((ret = tda10086_set_symbol_rate(state, fe_params)) < 0)
+ return ret;
+ if ((ret = tda10086_set_fec(state, fe_params)) < 0)
+ return ret;
+
+ // soft reset + disable TS output until lock
+ tda10086_write_mask(state, 0x10, 0x40, 0x40);
+ tda10086_write_mask(state, 0x00, 0x01, 0x00);
+
+ state->symbol_rate = fe_params->u.qpsk.symbol_rate;
+ state->frequency = fe_params->frequency;
+ return 0;
+}
+
+static int tda10086_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *fe_params)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+ u8 val;
+ int tmp;
+ u64 tmp64;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ // calculate the updated frequency (note: we convert from Hz->kHz)
+ tmp64 = tda10086_read_byte(state, 0x52);
+ tmp64 |= (tda10086_read_byte(state, 0x51) << 8);
+ if (tmp64 & 0x8000)
+ tmp64 |= 0xffffffffffff0000ULL;
+ tmp64 = (tmp64 * (SACLK/1000ULL));
+ do_div(tmp64, (1ULL<<15) * (1ULL<<1));
+ fe_params->frequency = (int) state->frequency + (int) tmp64;
+
+ // the inversion
+ val = tda10086_read_byte(state, 0x0c);
+ if (val & 0x80) {
+ switch(val & 0x40) {
+ case 0x00:
+ fe_params->inversion = INVERSION_OFF;
+ if (state->config->invert)
+ fe_params->inversion = INVERSION_ON;
+ break;
+ default:
+ fe_params->inversion = INVERSION_ON;
+ if (state->config->invert)
+ fe_params->inversion = INVERSION_OFF;
+ break;
+ }
+ } else {
+ tda10086_read_byte(state, 0x0f);
+ switch(val & 0x02) {
+ case 0x00:
+ fe_params->inversion = INVERSION_OFF;
+ if (state->config->invert)
+ fe_params->inversion = INVERSION_ON;
+ break;
+ default:
+ fe_params->inversion = INVERSION_ON;
+ if (state->config->invert)
+ fe_params->inversion = INVERSION_OFF;
+ break;
+ }
+ }
+
+ // calculate the updated symbol rate
+ tmp = tda10086_read_byte(state, 0x1d);
+ if (tmp & 0x80)
+ tmp |= 0xffffff00;
+ tmp = (tmp * 480 * (1<<1)) / 128;
+ tmp = ((state->symbol_rate/1000) * tmp) / (1000000/1000);
+ fe_params->u.qpsk.symbol_rate = state->symbol_rate + tmp;
+
+ // the FEC
+ val = (tda10086_read_byte(state, 0x0d) & 0x70) >> 4;
+ switch(val) {
+ case 0x00:
+ fe_params->u.qpsk.fec_inner = FEC_1_2;
+ break;
+ case 0x01:
+ fe_params->u.qpsk.fec_inner = FEC_2_3;
+ break;
+ case 0x02:
+ fe_params->u.qpsk.fec_inner = FEC_3_4;
+ break;
+ case 0x03:
+ fe_params->u.qpsk.fec_inner = FEC_4_5;
+ break;
+ case 0x04:
+ fe_params->u.qpsk.fec_inner = FEC_5_6;
+ break;
+ case 0x05:
+ fe_params->u.qpsk.fec_inner = FEC_6_7;
+ break;
+ case 0x06:
+ fe_params->u.qpsk.fec_inner = FEC_7_8;
+ break;
+ case 0x07:
+ fe_params->u.qpsk.fec_inner = FEC_8_9;
+ break;
+ }
+
+ return 0;
+}
+
+static int tda10086_read_status(struct dvb_frontend* fe, fe_status_t *fe_status)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+ u8 val;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ val = tda10086_read_byte(state, 0x0e);
+ *fe_status = 0;
+ if (val & 0x01)
+ *fe_status |= FE_HAS_SIGNAL;
+ if (val & 0x02)
+ *fe_status |= FE_HAS_CARRIER;
+ if (val & 0x04)
+ *fe_status |= FE_HAS_VITERBI;
+ if (val & 0x08)
+ *fe_status |= FE_HAS_SYNC;
+ if (val & 0x10)
+ *fe_status |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int tda10086_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+ u8 _str;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ _str = tda10086_read_byte(state, 0x43);
+ *signal = (_str << 8) | _str;
+
+ return 0;
+}
+
+static int tda10086_read_snr(struct dvb_frontend* fe, u16 * snr)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+ u8 _snr;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ _snr = tda10086_read_byte(state, 0x1c);
+ *snr = (_snr << 8) | _snr;
+
+ return 0;
+}
+
+static int tda10086_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ // read it
+ *ucblocks = tda10086_read_byte(state, 0x18) & 0x7f;
+
+ // reset counter
+ tda10086_write_byte(state, 0x18, 0x00);
+ tda10086_write_byte(state, 0x18, 0x80);
+
+ return 0;
+}
+
+static int tda10086_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ // read it
+ *ber = 0;
+ *ber |= tda10086_read_byte(state, 0x15);
+ *ber |= tda10086_read_byte(state, 0x16) << 8;
+ *ber |= (tda10086_read_byte(state, 0x17) & 0xf) << 16;
+
+ return 0;
+}
+
+static int tda10086_sleep(struct dvb_frontend* fe)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ tda10086_write_mask(state, 0x00, 0x08, 0x08);
+
+ return 0;
+}
+
+static int tda10086_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct tda10086_state* state = fe->demodulator_priv;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ if (enable) {
+ tda10086_write_mask(state, 0x00, 0x10, 0x10);
+ } else {
+ tda10086_write_mask(state, 0x00, 0x10, 0x00);
+ }
+
+ return 0;
+}
+
+static int tda10086_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+ fesettings->min_delay_ms = 50;
+ fesettings->step_size = 2000;
+ fesettings->max_drift = 8000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 1500;
+ fesettings->max_drift = 9000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 1000;
+ fesettings->max_drift = 8000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 500;
+ fesettings->max_drift = 7000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->max_drift = 14 * fesettings->step_size;
+ } else {
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->max_drift = 18 * fesettings->step_size;
+ }
+
+ return 0;
+}
+
+static void tda10086_release(struct dvb_frontend* fe)
+{
+ struct tda10086_state *state = fe->demodulator_priv;
+ tda10086_sleep(fe);
+ kfree(state);
+}
+
+static struct dvb_frontend_ops tda10086_ops = {
+
+ .info = {
+ .name = "Philips TDA10086 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK
+ },
+
+ .release = tda10086_release,
+
+ .init = tda10086_init,
+ .sleep = tda10086_sleep,
+ .i2c_gate_ctrl = tda10086_i2c_gate_ctrl,
+
+ .set_frontend = tda10086_set_frontend,
+ .get_frontend = tda10086_get_frontend,
+ .get_tune_settings = tda10086_get_tune_settings,
+
+ .read_status = tda10086_read_status,
+ .read_ber = tda10086_read_ber,
+ .read_signal_strength = tda10086_read_signal_strength,
+ .read_snr = tda10086_read_snr,
+ .read_ucblocks = tda10086_read_ucblocks,
+
+ .diseqc_send_master_cmd = tda10086_send_master_cmd,
+ .diseqc_send_burst = tda10086_send_burst,
+ .set_tone = tda10086_set_tone,
+};
+
+struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct tda10086_state *state;
+
+ dprintk ("%s\n", __FUNCTION__);
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct tda10086_state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ /* check if the demod is there */
+ if (tda10086_read_byte(state, 0x1e) != 0xe1) {
+ kfree(state);
+ return NULL;
+ }
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &tda10086_ops, sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+}
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("Philips TDA10086 DVB-S Demodulator");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(tda10086_attach);
diff --git a/drivers/media/dvb/frontends/tda10086.h b/drivers/media/dvb/frontends/tda10086.h
new file mode 100644
index 000000000000..18457adee30b
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda10086.h
@@ -0,0 +1,50 @@
+ /*
+ Driver for Philips tda10086 DVBS Frontend
+
+ (c) 2006 Andrew de Quincey
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#ifndef TDA10086_H
+#define TDA10086_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct tda10086_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* does the "inversion" need inverted? */
+ u8 invert;
+};
+
+#if defined(CONFIG_DVB_TDA10086) || defined(CONFIG_DVB_TDA10086_MODULE)
+extern struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+ struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* tda10086_attach(const struct tda10086_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TDA10086
+
+#endif // TDA10086_H
diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h
index e7a48f61ea2c..aae15bdce6eb 100644
--- a/drivers/media/dvb/frontends/tda8083.h
+++ b/drivers/media/dvb/frontends/tda8083.h
@@ -35,7 +35,16 @@ struct tda8083_config
u8 demod_address;
};
+#if defined(CONFIG_DVB_TDA8083) || defined(CONFIG_DVB_TDA8083_MODULE)
extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* tda8083_attach(const struct tda8083_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TDA8083
#endif // TDA8083_H
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
new file mode 100644
index 000000000000..eeab26bd36ed
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda826x.c
@@ -0,0 +1,173 @@
+ /*
+ Driver for Philips tda8262/tda8263 DVBS Silicon tuners
+
+ (c) 2006 Andrew de Quincey
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "tda826x.h"
+
+static int debug = 0;
+#define dprintk(args...) \
+ do { \
+ if (debug) printk(KERN_DEBUG "tda826x: " args); \
+ } while (0)
+
+struct tda826x_priv {
+ /* i2c details */
+ int i2c_address;
+ struct i2c_adapter *i2c;
+ u8 has_loopthrough:1;
+ u32 frequency;
+};
+
+static int tda826x_release(struct dvb_frontend *fe)
+{
+ if (fe->tuner_priv)
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int tda826x_sleep(struct dvb_frontend *fe)
+{
+ struct tda826x_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 buf [] = { 0x00, 0x8d };
+ struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 2 };
+
+ dprintk("%s:\n", __FUNCTION__);
+
+ if (!priv->has_loopthrough)
+ buf[1] = 0xad;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+ dprintk("%s: i2c error\n", __FUNCTION__);
+ }
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int tda826x_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct tda826x_priv *priv = fe->tuner_priv;
+ int ret;
+ u32 div;
+ u8 buf [11];
+ struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = buf, .len = 11 };
+
+ dprintk("%s:\n", __FUNCTION__);
+
+ div = (params->frequency + (1000-1)) / 1000;
+
+ buf[0] = 0x00; // subaddress
+ buf[1] = 0x09; // powerdown RSSI + the magic value 1
+ if (!priv->has_loopthrough)
+ buf[1] |= 0x20; // power down loopthrough if not needed
+ buf[2] = (1<<5) | 0x0b; // 1Mhz + 0.45 VCO
+ buf[3] = div >> 7;
+ buf[4] = div << 1;
+ buf[5] = 0xff; // basedband filter to max
+ buf[6] = 0xfe; // gains at max + no RF attenuation
+ buf[7] = 0x83; // charge pumps at high, tests off
+ buf[8] = 0x80; // recommended value 4 for AMPVCO + disable ports.
+ buf[9] = 0x1a; // normal caltime + recommended values for SELTH + SELVTL
+ buf[10] = 0xd4; // recommended value 13 for BBIAS + unknown bit set on
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+ dprintk("%s: i2c error\n", __FUNCTION__);
+ }
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ priv->frequency = div * 1000;
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int tda826x_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tda826x_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops tda826x_tuner_ops = {
+ .info = {
+ .name = "Philips TDA826X",
+ .frequency_min = 950000,
+ .frequency_min = 2175000
+ },
+ .release = tda826x_release,
+ .sleep = tda826x_sleep,
+ .set_params = tda826x_set_params,
+ .get_frequency = tda826x_get_frequency,
+};
+
+struct dvb_frontend *tda826x_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c, int has_loopthrough)
+{
+ struct tda826x_priv *priv = NULL;
+ u8 b1 [] = { 0, 0 };
+ struct i2c_msg msg = { .addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 2 };
+ int ret;
+
+ dprintk("%s:\n", __FUNCTION__);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ ret = i2c_transfer (i2c, &msg, 1);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (ret != 1)
+ return NULL;
+ if (!(b1[1] & 0x80))
+ return NULL;
+
+ priv = kzalloc(sizeof(struct tda826x_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->i2c_address = addr;
+ priv->i2c = i2c;
+ priv->has_loopthrough = has_loopthrough;
+
+ memcpy(&fe->ops.tuner_ops, &tda826x_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = priv;
+
+ return fe;
+}
+EXPORT_SYMBOL(tda826x_attach);
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+MODULE_DESCRIPTION("DVB TDA826x driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tda826x.h b/drivers/media/dvb/frontends/tda826x.h
new file mode 100644
index 000000000000..83998c001196
--- /dev/null
+++ b/drivers/media/dvb/frontends/tda826x.h
@@ -0,0 +1,53 @@
+ /*
+ Driver for Philips tda8262/tda8263 DVBS Silicon tuners
+
+ (c) 2006 Andrew de Quincey
+
+ 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#ifndef __DVB_TDA826X_H__
+#define __DVB_TDA826X_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a tda826x tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param addr i2c address of the tuner.
+ * @param i2c i2c adapter to use.
+ * @param has_loopthrough Set to 1 if the card has a loopthrough RF connector.
+ * @return FE pointer on success, NULL on failure.
+ */
+#if defined(CONFIG_DVB_TDA826X) || defined(CONFIG_DVB_TDA826X_MODULE)
+extern struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe, int addr,
+ struct i2c_adapter *i2c,
+ int has_loopthrough);
+#else
+static inline struct dvb_frontend* tda826x_attach(struct dvb_frontend *fe,
+ int addr,
+ struct i2c_adapter *i2c,
+ int has_loopthrough)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TDA826X
+
+#endif // __DVB_TDA826X_H__
diff --git a/drivers/media/dvb/frontends/tua6100.c b/drivers/media/dvb/frontends/tua6100.c
new file mode 100644
index 000000000000..88554393a9bf
--- /dev/null
+++ b/drivers/media/dvb/frontends/tua6100.c
@@ -0,0 +1,205 @@
+/**
+ * Driver for Infineon tua6100 pll.
+ *
+ * (c) 2006 Andrew de Quincey
+ *
+ * Based on code found in budget-av.c, which has the following:
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ * Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph Metzler
+ * & Marcus Metzler for convergence integrated media GmbH
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <asm/types.h>
+
+#include "tua6100.h"
+
+struct tua6100_priv {
+ /* i2c details */
+ int i2c_address;
+ struct i2c_adapter *i2c;
+ u32 frequency;
+};
+
+static int tua6100_release(struct dvb_frontend *fe)
+{
+ if (fe->tuner_priv)
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static int tua6100_sleep(struct dvb_frontend *fe)
+{
+ struct tua6100_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 reg0[] = { 0x00, 0x00 };
+ struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if ((ret = i2c_transfer (priv->i2c, &msg, 1)) != 1) {
+ printk("%s: i2c error\n", __FUNCTION__);
+ }
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int tua6100_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct tua6100_priv *priv = fe->tuner_priv;
+ u32 div;
+ u32 prediv;
+ u8 reg0[] = { 0x00, 0x00 };
+ u8 reg1[] = { 0x01, 0x00, 0x00, 0x00 };
+ u8 reg2[] = { 0x02, 0x00, 0x00 };
+ struct i2c_msg msg0 = { .addr = priv->i2c_address, .flags = 0, .buf = reg0, .len = 2 };
+ struct i2c_msg msg1 = { .addr = priv->i2c_address, .flags = 0, .buf = reg1, .len = 4 };
+ struct i2c_msg msg2 = { .addr = priv->i2c_address, .flags = 0, .buf = reg2, .len = 3 };
+
+#define _R 4
+#define _P 32
+#define _ri 4000000
+
+ // setup register 0
+ if (params->frequency < 2000000) {
+ reg0[1] = 0x03;
+ } else {
+ reg0[1] = 0x07;
+ }
+
+ // setup register 1
+ if (params->frequency < 1630000) {
+ reg1[1] = 0x2c;
+ } else {
+ reg1[1] = 0x0c;
+ }
+ if (_P == 64)
+ reg1[1] |= 0x40;
+ if (params->frequency >= 1525000)
+ reg1[1] |= 0x80;
+
+ // register 2
+ reg2[1] = (_R >> 8) & 0x03;
+ reg2[2] = _R;
+ if (params->frequency < 1455000) {
+ reg2[1] |= 0x1c;
+ } else if (params->frequency < 1630000) {
+ reg2[1] |= 0x0c;
+ } else {
+ reg2[1] |= 0x1c;
+ }
+
+ // The N divisor ratio (note: params->frequency is in kHz, but we need it in Hz)
+ prediv = (params->frequency * _R) / (_ri / 1000);
+ div = prediv / _P;
+ reg1[1] |= (div >> 9) & 0x03;
+ reg1[2] = div >> 1;
+ reg1[3] = (div << 7);
+ priv->frequency = ((div * _P) * (_ri / 1000)) / _R;
+
+ // Finally, calculate and store the value for A
+ reg1[3] |= (prediv - (div*_P)) & 0x7f;
+
+#undef _R
+#undef _P
+#undef _ri
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(priv->i2c, &msg0, 1) != 1)
+ return -EIO;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(priv->i2c, &msg2, 1) != 1)
+ return -EIO;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (i2c_transfer(priv->i2c, &msg1, 1) != 1)
+ return -EIO;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+}
+
+static int tua6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct tua6100_priv *priv = fe->tuner_priv;
+ *frequency = priv->frequency;
+ return 0;
+}
+
+static struct dvb_tuner_ops tua6100_tuner_ops = {
+ .info = {
+ .name = "Infineon TUA6100",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_step = 1000,
+ },
+ .release = tua6100_release,
+ .sleep = tua6100_sleep,
+ .set_params = tua6100_set_params,
+ .get_frequency = tua6100_get_frequency,
+};
+
+struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
+{
+ struct tua6100_priv *priv = NULL;
+ u8 b1 [] = { 0x80 };
+ u8 b2 [] = { 0x00 };
+ struct i2c_msg msg [] = { { .addr = addr, .flags = 0, .buf = b1, .len = 1 },
+ { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 } };
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ ret = i2c_transfer (i2c, msg, 2);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (ret != 2)
+ return NULL;
+
+ priv = kzalloc(sizeof(struct tua6100_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->i2c_address = addr;
+ priv->i2c = i2c;
+
+ memcpy(&fe->ops.tuner_ops, &tua6100_tuner_ops, sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = priv;
+ return fe;
+}
+EXPORT_SYMBOL(tua6100_attach);
+
+MODULE_DESCRIPTION("DVB tua6100 driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/tua6100.h b/drivers/media/dvb/frontends/tua6100.h
new file mode 100644
index 000000000000..8f98033ffa7b
--- /dev/null
+++ b/drivers/media/dvb/frontends/tua6100.h
@@ -0,0 +1,47 @@
+/**
+ * Driver for Infineon tua6100 PLL.
+ *
+ * (c) 2006 Andrew de Quincey
+ *
+ * Based on code found in budget-av.c, which has the following:
+ * Compiled from various sources by Michael Hunold <michael@mihu.de>
+ *
+ * CI interface support (c) 2004 Olivier Gournet <ogournet@anevia.com> &
+ * Andrew de Quincey <adq_dvb@lidskialf.net>
+ *
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * Copyright (C) 1999-2002 Ralph Metzler
+ * & Marcus Metzler for convergence integrated media GmbH
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __DVB_TUA6100_H__
+#define __DVB_TUA6100_H__
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+#if defined(CONFIG_DVB_TUA6100) || defined(CONFIG_DVB_TUA6100_MODULE)
+extern struct dvb_frontend *tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend* tua6100_attach(struct dvb_frontend *fe, int addr, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_TUA6100
+
+#endif
diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h
index 520f09522fbb..f0c9dded39d7 100644
--- a/drivers/media/dvb/frontends/ves1820.h
+++ b/drivers/media/dvb/frontends/ves1820.h
@@ -41,7 +41,16 @@ struct ves1820_config
u8 selagc:1;
};
+#if defined(CONFIG_DVB_VES1820) || defined(CONFIG_DVB_VES1820_MODULE)
extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
struct i2c_adapter* i2c, u8 pwm);
+#else
+static inline struct dvb_frontend* ves1820_attach(const struct ves1820_config* config,
+ struct i2c_adapter* i2c, u8 pwm)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_VES1820
#endif // VES1820_H
diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h
index ba88ae0855c9..395fed39b286 100644
--- a/drivers/media/dvb/frontends/ves1x93.h
+++ b/drivers/media/dvb/frontends/ves1x93.h
@@ -40,7 +40,16 @@ struct ves1x93_config
u8 invert_pwm:1;
};
+#if defined(CONFIG_DVB_VES1X93) || defined(CONFIG_DVB_VES1X93_MODULE)
extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
struct i2c_adapter* i2c);
+#else
+static inline struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
+ struct i2c_adapter* i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_VES1X93
#endif // VES1X93_H
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 2b95e8b6cd39..0e9b59af271e 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -140,6 +140,8 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
zl10353_single_write(fe, 0x5E, 0x00);
zl10353_single_write(fe, 0x65, 0x5A);
zl10353_single_write(fe, 0x66, 0xE9);
+ zl10353_single_write(fe, 0x6C, 0xCD);
+ zl10353_single_write(fe, 0x6D, 0x7E);
zl10353_single_write(fe, 0x62, 0x0A);
// if there is no attached secondary tuner, we call set_params to program
@@ -168,6 +170,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe,
// even if there isn't a PLL attached to the secondary bus
zl10353_write(fe, pllbuf, sizeof(pllbuf));
+ zl10353_single_write(fe, 0x5F, 0x13);
zl10353_single_write(fe, 0x70, 0x01);
udelay(250);
zl10353_single_write(fe, 0xE4, 0x00);
@@ -243,9 +246,12 @@ static int zl10353_init(struct dvb_frontend *fe)
if (debug_regs)
zl10353_dump_regs(fe);
+ if (state->config.parallel_ts)
+ zl10353_reset_attach[2] &= ~0x20;
/* Do a "hard" reset if not already done */
- if (zl10353_read_register(state, 0x50) != 0x03) {
+ if (zl10353_read_register(state, 0x50) != zl10353_reset_attach[1] ||
+ zl10353_read_register(state, 0x51) != zl10353_reset_attach[2]) {
rc = zl10353_write(fe, zl10353_reset_attach,
sizeof(zl10353_reset_attach));
if (debug_regs)
@@ -258,7 +264,6 @@ static int zl10353_init(struct dvb_frontend *fe)
static void zl10353_release(struct dvb_frontend *fe)
{
struct zl10353_state *state = fe->demodulator_priv;
-
kfree(state);
}
@@ -314,6 +319,7 @@ static struct dvb_frontend_ops zl10353_ops = {
.init = zl10353_init,
.sleep = zl10353_sleep,
+ .write = zl10353_write,
.set_frontend = zl10353_set_parameters,
.get_tune_settings = zl10353_get_tune_settings,
@@ -330,4 +336,3 @@ MODULE_AUTHOR("Chris Pascoe");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(zl10353_attach);
-EXPORT_SYMBOL(zl10353_write);
diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h
index 9770cb840cfc..79a947215c4d 100644
--- a/drivers/media/dvb/frontends/zl10353.h
+++ b/drivers/media/dvb/frontends/zl10353.h
@@ -31,11 +31,21 @@ struct zl10353_config
/* set if no pll is connected to the secondary i2c bus */
int no_tuner;
+
+ /* set if parallel ts output is required */
+ int parallel_ts;
};
+#if defined(CONFIG_DVB_ZL10353) || defined(CONFIG_DVB_ZL10353_MODULE)
extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
struct i2c_adapter *i2c);
-
-extern int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen);
+#else
+static inline struct dvb_frontend* zl10353_attach(const struct zl10353_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif // CONFIG_DVB_ZL10353
#endif /* ZL10353_H */
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 2310b2bfed4e..8e4ce101eb22 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -306,7 +306,7 @@ static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
}
-static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pluto_irq(int irq, void *dev_id)
{
struct pluto *pluto = dev_id;
u32 tscr;
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 5fb097595cfb..95531a624991 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -1,17 +1,17 @@
config DVB_AV7110
tristate "AV7110 cards"
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
- select FW_LOADER
+ select FW_LOADER if !DVB_AV7110_FIRMWARE
select VIDEO_SAA7146_VV
select DVB_PLL
- select DVB_VES1820
- select DVB_VES1X93
- select DVB_STV0299
- select DVB_TDA8083
- select DVB_SP8870
- select DVB_STV0297
- select DVB_L64781
- select DVB_LNBP21
+ select DVB_VES1820 if !DVB_FE_CUSTOMISE
+ select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+ select DVB_SP8870 if !DVB_FE_CUSTOMISE
+ select DVB_STV0297 if !DVB_FE_CUSTOMISE
+ select DVB_L64781 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
help
Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
@@ -63,14 +63,16 @@ config DVB_BUDGET
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146
select DVB_PLL
- select DVB_STV0299
- select DVB_VES1X93
- select DVB_VES1820
- select DVB_L64781
- select DVB_TDA8083
- select DVB_TDA10021
- select DVB_S5H1420
- select DVB_LNBP21
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+ select DVB_VES1820 if !DVB_FE_CUSTOMISE
+ select DVB_L64781 if !DVB_FE_CUSTOMISE
+ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_S5H1420 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+ select DVB_TDA826X if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -86,10 +88,10 @@ config DVB_BUDGET_CI
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146
select DVB_PLL
- select DVB_STV0297
- select DVB_STV0299
- select DVB_TDA1004X
- select DVB_LNBP21
+ select DVB_STV0297 if !DVB_FE_CUSTOMISE
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -108,9 +110,10 @@ config DVB_BUDGET_AV
depends on DVB_CORE && PCI && I2C && VIDEO_V4L1
select VIDEO_SAA7146_VV
select DVB_PLL
- select DVB_STV0299
- select DVB_TDA1004X
- select DVB_TDA10021
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+ select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_TUA6100 if !DVB_FE_CUSTOMISE
select FW_LOADER
help
Support for simple SAA7146 based DVB cards
@@ -127,9 +130,9 @@ config DVB_BUDGET_PATCH
depends on DVB_CORE && DVB_BUDGET && VIDEO_V4L1
select DVB_AV7110
select DVB_PLL
- select DVB_STV0299
- select DVB_VES1X93
- select DVB_TDA8083
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_VES1X93 if !DVB_FE_CUSTOMISE
+ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
help
Support for Budget Patch (full TS) modification on
SAA7146+AV7110 based cards (DVB-S cards). This
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 4506165c5de2..bba23bcd1b11 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -1383,8 +1383,10 @@ static void dvb_unregister(struct av7110 *av7110)
dvb_dmxdev_release(&av7110->dmxdev);
dvb_dmx_release(&av7110->demux);
- if (av7110->fe != NULL)
+ if (av7110->fe != NULL) {
dvb_unregister_frontend(av7110->fe);
+ dvb_frontend_detach(av7110->fe);
+ }
dvb_unregister_device(av7110->osd_dev);
av7110_av_unregister(av7110);
av7110_ca_unregister(av7110);
@@ -1699,9 +1701,13 @@ static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_front
static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
+#if defined(CONFIG_DVB_SP8870) || defined(CONFIG_DVB_SP8870_MODULE)
struct av7110* av7110 = (struct av7110*) fe->dvb->priv;
return request_firmware(fw, name, &av7110->dev->pci->dev);
+#else
+ return -EINVAL;
+#endif
}
static struct sp8870_config alps_tdlb7_config = {
@@ -2077,7 +2083,7 @@ static int frontend_init(struct av7110 *av7110)
if (av7110->dev->pci->subsystem_vendor == 0x110a) {
switch(av7110->dev->pci->subsystem_device) {
case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
- av7110->fe = ves1820_attach(&philips_cd1516_config,
+ av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config,
&av7110->i2c_adap, read_pwm(av7110));
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
@@ -2092,7 +2098,7 @@ static int frontend_init(struct av7110 *av7110)
case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
// try the ALPS BSRV2 first of all
- av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
+ av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2103,7 +2109,7 @@ static int frontend_init(struct av7110 *av7110)
}
// try the ALPS BSRU6 now
- av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap);
+ av7110->fe = dvb_attach(stv0299_attach, &alps_bsru6_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
av7110->fe->tuner_priv = &av7110->i2c_adap;
@@ -2116,7 +2122,7 @@ static int frontend_init(struct av7110 *av7110)
}
// Try the grundig 29504-451
- av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+ av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2130,7 +2136,7 @@ static int frontend_init(struct av7110 *av7110)
switch(av7110->dev->pci->subsystem_device) {
case 0x0000:
/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
- av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap,
+ av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap,
read_pwm(av7110));
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
@@ -2138,7 +2144,7 @@ static int frontend_init(struct av7110 *av7110)
break;
case 0x0003:
/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
- av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap,
+ av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap,
read_pwm(av7110));
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
@@ -2148,17 +2154,24 @@ static int frontend_init(struct av7110 *av7110)
break;
case 0x0001: // Hauppauge/TT Nexus-T premium rev1.X
-
- // ALPS TDLB7
- av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap);
+ // try ALPS TDLB7 first, then Grundig 29504-401
+ av7110->fe = dvb_attach(sp8870_attach, &alps_tdlb7_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params;
+ break;
}
+ /* fall-thru */
+
+ case 0x0008: // Hauppauge/TT DVB-T
+ // Grundig 29504-401
+ av7110->fe = dvb_attach(l64781_attach, &grundig_29504_401_config, &av7110->i2c_adap);
+ if (av7110->fe)
+ av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
break;
case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
- av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
+ av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
}
@@ -2166,7 +2179,7 @@ static int frontend_init(struct av7110 *av7110)
case 0x0004: // Galaxis DVB-S rev1.3
/* ALPS BSRV2 */
- av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap);
+ av7110->fe = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2178,7 +2191,7 @@ static int frontend_init(struct av7110 *av7110)
case 0x0006: /* Fujitsu-Siemens DVB-S rev 1.6 */
/* Grundig 29504-451 */
- av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap);
+ av7110->fe = dvb_attach(tda8083_attach, &grundig_29504_451_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd;
@@ -2188,17 +2201,9 @@ static int frontend_init(struct av7110 *av7110)
}
break;
- case 0x0008: // Hauppauge/TT DVB-T
-
- av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap);
- if (av7110->fe) {
- av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
- }
- break;
-
case 0x000A: // Hauppauge/TT Nexus-CA rev1.X
- av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap);
+ av7110->fe = dvb_attach(stv0297_attach, &nexusca_stv0297_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params;
@@ -2214,12 +2219,12 @@ static int frontend_init(struct av7110 *av7110)
case 0x000E: /* Hauppauge/TT Nexus-S rev 2.3 */
/* ALPS BSBE1 */
- av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap);
+ av7110->fe = dvb_attach(stv0299_attach, &alps_bsbe1_config, &av7110->i2c_adap);
if (av7110->fe) {
av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
av7110->fe->tuner_priv = &av7110->i2c_adap;
- if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) {
+ if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) {
printk("dvb-ttpci: LNBP21 not found!\n");
if (av7110->fe->ops.release)
av7110->fe->ops.release(av7110->fe);
@@ -2255,8 +2260,7 @@ static int frontend_init(struct av7110 *av7110)
ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
if (ret < 0) {
printk("av7110: Frontend registration failed!\n");
- if (av7110->fe->ops.release)
- av7110->fe->ops.release(av7110->fe);
+ dvb_frontend_detach(av7110->fe);
av7110->fe = NULL;
}
}
@@ -2823,7 +2827,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension av7110_extension = {
- .name = "dvb\0",
+ .name = "dvb",
.flags = SAA7146_I2C_SHORT_DELAY,
.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 0f3a044aeb17..8c577cf30fb3 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -33,7 +33,6 @@
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/delay.h>
-#include <linux/byteorder/swabb.h>
#include <linux/smp_lock.h>
#include <linux/fs.h>
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index 6079e8865d5b..dd9aee314e0a 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -35,7 +35,6 @@
#include <linux/fs.h>
#include <linux/timer.h>
#include <linux/poll.h>
-#include <linux/byteorder/swabb.h>
#include <linux/smp_lock.h>
#include "av7110.h"
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 75736f2fe838..37de2e88a273 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -34,7 +34,6 @@
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/delay.h>
-#include <linux/byteorder/swabb.h>
#include <linux/smp_lock.h>
#include <linux/fs.h>
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 6ffe53fdcf57..10cfe3131e72 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -32,7 +32,6 @@
#include <linux/fs.h>
#include <linux/timer.h>
#include <linux/poll.h>
-#include <linux/byteorder/swabb.h>
#include <linux/smp_lock.h>
#include "av7110.h"
@@ -922,7 +921,7 @@ static struct saa7146_ext_vv av7110_vv_data_st = {
static struct saa7146_ext_vv av7110_vv_data_c = {
.inputs = 1,
.audios = 1,
- .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_OUTPUT,
+ .capabilities = V4L2_CAP_TUNER | V4L2_CAP_SLICED_VBI_OUTPUT,
.flags = SAA7146_USE_PORT_B_FOR_VBI,
.stds = &standard[0],
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 2d21fec23b4d..2235ff8b8a1d 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -37,6 +37,7 @@
#include "stv0299.h"
#include "tda10021.h"
#include "tda1004x.h"
+#include "tua6100.h"
#include "dvb-pll.h"
#include <media/saa7146_vv.h>
#include <linux/module.h>
@@ -235,7 +236,7 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot)
/* set tda10021 back to original clock configuration on reset */
if (budget_av->tda10021_poclkp) {
- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
budget_av->tda10021_ts_enabled = 0;
}
@@ -257,7 +258,7 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot)
/* set tda10021 back to original clock configuration when cam removed */
if (budget_av->tda10021_poclkp) {
- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
budget_av->tda10021_ts_enabled = 0;
}
return 0;
@@ -277,7 +278,7 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
/* tda10021 seems to need a different TS clock config when data is routed to the CAM */
if (budget_av->tda10021_poclkp) {
- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
budget_av->tda10021_ts_enabled = 1;
}
@@ -548,144 +549,6 @@ static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe,
return 0;
}
-#define MIN2(a,b) ((a) < (b) ? (a) : (b))
-#define MIN3(a,b,c) MIN2(MIN2(a,b),c)
-
-static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *params)
-{
- u8 reg0 [2] = { 0x00, 0x00 };
- u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 };
- u8 reg2 [3] = { 0x02, 0x00, 0x00 };
- int _fband;
- int first_ZF;
- int R, A, N, P, M;
- struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 };
- int freq = params->frequency;
- struct budget *budget = (struct budget *) fe->dvb->priv;
-
- first_ZF = (freq) / 1000;
-
- if (abs(MIN2(abs(first_ZF-1190),abs(first_ZF-1790))) <
- abs(MIN3(abs(first_ZF-1202),abs(first_ZF-1542),abs(first_ZF-1890))))
- _fband = 2;
- else
- _fband = 3;
-
- if (_fband == 2) {
- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
- ((first_ZF >= 1430) && (first_ZF < 1950)))
- reg0[1] = 0x07;
- else if (((first_ZF >= 1350) && (first_ZF < 1430)) ||
- ((first_ZF >= 1950) && (first_ZF < 2150)))
- reg0[1] = 0x0B;
- }
-
- if(_fband == 3) {
- if (((first_ZF >= 950) && (first_ZF < 1350)) ||
- ((first_ZF >= 1455) && (first_ZF < 1950)))
- reg0[1] = 0x07;
- else if (((first_ZF >= 1350) && (first_ZF < 1420)) ||
- ((first_ZF >= 1950) && (first_ZF < 2150)))
- reg0[1] = 0x0B;
- else if ((first_ZF >= 1420) && (first_ZF < 1455))
- reg0[1] = 0x0F;
- }
-
- if (first_ZF > 1525)
- reg1[1] |= 0x80;
- else
- reg1[1] &= 0x7F;
-
- if (_fband == 2) {
- if (first_ZF > 1430) { /* 1430MHZ */
- reg1[1] &= 0xCF; /* N2 */
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- } else {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- }
- }
-
- if (_fband == 3) {
- if ((first_ZF >= 1455) &&
- (first_ZF < 1630)) {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- } else {
- if (first_ZF < 1455) {
- reg1[1] &= 0xCF; /* N2 */
- reg1[1] |= 0x20;
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- } else {
- if (first_ZF >= 1630) {
- reg1[1] &= 0xCF; /* N2 */
- reg2[1] &= 0xCF; /* R2 */
- reg2[1] |= 0x10;
- }
- }
- }
- }
-
- /* set ports, enable P0 for symbol rates > 4Ms/s */
- if (params->u.qpsk.symbol_rate >= 4000000)
- reg1[1] |= 0x0c;
- else
- reg1[1] |= 0x04;
-
- reg2[1] |= 0x0c;
-
- R = 64;
- A = 64;
- P = 64; //32
-
- M = (freq * R) / 4; /* in Mhz */
- N = (M - A * 1000) / (P * 1000);
-
- reg1[1] |= (N >> 9) & 0x03;
- reg1[2] = (N >> 1) & 0xff;
- reg1[3] = (N << 7) & 0x80;
-
- reg2[1] |= (R >> 8) & 0x03;
- reg2[2] = R & 0xFF; /* R */
-
- reg1[3] |= A & 0x7f; /* A */
-
- if (P == 64)
- reg1[1] |= 0x40; /* Prescaler 64/65 */
-
- reg0[1] |= 0x03;
-
- /* already enabled - do not reenable i2c repeater or TX fails */
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- msg.buf = reg0;
- msg.len = sizeof(reg0);
- if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
- return -EIO;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- msg.buf = reg1;
- msg.len = sizeof(reg1);
- if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
- return -EIO;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- msg.buf = reg2;
- msg.len = sizeof(reg2);
- if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
- return -EIO;
-
- return 0;
-}
-
static u8 typhoon_cinergy1200s_inittab[] = {
0x01, 0x15,
0x02, 0x30,
@@ -1068,9 +931,9 @@ static int tda10021_set_frontend(struct dvb_frontend *fe,
result = budget_av->tda10021_set_frontend(fe, p);
if (budget_av->tda10021_ts_enabled) {
- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1);
+ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa1);
} else {
- tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0);
+ tda10021_writereg(budget_av->budget.dvb_frontend, 0x12, 0xa0);
}
return result;
@@ -1096,15 +959,16 @@ static void frontend_init(struct budget_av *budget_av)
switch (saa->pci->subsystem_device) {
case SUBID_DVBS_KNC1:
+ case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBS_EASYWATCH_1:
if (saa->pci->subsystem_vendor == 0x1894) {
- fe = stv0299_attach(&cinergy_1200s_1894_0010_config,
+ fe = dvb_attach(stv0299_attach, &cinergy_1200s_1894_0010_config,
&budget_av->budget.i2c_adap);
if (fe) {
- fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params;
+ dvb_attach(tua6100_attach, fe, 0x60, &budget_av->budget.i2c_adap);
}
} else {
- fe = stv0299_attach(&typhoon_config,
+ fe = dvb_attach(stv0299_attach, &typhoon_config,
&budget_av->budget.i2c_adap);
if (fe) {
fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
@@ -1116,16 +980,15 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBS_TV_STAR_CI:
case SUBID_DVBS_CYNERGY1200N:
case SUBID_DVBS_EASYWATCH:
- fe = stv0299_attach(&philips_sd1878_config,
+ fe = dvb_attach(stv0299_attach, &philips_sd1878_config,
&budget_av->budget.i2c_adap);
if (fe) {
fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params;
}
break;
- case SUBID_DVBS_KNC1_PLUS:
case SUBID_DVBS_TYPHOON:
- fe = stv0299_attach(&typhoon_config,
+ fe = dvb_attach(stv0299_attach, &typhoon_config,
&budget_av->budget.i2c_adap);
if (fe) {
fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
@@ -1133,7 +996,7 @@ static void frontend_init(struct budget_av *budget_av)
break;
case SUBID_DVBS_CINERGY1200:
- fe = stv0299_attach(&cinergy_1200s_config,
+ fe = dvb_attach(stv0299_attach, &cinergy_1200s_config,
&budget_av->budget.i2c_adap);
if (fe) {
fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params;
@@ -1141,19 +1004,10 @@ static void frontend_init(struct budget_av *budget_av)
break;
case SUBID_DVBC_KNC1:
- budget_av->reinitialise_demod = 1;
- fe = tda10021_attach(&philips_cu1216_config,
- &budget_av->budget.i2c_adap,
- read_pwm(budget_av));
- if (fe) {
- fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params;
- }
- break;
-
case SUBID_DVBC_KNC1_PLUS:
case SUBID_DVBC_CINERGY1200:
budget_av->reinitialise_demod = 1;
- fe = tda10021_attach(&philips_cu1216_config,
+ fe = dvb_attach(tda10021_attach, &philips_cu1216_config,
&budget_av->budget.i2c_adap,
read_pwm(budget_av));
if (fe) {
@@ -1168,7 +1022,7 @@ static void frontend_init(struct budget_av *budget_av)
case SUBID_DVBT_KNC1_PLUS:
case SUBID_DVBT_CINERGY1200:
budget_av->reinitialise_demod = 1;
- fe = tda10046_attach(&philips_tu1216_config,
+ fe = dvb_attach(tda10046_attach, &philips_tu1216_config,
&budget_av->budget.i2c_adap);
if (fe) {
fe->ops.tuner_ops.init = philips_tu1216_tuner_init;
@@ -1192,8 +1046,7 @@ static void frontend_init(struct budget_av *budget_av)
if (dvb_register_frontend(&budget_av->budget.dvb_adapter,
budget_av->budget.dvb_frontend)) {
printk(KERN_ERR "budget-av: Frontend registration failed!\n");
- if (budget_av->budget.dvb_frontend->ops.release)
- budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend);
+ dvb_frontend_detach(budget_av->budget.dvb_frontend);
budget_av->budget.dvb_frontend = NULL;
}
}
@@ -1227,8 +1080,10 @@ static int budget_av_detach(struct saa7146_dev *dev)
if (budget_av->budget.ci_present)
ciintf_deinit(budget_av);
- if (budget_av->budget.dvb_frontend != NULL)
+ if (budget_av->budget.dvb_frontend != NULL) {
dvb_unregister_frontend(budget_av->budget.dvb_frontend);
+ dvb_frontend_detach(budget_av->budget.dvb_frontend);
+ }
err = ttpci_budget_deinit(&budget_av->budget);
kfree(budget_av);
@@ -1400,6 +1255,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(knc1s, 0x1131, 0x0010),
MAKE_EXTENSION_PCI(knc1s, 0x1894, 0x0010),
MAKE_EXTENSION_PCI(knc1sp, 0x1131, 0x0011),
+ MAKE_EXTENSION_PCI(knc1sp, 0x1894, 0x0011),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014),
MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016),
MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e),
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index ffbbb3e34be4..2a2e9b400613 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -749,17 +749,17 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb
// setup PLL filter and TDA9889
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
- tda1004x_write_byte(fe, 0x0C, 0x14);
+ tda1004x_writereg(fe, 0x0C, 0x14);
filter = 0;
break;
case BANDWIDTH_7_MHZ:
- tda1004x_write_byte(fe, 0x0C, 0x80);
+ tda1004x_writereg(fe, 0x0C, 0x80);
filter = 0;
break;
case BANDWIDTH_8_MHZ:
- tda1004x_write_byte(fe, 0x0C, 0x14);
+ tda1004x_writereg(fe, 0x0C, 0x14);
filter = 1;
break;
@@ -988,7 +988,7 @@ static void frontend_init(struct budget_ci *budget_ci)
switch (budget_ci->budget.dev->pci->subsystem_device) {
case 0x100c: // Hauppauge/TT Nova-CI budget (stv0299/ALPS BSRU6(tsa5059))
budget_ci->budget.dvb_frontend =
- stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap);
+ dvb_attach(stv0299_attach, &alps_bsru6_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
@@ -998,7 +998,7 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x100f: // Hauppauge/TT Nova-CI budget (stv0299b/Philips su1278(tsa5059))
budget_ci->budget.dvb_frontend =
- stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
+ dvb_attach(stv0299_attach, &philips_su1278_tt_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params;
break;
@@ -1008,7 +1008,7 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x1010: // TT DVB-C CI budget (stv0297/Philips tdm1316l(tda6651tt))
budget_ci->tuner_pll_address = 0x61;
budget_ci->budget.dvb_frontend =
- stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
@@ -1018,7 +1018,7 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
budget_ci->tuner_pll_address = 0x63;
budget_ci->budget.dvb_frontend =
- tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ dvb_attach(tda10045_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
@@ -1029,7 +1029,7 @@ static void frontend_init(struct budget_ci *budget_ci)
case 0x1012: // TT DVB-T CI budget (tda10046/Philips tdm1316l(tda6651tt))
budget_ci->tuner_pll_address = 0x60;
budget_ci->budget.dvb_frontend =
- tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ dvb_attach(tda10046_attach, &philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
@@ -1038,16 +1038,15 @@ static void frontend_init(struct budget_ci *budget_ci)
break;
case 0x1017: // TT S-1500 PCI
- budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap);
+ budget_ci->budget.dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap;
budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;
- if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) {
+ if (dvb_attach(lnbp21_attach, budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0) == NULL) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
- if (budget_ci->budget.dvb_frontend->ops.release)
- budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
+ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
@@ -1065,8 +1064,7 @@ static void frontend_init(struct budget_ci *budget_ci)
if (dvb_register_frontend
(&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) {
printk("budget-ci: Frontend registration failed!\n");
- if (budget_ci->budget.dvb_frontend->ops.release)
- budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend);
+ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
budget_ci->budget.dvb_frontend = NULL;
}
}
@@ -1114,8 +1112,10 @@ static int budget_ci_detach(struct saa7146_dev *dev)
if (budget_ci->budget.ci_present)
ciintf_deinit(budget_ci);
- if (budget_ci->budget.dvb_frontend)
+ if (budget_ci->budget.dvb_frontend) {
dvb_unregister_frontend(budget_ci->budget.dvb_frontend);
+ dvb_frontend_detach(budget_ci->budget.dvb_frontend);
+ }
err = ttpci_budget_deinit(&budget_ci->budget);
tasklet_kill(&budget_ci->msp430_irq_tasklet);
@@ -1153,7 +1153,7 @@ static struct pci_device_id pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension budget_extension = {
- .name = "budget_ci dvb\0",
+ .name = "budget_ci dvb",
.flags = SAA7146_I2C_SHORT_DELAY,
.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 57227441891e..fc1267b8c892 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -325,7 +325,7 @@ static void frontend_init(struct budget_patch* budget)
case 0x1013: // SATELCO Multimedia PCI
// try the ALPS BSRV2 first of all
- budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
@@ -335,7 +335,7 @@ static void frontend_init(struct budget_patch* budget)
}
// try the ALPS BSRU6 now
- budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
@@ -347,7 +347,7 @@ static void frontend_init(struct budget_patch* budget)
}
// Try the grundig 29504-451
- budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
@@ -367,8 +367,7 @@ static void frontend_init(struct budget_patch* budget)
} else {
if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
printk("budget-av: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops.release)
- budget->dvb_frontend->ops.release(budget->dvb_frontend);
+ dvb_frontend_detach(budget->dvb_frontend);
budget->dvb_frontend = NULL;
}
}
@@ -627,8 +626,10 @@ static int budget_patch_detach (struct saa7146_dev* dev)
struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
int err;
- if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
-
+ if (budget->dvb_frontend) {
+ dvb_unregister_frontend(budget->dvb_frontend);
+ dvb_frontend_detach(budget->dvb_frontend);
+ }
err = ttpci_budget_deinit (budget);
kfree (budget);
@@ -647,7 +648,7 @@ static void __exit budget_patch_exit(void)
}
static struct saa7146_extension budget_extension = {
- .name = "budget_patch dvb\0",
+ .name = "budget_patch dvb",
.flags = 0,
.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 863dffb4ed8e..e58f0391e9d1 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -41,6 +41,8 @@
#include "l64781.h"
#include "tda8083.h"
#include "s5h1420.h"
+#include "tda10086.h"
+#include "tda826x.h"
#include "lnbp21.h"
#include "bsru6.h"
@@ -342,6 +344,11 @@ static struct s5h1420_config s5h1420_config = {
.invert = 1,
};
+static struct tda10086_config tda10086_config = {
+ .demod_address = 0x0e,
+ .invert = 0,
+};
+
static u8 read_pwm(struct budget* budget)
{
u8 b = 0xff;
@@ -361,7 +368,7 @@ static void frontend_init(struct budget *budget)
case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))
case 0x1013:
// try the ALPS BSRV2 first of all
- budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
@@ -371,7 +378,7 @@ static void frontend_init(struct budget *budget)
}
// try the ALPS BSRU6 now
- budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
@@ -381,7 +388,7 @@ static void frontend_init(struct budget *budget)
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
- budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
+ budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
break;
@@ -390,7 +397,7 @@ static void frontend_init(struct budget *budget)
case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))
- budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;
break;
@@ -398,7 +405,7 @@ static void frontend_init(struct budget *budget)
break;
case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059))
- budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
@@ -408,7 +415,7 @@ static void frontend_init(struct budget *budget)
break;
case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))
- budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;
@@ -417,10 +424,28 @@ static void frontend_init(struct budget *budget)
break;
case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
- budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
+ budget->dvb_frontend = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);
if (budget->dvb_frontend) {
budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params;
- if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) {
+ if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
+ printk("%s: No LNBP21 found!\n", __FUNCTION__);
+ goto error_out;
+ }
+ break;
+ }
+
+ case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)
+ // gpio2 is connected to CLB - reset it + leave it high
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);
+ msleep(1);
+ saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);
+ msleep(1);
+
+ budget->dvb_frontend = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ if (dvb_attach(tda826x_attach, budget->dvb_frontend, 0x60, &budget->i2c_adap, 0) == NULL)
+ printk("%s: No tda826x found!\n", __FUNCTION__);
+ if (dvb_attach(lnbp21_attach, budget->dvb_frontend, &budget->i2c_adap, 0, 0) == NULL) {
printk("%s: No LNBP21 found!\n", __FUNCTION__);
goto error_out;
}
@@ -442,8 +467,7 @@ static void frontend_init(struct budget *budget)
error_out:
printk("budget: Frontend registration failed!\n");
- if (budget->dvb_frontend->ops.release)
- budget->dvb_frontend->ops.release(budget->dvb_frontend);
+ dvb_frontend_detach(budget->dvb_frontend);
budget->dvb_frontend = NULL;
return;
}
@@ -481,7 +505,10 @@ static int budget_detach (struct saa7146_dev* dev)
struct budget *budget = (struct budget*) dev->ext_priv;
int err;
- if (budget->dvb_frontend) dvb_unregister_frontend(budget->dvb_frontend);
+ if (budget->dvb_frontend) {
+ dvb_unregister_frontend(budget->dvb_frontend);
+ dvb_frontend_detach(budget->dvb_frontend);
+ }
err = ttpci_budget_deinit (budget);
@@ -497,6 +524,7 @@ MAKE_BUDGET_INFO(ttbs, "TT-Budget/WinTV-NOVA-S PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbc, "TT-Budget/WinTV-NOVA-C PCI", BUDGET_TT);
MAKE_BUDGET_INFO(ttbt, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
MAKE_BUDGET_INFO(satel, "SATELCO Multimedia PCI", BUDGET_TT_HW_DISEQC);
+MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);
MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);
MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);
@@ -506,6 +534,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
+ MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),
MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
{
@@ -516,7 +545,7 @@ static struct pci_device_id pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension budget_extension = {
- .name = "budget dvb\0",
+ .name = "budget dvb",
.flags = SAA7146_I2C_SHORT_DELAY,
.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 46a6a60d2ab9..e78ea9227b0e 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -2,13 +2,13 @@ config DVB_TTUSB_BUDGET
tristate "Technotrend/Hauppauge Nova-USB devices"
depends on DVB_CORE && USB && I2C
select DVB_PLL
- select DVB_CX22700
- select DVB_TDA1004X
- select DVB_VES1820
- select DVB_TDA8083
- select DVB_STV0299
- select DVB_STV0297
- select DVB_LNBP21
+ select DVB_CX22700 if !DVB_FE_CUSTOMISE
+ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+ select DVB_VES1820 if !DVB_FE_CUSTOMISE
+ select DVB_TDA8083 if !DVB_FE_CUSTOMISE
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_STV0297 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
help
Support for external USB adapters designed by Technotrend and
produced by Hauppauge, shipped under the brand name 'Nova-USB'.
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 04cef3023457..60820deb900b 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -732,7 +732,7 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
}
}
-static void ttusb_iso_irq(struct urb *urb, struct pt_regs *ptregs)
+static void ttusb_iso_irq(struct urb *urb)
{
struct ttusb *ttusb = urb->context;
@@ -1107,17 +1107,17 @@ static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb
// setup PLL filter
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
- tda1004x_write_byte(fe, 0x0C, 0);
+ tda1004x_writereg(fe, 0x0C, 0);
filter = 0;
break;
case BANDWIDTH_7_MHZ:
- tda1004x_write_byte(fe, 0x0C, 0);
+ tda1004x_writereg(fe, 0x0C, 0);
filter = 0;
break;
case BANDWIDTH_8_MHZ:
- tda1004x_write_byte(fe, 0x0C, 0xFF);
+ tda1004x_writereg(fe, 0x0C, 0xFF);
filter = 1;
break;
@@ -1564,13 +1564,13 @@ static void frontend_init(struct ttusb* ttusb)
switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) {
case 0x1003: // Hauppauge/TT Nova-USB-S budget (stv0299/ALPS BSRU6|BSBE1(tsa5059))
// try the stv0299 based first
- ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap);
+ ttusb->fe = dvb_attach(stv0299_attach, &alps_stv0299_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params;
if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1
alps_stv0299_config.inittab = alps_bsbe1_inittab;
- lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0);
+ dvb_attach(lnbp21_attach, ttusb->fe, &ttusb->i2c_adap, 0, 0);
} else { // ALPS BSRU6
ttusb->fe->ops.set_voltage = ttusb_set_voltage;
}
@@ -1578,7 +1578,7 @@ static void frontend_init(struct ttusb* ttusb)
}
// Grundig 29504-491
- ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
+ ttusb->fe = dvb_attach(tda8083_attach, &ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params;
ttusb->fe->ops.set_voltage = ttusb_set_voltage;
@@ -1587,13 +1587,13 @@ static void frontend_init(struct ttusb* ttusb)
break;
case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
- ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
+ ttusb->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
if (ttusb->fe != NULL) {
ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
break;
}
- ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
+ ttusb->fe = dvb_attach(stv0297_attach, &dvbc_philips_tdm1316l_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params;
break;
@@ -1602,14 +1602,14 @@ static void frontend_init(struct ttusb* ttusb)
case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
// try the ALPS TDMB7 first
- ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
+ ttusb->fe = dvb_attach(cx22700_attach, &alps_tdmb7_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params;
break;
}
// Philips td1316
- ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
+ ttusb->fe = dvb_attach(tda10046_attach, &philips_tdm1316l_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) {
ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init;
ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params;
@@ -1625,8 +1625,7 @@ static void frontend_init(struct ttusb* ttusb)
} else {
if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
printk("dvb-ttusb-budget: Frontend registration failed!\n");
- if (ttusb->fe->ops.release)
- ttusb->fe->ops.release(ttusb->fe);
+ dvb_frontend_detach(ttusb->fe);
ttusb->fe = NULL;
}
}
@@ -1763,7 +1762,10 @@ static void ttusb_disconnect(struct usb_interface *intf)
dvb_net_release(&ttusb->dvbnet);
dvb_dmxdev_release(&ttusb->dmxdev);
dvb_dmx_release(&ttusb->dvb_demux);
- if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe);
+ if (ttusb->fe != NULL) {
+ dvb_unregister_frontend(ttusb->fe);
+ dvb_frontend_detach(ttusb->fe);
+ }
i2c_del_adapter(&ttusb->i2c_adap);
dvb_unregister_adapter(&ttusb->adapter);
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 6c1cb770bcf5..a1c9fa9919ea 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -203,7 +203,7 @@ static u16 rc_keys[] = {
static void ttusb_dec_set_model(struct ttusb_dec *dec,
enum ttusb_dec_model model);
-static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
+static void ttusb_dec_handle_irq( struct urb *urb)
{
struct ttusb_dec * dec = urb->context;
char *buffer = dec->irq_buffer;
@@ -215,7 +215,7 @@ static void ttusb_dec_handle_irq( struct urb *urb, struct pt_regs *regs)
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is dead, cleanup */
dprintk("%s:urb shutting down with status: %d\n",
__FUNCTION__, urb->status);
@@ -755,7 +755,7 @@ static void ttusb_dec_process_urb_frame_list(unsigned long data)
}
}
-static void ttusb_dec_process_urb(struct urb *urb, struct pt_regs *ptregs)
+static void ttusb_dec_process_urb(struct urb *urb)
{
struct ttusb_dec *dec = urb->context;
@@ -1512,7 +1512,11 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
dvb_dmxdev_release(&dec->dmxdev);
dvb_dmx_release(&dec->demux);
- if (dec->fe) dvb_unregister_frontend(dec->fe);
+ if (dec->fe) {
+ dvb_unregister_frontend(dec->fe);
+ if (dec->fe->ops.release)
+ dec->fe->ops.release(dec->fe);
+ }
dvb_unregister_adapter(&dec->adapter);
}
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 220076b1b956..6d96b17a7f81 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -7,7 +7,7 @@ menu "Radio Adapters"
config RADIO_CADET
tristate "ADS Cadet AM/FM Tuner"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these AM/FM radio cards, and then
fill in the port address below.
@@ -25,7 +25,7 @@ config RADIO_CADET
config RADIO_RTRACK
tristate "AIMSlab RadioTrack (aka RadioReveal) support"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
@@ -59,7 +59,7 @@ config RADIO_RTRACK_PORT
config RADIO_RTRACK2
tristate "AIMSlab RadioTrack II support"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have this FM radio card, and then fill in the
port address below.
@@ -82,7 +82,7 @@ config RADIO_RTRACK2_PORT
config RADIO_AZTECH
tristate "Aztech/Packard Bell Radio"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
@@ -106,7 +106,7 @@ config RADIO_AZTECH_PORT
config RADIO_GEMTEK
tristate "GemTek Radio Card support"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have this FM radio card, and then fill in the
port address below.
@@ -131,7 +131,7 @@ config RADIO_GEMTEK_PORT
config RADIO_GEMTEK_PCI
tristate "GemTek PCI Radio Card support"
- depends on VIDEO_V4L1 && PCI
+ depends on VIDEO_V4L2 && PCI
---help---
Choose Y here if you have this PCI FM radio card.
@@ -145,7 +145,7 @@ config RADIO_GEMTEK_PCI
config RADIO_MAXIRADIO
tristate "Guillemot MAXI Radio FM 2000 radio"
- depends on VIDEO_V4L1 && PCI
+ depends on VIDEO_V4L2 && PCI
---help---
Choose Y here if you have this radio card. This card may also be
found as Gemtek PCI FM.
@@ -160,7 +160,7 @@ config RADIO_MAXIRADIO
config RADIO_MAESTRO
tristate "Maestro on board radio"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2 && PCI
---help---
Say Y here to directly support the on-board radio tuner on the
Maestro 2 or 2E sound card.
@@ -195,8 +195,7 @@ config RADIO_MIROPCM20_RDS
---help---
Choose Y here if you want to see RDS/RBDS information like
RadioText, Programme Service name, Clock Time and date, Programme
- TYpe and Traffic Announcement/Programme identification. You also
- need to say Y to "miroSOUND PCM20 radio" and devfs!
+ Type and Traffic Announcement/Programme identification.
It's not possible to read the raw RDS packets from the device, so
the driver cant provide an V4L interface for this. But the
@@ -208,7 +207,7 @@ config RADIO_MIROPCM20_RDS
config RADIO_SF16FMI
tristate "SF16FMI Radio"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these FM radio cards. If you
compile the driver into the kernel and your card is not PnP one, you
@@ -225,7 +224,7 @@ config RADIO_SF16FMI
config RADIO_SF16FMR2
tristate "SF16FMR2 Radio"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these FM radio cards.
@@ -239,7 +238,7 @@ config RADIO_SF16FMR2
config RADIO_TERRATEC
tristate "TerraTec ActiveRadio ISA Standalone"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have this FM radio card, and then fill in the
port address below. (TODO)
@@ -268,7 +267,7 @@ config RADIO_TERRATEC_PORT
config RADIO_TRUST
tristate "Trust FM radio card"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
help
This is a driver for the Trust FM radio cards. Say Y if you have
such a card and want to use it under Linux.
@@ -286,7 +285,7 @@ config RADIO_TRUST_PORT
config RADIO_TYPHOON
tristate "Typhoon Radio (a.k.a. EcoRadio)"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address and the frequency used for muting below.
@@ -330,7 +329,7 @@ config RADIO_TYPHOON_MUTEFREQ
config RADIO_ZOLTRIX
tristate "Zoltrix Radio"
- depends on ISA && VIDEO_V4L1
+ depends on ISA && VIDEO_V4L2
---help---
Choose Y here if you have one of these FM radio cards, and then fill
in the port address below.
@@ -352,7 +351,7 @@ config RADIO_ZOLTRIX_PORT
config USB_DSBR
tristate "D-Link USB FM radio support (EXPERIMENTAL)"
- depends on USB && VIDEO_V4L1 && EXPERIMENTAL
+ depends on USB && VIDEO_V4L2 && EXPERIMENTAL
---help---
Say Y here if you want to connect this type of radio to your
computer's USB port. Note that the audio is not digital, and
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index f7e33f9ee8e9..db865a0667e5 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -33,8 +33,14 @@
History:
+ Version 0.41-ac1:
+ Alan Cox: Some cleanups and fixes
+
+ Version 0.41:
+ Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+
Version 0.40:
- Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
+ Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
Version 0.30:
Markus: Updates for 2.5.x kernel and more ISO compliant source
@@ -65,13 +71,12 @@
*/
-
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/input.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
@@ -79,7 +84,22 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.40"
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+
+#define DRIVER_VERSION "v0.41"
+#define RADIO_VERSION KERNEL_VERSION(0,4,1)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }
+};
+
#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
@@ -111,7 +131,7 @@ static int radio_nr = -1;
module_param(radio_nr, int, 0);
/* Data for one (physical) device */
-typedef struct {
+struct dsbr100_device {
struct usb_device *usbdev;
struct video_device *videodev;
unsigned char transfer_buffer[TB_LEN];
@@ -119,7 +139,8 @@ typedef struct {
int stereo;
int users;
int removed;
-} dsbr100_device;
+ int muted;
+};
/* File system interface */
@@ -138,7 +159,6 @@ static struct video_device dsbr100_videodev_template=
.owner = THIS_MODULE,
.name = "D-Link DSB-R 100",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_AZTECH,
.fops = &usb_dsbr100_fops,
.release = video_device_release,
};
@@ -161,7 +181,7 @@ static struct usb_driver usb_dsbr100_driver = {
/* Low-level device interface begins here */
/* switch on radio */
-static int dsbr100_start(dsbr100_device *radio)
+static int dsbr100_start(struct dsbr100_device *radio)
{
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
@@ -172,12 +192,13 @@ static int dsbr100_start(dsbr100_device *radio)
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
return -1;
+ radio->muted=0;
return (radio->transfer_buffer)[0];
}
/* switch off radio */
-static int dsbr100_stop(dsbr100_device *radio)
+static int dsbr100_stop(struct dsbr100_device *radio)
{
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
@@ -188,11 +209,12 @@ static int dsbr100_stop(dsbr100_device *radio)
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
return -1;
+ radio->muted=1;
return (radio->transfer_buffer)[0];
}
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
-static int dsbr100_setfreq(dsbr100_device *radio, int freq)
+static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
{
freq = (freq/16*80)/1000+856;
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
@@ -217,7 +239,7 @@ static int dsbr100_setfreq(dsbr100_device *radio, int freq)
/* return the device status. This is, in effect, just whether it
sees a stereo signal or not. Pity. */
-static void dsbr100_getstat(dsbr100_device *radio)
+static void dsbr100_getstat(struct dsbr100_device *radio)
{
if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
USB_REQ_GET_STATUS,
@@ -236,9 +258,9 @@ usb if it is */
static int usb_dsbr100_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- dsbr100_device *radio;
+ struct dsbr100_device *radio;
- if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
+ if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
return -ENOMEM;
if (!(radio->videodev = video_device_alloc())) {
kfree(radio);
@@ -271,7 +293,7 @@ code I'd expect I better did that, but if there's a memory
leak here it's tiny (~50 bytes per disconnect) */
static void usb_dsbr100_disconnect(struct usb_interface *intf)
{
- dsbr100_device *radio = usb_get_intfdata(intf);
+ struct dsbr100_device *radio = usb_get_intfdata(intf);
usb_set_intfdata (intf, NULL);
if (radio) {
@@ -291,89 +313,121 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf)
static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
- dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+ struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
if (!radio)
return -EIO;
switch(cmd) {
- case VIDIOCGCAP: {
- struct video_capability *v = arg;
-
- memset(v, 0, sizeof(*v));
- v->type = VID_TYPE_TUNER;
- v->channels = 1;
- v->audios = 1;
- strcpy(v->name, "D-Link R-100 USB FM Radio");
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+ strlcpy(v->driver, "dsbr100", sizeof (v->driver));
+ strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER: {
- struct video_tuner *v = arg;
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *v = arg;
- dsbr100_getstat(radio);
- if(v->tuner) /* Only 1 tuner */
+ if (v->index > 0)
return -EINVAL;
+
+ dsbr100_getstat(radio);
+
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
v->rangelow = FREQ_MIN*FREQ_MUL;
v->rangehigh = FREQ_MAX*FREQ_MUL;
- v->flags = VIDEO_TUNER_LOW;
- v->mode = VIDEO_MODE_AUTO;
- v->signal = radio->stereo*0x7000;
- /* Don't know how to get signal strength */
- v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
- strcpy(v->name, "DSB R-100");
- return 0;
- }
- case VIDIOCSTUNER: {
- struct video_tuner *v = arg;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(radio->stereo)
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal = 0xFFFF; /* We can't get the signal strength */
- if(v->tuner!=0)
- return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
return 0;
}
- case VIDIOCGFREQ: {
- int *freq = arg;
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *v = arg;
- if (radio->curfreq==-1)
+ if (v->index > 0)
return -EINVAL;
- *freq = radio->curfreq;
+
return 0;
}
- case VIDIOCSFREQ: {
- int *freq = arg;
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
- radio->curfreq = *freq;
+ radio->curfreq = f->frequency;
if (dsbr100_setfreq(radio, radio->curfreq)==-1)
warn("Set frequency failed");
return 0;
}
- case VIDIOCGAUDIO: {
- struct video_audio *v = arg;
-
- memset(v, 0, sizeof(*v));
- v->flags |= VIDEO_AUDIO_MUTABLE;
- v->mode = VIDEO_SOUND_STEREO;
- v->volume = 1;
- v->step = 1;
- strcpy(v->name, "Radio");
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = radio->curfreq;
+
return 0;
}
- case VIDIOCSAUDIO: {
- struct video_audio *v = arg;
-
- if (v->audio)
- return -EINVAL;
- if (v->flags&VIDEO_AUDIO_MUTE) {
- if (dsbr100_stop(radio)==-1)
- warn("Radio did not respond properly");
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return 0;
+ }
}
- else
- if (dsbr100_start(radio)==-1)
- warn("Radio did not respond properly");
- return 0;
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=radio->muted;
+ return 0;
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ if (dsbr100_stop(radio)==-1)
+ warn("Radio did not respond properly");
+ } else {
+ if (dsbr100_start(radio)==-1)
+ warn("Radio did not respond properly");
+ }
+ return 0;
+ }
+ return -EINVAL;
}
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ usb_dsbr100_do_ioctl);
}
}
@@ -385,9 +439,11 @@ static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
static int usb_dsbr100_open(struct inode *inode, struct file *file)
{
- dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+ struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
radio->users = 1;
+ radio->muted = 1;
+
if (dsbr100_start(radio)<0) {
warn("Radio did not start up properly");
radio->users = 0;
@@ -399,7 +455,7 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file)
static int usb_dsbr100_close(struct inode *inode, struct file *file)
{
- dsbr100_device *radio=video_get_drvdata(video_devdata(file));
+ struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
if (!radio)
return -ENODEV;
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index df22a582e7a2..3368a89bfadb 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -1,5 +1,6 @@
/* radiotrack (radioreveal) driver for Linux radio support
* (c) 1997 M. Kirkwood
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
* Converted to new API by Alan Cox <Alan.Cox@linux.org>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
@@ -33,11 +34,13 @@
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_RTRACK_PORT */
#include <asm/semaphore.h> /* Lock for the I/O */
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
#ifndef CONFIG_RADIO_RTRACK_PORT
#define CONFIG_RADIO_RTRACK_PORT -1
#endif
@@ -209,6 +212,25 @@ static int rt_getsigstr(struct rt_device *dev)
return 1; /* signal present */
}
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
static int rt_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{
@@ -217,73 +239,114 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
- strcpy(v->name, "RadioTrack");
+ strlcpy(v->driver, "radio-aimslab", sizeof (v->driver));
+ strlcpy(v->card, "RadioTrack", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
+
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
- v->flags=VIDEO_TUNER_LOW;
- v->mode=VIDEO_MODE_AUTO;
- strcpy(v->name, "FM");
+ v->rxsubchans =V4L2_TUNER_SUB_MONO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
v->signal=0xFFFF*rt_getsigstr(rt);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner!=0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
+
return 0;
}
- case VIDIOCGFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- *freq = rt->curfreq;
+ struct v4l2_frequency *f = arg;
+
+ rt->curfreq = f->frequency;
+ rt_setfreq(rt, rt->curfreq);
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_G_FREQUENCY:
{
- unsigned long *freq = arg;
- rt->curfreq = *freq;
- rt_setfreq(rt, rt->curfreq);
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = rt->curfreq;
+
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *v = arg;
- memset(v,0, sizeof(*v));
- v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
- v->volume=rt->curvol * 6554;
- v->step=6554;
- strcpy(v->name, "Radio");
- return 0;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_G_CTRL:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
- rt_mute(rt);
- else
- rt_setvol(rt,v->volume/6554);
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=rt->muted;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=rt->curvol * 6554;
+ return (0);
+ }
+ return -EINVAL;
}
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ rt_mute(rt);
+ } else {
+ rt_setvol(rt,rt->curvol);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ rt_setvol(rt,ctrl->value);
+ return (0);
+ }
+ return -EINVAL;
+ }
+
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ rt_do_ioctl);
}
}
@@ -309,7 +372,7 @@ static struct video_device rtrack_radio=
.owner = THIS_MODULE,
.name = "RadioTrack radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_RTRACK,
+ .hardware = 0,
.fops = &rtrack_fops,
};
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 95e6322133ee..3ba5fa8cf7e6 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -1,5 +1,6 @@
/* radio-aztech.c - Aztech radio card driver for Linux 2.2
*
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
* Adapted to support the Video for Linux API by
* Russell Kroll <rkroll@exploits.org>. Based on original tuner code by:
*
@@ -30,9 +31,30 @@
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_AZTECH_PORT */
+
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -166,81 +188,121 @@ static int az_do_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
- strcpy(v->name, "Aztech Radio");
+ strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
+ strlcpy(v->card, "Aztech Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
+
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
- v->flags=VIDEO_TUNER_LOW;
- v->mode=VIDEO_MODE_AUTO;
- v->signal=0xFFFF*az_getsigstr(az);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
if(az_getstereo(az))
- v->flags|=VIDEO_TUNER_STEREO_ON;
- strcpy(v->name, "FM");
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*az_getsigstr(az);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner!=0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
+
return 0;
}
- case VIDIOCGFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- *freq = az->curfreq;
+ struct v4l2_frequency *f = arg;
+
+ az->curfreq = f->frequency;
+ az_setfreq(az, az->curfreq);
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_G_FREQUENCY:
{
- unsigned long *freq = arg;
- az->curfreq = *freq;
- az_setfreq(az, az->curfreq);
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = az->curfreq;
+
return 0;
}
- case VIDIOCGAUDIO:
+
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *v = arg;
- memset(v,0, sizeof(*v));
- v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
- if(az->stereo)
- v->mode=VIDEO_SOUND_STEREO;
- else
- v->mode=VIDEO_SOUND_MONO;
- v->volume=az->curvol;
- v->step=16384;
- strcpy(v->name, "Radio");
- return 0;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_G_CTRL:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
- az->curvol=v->volume;
-
- az->stereo=(v->mode&VIDEO_SOUND_STEREO)?1:0;
- if(v->flags&VIDEO_AUDIO_MUTE)
- az_setvol(az,0);
- else
- az_setvol(az,az->curvol);
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (az->curvol==0)
+ ctrl->value=1;
+ else
+ ctrl->value=0;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=az->curvol * 6554;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ az_setvol(az,0);
+ } else {
+ az_setvol(az,az->curvol);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ az_setvol(az,ctrl->value);
+ return (0);
+ }
+ return -EINVAL;
}
+
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ az_do_ioctl);
}
}
@@ -266,7 +328,7 @@ static struct video_device aztech_radio=
.owner = THIS_MODULE,
.name = "Aztech radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_AZTECH,
+ .hardware = 0,
.fops = &aztech_fops,
};
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8641aec7baf8..69d4b7919c5a 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -25,20 +25,28 @@
*
* 2003-01-31 Alan Cox <alan@redhat.com>
* Cleaned up locking, delay code, general odds and ends
+ *
+ * 2006-07-30 Hans J. Koch <koch@hjk-az.de>
+ * Changed API to V4L2
*/
+#include <linux/version.h>
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* V4L2 API defs */
#include <media/v4l2-common.h>
#include <linux/param.h>
#include <linux/pnp.h>
#define RDS_BUFFER 256
+#define RDS_RX_FLAG 1
+#define MBS_RX_FLAG 2
+
+#define CADET_VERSION KERNEL_VERSION(0,3,3)
static int io=-1; /* default to isapnp activation */
static int radio_nr = -1;
@@ -61,44 +69,24 @@ static int cadet_probe(void);
*/
static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
-static int cadet_getrds(void)
-{
- int rdsstat=0;
-
- spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
- outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */
- spin_unlock(&cadet_io_lock);
-
- msleep(100);
-
- spin_lock(&cadet_io_lock);
- outb(3,io); /* Select Decoder Control/Status */
- if((inb(io+1)&0x80)!=0) {
- rdsstat|=VIDEO_TUNER_RDS_ON;
- }
- if((inb(io+1)&0x10)!=0) {
- rdsstat|=VIDEO_TUNER_MBS_ON;
- }
- spin_unlock(&cadet_io_lock);
- return rdsstat;
-}
-static int cadet_getstereo(void)
+static int
+cadet_getstereo(void)
{
- int ret = 0;
+ int ret = V4L2_TUNER_SUB_MONO;
if(curtuner != 0) /* Only FM has stereo capability! */
- return 0;
+ return V4L2_TUNER_SUB_MONO;
spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
if( (inb(io+1) & 0x40) == 0)
- ret = 1;
+ ret = V4L2_TUNER_SUB_STEREO;
spin_unlock(&cadet_io_lock);
return ret;
}
-static unsigned cadet_gettune(void)
+static unsigned
+cadet_gettune(void)
{
int curvol,i;
unsigned fifo=0;
@@ -135,7 +123,8 @@ static unsigned cadet_gettune(void)
return fifo;
}
-static unsigned cadet_getfreq(void)
+static unsigned
+cadet_getfreq(void)
{
int i;
unsigned freq=0,test,fifo=0;
@@ -167,7 +156,8 @@ static unsigned cadet_getfreq(void)
return freq;
}
-static void cadet_settune(unsigned fifo)
+static void
+cadet_settune(unsigned fifo)
{
int i;
unsigned test;
@@ -195,7 +185,8 @@ static void cadet_settune(unsigned fifo)
spin_unlock(&cadet_io_lock);
}
-static void cadet_setfreq(unsigned freq)
+static void
+cadet_setfreq(unsigned freq)
{
unsigned fifo;
int i,j,test;
@@ -255,7 +246,8 @@ static void cadet_setfreq(unsigned freq)
}
-static int cadet_getvol(void)
+static int
+cadet_getvol(void)
{
int ret = 0;
@@ -270,7 +262,8 @@ static int cadet_getvol(void)
}
-static void cadet_setvol(int vol)
+static void
+cadet_setvol(int vol)
{
spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
@@ -281,7 +274,8 @@ static void cadet_setvol(int vol)
spin_unlock(&cadet_io_lock);
}
-static void cadet_handler(unsigned long data)
+static void
+cadet_handler(unsigned long data)
{
/*
* Service the RDS fifo
@@ -322,8 +316,8 @@ static void cadet_handler(unsigned long data)
-static ssize_t cadet_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
+static ssize_t
+cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
int i=0;
unsigned char readbuf[RDS_BUFFER];
@@ -359,128 +353,156 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
{
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
- memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- v->channels=2;
- v->audios=1;
- strcpy(v->name, "ADS Cadet");
+ struct v4l2_capability *cap = arg;
+ memset(cap,0,sizeof(*cap));
+ cap->capabilities =
+ V4L2_CAP_TUNER |
+ V4L2_CAP_READWRITE;
+ cap->version = CADET_VERSION;
+ strcpy(cap->driver, "ADS Cadet");
+ strcpy(cap->card, "ADS Cadet");
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if((v->tuner<0)||(v->tuner>1)) {
- return -EINVAL;
- }
- switch(v->tuner) {
- case 0:
- strcpy(v->name,"FM");
- v->rangelow=1400; /* 87.5 MHz */
- v->rangehigh=1728; /* 108.0 MHz */
- v->flags=0;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- if(cadet_getstereo()==1) {
- v->flags|=VIDEO_TUNER_STEREO_ON;
- }
- v->flags|=cadet_getrds();
- break;
- case 1:
- strcpy(v->name,"AM");
- v->rangelow=8320; /* 520 kHz */
- v->rangehigh=26400; /* 1650 kHz */
- v->flags=0;
- v->flags|=VIDEO_TUNER_LOW;
- v->mode=0;
- v->mode|=VIDEO_MODE_AUTO;
- v->signal=sigstrength;
- break;
+ struct v4l2_tuner *t = arg;
+ memset(t,0,sizeof(*t));
+ t->type = V4L2_TUNER_RADIO;
+ switch (t->index)
+ {
+ case 0: strcpy(t->name, "FM");
+ t->capability = V4L2_TUNER_CAP_STEREO;
+ t->rangelow = 1400; /* 87.5 MHz */
+ t->rangehigh = 1728; /* 108.0 MHz */
+ t->rxsubchans=cadet_getstereo();
+ switch (t->rxsubchans){
+ case V4L2_TUNER_SUB_MONO:
+ t->audmode = V4L2_TUNER_MODE_MONO;
+ break;
+ case V4L2_TUNER_SUB_STEREO:
+ t->audmode = V4L2_TUNER_MODE_STEREO;
+ break;
+ default: ;
+ }
+ break;
+ case 1: strcpy(t->name, "AM");
+ t->capability = V4L2_TUNER_CAP_LOW;
+ t->rangelow = 8320; /* 520 kHz */
+ t->rangehigh = 26400; /* 1650 kHz */
+ t->rxsubchans = V4L2_TUNER_SUB_MONO;
+ t->audmode = V4L2_TUNER_MODE_MONO;
+ break;
+ default:
+ return -EINVAL;
}
+
+ t->signal = sigstrength; /* We might need to modify scaling of this */
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if((v->tuner<0)||(v->tuner>1)) {
+ struct v4l2_tuner *t = arg;
+ if((t->index != 0)&&(t->index != 1))
return -EINVAL;
- }
- curtuner=v->tuner;
+
+ curtuner = t->index;
return 0;
}
- case VIDIOCGFREQ:
+ case VIDIOC_G_FREQUENCY:
{
- unsigned long *freq = arg;
- *freq = cadet_getfreq();
+ struct v4l2_frequency *f = arg;
+ memset(f,0,sizeof(*f));
+ f->tuner = curtuner;
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = cadet_getfreq();
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- if((curtuner==0)&&((*freq<1400)||(*freq>1728))) {
+ struct v4l2_frequency *f = arg;
+ if (f->type != V4L2_TUNER_RADIO){
+ return -EINVAL;
+ }
+ if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728))) {
return -EINVAL;
}
- if((curtuner==1)&&((*freq<8320)||(*freq>26400))) {
+ if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400))) {
return -EINVAL;
}
- cadet_setfreq(*freq);
+ cadet_setfreq(f->frequency);
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOC_G_CTRL:
{
- struct video_audio *v = arg;
- memset(v,0, sizeof(*v));
- v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
- if(cadet_getstereo()==0) {
- v->mode=VIDEO_SOUND_MONO;
- } else {
- v->mode=VIDEO_SOUND_STEREO;
+ struct v4l2_control *c = arg;
+ switch (c->id){
+ case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
+ c->value = (cadet_getvol() == 0);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ c->value = cadet_getvol();
+ break;
+ default:
+ return -EINVAL;
}
- v->volume=cadet_getvol();
- v->step=0xffff;
- strcpy(v->name, "Radio");
return 0;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_S_CTRL:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
- cadet_setvol(v->volume);
- if(v->flags&VIDEO_AUDIO_MUTE)
- cadet_setvol(0);
- else
- cadet_setvol(0xffff);
+ struct v4l2_control *c = arg;
+ switch (c->id){
+ case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
+ if (c->value) cadet_setvol(0);
+ else cadet_setvol(0xffff);
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ cadet_setvol(c->value);
+ break;
+ default:
+ return -EINVAL;
+ }
return 0;
}
+
default:
return -ENOIOCTLCMD;
}
}
-static int cadet_ioctl(struct inode *inode, struct file *file,
+static int
+cadet_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return video_usercopy(inode, file, cmd, arg, cadet_do_ioctl);
}
-static int cadet_open(struct inode *inode, struct file *file)
+static int
+cadet_open(struct inode *inode, struct file *file)
{
- if(users)
- return -EBUSY;
users++;
- init_waitqueue_head(&read_queue);
+ if (1 == users) init_waitqueue_head(&read_queue);
return 0;
}
-static int cadet_release(struct inode *inode, struct file *file)
+static int
+cadet_release(struct inode *inode, struct file *file)
{
- del_timer_sync(&readtimer);
- rdsstat=0;
users--;
+ if (0 == users){
+ del_timer_sync(&readtimer);
+ rdsstat=0;
+ }
+ return 0;
+}
+
+static unsigned int
+cadet_poll(struct file *file, struct poll_table_struct *wait)
+{
+ poll_wait(file,&read_queue,wait);
+ if(rdsin != rdsout)
+ return POLLIN | POLLRDNORM;
return 0;
}
@@ -491,6 +513,7 @@ static struct file_operations cadet_fops = {
.release = cadet_release,
.read = cadet_read,
.ioctl = cadet_ioctl,
+ .poll = cadet_poll,
.compat_ioctl = v4l_compat_ioctl32,
.llseek = no_llseek,
};
@@ -500,7 +523,6 @@ static struct video_device cadet_radio=
.owner = THIS_MODULE,
.name = "Cadet radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_CADET,
.fops = &cadet_fops,
};
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 4c82956390c1..eb14106f66fa 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -34,6 +34,8 @@
*
* TODO: multiple device support and portability were not tested
*
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
***************************************************************************
*/
@@ -42,10 +44,32 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/pci.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/errno.h>
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -183,91 +207,117 @@ static int gemtek_pci_do_ioctl(struct inode *inode, struct file *file,
struct gemtek_pci_card *card = dev->priv;
switch ( cmd ) {
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *c = arg;
+ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+ strlcpy(v->driver, "radio-gemtek-pci", sizeof (v->driver));
+ strlcpy(v->card, "GemTek PCI Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
- memset(c,0,sizeof(*c));
- c->type = VID_TYPE_TUNER;
- c->channels = 1;
- c->audios = 1;
- strcpy( c->name, "Gemtek PCI Radio" );
return 0;
}
-
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *t = arg;
+ struct v4l2_tuner *v = arg;
- if ( t->tuner )
+ if (v->index > 0)
return -EINVAL;
- t->rangelow = GEMTEK_PCI_RANGE_LOW;
- t->rangehigh = GEMTEK_PCI_RANGE_HIGH;
- t->flags = VIDEO_TUNER_LOW;
- t->mode = VIDEO_MODE_AUTO;
- t->signal = 0xFFFF * gemtek_pci_getsignal( card );
- strcpy( t->name, "FM" );
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
+ v->rangelow = GEMTEK_PCI_RANGE_LOW;
+ v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*gemtek_pci_getsignal( card );
+
return 0;
}
-
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *t = arg;
- if ( t->tuner )
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- return 0;
- }
- case VIDIOCGFREQ:
- {
- unsigned long *freq = arg;
- *freq = card->current_frequency;
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
+ struct v4l2_frequency *f = arg;
- if ( (*freq < GEMTEK_PCI_RANGE_LOW) ||
- (*freq > GEMTEK_PCI_RANGE_HIGH) )
+ if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) ||
+ (f->frequency > GEMTEK_PCI_RANGE_HIGH) )
return -EINVAL;
- gemtek_pci_setfrequency( card, *freq );
- card->current_frequency = *freq;
- card->mute = FALSE;
+ gemtek_pci_setfrequency( card, f->frequency );
+ card->current_frequency = f->frequency;
+ card->mute = FALSE;
return 0;
}
-
- case VIDIOCGAUDIO:
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *a = arg;
-
- memset( a, 0, sizeof( *a ) );
- a->flags |= VIDEO_AUDIO_MUTABLE;
- a->volume = 1;
- a->step = 65535;
- strcpy( a->name, "Radio" );
- return 0;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
}
-
- case VIDIOCSAUDIO:
+ case VIDIOC_G_CTRL:
{
- struct video_audio *a = arg;
-
- if ( a->audio )
- return -EINVAL;
-
- if ( a->flags & VIDEO_AUDIO_MUTE )
- gemtek_pci_mute( card );
- else
- gemtek_pci_unmute( card );
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=card->mute;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ if (card->mute)
+ ctrl->value=0;
+ else
+ ctrl->value=65535;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ gemtek_pci_mute(card);
+ } else {
+ gemtek_pci_unmute(card);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ if (ctrl->value) {
+ gemtek_pci_unmute(card);
+ } else {
+ gemtek_pci_mute(card);
+ }
+ return (0);
+ }
+ return -EINVAL;
}
-
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ gemtek_pci_do_ioctl);
}
}
@@ -309,7 +359,7 @@ static struct video_device vdev_template = {
.owner = THIS_MODULE,
.name = "Gemtek PCI Radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_GEMTEK,
+ .hardware = 0,
.fops = &gemtek_pci_fops,
};
@@ -399,7 +449,7 @@ static int __init gemtek_pci_init_module( void )
static void __exit gemtek_pci_cleanup_module( void )
{
- return pci_unregister_driver( &gemtek_pci_driver );
+ pci_unregister_driver(&gemtek_pci_driver);
}
MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" );
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 162f37d8bf96..730fe16126cb 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -13,6 +13,7 @@
*
* TODO: Allow for more than one of these foolish entities :-)
*
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h> /* Modules */
@@ -21,11 +22,32 @@
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
#include <linux/spinlock.h>
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
#ifndef CONFIG_RADIO_GEMTEK_PORT
#define CONFIG_RADIO_GEMTEK_PORT -1
#endif
@@ -147,77 +169,122 @@ static int gemtek_do_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
- strcpy(v->name, "GemTek");
+ strlcpy(v->driver, "radio-gemtek", sizeof (v->driver));
+ strlcpy(v->card, "GemTek", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- v->rangelow=87*16000;
- v->rangehigh=108*16000;
- v->flags=VIDEO_TUNER_LOW;
- v->mode=VIDEO_MODE_AUTO;
- v->signal=0xFFFF*gemtek_getsigstr(rt);
+
+ memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
+ v->rangelow=(87*16000);
+ v->rangehigh=(108*16000);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*gemtek_getsigstr(rt);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner!=0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
- return 0;
- }
- case VIDIOCGFREQ:
- {
- unsigned long *freq = arg;
- *freq = rt->curfreq;
+
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- rt->curfreq = *freq;
+ struct v4l2_frequency *f = arg;
+
+ rt->curfreq = f->frequency;
/* needs to be called twice in order for getsigstr to work */
gemtek_setfreq(rt, rt->curfreq);
gemtek_setfreq(rt, rt->curfreq);
return 0;
}
- case VIDIOCGAUDIO:
- {
- struct video_audio *v = arg;
- memset(v,0, sizeof(*v));
- v->flags|=VIDEO_AUDIO_MUTABLE;
- v->volume=1;
- v->step=65535;
- strcpy(v->name, "Radio");
- return 0;
- }
- case VIDIOCSAUDIO:
+ case VIDIOC_G_FREQUENCY:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
+ struct v4l2_frequency *f = arg;
- if(v->flags&VIDEO_AUDIO_MUTE)
- gemtek_mute(rt);
- else
- gemtek_unmute(rt);
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = rt->curfreq;
return 0;
}
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=rt->muted;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ if (rt->muted)
+ ctrl->value=0;
+ else
+ ctrl->value=65535;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ gemtek_mute(rt);
+ } else {
+ gemtek_unmute(rt);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ if (ctrl->value) {
+ gemtek_unmute(rt);
+ } else {
+ gemtek_mute(rt);
+ }
+ return (0);
+ }
+ return -EINVAL;
+ }
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ gemtek_do_ioctl);
}
}
@@ -243,7 +310,7 @@ static struct video_device gemtek_radio=
.owner = THIS_MODULE,
.name = "GemTek radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_GEMTEK,
+ .hardware = 0,
.fops = &gemtek_fops,
};
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index fcfa6c9fe225..e8ce5f75cf12 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -14,6 +14,8 @@
* version 0.04
* + code improvements
* + VIDEO_TUNER_LOW is permanent
+ *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h>
@@ -25,10 +27,23 @@
#include <asm/uaccess.h>
#include <linux/mutex.h>
#include <linux/pci.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-#define DRIVER_VERSION "0.05"
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,6)
+#define DRIVER_VERSION "0.06"
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }
+};
#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */
@@ -96,7 +111,7 @@ static struct file_operations maestro_fops = {
static struct video_device maestro_radio = {
.name = "Maestro radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_SF16MI,
+ .hardware = 0,
.fops = &maestro_fops,
};
@@ -130,7 +145,7 @@ static u32 radio_bits_get(struct radio_device *dev)
rdata = inw(io);
if(!l)
dev->stereo = rdata & STR_MOST ?
- 0 : VIDEO_TUNER_STEREO_ON;
+ 0 : 1;
else
if(rdata & STR_DATA)
data++;
@@ -183,72 +198,120 @@ static inline int radio_function(struct inode *inode, struct file *file,
struct radio_device *card = video_get_drvdata(dev);
switch (cmd) {
- case VIDIOCGCAP: {
- struct video_capability *v = arg;
- memset(v, 0, sizeof(*v));
- strcpy(v->name, "Maestro radio");
- v->type = VID_TYPE_TUNER;
- v->channels = v->audios = 1;
- return 0;
- } case VIDIOCGTUNER: {
- struct video_tuner *v = arg;
- if (v->tuner)
- return -EINVAL;
- (void)radio_bits_get(card);
- v->flags = VIDEO_TUNER_LOW | card->stereo;
- v->signal = card->tuned;
- strcpy(v->name, "FM");
- v->rangelow = FREQ_LO;
- v->rangehigh = FREQ_HI;
- v->mode = VIDEO_MODE_AUTO;
- return 0;
- } case VIDIOCSTUNER: {
- struct video_tuner *v = arg;
- if (v->tuner != 0)
- return -EINVAL;
- return 0;
- } case VIDIOCGFREQ: {
- unsigned long *freq = arg;
- *freq = BITS2FREQ(radio_bits_get(card));
- return 0;
- } case VIDIOCSFREQ: {
- unsigned long *freq = arg;
- if (*freq < FREQ_LO || *freq > FREQ_HI)
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *v = arg;
+ memset(v,0,sizeof(*v));
+ strlcpy(v->driver, "radio-maestro", sizeof (v->driver));
+ strlcpy(v->card, "Maestro Radio", sizeof (v->card));
+ sprintf(v->bus_info,"PCI");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
+ return 0;
+ }
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ (void)radio_bits_get(card);
+
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
+ v->rangelow = FREQ_LO;
+ v->rangehigh = FREQ_HI;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(card->stereo)
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=card->tuned;
+
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
+ return -EINVAL;
+
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
+ return -EINVAL;
+ radio_bits_set(card, FREQ2BITS(f->frequency));
+
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = BITS2FREQ(radio_bits_get(card));
+
+ return 0;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
return -EINVAL;
- radio_bits_set(card, FREQ2BITS(*freq));
- return 0;
- } case VIDIOCGAUDIO: {
- struct video_audio *v = arg;
- memset(v, 0, sizeof(*v));
- strcpy(v->name, "Radio");
- v->flags = VIDEO_AUDIO_MUTABLE | card->muted;
- v->mode = VIDEO_SOUND_STEREO;
- return 0;
- } case VIDIOCSAUDIO: {
- struct video_audio *v = arg;
- if (v->audio)
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=card->muted;
+ return (0);
+ }
return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
{
- register u16 io = card->io;
- register u16 omask = inw(io + IO_MASK);
- outw(~STR_WREN, io + IO_MASK);
- outw((card->muted = v->flags & VIDEO_AUDIO_MUTE) ?
- STR_WREN : 0, io);
- udelay(4);
- outw(omask, io + IO_MASK);
- msleep(125);
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ {
+ register u16 io = card->io;
+ register u16 omask = inw(io + IO_MASK);
+ outw(~STR_WREN, io + IO_MASK);
+ outw((card->muted = ctrl->value ) ?
+ STR_WREN : 0, io);
+ udelay(4);
+ outw(omask, io + IO_MASK);
+ msleep(125);
+
+ return (0);
+ }
+ }
+ return -EINVAL;
}
- } case VIDIOCGUNIT: {
- struct video_unit *v = arg;
- v->video = VIDEO_NO_UNIT;
- v->vbi = VIDEO_NO_UNIT;
- v->radio = dev->minor;
- v->audio = 0;
- v->teletext = VIDEO_NO_UNIT;
- return 0;
- } default:
- return -ENOIOCTLCMD;
+ default:
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ radio_function);
}
}
@@ -275,7 +338,7 @@ static u16 __devinit radio_power_on(struct radio_device *dev)
omask = inw(io + IO_MASK);
odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
outw(odir & ~STR_WREN, io + IO_DIR);
- dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE;
+ dev->muted = inw(io) & STR_WREN ? 0 : 1;
outw(odir, io + IO_DIR);
outw(~(STR_WREN | STR_CLK), io + IO_MASK);
outw(dev->muted ? 0 : STR_WREN, io);
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index f93d7afe7304..c2eeae7a10d0 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -20,13 +20,14 @@
* 0.75b
* - better pci interface thanks to Francois Romieu <romieu@cogenit.fr>
*
- * 0.75
+ * 0.75 Sun Feb 4 22:51:27 EET 2001
* - tiding up
* - removed support for multiple devices as it didn't work anyway
*
* BUGS:
* - card unmutes if you change frequency
*
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
@@ -40,11 +41,24 @@
#include <linux/mutex.h>
#include <linux/pci.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-/* version 0.75 Sun Feb 4 22:51:27 EET 2001 */
-#define DRIVER_VERSION "0.75"
+#define DRIVER_VERSION "0.76"
+
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,7,6)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }
+};
#ifndef PCI_VENDOR_ID_GUILLEMOT
#define PCI_VENDOR_ID_GUILLEMOT 0x5046
@@ -90,7 +104,6 @@ static struct video_device maxiradio_radio =
.owner = THIS_MODULE,
.name = "Maxi Radio FM2000 radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_SF16MI,
.fops = &maxiradio_fops,
};
@@ -176,89 +189,116 @@ static inline int radio_function(struct inode *inode, struct file *file,
struct radio_device *card=dev->priv;
switch(cmd) {
- case VIDIOCGCAP: {
- struct video_capability *v = arg;
-
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- strcpy(v->name, "Maxi Radio FM2000 radio");
- v->type=VID_TYPE_TUNER;
- v->channels=v->audios=1;
+ strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver));
+ strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER: {
- struct video_tuner *v = arg;
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *v = arg;
- if(v->tuner)
+ if (v->index > 0)
return -EINVAL;
- card->stereo = 0xffff * get_stereo(card->io);
- card->tuned = 0xffff * get_tune(card->io);
-
- v->flags = VIDEO_TUNER_LOW | card->stereo;
- v->signal = card->tuned;
-
+ memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
-
- v->rangelow = FREQ_LO;
- v->rangehigh = FREQ_HI;
- v->mode = VIDEO_MODE_AUTO;
+ v->type = V4L2_TUNER_RADIO;
+
+ v->rangelow=FREQ_LO;
+ v->rangehigh=FREQ_HI;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(get_stereo(card->io))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xffff*get_tune(card->io);
return 0;
}
- case VIDIOCSTUNER: {
- struct video_tuner *v = arg;
- if(v->tuner!=0)
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- return 0;
- }
- case VIDIOCGFREQ: {
- unsigned long *freq = arg;
- *freq = card->freq;
return 0;
}
- case VIDIOCSFREQ: {
- unsigned long *freq = arg;
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
- if (*freq < FREQ_LO || *freq > FREQ_HI)
+ if (f->frequency < FREQ_LO || f->frequency > FREQ_HI)
return -EINVAL;
- card->freq = *freq;
+
+ card->freq = f->frequency;
set_freq(card->io, FREQ2BITS(card->freq));
msleep(125);
return 0;
}
- case VIDIOCGAUDIO: {
- struct video_audio *v = arg;
- memset(v,0,sizeof(*v));
- strcpy(v->name, "Radio");
- v->flags=VIDEO_AUDIO_MUTABLE | card->muted;
- v->mode=VIDEO_SOUND_STEREO;
- return 0;
- }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
- case VIDIOCSAUDIO: {
- struct video_audio *v = arg;
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = card->freq;
- if(v->audio)
- return -EINVAL;
- card->muted = v->flags & VIDEO_AUDIO_MUTE;
- if(card->muted)
- turn_power(card->io, 0);
- else
- set_freq(card->io, FREQ2BITS(card->freq));
return 0;
}
- case VIDIOCGUNIT: {
- struct video_unit *v = arg;
-
- v->video=VIDEO_NO_UNIT;
- v->vbi=VIDEO_NO_UNIT;
- v->radio=dev->minor;
- v->audio=0;
- v->teletext=VIDEO_NO_UNIT;
- return 0;
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=card->muted;
+ return (0);
+ }
+ return -EINVAL;
}
- default: return -ENOIOCTLCMD;
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ card->muted = ctrl->value;
+ if(card->muted)
+ turn_power(card->io, 0);
+ else
+ set_freq(card->io, FREQ2BITS(card->freq));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+ default:
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ radio_function);
+
}
}
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 5b68ac4c7322..b9e98483e58d 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -6,6 +6,7 @@
*
* TODO: Allow for more than one of these foolish entities :-)
*
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h> /* Modules */
@@ -14,11 +15,32 @@
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_RTRACK2_PORT */
#include <linux/spinlock.h>
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
#ifndef CONFIG_RADIO_RTRACK2_PORT
#define CONFIG_RADIO_RTRACK2_PORT -1
#endif
@@ -115,75 +137,120 @@ static int rt_do_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
- strcpy(v->name, "RadioTrack II");
+ strlcpy(v->driver, "radio-rtrack2", sizeof (v->driver));
+ strlcpy(v->card, "RadioTrack II", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- v->rangelow=88*16000;
- v->rangehigh=108*16000;
- v->flags=VIDEO_TUNER_LOW;
- v->mode=VIDEO_MODE_AUTO;
- v->signal=0xFFFF*rt_getsigstr(rt);
+
+ memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
+ v->rangelow=(88*16000);
+ v->rangehigh=(108*16000);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*rt_getsigstr(rt);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner!=0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
+
return 0;
}
- case VIDIOCGFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- *freq = rt->curfreq;
+ struct v4l2_frequency *f = arg;
+
+ rt->curfreq = f->frequency;
+ rt_setfreq(rt, rt->curfreq);
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_G_FREQUENCY:
{
- unsigned long *freq = arg;
- rt->curfreq = *freq;
- rt_setfreq(rt, rt->curfreq);
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = rt->curfreq;
+
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *v = arg;
- memset(v,0, sizeof(*v));
- v->flags|=VIDEO_AUDIO_MUTABLE;
- v->volume=1;
- v->step=65535;
- strcpy(v->name, "Radio");
- return 0;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_G_CTRL:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
-
- if(v->flags&VIDEO_AUDIO_MUTE)
- rt_mute(rt);
- else
- rt_unmute(rt);
-
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=rt->muted;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ if (rt->muted)
+ ctrl->value=0;
+ else
+ ctrl->value=65535;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ rt_mute(rt);
+ } else {
+ rt_unmute(rt);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ if (ctrl->value) {
+ rt_unmute(rt);
+ } else {
+ rt_mute(rt);
+ }
+ return (0);
+ }
+ return -EINVAL;
}
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ rt_do_ioctl);
}
}
@@ -209,7 +276,7 @@ static struct video_device rtrack2_radio=
.owner = THIS_MODULE,
.name = "RadioTrack II radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_RTRACK2,
+ .hardware = 0,
.fops = &rtrack2_fops,
};
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index efee6e339d15..ecc854b4ba38 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -13,20 +13,35 @@
* No volume control - only mute/unmute - you have to use line volume
* control on SB-part of SF16FMI
*
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
+#include <linux/version.h>
#include <linux/kernel.h> /* __setup */
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
#include <linux/ioport.h> /* request_region */
#include <linux/delay.h> /* udelay */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
#include <linux/isapnp.h>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include <linux/mutex.h>
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ }
+};
+
struct fmi_device
{
int port;
@@ -123,93 +138,122 @@ static int fmi_do_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- strcpy(v->name, "SF16-FMx radio");
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
+ strlcpy(v->driver, "radio-sf16fmi", sizeof (v->driver));
+ strlcpy(v->card, "SF16-FMx radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
+ struct v4l2_tuner *v = arg;
int mult;
- if(v->tuner) /* Only 1 tuner */
+ if (v->index > 0)
return -EINVAL;
+
+ memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
- mult = (fmi->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+ v->type = V4L2_TUNER_RADIO;
+
+ mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
v->rangelow = RSF16_MINFREQ/mult;
v->rangehigh = RSF16_MAXFREQ/mult;
- v->flags=fmi->flags;
- v->mode=VIDEO_MODE_AUTO;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
+ v->capability=fmi->flags&V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_STEREO;
v->signal = fmi_getsigstr(fmi);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner!=0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- fmi->flags = v->flags & VIDEO_TUNER_LOW;
- /* Only 1 tuner so no setting needed ! */
- return 0;
- }
- case VIDIOCGFREQ:
- {
- unsigned long *freq = arg;
- *freq = fmi->curfreq;
- if (!(fmi->flags & VIDEO_TUNER_LOW))
- *freq /= 1000;
+
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- if (!(fmi->flags & VIDEO_TUNER_LOW))
- *freq *= 1000;
- if (*freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
+ struct v4l2_frequency *f = arg;
+
+ if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
+ f->frequency *= 1000;
+ if (f->frequency < RSF16_MINFREQ ||
+ f->frequency > RSF16_MAXFREQ )
return -EINVAL;
/*rounding in steps of 800 to match th freq
that will be used */
- fmi->curfreq = (*freq/800)*800;
+ fmi->curfreq = (f->frequency/800)*800;
fmi_setfreq(fmi);
+
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOC_G_FREQUENCY:
{
- struct video_audio *v = arg;
- memset(v,0,sizeof(*v));
- v->flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
- strcpy(v->name, "Radio");
- v->mode=VIDEO_SOUND_STEREO;
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = fmi->curfreq;
+ if (!(fmi->flags & V4L2_TUNER_CAP_LOW))
+ f->frequency /= 1000;
+
return 0;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
- fmi->curvol= v->flags&VIDEO_AUDIO_MUTE ? 0 : 1;
- fmi->curvol ?
- fmi_unmute(fmi->port) : fmi_mute(fmi->port);
- return 0;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
}
- case VIDIOCGUNIT:
+ case VIDIOC_G_CTRL:
{
- struct video_unit *v = arg;
- v->video=VIDEO_NO_UNIT;
- v->vbi=VIDEO_NO_UNIT;
- v->radio=dev->minor;
- v->audio=0; /* How do we find out this??? */
- v->teletext=VIDEO_NO_UNIT;
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=fmi->curvol;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ {
+ if (ctrl->value)
+ fmi_mute(fmi->port);
+ else
+ fmi_unmute(fmi->port);
+
+ fmi->curvol=ctrl->value;
+ return (0);
+ }
+ }
+ return -EINVAL;
}
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ fmi_do_ioctl);
}
}
@@ -235,7 +279,7 @@ static struct video_device fmi_radio=
.owner = THIS_MODULE,
.name = "SF16FMx radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_SF16MI,
+ .hardware = 0,
.fops = &fmi_fops,
};
@@ -294,7 +338,7 @@ static int __init fmi_init(void)
fmi_unit.port = io;
fmi_unit.curvol = 0;
fmi_unit.curfreq = 0;
- fmi_unit.flags = VIDEO_TUNER_LOW;
+ fmi_unit.flags = V4L2_TUNER_CAP_LOW;
fmi_radio.priv = &fmi_unit;
mutex_init(&lock);
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 3483b2c7bc9d..4444dce864a9 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -10,6 +10,8 @@
* For read stereo/mono you must wait 0.1 sec after set frequency and
* card unmuted so I set frequency on unmute
* Signal handling seem to work only on autoscanning (not implemented)
+ *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h> /* Modules */
@@ -18,12 +20,34 @@
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
#include <linux/mutex.h>
static struct mutex lock;
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 1<<12,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
#undef DEBUG
//#define DEBUG 1
@@ -214,63 +238,65 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- strcpy(v->name, "SF16-FMR2 radio");
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
+ strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver));
+ strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
+ struct v4l2_tuner *v = arg;
int mult;
- if(v->tuner) /* Only 1 tuner */
+ if (v->index > 0)
return -EINVAL;
+
+ memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
- mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
+ v->type = V4L2_TUNER_RADIO;
+
+ mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
v->rangelow = RSF16_MINFREQ/mult;
v->rangehigh = RSF16_MAXFREQ/mult;
- v->flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
- if (fmr2->mute)
- v->flags |= VIDEO_AUDIO_MUTE;
- v->mode=VIDEO_MODE_AUTO;
+ v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
+ v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW;
+
+ v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
+ V4L2_TUNER_MODE_MONO;
mutex_lock(&lock);
v->signal = fmr2_getsigstr(fmr2);
mutex_unlock(&lock);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if (v->tuner!=0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- fmr2->flags = v->flags & VIDEO_TUNER_LOW;
- return 0;
- }
- case VIDIOCGFREQ:
- {
- unsigned long *freq = arg;
- *freq = fmr2->curfreq;
- if (!(fmr2->flags & VIDEO_TUNER_LOW))
- *freq /= 1000;
+
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- if (!(fmr2->flags & VIDEO_TUNER_LOW))
- *freq *= 1000;
- if ( *freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
+ struct v4l2_frequency *f = arg;
+
+ if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
+ f->frequency *= 1000;
+ if (f->frequency < RSF16_MINFREQ ||
+ f->frequency > RSF16_MAXFREQ )
return -EINVAL;
- /* rounding in steps of 200 to match th freq
- * that will be used
- */
- fmr2->curfreq = (*freq/200)*200;
+ /*rounding in steps of 200 to match th freq
+ that will be used */
+ fmr2->curfreq = (f->frequency/200)*200;
/* set card freq (if not muted) */
if (fmr2->curvol && !fmr2->mute)
@@ -279,40 +305,81 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
fmr2_setfreq(fmr2);
mutex_unlock(&lock);
}
+
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOC_G_FREQUENCY:
{
- struct video_audio *v = arg;
- memset(v,0,sizeof(*v));
- /* !!! do not return VIDEO_AUDIO_MUTE */
- v->flags = VIDEO_AUDIO_MUTABLE;
- strcpy(v->name, "Radio");
- /* get current stereo mode */
- v->mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
- /* volume supported ? */
- if (fmr2->card_type == 11)
- {
- v->flags |= VIDEO_AUDIO_VOLUME;
- v->step = 1 << 12;
- v->volume = fmr2->curvol;
- }
- debug_print((KERN_DEBUG "Get flags %d vol %d\n", v->flags, v->volume));
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = fmr2->curfreq;
+ if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
+ f->frequency /= 1000;
+
return 0;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
- debug_print((KERN_DEBUG "Set flags %d vol %d\n", v->flags, v->volume));
- /* set volume */
- if (v->flags & VIDEO_AUDIO_VOLUME)
- fmr2->curvol = v->volume; /* !!! set with precision */
- if (fmr2->card_type != 11) fmr2->curvol = 65535;
- fmr2->mute = 0;
- if (v->flags & VIDEO_AUDIO_MUTE)
- fmr2->mute = 1;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if ((fmr2->card_type != 11)
+ && V4L2_CID_AUDIO_VOLUME)
+ radio_qctrl[i].step=65535;
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=fmr2->mute;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=fmr2->curvol;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ fmr2->mute=ctrl->value;
+ if (fmr2->card_type != 11) {
+ if (!fmr2->mute) {
+ fmr2->curvol = 65535;
+ } else {
+ fmr2->curvol = 0;
+ }
+ }
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ fmr2->curvol = ctrl->value;
+ if (fmr2->card_type != 11) {
+ if (fmr2->curvol) {
+ fmr2->curvol = 65535;
+ fmr2->mute = 0;
+ } else {
+ fmr2->curvol = 0;
+ fmr2->mute = 1;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
#ifdef DEBUG
if (fmr2->curvol && !fmr2->mute)
printk(KERN_DEBUG "unmute\n");
@@ -320,27 +387,18 @@ static int fmr2_do_ioctl(struct inode *inode, struct file *file,
printk(KERN_DEBUG "mute\n");
#endif
mutex_lock(&lock);
- if (fmr2->curvol && !fmr2->mute)
- {
+ if (fmr2->curvol && !fmr2->mute) {
fmr2_setvolume(fmr2);
fmr2_setfreq(fmr2);
- }
- else fmr2_mute(fmr2->port);
+ } else
+ fmr2_mute(fmr2->port);
mutex_unlock(&lock);
- return 0;
- }
- case VIDIOCGUNIT:
- {
- struct video_unit *v = arg;
- v->video=VIDEO_NO_UNIT;
- v->vbi=VIDEO_NO_UNIT;
- v->radio=dev->minor;
- v->audio=0; /* How do we find out this??? */
- v->teletext=VIDEO_NO_UNIT;
- return 0;
+ return (0);
}
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ fmr2_do_ioctl);
+
}
}
@@ -366,7 +424,7 @@ static struct video_device fmr2_radio=
.owner = THIS_MODULE,
.name = "SF16FMR2 radio",
. type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_SF16FMR2,
+ .hardware = 0,
.fops = &fmr2_fops,
};
@@ -377,7 +435,7 @@ static int __init fmr2_init(void)
fmr2_unit.mute = 0;
fmr2_unit.curfreq = 0;
fmr2_unit.stereo = 1;
- fmr2_unit.flags = VIDEO_TUNER_LOW;
+ fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
fmr2_unit.card_type = 0;
fmr2_radio.priv = &fmr2_unit;
@@ -396,7 +454,6 @@ static int __init fmr2_init(void)
}
printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
- debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
/* mute card - prevents noisy bootups */
mutex_lock(&lock);
fmr2_mute(io);
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index dfba4ae596cd..f539491a0d76 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -21,6 +21,7 @@
* If you can help me out with that, please contact me!!
*
*
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h> /* Modules */
@@ -29,11 +30,32 @@
#include <linux/delay.h> /* udelay */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_TERRATEC_PORT */
#include <linux/spinlock.h>
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
#ifndef CONFIG_RADIO_TERRATEC_PORT
#define CONFIG_RADIO_TERRATEC_PORT 0x590
#endif
@@ -194,73 +216,117 @@ static int tt_do_ioctl(struct inode *inode, struct file *file,
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
- strcpy(v->name, "ActiveRadio");
+ strlcpy(v->driver, "radio-terratec", sizeof (v->driver));
+ strlcpy(v->card, "ActiveRadio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
+
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
v->rangelow=(87*16000);
v->rangehigh=(108*16000);
- v->flags=VIDEO_TUNER_LOW;
- v->mode=VIDEO_MODE_AUTO;
- strcpy(v->name, "FM");
+ v->rxsubchans =V4L2_TUNER_SUB_MONO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
v->signal=0xFFFF*tt_getsigstr(tt);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner!=0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
+
return 0;
}
- case VIDIOCGFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- *freq = tt->curfreq;
+ struct v4l2_frequency *f = arg;
+
+ tt->curfreq = f->frequency;
+ tt_setfreq(tt, tt->curfreq);
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_G_FREQUENCY:
{
- unsigned long *freq = arg;
- tt->curfreq = *freq;
- tt_setfreq(tt, tt->curfreq);
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = tt->curfreq;
+
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *v = arg;
- memset(v,0, sizeof(*v));
- v->flags|=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
- v->volume=tt->curvol * 6554;
- v->step=6554;
- strcpy(v->name, "Radio");
- return 0;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_G_CTRL:
{
- struct video_audio *v = arg;
- if(v->audio)
- return -EINVAL;
- if(v->flags&VIDEO_AUDIO_MUTE)
- tt_mute(tt);
- else
- tt_setvol(tt,v->volume/6554);
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (tt->muted)
+ ctrl->value=1;
+ else
+ ctrl->value=0;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=tt->curvol * 6554;
+ return (0);
+ }
+ return -EINVAL;
}
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ tt_mute(tt);
+ } else {
+ tt_setvol(tt,tt->curvol);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ tt_setvol(tt,ctrl->value);
+ return (0);
+ }
+ return -EINVAL;
+ }
+
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ tt_do_ioctl);
}
}
@@ -286,7 +352,7 @@ static struct video_device terratec_radio=
.owner = THIS_MODULE,
.name = "TerraTec ActiveRadio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_TERRATEC,
+ .hardware = 0,
.fops = &terratec_fops,
};
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 8da4badc22b4..bb03ad5a2033 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -12,7 +12,7 @@
* Scott McGrath (smcgrath@twilight.vtc.vsc.edu)
* William McGrath (wmcgrath@twilight.vtc.vsc.edu)
*
- * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <stdarg.h>
@@ -21,9 +21,46 @@
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/uaccess.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_TRUST_PORT */
+
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 2048,
+ .default_value = 65535,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_AUDIO_BASS,
+ .name = "Bass",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 4370,
+ .default_value = 32768,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_AUDIO_TREBLE,
+ .name = "Treble",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 4370,
+ .default_value = 32768,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },
+};
/* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
@@ -160,88 +197,125 @@ static int tr_do_ioctl(struct inode *inode, struct file *file,
{
switch(cmd)
{
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
-
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type=VID_TYPE_TUNER;
- v->channels=1;
- v->audios=1;
- strcpy(v->name, "Trust FM Radio");
+ strlcpy(v->driver, "radio-trust", sizeof (v->driver));
+ strlcpy(v->card, "Trust FM Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
+ struct v4l2_tuner *v = arg;
- if(v->tuner) /* Only 1 tuner */
+ if (v->index > 0)
return -EINVAL;
- v->rangelow = 87500 * 16;
- v->rangehigh = 108000 * 16;
- v->flags = VIDEO_TUNER_LOW;
- v->mode = VIDEO_MODE_AUTO;
+ memset(v,0,sizeof(*v));
+ strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
- v->signal = tr_getsigstr();
+ v->rangelow=(87.5*16000);
+ v->rangehigh=(108*16000);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
if(tr_getstereo())
- v->flags |= VIDEO_TUNER_STEREO_ON;
-
- strcpy(v->name, "FM");
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=tr_getsigstr();
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if(v->tuner != 0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
+
return 0;
}
- case VIDIOCGFREQ:
+ case VIDIOC_S_FREQUENCY:
{
- unsigned long *freq = arg;
- *freq = curfreq;
+ struct v4l2_frequency *f = arg;
+
+ curfreq = f->frequency;
+ tr_setfreq(curfreq);
return 0;
}
- case VIDIOCSFREQ:
+ case VIDIOC_G_FREQUENCY:
{
- unsigned long *freq = arg;
- tr_setfreq(*freq);
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = curfreq;
+
return 0;
}
- case VIDIOCGAUDIO:
+ case VIDIOC_QUERYCTRL:
{
- struct video_audio *v = arg;
-
- memset(v,0, sizeof(*v));
- v->flags = VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME |
- VIDEO_AUDIO_BASS | VIDEO_AUDIO_TREBLE;
- v->mode = curstereo? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
- v->volume = curvol * 2048;
- v->step = 2048;
- v->bass = curbass * 4370;
- v->treble = curtreble * 4370;
-
- strcpy(v->name, "Trust FM Radio");
- return 0;
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_G_CTRL:
{
- struct video_audio *v = arg;
-
- if(v->audio)
- return -EINVAL;
- tr_setvol(v->volume);
- tr_setbass(v->bass);
- tr_settreble(v->treble);
- tr_setstereo(v->mode & VIDEO_SOUND_STEREO);
- tr_setmute(v->flags & VIDEO_AUDIO_MUTE);
- return 0;
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=curmute;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value= curvol * 2048;
+ return (0);
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value= curbass * 4370;
+ return (0);
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value= curtreble * 4370;
+ return (0);
+ }
+ return -EINVAL;
}
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ tr_setmute(ctrl->value);
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ tr_setvol(ctrl->value);
+ return 0;
+ case V4L2_CID_AUDIO_BASS:
+ tr_setbass(ctrl->value);
+ return 0;
+ case V4L2_CID_AUDIO_TREBLE:
+ tr_settreble(ctrl->value);
+ return (0);
+ }
+ return -EINVAL;
+ }
+
default:
- return -ENOIOCTLCMD;
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ tr_do_ioctl);
}
}
@@ -265,7 +339,7 @@ static struct video_device trust_radio=
.owner = THIS_MODULE,
.name = "Trust FM Radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_TRUST,
+ .hardware = 0,
.fops = &trust_fops,
};
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index edd012288669..4a72b4d4e62a 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -27,6 +27,8 @@
* value where I do expect just noise and turn the speaker volume down.
* The frequency change is necessary since the card never seems to be
* completely silent.
+ *
+ * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h> /* Modules */
@@ -35,11 +37,32 @@
#include <linux/proc_fs.h> /* radio card status report */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_TYPHOON_* */
-#define BANNER "Typhoon Radio Card driver v0.1\n"
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,1,1)
+#define BANNER "Typhoon Radio Card driver v0.1.1\n"
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 1<<14,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
+
#ifndef CONFIG_RADIO_TYPHOON_PORT
#define CONFIG_RADIO_TYPHOON_PORT -1
@@ -171,76 +194,114 @@ static int typhoon_do_ioctl(struct inode *inode, struct file *file,
struct typhoon_device *typhoon = dev->priv;
switch (cmd) {
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type = VID_TYPE_TUNER;
- v->channels = 1;
- v->audios = 1;
- strcpy(v->name, "Typhoon Radio");
+ strlcpy(v->driver, "radio-typhoon", sizeof (v->driver));
+ strlcpy(v->card, "Typhoon Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if (v->tuner) /* Only 1 tuner */
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- v->rangelow = 875 * 1600;
- v->rangehigh = 1080 * 1600;
- v->flags = VIDEO_TUNER_LOW;
- v->mode = VIDEO_MODE_AUTO;
- v->signal = 0xFFFF; /* We can't get the signal strength */
+
+ memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
+ v->type = V4L2_TUNER_RADIO;
+
+ v->rangelow=(87.5*16000);
+ v->rangehigh=(108*16000);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal = 0xFFFF; /* We can't get the signal strength */
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if (v->tuner != 0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
+
return 0;
}
- case VIDIOCGFREQ:
- {
- unsigned long *freq = arg;
- *freq = typhoon->curfreq;
- return 0;
- }
- case VIDIOCSFREQ:
- {
- unsigned long *freq = arg;
- typhoon->curfreq = *freq;
- typhoon_setfreq(typhoon, typhoon->curfreq);
- return 0;
- }
- case VIDIOCGAUDIO:
+ case VIDIOC_S_FREQUENCY:
{
- struct video_audio *v = arg;
- memset(v, 0, sizeof(*v));
- v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
- v->mode |= VIDEO_SOUND_MONO;
- v->volume = typhoon->curvol;
- v->step = 1 << 14;
- strcpy(v->name, "Typhoon Radio");
+ struct v4l2_frequency *f = arg;
+
+ typhoon->curfreq = f->frequency;
+ typhoon_setfreq(typhoon, typhoon->curfreq);
return 0;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_G_FREQUENCY:
{
- struct video_audio *v = arg;
- if (v->audio)
- return -EINVAL;
- if (v->flags & VIDEO_AUDIO_MUTE)
- typhoon_mute(typhoon);
- else
- typhoon_unmute(typhoon);
- if (v->flags & VIDEO_AUDIO_VOLUME)
- typhoon_setvol(typhoon, v->volume);
+ struct v4l2_frequency *f = arg;
+
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = typhoon->curfreq;
+
return 0;
}
- default:
- return -ENOIOCTLCMD;
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=typhoon->muted;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=typhoon->curvol;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ typhoon_mute(typhoon);
+ } else {
+ typhoon_unmute(typhoon);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ typhoon_setvol(typhoon, ctrl->value);
+ return (0);
+ }
+ return -EINVAL;
+ }
+
+ default:
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ typhoon_do_ioctl);
}
}
@@ -271,7 +332,7 @@ static struct video_device typhoon_radio =
.owner = THIS_MODULE,
.name = "Typhoon Radio",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_TYPHOON,
+ .hardware = 0,
.fops = &typhoon_fops,
};
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 59b86a6b4b0e..671fe1b1e5bc 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -24,6 +24,9 @@
* - Added unmute function
* - Reworked ioctl functions
* 2002-07-15 - Fix Stereo typo
+ *
+ * 2006-07-24 - Converted to V4L2 API
+ * by Mauro Carvalho Chehab <mchehab@infradead.org>
*/
#include <linux/module.h> /* Modules */
@@ -32,9 +35,30 @@
#include <linux/delay.h> /* udelay, msleep */
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
-#include <linux/videodev.h> /* kernel radio structs */
+#include <linux/videodev2.h> /* kernel radio structs */
#include <media/v4l2-common.h>
-#include <linux/config.h> /* CONFIG_RADIO_ZOLTRIX_PORT */
+
+#include <linux/version.h> /* for KERNEL_VERSION MACRO */
+#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+
+static struct v4l2_queryctrl radio_qctrl[] = {
+ {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 4096,
+ .default_value = 0xff,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ }
+};
#ifndef CONFIG_RADIO_ZOLTRIX_PORT
#define CONFIG_RADIO_ZOLTRIX_PORT -1
@@ -213,78 +237,116 @@ static int zol_do_ioctl(struct inode *inode, struct file *file,
struct zol_device *zol = dev->priv;
switch (cmd) {
- case VIDIOCGCAP:
+ case VIDIOC_QUERYCAP:
{
- struct video_capability *v = arg;
-
+ struct v4l2_capability *v = arg;
memset(v,0,sizeof(*v));
- v->type = VID_TYPE_TUNER;
- v->channels = 1 + zol->stereo;
- v->audios = 1;
- strcpy(v->name, "Zoltrix Radio");
+ strlcpy(v->driver, "radio-zoltrix", sizeof (v->driver));
+ strlcpy(v->card, "Zoltrix Radio", sizeof (v->card));
+ sprintf(v->bus_info,"ISA");
+ v->version = RADIO_VERSION;
+ v->capabilities = V4L2_CAP_TUNER;
+
return 0;
}
- case VIDIOCGTUNER:
+ case VIDIOC_G_TUNER:
{
- struct video_tuner *v = arg;
- if (v->tuner)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
+
+ memset(v,0,sizeof(*v));
strcpy(v->name, "FM");
- v->rangelow = (int) (88.0 * 16000);
- v->rangehigh = (int) (108.0 * 16000);
- v->flags = zol_is_stereo(zol)
- ? VIDEO_TUNER_STEREO_ON : 0;
- v->flags |= VIDEO_TUNER_LOW;
- v->mode = VIDEO_MODE_AUTO;
- v->signal = 0xFFFF * zol_getsigstr(zol);
+ v->type = V4L2_TUNER_RADIO;
+
+ v->rangelow=(88*16000);
+ v->rangehigh=(108*16000);
+ v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
+ v->capability=V4L2_TUNER_CAP_LOW;
+ if(zol_is_stereo(zol))
+ v->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ v->audmode = V4L2_TUNER_MODE_MONO;
+ v->signal=0xFFFF*zol_getsigstr(zol);
+
return 0;
}
- case VIDIOCSTUNER:
+ case VIDIOC_S_TUNER:
{
- struct video_tuner *v = arg;
- if (v->tuner != 0)
+ struct v4l2_tuner *v = arg;
+
+ if (v->index > 0)
return -EINVAL;
- /* Only 1 tuner so no setting needed ! */
+
return 0;
}
- case VIDIOCGFREQ:
- {
- unsigned long *freq = arg;
- *freq = zol->curfreq;
- return 0;
- }
- case VIDIOCSFREQ:
- {
- unsigned long *freq = arg;
- zol->curfreq = *freq;
- zol_setfreq(zol, zol->curfreq);
- return 0;
- }
- case VIDIOCGAUDIO:
+ case VIDIOC_S_FREQUENCY:
{
- struct video_audio *v = arg;
- memset(v, 0, sizeof(*v));
- v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
- v->mode |= zol_is_stereo(zol)
- ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
- v->volume = zol->curvol * 4096;
- v->step = 4096;
- strcpy(v->name, "Zoltrix Radio");
+ struct v4l2_frequency *f = arg;
+
+ zol->curfreq = f->frequency;
+ zol_setfreq(zol, zol->curfreq);
return 0;
}
- case VIDIOCSAUDIO:
+ case VIDIOC_G_FREQUENCY:
{
- struct video_audio *v = arg;
- if (v->audio)
- return -EINVAL;
+ struct v4l2_frequency *f = arg;
- if (v->flags & VIDEO_AUDIO_MUTE)
- zol_mute(zol);
- else {
- zol_unmute(zol);
- zol_setvol(zol, v->volume / 4096);
- }
+ f->type = V4L2_TUNER_RADIO;
+ f->frequency = zol->curfreq;
+ return 0;
+ }
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
+ if (qc->id && qc->id == radio_qctrl[i].id) {
+ memcpy(qc, &(radio_qctrl[i]),
+ sizeof(*qc));
+ return (0);
+ }
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_G_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value=zol->muted;
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value=zol->curvol * 4096;
+ return (0);
+ }
+ return -EINVAL;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ struct v4l2_control *ctrl= arg;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (ctrl->value) {
+ zol_mute(zol);
+ } else {
+ zol_unmute(zol);
+ zol_setvol(zol,zol->curvol);
+ }
+ return (0);
+ case V4L2_CID_AUDIO_VOLUME:
+ zol_setvol(zol,ctrl->value/4096);
+ return (0);
+ }
+ zol->stereo = 1;
+ zol_setfreq(zol, zol->curfreq);
+#if 0
+/* FIXME: Implement stereo/mono switch on V4L2 */
if (v->mode & VIDEO_SOUND_STEREO) {
zol->stereo = 1;
zol_setfreq(zol, zol->curfreq);
@@ -293,10 +355,13 @@ static int zol_do_ioctl(struct inode *inode, struct file *file,
zol->stereo = 0;
zol_setfreq(zol, zol->curfreq);
}
- return 0;
+#endif
+ return -EINVAL;
}
- default:
- return -ENOIOCTLCMD;
+
+ default:
+ return v4l_compat_translate_ioctl(inode,file,cmd,arg,
+ zol_do_ioctl);
}
}
@@ -323,7 +388,7 @@ static struct video_device zoltrix_radio =
.owner = THIS_MODULE,
.name = "Zoltrix Radio Plus",
.type = VID_TYPE_TUNER,
- .hardware = VID_HARDWARE_ZOLTRIX,
+ .hardware = 0,
.fops = &zoltrix_fops,
};
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 94d078b77bab..fbe5b6168cc2 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -16,6 +16,322 @@ config VIDEO_ADV_DEBUG
V4L devices.
In doubt, say N.
+config VIDEO_HELPER_CHIPS_AUTO
+ bool "Autoselect pertinent encoders/decoders and other helper chips"
+ default y
+ ---help---
+ Most video cards may require additional modules to encode or
+ decode audio/video standards. This option will autoselect
+ all pertinent modules to each selected video module.
+
+ Unselect this only if you know exaclty what you are doing, since
+ it may break support on some boards.
+
+ In doubt, say Y.
+
+#
+# Encoder / Decoder module configuration
+#
+
+menu "Encoders/decoders and other helper chips"
+ depends on VIDEO_DEV && !VIDEO_HELPER_CHIPS_AUTO
+
+comment "Audio decoders"
+
+config VIDEO_TVAUDIO
+ tristate "Simple audio decoder chips"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for several audio decoder chips found on some bt8xx boards:
+ Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300,
+ tea6320, tea6420, tda8425, ta8874z.
+ Microchip: pic16c54 based design on ProVideo PV951 board.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvaudio.
+
+config VIDEO_TDA7432
+ tristate "Philips TDA7432 audio processor"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for tda7432 audio decoder chip found on some bt8xx boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tda7432.
+
+config VIDEO_TDA9840
+ tristate "Philips TDA9840 audio processor"
+ depends on VIDEO_DEV && I2C
+ ---help---
+ Support for tda9840 audio decoder chip found on some Zoran boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tda9840.
+
+config VIDEO_TDA9875
+ tristate "Philips TDA9875 audio processor"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for tda9875 audio decoder chip found on some bt8xx boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tda9875.
+
+config VIDEO_TEA6415C
+ tristate "Philips TEA6415C audio processor"
+ depends on VIDEO_DEV && I2C
+ ---help---
+ Support for tea6415c audio decoder chip found on some bt8xx boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tea6415c.
+
+config VIDEO_TEA6420
+ tristate "Philips TEA6420 audio processor"
+ depends on VIDEO_DEV && I2C
+ ---help---
+ Support for tea6420 audio decoder chip found on some bt8xx boards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tea6420.
+
+config VIDEO_MSP3400
+ tristate "Micronas MSP34xx audio decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Micronas MSP34xx series of audio decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called msp3400.
+
+config VIDEO_CS53L32A
+ tristate "Cirrus Logic CS53L32A audio ADC"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Cirrus Logic CS53L32A low voltage
+ stereo A/D converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cs53l32a.
+
+config VIDEO_TLV320AIC23B
+ tristate "Texas Instruments TLV320AIC23B audio codec"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Texas Instruments TLV320AIC23B audio codec.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tlv320aic23b.
+
+config VIDEO_WM8775
+ tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Wolfson Microelectronics WM8775 high
+ performance stereo A/D Converter with a 4 channel input mixer.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wm8775.
+
+config VIDEO_WM8739
+ tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Wolfson Microelectronics WM8739
+ stereo A/D Converter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called wm8739.
+
+comment "Video decoders"
+
+config VIDEO_BT819
+ tristate "BT819A VideoStream decoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for BT819A video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bt819.
+
+config VIDEO_BT856
+ tristate "BT856 VideoStream decoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for BT856 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bt856.
+
+config VIDEO_BT866
+ tristate "BT866 VideoStream decoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for BT866 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called bt866.
+
+config VIDEO_KS0127
+ tristate "KS0127 video decoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for KS0127 video decoder.
+
+ This chip is used on AverMedia AVS6EYES Zoran-based MJPEG
+ cards.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ks0127.
+
+config VIDEO_SAA7110
+ tristate "Philips SAA7110 video decoder"
+ depends on VIDEO_V4L1
+ ---help---
+ Support for the Philips SAA7110 video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7110.
+
+config VIDEO_SAA7111
+ tristate "Philips SAA7111 video decoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for the Philips SAA711 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7111.
+
+config VIDEO_SAA7114
+ tristate "Philips SAA7114 video decoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for the Philips SAA7114 video decoder. This driver
+ is used only on Zoran driver and should be moved soon to
+ SAA711x module.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7114.
+
+config VIDEO_SAA711X
+ tristate "Philips SAA7113/4/5 video decoders"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Philips SAA7113/4/5 video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7115.
+
+config VIDEO_SAA7191
+ tristate "Philips SAA7191 video decoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for the Philips SAA7191 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7191.
+
+config VIDEO_TVP5150
+ tristate "Texas Instruments TVP5150 video decoder"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Texas Instruments TVP5150 video decoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tvp5150.
+
+config VIDEO_VPX3220
+ tristate "vpx3220a, vpx3216b & vpx3214c video decoders"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for VPX322x video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpx3220.
+
+comment "Video and audio decoders"
+
+source "drivers/media/video/cx25840/Kconfig"
+
+comment "MPEG video encoders"
+
+config VIDEO_CX2341X
+ tristate "Conexant CX2341x MPEG encoders"
+ depends on VIDEO_V4L2 && EXPERIMENTAL
+ ---help---
+ Support for the Conexant CX23416 MPEG encoders
+ and CX23415 MPEG encoder/decoders.
+
+ This module currently supports the encoding functions only.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cx2341x.
+
+comment "Video encoders"
+
+config VIDEO_SAA7127
+ tristate "Philips SAA7127/9 digital video encoders"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the Philips SAA7127/9 digital video encoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7127.
+
+config VIDEO_SAA7185
+ tristate "Philips SAA7185 video encoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for the Philips SAA7185 video encoder.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa7185.
+
+config VIDEO_ADV7170
+ tristate "Analog Devices ADV7170 video encoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for the Analog Devices ADV7170 video encoder driver
+
+ To compile this driver as a module, choose M here: the
+ module will be called adv7170.
+
+config VIDEO_ADV7175
+ tristate "Analog Devices ADV7175 video encoder"
+ depends on VIDEO_V4L1 && I2C
+ ---help---
+ Support for the Analog Devices ADV7175 video encoder driver
+
+ To compile this driver as a module, choose M here: the
+ module will be called adv7175.
+
+comment "Video improvement chips"
+
+config VIDEO_UPD64031A
+ tristate "NEC Electronics uPD64031A Ghost Reduction"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the NEC Electronics uPD64031A Ghost Reduction
+ video chip. It is most often found in NTSC TV cards made for
+ Japan and is used to reduce the 'ghosting' effect that can
+ be present in analog TV broadcasts.
+
+ To compile this driver as a module, choose M here: the
+ module will be called upd64031a.
+
+config VIDEO_UPD64083
+ tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
+ ---help---
+ Support for the NEC Electronics uPD64083 3-Dimensional Y/C
+ separation video chip. It is used to improve the quality of
+ the colors of a composite signal.
+
+ To compile this driver as a module, choose M here: the
+ module will be called upd64083.
+
+endmenu # encoder / decoder chips
+
config VIDEO_VIVI
tristate "Virtual Video Driver"
depends on VIDEO_V4L2 && !SPARC32 && !SPARC64
@@ -37,7 +353,7 @@ config VIDEO_SAA6588
help
Support for Radio Data System (RDS) decoder. This allows seeing
radio station identification transmitted using this standard.
- Currentlly, it works only with bt8x8 chips.
+ Currently, it works only with bt8x8 chips.
To compile this driver as a module, choose M here: the
module will be called saa6588.
@@ -135,7 +451,7 @@ source "drivers/media/video/cpia2/Kconfig"
config VIDEO_SAA5246A
tristate "SAA5246A, SAA5281 Teletext processor"
- depends on I2C && VIDEO_V4L1
+ depends on I2C && VIDEO_V4L2
help
Support for I2C bus based teletext using the SAA5246A or SAA5281
chip. Useful only if you live in Europe.
@@ -145,7 +461,7 @@ config VIDEO_SAA5246A
config VIDEO_SAA5249
tristate "SAA5249 Teletext processor"
- depends on VIDEO_DEV && I2C && VIDEO_V4L1
+ depends on VIDEO_DEV && I2C && VIDEO_V4L2
help
Support for I2C bus based teletext using the SAA5249 chip. At the
moment this is only useful on some European WinTV cards.
@@ -162,8 +478,9 @@ config TUNER_3036
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
- depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L1
+ depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
select I2C_ALGO_SGI
+ select VIDEO_SAA7191 if VIDEO_HELPER_CHIPS_AUTO
help
Say Y here to build in support for the Vino video input system found
on SGI Indy machines.
@@ -176,6 +493,9 @@ config VIDEO_STRADIS
driver for PCI. There is a product page at
<http://www.stradis.com/>.
+config VIDEO_ZORAN_ZR36060
+ tristate
+
config VIDEO_ZORAN
tristate "Zoran ZR36057/36067 Video For Linux"
depends on PCI && I2C_ALGOBIT && VIDEO_V4L1 && !PPC64
@@ -192,12 +512,18 @@ config VIDEO_ZORAN
config VIDEO_ZORAN_BUZ
tristate "Iomega Buz support"
depends on VIDEO_ZORAN
+ select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_SAA7185 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_ZORAN_ZR36060
help
Support for the Iomega Buz MJPEG capture/playback card.
config VIDEO_ZORAN_DC10
tristate "Pinnacle/Miro DC10(+) support"
depends on VIDEO_ZORAN
+ select VIDEO_SAA7110
+ select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_ZORAN_ZR36060
help
Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback
card.
@@ -205,6 +531,8 @@ config VIDEO_ZORAN_DC10
config VIDEO_ZORAN_DC30
tristate "Pinnacle/Miro DC30(+) support"
depends on VIDEO_ZORAN
+ select VIDEO_ADV7175 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_VPX3220 if VIDEO_HELPER_CHIPS_AUTO
help
Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback
card. This also supports really old DC10 cards based on the
@@ -213,6 +541,9 @@ config VIDEO_ZORAN_DC30
config VIDEO_ZORAN_LML33
tristate "Linux Media Labs LML33 support"
depends on VIDEO_ZORAN
+ select VIDEO_BT819 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_ZORAN_ZR36060
help
Support for the Linux Media Labs LML33 MJPEG capture/playback
card.
@@ -220,6 +551,9 @@ config VIDEO_ZORAN_LML33
config VIDEO_ZORAN_LML33R10
tristate "Linux Media Labs LML33R10 support"
depends on VIDEO_ZORAN
+ select VIDEO_SAA7114 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_ADV7170 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_ZORAN_ZR36060
help
support for the Linux Media Labs LML33R10 MJPEG capture/playback
card.
@@ -227,6 +561,9 @@ config VIDEO_ZORAN_LML33R10
config VIDEO_ZORAN_AVS6EYES
tristate "AverMedia 6 Eyes support (EXPERIMENTAL)"
depends on VIDEO_ZORAN && EXPERIMENTAL && VIDEO_V4L1
+ select VIDEO_BT856 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_KS0127 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_ZORAN_ZR36060
help
Support for the AverMedia 6 Eyes video surveillance card.
@@ -263,6 +600,10 @@ config VIDEO_MXB
depends on PCI && VIDEO_V4L1 && I2C
select VIDEO_SAA7146_VV
select VIDEO_TUNER
+ select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TDA9840 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TEA6415C if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TEA6420 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for the 'Multimedia eXtension Board'
TV card by Siemens-Nixdorf.
@@ -274,7 +615,7 @@ config VIDEO_DPC
tristate "Philips-Semiconductors 'dpc7146 demonstration board'"
depends on PCI && VIDEO_V4L1 && I2C
select VIDEO_SAA7146_VV
- select VIDEO_V4L2
+ select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for the 'dpc7146 demonstration
board' by Philips-Semiconductors. It's the reference design
@@ -287,9 +628,8 @@ config VIDEO_DPC
config VIDEO_HEXIUM_ORION
tristate "Hexium HV-PCI6 and Orion frame grabber"
- depends on PCI && VIDEO_V4L1 && I2C
+ depends on PCI && VIDEO_V4L2 && I2C
select VIDEO_SAA7146_VV
- select VIDEO_V4L2
---help---
This is a video4linux driver for the Hexium HV-PCI6 and
Orion frame grabber cards by Hexium.
@@ -299,9 +639,8 @@ config VIDEO_HEXIUM_ORION
config VIDEO_HEXIUM_GEMINI
tristate "Hexium Gemini frame grabber"
- depends on PCI && VIDEO_V4L1 && I2C
+ depends on PCI && VIDEO_V4L2 && I2C
select VIDEO_SAA7146_VV
- select VIDEO_V4L2
---help---
This is a video4linux driver for the Hexium Gemini frame
grabber card by Hexium. Please note that the Gemini Dual
@@ -320,123 +659,16 @@ config VIDEO_M32R_AR
camera module.
config VIDEO_M32R_AR_M64278
- tristate "Use Colour AR module M64278(VGA)"
- depends on VIDEO_M32R_AR && PLAT_M32700UT
- ---help---
- Say Y here to use the Renesas M64278E-800 camera module,
- which supports VGA(640x480 pixcels) size of images.
-
-#
-# Encoder / Decoder module configuration
-#
-
-menu "Encoders and Decoders"
- depends on VIDEO_DEV
-
-config VIDEO_MSP3400
- tristate "Micronas MSP34xx audio decoders"
- depends on VIDEO_DEV && I2C
- ---help---
- Support for the Micronas MSP34xx series of audio decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called msp3400.
-
-config VIDEO_CS53L32A
- tristate "Cirrus Logic CS53L32A audio ADC"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
- ---help---
- Support for the Cirrus Logic CS53L32A low voltage
- stereo A/D converter.
-
- To compile this driver as a module, choose M here: the
- module will be called cs53l32a.
-
-config VIDEO_TLV320AIC23B
- tristate "Texas Instruments TLV320AIC23B audio codec"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
- ---help---
- Support for the Texas Instruments TLV320AIC23B audio codec.
-
- To compile this driver as a module, choose M here: the
- module will be called tlv320aic23b.
-
-config VIDEO_WM8775
- tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
- ---help---
- Support for the Wolfson Microelectronics WM8775 high
- performance stereo A/D Converter with a 4 channel input mixer.
-
- To compile this driver as a module, choose M here: the
- module will be called wm8775.
-
-config VIDEO_WM8739
- tristate "Wolfson Microelectronics WM8739 stereo audio ADC"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ tristate "AR device with color module M64278(VGA)"
+ depends on PLAT_M32700UT
+ select VIDEO_M32R_AR
---help---
- Support for the Wolfson Microelectronics WM8739
- stereo A/D Converter.
+ This is a video4linux driver for the Renesas AR (Artificial
+ Retina) with M64278E-800 camera module.
+ This module supports VGA(640x480 pixels) resolutions.
To compile this driver as a module, choose M here: the
- module will be called wm8739.
-
-config VIDEO_CX2341X
- tristate "Conexant CX2341x MPEG encoders"
- depends on VIDEO_V4L2 && EXPERIMENTAL
- ---help---
- Support for the Conexant CX23416 MPEG encoders
- and CX23415 MPEG encoder/decoders.
-
- This module currently supports the encoding functions only.
-
- To compile this driver as a module, choose M here: the
- module will be called cx2341x.
-
-source "drivers/media/video/cx25840/Kconfig"
-
-config VIDEO_SAA711X
- tristate "Philips SAA7113/4/5 video decoders"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
- ---help---
- Support for the Philips SAA7113/4/5 video decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7115.
-
-config VIDEO_SAA7127
- tristate "Philips SAA7127/9 digital video encoders"
- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
- ---help---
- Support for the Philips SAA7127/9 digital video encoders.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7127.
-
-config VIDEO_UPD64031A
- tristate "NEC Electronics uPD64031A Ghost Reduction"
- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
- ---help---
- Support for the NEC Electronics uPD64031A Ghost Reduction
- video chip. It is most often found in NTSC TV cards made for
- Japan and is used to reduce the 'ghosting' effect that can
- be present in analog TV broadcasts.
-
- To compile this driver as a module, choose M here: the
- module will be called upd64031a.
-
-config VIDEO_UPD64083
- tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation"
- depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
- ---help---
- Support for the NEC Electronics uPD64083 3-Dimensional Y/C
- separation video chip. It is used to improve the quality of
- the colors of a composite signal.
-
- To compile this driver as a module, choose M here: the
- module will be called upd64083.
-
-endmenu # encoder / decoder chips
+ module will be called arv.
#
# USB Multimedia device configuration
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index e82e511f2a72..af57abce8a6e 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -17,7 +17,10 @@ ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
endif
obj-$(CONFIG_VIDEO_BT848) += bt8xx/
-obj-$(CONFIG_VIDEO_BT848) += tvaudio.o tda7432.o tda9875.o ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_BT848) += ir-kbd-i2c.o
+obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
+obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
+obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o
obj-$(CONFIG_VIDEO_ZR36120) += zoran.o
@@ -27,17 +30,32 @@ obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
obj-$(CONFIG_VIDEO_W9966) += w9966.o
-obj-$(CONFIG_VIDEO_ZORAN_BUZ) += saa7111.o saa7185.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_DC10) += saa7110.o adv7175.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_DC30) += adv7175.o vpx3220.o zr36050.o \
- zr36016.o
-obj-$(CONFIG_VIDEO_ZORAN_LML33) += bt819.o bt856.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_LML33R10) += saa7114.o adv7170.o zr36060.o
-obj-$(CONFIG_VIDEO_ZORAN_AVS6EYES) += bt866.o ks0127.o zr36060.o
+
+obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
+obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
+obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
+obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
+obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
+obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
+obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
+obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
+obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
+obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
+obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
+obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
+obj-$(CONFIG_VIDEO_BT819) += bt819.o
+obj-$(CONFIG_VIDEO_BT856) += bt856.o
+obj-$(CONFIG_VIDEO_BT866) += bt866.o
+obj-$(CONFIG_VIDEO_KS0127) += ks0127.o
+
obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o
+obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o
+obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o
+
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_PLANB) += planb.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o saa7191.o indycam.o
+obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
obj-$(CONFIG_VIDEO_CPIA) += cpia.o
obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
@@ -46,7 +64,7 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
obj-$(CONFIG_VIDEO_EM28XX) += em28xx/
-obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o
+obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o
@@ -55,10 +73,10 @@ obj-$(CONFIG_VIDEO_WM8775) += wm8775.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
-obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o
+obj-$(CONFIG_VIDEO_MXB) += mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
-obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o
+obj-$(CONFIG_VIDEO_DPC) += dpc7146.o
obj-$(CONFIG_TUNER_3036) += tuner-3036.o
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
@@ -70,8 +88,6 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o
obj-$(CONFIG_VIDEO_CX25840) += cx25840/
-obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
-obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
@@ -96,4 +112,3 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
extra-cflags-$(CONFIG_VIDEO_V4L1_COMPAT) += -DCONFIG_VIDEO_V4L1_COMPAT
-
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 5c5e682a3004..4861799eb430 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -549,7 +549,7 @@ static int ar_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
/*
* Interrupt handler
*/
-static void ar_interrupt(int irq, void *dev, struct pt_regs *regs)
+static void ar_interrupt(int irq, void *dev)
{
struct ar_device *ar = dev;
unsigned int line_count;
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 05e42bbcfc3d..772fd52d551a 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -65,7 +65,7 @@ MODULE_LICENSE("GPL");
struct bt866 {
struct i2c_client *i2c;
int addr;
- unsigned char reg[128];
+ unsigned char reg[256];
int norm;
int enable;
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index cdcf55650714..58eae887a629 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -8,7 +8,10 @@ config VIDEO_BT848
select VIDEO_IR
select VIDEO_TUNER
select VIDEO_TVEEPROM
- select VIDEO_MSP3400
+ select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TVAUDIO if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TDA7432 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TDA9875 if VIDEO_HELPER_CHIPS_AUTO
---help---
Support for BT848 based frame grabber/overlay boards. This includes
the Miro, Hauppauge and STB boards. Please read the material in
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index de14818d5cc4..a84903e0d810 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -2000,7 +2000,7 @@ struct tvcard bttv_tvcards[] = {
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
- .muxsel = { 3, 0, 1, 2 },
+ .muxsel = { 3, 1 },
.pll = PLL_28,
.no_gpioirq = 1,
.has_dvb = 1,
@@ -4991,7 +4991,7 @@ void __devinit bttv_check_chipset(void)
int pcipci_fail = 0;
struct pci_dev *dev = NULL;
- if (pci_pci_problems & PCIPCI_FAIL)
+ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) /* should check if target is AGP */
pcipci_fail = 1;
if (pci_pci_problems & (PCIPCI_TRITON|PCIPCI_NATOMA|PCIPCI_VIAETBF))
triton1 = 1;
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 20dff7c316eb..6e1ddad9f0c1 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2431,6 +2431,14 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file,
fbuf->bytesperline = btv->fbuf.fmt.bytesperline;
if (fh->ovfmt)
fbuf->depth = fh->ovfmt->depth;
+ else {
+ if (fbuf->width)
+ fbuf->depth = ((fbuf->bytesperline<<3)
+ + (fbuf->width-1) )
+ /fbuf->width;
+ else
+ fbuf->depth = 0;
+ }
return 0;
}
case VIDIOCSFBUF:
@@ -3745,7 +3753,7 @@ bttv_irq_switch_vbi(struct bttv *btv)
spin_unlock(&btv->s_lock);
}
-static irqreturn_t bttv_irq(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t bttv_irq(int irq, void *dev_id)
{
u32 stat,astat;
u32 dstat;
@@ -4186,6 +4194,7 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
return;
}
+#ifdef CONFIG_PM
static int bttv_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
struct bttv *btv = pci_get_drvdata(pci_dev);
@@ -4266,6 +4275,7 @@ static int bttv_resume(struct pci_dev *pci_dev)
spin_unlock_irqrestore(&btv->s_lock,flags);
return 0;
}
+#endif
static struct pci_device_id bttv_pci_tbl[] = {
{PCI_VENDOR_ID_BROOKTREE, PCI_DEVICE_ID_BT848,
@@ -4286,8 +4296,10 @@ static struct pci_driver bttv_pci_driver = {
.id_table = bttv_pci_tbl,
.probe = bttv_probe,
.remove = __devexit_p(bttv_remove),
+#ifdef CONFIG_PM
.suspend = bttv_suspend,
.resume = bttv_resume,
+#endif
};
static int bttv_init_module(void)
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 4b562b386fcf..70de6c96e201 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -8,6 +8,9 @@
& Marcus Metzler (mocm@thp.uni-koeln.de)
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+ (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+ - Multituner support and i2c address binding
+
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
@@ -45,10 +48,18 @@ static int i2c_debug;
static int i2c_hw;
static int i2c_scan;
module_param(i2c_debug, int, 0644);
+MODULE_PARM_DESC(i2c_hw,"configure i2c debug level");
module_param(i2c_hw, int, 0444);
+MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, "
+ "instead of software bitbang");
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+static unsigned int i2c_udelay = 5;
+module_param(i2c_udelay, int, 0444);
+MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs "
+ "(should be 5 or higher). Lower value means higher bus speed.");
+
/* ----------------------------------------------------------------------- */
/* I2C functions - bitbanging adapter (software i2c) */
@@ -100,7 +111,6 @@ static struct i2c_algo_bit_data bttv_i2c_algo_bit_template = {
.getsda = bttv_bit_getsda,
.getscl = bttv_bit_getscl,
.udelay = 16,
- .mdelay = 10,
.timeout = 200,
};
@@ -426,6 +436,11 @@ int __devinit init_bttv_i2c(struct bttv *btv)
sizeof(bttv_i2c_adap_hw_template));
} else {
/* bt848 */
+ /* Prevents usage of invalid delay values */
+ if (i2c_udelay<5)
+ i2c_udelay=5;
+ bttv_i2c_algo_bit_template.udelay=i2c_udelay;
+
memcpy(&btv->c.i2c_adap, &bttv_i2c_adap_sw_template,
sizeof(bttv_i2c_adap_sw_template));
memcpy(&btv->i2c_algo, &bttv_i2c_algo_bit_template,
diff --git a/drivers/media/video/compat_ioctl32.c b/drivers/media/video/compat_ioctl32.c
index b69ee1194815..d82a488f12a6 100644
--- a/drivers/media/video/compat_ioctl32.c
+++ b/drivers/media/video/compat_ioctl32.c
@@ -58,6 +58,7 @@ static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user
return 0;
}
+
struct video_buffer32 {
compat_caddr_t base;
compat_int_t height, width, depth, bytesperline;
@@ -618,6 +619,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
struct video_buffer vb;
struct video_window vw;
struct video_code vc;
+ struct video_audio va;
#endif
struct v4l2_format v2f;
struct v4l2_buffer v2b;
@@ -635,31 +637,31 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
/* First, convert the command. */
switch(cmd) {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
- case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
- case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
- case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
- case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
- case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
- case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
- case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
+ case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break;
+ case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break;
+ case VIDIOCGWIN32: realcmd = cmd = VIDIOCGWIN; break;
+ case VIDIOCGFBUF32: realcmd = cmd = VIDIOCGFBUF; break;
+ case VIDIOCSFBUF32: realcmd = cmd = VIDIOCSFBUF; break;
+ case VIDIOCGFREQ32: realcmd = cmd = VIDIOCGFREQ; break;
+ case VIDIOCSFREQ32: realcmd = cmd = VIDIOCSFREQ; break;
+ case VIDIOCSMICROCODE32: realcmd = cmd = VIDIOCSMICROCODE; break;
#endif
- case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
- case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
- case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
- case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
- case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
- case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
- case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
- case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
- case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
- case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
+ case VIDIOC_G_FMT32: realcmd = cmd = VIDIOC_G_FMT; break;
+ case VIDIOC_S_FMT32: realcmd = cmd = VIDIOC_S_FMT; break;
+ case VIDIOC_QUERYBUF32: realcmd = cmd = VIDIOC_QUERYBUF; break;
+ case VIDIOC_QBUF32: realcmd = cmd = VIDIOC_QBUF; break;
+ case VIDIOC_DQBUF32: realcmd = cmd = VIDIOC_DQBUF; break;
+ case VIDIOC_STREAMON32: realcmd = cmd = VIDIOC_STREAMON; break;
+ case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
+ case VIDIOC_G_FBUF32: realcmd = cmd = VIDIOC_G_FBUF; break;
+ case VIDIOC_S_FBUF32: realcmd = cmd = VIDIOC_S_FBUF; break;
+ case VIDIOC_OVERLAY32: realcmd = cmd = VIDIOC_OVERLAY; break;
case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break;
- case VIDIOC_S_CTRL32: cmd = VIDIOC_S_CTRL; break;
- case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
- case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
- case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
+ case VIDIOC_S_CTRL32: realcmd = cmd = VIDIOC_S_CTRL; break;
+ case VIDIOC_G_INPUT32: realcmd = cmd = VIDIOC_G_INPUT; break;
+ case VIDIOC_S_INPUT32: realcmd = cmd = VIDIOC_S_INPUT; break;
+ case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break;
};
switch(cmd) {
@@ -676,6 +678,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
compatible_arg = 0;
break;
+
case VIDIOCSFREQ:
#endif
case VIDIOC_S_INPUT:
@@ -683,7 +686,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
err = get_user(karg.vx, (u32 __user *)up);
- compatible_arg = 0;
+ compatible_arg = 1;
break;
case VIDIOC_S_FBUF:
@@ -739,6 +742,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOC_G_FBUF:
case VIDIOC_G_INPUT:
compatible_arg = 0;
+ break;
#ifdef CONFIG_VIDEO_V4L1_COMPAT
case VIDIOCSMICROCODE:
err = microcode32(&karg.vc, up);
@@ -755,7 +759,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
- err = native_ioctl(file, realcmd, (unsigned long)&karg);
+ err = native_ioctl(file, realcmd, (unsigned long) &karg);
set_fs(old_fs);
}
if(err == 0) {
@@ -772,6 +776,7 @@ static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case VIDIOCGFBUF:
err = put_video_buffer32(&karg.vb, up);
break;
+
#endif
case VIDIOC_G_FBUF:
err = put_v4l2_framebuffer32(&karg.v2fb, up);
@@ -841,10 +846,14 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOCSFBUF32:
case VIDIOCGFREQ32:
case VIDIOCSFREQ32:
+ case VIDIOCGAUDIO:
+ case VIDIOCSAUDIO:
#endif
case VIDIOC_QUERYCAP:
case VIDIOC_ENUM_FMT:
case VIDIOC_G_FMT32:
+ case VIDIOC_CROPCAP:
+ case VIDIOC_S_CROP:
case VIDIOC_S_FMT32:
case VIDIOC_REQBUFS:
case VIDIOC_QUERYBUF32:
@@ -882,8 +891,6 @@ long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
case VIDIOCSPICT:
case VIDIOCCAPTURE:
case VIDIOCKEY:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
case VIDIOCSYNC:
case VIDIOCMCAPTURE:
case VIDIOCGMBUF:
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index c5ecb2be5f93..8d2dfc128821 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -50,10 +50,6 @@
/***
* Image defines
***/
-#ifndef true
-#define true 1
-#define false 0
-#endif
/* Misc constants */
#define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index f4da02941493..28dc6a1a1e43 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -49,7 +49,7 @@ static int frame_sizes[] = {
#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt]
static void process_frame(struct camera_data *cam);
-static void cpia2_usb_complete(struct urb *urb, struct pt_regs *);
+static void cpia2_usb_complete(struct urb *urb);
static int cpia2_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static void cpia2_usb_disconnect(struct usb_interface *intf);
@@ -199,7 +199,7 @@ static void add_COM(struct camera_data *cam)
*
* callback when incoming packet is received
*****************************************************************************/
-static void cpia2_usb_complete(struct urb *urb, struct pt_regs *regs)
+static void cpia2_usb_complete(struct urb *urb)
{
int i;
unsigned char *cdata;
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 2ee34a3b9280..9da4726eb9b9 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -109,7 +109,7 @@ static struct cpia_camera_ops cpia_usb_ops = {
static LIST_HEAD(cam_list);
static spinlock_t cam_list_lock_usb;
-static void cpia_usb_complete(struct urb *urb, struct pt_regs *regs)
+static void cpia_usb_complete(struct urb *urb)
{
int i;
char *cdata;
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 65f00fc08fa9..657e0b969145 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -691,7 +691,7 @@ void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p)
.video_luma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR,
.video_chroma_spatial_filter_type = V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
.video_temporal_filter_mode = V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
- .video_temporal_filter = 0,
+ .video_temporal_filter = 8,
.video_median_filter_type = V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
.video_luma_median_filter_top = 255,
.video_luma_median_filter_bottom = 0,
@@ -731,6 +731,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
};
int err = 0;
+ u16 temporal = new->video_temporal_filter;
cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0);
@@ -741,6 +742,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
if (old == NULL || old->width != new->width || old->height != new->height ||
old->video_encoding != new->video_encoding) {
+ int is_scaling;
u16 w = new->width;
u16 h = new->height;
@@ -750,6 +752,20 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
}
err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
if (err) return err;
+
+ /* Adjust temporal filter if necessary. The problem with the temporal
+ filter is that it works well with full resolution capturing, but
+ not when the capture window is scaled (the filter introduces
+ a ghosting effect). So if the capture window changed, and there is
+ no updated filter value, then the filter is set depending on whether
+ the new window is full resolution or not.
+
+ For full resolution a setting of 8 really improves the video
+ quality, especially if the original video quality is suboptimal. */
+ is_scaling = new->width != 720 || new->height != (new->is_50hz ? 576 : 480);
+ if (old && old->video_temporal_filter == temporal) {
+ temporal = is_scaling ? 0 : 8;
+ }
}
if (old == NULL || old->stream_type != new->stream_type) {
@@ -815,9 +831,9 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
}
if (old == NULL ||
old->video_spatial_filter != new->video_spatial_filter ||
- old->video_temporal_filter != new->video_temporal_filter) {
+ old->video_temporal_filter != temporal) {
err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
- new->video_spatial_filter, new->video_temporal_filter);
+ new->video_spatial_filter, temporal);
if (err) return err;
}
if (old == NULL || old->video_temporal_decimation != new->video_temporal_decimation) {
@@ -855,6 +871,9 @@ void cx2341x_log_status(struct cx2341x_mpeg_params *p, const char *prefix)
printk(KERN_INFO "%s: Stream: %s\n",
prefix,
cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE));
+ printk(KERN_INFO "%s: VBI Format: %s\n",
+ prefix,
+ cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT));
/* Video */
printk(KERN_INFO "%s: Video: %dx%d, %d fps\n",
diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig
index 854264e42ec0..7cf29a03ed63 100644
--- a/drivers/media/video/cx25840/Kconfig
+++ b/drivers/media/video/cx25840/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_CX25840
tristate "Conexant CX2584x audio/video decoders"
- depends on VIDEO_DEV && I2C && EXPERIMENTAL
+ depends on VIDEO_V4L2 && I2C && EXPERIMENTAL
select FW_LOADER
---help---
Support for the Conexant CX2584x audio/video decoders.
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 6cc8bf215e85..f85f2084324f 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -111,6 +111,10 @@ void cx25840_vbi_setup(struct i2c_client *client)
uv_lpf=0;
comb=0;
sc=0x0a425f;
+ } else if (std == V4L2_STD_PAL_Nc) {
+ uv_lpf=1;
+ comb=0x20;
+ sc=556453;
} else {
uv_lpf=1;
comb=0x20;
@@ -231,6 +235,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
0, 0, 0, 0
};
+ int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
int i;
fmt = arg;
@@ -242,13 +247,25 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
if ((cx25840_read(client, 0x404) & 0x10) == 0)
break;
- for (i = 7; i <= 23; i++) {
- u8 v = cx25840_read(client, 0x424 + i - 7);
+ if (is_pal) {
+ for (i = 7; i <= 23; i++) {
+ u8 v = cx25840_read(client, 0x424 + i - 7);
- svbi->service_lines[0][i] = lcr2vbi[v >> 4];
- svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
- svbi->service_set |=
- svbi->service_lines[0][i] | svbi->service_lines[1][i];
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |=
+ svbi->service_lines[0][i] | svbi->service_lines[1][i];
+ }
+ }
+ else {
+ for (i = 10; i <= 21; i++) {
+ u8 v = cx25840_read(client, 0x424 + i - 10);
+
+ svbi->service_lines[0][i] = lcr2vbi[v >> 4];
+ svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
+ svbi->service_set |=
+ svbi->service_lines[0][i] | svbi->service_lines[1][i];
+ }
}
break;
}
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 7a94e6a11927..0f9d96963618 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -1,7 +1,3 @@
-config VIDEO_CX88_VP3054
- tristate
- depends on VIDEO_CX88_DVB && DVB_MT352
-
config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
depends on VIDEO_DEV && PCI && I2C
@@ -52,6 +48,14 @@ config VIDEO_CX88_DVB
depends on VIDEO_CX88 && DVB_CORE
select VIDEO_BUF_DVB
select DVB_PLL
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_OR51132 if !DVB_FE_CUSTOMISE
+ select DVB_CX22702 if !DVB_FE_CUSTOMISE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_NXT200X if !DVB_FE_CUSTOMISE
+ select DVB_CX24123 if !DVB_FE_CUSTOMISE
+ select DVB_ISL6421 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
Conexant 2388x chip.
@@ -59,101 +63,12 @@ config VIDEO_CX88_DVB
To compile this driver as a module, choose M here: the
module will be called cx88-dvb.
- You must also select one or more DVB/ATSC demodulators.
- If you are unsure which you need, choose all of them.
-
-config VIDEO_CX88_DVB_ALL_FRONTENDS
- bool "Build all supported frontends for cx2388x based TV cards"
- default y
- depends on VIDEO_CX88_DVB
- select DVB_MT352
- select VIDEO_CX88_VP3054
- select DVB_ZL10353
- select DVB_OR51132
- select DVB_CX22702
- select DVB_LGDT330X
- select DVB_NXT200X
- select DVB_CX24123
- select DVB_ISL6421
- ---help---
- This builds cx88-dvb with all currently supported frontend
- demodulators. If you wish to tweak your configuration, and
- only include support for the hardware that you need, choose N here.
-
- If you are unsure, choose Y.
-
-config VIDEO_CX88_DVB_MT352
- bool "Zarlink MT352 DVB-T Support"
- default y
- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
- select DVB_MT352
- ---help---
- This adds DVB-T support for cards based on the
- Connexant 2388x chip and the MT352 demodulator.
-
-config VIDEO_CX88_DVB_VP3054
- bool "VP-3054 Secondary I2C Bus Support"
- default y
- depends on VIDEO_CX88_DVB_MT352
- select VIDEO_CX88_VP3054
+config VIDEO_CX88_VP3054
+ tristate "VP-3054 Secondary I2C Bus Support"
+ default m
+ depends on VIDEO_CX88_DVB && DVB_MT352
---help---
This adds DVB-T support for cards based on the
- Connexant 2388x chip and the MT352 demodulator,
+ Conexant 2388x chip and the MT352 demodulator,
which also require support for the VP-3054
Secondary I2C bus, such at DNTV Live! DVB-T Pro.
-
-config VIDEO_CX88_DVB_ZL10353
- bool "Zarlink ZL10353 DVB-T Support"
- default y
- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
- select DVB_ZL10353
- ---help---
- This adds DVB-T support for cards based on the
- Connexant 2388x chip and the ZL10353 demodulator,
- successor to the Zarlink MT352.
-
-config VIDEO_CX88_DVB_OR51132
- bool "OR51132 ATSC Support"
- default y
- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
- select DVB_OR51132
- ---help---
- This adds ATSC 8VSB and QAM64/256 support for cards based on the
- Connexant 2388x chip and the OR51132 demodulator.
-
-config VIDEO_CX88_DVB_CX22702
- bool "Conexant CX22702 DVB-T Support"
- default y
- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
- select DVB_CX22702
- ---help---
- This adds DVB-T support for cards based on the
- Connexant 2388x chip and the CX22702 demodulator.
-
-config VIDEO_CX88_DVB_LGDT330X
- bool "LG Electronics DT3302/DT3303 ATSC Support"
- default y
- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
- select DVB_LGDT330X
- ---help---
- This adds ATSC 8VSB and QAM64/256 support for cards based on the
- Connexant 2388x chip and the LGDT3302/LGDT3303 demodulator.
-
-config VIDEO_CX88_DVB_NXT200X
- bool "NXT2002/NXT2004 ATSC Support"
- default y
- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
- select DVB_NXT200X
- ---help---
- This adds ATSC 8VSB and QAM64/256 support for cards based on the
- Connexant 2388x chip and the NXT2002/NXT2004 demodulator.
-
-config VIDEO_CX88_DVB_CX24123
- bool "Conexant CX24123 DVB-S Support"
- default y
- depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS
- select DVB_CX24123
- select DVB_ISL6421
- ---help---
- This adds DVB-S support for cards based on the
- Connexant 2388x chip and the CX24123 demodulator.
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile
index 352b919f30c4..639c3b659d0e 100644
--- a/drivers/media/video/cx88/Makefile
+++ b/drivers/media/video/cx88/Makefile
@@ -14,13 +14,6 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-extra-cflags-$(CONFIG_DVB_CX22702) += -DHAVE_CX22702=1
-extra-cflags-$(CONFIG_DVB_OR51132) += -DHAVE_OR51132=1
-extra-cflags-$(CONFIG_DVB_LGDT330X) += -DHAVE_LGDT330X=1
-extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1
-extra-cflags-$(CONFIG_DVB_ZL10353) += -DHAVE_ZL10353=1
-extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1
-extra-cflags-$(CONFIG_DVB_CX24123) += -DHAVE_CX24123=1
extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1
EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index f0340662e078..e4355fdc3b6d 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -262,7 +262,7 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip)
/*
* BOARD Specific: Handles IRQ calls
*/
-static irqreturn_t cx8801_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cx8801_irq(int irq, void *dev_id)
{
snd_cx88_card_t *chip = dev_id;
struct cx88_core *core = chip->core;
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index b60177f173c3..46738321adaf 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -896,7 +896,7 @@ static int mpeg_do_ioctl(struct inode *inode, struct file *file,
snprintf(name, sizeof(name), "%s/2", core->name);
printk("%s/2: ============ START LOG STATUS ============\n",
core->name);
- cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, 0);
+ cx88_call_i2c_clients(core, VIDIOC_LOG_STATUS, NULL);
cx2341x_log_status(&dev->params, name);
printk("%s/2: ============= END LOG STATUS =============\n",
core->name);
@@ -1086,7 +1086,7 @@ static int __devinit blackbird_probe(struct pci_dev *pci_dev,
return -EINVAL;
err = -ENODEV;
- if (!cx88_boards[core->board].blackbird)
+ if (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))
goto fail_core;
err = -ENOMEM;
@@ -1160,8 +1160,10 @@ static struct pci_driver blackbird_pci_driver = {
.id_table = cx8802_pci_tbl,
.probe = blackbird_probe,
.remove = __devexit_p(blackbird_remove),
+#ifdef CONFIG_PM
.suspend = cx8802_suspend_common,
.resume = cx8802_resume_common,
+#endif
};
static int blackbird_init(void)
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 14bd4863d157..f764a57c56be 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -294,7 +294,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_RADIO,
.gpio0 = 0x0000bd62,
},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_IODATA_GVVCP3PCI] = {
.name = "IODATA GV-VCP3/PCI",
@@ -358,7 +358,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_RADIO,
.gpio0 = 0x0000fde2,
},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_MSI_TVANYWHERE] = {
.name = "MSI TV-@nywhere",
@@ -401,7 +401,7 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x0700,
.gpio2 = 0x0101,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
.name = "DViCO FusionHDTV DVB-T1",
@@ -418,7 +418,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x000027df,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_LTV883] = {
.name = "KWorld LTV883RF",
@@ -488,7 +488,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x0f00,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
.name = "Hauppauge Nova-T DVB-T",
@@ -500,7 +500,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_DVB,
.vmux = 0,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_CONEXANT_DVB_T1] = {
.name = "Conexant DVB-T reference design",
@@ -512,7 +512,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_DVB,
.vmux = 0,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PROVIDEO_PV259] = {
.name = "Provideo PV259",
@@ -524,7 +524,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
}},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
.name = "DViCO FusionHDTV DVB-T Plus",
@@ -541,7 +541,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x000027df,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DNTV_LIVE_DVB_T] = {
.name = "digitalnow DNTV Live! DVB-T",
@@ -560,7 +560,7 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x00000700,
.gpio2 = 0x00000101,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PCHDTV_HD3000] = {
.name = "pcHDTV HD3000 HDTV",
@@ -599,7 +599,7 @@ struct cx88_board cx88_boards[] = {
.gpio2 = 0x00000000,
.gpio3 = 0x00000000,
},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_ROSLYN] = {
// entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>
@@ -633,7 +633,7 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0xed96,
.gpio2 = 0x00ff,
},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_DIGITALLOGIC_MEC] = {
.name = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
@@ -659,7 +659,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_RADIO,
.gpio0 = 0x00009d00,
},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_IODATA_GVBCTV7E] = {
.name = "IODATA GV/BCTV7E",
@@ -727,7 +727,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x97e9,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_ADSTECH_DVB_T_PCI] = {
.name = "ADS Tech Instant TV DVB-T PCI",
@@ -746,7 +746,7 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x0700,
.gpio2 = 0x0101,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
.name = "TerraTec Cinergy 1400 DVB-T",
@@ -755,7 +755,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_DVB,
.vmux = 0,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD] = {
.name = "DViCO FusionHDTV 5 Gold",
@@ -777,7 +777,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x87f9,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_AVERMEDIA_ULTRATV_MC_550] = {
.name = "AverMedia UltraTV Media Center PCI 550",
@@ -786,7 +786,7 @@ struct cx88_board cx88_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 0,
@@ -854,7 +854,7 @@ struct cx88_board cx88_boards[] = {
.gpio2 = 0x00000001,
.gpio3 = 0x00000000,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_WINFAST_DTV1000] = {
.name = "WinFast DTV1000-T",
@@ -866,7 +866,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_DVB,
.vmux = 0,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_AVERTV_303] = {
.name = "AVerTV 303 (M126)",
@@ -914,7 +914,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
.name = "Hauppauge Nova-SE2 DVB-S",
@@ -926,7 +926,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_DVB,
.vmux = 0,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_DVBS_100] = {
.name = "KWorld DVB-S 100",
@@ -944,7 +944,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_HVR1100] = {
.name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid",
@@ -964,7 +964,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
}},
/* fixme: Add radio support */
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
.name = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
@@ -981,7 +981,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 1,
}},
/* fixme: Add radio support */
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DNTV_LIVE_DVB_T_PRO] = {
.name = "digitalnow DNTV Live! DVB-T Pro",
@@ -1008,7 +1008,7 @@ struct cx88_board cx88_boards[] = {
.type = CX88_RADIO,
.gpio0 = 0xf80808,
},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_DVB_T_CX22702] = {
/* Kworld V-stream Xpert DVB-T with Thomson tuner */
@@ -1030,7 +1030,7 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x0700,
.gpio2 = 0x0101,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
.name = "DViCO FusionHDTV DVB-T Dual Digital",
@@ -1041,13 +1041,13 @@ struct cx88_board cx88_boards[] = {
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- .gpio0 = 0x000027df,
+ .gpio0 = 0x000067df,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- .gpio0 = 0x000027df,
+ .gpio0 = 0x000067df,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = {
/* FIXME: Audio not working for s-video / composite inputs. */
@@ -1075,7 +1075,7 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x3de6,
.gpio2 = 0x00ff,
},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = {
.name = "DViCO FusionHDTV DVB-T Hybrid",
@@ -1096,7 +1096,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x0000a75b,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_PCHDTV_HD5500] = {
.name = "pcHDTV HD5500 HDTV",
@@ -1118,7 +1118,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x87f9,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_KWORLD_MCE200_DELUXE] = {
/* FIXME: tested TV input only, disabled composite,
@@ -1134,7 +1134,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 0,
.gpio0 = 0x0000BDE6
}},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_PIXELVIEW_PLAYTV_P7000] = {
/* FIXME: SVideo, Composite and FM inputs are untested */
@@ -1150,7 +1150,7 @@ struct cx88_board cx88_boards[] = {
.vmux = 0,
.gpio0 = 0x5da6,
}},
- .blackbird = 1,
+ .mpeg = CX88_MPEG_BLACKBIRD,
},
[CX88_BOARD_NPGTECH_REALTV_TOP10FM] = {
.name = "NPG Tech Real TV FM Top 10",
@@ -1192,7 +1192,7 @@ struct cx88_board cx88_boards[] = {
.gpio2 = 0x00017304,
.gpio3 = 0x02000000,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
},
[CX88_BOARD_GENIATECH_DVBS] = {
.name = "Geniatech DVB-S",
@@ -1207,7 +1207,103 @@ struct cx88_board cx88_boards[] = {
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
}},
- .dvb = 1,
+ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_HAUPPAUGE_HVR3000] = {
+ /* FIXME: Add dvb & radio support */
+ .name = "Hauppauge WinTV-HVR3000 TriMode Analog/DVB-S/DVB-T",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x84bf,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x84bf,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x84bf,
+ }},
+ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_NORWOOD_MICRO] = {
+ .name = "Norwood Micro TV Tuner",
+ .tuner_type = TUNER_TNF_5335MF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0709,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x070b,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x070b,
+ }},
+ },
+ [CX88_BOARD_TE_DTV_250_OEM_SWANN] = {
+ .name = "Shenzhen Tungsten Ages Tech TE-DTV-250 / Swann OEM",
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x003fffff,
+ .gpio1 = 0x00e00000,
+ .gpio2 = 0x003fffff,
+ .gpio3 = 0x02000000,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x003fffff,
+ .gpio1 = 0x00e00000,
+ .gpio2 = 0x003fffff,
+ .gpio3 = 0x02000000,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x003fffff,
+ .gpio1 = 0x00e00000,
+ .gpio2 = 0x003fffff,
+ .gpio3 = 0x02000000,
+ }},
+ },
+ [CX88_BOARD_HAUPPAUGE_HVR1300] = {
+ .name = "Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder",
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .audio_chip = AUDIO_CHIP_WM8775,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xe780,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xe780,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xe780,
+ }},
+ /* fixme: Add radio support */
+ .mpeg = CX88_MPEG_DVB,
},
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -1254,7 +1350,7 @@ struct cx88_subid cx88_subids[] = {
.card = CX88_BOARD_LEADTEK_PVR2000,
},{
.subvendor = 0x107d,
- .subdevice = 0x663C,
+ .subdevice = 0x663c,
.card = CX88_BOARD_LEADTEK_PVR2000,
},{
.subvendor = 0x1461,
@@ -1458,6 +1554,55 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x14f1,
.subdevice = 0x0084,
.card = CX88_BOARD_GENIATECH_DVBS,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x1404,
+ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
+ },{
+ .subvendor = 0x1461,
+ .subdevice = 0xc111, /* AverMedia M150-D */
+ /* This board is known to work with the ASUS PVR416 config */
+ .card = CX88_BOARD_ASUS_PVR_416,
+ },{
+ .subvendor = 0xc180,
+ .subdevice = 0xc980,
+ .card = CX88_BOARD_TE_DTV_250_OEM_SWANN,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9600,
+ .card = CX88_BOARD_HAUPPAUGE_HVR1300,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9601,
+ .card = CX88_BOARD_HAUPPAUGE_HVR1300,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9602,
+ .card = CX88_BOARD_HAUPPAUGE_HVR1300,
+ },{
+ .subvendor = 0x107d,
+ .subdevice = 0x6632,
+ .card = CX88_BOARD_LEADTEK_PVR2000,
+ },{
+ .subvendor = 0x12ab,
+ .subdevice = 0x2300, /* Club3D Zap TV2100 */
+ .card = CX88_BOARD_KWORLD_DVB_T_CX22702,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x9000,
+ .card = CX88_BOARD_HAUPPAUGE_DVB_T1,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x1400,
+ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x1401,
+ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
+ },{
+ .subvendor = 0x0070,
+ .subdevice = 0x1402,
+ .card = CX88_BOARD_HAUPPAUGE_HVR3000,
},
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -1501,6 +1646,15 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
/* Make sure we support the board model */
switch (tv.model)
{
+ case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */
+ case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */
+ case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */
+ case 14109: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - low profile) */
+ case 14129: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge - LP) */
+ case 14559: /* WinTV-HVR3000 (OEM, no IR, b/panel video, 3.5mm audio in) */
+ case 14569: /* WinTV-HVR3000 (OEM, no IR, no back panel video) */
+ case 14659: /* WinTV-HVR3000 (OEM, no IR, b/panel video, RCA audio in - Low profile) */
+ case 14669: /* WinTV-HVR3000 (OEM, no IR, no b/panel video - Low profile) */
case 28552: /* WinTV-PVR 'Roslyn' (No IR) */
case 34519: /* WinTV-PCI-FM */
case 90002: /* Nova-T-PCI (9002) */
@@ -1512,6 +1666,11 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
case 92000: /* Nova-SE2 (OEM, No Video or IR) */
case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
+ case 96009: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX) */
+ case 96019: /* WinTV-HVR1300 (PAL Video, MPEG Video and IR RX/TX) */
+ case 96559: /* WinTV-HVR1300 (PAL Video, MPEG Video no IR) */
+ case 96569: /* WinTV-HVR1300 () */
+ case 96659: /* WinTV-HVR1300 () */
case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
/* known */
break;
@@ -1638,6 +1797,22 @@ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
core->name, i, cx88_boards[i].name);
}
+void cx88_card_setup_pre_i2c(struct cx88_core *core)
+{
+ switch (core->board) {
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ /* Bring the 702 demod up before i2c scanning/attach or devices are hidden */
+ /* We leave here with the 702 on the bus */
+ cx_write(MO_GP0_IO, 0x0000e780);
+ udelay(1000);
+ cx_clear(MO_GP0_IO, 0x00000080);
+ udelay(50);
+ cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
+ udelay(1000);
+ break;
+ }
+}
+
void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[256];
@@ -1666,6 +1841,8 @@ void cx88_card_setup(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_DVB_T1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
if (0 == core->i2c_rc)
hauppauge_eeprom(core,eeprom);
break;
@@ -1673,9 +1850,15 @@ void cx88_card_setup(struct cx88_core *core)
cx_write(MO_GP0_IO, 0x000007f8);
cx_write(MO_GP1_IO, 0x00000001);
break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
+ /* GPIO0:6 is hooked to FX2 reset pin */
+ cx_set(MO_GP0_IO, 0x00004040);
+ cx_clear(MO_GP0_IO, 0x00000040);
+ msleep(1000);
+ cx_set(MO_GP0_IO, 0x00004040);
+ /* FALLTHROUGH */
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
- case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
/* GPIO0:0 is hooked to mt352 reset pin */
cx_set(MO_GP0_IO, 0x00000101);
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 973d3f39b2d5..4b655f2ef278 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -105,7 +105,7 @@ static u32* cx88_risc_field(u32 *rp, struct scatterlist *sglist,
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
offset+=bpl;
} else {
- /* scanline needs to be splitted */
+ /* scanline needs to be split */
todo = bpl;
*(rp++)=cpu_to_le32(RISC_WRITE|RISC_SOL|
(sg_dma_len(sg)-offset));
@@ -658,13 +658,6 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
}
-static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
-{
- return (norm->id & V4L2_STD_625_50)
- ? HLNotchFilter135PAL
- : HLNotchFilter135NTSC;
-}
-
static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
{
/* Should always be Line Draw Time / (4*FSC) */
@@ -792,6 +785,11 @@ int cx88_start_audio_dma(struct cx88_core *core)
{
/* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */
int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4;
+
+ /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+ if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+ return 0;
+
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0);
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0);
@@ -801,11 +799,16 @@ int cx88_start_audio_dma(struct cx88_core *core)
/* start dma */
cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */
+
return 0;
}
int cx88_stop_audio_dma(struct cx88_core *core)
{
+ /* If downstream RISC is enabled, bail out; ALSA is managing DMA */
+ if (cx_read(MO_AUD_DMACNTRL) & 0x10)
+ return 0;
+
/* stop dma */
cx_write(MO_AUD_DMACNTRL, 0x0000);
@@ -927,7 +930,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
// htotal
tmp64 = norm_htotal(norm) * (u64)vdec_clock;
do_div(tmp64, fsc8);
- htotal = (u32)tmp64 | (norm_notchfilter(norm) << 11);
+ htotal = (u32)tmp64 | (HLNotchFilter4xFsc << 11);
dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n",
htotal, cx_read(MO_HTOTAL), (u32)tmp64);
cx_write(MO_HTOTAL, htotal);
@@ -1123,6 +1126,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
/* init hardware */
cx88_reset(core);
+ cx88_card_setup_pre_i2c(core);
cx88_i2c_init(core,pci);
cx88_call_i2c_clients (core, TUNER_SET_STANDBY, NULL);
cx88_card_setup(core);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index afde3789d702..0ef13e7efa2e 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -33,32 +33,18 @@
#include "dvb-pll.h"
#include <media/v4l2-common.h>
-#ifdef HAVE_MT352
-# include "mt352.h"
-# include "mt352_priv.h"
-# ifdef HAVE_VP3054_I2C
-# include "cx88-vp3054-i2c.h"
-# endif
-#endif
-#ifdef HAVE_ZL10353
-# include "zl10353.h"
-#endif
-#ifdef HAVE_CX22702
-# include "cx22702.h"
-#endif
-#ifdef HAVE_OR51132
-# include "or51132.h"
-#endif
-#ifdef HAVE_LGDT330X
-# include "lgdt330x.h"
-# include "lg_h06xf.h"
-#endif
-#ifdef HAVE_NXT200X
-# include "nxt200x.h"
-#endif
-#ifdef HAVE_CX24123
-# include "cx24123.h"
+#include "mt352.h"
+#include "mt352_priv.h"
+#ifdef HAVE_VP3054_I2C
+# include "cx88-vp3054-i2c.h"
#endif
+#include "zl10353.h"
+#include "cx22702.h"
+#include "or51132.h"
+#include "lgdt330x.h"
+#include "lg_h06xf.h"
+#include "nxt200x.h"
+#include "cx24123.h"
#include "isl6421.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
@@ -114,8 +100,6 @@ static struct videobuf_queue_ops dvb_qops = {
};
/* ------------------------------------------------------------------ */
-
-#ifdef HAVE_MT352
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
@@ -181,7 +165,7 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
}
static struct mt352_config dvico_fusionhdtv = {
- .demod_address = 0x0F,
+ .demod_address = 0x0f,
.demod_init = dvico_fusionhdtv_demod_init,
};
@@ -191,7 +175,7 @@ static struct mt352_config dntv_live_dvbt_config = {
};
static struct mt352_config dvico_fusionhdtv_dual = {
- .demod_address = 0x0F,
+ .demod_address = 0x0f,
.demod_init = dvico_dual_demod_init,
};
@@ -266,8 +250,8 @@ static int dntv_live_dvbt_pro_tuner_set_params(struct dvb_frontend* fe,
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, dev->core->pll_addr, buf[0], err);
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, dev->core->pll_addr, buf[0], err);
if (err < 0)
return err;
else
@@ -283,9 +267,7 @@ static struct mt352_config dntv_live_dvbt_pro_config = {
.demod_init = dntv_live_dvbt_pro_demod_init,
};
#endif
-#endif
-#ifdef HAVE_ZL10353
static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
@@ -304,8 +286,8 @@ static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, pllbuf[0], pllbuf[1], err);
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, pllbuf[0], pllbuf[1], err);
if (err < 0)
return err;
else
@@ -316,16 +298,14 @@ static int dvico_hybrid_tuner_set_params(struct dvb_frontend *fe,
}
static struct zl10353_config dvico_fusionhdtv_hybrid = {
- .demod_address = 0x0F,
+ .demod_address = 0x0f,
.no_tuner = 1,
};
static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
- .demod_address = 0x0F,
+ .demod_address = 0x0f,
};
-#endif
-#ifdef HAVE_CX22702
static struct cx22702_config connexant_refboard_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
@@ -335,13 +315,22 @@ static struct cx22702_config hauppauge_novat_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
};
+
static struct cx22702_config hauppauge_hvr1100_config = {
.demod_address = 0x63,
.output_mode = CX22702_SERIAL_OUTPUT,
};
-#endif
-#ifdef HAVE_OR51132
+static struct cx22702_config hauppauge_hvr1300_config = {
+ .demod_address = 0x63,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+};
+
+static struct cx22702_config hauppauge_hvr3000_config = {
+ .demod_address = 0x63,
+ .output_mode = CX22702_SERIAL_OUTPUT,
+};
+
static int or51132_set_ts_param(struct dvb_frontend* fe,
int is_punctured)
{
@@ -351,12 +340,10 @@ static int or51132_set_ts_param(struct dvb_frontend* fe,
}
static struct or51132_config pchdtv_hd3000 = {
- .demod_address = 0x15,
- .set_ts_params = or51132_set_ts_param,
+ .demod_address = 0x15,
+ .set_ts_params = or51132_set_ts_param,
};
-#endif
-#ifdef HAVE_LGDT330X
static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params)
{
@@ -373,14 +360,14 @@ static int lgdt3302_tuner_set_params(struct dvb_frontend* fe,
dvb_pll_configure(core->pll_desc, buf, params->frequency, 0);
dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
- __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
+ __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
if ((err = i2c_transfer(&core->i2c_adap, &msg, 1)) != 1) {
printk(KERN_WARNING "cx88-dvb: %s error "
- "(addr %02x <- %02x, err = %i)\n",
- __FUNCTION__, buf[0], buf[1], err);
+ "(addr %02x <- %02x, err = %i)\n",
+ __FUNCTION__, buf[0], buf[1], err);
if (err < 0)
return err;
else
@@ -425,28 +412,26 @@ static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
}
static struct lgdt330x_config fusionhdtv_3_gold = {
- .demod_address = 0x0e,
- .demod_chip = LGDT3302,
- .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
- .set_ts_params = lgdt330x_set_ts_param,
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3302,
+ .serial_mpeg = 0x04, /* TPSERIAL for 3302 in TOP_CONTROL */
+ .set_ts_params = lgdt330x_set_ts_param,
};
static struct lgdt330x_config fusionhdtv_5_gold = {
- .demod_address = 0x0e,
- .demod_chip = LGDT3303,
- .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .set_ts_params = lgdt330x_set_ts_param,
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+ .set_ts_params = lgdt330x_set_ts_param,
};
static struct lgdt330x_config pchdtv_hd5500 = {
- .demod_address = 0x59,
- .demod_chip = LGDT3303,
- .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
- .set_ts_params = lgdt330x_set_ts_param,
+ .demod_address = 0x59,
+ .demod_chip = LGDT3303,
+ .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
+ .set_ts_params = lgdt330x_set_ts_param,
};
-#endif
-#ifdef HAVE_NXT200X
static int nxt200x_set_ts_param(struct dvb_frontend* fe,
int is_punctured)
{
@@ -465,28 +450,27 @@ static int nxt200x_set_pll_input(u8* buf, int input)
}
static struct nxt200x_config ati_hdtvwonder = {
- .demod_address = 0x0a,
- .set_pll_input = nxt200x_set_pll_input,
- .set_ts_params = nxt200x_set_ts_param,
+ .demod_address = 0x0a,
+ .set_pll_input = nxt200x_set_pll_input,
+ .set_ts_params = nxt200x_set_ts_param,
};
-#endif
-#ifdef HAVE_CX24123
static int cx24123_set_ts_param(struct dvb_frontend* fe,
int is_punctured)
{
struct cx8802_dev *dev= fe->dvb->priv;
- dev->ts_gen_cntrl = 0x2;
+ dev->ts_gen_cntrl = 0x02;
return 0;
}
-static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe,
+ fe_sec_voltage_t voltage)
{
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
if (voltage == SEC_VOLTAGE_OFF) {
- cx_write(MO_GP0_IO, 0x000006fB);
+ cx_write(MO_GP0_IO, 0x000006fb);
} else {
cx_write(MO_GP0_IO, 0x000006f9);
}
@@ -496,7 +480,8 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t
return 0;
}
-static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
{
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
@@ -512,20 +497,20 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t
}
static struct cx24123_config geniatech_dvbs_config = {
- .demod_address = 0x55,
- .set_ts_params = cx24123_set_ts_param,
+ .demod_address = 0x55,
+ .set_ts_params = cx24123_set_ts_param,
};
static struct cx24123_config hauppauge_novas_config = {
- .demod_address = 0x55,
- .set_ts_params = cx24123_set_ts_param,
+ .demod_address = 0x55,
+ .set_ts_params = cx24123_set_ts_param,
};
static struct cx24123_config kworld_dvbs_100_config = {
- .demod_address = 0x15,
- .set_ts_params = cx24123_set_ts_param,
+ .demod_address = 0x15,
+ .set_ts_params = cx24123_set_ts_param,
+ .lnb_polarity = 1,
};
-#endif
static int dvb_register(struct cx8802_dev *dev)
{
@@ -535,114 +520,124 @@ static int dvb_register(struct cx8802_dev *dev)
/* init frontend */
switch (dev->core->board) {
-#ifdef HAVE_CX22702
case CX88_BOARD_HAUPPAUGE_DVB_T1:
- dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_novat_config,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_thomson_dtt759x);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt759x);
}
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
case CX88_BOARD_KWORLD_DVB_T_CX22702:
case CX88_BOARD_WINFAST_DTV1000:
- dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(cx22702_attach,
+ &connexant_refboard_config,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x60,
- &dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt7579);
}
break;
case CX88_BOARD_WINFAST_DTV2000H:
case CX88_BOARD_HAUPPAUGE_HVR1100:
case CX88_BOARD_HAUPPAUGE_HVR1100LP:
- dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr1100_config,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_fmd1216me);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_fmd1216me);
+ }
+ break;
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ dev->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr1300_config,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_fmd1216me);
+ }
+ break;
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
+ dev->dvb.frontend = dvb_attach(cx22702_attach,
+ &hauppauge_hvr3000_config,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_fmd1216me);
}
break;
-#endif
-#if defined(HAVE_MT352) || defined(HAVE_ZL10353)
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
-#ifdef HAVE_MT352
- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x60,
- &dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+ NULL, &dvb_pll_thomson_dtt7579);
break;
}
-#endif
-#ifdef HAVE_ZL10353
/* ZL10353 replaces MT352 on later cards */
- dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_plus_v1_1,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x60,
- &dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+ NULL, &dvb_pll_thomson_dtt7579);
}
-#endif
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
-#ifdef HAVE_MT352
/* The tin box says DEE1601, but it seems to be DTT7579
* compatible, with a slightly different MT352 AGC gain. */
- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv_dual,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv_dual,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, &dvb_pll_thomson_dtt7579);
break;
}
-#endif
-#ifdef HAVE_ZL10353
/* ZL10353 replaces MT352 on later cards */
- dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_plus_v1_1,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_thomson_dtt7579);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, &dvb_pll_thomson_dtt7579);
}
-#endif
break;
-#endif /* HAVE_MT352 || HAVE_ZL10353 */
-#ifdef HAVE_MT352
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
- dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_lg_z201);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, &dvb_pll_lg_z201);
}
break;
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
case CX88_BOARD_ADSTECH_DVB_T_PCI:
- dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &dntv_live_dvbt_config,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_unknown_1);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, &dvb_pll_unknown_1);
}
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
#ifdef HAVE_VP3054_I2C
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_fmd1216me;
- dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_pro_config,
+ dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&((struct vp3054_i2c_state *)dev->card_priv)->adap);
if (dev->dvb.frontend != NULL) {
dev->dvb.frontend->ops.tuner_ops.set_params = dntv_live_dvbt_pro_tuner_set_params;
@@ -651,30 +646,26 @@ static int dvb_register(struct cx8802_dev *dev)
printk("%s: built without vp3054 support\n", dev->core->name);
#endif
break;
-#endif
-#ifdef HAVE_ZL10353
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_thomson_fe6600;
- dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_hybrid,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dev->dvb.frontend->ops.tuner_ops.set_params = dvico_hybrid_tuner_set_params;
}
break;
-#endif
-#ifdef HAVE_OR51132
case CX88_BOARD_PCHDTV_HD3000:
- dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(or51132_attach,
+ &pchdtv_hd3000,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_thomson_dtt761x);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ &dev->core->i2c_adap,
+ &dvb_pll_thomson_dtt761x);
}
break;
-#endif
-#ifdef HAVE_LGDT330X
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
dev->ts_gen_cntrl = 0x08;
{
@@ -690,8 +681,9 @@ static int dvb_register(struct cx8802_dev *dev)
fusionhdtv_3_gold.pll_rf_set = lgdt330x_pll_rf_set;
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_microtune_4042;
- dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_3_gold,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
}
@@ -709,8 +701,9 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(200);
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_thomson_dtt761x;
- dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_3_gold,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_3_gold,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3302_tuner_set_params;
}
@@ -726,8 +719,9 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
- dev->dvb.frontend = lgdt330x_attach(&fusionhdtv_5_gold,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &fusionhdtv_5_gold,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
}
@@ -743,52 +737,51 @@ static int dvb_register(struct cx8802_dev *dev)
mdelay(100);
cx_set(MO_GP0_IO, 1);
mdelay(200);
- dev->dvb.frontend = lgdt330x_attach(&pchdtv_hd5500,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(lgdt330x_attach,
+ &pchdtv_hd5500,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
dev->dvb.frontend->ops.tuner_ops.set_params = lgdt3303_tuner_set_params;
}
}
break;
-#endif
-#ifdef HAVE_NXT200X
case CX88_BOARD_ATI_HDTVWONDER:
- dev->dvb.frontend = nxt200x_attach(&ati_hdtvwonder,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(nxt200x_attach,
+ &ati_hdtvwonder,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_pll_attach(dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- &dvb_pll_tuv1236d);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, &dvb_pll_tuv1236d);
}
break;
-#endif
-#ifdef HAVE_CX24123
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
- dev->dvb.frontend = cx24123_attach(&hauppauge_novas_config,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(cx24123_attach,
+ &hauppauge_novas_config,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend) {
- isl6421_attach(dev->dvb.frontend, &dev->core->i2c_adap,
- 0x08, 0x00, 0x00);
+ dvb_attach(isl6421_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x08, 0x00, 0x00);
}
break;
case CX88_BOARD_KWORLD_DVBS_100:
- dev->dvb.frontend = cx24123_attach(&kworld_dvbs_100_config,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(cx24123_attach,
+ &kworld_dvbs_100_config,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend) {
dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = kworld_dvbs_100_set_voltage;
}
break;
case CX88_BOARD_GENIATECH_DVBS:
- dev->dvb.frontend = cx24123_attach(&geniatech_dvbs_config,
- &dev->core->i2c_adap);
+ dev->dvb.frontend = dvb_attach(cx24123_attach,
+ &geniatech_dvbs_config,
+ &dev->core->i2c_adap);
if (dev->dvb.frontend) {
dev->core->prev_set_voltage = dev->dvb.frontend->ops.set_voltage;
dev->dvb.frontend->ops.set_voltage = geniatech_dvbs_set_voltage;
}
break;
-#endif
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
@@ -826,7 +819,7 @@ static int __devinit dvb_probe(struct pci_dev *pci_dev,
return -EINVAL;
err = -ENODEV;
- if (!cx88_boards[core->board].dvb)
+ if (!(cx88_boards[core->board].mpeg & CX88_MPEG_DVB))
goto fail_core;
err = -ENOMEM;
@@ -908,8 +901,10 @@ static struct pci_driver dvb_pci_driver = {
.id_table = cx8802_pci_tbl,
.probe = dvb_probe,
.remove = __devexit_p(dvb_remove),
+#ifdef CONFIG_PM
.suspend = cx8802_suspend_common,
.resume = cx8802_resume_common,
+#endif
};
static int dvb_init(void)
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 70663805cc30..88af23a93870 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -7,6 +7,9 @@
(c) 2002 Yurij Sysoev <yurij@naturesoft.net>
(c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
+ (c) 2005 Mauro Carvalho Chehab <mchehab@infradead.org>
+ - Multituner support and i2c address binding
+
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
@@ -40,6 +43,11 @@ static unsigned int i2c_scan = 0;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
+static unsigned int i2c_udelay = 5;
+module_param(i2c_udelay, int, 0644);
+MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs "
+ "(should be 5 or higher). Lower value means higher bus speed.");
+
#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \
printk(KERN_DEBUG "%s: " fmt, core->name , ## arg)
@@ -137,7 +145,7 @@ void cx88_call_i2c_clients(struct cx88_core *core, unsigned int cmd, void *arg)
if (0 != core->i2c_rc)
return;
- if (core->dvbdev) {
+ if ( (core->dvbdev) && (core->dvbdev->dvb.frontend) ) {
if (core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl)
core->dvbdev->dvb.frontend->ops.i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
@@ -155,7 +163,6 @@ static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
.getsda = cx8800_bit_getsda,
.getscl = cx8800_bit_getscl,
.udelay = 16,
- .mdelay = 10,
.timeout = 200,
};
@@ -199,6 +206,11 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
/* init + register i2c algo-bit adapter */
int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
{
+ /* Prevents usage of invalid delay values */
+ if (i2c_udelay<5)
+ i2c_udelay=5;
+ cx8800_i2c_algo_template.udelay=i2c_udelay;
+
memcpy(&core->i2c_adap, &cx8800_i2c_adap_template,
sizeof(core->i2c_adap));
memcpy(&core->i2c_algo, &cx8800_i2c_algo_template,
@@ -208,7 +220,7 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
if (core->tuner_type != TUNER_ABSENT)
core->i2c_adap.class |= I2C_CLASS_TV_ANALOG;
- if (cx88_boards[core->board].dvb)
+ if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB)
core->i2c_adap.class |= I2C_CLASS_TV_DIGITAL;
core->i2c_adap.dev.parent = &pci->dev;
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index c25564648993..ee48995a4ab5 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -107,7 +107,15 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
(gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : "");
- if (ir->mask_keydown) {
+ if (ir->core->board == CX88_BOARD_NORWOOD_MICRO) {
+ u32 gpio_key = cx_read(MO_GP0_IO);
+
+ data = (data << 4) | ((gpio_key & 0xf0) >> 4);
+
+ ir_input_keydown(ir->input, &ir->ir, data, data);
+ ir_input_nokey(ir->input, &ir->ir);
+
+ } else if (ir->mask_keydown) {
/* bit set on keydown */
if (gpio & ir->mask_keydown) {
ir_input_keydown(ir->input, &ir->ir, data, data);
@@ -187,6 +195,8 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
ir_codes = ir_codes_hauppauge_new;
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
@@ -248,6 +258,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir_type = IR_TYPE_PD;
ir->sampling = 0xff00; /* address */
break;
+ case CX88_BOARD_NORWOOD_MICRO:
+ ir_codes = ir_codes_norwood;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0x0e;
+ ir->mask_keyup = 0x80;
+ ir->polling = 50; /* ms */
+ break;
case CX88_BOARD_NPGTECH_REALTV_TOP10FM:
ir_codes = ir_codes_npgtech;
ir->gpio_addr = MO_GP0_IO;
@@ -402,6 +419,8 @@ void cx88_ir_irq(struct cx88_core *core)
case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
case CX88_BOARD_HAUPPAUGE_HVR1100:
+ case CX88_BOARD_HAUPPAUGE_HVR1300:
+ case CX88_BOARD_HAUPPAUGE_HVR3000:
ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
ir_dprintk("biphase decoded: %x\n", ircode);
if ((ircode & 0xfffff000) != 0x3000)
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 138a4f692501..6b23a4e6f66d 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -65,8 +65,17 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
/* FIXME: this needs a review.
* also: move to cx88-blackbird + cx88-dvb source files? */
+ if (cx88_boards[core->board].mpeg == (CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) ) {
+ /* Report a warning until the mini driver patch is applied,
+ * else the following conditions will set the dma registers incorrectly.
+ * This will be removed in the next major patch and changes to the conditions
+ * will be made.
+ */
+ printk(KERN_INFO "%s() board->(CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD) is invalid\n", __FUNCTION__);
+ return -EINVAL;
+ }
- if (cx88_boards[core->board].dvb) {
+ if (cx88_boards[core->board].mpeg & CX88_MPEG_DVB) {
/* negedge driven & software reset */
cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
udelay(100);
@@ -92,7 +101,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
udelay(100);
}
- if (cx88_boards[core->board].blackbird) {
+ if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */
cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */
@@ -367,7 +376,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
#define MAX_IRQ_LOOP 10
-static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cx8802_irq(int irq, void *dev_id)
{
struct cx8802_dev *dev = dev_id;
struct cx88_core *core = dev->core;
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 5785c3481579..58ba9f773524 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -52,7 +52,6 @@
#include <linux/init.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
-#include <linux/config.h>
#include <linux/kthread.h>
#include "cx88.h"
@@ -138,16 +137,12 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
{
u32 volume;
-#ifndef CONFIG_VIDEO_CX88_ALSA
/* restart dma; This avoids buzz in NICAM and is good in others */
cx88_stop_audio_dma(core);
-#endif
cx_write(AUD_RATE_THRES_DMD, 0x000000C0);
-#ifndef CONFIG_VIDEO_CX88_ALSA
cx88_start_audio_dma(core);
-#endif
- if (cx88_boards[core->board].blackbird) {
+ if (cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD) {
/* sets sound input from external adc */
switch (core->board) {
case CX88_BOARD_HAUPPAUGE_ROSLYN:
@@ -169,7 +164,7 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl)
cx_write(AUD_I2SCNTL, 0);
/* cx_write(AUD_APB_IN_RATE_ADJ, 0); */
}
- if ((always_analog) || (!cx88_boards[core->board].blackbird)) {
+ if ((always_analog) || (!(cx88_boards[core->board].mpeg & CX88_MPEG_BLACKBIRD))) {
ctl |= EN_DAC_ENABLE;
cx_write(AUD_CTL, ctl);
}
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 94c92bacc342..90e298d074d1 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -497,6 +497,7 @@ static int start_video_dma(struct cx8800_dev *dev,
return 0;
}
+#ifdef CONFIG_PM
static int stop_video_dma(struct cx8800_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -512,6 +513,7 @@ static int stop_video_dma(struct cx8800_dev *dev)
cx_clear(MO_VID_INTMSK, 0x0f0011);
return 0;
}
+#endif
static int restart_video_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
@@ -1742,7 +1744,7 @@ static void cx8800_vid_irq(struct cx8800_dev *dev)
}
}
-static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cx8800_irq(int irq, void *dev_id)
{
struct cx8800_dev *dev = dev_id;
struct cx88_core *core = dev->core;
@@ -1926,6 +1928,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
if (TUNER_ABSENT != core->tuner_type)
request_module("tuner");
+ if (cx88_boards[ core->board ].audio_chip == AUDIO_CHIP_WM8775)
+ request_module("wm8775");
+
/* register v4l devices */
dev->video_dev = cx88_vdev_init(core,dev->pci,
&cx8800_video_template,"video");
@@ -2017,6 +2022,7 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
+#ifdef CONFIG_PM
static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
@@ -2092,6 +2098,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
return 0;
}
+#endif
/* ----------------------------------------------------------- */
@@ -2112,9 +2119,10 @@ static struct pci_driver cx8800_pci_driver = {
.id_table = cx8800_pci_tbl,
.probe = cx8800_initdev,
.remove = __devexit_p(cx8800_finidev),
-
+#ifdef CONFIG_PM
.suspend = cx8800_suspend,
.resume = cx8800_resume,
+#endif
};
static int cx8800_init(void)
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 751a754a45e9..2b4f1970c7df 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -100,7 +100,6 @@ static struct i2c_algo_bit_data vp3054_i2c_algo_template = {
.getsda = vp3054_bit_getsda,
.getscl = vp3054_bit_getscl,
.udelay = 16,
- .mdelay = 10,
.timeout = 200,
};
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index e7810955dd4f..3bc91aad4fe5 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -30,6 +30,7 @@
#include <media/tveeprom.h>
#include <media/video-buf.h>
#include <media/cx2341x.h>
+#include <media/audiochip.h>
#include <media/video-buf-dvb.h>
#include "btcx-risc.h"
@@ -39,12 +40,6 @@
#include <linux/mutex.h>
#define CX88_VERSION_CODE KERNEL_VERSION(0,0,6)
-#ifndef TRUE
-# define TRUE (1==1)
-#endif
-#ifndef FALSE
-# define FALSE (1==0)
-#endif
#define UNSET (-1U)
#define CX88_MAXBOARDS 8
@@ -73,6 +68,12 @@ enum cx88_deemph_type {
FM_DEEMPH_75
};
+enum cx88_board_type {
+ CX88_BOARD_NONE = 0,
+ CX88_MPEG_DVB,
+ CX88_MPEG_BLACKBIRD
+};
+
/* ----------------------------------------------------------- */
/* tv norms */
@@ -197,6 +198,10 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_NPGTECH_REALTV_TOP10FM 50
#define CX88_BOARD_WINFAST_DTV2000H 51
#define CX88_BOARD_GENIATECH_DVBS 52
+#define CX88_BOARD_HAUPPAUGE_HVR3000 53
+#define CX88_BOARD_NORWOOD_MICRO 54
+#define CX88_BOARD_TE_DTV_250_OEM_SWANN 55
+#define CX88_BOARD_HAUPPAUGE_HVR1300 56
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -226,8 +231,8 @@ struct cx88_board {
int tda9887_conf;
struct cx88_input input[MAX_CX88_INPUT];
struct cx88_input radio;
- unsigned int blackbird:1;
- unsigned int dvb:1;
+ enum cx88_board_type mpeg;
+ enum audiochip audio_chip;
};
struct cx88_subid {
@@ -545,6 +550,7 @@ extern const unsigned int cx88_idcount;
extern void cx88_card_list(struct cx88_core *core, struct pci_dev *pci);
extern void cx88_card_setup(struct cx88_core *core);
+extern void cx88_card_setup_pre_i2c(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-tvaudio.c */
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index b9ba95f5e026..b1012e92ee04 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -166,7 +166,7 @@ static int dabusb_free_buffers (pdabusb_t s)
return 0;
}
/*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (struct urb *purb, struct pt_regs *regs)
+static void dabusb_iso_complete (struct urb *purb)
{
pbuff_t b = purb->context;
pdabusb_t s = b->s;
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index dfb15bfb83dc..9285a58e47aa 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -5,7 +5,8 @@ config VIDEO_EM28XX
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
- select VIDEO_SAA711X
+ select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for Empia 28xx based TV cards.
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 4350cc75b025..255a47dfb84f 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -382,7 +382,7 @@ int em28xx_resolution_set(struct em28xx *dev)
/******************* isoc transfer handling ****************************/
#ifdef ENABLE_DEBUG_ISOC_FRAMES
-static void em28xx_isoc_dump(struct urb *urb, struct pt_regs *regs)
+static void em28xx_isoc_dump(struct urb *urb)
{
int len = 0;
int ntrans = 0;
@@ -534,7 +534,7 @@ static inline void em28xx_isoc_video_copy(struct em28xx *dev,
* em28xx_isoIrq()
* handles the incoming isoc urbs and fills the frames from our inqueue
*/
-static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
+static void em28xx_isocIrq(struct urb *urb)
{
struct em28xx *dev = urb->context;
int i, status;
@@ -545,7 +545,7 @@ static void em28xx_isocIrq(struct urb *urb, struct pt_regs *regs)
return;
#ifdef ENABLE_DEBUG_ISOC_FRAMES
if (isoc_debug>1)
- em28xx_isoc_dump(urb, regs);
+ em28xx_isoc_dump(urb);
#endif
if (urb->status == -ENOENT)
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 8992b6e62b9f..f786ab11d2cd 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -398,7 +398,7 @@ int et61x251_i2c_write(struct et61x251_device* cam, u8 address, u8 value)
/*****************************************************************************/
-static void et61x251_urb_complete(struct urb *urb, struct pt_regs* regs)
+static void et61x251_urb_complete(struct urb *urb)
{
struct et61x251_device* cam = urb->context;
struct et61x251_frame_t** f;
@@ -973,16 +973,32 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,
et61x251_show_i2c_val, et61x251_store_i2c_val);
-static void et61x251_create_sysfs(struct et61x251_device* cam)
+static int et61x251_create_sysfs(struct et61x251_device* cam)
{
struct video_device *v4ldev = cam->v4ldev;
+ int rc;
- video_device_create_file(v4ldev, &class_device_attr_reg);
- video_device_create_file(v4ldev, &class_device_attr_val);
+ rc = video_device_create_file(v4ldev, &class_device_attr_reg);
+ if (rc) goto err;
+ rc = video_device_create_file(v4ldev, &class_device_attr_val);
+ if (rc) goto err_reg;
if (cam->sensor.sysfs_ops) {
- video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
- video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+ if (rc) goto err_val;
+ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+ if (rc) goto err_i2c_reg;
}
+
+ return 0;
+
+err_i2c_reg:
+ video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+err_val:
+ video_device_remove_file(v4ldev, &class_device_attr_val);
+err_reg:
+ video_device_remove_file(v4ldev, &class_device_attr_reg);
+err:
+ return rc;
}
#endif /* CONFIG_VIDEO_ADV_DEBUG */
@@ -2534,7 +2550,9 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- et61x251_create_sysfs(cam);
+ err = et61x251_create_sysfs(cam);
+ if (err)
+ goto fail2;
DBG(2, "Optional device control through 'sysfs' interface ready");
#endif
@@ -2544,6 +2562,13 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return 0;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+fail2:
+ video_nr[dev_nr] = -1;
+ dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
+ mutex_unlock(&cam->dev_mutex);
+ video_unregister_device(cam->v4ldev);
+#endif
fail:
if (cam) {
kfree(cam->control_buffer);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index fba30a40e9c6..1457b1602221 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -64,23 +64,32 @@ MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults
static int get_key_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[3];
- int start, toggle, dev, code;
+ int start, range, toggle, dev, code;
/* poll IR chip */
if (3 != i2c_master_recv(&ir->c,buf,3))
return -EIO;
/* split rc5 data block ... */
- start = (buf[0] >> 6) & 3;
+ start = (buf[0] >> 7) & 1;
+ range = (buf[0] >> 6) & 1;
toggle = (buf[0] >> 5) & 1;
dev = buf[0] & 0x1f;
code = (buf[1] >> 2) & 0x3f;
- if (3 != start)
+ /* rc5 has two start bits
+ * the first bit must be one
+ * the second bit defines the command range (1 = 0-63, 0 = 64 - 127)
+ */
+ if (!start)
/* no key pressed */
return 0;
- dprintk(1,"ir hauppauge (rc5): s%d t%d dev=%d code=%d\n",
- start, toggle, dev, code);
+
+ if (!range)
+ code += 64;
+
+ dprintk(1,"ir hauppauge (rc5): s%d r%d t%d dev=%d code=%d\n",
+ start, range, toggle, dev, code);
/* return key */
*ir_key = code;
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index 3bf7ac4f5288..c1a377f797d9 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -832,8 +832,7 @@ static int ks0127_detach(struct i2c_client *client)
static int __devinit ks0127_init_module(void)
{
init_reg_defaults();
- i2c_add_driver(&i2c_driver_ks0127);
- return 0;
+ return i2c_add_driver(&i2c_driver_ks0127);
}
static void __devexit ks0127_cleanup_module(void)
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index e278753f8f25..b083338823df 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -786,7 +786,7 @@ static void mchip_cont_compression_start(void)
/* Interrupt handling */
/****************************************************************************/
-static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t meye_irq(int irq, void *dev_id)
{
u32 v;
int reqnr;
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 56246b8578f3..cf43df3fe708 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -904,6 +904,8 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind)
state->has_virtual_dolby_surround = msp_revision == 'G' && msp_prod_lo == 1;
/* Has Virtual Dolby Surround & Dolby Pro Logic: only in msp34x2 */
state->has_dolby_pro_logic = msp_revision == 'G' && msp_prod_lo == 2;
+ /* The msp343xG supports BTSC only and cannot do Automatic Standard Detection. */
+ state->force_btsc = msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3;
state->opmode = opmode;
if (state->opmode == OPMODE_AUTO) {
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
index 545e4ac094f2..7531efa1615e 100644
--- a/drivers/media/video/msp3400-driver.h
+++ b/drivers/media/video/msp3400-driver.h
@@ -64,6 +64,7 @@ struct msp_state {
u8 has_sound_processing;
u8 has_virtual_dolby_surround;
u8 has_dolby_pro_logic;
+ u8 force_btsc;
int radio;
int opmode;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index ed02ff811388..4c7f85b566a0 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -960,9 +960,10 @@ int msp34xxg_thread(void *data)
/* setup the chip*/
msp34xxg_reset(client);
- state->std = state->radio ? 0x40 : msp_standard;
- /* start autodetect */
+ state->std = state->radio ? 0x40 :
+ (state->force_btsc && msp_standard == 1) ? 32 : msp_standard;
msp_write_dem(client, 0x20, state->std);
+ /* start autodetect */
if (state->std != 1)
goto unmute;
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index 1b07a61c2ebb..b4db2cbb5a84 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -301,10 +301,11 @@ static struct symbolic_list senlist[] = {
static struct symbolic_list urb_errlist[] = {
{ -ENOSR, "Buffer error (overrun)" },
{ -EPIPE, "Stalled (device not responding)" },
- { -EOVERFLOW, "Babble (bad cable?)" },
+ { -EOVERFLOW, "Babble (device sends too much data)" },
{ -EPROTO, "Bit-stuff error (bad cable?)" },
- { -EILSEQ, "CRC/Timeout" },
- { -ETIMEDOUT, "NAK (device does not respond)" },
+ { -EILSEQ, "CRC/Timeout (bad cable?)" },
+ { -ETIME, "Device does not respond to token" },
+ { -ETIMEDOUT, "Device does not respond to command" },
{ -1, NULL }
};
@@ -3502,7 +3503,7 @@ check_middle:
}
static void
-ov51x_isoc_irq(struct urb *urb, struct pt_regs *regs)
+ov51x_isoc_irq(struct urb *urb)
{
int i;
struct usb_ov511 *ov;
@@ -5647,17 +5648,49 @@ static ssize_t show_exposure(struct class_device *cd, char *buf)
}
static CLASS_DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
-static void ov_create_sysfs(struct video_device *vdev)
+static int ov_create_sysfs(struct video_device *vdev)
{
- video_device_create_file(vdev, &class_device_attr_custom_id);
- video_device_create_file(vdev, &class_device_attr_model);
- video_device_create_file(vdev, &class_device_attr_bridge);
- video_device_create_file(vdev, &class_device_attr_sensor);
- video_device_create_file(vdev, &class_device_attr_brightness);
- video_device_create_file(vdev, &class_device_attr_saturation);
- video_device_create_file(vdev, &class_device_attr_contrast);
- video_device_create_file(vdev, &class_device_attr_hue);
- video_device_create_file(vdev, &class_device_attr_exposure);
+ int rc;
+
+ rc = video_device_create_file(vdev, &class_device_attr_custom_id);
+ if (rc) goto err;
+ rc = video_device_create_file(vdev, &class_device_attr_model);
+ if (rc) goto err_id;
+ rc = video_device_create_file(vdev, &class_device_attr_bridge);
+ if (rc) goto err_model;
+ rc = video_device_create_file(vdev, &class_device_attr_sensor);
+ if (rc) goto err_bridge;
+ rc = video_device_create_file(vdev, &class_device_attr_brightness);
+ if (rc) goto err_sensor;
+ rc = video_device_create_file(vdev, &class_device_attr_saturation);
+ if (rc) goto err_bright;
+ rc = video_device_create_file(vdev, &class_device_attr_contrast);
+ if (rc) goto err_sat;
+ rc = video_device_create_file(vdev, &class_device_attr_hue);
+ if (rc) goto err_contrast;
+ rc = video_device_create_file(vdev, &class_device_attr_exposure);
+ if (rc) goto err_hue;
+
+ return 0;
+
+err_hue:
+ video_device_remove_file(vdev, &class_device_attr_hue);
+err_contrast:
+ video_device_remove_file(vdev, &class_device_attr_contrast);
+err_sat:
+ video_device_remove_file(vdev, &class_device_attr_saturation);
+err_bright:
+ video_device_remove_file(vdev, &class_device_attr_brightness);
+err_sensor:
+ video_device_remove_file(vdev, &class_device_attr_sensor);
+err_bridge:
+ video_device_remove_file(vdev, &class_device_attr_bridge);
+err_model:
+ video_device_remove_file(vdev, &class_device_attr_model);
+err_id:
+ video_device_remove_file(vdev, &class_device_attr_custom_id);
+err:
+ return rc;
}
/****************************************************************************
@@ -5816,7 +5849,11 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
ov->vdev->minor);
usb_set_intfdata(intf, ov);
- ov_create_sysfs(ov->vdev);
+ if (ov_create_sysfs(ov->vdev)) {
+ err("ov_create_sysfs failed");
+ goto error;
+ }
+
return 0;
error:
diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c
index 3484e36b6801..368d6e219fa4 100644
--- a/drivers/media/video/planb.c
+++ b/drivers/media/video/planb.c
@@ -91,7 +91,7 @@ static void planb_close(struct video_device *);
static int planb_ioctl(struct video_device *, unsigned int, void *);
static int planb_init_done(struct video_device *);
static int planb_mmap(struct video_device *, const char *, unsigned long);
-static void planb_irq(int, void *, struct pt_regs *);
+static void planb_irq(int, void *);
static void release_planb(void);
int init_planbs(struct video_init *);
@@ -1316,7 +1316,7 @@ cmd_tab_data_end:
return c1;
}
-static void planb_irq(int irq, void *dev_id, struct pt_regs * regs)
+static void planb_irq(int irq, void *dev_id)
{
unsigned int stat, astat;
struct planb *pb = (struct planb *)dev_id;
diff --git a/drivers/media/video/pvrusb2/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 7e727fe14b32..5645c9318890 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -5,8 +5,6 @@ config VIDEO_PVRUSB2
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
- select VIDEO_SAA711X
- select VIDEO_MSP3400
---help---
This is a video4linux driver for Conexant 23416 based
usb2 personal video recorder devices.
@@ -14,6 +12,20 @@ config VIDEO_PVRUSB2
To compile this driver as a module, choose M here: the
module will be called pvrusb2
+config VIDEO_PVRUSB2_29XXX
+ bool "Hauppauge WinTV-PVR USB2 support for 29xxx model series"
+ depends on VIDEO_PVRUSB2 && EXPERIMENTAL
+ select VIDEO_SAA711X
+ select VIDEO_MSP3400
+ ---help---
+ This option enables support for WinTV-PVR USB2 devices whose
+ model number is of the form "29xxx" (leading prefix of "29"
+ followed by 3 digits).
+ To see if you may need this option, examine the white
+ sticker on the underside of your device.
+
+ If you are in doubt, say Y.
+
config VIDEO_PVRUSB2_24XXX
bool "Hauppauge WinTV-PVR USB2 support for 24xxx model series"
depends on VIDEO_PVRUSB2 && EXPERIMENTAL
@@ -25,14 +37,9 @@ config VIDEO_PVRUSB2_24XXX
form "24xxx" (leading prefix of "24" followed by 3 digits).
To see if you may need this option, examine the white
sticker on the underside of your device. Enabling this
- option will not harm support for older devices, however it
- is a separate option because of the experimental nature of
- this new feature.
-
- If you are in doubt, say N.
+ option will not harm support for older devices.
- Note: This feature is _very_ experimental. You have been
- warned.
+ If you are in doubt, say Y.
config VIDEO_PVRUSB2_SYSFS
bool "pvrusb2 sysfs support (EXPERIMENTAL)"
@@ -60,3 +67,5 @@ config VIDEO_PVRUSB2_DEBUGIFC
You do not need to select this option unless you plan
on debugging the driver or performing a manual firmware
extraction.
+
+ If you are in doubt, say N.
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 02e414210dac..69b3e43cd0eb 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -1,10 +1,6 @@
obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
-obj-pvrusb2-24xxx-$(CONFIG_VIDEO_PVRUSB2_24XXX) := \
- pvrusb2-cx2584x-v4l.o \
- pvrusb2-wm8775.o
-
pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
pvrusb2-encoder.o pvrusb2-video-v4l.o \
@@ -12,7 +8,7 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
pvrusb2-main.o pvrusb2-hdw.o pvrusb2-v4l2.o \
pvrusb2-ctrl.o pvrusb2-std.o \
pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
- $(obj-pvrusb2-24xxx-y) \
+ pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
$(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index fb6198f1df98..c77de859cc8e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -43,12 +43,17 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
if (cptr->info->type == pvr2_ctl_bitmask) {
mask &= cptr->info->def.type_bitmask.valid_bits;
} else if (cptr->info->type == pvr2_ctl_int) {
- if (val < cptr->info->def.type_int.min_value) {
- break;
+ int lim;
+ lim = cptr->info->def.type_int.min_value;
+ if (cptr->info->get_min_value) {
+ cptr->info->get_min_value(cptr,&lim);
}
- if (val > cptr->info->def.type_int.max_value) {
- break;
+ if (val < lim) break;
+ lim = cptr->info->def.type_int.max_value;
+ if (cptr->info->get_max_value) {
+ cptr->info->get_max_value(cptr,&lim);
}
+ if (val > lim) break;
} else if (cptr->info->type == pvr2_ctl_enum) {
if (val >= cptr->info->def.type_enum.count) {
break;
@@ -91,7 +96,9 @@ int pvr2_ctrl_get_max(struct pvr2_ctrl *cptr)
int ret = 0;
if (!cptr) return 0;
LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->type == pvr2_ctl_int) {
+ if (cptr->info->get_max_value) {
+ cptr->info->get_max_value(cptr,&ret);
+ } else if (cptr->info->type == pvr2_ctl_int) {
ret = cptr->info->def.type_int.max_value;
}
} while(0); LOCK_GIVE(cptr->hdw->big_lock);
@@ -105,7 +112,9 @@ int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr)
int ret = 0;
if (!cptr) return 0;
LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->type == pvr2_ctl_int) {
+ if (cptr->info->get_min_value) {
+ cptr->info->get_min_value(cptr,&ret);
+ } else if (cptr->info->type == pvr2_ctl_int) {
ret = cptr->info->def.type_int.min_value;
}
} while(0); LOCK_GIVE(cptr->hdw->big_lock);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index c80c26be6e4d..df8feac16aee 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -221,7 +221,7 @@ static unsigned int decoder_describe(struct pvr2_v4l_cx2584x *ctxt,
static void decoder_reset(struct pvr2_v4l_cx2584x *ctxt)
{
int ret;
- ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,NULL);
+ ret = pvr2_i2c_client_cmd(ctxt->client,VIDIOC_INT_RESET,0);
pvr2_trace(PVR2_TRACE_CHIPS,"i2c cx25840 decoder_reset (ret=%d)",ret);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 18a7073501c6..c94f97b79392 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -317,7 +317,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failed to configure cx32416");
+ "Failed to configure cx23416");
return ret;
}
@@ -337,7 +337,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw)
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
- "Failed to initialize cx32416 video input");
+ "Failed to initialize cx23416 video input");
return ret;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index 0d6dc33ca320..34b08fbcc6ea 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -33,7 +33,6 @@
*/
-#include <linux/config.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
@@ -41,32 +40,6 @@
#include "pvrusb2-io.h"
#include <media/cx2341x.h>
-/* Legal values for the SRATE state variable */
-#define PVR2_CVAL_SRATE_48 0
-#define PVR2_CVAL_SRATE_44_1 1
-
-/* Legal values for the AUDIOBITRATE state variable */
-#define PVR2_CVAL_AUDIOBITRATE_384 0
-#define PVR2_CVAL_AUDIOBITRATE_320 1
-#define PVR2_CVAL_AUDIOBITRATE_256 2
-#define PVR2_CVAL_AUDIOBITRATE_224 3
-#define PVR2_CVAL_AUDIOBITRATE_192 4
-#define PVR2_CVAL_AUDIOBITRATE_160 5
-#define PVR2_CVAL_AUDIOBITRATE_128 6
-#define PVR2_CVAL_AUDIOBITRATE_112 7
-#define PVR2_CVAL_AUDIOBITRATE_96 8
-#define PVR2_CVAL_AUDIOBITRATE_80 9
-#define PVR2_CVAL_AUDIOBITRATE_64 10
-#define PVR2_CVAL_AUDIOBITRATE_56 11
-#define PVR2_CVAL_AUDIOBITRATE_48 12
-#define PVR2_CVAL_AUDIOBITRATE_32 13
-#define PVR2_CVAL_AUDIOBITRATE_VBR 14
-
-/* Legal values for the AUDIOEMPHASIS state variable */
-#define PVR2_CVAL_AUDIOEMPHASIS_NONE 0
-#define PVR2_CVAL_AUDIOEMPHASIS_50_15 1
-#define PVR2_CVAL_AUDIOEMPHASIS_CCITT 2
-
/* Legal values for PVR2_CID_HSM */
#define PVR2_CVAL_HSM_FAIL 0
#define PVR2_CVAL_HSM_FULL 1
@@ -107,6 +80,8 @@ struct pvr2_ctl_info {
/* Control's implementation */
pvr2_ctlf_get_value get_value; /* Get its value */
+ pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */
+ pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */
pvr2_ctlf_set_value set_value; /* Set its value */
pvr2_ctlf_val_to_sym val_to_sym; /* Custom convert value->symbol */
pvr2_ctlf_sym_to_val sym_to_val; /* Custom convert symbol->value */
@@ -193,9 +168,7 @@ struct pvr2_decoder_ctrl {
/* Known major hardware variants, keyed from device ID */
#define PVR2_HDW_TYPE_29XXX 0
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
#define PVR2_HDW_TYPE_24XXX 1
-#endif
typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
#define PVR2_I2C_FUNC_CNT 128
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index be1e5cc78081..f920e0ccacd3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -24,6 +24,7 @@
#include <linux/slab.h>
#include <linux/firmware.h>
#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
#include <asm/semaphore.h>
#include "pvrusb2.h"
#include "pvrusb2-std.h"
@@ -38,9 +39,7 @@
struct usb_device_id pvr2_device_table[] = {
[PVR2_HDW_TYPE_29XXX] = { USB_DEVICE(0x2040, 0x2900) },
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
[PVR2_HDW_TYPE_24XXX] = { USB_DEVICE(0x2040, 0x2400) },
-#endif
{ }
};
@@ -48,9 +47,7 @@ MODULE_DEVICE_TABLE(usb, pvr2_device_table);
static const char *pvr2_device_names[] = {
[PVR2_HDW_TYPE_29XXX] = "WinTV PVR USB2 Model Category 29xxxx",
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
[PVR2_HDW_TYPE_24XXX] = "WinTV PVR USB2 Model Category 24xxxx",
-#endif
};
struct pvr2_string_table {
@@ -58,14 +55,12 @@ struct pvr2_string_table {
unsigned int cnt;
};
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
// Names of other client modules to request for 24xxx model hardware
static const char *pvr2_client_24xxx[] = {
"cx25840",
"tuner",
"wm8775",
};
-#endif
// Names of other client modules to request for 29xxx model hardware
static const char *pvr2_client_29xxx[] = {
@@ -79,12 +74,10 @@ static struct pvr2_string_table pvr2_client_lists[] = {
pvr2_client_29xxx,
sizeof(pvr2_client_29xxx)/sizeof(pvr2_client_29xxx[0]),
},
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
[PVR2_HDW_TYPE_24XXX] = {
pvr2_client_24xxx,
sizeof(pvr2_client_24xxx)/sizeof(pvr2_client_24xxx[0]),
},
-#endif
};
static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
@@ -221,14 +214,15 @@ static const struct pvr2_mpeg_ids mpeg_ids[] = {
};
#define MPEGDEF_COUNT (sizeof(mpeg_ids)/sizeof(mpeg_ids[0]))
+
static const char *control_values_srate[] = {
- [PVR2_CVAL_SRATE_48] = "48KHz",
- [PVR2_CVAL_SRATE_44_1] = "44.1KHz",
+ [V4L2_MPEG_AUDIO_SAMPLING_FREQ_44100] = "44.1 kHz",
+ [V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000] = "48 kHz",
+ [V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000] = "32 kHz",
};
-
static const char *control_values_input[] = {
[PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/
[PVR2_CVAL_INPUT_RADIO] = "radio",
@@ -362,6 +356,50 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v)
return 0;
}
+static int ctrl_hres_max_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ /* If we're dealing with a 24xxx device, force the horizontal
+ maximum to be 720 no matter what, since we can't get the device
+ to work properly with any other value. Otherwise just return
+ the normal value. */
+ *vp = cptr->info->def.type_int.max_value;
+ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
+ return 0;
+}
+
+static int ctrl_hres_min_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ /* If we're dealing with a 24xxx device, force the horizontal
+ minimum to be 720 no matter what, since we can't get the device
+ to work properly with any other value. Otherwise just return
+ the normal value. */
+ *vp = cptr->info->def.type_int.min_value;
+ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) *vp = 720;
+ return 0;
+}
+
+static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ /* Actual maximum depends on the video standard in effect. */
+ if (cptr->hdw->std_mask_cur & V4L2_STD_525_60) {
+ *vp = 480;
+ } else {
+ *vp = 576;
+ }
+ return 0;
+}
+
+static int ctrl_vres_min_get(struct pvr2_ctrl *cptr,int *vp)
+{
+ /* Actual minimum depends on device type. */
+ if (cptr->hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
+ *vp = 75;
+ } else {
+ *vp = 17;
+ }
+ return 0;
+}
+
static int ctrl_cx2341x_is_dirty(struct pvr2_ctrl *cptr)
{
return cptr->hdw->enc_stale != 0;
@@ -719,19 +757,27 @@ static const struct pvr2_ctl_info control_defs[] = {
.internal_id = PVR2_CID_HRES,
.default_value = 720,
DEFREF(res_hor),
- DEFINT(320,720),
+ DEFINT(19,720),
+ /* Hook in check for clamp on horizontal resolution in
+ order to avoid unsolved problem involving cx25840. */
+ .get_max_value = ctrl_hres_max_get,
+ .get_min_value = ctrl_hres_min_get,
},{
.desc = "Vertical capture resolution",
.name = "resolution_ver",
.internal_id = PVR2_CID_VRES,
.default_value = 480,
DEFREF(res_ver),
- DEFINT(200,625),
+ DEFINT(17,576),
+ /* Hook in check for video standard and adjust maximum
+ depending on the standard. */
+ .get_max_value = ctrl_vres_max_get,
+ .get_min_value = ctrl_vres_min_get,
},{
.v4l_id = V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
- .desc = "Sample rate",
+ .default_value = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+ .desc = "Audio Sampling Frequency",
.name = "srate",
- .default_value = PVR2_CVAL_SRATE_48,
DEFREF(srate),
DEFENUM(control_values_srate),
},{
@@ -935,22 +981,18 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw)
static const char *fw_files_29xxx[] = {
"v4l-pvrusb2-29xxx-01.fw",
};
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
static const char *fw_files_24xxx[] = {
"v4l-pvrusb2-24xxx-01.fw",
};
-#endif
static const struct pvr2_string_table fw_file_defs[] = {
[PVR2_HDW_TYPE_29XXX] = {
fw_files_29xxx,
sizeof(fw_files_29xxx)/sizeof(fw_files_29xxx[0]),
},
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
[PVR2_HDW_TYPE_24XXX] = {
fw_files_24xxx,
sizeof(fw_files_24xxx)/sizeof(fw_files_24xxx[0]),
},
-#endif
};
hdw->fw1_state = FW1_STATE_FAILED; // default result
@@ -2237,11 +2279,14 @@ static int pvr2_hdw_commit_ctl_internal(struct pvr2_hdw *hdw)
}
if (hdw->std_dirty ||
+ hdw->enc_stale ||
+ hdw->srate_dirty ||
+ hdw->res_ver_dirty ||
+ hdw->res_hor_dirty ||
0) {
/* If any of this changes, then the encoder needs to be
reconfigured, and we need to reset the stream. */
stale_subsys_mask |= (1<<PVR2_SUBSYS_B_ENC_CFG);
- stale_subsys_mask |= hdw->subsys_stream_mask;
}
if (hdw->srate_dirty) {
@@ -2507,7 +2552,7 @@ void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *hdw,int v)
}
-static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs)
+static void pvr2_ctl_write_complete(struct urb *urb)
{
struct pvr2_hdw *hdw = urb->context;
hdw->ctl_write_pend_flag = 0;
@@ -2516,7 +2561,7 @@ static void pvr2_ctl_write_complete(struct urb *urb, struct pt_regs *regs)
}
-static void pvr2_ctl_read_complete(struct urb *urb, struct pt_regs *regs)
+static void pvr2_ctl_read_complete(struct urb *urb)
{
struct pvr2_hdw *hdw = urb->context;
hdw->ctl_read_pend_flag = 0;
@@ -3087,6 +3132,42 @@ static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
}
+int pvr2_hdw_register_access(struct pvr2_hdw *hdw,
+ u32 chip_id,unsigned long reg_id,
+ int setFl,u32 *val_ptr)
+{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ struct list_head *item;
+ struct pvr2_i2c_client *cp;
+ struct v4l2_register req;
+ int stat = 0;
+ int okFl = 0;
+
+ req.i2c_id = chip_id;
+ req.reg = reg_id;
+ if (setFl) req.val = *val_ptr;
+ mutex_lock(&hdw->i2c_list_lock); do {
+ list_for_each(item,&hdw->i2c_clients) {
+ cp = list_entry(item,struct pvr2_i2c_client,list);
+ if (cp->client->driver->id != chip_id) continue;
+ stat = pvr2_i2c_client_cmd(
+ cp,(setFl ? VIDIOC_INT_S_REGISTER :
+ VIDIOC_INT_G_REGISTER),&req);
+ if (!setFl) *val_ptr = req.val;
+ okFl = !0;
+ break;
+ }
+ } while (0); mutex_unlock(&hdw->i2c_list_lock);
+ if (okFl) {
+ return stat;
+ }
+ return -EINVAL;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
/*
Stuff for Emacs to see, in order to encourage consistent editing style:
*** Local Variables: ***
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index fd931b5da490..29979bb2a768 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -211,6 +211,14 @@ int pvr2_hdw_v4l_get_minor_number(struct pvr2_hdw *);
/* Store the v4l minor device number */
void pvr2_hdw_v4l_store_minor_number(struct pvr2_hdw *,int);
+/* Direct read/write access to chip's registers:
+ chip_id - unique id of chip (e.g. I2C_DRIVERD_xxxx)
+ reg_id - register number to access
+ setFl - true to set the register, false to read it
+ val_ptr - storage location for source / result. */
+int pvr2_hdw_register_access(struct pvr2_hdw *,
+ u32 chip_id,unsigned long reg_id,
+ int setFl,u32 *val_ptr);
/* The following entry points are all lower level things you normally don't
want to worry about. */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
index fbe6039aeb6a..05121666b9ba 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c
@@ -19,6 +19,7 @@
*
*/
+#include <linux/kernel.h>
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
@@ -26,10 +27,8 @@
#include "pvrusb2-audio.h"
#include "pvrusb2-tuner.h"
#include "pvrusb2-video-v4l.h"
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
#include "pvrusb2-cx2584x-v4l.h"
#include "pvrusb2-wm8775.h"
-#endif
#define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
@@ -71,7 +70,6 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
return;
}
}
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
if (id == I2C_DRIVERID_CX25840) {
if (pvr2_i2c_cx2584x_v4l_setup(hdw,cp)) {
return;
@@ -82,7 +80,6 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
return;
}
}
-#endif
if (id == I2C_DRIVERID_SAA711X) {
if (pvr2_i2c_decoder_v4l_setup(hdw,cp)) {
return;
@@ -93,7 +90,8 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp)
const struct pvr2_i2c_op *pvr2_i2c_get_op(unsigned int idx)
{
- if (idx >= sizeof(ops)/sizeof(ops[0])) return 0;
+ if (idx >= ARRAY_SIZE(ops))
+ return NULL;
return ops[idx];
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
index 8a9933dec912..05ea17afe903 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c
@@ -31,7 +31,7 @@ static void set_standard(struct pvr2_hdw *hdw)
v4l2_std_id vs;
vs = hdw->std_mask_cur;
pvr2_trace(PVR2_TRACE_CHIPS,
- "i2c v4l2 set_standard(0x%llx)",(__u64)vs);
+ "i2c v4l2 set_standard(0x%llx)",(long long unsigned)vs);
pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 7fca47982277..3b9012f8e380 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -185,8 +185,6 @@ static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
}
}
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
-
/* This is a special entry point that is entered if an I2C operation is
attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this
part doesn't work, but we know it is really there. So let's look for
@@ -289,8 +287,6 @@ static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
return -EIO;
}
-#endif /* CONFIG_VIDEO_PVRUSB2_24XXX */
-
/* This is a very, very limited I2C adapter implementation. We can only
support what we actually know will work on the device... */
static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
@@ -897,14 +893,12 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
hdw->i2c_func[idx] = pvr2_i2c_basic_op;
}
-#ifdef CONFIG_VIDEO_PVRUSB2_24XXX
// If however we're dealing with new hardware, insert some hacks in
// the I2C transfer stack to let things work better.
if (hdw->hdw_type == PVR2_HDW_TYPE_24XXX) {
hdw->i2c_func[0x1b] = i2c_hack_wm8775;
hdw->i2c_func[0x44] = i2c_hack_cx25840;
}
-#endif
// Configure the adapter and set up everything else related to it.
memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index 1e393762546c..70aa63eba0cb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -429,7 +429,7 @@ static void pvr2_stream_done(struct pvr2_stream *sp)
} while (0); mutex_unlock(&sp->mutex);
}
-static void buffer_complete(struct urb *urb, struct pt_regs *regs)
+static void buffer_complete(struct urb *urb)
{
struct pvr2_buffer *bp = urb->context;
struct pvr2_stream *sp;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index 8f1a5afdd34e..e976c484c058 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index d1dda5caf406..c294f46db9b9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -19,7 +19,6 @@
*
*/
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <asm/semaphore.h>
@@ -40,8 +39,6 @@ struct pvr2_sysfs {
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
struct pvr2_sysfs_ctl_item *item_first;
struct pvr2_sysfs_ctl_item *item_last;
- struct sysfs_ops kops;
- struct kobj_type ktype;
struct class_device_attribute attr_v4l_minor_number;
struct class_device_attribute attr_unit_number;
int v4l_minor_number_created_ok;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 0caf70b8c0de..97e974d9b9c3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -29,27 +29,17 @@
#include "pvrusb2-v4l2.h"
#include "pvrusb2-ioread.h"
#include <linux/videodev2.h>
+#include <media/v4l2-dev.h>
#include <media/v4l2-common.h>
struct pvr2_v4l2_dev;
struct pvr2_v4l2_fh;
struct pvr2_v4l2;
-/* V4L no longer provide the ability to set / get a private context pointer
- (i.e. video_get_drvdata / video_set_drvdata), which means we have to
- concoct our own context locating mechanism. Supposedly this is intended
- to simplify driver implementation. It's not clear to me how that can
- possibly be true. Our solution here is to maintain a lookup table of
- our context instances, indexed by the minor device number of the V4L
- device. See pvr2_v4l2_open() for some implications of this approach. */
-static struct pvr2_v4l2_dev *devices[256];
-static DEFINE_MUTEX(device_lock);
-
struct pvr2_v4l2_dev {
+ struct video_device devbase; /* MUST be first! */
struct pvr2_v4l2 *v4lp;
- struct video_device *vdev;
struct pvr2_context_stream *stream;
- int ctxt_idx;
enum pvr2_config config;
};
@@ -74,7 +64,7 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
/* streams */
- struct pvr2_v4l2_dev video_dev;
+ struct pvr2_v4l2_dev *vdev;
};
static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1};
@@ -459,18 +449,26 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = 0;
switch(vf->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
+ int lmin,lmax;
+ struct pvr2_ctrl *hcp,*vcp;
int h = vf->fmt.pix.height;
int w = vf->fmt.pix.width;
-
- if (h < 200) {
- h = 200;
- } else if (h > 625) {
- h = 625;
+ hcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_HRES);
+ vcp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_VRES);
+
+ lmin = pvr2_ctrl_get_min(hcp);
+ lmax = pvr2_ctrl_get_max(hcp);
+ if (w < lmin) {
+ w = lmin;
+ } else if (w > lmax) {
+ w = lmax;
}
- if (w < 320) {
- w = 320;
- } else if (w > 720) {
- w = 720;
+ lmin = pvr2_ctrl_get_min(vcp);
+ lmax = pvr2_ctrl_get_max(vcp);
+ if (h < lmin) {
+ h = lmin;
+ } else if (h > lmax) {
+ h = lmax;
}
memcpy(vf, &pvr_format[PVR_FORMAT_PIX],
@@ -479,14 +477,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
vf->fmt.pix.height = h;
if (cmd == VIDIOC_S_FMT) {
- pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,
- PVR2_CID_HRES),
- vf->fmt.pix.width);
- pvr2_ctrl_set_value(
- pvr2_hdw_get_ctrl_by_id(hdw,
- PVR2_CID_VRES),
- vf->fmt.pix.height);
+ pvr2_ctrl_set_value(hcp,vf->fmt.pix.width);
+ pvr2_ctrl_set_value(vcp,vf->fmt.pix.height);
}
} break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
@@ -669,6 +661,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
ret = 0;
break;
}
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_INT_G_REGISTER:
+ case VIDIOC_INT_S_REGISTER:
+ {
+ u32 val;
+ struct v4l2_register *req = (struct v4l2_register *)arg;
+ if (cmd == VIDIOC_INT_S_REGISTER) val = req->val;
+ ret = pvr2_hdw_register_access(
+ hdw,req->i2c_id,req->reg,
+ cmd == VIDIOC_INT_S_REGISTER,&val);
+ if (cmd == VIDIOC_INT_G_REGISTER) req->val = val;
+ break;
+ }
+#endif
default :
ret = v4l_compat_translate_ioctl(inode,file,cmd,
@@ -702,21 +708,22 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n",
- dip->vdev->minor,pvr2_config_get_name(dip->config));
- if (dip->ctxt_idx >= 0) {
- mutex_lock(&device_lock);
- devices[dip->ctxt_idx] = NULL;
- dip->ctxt_idx = -1;
- mutex_unlock(&device_lock);
- }
- video_unregister_device(dip->vdev);
+ dip->devbase.minor,pvr2_config_get_name(dip->config));
+
+ /* Paranoia */
+ dip->v4lp = 0;
+ dip->stream = 0;
+
+ /* Actual deallocation happens later when all internal references
+ are gone. */
+ video_unregister_device(&dip->devbase);
}
static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
{
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1);
- pvr2_v4l2_dev_destroy(&vp->video_dev);
+ pvr2_v4l2_dev_destroy(vp->vdev);
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
@@ -724,6 +731,14 @@ static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
}
+static void pvr2_video_device_release(struct video_device *vdev)
+{
+ struct pvr2_v4l2_dev *dev;
+ dev = container_of(vdev,struct pvr2_v4l2_dev,devbase);
+ kfree(dev);
+}
+
+
static void pvr2_v4l2_internal_check(struct pvr2_channel *chp)
{
struct pvr2_v4l2 *vp;
@@ -795,40 +810,12 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
static int pvr2_v4l2_open(struct inode *inode, struct file *file)
{
- struct pvr2_v4l2_dev *dip = NULL; /* Our own context pointer */
+ struct pvr2_v4l2_dev *dip; /* Our own context pointer */
struct pvr2_v4l2_fh *fhp;
struct pvr2_v4l2 *vp;
struct pvr2_hdw *hdw;
- mutex_lock(&device_lock);
- /* MCI 7-Jun-2006 Even though we're just doing what amounts to an
- atomic read of the device mapping array here, we still need the
- mutex. The problem is that there is a tiny race possible when
- we register the device. We can't update the device mapping
- array until after the device has been registered, owing to the
- fact that we can't know the minor device number until after the
- registration succeeds. And if another thread tries to open the
- device in the window of time after registration but before the
- map is updated, then it will get back an erroneous null pointer
- and the open will result in a spurious failure. The only way to
- prevent that is to (a) be inside the mutex here before we access
- the array, and (b) cover the entire registration process later
- on with this same mutex. Thus if we get inside the mutex here,
- then we can be assured that the registration process actually
- completed correctly. This is an unhappy complication from the
- use of global data in a driver that lives in a preemptible
- environment. It sure would be nice if the video device itself
- had a means for storing and retrieving a local context pointer.
- Oh wait. It did. But now it's gone. Silly me. */
- {
- unsigned int midx = iminor(file->f_dentry->d_inode);
- if (midx < sizeof(devices)/sizeof(devices[0])) {
- dip = devices[midx];
- }
- }
- mutex_unlock(&device_lock);
-
- if (!dip) return -ENODEV; /* Should be impossible but I'm paranoid */
+ dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
vp = dip->v4lp;
hdw = vp->channel.hdw;
@@ -1058,38 +1045,24 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
return;
}
- dip->vdev = video_device_alloc();
- if (!dip->vdev) {
- err("Alloc of pvrusb2 v4l video device failed");
- return;
- }
-
- memcpy(dip->vdev,&vdev_template,sizeof(vdev_template));
- dip->vdev->release = video_device_release;
- mutex_lock(&device_lock);
+ memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template));
+ dip->devbase.release = pvr2_video_device_release;
mindevnum = -1;
unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw);
if ((unit_number >= 0) && (unit_number < PVR_NUM)) {
mindevnum = video_nr[unit_number];
}
- if ((video_register_device(dip->vdev, v4l_type, mindevnum) < 0) &&
- (video_register_device(dip->vdev, v4l_type, -1) < 0)) {
+ if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
+ (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
err("Failed to register pvrusb2 v4l video device");
} else {
printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
- dip->vdev->minor,pvr2_config_get_name(dip->config));
- }
-
- if ((dip->vdev->minor < sizeof(devices)/sizeof(devices[0])) &&
- (devices[dip->vdev->minor] == NULL)) {
- dip->ctxt_idx = dip->vdev->minor;
- devices[dip->ctxt_idx] = dip;
+ dip->devbase.minor,pvr2_config_get_name(dip->config));
}
- mutex_unlock(&device_lock);
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
- dip->vdev->minor);
+ dip->devbase.minor);
}
@@ -1100,15 +1073,19 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
vp = kmalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
memset(vp,0,sizeof(*vp));
- vp->video_dev.ctxt_idx = -1;
+ vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
+ if (!vp->vdev) {
+ kfree(vp);
+ return 0;
+ }
+ memset(vp->vdev,0,sizeof(*vp->vdev));
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check;
/* register streams */
- pvr2_v4l2_dev_init(&vp->video_dev,vp,pvr2_config_mpeg);
-
+ pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
return vp;
}
diff --git a/drivers/media/video/pwc/philips.txt b/drivers/media/video/pwc/philips.txt
index 11f751a6bda5..f5e848410311 100644
--- a/drivers/media/video/pwc/philips.txt
+++ b/drivers/media/video/pwc/philips.txt
@@ -175,8 +175,8 @@ dev_hint
- If a device node is already occupied, registration will fail and
the webcam is not available.
- You can have up to 64 video devices; be sure to make enough device
- nodes in /dev if you want to spread the numbers (this does not apply
- to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA).
+ nodes in /dev if you want to spread the numbers.
+ After /dev/video9 comes /dev/video10 (not /dev/videoA).
- If a camera does not match any dev_hint, it will simply get assigned
the first available device node, just as it used to be.
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index d4703944df9c..46c114830884 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -682,7 +682,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_
/* This gets called for the Isochronous pipe (video). This is done in
* interrupt time, so it has to be fast, not crash, and not stall. Neat.
*/
-static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
+static void pwc_isoc_handler(struct urb *urb)
{
struct pwc_device *pdev;
int i, fst, flen;
@@ -711,7 +711,7 @@ static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs)
case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break;
case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break;
case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break;
- case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break;
+ case -ETIME: errmsg = "Device does not respond"; break;
}
PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg);
/* Give up after a number of contiguous errors on the USB bus.
@@ -1024,12 +1024,25 @@ static ssize_t show_snapshot_button_status(struct class_device *class_dev, char
static CLASS_DEVICE_ATTR(button, S_IRUGO | S_IWUSR, show_snapshot_button_status,
NULL);
-static void pwc_create_sysfs_files(struct video_device *vdev)
+static int pwc_create_sysfs_files(struct video_device *vdev)
{
struct pwc_device *pdev = video_get_drvdata(vdev);
- if (pdev->features & FEATURE_MOTOR_PANTILT)
- video_device_create_file(vdev, &class_device_attr_pan_tilt);
- video_device_create_file(vdev, &class_device_attr_button);
+ int rc;
+
+ rc = video_device_create_file(vdev, &class_device_attr_button);
+ if (rc)
+ goto err;
+ if (pdev->features & FEATURE_MOTOR_PANTILT) {
+ rc = video_device_create_file(vdev,&class_device_attr_pan_tilt);
+ if (rc) goto err_button;
+ }
+
+ return 0;
+
+err_button:
+ video_device_remove_file(vdev, &class_device_attr_button);
+err:
+ return rc;
}
static void pwc_remove_sysfs_files(struct video_device *vdev)
@@ -1408,7 +1421,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
struct usb_device *udev = interface_to_usbdev(intf);
struct pwc_device *pdev = NULL;
int vendor_id, product_id, type_id;
- int i, hint;
+ int i, hint, rc;
int features = 0;
int video_nr = -1; /* default: use next available device */
char serial_number[30], *name;
@@ -1709,9 +1722,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
if (i < 0) {
PWC_ERROR("Failed to register as video device (%d).\n", i);
- video_device_release(pdev->vdev); /* Drip... drip... drip... */
- kfree(pdev); /* Oops, no memory leaks please */
- return -EIO;
+ rc = i;
+ goto err;
}
else {
PWC_INFO("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F);
@@ -1723,13 +1735,24 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
usb_set_intfdata (intf, pdev);
- pwc_create_sysfs_files(pdev->vdev);
+ rc = pwc_create_sysfs_files(pdev->vdev);
+ if (rc)
+ goto err_unreg;
/* Set the leds off */
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
return 0;
+
+err_unreg:
+ if (hint < MAX_DEV_HINTS)
+ device_hint[hint].pdev = NULL;
+ video_unregister_device(pdev->vdev);
+err:
+ video_device_release(pdev->vdev); /* Drip... drip... drip... */
+ kfree(pdev); /* Oops, no memory leaks please */
+ return rc;
}
/* The user janked out the cable... */
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
index 59a187272c83..77bb940a1a4f 100644
--- a/drivers/media/video/saa5246a.c
+++ b/drivers/media/video/saa5246a.c
@@ -830,7 +830,6 @@ static struct video_device saa_template =
.owner = THIS_MODULE,
.name = IF_NAME,
.type = VID_TYPE_TELETEXT,
- .hardware = VID_HARDWARE_SAA5249,
.fops = &saa_fops,
.release = video_device_release,
.minor = -1,
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index 19a8d65699f8..bb3fb4387f65 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -713,7 +713,6 @@ static struct video_device saa_template =
.owner = THIS_MODULE,
.name = IF_NAME,
.type = VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */
- .hardware = VID_HARDWARE_SAA5249,
.fops = &saa_fops,
};
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index b59c11717273..c5719f7bd1ac 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -1,4 +1,6 @@
-/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver
+/* saa711x - Philips SAA711x video decoder driver
+ * This driver can work with saa7111, saa7111a, saa7113, saa7114,
+ * saa7115 and saa7118.
*
* Based on saa7114 driver by Maxim Yevtyushkin, which is based on
* the saa7111 driver by Dave Perks.
@@ -16,7 +18,9 @@
* (2/17/2003)
*
* VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl>
- * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
+ * SAA7111, SAA7113 and SAA7118 support
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -33,6 +37,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+#include "saa711x_regs.h"
#include <linux/kernel.h>
#include <linux/module.h>
@@ -43,7 +48,9 @@
#include <media/saa7115.h>
#include <asm/div64.h>
-MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver");
+#define VRES_60HZ (480+16)
+
+MODULE_DESCRIPTION("Philips SAA7111/SAA7113/SAA7114/SAA7115/SAA7118 video decoder driver");
MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
"Hans Verkuil, Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
@@ -54,14 +61,14 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
static unsigned short normal_i2c[] = {
- 0x4a >> 1, 0x48 >> 1, /* SAA7113 */
- 0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */
+ 0x4a >> 1, 0x48 >> 1, /* SAA7111, SAA7111A and SAA7113 */
+ 0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
-struct saa7115_state {
+struct saa711x_state {
v4l2_std_id std;
int input;
int enable;
@@ -70,6 +77,8 @@ struct saa7115_state {
int contrast;
int hue;
int sat;
+ int width;
+ int height;
enum v4l2_chip_ident ident;
u32 audclk_freq;
u32 crystal_freq;
@@ -80,420 +89,508 @@ struct saa7115_state {
/* ----------------------------------------------------------------------- */
-static inline int saa7115_write(struct i2c_client *client, u8 reg, u8 value)
+static inline int saa711x_write(struct i2c_client *client, u8 reg, u8 value)
{
return i2c_smbus_write_byte_data(client, reg, value);
}
-static int saa7115_writeregs(struct i2c_client *client, const unsigned char *regs)
+/* Sanity routine to check if a register is present */
+static int saa711x_has_reg(const int id, const u8 reg)
{
+ if (id == V4L2_IDENT_SAA7111)
+ return reg < 0x20 && reg != 0x01 && reg != 0x0f &&
+ (reg < 0x13 || reg > 0x19) && reg != 0x1d && reg != 0x1e;
+
+ /* common for saa7113/4/5/8 */
+ if (unlikely((reg >= 0x3b && reg <= 0x3f) || reg == 0x5c || reg == 0x5f ||
+ reg == 0xa3 || reg == 0xa7 || reg == 0xab || reg == 0xaf || (reg >= 0xb5 && reg <= 0xb7) ||
+ reg == 0xd3 || reg == 0xd7 || reg == 0xdb || reg == 0xdf || (reg >= 0xe5 && reg <= 0xe7) ||
+ reg == 0x82 || (reg >= 0x89 && reg <= 0x8e)))
+ return 0;
+
+ switch (id) {
+ case V4L2_IDENT_SAA7113:
+ return reg != 0x14 && (reg < 0x18 || reg > 0x1e) && (reg < 0x20 || reg > 0x3f) &&
+ reg != 0x5d && reg < 0x63;
+ case V4L2_IDENT_SAA7114:
+ return (reg < 0x1a || reg > 0x1e) && (reg < 0x20 || reg > 0x2f) &&
+ (reg < 0x63 || reg > 0x7f) && reg != 0x33 && reg != 0x37 &&
+ reg != 0x81 && reg < 0xf0;
+ case V4L2_IDENT_SAA7115:
+ return (reg < 0x20 || reg > 0x2f) && reg != 0x65 && (reg < 0xfc || reg > 0xfe);
+ case V4L2_IDENT_SAA7118:
+ return (reg < 0x1a || reg > 0x1d) && (reg < 0x20 || reg > 0x22) &&
+ (reg < 0x26 || reg > 0x28) && reg != 0x33 && reg != 0x37 &&
+ (reg < 0x63 || reg > 0x7f) && reg != 0x81 && reg < 0xf0;
+ }
+ return 1;
+}
+
+static int saa711x_writeregs(struct i2c_client *client, const unsigned char *regs)
+{
+ struct saa711x_state *state = i2c_get_clientdata(client);
unsigned char reg, data;
while (*regs != 0x00) {
reg = *(regs++);
data = *(regs++);
- if (saa7115_write(client, reg, data) < 0)
- return -1;
+
+ /* According with datasheets, reserved regs should be
+ filled with 0 - seems better not to touch on they */
+ if (saa711x_has_reg(state->ident,reg)) {
+ if (saa711x_write(client, reg, data) < 0)
+ return -1;
+ } else {
+ v4l_dbg(1, debug, client, "tried to access reserved reg 0x%02x\n", reg);
+ }
}
return 0;
}
-static inline int saa7115_read(struct i2c_client *client, u8 reg)
+static inline int saa711x_read(struct i2c_client *client, u8 reg)
{
return i2c_smbus_read_byte_data(client, reg);
}
/* ----------------------------------------------------------------------- */
+/* SAA7111 initialization table */
+static const unsigned char saa7111_init[] = {
+ R_01_INC_DELAY, 0x00, /* reserved */
+
+ /*front end */
+ R_02_INPUT_CNTL_1, 0xd0, /* FUSE=3, GUDL=2, MODE=0 */
+ R_03_INPUT_CNTL_2, 0x23, /* HLNRS=0, VBSL=1, WPOFF=0, HOLDG=0,
+ * GAFIX=0, GAI1=256, GAI2=256 */
+ R_04_INPUT_CNTL_3, 0x00, /* GAI1=256 */
+ R_05_INPUT_CNTL_4, 0x00, /* GAI2=256 */
+
+ /* decoder */
+ R_06_H_SYNC_START, 0xf3, /* HSB at 13(50Hz) / 17(60Hz)
+ * pixels after end of last line */
+ R_07_H_SYNC_STOP, 0xe8, /* HSS seems to be needed to
+ * work with NTSC, too */
+ R_08_SYNC_CNTL, 0xc8, /* AUFD=1, FSEL=1, EXFIL=0,
+ * VTRC=1, HPLL=0, VNOI=0 */
+ R_09_LUMA_CNTL, 0x01, /* BYPS=0, PREF=0, BPSS=0,
+ * VBLB=0, UPTCV=0, APER=1 */
+ R_0A_LUMA_BRIGHT_CNTL, 0x80,
+ R_0B_LUMA_CONTRAST_CNTL, 0x47, /* 0b - CONT=1.109 */
+ R_0C_CHROMA_SAT_CNTL, 0x40,
+ R_0D_CHROMA_HUE_CNTL, 0x00,
+ R_0E_CHROMA_CNTL_1, 0x01, /* 0e - CDTO=0, CSTD=0, DCCF=0,
+ * FCTC=0, CHBW=1 */
+ R_0F_CHROMA_GAIN_CNTL, 0x00, /* reserved */
+ R_10_CHROMA_CNTL_2, 0x48, /* 10 - OFTS=1, HDEL=0, VRLN=1, YDEL=0 */
+ R_11_MODE_DELAY_CNTL, 0x1c, /* 11 - GPSW=0, CM99=0, FECO=0, COMPO=1,
+ * OEYC=1, OEHV=1, VIPB=0, COLO=0 */
+ R_12_RT_SIGNAL_CNTL, 0x00, /* 12 - output control 2 */
+ R_13_RT_X_PORT_OUT_CNTL, 0x00, /* 13 - output control 3 */
+ R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+ R_15_VGATE_START_FID_CHG, 0x00,
+ R_16_VGATE_STOP, 0x00,
+ R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
+
+ 0x00, 0x00
+};
+
+/* SAA7113 init codes */
+static const unsigned char saa7113_init[] = {
+ R_01_INC_DELAY, 0x08,
+ R_02_INPUT_CNTL_1, 0xc2,
+ R_03_INPUT_CNTL_2, 0x30,
+ R_04_INPUT_CNTL_3, 0x00,
+ R_05_INPUT_CNTL_4, 0x00,
+ R_06_H_SYNC_START, 0x89,
+ R_07_H_SYNC_STOP, 0x0d,
+ R_08_SYNC_CNTL, 0x88,
+ R_09_LUMA_CNTL, 0x01,
+ R_0A_LUMA_BRIGHT_CNTL, 0x80,
+ R_0B_LUMA_CONTRAST_CNTL, 0x47,
+ R_0C_CHROMA_SAT_CNTL, 0x40,
+ R_0D_CHROMA_HUE_CNTL, 0x00,
+ R_0E_CHROMA_CNTL_1, 0x01,
+ R_0F_CHROMA_GAIN_CNTL, 0x2a,
+ R_10_CHROMA_CNTL_2, 0x08,
+ R_11_MODE_DELAY_CNTL, 0x0c,
+ R_12_RT_SIGNAL_CNTL, 0x07,
+ R_13_RT_X_PORT_OUT_CNTL, 0x00,
+ R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+ R_15_VGATE_START_FID_CHG, 0x00,
+ R_16_VGATE_STOP, 0x00,
+ R_17_MISC_VGATE_CONF_AND_MSB, 0x00,
+
+ 0x00, 0x00
+};
+
/* If a value differs from the Hauppauge driver values, then the comment starts with
'was 0xXX' to denote the Hauppauge value. Otherwise the value is identical to what the
Hauppauge driver sets. */
+/* SAA7114 and SAA7115 initialization table */
static const unsigned char saa7115_init_auto_input[] = {
/* Front-End Part */
- 0x01, 0x48, /* white peak control disabled */
- 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */
- 0x04, 0x90, /* analog gain set to 0 */
- 0x05, 0x90, /* analog gain set to 0 */
+ R_01_INC_DELAY, 0x48, /* white peak control disabled */
+ R_03_INPUT_CNTL_2, 0x20, /* was 0x30. 0x20: long vertical blanking */
+ R_04_INPUT_CNTL_3, 0x90, /* analog gain set to 0 */
+ R_05_INPUT_CNTL_4, 0x90, /* analog gain set to 0 */
/* Decoder Part */
- 0x06, 0xeb, /* horiz sync begin = -21 */
- 0x07, 0xe0, /* horiz sync stop = -17 */
- 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
- 0x0b, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
- 0x0c, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
- 0x0d, 0x00, /* chrominance hue control */
- 0x0f, 0x00, /* chrominance gain control: use automicatic mode */
- 0x10, 0x06, /* chrominance/luminance control: active adaptive combfilter */
- 0x11, 0x00, /* delay control */
- 0x12, 0x9d, /* RTS0 output control: VGATE */
- 0x13, 0x80, /* X-port output control: ITU656 standard mode, RTCO output enable RTCE */
- 0x14, 0x00, /* analog/ADC/auto compatibility control */
- 0x18, 0x40, /* raw data gain 0x00 = nominal */
- 0x19, 0x80, /* raw data offset 0x80 = 0 LSB */
- 0x1a, 0x77, /* color killer level control 0x77 = recommended */
- 0x1b, 0x42, /* misc chroma control 0x42 = recommended */
- 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */
- 0x1d, 0x01, /* combfilter control 0x01 = recommended */
+ R_06_H_SYNC_START, 0xeb, /* horiz sync begin = -21 */
+ R_07_H_SYNC_STOP, 0xe0, /* horiz sync stop = -17 */
+ R_09_LUMA_CNTL, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
+ R_0A_LUMA_BRIGHT_CNTL, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */
+ R_0B_LUMA_CONTRAST_CNTL, 0x44, /* was 0x48. decoder contrast, 0x44 is itu standard */
+ R_0C_CHROMA_SAT_CNTL, 0x40, /* was 0x47. decoder saturation, 0x40 is itu standard */
+ R_0D_CHROMA_HUE_CNTL, 0x00,
+ R_0F_CHROMA_GAIN_CNTL, 0x00, /* use automatic gain */
+ R_10_CHROMA_CNTL_2, 0x06, /* chroma: active adaptive combfilter */
+ R_11_MODE_DELAY_CNTL, 0x00,
+ R_12_RT_SIGNAL_CNTL, 0x9d, /* RTS0 output control: VGATE */
+ R_13_RT_X_PORT_OUT_CNTL, 0x80, /* ITU656 standard mode, RTCO output enable RTCE */
+ R_14_ANAL_ADC_COMPAT_CNTL, 0x00,
+ R_18_RAW_DATA_GAIN_CNTL, 0x40, /* gain 0x00 = nominal */
+ R_19_RAW_DATA_OFF_CNTL, 0x80,
+ R_1A_COLOR_KILL_LVL_CNTL, 0x77, /* recommended value */
+ R_1B_MISC_TVVCRDET, 0x42, /* recommended value */
+ R_1C_ENHAN_COMB_CTRL1, 0xa9, /* recommended value */
+ R_1D_ENHAN_COMB_CTRL2, 0x01, /* recommended value */
+
+
+ R_80_GLOBAL_CNTL_1, 0x0, /* No tasks enabled at init */
/* Power Device Control */
- 0x88, 0xd0, /* reset device */
- 0x88, 0xf0, /* set device programmed, all in operational mode */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset device */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* set device programmed, all in operational mode */
0x00, 0x00
};
+/* Used to reset saa7113, saa7114 and saa7115 */
static const unsigned char saa7115_cfg_reset_scaler[] = {
- 0x87, 0x00, /* disable I-port output */
- 0x88, 0xd0, /* reset scaler */
- 0x88, 0xf0, /* activate scaler */
- 0x87, 0x01, /* enable I-port output */
+ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x00, /* disable I-port output */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
+ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* enable I-port output */
0x00, 0x00
};
/* ============== SAA7715 VIDEO templates ============= */
-static const unsigned char saa7115_cfg_60hz_fullres_x[] = {
- 0xcc, 0xd0, /* hsize low (output), hor. output window size = 0x2d0 = 720 */
- 0xcd, 0x02, /* hsize hi (output) */
+static const unsigned char saa7115_cfg_60hz_video[] = {
+ R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
- /* Why not in 60hz-Land, too? */
- 0xd0, 0x01, /* downscale = 1 */
- 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
- 0xd9, 0x04,
- 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
- 0xdd, 0x02, /* H-scaling incr chroma */
+ R_15_VGATE_START_FID_CHG, 0x03,
+ R_16_VGATE_STOP, 0x11,
+ R_17_MISC_VGATE_CONF_AND_MSB, 0x9c,
- 0x00, 0x00
-};
-static const unsigned char saa7115_cfg_60hz_fullres_y[] = {
- 0xce, 0xf8, /* vsize low (output), ver. output window size = 248 (but 60hz is 240?) */
- 0xcf, 0x00, /* vsize hi (output) */
+ R_08_SYNC_CNTL, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
+ R_0E_CHROMA_CNTL_1, 0x07, /* video autodetection is on */
- /* Why not in 60hz-Land, too? */
- 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
- 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+ R_5A_V_OFF_FOR_SLICER, 0x06, /* standard 60hz value for ITU656 line counting */
- 0xe0, 0x00, /* V-scaling incr luma low */
- 0xe1, 0x04, /* " hi */
- 0xe2, 0x00, /* V-scaling incr chroma low */
- 0xe3, 0x04, /* " hi */
+ /* Task A */
+ R_90_A_TASK_HANDLING_CNTL, 0x80,
+ R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
+ R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
+ R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
- 0x00, 0x00
-};
+ /* hoffset low (input), 0x0002 is minimum */
+ R_94_A_HORIZ_INPUT_WINDOW_START, 0x01,
+ R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
-static const unsigned char saa7115_cfg_60hz_video[] = {
- 0x80, 0x00, /* reset tasks */
- 0x88, 0xd0, /* reset scaler */
+ /* hsize low (input), 0x02d0 = 720 */
+ R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+ R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
- 0x15, 0x03, /* VGATE pulse start */
- 0x16, 0x11, /* VGATE pulse stop */
- 0x17, 0x9c, /* VGATE MSB and other values */
+ R_98_A_VERT_INPUT_WINDOW_START, 0x05,
+ R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
- 0x08, 0x68, /* 0xBO: auto detection, 0x68 = NTSC */
- 0x0e, 0x07, /* lots of different stuff... video autodetection is on */
+ R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x0c,
+ R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
- 0x5a, 0x06, /* Vertical offset, standard 60hz value for ITU656 line counting */
+ R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
+ R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05,
- /* Task A */
- 0x90, 0x80, /* Task Handling Control */
- 0x91, 0x48, /* X-port formats/config */
- 0x92, 0x40, /* Input Ref. signal Def. */
- 0x93, 0x84, /* I-port config */
- 0x94, 0x01, /* hoffset low (input), 0x0002 is minimum */
- 0x95, 0x00, /* hoffset hi (input) */
- 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
- 0x97, 0x02, /* hsize hi (input) */
- 0x98, 0x05, /* voffset low (input) */
- 0x99, 0x00, /* voffset hi (input) */
- 0x9a, 0x0c, /* vsize low (input), 0x0c = 12 */
- 0x9b, 0x00, /* vsize hi (input) */
- 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
- 0x9d, 0x05, /* hsize hi (output) */
- 0x9e, 0x0c, /* vsize low (output), 0x0c = 12 */
- 0x9f, 0x00, /* vsize hi (output) */
+ R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x0c,
+ R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00,
/* Task B */
- 0xc0, 0x00, /* Task Handling Control */
- 0xc1, 0x08, /* X-port formats/config */
- 0xc2, 0x00, /* Input Ref. signal Def. */
- 0xc3, 0x80, /* I-port config */
- 0xc4, 0x02, /* hoffset low (input), 0x0002 is minimum */
- 0xc5, 0x00, /* hoffset hi (input) */
- 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
- 0xc7, 0x02, /* hsize hi (input) */
- 0xc8, 0x12, /* voffset low (input), 0x12 = 18 */
- 0xc9, 0x00, /* voffset hi (input) */
- 0xca, 0xf8, /* vsize low (input), 0xf8 = 248 */
- 0xcb, 0x00, /* vsize hi (input) */
- 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
- 0xcd, 0x02, /* hsize hi (output) */
-
- 0xf0, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
- 0xf1, 0x05, /* low bit with 0xF0 */
- 0xf5, 0xad, /* Set pulse generator register */
- 0xf6, 0x01,
-
- 0x87, 0x00, /* Disable I-port output */
- 0x88, 0xd0, /* reset scaler */
- 0x80, 0x20, /* Activate only task "B", continuous mode (was 0xA0) */
- 0x88, 0xf0, /* activate scaler */
- 0x87, 0x01, /* Enable I-port output */
- 0x00, 0x00
-};
+ R_C0_B_TASK_HANDLING_CNTL, 0x00,
+ R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
+ R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
+ R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
-static const unsigned char saa7115_cfg_50hz_fullres_x[] = {
- 0xcc, 0xd0, /* hsize low (output), 720 same as 60hz */
- 0xcd, 0x02, /* hsize hi (output) */
+ /* 0x0002 is minimum */
+ R_C4_B_HORIZ_INPUT_WINDOW_START, 0x02,
+ R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
- 0xd0, 0x01, /* down scale = 1 */
- 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
- 0xd9, 0x04,
- 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
- 0xdd, 0x02, /* H-scaling incr chroma */
+ /* 0x02d0 = 720 */
+ R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+ R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
- 0x00, 0x00
-};
-static const unsigned char saa7115_cfg_50hz_fullres_y[] = {
- 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
- 0xcf, 0x01, /* vsize hi (output) */
+ /* vwindow start 0x12 = 18 */
+ R_C8_B_VERT_INPUT_WINDOW_START, 0x12,
+ R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+ /* vwindow length 0xf8 = 248 */
+ R_CA_B_VERT_INPUT_WINDOW_LENGTH, VRES_60HZ>>1,
+ R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, VRES_60HZ>>9,
- 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
- 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
+ /* hwindow 0x02d0 = 720 */
+ R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
+ R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
- 0xe0, 0x00, /* V-scaling incr luma low */
- 0xe1, 0x04, /* " hi */
- 0xe2, 0x00, /* V-scaling incr chroma low */
- 0xe3, 0x04, /* " hi */
+ R_F0_LFCO_PER_LINE, 0xad, /* Set PLL Register. 60hz 525 lines per frame, 27 MHz */
+ R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0 */
+ R_F5_PULSGEN_LINE_LENGTH, 0xad,
+ R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
0x00, 0x00
};
static const unsigned char saa7115_cfg_50hz_video[] = {
- 0x80, 0x00, /* reset tasks */
- 0x88, 0xd0, /* reset scaler */
+ R_80_GLOBAL_CNTL_1, 0x00,
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
- 0x15, 0x37, /* VGATE start */
- 0x16, 0x16, /* VGATE stop */
- 0x17, 0x99, /* VGATE MSB and other values */
+ R_15_VGATE_START_FID_CHG, 0x37, /* VGATE start */
+ R_16_VGATE_STOP, 0x16,
+ R_17_MISC_VGATE_CONF_AND_MSB, 0x99,
- 0x08, 0x28, /* 0x28 = PAL */
- 0x0e, 0x07, /* chrominance control 1 */
+ R_08_SYNC_CNTL, 0x28, /* 0x28 = PAL */
+ R_0E_CHROMA_CNTL_1, 0x07,
- 0x5a, 0x03, /* Vertical offset, standard 50hz value */
+ R_5A_V_OFF_FOR_SLICER, 0x03, /* standard 50hz value */
/* Task A */
- 0x90, 0x81, /* Task Handling Control */
- 0x91, 0x48, /* X-port formats/config */
- 0x92, 0x40, /* Input Ref. signal Def. */
- 0x93, 0x84, /* I-port config */
+ R_90_A_TASK_HANDLING_CNTL, 0x81,
+ R_91_A_X_PORT_FORMATS_AND_CONF, 0x48,
+ R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL, 0x40,
+ R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF, 0x84,
+
/* This is weird: the datasheet says that you should use 2 as the minimum value, */
/* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
- 0x94, 0x00, /* hoffset low (input), 0x0002 is minimum */
- 0x95, 0x00, /* hoffset hi (input) */
- 0x96, 0xd0, /* hsize low (input), 0x02d0 = 720 */
- 0x97, 0x02, /* hsize hi (input) */
- 0x98, 0x03, /* voffset low (input) */
- 0x99, 0x00, /* voffset hi (input) */
- 0x9a, 0x12, /* vsize low (input), 0x12 = 18 */
- 0x9b, 0x00, /* vsize hi (input) */
- 0x9c, 0xa0, /* hsize low (output), 0x05a0 = 1440 */
- 0x9d, 0x05, /* hsize hi (output) */
- 0x9e, 0x12, /* vsize low (output), 0x12 = 18 */
- 0x9f, 0x00, /* vsize hi (output) */
+ /* hoffset low (input), 0x0002 is minimum */
+ R_94_A_HORIZ_INPUT_WINDOW_START, 0x00,
+ R_95_A_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+ /* hsize low (input), 0x02d0 = 720 */
+ R_96_A_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+ R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+ R_98_A_VERT_INPUT_WINDOW_START, 0x03,
+ R_99_A_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+ /* vsize 0x12 = 18 */
+ R_9A_A_VERT_INPUT_WINDOW_LENGTH, 0x12,
+ R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB, 0x00,
+
+ /* hsize 0x05a0 = 1440 */
+ R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH, 0xa0,
+ R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x05, /* hsize hi (output) */
+ R_9E_A_VERT_OUTPUT_WINDOW_LENGTH, 0x12, /* vsize low (output), 0x12 = 18 */
+ R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB, 0x00, /* vsize hi (output) */
/* Task B */
- 0xc0, 0x00, /* Task Handling Control */
- 0xc1, 0x08, /* X-port formats/config */
- 0xc2, 0x00, /* Input Ref. signal Def. */
- 0xc3, 0x80, /* I-port config */
- 0xc4, 0x00, /* hoffset low (input), 0x0002 is minimum. See comment at 0x94 above. */
- 0xc5, 0x00, /* hoffset hi (input) */
- 0xc6, 0xd0, /* hsize low (input), 0x02d0 = 720 */
- 0xc7, 0x02, /* hsize hi (input) */
- 0xc8, 0x16, /* voffset low (input), 0x16 = 22 */
- 0xc9, 0x00, /* voffset hi (input) */
- 0xca, 0x20, /* vsize low (input), 0x0120 = 288 */
- 0xcb, 0x01, /* vsize hi (input) */
- 0xcc, 0xd0, /* hsize low (output), 0x02d0 = 720 */
- 0xcd, 0x02, /* hsize hi (output) */
- 0xce, 0x20, /* vsize low (output), 0x0120 = 288 */
- 0xcf, 0x01, /* vsize hi (output) */
-
- 0xf0, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
- 0xf1, 0x05, /* low bit with 0xF0, (was 0x05) */
- 0xf5, 0xb0, /* Set pulse generator register */
- 0xf6, 0x01,
-
- 0x87, 0x00, /* Disable I-port output */
- 0x88, 0xd0, /* reset scaler (was 0xD0) */
- 0x80, 0x20, /* Activate only task "B" */
- 0x88, 0xf0, /* activate scaler */
- 0x87, 0x01, /* Enable I-port output */
+ R_C0_B_TASK_HANDLING_CNTL, 0x00,
+ R_C1_B_X_PORT_FORMATS_AND_CONF, 0x08,
+ R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION, 0x00,
+ R_C3_B_I_PORT_FORMATS_AND_CONF, 0x80,
+
+ /* This is weird: the datasheet says that you should use 2 as the minimum value, */
+ /* but Hauppauge uses 0, and changing that to 2 causes indeed problems (for 50hz) */
+ /* hoffset low (input), 0x0002 is minimum. See comment above. */
+ R_C4_B_HORIZ_INPUT_WINDOW_START, 0x00,
+ R_C5_B_HORIZ_INPUT_WINDOW_START_MSB, 0x00,
+
+ /* hsize 0x02d0 = 720 */
+ R_C6_B_HORIZ_INPUT_WINDOW_LENGTH, 0xd0,
+ R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB, 0x02,
+
+ /* voffset 0x16 = 22 */
+ R_C8_B_VERT_INPUT_WINDOW_START, 0x16,
+ R_C9_B_VERT_INPUT_WINDOW_START_MSB, 0x00,
+
+ /* vsize 0x0120 = 288 */
+ R_CA_B_VERT_INPUT_WINDOW_LENGTH, 0x20,
+ R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB, 0x01,
+
+ /* hsize 0x02d0 = 720 */
+ R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH, 0xd0,
+ R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB, 0x02,
+
+ R_F0_LFCO_PER_LINE, 0xb0, /* Set PLL Register. 50hz 625 lines per frame, 27 MHz */
+ R_F1_P_I_PARAM_SELECT, 0x05, /* low bit with 0xF0, (was 0x05) */
+ R_F5_PULSGEN_LINE_LENGTH, 0xb0,
+ R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG, 0x01,
+
0x00, 0x00
};
/* ============== SAA7715 VIDEO templates (end) ======= */
static const unsigned char saa7115_cfg_vbi_on[] = {
- 0x80, 0x00, /* reset tasks */
- 0x88, 0xd0, /* reset scaler */
- 0x80, 0x30, /* Activate both tasks */
- 0x88, 0xf0, /* activate scaler */
- 0x87, 0x01, /* Enable I-port output */
+ R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
+ R_80_GLOBAL_CNTL_1, 0x30, /* Activate both tasks */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
+ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
+
0x00, 0x00
};
static const unsigned char saa7115_cfg_vbi_off[] = {
- 0x80, 0x00, /* reset tasks */
- 0x88, 0xd0, /* reset scaler */
- 0x80, 0x20, /* Activate only task "B" */
- 0x88, 0xf0, /* activate scaler */
- 0x87, 0x01, /* Enable I-port output */
- 0x00, 0x00
-};
+ R_80_GLOBAL_CNTL_1, 0x00, /* reset tasks */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0, /* reset scaler */
+ R_80_GLOBAL_CNTL_1, 0x20, /* Activate only task "B" */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0, /* activate scaler */
+ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01, /* Enable I-port output */
-static const unsigned char saa7113_init_auto_input[] = {
- 0x01, 0x08, /* PH7113_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */
- 0x02, 0xc2, /* PH7113_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */
- 0x03, 0x30, /* PH7113_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */
- 0x04, 0x00, /* PH7113_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */
- 0x05, 0x00, /* PH7113_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */
- 0x06, 0x89, /* PH7113_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */
- 0x07, 0x0d, /* PH7113_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */
- 0x08, 0x88, /* PH7113_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */
- 0x09, 0x01, /* PH7113_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */
- 0x0a, 0x80, /* PH7113_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */
- 0x0b, 0x47, /* PH7113_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */
- 0x0c, 0x40, /* PH7113_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */
- 0x0d, 0x00, /* PH7113_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */
- 0x0e, 0x01, /* PH7113_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */
- 0x0f, 0x2a, /* PH7113_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */
- 0x10, 0x08, /* PH7113_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */
- 0x11, 0x0c, /* PH7113_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */
- 0x12, 0x07, /* PH7113_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */
- 0x13, 0x00, /* PH7113_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */
- 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */
- 0x15, 0x00, /* PH7113_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */
- 0x16, 0x00, /* PH7113_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */
- 0x17, 0x00, /* PH7113_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */
0x00, 0x00
};
+
static const unsigned char saa7115_init_misc[] = {
- 0x81, 0x01, /* reg 0x15,0x16 define blanking window */
- 0x82, 0x00,
- 0x83, 0x01, /* I port settings */
- 0x84, 0x20,
- 0x85, 0x21,
- 0x86, 0xc5,
- 0x87, 0x01,
+ R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F, 0x01,
+ R_83_X_PORT_I_O_ENA_AND_OUT_CLK, 0x01,
+ R_84_I_PORT_SIGNAL_DEF, 0x20,
+ R_85_I_PORT_SIGNAL_POLAR, 0x21,
+ R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT, 0xc5,
+ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 0x01,
/* Task A */
- 0xa0, 0x01, /* down scale = 1 */
- 0xa1, 0x00, /* prescale accumulation length = 1 */
- 0xa2, 0x00, /* dc gain and fir prefilter control */
- 0xa4, 0x80, /* Lum Brightness, nominal value = 0x80 */
- 0xa5, 0x40, /* Lum contrast, nominal value = 0x40 */
- 0xa6, 0x40, /* Chroma satur. nominal value = 0x80 */
- 0xa8, 0x00, /* hor lum scaling 0x0200 = 2 zoom */
- 0xa9, 0x02, /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
- 0xaa, 0x00, /* H-phase offset Luma = 0 */
- 0xac, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
- 0xad, 0x01, /* H-scaling incr chroma */
- 0xae, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
-
- 0xb0, 0x00, /* V-scaling incr luma low */
- 0xb1, 0x04, /* " hi */
- 0xb2, 0x00, /* V-scaling incr chroma low */
- 0xb3, 0x04, /* " hi */
- 0xb4, 0x01, /* V-scaling mode control */
- 0xb8, 0x00, /* V-phase offset chroma 00 */
- 0xb9, 0x00, /* V-phase offset chroma 01 */
- 0xba, 0x00, /* V-phase offset chroma 10 */
- 0xbb, 0x00, /* V-phase offset chroma 11 */
- 0xbc, 0x00, /* V-phase offset luma 00 */
- 0xbd, 0x00, /* V-phase offset luma 01 */
- 0xbe, 0x00, /* V-phase offset luma 10 */
- 0xbf, 0x00, /* V-phase offset luma 11 */
+ R_A0_A_HORIZ_PRESCALING, 0x01,
+ R_A1_A_ACCUMULATION_LENGTH, 0x00,
+ R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
+
+ /* Configure controls at nominal value*/
+ R_A4_A_LUMA_BRIGHTNESS_CNTL, 0x80,
+ R_A5_A_LUMA_CONTRAST_CNTL, 0x40,
+ R_A6_A_CHROMA_SATURATION_CNTL, 0x40,
+
+ /* note: 2 x zoom ensures that VBI lines have same length as video lines. */
+ R_A8_A_HORIZ_LUMA_SCALING_INC, 0x00,
+ R_A9_A_HORIZ_LUMA_SCALING_INC_MSB, 0x02,
+
+ R_AA_A_HORIZ_LUMA_PHASE_OFF, 0x00,
+
+ /* must be horiz lum scaling / 2 */
+ R_AC_A_HORIZ_CHROMA_SCALING_INC, 0x00,
+ R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB, 0x01,
+
+ /* must be offset luma / 2 */
+ R_AE_A_HORIZ_CHROMA_PHASE_OFF, 0x00,
+
+ R_B0_A_VERT_LUMA_SCALING_INC, 0x00,
+ R_B1_A_VERT_LUMA_SCALING_INC_MSB, 0x04,
+
+ R_B2_A_VERT_CHROMA_SCALING_INC, 0x00,
+ R_B3_A_VERT_CHROMA_SCALING_INC_MSB, 0x04,
+
+ R_B4_A_VERT_SCALING_MODE_CNTL, 0x01,
+
+ R_B8_A_VERT_CHROMA_PHASE_OFF_00, 0x00,
+ R_B9_A_VERT_CHROMA_PHASE_OFF_01, 0x00,
+ R_BA_A_VERT_CHROMA_PHASE_OFF_10, 0x00,
+ R_BB_A_VERT_CHROMA_PHASE_OFF_11, 0x00,
+
+ R_BC_A_VERT_LUMA_PHASE_OFF_00, 0x00,
+ R_BD_A_VERT_LUMA_PHASE_OFF_01, 0x00,
+ R_BE_A_VERT_LUMA_PHASE_OFF_10, 0x00,
+ R_BF_A_VERT_LUMA_PHASE_OFF_11, 0x00,
/* Task B */
- 0xd0, 0x01, /* down scale = 1 */
- 0xd1, 0x00, /* prescale accumulation length = 1 */
- 0xd2, 0x00, /* dc gain and fir prefilter control */
- 0xd4, 0x80, /* Lum Brightness, nominal value = 0x80 */
- 0xd5, 0x40, /* Lum contrast, nominal value = 0x40 */
- 0xd6, 0x40, /* Chroma satur. nominal value = 0x80 */
- 0xd8, 0x00, /* hor lum scaling 0x0400 = 1 */
- 0xd9, 0x04,
- 0xda, 0x00, /* H-phase offset Luma = 0 */
- 0xdc, 0x00, /* hor chrom scaling 0x0200. must be hor lum scaling / 2 */
- 0xdd, 0x02, /* H-scaling incr chroma */
- 0xde, 0x00, /* H-phase offset chroma. must be offset luma / 2 */
-
- 0xe0, 0x00, /* V-scaling incr luma low */
- 0xe1, 0x04, /* " hi */
- 0xe2, 0x00, /* V-scaling incr chroma low */
- 0xe3, 0x04, /* " hi */
- 0xe4, 0x01, /* V-scaling mode control */
- 0xe8, 0x00, /* V-phase offset chroma 00 */
- 0xe9, 0x00, /* V-phase offset chroma 01 */
- 0xea, 0x00, /* V-phase offset chroma 10 */
- 0xeb, 0x00, /* V-phase offset chroma 11 */
- 0xec, 0x00, /* V-phase offset luma 00 */
- 0xed, 0x00, /* V-phase offset luma 01 */
- 0xee, 0x00, /* V-phase offset luma 10 */
- 0xef, 0x00, /* V-phase offset luma 11 */
-
- 0xf2, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
- 0xf3, 0x46,
- 0xf4, 0x00,
- 0xf7, 0x4b, /* not the recommended settings! */
- 0xf8, 0x00,
- 0xf9, 0x4b,
- 0xfa, 0x00,
- 0xfb, 0x4b,
- 0xff, 0x88, /* PLL2 lock detection settings: 71 lines 50% phase error */
+ R_D0_B_HORIZ_PRESCALING, 0x01,
+ R_D1_B_ACCUMULATION_LENGTH, 0x00,
+ R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER, 0x00,
+
+ /* Configure controls at nominal value*/
+ R_D4_B_LUMA_BRIGHTNESS_CNTL, 0x80,
+ R_D5_B_LUMA_CONTRAST_CNTL, 0x40,
+ R_D6_B_CHROMA_SATURATION_CNTL, 0x40,
+
+ /* hor lum scaling 0x0400 = 1 */
+ R_D8_B_HORIZ_LUMA_SCALING_INC, 0x00,
+ R_D9_B_HORIZ_LUMA_SCALING_INC_MSB, 0x04,
+
+ R_DA_B_HORIZ_LUMA_PHASE_OFF, 0x00,
+
+ /* must be hor lum scaling / 2 */
+ R_DC_B_HORIZ_CHROMA_SCALING, 0x00,
+ R_DD_B_HORIZ_CHROMA_SCALING_MSB, 0x02,
+
+ /* must be offset luma / 2 */
+ R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA, 0x00,
+
+ R_E0_B_VERT_LUMA_SCALING_INC, 0x00,
+ R_E1_B_VERT_LUMA_SCALING_INC_MSB, 0x04,
+
+ R_E2_B_VERT_CHROMA_SCALING_INC, 0x00,
+ R_E3_B_VERT_CHROMA_SCALING_INC_MSB, 0x04,
+
+ R_E4_B_VERT_SCALING_MODE_CNTL, 0x01,
+
+ R_E8_B_VERT_CHROMA_PHASE_OFF_00, 0x00,
+ R_E9_B_VERT_CHROMA_PHASE_OFF_01, 0x00,
+ R_EA_B_VERT_CHROMA_PHASE_OFF_10, 0x00,
+ R_EB_B_VERT_CHROMA_PHASE_OFF_11, 0x00,
+
+ R_EC_B_VERT_LUMA_PHASE_OFF_00, 0x00,
+ R_ED_B_VERT_LUMA_PHASE_OFF_01, 0x00,
+ R_EE_B_VERT_LUMA_PHASE_OFF_10, 0x00,
+ R_EF_B_VERT_LUMA_PHASE_OFF_11, 0x00,
+
+ R_F2_NOMINAL_PLL2_DTO, 0x50, /* crystal clock = 24.576 MHz, target = 27MHz */
+ R_F3_PLL_INCREMENT, 0x46,
+ R_F4_PLL2_STATUS, 0x00,
+ R_F7_PULSE_A_POS_MSB, 0x4b, /* not the recommended settings! */
+ R_F8_PULSE_B_POS, 0x00,
+ R_F9_PULSE_B_POS_MSB, 0x4b,
+ R_FA_PULSE_C_POS, 0x00,
+ R_FB_PULSE_C_POS_MSB, 0x4b,
+
+ /* PLL2 lock detection settings: 71 lines 50% phase error */
+ R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES, 0x88,
/* Turn off VBI */
- 0x40, 0x20, /* No framing code errors allowed. */
- 0x41, 0xff,
- 0x42, 0xff,
- 0x43, 0xff,
- 0x44, 0xff,
- 0x45, 0xff,
- 0x46, 0xff,
- 0x47, 0xff,
- 0x48, 0xff,
- 0x49, 0xff,
- 0x4a, 0xff,
- 0x4b, 0xff,
- 0x4c, 0xff,
- 0x4d, 0xff,
- 0x4e, 0xff,
- 0x4f, 0xff,
- 0x50, 0xff,
- 0x51, 0xff,
- 0x52, 0xff,
- 0x53, 0xff,
- 0x54, 0xff,
- 0x55, 0xff,
- 0x56, 0xff,
- 0x57, 0xff,
- 0x58, 0x40,
- 0x59, 0x47,
- 0x5b, 0x83,
- 0x5d, 0xbd,
- 0x5e, 0x35,
-
- 0x02, 0x84, /* input tuner -> input 4, amplifier active */
- 0x09, 0x53, /* 0x53, was 0x56 for 60hz. luminance control */
-
- 0x80, 0x20, /* enable task B */
- 0x88, 0xd0,
- 0x88, 0xf0,
+ R_40_SLICER_CNTL_1, 0x20, /* No framing code errors allowed. */
+ R_41_LCR_BASE, 0xff,
+ R_41_LCR_BASE+1, 0xff,
+ R_41_LCR_BASE+2, 0xff,
+ R_41_LCR_BASE+3, 0xff,
+ R_41_LCR_BASE+4, 0xff,
+ R_41_LCR_BASE+5, 0xff,
+ R_41_LCR_BASE+6, 0xff,
+ R_41_LCR_BASE+7, 0xff,
+ R_41_LCR_BASE+8, 0xff,
+ R_41_LCR_BASE+9, 0xff,
+ R_41_LCR_BASE+10, 0xff,
+ R_41_LCR_BASE+11, 0xff,
+ R_41_LCR_BASE+12, 0xff,
+ R_41_LCR_BASE+13, 0xff,
+ R_41_LCR_BASE+14, 0xff,
+ R_41_LCR_BASE+15, 0xff,
+ R_41_LCR_BASE+16, 0xff,
+ R_41_LCR_BASE+17, 0xff,
+ R_41_LCR_BASE+18, 0xff,
+ R_41_LCR_BASE+19, 0xff,
+ R_41_LCR_BASE+20, 0xff,
+ R_41_LCR_BASE+21, 0xff,
+ R_41_LCR_BASE+22, 0xff,
+ R_58_PROGRAM_FRAMING_CODE, 0x40,
+ R_59_H_OFF_FOR_SLICER, 0x47,
+ R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF, 0x83,
+ R_5D_DID, 0xbd,
+ R_5E_SDID, 0x35,
+
+ R_02_INPUT_CNTL_1, 0x84, /* input tuner -> input 4, amplifier active */
+
+ R_80_GLOBAL_CNTL_1, 0x20, /* enable task B */
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xd0,
+ R_88_POWER_SAVE_ADC_PORT_CNTL, 0xf0,
0x00, 0x00
};
-static int saa7115_odd_parity(u8 c)
+static int saa711x_odd_parity(u8 c)
{
c ^= (c >> 4);
c ^= (c >> 2);
@@ -502,7 +599,7 @@ static int saa7115_odd_parity(u8 c)
return c & 1;
}
-static int saa7115_decode_vps(u8 * dst, u8 * p)
+static int saa711x_decode_vps(u8 * dst, u8 * p)
{
static const u8 biphase_tbl[] = {
0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
@@ -549,7 +646,7 @@ static int saa7115_decode_vps(u8 * dst, u8 * p)
return err & 0xf0;
}
-static int saa7115_decode_wss(u8 * p)
+static int saa711x_decode_wss(u8 * p)
{
static const int wss_bits[8] = {
0, 0, 0, 1, 0, 1, 1, 1
@@ -576,26 +673,25 @@ static int saa7115_decode_wss(u8 * p)
return wss;
}
-
-static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+static int saa711x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
u32 acpf;
u32 acni;
u32 hz;
u64 f;
u8 acc = 0; /* reg 0x3a, audio clock control */
+ /* Checks for chips that don't have audio clock (saa7111, saa7113) */
+ if (!saa711x_has_reg(state->ident,R_30_AUD_MAST_CLK_CYCLES_PER_FIELD))
+ return 0;
+
v4l_dbg(1, debug, client, "set audio clock freq: %d\n", freq);
/* sanity check */
if (freq < 32000 || freq > 48000)
return -EINVAL;
- /* The saa7113 has no audio clock */
- if (state->ident == V4L2_IDENT_SAA7113)
- return 0;
-
/* hz is the refresh rate times 100 */
hz = (state->std & V4L2_STD_525_60) ? 5994 : 5000;
/* acpf = (256 * freq) / field_frequency == (256 * 100 * freq) / hz */
@@ -617,22 +713,26 @@ static int saa7115_set_audio_clock_freq(struct i2c_client *client, u32 freq)
if (state->apll)
acc |= 0x08;
- saa7115_write(client, 0x38, 0x03);
- saa7115_write(client, 0x39, 0x10);
- saa7115_write(client, 0x3a, acc);
- saa7115_write(client, 0x30, acpf & 0xff);
- saa7115_write(client, 0x31, (acpf >> 8) & 0xff);
- saa7115_write(client, 0x32, (acpf >> 16) & 0x03);
- saa7115_write(client, 0x34, acni & 0xff);
- saa7115_write(client, 0x35, (acni >> 8) & 0xff);
- saa7115_write(client, 0x36, (acni >> 16) & 0x3f);
+ saa711x_write(client, R_38_CLK_RATIO_AMXCLK_TO_ASCLK, 0x03);
+ saa711x_write(client, R_39_CLK_RATIO_ASCLK_TO_ALRCLK, 0x10);
+ saa711x_write(client, R_3A_AUD_CLK_GEN_BASIC_SETUP, acc);
+
+ saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD, acpf & 0xff);
+ saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+1,
+ (acpf >> 8) & 0xff);
+ saa711x_write(client, R_30_AUD_MAST_CLK_CYCLES_PER_FIELD+2,
+ (acpf >> 16) & 0x03);
+
+ saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC, acni & 0xff);
+ saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+1, (acni >> 8) & 0xff);
+ saa711x_write(client, R_34_AUD_MAST_CLK_NOMINAL_INC+2, (acni >> 16) & 0x3f);
state->audclk_freq = freq;
return 0;
}
-static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -642,7 +742,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
}
state->bright = ctrl->value;
- saa7115_write(client, 0x0a, state->bright);
+ saa711x_write(client, R_0A_LUMA_BRIGHT_CNTL, state->bright);
break;
case V4L2_CID_CONTRAST:
@@ -652,7 +752,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
}
state->contrast = ctrl->value;
- saa7115_write(client, 0x0b, state->contrast);
+ saa711x_write(client, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
break;
case V4L2_CID_SATURATION:
@@ -662,7 +762,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
}
state->sat = ctrl->value;
- saa7115_write(client, 0x0c, state->sat);
+ saa711x_write(client, R_0C_CHROMA_SAT_CNTL, state->sat);
break;
case V4L2_CID_HUE:
@@ -672,7 +772,7 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
}
state->hue = ctrl->value;
- saa7115_write(client, 0x0d, state->hue);
+ saa711x_write(client, R_0D_CHROMA_HUE_CNTL, state->hue);
break;
default:
@@ -682,9 +782,9 @@ static int saa7115_set_v4lctrl(struct i2c_client *client, struct v4l2_control *c
return 0;
}
-static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+static int saa711x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -706,10 +806,115 @@ static int saa7115_get_v4lctrl(struct i2c_client *client, struct v4l2_control *c
return 0;
}
-static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+static int saa711x_set_size(struct i2c_client *client, int width, int height)
+{
+ struct saa711x_state *state = i2c_get_clientdata(client);
+ int HPSC, HFSC;
+ int VSCY;
+ int res;
+ int is_50hz = state->std & V4L2_STD_625_50;
+ int Vsrc = is_50hz ? 576 : 480;
+
+ v4l_dbg(1, debug, client, "decoder set size to %ix%i\n",width,height);
+
+ /* FIXME need better bounds checking here */
+ if ((width < 1) || (width > 1440))
+ return -EINVAL;
+ if ((height < 1) || (height > Vsrc))
+ return -EINVAL;
+
+ if (!saa711x_has_reg(state->ident,R_D0_B_HORIZ_PRESCALING)) {
+ /* Decoder only supports 720 columns and 480 or 576 lines */
+ if (width != 720)
+ return -EINVAL;
+ if (height != Vsrc)
+ return -EINVAL;
+ }
+
+ state->width = width;
+ state->height = height;
+
+ if (!saa711x_has_reg(state->ident, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH))
+ return 0;
+
+ /* probably have a valid size, let's set it */
+ /* Set output width/height */
+ /* width */
+
+ saa711x_write(client, R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,
+ (u8) (width & 0xff));
+ saa711x_write(client, R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB,
+ (u8) ((width >> 8) & 0xff));
+
+ /* Vertical Scaling uses height/2 */
+ res=height/2;
+
+ /* On 60Hz, it is using a higher Vertical Output Size */
+ if (!is_50hz)
+ res+=(VRES_60HZ-480)>>1;
+
+ /* height */
+ saa711x_write(client, R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,
+ (u8) (res & 0xff));
+ saa711x_write(client, R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB,
+ (u8) ((res >> 8) & 0xff));
+
+ /* Scaling settings */
+ /* Hprescaler is floor(inres/outres) */
+ HPSC = (int)(720 / width);
+ /* 0 is not allowed (div. by zero) */
+ HPSC = HPSC ? HPSC : 1;
+ HFSC = (int)((1024 * 720) / (HPSC * width));
+ /* FIXME hardcodes to "Task B"
+ * write H prescaler integer */
+ saa711x_write(client, R_D0_B_HORIZ_PRESCALING,
+ (u8) (HPSC & 0x3f));
+
+ v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
+ /* write H fine-scaling (luminance) */
+ saa711x_write(client, R_D8_B_HORIZ_LUMA_SCALING_INC,
+ (u8) (HFSC & 0xff));
+ saa711x_write(client, R_D9_B_HORIZ_LUMA_SCALING_INC_MSB,
+ (u8) ((HFSC >> 8) & 0xff));
+ /* write H fine-scaling (chrominance)
+ * must be lum/2, so i'll just bitshift :) */
+ saa711x_write(client, R_DC_B_HORIZ_CHROMA_SCALING,
+ (u8) ((HFSC >> 1) & 0xff));
+ saa711x_write(client, R_DD_B_HORIZ_CHROMA_SCALING_MSB,
+ (u8) ((HFSC >> 9) & 0xff));
+
+ VSCY = (int)((1024 * Vsrc) / height);
+ v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
+
+ /* Correct Contrast and Luminance */
+ saa711x_write(client, R_D5_B_LUMA_CONTRAST_CNTL,
+ (u8) (64 * 1024 / VSCY));
+ saa711x_write(client, R_D6_B_CHROMA_SATURATION_CNTL,
+ (u8) (64 * 1024 / VSCY));
+
+ /* write V fine-scaling (luminance) */
+ saa711x_write(client, R_E0_B_VERT_LUMA_SCALING_INC,
+ (u8) (VSCY & 0xff));
+ saa711x_write(client, R_E1_B_VERT_LUMA_SCALING_INC_MSB,
+ (u8) ((VSCY >> 8) & 0xff));
+ /* write V fine-scaling (chrominance) */
+ saa711x_write(client, R_E2_B_VERT_CHROMA_SCALING_INC,
+ (u8) (VSCY & 0xff));
+ saa711x_write(client, R_E3_B_VERT_CHROMA_SCALING_INC_MSB,
+ (u8) ((VSCY >> 8) & 0xff));
+
+ saa711x_writeregs(client, saa7115_cfg_reset_scaler);
+
+ /* Activates task "B" */
+ saa711x_write(client, R_80_GLOBAL_CNTL_1,
+ saa711x_read(client,R_80_GLOBAL_CNTL_1)|0x20);
+
+ return 0;
+}
+
+static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
- int taskb = saa7115_read(client, 0x80) & 0x10;
+ struct saa711x_state *state = i2c_get_clientdata(client);
/* Prevent unnecessary standard changes. During a standard
change the I-Port is temporarily disabled. Any devices
@@ -721,17 +926,21 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
if (std == state->std)
return;
+ state->std = std;
+
// This works for NTSC-M, SECAM-L and the 50Hz PAL variants.
if (std & V4L2_STD_525_60) {
v4l_dbg(1, debug, client, "decoder set standard 60 Hz\n");
- saa7115_writeregs(client, saa7115_cfg_60hz_video);
+ saa711x_writeregs(client, saa7115_cfg_60hz_video);
+ saa711x_set_size(client,720,480);
} else {
v4l_dbg(1, debug, client, "decoder set standard 50 Hz\n");
- saa7115_writeregs(client, saa7115_cfg_50hz_video);
+ saa711x_writeregs(client, saa7115_cfg_50hz_video);
+ saa711x_set_size(client,720,576);
}
/* Register 0E - Bits D6-D4 on NO-AUTO mode
- (SAA7113 doesn't have auto mode)
+ (SAA7111 and SAA7113 doesn't have auto mode)
50 Hz / 625 lines 60 Hz / 525 lines
000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz)
001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz)
@@ -739,8 +948,9 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
011 NTSC N (3.58MHz) PAL M (3.58MHz)
100 reserved NTSC-Japan (3.58MHz)
*/
- if (state->ident == V4L2_IDENT_SAA7113) {
- u8 reg = saa7115_read(client, 0x0e) & 0x8f;
+ if (state->ident == V4L2_IDENT_SAA7111 ||
+ state->ident == V4L2_IDENT_SAA7113) {
+ u8 reg = saa711x_read(client, R_0E_CHROMA_CNTL_1) & 0x8f;
if (std == V4L2_STD_PAL_M) {
reg |= 0x30;
@@ -750,32 +960,33 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
reg |= 0x10;
} else if (std == V4L2_STD_NTSC_M_JP) {
reg |= 0x40;
+ } else if (std == V4L2_STD_SECAM) {
+ reg |= 0x50;
}
- saa7115_write(client, 0x0e, reg);
- }
-
+ saa711x_write(client, R_0E_CHROMA_CNTL_1, reg);
+ } else {
+ /* restart task B if needed */
+ int taskb = saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10;
- state->std = std;
+ if (taskb && state->ident == V4L2_IDENT_SAA7114) {
+ saa711x_writeregs(client, saa7115_cfg_vbi_on);
+ }
- /* restart task B if needed */
- if (taskb && state->ident != V4L2_IDENT_SAA7115) {
- saa7115_writeregs(client, saa7115_cfg_vbi_on);
+ /* switch audio mode too! */
+ saa711x_set_audio_clock_freq(client, state->audclk_freq);
}
-
- /* switch audio mode too! */
- saa7115_set_audio_clock_freq(client, state->audclk_freq);
}
-static v4l2_std_id saa7115_get_v4lstd(struct i2c_client *client)
+static v4l2_std_id saa711x_get_v4lstd(struct i2c_client *client)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
return state->std;
}
-static void saa7115_log_status(struct i2c_client *client)
+static void saa711x_log_status(struct i2c_client *client)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
int reg1e, reg1f;
int signalOk;
int vcr;
@@ -783,7 +994,7 @@ static void saa7115_log_status(struct i2c_client *client)
v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq);
if (state->ident != V4L2_IDENT_SAA7115) {
/* status for the saa7114 */
- reg1f = saa7115_read(client, 0x1f);
+ reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
signalOk = (reg1f & 0xc1) == 0x81;
v4l_info(client, "Video signal: %s\n", signalOk ? "ok" : "bad");
v4l_info(client, "Frequency: %s\n", (reg1f & 0x20) ? "60 Hz" : "50 Hz");
@@ -791,8 +1002,8 @@ static void saa7115_log_status(struct i2c_client *client)
}
/* status for the saa7115 */
- reg1e = saa7115_read(client, 0x1e);
- reg1f = saa7115_read(client, 0x1f);
+ reg1e = saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC);
+ reg1f = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
signalOk = (reg1f & 0xc1) == 0x81 && (reg1e & 0xc0) == 0x80;
vcr = !(reg1f & 0x10);
@@ -819,19 +1030,27 @@ static void saa7115_log_status(struct i2c_client *client)
v4l_info(client, "Detected format: BW/No color\n");
break;
}
+ v4l_info(client, "Width, Height: %d, %d\n", state->width, state->height);
}
/* setup the sliced VBI lcr registers according to the sliced VBI format */
-static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
+static void saa711x_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_format *fmt)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
int is_50hz = (state->std & V4L2_STD_625_50);
u8 lcr[24];
int i, x;
- /* saa7113/7114 doesn't yet support VBI */
+#if 1
+ /* saa7113/7114/7118 VBI support are experimental */
+ if (!saa711x_has_reg(state->ident,R_41_LCR_BASE))
+ return;
+
+#else
+ /* SAA7113 and SAA7118 also should support VBI - Need testing */
if (state->ident != V4L2_IDENT_SAA7115)
return;
+#endif
for (i = 0; i <= 23; i++)
lcr[i] = 0xff;
@@ -888,14 +1107,16 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo
/* write the lcr registers */
for (i = 2; i <= 23; i++) {
- saa7115_write(client, i - 2 + 0x41, lcr[i]);
+ saa711x_write(client, i - 2 + R_41_LCR_BASE, lcr[i]);
}
/* enable/disable raw VBI capturing */
- saa7115_writeregs(client, fmt->service_set == 0 ? saa7115_cfg_vbi_on : saa7115_cfg_vbi_off);
+ saa711x_writeregs(client, fmt->service_set == 0 ?
+ saa7115_cfg_vbi_on :
+ saa7115_cfg_vbi_off);
}
-static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
{
static u16 lcr2vbi[] = {
0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
@@ -911,10 +1132,10 @@ static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
return -EINVAL;
memset(sliced, 0, sizeof(*sliced));
/* done if using raw VBI */
- if (saa7115_read(client, 0x80) & 0x10)
+ if (saa711x_read(client, R_80_GLOBAL_CNTL_1) & 0x10)
return 0;
for (i = 2; i <= 23; i++) {
- u8 v = saa7115_read(client, i - 2 + 0x41);
+ u8 v = saa711x_read(client, i - 2 + R_41_LCR_BASE);
sliced->service_lines[0][i] = lcr2vbi[v >> 4];
sliced->service_lines[1][i] = lcr2vbi[v & 0xf];
@@ -924,114 +1145,31 @@ static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt
return 0;
}
-static int saa7115_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
+static int saa711x_set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
- struct v4l2_pix_format *pix;
- int HPSC, HFSC;
- int VSCY, Vsrc;
- int is_50hz = state->std & V4L2_STD_625_50;
-
if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- saa7115_set_lcr(client, &fmt->fmt.sliced);
+ saa711x_set_lcr(client, &fmt->fmt.sliced);
return 0;
}
if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- pix = &(fmt->fmt.pix);
-
- v4l_dbg(1, debug, client, "decoder set size\n");
-
- /* FIXME need better bounds checking here */
- if ((pix->width < 1) || (pix->width > 1440))
- return -EINVAL;
- if ((pix->height < 1) || (pix->height > 960))
- return -EINVAL;
-
- /* probably have a valid size, let's set it */
- /* Set output width/height */
- /* width */
- saa7115_write(client, 0xcc, (u8) (pix->width & 0xff));
- saa7115_write(client, 0xcd, (u8) ((pix->width >> 8) & 0xff));
- /* height */
- saa7115_write(client, 0xce, (u8) (pix->height & 0xff));
- saa7115_write(client, 0xcf, (u8) ((pix->height >> 8) & 0xff));
-
- /* Scaling settings */
- /* Hprescaler is floor(inres/outres) */
- /* FIXME hardcoding input res */
- if (pix->width != 720) {
- HPSC = (int)(720 / pix->width);
- /* 0 is not allowed (div. by zero) */
- HPSC = HPSC ? HPSC : 1;
- HFSC = (int)((1024 * 720) / (HPSC * pix->width));
-
- v4l_dbg(1, debug, client, "Hpsc: 0x%05x, Hfsc: 0x%05x\n", HPSC, HFSC);
- /* FIXME hardcodes to "Task B"
- * write H prescaler integer */
- saa7115_write(client, 0xd0, (u8) (HPSC & 0x3f));
-
- /* write H fine-scaling (luminance) */
- saa7115_write(client, 0xd8, (u8) (HFSC & 0xff));
- saa7115_write(client, 0xd9, (u8) ((HFSC >> 8) & 0xff));
- /* write H fine-scaling (chrominance)
- * must be lum/2, so i'll just bitshift :) */
- saa7115_write(client, 0xDC, (u8) ((HFSC >> 1) & 0xff));
- saa7115_write(client, 0xDD, (u8) ((HFSC >> 9) & 0xff));
- } else {
- if (is_50hz) {
- v4l_dbg(1, debug, client, "Setting full 50hz width\n");
- saa7115_writeregs(client, saa7115_cfg_50hz_fullres_x);
- } else {
- v4l_dbg(1, debug, client, "Setting full 60hz width\n");
- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
- }
- }
-
- Vsrc = is_50hz ? 576 : 480;
-
- if (pix->height != Vsrc) {
- VSCY = (int)((1024 * Vsrc) / pix->height);
- v4l_dbg(1, debug, client, "Vsrc: %d, Vscy: 0x%05x\n", Vsrc, VSCY);
-
- /* Correct Contrast and Luminance */
- saa7115_write(client, 0xd5, (u8) (64 * 1024 / VSCY));
- saa7115_write(client, 0xd6, (u8) (64 * 1024 / VSCY));
-
- /* write V fine-scaling (luminance) */
- saa7115_write(client, 0xe0, (u8) (VSCY & 0xff));
- saa7115_write(client, 0xe1, (u8) ((VSCY >> 8) & 0xff));
- /* write V fine-scaling (chrominance) */
- saa7115_write(client, 0xe2, (u8) (VSCY & 0xff));
- saa7115_write(client, 0xe3, (u8) ((VSCY >> 8) & 0xff));
- } else {
- if (is_50hz) {
- v4l_dbg(1, debug, client, "Setting full 50Hz height\n");
- saa7115_writeregs(client, saa7115_cfg_50hz_fullres_y);
- } else {
- v4l_dbg(1, debug, client, "Setting full 60hz height\n");
- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
- }
- }
-
- saa7115_writeregs(client, saa7115_cfg_reset_scaler);
- return 0;
+ return saa711x_set_size(client,fmt->fmt.pix.width,fmt->fmt.pix.height);
}
/* Decode the sliced VBI data stream as created by the saa7115.
The format is described in the saa7115 datasheet in Tables 25 and 26
and in Figure 33.
The current implementation uses SAV/EAV codes and not the ancillary data
- headers. The vbi->p pointer points to the SDID byte right after the SAV
+ headers. The vbi->p pointer points to the R_5E_SDID byte right after the SAV
code. */
-static void saa7115_decode_vbi_line(struct i2c_client *client,
+static void saa711x_decode_vbi_line(struct i2c_client *client,
struct v4l2_decode_vbi_line *vbi)
{
static const char vbi_no_data_pattern[] = {
0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0
};
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
u8 *p = vbi->p;
u32 wss;
int id1, id2; /* the ID1 and ID2 bytes from the internal header */
@@ -1066,12 +1204,12 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
vbi->type = V4L2_SLICED_TELETEXT_B;
break;
case 4:
- if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1]))
+ if (!saa711x_odd_parity(p[0]) || !saa711x_odd_parity(p[1]))
return;
vbi->type = V4L2_SLICED_CAPTION_525;
break;
case 5:
- wss = saa7115_decode_wss(p);
+ wss = saa711x_decode_wss(p);
if (wss == -1)
return;
p[0] = wss & 0xff;
@@ -1079,7 +1217,7 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
vbi->type = V4L2_SLICED_WSS_625;
break;
case 7:
- if (saa7115_decode_vps(p, p) != 0)
+ if (saa711x_decode_vps(p, p) != 0)
return;
vbi->type = V4L2_SLICED_VPS;
break;
@@ -1090,21 +1228,21 @@ static void saa7115_decode_vbi_line(struct i2c_client *client,
/* ============ SAA7115 AUDIO settings (end) ============= */
-static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static int saa711x_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
int *iarg = arg;
/* ioctls to allow direct access to the saa7115 registers for testing */
switch (cmd) {
case VIDIOC_S_FMT:
- return saa7115_set_v4lfmt(client, (struct v4l2_format *)arg);
+ return saa711x_set_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_G_FMT:
- return saa7115_get_v4lfmt(client, (struct v4l2_format *)arg);
+ return saa711x_get_v4lfmt(client, (struct v4l2_format *)arg);
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
- return saa7115_set_audio_clock_freq(client, *(u32 *)arg);
+ return saa711x_set_audio_clock_freq(client, *(u32 *)arg);
case VIDIOC_G_TUNER:
{
@@ -1113,7 +1251,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
if (state->radio)
break;
- status = saa7115_read(client, 0x1f);
+ status = saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC);
v4l_dbg(1, debug, client, "status: 0x%02x\n", status);
vt->signal = ((status & (1 << 6)) == 0) ? 0xffff : 0x0;
@@ -1121,14 +1259,14 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
}
case VIDIOC_LOG_STATUS:
- saa7115_log_status(client);
+ saa711x_log_status(client);
break;
case VIDIOC_G_CTRL:
- return saa7115_get_v4lctrl(client, (struct v4l2_control *)arg);
+ return saa711x_get_v4lctrl(client, (struct v4l2_control *)arg);
case VIDIOC_S_CTRL:
- return saa7115_set_v4lctrl(client, (struct v4l2_control *)arg);
+ return saa711x_set_v4lctrl(client, (struct v4l2_control *)arg);
case VIDIOC_QUERYCTRL:
{
@@ -1146,12 +1284,12 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
}
case VIDIOC_G_STD:
- *(v4l2_std_id *)arg = saa7115_get_v4lstd(client);
+ *(v4l2_std_id *)arg = saa711x_get_v4lstd(client);
break;
case VIDIOC_S_STD:
state->radio = 0;
- saa7115_set_v4lstd(client, *(v4l2_std_id *)arg);
+ saa711x_set_v4lstd(client, *(v4l2_std_id *)arg);
break;
case AUDC_SET_RADIO:
@@ -1187,13 +1325,13 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
state->input = route->input;
/* select mode */
- saa7115_write(client, 0x02,
- (saa7115_read(client, 0x02) & 0xf0) |
+ saa711x_write(client, R_02_INPUT_CNTL_1,
+ (saa711x_read(client, R_02_INPUT_CNTL_1) & 0xf0) |
state->input);
/* bypass chrominance trap for S-Video modes */
- saa7115_write(client, 0x09,
- (saa7115_read(client, 0x09) & 0x7f) |
+ saa711x_write(client, R_09_LUMA_CNTL,
+ (saa711x_read(client, R_09_LUMA_CNTL) & 0x7f) |
(state->input >= SAA7115_SVIDEO0 ? 0x80 : 0x0));
break;
}
@@ -1205,7 +1343,9 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
if (state->enable != (cmd == VIDIOC_STREAMON)) {
state->enable = (cmd == VIDIOC_STREAMON);
- saa7115_write(client, 0x87, state->enable);
+ saa711x_write(client,
+ R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED,
+ state->enable);
}
break;
@@ -1220,17 +1360,17 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
state->cgcdiv = (freq->flags & SAA7115_FREQ_FL_CGCDIV) ? 3 : 4;
state->ucgc = (freq->flags & SAA7115_FREQ_FL_UCGC) ? 1 : 0;
state->apll = (freq->flags & SAA7115_FREQ_FL_APLL) ? 1 : 0;
- saa7115_set_audio_clock_freq(client, state->audclk_freq);
+ saa711x_set_audio_clock_freq(client, state->audclk_freq);
break;
}
case VIDIOC_INT_DECODE_VBI_LINE:
- saa7115_decode_vbi_line(client, arg);
+ saa711x_decode_vbi_line(client, arg);
break;
case VIDIOC_INT_RESET:
v4l_dbg(1, debug, client, "decoder RESET\n");
- saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+ saa711x_writeregs(client, saa7115_cfg_reset_scaler);
break;
case VIDIOC_INT_G_VBI_DATA:
@@ -1239,25 +1379,25 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
switch (data->id) {
case V4L2_SLICED_WSS_625:
- if (saa7115_read(client, 0x6b) & 0xc0)
+ if (saa711x_read(client, 0x6b) & 0xc0)
return -EIO;
- data->data[0] = saa7115_read(client, 0x6c);
- data->data[1] = saa7115_read(client, 0x6d);
+ data->data[0] = saa711x_read(client, 0x6c);
+ data->data[1] = saa711x_read(client, 0x6d);
return 0;
case V4L2_SLICED_CAPTION_525:
if (data->field == 0) {
/* CC */
- if (saa7115_read(client, 0x66) & 0xc0)
+ if (saa711x_read(client, 0x66) & 0xc0)
return -EIO;
- data->data[0] = saa7115_read(client, 0x67);
- data->data[1] = saa7115_read(client, 0x68);
+ data->data[0] = saa711x_read(client, 0x67);
+ data->data[1] = saa711x_read(client, 0x68);
return 0;
}
/* XDS */
- if (saa7115_read(client, 0x66) & 0x30)
+ if (saa711x_read(client, 0x66) & 0x30)
return -EIO;
- data->data[0] = saa7115_read(client, 0x69);
- data->data[1] = saa7115_read(client, 0x6a);
+ data->data[0] = saa711x_read(client, 0x69);
+ data->data[1] = saa711x_read(client, 0x6a);
return 0;
default:
return -EINVAL;
@@ -1272,7 +1412,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
if (reg->i2c_id != I2C_DRIVERID_SAA711X)
return -EINVAL;
- reg->val = saa7115_read(client, reg->reg & 0xff);
+ reg->val = saa711x_read(client, reg->reg & 0xff);
break;
}
@@ -1284,7 +1424,7 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
return -EINVAL;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- saa7115_write(client, reg->reg & 0xff, reg->val & 0xff);
+ saa711x_write(client, reg->reg & 0xff, reg->val & 0xff);
break;
}
#endif
@@ -1302,12 +1442,14 @@ static int saa7115_command(struct i2c_client *client, unsigned int cmd, void *ar
/* ----------------------------------------------------------------------- */
-static struct i2c_driver i2c_driver_saa7115;
+static struct i2c_driver i2c_driver_saa711x;
-static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
+static int saa711x_attach(struct i2c_adapter *adapter, int address, int kind)
{
struct i2c_client *client;
- struct saa7115_state *state;
+ struct saa711x_state *state;
+ int i;
+ char name[17];
u8 chip_id;
/* Check if the adapter supports the needed features */
@@ -1319,28 +1461,31 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
- client->driver = &i2c_driver_saa7115;
+ client->driver = &i2c_driver_saa711x;
snprintf(client->name, sizeof(client->name) - 1, "saa7115");
v4l_dbg(1, debug, client, "detecting saa7115 client on address 0x%x\n", address << 1);
- saa7115_write(client, 0, 5);
- chip_id = saa7115_read(client, 0) & 0x0f;
- if (chip_id < 3 && chip_id > 5) {
- v4l_dbg(1, debug, client, "saa7115 not found\n");
- kfree(client);
- return 0;
+ for (i=0;i<0x0f;i++) {
+ saa711x_write(client, 0, i);
+ name[i] = (saa711x_read(client, 0) &0x0f) +'0';
+ if (name[i]>'9')
+ name[i]+='a'-'9'-1;
}
+ name[i]='\0';
+
+ saa711x_write(client, 0, 5);
+ chip_id = saa711x_read(client, 0) & 0x0f;
+
snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id);
- v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name);
+ v4l_info(client, "saa711%d found (%s) @ 0x%x (%s)\n", chip_id, name, address << 1, adapter->name);
- state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL);
i2c_set_clientdata(client, state);
if (state == NULL) {
kfree(client);
return -ENOMEM;
}
- state->std = V4L2_STD_NTSC;
state->input = -1;
state->enable = 1;
state->radio = 0;
@@ -1349,15 +1494,25 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
state->hue = 0;
state->sat = 64;
switch (chip_id) {
+ case 1:
+ state->ident = V4L2_IDENT_SAA7111;
+ break;
case 3:
state->ident = V4L2_IDENT_SAA7113;
break;
case 4:
state->ident = V4L2_IDENT_SAA7114;
break;
- default:
+ case 5:
state->ident = V4L2_IDENT_SAA7115;
break;
+ case 8:
+ state->ident = V4L2_IDENT_SAA7118;
+ break;
+ default:
+ state->ident = V4L2_IDENT_SAA7111;
+ v4l_info(client, "WARNING: Chip is not known - Falling back to saa7111\n");
+
}
state->audclk_freq = 48000;
@@ -1365,38 +1520,39 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind)
v4l_dbg(1, debug, client, "writing init values\n");
/* init to 60hz/48khz */
- if (state->ident == V4L2_IDENT_SAA7113) {
- state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
- saa7115_writeregs(client, saa7113_init_auto_input);
- } else {
+ state->crystal_freq = SAA7115_FREQ_24_576_MHZ;
+ switch (state->ident) {
+ case V4L2_IDENT_SAA7111:
+ saa711x_writeregs(client, saa7111_init);
+ break;
+ case V4L2_IDENT_SAA7113:
+ saa711x_writeregs(client, saa7113_init);
+ break;
+ default:
state->crystal_freq = SAA7115_FREQ_32_11_MHZ;
- saa7115_writeregs(client, saa7115_init_auto_input);
+ saa711x_writeregs(client, saa7115_init_auto_input);
}
- saa7115_writeregs(client, saa7115_init_misc);
- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x);
- saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y);
- saa7115_writeregs(client, saa7115_cfg_60hz_video);
- saa7115_set_audio_clock_freq(client, state->audclk_freq);
- saa7115_writeregs(client, saa7115_cfg_reset_scaler);
+ saa711x_writeregs(client, saa7115_init_misc);
+ saa711x_set_v4lstd(client, V4L2_STD_NTSC);
i2c_attach_client(client);
v4l_dbg(1, debug, client, "status: (1E) 0x%02x, (1F) 0x%02x\n",
- saa7115_read(client, 0x1e), saa7115_read(client, 0x1f));
+ saa711x_read(client, R_1E_STATUS_BYTE_1_VD_DEC), saa711x_read(client, R_1F_STATUS_BYTE_2_VD_DEC));
return 0;
}
-static int saa7115_probe(struct i2c_adapter *adapter)
+static int saa711x_probe(struct i2c_adapter *adapter)
{
if (adapter->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adapter, &addr_data, &saa7115_attach);
+ return i2c_probe(adapter, &addr_data, &saa711x_attach);
return 0;
}
-static int saa7115_detach(struct i2c_client *client)
+static int saa711x_detach(struct i2c_client *client)
{
- struct saa7115_state *state = i2c_get_clientdata(client);
+ struct saa711x_state *state = i2c_get_clientdata(client);
int err;
err = i2c_detach_client(client);
@@ -1412,26 +1568,26 @@ static int saa7115_detach(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
/* i2c implementation */
-static struct i2c_driver i2c_driver_saa7115 = {
+static struct i2c_driver i2c_driver_saa711x = {
.driver = {
.name = "saa7115",
},
.id = I2C_DRIVERID_SAA711X,
- .attach_adapter = saa7115_probe,
- .detach_client = saa7115_detach,
- .command = saa7115_command,
+ .attach_adapter = saa711x_probe,
+ .detach_client = saa711x_detach,
+ .command = saa711x_command,
};
-static int __init saa7115_init_module(void)
+static int __init saa711x_init_module(void)
{
- return i2c_add_driver(&i2c_driver_saa7115);
+ return i2c_add_driver(&i2c_driver_saa711x);
}
-static void __exit saa7115_cleanup_module(void)
+static void __exit saa711x_cleanup_module(void)
{
- i2c_del_driver(&i2c_driver_saa7115);
+ i2c_del_driver(&i2c_driver_saa711x);
}
-module_init(saa7115_init_module);
-module_exit(saa7115_cleanup_module);
+module_init(saa711x_init_module);
+module_exit(saa711x_cleanup_module);
diff --git a/drivers/media/video/saa711x_regs.h b/drivers/media/video/saa711x_regs.h
new file mode 100644
index 000000000000..4e5f2eb0a2c1
--- /dev/null
+++ b/drivers/media/video/saa711x_regs.h
@@ -0,0 +1,549 @@
+/* saa711x - Philips SAA711x video decoder register specifications
+ *
+ * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.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.
+ *
+ * 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.
+ */
+
+#define R_00_CHIP_VERSION 0x00
+/* Video Decoder */
+ /* Video Decoder - Frontend part */
+#define R_01_INC_DELAY 0x01
+#define R_02_INPUT_CNTL_1 0x02
+#define R_03_INPUT_CNTL_2 0x03
+#define R_04_INPUT_CNTL_3 0x04
+#define R_05_INPUT_CNTL_4 0x05
+ /* Video Decoder - Decoder part */
+#define R_06_H_SYNC_START 0x06
+#define R_07_H_SYNC_STOP 0x07
+#define R_08_SYNC_CNTL 0x08
+#define R_09_LUMA_CNTL 0x09
+#define R_0A_LUMA_BRIGHT_CNTL 0x0a
+#define R_0B_LUMA_CONTRAST_CNTL 0x0b
+#define R_0C_CHROMA_SAT_CNTL 0x0c
+#define R_0D_CHROMA_HUE_CNTL 0x0d
+#define R_0E_CHROMA_CNTL_1 0x0e
+#define R_0F_CHROMA_GAIN_CNTL 0x0f
+#define R_10_CHROMA_CNTL_2 0x10
+#define R_11_MODE_DELAY_CNTL 0x11
+#define R_12_RT_SIGNAL_CNTL 0x12
+#define R_13_RT_X_PORT_OUT_CNTL 0x13
+#define R_14_ANAL_ADC_COMPAT_CNTL 0x14
+#define R_15_VGATE_START_FID_CHG 0x15
+#define R_16_VGATE_STOP 0x16
+#define R_17_MISC_VGATE_CONF_AND_MSB 0x17
+#define R_18_RAW_DATA_GAIN_CNTL 0x18
+#define R_19_RAW_DATA_OFF_CNTL 0x19
+#define R_1A_COLOR_KILL_LVL_CNTL 0x1a
+#define R_1B_MISC_TVVCRDET 0x1b
+#define R_1C_ENHAN_COMB_CTRL1 0x1c
+#define R_1D_ENHAN_COMB_CTRL2 0x1d
+#define R_1E_STATUS_BYTE_1_VD_DEC 0x1e
+#define R_1F_STATUS_BYTE_2_VD_DEC 0x1f
+
+/* Component processing and interrupt masking part */
+#define R_23_INPUT_CNTL_5 0x23
+#define R_24_INPUT_CNTL_6 0x24
+#define R_25_INPUT_CNTL_7 0x25
+#define R_29_COMP_DELAY 0x29
+#define R_2A_COMP_BRIGHT_CNTL 0x2a
+#define R_2B_COMP_CONTRAST_CNTL 0x2b
+#define R_2C_COMP_SAT_CNTL 0x2c
+#define R_2D_INTERRUPT_MASK_1 0x2d
+#define R_2E_INTERRUPT_MASK_2 0x2e
+#define R_2F_INTERRUPT_MASK_3 0x2f
+
+/* Audio clock generator part */
+#define R_30_AUD_MAST_CLK_CYCLES_PER_FIELD 0x30
+#define R_34_AUD_MAST_CLK_NOMINAL_INC 0x34
+#define R_38_CLK_RATIO_AMXCLK_TO_ASCLK 0x38
+#define R_39_CLK_RATIO_ASCLK_TO_ALRCLK 0x39
+#define R_3A_AUD_CLK_GEN_BASIC_SETUP 0x3a
+
+/* General purpose VBI data slicer part */
+#define R_40_SLICER_CNTL_1 0x40
+#define R_41_LCR_BASE 0x41
+#define R_58_PROGRAM_FRAMING_CODE 0x58
+#define R_59_H_OFF_FOR_SLICER 0x59
+#define R_5A_V_OFF_FOR_SLICER 0x5a
+#define R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF 0x5b
+#define R_5D_DID 0x5d
+#define R_5E_SDID 0x5e
+#define R_60_SLICER_STATUS_BYTE_0 0x60
+#define R_61_SLICER_STATUS_BYTE_1 0x61
+#define R_62_SLICER_STATUS_BYTE_2 0x62
+
+/* X port, I port and the scaler part */
+ /* Task independent global settings */
+#define R_80_GLOBAL_CNTL_1 0x80
+#define R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F 0x81
+#define R_83_X_PORT_I_O_ENA_AND_OUT_CLK 0x83
+#define R_84_I_PORT_SIGNAL_DEF 0x84
+#define R_85_I_PORT_SIGNAL_POLAR 0x85
+#define R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT 0x86
+#define R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED 0x87
+#define R_88_POWER_SAVE_ADC_PORT_CNTL 0x88
+#define R_8F_STATUS_INFO_SCALER 0x8f
+ /* Task A definition */
+ /* Basic settings and acquisition window definition */
+#define R_90_A_TASK_HANDLING_CNTL 0x90
+#define R_91_A_X_PORT_FORMATS_AND_CONF 0x91
+#define R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL 0x92
+#define R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF 0x93
+#define R_94_A_HORIZ_INPUT_WINDOW_START 0x94
+#define R_95_A_HORIZ_INPUT_WINDOW_START_MSB 0x95
+#define R_96_A_HORIZ_INPUT_WINDOW_LENGTH 0x96
+#define R_97_A_HORIZ_INPUT_WINDOW_LENGTH_MSB 0x97
+#define R_98_A_VERT_INPUT_WINDOW_START 0x98
+#define R_99_A_VERT_INPUT_WINDOW_START_MSB 0x99
+#define R_9A_A_VERT_INPUT_WINDOW_LENGTH 0x9a
+#define R_9B_A_VERT_INPUT_WINDOW_LENGTH_MSB 0x9b
+#define R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH 0x9c
+#define R_9D_A_HORIZ_OUTPUT_WINDOW_LENGTH_MSB 0x9d
+#define R_9E_A_VERT_OUTPUT_WINDOW_LENGTH 0x9e
+#define R_9F_A_VERT_OUTPUT_WINDOW_LENGTH_MSB 0x9f
+ /* FIR filtering and prescaling */
+#define R_A0_A_HORIZ_PRESCALING 0xa0
+#define R_A1_A_ACCUMULATION_LENGTH 0xa1
+#define R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER 0xa2
+#define R_A4_A_LUMA_BRIGHTNESS_CNTL 0xa4
+#define R_A5_A_LUMA_CONTRAST_CNTL 0xa5
+#define R_A6_A_CHROMA_SATURATION_CNTL 0xa6
+ /* Horizontal phase scaling */
+#define R_A8_A_HORIZ_LUMA_SCALING_INC 0xa8
+#define R_A9_A_HORIZ_LUMA_SCALING_INC_MSB 0xa9
+#define R_AA_A_HORIZ_LUMA_PHASE_OFF 0xaa
+#define R_AC_A_HORIZ_CHROMA_SCALING_INC 0xac
+#define R_AD_A_HORIZ_CHROMA_SCALING_INC_MSB 0xad
+#define R_AE_A_HORIZ_CHROMA_PHASE_OFF 0xae
+#define R_AF_A_HORIZ_CHROMA_PHASE_OFF_MSB 0xaf
+ /* Vertical scaling */
+#define R_B0_A_VERT_LUMA_SCALING_INC 0xb0
+#define R_B1_A_VERT_LUMA_SCALING_INC_MSB 0xb1
+#define R_B2_A_VERT_CHROMA_SCALING_INC 0xb2
+#define R_B3_A_VERT_CHROMA_SCALING_INC_MSB 0xb3
+#define R_B4_A_VERT_SCALING_MODE_CNTL 0xb4
+#define R_B8_A_VERT_CHROMA_PHASE_OFF_00 0xb8
+#define R_B9_A_VERT_CHROMA_PHASE_OFF_01 0xb9
+#define R_BA_A_VERT_CHROMA_PHASE_OFF_10 0xba
+#define R_BB_A_VERT_CHROMA_PHASE_OFF_11 0xbb
+#define R_BC_A_VERT_LUMA_PHASE_OFF_00 0xbc
+#define R_BD_A_VERT_LUMA_PHASE_OFF_01 0xbd
+#define R_BE_A_VERT_LUMA_PHASE_OFF_10 0xbe
+#define R_BF_A_VERT_LUMA_PHASE_OFF_11 0xbf
+ /* Task B definition */
+ /* Basic settings and acquisition window definition */
+#define R_C0_B_TASK_HANDLING_CNTL 0xc0
+#define R_C1_B_X_PORT_FORMATS_AND_CONF 0xc1
+#define R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION 0xc2
+#define R_C3_B_I_PORT_FORMATS_AND_CONF 0xc3
+#define R_C4_B_HORIZ_INPUT_WINDOW_START 0xc4
+#define R_C5_B_HORIZ_INPUT_WINDOW_START_MSB 0xc5
+#define R_C6_B_HORIZ_INPUT_WINDOW_LENGTH 0xc6
+#define R_C7_B_HORIZ_INPUT_WINDOW_LENGTH_MSB 0xc7
+#define R_C8_B_VERT_INPUT_WINDOW_START 0xc8
+#define R_C9_B_VERT_INPUT_WINDOW_START_MSB 0xc9
+#define R_CA_B_VERT_INPUT_WINDOW_LENGTH 0xca
+#define R_CB_B_VERT_INPUT_WINDOW_LENGTH_MSB 0xcb
+#define R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH 0xcc
+#define R_CD_B_HORIZ_OUTPUT_WINDOW_LENGTH_MSB 0xcd
+#define R_CE_B_VERT_OUTPUT_WINDOW_LENGTH 0xce
+#define R_CF_B_VERT_OUTPUT_WINDOW_LENGTH_MSB 0xcf
+ /* FIR filtering and prescaling */
+#define R_D0_B_HORIZ_PRESCALING 0xd0
+#define R_D1_B_ACCUMULATION_LENGTH 0xd1
+#define R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER 0xd2
+#define R_D4_B_LUMA_BRIGHTNESS_CNTL 0xd4
+#define R_D5_B_LUMA_CONTRAST_CNTL 0xd5
+#define R_D6_B_CHROMA_SATURATION_CNTL 0xd6
+ /* Horizontal phase scaling */
+#define R_D8_B_HORIZ_LUMA_SCALING_INC 0xd8
+#define R_D9_B_HORIZ_LUMA_SCALING_INC_MSB 0xd9
+#define R_DA_B_HORIZ_LUMA_PHASE_OFF 0xda
+#define R_DC_B_HORIZ_CHROMA_SCALING 0xdc
+#define R_DD_B_HORIZ_CHROMA_SCALING_MSB 0xdd
+#define R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA 0xde
+ /* Vertical scaling */
+#define R_E0_B_VERT_LUMA_SCALING_INC 0xe0
+#define R_E1_B_VERT_LUMA_SCALING_INC_MSB 0xe1
+#define R_E2_B_VERT_CHROMA_SCALING_INC 0xe2
+#define R_E3_B_VERT_CHROMA_SCALING_INC_MSB 0xe3
+#define R_E4_B_VERT_SCALING_MODE_CNTL 0xe4
+#define R_E8_B_VERT_CHROMA_PHASE_OFF_00 0xe8
+#define R_E9_B_VERT_CHROMA_PHASE_OFF_01 0xe9
+#define R_EA_B_VERT_CHROMA_PHASE_OFF_10 0xea
+#define R_EB_B_VERT_CHROMA_PHASE_OFF_11 0xeb
+#define R_EC_B_VERT_LUMA_PHASE_OFF_00 0xec
+#define R_ED_B_VERT_LUMA_PHASE_OFF_01 0xed
+#define R_EE_B_VERT_LUMA_PHASE_OFF_10 0xee
+#define R_EF_B_VERT_LUMA_PHASE_OFF_11 0xef
+
+/* second PLL (PLL2) and Pulsegenerator Programming */
+#define R_F0_LFCO_PER_LINE 0xf0
+#define R_F1_P_I_PARAM_SELECT 0xf1
+#define R_F2_NOMINAL_PLL2_DTO 0xf2
+#define R_F3_PLL_INCREMENT 0xf3
+#define R_F4_PLL2_STATUS 0xf4
+#define R_F5_PULSGEN_LINE_LENGTH 0xf5
+#define R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG 0xf6
+#define R_F7_PULSE_A_POS_MSB 0xf7
+#define R_F8_PULSE_B_POS 0xf8
+#define R_F9_PULSE_B_POS_MSB 0xf9
+#define R_FA_PULSE_C_POS 0xfa
+#define R_FB_PULSE_C_POS_MSB 0xfb
+#define R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES 0xff
+
+#if 0
+/* Those structs will be used in the future for debug purposes */
+struct saa711x_reg_descr {
+ u8 reg;
+ int count;
+ char *name;
+};
+
+struct saa711x_reg_descr saa711x_regs[] = {
+ /* REG COUNT NAME */
+ {R_00_CHIP_VERSION,1,
+ "Chip version"},
+
+ /* Video Decoder: R_01_INC_DELAY to R_1F_STATUS_BYTE_2_VD_DEC */
+
+ /* Video Decoder - Frontend part: R_01_INC_DELAY to R_05_INPUT_CNTL_4 */
+ {R_01_INC_DELAY,1,
+ "Increment delay"},
+ {R_02_INPUT_CNTL_1,1,
+ "Analog input control 1"},
+ {R_03_INPUT_CNTL_2,1,
+ "Analog input control 2"},
+ {R_04_INPUT_CNTL_3,1,
+ "Analog input control 3"},
+ {R_05_INPUT_CNTL_4,1,
+ "Analog input control 4"},
+
+ /* Video Decoder - Decoder part: R_06_H_SYNC_START to R_1F_STATUS_BYTE_2_VD_DEC */
+ {R_06_H_SYNC_START,1,
+ "Horizontal sync start"},
+ {R_07_H_SYNC_STOP,1,
+ "Horizontal sync stop"},
+ {R_08_SYNC_CNTL,1,
+ "Sync control"},
+ {R_09_LUMA_CNTL,1,
+ "Luminance control"},
+ {R_0A_LUMA_BRIGHT_CNTL,1,
+ "Luminance brightness control"},
+ {R_0B_LUMA_CONTRAST_CNTL,1,
+ "Luminance contrast control"},
+ {R_0C_CHROMA_SAT_CNTL,1,
+ "Chrominance saturation control"},
+ {R_0D_CHROMA_HUE_CNTL,1,
+ "Chrominance hue control"},
+ {R_0E_CHROMA_CNTL_1,1,
+ "Chrominance control 1"},
+ {R_0F_CHROMA_GAIN_CNTL,1,
+ "Chrominance gain control"},
+ {R_10_CHROMA_CNTL_2,1,
+ "Chrominance control 2"},
+ {R_11_MODE_DELAY_CNTL,1,
+ "Mode/delay control"},
+ {R_12_RT_SIGNAL_CNTL,1,
+ "RT signal control"},
+ {R_13_RT_X_PORT_OUT_CNTL,1,
+ "RT/X port output control"},
+ {R_14_ANAL_ADC_COMPAT_CNTL,1,
+ "Analog/ADC/compatibility control"},
+ {R_15_VGATE_START_FID_CHG, 1,
+ "VGATE start FID change"},
+ {R_16_VGATE_STOP,1,
+ "VGATE stop"},
+ {R_17_MISC_VGATE_CONF_AND_MSB, 1,
+ "Miscellaneous VGATE configuration and MSBs"},
+ {R_18_RAW_DATA_GAIN_CNTL,1,
+ "Raw data gain control",},
+ {R_19_RAW_DATA_OFF_CNTL,1,
+ "Raw data offset control",},
+ {R_1A_COLOR_KILL_LVL_CNTL,1,
+ "Color Killer Level Control"},
+ { R_1B_MISC_TVVCRDET, 1,
+ "MISC /TVVCRDET"},
+ { R_1C_ENHAN_COMB_CTRL1, 1,
+ "Enhanced comb ctrl1"},
+ { R_1D_ENHAN_COMB_CTRL2, 1,
+ "Enhanced comb ctrl1"},
+ {R_1E_STATUS_BYTE_1_VD_DEC,1,
+ "Status byte 1 video decoder"},
+ {R_1F_STATUS_BYTE_2_VD_DEC,1,
+ "Status byte 2 video decoder"},
+
+ /* Component processing and interrupt masking part: 0x20h to R_2F_INTERRUPT_MASK_3 */
+ /* 0x20 to 0x22 - Reserved */
+ {R_23_INPUT_CNTL_5,1,
+ "Analog input control 5"},
+ {R_24_INPUT_CNTL_6,1,
+ "Analog input control 6"},
+ {R_25_INPUT_CNTL_7,1,
+ "Analog input control 7"},
+ /* 0x26 to 0x28 - Reserved */
+ {R_29_COMP_DELAY,1,
+ "Component delay"},
+ {R_2A_COMP_BRIGHT_CNTL,1,
+ "Component brightness control"},
+ {R_2B_COMP_CONTRAST_CNTL,1,
+ "Component contrast control"},
+ {R_2C_COMP_SAT_CNTL,1,
+ "Component saturation control"},
+ {R_2D_INTERRUPT_MASK_1,1,
+ "Interrupt mask 1"},
+ {R_2E_INTERRUPT_MASK_2,1,
+ "Interrupt mask 2"},
+ {R_2F_INTERRUPT_MASK_3,1,
+ "Interrupt mask 3"},
+
+ /* Audio clock generator part: R_30_AUD_MAST_CLK_CYCLES_PER_FIELD to 0x3f */
+ {R_30_AUD_MAST_CLK_CYCLES_PER_FIELD,3,
+ "Audio master clock cycles per field"},
+ /* 0x33 - Reserved */
+ {R_34_AUD_MAST_CLK_NOMINAL_INC,3,
+ "Audio master clock nominal increment"},
+ /* 0x37 - Reserved */
+ {R_38_CLK_RATIO_AMXCLK_TO_ASCLK,1,
+ "Clock ratio AMXCLK to ASCLK"},
+ {R_39_CLK_RATIO_ASCLK_TO_ALRCLK,1,
+ "Clock ratio ASCLK to ALRCLK"},
+ {R_3A_AUD_CLK_GEN_BASIC_SETUP,1,
+ "Audio clock generator basic setup"},
+ /* 0x3b-0x3f - Reserved */
+
+ /* General purpose VBI data slicer part: R_40_SLICER_CNTL_1 to 0x7f */
+ {R_40_SLICER_CNTL_1,1,
+ "Slicer control 1"},
+ {R_41_LCR,23,
+ "R_41_LCR"},
+ {R_58_PROGRAM_FRAMING_CODE,1,
+ "Programmable framing code"},
+ {R_59_H_OFF_FOR_SLICER,1,
+ "Horizontal offset for slicer"},
+ {R_5A_V_OFF_FOR_SLICER,1,
+ "Vertical offset for slicer"},
+ {R_5B_FLD_OFF_AND_MSB_FOR_H_AND_V_OFF,1,
+ "Field offset and MSBs for horizontal and vertical offset"},
+ {R_5D_DID,1,
+ "Header and data identification (R_5D_DID)"},
+ {R_5E_SDID,1,
+ "Sliced data identification (R_5E_SDID) code"},
+ {R_60_SLICER_STATUS_BYTE_0,1,
+ "Slicer status byte 0"},
+ {R_61_SLICER_STATUS_BYTE_1,1,
+ "Slicer status byte 1"},
+ {R_62_SLICER_STATUS_BYTE_2,1,
+ "Slicer status byte 2"},
+ /* 0x63-0x7f - Reserved */
+
+ /* X port, I port and the scaler part: R_80_GLOBAL_CNTL_1 to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
+ /* Task independent global settings: R_80_GLOBAL_CNTL_1 to R_8F_STATUS_INFO_SCALER */
+ {R_80_GLOBAL_CNTL_1,1,
+ "Global control 1"},
+ {R_81_V_SYNC_FLD_ID_SRC_SEL_AND_RETIMED_V_F,1,
+ "Vertical sync and Field ID source selection, retimed V and F signals"},
+ /* 0x82 - Reserved */
+ {R_83_X_PORT_I_O_ENA_AND_OUT_CLK,1,
+ "X port I/O enable and output clock"},
+ {R_84_I_PORT_SIGNAL_DEF,1,
+ "I port signal definitions"},
+ {R_85_I_PORT_SIGNAL_POLAR,1,
+ "I port signal polarities"},
+ {R_86_I_PORT_FIFO_FLAG_CNTL_AND_ARBIT,1,
+ "I port FIFO flag control and arbitration"},
+ {R_87_I_PORT_I_O_ENA_OUT_CLK_AND_GATED, 1,
+ "I port I/O enable output clock and gated"},
+ {R_88_POWER_SAVE_ADC_PORT_CNTL,1,
+ "Power save/ADC port control"},
+ /* 089-0x8e - Reserved */
+ {R_8F_STATUS_INFO_SCALER,1,
+ "Status information scaler part"},
+
+ /* Task A definition: R_90_A_TASK_HANDLING_CNTL to R_BF_A_VERT_LUMA_PHASE_OFF_11 */
+ /* Task A: Basic settings and acquisition window definition */
+ {R_90_A_TASK_HANDLING_CNTL,1,
+ "Task A: Task handling control"},
+ {R_91_A_X_PORT_FORMATS_AND_CONF,1,
+ "Task A: X port formats and configuration"},
+ {R_92_A_X_PORT_INPUT_REFERENCE_SIGNAL,1,
+ "Task A: X port input reference signal definition"},
+ {R_93_A_I_PORT_OUTPUT_FORMATS_AND_CONF,1,
+ "Task A: I port output formats and configuration"},
+ {R_94_A_HORIZ_INPUT_WINDOW_START,2,
+ "Task A: Horizontal input window start"},
+ {R_96_A_HORIZ_INPUT_WINDOW_LENGTH,2,
+ "Task A: Horizontal input window length"},
+ {R_98_A_VERT_INPUT_WINDOW_START,2,
+ "Task A: Vertical input window start"},
+ {R_9A_A_VERT_INPUT_WINDOW_LENGTH,2,
+ "Task A: Vertical input window length"},
+ {R_9C_A_HORIZ_OUTPUT_WINDOW_LENGTH,2,
+ "Task A: Horizontal output window length"},
+ {R_9E_A_VERT_OUTPUT_WINDOW_LENGTH,2,
+ "Task A: Vertical output window length"},
+
+ /* Task A: FIR filtering and prescaling */
+ {R_A0_A_HORIZ_PRESCALING,1,
+ "Task A: Horizontal prescaling"},
+ {R_A1_A_ACCUMULATION_LENGTH,1,
+ "Task A: Accumulation length"},
+ {R_A2_A_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
+ "Task A: Prescaler DC gain and FIR prefilter"},
+ /* 0xa3 - Reserved */
+ {R_A4_A_LUMA_BRIGHTNESS_CNTL,1,
+ "Task A: Luminance brightness control"},
+ {R_A5_A_LUMA_CONTRAST_CNTL,1,
+ "Task A: Luminance contrast control"},
+ {R_A6_A_CHROMA_SATURATION_CNTL,1,
+ "Task A: Chrominance saturation control"},
+ /* 0xa7 - Reserved */
+
+ /* Task A: Horizontal phase scaling */
+ {R_A8_A_HORIZ_LUMA_SCALING_INC,2,
+ "Task A: Horizontal luminance scaling increment"},
+ {R_AA_A_HORIZ_LUMA_PHASE_OFF,1,
+ "Task A: Horizontal luminance phase offset"},
+ /* 0xab - Reserved */
+ {R_AC_A_HORIZ_CHROMA_SCALING_INC,2,
+ "Task A: Horizontal chrominance scaling increment"},
+ {R_AE_A_HORIZ_CHROMA_PHASE_OFF,1,
+ "Task A: Horizontal chrominance phase offset"},
+ /* 0xaf - Reserved */
+
+ /* Task A: Vertical scaling */
+ {R_B0_A_VERT_LUMA_SCALING_INC,2,
+ "Task A: Vertical luminance scaling increment"},
+ {R_B2_A_VERT_CHROMA_SCALING_INC,2,
+ "Task A: Vertical chrominance scaling increment"},
+ {R_B4_A_VERT_SCALING_MODE_CNTL,1,
+ "Task A: Vertical scaling mode control"},
+ /* 0xb5-0xb7 - Reserved */
+ {R_B8_A_VERT_CHROMA_PHASE_OFF_00,1,
+ "Task A: Vertical chrominance phase offset '00'"},
+ {R_B9_A_VERT_CHROMA_PHASE_OFF_01,1,
+ "Task A: Vertical chrominance phase offset '01'"},
+ {R_BA_A_VERT_CHROMA_PHASE_OFF_10,1,
+ "Task A: Vertical chrominance phase offset '10'"},
+ {R_BB_A_VERT_CHROMA_PHASE_OFF_11,1,
+ "Task A: Vertical chrominance phase offset '11'"},
+ {R_BC_A_VERT_LUMA_PHASE_OFF_00,1,
+ "Task A: Vertical luminance phase offset '00'"},
+ {R_BD_A_VERT_LUMA_PHASE_OFF_01,1,
+ "Task A: Vertical luminance phase offset '01'"},
+ {R_BE_A_VERT_LUMA_PHASE_OFF_10,1,
+ "Task A: Vertical luminance phase offset '10'"},
+ {R_BF_A_VERT_LUMA_PHASE_OFF_11,1,
+ "Task A: Vertical luminance phase offset '11'"},
+
+ /* Task B definition: R_C0_B_TASK_HANDLING_CNTL to R_EF_B_VERT_LUMA_PHASE_OFF_11 */
+ /* Task B: Basic settings and acquisition window definition */
+ {R_C0_B_TASK_HANDLING_CNTL,1,
+ "Task B: Task handling control"},
+ {R_C1_B_X_PORT_FORMATS_AND_CONF,1,
+ "Task B: X port formats and configuration"},
+ {R_C2_B_INPUT_REFERENCE_SIGNAL_DEFINITION,1,
+ "Task B: Input reference signal definition"},
+ {R_C3_B_I_PORT_FORMATS_AND_CONF,1,
+ "Task B: I port formats and configuration"},
+ {R_C4_B_HORIZ_INPUT_WINDOW_START,2,
+ "Task B: Horizontal input window start"},
+ {R_C6_B_HORIZ_INPUT_WINDOW_LENGTH,2,
+ "Task B: Horizontal input window length"},
+ {R_C8_B_VERT_INPUT_WINDOW_START,2,
+ "Task B: Vertical input window start"},
+ {R_CA_B_VERT_INPUT_WINDOW_LENGTH,2,
+ "Task B: Vertical input window length"},
+ {R_CC_B_HORIZ_OUTPUT_WINDOW_LENGTH,2,
+ "Task B: Horizontal output window length"},
+ {R_CE_B_VERT_OUTPUT_WINDOW_LENGTH,2,
+ "Task B: Vertical output window length"},
+
+ /* Task B: FIR filtering and prescaling */
+ {R_D0_B_HORIZ_PRESCALING,1,
+ "Task B: Horizontal prescaling"},
+ {R_D1_B_ACCUMULATION_LENGTH,1,
+ "Task B: Accumulation length"},
+ {R_D2_B_PRESCALER_DC_GAIN_AND_FIR_PREFILTER,1,
+ "Task B: Prescaler DC gain and FIR prefilter"},
+ /* 0xd3 - Reserved */
+ {R_D4_B_LUMA_BRIGHTNESS_CNTL,1,
+ "Task B: Luminance brightness control"},
+ {R_D5_B_LUMA_CONTRAST_CNTL,1,
+ "Task B: Luminance contrast control"},
+ {R_D6_B_CHROMA_SATURATION_CNTL,1,
+ "Task B: Chrominance saturation control"},
+ /* 0xd7 - Reserved */
+
+ /* Task B: Horizontal phase scaling */
+ {R_D8_B_HORIZ_LUMA_SCALING_INC,2,
+ "Task B: Horizontal luminance scaling increment"},
+ {R_DA_B_HORIZ_LUMA_PHASE_OFF,1,
+ "Task B: Horizontal luminance phase offset"},
+ /* 0xdb - Reserved */
+ {R_DC_B_HORIZ_CHROMA_SCALING,2,
+ "Task B: Horizontal chrominance scaling"},
+ {R_DE_B_HORIZ_PHASE_OFFSET_CRHOMA,1,
+ "Task B: Horizontal Phase Offset Chroma"},
+ /* 0xdf - Reserved */
+
+ /* Task B: Vertical scaling */
+ {R_E0_B_VERT_LUMA_SCALING_INC,2,
+ "Task B: Vertical luminance scaling increment"},
+ {R_E2_B_VERT_CHROMA_SCALING_INC,2,
+ "Task B: Vertical chrominance scaling increment"},
+ {R_E4_B_VERT_SCALING_MODE_CNTL,1,
+ "Task B: Vertical scaling mode control"},
+ /* 0xe5-0xe7 - Reserved */
+ {R_E8_B_VERT_CHROMA_PHASE_OFF_00,1,
+ "Task B: Vertical chrominance phase offset '00'"},
+ {R_E9_B_VERT_CHROMA_PHASE_OFF_01,1,
+ "Task B: Vertical chrominance phase offset '01'"},
+ {R_EA_B_VERT_CHROMA_PHASE_OFF_10,1,
+ "Task B: Vertical chrominance phase offset '10'"},
+ {R_EB_B_VERT_CHROMA_PHASE_OFF_11,1,
+ "Task B: Vertical chrominance phase offset '11'"},
+ {R_EC_B_VERT_LUMA_PHASE_OFF_00,1,
+ "Task B: Vertical luminance phase offset '00'"},
+ {R_ED_B_VERT_LUMA_PHASE_OFF_01,1,
+ "Task B: Vertical luminance phase offset '01'"},
+ {R_EE_B_VERT_LUMA_PHASE_OFF_10,1,
+ "Task B: Vertical luminance phase offset '10'"},
+ {R_EF_B_VERT_LUMA_PHASE_OFF_11,1,
+ "Task B: Vertical luminance phase offset '11'"},
+
+ /* second PLL (PLL2) and Pulsegenerator Programming */
+ { R_F0_LFCO_PER_LINE, 1,
+ "LFCO's per line"},
+ { R_F1_P_I_PARAM_SELECT,1,
+ "P-/I- Param. Select., PLL Mode, PLL H-Src., LFCO's per line"},
+ { R_F2_NOMINAL_PLL2_DTO,1,
+ "Nominal PLL2 DTO"},
+ {R_F3_PLL_INCREMENT,1,
+ "PLL2 Increment"},
+ {R_F4_PLL2_STATUS,1,
+ "PLL2 Status"},
+ {R_F5_PULSGEN_LINE_LENGTH,1,
+ "Pulsgen. line length"},
+ {R_F6_PULSE_A_POS_LSB_AND_PULSEGEN_CONFIG,1,
+ "Pulse A Position, Pulsgen Resync., Pulsgen. H-Src., Pulsgen. line length"},
+ {R_F7_PULSE_A_POS_MSB,1,
+ "Pulse A Position"},
+ {R_F8_PULSE_B_POS,2,
+ "Pulse B Position"},
+ {R_FA_PULSE_C_POS,2,
+ "Pulse C Position"},
+ /* 0xfc to 0xfe - Reserved */
+ {R_FF_S_PLL_MAX_PHASE_ERR_THRESH_NUM_LINES,1,
+ "S_PLL max. phase, error threshold, PLL2 no. of lines, threshold"},
+};
+#endif
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index f5543166d193..59da79ce2efd 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -41,53 +41,15 @@ config VIDEO_SAA7134_DVB
select VIDEO_BUF_DVB
select FW_LOADER
select DVB_PLL
+ select DVB_MT352 if !DVB_FE_CUSTOMISE
+ select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+ select DVB_NXT200X if !DVB_FE_CUSTOMISE
+ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+ select DVB_TDA826X if !DVB_FE_CUSTOMISE
+ select DVB_ISL6421 if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
To compile this driver as a module, choose M here: the
module will be called saa7134-dvb.
-
- You must also select one or more DVB demodulators.
- If you are unsure which you need, choose all of them.
-
-config VIDEO_SAA7134_DVB_ALL_FRONTENDS
- bool "Build all supported frontends for saa7134 based TV cards"
- default y
- depends on VIDEO_SAA7134_DVB
- select DVB_MT352
- select DVB_TDA1004X
- select DVB_NXT200X
- ---help---
- This builds saa7134-dvb with all currently supported frontend
- demodulators. If you wish to tweak your configuration, and
- only include support for the hardware that you need, choose N here.
-
- If you are unsure, choose Y.
-
-config VIDEO_SAA7134_DVB_MT352
- bool "Zarlink MT352 DVB-T Support"
- default y
- depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
- select DVB_MT352
- ---help---
- This adds DVB-T support for cards based on the
- Philips saa7134 chip and the MT352 demodulator.
-
-config VIDEO_SAA7134_DVB_TDA1004X
- bool "Phillips TDA10045H/TDA10046H DVB-T Support"
- default y
- depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
- select DVB_TDA1004X
- ---help---
- This adds DVB-T support for cards based on the
- Philips saa7134 chip and the TDA10045H/TDA10046H demodulator.
-
-config VIDEO_SAA7134_DVB_NXT200X
- bool "NXT2002/NXT2004 ATSC Support"
- default y
- depends on VIDEO_SAA7134_DVB && !VIDEO_SAA7134_DVB_ALL_FRONTENDS
- select DVB_NXT200X
- ---help---
- This adds ATSC 8VSB and QAM64/256 support for cards based on the
- Philips saa7134 chip and the NXT2002/NXT2004 demodulator.
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index be7b9ee697d6..89a1565b4256 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -16,8 +16,5 @@ EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
extra-cflags-$(CONFIG_VIDEO_BUF_DVB) += -DHAVE_VIDEO_BUF_DVB=1
-extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1
-extra-cflags-$(CONFIG_DVB_TDA1004X) += -DHAVE_TDA1004X=1
-extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1
EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index d73cff1970ae..4abf5c03a740 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -212,7 +212,7 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev,
*
*/
-static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id)
{
struct saa7134_dmasound *dmasound = dev_id;
struct saa7134_dev *dev = dmasound->priv_data;
@@ -590,6 +590,11 @@ static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream)
{
+ snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream);
+ struct saa7134_dev *dev = saa7134->dev;
+
+ dev->ctl_mute = 1;
+ saa7134_tvaudio_setmute(dev);
return 0;
}
@@ -631,6 +636,9 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream)
runtime->private_free = snd_card_saa7134_runtime_free;
runtime->hw = snd_card_saa7134_capture;
+ dev->ctl_mute = 0;
+ saa7134_tvaudio_setmute(dev);
+
if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
return err;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 927413aded10..c9d8e3b9cc37 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -1911,7 +1911,7 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_FLYDVBT_DUO_CARDBUS] = {
- .name = "LifeView/Typhoon FlyDVB-T Duo Cardbus",
+ .name = "LifeView/Typhoon/Genius FlyDVB-T Duo Cardbus",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_TDA8290,
.radio_type = UNSET,
@@ -2891,6 +2891,137 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x8000,
},
},
+ [SAA7134_BOARD_MEDION_MD8800_QUADRO] = {
+ .name = "Medion Md8800 Quadro",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_FLYDVBS_LR300] = {
+ /* LifeView FlyDVB-s */
+ /* Igor M. Liplianin <liplianin@tut.by> */
+ .name = "LifeView FlyDVB-S /Acorp TV134DS",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1, /* Composite input */
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo, /* S-Video signal on S-Video input */
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_PROTEUS_2309] = {
+ .name = "Proteus Pro 2309",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_A16AR] = {
+ /* Petr Baudis <pasky@ucw.cz> */
+ .name = "AVerMedia TV Hybrid A16AR",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290, /* untested */
+ .radio_type = TUNER_TEA5767, /* untested */
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_ASUS_EUROPA2_HYBRID] = {
+ .name = "Asus Europa2 OEM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT| TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -3375,7 +3506,7 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_FLYDVB_TRIO,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134, /* SAA 7131E */
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1461,
.subdevice = 0x2c05,
.driver_data = SAA7134_BOARD_AVERMEDIA_777,
@@ -3422,6 +3553,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x0005,
.driver_data = SAA7134_BOARD_MD7134_BRIDGE_2,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x5168,
+ .subdevice = 0x0300,
+ .driver_data = SAA7134_BOARD_FLYDVBS_LR300,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x4e42,
+ .subdevice = 0x0300,/* LR300 */
+ .driver_data = SAA7134_BOARD_FLYDVBS_LR300,
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1489,
@@ -3446,6 +3589,48 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x3502, /* whats the difference to 0x3306 ?*/
.driver_data = SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x0007,
+ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x0008,
+ .driver_data = SAA7134_BOARD_MEDION_MD8800_QUADRO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461,
+ .subdevice = 0x2c05,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_777,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1489,
+ .subdevice = 0x0502, /* Cardbus version */
+ .driver_data = SAA7134_BOARD_FLYDVBT_DUO_CARDBUS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = 0x0919, /* Philips Proteus PRO 2309 */
+ .subdevice = 0x2003,
+ .driver_data = SAA7134_BOARD_PROTEUS_2309,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461,
+ .subdevice = 0x2c00,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A16AR,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1043,
+ .subdevice = 0x4860,
+ .driver_data = SAA7134_BOARD_ASUS_EUROPA2_HYBRID,
+ },{
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -3548,6 +3733,12 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS:
case SAA7134_BOARD_FLYDVBT_LR301:
case SAA7134_BOARD_FLYDVBTDUO:
+ case SAA7134_BOARD_PROTEUS_2309:
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
+ saa_writeb(SAA7134_GPIO_GPMODE3, 0x80);
+ saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x40);
dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_MD5044:
@@ -3581,6 +3772,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00);
break;
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
case SAA7134_BOARD_AVERMEDIA_CARDBUS:
/* power-up tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff);
@@ -3713,6 +3905,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
+ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
/* The Philips EUROPA based hybrid boards have the tuner connected through
* the channel decoder. We have to make it transparent to find it
*/
@@ -3732,6 +3925,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
case SAA7134_BOARD_PHILIPS_TIGER:
case SAA7134_BOARD_TEVION_DVBT_220RF:
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
+ case SAA7134_BOARD_MEDION_MD8800_QUADRO:
/* this is a hybrid board, initialize to analog mode
* and configure firmware eeprom address
*/
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index be3a81fc90a2..5c9e63dfbea6 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -495,7 +495,7 @@ static void print_irqstatus(struct saa7134_dev *dev, int loop,
printk("\n");
}
-static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t saa7134_irq(int irq, void *dev_id)
{
struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
unsigned long report,status;
@@ -843,7 +843,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
latency = 0x0A;
}
#endif
- if (pci_pci_problems & PCIPCI_FAIL) {
+ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) {
printk(KERN_INFO "%s: quirk: this driver and your "
"chipset may not work together"
" in overlay mode.\n",dev->name);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 279828b8f299..1ba53b525ad2 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -34,17 +34,14 @@
#include <media/v4l2-common.h>
#include "dvb-pll.h"
-#ifdef HAVE_MT352
-# include "mt352.h"
-# include "mt352_priv.h" /* FIXME */
-#endif
-#ifdef HAVE_TDA1004X
-# include "tda1004x.h"
-#endif
-#ifdef HAVE_NXT200X
-# include "nxt200x.h"
-#endif
-
+#include "mt352.h"
+#include "mt352_priv.h" /* FIXME */
+#include "tda1004x.h"
+#include "nxt200x.h"
+
+#include "tda10086.h"
+#include "tda826x.h"
+#include "isl6421.h"
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
@@ -54,8 +51,6 @@ module_param(antenna_pwr, int, 0444);
MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
/* ------------------------------------------------------------------ */
-
-#ifdef HAVE_MT352
static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
{
u32 ok;
@@ -185,12 +180,8 @@ static struct mt352_config avermedia_777 = {
.demod_address = 0xf,
.demod_init = mt352_aver777_init,
};
-#endif
/* ------------------------------------------------------------------ */
-
-#ifdef HAVE_TDA1004X
-
static int philips_tda6651_pll_set(u8 addr, struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
@@ -883,6 +874,34 @@ static struct tda1004x_config philips_tiger_config = {
/* ------------------------------------------------------------------ */
+static int asus_p7131_dual_tuner_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x6a};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+ /* make sure the DVB-T antenna input is set */
+ saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000);
+ return 0;
+}
+
+static int asus_p7131_dual_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x68};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ /* reset antenna inputs for analog usage */
+ saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0200000);
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
static int lifeview_trio_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
int ret;
@@ -969,11 +988,58 @@ static struct tda1004x_config tevion_dvbt220rf_config = {
.request_firmware = NULL,
};
-#endif
+/* ------------------------------------------------------------------ */
+
+static int md8800_dvbt_analog_mode(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 data[] = { 0x3c, 0x33, 0x68};
+ struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)};
+
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ philips_tda827xa_tuner_sleep( 0x61, fe);
+ return 0;
+}
+
+static int md8800_dvbt_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ int ret;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tda8290_close[] = { 0x21, 0xc0};
+ static u8 tda8290_open[] = { 0x21, 0x80};
+ struct i2c_msg tda8290_msg = {.addr = 0x4b,.flags = 0, .len = 2};
+ /* close tda8290 i2c bridge */
+ tda8290_msg.buf = tda8290_close;
+ ret = i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+ if (ret != 1)
+ return -EIO;
+ msleep(20);
+ ret = philips_tda827xa_pll_set(0x60, fe, params);
+ if (ret != 0)
+ return ret;
+ /* open tda8290 i2c bridge */
+ tda8290_msg.buf = tda8290_open;
+ i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1);
+ return ret;
+}
+
+static struct tda1004x_config md8800_dvbt_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .if_freq = TDA10046_FREQ_045,
+ .request_firmware = NULL,
+};
+
+static struct tda10086_config flydvbs = {
+ .demod_address = 0x0e,
+ .invert = 0,
+};
/* ------------------------------------------------------------------ */
-#ifdef HAVE_NXT200X
static struct nxt200x_config avertvhda180 = {
.demod_address = 0x0a,
};
@@ -991,7 +1057,6 @@ static struct nxt200x_config kworldatsc110 = {
.demod_address = 0x0a,
.set_pll_input = nxt200x_set_pll_input,
};
-#endif
/* ------------------------------------------------------------------ */
@@ -1009,29 +1074,27 @@ static int dvb_init(struct saa7134_dev *dev)
dev);
switch (dev->board) {
-#ifdef HAVE_MT352
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
printk("%s: pinnacle 300i dvb setup\n",dev->name);
- dev->dvb.frontend = mt352_attach(&pinnacle_300i,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(mt352_attach, &pinnacle_300i,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.set_params = mt352_pinnacle_tuner_set_params;
}
break;
-
case SAA7134_BOARD_AVERMEDIA_777:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
printk("%s: avertv 777 dvb setup\n",dev->name);
- dev->dvb.frontend = mt352_attach(&avermedia_777,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.calc_regs = mt352_aver777_tuner_calc_regs;
}
break;
-#endif
-#ifdef HAVE_TDA1004X
case SAA7134_BOARD_MD7134:
- dev->dvb.frontend = tda10046_attach(&medion_cardbus,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &medion_cardbus,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
@@ -1039,16 +1102,18 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
- dev->dvb.frontend = tda10046_attach(&philips_tu1216_60_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tu1216_60_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_60_init;
dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_60_set_params;
}
break;
case SAA7134_BOARD_FLYDVBTDUO:
- dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &tda827x_lifeview_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
@@ -1056,8 +1121,9 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
- dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &tda827x_lifeview_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
@@ -1065,8 +1131,9 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
- dev->dvb.frontend = tda10046_attach(&philips_europa_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_europa_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
@@ -1076,8 +1143,9 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
- dev->dvb.frontend = tda10046_attach(&philips_europa_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_europa_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
@@ -1085,16 +1153,18 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
- dev->dvb.frontend = tda10046_attach(&philips_tu1216_61_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tu1216_61_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tu1216_tuner_61_init;
dev->dvb.frontend->ops.tuner_ops.set_params = philips_tu1216_tuner_61_set_params;
}
break;
case SAA7134_BOARD_PHILIPS_TIGER:
- dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tiger_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
@@ -1102,17 +1172,19 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- dev->dvb.frontend = tda10046_attach(&philips_tiger_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &philips_tiger_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
- dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
- dev->dvb.frontend->ops.tuner_ops.sleep = philips_tiger_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.init = asus_p7131_dual_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = asus_p7131_dual_tuner_sleep;
dev->dvb.frontend->ops.tuner_ops.set_params = philips_tiger_tuner_set_params;
}
break;
case SAA7134_BOARD_FLYDVBT_LR301:
- dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &tda827x_lifeview_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = philips_tda827x_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = philips_tda827x_tuner_sleep;
@@ -1120,16 +1192,18 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_FLYDVB_TRIO:
- dev->dvb.frontend = tda10046_attach(&lifeview_trio_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &lifeview_trio_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.sleep = lifeview_trio_tuner_sleep;
dev->dvb.frontend->ops.tuner_ops.set_params = lifeview_trio_tuner_set_params;
}
break;
case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331:
- dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &ads_tech_duo_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
@@ -1137,37 +1211,75 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
- dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &tevion_dvbt220rf_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.sleep = tevion_dvb220rf_tuner_sleep;
dev->dvb.frontend->ops.tuner_ops.set_params = tevion_dvb220rf_tuner_set_params;
}
break;
case SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS:
- dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config,
- &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach,
+ &ads_tech_duo_config,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
dev->dvb.frontend->ops.tuner_ops.init = ads_duo_tuner_init;
dev->dvb.frontend->ops.tuner_ops.sleep = ads_duo_tuner_sleep;
dev->dvb.frontend->ops.tuner_ops.set_params = ads_duo_tuner_set_params;
}
break;
-#endif
-#ifdef HAVE_NXT200X
+ case SAA7134_BOARD_MEDION_MD8800_QUADRO:
+ dev->dvb.frontend = tda10046_attach(&md8800_dvbt_config,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->dvb.frontend->ops.tuner_ops.init = philips_tiger_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = md8800_dvbt_analog_mode;
+ dev->dvb.frontend->ops.tuner_ops.set_params = md8800_dvbt_pll_set;
+ }
+ break;
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
- dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
- dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tdhu2);
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, &dvb_pll_tdhu2);
}
break;
case SAA7134_BOARD_KWORLD_ATSC110:
- dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
+ NULL, &dvb_pll_tuv1236d);
+ }
+ break;
+ case SAA7134_BOARD_FLYDVBS_LR300:
+ dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+ &dev->i2c_adap);
if (dev->dvb.frontend) {
- dvb_pll_attach(dev->dvb.frontend, 0x61, &dev->i2c_adap, &dvb_pll_tuv1236d);
+ if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL) {
+ printk("%s: No tda826x found!\n", __FUNCTION__);
+ }
+ if (dvb_attach(isl6421_attach, dev->dvb.frontend,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL) {
+ printk("%s: No ISL6421 found!\n", __FUNCTION__);
+ }
}
break;
-#endif
+ case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
+ dev->dvb.frontend = tda10046_attach(&medion_cardbus,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
+ dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ dev->dvb.frontend->ops.tuner_ops.init = philips_fmd1216_tuner_init;
+ dev->dvb.frontend->ops.tuner_ops.sleep = philips_fmd1216_tuner_sleep;
+ dev->dvb.frontend->ops.tuner_ops.set_params = philips_fmd1216_tuner_set_params;
+ }
+ break;
+
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
break;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index 7c595492c56b..ff5991136f4e 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -185,6 +185,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+ case SAA7134_BOARD_AVERMEDIA_A16AR:
ir_codes = ir_codes_avermedia;
mask_keycode = 0x0007C8;
mask_keydown = 0x000010;
@@ -228,6 +229,12 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x400000;
polling = 50; // ms
break;
+ case SAA7134_BOARD_PROTEUS_2309:
+ ir_codes = ir_codes_proteus_2309;
+ mask_keycode = 0x00007F;
+ mask_keyup = 0x000080;
+ polling = 50; // ms
+ break;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
ir_codes = ir_codes_videomate_tv_pvr;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 2e3ba5f31453..bfcb860d14cc 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -814,7 +814,7 @@ struct file_operations saa7134_mixer_fops = {
/* ------------------------------------------------------------------ */
-static irqreturn_t saa7134_oss_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t saa7134_oss_irq(int irq, void *dev_id)
{
struct saa7134_dmasound *dmasound = dev_id;
struct saa7134_dev *dev = dmasound->priv_data;
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 0db53d192b2a..dd759d6d8d25 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -72,12 +72,12 @@ static struct mainscan {
int carr;
} mainscan[] = {
{
- .name = "M",
- .std = V4L2_STD_NTSC | V4L2_STD_PAL_M,
+ .name = "MN",
+ .std = V4L2_STD_MN,
.carr = 4500,
},{
- .name = "BG",
- .std = V4L2_STD_PAL_BG,
+ .name = "BGH",
+ .std = V4L2_STD_B | V4L2_STD_GH,
.carr = 5500,
},{
.name = "I",
@@ -85,7 +85,7 @@ static struct mainscan {
.carr = 6000,
},{
.name = "DKL",
- .std = V4L2_STD_PAL_DK | V4L2_STD_SECAM,
+ .std = V4L2_STD_DK | V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC,
.carr = 6500,
}
};
@@ -93,76 +93,70 @@ static struct mainscan {
static struct saa7134_tvaudio tvaudio[] = {
{
.name = "PAL-B/G FM-stereo",
- .std = V4L2_STD_PAL,
+ .std = V4L2_STD_PAL_BG,
.mode = TVAUDIO_FM_BG_STEREO,
.carr1 = 5500,
.carr2 = 5742,
},{
.name = "PAL-D/K1 FM-stereo",
- .std = V4L2_STD_PAL,
+ .std = V4L2_STD_PAL_DK,
.carr1 = 6500,
.carr2 = 6258,
.mode = TVAUDIO_FM_BG_STEREO,
},{
.name = "PAL-D/K2 FM-stereo",
- .std = V4L2_STD_PAL,
+ .std = V4L2_STD_PAL_DK,
.carr1 = 6500,
.carr2 = 6742,
.mode = TVAUDIO_FM_BG_STEREO,
},{
.name = "PAL-D/K3 FM-stereo",
- .std = V4L2_STD_PAL,
+ .std = V4L2_STD_PAL_DK,
.carr1 = 6500,
.carr2 = 5742,
.mode = TVAUDIO_FM_BG_STEREO,
},{
.name = "PAL-B/G NICAM",
- .std = V4L2_STD_PAL,
+ .std = V4L2_STD_PAL_BG,
.carr1 = 5500,
.carr2 = 5850,
.mode = TVAUDIO_NICAM_FM,
},{
.name = "PAL-I NICAM",
- .std = V4L2_STD_PAL,
+ .std = V4L2_STD_PAL_I,
.carr1 = 6000,
.carr2 = 6552,
.mode = TVAUDIO_NICAM_FM,
},{
.name = "PAL-D/K NICAM",
- .std = V4L2_STD_PAL,
+ .std = V4L2_STD_PAL_DK,
.carr1 = 6500,
.carr2 = 5850,
.mode = TVAUDIO_NICAM_FM,
},{
.name = "SECAM-L NICAM",
- .std = V4L2_STD_SECAM,
+ .std = V4L2_STD_SECAM_L,
.carr1 = 6500,
.carr2 = 5850,
.mode = TVAUDIO_NICAM_AM,
},{
- .name = "SECAM-L MONO",
- .std = V4L2_STD_SECAM,
+ .name = "SECAM-D/K NICAM",
+ .std = V4L2_STD_SECAM_DK,
.carr1 = 6500,
- .carr2 = -1,
- .mode = TVAUDIO_AM_MONO,
+ .carr2 = 5850,
+ .mode = TVAUDIO_NICAM_FM,
},{
- .name = "SECAM-D/K",
- .std = V4L2_STD_SECAM,
- .carr1 = 6500,
- .carr2 = -1,
- .mode = TVAUDIO_FM_MONO,
+ .name = "NTSC-A2 FM-stereo",
+ .std = V4L2_STD_NTSC,
+ .carr1 = 4500,
+ .carr2 = 4724,
+ .mode = TVAUDIO_FM_K_STEREO,
},{
.name = "NTSC-M",
.std = V4L2_STD_NTSC,
.carr1 = 4500,
.carr2 = -1,
.mode = TVAUDIO_FM_MONO,
- },{
- .name = "NTSC-A2 FM-stereo",
- .std = V4L2_STD_NTSC,
- .carr1 = 4500,
- .carr2 = 4724,
- .mode = TVAUDIO_FM_K_STEREO,
}
};
#define TVAUDIO (sizeof(tvaudio)/sizeof(struct saa7134_tvaudio))
@@ -340,12 +334,6 @@ static void tvaudio_setmode(struct saa7134_dev *dev,
saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1);
saa_writeb(SAA7134_NICAM_CONFIG, 0x00);
break;
- case TVAUDIO_AM_MONO:
- saa_writeb(SAA7134_DEMODULATOR, 0x12);
- saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00);
- saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44);
- saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0);
- break;
case TVAUDIO_FM_SAT_STEREO:
/* not implemented (yet) */
break;
@@ -390,7 +378,6 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
}
printk("\n");
}
-
if (dev->tvnorm->id & scan->std) {
tvaudio_setcarrier(dev,scan->carr-90,scan->carr-90);
saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
@@ -426,7 +413,6 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
switch (audio->mode) {
case TVAUDIO_FM_MONO:
- case TVAUDIO_AM_MONO:
return V4L2_TUNER_SUB_MONO;
case TVAUDIO_FM_K_STEREO:
case TVAUDIO_FM_BG_STEREO:
@@ -495,7 +481,6 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
switch (audio->mode) {
case TVAUDIO_FM_MONO:
- case TVAUDIO_AM_MONO:
/* nothing to do ... */
break;
case TVAUDIO_FM_K_STEREO:
@@ -556,6 +541,7 @@ static int tvaudio_thread(void *data)
if (1 == nscan) {
/* only one candidate -- skip scan ;) */
+ dprintk("only one main carrier candidate - skipping scan\n");
max1 = 12345;
carrier = default_carrier;
} else {
@@ -603,7 +589,6 @@ static int tvaudio_thread(void *data)
dev->automute = 0;
saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
saa7134_tvaudio_setmute(dev);
-
/* find the exact tv audio norm */
for (audio = UNSET, i = 0; i < TVAUDIO; i++) {
if (dev->tvnorm->id != UNSET &&
@@ -611,7 +596,7 @@ static int tvaudio_thread(void *data)
continue;
if (tvaudio[i].carr1 != carrier)
continue;
-
+ /* Note: at least the primary carrier is right here */
if (UNSET == audio)
audio = i;
tvaudio_setmode(dev,&tvaudio[i],"trying");
@@ -626,6 +611,7 @@ static int tvaudio_thread(void *data)
if (UNSET == audio)
continue;
tvaudio_setmode(dev,&tvaudio[audio],"using");
+
tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO);
dev->tvaudio = &tvaudio[audio];
@@ -750,7 +736,6 @@ static int mute_input_7133(struct saa7134_dev *dev)
int mask;
struct saa7134_input *in;
- /* Hac 0506 route OSS sound simultanously */
xbarin = 0x03;
switch (dev->input->amux) {
case TV:
@@ -834,18 +819,16 @@ static int tvaudio_thread_ddep(void *data)
} else {
/* (let chip) scan for sound carrier */
norms = 0;
- if (dev->tvnorm->id & V4L2_STD_PAL) {
- dprintk("PAL scan\n");
- norms |= 0x2c; /* B/G + D/K + I */
- }
- if (dev->tvnorm->id & V4L2_STD_NTSC) {
- dprintk("NTSC scan\n");
- norms |= 0x40; /* M */
- }
- if (dev->tvnorm->id & V4L2_STD_SECAM) {
- dprintk("SECAM scan\n");
- norms |= 0x18; /* L + D/K */
- }
+ if (dev->tvnorm->id & (V4L2_STD_B | V4L2_STD_GH))
+ norms |= 0x04;
+ if (dev->tvnorm->id & V4L2_STD_PAL_I)
+ norms |= 0x20;
+ if (dev->tvnorm->id & V4L2_STD_DK)
+ norms |= 0x08;
+ if (dev->tvnorm->id & V4L2_STD_MN)
+ norms |= 0x40;
+ if (dev->tvnorm->id & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC))
+ norms |= 0x10;
if (0 == norms)
norms = 0x7c; /* all */
dprintk("scanning:%s%s%s%s%s\n",
@@ -1034,7 +1017,11 @@ int saa7134_tvaudio_fini(struct saa7134_dev *dev)
int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
{
- if (dev->thread.pid >= 0) {
+ if (dev->input->amux != TV) {
+ dprintk("sound IF not in use, skipping scan\n");
+ dev->automute = 0;
+ saa7134_tvaudio_setmute(dev);
+ } else if (dev->thread.pid >= 0) {
dev->thread.mode = UNSET;
dev->thread.scan2++;
wake_up_interruptible(&dev->thread.wq);
@@ -1046,6 +1033,7 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
}
EXPORT_SYMBOL(saa_dsp_writel);
+EXPORT_SYMBOL(saa7134_tvaudio_setmute);
/* ----------------------------------------------------------- */
/*
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 2c171af9a9f2..830617ea81cc 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -43,12 +43,16 @@ static unsigned int gbuffers = 8;
static unsigned int noninterlaced = 1;
static unsigned int gbufsize = 720*576*4;
static unsigned int gbufsize_max = 720*576*4;
+static char secam[] = "--";
module_param(video_debug, int, 0644);
MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
module_param(gbuffers, int, 0444);
MODULE_PARM_DESC(gbuffers,"number of capture buffers, range 2-32");
module_param(noninterlaced, int, 0644);
MODULE_PARM_DESC(noninterlaced,"capture non interlaced video");
+module_param_string(secam, secam, sizeof(secam), 0644);
+MODULE_PARM_DESC(secam, "force SECAM variant, either DK,L or Lc");
+
#define dprintk(fmt, arg...) if (video_debug) \
printk(KERN_DEBUG "%s/video: " fmt, dev->name , ## arg)
@@ -279,7 +283,43 @@ static struct saa7134_tvnorm tvnorms[] = {
.id = V4L2_STD_SECAM,
NORM_625_50,
- .sync_control = 0x18, /* old: 0x58, */
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "SECAM-DK",
+ .id = V4L2_STD_SECAM_DK,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "SECAM-L",
+ .id = V4L2_STD_SECAM_L,
+ NORM_625_50,
+
+ .sync_control = 0x18,
+ .luma_control = 0x1b,
+ .chroma_ctrl1 = 0xd1,
+ .chroma_gain = 0x80,
+ .chroma_ctrl2 = 0x00,
+ .vgate_misc = 0x1c,
+
+ },{
+ .name = "SECAM-Lc",
+ .id = V4L2_STD_SECAM_LC,
+ NORM_625_50,
+
+ .sync_control = 0x18,
.luma_control = 0x1b,
.chroma_ctrl1 = 0xd1,
.chroma_gain = 0x80,
@@ -1769,6 +1809,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
v4l2_std_id *id = arg;
unsigned int i;
+ v4l2_std_id fixup;
for (i = 0; i < TVNORMS; i++)
if (*id == tvnorms[i].id)
@@ -1779,7 +1820,22 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
break;
if (i == TVNORMS)
return -EINVAL;
-
+ if ((*id & V4L2_STD_SECAM) && (secam[0] != '-')) {
+ if (secam[0] == 'L' || secam[0] == 'l') {
+ if (secam[1] == 'C' || secam[1] == 'c')
+ fixup = V4L2_STD_SECAM_LC;
+ else
+ fixup = V4L2_STD_SECAM_L;
+ } else {
+ if (secam[0] == 'D' || secam[0] == 'd')
+ fixup = V4L2_STD_SECAM_DK;
+ else
+ fixup = V4L2_STD_SECAM;
+ }
+ for (i = 0; i < TVNORMS; i++)
+ if (fixup == tvnorms[i].id)
+ break;
+ }
mutex_lock(&dev->lock);
if (res_check(fh, RESOURCE_OVERLAY)) {
spin_lock_irqsave(&dev->slock,flags);
@@ -2192,7 +2248,11 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
t->type = V4L2_TUNER_RADIO;
saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
-
+ if (dev->input->amux == TV) {
+ t->signal = 0xf800 - ((saa_readb(0x581) & 0x1f) << 11);
+ t->rxsubchans = (saa_readb(0x529) & 0x08) ?
+ V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
+ }
return 0;
}
case VIDIOC_S_TUNER:
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index c04ce6152fd5..7cf96b430250 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -61,7 +61,6 @@ enum saa7134_tvaudio_mode {
TVAUDIO_FM_K_STEREO = 4,
TVAUDIO_NICAM_AM = 5,
TVAUDIO_NICAM_FM = 6,
- TVAUDIO_AM_MONO = 7
};
enum saa7134_audio_in {
@@ -223,6 +222,11 @@ struct saa7134_format {
#define SAA7134_BOARD_MD7134_BRIDGE_2 93
#define SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS 94
#define SAA7134_BOARD_FLYVIDEO3000_NTSC 95
+#define SAA7134_BOARD_MEDION_MD8800_QUADRO 96
+#define SAA7134_BOARD_FLYDVBS_LR300 97
+#define SAA7134_BOARD_PROTEUS_2309 98
+#define SAA7134_BOARD_AVERMEDIA_A16AR 99
+#define SAA7134_BOARD_ASUS_EUROPA2_HYBRID 100
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index 67987baee77a..7aeec574d7ce 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -282,7 +282,7 @@ static void se401_auto_resetlevel(struct usb_se401 *se401)
}
/* irq handler for snapshot button */
-static void se401_button_irq(struct urb *urb, struct pt_regs *regs)
+static void se401_button_irq(struct urb *urb)
{
struct usb_se401 *se401 = urb->context;
int status;
@@ -318,7 +318,7 @@ exit:
__FUNCTION__, status);
}
-static void se401_video_irq(struct urb *urb, struct pt_regs *regs)
+static void se401_video_irq(struct urb *urb)
{
struct usb_se401 *se401 = urb->context;
int length = urb->actual_length;
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 48d138a7c723..a4702d3c2aca 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -518,7 +518,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
}
-static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
+static void sn9c102_urb_complete(struct urb *urb)
{
struct sn9c102_device* cam = urb->context;
struct sn9c102_frame_t** f;
@@ -1240,23 +1240,53 @@ static CLASS_DEVICE_ATTR(frame_header, S_IRUGO,
sn9c102_show_frame_header, NULL);
-static void sn9c102_create_sysfs(struct sn9c102_device* cam)
+static int sn9c102_create_sysfs(struct sn9c102_device* cam)
{
struct video_device *v4ldev = cam->v4ldev;
+ int rc;
+
+ rc = video_device_create_file(v4ldev, &class_device_attr_reg);
+ if (rc) goto err;
+ rc = video_device_create_file(v4ldev, &class_device_attr_val);
+ if (rc) goto err_reg;
+ rc = video_device_create_file(v4ldev, &class_device_attr_frame_header);
+ if (rc) goto err_val;
- video_device_create_file(v4ldev, &class_device_attr_reg);
- video_device_create_file(v4ldev, &class_device_attr_val);
- video_device_create_file(v4ldev, &class_device_attr_frame_header);
- if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102)
- video_device_create_file(v4ldev, &class_device_attr_green);
- else if (cam->bridge == BRIDGE_SN9C103) {
- video_device_create_file(v4ldev, &class_device_attr_blue);
- video_device_create_file(v4ldev, &class_device_attr_red);
- }
if (cam->sensor.sysfs_ops) {
- video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
- video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
+ if (rc) goto err_frhead;
+ rc = video_device_create_file(v4ldev, &class_device_attr_i2c_val);
+ if (rc) goto err_i2c_reg;
+ }
+
+ if (cam->bridge == BRIDGE_SN9C101 || cam->bridge == BRIDGE_SN9C102) {
+ rc = video_device_create_file(v4ldev, &class_device_attr_green);
+ if (rc) goto err_i2c_val;
+ } else if (cam->bridge == BRIDGE_SN9C103) {
+ rc = video_device_create_file(v4ldev, &class_device_attr_blue);
+ if (rc) goto err_i2c_val;
+ rc = video_device_create_file(v4ldev, &class_device_attr_red);
+ if (rc) goto err_blue;
}
+
+ return 0;
+
+err_blue:
+ video_device_remove_file(v4ldev, &class_device_attr_blue);
+err_i2c_val:
+ if (cam->sensor.sysfs_ops)
+ video_device_remove_file(v4ldev, &class_device_attr_i2c_val);
+err_i2c_reg:
+ if (cam->sensor.sysfs_ops)
+ video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
+err_frhead:
+ video_device_remove_file(v4ldev, &class_device_attr_frame_header);
+err_val:
+ video_device_remove_file(v4ldev, &class_device_attr_val);
+err_reg:
+ video_device_remove_file(v4ldev, &class_device_attr_reg);
+err:
+ return rc;
}
#endif /* CONFIG_VIDEO_ADV_DEBUG */
@@ -2809,10 +2839,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
DBG(1, "V4L2 device registration failed");
if (err == -ENFILE && video_nr[dev_nr] == -1)
DBG(1, "Free /dev/videoX node not found");
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
- mutex_unlock(&cam->dev_mutex);
- goto fail;
+ goto fail2;
}
DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
@@ -2823,7 +2850,9 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
#ifdef CONFIG_VIDEO_ADV_DEBUG
- sn9c102_create_sysfs(cam);
+ err = sn9c102_create_sysfs(cam);
+ if (err)
+ goto fail3;
DBG(2, "Optional device control through 'sysfs' interface ready");
#endif
@@ -2833,6 +2862,14 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
return 0;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+fail3:
+ video_unregister_device(cam->v4ldev);
+#endif
+fail2:
+ video_nr[dev_nr] = -1;
+ dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
+ mutex_unlock(&cam->dev_mutex);
fail:
if (cam) {
kfree(cam->control_buffer);
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 5686547ba76a..525d81288d55 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -406,7 +406,7 @@ static void send_osd_data(struct saa7146 *saa)
}
}
-static irqreturn_t saa7146_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t saa7146_irq(int irq, void *dev_id)
{
struct saa7146 *saa = dev_id;
u32 stat, astat;
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index 2ba2991a214f..6d1ef1e2e8ef 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -516,16 +516,45 @@ stv680_file(frames_read, framecount, "%d\n");
stv680_file(packets_dropped, dropped, "%d\n");
stv680_file(decoding_errors, error, "%d\n");
-static void stv680_create_sysfs_files(struct video_device *vdev)
+static int stv680_create_sysfs_files(struct video_device *vdev)
{
- video_device_create_file(vdev, &class_device_attr_model);
- video_device_create_file(vdev, &class_device_attr_in_use);
- video_device_create_file(vdev, &class_device_attr_streaming);
- video_device_create_file(vdev, &class_device_attr_palette);
- video_device_create_file(vdev, &class_device_attr_frames_total);
- video_device_create_file(vdev, &class_device_attr_frames_read);
- video_device_create_file(vdev, &class_device_attr_packets_dropped);
- video_device_create_file(vdev, &class_device_attr_decoding_errors);
+ int rc;
+
+ rc = video_device_create_file(vdev, &class_device_attr_model);
+ if (rc) goto err;
+ rc = video_device_create_file(vdev, &class_device_attr_in_use);
+ if (rc) goto err_model;
+ rc = video_device_create_file(vdev, &class_device_attr_streaming);
+ if (rc) goto err_inuse;
+ rc = video_device_create_file(vdev, &class_device_attr_palette);
+ if (rc) goto err_stream;
+ rc = video_device_create_file(vdev, &class_device_attr_frames_total);
+ if (rc) goto err_pal;
+ rc = video_device_create_file(vdev, &class_device_attr_frames_read);
+ if (rc) goto err_framtot;
+ rc = video_device_create_file(vdev, &class_device_attr_packets_dropped);
+ if (rc) goto err_framread;
+ rc = video_device_create_file(vdev, &class_device_attr_decoding_errors);
+ if (rc) goto err_dropped;
+
+ return 0;
+
+err_dropped:
+ video_device_remove_file(vdev, &class_device_attr_packets_dropped);
+err_framread:
+ video_device_remove_file(vdev, &class_device_attr_frames_read);
+err_framtot:
+ video_device_remove_file(vdev, &class_device_attr_frames_total);
+err_pal:
+ video_device_remove_file(vdev, &class_device_attr_palette);
+err_stream:
+ video_device_remove_file(vdev, &class_device_attr_streaming);
+err_inuse:
+ video_device_remove_file(vdev, &class_device_attr_in_use);
+err_model:
+ video_device_remove_file(vdev, &class_device_attr_model);
+err:
+ return rc;
}
static void stv680_remove_sysfs_files(struct video_device *vdev)
@@ -582,7 +611,7 @@ static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
return 0;
}
-static void stv680_video_irq (struct urb *urb, struct pt_regs *regs)
+static void stv680_video_irq (struct urb *urb)
{
struct usb_stv *stv680 = urb->context;
int length = urb->actual_length;
@@ -1418,9 +1447,13 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
PDEBUG (0, "STV(i): registered new video device: video%d", stv680->vdev->minor);
usb_set_intfdata (intf, stv680);
- stv680_create_sysfs_files(stv680->vdev);
+ retval = stv680_create_sysfs_files(stv680->vdev);
+ if (retval)
+ goto error_unreg;
return 0;
+error_unreg:
+ video_unregister_device(stv680->vdev);
error_vdev:
video_device_release(stv680->vdev);
error:
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 8dab481d384a..87ffb0e84a7a 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -480,6 +480,8 @@ static int tda9887_set_config(struct tuner *t, char *buf)
}
if ((t->tda9887_config & TDA9887_INTERCARRIER_NTSC) && (t->std & V4L2_STD_NTSC))
buf[1] &= ~cQSS;
+ if (t->tda9887_config & TDA9887_GATING_18)
+ buf[3] &= ~cGating_36;
return 0;
}
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index abe37cf632c6..63db4e97ae6c 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -10,7 +10,7 @@
#include <media/v4l2-common.h>
static int offset = 0;
-module_param(offset, int, 0666);
+module_param(offset, int, 0664);
MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
/* ---------------------------------------------------------------------- */
@@ -331,6 +331,8 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
else if (params->default_top_high)
config |= TDA9887_TOP(params->default_top_high);
}
+ if (params->default_pll_gating_18)
+ config |= TDA9887_GATING_18;
i2c_clients_command(c->adapter, TDA9887_SET_CONFIG, &config);
}
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -439,8 +441,6 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
buffer[3] = 0xa4;
break;
}
- buffer[0] = (div>>8) & 0x7f;
- buffer[1] = div & 0xff;
if (params->cb_first_if_lower_freq && div < t->last_div) {
buffer[0] = buffer[2];
buffer[1] = buffer[3];
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 8b542599ed47..781682373b61 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -650,6 +650,7 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = {
.count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges),
.has_tda9887 = 1,
.port1_invert_for_secam_lc = 1,
+ .default_pll_gating_18 = 1,
},
};
@@ -1045,7 +1046,6 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges,
.count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges),
- .has_tda9887 = 1,
},
};
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 936e3f746fba..fcaef4bf8289 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -28,6 +28,7 @@
#include <linux/i2c-algo-bit.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
+#include <linux/kthread.h>
#include <media/tvaudio.h>
#include <media/v4l2-common.h>
@@ -124,11 +125,8 @@ struct CHIPSTATE {
int input;
/* thread */
- pid_t tpid;
- struct completion texit;
- wait_queue_head_t wq;
+ struct task_struct *thread;
struct timer_list wt;
- int done;
int watch_stereo;
int audmode;
};
@@ -264,28 +262,23 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
static void chip_thread_wake(unsigned long data)
{
struct CHIPSTATE *chip = (struct CHIPSTATE*)data;
- wake_up_interruptible(&chip->wq);
+ wake_up_process(chip->thread);
}
static int chip_thread(void *data)
{
- DECLARE_WAITQUEUE(wait, current);
struct CHIPSTATE *chip = data;
struct CHIPDESC *desc = chiplist + chip->type;
- daemonize("%s", chip->c.name);
- allow_signal(SIGTERM);
v4l_dbg(1, debug, &chip->c, "%s: thread started\n", chip->c.name);
for (;;) {
- add_wait_queue(&chip->wq, &wait);
- if (!chip->done) {
- set_current_state(TASK_INTERRUPTIBLE);
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!kthread_should_stop())
schedule();
- }
- remove_wait_queue(&chip->wq, &wait);
+ set_current_state(TASK_RUNNING);
try_to_freeze();
- if (chip->done || signal_pending(current))
+ if (kthread_should_stop())
break;
v4l_dbg(1, debug, &chip->c, "%s: thread wakeup\n", chip->c.name);
@@ -301,7 +294,6 @@ static int chip_thread(void *data)
}
v4l_dbg(1, debug, &chip->c, "%s: thread exiting\n", chip->c.name);
- complete_and_exit(&chip->texit, 0);
return 0;
}
@@ -1536,19 +1528,18 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind)
chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
}
- chip->tpid = -1;
+ chip->thread = NULL;
if (desc->checkmode) {
/* start async thread */
init_timer(&chip->wt);
chip->wt.function = chip_thread_wake;
chip->wt.data = (unsigned long)chip;
- init_waitqueue_head(&chip->wq);
- init_completion(&chip->texit);
- chip->tpid = kernel_thread(chip_thread,(void *)chip,0);
- if (chip->tpid < 0)
- v4l_warn(&chip->c, "%s: kernel_thread() failed\n",
+ chip->thread = kthread_run(chip_thread, chip, chip->c.name);
+ if (IS_ERR(chip->thread)) {
+ v4l_warn(&chip->c, "%s: failed to create kthread\n",
chip->c.name);
- wake_up_interruptible(&chip->wq);
+ chip->thread = NULL;
+ }
}
return 0;
}
@@ -1569,11 +1560,10 @@ static int chip_detach(struct i2c_client *client)
struct CHIPSTATE *chip = i2c_get_clientdata(client);
del_timer_sync(&chip->wt);
- if (chip->tpid >= 0) {
+ if (chip->thread) {
/* shutdown async thread */
- chip->done = 1;
- wake_up_interruptible(&chip->wq);
- wait_for_completion(&chip->texit);
+ kthread_stop(chip->thread);
+ chip->thread = NULL;
}
i2c_detach_client(&chip->c);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index d95529e8e513..e6baaee038bf 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -222,8 +222,8 @@ hauppauge_tuner[] =
{ TUNER_TCL_2002MB, "TCL M2523_3DB_E"},
{ TUNER_ABSENT, "Philips 8275A"},
{ TUNER_ABSENT, "Microtune MT2060"},
- { TUNER_ABSENT, "Philips FM1236 MK5"},
- { TUNER_ABSENT, "Philips FM1216ME MK5"},
+ { TUNER_PHILIPS_FM1236_MK3, "Philips FM1236 MK5"},
+ { TUNER_PHILIPS_FM1216ME_MK3, "Philips FM1216ME MK5"},
{ TUNER_ABSENT, "TCL M2523_3DI_E"},
{ TUNER_ABSENT, "Samsung THPD5222FG30A"},
/* 120-129 */
@@ -605,6 +605,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->tuner_formats |= hauppauge_tuner_fmt[i].id;
t_fmt_name1[j++] = hauppauge_tuner_fmt[i].name;
}
+ }
+ for (i = j = 0; i < 8; i++) {
if (t_format2 & (1 << i)) {
tvee->tuner2_formats |= hauppauge_tuner_fmt[i].id;
t_fmt_name2[j++] = hauppauge_tuner_fmt[i].name;
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index b167ffab2520..bc0a4fc27b24 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -294,7 +294,7 @@ static inline void tvp5150_selmux(struct i2c_client *c)
if ((decoder->route.output & TVP5150_BLACK_SCREEN) || !decoder->enable)
input = 8;
- switch (input) {
+ switch (decoder->route.input) {
case TVP5150_COMPOSITE1:
input |= 2;
/* fall through */
@@ -308,6 +308,11 @@ static inline void tvp5150_selmux(struct i2c_client *c)
break;
}
+ tvp5150_dbg( 1, "Selecting video route: route input=%i, output=%i "
+ "=> tvp5150 input=%i, opmode=%i\n",
+ decoder->route.input,decoder->route.output,
+ input, opmode );
+
tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
};
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 6f31ecc88843..abe214619092 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -222,6 +222,7 @@ static void konicawc_adjust_picture(struct uvd *uvd)
static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
{
struct input_dev *input_dev;
+ int error;
usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
strncat(cam->input_physname, "/input0", sizeof(cam->input_physname));
@@ -242,7 +243,13 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
input_dev->private = cam;
- input_register_device(cam->input);
+ error = input_register_device(cam->input);
+ if (error) {
+ warn("Failed to register camera's input device, err: %d\n",
+ error);
+ input_free_device(cam->input);
+ cam->input = NULL;
+ }
}
static void konicawc_unregister_input(struct konicawc *cam)
@@ -380,7 +387,7 @@ static void resubmit_urb(struct uvd *uvd, struct urb *urb)
}
-static void konicawc_isoc_irq(struct urb *urb, struct pt_regs *regs)
+static void konicawc_isoc_irq(struct urb *urb)
{
struct uvd *uvd = urb->context;
struct konicawc *cam = (struct konicawc *)uvd->user_data;
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index 56e01b622417..9a26b9484aae 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -125,7 +125,7 @@ static void qcm_report_buttonstat(struct qcm *cam)
}
}
-static void qcm_int_irq(struct urb *urb, struct pt_regs *regs)
+static void qcm_int_irq(struct urb *urb)
{
int ret;
struct uvd *uvd = urb->context;
@@ -606,7 +606,7 @@ static void resubmit_urb(struct uvd *uvd, struct urb *urb)
err("usb_submit_urb error (%d)", ret);
}
-static void qcm_isoc_irq(struct urb *urb, struct pt_regs *regs)
+static void qcm_isoc_irq(struct urb *urb)
{
int len;
struct uvd *uvd = urb->context;
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index 13b37c8c0d56..d8b88024bc2f 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -1680,7 +1680,7 @@ static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
return totlen;
}
-static void usbvideo_IsocIrq(struct urb *urb, struct pt_regs *regs)
+static void usbvideo_IsocIrq(struct urb *urb)
{
int i, ret, len;
struct uvd *uvd = urb->context;
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index 90d48e8510ba..08f9559a6bfa 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -7,6 +7,7 @@
* Monroe Williams (monroe@pobox.com)
*
* Supports 3COM HomeConnect PC Digital WebCam
+ * Supports Compro PS39U WebCam
*
* 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
@@ -60,6 +61,8 @@
/* Define these values to match your device */
#define USB_VICAM_VENDOR_ID 0x04c1
#define USB_VICAM_PRODUCT_ID 0x009d
+#define USB_COMPRO_VENDOR_ID 0x0602
+#define USB_COMPRO_PRODUCT_ID 0x1001
#define VICAM_BYTES_PER_PIXEL 3
#define VICAM_MAX_READ_SIZE (512*242+128)
@@ -1254,6 +1257,7 @@ static struct video_device vicam_template = {
/* table of devices that work with this driver */
static struct usb_device_id vicam_table[] = {
{USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
+ {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
{} /* Terminating entry */
};
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index d7c3fcbc80f7..1d899e2db394 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -349,6 +349,8 @@ v4l_compat_translate_ioctl(struct inode *inode,
{
struct video_buffer *buffer = arg;
+ memset(buffer, 0, sizeof(*buffer));
+
err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
if (err < 0) {
dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n",err);
@@ -361,7 +363,7 @@ v4l_compat_translate_ioctl(struct inode *inode,
switch (fbuf2.fmt.pixelformat) {
case V4L2_PIX_FMT_RGB332:
buffer->depth = 8;
- break;
+ break;
case V4L2_PIX_FMT_RGB555:
buffer->depth = 15;
break;
@@ -377,9 +379,13 @@ v4l_compat_translate_ioctl(struct inode *inode,
default:
buffer->depth = 0;
}
- if (0 != fbuf2.fmt.bytesperline)
+ if (fbuf2.fmt.bytesperline) {
buffer->bytesperline = fbuf2.fmt.bytesperline;
- else {
+ if (!buffer->depth && buffer->width)
+ buffer->depth = ((fbuf2.fmt.bytesperline<<3)
+ + (buffer->width-1) )
+ /buffer->width;
+ } else {
buffer->bytesperline =
(buffer->width * buffer->depth + 7) & 7;
buffer->bytesperline >>= 3;
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 8d972ffdaf98..78d28b03ec93 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -938,6 +938,7 @@ void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg)
case VIDIOC_INT_AUDIO_CLOCK_FREQ:
case VIDIOC_INT_I2S_CLOCK_FREQ:
case VIDIOC_INT_S_STANDBY:
+ case VIDIOC_INT_RESET:
{
u32 *p=arg;
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index 7ee8a53cd336..f53edf1923b7 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -223,6 +223,7 @@ fail_dmxdev:
fail_dmx:
dvb_unregister_frontend(dvb->frontend);
fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
fail_adapter:
return result;
@@ -236,6 +237,7 @@ void videobuf_dvb_unregister(struct videobuf_dvb *dvb)
dvb_dmxdev_release(&dvb->dmxdev);
dvb_dmx_release(&dvb->demux);
dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
dvb_unregister_adapter(&dvb->adapter);
}
diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
index acc5ea936687..f429f49901b9 100644
--- a/drivers/media/video/video-buf.c
+++ b/drivers/media/video/video-buf.c
@@ -365,7 +365,12 @@ videobuf_iolock(struct videobuf_queue* q, struct videobuf_buffer *vb,
if (NULL == fbuf)
return -EINVAL;
/* FIXME: need sanity checks for vb->boff */
- bus = (dma_addr_t)fbuf->base + vb->boff;
+ /*
+ * Using a double cast to avoid compiler warnings when
+ * building for PAE. Compiler doesn't like direct casting
+ * of a 32 bit ptr to 64 bit integer.
+ */
+ bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
err = videobuf_dma_init_overlay(&vb->dma,PCI_DMA_FROMDEVICE,
bus, pages);
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index edd7b83c3464..d424a4129d69 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -17,10 +17,11 @@
*/
#define dbgarg(cmd, fmt, arg...) \
- if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
+ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
printk (KERN_DEBUG "%s: ", vfd->name); \
v4l_printk_ioctl(cmd); \
- printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+ printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \
+ }
#define dbgarg2(fmt, arg...) \
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
@@ -739,13 +740,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_DQBUF:
{
struct v4l2_buffer *p=arg;
- if (!vfd->vidioc_qbuf)
+ if (!vfd->vidioc_dqbuf)
break;
ret = check_fmt (vfd, p->type);
if (ret)
break;
- ret=vfd->vidioc_qbuf(file, fh, p);
+ ret=vfd->vidioc_dqbuf(file, fh, p);
if (!ret)
dbgbuf(cmd,vfd,p);
break;
@@ -836,7 +837,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
break;
}
- if (index < 0 || index >= vfd->tvnormsize) {
+ if (index<0 || index >= vfd->tvnormsize) {
ret=-EINVAL;
break;
}
@@ -1283,9 +1284,36 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_PARM:
{
struct v4l2_streamparm *p=arg;
- if (!vfd->vidioc_g_parm)
- break;
- ret=vfd->vidioc_g_parm(file, fh, p);
+ if (vfd->vidioc_g_parm) {
+ ret=vfd->vidioc_g_parm(file, fh, p);
+ } else {
+ struct v4l2_standard s;
+ int i;
+
+ if (!vfd->tvnormsize) {
+ printk (KERN_WARNING "%s: no TV norms defined!\n",
+ vfd->name);
+ break;
+ }
+
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ for (i = 0; i < vfd->tvnormsize; i++)
+ if (vfd->tvnorms[i].id == vfd->current_norm)
+ break;
+ if (i >= vfd->tvnormsize)
+ return -EINVAL;
+
+ v4l2_video_std_construct(&s, vfd->current_norm,
+ vfd->tvnorms[i].name);
+
+ memset(p,0,sizeof(*p));
+
+ p->parm.capture.timeperframe = s.frameperiod;
+ ret=0;
+ }
+
dbgarg (cmd, "type=%d\n", p->type);
break;
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 268e69fdefc6..6b6dff4d236a 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2325,7 +2325,7 @@ static void vino_capture_tasklet(unsigned long channel) {
}
}
-static irqreturn_t vino_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t vino_interrupt(int irq, void *dev_id)
{
u32 ctrl, intr;
unsigned int fc_a, fc_b;
@@ -4404,7 +4404,6 @@ static struct video_device v4l_device_template = {
.name = "NOT SET",
//.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
// VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
- .hardware = VID_HARDWARE_VINO,
.fops = &vino_fops,
.minor = -1,
};
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 841884af0cc0..3c8dc72dc8e9 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -272,7 +272,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
/* Get first addr pointed to pixel position */
oldpg=get_addr_pos(pos,pages,to_addr);
- pg=pfn_to_page(to_addr[oldpg].sg->dma_address >> PAGE_SHIFT);
+ pg=pfn_to_page(sg_dma_address(to_addr[oldpg].sg) >> PAGE_SHIFT);
basep = kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[oldpg].sg->offset;
/* We will just duplicate the second pixel at the packet */
@@ -287,7 +287,7 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
for (color=0;color<4;color++) {
pgpos=get_addr_pos(pos,pages,to_addr);
if (pgpos!=oldpg) {
- pg=pfn_to_page(to_addr[pgpos].sg->dma_address >> PAGE_SHIFT);
+ pg=pfn_to_page(sg_dma_address(to_addr[pgpos].sg) >> PAGE_SHIFT);
kunmap_atomic(basep, KM_BOUNCE_READ);
basep= kmap_atomic(pg, KM_BOUNCE_READ)+to_addr[pgpos].sg->offset;
oldpg=pgpos;
@@ -339,8 +339,8 @@ static void gen_line(struct sg_to_addr to_addr[],int inipos,int pages,int wmax,
for (color=0;color<4;color++) {
pgpos=get_addr_pos(pos,pages,to_addr);
if (pgpos!=oldpg) {
- pg=pfn_to_page(to_addr[pgpos].
- sg->dma_address
+ pg=pfn_to_page(sg_dma_address(
+ to_addr[pgpos].sg)
>> PAGE_SHIFT);
kunmap_atomic(basep,
KM_BOUNCE_READ);
@@ -386,7 +386,7 @@ static void vivi_fillbuff(struct vivi_dev *dev,struct vivi_buffer *buf)
struct timeval ts;
/* Test if DMA mapping is ready */
- if (!vb->dma.sglist[0].dma_address)
+ if (!sg_dma_address(&vb->dma.sglist[0]))
return;
prep_to_addr(to_addr,vb);
@@ -783,7 +783,7 @@ static int vivi_map_sg(void *dev, struct scatterlist *sg, int nents,
for (i = 0; i < nents; i++ ) {
BUG_ON(!sg[i].page);
- sg[i].dma_address = page_to_phys(sg[i].page) + sg[i].offset;
+ sg_dma_address(&sg[i]) = page_to_phys(sg[i].page) + sg[i].offset;
}
return nents;
@@ -992,7 +992,8 @@ static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
struct vivi_fh *fh=priv;
struct videobuf_queue *q=&fh->vb_vidq;
struct v4l2_requestbuffers req;
- unsigned int i, ret;
+ unsigned int i;
+ int ret;
req.type = q->type;
req.count = 8;
@@ -1359,6 +1360,8 @@ static int __init vivi_init(void)
dev->vidq.timeout.data = (unsigned long)dev;
init_timer(&dev->vidq.timeout);
+ vivi.current_norm = tvnorms[0].id;
+
ret = video_register_device(&vivi, VFL_TYPE_GRABBER, video_nr);
printk(KERN_INFO "Video Technology Magazine Virtual Video Capture Board (Load status: %d)\n", ret);
return ret;
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 1eca7e65d235..8ef31ed7d3f1 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -744,6 +744,6 @@ vpx3220_cleanup (void)
module_init(vpx3220_init);
module_exit(vpx3220_cleanup);
-MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video encoder driver");
+MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
MODULE_AUTHOR("Laurent Pinchart");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 20f211b55ad4..ddce2fb83424 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -417,7 +417,7 @@ static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
static int w9968cf_read_sb(struct w9968cf_device*);
static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs);
+static void w9968cf_urb_complete(struct urb *urb);
/* Low-level I2C (SMBus) I/O */
static int w9968cf_smbus_start(struct w9968cf_device*);
@@ -586,15 +586,14 @@ static struct w9968cf_symbolic_list urb_errlist[] = {
{ -EFBIG, "Too much ISO frames requested" },
{ -ENOSR, "Buffer error (overrun)" },
{ -EPIPE, "Specified endpoint is stalled (device not responding)"},
- { -EOVERFLOW, "Babble (bad cable?)" },
+ { -EOVERFLOW, "Babble (too much data)" },
{ -EPROTO, "Bit-stuff error (bad cable?)" },
{ -EILSEQ, "CRC/Timeout" },
- { -ETIMEDOUT, "NAK (device does not respond)" },
+ { -ETIME, "Device does not respond to token" },
+ { -ETIMEDOUT, "Device does not respond to command" },
{ -1, NULL }
};
-
-
/****************************************************************************
* Memory management functions *
****************************************************************************/
@@ -782,7 +781,7 @@ static int w9968cf_allocate_memory(struct w9968cf_device* cam)
If there are no requested frames in the FIFO list, packets are collected into
a temporary buffer.
--------------------------------------------------------------------------*/
-static void w9968cf_urb_complete(struct urb *urb, struct pt_regs *regs)
+static void w9968cf_urb_complete(struct urb *urb)
{
struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
struct w9968cf_frame_t** f;
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 1b2be2d2a3ec..5b5563424422 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -303,7 +303,7 @@ int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
/*****************************************************************************/
-static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
+static void zc0301_urb_complete(struct urb *urb)
{
struct zc0301_device* cam = urb->context;
struct zc0301_frame_t** f;
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index f2249ed25273..653822ce391c 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -820,7 +820,6 @@ static struct i2c_algo_bit_data zoran_i2c_bit_data_template = {
.getsda = zoran_i2c_getsda,
.getscl = zoran_i2c_getscl,
.udelay = 10,
- .mdelay = 0,
.timeout = 100,
};
@@ -1279,9 +1278,7 @@ find_zr36057 (void)
zoran_num = 0;
while (zoran_num < BUZ_MAX &&
- (dev =
- pci_find_device(PCI_VENDOR_ID_ZORAN,
- PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
+ (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) {
card_num = card[zoran_num];
zr = &zoran[zoran_num];
memset(zr, 0, sizeof(struct zoran)); // Just in case if previous cycle failed
@@ -1542,7 +1539,8 @@ find_zr36057 (void)
goto zr_detach_vfe;
}
}
-
+ /* Success so keep the pci_dev referenced */
+ pci_dev_get(zr->pci_dev);
zoran_num++;
continue;
@@ -1564,6 +1562,9 @@ find_zr36057 (void)
iounmap(zr->zr36057_mem);
continue;
}
+ if (dev) /* Clean up ref count on early exit */
+ pci_dev_put(dev);
+
if (zoran_num == 0) {
dprintk(1, KERN_INFO "No known MJPEG cards found.\n");
}
@@ -1621,10 +1622,10 @@ init_dc10_cards (void)
dprintk(5, KERN_DEBUG "Jotti is een held!\n");
/* some mainboards might not do PCI-PCI data transfer well */
- if (pci_pci_problems & PCIPCI_FAIL) {
+ if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) {
dprintk(1,
KERN_WARNING
- "%s: chipset may not support reliable PCI-PCI DMA\n",
+ "%s: chipset does not support reliable PCI-PCI DMA\n",
ZORAN_NAME);
}
@@ -1632,7 +1633,7 @@ init_dc10_cards (void)
for (i = 0; i < zoran_num; i++) {
struct zoran *zr = &zoran[i];
- if (pci_pci_problems & PCIPCI_NATOMA && zr->revision <= 1) {
+ if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) {
zr->jpg_buffers.need_contiguous = 1;
dprintk(1,
KERN_INFO
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index 3cbac2e8aed3..168e431d7c71 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -1408,15 +1408,14 @@ error_handler (struct zoran *zr,
irqreturn_t
zoran_irq (int irq,
- void *dev_id,
- struct pt_regs *regs)
+ void *dev_id)
{
u32 stat, astat;
int count;
struct zoran *zr;
unsigned long flags;
- zr = (struct zoran *) dev_id;
+ zr = dev_id;
count = 0;
if (zr->testing) {
diff --git a/drivers/media/video/zoran_device.h b/drivers/media/video/zoran_device.h
index f19705cbdb39..37fa86a34083 100644
--- a/drivers/media/video/zoran_device.h
+++ b/drivers/media/video/zoran_device.h
@@ -64,9 +64,7 @@ extern int wait_grab_pending(struct zoran *zr);
/* interrupts */
extern void print_interrupts(struct zoran *zr);
extern void clear_interrupt_counters(struct zoran *zr);
-extern irqreturn_t zoran_irq(int irq,
- void *dev_id,
- struct pt_regs *regs);
+extern irqreturn_t zoran_irq(int irq, void *dev_id);
/* JPEG codec access */
extern void jpeg_start(struct zoran *zr);
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index 5f90db27892b..862a984c2155 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -1512,6 +1512,13 @@ setup_fbuffer (struct file *file,
if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
return -EPERM;
+ /* Don't allow frame buffer overlay if PCI or AGP is buggy, or on
+ ALi Magik (that needs very low latency while the card needs a
+ higher value always) */
+
+ if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK))
+ return -ENXIO;
+
/* we need a bytesperline value, even if not given */
if (!bytesperline)
bytesperline = width * ((fmt->depth + 7) & ~7) / 8;
diff --git a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c
index 50437383ed62..0cbf564388a6 100644
--- a/drivers/media/video/zr36120.c
+++ b/drivers/media/video/zr36120.c
@@ -335,13 +335,13 @@ DEBUG(printk(CARD_DEBUG "turning off\n",CARD));
}
static
-void zoran_irq(int irq, void *dev_id, struct pt_regs * regs)
+void zoran_irq(int irq, void *dev_id)
{
u32 stat,estat;
int count = 0;
struct zoran *ztv = dev_id;
- UNUSED(irq); UNUSED(regs);
+ UNUSED(irq);
for (;;) {
/* get/clear interrupt status bits */
stat=zrread(ZORAN_ISR);
@@ -987,6 +987,8 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
VID_TYPE_SCALES;
if (ztv->have_tuner)
c.type |= VID_TYPE_TUNER;
+ if (pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
+ c.type &= ~VID_TYPE_OVERLAY;
if (ztv->have_decoder) {
c.channels = ztv->card->video_inputs;
c.audios = ztv->card->audio_inputs;
@@ -1284,6 +1286,8 @@ int zoran_ioctl(struct video_device* dev, unsigned int cmd, void *arg)
struct video_buffer v;
if(!capable(CAP_SYS_ADMIN))
return -EPERM;
+ if (pcipci_problems & (PCIPCI_FAIL|PCIAGP_FAIL))
+ return -ENXIO;
if (copy_from_user(&v, arg,sizeof(v)))
return -EFAULT;
DEBUG(printk(CARD_DEBUG "VIDIOCSFBUF(%p,%d,%d,%d,%d)\n",CARD,v.base, v.width,v.height,v.depth,v.bytesperline));
@@ -1836,16 +1840,16 @@ int __init find_zoran(void)
struct zoran *ztv;
struct pci_dev *dev = NULL;
unsigned char revision;
- int zoran_num=0;
+ int zoran_num = 0;
- while ((dev = pci_find_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
+ while ((dev = pci_get_device(PCI_VENDOR_ID_ZORAN,PCI_DEVICE_ID_ZORAN_36120, dev)))
{
/* Ok, a ZR36120/ZR36125 found! */
ztv = &zorans[zoran_num];
ztv->dev = dev;
if (pci_enable_device(dev))
- return -EIO;
+ continue;
pci_read_config_byte(dev, PCI_CLASS_REVISION, &revision);
printk(KERN_INFO "zoran: Zoran %x (rev %d) ",
@@ -1863,17 +1867,18 @@ int __init find_zoran(void)
{
iounmap(ztv->zoran_mem);
printk(KERN_ERR "zoran: Bad irq number or handler\n");
- return -EINVAL;
+ continue;
}
if (result==-EBUSY)
printk(KERN_ERR "zoran: IRQ %d busy, change your PnP config in BIOS\n",dev->irq);
if (result < 0) {
iounmap(ztv->zoran_mem);
- return result;
+ continue;
}
/* Enable bus-mastering */
pci_set_master(dev);
-
+ /* Keep a reference */
+ pci_dev_get(dev);
zoran_num++;
}
if(zoran_num)
@@ -2030,13 +2035,16 @@ void release_zoran(int max)
/* free it */
free_irq(ztv->dev->irq,ztv);
- /* unregister i2c_bus */
+ /* unregister i2c_bus */
i2c_unregister_bus((&ztv->i2c));
/* unmap and free memory */
if (ztv->zoran_mem)
iounmap(ztv->zoran_mem);
+ /* Drop PCI device */
+ pci_dev_put(ztv->dev);
+
video_unregister_device(&ztv->video_dev);
video_unregister_device(&ztv->vbi_dev);
}
@@ -2053,13 +2061,12 @@ int __init zr36120_init(void)
handle_chipset();
zoran_cards = find_zoran();
- if (zoran_cards<0)
- /* no cards found, no need for a driver */
+ if (zoran_cards <= 0)
return -EIO;
/* initialize Zorans */
for (card=0; card<zoran_cards; card++) {
- if (init_zoran(card)<0) {
+ if (init_zoran(card) < 0) {
/* only release the zorans we have registered */
release_zoran(card);
return -EIO;
diff --git a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h
index 048b5b8610e3..bb2bf5aa0b62 100644
--- a/drivers/message/fusion/linux_compat.h
+++ b/drivers/message/fusion/linux_compat.h
@@ -6,13 +6,4 @@
#include <linux/version.h>
#include <scsi/scsi_device.h>
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6))
-static int inline scsi_device_online(struct scsi_device *sdev)
-{
- return sdev->online;
-}
-#endif
-
-
-/*}-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
#endif /* _LINUX_COMPAT_H */
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 29d0635cce1d..e5c72719debc 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -122,7 +122,7 @@ static DECLARE_WAIT_QUEUE_HEAD(mpt_waitq);
/*
* Forward protos...
*/
-static irqreturn_t mpt_interrupt(int irq, void *bus_id, struct pt_regs *r);
+static irqreturn_t mpt_interrupt(int irq, void *bus_id);
static int mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply);
static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes,
u32 *req, int replyBytes, u16 *u16reply, int maxwait,
@@ -351,7 +351,6 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
* mpt_interrupt - MPT adapter (IOC) specific interrupt handler.
* @irq: irq number (not used)
* @bus_id: bus identifier cookie == pointer to MPT_ADAPTER structure
- * @r: pt_regs pointer (not used)
*
* This routine is registered via the request_irq() kernel API call,
* and handles all interrupts generated from a specific MPT adapter
@@ -365,7 +364,7 @@ mpt_reply(MPT_ADAPTER *ioc, u32 pa)
* the protocol-specific details of the MPT request completion.
*/
static irqreturn_t
-mpt_interrupt(int irq, void *bus_id, struct pt_regs *r)
+mpt_interrupt(int irq, void *bus_id)
{
MPT_ADAPTER *ioc = bus_id;
u32 pa = CHIPREG_READ32_dmasync(&ioc->chip->ReplyFifo);
diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig
index fef677103880..6443392bffff 100644
--- a/drivers/message/i2o/Kconfig
+++ b/drivers/message/i2o/Kconfig
@@ -88,7 +88,7 @@ config I2O_BUS
config I2O_BLOCK
tristate "I2O Block OSM"
- depends on I2O
+ depends on I2O && BLOCK
---help---
Include support for the I2O Block OSM. The Block OSM presents disk
and other structured block devices to the operating system. If you
diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c
index ac06f10c54ec..d96c687aee93 100644
--- a/drivers/message/i2o/bus-osm.c
+++ b/drivers/message/i2o/bus-osm.c
@@ -80,18 +80,26 @@ static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan);
* @dev: device to verify if it is a I2O Bus Adapter device
*
* Because we want all Bus Adapters always return 0.
+ * Except when we fail. Then we are sad.
*
- * Returns 0.
+ * Returns 0, except when we fail to excel.
*/
static int i2o_bus_probe(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
+ int rc;
- device_create_file(dev, &dev_attr_scan);
+ rc = device_create_file(dev, &dev_attr_scan);
+ if (rc)
+ goto err_out;
osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
return 0;
+
+err_out:
+ put_device(dev);
+ return rc;
};
/**
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 7bd4d85d0b42..01a5a702b037 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -127,7 +127,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
DECLARE_WAIT_QUEUE_HEAD(wq);
struct i2o_exec_wait *wait;
static u32 tcntxt = 0x80000000;
- long flags;
+ unsigned long flags;
int rc = 0;
wait = i2o_exec_wait_alloc();
@@ -325,13 +325,24 @@ static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
static int i2o_exec_probe(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
+ int rc;
- i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
+ rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
+ if (rc) goto err_out;
- device_create_file(dev, &dev_attr_vendor_id);
- device_create_file(dev, &dev_attr_product_id);
+ rc = device_create_file(dev, &dev_attr_vendor_id);
+ if (rc) goto err_evtreg;
+ rc = device_create_file(dev, &dev_attr_product_id);
+ if (rc) goto err_vid;
return 0;
+
+err_vid:
+ device_remove_file(dev, &dev_attr_vendor_id);
+err_evtreg:
+ i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
+err_out:
+ return rc;
};
/**
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 1ddc2fb429d5..eaba81bf2eca 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -390,9 +390,9 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
}
/* request is already processed by us, so return */
- if (req->flags & REQ_SPECIAL) {
+ if (blk_special_request(req)) {
osm_debug("REQ_SPECIAL already set!\n");
- req->flags |= REQ_DONTPREP;
+ req->cmd_flags |= REQ_DONTPREP;
return BLKPREP_OK;
}
@@ -411,7 +411,8 @@ static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
ireq = req->special;
/* do not come back here */
- req->flags |= REQ_DONTPREP | REQ_SPECIAL;
+ req->cmd_type = REQ_TYPE_SPECIAL;
+ req->cmd_flags |= REQ_DONTPREP;
return BLKPREP_OK;
};
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index 1b58444d5aaf..62f1ac08332c 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -224,12 +224,11 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
* i2o_pci_interrupt - Interrupt handler for I2O controller
* @irq: interrupt line
* @dev_id: pointer to the I2O controller
- * @r: pointer to registers
*
* Handle an interrupt from a PCI based I2O controller. This turns out
* to be rather simple. We keep the controller pointer in the cookie.
*/
-static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id, struct pt_regs *r)
+static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id)
{
struct i2o_controller *c = dev_id;
u32 m;
@@ -372,12 +371,13 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
* Expose the ship behind i960 for initialization, or it will
* failed
*/
- i960 =
- pci_find_slot(c->pdev->bus->number,
+ i960 = pci_get_slot(c->pdev->bus,
PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
- if (i960)
+ if (i960) {
pci_write_config_word(i960, 0x42, 0);
+ pci_dev_put(i960);
+ }
c->promise = 1;
c->limit_sectors = 1;
diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
index 2bf32721eb53..149810a084f5 100644
--- a/drivers/mfd/ucb1x00-core.c
+++ b/drivers/mfd/ucb1x00-core.c
@@ -203,7 +203,7 @@ void ucb1x00_adc_disable(struct ucb1x00 *ucb)
* SIBCLK to talk to the chip. We leave the clock running until
* we have finished processing all interrupts from the chip.
*/
-static irqreturn_t ucb1x00_irq(int irqnr, void *devid, struct pt_regs *regs)
+static irqreturn_t ucb1x00_irq(int irqnr, void *devid)
{
struct ucb1x00 *ucb = devid;
struct ucb1x00_irq *irq;
diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
index 02776814443e..82938ad6ddbd 100644
--- a/drivers/mfd/ucb1x00-ts.c
+++ b/drivers/mfd/ucb1x00-ts.c
@@ -58,6 +58,7 @@ static int adcsync;
static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
{
struct input_dev *idev = ts->idev;
+
input_report_abs(idev, ABS_X, x);
input_report_abs(idev, ABS_Y, y);
input_report_abs(idev, ABS_PRESSURE, pressure);
@@ -67,6 +68,7 @@ static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x
static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
{
struct input_dev *idev = ts->idev;
+
input_report_abs(idev, ABS_PRESSURE, 0);
input_sync(idev);
}
@@ -189,6 +191,7 @@ static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
{
unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
+
if (machine_is_collie())
return (!(val & (UCB_TS_CR_TSPX_LOW)));
else
@@ -291,6 +294,7 @@ static int ucb1x00_thread(void *_ts)
static void ucb1x00_ts_irq(int idx, void *id)
{
struct ucb1x00_ts *ts = id;
+
ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
wake_up(&ts->irq_wait);
}
@@ -372,36 +376,43 @@ static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
{
struct ucb1x00_ts *ts;
+ struct input_dev *idev;
+ int err;
ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- ts->idev = input_allocate_device();
- if (!ts->idev) {
- kfree(ts);
- return -ENOMEM;
+ idev = input_allocate_device();
+ if (!ts || !idev) {
+ err = -ENOMEM;
+ goto fail;
}
ts->ucb = dev->ucb;
+ ts->idev = idev;
ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
- ts->idev->private = ts;
- ts->idev->name = "Touchscreen panel";
- ts->idev->id.product = ts->ucb->id;
- ts->idev->open = ucb1x00_ts_open;
- ts->idev->close = ucb1x00_ts_close;
+ idev->private = ts;
+ idev->name = "Touchscreen panel";
+ idev->id.product = ts->ucb->id;
+ idev->open = ucb1x00_ts_open;
+ idev->close = ucb1x00_ts_close;
- __set_bit(EV_ABS, ts->idev->evbit);
- __set_bit(ABS_X, ts->idev->absbit);
- __set_bit(ABS_Y, ts->idev->absbit);
- __set_bit(ABS_PRESSURE, ts->idev->absbit);
+ __set_bit(EV_ABS, idev->evbit);
+ __set_bit(ABS_X, idev->absbit);
+ __set_bit(ABS_Y, idev->absbit);
+ __set_bit(ABS_PRESSURE, idev->absbit);
- input_register_device(ts->idev);
+ err = input_register_device(idev);
+ if (err)
+ goto fail;
dev->priv = ts;
return 0;
+
+ fail:
+ input_free_device(idev);
+ kfree(ts);
+ return err;
}
static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 7fc692a8f5b0..b6c045dc97b4 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -18,7 +18,7 @@ config IBM_ASM
service processor board as a regular serial port. To make use of
this feature serial driver support (CONFIG_SERIAL_8250) must be
enabled.
-
+
WARNING: This software may not be supported or function
correctly on your IBM server. Please consult the IBM ServerProven
website <http://www.pc.ibm.com/ww/eserver/xseries/serverproven> for
@@ -28,5 +28,63 @@ config IBM_ASM
If unsure, say N.
-endmenu
+config SGI_IOC4
+ tristate "SGI IOC4 Base IO support"
+ ---help---
+ This option enables basic support for the IOC4 chip on certain
+ SGI IO controller cards (IO9, IO10, and PCI-RT). This option
+ does not enable any specific functions on such a card, but provides
+ necessary infrastructure for other drivers to utilize.
+
+ If you have an SGI Altix with an IOC4-based card say Y.
+ Otherwise say N.
+
+config TIFM_CORE
+ tristate "TI Flash Media interface support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ If you want support for Texas Instruments(R) Flash Media adapters
+ you should select this option and then also choose an appropriate
+ host adapter, such as 'TI Flash Media PCI74xx/PCI76xx host adapter
+ support', if you have a TI PCI74xx compatible card reader, for
+ example.
+ You will also have to select some flash card format drivers. MMC/SD
+ cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD
+ Interface support (MMC_TIFM_SD)'.
+
+ To compile this driver as a module, choose M here: the module will
+ be called tifm_core.
+
+config TIFM_7XX1
+ tristate "TI Flash Media PCI74xx/PCI76xx host adapter support (EXPERIMENTAL)"
+ depends on PCI && TIFM_CORE && EXPERIMENTAL
+ default TIFM_CORE
+ help
+ This option enables support for Texas Instruments(R) PCI74xx and
+ PCI76xx families of Flash Media adapters, found in many laptops.
+ To make actual use of the device, you will have to select some
+ flash card format drivers, as outlined in the TIFM_CORE Help.
+ To compile this driver as a module, choose M here: the module will
+ be called tifm_7xx1.
+
+config MSI_LAPTOP
+ tristate "MSI Laptop Extras"
+ depends on X86
+ depends on ACPI_EC
+ depends on BACKLIGHT_CLASS_DEVICE
+ ---help---
+ This is a driver for laptops built by MSI (MICRO-STAR
+ INTERNATIONAL):
+
+ MSI MegaBook S270 (MS-1013)
+ Cytron/TCM/Medion/Tchibo MD96100/SAM2000
+
+ It adds support for Bluetooth, WLAN and LCD brightness control.
+
+ More information about this driver is available at
+ <http://0pointer.de/lennart/tchibo.html>.
+
+ If you have an MSI S270 laptop, say Y or M here.
+
+endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 19c2b85249c3..c9e98ab021c5 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -3,5 +3,10 @@
#
obj- := misc.o # Dummy rule to force built-in.o to be made
-obj-$(CONFIG_IBM_ASM) += ibmasm/
+obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
+obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
+obj-$(CONFIG_LKDTM) += lkdtm.o
+obj-$(CONFIG_TIFM_CORE) += tifm_core.o
+obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
+obj-$(CONFIG_SGI_IOC4) += ioc4.o
diff --git a/drivers/misc/ibmasm/ibmasm.h b/drivers/misc/ibmasm/ibmasm.h
index 634d538ccd14..48d5abebfc30 100644
--- a/drivers/misc/ibmasm/ibmasm.h
+++ b/drivers/misc/ibmasm/ibmasm.h
@@ -196,10 +196,10 @@ extern int ibmasm_send_os_state(struct service_processor *sp, int os_state);
/* low level message processing */
extern int ibmasm_send_i2o_message(struct service_processor *sp);
-extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs);
+extern irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id);
/* remote console */
-extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp, struct pt_regs *regs);
+extern void ibmasm_handle_mouse_interrupt(struct service_processor *sp);
extern int ibmasm_init_remote_input_dev(struct service_processor *sp);
extern void ibmasm_free_remote_input_dev(struct service_processor *sp);
diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c
index 4a35caff5d02..b99dc507de2e 100644
--- a/drivers/misc/ibmasm/ibmasmfs.c
+++ b/drivers/misc/ibmasm/ibmasmfs.c
@@ -147,7 +147,6 @@ static struct inode *ibmasmfs_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_mode = mode;
ret->i_uid = ret->i_gid = 0;
- ret->i_blksize = PAGE_CACHE_SIZE;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
@@ -175,7 +174,7 @@ static struct dentry *ibmasmfs_create_file (struct super_block *sb,
}
inode->i_fop = fops;
- inode->u.generic_ip = data;
+ inode->i_private = data;
d_add(dentry, inode);
return dentry;
@@ -244,7 +243,7 @@ static int command_file_open(struct inode *inode, struct file *file)
{
struct ibmasmfs_command_data *command_data;
- if (!inode->u.generic_ip)
+ if (!inode->i_private)
return -ENODEV;
command_data = kmalloc(sizeof(struct ibmasmfs_command_data), GFP_KERNEL);
@@ -252,7 +251,7 @@ static int command_file_open(struct inode *inode, struct file *file)
return -ENOMEM;
command_data->command = NULL;
- command_data->sp = inode->u.generic_ip;
+ command_data->sp = inode->i_private;
file->private_data = command_data;
return 0;
}
@@ -351,10 +350,10 @@ static int event_file_open(struct inode *inode, struct file *file)
struct ibmasmfs_event_data *event_data;
struct service_processor *sp;
- if (!inode->u.generic_ip)
+ if (!inode->i_private)
return -ENODEV;
- sp = inode->u.generic_ip;
+ sp = inode->i_private;
event_data = kmalloc(sizeof(struct ibmasmfs_event_data), GFP_KERNEL);
if (!event_data)
@@ -439,14 +438,14 @@ static int r_heartbeat_file_open(struct inode *inode, struct file *file)
{
struct ibmasmfs_heartbeat_data *rhbeat;
- if (!inode->u.generic_ip)
+ if (!inode->i_private)
return -ENODEV;
rhbeat = kmalloc(sizeof(struct ibmasmfs_heartbeat_data), GFP_KERNEL);
if (!rhbeat)
return -ENOMEM;
- rhbeat->sp = (struct service_processor *)inode->u.generic_ip;
+ rhbeat->sp = inode->i_private;
rhbeat->active = 0;
ibmasm_init_reverse_heartbeat(rhbeat->sp, &rhbeat->heartbeat);
file->private_data = rhbeat;
@@ -508,7 +507,7 @@ static ssize_t r_heartbeat_file_write(struct file *file, const char __user *buf,
static int remote_settings_file_open(struct inode *inode, struct file *file)
{
- file->private_data = inode->u.generic_ip;
+ file->private_data = inode->i_private;
return 0;
}
diff --git a/drivers/misc/ibmasm/lowlevel.c b/drivers/misc/ibmasm/lowlevel.c
index 47949a2c7e94..a3c589b7cbfa 100644
--- a/drivers/misc/ibmasm/lowlevel.c
+++ b/drivers/misc/ibmasm/lowlevel.c
@@ -54,7 +54,7 @@ int ibmasm_send_i2o_message(struct service_processor *sp)
return 0;
}
-irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *regs)
+irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id)
{
u32 mfa;
struct service_processor *sp = (struct service_processor *)dev_id;
@@ -67,7 +67,7 @@ irqreturn_t ibmasm_interrupt_handler(int irq, void * dev_id, struct pt_regs *reg
dbg("respond to interrupt at %s\n", get_timestamp(tsbuf));
if (mouse_interrupt_pending(sp)) {
- ibmasm_handle_mouse_interrupt(sp, regs);
+ ibmasm_handle_mouse_interrupt(sp);
clear_mouse_interrupt(sp);
}
diff --git a/drivers/misc/ibmasm/remote.c b/drivers/misc/ibmasm/remote.c
index 0f9e3aa34d07..a40fda6c402c 100644
--- a/drivers/misc/ibmasm/remote.c
+++ b/drivers/misc/ibmasm/remote.c
@@ -158,12 +158,10 @@ static void print_input(struct remote_input *input)
}
}
-static void send_mouse_event(struct input_dev *dev, struct pt_regs *regs,
- struct remote_input *input)
+static void send_mouse_event(struct input_dev *dev, struct remote_input *input)
{
unsigned char buttons = input->mouse_buttons;
- input_regs(dev, regs);
input_report_abs(dev, ABS_X, input->data.mouse.x);
input_report_abs(dev, ABS_Y, input->data.mouse.y);
input_report_key(dev, BTN_LEFT, buttons & REMOTE_BUTTON_LEFT);
@@ -172,7 +170,7 @@ static void send_mouse_event(struct input_dev *dev, struct pt_regs *regs,
input_sync(dev);
}
-static void send_keyboard_event(struct input_dev *dev, struct pt_regs *regs,
+static void send_keyboard_event(struct input_dev *dev,
struct remote_input *input)
{
unsigned int key;
@@ -182,13 +180,11 @@ static void send_keyboard_event(struct input_dev *dev, struct pt_regs *regs,
key = xlate_high[code & 0xff];
else
key = xlate[code];
- input_regs(dev, regs);
input_report_key(dev, key, (input->data.keyboard.key_down) ? 1 : 0);
input_sync(dev);
}
-void ibmasm_handle_mouse_interrupt(struct service_processor *sp,
- struct pt_regs *regs)
+void ibmasm_handle_mouse_interrupt(struct service_processor *sp)
{
unsigned long reader;
unsigned long writer;
@@ -203,9 +199,9 @@ void ibmasm_handle_mouse_interrupt(struct service_processor *sp,
print_input(&input);
if (input.type == INPUT_TYPE_MOUSE) {
- send_mouse_event(sp->remote.mouse_dev, regs, &input);
+ send_mouse_event(sp->remote.mouse_dev, &input);
} else if (input.type == INPUT_TYPE_KEYBOARD) {
- send_keyboard_event(sp->remote.keybd_dev, regs, &input);
+ send_keyboard_event(sp->remote.keybd_dev, &input);
} else
break;
diff --git a/drivers/sn/ioc4.c b/drivers/misc/ioc4.c
index 8562821e6498..1c3c14a3839c 100644
--- a/drivers/sn/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (C) 2005-2006 Silicon Graphics, Inc. All Rights Reserved.
*/
/* This file contains the master driver module for use by SGI IOC4 subdrivers.
@@ -29,12 +29,9 @@
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/ioc4.h>
-#include <linux/mmtimer.h>
-#include <linux/rtc.h>
+#include <linux/ktime.h>
#include <linux/mutex.h>
-#include <asm/sn/addrs.h>
-#include <asm/sn/clksupport.h>
-#include <asm/sn/shub_mmr.h>
+#include <linux/time.h>
/***************
* Definitions *
@@ -43,7 +40,7 @@
/* Tweakable values */
/* PCI bus speed detection/calibration */
-#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
+#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
#define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */
#define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */
#define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */
@@ -143,11 +140,11 @@ ioc4_unregister_submodule(struct ioc4_submodule *is)
static void
ioc4_clock_calibrate(struct ioc4_driver_data *idd)
{
- extern unsigned long sn_rtc_cycles_per_second;
union ioc4_int_out int_out;
union ioc4_gpcr gpcr;
unsigned int state, last_state = 1;
- uint64_t start = 0, end, period;
+ struct timespec start_ts, end_ts;
+ uint64_t start, end, period;
unsigned int count = 0;
/* Enable output */
@@ -175,30 +172,28 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
if (!last_state && state) {
count++;
if (count == IOC4_CALIBRATE_END) {
- end = rtc_time();
+ ktime_get_ts(&end_ts);
break;
} else if (count == IOC4_CALIBRATE_DISCARD)
- start = rtc_time();
+ ktime_get_ts(&start_ts);
}
last_state = state;
} while (1);
/* Calculation rearranged to preserve intermediate precision.
* Logically:
- * 1. "end - start" gives us number of RTC cycles over all the
- * square wave cycles measured.
- * 2. Divide by number of square wave cycles to get number of
- * RTC cycles per square wave cycle.
+ * 1. "end - start" gives us the measurement period over all
+ * the square wave cycles.
+ * 2. Divide by number of square wave cycles to get the period
+ * of a square wave cycle.
* 3. Divide by 2*(int_out.fields.count+1), which is the formula
* by which the IOC4 generates the square wave, to get the
- * number of RTC cycles per IOC4 INT_OUT count.
- * 4. Divide by sn_rtc_cycles_per_second to get seconds per
- * count.
- * 5. Multiply by 1E9 to get nanoseconds per count.
+ * period of an IOC4 INT_OUT count.
*/
- period = ((end - start) * 1000000000) /
- (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)
- * sn_rtc_cycles_per_second);
+ end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec;
+ start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec;
+ period = (end - start) /
+ (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1));
/* Bounds check the result. */
if (period > IOC4_CALIBRATE_LOW_LIMIT ||
@@ -210,10 +205,12 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
period = IOC4_CALIBRATE_DEFAULT;
} else {
+ u64 ns = period;
+
+ do_div(ns, IOC4_EXTINT_COUNT_DIVISOR);
printk(KERN_DEBUG
- "IOC4 %s: PCI clock is %ld ns.\n",
- pci_name(idd->idd_pdev),
- period / IOC4_EXTINT_COUNT_DIVISOR);
+ "IOC4 %s: PCI clock is %lld ns.\n",
+ pci_name(idd->idd_pdev), ns);
}
/* Remember results. We store the extint clock period rather
diff --git a/drivers/misc/lkdtm.c b/drivers/misc/lkdtm.c
new file mode 100644
index 000000000000..bbdba7b37e11
--- /dev/null
+++ b/drivers/misc/lkdtm.c
@@ -0,0 +1,341 @@
+/*
+ * Kprobe module for testing crash dumps
+ *
+ * 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) IBM Corporation, 2006
+ *
+ * Author: Ankita Garg <ankita@in.ibm.com>
+ *
+ * This module induces system failures at predefined crashpoints to
+ * evaluate the reliability of crash dumps obtained using different dumping
+ * solutions.
+ *
+ * It is adapted from the Linux Kernel Dump Test Tool by
+ * Fernando Luis Vazquez Cao <http://lkdtt.sourceforge.net>
+ *
+ * Usage : insmod lkdtm.ko [recur_count={>0}] cpoint_name=<> cpoint_type=<>
+ * [cpoint_count={>0}]
+ *
+ * recur_count : Recursion level for the stack overflow test. Default is 10.
+ *
+ * cpoint_name : Crash point where the kernel is to be crashed. It can be
+ * one of INT_HARDWARE_ENTRY, INT_HW_IRQ_EN, INT_TASKLET_ENTRY,
+ * FS_DEVRW, MEM_SWAPOUT, TIMERADD, SCSI_DISPATCH_CMD,
+ * IDE_CORE_CP
+ *
+ * cpoint_type : Indicates the action to be taken on hitting the crash point.
+ * It can be one of PANIC, BUG, EXCEPTION, LOOP, OVERFLOW
+ *
+ * cpoint_count : Indicates the number of times the crash point is to be hit
+ * to trigger an action. The default is 10.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/kprobes.h>
+#include <linux/kallsyms.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <scsi/scsi_cmnd.h>
+
+#ifdef CONFIG_IDE
+#include <linux/ide.h>
+#endif
+
+#define NUM_CPOINTS 8
+#define NUM_CPOINT_TYPES 5
+#define DEFAULT_COUNT 10
+#define REC_NUM_DEFAULT 10
+
+enum cname {
+ INVALID,
+ INT_HARDWARE_ENTRY,
+ INT_HW_IRQ_EN,
+ INT_TASKLET_ENTRY,
+ FS_DEVRW,
+ MEM_SWAPOUT,
+ TIMERADD,
+ SCSI_DISPATCH_CMD,
+ IDE_CORE_CP
+};
+
+enum ctype {
+ NONE,
+ PANIC,
+ BUG,
+ EXCEPTION,
+ LOOP,
+ OVERFLOW
+};
+
+static char* cp_name[] = {
+ "INT_HARDWARE_ENTRY",
+ "INT_HW_IRQ_EN",
+ "INT_TASKLET_ENTRY",
+ "FS_DEVRW",
+ "MEM_SWAPOUT",
+ "TIMERADD",
+ "SCSI_DISPATCH_CMD",
+ "IDE_CORE_CP"
+};
+
+static char* cp_type[] = {
+ "PANIC",
+ "BUG",
+ "EXCEPTION",
+ "LOOP",
+ "OVERFLOW"
+};
+
+static struct jprobe lkdtm;
+
+static int lkdtm_parse_commandline(void);
+static void lkdtm_handler(void);
+
+static char* cpoint_name = INVALID;
+static char* cpoint_type = NONE;
+static int cpoint_count = DEFAULT_COUNT;
+static int recur_count = REC_NUM_DEFAULT;
+
+static enum cname cpoint = INVALID;
+static enum ctype cptype = NONE;
+static int count = DEFAULT_COUNT;
+
+module_param(recur_count, int, 0644);
+MODULE_PARM_DESC(recur_count, "Recurcion level for the stack overflow test,\
+ default is 10");
+module_param(cpoint_name, charp, 0644);
+MODULE_PARM_DESC(cpoint_name, "Crash Point, where kernel is to be crashed");
+module_param(cpoint_type, charp, 06444);
+MODULE_PARM_DESC(cpoint_type, "Crash Point Type, action to be taken on\
+ hitting the crash point");
+module_param(cpoint_count, int, 06444);
+MODULE_PARM_DESC(cpoint_count, "Crash Point Count, number of times the \
+ crash point is to be hit to trigger action");
+
+unsigned int jp_do_irq(unsigned int irq)
+{
+ lkdtm_handler();
+ jprobe_return();
+ return 0;
+}
+
+irqreturn_t jp_handle_irq_event(unsigned int irq, struct irqaction *action)
+{
+ lkdtm_handler();
+ jprobe_return();
+ return 0;
+}
+
+void jp_tasklet_action(struct softirq_action *a)
+{
+ lkdtm_handler();
+ jprobe_return();
+}
+
+void jp_ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
+{
+ lkdtm_handler();
+ jprobe_return();
+}
+
+struct scan_control;
+
+unsigned long jp_shrink_page_list(struct list_head *page_list,
+ struct scan_control *sc)
+{
+ lkdtm_handler();
+ jprobe_return();
+ return 0;
+}
+
+int jp_hrtimer_start(struct hrtimer *timer, ktime_t tim,
+ const enum hrtimer_mode mode)
+{
+ lkdtm_handler();
+ jprobe_return();
+ return 0;
+}
+
+int jp_scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+{
+ lkdtm_handler();
+ jprobe_return();
+ return 0;
+}
+
+#ifdef CONFIG_IDE
+int jp_generic_ide_ioctl(ide_drive_t *drive, struct file *file,
+ struct block_device *bdev, unsigned int cmd,
+ unsigned long arg)
+{
+ lkdtm_handler();
+ jprobe_return();
+ return 0;
+}
+#endif
+
+static int lkdtm_parse_commandline(void)
+{
+ int i;
+
+ if (cpoint_name == INVALID || cpoint_type == NONE ||
+ cpoint_count < 1 || recur_count < 1)
+ return -EINVAL;
+
+ for (i = 0; i < NUM_CPOINTS; ++i) {
+ if (!strcmp(cpoint_name, cp_name[i])) {
+ cpoint = i + 1;
+ break;
+ }
+ }
+
+ for (i = 0; i < NUM_CPOINT_TYPES; ++i) {
+ if (!strcmp(cpoint_type, cp_type[i])) {
+ cptype = i + 1;
+ break;
+ }
+ }
+
+ if (cpoint == INVALID || cptype == NONE)
+ return -EINVAL;
+
+ count = cpoint_count;
+
+ return 0;
+}
+
+static int recursive_loop(int a)
+{
+ char buf[1024];
+
+ memset(buf,0xFF,1024);
+ recur_count--;
+ if (!recur_count)
+ return 0;
+ else
+ return recursive_loop(a);
+}
+
+void lkdtm_handler(void)
+{
+ printk(KERN_INFO "lkdtm : Crash point %s of type %s hit\n",
+ cpoint_name, cpoint_type);
+ --count;
+
+ if (count == 0) {
+ switch (cptype) {
+ case NONE:
+ break;
+ case PANIC:
+ printk(KERN_INFO "lkdtm : PANIC\n");
+ panic("dumptest");
+ break;
+ case BUG:
+ printk(KERN_INFO "lkdtm : BUG\n");
+ BUG();
+ break;
+ case EXCEPTION:
+ printk(KERN_INFO "lkdtm : EXCEPTION\n");
+ *((int *) 0) = 0;
+ break;
+ case LOOP:
+ printk(KERN_INFO "lkdtm : LOOP\n");
+ for (;;);
+ break;
+ case OVERFLOW:
+ printk(KERN_INFO "lkdtm : OVERFLOW\n");
+ (void) recursive_loop(0);
+ break;
+ default:
+ break;
+ }
+ count = cpoint_count;
+ }
+}
+
+int lkdtm_module_init(void)
+{
+ int ret;
+
+ if (lkdtm_parse_commandline() == -EINVAL) {
+ printk(KERN_INFO "lkdtm : Invalid command\n");
+ return -EINVAL;
+ }
+
+ switch (cpoint) {
+ case INT_HARDWARE_ENTRY:
+ lkdtm.kp.symbol_name = "__do_IRQ";
+ lkdtm.entry = (kprobe_opcode_t*) jp_do_irq;
+ break;
+ case INT_HW_IRQ_EN:
+ lkdtm.kp.symbol_name = "handle_IRQ_event";
+ lkdtm.entry = (kprobe_opcode_t*) jp_handle_irq_event;
+ break;
+ case INT_TASKLET_ENTRY:
+ lkdtm.kp.symbol_name = "tasklet_action";
+ lkdtm.entry = (kprobe_opcode_t*) jp_tasklet_action;
+ break;
+ case FS_DEVRW:
+ lkdtm.kp.symbol_name = "ll_rw_block";
+ lkdtm.entry = (kprobe_opcode_t*) jp_ll_rw_block;
+ break;
+ case MEM_SWAPOUT:
+ lkdtm.kp.symbol_name = "shrink_page_list";
+ lkdtm.entry = (kprobe_opcode_t*) jp_shrink_page_list;
+ break;
+ case TIMERADD:
+ lkdtm.kp.symbol_name = "hrtimer_start";
+ lkdtm.entry = (kprobe_opcode_t*) jp_hrtimer_start;
+ break;
+ case SCSI_DISPATCH_CMD:
+ lkdtm.kp.symbol_name = "scsi_dispatch_cmd";
+ lkdtm.entry = (kprobe_opcode_t*) jp_scsi_dispatch_cmd;
+ break;
+ case IDE_CORE_CP:
+#ifdef CONFIG_IDE
+ lkdtm.kp.symbol_name = "generic_ide_ioctl";
+ lkdtm.entry = (kprobe_opcode_t*) jp_generic_ide_ioctl;
+#else
+ printk(KERN_INFO "lkdtm : Crash point not available\n");
+#endif
+ break;
+ default:
+ printk(KERN_INFO "lkdtm : Invalid Crash Point\n");
+ break;
+ }
+
+ if ((ret = register_jprobe(&lkdtm)) < 0) {
+ printk(KERN_INFO "lkdtm : Couldn't register jprobe\n");
+ return ret;
+ }
+
+ printk(KERN_INFO "lkdtm : Crash point %s of type %s registered\n",
+ cpoint_name, cpoint_type);
+ return 0;
+}
+
+void lkdtm_module_exit(void)
+{
+ unregister_jprobe(&lkdtm);
+ printk(KERN_INFO "lkdtm : Crash point unregistered\n");
+}
+
+module_init(lkdtm_module_init);
+module_exit(lkdtm_module_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/msi-laptop.c b/drivers/misc/msi-laptop.c
new file mode 100644
index 000000000000..fdb7153f4426
--- /dev/null
+++ b/drivers/misc/msi-laptop.c
@@ -0,0 +1,395 @@
+/*-*-linux-c-*-*/
+
+/*
+ Copyright (C) 2006 Lennart Poettering <mzxreary (at) 0pointer (dot) 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.
+
+ 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 Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ */
+
+/*
+ * msi-laptop.c - MSI S270 laptop support. This laptop is sold under
+ * various brands, including "Cytron/TCM/Medion/Tchibo MD96100".
+ *
+ * This driver exports a few files in /sys/devices/platform/msi-laptop-pf/:
+ *
+ * lcd_level - Screen brightness: contains a single integer in the
+ * range 0..8. (rw)
+ *
+ * auto_brightness - Enable automatic brightness control: contains
+ * either 0 or 1. If set to 1 the hardware adjusts the screen
+ * brightness automatically when the power cord is
+ * plugged/unplugged. (rw)
+ *
+ * wlan - WLAN subsystem enabled: contains either 0 or 1. (ro)
+ *
+ * bluetooth - Bluetooth subsystem enabled: contains either 0 or 1
+ * Please note that this file is constantly 0 if no Bluetooth
+ * hardware is available. (ro)
+ *
+ * In addition to these platform device attributes the driver
+ * registers itself in the Linux backlight control subsystem and is
+ * available to userspace under /sys/class/backlight/msi-laptop-bl/.
+ *
+ * This driver might work on other laptops produced by MSI. If you
+ * want to try it you can pass force=1 as argument to the module which
+ * will force it to load even when the DMI data doesn't identify the
+ * laptop as MSI S270. YMMV.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/autoconf.h>
+
+#define MSI_DRIVER_VERSION "0.5"
+
+#define MSI_LCD_LEVEL_MAX 9
+
+#define MSI_EC_COMMAND_WIRELESS 0x10
+#define MSI_EC_COMMAND_LCD_LEVEL 0x11
+
+static int force;
+module_param(force, bool, 0);
+MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
+
+static int auto_brightness;
+module_param(auto_brightness, int, 0);
+MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)");
+
+/* Hardware access */
+
+static int set_lcd_level(int level)
+{
+ u8 buf[2];
+
+ if (level < 0 || level >= MSI_LCD_LEVEL_MAX)
+ return -EINVAL;
+
+ buf[0] = 0x80;
+ buf[1] = (u8) (level*31);
+
+ return ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, buf, sizeof(buf), NULL, 0);
+}
+
+static int get_lcd_level(void)
+{
+ u8 wdata = 0, rdata;
+ int result;
+
+ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+ if (result < 0)
+ return result;
+
+ return (int) rdata / 31;
+}
+
+static int get_auto_brightness(void)
+{
+ u8 wdata = 4, rdata;
+ int result;
+
+ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, &wdata, 1, &rdata, 1);
+ if (result < 0)
+ return result;
+
+ return !!(rdata & 8);
+}
+
+static int set_auto_brightness(int enable)
+{
+ u8 wdata[2], rdata;
+ int result;
+
+ wdata[0] = 4;
+
+ result = ec_transaction(MSI_EC_COMMAND_LCD_LEVEL, wdata, 1, &rdata, 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);
+}
+
+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);
+ if (result < 0)
+ return -1;
+
+ if (wlan)
+ *wlan = !!(rdata & 8);
+
+ if (bluetooth)
+ *bluetooth = !!(rdata & 128);
+
+ return 0;
+}
+
+/* Backlight device stuff */
+
+static int bl_get_brightness(struct backlight_device *b)
+{
+ return get_lcd_level();
+}
+
+
+static int bl_update_status(struct backlight_device *b)
+{
+ return set_lcd_level(b->props->brightness);
+}
+
+static struct backlight_properties msibl_props = {
+ .owner = THIS_MODULE,
+ .get_brightness = bl_get_brightness,
+ .update_status = bl_update_status,
+ .max_brightness = MSI_LCD_LEVEL_MAX-1,
+};
+
+static struct backlight_device *msibl_device;
+
+/* Platform device */
+
+static ssize_t show_wlan(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret, enabled;
+
+ ret = get_wireless_state(&enabled, NULL);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t show_bluetooth(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret, enabled;
+
+ ret = get_wireless_state(NULL, &enabled);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", enabled);
+}
+
+static ssize_t show_lcd_level(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret;
+
+ ret = get_lcd_level();
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t store_lcd_level(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+
+ int level, ret;
+
+ if (sscanf(buf, "%i", &level) != 1 || (level < 0 || level >= MSI_LCD_LEVEL_MAX))
+ return -EINVAL;
+
+ ret = set_lcd_level(level);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static ssize_t show_auto_brightness(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+
+ int ret;
+
+ ret = get_auto_brightness();
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%i\n", ret);
+}
+
+static ssize_t store_auto_brightness(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+
+ int enable, ret;
+
+ if (sscanf(buf, "%i", &enable) != 1 || (enable != (enable & 1)))
+ return -EINVAL;
+
+ ret = set_auto_brightness(enable);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
+static DEVICE_ATTR(auto_brightness, 0644, show_auto_brightness, store_auto_brightness);
+static DEVICE_ATTR(bluetooth, 0444, show_bluetooth, NULL);
+static DEVICE_ATTR(wlan, 0444, show_wlan, NULL);
+
+static struct attribute *msipf_attributes[] = {
+ &dev_attr_lcd_level.attr,
+ &dev_attr_auto_brightness.attr,
+ &dev_attr_bluetooth.attr,
+ &dev_attr_wlan.attr,
+ NULL
+};
+
+static struct attribute_group msipf_attribute_group = {
+ .attrs = msipf_attributes
+};
+
+static struct platform_driver msipf_driver = {
+ .driver = {
+ .name = "msi-laptop-pf",
+ .owner = THIS_MODULE,
+ }
+};
+
+static struct platform_device *msipf_device;
+
+/* Initialization */
+
+static struct dmi_system_id __initdata msi_dmi_table[] = {
+ {
+ .ident = "MSI S270",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "MICRO-STAR INT'L CO.,LTD"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-1013"),
+ }
+ },
+ {
+ .ident = "Medion MD96100",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "NOTEBOOK"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "SAM2000"),
+ }
+ },
+ { }
+};
+
+
+static int __init msi_init(void)
+{
+ int ret;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (!force && !dmi_check_system(msi_dmi_table))
+ return -ENODEV;
+
+ if (auto_brightness < 0 || auto_brightness > 2)
+ return -EINVAL;
+
+ /* Register backlight stuff */
+
+ msibl_device = backlight_device_register("msi-laptop-bl", NULL, &msibl_props);
+ if (IS_ERR(msibl_device))
+ return PTR_ERR(msibl_device);
+
+ ret = platform_driver_register(&msipf_driver);
+ if (ret)
+ goto fail_backlight;
+
+ /* Register platform stuff */
+
+ msipf_device = platform_device_alloc("msi-laptop-pf", -1);
+ if (!msipf_device) {
+ ret = -ENOMEM;
+ goto fail_platform_driver;
+ }
+
+ ret = platform_device_add(msipf_device);
+ if (ret)
+ goto fail_platform_device1;
+
+ ret = sysfs_create_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+ if (ret)
+ goto fail_platform_device2;
+
+ /* Disable automatic brightness control by default because
+ * this module was probably loaded to do brightness control in
+ * software. */
+
+ if (auto_brightness != 2)
+ set_auto_brightness(auto_brightness);
+
+ printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n");
+
+ return 0;
+
+fail_platform_device2:
+
+ platform_device_del(msipf_device);
+
+fail_platform_device1:
+
+ platform_device_put(msipf_device);
+
+fail_platform_driver:
+
+ platform_driver_unregister(&msipf_driver);
+
+fail_backlight:
+
+ backlight_device_unregister(msibl_device);
+
+ return ret;
+}
+
+static void __exit msi_cleanup(void)
+{
+
+ sysfs_remove_group(&msipf_device->dev.kobj, &msipf_attribute_group);
+ platform_device_unregister(msipf_device);
+ platform_driver_unregister(&msipf_driver);
+ backlight_device_unregister(msibl_device);
+
+ /* Enable automatic brightness control again */
+ if (auto_brightness != 2)
+ set_auto_brightness(1);
+
+ printk(KERN_INFO "msi-laptop: driver unloaded.\n");
+}
+
+module_init(msi_init);
+module_exit(msi_cleanup);
+
+MODULE_AUTHOR("Lennart Poettering");
+MODULE_DESCRIPTION("MSI Laptop Support");
+MODULE_VERSION(MSI_DRIVER_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/tifm_7xx1.c b/drivers/misc/tifm_7xx1.c
new file mode 100644
index 000000000000..1ba8754e9383
--- /dev/null
+++ b/drivers/misc/tifm_7xx1.c
@@ -0,0 +1,438 @@
+/*
+ * tifm_7xx1.c - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.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/tifm.h>
+#include <linux/dma-mapping.h>
+
+#define DRIVER_NAME "tifm_7xx1"
+#define DRIVER_VERSION "0.6"
+
+static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
+{
+ int cnt;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->inhibit_new_cards) {
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ if (fm->sockets[cnt] == sock) {
+ fm->remove_mask |= (1 << cnt);
+ queue_work(fm->wq, &fm->media_remover);
+ break;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+}
+
+static void tifm_7xx1_remove_media(void *adapter)
+{
+ struct tifm_adapter *fm = adapter;
+ unsigned long flags;
+ int cnt;
+ struct tifm_dev *sock;
+
+ if (!class_device_get(&fm->cdev))
+ return;
+ spin_lock_irqsave(&fm->lock, flags);
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
+ printk(KERN_INFO DRIVER_NAME
+ ": demand removing card from socket %d\n", cnt);
+ sock = fm->sockets[cnt];
+ fm->sockets[cnt] = NULL;
+ fm->remove_mask &= ~(1 << cnt);
+
+ writel(0x0e00, sock->addr + SOCK_CONTROL);
+
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+ spin_unlock_irqrestore(&fm->lock, flags);
+ device_unregister(&sock->dev);
+ spin_lock_irqsave(&fm->lock, flags);
+ }
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ class_device_put(&fm->cdev);
+}
+
+static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
+{
+ struct tifm_adapter *fm = dev_id;
+ unsigned int irq_status;
+ unsigned int sock_irq_status, cnt;
+
+ spin_lock(&fm->lock);
+ irq_status = readl(fm->addr + FM_INTERRUPT_STATUS);
+ if (irq_status == 0 || irq_status == (~0)) {
+ spin_unlock(&fm->lock);
+ return IRQ_NONE;
+ }
+
+ if (irq_status & TIFM_IRQ_ENABLE) {
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ sock_irq_status = (irq_status >> cnt) &
+ (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
+
+ if (fm->sockets[cnt]) {
+ if (sock_irq_status &&
+ fm->sockets[cnt]->signal_irq)
+ sock_irq_status = fm->sockets[cnt]->
+ signal_irq(fm->sockets[cnt],
+ sock_irq_status);
+
+ if (irq_status & (1 << cnt))
+ fm->remove_mask |= 1 << cnt;
+ } else {
+ if (irq_status & (1 << cnt))
+ fm->insert_mask |= 1 << cnt;
+ }
+ }
+ }
+ writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
+
+ if (!fm->inhibit_new_cards) {
+ if (!fm->remove_mask && !fm->insert_mask) {
+ writel(TIFM_IRQ_ENABLE,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ } else {
+ queue_work(fm->wq, &fm->media_remover);
+ queue_work(fm->wq, &fm->media_inserter);
+ }
+ }
+
+ spin_unlock(&fm->lock);
+ return IRQ_HANDLED;
+}
+
+static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
+{
+ unsigned int s_state;
+ int cnt;
+
+ writel(0x0e00, sock_addr + SOCK_CONTROL);
+
+ for (cnt = 0; cnt < 100; cnt++) {
+ if (!(TIFM_SOCK_STATE_POWERED &
+ readl(sock_addr + SOCK_PRESENT_STATE)))
+ break;
+ msleep(10);
+ }
+
+ s_state = readl(sock_addr + SOCK_PRESENT_STATE);
+ if (!(TIFM_SOCK_STATE_OCCUPIED & s_state))
+ return FM_NULL;
+
+ if (is_x2) {
+ writel((s_state & 7) | 0x0c00, sock_addr + SOCK_CONTROL);
+ } else {
+ // SmartMedia cards need extra 40 msec
+ if (((readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7) == 1)
+ msleep(40);
+ writel(readl(sock_addr + SOCK_CONTROL) | TIFM_CTRL_LED,
+ sock_addr + SOCK_CONTROL);
+ msleep(10);
+ writel((s_state & 0x7) | 0x0c00 | TIFM_CTRL_LED,
+ sock_addr + SOCK_CONTROL);
+ }
+
+ for (cnt = 0; cnt < 100; cnt++) {
+ if ((TIFM_SOCK_STATE_POWERED &
+ readl(sock_addr + SOCK_PRESENT_STATE)))
+ break;
+ msleep(10);
+ }
+
+ if (!is_x2)
+ writel(readl(sock_addr + SOCK_CONTROL) & (~TIFM_CTRL_LED),
+ sock_addr + SOCK_CONTROL);
+
+ return (readl(sock_addr + SOCK_PRESENT_STATE) >> 4) & 7;
+}
+
+inline static char __iomem *
+tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
+{
+ return base_addr + ((sock_num + 1) << 10);
+}
+
+static void tifm_7xx1_insert_media(void *adapter)
+{
+ struct tifm_adapter *fm = adapter;
+ unsigned long flags;
+ tifm_media_id media_id;
+ char *card_name = "xx";
+ int cnt, ok_to_register;
+ unsigned int insert_mask;
+ struct tifm_dev *new_sock = NULL;
+
+ if (!class_device_get(&fm->cdev))
+ return;
+ spin_lock_irqsave(&fm->lock, flags);
+ insert_mask = fm->insert_mask;
+ fm->insert_mask = 0;
+ if (fm->inhibit_new_cards) {
+ spin_unlock_irqrestore(&fm->lock, flags);
+ class_device_put(&fm->cdev);
+ return;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+
+ for (cnt = 0; cnt < fm->max_sockets; cnt++) {
+ if (!(insert_mask & (1 << cnt)))
+ continue;
+
+ media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
+ fm->max_sockets == 2);
+ if (media_id) {
+ ok_to_register = 0;
+ new_sock = tifm_alloc_device(fm, cnt);
+ if (new_sock) {
+ new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
+ cnt);
+ new_sock->media_id = media_id;
+ switch (media_id) {
+ case 1:
+ card_name = "xd";
+ break;
+ case 2:
+ card_name = "ms";
+ break;
+ case 3:
+ card_name = "sd";
+ break;
+ default:
+ break;
+ }
+ snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
+ "tifm_%s%u:%u", card_name, fm->id, cnt);
+ printk(KERN_INFO DRIVER_NAME
+ ": %s card detected in socket %d\n",
+ card_name, cnt);
+ spin_lock_irqsave(&fm->lock, flags);
+ if (!fm->sockets[cnt]) {
+ fm->sockets[cnt] = new_sock;
+ ok_to_register = 1;
+ }
+ spin_unlock_irqrestore(&fm->lock, flags);
+ if (!ok_to_register ||
+ device_register(&new_sock->dev)) {
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->sockets[cnt] = NULL;
+ spin_unlock_irqrestore(&fm->lock,
+ flags);
+ tifm_free_device(&new_sock->dev);
+ }
+ }
+ }
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ }
+
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+ class_device_put(&fm->cdev);
+}
+
+static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ struct tifm_adapter *fm = pci_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->inhibit_new_cards = 1;
+ fm->remove_mask = 0xf;
+ fm->insert_mask = 0;
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+ flush_workqueue(fm->wq);
+
+ tifm_7xx1_remove_media(fm);
+
+ pci_set_power_state(dev, PCI_D3hot);
+ pci_disable_device(dev);
+ pci_save_state(dev);
+ return 0;
+}
+
+static int tifm_7xx1_resume(struct pci_dev *dev)
+{
+ struct tifm_adapter *fm = pci_get_drvdata(dev);
+ unsigned long flags;
+
+ pci_restore_state(dev);
+ pci_enable_device(dev);
+ pci_set_power_state(dev, PCI_D0);
+ pci_set_master(dev);
+
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->inhibit_new_cards = 0;
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+ fm->insert_mask = 0xf;
+ spin_unlock_irqrestore(&fm->lock, flags);
+ return 0;
+}
+
+static int tifm_7xx1_probe(struct pci_dev *dev,
+ const struct pci_device_id *dev_id)
+{
+ struct tifm_adapter *fm;
+ int pci_dev_busy = 0;
+ int rc;
+
+ rc = pci_set_dma_mask(dev, DMA_32BIT_MASK);
+ if (rc)
+ return rc;
+
+ rc = pci_enable_device(dev);
+ if (rc)
+ return rc;
+
+ pci_set_master(dev);
+
+ rc = pci_request_regions(dev, DRIVER_NAME);
+ if (rc) {
+ pci_dev_busy = 1;
+ goto err_out;
+ }
+
+ pci_intx(dev, 1);
+
+ fm = tifm_alloc_adapter();
+ if (!fm) {
+ rc = -ENOMEM;
+ goto err_out_int;
+ }
+
+ fm->dev = &dev->dev;
+ fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
+ fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
+ GFP_KERNEL);
+ if (!fm->sockets)
+ goto err_out_free;
+
+ INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media, fm);
+ INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media, fm);
+ fm->eject = tifm_7xx1_eject;
+ pci_set_drvdata(dev, fm);
+
+ fm->addr = ioremap(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+ if (!fm->addr)
+ goto err_out_free;
+
+ rc = request_irq(dev->irq, tifm_7xx1_isr, SA_SHIRQ, DRIVER_NAME, fm);
+ if (rc)
+ goto err_out_unmap;
+
+ rc = tifm_add_adapter(fm);
+ if (rc)
+ goto err_out_irq;
+
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
+ fm->addr + FM_SET_INTERRUPT_ENABLE);
+
+ fm->insert_mask = 0xf;
+
+ return 0;
+
+err_out_irq:
+ free_irq(dev->irq, fm);
+err_out_unmap:
+ iounmap(fm->addr);
+err_out_free:
+ pci_set_drvdata(dev, NULL);
+ tifm_free_adapter(fm);
+err_out_int:
+ pci_intx(dev, 0);
+ pci_release_regions(dev);
+err_out:
+ if (!pci_dev_busy)
+ pci_disable_device(dev);
+ return rc;
+}
+
+static void tifm_7xx1_remove(struct pci_dev *dev)
+{
+ struct tifm_adapter *fm = pci_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fm->lock, flags);
+ fm->inhibit_new_cards = 1;
+ fm->remove_mask = 0xf;
+ fm->insert_mask = 0;
+ writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ spin_unlock_irqrestore(&fm->lock, flags);
+
+ flush_workqueue(fm->wq);
+
+ tifm_7xx1_remove_media(fm);
+
+ writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+ free_irq(dev->irq, fm);
+
+ tifm_remove_adapter(fm);
+
+ pci_set_drvdata(dev, NULL);
+
+ iounmap(fm->addr);
+ pci_intx(dev, 0);
+ pci_release_regions(dev);
+
+ pci_disable_device(dev);
+ tifm_free_adapter(fm);
+}
+
+static struct pci_device_id tifm_7xx1_pci_tbl [] = {
+ { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ 0 }, /* xx21 - the one I have */
+ { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ 0 }, /* xx12 - should be also supported */
+ { }
+};
+
+static struct pci_driver tifm_7xx1_driver = {
+ .name = DRIVER_NAME,
+ .id_table = tifm_7xx1_pci_tbl,
+ .probe = tifm_7xx1_probe,
+ .remove = tifm_7xx1_remove,
+ .suspend = tifm_7xx1_suspend,
+ .resume = tifm_7xx1_resume,
+};
+
+static int __init tifm_7xx1_init(void)
+{
+ return pci_register_driver(&tifm_7xx1_driver);
+}
+
+static void __exit tifm_7xx1_exit(void)
+{
+ pci_unregister_driver(&tifm_7xx1_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia host driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, tifm_7xx1_pci_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_7xx1_init);
+module_exit(tifm_7xx1_exit);
diff --git a/drivers/misc/tifm_core.c b/drivers/misc/tifm_core.c
new file mode 100644
index 000000000000..ee326136d03b
--- /dev/null
+++ b/drivers/misc/tifm_core.c
@@ -0,0 +1,272 @@
+/*
+ * tifm_core.c - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.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/tifm.h>
+#include <linux/init.h>
+#include <linux/idr.h>
+
+#define DRIVER_NAME "tifm_core"
+#define DRIVER_VERSION "0.6"
+
+static DEFINE_IDR(tifm_adapter_idr);
+static DEFINE_SPINLOCK(tifm_adapter_lock);
+
+static tifm_media_id *tifm_device_match(tifm_media_id *ids,
+ struct tifm_dev *dev)
+{
+ while (*ids) {
+ if (dev->media_id == *ids)
+ return ids;
+ ids++;
+ }
+ return NULL;
+}
+
+static int tifm_match(struct device *dev, struct device_driver *drv)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *fm_drv;
+
+ fm_drv = container_of(drv, struct tifm_driver, driver);
+ if (!fm_drv->id_table)
+ return -EINVAL;
+ if (tifm_device_match(fm_drv->id_table, fm_dev))
+ return 1;
+ return -ENODEV;
+}
+
+static int tifm_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct tifm_dev *fm_dev;
+ int i = 0;
+ int length = 0;
+ const char *card_type_name[] = {"INV", "SM", "MS", "SD"};
+
+ if (!dev || !(fm_dev = container_of(dev, struct tifm_dev, dev)))
+ return -ENODEV;
+ if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
+ "TIFM_CARD_TYPE=%s", card_type_name[fm_dev->media_id]))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static struct bus_type tifm_bus_type = {
+ .name = "tifm",
+ .match = tifm_match,
+ .uevent = tifm_uevent,
+};
+
+static void tifm_free(struct class_device *cdev)
+{
+ struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
+
+ kfree(fm->sockets);
+ if (fm->wq)
+ destroy_workqueue(fm->wq);
+ kfree(fm);
+}
+
+static struct class tifm_adapter_class = {
+ .name = "tifm_adapter",
+ .release = tifm_free
+};
+
+struct tifm_adapter *tifm_alloc_adapter(void)
+{
+ struct tifm_adapter *fm;
+
+ fm = kzalloc(sizeof(struct tifm_adapter), GFP_KERNEL);
+ if (fm) {
+ fm->cdev.class = &tifm_adapter_class;
+ spin_lock_init(&fm->lock);
+ class_device_initialize(&fm->cdev);
+ }
+ return fm;
+}
+EXPORT_SYMBOL(tifm_alloc_adapter);
+
+void tifm_free_adapter(struct tifm_adapter *fm)
+{
+ class_device_put(&fm->cdev);
+}
+EXPORT_SYMBOL(tifm_free_adapter);
+
+int tifm_add_adapter(struct tifm_adapter *fm)
+{
+ int rc;
+
+ if (!idr_pre_get(&tifm_adapter_idr, GFP_KERNEL))
+ return -ENOMEM;
+
+ spin_lock(&tifm_adapter_lock);
+ rc = idr_get_new(&tifm_adapter_idr, fm, &fm->id);
+ spin_unlock(&tifm_adapter_lock);
+ if (!rc) {
+ snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
+ strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+
+ fm->wq = create_singlethread_workqueue(fm->wq_name);
+ if (fm->wq)
+ return class_device_add(&fm->cdev);
+
+ spin_lock(&tifm_adapter_lock);
+ idr_remove(&tifm_adapter_idr, fm->id);
+ spin_unlock(&tifm_adapter_lock);
+ rc = -ENOMEM;
+ }
+ return rc;
+}
+EXPORT_SYMBOL(tifm_add_adapter);
+
+void tifm_remove_adapter(struct tifm_adapter *fm)
+{
+ class_device_del(&fm->cdev);
+
+ spin_lock(&tifm_adapter_lock);
+ idr_remove(&tifm_adapter_idr, fm->id);
+ spin_unlock(&tifm_adapter_lock);
+}
+EXPORT_SYMBOL(tifm_remove_adapter);
+
+void tifm_free_device(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ if (fm_dev->wq)
+ destroy_workqueue(fm_dev->wq);
+ kfree(fm_dev);
+}
+EXPORT_SYMBOL(tifm_free_device);
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+{
+ struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
+
+ if (dev) {
+ spin_lock_init(&dev->lock);
+ snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
+ dev->wq = create_singlethread_workqueue(dev->wq_name);
+ if (!dev->wq) {
+ kfree(dev);
+ return NULL;
+ }
+ dev->dev.parent = fm->dev;
+ dev->dev.bus = &tifm_bus_type;
+ dev->dev.release = tifm_free_device;
+ }
+ return dev;
+}
+EXPORT_SYMBOL(tifm_alloc_device);
+
+void tifm_eject(struct tifm_dev *sock)
+{
+ struct tifm_adapter *fm = dev_get_drvdata(sock->dev.parent);
+ fm->eject(fm, sock);
+}
+EXPORT_SYMBOL(tifm_eject);
+
+int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction)
+{
+ return pci_map_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
+}
+EXPORT_SYMBOL(tifm_map_sg);
+
+void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction)
+{
+ pci_unmap_sg(to_pci_dev(sock->dev.parent), sg, nents, direction);
+}
+EXPORT_SYMBOL(tifm_unmap_sg);
+
+static int tifm_device_probe(struct device *dev)
+{
+ struct tifm_driver *drv;
+ struct tifm_dev *fm_dev;
+ int rc = 0;
+ const tifm_media_id *id;
+
+ drv = container_of(dev->driver, struct tifm_driver, driver);
+ fm_dev = container_of(dev, struct tifm_dev, dev);
+ get_device(dev);
+ if (!fm_dev->drv && drv->probe && drv->id_table) {
+ rc = -ENODEV;
+ id = tifm_device_match(drv->id_table, fm_dev);
+ if (id)
+ rc = drv->probe(fm_dev);
+ if (rc >= 0) {
+ rc = 0;
+ fm_dev->drv = drv;
+ }
+ }
+ if (rc)
+ put_device(dev);
+ return rc;
+}
+
+static int tifm_device_remove(struct device *dev)
+{
+ struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+ struct tifm_driver *drv = fm_dev->drv;
+
+ if (drv) {
+ if (drv->remove) drv->remove(fm_dev);
+ fm_dev->drv = 0;
+ }
+
+ put_device(dev);
+ return 0;
+}
+
+int tifm_register_driver(struct tifm_driver *drv)
+{
+ drv->driver.bus = &tifm_bus_type;
+ drv->driver.probe = tifm_device_probe;
+ drv->driver.remove = tifm_device_remove;
+
+ return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(tifm_register_driver);
+
+void tifm_unregister_driver(struct tifm_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(tifm_unregister_driver);
+
+static int __init tifm_init(void)
+{
+ int rc = bus_register(&tifm_bus_type);
+
+ if (!rc) {
+ rc = class_register(&tifm_adapter_class);
+ if (rc)
+ bus_unregister(&tifm_bus_type);
+ }
+
+ return rc;
+}
+
+static void __exit tifm_exit(void)
+{
+ class_unregister(&tifm_adapter_class);
+ bus_unregister(&tifm_bus_type);
+}
+
+subsys_initcall(tifm_init);
+module_exit(tifm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia core driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 45bcf098e762..ea41852ec8cd 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -21,7 +21,7 @@ config MMC_DEBUG
config MMC_BLOCK
tristate "MMC block device driver"
- depends on MMC
+ depends on MMC && BLOCK
default y
help
Say Y here to enable the MMC block device driver support.
@@ -109,4 +109,20 @@ config MMC_IMX
If unsure, say N.
+config MMC_TIFM_SD
+ tristate "TI Flash Media MMC/SD Interface support (EXPERIMENTAL)"
+ depends on MMC && EXPERIMENTAL
+ select TIFM_CORE
+ help
+ Say Y here if you want to be able to access MMC/SD cards with
+ the Texas Instruments(R) Flash Media card reader, found in many
+ laptops.
+ This option 'selects' (turns on, enables) 'TIFM_CORE', but you
+ probably also need appropriate card reader host adapter, such as
+ 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support
+ (TIFM_7XX1)'.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tifm_sd.
+
endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index d2957e35cc6f..acfd4de0aba5 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -23,8 +23,10 @@ obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
obj-$(CONFIG_MMC_OMAP) += omap.o
obj-$(CONFIG_MMC_AT91RM9200) += at91_mci.o
+obj-$(CONFIG_MMC_TIFM_SD) += tifm_sd.o
-mmc_core-y := mmc.o mmc_queue.o mmc_sysfs.o
+mmc_core-y := mmc.o mmc_sysfs.o
+mmc_core-$(CONFIG_BLOCK) += mmc_queue.o
ifeq ($(CONFIG_MMC_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/mmc/at91_mci.c b/drivers/mmc/at91_mci.c
index 6b7638b84290..494b23fb0a01 100644
--- a/drivers/mmc/at91_mci.c
+++ b/drivers/mmc/at91_mci.c
@@ -661,7 +661,7 @@ static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
/*
* Handle an interrupt
*/
-static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t at91_mci_irq(int irq, void *devid)
{
struct at91mci_host *host = devid;
int completed = 0;
@@ -754,7 +754,7 @@ static irqreturn_t at91_mci_irq(int irq, void *devid, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t at91_mmc_det_irq(int irq, void *_host, struct pt_regs *regs)
+static irqreturn_t at91_mmc_det_irq(int irq, void *_host)
{
struct at91mci_host *host = _host;
int present = !at91_get_gpio_value(irq);
@@ -822,6 +822,7 @@ static int at91_mci_probe(struct platform_device *pdev)
mmc->f_min = 375000;
mmc->f_max = 25000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_BYTEBLOCK;
host = mmc_priv(mmc);
host->mmc = mmc;
@@ -850,7 +851,7 @@ static int at91_mci_probe(struct platform_device *pdev)
/*
* Allocate the MCI interrupt
*/
- ret = request_irq(AT91_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
+ ret = request_irq(AT91RM9200_ID_MCI, at91_mci_irq, IRQF_SHARED, DRIVER_NAME, host);
if (ret) {
printk(KERN_ERR "Failed to request MCI interrupt\n");
clk_disable(mci_clk);
@@ -906,7 +907,7 @@ static int at91_mci_remove(struct platform_device *pdev)
mmc_remove_host(mmc);
at91_mci_disable();
- free_irq(AT91_ID_MCI, host);
+ free_irq(AT91RM9200_ID_MCI, host);
mmc_free_host(mmc);
clk_disable(mci_clk); /* Disable the peripheral clock */
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index 61268da13957..53ffcbb14a97 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -750,7 +750,7 @@ static void au1xmmc_dma_callback(int irq, void *dev_id)
#define STATUS_DATA_IN (SD_STATUS_NE)
#define STATUS_DATA_OUT (SD_STATUS_TH)
-static irqreturn_t au1xmmc_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t au1xmmc_irq(int irq, void *dev_id)
{
u32 status;
diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c
index fb6565b98f32..659d4a822cc5 100644
--- a/drivers/mmc/imxmmc.c
+++ b/drivers/mmc/imxmmc.c
@@ -635,7 +635,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat)
return trans_done;
}
-static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs)
+static void imxmci_dma_irq(int dma, void *devid)
{
struct imxmci_host *host = devid;
uint32_t stat = MMC_STATUS;
@@ -646,7 +646,7 @@ static void imxmci_dma_irq(int dma, void *devid, struct pt_regs *regs)
tasklet_schedule(&host->tasklet);
}
-static irqreturn_t imxmci_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t imxmci_irq(int irq, void *devid)
{
struct imxmci_host *host = devid;
uint32_t stat = MMC_STATUS;
@@ -956,7 +956,7 @@ static int imxmci_probe(struct platform_device *pdev)
mmc->f_min = 150000;
mmc->f_max = CLK_RATE/2;
mmc->ocr_avail = MMC_VDD_32_33;
- mmc->caps |= MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_BYTEBLOCK;
/* MMC core transfer sizes tunable parameters */
mmc->max_hw_segs = 64;
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index 74eaaee66de0..ee8863c123e3 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -996,7 +996,6 @@ static void mmc_read_scrs(struct mmc_host *host)
mmc_set_data_timeout(&data, card, 0);
- data.blksz_bits = 3;
data.blksz = 1 << 3;
data.blocks = 1;
data.flags = MMC_DATA_READ;
@@ -1167,9 +1166,9 @@ static void mmc_setup(struct mmc_host *host)
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
if (delay)
- schedule_delayed_work(&host->detect, delay);
+ mmc_schedule_delayed_work(&host->detect, delay);
else
- schedule_work(&host->detect);
+ mmc_schedule_work(&host->detect);
}
EXPORT_SYMBOL(mmc_detect_change);
@@ -1312,7 +1311,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
- flush_scheduled_work();
+ mmc_flush_scheduled_work();
mmc_free_host_sysfs(host);
}
diff --git a/drivers/mmc/mmc.h b/drivers/mmc/mmc.h
index 97bae00292fa..cd5e0ab3d84b 100644
--- a/drivers/mmc/mmc.h
+++ b/drivers/mmc/mmc.h
@@ -18,4 +18,8 @@ struct mmc_host *mmc_alloc_host_sysfs(int extra, struct device *dev);
int mmc_add_host_sysfs(struct mmc_host *host);
void mmc_remove_host_sysfs(struct mmc_host *host);
void mmc_free_host_sysfs(struct mmc_host *host);
+
+int mmc_schedule_work(struct work_struct *work);
+int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay);
+void mmc_flush_scheduled_work(void);
#endif
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index a0e0dad1b419..f9027c8db792 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -28,10 +28,12 @@
#include <linux/kdev_t.h>
#include <linux/blkdev.h>
#include <linux/mutex.h>
+#include <linux/scatterlist.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
#include <asm/system.h>
#include <asm/uaccess.h>
@@ -153,18 +155,84 @@ static int mmc_blk_prep_rq(struct mmc_queue *mq, struct request *req)
return stat;
}
+static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+{
+ int err;
+ u32 blocks;
+
+ struct mmc_request mrq;
+ struct mmc_command cmd;
+ struct mmc_data data;
+ unsigned int timeout_us;
+
+ struct scatterlist sg;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = MMC_APP_CMD;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+ err = mmc_wait_for_cmd(card->host, &cmd, 0);
+ if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD))
+ return (u32)-1;
+
+ memset(&cmd, 0, sizeof(struct mmc_command));
+
+ cmd.opcode = SD_APP_SEND_NUM_WR_BLKS;
+ cmd.arg = 0;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ memset(&data, 0, sizeof(struct mmc_data));
+
+ data.timeout_ns = card->csd.tacc_ns * 100;
+ data.timeout_clks = card->csd.tacc_clks * 100;
+
+ timeout_us = data.timeout_ns / 1000;
+ timeout_us += data.timeout_clks * 1000 /
+ (card->host->ios.clock / 1000);
+
+ if (timeout_us > 100000) {
+ data.timeout_ns = 100000000;
+ data.timeout_clks = 0;
+ }
+
+ data.blksz = 4;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+ data.sg = &sg;
+ data.sg_len = 1;
+
+ memset(&mrq, 0, sizeof(struct mmc_request));
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ sg_init_one(&sg, &blocks, 4);
+
+ mmc_wait_for_req(card->host, &mrq);
+
+ if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE)
+ return (u32)-1;
+
+ blocks = ntohl(blocks);
+
+ return blocks;
+}
+
static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
{
struct mmc_blk_data *md = mq->data;
struct mmc_card *card = md->queue.card;
+ struct mmc_blk_request brq;
int ret;
if (mmc_card_claim_host(card))
goto cmd_err;
do {
- struct mmc_blk_request brq;
struct mmc_command cmd;
+ u32 readcmd, writecmd;
memset(&brq, 0, sizeof(struct mmc_blk_request));
brq.mrq.cmd = &brq.cmd;
@@ -172,7 +240,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.cmd.arg = req->sector << 9;
brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
- brq.data.blksz_bits = md->block_bits;
brq.data.blksz = 1 << md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
@@ -181,20 +248,34 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
- if (rq_data_dir(req) == READ) {
- brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
- brq.data.flags |= MMC_DATA_READ;
- } else {
- brq.cmd.opcode = MMC_WRITE_BLOCK;
- brq.data.flags |= MMC_DATA_WRITE;
+ /*
+ * If the host doesn't support multiple block writes, force
+ * block writes to single block. SD cards are excepted from
+ * this rule as they support querying the number of
+ * successfully written sectors.
+ */
+ if (rq_data_dir(req) != READ &&
+ !(card->host->caps & MMC_CAP_MULTIWRITE) &&
+ !mmc_card_sd(card))
brq.data.blocks = 1;
- }
if (brq.data.blocks > 1) {
brq.data.flags |= MMC_DATA_MULTI;
brq.mrq.stop = &brq.stop;
+ readcmd = MMC_READ_MULTIPLE_BLOCK;
+ writecmd = MMC_WRITE_MULTIPLE_BLOCK;
} else {
brq.mrq.stop = NULL;
+ readcmd = MMC_READ_SINGLE_BLOCK;
+ writecmd = MMC_WRITE_BLOCK;
+ }
+
+ if (rq_data_dir(req) == READ) {
+ brq.cmd.opcode = readcmd;
+ brq.data.flags |= MMC_DATA_READ;
+ } else {
+ brq.cmd.opcode = writecmd;
+ brq.data.flags |= MMC_DATA_WRITE;
}
brq.data.sg = mq->sg;
@@ -219,27 +300,29 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
goto cmd_err;
}
- do {
- int err;
-
- cmd.opcode = MMC_SEND_STATUS;
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 5);
- if (err) {
- printk(KERN_ERR "%s: error %d requesting status\n",
- req->rq_disk->disk_name, err);
- goto cmd_err;
- }
- } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
+ if (rq_data_dir(req) != READ) {
+ do {
+ int err;
+
+ cmd.opcode = MMC_SEND_STATUS;
+ cmd.arg = card->rca << 16;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+ err = mmc_wait_for_cmd(card->host, &cmd, 5);
+ if (err) {
+ printk(KERN_ERR "%s: error %d requesting status\n",
+ req->rq_disk->disk_name, err);
+ goto cmd_err;
+ }
+ } while (!(cmd.resp[0] & R1_READY_FOR_DATA));
#if 0
- if (cmd.resp[0] & ~0x00000900)
- printk(KERN_ERR "%s: status = %08x\n",
- req->rq_disk->disk_name, cmd.resp[0]);
- if (mmc_decode_status(cmd.resp))
- goto cmd_err;
+ if (cmd.resp[0] & ~0x00000900)
+ printk(KERN_ERR "%s: status = %08x\n",
+ req->rq_disk->disk_name, cmd.resp[0]);
+ if (mmc_decode_status(cmd.resp))
+ goto cmd_err;
#endif
+ }
/*
* A block was successfully transferred.
@@ -262,19 +345,46 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
return 1;
cmd_err:
+ ret = 1;
+
+ /*
+ * If this is an SD card and we're writing, we can first
+ * mark the known good sectors as ok.
+ *
+ * If the card is not SD, we can still ok written sectors
+ * if the controller can do proper error reporting.
+ *
+ * For reads we just fail the entire chunk as that should
+ * be safe in all cases.
+ */
+ if (rq_data_dir(req) != READ && mmc_card_sd(card)) {
+ u32 blocks;
+ unsigned int bytes;
+
+ blocks = mmc_sd_num_wr_blocks(card);
+ if (blocks != (u32)-1) {
+ if (card->csd.write_partial)
+ bytes = blocks << md->block_bits;
+ else
+ bytes = blocks << 9;
+ spin_lock_irq(&md->lock);
+ ret = end_that_request_chunk(req, 1, bytes);
+ spin_unlock_irq(&md->lock);
+ }
+ } else if (rq_data_dir(req) != READ &&
+ (card->host->caps & MMC_CAP_MULTIWRITE)) {
+ spin_lock_irq(&md->lock);
+ ret = end_that_request_chunk(req, 1, brq.data.bytes_xfered);
+ spin_unlock_irq(&md->lock);
+ }
+
mmc_card_release_host(card);
- /*
- * This is a little draconian, but until we get proper
- * error handling sorted out here, its the best we can
- * do - especially as some hosts have no idea how much
- * data was transferred before the error occurred.
- */
spin_lock_irq(&md->lock);
- do {
+ while (ret) {
ret = end_that_request_chunk(req, 0,
req->current_nr_sectors << 9);
- } while (ret);
+ }
add_disk_randomness(req->rq_disk);
blkdev_dequeue_request(req);
diff --git a/drivers/mmc/mmc_queue.c b/drivers/mmc/mmc_queue.c
index 74f8cdeeff0f..4ccdd82b680f 100644
--- a/drivers/mmc/mmc_queue.c
+++ b/drivers/mmc/mmc_queue.c
@@ -28,7 +28,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
struct mmc_queue *mq = q->queuedata;
int ret = BLKPREP_KILL;
- if (req->flags & REQ_SPECIAL) {
+ if (blk_special_request(req)) {
/*
* Special commands already have the command
* blocks already setup in req->special.
@@ -36,7 +36,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
BUG_ON(!req->special);
ret = BLKPREP_OK;
- } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+ } else if (blk_fs_request(req) || blk_pc_request(req)) {
/*
* Block I/O requests need translating according
* to the protocol.
@@ -50,7 +50,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
}
if (ret == BLKPREP_OK)
- req->flags |= REQ_DONTPREP;
+ req->cmd_flags |= REQ_DONTPREP;
return ret;
}
diff --git a/drivers/mmc/mmc_sysfs.c b/drivers/mmc/mmc_sysfs.c
index a2a35fd946ee..10cc9734eaa0 100644
--- a/drivers/mmc/mmc_sysfs.c
+++ b/drivers/mmc/mmc_sysfs.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/idr.h>
+#include <linux/workqueue.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
@@ -317,10 +318,41 @@ void mmc_free_host_sysfs(struct mmc_host *host)
class_device_put(&host->class_dev);
}
+static struct workqueue_struct *workqueue;
+
+/*
+ * Internal function. Schedule work in the MMC work queue.
+ */
+int mmc_schedule_work(struct work_struct *work)
+{
+ return queue_work(workqueue, work);
+}
+
+/*
+ * Internal function. Schedule delayed work in the MMC work queue.
+ */
+int mmc_schedule_delayed_work(struct work_struct *work, unsigned long delay)
+{
+ return queue_delayed_work(workqueue, work, delay);
+}
+
+/*
+ * Internal function. Flush all scheduled work from the MMC work queue.
+ */
+void mmc_flush_scheduled_work(void)
+{
+ flush_workqueue(workqueue);
+}
static int __init mmc_init(void)
{
- int ret = bus_register(&mmc_bus_type);
+ int ret;
+
+ workqueue = create_singlethread_workqueue("kmmcd");
+ if (!workqueue)
+ return -ENOMEM;
+
+ ret = bus_register(&mmc_bus_type);
if (ret == 0) {
ret = class_register(&mmc_host_class);
if (ret)
@@ -333,6 +365,7 @@ static void __exit mmc_exit(void)
{
class_unregister(&mmc_host_class);
bus_unregister(&mmc_bus_type);
+ destroy_workqueue(workqueue);
}
module_init(mmc_init);
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 1886562abdd4..828503c4ee62 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -69,12 +69,13 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
unsigned int datactrl, timeout, irqmask;
unsigned long long clks;
void __iomem *base;
+ int blksz_bits;
DBG(host, "blksz %04x blks %04x flags %08x\n",
- 1 << data->blksz_bits, data->blocks, data->flags);
+ data->blksz, data->blocks, data->flags);
host->data = data;
- host->size = data->blocks << data->blksz_bits;
+ host->size = data->blksz;
host->data_xfered = 0;
mmci_init_sg(host, data);
@@ -88,7 +89,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
writel(timeout, base + MMCIDATATIMER);
writel(host->size, base + MMCIDATALENGTH);
- datactrl = MCI_DPSM_ENABLE | data->blksz_bits << 4;
+ blksz_bits = ffs(data->blksz) - 1;
+ BUG_ON(1 << blksz_bits != data->blksz);
+
+ datactrl = MCI_DPSM_ENABLE | blksz_bits << 4;
if (data->flags & MMC_DATA_READ) {
datactrl |= MCI_DPSM_DIRECTION;
irqmask = MCI_RXFIFOHALFFULLMASK;
@@ -145,7 +149,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
unsigned int status)
{
if (status & MCI_DATABLOCKEND) {
- host->data_xfered += 1 << data->blksz_bits;
+ host->data_xfered += data->blksz;
}
if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_TXUNDERRUN|MCI_RXOVERRUN)) {
if (status & MCI_DATACRCFAIL)
@@ -257,7 +261,7 @@ static int mmci_pio_write(struct mmci_host *host, char *buffer, unsigned int rem
/*
* PIO data transfer IRQ handler.
*/
-static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmci_pio_irq(int irq, void *dev_id)
{
struct mmci_host *host = dev_id;
void __iomem *base = host->base;
@@ -343,7 +347,7 @@ static irqreturn_t mmci_pio_irq(int irq, void *dev_id, struct pt_regs *regs)
/*
* Handle completion of command and data transfers.
*/
-static irqreturn_t mmci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmci_irq(int irq, void *dev_id)
{
struct mmci_host *host = dev_id;
u32 status;
@@ -505,6 +509,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
mmc->f_min = (host->mclk + 511) / 512;
mmc->f_max = min(host->mclk, fmax);
mmc->ocr_avail = plat->ocr_mask;
+ mmc->caps = MMC_CAP_MULTIWRITE;
/*
* We can do SGIO
diff --git a/drivers/mmc/omap.c b/drivers/mmc/omap.c
index ddf06b32c159..762fa2895891 100644
--- a/drivers/mmc/omap.c
+++ b/drivers/mmc/omap.c
@@ -377,7 +377,7 @@ static inline void mmc_omap_report_irq(u16 status)
}
}
-static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
{
struct mmc_omap_host * host = (struct mmc_omap_host *)dev_id;
u16 status;
@@ -514,7 +514,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mmc_omap_switch_irq(int irq, void *dev_id)
{
struct mmc_omap_host *host = (struct mmc_omap_host *) dev_id;
@@ -1034,13 +1034,14 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
host->irq = pdev->resource[1].start;
host->base = (void __iomem*)IO_ADDRESS(r->start);
- if (minfo->wire4)
- mmc->caps |= MMC_CAP_4_BIT_DATA;
-
mmc->ops = &mmc_omap_ops;
mmc->f_min = 400000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_BYTEBLOCK;
+
+ if (minfo->wire4)
+ mmc->caps |= MMC_CAP_4_BIT_DATA;
/* Use scatterlist DMA to reduce per-transfer costs.
* NOTE max_seg_size assumption that small blocks aren't
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index ef350908478c..a526698b8c91 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -299,7 +299,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
return 1;
}
-static irqreturn_t pxamci_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t pxamci_irq(int irq, void *devid)
{
struct pxamci_host *host = devid;
unsigned int ireg;
@@ -399,13 +399,13 @@ static struct mmc_host_ops pxamci_ops = {
.set_ios = pxamci_set_ios,
};
-static void pxamci_dma_irq(int dma, void *devid, struct pt_regs *regs)
+static void pxamci_dma_irq(int dma, void *devid)
{
printk(KERN_ERR "DMA%d: IRQ???\n", dma);
DCSR(dma) = DCSR_STARTINTR|DCSR_ENDINTR|DCSR_BUSERR;
}
-static irqreturn_t pxamci_detect_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t pxamci_detect_irq(int irq, void *devid)
{
struct pxamci_host *host = mmc_priv(devid);
diff --git a/drivers/mmc/sdhci.c b/drivers/mmc/sdhci.c
index 4e21b3b9d330..9a7d39b7cdbf 100644
--- a/drivers/mmc/sdhci.c
+++ b/drivers/mmc/sdhci.c
@@ -4,8 +4,9 @@
* Copyright (C) 2005-2006 Pierre Ossman, All Rights Reserved.
*
* 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.
+ * 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/delay.h>
@@ -34,6 +35,8 @@ static unsigned int debug_quirks = 0;
#define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0)
#define SDHCI_QUIRK_FORCE_DMA (1<<1)
+/* Controller doesn't like some resets when there is no card inserted. */
+#define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2)
static const struct pci_device_id pci_ids[] __devinitdata = {
{
@@ -50,7 +53,8 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
.device = PCI_DEVICE_ID_RICOH_R5C822,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
- .driver_data = SDHCI_QUIRK_FORCE_DMA,
+ .driver_data = SDHCI_QUIRK_FORCE_DMA |
+ SDHCI_QUIRK_NO_CARD_NO_RESET,
},
{
@@ -124,6 +128,12 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
{
unsigned long timeout;
+ if (host->chip->quirks & SDHCI_QUIRK_NO_CARD_NO_RESET) {
+ if (!(readl(host->ioaddr + SDHCI_PRESENT_STATE) &
+ SDHCI_CARD_PRESENT))
+ return;
+ }
+
writeb(mask, host->ioaddr + SDHCI_SOFTWARE_RESET);
if (mask & SDHCI_RESET_ALL)
@@ -716,6 +726,7 @@ static void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq)
} else
sdhci_send_command(host, mrq->cmd);
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -752,6 +763,7 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
ctrl &= ~SDHCI_CTRL_4BITBUS;
writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -859,6 +871,7 @@ static void sdhci_tasklet_finish(unsigned long param)
sdhci_deactivate_led(host);
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
mmc_request_done(host->mmc, mrq);
@@ -892,6 +905,7 @@ static void sdhci_timeout_timer(unsigned long data)
}
}
+ mmiowb();
spin_unlock_irqrestore(&host->lock, flags);
}
@@ -971,7 +985,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
}
}
-static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sdhci_irq(int irq, void *dev_id)
{
irqreturn_t result;
struct sdhci_host* host = dev_id;
@@ -1029,6 +1043,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id, struct pt_regs *regs)
result = IRQ_HANDLED;
+ mmiowb();
out:
spin_unlock(&host->lock);
@@ -1094,6 +1109,7 @@ static int sdhci_resume (struct pci_dev *pdev)
if (chip->hosts[i]->flags & SDHCI_USE_DMA)
pci_set_master(pdev);
sdhci_init(chip->hosts[i]);
+ mmiowb();
ret = mmc_resume_host(chip->hosts[i]->mmc);
if (ret)
return ret;
@@ -1167,6 +1183,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
host = mmc_priv(mmc);
host->mmc = mmc;
+ host->chip = chip;
+ chip->hosts[slot] = host;
+
host->bar = first_bar + slot;
host->addr = pci_resource_start(pdev, host->bar);
@@ -1262,7 +1281,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
mmc->ops = &sdhci_ops;
mmc->f_min = host->max_clk / 256;
mmc->f_max = host->max_clk;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
mmc->ocr_avail = 0;
if (caps & SDHCI_CAN_VDD_330)
@@ -1310,7 +1329,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
tasklet_init(&host->finish_tasklet,
sdhci_tasklet_finish, (unsigned long)host);
- setup_timer(&host->timer, sdhci_timeout_timer, (long)host);
+ setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
ret = request_irq(host->irq, sdhci_irq, IRQF_SHARED,
host->slot_descr, host);
@@ -1323,8 +1342,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
sdhci_dumpregs(host);
#endif
- host->chip = chip;
- chip->hosts[slot] = host;
+ mmiowb();
mmc_add_host(mmc);
diff --git a/drivers/mmc/sdhci.h b/drivers/mmc/sdhci.h
index f2453343f783..72a67937afe0 100644
--- a/drivers/mmc/sdhci.h
+++ b/drivers/mmc/sdhci.h
@@ -4,8 +4,9 @@
* Copyright (C) 2005 Pierre Ossman, All Rights Reserved.
*
* 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.
+ * 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.
*/
/*
diff --git a/drivers/mmc/tifm_sd.c b/drivers/mmc/tifm_sd.c
new file mode 100644
index 000000000000..2bacff60913d
--- /dev/null
+++ b/drivers/mmc/tifm_sd.c
@@ -0,0 +1,933 @@
+/*
+ * tifm_sd.c - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.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/tifm.h>
+#include <linux/mmc/protocol.h>
+#include <linux/mmc/host.h>
+#include <linux/highmem.h>
+
+#define DRIVER_NAME "tifm_sd"
+#define DRIVER_VERSION "0.6"
+
+static int no_dma = 0;
+static int fixed_timeout = 0;
+module_param(no_dma, bool, 0644);
+module_param(fixed_timeout, bool, 0644);
+
+/* Constants here are mostly from OMAP5912 datasheet */
+#define TIFM_MMCSD_RESET 0x0002
+#define TIFM_MMCSD_CLKMASK 0x03ff
+#define TIFM_MMCSD_POWER 0x0800
+#define TIFM_MMCSD_4BBUS 0x8000
+#define TIFM_MMCSD_RXDE 0x8000 /* rx dma enable */
+#define TIFM_MMCSD_TXDE 0x0080 /* tx dma enable */
+#define TIFM_MMCSD_BUFINT 0x0c00 /* set bits: AE, AF */
+#define TIFM_MMCSD_DPE 0x0020 /* data timeout counted in kilocycles */
+#define TIFM_MMCSD_INAB 0x0080 /* abort / initialize command */
+#define TIFM_MMCSD_READ 0x8000
+
+#define TIFM_MMCSD_DATAMASK 0x001d /* set bits: EOFB, BRS, CB, EOC */
+#define TIFM_MMCSD_ERRMASK 0x41e0 /* set bits: CERR, CCRC, CTO, DCRC, DTO */
+#define TIFM_MMCSD_EOC 0x0001 /* end of command phase */
+#define TIFM_MMCSD_CB 0x0004 /* card enter busy state */
+#define TIFM_MMCSD_BRS 0x0008 /* block received/sent */
+#define TIFM_MMCSD_EOFB 0x0010 /* card exit busy state */
+#define TIFM_MMCSD_DTO 0x0020 /* data time-out */
+#define TIFM_MMCSD_DCRC 0x0040 /* data crc error */
+#define TIFM_MMCSD_CTO 0x0080 /* command time-out */
+#define TIFM_MMCSD_CCRC 0x0100 /* command crc error */
+#define TIFM_MMCSD_AF 0x0400 /* fifo almost full */
+#define TIFM_MMCSD_AE 0x0800 /* fifo almost empty */
+#define TIFM_MMCSD_CERR 0x4000 /* card status error */
+
+#define TIFM_MMCSD_FIFO_SIZE 0x0020
+
+#define TIFM_MMCSD_RSP_R0 0x0000
+#define TIFM_MMCSD_RSP_R1 0x0100
+#define TIFM_MMCSD_RSP_R2 0x0200
+#define TIFM_MMCSD_RSP_R3 0x0300
+#define TIFM_MMCSD_RSP_R4 0x0400
+#define TIFM_MMCSD_RSP_R5 0x0500
+#define TIFM_MMCSD_RSP_R6 0x0600
+
+#define TIFM_MMCSD_RSP_BUSY 0x0800
+
+#define TIFM_MMCSD_CMD_BC 0x0000
+#define TIFM_MMCSD_CMD_BCR 0x1000
+#define TIFM_MMCSD_CMD_AC 0x2000
+#define TIFM_MMCSD_CMD_ADTC 0x3000
+
+typedef enum {
+ IDLE = 0,
+ CMD, /* main command ended */
+ BRS, /* block transfer finished */
+ SCMD, /* stop command ended */
+ CARD, /* card left busy state */
+ FIFO, /* FIFO operation completed (uncertain) */
+ READY
+} card_state_t;
+
+enum {
+ FIFO_RDY = 0x0001, /* hardware dependent value */
+ HOST_REG = 0x0002,
+ EJECT = 0x0004,
+ EJECT_DONE = 0x0008,
+ CARD_BUSY = 0x0010,
+ OPENDRAIN = 0x0040, /* hardware dependent value */
+ CARD_EVENT = 0x0100, /* hardware dependent value */
+ CARD_RO = 0x0200, /* hardware dependent value */
+ FIFO_EVENT = 0x10000 }; /* hardware dependent value */
+
+struct tifm_sd {
+ struct tifm_dev *dev;
+
+ unsigned int flags;
+ card_state_t state;
+ unsigned int clk_freq;
+ unsigned int clk_div;
+ unsigned long timeout_jiffies; // software timeout - 2 sec
+
+ struct mmc_request *req;
+ struct work_struct cmd_handler;
+ struct work_struct abort_handler;
+ wait_queue_head_t can_eject;
+
+ size_t written_blocks;
+ char *buffer;
+ size_t buffer_size;
+ size_t buffer_pos;
+
+};
+
+static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
+ unsigned int host_status)
+{
+ struct mmc_command *cmd = host->req->cmd;
+ unsigned int t_val = 0, cnt = 0;
+
+ if (host_status & TIFM_MMCSD_BRS) {
+ /* in non-dma rx mode BRS fires when fifo is still not empty */
+ if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
+ while (host->buffer_size > host->buffer_pos) {
+ t_val = readl(sock->addr + SOCK_MMCSD_DATA);
+ host->buffer[host->buffer_pos++] = t_val & 0xff;
+ host->buffer[host->buffer_pos++] =
+ (t_val >> 8) & 0xff;
+ }
+ }
+ return 1;
+ } else if (host->buffer) {
+ if ((cmd->data->flags & MMC_DATA_READ) &&
+ (host_status & TIFM_MMCSD_AF)) {
+ for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
+ t_val = readl(sock->addr + SOCK_MMCSD_DATA);
+ if (host->buffer_size > host->buffer_pos) {
+ host->buffer[host->buffer_pos++] =
+ t_val & 0xff;
+ host->buffer[host->buffer_pos++] =
+ (t_val >> 8) & 0xff;
+ }
+ }
+ } else if ((cmd->data->flags & MMC_DATA_WRITE)
+ && (host_status & TIFM_MMCSD_AE)) {
+ for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
+ if (host->buffer_size > host->buffer_pos) {
+ t_val = host->buffer[host->buffer_pos++] & 0x00ff;
+ t_val |= ((host->buffer[host->buffer_pos++]) << 8)
+ & 0xff00;
+ writel(t_val,
+ sock->addr + SOCK_MMCSD_DATA);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static unsigned int tifm_sd_op_flags(struct mmc_command *cmd)
+{
+ unsigned int rc = 0;
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ rc |= TIFM_MMCSD_RSP_R0;
+ break;
+ case MMC_RSP_R1B:
+ rc |= TIFM_MMCSD_RSP_BUSY; // deliberate fall-through
+ case MMC_RSP_R1:
+ rc |= TIFM_MMCSD_RSP_R1;
+ break;
+ case MMC_RSP_R2:
+ rc |= TIFM_MMCSD_RSP_R2;
+ break;
+ case MMC_RSP_R3:
+ rc |= TIFM_MMCSD_RSP_R3;
+ break;
+ case MMC_RSP_R6:
+ rc |= TIFM_MMCSD_RSP_R6;
+ break;
+ default:
+ BUG();
+ }
+
+ switch (mmc_cmd_type(cmd)) {
+ case MMC_CMD_BC:
+ rc |= TIFM_MMCSD_CMD_BC;
+ break;
+ case MMC_CMD_BCR:
+ rc |= TIFM_MMCSD_CMD_BCR;
+ break;
+ case MMC_CMD_AC:
+ rc |= TIFM_MMCSD_CMD_AC;
+ break;
+ case MMC_CMD_ADTC:
+ rc |= TIFM_MMCSD_CMD_ADTC;
+ break;
+ default:
+ BUG();
+ }
+ return rc;
+}
+
+static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned int cmd_mask = tifm_sd_op_flags(cmd) |
+ (host->flags & OPENDRAIN);
+
+ if (cmd->data && (cmd->data->flags & MMC_DATA_READ))
+ cmd_mask |= TIFM_MMCSD_READ;
+
+ dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
+ cmd->opcode, cmd->arg, cmd_mask);
+
+ writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
+ writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
+ writel(cmd->opcode | cmd_mask, sock->addr + SOCK_MMCSD_COMMAND);
+}
+
+static void tifm_sd_fetch_resp(struct mmc_command *cmd, struct tifm_dev *sock)
+{
+ cmd->resp[0] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x1c) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x18);
+ cmd->resp[1] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x14) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x10);
+ cmd->resp[2] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x0c) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x08);
+ cmd->resp[3] = (readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x04) << 16)
+ | readl(sock->addr + SOCK_MMCSD_RESPONSE + 0x00);
+}
+
+static void tifm_sd_process_cmd(struct tifm_dev *sock, struct tifm_sd *host,
+ unsigned int host_status)
+{
+ struct mmc_command *cmd = host->req->cmd;
+
+change_state:
+ switch (host->state) {
+ case IDLE:
+ return;
+ case CMD:
+ if (host_status & TIFM_MMCSD_EOC) {
+ tifm_sd_fetch_resp(cmd, sock);
+ if (cmd->data) {
+ host->state = BRS;
+ } else
+ host->state = READY;
+ goto change_state;
+ }
+ break;
+ case BRS:
+ if (tifm_sd_transfer_data(sock, host, host_status)) {
+ if (!host->req->stop) {
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ host->state = CARD;
+ } else {
+ host->state =
+ host->buffer ? READY : FIFO;
+ }
+ goto change_state;
+ }
+ tifm_sd_exec(host, host->req->stop);
+ host->state = SCMD;
+ }
+ break;
+ case SCMD:
+ if (host_status & TIFM_MMCSD_EOC) {
+ tifm_sd_fetch_resp(host->req->stop, sock);
+ if (cmd->error) {
+ host->state = READY;
+ } else if (cmd->data->flags & MMC_DATA_WRITE) {
+ host->state = CARD;
+ } else {
+ host->state = host->buffer ? READY : FIFO;
+ }
+ goto change_state;
+ }
+ break;
+ case CARD:
+ if (!(host->flags & CARD_BUSY)
+ && (host->written_blocks == cmd->data->blocks)) {
+ host->state = host->buffer ? READY : FIFO;
+ goto change_state;
+ }
+ break;
+ case FIFO:
+ if (host->flags & FIFO_RDY) {
+ host->state = READY;
+ host->flags &= ~FIFO_RDY;
+ goto change_state;
+ }
+ break;
+ case READY:
+ queue_work(sock->wq, &host->cmd_handler);
+ return;
+ }
+
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+}
+
+/* Called from interrupt handler */
+static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
+ unsigned int sock_irq_status)
+{
+ struct tifm_sd *host;
+ unsigned int host_status = 0, fifo_status = 0;
+ int error_code = 0;
+
+ spin_lock(&sock->lock);
+ host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
+ cancel_delayed_work(&host->abort_handler);
+
+ if (sock_irq_status & FIFO_EVENT) {
+ fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
+ writel(fifo_status, sock->addr + SOCK_DMA_FIFO_STATUS);
+
+ host->flags |= fifo_status & FIFO_RDY;
+ }
+
+ if (sock_irq_status & CARD_EVENT) {
+ host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+ writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+
+ if (!(host->flags & HOST_REG))
+ queue_work(sock->wq, &host->cmd_handler);
+ if (!host->req)
+ goto done;
+
+ if (host_status & TIFM_MMCSD_ERRMASK) {
+ if (host_status & TIFM_MMCSD_CERR)
+ error_code = MMC_ERR_FAILED;
+ else if (host_status &
+ (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
+ error_code = MMC_ERR_TIMEOUT;
+ else if (host_status &
+ (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
+ error_code = MMC_ERR_BADCRC;
+
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(TIFM_DMA_RESET, sock->addr + SOCK_DMA_CONTROL);
+
+ if (host->req->stop) {
+ if (host->state == SCMD) {
+ host->req->stop->error = error_code;
+ } else if(host->state == BRS) {
+ host->req->cmd->error = error_code;
+ tifm_sd_exec(host, host->req->stop);
+ queue_delayed_work(sock->wq,
+ &host->abort_handler,
+ host->timeout_jiffies);
+ host->state = SCMD;
+ goto done;
+ } else {
+ host->req->cmd->error = error_code;
+ }
+ } else {
+ host->req->cmd->error = error_code;
+ }
+ host->state = READY;
+ }
+
+ if (host_status & TIFM_MMCSD_CB)
+ host->flags |= CARD_BUSY;
+ if ((host_status & TIFM_MMCSD_EOFB) &&
+ (host->flags & CARD_BUSY)) {
+ host->written_blocks++;
+ host->flags &= ~CARD_BUSY;
+ }
+ }
+
+ if (host->req)
+ tifm_sd_process_cmd(sock, host, host_status);
+done:
+ dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
+ host_status, fifo_status);
+ spin_unlock(&sock->lock);
+ return sock_irq_status;
+}
+
+static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
+{
+ struct tifm_dev *sock = card->dev;
+ unsigned int dest_cnt;
+
+ /* DMA style IO */
+
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(long_log2(cmd->data->blksz) - 2,
+ sock->addr + SOCK_FIFO_PAGE_SIZE);
+ writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
+ writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+ dest_cnt = (cmd->data->blocks) << 8;
+
+ writel(sg_dma_address(cmd->data->sg), sock->addr + SOCK_DMA_ADDRESS);
+
+ writel(cmd->data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(cmd->data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
+
+ if (cmd->data->flags & MMC_DATA_WRITE) {
+ writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+ writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
+ sock->addr + SOCK_DMA_CONTROL);
+ } else {
+ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+ writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
+ }
+}
+
+static void tifm_sd_set_data_timeout(struct tifm_sd *host,
+ struct mmc_data *data)
+{
+ struct tifm_dev *sock = host->dev;
+ unsigned int data_timeout = data->timeout_clks;
+
+ if (fixed_timeout)
+ return;
+
+ data_timeout += data->timeout_ns /
+ ((1000000000 / host->clk_freq) * host->clk_div);
+ data_timeout *= 10; // call it fudge factor for now
+
+ if (data_timeout < 0xffff) {
+ writel((~TIFM_MMCSD_DPE) &
+ readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ } else {
+ writel(TIFM_MMCSD_DPE |
+ readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+ sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
+ data_timeout = (data_timeout >> 10) + 1;
+ if(data_timeout > 0xffff)
+ data_timeout = 0; /* set to unlimited */
+ writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+ }
+}
+
+static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+ int sg_count = 0;
+ struct mmc_data *r_data = mrq->cmd->data;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ if (host->flags & EJECT) {
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (host->req) {
+ printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (r_data) {
+ tifm_sd_set_data_timeout(host, r_data);
+
+ sg_count = tifm_map_sg(sock, r_data->sg, r_data->sg_len,
+ mrq->cmd->flags & MMC_DATA_WRITE
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ if (sg_count != 1) {
+ printk(KERN_ERR DRIVER_NAME
+ ": scatterlist map failed\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ host->written_blocks = 0;
+ host->flags &= ~CARD_BUSY;
+ tifm_sd_prepare_data(host, mrq->cmd);
+ }
+
+ host->req = mrq;
+ host->state = CMD;
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+ writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ tifm_sd_exec(host, mrq->cmd);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+
+err_out:
+ if (sg_count > 0)
+ tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+ (r_data->flags & MMC_DATA_WRITE)
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+
+ mrq->cmd->error = MMC_ERR_TIMEOUT;
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd(void *data)
+{
+ struct tifm_sd *host = data;
+ struct tifm_dev *sock = host->dev;
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct mmc_request *mrq;
+ struct mmc_data *r_data = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ mrq = host->req;
+ host->req = NULL;
+ host->state = IDLE;
+
+ if (!mrq) {
+ printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+ }
+
+ r_data = mrq->cmd->data;
+ if (r_data) {
+ if (r_data->flags & MMC_DATA_WRITE) {
+ r_data->bytes_xfered = host->written_blocks *
+ r_data->blksz;
+ } else {
+ r_data->bytes_xfered = r_data->blocks -
+ readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+ r_data->bytes_xfered *= r_data->blksz;
+ r_data->bytes_xfered += r_data->blksz -
+ readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+ }
+ tifm_unmap_sg(sock, r_data->sg, r_data->sg_len,
+ (r_data->flags & MMC_DATA_WRITE)
+ ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+ }
+
+ writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+ struct mmc_data *r_data = mrq->cmd->data;
+ char *t_buffer = NULL;
+
+ if (r_data) {
+ t_buffer = kmap(r_data->sg->page);
+ if (!t_buffer) {
+ printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
+ goto err_out;
+ }
+ }
+
+ spin_lock_irqsave(&sock->lock, flags);
+ if (host->flags & EJECT) {
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (host->req) {
+ printk(KERN_ERR DRIVER_NAME ": unfinished request detected\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ goto err_out;
+ }
+
+ if (r_data) {
+ tifm_sd_set_data_timeout(host, r_data);
+
+ host->buffer = t_buffer + r_data->sg->offset;
+ host->buffer_size = mrq->cmd->data->blocks *
+ mrq->cmd->data->blksz;
+
+ writel(TIFM_MMCSD_BUFINT |
+ readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+ writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
+ (TIFM_MMCSD_FIFO_SIZE - 1),
+ sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+ host->written_blocks = 0;
+ host->flags &= ~CARD_BUSY;
+ host->buffer_pos = 0;
+ writel(r_data->blocks - 1, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(r_data->blksz - 1, sock->addr + SOCK_MMCSD_BLOCK_LEN);
+ }
+
+ host->req = mrq;
+ host->state = CMD;
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+ writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ tifm_sd_exec(host, mrq->cmd);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+
+err_out:
+ if (t_buffer)
+ kunmap(r_data->sg->page);
+
+ mrq->cmd->error = MMC_ERR_TIMEOUT;
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_end_cmd_nodma(void *data)
+{
+ struct tifm_sd *host = (struct tifm_sd*)data;
+ struct tifm_dev *sock = host->dev;
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct mmc_request *mrq;
+ struct mmc_data *r_data = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ mrq = host->req;
+ host->req = NULL;
+ host->state = IDLE;
+
+ if (!mrq) {
+ printk(KERN_ERR DRIVER_NAME ": no request to complete?\n");
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return;
+ }
+
+ r_data = mrq->cmd->data;
+ if (r_data) {
+ writel((~TIFM_MMCSD_BUFINT) &
+ readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+ if (r_data->flags & MMC_DATA_WRITE) {
+ r_data->bytes_xfered = host->written_blocks *
+ r_data->blksz;
+ } else {
+ r_data->bytes_xfered = r_data->blocks -
+ readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
+ r_data->bytes_xfered *= r_data->blksz;
+ r_data->bytes_xfered += r_data->blksz -
+ readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
+ }
+ host->buffer = NULL;
+ host->buffer_pos = 0;
+ host->buffer_size = 0;
+ }
+
+ writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+
+ if (r_data)
+ kunmap(r_data->sg->page);
+
+ mmc_request_done(mmc, mrq);
+}
+
+static void tifm_sd_abort(void *data)
+{
+ printk(KERN_ERR DRIVER_NAME
+ ": card failed to respond for a long period of time");
+ tifm_eject(((struct tifm_sd*)data)->dev);
+}
+
+static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned int clk_div1, clk_div2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ dev_dbg(&sock->dev, "Setting bus width %d, power %d\n", ios->bus_width,
+ ios->power_mode);
+ if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
+ } else {
+ writel((~TIFM_MMCSD_4BBUS) &
+ readl(sock->addr + SOCK_MMCSD_CONFIG),
+ sock->addr + SOCK_MMCSD_CONFIG);
+ }
+
+ if (ios->clock) {
+ clk_div1 = 20000000 / ios->clock;
+ if (!clk_div1)
+ clk_div1 = 1;
+
+ clk_div2 = 24000000 / ios->clock;
+ if (!clk_div2)
+ clk_div2 = 1;
+
+ if ((20000000 / clk_div1) > ios->clock)
+ clk_div1++;
+ if ((24000000 / clk_div2) > ios->clock)
+ clk_div2++;
+ if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
+ host->clk_freq = 20000000;
+ host->clk_div = clk_div1;
+ writel((~TIFM_CTRL_FAST_CLK) &
+ readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ } else {
+ host->clk_freq = 24000000;
+ host->clk_div = clk_div2;
+ writel(TIFM_CTRL_FAST_CLK |
+ readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ }
+ } else {
+ host->clk_div = 0;
+ }
+ host->clk_div &= TIFM_MMCSD_CLKMASK;
+ writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
+ readl(sock->addr + SOCK_MMCSD_CONFIG)),
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
+ host->flags |= OPENDRAIN;
+ else
+ host->flags &= ~OPENDRAIN;
+
+ /* chip_select : maybe later */
+ //vdd
+ //power is set before probe / after remove
+ //I believe, power_off when already marked for eject is sufficient to
+ // allow removal.
+ if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
+ host->flags |= EJECT_DONE;
+ wake_up_all(&host->can_eject);
+ }
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static int tifm_sd_ro(struct mmc_host *mmc)
+{
+ int rc;
+ struct tifm_sd *host = mmc_priv(mmc);
+ struct tifm_dev *sock = host->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+
+ host->flags |= (CARD_RO & readl(sock->addr + SOCK_PRESENT_STATE));
+ rc = (host->flags & CARD_RO) ? 1 : 0;
+
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return rc;
+}
+
+static struct mmc_host_ops tifm_sd_ops = {
+ .request = tifm_sd_request,
+ .set_ios = tifm_sd_ios,
+ .get_ro = tifm_sd_ro
+};
+
+static void tifm_sd_register_host(void *data)
+{
+ struct tifm_sd *host = (struct tifm_sd*)data;
+ struct tifm_dev *sock = host->dev;
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ host->flags |= HOST_REG;
+ PREPARE_WORK(&host->cmd_handler,
+ no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+ data);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ dev_dbg(&sock->dev, "adding host\n");
+ mmc_add_host(mmc);
+}
+
+static int tifm_sd_probe(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc;
+ struct tifm_sd *host;
+ int rc = -EIO;
+
+ if (!(TIFM_SOCK_STATE_OCCUPIED &
+ readl(sock->addr + SOCK_PRESENT_STATE))) {
+ printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
+ return rc;
+ }
+
+ mmc = mmc_alloc_host(sizeof(struct tifm_sd), &sock->dev);
+ if (!mmc)
+ return -ENOMEM;
+
+ host = mmc_priv(mmc);
+ host->dev = sock;
+ host->clk_div = 61;
+ init_waitqueue_head(&host->can_eject);
+ INIT_WORK(&host->cmd_handler, tifm_sd_register_host, host);
+ INIT_WORK(&host->abort_handler, tifm_sd_abort, host);
+
+ tifm_set_drvdata(sock, mmc);
+ sock->signal_irq = tifm_sd_signal_irq;
+
+ host->clk_freq = 20000000;
+ host->timeout_jiffies = msecs_to_jiffies(1000);
+
+ tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
+ mmc->ops = &tifm_sd_ops;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->f_min = 20000000 / 60;
+ mmc->f_max = 24000000;
+ mmc->max_hw_segs = 1;
+ mmc->max_phys_segs = 1;
+ mmc->max_sectors = 127;
+ mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
+
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ for (rc = 0; rc < 50; rc++) {
+ /* Wait for reset ack */
+ if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+ rc = 0;
+ break;
+ }
+ msleep(10);
+ }
+
+ if (rc) {
+ printk(KERN_ERR DRIVER_NAME
+ ": card not ready - probe failed\n");
+ mmc_free_host(mmc);
+ return -ENODEV;
+ }
+
+ writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+ writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+ writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+ sock->addr + SOCK_MMCSD_INT_ENABLE);
+
+ writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
+ writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+ writel(host->clk_div | TIFM_MMCSD_POWER,
+ sock->addr + SOCK_MMCSD_CONFIG);
+
+ queue_delayed_work(sock->wq, &host->abort_handler,
+ host->timeout_jiffies);
+
+ return 0;
+}
+
+static int tifm_sd_host_is_down(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
+ unsigned long flags;
+ int rc = 0;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ rc = (host->flags & EJECT_DONE);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ return rc;
+}
+
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+ struct mmc_host *mmc = tifm_get_drvdata(sock);
+ struct tifm_sd *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&sock->lock, flags);
+ host->flags |= EJECT;
+ if (host->req)
+ queue_work(sock->wq, &host->cmd_handler);
+ spin_unlock_irqrestore(&sock->lock, flags);
+ wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
+ host->timeout_jiffies);
+
+ if (host->flags & HOST_REG)
+ mmc_remove_host(mmc);
+
+ /* The meaning of the bit majority in this constant is unknown. */
+ writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+ sock->addr + SOCK_CONTROL);
+ writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+ writel(TIFM_FIFO_INT_SETALL,
+ sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+ writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+
+ tifm_set_drvdata(sock, NULL);
+ mmc_free_host(mmc);
+}
+
+static tifm_media_id tifm_sd_id_tbl[] = {
+ FM_SD, 0
+};
+
+static struct tifm_driver tifm_sd_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE
+ },
+ .id_table = tifm_sd_id_tbl,
+ .probe = tifm_sd_probe,
+ .remove = tifm_sd_remove
+};
+
+static int __init tifm_sd_init(void)
+{
+ return tifm_register_driver(&tifm_sd_driver);
+}
+
+static void __exit tifm_sd_exit(void)
+{
+ tifm_unregister_driver(&tifm_sd_driver);
+}
+
+MODULE_AUTHOR("Alex Dubov");
+MODULE_DESCRIPTION("TI FlashMedia SD driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(tifm, tifm_sd_id_tbl);
+MODULE_VERSION(DRIVER_VERSION);
+
+module_init(tifm_sd_init);
+module_exit(tifm_sd_exit);
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index c351c6d1a18a..ced309b37a8f 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -4,8 +4,9 @@
* Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
*
* 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.
+ * 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.
*
*
* Warning!
@@ -1255,7 +1256,7 @@ end:
* Interrupt handling
*/
-static irqreturn_t wbsd_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wbsd_irq(int irq, void *dev_id)
{
struct wbsd_host *host = dev_id;
int isr;
@@ -1323,7 +1324,7 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
mmc->f_min = 375000;
mmc->f_max = 24000000;
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
- mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE | MMC_CAP_BYTEBLOCK;
spin_lock_init(&host->lock);
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 249baa701cb0..6072993f01e3 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -4,8 +4,9 @@
* Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
*
* 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.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
*/
#define LOCK_CODE 0xAA
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index a03e862851db..a304b34c2632 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -166,7 +166,7 @@ config MTD_CHAR
config MTD_BLOCK
tristate "Caching block device access to MTD devices"
- depends on MTD
+ depends on MTD && BLOCK
---help---
Although most flash chips have an erase size too large to be useful
as block devices, it is possible to use MTD devices which are based
@@ -188,7 +188,7 @@ config MTD_BLOCK
config MTD_BLOCK_RO
tristate "Readonly block device access to MTD devices"
- depends on MTD_BLOCK!=y && MTD
+ depends on MTD_BLOCK!=y && MTD && BLOCK
help
This allows you to mount read-only file systems (such as cramfs)
from an MTD device, without the overhead (and danger) of the caching
@@ -199,7 +199,7 @@ config MTD_BLOCK_RO
config FTL
tristate "FTL (Flash Translation Layer) support"
- depends on MTD
+ depends on MTD && BLOCK
---help---
This provides support for the original Flash Translation Layer which
is part of the PCMCIA specification. It uses a kind of pseudo-
@@ -215,7 +215,7 @@ config FTL
config NFTL
tristate "NFTL (NAND Flash Translation Layer) support"
- depends on MTD
+ depends on MTD && BLOCK
---help---
This provides support for the NAND Flash Translation Layer which is
used on M-Systems' DiskOnChip devices. It uses a kind of pseudo-
@@ -238,7 +238,7 @@ config NFTL_RW
config INFTL
tristate "INFTL (Inverse NAND Flash Translation Layer) support"
- depends on MTD
+ depends on MTD && BLOCK
---help---
This provides support for the Inverse NAND Flash Translation
Layer which is used on M-Systems' newer DiskOnChip devices. It
@@ -255,7 +255,7 @@ config INFTL
config RFD_FTL
tristate "Resident Flash Disk (Flash Translation Layer) support"
- depends on MTD
+ depends on MTD && BLOCK
---help---
This provides support for the flash translation layer known
as the Resident Flash Disk (RFD), as used by the Embedded BIOS
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index 6d8f30deb868..72e6d73beb40 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -270,7 +270,7 @@ config MTD_JEDEC
tristate "JEDEC device support"
depends on MTD && MTD_OBSOLETE_CHIPS && BROKEN
help
- Enable older older JEDEC flash interface devices for self
+ 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
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 16c02b5ccf7e..440f6851da69 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -136,7 +136,7 @@ config MTDRAM_ABS_POS
config MTD_BLOCK2MTD
tristate "MTD using block device"
- depends on MTD
+ depends on MTD && BLOCK
help
This driver allows a block device to appear as an MTD. It would
generally be used in the following cases:
diff --git a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c
index 642d96bc8919..2cc902436275 100644
--- a/drivers/mtd/maps/arctic-mtd.c
+++ b/drivers/mtd/maps/arctic-mtd.c
@@ -96,7 +96,7 @@ static struct mtd_partition arctic_partitions[PARTITIONS] = {
static int __init
init_arctic_mtd(void)
{
- int err = 0;
+ int err;
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
@@ -112,7 +112,7 @@ init_arctic_mtd(void)
arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map);
if (!arctic_mtd) {
- iounmap((void *) arctic_mtd_map.virt);
+ iounmap(arctic_mtd_map.virt);
return -ENXIO;
}
@@ -121,7 +121,7 @@ init_arctic_mtd(void)
err = add_mtd_partitions(arctic_mtd, arctic_partitions, PARTITIONS);
if (err) {
printk("%s: add_mtd_partitions failed\n", NAME);
- iounmap((void *) arctic_mtd_map.virt);
+ iounmap(arctic_mtd_map.virt);
}
return err;
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
index 51f962dd7e31..e074bb6787d2 100644
--- a/drivers/mtd/maps/bast-flash.c
+++ b/drivers/mtd/maps/bast-flash.c
@@ -1,4 +1,4 @@
-/* linux/drivers/mtd/maps/bast_flash.c
+/* linux/drivers/mtd/maps/bast-flash.c
*
* Copyright (c) 2004-2005 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c
index a64b1a5ab316..d76d5981b863 100644
--- a/drivers/mtd/maps/beech-mtd.c
+++ b/drivers/mtd/maps/beech-mtd.c
@@ -72,7 +72,7 @@ static struct mtd_partition beech_partitions[2] = {
static int __init
init_beech_mtd(void)
{
- int err = 0;
+ int err;
printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR);
@@ -89,7 +89,7 @@ init_beech_mtd(void)
beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map);
if (!beech_mtd) {
- iounmap((void *) beech_mtd_map.virt);
+ iounmap(beech_mtd_map.virt);
return -ENXIO;
}
@@ -98,7 +98,7 @@ init_beech_mtd(void)
err = add_mtd_partitions(beech_mtd, beech_partitions, 2);
if (err) {
printk("%s: add_mtd_partitions failed\n", NAME);
- iounmap((void *) beech_mtd_map.virt);
+ iounmap(beech_mtd_map.virt);
}
return err;
diff --git a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c
index d6bef100d69a..df2c38ef105a 100644
--- a/drivers/mtd/maps/cstm_mips_ixx.c
+++ b/drivers/mtd/maps/cstm_mips_ixx.c
@@ -175,8 +175,8 @@ int __init init_cstm_mips_ixx(void)
printk(KERN_WARNING "Failed to ioremap\n");
for (j = 0; j < i; j++) {
if (cstm_mips_ixx_map[j].virt) {
- iounmap((void *)cstm_mips_ixx_map[j].virt);
- cstm_mips_ixx_map[j].virt = 0;
+ iounmap(cstm_mips_ixx_map[j].virt);
+ cstm_mips_ixx_map[j].virt = NULL;
}
}
return -EIO;
@@ -214,8 +214,8 @@ int __init init_cstm_mips_ixx(void)
else {
for (i = 0; i < PHYSMAP_NUMBER; i++) {
if (cstm_mips_ixx_map[i].virt) {
- iounmap((void *)cstm_mips_ixx_map[i].virt);
- cstm_mips_ixx_map[i].virt = 0;
+ iounmap(cstm_mips_ixx_map[i].virt);
+ cstm_mips_ixx_map[i].virt = NULL;
}
}
return -ENXIO;
diff --git a/drivers/mtd/maps/dmv182.c b/drivers/mtd/maps/dmv182.c
index a43c49905cac..e0558b0b2fe6 100644
--- a/drivers/mtd/maps/dmv182.c
+++ b/drivers/mtd/maps/dmv182.c
@@ -1,6 +1,6 @@
/*
- * drivers/mtd/maps/svme182.c
+ * drivers/mtd/maps/dmv182.c
*
* Flash map driver for the Dy4 SVME182 board
*
diff --git a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c
index 198e840ff6db..f9e8e5bcbc33 100644
--- a/drivers/mtd/maps/nettel.c
+++ b/drivers/mtd/maps/nettel.c
@@ -463,7 +463,7 @@ int __init nettel_init(void)
#ifdef CONFIG_MTD_CFI_INTELEXT
out_unmap1:
- iounmap((void *) nettel_intel_map.virt);
+ iounmap(nettel_intel_map.virt);
#endif
out_unmap2:
diff --git a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c
index bc7cc71788bc..d1717763f719 100644
--- a/drivers/mtd/maps/physmap.c
+++ b/drivers/mtd/maps/physmap.c
@@ -62,7 +62,7 @@ static int physmap_flash_remove(struct platform_device *dev)
}
if (info->map.virt != NULL)
- iounmap((void *)info->map.virt);
+ iounmap(info->map.virt);
if (info->res != NULL) {
release_resource(info->res);
diff --git a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c
index 2257d2b500c0..4d858b3d5f82 100644
--- a/drivers/mtd/maps/redwood.c
+++ b/drivers/mtd/maps/redwood.c
@@ -126,7 +126,7 @@ static struct mtd_info *redwood_mtd;
int __init init_redwood_flash(void)
{
- int err = 0;
+ int err;
printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n",
WINDOW_SIZE, WINDOW_ADDR);
diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c
index 458d3c8ae1ee..178b53b56be9 100644
--- a/drivers/mtd/mtd_blkdevs.c
+++ b/drivers/mtd/mtd_blkdevs.c
@@ -46,7 +46,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
nsect = req->current_nr_sectors;
buf = req->buffer;
- if (!(req->flags & REQ_CMD))
+ if (!blk_fs_request(req))
return 0;
if (block + nsect > get_capacity(req->rq_disk))
@@ -69,7 +69,7 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr,
return 1;
default:
- printk(KERN_NOTICE "Unknown request %ld\n", rq_data_dir(req));
+ printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req));
return 0;
}
}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index c99302ed3823..1831340e5f51 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -21,7 +21,7 @@ config MTD_NAND_VERIFY_WRITE
NAND flash device internally checks only bits transitioning
from 1 to 0. There is a rare possibility that even though the
device thinks the write was successful, a bit could have been
- flipped accidentaly due to device wear or something else.
+ flipped accidentally due to device wear or something else.
config MTD_NAND_ECC_SMC
bool "NAND ECC Smart Media byte order"
diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c
index e0a1d386e581..94924d52a9b9 100644
--- a/drivers/mtd/nand/cs553x_nand.c
+++ b/drivers/mtd/nand/cs553x_nand.c
@@ -249,7 +249,7 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
goto out;
out_ior:
- iounmap((void *)this->IO_ADDR_R);
+ iounmap(this->IO_ADDR_R);
out_mtd:
kfree(new_mtd);
out:
diff --git a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c
index 12017f3c6bd6..1daf8231aaef 100644
--- a/drivers/mtd/nand/edb7312.c
+++ b/drivers/mtd/nand/edb7312.c
@@ -199,7 +199,7 @@ static void __exit ep7312_cleanup(void)
nand_release(ap7312_mtd);
/* Release io resource */
- iounmap((void *)this->IO_ADDR_R);
+ iounmap(this->IO_ADDR_R);
/* Free the MTD device structure */
kfree(ep7312_mtd);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 975b2ef61121..baece61169f4 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -415,7 +415,7 @@ static int nand_block_checkbad(struct mtd_info *mtd, loff_t ofs, int getchip,
* Wait for the ready pin, after a command
* The timeout is catched later.
*/
-static void nand_wait_ready(struct mtd_info *mtd)
+void nand_wait_ready(struct mtd_info *mtd)
{
struct nand_chip *chip = mtd->priv;
unsigned long timeo = jiffies + 2;
@@ -429,6 +429,7 @@ static void nand_wait_ready(struct mtd_info *mtd)
} while (time_before(jiffies, timeo));
led_trigger_event(nand_led_trigger, LED_OFF);
}
+EXPORT_SYMBOL_GPL(nand_wait_ready);
/**
* nand_command - [DEFAULT] Send command to NAND device
@@ -766,8 +767,8 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
- uint8_t *ecc_calc = chip->buffers.ecccalc;
- uint8_t *ecc_code = chip->buffers.ecccode;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
int *eccpos = chip->ecc.layout->eccpos;
nand_read_page_raw(mtd, chip, buf);
@@ -808,8 +809,8 @@ static int nand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
uint8_t *p = buf;
- uint8_t *ecc_calc = chip->buffers.ecccalc;
- uint8_t *ecc_code = chip->buffers.ecccode;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
+ uint8_t *ecc_code = chip->buffers->ecccode;
int *eccpos = chip->ecc.layout->eccpos;
for (i = 0; eccsteps; eccsteps--, i += eccbytes, p += eccsize) {
@@ -970,7 +971,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
page = realpage & chip->pagemask;
col = (int)(from & (mtd->writesize - 1));
- chip->oob_poi = chip->buffers.oobrbuf;
+ chip->oob_poi = chip->buffers->oobrbuf;
buf = ops->datbuf;
oob = ops->oobbuf;
@@ -981,7 +982,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
/* Is the current page in the buffer ? */
if (realpage != chip->pagebuf || oob) {
- bufpoi = aligned ? buf : chip->buffers.databuf;
+ bufpoi = aligned ? buf : chip->buffers->databuf;
if (likely(sndcmd)) {
chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
@@ -989,14 +990,17 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
}
/* Now read the page into the buffer */
- ret = chip->ecc.read_page(mtd, chip, bufpoi);
+ if (unlikely(ops->mode == MTD_OOB_RAW))
+ ret = chip->ecc.read_page_raw(mtd, chip, bufpoi);
+ else
+ ret = chip->ecc.read_page(mtd, chip, bufpoi);
if (ret < 0)
break;
/* Transfer not aligned data */
if (!aligned) {
chip->pagebuf = realpage;
- memcpy(buf, chip->buffers.databuf + col, bytes);
+ memcpy(buf, chip->buffers->databuf + col, bytes);
}
buf += bytes;
@@ -1023,7 +1027,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
nand_wait_ready(mtd);
}
} else {
- memcpy(buf, chip->buffers.databuf + col, bytes);
+ memcpy(buf, chip->buffers->databuf + col, bytes);
buf += bytes;
}
@@ -1266,7 +1270,7 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
realpage = (int)(from >> chip->page_shift);
page = realpage & chip->pagemask;
- chip->oob_poi = chip->buffers.oobrbuf;
+ chip->oob_poi = chip->buffers->oobrbuf;
while(1) {
sndcmd = chip->ecc.read_oob(mtd, chip, page, sndcmd);
@@ -1322,8 +1326,6 @@ static int nand_do_read_oob(struct mtd_info *mtd, loff_t from,
static int nand_read_oob(struct mtd_info *mtd, loff_t from,
struct mtd_oob_ops *ops)
{
- int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
- uint8_t *buf) = NULL;
struct nand_chip *chip = mtd->priv;
int ret = -ENOTSUPP;
@@ -1341,12 +1343,7 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
switch(ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_AUTO:
- break;
-
case MTD_OOB_RAW:
- /* Replace the read_page algorithm temporary */
- read_page = chip->ecc.read_page;
- chip->ecc.read_page = nand_read_page_raw;
break;
default:
@@ -1358,8 +1355,6 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from,
else
ret = nand_do_read_ops(mtd, from, ops);
- if (unlikely(ops->mode == MTD_OOB_RAW))
- chip->ecc.read_page = read_page;
out:
nand_release_device(mtd);
return ret;
@@ -1391,7 +1386,7 @@ static void nand_write_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
- uint8_t *ecc_calc = chip->buffers.ecccalc;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
int *eccpos = chip->ecc.layout->eccpos;
@@ -1417,7 +1412,7 @@ static void nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
int i, eccsize = chip->ecc.size;
int eccbytes = chip->ecc.bytes;
int eccsteps = chip->ecc.steps;
- uint8_t *ecc_calc = chip->buffers.ecccalc;
+ uint8_t *ecc_calc = chip->buffers->ecccalc;
const uint8_t *p = buf;
int *eccpos = chip->ecc.layout->eccpos;
@@ -1478,7 +1473,7 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
}
/**
- * nand_write_page - [INTERNAL] write one page
+ * nand_write_page - [REPLACEABLE] write one page
* @mtd: MTD device structure
* @chip: NAND chip descriptor
* @buf: the data to write
@@ -1486,13 +1481,16 @@ static void nand_write_page_syndrome(struct mtd_info *mtd,
* @cached: cached programming
*/
static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf, int page, int cached)
+ const uint8_t *buf, int page, int cached, int raw)
{
int status;
chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
- chip->ecc.write_page(mtd, chip, buf);
+ if (unlikely(raw))
+ chip->ecc.write_page_raw(mtd, chip, buf);
+ else
+ chip->ecc.write_page(mtd, chip, buf);
/*
* Cached progamming disabled for now, Not sure if its worth the
@@ -1627,7 +1625,7 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
(chip->pagebuf << chip->page_shift) < (to + ops->len))
chip->pagebuf = -1;
- chip->oob_poi = chip->buffers.oobwbuf;
+ chip->oob_poi = chip->buffers->oobwbuf;
while(1) {
int cached = writelen > bytes && page != blockmask;
@@ -1635,7 +1633,8 @@ static int nand_do_write_ops(struct mtd_info *mtd, loff_t to,
if (unlikely(oob))
oob = nand_fill_oob(chip, oob, ops);
- ret = nand_write_page(mtd, chip, buf, page, cached);
+ ret = chip->write_page(mtd, chip, buf, page, cached,
+ (ops->mode == MTD_OOB_RAW));
if (ret)
break;
@@ -1745,7 +1744,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
if (page == chip->pagebuf)
chip->pagebuf = -1;
- chip->oob_poi = chip->buffers.oobwbuf;
+ chip->oob_poi = chip->buffers->oobwbuf;
memset(chip->oob_poi, 0xff, mtd->oobsize);
nand_fill_oob(chip, ops->oobbuf, ops);
status = chip->ecc.write_oob(mtd, chip, page & chip->pagemask);
@@ -1768,8 +1767,6 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
static int nand_write_oob(struct mtd_info *mtd, loff_t to,
struct mtd_oob_ops *ops)
{
- void (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
- const uint8_t *buf) = NULL;
struct nand_chip *chip = mtd->priv;
int ret = -ENOTSUPP;
@@ -1787,12 +1784,7 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
switch(ops->mode) {
case MTD_OOB_PLACE:
case MTD_OOB_AUTO:
- break;
-
case MTD_OOB_RAW:
- /* Replace the write_page algorithm temporary */
- write_page = chip->ecc.write_page;
- chip->ecc.write_page = nand_write_page_raw;
break;
default:
@@ -1804,8 +1796,6 @@ static int nand_write_oob(struct mtd_info *mtd, loff_t to,
else
ret = nand_do_write_ops(mtd, to, ops);
- if (unlikely(ops->mode == MTD_OOB_RAW))
- chip->ecc.write_page = write_page;
out:
nand_release_device(mtd);
return ret;
@@ -2288,40 +2278,22 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
return type;
}
-/* module_text_address() isn't exported, and it's mostly a pointless
- test if this is a module _anyway_ -- they'd have to try _really_ hard
- to call us from in-kernel code if the core NAND support is modular. */
-#ifdef MODULE
-#define caller_is_module() (1)
-#else
-#define caller_is_module() \
- module_text_address((unsigned long)__builtin_return_address(0))
-#endif
-
/**
- * nand_scan - [NAND Interface] Scan for the NAND device
- * @mtd: MTD device structure
- * @maxchips: Number of chips to scan for
+ * nand_scan_ident - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ * @maxchips: Number of chips to scan for
*
- * This fills out all the uninitialized function pointers
- * with the defaults.
- * The flash ID is read and the mtd/chip structures are
- * filled with the appropriate values.
- * The mtd->owner field must be set to the module of the caller
+ * This is the first phase of the normal nand_scan() function. It
+ * reads the flash ID and sets up MTD fields accordingly.
*
+ * The mtd->owner field must be set to the module of the caller.
*/
-int nand_scan(struct mtd_info *mtd, int maxchips)
+int nand_scan_ident(struct mtd_info *mtd, int maxchips)
{
int i, busw, nand_maf_id;
struct nand_chip *chip = mtd->priv;
struct nand_flash_dev *type;
- /* Many callers got this wrong, so check for it for a while... */
- if (!mtd->owner && caller_is_module()) {
- printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
- BUG();
- }
-
/* Get buswidth to select the correct functions */
busw = chip->options & NAND_BUSWIDTH_16;
/* Set the default functions */
@@ -2353,8 +2325,31 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
chip->numchips = i;
mtd->size = i * chip->chipsize;
+ return 0;
+}
+
+
+/**
+ * nand_scan_tail - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ * @maxchips: Number of chips to scan for
+ *
+ * This is the second phase of the normal nand_scan() function. It
+ * fills out all the uninitialized function pointers with the defaults
+ * and scans for a bad block table if appropriate.
+ */
+int nand_scan_tail(struct mtd_info *mtd)
+{
+ int i;
+ struct nand_chip *chip = mtd->priv;
+
+ if (!(chip->options & NAND_OWN_BUFFERS))
+ chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
+ if (!chip->buffers)
+ return -ENOMEM;
+
/* Preset the internal oob write buffer */
- memset(chip->buffers.oobwbuf, 0xff, mtd->oobsize);
+ memset(chip->buffers->oobwbuf, 0xff, mtd->oobsize);
/*
* If no default placement scheme is given, select an appropriate one
@@ -2377,10 +2372,18 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
}
}
+ if (!chip->write_page)
+ chip->write_page = nand_write_page;
+
/*
* check ECC mode, default to software if 3byte/512byte hardware ECC is
* selected and we have 256 byte pagesize fallback to software ECC
*/
+ if (!chip->ecc.read_page_raw)
+ chip->ecc.read_page_raw = nand_read_page_raw;
+ if (!chip->ecc.write_page_raw)
+ chip->ecc.write_page_raw = nand_write_page_raw;
+
switch (chip->ecc.mode) {
case NAND_ECC_HW:
/* Use standard hwecc read page function ? */
@@ -2438,6 +2441,7 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
chip->ecc.size = mtd->writesize;
chip->ecc.bytes = 0;
break;
+
default:
printk(KERN_WARNING "Invalid NAND_ECC_MODE %d\n",
chip->ecc.mode);
@@ -2503,6 +2507,44 @@ int nand_scan(struct mtd_info *mtd, int maxchips)
return chip->scan_bbt(mtd);
}
+/* module_text_address() isn't exported, and it's mostly a pointless
+ test if this is a module _anyway_ -- they'd have to try _really_ hard
+ to call us from in-kernel code if the core NAND support is modular. */
+#ifdef MODULE
+#define caller_is_module() (1)
+#else
+#define caller_is_module() \
+ module_text_address((unsigned long)__builtin_return_address(0))
+#endif
+
+/**
+ * nand_scan - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+ * @maxchips: Number of chips to scan for
+ *
+ * This fills out all the uninitialized function pointers
+ * with the defaults.
+ * The flash ID is read and the mtd/chip structures are
+ * filled with the appropriate values.
+ * The mtd->owner field must be set to the module of the caller
+ *
+ */
+int nand_scan(struct mtd_info *mtd, int maxchips)
+{
+ int ret;
+
+ /* Many callers got this wrong, so check for it for a while... */
+ if (!mtd->owner && caller_is_module()) {
+ printk(KERN_CRIT "nand_scan() called with NULL mtd->owner!\n");
+ BUG();
+ }
+
+ ret = nand_scan_ident(mtd, maxchips);
+ if (!ret)
+ ret = nand_scan_tail(mtd);
+ return ret;
+}
+
/**
* nand_release - [NAND Interface] Free resources held by the NAND device
* @mtd: MTD device structure
@@ -2520,9 +2562,13 @@ void nand_release(struct mtd_info *mtd)
/* Free bad block table memory */
kfree(chip->bbt);
+ if (!(chip->options & NAND_OWN_BUFFERS))
+ kfree(chip->buffers);
}
EXPORT_SYMBOL_GPL(nand_scan);
+EXPORT_SYMBOL_GPL(nand_scan_ident);
+EXPORT_SYMBOL_GPL(nand_scan_tail);
EXPORT_SYMBOL_GPL(nand_release);
static int __init nand_base_init(void)
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index a612c4ea8194..9402653eb09b 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -759,7 +759,7 @@ static inline int nand_memory_bbt(struct mtd_info *mtd, struct nand_bbt_descr *b
struct nand_chip *this = mtd->priv;
bd->options &= ~NAND_BBT_SCANEMPTY;
- return create_bbt(mtd, this->buffers.databuf, bd, -1);
+ return create_bbt(mtd, this->buffers->databuf, bd, -1);
}
/**
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index dd5cea8b4a7a..b5a5f8da4722 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -175,6 +175,8 @@ int nftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
return res;
}
+#ifdef CONFIG_NFTL_RW
+
/*
* Write data and oob to flash
*/
@@ -196,8 +198,6 @@ static int nftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
return res;
}
-#ifdef CONFIG_NFTL_RW
-
/* Actual NFTL access routines */
/* NFTL_findfreeblock: Find a free Erase Unit on the NFTL partition. This function is used
* when the give Virtual Unit Chain
diff --git a/drivers/mtd/onenand/Kconfig b/drivers/mtd/onenand/Kconfig
index 5930a03736d7..373bddce8f1c 100644
--- a/drivers/mtd/onenand/Kconfig
+++ b/drivers/mtd/onenand/Kconfig
@@ -21,7 +21,7 @@ config MTD_ONENAND_VERIFY_WRITE
OneNAND flash device internally checks only bits transitioning
from 1 to 0. There is a rare possibility that even though the
device thinks the write was successful, a bit could have been
- flipped accidentaly due to device wear or something else.
+ flipped accidentally due to device wear or something else.
config MTD_ONENAND_GENERIC
tristate "OneNAND Flash device via platform device driver"
@@ -43,10 +43,4 @@ config MTD_ONENAND_OTP
OTP block is fully-guaranteed to be a valid block.
-config MTD_ONENAND_SYNC_READ
- bool "OneNAND Sync. Burst Read Support"
- depends on ARCH_OMAP
- help
- This enables support for Sync. Burst Read.
-
endmenu
diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c
index 84ec40d25438..8ed68b28afe3 100644
--- a/drivers/mtd/onenand/onenand_base.c
+++ b/drivers/mtd/onenand/onenand_base.c
@@ -1,7 +1,7 @@
/*
* linux/drivers/mtd/onenand/onenand_base.c
*
- * Copyright (C) 2005 Samsung Electronics
+ * Copyright (C) 2005-2006 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -199,6 +199,7 @@ static int onenand_command(struct mtd_info *mtd, int cmd, loff_t addr, size_t le
case ONENAND_CMD_UNLOCK:
case ONENAND_CMD_LOCK:
case ONENAND_CMD_LOCK_TIGHT:
+ case ONENAND_CMD_UNLOCK_ALL:
block = -1;
page = -1;
break;
@@ -1211,11 +1212,11 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
end = len >> this->erase_shift;
/* Continuous lock scheme */
- if (this->options & ONENAND_CONT_LOCK) {
+ if (this->options & ONENAND_HAS_CONT_LOCK) {
/* Set start block address */
this->write_word(start, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
/* Set end block address */
- this->write_word(end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
+ this->write_word(start + end - 1, this->base + ONENAND_REG_END_BLOCK_ADDRESS);
/* Write unlock command */
this->command(mtd, ONENAND_CMD_UNLOCK, 0, 0);
@@ -1236,7 +1237,7 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
}
/* Block lock scheme */
- for (block = start; block < end; block++) {
+ for (block = start; block < start + end; block++) {
/* Set block address */
value = onenand_block_address(this, block);
this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
@@ -1265,6 +1266,79 @@ static int onenand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
return 0;
}
+/**
+ * onenand_check_lock_status - [OneNAND Interface] Check lock status
+ * @param this onenand chip data structure
+ *
+ * Check lock status
+ */
+static void onenand_check_lock_status(struct onenand_chip *this)
+{
+ unsigned int value, block, status;
+ unsigned int end;
+
+ end = this->chipsize >> this->erase_shift;
+ for (block = 0; block < end; block++) {
+ /* Set block address */
+ value = onenand_block_address(this, block);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS1);
+ /* Select DataRAM for DDP */
+ value = onenand_bufferram_address(this, block);
+ this->write_word(value, this->base + ONENAND_REG_START_ADDRESS2);
+ /* Set start block address */
+ this->write_word(block, this->base + ONENAND_REG_START_BLOCK_ADDRESS);
+
+ /* Check lock status */
+ status = this->read_word(this->base + ONENAND_REG_WP_STATUS);
+ if (!(status & ONENAND_WP_US))
+ printk(KERN_ERR "block = %d, wp status = 0x%x\n", block, status);
+ }
+}
+
+/**
+ * onenand_unlock_all - [OneNAND Interface] unlock all blocks
+ * @param mtd MTD device structure
+ *
+ * Unlock all blocks
+ */
+static int onenand_unlock_all(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+
+ if (this->options & ONENAND_HAS_UNLOCK_ALL) {
+ /* Write unlock command */
+ this->command(mtd, ONENAND_CMD_UNLOCK_ALL, 0, 0);
+
+ /* There's no return value */
+ this->wait(mtd, FL_UNLOCKING);
+
+ /* Sanity check */
+ while (this->read_word(this->base + ONENAND_REG_CTRL_STATUS)
+ & ONENAND_CTRL_ONGO)
+ continue;
+
+ /* Workaround for all block unlock in DDP */
+ if (this->device_id & ONENAND_DEVICE_IS_DDP) {
+ loff_t ofs;
+ size_t len;
+
+ /* 1st block on another chip */
+ ofs = this->chipsize >> 1;
+ len = 1 << this->erase_shift;
+
+ onenand_unlock(mtd, ofs, len);
+ }
+
+ onenand_check_lock_status(this);
+
+ return 0;
+ }
+
+ mtd->unlock(mtd, 0x0, this->chipsize);
+
+ return 0;
+}
+
#ifdef CONFIG_MTD_ONENAND_OTP
/* Interal OTP operation */
@@ -1564,12 +1638,43 @@ static int onenand_lock_user_prot_reg(struct mtd_info *mtd, loff_t from,
#endif /* CONFIG_MTD_ONENAND_OTP */
/**
+ * onenand_lock_scheme - Check and set OneNAND lock scheme
+ * @param mtd MTD data structure
+ *
+ * Check and set OneNAND lock scheme
+ */
+static void onenand_lock_scheme(struct mtd_info *mtd)
+{
+ struct onenand_chip *this = mtd->priv;
+ unsigned int density, process;
+
+ /* Lock scheme depends on density and process */
+ density = this->device_id >> ONENAND_DEVICE_DENSITY_SHIFT;
+ process = this->version_id >> ONENAND_VERSION_PROCESS_SHIFT;
+
+ /* Lock scheme */
+ if (density >= ONENAND_DEVICE_DENSITY_1Gb) {
+ /* A-Die has all block unlock */
+ if (process) {
+ printk(KERN_DEBUG "Chip support all block unlock\n");
+ this->options |= ONENAND_HAS_UNLOCK_ALL;
+ }
+ } else {
+ /* Some OneNAND has continues lock scheme */
+ if (!process) {
+ printk(KERN_DEBUG "Lock scheme is Continues Lock\n");
+ this->options |= ONENAND_HAS_CONT_LOCK;
+ }
+ }
+}
+
+/**
* onenand_print_device_info - Print device ID
* @param device device ID
*
* Print device ID
*/
-static void onenand_print_device_info(int device)
+static void onenand_print_device_info(int device, int version)
{
int vcc, demuxed, ddp, density;
@@ -1583,6 +1688,7 @@ static void onenand_print_device_info(int device)
(16 << density),
vcc ? "2.65/3.3" : "1.8",
device);
+ printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version);
}
static const struct onenand_manufacturers onenand_manuf_ids[] = {
@@ -1625,9 +1731,14 @@ static int onenand_check_maf(int manuf)
static int onenand_probe(struct mtd_info *mtd)
{
struct onenand_chip *this = mtd->priv;
- int bram_maf_id, bram_dev_id, maf_id, dev_id;
- int version_id;
+ int bram_maf_id, bram_dev_id, maf_id, dev_id, ver_id;
int density;
+ int syscfg;
+
+ /* Save system configuration 1 */
+ syscfg = this->read_word(this->base + ONENAND_REG_SYS_CFG1);
+ /* Clear Sync. Burst Read mode to read BootRAM */
+ this->write_word((syscfg & ~ONENAND_SYS_CFG1_SYNC_READ), this->base + ONENAND_REG_SYS_CFG1);
/* Send the command for reading device ID from BootRAM */
this->write_word(ONENAND_CMD_READID, this->base + ONENAND_BOOTRAM);
@@ -1636,24 +1747,31 @@ static int onenand_probe(struct mtd_info *mtd)
bram_maf_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x0);
bram_dev_id = this->read_word(this->base + ONENAND_BOOTRAM + 0x2);
+ /* Reset OneNAND to read default register values */
+ this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
+ /* Wait reset */
+ this->wait(mtd, FL_RESETING);
+
+ /* Restore system configuration 1 */
+ this->write_word(syscfg, this->base + ONENAND_REG_SYS_CFG1);
+
/* Check manufacturer ID */
if (onenand_check_maf(bram_maf_id))
return -ENXIO;
- /* Reset OneNAND to read default register values */
- this->write_word(ONENAND_CMD_RESET, this->base + ONENAND_BOOTRAM);
-
/* Read manufacturer and device IDs from Register */
maf_id = this->read_word(this->base + ONENAND_REG_MANUFACTURER_ID);
dev_id = this->read_word(this->base + ONENAND_REG_DEVICE_ID);
+ ver_id= this->read_word(this->base + ONENAND_REG_VERSION_ID);
/* Check OneNAND device */
if (maf_id != bram_maf_id || dev_id != bram_dev_id)
return -ENXIO;
/* Flash device information */
- onenand_print_device_info(dev_id);
+ onenand_print_device_info(dev_id, ver_id);
this->device_id = dev_id;
+ this->version_id = ver_id;
density = dev_id >> ONENAND_DEVICE_DENSITY_SHIFT;
this->chipsize = (16 << density) << 20;
@@ -1676,16 +1794,8 @@ static int onenand_probe(struct mtd_info *mtd)
mtd->size = this->chipsize;
- /* Version ID */
- version_id = this->read_word(this->base + ONENAND_REG_VERSION_ID);
- printk(KERN_DEBUG "OneNAND version = 0x%04x\n", version_id);
-
- /* Lock scheme */
- if (density <= ONENAND_DEVICE_DENSITY_512Mb &&
- !(version_id >> ONENAND_VERSION_PROCESS_SHIFT)) {
- printk(KERN_INFO "Lock scheme is Continues Lock\n");
- this->options |= ONENAND_CONT_LOCK;
- }
+ /* Check OneNAND lock scheme */
+ onenand_lock_scheme(mtd);
return 0;
}
@@ -1821,7 +1931,7 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
mtd->owner = THIS_MODULE;
/* Unlock whole block */
- mtd->unlock(mtd, 0x0, this->chipsize);
+ onenand_unlock_all(mtd);
return this->scan_bbt(mtd);
}
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
index 1b82bccd8c71..11d170afa9c3 100644
--- a/drivers/net/3c501.c
+++ b/drivers/net/3c501.c
@@ -496,7 +496,6 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
* el_interrupt:
* @irq: Interrupt number
* @dev_id: The 3c501 that burped
- * @regs: Register data (surplus to our requirements)
*
* Handle the ether interface interrupts. The 3c501 needs a lot more
* hand holding than most cards. In particular we get a transmit interrupt
@@ -515,7 +514,7 @@ static int el_start_xmit(struct sk_buff *skb, struct net_device *dev)
* TCP window.
*/
-static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t el_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h
index 39d332474750..c56a2c62f7de 100644
--- a/drivers/net/3c501.h
+++ b/drivers/net/3c501.h
@@ -7,7 +7,7 @@ static int el1_probe1(struct net_device *dev, int ioaddr);
static int el_open(struct net_device *dev);
static void el_timeout(struct net_device *dev);
static int el_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t el_interrupt(int irq, void *dev_id);
static void el_receive(struct net_device *dev);
static void el_reset(struct net_device *dev);
static int el1_close(struct net_device *dev);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index ab8230a68bea..458cb9cbe915 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -649,7 +649,7 @@ static void receive_packet(struct net_device *dev, int len)
*
******************************************************/
-static irqreturn_t elp_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
+static irqreturn_t elp_interrupt(int irq, void *dev_id)
{
int len;
int dlen;
diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c
index 8205a535c5b7..aa43563610ae 100644
--- a/drivers/net/3c507.c
+++ b/drivers/net/3c507.c
@@ -286,7 +286,7 @@ static unsigned short init_words[] = {
static int el16_probe1(struct net_device *dev, int ioaddr);
static int el16_open(struct net_device *dev);
static int el16_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t el16_interrupt(int irq, void *dev_id);
static void el16_rx(struct net_device *dev);
static int el16_close(struct net_device *dev);
static struct net_device_stats *el16_get_stats(struct net_device *dev);
@@ -543,7 +543,7 @@ static int el16_send_packet (struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static irqreturn_t el16_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t el16_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index 59c33925be62..f791bf026e51 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -191,7 +191,7 @@ static ushort id_read_eeprom(int index);
static ushort read_eeprom(int ioaddr, int index);
static int el3_open(struct net_device *dev);
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t el3_interrupt(int irq, void *dev_id);
static void update_stats(struct net_device *dev);
static struct net_device_stats *el3_get_stats(struct net_device *dev);
static int el3_rx(struct net_device *dev);
@@ -225,6 +225,7 @@ static struct eisa_device_id el3_eisa_ids[] = {
{ "TCM5095" },
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, el3_eisa_ids);
static int el3_eisa_probe (struct device *device);
@@ -909,18 +910,13 @@ el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The EL3 interrupt handler. */
static irqreturn_t
-el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+el3_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct el3_private *lp;
int ioaddr, status;
int i = max_interrupt_work;
- if (dev == NULL) {
- printk ("el3_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
lp = netdev_priv(dev);
spin_lock(&lp->lock);
@@ -1005,7 +1001,7 @@ el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void el3_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- el3_interrupt(dev->irq, dev, NULL);
+ el3_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index 91f2232e6050..c307ce66145c 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -373,8 +373,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
static int corkscrew_rx(struct net_device *dev);
static void corkscrew_timeout(struct net_device *dev);
static int boomerang_rx(struct net_device *dev);
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t corkscrew_interrupt(int irq, void *dev_id);
static int corkscrew_close(struct net_device *dev);
static void update_stats(int addr, struct net_device *dev);
static struct net_device_stats *corkscrew_get_stats(struct net_device *dev);
@@ -1116,8 +1115,7 @@ static int corkscrew_start_xmit(struct sk_buff *skb,
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t corkscrew_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t corkscrew_interrupt(int irq, void *dev_id)
{
/* Use the now-standard shared IRQ implementation. */
struct net_device *dev = dev_id;
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index cf8a0bc3bf34..91849469b4f4 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -180,7 +180,7 @@ sizeof(nop_cmd) = 8;
dev->name,__LINE__); \
elmc_id_reset586(); } } }
-static irqreturn_t elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr);
+static irqreturn_t elmc_interrupt(int irq, void *dev_id);
static int elmc_open(struct net_device *dev);
static int elmc_close(struct net_device *dev);
static int elmc_send_packet(struct sk_buff *, struct net_device *);
@@ -900,16 +900,13 @@ static void *alloc_rfa(struct net_device *dev, void *ptr)
*/
static irqreturn_t
-elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
+elmc_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
unsigned short stat;
struct priv *p;
- if (dev == NULL) {
- printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2));
- return IRQ_NONE;
- } else if (!netif_running(dev)) {
+ if (!netif_running(dev)) {
/* The 3c523 has this habit of generating interrupts during the
reset. I'm not sure if the ni52 has this same problem, but it's
really annoying if we haven't finished initializing it. I was
diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c
index 625e57dc3b4a..f4aca5386add 100644
--- a/drivers/net/3c527.c
+++ b/drivers/net/3c527.c
@@ -217,7 +217,7 @@ static int mc32_command(struct net_device *dev, u16 cmd, void *data, int le
static int mc32_open(struct net_device *dev);
static void mc32_timeout(struct net_device *dev);
static int mc32_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mc32_interrupt(int irq, void *dev_id);
static int mc32_close(struct net_device *dev);
static struct net_device_stats *mc32_get_stats(struct net_device *dev);
static void mc32_set_multicast_list(struct net_device *dev);
@@ -1316,7 +1316,7 @@ static void mc32_tx_ring(struct net_device *dev)
*
*/
-static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t mc32_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct mc32_local *lp;
@@ -1324,11 +1324,6 @@ static irqreturn_t mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
int rx_event = 0;
int tx_event = 0;
- if (dev == NULL) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
- return IRQ_NONE;
- }
-
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index af301f09d674..80bdcf846234 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -717,8 +717,8 @@ static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int vortex_rx(struct net_device *dev);
static int boomerang_rx(struct net_device *dev);
-static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t vortex_interrupt(int irq, void *dev_id);
+static irqreturn_t boomerang_interrupt(int irq, void *dev_id);
static int vortex_close(struct net_device *dev);
static void dump_tx_ring(struct net_device *dev);
static void update_stats(void __iomem *ioaddr, struct net_device *dev);
@@ -794,7 +794,7 @@ static void poll_vortex(struct net_device *dev)
unsigned long flags;
local_save_flags(flags);
local_irq_disable();
- (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev,NULL);
+ (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
local_irq_restore(flags);
}
#endif
@@ -851,6 +851,7 @@ static struct eisa_device_id vortex_eisa_ids[] = {
{ "TCM5970", CH_3C597 },
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
static int vortex_eisa_probe(struct device *device);
static int vortex_eisa_remove(struct device *device);
@@ -1848,9 +1849,9 @@ static void vortex_tx_timeout(struct net_device *dev)
unsigned long flags;
local_irq_save(flags);
if (vp->full_bus_master_tx)
- boomerang_interrupt(dev->irq, dev, NULL);
+ boomerang_interrupt(dev->irq, dev);
else
- vortex_interrupt(dev->irq, dev, NULL);
+ vortex_interrupt(dev->irq, dev);
local_irq_restore(flags);
}
}
@@ -2148,7 +2149,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
static irqreturn_t
-vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+vortex_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct vortex_private *vp = netdev_priv(dev);
@@ -2253,7 +2254,7 @@ handler_exit:
*/
static irqreturn_t
-boomerang_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+boomerang_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct vortex_private *vp = netdev_priv(dev);
diff --git a/drivers/net/7990.c b/drivers/net/7990.c
index db7b19a5cd59..7733697f7776 100644
--- a/drivers/net/7990.c
+++ b/drivers/net/7990.c
@@ -438,7 +438,7 @@ static int lance_tx (struct net_device *dev)
}
static irqreturn_t
-lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+lance_interrupt (int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct lance_private *lp = netdev_priv(dev);
@@ -674,7 +674,7 @@ void lance_poll(struct net_device *dev)
WRITERAP(lp, LE_CSR0);
WRITERDP(lp, LE_C0_STRT);
spin_unlock (&lp->devlock);
- lance_interrupt(dev->irq, dev, NULL);
+ lance_interrupt(dev->irq, dev);
}
#endif
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 5a4990ae3730..458dd9f830c4 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -631,8 +631,7 @@ rx_next:
return 1; /* not done */
}
-static irqreturn_t
-cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t cp_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct cp_private *cp;
@@ -696,7 +695,7 @@ cp_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
static void cp_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- cp_interrupt(dev->irq, dev, NULL);
+ cp_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index dbc5c0b1b96c..d02ed51abfcc 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -629,8 +629,7 @@ static int rtl8139_poll(struct net_device *dev, int *budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void rtl8139_poll_controller(struct net_device *dev);
#endif
-static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance);
static int rtl8139_close (struct net_device *dev);
static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *rtl8139_get_stats (struct net_device *dev);
@@ -2146,8 +2145,7 @@ static int rtl8139_poll(struct net_device *dev, int *budget)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct rtl8139_private *tp = netdev_priv(dev);
@@ -2219,7 +2217,7 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance,
static void rtl8139_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- rtl8139_interrupt(dev->irq, dev, NULL);
+ rtl8139_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index c9e4dca9d410..8236f26ffd46 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -357,7 +357,7 @@ static char init_setup[] =
static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
@@ -501,7 +501,7 @@ static void i596_display_data(struct net_device *dev)
#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-static irqreturn_t i596_error(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i596_error(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
#ifdef ENABLE_MVME16x_NET
@@ -1283,7 +1283,7 @@ out:
return ERR_PTR(err);
}
-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct i596_private *lp;
@@ -1294,7 +1294,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#ifdef ENABLE_BVME6000_NET
if (MACH_IS_BVME6000) {
if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {
- i596_error(irq, dev_id, regs);
+ i596_error(irq, dev_id);
return IRQ_HANDLED;
}
}
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
index 5b6b05ed8f3c..3d1c599ac3cb 100644
--- a/drivers/net/8390.c
+++ b/drivers/net/8390.c
@@ -299,7 +299,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* Slow phase with lock held.
*/
- disable_irq_nosync_lockdep(dev->irq);
+ disable_irq_nosync_lockdep_irqsave(dev->irq, &flags);
spin_lock(&ei_local->page_lock);
@@ -338,7 +338,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_stop_queue(dev);
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
- enable_irq_lockdep(dev->irq);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
ei_local->stat.tx_errors++;
return 1;
}
@@ -379,7 +379,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
outb_p(ENISR_ALL, e8390_base + EN0_IMR);
spin_unlock(&ei_local->page_lock);
- enable_irq_lockdep(dev->irq);
+ enable_irq_lockdep_irqrestore(dev->irq, &flags);
dev_kfree_skb (skb);
ei_local->stat.tx_bytes += send_length;
@@ -391,7 +391,6 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* ei_interrupt - handle the interrupts from an 8390
* @irq: interrupt number
* @dev_id: a pointer to the net_device
- * @regs: unused
*
* Handle the ether interface interrupts. We pull packets from
* the 8390 via the card specific functions and fire them at the networking
@@ -400,21 +399,15 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* needed.
*/
-irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t ei_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
long e8390_base;
int interrupts, nr_serviced = 0;
struct ei_device *ei_local;
- if (dev == NULL)
- {
- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
e8390_base = dev->base_addr;
- ei_local = (struct ei_device *) netdev_priv(dev);
+ ei_local = netdev_priv(dev);
/*
* Protect the irq test too.
@@ -506,7 +499,7 @@ irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
void ei_poll(struct net_device *dev)
{
disable_irq_lockdep(dev->irq);
- ei_interrupt(dev->irq, dev, NULL);
+ ei_interrupt(dev->irq, dev);
enable_irq_lockdep(dev->irq);
}
#endif
diff --git a/drivers/net/8390.h b/drivers/net/8390.h
index ca4eb0ccf8cf..f44f1220b3a5 100644
--- a/drivers/net/8390.h
+++ b/drivers/net/8390.h
@@ -35,7 +35,7 @@ extern void ei_poll(struct net_device *dev);
extern void NS8390_init(struct net_device *dev, int startp);
extern int ei_open(struct net_device *dev);
extern int ei_close(struct net_device *dev);
-extern irqreturn_t ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t ei_interrupt(int irq, void *dev_id);
extern struct net_device *__alloc_ei_netdev(int size);
static inline struct net_device *alloc_ei_netdev(void)
{
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 63154774c257..ab92cc794c64 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -24,6 +24,9 @@ config NETDEVICES
If unsure, say Y.
+# All the following symbols are dependent on NETDEVICES - do not repeat
+# that for each of the symbols.
+if NETDEVICES
config IFB
tristate "Intermediate Functional Block support"
@@ -2112,7 +2115,7 @@ config SKY2
depends on PCI && EXPERIMENTAL
select CRC32
---help---
- This driver supports Gigabit Ethernet adapters based on the the
+ This driver supports Gigabit Ethernet adapters based on the
Marvell Yukon 2 chipset:
Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/
88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21
@@ -2852,6 +2855,8 @@ config NETCONSOLE
If you want to log kernel messages over the network, enable this.
See <file:Documentation/networking/netconsole.txt> for details.
+endif #NETDEVICES
+
config NETPOLL
def_bool NETCONSOLE
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 9953201c670d..a67f5efc983f 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -165,7 +165,7 @@ static struct devprobe2 mca_probes[] __initdata = {
* look for EISA/PCI/MCA cards in addition to ISA cards).
*/
static struct devprobe2 isa_probes[] __initdata = {
-#ifdef CONFIG_HP100 /* ISA, EISA & PCI */
+#if defined(CONFIG_HP100) && defined(CONFIG_ISA) /* ISA, EISA */
{hp100_probe, 0},
#endif
#ifdef CONFIG_3C515
diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c
index 5f7258fea19d..d76548e75350 100644
--- a/drivers/net/a2065.c
+++ b/drivers/net/a2065.c
@@ -425,8 +425,7 @@ static int lance_tx (struct net_device *dev)
return 0;
}
-static irqreturn_t
-lance_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lance_interrupt (int irq, void *dev_id)
{
struct net_device *dev;
struct lance_private *lp;
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index a075246f6f43..33c6645455ae 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -163,11 +163,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
#define SET_NETDEV_DEV(net, pdev) do{} while(0)
#endif
-#if LINUX_VERSION_CODE >= 0x2051c
#define ace_sync_irq(irq) synchronize_irq(irq)
-#else
-#define ace_sync_irq(irq) synchronize_irq()
-#endif
#ifndef offset_in_page
#define offset_in_page(ptr) ((unsigned long)(ptr) & ~PAGE_MASK)
@@ -2148,7 +2144,7 @@ static inline void ace_tx_int(struct net_device *dev,
}
-static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t ace_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct ace_private *ap = netdev_priv(dev);
diff --git a/drivers/net/acenic.h b/drivers/net/acenic.h
index efb14b9f4d90..8ca8534d70bf 100644
--- a/drivers/net/acenic.h
+++ b/drivers/net/acenic.h
@@ -769,7 +769,7 @@ static int ace_init(struct net_device *dev);
static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
-static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ace_interrupt(int irq, void *dev_id);
static int ace_load_firmware(struct net_device *dev);
static int ace_open(struct net_device *dev);
static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev);
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index 28855a01ed7b..ef65e5917c8f 100644
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -1257,7 +1257,7 @@ static int amd8111e_calc_coalesce(struct net_device *dev)
/*
This is device interrupt function. It handles transmit, receive,link change and hardware timer interrupts.
*/
-static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t amd8111e_interrupt(int irq, void *dev_id)
{
struct net_device * dev = (struct net_device *) dev_id;
@@ -1336,7 +1336,7 @@ static void amd8111e_poll(struct net_device *dev)
unsigned long flags;
local_save_flags(flags);
local_irq_disable();
- amd8111e_interrupt(0, dev, NULL);
+ amd8111e_interrupt(0, dev);
local_irq_restore(flags);
}
#endif
diff --git a/drivers/net/apne.c b/drivers/net/apne.c
index 643b08cc7403..9164d8cd670e 100644
--- a/drivers/net/apne.c
+++ b/drivers/net/apne.c
@@ -88,7 +88,7 @@ static void apne_block_input(struct net_device *dev, int count,
struct sk_buff *skb, int ring_offset);
static void apne_block_output(struct net_device *dev, const int count,
const unsigned char *buf, const int start_page);
-static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t apne_interrupt(int irq, void *dev_id);
static int init_pcmcia(void);
@@ -543,7 +543,7 @@ apne_block_output(struct net_device *dev, int count,
return;
}
-static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t apne_interrupt(int irq, void *dev_id)
{
unsigned char pcmcia_intreq;
@@ -559,7 +559,7 @@ static irqreturn_t apne_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (ei_debug > 3)
printk("pcmcia intreq = %x\n", pcmcia_intreq);
pcmcia_disable_irq(); /* to get rid of the sti() within ei_interrupt */
- ei_interrupt(irq, dev_id, regs);
+ ei_interrupt(irq, dev_id);
pcmcia_ack_int(pcmcia_get_intreq());
pcmcia_enable_irq();
return IRQ_HANDLED;
diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c
index ae7f828344d9..cc1a27ed197f 100644
--- a/drivers/net/appletalk/cops.c
+++ b/drivers/net/appletalk/cops.c
@@ -188,7 +188,7 @@ static void cops_reset (struct net_device *dev, int sleep);
static void cops_load (struct net_device *dev);
static int cops_nodeid (struct net_device *dev, int nodeid);
-static irqreturn_t cops_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t cops_interrupt (int irq, void *dev_id);
static void cops_poll (unsigned long ltdev);
static void cops_timeout(struct net_device *dev);
static void cops_rx (struct net_device *dev);
@@ -721,7 +721,7 @@ static void cops_poll(unsigned long ltdev)
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
-static irqreturn_t cops_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t cops_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct cops_local *lp;
diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c
index 7f7dd450226a..b98592a8bac8 100644
--- a/drivers/net/appletalk/ipddp.c
+++ b/drivers/net/appletalk/ipddp.c
@@ -145,9 +145,7 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
/* Create the Extended DDP header */
ddp = (struct ddpehdr *)skb->data;
- ddp->deh_len = skb->len;
- ddp->deh_hops = 1;
- ddp->deh_pad = 0;
+ ddp->deh_len_hops = htons(skb->len + (1<<10));
ddp->deh_sum = 0;
/*
@@ -170,7 +168,6 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev)
ddp->deh_sport = 72;
*((__u8 *)(ddp+1)) = 22; /* ddp type = IP */
- *((__u16 *)ddp)=ntohs(*((__u16 *)ddp)); /* fix up length field */
skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */
diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c
index d5666c37cb0d..2ea44ce49810 100644
--- a/drivers/net/appletalk/ltpc.c
+++ b/drivers/net/appletalk/ltpc.c
@@ -790,7 +790,7 @@ static int sendup_buffer (struct net_device *dev)
/* the handler for the board interrupt */
static irqreturn_t
-ltpc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr)
+ltpc_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
index 5a95005253fa..4e91dab1f17f 100644
--- a/drivers/net/arcnet/arcnet.c
+++ b/drivers/net/arcnet/arcnet.c
@@ -752,7 +752,7 @@ static void arcnet_timeout(struct net_device *dev)
* interrupts. Establish which device needs attention, and call the correct
* chipset interrupt handler.
*/
-irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t arcnet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct arcnet_local *lp;
diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c
index 3aef3c10d56f..9dfc09b181c1 100644
--- a/drivers/net/ariadne.c
+++ b/drivers/net/ariadne.c
@@ -120,7 +120,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void ariadne_tx_timeout(struct net_device *dev);
static int ariadne_rx(struct net_device *dev);
static void ariadne_reset(struct net_device *dev);
-static irqreturn_t ariadne_interrupt(int irq, void *data, struct pt_regs *fp);
+static irqreturn_t ariadne_interrupt(int irq, void *data);
static int ariadne_close(struct net_device *dev);
static struct net_device_stats *ariadne_get_stats(struct net_device *dev);
#ifdef HAVE_MULTICAST
@@ -416,7 +416,7 @@ static inline void ariadne_reset(struct net_device *dev)
}
-static irqreturn_t ariadne_interrupt(int irq, void *data, struct pt_regs *fp)
+static irqreturn_t ariadne_interrupt(int irq, void *data)
{
struct net_device *dev = (struct net_device *)data;
volatile struct Am79C960 *lance = (struct Am79C960*)dev->base_addr;
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
index 09d5c3f26985..ddd12d44ff22 100644
--- a/drivers/net/arm/am79c961a.c
+++ b/drivers/net/arm/am79c961a.c
@@ -38,7 +38,7 @@
#include "am79c961a.h"
static irqreturn_t
-am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+am79c961_interrupt (int irq, void *dev_id);
static unsigned int net_debug = NET_DEBUG;
@@ -596,7 +596,7 @@ am79c961_tx(struct net_device *dev, struct dev_priv *priv)
}
static irqreturn_t
-am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+am79c961_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct dev_priv *priv = netdev_priv(dev);
diff --git a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h
index 6a49ac7f6d46..483009fe6ec2 100644
--- a/drivers/net/arm/am79c961a.h
+++ b/drivers/net/arm/am79c961a.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/net/am79c961.h
+ * linux/drivers/net/arm/am79c961a.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
diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c
index 95b28aa01f4f..b54b857e357e 100644
--- a/drivers/net/arm/at91_ether.c
+++ b/drivers/net/arm/at91_ether.c
@@ -196,7 +196,7 @@ static void update_linkspeed(struct net_device *dev, int silent)
/*
* Handle interrupts from the PHY
*/
-static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t at91ether_phy_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct at91_private *lp = (struct at91_private *) dev->priv;
@@ -888,7 +888,7 @@ static void at91ether_rx(struct net_device *dev)
/*
* MAC interrupt handler
*/
-static irqreturn_t at91ether_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t at91ether_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct at91_private *lp = (struct at91_private *) dev->priv;
@@ -947,7 +947,7 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add
return -ENOMEM;
dev->base_addr = AT91_VA_BASE_EMAC;
- dev->irq = AT91_ID_EMAC;
+ dev->irq = AT91RM9200_ID_EMAC;
SET_MODULE_OWNER(dev);
/* Install the interrupt handler */
diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c
index cef00744a9dc..127561c782fd 100644
--- a/drivers/net/arm/ep93xx_eth.c
+++ b/drivers/net/arm/ep93xx_eth.c
@@ -9,7 +9,6 @@
* (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -436,7 +435,7 @@ static void ep93xx_tx_complete(struct net_device *dev)
netif_wake_queue(dev);
}
-static irqreturn_t ep93xx_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ep93xx_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct ep93xx_priv *ep = netdev_priv(dev);
diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
index 312955d07b28..f3478a30e778 100644
--- a/drivers/net/arm/ether1.c
+++ b/drivers/net/arm/ether1.c
@@ -68,7 +68,7 @@ static unsigned int net_debug = NET_DEBUG;
static int ether1_open(struct net_device *dev);
static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ether1_interrupt(int irq, void *dev_id);
static int ether1_close(struct net_device *dev);
static struct net_device_stats *ether1_getstats(struct net_device *dev);
static void ether1_setmulticastlist(struct net_device *dev);
@@ -908,7 +908,7 @@ ether1_recv_done (struct net_device *dev)
}
static irqreturn_t
-ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+ether1_interrupt (int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
int status;
diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
index 081074180e62..84686c8a5bc2 100644
--- a/drivers/net/arm/ether3.c
+++ b/drivers/net/arm/ether3.c
@@ -81,7 +81,7 @@ static int ether3_rx(struct net_device *dev, unsigned int maxcnt);
static void ether3_tx(struct net_device *dev);
static int ether3_open (struct net_device *dev);
static int ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ether3_interrupt (int irq, void *dev_id);
static int ether3_close (struct net_device *dev);
static struct net_device_stats *ether3_getstats (struct net_device *dev);
static void ether3_setmulticastlist (struct net_device *dev);
@@ -568,7 +568,7 @@ ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
}
static irqreturn_t
-ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ether3_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
unsigned int status, handled = IRQ_NONE;
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index 4aeca11f3ee2..8620a5b470f5 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -161,7 +161,7 @@ static int at1700_probe1(struct net_device *dev, int ioaddr);
static int read_eeprom(long ioaddr, int location);
static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t net_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static int net_close(struct net_device *dev);
static struct net_device_stats *net_get_stats(struct net_device *dev);
@@ -648,8 +648,7 @@ static int net_send_packet (struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static irqreturn_t
-net_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
index 92b52138acad..4e3bf6a1f22c 100644
--- a/drivers/net/atari_bionet.c
+++ b/drivers/net/atari_bionet.c
@@ -220,7 +220,7 @@ gsend:
}
static irqreturn_t
-bionet_intr(int irq, void *data, struct pt_regs *fp) {
+bionet_intr(int irq, void *data) {
return IRQ_HANDLED;
}
diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
index a1026251b933..3b5436149286 100644
--- a/drivers/net/atari_pamsnet.c
+++ b/drivers/net/atari_pamsnet.c
@@ -163,7 +163,7 @@ static int pamsnet_close(struct net_device *dev);
static struct net_device_stats *net_get_stats(struct net_device *dev);
static void pamsnet_tick(unsigned long);
-static irqreturn_t pamsnet_intr(int irq, void *data, struct pt_regs *fp);
+static irqreturn_t pamsnet_intr(int irq, void *data);
static DEFINE_TIMER(pamsnet_timer, pamsnet_tick, 0, 0);
@@ -494,7 +494,6 @@ static irqreturn_t
pamsnet_intr(irq, data, fp)
int irq;
void *data;
- struct pt_regs *fp;
{
return IRQ_HANDLED;
}
diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c
index b6570ca6ada7..d79489e46249 100644
--- a/drivers/net/atarilance.c
+++ b/drivers/net/atarilance.c
@@ -344,7 +344,7 @@ static unsigned long lance_probe1( struct net_device *dev, struct lance_addr
static int lance_open( struct net_device *dev );
static void lance_init_ring( struct net_device *dev );
static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
+static irqreturn_t lance_interrupt( int irq, void *dev_id );
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
static struct net_device_stats *lance_get_stats( struct net_device *dev );
@@ -866,7 +866,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
/* The LANCE interrupt handler. */
-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t lance_interrupt( int irq, void *dev_id )
{
struct net_device *dev = dev_id;
struct lance_private *lp;
diff --git a/drivers/net/atp.c b/drivers/net/atp.c
index f2c8e0d5497b..2d306fcb7f36 100644
--- a/drivers/net/atp.c
+++ b/drivers/net/atp.c
@@ -203,7 +203,7 @@ static void hardware_init(struct net_device *dev);
static void write_packet(long ioaddr, int length, unsigned char *packet, int pad, int mode);
static void trigger_send(long ioaddr, int length);
static int atp_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t atp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t atp_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static void read_block(long ioaddr, int length, unsigned char *buffer, int data_mode);
static int net_close(struct net_device *dev);
@@ -596,20 +596,15 @@ static int atp_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static irqreturn_t
-atp_interrupt(int irq, void *dev_instance, struct pt_regs * regs)
+static irqreturn_t atp_interrupt(int irq, void *dev_instance)
{
- struct net_device *dev = (struct net_device *)dev_instance;
+ struct net_device *dev = dev_instance;
struct net_local *lp;
long ioaddr;
static int num_tx_since_rx;
int boguscount = max_interrupt_work;
int handled = 0;
- if (dev == NULL) {
- printk(KERN_ERR "ATP_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
ioaddr = dev->base_addr;
lp = netdev_priv(dev);
diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c
index ac33b1b9cf4a..4873dc610d22 100644
--- a/drivers/net/au1000_eth.c
+++ b/drivers/net/au1000_eth.c
@@ -89,7 +89,7 @@ static int au1000_open(struct net_device *);
static int au1000_close(struct net_device *);
static int au1000_tx(struct sk_buff *, struct net_device *);
static int au1000_rx(struct net_device *);
-static irqreturn_t au1000_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t au1000_interrupt(int, void *);
static void au1000_tx_timeout(struct net_device *);
static void set_rx_mode(struct net_device *);
static struct net_device_stats *au1000_get_stats(struct net_device *);
@@ -1253,7 +1253,7 @@ static int au1000_rx(struct net_device *dev)
/*
* Au1000 interrupt service routine.
*/
-static irqreturn_t au1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t au1000_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index e891ea2ecc3c..1ec217433b4c 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -896,7 +896,7 @@ static int b44_poll(struct net_device *netdev, int *budget)
return (done ? 0 : 1);
}
-static irqreturn_t b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t b44_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct b44 *bp = netdev_priv(dev);
@@ -1461,7 +1461,7 @@ out:
static void b44_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- b44_interrupt(dev->irq, dev, NULL);
+ b44_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
@@ -1706,14 +1706,15 @@ static void __b44_set_rx_mode(struct net_device *dev)
__b44_set_mac_addr(bp);
- if (dev->flags & IFF_ALLMULTI)
+ if ((dev->flags & IFF_ALLMULTI) ||
+ (dev->mc_count > B44_MCAST_TABLE_SIZE))
val |= RXCONFIG_ALLMULTI;
else
i = __b44_load_mcast(bp, dev);
- for (; i < 64; i++) {
+ for (; i < 64; i++)
__b44_cam_write(bp, zero, i);
- }
+
bw32(bp, B44_RXCONFIG, val);
val = br32(bp, B44_CAM_CTRL);
bw32(bp, B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
@@ -2055,7 +2056,7 @@ static int b44_read_eeprom(struct b44 *bp, u8 *data)
u16 *ptr = (u16 *) data;
for (i = 0; i < 128; i += 2)
- ptr[i / 2] = readw(bp->regs + 4096 + i);
+ ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
return 0;
}
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 4adfe7b77031..4528ce9c4e43 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -152,9 +152,9 @@ static void bmac_init_chip(struct net_device *dev);
static void bmac_init_registers(struct net_device *dev);
static void bmac_enable_and_reset_chip(struct net_device *dev);
static int bmac_set_address(struct net_device *dev, void *addr);
-static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t bmac_misc_intr(int irq, void *dev_id);
+static irqreturn_t bmac_txdma_intr(int irq, void *dev_id);
+static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id);
static void bmac_set_timeout(struct net_device *dev);
static void bmac_tx_timeout(unsigned long data);
static int bmac_output(struct sk_buff *skb, struct net_device *dev);
@@ -688,7 +688,7 @@ static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev)
static int rxintcount;
-static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct bmac_data *bp = netdev_priv(dev);
@@ -765,7 +765,7 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
static int txintcount;
-static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bmac_txdma_intr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct bmac_data *bp = netdev_priv(dev);
@@ -1082,7 +1082,7 @@ static void bmac_set_multicast(struct net_device *dev)
static int miscintcount;
-static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bmac_misc_intr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct bmac_data *bp = netdev_priv(dev);
@@ -1091,7 +1091,7 @@ static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
XXDEBUG(("bmac_misc_intr\n"));
}
/* XXDEBUG(("bmac_misc_intr, status=%#08x\n", status)); */
- /* bmac_txdma_intr_inner(irq, dev_id, regs); */
+ /* bmac_txdma_intr_inner(irq, dev_id); */
/* if (status & FrameReceived) bp->stats.rx_dropped++; */
if (status & RxErrorMask) bp->stats.rx_errors++;
if (status & RxCRCCntExp) bp->stats.rx_crc_errors++;
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 7fcf015021ec..01b76d3aa42f 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -56,8 +56,8 @@
#define DRV_MODULE_NAME "bnx2"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "1.4.44"
-#define DRV_MODULE_RELDATE "August 10, 2006"
+#define DRV_MODULE_VERSION "1.4.45"
+#define DRV_MODULE_RELDATE "September 29, 2006"
#define RUN_AT(x) (jiffies + (x))
@@ -1888,7 +1888,7 @@ next_rx:
* is that the MSI interrupt is always serviced.
*/
static irqreturn_t
-bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
+bnx2_msi(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct bnx2 *bp = netdev_priv(dev);
@@ -1908,7 +1908,7 @@ bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
}
static irqreturn_t
-bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+bnx2_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct bnx2 *bp = netdev_priv(dev);
@@ -5554,7 +5554,7 @@ poll_bnx2(struct net_device *dev)
struct bnx2 *bp = netdev_priv(dev);
disable_irq(bp->pdev->irq);
- bnx2_interrupt(bp->pdev->irq, dev, NULL);
+ bnx2_interrupt(bp->pdev->irq, dev);
enable_irq(bp->pdev->irq);
}
#endif
@@ -5805,6 +5805,34 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
bp->cmd_ticks_int = bp->cmd_ticks;
}
+ /* Disable MSI on 5706 if AMD 8132 bridge is found.
+ *
+ * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
+ * with byte enables disabled on the unused 32-bit word. This is legal
+ * but causes problems on the AMD 8132 which will eventually stop
+ * responding after a while.
+ *
+ * AMD believes this incompatibility is unique to the 5706, and
+ * prefers to locally disable MSI rather than globally disabling it
+ * using pci_msi_quirk.
+ */
+ if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
+ struct pci_dev *amd_8132 = NULL;
+
+ while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_8132_BRIDGE,
+ amd_8132))) {
+ u8 rev;
+
+ pci_read_config_byte(amd_8132, PCI_REVISION_ID, &rev);
+ if (rev >= 0x10 && rev <= 0x13) {
+ disable_msi = 1;
+ pci_dev_put(amd_8132);
+ break;
+ }
+ }
+ }
+
bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
bp->req_line_speed = 0;
if (bp->phy_flags & PHY_SERDES_FLAG) {
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 6a407070c2e8..3fb354d9c515 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -85,6 +85,7 @@
#define AD_LINK_SPEED_BITMASK_10MBPS 0x2
#define AD_LINK_SPEED_BITMASK_100MBPS 0x4
#define AD_LINK_SPEED_BITMASK_1000MBPS 0x8
+#define AD_LINK_SPEED_BITMASK_10000MBPS 0x10
//endalloun
// compare MAC addresses
@@ -99,7 +100,7 @@ static u16 __get_link_speed(struct port *port);
static u8 __get_duplex(struct port *port);
static inline void __initialize_port_locks(struct port *port);
//conversions
-static void __ntohs_lacpdu(struct lacpdu *lacpdu);
+static void __htons_lacpdu(struct lacpdu *lacpdu);
static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
@@ -330,7 +331,8 @@ static inline void __release_rx_machine_lock(struct port *port)
* 0,
* %AD_LINK_SPEED_BITMASK_10MBPS,
* %AD_LINK_SPEED_BITMASK_100MBPS,
- * %AD_LINK_SPEED_BITMASK_1000MBPS
+ * %AD_LINK_SPEED_BITMASK_1000MBPS,
+ * %AD_LINK_SPEED_BITMASK_10000MBPS
*/
static u16 __get_link_speed(struct port *port)
{
@@ -357,6 +359,10 @@ static u16 __get_link_speed(struct port *port)
speed = AD_LINK_SPEED_BITMASK_1000MBPS;
break;
+ case SPEED_10000:
+ speed = AD_LINK_SPEED_BITMASK_10000MBPS;
+ break;
+
default:
speed = 0; // unknown speed value from ethtool. shouldn't happen
break;
@@ -414,23 +420,23 @@ static inline void __initialize_port_locks(struct port *port)
//conversions
/**
- * __ntohs_lacpdu - convert the contents of a LACPDU to host byte order
+ * __htons_lacpdu - convert the contents of a LACPDU to network byte order
* @lacpdu: the speicifed lacpdu
*
* For each multi-byte field in the lacpdu, convert its content
*/
-static void __ntohs_lacpdu(struct lacpdu *lacpdu)
+static void __htons_lacpdu(struct lacpdu *lacpdu)
{
if (lacpdu) {
- lacpdu->actor_system_priority = ntohs(lacpdu->actor_system_priority);
- lacpdu->actor_key = ntohs(lacpdu->actor_key);
- lacpdu->actor_port_priority = ntohs(lacpdu->actor_port_priority);
- lacpdu->actor_port = ntohs(lacpdu->actor_port);
- lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority);
- lacpdu->partner_key = ntohs(lacpdu->partner_key);
- lacpdu->partner_port_priority = ntohs(lacpdu->partner_port_priority);
- lacpdu->partner_port = ntohs(lacpdu->partner_port);
- lacpdu->collector_max_delay = ntohs(lacpdu->collector_max_delay);
+ lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority);
+ lacpdu->actor_key = htons(lacpdu->actor_key);
+ lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority);
+ lacpdu->actor_port = htons(lacpdu->actor_port);
+ lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
+ lacpdu->partner_key = htons(lacpdu->partner_key);
+ lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority);
+ lacpdu->partner_port = htons(lacpdu->partner_port);
+ lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay);
}
}
@@ -490,11 +496,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// record the new parameter values for the partner operational
- port->partner_oper_port_number = lacpdu->actor_port;
- port->partner_oper_port_priority = lacpdu->actor_port_priority;
+ port->partner_oper_port_number = ntohs(lacpdu->actor_port);
+ port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority);
port->partner_oper_system = lacpdu->actor_system;
- port->partner_oper_system_priority = lacpdu->actor_system_priority;
- port->partner_oper_key = lacpdu->actor_key;
+ port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority);
+ port->partner_oper_key = ntohs(lacpdu->actor_key);
// zero partener's lase states
port->partner_oper_port_state = 0;
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
@@ -561,11 +567,11 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// check if any parameter is different
- if ((lacpdu->actor_port != port->partner_oper_port_number) ||
- (lacpdu->actor_port_priority != port->partner_oper_port_priority) ||
+ if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) ||
+ (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) ||
MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
- (lacpdu->actor_system_priority != port->partner_oper_system_priority) ||
- (lacpdu->actor_key != port->partner_oper_key) ||
+ (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) ||
+ (ntohs(lacpdu->actor_key) != port->partner_oper_key) ||
((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
) {
// update the state machine Selected variable
@@ -628,11 +634,11 @@ static void __choose_matched(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// check if all parameters are alike
- if (((lacpdu->partner_port == port->actor_port_number) &&
- (lacpdu->partner_port_priority == port->actor_port_priority) &&
+ if (((ntohs(lacpdu->partner_port) == port->actor_port_number) &&
+ (ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) &&
!MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
- (lacpdu->partner_system_priority == port->actor_system_priority) &&
- (lacpdu->partner_key == port->actor_oper_port_key) &&
+ (ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) &&
+ (ntohs(lacpdu->partner_key) == port->actor_oper_port_key) &&
((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
// or this is individual link(aggregation == FALSE)
((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
@@ -662,11 +668,11 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
// validate lacpdu and port
if (lacpdu && port) {
// check if any parameter is different
- if ((lacpdu->partner_port != port->actor_port_number) ||
- (lacpdu->partner_port_priority != port->actor_port_priority) ||
+ if ((ntohs(lacpdu->partner_port) != port->actor_port_number) ||
+ (ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) ||
MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) ||
- (lacpdu->partner_system_priority != port->actor_system_priority) ||
- (lacpdu->partner_key != port->actor_oper_port_key) ||
+ (ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) ||
+ (ntohs(lacpdu->partner_key) != port->actor_oper_port_key) ||
((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) ||
((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) ||
((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
@@ -775,6 +781,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
case AD_LINK_SPEED_BITMASK_1000MBPS:
bandwidth = aggregator->num_of_ports * 1000;
break;
+ case AD_LINK_SPEED_BITMASK_10000MBPS:
+ bandwidth = aggregator->num_of_ports * 10000;
+ break;
default:
bandwidth=0; // to silent the compilor ....
}
@@ -847,7 +856,7 @@ static inline void __update_lacpdu_from_port(struct port *port)
*/
/* Convert all non u8 parameters to Big Endian for transmit */
- __ntohs_lacpdu(lacpdu);
+ __htons_lacpdu(lacpdu);
}
//////////////////////////////////////////////////////////////////////////////////////
@@ -2171,7 +2180,6 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
switch (lacpdu->subtype) {
case AD_TYPE_LACPDU:
- __ntohs_lacpdu(lacpdu);
dprintk("Received LACPDU on port %d\n", port->actor_port_number);
ad_rx_machine(lacpdu, port);
break;
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index e83bc825f6af..32923162179e 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -1433,7 +1433,7 @@ void bond_alb_monitor(struct bonding *bond)
* write lock to protect from other code that also
* sets the promiscuity.
*/
- write_lock(&bond->curr_slave_lock);
+ write_lock_bh(&bond->curr_slave_lock);
if (bond_info->primary_is_promisc &&
(++bond_info->rlb_promisc_timeout_counter >= RLB_PROMISC_TIMEOUT)) {
@@ -1448,7 +1448,7 @@ void bond_alb_monitor(struct bonding *bond)
bond_info->primary_is_promisc = 0;
}
- write_unlock(&bond->curr_slave_lock);
+ write_unlock_bh(&bond->curr_slave_lock);
if (bond_info->rlb_rebalance) {
bond_info->rlb_rebalance = 0;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 850aae21a2fe..c0bbddae4ec4 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -96,6 +96,7 @@ static char *lacp_rate = NULL;
static char *xmit_hash_policy = NULL;
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
+static char *arp_validate = NULL;
struct bond_params bonding_defaults;
module_param(max_bonds, int, 0);
@@ -127,6 +128,8 @@ module_param(arp_interval, int, 0);
MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
module_param_array(arp_ip_target, charp, NULL, 0);
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
+module_param(arp_validate, charp, 0);
+MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
/*----------------------------- Global variables ----------------------------*/
@@ -170,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[] = {
{ NULL, -1},
};
+struct bond_parm_tbl arp_validate_tbl[] = {
+{ "none", BOND_ARP_VALIDATE_NONE},
+{ "active", BOND_ARP_VALIDATE_ACTIVE},
+{ "backup", BOND_ARP_VALIDATE_BACKUP},
+{ "all", BOND_ARP_VALIDATE_ALL},
+{ NULL, -1},
+};
+
/*-------------------------- Forward declarations ---------------------------*/
static void bond_send_gratuitous_arp(struct bonding *bond);
@@ -638,6 +649,7 @@ verify:
case SPEED_10:
case SPEED_100:
case SPEED_1000:
+ case SPEED_10000:
break;
default:
return -1;
@@ -1210,10 +1222,14 @@ static int bond_compute_features(struct bonding *bond)
unsigned long features = BOND_INTERSECT_FEATURES;
struct slave *slave;
struct net_device *bond_dev = bond->dev;
+ unsigned short max_hard_header_len = ETH_HLEN;
int i;
- bond_for_each_slave(bond, slave, i)
+ bond_for_each_slave(bond, slave, i) {
features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
+ if (slave->dev->hard_header_len > max_hard_header_len)
+ max_hard_header_len = slave->dev->hard_header_len;
+ }
if ((features & NETIF_F_SG) &&
!(features & NETIF_F_ALL_CSUM))
@@ -1231,6 +1247,7 @@ static int bond_compute_features(struct bonding *bond)
features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
bond_dev->features = features;
+ bond_dev->hard_header_len = max_hard_header_len;
return 0;
}
@@ -1365,6 +1382,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
}
new_slave->dev = slave_dev;
+ slave_dev->priv_flags |= IFF_BONDING;
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
@@ -1417,6 +1435,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
bond_compute_features(bond);
+ new_slave->last_arp_rx = jiffies;
+
if (bond->params.miimon && !bond->params.use_carrier) {
link_reporting = bond_check_dev_link(bond, slave_dev, 1);
@@ -1493,29 +1513,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
switch (bond->params.mode) {
case BOND_MODE_ACTIVEBACKUP:
- /* if we're in active-backup mode, we need one and
- * only one active interface. The backup interfaces
- * will have their SLAVE_INACTIVE flag set because we
- * need them to be drop all packets. Thus, since we
- * guarantee that curr_active_slave always point to
- * the last usable interface, we just have to verify
- * this interface's flag.
- */
- if (((!bond->curr_active_slave) ||
- (bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
- (new_slave->link != BOND_LINK_DOWN)) {
- /* first slave or no active slave yet, and this link
- is OK, so make this interface the active one */
- bond_change_active_slave(bond, new_slave);
- printk(KERN_INFO DRV_NAME
- ": %s: first active interface up!\n",
- bond->dev->name);
- netif_carrier_on(bond->dev);
-
- } else {
- dprintk("This is just a backup slave\n");
- bond_set_slave_inactive_flags(new_slave);
- }
+ bond_set_slave_inactive_flags(new_slave);
+ bond_select_active_slave(bond);
break;
case BOND_MODE_8023AD:
/* in 802.3ad mode, the internal mechanism
@@ -1778,7 +1777,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
dev_set_mac_address(slave_dev, &addr);
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
- IFF_SLAVE_INACTIVE);
+ IFF_SLAVE_INACTIVE | IFF_BONDING |
+ IFF_SLAVE_NEEDARP);
kfree(slave);
@@ -2252,7 +2252,7 @@ static u32 bond_glean_dev_ip(struct net_device *dev)
{
struct in_device *idev;
struct in_ifaddr *ifa;
- u32 addr = 0;
+ __be32 addr = 0;
if (!dev)
return 0;
@@ -2291,6 +2291,25 @@ static int bond_has_ip(struct bonding *bond)
return 0;
}
+static int bond_has_this_ip(struct bonding *bond, u32 ip)
+{
+ struct vlan_entry *vlan, *vlan_next;
+
+ if (ip == bond->master_ip)
+ return 1;
+
+ if (list_empty(&bond->vlan_list))
+ return 0;
+
+ list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+ vlan_list) {
+ if (ip == vlan->vlan_ip)
+ return 1;
+ }
+
+ return 0;
+}
+
/*
* We go to the (large) trouble of VLAN tagging ARP frames because
* switches in VLAN mode (especially if ports are configured as
@@ -2429,6 +2448,93 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
}
}
+static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
+{
+ int i;
+ u32 *targets = bond->params.arp_targets;
+
+ targets = bond->params.arp_targets;
+ for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
+ dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] "
+ "%u.%u.%u.%u bhti(tip) %d\n",
+ NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]),
+ bond_has_this_ip(bond, tip));
+ if (sip == targets[i]) {
+ if (bond_has_this_ip(bond, tip))
+ slave->last_arp_rx = jiffies;
+ return;
+ }
+ }
+}
+
+static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
+{
+ struct arphdr *arp;
+ struct slave *slave;
+ struct bonding *bond;
+ unsigned char *arp_ptr;
+ u32 sip, tip;
+
+ if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
+ goto out;
+
+ bond = dev->priv;
+ read_lock(&bond->lock);
+
+ dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
+ bond->dev->name, skb->dev ? skb->dev->name : "NULL",
+ orig_dev ? orig_dev->name : "NULL");
+
+ slave = bond_get_slave_by_dev(bond, orig_dev);
+ if (!slave || !slave_do_arp_validate(bond, slave))
+ goto out_unlock;
+
+ /* ARP header, plus 2 device addresses, plus 2 IP addresses. */
+ if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
+ (2 * dev->addr_len) +
+ (2 * sizeof(u32)))))
+ goto out_unlock;
+
+ arp = skb->nh.arph;
+ if (arp->ar_hln != dev->addr_len ||
+ skb->pkt_type == PACKET_OTHERHOST ||
+ skb->pkt_type == PACKET_LOOPBACK ||
+ arp->ar_hrd != htons(ARPHRD_ETHER) ||
+ arp->ar_pro != htons(ETH_P_IP) ||
+ arp->ar_pln != 4)
+ goto out_unlock;
+
+ arp_ptr = (unsigned char *)(arp + 1);
+ arp_ptr += dev->addr_len;
+ memcpy(&sip, arp_ptr, 4);
+ arp_ptr += 4 + dev->addr_len;
+ memcpy(&tip, arp_ptr, 4);
+
+ dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u"
+ " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name,
+ slave->state, bond->params.arp_validate,
+ slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip));
+
+ /*
+ * Backup slaves won't see the ARP reply, but do come through
+ * here for each ARP probe (so we swap the sip/tip to validate
+ * the probe). In a "redundant switch, common router" type of
+ * configuration, the ARP probe will (hopefully) travel from
+ * the active, through one switch, the router, then the other
+ * switch before reaching the backup.
+ */
+ if (slave->state == BOND_STATE_ACTIVE)
+ bond_validate_arp(bond, slave, sip, tip);
+ else
+ bond_validate_arp(bond, slave, tip, sip);
+
+out_unlock:
+ read_unlock(&bond->lock);
+out:
+ dev_kfree_skb(skb);
+ return NET_RX_SUCCESS;
+}
+
/*
* this function is called regularly to monitor each slave's link
* ensuring that traffic is being sent and received when arp monitoring
@@ -2593,7 +2699,8 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
*/
bond_for_each_slave(bond, slave, i) {
if (slave->link != BOND_LINK_UP) {
- if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) {
+ if ((jiffies - slave_last_rx(bond, slave)) <=
+ delta_in_ticks) {
slave->link = BOND_LINK_UP;
@@ -2638,7 +2745,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
if ((slave != bond->curr_active_slave) &&
(!bond->current_arp_slave) &&
- (((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
+ (((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) &&
bond_has_ip(bond))) {
/* a backup slave has gone down; three times
* the delta allows the current slave to be
@@ -2685,7 +2792,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
* if it is up and needs to take over as the curr_active_slave
*/
if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
- (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
+ (((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) &&
bond_has_ip(bond))) &&
((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
@@ -2950,7 +3057,7 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave
seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
seq_printf(seq, "MII Status: %s\n",
(slave->link == BOND_LINK_UP) ? "up" : "down");
- seq_printf(seq, "Link Failure Count: %d\n",
+ seq_printf(seq, "Link Failure Count: %u\n",
slave->link_failure_count);
seq_printf(seq,
@@ -3210,6 +3317,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
(event_dev ? event_dev->name : "None"),
event);
+ if (!(event_dev->priv_flags & IFF_BONDING))
+ return NOTIFY_DONE;
+
if (event_dev->flags & IFF_MASTER) {
dprintk("IFF_MASTER\n");
return bond_master_netdev_event(event, event_dev);
@@ -3305,6 +3415,21 @@ static void bond_unregister_lacpdu(struct bonding *bond)
dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
}
+void bond_register_arp(struct bonding *bond)
+{
+ struct packet_type *pt = &bond->arp_mon_pt;
+
+ pt->type = htons(ETH_P_ARP);
+ pt->dev = NULL; /*bond->dev;XXX*/
+ pt->func = bond_arp_rcv;
+ dev_add_pack(pt);
+}
+
+void bond_unregister_arp(struct bonding *bond)
+{
+ dev_remove_pack(&bond->arp_mon_pt);
+}
+
/*---------------------------- Hashing Policies -----------------------------*/
/*
@@ -3391,6 +3516,9 @@ static int bond_open(struct net_device *bond_dev)
} else {
arp_timer->function = (void *)&bond_loadbalance_arp_mon;
}
+ if (bond->params.arp_validate)
+ bond_register_arp(bond);
+
add_timer(arp_timer);
}
@@ -3418,9 +3546,11 @@ static int bond_close(struct net_device *bond_dev)
bond_unregister_lacpdu(bond);
}
+ if (bond->params.arp_validate)
+ bond_unregister_arp(bond);
+
write_lock_bh(&bond->lock);
- bond_mc_list_destroy(bond);
/* signal timers not to re-arm */
bond->kill_timers = 1;
@@ -3451,8 +3581,6 @@ static int bond_close(struct net_device *bond_dev)
break;
}
- /* Release the bonded slaves */
- bond_release_all(bond_dev);
if ((bond->params.mode == BOND_MODE_TLB) ||
(bond->params.mode == BOND_MODE_ALB)) {
@@ -4179,6 +4307,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
/* Initialize the device options */
bond_dev->tx_queue_len = 0;
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
+ bond_dev->priv_flags |= IFF_BONDING;
/* At first, we block adding VLANs. That's the only way to
* prevent problems that occur when adding VLANs over an
@@ -4237,6 +4366,9 @@ static void bond_free_all(void)
list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
struct net_device *bond_dev = bond->dev;
+ bond_mc_list_destroy(bond);
+ /* Release the bonded slaves */
+ bond_release_all(bond_dev);
unregister_netdevice(bond_dev);
bond_deinit(bond_dev);
}
@@ -4270,6 +4402,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
static int bond_check_params(struct bond_params *params)
{
+ int arp_validate_value;
+
/*
* Convert string parameters.
*/
@@ -4473,6 +4607,29 @@ static int bond_check_params(struct bond_params *params)
arp_interval = 0;
}
+ if (arp_validate) {
+ if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
+ printk(KERN_ERR DRV_NAME
+ ": arp_validate only supported in active-backup mode\n");
+ return -EINVAL;
+ }
+ if (!arp_interval) {
+ printk(KERN_ERR DRV_NAME
+ ": arp_validate requires arp_interval\n");
+ return -EINVAL;
+ }
+
+ arp_validate_value = bond_parse_parm(arp_validate,
+ arp_validate_tbl);
+ if (arp_validate_value == -1) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: invalid arp_validate \"%s\"\n",
+ arp_validate == NULL ? "NULL" : arp_validate);
+ return -EINVAL;
+ }
+ } else
+ arp_validate_value = 0;
+
if (miimon) {
printk(KERN_INFO DRV_NAME
": MII link monitoring set to %d ms\n",
@@ -4481,8 +4638,10 @@ static int bond_check_params(struct bond_params *params)
int i;
printk(KERN_INFO DRV_NAME
- ": ARP monitoring set to %d ms with %d target(s):",
- arp_interval, arp_ip_count);
+ ": ARP monitoring set to %d ms, validate %s, with %d target(s):",
+ arp_interval,
+ arp_validate_tbl[arp_validate_value].modename,
+ arp_ip_count);
for (i = 0; i < arp_ip_count; i++)
printk (" %s", arp_ip_target[i]);
@@ -4516,6 +4675,7 @@ static int bond_check_params(struct bond_params *params)
params->xmit_policy = xmit_hashtype;
params->miimon = miimon;
params->arp_interval = arp_interval;
+ params->arp_validate = arp_validate_value;
params->updelay = updelay;
params->downdelay = downdelay;
params->use_carrier = use_carrier;
diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c
index cfe4dc3a93a3..ced9ed8f995a 100644
--- a/drivers/net/bonding/bond_sysfs.c
+++ b/drivers/net/bonding/bond_sysfs.c
@@ -51,6 +51,7 @@ extern struct bond_params bonding_defaults;
extern struct bond_parm_tbl bond_mode_tbl[];
extern struct bond_parm_tbl bond_lacp_tbl[];
extern struct bond_parm_tbl xmit_hashtype_tbl[];
+extern struct bond_parm_tbl arp_validate_tbl[];
static int expected_refcount = -1;
static struct class *netdev_class;
@@ -503,6 +504,53 @@ out:
static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
/*
+ * Show and set arp_validate.
+ */
+static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
+{
+ struct bonding *bond = to_bond(cd);
+
+ return sprintf(buf, "%s %d\n",
+ arp_validate_tbl[bond->params.arp_validate].modename,
+ bond->params.arp_validate) + 1;
+}
+
+static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
+{
+ int new_value;
+ struct bonding *bond = to_bond(cd);
+
+ new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
+ if (new_value < 0) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: Ignoring invalid arp_validate value %s\n",
+ bond->dev->name, buf);
+ return -EINVAL;
+ }
+ if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
+ printk(KERN_ERR DRV_NAME
+ ": %s: arp_validate only supported in active-backup mode.\n",
+ bond->dev->name);
+ return -EINVAL;
+ }
+ printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n",
+ bond->dev->name, arp_validate_tbl[new_value].modename,
+ new_value);
+
+ if (!bond->params.arp_validate && new_value) {
+ bond_register_arp(bond);
+ } else if (bond->params.arp_validate && !new_value) {
+ bond_unregister_arp(bond);
+ }
+
+ bond->params.arp_validate = new_value;
+
+ return count;
+}
+
+static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+
+/*
* Show and set the arp timer interval. There are two tricky bits
* here. First, if ARP monitoring is activated, then we must disable
* MII monitoring. Second, if the ARP timer isn't running, we must
@@ -914,6 +962,11 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si
"ARP monitoring. Disabling ARP monitoring...\n",
bond->dev->name);
bond->params.arp_interval = 0;
+ if (bond->params.arp_validate) {
+ bond_unregister_arp(bond);
+ bond->params.arp_validate =
+ BOND_ARP_VALIDATE_NONE;
+ }
/* Kill ARP timer, else it brings bond's link down */
if (bond->mii_timer.function) {
printk(KERN_INFO DRV_NAME
@@ -1093,7 +1146,7 @@ static ssize_t bonding_store_active_slave(struct class_device *cd, const char *b
strlen(slave->dev->name)) == 0) {
old_active = bond->curr_active_slave;
new_active = slave;
- if (new_active && (new_active == old_active)) {
+ if (new_active == old_active) {
/* do nothing */
printk(KERN_INFO DRV_NAME
": %s: %s is already the current active slave.\n",
@@ -1273,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, N
static struct attribute *per_bond_attrs[] = {
&class_device_attr_slaves.attr,
&class_device_attr_mode.attr,
+ &class_device_attr_arp_validate.attr,
&class_device_attr_arp_interval.attr,
&class_device_attr_arp_ip_target.attr,
&class_device_attr_downdelay.attr,
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 0bdfe2c71453..dc434fb6da85 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -22,8 +22,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "3.0.3"
-#define DRV_RELDATE "March 23, 2006"
+#define DRV_VERSION "3.1.1"
+#define DRV_RELDATE "September 26, 2006"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -126,6 +126,7 @@ struct bond_params {
int xmit_policy;
int miimon;
int arp_interval;
+ int arp_validate;
int use_carrier;
int updelay;
int downdelay;
@@ -149,8 +150,9 @@ struct slave {
struct net_device *dev; /* first - useful for panic debug */
struct slave *next;
struct slave *prev;
- s16 delay;
+ int delay;
u32 jiffies;
+ u32 last_arp_rx;
s8 link; /* one of BOND_LINK_XXXX */
s8 state; /* one of BOND_STATE_XXXX */
u32 original_flags;
@@ -198,6 +200,7 @@ struct bonding {
struct bond_params params;
struct list_head vlan_list;
struct vlan_group *vlgrp;
+ struct packet_type arp_mon_pt;
};
/**
@@ -228,6 +231,25 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
return (struct bonding *)slave->dev->master->priv;
}
+#define BOND_ARP_VALIDATE_NONE 0
+#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE)
+#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
+#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
+ BOND_ARP_VALIDATE_BACKUP)
+
+extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
+{
+ return bond->params.arp_validate & (1 << slave->state);
+}
+
+extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave)
+{
+ if (slave_do_arp_validate(bond, slave))
+ return slave->last_arp_rx;
+
+ return slave->dev->last_rx;
+}
+
static inline void bond_set_slave_inactive_flags(struct slave *slave)
{
struct bonding *bond = slave->dev->master->priv;
@@ -235,12 +257,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
bond->params.mode != BOND_MODE_ALB)
slave->state = BOND_STATE_BACKUP;
slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
+ if (slave_do_arp_validate(bond, slave))
+ slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
}
static inline void bond_set_slave_active_flags(struct slave *slave)
{
slave->state = BOND_STATE_ACTIVE;
- slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
+ slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP);
}
static inline void bond_set_master_3ad_flags(struct bonding *bond)
@@ -284,6 +308,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
const char *bond_mode_name(int mode);
void bond_select_active_slave(struct bonding *bond);
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
+void bond_register_arp(struct bonding *);
+void bond_unregister_arp(struct bonding *);
#endif /* _LINUX_BONDING_H */
diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c
index 7694365092f8..521c5b71023c 100644
--- a/drivers/net/cassini.c
+++ b/drivers/net/cassini.c
@@ -2469,7 +2469,7 @@ static inline void cas_handle_irqN(struct net_device *dev,
cas_post_rxcs_ringN(dev, cp, ring);
}
-static irqreturn_t cas_interruptN(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cas_interruptN(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct cas *cp = netdev_priv(dev);
@@ -2522,7 +2522,7 @@ static inline void cas_handle_irq1(struct cas *cp, const u32 status)
}
/* ring 2 handles a few more events than 3 and 4 */
-static irqreturn_t cas_interrupt1(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cas_interrupt1(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct cas *cp = netdev_priv(dev);
@@ -2574,7 +2574,7 @@ static inline void cas_handle_irq(struct net_device *dev,
cas_post_rxcs_ringN(dev, cp, 0);
}
-static irqreturn_t cas_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cas_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct cas *cp = netdev_priv(dev);
@@ -2689,7 +2689,7 @@ static void cas_netpoll(struct net_device *dev)
struct cas *cp = netdev_priv(dev);
cas_disable_irq(cp, 0);
- cas_interrupt(cp->pdev->irq, dev, NULL);
+ cas_interrupt(cp->pdev->irq, dev);
cas_enable_irq(cp, 0);
#ifdef USE_PCI_INTB
diff --git a/drivers/net/chelsio/cpl5_cmd.h b/drivers/net/chelsio/cpl5_cmd.h
index 27925e487bcf..5b357d9e88d6 100644
--- a/drivers/net/chelsio/cpl5_cmd.h
+++ b/drivers/net/chelsio/cpl5_cmd.h
@@ -108,7 +108,7 @@ struct cpl_tx_pkt_lso {
u8 iff:4;
#endif
u16 vlan;
- u32 len;
+ __be32 len;
u32 rsvd2;
u8 rsvd3;
@@ -119,7 +119,7 @@ struct cpl_tx_pkt_lso {
u8 ip_hdr_words:4;
u8 tcp_hdr_words:4;
#endif
- u16 eth_type_mss;
+ __be16 eth_type_mss;
};
struct cpl_rx_pkt {
@@ -138,7 +138,7 @@ struct cpl_rx_pkt {
u8 iff:4;
#endif
u16 csum;
- u16 vlan;
+ __be16 vlan;
u16 len;
};
diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c
index 5f1b06753462..ad7ff9641a7e 100644
--- a/drivers/net/chelsio/cxgb2.c
+++ b/drivers/net/chelsio/cxgb2.c
@@ -918,7 +918,7 @@ static void t1_netpoll(struct net_device *dev)
struct adapter *adapter = dev->priv;
local_irq_save(flags);
- t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter, NULL);
+ t1_select_intr_handler(adapter)(adapter->pdev->irq, adapter);
local_irq_restore(flags);
}
#endif
diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c
index ddd0bdb498f4..9799c12380fc 100644
--- a/drivers/net/chelsio/sge.c
+++ b/drivers/net/chelsio/sge.c
@@ -1217,7 +1217,7 @@ static inline int napi_is_scheduled(struct net_device *dev)
/*
* NAPI version of the main interrupt handler.
*/
-static irqreturn_t t1_interrupt_napi(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t t1_interrupt_napi(int irq, void *data)
{
int handled;
struct adapter *adapter = data;
@@ -1279,7 +1279,7 @@ static irqreturn_t t1_interrupt_napi(int irq, void *data, struct pt_regs *regs)
* 5. If we took an interrupt, but no valid respQ descriptors was found we
* let the slow_intr_handler run and do error handling.
*/
-static irqreturn_t t1_interrupt(int irq, void *cookie, struct pt_regs *regs)
+static irqreturn_t t1_interrupt(int irq, void *cookie)
{
int work_done;
struct respQ_e *e;
@@ -1312,7 +1312,7 @@ static irqreturn_t t1_interrupt(int irq, void *cookie, struct pt_regs *regs)
return IRQ_RETVAL(work_done != 0);
}
-intr_handler_t t1_select_intr_handler(adapter_t *adapter)
+irq_handler_t t1_select_intr_handler(adapter_t *adapter)
{
return adapter->params.sge.polling ? t1_interrupt_napi : t1_interrupt;
}
diff --git a/drivers/net/chelsio/sge.h b/drivers/net/chelsio/sge.h
index 6d0d24a6364f..91af47bab7be 100644
--- a/drivers/net/chelsio/sge.h
+++ b/drivers/net/chelsio/sge.h
@@ -43,13 +43,6 @@
#include <linux/interrupt.h>
#include <asm/byteorder.h>
-#ifndef IRQ_RETVAL
-#define IRQ_RETVAL(x)
-typedef void irqreturn_t;
-#endif
-
-typedef irqreturn_t (*intr_handler_t)(int, void *, struct pt_regs *);
-
struct sge_intr_counts {
unsigned int respQ_empty; /* # times respQ empty */
unsigned int respQ_overflow; /* # respQ overflow (fatal) */
@@ -88,7 +81,7 @@ struct sge *t1_sge_create(struct adapter *, struct sge_params *);
int t1_sge_configure(struct sge *, struct sge_params *);
int t1_sge_set_coalesce_params(struct sge *, struct sge_params *);
void t1_sge_destroy(struct sge *);
-intr_handler_t t1_select_intr_handler(adapter_t *adapter);
+irq_handler_t t1_select_intr_handler(adapter_t *adapter);
int t1_start_xmit(struct sk_buff *skb, struct net_device *dev);
void t1_set_vlan_accel(struct adapter *adapter, int on_off);
void t1_sge_start(struct sge *);
diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c
index f1501b6f247e..966b563e42bb 100644
--- a/drivers/net/cris/eth_v10.c
+++ b/drivers/net/cris/eth_v10.c
@@ -403,8 +403,8 @@ static int etrax_ethernet_init(void);
static int e100_open(struct net_device *dev);
static int e100_set_mac_address(struct net_device *dev, void *addr);
static int e100_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t e100nw_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t e100rxtx_interrupt(int irq, void *dev_id);
+static irqreturn_t e100nw_interrupt(int irq, void *dev_id);
static void e100_rx(struct net_device *dev);
static int e100_close(struct net_device *dev);
static int e100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
@@ -1197,7 +1197,7 @@ e100_send_packet(struct sk_buff *skb, struct net_device *dev)
*/
static irqreturn_t
-e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+e100rxtx_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct net_local *np = (struct net_local *)dev->priv;
@@ -1264,7 +1264,7 @@ e100rxtx_interrupt(int irq, void *dev_id, struct pt_regs * regs)
}
static irqreturn_t
-e100nw_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+e100nw_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct net_local *np = (struct net_local *)dev->priv;
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index e4d50f0de930..4ffc9b44a8e1 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -249,7 +249,7 @@ struct net_local {
static int cs89x0_probe1(struct net_device *dev, int ioaddr, int modular);
static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t net_interrupt(int irq, void *dev_id);
static void set_multicast_list(struct net_device *dev);
static void net_timeout(struct net_device *dev);
static void net_rx(struct net_device *dev);
@@ -495,7 +495,7 @@ get_eeprom_cksum(int off, int len, int *buffer)
static void net_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- net_interrupt(dev->irq, dev, NULL);
+ net_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
@@ -1573,7 +1573,7 @@ static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
diff --git a/drivers/net/de600.c b/drivers/net/de600.c
index 0b930da5d47d..690bb40b353d 100644
--- a/drivers/net/de600.c
+++ b/drivers/net/de600.c
@@ -258,19 +258,13 @@ static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev)
* Handle the network interface interrupts.
*/
-static irqreturn_t de600_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t de600_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
u8 irq_status;
int retrig = 0;
int boguscount = 0;
- /* This might just as well be deleted now, no crummy drivers present :-) */
- if ((dev == NULL) || (DE600_IRQ != irq)) {
- printk(KERN_ERR "%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq);
- return IRQ_NONE;
- }
-
spin_lock(&de600_lock);
select_nic();
diff --git a/drivers/net/de600.h b/drivers/net/de600.h
index e4073015dcd8..1288e48ba704 100644
--- a/drivers/net/de600.h
+++ b/drivers/net/de600.h
@@ -125,7 +125,7 @@ static struct net_device_stats *get_stats(struct net_device *dev);
static int de600_start_xmit(struct sk_buff *skb, struct net_device *dev);
/* Dispatch from interrupts. */
-static irqreturn_t de600_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t de600_interrupt(int irq, void *dev_id);
static int de600_tx_intr(struct net_device *dev, int irq_status);
static void de600_rx_intr(struct net_device *dev);
diff --git a/drivers/net/de620.c b/drivers/net/de620.c
index a18d4d14b665..b6ad0cb50552 100644
--- a/drivers/net/de620.c
+++ b/drivers/net/de620.c
@@ -221,7 +221,7 @@ static void de620_set_multicast_list(struct net_device *);
static int de620_start_xmit(struct sk_buff *, struct net_device *);
/* Dispatch from interrupts. */
-static irqreturn_t de620_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t de620_interrupt(int, void *);
static int de620_rx_intr(struct net_device *);
/* Initialization */
@@ -591,7 +591,7 @@ static int de620_start_xmit(struct sk_buff *skb, struct net_device *dev)
*
*/
static irqreturn_t
-de620_interrupt(int irq_in, void *dev_id, struct pt_regs *regs)
+de620_interrupt(int irq_in, void *dev_id)
{
struct net_device *dev = dev_id;
byte irq_status;
diff --git a/drivers/net/declance.c b/drivers/net/declance.c
index bbccd741cdbf..00e2a8a134d7 100644
--- a/drivers/net/declance.c
+++ b/drivers/net/declance.c
@@ -694,19 +694,17 @@ out:
spin_unlock(&lp->lock);
}
-static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t lance_dma_merr_int(const int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
printk("%s: DMA error\n", dev->name);
return IRQ_HANDLED;
}
-static irqreturn_t lance_interrupt(const int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t lance_interrupt(const int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct lance_private *lp = netdev_priv(dev);
volatile struct lance_regs *ll = lp->ll;
int csr0;
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index ae9680552b82..8f514cc0debd 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -248,8 +248,7 @@ static int dfx_close(struct net_device *dev);
static void dfx_int_pr_halt_id(DFX_board_t *bp);
static void dfx_int_type_0_process(DFX_board_t *bp);
static void dfx_int_common(struct net_device *dev);
-static irqreturn_t dfx_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t dfx_interrupt(int irq, void *dev_id);
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
static void dfx_ctl_set_multicast_list(struct net_device *dev);
@@ -1693,7 +1692,6 @@ static void dfx_int_common(struct net_device *dev)
* Arguments:
* irq - interrupt vector
* dev_id - pointer to device information
- * regs - pointer to registers structure
*
* Functional Description:
* This routine calls the interrupt processing routine for this adapter. It
@@ -1716,7 +1714,7 @@ static void dfx_int_common(struct net_device *dev)
* Interrupts are disabled, then reenabled at the adapter.
*/
-static irqreturn_t dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dfx_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
DFX_board_t *bp; /* private board structure pointer */
diff --git a/drivers/net/depca.c b/drivers/net/depca.c
index af594664df51..f87f6e3dc721 100644
--- a/drivers/net/depca.c
+++ b/drivers/net/depca.c
@@ -518,7 +518,7 @@ struct depca_private {
*/
static int depca_open(struct net_device *dev);
static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t depca_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t depca_interrupt(int irq, void *dev_id);
static int depca_close(struct net_device *dev);
static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void depca_tx_timeout(struct net_device *dev);
@@ -965,7 +965,7 @@ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev)
/*
** The DEPCA interrupt handler.
*/
-static irqreturn_t depca_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t depca_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct depca_private *lp;
diff --git a/drivers/net/dgrs.c b/drivers/net/dgrs.c
index e9361cb5f4cd..a79520295fd0 100644
--- a/drivers/net/dgrs.c
+++ b/drivers/net/dgrs.c
@@ -110,7 +110,6 @@ static char version[] __initdata =
* DGRS include files
*/
typedef unsigned char uchar;
-typedef unsigned int bool;
#define vol volatile
#include "dgrs.h"
@@ -896,10 +895,10 @@ static int dgrs_ioctl(struct net_device *devN, struct ifreq *ifr, int cmd)
* dev, priv will always refer to the 0th device in Multi-NIC mode.
*/
-static irqreturn_t dgrs_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dgrs_intr(int irq, void *dev_id)
{
- struct net_device *dev0 = (struct net_device *) dev_id;
- DGRS_PRIV *priv0 = (DGRS_PRIV *) dev0->priv;
+ struct net_device *dev0 = dev_id;
+ DGRS_PRIV *priv0 = dev0->priv;
I596_CB *cbp;
int cmd;
int i;
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index 7e95cf1a4872..9d446a0fe0bf 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -60,7 +60,7 @@ static void rio_timer (unsigned long data);
static void rio_tx_timeout (struct net_device *dev);
static void alloc_list (struct net_device *dev);
static int start_xmit (struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t rio_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t rio_interrupt (int irq, void *dev_instance);
static void rio_free_tx (struct net_device *dev, int irq);
static void tx_error (struct net_device *dev, int tx_status);
static int receive_packet (struct net_device *dev);
@@ -665,7 +665,7 @@ start_xmit (struct sk_buff *skb, struct net_device *dev)
}
static irqreturn_t
-rio_interrupt (int irq, void *dev_instance, struct pt_regs *rgs)
+rio_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct netdev_private *np;
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index a860ebbbf815..615d2b14efa7 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -159,7 +159,7 @@ static void dm9000_init_dm9000(struct net_device *);
static struct net_device_stats *dm9000_get_stats(struct net_device *);
-static irqreturn_t dm9000_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t dm9000_interrupt(int, void *);
static int dm9000_phy_read(struct net_device *dev, int phyaddr_unsused, int reg);
static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg,
@@ -346,7 +346,7 @@ static void dm9000_timeout(struct net_device *dev)
static void dm9000_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- dm9000_interrupt(dev->irq,dev,NULL);
+ dm9000_interrupt(dev->irq,dev);
enable_irq(dev->irq);
}
#endif
@@ -804,7 +804,7 @@ dm9000_tx_done(struct net_device *dev, board_info_t * db)
}
static irqreturn_t
-dm9000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+dm9000_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
board_info_t *db;
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index dc5e38aefca6..a3a08a5dd185 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
+ Intel PRO/100 Linux driver
+ Copyright(c) 1999 - 2006 Intel 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.
+ under the terms and conditions 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
+ This program is distributed in the hope 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.
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- The full GNU General Public License is included in this distribution in the
- file called LICENSE.
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -159,7 +159,7 @@
#define DRV_NAME "e100"
#define DRV_EXT "-NAPI"
-#define DRV_VERSION "3.5.16-k2"DRV_EXT
+#define DRV_VERSION "3.5.17-k2"DRV_EXT
#define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver"
#define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation"
#define PFX DRV_NAME ": "
@@ -1657,13 +1657,14 @@ static int e100_tx_clean(struct nic *nic)
spin_lock(&nic->cb_lock);
- DPRINTK(TX_DONE, DEBUG, "cb->status = 0x%04X\n",
- nic->cb_to_clean->status);
-
/* Clean CBs marked complete */
for(cb = nic->cb_to_clean;
cb->status & cpu_to_le16(cb_complete);
cb = nic->cb_to_clean = cb->next) {
+ DPRINTK(TX_DONE, DEBUG, "cb[%d]->status = 0x%04X\n",
+ (int)(((void*)cb - (void*)nic->cbs)/sizeof(struct cb)),
+ cb->status);
+
if(likely(cb->skb != NULL)) {
nic->net_stats.tx_packets++;
nic->net_stats.tx_bytes += cb->skb->len;
@@ -1948,7 +1949,7 @@ static int e100_rx_alloc_list(struct nic *nic)
return 0;
}
-static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t e100_intr(int irq, void *dev_id)
{
struct net_device *netdev = dev_id;
struct nic *nic = netdev_priv(netdev);
@@ -2004,7 +2005,7 @@ static void e100_netpoll(struct net_device *netdev)
struct nic *nic = netdev_priv(netdev);
e100_disable_irq(nic);
- e100_intr(nic->pdev->irq, netdev, NULL);
+ e100_intr(nic->pdev->irq, netdev);
e100_tx_clean(nic);
e100_enable_irq(nic);
}
@@ -2038,7 +2039,6 @@ static int e100_change_mtu(struct net_device *netdev, int new_mtu)
return 0;
}
-#ifdef CONFIG_PM
static int e100_asf(struct nic *nic)
{
/* ASF can be enabled from eeprom */
@@ -2047,7 +2047,6 @@ static int e100_asf(struct nic *nic)
!(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&
((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));
}
-#endif
static int e100_up(struct nic *nic)
{
@@ -2572,7 +2571,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = e100_netpoll;
#endif
- strcpy(netdev->name, pci_name(pdev));
+ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
nic = netdev_priv(netdev);
nic->netdev = netdev;
@@ -2719,22 +2718,23 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct nic *nic = netdev_priv(netdev);
- int retval;
- if(netif_running(netdev))
- e100_down(nic);
- e100_hw_reset(nic);
- netif_device_detach(netdev);
+ netif_poll_disable(nic->netdev);
+ del_timer_sync(&nic->watchdog);
+ netif_carrier_off(nic->netdev);
pci_save_state(pdev);
- retval = pci_enable_wake(pdev, pci_choose_state(pdev, state),
- nic->flags & (wol_magic | e100_asf(nic)));
- if (retval)
- DPRINTK(PROBE,ERR, "Error enabling wake\n");
+
+ if ((nic->flags & wol_magic) | e100_asf(nic)) {
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ } else {
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+ }
+
pci_disable_device(pdev);
- retval = pci_set_power_state(pdev, pci_choose_state(pdev, state));
- if (retval)
- DPRINTK(PROBE,ERR, "Error %d setting power state\n", retval);
+ pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
@@ -2743,39 +2743,40 @@ static int e100_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct nic *nic = netdev_priv(netdev);
- int retval;
- retval = pci_set_power_state(pdev, PCI_D0);
- if (retval)
- DPRINTK(PROBE,ERR, "Error waking adapter\n");
+ pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
/* ack any pending wake events, disable PME */
- retval = pci_enable_wake(pdev, 0, 0);
- if (retval)
- DPRINTK(PROBE,ERR, "Error clearing wake events\n");
+ pci_enable_wake(pdev, 0, 0);
netif_device_attach(netdev);
- if(netif_running(netdev))
+ if (netif_running(netdev))
e100_up(nic);
return 0;
}
-#endif
+#endif /* CONFIG_PM */
static void e100_shutdown(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
struct nic *nic = netdev_priv(netdev);
- int retval;
-#ifdef CONFIG_PM
- retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic | e100_asf(nic)));
-#else
- retval = pci_enable_wake(pdev, 0, nic->flags & (wol_magic));
-#endif
- if (retval)
- DPRINTK(PROBE,ERR, "Error enabling wake\n");
+ netif_poll_disable(nic->netdev);
+ del_timer_sync(&nic->watchdog);
+ netif_carrier_off(nic->netdev);
+
+ if ((nic->flags & wol_magic) | e100_asf(nic)) {
+ pci_enable_wake(pdev, PCI_D3hot, 1);
+ pci_enable_wake(pdev, PCI_D3cold, 1);
+ } else {
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
+ }
+
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
}
/* ------------------ PCI Error Recovery infrastructure -------------- */
@@ -2860,6 +2861,7 @@ static struct pci_driver e100_driver = {
.probe = e100_probe,
.remove = __devexit_p(e100_remove),
#ifdef CONFIG_PM
+ /* Power Management hooks */
.suspend = e100_suspend,
.resume = e100_resume,
#endif
diff --git a/drivers/net/e1000/LICENSE b/drivers/net/e1000/LICENSE
deleted file mode 100644
index 5f297e5bb465..000000000000
--- a/drivers/net/e1000/LICENSE
+++ /dev/null
@@ -1,339 +0,0 @@
-
-"This software program is licensed subject to the GNU General Public License
-(GPL). Version 2, June 1991, available at
-<http://www.fsf.org/copyleft/gpl.html>"
-
-GNU General Public License
-
-Version 2, June 1991
-
-Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-
-Everyone is permitted to copy and distribute verbatim copies of this license
-document, but changing it is not allowed.
-
-Preamble
-
-The licenses for most software are designed to take away your freedom to
-share and change it. By contrast, the GNU General Public License is intended
-to guarantee your freedom to share and change free software--to make sure
-the software is free for all its users. This General Public License applies
-to most of the Free Software Foundation's software and to any other program
-whose authors commit to using it. (Some other Free Software Foundation
-software is covered by the GNU Library General Public License instead.) You
-can apply it to your programs, too.
-
-When we speak of free software, we are referring to freedom, not price. Our
-General Public Licenses are designed to make sure that you have the freedom
-to distribute copies of free software (and charge for this service if you
-wish), that you receive source code or can get it if you want it, that you
-can change the software or use pieces of it in new free programs; and that
-you know you can do these things.
-
-To protect your rights, we need to make restrictions that forbid anyone to
-deny you these rights or to ask you to surrender the rights. These
-restrictions translate to certain responsibilities for you if you distribute
-copies of the software, or if you modify it.
-
-For example, if you distribute copies of such a program, whether gratis or
-for a fee, you must give the recipients all the rights that you have. You
-must make sure that they, too, receive or can get the source code. And you
-must show them these terms so they know their rights.
-
-We protect your rights with two steps: (1) copyright the software, and (2)
-offer you this license which gives you legal permission to copy, distribute
-and/or modify the software.
-
-Also, for each author's protection and ours, we want to make certain that
-everyone understands that there is no warranty for this free software. If
-the software is modified by someone else and passed on, we want its
-recipients to know that what they have is not the original, so that any
-problems introduced by others will not reflect on the original authors'
-reputations.
-
-Finally, any free program is threatened constantly by software patents. We
-wish to avoid the danger that redistributors of a free program will
-individually obtain patent licenses, in effect making the program
-proprietary. To prevent this, we have made it clear that any patent must be
-licensed for everyone's free use or not licensed at all.
-
-The precise terms and conditions for copying, distribution and modification
-follow.
-
-TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
-0. This License applies to any program or other work which contains a notice
- placed by the copyright holder saying it may be distributed under the
- terms of this General Public License. The "Program", below, refers to any
- such program or work, and a "work based on the Program" means either the
- Program or any derivative work under copyright law: that is to say, a
- work containing the Program or a portion of it, either verbatim or with
- modifications and/or translated into another language. (Hereinafter,
- translation is included without limitation in the term "modification".)
- Each licensee is addressed as "you".
-
- Activities other than copying, distribution and modification are not
- covered by this License; they are outside its scope. The act of running
- the Program is not restricted, and the output from the Program is covered
- only if its contents constitute a work based on the Program (independent
- of having been made by running the Program). Whether that is true depends
- on what the Program does.
-
-1. You may copy and distribute verbatim copies of the Program's source code
- as you receive it, in any medium, provided that you conspicuously and
- appropriately publish on each copy an appropriate copyright notice and
- disclaimer of warranty; keep intact all the notices that refer to this
- License and to the absence of any warranty; and give any other recipients
- of the Program a copy of this License along with the Program.
-
- You may charge a fee for the physical act of transferring a copy, and you
- may at your option offer warranty protection in exchange for a fee.
-
-2. You may modify your copy or copies of the Program or any portion of it,
- thus forming a work based on the Program, and copy and distribute such
- modifications or work under the terms of Section 1 above, provided that
- you also meet all of these conditions:
-
- * a) You must cause the modified files to carry prominent notices stating
- that you changed the files and the date of any change.
-
- * b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any part
- thereof, to be licensed as a whole at no charge to all third parties
- under the terms of this License.
-
- * c) If the modified program normally reads commands interactively when
- run, you must cause it, when started running for such interactive
- use in the most ordinary way, to print or display an announcement
- including an appropriate copyright notice and a notice that there is
- no warranty (or else, saying that you provide a warranty) and that
- users may redistribute the program under these conditions, and
- telling the user how to view a copy of this License. (Exception: if
- the Program itself is interactive but does not normally print such
- an announcement, your work based on the Program is not required to
- print an announcement.)
-
- These requirements apply to the modified work as a whole. If identifiable
- sections of that work are not derived from the Program, and can be
- reasonably considered independent and separate works in themselves, then
- this License, and its terms, do not apply to those sections when you
- distribute them as separate works. But when you distribute the same
- sections as part of a whole which is a work based on the Program, the
- distribution of the whole must be on the terms of this License, whose
- permissions for other licensees extend to the entire whole, and thus to
- each and every part regardless of who wrote it.
-
- Thus, it is not the intent of this section to claim rights or contest
- your rights to work written entirely by you; rather, the intent is to
- exercise the right to control the distribution of derivative or
- collective works based on the Program.
-
- In addition, mere aggregation of another work not based on the Program
- with the Program (or with a work based on the Program) on a volume of a
- storage or distribution medium does not bring the other work under the
- scope of this License.
-
-3. You may copy and distribute the Program (or a work based on it, under
- Section 2) in object code or executable form under the terms of Sections
- 1 and 2 above provided that you also do one of the following:
-
- * a) Accompany it with the complete corresponding machine-readable source
- code, which must be distributed under the terms of Sections 1 and 2
- above on a medium customarily used for software interchange; or,
-
- * b) Accompany it with a written offer, valid for at least three years,
- to give any third party, for a charge no more than your cost of
- physically performing source distribution, a complete machine-
- readable copy of the corresponding source code, to be distributed
- under the terms of Sections 1 and 2 above on a medium customarily
- used for software interchange; or,
-
- * c) Accompany it with the information you received as to the offer to
- distribute corresponding source code. (This alternative is allowed
- only for noncommercial distribution and only if you received the
- program in object code or executable form with such an offer, in
- accord with Subsection b above.)
-
- The source code for a work means the preferred form of the work for
- making modifications to it. For an executable work, complete source code
- means all the source code for all modules it contains, plus any
- associated interface definition files, plus the scripts used to control
- compilation and installation of the executable. However, as a special
- exception, the source code distributed need not include anything that is
- normally distributed (in either source or binary form) with the major
- components (compiler, kernel, and so on) of the operating system on which
- the executable runs, unless that component itself accompanies the
- executable.
-
- If distribution of executable or object code is made by offering access
- to copy from a designated place, then offering equivalent access to copy
- the source code from the same place counts as distribution of the source
- code, even though third parties are not compelled to copy the source
- along with the object code.
-
-4. You may not copy, modify, sublicense, or distribute the Program except as
- expressly provided under this License. Any attempt otherwise to copy,
- modify, sublicense or distribute the Program is void, and will
- automatically terminate your rights under this License. However, parties
- who have received copies, or rights, from you under this License will not
- have their licenses terminated so long as such parties remain in full
- compliance.
-
-5. You are not required to accept this License, since you have not signed
- it. However, nothing else grants you permission to modify or distribute
- the Program or its derivative works. These actions are prohibited by law
- if you do not accept this License. Therefore, by modifying or
- distributing the Program (or any work based on the Program), you
- indicate your acceptance of this License to do so, and all its terms and
- conditions for copying, distributing or modifying the Program or works
- based on it.
-
-6. Each time you redistribute the Program (or any work based on the
- Program), the recipient automatically receives a license from the
- original licensor to copy, distribute or modify the Program subject to
- these terms and conditions. You may not impose any further restrictions
- on the recipients' exercise of the rights granted herein. You are not
- responsible for enforcing compliance by third parties to this License.
-
-7. If, as a consequence of a court judgment or allegation of patent
- infringement or for any other reason (not limited to patent issues),
- conditions are imposed on you (whether by court order, agreement or
- otherwise) that contradict the conditions of this License, they do not
- excuse you from the conditions of this License. If you cannot distribute
- so as to satisfy simultaneously your obligations under this License and
- any other pertinent obligations, then as a consequence you may not
- distribute the Program at all. For example, if a patent license would
- not permit royalty-free redistribution of the Program by all those who
- receive copies directly or indirectly through you, then the only way you
- could satisfy both it and this License would be to refrain entirely from
- distribution of the Program.
-
- If any portion of this section is held invalid or unenforceable under any
- particular circumstance, the balance of the section is intended to apply
- and the section as a whole is intended to apply in other circumstances.
-
- It is not the purpose of this section to induce you to infringe any
- patents or other property right claims or to contest validity of any
- such claims; this section has the sole purpose of protecting the
- integrity of the free software distribution system, which is implemented
- by public license practices. Many people have made generous contributions
- to the wide range of software distributed through that system in
- reliance on consistent application of that system; it is up to the
- author/donor to decide if he or she is willing to distribute software
- through any other system and a licensee cannot impose that choice.
-
- This section is intended to make thoroughly clear what is believed to be
- a consequence of the rest of this License.
-
-8. If the distribution and/or use of the Program is restricted in certain
- countries either by patents or by copyrighted interfaces, the original
- copyright holder who places the Program under this License may add an
- explicit geographical distribution limitation excluding those countries,
- so that distribution is permitted only in or among countries not thus
- excluded. In such case, this License incorporates the limitation as if
- written in the body of this License.
-
-9. The Free Software Foundation may publish revised and/or new versions of
- the General Public License from time to time. Such new versions will be
- similar in spirit to the present version, but may differ in detail to
- address new problems or concerns.
-
- Each version is given a distinguishing version number. If the Program
- specifies a version number of this License which applies to it and "any
- later version", you have the option of following the terms and
- conditions either of that version or of any later version published by
- the Free Software Foundation. If the Program does not specify a version
- number of this License, you may choose any version ever published by the
- Free Software Foundation.
-
-10. If you wish to incorporate parts of the Program into other free programs
- whose distribution conditions are different, write to the author to ask
- for permission. For software which is copyrighted by the Free Software
- Foundation, write to the Free Software Foundation; we sometimes make
- exceptions for this. Our decision will be guided by the two goals of
- preserving the free status of all derivatives of our free software and
- of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
-11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
- FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
- OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
- PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER
- EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
- ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
- YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
- NECESSARY SERVICING, REPAIR OR CORRECTION.
-
-12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
- WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
- REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
- DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
- DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
- (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
- INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
- THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
- OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
-
-END OF TERMS AND CONDITIONS
-
-How to Apply These Terms to Your New Programs
-
-If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it free
-software which everyone can redistribute and change under these terms.
-
-To do so, attach the following notices to the program. It is safest to
-attach them to the start of each source file to most effectively convey the
-exclusion of warranty; and each file should have at least the "copyright"
-line and a pointer to where the full notice is found.
-
-one line to give the program's name and an idea of what it does.
-Copyright (C) yyyy name of author
-
-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.
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this when
-it starts in an interactive mode:
-
-Gnomovision version 69, Copyright (C) year name of author Gnomovision comes
-with ABSOLUTELY NO WARRANTY; for details type 'show w'. This is free
-software, and you are welcome to redistribute it under certain conditions;
-type 'show c' for details.
-
-The hypothetical commands 'show w' and 'show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may be
-called something other than 'show w' and 'show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
-Yoyodyne, Inc., hereby disclaims all copyright interest in the program
-'Gnomovision' (which makes passes at compilers) written by James Hacker.
-
-signature of Ty Coon, 1 April 1989
-Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General Public
-License instead of this License.
diff --git a/drivers/net/e1000/Makefile b/drivers/net/e1000/Makefile
index 5dea2b7dea4d..4a6ab1522451 100644
--- a/drivers/net/e1000/Makefile
+++ b/drivers/net/e1000/Makefile
@@ -1,25 +1,24 @@
################################################################################
#
-#
-# Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-#
-# 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
+# Intel PRO/1000 Linux driver
+# Copyright(c) 1999 - 2006 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
-# file called LICENSE.
-#
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
# Contact Information:
# Linux NICS <linux.nics@intel.com>
# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index 98afa9c2057e..7ecce438d258 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -1,25 +1,24 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
@@ -346,29 +345,9 @@ struct e1000_adapter {
};
enum e1000_state_t {
- __E1000_DRIVER_TESTING,
+ __E1000_TESTING,
__E1000_RESETTING,
+ __E1000_DOWN
};
-/* e1000_main.c */
-extern char e1000_driver_name[];
-extern char e1000_driver_version[];
-int e1000_up(struct e1000_adapter *adapter);
-void e1000_down(struct e1000_adapter *adapter);
-void e1000_reset(struct e1000_adapter *adapter);
-void e1000_reinit_locked(struct e1000_adapter *adapter);
-int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
-void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
-int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
-void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
-void e1000_update_stats(struct e1000_adapter *adapter);
-int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
-
-/* e1000_ethtool.c */
-void e1000_set_ethtool_ops(struct net_device *netdev);
-
-/* e1000_param.c */
-void e1000_check_options(struct e1000_adapter *adapter);
-
-
#endif /* _E1000_H_ */
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index e39aa1fc4d1e..773821e4cf57 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -1,25 +1,24 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
@@ -33,6 +32,21 @@
#include <asm/uaccess.h>
+extern char e1000_driver_name[];
+extern char e1000_driver_version[];
+
+extern int e1000_up(struct e1000_adapter *adapter);
+extern void e1000_down(struct e1000_adapter *adapter);
+extern void e1000_reinit_locked(struct e1000_adapter *adapter);
+extern void e1000_reset(struct e1000_adapter *adapter);
+extern int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
+extern int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+extern int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
+extern void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
+extern void e1000_update_stats(struct e1000_adapter *adapter);
+
+
struct e1000_stats {
char stat_string[ETH_GSTRING_LEN];
int sizeof_stat;
@@ -42,26 +56,30 @@ struct e1000_stats {
#define E1000_STAT(m) sizeof(((struct e1000_adapter *)0)->m), \
offsetof(struct e1000_adapter, m)
static const struct e1000_stats e1000_gstrings_stats[] = {
- { "rx_packets", E1000_STAT(net_stats.rx_packets) },
- { "tx_packets", E1000_STAT(net_stats.tx_packets) },
- { "rx_bytes", E1000_STAT(net_stats.rx_bytes) },
- { "tx_bytes", E1000_STAT(net_stats.tx_bytes) },
- { "rx_errors", E1000_STAT(net_stats.rx_errors) },
- { "tx_errors", E1000_STAT(net_stats.tx_errors) },
+ { "rx_packets", E1000_STAT(stats.gprc) },
+ { "tx_packets", E1000_STAT(stats.gptc) },
+ { "rx_bytes", E1000_STAT(stats.gorcl) },
+ { "tx_bytes", E1000_STAT(stats.gotcl) },
+ { "rx_broadcast", E1000_STAT(stats.bprc) },
+ { "tx_broadcast", E1000_STAT(stats.bptc) },
+ { "rx_multicast", E1000_STAT(stats.mprc) },
+ { "tx_multicast", E1000_STAT(stats.mptc) },
+ { "rx_errors", E1000_STAT(stats.rxerrc) },
+ { "tx_errors", E1000_STAT(stats.txerrc) },
{ "tx_dropped", E1000_STAT(net_stats.tx_dropped) },
- { "multicast", E1000_STAT(net_stats.multicast) },
- { "collisions", E1000_STAT(net_stats.collisions) },
- { "rx_length_errors", E1000_STAT(net_stats.rx_length_errors) },
+ { "multicast", E1000_STAT(stats.mprc) },
+ { "collisions", E1000_STAT(stats.colc) },
+ { "rx_length_errors", E1000_STAT(stats.rlerrc) },
{ "rx_over_errors", E1000_STAT(net_stats.rx_over_errors) },
- { "rx_crc_errors", E1000_STAT(net_stats.rx_crc_errors) },
+ { "rx_crc_errors", E1000_STAT(stats.crcerrs) },
{ "rx_frame_errors", E1000_STAT(net_stats.rx_frame_errors) },
{ "rx_no_buffer_count", E1000_STAT(stats.rnbc) },
- { "rx_missed_errors", E1000_STAT(net_stats.rx_missed_errors) },
- { "tx_aborted_errors", E1000_STAT(net_stats.tx_aborted_errors) },
- { "tx_carrier_errors", E1000_STAT(net_stats.tx_carrier_errors) },
+ { "rx_missed_errors", E1000_STAT(stats.mpc) },
+ { "tx_aborted_errors", E1000_STAT(stats.ecol) },
+ { "tx_carrier_errors", E1000_STAT(stats.tncrs) },
{ "tx_fifo_errors", E1000_STAT(net_stats.tx_fifo_errors) },
{ "tx_heartbeat_errors", E1000_STAT(net_stats.tx_heartbeat_errors) },
- { "tx_window_errors", E1000_STAT(net_stats.tx_window_errors) },
+ { "tx_window_errors", E1000_STAT(stats.latecol) },
{ "tx_abort_late_coll", E1000_STAT(stats.latecol) },
{ "tx_deferred_ok", E1000_STAT(stats.dc) },
{ "tx_single_coll_ok", E1000_STAT(stats.scc) },
@@ -193,13 +211,9 @@ e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
ADVERTISED_FIBRE |
ADVERTISED_Autoneg;
else
- hw->autoneg_advertised = ADVERTISED_10baseT_Half |
- ADVERTISED_10baseT_Full |
- ADVERTISED_100baseT_Half |
- ADVERTISED_100baseT_Full |
- ADVERTISED_1000baseT_Full|
- ADVERTISED_Autoneg |
- ADVERTISED_TP;
+ hw->autoneg_advertised = ecmd->advertising |
+ ADVERTISED_TP |
+ ADVERTISED_Autoneg;
ecmd->advertising = hw->autoneg_advertised;
} else
if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) {
@@ -229,11 +243,11 @@ e1000_get_pauseparam(struct net_device *netdev,
pause->autoneg =
(adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE);
- if (hw->fc == e1000_fc_rx_pause)
+ if (hw->fc == E1000_FC_RX_PAUSE)
pause->rx_pause = 1;
- else if (hw->fc == e1000_fc_tx_pause)
+ else if (hw->fc == E1000_FC_TX_PAUSE)
pause->tx_pause = 1;
- else if (hw->fc == e1000_fc_full) {
+ else if (hw->fc == E1000_FC_FULL) {
pause->rx_pause = 1;
pause->tx_pause = 1;
}
@@ -253,13 +267,13 @@ e1000_set_pauseparam(struct net_device *netdev,
msleep(1);
if (pause->rx_pause && pause->tx_pause)
- hw->fc = e1000_fc_full;
+ hw->fc = E1000_FC_FULL;
else if (pause->rx_pause && !pause->tx_pause)
- hw->fc = e1000_fc_rx_pause;
+ hw->fc = E1000_FC_RX_PAUSE;
else if (!pause->rx_pause && pause->tx_pause)
- hw->fc = e1000_fc_tx_pause;
+ hw->fc = E1000_FC_TX_PAUSE;
else if (!pause->rx_pause && !pause->tx_pause)
- hw->fc = e1000_fc_none;
+ hw->fc = E1000_FC_NONE;
hw->original_fc = hw->fc;
@@ -632,8 +646,8 @@ e1000_set_ringparam(struct net_device *netdev,
{
struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_mac_type mac_type = adapter->hw.mac_type;
- struct e1000_tx_ring *txdr, *tx_old, *tx_new;
- struct e1000_rx_ring *rxdr, *rx_old, *rx_new;
+ struct e1000_tx_ring *txdr, *tx_old;
+ struct e1000_rx_ring *rxdr, *rx_old;
int i, err, tx_ring_size, rx_ring_size;
if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending))
@@ -651,23 +665,17 @@ e1000_set_ringparam(struct net_device *netdev,
tx_old = adapter->tx_ring;
rx_old = adapter->rx_ring;
- adapter->tx_ring = kmalloc(tx_ring_size, GFP_KERNEL);
- if (!adapter->tx_ring) {
- err = -ENOMEM;
- goto err_setup_rx;
- }
- memset(adapter->tx_ring, 0, tx_ring_size);
+ err = -ENOMEM;
+ txdr = kzalloc(tx_ring_size, GFP_KERNEL);
+ if (!txdr)
+ goto err_alloc_tx;
- adapter->rx_ring = kmalloc(rx_ring_size, GFP_KERNEL);
- if (!adapter->rx_ring) {
- kfree(adapter->tx_ring);
- err = -ENOMEM;
- goto err_setup_rx;
- }
- memset(adapter->rx_ring, 0, rx_ring_size);
+ rxdr = kzalloc(rx_ring_size, GFP_KERNEL);
+ if (!rxdr)
+ goto err_alloc_rx;
- txdr = adapter->tx_ring;
- rxdr = adapter->rx_ring;
+ adapter->tx_ring = txdr;
+ adapter->rx_ring = rxdr;
rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD);
rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ?
@@ -694,16 +702,14 @@ e1000_set_ringparam(struct net_device *netdev,
/* save the new, restore the old in order to free it,
* then restore the new back again */
- rx_new = adapter->rx_ring;
- tx_new = adapter->tx_ring;
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
e1000_free_all_rx_resources(adapter);
e1000_free_all_tx_resources(adapter);
kfree(tx_old);
kfree(rx_old);
- adapter->rx_ring = rx_new;
- adapter->tx_ring = tx_new;
+ adapter->rx_ring = rxdr;
+ adapter->tx_ring = txdr;
if ((err = e1000_up(adapter)))
goto err_setup;
}
@@ -715,6 +721,10 @@ err_setup_tx:
err_setup_rx:
adapter->rx_ring = rx_old;
adapter->tx_ring = tx_old;
+ kfree(rxdr);
+err_alloc_rx:
+ kfree(txdr);
+err_alloc_tx:
e1000_up(adapter);
err_setup:
clear_bit(__E1000_RESETTING, &adapter->flags);
@@ -873,8 +883,7 @@ e1000_eeprom_test(struct e1000_adapter *adapter, uint64_t *data)
static irqreturn_t
e1000_test_intr(int irq,
- void *data,
- struct pt_regs *regs)
+ void *data)
{
struct net_device *netdev = (struct net_device *) data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -1610,7 +1619,7 @@ e1000_diag_test(struct net_device *netdev,
struct e1000_adapter *adapter = netdev_priv(netdev);
boolean_t if_running = netif_running(netdev);
- set_bit(__E1000_DRIVER_TESTING, &adapter->flags);
+ set_bit(__E1000_TESTING, &adapter->flags);
if (eth_test->flags == ETH_TEST_FL_OFFLINE) {
/* Offline tests */
@@ -1655,7 +1664,7 @@ e1000_diag_test(struct net_device *netdev,
adapter->hw.autoneg = autoneg;
e1000_reset(adapter);
- clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
+ clear_bit(__E1000_TESTING, &adapter->flags);
if (if_running)
dev_open(netdev);
} else {
@@ -1670,7 +1679,7 @@ e1000_diag_test(struct net_device *netdev,
data[2] = 0;
data[3] = 0;
- clear_bit(__E1000_DRIVER_TESTING, &adapter->flags);
+ clear_bit(__E1000_TESTING, &adapter->flags);
}
msleep_interruptible(4 * 1000);
}
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 10b8c8c25325..65077f39da69 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -1,25 +1,24 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
@@ -34,6 +33,63 @@
#include "e1000_hw.h"
+static int32_t e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask);
+static void e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask);
+static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *data);
+static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
+static int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
+static void e1000_release_software_semaphore(struct e1000_hw *hw);
+
+static uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw);
+static int32_t e1000_check_downshift(struct e1000_hw *hw);
+static int32_t e1000_check_polarity(struct e1000_hw *hw, e1000_rev_polarity *polarity);
+static void e1000_clear_hw_cntrs(struct e1000_hw *hw);
+static void e1000_clear_vfta(struct e1000_hw *hw);
+static int32_t e1000_commit_shadow_ram(struct e1000_hw *hw);
+static int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, boolean_t link_up);
+static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
+static int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
+static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t bank);
+static int32_t e1000_get_auto_rd_done(struct e1000_hw *hw);
+static int32_t e1000_get_cable_length(struct e1000_hw *hw, uint16_t *min_length, uint16_t *max_length);
+static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw);
+static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw);
+static int32_t e1000_get_software_flag(struct e1000_hw *hw);
+static int32_t e1000_ich8_cycle_init(struct e1000_hw *hw);
+static int32_t e1000_ich8_flash_cycle(struct e1000_hw *hw, uint32_t timeout);
+static int32_t e1000_id_led_init(struct e1000_hw *hw);
+static int32_t e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw, uint32_t cnf_base_addr, uint32_t cnf_size);
+static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw);
+static void e1000_init_rx_addrs(struct e1000_hw *hw);
+static void e1000_initialize_hardware_bits(struct e1000_hw *hw);
+static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw);
+static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw);
+static int32_t e1000_mng_enable_host_if(struct e1000_hw *hw);
+static int32_t e1000_mng_host_if_write(struct e1000_hw *hw, uint8_t *buffer, uint16_t length, uint16_t offset, uint8_t *sum);
+static int32_t e1000_mng_write_cmd_header(struct e1000_hw* hw, struct e1000_host_mng_command_header* hdr);
+static int32_t e1000_mng_write_commit(struct e1000_hw *hw);
+static int32_t e1000_phy_ife_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+static int32_t e1000_phy_igp_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+static int32_t e1000_write_eeprom_eewr(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd);
+static int32_t e1000_phy_m88_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
+static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
+static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t *data);
+static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte);
+static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte);
+static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data);
+static int32_t e1000_read_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t *data);
+static int32_t e1000_write_ich8_data(struct e1000_hw *hw, uint32_t index, uint32_t size, uint16_t data);
+static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset, uint16_t words, uint16_t *data);
+static void e1000_release_software_flag(struct e1000_hw *hw);
+static int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active);
+static int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active);
+static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw, uint32_t no_snoop);
+static void e1000_set_pci_express_master_disable(struct e1000_hw *hw);
+static int32_t e1000_wait_autoneg(struct e1000_hw *hw);
+static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, uint32_t value);
static int32_t e1000_set_phy_type(struct e1000_hw *hw);
static void e1000_phy_init_script(struct e1000_hw *hw);
static int32_t e1000_setup_copper_link(struct e1000_hw *hw);
@@ -70,69 +126,10 @@ static int32_t e1000_polarity_reversal_workaround(struct e1000_hw *hw);
static int32_t e1000_set_phy_mode(struct e1000_hw *hw);
static int32_t e1000_host_if_read_cookie(struct e1000_hw *hw, uint8_t *buffer);
static uint8_t e1000_calculate_mng_checksum(char *buffer, uint32_t length);
-static uint8_t e1000_arc_subsystem_valid(struct e1000_hw *hw);
-static int32_t e1000_check_downshift(struct e1000_hw *hw);
-static int32_t e1000_check_polarity(struct e1000_hw *hw, uint16_t *polarity);
-static void e1000_clear_hw_cntrs(struct e1000_hw *hw);
-static void e1000_clear_vfta(struct e1000_hw *hw);
-static int32_t e1000_commit_shadow_ram(struct e1000_hw *hw);
-static int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw,
- boolean_t link_up);
-static int32_t e1000_config_fc_after_link_up(struct e1000_hw *hw);
-static int32_t e1000_detect_gig_phy(struct e1000_hw *hw);
-static int32_t e1000_get_auto_rd_done(struct e1000_hw *hw);
-static int32_t e1000_get_cable_length(struct e1000_hw *hw,
- uint16_t *min_length,
- uint16_t *max_length);
-static int32_t e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw);
-static int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw);
-static int32_t e1000_id_led_init(struct e1000_hw * hw);
-static void e1000_init_rx_addrs(struct e1000_hw *hw);
-static boolean_t e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw);
-static int32_t e1000_poll_eerd_eewr_done(struct e1000_hw *hw, int eerd);
-static void e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw);
-static int32_t e1000_read_eeprom_eerd(struct e1000_hw *hw, uint16_t offset,
- uint16_t words, uint16_t *data);
-static int32_t e1000_set_d0_lplu_state(struct e1000_hw *hw, boolean_t active);
-static int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, boolean_t active);
-static int32_t e1000_wait_autoneg(struct e1000_hw *hw);
-
-static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset,
- uint32_t value);
-
-#define E1000_WRITE_REG_IO(a, reg, val) \
- e1000_write_reg_io((a), E1000_##reg, val)
static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw,
uint16_t duplex);
static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw);
-static int32_t e1000_erase_ich8_4k_segment(struct e1000_hw *hw,
- uint32_t segment);
-static int32_t e1000_get_software_flag(struct e1000_hw *hw);
-static int32_t e1000_get_software_semaphore(struct e1000_hw *hw);
-static int32_t e1000_init_lcd_from_nvm(struct e1000_hw *hw);
-static int32_t e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw);
-static int32_t e1000_read_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
- uint16_t words, uint16_t *data);
-static int32_t e1000_read_ich8_byte(struct e1000_hw *hw, uint32_t index,
- uint8_t* data);
-static int32_t e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index,
- uint16_t *data);
-static int32_t e1000_read_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr,
- uint16_t *data);
-static void e1000_release_software_flag(struct e1000_hw *hw);
-static void e1000_release_software_semaphore(struct e1000_hw *hw);
-static int32_t e1000_set_pci_ex_no_snoop(struct e1000_hw *hw,
- uint32_t no_snoop);
-static int32_t e1000_verify_write_ich8_byte(struct e1000_hw *hw,
- uint32_t index, uint8_t byte);
-static int32_t e1000_write_eeprom_ich8(struct e1000_hw *hw, uint16_t offset,
- uint16_t words, uint16_t *data);
-static int32_t e1000_write_ich8_byte(struct e1000_hw *hw, uint32_t index,
- uint8_t data);
-static int32_t e1000_write_kmrn_reg(struct e1000_hw *hw, uint32_t reg_addr,
- uint16_t data);
-
/* IGP cable length table */
static const
uint16_t e1000_igp_cable_length_table[IGP01E1000_AGC_LENGTH_TABLE_SIZE] =
@@ -156,13 +153,12 @@ uint16_t e1000_igp_2_cable_length_table[IGP02E1000_AGC_LENGTH_TABLE_SIZE] =
83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124,
104, 109, 114, 118, 121, 124};
-
/******************************************************************************
* Set the phy type member in the hw struct.
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-int32_t
+static int32_t
e1000_set_phy_type(struct e1000_hw *hw)
{
DEBUGFUNC("e1000_set_phy_type");
@@ -208,7 +204,6 @@ e1000_set_phy_type(struct e1000_hw *hw)
return E1000_SUCCESS;
}
-
/******************************************************************************
* IGP phy init script - initializes the GbE PHY
*
@@ -667,19 +662,12 @@ e1000_reset_hw(struct e1000_hw *hw)
E1000_WRITE_FLUSH(hw);
}
/* fall through */
- case e1000_82571:
- case e1000_82572:
- case e1000_ich8lan:
- case e1000_80003es2lan:
+ default:
+ /* Auto read done will delay 5ms or poll based on mac type */
ret_val = e1000_get_auto_rd_done(hw);
if (ret_val)
- /* We don't want to continue accessing MAC registers. */
return ret_val;
break;
- default:
- /* Wait for EEPROM reload (it happens automatically) */
- msleep(5);
- break;
}
/* Disable HW ARPs on ASF enabled adapters */
@@ -722,6 +710,123 @@ e1000_reset_hw(struct e1000_hw *hw)
}
/******************************************************************************
+ *
+ * Initialize a number of hardware-dependent bits
+ *
+ * hw: Struct containing variables accessed by shared code
+ *
+ * This function contains hardware limitation workarounds for PCI-E adapters
+ *
+ *****************************************************************************/
+static void
+e1000_initialize_hardware_bits(struct e1000_hw *hw)
+{
+ if ((hw->mac_type >= e1000_82571) && (!hw->initialize_hw_bits_disable)) {
+ /* Settings common to all PCI-express silicon */
+ uint32_t reg_ctrl, reg_ctrl_ext;
+ uint32_t reg_tarc0, reg_tarc1;
+ uint32_t reg_tctl;
+ uint32_t reg_txdctl, reg_txdctl1;
+
+ /* link autonegotiation/sync workarounds */
+ reg_tarc0 = E1000_READ_REG(hw, TARC0);
+ reg_tarc0 &= ~((1 << 30)|(1 << 29)|(1 << 28)|(1 << 27));
+
+ /* Enable not-done TX descriptor counting */
+ reg_txdctl = E1000_READ_REG(hw, TXDCTL);
+ reg_txdctl |= E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, TXDCTL, reg_txdctl);
+ reg_txdctl1 = E1000_READ_REG(hw, TXDCTL1);
+ reg_txdctl1 |= E1000_TXDCTL_COUNT_DESC;
+ E1000_WRITE_REG(hw, TXDCTL1, reg_txdctl1);
+
+ switch (hw->mac_type) {
+ case e1000_82571:
+ case e1000_82572:
+ /* Clear PHY TX compatible mode bits */
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ reg_tarc1 &= ~((1 << 30)|(1 << 29));
+
+ /* link autonegotiation/sync workarounds */
+ reg_tarc0 |= ((1 << 26)|(1 << 25)|(1 << 24)|(1 << 23));
+
+ /* TX ring control fixes */
+ reg_tarc1 |= ((1 << 26)|(1 << 25)|(1 << 24));
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ case e1000_82573:
+ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ reg_ctrl_ext &= ~(1 << 23);
+ reg_ctrl_ext |= (1 << 22);
+
+ /* TX byte count fix */
+ reg_ctrl = E1000_READ_REG(hw, CTRL);
+ reg_ctrl &= ~(1 << 29);
+
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+ E1000_WRITE_REG(hw, CTRL, reg_ctrl);
+ break;
+ case e1000_80003es2lan:
+ /* improve small packet performace for fiber/serdes */
+ if ((hw->media_type == e1000_media_type_fiber) ||
+ (hw->media_type == e1000_media_type_internal_serdes)) {
+ reg_tarc0 &= ~(1 << 20);
+ }
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ case e1000_ich8lan:
+ /* Reduce concurrent DMA requests to 3 from 4 */
+ if ((hw->revision_id < 3) ||
+ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))
+ reg_tarc0 |= ((1 << 29)|(1 << 28));
+
+ reg_ctrl_ext = E1000_READ_REG(hw, CTRL_EXT);
+ reg_ctrl_ext |= (1 << 22);
+ E1000_WRITE_REG(hw, CTRL_EXT, reg_ctrl_ext);
+
+ /* workaround TX hang with TSO=on */
+ reg_tarc0 |= ((1 << 27)|(1 << 26)|(1 << 24)|(1 << 23));
+
+ /* Multiple read bit is reversed polarity */
+ reg_tctl = E1000_READ_REG(hw, TCTL);
+ reg_tarc1 = E1000_READ_REG(hw, TARC1);
+ if (reg_tctl & E1000_TCTL_MULR)
+ reg_tarc1 &= ~(1 << 28);
+ else
+ reg_tarc1 |= (1 << 28);
+
+ /* workaround TX hang with TSO=on */
+ reg_tarc1 |= ((1 << 30)|(1 << 26)|(1 << 24));
+
+ E1000_WRITE_REG(hw, TARC1, reg_tarc1);
+ break;
+ default:
+ break;
+ }
+
+ E1000_WRITE_REG(hw, TARC0, reg_tarc0);
+ }
+}
+
+/******************************************************************************
* Performs basic configuration of the adapter.
*
* hw - Struct containing variables accessed by shared code
@@ -749,14 +854,13 @@ e1000_init_hw(struct e1000_hw *hw)
DEBUGFUNC("e1000_init_hw");
/* force full DMA clock frequency for 10/100 on ICH8 A0-B0 */
- if (hw->mac_type == e1000_ich8lan) {
- reg_data = E1000_READ_REG(hw, TARC0);
- reg_data |= 0x30000000;
- E1000_WRITE_REG(hw, TARC0, reg_data);
-
- reg_data = E1000_READ_REG(hw, STATUS);
- reg_data &= ~0x80000000;
- E1000_WRITE_REG(hw, STATUS, reg_data);
+ if ((hw->mac_type == e1000_ich8lan) &&
+ ((hw->revision_id < 3) ||
+ ((hw->device_id != E1000_DEV_ID_ICH8_IGP_M_AMT) &&
+ (hw->device_id != E1000_DEV_ID_ICH8_IGP_M)))) {
+ reg_data = E1000_READ_REG(hw, STATUS);
+ reg_data &= ~0x80000000;
+ E1000_WRITE_REG(hw, STATUS, reg_data);
}
/* Initialize Identification LED */
@@ -769,6 +873,9 @@ e1000_init_hw(struct e1000_hw *hw)
/* Set the media type and TBI compatibility */
e1000_set_media_type(hw);
+ /* Must be called after e1000_set_media_type because media_type is used */
+ e1000_initialize_hardware_bits(hw);
+
/* Disabling VLAN filtering. */
DEBUGOUT("Initializing the IEEE VLAN\n");
/* VET hardcoded to standard value and VFTA removed in ICH8 LAN */
@@ -860,17 +967,6 @@ e1000_init_hw(struct e1000_hw *hw)
if (hw->mac_type > e1000_82544) {
ctrl = E1000_READ_REG(hw, TXDCTL);
ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
- switch (hw->mac_type) {
- default:
- break;
- case e1000_82571:
- case e1000_82572:
- case e1000_82573:
- case e1000_ich8lan:
- case e1000_80003es2lan:
- ctrl |= E1000_TXDCTL_COUNT_DESC;
- break;
- }
E1000_WRITE_REG(hw, TXDCTL, ctrl);
}
@@ -908,8 +1004,6 @@ e1000_init_hw(struct e1000_hw *hw)
case e1000_ich8lan:
ctrl = E1000_READ_REG(hw, TXDCTL1);
ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB;
- if (hw->mac_type >= e1000_82571)
- ctrl |= E1000_TXDCTL_COUNT_DESC;
E1000_WRITE_REG(hw, TXDCTL1, ctrl);
break;
}
@@ -1018,11 +1112,11 @@ e1000_setup_link(struct e1000_hw *hw)
* control setting, then the variable hw->fc will
* be initialized based on a value in the EEPROM.
*/
- if (hw->fc == e1000_fc_default) {
+ if (hw->fc == E1000_FC_DEFAULT) {
switch (hw->mac_type) {
case e1000_ich8lan:
case e1000_82573:
- hw->fc = e1000_fc_full;
+ hw->fc = E1000_FC_FULL;
break;
default:
ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
@@ -1032,12 +1126,12 @@ e1000_setup_link(struct e1000_hw *hw)
return -E1000_ERR_EEPROM;
}
if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) == 0)
- hw->fc = e1000_fc_none;
+ hw->fc = E1000_FC_NONE;
else if ((eeprom_data & EEPROM_WORD0F_PAUSE_MASK) ==
EEPROM_WORD0F_ASM_DIR)
- hw->fc = e1000_fc_tx_pause;
+ hw->fc = E1000_FC_TX_PAUSE;
else
- hw->fc = e1000_fc_full;
+ hw->fc = E1000_FC_FULL;
break;
}
}
@@ -1047,10 +1141,10 @@ e1000_setup_link(struct e1000_hw *hw)
* hub or switch with different Flow Control capabilities.
*/
if (hw->mac_type == e1000_82542_rev2_0)
- hw->fc &= (~e1000_fc_tx_pause);
+ hw->fc &= (~E1000_FC_TX_PAUSE);
if ((hw->mac_type < e1000_82543) && (hw->report_tx_early == 1))
- hw->fc &= (~e1000_fc_rx_pause);
+ hw->fc &= (~E1000_FC_RX_PAUSE);
hw->original_fc = hw->fc;
@@ -1102,7 +1196,7 @@ e1000_setup_link(struct e1000_hw *hw)
* ability to transmit pause frames in not enabled, then these
* registers will be set to 0.
*/
- if (!(hw->fc & e1000_fc_tx_pause)) {
+ if (!(hw->fc & E1000_FC_TX_PAUSE)) {
E1000_WRITE_REG(hw, FCRTL, 0);
E1000_WRITE_REG(hw, FCRTH, 0);
} else {
@@ -1149,11 +1243,11 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572)
E1000_WRITE_REG(hw, SCTL, E1000_DISABLE_SERDES_LOOPBACK);
- /* On adapters with a MAC newer than 82544, SW Defineable pin 1 will be
+ /* On adapters with a MAC newer than 82544, SWDP 1 will be
* set when the optics detect a signal. On older adapters, it will be
* cleared when there is a signal. This applies to fiber media only.
- * If we're on serdes media, adjust the output amplitude to value set in
- * the EEPROM.
+ * If we're on serdes media, adjust the output amplitude to value
+ * set in the EEPROM.
*/
ctrl = E1000_READ_REG(hw, CTRL);
if (hw->media_type == e1000_media_type_fiber)
@@ -1189,11 +1283,11 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
* 3: Both Rx and TX flow control (symmetric) are enabled.
*/
switch (hw->fc) {
- case e1000_fc_none:
+ case E1000_FC_NONE:
/* Flow control is completely disabled by a software over-ride. */
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD);
break;
- case e1000_fc_rx_pause:
+ case E1000_FC_RX_PAUSE:
/* RX Flow control is enabled and TX Flow control is disabled by a
* software over-ride. Since there really isn't a way to advertise
* that we are capable of RX Pause ONLY, we will advertise that we
@@ -1202,13 +1296,13 @@ e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
*/
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
break;
- case e1000_fc_tx_pause:
+ case E1000_FC_TX_PAUSE:
/* TX Flow control is enabled, and RX Flow control is disabled, by a
* software over-ride.
*/
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_ASM_DIR);
break;
- case e1000_fc_full:
+ case E1000_FC_FULL:
/* Flow control (both RX and TX) is enabled by a software over-ride. */
txcw = (E1000_TXCW_ANE | E1000_TXCW_FD | E1000_TXCW_PAUSE_MASK);
break;
@@ -2124,13 +2218,13 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
* in the EEPROM is used.
*/
switch (hw->fc) {
- case e1000_fc_none: /* 0 */
+ case E1000_FC_NONE: /* 0 */
/* Flow control (RX & TX) is completely disabled by a
* software over-ride.
*/
mii_autoneg_adv_reg &= ~(NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
- case e1000_fc_rx_pause: /* 1 */
+ case E1000_FC_RX_PAUSE: /* 1 */
/* RX Flow control is enabled, and TX Flow control is
* disabled, by a software over-ride.
*/
@@ -2142,14 +2236,14 @@ e1000_phy_setup_autoneg(struct e1000_hw *hw)
*/
mii_autoneg_adv_reg |= (NWAY_AR_ASM_DIR | NWAY_AR_PAUSE);
break;
- case e1000_fc_tx_pause: /* 2 */
+ case E1000_FC_TX_PAUSE: /* 2 */
/* TX Flow control is enabled, and RX Flow control is
* disabled, by a software over-ride.
*/
mii_autoneg_adv_reg |= NWAY_AR_ASM_DIR;
mii_autoneg_adv_reg &= ~NWAY_AR_PAUSE;
break;
- case e1000_fc_full: /* 3 */
+ case E1000_FC_FULL: /* 3 */
/* Flow control (both RX and TX) is enabled by a software
* over-ride.
*/
@@ -2193,7 +2287,7 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw)
DEBUGFUNC("e1000_phy_force_speed_duplex");
/* Turn off Flow control if we are forcing speed and duplex. */
- hw->fc = e1000_fc_none;
+ hw->fc = E1000_FC_NONE;
DEBUGOUT1("hw->fc = %d\n", hw->fc);
@@ -2547,18 +2641,18 @@ e1000_force_mac_fc(struct e1000_hw *hw)
*/
switch (hw->fc) {
- case e1000_fc_none:
+ case E1000_FC_NONE:
ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE));
break;
- case e1000_fc_rx_pause:
+ case E1000_FC_RX_PAUSE:
ctrl &= (~E1000_CTRL_TFCE);
ctrl |= E1000_CTRL_RFCE;
break;
- case e1000_fc_tx_pause:
+ case E1000_FC_TX_PAUSE:
ctrl &= (~E1000_CTRL_RFCE);
ctrl |= E1000_CTRL_TFCE;
break;
- case e1000_fc_full:
+ case E1000_FC_FULL:
ctrl |= (E1000_CTRL_TFCE | E1000_CTRL_RFCE);
break;
default:
@@ -2657,14 +2751,14 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | NIC Resolution
*-------|---------|-------|---------|--------------------
- * 0 | 0 | DC | DC | e1000_fc_none
- * 0 | 1 | 0 | DC | e1000_fc_none
- * 0 | 1 | 1 | 0 | e1000_fc_none
- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
- * 1 | 0 | 0 | DC | e1000_fc_none
- * 1 | DC | 1 | DC | e1000_fc_full
- * 1 | 1 | 0 | 0 | e1000_fc_none
- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ * 0 | 0 | DC | DC | E1000_FC_NONE
+ * 0 | 1 | 0 | DC | E1000_FC_NONE
+ * 0 | 1 | 1 | 0 | E1000_FC_NONE
+ * 0 | 1 | 1 | 1 | E1000_FC_TX_PAUSE
+ * 1 | 0 | 0 | DC | E1000_FC_NONE
+ * 1 | DC | 1 | DC | E1000_FC_FULL
+ * 1 | 1 | 0 | 0 | E1000_FC_NONE
+ * 1 | 1 | 0 | 1 | E1000_FC_RX_PAUSE
*
*/
/* Are both PAUSE bits set to 1? If so, this implies
@@ -2676,7 +2770,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
*-------|---------|-------|---------|--------------------
- * 1 | DC | 1 | DC | e1000_fc_full
+ * 1 | DC | 1 | DC | E1000_FC_FULL
*
*/
if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
@@ -2687,11 +2781,11 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* ONLY. Hence, we must now check to see if we need to
* turn OFF the TRANSMISSION of PAUSE frames.
*/
- if (hw->original_fc == e1000_fc_full) {
- hw->fc = e1000_fc_full;
+ if (hw->original_fc == E1000_FC_FULL) {
+ hw->fc = E1000_FC_FULL;
DEBUGOUT("Flow Control = FULL.\n");
} else {
- hw->fc = e1000_fc_rx_pause;
+ hw->fc = E1000_FC_RX_PAUSE;
DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
}
}
@@ -2700,14 +2794,14 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
*-------|---------|-------|---------|--------------------
- * 0 | 1 | 1 | 1 | e1000_fc_tx_pause
+ * 0 | 1 | 1 | 1 | E1000_FC_TX_PAUSE
*
*/
else if (!(mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc = e1000_fc_tx_pause;
+ hw->fc = E1000_FC_TX_PAUSE;
DEBUGOUT("Flow Control = TX PAUSE frames only.\n");
}
/* For transmitting PAUSE frames ONLY.
@@ -2715,14 +2809,14 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* LOCAL DEVICE | LINK PARTNER
* PAUSE | ASM_DIR | PAUSE | ASM_DIR | Result
*-------|---------|-------|---------|--------------------
- * 1 | 1 | 0 | 1 | e1000_fc_rx_pause
+ * 1 | 1 | 0 | 1 | E1000_FC_RX_PAUSE
*
*/
else if ((mii_nway_adv_reg & NWAY_AR_PAUSE) &&
(mii_nway_adv_reg & NWAY_AR_ASM_DIR) &&
!(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) &&
(mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) {
- hw->fc = e1000_fc_rx_pause;
+ hw->fc = E1000_FC_RX_PAUSE;
DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
}
/* Per the IEEE spec, at this point flow control should be
@@ -2745,13 +2839,13 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
* be asked to delay transmission of packets than asking
* our link partner to pause transmission of frames.
*/
- else if ((hw->original_fc == e1000_fc_none ||
- hw->original_fc == e1000_fc_tx_pause) ||
+ else if ((hw->original_fc == E1000_FC_NONE ||
+ hw->original_fc == E1000_FC_TX_PAUSE) ||
hw->fc_strict_ieee) {
- hw->fc = e1000_fc_none;
+ hw->fc = E1000_FC_NONE;
DEBUGOUT("Flow Control = NONE.\n");
} else {
- hw->fc = e1000_fc_rx_pause;
+ hw->fc = E1000_FC_RX_PAUSE;
DEBUGOUT("Flow Control = RX PAUSE frames only.\n");
}
@@ -2766,7 +2860,7 @@ e1000_config_fc_after_link_up(struct e1000_hw *hw)
}
if (duplex == HALF_DUPLEX)
- hw->fc = e1000_fc_none;
+ hw->fc = E1000_FC_NONE;
/* Now we call a subroutine to actually force the MAC
* controller to use the correct flow control settings.
@@ -3417,9 +3511,8 @@ e1000_read_phy_reg(struct e1000_hw *hw,
return ret_val;
}
-int32_t
-e1000_read_phy_reg_ex(struct e1000_hw *hw,
- uint32_t reg_addr,
+static int32_t
+e1000_read_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
uint16_t *phy_data)
{
uint32_t i;
@@ -3499,8 +3592,7 @@ e1000_read_phy_reg_ex(struct e1000_hw *hw,
* data - data to write to the PHY
******************************************************************************/
int32_t
-e1000_write_phy_reg(struct e1000_hw *hw,
- uint32_t reg_addr,
+e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr,
uint16_t phy_data)
{
uint32_t ret_val;
@@ -3557,10 +3649,9 @@ e1000_write_phy_reg(struct e1000_hw *hw,
return ret_val;
}
-int32_t
-e1000_write_phy_reg_ex(struct e1000_hw *hw,
- uint32_t reg_addr,
- uint16_t phy_data)
+static int32_t
+e1000_write_phy_reg_ex(struct e1000_hw *hw, uint32_t reg_addr,
+ uint16_t phy_data)
{
uint32_t i;
uint32_t mdic = 0;
@@ -3711,7 +3802,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
swfw = E1000_SWFW_PHY0_SM;
}
if (e1000_swfw_sync_acquire(hw, swfw)) {
- e1000_release_software_semaphore(hw);
+ DEBUGOUT("Unable to acquire swfw sync\n");
return -E1000_ERR_SWFW_SYNC;
}
/* Read the device control register and assert the E1000_CTRL_PHY_RST
@@ -3734,6 +3825,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw)
if (hw->mac_type >= e1000_82571)
mdelay(10);
+
e1000_swfw_sync_release(hw, swfw);
} else {
/* Read the Extended Device Control Register, assert the PHY_RESET_DIR
@@ -3792,15 +3884,14 @@ e1000_phy_reset(struct e1000_hw *hw)
if (ret_val)
return E1000_SUCCESS;
- switch (hw->mac_type) {
- case e1000_82541_rev_2:
- case e1000_82571:
- case e1000_82572:
- case e1000_ich8lan:
+ switch (hw->phy_type) {
+ case e1000_phy_igp:
+ case e1000_phy_igp_2:
+ case e1000_phy_igp_3:
+ case e1000_phy_ife:
ret_val = e1000_phy_hw_reset(hw);
if (ret_val)
return ret_val;
-
break;
default:
ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
@@ -3936,7 +4027,7 @@ e1000_kumeran_lock_loss_workaround(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
******************************************************************************/
-int32_t
+static int32_t
e1000_detect_gig_phy(struct e1000_hw *hw)
{
int32_t phy_init_status, ret_val;
@@ -3945,6 +4036,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw)
DEBUGFUNC("e1000_detect_gig_phy");
+ if (hw->phy_id != 0)
+ return E1000_SUCCESS;
+
/* The 82571 firmware may still be configuring the PHY. In this
* case, we cannot access the PHY until the configuration is done. So
* we explicitly set the PHY values. */
@@ -4061,7 +4155,8 @@ e1000_phy_igp_get_info(struct e1000_hw *hw,
struct e1000_phy_info *phy_info)
{
int32_t ret_val;
- uint16_t phy_data, polarity, min_length, max_length, average;
+ uint16_t phy_data, min_length, max_length, average;
+ e1000_rev_polarity polarity;
DEBUGFUNC("e1000_phy_igp_get_info");
@@ -4086,8 +4181,8 @@ e1000_phy_igp_get_info(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- phy_info->mdix_mode = (phy_data & IGP01E1000_PSSR_MDIX) >>
- IGP01E1000_PSSR_MDIX_SHIFT;
+ phy_info->mdix_mode = (e1000_auto_x_mode)((phy_data & IGP01E1000_PSSR_MDIX) >>
+ IGP01E1000_PSSR_MDIX_SHIFT);
if ((phy_data & IGP01E1000_PSSR_SPEED_MASK) ==
IGP01E1000_PSSR_SPEED_1000MBPS) {
@@ -4096,10 +4191,12 @@ e1000_phy_igp_get_info(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
- SR_1000T_LOCAL_RX_STATUS_SHIFT;
- phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
- SR_1000T_REMOTE_RX_STATUS_SHIFT;
+ phy_info->local_rx = ((phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+ SR_1000T_LOCAL_RX_STATUS_SHIFT) ?
+ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
+ phy_info->remote_rx = ((phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+ SR_1000T_REMOTE_RX_STATUS_SHIFT) ?
+ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
/* Get cable length */
ret_val = e1000_get_cable_length(hw, &min_length, &max_length);
@@ -4135,7 +4232,8 @@ e1000_phy_ife_get_info(struct e1000_hw *hw,
struct e1000_phy_info *phy_info)
{
int32_t ret_val;
- uint16_t phy_data, polarity;
+ uint16_t phy_data;
+ e1000_rev_polarity polarity;
DEBUGFUNC("e1000_phy_ife_get_info");
@@ -4146,8 +4244,9 @@ e1000_phy_ife_get_info(struct e1000_hw *hw,
if (ret_val)
return ret_val;
phy_info->polarity_correction =
- (phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >>
- IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT;
+ ((phy_data & IFE_PSC_AUTO_POLARITY_DISABLE) >>
+ IFE_PSC_AUTO_POLARITY_DISABLE_SHIFT) ?
+ e1000_polarity_reversal_disabled : e1000_polarity_reversal_enabled;
if (phy_info->polarity_correction == e1000_polarity_reversal_enabled) {
ret_val = e1000_check_polarity(hw, &polarity);
@@ -4155,8 +4254,9 @@ e1000_phy_ife_get_info(struct e1000_hw *hw,
return ret_val;
} else {
/* Polarity is forced. */
- polarity = (phy_data & IFE_PSC_FORCE_POLARITY) >>
- IFE_PSC_FORCE_POLARITY_SHIFT;
+ polarity = ((phy_data & IFE_PSC_FORCE_POLARITY) >>
+ IFE_PSC_FORCE_POLARITY_SHIFT) ?
+ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
}
phy_info->cable_polarity = polarity;
@@ -4164,9 +4264,9 @@ e1000_phy_ife_get_info(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- phy_info->mdix_mode =
- (phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >>
- IFE_PMC_MDIX_MODE_SHIFT;
+ phy_info->mdix_mode = (e1000_auto_x_mode)
+ ((phy_data & (IFE_PMC_AUTO_MDIX | IFE_PMC_FORCE_MDIX)) >>
+ IFE_PMC_MDIX_MODE_SHIFT);
return E1000_SUCCESS;
}
@@ -4182,7 +4282,8 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
struct e1000_phy_info *phy_info)
{
int32_t ret_val;
- uint16_t phy_data, polarity;
+ uint16_t phy_data;
+ e1000_rev_polarity polarity;
DEBUGFUNC("e1000_phy_m88_get_info");
@@ -4195,11 +4296,14 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
return ret_val;
phy_info->extended_10bt_distance =
- (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
- M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+ ((phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE) >>
+ M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT) ?
+ e1000_10bt_ext_dist_enable_lower : e1000_10bt_ext_dist_enable_normal;
+
phy_info->polarity_correction =
- (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
- M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+ ((phy_data & M88E1000_PSCR_POLARITY_REVERSAL) >>
+ M88E1000_PSCR_POLARITY_REVERSAL_SHIFT) ?
+ e1000_polarity_reversal_disabled : e1000_polarity_reversal_enabled;
/* Check polarity status */
ret_val = e1000_check_polarity(hw, &polarity);
@@ -4211,15 +4315,15 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX) >>
- M88E1000_PSSR_MDIX_SHIFT;
+ phy_info->mdix_mode = (e1000_auto_x_mode)((phy_data & M88E1000_PSSR_MDIX) >>
+ M88E1000_PSSR_MDIX_SHIFT);
if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
/* Cable Length Estimation and Local/Remote Receiver Information
* are only valid at 1000 Mbps.
*/
if (hw->phy_type != e1000_phy_gg82563) {
- phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
+ phy_info->cable_length = (e1000_cable_length)((phy_data & M88E1000_PSSR_CABLE_LENGTH) >>
M88E1000_PSSR_CABLE_LENGTH_SHIFT);
} else {
ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE,
@@ -4227,18 +4331,20 @@ e1000_phy_m88_get_info(struct e1000_hw *hw,
if (ret_val)
return ret_val;
- phy_info->cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH;
+ phy_info->cable_length = (e1000_cable_length)(phy_data & GG82563_DSPD_CABLE_LENGTH);
}
ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data);
if (ret_val)
return ret_val;
- phy_info->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) >>
- SR_1000T_LOCAL_RX_STATUS_SHIFT;
+ phy_info->local_rx = ((phy_data & SR_1000T_LOCAL_RX_STATUS) >>
+ SR_1000T_LOCAL_RX_STATUS_SHIFT) ?
+ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
+ phy_info->remote_rx = ((phy_data & SR_1000T_REMOTE_RX_STATUS) >>
+ SR_1000T_REMOTE_RX_STATUS_SHIFT) ?
+ e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok;
- phy_info->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) >>
- SR_1000T_REMOTE_RX_STATUS_SHIFT;
}
return E1000_SUCCESS;
@@ -4441,7 +4547,7 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
eeprom->use_eewr = FALSE;
break;
case e1000_ich8lan:
- {
+ {
int32_t i = 0;
uint32_t flash_size = E1000_READ_ICH8_REG(hw, ICH8_FLASH_GFPREG);
@@ -4468,7 +4574,7 @@ e1000_init_eeprom_params(struct e1000_hw *hw)
hw->flash_bank_size /= 2 * sizeof(uint16_t);
break;
- }
+ }
default:
break;
}
@@ -4800,7 +4906,7 @@ e1000_release_eeprom(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-int32_t
+static int32_t
e1000_spi_eeprom_ready(struct e1000_hw *hw)
{
uint16_t retry_count = 0;
@@ -4854,44 +4960,43 @@ e1000_read_eeprom(struct e1000_hw *hw,
{
struct e1000_eeprom_info *eeprom = &hw->eeprom;
uint32_t i = 0;
- int32_t ret_val;
DEBUGFUNC("e1000_read_eeprom");
+ /* If eeprom is not yet detected, do so now */
+ if (eeprom->word_size == 0)
+ e1000_init_eeprom_params(hw);
+
/* A check for invalid values: offset too large, too many words, and not
* enough words.
*/
if ((offset >= eeprom->word_size) || (words > eeprom->word_size - offset) ||
(words == 0)) {
- DEBUGOUT("\"words\" parameter out of bounds\n");
+ DEBUGOUT2("\"words\" parameter out of bounds. Words = %d, size = %d\n", offset, eeprom->word_size);
return -E1000_ERR_EEPROM;
}
- /* FLASH reads without acquiring the semaphore are safe */
+ /* EEPROM's that don't use EERD to read require us to bit-bang the SPI
+ * directly. In this case, we need to acquire the EEPROM so that
+ * FW or other port software does not interrupt.
+ */
if (e1000_is_onboard_nvm_eeprom(hw) == TRUE &&
hw->eeprom.use_eerd == FALSE) {
- switch (hw->mac_type) {
- case e1000_80003es2lan:
- break;
- default:
- /* Prepare the EEPROM for reading */
- if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
- return -E1000_ERR_EEPROM;
- break;
- }
+ /* Prepare the EEPROM for bit-bang reading */
+ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS)
+ return -E1000_ERR_EEPROM;
}
- if (eeprom->use_eerd == TRUE) {
- ret_val = e1000_read_eeprom_eerd(hw, offset, words, data);
- if ((e1000_is_onboard_nvm_eeprom(hw) == TRUE) ||
- (hw->mac_type != e1000_82573))
- e1000_release_eeprom(hw);
- return ret_val;
- }
+ /* Eerd register EEPROM access requires no eeprom aquire/release */
+ if (eeprom->use_eerd == TRUE)
+ return e1000_read_eeprom_eerd(hw, offset, words, data);
+ /* ICH EEPROM access is done via the ICH flash controller */
if (eeprom->type == e1000_eeprom_ich8)
return e1000_read_eeprom_ich8(hw, offset, words, data);
+ /* Set up the SPI or Microwire EEPROM for bit-bang reading. We have
+ * acquired the EEPROM at this point, so any returns should relase it */
if (eeprom->type == e1000_eeprom_spi) {
uint16_t word_in;
uint8_t read_opcode = EEPROM_READ_OPCODE_SPI;
@@ -5206,6 +5311,10 @@ e1000_write_eeprom(struct e1000_hw *hw,
DEBUGFUNC("e1000_write_eeprom");
+ /* If eeprom is not yet detected, do so now */
+ if (eeprom->word_size == 0)
+ e1000_init_eeprom_params(hw);
+
/* A check for invalid values: offset too large, too many words, and not
* enough words.
*/
@@ -5248,7 +5357,7 @@ e1000_write_eeprom(struct e1000_hw *hw,
* data - pointer to array of 8 bit words to be written to the EEPROM
*
*****************************************************************************/
-int32_t
+static int32_t
e1000_write_eeprom_spi(struct e1000_hw *hw,
uint16_t offset,
uint16_t words,
@@ -5314,7 +5423,7 @@ e1000_write_eeprom_spi(struct e1000_hw *hw,
* data - pointer to array of 16 bit words to be written to the EEPROM
*
*****************************************************************************/
-int32_t
+static int32_t
e1000_write_eeprom_microwire(struct e1000_hw *hw,
uint16_t offset,
uint16_t words,
@@ -5411,10 +5520,8 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
int32_t error = E1000_SUCCESS;
uint32_t old_bank_offset = 0;
uint32_t new_bank_offset = 0;
- uint32_t sector_retries = 0;
uint8_t low_byte = 0;
uint8_t high_byte = 0;
- uint8_t temp_byte = 0;
boolean_t sector_write_failed = FALSE;
if (hw->mac_type == e1000_82573) {
@@ -5467,41 +5574,46 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
e1000_erase_ich8_4k_segment(hw, 0);
}
- do {
- sector_write_failed = FALSE;
- /* Loop for every byte in the shadow RAM,
- * which is in units of words. */
- for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
- /* Determine whether to write the value stored
- * in the other NVM bank or a modified value stored
- * in the shadow RAM */
- if (hw->eeprom_shadow_ram[i].modified == TRUE) {
- low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
- e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
- &temp_byte);
- udelay(100);
- error = e1000_verify_write_ich8_byte(hw,
- (i << 1) + new_bank_offset,
- low_byte);
- if (error != E1000_SUCCESS)
- sector_write_failed = TRUE;
+ sector_write_failed = FALSE;
+ /* Loop for every byte in the shadow RAM,
+ * which is in units of words. */
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ /* Determine whether to write the value stored
+ * in the other NVM bank or a modified value stored
+ * in the shadow RAM */
+ if (hw->eeprom_shadow_ram[i].modified == TRUE) {
+ low_byte = (uint8_t)hw->eeprom_shadow_ram[i].eeprom_word;
+ udelay(100);
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset, low_byte);
+
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ else {
high_byte =
(uint8_t)(hw->eeprom_shadow_ram[i].eeprom_word >> 8);
- e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
- &temp_byte);
- udelay(100);
- } else {
- e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
- &low_byte);
udelay(100);
- error = e1000_verify_write_ich8_byte(hw,
- (i << 1) + new_bank_offset, low_byte);
- if (error != E1000_SUCCESS)
- sector_write_failed = TRUE;
+ }
+ } else {
+ e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset,
+ &low_byte);
+ udelay(100);
+ error = e1000_verify_write_ich8_byte(hw,
+ (i << 1) + new_bank_offset, low_byte);
+
+ if (error != E1000_SUCCESS)
+ sector_write_failed = TRUE;
+ else {
e1000_read_ich8_byte(hw, (i << 1) + old_bank_offset + 1,
&high_byte);
+ udelay(100);
}
+ }
+ /* If the write of the low byte was successful, go ahread and
+ * write the high byte while checking to make sure that if it
+ * is the signature byte, then it is handled properly */
+ if (sector_write_failed == FALSE) {
/* If the word is 0x13, then make sure the signature bits
* (15:14) are 11b until the commit has completed.
* This will allow us to write 10b which indicates the
@@ -5512,45 +5624,45 @@ e1000_commit_shadow_ram(struct e1000_hw *hw)
high_byte = E1000_ICH8_NVM_SIG_MASK | high_byte;
error = e1000_verify_write_ich8_byte(hw,
- (i << 1) + new_bank_offset + 1, high_byte);
+ (i << 1) + new_bank_offset + 1, high_byte);
if (error != E1000_SUCCESS)
sector_write_failed = TRUE;
- if (sector_write_failed == FALSE) {
- /* Clear the now not used entry in the cache */
- hw->eeprom_shadow_ram[i].modified = FALSE;
- hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
- }
+ } else {
+ /* If the write failed then break from the loop and
+ * return an error */
+ break;
}
+ }
- /* Don't bother writing the segment valid bits if sector
- * programming failed. */
- if (sector_write_failed == FALSE) {
- /* Finally validate the new segment by setting bit 15:14
- * to 10b in word 0x13 , this can be done without an
- * erase as well since these bits are 11 to start with
- * and we need to change bit 14 to 0b */
- e1000_read_ich8_byte(hw,
- E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
- &high_byte);
- high_byte &= 0xBF;
+ /* Don't bother writing the segment valid bits if sector
+ * programming failed. */
+ if (sector_write_failed == FALSE) {
+ /* Finally validate the new segment by setting bit 15:14
+ * to 10b in word 0x13 , this can be done without an
+ * erase as well since these bits are 11 to start with
+ * and we need to change bit 14 to 0b */
+ e1000_read_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
+ &high_byte);
+ high_byte &= 0xBF;
+ error = e1000_verify_write_ich8_byte(hw,
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset, high_byte);
+ /* And invalidate the previously valid segment by setting
+ * its signature word (0x13) high_byte to 0b. This can be
+ * done without an erase because flash erase sets all bits
+ * to 1's. We can write 1's to 0's without an erase */
+ if (error == E1000_SUCCESS) {
error = e1000_verify_write_ich8_byte(hw,
- E1000_ICH8_NVM_SIG_WORD * 2 + 1 + new_bank_offset,
- high_byte);
- if (error != E1000_SUCCESS)
- sector_write_failed = TRUE;
+ E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset, 0);
+ }
- /* And invalidate the previously valid segment by setting
- * its signature word (0x13) high_byte to 0b. This can be
- * done without an erase because flash erase sets all bits
- * to 1's. We can write 1's to 0's without an erase */
- error = e1000_verify_write_ich8_byte(hw,
- E1000_ICH8_NVM_SIG_WORD * 2 + 1 + old_bank_offset,
- 0);
- if (error != E1000_SUCCESS)
- sector_write_failed = TRUE;
+ /* Clear the now not used entry in the cache */
+ for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
+ hw->eeprom_shadow_ram[i].modified = FALSE;
+ hw->eeprom_shadow_ram[i].eeprom_word = 0xFFFF;
}
- } while (++sector_retries < 10 && sector_write_failed == TRUE);
+ }
}
return error;
@@ -5640,99 +5752,6 @@ e1000_init_rx_addrs(struct e1000_hw *hw)
}
/******************************************************************************
- * Updates the MAC's list of multicast addresses.
- *
- * hw - Struct containing variables accessed by shared code
- * mc_addr_list - the list of new multicast addresses
- * mc_addr_count - number of addresses
- * pad - number of bytes between addresses in the list
- * rar_used_count - offset where to start adding mc addresses into the RAR's
- *
- * The given list replaces any existing list. Clears the last 15 receive
- * address registers and the multicast table. Uses receive address registers
- * for the first 15 multicast addresses, and hashes the rest into the
- * multicast table.
- *****************************************************************************/
-#if 0
-void
-e1000_mc_addr_list_update(struct e1000_hw *hw,
- uint8_t *mc_addr_list,
- uint32_t mc_addr_count,
- uint32_t pad,
- uint32_t rar_used_count)
-{
- uint32_t hash_value;
- uint32_t i;
- uint32_t num_rar_entry;
- uint32_t num_mta_entry;
-
- DEBUGFUNC("e1000_mc_addr_list_update");
-
- /* Set the new number of MC addresses that we are being requested to use. */
- hw->num_mc_addrs = mc_addr_count;
-
- /* Clear RAR[1-15] */
- DEBUGOUT(" Clearing RAR[1-15]\n");
- num_rar_entry = E1000_RAR_ENTRIES;
- if (hw->mac_type == e1000_ich8lan)
- num_rar_entry = E1000_RAR_ENTRIES_ICH8LAN;
- /* Reserve a spot for the Locally Administered Address to work around
- * an 82571 issue in which a reset on one port will reload the MAC on
- * the other port. */
- if ((hw->mac_type == e1000_82571) && (hw->laa_is_present == TRUE))
- num_rar_entry -= 1;
-
- for (i = rar_used_count; i < num_rar_entry; i++) {
- E1000_WRITE_REG_ARRAY(hw, RA, (i << 1), 0);
- E1000_WRITE_FLUSH(hw);
- E1000_WRITE_REG_ARRAY(hw, RA, ((i << 1) + 1), 0);
- E1000_WRITE_FLUSH(hw);
- }
-
- /* Clear the MTA */
- DEBUGOUT(" Clearing MTA\n");
- num_mta_entry = E1000_NUM_MTA_REGISTERS;
- if (hw->mac_type == e1000_ich8lan)
- num_mta_entry = E1000_NUM_MTA_REGISTERS_ICH8LAN;
- for (i = 0; i < num_mta_entry; i++) {
- E1000_WRITE_REG_ARRAY(hw, MTA, i, 0);
- E1000_WRITE_FLUSH(hw);
- }
-
- /* Add the new addresses */
- for (i = 0; i < mc_addr_count; i++) {
- DEBUGOUT(" Adding the multicast addresses:\n");
- DEBUGOUT7(" MC Addr #%d =%.2X %.2X %.2X %.2X %.2X %.2X\n", i,
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad)],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 1],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 2],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 3],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 4],
- mc_addr_list[i * (ETH_LENGTH_OF_ADDRESS + pad) + 5]);
-
- hash_value = e1000_hash_mc_addr(hw,
- mc_addr_list +
- (i * (ETH_LENGTH_OF_ADDRESS + pad)));
-
- DEBUGOUT1(" Hash value = 0x%03X\n", hash_value);
-
- /* Place this multicast address in the RAR if there is room, *
- * else put it in the MTA
- */
- if (rar_used_count < num_rar_entry) {
- e1000_rar_set(hw,
- mc_addr_list + (i * (ETH_LENGTH_OF_ADDRESS + pad)),
- rar_used_count);
- rar_used_count++;
- } else {
- e1000_mta_set(hw, hash_value);
- }
- }
- DEBUGOUT("MC Update Complete\n");
-}
-#endif /* 0 */
-
-/******************************************************************************
* Hashes an address to determine its location in the multicast table
*
* hw - Struct containing variables accessed by shared code
@@ -6290,7 +6309,7 @@ e1000_led_off(struct e1000_hw *hw)
*
* hw - Struct containing variables accessed by shared code
*****************************************************************************/
-void
+static void
e1000_clear_hw_cntrs(struct e1000_hw *hw)
{
volatile uint32_t temp;
@@ -6539,6 +6558,8 @@ e1000_tbi_adjust_stats(struct e1000_hw *hw,
void
e1000_get_bus_info(struct e1000_hw *hw)
{
+ int32_t ret_val;
+ uint16_t pci_ex_link_status;
uint32_t status;
switch (hw->mac_type) {
@@ -6548,18 +6569,25 @@ e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_speed = e1000_bus_speed_unknown;
hw->bus_width = e1000_bus_width_unknown;
break;
+ case e1000_82571:
case e1000_82572:
case e1000_82573:
+ case e1000_80003es2lan:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
- hw->bus_width = e1000_bus_width_pciex_1;
+ ret_val = e1000_read_pcie_cap_reg(hw,
+ PCI_EX_LINK_STATUS,
+ &pci_ex_link_status);
+ if (ret_val)
+ hw->bus_width = e1000_bus_width_unknown;
+ else
+ hw->bus_width = (pci_ex_link_status & PCI_EX_LINK_WIDTH_MASK) >>
+ PCI_EX_LINK_WIDTH_SHIFT;
break;
- case e1000_82571:
case e1000_ich8lan:
- case e1000_80003es2lan:
hw->bus_type = e1000_bus_type_pci_express;
hw->bus_speed = e1000_bus_speed_2500;
- hw->bus_width = e1000_bus_width_pciex_4;
+ hw->bus_width = e1000_bus_width_pciex_1;
break;
default:
status = E1000_READ_REG(hw, STATUS);
@@ -6593,25 +6621,6 @@ e1000_get_bus_info(struct e1000_hw *hw)
break;
}
}
-/******************************************************************************
- * Reads a value from one of the devices registers using port I/O (as opposed
- * memory mapped I/O). Only 82544 and newer devices support port I/O.
- *
- * hw - Struct containing variables accessed by shared code
- * offset - offset to read from
- *****************************************************************************/
-#if 0
-uint32_t
-e1000_read_reg_io(struct e1000_hw *hw,
- uint32_t offset)
-{
- unsigned long io_addr = hw->io_base;
- unsigned long io_data = hw->io_base + 4;
-
- e1000_io_write(hw, io_addr, offset);
- return e1000_io_read(hw, io_data);
-}
-#endif /* 0 */
/******************************************************************************
* Writes a value to one of the devices registers using port I/O (as opposed to
@@ -6633,7 +6642,6 @@ e1000_write_reg_io(struct e1000_hw *hw,
e1000_io_write(hw, io_data, value);
}
-
/******************************************************************************
* Estimates the cable length.
*
@@ -6842,7 +6850,7 @@ e1000_get_cable_length(struct e1000_hw *hw,
*****************************************************************************/
static int32_t
e1000_check_polarity(struct e1000_hw *hw,
- uint16_t *polarity)
+ e1000_rev_polarity *polarity)
{
int32_t ret_val;
uint16_t phy_data;
@@ -6856,8 +6864,10 @@ e1000_check_polarity(struct e1000_hw *hw,
&phy_data);
if (ret_val)
return ret_val;
- *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY) >>
- M88E1000_PSSR_REV_POLARITY_SHIFT;
+ *polarity = ((phy_data & M88E1000_PSSR_REV_POLARITY) >>
+ M88E1000_PSSR_REV_POLARITY_SHIFT) ?
+ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
+
} else if (hw->phy_type == e1000_phy_igp ||
hw->phy_type == e1000_phy_igp_3 ||
hw->phy_type == e1000_phy_igp_2) {
@@ -6879,19 +6889,22 @@ e1000_check_polarity(struct e1000_hw *hw,
return ret_val;
/* Check the polarity bits */
- *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ? 1 : 0;
+ *polarity = (phy_data & IGP01E1000_PHY_POLARITY_MASK) ?
+ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
} else {
/* For 10 Mbps, read the polarity bit in the status register. (for
* 100 Mbps this bit is always 0) */
- *polarity = phy_data & IGP01E1000_PSSR_POLARITY_REVERSED;
+ *polarity = (phy_data & IGP01E1000_PSSR_POLARITY_REVERSED) ?
+ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
}
} else if (hw->phy_type == e1000_phy_ife) {
ret_val = e1000_read_phy_reg(hw, IFE_PHY_EXTENDED_STATUS_CONTROL,
&phy_data);
if (ret_val)
return ret_val;
- *polarity = (phy_data & IFE_PESC_POLARITY_REVERSED) >>
- IFE_PESC_POLARITY_REVERSED_SHIFT;
+ *polarity = ((phy_data & IFE_PESC_POLARITY_REVERSED) >>
+ IFE_PESC_POLARITY_REVERSED_SHIFT) ?
+ e1000_rev_polarity_reversed : e1000_rev_polarity_normal;
}
return E1000_SUCCESS;
}
@@ -7259,7 +7272,7 @@ e1000_set_d3_lplu_state(struct e1000_hw *hw,
} else if (hw->smart_speed == e1000_smart_speed_off) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
&phy_data);
- if (ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
@@ -7369,7 +7382,7 @@ e1000_set_d0_lplu_state(struct e1000_hw *hw,
} else if (hw->smart_speed == e1000_smart_speed_off) {
ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
&phy_data);
- if (ret_val)
+ if (ret_val)
return ret_val;
phy_data &= ~IGP01E1000_PSCFR_SMART_SPEED;
@@ -7475,7 +7488,7 @@ e1000_set_vco_speed(struct e1000_hw *hw)
*
* returns: - E1000_SUCCESS .
****************************************************************************/
-int32_t
+static int32_t
e1000_host_if_read_cookie(struct e1000_hw * hw, uint8_t *buffer)
{
uint8_t i;
@@ -7686,7 +7699,7 @@ e1000_check_mng_mode(struct e1000_hw *hw)
****************************************************************************/
int32_t
e1000_mng_write_dhcp_info(struct e1000_hw * hw, uint8_t *buffer,
- uint16_t length)
+ uint16_t length)
{
int32_t ret_val;
struct e1000_host_mng_command_header hdr;
@@ -7716,7 +7729,7 @@ e1000_mng_write_dhcp_info(struct e1000_hw * hw, uint8_t *buffer,
*
* returns - checksum of buffer contents.
****************************************************************************/
-uint8_t
+static uint8_t
e1000_calculate_mng_checksum(char *buffer, uint32_t length)
{
uint8_t sum = 0;
@@ -7914,32 +7927,6 @@ e1000_set_pci_express_master_disable(struct e1000_hw *hw)
E1000_WRITE_REG(hw, CTRL, ctrl);
}
-/***************************************************************************
- *
- * Enables PCI-Express master access.
- *
- * hw: Struct containing variables accessed by shared code
- *
- * returns: - none.
- *
- ***************************************************************************/
-#if 0
-void
-e1000_enable_pciex_master(struct e1000_hw *hw)
-{
- uint32_t ctrl;
-
- DEBUGFUNC("e1000_enable_pciex_master");
-
- if (hw->bus_type != e1000_bus_type_pci_express)
- return;
-
- ctrl = E1000_READ_REG(hw, CTRL);
- ctrl &= ~E1000_CTRL_GIO_MASTER_DISABLE;
- E1000_WRITE_REG(hw, CTRL, ctrl);
-}
-#endif /* 0 */
-
/*******************************************************************************
*
* Disables PCI-Express master access and verifies there are no pending requests
@@ -8063,7 +8050,6 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw)
msleep(1);
timeout--;
}
-
if (!timeout) {
DEBUGOUT("MNG configuration cycle has not completed.\n");
return -E1000_ERR_RESET;
@@ -8172,8 +8158,9 @@ e1000_get_software_semaphore(struct e1000_hw *hw)
DEBUGFUNC("e1000_get_software_semaphore");
- if (hw->mac_type != e1000_80003es2lan)
+ if (hw->mac_type != e1000_80003es2lan) {
return E1000_SUCCESS;
+ }
while (timeout) {
swsm = E1000_READ_REG(hw, SWSM);
@@ -8206,8 +8193,9 @@ e1000_release_software_semaphore(struct e1000_hw *hw)
DEBUGFUNC("e1000_release_software_semaphore");
- if (hw->mac_type != e1000_80003es2lan)
+ if (hw->mac_type != e1000_80003es2lan) {
return;
+ }
swsm = E1000_READ_REG(hw, SWSM);
/* Release the SW semaphores.*/
@@ -8241,7 +8229,7 @@ e1000_check_phy_reset_block(struct e1000_hw *hw)
if (hw->mac_type > e1000_82547_rev_2)
manc = E1000_READ_REG(hw, MANC);
return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ?
- E1000_BLK_PHY_RESET : E1000_SUCCESS;
+ E1000_BLK_PHY_RESET : E1000_SUCCESS;
}
static uint8_t
@@ -8377,66 +8365,6 @@ e1000_release_software_flag(struct e1000_hw *hw)
return;
}
-/***************************************************************************
- *
- * Disable dynamic power down mode in ife PHY.
- * It can be used to workaround band-gap problem.
- *
- * hw: Struct containing variables accessed by shared code
- *
- ***************************************************************************/
-#if 0
-int32_t
-e1000_ife_disable_dynamic_power_down(struct e1000_hw *hw)
-{
- uint16_t phy_data;
- int32_t ret_val = E1000_SUCCESS;
-
- DEBUGFUNC("e1000_ife_disable_dynamic_power_down");
-
- if (hw->phy_type == e1000_phy_ife) {
- ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
- if (ret_val)
- return ret_val;
-
- phy_data |= IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
- ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
- }
-
- return ret_val;
-}
-#endif /* 0 */
-
-/***************************************************************************
- *
- * Enable dynamic power down mode in ife PHY.
- * It can be used to workaround band-gap problem.
- *
- * hw: Struct containing variables accessed by shared code
- *
- ***************************************************************************/
-#if 0
-int32_t
-e1000_ife_enable_dynamic_power_down(struct e1000_hw *hw)
-{
- uint16_t phy_data;
- int32_t ret_val = E1000_SUCCESS;
-
- DEBUGFUNC("e1000_ife_enable_dynamic_power_down");
-
- if (hw->phy_type == e1000_phy_ife) {
- ret_val = e1000_read_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, &phy_data);
- if (ret_val)
- return ret_val;
-
- phy_data &= ~IFE_PSC_DISABLE_DYNAMIC_POWER_DOWN;
- ret_val = e1000_write_phy_reg(hw, IFE_PHY_SPECIAL_CONTROL, phy_data);
- }
-
- return ret_val;
-}
-#endif /* 0 */
-
/******************************************************************************
* Reads a 16 bit word or words from the EEPROM using the ICH8's flash access
* register.
@@ -8832,20 +8760,22 @@ static int32_t
e1000_verify_write_ich8_byte(struct e1000_hw *hw, uint32_t index, uint8_t byte)
{
int32_t error = E1000_SUCCESS;
- int32_t program_retries;
- uint8_t temp_byte;
+ int32_t program_retries = 0;
- e1000_write_ich8_byte(hw, index, byte);
- udelay(100);
+ DEBUGOUT2("Byte := %2.2X Offset := %d\n", byte, index);
- for (program_retries = 0; program_retries < 100; program_retries++) {
- e1000_read_ich8_byte(hw, index, &temp_byte);
- if (temp_byte == byte)
- break;
- udelay(10);
- e1000_write_ich8_byte(hw, index, byte);
- udelay(100);
+ error = e1000_write_ich8_byte(hw, index, byte);
+
+ if (error != E1000_SUCCESS) {
+ for (program_retries = 0; program_retries < 100; program_retries++) {
+ DEBUGOUT2("Retrying \t Byte := %2.2X Offset := %d\n", byte, index);
+ error = e1000_write_ich8_byte(hw, index, byte);
+ udelay(100);
+ if (error == E1000_SUCCESS)
+ break;
+ }
}
+
if (program_retries == 100)
error = E1000_ERR_EEPROM;
@@ -8886,39 +8816,27 @@ e1000_read_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t *data)
}
/******************************************************************************
- * Writes a word to the NVM using the ICH8 flash access registers.
+ * Erases the bank specified. Each bank may be a 4, 8 or 64k block. Banks are 0
+ * based.
*
* hw - pointer to e1000_hw structure
- * index - The starting byte index of the word to read.
- * data - The word to write to the NVM.
- *****************************************************************************/
-#if 0
-int32_t
-e1000_write_ich8_word(struct e1000_hw *hw, uint32_t index, uint16_t data)
-{
- int32_t status = E1000_SUCCESS;
- status = e1000_write_ich8_data(hw, index, 2, data);
- return status;
-}
-#endif /* 0 */
-
-/******************************************************************************
- * Erases the bank specified. Each bank is a 4k block. Segments are 0 based.
- * segment N is 4096 * N + flash_reg_addr.
+ * bank - 0 for first bank, 1 for second bank
*
- * hw - pointer to e1000_hw structure
- * segment - 0 for first segment, 1 for second segment, etc.
+ * Note that this function may actually erase as much as 8 or 64 KBytes. The
+ * amount of NVM used in each bank is a *minimum* of 4 KBytes, but in fact the
+ * bank size may be 4, 8 or 64 KBytes
*****************************************************************************/
-static int32_t
-e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
+int32_t
+e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t bank)
{
union ich8_hws_flash_status hsfsts;
union ich8_hws_flash_ctrl hsflctl;
uint32_t flash_linear_address;
int32_t count = 0;
int32_t error = E1000_ERR_EEPROM;
- int32_t iteration, seg_size;
- int32_t sector_size;
+ int32_t iteration;
+ int32_t sub_sector_size = 0;
+ int32_t bank_size;
int32_t j = 0;
int32_t error_flag = 0;
@@ -8927,22 +8845,27 @@ e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
/* Determine HW Sector size: Read BERASE bits of Hw flash Status register */
/* 00: The Hw sector is 256 bytes, hence we need to erase 16
* consecutive sectors. The start index for the nth Hw sector can be
- * calculated as = segment * 4096 + n * 256
+ * calculated as bank * 4096 + n * 256
* 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
* The start index for the nth Hw sector can be calculated
- * as = segment * 4096
- * 10: Error condition
- * 11: The Hw sector size is much bigger than the size asked to
- * erase...error condition */
+ * as bank * 4096
+ * 10: The HW sector is 8K bytes
+ * 11: The Hw sector size is 64K bytes */
if (hsfsts.hsf_status.berasesz == 0x0) {
/* Hw sector size 256 */
- sector_size = seg_size = ICH8_FLASH_SEG_SIZE_256;
+ sub_sector_size = ICH8_FLASH_SEG_SIZE_256;
+ bank_size = ICH8_FLASH_SECTOR_SIZE;
iteration = ICH8_FLASH_SECTOR_SIZE / ICH8_FLASH_SEG_SIZE_256;
} else if (hsfsts.hsf_status.berasesz == 0x1) {
- sector_size = seg_size = ICH8_FLASH_SEG_SIZE_4K;
+ bank_size = ICH8_FLASH_SEG_SIZE_4K;
+ iteration = 1;
+ } else if (hw->mac_type != e1000_ich8lan &&
+ hsfsts.hsf_status.berasesz == 0x2) {
+ /* 8K erase size invalid for ICH8 - added in for ICH9 */
+ bank_size = ICH9_FLASH_SEG_SIZE_8K;
iteration = 1;
} else if (hsfsts.hsf_status.berasesz == 0x3) {
- sector_size = seg_size = ICH8_FLASH_SEG_SIZE_64K;
+ bank_size = ICH8_FLASH_SEG_SIZE_64K;
iteration = 1;
} else {
return error;
@@ -8966,16 +8889,15 @@ e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
/* Write the last 24 bits of an index within the block into Flash
* Linear address field in Flash Address. This probably needs to
- * be calculated here based off the on-chip segment size and the
- * software segment size assumed (4K) */
- /* TBD */
- flash_linear_address = segment * sector_size + j * seg_size;
- flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK;
+ * be calculated here based off the on-chip erase sector size and
+ * the software bank size (4, 8 or 64 KBytes) */
+ flash_linear_address = bank * bank_size + j * sub_sector_size;
flash_linear_address += hw->flash_base_addr;
+ flash_linear_address &= ICH8_FLASH_LINEAR_ADDR_MASK;
E1000_WRITE_ICH8_REG(hw, ICH8_FLASH_FADDR, flash_linear_address);
- error = e1000_ich8_flash_cycle(hw, 1000000);
+ error = e1000_ich8_flash_cycle(hw, ICH8_FLASH_ERASE_TIMEOUT);
/* Check if FCERR is set to 1. If 1, clear it and try the whole
* sequence a few more times else Done */
if (error == E1000_SUCCESS) {
@@ -8999,44 +8921,6 @@ e1000_erase_ich8_4k_segment(struct e1000_hw *hw, uint32_t segment)
return error;
}
-/******************************************************************************
- *
- * Reverse duplex setting without breaking the link.
- *
- * hw: Struct containing variables accessed by shared code
- *
- *****************************************************************************/
-#if 0
-int32_t
-e1000_duplex_reversal(struct e1000_hw *hw)
-{
- int32_t ret_val;
- uint16_t phy_data;
-
- if (hw->phy_type != e1000_phy_igp_3)
- return E1000_SUCCESS;
-
- ret_val = e1000_read_phy_reg(hw, PHY_CTRL, &phy_data);
- if (ret_val)
- return ret_val;
-
- phy_data ^= MII_CR_FULL_DUPLEX;
-
- ret_val = e1000_write_phy_reg(hw, PHY_CTRL, phy_data);
- if (ret_val)
- return ret_val;
-
- ret_val = e1000_read_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, &phy_data);
- if (ret_val)
- return ret_val;
-
- phy_data |= IGP3_PHY_MISC_DUPLEX_MANUAL_SET;
- ret_val = e1000_write_phy_reg(hw, IGP3E1000_PHY_MISC_CTRL, phy_data);
-
- return ret_val;
-}
-#endif /* 0 */
-
static int32_t
e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw,
uint32_t cnf_base_addr, uint32_t cnf_size)
@@ -9071,6 +8955,14 @@ e1000_init_lcd_from_nvm_config_region(struct e1000_hw *hw,
}
+/******************************************************************************
+ * This function initializes the PHY from the NVM on ICH8 platforms. This
+ * is needed due to an issue where the NVM configuration is not properly
+ * autoloaded after power transitions. Therefore, after each PHY reset, we
+ * will load the configuration data out of the NVM manually.
+ *
+ * hw: Struct containing variables accessed by shared code
+ *****************************************************************************/
static int32_t
e1000_init_lcd_from_nvm(struct e1000_hw *hw)
{
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index a170e96251f6..112447fd8bf2 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -1,25 +1,24 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
@@ -93,11 +92,11 @@ typedef enum {
/* Flow Control Settings */
typedef enum {
- e1000_fc_none = 0,
- e1000_fc_rx_pause = 1,
- e1000_fc_tx_pause = 2,
- e1000_fc_full = 3,
- e1000_fc_default = 0xFF
+ E1000_FC_NONE = 0,
+ E1000_FC_RX_PAUSE = 1,
+ E1000_FC_TX_PAUSE = 2,
+ E1000_FC_FULL = 3,
+ E1000_FC_DEFAULT = 0xFF
} e1000_fc_type;
struct e1000_shadow_ram {
@@ -302,6 +301,9 @@ typedef enum {
#define E1000_BLK_PHY_RESET 12
#define E1000_ERR_SWFW_SYNC 13
+#define E1000_BYTE_SWAP_WORD(_value) ((((_value) & 0x00ff) << 8) | \
+ (((_value) & 0xff00) >> 8))
+
/* Function prototypes */
/* Initialization */
int32_t e1000_reset_hw(struct e1000_hw *hw);
@@ -314,7 +316,7 @@ int32_t e1000_setup_link(struct e1000_hw *hw);
int32_t e1000_phy_setup_autoneg(struct e1000_hw *hw);
void e1000_config_collision_dist(struct e1000_hw *hw);
int32_t e1000_check_for_link(struct e1000_hw *hw);
-int32_t e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t * speed, uint16_t * duplex);
+int32_t e1000_get_speed_and_duplex(struct e1000_hw *hw, uint16_t *speed, uint16_t *duplex);
int32_t e1000_force_mac_fc(struct e1000_hw *hw);
/* PHY */
@@ -322,9 +324,9 @@ int32_t e1000_read_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t *phy
int32_t e1000_write_phy_reg(struct e1000_hw *hw, uint32_t reg_addr, uint16_t data);
int32_t e1000_phy_hw_reset(struct e1000_hw *hw);
int32_t e1000_phy_reset(struct e1000_hw *hw);
-void e1000_phy_powerdown_workaround(struct e1000_hw *hw);
int32_t e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info);
int32_t e1000_validate_mdi_setting(struct e1000_hw *hw);
+void e1000_phy_powerdown_workaround(struct e1000_hw *hw);
/* EEPROM Functions */
int32_t e1000_init_eeprom_params(struct e1000_hw *hw);
@@ -393,7 +395,6 @@ int32_t e1000_read_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uin
int32_t e1000_validate_eeprom_checksum(struct e1000_hw *hw);
int32_t e1000_update_eeprom_checksum(struct e1000_hw *hw);
int32_t e1000_write_eeprom(struct e1000_hw *hw, uint16_t reg, uint16_t words, uint16_t *data);
-int32_t e1000_read_part_num(struct e1000_hw *hw, uint32_t * part_num);
int32_t e1000_read_mac_addr(struct e1000_hw * hw);
/* Filters (multicast, vlan, receive) */
@@ -420,6 +421,7 @@ void e1000_pci_set_mwi(struct e1000_hw *hw);
void e1000_pci_clear_mwi(struct e1000_hw *hw);
void e1000_read_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
void e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t * value);
+int32_t e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value);
/* Port I/O is only supported on 82544 and newer */
void e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value);
int32_t e1000_disable_pciex_master(struct e1000_hw *hw);
@@ -574,10 +576,10 @@ int32_t e1000_check_phy_reset_block(struct e1000_hw *hw);
* E1000_RAR_ENTRIES - 1 multicast addresses.
*/
#define E1000_RAR_ENTRIES 15
-#define E1000_RAR_ENTRIES_ICH8LAN 7
+#define E1000_RAR_ENTRIES_ICH8LAN 6
-#define MIN_NUMBER_OF_DESCRIPTORS 8
-#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
+#define MIN_NUMBER_OF_DESCRIPTORS 8
+#define MAX_NUMBER_OF_DESCRIPTORS 0xFFF8
/* Receive Descriptor */
struct e1000_rx_desc {
@@ -1300,6 +1302,7 @@ struct e1000_hw_stats {
uint64_t algnerrc;
uint64_t symerrs;
uint64_t rxerrc;
+ uint64_t txerrc;
uint64_t mpc;
uint64_t scc;
uint64_t ecol;
@@ -1332,8 +1335,9 @@ struct e1000_hw_stats {
uint64_t gotch;
uint64_t rnbc;
uint64_t ruc;
- uint64_t rfc;
uint64_t roc;
+ uint64_t rlerrc;
+ uint64_t rfc;
uint64_t rjc;
uint64_t mgprc;
uint64_t mgpdc;
@@ -1367,8 +1371,8 @@ struct e1000_hw_stats {
/* Structure containing variables used by the shared code (e1000_hw.c) */
struct e1000_hw {
- uint8_t *hw_addr;
- uint8_t *flash_address;
+ uint8_t __iomem *hw_addr;
+ uint8_t __iomem *flash_address;
e1000_mac_type mac_type;
e1000_phy_type phy_type;
uint32_t phy_init_script;
@@ -1440,6 +1444,7 @@ struct e1000_hw {
boolean_t tbi_compatibility_on;
boolean_t laa_is_present;
boolean_t phy_reset_disable;
+ boolean_t initialize_hw_bits_disable;
boolean_t fc_send_xon;
boolean_t fc_strict_ieee;
boolean_t report_tx_early;
@@ -1613,16 +1618,17 @@ struct e1000_hw {
#define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
#define E1000_CTRL_EXT_LINK_MODE_GMII 0x00000000
#define E1000_CTRL_EXT_LINK_MODE_TBI 0x00C00000
-#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000
+#define E1000_CTRL_EXT_LINK_MODE_KMRN 0x00000000
#define E1000_CTRL_EXT_LINK_MODE_SERDES 0x00C00000
+#define E1000_CTRL_EXT_LINK_MODE_SGMII 0x00800000
#define E1000_CTRL_EXT_WR_WMARK_MASK 0x03000000
#define E1000_CTRL_EXT_WR_WMARK_256 0x00000000
#define E1000_CTRL_EXT_WR_WMARK_320 0x01000000
#define E1000_CTRL_EXT_WR_WMARK_384 0x02000000
#define E1000_CTRL_EXT_WR_WMARK_448 0x03000000
-#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
-#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
-#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
+#define E1000_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
+#define E1000_CTRL_EXT_IAME 0x08000000 /* Interrupt acknowledge Auto-mask */
+#define E1000_CTRL_EXT_INT_TIMER_CLR 0x20000000 /* Clear Interrupt timers after IMS clear */
#define E1000_CRTL_EXT_PB_PAREN 0x01000000 /* packet buffer parity error detection enabled */
#define E1000_CTRL_EXT_DF_PAREN 0x02000000 /* descriptor FIFO parity error detection enable */
#define E1000_CTRL_EXT_GHOST_PAREN 0x40000000
@@ -2218,6 +2224,11 @@ struct e1000_host_command_info {
#define E1000_FACTPS_LAN_FUNC_SEL 0x40000000
#define E1000_FACTPS_PM_STATE_CHANGED 0x80000000
+/* PCI-Ex Config Space */
+#define PCI_EX_LINK_STATUS 0x12
+#define PCI_EX_LINK_WIDTH_MASK 0x3F0
+#define PCI_EX_LINK_WIDTH_SHIFT 4
+
/* EEPROM Commands - Microwire */
#define EEPROM_READ_OPCODE_MICROWIRE 0x6 /* EEPROM read opcode */
#define EEPROM_WRITE_OPCODE_MICROWIRE 0x5 /* EEPROM write opcode */
@@ -3120,6 +3131,7 @@ struct e1000_host_command_info {
/* I = Integrated
* E = External
*/
+#define M88_VENDOR 0x0141
#define M88E1000_E_PHY_ID 0x01410C50
#define M88E1000_I_PHY_ID 0x01410C30
#define M88E1011_I_PHY_ID 0x01410C20
@@ -3244,10 +3256,12 @@ struct e1000_host_command_info {
#define IFE_PSCL_PROBE_LEDS_OFF 0x0006 /* Force LEDs 0 and 2 off */
#define IFE_PSCL_PROBE_LEDS_ON 0x0007 /* Force LEDs 0 and 2 on */
-#define ICH8_FLASH_COMMAND_TIMEOUT 500 /* 500 ms , should be adjusted */
-#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles , should be adjusted */
+#define ICH8_FLASH_COMMAND_TIMEOUT 5000 /* 5000 uSecs - adjusted */
+#define ICH8_FLASH_ERASE_TIMEOUT 3000000 /* Up to 3 seconds - worst case */
+#define ICH8_FLASH_CYCLE_REPEAT_COUNT 10 /* 10 cycles */
#define ICH8_FLASH_SEG_SIZE_256 256
#define ICH8_FLASH_SEG_SIZE_4K 4096
+#define ICH9_FLASH_SEG_SIZE_8K 8192
#define ICH8_FLASH_SEG_SIZE_64K 65536
#define ICH8_CYCLE_READ 0x0
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 3f6a752700a1..ce0d35fe3947 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -1,25 +1,24 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
@@ -36,7 +35,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "7.2.7-k2"DRIVERNAPI
+#define DRV_VERSION "7.2.9-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -110,16 +109,24 @@ static struct pci_device_id e1000_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, e1000_pci_tbl);
+int e1000_up(struct e1000_adapter *adapter);
+void e1000_down(struct e1000_adapter *adapter);
+void e1000_reinit_locked(struct e1000_adapter *adapter);
+void e1000_reset(struct e1000_adapter *adapter);
+int e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx);
+int e1000_setup_all_tx_resources(struct e1000_adapter *adapter);
+int e1000_setup_all_rx_resources(struct e1000_adapter *adapter);
+void e1000_free_all_tx_resources(struct e1000_adapter *adapter);
+void e1000_free_all_rx_resources(struct e1000_adapter *adapter);
static int e1000_setup_tx_resources(struct e1000_adapter *adapter,
- struct e1000_tx_ring *txdr);
+ struct e1000_tx_ring *txdr);
static int e1000_setup_rx_resources(struct e1000_adapter *adapter,
- struct e1000_rx_ring *rxdr);
+ struct e1000_rx_ring *rxdr);
static void e1000_free_tx_resources(struct e1000_adapter *adapter,
- struct e1000_tx_ring *tx_ring);
+ struct e1000_tx_ring *tx_ring);
static void e1000_free_rx_resources(struct e1000_adapter *adapter,
- struct e1000_rx_ring *rx_ring);
-
-/* Local Function Prototypes */
+ struct e1000_rx_ring *rx_ring);
+void e1000_update_stats(struct e1000_adapter *adapter);
static int e1000_init_module(void);
static void e1000_exit_module(void);
@@ -146,7 +153,7 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static struct net_device_stats * e1000_get_stats(struct net_device *netdev);
static int e1000_change_mtu(struct net_device *netdev, int new_mtu);
static int e1000_set_mac(struct net_device *netdev, void *p);
-static irqreturn_t e1000_intr(int irq, void *data, struct pt_regs *regs);
+static irqreturn_t e1000_intr(int irq, void *data);
static boolean_t e1000_clean_tx_irq(struct e1000_adapter *adapter,
struct e1000_tx_ring *tx_ring);
#ifdef CONFIG_E1000_NAPI
@@ -172,6 +179,7 @@ static void e1000_alloc_rx_buffers_ps(struct e1000_adapter *adapter,
static int e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd);
static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
int cmd);
+void e1000_set_ethtool_ops(struct net_device *netdev);
static void e1000_enter_82542_rst(struct e1000_adapter *adapter);
static void e1000_leave_82542_rst(struct e1000_adapter *adapter);
static void e1000_tx_timeout(struct net_device *dev);
@@ -196,6 +204,8 @@ static void e1000_shutdown(struct pci_dev *pdev);
static void e1000_netpoll (struct net_device *netdev);
#endif
+extern void e1000_check_options(struct e1000_adapter *adapter);
+
static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state);
static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev);
@@ -212,9 +222,9 @@ static struct pci_driver e1000_driver = {
.id_table = e1000_pci_tbl,
.probe = e1000_probe,
.remove = __devexit_p(e1000_remove),
+#ifdef CONFIG_PM
/* Power Managment Hooks */
.suspend = e1000_suspend,
-#ifdef CONFIG_PM
.resume = e1000_resume,
#endif
.shutdown = e1000_shutdown,
@@ -466,13 +476,14 @@ e1000_up(struct e1000_adapter *adapter)
adapter->tx_queue_len = netdev->tx_queue_len;
- mod_timer(&adapter->watchdog_timer, jiffies);
-
#ifdef CONFIG_E1000_NAPI
netif_poll_enable(netdev);
#endif
e1000_irq_enable(adapter);
+ clear_bit(__E1000_DOWN, &adapter->flags);
+
+ mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
return 0;
}
@@ -502,25 +513,48 @@ void e1000_power_up_phy(struct e1000_adapter *adapter)
static void e1000_power_down_phy(struct e1000_adapter *adapter)
{
- boolean_t mng_mode_enabled = (adapter->hw.mac_type >= e1000_82571) &&
- e1000_check_mng_mode(&adapter->hw);
- /* Power down the PHY so no link is implied when interface is down
- * The PHY cannot be powered down if any of the following is TRUE
+ /* Power down the PHY so no link is implied when interface is down *
+ * The PHY cannot be powered down if any of the following is TRUE *
* (a) WoL is enabled
* (b) AMT is active
* (c) SoL/IDER session is active */
if (!adapter->wol && adapter->hw.mac_type >= e1000_82540 &&
- adapter->hw.mac_type != e1000_ich8lan &&
- adapter->hw.media_type == e1000_media_type_copper &&
- !(E1000_READ_REG(&adapter->hw, MANC) & E1000_MANC_SMBUS_EN) &&
- !mng_mode_enabled &&
- !e1000_check_phy_reset_block(&adapter->hw)) {
+ adapter->hw.media_type == e1000_media_type_copper) {
uint16_t mii_reg = 0;
+
+ switch (adapter->hw.mac_type) {
+ case e1000_82540:
+ case e1000_82545:
+ case e1000_82545_rev_3:
+ case e1000_82546:
+ case e1000_82546_rev_3:
+ case e1000_82541:
+ case e1000_82541_rev_2:
+ case e1000_82547:
+ case e1000_82547_rev_2:
+ if (E1000_READ_REG(&adapter->hw, MANC) &
+ E1000_MANC_SMBUS_EN)
+ goto out;
+ break;
+ case e1000_82571:
+ case e1000_82572:
+ case e1000_82573:
+ case e1000_80003es2lan:
+ case e1000_ich8lan:
+ if (e1000_check_mng_mode(&adapter->hw) ||
+ e1000_check_phy_reset_block(&adapter->hw))
+ goto out;
+ break;
+ default:
+ goto out;
+ }
e1000_read_phy_reg(&adapter->hw, PHY_CTRL, &mii_reg);
mii_reg |= MII_CR_POWER_DOWN;
e1000_write_phy_reg(&adapter->hw, PHY_CTRL, mii_reg);
mdelay(1);
}
+out:
+ return;
}
void
@@ -528,6 +562,10 @@ e1000_down(struct e1000_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
+ /* signal that we're down so the interrupt handler does not
+ * reschedule our watchdog timer */
+ set_bit(__E1000_DOWN, &adapter->flags);
+
e1000_irq_disable(adapter);
del_timer_sync(&adapter->tx_fifo_stall_timer);
@@ -563,6 +601,9 @@ void
e1000_reset(struct e1000_adapter *adapter)
{
uint32_t pba, manc;
+#ifdef DISABLE_MULR
+ uint32_t tctl;
+#endif
uint16_t fc_high_water_mark = E1000_FC_HIGH_DIFF;
/* Repartition Pba for greater than 9k mtu
@@ -629,6 +670,12 @@ e1000_reset(struct e1000_adapter *adapter)
e1000_reset_hw(&adapter->hw);
if (adapter->hw.mac_type >= e1000_82544)
E1000_WRITE_REG(&adapter->hw, WUC, 0);
+#ifdef DISABLE_MULR
+ /* disable Multiple Reads in Transmit Control Register for debugging */
+ tctl = E1000_READ_REG(hw, TCTL);
+ E1000_WRITE_REG(hw, TCTL, tctl & ~E1000_TCTL_MULR);
+
+#endif
if (e1000_init_hw(&adapter->hw))
DPRINTK(PROBE, ERR, "Hardware Error\n");
e1000_update_mng_vlan(adapter);
@@ -652,9 +699,7 @@ e1000_reset(struct e1000_adapter *adapter)
phy_data);
}
- if (adapter->hw.mac_type < e1000_ich8lan)
- /* FIXME: this code is duplicate and wrong for PCI Express */
- if (adapter->en_mng_pt) {
+ if ((adapter->en_mng_pt) && (adapter->hw.mac_type < e1000_82571)) {
manc = E1000_READ_REG(&adapter->hw, MANC);
manc |= (E1000_MANC_ARP_EN | E1000_MANC_EN_MNG2HOST);
E1000_WRITE_REG(&adapter->hw, MANC, manc);
@@ -760,7 +805,7 @@ e1000_probe(struct pci_dev *pdev,
#ifdef CONFIG_NET_POLL_CONTROLLER
netdev->poll_controller = e1000_netpoll;
#endif
- strcpy(netdev->name, pci_name(pdev));
+ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len;
@@ -863,11 +908,6 @@ e1000_probe(struct pci_dev *pdev,
INIT_WORK(&adapter->reset_task,
(void (*)(void *))e1000_reset_task, netdev);
- /* we're going to reset, so assume we have no link for now */
-
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
-
e1000_check_options(adapter);
/* Initial Wake on LAN setting
@@ -974,6 +1014,10 @@ e1000_probe(struct pci_dev *pdev,
if ((err = register_netdev(netdev)))
goto err_register;
+ /* tell the stack to leave us alone until e1000_open() is called */
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
DPRINTK(PROBE, INFO, "Intel(R) PRO/1000 Network Connection\n");
cards_found++;
@@ -1032,8 +1076,7 @@ e1000_remove(struct pci_dev *pdev)
flush_scheduled_work();
- if (adapter->hw.mac_type >= e1000_82540 &&
- adapter->hw.mac_type != e1000_ich8lan &&
+ if (adapter->hw.mac_type < e1000_82571 &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
if (manc & E1000_MANC_SMBUS_EN) {
@@ -1161,6 +1204,8 @@ e1000_sw_init(struct e1000_adapter *adapter)
atomic_set(&adapter->irq_sem, 1);
spin_lock_init(&adapter->stats_lock);
+ set_bit(__E1000_DOWN, &adapter->flags);
+
return 0;
}
@@ -1226,7 +1271,7 @@ e1000_open(struct net_device *netdev)
int err;
/* disallow open during test */
- if (test_bit(__E1000_DRIVER_TESTING, &adapter->flags))
+ if (test_bit(__E1000_TESTING, &adapter->flags))
return -EBUSY;
/* allocate transmit descriptors */
@@ -1299,8 +1344,12 @@ e1000_close(struct net_device *netdev)
e1000_free_all_tx_resources(adapter);
e1000_free_all_rx_resources(adapter);
+ /* kill manageability vlan ID if supported, but not if a vlan with
+ * the same ID is registered on the host OS (let 8021q kill it) */
if ((adapter->hw.mng_cookie.status &
- E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT)) {
+ E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
+ !(adapter->vlgrp &&
+ adapter->vlgrp->vlan_devices[adapter->mng_vlan_id])) {
e1000_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
}
@@ -1510,27 +1559,14 @@ e1000_configure_tx(struct e1000_adapter *adapter)
/* Program the Transmit Control Register */
tctl = E1000_READ_REG(hw, TCTL);
-
tctl &= ~E1000_TCTL_CT;
tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
(E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT);
-#ifdef DISABLE_MULR
- /* disable Multiple Reads for debugging */
- tctl &= ~E1000_TCTL_MULR;
-#endif
-
if (hw->mac_type == e1000_82571 || hw->mac_type == e1000_82572) {
tarc = E1000_READ_REG(hw, TARC0);
- tarc |= ((1 << 25) | (1 << 21));
+ tarc |= (1 << 21);
E1000_WRITE_REG(hw, TARC0, tarc);
- tarc = E1000_READ_REG(hw, TARC1);
- tarc |= (1 << 25);
- if (tctl & E1000_TCTL_MULR)
- tarc &= ~(1 << 28);
- else
- tarc |= (1 << 28);
- E1000_WRITE_REG(hw, TARC1, tarc);
} else if (hw->mac_type == e1000_80003es2lan) {
tarc = E1000_READ_REG(hw, TARC0);
tarc |= 1;
@@ -2892,6 +2928,35 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
return 0;
}
+static int __e1000_maybe_stop_tx(struct net_device *netdev, int size)
+{
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ struct e1000_tx_ring *tx_ring = adapter->tx_ring;
+
+ netif_stop_queue(netdev);
+ /* Herbert's original patch had:
+ * smp_mb__after_netif_stop_queue();
+ * but since that doesn't exist yet, just open code it. */
+ smp_mb();
+
+ /* We need to check again in a case another CPU has just
+ * made room available. */
+ if (likely(E1000_DESC_UNUSED(tx_ring) < size))
+ return -EBUSY;
+
+ /* A reprieve! */
+ netif_start_queue(netdev);
+ return 0;
+}
+
+static int e1000_maybe_stop_tx(struct net_device *netdev,
+ struct e1000_tx_ring *tx_ring, int size)
+{
+ if (likely(E1000_DESC_UNUSED(tx_ring) >= size))
+ return 0;
+ return __e1000_maybe_stop_tx(netdev, size);
+}
+
#define TXD_USE_COUNT(S, X) (((S) >> (X)) + 1 )
static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
@@ -2910,6 +2975,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
unsigned int f;
len -= skb->data_len;
+ /* This goes back to the question of how to logically map a tx queue
+ * to a flow. Right now, performance is impacted slightly negatively
+ * if using multiple tx queues. If the stack breaks away from a
+ * single qdisc implementation, we can look at this again. */
tx_ring = adapter->tx_ring;
if (unlikely(skb->len <= 0)) {
@@ -3005,8 +3074,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
/* need: count + 2 desc gap to keep tail from touching
* head, otherwise try next time */
- if (unlikely(E1000_DESC_UNUSED(tx_ring) < count + 2)) {
- netif_stop_queue(netdev);
+ if (unlikely(e1000_maybe_stop_tx(netdev, tx_ring, count + 2))) {
spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_BUSY;
}
@@ -3014,7 +3082,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(adapter->hw.mac_type == e1000_82547)) {
if (unlikely(e1000_82547_fifo_workaround(adapter, skb))) {
netif_stop_queue(netdev);
- mod_timer(&adapter->tx_fifo_stall_timer, jiffies);
+ mod_timer(&adapter->tx_fifo_stall_timer, jiffies + 1);
spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_BUSY;
}
@@ -3053,8 +3121,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
netdev->trans_start = jiffies;
/* Make sure there is space in the ring for the next send. */
- if (unlikely(E1000_DESC_UNUSED(tx_ring) < MAX_SKB_FRAGS + 2))
- netif_stop_queue(netdev);
+ e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
spin_unlock_irqrestore(&tx_ring->tx_lock, flags);
return NETDEV_TX_OK;
@@ -3131,11 +3198,13 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
}
break;
case e1000_82573:
- /* only enable jumbo frames if ASPM is disabled completely
- * this means both bits must be zero in 0x1A bits 3:2 */
+ /* Jumbo Frames not supported if:
+ * - this is not an 82573L device
+ * - ASPM is enabled in any way (0x1A bits 3:2) */
e1000_read_eeprom(&adapter->hw, EEPROM_INIT_3GIO_3, 1,
&eeprom_data);
- if (eeprom_data & EEPROM_WORD1A_ASPM_MASK) {
+ if ((adapter->hw.device_id != E1000_DEV_ID_82573L) ||
+ (eeprom_data & EEPROM_WORD1A_ASPM_MASK)) {
if (max_frame > MAXIMUM_ETHERNET_FRAME_SIZE) {
DPRINTK(PROBE, ERR,
"Jumbo Frames not supported.\n");
@@ -3143,6 +3212,8 @@ e1000_change_mtu(struct net_device *netdev, int new_mtu)
}
break;
}
+ /* ERT will be enabled later to enable wire speed receives */
+
/* fall through to get support */
case e1000_82571:
case e1000_82572:
@@ -3328,16 +3399,15 @@ e1000_update_stats(struct e1000_adapter *adapter)
adapter->stats.crcerrs + adapter->stats.algnerrc +
adapter->stats.ruc + adapter->stats.roc +
adapter->stats.cexterr;
- adapter->net_stats.rx_length_errors = adapter->stats.ruc +
- adapter->stats.roc;
+ adapter->stats.rlerrc = adapter->stats.ruc + adapter->stats.roc;
+ adapter->net_stats.rx_length_errors = adapter->stats.rlerrc;
adapter->net_stats.rx_crc_errors = adapter->stats.crcerrs;
adapter->net_stats.rx_frame_errors = adapter->stats.algnerrc;
adapter->net_stats.rx_missed_errors = adapter->stats.mpc;
/* Tx Errors */
-
- adapter->net_stats.tx_errors = adapter->stats.ecol +
- adapter->stats.latecol;
+ adapter->stats.txerrc = adapter->stats.ecol + adapter->stats.latecol;
+ adapter->net_stats.tx_errors = adapter->stats.txerrc;
adapter->net_stats.tx_aborted_errors = adapter->stats.ecol;
adapter->net_stats.tx_window_errors = adapter->stats.latecol;
adapter->net_stats.tx_carrier_errors = adapter->stats.tncrs;
@@ -3366,11 +3436,10 @@ e1000_update_stats(struct e1000_adapter *adapter)
* e1000_intr - Interrupt Handler
* @irq: interrupt number
* @data: pointer to a network interface device structure
- * @pt_regs: CPU registers structure
**/
static irqreturn_t
-e1000_intr(int irq, void *data, struct pt_regs *regs)
+e1000_intr(int irq, void *data)
{
struct net_device *netdev = data;
struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3408,7 +3477,9 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
rctl = E1000_READ_REG(hw, RCTL);
E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
}
- mod_timer(&adapter->watchdog_timer, jiffies);
+ /* guard against interrupt when we're going down */
+ if (!test_bit(__E1000_DOWN, &adapter->flags))
+ mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
#ifdef CONFIG_E1000_NAPI
@@ -3546,13 +3617,14 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
tx_ring->next_to_clean = i;
#define TX_WAKE_THRESHOLD 32
- if (unlikely(cleaned && netif_queue_stopped(netdev) &&
- netif_carrier_ok(netdev))) {
- spin_lock(&tx_ring->tx_lock);
- if (netif_queue_stopped(netdev) &&
- (E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD))
+ if (unlikely(cleaned && netif_carrier_ok(netdev) &&
+ E1000_DESC_UNUSED(tx_ring) >= TX_WAKE_THRESHOLD)) {
+ /* Make sure that anybody stopping the queue after this
+ * sees the new next_to_clean.
+ */
+ smp_mb();
+ if (netif_queue_stopped(netdev))
netif_wake_queue(netdev);
- spin_unlock(&tx_ring->tx_lock);
}
if (adapter->detect_tx_hung) {
@@ -4412,13 +4484,21 @@ e1000_write_pci_cfg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
pci_write_config_word(adapter->pdev, reg, *value);
}
-#if 0
-uint32_t
-e1000_io_read(struct e1000_hw *hw, unsigned long port)
+int32_t
+e1000_read_pcie_cap_reg(struct e1000_hw *hw, uint32_t reg, uint16_t *value)
{
- return inl(port);
+ struct e1000_adapter *adapter = hw->back;
+ uint16_t cap_offset;
+
+ cap_offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+ if (!cap_offset)
+ return -E1000_ERR_CONFIG;
+
+ pci_read_config_word(adapter->pdev, cap_offset + reg, value);
+
+ return E1000_SUCCESS;
}
-#endif /* 0 */
+
void
e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
@@ -4693,9 +4773,7 @@ e1000_suspend(struct pci_dev *pdev, pm_message_t state)
pci_enable_wake(pdev, PCI_D3cold, 0);
}
- /* FIXME: this code is incorrect for PCI Express */
- if (adapter->hw.mac_type >= e1000_82540 &&
- adapter->hw.mac_type != e1000_ich8lan &&
+ if (adapter->hw.mac_type < e1000_82571 &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
if (manc & E1000_MANC_SMBUS_EN) {
@@ -4747,9 +4825,7 @@ e1000_resume(struct pci_dev *pdev)
netif_device_attach(netdev);
- /* FIXME: this code is incorrect for PCI Express */
- if (adapter->hw.mac_type >= e1000_82540 &&
- adapter->hw.mac_type != e1000_ich8lan &&
+ if (adapter->hw.mac_type < e1000_82571 &&
adapter->hw.media_type == e1000_media_type_copper) {
manc = E1000_READ_REG(&adapter->hw, MANC);
manc &= ~(E1000_MANC_ARP_EN);
@@ -4785,7 +4861,7 @@ e1000_netpoll(struct net_device *netdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
- e1000_intr(adapter->pdev->irq, netdev, NULL);
+ e1000_intr(adapter->pdev->irq, netdev);
e1000_clean_tx_irq(adapter, adapter->tx_ring);
#ifndef CONFIG_E1000_NAPI
adapter->clean_rx(adapter, adapter->rx_ring);
@@ -4835,8 +4911,8 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev)
}
pci_set_master(pdev);
- pci_enable_wake(pdev, 3, 0);
- pci_enable_wake(pdev, 4, 0); /* 4 == D3 cold */
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_enable_wake(pdev, PCI_D3cold, 0);
/* Perform card reset only on one instance of the card */
if (PCI_FUNC (pdev->devfn) != 0)
diff --git a/drivers/net/e1000/e1000_osdep.h b/drivers/net/e1000/e1000_osdep.h
index 46bc49df15e7..a464cb290621 100644
--- a/drivers/net/e1000/e1000_osdep.h
+++ b/drivers/net/e1000/e1000_osdep.h
@@ -1,25 +1,24 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c
index 212842738972..9c3c1acefccc 100644
--- a/drivers/net/e1000/e1000_param.c
+++ b/drivers/net/e1000/e1000_param.c
@@ -1,25 +1,24 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/1000 Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
@@ -397,17 +396,17 @@ e1000_check_options(struct e1000_adapter *adapter)
{ /* Flow Control */
struct e1000_opt_list fc_list[] =
- {{ e1000_fc_none, "Flow Control Disabled" },
- { e1000_fc_rx_pause,"Flow Control Receive Only" },
- { e1000_fc_tx_pause,"Flow Control Transmit Only" },
- { e1000_fc_full, "Flow Control Enabled" },
- { e1000_fc_default, "Flow Control Hardware Default" }};
+ {{ E1000_FC_NONE, "Flow Control Disabled" },
+ { E1000_FC_RX_PAUSE,"Flow Control Receive Only" },
+ { E1000_FC_TX_PAUSE,"Flow Control Transmit Only" },
+ { E1000_FC_FULL, "Flow Control Enabled" },
+ { E1000_FC_DEFAULT, "Flow Control Hardware Default" }};
struct e1000_option opt = {
.type = list_option,
.name = "Flow Control",
.err = "reading default settings from EEPROM",
- .def = e1000_fc_default,
+ .def = E1000_FC_DEFAULT,
.arg = { .l = { .nr = ARRAY_SIZE(fc_list),
.p = fc_list }}
};
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index 09ff9b9418f4..a4eb0dc99ecf 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -311,7 +311,7 @@ struct eepro_local {
static int eepro_probe1(struct net_device *dev, int autoprobe);
static int eepro_open(struct net_device *dev);
static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t eepro_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t eepro_interrupt(int irq, void *dev_id);
static void eepro_rx(struct net_device *dev);
static void eepro_transmit_interrupt(struct net_device *dev);
static int eepro_close(struct net_device *dev);
@@ -994,16 +994,6 @@ static int eepro_open(struct net_device *dev)
return -EAGAIN;
}
-#ifdef irq2dev_map
- if (((irq2dev_map[dev->irq] != 0)
- || (irq2dev_map[dev->irq] = dev) == 0) &&
- (irq2dev_map[dev->irq]!=dev)) {
- /* printk("%s: IRQ map wrong\n", dev->name); */
- free_irq(dev->irq, dev);
- return -EAGAIN;
- }
-#endif
-
/* Initialize the 82595. */
eepro_sw2bank2(ioaddr); /* be CAREFUL, BANK 2 now */
@@ -1196,19 +1186,13 @@ static int eepro_send_packet(struct sk_buff *skb, struct net_device *dev)
Handle the network interface interrupts. */
static irqreturn_t
-eepro_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+eepro_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
- /* (struct net_device *)(irq2dev_map[irq]);*/
+ struct net_device *dev = dev_id;
struct eepro_local *lp;
int ioaddr, status, boguscount = 20;
int handled = 0;
- if (dev == NULL) {
- printk (KERN_ERR "eepro_interrupt(): irq %d for unknown device.\\n", irq);
- return IRQ_NONE;
- }
-
lp = netdev_priv(dev);
spin_lock(&lp->lock);
@@ -1288,10 +1272,6 @@ static int eepro_close(struct net_device *dev)
/* release the interrupt */
free_irq(dev->irq, dev);
-#ifdef irq2dev_map
- irq2dev_map[dev->irq] = 0;
-#endif
-
/* Update the statistics here. What statistics? */
return 0;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 499e93b31f54..e28bb1e38f8d 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -488,7 +488,7 @@ static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void speedo_refill_rx_buffers(struct net_device *dev, int force);
static int speedo_rx(struct net_device *dev);
static void speedo_tx_buffer_gc(struct net_device *dev);
-static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t speedo_interrupt(int irq, void *dev_instance);
static int speedo_close(struct net_device *dev);
static struct net_device_stats *speedo_get_stats(struct net_device *dev);
static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -606,7 +606,7 @@ static void poll_speedo (struct net_device *dev)
/* disable_irq is not very nice, but with the funny lockless design
we have no other choice. */
disable_irq(dev->irq);
- speedo_interrupt (dev->irq, dev, NULL);
+ speedo_interrupt (dev->irq, dev);
enable_irq(dev->irq);
}
#endif
@@ -1541,7 +1541,7 @@ static void speedo_tx_buffer_gc(struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t speedo_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t speedo_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *)dev_instance;
struct speedo_private *sp;
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index 9cb05d99ee1b..e14be020e562 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -249,7 +249,7 @@ static void eexp_timeout(struct net_device *dev);
static struct net_device_stats *eexp_stats(struct net_device *dev);
static int eexp_xmit(struct sk_buff *buf, struct net_device *dev);
-static irqreturn_t eexp_irq(int irq, void *dev_addr, struct pt_regs *regs);
+static irqreturn_t eexp_irq(int irq, void *dev_addr);
static void eexp_set_multicast(struct net_device *dev);
/*
@@ -789,20 +789,13 @@ static void eexp_cmd_clear(struct net_device *dev)
}
}
-static irqreturn_t eexp_irq(int irq, void *dev_info, struct pt_regs *regs)
+static irqreturn_t eexp_irq(int irq, void *dev_info)
{
struct net_device *dev = dev_info;
struct net_local *lp;
unsigned short ioaddr,status,ack_cmd;
unsigned short old_read_ptr, old_write_ptr;
- if (dev==NULL)
- {
- printk(KERN_WARNING "eexpress: irq %d for unknown device\n",
- irq);
- return IRQ_NONE;
- }
-
lp = netdev_priv(dev);
ioaddr = dev->base_addr;
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h
index 23b451a8ae12..b40724fc6b74 100644
--- a/drivers/net/ehea/ehea.h
+++ b/drivers/net/ehea/ehea.h
@@ -39,7 +39,7 @@
#include <asm/io.h>
#define DRV_NAME "ehea"
-#define DRV_VERSION "EHEA_0028"
+#define DRV_VERSION "EHEA_0034"
#define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \
| NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
@@ -50,6 +50,7 @@
#define EHEA_MAX_ENTRIES_SQ 32767
#define EHEA_MIN_ENTRIES_QP 127
+#define EHEA_SMALL_QUEUES
#define EHEA_NUM_TX_QP 1
#ifdef EHEA_SMALL_QUEUES
@@ -59,11 +60,11 @@
#define EHEA_DEF_ENTRIES_RQ2 1023
#define EHEA_DEF_ENTRIES_RQ3 1023
#else
-#define EHEA_MAX_CQE_COUNT 32000
-#define EHEA_DEF_ENTRIES_SQ 16000
-#define EHEA_DEF_ENTRIES_RQ1 32080
-#define EHEA_DEF_ENTRIES_RQ2 4020
-#define EHEA_DEF_ENTRIES_RQ3 4020
+#define EHEA_MAX_CQE_COUNT 4080
+#define EHEA_DEF_ENTRIES_SQ 4080
+#define EHEA_DEF_ENTRIES_RQ1 8160
+#define EHEA_DEF_ENTRIES_RQ2 2040
+#define EHEA_DEF_ENTRIES_RQ3 2040
#endif
#define EHEA_MAX_ENTRIES_EQ 20
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c
index 263d1c5b3f23..eb7d44de59ff 100644
--- a/drivers/net/ehea/ehea_main.c
+++ b/drivers/net/ehea/ehea_main.c
@@ -536,16 +536,14 @@ void ehea_send_irq_tasklet(unsigned long data)
tasklet_hi_schedule(&pr->send_comp_task);
}
-static irqreturn_t ehea_send_irq_handler(int irq, void *param,
- struct pt_regs *regs)
+static irqreturn_t ehea_send_irq_handler(int irq, void *param)
{
struct ehea_port_res *pr = param;
tasklet_hi_schedule(&pr->send_comp_task);
return IRQ_HANDLED;
}
-static irqreturn_t ehea_recv_irq_handler(int irq, void *param,
- struct pt_regs *regs)
+static irqreturn_t ehea_recv_irq_handler(int irq, void *param)
{
struct ehea_port_res *pr = param;
struct ehea_port *port = pr->port;
@@ -553,8 +551,7 @@ static irqreturn_t ehea_recv_irq_handler(int irq, void *param,
return IRQ_HANDLED;
}
-static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param,
- struct pt_regs *regs)
+static irqreturn_t ehea_qp_aff_irq_handler(int irq, void *param)
{
struct ehea_port *port = param;
struct ehea_eqe *eqe;
@@ -769,7 +766,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
if (EHEA_BMASK_GET(NEQE_PORT_UP, eqe)) {
if (!netif_carrier_ok(port->netdev)) {
ret = ehea_sense_port_attr(
- adapter->port[portnum]);
+ port);
if (ret) {
ehea_error("failed resensing port "
"attributes");
@@ -821,7 +818,7 @@ static void ehea_parse_eqe(struct ehea_adapter *adapter, u64 eqe)
netif_stop_queue(port->netdev);
break;
default:
- ehea_error("unknown event code %x", ec);
+ ehea_error("unknown event code %x, eqe=0x%lX", ec, eqe);
break;
}
}
@@ -850,8 +847,7 @@ static void ehea_neq_tasklet(unsigned long data)
adapter->neq->fw_handle, event_mask);
}
-static irqreturn_t ehea_interrupt_neq(int irq, void *param,
- struct pt_regs *regs)
+static irqreturn_t ehea_interrupt_neq(int irq, void *param)
{
struct ehea_adapter *adapter = param;
tasklet_hi_schedule(&adapter->neq_tasklet);
@@ -1845,7 +1841,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (netif_msg_tx_queued(port)) {
ehea_info("post swqe on QP %d", pr->qp->init_attr.qp_nr);
- ehea_dump(swqe, sizeof(*swqe), "swqe");
+ ehea_dump(swqe, 512, "swqe");
}
ehea_post_swqe(pr->qp, swqe);
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c
index 4a85aca4c7e9..0b51a8cea077 100644
--- a/drivers/net/ehea/ehea_phyp.c
+++ b/drivers/net/ehea/ehea_phyp.c
@@ -44,71 +44,99 @@ static inline u16 get_order_of_qentries(u16 queue_entries)
#define H_ALL_RES_TYPE_MR 5
#define H_ALL_RES_TYPE_MW 6
-static long ehea_hcall_9arg_9ret(unsigned long opcode,
- unsigned long arg1, unsigned long arg2,
- unsigned long arg3, unsigned long arg4,
- unsigned long arg5, unsigned long arg6,
- unsigned long arg7, unsigned long arg8,
- unsigned long arg9, unsigned long *out1,
- unsigned long *out2,unsigned long *out3,
- unsigned long *out4,unsigned long *out5,
- unsigned long *out6,unsigned long *out7,
- unsigned long *out8,unsigned long *out9)
+static long ehea_plpar_hcall_norets(unsigned long opcode,
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7)
{
- long hret;
+ long ret;
int i, sleep_msecs;
for (i = 0; i < 5; i++) {
- hret = plpar_hcall_9arg_9ret(opcode,arg1, arg2, arg3, arg4,
- arg5, arg6, arg7, arg8, arg9, out1,
- out2, out3, out4, out5, out6, out7,
- out8, out9);
- if (H_IS_LONG_BUSY(hret)) {
- sleep_msecs = get_longbusy_msecs(hret);
+ ret = plpar_hcall_norets(opcode, arg1, arg2, arg3, arg4,
+ arg5, arg6, arg7);
+
+ if (H_IS_LONG_BUSY(ret)) {
+ sleep_msecs = get_longbusy_msecs(ret);
msleep_interruptible(sleep_msecs);
continue;
}
- if (hret < H_SUCCESS)
- ehea_error("op=%lx hret=%lx "
- "i1=%lx i2=%lx i3=%lx i4=%lx i5=%lx i6=%lx "
- "i7=%lx i8=%lx i9=%lx "
- "o1=%lx o2=%lx o3=%lx o4=%lx o5=%lx o6=%lx "
- "o7=%lx o8=%lx o9=%lx",
- opcode, hret, arg1, arg2, arg3, arg4, arg5,
- arg6, arg7, arg8, arg9, *out1, *out2, *out3,
- *out4, *out5, *out6, *out7, *out8, *out9);
- return hret;
+ if (ret < H_SUCCESS)
+ ehea_error("opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx ",
+ opcode, ret,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7);
+
+ return ret;
}
+
return H_BUSY;
}
-u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category,
- const u64 qp_handle, const u64 sel_mask, void *cb_addr)
+static long ehea_plpar_hcall9(unsigned long opcode,
+ unsigned long *outs, /* array of 9 outputs */
+ unsigned long arg1,
+ unsigned long arg2,
+ unsigned long arg3,
+ unsigned long arg4,
+ unsigned long arg5,
+ unsigned long arg6,
+ unsigned long arg7,
+ unsigned long arg8,
+ unsigned long arg9)
{
- u64 dummy;
+ long ret;
+ int i, sleep_msecs;
- if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) {
- ehea_error("not on pageboundary");
- return H_PARAMETER;
+ for (i = 0; i < 5; i++) {
+ ret = plpar_hcall9(opcode, outs,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9);
+
+ if (H_IS_LONG_BUSY(ret)) {
+ sleep_msecs = get_longbusy_msecs(ret);
+ msleep_interruptible(sleep_msecs);
+ continue;
+ }
+
+ if (ret < H_SUCCESS)
+ ehea_error("opcode=%lx ret=%lx"
+ " arg1=%lx arg2=%lx arg3=%lx arg4=%lx"
+ " arg5=%lx arg6=%lx arg7=%lx arg8=%lx"
+ " arg9=%lx"
+ " out1=%lx out2=%lx out3=%lx out4=%lx"
+ " out5=%lx out6=%lx out7=%lx out8=%lx"
+ " out9=%lx",
+ opcode, ret,
+ arg1, arg2, arg3, arg4, arg5,
+ arg6, arg7, arg8, arg9,
+ outs[0], outs[1], outs[2], outs[3],
+ outs[4], outs[5], outs[6], outs[7],
+ outs[8]);
+
+ return ret;
}
- return ehea_hcall_9arg_9ret(H_QUERY_HEA_QP,
- adapter_handle, /* R4 */
- qp_category, /* R5 */
- qp_handle, /* R6 */
- sel_mask, /* R7 */
- virt_to_abs(cb_addr), /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- &dummy, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ return H_BUSY;
+}
+
+u64 ehea_h_query_ehea_qp(const u64 adapter_handle, const u8 qp_category,
+ const u64 qp_handle, const u64 sel_mask, void *cb_addr)
+{
+ return ehea_plpar_hcall_norets(H_QUERY_HEA_QP,
+ adapter_handle, /* R4 */
+ qp_category, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0);
}
/* input param R5 */
@@ -180,6 +208,7 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
u64 *qp_handle, struct h_epas *h_epas)
{
u64 hret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
u64 allocate_controls =
EHEA_BMASK_SET(H_ALL_RES_QP_EQPO, init_attr->low_lat_rq1 ? 1 : 0)
@@ -219,45 +248,29 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ2, init_attr->rq2_threshold)
| EHEA_BMASK_SET(H_ALL_RES_QP_TH_RQ3, init_attr->rq3_threshold);
- u64 r5_out = 0;
- u64 r6_out = 0;
- u64 r7_out = 0;
- u64 r8_out = 0;
- u64 r9_out = 0;
- u64 g_la_user_out = 0;
- u64 r11_out = 0;
- u64 r12_out = 0;
-
- hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
- adapter_handle, /* R4 */
- allocate_controls, /* R5 */
- init_attr->send_cq_handle, /* R6 */
- init_attr->recv_cq_handle, /* R7 */
- init_attr->aff_eq_handle, /* R8 */
- r9_reg, /* R9 */
- max_r10_reg, /* R10 */
- r11_in, /* R11 */
- threshold, /* R12 */
- qp_handle, /* R4 */
- &r5_out, /* R5 */
- &r6_out, /* R6 */
- &r7_out, /* R7 */
- &r8_out, /* R8 */
- &r9_out, /* R9 */
- &g_la_user_out, /* R10 */
- &r11_out, /* R11 */
- &r12_out); /* R12 */
-
- init_attr->qp_nr = (u32)r5_out;
+ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
+ outs,
+ adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ init_attr->send_cq_handle, /* R6 */
+ init_attr->recv_cq_handle, /* R7 */
+ init_attr->aff_eq_handle, /* R8 */
+ r9_reg, /* R9 */
+ max_r10_reg, /* R10 */
+ r11_in, /* R11 */
+ threshold); /* R12 */
+
+ *qp_handle = outs[0];
+ init_attr->qp_nr = (u32)outs[1];
init_attr->act_nr_send_wqes =
- (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, r6_out);
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_SWQE, outs[2]);
init_attr->act_nr_rwqes_rq1 =
- (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, r6_out);
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R1WQE, outs[2]);
init_attr->act_nr_rwqes_rq2 =
- (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, r6_out);
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R2WQE, outs[2]);
init_attr->act_nr_rwqes_rq3 =
- (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, r6_out);
+ (u16)EHEA_BMASK_GET(H_ALL_RES_QP_ACT_R3WQE, outs[2]);
init_attr->act_wqe_size_enc_sq = init_attr->wqe_size_enc_sq;
init_attr->act_wqe_size_enc_rq1 = init_attr->wqe_size_enc_rq1;
@@ -265,25 +278,25 @@ u64 ehea_h_alloc_resource_qp(const u64 adapter_handle,
init_attr->act_wqe_size_enc_rq3 = init_attr->wqe_size_enc_rq3;
init_attr->nr_sq_pages =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, r8_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_SQ, outs[4]);
init_attr->nr_rq1_pages =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, r8_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ1, outs[4]);
init_attr->nr_rq2_pages =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, r9_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ2, outs[5]);
init_attr->nr_rq3_pages =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, r9_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_SIZE_RQ3, outs[5]);
init_attr->liobn_sq =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, r11_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_SQ, outs[7]);
init_attr->liobn_rq1 =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, r11_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ1, outs[7]);
init_attr->liobn_rq2 =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, r12_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ2, outs[8]);
init_attr->liobn_rq3 =
- (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, r12_out);
+ (u32)EHEA_BMASK_GET(H_ALL_RES_QP_LIOBN_RQ3, outs[8]);
if (!hret)
- hcp_epas_ctor(h_epas, g_la_user_out, g_la_user_out);
+ hcp_epas_ctor(h_epas, outs[6], outs[6]);
return hret;
}
@@ -292,31 +305,24 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
struct ehea_cq_attr *cq_attr,
u64 *cq_handle, struct h_epas *epas)
{
- u64 hret, dummy, act_nr_of_cqes_out, act_pages_out;
- u64 g_la_privileged_out, g_la_user_out;
-
- hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
- adapter_handle, /* R4 */
- H_ALL_RES_TYPE_CQ, /* R5 */
- cq_attr->eq_handle, /* R6 */
- cq_attr->cq_token, /* R7 */
- cq_attr->max_nr_of_cqes, /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- cq_handle, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &act_nr_of_cqes_out, /* R7 */
- &act_pages_out, /* R8 */
- &g_la_privileged_out, /* R9 */
- &g_la_user_out, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
-
- cq_attr->act_nr_of_cqes = act_nr_of_cqes_out;
- cq_attr->nr_pages = act_pages_out;
+ u64 hret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
+ outs,
+ adapter_handle, /* R4 */
+ H_ALL_RES_TYPE_CQ, /* R5 */
+ cq_attr->eq_handle, /* R6 */
+ cq_attr->cq_token, /* R7 */
+ cq_attr->max_nr_of_cqes, /* R8 */
+ 0, 0, 0, 0); /* R9-R12 */
+
+ *cq_handle = outs[0];
+ cq_attr->act_nr_of_cqes = outs[3];
+ cq_attr->nr_pages = outs[4];
if (!hret)
- hcp_epas_ctor(epas, g_la_privileged_out, g_la_user_out);
+ hcp_epas_ctor(epas, outs[5], outs[6]);
return hret;
}
@@ -361,9 +367,8 @@ u64 ehea_h_alloc_resource_cq(const u64 adapter_handle,
u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
struct ehea_eq_attr *eq_attr, u64 *eq_handle)
{
- u64 hret, dummy, eq_liobn, allocate_controls;
- u64 ist1_out, ist2_out, ist3_out, ist4_out;
- u64 act_nr_of_eqes_out, act_pages_out;
+ u64 hret, allocate_controls;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
/* resource type */
allocate_controls =
@@ -372,27 +377,20 @@ u64 ehea_h_alloc_resource_eq(const u64 adapter_handle,
| EHEA_BMASK_SET(H_ALL_RES_EQ_INH_EQE_GEN, !eq_attr->eqe_gen)
| EHEA_BMASK_SET(H_ALL_RES_EQ_NON_NEQ_ISN, 1);
- hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
- adapter_handle, /* R4 */
- allocate_controls, /* R5 */
- eq_attr->max_nr_of_eqes, /* R6 */
- 0, 0, 0, 0, 0, 0, /* R7-R10 */
- eq_handle, /* R4 */
- &dummy, /* R5 */
- &eq_liobn, /* R6 */
- &act_nr_of_eqes_out, /* R7 */
- &act_pages_out, /* R8 */
- &ist1_out, /* R9 */
- &ist2_out, /* R10 */
- &ist3_out, /* R11 */
- &ist4_out); /* R12 */
-
- eq_attr->act_nr_of_eqes = act_nr_of_eqes_out;
- eq_attr->nr_pages = act_pages_out;
- eq_attr->ist1 = ist1_out;
- eq_attr->ist2 = ist2_out;
- eq_attr->ist3 = ist3_out;
- eq_attr->ist4 = ist4_out;
+ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
+ outs,
+ adapter_handle, /* R4 */
+ allocate_controls, /* R5 */
+ eq_attr->max_nr_of_eqes, /* R6 */
+ 0, 0, 0, 0, 0, 0); /* R7-R10 */
+
+ *eq_handle = outs[0];
+ eq_attr->act_nr_of_eqes = outs[3];
+ eq_attr->nr_pages = outs[4];
+ eq_attr->ist1 = outs[5];
+ eq_attr->ist2 = outs[6];
+ eq_attr->ist3 = outs[7];
+ eq_attr->ist4 = outs[8];
return hret;
}
@@ -402,31 +400,22 @@ u64 ehea_h_modify_ehea_qp(const u64 adapter_handle, const u8 cat,
void *cb_addr, u64 *inv_attr_id, u64 *proc_mask,
u16 *out_swr, u16 *out_rwr)
{
- u64 hret, dummy, act_out_swr, act_out_rwr;
-
- if ((((u64)cb_addr) & (PAGE_SIZE - 1)) != 0) {
- ehea_error("not on page boundary");
- return H_PARAMETER;
- }
-
- hret = ehea_hcall_9arg_9ret(H_MODIFY_HEA_QP,
- adapter_handle, /* R4 */
- (u64) cat, /* R5 */
- qp_handle, /* R6 */
- sel_mask, /* R7 */
- virt_to_abs(cb_addr), /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- inv_attr_id, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &act_out_swr, /* R7 */
- &act_out_rwr, /* R8 */
- proc_mask, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
- *out_swr = act_out_swr;
- *out_rwr = act_out_rwr;
+ u64 hret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ hret = ehea_plpar_hcall9(H_MODIFY_HEA_QP,
+ outs,
+ adapter_handle, /* R4 */
+ (u64) cat, /* R5 */
+ qp_handle, /* R6 */
+ sel_mask, /* R7 */
+ virt_to_abs(cb_addr), /* R8 */
+ 0, 0, 0, 0); /* R9-R12 */
+
+ *inv_attr_id = outs[0];
+ *out_swr = outs[3];
+ *out_rwr = outs[4];
+ *proc_mask = outs[5];
return hret;
}
@@ -435,122 +424,81 @@ u64 ehea_h_register_rpage(const u64 adapter_handle, const u8 pagesize,
const u8 queue_type, const u64 resource_handle,
const u64 log_pageaddr, u64 count)
{
- u64 dummy, reg_control;
+ u64 reg_control;
reg_control = EHEA_BMASK_SET(H_REG_RPAGE_PAGE_SIZE, pagesize)
| EHEA_BMASK_SET(H_REG_RPAGE_QT, queue_type);
- return ehea_hcall_9arg_9ret(H_REGISTER_HEA_RPAGES,
- adapter_handle, /* R4 */
- reg_control, /* R5 */
- resource_handle, /* R6 */
- log_pageaddr, /* R7 */
- count, /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- &dummy, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ return ehea_plpar_hcall_norets(H_REGISTER_HEA_RPAGES,
+ adapter_handle, /* R4 */
+ reg_control, /* R5 */
+ resource_handle, /* R6 */
+ log_pageaddr, /* R7 */
+ count, /* R8 */
+ 0, 0); /* R9-R10 */
}
u64 ehea_h_register_smr(const u64 adapter_handle, const u64 orig_mr_handle,
const u64 vaddr_in, const u32 access_ctrl, const u32 pd,
struct ehea_mr *mr)
{
- u64 hret, dummy, lkey_out;
-
- hret = ehea_hcall_9arg_9ret(H_REGISTER_SMR,
- adapter_handle , /* R4 */
- orig_mr_handle, /* R5 */
- vaddr_in, /* R6 */
- (((u64)access_ctrl) << 32ULL), /* R7 */
- pd, /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- &mr->handle, /* R4 */
- &dummy, /* R5 */
- &lkey_out, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
- mr->lkey = (u32)lkey_out;
+ u64 hret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ hret = ehea_plpar_hcall9(H_REGISTER_SMR,
+ outs,
+ adapter_handle , /* R4 */
+ orig_mr_handle, /* R5 */
+ vaddr_in, /* R6 */
+ (((u64)access_ctrl) << 32ULL), /* R7 */
+ pd, /* R8 */
+ 0, 0, 0, 0); /* R9-R12 */
+
+ mr->handle = outs[0];
+ mr->lkey = (u32)outs[2];
return hret;
}
u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle)
{
- u64 hret, dummy, ladr_next_sq_wqe_out;
- u64 ladr_next_rq1_wqe_out, ladr_next_rq2_wqe_out, ladr_next_rq3_wqe_out;
-
- hret = ehea_hcall_9arg_9ret(H_DISABLE_AND_GET_HEA,
- adapter_handle, /* R4 */
- H_DISABLE_GET_EHEA_WQE_P, /* R5 */
- qp_handle, /* R6 */
- 0, 0, 0, 0, 0, 0, /* R7-R12 */
- &ladr_next_sq_wqe_out, /* R4 */
- &ladr_next_rq1_wqe_out, /* R5 */
- &ladr_next_rq2_wqe_out, /* R6 */
- &ladr_next_rq3_wqe_out, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
- return hret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ return ehea_plpar_hcall9(H_DISABLE_AND_GET_HEA,
+ outs,
+ adapter_handle, /* R4 */
+ H_DISABLE_GET_EHEA_WQE_P, /* R5 */
+ qp_handle, /* R6 */
+ 0, 0, 0, 0, 0, 0); /* R7-R12 */
}
u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle)
{
- u64 dummy;
-
- return ehea_hcall_9arg_9ret(H_FREE_RESOURCE,
- adapter_handle, /* R4 */
- res_handle, /* R5 */
- 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */
- &dummy, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ return ehea_plpar_hcall_norets(H_FREE_RESOURCE,
+ adapter_handle, /* R4 */
+ res_handle, /* R5 */
+ 0, 0, 0, 0, 0); /* R6-R10 */
}
u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr,
const u64 length, const u32 access_ctrl,
const u32 pd, u64 *mr_handle, u32 *lkey)
{
- u64 hret, dummy, lkey_out;
-
- hret = ehea_hcall_9arg_9ret(H_ALLOC_HEA_RESOURCE,
- adapter_handle, /* R4 */
- 5, /* R5 */
- vaddr, /* R6 */
- length, /* R7 */
- (((u64) access_ctrl) << 32ULL),/* R8 */
- pd, /* R9 */
- 0, 0, 0, /* R10-R12 */
- mr_handle, /* R4 */
- &dummy, /* R5 */
- &lkey_out, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
- *lkey = (u32) lkey_out;
-
+ u64 hret;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+
+ hret = ehea_plpar_hcall9(H_ALLOC_HEA_RESOURCE,
+ outs,
+ adapter_handle, /* R4 */
+ 5, /* R5 */
+ vaddr, /* R6 */
+ length, /* R7 */
+ (((u64) access_ctrl) << 32ULL), /* R8 */
+ pd, /* R9 */
+ 0, 0, 0); /* R10-R12 */
+
+ *mr_handle = outs[0];
+ *lkey = (u32)outs[2];
return hret;
}
@@ -570,23 +518,14 @@ u64 ehea_h_register_rpage_mr(const u64 adapter_handle, const u64 mr_handle,
u64 ehea_h_query_ehea(const u64 adapter_handle, void *cb_addr)
{
- u64 hret, dummy, cb_logaddr;
+ u64 hret, cb_logaddr;
cb_logaddr = virt_to_abs(cb_addr);
- hret = ehea_hcall_9arg_9ret(H_QUERY_HEA,
- adapter_handle, /* R4 */
- cb_logaddr, /* R5 */
- 0, 0, 0, 0, 0, 0, 0, /* R6-R12 */
- &dummy, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ hret = ehea_plpar_hcall_norets(H_QUERY_HEA,
+ adapter_handle, /* R4 */
+ cb_logaddr, /* R5 */
+ 0, 0, 0, 0, 0); /* R6-R10 */
#ifdef DEBUG
ehea_dmp(cb_addr, sizeof(struct hcp_query_ehea), "hcp_query_ehea");
#endif
@@ -597,36 +536,28 @@ u64 ehea_h_query_ehea_port(const u64 adapter_handle, const u16 port_num,
const u8 cb_cat, const u64 select_mask,
void *cb_addr)
{
- u64 port_info, dummy;
+ u64 port_info;
u64 cb_logaddr = virt_to_abs(cb_addr);
u64 arr_index = 0;
port_info = EHEA_BMASK_SET(H_MEHEAPORT_CAT, cb_cat)
| EHEA_BMASK_SET(H_MEHEAPORT_PN, port_num);
- return ehea_hcall_9arg_9ret(H_QUERY_HEA_PORT,
- adapter_handle, /* R4 */
- port_info, /* R5 */
- select_mask, /* R6 */
- arr_index, /* R7 */
- cb_logaddr, /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- &dummy, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ return ehea_plpar_hcall_norets(H_QUERY_HEA_PORT,
+ adapter_handle, /* R4 */
+ port_info, /* R5 */
+ select_mask, /* R6 */
+ arr_index, /* R7 */
+ cb_logaddr, /* R8 */
+ 0, 0); /* R9-R10 */
}
u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
const u8 cb_cat, const u64 select_mask,
void *cb_addr)
{
- u64 port_info, dummy, inv_attr_ident, proc_mask;
+ u64 outs[PLPAR_HCALL9_BUFSIZE];
+ u64 port_info;
u64 arr_index = 0;
u64 cb_logaddr = virt_to_abs(cb_addr);
@@ -635,29 +566,21 @@ u64 ehea_h_modify_ehea_port(const u64 adapter_handle, const u16 port_num,
#ifdef DEBUG
ehea_dump(cb_addr, sizeof(struct hcp_ehea_port_cb0), "Before HCALL");
#endif
- return ehea_hcall_9arg_9ret(H_MODIFY_HEA_PORT,
- adapter_handle, /* R4 */
- port_info, /* R5 */
- select_mask, /* R6 */
- arr_index, /* R7 */
- cb_logaddr, /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- &inv_attr_ident, /* R4 */
- &proc_mask, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ return ehea_plpar_hcall9(H_MODIFY_HEA_PORT,
+ outs,
+ adapter_handle, /* R4 */
+ port_info, /* R5 */
+ select_mask, /* R6 */
+ arr_index, /* R7 */
+ cb_logaddr, /* R8 */
+ 0, 0, 0, 0); /* R9-R12 */
}
u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
const u8 reg_type, const u64 mc_mac_addr,
const u16 vlan_id, const u32 hcall_id)
{
- u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id, dummy;
+ u64 r5_port_num, r6_reg_type, r7_mc_mac_addr, r8_vlan_id;
u64 mac_addr = mc_mac_addr >> 16;
r5_port_num = EHEA_BMASK_SET(H_REGBCMC_PN, port_num);
@@ -665,41 +588,21 @@ u64 ehea_h_reg_dereg_bcmc(const u64 adapter_handle, const u16 port_num,
r7_mc_mac_addr = EHEA_BMASK_SET(H_REGBCMC_MACADDR, mac_addr);
r8_vlan_id = EHEA_BMASK_SET(H_REGBCMC_VLANID, vlan_id);
- return ehea_hcall_9arg_9ret(hcall_id,
- adapter_handle, /* R4 */
- r5_port_num, /* R5 */
- r6_reg_type, /* R6 */
- r7_mc_mac_addr, /* R7 */
- r8_vlan_id, /* R8 */
- 0, 0, 0, 0, /* R9-R12 */
- &dummy, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ return ehea_plpar_hcall_norets(hcall_id,
+ adapter_handle, /* R4 */
+ r5_port_num, /* R5 */
+ r6_reg_type, /* R6 */
+ r7_mc_mac_addr, /* R7 */
+ r8_vlan_id, /* R8 */
+ 0, 0); /* R9-R12 */
}
u64 ehea_h_reset_events(const u64 adapter_handle, const u64 neq_handle,
const u64 event_mask)
{
- u64 dummy;
-
- return ehea_hcall_9arg_9ret(H_RESET_EVENTS,
- adapter_handle, /* R4 */
- neq_handle, /* R5 */
- event_mask, /* R6 */
- 0, 0, 0, 0, 0, 0, /* R7-R12 */
- &dummy, /* R4 */
- &dummy, /* R5 */
- &dummy, /* R6 */
- &dummy, /* R7 */
- &dummy, /* R8 */
- &dummy, /* R9 */
- &dummy, /* R10 */
- &dummy, /* R11 */
- &dummy); /* R12 */
+ return ehea_plpar_hcall_norets(H_RESET_EVENTS,
+ adapter_handle, /* R4 */
+ neq_handle, /* R5 */
+ event_mask, /* R6 */
+ 0, 0, 0, 0); /* R7-R12 */
}
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index ba2565ee0439..3a6a83d3ee1c 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -297,7 +297,7 @@ static void epic_init_ring(struct net_device *dev);
static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int epic_rx(struct net_device *dev, int budget);
static int epic_poll(struct net_device *dev, int *budget);
-static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t epic_interrupt(int irq, void *dev_instance);
static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
static int epic_close(struct net_device *dev);
@@ -1081,7 +1081,7 @@ static void epic_tx(struct net_device *dev, struct epic_private *ep)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t epic_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t epic_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct epic_private *ep = dev->priv;
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index f16b6a5aaa34..b7b8bc2a6307 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -162,9 +162,9 @@ static char *version =
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/jiffies.h>
+#include <linux/io.h>
#include <asm/system.h>
-#include <asm/io.h>
#include <asm/dma.h>
@@ -410,7 +410,7 @@ static int eth16i_close(struct net_device *dev);
static int eth16i_tx(struct sk_buff *skb, struct net_device *dev);
static void eth16i_rx(struct net_device *dev);
static void eth16i_timeout(struct net_device *dev);
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t eth16i_interrupt(int irq, void *dev_id);
static void eth16i_reset(struct net_device *dev);
static void eth16i_timeout(struct net_device *dev);
static void eth16i_skip_packet(struct net_device *dev);
@@ -1226,7 +1226,7 @@ static void eth16i_rx(struct net_device *dev)
} /* while */
}
-static irqreturn_t eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t eth16i_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct eth16i_local *lp;
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index 75a43f7c70cf..c8c41f0a47d6 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -300,7 +300,7 @@ struct ewrk3_private {
*/
static int ewrk3_open(struct net_device *dev);
static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ewrk3_interrupt(int irq, void *dev_id);
static int ewrk3_close(struct net_device *dev);
static struct net_device_stats *ewrk3_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -884,7 +884,7 @@ err_out:
/*
** The EWRK3 interrupt handler.
*/
-static irqreturn_t ewrk3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ewrk3_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct ewrk3_private *lp;
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index 191bd429076a..38a13f440530 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -434,7 +434,7 @@ static void reset_timer(unsigned long data);
static void tx_timeout(struct net_device *dev);
static void init_ring(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
static int netdev_rx(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
static void __set_rx_mode(struct net_device *dev);
@@ -1453,7 +1453,7 @@ static void reset_rx_descriptors(struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t intr_handler(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct netdev_private *np = netdev_priv(dev);
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 55d86bc4c104..6764281b4531 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -229,7 +229,7 @@ struct fec_enet_private {
static int fec_enet_open(struct net_device *dev);
static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void fec_enet_mii(struct net_device *dev);
-static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
static void fec_enet_tx(struct net_device *dev);
static void fec_enet_rx(struct net_device *dev);
static int fec_enet_close(struct net_device *dev);
@@ -450,7 +450,7 @@ fec_timeout(struct net_device *dev)
* This is called from the MPC core interrupt.
*/
static irqreturn_t
-fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+fec_enet_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
volatile fec_t *fecp;
@@ -1236,7 +1236,7 @@ static void
mii_link_interrupt(void *dev_id);
#else
static irqreturn_t
-mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+mii_link_interrupt(int irq, void * dev_id);
#endif
#endif
@@ -1251,7 +1251,7 @@ static void __inline__ fec_request_intrs(struct net_device *dev)
static const struct idesc {
char *name;
unsigned short irq;
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
+ irq_handler_t handler;
} *idp, id[] = {
{ "fec(RX)", 86, fec_enet_interrupt },
{ "fec(TX)", 87, fec_enet_interrupt },
@@ -2117,7 +2117,7 @@ static void
mii_link_interrupt(void *dev_id)
#else
static irqreturn_t
-mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+mii_link_interrupt(int irq, void * dev_id)
#endif
{
struct net_device *dev = dev_id;
diff --git a/drivers/net/fec_8xx/fec_main.c b/drivers/net/fec_8xx/fec_main.c
index 22ac2df1aeb0..8e7a56fadfd2 100644
--- a/drivers/net/fec_8xx/fec_main.c
+++ b/drivers/net/fec_8xx/fec_main.c
@@ -30,6 +30,7 @@
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
#include <asm/8xx_immap.h>
#include <asm/pgtable.h>
@@ -37,7 +38,6 @@
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/commproc.h>
-#include <asm/dma-mapping.h>
#include "fec_8xx.h"
@@ -708,7 +708,7 @@ static void fec_enet_tx(struct net_device *dev)
* This is called from the MPC core interrupt.
*/
static irqreturn_t
-fec_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+fec_enet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct fec_enet_private *fep;
@@ -768,7 +768,7 @@ fec_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* This interrupt occurs when the PHY detects a link change. */
static irqreturn_t
-fec_mii_link_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+fec_mii_link_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct fec_enet_private *fep;
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 97db910fbc8c..c5ed635bce36 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -2397,7 +2397,7 @@ static void nv_link_irq(struct net_device *dev)
dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);
}
-static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t nv_nic_irq(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
@@ -2490,13 +2490,14 @@ static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs)
return IRQ_RETVAL(i);
}
-static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t nv_nic_irq_tx(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 events;
int i;
+ unsigned long flags;
dprintk(KERN_DEBUG "%s: nv_nic_irq_tx\n", dev->name);
@@ -2508,16 +2509,16 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
if (!(events & np->irqmask))
break;
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
nv_tx_done(dev);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
if (events & (NVREG_IRQ_TX_ERR)) {
dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
dev->name, events);
}
if (i > max_interrupt_work) {
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
pci_push(base);
@@ -2527,7 +2528,7 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data, struct pt_regs *regs)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_tx.\n", dev->name, i);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
break;
}
@@ -2576,7 +2577,7 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
#endif
#ifdef CONFIG_FORCEDETH_NAPI
-static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t nv_nic_irq_rx(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
u8 __iomem *base = get_hwbase(dev);
@@ -2594,13 +2595,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
return IRQ_HANDLED;
}
#else
-static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t nv_nic_irq_rx(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 events;
int i;
+ unsigned long flags;
dprintk(KERN_DEBUG "%s: nv_nic_irq_rx\n", dev->name);
@@ -2614,14 +2616,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
nv_rx_process(dev, dev->weight);
if (nv_alloc_rx(dev)) {
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
if (!np->in_shutdown)
mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
}
if (i > max_interrupt_work) {
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
pci_push(base);
@@ -2631,7 +2633,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_rx.\n", dev->name, i);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
break;
}
}
@@ -2641,13 +2643,14 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data, struct pt_regs *regs)
}
#endif
-static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t nv_nic_irq_other(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
u8 __iomem *base = get_hwbase(dev);
u32 events;
int i;
+ unsigned long flags;
dprintk(KERN_DEBUG "%s: nv_nic_irq_other\n", dev->name);
@@ -2660,14 +2663,14 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
break;
if (events & NVREG_IRQ_LINK) {
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
nv_link_irq(dev);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
}
if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
nv_linkchange(dev);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
np->link_timeout = jiffies + LINK_TIMEOUT;
}
if (events & (NVREG_IRQ_UNKNOWN)) {
@@ -2675,7 +2678,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
dev->name, events);
}
if (i > max_interrupt_work) {
- spin_lock_irq(&np->lock);
+ spin_lock_irqsave(&np->lock, flags);
/* disable interrupts on the nic */
writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
pci_push(base);
@@ -2685,7 +2688,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
}
printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq_other.\n", dev->name, i);
- spin_unlock_irq(&np->lock);
+ spin_unlock_irqrestore(&np->lock, flags);
break;
}
@@ -2695,7 +2698,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data, struct pt_regs *regs)
return IRQ_RETVAL(i);
}
-static irqreturn_t nv_nic_irq_test(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t nv_nic_irq_test(int foo, void *data)
{
struct net_device *dev = (struct net_device *) data;
struct fe_priv *np = netdev_priv(dev);
@@ -2905,22 +2908,22 @@ static void nv_do_nic_poll(unsigned long data)
pci_push(base);
if (!using_multi_irqs(dev)) {
- nv_nic_irq(0, dev, NULL);
+ nv_nic_irq(0, dev);
if (np->msi_flags & NV_MSI_X_ENABLED)
enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector);
else
enable_irq_lockdep(dev->irq);
} else {
if (np->nic_poll_irq & NVREG_IRQ_RX_ALL) {
- nv_nic_irq_rx(0, dev, NULL);
+ nv_nic_irq_rx(0, dev);
enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
}
if (np->nic_poll_irq & NVREG_IRQ_TX_ALL) {
- nv_nic_irq_tx(0, dev, NULL);
+ nv_nic_irq_tx(0, dev);
enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_TX].vector);
}
if (np->nic_poll_irq & NVREG_IRQ_OTHER) {
- nv_nic_irq_other(0, dev, NULL);
+ nv_nic_irq_other(0, dev);
enable_irq_lockdep(np->msi_x_entry[NV_MSI_X_VECTOR_OTHER].vector);
}
}
@@ -3789,6 +3792,12 @@ static int nv_loopback_test(struct net_device *dev)
/* setup packet for tx */
pkt_len = ETH_DATA_LEN;
tx_skb = dev_alloc_skb(pkt_len);
+ if (!tx_skb) {
+ printk(KERN_ERR "dev_alloc_skb() failed during loopback test"
+ " of %s\n", dev->name);
+ ret = 0;
+ goto out;
+ }
pkt_data = skb_put(tx_skb, pkt_len);
for (i = 0; i < pkt_len; i++)
pkt_data[i] = (u8)(i & 0xff);
@@ -3853,7 +3862,7 @@ static int nv_loopback_test(struct net_device *dev)
tx_skb->end-tx_skb->data,
PCI_DMA_TODEVICE);
dev_kfree_skb_any(tx_skb);
-
+ out:
/* stop engines */
nv_stop_rx(dev);
nv_stop_tx(dev);
diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c
index 34412bc7c4b6..cb3958704a87 100644
--- a/drivers/net/fs_enet/fs_enet-main.c
+++ b/drivers/net/fs_enet/fs_enet-main.c
@@ -441,7 +441,7 @@ static void fs_enet_tx(struct net_device *dev)
* This is called from the MPC core interrupt.
*/
static irqreturn_t
-fs_enet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+fs_enet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct fs_enet_private *fep;
@@ -667,7 +667,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
static int fs_request_irq(struct net_device *dev, int irq, const char *name,
- irqreturn_t (*irqf)(int irq, void *dev_id, struct pt_regs *regs))
+ irq_handler_t irqf)
{
struct fs_enet_private *fep = netdev_priv(dev);
@@ -944,12 +944,13 @@ extern int fs_mii_connect(struct net_device *dev);
extern void fs_mii_disconnect(struct net_device *dev);
static struct net_device *fs_init_instance(struct device *dev,
- const struct fs_platform_info *fpi)
+ struct fs_platform_info *fpi)
{
struct net_device *ndev = NULL;
struct fs_enet_private *fep = NULL;
int privsize, i, r, err = 0, registered = 0;
+ fpi->fs_no = fs_get_id(fpi);
/* guard */
if ((unsigned int)fpi->fs_no >= FS_MAX_INDEX)
return ERR_PTR(-EINVAL);
@@ -971,7 +972,7 @@ static struct net_device *fs_init_instance(struct device *dev,
dev_set_drvdata(dev, ndev);
fep->fpi = fpi;
if (fpi->init_ioports)
- fpi->init_ioports();
+ fpi->init_ioports((struct fs_platform_info *)fpi);
#ifdef CONFIG_FS_ENET_HAS_FEC
if (fs_get_fec_index(fpi->fs_no) >= 0)
diff --git a/drivers/net/fs_enet/fs_enet.h b/drivers/net/fs_enet/fs_enet.h
index 95022c005f75..92590d8fc24b 100644
--- a/drivers/net/fs_enet/fs_enet.h
+++ b/drivers/net/fs_enet/fs_enet.h
@@ -6,11 +6,10 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/phy.h>
+#include <linux/dma-mapping.h>
#include <linux/fs_enet_pd.h>
-#include <asm/dma-mapping.h>
-
#ifdef CONFIG_CPM1
#include <asm/commproc.h>
diff --git a/drivers/net/fs_enet/mii-fec.c b/drivers/net/fs_enet/mii-fec.c
index 1328e10caa35..baaae3dbf2e6 100644
--- a/drivers/net/fs_enet/mii-fec.c
+++ b/drivers/net/fs_enet/mii-fec.c
@@ -12,8 +12,6 @@
* kind, whether express or implied.
*/
-
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 280b114e253f..a06d8d1aaceb 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -119,9 +119,9 @@ struct sk_buff *gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp);
static struct net_device_stats *gfar_get_stats(struct net_device *dev);
static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
-static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_error(int irq, void *dev_id);
+static irqreturn_t gfar_transmit(int irq, void *dev_id);
+static irqreturn_t gfar_interrupt(int irq, void *dev_id);
static void adjust_link(struct net_device *dev);
static void init_registers(struct net_device *dev);
static int init_phy(struct net_device *dev);
@@ -1173,7 +1173,7 @@ static void gfar_timeout(struct net_device *dev)
}
/* Interrupt Handler for Transmit complete */
-static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_transmit(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct gfar_private *priv = netdev_priv(dev);
@@ -1305,7 +1305,7 @@ static inline void count_errors(unsigned short status, struct gfar_private *priv
}
}
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t gfar_receive(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct gfar_private *priv = netdev_priv(dev);
@@ -1537,7 +1537,7 @@ static int gfar_poll(struct net_device *dev, int *budget)
#endif
/* The interrupt handler for devices with one interrupt */
-static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct gfar_private *priv = netdev_priv(dev);
@@ -1550,11 +1550,11 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* Check for reception */
if ((events & IEVENT_RXF0) || (events & IEVENT_RXB0))
- gfar_receive(irq, dev_id, regs);
+ gfar_receive(irq, dev_id);
/* Check for transmit completion */
if ((events & IEVENT_TXF) || (events & IEVENT_TXB))
- gfar_transmit(irq, dev_id, regs);
+ gfar_transmit(irq, dev_id);
/* Update error statistics */
if (events & IEVENT_TXE) {
@@ -1578,7 +1578,7 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
priv->stats.rx_errors++;
priv->extra_stats.rx_bsy++;
- gfar_receive(irq, dev_id, regs);
+ gfar_receive(irq, dev_id);
#ifndef CONFIG_GFAR_NAPI
/* Clear the halt bit in RSTAT */
@@ -1857,7 +1857,7 @@ static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr)
}
/* GFAR error interrupt handler */
-static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gfar_error(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct gfar_private *priv = netdev_priv(dev);
@@ -1898,7 +1898,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
priv->stats.rx_errors++;
priv->extra_stats.rx_bsy++;
- gfar_receive(irq, dev_id, regs);
+ gfar_receive(irq, dev_id);
#ifndef CONFIG_GFAR_NAPI
/* Clear the halt bit in RSTAT */
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c35d47c40c39..9e81a50cf2be 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -754,7 +754,7 @@ static inline void gfar_write(volatile unsigned __iomem *addr, u32 val)
out_be32(addr, val);
}
-extern irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t gfar_receive(int irq, void *dev_id);
extern int startup_gfar(struct net_device *dev);
extern void stop_gfar(struct net_device *dev);
extern void gfar_halt(struct net_device *dev);
diff --git a/drivers/net/gt64240eth.h b/drivers/net/gt64240eth.h
deleted file mode 100644
index 0d6f486e4579..000000000000
--- a/drivers/net/gt64240eth.h
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2001 Patton Electronics Company
- * Copyright (C) 2002 Momentum Computer
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or support@mvista.com
- *
- * This program is free software; you can distribute 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 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.
- *
- * Ethernet driver definitions for the MIPS GT96100 Advanced
- * Communication Controller.
- *
- * Modified for the Marvellous GT64240 Retarded Communication Controller.
- */
-#ifndef _GT64240ETH_H
-#define _GT64240ETH_H
-
-#include <asm/gt64240.h>
-
-#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400
-
-/* Translate those weanie names from Galileo/VxWorks header files: */
-
-#define GT64240_MRR MAIN_ROUTING_REGISTER
-#define GT64240_CIU_ARBITER_CONFIG COMM_UNIT_ARBITER_CONFIGURATION_REGISTER
-#define GT64240_CIU_ARBITER_CONTROL COMM_UNIT_ARBITER_CONTROL
-#define GT64240_MAIN_LOW_CAUSE LOW_INTERRUPT_CAUSE_REGISTER
-#define GT64240_MAIN_HIGH_CAUSE HIGH_INTERRUPT_CAUSE_REGISTER
-#define GT64240_CPU_LOW_MASK CPU_INTERRUPT_MASK_REGISTER_LOW
-#define GT64240_CPU_HIGH_MASK CPU_INTERRUPT_MASK_REGISTER_HIGH
-#define GT64240_CPU_SELECT_CAUSE CPU_SELECT_CAUSE_REGISTER
-
-#define GT64240_ETH_PHY_ADDR_REG ETHERNET_PHY_ADDRESS_REGISTER
-#define GT64240_ETH_PORT_CONFIG ETHERNET0_PORT_CONFIGURATION_REGISTER
-#define GT64240_ETH_PORT_CONFIG_EXT ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER
-#define GT64240_ETH_PORT_COMMAND ETHERNET0_PORT_COMMAND_REGISTER
-#define GT64240_ETH_PORT_STATUS ETHERNET0_PORT_STATUS_REGISTER
-#define GT64240_ETH_IO_SIZE ETHERNET_PORTS_DIFFERENCE_OFFSETS
-#define GT64240_ETH_SMI_REG ETHERNET_SMI_REGISTER
-#define GT64240_ETH_MIB_COUNT_BASE ETHERNET0_MIB_COUNTER_BASE
-#define GT64240_ETH_SDMA_CONFIG ETHERNET0_SDMA_CONFIGURATION_REGISTER
-#define GT64240_ETH_SDMA_COMM ETHERNET0_SDMA_COMMAND_REGISTER
-#define GT64240_ETH_INT_MASK ETHERNET0_INTERRUPT_MASK_REGISTER
-#define GT64240_ETH_INT_CAUSE ETHERNET0_INTERRUPT_CAUSE_REGISTER
-#define GT64240_ETH_CURR_TX_DESC_PTR0 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0
-#define GT64240_ETH_CURR_TX_DESC_PTR1 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1
-#define GT64240_ETH_1ST_RX_DESC_PTR0 ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0
-#define GT64240_ETH_CURR_RX_DESC_PTR0 ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0
-#define GT64240_ETH_HASH_TBL_PTR ETHERNET0_HASH_TABLE_POINTER_REGISTER
-
-/* Turn on NAPI by default */
-
-#define GT64240_NAPI 1
-
-/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */
-/* (Board-specific to the DSL3224 Rev A board ONLY!) */
-#define D3224_MPP_CTRL0_SETTING 0x66669900
-#define D3224_MPP_CTRL1_SETTING 0x00000000
-#define D3224_MPP_CTRL2_SETTING 0x00887700
-#define D3224_MPP_CTRL3_SETTING 0x00000044
-#define D3224_GPP_IO_CTRL_SETTING 0x0000e800
-#define D3224_GPP_LEVEL_CTRL_SETTING 0xf001f703
-#define D3224_GPP_VALUE_SETTING 0x00000000
-
-/* Keep the ring sizes a power of two for efficiency. */
-//-#define TX_RING_SIZE 16
-#define TX_RING_SIZE 64 /* TESTING !!! */
-#define RX_RING_SIZE 32
-#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
-
-#define RX_HASH_TABLE_SIZE 16384
-#define HASH_HOP_NUMBER 12
-
-#define NUM_INTERFACES 3
-
-#define GT64240ETH_TX_TIMEOUT HZ/4
-
-#define MIPS_GT64240_BASE 0xf4000000
-#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG)
-#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE)
-#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE)
-
-#if defined(CONFIG_MIPS_DSL3224)
-#define GT64240_ETHER0_IRQ 4
-#define GT64240_ETHER1_IRQ 4
-#else
-#define GT64240_ETHER0_IRQ -1
-#define GT64240_ETHER1_IRQ -1
-#endif
-
-#define REV_GT64240 0x1
-#define REV_GT64240A 0x10
-
-#define GT64240ETH_READ(gp, offset) \
- GT_READ((gp)->port_offset + (offset))
-
-#define GT64240ETH_WRITE(gp, offset, data) \
- GT_WRITE((gp)->port_offset + (offset), (data))
-
-#define GT64240ETH_SETBIT(gp, offset, bits) \
- GT64240ETH_WRITE((gp), (offset), \
- GT64240ETH_READ((gp), (offset)) | (bits))
-
-#define GT64240ETH_CLRBIT(gp, offset, bits) \
- GT64240ETH_WRITE((gp), (offset), \
- GT64240ETH_READ((gp), (offset)) & ~(bits))
-
-#define GT64240_READ(ofs) GT_READ(ofs)
-#define GT64240_WRITE(ofs, data) GT_WRITE((ofs), (data))
-
-/* Bit definitions of the SMI Reg */
-enum {
- smirDataMask = 0xffff,
- smirPhyAdMask = 0x1f << 16,
- smirPhyAdBit = 16,
- smirRegAdMask = 0x1f << 21,
- smirRegAdBit = 21,
- smirOpCode = 1 << 26,
- smirReadValid = 1 << 27,
- smirBusy = 1 << 28
-};
-
-/* Bit definitions of the Port Config Reg */
-enum pcr_bits {
- pcrPM = 1 << 0,
- pcrRBM = 1 << 1,
- pcrPBF = 1 << 2,
- pcrEN = 1 << 7,
- pcrLPBKMask = 0x3 << 8,
- pcrLPBKBit = 1 << 8,
- pcrFC = 1 << 10,
- pcrHS = 1 << 12,
- pcrHM = 1 << 13,
- pcrHDM = 1 << 14,
- pcrHD = 1 << 15,
- pcrISLMask = 0x7 << 28,
- pcrISLBit = 28,
- pcrACCS = 1 << 31
-};
-
-/* Bit definitions of the Port Config Extend Reg */
-enum pcxr_bits {
- pcxrIGMP = 1,
- pcxrSPAN = 2,
- pcxrPAR = 4,
- pcxrPRIOtxMask = 0x7 << 3,
- pcxrPRIOtxBit = 3,
- pcxrPRIOrxMask = 0x3 << 6,
- pcxrPRIOrxBit = 6,
- pcxrPRIOrxOverride = 1 << 8,
- pcxrDPLXen = 1 << 9,
- pcxrFCTLen = 1 << 10,
- pcxrFLP = 1 << 11,
- pcxrFCTL = 1 << 12,
- pcxrMFLMask = 0x3 << 14,
- pcxrMFLBit = 14,
- pcxrMIBclrMode = 1 << 16,
- pcxrSpeed = 1 << 18,
- pcxrSpeeden = 1 << 19,
- pcxrRMIIen = 1 << 20,
- pcxrDSCPen = 1 << 21
-};
-
-/* Bit definitions of the Port Command Reg */
-enum pcmr_bits {
- pcmrFJ = 1 << 15
-};
-
-
-/* Bit definitions of the Port Status Reg */
-enum psr_bits {
- psrSpeed = 1,
- psrDuplex = 2,
- psrFctl = 4,
- psrLink = 8,
- psrPause = 1 << 4,
- psrTxLow = 1 << 5,
- psrTxHigh = 1 << 6,
- psrTxInProg = 1 << 7
-};
-
-/* Bit definitions of the SDMA Config Reg */
-enum sdcr_bits {
- sdcrRCMask = 0xf << 2,
- sdcrRCBit = 2,
- sdcrBLMR = 1 << 6,
- sdcrBLMT = 1 << 7,
- sdcrPOVR = 1 << 8,
- sdcrRIFB = 1 << 9,
- sdcrBSZMask = 0x3 << 12,
- sdcrBSZBit = 12
-};
-
-/* Bit definitions of the SDMA Command Reg */
-enum sdcmr_bits {
- sdcmrERD = 1 << 7,
- sdcmrAR = 1 << 15,
- sdcmrSTDH = 1 << 16,
- sdcmrSTDL = 1 << 17,
- sdcmrTXDH = 1 << 23,
- sdcmrTXDL = 1 << 24,
- sdcmrAT = 1 << 31
-};
-
-/* Bit definitions of the Interrupt Cause Reg */
-enum icr_bits {
- icrRxBuffer = 1,
- icrTxBufferHigh = 1 << 2,
- icrTxBufferLow = 1 << 3,
- icrTxEndHigh = 1 << 6,
- icrTxEndLow = 1 << 7,
- icrRxError = 1 << 8,
- icrTxErrorHigh = 1 << 10,
- icrTxErrorLow = 1 << 11,
- icrRxOVR = 1 << 12,
- icrTxUdr = 1 << 13,
- icrRxBufferQ0 = 1 << 16,
- icrRxBufferQ1 = 1 << 17,
- icrRxBufferQ2 = 1 << 18,
- icrRxBufferQ3 = 1 << 19,
- icrRxErrorQ0 = 1 << 20,
- icrRxErrorQ1 = 1 << 21,
- icrRxErrorQ2 = 1 << 22,
- icrRxErrorQ3 = 1 << 23,
- icrMIIPhySTC = 1 << 28,
- icrSMIdone = 1 << 29,
- icrEtherIntSum = 1 << 31
-};
-
-
-/* The Rx and Tx descriptor lists. */
-#ifdef __LITTLE_ENDIAN
-typedef struct {
- u32 cmdstat;
- u16 reserved; //-prk21aug01 u32 reserved:16;
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u32 buff_ptr;
- u32 next;
-} gt64240_td_t;
-
-typedef struct {
- u32 cmdstat;
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
- u32 buff_ptr;
- u32 next;
-} gt64240_rd_t;
-#elif defined(__BIG_ENDIAN)
-typedef struct {
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u16 reserved; //-prk21aug01 u32 reserved:16;
- u32 cmdstat;
- u32 next;
- u32 buff_ptr;
-} gt64240_td_t;
-
-typedef struct {
- u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
- u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
- u32 cmdstat;
- u32 next;
- u32 buff_ptr;
-} gt64240_rd_t;
-#else
-#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined!
-#endif
-
-
-/* Values for the Tx command-status descriptor entry. */
-enum td_cmdstat {
- txOwn = 1 << 31,
- txAutoMode = 1 << 30,
- txEI = 1 << 23,
- txGenCRC = 1 << 22,
- txPad = 1 << 18,
- txFirst = 1 << 17,
- txLast = 1 << 16,
- txErrorSummary = 1 << 15,
- txReTxCntMask = 0x0f << 10,
- txReTxCntBit = 10,
- txCollision = 1 << 9,
- txReTxLimit = 1 << 8,
- txUnderrun = 1 << 6,
- txLateCollision = 1 << 5
-};
-
-
-/* Values for the Rx command-status descriptor entry. */
-enum rd_cmdstat {
- rxOwn = 1 << 31,
- rxAutoMode = 1 << 30,
- rxEI = 1 << 23,
- rxFirst = 1 << 17,
- rxLast = 1 << 16,
- rxErrorSummary = 1 << 15,
- rxIGMP = 1 << 14,
- rxHashExpired = 1 << 13,
- rxMissedFrame = 1 << 12,
- rxFrameType = 1 << 11,
- rxShortFrame = 1 << 8,
- rxMaxFrameLen = 1 << 7,
- rxOverrun = 1 << 6,
- rxCollision = 1 << 4,
- rxCRCError = 1
-};
-
-/* Bit fields of a Hash Table Entry */
-enum hash_table_entry {
- hteValid = 1,
- hteSkip = 2,
- hteRD = 4
-};
-
-// The MIB counters
-typedef struct {
- u32 byteReceived;
- u32 byteSent;
- u32 framesReceived;
- u32 framesSent;
- u32 totalByteReceived;
- u32 totalFramesReceived;
- u32 broadcastFramesReceived;
- u32 multicastFramesReceived;
- u32 cRCError;
- u32 oversizeFrames;
- u32 fragments;
- u32 jabber;
- u32 collision;
- u32 lateCollision;
- u32 frames64;
- u32 frames65_127;
- u32 frames128_255;
- u32 frames256_511;
- u32 frames512_1023;
- u32 frames1024_MaxSize;
- u32 macRxError;
- u32 droppedFrames;
- u32 outMulticastFrames;
- u32 outBroadcastFrames;
- u32 undersizeFrames;
-} mib_counters_t;
-
-
-struct gt64240_private {
- gt64240_rd_t *rx_ring;
- gt64240_td_t *tx_ring;
- // The Rx and Tx rings must be 16-byte aligned
- dma_addr_t rx_ring_dma;
- dma_addr_t tx_ring_dma;
- char *hash_table;
- // The Hash Table must be 8-byte aligned
- dma_addr_t hash_table_dma;
- int hash_mode;
-
- // The Rx buffers must be 8-byte aligned
- char *rx_buff;
- dma_addr_t rx_buff_dma;
- // Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
- // of payload must be 8-byte aligned
- struct sk_buff *tx_skbuff[TX_RING_SIZE];
- int rx_next_out; /* The next free ring entry to receive */
- int tx_next_in; /* The next free ring entry to send */
- int tx_next_out; /* The last ring entry the ISR processed */
- int tx_count; /* current # of pkts waiting to be sent in Tx ring */
- int intr_work_done; /* number of Rx and Tx pkts processed in the isr */
- int tx_full; /* Tx ring is full */
-
- mib_counters_t mib;
- struct net_device_stats stats;
-
- int io_size;
- int port_num; // 0 or 1
- u32 port_offset;
-
- int phy_addr; // PHY address
- u32 last_psr; // last value of the port status register
-
- int options; /* User-settable misc. driver options. */
- int drv_flags;
- spinlock_t lock; /* Serialise access to device */
- struct mii_if_info mii_if;
-
- u32 msg_enable;
-};
-
-#endif /* _GT64240ETH_H */
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 5c89ae78a519..c3c0d67fc383 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -556,7 +556,7 @@ static void hamachi_timer(unsigned long data);
static void hamachi_tx_timeout(struct net_device *dev);
static void hamachi_init_ring(struct net_device *dev);
static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t hamachi_interrupt(int irq, void *dev_instance);
static int hamachi_rx(struct net_device *dev);
static inline int hamachi_tx(struct net_device *dev);
static void hamachi_error(struct net_device *dev, int intr_status);
@@ -1376,7 +1376,7 @@ static int hamachi_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t hamachi_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t hamachi_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct hamachi_private *hmp = netdev_priv(dev);
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 9220de9f4fe7..1ed9cccd3c11 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -323,7 +323,7 @@ static int eppconfig(struct baycom_state *bc)
/* ---------------------------------------------------------------------- */
-static void epp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void epp_interrupt(int irq, void *dev_id)
{
}
diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c
index 77411a00d1ee..5930aeb35015 100644
--- a/drivers/net/hamradio/baycom_par.c
+++ b/drivers/net/hamradio/baycom_par.c
@@ -270,7 +270,7 @@ static __inline__ void par96_rx(struct net_device *dev, struct baycom_state *bc)
/* --------------------------------------------------------------------- */
-static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void par96_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct baycom_state *bc = netdev_priv(dev);
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c
index 55906c7b4bb1..59214e74b9cf 100644
--- a/drivers/net/hamradio/baycom_ser_fdx.c
+++ b/drivers/net/hamradio/baycom_ser_fdx.c
@@ -279,7 +279,7 @@ static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc,
/* --------------------------------------------------------------------- */
-static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ser12_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct baycom_state *bc = netdev_priv(dev);
diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c
index de95de8983da..3bcc57acbe6d 100644
--- a/drivers/net/hamradio/baycom_ser_hdx.c
+++ b/drivers/net/hamradio/baycom_ser_hdx.c
@@ -373,7 +373,7 @@ static inline void ser12_rx(struct net_device *dev, struct baycom_state *bc)
/* --------------------------------------------------------------------- */
-static irqreturn_t ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ser12_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct baycom_state *bc = netdev_priv(dev);
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index c9a46b89942a..0f8b9afd55b4 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -249,7 +249,7 @@ static void start_timer(struct scc_priv *priv, int t, int r15);
static inline unsigned char random(void);
static inline void z8530_isr(struct scc_info *info);
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t scc_isr(int irq, void *dev_id);
static void rx_isr(struct scc_priv *priv);
static void special_condition(struct scc_priv *priv, int rc);
static void rx_bh(void *arg);
@@ -1142,7 +1142,7 @@ static inline void z8530_isr(struct scc_info *info)
}
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scc_isr(int irq, void *dev_id)
{
struct scc_info *info = dev_id;
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index df4b68142ac7..ec9b6d9b6f05 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -200,7 +200,7 @@ static void z8530_init(void);
static void init_channel(struct scc_channel *scc);
static void scc_key_trx (struct scc_channel *scc, char tx);
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t scc_isr(int irq, void *dev_id);
static void scc_init_timer(struct scc_channel *scc);
static int scc_net_alloc(const char *name, struct scc_channel *scc);
@@ -626,7 +626,7 @@ static void scc_isr_dispatch(struct scc_channel *scc, int vector)
#define SCC_IRQTIMEOUT 30000
-static irqreturn_t scc_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scc_isr(int irq, void *dev_id)
{
unsigned char vector;
struct scc_channel *scc;
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index f98f5777dfbb..3c4455bd466d 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -702,7 +702,7 @@ static void yam_tx_byte(struct net_device *dev, struct yam_port *yp)
* ISR routine
************************************************************************************/
-static irqreturn_t yam_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t yam_interrupt(int irq, void *dev_id)
{
struct net_device *dev;
struct yam_port *yp;
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index 03b3df33d81b..844c136e9920 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -188,10 +188,12 @@ struct hp100_private {
/*
* variables
*/
+#ifdef CONFIG_ISA
static const char *hp100_isa_tbl[] = {
"HWPF150", /* HP J2573 rev A */
"HWP1950", /* HP J2573 */
};
+#endif
#ifdef CONFIG_EISA
static struct eisa_device_id hp100_eisa_tbl[] = {
@@ -247,7 +249,7 @@ static void hp100_misc_interrupt(struct net_device *dev);
static void hp100_update_stats(struct net_device *dev);
static void hp100_clear_stats(struct hp100_private *lp, int ioaddr);
static void hp100_set_multicast_list(struct net_device *dev);
-static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t hp100_interrupt(int irq, void *dev_id);
static void hp100_start_interface(struct net_device *dev);
static void hp100_stop_interface(struct net_device *dev);
static void hp100_load_eeprom(struct net_device *dev, u_short ioaddr);
@@ -333,6 +335,7 @@ static __devinit const char *hp100_read_id(int ioaddr)
return str;
}
+#ifdef CONFIG_ISA
static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
{
const char *sig;
@@ -390,9 +393,9 @@ static int __init hp100_isa_probe(struct net_device *dev, int addr)
}
return err;
}
+#endif /* CONFIG_ISA */
-
-#ifndef MODULE
+#if !defined(MODULE) && defined(CONFIG_ISA)
struct net_device * __init hp100_probe(int unit)
{
struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
@@ -422,7 +425,7 @@ struct net_device * __init hp100_probe(int unit)
free_netdev(dev);
return ERR_PTR(err);
}
-#endif
+#endif /* !MODULE && CONFIG_ISA */
static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
u_char bus, struct pci_dev *pci_dev)
@@ -2184,7 +2187,7 @@ static void hp100_set_multicast_list(struct net_device *dev)
* hardware interrupt handling
*/
-static irqreturn_t hp100_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hp100_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct hp100_private *lp = netdev_priv(dev);
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
index d52e3bd01301..ffeafb28f782 100644
--- a/drivers/net/ibm_emac/ibm_emac_core.c
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -184,7 +184,7 @@ static const char emac_stats_keys[EMAC_ETHTOOL_STATS_COUNT][ETH_GSTRING_LEN] = {
"tx_errors"
};
-static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t emac_irq(int irq, void *dev_instance);
static void emac_clean_tx_ring(struct ocp_enet_private *dev);
static inline int emac_phy_supports_gige(int phy_mode)
@@ -1515,7 +1515,7 @@ static void emac_rxde(void *param)
}
/* Hard IRQ */
-static irqreturn_t emac_irq(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t emac_irq(int irq, void *dev_instance)
{
struct ocp_enet_private *dev = dev_instance;
struct emac_regs __iomem *p = dev->emacp;
diff --git a/drivers/net/ibm_emac/ibm_emac_debug.c b/drivers/net/ibm_emac/ibm_emac_debug.c
index c3645908034d..92f970d402df 100644
--- a/drivers/net/ibm_emac/ibm_emac_debug.c
+++ b/drivers/net/ibm_emac/ibm_emac_debug.c
@@ -179,8 +179,7 @@ void emac_dbg_dump_all(void)
}
#if defined(CONFIG_MAGIC_SYSRQ)
-static void emac_sysrq_handler(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void emac_sysrq_handler(int key, struct tty_struct *tty)
{
emac_dbg_dump_all();
}
diff --git a/drivers/net/ibm_emac/ibm_emac_debug.h b/drivers/net/ibm_emac/ibm_emac_debug.h
index 5761389495d0..6c7dccc84bf5 100644
--- a/drivers/net/ibm_emac/ibm_emac_debug.h
+++ b/drivers/net/ibm_emac/ibm_emac_debug.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_emac/ibm_ocp_debug.h
+ * drivers/net/ibm_emac/ibm_emac_debug.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, debug print routines.
*
diff --git a/drivers/net/ibm_emac/ibm_emac_mal.c b/drivers/net/ibm_emac/ibm_emac_mal.c
index af50e7b2e0d7..6c0f071e4052 100644
--- a/drivers/net/ibm_emac/ibm_emac_mal.c
+++ b/drivers/net/ibm_emac/ibm_emac_mal.c
@@ -168,7 +168,7 @@ static inline void mal_disable_eob_irq(struct ibm_ocp_mal *mal)
MAL_DBG2("%d: disable_irq" NL, mal->def->index);
}
-static irqreturn_t mal_serr(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t mal_serr(int irq, void *dev_instance)
{
struct ibm_ocp_mal *mal = dev_instance;
u32 esr = get_mal_dcrn(mal, MAL_ESR);
@@ -216,7 +216,7 @@ static inline void mal_schedule_poll(struct ibm_ocp_mal *mal)
MAL_DBG2("%d: already in poll" NL, mal->def->index);
}
-static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t mal_txeob(int irq, void *dev_instance)
{
struct ibm_ocp_mal *mal = dev_instance;
u32 r = get_mal_dcrn(mal, MAL_TXEOBISR);
@@ -226,7 +226,7 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t mal_rxeob(int irq, void *dev_instance)
{
struct ibm_ocp_mal *mal = dev_instance;
u32 r = get_mal_dcrn(mal, MAL_RXEOBISR);
@@ -236,7 +236,7 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t mal_txde(int irq, void *dev_instance)
{
struct ibm_ocp_mal *mal = dev_instance;
u32 deir = get_mal_dcrn(mal, MAL_TXDEIR);
@@ -252,7 +252,7 @@ static irqreturn_t mal_txde(int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t mal_rxde(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t mal_rxde(int irq, void *dev_instance)
{
struct ibm_ocp_mal *mal = dev_instance;
struct list_head *l;
diff --git a/drivers/net/ibm_emac/ibm_emac_rgmii.h b/drivers/net/ibm_emac/ibm_emac_rgmii.h
index 94abde55e2e9..117ea486c2ca 100644
--- a/drivers/net/ibm_emac/ibm_emac_rgmii.h
+++ b/drivers/net/ibm_emac/ibm_emac_rgmii.h
@@ -1,5 +1,5 @@
/*
- * drivers/net/ibm_emac/ibm_emac_rgmii.c
+ * drivers/net/ibm_emac/ibm_emac_rgmii.h
*
* Driver for PowerPC 4xx on-chip ethernet controller, RGMII bridge support.
*
diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c
index 2a95d72fa593..3f946c811511 100644
--- a/drivers/net/ibmlana.c
+++ b/drivers/net/ibmlana.c
@@ -705,7 +705,7 @@ static void irqtxerr_handler(struct net_device *dev)
/* general interrupt entry */
-static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs)
+static irqreturn_t irq_handler(int irq, void *device)
{
struct net_device *dev = (struct net_device *) device;
u16 ival;
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c
index 767203d35bc2..44c9f993dcc4 100644
--- a/drivers/net/ibmveth.c
+++ b/drivers/net/ibmveth.c
@@ -93,7 +93,7 @@ static void ibmveth_proc_register_driver(void);
static void ibmveth_proc_unregister_driver(void);
static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter);
static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter);
-static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance);
static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter);
static struct kobj_type ktype_veth_pool;
@@ -212,7 +212,8 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
break;
}
- free_index = pool->consumer_index++ % pool->size;
+ free_index = pool->consumer_index;
+ pool->consumer_index = (pool->consumer_index + 1) % pool->size;
index = pool->free_map[free_index];
ibmveth_assert(index != IBM_VETH_INVALID_MAP);
@@ -238,7 +239,10 @@ static void ibmveth_replenish_buffer_pool(struct ibmveth_adapter *adapter, struc
if(lpar_rc != H_SUCCESS) {
pool->free_map[free_index] = index;
pool->skbuff[index] = NULL;
- pool->consumer_index--;
+ if (pool->consumer_index == 0)
+ pool->consumer_index = pool->size - 1;
+ else
+ pool->consumer_index--;
dma_unmap_single(&adapter->vdev->dev,
pool->dma_addr[index], pool->buff_size,
DMA_FROM_DEVICE);
@@ -325,7 +329,10 @@ static void ibmveth_remove_buffer_from_pool(struct ibmveth_adapter *adapter, u64
adapter->rx_buff_pool[pool].buff_size,
DMA_FROM_DEVICE);
- free_index = adapter->rx_buff_pool[pool].producer_index++ % adapter->rx_buff_pool[pool].size;
+ free_index = adapter->rx_buff_pool[pool].producer_index;
+ adapter->rx_buff_pool[pool].producer_index
+ = (adapter->rx_buff_pool[pool].producer_index + 1)
+ % adapter->rx_buff_pool[pool].size;
adapter->rx_buff_pool[pool].free_map[free_index] = index;
mb();
@@ -437,6 +444,31 @@ static void ibmveth_cleanup(struct ibmveth_adapter *adapter)
&adapter->rx_buff_pool[i]);
}
+static int ibmveth_register_logical_lan(struct ibmveth_adapter *adapter,
+ union ibmveth_buf_desc rxq_desc, u64 mac_address)
+{
+ int rc, try_again = 1;
+
+ /* After a kexec the adapter will still be open, so our attempt to
+ * open it will fail. So if we get a failure we free the adapter and
+ * try again, but only once. */
+retry:
+ rc = h_register_logical_lan(adapter->vdev->unit_address,
+ adapter->buffer_list_dma, rxq_desc.desc,
+ adapter->filter_list_dma, mac_address);
+
+ if (rc != H_SUCCESS && try_again) {
+ do {
+ rc = h_free_logical_lan(adapter->vdev->unit_address);
+ } while (H_IS_LONG_BUSY(rc) || (rc == H_BUSY));
+
+ try_again = 0;
+ goto retry;
+ }
+
+ return rc;
+}
+
static int ibmveth_open(struct net_device *netdev)
{
struct ibmveth_adapter *adapter = netdev->priv;
@@ -502,12 +534,9 @@ static int ibmveth_open(struct net_device *netdev)
ibmveth_debug_printk("filter list @ 0x%p\n", adapter->filter_list_addr);
ibmveth_debug_printk("receive q @ 0x%p\n", adapter->rx_queue.queue_addr);
+ h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE);
- lpar_rc = h_register_logical_lan(adapter->vdev->unit_address,
- adapter->buffer_list_dma,
- rxq_desc.desc,
- adapter->filter_list_dma,
- mac_address);
+ lpar_rc = ibmveth_register_logical_lan(adapter, rxq_desc, mac_address);
if(lpar_rc != H_SUCCESS) {
ibmveth_error_printk("h_register_logical_lan failed with %ld\n", lpar_rc);
@@ -543,7 +572,7 @@ static int ibmveth_open(struct net_device *netdev)
}
ibmveth_debug_printk("initial replenish cycle\n");
- ibmveth_interrupt(netdev->irq, netdev, NULL);
+ ibmveth_interrupt(netdev->irq, netdev);
netif_start_queue(netdev);
@@ -816,7 +845,7 @@ static int ibmveth_poll(struct net_device *netdev, int *budget)
return 0;
}
-static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance)
{
struct net_device *netdev = dev_instance;
struct ibmveth_adapter *adapter = netdev->priv;
@@ -905,6 +934,14 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu)
return -EINVAL;
}
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void ibmveth_poll_controller(struct net_device *dev)
+{
+ ibmveth_replenish_task(dev->priv);
+ ibmveth_interrupt(dev->irq, dev);
+}
+#endif
+
static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id)
{
int rc, i;
@@ -977,6 +1014,9 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_
netdev->ethtool_ops = &netdev_ethtool_ops;
netdev->change_mtu = ibmveth_change_mtu;
SET_NETDEV_DEV(netdev, &dev->dev);
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ netdev->poll_controller = ibmveth_poll_controller;
+#endif
netdev->features |= NETIF_F_LLTX;
spin_lock_init(&adapter->stats_lock);
@@ -1132,7 +1172,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
{
struct proc_dir_entry *entry;
if (ibmveth_proc_dir) {
- entry = create_proc_entry(adapter->netdev->name, S_IFREG, ibmveth_proc_dir);
+ char u_addr[10];
+ sprintf(u_addr, "%x", adapter->vdev->unit_address);
+ entry = create_proc_entry(u_addr, S_IFREG, ibmveth_proc_dir);
if (!entry) {
ibmveth_error_printk("Cannot create adapter proc entry");
} else {
@@ -1147,7 +1189,9 @@ static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter)
static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter)
{
if (ibmveth_proc_dir) {
- remove_proc_entry(adapter->netdev->name, ibmveth_proc_dir);
+ char u_addr[10];
+ sprintf(u_addr, "%x", adapter->vdev->unit_address);
+ remove_proc_entry(u_addr, ibmveth_proc_dir);
}
}
@@ -1261,7 +1305,7 @@ const char * buf, size_t count)
}
/* kick the interrupt handler to allocate/deallocate pools */
- ibmveth_interrupt(netdev->irq, netdev, NULL);
+ ibmveth_interrupt(netdev->irq, netdev);
return count;
}
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c
index 6469130c1413..c26a4b8e552a 100644
--- a/drivers/net/ifb.c
+++ b/drivers/net/ifb.c
@@ -200,8 +200,8 @@ static struct net_device_stats *ifb_get_stats(struct net_device *dev)
pr_debug("tasklets stats %ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld:%ld \n",
dp->st_task_enter, dp->st_txq_refl_try, dp->st_rxq_enter,
- dp->st_rx2tx_tran dp->st_rxq_notenter, dp->st_rx_frm_egr,
- dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch );
+ dp->st_rx2tx_tran, dp->st_rxq_notenter, dp->st_rx_frm_egr,
+ dp->st_rx_frm_ing, dp->st_rxq_check, dp->st_rxq_rsch);
return stats;
}
diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
index 87650237dc5c..e963dbf816be 100644
--- a/drivers/net/ioc3-eth.c
+++ b/drivers/net/ioc3-eth.c
@@ -750,7 +750,7 @@ static void ioc3_error(struct ioc3_private *ip, u32 eisr)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t ioc3_interrupt(int irq, void *_dev, struct pt_regs *regs)
+static irqreturn_t ioc3_interrupt(int irq, void *_dev)
{
struct net_device *dev = (struct net_device *)_dev;
struct ioc3_private *ip = netdev_priv(dev);
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
index e9e6d99a9add..7c8ccc09b601 100644
--- a/drivers/net/irda/Kconfig
+++ b/drivers/net/irda/Kconfig
@@ -287,6 +287,7 @@ comment "FIR device drivers"
config USB_IRDA
tristate "IrDA USB dongles"
depends on IRDA && USB
+ select FW_LOADER
---help---
Say Y here if you want to build support for the USB IrDA FIR Dongle
device driver. To compile it as a module, choose M here: the module
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 68d4c418cb98..cebf8c374bc5 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -660,22 +660,15 @@ static int ali_ircc_read_dongle_id (int i, chipio_t *info)
* An interrupt from the chip has arrived. Time to do some work
*
*/
-static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct ali_ircc_cb *self;
int ret;
IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __FUNCTION__);
- if (!dev) {
- IRDA_WARNING("%s: irq %d for unknown device.\n",
- ALI_IRCC_DRIVER_NAME, irq);
- return IRQ_NONE;
- }
-
- self = (struct ali_ircc_cb *) dev->priv;
+ self = dev->priv;
spin_lock(&self->lock);
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index 7b2b4135bb23..37914dc5b90e 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -51,7 +51,7 @@ static int au1k_irda_start(struct net_device *);
static int au1k_irda_stop(struct net_device *dev);
static int au1k_irda_hard_xmit(struct sk_buff *, struct net_device *);
static int au1k_irda_rx(struct net_device *);
-static void au1k_irda_interrupt(int, void *, struct pt_regs *);
+static void au1k_irda_interrupt(int, void *);
static void au1k_tx_timeout(struct net_device *);
static struct net_device_stats *au1k_irda_stats(struct net_device *);
static int au1k_irda_ioctl(struct net_device *, struct ifreq *, int);
@@ -627,7 +627,7 @@ static int au1k_irda_rx(struct net_device *dev)
}
-void au1k_irda_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+void au1k_irda_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
index 33c07d5275da..16620bd97fbf 100644
--- a/drivers/net/irda/donauboe.c
+++ b/drivers/net/irda/donauboe.c
@@ -657,12 +657,6 @@ toshoboe_makemttpacket (struct toshoboe_cb *self, void *buf, int mtt)
return xbofs;
}
-static int toshoboe_invalid_dev(int irq)
-{
- printk (KERN_WARNING DRIVER_NAME ": irq %d for unknown device.\n", irq);
- return 1;
-}
-
#ifdef USE_PROBE
/***********************************************************************/
/* Probe code */
@@ -709,14 +703,11 @@ stuff_byte (__u8 byte, __u8 * buf)
}
static irqreturn_t
-toshoboe_probeinterrupt (int irq, void *dev_id, struct pt_regs *regs)
+toshoboe_probeinterrupt (int irq, void *dev_id)
{
- struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
+ struct toshoboe_cb *self = dev_id;
__u8 irqstat;
- if (self == NULL && toshoboe_invalid_dev(irq))
- return IRQ_NONE;
-
irqstat = INB (OBOE_ISR);
/* was it us */
@@ -1161,15 +1152,12 @@ dumpbufs(skb->data,skb->len,'>');
/*interrupt handler */
static irqreturn_t
-toshoboe_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+toshoboe_interrupt (int irq, void *dev_id)
{
- struct toshoboe_cb *self = (struct toshoboe_cb *) dev_id;
+ struct toshoboe_cb *self = dev_id;
__u8 irqstat;
struct sk_buff *skb = NULL;
- if (self == NULL && toshoboe_invalid_dev(irq))
- return IRQ_NONE;
-
irqstat = INB (OBOE_ISR);
/* was it us */
@@ -1357,13 +1345,11 @@ toshoboe_net_open (struct net_device *dev)
{
struct toshoboe_cb *self;
unsigned long flags;
+ int rc;
IRDA_DEBUG (4, "%s()\n", __FUNCTION__);
- IRDA_ASSERT (dev != NULL, return -1; );
- self = (struct toshoboe_cb *) dev->priv;
-
- IRDA_ASSERT (self != NULL, return 0; );
+ self = netdev_priv(dev);
if (self->async)
return -EBUSY;
@@ -1371,11 +1357,10 @@ toshoboe_net_open (struct net_device *dev)
if (self->stopped)
return 0;
- if (request_irq (self->io.irq, toshoboe_interrupt,
- IRQF_SHARED | IRQF_DISABLED, dev->name, (void *) self))
- {
- return -EAGAIN;
- }
+ rc = request_irq (self->io.irq, toshoboe_interrupt,
+ IRQF_SHARED | IRQF_DISABLED, dev->name, self);
+ if (rc)
+ return rc;
spin_lock_irqsave(&self->spinlock, flags);
toshoboe_startchip (self);
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 2a0d538b387f..14bda765c2fa 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -114,9 +114,9 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
static int irda_usb_open(struct irda_usb_cb *self);
static void irda_usb_close(struct irda_usb_cb *self);
-static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs);
-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs);
-static void irda_usb_receive(struct urb *urb, struct pt_regs *regs);
+static void speed_bulk_callback(struct urb *urb);
+static void write_bulk_callback(struct urb *urb);
+static void irda_usb_receive(struct urb *urb);
static void irda_usb_rx_defer_expired(unsigned long data);
static int irda_usb_net_open(struct net_device *dev);
static int irda_usb_net_close(struct net_device *dev);
@@ -343,7 +343,7 @@ static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
* Speed URB callback
* Now, we can only get called for the speed URB.
*/
-static void speed_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void speed_bulk_callback(struct urb *urb)
{
struct irda_usb_cb *self = urb->context;
@@ -562,7 +562,7 @@ drop:
/*
* Note : this function will be called only for tx_urb...
*/
-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void write_bulk_callback(struct urb *urb)
{
unsigned long flags;
struct sk_buff *skb = urb->context;
@@ -671,10 +671,8 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* Jean II */
done = 1;
break;
- case -ECONNABORTED: /* -103 */
- case -ECONNRESET: /* -104 */
- case -ETIMEDOUT: /* -110 */
- case -ENOENT: /* -2 (urb unlinked by us) */
+ case -ECONNRESET:
+ case -ENOENT: /* urb unlinked by us */
default: /* ??? - Play safe */
urb->status = 0;
netif_wake_queue(self->netdev);
@@ -712,10 +710,8 @@ static void irda_usb_net_timeout(struct net_device *netdev)
* Jean II */
done = 1;
break;
- case -ECONNABORTED: /* -103 */
- case -ECONNRESET: /* -104 */
- case -ETIMEDOUT: /* -110 */
- case -ENOENT: /* -2 (urb unlinked by us) */
+ case -ECONNRESET:
+ case -ENOENT: /* urb unlinked by us */
default: /* ??? - Play safe */
if(skb != NULL) {
dev_kfree_skb_any(skb);
@@ -813,7 +809,7 @@ static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, struc
* Called by the USB subsystem when a frame has been received
*
*/
-static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
+static void irda_usb_receive(struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
struct irda_usb_cb *self;
@@ -845,14 +841,14 @@ static void irda_usb_receive(struct urb *urb, struct pt_regs *regs)
self->stats.rx_crc_errors++;
/* Also precursor to a hot-unplug on UHCI. */
/* Fallthrough... */
- case -ECONNRESET: /* -104 */
+ case -ECONNRESET:
/* Random error, if I remember correctly */
/* uhci_cleanup_unlink() is going to kill the Rx
* URB just after we return. No problem, at this
* point the URB will be idle ;-) - Jean II */
- case -ESHUTDOWN: /* -108 */
+ case -ESHUTDOWN:
/* That's usually a hot-unplug. Submit will fail... */
- case -ETIMEDOUT: /* -110 */
+ case -ETIME:
/* Usually precursor to a hot-unplug on OHCI. */
default:
self->stats.rx_errors++;
diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c
index ba4f3eb988b3..654a68b490ae 100644
--- a/drivers/net/irda/irport.c
+++ b/drivers/net/irda/irport.c
@@ -87,8 +87,7 @@ static struct net_device_stats *irport_net_get_stats(struct net_device *dev);
static int irport_change_speed_complete(struct irda_task *task);
static void irport_timeout(struct net_device *dev);
-static irqreturn_t irport_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t irport_interrupt(int irq, void *dev_id);
static int irport_hard_xmit(struct sk_buff *skb, struct net_device *dev);
static void irport_change_speed(void *priv, __u32 speed);
static int irport_net_open(struct net_device *dev);
@@ -761,25 +760,20 @@ static inline void irport_receive(struct irport_cb *self)
}
/*
- * Function irport_interrupt (irq, dev_id, regs)
+ * Function irport_interrupt (irq, dev_id)
*
* Interrupt handler
*/
-static irqreturn_t irport_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t irport_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct irport_cb *self;
int boguscount = 0;
int iobase;
int iir, lsr;
int handled = 0;
- if (!dev) {
- IRDA_WARNING("%s() irq %d for unknown device.\n", __FUNCTION__, irq);
- return IRQ_NONE;
- }
- self = (struct irport_cb *) dev->priv;
+ self = dev->priv;
spin_lock(&self->lock);
diff --git a/drivers/net/irda/irport.h b/drivers/net/irda/irport.h
index fc89c8c3dd7f..3f46b84c6c85 100644
--- a/drivers/net/irda/irport.h
+++ b/drivers/net/irda/irport.h
@@ -74,7 +74,7 @@ struct irport_cb {
/* For piggyback drivers */
void *priv;
void (*change_speed)(void *priv, __u32 speed);
- int (*interrupt)(int irq, void *dev_id, struct pt_regs *regs);
+ irqreturn_t (*interrupt)(int irq, void *dev_id);
};
#endif /* IRPORT_H */
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index 415ba8dc94ce..b32c52ed19d7 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -764,7 +764,7 @@ static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev)
}
/* Receive callback function. */
-static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs)
+static void mcs_receive_irq(struct urb *urb)
{
__u8 *bytes;
struct mcs_cb *mcs = urb->context;
@@ -813,7 +813,7 @@ static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs)
}
/* Transmit callback funtion. */
-static void mcs_send_irq(struct urb *urb, struct pt_regs *regs)
+static void mcs_send_irq(struct urb *urb)
{
struct mcs_cb *mcs = urb->context;
struct net_device *ndev = mcs->netdev;
diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h
index 1a723d725c2a..b18148cee638 100644
--- a/drivers/net/irda/mcs7780.h
+++ b/drivers/net/irda/mcs7780.h
@@ -156,8 +156,8 @@ static int mcs_net_close(struct net_device *netdev);
static int mcs_net_open(struct net_device *netdev);
static struct net_device_stats *mcs_net_get_stats(struct net_device *netdev);
-static void mcs_receive_irq(struct urb *urb, struct pt_regs *regs);
-static void mcs_send_irq(struct urb *urb, struct pt_regs *regs);
+static void mcs_receive_irq(struct urb *urb);
+static void mcs_send_irq(struct urb *urb);
static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *netdev);
static int mcs_probe(struct usb_interface *intf,
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index cb62f2a9676a..29b5ccd29d0b 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -110,7 +110,7 @@ static nsc_chip_t chips[] = {
{ "PC87338", { 0x398, 0x15c, 0x2e }, 0x08, 0xb0, 0xf8,
nsc_ircc_probe_338, nsc_ircc_init_338 },
/* Contributed by Steffen Pingel - IBM X40 */
- { "PC8738x", { 0x164e, 0x4e, 0x0 }, 0x20, 0xf4, 0xff,
+ { "PC8738x", { 0x164e, 0x4e, 0x2e }, 0x20, 0xf4, 0xff,
nsc_ircc_probe_39x, nsc_ircc_init_39x },
/* Contributed by Jan Frey - IBM A30/A31 */
{ "PC8739x", { 0x2e, 0x4e, 0x0 }, 0x20, 0xea, 0xff,
@@ -2066,20 +2066,14 @@ static void nsc_ircc_fir_interrupt(struct nsc_ircc_cb *self, int iobase,
* An interrupt from the chip has arrived. Time to do some work
*
*/
-static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct nsc_ircc_cb *self;
__u8 bsr, eir;
int iobase;
- if (!dev) {
- IRDA_WARNING("%s: irq %d for unknown device.\n",
- driver_name, irq);
- return IRQ_NONE;
- }
- self = (struct nsc_ircc_cb *) dev->priv;
+ self = dev->priv;
spin_lock(&self->lock);
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
index afb19e8d95c8..f9a1c88a4283 100644
--- a/drivers/net/irda/pxaficp_ir.c
+++ b/drivers/net/irda/pxaficp_ir.c
@@ -199,7 +199,7 @@ static int pxa_irda_set_speed(struct pxa_irda *si, int speed)
}
/* SIR interrupt service routine. */
-static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct pxa_irda *si = netdev_priv(dev);
@@ -281,7 +281,7 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id, struct pt_regs *regs)
}
/* FIR Receive DMA interrupt handler */
-static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *regs)
+static void pxa_irda_fir_dma_rx_irq(int channel, void *data)
{
int dcsr = DCSR(channel);
@@ -291,7 +291,7 @@ static void pxa_irda_fir_dma_rx_irq(int channel, void *data, struct pt_regs *reg
}
/* FIR Transmit DMA interrupt handler */
-static void pxa_irda_fir_dma_tx_irq(int channel, void *data, struct pt_regs *regs)
+static void pxa_irda_fir_dma_tx_irq(int channel, void *data)
{
struct net_device *dev = data;
struct pxa_irda *si = netdev_priv(dev);
@@ -388,7 +388,7 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev)
}
/* FIR interrupt handler */
-static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pxa_irda_fir_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct pxa_irda *si = netdev_priv(dev);
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 8d5a288d7976..937372d00398 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -579,7 +579,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev)
sa1100_irda_rx_dma_start(si);
}
-static irqreturn_t sa1100_irda_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sa1100_irda_irq(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
if (IS_FIR(((struct sa1100_irda *)dev->priv)))
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 2eff45bedc7c..31c623381ea8 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -196,7 +196,7 @@ static void smsc_ircc_dma_xmit(struct smsc_ircc_cb *self, int bofs);
static void smsc_ircc_dma_xmit_complete(struct smsc_ircc_cb *self);
static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed);
static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, u32 speed);
-static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id);
static irqreturn_t smsc_ircc_interrupt_sir(struct net_device *dev);
static void smsc_ircc_sir_start(struct smsc_ircc_cb *self);
#if SMSC_IRCC2_C_SIR_STOP
@@ -1455,7 +1455,7 @@ static void smsc_ircc_sir_receive(struct smsc_ircc_cb *self)
* An interrupt from the chip has arrived. Time to do some work
*
*/
-static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct smsc_ircc_cb *self;
@@ -1520,7 +1520,7 @@ static irqreturn_t smsc_ircc_interrupt(int irq, void *dev_id, struct pt_regs *re
}
/*
- * Function irport_interrupt_sir (irq, dev_id, regs)
+ * Function irport_interrupt_sir (irq, dev_id)
*
* Interrupt handler for SIR modes
*/
@@ -2354,6 +2354,26 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
#define PCIID_VENDOR_INTEL 0x8086
#define PCIID_VENDOR_ALI 0x10b9
static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
+ /*
+ * Subsystems needing entries:
+ * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family
+ * 0x10b9:0x1533 0x0e11:0x005a Compaq nc4000 family
+ * 0x8086:0x24cc 0x0e11:0x002a HP nx9000 family
+ */
+ {
+ /* Guessed entry */
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+ .device = 0x24cc,
+ .subvendor = 0x103c,
+ .subdevice = 0x08bc,
+ .sir_io = 0x02f8,
+ .fir_io = 0x0130,
+ .fir_irq = 0x05,
+ .fir_dma = 0x03,
+ .cfg_base = 0x004e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "HP nx5000 family",
+ },
{
.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
.device = 0x24cc,
@@ -2366,7 +2386,7 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
.fir_dma = 0x03,
.cfg_base = 0x004e,
.preconfigure = preconfigure_through_82801,
- .name = "HP nc8000",
+ .name = "HP nc8000 family",
},
{
.vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
@@ -2379,7 +2399,21 @@ static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __ini
.fir_dma = 0x03,
.cfg_base = 0x004e,
.preconfigure = preconfigure_through_82801,
- .name = "HP nc6000",
+ .name = "HP nc6000 family",
+ },
+ {
+ .vendor = PCIID_VENDOR_INTEL, /* Intel 82801DBM LPC bridge */
+ .device = 0x24cc,
+ .subvendor = 0x0e11,
+ .subdevice = 0x0860,
+ /* I assume these are the same for x1000 as for the others */
+ .sir_io = 0x02e8,
+ .fir_io = 0x02f8,
+ .fir_irq = 0x07,
+ .fir_dma = 0x03,
+ .cfg_base = 0x002e,
+ .preconfigure = preconfigure_through_82801,
+ .name = "Compaq x1000 family",
},
{
/* Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge */
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index d61b208b52a2..be8a66e702b0 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -149,8 +149,6 @@ enum StirFifoCtlMask {
FIFOCTL_DIR = 0x10,
FIFOCTL_CLR = 0x08,
FIFOCTL_EMPTY = 0x04,
- FIFOCTL_RXERR = 0x02,
- FIFOCTL_TXERR = 0x01,
};
enum StirDiagMask {
@@ -615,19 +613,6 @@ static int fifo_txwait(struct stir_cb *stir, int space)
pr_debug("fifo status 0x%lx count %lu\n", status, count);
- /* error when receive/transmit fifo gets confused */
- if (status & FIFOCTL_RXERR) {
- stir->stats.rx_fifo_errors++;
- stir->stats.rx_errors++;
- break;
- }
-
- if (status & FIFOCTL_TXERR) {
- stir->stats.tx_fifo_errors++;
- stir->stats.tx_errors++;
- break;
- }
-
/* is fifo receiving already, or empty */
if (!(status & FIFOCTL_DIR)
|| (status & FIFOCTL_EMPTY))
@@ -819,7 +804,7 @@ static int stir_transmit_thread(void *arg)
* Wakes up every ms (usb round trip) with wrapped
* data.
*/
-static void stir_rcv_irq(struct urb *urb, struct pt_regs *regs)
+static void stir_rcv_irq(struct urb *urb)
{
struct stir_cb *stir = urb->context;
int err;
diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c
index 79b85f327500..c3ed9b3067e5 100644
--- a/drivers/net/irda/via-ircc.c
+++ b/drivers/net/irda/via-ircc.c
@@ -93,8 +93,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb,
struct net_device *dev);
static void via_hw_init(struct via_ircc_cb *self);
static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 baud);
-static irqreturn_t via_ircc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t via_ircc_interrupt(int irq, void *dev_id);
static int via_ircc_is_receiving(struct via_ircc_cb *self);
static int via_ircc_read_dongle_id(int iobase);
@@ -1223,8 +1222,13 @@ static int upload_rxdata(struct via_ircc_cb *self, int iobase)
IRDA_DEBUG(2, "%s(): len=%x\n", __FUNCTION__, len);
+ if ((len - 4) < 2) {
+ self->stats.rx_dropped++;
+ return FALSE;
+ }
+
skb = dev_alloc_skb(len + 1);
- if ((skb == NULL) || ((len - 4) < 2)) {
+ if (skb == NULL) {
self->stats.rx_dropped++;
return FALSE;
}
@@ -1340,13 +1344,12 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase)
/*
- * Function via_ircc_interrupt (irq, dev_id, regs)
+ * Function via_ircc_interrupt (irq, dev_id)
*
* An interrupt from the chip has arrived. Time to do some work
*
*/
-static irqreturn_t via_ircc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t via_ircc_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct via_ircc_cb *self;
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index 92d646cc9edc..18c68193bf14 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -1455,8 +1455,7 @@ static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
/********************************************************/
-static irqreturn_t vlsi_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t vlsi_interrupt(int irq, void *dev_instance)
{
struct net_device *ndev = dev_instance;
vlsi_irda_dev_t *idev = ndev->priv;
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index a82a4ba8de4f..c37f0bc4c7f9 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -58,7 +58,7 @@ typedef void irqreturn_t;
/* PDE() introduced in 2.5.4 */
#ifdef CONFIG_PROC_FS
-#define PDE(inode) ((inode)->u.generic_ip)
+#define PDE(inode) ((inode)->i_private)
#endif
/* irda crc16 calculation exported in 2.5.42 */
diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c
index 7de1afdeec3d..4212657fa4f9 100644
--- a/drivers/net/irda/w83977af_ir.c
+++ b/drivers/net/irda/w83977af_ir.c
@@ -1111,20 +1111,14 @@ static __u8 w83977af_fir_interrupt(struct w83977af_ir *self, int isr)
* An interrupt from the chip has arrived. Time to do some work
*
*/
-static irqreturn_t w83977af_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t w83977af_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct w83977af_ir *self;
__u8 set, icr, isr;
int iobase;
- if (!dev) {
- printk(KERN_WARNING "%s: irq %d for unknown device.\n",
- driver_name, irq);
- return IRQ_NONE;
- }
- self = (struct w83977af_ir *) dev->priv;
+ self = dev->priv;
iobase = self->io.fir_base;
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index 984c31d1b3fb..0343f12d2ffb 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -107,7 +107,7 @@ struct net_local {
static int netcard_probe1(struct net_device *dev, int ioaddr);
static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t net_interrupt(int irq, void *dev_id);
static void net_rx(struct net_device *dev);
static int net_close(struct net_device *dev);
static struct net_device_stats *net_get_stats(struct net_device *dev);
@@ -504,7 +504,7 @@ void net_tx(struct net_device *dev)
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *np;
diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c
index 41b1d08fd57b..2284e2ce1692 100644
--- a/drivers/net/iseries_veth.c
+++ b/drivers/net/iseries_veth.c
@@ -586,7 +586,7 @@ static void veth_handle_int(struct veth_lpevent *event)
};
}
-static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs)
+static void veth_handle_event(struct HvLpEvent *event)
{
struct veth_lpevent *veth_event = (struct veth_lpevent *)event;
diff --git a/drivers/net/ixgb/Makefile b/drivers/net/ixgb/Makefile
index a8a2d3d03567..838a5084fa00 100644
--- a/drivers/net/ixgb/Makefile
+++ b/drivers/net/ixgb/Makefile
@@ -1,33 +1,33 @@
################################################################################
#
-#
-# Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-#
-# 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
+# Intel PRO/10GbE Linux driver
+# Copyright(c) 1999 - 2006 Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
-# file called LICENSE.
-#
+# this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# The full GNU General Public License is included in this distribution in
+# the file called "COPYING".
+#
# Contact Information:
# Linux NICS <linux.nics@intel.com>
+# e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
# Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
#
################################################################################
#
-# Makefile for the Intel(R) PRO/10GbE driver
+# Makefile for the Intel(R) PRO/10GbE ethernet driver
#
obj-$(CONFIG_IXGB) += ixgb.o
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h
index a51604b3651f..50ffe90488ff 100644
--- a/drivers/net/ixgb/ixgb.h
+++ b/drivers/net/ixgb/ixgb.h
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -111,7 +111,7 @@ struct ixgb_adapter;
#define IXGB_RXBUFFER_16384 16384
/* How many Rx Buffers do we bundle into one write to the hardware ? */
-#define IXGB_RX_BUFFER_WRITE 4 /* Must be power of 2 */
+#define IXGB_RX_BUFFER_WRITE 8 /* Must be power of 2 */
/* only works for sizes that are powers of 2 */
#define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1)))
diff --git a/drivers/net/ixgb/ixgb_ee.c b/drivers/net/ixgb/ixgb_ee.c
index 8357c5590bfb..f15aebde7b90 100644
--- a/drivers/net/ixgb/ixgb_ee.c
+++ b/drivers/net/ixgb/ixgb_ee.c
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixgb/ixgb_ee.h b/drivers/net/ixgb/ixgb_ee.h
index bf6fa220f38e..ef236b935c15 100644
--- a/drivers/net/ixgb/ixgb_ee.h
+++ b/drivers/net/ixgb/ixgb_ee.h
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c
index 64a383e4e892..cd22523fb035 100644
--- a/drivers/net/ixgb/ixgb_ethtool.c
+++ b/drivers/net/ixgb/ixgb_ethtool.c
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixgb/ixgb_hw.c b/drivers/net/ixgb/ixgb_hw.c
index acc6df7a6b38..02089b64e42c 100644
--- a/drivers/net/ixgb/ixgb_hw.c
+++ b/drivers/net/ixgb/ixgb_hw.c
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixgb/ixgb_hw.h b/drivers/net/ixgb/ixgb_hw.h
index cb4568915ada..40ef5ca88717 100644
--- a/drivers/net/ixgb/ixgb_hw.h
+++ b/drivers/net/ixgb/ixgb_hw.h
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixgb/ixgb_ids.h b/drivers/net/ixgb/ixgb_ids.h
index 9fd61189b4b2..4376e7e8fbef 100644
--- a/drivers/net/ixgb/ixgb_ids.h
+++ b/drivers/net/ixgb/ixgb_ids.h
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 2e0f4b950a90..e09f575a3a38 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
@@ -36,7 +36,7 @@ static char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "1.0.112-k2"DRIVERNAPI
+#define DRV_VERSION "1.0.117-k2"DRIVERNAPI
char ixgb_driver_version[] = DRV_VERSION;
static char ixgb_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
@@ -93,7 +93,7 @@ static int ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev);
static struct net_device_stats *ixgb_get_stats(struct net_device *netdev);
static int ixgb_change_mtu(struct net_device *netdev, int new_mtu);
static int ixgb_set_mac(struct net_device *netdev, void *p);
-static irqreturn_t ixgb_intr(int irq, void *data, struct pt_regs *regs);
+static irqreturn_t ixgb_intr(int irq, void *data);
static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter);
#ifdef CONFIG_IXGB_NAPI
@@ -437,7 +437,7 @@ ixgb_probe(struct pci_dev *pdev,
netdev->poll_controller = ixgb_netpoll;
#endif
- strcpy(netdev->name, pci_name(pdev));
+ strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1);
netdev->mem_start = mmio_start;
netdev->mem_end = mmio_start + mmio_len;
netdev->base_addr = adapter->hw.io_base;
@@ -1687,11 +1687,10 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
* ixgb_intr - Interrupt Handler
* @irq: interrupt number
* @data: pointer to a network interface device structure
- * @pt_regs: CPU registers structure
**/
static irqreturn_t
-ixgb_intr(int irq, void *data, struct pt_regs *regs)
+ixgb_intr(int irq, void *data)
{
struct net_device *netdev = data;
struct ixgb_adapter *adapter = netdev_priv(netdev);
@@ -2213,7 +2212,7 @@ static void ixgb_netpoll(struct net_device *dev)
struct ixgb_adapter *adapter = netdev_priv(dev);
disable_irq(adapter->pdev->irq);
- ixgb_intr(adapter->pdev->irq, dev, NULL);
+ ixgb_intr(adapter->pdev->irq, dev);
enable_irq(adapter->pdev->irq);
}
#endif
@@ -2230,7 +2229,7 @@ static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
enum pci_channel_state state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct ixgb_adapter *adapter = netdev->priv;
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
if(netif_running(netdev))
ixgb_down(adapter, TRUE);
@@ -2253,7 +2252,7 @@ static pci_ers_result_t ixgb_io_error_detected (struct pci_dev *pdev,
static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct ixgb_adapter *adapter = netdev->priv;
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
if(pci_enable_device(pdev)) {
DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n");
@@ -2297,7 +2296,7 @@ static pci_ers_result_t ixgb_io_slot_reset (struct pci_dev *pdev)
static void ixgb_io_resume (struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct ixgb_adapter *adapter = netdev->priv;
+ struct ixgb_adapter *adapter = netdev_priv(netdev);
pci_set_master(pdev);
diff --git a/drivers/net/ixgb/ixgb_osdep.h b/drivers/net/ixgb/ixgb_osdep.h
index 19cb1d586dec..8434d752fd81 100644
--- a/drivers/net/ixgb/ixgb_osdep.h
+++ b/drivers/net/ixgb/ixgb_osdep.h
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c
index 39fbed29a3df..b27442a121f2 100644
--- a/drivers/net/ixgb/ixgb_param.c
+++ b/drivers/net/ixgb/ixgb_param.c
@@ -1,27 +1,27 @@
/*******************************************************************************
-
- Copyright(c) 1999 - 2006 Intel Corporation. All rights reserved.
-
- 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
+ Intel PRO/10GbE Linux driver
+ Copyright(c) 1999 - 2006 Intel Corporation.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms and conditions of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ This program is distributed in the hope 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 full GNU General Public License is included in this distribution in the
- file called LICENSE.
-
+ this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+ The full GNU General Public License is included in this distribution in
+ the file called "COPYING".
+
Contact Information:
Linux NICS <linux.nics@intel.com>
+ e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
*******************************************************************************/
diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c
index 6eeb965b4d72..a4eccb11d677 100644
--- a/drivers/net/ixp2000/ixpdev.c
+++ b/drivers/net/ixp2000/ixpdev.c
@@ -188,7 +188,7 @@ static void ixpdev_tx_complete(void)
}
}
-static irqreturn_t ixpdev_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ixpdev_interrupt(int irq, void *dev_id)
{
u32 status;
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index f349e88e0ddf..6efbd499d752 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -301,7 +301,7 @@ static int lance_open(struct net_device *dev);
static void lance_init_ring(struct net_device *dev, gfp_t mode);
static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lance_rx(struct net_device *dev);
-static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t lance_interrupt(int irq, void *dev_id);
static int lance_close(struct net_device *dev);
static struct net_device_stats *lance_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
@@ -1012,19 +1012,13 @@ out:
}
/* The LANCE interrupt handler. */
-static irqreturn_t
-lance_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t lance_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct lance_private *lp;
int csr0, ioaddr, boguscnt=10;
int must_restart;
- if (dev == NULL) {
- printk ("lance_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
ioaddr = dev->base_addr;
lp = dev->priv;
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index da1eedef0b55..f4d815bca643 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -403,7 +403,7 @@ static char init_setup[] =
static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
@@ -527,7 +527,7 @@ static void i596_display_data(struct net_device *dev)
#if defined(ENABLE_MVME16x_NET) || defined(ENABLE_BVME6000_NET)
-static void i596_error(int irq, void *dev_id, struct pt_regs *regs)
+static void i596_error(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;
@@ -1252,12 +1252,12 @@ static int __devinit i82596_probe(struct net_device *dev,
static void i596_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- i596_interrupt(dev->irq, dev, NULL);
+ i596_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i596_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct i596_private *lp;
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index f429b19bf620..82c10dec1b5a 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -58,7 +58,11 @@
#include <linux/tcp.h>
#include <linux/percpu.h>
-static DEFINE_PER_CPU(struct net_device_stats, loopback_stats);
+struct pcpu_lstats {
+ unsigned long packets;
+ unsigned long bytes;
+};
+static DEFINE_PER_CPU(struct pcpu_lstats, pcpu_lstats);
#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
@@ -128,7 +132,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
*/
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct net_device_stats *lb_stats;
+ struct pcpu_lstats *lb_stats;
skb_orphan(skb);
@@ -149,55 +153,61 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
dev->last_rx = jiffies;
- lb_stats = &per_cpu(loopback_stats, get_cpu());
- lb_stats->rx_bytes += skb->len;
- lb_stats->tx_bytes = lb_stats->rx_bytes;
- lb_stats->rx_packets++;
- lb_stats->tx_packets = lb_stats->rx_packets;
- put_cpu();
+ /* it's OK to use __get_cpu_var() because BHs are off */
+ lb_stats = &__get_cpu_var(pcpu_lstats);
+ lb_stats->bytes += skb->len;
+ lb_stats->packets++;
netif_rx(skb);
- return(0);
+ return 0;
}
+static struct net_device_stats loopback_stats;
+
static struct net_device_stats *get_stats(struct net_device *dev)
{
- struct net_device_stats *stats = dev->priv;
+ struct net_device_stats *stats = &loopback_stats;
+ unsigned long bytes = 0;
+ unsigned long packets = 0;
int i;
- if (!stats) {
- return NULL;
- }
-
- memset(stats, 0, sizeof(struct net_device_stats));
-
for_each_possible_cpu(i) {
- struct net_device_stats *lb_stats;
+ const struct pcpu_lstats *lb_stats;
- lb_stats = &per_cpu(loopback_stats, i);
- stats->rx_bytes += lb_stats->rx_bytes;
- stats->tx_bytes += lb_stats->tx_bytes;
- stats->rx_packets += lb_stats->rx_packets;
- stats->tx_packets += lb_stats->tx_packets;
+ lb_stats = &per_cpu(pcpu_lstats, i);
+ bytes += lb_stats->bytes;
+ packets += lb_stats->packets;
}
-
+ stats->rx_packets = packets;
+ stats->tx_packets = packets;
+ stats->rx_bytes = bytes;
+ stats->tx_bytes = bytes;
return stats;
}
-static u32 loopback_get_link(struct net_device *dev)
+static u32 always_on(struct net_device *dev)
{
return 1;
}
static const struct ethtool_ops loopback_ethtool_ops = {
- .get_link = loopback_get_link,
+ .get_link = always_on,
.get_tso = ethtool_op_get_tso,
.set_tso = ethtool_op_set_tso,
+ .get_tx_csum = always_on,
+ .get_sg = always_on,
+ .get_rx_csum = always_on,
};
+/*
+ * The loopback device is special. There is only one instance and
+ * it is statically allocated. Don't do this for other devices.
+ */
struct net_device loopback_dev = {
.name = "lo",
+ .get_stats = &get_stats,
+ .priv = &loopback_stats,
.mtu = (16 * 1024) + 20 + 20 + 12,
.hard_start_xmit = loopback_xmit,
.hard_header = eth_header,
@@ -221,16 +231,6 @@ struct net_device loopback_dev = {
/* Setup and register the loopback device. */
int __init loopback_init(void)
{
- struct net_device_stats *stats;
-
- /* Can survive without statistics */
- stats = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
- if (stats) {
- memset(stats, 0, sizeof(struct net_device_stats));
- loopback_dev.priv = stats;
- loopback_dev.get_stats = &get_stats;
- }
-
return register_netdev(&loopback_dev);
};
diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c
index 0258aaca9ed3..b833016f1825 100644
--- a/drivers/net/lp486e.c
+++ b/drivers/net/lp486e.c
@@ -379,7 +379,7 @@ static char init_setup[14] = {
static int i596_open(struct net_device *dev);
static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t i596_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t i596_interrupt(int irq, void *dev_id);
static int i596_close(struct net_device *dev);
static struct net_device_stats *i596_get_stats(struct net_device *dev);
static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd);
@@ -1151,7 +1151,7 @@ i596_handle_CU_completion(struct net_device *dev,
}
static irqreturn_t
-i596_interrupt (int irq, void *dev_instance, struct pt_regs *regs) {
+i596_interrupt (int irq, void *dev_instance) {
struct net_device *dev = (struct net_device *) dev_instance;
struct i596_private *lp;
unsigned short status, ack_cmd = 0;
diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c
index 8472b71641da..e960138011c0 100644
--- a/drivers/net/mac89x0.c
+++ b/drivers/net/mac89x0.c
@@ -129,7 +129,7 @@ extern void reset_chip(struct net_device *dev);
#endif
static int net_open(struct net_device *dev);
static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t net_interrupt(int irq, void *dev_id);
static void set_multicast_list(struct net_device *dev);
static void net_rx(struct net_device *dev);
static int net_close(struct net_device *dev);
@@ -431,7 +431,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static irqreturn_t net_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t net_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 27c24eaa2414..2907cfb12ada 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -82,9 +82,9 @@ static struct net_device_stats *mace_stats(struct net_device *dev);
static void mace_set_multicast(struct net_device *dev);
static void mace_reset(struct net_device *dev);
static int mace_set_address(struct net_device *dev, void *addr);
-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mace_interrupt(int irq, void *dev_id);
+static irqreturn_t mace_txdma_intr(int irq, void *dev_id);
+static irqreturn_t mace_rxdma_intr(int irq, void *dev_id);
static void mace_set_timeout(struct net_device *dev);
static void mace_tx_timeout(unsigned long data);
static inline void dbdma_reset(volatile struct dbdma_regs __iomem *dma);
@@ -678,7 +678,7 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr)
printk(KERN_DEBUG "mace: jabbering transceiver\n");
}
-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -890,12 +890,12 @@ out:
spin_unlock_irqrestore(&mp->lock, flags);
}
-static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_txdma_intr(int irq, void *dev_id)
{
return IRQ_HANDLED;
}
-static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_rxdma_intr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct mace_data *mp = (struct mace_data *) dev->priv;
diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c
index 696d5513e558..464e4a6f3d5f 100644
--- a/drivers/net/macmace.c
+++ b/drivers/net/macmace.c
@@ -77,8 +77,8 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
static struct net_device_stats *mace_stats(struct net_device *dev);
static void mace_set_multicast(struct net_device *dev);
static int mace_set_address(struct net_device *dev, void *addr);
-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mace_interrupt(int irq, void *dev_id);
+static irqreturn_t mace_dma_intr(int irq, void *dev_id);
static void mace_tx_timeout(struct net_device *dev);
/* Bit-reverse one byte of an ethernet hardware address. */
@@ -573,7 +573,7 @@ static void mace_recv_interrupt(struct net_device *dev)
* Process the chip interrupt
*/
-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -645,7 +645,7 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf)
* The PSC has passed us a DMA interrupt event.
*/
-static irqreturn_t mace_dma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_dma_intr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct mace_data *mp = (struct mace_data *) dev->priv;
diff --git a/drivers/net/meth.c b/drivers/net/meth.c
index 55b1495a70d6..c1aa60b9a982 100644
--- a/drivers/net/meth.c
+++ b/drivers/net/meth.c
@@ -92,7 +92,7 @@ struct meth_private {
};
static void meth_tx_timeout(struct net_device *dev);
-static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs);
+static irqreturn_t meth_interrupt(int irq, void *dev_id);
/* global, initialized in ip32-setup.c */
char o2meth_eaddr[8]={0,0,0,0,0,0,0,0};
@@ -569,7 +569,7 @@ static void meth_error(struct net_device* dev, unsigned status)
/*
* The typical interrupt entry point
*/
-static irqreturn_t meth_interrupt(int irq, void *dev_id, struct pt_regs *pregs)
+static irqreturn_t meth_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct meth_private *priv = (struct meth_private *) dev->priv;
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c
index 07e58f4a2916..c9469985bd71 100644
--- a/drivers/net/mipsnet.c
+++ b/drivers/net/mipsnet.c
@@ -116,8 +116,7 @@ static inline ssize_t mipsnet_get_fromdev(struct net_device *dev, size_t count)
return count;
}
-static irqreturn_t
-mipsnet_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mipsnet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c
index 7f8e5ad1b704..9997081c6dae 100644
--- a/drivers/net/mv643xx_eth.c
+++ b/drivers/net/mv643xx_eth.c
@@ -507,8 +507,7 @@ static void mv643xx_eth_update_pscr(struct net_device *dev,
* Output : N/A
*/
-static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct mv643xx_private *mp = netdev_priv(dev);
@@ -1252,7 +1251,7 @@ static void mv643xx_netpoll(struct net_device *netdev)
/* wait for previous write to complete */
mv_read(MV643XX_ETH_INTERRUPT_MASK_REG(port_num));
- mv643xx_eth_int_handler(netdev->irq, netdev, NULL);
+ mv643xx_eth_int_handler(netdev->irq, netdev);
mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), ETH_INT_UNMASK_ALL);
}
@@ -2156,7 +2155,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp)
for (offset = ETH_MIB_BAD_OCTETS_RECEIVED;
offset <= ETH_MIB_FRAMES_1024_TO_MAX_OCTETS;
offset += 4)
- *(u32 *)((char *)p + offset) = read_mib(mp, offset);
+ *(u32 *)((char *)p + offset) += read_mib(mp, offset);
p->good_octets_sent += read_mib(mp, ETH_MIB_GOOD_OCTETS_SENT_LOW);
p->good_octets_sent +=
@@ -2165,7 +2164,7 @@ static void eth_update_mib_counters(struct mv643xx_private *mp)
for (offset = ETH_MIB_GOOD_FRAMES_SENT;
offset <= ETH_MIB_LATE_COLLISION;
offset += 4)
- *(u32 *)((char *)p + offset) = read_mib(mp, offset);
+ *(u32 *)((char *)p + offset) += read_mib(mp, offset);
}
/*
diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c
index 4330197994df..fdbb0d7213b0 100644
--- a/drivers/net/myri10ge/myri10ge.c
+++ b/drivers/net/myri10ge/myri10ge.c
@@ -1148,7 +1148,7 @@ static int myri10ge_poll(struct net_device *netdev, int *budget)
return 1;
}
-static irqreturn_t myri10ge_intr(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t myri10ge_intr(int irq, void *arg)
{
struct myri10ge_priv *mgp = arg;
struct mcp_irq_data *stats = mgp->fw_stats;
diff --git a/drivers/net/myri_code.h b/drivers/net/myri_code.h
index e21ec9b2c706..ba7b8652c501 100644
--- a/drivers/net/myri_code.h
+++ b/drivers/net/myri_code.h
@@ -1,8 +1,8 @@
/* This is the Myrinet MCP code for LANai4.x */
/* Generated by cat $MYRI_HOME/lib/lanai/mcp4.dat > myri_code4.h */
-static unsigned int lanai4_code_off = 0x0000; /* half-word offset */
-static unsigned char lanai4_code[76256] __initdata = {
+static unsigned int __devinitdata lanai4_code_off = 0x0000; /* half-word offset */
+static unsigned char __devinitdata lanai4_code[76256] = {
0xF2,0x0E,
0xFE,0x00, 0xC2,0x90, 0x00,0x00, 0x07,0x88, 0x00,0x08, 0xE0,0x01, 0x01,0x4C, 0x97,0x93,
0xFF,0xFC, 0xE0,0x00, 0x00,0x14, 0x00,0x00, 0x00,0x01, 0x00,0x00, 0x00,0x00, 0x92,0x93,
@@ -4774,8 +4774,8 @@ static unsigned char lanai4_code[76256] __initdata = {
/* This is the LANai data */
-static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */
-static unsigned char lanai4_data[20472] __initdata;
+static unsigned int __devinitdata lanai4_data_off = 0x94F0; /* half-word offset */
+static unsigned char __devinitdata lanai4_data[20472];
#ifdef SYMBOL_DEFINES_COMPILED
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index a925bc9db4ac..7747bfd99f91 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -168,7 +168,7 @@ static int myri_do_handshake(struct myri_eth *mp)
return 0;
}
-static int myri_load_lanai(struct myri_eth *mp)
+static int __devinit myri_load_lanai(struct myri_eth *mp)
{
struct net_device *dev = mp->dev;
struct myri_shmem __iomem *shmem = mp->shmem;
@@ -536,7 +536,7 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev)
}
}
-static irqreturn_t myri_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t myri_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct myri_eth *mp = (struct myri_eth *) dev->priv;
@@ -891,7 +891,7 @@ static void dump_eeprom(struct myri_eth *mp)
}
#endif
-static int __init myri_ether_init(struct sbus_dev *sdev)
+static int __devinit myri_ether_init(struct sbus_dev *sdev)
{
static int num;
static unsigned version_printed;
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index d7b241f7d7bc..ffa0afd2eddc 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -623,7 +623,7 @@ static void free_ring(struct net_device *dev);
static void reinit_ring(struct net_device *dev);
static void init_registers(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
static void netdev_error(struct net_device *dev, int intr_status);
static int natsemi_poll(struct net_device *dev, int *budget);
static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do);
@@ -2088,7 +2088,7 @@ static void netdev_tx_done(struct net_device *dev)
/* The interrupt handler doesn't actually handle interrupts itself, it
* schedules a NAPI poll if there is anything to do. */
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t intr_handler(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct netdev_private *np = netdev_priv(dev);
@@ -2373,7 +2373,7 @@ static struct net_device_stats *get_stats(struct net_device *dev)
static void natsemi_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- intr_handler(dev->irq, dev, NULL);
+ intr_handler(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c
index 0fa8e4d22769..d66328975425 100644
--- a/drivers/net/ne3210.c
+++ b/drivers/net/ne3210.c
@@ -343,6 +343,7 @@ static struct eisa_device_id ne3210_ids[] = {
{ "NVL1801" },
{ "" },
};
+MODULE_DEVICE_TABLE(eisa, ne3210_ids);
static struct eisa_driver ne3210_eisa_driver = {
.id_table = ne3210_ids,
diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c
index 30ed9a5a40e0..a53644f6a29b 100644
--- a/drivers/net/netx-eth.c
+++ b/drivers/net/netx-eth.c
@@ -176,7 +176,7 @@ static void netx_eth_receive(struct net_device *ndev)
}
static irqreturn_t
-netx_eth_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+netx_eth_interrupt(int irq, void *dev_id)
{
struct net_device *ndev = dev_id;
struct netx_eth_priv *priv = netdev_priv(ndev);
diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c
index 383c690eefec..8be0d030d6f4 100644
--- a/drivers/net/ni5010.c
+++ b/drivers/net/ni5010.c
@@ -99,7 +99,7 @@ struct ni5010_local {
static int ni5010_probe1(struct net_device *dev, int ioaddr);
static int ni5010_open(struct net_device *dev);
static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ni5010_interrupt(int irq, void *dev_id);
static void ni5010_rx(struct net_device *dev);
static void ni5010_timeout(struct net_device *dev);
static int ni5010_close(struct net_device *dev);
@@ -468,7 +468,7 @@ static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev)
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
-static irqreturn_t ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ni5010_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct ni5010_local *lp;
diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c
index e8889235996e..26e42f6e9fb1 100644
--- a/drivers/net/ni52.c
+++ b/drivers/net/ni52.c
@@ -195,7 +195,7 @@ sizeof(nop_cmd) = 8;
#define NI52_ADDR2 0x01
static int ni52_probe1(struct net_device *dev,int ioaddr);
-static irqreturn_t ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
+static irqreturn_t ni52_interrupt(int irq,void *dev_id);
static int ni52_open(struct net_device *dev);
static int ni52_close(struct net_device *dev);
static int ni52_send_packet(struct sk_buff *,struct net_device *);
@@ -837,7 +837,7 @@ static void *alloc_rfa(struct net_device *dev,void *ptr)
* Interrupt Handler ...
*/
-static irqreturn_t ni52_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
+static irqreturn_t ni52_interrupt(int irq,void *dev_id)
{
struct net_device *dev = dev_id;
unsigned short stat;
diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c
index fab3c8593ac1..340ad0d5388a 100644
--- a/drivers/net/ni65.c
+++ b/drivers/net/ni65.c
@@ -248,7 +248,7 @@ struct priv
};
static int ni65_probe1(struct net_device *dev,int);
-static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+static irqreturn_t ni65_interrupt(int irq, void * dev_id);
static void ni65_recv_intr(struct net_device *dev,int);
static void ni65_xmit_intr(struct net_device *dev,int);
static int ni65_open(struct net_device *dev);
@@ -871,7 +871,7 @@ static int ni65_lance_reinit(struct net_device *dev)
/*
* interrupt handler
*/
-static irqreturn_t ni65_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+static irqreturn_t ni65_interrupt(int irq, void * dev_id)
{
int csr0 = 0;
struct net_device *dev = dev_id;
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index e10da1aa3d30..b0127c71a5b6 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -1288,7 +1288,7 @@ static void ns83820_mib_isr(struct ns83820 *dev)
}
static void ns83820_do_isr(struct net_device *ndev, u32 isr);
-static irqreturn_t ns83820_irq(int foo, void *data, struct pt_regs *regs)
+static irqreturn_t ns83820_irq(int foo, void *data)
{
struct net_device *ndev = data;
struct ns83820 *dev = PRIV(ndev);
diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
index 2687e747657d..00ca0fdb837b 100644
--- a/drivers/net/pci-skeleton.c
+++ b/drivers/net/pci-skeleton.c
@@ -502,8 +502,7 @@ static void netdrv_tx_timeout (struct net_device *dev);
static void netdrv_init_ring (struct net_device *dev);
static int netdrv_start_xmit (struct sk_buff *skb,
struct net_device *dev);
-static irqreturn_t netdrv_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t netdrv_interrupt (int irq, void *dev_instance);
static int netdrv_close (struct net_device *dev);
static int netdrv_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
static struct net_device_stats *netdrv_get_stats (struct net_device *dev);
@@ -1654,8 +1653,7 @@ static void netdrv_weird_interrupt (struct net_device *dev,
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t netdrv_interrupt (int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t netdrv_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct netdrv_private *tp = dev->priv;
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index 2418cdb9d317..046009928526 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -238,7 +238,7 @@ static void tc574_reset(struct net_device *dev);
static void media_check(unsigned long arg);
static int el3_open(struct net_device *dev);
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t el3_interrupt(int irq, void *dev_id);
static void update_stats(struct net_device *dev);
static struct net_device_stats *el3_get_stats(struct net_device *dev);
static int el3_rx(struct net_device *dev, int worklimit);
@@ -817,7 +817,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* The EL3 interrupt handler. */
-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t el3_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct el3_private *lp = netdev_priv(dev);
@@ -927,7 +927,7 @@ static void media_check(unsigned long arg)
if ((inw(ioaddr + EL3_STATUS) & IntLatch) && (inb(ioaddr + Timer) == 0xff)) {
if (!lp->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- el3_interrupt(dev->irq, lp, NULL);
+ el3_interrupt(dev->irq, lp);
lp->fast_poll = HZ;
}
if (lp->fast_poll) {
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index a0e2b01c027c..231fa2c9ec6c 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -151,7 +151,7 @@ static void media_check(unsigned long arg);
static int el3_config(struct net_device *dev, struct ifmap *map);
static int el3_open(struct net_device *dev);
static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t el3_interrupt(int irq, void *dev_id);
static void update_stats(struct net_device *dev);
static struct net_device_stats *el3_get_stats(struct net_device *dev);
static int el3_rx(struct net_device *dev);
@@ -645,7 +645,7 @@ static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* The EL3 interrupt handler. */
-static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t el3_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct el3_private *lp = netdev_priv(dev);
@@ -748,7 +748,7 @@ static void media_check(unsigned long arg)
(inb(ioaddr + EL3_TIMER) == 0xff)) {
if (!lp->fast_poll)
printk(KERN_WARNING "%s: interrupt(s) dropped!\n", dev->name);
- el3_interrupt(dev->irq, lp, NULL);
+ el3_interrupt(dev->irq, lp);
lp->fast_poll = HZ;
}
if (lp->fast_poll) {
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index a8891a9000ac..5ddd5742f779 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -92,7 +92,7 @@ static int axnet_open(struct net_device *dev);
static int axnet_close(struct net_device *dev);
static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
static void ei_watchdog(u_long arg);
static void axnet_reset_8390(struct net_device *dev);
@@ -112,7 +112,7 @@ static void axdev_setup(struct net_device *dev);
static void AX88190_init(struct net_device *dev, int startp);
static int ax_open(struct net_device *dev);
static int ax_close(struct net_device *dev);
-static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ax_interrupt(int irq, void *dev_id);
/*====================================================================*/
@@ -599,11 +599,11 @@ static void axnet_reset_8390(struct net_device *dev)
/*====================================================================*/
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
PRIV(dev)->stale = 0;
- return ax_interrupt(irq, dev_id, regs);
+ return ax_interrupt(irq, dev_id);
}
static void ei_watchdog(u_long arg)
@@ -621,7 +621,7 @@ static void ei_watchdog(u_long arg)
if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
if (!info->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- ei_irq_wrapper(dev->irq, dev, NULL);
+ ei_irq_wrapper(dev->irq, dev);
info->fast_poll = HZ;
}
if (info->fast_poll) {
@@ -1193,7 +1193,7 @@ static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev)
* needed.
*/
-static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ax_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
long e8390_base;
@@ -1201,14 +1201,8 @@ static irqreturn_t ax_interrupt(int irq, void *dev_id, struct pt_regs * regs)
struct ei_device *ei_local;
int handled = 0;
- if (dev == NULL)
- {
- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
e8390_base = dev->base_addr;
- ei_local = (struct ei_device *) netdev_priv(dev);
+ ei_local = netdev_priv(dev);
/*
* Protect the irq test too.
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index d682f30dea6e..65f6fdf43725 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -97,7 +97,7 @@ static int fjn_config(struct net_device *dev, struct ifmap *map);
static int fjn_open(struct net_device *dev);
static int fjn_close(struct net_device *dev);
static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fjn_interrupt(int irq, void *dev_id);
static void fjn_rx(struct net_device *dev);
static void fjn_reset(struct net_device *dev);
static struct net_device_stats *fjn_get_stats(struct net_device *dev);
@@ -733,7 +733,7 @@ module_exit(exit_fmvj18x_cs);
/*====================================================================*/
-static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t fjn_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
local_info_t *lp = netdev_priv(dev);
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 7d5687e94607..e77110e4c288 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -426,7 +426,7 @@ static int mace_open(struct net_device *dev);
static int mace_close(struct net_device *dev);
static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void mace_tx_timeout(struct net_device *dev);
-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mace_interrupt(int irq, void *dev_id);
static struct net_device_stats *mace_get_stats(struct net_device *dev);
static int mace_rx(struct net_device *dev, unsigned char RxCnt);
static void restore_multicast_list(struct net_device *dev);
@@ -1002,7 +1002,7 @@ static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
mace_interrupt
The interrupt handler.
---------------------------------------------------------------------------- */
-static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
mace_private *lp = netdev_priv(dev);
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index a09c22840f63..0c00d182e7fd 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -109,7 +109,7 @@ static int pcnet_open(struct net_device *dev);
static int pcnet_close(struct net_device *dev);
static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static const struct ethtool_ops netdev_ethtool_ops;
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
static void ei_watchdog(u_long arg);
static void pcnet_reset_8390(struct net_device *dev);
static int set_config(struct net_device *dev, struct ifmap *map);
@@ -1071,11 +1071,11 @@ static int set_config(struct net_device *dev, struct ifmap *map)
/*====================================================================*/
-static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ei_irq_wrapper(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
pcnet_dev_t *info;
- irqreturn_t ret = ei_interrupt(irq, dev_id, regs);
+ irqreturn_t ret = ei_interrupt(irq, dev_id);
if (ret == IRQ_HANDLED) {
info = PRIV(dev);
@@ -1100,7 +1100,7 @@ static void ei_watchdog(u_long arg)
if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
if (!info->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- ei_irq_wrapper(dev->irq, dev, NULL);
+ ei_irq_wrapper(dev->irq, dev);
info->fast_poll = HZ;
}
if (info->fast_poll) {
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index a2f3a0e2a005..20fcc3576202 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -287,7 +287,7 @@ static int smc_close(struct net_device *dev);
static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void smc_tx_timeout(struct net_device *dev);
static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t smc_interrupt(int irq, void *dev_id);
static void smc_rx(struct net_device *dev);
static struct net_device_stats *smc_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
@@ -1545,7 +1545,7 @@ static void smc_eph_irq(struct net_device *dev)
/*====================================================================*/
-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t smc_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct smc_private *smc = netdev_priv(dev);
@@ -1966,7 +1966,7 @@ static void media_check(u_long arg)
if (smc->watchdog++ && ((i>>8) & i)) {
if (!smc->fast_poll)
printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
- smc_interrupt(dev->irq, smc, NULL);
+ smc_interrupt(dev->irq, smc);
smc->fast_poll = HZ;
}
if (smc->fast_poll) {
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 62664c01eb45..f3914f58d67f 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -308,7 +308,7 @@ static void xirc2ps_detach(struct pcmcia_device *p_dev);
* less on other parts of the kernel.
*/
-static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id);
/****************
* A linked list of "instances" of the device. Each actual
@@ -1121,7 +1121,7 @@ static int xirc2ps_resume(struct pcmcia_device *link)
* This is the Interrupt service route.
*/
static irqreturn_t
-xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+xirc2ps_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
local_info_t *lp = netdev_priv(dev);
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 21dc68eff514..36f9d988278f 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -21,8 +21,6 @@
*
*************************************************************************/
-#include <linux/config.h>
-
#define DRV_NAME "pcnet32"
#ifdef CONFIG_PCNET32_NAPI
#define DRV_VERSION "1.33-NAPI"
@@ -306,7 +304,7 @@ static int pcnet32_open(struct net_device *);
static int pcnet32_init_ring(struct net_device *);
static int pcnet32_start_xmit(struct sk_buff *, struct net_device *);
static void pcnet32_tx_timeout(struct net_device *dev);
-static irqreturn_t pcnet32_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t pcnet32_interrupt(int, void *);
static int pcnet32_close(struct net_device *);
static struct net_device_stats *pcnet32_get_stats(struct net_device *);
static void pcnet32_load_multicast(struct net_device *dev);
@@ -676,7 +674,7 @@ static void pcnet32_purge_rx_ring(struct net_device *dev)
static void pcnet32_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- pcnet32_interrupt(0, dev, NULL);
+ pcnet32_interrupt(0, dev);
enable_irq(dev->irq);
}
#endif
@@ -2563,7 +2561,7 @@ static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The PCNET32 interrupt handler. */
static irqreturn_t
-pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+pcnet32_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct pcnet32_private *lp;
@@ -2571,13 +2569,6 @@ pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
u16 csr0;
int boguscnt = max_interrupt_work;
- if (!dev) {
- if (pcnet32_debug & NETIF_MSG_INTR)
- printk(KERN_DEBUG "%s(): irq %d for unknown device\n",
- __FUNCTION__, irq);
- return IRQ_NONE;
- }
-
ioaddr = dev->base_addr;
lp = dev->priv;
diff --git a/drivers/net/phy/fixed.c b/drivers/net/phy/fixed.c
index 19f7ee63276f..f14e99276dba 100644
--- a/drivers/net/phy/fixed.c
+++ b/drivers/net/phy/fixed.c
@@ -13,7 +13,6 @@
* option) any later version.
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -289,9 +288,13 @@ static int fixed_mdio_register_device(int number, int speed, int duplex)
goto probe_fail;
}
- device_bind_driver(&phydev->dev);
+ err = device_bind_driver(&phydev->dev);
+
up_write(&phydev->dev.bus->subsys.rwsem);
+ if (err)
+ goto probe_fail;
+
return 0;
probe_fail:
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index f5aad77288f9..3af9fcf76c81 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -480,7 +480,7 @@ void phy_error(struct phy_device *phydev)
* description: When a PHY interrupt occurs, the handler disables
* interrupts, and schedules a work task to clear the interrupt.
*/
-static irqreturn_t phy_interrupt(int irq, void *phy_dat, struct pt_regs *regs)
+static irqreturn_t phy_interrupt(int irq, void *phy_dat)
{
struct phy_device *phydev = phy_dat;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 2d1ecfdc80db..3bbd5e70c209 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -212,11 +212,13 @@ struct phy_device *phy_attach(struct net_device *dev,
err = d->driver->probe(d);
- if (err < 0)
- return ERR_PTR(err);
+ if (err >= 0)
+ err = device_bind_driver(d);
- device_bind_driver(d);
up_write(&d->bus->subsys.rwsem);
+
+ if (err)
+ return ERR_PTR(err);
}
if (phydev->attached_dev) {
@@ -522,7 +524,7 @@ EXPORT_SYMBOL(genphy_read_status);
static int genphy_config_init(struct phy_device *phydev)
{
- u32 val;
+ int val;
u32 features;
/* For now, I'll claim that the generic driver supports
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index d4f54e9798cd..71afb274498f 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -143,7 +143,7 @@ static void plip_bh(struct net_device *dev);
static void plip_timer_bh(struct net_device *dev);
/* Interrupt handler */
-static void plip_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void plip_interrupt(int irq, void *dev_id);
/* Functions for DEV methods */
static int plip_tx_packet(struct sk_buff *skb, struct net_device *dev);
@@ -385,7 +385,7 @@ plip_timer_bh(struct net_device *dev)
struct net_local *nl = netdev_priv(dev);
if (!(atomic_read (&nl->kill_timer))) {
- plip_interrupt (-1, dev, NULL);
+ plip_interrupt (-1, dev);
schedule_delayed_work(&nl->timer, 1);
}
@@ -902,18 +902,13 @@ plip_error(struct net_device *dev, struct net_local *nl,
/* Handle the parallel port interrupts. */
static void
-plip_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+plip_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *nl;
struct plip_local *rcv;
unsigned char c0;
- if (dev == NULL) {
- printk(KERN_DEBUG "plip_interrupt: irq %d for unknown device.\n", irq);
- return;
- }
-
nl = netdev_priv(dev);
rcv = &nl->rcv_data;
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 5666ed998142..0adee733b761 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -600,6 +600,7 @@ static int pppoe_connect(struct socket *sock, struct sockaddr *uservaddr,
po->chan.hdrlen = (sizeof(struct pppoe_hdr) +
dev->hard_header_len);
+ po->chan.mtu = dev->mtu - sizeof(struct pppoe_hdr);
po->chan.private = sk;
po->chan.ops = &pppoe_chan_ops;
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c
index 157471846349..ec640f6229ae 100644
--- a/drivers/net/qla3xxx.c
+++ b/drivers/net/qla3xxx.c
@@ -1965,7 +1965,7 @@ quit_polling:
return 1;
}
-static irqreturn_t ql3xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
{
struct net_device *ndev = dev_id;
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index 4c47c5b10ba0..f1c75751cab7 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -473,8 +473,7 @@ MODULE_VERSION(RTL8169_VERSION);
static int rtl8169_open(struct net_device *dev);
static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs);
+static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance);
static int rtl8169_init_ring(struct net_device *dev);
static void rtl8169_hw_start(struct net_device *dev);
static int rtl8169_close(struct net_device *dev);
@@ -1392,7 +1391,7 @@ static void rtl8169_netpoll(struct net_device *dev)
struct pci_dev *pdev = tp->pci_dev;
disable_irq(pdev->irq);
- rtl8169_interrupt(pdev->irq, dev, NULL);
+ rtl8169_interrupt(pdev->irq, dev);
enable_irq(pdev->irq);
}
#endif
@@ -2592,7 +2591,7 @@ rtl8169_rx_interrupt(struct net_device *dev, struct rtl8169_private *tp,
/* The interrupt handler does all of the Rx thread work and cleans up after the Tx thread. */
static irqreturn_t
-rtl8169_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+rtl8169_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct rtl8169_private *tp = netdev_priv(dev);
diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c
index 6108bac8d56a..d81536f90df6 100644
--- a/drivers/net/rrunner.c
+++ b/drivers/net/rrunner.c
@@ -1053,7 +1053,7 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index)
}
-static irqreturn_t rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t rr_interrupt(int irq, void *dev_id)
{
struct rr_private *rrpriv;
struct rr_regs __iomem *regs;
diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h
index 99451b523399..9f3e050c4dc6 100644
--- a/drivers/net/rrunner.h
+++ b/drivers/net/rrunner.h
@@ -829,7 +829,7 @@ struct rr_private
*/
static int rr_init(struct net_device *dev);
static int rr_init1(struct net_device *dev);
-static irqreturn_t rr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t rr_interrupt(int irq, void *dev_id);
static int rr_open(struct net_device *dev);
static int rr_start_xmit(struct sk_buff *skb, struct net_device *dev);
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index f5dbeb27b6f0..a231ab7d28dd 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -2904,7 +2904,7 @@ static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device
{
u64 val64 = 0x0;
nic_t *sp = dev->priv;
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
//address transaction
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -2953,7 +2953,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
u64 val64 = 0x0;
u64 rval64 = 0x0;
nic_t *sp = dev->priv;
- XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
+ XENA_dev_config_t __iomem *bar0 = sp->bar0;
/* address transaction */
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -3276,7 +3276,7 @@ static void alarm_intr_handler(struct s2io_nic *nic)
* SUCCESS on success and FAILURE on failure.
*/
-static int wait_for_cmd_complete(void *addr, u64 busy_bit)
+static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
{
int ret = FAILURE, cnt = 0;
u64 val64;
@@ -4029,8 +4029,7 @@ static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
return 0;
}
-static irqreturn_t
-s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
nic_t *sp = dev->priv;
@@ -4063,8 +4062,7 @@ s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t
-s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
{
ring_info_t *ring = (ring_info_t *)dev_id;
nic_t *sp = ring->nic;
@@ -4078,8 +4076,7 @@ s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t
-s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
{
fifo_info_t *fifo = (fifo_info_t *)dev_id;
nic_t *sp = fifo->nic;
@@ -4155,7 +4152,6 @@ static void s2io_txpic_intr_handle(nic_t *sp)
* s2io_isr - ISR handler of the device .
* @irq: the irq of the device.
* @dev_id: a void pointer to the dev structure of the NIC.
- * @pt_regs: pointer to the registers pushed on the stack.
* Description: This function is the ISR handler of the device. It
* identifies the reason for the interrupt and calls the relevant
* service routines. As a contongency measure, this ISR allocates the
@@ -4165,7 +4161,7 @@ static void s2io_txpic_intr_handle(nic_t *sp)
* IRQ_HANDLED: will be returned if IRQ was handled by this routine
* IRQ_NONE: will be returned if interrupt is not from our device
*/
-static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t s2io_isr(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
nic_t *sp = dev->priv;
@@ -4303,11 +4299,11 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
sp->stats.tx_errors =
le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
sp->stats.rx_errors =
- le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
+ le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
sp->stats.multicast =
le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
sp->stats.rx_length_errors =
- le32_to_cpu(mac_control->stats_info->rmac_long_frms);
+ le64_to_cpu(mac_control->stats_info->rmac_long_frms);
return (&sp->stats);
}
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h
index 3afd9126a591..12b719f4d00f 100644
--- a/drivers/net/s2io.h
+++ b/drivers/net/s2io.h
@@ -116,179 +116,179 @@ typedef struct {
/* The statistics block of Xena */
typedef struct stat_block {
/* Tx MAC statistics counters. */
- u32 tmac_data_octets;
- u32 tmac_frms;
- u64 tmac_drop_frms;
- u32 tmac_bcst_frms;
- u32 tmac_mcst_frms;
- u64 tmac_pause_ctrl_frms;
- u32 tmac_ucst_frms;
- u32 tmac_ttl_octets;
- u32 tmac_any_err_frms;
- u32 tmac_nucst_frms;
- u64 tmac_ttl_less_fb_octets;
- u64 tmac_vld_ip_octets;
- u32 tmac_drop_ip;
- u32 tmac_vld_ip;
- u32 tmac_rst_tcp;
- u32 tmac_icmp;
- u64 tmac_tcp;
- u32 reserved_0;
- u32 tmac_udp;
+ __le32 tmac_data_octets;
+ __le32 tmac_frms;
+ __le64 tmac_drop_frms;
+ __le32 tmac_bcst_frms;
+ __le32 tmac_mcst_frms;
+ __le64 tmac_pause_ctrl_frms;
+ __le32 tmac_ucst_frms;
+ __le32 tmac_ttl_octets;
+ __le32 tmac_any_err_frms;
+ __le32 tmac_nucst_frms;
+ __le64 tmac_ttl_less_fb_octets;
+ __le64 tmac_vld_ip_octets;
+ __le32 tmac_drop_ip;
+ __le32 tmac_vld_ip;
+ __le32 tmac_rst_tcp;
+ __le32 tmac_icmp;
+ __le64 tmac_tcp;
+ __le32 reserved_0;
+ __le32 tmac_udp;
/* Rx MAC Statistics counters. */
- u32 rmac_data_octets;
- u32 rmac_vld_frms;
- u64 rmac_fcs_err_frms;
- u64 rmac_drop_frms;
- u32 rmac_vld_bcst_frms;
- u32 rmac_vld_mcst_frms;
- u32 rmac_out_rng_len_err_frms;
- u32 rmac_in_rng_len_err_frms;
- u64 rmac_long_frms;
- u64 rmac_pause_ctrl_frms;
- u64 rmac_unsup_ctrl_frms;
- u32 rmac_accepted_ucst_frms;
- u32 rmac_ttl_octets;
- u32 rmac_discarded_frms;
- u32 rmac_accepted_nucst_frms;
- u32 reserved_1;
- u32 rmac_drop_events;
- u64 rmac_ttl_less_fb_octets;
- u64 rmac_ttl_frms;
- u64 reserved_2;
- u32 rmac_usized_frms;
- u32 reserved_3;
- u32 rmac_frag_frms;
- u32 rmac_osized_frms;
- u32 reserved_4;
- u32 rmac_jabber_frms;
- u64 rmac_ttl_64_frms;
- u64 rmac_ttl_65_127_frms;
- u64 reserved_5;
- u64 rmac_ttl_128_255_frms;
- u64 rmac_ttl_256_511_frms;
- u64 reserved_6;
- u64 rmac_ttl_512_1023_frms;
- u64 rmac_ttl_1024_1518_frms;
- u32 rmac_ip;
- u32 reserved_7;
- u64 rmac_ip_octets;
- u32 rmac_drop_ip;
- u32 rmac_hdr_err_ip;
- u32 reserved_8;
- u32 rmac_icmp;
- u64 rmac_tcp;
- u32 rmac_err_drp_udp;
- u32 rmac_udp;
- u64 rmac_xgmii_err_sym;
- u64 rmac_frms_q0;
- u64 rmac_frms_q1;
- u64 rmac_frms_q2;
- u64 rmac_frms_q3;
- u64 rmac_frms_q4;
- u64 rmac_frms_q5;
- u64 rmac_frms_q6;
- u64 rmac_frms_q7;
- u16 rmac_full_q3;
- u16 rmac_full_q2;
- u16 rmac_full_q1;
- u16 rmac_full_q0;
- u16 rmac_full_q7;
- u16 rmac_full_q6;
- u16 rmac_full_q5;
- u16 rmac_full_q4;
- u32 reserved_9;
- u32 rmac_pause_cnt;
- u64 rmac_xgmii_data_err_cnt;
- u64 rmac_xgmii_ctrl_err_cnt;
- u32 rmac_err_tcp;
- u32 rmac_accepted_ip;
+ __le32 rmac_data_octets;
+ __le32 rmac_vld_frms;
+ __le64 rmac_fcs_err_frms;
+ __le64 rmac_drop_frms;
+ __le32 rmac_vld_bcst_frms;
+ __le32 rmac_vld_mcst_frms;
+ __le32 rmac_out_rng_len_err_frms;
+ __le32 rmac_in_rng_len_err_frms;
+ __le64 rmac_long_frms;
+ __le64 rmac_pause_ctrl_frms;
+ __le64 rmac_unsup_ctrl_frms;
+ __le32 rmac_accepted_ucst_frms;
+ __le32 rmac_ttl_octets;
+ __le32 rmac_discarded_frms;
+ __le32 rmac_accepted_nucst_frms;
+ __le32 reserved_1;
+ __le32 rmac_drop_events;
+ __le64 rmac_ttl_less_fb_octets;
+ __le64 rmac_ttl_frms;
+ __le64 reserved_2;
+ __le32 rmac_usized_frms;
+ __le32 reserved_3;
+ __le32 rmac_frag_frms;
+ __le32 rmac_osized_frms;
+ __le32 reserved_4;
+ __le32 rmac_jabber_frms;
+ __le64 rmac_ttl_64_frms;
+ __le64 rmac_ttl_65_127_frms;
+ __le64 reserved_5;
+ __le64 rmac_ttl_128_255_frms;
+ __le64 rmac_ttl_256_511_frms;
+ __le64 reserved_6;
+ __le64 rmac_ttl_512_1023_frms;
+ __le64 rmac_ttl_1024_1518_frms;
+ __le32 rmac_ip;
+ __le32 reserved_7;
+ __le64 rmac_ip_octets;
+ __le32 rmac_drop_ip;
+ __le32 rmac_hdr_err_ip;
+ __le32 reserved_8;
+ __le32 rmac_icmp;
+ __le64 rmac_tcp;
+ __le32 rmac_err_drp_udp;
+ __le32 rmac_udp;
+ __le64 rmac_xgmii_err_sym;
+ __le64 rmac_frms_q0;
+ __le64 rmac_frms_q1;
+ __le64 rmac_frms_q2;
+ __le64 rmac_frms_q3;
+ __le64 rmac_frms_q4;
+ __le64 rmac_frms_q5;
+ __le64 rmac_frms_q6;
+ __le64 rmac_frms_q7;
+ __le16 rmac_full_q3;
+ __le16 rmac_full_q2;
+ __le16 rmac_full_q1;
+ __le16 rmac_full_q0;
+ __le16 rmac_full_q7;
+ __le16 rmac_full_q6;
+ __le16 rmac_full_q5;
+ __le16 rmac_full_q4;
+ __le32 reserved_9;
+ __le32 rmac_pause_cnt;
+ __le64 rmac_xgmii_data_err_cnt;
+ __le64 rmac_xgmii_ctrl_err_cnt;
+ __le32 rmac_err_tcp;
+ __le32 rmac_accepted_ip;
/* PCI/PCI-X Read transaction statistics. */
- u32 new_rd_req_cnt;
- u32 rd_req_cnt;
- u32 rd_rtry_cnt;
- u32 new_rd_req_rtry_cnt;
+ __le32 new_rd_req_cnt;
+ __le32 rd_req_cnt;
+ __le32 rd_rtry_cnt;
+ __le32 new_rd_req_rtry_cnt;
/* PCI/PCI-X Write/Read transaction statistics. */
- u32 wr_req_cnt;
- u32 wr_rtry_rd_ack_cnt;
- u32 new_wr_req_rtry_cnt;
- u32 new_wr_req_cnt;
- u32 wr_disc_cnt;
- u32 wr_rtry_cnt;
+ __le32 wr_req_cnt;
+ __le32 wr_rtry_rd_ack_cnt;
+ __le32 new_wr_req_rtry_cnt;
+ __le32 new_wr_req_cnt;
+ __le32 wr_disc_cnt;
+ __le32 wr_rtry_cnt;
/* PCI/PCI-X Write / DMA Transaction statistics. */
- u32 txp_wr_cnt;
- u32 rd_rtry_wr_ack_cnt;
- u32 txd_wr_cnt;
- u32 txd_rd_cnt;
- u32 rxd_wr_cnt;
- u32 rxd_rd_cnt;
- u32 rxf_wr_cnt;
- u32 txf_rd_cnt;
+ __le32 txp_wr_cnt;
+ __le32 rd_rtry_wr_ack_cnt;
+ __le32 txd_wr_cnt;
+ __le32 txd_rd_cnt;
+ __le32 rxd_wr_cnt;
+ __le32 rxd_rd_cnt;
+ __le32 rxf_wr_cnt;
+ __le32 txf_rd_cnt;
/* Tx MAC statistics overflow counters. */
- u32 tmac_data_octets_oflow;
- u32 tmac_frms_oflow;
- u32 tmac_bcst_frms_oflow;
- u32 tmac_mcst_frms_oflow;
- u32 tmac_ucst_frms_oflow;
- u32 tmac_ttl_octets_oflow;
- u32 tmac_any_err_frms_oflow;
- u32 tmac_nucst_frms_oflow;
- u64 tmac_vlan_frms;
- u32 tmac_drop_ip_oflow;
- u32 tmac_vld_ip_oflow;
- u32 tmac_rst_tcp_oflow;
- u32 tmac_icmp_oflow;
- u32 tpa_unknown_protocol;
- u32 tmac_udp_oflow;
- u32 reserved_10;
- u32 tpa_parse_failure;
+ __le32 tmac_data_octets_oflow;
+ __le32 tmac_frms_oflow;
+ __le32 tmac_bcst_frms_oflow;
+ __le32 tmac_mcst_frms_oflow;
+ __le32 tmac_ucst_frms_oflow;
+ __le32 tmac_ttl_octets_oflow;
+ __le32 tmac_any_err_frms_oflow;
+ __le32 tmac_nucst_frms_oflow;
+ __le64 tmac_vlan_frms;
+ __le32 tmac_drop_ip_oflow;
+ __le32 tmac_vld_ip_oflow;
+ __le32 tmac_rst_tcp_oflow;
+ __le32 tmac_icmp_oflow;
+ __le32 tpa_unknown_protocol;
+ __le32 tmac_udp_oflow;
+ __le32 reserved_10;
+ __le32 tpa_parse_failure;
/* Rx MAC Statistics overflow counters. */
- u32 rmac_data_octets_oflow;
- u32 rmac_vld_frms_oflow;
- u32 rmac_vld_bcst_frms_oflow;
- u32 rmac_vld_mcst_frms_oflow;
- u32 rmac_accepted_ucst_frms_oflow;
- u32 rmac_ttl_octets_oflow;
- u32 rmac_discarded_frms_oflow;
- u32 rmac_accepted_nucst_frms_oflow;
- u32 rmac_usized_frms_oflow;
- u32 rmac_drop_events_oflow;
- u32 rmac_frag_frms_oflow;
- u32 rmac_osized_frms_oflow;
- u32 rmac_ip_oflow;
- u32 rmac_jabber_frms_oflow;
- u32 rmac_icmp_oflow;
- u32 rmac_drop_ip_oflow;
- u32 rmac_err_drp_udp_oflow;
- u32 rmac_udp_oflow;
- u32 reserved_11;
- u32 rmac_pause_cnt_oflow;
- u64 rmac_ttl_1519_4095_frms;
- u64 rmac_ttl_4096_8191_frms;
- u64 rmac_ttl_8192_max_frms;
- u64 rmac_ttl_gt_max_frms;
- u64 rmac_osized_alt_frms;
- u64 rmac_jabber_alt_frms;
- u64 rmac_gt_max_alt_frms;
- u64 rmac_vlan_frms;
- u32 rmac_len_discard;
- u32 rmac_fcs_discard;
- u32 rmac_pf_discard;
- u32 rmac_da_discard;
- u32 rmac_red_discard;
- u32 rmac_rts_discard;
- u32 reserved_12;
- u32 rmac_ingm_full_discard;
- u32 reserved_13;
- u32 rmac_accepted_ip_oflow;
- u32 reserved_14;
- u32 link_fault_cnt;
+ __le32 rmac_data_octets_oflow;
+ __le32 rmac_vld_frms_oflow;
+ __le32 rmac_vld_bcst_frms_oflow;
+ __le32 rmac_vld_mcst_frms_oflow;
+ __le32 rmac_accepted_ucst_frms_oflow;
+ __le32 rmac_ttl_octets_oflow;
+ __le32 rmac_discarded_frms_oflow;
+ __le32 rmac_accepted_nucst_frms_oflow;
+ __le32 rmac_usized_frms_oflow;
+ __le32 rmac_drop_events_oflow;
+ __le32 rmac_frag_frms_oflow;
+ __le32 rmac_osized_frms_oflow;
+ __le32 rmac_ip_oflow;
+ __le32 rmac_jabber_frms_oflow;
+ __le32 rmac_icmp_oflow;
+ __le32 rmac_drop_ip_oflow;
+ __le32 rmac_err_drp_udp_oflow;
+ __le32 rmac_udp_oflow;
+ __le32 reserved_11;
+ __le32 rmac_pause_cnt_oflow;
+ __le64 rmac_ttl_1519_4095_frms;
+ __le64 rmac_ttl_4096_8191_frms;
+ __le64 rmac_ttl_8192_max_frms;
+ __le64 rmac_ttl_gt_max_frms;
+ __le64 rmac_osized_alt_frms;
+ __le64 rmac_jabber_alt_frms;
+ __le64 rmac_gt_max_alt_frms;
+ __le64 rmac_vlan_frms;
+ __le32 rmac_len_discard;
+ __le32 rmac_fcs_discard;
+ __le32 rmac_pf_discard;
+ __le32 rmac_da_discard;
+ __le32 rmac_red_discard;
+ __le32 rmac_rts_discard;
+ __le32 reserved_12;
+ __le32 rmac_ingm_full_discard;
+ __le32 reserved_13;
+ __le32 rmac_accepted_ip_oflow;
+ __le32 reserved_14;
+ __le32 link_fault_cnt;
u8 buffer[20];
swStat_t sw_stat;
xpakStat_t xpak_stat;
@@ -992,12 +992,12 @@ static void s2io_init_pci(nic_t * sp);
static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
static void s2io_alarm_handle(unsigned long data);
static int s2io_enable_msi(nic_t *nic);
-static irqreturn_t s2io_msi_handle(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
static irqreturn_t
-s2io_msix_ring_handle(int irq, void *dev_id, struct pt_regs *regs);
+s2io_msix_ring_handle(int irq, void *dev_id);
static irqreturn_t
-s2io_msix_fifo_handle(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t s2io_isr(int irq, void *dev_id, struct pt_regs *regs);
+s2io_msix_fifo_handle(int irq, void *dev_id);
+static irqreturn_t s2io_isr(int irq, void *dev_id);
static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
static const struct ethtool_ops netdev_ethtool_ops;
static void s2io_set_link(unsigned long data);
diff --git a/drivers/net/saa9730.c b/drivers/net/saa9730.c
index c479b07be788..b269513cde45 100644
--- a/drivers/net/saa9730.c
+++ b/drivers/net/saa9730.c
@@ -745,10 +745,9 @@ static int lan_saa9730_rx(struct net_device *dev)
return 0;
}
-static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t lan_saa9730_interrupt(const int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct lan_saa9730_private *lp = netdev_priv(dev);
if (lan_saa9730_debug > 5)
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index a1789ae59278..b9fa4fbb1398 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -84,7 +84,7 @@ extern int sb1000_probe(struct net_device *dev);
static int sb1000_open(struct net_device *dev);
static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
static int sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t sb1000_interrupt(int irq, void *dev_id);
static struct net_device_stats *sb1000_stats(struct net_device *dev);
static int sb1000_close(struct net_device *dev);
@@ -1079,24 +1079,18 @@ sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
/* SB1000 interrupt handler. */
-static irqreturn_t sb1000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sb1000_interrupt(int irq, void *dev_id)
{
char *name;
unsigned char st;
int ioaddr[2];
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct sb1000_private *lp = netdev_priv(dev);
const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00};
const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00};
const int MaxRxErrorCount = 6;
- if (dev == NULL) {
- printk(KERN_ERR "sb1000_interrupt(): irq %d for unknown device.\n",
- irq);
- return IRQ_NONE;
- }
-
ioaddr[0] = dev->base_addr;
/* mem_start holds the second I/O address */
ioaddr[1] = dev->mem_start;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index e4c8896b76cb..db2324939b69 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -294,7 +294,7 @@ static void sbmac_channel_stop(struct sbmac_softc *s);
static sbmac_state_t sbmac_set_channel_state(struct sbmac_softc *,sbmac_state_t);
static void sbmac_promiscuous_mode(struct sbmac_softc *sc,int onoff);
static uint64_t sbmac_addr2reg(unsigned char *ptr);
-static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs);
+static irqreturn_t sbmac_intr(int irq,void *dev_instance);
static int sbmac_start_tx(struct sk_buff *skb, struct net_device *dev);
static void sbmac_setmulti(struct sbmac_softc *sc);
static int sbmac_init(struct net_device *dev, int idx);
@@ -2049,7 +2049,7 @@ static int sbmac_set_duplex(struct sbmac_softc *s,sbmac_duplex_t duplex,sbmac_fc
* Return value:
* nothing
********************************************************************* */
-static irqreturn_t sbmac_intr(int irq,void *dev_instance,struct pt_regs *rgs)
+static irqreturn_t sbmac_intr(int irq,void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct sbmac_softc *sc = netdev_priv(dev);
diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c
index 20afdc7f2b97..d9d0a3a3c558 100644
--- a/drivers/net/seeq8005.c
+++ b/drivers/net/seeq8005.c
@@ -83,7 +83,7 @@ static int seeq8005_probe1(struct net_device *dev, int ioaddr);
static int seeq8005_open(struct net_device *dev);
static void seeq8005_timeout(struct net_device *dev);
static int seeq8005_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t seeq8005_interrupt(int irq, void *dev_id);
static void seeq8005_rx(struct net_device *dev);
static int seeq8005_close(struct net_device *dev);
static struct net_device_stats *seeq8005_get_stats(struct net_device *dev);
@@ -437,7 +437,7 @@ inline void wait_for_buffer(struct net_device * dev)
/* The typical workload of the driver:
Handle the network interface interrupts. */
-static irqreturn_t seeq8005_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t seeq8005_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *lp;
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c
index f95a5b0223fb..a833e7f9757f 100644
--- a/drivers/net/sgiseeq.c
+++ b/drivers/net/sgiseeq.c
@@ -432,7 +432,7 @@ static inline void sgiseeq_tx(struct net_device *dev, struct sgiseeq_private *sp
}
}
-static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sgiseeq_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct sgiseeq_private *sp = netdev_priv(dev);
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c
index e8f26b79bbaf..aaba458584fb 100644
--- a/drivers/net/sis190.c
+++ b/drivers/net/sis190.c
@@ -713,7 +713,7 @@ static void sis190_tx_interrupt(struct net_device *dev,
* The interrupt handler does all of the Rx thread work and cleans up after
* the Tx thread.
*/
-static irqreturn_t sis190_interrupt(int irq, void *__dev, struct pt_regs *regs)
+static irqreturn_t sis190_interrupt(int irq, void *__dev)
{
struct net_device *dev = __dev;
struct sis190_private *tp = netdev_priv(dev);
@@ -758,7 +758,7 @@ static void sis190_netpoll(struct net_device *dev)
struct pci_dev *pdev = tp->pci_dev;
disable_irq(pdev->irq);
- sis190_interrupt(pdev->irq, dev, NULL);
+ sis190_interrupt(pdev->irq, dev);
enable_irq(pdev->irq);
}
#endif
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 28606e20df1c..fb2b53051635 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -218,7 +218,7 @@ static void sis900_init_rx_ring(struct net_device *net_dev);
static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
static int sis900_rx(struct net_device *net_dev);
static void sis900_finish_xmit (struct net_device *net_dev);
-static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t sis900_interrupt(int irq, void *dev_instance);
static int sis900_close(struct net_device *net_dev);
static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd);
static struct net_device_stats *sis900_get_stats(struct net_device *net_dev);
@@ -988,7 +988,7 @@ static u16 sis900_reset_phy(struct net_device *net_dev, int phy_addr)
static void sis900_poll(struct net_device *dev)
{
disable_irq(dev->irq);
- sis900_interrupt(dev->irq, dev, NULL);
+ sis900_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
@@ -1642,7 +1642,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
* and cleans up after the Tx thread
*/
-static irqreturn_t sis900_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t sis900_interrupt(int irq, void *dev_instance)
{
struct net_device *net_dev = dev_instance;
struct sis900_private *sis_priv = net_dev->priv;
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 99e92627642c..d4913c3de2a1 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -196,8 +196,8 @@ static SK_BOOL BoardAllocMem(SK_AC *pAC);
static void BoardFreeMem(SK_AC *pAC);
static void BoardInitMem(SK_AC *pAC);
static void SetupRing(SK_AC*, void*, uintptr_t, RXD**, RXD**, RXD**, int*, SK_BOOL);
-static SkIsrRetVar SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs);
-static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs);
+static SkIsrRetVar SkGeIsr(int irq, void *dev_id);
+static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id);
static int SkGeOpen(struct SK_NET_DEVICE *dev);
static int SkGeClose(struct SK_NET_DEVICE *dev);
static int SkGeXmit(struct sk_buff *skb, struct SK_NET_DEVICE *dev);
@@ -880,7 +880,7 @@ int PortIndex) /* index of the port for which to re-init */
* Returns: N/A
*
*/
-static SkIsrRetVar SkGeIsr(int irq, void *dev_id, struct pt_regs *ptregs)
+static SkIsrRetVar SkGeIsr(int irq, void *dev_id)
{
struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
DEV_NET *pNet;
@@ -1029,7 +1029,7 @@ SK_U32 IntSrc; /* interrupts source register contents */
* Returns: N/A
*
*/
-static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id, struct pt_regs *ptregs)
+static SkIsrRetVar SkGeIsrOnePort(int irq, void *dev_id)
{
struct SK_NET_DEVICE *dev = (struct SK_NET_DEVICE *)dev_id;
DEV_NET *pNet;
@@ -1140,7 +1140,7 @@ SK_U32 IntSrc; /* interrupts source register contents */
static void SkGePollController(struct net_device *dev)
{
disable_irq(dev->irq);
- SkGeIsr(dev->irq, dev, NULL);
+ SkGeIsr(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
index 37b88da1abe5..96e06c51b75d 100644
--- a/drivers/net/sk_mca.c
+++ b/drivers/net/sk_mca.c
@@ -732,7 +732,7 @@ static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
/* general interrupt entry */
-static irqreturn_t irq_handler(int irq, void *device, struct pt_regs *regs)
+static irqreturn_t irq_handler(int irq, void *device)
{
struct net_device *dev = (struct net_device *) device;
u16 csr0val;
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index 8e4d18440a56..9733a11c6146 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -101,7 +101,7 @@ static const char * const boot_msg =
static int skfp_driver_init(struct net_device *dev);
static int skfp_open(struct net_device *dev);
static int skfp_close(struct net_device *dev);
-static irqreturn_t skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t skfp_interrupt(int irq, void *dev_id);
static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev);
static void skfp_ctl_set_multicast_list(struct net_device *dev);
static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev);
@@ -593,7 +593,6 @@ static int skfp_close(struct net_device *dev)
* Arguments:
* irq - interrupt vector
* dev_id - pointer to device information
- * regs - pointer to registers structure
*
* Functional Description:
* This routine calls the interrupt processing routine for this adapter. It
@@ -615,17 +614,12 @@ static int skfp_close(struct net_device *dev)
* Interrupts are disabled, then reenabled at the adapter.
*/
-irqreturn_t skfp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t skfp_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct s_smc *smc; /* private board structure pointer */
skfddi_priv *bp;
- if (dev == NULL) {
- printk("%s: irq %d for unknown device\n", dev->name, irq);
- return IRQ_NONE;
- }
-
smc = netdev_priv(dev);
bp = &smc->os;
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 9142d91355bc..e7e414928f89 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -43,7 +43,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.8"
+#define DRV_VERSION "1.9"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -58,6 +58,7 @@
#define TX_WATCHDOG (5 * HZ)
#define NAPI_WEIGHT 64
#define BLINK_MS 250
+#define LINK_HZ (HZ/2)
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
@@ -196,8 +197,8 @@ static u32 skge_supported_modes(const struct skge_hw *hw)
else if (hw->chip_id == CHIP_ID_YUKON)
supported &= ~SUPPORTED_1000baseT_Half;
} else
- supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
- | SUPPORTED_Autoneg;
+ supported = SUPPORTED_1000baseT_Full | SUPPORTED_1000baseT_Half
+ | SUPPORTED_FIBRE | SUPPORTED_Autoneg;
return supported;
}
@@ -486,31 +487,37 @@ static void skge_get_pauseparam(struct net_device *dev,
{
struct skge_port *skge = netdev_priv(dev);
- ecmd->tx_pause = (skge->flow_control == FLOW_MODE_LOC_SEND)
- || (skge->flow_control == FLOW_MODE_SYMMETRIC);
- ecmd->rx_pause = (skge->flow_control == FLOW_MODE_REM_SEND)
- || (skge->flow_control == FLOW_MODE_SYMMETRIC);
+ ecmd->rx_pause = (skge->flow_control == FLOW_MODE_SYMMETRIC)
+ || (skge->flow_control == FLOW_MODE_SYM_OR_REM);
+ ecmd->tx_pause = ecmd->rx_pause || (skge->flow_control == FLOW_MODE_LOC_SEND);
- ecmd->autoneg = skge->autoneg;
+ ecmd->autoneg = ecmd->rx_pause || ecmd->tx_pause;
}
static int skge_set_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *ecmd)
{
struct skge_port *skge = netdev_priv(dev);
+ struct ethtool_pauseparam old;
- skge->autoneg = ecmd->autoneg;
- if (ecmd->rx_pause && ecmd->tx_pause)
- skge->flow_control = FLOW_MODE_SYMMETRIC;
- else if (ecmd->rx_pause && !ecmd->tx_pause)
- skge->flow_control = FLOW_MODE_REM_SEND;
- else if (!ecmd->rx_pause && ecmd->tx_pause)
- skge->flow_control = FLOW_MODE_LOC_SEND;
- else
- skge->flow_control = FLOW_MODE_NONE;
+ skge_get_pauseparam(dev, &old);
+
+ if (ecmd->autoneg != old.autoneg)
+ skge->flow_control = ecmd->autoneg ? FLOW_MODE_NONE : FLOW_MODE_SYMMETRIC;
+ else {
+ if (ecmd->rx_pause && ecmd->tx_pause)
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+ else if (ecmd->rx_pause && !ecmd->tx_pause)
+ skge->flow_control = FLOW_MODE_SYM_OR_REM;
+ else if (!ecmd->rx_pause && ecmd->tx_pause)
+ skge->flow_control = FLOW_MODE_LOC_SEND;
+ else
+ skge->flow_control = FLOW_MODE_NONE;
+ }
if (netif_running(dev))
skge_phy_reset(skge);
+
return 0;
}
@@ -605,7 +612,12 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
if (hw->chip_id == CHIP_ID_GENESIS) {
switch (mode) {
case LED_MODE_OFF:
- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
+ if (hw->phy_type == SK_PHY_BCOM)
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
+ else {
+ skge_write32(hw, SK_REG(port, TX_LED_VAL), 0);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF);
+ }
skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
@@ -625,8 +637,14 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
- xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
- break;
+ if (hw->phy_type == SK_PHY_BCOM)
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
+ else {
+ skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON);
+ skge_write32(hw, SK_REG(port, TX_LED_VAL), 100);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
+ }
+
}
} else {
switch (mode) {
@@ -842,6 +860,23 @@ static int skge_rx_fill(struct net_device *dev)
return 0;
}
+static const char *skge_pause(enum pause_status status)
+{
+ switch(status) {
+ case FLOW_STAT_NONE:
+ return "none";
+ case FLOW_STAT_REM_SEND:
+ return "rx only";
+ case FLOW_STAT_LOC_SEND:
+ return "tx_only";
+ case FLOW_STAT_SYMMETRIC: /* Both station may send PAUSE */
+ return "both";
+ default:
+ return "indeterminated";
+ }
+}
+
+
static void skge_link_up(struct skge_port *skge)
{
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG),
@@ -850,16 +885,13 @@ static void skge_link_up(struct skge_port *skge)
netif_carrier_on(skge->netdev);
netif_wake_queue(skge->netdev);
- if (netif_msg_link(skge))
+ if (netif_msg_link(skge)) {
printk(KERN_INFO PFX
"%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
skge->netdev->name, skge->speed,
skge->duplex == DUPLEX_FULL ? "full" : "half",
- (skge->flow_control == FLOW_MODE_NONE) ? "none" :
- (skge->flow_control == FLOW_MODE_LOC_SEND) ? "tx only" :
- (skge->flow_control == FLOW_MODE_REM_SEND) ? "rx only" :
- (skge->flow_control == FLOW_MODE_SYMMETRIC) ? "tx and rx" :
- "unknown");
+ skge_pause(skge->flow_status));
+ }
}
static void skge_link_down(struct skge_port *skge)
@@ -872,6 +904,29 @@ static void skge_link_down(struct skge_port *skge)
printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
}
+
+static void xm_link_down(struct skge_hw *hw, int port)
+{
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
+ u16 cmd, msk;
+
+ if (hw->phy_type == SK_PHY_XMAC) {
+ msk = xm_read16(hw, port, XM_IMSK);
+ msk |= XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | XM_IS_AND;
+ xm_write16(hw, port, XM_IMSK, msk);
+ }
+
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
+ cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
+ /* dummy read to ensure writing */
+ (void) xm_read16(hw, port, XM_MMU_CMD);
+
+ if (netif_carrier_ok(dev))
+ skge_link_down(skge);
+}
+
static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
{
int i;
@@ -879,6 +934,9 @@ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
*val = xm_read16(hw, port, XM_PHY_DATA);
+ if (hw->phy_type == SK_PHY_XMAC)
+ goto ready;
+
for (i = 0; i < PHY_RETRIES; i++) {
if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
goto ready;
@@ -965,7 +1023,8 @@ static void genesis_reset(struct skge_hw *hw, int port)
xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
/* disable Broadcom PHY IRQ */
- xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+ if (hw->phy_type == SK_PHY_BCOM)
+ xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
xm_outhash(hw, port, XM_HSM, zero);
}
@@ -976,7 +1035,15 @@ static const u16 phy_pause_map[] = {
[FLOW_MODE_NONE] = 0,
[FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM,
[FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP,
- [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
+ [FLOW_MODE_SYM_OR_REM] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
+};
+
+/* special defines for FIBER (88E1011S only) */
+static const u16 fiber_pause_map[] = {
+ [FLOW_MODE_NONE] = PHY_X_P_NO_PAUSE,
+ [FLOW_MODE_LOC_SEND] = PHY_X_P_ASYM_MD,
+ [FLOW_MODE_SYMMETRIC] = PHY_X_P_SYM_MD,
+ [FLOW_MODE_SYM_OR_REM] = PHY_X_P_BOTH_MD,
};
@@ -992,68 +1059,64 @@ static void bcom_check_link(struct skge_hw *hw, int port)
status = xm_phy_read(hw, port, PHY_BCOM_STAT);
if ((status & PHY_ST_LSYNC) == 0) {
- u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
- cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
- xm_write16(hw, port, XM_MMU_CMD, cmd);
- /* dummy read to ensure writing */
- (void) xm_read16(hw, port, XM_MMU_CMD);
-
- if (netif_carrier_ok(dev))
- skge_link_down(skge);
- } else {
- if (skge->autoneg == AUTONEG_ENABLE &&
- (status & PHY_ST_AN_OVER)) {
- u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
- u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
-
- if (lpa & PHY_B_AN_RF) {
- printk(KERN_NOTICE PFX "%s: remote fault\n",
- dev->name);
- return;
- }
+ xm_link_down(hw, port);
+ return;
+ }
- /* Check Duplex mismatch */
- switch (aux & PHY_B_AS_AN_RES_MSK) {
- case PHY_B_RES_1000FD:
- skge->duplex = DUPLEX_FULL;
- break;
- case PHY_B_RES_1000HD:
- skge->duplex = DUPLEX_HALF;
- break;
- default:
- printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
- dev->name);
- return;
- }
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ u16 lpa, aux;
+ if (!(status & PHY_ST_AN_OVER))
+ return;
- /* We are using IEEE 802.3z/D5.0 Table 37-4 */
- switch (aux & PHY_B_AS_PAUSE_MSK) {
- case PHY_B_AS_PAUSE_MSK:
- skge->flow_control = FLOW_MODE_SYMMETRIC;
- break;
- case PHY_B_AS_PRR:
- skge->flow_control = FLOW_MODE_REM_SEND;
- break;
- case PHY_B_AS_PRT:
- skge->flow_control = FLOW_MODE_LOC_SEND;
- break;
- default:
- skge->flow_control = FLOW_MODE_NONE;
- }
+ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
+ if (lpa & PHY_B_AN_RF) {
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
+ dev->name);
+ return;
+ }
+
+ aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
- skge->speed = SPEED_1000;
+ /* Check Duplex mismatch */
+ switch (aux & PHY_B_AS_AN_RES_MSK) {
+ case PHY_B_RES_1000FD:
+ skge->duplex = DUPLEX_FULL;
+ break;
+ case PHY_B_RES_1000HD:
+ skge->duplex = DUPLEX_HALF;
+ break;
+ default:
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+ dev->name);
+ return;
}
- if (!netif_carrier_ok(dev))
- genesis_link_up(skge);
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ switch (aux & PHY_B_AS_PAUSE_MSK) {
+ case PHY_B_AS_PAUSE_MSK:
+ skge->flow_status = FLOW_STAT_SYMMETRIC;
+ break;
+ case PHY_B_AS_PRR:
+ skge->flow_status = FLOW_STAT_REM_SEND;
+ break;
+ case PHY_B_AS_PRT:
+ skge->flow_status = FLOW_STAT_LOC_SEND;
+ break;
+ default:
+ skge->flow_status = FLOW_STAT_NONE;
+ }
+ skge->speed = SPEED_1000;
}
+
+ if (!netif_carrier_ok(dev))
+ genesis_link_up(skge);
}
/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
* Phy on for 100 or 10Mbit operation
*/
-static void bcom_phy_init(struct skge_port *skge, int jumbo)
+static void bcom_phy_init(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
@@ -1144,7 +1207,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
/* Handle Jumbo frames */
- if (jumbo) {
+ if (hw->dev[port]->mtu > ETH_DATA_LEN) {
xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
@@ -1157,8 +1220,142 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
/* Use link status change interrupt */
xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+}
+
+static void xm_phy_init(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ u16 ctrl = 0;
+
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ if (skge->advertising & ADVERTISED_1000baseT_Half)
+ ctrl |= PHY_X_AN_HD;
+ if (skge->advertising & ADVERTISED_1000baseT_Full)
+ ctrl |= PHY_X_AN_FD;
+
+ ctrl |= fiber_pause_map[skge->flow_control];
+
+ xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl);
+
+ /* Restart Auto-negotiation */
+ ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
+ } else {
+ /* Set DuplexMode in Config register */
+ if (skge->duplex == DUPLEX_FULL)
+ ctrl |= PHY_CT_DUP_MD;
+ /*
+ * Do NOT enable Auto-negotiation here. This would hold
+ * the link down because no IDLEs are transmitted
+ */
+ }
+
+ xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);
- bcom_check_link(hw, port);
+ /* Poll PHY for status changes */
+ schedule_delayed_work(&skge->link_thread, LINK_HZ);
+}
+
+static void xm_check_link(struct net_device *dev)
+{
+ struct skge_port *skge = netdev_priv(dev);
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ u16 status;
+
+ /* read twice because of latch */
+ (void) xm_phy_read(hw, port, PHY_XMAC_STAT);
+ status = xm_phy_read(hw, port, PHY_XMAC_STAT);
+
+ if ((status & PHY_ST_LSYNC) == 0) {
+ xm_link_down(hw, port);
+ return;
+ }
+
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ u16 lpa, res;
+
+ if (!(status & PHY_ST_AN_OVER))
+ return;
+
+ lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
+ if (lpa & PHY_B_AN_RF) {
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
+ dev->name);
+ return;
+ }
+
+ res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
+
+ /* Check Duplex mismatch */
+ switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) {
+ case PHY_X_RS_FD:
+ skge->duplex = DUPLEX_FULL;
+ break;
+ case PHY_X_RS_HD:
+ skge->duplex = DUPLEX_HALF;
+ break;
+ default:
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+ dev->name);
+ return;
+ }
+
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ if ((skge->flow_control == FLOW_MODE_SYMMETRIC ||
+ skge->flow_control == FLOW_MODE_SYM_OR_REM) &&
+ (lpa & PHY_X_P_SYM_MD))
+ skge->flow_status = FLOW_STAT_SYMMETRIC;
+ else if (skge->flow_control == FLOW_MODE_SYM_OR_REM &&
+ (lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD)
+ /* Enable PAUSE receive, disable PAUSE transmit */
+ skge->flow_status = FLOW_STAT_REM_SEND;
+ else if (skge->flow_control == FLOW_MODE_LOC_SEND &&
+ (lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD)
+ /* Disable PAUSE receive, enable PAUSE transmit */
+ skge->flow_status = FLOW_STAT_LOC_SEND;
+ else
+ skge->flow_status = FLOW_STAT_NONE;
+
+ skge->speed = SPEED_1000;
+ }
+
+ if (!netif_carrier_ok(dev))
+ genesis_link_up(skge);
+}
+
+/* Poll to check for link coming up.
+ * Since internal PHY is wired to a level triggered pin, can't
+ * get an interrupt when carrier is detected.
+ */
+static void xm_link_timer(void *arg)
+{
+ struct net_device *dev = arg;
+ struct skge_port *skge = netdev_priv(arg);
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+
+ if (!netif_running(dev))
+ return;
+
+ if (netif_carrier_ok(dev)) {
+ xm_read16(hw, port, XM_ISRC);
+ if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS))
+ goto nochange;
+ } else {
+ if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
+ goto nochange;
+ xm_read16(hw, port, XM_ISRC);
+ if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
+ goto nochange;
+ }
+
+ mutex_lock(&hw->phy_mutex);
+ xm_check_link(dev);
+ mutex_unlock(&hw->phy_mutex);
+
+nochange:
+ schedule_delayed_work(&skge->link_thread, LINK_HZ);
}
static void genesis_mac_init(struct skge_hw *hw, int port)
@@ -1189,20 +1386,29 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* namely for the 1000baseTX cards that use the XMAC's
* GMII mode.
*/
- /* Take external Phy out of reset */
- r = skge_read32(hw, B2_GP_IO);
- if (port == 0)
- r |= GP_DIR_0|GP_IO_0;
- else
- r |= GP_DIR_2|GP_IO_2;
+ if (hw->phy_type != SK_PHY_XMAC) {
+ /* Take external Phy out of reset */
+ r = skge_read32(hw, B2_GP_IO);
+ if (port == 0)
+ r |= GP_DIR_0|GP_IO_0;
+ else
+ r |= GP_DIR_2|GP_IO_2;
- skge_write32(hw, B2_GP_IO, r);
+ skge_write32(hw, B2_GP_IO, r);
+ /* Enable GMII interface */
+ xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+ }
- /* Enable GMII interface */
- xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
- bcom_phy_init(skge, jumbo);
+ switch(hw->phy_type) {
+ case SK_PHY_XMAC:
+ xm_phy_init(skge);
+ break;
+ case SK_PHY_BCOM:
+ bcom_phy_init(skge);
+ bcom_check_link(hw, port);
+ }
/* Set Station Address */
xm_outaddr(hw, port, XM_SA, dev->dev_addr);
@@ -1335,16 +1541,18 @@ static void genesis_stop(struct skge_port *skge)
skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
/* For external PHYs there must be special handling */
- reg = skge_read32(hw, B2_GP_IO);
- if (port == 0) {
- reg |= GP_DIR_0;
- reg &= ~GP_IO_0;
- } else {
- reg |= GP_DIR_2;
- reg &= ~GP_IO_2;
+ if (hw->phy_type != SK_PHY_XMAC) {
+ reg = skge_read32(hw, B2_GP_IO);
+ if (port == 0) {
+ reg |= GP_DIR_0;
+ reg &= ~GP_IO_0;
+ } else {
+ reg |= GP_DIR_2;
+ reg &= ~GP_IO_2;
+ }
+ skge_write32(hw, B2_GP_IO, reg);
+ skge_read32(hw, B2_GP_IO);
}
- skge_write32(hw, B2_GP_IO, reg);
- skge_read32(hw, B2_GP_IO);
xm_write16(hw, port, XM_MMU_CMD,
xm_read16(hw, port, XM_MMU_CMD)
@@ -1391,6 +1599,10 @@ static void genesis_mac_intr(struct skge_hw *hw, int port)
printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
skge->netdev->name, status);
+ if (hw->phy_type == SK_PHY_XMAC &&
+ (status & (XM_IS_INP_ASS | XM_IS_LIPA_RC)))
+ xm_link_down(hw, port);
+
if (status & XM_IS_TXF_UR) {
xm_write32(hw, port, XM_MODE, XM_MD_FTF);
++skge->net_stats.tx_fifo_errors;
@@ -1405,8 +1617,8 @@ static void genesis_link_up(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
- u16 cmd;
- u32 mode, msk;
+ u16 cmd, msk;
+ u32 mode;
cmd = xm_read16(hw, port, XM_MMU_CMD);
@@ -1414,8 +1626,8 @@ static void genesis_link_up(struct skge_port *skge)
* enabling pause frame reception is required for 1000BT
* because the XMAC is not reset if the link is going down
*/
- if (skge->flow_control == FLOW_MODE_NONE ||
- skge->flow_control == FLOW_MODE_LOC_SEND)
+ if (skge->flow_status == FLOW_STAT_NONE ||
+ skge->flow_status == FLOW_STAT_LOC_SEND)
/* Disable Pause Frame Reception */
cmd |= XM_MMU_IGN_PF;
else
@@ -1425,8 +1637,8 @@ static void genesis_link_up(struct skge_port *skge)
xm_write16(hw, port, XM_MMU_CMD, cmd);
mode = xm_read32(hw, port, XM_MODE);
- if (skge->flow_control == FLOW_MODE_SYMMETRIC ||
- skge->flow_control == FLOW_MODE_LOC_SEND) {
+ if (skge->flow_status== FLOW_STAT_SYMMETRIC ||
+ skge->flow_status == FLOW_STAT_LOC_SEND) {
/*
* Configure Pause Frame Generation
* Use internal and external Pause Frame Generation.
@@ -1454,27 +1666,28 @@ static void genesis_link_up(struct skge_port *skge)
}
xm_write32(hw, port, XM_MODE, mode);
-
msk = XM_DEF_MSK;
- /* disable GP0 interrupt bit for external Phy */
- msk |= XM_IS_INP_ASS;
+ if (hw->phy_type != SK_PHY_XMAC)
+ msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */
xm_write16(hw, port, XM_IMSK, msk);
xm_read16(hw, port, XM_ISRC);
/* get MMU Command Reg. */
cmd = xm_read16(hw, port, XM_MMU_CMD);
- if (skge->duplex == DUPLEX_FULL)
+ if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
cmd |= XM_MMU_GMII_FD;
/*
* Workaround BCOM Errata (#10523) for all BCom Phys
* Enable Power Management after link up
*/
- xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
- xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
- & ~PHY_B_AC_DIS_PM);
- xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+ if (hw->phy_type == SK_PHY_BCOM) {
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+ xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+ & ~PHY_B_AC_DIS_PM);
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+ }
/* enable Rx/Tx */
xm_write16(hw, port, XM_MMU_CMD,
@@ -1605,11 +1818,17 @@ static void yukon_init(struct skge_hw *hw, int port)
adv |= PHY_M_AN_10_FD;
if (skge->advertising & ADVERTISED_10baseT_Half)
adv |= PHY_M_AN_10_HD;
- } else /* special defines for FIBER (88E1011S only) */
- adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
- /* Set Flow-control capabilities */
- adv |= phy_pause_map[skge->flow_control];
+ /* Set Flow-control capabilities */
+ adv |= phy_pause_map[skge->flow_control];
+ } else {
+ if (skge->advertising & ADVERTISED_1000baseT_Full)
+ adv |= PHY_M_AN_1000X_AFD;
+ if (skge->advertising & ADVERTISED_1000baseT_Half)
+ adv |= PHY_M_AN_1000X_AHD;
+
+ adv |= fiber_pause_map[skge->flow_control];
+ }
/* Restart Auto-negotiation */
ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
@@ -1743,6 +1962,11 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
case FLOW_MODE_LOC_SEND:
/* disable Rx flow-control */
reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
+ break;
+ case FLOW_MODE_SYMMETRIC:
+ case FLOW_MODE_SYM_OR_REM:
+ /* enable Tx & Rx flow-control */
+ break;
}
gma_write16(hw, port, GM_GP_CTRL, reg);
@@ -1937,13 +2161,11 @@ static void yukon_link_down(struct skge_port *skge)
ctrl &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
gma_write16(hw, port, GM_GP_CTRL, ctrl);
- if (skge->flow_control == FLOW_MODE_REM_SEND) {
+ if (skge->flow_status == FLOW_STAT_REM_SEND) {
+ ctrl = gm_phy_read(hw, port, PHY_MARV_AUNE_ADV);
+ ctrl |= PHY_M_AN_ASP;
/* restore Asymmetric Pause bit */
- gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
- gm_phy_read(hw, port,
- PHY_MARV_AUNE_ADV)
- | PHY_M_AN_ASP);
-
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, ctrl);
}
yukon_reset(hw, port);
@@ -1990,19 +2212,19 @@ static void yukon_phy_intr(struct skge_port *skge)
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
switch (phystat & PHY_M_PS_PAUSE_MSK) {
case PHY_M_PS_PAUSE_MSK:
- skge->flow_control = FLOW_MODE_SYMMETRIC;
+ skge->flow_status = FLOW_STAT_SYMMETRIC;
break;
case PHY_M_PS_RX_P_EN:
- skge->flow_control = FLOW_MODE_REM_SEND;
+ skge->flow_status = FLOW_STAT_REM_SEND;
break;
case PHY_M_PS_TX_P_EN:
- skge->flow_control = FLOW_MODE_LOC_SEND;
+ skge->flow_status = FLOW_STAT_LOC_SEND;
break;
default:
- skge->flow_control = FLOW_MODE_NONE;
+ skge->flow_status = FLOW_STAT_NONE;
}
- if (skge->flow_control == FLOW_MODE_NONE ||
+ if (skge->flow_status == FLOW_STAT_NONE ||
(skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF))
skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
else
@@ -2240,6 +2462,8 @@ static int skge_down(struct net_device *dev)
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
netif_stop_queue(dev);
+ if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
+ cancel_rearming_delayed_work(&skge->link_thread);
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
if (hw->chip_id == CHIP_ID_GENESIS)
@@ -2862,7 +3086,7 @@ static void skge_extirq(void *arg)
if (netif_running(dev)) {
if (hw->chip_id != CHIP_ID_GENESIS)
yukon_phy_intr(skge);
- else
+ else if (hw->phy_type == SK_PHY_BCOM)
bcom_phy_intr(skge);
}
}
@@ -2875,7 +3099,7 @@ static void skge_extirq(void *arg)
spin_unlock_irq(&hw->hw_lock);
}
-static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t skge_intr(int irq, void *dev_id)
{
struct skge_hw *hw = dev_id;
u32 status;
@@ -2949,7 +3173,7 @@ static void skge_netpoll(struct net_device *dev)
struct skge_port *skge = netdev_priv(dev);
disable_irq(dev->irq);
- skge_intr(dev->irq, skge->hw, NULL);
+ skge_intr(dev->irq, skge->hw);
enable_irq(dev->irq);
}
#endif
@@ -3014,7 +3238,7 @@ static int skge_reset(struct skge_hw *hw)
{
u32 reg;
u16 ctst, pci_status;
- u8 t8, mac_cfg, pmd_type, phy_type;
+ u8 t8, mac_cfg, pmd_type;
int i;
ctst = skge_read16(hw, B0_CTST);
@@ -3038,19 +3262,22 @@ static int skge_reset(struct skge_hw *hw)
ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
hw->chip_id = skge_read8(hw, B2_CHIP_ID);
- phy_type = skge_read8(hw, B2_E_1) & 0xf;
+ hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
pmd_type = skge_read8(hw, B2_PMD_TYP);
hw->copper = (pmd_type == 'T' || pmd_type == '1');
switch (hw->chip_id) {
case CHIP_ID_GENESIS:
- switch (phy_type) {
+ switch (hw->phy_type) {
+ case SK_PHY_XMAC:
+ hw->phy_addr = PHY_ADDR_XMAC;
+ break;
case SK_PHY_BCOM:
hw->phy_addr = PHY_ADDR_BCOM;
break;
default:
printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
- pci_name(hw->pdev), phy_type);
+ pci_name(hw->pdev), hw->phy_type);
return -EOPNOTSUPP;
}
break;
@@ -3058,7 +3285,7 @@ static int skge_reset(struct skge_hw *hw)
case CHIP_ID_YUKON:
case CHIP_ID_YUKON_LITE:
case CHIP_ID_YUKON_LP:
- if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
+ if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
hw->copper = 1;
hw->phy_addr = PHY_ADDR_MARV;
@@ -3089,10 +3316,13 @@ static int skge_reset(struct skge_hw *hw)
else
hw->ram_size = t8 * 4096;
- hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
+ hw->intr_mask = IS_HW_ERR | IS_PORT_1;
if (hw->ports > 1)
hw->intr_mask |= IS_PORT_2;
+ if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC))
+ hw->intr_mask |= IS_EXT_REG;
+
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_init(hw);
else {
@@ -3217,7 +3447,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
/* Auto speed and flow control */
skge->autoneg = AUTONEG_ENABLE;
- skge->flow_control = FLOW_MODE_SYMMETRIC;
+ skge->flow_control = FLOW_MODE_SYM_OR_REM;
skge->duplex = -1;
skge->speed = -1;
skge->advertising = skge_supported_modes(hw);
@@ -3226,6 +3456,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
skge->port = port;
+ /* Only used for Genesis XMAC */
+ INIT_WORK(&skge->link_thread, xm_link_timer, dev);
+
if (hw->chip_id != CHIP_ID_GENESIS) {
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
skge->rx_csum = 1;
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 79e09271bcf9..537c0aaa1db8 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -934,7 +934,7 @@ enum {
PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */
PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
- PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
+ PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */
PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */
@@ -1097,13 +1097,36 @@ enum {
/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
enum {
- PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */
+ PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */
PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */
PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */
PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */
};
+/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/
+enum {
+ PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */
+ PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */
+};
+
+/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/
+enum {
+ PHY_X_RS_PAUSE = 3<<7, /* Bit 8..7: selected Pause Mode */
+ PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */
+ PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */
+ PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */
+ PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */
+};
+
+/* Remote Fault Bits (PHY_X_AN_RFB) encoding */
+enum {
+ X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */
+ X_RFB_LF = 1<<12,/* Bit 13..12 Link Failure */
+ X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */
+ X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */
+};
+
/* Broadcom-Specific */
/***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
enum {
@@ -2158,8 +2181,8 @@ enum {
XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */
XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */
XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */
- XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
- XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
+ XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
+ XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */
XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */
XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */
@@ -2172,8 +2195,7 @@ enum {
XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */
};
-#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \
- XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \
+#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | \
XM_IS_RXF_OV | XM_IS_TXF_UR))
@@ -2396,6 +2418,7 @@ struct skge_hw {
u8 chip_rev;
u8 copper;
u8 ports;
+ u8 phy_type;
u32 ram_size;
u32 ram_offset;
@@ -2404,13 +2427,24 @@ struct skge_hw {
struct mutex phy_mutex;
};
-enum {
- FLOW_MODE_NONE = 0, /* No Flow-Control */
- FLOW_MODE_LOC_SEND = 1, /* Local station sends PAUSE */
- FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */
+enum pause_control {
+ FLOW_MODE_NONE = 1, /* No Flow-Control */
+ FLOW_MODE_LOC_SEND = 2, /* Local station sends PAUSE */
FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */
+ FLOW_MODE_SYM_OR_REM = 4, /* Both stations may send PAUSE or
+ * just the remote station may send PAUSE
+ */
};
+enum pause_status {
+ FLOW_STAT_INDETERMINATED=0, /* indeterminated */
+ FLOW_STAT_NONE, /* No Flow Control */
+ FLOW_STAT_REM_SEND, /* Remote Station sends PAUSE */
+ FLOW_STAT_LOC_SEND, /* Local station sends PAUSE */
+ FLOW_STAT_SYMMETRIC, /* Both station may send PAUSE */
+};
+
+
struct skge_port {
u32 msg_enable;
struct skge_hw *hw;
@@ -2422,9 +2456,11 @@ struct skge_port {
struct net_device_stats net_stats;
+ struct work_struct link_thread;
+ enum pause_control flow_control;
+ enum pause_status flow_status;
u8 rx_csum;
u8 blink_on;
- u8 flow_control;
u8 wol;
u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c
index 7eeefa2d6c89..67ecd66f26d6 100644
--- a/drivers/net/sky2.c
+++ b/drivers/net/sky2.c
@@ -50,19 +50,18 @@
#include "sky2.h"
#define DRV_NAME "sky2"
-#define DRV_VERSION "1.7"
+#define DRV_VERSION "1.10"
#define PFX DRV_NAME " "
/*
* The Yukon II chipset takes 64 bit command blocks (called list elements)
* that are organized into three (receive, transmit, status) different rings
- * similar to Tigon3. A transmit can require several elements;
- * a receive requires one (or two if using 64 bit dma).
+ * similar to Tigon3.
*/
-#define RX_LE_SIZE 512
+#define RX_LE_SIZE 1024
#define RX_LE_BYTES (RX_LE_SIZE*sizeof(struct sky2_rx_le))
-#define RX_MAX_PENDING (RX_LE_SIZE/2 - 2)
+#define RX_MAX_PENDING (RX_LE_SIZE/6 - 2)
#define RX_DEF_PENDING RX_MAX_PENDING
#define RX_SKB_ALIGN 8
#define RX_BUF_WRITE 16
@@ -74,7 +73,6 @@
#define STATUS_RING_SIZE 2048 /* 2 ports * (TX + 2*RX) */
#define STATUS_LE_BYTES (STATUS_RING_SIZE*sizeof(struct sky2_status_le))
-#define ETH_JUMBO_MTU 9000
#define TX_WATCHDOG (5 * HZ)
#define NAPI_WEIGHT 64
#define PHY_RETRIES 1000
@@ -90,7 +88,7 @@ static int debug = -1; /* defaults above */
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
-static int copybreak __read_mostly = 256;
+static int copybreak __read_mostly = 128;
module_param(copybreak, int, 0);
MODULE_PARM_DESC(copybreak, "Receive copy threshold");
@@ -98,9 +96,9 @@ static int disable_msi = 0;
module_param(disable_msi, int, 0);
MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
-static int idle_timeout = 100;
+static int idle_timeout = 0;
module_param(idle_timeout, int, 0);
-MODULE_PARM_DESC(idle_timeout, "Idle timeout workaround for lost interrupts (ms)");
+MODULE_PARM_DESC(idle_timeout, "Watchdog timer for lost interrupts (ms)");
static const struct pci_device_id sky2_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9000) },
@@ -286,6 +284,31 @@ static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
gma_write16(hw, port, GM_RX_CTRL, reg);
}
+/* flow control to advertise bits */
+static const u16 copper_fc_adv[] = {
+ [FC_NONE] = 0,
+ [FC_TX] = PHY_M_AN_ASP,
+ [FC_RX] = PHY_M_AN_PC,
+ [FC_BOTH] = PHY_M_AN_PC | PHY_M_AN_ASP,
+};
+
+/* flow control to advertise bits when using 1000BaseX */
+static const u16 fiber_fc_adv[] = {
+ [FC_BOTH] = PHY_M_P_BOTH_MD_X,
+ [FC_TX] = PHY_M_P_ASYM_MD_X,
+ [FC_RX] = PHY_M_P_SYM_MD_X,
+ [FC_NONE] = PHY_M_P_NO_PAUSE_X,
+};
+
+/* flow control to GMA disable bits */
+static const u16 gm_fc_disable[] = {
+ [FC_NONE] = GM_GPCR_FC_RX_DIS | GM_GPCR_FC_TX_DIS,
+ [FC_TX] = GM_GPCR_FC_RX_DIS,
+ [FC_RX] = GM_GPCR_FC_TX_DIS,
+ [FC_BOTH] = 0,
+};
+
+
static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
{
struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -358,16 +381,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
}
- ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
- if (sky2->autoneg == AUTONEG_DISABLE)
- ctrl &= ~PHY_CT_ANE;
- else
- ctrl |= PHY_CT_ANE;
-
- ctrl |= PHY_CT_RESET;
- gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
-
- ctrl = 0;
+ ctrl = PHY_CT_RESET;
ct1000 = 0;
adv = PHY_AN_CSMA;
reg = 0;
@@ -386,20 +400,16 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
adv |= PHY_M_AN_10_FD;
if (sky2->advertising & ADVERTISED_10baseT_Half)
adv |= PHY_M_AN_10_HD;
+
+ adv |= copper_fc_adv[sky2->flow_mode];
} else { /* special defines for FIBER (88E1040S only) */
if (sky2->advertising & ADVERTISED_1000baseT_Full)
adv |= PHY_M_AN_1000X_AFD;
if (sky2->advertising & ADVERTISED_1000baseT_Half)
adv |= PHY_M_AN_1000X_AHD;
- }
- /* Set Flow-control capabilities */
- if (sky2->tx_pause && sky2->rx_pause)
- adv |= PHY_AN_PAUSE_CAP; /* symmetric */
- else if (sky2->rx_pause && !sky2->tx_pause)
- adv |= PHY_AN_PAUSE_ASYM | PHY_AN_PAUSE_CAP;
- else if (!sky2->rx_pause && sky2->tx_pause)
- adv |= PHY_AN_PAUSE_ASYM; /* local */
+ adv |= fiber_fc_adv[sky2->flow_mode];
+ }
/* Restart Auto-negotiation */
ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
@@ -424,25 +434,17 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
if (sky2->duplex == DUPLEX_FULL) {
reg |= GM_GPCR_DUP_FULL;
ctrl |= PHY_CT_DUP_MD;
- } else if (sky2->speed != SPEED_1000 && hw->chip_id != CHIP_ID_YUKON_EC_U) {
- /* Turn off flow control for 10/100mbps */
- sky2->rx_pause = 0;
- sky2->tx_pause = 0;
- }
+ } else if (sky2->speed < SPEED_1000)
+ sky2->flow_mode = FC_NONE;
- if (!sky2->rx_pause)
- reg |= GM_GPCR_FC_RX_DIS;
- if (!sky2->tx_pause)
- reg |= GM_GPCR_FC_TX_DIS;
+ reg |= gm_fc_disable[sky2->flow_mode];
/* Forward pause packets to GMAC? */
- if (sky2->tx_pause || sky2->rx_pause)
+ if (sky2->flow_mode & FC_RX)
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
else
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
-
- ctrl |= PHY_CT_RESET;
}
gma_write16(hw, port, GM_GP_CTRL, reg);
@@ -685,7 +687,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
- sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
+ sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 512/8);
sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
if (hw->dev[port]->mtu > ETH_DATA_LEN) {
/* set Tx GMAC FIFO Almost Empty Threshold */
@@ -769,9 +771,16 @@ static inline struct sky2_tx_le *get_tx_le(struct sky2_port *sky2)
struct sky2_tx_le *le = sky2->tx_le + sky2->tx_prod;
sky2->tx_prod = RING_NEXT(sky2->tx_prod, TX_RING_SIZE);
+ le->ctrl = 0;
return le;
}
+static inline struct tx_ring_info *tx_le_re(struct sky2_port *sky2,
+ struct sky2_tx_le *le)
+{
+ return sky2->tx_ring + (le - sky2->tx_le);
+}
+
/* Update chip's next pointer */
static inline void sky2_put_idx(struct sky2_hw *hw, unsigned q, u16 idx)
{
@@ -786,6 +795,7 @@ static inline struct sky2_rx_le *sky2_next_rx(struct sky2_port *sky2)
{
struct sky2_rx_le *le = sky2->rx_le + sky2->rx_put;
sky2->rx_put = RING_NEXT(sky2->rx_put, RX_LE_SIZE);
+ le->ctrl = 0;
return le;
}
@@ -795,17 +805,16 @@ static inline u32 high32(dma_addr_t a)
return sizeof(a) > sizeof(u32) ? (a >> 16) >> 16 : 0;
}
-/* Build description to hardware about buffer */
-static void sky2_rx_add(struct sky2_port *sky2, dma_addr_t map)
+/* Build description to hardware for one receive segment */
+static void sky2_rx_add(struct sky2_port *sky2, u8 op,
+ dma_addr_t map, unsigned len)
{
struct sky2_rx_le *le;
u32 hi = high32(map);
- u16 len = sky2->rx_bufsize;
if (sky2->rx_addr64 != hi) {
le = sky2_next_rx(sky2);
le->addr = cpu_to_le32(hi);
- le->ctrl = 0;
le->opcode = OP_ADDR64 | HW_OWNER;
sky2->rx_addr64 = high32(map + len);
}
@@ -813,10 +822,52 @@ static void sky2_rx_add(struct sky2_port *sky2, dma_addr_t map)
le = sky2_next_rx(sky2);
le->addr = cpu_to_le32((u32) map);
le->length = cpu_to_le16(len);
- le->ctrl = 0;
- le->opcode = OP_PACKET | HW_OWNER;
+ le->opcode = op | HW_OWNER;
}
+/* Build description to hardware for one possibly fragmented skb */
+static void sky2_rx_submit(struct sky2_port *sky2,
+ const struct rx_ring_info *re)
+{
+ int i;
+
+ sky2_rx_add(sky2, OP_PACKET, re->data_addr, sky2->rx_data_size);
+
+ for (i = 0; i < skb_shinfo(re->skb)->nr_frags; i++)
+ sky2_rx_add(sky2, OP_BUFFER, re->frag_addr[i], PAGE_SIZE);
+}
+
+
+static void sky2_rx_map_skb(struct pci_dev *pdev, struct rx_ring_info *re,
+ unsigned size)
+{
+ struct sk_buff *skb = re->skb;
+ int i;
+
+ re->data_addr = pci_map_single(pdev, skb->data, size, PCI_DMA_FROMDEVICE);
+ pci_unmap_len_set(re, data_size, size);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+ re->frag_addr[i] = pci_map_page(pdev,
+ skb_shinfo(skb)->frags[i].page,
+ skb_shinfo(skb)->frags[i].page_offset,
+ skb_shinfo(skb)->frags[i].size,
+ PCI_DMA_FROMDEVICE);
+}
+
+static void sky2_rx_unmap_skb(struct pci_dev *pdev, struct rx_ring_info *re)
+{
+ struct sk_buff *skb = re->skb;
+ int i;
+
+ pci_unmap_single(pdev, re->data_addr, pci_unmap_len(re, data_size),
+ PCI_DMA_FROMDEVICE);
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+ pci_unmap_page(pdev, re->frag_addr[i],
+ skb_shinfo(skb)->frags[i].size,
+ PCI_DMA_FROMDEVICE);
+}
/* Tell chip where to start receive checksum.
* Actually has two checksums, but set both same to avoid possible byte
@@ -877,12 +928,10 @@ static void sky2_rx_clean(struct sky2_port *sky2)
memset(sky2->rx_le, 0, RX_LE_BYTES);
for (i = 0; i < sky2->rx_pending; i++) {
- struct ring_info *re = sky2->rx_ring + i;
+ struct rx_ring_info *re = sky2->rx_ring + i;
if (re->skb) {
- pci_unmap_single(sky2->hw->pdev,
- re->mapaddr, sky2->rx_bufsize,
- PCI_DMA_FROMDEVICE);
+ sky2_rx_unmap_skb(sky2->hw->pdev, re);
kfree_skb(re->skb);
re->skb = NULL;
}
@@ -936,13 +985,13 @@ static void sky2_vlan_rx_register(struct net_device *dev, struct vlan_group *grp
struct sky2_hw *hw = sky2->hw;
u16 port = sky2->port;
- spin_lock_bh(&sky2->tx_lock);
+ netif_tx_lock_bh(dev);
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_ON);
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_ON);
sky2->vlgrp = grp;
- spin_unlock_bh(&sky2->tx_lock);
+ netif_tx_unlock_bh(dev);
}
static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
@@ -951,50 +1000,69 @@ static void sky2_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
struct sky2_hw *hw = sky2->hw;
u16 port = sky2->port;
- spin_lock_bh(&sky2->tx_lock);
+ netif_tx_lock_bh(dev);
sky2_write32(hw, SK_REG(port, RX_GMF_CTRL_T), RX_VLAN_STRIP_OFF);
sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T), TX_VLAN_TAG_OFF);
if (sky2->vlgrp)
sky2->vlgrp->vlan_devices[vid] = NULL;
- spin_unlock_bh(&sky2->tx_lock);
+ netif_tx_unlock_bh(dev);
}
#endif
/*
+ * Allocate an skb for receiving. If the MTU is large enough
+ * make the skb non-linear with a fragment list of pages.
+ *
* It appears the hardware has a bug in the FIFO logic that
* cause it to hang if the FIFO gets overrun and the receive buffer
* is not 64 byte aligned. The buffer returned from netdev_alloc_skb is
* aligned except if slab debugging is enabled.
*/
-static inline struct sk_buff *sky2_alloc_skb(struct net_device *dev,
- unsigned int length,
- gfp_t gfp_mask)
+static struct sk_buff *sky2_rx_alloc(struct sky2_port *sky2)
{
struct sk_buff *skb;
+ unsigned long p;
+ int i;
- skb = __netdev_alloc_skb(dev, length + RX_SKB_ALIGN, gfp_mask);
- if (likely(skb)) {
- unsigned long p = (unsigned long) skb->data;
- skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
+ skb = netdev_alloc_skb(sky2->netdev, sky2->rx_data_size + RX_SKB_ALIGN);
+ if (!skb)
+ goto nomem;
+
+ p = (unsigned long) skb->data;
+ skb_reserve(skb, ALIGN(p, RX_SKB_ALIGN) - p);
+
+ for (i = 0; i < sky2->rx_nfrags; i++) {
+ struct page *page = alloc_page(GFP_ATOMIC);
+
+ if (!page)
+ goto free_partial;
+ skb_fill_page_desc(skb, i, page, 0, PAGE_SIZE);
}
return skb;
+free_partial:
+ kfree_skb(skb);
+nomem:
+ return NULL;
}
/*
* Allocate and setup receiver buffer pool.
- * In case of 64 bit dma, there are 2X as many list elements
- * available as ring entries
- * and need to reserve one list element so we don't wrap around.
+ * Normal case this ends up creating one list element for skb
+ * in the receive ring. Worst case if using large MTU and each
+ * allocation falls on a different 64 bit region, that results
+ * in 6 list elements per ring entry.
+ * One element is used for checksum enable/disable, and one
+ * extra to avoid wrap.
*/
static int sky2_rx_start(struct sky2_port *sky2)
{
struct sky2_hw *hw = sky2->hw;
+ struct rx_ring_info *re;
unsigned rxq = rxqaddr[sky2->port];
- int i;
- unsigned thresh;
+ unsigned i, size, space, thresh;
sky2->rx_put = sky2->rx_next = 0;
sky2_qset(hw, rxq);
@@ -1007,27 +1075,56 @@ static int sky2_rx_start(struct sky2_port *sky2)
sky2_prefetch_init(hw, rxq, sky2->rx_le_map, RX_LE_SIZE - 1);
rx_set_checksum(sky2);
+
+ /* Space needed for frame data + headers rounded up */
+ size = ALIGN(sky2->netdev->mtu + ETH_HLEN + VLAN_HLEN, 8)
+ + 8;
+
+ /* Stopping point for hardware truncation */
+ thresh = (size - 8) / sizeof(u32);
+
+ /* Account for overhead of skb - to avoid order > 0 allocation */
+ space = SKB_DATA_ALIGN(size) + NET_SKB_PAD
+ + sizeof(struct skb_shared_info);
+
+ sky2->rx_nfrags = space >> PAGE_SHIFT;
+ BUG_ON(sky2->rx_nfrags > ARRAY_SIZE(re->frag_addr));
+
+ if (sky2->rx_nfrags != 0) {
+ /* Compute residue after pages */
+ space = sky2->rx_nfrags << PAGE_SHIFT;
+
+ if (space < size)
+ size -= space;
+ else
+ size = 0;
+
+ /* Optimize to handle small packets and headers */
+ if (size < copybreak)
+ size = copybreak;
+ if (size < ETH_HLEN)
+ size = ETH_HLEN;
+ }
+ sky2->rx_data_size = size;
+
+ /* Fill Rx ring */
for (i = 0; i < sky2->rx_pending; i++) {
- struct ring_info *re = sky2->rx_ring + i;
+ re = sky2->rx_ring + i;
- re->skb = sky2_alloc_skb(sky2->netdev, sky2->rx_bufsize,
- GFP_KERNEL);
+ re->skb = sky2_rx_alloc(sky2);
if (!re->skb)
goto nomem;
- re->mapaddr = pci_map_single(hw->pdev, re->skb->data,
- sky2->rx_bufsize, PCI_DMA_FROMDEVICE);
- sky2_rx_add(sky2, re->mapaddr);
+ sky2_rx_map_skb(hw->pdev, re, sky2->rx_data_size);
+ sky2_rx_submit(sky2, re);
}
-
/*
* The receiver hangs if it receives frames larger than the
* packet buffer. As a workaround, truncate oversize frames, but
* the register is limited to 9 bits, so if you do frames > 2052
* you better get the MTU right!
*/
- thresh = (sky2->rx_bufsize - 8) / sizeof(u32);
if (thresh > 0x1ff)
sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_OFF);
else {
@@ -1035,7 +1132,6 @@ static int sky2_rx_start(struct sky2_port *sky2)
sky2_write32(hw, SK_REG(sky2->port, RX_GMF_CTRL_T), RX_TRUNC_ON);
}
-
/* Tell chip about available buffers */
sky2_write16(hw, Y2_QADDR(rxq, PREF_UNIT_PUT_IDX), sky2->rx_put);
return 0;
@@ -1094,7 +1190,7 @@ static int sky2_up(struct net_device *dev)
goto err_out;
memset(sky2->rx_le, 0, RX_LE_BYTES);
- sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct ring_info),
+ sky2->rx_ring = kcalloc(sky2->rx_pending, sizeof(struct rx_ring_info),
GFP_KERNEL);
if (!sky2->rx_ring)
goto err_out;
@@ -1124,7 +1220,8 @@ static int sky2_up(struct net_device *dev)
sky2_qset(hw, txqaddr[port]);
/* Set almost empty threshold */
- if (hw->chip_id == CHIP_ID_YUKON_EC_U && hw->chip_rev == 1)
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U
+ && hw->chip_rev == CHIP_REV_YU_EC_U_A0)
sky2_write16(hw, Q_ADDR(txqaddr[port], Q_AL), 0x1a0);
sky2_prefetch_init(hw, txqaddr[port], sky2->tx_le_map,
@@ -1195,8 +1292,6 @@ static unsigned tx_le_req(const struct sk_buff *skb)
* A single packet can generate multiple list elements, and
* the number of ring elements will probably be less than the number
* of list elements used.
- *
- * No BH disabling for tx_lock here (like tg3)
*/
static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
{
@@ -1210,27 +1305,8 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
u16 mss;
u8 ctrl;
- /* No BH disabling for tx_lock here. We are running in BH disabled
- * context and TX reclaim runs via poll inside of a software
- * interrupt, and no related locks in IRQ processing.
- */
- if (!spin_trylock(&sky2->tx_lock))
- return NETDEV_TX_LOCKED;
-
- if (unlikely(tx_avail(sky2) < tx_le_req(skb))) {
- /* There is a known but harmless race with lockless tx
- * and netif_stop_queue.
- */
- if (!netif_queue_stopped(dev)) {
- netif_stop_queue(dev);
- if (net_ratelimit())
- printk(KERN_WARNING PFX "%s: ring full when queue awake!\n",
- dev->name);
- }
- spin_unlock(&sky2->tx_lock);
-
- return NETDEV_TX_BUSY;
- }
+ if (unlikely(tx_avail(sky2) < tx_le_req(skb)))
+ return NETDEV_TX_BUSY;
if (unlikely(netif_msg_tx_queued(sky2)))
printk(KERN_DEBUG "%s: tx queued, slot %u, len %d\n",
@@ -1240,13 +1316,10 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
mapping = pci_map_single(hw->pdev, skb->data, len, PCI_DMA_TODEVICE);
addr64 = high32(mapping);
- re = sky2->tx_ring + sky2->tx_prod;
-
/* Send high bits if changed or crosses boundary */
if (addr64 != sky2->tx_addr64 || high32(mapping + len) != sky2->tx_addr64) {
le = get_tx_le(sky2);
le->addr = cpu_to_le32(addr64);
- le->ctrl = 0;
le->opcode = OP_ADDR64 | HW_OWNER;
sky2->tx_addr64 = high32(mapping + len);
}
@@ -1262,7 +1335,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
le = get_tx_le(sky2);
le->addr = cpu_to_le32(mss);
le->opcode = OP_LRGLEN | HW_OWNER;
- le->ctrl = 0;
sky2->tx_last_mss = mss;
}
}
@@ -1275,7 +1347,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
le = get_tx_le(sky2);
le->addr = 0;
le->opcode = OP_VLAN|HW_OWNER;
- le->ctrl = 0;
} else
le->opcode |= OP_VLAN;
le->length = cpu_to_be16(vlan_tx_tag_get(skb));
@@ -1312,13 +1383,13 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
le->ctrl = ctrl;
le->opcode = mss ? (OP_LARGESEND | HW_OWNER) : (OP_PACKET | HW_OWNER);
- /* Record the transmit mapping info */
+ re = tx_le_re(sky2, le);
re->skb = skb;
pci_unmap_addr_set(re, mapaddr, mapping);
+ pci_unmap_len_set(re, maplen, len);
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
- struct tx_ring_info *fre;
+ const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
mapping = pci_map_page(hw->pdev, frag->page, frag->page_offset,
frag->size, PCI_DMA_TODEVICE);
@@ -1337,12 +1408,12 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
le->ctrl = ctrl;
le->opcode = OP_BUFFER | HW_OWNER;
- fre = sky2->tx_ring
- + RING_NEXT((re - sky2->tx_ring) + i, TX_RING_SIZE);
- pci_unmap_addr_set(fre, mapaddr, mapping);
+ re = tx_le_re(sky2, le);
+ re->skb = skb;
+ pci_unmap_addr_set(re, mapaddr, mapping);
+ pci_unmap_len_set(re, maplen, frag->size);
}
- re->idx = sky2->tx_prod;
le->ctrl |= EOP;
if (tx_avail(sky2) <= MAX_SKB_TX_LE)
@@ -1350,8 +1421,6 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
sky2_put_idx(hw, txqaddr[sky2->port], sky2->tx_prod);
- spin_unlock(&sky2->tx_lock);
-
dev->trans_start = jiffies;
return NETDEV_TX_OK;
}
@@ -1360,59 +1429,59 @@ static int sky2_xmit_frame(struct sk_buff *skb, struct net_device *dev)
* Free ring elements from starting at tx_cons until "done"
*
* NB: the hardware will tell us about partial completion of multi-part
- * buffers; these are deferred until completion.
+ * buffers so make sure not to free skb to early.
*/
static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
{
struct net_device *dev = sky2->netdev;
struct pci_dev *pdev = sky2->hw->pdev;
- u16 nxt, put;
- unsigned i;
+ unsigned idx;
BUG_ON(done >= TX_RING_SIZE);
- if (unlikely(netif_msg_tx_done(sky2)))
- printk(KERN_DEBUG "%s: tx done, up to %u\n",
- dev->name, done);
-
- for (put = sky2->tx_cons; put != done; put = nxt) {
- struct tx_ring_info *re = sky2->tx_ring + put;
- struct sk_buff *skb = re->skb;
-
- nxt = re->idx;
- BUG_ON(nxt >= TX_RING_SIZE);
- prefetch(sky2->tx_ring + nxt);
-
- /* Check for partial status */
- if (tx_dist(put, done) < tx_dist(put, nxt))
+ for (idx = sky2->tx_cons; idx != done;
+ idx = RING_NEXT(idx, TX_RING_SIZE)) {
+ struct sky2_tx_le *le = sky2->tx_le + idx;
+ struct tx_ring_info *re = sky2->tx_ring + idx;
+
+ switch(le->opcode & ~HW_OWNER) {
+ case OP_LARGESEND:
+ case OP_PACKET:
+ pci_unmap_single(pdev,
+ pci_unmap_addr(re, mapaddr),
+ pci_unmap_len(re, maplen),
+ PCI_DMA_TODEVICE);
break;
-
- skb = re->skb;
- pci_unmap_single(pdev, pci_unmap_addr(re, mapaddr),
- skb_headlen(skb), PCI_DMA_TODEVICE);
-
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- struct tx_ring_info *fre;
- fre = sky2->tx_ring + RING_NEXT(put + i, TX_RING_SIZE);
- pci_unmap_page(pdev, pci_unmap_addr(fre, mapaddr),
- skb_shinfo(skb)->frags[i].size,
+ case OP_BUFFER:
+ pci_unmap_page(pdev, pci_unmap_addr(re, mapaddr),
+ pci_unmap_len(re, maplen),
PCI_DMA_TODEVICE);
+ break;
+ }
+
+ if (le->ctrl & EOP) {
+ if (unlikely(netif_msg_tx_done(sky2)))
+ printk(KERN_DEBUG "%s: tx done %u\n",
+ dev->name, idx);
+ dev_kfree_skb(re->skb);
}
- dev_kfree_skb(skb);
+ le->opcode = 0; /* paranoia */
}
- sky2->tx_cons = put;
+ sky2->tx_cons = idx;
if (tx_avail(sky2) > MAX_SKB_TX_LE + 4)
netif_wake_queue(dev);
}
/* Cleanup all untransmitted buffers, assume transmitter not running */
-static void sky2_tx_clean(struct sky2_port *sky2)
+static void sky2_tx_clean(struct net_device *dev)
{
- spin_lock_bh(&sky2->tx_lock);
+ struct sky2_port *sky2 = netdev_priv(dev);
+
+ netif_tx_lock_bh(dev);
sky2_tx_complete(sky2, sky2->tx_prod);
- spin_unlock_bh(&sky2->tx_lock);
+ netif_tx_unlock_bh(dev);
}
/* Network shutdown */
@@ -1434,6 +1503,11 @@ static int sky2_down(struct net_device *dev)
/* Stop more packets from being queued */
netif_stop_queue(dev);
+ /* Disable port IRQ */
+ imask = sky2_read32(hw, B0_IMSK);
+ imask &= ~portirq_msk[port];
+ sky2_write32(hw, B0_IMSK, imask);
+
sky2_gmac_reset(hw, port);
/* Stop transmitter */
@@ -1443,6 +1517,13 @@ static int sky2_down(struct net_device *dev)
sky2_write32(hw, RB_ADDR(txqaddr[port], RB_CTRL),
RB_RST_SET | RB_DIS_OP_MD);
+ /* WA for dev. #4.209 */
+ if (hw->chip_id == CHIP_ID_YUKON_EC_U
+ && hw->chip_rev == CHIP_REV_YU_EC_U_A1)
+ sky2_write32(hw, SK_REG(port, TX_GMF_CTRL_T),
+ sky2->speed != SPEED_1000 ?
+ TX_STFW_ENA : TX_STFW_DIS);
+
ctrl = gma_read16(hw, port, GM_GP_CTRL);
ctrl &= ~(GM_GPCR_TX_ENA | GM_GPCR_RX_ENA);
gma_write16(hw, port, GM_GP_CTRL, ctrl);
@@ -1477,11 +1558,6 @@ static int sky2_down(struct net_device *dev)
sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
- /* Disable port IRQ */
- imask = sky2_read32(hw, B0_IMSK);
- imask &= ~portirq_msk[port];
- sky2_write32(hw, B0_IMSK, imask);
-
sky2_phy_power(hw, port, 0);
/* turn off LED's */
@@ -1489,7 +1565,7 @@ static int sky2_down(struct net_device *dev)
synchronize_irq(hw->pdev->irq);
- sky2_tx_clean(sky2);
+ sky2_tx_clean(dev);
sky2_rx_clean(sky2);
pci_free_consistent(hw->pdev, RX_LE_BYTES,
@@ -1533,6 +1609,12 @@ static void sky2_link_up(struct sky2_port *sky2)
struct sky2_hw *hw = sky2->hw;
unsigned port = sky2->port;
u16 reg;
+ static const char *fc_name[] = {
+ [FC_NONE] = "none",
+ [FC_TX] = "tx",
+ [FC_RX] = "rx",
+ [FC_BOTH] = "both",
+ };
/* enable Rx/Tx */
reg = gma_read16(hw, port, GM_GP_CTRL);
@@ -1576,8 +1658,7 @@ static void sky2_link_up(struct sky2_port *sky2)
"%s: Link is up at %d Mbps, %s duplex, flow control %s\n",
sky2->netdev->name, sky2->speed,
sky2->duplex == DUPLEX_FULL ? "full" : "half",
- (sky2->tx_pause && sky2->rx_pause) ? "both" :
- sky2->tx_pause ? "tx" : sky2->rx_pause ? "rx" : "none");
+ fc_name[sky2->flow_status]);
}
static void sky2_link_down(struct sky2_port *sky2)
@@ -1592,7 +1673,7 @@ static void sky2_link_down(struct sky2_port *sky2)
reg &= ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA);
gma_write16(hw, port, GM_GP_CTRL, reg);
- if (sky2->rx_pause && !sky2->tx_pause) {
+ if (sky2->flow_status == FC_RX) {
/* restore Asymmetric Pause bit */
gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
gm_phy_read(hw, port, PHY_MARV_AUNE_ADV)
@@ -1611,6 +1692,14 @@ static void sky2_link_down(struct sky2_port *sky2)
sky2_phy_init(hw, port);
}
+static enum flow_control sky2_flow(int rx, int tx)
+{
+ if (rx)
+ return tx ? FC_BOTH : FC_RX;
+ else
+ return tx ? FC_TX : FC_NONE;
+}
+
static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
{
struct sky2_hw *hw = sky2->hw;
@@ -1624,35 +1713,27 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
return -1;
}
- if (hw->chip_id != CHIP_ID_YUKON_FE &&
- gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
- printk(KERN_ERR PFX "%s: master/slave fault",
- sky2->netdev->name);
- return -1;
- }
-
if (!(aux & PHY_M_PS_SPDUP_RES)) {
printk(KERN_ERR PFX "%s: speed/duplex mismatch",
sky2->netdev->name);
return -1;
}
- sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
-
sky2->speed = sky2_phy_speed(hw, aux);
+ sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
/* Pause bits are offset (9..8) */
if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
aux >>= 6;
- sky2->rx_pause = (aux & PHY_M_PS_RX_P_EN) != 0;
- sky2->tx_pause = (aux & PHY_M_PS_TX_P_EN) != 0;
+ sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN,
+ aux & PHY_M_PS_TX_P_EN);
- if (sky2->duplex == DUPLEX_HALF && sky2->speed != SPEED_1000
+ if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
&& hw->chip_id != CHIP_ID_YUKON_EC_U)
- sky2->rx_pause = sky2->tx_pause = 0;
+ sky2->flow_status = FC_NONE;
- if (sky2->rx_pause || sky2->tx_pause)
+ if (aux & PHY_M_PS_RX_P_EN)
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
else
sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
@@ -1667,13 +1748,13 @@ static void sky2_phy_intr(struct sky2_hw *hw, unsigned port)
struct sky2_port *sky2 = netdev_priv(dev);
u16 istatus, phystat;
+ if (!netif_running(dev))
+ return;
+
spin_lock(&sky2->phy_lock);
istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
- if (!netif_running(dev))
- goto out;
-
if (netif_msg_intr(sky2))
printk(KERN_INFO PFX "%s: phy interrupt status 0x%x 0x%x\n",
sky2->netdev->name, istatus, phystat);
@@ -1730,31 +1811,22 @@ static void sky2_tx_timeout(struct net_device *dev)
} else if (report != sky2->tx_cons) {
printk(KERN_INFO PFX "status report lost?\n");
- spin_lock_bh(&sky2->tx_lock);
+ netif_tx_lock_bh(dev);
sky2_tx_complete(sky2, report);
- spin_unlock_bh(&sky2->tx_lock);
+ netif_tx_unlock_bh(dev);
} else {
printk(KERN_INFO PFX "hardware hung? flushing\n");
sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
- sky2_tx_clean(sky2);
+ sky2_tx_clean(dev);
sky2_qset(hw, txq);
sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
}
}
-
-/* Want receive buffer size to be multiple of 64 bits
- * and incl room for vlan and truncation
- */
-static inline unsigned sky2_buf_size(int mtu)
-{
- return ALIGN(mtu + ETH_HLEN + VLAN_HLEN, 8) + 8;
-}
-
static int sky2_change_mtu(struct net_device *dev, int new_mtu)
{
struct sky2_port *sky2 = netdev_priv(dev);
@@ -1789,7 +1861,7 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
sky2_rx_clean(sky2);
dev->mtu = new_mtu;
- sky2->rx_bufsize = sky2_buf_size(new_mtu);
+
mode = DATA_BLIND_VAL(DATA_BLIND_DEF) |
GM_SMOD_VLAN_ENA | IPG_DATA_VAL(IPG_DATA_DEF);
@@ -1815,16 +1887,100 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
return err;
}
+/* For small just reuse existing skb for next receive */
+static struct sk_buff *receive_copy(struct sky2_port *sky2,
+ const struct rx_ring_info *re,
+ unsigned length)
+{
+ struct sk_buff *skb;
+
+ skb = netdev_alloc_skb(sky2->netdev, length + 2);
+ if (likely(skb)) {
+ skb_reserve(skb, 2);
+ pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->data_addr,
+ length, PCI_DMA_FROMDEVICE);
+ memcpy(skb->data, re->skb->data, length);
+ skb->ip_summed = re->skb->ip_summed;
+ skb->csum = re->skb->csum;
+ pci_dma_sync_single_for_device(sky2->hw->pdev, re->data_addr,
+ length, PCI_DMA_FROMDEVICE);
+ re->skb->ip_summed = CHECKSUM_NONE;
+ skb_put(skb, length);
+ }
+ return skb;
+}
+
+/* Adjust length of skb with fragments to match received data */
+static void skb_put_frags(struct sk_buff *skb, unsigned int hdr_space,
+ unsigned int length)
+{
+ int i, num_frags;
+ unsigned int size;
+
+ /* put header into skb */
+ size = min(length, hdr_space);
+ skb->tail += size;
+ skb->len += size;
+ length -= size;
+
+ num_frags = skb_shinfo(skb)->nr_frags;
+ for (i = 0; i < num_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+ if (length == 0) {
+ /* don't need this page */
+ __free_page(frag->page);
+ --skb_shinfo(skb)->nr_frags;
+ } else {
+ size = min(length, (unsigned) PAGE_SIZE);
+
+ frag->size = size;
+ skb->data_len += size;
+ skb->truesize += size;
+ skb->len += size;
+ length -= size;
+ }
+ }
+}
+
+/* Normal packet - take skb from ring element and put in a new one */
+static struct sk_buff *receive_new(struct sky2_port *sky2,
+ struct rx_ring_info *re,
+ unsigned int length)
+{
+ struct sk_buff *skb, *nskb;
+ unsigned hdr_space = sky2->rx_data_size;
+
+ pr_debug(PFX "receive new length=%d\n", length);
+
+ /* Don't be tricky about reusing pages (yet) */
+ nskb = sky2_rx_alloc(sky2);
+ if (unlikely(!nskb))
+ return NULL;
+
+ skb = re->skb;
+ sky2_rx_unmap_skb(sky2->hw->pdev, re);
+
+ prefetch(skb->data);
+ re->skb = nskb;
+ sky2_rx_map_skb(sky2->hw->pdev, re, hdr_space);
+
+ if (skb_shinfo(skb)->nr_frags)
+ skb_put_frags(skb, hdr_space, length);
+ else
+ skb_put(skb, length);
+ return skb;
+}
+
/*
* Receive one packet.
- * For small packets or errors, just reuse existing skb.
* For larger packets, get new buffer.
*/
static struct sk_buff *sky2_receive(struct net_device *dev,
u16 length, u32 status)
{
struct sky2_port *sky2 = netdev_priv(dev);
- struct ring_info *re = sky2->rx_ring + sky2->rx_next;
+ struct rx_ring_info *re = sky2->rx_ring + sky2->rx_next;
struct sk_buff *skb = NULL;
if (unlikely(netif_msg_rx_status(sky2)))
@@ -1843,40 +1999,12 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
if (length > dev->mtu + ETH_HLEN)
goto oversize;
- if (length < copybreak) {
- skb = netdev_alloc_skb(dev, length + 2);
- if (!skb)
- goto resubmit;
-
- skb_reserve(skb, 2);
- pci_dma_sync_single_for_cpu(sky2->hw->pdev, re->mapaddr,
- length, PCI_DMA_FROMDEVICE);
- memcpy(skb->data, re->skb->data, length);
- skb->ip_summed = re->skb->ip_summed;
- skb->csum = re->skb->csum;
- pci_dma_sync_single_for_device(sky2->hw->pdev, re->mapaddr,
- length, PCI_DMA_FROMDEVICE);
- } else {
- struct sk_buff *nskb;
-
- nskb = sky2_alloc_skb(dev, sky2->rx_bufsize, GFP_ATOMIC);
- if (!nskb)
- goto resubmit;
-
- skb = re->skb;
- re->skb = nskb;
- pci_unmap_single(sky2->hw->pdev, re->mapaddr,
- sky2->rx_bufsize, PCI_DMA_FROMDEVICE);
- prefetch(skb->data);
-
- re->mapaddr = pci_map_single(sky2->hw->pdev, nskb->data,
- sky2->rx_bufsize, PCI_DMA_FROMDEVICE);
- }
-
- skb_put(skb, length);
+ if (length < copybreak)
+ skb = receive_copy(sky2, re, length);
+ else
+ skb = receive_new(sky2, re, length);
resubmit:
- re->skb->ip_summed = CHECKSUM_NONE;
- sky2_rx_add(sky2, re->mapaddr);
+ sky2_rx_submit(sky2, re);
return skb;
@@ -1886,6 +2014,10 @@ oversize:
error:
++sky2->net_stats.rx_errors;
+ if (status & GMR_FS_RX_FF_OV) {
+ sky2->net_stats.rx_fifo_errors++;
+ goto resubmit;
+ }
if (netif_msg_rx_err(sky2) && net_ratelimit())
printk(KERN_INFO PFX "%s: rx error, status 0x%x length %d\n",
@@ -1897,8 +2029,6 @@ error:
sky2->net_stats.rx_frame_errors++;
if (status & GMR_FS_CRC_ERR)
sky2->net_stats.rx_crc_errors++;
- if (status & GMR_FS_RX_FF_OV)
- sky2->net_stats.rx_fifo_errors++;
goto resubmit;
}
@@ -1909,9 +2039,9 @@ static inline void sky2_tx_done(struct net_device *dev, u16 last)
struct sky2_port *sky2 = netdev_priv(dev);
if (netif_running(dev)) {
- spin_lock(&sky2->tx_lock);
+ netif_tx_lock(dev);
sky2_tx_complete(sky2, last);
- spin_unlock(&sky2->tx_lock);
+ netif_tx_unlock(dev);
}
}
@@ -2082,7 +2212,7 @@ static void sky2_hw_intr(struct sky2_hw *hw)
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
sky2_pci_write16(hw, PCI_STATUS,
- pci_err | PCI_STATUS_ERROR_BITS);
+ pci_err | PCI_STATUS_ERROR_BITS);
sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
@@ -2228,7 +2358,7 @@ static int sky2_poll(struct net_device *dev0, int *budget)
}
}
-static irqreturn_t sky2_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sky2_intr(int irq, void *dev_id)
{
struct sky2_hw *hw = dev_id;
struct net_device *dev0 = hw->dev[0];
@@ -2618,7 +2748,7 @@ static int sky2_nway_reset(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
- if (sky2->autoneg != AUTONEG_ENABLE)
+ if (!netif_running(dev) || sky2->autoneg != AUTONEG_ENABLE)
return -EINVAL;
sky2_phy_reinit(sky2);
@@ -2720,6 +2850,14 @@ static int sky2_set_mac_address(struct net_device *dev, void *p)
return 0;
}
+static void inline sky2_add_filter(u8 filter[8], const u8 *addr)
+{
+ u32 bit;
+
+ bit = ether_crc(ETH_ALEN, addr) & 63;
+ filter[bit >> 3] |= 1 << (bit & 7);
+}
+
static void sky2_set_multicast(struct net_device *dev)
{
struct sky2_port *sky2 = netdev_priv(dev);
@@ -2728,7 +2866,10 @@ static void sky2_set_multicast(struct net_device *dev)
struct dev_mc_list *list = dev->mc_list;
u16 reg;
u8 filter[8];
+ int rx_pause;
+ static const u8 pause_mc_addr[ETH_ALEN] = { 0x1, 0x80, 0xc2, 0x0, 0x0, 0x1 };
+ rx_pause = (sky2->flow_status == FC_RX || sky2->flow_status == FC_BOTH);
memset(filter, 0, sizeof(filter));
reg = gma_read16(hw, port, GM_RX_CTRL);
@@ -2736,18 +2877,19 @@ static void sky2_set_multicast(struct net_device *dev)
if (dev->flags & IFF_PROMISC) /* promiscuous */
reg &= ~(GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
- else if ((dev->flags & IFF_ALLMULTI) || dev->mc_count > 16) /* all multicast */
+ else if (dev->flags & IFF_ALLMULTI)
memset(filter, 0xff, sizeof(filter));
- else if (dev->mc_count == 0) /* no multicast */
+ else if (dev->mc_count == 0 && !rx_pause)
reg &= ~GM_RXCR_MCF_ENA;
else {
int i;
reg |= GM_RXCR_MCF_ENA;
- for (i = 0; list && i < dev->mc_count; i++, list = list->next) {
- u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f;
- filter[bit / 8] |= 1 << (bit % 8);
- }
+ if (rx_pause)
+ sky2_add_filter(filter, pause_mc_addr);
+
+ for (i = 0; list && i < dev->mc_count; i++, list = list->next)
+ sky2_add_filter(filter, list->dmi_addr);
}
gma_write16(hw, port, GM_MC_ADDR_H1,
@@ -2860,8 +3002,20 @@ static void sky2_get_pauseparam(struct net_device *dev,
{
struct sky2_port *sky2 = netdev_priv(dev);
- ecmd->tx_pause = sky2->tx_pause;
- ecmd->rx_pause = sky2->rx_pause;
+ switch (sky2->flow_mode) {
+ case FC_NONE:
+ ecmd->tx_pause = ecmd->rx_pause = 0;
+ break;
+ case FC_TX:
+ ecmd->tx_pause = 1, ecmd->rx_pause = 0;
+ break;
+ case FC_RX:
+ ecmd->tx_pause = 0, ecmd->rx_pause = 1;
+ break;
+ case FC_BOTH:
+ ecmd->tx_pause = ecmd->rx_pause = 1;
+ }
+
ecmd->autoneg = sky2->autoneg;
}
@@ -2871,10 +3025,10 @@ static int sky2_set_pauseparam(struct net_device *dev,
struct sky2_port *sky2 = netdev_priv(dev);
sky2->autoneg = ecmd->autoneg;
- sky2->tx_pause = ecmd->tx_pause != 0;
- sky2->rx_pause = ecmd->rx_pause != 0;
+ sky2->flow_mode = sky2_flow(ecmd->rx_pause, ecmd->tx_pause);
- sky2_phy_reinit(sky2);
+ if (netif_running(dev))
+ sky2_phy_reinit(sky2);
return 0;
}
@@ -3102,11 +3256,10 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
sky2->hw = hw;
sky2->msg_enable = netif_msg_init(debug, default_msg);
- spin_lock_init(&sky2->tx_lock);
/* Auto speed and flow control */
sky2->autoneg = AUTONEG_ENABLE;
- sky2->tx_pause = 1;
- sky2->rx_pause = 1;
+ sky2->flow_mode = FC_BOTH;
+
sky2->duplex = -1;
sky2->speed = -1;
sky2->advertising = sky2_supported_modes(hw);
@@ -3115,13 +3268,11 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
spin_lock_init(&sky2->phy_lock);
sky2->tx_pending = TX_DEF_PENDING;
sky2->rx_pending = RX_DEF_PENDING;
- sky2->rx_bufsize = sky2_buf_size(ETH_DATA_LEN);
hw->dev[port] = dev;
sky2->port = port;
- dev->features |= NETIF_F_LLTX;
if (hw->chip_id != CHIP_ID_YUKON_EC_U)
dev->features |= NETIF_F_TSO;
if (highmem)
@@ -3157,8 +3308,7 @@ static void __devinit sky2_show_addr(struct net_device *dev)
}
/* Handle software interrupt used during MSI test */
-static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t __devinit sky2_test_intr(int irq, void *dev_id)
{
struct sky2_hw *hw = dev_id;
u32 status = sky2_read32(hw, B0_Y2_SP_ISRC2);
@@ -3200,9 +3350,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
if (!hw->msi_detected) {
/* MSI test failed, go back to INTx mode */
- printk(KERN_WARNING PFX "%s: No interrupt was generated using MSI, "
- "switching to INTx mode. Please report this failure to "
- "the PCI maintainer and include system chipset information.\n",
+ printk(KERN_INFO PFX "%s: No interrupt generated using MSI, "
+ "switching to INTx mode.\n",
pci_name(pdev));
err = -EOPNOTSUPP;
@@ -3210,6 +3359,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
}
sky2_write32(hw, B0_IMSK, 0);
+ sky2_read32(hw, B0_IMSK);
free_irq(pdev->irq, hw);
@@ -3316,6 +3466,14 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
if (!dev)
goto err_out_free_pci;
+ if (!disable_msi && pci_enable_msi(pdev) == 0) {
+ err = sky2_test_msi(hw);
+ if (err == -EOPNOTSUPP)
+ pci_disable_msi(pdev);
+ else if (err)
+ goto err_out_free_netdev;
+ }
+
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "%s: cannot register net device\n",
@@ -3323,6 +3481,14 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
goto err_out_free_netdev;
}
+ err = request_irq(pdev->irq, sky2_intr, IRQF_SHARED, dev->name, hw);
+ if (err) {
+ printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+ pci_name(pdev), pdev->irq);
+ goto err_out_unregister;
+ }
+ sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
+
sky2_show_addr(dev);
if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) {
@@ -3337,23 +3503,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
}
}
- if (!disable_msi && pci_enable_msi(pdev) == 0) {
- err = sky2_test_msi(hw);
- if (err == -EOPNOTSUPP)
- pci_disable_msi(pdev);
- else if (err)
- goto err_out_unregister;
- }
-
- err = request_irq(pdev->irq, sky2_intr, IRQF_SHARED, DRV_NAME, hw);
- if (err) {
- printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
- pci_name(pdev), pdev->irq);
- goto err_out_unregister;
- }
-
- sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
-
setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
sky2_idle_start(hw);
@@ -3363,10 +3512,6 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
err_out_unregister:
pci_disable_msi(pdev);
- if (dev1) {
- unregister_netdev(dev1);
- free_netdev(dev1);
- }
unregister_netdev(dev);
err_out_free_netdev:
free_netdev(dev);
diff --git a/drivers/net/sky2.h b/drivers/net/sky2.h
index 4c13c371bc21..6d2a23f66c9a 100644
--- a/drivers/net/sky2.h
+++ b/drivers/net/sky2.h
@@ -4,6 +4,8 @@
#ifndef _SKY2_H
#define _SKY2_H
+#define ETH_JUMBO_MTU 9000 /* Maximum MTU supported */
+
/* PCI config registers */
enum {
PCI_DEV_REG1 = 0x40,
@@ -1574,7 +1576,7 @@ enum {
GMR_FS_ANY_ERR = GMR_FS_RX_FF_OV | GMR_FS_CRC_ERR |
GMR_FS_FRAGMENT | GMR_FS_LONG_ERR |
- GMR_FS_MII_ERR | GMR_FS_BAD_FC |
+ GMR_FS_MII_ERR | GMR_FS_GOOD_FC | GMR_FS_BAD_FC |
GMR_FS_UN_SIZE | GMR_FS_JABBER,
};
@@ -1816,12 +1818,21 @@ struct sky2_status_le {
struct tx_ring_info {
struct sk_buff *skb;
DECLARE_PCI_UNMAP_ADDR(mapaddr);
- u16 idx;
+ DECLARE_PCI_UNMAP_ADDR(maplen);
};
-struct ring_info {
+struct rx_ring_info {
struct sk_buff *skb;
- dma_addr_t mapaddr;
+ dma_addr_t data_addr;
+ DECLARE_PCI_UNMAP_ADDR(data_size);
+ dma_addr_t frag_addr[ETH_JUMBO_MTU >> PAGE_SHIFT];
+};
+
+enum flow_control {
+ FC_NONE = 0,
+ FC_TX = 1,
+ FC_RX = 2,
+ FC_BOTH = 3,
};
struct sky2_port {
@@ -1831,7 +1842,6 @@ struct sky2_port {
u32 msg_enable;
spinlock_t phy_lock;
- spinlock_t tx_lock ____cacheline_aligned_in_smp;
struct tx_ring_info *tx_ring;
struct sky2_tx_le *tx_le;
u16 tx_cons; /* next le to check */
@@ -1841,13 +1851,15 @@ struct sky2_port {
u16 tx_last_mss;
u32 tx_tcpsum;
- struct ring_info *rx_ring ____cacheline_aligned_in_smp;
+ struct rx_ring_info *rx_ring ____cacheline_aligned_in_smp;
struct sky2_rx_le *rx_le;
u32 rx_addr64;
u16 rx_next; /* next re to check */
u16 rx_put; /* next le index to use */
u16 rx_pending;
- u16 rx_bufsize;
+ u16 rx_data_size;
+ u16 rx_nfrags;
+
#ifdef SKY2_VLAN_TAG_USED
u16 rx_tag;
struct vlan_group *vlgrp;
@@ -1855,13 +1867,13 @@ struct sky2_port {
dma_addr_t rx_le_map;
dma_addr_t tx_le_map;
- u32 advertising; /* ADVERTISED_ bits */
+ u16 advertising; /* ADVERTISED_ bits */
u16 speed; /* SPEED_1000, SPEED_100, ... */
u8 autoneg; /* AUTONEG_ENABLE, AUTONEG_DISABLE */
u8 duplex; /* DUPLEX_HALF, DUPLEX_FULL */
- u8 rx_pause;
- u8 tx_pause;
u8 rx_csum;
+ enum flow_control flow_mode;
+ enum flow_control flow_status;
struct net_device_stats net_stats;
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index 7986514883ac..889ef0d7c374 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -127,7 +127,7 @@ MODULE_DEVICE_TABLE(isapnp, ultra_device_ids);
static void ultra_poll(struct net_device *dev)
{
disable_irq(dev->irq);
- ei_interrupt(dev->irq, dev, NULL);
+ ei_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index a621b17456e5..2c4343395a4d 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -1074,7 +1074,7 @@ static void smc911x_phy_interrupt(struct net_device *dev)
* This is the main routine of the driver, to handle the device when
* it needs some attention.
*/
-static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t smc911x_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
unsigned long ioaddr = dev->base_addr;
@@ -1251,7 +1251,7 @@ static irqreturn_t smc911x_interrupt(int irq, void *dev_id, struct pt_regs *regs
#ifdef SMC_USE_DMA
static void
-smc911x_tx_dma_irq(int dma, void *data, struct pt_regs *regs)
+smc911x_tx_dma_irq(int dma, void *data)
{
struct net_device *dev = (struct net_device *)data;
struct smc911x_local *lp = netdev_priv(dev);
@@ -1285,7 +1285,7 @@ smc911x_tx_dma_irq(int dma, void *data, struct pt_regs *regs)
"%s: TX DMA irq completed\n", dev->name);
}
static void
-smc911x_rx_dma_irq(int dma, void *data, struct pt_regs *regs)
+smc911x_rx_dma_irq(int dma, void *data)
{
struct net_device *dev = (struct net_device *)data;
unsigned long ioaddr = dev->base_addr;
diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c
index 5506a0d3efe2..c0d13d650913 100644
--- a/drivers/net/smc9194.c
+++ b/drivers/net/smc9194.c
@@ -270,7 +270,7 @@ static void smc_set_multicast_list(struct net_device *dev);
/*
. Handles the actual interrupt
*/
-static irqreturn_t smc_interrupt(int irq, void *, struct pt_regs *regs);
+static irqreturn_t smc_interrupt(int irq, void *);
/*
. This is a separate procedure to handle the receipt of a packet, to
. leave the interrupt code looking slightly cleaner
@@ -1391,7 +1391,7 @@ static void smc_tx( struct net_device * dev )
.
---------------------------------------------------------------------*/
-static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+static irqreturn_t smc_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
int ioaddr = dev->base_addr;
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index d7e56438b5d6..95b6478f55c6 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -1284,7 +1284,7 @@ static void smc_eph_interrupt(struct net_device *dev)
* This is the main routine of the driver, to handle the device when
* it needs some attention.
*/
-static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t smc_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct smc_local *lp = netdev_priv(dev);
@@ -1400,7 +1400,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static void smc_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- smc_interrupt(dev->irq, dev, NULL);
+ smc_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 7aa7fbac8224..0c9f1e7dab2e 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -195,6 +195,7 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_IRQ_FLAGS (( \
machine_is_omap_h2() \
|| machine_is_omap_h3() \
+ || machine_is_omap_h4() \
|| (machine_is_omap_innovator() && !cpu_is_omap1510()) \
) ? IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING)
@@ -379,6 +380,42 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
#define SMC_IRQ_FLAGS (0)
+#elif defined(CONFIG_ARCH_VERSATILE)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS (0)
+
+#elif defined(CONFIG_ARCH_VERSATILE)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+
+#define SMC_IRQ_FLAGS (0)
+
#else
#define SMC_CAN_USE_8BIT 1
@@ -488,7 +525,7 @@ smc_pxa_dma_insw(void __iomem *ioaddr, u_long physaddr, int reg, int dma,
#endif
static void
-smc_pxa_dma_irq(int dma, void *dummy, struct pt_regs *regs)
+smc_pxa_dma_irq(int dma, void *dummy)
{
DCSR(dma) = 0;
}
diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c
index 870cf6b07389..ed7aa0a5acca 100644
--- a/drivers/net/sonic.c
+++ b/drivers/net/sonic.c
@@ -293,17 +293,12 @@ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
-static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sonic_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
+ struct net_device *dev = dev_id;
struct sonic_local *lp = netdev_priv(dev);
int status;
- if (dev == NULL) {
- printk(KERN_ERR "sonic_interrupt: irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT))
return IRQ_NONE;
diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h
index 7f886e8ae28f..7db13e4a7ea5 100644
--- a/drivers/net/sonic.h
+++ b/drivers/net/sonic.h
@@ -328,7 +328,7 @@ struct sonic_local {
static int sonic_open(struct net_device *dev);
static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t sonic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t sonic_interrupt(int irq, void *dev_id);
static void sonic_rx(struct net_device *dev);
static int sonic_close(struct net_device *dev);
static struct net_device_stats *sonic_get_stats(struct net_device *dev);
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index cc240adb7269..418138dd6c68 100644
--- a/drivers/net/spider_net.c
+++ b/drivers/net/spider_net.c
@@ -55,12 +55,13 @@ MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com> and Jens Osterkamp " \
"<Jens.Osterkamp@de.ibm.com>");
MODULE_DESCRIPTION("Spider Southbridge Gigabit Ethernet driver");
MODULE_LICENSE("GPL");
+MODULE_VERSION(VERSION);
static int rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_DEFAULT;
static int tx_descriptors = SPIDER_NET_TX_DESCRIPTORS_DEFAULT;
-module_param(rx_descriptors, int, 0644);
-module_param(tx_descriptors, int, 0644);
+module_param(rx_descriptors, int, 0444);
+module_param(tx_descriptors, int, 0444);
MODULE_PARM_DESC(rx_descriptors, "number of descriptors used " \
"in rx chains");
@@ -300,7 +301,7 @@ static int
spider_net_init_chain(struct spider_net_card *card,
struct spider_net_descr_chain *chain,
struct spider_net_descr *start_descr,
- int direction, int no)
+ int no)
{
int i;
struct spider_net_descr *descr;
@@ -315,9 +316,9 @@ spider_net_init_chain(struct spider_net_card *card,
buf = pci_map_single(card->pdev, descr,
SPIDER_NET_DESCR_SIZE,
- direction);
+ PCI_DMA_BIDIRECTIONAL);
- if (buf == DMA_ERROR_CODE)
+ if (pci_dma_mapping_error(buf))
goto iommu_error;
descr->bus_addr = buf;
@@ -329,11 +330,6 @@ spider_net_init_chain(struct spider_net_card *card,
(descr-1)->next = start_descr;
start_descr->prev = descr-1;
- descr = start_descr;
- if (direction == PCI_DMA_FROMDEVICE)
- for (i=0; i < no; i++, descr++)
- descr->next_descr_addr = descr->next->bus_addr;
-
spin_lock_init(&chain->lock);
chain->head = start_descr;
chain->tail = start_descr;
@@ -346,7 +342,7 @@ iommu_error:
if (descr->bus_addr)
pci_unmap_single(card->pdev, descr->bus_addr,
SPIDER_NET_DESCR_SIZE,
- direction);
+ PCI_DMA_BIDIRECTIONAL);
return -ENOMEM;
}
@@ -362,15 +358,15 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
struct spider_net_descr *descr;
descr = card->rx_chain.head;
- while (descr->next != card->rx_chain.head) {
+ do {
if (descr->skb) {
dev_kfree_skb(descr->skb);
pci_unmap_single(card->pdev, descr->buf_addr,
SPIDER_NET_MAX_FRAME,
- PCI_DMA_FROMDEVICE);
+ PCI_DMA_BIDIRECTIONAL);
}
descr = descr->next;
- }
+ } while (descr != card->rx_chain.head);
}
/**
@@ -420,7 +416,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
buf = pci_map_single(card->pdev, descr->skb->data,
SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
descr->buf_addr = buf;
- if (buf == DMA_ERROR_CODE) {
+ if (pci_dma_mapping_error(buf)) {
dev_kfree_skb_any(descr->skb);
if (netif_msg_rx_err(card) && net_ratelimit())
pr_err("Could not iommu-map rx buffer\n");
@@ -645,26 +641,41 @@ static int
spider_net_prepare_tx_descr(struct spider_net_card *card,
struct sk_buff *skb)
{
- struct spider_net_descr *descr = card->tx_chain.head;
+ struct spider_net_descr *descr;
dma_addr_t buf;
+ unsigned long flags;
+ int length;
- buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
- if (buf == DMA_ERROR_CODE) {
+ length = skb->len;
+ if (length < ETH_ZLEN) {
+ if (skb_pad(skb, ETH_ZLEN-length))
+ return 0;
+ length = ETH_ZLEN;
+ }
+
+ buf = pci_map_single(card->pdev, skb->data, length, PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(buf)) {
if (netif_msg_tx_err(card) && net_ratelimit())
pr_err("could not iommu-map packet (%p, %i). "
- "Dropping packet\n", skb->data, skb->len);
+ "Dropping packet\n", skb->data, length);
card->spider_stats.tx_iommu_map_error++;
return -ENOMEM;
}
+ spin_lock_irqsave(&card->tx_chain.lock, flags);
+ descr = card->tx_chain.head;
+ card->tx_chain.head = descr->next;
+
descr->buf_addr = buf;
- descr->buf_size = skb->len;
+ descr->buf_size = length;
descr->next_descr_addr = 0;
descr->skb = skb;
descr->data_status = 0;
descr->dmac_cmd_status =
SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
+ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+
if (skb->protocol == htons(ETH_P_IP))
switch (skb->nh.iph->protocol) {
case IPPROTO_TCP:
@@ -675,32 +686,51 @@ spider_net_prepare_tx_descr(struct spider_net_card *card,
break;
}
+ /* Chain the bus address, so that the DMA engine finds this descr. */
descr->prev->next_descr_addr = descr->bus_addr;
+ card->netdev->trans_start = jiffies; /* set netdev watchdog timer */
return 0;
}
-/**
- * spider_net_release_tx_descr - processes a used tx descriptor
- * @card: card structure
- * @descr: descriptor to release
- *
- * releases a used tx descriptor (unmapping, freeing of skb)
- */
-static inline void
-spider_net_release_tx_descr(struct spider_net_card *card)
+static int
+spider_net_set_low_watermark(struct spider_net_card *card)
{
+ unsigned long flags;
+ int status;
+ int cnt=0;
+ int i;
struct spider_net_descr *descr = card->tx_chain.tail;
- struct sk_buff *skb;
- card->tx_chain.tail = card->tx_chain.tail->next;
- descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+ /* Measure the length of the queue. Measurement does not
+ * need to be precise -- does not need a lock. */
+ while (descr != card->tx_chain.head) {
+ status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
+ if (status == SPIDER_NET_DESCR_NOT_IN_USE)
+ break;
+ descr = descr->next;
+ cnt++;
+ }
- /* unmap the skb */
- skb = descr->skb;
- pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb_any(skb);
+ /* If TX queue is short, don't even bother with interrupts */
+ if (cnt < card->num_tx_desc/4)
+ return cnt;
+
+ /* Set low-watermark 3/4th's of the way into the queue. */
+ descr = card->tx_chain.tail;
+ cnt = (cnt*3)/4;
+ for (i=0;i<cnt; i++)
+ descr = descr->next;
+
+ /* Set the new watermark, clear the old watermark */
+ spin_lock_irqsave(&card->tx_chain.lock, flags);
+ descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
+ if (card->low_watermark && card->low_watermark != descr)
+ card->low_watermark->dmac_cmd_status =
+ card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
+ card->low_watermark = descr;
+ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+ return cnt;
}
/**
@@ -719,21 +749,29 @@ static int
spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
{
struct spider_net_descr_chain *chain = &card->tx_chain;
+ struct spider_net_descr *descr;
+ struct sk_buff *skb;
+ u32 buf_addr;
+ unsigned long flags;
int status;
- spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR);
-
while (chain->tail != chain->head) {
- status = spider_net_get_descr_status(chain->tail);
+ spin_lock_irqsave(&chain->lock, flags);
+ descr = chain->tail;
+
+ status = spider_net_get_descr_status(descr);
switch (status) {
case SPIDER_NET_DESCR_COMPLETE:
card->netdev_stats.tx_packets++;
- card->netdev_stats.tx_bytes += chain->tail->skb->len;
+ card->netdev_stats.tx_bytes += descr->skb->len;
break;
case SPIDER_NET_DESCR_CARDOWNED:
- if (!brutal)
+ if (!brutal) {
+ spin_unlock_irqrestore(&chain->lock, flags);
return 1;
+ }
+
/* fallthrough, if we release the descriptors
* brutally (then we don't care about
* SPIDER_NET_DESCR_CARDOWNED) */
@@ -750,11 +788,25 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
default:
card->netdev_stats.tx_dropped++;
- return 1;
+ if (!brutal) {
+ spin_unlock_irqrestore(&chain->lock, flags);
+ return 1;
+ }
}
- spider_net_release_tx_descr(card);
- }
+ chain->tail = descr->next;
+ descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+ skb = descr->skb;
+ buf_addr = descr->buf_addr;
+ spin_unlock_irqrestore(&chain->lock, flags);
+
+ /* unmap the skb */
+ if (skb) {
+ int len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+ pci_unmap_single(card->pdev, buf_addr, len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+ }
+ }
return 0;
}
@@ -763,8 +815,12 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
* @card: card structure
* @descr: descriptor address to enable TX processing at
*
- * spider_net_kick_tx_dma writes the current tx chain head as start address
- * of the tx descriptor chain and enables the transmission DMA engine
+ * This routine will start the transmit DMA running if
+ * it is not already running. This routine ned only be
+ * called when queueing a new packet to an empty tx queue.
+ * Writes the current tx chain head as start address
+ * of the tx descriptor chain and enables the transmission
+ * DMA engine.
*/
static inline void
spider_net_kick_tx_dma(struct spider_net_card *card)
@@ -804,65 +860,43 @@ out:
static int
spider_net_xmit(struct sk_buff *skb, struct net_device *netdev)
{
+ int cnt;
struct spider_net_card *card = netdev_priv(netdev);
struct spider_net_descr_chain *chain = &card->tx_chain;
- struct spider_net_descr *descr = chain->head;
- unsigned long flags;
- int result;
-
- spin_lock_irqsave(&chain->lock, flags);
spider_net_release_tx_chain(card, 0);
- if (chain->head->next == chain->tail->prev) {
- card->netdev_stats.tx_dropped++;
- result = NETDEV_TX_LOCKED;
- goto out;
- }
+ if ((chain->head->next == chain->tail->prev) ||
+ (spider_net_prepare_tx_descr(card, skb) != 0)) {
- if (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) {
card->netdev_stats.tx_dropped++;
- result = NETDEV_TX_LOCKED;
- goto out;
+ netif_stop_queue(netdev);
+ return NETDEV_TX_BUSY;
}
- if (spider_net_prepare_tx_descr(card, skb) != 0) {
- card->netdev_stats.tx_dropped++;
- result = NETDEV_TX_BUSY;
- goto out;
- }
-
- result = NETDEV_TX_OK;
-
- spider_net_kick_tx_dma(card);
- card->tx_chain.head = card->tx_chain.head->next;
-
-out:
- spin_unlock_irqrestore(&chain->lock, flags);
- netif_wake_queue(netdev);
- return result;
+ cnt = spider_net_set_low_watermark(card);
+ if (cnt < 5)
+ spider_net_kick_tx_dma(card);
+ return NETDEV_TX_OK;
}
/**
* spider_net_cleanup_tx_ring - cleans up the TX ring
* @card: card structure
*
- * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use
- * interrupts to cleanup our TX ring) and returns sent packets to the stack
- * by freeing them
+ * spider_net_cleanup_tx_ring is called by either the tx_timer
+ * or from the NAPI polling routine.
+ * This routine releases resources associted with transmitted
+ * packets, including updating the queue tail pointer.
*/
static void
spider_net_cleanup_tx_ring(struct spider_net_card *card)
{
- unsigned long flags;
-
- spin_lock_irqsave(&card->tx_chain.lock, flags);
-
if ((spider_net_release_tx_chain(card, 0) != 0) &&
- (card->netdev->flags & IFF_UP))
+ (card->netdev->flags & IFF_UP)) {
spider_net_kick_tx_dma(card);
-
- spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+ netif_wake_queue(card->netdev);
+ }
}
/**
@@ -1053,6 +1087,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
int packets_to_do, packets_done = 0;
int no_more_packets = 0;
+ spider_net_cleanup_tx_ring(card);
packets_to_do = min(*budget, netdev->quota);
while (packets_to_do) {
@@ -1243,12 +1278,15 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_PHYINT:
case SPIDER_NET_GMAC2INT:
case SPIDER_NET_GMAC1INT:
- case SPIDER_NET_GIPSINT:
case SPIDER_NET_GFIFOINT:
case SPIDER_NET_DMACINT:
case SPIDER_NET_GSYSINT:
break; */
+ case SPIDER_NET_GIPSINT:
+ show_error = 0;
+ break;
+
case SPIDER_NET_GPWOPCMPINT:
/* PHY write operation completed */
show_error = 0;
@@ -1307,9 +1345,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
case SPIDER_NET_GDTDCEINT:
/* chain end. If a descriptor should be sent, kick off
* tx dma
- if (card->tx_chain.tail == card->tx_chain.head)
+ if (card->tx_chain.tail != card->tx_chain.head)
spider_net_kick_tx_dma(card);
- show_error = 0; */
+ */
+ show_error = 0;
break;
/* case SPIDER_NET_G1TMCNTINT: not used. print a message */
@@ -1354,7 +1393,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
if (netif_msg_intr(card))
pr_err("got descriptor chain end interrupt, "
"restarting DMAC %c.\n",
- 'D'+i-SPIDER_NET_GDDDCEINT);
+ 'D'-(i-SPIDER_NET_GDDDCEINT)/3);
spider_net_refill_rx_chain(card);
spider_net_enable_rxdmac(card);
show_error = 0;
@@ -1423,8 +1462,9 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
}
if ((show_error) && (netif_msg_intr(card)))
- pr_err("Got error interrupt, GHIINT0STS = 0x%08x, "
+ pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
"GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
+ card->netdev->name,
status_reg, error_reg1, error_reg2);
/* clear interrupt sources */
@@ -1445,7 +1485,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
* interrupts for this device and makes the stack poll the driver
*/
static irqreturn_t
-spider_net_interrupt(int irq, void *ptr, struct pt_regs *regs)
+spider_net_interrupt(int irq, void *ptr)
{
struct net_device *netdev = ptr;
struct spider_net_card *card = netdev_priv(netdev);
@@ -1460,6 +1500,8 @@ spider_net_interrupt(int irq, void *ptr, struct pt_regs *regs)
spider_net_rx_irq_off(card);
netif_rx_schedule(netdev);
}
+ if (status_reg & SPIDER_NET_TXINT)
+ netif_rx_schedule(netdev);
if (status_reg & SPIDER_NET_ERRINT )
spider_net_handle_error_irq(card, status_reg);
@@ -1481,7 +1523,7 @@ static void
spider_net_poll_controller(struct net_device *netdev)
{
disable_irq(netdev->irq);
- spider_net_interrupt(netdev->irq, netdev, NULL);
+ spider_net_interrupt(netdev->irq, netdev);
enable_irq(netdev->irq);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
@@ -1599,7 +1641,7 @@ spider_net_enable_card(struct spider_net_card *card)
SPIDER_NET_INT2_MASK_VALUE);
spider_net_write_reg(card, SPIDER_NET_GDTDMACCNTR,
- SPIDER_NET_GDTDCEIDIS);
+ SPIDER_NET_GDTBSTA | SPIDER_NET_GDTDCEIDIS);
}
/**
@@ -1615,17 +1657,26 @@ int
spider_net_open(struct net_device *netdev)
{
struct spider_net_card *card = netdev_priv(netdev);
- int result;
+ struct spider_net_descr *descr;
+ int i, result;
result = -ENOMEM;
if (spider_net_init_chain(card, &card->tx_chain, card->descr,
- PCI_DMA_TODEVICE, card->tx_desc))
+ card->num_tx_desc))
goto alloc_tx_failed;
+
+ card->low_watermark = NULL;
+
+ /* rx_chain is after tx_chain, so offset is descr + tx_count */
if (spider_net_init_chain(card, &card->rx_chain,
- card->descr + card->rx_desc,
- PCI_DMA_FROMDEVICE, card->rx_desc))
+ card->descr + card->num_tx_desc,
+ card->num_rx_desc))
goto alloc_rx_failed;
+ descr = card->rx_chain.head;
+ for (i=0; i < card->num_rx_desc; i++, descr++)
+ descr->next_descr_addr = descr->next->bus_addr;
+
/* allocate rx skbs */
if (spider_net_alloc_rx_skbs(card))
goto alloc_skbs_failed;
@@ -1878,10 +1929,7 @@ spider_net_stop(struct net_device *netdev)
spider_net_disable_rxdmac(card);
/* release chains */
- if (spin_trylock(&card->tx_chain.lock)) {
- spider_net_release_tx_chain(card, 1);
- spin_unlock(&card->tx_chain.lock);
- }
+ spider_net_release_tx_chain(card, 1);
spider_net_free_chain(card, &card->tx_chain);
spider_net_free_chain(card, &card->rx_chain);
@@ -2012,8 +2060,8 @@ spider_net_setup_netdev(struct spider_net_card *card)
card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
- card->tx_desc = tx_descriptors;
- card->rx_desc = rx_descriptors;
+ card->num_tx_desc = tx_descriptors;
+ card->num_rx_desc = rx_descriptors;
spider_net_setup_netdev_ops(netdev);
@@ -2252,6 +2300,8 @@ static struct pci_driver spider_net_driver = {
*/
static int __init spider_net_init(void)
{
+ printk(KERN_INFO "Spidernet version %s.\n", VERSION);
+
if (rx_descriptors < SPIDER_NET_RX_DESCRIPTORS_MIN) {
rx_descriptors = SPIDER_NET_RX_DESCRIPTORS_MIN;
pr_info("adjusting rx descriptors to %i.\n", rx_descriptors);
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h
index a59deda2f95e..b3b46119b424 100644
--- a/drivers/net/spider_net.h
+++ b/drivers/net/spider_net.h
@@ -24,6 +24,8 @@
#ifndef _SPIDER_NET_H
#define _SPIDER_NET_H
+#define VERSION "1.1 A"
+
#include "sungem_phy.h"
extern int spider_net_stop(struct net_device *netdev);
@@ -47,7 +49,7 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_TX_DESCRIPTORS_MIN 16
#define SPIDER_NET_TX_DESCRIPTORS_MAX 512
-#define SPIDER_NET_TX_TIMER 20
+#define SPIDER_NET_TX_TIMER (HZ/5)
#define SPIDER_NET_RX_CSUM_DEFAULT 1
@@ -189,7 +191,9 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_MACMODE_VALUE 0x00000001
#define SPIDER_NET_BURSTLMT_VALUE 0x00000200 /* about 16 us */
-/* 1(0) enable r/tx dma
+/* DMAC control register GDMACCNTR
+ *
+ * 1(0) enable r/tx dma
* 0000000 fixed to 0
*
* 000000 fixed to 0
@@ -198,6 +202,7 @@ extern char spider_net_driver_name[];
*
* 000000 fixed to 0
* 00 burst alignment: 128 bytes
+ * 11 burst alignment: 1024 bytes
*
* 00000 fixed to 0
* 0 descr writeback size 32 bytes
@@ -208,10 +213,13 @@ extern char spider_net_driver_name[];
#define SPIDER_NET_DMA_RX_VALUE 0x80000000
#define SPIDER_NET_DMA_RX_FEND_VALUE 0x00030003
/* to set TX_DMA_EN */
-#define SPIDER_NET_TX_DMA_EN 0x80000000
-#define SPIDER_NET_GDTDCEIDIS 0x00000002
-#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \
- SPIDER_NET_GDTDCEIDIS
+#define SPIDER_NET_TX_DMA_EN 0x80000000
+#define SPIDER_NET_GDTBSTA 0x00000300
+#define SPIDER_NET_GDTDCEIDIS 0x00000002
+#define SPIDER_NET_DMA_TX_VALUE SPIDER_NET_TX_DMA_EN | \
+ SPIDER_NET_GDTBSTA | \
+ SPIDER_NET_GDTDCEIDIS
+
#define SPIDER_NET_DMA_TX_FEND_VALUE 0x00030003
/* SPIDER_NET_UA_DESCR_VALUE is OR'ed with the unicast address */
@@ -320,13 +328,10 @@ enum spider_net_int2_status {
SPIDER_NET_GRISPDNGINT
};
-#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GTTEDINT) | \
- (1 << SPIDER_NET_GDTDCEINT) | \
- (1 << SPIDER_NET_GDTFDCINT) )
+#define SPIDER_NET_TXINT ( (1 << SPIDER_NET_GDTFDCINT) )
-/* we rely on flagged descriptor interrupts*/
-#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) | \
- (1 << SPIDER_NET_GRMFLLINT) )
+/* We rely on flagged descriptor interrupts */
+#define SPIDER_NET_RXINT ( (1 << SPIDER_NET_GDAFDCINT) )
#define SPIDER_NET_ERRINT ( 0xffffffff & \
(~SPIDER_NET_TXINT) & \
@@ -349,6 +354,7 @@ enum spider_net_int2_status {
#define SPIDER_NET_DESCR_FORCE_END 0x50000000 /* used in rx and tx */
#define SPIDER_NET_DESCR_CARDOWNED 0xA0000000 /* used in rx and tx */
#define SPIDER_NET_DESCR_NOT_IN_USE 0xF0000000
+#define SPIDER_NET_DESCR_TXDESFLG 0x00800000
struct spider_net_descr {
/* as defined by the hardware */
@@ -433,6 +439,7 @@ struct spider_net_card {
struct spider_net_descr_chain tx_chain;
struct spider_net_descr_chain rx_chain;
+ struct spider_net_descr *low_watermark;
struct net_device_stats netdev_stats;
@@ -448,8 +455,8 @@ struct spider_net_card {
/* for ethtool */
int msg_enable;
- int rx_desc;
- int tx_desc;
+ int num_rx_desc;
+ int num_tx_desc;
struct spider_net_extra_stats spider_stats;
struct spider_net_descr descr[0];
diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c
index 589e43658dee..91b995102915 100644
--- a/drivers/net/spider_net_ethtool.c
+++ b/drivers/net/spider_net_ethtool.c
@@ -76,7 +76,7 @@ spider_net_ethtool_get_drvinfo(struct net_device *netdev,
/* clear and fill out info */
memset(drvinfo, 0, sizeof(struct ethtool_drvinfo));
strncpy(drvinfo->driver, spider_net_driver_name, 32);
- strncpy(drvinfo->version, "0.1", 32);
+ strncpy(drvinfo->version, VERSION, 32);
strcpy(drvinfo->fw_version, "no information");
strncpy(drvinfo->bus_info, pci_name(card->pdev), 32);
}
@@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev,
struct spider_net_card *card = netdev->priv;
ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
- ering->tx_pending = card->tx_desc;
+ ering->tx_pending = card->num_tx_desc;
ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
- ering->rx_pending = card->rx_desc;
+ ering->rx_pending = card->num_rx_desc;
}
static int spider_net_get_stats_count(struct net_device *netdev)
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 3d617e8f54b5..7a0aee6c869d 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -632,7 +632,7 @@ static void check_duplex(struct net_device *dev);
static void tx_timeout(struct net_device *dev);
static void init_ring(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
static void netdev_error(struct net_device *dev, int intr_status);
static int __netdev_rx(struct net_device *dev, int *quota);
static void refill_rx_ring(struct net_device *dev);
@@ -1307,7 +1307,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t intr_handler(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct netdev_private *np = netdev_priv(dev);
diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c
index 3fd7a4fee665..e6f90427160c 100644
--- a/drivers/net/stnic.c
+++ b/drivers/net/stnic.c
@@ -19,7 +19,7 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <asm/se/se.h>
+#include <asm/se.h>
#include <asm/machvec.h>
#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c
index 0605461bc56d..a3220a96524f 100644
--- a/drivers/net/sun3_82586.c
+++ b/drivers/net/sun3_82586.c
@@ -122,7 +122,7 @@ sizeof(nop_cmd) = 8;
DELAY_16(); DELAY_16(); } }
static int sun3_82586_probe1(struct net_device *dev,int ioaddr);
-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr);
+static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id);
static int sun3_82586_open(struct net_device *dev);
static int sun3_82586_close(struct net_device *dev);
static int sun3_82586_send_packet(struct sk_buff *,struct net_device *);
@@ -330,7 +330,7 @@ out2:
out1:
free_netdev(dev);
out:
- iounmap((void *)ioaddr);
+ iounmap((void __iomem *)ioaddr);
return ERR_PTR(err);
}
@@ -678,7 +678,7 @@ static void *alloc_rfa(struct net_device *dev,void *ptr)
* Interrupt Handler ...
*/
-static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id,struct pt_regs *reg_ptr)
+static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id)
{
struct net_device *dev = dev_id;
unsigned short stat;
diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c
index 61a832ce7ccf..b865db363ba0 100644
--- a/drivers/net/sun3lance.c
+++ b/drivers/net/sun3lance.c
@@ -237,7 +237,7 @@ static int lance_probe( struct net_device *dev);
static int lance_open( struct net_device *dev );
static void lance_init_ring( struct net_device *dev );
static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev );
-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp );
+static irqreturn_t lance_interrupt( int irq, void *dev_id);
static int lance_rx( struct net_device *dev );
static int lance_close( struct net_device *dev );
static struct net_device_stats *lance_get_stats( struct net_device *dev );
@@ -286,7 +286,7 @@ struct net_device * __init sun3lance_probe(int unit)
out1:
#ifdef CONFIG_SUN3
- iounmap((void *)dev->base_addr);
+ iounmap((void __iomem *)dev->base_addr);
#endif
out:
free_netdev(dev);
@@ -326,7 +326,7 @@ static int __init lance_probe( struct net_device *dev)
ioaddr_probe[1] = tmp2;
#ifdef CONFIG_SUN3
- iounmap((void *)ioaddr);
+ iounmap((void __iomem *)ioaddr);
#endif
return 0;
}
@@ -642,7 +642,7 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev )
/* The LANCE interrupt handler. */
-static irqreturn_t lance_interrupt( int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t lance_interrupt( int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct lance_private *lp = netdev_priv(dev);
@@ -956,7 +956,7 @@ void cleanup_module(void)
{
unregister_netdev(sun3lance_dev);
#ifdef CONFIG_SUN3
- iounmap((void *)sun3lance_dev->base_addr);
+ iounmap((void __iomem *)sun3lance_dev->base_addr);
#endif
free_netdev(sun3lance_dev);
}
diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c
index 9e4be86495a0..18f88853e1e5 100644
--- a/drivers/net/sunbmac.c
+++ b/drivers/net/sunbmac.c
@@ -42,7 +42,7 @@
#define DRV_RELDATE "11/24/03"
#define DRV_AUTHOR "David S. Miller (davem@redhat.com)"
-static char version[] __initdata =
+static char version[] =
DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
MODULE_VERSION(DRV_VERSION);
@@ -888,7 +888,7 @@ static void bigmac_rx(struct bigmac *bp)
printk(KERN_NOTICE "%s: Memory squeeze, deferring packet.\n", bp->dev->name);
}
-static irqreturn_t bigmac_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bigmac_interrupt(int irq, void *dev_id)
{
struct bigmac *bp = (struct bigmac *) dev_id;
u32 qec_status, bmac_status;
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 6b8f4baf87fd..41c503d8bac4 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -420,7 +420,7 @@ static void tx_timeout(struct net_device *dev);
static void init_ring(struct net_device *dev);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
static int reset_tx (struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
static void rx_poll(unsigned long data);
static void tx_poll(unsigned long data);
static void refill_rx (struct net_device *dev);
@@ -1102,7 +1102,7 @@ reset_tx (struct net_device *dev)
/* The interrupt handler cleans up after the Tx thread,
and schedule a Rx thread work */
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t intr_handler(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *)dev_instance;
struct netdev_private *np = netdev_priv(dev);
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 0975695ae31b..253e96e7ad20 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -932,7 +932,7 @@ static int gem_poll(struct net_device *dev, int *budget)
return 0;
}
-static irqreturn_t gem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t gem_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct gem *gp = dev->priv;
@@ -975,7 +975,7 @@ static void gem_poll_controller(struct net_device *dev)
/* gem_interrupt is safe to reentrance so no need
* to disable_irq here.
*/
- gem_interrupt(dev->irq, dev, NULL);
+ gem_interrupt(dev->irq, dev);
}
#endif
diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c
index f05eea53623b..9d7cd130c19d 100644
--- a/drivers/net/sunhme.c
+++ b/drivers/net/sunhme.c
@@ -2093,10 +2093,10 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev)
RXD((">"));
}
-static irqreturn_t happy_meal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t happy_meal_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *) dev_id;
- struct happy_meal *hp = dev->priv;
+ struct net_device *dev = dev_id;
+ struct happy_meal *hp = netdev_priv(dev);
u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT);
HMD(("happy_meal_interrupt: status=%08x ", happy_status));
@@ -2132,7 +2132,7 @@ out:
}
#ifdef CONFIG_SBUS
-static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie, struct pt_regs *ptregs)
+static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie)
{
struct quattro *qp = (struct quattro *) cookie;
int i;
diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c
index feb42db10ee1..5b00d79b5573 100644
--- a/drivers/net/sunlance.c
+++ b/drivers/net/sunlance.c
@@ -820,9 +820,9 @@ out:
spin_unlock(&lp->lock);
}
-static irqreturn_t lance_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t lance_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct lance_private *lp = netdev_priv(dev);
int csr0;
diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c
index 9202a1c369dd..7874eb1ef043 100644
--- a/drivers/net/sunqe.c
+++ b/drivers/net/sunqe.c
@@ -466,9 +466,9 @@ static void qe_tx_reclaim(struct sunqe *qep);
* so we just run through each qe and check to see who is signaling
* and thus needs to be serviced.
*/
-static irqreturn_t qec_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t qec_interrupt(int irq, void *dev_id)
{
- struct sunqec *qecp = (struct sunqec *) dev_id;
+ struct sunqec *qecp = dev_id;
u32 qec_status;
int channel = 0;
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c
index 60f026509487..81ed82f0b520 100644
--- a/drivers/net/tc35815.c
+++ b/drivers/net/tc35815.c
@@ -453,7 +453,7 @@ static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr
static int tc35815_open(struct net_device *dev);
static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev);
static void tc35815_tx_timeout(struct net_device *dev);
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t tc35815_interrupt(int irq, void *dev_id);
static void tc35815_rx(struct net_device *dev);
static void tc35815_txdone(struct net_device *dev);
static int tc35815_close(struct net_device *dev);
@@ -1044,7 +1044,7 @@ static void tc35815_fatal_error_interrupt(struct net_device *dev, int status)
* The typical workload of the driver:
* Handle the network interface interrupts.
*/
-static irqreturn_t tc35815_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t tc35815_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct tc35815_regs *tr;
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index aaf45b907a78..8e398499c045 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -68,8 +68,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.65"
-#define DRV_MODULE_RELDATE "August 07, 2006"
+#define DRV_MODULE_VERSION "3.67"
+#define DRV_MODULE_RELDATE "October 18, 2006"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -129,7 +129,7 @@
#define RX_JUMBO_PKT_BUF_SZ (9046 + tp->rx_offset + 64)
/* minimum number of free TX descriptors required to wake up TX process */
-#define TG3_TX_WAKEUP_THRESH (TG3_TX_RING_SIZE / 4)
+#define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4)
/* number of ETHTOOL_GSTATS u64's */
#define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64))
@@ -173,6 +173,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5705F)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5720)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5721)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5722)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5751)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5750M)},
@@ -187,6 +188,7 @@ static struct pci_device_id tg3_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5754M)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5755M)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5756)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5786)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5787M)},
@@ -197,6 +199,8 @@ static struct pci_device_id tg3_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5780S)},
{PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5781)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906)},
+ {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5906M)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)},
{PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)},
{PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)},
@@ -424,6 +428,16 @@ static void tg3_write32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
readl(mbox);
}
+static u32 tg3_read32_mbox_5906(struct tg3 *tp, u32 off)
+{
+ return (readl(tp->regs + off + GRCMBOX_BASE));
+}
+
+static void tg3_write32_mbox_5906(struct tg3 *tp, u32 off, u32 val)
+{
+ writel(val, tp->regs + off + GRCMBOX_BASE);
+}
+
#define tw32_mailbox(reg, val) tp->write32_mbox(tp, reg, val)
#define tw32_mailbox_f(reg, val) tw32_mailbox_flush(tp, (reg), (val))
#define tw32_rx_mbox(reg, val) tp->write32_rx_mbox(tp, reg, val)
@@ -439,6 +453,10 @@ static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
{
unsigned long flags;
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+ (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC))
+ return;
+
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
@@ -460,6 +478,12 @@ static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
{
unsigned long flags;
+ if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) &&
+ (off >= NIC_SRAM_STATS_BLK) && (off < NIC_SRAM_TX_BUFFER_DESC)) {
+ *val = 0;
+ return;
+ }
+
spin_lock_irqsave(&tp->indirect_lock, flags);
if (tp->tg3_flags & TG3_FLAG_SRAM_USE_CONFIG) {
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
@@ -489,6 +513,9 @@ static inline void tg3_cond_int(struct tg3 *tp)
if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS) &&
(tp->hw_status->status & SD_STATUS_UPDATED))
tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
+ else
+ tw32(HOSTCC_MODE, tp->coalesce_mode |
+ (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW));
}
static void tg3_enable_ints(struct tg3 *tp)
@@ -654,6 +681,10 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
unsigned int loops;
int ret;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 &&
+ (reg == MII_TG3_CTRL || reg == MII_TG3_AUX_CTRL))
+ return 0;
+
if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) {
tw32_f(MAC_MI_MODE,
(tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL));
@@ -1004,6 +1035,24 @@ out:
phy_reg | MII_TG3_EXT_CTRL_FIFO_ELASTIC);
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 phy_reg;
+
+ /* adjust output voltage */
+ tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x12);
+
+ if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phy_reg)) {
+ u32 phy_reg2;
+
+ tg3_writephy(tp, MII_TG3_EPHY_TEST,
+ phy_reg | MII_TG3_EPHY_SHADOW_EN);
+ /* Enable auto-MDIX */
+ if (!tg3_readphy(tp, 0x10, &phy_reg2))
+ tg3_writephy(tp, 0x10, phy_reg2 | 0x4000);
+ tg3_writephy(tp, MII_TG3_EPHY_TEST, phy_reg);
+ }
+ }
+
tg3_phy_set_wirespeed(tp);
return 0;
}
@@ -1117,6 +1166,15 @@ static void tg3_nvram_unlock(struct tg3 *);
static void tg3_power_down_phy(struct tg3 *tp)
{
+ if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
+ return;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
+ tg3_writephy(tp, MII_TG3_EXT_CTRL,
+ MII_TG3_EXT_CTRL_FORCE_LED_OFF);
+ tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
+ }
+
/* The PHY should not be powered down on some chips because
* of bugs.
*/
@@ -1199,7 +1257,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tg3_setup_phy(tp, 0);
}
- if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 val;
+
+ val = tr32(GRC_VCPU_EXT_CTRL);
+ tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_DISABLE_WOL);
+ } else if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
int i;
u32 val;
@@ -1223,7 +1286,10 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a);
udelay(40);
- mac_mode = MAC_MODE_PORT_MODE_MII;
+ if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
+ mac_mode = MAC_MODE_PORT_MODE_GMII;
+ else
+ mac_mode = MAC_MODE_PORT_MODE_MII;
if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 ||
!(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB))
@@ -1301,15 +1367,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
}
if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) &&
- !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) {
- /* Turn off the PHY */
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
- tg3_writephy(tp, MII_TG3_EXT_CTRL,
- MII_TG3_EXT_CTRL_FORCE_LED_OFF);
- tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2);
- tg3_power_down_phy(tp);
- }
- }
+ !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF))
+ tg3_power_down_phy(tp);
tg3_frob_aux_power(tp);
@@ -1467,6 +1526,13 @@ static void tg3_aux_stat_to_speed_duplex(struct tg3 *tp, u32 val, u16 *speed, u8
break;
default:
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ *speed = (val & MII_TG3_AUX_STAT_100) ? SPEED_100 :
+ SPEED_10;
+ *duplex = (val & MII_TG3_AUX_STAT_FULL) ? DUPLEX_FULL :
+ DUPLEX_HALF;
+ break;
+ }
*speed = SPEED_INVALID;
*duplex = DUPLEX_INVALID;
break;
@@ -1749,7 +1815,7 @@ static int tg3_setup_copper_phy(struct tg3 *tp, int force_reset)
if (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT)
tg3_writephy(tp, MII_TG3_IMASK, ~MII_TG3_INT_LINKCHG);
- else
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tg3_writephy(tp, MII_TG3_IMASK, ~0);
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
@@ -2406,24 +2472,27 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
expected_sg_dig_ctrl |= (1 << 12);
if (sg_dig_ctrl != expected_sg_dig_ctrl) {
+ if ((tp->tg3_flags2 & TG3_FLG2_PARALLEL_DETECT) &&
+ tp->serdes_counter &&
+ ((mac_status & (MAC_STATUS_PCS_SYNCED |
+ MAC_STATUS_RCVD_CFG)) ==
+ MAC_STATUS_PCS_SYNCED)) {
+ tp->serdes_counter--;
+ current_link_up = 1;
+ goto out;
+ }
+restart_autoneg:
if (workaround)
tw32_f(MAC_SERDES_CFG, serdes_cfg | 0xc011000);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl | (1 << 30));
udelay(5);
tw32_f(SG_DIG_CTRL, expected_sg_dig_ctrl);
- tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
} else if (mac_status & (MAC_STATUS_PCS_SYNCED |
MAC_STATUS_SIGNAL_DET)) {
- int i;
-
- /* Giver time to negotiate (~200ms) */
- for (i = 0; i < 40000; i++) {
- sg_dig_status = tr32(SG_DIG_STATUS);
- if (sg_dig_status & (0x3))
- break;
- udelay(5);
- }
+ sg_dig_status = tr32(SG_DIG_STATUS);
mac_status = tr32(MAC_STATUS);
if ((sg_dig_status & (1 << 1)) &&
@@ -2439,10 +2508,11 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
tg3_setup_flow_control(tp, local_adv, remote_adv);
current_link_up = 1;
- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter = 0;
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
} else if (!(sg_dig_status & (1 << 1))) {
- if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED)
- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+ if (tp->serdes_counter)
+ tp->serdes_counter--;
else {
if (workaround) {
u32 val = serdes_cfg;
@@ -2466,9 +2536,17 @@ static int tg3_setup_fiber_hw_autoneg(struct tg3 *tp, u32 mac_status)
!(mac_status & MAC_STATUS_RCVD_CFG)) {
tg3_setup_flow_control(tp, 0, 0);
current_link_up = 1;
- }
+ tp->tg3_flags2 |=
+ TG3_FLG2_PARALLEL_DETECT;
+ tp->serdes_counter =
+ SERDES_PARALLEL_DET_TIMEOUT;
+ } else
+ goto restart_autoneg;
}
}
+ } else {
+ tp->serdes_counter = SERDES_AN_TIMEOUT_5704S;
+ tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
}
out:
@@ -2599,14 +2677,16 @@ static int tg3_setup_fiber_phy(struct tg3 *tp, int force_reset)
MAC_STATUS_CFG_CHANGED));
udelay(5);
if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED |
- MAC_STATUS_CFG_CHANGED)) == 0)
+ MAC_STATUS_CFG_CHANGED |
+ MAC_STATUS_LNKSTATE_CHANGED)) == 0)
break;
}
mac_status = tr32(MAC_STATUS);
if ((mac_status & MAC_STATUS_PCS_SYNCED) == 0) {
current_link_up = 0;
- if (tp->link_config.autoneg == AUTONEG_ENABLE) {
+ if (tp->link_config.autoneg == AUTONEG_ENABLE &&
+ tp->serdes_counter == 0) {
tw32_f(MAC_MODE, (tp->mac_mode |
MAC_MODE_SEND_CONFIGS));
udelay(1);
@@ -2711,7 +2791,7 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
tg3_writephy(tp, MII_BMCR, bmcr);
tw32_f(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED);
- tp->tg3_flags2 |= TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter = SERDES_AN_TIMEOUT_5714S;
tp->tg3_flags2 &= ~TG3_FLG2_PARALLEL_DETECT;
return err;
@@ -2816,9 +2896,9 @@ static int tg3_setup_fiber_mii_phy(struct tg3 *tp, int force_reset)
static void tg3_serdes_parallel_detect(struct tg3 *tp)
{
- if (tp->tg3_flags2 & TG3_FLG2_PHY_JUST_INITTED) {
+ if (tp->serdes_counter) {
/* Give autoneg time to complete. */
- tp->tg3_flags2 &= ~TG3_FLG2_PHY_JUST_INITTED;
+ tp->serdes_counter--;
return;
}
if (!netif_carrier_ok(tp->dev) &&
@@ -2995,10 +3075,10 @@ static void tg3_tx(struct tg3 *tp)
smp_mb();
if (unlikely(netif_queue_stopped(tp->dev) &&
- (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))) {
+ (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))) {
netif_tx_lock(tp->dev);
if (netif_queue_stopped(tp->dev) &&
- (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH))
+ (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp)))
netif_wake_queue(tp->dev);
netif_tx_unlock(tp->dev);
}
@@ -3401,7 +3481,7 @@ static inline void tg3_full_unlock(struct tg3 *tp)
/* One-shot MSI handler - Chip automatically disables interrupt
* after sending MSI so driver doesn't have to do it.
*/
-static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tg3_msi_1shot(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
@@ -3419,7 +3499,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id, struct pt_regs *regs)
* flush status block and interrupt mailbox. PCI ordering rules
* guarantee that MSI will arrive after the status block.
*/
-static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tg3_msi(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
@@ -3440,7 +3520,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_RETVAL(1);
}
-static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tg3_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
@@ -3483,7 +3563,7 @@ out:
return IRQ_RETVAL(handled);
}
-static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
@@ -3526,8 +3606,7 @@ out:
}
/* ISR for interrupt test */
-static irqreturn_t tg3_test_isr(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t tg3_test_isr(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
@@ -3535,8 +3614,7 @@ static irqreturn_t tg3_test_isr(int irq, void *dev_id,
if ((sblk->status & SD_STATUS_UPDATED) ||
!(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
- tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
- 0x00000001);
+ tg3_disable_ints(tp);
return IRQ_RETVAL(1);
}
return IRQ_RETVAL(0);
@@ -3572,7 +3650,7 @@ static void tg3_poll_controller(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
- tg3_interrupt(tp->pdev->irq, dev, NULL);
+ tg3_interrupt(tp->pdev->irq, dev);
}
#endif
@@ -3850,7 +3928,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
tp->tx_prod = entry;
if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
netif_stop_queue(dev);
- if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
+ if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
netif_wake_queue(tp->dev);
}
@@ -4065,7 +4143,7 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
tp->tx_prod = entry;
if (unlikely(tg3_tx_avail(tp) <= (MAX_SKB_FRAGS + 1))) {
netif_stop_queue(dev);
- if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH)
+ if (tg3_tx_avail(tp) > TG3_TX_WAKEUP_THRESH(tp))
netif_wake_queue(tp->dev);
}
@@ -4644,6 +4722,44 @@ static void tg3_write_sig_legacy(struct tg3 *tp, int kind)
}
}
+static int tg3_poll_fw(struct tg3 *tp)
+{
+ int i;
+ u32 val;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ for (i = 0; i < 400; i++) {
+ if (tr32(VCPU_STATUS) & VCPU_STATUS_INIT_DONE)
+ return 0;
+ udelay(10);
+ }
+ return -ENODEV;
+ }
+
+ /* Wait for firmware initialization to complete. */
+ for (i = 0; i < 100000; i++) {
+ tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
+ if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
+ break;
+ udelay(10);
+ }
+
+ /* Chip might not be fitted with firmware. Some Sun onboard
+ * parts are configured like that. So don't signal the timeout
+ * of the above loop as an error, but do report the lack of
+ * running firmware once.
+ */
+ if (i >= 100000 &&
+ !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
+ tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
+
+ printk(KERN_INFO PFX "%s: No firmware running.\n",
+ tp->dev->name);
+ }
+
+ return 0;
+}
+
static void tg3_stop_fw(struct tg3 *);
/* tp->lock is held. */
@@ -4651,7 +4767,7 @@ static int tg3_chip_reset(struct tg3 *tp)
{
u32 val;
void (*write_op)(struct tg3 *, u32, u32);
- int i;
+ int err;
tg3_nvram_lock(tp);
@@ -4688,6 +4804,12 @@ static int tg3_chip_reset(struct tg3 *tp)
}
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tw32(VCPU_STATUS, tr32(VCPU_STATUS) | VCPU_STATUS_DRV_RESET);
+ tw32(GRC_VCPU_EXT_CTRL,
+ tr32(GRC_VCPU_EXT_CTRL) & ~GRC_VCPU_EXT_CTRL_HALT_CPU);
+ }
+
if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
val |= GRC_MISC_CFG_KEEP_GPHY_POWER;
tw32(GRC_MISC_CFG, val);
@@ -4811,26 +4933,9 @@ static int tg3_chip_reset(struct tg3 *tp)
tw32_f(MAC_MODE, 0);
udelay(40);
- /* Wait for firmware initialization to complete. */
- for (i = 0; i < 100000; i++) {
- tg3_read_mem(tp, NIC_SRAM_FIRMWARE_MBOX, &val);
- if (val == ~NIC_SRAM_FIRMWARE_MBOX_MAGIC1)
- break;
- udelay(10);
- }
-
- /* Chip might not be fitted with firmare. Some Sun onboard
- * parts are configured like that. So don't signal the timeout
- * of the above loop as an error, but do report the lack of
- * running firmware once.
- */
- if (i >= 100000 &&
- !(tp->tg3_flags2 & TG3_FLG2_NO_FWARE_REPORTED)) {
- tp->tg3_flags2 |= TG3_FLG2_NO_FWARE_REPORTED;
-
- printk(KERN_INFO PFX "%s: No firmware running.\n",
- tp->dev->name);
- }
+ err = tg3_poll_fw(tp);
+ if (err)
+ return err;
if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) &&
tp->pci_chip_rev_id != CHIPREV_ID_5750_A0) {
@@ -5036,6 +5141,12 @@ static int tg3_halt_cpu(struct tg3 *tp, u32 offset)
BUG_ON(offset == TX_CPU_BASE &&
(tp->tg3_flags2 & TG3_FLG2_5705_PLUS));
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 val = tr32(GRC_VCPU_EXT_CTRL);
+
+ tw32(GRC_VCPU_EXT_CTRL, val | GRC_VCPU_EXT_CTRL_HALT_CPU);
+ return 0;
+ }
if (offset == RX_CPU_BASE) {
for (i = 0; i < 10000; i++) {
tw32(offset + CPU_STATE, 0xffffffff);
@@ -6040,6 +6151,13 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
val = 1;
else if (val > tp->rx_std_max_post)
val = tp->rx_std_max_post;
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (tp->pci_chip_rev_id == CHIPREV_ID_5906_A1)
+ tw32(ISO_PKT_TX, (tr32(ISO_PKT_TX) & ~0x3) | 0x2);
+
+ if (val > (TG3_RX_INTERNAL_RING_SZ_5906 / 2))
+ val = TG3_RX_INTERNAL_RING_SZ_5906 / 2;
+ }
tw32(RCVBDI_STD_THRESH, val);
@@ -6460,7 +6578,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
if (err)
return err;
- if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) {
+ if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906) {
u32 tmp;
/* Clear CRC stats. */
@@ -6660,12 +6779,14 @@ static void tg3_timer(unsigned long __opaque)
need_setup = 1;
}
if (need_setup) {
- tw32_f(MAC_MODE,
- (tp->mac_mode &
- ~MAC_MODE_PORT_MODE_MASK));
- udelay(40);
- tw32_f(MAC_MODE, tp->mac_mode);
- udelay(40);
+ if (!tp->serdes_counter) {
+ tw32_f(MAC_MODE,
+ (tp->mac_mode &
+ ~MAC_MODE_PORT_MODE_MASK));
+ udelay(40);
+ tw32_f(MAC_MODE, tp->mac_mode);
+ udelay(40);
+ }
tg3_setup_phy(tp, 0);
}
} else if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES)
@@ -6674,13 +6795,29 @@ static void tg3_timer(unsigned long __opaque)
tp->timer_counter = tp->timer_multiplier;
}
- /* Heartbeat is only sent once every 2 seconds. */
+ /* Heartbeat is only sent once every 2 seconds.
+ *
+ * The heartbeat is to tell the ASF firmware that the host
+ * driver is still alive. In the event that the OS crashes,
+ * ASF needs to reset the hardware to free up the FIFO space
+ * that may be filled with rx packets destined for the host.
+ * If the FIFO is full, ASF will no longer function properly.
+ *
+ * Unintended resets have been reported on real time kernels
+ * where the timer doesn't run on time. Netpoll will also have
+ * same problem.
+ *
+ * The new FWCMD_NICDRV_ALIVE3 command tells the ASF firmware
+ * to check the ring condition when the heartbeat is expiring
+ * before doing the reset. This will prevent most unintended
+ * resets.
+ */
if (!--tp->asf_counter) {
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val;
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX,
- FWCMD_NICDRV_ALIVE2);
+ FWCMD_NICDRV_ALIVE3);
tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4);
/* 5 seconds timeout */
tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 5);
@@ -6700,7 +6837,7 @@ restart_timer:
static int tg3_request_irq(struct tg3 *tp)
{
- irqreturn_t (*fn)(int, void *, struct pt_regs *);
+ irq_handler_t fn;
unsigned long flags;
struct net_device *dev = tp->dev;
@@ -6721,8 +6858,7 @@ static int tg3_request_irq(struct tg3 *tp)
static int tg3_test_interrupt(struct tg3 *tp)
{
struct net_device *dev = tp->dev;
- int err, i;
- u32 int_mbox = 0;
+ int err, i, intr_ok = 0;
if (!netif_running(dev))
return -ENODEV;
@@ -6743,10 +6879,18 @@ static int tg3_test_interrupt(struct tg3 *tp)
HOSTCC_MODE_NOW);
for (i = 0; i < 5; i++) {
+ u32 int_mbox, misc_host_ctrl;
+
int_mbox = tr32_mailbox(MAILBOX_INTERRUPT_0 +
TG3_64BIT_REG_LOW);
- if (int_mbox != 0)
+ misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL);
+
+ if ((int_mbox != 0) ||
+ (misc_host_ctrl & MISC_HOST_CTRL_MASK_PCI_INT)) {
+ intr_ok = 1;
break;
+ }
+
msleep(10);
}
@@ -6759,7 +6903,7 @@ static int tg3_test_interrupt(struct tg3 *tp)
if (err)
return err;
- if (int_mbox != 0)
+ if (intr_ok)
return 0;
return -EIO;
@@ -6936,9 +7080,10 @@ static int tg3_open(struct net_device *dev)
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
if (tp->tg3_flags2 & TG3_FLG2_1SHOT_MSI) {
- u32 val = tr32(0x7c04);
+ u32 val = tr32(PCIE_TRANSACTION_CFG);
- tw32(0x7c04, val | (1 << 29));
+ tw32(PCIE_TRANSACTION_CFG,
+ val | PCIE_TRANS_CFG_1SHOT_MSI);
}
}
}
@@ -7857,7 +8002,7 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
if (wol->wolopts & ~WAKE_MAGIC)
return -EINVAL;
if ((wol->wolopts & WAKE_MAGIC) &&
- tp->tg3_flags2 & TG3_FLG2_PHY_SERDES &&
+ tp->tg3_flags2 & TG3_FLG2_ANY_SERDES &&
!(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
return -EINVAL;
@@ -7893,7 +8038,8 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
return -EINVAL;
return 0;
}
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) {
+ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) {
if (value)
dev->features |= NETIF_F_TSO6;
else
@@ -7960,7 +8106,10 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
- (ering->tx_pending > TG3_TX_RING_SIZE - 1))
+ (ering->tx_pending > TG3_TX_RING_SIZE - 1) ||
+ (ering->tx_pending <= MAX_SKB_FRAGS) ||
+ ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_1_BUG) &&
+ (ering->tx_pending <= (MAX_SKB_FRAGS * 3))))
return -EINVAL;
if (netif_running(dev)) {
@@ -8147,6 +8296,8 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
#define NVRAM_TEST_SIZE 0x100
#define NVRAM_SELFBOOT_FORMAT1_SIZE 0x14
+#define NVRAM_SELFBOOT_HW_SIZE 0x20
+#define NVRAM_SELFBOOT_DATA_SIZE 0x1c
static int tg3_test_nvram(struct tg3 *tp)
{
@@ -8158,12 +8309,14 @@ static int tg3_test_nvram(struct tg3 *tp)
if (magic == TG3_EEPROM_MAGIC)
size = NVRAM_TEST_SIZE;
- else if ((magic & 0xff000000) == 0xa5000000) {
+ else if ((magic & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) {
if ((magic & 0xe00000) == 0x200000)
size = NVRAM_SELFBOOT_FORMAT1_SIZE;
else
return 0;
- } else
+ } else if ((magic & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
+ size = NVRAM_SELFBOOT_HW_SIZE;
+ else
return -EIO;
buf = kmalloc(size, GFP_KERNEL);
@@ -8182,7 +8335,8 @@ static int tg3_test_nvram(struct tg3 *tp)
goto out;
/* Selfboot format */
- if (cpu_to_be32(buf[0]) != TG3_EEPROM_MAGIC) {
+ if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_FW_MSK) ==
+ TG3_EEPROM_MAGIC_FW) {
u8 *buf8 = (u8 *) buf, csum8 = 0;
for (i = 0; i < size; i++)
@@ -8197,6 +8351,51 @@ static int tg3_test_nvram(struct tg3 *tp)
goto out;
}
+ if ((cpu_to_be32(buf[0]) & TG3_EEPROM_MAGIC_HW_MSK) ==
+ TG3_EEPROM_MAGIC_HW) {
+ u8 data[NVRAM_SELFBOOT_DATA_SIZE];
+ u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
+ u8 *buf8 = (u8 *) buf;
+ int j, k;
+
+ /* Separate the parity bits and the data bytes. */
+ for (i = 0, j = 0, k = 0; i < NVRAM_SELFBOOT_HW_SIZE; i++) {
+ if ((i == 0) || (i == 8)) {
+ int l;
+ u8 msk;
+
+ for (l = 0, msk = 0x80; l < 7; l++, msk >>= 1)
+ parity[k++] = buf8[i] & msk;
+ i++;
+ }
+ else if (i == 16) {
+ int l;
+ u8 msk;
+
+ for (l = 0, msk = 0x20; l < 6; l++, msk >>= 1)
+ parity[k++] = buf8[i] & msk;
+ i++;
+
+ for (l = 0, msk = 0x80; l < 8; l++, msk >>= 1)
+ parity[k++] = buf8[i] & msk;
+ i++;
+ }
+ data[j++] = buf8[i];
+ }
+
+ err = -EIO;
+ for (i = 0; i < NVRAM_SELFBOOT_DATA_SIZE; i++) {
+ u8 hw8 = hweight8(data[i]);
+
+ if ((hw8 & 0x1) && parity[i])
+ goto out;
+ else if (!(hw8 & 0x1) && !parity[i])
+ goto out;
+ }
+ err = 0;
+ goto out;
+ }
+
/* Bootstrap checksum at offset 0x10 */
csum = calc_crc((unsigned char *) buf, 0x10);
if(csum != cpu_to_le32(buf[0x10/4]))
@@ -8243,7 +8442,7 @@ static int tg3_test_link(struct tg3 *tp)
/* Only test the commonly used registers */
static int tg3_test_registers(struct tg3 *tp)
{
- int i, is_5705;
+ int i, is_5705, is_5750;
u32 offset, read_mask, write_mask, val, save_val, read_val;
static struct {
u16 offset;
@@ -8251,6 +8450,7 @@ static int tg3_test_registers(struct tg3 *tp)
#define TG3_FL_5705 0x1
#define TG3_FL_NOT_5705 0x2
#define TG3_FL_NOT_5788 0x4
+#define TG3_FL_NOT_5750 0x8
u32 read_mask;
u32 write_mask;
} reg_tbl[] = {
@@ -8361,9 +8561,9 @@ static int tg3_test_registers(struct tg3 *tp)
0xffffffff, 0x00000000 },
/* Buffer Manager Control Registers. */
- { BUFMGR_MB_POOL_ADDR, 0x0000,
+ { BUFMGR_MB_POOL_ADDR, TG3_FL_NOT_5750,
0x00000000, 0x007fff80 },
- { BUFMGR_MB_POOL_SIZE, 0x0000,
+ { BUFMGR_MB_POOL_SIZE, TG3_FL_NOT_5750,
0x00000000, 0x007fffff },
{ BUFMGR_MB_RDMA_LOW_WATER, 0x0000,
0x00000000, 0x0000003f },
@@ -8389,10 +8589,12 @@ static int tg3_test_registers(struct tg3 *tp)
{ 0xffff, 0x0000, 0x00000000, 0x00000000 },
};
- if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS)
+ is_5705 = is_5750 = 0;
+ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
is_5705 = 1;
- else
- is_5705 = 0;
+ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)
+ is_5750 = 1;
+ }
for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
if (is_5705 && (reg_tbl[i].flags & TG3_FL_NOT_5705))
@@ -8405,6 +8607,9 @@ static int tg3_test_registers(struct tg3 *tp)
(reg_tbl[i].flags & TG3_FL_NOT_5788))
continue;
+ if (is_5750 && (reg_tbl[i].flags & TG3_FL_NOT_5750))
+ continue;
+
offset = (u32) reg_tbl[i].offset;
read_mask = reg_tbl[i].read_mask;
write_mask = reg_tbl[i].write_mask;
@@ -8496,6 +8701,13 @@ static int tg3_test_memory(struct tg3 *tp)
{ 0x00008000, 0x02000},
{ 0x00010000, 0x0c000},
{ 0xffffffff, 0x00000}
+ }, mem_tbl_5906[] = {
+ { 0x00000200, 0x00008},
+ { 0x00004000, 0x00400},
+ { 0x00006000, 0x00400},
+ { 0x00008000, 0x01000},
+ { 0x00010000, 0x01000},
+ { 0xffffffff, 0x00000}
};
struct mem_entry *mem_tbl;
int err = 0;
@@ -8505,6 +8717,8 @@ static int tg3_test_memory(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
mem_tbl = mem_tbl_5755;
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ mem_tbl = mem_tbl_5906;
else
mem_tbl = mem_tbl_5705;
} else
@@ -8541,13 +8755,41 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
return 0;
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
- MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY |
- MAC_MODE_PORT_MODE_GMII;
+ MAC_MODE_PORT_INT_LPBACK | MAC_MODE_LINK_POLARITY;
+ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ mac_mode |= MAC_MODE_PORT_MODE_MII;
+ else
+ mac_mode |= MAC_MODE_PORT_MODE_GMII;
tw32(MAC_MODE, mac_mode);
} else if (loopback_mode == TG3_PHY_LOOPBACK) {
- tg3_writephy(tp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
- BMCR_SPEED1000);
+ u32 val;
+
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ u32 phytest;
+
+ if (!tg3_readphy(tp, MII_TG3_EPHY_TEST, &phytest)) {
+ u32 phy;
+
+ tg3_writephy(tp, MII_TG3_EPHY_TEST,
+ phytest | MII_TG3_EPHY_SHADOW_EN);
+ if (!tg3_readphy(tp, 0x1b, &phy))
+ tg3_writephy(tp, 0x1b, phy & ~0x20);
+ if (!tg3_readphy(tp, 0x10, &phy))
+ tg3_writephy(tp, 0x10, phy & ~0x4000);
+ tg3_writephy(tp, MII_TG3_EPHY_TEST, phytest);
+ }
+ }
+ val = BMCR_LOOPBACK | BMCR_FULLDPLX;
+ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ val |= BMCR_SPEED100;
+ else
+ val |= BMCR_SPEED1000;
+
+ tg3_writephy(tp, MII_BMCR, val);
udelay(40);
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tg3_writephy(tp, MII_TG3_EPHY_PTEST, 0x1800);
+
/* reset to prevent losing 1st rx packet intermittently */
if (tp->tg3_flags2 & TG3_FLG2_MII_SERDES) {
tw32_f(MAC_RX_MODE, RX_MODE_RESET);
@@ -8555,7 +8797,11 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
tw32_f(MAC_RX_MODE, tp->rx_mode);
}
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
- MAC_MODE_LINK_POLARITY | MAC_MODE_PORT_MODE_GMII;
+ MAC_MODE_LINK_POLARITY;
+ if (tp->tg3_flags & TG3_FLAG_10_100_ONLY)
+ mac_mode |= MAC_MODE_PORT_MODE_MII;
+ else
+ mac_mode |= MAC_MODE_PORT_MODE_GMII;
if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) {
mac_mode &= ~MAC_MODE_LINK_POLARITY;
tg3_writephy(tp, MII_TG3_EXT_CTRL,
@@ -8604,7 +8850,8 @@ static int tg3_run_loopback(struct tg3 *tp, int loopback_mode)
udelay(10);
- for (i = 0; i < 10; i++) {
+ /* 250 usec to allow enough time on some 10/100 Mbps devices. */
+ for (i = 0; i < 25; i++) {
tw32_f(HOSTCC_MODE, tp->coalesce_mode | HOSTCC_MODE_ENABLE |
HOSTCC_MODE_NOW);
@@ -8956,7 +9203,9 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
return;
- if ((magic != TG3_EEPROM_MAGIC) && ((magic & 0xff000000) != 0xa5000000))
+ if ((magic != TG3_EEPROM_MAGIC) &&
+ ((magic & TG3_EEPROM_MAGIC_FW_MSK) != TG3_EEPROM_MAGIC_FW) &&
+ ((magic & TG3_EEPROM_MAGIC_HW_MSK) != TG3_EEPROM_MAGIC_HW))
return;
/*
@@ -9194,6 +9443,13 @@ static void __devinit tg3_get_5787_nvram_info(struct tg3 *tp)
}
}
+static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp)
+{
+ tp->nvram_jedecnum = JEDEC_ATMEL;
+ tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED;
+ tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE;
+}
+
/* Chips other than 5700/5701 use the NVRAM for fetching info. */
static void __devinit tg3_nvram_init(struct tg3 *tp)
{
@@ -9230,6 +9486,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
tg3_get_5755_nvram_info(tp);
else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tg3_get_5787_nvram_info(tp);
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ tg3_get_5906_nvram_info(tp);
else
tg3_get_nvram_info(tp);
@@ -9703,6 +9961,12 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp)
/* Assume an onboard device by default. */
tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ if (!(tr32(PCIE_TRANSACTION_CFG) & PCIE_TRANS_CFG_LOM))
+ tp->tg3_flags &= ~TG3_FLAG_EEPROM_WRITE_PROT;
+ return;
+ }
+
tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val);
if (val == NIC_SRAM_DATA_SIG_MAGIC) {
u32 nic_cfg, led_cfg;
@@ -10034,7 +10298,10 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
}
out_not_found:
- strcpy(tp->board_part_number, "none");
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ strcpy(tp->board_part_number, "BCM95906");
+ else
+ strcpy(tp->board_part_number, "none");
}
static void __devinit tg3_read_fw_ver(struct tg3 *tp)
@@ -10236,6 +10503,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 ||
(tp->tg3_flags2 & TG3_FLG2_5780_CLASS))
tp->tg3_flags2 |= TG3_FLG2_5750_PLUS;
@@ -10245,7 +10513,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) {
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2;
tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI;
} else {
@@ -10262,7 +10531,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5750 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 &&
GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755 &&
- GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787 &&
+ GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE;
if (pci_find_capability(tp->pdev, PCI_CAP_ID_EXP) != 0)
@@ -10392,6 +10662,12 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_cmd &= ~PCI_COMMAND_MEMORY;
pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd);
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tp->read32_mbox = tg3_read32_mbox_5906;
+ tp->write32_mbox = tg3_write32_mbox_5906;
+ tp->write32_tx_mbox = tg3_write32_mbox_5906;
+ tp->write32_rx_mbox = tg3_write32_mbox_5906;
+ }
if (tp->write32 == tg3_write_indirect_reg32 ||
((tp->tg3_flags & TG3_FLAG_PCIX_MODE) &&
@@ -10463,6 +10739,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705) &&
(tp->pci_chip_rev_id != CHIPREV_ID_5705_A0) &&
(tp->pci_chip_rev_id != CHIPREV_ID_5705_A1)) ||
+ (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) ||
(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
tp->tg3_flags2 |= TG3_FLG2_NO_ETH_WIRE_SPEED;
@@ -10476,7 +10753,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG;
- else
+ else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)
tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG;
}
@@ -10566,7 +10843,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
tp->pdev->device == PCI_DEVICE_ID_TIGON3_5705F)) ||
(tp->pdev->vendor == PCI_VENDOR_ID_BROADCOM &&
(tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F ||
- tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)))
+ tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F)) ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->tg3_flags |= TG3_FLAG_10_100_ONLY;
err = tg3_phy_probe(tp);
@@ -10617,7 +10895,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
* straddle the 4GB address boundary in some cases.
*/
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 ||
- GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787)
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 ||
+ GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
tp->dev->hard_start_xmit = tg3_start_xmit;
else
tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug;
@@ -10698,6 +10977,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
else
tg3_nvram_unlock(tp);
}
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
+ mac_offset = 0x10;
/* First try to get it from MAC address mailbox. */
tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi);
@@ -11181,6 +11462,12 @@ static void __devinit tg3_init_bufmgr_config(struct tg3 *tp)
DEFAULT_MB_MACRX_LOW_WATER_5705;
tp->bufmgr_config.mbuf_high_water =
DEFAULT_MB_HIGH_WATER_5705;
+ if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) {
+ tp->bufmgr_config.mbuf_mac_rx_low_water =
+ DEFAULT_MB_MACRX_LOW_WATER_5906;
+ tp->bufmgr_config.mbuf_high_water =
+ DEFAULT_MB_HIGH_WATER_5906;
+ }
tp->bufmgr_config.mbuf_read_dma_low_water_jumbo =
DEFAULT_MB_RDMA_LOW_WATER_JUMBO_5780;
@@ -11224,6 +11511,8 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
case PHY_ID_BCM5780: return "5780";
case PHY_ID_BCM5755: return "5755";
case PHY_ID_BCM5787: return "5787";
+ case PHY_ID_BCM5756: return "5722/5756";
+ case PHY_ID_BCM5906: return "5906";
case PHY_ID_BCM8002: return "8002/serdes";
case 0: return "serdes";
default: return "unknown";
@@ -11526,7 +11815,8 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
*/
if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
dev->features |= NETIF_F_TSO;
- if (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)
+ if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) &&
+ (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906))
dev->features |= NETIF_F_TSO6;
}
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 3ecf356cfb08..92f53000bce6 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -24,6 +24,8 @@
#define RX_COPY_THRESHOLD 256
+#define TG3_RX_INTERNAL_RING_SZ_5906 32
+
#define RX_STD_MAX_SIZE 1536
#define RX_STD_MAX_SIZE_5705 512
#define RX_JUMBO_MAX_SIZE 0xdeadbeef /* XXX */
@@ -129,6 +131,7 @@
#define CHIPREV_ID_5752_A0_HW 0x5000
#define CHIPREV_ID_5752_A0 0x6000
#define CHIPREV_ID_5752_A1 0x6001
+#define CHIPREV_ID_5906_A1 0xc001
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
@@ -141,6 +144,7 @@
#define ASIC_REV_5714 0x09
#define ASIC_REV_5755 0x0a
#define ASIC_REV_5787 0x0b
+#define ASIC_REV_5906 0x0c
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
@@ -646,7 +650,8 @@
#define SNDDATAI_SCTRL_FORCE_ZERO 0x00000010
#define SNDDATAI_STATSENAB 0x00000c0c
#define SNDDATAI_STATSINCMASK 0x00000c10
-/* 0xc14 --> 0xc80 unused */
+#define ISO_PKT_TX 0x00000c20
+/* 0xc24 --> 0xc80 unused */
#define SNDDATAI_COS_CNT_0 0x00000c80
#define SNDDATAI_COS_CNT_1 0x00000c84
#define SNDDATAI_COS_CNT_2 0x00000c88
@@ -997,11 +1002,13 @@
#define BUFMGR_MB_MACRX_LOW_WATER 0x00004414
#define DEFAULT_MB_MACRX_LOW_WATER 0x00000020
#define DEFAULT_MB_MACRX_LOW_WATER_5705 0x00000010
+#define DEFAULT_MB_MACRX_LOW_WATER_5906 0x00000004
#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO 0x00000098
#define DEFAULT_MB_MACRX_LOW_WATER_JUMBO_5780 0x0000004b
#define BUFMGR_MB_HIGH_WATER 0x00004418
#define DEFAULT_MB_HIGH_WATER 0x00000060
#define DEFAULT_MB_HIGH_WATER_5705 0x00000060
+#define DEFAULT_MB_HIGH_WATER_5906 0x00000010
#define DEFAULT_MB_HIGH_WATER_JUMBO 0x0000017c
#define DEFAULT_MB_HIGH_WATER_JUMBO_5780 0x00000096
#define BUFMGR_RX_MB_ALLOC_REQ 0x0000441c
@@ -1138,7 +1145,12 @@
#define TX_CPU_STATE 0x00005404
#define TX_CPU_PGMCTR 0x0000541c
+#define VCPU_STATUS 0x00005100
+#define VCPU_STATUS_INIT_DONE 0x04000000
+#define VCPU_STATUS_DRV_RESET 0x08000000
+
/* Mailboxes */
+#define GRCMBOX_BASE 0x00005600
#define GRCMBOX_INTERRUPT_0 0x00005800 /* 64-bit */
#define GRCMBOX_INTERRUPT_1 0x00005808 /* 64-bit */
#define GRCMBOX_INTERRUPT_2 0x00005810 /* 64-bit */
@@ -1398,7 +1410,10 @@
#define GRC_EEPROM_CTRL 0x00006840
#define GRC_MDI_CTRL 0x00006844
#define GRC_SEEPROM_DELAY 0x00006848
-/* 0x684c --> 0x6c00 unused */
+/* 0x684c --> 0x6890 unused */
+#define GRC_VCPU_EXT_CTRL 0x00006890
+#define GRC_VCPU_EXT_CTRL_HALT_CPU 0x00400000
+#define GRC_VCPU_EXT_CTRL_DISABLE_WOL 0x20000000
#define GRC_FASTBOOT_PC 0x00006894 /* 5752, 5755, 5787 */
/* 0x6c00 --> 0x7000 unused */
@@ -1485,9 +1500,17 @@
#define NVRAM_WRITE1 0x00007028
/* 0x702c --> 0x7400 unused */
-/* 0x7400 --> 0x8000 unused */
+/* 0x7400 --> 0x7c00 unused */
+#define PCIE_TRANSACTION_CFG 0x00007c04
+#define PCIE_TRANS_CFG_1SHOT_MSI 0x20000000
+#define PCIE_TRANS_CFG_LOM 0x00000020
+
#define TG3_EEPROM_MAGIC 0x669955aa
+#define TG3_EEPROM_MAGIC_FW 0xa5000000
+#define TG3_EEPROM_MAGIC_FW_MSK 0xff000000
+#define TG3_EEPROM_MAGIC_HW 0xabcd
+#define TG3_EEPROM_MAGIC_HW_MSK 0xffff
/* 32K Window into NIC internal memory */
#define NIC_SRAM_WIN_BASE 0x00008000
@@ -1537,6 +1560,7 @@
#define FWCMD_NICDRV_FIX_DMAR 0x00000005
#define FWCMD_NICDRV_FIX_DMAW 0x00000006
#define FWCMD_NICDRV_ALIVE2 0x0000000d
+#define FWCMD_NICDRV_ALIVE3 0x0000000e
#define NIC_SRAM_FW_CMD_LEN_MBOX 0x00000b7c
#define NIC_SRAM_FW_CMD_DATA_MBOX 0x00000b80
#define NIC_SRAM_FW_ASF_STATUS_MBOX 0x00000c00
@@ -1604,6 +1628,7 @@
#define MII_TG3_DSP_RW_PORT 0x15 /* DSP coefficient read/write port */
#define MII_TG3_DSP_ADDRESS 0x17 /* DSP address register */
+#define MII_TG3_EPHY_PTEST 0x17 /* 5906 PHY register */
#define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */
@@ -1617,6 +1642,8 @@
#define MII_TG3_AUX_STAT_100FULL 0x0500
#define MII_TG3_AUX_STAT_1000HALF 0x0600
#define MII_TG3_AUX_STAT_1000FULL 0x0700
+#define MII_TG3_AUX_STAT_100 0x0008
+#define MII_TG3_AUX_STAT_FULL 0x0001
#define MII_TG3_ISTAT 0x1a /* IRQ status register */
#define MII_TG3_IMASK 0x1b /* IRQ mask register */
@@ -1627,6 +1654,9 @@
#define MII_TG3_INT_DUPLEXCHG 0x0008
#define MII_TG3_INT_ANEG_PAGE_RX 0x0400
+#define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */
+#define MII_TG3_EPHY_SHADOW_EN 0x80
+
/* There are two ways to manage the TX descriptors on the tigon3.
* Either the descriptors are in host DMA'able memory, or they
* exist only in the cards on-chip SRAM. All 16 send bds are under
@@ -2203,7 +2233,6 @@ struct tg3 {
#define TG3_FLG2_PCI_EXPRESS 0x00000200
#define TG3_FLG2_ASF_NEW_HANDSHAKE 0x00000400
#define TG3_FLG2_HW_AUTONEG 0x00000800
-#define TG3_FLG2_PHY_JUST_INITTED 0x00001000
#define TG3_FLG2_PHY_SERDES 0x00002000
#define TG3_FLG2_CAPACITIVE_COUPLING 0x00004000
#define TG3_FLG2_FLASH 0x00008000
@@ -2236,6 +2265,12 @@ struct tg3 {
u16 asf_counter;
u16 asf_multiplier;
+ /* 1 second counter for transient serdes link events */
+ u32 serdes_counter;
+#define SERDES_AN_TIMEOUT_5704S 2
+#define SERDES_PARALLEL_DET_TIMEOUT 1
+#define SERDES_AN_TIMEOUT_5714S 1
+
struct tg3_link_config link_config;
struct tg3_bufmgr_config bufmgr_config;
@@ -2276,6 +2311,8 @@ struct tg3 {
#define PHY_ID_BCM5780 0x60008350
#define PHY_ID_BCM5755 0xbc050cc0
#define PHY_ID_BCM5787 0xbc050ce0
+#define PHY_ID_BCM5756 0xbc050ed0
+#define PHY_ID_BCM5906 0xdc00ac40
#define PHY_ID_BCM8002 0x60010140
#define PHY_ID_INVALID 0xffffffff
#define PHY_ID_REV_MASK 0x0000000f
@@ -2302,7 +2339,8 @@ struct tg3 {
(X) == PHY_ID_BCM5705 || (X) == PHY_ID_BCM5750 || \
(X) == PHY_ID_BCM5752 || (X) == PHY_ID_BCM5714 || \
(X) == PHY_ID_BCM5780 || (X) == PHY_ID_BCM5787 || \
- (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM8002)
+ (X) == PHY_ID_BCM5755 || (X) == PHY_ID_BCM5756 || \
+ (X) == PHY_ID_BCM5906 || (X) == PHY_ID_BCM8002)
struct tg3_hw_stats *hw_stats;
dma_addr_t stats_mapping;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index 8d807bf603a0..e14f5a00f65a 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -289,7 +289,7 @@ static void TLan_Eisa_Cleanup( void );
static int TLan_Init( struct net_device * );
static int TLan_Open( struct net_device *dev );
static int TLan_StartTx( struct sk_buff *, struct net_device *);
-static irqreturn_t TLan_HandleInterrupt( int, void *, struct pt_regs *);
+static irqreturn_t TLan_HandleInterrupt( int, void *);
static int TLan_Close( struct net_device *);
static struct net_device_stats *TLan_GetStats( struct net_device *);
static void TLan_SetMulticastList( struct net_device *);
@@ -824,7 +824,7 @@ static void __init TLan_EisaProbe (void)
static void TLan_Poll(struct net_device *dev)
{
disable_irq(dev->irq);
- TLan_HandleInterrupt(dev->irq, dev, NULL);
+ TLan_HandleInterrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
@@ -1151,7 +1151,6 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
* occurred.
* dev_id A pointer to the device assigned to
* this irq line.
- * regs ???
*
* This function handles an interrupt generated by its
* assigned TLAN adapter. The function deactivates
@@ -1162,7 +1161,7 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev )
*
**************************************************************/
-static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t TLan_HandleInterrupt(int irq, void *dev_id)
{
u32 ack;
struct net_device *dev;
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 412390ba142e..7580bdeacadc 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -130,7 +130,7 @@ static int xl_xmit(struct sk_buff *skb, struct net_device *dev);
static void xl_dn_comp(struct net_device *dev);
static int xl_close(struct net_device *dev);
static void xl_set_rx_mode(struct net_device *dev);
-static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t xl_interrupt(int irq, void *dev_id);
static struct net_device_stats * xl_get_stats(struct net_device *dev);
static int xl_set_mac_address(struct net_device *dev, void *addr) ;
static void xl_arb_cmd(struct net_device *dev);
@@ -1042,7 +1042,7 @@ static void xl_freemem(struct net_device *dev)
return ;
}
-static irqreturn_t xl_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t xl_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct xl_private *xl_priv =(struct xl_private *)dev->priv;
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 4470025ff7f8..bfe59865b1dd 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -197,7 +197,7 @@ static void open_sap(unsigned char type, struct net_device *dev);
static void tok_set_multicast_list(struct net_device *dev);
static int tok_send_packet(struct sk_buff *skb, struct net_device *dev);
static int tok_close(struct net_device *dev);
-static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t tok_interrupt(int irq, void *dev_id);
static void initial_tok_int(struct net_device *dev);
static void tr_tx(struct net_device *dev);
static void tr_rx(struct net_device *dev);
@@ -1166,7 +1166,7 @@ static void dir_open_adapter (struct net_device *dev)
/******************************************************************************/
-static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tok_interrupt(int irq, void *dev_id)
{
unsigned char status;
/* unsigned char status_even ; */
@@ -1178,7 +1178,7 @@ static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
dev = dev_id;
#if TR_VERBOSE
- DPRINTK("Int from tok_driver, dev : %p irq%d regs=%p\n", dev,irq,regs);
+ DPRINTK("Int from tok_driver, dev : %p irq%d\n", dev,irq);
#endif
ti = (struct tok_info *) dev->priv;
if (ti->sram_phys & 1)
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 0d66700c6ced..e999feb8c0bb 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -206,8 +206,7 @@ static int streamer_open(struct net_device *dev);
static int streamer_xmit(struct sk_buff *skb, struct net_device *dev);
static int streamer_close(struct net_device *dev);
static void streamer_set_rx_mode(struct net_device *dev);
-static irqreturn_t streamer_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t streamer_interrupt(int irq, void *dev_id);
static struct net_device_stats *streamer_get_stats(struct net_device *dev);
static int streamer_set_mac_address(struct net_device *dev, void *addr);
static void streamer_arb_cmd(struct net_device *dev);
@@ -1028,7 +1027,7 @@ static void streamer_rx(struct net_device *dev)
} /* end for all completed rx descriptors */
}
-static irqreturn_t streamer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t streamer_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct streamer_private *streamer_priv =
@@ -1876,7 +1875,6 @@ static int sprintf_info(char *buffer, struct net_device *dev)
datap[size+1]=io_word & 0xff;
}
-
size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name);
size += sprintf(buffer + size,
@@ -1932,64 +1930,6 @@ static int sprintf_info(char *buffer, struct net_device *dev)
#endif
#endif
-#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
-{
- int i;
- struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
- u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
-
- switch(cmd) {
- case IOCTL_SISR_MASK:
- writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
- break;
- case IOCTL_SPIN_LOCK_TEST:
- printk(KERN_INFO "spin_lock() called.\n");
- spin_lock(&streamer_priv->streamer_lock);
- spin_unlock(&streamer_priv->streamer_lock);
- printk(KERN_INFO "spin_unlock() finished.\n");
- break;
- case IOCTL_PRINT_BDAS:
- printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
- readw(streamer_mmio + RXBDA),
- readw(streamer_mmio + RXLBDA),
- readw(streamer_mmio + TX2FDA),
- readw(streamer_mmio + TX2LFDA));
- break;
- case IOCTL_PRINT_REGISTERS:
- printk(KERN_INFO "registers:\n");
- printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n",
- readw(streamer_mmio + SISR),
- readw(streamer_mmio + MISR_RUM),
- readw(streamer_mmio + LISR),
- readw(streamer_mmio + BCTL),
- readw(streamer_mmio + BMCTL_SUM),
- readw(streamer_mmio + SISR_MASK),
- readw(streamer_mmio + MISR_MASK));
- break;
- case IOCTL_PRINT_RX_BUFS:
- printk(KERN_INFO "Print rx bufs:\n");
- for(i=0; i<STREAMER_RX_RING_SIZE; i++)
- printk(KERN_INFO "rx_ring %d status: 0x%x\n", i,
- streamer_priv->streamer_rx_ring[i].status);
- break;
- case IOCTL_PRINT_TX_BUFS:
- printk(KERN_INFO "Print tx bufs:\n");
- for(i=0; i<STREAMER_TX_RING_SIZE; i++)
- printk(KERN_INFO "tx_ring %d status: 0x%x\n", i,
- streamer_priv->streamer_tx_ring[i].status);
- break;
- case IOCTL_RX_CMD:
- streamer_rx(dev);
- printk(KERN_INFO "Sent rx command.\n");
- break;
- default:
- printk(KERN_INFO "Bad ioctl!\n");
- }
- return 0;
-}
-#endif
-
static struct pci_driver streamer_pci_driver = {
.name = "lanstreamer",
.id_table = streamer_pci_tbl,
diff --git a/drivers/net/tokenring/lanstreamer.h b/drivers/net/tokenring/lanstreamer.h
index 5557d8e1e22d..e7bb3494afc7 100644
--- a/drivers/net/tokenring/lanstreamer.h
+++ b/drivers/net/tokenring/lanstreamer.h
@@ -62,18 +62,6 @@
#include <linux/version.h>
-#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-#include <asm/ioctl.h>
-#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE
-#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1
-#define IOCTL_RX_CMD SIOCDEVPRIVATE+2
-#define IOCTL_TX_CMD SIOCDEVPRIVATE+3
-#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4
-#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5
-#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6
-#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7
-#endif
-
/* MAX_INTR - the maximum number of times we can loop
* inside the interrupt function before returning
* control to the OS (maximum value is 256)
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index 666bbaaae82f..ed274d6909d0 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -70,7 +70,7 @@ static void madgemc_setregpage(struct net_device *dev, int page);
static void madgemc_setsifsel(struct net_device *dev, int val);
static void madgemc_setint(struct net_device *dev, int val);
-static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t madgemc_interrupt(int irq, void *dev_id);
/*
* These work around paging, however they don't guarentee you're on the
@@ -417,7 +417,7 @@ getout:
* exhausted all contiguous interrupts.
*
*/
-static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t madgemc_interrupt(int irq, void *dev_id)
{
int pending,reg1;
struct net_device *dev;
@@ -451,7 +451,7 @@ static irqreturn_t madgemc_interrupt(int irq, void *dev_id, struct pt_regs *regs
outb(reg1, dev->base_addr + MC_CONTROL_REG1);
/* Continue handling as normal */
- tms380tr_interrupt(irq, dev_id, regs);
+ tms380tr_interrupt(irq, dev_id);
pending = SIFREADW(SIFSTS); /* restart - the SIF way */
diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c
index 85831484bc40..cd142d0302bc 100644
--- a/drivers/net/tokenring/olympic.c
+++ b/drivers/net/tokenring/olympic.c
@@ -185,7 +185,7 @@ static int olympic_xmit(struct sk_buff *skb, struct net_device *dev);
static int olympic_close(struct net_device *dev);
static void olympic_set_rx_mode(struct net_device *dev);
static void olympic_freemem(struct net_device *dev) ;
-static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t olympic_interrupt(int irq, void *dev_id);
static struct net_device_stats * olympic_get_stats(struct net_device *dev);
static int olympic_set_mac_address(struct net_device *dev, void *addr) ;
static void olympic_arb_cmd(struct net_device *dev);
@@ -925,7 +925,7 @@ static void olympic_freemem(struct net_device *dev)
return ;
}
-static irqreturn_t olympic_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t olympic_interrupt(int irq, void *dev_id)
{
struct net_device *dev= (struct net_device *)dev_id;
struct olympic_private *olympic_priv=(struct olympic_private *)dev->priv;
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 85a7f797d343..46dabdb12071 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -141,7 +141,7 @@ static int smctr_init_shared_memory(struct net_device *dev);
static int smctr_init_tx_bdbs(struct net_device *dev);
static int smctr_init_tx_fcbs(struct net_device *dev);
static int smctr_internal_self_test(struct net_device *dev);
-static irqreturn_t smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t smctr_interrupt(int irq, void *dev_id);
static int smctr_issue_enable_int_cmd(struct net_device *dev,
__u16 interrupt_enable_mask);
static int smctr_issue_int_ack(struct net_device *dev, __u16 iack_code,
@@ -1980,7 +1980,7 @@ static int smctr_internal_self_test(struct net_device *dev)
/*
* The typical workload of the driver: Handle the network interface interrupts.
*/
-static irqreturn_t smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t smctr_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *tp;
@@ -1990,15 +1990,8 @@ static irqreturn_t smctr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
__u8 isb_type, isb_subtype;
__u16 isb_index;
- if(dev == NULL)
- {
- printk(KERN_CRIT "%s: irq %d for unknown device.\n", dev->name, irq);
- return IRQ_NONE;
- }
-
ioaddr = dev->base_addr;
tp = netdev_priv(dev);
-
if(tp->status == NOT_INITIALIZED)
return IRQ_NONE;
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index c1925590a0e1..ea797ca2b988 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -744,18 +744,13 @@ static void tms380tr_timer_chk(unsigned long data)
/*
* The typical workload of the driver: Handle the network interface interrupts.
*/
-irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t tms380tr_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct net_local *tp;
unsigned short irq_type;
int handled = 0;
- if(dev == NULL) {
- printk(KERN_INFO "%s: irq %d for unknown device.\n", dev->name, irq);
- return IRQ_NONE;
- }
-
tp = netdev_priv(dev);
irq_type = SIFREADW(SIFSTS);
diff --git a/drivers/net/tokenring/tms380tr.h b/drivers/net/tokenring/tms380tr.h
index 30452c67bb68..2a16078ac3fd 100644
--- a/drivers/net/tokenring/tms380tr.h
+++ b/drivers/net/tokenring/tms380tr.h
@@ -16,7 +16,7 @@
/* module prototypes */
int tms380tr_open(struct net_device *dev);
int tms380tr_close(struct net_device *dev);
-irqreturn_t tms380tr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t tms380tr_interrupt(int irq, void *dev_id);
int tmsdev_init(struct net_device *dev, struct device *pdev);
void tmsdev_term(struct net_device *dev);
void tms380tr_wait(unsigned long time);
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index 7d3e270c4f45..3b2f00b9b7bd 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -224,8 +224,7 @@ static void __devexit tms_pci_detach (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
- if (!dev)
- BUG();
+ BUG_ON(!dev);
unregister_netdev(dev);
release_region(dev->base_addr, TMS_PCI_IO_EXTENT);
free_irq(dev->irq, dev);
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index e1b48bd86646..f6b3a94e97bf 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -484,7 +484,7 @@ rx_next:
de->rx_tail = rx_tail;
}
-static irqreturn_t de_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t de_interrupt (int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct de_private *de = dev->priv;
@@ -1730,7 +1730,7 @@ static void __init de21040_get_media_info(struct de_private *de)
}
/* Note: this routine returns extra data bits for size detection. */
-static unsigned __init tulip_read_eeprom(void __iomem *regs, int location, int addr_len)
+static unsigned __devinit tulip_read_eeprom(void __iomem *regs, int location, int addr_len)
{
int i;
unsigned retval = 0;
@@ -1926,7 +1926,7 @@ bad_srom:
goto fill_defaults;
}
-static int __init de_init_one (struct pci_dev *pdev,
+static int __devinit de_init_one (struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct net_device *dev;
@@ -2082,7 +2082,7 @@ err_out_free:
return rc;
}
-static void __exit de_remove_one (struct pci_dev *pdev)
+static void __devexit de_remove_one (struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct de_private *de = dev->priv;
@@ -2164,7 +2164,7 @@ static struct pci_driver de_driver = {
.name = DRV_NAME,
.id_table = de_pci_tbl,
.probe = de_init_one,
- .remove = __exit_p(de_remove_one),
+ .remove = __devexit_p(de_remove_one),
#ifdef CONFIG_PM
.suspend = de_suspend,
.resume = de_resume,
diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
index e661d0a9cc64..3f4b6408b755 100644
--- a/drivers/net/tulip/de4x5.c
+++ b/drivers/net/tulip/de4x5.c
@@ -896,7 +896,7 @@ static struct {
*/
static int de4x5_open(struct net_device *dev);
static int de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t de4x5_interrupt(int irq, void *dev_id);
static int de4x5_close(struct net_device *dev);
static struct net_device_stats *de4x5_get_stats(struct net_device *dev);
static void de4x5_local_stats(struct net_device *dev, char *buf, int pkt_len);
@@ -1538,18 +1538,14 @@ de4x5_queue_pkt(struct sk_buff *skb, struct net_device *dev)
** interrupt is asserted and this routine entered.
*/
static irqreturn_t
-de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+de4x5_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct de4x5_private *lp;
s32 imr, omr, sts, limit;
u_long iobase;
unsigned int handled = 0;
- if (dev == NULL) {
- printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
lp = netdev_priv(dev);
spin_lock(&lp->lock);
iobase = dev->base_addr;
@@ -2114,6 +2110,7 @@ static struct eisa_device_id de4x5_eisa_ids[] = {
{ "DEC4250", 0 }, /* 0 is the board name index... */
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, de4x5_eisa_ids);
static struct eisa_driver de4x5_eisa_driver = {
.id_table = de4x5_eisa_ids,
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index ccf2c225f084..4dd8a0bae860 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -300,7 +300,7 @@ static struct net_device_stats * dmfe_get_stats(struct DEVICE *);
static void dmfe_set_filter_mode(struct DEVICE *);
static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long ,int);
-static irqreturn_t dmfe_interrupt(int , void *, struct pt_regs *);
+static irqreturn_t dmfe_interrupt(int , void *);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void poll_dmfe (struct net_device *dev);
#endif
@@ -735,7 +735,7 @@ static int dmfe_stop(struct DEVICE *dev)
* receive the packet to upper layer, free the transmitted packet
*/
-static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dmfe_interrupt(int irq, void *dev_id)
{
struct DEVICE *dev = dev_id;
struct dmfe_board_info *db = netdev_priv(dev);
@@ -806,7 +806,7 @@ static void poll_dmfe (struct net_device *dev)
/* disable_irq here is not very nice, but with the lockless
interrupt handler we have no other choice. */
disable_irq(dev->irq);
- dmfe_interrupt (dev->irq, dev, NULL);
+ dmfe_interrupt (dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index 7f8f5d42a761..e3488d7b8ede 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -496,7 +496,7 @@ static inline unsigned int phy_interrupt (struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+irqreturn_t tulip_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *)dev_instance;
struct tulip_private *tp = netdev_priv(dev);
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h
index 25668ddb1f7e..ad107f45c7b1 100644
--- a/drivers/net/tulip/tulip.h
+++ b/drivers/net/tulip/tulip.h
@@ -424,7 +424,7 @@ int tulip_read_eeprom(struct net_device *dev, int location, int addr_len);
/* interrupt.c */
extern unsigned int tulip_max_interrupt_work;
extern int tulip_rx_copybreak;
-irqreturn_t tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+irqreturn_t tulip_interrupt(int irq, void *dev_instance);
int tulip_refill_rx(struct net_device *dev);
#ifdef CONFIG_TULIP_NAPI
int tulip_poll(struct net_device *dev, int *budget);
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index 831919a81918..0aee618f883c 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -1823,7 +1823,7 @@ static void poll_tulip (struct net_device *dev)
/* disable_irq here is not very nice, but with the lockless
interrupt handler we have no other choice. */
disable_irq(dev->irq);
- tulip_interrupt (dev->irq, dev, NULL);
+ tulip_interrupt (dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c
index 0b176be51eb3..229158e8e4be 100644
--- a/drivers/net/tulip/uli526x.c
+++ b/drivers/net/tulip/uli526x.c
@@ -224,7 +224,7 @@ static struct net_device_stats * uli526x_get_stats(struct net_device *);
static void uli526x_set_filter_mode(struct net_device *);
static const struct ethtool_ops netdev_ethtool_ops;
static u16 read_srom_word(long, int);
-static irqreturn_t uli526x_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t uli526x_interrupt(int, void *);
static void uli526x_descriptor_init(struct uli526x_board_info *, unsigned long);
static void allocate_rx_buffer(struct uli526x_board_info *);
static void update_cr6(u32, unsigned long);
@@ -659,7 +659,7 @@ static int uli526x_stop(struct net_device *dev)
* receive the packet to upper layer, free the transmitted packet
*/
-static irqreturn_t uli526x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t uli526x_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct uli526x_board_info *db = netdev_priv(dev);
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index 2fca1ee24f5a..002a05e0722f 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -332,7 +332,7 @@ static void tx_timeout(struct net_device *dev);
static int alloc_ringdesc(struct net_device *dev);
static void free_ringdesc(struct netdev_private *np);
static int start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t intr_handler(int irq, void *dev_instance);
static void netdev_error(struct net_device *dev, int intr_status);
static int netdev_rx(struct net_device *dev);
static u32 __set_rx_mode(struct net_device *dev);
@@ -1110,7 +1110,7 @@ static void netdev_tx_done(struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t intr_handler(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *)dev_instance;
struct netdev_private *np = netdev_priv(dev);
diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
index 629eac645289..61d313049dd0 100644
--- a/drivers/net/tulip/xircom_cb.c
+++ b/drivers/net/tulip/xircom_cb.c
@@ -114,7 +114,7 @@ struct xircom_private {
/* Function prototypes */
static int xircom_probe(struct pci_dev *pdev, const struct pci_device_id *id);
static void xircom_remove(struct pci_dev *pdev);
-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t xircom_interrupt(int irq, void *dev_instance);
static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int xircom_open(struct net_device *dev);
static int xircom_close(struct net_device *dev);
@@ -334,7 +334,7 @@ static void __devexit xircom_remove(struct pci_dev *pdev)
leave("xircom_remove");
}
-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct xircom_private *card = netdev_priv(dev);
@@ -513,7 +513,7 @@ static struct net_device_stats *xircom_get_stats(struct net_device *dev)
static void xircom_poll_controller(struct net_device *dev)
{
disable_irq(dev->irq);
- xircom_interrupt(dev->irq, dev, NULL);
+ xircom_interrupt(dev->irq, dev);
enable_irq(dev->irq);
}
#endif
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index 312788caa4c6..a998c5d0ae9c 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -328,7 +328,7 @@ static void xircom_init_ring(struct net_device *dev);
static int xircom_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int xircom_rx(struct net_device *dev);
static void xircom_media_change(struct net_device *dev);
-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t xircom_interrupt(int irq, void *dev_instance);
static int xircom_close(struct net_device *dev);
static struct net_device_stats *xircom_get_stats(struct net_device *dev);
static int xircom_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -1044,7 +1044,7 @@ static void check_duplex(struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t xircom_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t xircom_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct xircom_private *tp = netdev_priv(dev);
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index de8da6dee1b0..151a2e10e4f3 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -288,11 +288,10 @@ static inline size_t iov_total(const struct iovec *iv, unsigned long count)
return len;
}
-/* Writev */
-static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
- unsigned long count, loff_t *pos)
+static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
+ unsigned long count, loff_t pos)
{
- struct tun_struct *tun = file->private_data;
+ struct tun_struct *tun = iocb->ki_filp->private_data;
if (!tun)
return -EBADFD;
@@ -302,14 +301,6 @@ static ssize_t tun_chr_writev(struct file * file, const struct iovec *iv,
return tun_get_user(tun, (struct iovec *) iv, iov_total(iv, count));
}
-/* Write */
-static ssize_t tun_chr_write(struct file * file, const char __user * buf,
- size_t count, loff_t *pos)
-{
- struct iovec iv = { (void __user *) buf, count };
- return tun_chr_writev(file, &iv, 1, pos);
-}
-
/* Put packet to the user space buffer */
static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
struct sk_buff *skb,
@@ -343,10 +334,10 @@ static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
return total;
}
-/* Readv */
-static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
- unsigned long count, loff_t *pos)
+static ssize_t tun_chr_aio_read(struct kiocb *iocb, const struct iovec *iv,
+ unsigned long count, loff_t pos)
{
+ struct file *file = iocb->ki_filp;
struct tun_struct *tun = file->private_data;
DECLARE_WAITQUEUE(wait, current);
struct sk_buff *skb;
@@ -426,14 +417,6 @@ static ssize_t tun_chr_readv(struct file *file, const struct iovec *iv,
return ret;
}
-/* Read */
-static ssize_t tun_chr_read(struct file * file, char __user * buf,
- size_t count, loff_t *pos)
-{
- struct iovec iv = { buf, count };
- return tun_chr_readv(file, &iv, 1, pos);
-}
-
static void tun_setup(struct net_device *dev)
{
struct tun_struct *tun = netdev_priv(dev);
@@ -714,7 +697,7 @@ static int tun_chr_fasync(int fd, struct file *file, int on)
return ret;
if (on) {
- ret = f_setown(file, current->pid, 0);
+ ret = __f_setown(file, task_pid(current), PIDTYPE_PID, 0);
if (ret)
return ret;
tun->flags |= TUN_FASYNC;
@@ -764,10 +747,10 @@ static int tun_chr_close(struct inode *inode, struct file *file)
static struct file_operations tun_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .read = tun_chr_read,
- .readv = tun_chr_readv,
- .write = tun_chr_write,
- .writev = tun_chr_writev,
+ .read = do_sync_read,
+ .aio_read = tun_chr_aio_read,
+ .write = do_sync_write,
+ .aio_write = tun_chr_aio_write,
.poll = tun_chr_poll,
.ioctl = tun_chr_ioctl,
.open = tun_chr_open,
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 8f6f6fd8b87d..3bf9e630404f 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -333,11 +333,7 @@ enum state_values {
#define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)
#define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
-#define typhoon_synchronize_irq(x) synchronize_irq()
-#else
#define typhoon_synchronize_irq(x) synchronize_irq(x)
-#endif
#if defined(NETIF_F_TSO)
#define skb_tso_size(x) (skb_shinfo(x)->gso_size)
@@ -1830,7 +1826,7 @@ typhoon_poll(struct net_device *dev, int *total_budget)
}
static irqreturn_t
-typhoon_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
+typhoon_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = (struct net_device *) dev_instance;
struct typhoon *tp = dev->priv;
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index 700ebd7d1457..12cd7b561f35 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3844,8 +3844,7 @@ static int ucc_geth_poll(struct net_device *dev, int *budget)
}
#endif /* CONFIG_UGETH_NAPI */
-static irqreturn_t ucc_geth_irq_handler(int irq, void *info,
- struct pt_regs *regs)
+static irqreturn_t ucc_geth_irq_handler(int irq, void *info)
{
struct net_device *dev = (struct net_device *)info;
ucc_geth_private_t *ugeth = netdev_priv(dev);
@@ -3910,7 +3909,7 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info,
return IRQ_HANDLED;
}
-static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t phy_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
ucc_geth_private_t *ugeth = netdev_priv(dev);
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c
index f91028c5386d..67260eb3188a 100644
--- a/drivers/net/ucc_geth_phy.c
+++ b/drivers/net/ucc_geth_phy.c
@@ -17,7 +17,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index cbebf1b96e9d..ebbda1d8f542 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -404,7 +404,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int location, int val
static int rhine_open(struct net_device *dev);
static void rhine_tx_timeout(struct net_device *dev);
static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t rhine_interrupt(int irq, void *dev_instance);
static void rhine_tx(struct net_device *dev);
static int rhine_rx(struct net_device *dev, int limit);
static void rhine_error(struct net_device *dev, int intr_status);
@@ -569,7 +569,7 @@ static void __devinit rhine_reload_eeprom(long pioaddr, struct net_device *dev)
static void rhine_poll(struct net_device *dev)
{
disable_irq(dev->irq);
- rhine_interrupt(dev->irq, (void *)dev, NULL);
+ rhine_interrupt(dev->irq, (void *)dev);
enable_irq(dev->irq);
}
#endif
@@ -1290,7 +1290,7 @@ static int rhine_start_tx(struct sk_buff *skb, struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t rhine_interrupt(int irq, void *dev_instance, struct pt_regs *rgs)
+static irqreturn_t rhine_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct rhine_private *rp = netdev_priv(dev);
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 7d8808ce541f..74f894795a1b 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -236,7 +236,7 @@ static void velocity_print_info(struct velocity_info *vptr);
static int velocity_open(struct net_device *dev);
static int velocity_change_mtu(struct net_device *dev, int mtu);
static int velocity_xmit(struct sk_buff *skb, struct net_device *dev);
-static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs);
+static int velocity_intr(int irq, void *dev_instance);
static void velocity_set_multi(struct net_device *dev);
static struct net_device_stats *velocity_get_stats(struct net_device *dev);
static int velocity_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -2036,7 +2036,6 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
* velocity_intr - interrupt callback
* @irq: interrupt number
* @dev_instance: interrupting device
- * @pt_regs: CPU register state at interrupt
*
* Called whenever an interrupt is generated by the velocity
* adapter IRQ line. We may not be the source of the interrupt
@@ -2044,7 +2043,7 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
* efficiently as possible.
*/
-static int velocity_intr(int irq, void *dev_instance, struct pt_regs *regs)
+static int velocity_intr(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct velocity_info *vptr = netdev_priv(dev);
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 54b8e492ef97..58b7efbb0750 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -154,7 +154,7 @@ config HDLC
If unsure, say N.
config HDLC_RAW
- bool "Raw HDLC support"
+ tristate "Raw HDLC support"
depends on HDLC
help
Generic HDLC driver supporting raw HDLC over WAN connections.
@@ -162,7 +162,7 @@ config HDLC_RAW
If unsure, say N.
config HDLC_RAW_ETH
- bool "Raw HDLC Ethernet device support"
+ tristate "Raw HDLC Ethernet device support"
depends on HDLC
help
Generic HDLC driver supporting raw HDLC Ethernet device emulation
@@ -173,7 +173,7 @@ config HDLC_RAW_ETH
If unsure, say N.
config HDLC_CISCO
- bool "Cisco HDLC support"
+ tristate "Cisco HDLC support"
depends on HDLC
help
Generic HDLC driver supporting Cisco HDLC over WAN connections.
@@ -181,7 +181,7 @@ config HDLC_CISCO
If unsure, say N.
config HDLC_FR
- bool "Frame Relay support"
+ tristate "Frame Relay support"
depends on HDLC
help
Generic HDLC driver supporting Frame Relay over WAN connections.
@@ -189,7 +189,7 @@ config HDLC_FR
If unsure, say N.
config HDLC_PPP
- bool "Synchronous Point-to-Point Protocol (PPP) support"
+ tristate "Synchronous Point-to-Point Protocol (PPP) support"
depends on HDLC
help
Generic HDLC driver supporting PPP over WAN connections.
@@ -197,7 +197,7 @@ config HDLC_PPP
If unsure, say N.
config HDLC_X25
- bool "X.25 protocol support"
+ tristate "X.25 protocol support"
depends on HDLC && (LAPB=m && HDLC=m || LAPB=y)
help
Generic HDLC driver supporting X.25 over WAN connections.
diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile
index 316ca6869d5e..83ec2c87ba3f 100644
--- a/drivers/net/wan/Makefile
+++ b/drivers/net/wan/Makefile
@@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o
cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
cyclomx-objs := $(cyclomx-y)
-hdlc-y := hdlc_generic.o
-hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o
-hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
-hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
-hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o
-hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
-hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o
-hdlc-objs := $(hdlc-y)
+obj-$(CONFIG_HDLC) += hdlc.o
+obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
+obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
+obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
+obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
+obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o
+obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
pc300-y := pc300_drv.o
pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
@@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
obj-$(CONFIG_LAPBETHER) += lapbether.o
obj-$(CONFIG_SBNI) += sbni.o
obj-$(CONFIG_PC300) += pc300.o
-obj-$(CONFIG_HDLC) += hdlc.o
-ifeq ($(CONFIG_HDLC_PPP),y)
- obj-$(CONFIG_HDLC) += syncppp.o
-endif
obj-$(CONFIG_N2) += n2.o
obj-$(CONFIG_C101) += c101.o
obj-$(CONFIG_WANXL) += wanxl.o
diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
index 1f95b4864ea1..e1bf8b93f958 100644
--- a/drivers/net/wan/cosa.c
+++ b/drivers/net/wan/cosa.c
@@ -345,7 +345,7 @@ static void put_driver_status(struct cosa_data *cosa);
static void put_driver_status_nolock(struct cosa_data *cosa);
/* Interrupt handling */
-static irqreturn_t cosa_interrupt(int irq, void *cosa, struct pt_regs *regs);
+static irqreturn_t cosa_interrupt(int irq, void *cosa);
/* I/O ops debugging */
#ifdef DEBUG_IO
@@ -1972,7 +1972,7 @@ out:
spin_unlock_irqrestore(&cosa->lock, flags);
}
-static irqreturn_t cosa_interrupt(int irq, void *cosa_, struct pt_regs *regs)
+static irqreturn_t cosa_interrupt(int irq, void *cosa_)
{
unsigned status;
int count = 0;
diff --git a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
index a5e7ce1bd16a..6e5f1c898517 100644
--- a/drivers/net/wan/cycx_main.c
+++ b/drivers/net/wan/cycx_main.c
@@ -74,7 +74,7 @@ static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf);
static int cycx_wan_shutdown(struct wan_device *wandev);
/* Miscellaneous functions */
-static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t cycx_isr(int irq, void *dev_id);
/* Global Data
* Note: All data must be explicitly initialized!!!
@@ -301,11 +301,11 @@ out: return ret;
* o acknowledge Cyclom 2X hardware interrupt.
* o call protocol-specific interrupt service routine, if any.
*/
-static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cycx_isr(int irq, void *dev_id)
{
- struct cycx_device *card = (struct cycx_device *)dev_id;
+ struct cycx_device *card = dev_id;
- if (!card || card->wandev.state == WAN_UNCONFIGURED)
+ if (card->wandev.state == WAN_UNCONFIGURED)
goto out;
if (card->in_isr) {
diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c
index af4d4155905b..25021a7992a9 100644
--- a/drivers/net/wan/dscc4.c
+++ b/drivers/net/wan/dscc4.c
@@ -365,7 +365,7 @@ static int dscc4_init_ring(struct net_device *);
static void dscc4_release_ring(struct dscc4_dev_priv *);
static void dscc4_timer(unsigned long);
static void dscc4_tx_timeout(struct net_device *);
-static irqreturn_t dscc4_irq(int irq, void *dev_id, struct pt_regs *ptregs);
+static irqreturn_t dscc4_irq(int irq, void *dev_id);
static int dscc4_hdlc_attach(struct net_device *, unsigned short, unsigned short);
static int dscc4_set_iface(struct dscc4_dev_priv *, struct net_device *);
#ifdef DSCC4_POLLING
@@ -1476,7 +1476,7 @@ static int dscc4_set_iface(struct dscc4_dev_priv *dpriv, struct net_device *dev)
return ret;
}
-static irqreturn_t dscc4_irq(int irq, void *token, struct pt_regs *ptregs)
+static irqreturn_t dscc4_irq(int irq, void *token)
{
struct dscc4_dev_priv *root = token;
struct dscc4_pci_priv *priv;
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 564351aafa41..c45d6a83339d 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -1498,7 +1498,7 @@ do_bottom_half_rx(struct fst_card_info *card)
* Dev_id is our fst_card_info pointer
*/
static irqreturn_t
-fst_intr(int irq, void *dev_id, struct pt_regs *regs)
+fst_intr(int irq, void *dev_id)
{
struct fst_card_info *card;
struct fst_port_info *port;
diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd6457x.c
index dce2bb317b82..8d0a1f2f00e5 100644
--- a/drivers/net/wan/hd6457x.c
+++ b/drivers/net/wan/hd6457x.c
@@ -424,7 +424,7 @@ static inline void sca_tx_intr(port_t *port)
-static irqreturn_t sca_intr(int irq, void* dev_id, struct pt_regs *regs)
+static irqreturn_t sca_intr(int irq, void* dev_id)
{
card_t *card = dev_id;
int i;
diff --git a/drivers/net/wan/hdlc_generic.c b/drivers/net/wan/hdlc.c
index 04ca1f7b6424..db354e0edbe5 100644
--- a/drivers/net/wan/hdlc_generic.c
+++ b/drivers/net/wan/hdlc.c
@@ -1,7 +1,7 @@
/*
* Generic HDLC support routines for Linux
*
- * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -17,9 +17,9 @@
* Use sethdlc utility to set line parameters, protocol and PVCs
*
* How does it work:
- * - proto.open(), close(), start(), stop() calls are serialized.
+ * - proto->open(), close(), start(), stop() calls are serialized.
* The order is: open, [ start, stop ... ] close ...
- * - proto.start() and stop() are called with spin_lock_irq held.
+ * - proto->start() and stop() are called with spin_lock_irq held.
*/
#include <linux/module.h>
@@ -38,10 +38,12 @@
#include <linux/hdlc.h>
-static const char* version = "HDLC support module revision 1.19";
+static const char* version = "HDLC support module revision 1.20";
#undef DEBUG_LINK
+static struct hdlc_proto *first_proto = NULL;
+
static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
{
@@ -63,11 +65,11 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *p, struct net_device *orig_dev)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->proto.netif_rx)
- return hdlc->proto.netif_rx(skb);
+ struct hdlc_device_desc *desc = dev_to_desc(dev);
+ if (desc->netif_rx)
+ return desc->netif_rx(skb);
- hdlc->stats.rx_dropped++; /* Shouldn't happen */
+ desc->stats.rx_dropped++; /* Shouldn't happen */
dev_kfree_skb(skb);
return NET_RX_DROP;
}
@@ -77,8 +79,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
static inline void hdlc_proto_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->proto.start)
- return hdlc->proto.start(dev);
+ if (hdlc->proto->start)
+ return hdlc->proto->start(dev);
}
@@ -86,8 +88,8 @@ static inline void hdlc_proto_start(struct net_device *dev)
static inline void hdlc_proto_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->proto.stop)
- return hdlc->proto.stop(dev);
+ if (hdlc->proto->stop)
+ return hdlc->proto->stop(dev);
}
@@ -144,15 +146,15 @@ int hdlc_open(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
- printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n",
+ printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,
hdlc->carrier, hdlc->open);
#endif
- if (hdlc->proto.id == -1)
+ if (hdlc->proto == NULL)
return -ENOSYS; /* no protocol attached */
- if (hdlc->proto.open) {
- int result = hdlc->proto.open(dev);
+ if (hdlc->proto->open) {
+ int result = hdlc->proto->open(dev);
if (result)
return result;
}
@@ -178,7 +180,7 @@ void hdlc_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
- printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n",
+ printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,
hdlc->carrier, hdlc->open);
#endif
@@ -190,68 +192,34 @@ void hdlc_close(struct net_device *dev)
spin_unlock_irq(&hdlc->state_lock);
- if (hdlc->proto.close)
- hdlc->proto.close(dev);
+ if (hdlc->proto->close)
+ hdlc->proto->close(dev);
}
-#ifndef CONFIG_HDLC_RAW
-#define hdlc_raw_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_RAW_ETH
-#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_PPP
-#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_CISCO
-#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_FR
-#define hdlc_fr_ioctl(dev, ifr) -ENOSYS
-#endif
-
-#ifndef CONFIG_HDLC_X25
-#define hdlc_x25_ioctl(dev, ifr) -ENOSYS
-#endif
-
-
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
- unsigned int proto;
+ struct hdlc_proto *proto = first_proto;
+ int result;
if (cmd != SIOCWANDEV)
return -EINVAL;
- switch(ifr->ifr_settings.type) {
- case IF_PROTO_HDLC:
- case IF_PROTO_HDLC_ETH:
- case IF_PROTO_PPP:
- case IF_PROTO_CISCO:
- case IF_PROTO_FR:
- case IF_PROTO_X25:
- proto = ifr->ifr_settings.type;
- break;
-
- default:
- proto = hdlc->proto.id;
+ if (dev_to_hdlc(dev)->proto) {
+ result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr);
+ if (result != -EINVAL)
+ return result;
}
- switch(proto) {
- case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr);
- case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr);
- case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr);
- case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr);
- case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr);
- case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr);
- default: return -EINVAL;
+ /* Not handled by currently attached protocol (if any) */
+
+ while (proto) {
+ if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
+ return result;
+ proto = proto->next;
}
+ return -EINVAL;
}
void hdlc_setup(struct net_device *dev)
@@ -267,8 +235,6 @@ void hdlc_setup(struct net_device *dev)
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
- hdlc->proto.id = -1;
- hdlc->proto.detach = NULL;
hdlc->carrier = 1;
hdlc->open = 0;
spin_lock_init(&hdlc->state_lock);
@@ -277,7 +243,8 @@ void hdlc_setup(struct net_device *dev)
struct net_device *alloc_hdlcdev(void *priv)
{
struct net_device *dev;
- dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup);
+ dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
+ sizeof(hdlc_device), "hdlc%d", hdlc_setup);
if (dev)
dev_to_hdlc(dev)->priv = priv;
return dev;
@@ -286,13 +253,71 @@ struct net_device *alloc_hdlcdev(void *priv)
void unregister_hdlc_device(struct net_device *dev)
{
rtnl_lock();
- hdlc_proto_detach(dev_to_hdlc(dev));
unregister_netdevice(dev);
+ detach_hdlc_protocol(dev);
rtnl_unlock();
}
+int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
+ int (*rx)(struct sk_buff *skb), size_t size)
+{
+ detach_hdlc_protocol(dev);
+
+ if (!try_module_get(proto->module))
+ return -ENOSYS;
+
+ if (size)
+ if ((dev_to_hdlc(dev)->state = kmalloc(size,
+ GFP_KERNEL)) == NULL) {
+ printk(KERN_WARNING "Memory squeeze on"
+ " hdlc_proto_attach()\n");
+ module_put(proto->module);
+ return -ENOBUFS;
+ }
+ dev_to_hdlc(dev)->proto = proto;
+ dev_to_desc(dev)->netif_rx = rx;
+ return 0;
+}
+
+
+void detach_hdlc_protocol(struct net_device *dev)
+{
+ hdlc_device *hdlc = dev_to_hdlc(dev);
+
+ if (hdlc->proto) {
+ if (hdlc->proto->detach)
+ hdlc->proto->detach(dev);
+ module_put(hdlc->proto->module);
+ hdlc->proto = NULL;
+ }
+ kfree(hdlc->state);
+ hdlc->state = NULL;
+}
+
+
+void register_hdlc_protocol(struct hdlc_proto *proto)
+{
+ proto->next = first_proto;
+ first_proto = proto;
+}
+
+
+void unregister_hdlc_protocol(struct hdlc_proto *proto)
+{
+ struct hdlc_proto **p = &first_proto;
+ while (*p) {
+ if (*p == proto) {
+ *p = proto->next;
+ return;
+ }
+ p = &((*p)->next);
+ }
+}
+
+
+
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
MODULE_DESCRIPTION("HDLC support module");
MODULE_LICENSE("GPL v2");
@@ -303,6 +328,10 @@ EXPORT_SYMBOL(hdlc_ioctl);
EXPORT_SYMBOL(hdlc_setup);
EXPORT_SYMBOL(alloc_hdlcdev);
EXPORT_SYMBOL(unregister_hdlc_device);
+EXPORT_SYMBOL(register_hdlc_protocol);
+EXPORT_SYMBOL(unregister_hdlc_protocol);
+EXPORT_SYMBOL(attach_hdlc_protocol);
+EXPORT_SYMBOL(detach_hdlc_protocol);
static struct packet_type hdlc_packet_type = {
.type = __constant_htons(ETH_P_HDLC),
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index f289daba0c7b..b0bc5ddcf1b1 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* Cisco HDLC support
*
- * Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2000 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -34,17 +34,56 @@
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
+struct hdlc_header {
+ u8 address;
+ u8 control;
+ u16 protocol;
+}__attribute__ ((packed));
+
+
+struct cisco_packet {
+ u32 type; /* code */
+ u32 par1;
+ u32 par2;
+ u16 rel; /* reliability */
+ u32 time;
+}__attribute__ ((packed));
+#define CISCO_PACKET_LEN 18
+#define CISCO_BIG_PACKET_LEN 20
+
+
+struct cisco_state {
+ cisco_proto settings;
+
+ struct timer_list timer;
+ unsigned long last_poll;
+ int up;
+ int request_sent;
+ u32 txseq; /* TX sequence number */
+ u32 rxseq; /* RX sequence number */
+};
+
+
+static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
+
+
+static inline struct cisco_state * state(hdlc_device *hdlc)
+{
+ return(struct cisco_state *)(hdlc->state);
+}
+
+
static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
u16 type, void *daddr, void *saddr,
unsigned int len)
{
- hdlc_header *data;
+ struct hdlc_header *data;
#ifdef DEBUG_HARD_HEADER
printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
#endif
- skb_push(skb, sizeof(hdlc_header));
- data = (hdlc_header*)skb->data;
+ skb_push(skb, sizeof(struct hdlc_header));
+ data = (struct hdlc_header*)skb->data;
if (type == CISCO_KEEPALIVE)
data->address = CISCO_MULTICAST;
else
@@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
data->control = 0;
data->protocol = htons(type);
- return sizeof(hdlc_header);
+ return sizeof(struct hdlc_header);
}
@@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
u32 par1, u32 par2)
{
struct sk_buff *skb;
- cisco_packet *data;
+ struct cisco_packet *data;
- skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
+ skb = dev_alloc_skb(sizeof(struct hdlc_header) +
+ sizeof(struct cisco_packet));
if (!skb) {
printk(KERN_WARNING
"%s: Memory squeeze on cisco_keepalive_send()\n",
@@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
}
skb_reserve(skb, 4);
cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
- data = (cisco_packet*)(skb->data + 4);
+ data = (struct cisco_packet*)(skb->data + 4);
data->type = htonl(type);
data->par1 = htonl(par1);
@@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
/* we will need do_div here if 1000 % HZ != 0 */
data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
- skb_put(skb, sizeof(cisco_packet));
+ skb_put(skb, sizeof(struct cisco_packet));
skb->priority = TC_PRIO_CONTROL;
skb->dev = dev;
skb->nh.raw = skb->data;
@@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
{
- hdlc_header *data = (hdlc_header*)skb->data;
+ struct hdlc_header *data = (struct hdlc_header*)skb->data;
- if (skb->len < sizeof(hdlc_header))
+ if (skb->len < sizeof(struct hdlc_header))
return __constant_htons(ETH_P_HDLC);
if (data->address != CISCO_MULTICAST &&
@@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
case __constant_htons(ETH_P_IP):
case __constant_htons(ETH_P_IPX):
case __constant_htons(ETH_P_IPV6):
- skb_pull(skb, sizeof(hdlc_header));
+ skb_pull(skb, sizeof(struct hdlc_header));
return data->protocol;
default:
return __constant_htons(ETH_P_HDLC);
@@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
hdlc_device *hdlc = dev_to_hdlc(dev);
- hdlc_header *data = (hdlc_header*)skb->data;
- cisco_packet *cisco_data;
+ struct hdlc_header *data = (struct hdlc_header*)skb->data;
+ struct cisco_packet *cisco_data;
struct in_device *in_dev;
- u32 addr, mask;
+ __be32 addr, mask;
- if (skb->len < sizeof(hdlc_header))
+ if (skb->len < sizeof(struct hdlc_header))
goto rx_error;
if (data->address != CISCO_MULTICAST &&
@@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb)
return NET_RX_SUCCESS;
case CISCO_KEEPALIVE:
- if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN &&
- skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
- printk(KERN_INFO "%s: Invalid length of Cisco "
- "control packet (%d bytes)\n",
- dev->name, skb->len);
+ if ((skb->len != sizeof(struct hdlc_header) +
+ CISCO_PACKET_LEN) &&
+ (skb->len != sizeof(struct hdlc_header) +
+ CISCO_BIG_PACKET_LEN)) {
+ printk(KERN_INFO "%s: Invalid length of Cisco control"
+ " packet (%d bytes)\n", dev->name, skb->len);
goto rx_error;
}
- cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header));
+ cisco_data = (struct cisco_packet*)(skb->data + sizeof
+ (struct hdlc_header));
switch(ntohl (cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
@@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb)
goto rx_error;
case CISCO_KEEPALIVE_REQ:
- hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
- if (hdlc->state.cisco.request_sent &&
- ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
- hdlc->state.cisco.last_poll = jiffies;
- if (!hdlc->state.cisco.up) {
+ state(hdlc)->rxseq = ntohl(cisco_data->par1);
+ if (state(hdlc)->request_sent &&
+ ntohl(cisco_data->par2) == state(hdlc)->txseq) {
+ state(hdlc)->last_poll = jiffies;
+ if (!state(hdlc)->up) {
u32 sec, min, hrs, days;
sec = ntohl(cisco_data->time) / 1000;
min = sec / 60; sec -= min * 60;
@@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb)
dev->name, days, hrs,
min, sec);
netif_dormant_off(dev);
- hdlc->state.cisco.up = 1;
+ state(hdlc)->up = 1;
}
}
@@ -208,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb)
return NET_RX_DROP;
rx_error:
- hdlc->stats.rx_errors++; /* Mark error */
+ dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -220,23 +262,22 @@ static void cisco_timer(unsigned long arg)
struct net_device *dev = (struct net_device *)arg;
hdlc_device *hdlc = dev_to_hdlc(dev);
- if (hdlc->state.cisco.up &&
- time_after(jiffies, hdlc->state.cisco.last_poll +
- hdlc->state.cisco.settings.timeout * HZ)) {
- hdlc->state.cisco.up = 0;
+ if (state(hdlc)->up &&
+ time_after(jiffies, state(hdlc)->last_poll +
+ state(hdlc)->settings.timeout * HZ)) {
+ state(hdlc)->up = 0;
printk(KERN_INFO "%s: Link down\n", dev->name);
netif_dormant_on(dev);
}
- cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
- ++hdlc->state.cisco.txseq,
- hdlc->state.cisco.rxseq);
- hdlc->state.cisco.request_sent = 1;
- hdlc->state.cisco.timer.expires = jiffies +
- hdlc->state.cisco.settings.interval * HZ;
- hdlc->state.cisco.timer.function = cisco_timer;
- hdlc->state.cisco.timer.data = arg;
- add_timer(&hdlc->state.cisco.timer);
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
+ state(hdlc)->rxseq);
+ state(hdlc)->request_sent = 1;
+ state(hdlc)->timer.expires = jiffies +
+ state(hdlc)->settings.interval * HZ;
+ state(hdlc)->timer.function = cisco_timer;
+ state(hdlc)->timer.data = arg;
+ add_timer(&state(hdlc)->timer);
}
@@ -244,15 +285,15 @@ static void cisco_timer(unsigned long arg)
static void cisco_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- hdlc->state.cisco.up = 0;
- hdlc->state.cisco.request_sent = 0;
- hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
-
- init_timer(&hdlc->state.cisco.timer);
- hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
- hdlc->state.cisco.timer.function = cisco_timer;
- hdlc->state.cisco.timer.data = (unsigned long)dev;
- add_timer(&hdlc->state.cisco.timer);
+ state(hdlc)->up = 0;
+ state(hdlc)->request_sent = 0;
+ state(hdlc)->txseq = state(hdlc)->rxseq = 0;
+
+ init_timer(&state(hdlc)->timer);
+ state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
+ state(hdlc)->timer.function = cisco_timer;
+ state(hdlc)->timer.data = (unsigned long)dev;
+ add_timer(&state(hdlc)->timer);
}
@@ -260,15 +301,24 @@ static void cisco_start(struct net_device *dev)
static void cisco_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- del_timer_sync(&hdlc->state.cisco.timer);
+ del_timer_sync(&state(hdlc)->timer);
netif_dormant_on(dev);
- hdlc->state.cisco.up = 0;
- hdlc->state.cisco.request_sent = 0;
+ state(hdlc)->up = 0;
+ state(hdlc)->request_sent = 0;
}
-int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .start = cisco_start,
+ .stop = cisco_stop,
+ .type_trans = cisco_type_trans,
+ .ioctl = cisco_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
{
cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
const size_t size = sizeof(cisco_proto);
@@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_CISCO;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
+ if (copy_to_user(cisco_s, &state(hdlc)->settings, size))
return -EFAULT;
return 0;
@@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
-
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memcpy(&hdlc->state.cisco.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
+ result = attach_hdlc_protocol(dev, &proto, cisco_rx,
+ sizeof(struct cisco_state));
+ if (result)
+ return result;
- hdlc->proto.start = cisco_start;
- hdlc->proto.stop = cisco_stop;
- hdlc->proto.netif_rx = cisco_rx;
- hdlc->proto.type_trans = cisco_type_trans;
- hdlc->proto.id = IF_PROTO_CISCO;
+ memcpy(&state(hdlc)->settings, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = cisco_hard_header;
dev->hard_header_cache = NULL;
@@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c
index 7bb737bbdeb9..b45ab680d2d6 100644
--- a/drivers/net/wan/hdlc_fr.c
+++ b/drivers/net/wan/hdlc_fr.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* Frame Relay support
*
- * Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -52,6 +52,8 @@
#undef DEBUG_PKT
#undef DEBUG_ECN
#undef DEBUG_LINK
+#undef DEBUG_PROTO
+#undef DEBUG_PVC
#define FR_UI 0x03
#define FR_PAD 0x00
@@ -115,13 +117,53 @@ typedef struct {
}__attribute__ ((packed)) fr_hdr;
+typedef struct pvc_device_struct {
+ struct net_device *frad;
+ struct net_device *main;
+ struct net_device *ether; /* bridged Ethernet interface */
+ struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
+ int dlci;
+ int open_count;
+
+ struct {
+ unsigned int new: 1;
+ unsigned int active: 1;
+ unsigned int exist: 1;
+ unsigned int deleted: 1;
+ unsigned int fecn: 1;
+ unsigned int becn: 1;
+ unsigned int bandwidth; /* Cisco LMI reporting only */
+ }state;
+}pvc_device;
+
+
+struct frad_state {
+ fr_proto settings;
+ pvc_device *first_pvc;
+ int dce_pvc_count;
+
+ struct timer_list timer;
+ unsigned long last_poll;
+ int reliable;
+ int dce_changed;
+ int request;
+ int fullrep_sent;
+ u32 last_errors; /* last errors bit list */
+ u8 n391cnt;
+ u8 txseq; /* TX sequence number */
+ u8 rxseq; /* RX sequence number */
+};
+
+
+static int fr_ioctl(struct net_device *dev, struct ifreq *ifr);
+
+
static inline u16 q922_to_dlci(u8 *hdr)
{
return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
}
-
static inline void dlci_to_q922(u8 *hdr, u16 dlci)
{
hdr[0] = (dlci >> 2) & 0xFC;
@@ -129,10 +171,21 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci)
}
+static inline struct frad_state * state(hdlc_device *hdlc)
+{
+ return(struct frad_state *)(hdlc->state);
+}
+
+
+static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+{
+ return dev->priv;
+}
+
static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
{
- pvc_device *pvc = hdlc->state.fr.first_pvc;
+ pvc_device *pvc = state(hdlc)->first_pvc;
while (pvc) {
if (pvc->dlci == dlci)
@@ -146,10 +199,10 @@ static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
}
-static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
+static pvc_device* add_pvc(struct net_device *dev, u16 dlci)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
+ pvc_device *pvc, **pvc_p = &state(hdlc)->first_pvc;
while (*pvc_p) {
if ((*pvc_p)->dlci == dlci)
@@ -160,12 +213,15 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
}
pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
+#ifdef DEBUG_PVC
+ printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev);
+#endif
if (!pvc)
return NULL;
memset(pvc, 0, sizeof(pvc_device));
pvc->dlci = dlci;
- pvc->master = dev;
+ pvc->frad = dev;
pvc->next = *pvc_p; /* Put it in the chain */
*pvc_p = pvc;
return pvc;
@@ -174,7 +230,7 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
static inline int pvc_is_used(pvc_device *pvc)
{
- return pvc->main != NULL || pvc->ether != NULL;
+ return pvc->main || pvc->ether;
}
@@ -200,11 +256,14 @@ static inline void pvc_carrier(int on, pvc_device *pvc)
static inline void delete_unused_pvcs(hdlc_device *hdlc)
{
- pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
+ pvc_device **pvc_p = &state(hdlc)->first_pvc;
while (*pvc_p) {
if (!pvc_is_used(*pvc_p)) {
pvc_device *pvc = *pvc_p;
+#ifdef DEBUG_PVC
+ printk(KERN_DEBUG "freeing unused pvc: %p\n", pvc);
+#endif
*pvc_p = pvc->next;
kfree(pvc);
continue;
@@ -295,16 +354,16 @@ static int pvc_open(struct net_device *dev)
{
pvc_device *pvc = dev_to_pvc(dev);
- if ((pvc->master->flags & IFF_UP) == 0)
- return -EIO; /* Master must be UP in order to activate PVC */
+ if ((pvc->frad->flags & IFF_UP) == 0)
+ return -EIO; /* Frad must be UP in order to activate PVC */
if (pvc->open_count++ == 0) {
- hdlc_device *hdlc = dev_to_hdlc(pvc->master);
- if (hdlc->state.fr.settings.lmi == LMI_NONE)
- pvc->state.active = netif_carrier_ok(pvc->master);
+ hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
+ if (state(hdlc)->settings.lmi == LMI_NONE)
+ pvc->state.active = netif_carrier_ok(pvc->frad);
pvc_carrier(pvc->state.active, pvc);
- hdlc->state.fr.dce_changed = 1;
+ state(hdlc)->dce_changed = 1;
}
return 0;
}
@@ -316,12 +375,12 @@ static int pvc_close(struct net_device *dev)
pvc_device *pvc = dev_to_pvc(dev);
if (--pvc->open_count == 0) {
- hdlc_device *hdlc = dev_to_hdlc(pvc->master);
- if (hdlc->state.fr.settings.lmi == LMI_NONE)
+ hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
+ if (state(hdlc)->settings.lmi == LMI_NONE)
pvc->state.active = 0;
- if (hdlc->state.fr.settings.dce) {
- hdlc->state.fr.dce_changed = 1;
+ if (state(hdlc)->settings.dce) {
+ state(hdlc)->dce_changed = 1;
pvc->state.active = 0;
}
}
@@ -348,7 +407,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
info.dlci = pvc->dlci;
- memcpy(info.master, pvc->master->name, IFNAMSIZ);
+ memcpy(info.master, pvc->frad->name, IFNAMSIZ);
if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info,
&info, sizeof(info)))
return -EFAULT;
@@ -361,7 +420,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
{
- return netdev_priv(dev);
+ return &dev_to_desc(dev)->stats;
}
@@ -393,7 +452,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
stats->tx_packets++;
if (pvc->state.fecn) /* TX Congestion counter */
stats->tx_compressed++;
- skb->dev = pvc->master;
+ skb->dev = pvc->frad;
dev_queue_xmit(skb);
return 0;
}
@@ -419,7 +478,7 @@ static int pvc_change_mtu(struct net_device *dev, int new_mtu)
static inline void fr_log_dlci_active(pvc_device *pvc)
{
printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n",
- pvc->master->name,
+ pvc->frad->name,
pvc->dlci,
pvc->main ? pvc->main->name : "",
pvc->main && pvc->ether ? " " : "",
@@ -438,21 +497,20 @@ static inline u8 fr_lmi_nextseq(u8 x)
}
-
static void fr_lmi_send(struct net_device *dev, int fullrep)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
struct sk_buff *skb;
- pvc_device *pvc = hdlc->state.fr.first_pvc;
- int lmi = hdlc->state.fr.settings.lmi;
- int dce = hdlc->state.fr.settings.dce;
+ pvc_device *pvc = state(hdlc)->first_pvc;
+ int lmi = state(hdlc)->settings.lmi;
+ int dce = state(hdlc)->settings.dce;
int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH;
int stat_len = (lmi == LMI_CISCO) ? 6 : 3;
u8 *data;
int i = 0;
if (dce && fullrep) {
- len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
+ len += state(hdlc)->dce_pvc_count * (2 + stat_len);
if (len > HDLC_MAX_MRU) {
printk(KERN_WARNING "%s: Too many PVCs while sending "
"LMI full report\n", dev->name);
@@ -486,8 +544,9 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE;
data[i++] = LMI_INTEG_LEN;
- data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
- data[i++] = hdlc->state.fr.rxseq;
+ data[i++] = state(hdlc)->txseq =
+ fr_lmi_nextseq(state(hdlc)->txseq);
+ data[i++] = state(hdlc)->rxseq;
if (dce && fullrep) {
while (pvc) {
@@ -496,7 +555,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
data[i++] = stat_len;
/* LMI start/restart */
- if (hdlc->state.fr.reliable && !pvc->state.exist) {
+ if (state(hdlc)->reliable && !pvc->state.exist) {
pvc->state.exist = pvc->state.new = 1;
fr_log_dlci_active(pvc);
}
@@ -541,15 +600,15 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
static void fr_set_link_state(int reliable, struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- pvc_device *pvc = hdlc->state.fr.first_pvc;
+ pvc_device *pvc = state(hdlc)->first_pvc;
- hdlc->state.fr.reliable = reliable;
+ state(hdlc)->reliable = reliable;
if (reliable) {
netif_dormant_off(dev);
- hdlc->state.fr.n391cnt = 0; /* Request full status */
- hdlc->state.fr.dce_changed = 1;
+ state(hdlc)->n391cnt = 0; /* Request full status */
+ state(hdlc)->dce_changed = 1;
- if (hdlc->state.fr.settings.lmi == LMI_NONE) {
+ if (state(hdlc)->settings.lmi == LMI_NONE) {
while (pvc) { /* Activate all PVCs */
pvc_carrier(1, pvc);
pvc->state.exist = pvc->state.active = 1;
@@ -563,7 +622,7 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
pvc_carrier(0, pvc);
pvc->state.exist = pvc->state.active = 0;
pvc->state.new = 0;
- if (!hdlc->state.fr.settings.dce)
+ if (!state(hdlc)->settings.dce)
pvc->state.bandwidth = 0;
pvc = pvc->next;
}
@@ -571,7 +630,6 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
}
-
static void fr_timer(unsigned long arg)
{
struct net_device *dev = (struct net_device *)arg;
@@ -579,62 +637,61 @@ static void fr_timer(unsigned long arg)
int i, cnt = 0, reliable;
u32 list;
- if (hdlc->state.fr.settings.dce) {
- reliable = hdlc->state.fr.request &&
- time_before(jiffies, hdlc->state.fr.last_poll +
- hdlc->state.fr.settings.t392 * HZ);
- hdlc->state.fr.request = 0;
+ if (state(hdlc)->settings.dce) {
+ reliable = state(hdlc)->request &&
+ time_before(jiffies, state(hdlc)->last_poll +
+ state(hdlc)->settings.t392 * HZ);
+ state(hdlc)->request = 0;
} else {
- hdlc->state.fr.last_errors <<= 1; /* Shift the list */
- if (hdlc->state.fr.request) {
- if (hdlc->state.fr.reliable)
+ state(hdlc)->last_errors <<= 1; /* Shift the list */
+ if (state(hdlc)->request) {
+ if (state(hdlc)->reliable)
printk(KERN_INFO "%s: No LMI status reply "
"received\n", dev->name);
- hdlc->state.fr.last_errors |= 1;
+ state(hdlc)->last_errors |= 1;
}
- list = hdlc->state.fr.last_errors;
- for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
+ list = state(hdlc)->last_errors;
+ for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1)
cnt += (list & 1); /* errors count */
- reliable = (cnt < hdlc->state.fr.settings.n392);
+ reliable = (cnt < state(hdlc)->settings.n392);
}
- if (hdlc->state.fr.reliable != reliable) {
+ if (state(hdlc)->reliable != reliable) {
printk(KERN_INFO "%s: Link %sreliable\n", dev->name,
reliable ? "" : "un");
fr_set_link_state(reliable, dev);
}
- if (hdlc->state.fr.settings.dce)
- hdlc->state.fr.timer.expires = jiffies +
- hdlc->state.fr.settings.t392 * HZ;
+ if (state(hdlc)->settings.dce)
+ state(hdlc)->timer.expires = jiffies +
+ state(hdlc)->settings.t392 * HZ;
else {
- if (hdlc->state.fr.n391cnt)
- hdlc->state.fr.n391cnt--;
+ if (state(hdlc)->n391cnt)
+ state(hdlc)->n391cnt--;
- fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0);
+ fr_lmi_send(dev, state(hdlc)->n391cnt == 0);
- hdlc->state.fr.last_poll = jiffies;
- hdlc->state.fr.request = 1;
- hdlc->state.fr.timer.expires = jiffies +
- hdlc->state.fr.settings.t391 * HZ;
+ state(hdlc)->last_poll = jiffies;
+ state(hdlc)->request = 1;
+ state(hdlc)->timer.expires = jiffies +
+ state(hdlc)->settings.t391 * HZ;
}
- hdlc->state.fr.timer.function = fr_timer;
- hdlc->state.fr.timer.data = arg;
- add_timer(&hdlc->state.fr.timer);
+ state(hdlc)->timer.function = fr_timer;
+ state(hdlc)->timer.data = arg;
+ add_timer(&state(hdlc)->timer);
}
-
static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
pvc_device *pvc;
u8 rxseq, txseq;
- int lmi = hdlc->state.fr.settings.lmi;
- int dce = hdlc->state.fr.settings.dce;
+ int lmi = state(hdlc)->settings.lmi;
+ int dce = state(hdlc)->settings.dce;
int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i;
if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH :
@@ -645,8 +702,8 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI :
NLPID_CCITT_ANSI_LMI)) {
- printk(KERN_INFO "%s: Received non-LMI frame with LMI"
- " DLCI\n", dev->name);
+ printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
+ dev->name);
return 1;
}
@@ -706,53 +763,53 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
}
i++;
- hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
+ state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */
rxseq = skb->data[i++]; /* Should confirm our sequence */
- txseq = hdlc->state.fr.txseq;
+ txseq = state(hdlc)->txseq;
if (dce)
- hdlc->state.fr.last_poll = jiffies;
+ state(hdlc)->last_poll = jiffies;
error = 0;
- if (!hdlc->state.fr.reliable)
+ if (!state(hdlc)->reliable)
error = 1;
- if (rxseq == 0 || rxseq != txseq) {
- hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
+ if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */
+ state(hdlc)->n391cnt = 0;
error = 1;
}
if (dce) {
- if (hdlc->state.fr.fullrep_sent && !error) {
+ if (state(hdlc)->fullrep_sent && !error) {
/* Stop sending full report - the last one has been confirmed by DTE */
- hdlc->state.fr.fullrep_sent = 0;
- pvc = hdlc->state.fr.first_pvc;
+ state(hdlc)->fullrep_sent = 0;
+ pvc = state(hdlc)->first_pvc;
while (pvc) {
if (pvc->state.new) {
pvc->state.new = 0;
/* Tell DTE that new PVC is now active */
- hdlc->state.fr.dce_changed = 1;
+ state(hdlc)->dce_changed = 1;
}
pvc = pvc->next;
}
}
- if (hdlc->state.fr.dce_changed) {
+ if (state(hdlc)->dce_changed) {
reptype = LMI_FULLREP;
- hdlc->state.fr.fullrep_sent = 1;
- hdlc->state.fr.dce_changed = 0;
+ state(hdlc)->fullrep_sent = 1;
+ state(hdlc)->dce_changed = 0;
}
- hdlc->state.fr.request = 1; /* got request */
+ state(hdlc)->request = 1; /* got request */
fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
return 0;
}
/* DTE */
- hdlc->state.fr.request = 0; /* got response, no request pending */
+ state(hdlc)->request = 0; /* got response, no request pending */
if (error)
return 0;
@@ -760,7 +817,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
if (reptype != LMI_FULLREP)
return 0;
- pvc = hdlc->state.fr.first_pvc;
+ pvc = state(hdlc)->first_pvc;
while (pvc) {
pvc->state.deleted = 1;
@@ -827,7 +884,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
i += stat_len;
}
- pvc = hdlc->state.fr.first_pvc;
+ pvc = state(hdlc)->first_pvc;
while (pvc) {
if (pvc->state.deleted && pvc->state.exist) {
@@ -841,17 +898,16 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
}
/* Next full report after N391 polls */
- hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
+ state(hdlc)->n391cnt = state(hdlc)->settings.n391;
return 0;
}
-
static int fr_rx(struct sk_buff *skb)
{
- struct net_device *ndev = skb->dev;
- hdlc_device *hdlc = dev_to_hdlc(ndev);
+ struct net_device *frad = skb->dev;
+ hdlc_device *hdlc = dev_to_hdlc(frad);
fr_hdr *fh = (fr_hdr*)skb->data;
u8 *data = skb->data;
u16 dlci;
@@ -864,11 +920,11 @@ static int fr_rx(struct sk_buff *skb)
dlci = q922_to_dlci(skb->data);
if ((dlci == LMI_CCITT_ANSI_DLCI &&
- (hdlc->state.fr.settings.lmi == LMI_ANSI ||
- hdlc->state.fr.settings.lmi == LMI_CCITT)) ||
+ (state(hdlc)->settings.lmi == LMI_ANSI ||
+ state(hdlc)->settings.lmi == LMI_CCITT)) ||
(dlci == LMI_CISCO_DLCI &&
- hdlc->state.fr.settings.lmi == LMI_CISCO)) {
- if (fr_lmi_recv(ndev, skb))
+ state(hdlc)->settings.lmi == LMI_CISCO)) {
+ if (fr_lmi_recv(frad, skb))
goto rx_error;
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
@@ -878,7 +934,7 @@ static int fr_rx(struct sk_buff *skb)
if (!pvc) {
#ifdef DEBUG_PKT
printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
- ndev->name, dlci);
+ frad->name, dlci);
#endif
dev_kfree_skb_any(skb);
return NET_RX_DROP;
@@ -886,7 +942,7 @@ static int fr_rx(struct sk_buff *skb)
if (pvc->state.fecn != fh->fecn) {
#ifdef DEBUG_ECN
- printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name,
+ printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", frad->name,
dlci, fh->fecn ? "N" : "FF");
#endif
pvc->state.fecn ^= 1;
@@ -894,7 +950,7 @@ static int fr_rx(struct sk_buff *skb)
if (pvc->state.becn != fh->becn) {
#ifdef DEBUG_ECN
- printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name,
+ printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", frad->name,
dlci, fh->becn ? "N" : "FF");
#endif
pvc->state.becn ^= 1;
@@ -902,7 +958,7 @@ static int fr_rx(struct sk_buff *skb)
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- hdlc->stats.rx_dropped++;
+ dev_to_desc(frad)->stats.rx_dropped++;
return NET_RX_DROP;
}
@@ -938,13 +994,13 @@ static int fr_rx(struct sk_buff *skb)
default:
printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
- "PID=%x\n", ndev->name, oui, pid);
+ "PID=%x\n", frad->name, oui, pid);
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
} else {
printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
- "length = %i\n", ndev->name, data[3], skb->len);
+ "length = %i\n", frad->name, data[3], skb->len);
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -964,7 +1020,7 @@ static int fr_rx(struct sk_buff *skb)
}
rx_error:
- hdlc->stats.rx_errors++; /* Mark error */
+ dev_to_desc(frad)->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -977,44 +1033,42 @@ static void fr_start(struct net_device *dev)
#ifdef DEBUG_LINK
printk(KERN_DEBUG "fr_start\n");
#endif
- if (hdlc->state.fr.settings.lmi != LMI_NONE) {
- hdlc->state.fr.reliable = 0;
- hdlc->state.fr.dce_changed = 1;
- hdlc->state.fr.request = 0;
- hdlc->state.fr.fullrep_sent = 0;
- hdlc->state.fr.last_errors = 0xFFFFFFFF;
- hdlc->state.fr.n391cnt = 0;
- hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
-
- init_timer(&hdlc->state.fr.timer);
+ if (state(hdlc)->settings.lmi != LMI_NONE) {
+ state(hdlc)->reliable = 0;
+ state(hdlc)->dce_changed = 1;
+ state(hdlc)->request = 0;
+ state(hdlc)->fullrep_sent = 0;
+ state(hdlc)->last_errors = 0xFFFFFFFF;
+ state(hdlc)->n391cnt = 0;
+ state(hdlc)->txseq = state(hdlc)->rxseq = 0;
+
+ init_timer(&state(hdlc)->timer);
/* First poll after 1 s */
- hdlc->state.fr.timer.expires = jiffies + HZ;
- hdlc->state.fr.timer.function = fr_timer;
- hdlc->state.fr.timer.data = (unsigned long)dev;
- add_timer(&hdlc->state.fr.timer);
+ state(hdlc)->timer.expires = jiffies + HZ;
+ state(hdlc)->timer.function = fr_timer;
+ state(hdlc)->timer.data = (unsigned long)dev;
+ add_timer(&state(hdlc)->timer);
} else
fr_set_link_state(1, dev);
}
-
static void fr_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
#ifdef DEBUG_LINK
printk(KERN_DEBUG "fr_stop\n");
#endif
- if (hdlc->state.fr.settings.lmi != LMI_NONE)
- del_timer_sync(&hdlc->state.fr.timer);
+ if (state(hdlc)->settings.lmi != LMI_NONE)
+ del_timer_sync(&state(hdlc)->timer);
fr_set_link_state(0, dev);
}
-
static void fr_close(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- pvc_device *pvc = hdlc->state.fr.first_pvc;
+ pvc_device *pvc = state(hdlc)->first_pvc;
while (pvc) { /* Shutdown all PVCs for this FRAD */
if (pvc->main)
@@ -1025,7 +1079,8 @@ static void fr_close(struct net_device *dev)
}
}
-static void dlci_setup(struct net_device *dev)
+
+static void pvc_setup(struct net_device *dev)
{
dev->type = ARPHRD_DLCI;
dev->flags = IFF_POINTOPOINT;
@@ -1033,9 +1088,9 @@ static void dlci_setup(struct net_device *dev)
dev->addr_len = 2;
}
-static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
+static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
{
- hdlc_device *hdlc = dev_to_hdlc(master);
+ hdlc_device *hdlc = dev_to_hdlc(frad);
pvc_device *pvc = NULL;
struct net_device *dev;
int result, used;
@@ -1044,9 +1099,9 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
if (type == ARPHRD_ETHER)
prefix = "pvceth%d";
- if ((pvc = add_pvc(master, dlci)) == NULL) {
+ if ((pvc = add_pvc(frad, dlci)) == NULL) {
printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
- master->name);
+ frad->name);
return -ENOBUFS;
}
@@ -1060,11 +1115,11 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
"pvceth%d", ether_setup);
else
dev = alloc_netdev(sizeof(struct net_device_stats),
- "pvc%d", dlci_setup);
+ "pvc%d", pvc_setup);
if (!dev) {
printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
- master->name);
+ frad->name);
delete_unused_pvcs(hdlc);
return -ENOBUFS;
}
@@ -1102,8 +1157,8 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
dev->destructor = free_netdev;
*get_dev_p(pvc, type) = dev;
if (!used) {
- hdlc->state.fr.dce_changed = 1;
- hdlc->state.fr.dce_pvc_count++;
+ state(hdlc)->dce_changed = 1;
+ state(hdlc)->dce_pvc_count++;
}
return 0;
}
@@ -1128,8 +1183,8 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
*get_dev_p(pvc, type) = NULL;
if (!pvc_is_used(pvc)) {
- hdlc->state.fr.dce_pvc_count--;
- hdlc->state.fr.dce_changed = 1;
+ state(hdlc)->dce_pvc_count--;
+ state(hdlc)->dce_changed = 1;
}
delete_unused_pvcs(hdlc);
return 0;
@@ -1137,14 +1192,13 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
-static void fr_destroy(hdlc_device *hdlc)
+static void fr_destroy(struct net_device *frad)
{
- pvc_device *pvc;
-
- pvc = hdlc->state.fr.first_pvc;
- hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
- hdlc->state.fr.dce_pvc_count = 0;
- hdlc->state.fr.dce_changed = 1;
+ hdlc_device *hdlc = dev_to_hdlc(frad);
+ pvc_device *pvc = state(hdlc)->first_pvc;
+ state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */
+ state(hdlc)->dce_pvc_count = 0;
+ state(hdlc)->dce_changed = 1;
while (pvc) {
pvc_device *next = pvc->next;
@@ -1161,8 +1215,17 @@ static void fr_destroy(hdlc_device *hdlc)
}
+static struct hdlc_proto proto = {
+ .close = fr_close,
+ .start = fr_start,
+ .stop = fr_stop,
+ .detach = fr_destroy,
+ .ioctl = fr_ioctl,
+ .module = THIS_MODULE,
+};
+
-int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
+static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
{
fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
const size_t size = sizeof(fr_proto);
@@ -1173,12 +1236,14 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_FR;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
+ if (copy_to_user(fr_s, &state(hdlc)->settings, size))
return -EFAULT;
return 0;
@@ -1213,20 +1278,16 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- if (hdlc->proto.id != IF_PROTO_FR) {
- hdlc_proto_detach(hdlc);
- hdlc->state.fr.first_pvc = NULL;
- hdlc->state.fr.dce_pvc_count = 0;
+ if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */
+ result = attach_hdlc_protocol(dev, &proto, fr_rx,
+ sizeof(struct frad_state));
+ if (result)
+ return result;
+ state(hdlc)->first_pvc = NULL;
+ state(hdlc)->dce_pvc_count = 0;
}
- memcpy(&hdlc->state.fr.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.close = fr_close;
- hdlc->proto.start = fr_start;
- hdlc->proto.stop = fr_stop;
- hdlc->proto.detach = fr_destroy;
- hdlc->proto.netif_rx = fr_rx;
- hdlc->proto.id = IF_PROTO_FR;
+ memcpy(&state(hdlc)->settings, &new_settings, size);
+
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_FRAD;
@@ -1238,6 +1299,9 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
case IF_PROTO_FR_DEL_PVC:
case IF_PROTO_FR_ADD_ETH_PVC:
case IF_PROTO_FR_DEL_ETH_PVC:
+ if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
+ return -EINVAL;
+
if(!capable(CAP_NET_ADMIN))
return -EPERM;
@@ -1263,3 +1327,24 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index fbaab5bf71eb..e9f717070fde 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* Point-to-point protocol support
*
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -22,6 +22,21 @@
#include <linux/lapb.h>
#include <linux/rtnetlink.h>
#include <linux/hdlc.h>
+#include <net/syncppp.h>
+
+struct ppp_state {
+ struct ppp_device pppdev;
+ struct ppp_device *syncppp_ptr;
+ int (*old_change_mtu)(struct net_device *dev, int new_mtu);
+};
+
+static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
+
+
+static inline struct ppp_state* state(hdlc_device *hdlc)
+{
+ return(struct ppp_state *)(hdlc->state);
+}
static int ppp_open(struct net_device *dev)
@@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev)
void *old_ioctl;
int result;
- dev->priv = &hdlc->state.ppp.syncppp_ptr;
- hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
- hdlc->state.ppp.pppdev.dev = dev;
+ dev->priv = &state(hdlc)->syncppp_ptr;
+ state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
+ state(hdlc)->pppdev.dev = dev;
old_ioctl = dev->do_ioctl;
- hdlc->state.ppp.old_change_mtu = dev->change_mtu;
- sppp_attach(&hdlc->state.ppp.pppdev);
+ state(hdlc)->old_change_mtu = dev->change_mtu;
+ sppp_attach(&state(hdlc)->pppdev);
/* sppp_attach nukes them. We don't need syncppp's ioctl */
dev->do_ioctl = old_ioctl;
- hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
+ state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO;
dev->type = ARPHRD_PPP;
result = sppp_open(dev);
if (result) {
@@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev)
sppp_close(dev);
sppp_detach(dev);
dev->rebuild_header = NULL;
- dev->change_mtu = hdlc->state.ppp.old_change_mtu;
+ dev->change_mtu = state(hdlc)->old_change_mtu;
dev->mtu = HDLC_MAX_MTU;
dev->hard_header_len = 16;
}
@@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
-int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .open = ppp_open,
+ .close = ppp_close,
+ .type_trans = ppp_type_trans,
+ .ioctl = ppp_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
int result;
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_PPP;
return 0; /* return protocol only, no settable parameters */
@@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.open = ppp_open;
- hdlc->proto.close = ppp_close;
- hdlc->proto.type_trans = ppp_type_trans;
- hdlc->proto.id = IF_PROTO_PPP;
+ result = attach_hdlc_protocol(dev, &proto, NULL,
+ sizeof(struct ppp_state));
+ if (result)
+ return result;
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_PPP;
@@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("PPP protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
index f15aa6ba77f1..fe3cae5c6b9d 100644
--- a/drivers/net/wan/hdlc_raw.c
+++ b/drivers/net/wan/hdlc_raw.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* HDLC support
*
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -24,6 +24,8 @@
#include <linux/hdlc.h>
+static int raw_ioctl(struct net_device *dev, struct ifreq *ifr);
+
static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
{
return __constant_htons(ETH_P_IP);
@@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
-int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .type_trans = raw_type_trans,
+ .ioctl = raw_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
{
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
const size_t size = sizeof(raw_hdlc_proto);
@@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_HDLC;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+ if (copy_to_user(raw_s, hdlc->state, size))
return -EFAULT;
return 0;
@@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.type_trans = raw_type_trans;
- hdlc->proto.id = IF_PROTO_HDLC;
+ result = attach_hdlc_protocol(dev, &proto, NULL,
+ sizeof(raw_hdlc_proto));
+ if (result)
+ return result;
+ memcpy(hdlc->state, &new_settings, size);
dev->hard_start_xmit = hdlc->xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_RAWHDLC;
@@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_raw_eth.c b/drivers/net/wan/hdlc_raw_eth.c
index d1884987f94e..1a69a9aaa9b9 100644
--- a/drivers/net/wan/hdlc_raw_eth.c
+++ b/drivers/net/wan/hdlc_raw_eth.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* HDLC Ethernet emulation support
*
- * Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 2002-2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -25,6 +25,7 @@
#include <linux/etherdevice.h>
#include <linux/hdlc.h>
+static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
static int eth_tx(struct sk_buff *skb, struct net_device *dev)
{
@@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev)
}
-int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
+static struct hdlc_proto proto = {
+ .type_trans = eth_type_trans,
+ .ioctl = raw_eth_ioctl,
+ .module = THIS_MODULE,
+};
+
+
+static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
{
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
const size_t size = sizeof(raw_hdlc_proto);
@@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_HDLC_ETH;
if (ifr->ifr_settings.size < size) {
ifr->ifr_settings.size = size; /* data size wanted */
return -ENOBUFS;
}
- if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
+ if (copy_to_user(raw_s, hdlc->state, size))
return -EFAULT;
return 0;
@@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.type_trans = eth_type_trans;
- hdlc->proto.id = IF_PROTO_HDLC_ETH;
+ result = attach_hdlc_protocol(dev, &proto, NULL,
+ sizeof(raw_hdlc_proto));
+ if (result)
+ return result;
+ memcpy(hdlc->state, &new_settings, size);
dev->hard_start_xmit = eth_tx;
old_ch_mtu = dev->change_mtu;
old_qlen = dev->tx_queue_len;
@@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/hdlc_x25.c b/drivers/net/wan/hdlc_x25.c
index a867fb411f89..e4bb9f8ad433 100644
--- a/drivers/net/wan/hdlc_x25.c
+++ b/drivers/net/wan/hdlc_x25.c
@@ -2,7 +2,7 @@
* Generic HDLC support routines for Linux
* X.25 support
*
- * Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
+ * Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License
@@ -25,6 +25,8 @@
#include <net/x25device.h>
+static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
+
/* These functions are callbacks called by LAPB layer */
static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
@@ -162,30 +164,39 @@ static void x25_close(struct net_device *dev)
static int x25_rx(struct sk_buff *skb)
{
- hdlc_device *hdlc = dev_to_hdlc(skb->dev);
+ struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- hdlc->stats.rx_dropped++;
+ desc->stats.rx_dropped++;
return NET_RX_DROP;
}
if (lapb_data_received(skb->dev, skb) == LAPB_OK)
return NET_RX_SUCCESS;
- hdlc->stats.rx_errors++;
+ desc->stats.rx_errors++;
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
+static struct hdlc_proto proto = {
+ .open = x25_open,
+ .close = x25_close,
+ .ioctl = x25_ioctl,
+ .module = THIS_MODULE,
+};
+
-int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
+static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
int result;
switch (ifr->ifr_settings.type) {
case IF_GET_PROTO:
+ if (dev_to_hdlc(dev)->proto != &proto)
+ return -EINVAL;
ifr->ifr_settings.type = IF_PROTO_X25;
return 0; /* return protocol only, no settable parameters */
@@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
if (result)
return result;
- hdlc_proto_detach(hdlc);
- memset(&hdlc->proto, 0, sizeof(hdlc->proto));
-
- hdlc->proto.open = x25_open;
- hdlc->proto.close = x25_close;
- hdlc->proto.netif_rx = x25_rx;
- hdlc->proto.type_trans = NULL;
- hdlc->proto.id = IF_PROTO_X25;
+ if ((result = attach_hdlc_protocol(dev, &proto,
+ x25_rx, 0)) != 0)
+ return result;
dev->hard_start_xmit = x25_xmit;
dev->hard_header = NULL;
dev->type = ARPHRD_X25;
@@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
return -EINVAL;
}
+
+
+static int __init mod_init(void)
+{
+ register_hdlc_protocol(&proto);
+ return 0;
+}
+
+
+
+static void __exit mod_exit(void)
+{
+ unregister_hdlc_protocol(&proto);
+}
+
+
+module_init(mod_init);
+module_exit(mod_exit);
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c
index 7b5d81deb028..2b54f1bc3a0d 100644
--- a/drivers/net/wan/lmc/lmc_main.c
+++ b/drivers/net/wan/lmc/lmc_main.c
@@ -100,7 +100,7 @@ static int lmc_rx (struct net_device *dev);
static int lmc_open(struct net_device *dev);
static int lmc_close(struct net_device *dev);
static struct net_device_stats *lmc_get_stats(struct net_device *dev);
-static irqreturn_t lmc_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t lmc_interrupt(int irq, void *dev_instance);
static void lmc_initcsrs(lmc_softc_t * const sc, lmc_csrptr_t csr_base, size_t csr_size);
static void lmc_softreset(lmc_softc_t * const);
static void lmc_running_reset(struct net_device *dev);
@@ -1273,7 +1273,7 @@ static int lmc_ifdown (struct net_device *dev) /*fold00*/
/* Interrupt handling routine. This will take an incoming packet, or clean
* up after a trasmit.
*/
-static irqreturn_t lmc_interrupt (int irq, void *dev_instance, struct pt_regs *regs) /*fold00*/
+static irqreturn_t lmc_interrupt (int irq, void *dev_instance) /*fold00*/
{
struct net_device *dev = (struct net_device *) dev_instance;
lmc_softc_t *sc;
diff --git a/drivers/net/wan/pc300.h b/drivers/net/wan/pc300.h
index 2024b26b99e6..63e9fcf31fb8 100644
--- a/drivers/net/wan/pc300.h
+++ b/drivers/net/wan/pc300.h
@@ -100,6 +100,7 @@
#define _PC300_H
#include <linux/hdlc.h>
+#include <net/syncppp.h>
#include "hd64572.h"
#include "pc300-falc-lh.h"
diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c
index 56e69403d178..5823e3bca178 100644
--- a/drivers/net/wan/pc300_drv.c
+++ b/drivers/net/wan/pc300_drv.c
@@ -284,7 +284,7 @@ static void rx_dma_buf_pt_init(pc300_t *, int);
static void rx_dma_buf_init(pc300_t *, int);
static void tx_dma_buf_check(pc300_t *, int);
static void rx_dma_buf_check(pc300_t *, int);
-static irqreturn_t cpc_intr(int, void *, struct pt_regs *);
+static irqreturn_t cpc_intr(int, void *);
static struct net_device_stats *cpc_get_stats(struct net_device *);
static int clock_rate_calc(uclong, uclong, int *);
static uclong detect_ram(pc300_t *);
@@ -2016,7 +2016,6 @@ static void sca_intr(pc300_t * card)
pc300ch_t *chan = &card->chan[ch];
pc300dev_t *d = &chan->d;
struct net_device *dev = d->dev;
- hdlc_device *hdlc = dev_to_hdlc(dev);
spin_lock(&card->card_lock);
@@ -2049,8 +2048,8 @@ static void sca_intr(pc300_t * card)
}
cpc_net_rx(dev);
/* Discard invalid frames */
- hdlc->stats.rx_errors++;
- hdlc->stats.rx_over_errors++;
+ hdlc_stats(dev)->rx_errors++;
+ hdlc_stats(dev)->rx_over_errors++;
chan->rx_first_bd = 0;
chan->rx_last_bd = N_DMA_RX_BUF - 1;
rx_dma_start(card, ch);
@@ -2116,8 +2115,8 @@ static void sca_intr(pc300_t * card)
card->hw.cpld_reg2) &
~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
}
- hdlc->stats.tx_errors++;
- hdlc->stats.tx_fifo_errors++;
+ hdlc_stats(dev)->tx_errors++;
+ hdlc_stats(dev)->tx_fifo_errors++;
sca_tx_intr(d);
}
}
@@ -2364,7 +2363,7 @@ static void falc_intr(pc300_t * card)
}
}
-static irqreturn_t cpc_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cpc_intr(int irq, void *dev_id)
{
pc300_t *card;
volatile ucchar plx_status;
@@ -2534,7 +2533,6 @@ static int cpc_change_mtu(struct net_device *dev, int new_mtu)
static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -2552,10 +2550,10 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGPC300CONF:
#ifdef CONFIG_PC300_MLPPP
if (conf->proto != PC300_PROTO_MLPPP) {
- conf->proto = hdlc->proto.id;
+ conf->proto = /* FIXME hdlc->proto.id */ 0;
}
#else
- conf->proto = hdlc->proto.id;
+ conf->proto = /* FIXME hdlc->proto.id */ 0;
#endif
memcpy(&conf_aux.conf, conf, sizeof(pc300chconf_t));
memcpy(&conf_aux.hw, &card->hw, sizeof(pc300hw_t));
@@ -2588,12 +2586,12 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
}
} else {
memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
- hdlc->proto.id = conf->proto;
+ /* FIXME hdlc->proto.id = conf->proto; */
}
}
#else
memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
- hdlc->proto.id = conf->proto;
+ /* FIXME hdlc->proto.id = conf->proto; */
#endif
return 0;
case SIOCGPC300STATUS:
@@ -2606,7 +2604,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
case SIOCGPC300UTILSTATS:
{
if (!arg) { /* clear statistics */
- memset(&hdlc->stats, 0, sizeof(struct net_device_stats));
+ memset(hdlc_stats(dev), 0, sizeof(struct net_device_stats));
if (card->hw.type == PC300_TE) {
memset(&chan->falc, 0, sizeof(falc_t));
}
@@ -2617,7 +2615,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
pc300stats.hw_type = card->hw.type;
pc300stats.line_on = card->chan[ch].d.line_on;
pc300stats.line_off = card->chan[ch].d.line_off;
- memcpy(&pc300stats.gen_stats, &hdlc->stats,
+ memcpy(&pc300stats.gen_stats, hdlc_stats(dev),
sizeof(struct net_device_stats));
if (card->hw.type == PC300_TE)
memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t));
@@ -3147,7 +3145,6 @@ static void cpc_closech(pc300dev_t * d)
int cpc_open(struct net_device *dev)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
struct ifreq ifr;
int result;
@@ -3156,12 +3153,14 @@ int cpc_open(struct net_device *dev)
printk("pc300: cpc_open");
#endif
+#ifdef FIXME
if (hdlc->proto.id == IF_PROTO_PPP) {
d->if_ptr = &hdlc->state.ppp.pppdev;
}
+#endif
result = hdlc_open(dev);
- if (hdlc->proto.id == IF_PROTO_PPP) {
+ if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
dev->priv = d;
}
if (result) {
@@ -3176,7 +3175,6 @@ int cpc_open(struct net_device *dev)
static int cpc_close(struct net_device *dev)
{
- hdlc_device *hdlc = dev_to_hdlc(dev);
pc300dev_t *d = (pc300dev_t *) dev->priv;
pc300ch_t *chan = (pc300ch_t *) d->chan;
pc300_t *card = (pc300_t *) chan->card;
@@ -3193,7 +3191,7 @@ static int cpc_close(struct net_device *dev)
CPC_UNLOCK(card, flags);
hdlc_close(dev);
- if (hdlc->proto.id == IF_PROTO_PPP) {
+ if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
d->if_ptr = NULL;
}
#ifdef CONFIG_PC300_MLPPP
diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c
index fc75bec19029..fc5c0c611ffd 100644
--- a/drivers/net/wan/sbni.c
+++ b/drivers/net/wan/sbni.c
@@ -119,7 +119,7 @@ static int sbni_ioctl( struct net_device *, struct ifreq *, int );
static struct net_device_stats *sbni_get_stats( struct net_device * );
static void set_multicast_list( struct net_device * );
-static irqreturn_t sbni_interrupt( int, void *, struct pt_regs * );
+static irqreturn_t sbni_interrupt( int, void * );
static void handle_channel( struct net_device * );
static int recv_frame( struct net_device * );
static void send_frame( struct net_device * );
@@ -501,7 +501,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
*/
static irqreturn_t
-sbni_interrupt( int irq, void *dev_id, struct pt_regs *regs )
+sbni_interrupt( int irq, void *dev_id )
{
struct net_device *dev = (struct net_device *) dev_id;
struct net_local *nl = (struct net_local *) dev->priv;
diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
index 0ba018f8382b..6a485f0556f4 100644
--- a/drivers/net/wan/sdla.c
+++ b/drivers/net/wan/sdla.c
@@ -867,7 +867,7 @@ static void sdla_receive(struct net_device *dev)
spin_unlock_irqrestore(&sdla_lock, flags);
}
-static irqreturn_t sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t sdla_isr(int irq, void *dev_id)
{
struct net_device *dev;
struct frad_local *flp;
@@ -875,13 +875,7 @@ static irqreturn_t sdla_isr(int irq, void *dev_id, struct pt_regs * regs)
dev = dev_id;
- if (dev == NULL)
- {
- printk(KERN_WARNING "sdla_isr(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
- flp = dev->priv;
+ flp = netdev_priv(dev);
if (!flp->initialized)
{
diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c
index c13b459a0137..218f7b574ab3 100644
--- a/drivers/net/wan/syncppp.c
+++ b/drivers/net/wan/syncppp.c
@@ -469,7 +469,7 @@ static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb)
struct net_device *dev = sp->pp_if;
int len = skb->len;
u8 *p, opt[6];
- u32 rmagic;
+ u32 rmagic = 0;
if (!pskb_may_pull(skb, sizeof(struct lcp_header))) {
if (sp->pp_flags & PP_DEBUG)
@@ -763,7 +763,7 @@ static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb)
{
struct in_device *in_dev;
struct in_ifaddr *ifa;
- u32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
+ __be32 addr = 0, mask = ~0; /* FIXME: is the mask correct? */
#ifdef CONFIG_INET
rcu_read_lock();
if ((in_dev = __in_dev_get_rcu(dev)) != NULL)
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index ec68f7dfd93f..c73601574334 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -244,7 +244,7 @@ static inline void wanxl_rx_intr(card_t *card)
-static irqreturn_t wanxl_intr(int irq, void* dev_id, struct pt_regs *regs)
+static irqreturn_t wanxl_intr(int irq, void* dev_id)
{
card_t *card = dev_id;
int i;
diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c
index caa48f12fd0f..59ddd21c3958 100644
--- a/drivers/net/wan/z85230.c
+++ b/drivers/net/wan/z85230.c
@@ -728,7 +728,7 @@ EXPORT_SYMBOL(z8530_nop);
* channel). c->lock for both channels points to dev->lock
*/
-irqreturn_t z8530_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t z8530_interrupt(int irq, void *dev_id)
{
struct z8530_dev *dev=dev_id;
u8 intr;
diff --git a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h
index 77e53208045f..158aea7b8eac 100644
--- a/drivers/net/wan/z85230.h
+++ b/drivers/net/wan/z85230.h
@@ -396,7 +396,7 @@ struct z8530_dev
extern u8 z8530_dead_port[];
extern u8 z8530_hdlc_kilostream_85230[];
extern u8 z8530_hdlc_kilostream[];
-extern irqreturn_t z8530_interrupt(int, void *, struct pt_regs *);
+extern irqreturn_t z8530_interrupt(int, void *);
extern void z8530_describe(struct z8530_dev *, char *mapping, unsigned long io);
extern int z8530_init(struct z8530_dev *);
extern int z8530_shutdown(struct z8530_dev *);
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig
index bd4a68c85a47..ece3d9c2dc61 100644
--- a/drivers/net/wireless/Kconfig
+++ b/drivers/net/wireless/Kconfig
@@ -301,7 +301,7 @@ config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA)
---help---
- A driver for 802.11b wireless cards based based on the "Hermes" or
+ A driver for 802.11b wireless cards based on the "Hermes" or
Intersil HFA384x (Prism 2) MAC controller. This includes the vast
majority of the PCMCIA 802.11b cards (which are nearly all rebadges)
- except for the Cisco/Aironet cards. Cards supported include the
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index bff04cba3fed..0a33c8a56e13 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -1120,8 +1120,7 @@ static void mpi_receive_802_3(struct airo_info *ai);
static void mpi_receive_802_11(struct airo_info *ai);
static int waitbusy (struct airo_info *ai);
-static irqreturn_t airo_interrupt( int irq, void* dev_id, struct pt_regs
- *regs);
+static irqreturn_t airo_interrupt( int irq, void* dev_id);
static int airo_thread(void *data);
static void timer_func( struct net_device *dev );
static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
@@ -3151,7 +3150,7 @@ static int airo_thread(void *data) {
return 0;
}
-static irqreturn_t airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
+static irqreturn_t airo_interrupt ( int irq, void* dev_id) {
struct net_device *dev = (struct net_device *)dev_id;
u16 status;
u16 fid;
@@ -5659,25 +5658,40 @@ static int airo_pci_resume(struct pci_dev *pdev)
static int __init airo_init_module( void )
{
- int i, have_isa_dev = 0;
+ int i;
+#if 0
+ int have_isa_dev = 0;
+#endif
airo_entry = create_proc_entry("aironet",
S_IFDIR | airo_perm,
proc_root_driver);
- airo_entry->uid = proc_uid;
- airo_entry->gid = proc_gid;
+
+ if (airo_entry) {
+ airo_entry->uid = proc_uid;
+ airo_entry->gid = proc_gid;
+ }
for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
airo_print_info("", "Trying to configure ISA adapter at irq=%d "
"io=0x%x", irq[i], io[i] );
if (init_airo_card( irq[i], io[i], 0, NULL ))
+#if 0
have_isa_dev = 1;
+#else
+ /* do nothing */ ;
+#endif
}
#ifdef CONFIG_PCI
airo_print_info("", "Probing for PCI adapters");
- pci_register_driver(&airo_driver);
+ i = pci_register_driver(&airo_driver);
airo_print_info("", "Finished probing for PCI adapters");
+
+ if (i) {
+ remove_proc_entry("aironet", proc_root_driver);
+ return i;
+ }
#endif
/* Always exit with success, as we are a library module
@@ -5868,7 +5882,7 @@ static int airo_set_essid(struct net_device *dev,
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
/* Check the size of the string */
- if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
+ if(dwrq->length > IW_ESSID_MAX_SIZE) {
return -E2BIG ;
}
/* Check if index is valid */
@@ -5880,7 +5894,7 @@ static int airo_set_essid(struct net_device *dev,
memset(SSID_rid.ssids[index].ssid, 0,
sizeof(SSID_rid.ssids[index].ssid));
memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
- SSID_rid.ssids[index].len = dwrq->length - 1;
+ SSID_rid.ssids[index].len = dwrq->length;
}
SSID_rid.len = sizeof(SSID_rid);
/* Write it to the card */
@@ -5990,7 +6004,7 @@ static int airo_set_nick(struct net_device *dev,
struct airo_info *local = dev->priv;
/* Check the size of the string */
- if(dwrq->length > 16 + 1) {
+ if(dwrq->length > 16) {
return -E2BIG;
}
readConfigRid(local, 1);
@@ -6015,7 +6029,7 @@ static int airo_get_nick(struct net_device *dev,
readConfigRid(local, 1);
strncpy(extra, local->config.nodeName, 16);
extra[16] = '\0';
- dwrq->length = strlen(extra) + 1;
+ dwrq->length = strlen(extra);
return 0;
}
@@ -6767,9 +6781,9 @@ static int airo_set_retry(struct net_device *dev,
}
readConfigRid(local, 1);
if(vwrq->flags & IW_RETRY_LIMIT) {
- if(vwrq->flags & IW_RETRY_MAX)
+ if(vwrq->flags & IW_RETRY_LONG)
local->config.longRetryLimit = vwrq->value;
- else if (vwrq->flags & IW_RETRY_MIN)
+ else if (vwrq->flags & IW_RETRY_SHORT)
local->config.shortRetryLimit = vwrq->value;
else {
/* No modifier : set both */
@@ -6805,14 +6819,14 @@ static int airo_get_retry(struct net_device *dev,
if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
vwrq->flags = IW_RETRY_LIFETIME;
vwrq->value = (int)local->config.txLifetime * 1024;
- } else if((vwrq->flags & IW_RETRY_MAX)) {
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ } else if((vwrq->flags & IW_RETRY_LONG)) {
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
vwrq->value = (int)local->config.longRetryLimit;
} else {
vwrq->flags = IW_RETRY_LIMIT;
vwrq->value = (int)local->config.shortRetryLimit;
if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
- vwrq->flags |= IW_RETRY_MIN;
+ vwrq->flags |= IW_RETRY_SHORT;
}
return 0;
@@ -6990,6 +7004,7 @@ static int airo_set_power(struct net_device *dev,
local->config.rmode |= RXMODE_BC_MC_ADDR;
set_bit (FLAG_COMMIT, &local->flags);
case IW_POWER_ON:
+ /* This is broken, fixme ;-) */
break;
default:
return -EINVAL;
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index bb6bea4f3233..4688e56b69c7 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -78,7 +78,7 @@ static int arlans_found;
static int arlan_open(struct net_device *dev);
static int arlan_tx(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t arlan_interrupt(int irq, void *dev_id);
static int arlan_close(struct net_device *dev);
static struct net_device_stats *
arlan_statistics (struct net_device *dev);
@@ -1651,7 +1651,7 @@ end_int_process:
return;
}
-static irqreturn_t arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t arlan_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct arlan_private *priv = netdev_priv(dev);
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 995c7bea5897..31eed85de60f 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -1145,7 +1145,7 @@ next:
}
}
-static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t service_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct atmel_private *priv = netdev_priv(dev);
@@ -1656,13 +1656,13 @@ static int atmel_set_essid(struct net_device *dev,
priv->connect_to_any_BSS = 0;
/* Check the size of the string */
- if (dwrq->length > MAX_SSID_LENGTH + 1)
+ if (dwrq->length > MAX_SSID_LENGTH)
return -E2BIG;
if (index != 0)
return -EINVAL;
- memcpy(priv->new_SSID, extra, dwrq->length - 1);
- priv->new_SSID_size = dwrq->length - 1;
+ memcpy(priv->new_SSID, extra, dwrq->length);
+ priv->new_SSID_size = dwrq->length;
}
return -EINPROGRESS;
@@ -2120,9 +2120,9 @@ static int atmel_set_retry(struct net_device *dev,
struct atmel_private *priv = netdev_priv(dev);
if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
- if (vwrq->flags & IW_RETRY_MAX)
+ if (vwrq->flags & IW_RETRY_LONG)
priv->long_retry = vwrq->value;
- else if (vwrq->flags & IW_RETRY_MIN)
+ else if (vwrq->flags & IW_RETRY_SHORT)
priv->short_retry = vwrq->value;
else {
/* No modifier : set both */
@@ -2144,15 +2144,15 @@ static int atmel_get_retry(struct net_device *dev,
vwrq->disabled = 0; /* Can't be disabled */
- /* Note : by default, display the min retry number */
- if (vwrq->flags & IW_RETRY_MAX) {
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ /* Note : by default, display the short retry number */
+ if (vwrq->flags & IW_RETRY_LONG) {
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
vwrq->value = priv->long_retry;
} else {
vwrq->flags = IW_RETRY_LIMIT;
vwrq->value = priv->short_retry;
if (priv->long_retry != priv->short_retry)
- vwrq->flags |= IW_RETRY_MIN;
+ vwrq->flags |= IW_RETRY_SHORT;
}
return 0;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h
index 6d4ea36bc564..d6a8bf09878e 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx.h
+++ b/drivers/net/wireless/bcm43xx/bcm43xx.h
@@ -666,7 +666,6 @@ struct bcm43xx_noise_calculation {
};
struct bcm43xx_stats {
- u8 link_quality;
u8 noise;
struct iw_statistics wstats;
/* Store the last TX/RX times here for updating the leds. */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
index 923275ea0789..b9df06a06ea9 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_debugfs.c
@@ -54,7 +54,7 @@ static ssize_t write_file_dummy(struct file *file, const char __user *buf,
static int open_file_generic(struct inode *inode, struct file *file)
{
- file->private_data = inode->u.generic_ip;
+ file->private_data = inode->i_private;
return 0;
}
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
index cb9a3ae8463a..bad3452ea893 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c
@@ -1834,7 +1834,7 @@ static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
}
/* Interrupt handler top-half */
-static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id)
{
irqreturn_t ret = IRQ_HANDLED;
struct bcm43xx_private *bcm = dev_id;
@@ -2405,9 +2405,10 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
BCM43xx_UCODE_TIME) & 0x1f);
if ( value16 > 0x128 ) {
- dprintk(KERN_ERR PFX
- "Firmware: no support for microcode rev > 0x128\n");
- err = -1;
+ printk(KERN_ERR PFX
+ "Firmware: no support for microcode extracted "
+ "from version 4.x binary drivers.\n");
+ err = -EOPNOTSUPP;
goto err_release_fw;
}
@@ -3169,8 +3170,7 @@ static void bcm43xx_periodic_work_handler(void *d)
* be preemtible.
*/
mutex_lock(&bcm->mutex);
- netif_stop_queue(bcm->net_dev);
- synchronize_net();
+ netif_tx_disable(bcm->net_dev);
spin_lock_irqsave(&bcm->irq_lock, flags);
bcm43xx_mac_suspend(bcm);
if (bcm43xx_using_pio(bcm))
@@ -3963,7 +3963,7 @@ static void bcm43xx_net_poll_controller(struct net_device *net_dev)
local_irq_save(flags);
if (bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED)
- bcm43xx_interrupt_handler(bcm->irq, bcm, NULL);
+ bcm43xx_interrupt_handler(bcm->irq, bcm);
local_irq_restore(flags);
}
#endif /* CONFIG_NET_POLL_CONTROLLER */
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
index eafd0f662686..52ce2a9334fb 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c
@@ -361,7 +361,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev <= 2)
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
- else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
+ else if ((phy->rev >= 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
else
@@ -371,7 +371,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
if (phy->rev == 2)
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
- else if ((phy->rev > 2) && (phy->rev <= 7))
+ else if ((phy->rev > 2) && (phy->rev <= 8))
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
@@ -1197,7 +1197,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
if (phy->rev == 1)
bcm43xx_phy_initb5(bcm);
- else if (phy->rev >= 2 && phy->rev <= 7)
+ else
bcm43xx_phy_initb6(bcm);
if (phy->rev >= 2 || phy->connected)
bcm43xx_phy_inita(bcm);
@@ -1241,23 +1241,22 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
bcm43xx_phy_lo_g_measure(bcm);
} else {
if (radio->version == 0x2050 && radio->revision == 8) {
- //FIXME
+ bcm43xx_radio_write16(bcm, 0x0052,
+ (radio->txctl1 << 4) | radio->txctl2);
} else {
bcm43xx_radio_write16(bcm, 0x0052,
(bcm43xx_radio_read16(bcm, 0x0052)
& 0xFFF0) | radio->txctl1);
}
if (phy->rev >= 6) {
- /*
bcm43xx_phy_write(bcm, 0x0036,
(bcm43xx_phy_read(bcm, 0x0036)
- & 0xF000) | (FIXME << 12));
- */
+ & 0xF000) | (radio->txctl2 << 12));
}
if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
bcm43xx_phy_write(bcm, 0x002E, 0x8075);
else
- bcm43xx_phy_write(bcm, 0x003E, 0x807F);
+ bcm43xx_phy_write(bcm, 0x002E, 0x807F);
if (phy->rev < 2)
bcm43xx_phy_write(bcm, 0x002F, 0x0101);
else
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
index 888077fc14c4..9b7b15cf6561 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_wx.c
@@ -334,7 +334,7 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
size_t len;
mutex_lock(&bcm->mutex);
- len = strlen(bcm->nick) + 1;
+ len = strlen(bcm->nick);
memcpy(extra, bcm->nick, len);
data->data.length = (__u16)len;
data->data.flags = 1;
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
index c0efbfe605a5..0159e4e93201 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_xmit.c
@@ -496,15 +496,14 @@ int bcm43xx_rx(struct bcm43xx_private *bcm,
stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
!!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
!!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
-//TODO stats.noise =
+ stats.noise = bcm->stats.noise;
if (is_ofdm)
stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
else
stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
stats.received_channel = radio->channel;
-//TODO stats.control =
stats.mask = IEEE80211_STATMASK_SIGNAL |
-//TODO IEEE80211_STATMASK_NOISE |
+ IEEE80211_STATMASK_NOISE |
IEEE80211_STATMASK_RATE |
IEEE80211_STATMASK_RSSI;
if (phy->type == BCM43xx_PHYTYPE_A)
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
index d500012fdc7a..ed00ebb6e7f4 100644
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -2622,7 +2622,7 @@ static void prism2_check_magic(local_info_t *local)
/* Called only from hardware IRQ */
-static irqreturn_t prism2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t prism2_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *) dev_id;
struct hostap_interface *iface;
diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c
index 7a4978516eac..d061fb3443ff 100644
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1412,9 +1412,9 @@ static int prism2_ioctl_siwretry(struct net_device *dev,
/* what could be done, if firmware would support this.. */
if (rrq->flags & IW_RETRY_LIMIT) {
- if (rrq->flags & IW_RETRY_MAX)
+ if (rrq->flags & IW_RETRY_LONG)
HFA384X_RID_LONGRETRYLIMIT = rrq->value;
- else if (rrq->flags & IW_RETRY_MIN)
+ else if (rrq->flags & IW_RETRY_SHORT)
HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
else {
HFA384X_RID_LONGRETRYLIMIT = rrq->value;
@@ -1468,14 +1468,14 @@ static int prism2_ioctl_giwretry(struct net_device *dev,
rrq->value = le16_to_cpu(altretry);
else
rrq->value = local->manual_retry_count;
- } else if ((rrq->flags & IW_RETRY_MAX)) {
- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ } else if ((rrq->flags & IW_RETRY_LONG)) {
+ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
rrq->value = longretry;
} else {
rrq->flags = IW_RETRY_LIMIT;
rrq->value = shortretry;
if (shortretry != longretry)
- rrq->flags |= IW_RETRY_MIN;
+ rrq->flags |= IW_RETRY_SHORT;
}
}
return 0;
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c
index b4d81a04c895..4e4eaa2a99ca 100644
--- a/drivers/net/wireless/ipw2100.c
+++ b/drivers/net/wireless/ipw2100.c
@@ -150,7 +150,6 @@ that only one external action is invoked at a time.
#include <linux/skbuff.h>
#include <asm/uaccess.h>
#include <asm/io.h>
-#define __KERNEL_SYSCALLS__
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/slab.h>
@@ -163,6 +162,7 @@ that only one external action is invoked at a time.
#include <linux/firmware.h>
#include <linux/acpi.h>
#include <linux/ctype.h>
+#include <linux/latency.h>
#include "ipw2100.h"
@@ -1697,6 +1697,11 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
return 0;
}
+ /* the ipw2100 hardware really doesn't want power management delays
+ * longer than 175usec
+ */
+ modify_acceptable_latency("ipw2100", 175);
+
/* If the interrupt is enabled, turn it off... */
spin_lock_irqsave(&priv->low_lock, flags);
ipw2100_disable_interrupts(priv);
@@ -1849,6 +1854,8 @@ static void ipw2100_down(struct ipw2100_priv *priv)
ipw2100_disable_interrupts(priv);
spin_unlock_irqrestore(&priv->low_lock, flags);
+ modify_acceptable_latency("ipw2100", INFINITE_LATENCY);
+
#ifdef ACPI_CSTATE_LIMIT_DEFINED
if (priv->config & CFG_C3_DISABLED) {
IPW_DEBUG_INFO(": Resetting C3 transitions.\n");
@@ -3248,7 +3255,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv)
IPW_DEBUG_ISR("exit\n");
}
-static irqreturn_t ipw2100_interrupt(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t ipw2100_interrupt(int irq, void *data)
{
struct ipw2100_priv *priv = data;
u32 inta, inta_mask;
@@ -6267,7 +6274,9 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev,
IPW_DEBUG_INFO("%s: Bound to %s\n", dev->name, pci_name(pci_dev));
/* perform this after register_netdev so that dev->name is set */
- sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+ err = sysfs_create_group(&pci_dev->dev.kobj, &ipw2100_attribute_group);
+ if (err)
+ goto fail_unlock;
/* If the RF Kill switch is disabled, go ahead and complete the
* startup sequence */
@@ -6533,13 +6542,17 @@ static int __init ipw2100_init(void)
printk(KERN_INFO DRV_NAME ": %s\n", DRV_COPYRIGHT);
ret = pci_register_driver(&ipw2100_pci_driver);
+ if (ret)
+ goto out;
+ set_acceptable_latency("ipw2100", INFINITE_LATENCY);
#ifdef CONFIG_IPW2100_DEBUG
ipw2100_debug_level = debug;
- driver_create_file(&ipw2100_pci_driver.driver,
- &driver_attr_debug_level);
+ ret = driver_create_file(&ipw2100_pci_driver.driver,
+ &driver_attr_debug_level);
#endif
+out:
return ret;
}
@@ -6554,6 +6567,7 @@ static void __exit ipw2100_exit(void)
&driver_attr_debug_level);
#endif
pci_unregister_driver(&ipw2100_pci_driver);
+ remove_acceptable_latency("ipw2100");
}
module_init(ipw2100_init);
@@ -6958,7 +6972,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
}
if (wrqu->essid.flags && wrqu->essid.length) {
- length = wrqu->essid.length - 1;
+ length = wrqu->essid.length;
essid = extra;
}
@@ -7051,7 +7065,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
struct ipw2100_priv *priv = ieee80211_priv(dev);
- wrqu->data.length = strlen(priv->nick) + 1;
+ wrqu->data.length = strlen(priv->nick);
memcpy(extra, priv->nick, wrqu->data.length);
wrqu->data.flags = 1; /* active */
@@ -7343,14 +7357,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
goto done;
}
- if (wrqu->retry.flags & IW_RETRY_MIN) {
+ if (wrqu->retry.flags & IW_RETRY_SHORT) {
err = ipw2100_set_short_retry(priv, wrqu->retry.value);
IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
wrqu->retry.value);
goto done;
}
- if (wrqu->retry.flags & IW_RETRY_MAX) {
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
err = ipw2100_set_long_retry(priv, wrqu->retry.value);
IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
wrqu->retry.value);
@@ -7383,14 +7397,14 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
return -EINVAL;
- if (wrqu->retry.flags & IW_RETRY_MAX) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
wrqu->retry.value = priv->long_retry_limit;
} else {
wrqu->retry.flags =
(priv->short_retry_limit !=
priv->long_retry_limit) ?
- IW_RETRY_LIMIT | IW_RETRY_MIN : IW_RETRY_LIMIT;
+ IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
wrqu->retry.value = priv->short_retry_limit;
}
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c
index 7358664e0908..1f742814a01c 100644
--- a/drivers/net/wireless/ipw2200.c
+++ b/drivers/net/wireless/ipw2200.c
@@ -8875,8 +8875,6 @@ static int ipw_wx_set_essid(struct net_device *dev,
}
length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
- if (!extra[length - 1])
- length--;
priv->config |= CFG_STATIC_ESSID;
@@ -8953,7 +8951,7 @@ static int ipw_wx_get_nick(struct net_device *dev,
struct ipw_priv *priv = ieee80211_priv(dev);
IPW_DEBUG_WX("Getting nick\n");
mutex_lock(&priv->mutex);
- wrqu->data.length = strlen(priv->nick) + 1;
+ wrqu->data.length = strlen(priv->nick);
memcpy(extra, priv->nick, wrqu->data.length);
wrqu->data.flags = 1; /* active */
mutex_unlock(&priv->mutex);
@@ -9276,9 +9274,9 @@ static int ipw_wx_set_retry(struct net_device *dev,
return -EINVAL;
mutex_lock(&priv->mutex);
- if (wrqu->retry.flags & IW_RETRY_MIN)
+ if (wrqu->retry.flags & IW_RETRY_SHORT)
priv->short_retry_limit = (u8) wrqu->retry.value;
- else if (wrqu->retry.flags & IW_RETRY_MAX)
+ else if (wrqu->retry.flags & IW_RETRY_LONG)
priv->long_retry_limit = (u8) wrqu->retry.value;
else {
priv->short_retry_limit = (u8) wrqu->retry.value;
@@ -9307,11 +9305,11 @@ static int ipw_wx_get_retry(struct net_device *dev,
return -EINVAL;
}
- if (wrqu->retry.flags & IW_RETRY_MAX) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
wrqu->retry.value = priv->long_retry_limit;
- } else if (wrqu->retry.flags & IW_RETRY_MIN) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ } else if (wrqu->retry.flags & IW_RETRY_SHORT) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
wrqu->retry.value = priv->short_retry_limit;
} else {
wrqu->retry.flags = IW_RETRY_LIMIT;
@@ -10469,7 +10467,7 @@ static const struct ethtool_ops ipw_ethtool_ops = {
.set_eeprom = ipw_ethtool_set_eeprom,
};
-static irqreturn_t ipw_isr(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t ipw_isr(int irq, void *data)
{
struct ipw_priv *priv = data;
u32 inta, inta_mask;
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 36b5e004305e..6714e0dfa8d6 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -207,7 +207,7 @@ static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
static int netwave_rx( struct net_device *dev);
/* Interrupt routines */
-static irqreturn_t netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t netwave_interrupt(int irq, void *dev_id);
static void netwave_watchdog(struct net_device *);
/* Statistics */
@@ -1072,7 +1072,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
} /* netwave_start_xmit */
/*
- * Function netwave_interrupt (irq, dev_id, regs)
+ * Function netwave_interrupt (irq, dev_id)
*
* This function is the interrupt handler for the Netwave card. This
* routine will be called whenever:
@@ -1081,7 +1081,7 @@ static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
* ready to transmit another packet.
* 3. A command has completed execution.
*/
-static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs)
+static irqreturn_t netwave_interrupt(int irq, void* dev_id)
{
kio_addr_t iobase;
u_char __iomem *ramBase;
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index 1840b69e3cb5..b779c7dcc1a8 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -1952,9 +1952,9 @@ static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw)
dev->name);
}
-irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t orinoco_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
int count = MAX_IRQLOOPS_PER_IRQ;
@@ -3037,7 +3037,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
}
erq->flags = 1;
- erq->length = strlen(essidbuf) + 1;
+ erq->length = strlen(essidbuf);
return 0;
}
@@ -3078,7 +3078,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev,
memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
orinoco_unlock(priv, &flags);
- nrq->length = strlen(nickbuf)+1;
+ nrq->length = strlen(nickbuf);
return 0;
}
@@ -3575,14 +3575,14 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
rrq->value = lifetime * 1000; /* ??? */
} else {
/* By default, display the min number */
- if ((rrq->flags & IW_RETRY_MAX)) {
- rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if ((rrq->flags & IW_RETRY_LONG)) {
+ rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
rrq->value = long_limit;
} else {
rrq->flags = IW_RETRY_LIMIT;
rrq->value = short_limit;
if(short_limit != long_limit)
- rrq->flags |= IW_RETRY_MIN;
+ rrq->flags |= IW_RETRY_SHORT;
}
}
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index fb5700d6c454..4720fb20d66d 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -128,7 +128,7 @@ extern void free_orinocodev(struct net_device *dev);
extern int __orinoco_up(struct net_device *dev);
extern int __orinoco_down(struct net_device *dev);
extern int orinoco_reinit_firmware(struct net_device *dev);
-extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
+extern irqreturn_t orinoco_interrupt(int irq, void * dev_id);
/********************************************************************/
/* Locking and synchronization functions */
diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c
index c09fbf733b3a..286325ca3293 100644
--- a/drivers/net/wireless/prism54/isl_ioctl.c
+++ b/drivers/net/wireless/prism54/isl_ioctl.c
@@ -742,9 +742,9 @@ prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
/* Check if we were asked for `any' */
if (dwrq->flags && dwrq->length) {
- if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
+ if (dwrq->length > 32)
return -E2BIG;
- essid.length = dwrq->length - 1;
+ essid.length = dwrq->length;
memcpy(essid.octets, extra, dwrq->length);
} else
essid.length = 0;
@@ -814,7 +814,7 @@ prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
dwrq->length = 0;
down_read(&priv->mib_sem);
- dwrq->length = strlen(priv->nickname) + 1;
+ dwrq->length = strlen(priv->nickname);
memcpy(extra, priv->nickname, dwrq->length);
up_read(&priv->mib_sem);
@@ -992,9 +992,9 @@ prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
return -EINVAL;
if (vwrq->flags & IW_RETRY_LIMIT) {
- if (vwrq->flags & IW_RETRY_MIN)
+ if (vwrq->flags & IW_RETRY_SHORT)
slimit = vwrq->value;
- else if (vwrq->flags & IW_RETRY_MAX)
+ else if (vwrq->flags & IW_RETRY_LONG)
llimit = vwrq->value;
else {
/* we are asked to set both */
@@ -1035,18 +1035,18 @@ prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
vwrq->value = r.u * 1024;
vwrq->flags = IW_RETRY_LIFETIME;
- } else if ((vwrq->flags & IW_RETRY_MAX)) {
+ } else if ((vwrq->flags & IW_RETRY_LONG)) {
/* we are asked for the long retry limit */
rvalue |=
mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
vwrq->value = r.u;
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
} else {
/* default. get the short retry limit */
rvalue |=
mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
vwrq->value = r.u;
- vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
}
return rvalue;
diff --git a/drivers/net/wireless/prism54/islpci_dev.c b/drivers/net/wireless/prism54/islpci_dev.c
index ab3c5a27efd9..ec1c00f19eb3 100644
--- a/drivers/net/wireless/prism54/islpci_dev.c
+++ b/drivers/net/wireless/prism54/islpci_dev.c
@@ -182,7 +182,7 @@ isl_upload_firmware(islpci_private *priv)
******************************************************************************/
irqreturn_t
-islpci_interrupt(int irq, void *config, struct pt_regs *regs)
+islpci_interrupt(int irq, void *config)
{
u32 reg;
islpci_private *priv = config;
diff --git a/drivers/net/wireless/prism54/islpci_dev.h b/drivers/net/wireless/prism54/islpci_dev.h
index 5049f37455b1..2f7e525d0cf6 100644
--- a/drivers/net/wireless/prism54/islpci_dev.h
+++ b/drivers/net/wireless/prism54/islpci_dev.h
@@ -198,7 +198,7 @@ islpci_state_t islpci_set_state(islpci_private *priv, islpci_state_t new_state);
#define ISLPCI_TX_TIMEOUT (2*HZ)
-irqreturn_t islpci_interrupt(int, void *, struct pt_regs *);
+irqreturn_t islpci_interrupt(int, void *);
int prism54_post_setup(islpci_private *, int);
int islpci_reset(islpci_private *, int);
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 4574290f971f..0b381d77015c 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -130,7 +130,7 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, i
static void verify_dl_startup(u_long);
/* Prototypes for interrpt time functions **********************************/
-static irqreturn_t ray_interrupt (int reg, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ray_interrupt (int reg, void *dev_id);
static void clear_interrupt(ray_dev_t *local);
static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
unsigned int pkt_addr, int rx_len);
@@ -1173,7 +1173,7 @@ static int ray_set_essid(struct net_device *dev,
return -EOPNOTSUPP;
} else {
/* Check the size of the string */
- if(dwrq->length > IW_ESSID_MAX_SIZE + 1) {
+ if(dwrq->length > IW_ESSID_MAX_SIZE) {
return -E2BIG;
}
@@ -1940,7 +1940,7 @@ static void set_multicast_list(struct net_device *dev)
/*=============================================================================
* All routines below here are run at interrupt time.
=============================================================================*/
-static irqreturn_t ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t ray_interrupt(int irq, void *dev_id)
{
struct net_device *dev = (struct net_device *)dev_id;
struct pcmcia_device *link;
diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c
index ccaf28e8db0a..337c692f6fd6 100644
--- a/drivers/net/wireless/strip.c
+++ b/drivers/net/wireless/strip.c
@@ -1342,7 +1342,7 @@ static unsigned char *strip_make_packet(unsigned char *buffer,
* 'broadcast hub' radio (First byte of address being 0xFF means broadcast)
*/
if (haddr.c[0] == 0xFF) {
- u32 brd = 0;
+ __be32 brd = 0;
struct in_device *in_dev;
rcu_read_lock();
@@ -1406,7 +1406,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
int doreset = (long) jiffies - strip_info->watchdog_doreset >= 0;
int doprobe = (long) jiffies - strip_info->watchdog_doprobe >= 0
&& !doreset;
- u32 addr, brd;
+ __be32 addr, brd;
/*
* 1. If we have a packet, encapsulate it and put it in the buffer
diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
index 5b69befdab74..24221e476cd3 100644
--- a/drivers/net/wireless/wavelan.c
+++ b/drivers/net/wireless/wavelan.c
@@ -3768,7 +3768,7 @@ static int wv_check_ioaddr(unsigned long ioaddr, u8 * mac)
* This function is the interrupt handler for the WaveLAN card. This
* routine will be called whenever:
*/
-static irqreturn_t wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wavelan_interrupt(int irq, void *dev_id)
{
struct net_device *dev;
unsigned long ioaddr;
diff --git a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
index 5cb0bc8bb128..72b646c77d5a 100644
--- a/drivers/net/wireless/wavelan.p.h
+++ b/drivers/net/wireless/wavelan.p.h
@@ -642,8 +642,7 @@ static int
/* ---------------------- INTERRUPT HANDLING ---------------------- */
static irqreturn_t
wavelan_interrupt(int, /* interrupt handler */
- void *,
- struct pt_regs *);
+ void *);
static void
wavelan_watchdog(struct net_device *); /* transmission watchdog */
/* ------------------- CONFIGURATION CALLBACKS ------------------- */
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index 0065f057bb1c..aafb301041b1 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -4117,24 +4117,14 @@ wv_pcmcia_release(struct pcmcia_device *link)
*/
static irqreturn_t
wavelan_interrupt(int irq,
- void * dev_id,
- struct pt_regs * regs)
+ void * dev_id)
{
- struct net_device * dev;
+ struct net_device * dev = dev_id;
net_local * lp;
kio_addr_t base;
int status0;
u_int tx_status;
- if ((dev = dev_id) == NULL)
- {
-#ifdef DEBUG_INTERRUPT_ERROR
- printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n",
- irq);
-#endif
- return IRQ_NONE;
- }
-
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
#endif
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index f34a36b0c7b0..4d1c4905c749 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -738,8 +738,7 @@ static void
/* ---------------------- INTERRUPT HANDLING ---------------------- */
static irqreturn_t
wavelan_interrupt(int, /* Interrupt handler */
- void *,
- struct pt_regs *);
+ void *);
static void
wavelan_watchdog(struct net_device *); /* Transmission watchdog */
/* ------------------- CONFIGURATION CALLBACKS ------------------- */
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index e0d294c12970..5b98a7876982 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -1145,7 +1145,6 @@ static inline void wl3501_ack_interrupt(struct wl3501_card *this)
* wl3501_interrupt - Hardware interrupt from card.
* @irq - Interrupt number
* @dev_id - net_device
- * @regs - registers
*
* We must acknowledge the interrupt as soon as possible, and block the
* interrupt from the same card immediately to prevent re-entry.
@@ -1154,27 +1153,20 @@ static inline void wl3501_ack_interrupt(struct wl3501_card *this)
* On the other hand, to prevent SUTRO from malfunctioning, we must
* unlock the SUTRO as soon as possible.
*/
-static irqreturn_t wl3501_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wl3501_interrupt(int irq, void *dev_id)
{
- struct net_device *dev = (struct net_device *)dev_id;
+ struct net_device *dev = dev_id;
struct wl3501_card *this;
- int handled = 1;
- if (!dev)
- goto unknown;
- this = dev->priv;
+ this = netdev_priv(dev);
spin_lock(&this->lock);
wl3501_ack_interrupt(this);
wl3501_block_interrupt(this);
wl3501_rx_interrupt(dev);
wl3501_unblock_interrupt(this);
spin_unlock(&this->lock);
-out:
- return IRQ_RETVAL(handled);
-unknown:
- handled = 0;
- printk(KERN_ERR "%s: irq %d for unknown device.\n", __FUNCTION__, irq);
- goto out;
+
+ return IRQ_HANDLED;
}
static int wl3501_reset_board(struct wl3501_card *this)
@@ -1802,15 +1794,15 @@ static int wl3501_get_retry(struct net_device *dev,
&retry, sizeof(retry));
if (rc)
goto out;
- if (wrqu->retry.flags & IW_RETRY_MAX) {
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (wrqu->retry.flags & IW_RETRY_LONG) {
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
goto set_value;
}
rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
&retry, sizeof(retry));
if (rc)
goto out;
- wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
set_value:
wrqu->retry.value = retry;
wrqu->retry.disabled = 0;
diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c
index c52e9bcf8d02..30057a335a7b 100644
--- a/drivers/net/wireless/zd1201.c
+++ b/drivers/net/wireless/zd1201.c
@@ -112,14 +112,14 @@ exit:
return err;
}
-static void zd1201_usbfree(struct urb *urb, struct pt_regs *regs)
+static void zd1201_usbfree(struct urb *urb)
{
struct zd1201 *zd = urb->context;
switch(urb->status) {
case -EILSEQ:
case -ENODEV:
- case -ETIMEDOUT:
+ case -ETIME:
case -ENOENT:
case -EPIPE:
case -EOVERFLOW:
@@ -177,7 +177,7 @@ static int zd1201_docmd(struct zd1201 *zd, int cmd, int parm0,
}
/* Callback after sending out a packet */
-static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs)
+static void zd1201_usbtx(struct urb *urb)
{
struct zd1201 *zd = urb->context;
netif_wake_queue(zd->dev);
@@ -185,7 +185,7 @@ static void zd1201_usbtx(struct urb *urb, struct pt_regs *regs)
}
/* Incoming data */
-static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
+static void zd1201_usbrx(struct urb *urb)
{
struct zd1201 *zd = urb->context;
int free = 0;
@@ -201,7 +201,7 @@ static void zd1201_usbrx(struct urb *urb, struct pt_regs *regs)
switch(urb->status) {
case -EILSEQ:
case -ENODEV:
- case -ETIMEDOUT:
+ case -ETIME:
case -ENOENT:
case -EPIPE:
case -EOVERFLOW:
@@ -1218,7 +1218,7 @@ static int zd1201_set_essid(struct net_device *dev,
return -EINVAL;
if (data->length < 1)
data->length = 1;
- zd->essidlen = data->length-1;
+ zd->essidlen = data->length;
memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
memcpy(zd->essid, essid, data->length);
return zd1201_join(zd, zd->essid, zd->essidlen);
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c
index 7c4e32cf0d47..aa661b2b76c7 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.c
+++ b/drivers/net/wireless/zd1211rw/zd_chip.c
@@ -249,7 +249,6 @@ int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value)
{
int r;
- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
mutex_lock(&chip->mutex);
r = zd_ioread16_locked(chip, value, addr);
mutex_unlock(&chip->mutex);
@@ -260,7 +259,6 @@ int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value)
{
int r;
- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
mutex_lock(&chip->mutex);
r = zd_ioread32_locked(chip, value, addr);
mutex_unlock(&chip->mutex);
@@ -271,7 +269,6 @@ int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value)
{
int r;
- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
mutex_lock(&chip->mutex);
r = zd_iowrite16_locked(chip, value, addr);
mutex_unlock(&chip->mutex);
@@ -282,7 +279,6 @@ int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value)
{
int r;
- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
mutex_lock(&chip->mutex);
r = zd_iowrite32_locked(chip, value, addr);
mutex_unlock(&chip->mutex);
@@ -294,7 +290,6 @@ int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
{
int r;
- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
mutex_lock(&chip->mutex);
r = zd_ioread32v_locked(chip, values, addresses, count);
mutex_unlock(&chip->mutex);
@@ -306,7 +301,6 @@ int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
{
int r;
- ZD_ASSERT(!mutex_is_locked(&chip->mutex));
mutex_lock(&chip->mutex);
r = zd_iowrite32a_locked(chip, ioreqs, count);
mutex_unlock(&chip->mutex);
@@ -331,13 +325,22 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type)
chip->patch_cr157 = (value >> 13) & 0x1;
chip->patch_6m_band_edge = (value >> 21) & 0x1;
chip->new_phy_layout = (value >> 31) & 0x1;
+ chip->link_led = ((value >> 4) & 1) ? LED1 : LED2;
+ chip->supports_tx_led = 1;
+ if (value & (1 << 24)) { /* LED scenario */
+ if (value & (1 << 29))
+ chip->supports_tx_led = 0;
+ }
dev_dbg_f(zd_chip_dev(chip),
"RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
- "patch 6M %d new PHY %d\n",
+ "patch 6M %d new PHY %d link LED%d tx led %d\n",
zd_rf_name(*rf_type), *rf_type,
chip->pa_type, chip->patch_cck_gain,
- chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout);
+ chip->patch_cr157, chip->patch_6m_band_edge,
+ chip->new_phy_layout,
+ chip->link_led == LED1 ? 1 : 2,
+ chip->supports_tx_led);
return 0;
error:
*rf_type = 0;
@@ -1181,7 +1184,7 @@ static int update_pwr_int(struct zd_chip *chip, u8 channel)
u8 value = chip->pwr_int_values[channel - 1];
dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
channel, value);
- return zd_iowrite32_locked(chip, value, CR31);
+ return zd_iowrite16_locked(chip, value, CR31);
}
static int update_pwr_cal(struct zd_chip *chip, u8 channel)
@@ -1189,12 +1192,12 @@ static int update_pwr_cal(struct zd_chip *chip, u8 channel)
u8 value = chip->pwr_cal_values[channel-1];
dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
channel, value);
- return zd_iowrite32_locked(chip, value, CR68);
+ return zd_iowrite16_locked(chip, value, CR68);
}
static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
{
- struct zd_ioreq32 ioreqs[3];
+ struct zd_ioreq16 ioreqs[3];
ioreqs[0].addr = CR67;
ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
@@ -1206,7 +1209,7 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
dev_dbg_f(zd_chip_dev(chip),
"channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
- return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
}
static int update_channel_integration_and_calibration(struct zd_chip *chip,
@@ -1218,7 +1221,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
if (r)
return r;
if (chip->is_zd1211b) {
- static const struct zd_ioreq32 ioreqs[] = {
+ static const struct zd_ioreq16 ioreqs[] = {
{ CR69, 0x28 },
{},
{ CR69, 0x2a },
@@ -1230,7 +1233,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
r = update_pwr_cal(chip, channel);
if (r)
return r;
- r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
if (r)
return r;
}
@@ -1252,7 +1255,7 @@ static int patch_cck_gain(struct zd_chip *chip)
if (r)
return r;
dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
- return zd_iowrite32_locked(chip, value & 0xff, CR47);
+ return zd_iowrite16_locked(chip, value & 0xff, CR47);
}
int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
@@ -1295,89 +1298,60 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
return channel;
}
-static u16 led_mask(int led)
+int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
{
- switch (led) {
- case 1:
- return LED1;
- case 2:
- return LED2;
- default:
- return 0;
- }
-}
-
-static int read_led_reg(struct zd_chip *chip, u16 *status)
-{
- ZD_ASSERT(mutex_is_locked(&chip->mutex));
- return zd_ioread16_locked(chip, status, CR_LED);
-}
-
-static int write_led_reg(struct zd_chip *chip, u16 status)
-{
- ZD_ASSERT(mutex_is_locked(&chip->mutex));
- return zd_iowrite16_locked(chip, status, CR_LED);
-}
+ static const zd_addr_t a[] = {
+ FW_LINK_STATUS,
+ CR_LED,
+ };
-int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status)
-{
- int r, ret;
- u16 mask = led_mask(led);
- u16 reg;
+ int r;
+ u16 v[ARRAY_SIZE(a)];
+ struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
+ [0] = { FW_LINK_STATUS },
+ [1] = { CR_LED },
+ };
+ u16 other_led;
- if (!mask)
- return -EINVAL;
mutex_lock(&chip->mutex);
- r = read_led_reg(chip, &reg);
+ r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a));
if (r)
- return r;
+ goto out;
+
+ other_led = chip->link_led == LED1 ? LED2 : LED1;
+
switch (status) {
- case LED_STATUS:
- return (reg & mask) ? LED_ON : LED_OFF;
case LED_OFF:
- reg &= ~mask;
- ret = LED_OFF;
+ ioreqs[0].value = FW_LINK_OFF;
+ ioreqs[1].value = v[1] & ~(LED1|LED2);
break;
- case LED_FLIP:
- reg ^= mask;
- ret = (reg&mask) ? LED_ON : LED_OFF;
+ case LED_SCANNING:
+ ioreqs[0].value = FW_LINK_OFF;
+ ioreqs[1].value = v[1] & ~other_led;
+ if (get_seconds() % 3 == 0) {
+ ioreqs[1].value &= ~chip->link_led;
+ } else {
+ ioreqs[1].value |= chip->link_led;
+ }
break;
- case LED_ON:
- reg |= mask;
- ret = LED_ON;
+ case LED_ASSOCIATED:
+ ioreqs[0].value = FW_LINK_TX;
+ ioreqs[1].value = v[1] & ~other_led;
+ ioreqs[1].value |= chip->link_led;
break;
default:
- return -EINVAL;
- }
- r = write_led_reg(chip, reg);
- if (r) {
- ret = r;
+ r = -EINVAL;
goto out;
}
-out:
- mutex_unlock(&chip->mutex);
- return r;
-}
-
-int zd_chip_led_flip(struct zd_chip *chip, int led,
- const unsigned int *phases_msecs, unsigned int count)
-{
- int i, r;
- enum led_status status;
- r = zd_chip_led_status(chip, led, LED_STATUS);
- if (r)
- return r;
- status = r;
- for (i = 0; i < count; i++) {
- r = zd_chip_led_status(chip, led, LED_FLIP);
- if (r < 0)
+ if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) {
+ r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+ if (r)
goto out;
- msleep(phases_msecs[i]);
}
-
+ r = 0;
out:
- zd_chip_led_status(chip, led, status);
+ mutex_unlock(&chip->mutex);
return r;
}
@@ -1679,4 +1653,3 @@ int zd_rfwritev_cr_locked(struct zd_chip *chip,
return 0;
}
-
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h
index 4b1250859897..ae59597ce4e1 100644
--- a/drivers/net/wireless/zd1211rw/zd_chip.h
+++ b/drivers/net/wireless/zd1211rw/zd_chip.h
@@ -428,6 +428,7 @@
/* masks for controlling LEDs */
#define LED1 0x0100
#define LED2 0x0200
+#define LED_SW 0x0400
/* Seems to indicate that the configuration is over.
*/
@@ -629,6 +630,10 @@
#define FW_SOFT_RESET FW_REG(4)
#define FW_FLASH_CHK FW_REG(5)
+#define FW_LINK_OFF 0x0
+#define FW_LINK_TX 0x1
+/* 0x2 - link led on? */
+
enum {
CR_BASE_OFFSET = 0x9000,
FW_START_OFFSET = 0xee00,
@@ -663,8 +668,11 @@ struct zd_chip {
u8 pwr_int_values[E2P_CHANNEL_COUNT];
/* SetPointOFDM in the vendor driver */
u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
- u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
- new_phy_layout:1, is_zd1211b:1;
+ u16 link_led;
+ unsigned int pa_type:4,
+ patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
+ new_phy_layout:1,
+ is_zd1211b:1, supports_tx_led:1;
};
static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
@@ -812,15 +820,12 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip);
int zd_chip_unlock_phy_regs(struct zd_chip *chip);
enum led_status {
- LED_OFF = 0,
- LED_ON = 1,
- LED_FLIP = 2,
- LED_STATUS = 3,
+ LED_OFF = 0,
+ LED_SCANNING = 1,
+ LED_ASSOCIATED = 2,
};
-int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status);
-int zd_chip_led_flip(struct zd_chip *chip, int led,
- const unsigned int *phases_msecs, unsigned int count);
+int zd_chip_control_leds(struct zd_chip *chip, enum led_status status);
int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c
index 1989f1c05fbe..2d12837052b0 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.c
+++ b/drivers/net/wireless/zd1211rw/zd_mac.c
@@ -33,6 +33,10 @@
static void ieee_init(struct ieee80211_device *ieee);
static void softmac_init(struct ieee80211softmac_device *sm);
+static void housekeeping_init(struct zd_mac *mac);
+static void housekeeping_enable(struct zd_mac *mac);
+static void housekeeping_disable(struct zd_mac *mac);
+
int zd_mac_init(struct zd_mac *mac,
struct net_device *netdev,
struct usb_interface *intf)
@@ -46,6 +50,7 @@ int zd_mac_init(struct zd_mac *mac,
ieee_init(ieee);
softmac_init(ieee80211_priv(netdev));
zd_chip_init(&mac->chip, netdev, intf);
+ housekeeping_init(mac);
return 0;
}
@@ -178,6 +183,7 @@ int zd_mac_open(struct net_device *netdev)
if (r < 0)
goto disable_rx;
+ housekeeping_enable(mac);
ieee80211softmac_start(netdev);
return 0;
disable_rx:
@@ -204,6 +210,7 @@ int zd_mac_stop(struct net_device *netdev)
*/
zd_chip_disable_rx(chip);
+ housekeeping_disable(mac);
ieee80211softmac_stop(netdev);
zd_chip_disable_hwint(chip);
@@ -1080,3 +1087,46 @@ void zd_dump_rx_status(const struct rx_status *status)
}
}
#endif /* DEBUG */
+
+#define LINK_LED_WORK_DELAY HZ
+
+static void link_led_handler(void *p)
+{
+ struct zd_mac *mac = p;
+ struct zd_chip *chip = &mac->chip;
+ struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
+ int is_associated;
+ int r;
+
+ spin_lock_irq(&mac->lock);
+ is_associated = sm->associated != 0;
+ spin_unlock_irq(&mac->lock);
+
+ r = zd_chip_control_leds(chip,
+ is_associated ? LED_ASSOCIATED : LED_SCANNING);
+ if (r)
+ dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
+
+ queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
+ LINK_LED_WORK_DELAY);
+}
+
+static void housekeeping_init(struct zd_mac *mac)
+{
+ INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac);
+}
+
+static void housekeeping_enable(struct zd_mac *mac)
+{
+ dev_dbg_f(zd_mac_dev(mac), "\n");
+ queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
+ 0);
+}
+
+static void housekeeping_disable(struct zd_mac *mac)
+{
+ dev_dbg_f(zd_mac_dev(mac), "\n");
+ cancel_rearming_delayed_workqueue(zd_workqueue,
+ &mac->housekeeping.link_led_work);
+ zd_chip_control_leds(&mac->chip, LED_OFF);
+}
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.h b/drivers/net/wireless/zd1211rw/zd_mac.h
index 29b51fd7d4e5..b8ea3de7924a 100644
--- a/drivers/net/wireless/zd1211rw/zd_mac.h
+++ b/drivers/net/wireless/zd1211rw/zd_mac.h
@@ -120,6 +120,10 @@ enum mac_flags {
MAC_FIXED_CHANNEL = 0x01,
};
+struct housekeeping {
+ struct work_struct link_led_work;
+};
+
#define ZD_MAC_STATS_BUFFER_SIZE 16
struct zd_mac {
@@ -128,6 +132,7 @@ struct zd_mac {
struct net_device *netdev;
/* Unlocked reading possible */
struct iw_statistics iw_stats;
+ struct housekeeping housekeeping;
unsigned int stats_count;
u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
diff --git a/drivers/net/wireless/zd1211rw/zd_netdev.c b/drivers/net/wireless/zd1211rw/zd_netdev.c
index 440ef24b5fd1..af3a7b36d078 100644
--- a/drivers/net/wireless/zd1211rw/zd_netdev.c
+++ b/drivers/net/wireless/zd1211rw/zd_netdev.c
@@ -82,7 +82,7 @@ static int iw_get_nick(struct net_device *netdev,
union iwreq_data *req, char *extra)
{
strcpy(extra, "zd1211");
- req->data.length = strlen(extra) + 1;
+ req->data.length = strlen(extra);
req->data.flags = 1;
return 0;
}
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c
index 31027e52b04b..3faaeb2b7c89 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.c
+++ b/drivers/net/wireless/zd1211rw/zd_usb.c
@@ -24,6 +24,7 @@
#include <linux/errno.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
+#include <linux/workqueue.h>
#include <net/ieee80211.h>
#include "zd_def.h"
@@ -407,7 +408,7 @@ static inline void handle_retry_failed_int(struct urb *urb)
}
-static void int_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+static void int_urb_complete(struct urb *urb)
{
int r;
struct usb_int_header *hdr;
@@ -608,7 +609,7 @@ static void handle_rx_packet(struct zd_usb *usb, const u8 *buffer,
}
}
-static void rx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+static void rx_urb_complete(struct urb *urb)
{
struct zd_usb *usb;
struct zd_usb_rx *rx;
@@ -778,7 +779,7 @@ void zd_usb_disable_rx(struct zd_usb *usb)
spin_unlock_irqrestore(&rx->lock, flags);
}
-static void tx_urb_complete(struct urb *urb, struct pt_regs *pt_regs)
+static void tx_urb_complete(struct urb *urb)
{
int r;
@@ -1112,12 +1113,20 @@ static struct usb_driver driver = {
.disconnect = disconnect,
};
+struct workqueue_struct *zd_workqueue;
+
static int __init usb_init(void)
{
int r;
pr_debug("usb_init()\n");
+ zd_workqueue = create_singlethread_workqueue(driver.name);
+ if (zd_workqueue == NULL) {
+ printk(KERN_ERR "%s: couldn't create workqueue\n", driver.name);
+ return -ENOMEM;
+ }
+
r = usb_register(&driver);
if (r) {
printk(KERN_ERR "usb_register() failed. Error number %d\n", r);
@@ -1132,6 +1141,7 @@ static void __exit usb_exit(void)
{
pr_debug("usb_exit()\n");
usb_deregister(&driver);
+ destroy_workqueue(zd_workqueue);
}
module_init(usb_init);
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.h b/drivers/net/wireless/zd1211rw/zd_usb.h
index ded39de5f72d..e81a2d3cfffd 100644
--- a/drivers/net/wireless/zd1211rw/zd_usb.h
+++ b/drivers/net/wireless/zd1211rw/zd_usb.h
@@ -238,4 +238,6 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
+extern struct workqueue_struct *zd_workqueue;
+
#endif /* _ZD_USB_H */
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index a4c4953f1365..2412ce4917f2 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -350,7 +350,7 @@ static void yellowfin_timer(unsigned long data);
static void yellowfin_tx_timeout(struct net_device *dev);
static void yellowfin_init_ring(struct net_device *dev);
static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance);
static int yellowfin_rx(struct net_device *dev);
static void yellowfin_error(struct net_device *dev, int intr_status);
static int yellowfin_close(struct net_device *dev);
@@ -888,7 +888,7 @@ static int yellowfin_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* The interrupt handler does all of the Rx thread work and cleans up
after the Tx thread. */
-static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct yellowfin_private *yp;
@@ -896,13 +896,6 @@ static irqreturn_t yellowfin_interrupt(int irq, void *dev_instance, struct pt_re
int boguscnt = max_interrupt_work;
unsigned int handled = 0;
-#ifndef final_version /* Can never occur. */
- if (dev == NULL) {
- printk (KERN_ERR "yellowfin_interrupt(): irq %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-#endif
-
yp = netdev_priv(dev);
ioaddr = yp->base;
diff --git a/drivers/net/znet.c b/drivers/net/znet.c
index 656d5a02908b..b24b0727108c 100644
--- a/drivers/net/znet.c
+++ b/drivers/net/znet.c
@@ -158,7 +158,7 @@ struct netidblk {
static int znet_open(struct net_device *dev);
static int znet_send_packet(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t znet_interrupt(int irq, void *dev_id);
static void znet_rx(struct net_device *dev);
static int znet_close(struct net_device *dev);
static struct net_device_stats *net_get_stats(struct net_device *dev);
@@ -602,7 +602,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev)
}
/* The ZNET interrupt handler. */
-static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t znet_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct znet_private *znet = dev->priv;
@@ -610,11 +610,6 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id, struct pt_regs * regs)
int boguscnt = 20;
int handled = 0;
- if (dev == NULL) {
- printk(KERN_WARNING "znet_interrupt(): IRQ %d for unknown device.\n", irq);
- return IRQ_NONE;
- }
-
spin_lock (&znet->lock);
ioaddr = dev->base_addr;
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
index 71c2da277d6e..5756401fb15b 100644
--- a/drivers/oprofile/oprofilefs.c
+++ b/drivers/oprofile/oprofilefs.c
@@ -31,7 +31,6 @@ static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode)
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
}
@@ -110,8 +109,8 @@ static ssize_t ulong_write_file(struct file * file, char const __user * buf, siz
static int default_open(struct inode * inode, struct file * filp)
{
- if (inode->u.generic_ip)
- filp->private_data = inode->u.generic_ip;
+ if (inode->i_private)
+ filp->private_data = inode->i_private;
return 0;
}
@@ -158,7 +157,7 @@ int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
if (!d)
return -EFAULT;
- d->d_inode->u.generic_ip = val;
+ d->d_inode->i_private = val;
return 0;
}
@@ -171,7 +170,7 @@ int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
if (!d)
return -EFAULT;
- d->d_inode->u.generic_ip = val;
+ d->d_inode->i_private = val;
return 0;
}
@@ -197,7 +196,7 @@ int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
if (!d)
return -EFAULT;
- d->d_inode->u.generic_ip = val;
+ d->d_inode->i_private = val;
return 0;
}
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 0d96c50ffe9c..03c763c2d0e0 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -368,8 +368,7 @@ static struct hw_interrupt_type dino_interrupt_type = {
* ilr_loop counter is a kluge to prevent a "stuck" IRQ line from
* wedging the CPU. Could be removed or made optional at some point.
*/
-static irqreturn_t
-dino_isr(int irq, void *intr_dev, struct pt_regs *regs)
+static irqreturn_t dino_isr(int irq, void *intr_dev)
{
struct dino_device *dino_dev = intr_dev;
u32 mask;
@@ -390,7 +389,7 @@ ilr_again:
int irq = dino_dev->global_irq[local_irq];
DBG(KERN_DEBUG "%s(%d, %p) mask 0x%x\n",
__FUNCTION__, irq, intr_dev, mask);
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
mask &= ~(1 << local_irq);
} while (mask);
diff --git a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
index 884965cedec9..e97cecbc4d18 100644
--- a/drivers/parisc/eisa.c
+++ b/drivers/parisc/eisa.c
@@ -199,7 +199,7 @@ static struct hw_interrupt_type eisa_interrupt_type = {
.end = no_end_irq,
};
-static irqreturn_t eisa_irq(int wax_irq, void *intr_dev, struct pt_regs *regs)
+static irqreturn_t eisa_irq(int wax_irq, void *intr_dev)
{
int irq = gsc_readb(0xfc01f000); /* EISA supports 16 irqs */
unsigned long flags;
@@ -234,7 +234,7 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev, struct pt_regs *regs)
}
spin_unlock_irqrestore(&eisa_irq_lock, flags);
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
spin_lock_irqsave(&eisa_irq_lock, flags);
/* unmask */
@@ -249,7 +249,7 @@ static irqreturn_t eisa_irq(int wax_irq, void *intr_dev, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t dummy_irq2_handler(int _, void *dev, struct pt_regs *regs)
+static irqreturn_t dummy_irq2_handler(int _, void *dev)
{
printk(KERN_ALERT "eisa: uhh, irq2?\n");
return IRQ_HANDLED;
diff --git a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
index b45aa5c675a0..1b3e3fd12d95 100644
--- a/drivers/parisc/gsc.c
+++ b/drivers/parisc/gsc.c
@@ -73,7 +73,7 @@ EXPORT_SYMBOL(gsc_alloc_irq);
EXPORT_SYMBOL(gsc_claim_irq);
/* Common interrupt demultiplexer used by Asp, Lasi & Wax. */
-irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev, struct pt_regs *regs)
+irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev)
{
unsigned long irr;
struct gsc_asic *gsc_asic = dev;
@@ -87,7 +87,7 @@ irqreturn_t gsc_asic_intr(int gsc_asic_irq, void *dev, struct pt_regs *regs)
do {
int local_irq = __ffs(irr);
unsigned int irq = gsc_asic->global_irq[local_irq];
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
irr &= ~(1 << local_irq);
} while (irr);
diff --git a/drivers/parisc/gsc.h b/drivers/parisc/gsc.h
index a3dc456709d7..762a1babad60 100644
--- a/drivers/parisc/gsc.h
+++ b/drivers/parisc/gsc.h
@@ -44,4 +44,4 @@ void gsc_fixup_irqs(struct parisc_device *parent, void *ctrl,
void (*choose)(struct parisc_device *child, void *ctrl));
void gsc_asic_assign_irq(struct gsc_asic *asic, int local_irq, int *irqp);
-irqreturn_t gsc_asic_intr(int irq, void *dev, struct pt_regs *regs);
+irqreturn_t gsc_asic_intr(int irq, void *dev);
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 1fbda77cefc2..c2949b4367e5 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -146,7 +146,7 @@
#include <asm/superio.h>
#endif
-#include <asm/iosapic.h>
+#include <asm/ropes.h>
#include "./iosapic_private.h"
#define MODULE_NAME "iosapic"
@@ -692,6 +692,7 @@ static void iosapic_end_irq(unsigned int irq)
DBG(KERN_DEBUG "end_irq(%d): eoi(%p, 0x%x)\n", irq,
vi->eoi_addr, vi->eoi_data);
iosapic_eoi(vi->eoi_addr, vi->eoi_data);
+ cpu_end_irq(irq);
}
static unsigned int iosapic_startup_irq(unsigned int irq)
@@ -728,7 +729,7 @@ static struct hw_interrupt_type iosapic_interrupt_type = {
.shutdown = iosapic_disable_irq,
.enable = iosapic_enable_irq,
.disable = iosapic_disable_irq,
- .ack = no_ack_irq,
+ .ack = cpu_ack_irq,
.end = iosapic_end_irq,
#ifdef CONFIG_SMP
.set_affinity = iosapic_set_affinity_irq,
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index 3fe4a77fa16a..ba6769934c77 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -46,9 +46,9 @@
#include <asm/page.h>
#include <asm/system.h>
+#include <asm/ropes.h>
#include <asm/hardware.h> /* for register_parisc_driver() stuff */
#include <asm/parisc-device.h>
-#include <asm/iosapic.h> /* for iosapic_register() */
#include <asm/io.h> /* read/write stuff */
#undef DEBUG_LBA /* general stuff */
@@ -100,113 +100,10 @@
#define MODULE_NAME "LBA"
-#define LBA_FUNC_ID 0x0000 /* function id */
-#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
-#define LBA_CAPABLE 0x0030 /* capabilities register */
-
-#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
-#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
-
-#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
-#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
-#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
-
-#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
-#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
-#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
-#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
-
-#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
-
-#define LBA_STAT_CTL 0x0108 /* Status & Control */
-#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
-#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
-#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
-#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
-
-#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
-#define LBA_LMMIO_MASK 0x0208
-
-#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
-#define LBA_GMMIO_MASK 0x0218
-
-#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
-#define LBA_WLMMIO_MASK 0x0228
-
-#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
-#define LBA_WGMMIO_MASK 0x0238
-
-#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
-#define LBA_IOS_MASK 0x0248
-
-#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
-#define LBA_ELMMIO_MASK 0x0258
-
-#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
-#define LBA_EIOS_MASK 0x0268
-
-#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
-#define LBA_DMA_CTL 0x0278 /* firmware sets this */
-
-#define LBA_IBASE 0x0300 /* SBA DMA support */
-#define LBA_IMASK 0x0308
-
-/* FIXME: ignore DMA Hint stuff until we can measure performance */
-#define LBA_HINT_CFG 0x0310
-#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
-
-#define LBA_BUS_MODE 0x0620
-
-/* ERROR regs are needed for config cycle kluges */
-#define LBA_ERROR_CONFIG 0x0680
-#define LBA_SMART_MODE 0x20
-#define LBA_ERROR_STATUS 0x0688
-#define LBA_ROPE_CTL 0x06A0
-
-#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
-
/* non-postable I/O port space, densely packed */
#define LBA_PORT_BASE (PCI_F_EXTEND | 0xfee00000UL)
static void __iomem *astro_iop_base __read_mostly;
-#define ELROY_HVERS 0x782
-#define MERCURY_HVERS 0x783
-#define QUICKSILVER_HVERS 0x784
-
-static inline int IS_ELROY(struct parisc_device *d)
-{
- return (d->id.hversion == ELROY_HVERS);
-}
-
-static inline int IS_MERCURY(struct parisc_device *d)
-{
- return (d->id.hversion == MERCURY_HVERS);
-}
-
-static inline int IS_QUICKSILVER(struct parisc_device *d)
-{
- return (d->id.hversion == QUICKSILVER_HVERS);
-}
-
-
-/*
-** lba_device: Per instance Elroy data structure
-*/
-struct lba_device {
- struct pci_hba_data hba;
-
- spinlock_t lba_lock;
- void *iosapic_obj;
-
-#ifdef CONFIG_64BIT
- void __iomem * iop_base; /* PA_VIEW - for IO port accessor funcs */
-#endif
-
- int flags; /* state/functionality enabled */
- int hw_rev; /* HW revision of chip */
-};
-
-
static u32 lba_t32;
/* lba flags */
@@ -1542,8 +1439,8 @@ lba_driver_probe(struct parisc_device *dev)
default: version = "TR4+";
}
- printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
- MODULE_NAME, version, func_class & 0xf, dev->hpa.start);
+ printk(KERN_INFO "Elroy version %s (0x%x) found at 0x%lx\n",
+ version, func_class & 0xf, dev->hpa.start);
if (func_class < 2) {
printk(KERN_WARNING "Can't support LBA older than "
@@ -1563,14 +1460,18 @@ lba_driver_probe(struct parisc_device *dev)
}
} else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) {
+ int major, minor;
+
func_class &= 0xff;
- version = kmalloc(6, GFP_KERNEL);
- snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf));
+ major = func_class >> 4, minor = func_class & 0xf;
+
/* We could use one printk for both Elroy and Mercury,
* but for the mask for func_class.
*/
- printk(KERN_INFO "%s version %s (0x%x) found at 0x%lx\n",
- MODULE_NAME, version, func_class & 0xff, dev->hpa.start);
+ printk(KERN_INFO "%s version TR%d.%d (0x%x) found at 0x%lx\n",
+ IS_MERCURY(dev) ? "Mercury" : "Quicksilver", major,
+ minor, func_class, dev->hpa.start);
+
cfg_ops = &mercury_cfg_ops;
} else {
printk(KERN_ERR "Unknown LBA found at 0x%lx\n", dev->hpa.start);
@@ -1600,6 +1501,7 @@ lba_driver_probe(struct parisc_device *dev)
lba_dev->hba.dev = dev;
lba_dev->iosapic_obj = tmp_obj; /* save interrupt handle */
lba_dev->hba.iommu = sba_get_iommu(dev); /* get iommu data */
+ parisc_set_drvdata(dev, lba_dev);
/* ------------ Second : initialize common stuff ---------- */
pci_bios = &lba_bios_ops;
diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c
index bf00fa2537bb..8dac2ba82bb9 100644
--- a/drivers/parisc/led.c
+++ b/drivers/parisc/led.c
@@ -684,7 +684,7 @@ int __init led_init(void)
int ret;
snprintf(lcd_text_default, sizeof(lcd_text_default),
- "Linux %s", system_utsname.release);
+ "Linux %s", init_utsname()->release);
/* Work around the buggy PDC of KittyHawk-machines */
switch (CPU_HVERSION) {
diff --git a/drivers/parisc/power.c b/drivers/parisc/power.c
index fad5a33bf0fa..97e9dc066f95 100644
--- a/drivers/parisc/power.c
+++ b/drivers/parisc/power.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/parisc/kernel/power.c
+ * linux/drivers/parisc/power.c
* HP PARISC soft power switch support driver
*
* Copyright (c) 2001-2005 Helge Deller <deller@gmx.de>
@@ -84,8 +84,7 @@
static void deferred_poweroff(void *dummy)
{
- extern int cad_pid; /* from kernel/sys.c */
- if (kill_proc(cad_pid, SIGINT, 1)) {
+ if (kill_cad_pid(SIGINT, 1)) {
/* just in case killing init process failed */
machine_power_off();
}
@@ -189,7 +188,7 @@ static void polling_tasklet_func(unsigned long soft_power_reg)
* powerfail interruption handler (irq IRQ_FROM_REGION(CPU_IRQ_REGION)+2)
*/
#if 0
-static void powerfail_interrupt(int code, void *x, struct pt_regs *regs)
+static void powerfail_interrupt(int code, void *x)
{
printk(KERN_CRIT "POWERFAIL INTERRUPTION !\n");
poweroff();
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index 8b4732815511..f1e7ccd5475b 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -38,22 +38,15 @@
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <asm/ropes.h>
+#include <asm/mckinley.h> /* for proc_mckinley_root */
#include <asm/runway.h> /* for proc_runway_root */
#include <asm/pdc.h> /* for PDC_MODEL_* */
#include <asm/pdcpat.h> /* for is_pdc_pat() */
#include <asm/parisc-device.h>
-
-/* declared in arch/parisc/kernel/setup.c */
-extern struct proc_dir_entry * proc_mckinley_root;
-
#define MODULE_NAME "SBA"
-#ifdef CONFIG_PROC_FS
-/* depends on proc fs support. But costs CPU performance */
-#undef SBA_COLLECT_STATS
-#endif
-
/*
** The number of debug flags is a clue - this code is fragile.
** Don't even think about messing with it unless you have
@@ -92,202 +85,12 @@ extern struct proc_dir_entry * proc_mckinley_root;
#define DBG_RES(x...)
#endif
-#if defined(CONFIG_64BIT)
-/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
-#define ZX1_SUPPORT
-#endif
-
#define SBA_INLINE __inline__
-
-/*
-** The number of pdir entries to "free" before issueing
-** a read to PCOM register to flush out PCOM writes.
-** Interacts with allocation granularity (ie 4 or 8 entries
-** allocated and free'd/purged at a time might make this
-** less interesting).
-*/
-#define DELAYED_RESOURCE_CNT 16
-
#define DEFAULT_DMA_HINT_REG 0
-#define ASTRO_RUNWAY_PORT 0x582
-#define IKE_MERCED_PORT 0x803
-#define REO_MERCED_PORT 0x804
-#define REOG_MERCED_PORT 0x805
-#define PLUTO_MCKINLEY_PORT 0x880
-
-#define SBA_FUNC_ID 0x0000 /* function id */
-#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
-
-#define IS_ASTRO(id) ((id)->hversion == ASTRO_RUNWAY_PORT)
-#define IS_IKE(id) ((id)->hversion == IKE_MERCED_PORT)
-#define IS_PLUTO(id) ((id)->hversion == PLUTO_MCKINLEY_PORT)
-
-#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
-
-#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
-#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
-/* Ike's IOC's occupy functions 2 and 3 */
-#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
-
-#define IOC_CTRL 0x8 /* IOC_CTRL offset */
-#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
-#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
-#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
-#define IOC_CTRL_RM (1 << 8) /* Real Mode */
-#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
-#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
-#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
-
-#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
-
-#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
-
-
-/*
-** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
-** Firmware programs this stuff. Don't touch it.
-*/
-#define LMMIO_DIRECT0_BASE 0x300
-#define LMMIO_DIRECT0_MASK 0x308
-#define LMMIO_DIRECT0_ROUTE 0x310
-
-#define LMMIO_DIST_BASE 0x360
-#define LMMIO_DIST_MASK 0x368
-#define LMMIO_DIST_ROUTE 0x370
-
-#define IOS_DIST_BASE 0x390
-#define IOS_DIST_MASK 0x398
-#define IOS_DIST_ROUTE 0x3A0
-
-#define IOS_DIRECT_BASE 0x3C0
-#define IOS_DIRECT_MASK 0x3C8
-#define IOS_DIRECT_ROUTE 0x3D0
-
-/*
-** Offsets into I/O TLB (Function 2 and 3 on Ike)
-*/
-#define ROPE0_CTL 0x200 /* "regbus pci0" */
-#define ROPE1_CTL 0x208
-#define ROPE2_CTL 0x210
-#define ROPE3_CTL 0x218
-#define ROPE4_CTL 0x220
-#define ROPE5_CTL 0x228
-#define ROPE6_CTL 0x230
-#define ROPE7_CTL 0x238
-
-#define IOC_ROPE0_CFG 0x500 /* pluto only */
-#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
-
-
-
-#define HF_ENABLE 0x40
-
-
-#define IOC_IBASE 0x300 /* IO TLB */
-#define IOC_IMASK 0x308
-#define IOC_PCOM 0x310
-#define IOC_TCNFG 0x318
-#define IOC_PDIR_BASE 0x320
-
-/* AGP GART driver looks for this */
-#define SBA_IOMMU_COOKIE 0x0000badbadc0ffeeUL
-
-
-/*
-** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
-** It's safer (avoid memory corruption) to keep DMA page mappings
-** equivalently sized to VM PAGE_SIZE.
-**
-** We really can't avoid generating a new mapping for each
-** page since the Virtual Coherence Index has to be generated
-** and updated for each page.
-**
-** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
-*/
-#define IOVP_SIZE PAGE_SIZE
-#define IOVP_SHIFT PAGE_SHIFT
-#define IOVP_MASK PAGE_MASK
-
-#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
-#define SBA_PERF_MASK1 0x718
-#define SBA_PERF_MASK2 0x730
-
-
-/*
-** Offsets into PCI Performance Counters (functions 12 and 13)
-** Controlled by PERF registers in function 2 & 3 respectively.
-*/
-#define SBA_PERF_CNT1 0x200
-#define SBA_PERF_CNT2 0x208
-#define SBA_PERF_CNT3 0x210
-
-
-struct ioc {
- void __iomem *ioc_hpa; /* I/O MMU base address */
- char *res_map; /* resource map, bit == pdir entry */
- u64 *pdir_base; /* physical base address */
- unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
- unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
-#ifdef ZX1_SUPPORT
- unsigned long iovp_mask; /* help convert IOVA to IOVP */
-#endif
- unsigned long *res_hint; /* next avail IOVP - circular search */
- spinlock_t res_lock;
- unsigned int res_bitshift; /* from the LEFT! */
- unsigned int res_size; /* size of resource map in bytes */
-#ifdef SBA_HINT_SUPPORT
-/* FIXME : DMA HINTs not used */
- unsigned long hint_mask_pdir; /* bits used for DMA hints */
- unsigned int hint_shift_pdir;
-#endif
-#if DELAYED_RESOURCE_CNT > 0
- int saved_cnt;
- struct sba_dma_pair {
- dma_addr_t iova;
- size_t size;
- } saved[DELAYED_RESOURCE_CNT];
-#endif
-
-#ifdef SBA_COLLECT_STATS
-#define SBA_SEARCH_SAMPLE 0x100
- unsigned long avg_search[SBA_SEARCH_SAMPLE];
- unsigned long avg_idx; /* current index into avg_search */
- unsigned long used_pages;
- unsigned long msingle_calls;
- unsigned long msingle_pages;
- unsigned long msg_calls;
- unsigned long msg_pages;
- unsigned long usingle_calls;
- unsigned long usingle_pages;
- unsigned long usg_calls;
- unsigned long usg_pages;
-#endif
-
- /* STUFF We don't need in performance path */
- unsigned int pdir_size; /* in bytes, determined by IOV Space size */
-};
-
-struct sba_device {
- struct sba_device *next; /* list of SBA's in system */
- struct parisc_device *dev; /* dev found in bus walk */
- struct parisc_device_id *iodc; /* data about dev from firmware */
- const char *name;
- void __iomem *sba_hpa; /* base address */
- spinlock_t sba_lock;
- unsigned int flags; /* state/functionality enabled */
- unsigned int hw_rev; /* HW revision of chip */
-
- struct resource chip_resv; /* MMIO reserved for chip */
- struct resource iommu_resv; /* MMIO reserved for iommu */
-
- unsigned int num_ioc; /* number of on-board IOC's */
- struct ioc ioc[MAX_IOC];
-};
-
-
-static struct sba_device *sba_list;
+struct sba_device *sba_list;
+EXPORT_SYMBOL_GPL(sba_list);
static unsigned long ioc_needs_fdc = 0;
@@ -300,8 +103,14 @@ static unsigned long piranha_bad_128k = 0;
/* Looks nice and keeps the compiler happy */
#define SBA_DEV(d) ((struct sba_device *) (d))
+#ifdef CONFIG_AGP_PARISC
+#define SBA_AGP_SUPPORT
+#endif /*CONFIG_AGP_PARISC*/
+
#ifdef SBA_AGP_SUPPORT
-static int reserve_sba_gart = 1;
+static int sba_reserve_agpgart = 1;
+module_param(sba_reserve_agpgart, int, 1);
+MODULE_PARM_DESC(sba_reserve_agpgart, "Reserve half of IO pdir as AGPGART");
#endif
#define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
@@ -741,7 +550,7 @@ sba_io_pdir_entry(u64 *pdir_ptr, space_t sid, unsigned long vba,
asm("lci 0(%%sr1, %1), %0" : "=r" (ci) : "r" (vba));
pa |= (ci >> 12) & 0xff; /* move CI (8 bits) into lowest byte */
- pa |= 0x8000000000000000ULL; /* set "valid" bit */
+ pa |= SBA_PDIR_VALID_BIT; /* set "valid" bit */
*pdir_ptr = cpu_to_le64(pa); /* swap and store into I/O Pdir */
/*
@@ -1498,6 +1307,10 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
WRITE_REG(ioc->ibase | 31, ioc->ioc_hpa + IOC_PCOM);
#ifdef SBA_AGP_SUPPORT
+{
+ struct klist_iter i;
+ struct device *dev = NULL;
+
/*
** If an AGP device is present, only use half of the IOV space
** for PCI DMA. Unfortunately we can't know ahead of time
@@ -1506,20 +1319,22 @@ sba_ioc_init_pluto(struct parisc_device *sba, struct ioc *ioc, int ioc_num)
** We program the next pdir index after we stop w/ a key for
** the GART code to handshake on.
*/
- device=NULL;
- for (lba = sba->child; lba; lba = lba->sibling) {
+ klist_iter_init(&sba->dev.klist_children, &i);
+ while ((dev = next_device(&i))) {
+ struct parisc_device *lba = to_parisc_device(dev);
if (IS_QUICKSILVER(lba))
- break;
+ agp_found = 1;
}
+ klist_iter_exit(&i);
- if (lba) {
- DBG_INIT("%s: Reserving half of IOVA space for AGP GART support\n", __FUNCTION__);
+ if (agp_found && sba_reserve_agpgart) {
+ printk(KERN_INFO "%s: reserving %dMb of IOVA space for agpgart\n",
+ __FUNCTION__, (iova_space_size/2) >> 20);
ioc->pdir_size /= 2;
- ((u64 *)ioc->pdir_base)[PDIR_INDEX(iova_space_size/2)] = SBA_IOMMU_COOKIE;
- } else {
- DBG_INIT("%s: No GART needed - no AGP controller found\n", __FUNCTION__);
+ ioc->pdir_base[PDIR_INDEX(iova_space_size/2)] = SBA_AGPGART_COOKIE;
}
-#endif /* 0 */
+}
+#endif /*SBA_AGP_SUPPORT*/
}
@@ -1701,7 +1516,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
}
#endif
- if (!IS_PLUTO(sba_dev->iodc)) {
+ if (!IS_PLUTO(sba_dev->dev)) {
ioc_ctl = READ_REG(sba_dev->sba_hpa+IOC_CTRL);
DBG_INIT("%s() hpa 0x%lx ioc_ctl 0x%Lx ->",
__FUNCTION__, sba_dev->sba_hpa, ioc_ctl);
@@ -1718,9 +1533,8 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
#endif
} /* if !PLUTO */
- if (IS_ASTRO(sba_dev->iodc)) {
+ if (IS_ASTRO(sba_dev->dev)) {
int err;
- /* PAT_PDC (L-class) also reports the same goofy base */
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, ASTRO_IOC_OFFSET);
num_ioc = 1;
@@ -1730,13 +1544,9 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
err = request_resource(&iomem_resource, &(sba_dev->chip_resv));
BUG_ON(err < 0);
- } else if (IS_PLUTO(sba_dev->iodc)) {
+ } else if (IS_PLUTO(sba_dev->dev)) {
int err;
- /* We use a negative value for IOC HPA so it gets
- * corrected when we add it with IKE's IOC offset.
- * Doesnt look clean, but fewer code.
- */
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, PLUTO_IOC_OFFSET);
num_ioc = 1;
@@ -1752,14 +1562,14 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
err = request_resource(&iomem_resource, &(sba_dev->iommu_resv));
WARN_ON(err < 0);
} else {
- /* IS_IKE (ie N-class, L3000, L1500) */
+ /* IKE, REO */
sba_dev->ioc[0].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(0));
sba_dev->ioc[1].ioc_hpa = ioc_remap(sba_dev, IKE_IOC_OFFSET(1));
num_ioc = 2;
/* TODO - LOOKUP Ike/Stretch chipset mem map */
}
- /* XXX: What about Reo? */
+ /* XXX: What about Reo Grande? */
sba_dev->num_ioc = num_ioc;
for (i = 0; i < num_ioc; i++) {
@@ -1774,7 +1584,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
* Overrides bit 1 in DMA Hint Sets.
* Improves netperf UDP_STREAM by ~10% for bcm5701.
*/
- if (IS_PLUTO(sba_dev->iodc)) {
+ if (IS_PLUTO(sba_dev->dev)) {
void __iomem *rope_cfg;
unsigned long cfg_val;
@@ -1803,7 +1613,7 @@ printk("sba_hw_init(): mem_boot 0x%x 0x%x 0x%x 0x%x\n", PAGE0->mem_boot.hpa,
READ_REG(sba_dev->ioc[i].ioc_hpa + 0x400)
);
- if (IS_PLUTO(sba_dev->iodc)) {
+ if (IS_PLUTO(sba_dev->dev)) {
sba_ioc_init_pluto(sba_dev->dev, &(sba_dev->ioc[i]), i);
} else {
sba_ioc_init(sba_dev->dev, &(sba_dev->ioc[i]), i);
@@ -2067,7 +1877,7 @@ sba_driver_callback(struct parisc_device *dev)
/* Read HW Rev First */
func_class = READ_REG(sba_addr + SBA_FCLASS);
- if (IS_ASTRO(&dev->id)) {
+ if (IS_ASTRO(dev)) {
unsigned long fclass;
static char astro_rev[]="Astro ?.?";
@@ -2078,11 +1888,11 @@ sba_driver_callback(struct parisc_device *dev)
astro_rev[8] = '0' + (char) ((fclass & 0x18) >> 3);
version = astro_rev;
- } else if (IS_IKE(&dev->id)) {
+ } else if (IS_IKE(dev)) {
static char ike_rev[] = "Ike rev ?";
ike_rev[8] = '0' + (char) (func_class & 0xff);
version = ike_rev;
- } else if (IS_PLUTO(&dev->id)) {
+ } else if (IS_PLUTO(dev)) {
static char pluto_rev[]="Pluto ?.?";
pluto_rev[6] = '0' + (char) ((func_class & 0xf0) >> 4);
pluto_rev[8] = '0' + (char) (func_class & 0x0f);
@@ -2097,7 +1907,7 @@ sba_driver_callback(struct parisc_device *dev)
global_ioc_cnt = count_parisc_driver(&sba_driver);
/* Astro and Pluto have one IOC per SBA */
- if ((!IS_ASTRO(&dev->id)) || (!IS_PLUTO(&dev->id)))
+ if ((!IS_ASTRO(dev)) || (!IS_PLUTO(dev)))
global_ioc_cnt *= 2;
}
@@ -2117,7 +1927,6 @@ sba_driver_callback(struct parisc_device *dev)
sba_dev->dev = dev;
sba_dev->hw_rev = func_class;
- sba_dev->iodc = &dev->id;
sba_dev->name = dev->name;
sba_dev->sba_hpa = sba_addr;
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index 4ee26a6d9e25..1fd97f7c8b98 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -94,7 +94,7 @@ static struct superio_device sio_dev;
#define PFX SUPERIO ": "
static irqreturn_t
-superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
+superio_interrupt(int parent_irq, void *devp)
{
u8 results;
u8 local_irq;
@@ -138,7 +138,7 @@ superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
}
/* Call the appropriate device's interrupt */
- __do_IRQ(local_irq, regs);
+ __do_IRQ(local_irq);
/* set EOI - forces a new interrupt if a lower priority device
* still needs service.
diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c
index fd41e28101ea..ff9f34453530 100644
--- a/drivers/parport/daisy.c
+++ b/drivers/parport/daisy.c
@@ -30,7 +30,7 @@
#undef DEBUG
#ifdef DEBUG
-#define DPRINTK(stuff...) printk (stuff)
+#define DPRINTK(stuff...) printk(stuff)
#else
#define DPRINTK(stuff...)
#endif
@@ -46,16 +46,16 @@ static DEFINE_SPINLOCK(topology_lock);
static int numdevs = 0;
/* Forward-declaration of lower-level functions. */
-static int mux_present (struct parport *port);
-static int num_mux_ports (struct parport *port);
-static int select_port (struct parport *port);
-static int assign_addrs (struct parport *port);
+static int mux_present(struct parport *port);
+static int num_mux_ports(struct parport *port);
+static int select_port(struct parport *port);
+static int assign_addrs(struct parport *port);
/* Add a device to the discovered topology. */
-static void add_dev (int devnum, struct parport *port, int daisy)
+static void add_dev(int devnum, struct parport *port, int daisy)
{
struct daisydev *newdev, **p;
- newdev = kmalloc (sizeof (struct daisydev), GFP_KERNEL);
+ newdev = kmalloc(sizeof(struct daisydev), GFP_KERNEL);
if (newdev) {
newdev->port = port;
newdev->daisy = daisy;
@@ -70,9 +70,9 @@ static void add_dev (int devnum, struct parport *port, int daisy)
}
/* Clone a parport (actually, make an alias). */
-static struct parport *clone_parport (struct parport *real, int muxport)
+static struct parport *clone_parport(struct parport *real, int muxport)
{
- struct parport *extra = parport_register_port (real->base,
+ struct parport *extra = parport_register_port(real->base,
real->irq,
real->dma,
real->ops);
@@ -88,7 +88,7 @@ static struct parport *clone_parport (struct parport *real, int muxport)
/* Discover the IEEE1284.3 topology on a port -- muxes and daisy chains.
* Return value is number of devices actually detected. */
-int parport_daisy_init (struct parport *port)
+int parport_daisy_init(struct parport *port)
{
int detected = 0;
char *deviceid;
@@ -103,26 +103,26 @@ again:
/* If mux present on normal port, need to create new
* parports for each extra port. */
- if (port->muxport < 0 && mux_present (port) &&
+ if (port->muxport < 0 && mux_present(port) &&
/* don't be fooled: a mux must have 2 or 4 ports. */
- ((num_ports = num_mux_ports (port)) == 2 || num_ports == 4)) {
+ ((num_ports = num_mux_ports(port)) == 2 || num_ports == 4)) {
/* Leave original as port zero. */
port->muxport = 0;
- printk (KERN_INFO
+ printk(KERN_INFO
"%s: 1st (default) port of %d-way multiplexor\n",
port->name, num_ports);
for (i = 1; i < num_ports; i++) {
/* Clone the port. */
- struct parport *extra = clone_parport (port, i);
+ struct parport *extra = clone_parport(port, i);
if (!extra) {
- if (signal_pending (current))
+ if (signal_pending(current))
break;
- schedule ();
+ schedule();
continue;
}
- printk (KERN_INFO
+ printk(KERN_INFO
"%s: %d%s port of %d-way multiplexor on %s\n",
extra->name, i + 1, th[i + 1], num_ports,
port->name);
@@ -135,34 +135,34 @@ again:
}
if (port->muxport >= 0)
- select_port (port);
+ select_port(port);
- parport_daisy_deselect_all (port);
- detected += assign_addrs (port);
+ parport_daisy_deselect_all(port);
+ detected += assign_addrs(port);
/* Count the potential legacy device at the end. */
- add_dev (numdevs++, port, -1);
+ add_dev(numdevs++, port, -1);
/* Find out the legacy device's IEEE 1284 device ID. */
- deviceid = kmalloc (1024, GFP_KERNEL);
+ deviceid = kmalloc(1024, GFP_KERNEL);
if (deviceid) {
- if (parport_device_id (numdevs - 1, deviceid, 1024) > 2)
+ if (parport_device_id(numdevs - 1, deviceid, 1024) > 2)
detected++;
- kfree (deviceid);
+ kfree(deviceid);
}
if (!detected && !last_try) {
/* No devices were detected. Perhaps they are in some
funny state; let's try to reset them and see if
they wake up. */
- parport_daisy_fini (port);
- parport_write_control (port, PARPORT_CONTROL_SELECT);
- udelay (50);
- parport_write_control (port,
+ parport_daisy_fini(port);
+ parport_write_control(port, PARPORT_CONTROL_SELECT);
+ udelay(50);
+ parport_write_control(port,
PARPORT_CONTROL_SELECT |
PARPORT_CONTROL_INIT);
- udelay (50);
+ udelay(50);
last_try = 1;
goto again;
}
@@ -171,7 +171,7 @@ again:
}
/* Forget about devices on a physical port. */
-void parport_daisy_fini (struct parport *port)
+void parport_daisy_fini(struct parport *port)
{
struct daisydev **p;
@@ -214,9 +214,9 @@ void parport_daisy_fini (struct parport *port)
* for parport_register_device().
**/
-struct pardevice *parport_open (int devnum, const char *name,
+struct pardevice *parport_open(int devnum, const char *name,
int (*pf) (void *), void (*kf) (void *),
- void (*irqf) (int, void *, struct pt_regs *),
+ void (*irqf) (int, void *),
int flags, void *handle)
{
struct daisydev *p = topology;
@@ -237,7 +237,7 @@ struct pardevice *parport_open (int devnum, const char *name,
port = parport_get_port(p->port);
spin_unlock(&topology_lock);
- dev = parport_register_device (port, name, pf, kf,
+ dev = parport_register_device(port, name, pf, kf,
irqf, flags, handle);
parport_put_port(port);
if (!dev)
@@ -248,13 +248,13 @@ struct pardevice *parport_open (int devnum, const char *name,
/* Check that there really is a device to select. */
if (daisy >= 0) {
int selected;
- parport_claim_or_block (dev);
+ parport_claim_or_block(dev);
selected = port->daisy;
- parport_release (dev);
+ parport_release(dev);
if (selected != daisy) {
/* No corresponding device. */
- parport_unregister_device (dev);
+ parport_unregister_device(dev);
return NULL;
}
}
@@ -270,9 +270,9 @@ struct pardevice *parport_open (int devnum, const char *name,
* parport_register_device().
**/
-void parport_close (struct pardevice *dev)
+void parport_close(struct pardevice *dev)
{
- parport_unregister_device (dev);
+ parport_unregister_device(dev);
}
/**
@@ -287,7 +287,7 @@ void parport_close (struct pardevice *dev)
* exists.
**/
-int parport_device_num (int parport, int mux, int daisy)
+int parport_device_num(int parport, int mux, int daisy)
{
int res = -ENXIO;
struct daisydev *dev;
@@ -305,16 +305,16 @@ int parport_device_num (int parport, int mux, int daisy)
}
/* Send a daisy-chain-style CPP command packet. */
-static int cpp_daisy (struct parport *port, int cmd)
+static int cpp_daisy(struct parport *port, int cmd)
{
unsigned char s;
- parport_data_forward (port);
- parport_write_data (port, 0xaa); udelay (2);
- parport_write_data (port, 0x55); udelay (2);
- parport_write_data (port, 0x00); udelay (2);
- parport_write_data (port, 0xff); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ parport_data_forward(port);
+ parport_write_data(port, 0xaa); udelay(2);
+ parport_write_data(port, 0x55); udelay(2);
+ parport_write_data(port, 0x00); udelay(2);
+ parport_write_data(port, 0xff); udelay(2);
+ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
| PARPORT_STATUS_PAPEROUT
| PARPORT_STATUS_SELECT
| PARPORT_STATUS_ERROR);
@@ -322,54 +322,54 @@ static int cpp_daisy (struct parport *port, int cmd)
| PARPORT_STATUS_PAPEROUT
| PARPORT_STATUS_SELECT
| PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
+ DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff(%02x)\n",
port->name, s);
return -ENXIO;
}
- parport_write_data (port, 0x87); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ parport_write_data(port, 0x87); udelay(2);
+ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
| PARPORT_STATUS_PAPEROUT
| PARPORT_STATUS_SELECT
| PARPORT_STATUS_ERROR);
if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
+ DPRINTK(KERN_DEBUG "%s: cpp_daisy: aa5500ff87(%02x)\n",
port->name, s);
return -ENXIO;
}
- parport_write_data (port, 0x78); udelay (2);
- parport_write_data (port, cmd); udelay (2);
- parport_frob_control (port,
+ parport_write_data(port, 0x78); udelay(2);
+ parport_write_data(port, cmd); udelay(2);
+ parport_frob_control(port,
PARPORT_CONTROL_STROBE,
PARPORT_CONTROL_STROBE);
- udelay (1);
- s = parport_read_status (port);
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
- udelay (1);
- parport_write_data (port, 0xff); udelay (2);
+ udelay(1);
+ s = parport_read_status(port);
+ parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
+ udelay(1);
+ parport_write_data(port, 0xff); udelay(2);
return s;
}
/* Send a mux-style CPP command packet. */
-static int cpp_mux (struct parport *port, int cmd)
+static int cpp_mux(struct parport *port, int cmd)
{
unsigned char s;
int rc;
- parport_data_forward (port);
- parport_write_data (port, 0xaa); udelay (2);
- parport_write_data (port, 0x55); udelay (2);
- parport_write_data (port, 0xf0); udelay (2);
- parport_write_data (port, 0x0f); udelay (2);
- parport_write_data (port, 0x52); udelay (2);
- parport_write_data (port, 0xad); udelay (2);
- parport_write_data (port, cmd); udelay (2);
+ parport_data_forward(port);
+ parport_write_data(port, 0xaa); udelay(2);
+ parport_write_data(port, 0x55); udelay(2);
+ parport_write_data(port, 0xf0); udelay(2);
+ parport_write_data(port, 0x0f); udelay(2);
+ parport_write_data(port, 0x52); udelay(2);
+ parport_write_data(port, 0xad); udelay(2);
+ parport_write_data(port, cmd); udelay(2);
- s = parport_read_status (port);
+ s = parport_read_status(port);
if (!(s & PARPORT_STATUS_ACK)) {
- DPRINTK (KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
+ DPRINTK(KERN_DEBUG "%s: cpp_mux: aa55f00f52ad%02x(%02x)\n",
port->name, cmd, s);
return -EIO;
}
@@ -382,12 +382,12 @@ static int cpp_mux (struct parport *port, int cmd)
return rc;
}
-void parport_daisy_deselect_all (struct parport *port)
+void parport_daisy_deselect_all(struct parport *port)
{
- cpp_daisy (port, 0x30);
+ cpp_daisy(port, 0x30);
}
-int parport_daisy_select (struct parport *port, int daisy, int mode)
+int parport_daisy_select(struct parport *port, int daisy, int mode)
{
switch (mode)
{
@@ -395,14 +395,14 @@ int parport_daisy_select (struct parport *port, int daisy, int mode)
case IEEE1284_MODE_EPP:
case IEEE1284_MODE_EPPSL:
case IEEE1284_MODE_EPPSWE:
- return !(cpp_daisy (port, 0x20 + daisy) &
+ return !(cpp_daisy(port, 0x20 + daisy) &
PARPORT_STATUS_ERROR);
// For these modes we should switch to ECP mode:
case IEEE1284_MODE_ECP:
case IEEE1284_MODE_ECPRLE:
case IEEE1284_MODE_ECPSWE:
- return !(cpp_daisy (port, 0xd0 + daisy) &
+ return !(cpp_daisy(port, 0xd0 + daisy) &
PARPORT_STATUS_ERROR);
// Nothing was told for BECP in Daisy chain specification.
@@ -413,28 +413,28 @@ int parport_daisy_select (struct parport *port, int daisy, int mode)
case IEEE1284_MODE_BYTE:
case IEEE1284_MODE_COMPAT:
default:
- return !(cpp_daisy (port, 0xe0 + daisy) &
+ return !(cpp_daisy(port, 0xe0 + daisy) &
PARPORT_STATUS_ERROR);
}
}
-static int mux_present (struct parport *port)
+static int mux_present(struct parport *port)
{
- return cpp_mux (port, 0x51) == 3;
+ return cpp_mux(port, 0x51) == 3;
}
-static int num_mux_ports (struct parport *port)
+static int num_mux_ports(struct parport *port)
{
- return cpp_mux (port, 0x58);
+ return cpp_mux(port, 0x58);
}
-static int select_port (struct parport *port)
+static int select_port(struct parport *port)
{
int muxport = port->muxport;
- return cpp_mux (port, 0x60 + muxport) == muxport;
+ return cpp_mux(port, 0x60 + muxport) == muxport;
}
-static int assign_addrs (struct parport *port)
+static int assign_addrs(struct parport *port)
{
unsigned char s;
unsigned char daisy;
@@ -442,12 +442,12 @@ static int assign_addrs (struct parport *port)
int detected;
char *deviceid;
- parport_data_forward (port);
- parport_write_data (port, 0xaa); udelay (2);
- parport_write_data (port, 0x55); udelay (2);
- parport_write_data (port, 0x00); udelay (2);
- parport_write_data (port, 0xff); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ parport_data_forward(port);
+ parport_write_data(port, 0xaa); udelay(2);
+ parport_write_data(port, 0x55); udelay(2);
+ parport_write_data(port, 0x00); udelay(2);
+ parport_write_data(port, 0xff); udelay(2);
+ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
| PARPORT_STATUS_PAPEROUT
| PARPORT_STATUS_SELECT
| PARPORT_STATUS_ERROR);
@@ -455,40 +455,40 @@ static int assign_addrs (struct parport *port)
| PARPORT_STATUS_PAPEROUT
| PARPORT_STATUS_SELECT
| PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
+ DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff(%02x)\n",
port->name, s);
return 0;
}
- parport_write_data (port, 0x87); udelay (2);
- s = parport_read_status (port) & (PARPORT_STATUS_BUSY
+ parport_write_data(port, 0x87); udelay(2);
+ s = parport_read_status(port) & (PARPORT_STATUS_BUSY
| PARPORT_STATUS_PAPEROUT
| PARPORT_STATUS_SELECT
| PARPORT_STATUS_ERROR);
if (s != (PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR)) {
- DPRINTK (KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
+ DPRINTK(KERN_DEBUG "%s: assign_addrs: aa5500ff87(%02x)\n",
port->name, s);
return 0;
}
- parport_write_data (port, 0x78); udelay (2);
- s = parport_read_status (port);
+ parport_write_data(port, 0x78); udelay(2);
+ s = parport_read_status(port);
for (daisy = 0;
(s & (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT))
== (PARPORT_STATUS_PAPEROUT|PARPORT_STATUS_SELECT)
&& daisy < 4;
++daisy) {
- parport_write_data (port, daisy);
- udelay (2);
- parport_frob_control (port,
+ parport_write_data(port, daisy);
+ udelay(2);
+ parport_frob_control(port,
PARPORT_CONTROL_STROBE,
PARPORT_CONTROL_STROBE);
- udelay (1);
- parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
- udelay (1);
+ udelay(1);
+ parport_frob_control(port, PARPORT_CONTROL_STROBE, 0);
+ udelay(1);
- add_dev (numdevs++, port, daisy);
+ add_dev(numdevs++, port, daisy);
/* See if this device thought it was the last in the
* chain. */
@@ -499,21 +499,21 @@ static int assign_addrs (struct parport *port)
last_dev from next device or if last_dev does not
work status lines from some non-daisy chain
device. */
- s = parport_read_status (port);
+ s = parport_read_status(port);
}
- parport_write_data (port, 0xff); udelay (2);
+ parport_write_data(port, 0xff); udelay(2);
detected = numdevs - thisdev;
- DPRINTK (KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
+ DPRINTK(KERN_DEBUG "%s: Found %d daisy-chained devices\n", port->name,
detected);
/* Ask the new devices to introduce themselves. */
- deviceid = kmalloc (1024, GFP_KERNEL);
+ deviceid = kmalloc(1024, GFP_KERNEL);
if (!deviceid) return 0;
for (daisy = 0; thisdev < numdevs; thisdev++, daisy++)
- parport_device_id (thisdev, deviceid, 1024);
+ parport_device_id(thisdev, deviceid, 1024);
- kfree (deviceid);
+ kfree(deviceid);
return detected;
}
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 7ff09f0f858f..5accaa7bde31 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -571,7 +571,7 @@ static int parport_ieee1284_ack_data_avail (struct parport *port)
#endif /* IEEE1284 support */
/* Handle an interrupt. */
-void parport_ieee1284_interrupt (int which, void *handle, struct pt_regs *regs)
+void parport_ieee1284_interrupt (int which, void *handle)
{
struct parport *port = handle;
parport_ieee1284_wakeup (port);
diff --git a/drivers/parport/parport_amiga.c b/drivers/parport/parport_amiga.c
index 5126e74ac2ec..a0afaee5ebe5 100644
--- a/drivers/parport/parport_amiga.c
+++ b/drivers/parport/parport_amiga.c
@@ -138,9 +138,9 @@ static unsigned char amiga_read_status(struct parport *p)
}
/* as this ports irq handling is already done, we use a generic funktion */
-static irqreturn_t amiga_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t amiga_interrupt(int irq, void *dev_id)
{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
+ parport_generic_irq(irq, (struct parport *) dev_id);
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
index 78c3f34108bc..6ea9929b8c7f 100644
--- a/drivers/parport/parport_atari.c
+++ b/drivers/parport/parport_atari.c
@@ -104,9 +104,9 @@ parport_atari_restore_state(struct parport *p, struct parport_state *s)
}
static irqreturn_t
-parport_atari_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+parport_atari_interrupt(int irq, void *dev_id)
{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
+ parport_generic_irq(irq, (struct parport *) dev_id);
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_ax88796.c b/drivers/parport/parport_ax88796.c
index 1850632590fd..74f4e9742c6c 100644
--- a/drivers/parport/parport_ax88796.c
+++ b/drivers/parport/parport_ax88796.c
@@ -233,9 +233,9 @@ parport_ax88796_restore_state(struct parport *p, struct parport_state *s)
}
static irqreturn_t
-parport_ax88796_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+parport_ax88796_interrupt(int irq, void *dev_id)
{
- parport_generic_irq(irq, dev_id, regs);
+ parport_generic_irq(irq, dev_id);
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index 7352104f7b30..a7c5ead9a3d3 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -81,9 +81,9 @@ static int clear_epp_timeout(struct parport *pb)
* of these are in parport_gsc.h.
*/
-static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t parport_gsc_interrupt(int irq, void *dev_id)
{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
+ parport_generic_irq(irq, (struct parport *) dev_id);
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c
index 46e06e596d73..e3e19277030a 100644
--- a/drivers/parport/parport_ip32.c
+++ b/drivers/parport/parport_ip32.c
@@ -548,10 +548,8 @@ static void parport_ip32_dma_setup_context(unsigned int limit)
* parport_ip32_dma_interrupt - DMA interrupt handler
* @irq: interrupt number
* @dev_id: unused
- * @regs: pointer to &struct pt_regs
*/
-static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id)
{
if (parport_ip32_dma.left)
pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx);
@@ -560,8 +558,7 @@ static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id,
}
#if DEBUG_PARPORT_IP32
-static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id)
{
pr_trace1(NULL, "(%d)", irq);
return IRQ_HANDLED;
@@ -772,13 +769,11 @@ static inline void parport_ip32_wakeup(struct parport *p)
* parport_ip32_interrupt - interrupt handler
* @irq: interrupt number
* @dev_id: pointer to &struct parport
- * @regs: pointer to &struct pt_regs
*
* Caught interrupts are forwarded to the upper parport layer if IRQ_mode is
* %PARPORT_IP32_IRQ_FWD.
*/
-static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id)
{
struct parport * const p = dev_id;
struct parport_ip32_private * const priv = p->physport->private_data;
diff --git a/drivers/parport/parport_mfc3.c b/drivers/parport/parport_mfc3.c
index b2b8092a2b39..e5b0a544de40 100644
--- a/drivers/parport/parport_mfc3.c
+++ b/drivers/parport/parport_mfc3.c
@@ -211,7 +211,7 @@ static void mfc3_change_mode( struct parport *p, int m)
static int use_cnt = 0;
-static irqreturn_t mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mfc3_interrupt(int irq, void *dev_id)
{
int i;
@@ -219,7 +219,7 @@ static irqreturn_t mfc3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (this_port[i] != NULL)
if (pia(this_port[i])->crb & 128) { /* Board caused interrupt */
dummy = pia(this_port[i])->pprb; /* clear irq bit */
- parport_generic_irq(irq, this_port[i], regs);
+ parport_generic_irq(irq, this_port[i]);
}
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index fe800dc0be9f..39c96641bc72 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -270,9 +270,9 @@ static int clear_epp_timeout(struct parport *pb)
* of these are in parport_pc.h.
*/
-static irqreturn_t parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t parport_pc_interrupt(int irq, void *dev_id)
{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
+ parport_generic_irq(irq, (struct parport *) dev_id);
/* FIXME! Was it really ours? */
return IRQ_HANDLED;
}
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 98b83a85c60e..78c0a269a2ba 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -374,6 +374,7 @@ static void __devexit parport_serial_pci_remove (struct pci_dev *dev)
return;
}
+#ifdef CONFIG_PM
static int parport_serial_pci_suspend(struct pci_dev *dev, pm_message_t state)
{
struct parport_serial_private *priv = pci_get_drvdata(dev);
@@ -407,14 +408,17 @@ static int parport_serial_pci_resume(struct pci_dev *dev)
return 0;
}
+#endif
static struct pci_driver parport_serial_pci_driver = {
.name = "parport_serial",
.id_table = parport_serial_pci_tbl,
.probe = parport_serial_pci_probe,
.remove = __devexit_p(parport_serial_pci_remove),
+#ifdef CONFIG_PM
.suspend = parport_serial_pci_suspend,
.resume = parport_serial_pci_resume,
+#endif
};
diff --git a/drivers/parport/parport_sunbpp.c b/drivers/parport/parport_sunbpp.c
index fac333b279bf..9793533276ec 100644
--- a/drivers/parport/parport_sunbpp.c
+++ b/drivers/parport/parport_sunbpp.c
@@ -46,9 +46,9 @@
#define dprintk(x)
#endif
-static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t parport_sunbpp_interrupt(int irq, void *dev_id)
{
- parport_generic_irq(irq, (struct parport *) dev_id, regs);
+ parport_generic_irq(irq, (struct parport *) dev_id);
return IRQ_HANDLED;
}
diff --git a/drivers/parport/share.c b/drivers/parport/share.c
index 94dc506b83d1..fd9129e424f9 100644
--- a/drivers/parport/share.c
+++ b/drivers/parport/share.c
@@ -519,7 +519,7 @@ void parport_remove_port(struct parport *port)
struct pardevice *
parport_register_device(struct parport *port, const char *name,
int (*pf)(void *), void (*kf)(void *),
- void (*irq_func)(int, void *, struct pt_regs *),
+ void (*irq_func)(int, void *),
int flags, void *handle)
{
struct pardevice *tmp;
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index c27e782e6df9..ecc50db8585a 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -52,3 +52,11 @@ config PCI_DEBUG
When in doubt, say N.
+config HT_IRQ
+ bool "Interrupts on hypertransport devices"
+ default y
+ depends on PCI && X86_LOCAL_APIC && X86_IO_APIC
+ help
+ This allows native hypertransport devices to use interrupts.
+
+ If unsure say Y.
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index f2d152b818f0..e3beb784406f 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -14,6 +14,12 @@ obj-$(CONFIG_HOTPLUG) += hotplug.o
# Build the PCI Hotplug drivers if we were asked to
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
+# Build the PCI MSI interrupt support
+obj-$(CONFIG_PCI_MSI) += msi.o
+
+# Build the Hypertransport interrupt support
+obj-$(CONFIG_HT_IRQ) += htirq.o
+
#
# Some architectures use the generic PCI setup functions
#
@@ -27,11 +33,6 @@ obj-$(CONFIG_PPC64) += setup-bus.o
obj-$(CONFIG_MIPS) += setup-bus.o setup-irq.o
obj-$(CONFIG_X86_VISWS) += setup-irq.o
-msiobj-y := msi.o msi-apic.o
-msiobj-$(CONFIG_IA64_GENERIC) += msi-altix.o
-msiobj-$(CONFIG_IA64_SGI_SN2) += msi-altix.o
-obj-$(CONFIG_PCI_MSI) += $(msiobj-y)
-
#
# ACPI Related PCI FW Functions
#
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 5f7db9d2436e..aadaa3c8096b 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -77,9 +77,12 @@ pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
* This adds a single pci device to the global
* device list and adds sysfs and procfs entries
*/
-void __devinit pci_bus_add_device(struct pci_dev *dev)
+int __devinit pci_bus_add_device(struct pci_dev *dev)
{
- device_add(&dev->dev);
+ int retval;
+ retval = device_add(&dev->dev);
+ if (retval)
+ return retval;
down_write(&pci_bus_sem);
list_add_tail(&dev->global_list, &pci_devices);
@@ -87,6 +90,7 @@ void __devinit pci_bus_add_device(struct pci_dev *dev)
pci_proc_attach_device(dev);
pci_create_sysfs_dev_files(dev);
+ return 0;
}
/**
@@ -104,6 +108,7 @@ void __devinit pci_bus_add_device(struct pci_dev *dev)
void __devinit pci_bus_add_devices(struct pci_bus *bus)
{
struct pci_dev *dev;
+ int retval;
list_for_each_entry(dev, &bus->devices, bus_list) {
/*
@@ -112,7 +117,9 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
*/
if (!list_empty(&dev->global_list))
continue;
- pci_bus_add_device(dev);
+ retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "Error adding device, continuing\n");
}
list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -129,10 +136,13 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
list_add_tail(&dev->subordinate->node,
&dev->bus->children);
up_write(&pci_bus_sem);
- }
+ }
pci_bus_add_devices(dev->subordinate);
-
- sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
+ retval = sysfs_create_link(&dev->subordinate->class_dev.kobj,
+ &dev->dev.kobj, "bridge");
+ if (retval)
+ dev_err(&dev->dev, "Error creating sysfs "
+ "bridge symlink, continuing...\n");
}
}
}
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 8a60f391ffcf..6e780db9454d 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -157,7 +157,7 @@ config HOTPLUG_PCI_RPA
tristate "RPA PCI Hotplug driver"
depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
help
- Say Y here if you have a a RPA system that supports PCI Hotplug.
+ Say Y here if you have a RPA system that supports PCI Hotplug.
To compile this driver as a module, choose M here: the
module will be called rpaphp.
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c
index 51cb9f817c22..270a33cc08f6 100644
--- a/drivers/pci/hotplug/acpi_pcihp.c
+++ b/drivers/pci/hotplug/acpi_pcihp.c
@@ -29,10 +29,10 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <acpi/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/actypes.h>
-#include "pci_hotplug.h"
#define MY_NAME "acpi_pcihp"
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index be104eced34c..59c5b242d86d 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -38,7 +38,7 @@
#include <linux/acpi.h>
#include <linux/kobject.h> /* for KOBJ_NAME_LEN */
#include <linux/mutex.h>
-#include "pci_hotplug.h"
+#include <linux/pci_hotplug.h>
#define dbg(format, arg...) \
do { \
@@ -150,6 +150,11 @@ struct acpiphp_attention_info
struct module *owner;
};
+struct acpiphp_ioapic {
+ struct pci_dev *dev;
+ u32 gsi_base;
+ struct list_head list;
+};
/* PCI bus bridge HID */
#define ACPI_PCI_HOST_HID "PNP0A03"
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index e2fef60c2d06..c57d9d5ce84e 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -37,10 +37,10 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
-#include "pci_hotplug.h"
#include "acpiphp.h"
#define MY_NAME "acpiphp"
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index ae67a8f55ba1..c44311ac2fd3 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -45,14 +45,16 @@
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/smp_lock.h>
#include <linux/mutex.h>
#include "../pci.h"
-#include "pci_hotplug.h"
#include "acpiphp.h"
static LIST_HEAD(bridge_list);
+static LIST_HEAD(ioapic_list);
+static DEFINE_SPINLOCK(ioapic_list_lock);
#define MY_NAME "acpiphp_glue"
@@ -797,6 +799,7 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
struct pci_dev *pdev;
u32 gsi_base;
u64 phys_addr;
+ struct acpiphp_ioapic *ioapic;
/* Evaluate _STA if present */
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
@@ -811,41 +814,107 @@ ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
if (get_gsi_base(handle, &gsi_base))
return AE_OK;
+ ioapic = kmalloc(sizeof(*ioapic), GFP_KERNEL);
+ if (!ioapic)
+ return AE_NO_MEMORY;
+
pdev = get_apic_pci_info(handle);
if (!pdev)
- return AE_OK;
+ goto exit_kfree;
- if (pci_enable_device(pdev)) {
- pci_dev_put(pdev);
- return AE_OK;
- }
+ if (pci_enable_device(pdev))
+ goto exit_pci_dev_put;
pci_set_master(pdev);
- if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) {
- pci_disable_device(pdev);
- pci_dev_put(pdev);
- return AE_OK;
- }
+ if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)"))
+ goto exit_pci_disable_device;
phys_addr = pci_resource_start(pdev, 0);
- if (acpi_register_ioapic(handle, phys_addr, gsi_base)) {
- pci_release_region(pdev, 0);
- pci_disable_device(pdev);
- pci_dev_put(pdev);
+ if (acpi_register_ioapic(handle, phys_addr, gsi_base))
+ goto exit_pci_release_region;
+
+ ioapic->gsi_base = gsi_base;
+ ioapic->dev = pdev;
+ spin_lock(&ioapic_list_lock);
+ list_add_tail(&ioapic->list, &ioapic_list);
+ spin_unlock(&ioapic_list_lock);
+
+ return AE_OK;
+
+ exit_pci_release_region:
+ pci_release_region(pdev, 0);
+ exit_pci_disable_device:
+ pci_disable_device(pdev);
+ exit_pci_dev_put:
+ pci_dev_put(pdev);
+ exit_kfree:
+ kfree(ioapic);
+
+ return AE_OK;
+}
+
+static acpi_status
+ioapic_remove(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ acpi_status status;
+ unsigned long sta;
+ acpi_handle tmp;
+ u32 gsi_base;
+ struct acpiphp_ioapic *pos, *n, *ioapic = NULL;
+
+ /* Evaluate _STA if present */
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
+ return AE_CTRL_DEPTH;
+
+ /* Scan only PCI bus scope */
+ status = acpi_get_handle(handle, "_HID", &tmp);
+ if (ACPI_SUCCESS(status))
+ return AE_CTRL_DEPTH;
+
+ if (get_gsi_base(handle, &gsi_base))
return AE_OK;
+
+ acpi_unregister_ioapic(handle, gsi_base);
+
+ spin_lock(&ioapic_list_lock);
+ list_for_each_entry_safe(pos, n, &ioapic_list, list) {
+ if (pos->gsi_base != gsi_base)
+ continue;
+ ioapic = pos;
+ list_del(&ioapic->list);
+ break;
}
+ spin_unlock(&ioapic_list_lock);
+
+ if (!ioapic)
+ return AE_OK;
+
+ pci_release_region(ioapic->dev, 0);
+ pci_disable_device(ioapic->dev);
+ pci_dev_put(ioapic->dev);
+ kfree(ioapic);
return AE_OK;
}
static int acpiphp_configure_ioapics(acpi_handle handle)
{
+ ioapic_add(handle, 0, NULL, NULL);
acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
return 0;
}
+static int acpiphp_unconfigure_ioapics(acpi_handle handle)
+{
+ ioapic_remove(handle, 0, NULL, NULL);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ ACPI_UINT32_MAX, ioapic_remove, NULL, NULL);
+ return 0;
+}
+
static int power_on_slot(struct acpiphp_slot *slot)
{
acpi_status status;
@@ -997,7 +1066,7 @@ acpiphp_bus_add_out:
* @handle: handle to acpi namespace
*
*/
-int acpiphp_bus_trim(acpi_handle handle)
+static int acpiphp_bus_trim(acpi_handle handle)
{
struct acpi_device *device;
int retval;
@@ -1074,10 +1143,11 @@ static int enable_device(struct acpiphp_slot *slot)
pci_bus_assign_resources(bus);
acpiphp_sanitize_bus(bus);
+ acpiphp_set_hpp_values(slot->bridge->handle, bus);
+ list_for_each_entry(func, &slot->funcs, sibling)
+ acpiphp_configure_ioapics(func->handle);
pci_enable_bridges(bus);
pci_bus_add_devices(bus);
- acpiphp_set_hpp_values(slot->bridge->handle, bus);
- acpiphp_configure_ioapics(slot->bridge->handle);
/* associate pci_dev to our representation */
list_for_each (l, &slot->funcs) {
@@ -1103,6 +1173,16 @@ static int enable_device(struct acpiphp_slot *slot)
return retval;
}
+static void disable_bridges(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (dev->subordinate) {
+ disable_bridges(dev->subordinate);
+ pci_disable_device(dev);
+ }
+ }
+}
/**
* disable_device - disable a slot
@@ -1127,6 +1207,19 @@ static int disable_device(struct acpiphp_slot *slot)
func->bridge = NULL;
}
+ if (func->pci_dev) {
+ pci_stop_bus_device(func->pci_dev);
+ if (func->pci_dev->subordinate) {
+ disable_bridges(func->pci_dev->subordinate);
+ pci_disable_device(func->pci_dev);
+ }
+ }
+ }
+
+ list_for_each (l, &slot->funcs) {
+ func = list_entry(l, struct acpiphp_func, sibling);
+
+ acpiphp_unconfigure_ioapics(func->handle);
acpiphp_bus_trim(func->handle);
/* try to remove anyway.
* acpiphp_bus_add might have been failed */
diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c
index d0a07d9ab30c..bd40aee10e16 100644
--- a/drivers/pci/hotplug/acpiphp_ibm.c
+++ b/drivers/pci/hotplug/acpiphp_ibm.c
@@ -35,7 +35,6 @@
#include <linux/moduleparam.h>
#include "acpiphp.h"
-#include "pci_hotplug.h"
#define DRIVER_VERSION "1.0.1"
#define DRIVER_AUTHOR "Irene Zubarev <zubarev@us.ibm.com>, Vernon Mauery <vernux@us.ibm.com>"
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index d5df5871cfa2..684551559d44 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -29,12 +29,12 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <asm/atomic.h>
#include <linux/delay.h>
-#include "pci_hotplug.h"
#include "cpci_hotplug.h"
#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>"
@@ -342,7 +342,7 @@ cpci_hp_unregister_bus(struct pci_bus *bus)
/* This is the interrupt mode interrupt handler */
static irqreturn_t
-cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
+cpci_hp_intr(int irq, void *data)
{
dbg("entered cpci_hp_intr");
diff --git a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c
index 4afcaffd031c..7b1beaad2752 100644
--- a/drivers/pci/hotplug/cpci_hotplug_pci.c
+++ b/drivers/pci/hotplug/cpci_hotplug_pci.c
@@ -26,9 +26,9 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/proc_fs.h>
#include "../pci.h"
-#include "pci_hotplug.h"
#include "cpci_hotplug.h"
#define MY_NAME "cpci_hotplug"
diff --git a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c
index e847f0d6c7fe..f3852a6b74ea 100644
--- a/drivers/pci/hotplug/cpcihp_generic.c
+++ b/drivers/pci/hotplug/cpcihp_generic.c
@@ -84,7 +84,7 @@ static int __init validate_parameters(void)
if(!bridge) {
info("not configured, disabling.");
- return 1;
+ return -EINVAL;
}
str = bridge;
if(!*str)
@@ -147,7 +147,7 @@ static int __init cpcihp_generic_init(void)
info(DRIVER_DESC " version: " DRIVER_VERSION);
status = validate_parameters();
- if(status != 0)
+ if (status)
return status;
r = request_region(port, 1, "#ENUM hotswap signal register");
diff --git a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h
index c74e9e37e76b..298ad7f3f4f4 100644
--- a/drivers/pci/hotplug/cpqphp.h
+++ b/drivers/pci/hotplug/cpqphp.h
@@ -28,7 +28,6 @@
#ifndef _CPQPHP_H
#define _CPQPHP_H
-#include "pci_hotplug.h"
#include <linux/interrupt.h>
#include <asm/io.h> /* for read? and write? functions */
#include <linux/delay.h> /* for delays */
@@ -409,7 +408,7 @@ extern void cpqhp_remove_debugfs_files (struct controller *ctrl);
/* controller functions */
extern void cpqhp_pushbutton_thread (unsigned long event_pointer);
-extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs);
+extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data);
extern int cpqhp_find_available_resources (struct controller *ctrl, void __iomem *rom_start);
extern int cpqhp_event_start_thread (void);
extern void cpqhp_event_stop_thread (void);
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index 1fc259913b68..5617cfdadc5c 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <linux/interrupt.h>
diff --git a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c
index ae2dd36efef2..79ff6b4de3a6 100644
--- a/drivers/pci/hotplug/cpqphp_ctrl.c
+++ b/drivers/pci/hotplug/cpqphp_ctrl.c
@@ -36,6 +36,7 @@
#include <linux/wait.h>
#include <linux/smp_lock.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include "cpqphp.h"
static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,
@@ -889,7 +890,7 @@ int cpqhp_resource_sort_and_combine(struct pci_resource **head)
}
-irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs)
+irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data)
{
struct controller *ctrl = data;
u8 schedule_flag = 0;
diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c
index cf0878917537..298a6cfd8406 100644
--- a/drivers/pci/hotplug/cpqphp_nvram.c
+++ b/drivers/pci/hotplug/cpqphp_nvram.c
@@ -33,6 +33,7 @@
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include "cpqphp.h"
diff --git a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c
index 0d9688952f4a..fc7c74d72595 100644
--- a/drivers/pci/hotplug/cpqphp_pci.c
+++ b/drivers/pci/hotplug/cpqphp_pci.c
@@ -33,6 +33,7 @@
#include <linux/workqueue.h>
#include <linux/proc_fs.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include "../pci.h"
#include "cpqphp.h"
#include "cpqphp_nvram.h"
diff --git a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c
index 8b3da007e859..634f74d919d3 100644
--- a/drivers/pci/hotplug/cpqphp_sysfs.c
+++ b/drivers/pci/hotplug/cpqphp_sysfs.c
@@ -32,6 +32,7 @@
#include <linux/proc_fs.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/debugfs.h>
#include "cpqphp.h"
@@ -140,7 +141,7 @@ struct ctrl_dbg {
static int open(struct inode *inode, struct file *file)
{
- struct controller *ctrl = inode->u.generic_ip;
+ struct controller *ctrl = inode->i_private;
struct ctrl_dbg *dbg;
int retval = -ENOMEM;
diff --git a/drivers/pci/hotplug/fakephp.c b/drivers/pci/hotplug/fakephp.c
index dd2b762777c4..e27907c91d92 100644
--- a/drivers/pci/hotplug/fakephp.c
+++ b/drivers/pci/hotplug/fakephp.c
@@ -35,10 +35,10 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
-#include "pci_hotplug.h"
#include "../pci.h"
#if !defined(MODULE)
@@ -176,17 +176,25 @@ static void pci_rescan_slot(struct pci_dev *temp)
struct pci_bus *bus = temp->bus;
struct pci_dev *dev;
int func;
+ int retval;
u8 hdr_type;
+
if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
temp->hdr_type = hdr_type & 0x7f;
- if (!pci_find_slot(bus->number, temp->devfn)) {
+ if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
+ pci_dev_put(dev);
+ else {
dev = pci_scan_single_device(bus, temp->devfn);
if (dev) {
dbg("New device on %s function %x:%x\n",
bus->name, temp->devfn >> 3,
temp->devfn & 7);
- pci_bus_add_device(dev);
- add_slot(dev);
+ retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "error adding "
+ "device, continuing.\n");
+ else
+ add_slot(dev);
}
}
/* multifunction device? */
@@ -199,14 +207,20 @@ static void pci_rescan_slot(struct pci_dev *temp)
continue;
temp->hdr_type = hdr_type & 0x7f;
- if (!pci_find_slot(bus->number, temp->devfn)) {
+ if ((dev = pci_get_slot(bus, temp->devfn)) != NULL)
+ pci_dev_put(dev);
+ else {
dev = pci_scan_single_device(bus, temp->devfn);
if (dev) {
dbg("New device on %s function %x:%x\n",
bus->name, temp->devfn >> 3,
temp->devfn & 7);
- pci_bus_add_device(dev);
- add_slot(dev);
+ retval = pci_bus_add_device(dev);
+ if (retval)
+ dev_err(&dev->dev, "error adding "
+ "device, continuing.\n");
+ else
+ add_slot(dev);
}
}
}
@@ -295,7 +309,7 @@ static int disable_slot(struct hotplug_slot *slot)
/* search for subfunctions and disable them first */
if (!(dslot->dev->devfn & 7)) {
for (func = 1; func < 8; func++) {
- dev = pci_find_slot(dslot->dev->bus->number,
+ dev = pci_get_slot(dslot->dev->bus,
dslot->dev->devfn + func);
if (dev) {
hslot = get_slot_from_dev(dev);
@@ -305,6 +319,7 @@ static int disable_slot(struct hotplug_slot *slot)
err("Hotplug slot not found for subfunction of PCI device\n");
return -ENODEV;
}
+ pci_dev_put(dev);
} else
dbg("No device in slot found\n");
}
diff --git a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h
index dba6d8ca9bda..612d96301509 100644
--- a/drivers/pci/hotplug/ibmphp.h
+++ b/drivers/pci/hotplug/ibmphp.h
@@ -30,7 +30,7 @@
*
*/
-#include "pci_hotplug.h"
+#include <linux/pci_hotplug.h>
extern int ibmphp_debug;
diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c
index b7b378df89e3..f5d632e72323 100644
--- a/drivers/pci/hotplug/pci_hotplug_core.c
+++ b/drivers/pci/hotplug/pci_hotplug_core.c
@@ -21,9 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <greg@kroah.com>
- *
- * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs
+ * Send feedback to <kristen.c.accardi@intel.com>
*
*/
@@ -32,6 +30,8 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/list.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/smp_lock.h>
@@ -39,11 +39,8 @@
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <asm/uaccess.h>
-#include <linux/kobject.h>
-#include <linux/sysfs.h>
-#include "pci_hotplug.h"
-
#define MY_NAME "pci_hotplug"
@@ -482,31 +479,95 @@ static int has_test_file (struct hotplug_slot *slot)
static int fs_add_slot (struct hotplug_slot *slot)
{
- if (has_power_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+ int retval = 0;
- if (has_attention_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+ if (has_power_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+ if (retval)
+ goto exit_power;
+ }
- if (has_latch_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+ if (has_attention_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_attention.attr);
+ if (retval)
+ goto exit_attention;
+ }
- if (has_adapter_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+ if (has_latch_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_latch.attr);
+ if (retval)
+ goto exit_latch;
+ }
- if (has_address_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+ if (has_adapter_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_presence.attr);
+ if (retval)
+ goto exit_adapter;
+ }
- if (has_max_bus_speed_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+ if (has_address_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_address.attr);
+ if (retval)
+ goto exit_address;
+ }
+
+ if (has_max_bus_speed_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_max_bus_speed.attr);
+ if (retval)
+ goto exit_max_speed;
+ }
+
+ if (has_cur_bus_speed_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_cur_bus_speed.attr);
+ if (retval)
+ goto exit_cur_speed;
+ }
+
+ if (has_test_file(slot) == 0) {
+ retval = sysfs_create_file(&slot->kobj,
+ &hotplug_slot_attr_test.attr);
+ if (retval)
+ goto exit_test;
+ }
+ goto exit;
+
+exit_test:
if (has_cur_bus_speed_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
- if (has_test_file(slot) == 0)
- sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr);
+exit_cur_speed:
+ if (has_max_bus_speed_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
- return 0;
+exit_max_speed:
+ if (has_address_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+
+exit_address:
+ if (has_adapter_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+
+exit_adapter:
+ if (has_latch_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+
+exit_latch:
+ if (has_attention_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+
+exit_attention:
+ if (has_power_file(slot) == 0)
+ sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+exit_power:
+exit:
+ return retval;
}
static void fs_remove_slot (struct hotplug_slot *slot)
@@ -626,8 +687,11 @@ int pci_hp_deregister (struct hotplug_slot *slot)
*
* Returns 0 if successful, anything else for an error.
*/
-int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info)
+int __must_check pci_hp_change_slot_info(struct hotplug_slot *slot,
+ struct hotplug_slot_info *info)
{
+ int retval;
+
if ((slot == NULL) || (info == NULL))
return -ENODEV;
@@ -636,32 +700,60 @@ int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info
* for the files referring to the fields that have now changed.
*/
if ((has_power_file(slot) == 0) &&
- (slot->info->power_status != info->power_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr);
+ (slot->info->power_status != info->power_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_power.attr);
+ if (retval)
+ return retval;
+ }
if ((has_attention_file(slot) == 0) &&
- (slot->info->attention_status != info->attention_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr);
+ (slot->info->attention_status != info->attention_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_attention.attr);
+ if (retval)
+ return retval;
+ }
if ((has_latch_file(slot) == 0) &&
- (slot->info->latch_status != info->latch_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr);
+ (slot->info->latch_status != info->latch_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_latch.attr);
+ if (retval)
+ return retval;
+ }
if ((has_adapter_file(slot) == 0) &&
- (slot->info->adapter_status != info->adapter_status))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr);
+ (slot->info->adapter_status != info->adapter_status)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_presence.attr);
+ if (retval)
+ return retval;
+ }
if ((has_address_file(slot) == 0) &&
- (slot->info->address != info->address))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_address.attr);
+ (slot->info->address != info->address)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_address.attr);
+ if (retval)
+ return retval;
+ }
if ((has_max_bus_speed_file(slot) == 0) &&
- (slot->info->max_bus_speed != info->max_bus_speed))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr);
+ (slot->info->max_bus_speed != info->max_bus_speed)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_max_bus_speed.attr);
+ if (retval)
+ return retval;
+ }
if ((has_cur_bus_speed_file(slot) == 0) &&
- (slot->info->cur_bus_speed != info->cur_bus_speed))
- sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr);
+ (slot->info->cur_bus_speed != info->cur_bus_speed)) {
+ retval = sysfs_update_file(&slot->kobj,
+ &hotplug_slot_attr_cur_bus_speed.attr);
+ if (retval)
+ return retval;
+ }
memcpy (slot->info, info, sizeof (struct hotplug_slot_info));
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index eaea9d36a1bb..4fb12fcda563 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -31,11 +31,11 @@
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/delay.h>
#include <linux/sched.h> /* signal_pending() */
#include <linux/pcieport_if.h>
#include <linux/mutex.h>
-#include "pci_hotplug.h"
#define MY_NAME "pciehp"
@@ -92,6 +92,7 @@ struct php_ctlr_state_s {
struct controller {
struct controller *next;
struct mutex crit_sect; /* critical section mutex */
+ struct mutex ctrl_lock; /* controller lock */
struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
int num_slots; /* Number of slots on ctlr */
int slot_num_inc; /* 1 or -1 */
@@ -166,10 +167,10 @@ struct controller {
* error Messages
*/
#define msg_initialization_err "Initialization failure, error=%d\n"
-#define msg_button_on "PCI slot #%d - powering on due to button press.\n"
-#define msg_button_off "PCI slot #%d - powering off due to button press.\n"
-#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n"
-#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n"
+#define msg_button_on "PCI slot #%s - powering on due to button press.\n"
+#define msg_button_off "PCI slot #%s - powering off due to button press.\n"
+#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
+#define msg_button_ignore "PCI slot #%s - button press ignored. (action in progress...)\n"
/* controller functions */
extern int pciehp_event_start_thread (void);
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index c67b7c3f1ddf..f93e81e2d2c7 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -448,7 +448,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
}
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
@@ -456,7 +456,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
if (rc) {
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
goto err_out_free_ctrl_slot;
} else
/* Wait for the command to complete */
@@ -464,7 +464,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
return 0;
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index 33d198768356..372c63e35aa9 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -43,6 +43,11 @@ static int event_finished;
static unsigned long pushbutton_pending; /* = 0 */
static unsigned long surprise_rm_pending; /* = 0 */
+static inline char *slot_name(struct slot *p_slot)
+{
+ return p_slot->hotplug_slot->name;
+}
+
u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
{
struct controller *ctrl = (struct controller *) inst_id;
@@ -68,7 +73,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
/*
* Button pressed - See if need to TAKE ACTION!!!
*/
- info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Button pressed on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_BUTTON_PRESS;
if ((p_slot->state == BLINKINGON_STATE)
@@ -78,7 +83,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
* or hot-remove
*/
taskInfo->event_type = INT_BUTTON_CANCEL;
- info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Button cancel on Slot(%s)\n", slot_name(p_slot));
} else if ((p_slot->state == POWERON_STATE)
|| (p_slot->state == POWEROFF_STATE)) {
/* Ignore if the slot is on power-on or power-off state; this
@@ -86,7 +91,7 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
* hot-remove is undergoing
*/
taskInfo->event_type = INT_BUTTON_IGNORE;
- info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Button ignore on Slot(%s)\n", slot_name(p_slot));
}
if (rc)
@@ -122,13 +127,13 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
/*
* Switch opened
*/
- info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Latch open on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_SWITCH_OPEN;
} else {
/*
* Switch closed
*/
- info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Latch close on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_SWITCH_CLOSE;
}
@@ -166,13 +171,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
/*
* Card Present
*/
- info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Card present on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_PRESENCE_ON;
} else {
/*
* Not Present
*/
- info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Card not present on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_PRESENCE_OFF;
}
@@ -206,13 +211,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
/*
* power fault Cleared
*/
- info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Power fault cleared on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_POWER_FAULT_CLEAR;
} else {
/*
* power fault
*/
- info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
+ info("Power fault on Slot(%s)\n", slot_name(p_slot));
taskInfo->event_type = INT_POWER_FAULT;
info("power fault bit %x set\n", hp_slot);
}
@@ -229,13 +234,13 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
static void set_slot_off(struct controller *ctrl, struct slot * pslot)
{
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
if (POWER_CTRL(ctrl->ctrlcap)) {
if (pslot->hpc_ops->power_off_slot(pslot)) {
err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
return;
}
wait_for_ctrl_irq (ctrl);
@@ -249,14 +254,14 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
if (ATTN_LED(ctrl->ctrlcap)) {
if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
return;
}
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
}
/**
@@ -279,13 +284,13 @@ static int board_added(struct slot *p_slot)
ctrl->slot_device_offset, hp_slot);
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* Power on slot */
rc = p_slot->hpc_ops->power_on_slot(p_slot);
if (rc) {
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
return -1;
}
@@ -301,7 +306,7 @@ static int board_added(struct slot *p_slot)
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
/* Wait for ~1 second */
wait_for_ctrl_irq (ctrl);
@@ -335,7 +340,7 @@ static int board_added(struct slot *p_slot)
pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
if (PWR_LED(ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
p_slot->hpc_ops->green_led_on(p_slot);
@@ -343,7 +348,7 @@ static int board_added(struct slot *p_slot)
wait_for_ctrl_irq (ctrl);
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
}
return 0;
@@ -375,14 +380,14 @@ static int remove_board(struct slot *p_slot)
dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
if (POWER_CTRL(ctrl->ctrlcap)) {
/* power off slot */
rc = p_slot->hpc_ops->power_off_slot(p_slot);
if (rc) {
err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
return rc;
}
/* Wait for the command to complete */
@@ -398,7 +403,7 @@ static int remove_board(struct slot *p_slot)
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
return 0;
}
@@ -445,7 +450,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->crit_sect);
+ mutex_lock(&p_slot->ctrl->ctrl_lock);
p_slot->hpc_ops->green_led_off(p_slot);
@@ -453,7 +458,7 @@ static void pciehp_pushbutton_thread(unsigned long slot)
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->crit_sect);
+ mutex_unlock(&p_slot->ctrl->ctrl_lock);
}
p_slot->state = STATIC_STATE;
}
@@ -495,7 +500,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
/* Wait for exclusive access to hardware */
- mutex_lock(&p_slot->ctrl->crit_sect);
+ mutex_lock(&p_slot->ctrl->ctrl_lock);
p_slot->hpc_ops->green_led_off(p_slot);
@@ -503,7 +508,7 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
wait_for_ctrl_irq (p_slot->ctrl);
/* Done with exclusive hardware access */
- mutex_unlock(&p_slot->ctrl->crit_sect);
+ mutex_unlock(&p_slot->ctrl->ctrl_lock);
}
p_slot->state = STATIC_STATE;
}
@@ -616,7 +621,7 @@ static void interrupt_event_handler(struct controller *ctrl)
switch (p_slot->state) {
case BLINKINGOFF_STATE:
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_on(p_slot);
@@ -630,11 +635,11 @@ static void interrupt_event_handler(struct controller *ctrl)
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
break;
case BLINKINGON_STATE:
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
if (PWR_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->green_led_off(p_slot);
@@ -647,14 +652,14 @@ static void interrupt_event_handler(struct controller *ctrl)
wait_for_ctrl_irq (ctrl);
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
break;
default:
warn("Not a valid state\n");
return;
}
- info(msg_button_cancel, p_slot->number);
+ info(msg_button_cancel, slot_name(p_slot));
p_slot->state = STATIC_STATE;
}
/* ***********Button Pressed (No action on 1st press...) */
@@ -667,16 +672,16 @@ static void interrupt_event_handler(struct controller *ctrl)
/* slot is on */
dbg("slot is on\n");
p_slot->state = BLINKINGOFF_STATE;
- info(msg_button_off, p_slot->number);
+ info(msg_button_off, slot_name(p_slot));
} else {
/* slot is off */
dbg("slot is off\n");
p_slot->state = BLINKINGON_STATE;
- info(msg_button_on, p_slot->number);
+ info(msg_button_on, slot_name(p_slot));
}
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
/* blink green LED and turn off amber */
if (PWR_LED(ctrl->ctrlcap)) {
@@ -693,7 +698,7 @@ static void interrupt_event_handler(struct controller *ctrl)
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
init_timer(&p_slot->task_event);
p_slot->task_event.expires = jiffies + 5 * HZ; /* 5 second delay */
@@ -708,7 +713,7 @@ static void interrupt_event_handler(struct controller *ctrl)
if (POWER_CTRL(ctrl->ctrlcap)) {
dbg("power fault\n");
/* Wait for exclusive access to hardware */
- mutex_lock(&ctrl->crit_sect);
+ mutex_lock(&ctrl->ctrl_lock);
if (ATTN_LED(ctrl->ctrlcap)) {
p_slot->hpc_ops->set_attention_status(p_slot, 1);
@@ -721,7 +726,7 @@ static void interrupt_event_handler(struct controller *ctrl)
}
/* Done with exclusive hardware access */
- mutex_unlock(&ctrl->crit_sect);
+ mutex_unlock(&ctrl->ctrl_lock);
}
}
/***********SURPRISE REMOVAL********************/
@@ -760,28 +765,30 @@ int pciehp_enable_slot(struct slot *p_slot)
rc = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (rc || !getstatus) {
- info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+ info("%s: no adapter on slot(%s)\n", __FUNCTION__,
+ slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (rc || getstatus) {
- info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+ info("%s: latch open on slot(%s)\n", __FUNCTION__,
+ slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
}
if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
rc = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (rc || getstatus) {
- info("%s: already enabled on slot(%x)\n", __FUNCTION__, p_slot->number);
+ info("%s: already enabled on slot(%s)\n", __FUNCTION__,
+ slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -EINVAL;
}
}
- mutex_unlock(&p_slot->ctrl->crit_sect);
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
@@ -790,9 +797,9 @@ int pciehp_enable_slot(struct slot *p_slot)
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
}
- if (p_slot)
- update_slot_info(p_slot);
+ update_slot_info(p_slot);
+ mutex_unlock(&p_slot->ctrl->crit_sect);
return rc;
}
@@ -811,34 +818,37 @@ int pciehp_disable_slot(struct slot *p_slot)
if (!HP_SUPR_RM(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_adapter_status(p_slot, &getstatus);
if (ret || !getstatus) {
- info("%s: no adapter on slot(%x)\n", __FUNCTION__, p_slot->number);
+ info("%s: no adapter on slot(%s)\n", __FUNCTION__,
+ slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
}
if (MRL_SENS(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (ret || getstatus) {
- info("%s: latch open on slot(%x)\n", __FUNCTION__, p_slot->number);
+ info("%s: latch open on slot(%s)\n", __FUNCTION__,
+ slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -ENODEV;
}
}
if (POWER_CTRL(p_slot->ctrl->ctrlcap)) {
ret = p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
if (ret || !getstatus) {
- info("%s: already disabled slot(%x)\n", __FUNCTION__, p_slot->number);
+ info("%s: already disabled slot(%s)\n", __FUNCTION__,
+ slot_name(p_slot));
mutex_unlock(&p_slot->ctrl->crit_sect);
- return 1;
+ return -EINVAL;
}
}
- mutex_unlock(&p_slot->ctrl->crit_sect);
-
ret = remove_board(p_slot);
update_slot_info(p_slot);
+
+ mutex_unlock(&p_slot->ctrl->crit_sect);
return ret;
}
diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c
index 6ab3b6cd2b54..1c551c697c35 100644
--- a/drivers/pci/hotplug/pciehp_hpc.c
+++ b/drivers/pci/hotplug/pciehp_hpc.c
@@ -222,7 +222,7 @@ static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
static int ctlr_seq_num = 0; /* Controller sequence # */
static spinlock_t list_lock;
-static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs);
+static irqreturn_t pcie_isr(int IRQ, void *dev_id);
static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
@@ -239,7 +239,7 @@ static void int_poll_timeout(unsigned long lphp_ctlr)
}
/* Poll for interrupt events. regs == NULL => polling */
- pcie_isr( 0, (void *)php_ctlr, NULL );
+ pcie_isr( 0, (void *)php_ctlr );
init_timer(&php_ctlr->int_poll_timer);
@@ -863,7 +863,7 @@ static int hpc_power_off_slot(struct slot * slot)
return retval;
}
-static irqreturn_t pcie_isr(int IRQ, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pcie_isr(int IRQ, void *dev_id)
{
struct controller *ctrl = NULL;
struct php_ctlr_state_s *php_ctlr;
@@ -1402,6 +1402,8 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
pdev->subsystem_vendor, pdev->subsystem_device);
mutex_init(&ctrl->crit_sect);
+ mutex_init(&ctrl->ctrl_lock);
+
/* setup wait queue */
init_waitqueue_head(&ctrl->queue);
diff --git a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c
index 8ad446605f75..50bcd3fe61da 100644
--- a/drivers/pci/hotplug/pcihp_skeleton.c
+++ b/drivers/pci/hotplug/pcihp_skeleton.c
@@ -1,5 +1,5 @@
/*
- * PCI Hot Plug Controller Skeleton Driver - 0.2
+ * PCI Hot Plug Controller Skeleton Driver - 0.3
*
* Copyright (C) 2001,2003 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2001,2003 IBM Corp.
@@ -21,7 +21,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * This driver is to be used as a skeleton driver to be show how to interface
+ * This driver is to be used as a skeleton driver to show how to interface
* with the pci hotplug core easily.
*
* Send feedback to <greg@kroah.com>
@@ -33,8 +33,8 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/init.h>
-#include "pci_hotplug.h"
#define SLOT_NAME_SIZE 10
struct slot {
@@ -58,8 +58,6 @@ static LIST_HEAD(slot_list);
#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg)
#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg)
-
-
/* local variables */
static int debug;
static int num_slots;
@@ -109,7 +107,6 @@ static int enable_slot(struct hotplug_slot *hotplug_slot)
return retval;
}
-
static int disable_slot(struct hotplug_slot *hotplug_slot)
{
struct slot *slot = hotplug_slot->private;
@@ -342,7 +339,7 @@ static int __init pcihp_skel_init(void)
info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
/*
* Do specific initialization stuff for your driver here
- * Like initializing your controller hardware (if any) and
+ * like initializing your controller hardware (if any) and
* determining the number of slots you have in the system
* right now.
*/
diff --git a/drivers/pci/hotplug/rpadlpar_sysfs.c b/drivers/pci/hotplug/rpadlpar_sysfs.c
index db69be85b458..6c5be3ff578c 100644
--- a/drivers/pci/hotplug/rpadlpar_sysfs.c
+++ b/drivers/pci/hotplug/rpadlpar_sysfs.c
@@ -14,7 +14,7 @@
*/
#include <linux/kobject.h>
#include <linux/string.h>
-#include "pci_hotplug.h"
+#include <linux/pci_hotplug.h>
#include "rpadlpar.h"
#define DLPAR_KOBJ_NAME "control"
diff --git a/drivers/pci/hotplug/rpaphp.h b/drivers/pci/hotplug/rpaphp.h
index 310b6186c0e5..2e7accf0f734 100644
--- a/drivers/pci/hotplug/rpaphp.h
+++ b/drivers/pci/hotplug/rpaphp.h
@@ -28,7 +28,7 @@
#define _PPC64PHP_H
#include <linux/pci.h>
-#include "pci_hotplug.h"
+#include <linux/pci_hotplug.h>
#define DR_INDICATOR 9002
#define DR_ENTITY_SENSE 9003
diff --git a/drivers/pci/hotplug/rpaphp_core.c b/drivers/pci/hotplug/rpaphp_core.c
index 7288a3eccfb3..141486df235b 100644
--- a/drivers/pci/hotplug/rpaphp_core.c
+++ b/drivers/pci/hotplug/rpaphp_core.c
@@ -26,6 +26,7 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
@@ -36,7 +37,6 @@
#include "../pci.h" /* for pci_add_new_bus */
/* and pci_do_scan_bus */
#include "rpaphp.h"
-#include "pci_hotplug.h"
int debug;
static struct semaphore rpaphp_sem;
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index f31d83c2c633..b62ad31a9739 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/proc_fs.h>
#include <linux/types.h>
#include <linux/mutex.h>
@@ -29,7 +30,6 @@
#include <asm/sn/types.h>
#include "../pci.h"
-#include "pci_hotplug.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
diff --git a/drivers/pci/hotplug/shpchp.h b/drivers/pci/hotplug/shpchp.h
index 7208b95c6ee7..ea2087c34149 100644
--- a/drivers/pci/hotplug/shpchp.h
+++ b/drivers/pci/hotplug/shpchp.h
@@ -31,12 +31,11 @@
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/pci_hotplug.h>
#include <linux/delay.h>
#include <linux/sched.h> /* signal_pending(), struct timer_list */
#include <linux/mutex.h>
-#include "pci_hotplug.h"
-
#if !defined(MODULE)
#define MY_NAME "shpchp"
#else
@@ -103,7 +102,6 @@ struct controller {
u32 cap_offset;
unsigned long mmio_base;
unsigned long mmio_size;
- volatile int cmd_busy;
};
@@ -173,7 +171,7 @@ struct controller {
#define msg_button_cancel "PCI slot #%s - action canceled due to button press.\n"
/* sysfs functions for the hotplug controller info */
-extern void shpchp_create_ctrl_files (struct controller *ctrl);
+extern int __must_check shpchp_create_ctrl_files(struct controller *ctrl);
extern int shpchp_sysfs_enable_slot(struct slot *slot);
extern int shpchp_sysfs_disable_slot(struct slot *slot);
diff --git a/drivers/pci/hotplug/shpchp_core.c b/drivers/pci/hotplug/shpchp_core.c
index a14e7de19846..235c18a22393 100644
--- a/drivers/pci/hotplug/shpchp_core.c
+++ b/drivers/pci/hotplug/shpchp_core.c
@@ -449,10 +449,14 @@ static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ctrl->speed = PCI_SPEED_33MHz;
}
- shpchp_create_ctrl_files(ctrl);
+ rc = shpchp_create_ctrl_files(ctrl);
+ if (rc)
+ goto err_cleanup_slots;
return 0;
+err_cleanup_slots:
+ cleanup_slots(ctrl);
err_out_release_ctlr:
ctrl->hpc_ops->release_ctlr(ctrl);
err_out_free_ctrl:
diff --git a/drivers/pci/hotplug/shpchp_hpc.c b/drivers/pci/hotplug/shpchp_hpc.c
index 0f9798df4704..83a5226ba9ed 100644
--- a/drivers/pci/hotplug/shpchp_hpc.c
+++ b/drivers/pci/hotplug/shpchp_hpc.c
@@ -218,7 +218,7 @@ static spinlock_t list_lock;
static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
-static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t shpc_isr(int irq, void *dev_id);
static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec);
static int hpc_check_cmd_status(struct controller *ctrl);
@@ -276,7 +276,7 @@ static void int_poll_timeout(unsigned long lphp_ctlr)
DBG_ENTER_ROUTINE
/* Poll for interrupt events. regs == NULL => polling */
- shpc_isr(0, php_ctlr->callback_instance_id, NULL);
+ shpc_isr(0, php_ctlr->callback_instance_id);
init_timer(&php_ctlr->int_poll_timer);
if (!shpchp_poll_time)
@@ -302,21 +302,51 @@ static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int sec)
add_timer(&php_ctlr->int_poll_timer);
}
+static inline int is_ctrl_busy(struct controller *ctrl)
+{
+ u16 cmd_status = shpc_readw(ctrl, CMD_STATUS);
+ return cmd_status & 0x1;
+}
+
+/*
+ * Returns 1 if SHPC finishes executing a command within 1 sec,
+ * otherwise returns 0.
+ */
+static inline int shpc_poll_ctrl_busy(struct controller *ctrl)
+{
+ int i;
+
+ if (!is_ctrl_busy(ctrl))
+ return 1;
+
+ /* Check every 0.1 sec for a total of 1 sec */
+ for (i = 0; i < 10; i++) {
+ msleep(100);
+ if (!is_ctrl_busy(ctrl))
+ return 1;
+ }
+
+ return 0;
+}
+
static inline int shpc_wait_cmd(struct controller *ctrl)
{
int retval = 0;
- unsigned int timeout_msec = shpchp_poll_mode ? 2000 : 1000;
- unsigned long timeout = msecs_to_jiffies(timeout_msec);
- int rc = wait_event_interruptible_timeout(ctrl->queue,
- !ctrl->cmd_busy, timeout);
- if (!rc) {
+ unsigned long timeout = msecs_to_jiffies(1000);
+ int rc;
+
+ if (shpchp_poll_mode)
+ rc = shpc_poll_ctrl_busy(ctrl);
+ else
+ rc = wait_event_interruptible_timeout(ctrl->queue,
+ !is_ctrl_busy(ctrl), timeout);
+ if (!rc && is_ctrl_busy(ctrl)) {
retval = -EIO;
- err("Command not completed in %d msec\n", timeout_msec);
+ err("Command not completed in 1000 msec\n");
} else if (rc < 0) {
retval = -EINTR;
info("Command was interrupted by a signal\n");
}
- ctrl->cmd_busy = 0;
return retval;
}
@@ -327,26 +357,15 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
u16 cmd_status;
int retval = 0;
u16 temp_word;
- int i;
DBG_ENTER_ROUTINE
mutex_lock(&slot->ctrl->cmd_lock);
- for (i = 0; i < 10; i++) {
- cmd_status = shpc_readw(ctrl, CMD_STATUS);
-
- if (!(cmd_status & 0x1))
- break;
- /* Check every 0.1 sec for a total of 1 sec*/
- msleep(100);
- }
-
- cmd_status = shpc_readw(ctrl, CMD_STATUS);
-
- if (cmd_status & 0x1) {
+ if (!shpc_poll_ctrl_busy(ctrl)) {
/* After 1 sec and and the controller is still busy */
- err("%s : Controller is still busy after 1 sec.\n", __FUNCTION__);
+ err("%s : Controller is still busy after 1 sec.\n",
+ __FUNCTION__);
retval = -EBUSY;
goto out;
}
@@ -358,7 +377,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
/* To make sure the Controller Busy bit is 0 before we send out the
* command.
*/
- slot->ctrl->cmd_busy = 1;
shpc_writew(ctrl, CMD, temp_word);
/*
@@ -870,7 +888,7 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
return retval;
}
-static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t shpc_isr(int irq, void *dev_id)
{
struct controller *ctrl = (struct controller *)dev_id;
struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
@@ -908,7 +926,6 @@ static irqreturn_t shpc_isr(int irq, void *dev_id, struct pt_regs *regs)
serr_int &= ~SERR_INTR_RSVDZ_MASK;
shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
- ctrl->cmd_busy = 0;
wake_up_interruptible(&ctrl->queue);
}
@@ -1101,7 +1118,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
{
struct php_ctlr_state_s *php_ctlr, *p;
void *instance_id = ctrl;
- int rc, num_slots = 0;
+ int rc = -1, num_slots = 0;
u8 hp_slot;
u32 shpc_base_offset;
u32 tempdword, slot_reg, slot_config;
@@ -1167,11 +1184,15 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
pdev->subsystem_device);
- if (pci_enable_device(pdev))
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ err("%s: pci_enable_device failed\n", __FUNCTION__);
goto abort_free_ctlr;
+ }
if (!request_mem_region(ctrl->mmio_base, ctrl->mmio_size, MY_NAME)) {
err("%s: cannot reserve MMIO region\n", __FUNCTION__);
+ rc = -1;
goto abort_free_ctlr;
}
@@ -1180,6 +1201,7 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
err("%s: cannot remap MMIO region %lx @ %lx\n", __FUNCTION__,
ctrl->mmio_size, ctrl->mmio_base);
release_mem_region(ctrl->mmio_base, ctrl->mmio_size);
+ rc = -1;
goto abort_free_ctlr;
}
dbg("%s: php_ctlr->creg %p\n", __FUNCTION__, php_ctlr->creg);
@@ -1282,8 +1304,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
*/
if (atomic_add_return(1, &shpchp_num_controllers) == 1) {
shpchp_wq = create_singlethread_workqueue("shpchpd");
- if (!shpchp_wq)
- return -ENOMEM;
+ if (!shpchp_wq) {
+ rc = -ENOMEM;
+ goto abort_free_ctlr;
+ }
}
/*
@@ -1313,8 +1337,10 @@ int shpc_init(struct controller * ctrl, struct pci_dev * pdev)
/* We end up here for the many possible ways to fail this API. */
abort_free_ctlr:
+ if (php_ctlr->creg)
+ iounmap(php_ctlr->creg);
kfree(php_ctlr);
abort:
DBG_LEAVE_ROUTINE
- return -1;
+ return rc;
}
diff --git a/drivers/pci/hotplug/shpchp_sysfs.c b/drivers/pci/hotplug/shpchp_sysfs.c
index 620e1139e607..29fa9d26adae 100644
--- a/drivers/pci/hotplug/shpchp_sysfs.c
+++ b/drivers/pci/hotplug/shpchp_sysfs.c
@@ -91,9 +91,9 @@ static ssize_t show_ctrl (struct device *dev, struct device_attribute *attr, cha
}
static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL);
-void shpchp_create_ctrl_files (struct controller *ctrl)
+int __must_check shpchp_create_ctrl_files (struct controller *ctrl)
{
- device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
+ return device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl);
}
void shpchp_remove_ctrl_files(struct controller *ctrl)
diff --git a/drivers/pci/htirq.c b/drivers/pci/htirq.c
new file mode 100644
index 000000000000..0e27f2404a83
--- /dev/null
+++ b/drivers/pci/htirq.c
@@ -0,0 +1,190 @@
+/*
+ * File: htirq.c
+ * Purpose: Hypertransport Interrupt Capability
+ *
+ * Copyright (C) 2006 Linux Networx
+ * Copyright (C) Eric Biederman <ebiederman@lnxi.com>
+ */
+
+#include <linux/irq.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/gfp.h>
+#include <linux/htirq.h>
+
+/* Global ht irq lock.
+ *
+ * This is needed to serialize access to the data port in hypertransport
+ * irq capability.
+ *
+ * With multiple simultaneous hypertransport irq devices it might pay
+ * to make this more fine grained. But start with simple, stupid, and correct.
+ */
+static DEFINE_SPINLOCK(ht_irq_lock);
+
+struct ht_irq_cfg {
+ struct pci_dev *dev;
+ unsigned pos;
+ unsigned idx;
+};
+
+void write_ht_irq_low(unsigned int irq, u32 data)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+void write_ht_irq_high(unsigned int irq, u32 data)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+u32 read_ht_irq_low(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ u32 data;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+ return data;
+}
+
+u32 read_ht_irq_high(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg = get_irq_data(irq);
+ unsigned long flags;
+ u32 data;
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx + 1);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+ return data;
+}
+
+void mask_ht_irq(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg;
+ unsigned long flags;
+ u32 data;
+
+ cfg = get_irq_data(irq);
+
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ data |= 1;
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+void unmask_ht_irq(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg;
+ unsigned long flags;
+ u32 data;
+
+ cfg = get_irq_data(irq);
+
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(cfg->dev, cfg->pos + 2, cfg->idx);
+ pci_read_config_dword(cfg->dev, cfg->pos + 4, &data);
+ data &= ~1;
+ pci_write_config_dword(cfg->dev, cfg->pos + 4, data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+}
+
+/**
+ * ht_create_irq - create an irq and attach it to a device.
+ * @dev: The hypertransport device to find the irq capability on.
+ * @idx: Which of the possible irqs to attach to.
+ *
+ * ht_create_irq is needs to be called for all hypertransport devices
+ * that generate irqs.
+ *
+ * The irq number of the new irq or a negative error value is returned.
+ */
+int ht_create_irq(struct pci_dev *dev, int idx)
+{
+ struct ht_irq_cfg *cfg;
+ unsigned long flags;
+ u32 data;
+ int max_irq;
+ int pos;
+ int irq;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_HT);
+ while (pos) {
+ u8 subtype;
+ pci_read_config_byte(dev, pos + 3, &subtype);
+ if (subtype == HT_CAPTYPE_IRQ)
+ break;
+ pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT);
+ }
+ if (!pos)
+ return -EINVAL;
+
+ /* Verify the idx I want to use is in range */
+ spin_lock_irqsave(&ht_irq_lock, flags);
+ pci_write_config_byte(dev, pos + 2, 1);
+ pci_read_config_dword(dev, pos + 4, &data);
+ spin_unlock_irqrestore(&ht_irq_lock, flags);
+
+ max_irq = (data >> 16) & 0xff;
+ if ( idx > max_irq)
+ return -EINVAL;
+
+ cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ cfg->dev = dev;
+ cfg->pos = pos;
+ cfg->idx = 0x10 + (idx * 2);
+
+ irq = create_irq();
+ if (irq < 0) {
+ kfree(cfg);
+ return -EBUSY;
+ }
+ set_irq_data(irq, cfg);
+
+ if (arch_setup_ht_irq(irq, dev) < 0) {
+ ht_destroy_irq(irq);
+ return -EBUSY;
+ }
+
+ return irq;
+}
+
+/**
+ * ht_destroy_irq - destroy an irq created with ht_create_irq
+ *
+ * This reverses ht_create_irq removing the specified irq from
+ * existence. The irq should be free before this happens.
+ */
+void ht_destroy_irq(unsigned int irq)
+{
+ struct ht_irq_cfg *cfg;
+
+ cfg = get_irq_data(irq);
+ set_irq_chip(irq, NULL);
+ set_irq_data(irq, NULL);
+ destroy_irq(irq);
+
+ kfree(cfg);
+}
+
+EXPORT_SYMBOL(ht_create_irq);
+EXPORT_SYMBOL(ht_destroy_irq);
diff --git a/drivers/pci/msi-apic.c b/drivers/pci/msi-apic.c
deleted file mode 100644
index 5ed798b319c7..000000000000
--- a/drivers/pci/msi-apic.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * MSI hooks for standard x86 apic
- */
-
-#include <linux/pci.h>
-#include <linux/irq.h>
-#include <asm/smp.h>
-
-#include "msi.h"
-
-/*
- * Shifts for APIC-based data
- */
-
-#define MSI_DATA_VECTOR_SHIFT 0
-#define MSI_DATA_VECTOR(v) (((u8)v) << MSI_DATA_VECTOR_SHIFT)
-
-#define MSI_DATA_DELIVERY_SHIFT 8
-#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_SHIFT)
-#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_SHIFT)
-
-#define MSI_DATA_LEVEL_SHIFT 14
-#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
-#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
-
-#define MSI_DATA_TRIGGER_SHIFT 15
-#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
-#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
-
-/*
- * Shift/mask fields for APIC-based bus address
- */
-
-#define MSI_ADDR_HEADER 0xfee00000
-
-#define MSI_ADDR_DESTID_MASK 0xfff0000f
-#define MSI_ADDR_DESTID_CPU(cpu) ((cpu) << MSI_TARGET_CPU_SHIFT)
-
-#define MSI_ADDR_DESTMODE_SHIFT 2
-#define MSI_ADDR_DESTMODE_PHYS (0 << MSI_ADDR_DESTMODE_SHIFT)
-#define MSI_ADDR_DESTMODE_LOGIC (1 << MSI_ADDR_DESTMODE_SHIFT)
-
-#define MSI_ADDR_REDIRECTION_SHIFT 3
-#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT)
-#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT)
-
-
-static void
-msi_target_apic(unsigned int vector,
- unsigned int dest_cpu,
- u32 *address_hi, /* in/out */
- u32 *address_lo) /* in/out */
-{
- u32 addr = *address_lo;
-
- addr &= MSI_ADDR_DESTID_MASK;
- addr |= MSI_ADDR_DESTID_CPU(cpu_physical_id(dest_cpu));
-
- *address_lo = addr;
-}
-
-static int
-msi_setup_apic(struct pci_dev *pdev, /* unused in generic */
- unsigned int vector,
- u32 *address_hi,
- u32 *address_lo,
- u32 *data)
-{
- unsigned long dest_phys_id;
-
- dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
-
- *address_hi = 0;
- *address_lo = MSI_ADDR_HEADER |
- MSI_ADDR_DESTMODE_PHYS |
- MSI_ADDR_REDIRECTION_CPU |
- MSI_ADDR_DESTID_CPU(dest_phys_id);
-
- *data = MSI_DATA_TRIGGER_EDGE |
- MSI_DATA_LEVEL_ASSERT |
- MSI_DATA_DELIVERY_FIXED |
- MSI_DATA_VECTOR(vector);
-
- return 0;
-}
-
-static void
-msi_teardown_apic(unsigned int vector)
-{
- return; /* no-op */
-}
-
-/*
- * Generic ops used on most IA archs/platforms. Set with msi_register()
- */
-
-struct msi_ops msi_apic_ops = {
- .setup = msi_setup_apic,
- .teardown = msi_teardown_apic,
- .target = msi_target_apic,
-};
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index a83c1f5735d6..9fc9a34ef24a 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -6,6 +6,7 @@
* Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
*/
+#include <linux/err.h>
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
@@ -14,6 +15,7 @@
#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
+#include <linux/msi.h>
#include <asm/errno.h>
#include <asm/io.h>
@@ -27,60 +29,36 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
static kmem_cache_t* msi_cachep;
static int pci_msi_enable = 1;
-static int last_alloc_vector;
-static int nr_released_vectors;
-static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
-static int nr_msix_devices;
-
-#ifndef CONFIG_X86_IO_APIC
-int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
-#endif
-
-static struct msi_ops *msi_ops;
-
-int
-msi_register(struct msi_ops *ops)
-{
- msi_ops = ops;
- return 0;
-}
-
-static void msi_cache_ctor(void *p, kmem_cache_t *cache, unsigned long flags)
-{
- memset(p, 0, sizeof(struct msi_desc));
-}
static int msi_cache_init(void)
{
- msi_cachep = kmem_cache_create("msi_cache",
- sizeof(struct msi_desc),
- 0, SLAB_HWCACHE_ALIGN, msi_cache_ctor, NULL);
+ msi_cachep = kmem_cache_create("msi_cache", sizeof(struct msi_desc),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
if (!msi_cachep)
return -ENOMEM;
return 0;
}
-static void msi_set_mask_bit(unsigned int vector, int flag)
+static void msi_set_mask_bit(unsigned int irq, int flag)
{
struct msi_desc *entry;
- entry = (struct msi_desc *)msi_desc[vector];
- if (!entry || !entry->dev || !entry->mask_base)
- return;
+ entry = msi_desc[irq];
+ BUG_ON(!entry || !entry->dev);
switch (entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
- {
- int pos;
- u32 mask_bits;
-
- pos = (long)entry->mask_base;
- pci_read_config_dword(entry->dev, pos, &mask_bits);
- mask_bits &= ~(1);
- mask_bits |= flag;
- pci_write_config_dword(entry->dev, pos, mask_bits);
+ if (entry->msi_attrib.maskbit) {
+ int pos;
+ u32 mask_bits;
+
+ pos = (long)entry->mask_base;
+ pci_read_config_dword(entry->dev, pos, &mask_bits);
+ mask_bits &= ~(1);
+ mask_bits |= flag;
+ pci_write_config_dword(entry->dev, pos, mask_bits);
+ }
break;
- }
case PCI_CAP_ID_MSIX:
{
int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -89,261 +67,101 @@ static void msi_set_mask_bit(unsigned int vector, int flag)
break;
}
default:
+ BUG();
break;
}
}
-#ifdef CONFIG_SMP
-static void set_msi_affinity(unsigned int vector, cpumask_t cpu_mask)
+void read_msi_msg(unsigned int irq, struct msi_msg *msg)
{
- struct msi_desc *entry;
- u32 address_hi, address_lo;
- unsigned int irq = vector;
- unsigned int dest_cpu = first_cpu(cpu_mask);
-
- entry = (struct msi_desc *)msi_desc[vector];
- if (!entry || !entry->dev)
- return;
-
- switch (entry->msi_attrib.type) {
+ struct msi_desc *entry = get_irq_data(irq);
+ switch(entry->msi_attrib.type) {
case PCI_CAP_ID_MSI:
{
- int pos = pci_find_capability(entry->dev, PCI_CAP_ID_MSI);
-
- if (!pos)
- return;
-
- pci_read_config_dword(entry->dev, msi_upper_address_reg(pos),
- &address_hi);
- pci_read_config_dword(entry->dev, msi_lower_address_reg(pos),
- &address_lo);
-
- msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
-
- pci_write_config_dword(entry->dev, msi_upper_address_reg(pos),
- address_hi);
- pci_write_config_dword(entry->dev, msi_lower_address_reg(pos),
- address_lo);
- set_native_irq_info(irq, cpu_mask);
+ struct pci_dev *dev = entry->dev;
+ int pos = entry->msi_attrib.pos;
+ u16 data;
+
+ pci_read_config_dword(dev, msi_lower_address_reg(pos),
+ &msg->address_lo);
+ if (entry->msi_attrib.is_64) {
+ pci_read_config_dword(dev, msi_upper_address_reg(pos),
+ &msg->address_hi);
+ pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ } else {
+ msg->address_hi = 0;
+ pci_read_config_word(dev, msi_data_reg(pos, 1), &data);
+ }
+ msg->data = data;
break;
}
case PCI_CAP_ID_MSIX:
{
- int offset_hi =
- entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET;
- int offset_lo =
- entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET;
-
- address_hi = readl(entry->mask_base + offset_hi);
- address_lo = readl(entry->mask_base + offset_lo);
+ void __iomem *base;
+ base = entry->mask_base +
+ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
- msi_ops->target(vector, dest_cpu, &address_hi, &address_lo);
+ msg->address_lo = readl(base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+ msg->address_hi = readl(base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+ msg->data = readl(base + PCI_MSIX_ENTRY_DATA_OFFSET);
+ break;
+ }
+ default:
+ BUG();
+ }
+}
- writel(address_hi, entry->mask_base + offset_hi);
- writel(address_lo, entry->mask_base + offset_lo);
- set_native_irq_info(irq, cpu_mask);
+void write_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+ struct msi_desc *entry = get_irq_data(irq);
+ switch (entry->msi_attrib.type) {
+ case PCI_CAP_ID_MSI:
+ {
+ struct pci_dev *dev = entry->dev;
+ int pos = entry->msi_attrib.pos;
+
+ pci_write_config_dword(dev, msi_lower_address_reg(pos),
+ msg->address_lo);
+ if (entry->msi_attrib.is_64) {
+ pci_write_config_dword(dev, msi_upper_address_reg(pos),
+ msg->address_hi);
+ pci_write_config_word(dev, msi_data_reg(pos, 1),
+ msg->data);
+ } else {
+ pci_write_config_word(dev, msi_data_reg(pos, 0),
+ msg->data);
+ }
break;
}
- default:
+ case PCI_CAP_ID_MSIX:
+ {
+ void __iomem *base;
+ base = entry->mask_base +
+ entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE;
+
+ writel(msg->address_lo,
+ base + PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
+ writel(msg->address_hi,
+ base + PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
+ writel(msg->data, base + PCI_MSIX_ENTRY_DATA_OFFSET);
break;
}
-}
-#else
-#define set_msi_affinity NULL
-#endif /* CONFIG_SMP */
-
-static void mask_MSI_irq(unsigned int vector)
-{
- msi_set_mask_bit(vector, 1);
-}
-
-static void unmask_MSI_irq(unsigned int vector)
-{
- msi_set_mask_bit(vector, 0);
-}
-
-static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
-{
- struct msi_desc *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[vector];
- if (!entry || !entry->dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
- return 0;
+ default:
+ BUG();
}
- entry->msi_attrib.state = 1; /* Mark it active */
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return 0; /* never anything pending */
-}
-
-static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
-{
- startup_msi_irq_wo_maskbit(vector);
- unmask_MSI_irq(vector);
- return 0; /* never anything pending */
-}
-
-static void shutdown_msi_irq(unsigned int vector)
-{
- struct msi_desc *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[vector];
- if (entry && entry->dev)
- entry->msi_attrib.state = 0; /* Mark it not active */
- spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static void end_msi_irq_wo_maskbit(unsigned int vector)
-{
- move_native_irq(vector);
- ack_APIC_irq();
}
-static void end_msi_irq_w_maskbit(unsigned int vector)
+void mask_msi_irq(unsigned int irq)
{
- move_native_irq(vector);
- unmask_MSI_irq(vector);
- ack_APIC_irq();
+ msi_set_mask_bit(irq, 1);
}
-static void do_nothing(unsigned int vector)
+void unmask_msi_irq(unsigned int irq)
{
+ msi_set_mask_bit(irq, 0);
}
-/*
- * Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI-X Capability Structure.
- */
-static struct hw_interrupt_type msix_irq_type = {
- .typename = "PCI-MSI-X",
- .startup = startup_msi_irq_w_maskbit,
- .shutdown = shutdown_msi_irq,
- .enable = unmask_MSI_irq,
- .disable = mask_MSI_irq,
- .ack = mask_MSI_irq,
- .end = end_msi_irq_w_maskbit,
- .set_affinity = set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure with
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_w_maskbit_type = {
- .typename = "PCI-MSI",
- .startup = startup_msi_irq_w_maskbit,
- .shutdown = shutdown_msi_irq,
- .enable = unmask_MSI_irq,
- .disable = mask_MSI_irq,
- .ack = mask_MSI_irq,
- .end = end_msi_irq_w_maskbit,
- .set_affinity = set_msi_affinity
-};
-
-/*
- * Interrupt Type for MSI PCI/PCI-X/PCI-Express Devices,
- * which implement the MSI Capability Structure without
- * Mask-and-Pending Bits.
- */
-static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
- .typename = "PCI-MSI",
- .startup = startup_msi_irq_wo_maskbit,
- .shutdown = shutdown_msi_irq,
- .enable = do_nothing,
- .disable = do_nothing,
- .ack = do_nothing,
- .end = end_msi_irq_wo_maskbit,
- .set_affinity = set_msi_affinity
-};
-
-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign);
-static int assign_msi_vector(void)
-{
- static int new_vector_avail = 1;
- int vector;
- unsigned long flags;
-
- /*
- * msi_lock is provided to ensure that successful allocation of MSI
- * vector is assigned unique among drivers.
- */
- spin_lock_irqsave(&msi_lock, flags);
-
- if (!new_vector_avail) {
- int free_vector = 0;
-
- /*
- * vector_irq[] = -1 indicates that this specific vector is:
- * - assigned for MSI (since MSI have no associated IRQ) or
- * - assigned for legacy if less than 16, or
- * - having no corresponding 1:1 vector-to-IOxAPIC IRQ mapping
- * vector_irq[] = 0 indicates that this vector, previously
- * assigned for MSI, is freed by hotplug removed operations.
- * This vector will be reused for any subsequent hotplug added
- * operations.
- * vector_irq[] > 0 indicates that this vector is assigned for
- * IOxAPIC IRQs. This vector and its value provides a 1-to-1
- * vector-to-IOxAPIC IRQ mapping.
- */
- for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
- if (vector_irq[vector] != 0)
- continue;
- free_vector = vector;
- if (!msi_desc[vector])
- break;
- else
- continue;
- }
- if (!free_vector) {
- spin_unlock_irqrestore(&msi_lock, flags);
- return -EBUSY;
- }
- vector_irq[free_vector] = -1;
- nr_released_vectors--;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (msi_desc[free_vector] != NULL) {
- struct pci_dev *dev;
- int tail;
-
- /* free all linked vectors before re-assign */
- do {
- spin_lock_irqsave(&msi_lock, flags);
- dev = msi_desc[free_vector]->dev;
- tail = msi_desc[free_vector]->link.tail;
- spin_unlock_irqrestore(&msi_lock, flags);
- msi_free_vector(dev, tail, 1);
- } while (free_vector != tail);
- }
-
- return free_vector;
- }
- vector = assign_irq_vector(AUTO_ASSIGN);
- last_alloc_vector = vector;
- if (vector == LAST_DEVICE_VECTOR)
- new_vector_avail = 0;
-
- spin_unlock_irqrestore(&msi_lock, flags);
- return vector;
-}
-
-static int get_new_vector(void)
-{
- int vector = assign_msi_vector();
-
- if (vector > 0)
- set_intr_gate(vector, interrupt[vector]);
-
- return vector;
-}
-
+static int msi_free_irq(struct pci_dev* dev, int irq);
static int msi_init(void)
{
static int status = -ENOMEM;
@@ -358,22 +176,6 @@ static int msi_init(void)
return status;
}
- status = msi_arch_init();
- if (status < 0) {
- pci_msi_enable = 0;
- printk(KERN_WARNING
- "PCI: MSI arch init failed. MSI disabled.\n");
- return status;
- }
-
- if (! msi_ops) {
- printk(KERN_WARNING
- "PCI: MSI ops not registered. MSI disabled.\n");
- status = -EINVAL;
- return status;
- }
-
- last_alloc_vector = assign_irq_vector(AUTO_ASSIGN);
status = msi_cache_init();
if (status < 0) {
pci_msi_enable = 0;
@@ -381,61 +183,61 @@ static int msi_init(void)
return status;
}
- if (last_alloc_vector < 0) {
- pci_msi_enable = 0;
- printk(KERN_WARNING "PCI: No interrupt vectors available for MSI\n");
- status = -EBUSY;
- return status;
- }
- vector_irq[last_alloc_vector] = 0;
- nr_released_vectors++;
-
return status;
}
-static int get_msi_vector(struct pci_dev *dev)
-{
- return get_new_vector();
-}
-
static struct msi_desc* alloc_msi_entry(void)
{
struct msi_desc *entry;
- entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
+ entry = kmem_cache_zalloc(msi_cachep, GFP_KERNEL);
if (!entry)
return NULL;
- memset(entry, 0, sizeof(struct msi_desc));
entry->link.tail = entry->link.head = 0; /* single message */
entry->dev = NULL;
return entry;
}
-static void attach_msi_entry(struct msi_desc *entry, int vector)
+static void attach_msi_entry(struct msi_desc *entry, int irq)
{
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
- msi_desc[vector] = entry;
+ msi_desc[irq] = entry;
spin_unlock_irqrestore(&msi_lock, flags);
}
-static void irq_handler_init(int cap_id, int pos, int mask)
+static int create_msi_irq(void)
{
- unsigned long flags;
+ struct msi_desc *entry;
+ int irq;
- spin_lock_irqsave(&irq_desc[pos].lock, flags);
- if (cap_id == PCI_CAP_ID_MSIX)
- irq_desc[pos].chip = &msix_irq_type;
- else {
- if (!mask)
- irq_desc[pos].chip = &msi_irq_wo_maskbit_type;
- else
- irq_desc[pos].chip = &msi_irq_w_maskbit_type;
+ entry = alloc_msi_entry();
+ if (!entry)
+ return -ENOMEM;
+
+ irq = create_irq();
+ if (irq < 0) {
+ kmem_cache_free(msi_cachep, entry);
+ return -EBUSY;
}
- spin_unlock_irqrestore(&irq_desc[pos].lock, flags);
+
+ set_irq_data(irq, entry);
+
+ return irq;
+}
+
+static void destroy_msi_irq(unsigned int irq)
+{
+ struct msi_desc *entry;
+
+ entry = get_irq_data(irq);
+ set_irq_chip(irq, NULL);
+ set_irq_data(irq, NULL);
+ destroy_irq(irq);
+ kmem_cache_free(msi_cachep, entry);
}
static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
@@ -480,21 +282,21 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
}
}
-static int msi_lookup_vector(struct pci_dev *dev, int type)
+static int msi_lookup_irq(struct pci_dev *dev, int type)
{
- int vector;
+ int irq;
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
- for (vector = FIRST_DEVICE_VECTOR; vector < NR_IRQS; vector++) {
- if (!msi_desc[vector] || msi_desc[vector]->dev != dev ||
- msi_desc[vector]->msi_attrib.type != type ||
- msi_desc[vector]->msi_attrib.default_vector != dev->irq)
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
+ msi_desc[irq]->msi_attrib.type != type ||
+ msi_desc[irq]->msi_attrib.default_irq != dev->irq)
continue;
spin_unlock_irqrestore(&msi_lock, flags);
- /* This pre-assigned MSI vector for this device
- already exits. Override dev->irq with this vector */
- dev->irq = vector;
+ /* This pre-assigned MSI irq for this device
+ already exits. Override dev->irq with this irq */
+ dev->irq = irq;
return 0;
}
spin_unlock_irqrestore(&msi_lock, flags);
@@ -506,11 +308,6 @@ void pci_scan_msi_device(struct pci_dev *dev)
{
if (!dev)
return;
-
- if (pci_find_capability(dev, PCI_CAP_ID_MSIX) > 0)
- nr_msix_devices++;
- else if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0)
- nr_reserved_vectors++;
}
#ifdef CONFIG_PM
@@ -584,7 +381,7 @@ int pci_save_msix_state(struct pci_dev *dev)
{
int pos;
int temp;
- int vector, head, tail = 0;
+ int irq, head, tail = 0;
u16 control;
struct pci_cap_saved_state *save_state;
@@ -606,33 +403,20 @@ int pci_save_msix_state(struct pci_dev *dev)
/* save the table */
temp = dev->irq;
- if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+ if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
kfree(save_state);
return -EINVAL;
}
- vector = head = dev->irq;
+ irq = head = dev->irq;
while (head != tail) {
- int j;
- void __iomem *base;
struct msi_desc *entry;
- entry = msi_desc[vector];
- base = entry->mask_base;
- j = entry->msi_attrib.entry_nr;
-
- entry->address_lo_save =
- readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- entry->address_hi_save =
- readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- entry->data_save =
- readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
-
- tail = msi_desc[vector]->link.tail;
- vector = tail;
+ entry = msi_desc[irq];
+ read_msi_msg(irq, &entry->msg_save);
+
+ tail = msi_desc[irq]->link.tail;
+ irq = tail;
}
dev->irq = temp;
@@ -645,9 +429,7 @@ void pci_restore_msix_state(struct pci_dev *dev)
{
u16 save;
int pos;
- int vector, head, tail = 0;
- void __iomem *base;
- int j;
+ int irq, head, tail = 0;
struct msi_desc *entry;
int temp;
struct pci_cap_saved_state *save_state;
@@ -665,26 +447,15 @@ void pci_restore_msix_state(struct pci_dev *dev)
/* route the table */
temp = dev->irq;
- if (msi_lookup_vector(dev, PCI_CAP_ID_MSIX))
+ if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
return;
- vector = head = dev->irq;
+ irq = head = dev->irq;
while (head != tail) {
- entry = msi_desc[vector];
- base = entry->mask_base;
- j = entry->msi_attrib.entry_nr;
-
- writel(entry->address_lo_save,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel(entry->address_hi_save,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel(entry->data_save,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
-
- tail = msi_desc[vector]->link.tail;
- vector = tail;
+ entry = msi_desc[irq];
+ write_msi_msg(irq, &entry->msg_save);
+
+ tail = msi_desc[irq]->link.tail;
+ irq = tail;
}
dev->irq = temp;
@@ -693,104 +464,68 @@ void pci_restore_msix_state(struct pci_dev *dev)
}
#endif
-static int msi_register_init(struct pci_dev *dev, struct msi_desc *entry)
-{
- int status;
- u32 address_hi;
- u32 address_lo;
- u32 data;
- int pos, vector = dev->irq;
- u16 control;
-
- pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- pci_read_config_word(dev, msi_control_reg(pos), &control);
-
- /* Configure MSI capability structure */
- status = msi_ops->setup(dev, vector, &address_hi, &address_lo, &data);
- if (status < 0)
- return status;
-
- pci_write_config_dword(dev, msi_lower_address_reg(pos), address_lo);
- if (is_64bit_address(control)) {
- pci_write_config_dword(dev,
- msi_upper_address_reg(pos), address_hi);
- pci_write_config_word(dev,
- msi_data_reg(pos, 1), data);
- } else
- pci_write_config_word(dev,
- msi_data_reg(pos, 0), data);
- if (entry->msi_attrib.maskbit) {
- unsigned int maskbits, temp;
- /* All MSIs are unmasked by default, Mask them all */
- pci_read_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
- &maskbits);
- temp = (1 << multi_msi_capable(control));
- temp = ((temp - 1) & ~temp);
- maskbits |= temp;
- pci_write_config_dword(dev,
- msi_mask_bits_reg(pos, is_64bit_address(control)),
- maskbits);
- }
-
- return 0;
-}
-
/**
* msi_capability_init - configure device's MSI capability structure
* @dev: pointer to the pci_dev data structure of MSI device function
*
* Setup the MSI capability structure of device function with a single
- * MSI vector, regardless of device function is capable of handling
+ * MSI irq, regardless of device function is capable of handling
* multiple messages. A return of zero indicates the successful setup
- * of an entry zero with the new MSI vector or non-zero for otherwise.
+ * of an entry zero with the new MSI irq or non-zero for otherwise.
**/
static int msi_capability_init(struct pci_dev *dev)
{
int status;
struct msi_desc *entry;
- int pos, vector;
+ int pos, irq;
u16 control;
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
pci_read_config_word(dev, msi_control_reg(pos), &control);
/* MSI Entry Initialization */
- entry = alloc_msi_entry();
- if (!entry)
- return -ENOMEM;
+ irq = create_msi_irq();
+ if (irq < 0)
+ return irq;
- vector = get_msi_vector(dev);
- if (vector < 0) {
- kmem_cache_free(msi_cachep, entry);
- return -EBUSY;
- }
- entry->link.head = vector;
- entry->link.tail = vector;
+ entry = get_irq_data(irq);
+ entry->link.head = irq;
+ entry->link.tail = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSI;
- entry->msi_attrib.state = 0; /* Mark it not active */
+ entry->msi_attrib.is_64 = is_64bit_address(control);
entry->msi_attrib.entry_nr = 0;
entry->msi_attrib.maskbit = is_mask_bit_support(control);
- entry->msi_attrib.default_vector = dev->irq; /* Save IOAPIC IRQ */
- dev->irq = vector;
- entry->dev = dev;
+ entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
+ entry->msi_attrib.pos = pos;
if (is_mask_bit_support(control)) {
entry->mask_base = (void __iomem *)(long)msi_mask_bits_reg(pos,
is_64bit_address(control));
}
- /* Replace with MSI handler */
- irq_handler_init(PCI_CAP_ID_MSI, vector, entry->msi_attrib.maskbit);
+ entry->dev = dev;
+ if (entry->msi_attrib.maskbit) {
+ unsigned int maskbits, temp;
+ /* All MSIs are unmasked by default, Mask them all */
+ pci_read_config_dword(dev,
+ msi_mask_bits_reg(pos, is_64bit_address(control)),
+ &maskbits);
+ temp = (1 << multi_msi_capable(control));
+ temp = ((temp - 1) & ~temp);
+ maskbits |= temp;
+ pci_write_config_dword(dev,
+ msi_mask_bits_reg(pos, is_64bit_address(control)),
+ maskbits);
+ }
/* Configure MSI capability structure */
- status = msi_register_init(dev, entry);
- if (status != 0) {
- dev->irq = entry->msi_attrib.default_vector;
- kmem_cache_free(msi_cachep, entry);
+ status = arch_setup_msi_irq(irq, dev);
+ if (status < 0) {
+ destroy_msi_irq(irq);
return status;
}
- attach_msi_entry(entry, vector);
+ attach_msi_entry(entry, irq);
/* Set MSI enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+ dev->irq = irq;
return 0;
}
@@ -801,18 +536,15 @@ static int msi_capability_init(struct pci_dev *dev)
* @nvec: number of @entries
*
* Setup the MSI-X capability structure of device function with a
- * single MSI-X vector. A return of zero indicates the successful setup of
- * requested MSI-X entries with allocated vectors or non-zero for otherwise.
+ * single MSI-X irq. A return of zero indicates the successful setup of
+ * requested MSI-X entries with allocated irqs or non-zero for otherwise.
**/
static int msix_capability_init(struct pci_dev *dev,
struct msix_entry *entries, int nvec)
{
struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
- u32 address_hi;
- u32 address_lo;
- u32 data;
int status;
- int vector, pos, i, j, nr_entries, temp = 0;
+ int irq, pos, i, j, nr_entries, temp = 0;
unsigned long phys_addr;
u32 table_offset;
u16 control;
@@ -834,65 +566,56 @@ static int msix_capability_init(struct pci_dev *dev,
/* MSI-X Table Initialization */
for (i = 0; i < nvec; i++) {
- entry = alloc_msi_entry();
- if (!entry)
- break;
- vector = get_msi_vector(dev);
- if (vector < 0) {
- kmem_cache_free(msi_cachep, entry);
+ irq = create_msi_irq();
+ if (irq < 0)
break;
- }
+ entry = get_irq_data(irq);
j = entries[i].entry;
- entries[i].vector = vector;
+ entries[i].vector = irq;
entry->msi_attrib.type = PCI_CAP_ID_MSIX;
- entry->msi_attrib.state = 0; /* Mark it not active */
+ entry->msi_attrib.is_64 = 1;
entry->msi_attrib.entry_nr = j;
entry->msi_attrib.maskbit = 1;
- entry->msi_attrib.default_vector = dev->irq;
+ entry->msi_attrib.default_irq = dev->irq;
+ entry->msi_attrib.pos = pos;
entry->dev = dev;
entry->mask_base = base;
if (!head) {
- entry->link.head = vector;
- entry->link.tail = vector;
+ entry->link.head = irq;
+ entry->link.tail = irq;
head = entry;
} else {
entry->link.head = temp;
entry->link.tail = tail->link.tail;
- tail->link.tail = vector;
- head->link.head = vector;
+ tail->link.tail = irq;
+ head->link.head = irq;
}
- temp = vector;
+ temp = irq;
tail = entry;
- /* Replace with MSI-X handler */
- irq_handler_init(PCI_CAP_ID_MSIX, vector, 1);
/* Configure MSI-X capability structure */
- status = msi_ops->setup(dev, vector,
- &address_hi,
- &address_lo,
- &data);
- if (status < 0)
+ status = arch_setup_msi_irq(irq, dev);
+ if (status < 0) {
+ destroy_msi_irq(irq);
break;
+ }
- writel(address_lo,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel(address_hi,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel(data,
- base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
- attach_msi_entry(entry, vector);
+ attach_msi_entry(entry, irq);
}
if (i != nvec) {
+ int avail = i - 1;
i--;
for (; i >= 0; i--) {
- vector = (entries + i)->vector;
- msi_free_vector(dev, vector, 0);
+ irq = (entries + i)->vector;
+ msi_free_irq(dev, irq);
(entries + i)->vector = 0;
}
- return -EBUSY;
+ /* If we had some success report the number of irqs
+ * we succeeded in setting up.
+ */
+ if (avail <= 0)
+ avail = -EBUSY;
+ return avail;
}
/* Set MSI-X enabled bits */
enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
@@ -901,31 +624,51 @@ static int msix_capability_init(struct pci_dev *dev,
}
/**
- * pci_enable_msi - configure device's MSI capability structure
+ * pci_msi_supported - check whether MSI may be enabled on device
* @dev: pointer to the pci_dev data structure of MSI device function
*
- * Setup the MSI capability structure of device function with
- * a single MSI vector upon its software driver call to request for
- * MSI mode enabled on its hardware device function. A return of zero
- * indicates the successful setup of an entry zero with the new MSI
- * vector or non-zero for otherwise.
+ * Look at global flags, the device itself, and its parent busses
+ * to return 0 if MSI are supported for the device.
**/
-int pci_enable_msi(struct pci_dev* dev)
+static
+int pci_msi_supported(struct pci_dev * dev)
{
struct pci_bus *bus;
- int pos, temp, status = -EINVAL;
- u16 control;
- if (!pci_msi_enable || !dev)
- return status;
-
- if (dev->no_msi)
- return status;
+ /* MSI must be globally enabled and supported by the device */
+ if (!pci_msi_enable || !dev || dev->no_msi)
+ return -EINVAL;
+ /* Any bridge which does NOT route MSI transactions from it's
+ * secondary bus to it's primary bus must set NO_MSI flag on
+ * the secondary pci_bus.
+ * We expect only arch-specific PCI host bus controller driver
+ * or quirks for specific PCI bridges to be setting NO_MSI.
+ */
for (bus = dev->bus; bus; bus = bus->parent)
if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
return -EINVAL;
+ return 0;
+}
+
+/**
+ * pci_enable_msi - configure device's MSI capability structure
+ * @dev: pointer to the pci_dev data structure of MSI device function
+ *
+ * Setup the MSI capability structure of device function with
+ * a single MSI irq upon its software driver call to request for
+ * MSI mode enabled on its hardware device function. A return of zero
+ * indicates the successful setup of an entry zero with the new MSI
+ * irq or non-zero for otherwise.
+ **/
+int pci_enable_msi(struct pci_dev* dev)
+{
+ int pos, temp, status;
+
+ if (pci_msi_supported(dev) < 0)
+ return -EINVAL;
+
temp = dev->irq;
status = msi_init();
@@ -936,52 +679,25 @@ int pci_enable_msi(struct pci_dev* dev)
if (!pos)
return -EINVAL;
- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
- /* Lookup Sucess */
- unsigned long flags;
+ WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
- pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (control & PCI_MSI_FLAGS_ENABLE)
- return 0; /* Already in MSI mode */
- spin_lock_irqsave(&msi_lock, flags);
- if (!vector_irq[dev->irq]) {
- msi_desc[dev->irq]->msi_attrib.state = 0;
- vector_irq[dev->irq] = -1;
- nr_released_vectors--;
- spin_unlock_irqrestore(&msi_lock, flags);
- status = msi_register_init(dev, msi_desc[dev->irq]);
- if (status == 0)
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
- return status;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
- dev->irq = temp;
- }
- /* Check whether driver already requested for MSI-X vectors */
+ /* Check whether driver already requested for MSI-X irqs */
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
+ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
printk(KERN_INFO "PCI: %s: Can't enable MSI. "
- "Device already has MSI-X vectors assigned\n",
+ "Device already has MSI-X irq assigned\n",
pci_name(dev));
dev->irq = temp;
return -EINVAL;
}
status = msi_capability_init(dev);
- if (!status) {
- if (!pos)
- nr_reserved_vectors--; /* Only MSI capable */
- else if (nr_msix_devices > 0)
- nr_msix_devices--; /* Both MSI and MSI-X capable,
- but choose enabling MSI */
- }
-
return status;
}
void pci_disable_msi(struct pci_dev* dev)
{
struct msi_desc *entry;
- int pos, default_vector;
+ int pos, default_irq;
u16 control;
unsigned long flags;
@@ -998,41 +714,41 @@ void pci_disable_msi(struct pci_dev* dev)
if (!(control & PCI_MSI_FLAGS_ENABLE))
return;
+ disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
+
spin_lock_irqsave(&msi_lock, flags);
entry = msi_desc[dev->irq];
if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
spin_unlock_irqrestore(&msi_lock, flags);
return;
}
- if (entry->msi_attrib.state) {
+ if (irq_has_action(dev->irq)) {
spin_unlock_irqrestore(&msi_lock, flags);
printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
- "free_irq() on MSI vector %d\n",
+ "free_irq() on MSI irq %d\n",
pci_name(dev), dev->irq);
- BUG_ON(entry->msi_attrib.state > 0);
+ BUG_ON(irq_has_action(dev->irq));
} else {
- vector_irq[dev->irq] = 0; /* free it */
- nr_released_vectors++;
- default_vector = entry->msi_attrib.default_vector;
+ default_irq = entry->msi_attrib.default_irq;
spin_unlock_irqrestore(&msi_lock, flags);
- /* Restore dev->irq to its default pin-assertion vector */
- dev->irq = default_vector;
- disable_msi_mode(dev, pci_find_capability(dev, PCI_CAP_ID_MSI),
- PCI_CAP_ID_MSI);
+ msi_free_irq(dev, dev->irq);
+
+ /* Restore dev->irq to its default pin-assertion irq */
+ dev->irq = default_irq;
}
}
-static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
+static int msi_free_irq(struct pci_dev* dev, int irq)
{
struct msi_desc *entry;
int head, entry_nr, type;
void __iomem *base;
unsigned long flags;
- msi_ops->teardown(vector);
+ arch_teardown_msi_irq(irq);
spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[vector];
+ entry = msi_desc[irq];
if (!entry || entry->dev != dev) {
spin_unlock_irqrestore(&msi_lock, flags);
return -EINVAL;
@@ -1044,112 +760,46 @@ static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
msi_desc[entry->link.head]->link.tail = entry->link.tail;
msi_desc[entry->link.tail]->link.head = entry->link.head;
entry->dev = NULL;
- if (!reassign) {
- vector_irq[vector] = 0;
- nr_released_vectors++;
- }
- msi_desc[vector] = NULL;
+ msi_desc[irq] = NULL;
spin_unlock_irqrestore(&msi_lock, flags);
- kmem_cache_free(msi_cachep, entry);
+ destroy_msi_irq(irq);
if (type == PCI_CAP_ID_MSIX) {
- if (!reassign)
- writel(1, base +
- entry_nr * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
+ writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
+ PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
- if (head == vector)
+ if (head == irq)
iounmap(base);
}
return 0;
}
-static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
-{
- int vector = head, tail = 0;
- int i, j = 0, nr_entries = 0;
- void __iomem *base;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- while (head != tail) {
- nr_entries++;
- tail = msi_desc[vector]->link.tail;
- if (entries[0].entry == msi_desc[vector]->msi_attrib.entry_nr)
- j = vector;
- vector = tail;
- }
- if (*nvec > nr_entries) {
- spin_unlock_irqrestore(&msi_lock, flags);
- *nvec = nr_entries;
- return -EINVAL;
- }
- vector = ((j > 0) ? j : head);
- for (i = 0; i < *nvec; i++) {
- j = msi_desc[vector]->msi_attrib.entry_nr;
- msi_desc[vector]->msi_attrib.state = 0; /* Mark it not active */
- vector_irq[vector] = -1; /* Mark it busy */
- nr_released_vectors--;
- entries[i].vector = vector;
- if (j != (entries + i)->entry) {
- base = msi_desc[vector]->mask_base;
- msi_desc[vector]->msi_attrib.entry_nr =
- (entries + i)->entry;
- writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET), base +
- (entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET);
- writel( readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET), base +
- (entries + i)->entry * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET);
- writel( (readl(base + j * PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET) & 0xff00) | vector,
- base + (entries+i)->entry*PCI_MSIX_ENTRY_SIZE +
- PCI_MSIX_ENTRY_DATA_OFFSET);
- }
- vector = msi_desc[vector]->link.tail;
- }
- spin_unlock_irqrestore(&msi_lock, flags);
-
- return 0;
-}
-
/**
* pci_enable_msix - configure device's MSI-X capability structure
* @dev: pointer to the pci_dev data structure of MSI-X device function
* @entries: pointer to an array of MSI-X entries
- * @nvec: number of MSI-X vectors requested for allocation by device driver
+ * @nvec: number of MSI-X irqs requested for allocation by device driver
*
* Setup the MSI-X capability structure of device function with the number
- * of requested vectors upon its software driver call to request for
+ * of requested irqs upon its software driver call to request for
* MSI-X mode enabled on its hardware device function. A return of zero
* indicates the successful configuration of MSI-X capability structure
- * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
+ * with new allocated MSI-X irqs. A return of < 0 indicates a failure.
* Or a return of > 0 indicates that driver request is exceeding the number
- * of vectors available. Driver should use the returned value to re-send
+ * of irqs available. Driver should use the returned value to re-send
* its request.
**/
int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
{
- struct pci_bus *bus;
- int status, pos, nr_entries, free_vectors;
+ int status, pos, nr_entries;
int i, j, temp;
u16 control;
- unsigned long flags;
- if (!pci_msi_enable || !dev || !entries)
+ if (!entries || pci_msi_supported(dev) < 0)
return -EINVAL;
- if (dev->no_msi)
- return -EINVAL;
-
- for (bus = dev->bus; bus; bus = bus->parent)
- if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
- return -EINVAL;
-
status = msi_init();
if (status < 0)
return status;
@@ -1159,9 +809,6 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
return -EINVAL;
pci_read_config_word(dev, msi_control_reg(pos), &control);
- if (control & PCI_MSIX_FLAGS_ENABLE)
- return -EINVAL; /* Already in MSI-X mode */
-
nr_entries = multi_msix_capable(control);
if (nvec > nr_entries)
return -EINVAL;
@@ -1176,56 +823,18 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
}
}
temp = dev->irq;
- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
- /* Lookup Sucess */
- nr_entries = nvec;
- /* Reroute MSI-X table */
- if (reroute_msix_table(dev->irq, entries, &nr_entries)) {
- /* #requested > #previous-assigned */
- dev->irq = temp;
- return nr_entries;
- }
- dev->irq = temp;
- enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
- return 0;
- }
- /* Check whether driver already requested for MSI vector */
+ WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+
+ /* Check whether driver already requested for MSI irq */
if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
- !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
+ !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
- "Device already has an MSI vector assigned\n",
+ "Device already has an MSI irq assigned\n",
pci_name(dev));
dev->irq = temp;
return -EINVAL;
}
-
- spin_lock_irqsave(&msi_lock, flags);
- /*
- * msi_lock is provided to ensure that enough vectors resources are
- * available before granting.
- */
- free_vectors = pci_vector_resources(last_alloc_vector,
- nr_released_vectors);
- /* Ensure that each MSI/MSI-X device has one vector reserved by
- default to avoid any MSI-X driver to take all available
- resources */
- free_vectors -= nr_reserved_vectors;
- /* Find the average of free vectors among MSI-X devices */
- if (nr_msix_devices > 0)
- free_vectors /= nr_msix_devices;
- spin_unlock_irqrestore(&msi_lock, flags);
-
- if (nvec > free_vectors) {
- if (free_vectors > 0)
- return free_vectors;
- else
- return -EBUSY;
- }
-
status = msix_capability_init(dev, entries, nvec);
- if (!status && nr_msix_devices > 0)
- nr_msix_devices--;
-
return status;
}
@@ -1247,53 +856,47 @@ void pci_disable_msix(struct pci_dev* dev)
if (!(control & PCI_MSIX_FLAGS_ENABLE))
return;
+ disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
+
temp = dev->irq;
- if (!msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
- int state, vector, head, tail = 0, warning = 0;
+ if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ int irq, head, tail = 0, warning = 0;
unsigned long flags;
- vector = head = dev->irq;
- spin_lock_irqsave(&msi_lock, flags);
+ irq = head = dev->irq;
+ dev->irq = temp; /* Restore pin IRQ */
while (head != tail) {
- state = msi_desc[vector]->msi_attrib.state;
- if (state)
+ spin_lock_irqsave(&msi_lock, flags);
+ tail = msi_desc[irq]->link.tail;
+ spin_unlock_irqrestore(&msi_lock, flags);
+ if (irq_has_action(irq))
warning = 1;
- else {
- vector_irq[vector] = 0; /* free it */
- nr_released_vectors++;
- }
- tail = msi_desc[vector]->link.tail;
- vector = tail;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
}
- spin_unlock_irqrestore(&msi_lock, flags);
+ msi_free_irq(dev, irq);
if (warning) {
- dev->irq = temp;
printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
- "free_irq() on all MSI-X vectors\n",
+ "free_irq() on all MSI-X irqs\n",
pci_name(dev));
BUG_ON(warning > 0);
- } else {
- dev->irq = temp;
- disable_msi_mode(dev,
- pci_find_capability(dev, PCI_CAP_ID_MSIX),
- PCI_CAP_ID_MSIX);
-
}
}
}
/**
- * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
+ * msi_remove_pci_irq_vectors - reclaim MSI(X) irqs to unused state
* @dev: pointer to the pci_dev data structure of MSI(X) device function
*
* Being called during hotplug remove, from which the device function
- * is hot-removed. All previous assigned MSI/MSI-X vectors, if
+ * is hot-removed. All previous assigned MSI/MSI-X irqs, if
* allocated for this device function, are reclaimed to unused state,
* which may be used later on.
**/
void msi_remove_pci_irq_vectors(struct pci_dev* dev)
{
- int state, pos, temp;
+ int pos, temp;
unsigned long flags;
if (!pci_msi_enable || !dev)
@@ -1301,42 +904,38 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
temp = dev->irq; /* Save IOAPIC IRQ */
pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSI)) {
- spin_lock_irqsave(&msi_lock, flags);
- state = msi_desc[dev->irq]->msi_attrib.state;
- spin_unlock_irqrestore(&msi_lock, flags);
- if (state) {
+ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+ if (irq_has_action(dev->irq)) {
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on MSI vector %d\n",
+ "called without free_irq() on MSI irq %d\n",
pci_name(dev), dev->irq);
- BUG_ON(state > 0);
- } else /* Release MSI vector assigned to this device */
- msi_free_vector(dev, dev->irq, 0);
+ BUG_ON(irq_has_action(dev->irq));
+ } else /* Release MSI irq assigned to this device */
+ msi_free_irq(dev, dev->irq);
dev->irq = temp; /* Restore IOAPIC IRQ */
}
pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
- if (pos > 0 && !msi_lookup_vector(dev, PCI_CAP_ID_MSIX)) {
- int vector, head, tail = 0, warning = 0;
+ if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+ int irq, head, tail = 0, warning = 0;
void __iomem *base = NULL;
- vector = head = dev->irq;
+ irq = head = dev->irq;
while (head != tail) {
spin_lock_irqsave(&msi_lock, flags);
- state = msi_desc[vector]->msi_attrib.state;
- tail = msi_desc[vector]->link.tail;
- base = msi_desc[vector]->mask_base;
+ tail = msi_desc[irq]->link.tail;
+ base = msi_desc[irq]->mask_base;
spin_unlock_irqrestore(&msi_lock, flags);
- if (state)
+ if (irq_has_action(irq))
warning = 1;
- else if (vector != head) /* Release MSI-X vector */
- msi_free_vector(dev, vector, 0);
- vector = tail;
+ else if (irq != head) /* Release MSI-X irq */
+ msi_free_irq(dev, irq);
+ irq = tail;
}
- msi_free_vector(dev, vector, 0);
+ msi_free_irq(dev, irq);
if (warning) {
iounmap(base);
printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
- "called without free_irq() on all MSI-X vectors\n",
+ "called without free_irq() on all MSI-X irqs\n",
pci_name(dev));
BUG_ON(warning > 0);
}
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index 56951c39d3a3..f0cca1772f9c 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -7,84 +7,6 @@
#define MSI_H
/*
- * MSI operation vector. Used by the msi core code (drivers/pci/msi.c)
- * to abstract platform-specific tasks relating to MSI address generation
- * and resource management.
- */
-struct msi_ops {
- /**
- * setup - generate an MSI bus address and data for a given vector
- * @pdev: PCI device context (in)
- * @vector: vector allocated by the msi core (in)
- * @addr_hi: upper 32 bits of PCI bus MSI address (out)
- * @addr_lo: lower 32 bits of PCI bus MSI address (out)
- * @data: MSI data payload (out)
- *
- * Description: The setup op is used to generate a PCI bus addres and
- * data which the msi core will program into the card MSI capability
- * registers. The setup routine is responsible for picking an initial
- * cpu to target the MSI at. The setup routine is responsible for
- * examining pdev to determine the MSI capabilities of the card and
- * generating a suitable address/data. The setup routine is
- * responsible for allocating and tracking any system resources it
- * needs to route the MSI to the cpu it picks, and for associating
- * those resources with the passed in vector.
- *
- * Returns 0 if the MSI address/data was successfully setup.
- **/
-
- int (*setup) (struct pci_dev *pdev, unsigned int vector,
- u32 *addr_hi, u32 *addr_lo, u32 *data);
-
- /**
- * teardown - release resources allocated by setup
- * @vector: vector context for resources (in)
- *
- * Description: The teardown op is used to release any resources
- * that were allocated in the setup routine associated with the passed
- * in vector.
- **/
-
- void (*teardown) (unsigned int vector);
-
- /**
- * target - retarget an MSI at a different cpu
- * @vector: vector context for resources (in)
- * @cpu: new cpu to direct vector at (in)
- * @addr_hi: new value of PCI bus upper 32 bits (in/out)
- * @addr_lo: new value of PCI bus lower 32 bits (in/out)
- *
- * Description: The target op is used to redirect an MSI vector
- * at a different cpu. addr_hi/addr_lo coming in are the existing
- * values that the MSI core has programmed into the card. The
- * target code is responsible for freeing any resources (if any)
- * associated with the old address, and generating a new PCI bus
- * addr_hi/addr_lo that will redirect the vector at the indicated cpu.
- **/
-
- void (*target) (unsigned int vector, unsigned int cpu,
- u32 *addr_hi, u32 *addr_lo);
-};
-
-extern int msi_register(struct msi_ops *ops);
-
-#include <asm/msi.h>
-
-/*
- * Assume the maximum number of hot plug slots supported by the system is about
- * ten. The worstcase is that each of these slots is hot-added with a device,
- * which has two MSI/MSI-X capable functions. To avoid any MSI-X driver, which
- * attempts to request all available vectors, NR_HP_RESERVED_VECTORS is defined
- * as below to ensure at least one message is assigned to each detected MSI/
- * MSI-X device function.
- */
-#define NR_HP_RESERVED_VECTORS 20
-
-extern int vector_irq[NR_VECTORS];
-extern void (*interrupt[NR_IRQS])(void);
-extern int pci_vector_resources(int last, int nr_released);
-
-/*
* MSI-X Address Register
*/
#define PCI_MSIX_FLAGS_QSIZE 0x7FF
@@ -110,8 +32,8 @@ extern int pci_vector_resources(int last, int nr_released);
(1 << ((control & PCI_MSI_FLAGS_QMASK) >> 1))
#define multi_msi_enable(control, num) \
control |= (((num >> 1) << 4) & PCI_MSI_FLAGS_QSIZE);
-#define is_64bit_address(control) (control & PCI_MSI_FLAGS_64BIT)
-#define is_mask_bit_support(control) (control & PCI_MSI_FLAGS_MASKBIT)
+#define is_64bit_address(control) (!!(control & PCI_MSI_FLAGS_64BIT))
+#define is_mask_bit_support(control) (!!(control & PCI_MSI_FLAGS_MASKBIT))
#define msi_enable(control, num) multi_msi_enable(control, num); \
control |= PCI_MSI_FLAGS_ENABLE
@@ -125,32 +47,4 @@ extern int pci_vector_resources(int last, int nr_released);
#define msix_mask(address) (address | PCI_MSIX_FLAGS_BITMASK)
#define msix_is_pending(address) (address & PCI_MSIX_FLAGS_PENDMASK)
-struct msi_desc {
- struct {
- __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
- __u8 maskbit : 1; /* mask-pending bit supported ? */
- __u8 state : 1; /* {0: free, 1: busy} */
- __u8 reserved: 1; /* reserved */
- __u8 entry_nr; /* specific enabled entry */
- __u8 default_vector; /* default pre-assigned vector */
- __u8 unused; /* formerly unused destination cpu*/
- }msi_attrib;
-
- struct {
- __u16 head;
- __u16 tail;
- }link;
-
- void __iomem *mask_base;
- struct pci_dev *dev;
-
-#ifdef CONFIG_PM
- /* PM save area for MSIX address/data */
-
- u32 address_hi_save;
- u32 address_lo_save;
- u32 data_save;
-#endif
-};
-
#endif /* MSI_H */
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index d8ace1f90dd2..b1c0c707d96c 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -56,6 +56,7 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
subdevice=PCI_ANY_ID, class=0, class_mask=0;
unsigned long driver_data=0;
int fields=0;
+ int retval = 0;
fields = sscanf(buf, "%x %x %x %x %x %x %lux",
&vendor, &device, &subvendor, &subdevice,
@@ -82,10 +83,12 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
spin_unlock(&pdrv->dynids.lock);
if (get_driver(&pdrv->driver)) {
- driver_attach(&pdrv->driver);
+ retval = driver_attach(&pdrv->driver);
put_driver(&pdrv->driver);
}
+ if (retval)
+ return retval;
return count;
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
@@ -418,7 +421,11 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
drv->driver.bus = &pci_bus_type;
drv->driver.owner = owner;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
- drv->driver.multithread_probe = pci_multithread_probe;
+
+ if (pci_multithread_probe)
+ drv->driver.multithread_probe = pci_multithread_probe;
+ else
+ drv->driver.multithread_probe = drv->multithread_probe;
spin_lock_init(&drv->dynids.lock);
INIT_LIST_HEAD(&drv->dynids.list);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index fdefa7dcd156..a1d2e979b17f 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -117,6 +117,7 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
+ int retval = 0;
/* this can crash the machine when done on the "wrong" device */
if (!capable(CAP_SYS_ADMIN))
@@ -126,11 +127,53 @@ is_enabled_store(struct device *dev, struct device_attribute *attr,
pci_disable_device(pdev);
if (*buf == '1')
- pci_enable_device(pdev);
+ retval = pci_enable_device(pdev);
+ if (retval)
+ return retval;
return count;
}
+static ssize_t
+msi_bus_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ if (!pdev->subordinate)
+ return 0;
+
+ return sprintf (buf, "%u\n",
+ !(pdev->subordinate->bus_flags & PCI_BUS_FLAGS_NO_MSI));
+}
+
+static ssize_t
+msi_bus_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ /* bad things may happen if the no_msi flag is changed
+ * while some drivers are loaded */
+ if (!capable(CAP_SYS_ADMIN))
+ return count;
+
+ if (!pdev->subordinate)
+ return count;
+
+ if (*buf == '0') {
+ pdev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ dev_warn(&pdev->dev, "forced subordinate bus to not support MSI,"
+ " bad things could happen.\n");
+ }
+
+ if (*buf == '1') {
+ pdev->subordinate->bus_flags &= ~PCI_BUS_FLAGS_NO_MSI;
+ dev_warn(&pdev->dev, "forced subordinate bus to support MSI,"
+ " bad things could happen.\n");
+ }
+
+ return count;
+}
struct device_attribute pci_dev_attrs[] = {
__ATTR_RO(resource),
@@ -145,6 +188,7 @@ struct device_attribute pci_dev_attrs[] = {
__ATTR(enable, 0600, is_enabled_show, is_enabled_store),
__ATTR(broken_parity_status,(S_IRUGO|S_IWUSR),
broken_parity_status_show,broken_parity_status_store),
+ __ATTR(msi_bus, 0644, msi_bus_show, msi_bus_store),
__ATTR_NULL,
};
@@ -385,15 +429,38 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
}
/**
+ * pci_remove_resource_files - cleanup resource files
+ * @dev: dev to cleanup
+ *
+ * If we created resource files for @dev, remove them from sysfs and
+ * free their resources.
+ */
+static void
+pci_remove_resource_files(struct pci_dev *pdev)
+{
+ int i;
+
+ for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+ struct bin_attribute *res_attr;
+
+ res_attr = pdev->res_attr[i];
+ if (res_attr) {
+ sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
+ kfree(res_attr);
+ }
+ }
+}
+
+/**
* pci_create_resource_files - create resource files in sysfs for @dev
* @dev: dev in question
*
* Walk the resources in @dev creating files for each resource available.
*/
-static void
-pci_create_resource_files(struct pci_dev *pdev)
+static int pci_create_resource_files(struct pci_dev *pdev)
{
int i;
+ int retval;
/* Expose the PCI resources from this device as files */
for (i = 0; i < PCI_ROM_RESOURCE; i++) {
@@ -416,35 +483,19 @@ pci_create_resource_files(struct pci_dev *pdev)
res_attr->size = pci_resource_len(pdev, i);
res_attr->mmap = pci_mmap_resource;
res_attr->private = &pdev->resource[i];
- sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
- }
- }
-}
-
-/**
- * pci_remove_resource_files - cleanup resource files
- * @dev: dev to cleanup
- *
- * If we created resource files for @dev, remove them from sysfs and
- * free their resources.
- */
-static void
-pci_remove_resource_files(struct pci_dev *pdev)
-{
- int i;
-
- for (i = 0; i < PCI_ROM_RESOURCE; i++) {
- struct bin_attribute *res_attr;
-
- res_attr = pdev->res_attr[i];
- if (res_attr) {
- sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
- kfree(res_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
+ if (retval) {
+ pci_remove_resource_files(pdev);
+ return retval;
+ }
+ } else {
+ return -ENOMEM;
}
}
+ return 0;
}
#else /* !HAVE_PCI_MMAP */
-static inline void pci_create_resource_files(struct pci_dev *dev) { return; }
+static inline int pci_create_resource_files(struct pci_dev *dev) { return 0; }
static inline void pci_remove_resource_files(struct pci_dev *dev) { return; }
#endif /* HAVE_PCI_MMAP */
@@ -529,22 +580,27 @@ static struct bin_attribute pcie_config_attr = {
.write = pci_write_config,
};
-int pci_create_sysfs_dev_files (struct pci_dev *pdev)
+int __must_check pci_create_sysfs_dev_files (struct pci_dev *pdev)
{
+ struct bin_attribute *rom_attr = NULL;
+ int retval;
+
if (!sysfs_initialized)
return -EACCES;
if (pdev->cfg_size < 4096)
- sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pci_config_attr);
else
- sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+ if (retval)
+ goto err;
- pci_create_resource_files(pdev);
+ retval = pci_create_resource_files(pdev);
+ if (retval)
+ goto err_bin_file;
/* If the device has a ROM, try to expose it in sysfs. */
if (pci_resource_len(pdev, PCI_ROM_RESOURCE)) {
- struct bin_attribute *rom_attr;
-
rom_attr = kzalloc(sizeof(*rom_attr), GFP_ATOMIC);
if (rom_attr) {
pdev->rom_attr = rom_attr;
@@ -554,13 +610,28 @@ int pci_create_sysfs_dev_files (struct pci_dev *pdev)
rom_attr->attr.owner = THIS_MODULE;
rom_attr->read = pci_read_rom;
rom_attr->write = pci_write_rom;
- sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
+ retval = sysfs_create_bin_file(&pdev->dev.kobj, rom_attr);
+ if (retval)
+ goto err_rom;
+ } else {
+ retval = -ENOMEM;
+ goto err_bin_file;
}
}
/* add platform-specific attributes */
pcibios_add_platform_entries(pdev);
-
+
return 0;
+
+err_rom:
+ kfree(rom_attr);
+err_bin_file:
+ if (pdev->cfg_size < 4096)
+ sysfs_remove_bin_file(&pdev->dev.kobj, &pci_config_attr);
+ else
+ sysfs_remove_bin_file(&pdev->dev.kobj, &pcie_config_attr);
+err:
+ return retval;
}
/**
@@ -589,10 +660,14 @@ void pci_remove_sysfs_dev_files(struct pci_dev *pdev)
static int __init pci_sysfs_init(void)
{
struct pci_dev *pdev = NULL;
-
+ int retval;
+
sysfs_initialized = 1;
- for_each_pci_dev(pdev)
- pci_create_sysfs_dev_files(pdev);
+ for_each_pci_dev(pdev) {
+ retval = pci_create_sysfs_dev_files(pdev);
+ if (retval)
+ return retval;
+ }
return 0;
}
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 590f4e6f505d..a544997399b3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -445,6 +445,51 @@ pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
EXPORT_SYMBOL(pci_choose_state);
+static int pci_save_pcie_state(struct pci_dev *dev)
+{
+ int pos, i = 0;
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (pos <= 0)
+ return 0;
+
+ save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
+ if (!save_state) {
+ dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
+ return -ENOMEM;
+ }
+ cap = (u16 *)&save_state->data[0];
+
+ pci_read_config_word(dev, pos + PCI_EXP_DEVCTL, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_LNKCTL, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_SLTCTL, &cap[i++]);
+ pci_read_config_word(dev, pos + PCI_EXP_RTCTL, &cap[i++]);
+ pci_add_saved_cap(dev, save_state);
+ return 0;
+}
+
+static void pci_restore_pcie_state(struct pci_dev *dev)
+{
+ int i = 0, pos;
+ struct pci_cap_saved_state *save_state;
+ u16 *cap;
+
+ save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!save_state || pos <= 0)
+ return;
+ cap = (u16 *)&save_state->data[0];
+
+ pci_write_config_word(dev, pos + PCI_EXP_DEVCTL, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
+ pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
+ pci_remove_saved_cap(save_state);
+ kfree(save_state);
+}
+
/**
* pci_save_state - save the PCI configuration space of a device before suspending
* @dev: - PCI device that we're dealing with
@@ -460,6 +505,8 @@ pci_save_state(struct pci_dev *dev)
return i;
if ((i = pci_save_msix_state(dev)) != 0)
return i;
+ if ((i = pci_save_pcie_state(dev)) != 0)
+ return i;
return 0;
}
@@ -473,6 +520,9 @@ pci_restore_state(struct pci_dev *dev)
int i;
int val;
+ /* PCI Express register must be restored first */
+ pci_restore_pcie_state(dev);
+
/*
* The Base Address register should be programmed before the command
* register(s)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 08d58fc78ee1..6bf327db5c5e 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -42,7 +42,7 @@ extern void pci_remove_legacy_files(struct pci_bus *bus);
/* Lock for read/write access to pci device and bus lists */
extern struct rw_semaphore pci_bus_sem;
-#ifdef CONFIG_X86_IO_APIC
+#ifdef CONFIG_PCI_MSI
extern int pci_msi_quirk;
#else
#define pci_msi_quirk 0
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 1012db8b8b2c..0ad92a8ad8b1 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -34,3 +34,4 @@ config HOTPLUG_PCI_PCIE_POLL_EVENT_MODE
When in doubt, say N.
+source "drivers/pci/pcie/aer/Kconfig"
diff --git a/drivers/pci/pcie/Makefile b/drivers/pci/pcie/Makefile
index 984fa87283e3..e00fb99acf44 100644
--- a/drivers/pci/pcie/Makefile
+++ b/drivers/pci/pcie/Makefile
@@ -5,3 +5,6 @@
pcieportdrv-y := portdrv_core.o portdrv_pci.o portdrv_bus.o
obj-$(CONFIG_PCIEPORTBUS) += pcieportdrv.o
+
+# Build PCI Express AER if needed
+obj-$(CONFIG_PCIEAER) += aer/
diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
new file mode 100644
index 000000000000..3f37a60a6438
--- /dev/null
+++ b/drivers/pci/pcie/aer/Kconfig
@@ -0,0 +1,12 @@
+#
+# PCI Express Root Port Device AER Configuration
+#
+
+config PCIEAER
+ boolean "Root Port Advanced Error Reporting support"
+ depends on PCIEPORTBUS && ACPI
+ default y
+ help
+ This enables PCI Express Root Port Advanced Error Reporting
+ (AER) driver support. Error reporting messages sent to Root
+ Port will be handled by PCI Express AER driver.
diff --git a/drivers/pci/pcie/aer/Makefile b/drivers/pci/pcie/aer/Makefile
new file mode 100644
index 000000000000..15a4f40d520b
--- /dev/null
+++ b/drivers/pci/pcie/aer/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for PCI-Express Root Port Advanced Error Reporting Driver
+#
+
+obj-$(CONFIG_PCIEAER) += aerdriver.o
+
+aerdriver-objs := aerdrv_errprint.o aerdrv_core.o aerdrv.o aerdrv_acpi.o
+
diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c
new file mode 100644
index 000000000000..04c43ef529ac
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv.c
@@ -0,0 +1,345 @@
+/*
+ * drivers/pci/pcie/aer/aerdrv.c
+ *
+ * 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.
+ *
+ * This file implements the AER root port service driver. The driver will
+ * register an irq handler. When root port triggers an AER interrupt, the irq
+ * handler will collect root port status and schedule a work.
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pcieport_if.h>
+
+#include "aerdrv.h"
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_AUTHOR "tom.l.nguyen@intel.com"
+#define DRIVER_DESC "Root Port Advanced Error Reporting Driver"
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static int __devinit aer_probe (struct pcie_device *dev,
+ const struct pcie_port_service_id *id );
+static void aer_remove(struct pcie_device *dev);
+static int aer_suspend(struct pcie_device *dev, pm_message_t state)
+{return 0;}
+static int aer_resume(struct pcie_device *dev) {return 0;}
+static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
+ enum pci_channel_state error);
+static void aer_error_resume(struct pci_dev *dev);
+static pci_ers_result_t aer_root_reset(struct pci_dev *dev);
+
+/*
+ * PCI Express bus's AER Root service driver data structure
+ */
+static struct pcie_port_service_id aer_id[] = {
+ {
+ .vendor = PCI_ANY_ID,
+ .device = PCI_ANY_ID,
+ .port_type = PCIE_RC_PORT,
+ .service_type = PCIE_PORT_SERVICE_AER,
+ },
+ { /* end: all zeroes */ }
+};
+
+static struct pci_error_handlers aer_error_handlers = {
+ .error_detected = aer_error_detected,
+ .resume = aer_error_resume,
+};
+
+static struct pcie_port_service_driver aerdrv = {
+ .name = "aer",
+ .id_table = &aer_id[0],
+
+ .probe = aer_probe,
+ .remove = aer_remove,
+
+ .suspend = aer_suspend,
+ .resume = aer_resume,
+
+ .err_handler = &aer_error_handlers,
+
+ .reset_link = aer_root_reset,
+};
+
+/**
+ * aer_irq - Root Port's ISR
+ * @irq: IRQ assigned to Root Port
+ * @context: pointer to Root Port data structure
+ *
+ * Invoked when Root Port detects AER messages.
+ **/
+static irqreturn_t aer_irq(int irq, void *context)
+{
+ unsigned int status, id;
+ struct pcie_device *pdev = (struct pcie_device *)context;
+ struct aer_rpc *rpc = get_service_data(pdev);
+ int next_prod_idx;
+ unsigned long flags;
+ int pos;
+
+ pos = pci_find_aer_capability(pdev->port);
+ /*
+ * Must lock access to Root Error Status Reg, Root Error ID Reg,
+ * and Root error producer/consumer index
+ */
+ spin_lock_irqsave(&rpc->e_lock, flags);
+
+ /* Read error status */
+ pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, &status);
+ if (!(status & ROOT_ERR_STATUS_MASKS)) {
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return IRQ_NONE;
+ }
+
+ /* Read error source and clear error status */
+ pci_read_config_dword(pdev->port, pos + PCI_ERR_ROOT_COR_SRC, &id);
+ pci_write_config_dword(pdev->port, pos + PCI_ERR_ROOT_STATUS, status);
+
+ /* Store error source for later DPC handler */
+ next_prod_idx = rpc->prod_idx + 1;
+ if (next_prod_idx == AER_ERROR_SOURCES_MAX)
+ next_prod_idx = 0;
+ if (next_prod_idx == rpc->cons_idx) {
+ /*
+ * Error Storm Condition - possibly the same error occurred.
+ * Drop the error.
+ */
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return IRQ_HANDLED;
+ }
+ rpc->e_sources[rpc->prod_idx].status = status;
+ rpc->e_sources[rpc->prod_idx].id = id;
+ rpc->prod_idx = next_prod_idx;
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+
+ /* Invoke DPC handler */
+ schedule_work(&rpc->dpc_handler);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * aer_alloc_rpc - allocate Root Port data structure
+ * @dev: pointer to the pcie_dev data structure
+ *
+ * Invoked when Root Port's AER service is loaded.
+ **/
+static struct aer_rpc* aer_alloc_rpc(struct pcie_device *dev)
+{
+ struct aer_rpc *rpc;
+
+ if (!(rpc = (struct aer_rpc *)kmalloc(sizeof(struct aer_rpc),
+ GFP_KERNEL)))
+ return NULL;
+
+ memset(rpc, 0, sizeof(struct aer_rpc));
+ /*
+ * Initialize Root lock access, e_lock, to Root Error Status Reg,
+ * Root Error ID Reg, and Root error producer/consumer index.
+ */
+ rpc->e_lock = SPIN_LOCK_UNLOCKED;
+
+ rpc->rpd = dev;
+ INIT_WORK(&rpc->dpc_handler, aer_isr, (void *)dev);
+ rpc->prod_idx = rpc->cons_idx = 0;
+ mutex_init(&rpc->rpc_mutex);
+ init_waitqueue_head(&rpc->wait_release);
+
+ /* Use PCIE bus function to store rpc into PCIE device */
+ set_service_data(dev, rpc);
+
+ return rpc;
+}
+
+/**
+ * aer_remove - clean up resources
+ * @dev: pointer to the pcie_dev data structure
+ *
+ * Invoked when PCI Express bus unloads or AER probe fails.
+ **/
+static void aer_remove(struct pcie_device *dev)
+{
+ struct aer_rpc *rpc = get_service_data(dev);
+
+ if (rpc) {
+ /* If register interrupt service, it must be free. */
+ if (rpc->isr)
+ free_irq(dev->irq, dev);
+
+ wait_event(rpc->wait_release, rpc->prod_idx == rpc->cons_idx);
+
+ aer_delete_rootport(rpc);
+ set_service_data(dev, NULL);
+ }
+}
+
+/**
+ * aer_probe - initialize resources
+ * @dev: pointer to the pcie_dev data structure
+ * @id: pointer to the service id data structure
+ *
+ * Invoked when PCI Express bus loads AER service driver.
+ **/
+static int __devinit aer_probe (struct pcie_device *dev,
+ const struct pcie_port_service_id *id )
+{
+ int status;
+ struct aer_rpc *rpc;
+ struct device *device = &dev->device;
+
+ /* Init */
+ if ((status = aer_init(dev)))
+ return status;
+
+ /* Alloc rpc data structure */
+ if (!(rpc = aer_alloc_rpc(dev))) {
+ printk(KERN_DEBUG "%s: Alloc rpc fails on PCIE device[%s]\n",
+ __FUNCTION__, device->bus_id);
+ aer_remove(dev);
+ return -ENOMEM;
+ }
+
+ /* Request IRQ ISR */
+ if ((status = request_irq(dev->irq, aer_irq, SA_SHIRQ, "aerdrv",
+ dev))) {
+ printk(KERN_DEBUG "%s: Request ISR fails on PCIE device[%s]\n",
+ __FUNCTION__, device->bus_id);
+ aer_remove(dev);
+ return status;
+ }
+
+ rpc->isr = 1;
+
+ aer_enable_rootport(rpc);
+
+ return status;
+}
+
+/**
+ * aer_root_reset - reset link on Root Port
+ * @dev: pointer to Root Port's pci_dev data structure
+ *
+ * Invoked by Port Bus driver when performing link reset at Root Port.
+ **/
+static pci_ers_result_t aer_root_reset(struct pci_dev *dev)
+{
+ u16 p2p_ctrl;
+ u32 status;
+ int pos;
+
+ pos = pci_find_aer_capability(dev);
+
+ /* Disable Root's interrupt in response to error messages */
+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_COMMAND, 0);
+
+ /* Assert Secondary Bus Reset */
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &p2p_ctrl);
+ p2p_ctrl |= PCI_CB_BRIDGE_CTL_CB_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
+
+ /* De-assert Secondary Bus Reset */
+ p2p_ctrl &= ~PCI_CB_BRIDGE_CTL_CB_RESET;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, p2p_ctrl);
+
+ /*
+ * System software must wait for at least 100ms from the end
+ * of a reset of one or more device before it is permitted
+ * to issue Configuration Requests to those devices.
+ */
+ msleep(200);
+ printk(KERN_DEBUG "Complete link reset at Root[%s]\n", dev->dev.bus_id);
+
+ /* Enable Root Port's interrupt in response to error messages */
+ pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
+ pci_write_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, status);
+ pci_write_config_dword(dev,
+ pos + PCI_ERR_ROOT_COMMAND,
+ ROOT_PORT_INTR_ON_MESG_MASK);
+
+ return PCI_ERS_RESULT_RECOVERED;
+}
+
+/**
+ * aer_error_detected - update severity status
+ * @dev: pointer to Root Port's pci_dev data structure
+ * @error: error severity being notified by port bus
+ *
+ * Invoked by Port Bus driver during error recovery.
+ **/
+static pci_ers_result_t aer_error_detected(struct pci_dev *dev,
+ enum pci_channel_state error)
+{
+ /* Root Port has no impact. Always recovers. */
+ return PCI_ERS_RESULT_CAN_RECOVER;
+}
+
+/**
+ * aer_error_resume - clean up corresponding error status bits
+ * @dev: pointer to Root Port's pci_dev data structure
+ *
+ * Invoked by Port Bus driver during nonfatal recovery.
+ **/
+static void aer_error_resume(struct pci_dev *dev)
+{
+ int pos;
+ u32 status, mask;
+ u16 reg16;
+
+ /* Clean up Root device status */
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ pci_read_config_word(dev, pos + PCI_EXP_DEVSTA, &reg16);
+ pci_write_config_word(dev, pos + PCI_EXP_DEVSTA, reg16);
+
+ /* Clean AER Root Error Status */
+ pos = pci_find_aer_capability(dev);
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
+ if (dev->error_state == pci_channel_io_normal)
+ status &= ~mask; /* Clear corresponding nonfatal bits */
+ else
+ status &= mask; /* Clear corresponding fatal bits */
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
+}
+
+/**
+ * aer_service_init - register AER root service driver
+ *
+ * Invoked when AER root service driver is loaded.
+ **/
+static int __init aer_service_init(void)
+{
+ return pcie_port_service_register(&aerdrv);
+}
+
+/**
+ * aer_service_exit - unregister AER root service driver
+ *
+ * Invoked when AER root service driver is unloaded.
+ **/
+static void __exit aer_service_exit(void)
+{
+ pcie_port_service_unregister(&aerdrv);
+}
+
+module_init(aer_service_init);
+module_exit(aer_service_exit);
diff --git a/drivers/pci/pcie/aer/aerdrv.h b/drivers/pci/pcie/aer/aerdrv.h
new file mode 100644
index 000000000000..daf0cad88fc8
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#ifndef _AERDRV_H_
+#define _AERDRV_H_
+
+#include <linux/pcieport_if.h>
+#include <linux/aer.h>
+
+#define AER_NONFATAL 0
+#define AER_FATAL 1
+#define AER_CORRECTABLE 2
+#define AER_UNCORRECTABLE 4
+#define AER_ERROR_MASK 0x001fffff
+#define AER_ERROR(d) (d & AER_ERROR_MASK)
+
+#define OSC_METHOD_RUN_SUCCESS 0
+#define OSC_METHOD_NOT_SUPPORTED 1
+#define OSC_METHOD_RUN_FAILURE 2
+
+/* Root Error Status Register Bits */
+#define ROOT_ERR_STATUS_MASKS 0x0f
+
+#define SYSTEM_ERROR_INTR_ON_MESG_MASK (PCI_EXP_RTCTL_SECEE| \
+ PCI_EXP_RTCTL_SENFEE| \
+ PCI_EXP_RTCTL_SEFEE)
+#define ROOT_PORT_INTR_ON_MESG_MASK (PCI_ERR_ROOT_CMD_COR_EN| \
+ PCI_ERR_ROOT_CMD_NONFATAL_EN| \
+ PCI_ERR_ROOT_CMD_FATAL_EN)
+#define ERR_COR_ID(d) (d & 0xffff)
+#define ERR_UNCOR_ID(d) (d >> 16)
+
+#define AER_SUCCESS 0
+#define AER_UNSUCCESS 1
+#define AER_ERROR_SOURCES_MAX 100
+
+#define AER_LOG_TLP_MASKS (PCI_ERR_UNC_POISON_TLP| \
+ PCI_ERR_UNC_ECRC| \
+ PCI_ERR_UNC_UNSUP| \
+ PCI_ERR_UNC_COMP_ABORT| \
+ PCI_ERR_UNC_UNX_COMP| \
+ PCI_ERR_UNC_MALF_TLP)
+
+/* AER Error Info Flags */
+#define AER_TLP_HEADER_VALID_FLAG 0x00000001
+#define AER_MULTI_ERROR_VALID_FLAG 0x00000002
+
+#define ERR_CORRECTABLE_ERROR_MASK 0x000031c1
+#define ERR_UNCORRECTABLE_ERROR_MASK 0x001ff010
+
+struct header_log_regs {
+ unsigned int dw0;
+ unsigned int dw1;
+ unsigned int dw2;
+ unsigned int dw3;
+};
+
+struct aer_err_info {
+ int severity; /* 0:NONFATAL | 1:FATAL | 2:COR */
+ int flags;
+ unsigned int status; /* COR/UNCOR Error Status */
+ struct header_log_regs tlp; /* TLP Header */
+};
+
+struct aer_err_source {
+ unsigned int status;
+ unsigned int id;
+};
+
+struct aer_rpc {
+ struct pcie_device *rpd; /* Root Port device */
+ struct work_struct dpc_handler;
+ struct aer_err_source e_sources[AER_ERROR_SOURCES_MAX];
+ unsigned short prod_idx; /* Error Producer Index */
+ unsigned short cons_idx; /* Error Consumer Index */
+ int isr;
+ spinlock_t e_lock; /*
+ * Lock access to Error Status/ID Regs
+ * and error producer/consumer index
+ */
+ struct mutex rpc_mutex; /*
+ * only one thread could do
+ * recovery on the same
+ * root port hierachy
+ */
+ wait_queue_head_t wait_release;
+};
+
+struct aer_broadcast_data {
+ enum pci_channel_state state;
+ enum pci_ers_result result;
+};
+
+static inline pci_ers_result_t merge_result(enum pci_ers_result orig,
+ enum pci_ers_result new)
+{
+ switch (orig) {
+ case PCI_ERS_RESULT_CAN_RECOVER:
+ case PCI_ERS_RESULT_RECOVERED:
+ orig = new;
+ break;
+ case PCI_ERS_RESULT_DISCONNECT:
+ if (new == PCI_ERS_RESULT_NEED_RESET)
+ orig = new;
+ break;
+ default:
+ break;
+ }
+
+ return orig;
+}
+
+extern struct bus_type pcie_port_bus_type;
+extern void aer_enable_rootport(struct aer_rpc *rpc);
+extern void aer_delete_rootport(struct aer_rpc *rpc);
+extern int aer_init(struct pcie_device *dev);
+extern void aer_isr(void *context);
+extern void aer_print_error(struct pci_dev *dev, struct aer_err_info *info);
+extern int aer_osc_setup(struct pci_dev *dev);
+
+#endif //_AERDRV_H_
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
new file mode 100644
index 000000000000..fa68e89ebec9
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -0,0 +1,68 @@
+/*
+ * Access ACPI _OSC method
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/delay.h>
+#include "aerdrv.h"
+
+/**
+ * aer_osc_setup - run ACPI _OSC method
+ *
+ * Return:
+ * Zero if success. Nonzero for otherwise.
+ *
+ * Invoked when PCIE bus loads AER service driver. To avoid conflict with
+ * BIOS AER support requires BIOS to yield AER control to OS native driver.
+ **/
+int aer_osc_setup(struct pci_dev *dev)
+{
+ int retval = OSC_METHOD_RUN_SUCCESS;
+ acpi_status status;
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ struct pci_dev *pdev = dev;
+ struct pci_bus *parent;
+
+ while (!handle) {
+ if (!pdev || !pdev->bus->parent)
+ break;
+ parent = pdev->bus->parent;
+ if (!parent->self)
+ /* Parent must be a host bridge */
+ handle = acpi_get_pci_rootbridge_handle(
+ pci_domain_nr(parent),
+ parent->number);
+ else
+ handle = DEVICE_ACPI_HANDLE(
+ &(parent->self->dev));
+ pdev = parent->self;
+ }
+
+ if (!handle)
+ return OSC_METHOD_NOT_SUPPORTED;
+
+ pci_osc_support_set(OSC_EXT_PCI_CONFIG_SUPPORT);
+ status = pci_osc_control_set(handle, OSC_PCI_EXPRESS_AER_CONTROL |
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ if (ACPI_FAILURE(status)) {
+ if (status == AE_SUPPORT)
+ retval = OSC_METHOD_NOT_SUPPORTED;
+ else
+ retval = OSC_METHOD_RUN_FAILURE;
+ }
+
+ return retval;
+}
+
diff --git a/drivers/pci/pcie/aer/aerdrv_core.c b/drivers/pci/pcie/aer/aerdrv_core.c
new file mode 100644
index 000000000000..1c7e660d6535
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv_core.c
@@ -0,0 +1,758 @@
+/*
+ * drivers/pci/pcie/aer/aerdrv_core.c
+ *
+ * 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.
+ *
+ * This file implements the core part of PCI-Express AER. When an pci-express
+ * error is delivered, an error message will be collected and printed to
+ * console, then, an error recovery procedure will be executed by following
+ * the pci error recovery rules.
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+#include <linux/acpi.h>
+#include <linux/pci-acpi.h>
+#include <linux/delay.h>
+#include "aerdrv.h"
+
+static int forceload;
+module_param(forceload, bool, 0);
+
+#define PCI_CFG_SPACE_SIZE (0x100)
+int pci_find_aer_capability(struct pci_dev *dev)
+{
+ int pos;
+ u32 reg32 = 0;
+
+ /* Check if it's a pci-express device */
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return 0;
+
+ /* Check if it supports pci-express AER */
+ pos = PCI_CFG_SPACE_SIZE;
+ while (pos) {
+ if (pci_read_config_dword(dev, pos, &reg32))
+ return 0;
+
+ /* some broken boards return ~0 */
+ if (reg32 == 0xffffffff)
+ return 0;
+
+ if (PCI_EXT_CAP_ID(reg32) == PCI_EXT_CAP_ID_ERR)
+ break;
+
+ pos = reg32 >> 20;
+ }
+
+ return pos;
+}
+
+int pci_enable_pcie_error_reporting(struct pci_dev *dev)
+{
+ u16 reg16 = 0;
+ int pos;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return -EIO;
+
+ pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
+ reg16 = reg16 |
+ PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE;
+ pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
+ reg16);
+ return 0;
+}
+
+int pci_disable_pcie_error_reporting(struct pci_dev *dev)
+{
+ u16 reg16 = 0;
+ int pos;
+
+ pos = pci_find_capability(dev, PCI_CAP_ID_EXP);
+ if (!pos)
+ return -EIO;
+
+ pci_read_config_word(dev, pos+PCI_EXP_DEVCTL, &reg16);
+ reg16 = reg16 & ~(PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE);
+ pci_write_config_word(dev, pos+PCI_EXP_DEVCTL,
+ reg16);
+ return 0;
+}
+
+int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev)
+{
+ int pos;
+ u32 status, mask;
+
+ pos = pci_find_aer_capability(dev);
+ if (!pos)
+ return -EIO;
+
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, &status);
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_SEVER, &mask);
+ if (dev->error_state == pci_channel_io_normal)
+ status &= ~mask; /* Clear corresponding nonfatal bits */
+ else
+ status &= mask; /* Clear corresponding fatal bits */
+ pci_write_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS, status);
+
+ return 0;
+}
+
+static int find_device_iter(struct device *device, void *data)
+{
+ struct pci_dev *dev;
+ u16 id = *(unsigned long *)data;
+ u8 secondary, subordinate, d_bus = id >> 8;
+
+ if (device->bus == &pci_bus_type) {
+ dev = to_pci_dev(device);
+ if (id == ((dev->bus->number << 8) | dev->devfn)) {
+ /*
+ * Device ID match
+ */
+ *(unsigned long*)data = (unsigned long)device;
+ return 1;
+ }
+
+ /*
+ * If device is P2P, check if it is an upstream?
+ */
+ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
+ pci_read_config_byte(dev, PCI_SECONDARY_BUS,
+ &secondary);
+ pci_read_config_byte(dev, PCI_SUBORDINATE_BUS,
+ &subordinate);
+ if (d_bus >= secondary && d_bus <= subordinate) {
+ *(unsigned long*)data = (unsigned long)device;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * find_source_device - search through device hierarchy for source device
+ * @p_dev: pointer to Root Port pci_dev data structure
+ * @id: device ID of agent who sends an error message to this Root Port
+ *
+ * Invoked when error is detected at the Root Port.
+ **/
+static struct device* find_source_device(struct pci_dev *parent, u16 id)
+{
+ struct pci_dev *dev = parent;
+ struct device *device;
+ unsigned long device_addr;
+ int status;
+
+ /* Is Root Port an agent that sends error message? */
+ if (id == ((dev->bus->number << 8) | dev->devfn))
+ return &dev->dev;
+
+ do {
+ device_addr = id;
+ if ((status = device_for_each_child(&dev->dev,
+ &device_addr, find_device_iter))) {
+ device = (struct device*)device_addr;
+ dev = to_pci_dev(device);
+ if (id == ((dev->bus->number << 8) | dev->devfn))
+ return device;
+ }
+ }while (status);
+
+ return NULL;
+}
+
+static void report_error_detected(struct pci_dev *dev, void *data)
+{
+ pci_ers_result_t vote;
+ struct pci_error_handlers *err_handler;
+ struct aer_broadcast_data *result_data;
+ result_data = (struct aer_broadcast_data *) data;
+
+ dev->error_state = result_data->state;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->error_detected) {
+ if (result_data->state == pci_channel_io_frozen &&
+ !(dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)) {
+ /*
+ * In case of fatal recovery, if one of down-
+ * stream device has no driver. We might be
+ * unable to recover because a later insmod
+ * of a driver for this device is unaware of
+ * its hw state.
+ */
+ printk(KERN_DEBUG "Device ID[%s] has %s\n",
+ dev->dev.bus_id, (dev->driver) ?
+ "no AER-aware driver" : "no driver");
+ }
+ return;
+ }
+
+ err_handler = dev->driver->err_handler;
+ vote = err_handler->error_detected(dev, result_data->state);
+ result_data->result = merge_result(result_data->result, vote);
+ return;
+}
+
+static void report_mmio_enabled(struct pci_dev *dev, void *data)
+{
+ pci_ers_result_t vote;
+ struct pci_error_handlers *err_handler;
+ struct aer_broadcast_data *result_data;
+ result_data = (struct aer_broadcast_data *) data;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->mmio_enabled)
+ return;
+
+ err_handler = dev->driver->err_handler;
+ vote = err_handler->mmio_enabled(dev);
+ result_data->result = merge_result(result_data->result, vote);
+ return;
+}
+
+static void report_slot_reset(struct pci_dev *dev, void *data)
+{
+ pci_ers_result_t vote;
+ struct pci_error_handlers *err_handler;
+ struct aer_broadcast_data *result_data;
+ result_data = (struct aer_broadcast_data *) data;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->slot_reset)
+ return;
+
+ err_handler = dev->driver->err_handler;
+ vote = err_handler->slot_reset(dev);
+ result_data->result = merge_result(result_data->result, vote);
+ return;
+}
+
+static void report_resume(struct pci_dev *dev, void *data)
+{
+ struct pci_error_handlers *err_handler;
+
+ dev->error_state = pci_channel_io_normal;
+
+ if (!dev->driver ||
+ !dev->driver->err_handler ||
+ !dev->driver->err_handler->slot_reset)
+ return;
+
+ err_handler = dev->driver->err_handler;
+ err_handler->resume(dev);
+ return;
+}
+
+/**
+ * broadcast_error_message - handle message broadcast to downstream drivers
+ * @device: pointer to from where in a hierarchy message is broadcasted down
+ * @api: callback to be broadcasted
+ * @state: error state
+ *
+ * Invoked during error recovery process. Once being invoked, the content
+ * of error severity will be broadcasted to all downstream drivers in a
+ * hierarchy in question.
+ **/
+static pci_ers_result_t broadcast_error_message(struct pci_dev *dev,
+ enum pci_channel_state state,
+ char *error_mesg,
+ void (*cb)(struct pci_dev *, void *))
+{
+ struct aer_broadcast_data result_data;
+
+ printk(KERN_DEBUG "Broadcast %s message\n", error_mesg);
+ result_data.state = state;
+ if (cb == report_error_detected)
+ result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
+ else
+ result_data.result = PCI_ERS_RESULT_RECOVERED;
+
+ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE) {
+ /*
+ * If the error is reported by a bridge, we think this error
+ * is related to the downstream link of the bridge, so we
+ * do error recovery on all subordinates of the bridge instead
+ * of the bridge and clear the error status of the bridge.
+ */
+ if (cb == report_error_detected)
+ dev->error_state = state;
+ pci_walk_bus(dev->subordinate, cb, &result_data);
+ if (cb == report_resume) {
+ pci_cleanup_aer_uncorrect_error_status(dev);
+ dev->error_state = pci_channel_io_normal;
+ }
+ }
+ else {
+ /*
+ * If the error is reported by an end point, we think this
+ * error is related to the upstream link of the end point.
+ */
+ pci_walk_bus(dev->bus, cb, &result_data);
+ }
+
+ return result_data.result;
+}
+
+struct find_aer_service_data {
+ struct pcie_port_service_driver *aer_driver;
+ int is_downstream;
+};
+
+static int find_aer_service_iter(struct device *device, void *data)
+{
+ struct device_driver *driver;
+ struct pcie_port_service_driver *service_driver;
+ struct pcie_device *pcie_dev;
+ struct find_aer_service_data *result;
+
+ result = (struct find_aer_service_data *) data;
+
+ if (device->bus == &pcie_port_bus_type) {
+ pcie_dev = to_pcie_device(device);
+ if (pcie_dev->id.port_type == PCIE_SW_DOWNSTREAM_PORT)
+ result->is_downstream = 1;
+
+ driver = device->driver;
+ if (driver) {
+ service_driver = to_service_driver(driver);
+ if (service_driver->id_table->service_type ==
+ PCIE_PORT_SERVICE_AER) {
+ result->aer_driver = service_driver;
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void find_aer_service(struct pci_dev *dev,
+ struct find_aer_service_data *data)
+{
+ int retval;
+ retval = device_for_each_child(&dev->dev, data, find_aer_service_iter);
+}
+
+static pci_ers_result_t reset_link(struct pcie_device *aerdev,
+ struct pci_dev *dev)
+{
+ struct pci_dev *udev;
+ pci_ers_result_t status;
+ struct find_aer_service_data data;
+
+ if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE)
+ udev = dev;
+ else
+ udev= dev->bus->self;
+
+ data.is_downstream = 0;
+ data.aer_driver = NULL;
+ find_aer_service(udev, &data);
+
+ /*
+ * Use the aer driver of the error agent firstly.
+ * If it hasn't the aer driver, use the root port's
+ */
+ if (!data.aer_driver || !data.aer_driver->reset_link) {
+ if (data.is_downstream &&
+ aerdev->device.driver &&
+ to_service_driver(aerdev->device.driver)->reset_link) {
+ data.aer_driver =
+ to_service_driver(aerdev->device.driver);
+ } else {
+ printk(KERN_DEBUG "No link-reset support to Device ID"
+ "[%s]\n",
+ dev->dev.bus_id);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+ }
+
+ status = data.aer_driver->reset_link(udev);
+ if (status != PCI_ERS_RESULT_RECOVERED) {
+ printk(KERN_DEBUG "Link reset at upstream Device ID"
+ "[%s] failed\n",
+ udev->dev.bus_id);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ return status;
+}
+
+/**
+ * do_recovery - handle nonfatal/fatal error recovery process
+ * @aerdev: pointer to a pcie_device data structure of root port
+ * @dev: pointer to a pci_dev data structure of agent detecting an error
+ * @severity: error severity type
+ *
+ * Invoked when an error is nonfatal/fatal. Once being invoked, broadcast
+ * error detected message to all downstream drivers within a hierarchy in
+ * question and return the returned code.
+ **/
+static pci_ers_result_t do_recovery(struct pcie_device *aerdev,
+ struct pci_dev *dev,
+ int severity)
+{
+ pci_ers_result_t status, result = PCI_ERS_RESULT_RECOVERED;
+ enum pci_channel_state state;
+
+ if (severity == AER_FATAL)
+ state = pci_channel_io_frozen;
+ else
+ state = pci_channel_io_normal;
+
+ status = broadcast_error_message(dev,
+ state,
+ "error_detected",
+ report_error_detected);
+
+ if (severity == AER_FATAL) {
+ result = reset_link(aerdev, dev);
+ if (result != PCI_ERS_RESULT_RECOVERED) {
+ /* TODO: Should panic here? */
+ return result;
+ }
+ }
+
+ if (status == PCI_ERS_RESULT_CAN_RECOVER)
+ status = broadcast_error_message(dev,
+ state,
+ "mmio_enabled",
+ report_mmio_enabled);
+
+ if (status == PCI_ERS_RESULT_NEED_RESET) {
+ /*
+ * TODO: Should call platform-specific
+ * functions to reset slot before calling
+ * drivers' slot_reset callbacks?
+ */
+ status = broadcast_error_message(dev,
+ state,
+ "slot_reset",
+ report_slot_reset);
+ }
+
+ if (status == PCI_ERS_RESULT_RECOVERED)
+ broadcast_error_message(dev,
+ state,
+ "resume",
+ report_resume);
+
+ return status;
+}
+
+/**
+ * handle_error_source - handle logging error into an event log
+ * @aerdev: pointer to pcie_device data structure of the root port
+ * @dev: pointer to pci_dev data structure of error source device
+ * @info: comprehensive error information
+ *
+ * Invoked when an error being detected by Root Port.
+ **/
+static void handle_error_source(struct pcie_device * aerdev,
+ struct pci_dev *dev,
+ struct aer_err_info info)
+{
+ pci_ers_result_t status = 0;
+ int pos;
+
+ if (info.severity == AER_CORRECTABLE) {
+ /*
+ * Correctable error does not need software intevention.
+ * No need to go through error recovery process.
+ */
+ pos = pci_find_aer_capability(dev);
+ if (pos)
+ pci_write_config_dword(dev, pos + PCI_ERR_COR_STATUS,
+ info.status);
+ } else {
+ status = do_recovery(aerdev, dev, info.severity);
+ if (status == PCI_ERS_RESULT_RECOVERED) {
+ printk(KERN_DEBUG "AER driver successfully recovered\n");
+ } else {
+ /* TODO: Should kernel panic here? */
+ printk(KERN_DEBUG "AER driver didn't recover\n");
+ }
+ }
+}
+
+/**
+ * aer_enable_rootport - enable Root Port's interrupts when receiving messages
+ * @rpc: pointer to a Root Port data structure
+ *
+ * Invoked when PCIE bus loads AER service driver.
+ **/
+void aer_enable_rootport(struct aer_rpc *rpc)
+{
+ struct pci_dev *pdev = rpc->rpd->port;
+ int pos, aer_pos;
+ u16 reg16;
+ u32 reg32;
+
+ pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+ /* Clear PCIE Capability's Device Status */
+ pci_read_config_word(pdev, pos+PCI_EXP_DEVSTA, &reg16);
+ pci_write_config_word(pdev, pos+PCI_EXP_DEVSTA, reg16);
+
+ /* Disable system error generation in response to error messages */
+ pci_read_config_word(pdev, pos + PCI_EXP_RTCTL, &reg16);
+ reg16 &= ~(SYSTEM_ERROR_INTR_ON_MESG_MASK);
+ pci_write_config_word(pdev, pos + PCI_EXP_RTCTL, reg16);
+
+ aer_pos = pci_find_aer_capability(pdev);
+ /* Clear error status */
+ pci_read_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, &reg32);
+ pci_write_config_dword(pdev, aer_pos + PCI_ERR_ROOT_STATUS, reg32);
+ pci_read_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, &reg32);
+ pci_write_config_dword(pdev, aer_pos + PCI_ERR_COR_STATUS, reg32);
+ pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
+ pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
+
+ /* Enable Root Port device reporting error itself */
+ pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16);
+ reg16 = reg16 |
+ PCI_EXP_DEVCTL_CERE |
+ PCI_EXP_DEVCTL_NFERE |
+ PCI_EXP_DEVCTL_FERE |
+ PCI_EXP_DEVCTL_URRE;
+ pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,
+ reg16);
+
+ /* Enable Root Port's interrupt in response to error messages */
+ pci_write_config_dword(pdev,
+ aer_pos + PCI_ERR_ROOT_COMMAND,
+ ROOT_PORT_INTR_ON_MESG_MASK);
+}
+
+/**
+ * disable_root_aer - disable Root Port's interrupts when receiving messages
+ * @rpc: pointer to a Root Port data structure
+ *
+ * Invoked when PCIE bus unloads AER service driver.
+ **/
+static void disable_root_aer(struct aer_rpc *rpc)
+{
+ struct pci_dev *pdev = rpc->rpd->port;
+ u32 reg32;
+ int pos;
+
+ pos = pci_find_aer_capability(pdev);
+ /* Disable Root's interrupt in response to error messages */
+ pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
+
+ /* Clear Root's error status reg */
+ pci_read_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, &reg32);
+ pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_STATUS, reg32);
+}
+
+/**
+ * get_e_source - retrieve an error source
+ * @rpc: pointer to the root port which holds an error
+ *
+ * Invoked by DPC handler to consume an error.
+ **/
+static struct aer_err_source* get_e_source(struct aer_rpc *rpc)
+{
+ struct aer_err_source *e_source;
+ unsigned long flags;
+
+ /* Lock access to Root error producer/consumer index */
+ spin_lock_irqsave(&rpc->e_lock, flags);
+ if (rpc->prod_idx == rpc->cons_idx) {
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+ return NULL;
+ }
+ e_source = &rpc->e_sources[rpc->cons_idx];
+ rpc->cons_idx++;
+ if (rpc->cons_idx == AER_ERROR_SOURCES_MAX)
+ rpc->cons_idx = 0;
+ spin_unlock_irqrestore(&rpc->e_lock, flags);
+
+ return e_source;
+}
+
+static int get_device_error_info(struct pci_dev *dev, struct aer_err_info *info)
+{
+ int pos;
+
+ pos = pci_find_aer_capability(dev);
+
+ /* The device might not support AER */
+ if (!pos)
+ return AER_SUCCESS;
+
+ if (info->severity == AER_CORRECTABLE) {
+ pci_read_config_dword(dev, pos + PCI_ERR_COR_STATUS,
+ &info->status);
+ if (!(info->status & ERR_CORRECTABLE_ERROR_MASK))
+ return AER_UNSUCCESS;
+ } else if (dev->hdr_type & PCI_HEADER_TYPE_BRIDGE ||
+ info->severity == AER_NONFATAL) {
+
+ /* Link is still healthy for IO reads */
+ pci_read_config_dword(dev, pos + PCI_ERR_UNCOR_STATUS,
+ &info->status);
+ if (!(info->status & ERR_UNCORRECTABLE_ERROR_MASK))
+ return AER_UNSUCCESS;
+
+ if (info->status & AER_LOG_TLP_MASKS) {
+ info->flags |= AER_TLP_HEADER_VALID_FLAG;
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG, &info->tlp.dw0);
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG + 4, &info->tlp.dw1);
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG + 8, &info->tlp.dw2);
+ pci_read_config_dword(dev,
+ pos + PCI_ERR_HEADER_LOG + 12, &info->tlp.dw3);
+ }
+ }
+
+ return AER_SUCCESS;
+}
+
+/**
+ * aer_isr_one_error - consume an error detected by root port
+ * @p_device: pointer to error root port service device
+ * @e_src: pointer to an error source
+ **/
+static void aer_isr_one_error(struct pcie_device *p_device,
+ struct aer_err_source *e_src)
+{
+ struct device *s_device;
+ struct aer_err_info e_info = {0, 0, 0,};
+ int i;
+ u16 id;
+
+ /*
+ * There is a possibility that both correctable error and
+ * uncorrectable error being logged. Report correctable error first.
+ */
+ for (i = 1; i & ROOT_ERR_STATUS_MASKS ; i <<= 2) {
+ if (i > 4)
+ break;
+ if (!(e_src->status & i))
+ continue;
+
+ /* Init comprehensive error information */
+ if (i & PCI_ERR_ROOT_COR_RCV) {
+ id = ERR_COR_ID(e_src->id);
+ e_info.severity = AER_CORRECTABLE;
+ } else {
+ id = ERR_UNCOR_ID(e_src->id);
+ e_info.severity = ((e_src->status >> 6) & 1);
+ }
+ if (e_src->status &
+ (PCI_ERR_ROOT_MULTI_COR_RCV |
+ PCI_ERR_ROOT_MULTI_UNCOR_RCV))
+ e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
+ if (!(s_device = find_source_device(p_device->port, id))) {
+ printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
+ __FUNCTION__, id);
+ continue;
+ }
+ if (get_device_error_info(to_pci_dev(s_device), &e_info) ==
+ AER_SUCCESS) {
+ aer_print_error(to_pci_dev(s_device), &e_info);
+ handle_error_source(p_device,
+ to_pci_dev(s_device),
+ e_info);
+ }
+ }
+}
+
+/**
+ * aer_isr - consume errors detected by root port
+ * @context: pointer to a private data of pcie device
+ *
+ * Invoked, as DPC, when root port records new detected error
+ **/
+void aer_isr(void *context)
+{
+ struct pcie_device *p_device = (struct pcie_device *) context;
+ struct aer_rpc *rpc = get_service_data(p_device);
+ struct aer_err_source *e_src;
+
+ mutex_lock(&rpc->rpc_mutex);
+ e_src = get_e_source(rpc);
+ while (e_src) {
+ aer_isr_one_error(p_device, e_src);
+ e_src = get_e_source(rpc);
+ }
+ mutex_unlock(&rpc->rpc_mutex);
+
+ wake_up(&rpc->wait_release);
+}
+
+/**
+ * aer_delete_rootport - disable root port aer and delete service data
+ * @rpc: pointer to a root port device being deleted
+ *
+ * Invoked when AER service unloaded on a specific Root Port
+ **/
+void aer_delete_rootport(struct aer_rpc *rpc)
+{
+ /* Disable root port AER itself */
+ disable_root_aer(rpc);
+
+ kfree(rpc);
+}
+
+/**
+ * aer_init - provide AER initialization
+ * @dev: pointer to AER pcie device
+ *
+ * Invoked when AER service driver is loaded.
+ **/
+int aer_init(struct pcie_device *dev)
+{
+ int status;
+
+ /* Run _OSC Method */
+ status = aer_osc_setup(dev->port);
+
+ if(status != OSC_METHOD_RUN_SUCCESS) {
+ printk(KERN_DEBUG "%s: AER service init fails - %s\n",
+ __FUNCTION__,
+ (status == OSC_METHOD_NOT_SUPPORTED) ?
+ "No ACPI _OSC support" : "Run ACPI _OSC fails");
+
+ if (!forceload)
+ return status;
+ }
+
+ return AER_SUCCESS;
+}
+
+EXPORT_SYMBOL_GPL(pci_find_aer_capability);
+EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
+EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
+EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
+
diff --git a/drivers/pci/pcie/aer/aerdrv_errprint.c b/drivers/pci/pcie/aer/aerdrv_errprint.c
new file mode 100644
index 000000000000..3933d4f30e8c
--- /dev/null
+++ b/drivers/pci/pcie/aer/aerdrv_errprint.c
@@ -0,0 +1,248 @@
+/*
+ * drivers/pci/pcie/aer/aerdrv_errprint.c
+ *
+ * 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.
+ *
+ * Format error messages and print them to console.
+ *
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/pm.h>
+#include <linux/suspend.h>
+
+#include "aerdrv.h"
+
+#define AER_AGENT_RECEIVER 0
+#define AER_AGENT_REQUESTER 1
+#define AER_AGENT_COMPLETER 2
+#define AER_AGENT_TRANSMITTER 3
+
+#define AER_AGENT_REQUESTER_MASK (PCI_ERR_UNC_COMP_TIME| \
+ PCI_ERR_UNC_UNSUP)
+
+#define AER_AGENT_COMPLETER_MASK PCI_ERR_UNC_COMP_ABORT
+
+#define AER_AGENT_TRANSMITTER_MASK(t, e) (e & (PCI_ERR_COR_REP_ROLL| \
+ ((t == AER_CORRECTABLE) ? PCI_ERR_COR_REP_TIMER: 0)))
+
+#define AER_GET_AGENT(t, e) \
+ ((e & AER_AGENT_COMPLETER_MASK) ? AER_AGENT_COMPLETER : \
+ (e & AER_AGENT_REQUESTER_MASK) ? AER_AGENT_REQUESTER : \
+ (AER_AGENT_TRANSMITTER_MASK(t, e)) ? AER_AGENT_TRANSMITTER : \
+ AER_AGENT_RECEIVER)
+
+#define AER_PHYSICAL_LAYER_ERROR_MASK PCI_ERR_COR_RCVR
+#define AER_DATA_LINK_LAYER_ERROR_MASK(t, e) \
+ (PCI_ERR_UNC_DLP| \
+ PCI_ERR_COR_BAD_TLP| \
+ PCI_ERR_COR_BAD_DLLP| \
+ PCI_ERR_COR_REP_ROLL| \
+ ((t == AER_CORRECTABLE) ? \
+ PCI_ERR_COR_REP_TIMER: 0))
+
+#define AER_PHYSICAL_LAYER_ERROR 0
+#define AER_DATA_LINK_LAYER_ERROR 1
+#define AER_TRANSACTION_LAYER_ERROR 2
+
+#define AER_GET_LAYER_ERROR(t, e) \
+ ((e & AER_PHYSICAL_LAYER_ERROR_MASK) ? \
+ AER_PHYSICAL_LAYER_ERROR : \
+ (e & AER_DATA_LINK_LAYER_ERROR_MASK(t, e)) ? \
+ AER_DATA_LINK_LAYER_ERROR : \
+ AER_TRANSACTION_LAYER_ERROR)
+
+/*
+ * AER error strings
+ */
+static char* aer_error_severity_string[] = {
+ "Uncorrected (Non-Fatal)",
+ "Uncorrected (Fatal)",
+ "Corrected"
+};
+
+static char* aer_error_layer[] = {
+ "Physical Layer",
+ "Data Link Layer",
+ "Transaction Layer"
+};
+static char* aer_correctable_error_string[] = {
+ "Receiver Error ", /* Bit Position 0 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Bad TLP ", /* Bit Position 6 */
+ "Bad DLLP ", /* Bit Position 7 */
+ "RELAY_NUM Rollover ", /* Bit Position 8 */
+ NULL,
+ NULL,
+ NULL,
+ "Replay Timer Timeout ", /* Bit Position 12 */
+ "Advisory Non-Fatal ", /* Bit Position 13 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static char* aer_uncorrectable_error_string[] = {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Data Link Protocol ", /* Bit Position 4 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ "Poisoned TLP ", /* Bit Position 12 */
+ "Flow Control Protocol ", /* Bit Position 13 */
+ "Completion Timeout ", /* Bit Position 14 */
+ "Completer Abort ", /* Bit Position 15 */
+ "Unexpected Completion ", /* Bit Position 16 */
+ "Receiver Overflow ", /* Bit Position 17 */
+ "Malformed TLP ", /* Bit Position 18 */
+ "ECRC ", /* Bit Position 19 */
+ "Unsupported Request ", /* Bit Position 20 */
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+};
+
+static char* aer_agent_string[] = {
+ "Receiver ID",
+ "Requester ID",
+ "Completer ID",
+ "Transmitter ID"
+};
+
+static char * aer_get_error_source_name(int severity,
+ unsigned int status,
+ char errmsg_buff[])
+{
+ int i;
+ char * errmsg = NULL;
+
+ for (i = 0; i < 32; i++) {
+ if (!(status & (1 << i)))
+ continue;
+
+ if (severity == AER_CORRECTABLE)
+ errmsg = aer_correctable_error_string[i];
+ else
+ errmsg = aer_uncorrectable_error_string[i];
+
+ if (!errmsg) {
+ sprintf(errmsg_buff, "Unknown Error Bit %2d ", i);
+ errmsg = errmsg_buff;
+ }
+
+ break;
+ }
+
+ return errmsg;
+}
+
+static DEFINE_SPINLOCK(logbuf_lock);
+static char errmsg_buff[100];
+void aer_print_error(struct pci_dev *dev, struct aer_err_info *info)
+{
+ char * errmsg;
+ int err_layer, agent;
+ char * loglevel;
+
+ if (info->severity == AER_CORRECTABLE)
+ loglevel = KERN_WARNING;
+ else
+ loglevel = KERN_ERR;
+
+ printk("%s+------ PCI-Express Device Error ------+\n", loglevel);
+ printk("%sError Severity\t\t: %s\n", loglevel,
+ aer_error_severity_string[info->severity]);
+
+ if ( info->status == 0) {
+ printk("%sPCIE Bus Error type\t: (Unaccessible)\n", loglevel);
+ printk("%sUnaccessible Received\t: %s\n", loglevel,
+ info->flags & AER_MULTI_ERROR_VALID_FLAG ?
+ "Multiple" : "First");
+ printk("%sUnregistered Agent ID\t: %04x\n", loglevel,
+ (dev->bus->number << 8) | dev->devfn);
+ } else {
+ err_layer = AER_GET_LAYER_ERROR(info->severity, info->status);
+ printk("%sPCIE Bus Error type\t: %s\n", loglevel,
+ aer_error_layer[err_layer]);
+
+ spin_lock(&logbuf_lock);
+ errmsg = aer_get_error_source_name(info->severity,
+ info->status,
+ errmsg_buff);
+ printk("%s%s\t: %s\n", loglevel, errmsg,
+ info->flags & AER_MULTI_ERROR_VALID_FLAG ?
+ "Multiple" : "First");
+ spin_unlock(&logbuf_lock);
+
+ agent = AER_GET_AGENT(info->severity, info->status);
+ printk("%s%s\t\t: %04x\n", loglevel,
+ aer_agent_string[agent],
+ (dev->bus->number << 8) | dev->devfn);
+
+ printk("%sVendorID=%04xh, DeviceID=%04xh,"
+ " Bus=%02xh, Device=%02xh, Function=%02xh\n",
+ loglevel,
+ dev->vendor,
+ dev->device,
+ dev->bus->number,
+ PCI_SLOT(dev->devfn),
+ PCI_FUNC(dev->devfn));
+
+ if (info->flags & AER_TLP_HEADER_VALID_FLAG) {
+ unsigned char *tlp = (unsigned char *) &info->tlp;
+ printk("%sTLB Header:\n", loglevel);
+ printk("%s%02x%02x%02x%02x %02x%02x%02x%02x"
+ " %02x%02x%02x%02x %02x%02x%02x%02x\n",
+ loglevel,
+ *(tlp + 3), *(tlp + 2), *(tlp + 1), *tlp,
+ *(tlp + 7), *(tlp + 6), *(tlp + 5), *(tlp + 4),
+ *(tlp + 11), *(tlp + 10), *(tlp + 9),
+ *(tlp + 8), *(tlp + 15), *(tlp + 14),
+ *(tlp + 13), *(tlp + 12));
+ }
+ }
+}
+
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 1d317d22ee89..3656e0349dd1 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -9,6 +9,8 @@
#ifndef _PORTDRV_H_
#define _PORTDRV_H_
+#include <linux/compiler.h>
+
#if !defined(PCI_CAP_ID_PME)
#define PCI_CAP_ID_PME 1
#endif
@@ -39,7 +41,7 @@ extern int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state);
extern int pcie_port_device_resume(struct pci_dev *dev);
#endif
extern void pcie_port_device_remove(struct pci_dev *dev);
-extern void pcie_port_bus_register(void);
+extern int __must_check pcie_port_bus_register(void);
extern void pcie_port_bus_unregister(void);
#endif /* _PORTDRV_H_ */
diff --git a/drivers/pci/pcie/portdrv_bus.c b/drivers/pci/pcie/portdrv_bus.c
index 3e84b501e6a4..3f0976868eda 100644
--- a/drivers/pci/pcie/portdrv_bus.c
+++ b/drivers/pci/pcie/portdrv_bus.c
@@ -24,6 +24,7 @@ struct bus_type pcie_port_bus_type = {
.suspend = pcie_port_bus_suspend,
.resume = pcie_port_bus_resume,
};
+EXPORT_SYMBOL_GPL(pcie_port_bus_type);
static int pcie_port_bus_match(struct device *dev, struct device_driver *drv)
{
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 55c662267868..b20a9b81dae2 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -339,8 +339,7 @@ static int suspend_iter(struct device *dev, void *data)
int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
{
- device_for_each_child(&dev->dev, &state, suspend_iter);
- return 0;
+ return device_for_each_child(&dev->dev, &state, suspend_iter);
}
static int resume_iter(struct device *dev, void *data)
@@ -358,8 +357,7 @@ static int resume_iter(struct device *dev, void *data)
int pcie_port_device_resume(struct pci_dev *dev)
{
- device_for_each_child(&dev->dev, NULL, resume_iter);
- return 0;
+ return device_for_each_child(&dev->dev, NULL, resume_iter);
}
#endif
@@ -402,9 +400,9 @@ void pcie_port_device_remove(struct pci_dev *dev)
pci_disable_msi(dev);
}
-void pcie_port_bus_register(void)
+int pcie_port_bus_register(void)
{
- bus_register(&pcie_port_bus_type);
+ return bus_register(&pcie_port_bus_type);
}
void pcie_port_bus_unregister(void)
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index 478d0d28f7ad..b4da7954611e 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -14,8 +14,10 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/pcieport_if.h>
+#include <linux/aer.h>
#include "portdrv.h"
+#include "aer/aerdrv.h"
/*
* Version Information
@@ -30,6 +32,43 @@ MODULE_LICENSE("GPL");
/* global data */
static const char device_name[] = "pcieport-driver";
+static int pcie_portdrv_save_config(struct pci_dev *dev)
+{
+ return pci_save_state(dev);
+}
+
+static int pcie_portdrv_restore_config(struct pci_dev *dev)
+{
+ int retval;
+
+ pci_restore_state(dev);
+ retval = pci_enable_device(dev);
+ if (retval)
+ return retval;
+ pci_set_master(dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int pcie_portdrv_suspend(struct pci_dev *dev, pm_message_t state)
+{
+ int ret = pcie_port_device_suspend(dev, state);
+
+ if (!ret)
+ ret = pcie_portdrv_save_config(dev);
+ return ret;
+}
+
+static int pcie_portdrv_resume(struct pci_dev *dev)
+{
+ pcie_portdrv_restore_config(dev);
+ return pcie_port_device_resume(dev);
+}
+#else
+#define pcie_portdrv_suspend NULL
+#define pcie_portdrv_resume NULL
+#endif
+
/*
* pcie_portdrv_probe - Probe PCI-Express port devices
* @dev: PCI-Express port device being probed
@@ -61,6 +100,10 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
return -ENOMEM;
}
+ pcie_portdrv_save_config(dev);
+
+ pci_enable_pcie_error_reporting(dev);
+
return 0;
}
@@ -70,39 +113,151 @@ static void pcie_portdrv_remove (struct pci_dev *dev)
kfree(pci_get_drvdata(dev));
}
-#ifdef CONFIG_PM
-static int pcie_portdrv_save_config(struct pci_dev *dev)
+static int error_detected_iter(struct device *device, void *data)
{
- return pci_save_state(dev);
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+ struct aer_broadcast_data *result_data;
+ pci_ers_result_t status;
+
+ result_data = (struct aer_broadcast_data *) data;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (!driver ||
+ !driver->err_handler ||
+ !driver->err_handler->error_detected)
+ return 0;
+
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error detected message to service drivers */
+ status = driver->err_handler->error_detected(
+ pcie_device->port,
+ result_data->state);
+ result_data->result =
+ merge_result(result_data->result, status);
+ }
+
+ return 0;
}
-static int pcie_portdrv_restore_config(struct pci_dev *dev)
+static pci_ers_result_t pcie_portdrv_error_detected(struct pci_dev *dev,
+ enum pci_channel_state error)
{
+ struct aer_broadcast_data result_data =
+ {error, PCI_ERS_RESULT_CAN_RECOVER};
int retval;
- pci_restore_state(dev);
- retval = pci_enable_device(dev);
- if (retval)
- return retval;
- pci_set_master(dev);
+ /* can not fail */
+ retval = device_for_each_child(&dev->dev, &result_data, error_detected_iter);
+
+ return result_data.result;
+}
+
+static int mmio_enabled_iter(struct device *device, void *data)
+{
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+ pci_ers_result_t status, *result;
+
+ result = (pci_ers_result_t *) data;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (driver &&
+ driver->err_handler &&
+ driver->err_handler->mmio_enabled) {
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error message to service drivers */
+ status = driver->err_handler->mmio_enabled(
+ pcie_device->port);
+ *result = merge_result(*result, status);
+ }
+ }
+
return 0;
}
-static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state)
+static pci_ers_result_t pcie_portdrv_mmio_enabled(struct pci_dev *dev)
{
- int ret = pcie_port_device_suspend(dev, state);
+ pci_ers_result_t status = PCI_ERS_RESULT_RECOVERED;
+ int retval;
- if (!ret)
- ret = pcie_portdrv_save_config(dev);
- return ret;
+ /* get true return value from &status */
+ retval = device_for_each_child(&dev->dev, &status, mmio_enabled_iter);
+ return status;
}
-static int pcie_portdrv_resume (struct pci_dev *dev)
+static int slot_reset_iter(struct device *device, void *data)
{
- pcie_portdrv_restore_config(dev);
- return pcie_port_device_resume(dev);
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+ pci_ers_result_t status, *result;
+
+ result = (pci_ers_result_t *) data;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (driver &&
+ driver->err_handler &&
+ driver->err_handler->slot_reset) {
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error message to service drivers */
+ status = driver->err_handler->slot_reset(
+ pcie_device->port);
+ *result = merge_result(*result, status);
+ }
+ }
+
+ return 0;
+}
+
+static pci_ers_result_t pcie_portdrv_slot_reset(struct pci_dev *dev)
+{
+ pci_ers_result_t status;
+ int retval;
+
+ /* If fatal, restore cfg space for possible link reset at upstream */
+ if (dev->error_state == pci_channel_io_frozen) {
+ pcie_portdrv_restore_config(dev);
+ pci_enable_pcie_error_reporting(dev);
+ }
+
+ /* get true return value from &status */
+ retval = device_for_each_child(&dev->dev, &status, slot_reset_iter);
+
+ return status;
+}
+
+static int resume_iter(struct device *device, void *data)
+{
+ struct pcie_device *pcie_device;
+ struct pcie_port_service_driver *driver;
+
+ if (device->bus == &pcie_port_bus_type && device->driver) {
+ driver = to_service_driver(device->driver);
+ if (driver &&
+ driver->err_handler &&
+ driver->err_handler->resume) {
+ pcie_device = to_pcie_device(device);
+
+ /* Forward error message to service drivers */
+ driver->err_handler->resume(pcie_device->port);
+ }
+ }
+
+ return 0;
+}
+
+static void pcie_portdrv_err_resume(struct pci_dev *dev)
+{
+ int retval;
+ /* nothing to do with error value, if it ever happens */
+ retval = device_for_each_child(&dev->dev, NULL, resume_iter);
}
-#endif
/*
* LINUX Device Driver Model
@@ -114,6 +269,13 @@ static const struct pci_device_id port_pci_ids[] = { {
};
MODULE_DEVICE_TABLE(pci, port_pci_ids);
+static struct pci_error_handlers pcie_portdrv_err_handler = {
+ .error_detected = pcie_portdrv_error_detected,
+ .mmio_enabled = pcie_portdrv_mmio_enabled,
+ .slot_reset = pcie_portdrv_slot_reset,
+ .resume = pcie_portdrv_err_resume,
+};
+
static struct pci_driver pcie_portdrv = {
.name = (char *)device_name,
.id_table = &port_pci_ids[0],
@@ -121,20 +283,25 @@ static struct pci_driver pcie_portdrv = {
.probe = pcie_portdrv_probe,
.remove = pcie_portdrv_remove,
-#ifdef CONFIG_PM
.suspend = pcie_portdrv_suspend,
.resume = pcie_portdrv_resume,
-#endif /* PM */
+
+ .err_handler = &pcie_portdrv_err_handler,
};
static int __init pcie_portdrv_init(void)
{
- int retval = 0;
+ int retval;
- pcie_port_bus_register();
+ retval = pcie_port_bus_register();
+ if (retval) {
+ printk(KERN_WARNING "PCIE: bus_register error: %d\n", retval);
+ goto out;
+ }
retval = pci_register_driver(&pcie_portdrv);
if (retval)
pcie_port_bus_unregister();
+ out:
return retval;
}
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c5a58d1c6c1c..e159d6604494 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -339,6 +339,7 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
{
struct pci_bus *child;
int i;
+ int retval;
/*
* Allocate a new bus, and inherit stuff from the parent..
@@ -356,8 +357,13 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
child->class_dev.class = &pcibus_class;
sprintf(child->class_dev.class_id, "%04x:%02x", pci_domain_nr(child), busnr);
- class_device_register(&child->class_dev);
- class_device_create_file(&child->class_dev, &class_device_attr_cpuaffinity);
+ retval = class_device_register(&child->class_dev);
+ if (retval)
+ goto error_register;
+ retval = class_device_create_file(&child->class_dev,
+ &class_device_attr_cpuaffinity);
+ if (retval)
+ goto error_file_create;
/*
* Set up the primary, secondary and subordinate
@@ -375,6 +381,12 @@ pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr)
bridge->subordinate = child;
return child;
+
+error_file_create:
+ class_device_unregister(&child->class_dev);
+error_register:
+ kfree(child);
+ return NULL;
}
struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
@@ -1055,3 +1067,95 @@ EXPORT_SYMBOL(pci_scan_bridge);
EXPORT_SYMBOL(pci_scan_single_device);
EXPORT_SYMBOL_GPL(pci_scan_child_bus);
#endif
+
+static int __init pci_sort_bf_cmp(const struct pci_dev *a, const struct pci_dev *b)
+{
+ if (pci_domain_nr(a->bus) < pci_domain_nr(b->bus)) return -1;
+ else if (pci_domain_nr(a->bus) > pci_domain_nr(b->bus)) return 1;
+
+ if (a->bus->number < b->bus->number) return -1;
+ else if (a->bus->number > b->bus->number) return 1;
+
+ if (a->devfn < b->devfn) return -1;
+ else if (a->devfn > b->devfn) return 1;
+
+ return 0;
+}
+
+/*
+ * Yes, this forcably breaks the klist abstraction temporarily. It
+ * just wants to sort the klist, not change reference counts and
+ * take/drop locks rapidly in the process. It does all this while
+ * holding the lock for the list, so objects can't otherwise be
+ * added/removed while we're swizzling.
+ */
+static void __init pci_insertion_sort_klist(struct pci_dev *a, struct list_head *list)
+{
+ struct list_head *pos;
+ struct klist_node *n;
+ struct device *dev;
+ struct pci_dev *b;
+
+ list_for_each(pos, list) {
+ n = container_of(pos, struct klist_node, n_node);
+ dev = container_of(n, struct device, knode_bus);
+ b = to_pci_dev(dev);
+ if (pci_sort_bf_cmp(a, b) <= 0) {
+ list_move_tail(&a->dev.knode_bus.n_node, &b->dev.knode_bus.n_node);
+ return;
+ }
+ }
+ list_move_tail(&a->dev.knode_bus.n_node, list);
+}
+
+static void __init pci_sort_breadthfirst_klist(void)
+{
+ LIST_HEAD(sorted_devices);
+ struct list_head *pos, *tmp;
+ struct klist_node *n;
+ struct device *dev;
+ struct pci_dev *pdev;
+
+ spin_lock(&pci_bus_type.klist_devices.k_lock);
+ list_for_each_safe(pos, tmp, &pci_bus_type.klist_devices.k_list) {
+ n = container_of(pos, struct klist_node, n_node);
+ dev = container_of(n, struct device, knode_bus);
+ pdev = to_pci_dev(dev);
+ pci_insertion_sort_klist(pdev, &sorted_devices);
+ }
+ list_splice(&sorted_devices, &pci_bus_type.klist_devices.k_list);
+ spin_unlock(&pci_bus_type.klist_devices.k_lock);
+}
+
+static void __init pci_insertion_sort_devices(struct pci_dev *a, struct list_head *list)
+{
+ struct pci_dev *b;
+
+ list_for_each_entry(b, list, global_list) {
+ if (pci_sort_bf_cmp(a, b) <= 0) {
+ list_move_tail(&a->global_list, &b->global_list);
+ return;
+ }
+ }
+ list_move_tail(&a->global_list, list);
+}
+
+static void __init pci_sort_breadthfirst_devices(void)
+{
+ LIST_HEAD(sorted_devices);
+ struct pci_dev *dev, *tmp;
+
+ down_write(&pci_bus_sem);
+ list_for_each_entry_safe(dev, tmp, &pci_devices, global_list) {
+ pci_insertion_sort_devices(dev, &sorted_devices);
+ }
+ list_splice(&sorted_devices, &pci_devices);
+ up_write(&pci_bus_sem);
+}
+
+void __init pci_sort_breadthfirst(void)
+{
+ pci_sort_breadthfirst_devices();
+ pci_sort_breadthfirst_klist();
+}
+
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index def78a2a7c15..e8a7f1b1b2bc 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -93,8 +93,21 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev)
pci_pci_problems |= PCIPCI_FAIL;
}
}
+
+static void __devinit quirk_nopciamd(struct pci_dev *dev)
+{
+ u8 rev;
+ pci_read_config_byte(dev, 0x08, &rev);
+ if (rev == 0x13) {
+ /* Erratum 24 */
+ printk(KERN_INFO "Chipset erratum: Disabling direct PCI/AGP transfers.\n");
+ pci_pci_problems |= PCIAGP_FAIL;
+ }
+}
+
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci );
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8151_0, quirk_nopciamd );
/*
* Triton requires workarounds to be used by the drivers
@@ -440,6 +453,12 @@ static void __devinit quirk_ich6_lpc_acpi(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0, quirk_ich6_lpc_acpi );
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_31, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_0, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_2, quirk_ich6_lpc_acpi );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_3, quirk_ich6_lpc_acpi );
/*
* VIA ACPI: One IO region pointed to by longword at
@@ -555,7 +574,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237, quirk_via_vt
* is currently marked NoFix
*
* We have multiple reports of hangs with this chipset that went away with
- * noapic specified. For the moment we assume its the errata. We may be wrong
+ * noapic specified. For the moment we assume it's the erratum. We may be wrong
* of course. However the advice is demonstrably good even if so..
*/
static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
@@ -564,7 +583,7 @@ static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
if (rev >= 0x02) {
- printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n");
+ printk(KERN_WARNING "I/O APIC: AMD Erratum #22 may be present. In the event of instability try\n");
printk(KERN_WARNING " : booting with the \"noapic\" option.\n");
}
}
@@ -577,8 +596,6 @@ static void __init quirk_ioapic_rmw(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw );
-int pci_msi_quirk;
-
#define AMD8131_revA0 0x01
#define AMD8131_revB0 0x11
#define AMD8131_MISC 0x40
@@ -587,12 +604,6 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
{
unsigned char revid, tmp;
- if (dev->subordinate) {
- printk(KERN_WARNING "PCI: MSI quirk detected. "
- "PCI_BUS_FLAGS_NO_MSI set for subordinate bus.\n");
- dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
- }
-
if (nr_ioapics == 0)
return;
@@ -605,13 +616,6 @@ static void __init quirk_amd_8131_ioapic(struct pci_dev *dev)
}
}
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_amd_8131_ioapic);
-
-static void __init quirk_svw_msi(struct pci_dev *dev)
-{
- pci_msi_quirk = 1;
- printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi );
#endif /* CONFIG_X86_IO_APIC */
@@ -650,11 +654,43 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_vi
* Some of the on-chip devices are actually '586 devices' so they are
* listed here.
*/
+
+static int via_irq_fixup_needed = -1;
+
+/*
+ * As some VIA hardware is available in PCI-card form, we need to restrict
+ * this quirk to VIA PCI hardware built onto VIA-based motherboards only.
+ * We try to locate a VIA southbridge before deciding whether the quirk
+ * should be applied.
+ */
+static const struct pci_device_id via_irq_fixup_tbl[] = {
+ {
+ .vendor = PCI_VENDOR_ID_VIA,
+ .device = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .class = PCI_CLASS_BRIDGE_ISA << 8,
+ .class_mask = 0xffff00,
+ },
+ { 0, },
+};
+
static void quirk_via_irq(struct pci_dev *dev)
{
u8 irq, new_irq;
- new_irq = dev->irq & 0xf;
+ if (via_irq_fixup_needed == -1)
+ via_irq_fixup_needed = pci_dev_present(via_irq_fixup_tbl);
+
+ if (!via_irq_fixup_needed)
+ return;
+
+ new_irq = dev->irq;
+
+ /* Don't quirk interrupts outside the legacy IRQ range */
+ if (!new_irq || new_irq > 15)
+ return;
+
pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
if (new_irq != irq) {
printk(KERN_INFO "PCI: VIA IRQ fixup for %s, from %d to %d\n",
@@ -663,14 +699,7 @@ static void quirk_via_irq(struct pci_dev *dev)
pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq);
}
}
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_0, quirk_via_irq);
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_1, quirk_via_irq);
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irq);
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_irq);
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8235_USB_2, quirk_via_irq);
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_irq);
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_irq);
-DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irq);
+DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
/*
* VIA VT82C598 has its device ID settable and many BIOSes
@@ -1590,6 +1619,51 @@ static void __devinit fixup_rev1_53c810(struct pci_dev* dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810);
+/*
+ * Fixup to mark boot BIOS video selected by BIOS before it changes
+ *
+ * From information provided by "Jon Smirl" <jonsmirl@gmail.com>
+ *
+ * The standard boot ROM sequence for an x86 machine uses the BIOS
+ * to select an initial video card for boot display. This boot video
+ * card will have it's BIOS copied to C0000 in system RAM.
+ * IORESOURCE_ROM_SHADOW is used to associate the boot video
+ * card with this copy. On laptops this copy has to be used since
+ * the main ROM may be compressed or combined with another image.
+ * See pci_map_rom() for use of this flag. IORESOURCE_ROM_SHADOW
+ * is marked here since the boot video device will be the only enabled
+ * video device at this point.
+ */
+
+static void __devinit fixup_video(struct pci_dev *pdev)
+{
+ struct pci_dev *bridge;
+ struct pci_bus *bus;
+ u16 config;
+
+ if ((pdev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+ return;
+
+ /* Is VGA routed to us? */
+ bus = pdev->bus;
+ while (bus) {
+ bridge = bus->self;
+ if (bridge) {
+ pci_read_config_word(bridge, PCI_BRIDGE_CONTROL,
+ &config);
+ if (!(config & PCI_BRIDGE_CTL_VGA))
+ return;
+ }
+ bus = bus->parent;
+ }
+ pci_read_config_word(pdev, PCI_COMMAND, &config);
+ if (config & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) {
+ pdev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_SHADOW;
+ printk(KERN_DEBUG "Boot video device is %s\n", pci_name(pdev));
+ }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, fixup_video);
+
static void pci_do_fixups(struct pci_dev *dev, struct pci_fixup *f, struct pci_fixup *end)
{
@@ -1690,6 +1764,96 @@ static void __devinit quirk_nvidia_ck804_pcie_aer_ext_cap(struct pci_dev *dev)
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
quirk_nvidia_ck804_pcie_aer_ext_cap);
+#ifdef CONFIG_PCI_MSI
+/* To disable MSI globally */
+int pci_msi_quirk;
+
+/* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
+ * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
+ * some other busses controlled by the chipset even if Linux is not aware of it.
+ * Instead of setting the flag on all busses in the machine, simply disable MSI
+ * globally.
+ */
+static void __init quirk_svw_msi(struct pci_dev *dev)
+{
+ pci_msi_quirk = 1;
+ printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
+
+/* Disable MSI on chipsets that are known to not support it */
+static void __devinit quirk_disable_msi(struct pci_dev *dev)
+{
+ if (dev->subordinate) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "PCI_BUS_FLAGS_NO_MSI set for %s subordinate bus.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8131_BRIDGE, quirk_disable_msi);
+
+/* Go through the list of Hypertransport capabilities and
+ * return 1 if a HT MSI capability is found and enabled */
+static int __devinit msi_ht_cap_enabled(struct pci_dev *dev)
+{
+ u8 pos;
+ int ttl;
+ for (pos = pci_find_capability(dev, PCI_CAP_ID_HT), ttl = 48;
+ pos && ttl;
+ pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_HT), ttl--) {
+ u32 cap_hdr;
+ /* MSI mapping section according to Hypertransport spec */
+ if (pci_read_config_dword(dev, pos, &cap_hdr) == 0
+ && (cap_hdr & 0xf8000000) == 0xa8000000 /* MSI mapping */) {
+ printk(KERN_INFO "PCI: Found HT MSI mapping on %s with capability %s\n",
+ pci_name(dev), cap_hdr & 0x10000 ? "enabled" : "disabled");
+ return (cap_hdr & 0x10000) != 0; /* MSI mapping cap enabled */
+ }
+ }
+ return 0;
+}
+
+/* Check the hypertransport MSI mapping to know whether MSI is enabled or not */
+static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
+{
+ if (dev->subordinate && !msi_ht_cap_enabled(dev)) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "MSI disabled on chipset %s.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
+ quirk_msi_ht_cap);
+
+/* The nVidia CK804 chipset may have 2 HT MSI mappings.
+ * MSI are supported if the MSI capability set in any of these mappings.
+ */
+static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
+{
+ struct pci_dev *pdev;
+
+ if (!dev->subordinate)
+ return;
+
+ /* check HT MSI cap on this chipset and the root one.
+ * a single one having MSI is enough to be sure that MSI are supported.
+ */
+ pdev = pci_get_slot(dev->bus, 0);
+ if (dev->subordinate && !msi_ht_cap_enabled(dev)
+ && !msi_ht_cap_enabled(pdev)) {
+ printk(KERN_WARNING "PCI: MSI quirk detected. "
+ "MSI disabled on chipset %s.\n",
+ pci_name(dev));
+ dev->subordinate->bus_flags |= PCI_BUS_FLAGS_NO_MSI;
+ }
+ pci_dev_put(pdev);
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
+ quirk_nvidia_ck804_msi_ht_cap);
+#endif /* CONFIG_PCI_MSI */
+
EXPORT_SYMBOL(pcie_mch_quirk);
#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_fixup_device);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 99ffbd478b29..430281b2e921 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -16,8 +16,11 @@ static void pci_free_resources(struct pci_dev *dev)
}
}
-static void pci_destroy_dev(struct pci_dev *dev)
+static void pci_stop_dev(struct pci_dev *dev)
{
+ if (!dev->global_list.next)
+ return;
+
if (!list_empty(&dev->global_list)) {
pci_proc_detach_device(dev);
pci_remove_sysfs_dev_files(dev);
@@ -27,6 +30,11 @@ static void pci_destroy_dev(struct pci_dev *dev)
dev->global_list.next = dev->global_list.prev = NULL;
up_write(&pci_bus_sem);
}
+}
+
+static void pci_destroy_dev(struct pci_dev *dev)
+{
+ pci_stop_dev(dev);
/* Remove the device from the device lists, and prevent any further
* list accesses from this device */
@@ -119,5 +127,32 @@ void pci_remove_behind_bridge(struct pci_dev *dev)
}
}
+static void pci_stop_bus_devices(struct pci_bus *bus)
+{
+ struct list_head *l, *n;
+
+ list_for_each_safe(l, n, &bus->devices) {
+ struct pci_dev *dev = pci_dev_b(l);
+ pci_stop_bus_device(dev);
+ }
+}
+
+/**
+ * pci_stop_bus_device - stop a PCI device and any children
+ * @dev: the device to stop
+ *
+ * Stop a PCI device (detach the driver, remove from the global list
+ * and so on). This also stop any subordinate buses and children in a
+ * depth-first manner.
+ */
+void pci_stop_bus_device(struct pci_dev *dev)
+{
+ if (dev->subordinate)
+ pci_stop_bus_devices(dev->subordinate);
+
+ pci_stop_dev(dev);
+}
+
EXPORT_SYMBOL(pci_remove_bus_device);
EXPORT_SYMBOL(pci_remove_behind_bridge);
+EXPORT_SYMBOL_GPL(pci_stop_bus_device);
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index f5ee7ce16fa6..43e4a49f2cc4 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -71,7 +71,10 @@ void __iomem *pci_map_rom(struct pci_dev *pdev, size_t *size)
void __iomem *image;
int last_image;
- /* IORESOURCE_ROM_SHADOW only set on x86 */
+ /*
+ * IORESOURCE_ROM_SHADOW set if the VGA enable bit of the Bridge Control
+ * register is set for embedded VGA.
+ */
if (res->flags & IORESOURCE_ROM_SHADOW) {
/* primary video rom always starts here */
start = (loff_t)0xC0000;
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index d529462d1b53..2f13eba5d5ae 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -140,6 +140,31 @@ struct pci_dev * pci_get_slot(struct pci_bus *bus, unsigned int devfn)
}
/**
+ * pci_get_bus_and_slot - locate PCI device from a given PCI slot
+ * @bus: number of PCI bus on which desired PCI device resides
+ * @devfn: encodes number of PCI slot in which the desired PCI
+ * device resides and the logical device number within that slot
+ * in case of multi-function devices.
+ *
+ * Given a PCI bus and slot/function number, the desired PCI device
+ * is located in system global list of PCI devices. If the device
+ * is found, a pointer to its data structure is returned. If no
+ * device is found, %NULL is returned. The returned device has its
+ * reference count bumped by one.
+ */
+
+struct pci_dev * pci_get_bus_and_slot(unsigned int bus, unsigned int devfn)
+{
+ struct pci_dev *dev = NULL;
+
+ while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+ if (dev->bus->number == bus && dev->devfn == devfn)
+ return dev;
+ }
+ return NULL;
+}
+
+/**
* pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
* @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
* @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
@@ -274,6 +299,45 @@ pci_get_device(unsigned int vendor, unsigned int device, struct pci_dev *from)
return pci_get_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}
+/**
+ * pci_get_device_reverse - begin or continue searching for a PCI device by vendor/device id
+ * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
+ * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
+ * @from: Previous PCI device found in search, or %NULL for new search.
+ *
+ * Iterates through the list of known PCI devices in the reverse order of
+ * pci_get_device.
+ * If a PCI device is found with a matching @vendor and @device, the reference
+ * count to the device is incremented and a pointer to its device structure
+ * is returned Otherwise, %NULL is returned. A new search is initiated by
+ * passing %NULL as the @from argument. Otherwise if @from is not %NULL,
+ * searches continue from next device on the global list. The reference
+ * count for @from is always decremented if it is not %NULL.
+ */
+struct pci_dev *
+pci_get_device_reverse(unsigned int vendor, unsigned int device, struct pci_dev *from)
+{
+ struct list_head *n;
+ struct pci_dev *dev;
+
+ WARN_ON(in_interrupt());
+ down_read(&pci_bus_sem);
+ n = from ? from->global_list.prev : pci_devices.prev;
+
+ while (n && (n != &pci_devices)) {
+ dev = pci_dev_g(n);
+ if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
+ (device == PCI_ANY_ID || dev->device == device))
+ goto exit;
+ n = n->prev;
+ }
+ dev = NULL;
+exit:
+ dev = pci_dev_get(dev);
+ up_read(&pci_bus_sem);
+ pci_dev_put(from);
+ return dev;
+}
/**
* pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
@@ -382,12 +446,16 @@ exit:
}
EXPORT_SYMBOL(pci_dev_present);
-EXPORT_SYMBOL(pci_find_bus);
-EXPORT_SYMBOL(pci_find_next_bus);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_device_reverse);
EXPORT_SYMBOL(pci_find_slot);
+/* For boot time work */
+EXPORT_SYMBOL(pci_find_bus);
+EXPORT_SYMBOL(pci_find_next_bus);
+/* For everyone */
EXPORT_SYMBOL(pci_get_device);
+EXPORT_SYMBOL(pci_get_device_reverse);
EXPORT_SYMBOL(pci_get_subsys);
EXPORT_SYMBOL(pci_get_slot);
+EXPORT_SYMBOL(pci_get_bus_and_slot);
EXPORT_SYMBOL(pci_get_class);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 47c1071ad84e..8f7bcf56f149 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -57,10 +57,17 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
/* Don't touch classless devices or host bridges or ioapics. */
if (class == PCI_CLASS_NOT_DEFINED ||
- class == PCI_CLASS_BRIDGE_HOST ||
- class == PCI_CLASS_SYSTEM_PIC)
+ class == PCI_CLASS_BRIDGE_HOST)
continue;
+ /* Don't touch ioapic devices already enabled by firmware */
+ if (class == PCI_CLASS_SYSTEM_PIC) {
+ u16 command;
+ pci_read_config_word(dev, PCI_COMMAND, &command);
+ if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
+ continue;
+ }
+
pdev_sort_resources(dev, &head);
}
diff --git a/drivers/pcmcia/at91_cf.c b/drivers/pcmcia/at91_cf.c
index 40569f40e90e..7f5df9a9f393 100644
--- a/drivers/pcmcia/at91_cf.c
+++ b/drivers/pcmcia/at91_cf.c
@@ -64,9 +64,9 @@ static int at91_cf_ss_init(struct pcmcia_socket *s)
return 0;
}
-static irqreturn_t at91_cf_irq(int irq, void *_cf, struct pt_regs *r)
+static irqreturn_t at91_cf_irq(int irq, void *_cf)
{
- struct at91_cf_socket *cf = (struct at91_cf_socket *) _cf;
+ struct at91_cf_socket *cf = _cf;
if (irq == cf->board->det_pin) {
unsigned present = at91_cf_present(cf);
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 3f6d51d11374..2d7effe7990d 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -138,7 +138,7 @@ int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void
cs_dbg(s, 3, "read_cb_mem(%d, %#x, %u)\n", space, addr, len);
- dev = pci_find_slot(s->cb_dev->subordinate->number, 0);
+ dev = pci_get_slot(s->cb_dev->subordinate, 0);
if (!dev)
goto fail;
@@ -152,6 +152,9 @@ int read_cb_mem(struct pcmcia_socket * s, int space, u_int addr, u_int len, void
}
res = dev->resource + space - 1;
+
+ pci_dev_put(dev);
+
if (!res->flags)
goto fail;
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index ad02629c8be2..caca0dc9d30f 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -650,7 +650,7 @@ static int hs_set_mem_map(struct pcmcia_socket *s, struct pccard_mem_map *mem)
*/
static int hs_irq_demux(int irq, void *dev)
{
- hs_socket_t *sp = (hs_socket_t *)dev;
+ hs_socket_t *sp = dev;
u_int cscr;
DPRINTK("hs_irq_demux(irq=%d)\n", irq);
@@ -671,13 +671,12 @@ static int hs_irq_demux(int irq, void *dev)
* Interrupt handling routine.
*/
-static irqreturn_t hs_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t hs_interrupt(int irq, void *dev)
{
- hs_socket_t *sp = (hs_socket_t *)dev;
+ hs_socket_t *sp = dev;
u_int events = 0;
u_int cscr;
-
-
+
cscr = hs_in(sp, CSCR);
DPRINTK("hs_interrupt, cscr=%04x\n", cscr);
diff --git a/drivers/pcmcia/i82092.c b/drivers/pcmcia/i82092.c
index 2163aa75a257..82715f448957 100644
--- a/drivers/pcmcia/i82092.c
+++ b/drivers/pcmcia/i82092.c
@@ -315,7 +315,7 @@ static int to_cycles(int ns)
/* Interrupt handler functionality */
-static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t i82092aa_interrupt(int irq, void *dev)
{
int i;
int loopcount = 0;
diff --git a/drivers/pcmcia/i82092aa.h b/drivers/pcmcia/i82092aa.h
index 9c14599d0673..b0d453303c5d 100644
--- a/drivers/pcmcia/i82092aa.h
+++ b/drivers/pcmcia/i82092aa.h
@@ -23,7 +23,7 @@
static int i82092aa_pci_probe(struct pci_dev *dev, const struct pci_device_id *id);
static void i82092aa_pci_remove(struct pci_dev *dev);
static int card_present(int socketno);
-static irqreturn_t i82092aa_interrupt(int irq, void *dev, struct pt_regs *regs);
+static irqreturn_t i82092aa_interrupt(int irq, void *dev);
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 1cc2682394b1..ea74f98a7350 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -80,7 +80,7 @@ module_param(pc_debug, int, 0644);
#define debug(lvl, fmt, arg...) do { } while (0)
#endif
-static irqreturn_t i365_count_irq(int, void *, struct pt_regs *);
+static irqreturn_t i365_count_irq(int, void *);
static inline int _check_irq(int irq, int flags)
{
if (request_irq(irq, i365_count_irq, flags, "x", i365_count_irq) != 0)
@@ -498,7 +498,7 @@ static u_int __init set_bridge_opts(u_short s, u_short ns)
static volatile u_int irq_hits;
static u_short irq_sock;
-static irqreturn_t i365_count_irq(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t i365_count_irq(int irq, void *dev)
{
i365_get(irq_sock, I365_CSC);
irq_hits++;
@@ -848,8 +848,7 @@ static void __init isa_probe(void)
/*====================================================================*/
-static irqreturn_t pcic_interrupt(int irq, void *dev,
- struct pt_regs *regs)
+static irqreturn_t pcic_interrupt(int irq, void *dev)
{
int i, j, csc;
u_int events, active;
@@ -898,7 +897,7 @@ static irqreturn_t pcic_interrupt(int irq, void *dev,
static void pcic_interrupt_wrapper(u_long data)
{
- pcic_interrupt(0, NULL, NULL);
+ pcic_interrupt(0, NULL);
poll_timer.expires = jiffies + poll_interval;
add_timer(&poll_timer);
}
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index 9e768eaef17a..36fdaa58458c 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -254,7 +254,7 @@ static pcc_t pcc[] = {
#endif /* CONFIG_PLAT_USRV */
};
-static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t pcc_interrupt(int, void *);
/*====================================================================*/
@@ -372,14 +372,13 @@ static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr
/*====================================================================*/
-static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t pcc_interrupt(int irq, void *dev)
{
int i;
u_int events = 0;
int handled = 0;
- debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p, regs=%p\n",
- irq, dev, regs);
+ debug(3, "m32r_cfc: pcc_interrupt: irq=%d, dev=%p\n", irq, dev);
for (i = 0; i < pcc_sockets; i++) {
if (socket[i].cs_irq1 != irq && socket[i].cs_irq2 != irq)
continue;
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index 61d50b5620dd..bbf025874d0c 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -267,7 +267,7 @@ static pcc_t pcc[] = {
{ "xnux2", 0 }, { "xnux2", 0 },
};
-static irqreturn_t pcc_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t pcc_interrupt(int, void *);
/*====================================================================*/
@@ -352,7 +352,7 @@ static void add_pcc_socket(ulong base, int irq, ulong mapaddr, kio_addr_t ioaddr
/*====================================================================*/
-static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t pcc_interrupt(int irq, void *dev)
{
int i, j, irc;
u_int events, active;
@@ -395,7 +395,7 @@ static irqreturn_t pcc_interrupt(int irq, void *dev, struct pt_regs *regs)
static void pcc_interrupt_wrapper(u_long data)
{
- pcc_interrupt(0, NULL, NULL);
+ pcc_interrupt(0, NULL);
init_timer(&poll_timer);
poll_timer.expires = jiffies + poll_interval;
add_timer(&poll_timer);
diff --git a/drivers/pcmcia/m8xx_pcmcia.c b/drivers/pcmcia/m8xx_pcmcia.c
index d0f68ab8f041..e070a2896769 100644
--- a/drivers/pcmcia/m8xx_pcmcia.c
+++ b/drivers/pcmcia/m8xx_pcmcia.c
@@ -266,7 +266,7 @@ static const u32 m8xx_size_to_gray[M8XX_SIZES_NO] =
/* ------------------------------------------------------------------------- */
-static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs);
+static irqreturn_t m8xx_interrupt(int irq, void *dev);
#define PCMCIA_BMT_LIMIT (15*4) /* Bus Monitor Timeout value */
@@ -646,7 +646,7 @@ static struct platform_device m8xx_device = {
static u32 pending_events[PCMCIA_SOCKETS_NO];
static DEFINE_SPINLOCK(pending_event_lock);
-static irqreturn_t m8xx_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t m8xx_interrupt(int irq, void *dev)
{
struct socket_info *s;
struct event_table *e;
diff --git a/drivers/pcmcia/omap_cf.c b/drivers/pcmcia/omap_cf.c
index 420e10aec0ae..c8e838c69766 100644
--- a/drivers/pcmcia/omap_cf.c
+++ b/drivers/pcmcia/omap_cf.c
@@ -67,6 +67,7 @@ struct omap_cf_socket {
struct platform_device *pdev;
unsigned long phys_cf;
u_int irq;
+ struct resource iomem;
};
#define POLL_INTERVAL (2 * HZ)
@@ -101,7 +102,7 @@ static void omap_cf_timer(unsigned long _cf)
* claim the card's IRQ. It may also detect some card insertions, but
* not removals; it can't always eliminate timer irqs.
*/
-static irqreturn_t omap_cf_irq(int irq, void *_cf, struct pt_regs *r)
+static irqreturn_t omap_cf_irq(int irq, void *_cf)
{
omap_cf_timer((unsigned long)_cf);
return IRQ_HANDLED;
@@ -112,16 +113,14 @@ static int omap_cf_get_status(struct pcmcia_socket *s, u_int *sp)
if (!sp)
return -EINVAL;
- /* FIXME power management should probably be board-specific:
- * - 3VCARD vs XVCARD (OSK only handles 3VCARD)
- * - POWERON (switched on/off by set_socket)
- */
+ /* NOTE CF is always 3VCARD */
if (omap_cf_present()) {
struct omap_cf_socket *cf;
*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
cf = container_of(s, struct omap_cf_socket, socket);
- s->irq.AssignedIRQ = cf->irq;
+ s->irq.AssignedIRQ = 0;
+ s->pci_irq = cf->irq;
} else
*sp = 0;
return 0;
@@ -132,7 +131,7 @@ omap_cf_set_socket(struct pcmcia_socket *sock, struct socket_state_t *s)
{
u16 control;
- /* FIXME some non-OSK boards will support power switching */
+ /* REVISIT some non-OSK boards may support power switching */
switch (s->Vcc) {
case 0:
case 33:
@@ -204,7 +203,7 @@ static struct pccard_operations omap_cf_ops = {
* "what chipselect is used". Boards could want more.
*/
-static int __init omap_cf_probe(struct device *dev)
+static int __devinit omap_cf_probe(struct device *dev)
{
unsigned seg;
struct omap_cf_socket *cf;
@@ -253,6 +252,9 @@ static int __init omap_cf_probe(struct device *dev)
default:
goto fail1;
}
+ cf->iomem.start = cf->phys_cf;
+ cf->iomem.end = cf->iomem.end + SZ_8K - 1;
+ cf->iomem.flags = IORESOURCE_MEM;
/* pcmcia layer only remaps "real" memory */
cf->socket.io_offset = (unsigned long)
@@ -296,6 +298,7 @@ static int __init omap_cf_probe(struct device *dev)
cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP
| SS_CAP_MEM_ALIGN;
cf->socket.map_size = SZ_2K;
+ cf->socket.io[0].res = &cf->iomem;
status = pcmcia_register_socket(&cf->socket);
if (status < 0)
@@ -334,15 +337,15 @@ static struct device_driver omap_cf_driver = {
.bus = &platform_bus_type,
.probe = omap_cf_probe,
.remove = __devexit_p(omap_cf_remove),
- .suspend = pcmcia_socket_dev_suspend,
- .resume = pcmcia_socket_dev_resume,
+ .suspend = pcmcia_socket_dev_suspend,
+ .resume = pcmcia_socket_dev_resume,
};
static int __init omap_cf_init(void)
{
if (cpu_is_omap16xx())
- driver_register(&omap_cf_driver);
- return 0;
+ return driver_register(&omap_cf_driver);
+ return -ENODEV;
}
static void __exit omap_cf_exit(void)
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
index c8323399e9e4..74cebd424032 100644
--- a/drivers/pcmcia/pcmcia_resource.c
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -784,7 +784,7 @@ EXPORT_SYMBOL(pcmcia_request_io);
*/
#ifdef CONFIG_PCMCIA_PROBE
-static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
+static irqreturn_t test_action(int cpl, void *dev_id)
{
return IRQ_NONE;
}
diff --git a/drivers/pcmcia/pd6729.c b/drivers/pcmcia/pd6729.c
index 22c5e7427ddd..c83a0a6b158f 100644
--- a/drivers/pcmcia/pd6729.c
+++ b/drivers/pcmcia/pd6729.c
@@ -182,7 +182,7 @@ static void indirect_write16(struct pd6729_socket *socket, unsigned short reg,
/* Interrupt handler functionality */
-static irqreturn_t pd6729_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t pd6729_interrupt(int irq, void *dev)
{
struct pd6729_socket *socket = (struct pd6729_socket *)dev;
int i;
@@ -249,7 +249,7 @@ static void pd6729_interrupt_wrapper(unsigned long data)
{
struct pd6729_socket *socket = (struct pd6729_socket *) data;
- pd6729_interrupt(0, (void *)socket, NULL);
+ pd6729_interrupt(0, (void *)socket);
mod_timer(&socket->poll_timer, jiffies + HZ);
}
@@ -575,7 +575,7 @@ static struct pccard_operations pd6729_operations = {
.set_mem_map = pd6729_set_mem_map,
};
-static irqreturn_t pd6729_test(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t pd6729_test(int irq, void *dev)
{
dprintk("-> hit on irq %d\n", irq);
return IRQ_HANDLED;
diff --git a/drivers/pcmcia/soc_common.c b/drivers/pcmcia/soc_common.c
index ecaa132fa592..3627e52e0c27 100644
--- a/drivers/pcmcia/soc_common.c
+++ b/drivers/pcmcia/soc_common.c
@@ -256,7 +256,7 @@ static void soc_common_pcmcia_poll_event(unsigned long dummy)
* handling code performs scheduling operations which cannot be
* executed from within an interrupt context.
*/
-static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t soc_common_pcmcia_interrupt(int irq, void *dev)
{
struct soc_pcmcia_socket *skt = dev;
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index c5d7476da471..933cd864a5c9 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -298,7 +298,7 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
{
struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
cisdump_t *cis;
- ssize_t ret = count;
+ int error;
if (off)
return -EINVAL;
@@ -316,25 +316,22 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
cis->Length = count + 1;
memcpy(cis->Data, buf, count);
- if (pcmcia_replace_cis(s, cis))
- ret = -EIO;
-
+ error = pcmcia_replace_cis(s, cis);
kfree(cis);
+ if (error)
+ return -EIO;
- if (!ret) {
- mutex_lock(&s->skt_mutex);
- if ((s->callback) && (s->state & SOCKET_PRESENT) &&
- !(s->state & SOCKET_CARDBUS)) {
- if (try_module_get(s->callback->owner)) {
- s->callback->requery(s);
- module_put(s->callback->owner);
- }
+ mutex_lock(&s->skt_mutex);
+ if ((s->callback) && (s->state & SOCKET_PRESENT) &&
+ !(s->state & SOCKET_CARDBUS)) {
+ if (try_module_get(s->callback->owner)) {
+ s->callback->requery(s);
+ module_put(s->callback->owner);
}
- mutex_unlock(&s->skt_mutex);
}
+ mutex_unlock(&s->skt_mutex);
-
- return (ret);
+ return count;
}
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index 65a60671659f..2d2f415f80a8 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -116,7 +116,7 @@ module_param(cycle_time, int, 0444);
/*====================================================================*/
-static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs);
+static irqreturn_t tcic_interrupt(int irq, void *dev);
static void tcic_timer(u_long data);
static struct pccard_operations tcic_operations;
@@ -218,7 +218,7 @@ static int to_cycles(int ns)
static volatile u_int irq_hits;
-static irqreturn_t __init tcic_irq_count(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t __init tcic_irq_count(int irq, void *dev)
{
irq_hits++;
return IRQ_HANDLED;
@@ -505,7 +505,7 @@ static int __init init_tcic(void)
}
/* jump start interrupt handler, if needed */
- tcic_interrupt(0, NULL, NULL);
+ tcic_interrupt(0, NULL);
platform_device_register(&tcic_device);
@@ -547,7 +547,7 @@ static void __exit exit_tcic(void)
/*====================================================================*/
-static irqreturn_t tcic_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t tcic_interrupt(int irq, void *dev)
{
int i, quick = 0;
u_char latch, sstat;
@@ -606,7 +606,7 @@ static void tcic_timer(u_long data)
{
debug(2, "tcic_timer()\n");
tcic_timer_pending = 0;
- tcic_interrupt(0, NULL, NULL);
+ tcic_interrupt(0, NULL);
} /* tcic_timer */
/*====================================================================*/
diff --git a/drivers/pcmcia/vrc4171_card.c b/drivers/pcmcia/vrc4171_card.c
index e076a13db555..e90d8e8c5fd6 100644
--- a/drivers/pcmcia/vrc4171_card.c
+++ b/drivers/pcmcia/vrc4171_card.c
@@ -514,7 +514,7 @@ static inline unsigned int get_events(int slot)
return events;
}
-static irqreturn_t pccard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pccard_interrupt(int irq, void *dev_id)
{
vrc4171_socket_t *socket;
unsigned int events;
diff --git a/drivers/pcmcia/vrc4173_cardu.c b/drivers/pcmcia/vrc4173_cardu.c
index d19a9138135f..812f038e9bda 100644
--- a/drivers/pcmcia/vrc4173_cardu.c
+++ b/drivers/pcmcia/vrc4173_cardu.c
@@ -440,7 +440,7 @@ static uint16_t get_events(vrc4173_socket_t *socket)
return events;
}
-static void cardu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void cardu_interrupt(int irq, void *dev_id)
{
vrc4173_socket_t *socket = (vrc4173_socket_t *)dev_id;
uint16_t events;
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index 1344746381e8..26229d9da762 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -442,7 +442,7 @@ static int yenta_set_mem_map(struct pcmcia_socket *sock, struct pccard_mem_map *
-static irqreturn_t yenta_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t yenta_interrupt(int irq, void *dev_id)
{
unsigned int events;
struct yenta_socket *socket = (struct yenta_socket *) dev_id;
@@ -478,7 +478,7 @@ static void yenta_interrupt_wrapper(unsigned long data)
{
struct yenta_socket *socket = (struct yenta_socket *) data;
- yenta_interrupt(0, (void *)socket, NULL);
+ yenta_interrupt(0, (void *)socket);
socket->poll_timer.expires = jiffies + HZ;
add_timer(&socket->poll_timer);
}
@@ -896,7 +896,7 @@ static unsigned int yenta_probe_irq(struct yenta_socket *socket, u32 isa_irq_mas
#ifdef CONFIG_YENTA_TI
/* interrupt handler, only used during probing */
-static irqreturn_t yenta_probe_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t yenta_probe_handler(int irq, void *dev_id)
{
struct yenta_socket *socket = (struct yenta_socket *) dev_id;
u8 csc;
diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c
index f2e0179962e2..3ac5b123215a 100644
--- a/drivers/pnp/isapnp/core.c
+++ b/drivers/pnp/isapnp/core.c
@@ -1049,6 +1049,10 @@ static int __init isapnp_init(void)
printk(KERN_INFO "isapnp: ISA Plug & Play support disabled\n");
return 0;
}
+#ifdef CONFIG_PPC_MERGE
+ if (check_legacy_ioport(_PIDXR) || check_legacy_ioport(_PNPWRP))
+ return -EINVAL;
+#endif
#ifdef ISAPNP_REGION_OK
if (!request_region(_PIDXR, 1, "isapnp index")) {
printk(KERN_ERR "isapnp: Index Register 0x%x already used\n", _PIDXR);
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index dc79b0a0059f..379048fdf05d 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -776,21 +776,32 @@ static void pnpacpi_encode_dma(struct acpi_resource *resource,
struct resource *p)
{
/* Note: pnp_assign_dma will copy pnp_dma->flags into p->flags */
- if (p->flags & IORESOURCE_DMA_COMPATIBLE)
- resource->data.dma.type = ACPI_COMPATIBILITY;
- else if (p->flags & IORESOURCE_DMA_TYPEA)
- resource->data.dma.type = ACPI_TYPE_A;
- else if (p->flags & IORESOURCE_DMA_TYPEB)
- resource->data.dma.type = ACPI_TYPE_B;
- else if (p->flags & IORESOURCE_DMA_TYPEF)
- resource->data.dma.type = ACPI_TYPE_F;
- if (p->flags & IORESOURCE_DMA_8BIT)
- resource->data.dma.transfer = ACPI_TRANSFER_8;
- else if (p->flags & IORESOURCE_DMA_8AND16BIT)
- resource->data.dma.transfer = ACPI_TRANSFER_8_16;
- else if (p->flags & IORESOURCE_DMA_16BIT)
- resource->data.dma.transfer = ACPI_TRANSFER_16;
- resource->data.dma.bus_master = p->flags & IORESOURCE_DMA_MASTER;
+ switch (p->flags & IORESOURCE_DMA_SPEED_MASK) {
+ case IORESOURCE_DMA_TYPEA:
+ resource->data.dma.type = ACPI_TYPE_A;
+ break;
+ case IORESOURCE_DMA_TYPEB:
+ resource->data.dma.type = ACPI_TYPE_B;
+ break;
+ case IORESOURCE_DMA_TYPEF:
+ resource->data.dma.type = ACPI_TYPE_F;
+ break;
+ default:
+ resource->data.dma.type = ACPI_COMPATIBILITY;
+ }
+
+ switch (p->flags & IORESOURCE_DMA_TYPE_MASK) {
+ case IORESOURCE_DMA_8BIT:
+ resource->data.dma.transfer = ACPI_TRANSFER_8;
+ break;
+ case IORESOURCE_DMA_8AND16BIT:
+ resource->data.dma.transfer = ACPI_TRANSFER_8_16;
+ break;
+ default:
+ resource->data.dma.transfer = ACPI_TRANSFER_16;
+ }
+
+ resource->data.dma.bus_master = !!(p->flags & IORESOURCE_DMA_MASTER);
resource->data.dma.channel_count = 1;
resource->data.dma.channels[0] = p->start;
}
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 551f58e29810..81a6c83d89a6 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -526,6 +526,10 @@ static int __init pnpbios_init(void)
{
int ret;
+#if defined(CONFIG_PPC_MERGE)
+ if (check_legacy_ioport(PNPBIOS_BASE))
+ return -ENODEV;
+#endif
if (pnpbios_disabled || dmi_check_system(pnpbios_dmi_table)) {
printk(KERN_INFO "PnPBIOS: Disabled\n");
return -ENODEV;
@@ -575,6 +579,10 @@ subsys_initcall(pnpbios_init);
static int __init pnpbios_thread_init(void)
{
+#if defined(CONFIG_PPC_MERGE)
+ if (check_legacy_ioport(PNPBIOS_BASE))
+ return 0;
+#endif
if (pnpbios_disabled)
return 0;
#ifdef CONFIG_HOTPLUG
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 5c8ec21e1086..a685fbec4604 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -348,7 +348,7 @@ int pnp_check_mem(struct pnp_dev * dev, int idx)
return 1;
}
-static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pnp_test_handler(int irq, void *dev_id)
{
return IRQ_HANDLED;
}
diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
index 0b2d2c3579a7..4142115d298e 100644
--- a/drivers/rapidio/Kconfig
+++ b/drivers/rapidio/Kconfig
@@ -15,4 +15,4 @@ config RAPIDIO_DISC_TIMEOUT
default "30"
---help---
Amount of time a discovery node waits for a host to complete
- enumeration beforing giving up.
+ enumeration before giving up.
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 7ff1d88094b6..fc766a7a611e 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -27,7 +27,7 @@ config RTC_HCTOSYS
help
If you say yes here, the system time will be set using
the value read from the specified RTC device. This is useful
- in order to avoid unnecessary fschk runs.
+ in order to avoid unnecessary fsck runs.
config RTC_HCTOSYS_DEVICE
string "The RTC to read the time from"
@@ -37,6 +37,13 @@ config RTC_HCTOSYS_DEVICE
The RTC device that will be used as the source for
the system time, usually rtc0.
+config RTC_DEBUG
+ bool "RTC debug support"
+ depends on RTC_CLASS = y
+ help
+ Say yes here to enable debugging support in the RTC framework
+ and individual RTC drivers.
+
comment "RTC interfaces"
depends on RTC_CLASS
@@ -45,8 +52,8 @@ config RTC_INTF_SYSFS
depends on RTC_CLASS && SYSFS
default RTC_CLASS
help
- Say yes here if you want to use your RTC using the sysfs
- interface, /sys/class/rtc/rtcX .
+ Say yes here if you want to use your RTCs using sysfs interfaces,
+ /sys/class/rtc/rtc0 through /sys/.../rtcN.
This driver can also be built as a module. If so, the module
will be called rtc-sysfs.
@@ -56,8 +63,9 @@ config RTC_INTF_PROC
depends on RTC_CLASS && PROC_FS
default RTC_CLASS
help
- Say yes here if you want to use your RTC using the proc
- interface, /proc/driver/rtc .
+ Say yes here if you want to use your first RTC through the proc
+ interface, /proc/driver/rtc. Other RTCs will not be available
+ through that API.
This driver can also be built as a module. If so, the module
will be called rtc-proc.
@@ -67,8 +75,11 @@ config RTC_INTF_DEV
depends on RTC_CLASS
default RTC_CLASS
help
- Say yes here if you want to use your RTC using the dev
- interface, /dev/rtc .
+ Say yes here if you want to use your RTCs using the /dev
+ interfaces, which "udev" sets up as /dev/rtc0 through
+ /dev/rtcN. You may want to set up a symbolic link so one
+ of these can be accessed as /dev/rtc, which is a name
+ expected by "hwclock" and some other programs.
This driver can also be built as a module. If so, the module
will be called rtc-dev.
@@ -78,7 +89,8 @@ config RTC_INTF_DEV_UIE_EMUL
depends on RTC_INTF_DEV
help
Provides an emulation for RTC_UIE if the underlaying rtc chip
- driver did not provide RTC_UIE ioctls.
+ driver does not expose RTC_UIE ioctls. Those requests generate
+ once-per-second update interrupts, used for synchronization.
comment "RTC drivers"
depends on RTC_CLASS
@@ -238,6 +250,16 @@ config RTC_DRV_SA1100
To compile this driver as a module, choose M here: the
module will be called rtc-sa1100.
+config RTC_DRV_SH
+ tristate "SuperH On-Chip RTC"
+ depends on RTC_CLASS && SUPERH
+ help
+ Say Y here to enable support for the on-chip RTC found in
+ most SuperH processors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called rtc-sh.
+
config RTC_DRV_VR41XX
tristate "NEC VR41XX"
depends on RTC_CLASS && CPU_VR41XX
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index bbcfb09d81d9..3ba5ff6e6800 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -2,6 +2,10 @@
# Makefile for RTC class/drivers.
#
+ifeq ($(CONFIG_RTC_DEBUG),y)
+ EXTRA_CFLAGS += -DDEBUG
+endif
+
obj-$(CONFIG_RTC_LIB) += rtc-lib.o
obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
@@ -31,3 +35,4 @@ obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_AT91) += rtc-at91.o
+obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 1cb61a761cb2..7a0d8ee2de9c 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -39,7 +39,7 @@ static void rtc_device_release(struct class_device *class_dev)
* Returns the pointer to the new struct class device.
*/
struct rtc_device *rtc_device_register(const char *name, struct device *dev,
- struct rtc_class_ops *ops,
+ const struct rtc_class_ops *ops,
struct module *owner)
{
struct rtc_device *rtc;
@@ -142,9 +142,9 @@ static void __exit rtc_exit(void)
class_destroy(rtc_class);
}
-module_init(rtc_init);
+subsys_initcall(rtc_init);
module_exit(rtc_exit);
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>");
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("RTC class support");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-at91.c b/drivers/rtc/rtc-at91.c
index dfd0ce86f6a0..bd61e99540a3 100644
--- a/drivers/rtc/rtc-at91.c
+++ b/drivers/rtc/rtc-at91.c
@@ -238,8 +238,7 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
/*
* IRQ handler for the RTC
*/
-static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -267,7 +266,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id,
return IRQ_NONE; /* not handled */
}
-static struct rtc_class_ops at91_rtc_ops = {
+static const struct rtc_class_ops at91_rtc_ops = {
.ioctl = at91_rtc_ioctl,
.read_time = at91_rtc_readtime,
.set_time = at91_rtc_settime,
@@ -307,6 +306,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return PTR_ERR(rtc);
}
platform_set_drvdata(pdev, rtc);
+ device_init_wakeup(&pdev->dev, 1);
printk(KERN_INFO "AT91 Real Time Clock driver.\n");
return 0;
@@ -327,6 +327,7 @@ static int __devexit at91_rtc_remove(struct platform_device *pdev)
rtc_device_unregister(rtc);
platform_set_drvdata(pdev, NULL);
+ device_init_wakeup(&pdev->dev, 0);
return 0;
}
@@ -336,6 +337,7 @@ static int __devexit at91_rtc_remove(struct platform_device *pdev)
/* AT91RM9200 RTC Power management control */
static struct timespec at91_rtc_delta;
+static u32 at91_rtc_imr;
static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
@@ -349,6 +351,18 @@ static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
rtc_tm_to_time(&tm, &time.tv_sec);
save_time_delta(&at91_rtc_delta, &time);
+ /* this IRQ is shared with DBGU and other hardware which isn't
+ * necessarily doing PM like we are...
+ */
+ at91_rtc_imr = at91_sys_read(AT91_RTC_IMR)
+ & (AT91_RTC_ALARM|AT91_RTC_SECEV);
+ if (at91_rtc_imr) {
+ if (device_may_wakeup(&pdev->dev))
+ enable_irq_wake(AT91_ID_SYS);
+ else
+ at91_sys_write(AT91_RTC_IDR, at91_rtc_imr);
+ }
+
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
@@ -367,6 +381,13 @@ static int at91_rtc_resume(struct platform_device *pdev)
rtc_tm_to_time(&tm, &time.tv_sec);
restore_time_delta(&at91_rtc_delta, &time);
+ if (at91_rtc_imr) {
+ if (device_may_wakeup(&pdev->dev))
+ disable_irq_wake(AT91_ID_SYS);
+ else
+ at91_sys_write(AT91_RTC_IER, at91_rtc_imr);
+ }
+
pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index 61a58259c93f..583789c66cdb 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -24,7 +24,7 @@ static int rtc_dev_open(struct inode *inode, struct file *file)
int err;
struct rtc_device *rtc = container_of(inode->i_cdev,
struct rtc_device, char_dev);
- struct rtc_class_ops *ops = rtc->ops;
+ const struct rtc_class_ops *ops = rtc->ops;
/* We keep the lock as long as the device is in use
* and return immediately if busy
@@ -209,7 +209,7 @@ static int rtc_dev_ioctl(struct inode *inode, struct file *file,
int err = 0;
struct class_device *class_dev = file->private_data;
struct rtc_device *rtc = to_rtc_device(class_dev);
- struct rtc_class_ops *ops = rtc->ops;
+ const struct rtc_class_ops *ops = rtc->ops;
struct rtc_time tm;
struct rtc_wkalrm alarm;
void __user *uarg = (void __user *) arg;
@@ -406,7 +406,6 @@ static int rtc_dev_add_device(struct class_device *class_dev,
rtc->char_dev.owner = rtc->owner;
if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) {
- cdev_del(&rtc->char_dev);
dev_err(class_dev->dev,
"failed to add char device %d:%d\n",
MAJOR(rtc_devt), rtc->id);
@@ -496,7 +495,7 @@ static void __exit rtc_dev_exit(void)
unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
}
-module_init(rtc_dev_init);
+subsys_initcall(rtc_dev_init);
module_exit(rtc_dev_exit);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index e8afb9384786..3f0f7b8fa813 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -141,9 +141,9 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
- "write", dt->tm_sec, dt->tm_min,
- dt->tm_hour, dt->tm_mday,
- dt->tm_mon, dt->tm_year, dt->tm_wday);
+ "write", t->tm_sec, t->tm_min,
+ t->tm_hour, t->tm_mday,
+ t->tm_mon, t->tm_year, t->tm_wday);
*buf++ = 0; /* first register addr */
buf[DS1307_REG_SECS] = BIN2BCD(t->tm_sec);
@@ -178,7 +178,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
return 0;
}
-static struct rtc_class_ops ds13xx_rtc_ops = {
+static const struct rtc_class_ops ds13xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
};
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 209001495474..78552e6e76aa 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -18,7 +18,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#define DRV_VERSION "0.1"
+#define DRV_VERSION "0.2"
#define RTC_REG_SIZE 0x2000
#define RTC_OFFSET 0x1ff0
@@ -189,8 +189,7 @@ static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return 0;
}
-static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
@@ -250,7 +249,7 @@ static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
return 0;
}
-static struct rtc_class_ops ds1553_rtc_ops = {
+static const struct rtc_class_ops ds1553_rtc_ops = {
.read_time = ds1553_rtc_read_time,
.set_time = ds1553_rtc_set_time,
.read_alarm = ds1553_rtc_read_alarm,
@@ -357,9 +356,13 @@ static int __init ds1553_rtc_probe(struct platform_device *pdev)
pdata->rtc = rtc;
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
- sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
+ if (ret)
+ goto out;
return 0;
out:
+ if (pdata->rtc)
+ rtc_device_unregister(pdata->rtc);
if (pdata->irq >= 0)
free_irq(pdata->irq, pdev);
if (ioaddr)
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index 9be81fd4737c..67e816a9a39f 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -55,7 +55,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
}
dev_dbg(&client->dev,
- "%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
+ "%s: raw read data - counters=%02x,%02x,%02x,%02x\n",
__FUNCTION__, buf[0], buf[1], buf[2], buf[3]);
time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
@@ -96,7 +96,7 @@ static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
unsigned long secs;
dev_dbg(&client->dev,
- "%s: secs=%d, mins=%d, hours=%d, ",
+ "%s: 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,
@@ -156,7 +156,7 @@ static ssize_t show_control(struct device *dev, struct device_attribute *attr, c
}
static DEVICE_ATTR(control, S_IRUGO, show_control, NULL);
-static struct rtc_class_ops ds1672_rtc_ops = {
+static const struct rtc_class_ops ds1672_rtc_ops = {
.read_time = ds1672_rtc_read_time,
.set_time = ds1672_rtc_set_time,
.set_mmss = ds1672_rtc_set_mmss,
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 8e47e5a06d2a..6273a3d240a2 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -17,7 +17,7 @@
#include <linux/platform_device.h>
#include <linux/io.h>
-#define DRV_VERSION "0.1"
+#define DRV_VERSION "0.2"
#define RTC_REG_SIZE 0x800
#define RTC_OFFSET 0x7f8
@@ -116,7 +116,7 @@ static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
return 0;
}
-static struct rtc_class_ops ds1742_rtc_ops = {
+static const struct rtc_class_ops ds1742_rtc_ops = {
.read_time = ds1742_rtc_read_time,
.set_time = ds1742_rtc_set_time,
};
@@ -196,7 +196,7 @@ static int __init ds1742_rtc_probe(struct platform_device *pdev)
writeb(sec, ioaddr + RTC_SECONDS);
writeb(cen & RTC_CENTURY_MASK, ioaddr + RTC_CONTROL);
}
- if (readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG)
+ if (!(readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG))
dev_warn(&pdev->dev, "voltage-low detected.\n");
rtc = rtc_device_register(pdev->name, &pdev->dev,
@@ -208,9 +208,13 @@ static int __init ds1742_rtc_probe(struct platform_device *pdev)
pdata->rtc = rtc;
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
- sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr);
+ if (ret)
+ goto out;
return 0;
out:
+ if (pdata->rtc)
+ rtc_device_unregister(pdata->rtc);
if (ioaddr)
iounmap(ioaddr);
if (pdata->baseaddr)
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index e1a1169e4664..ef4f147f3c0c 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -73,7 +73,7 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
-static struct rtc_class_ops ep93xx_rtc_ops = {
+static const struct rtc_class_ops ep93xx_rtc_ops = {
.read_time = ep93xx_rtc_read_time,
.set_time = ep93xx_rtc_set_time,
.set_mmss = ep93xx_rtc_set_mmss,
diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c
index f324d0a635d4..1c743641b73b 100644
--- a/drivers/rtc/rtc-isl1208.c
+++ b/drivers/rtc/rtc-isl1208.c
@@ -390,7 +390,7 @@ static int isl1208_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
return isl1208_i2c_read_alarm(to_i2c_client(dev), alarm);
}
-static struct rtc_class_ops isl1208_rtc_ops = {
+static const struct rtc_class_ops isl1208_rtc_ops = {
.proc = isl1208_rtc_proc,
.read_time = isl1208_rtc_read_time,
.set_time = isl1208_rtc_set_time,
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index 9812120f3a7c..ba795a4db1e9 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -94,12 +94,12 @@ EXPORT_SYMBOL(rtc_time_to_tm);
int rtc_valid_tm(struct rtc_time *tm)
{
if (tm->tm_year < 70
- || tm->tm_mon >= 12
+ || ((unsigned)tm->tm_mon) >= 12
|| tm->tm_mday < 1
|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
- || tm->tm_hour >= 24
- || tm->tm_min >= 60
- || tm->tm_sec >= 60)
+ || ((unsigned)tm->tm_hour) >= 24
+ || ((unsigned)tm->tm_min) >= 60
+ || ((unsigned)tm->tm_sec) >= 60)
return -EINVAL;
return 0;
diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c
index 8c0d1a6739ad..8ff4a1221f59 100644
--- a/drivers/rtc/rtc-m48t86.c
+++ b/drivers/rtc/rtc-m48t86.c
@@ -138,7 +138,7 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
-static struct rtc_class_ops m48t86_rtc_ops = {
+static const struct rtc_class_ops m48t86_rtc_ops = {
.read_time = m48t86_rtc_read_time,
.set_time = m48t86_rtc_set_time,
.proc = m48t86_rtc_proc,
diff --git a/drivers/rtc/rtc-max6902.c b/drivers/rtc/rtc-max6902.c
index 2c9739562b5c..d94170728075 100644
--- a/drivers/rtc/rtc-max6902.c
+++ b/drivers/rtc/rtc-max6902.c
@@ -1,4 +1,4 @@
-/* drivers/char/max6902.c
+/* drivers/rtc/rtc-max6902.c
*
* Copyright (C) 2006 8D Technologies inc.
* Copyright (C) 2004 Compulab Ltd.
@@ -19,7 +19,6 @@
* - Initial driver creation.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
@@ -137,7 +136,7 @@ static int max6902_get_datetime(struct device *dev, struct rtc_time *dt)
dt->tm_min = BCD2BIN(chip->buf[2]);
dt->tm_hour = BCD2BIN(chip->buf[3]);
dt->tm_mday = BCD2BIN(chip->buf[4]);
- dt->tm_mon = BCD2BIN(chip->buf[5] - 1);
+ dt->tm_mon = BCD2BIN(chip->buf[5]) - 1;
dt->tm_wday = BCD2BIN(chip->buf[6]);
dt->tm_year = BCD2BIN(chip->buf[7]);
@@ -207,7 +206,7 @@ static int max6902_set_time(struct device *dev, struct rtc_time *tm)
return max6902_set_datetime(dev, tm);
}
-static struct rtc_class_ops max6902_rtc_ops = {
+static const struct rtc_class_ops max6902_rtc_ops = {
.read_time = max6902_read_time,
.set_time = max6902_set_time,
};
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index ba9a583b7b68..a760cf69af90 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -95,7 +95,7 @@ static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
- + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 100 : 0);
+ + (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 0 : 100);
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -135,7 +135,7 @@ static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
/* year and century */
buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
- if (tm->tm_year / 100)
+ if (tm->tm_year < 100)
buf[PCF8563_REG_MO] |= PCF8563_MO_C;
buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
@@ -227,7 +227,7 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
return pcf8563_set_datetime(to_i2c_client(dev), tm);
}
-static struct rtc_class_ops pcf8563_rtc_ops = {
+static const struct rtc_class_ops pcf8563_rtc_ops = {
.read_time = pcf8563_rtc_read_time,
.set_time = pcf8563_rtc_set_time,
};
diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c
index b235a30cb661..5875ebb8c79d 100644
--- a/drivers/rtc/rtc-pcf8583.c
+++ b/drivers/rtc/rtc-pcf8583.c
@@ -273,7 +273,7 @@ static int pcf8583_rtc_set_time(struct device *dev, struct rtc_time *tm)
return ret;
}
-static struct rtc_class_ops pcf8583_rtc_ops = {
+static const struct rtc_class_ops pcf8583_rtc_ops = {
.read_time = pcf8583_rtc_read_time,
.set_time = pcf8583_rtc_set_time,
};
diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c
index d6d1c5726b0e..f13daa9fecaa 100644
--- a/drivers/rtc/rtc-pl031.c
+++ b/drivers/rtc/rtc-pl031.c
@@ -47,7 +47,7 @@ struct pl031_local {
void __iomem *base;
};
-static irqreturn_t pl031_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pl031_interrupt(int irq, void *dev_id)
{
struct rtc_device *rtc = dev_id;
@@ -128,7 +128,7 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
return 0;
}
-static struct rtc_class_ops pl031_ops = {
+static const struct rtc_class_ops pl031_ops = {
.open = pl031_open,
.release = pl031_release,
.ioctl = pl031_ioctl,
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index cef5f5a3bbf9..d51d8f20e634 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -23,7 +23,7 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
{
int err;
struct class_device *class_dev = seq->private;
- struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
+ const struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
struct rtc_wkalrm alrm;
struct rtc_time tm;
@@ -61,7 +61,7 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
else
seq_printf(seq, "**-");
- if ((unsigned int)alrm.time.tm_mday <= 31)
+ if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31)
seq_printf(seq, "%02d\n", alrm.time.tm_mday);
else
seq_printf(seq, "**\n");
@@ -156,7 +156,7 @@ static void __exit rtc_proc_exit(void)
class_interface_unregister(&rtc_proc_interface);
}
-module_init(rtc_proc_init);
+subsys_initcall(rtc_proc_init);
module_exit(rtc_proc_exit);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c
index 0964d1dba925..f50f3fc353cd 100644
--- a/drivers/rtc/rtc-rs5c348.c
+++ b/drivers/rtc/rtc-rs5c348.c
@@ -23,7 +23,7 @@
#include <linux/workqueue.h>
#include <linux/spi/spi.h>
-#define DRV_VERSION "0.1"
+#define DRV_VERSION "0.2"
#define RS5C348_REG_SECS 0
#define RS5C348_REG_MINS 1
@@ -140,7 +140,7 @@ rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)
return 0;
}
-static struct rtc_class_ops rs5c348_rtc_ops = {
+static const struct rtc_class_ops rs5c348_rtc_ops = {
.read_time = rs5c348_rtc_read_time,
.set_time = rs5c348_rtc_set_time,
};
@@ -175,8 +175,15 @@ static int __devinit rs5c348_probe(struct spi_device *spi)
goto kfree_exit;
if (ret & (RS5C348_BIT_XSTP | RS5C348_BIT_VDET)) {
u8 buf[2];
+ struct rtc_time tm;
if (ret & RS5C348_BIT_VDET)
dev_warn(&spi->dev, "voltage-low detected.\n");
+ if (ret & RS5C348_BIT_XSTP)
+ dev_warn(&spi->dev, "oscillator-stop detected.\n");
+ rtc_time_to_tm(0, &tm); /* 1970/1/1 */
+ ret = rs5c348_rtc_set_time(&spi->dev, &tm);
+ if (ret < 0)
+ goto kfree_exit;
buf[0] = RS5C348_CMD_W(RS5C348_REG_CTL2);
buf[1] = 0;
ret = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c
index 7553d797603f..2a86632580f1 100644
--- a/drivers/rtc/rtc-rs5c372.c
+++ b/drivers/rtc/rtc-rs5c372.c
@@ -91,7 +91,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
unsigned char buf[8] = { RS5C372_REG_BASE };
dev_dbg(&client->dev,
- "%s: secs=%d, mins=%d, hours=%d ",
+ "%s: 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,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
@@ -126,7 +126,7 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
return -EIO;
}
- dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim);
+ dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim);
if (osc)
*osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768;
@@ -160,7 +160,7 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
-static struct rtc_class_ops rs5c372_rtc_ops = {
+static const struct rtc_class_ops rs5c372_rtc_ops = {
.proc = rs5c372_rtc_proc,
.read_time = rs5c372_rtc_read_time,
.set_time = rs5c372_rtc_set_time,
diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c
index 2c7de79c83b9..e301dea57bb3 100644
--- a/drivers/rtc/rtc-s3c.c
+++ b/drivers/rtc/rtc-s3c.c
@@ -46,7 +46,7 @@ static unsigned int tick_count;
/* IRQ Handlers */
-static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
+static irqreturn_t s3c_rtc_alarmirq(int irq, void *id)
{
struct rtc_device *rdev = id;
@@ -54,7 +54,7 @@ static irqreturn_t s3c_rtc_alarmirq(int irq, void *id, struct pt_regs *r)
return IRQ_HANDLED;
}
-static irqreturn_t s3c_rtc_tickirq(int irq, void *id, struct pt_regs *r)
+static irqreturn_t s3c_rtc_tickirq(int irq, void *id)
{
struct rtc_device *rdev = id;
@@ -386,7 +386,7 @@ static void s3c_rtc_release(struct device *dev)
free_irq(s3c_rtc_tickno, rtc_dev);
}
-static struct rtc_class_ops s3c_rtcops = {
+static const struct rtc_class_ops s3c_rtcops = {
.open = s3c_rtc_open,
.release = s3c_rtc_release,
.ioctl = s3c_rtc_ioctl,
diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c
index ee4b61ee67b0..bd4d7d174ef4 100644
--- a/drivers/rtc/rtc-sa1100.c
+++ b/drivers/rtc/rtc-sa1100.c
@@ -68,8 +68,7 @@ static int rtc_update_alarm(struct rtc_time *alrm)
return ret;
}
-static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = to_platform_device(dev_id);
struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -106,8 +105,7 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id,
static int rtc_timer1_count;
-static irqreturn_t timer1_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t timer1_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = to_platform_device(dev_id);
struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -303,7 +301,7 @@ static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
-static struct rtc_class_ops sa1100_rtc_ops = {
+static const struct rtc_class_ops sa1100_rtc_ops = {
.open = sa1100_rtc_open,
.read_callback = sa1100_rtc_read_callback,
.release = sa1100_rtc_release,
diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c
new file mode 100644
index 000000000000..143302a8e79c
--- /dev/null
+++ b/drivers/rtc/rtc-sh.c
@@ -0,0 +1,467 @@
+/*
+ * SuperH On-Chip RTC Support
+ *
+ * Copyright (C) 2006 Paul Mundt
+ *
+ * Based on the old arch/sh/kernel/cpu/rtc.c by:
+ *
+ * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka
+ *
+ * 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/module.h>
+#include <linux/kernel.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_CPU_SH3
+#define rtc_reg_size sizeof(u16)
+#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
+#elif defined(CONFIG_CPU_SH4)
+#define rtc_reg_size sizeof(u32)
+#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
+#endif
+
+#define RTC_REG(r) ((r) * rtc_reg_size)
+
+#define R64CNT RTC_REG(0)
+#define RSECCNT RTC_REG(1)
+#define RMINCNT RTC_REG(2)
+#define RHRCNT RTC_REG(3)
+#define RWKCNT RTC_REG(4)
+#define RDAYCNT RTC_REG(5)
+#define RMONCNT RTC_REG(6)
+#define RYRCNT RTC_REG(7)
+#define RSECAR RTC_REG(8)
+#define RMINAR RTC_REG(9)
+#define RHRAR RTC_REG(10)
+#define RWKAR RTC_REG(11)
+#define RDAYAR RTC_REG(12)
+#define RMONAR RTC_REG(13)
+#define RCR1 RTC_REG(14)
+#define RCR2 RTC_REG(15)
+
+/* RCR1 Bits */
+#define RCR1_CF 0x80 /* Carry Flag */
+#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
+#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
+#define RCR1_AF 0x01 /* Alarm Flag */
+
+/* RCR2 Bits */
+#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
+#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
+#define RCR2_RTCEN 0x08 /* ENable RTC */
+#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
+#define RCR2_RESET 0x02 /* Reset bit */
+#define RCR2_START 0x01 /* Start bit */
+
+struct sh_rtc {
+ void __iomem *regbase;
+ unsigned long regsize;
+ struct resource *res;
+ unsigned int alarm_irq, periodic_irq, carry_irq;
+ struct rtc_device *rtc_dev;
+ spinlock_t lock;
+};
+
+static irqreturn_t sh_rtc_interrupt(int irq, void *id)
+{
+ struct platform_device *pdev = id;
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int tmp, events = 0;
+
+ spin_lock(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR1);
+
+ if (tmp & RCR1_AF)
+ events |= RTC_AF | RTC_IRQF;
+
+ tmp &= ~(RCR1_CF | RCR1_AF);
+
+ writeb(tmp, rtc->regbase + RCR1);
+
+ rtc_update_irq(&rtc->rtc_dev->class_dev, 1, events);
+
+ spin_unlock(&rtc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t sh_rtc_periodic(int irq, void *id)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(id);
+
+ spin_lock(&rtc->lock);
+
+ rtc_update_irq(&rtc->rtc_dev->class_dev, 1, RTC_PF | RTC_IRQF);
+
+ spin_unlock(&rtc->lock);
+
+ return IRQ_HANDLED;
+}
+
+static inline void sh_rtc_setpie(struct device *dev, unsigned int enable)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+
+ spin_lock_irq(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR2);
+
+ if (enable) {
+ tmp &= ~RCR2_PESMASK;
+ tmp |= RCR2_PEF | (2 << 4);
+ } else
+ tmp &= ~(RCR2_PESMASK | RCR2_PEF);
+
+ writeb(tmp, rtc->regbase + RCR2);
+
+ spin_unlock_irq(&rtc->lock);
+}
+
+static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+
+ spin_lock_irq(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR1);
+
+ if (enable)
+ tmp |= RCR1_AIE;
+ else
+ tmp &= ~RCR1_AIE;
+
+ writeb(tmp, rtc->regbase + RCR1);
+
+ spin_unlock_irq(&rtc->lock);
+}
+
+static int sh_rtc_open(struct device *dev)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+ int ret;
+
+ tmp = readb(rtc->regbase + RCR1);
+ tmp &= ~RCR1_CF;
+ tmp |= RCR1_CIE;
+ writeb(tmp, rtc->regbase + RCR1);
+
+ ret = request_irq(rtc->periodic_irq, sh_rtc_periodic, IRQF_DISABLED,
+ "sh-rtc period", dev);
+ if (unlikely(ret)) {
+ dev_err(dev, "request period IRQ failed with %d, IRQ %d\n",
+ ret, rtc->periodic_irq);
+ return ret;
+ }
+
+ ret = request_irq(rtc->carry_irq, sh_rtc_interrupt, IRQF_DISABLED,
+ "sh-rtc carry", dev);
+ if (unlikely(ret)) {
+ dev_err(dev, "request carry IRQ failed with %d, IRQ %d\n",
+ ret, rtc->carry_irq);
+ free_irq(rtc->periodic_irq, dev);
+ goto err_bad_carry;
+ }
+
+ ret = request_irq(rtc->alarm_irq, sh_rtc_interrupt, IRQF_DISABLED,
+ "sh-rtc alarm", dev);
+ if (unlikely(ret)) {
+ dev_err(dev, "request alarm IRQ failed with %d, IRQ %d\n",
+ ret, rtc->alarm_irq);
+ goto err_bad_alarm;
+ }
+
+ return 0;
+
+err_bad_alarm:
+ free_irq(rtc->carry_irq, dev);
+err_bad_carry:
+ free_irq(rtc->periodic_irq, dev);
+
+ return ret;
+}
+
+static void sh_rtc_release(struct device *dev)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+
+ sh_rtc_setpie(dev, 0);
+
+ free_irq(rtc->periodic_irq, dev);
+ free_irq(rtc->carry_irq, dev);
+ free_irq(rtc->alarm_irq, dev);
+}
+
+static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct sh_rtc *rtc = dev_get_drvdata(dev);
+ unsigned int tmp;
+
+ tmp = readb(rtc->regbase + RCR1);
+ seq_printf(seq, "alarm_IRQ\t: %s\n",
+ (tmp & RCR1_AIE) ? "yes" : "no");
+ seq_printf(seq, "carry_IRQ\t: %s\n",
+ (tmp & RCR1_CIE) ? "yes" : "no");
+
+ tmp = readb(rtc->regbase + RCR2);
+ seq_printf(seq, "periodic_IRQ\t: %s\n",
+ (tmp & RCR2_PEF) ? "yes" : "no");
+
+ return 0;
+}
+
+static int sh_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ unsigned int ret = -ENOIOCTLCMD;
+
+ switch (cmd) {
+ case RTC_PIE_OFF:
+ case RTC_PIE_ON:
+ sh_rtc_setpie(dev, cmd == RTC_PIE_ON);
+ ret = 0;
+ break;
+ case RTC_AIE_OFF:
+ case RTC_AIE_ON:
+ sh_rtc_setaie(dev, cmd == RTC_AIE_ON);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int sec128, sec2, yr, yr100, cf_bit;
+
+ do {
+ unsigned int tmp;
+
+ spin_lock_irq(&rtc->lock);
+
+ tmp = readb(rtc->regbase + RCR1);
+ tmp &= ~RCR1_CF; /* Clear CF-bit */
+ tmp |= RCR1_CIE;
+ writeb(tmp, rtc->regbase + RCR1);
+
+ sec128 = readb(rtc->regbase + R64CNT);
+
+ tm->tm_sec = BCD2BIN(readb(rtc->regbase + RSECCNT));
+ tm->tm_min = BCD2BIN(readb(rtc->regbase + RMINCNT));
+ tm->tm_hour = BCD2BIN(readb(rtc->regbase + RHRCNT));
+ tm->tm_wday = BCD2BIN(readb(rtc->regbase + RWKCNT));
+ tm->tm_mday = BCD2BIN(readb(rtc->regbase + RDAYCNT));
+ tm->tm_mon = BCD2BIN(readb(rtc->regbase + RMONCNT));
+
+#if defined(CONFIG_CPU_SH4)
+ yr = readw(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN(yr >> 8);
+ yr &= 0xff;
+#else
+ yr = readb(rtc->regbase + RYRCNT);
+ yr100 = BCD2BIN((yr == 0x99) ? 0x19 : 0x20);
+#endif
+
+ tm->tm_year = (yr100 * 100 + BCD2BIN(yr)) - 1900;
+
+ sec2 = readb(rtc->regbase + R64CNT);
+ cf_bit = readb(rtc->regbase + RCR1) & RCR1_CF;
+
+ spin_unlock_irq(&rtc->lock);
+ } while (cf_bit != 0 || ((sec128 ^ sec2) & RTC_BIT_INVERTED) != 0);
+
+#if RTC_BIT_INVERTED != 0
+ if ((sec128 & RTC_BIT_INVERTED))
+ tm->tm_sec--;
+#endif
+
+ 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,
+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ if (rtc_valid_tm(tm) < 0)
+ dev_err(dev, "invalid date\n");
+
+ return 0;
+}
+
+static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+ unsigned int tmp;
+ int year;
+
+ spin_lock_irq(&rtc->lock);
+
+ /* Reset pre-scaler & stop RTC */
+ tmp = readb(rtc->regbase + RCR2);
+ tmp |= RCR2_RESET;
+ writeb(tmp, rtc->regbase + RCR2);
+
+ writeb(BIN2BCD(tm->tm_sec), rtc->regbase + RSECCNT);
+ writeb(BIN2BCD(tm->tm_min), rtc->regbase + RMINCNT);
+ writeb(BIN2BCD(tm->tm_hour), rtc->regbase + RHRCNT);
+ writeb(BIN2BCD(tm->tm_wday), rtc->regbase + RWKCNT);
+ writeb(BIN2BCD(tm->tm_mday), rtc->regbase + RDAYCNT);
+ writeb(BIN2BCD(tm->tm_mon), rtc->regbase + RMONCNT);
+
+#ifdef CONFIG_CPU_SH3
+ year = tm->tm_year % 100;
+ writeb(BIN2BCD(year), rtc->regbase + RYRCNT);
+#else
+ year = (BIN2BCD((tm->tm_year + 1900) / 100) << 8) |
+ BIN2BCD(tm->tm_year % 100);
+ writew(year, rtc->regbase + RYRCNT);
+#endif
+
+ /* Start RTC */
+ tmp = readb(rtc->regbase + RCR2);
+ tmp &= ~RCR2_RESET;
+ tmp |= RCR2_RTCEN | RCR2_START;
+ writeb(tmp, rtc->regbase + RCR2);
+
+ spin_unlock_irq(&rtc->lock);
+
+ return 0;
+}
+
+static struct rtc_class_ops sh_rtc_ops = {
+ .open = sh_rtc_open,
+ .release = sh_rtc_release,
+ .ioctl = sh_rtc_ioctl,
+ .read_time = sh_rtc_read_time,
+ .set_time = sh_rtc_set_time,
+ .proc = sh_rtc_proc,
+};
+
+static int __devinit sh_rtc_probe(struct platform_device *pdev)
+{
+ struct sh_rtc *rtc;
+ struct resource *res;
+ int ret = -ENOENT;
+
+ rtc = kzalloc(sizeof(struct sh_rtc), GFP_KERNEL);
+ if (unlikely(!rtc))
+ return -ENOMEM;
+
+ spin_lock_init(&rtc->lock);
+
+ rtc->periodic_irq = platform_get_irq(pdev, 0);
+ if (unlikely(rtc->periodic_irq < 0)) {
+ dev_err(&pdev->dev, "No IRQ for period\n");
+ goto err_badres;
+ }
+
+ rtc->carry_irq = platform_get_irq(pdev, 1);
+ if (unlikely(rtc->carry_irq < 0)) {
+ dev_err(&pdev->dev, "No IRQ for carry\n");
+ goto err_badres;
+ }
+
+ rtc->alarm_irq = platform_get_irq(pdev, 2);
+ if (unlikely(rtc->alarm_irq < 0)) {
+ dev_err(&pdev->dev, "No IRQ for alarm\n");
+ goto err_badres;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ if (unlikely(res == NULL)) {
+ dev_err(&pdev->dev, "No IO resource\n");
+ goto err_badres;
+ }
+
+ rtc->regsize = res->end - res->start + 1;
+
+ rtc->res = request_mem_region(res->start, rtc->regsize, pdev->name);
+ if (unlikely(!rtc->res)) {
+ ret = -EBUSY;
+ goto err_badres;
+ }
+
+ rtc->regbase = (void __iomem *)rtc->res->start;
+ if (unlikely(!rtc->regbase)) {
+ ret = -EINVAL;
+ goto err_badmap;
+ }
+
+ rtc->rtc_dev = rtc_device_register("sh", &pdev->dev,
+ &sh_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ goto err_badmap;
+ }
+
+ platform_set_drvdata(pdev, rtc);
+
+ return 0;
+
+err_badmap:
+ release_resource(rtc->res);
+err_badres:
+ kfree(rtc);
+
+ return ret;
+}
+
+static int __devexit sh_rtc_remove(struct platform_device *pdev)
+{
+ struct sh_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (likely(rtc->rtc_dev))
+ rtc_device_unregister(rtc->rtc_dev);
+
+ sh_rtc_setpie(&pdev->dev, 0);
+ sh_rtc_setaie(&pdev->dev, 0);
+
+ release_resource(rtc->res);
+
+ platform_set_drvdata(pdev, NULL);
+
+ kfree(rtc);
+
+ return 0;
+}
+static struct platform_driver sh_rtc_platform_driver = {
+ .driver = {
+ .name = "sh-rtc",
+ .owner = THIS_MODULE,
+ },
+ .probe = sh_rtc_probe,
+ .remove = __devexit_p(sh_rtc_remove),
+};
+
+static int __init sh_rtc_init(void)
+{
+ return platform_driver_register(&sh_rtc_platform_driver);
+}
+
+static void __exit sh_rtc_exit(void)
+{
+ platform_driver_unregister(&sh_rtc_platform_driver);
+}
+
+module_init(sh_rtc_init);
+module_exit(sh_rtc_exit);
+
+MODULE_DESCRIPTION("SuperH on-chip RTC driver");
+MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index 7c1f3d2e53c4..625637b84d33 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -116,7 +116,7 @@ static void __exit rtc_sysfs_exit(void)
class_interface_unregister(&rtc_sysfs_interface);
}
-module_init(rtc_sysfs_init);
+subsys_initcall(rtc_sysfs_init);
module_exit(rtc_sysfs_exit);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c
index e1fa5fe7901f..bc4bd24508a2 100644
--- a/drivers/rtc/rtc-test.c
+++ b/drivers/rtc/rtc-test.c
@@ -75,7 +75,7 @@ static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
}
}
-static struct rtc_class_ops test_rtc_ops = {
+static const struct rtc_class_ops test_rtc_ops = {
.proc = test_rtc_proc,
.read_time = test_rtc_read_time,
.set_time = test_rtc_set_time,
diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c
index a40f400acff6..3b58d3d5d38a 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -149,7 +149,7 @@ static int v3020_set_time(struct device *dev, struct rtc_time *dt)
return 0;
}
-static struct rtc_class_ops v3020_rtc_ops = {
+static const struct rtc_class_ops v3020_rtc_ops = {
.read_time = v3020_read_time,
.set_time = v3020_set_time,
};
@@ -169,9 +169,6 @@ static int rtc_probe(struct platform_device *pdev)
if (pdev->resource[0].flags != IORESOURCE_MEM)
return -EBUSY;
- if (pdev == NULL)
- return -EBUSY;
-
chip = kzalloc(sizeof *chip, GFP_KERNEL);
if (!chip)
return -ENOMEM;
@@ -198,9 +195,9 @@ static int rtc_probe(struct platform_device *pdev)
* are all disabled */
v3020_set_reg(chip, V3020_STATUS_0, 0x0);
- dev_info(&pdev->dev, "Chip available at physical address 0x%p,"
+ dev_info(&pdev->dev, "Chip available at physical address 0x%llx,"
"data connected to D%d\n",
- (void*)pdev->resource[0].start,
+ (unsigned long long)pdev->resource[0].start,
chip->leftshift);
platform_set_drvdata(pdev, chip);
diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c
index 596764fd29f5..e40322b71938 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -268,7 +268,7 @@ static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long
return 0;
}
-static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = (struct platform_device *)dev_id;
struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -280,7 +280,7 @@ static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *
return IRQ_HANDLED;
}
-static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rtclong1_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = (struct platform_device *)dev_id;
struct rtc_device *rtc = platform_get_drvdata(pdev);
@@ -296,7 +296,7 @@ static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *reg
return IRQ_HANDLED;
}
-static struct rtc_class_ops vr41xx_rtc_ops = {
+static const struct rtc_class_ops vr41xx_rtc_ops = {
.release = vr41xx_rtc_release,
.ioctl = vr41xx_rtc_ioctl,
.read_time = vr41xx_rtc_read_time,
diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c
index 788b6d1f8f2f..522c69753bbf 100644
--- a/drivers/rtc/rtc-x1205.c
+++ b/drivers/rtc/rtc-x1205.c
@@ -460,7 +460,7 @@ static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
return 0;
}
-static struct rtc_class_ops x1205_rtc_ops = {
+static const struct rtc_class_ops x1205_rtc_ops = {
.proc = x1205_rtc_proc,
.read_time = x1205_rtc_read_time,
.set_time = x1205_rtc_set_time,
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index 929d6fff6152..b250c5354503 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -1,4 +1,4 @@
-if S390
+if S390 && BLOCK
comment "S/390 block device drivers"
depends on S390
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index d0647d116eaa..79ffef6bfaf8 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -203,6 +203,7 @@ dasd_state_basic_to_known(struct dasd_device * device)
rc = dasd_flush_ccw_queue(device, 1);
if (rc)
return rc;
+ dasd_clear_timer(device);
DBF_DEV_EVENT(DBF_EMERG, device, "%p debug area deleted", device);
if (device->debug_area != NULL) {
diff --git a/drivers/s390/block/dasd_diag.c b/drivers/s390/block/dasd_diag.c
index 23fa0b289173..53db58a68617 100644
--- a/drivers/s390/block/dasd_diag.c
+++ b/drivers/s390/block/dasd_diag.c
@@ -63,44 +63,26 @@ static const u8 DASD_DIAG_CMS1[] = { 0xc3, 0xd4, 0xe2, 0xf1 };/* EBCDIC CMS1 */
* and function code cmd.
* In case of an exception return 3. Otherwise return result of bitwise OR of
* resulting condition code and DIAG return code. */
-static __inline__ int
-dia250(void *iob, int cmd)
+static inline int dia250(void *iob, int cmd)
{
+ register unsigned long reg0 asm ("0") = (unsigned long) iob;
typedef union {
struct dasd_diag_init_io init_io;
struct dasd_diag_rw_io rw_io;
} addr_type;
int rc;
- __asm__ __volatile__(
-#ifdef CONFIG_64BIT
- " lghi %0,3\n"
- " lgr 0,%3\n"
- " diag 0,%2,0x250\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- " or %0,1\n"
- "1:\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous\n"
-#else
- " lhi %0,3\n"
- " lr 0,%3\n"
+ rc = 3;
+ asm volatile(
" diag 0,%2,0x250\n"
"0: ipm %0\n"
" srl %0,28\n"
" or %0,1\n"
"1:\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous\n"
-#endif
- : "=&d" (rc), "=m" (*(addr_type *) iob)
- : "d" (cmd), "d" (iob), "m" (*(addr_type *) iob)
- : "0", "1", "cc");
+ EX_TABLE(0b,1b)
+ : "+d" (rc), "=m" (*(addr_type *) iob)
+ : "d" (cmd), "d" (reg0), "m" (*(addr_type *) iob)
+ : "1", "cc");
return rc;
}
@@ -236,7 +218,7 @@ dasd_diag_term_IO(struct dasd_ccw_req * cqr)
/* Handle external interruption. */
static void
-dasd_ext_handler(struct pt_regs *regs, __u16 code)
+dasd_ext_handler(__u16 code)
{
struct dasd_ccw_req *cqr, *next;
struct dasd_device *device;
@@ -547,7 +529,7 @@ dasd_diag_build_cp(struct dasd_device * device, struct request *req)
}
cqr->retries = DIAG_MAX_RETRIES;
cqr->buildclk = get_clock();
- if (req->flags & REQ_FAILFAST)
+ if (req->cmd_flags & REQ_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->device = device;
cqr->expires = DIAG_TIMEOUT;
diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index b7a7fac3f7c3..5ecea3e4fdef 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -1266,7 +1266,7 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
recid++;
}
}
- if (req->flags & REQ_FAILFAST)
+ if (req->cmd_flags & REQ_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->device = device;
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
diff --git a/drivers/s390/block/dasd_fba.c b/drivers/s390/block/dasd_fba.c
index e85015be109b..80926c548228 100644
--- a/drivers/s390/block/dasd_fba.c
+++ b/drivers/s390/block/dasd_fba.c
@@ -344,7 +344,7 @@ dasd_fba_build_cp(struct dasd_device * device, struct request *req)
recid++;
}
}
- if (req->flags & REQ_FAILFAST)
+ if (req->cmd_flags & REQ_FAILFAST)
set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
cqr->device = device;
cqr->expires = 5 * 60 * HZ; /* 5 minutes */
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index cab2c736683a..a04d9120cef0 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -89,28 +89,15 @@ MODULE_LICENSE("GPL");
*/
static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index)
{
- int cc;
+ int cc = 2; /* return unused cc 2 if pgin traps */
- __asm__ __volatile__ (
- " lhi %0,2\n" /* return unused cc 2 if pgin traps */
- " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " .insn rre,0xb22e0000,%1,%2\n" /* pgin %1,%2 */
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifndef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (cc)
- : "a" (__pa(page_addr)), "a" (xpage_index)
- : "cc" );
+ EX_TABLE(0b,1b)
+ : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
if (cc == 3)
return -ENXIO;
if (cc == 2) {
@@ -137,28 +124,15 @@ static int xpram_page_in (unsigned long page_addr, unsigned int xpage_index)
*/
static long xpram_page_out (unsigned long page_addr, unsigned int xpage_index)
{
- int cc;
+ int cc = 2; /* return unused cc 2 if pgin traps */
- __asm__ __volatile__ (
- " lhi %0,2\n" /* return unused cc 2 if pgout traps */
- " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " .insn rre,0xb22f0000,%1,%2\n" /* pgout %1,%2 */
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifndef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (cc)
- : "a" (__pa(page_addr)), "a" (xpage_index)
- : "cc" );
+ EX_TABLE(0b,1b)
+ : "+d" (cc) : "a" (__pa(page_addr)), "d" (xpage_index) : "cc");
if (cc == 3)
return -ENXIO;
if (cc == 2) {
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 2fa566fa6da4..d7de175d53f0 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -1103,7 +1103,7 @@ tty3215_start(struct tty_struct *tty)
}
}
-static struct tty_operations tty3215_ops = {
+static const struct tty_operations tty3215_ops = {
.open = tty3215_open,
.close = tty3215_close,
.write = tty3215_write,
diff --git a/drivers/s390/char/ctrlchar.c b/drivers/s390/char/ctrlchar.c
index d83eb6358bac..49e9628d9297 100644
--- a/drivers/s390/char/ctrlchar.c
+++ b/drivers/s390/char/ctrlchar.c
@@ -20,7 +20,7 @@ static int ctrlchar_sysrq_key;
static void
ctrlchar_handle_sysrq(void *tty)
{
- handle_sysrq(ctrlchar_sysrq_key, NULL, (struct tty_struct *) tty);
+ handle_sysrq(ctrlchar_sysrq_key, (struct tty_struct *) tty);
}
static DECLARE_WORK(ctrlchar_work, ctrlchar_handle_sysrq, NULL);
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index ef004d089712..78f8bda81dae 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -17,7 +17,6 @@
#include <asm/ccwdev.h>
#include <asm/cio.h>
-#include <asm/cpcmd.h>
#include <asm/ebcdic.h>
#include <asm/idals.h>
@@ -28,7 +27,7 @@ struct raw3270_fn fs3270_fn;
struct fs3270 {
struct raw3270_view view;
- pid_t fs_pid; /* Pid of controlling program. */
+ struct pid *fs_pid; /* Pid of controlling program. */
int read_command; /* ccw command to use for reads. */
int write_command; /* ccw command to use for writes. */
int attention; /* Got attention. */
@@ -103,7 +102,7 @@ fs3270_restore_callback(struct raw3270_request *rq, void *data)
fp = (struct fs3270 *) rq->view;
if (rq->rc != 0 || rq->rescnt != 0) {
if (fp->fs_pid)
- kill_proc(fp->fs_pid, SIGHUP, 1);
+ kill_pid(fp->fs_pid, SIGHUP, 1);
}
fp->rdbuf_size = 0;
raw3270_request_reset(rq);
@@ -174,7 +173,7 @@ fs3270_save_callback(struct raw3270_request *rq, void *data)
*/
if (rq->rc != 0 || rq->rescnt == 0) {
if (fp->fs_pid)
- kill_proc(fp->fs_pid, SIGHUP, 1);
+ kill_pid(fp->fs_pid, SIGHUP, 1);
fp->rdbuf_size = 0;
} else
fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
@@ -443,7 +442,7 @@ fs3270_open(struct inode *inode, struct file *filp)
return PTR_ERR(fp);
init_waitqueue_head(&fp->wait);
- fp->fs_pid = current->pid;
+ fp->fs_pid = get_pid(task_pid(current));
rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
if (rc) {
fs3270_free_view(&fp->view);
@@ -481,7 +480,8 @@ fs3270_close(struct inode *inode, struct file *filp)
fp = filp->private_data;
filp->private_data = NULL;
if (fp) {
- fp->fs_pid = 0;
+ put_pid(fp->fs_pid);
+ fp->fs_pid = NULL;
raw3270_reset(&fp->view);
raw3270_put_view(&fp->view);
raw3270_del_view(&fp->view);
diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c
index 3be06569180d..e3491a5f5219 100644
--- a/drivers/s390/char/keyboard.c
+++ b/drivers/s390/char/keyboard.c
@@ -304,7 +304,7 @@ kbd_keycode(struct kbd_data *kbd, unsigned int keycode)
if (kbd->sysrq) {
if (kbd->sysrq == K(KT_LATIN, '-')) {
kbd->sysrq = 0;
- handle_sysrq(value, NULL, kbd->tty);
+ handle_sysrq(value, kbd->tty);
return;
}
if (value == '-') {
diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c
index 1e3939aeb8ab..b9b0fc3f812b 100644
--- a/drivers/s390/char/monwriter.c
+++ b/drivers/s390/char/monwriter.c
@@ -26,6 +26,7 @@
#define MONWRITE_MAX_DATALEN 4024
static int mon_max_bufs = 255;
+static int mon_buf_count;
struct mon_buf {
struct list_head list;
@@ -40,7 +41,6 @@ struct mon_private {
size_t hdr_to_read;
size_t data_to_read;
struct mon_buf *current_buf;
- int mon_buf_count;
};
/*
@@ -73,12 +73,15 @@ static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
struct mon_buf *entry, *next;
list_for_each_entry_safe(entry, next, &monpriv->list, list)
- if (entry->hdr.applid == monhdr->applid &&
+ if ((entry->hdr.mon_function == monhdr->mon_function ||
+ monhdr->mon_function == MONWRITE_STOP_INTERVAL) &&
+ entry->hdr.applid == monhdr->applid &&
entry->hdr.record_num == monhdr->record_num &&
entry->hdr.version == monhdr->version &&
entry->hdr.release == monhdr->release &&
entry->hdr.mod_level == monhdr->mod_level)
return entry;
+
return NULL;
}
@@ -92,25 +95,27 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
monhdr->mon_function > MONWRITE_START_CONFIG ||
monhdr->hdrlen != sizeof(struct monwrite_hdr))
return -EINVAL;
- monbuf = monwrite_find_hdr(monpriv, monhdr);
+ monbuf = NULL;
+ if (monhdr->mon_function != MONWRITE_GEN_EVENT)
+ monbuf = monwrite_find_hdr(monpriv, monhdr);
if (monbuf) {
if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) {
monhdr->datalen = monbuf->hdr.datalen;
rc = monwrite_diag(monhdr, monbuf->data,
APPLDATA_STOP_REC);
list_del(&monbuf->list);
- monpriv->mon_buf_count--;
+ mon_buf_count--;
kfree(monbuf->data);
kfree(monbuf);
monbuf = NULL;
}
- } else {
- if (monpriv->mon_buf_count >= mon_max_bufs)
+ } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) {
+ if (mon_buf_count >= mon_max_bufs)
return -ENOSPC;
monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL);
if (!monbuf)
return -ENOMEM;
- monbuf->data = kzalloc(monbuf->hdr.datalen,
+ monbuf->data = kzalloc(monhdr->datalen,
GFP_KERNEL | GFP_DMA);
if (!monbuf->data) {
kfree(monbuf);
@@ -118,7 +123,8 @@ static int monwrite_new_hdr(struct mon_private *monpriv)
}
monbuf->hdr = *monhdr;
list_add_tail(&monbuf->list, &monpriv->list);
- monpriv->mon_buf_count++;
+ if (monhdr->mon_function != MONWRITE_GEN_EVENT)
+ mon_buf_count++;
}
monpriv->current_buf = monbuf;
return 0;
@@ -186,7 +192,7 @@ static int monwrite_close(struct inode *inode, struct file *filp)
if (entry->hdr.mon_function != MONWRITE_GEN_EVENT)
monwrite_diag(&entry->hdr, entry->data,
APPLDATA_STOP_REC);
- monpriv->mon_buf_count--;
+ mon_buf_count--;
list_del(&entry->list);
kfree(entry->data);
kfree(entry);
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 985d1613baaa..8a056df09d6b 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -100,13 +100,12 @@ service_call(sclp_cmdw_t command, void *sccb)
{
int cc;
- __asm__ __volatile__(
- " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
- " ipm %0\n"
- " srl %0,28"
- : "=&d" (cc)
- : "d" (command), "a" (__pa(sccb))
- : "cc", "memory" );
+ asm volatile(
+ " .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */
+ " ipm %0\n"
+ " srl %0,28"
+ : "=&d" (cc) : "d" (command), "a" (__pa(sccb))
+ : "cc", "memory");
if (cc == 3)
return -EIO;
if (cc == 2)
@@ -325,7 +324,7 @@ __sclp_find_req(u32 sccb)
* Prepare read event data request if necessary. Start processing of next
* request on queue. */
static void
-sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
+sclp_interrupt_handler(__u16 code)
{
struct sclp_req *req;
u32 finished_sccb;
@@ -360,16 +359,6 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
sclp_process_queue();
}
-/* Return current Time-Of-Day clock. */
-static inline u64
-sclp_get_clock(void)
-{
- u64 result;
-
- asm volatile ("STCK 0(%1)" : "=m" (result) : "a" (&(result)) : "cc");
- return result;
-}
-
/* Convert interval in jiffies to TOD ticks. */
static inline u64
sclp_tod_from_jiffies(unsigned long jiffies)
@@ -382,7 +371,6 @@ sclp_tod_from_jiffies(unsigned long jiffies)
void
sclp_sync_wait(void)
{
- unsigned long psw_mask;
unsigned long flags;
unsigned long cr0, cr0_sync;
u64 timeout;
@@ -392,7 +380,7 @@ sclp_sync_wait(void)
timeout = 0;
if (timer_pending(&sclp_request_timer)) {
/* Get timeout TOD value */
- timeout = sclp_get_clock() +
+ timeout = get_clock() +
sclp_tod_from_jiffies(sclp_request_timer.expires -
jiffies);
}
@@ -406,13 +394,12 @@ sclp_sync_wait(void)
cr0_sync |= 0x00000200;
cr0_sync &= 0xFFFFF3AC;
__ctl_load(cr0_sync, 0, 0);
- asm volatile ("STOSM 0(%1),0x01"
- : "=m" (psw_mask) : "a" (&psw_mask) : "memory");
+ __raw_local_irq_stosm(0x01);
/* Loop until driver state indicates finished request */
while (sclp_running_state != sclp_running_state_idle) {
/* Check for expired request timer */
if (timer_pending(&sclp_request_timer) &&
- sclp_get_clock() > timeout &&
+ get_clock() > timeout &&
del_timer(&sclp_request_timer))
sclp_request_timer.function(sclp_request_timer.data);
barrier();
@@ -756,7 +743,7 @@ EXPORT_SYMBOL(sclp_reactivate);
/* Handler for external interruption used during initialization. Modify
* request state to done. */
static void
-sclp_check_handler(struct pt_regs *regs, __u16 code)
+sclp_check_handler(__u16 code)
{
u32 finished_sccb;
diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c
index f6cf9023039e..6f43e04dbefd 100644
--- a/drivers/s390/char/sclp_tty.c
+++ b/drivers/s390/char/sclp_tty.c
@@ -711,7 +711,7 @@ static struct sclp_register sclp_input_event =
.receiver_fn = sclp_tty_receiver
};
-static struct tty_operations sclp_ops = {
+static const struct tty_operations sclp_ops = {
.open = sclp_tty_open,
.close = sclp_tty_close,
.write = sclp_tty_write,
diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c
index 54fba6f17188..723bf4191bfe 100644
--- a/drivers/s390/char/sclp_vt220.c
+++ b/drivers/s390/char/sclp_vt220.c
@@ -655,7 +655,7 @@ __sclp_vt220_init(int early)
return 0;
}
-static struct tty_operations sclp_vt220_ops = {
+static const struct tty_operations sclp_vt220_ops = {
.open = sclp_vt220_open,
.close = sclp_vt220_close,
.write = sclp_vt220_write,
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 29718042c6c9..4717c3611601 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -698,7 +698,6 @@ tty3270_alloc_view(void)
if (!tp->freemem_pages)
goto out_tp;
INIT_LIST_HEAD(&tp->freemem);
- init_timer(&tp->timer);
for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
tp->freemem_pages[pages] = (void *)
__get_free_pages(GFP_KERNEL|GFP_DMA, 0);
@@ -1738,7 +1737,7 @@ tty3270_ioctl(struct tty_struct *tty, struct file *file,
return kbd_ioctl(tp->kbd, file, cmd, arg);
}
-static struct tty_operations tty3270_ops = {
+static const struct tty_operations tty3270_ops = {
.open = tty3270_open,
.close = tty3270_close,
.write = tty3270_write,
diff --git a/drivers/s390/char/vmwatchdog.c b/drivers/s390/char/vmwatchdog.c
index 807320a41fa4..4b868f72fe89 100644
--- a/drivers/s390/char/vmwatchdog.c
+++ b/drivers/s390/char/vmwatchdog.c
@@ -54,48 +54,20 @@ enum vmwdt_func {
static int __diag288(enum vmwdt_func func, unsigned int timeout,
char *cmd, size_t len)
{
- register unsigned long __func asm("2");
- register unsigned long __timeout asm("3");
- register unsigned long __cmdp asm("4");
- register unsigned long __cmdl asm("5");
+ register unsigned long __func asm("2") = func;
+ register unsigned long __timeout asm("3") = timeout;
+ register unsigned long __cmdp asm("4") = virt_to_phys(cmd);
+ register unsigned long __cmdl asm("5") = len;
int err;
- __func = func;
- __timeout = timeout;
- __cmdp = virt_to_phys(cmd);
- __cmdl = len;
- err = 0;
- asm volatile (
-#ifdef CONFIG_64BIT
- "diag %2,%4,0x288\n"
- "1: \n"
- ".section .fixup,\"ax\"\n"
- "2: lghi %0,%1\n"
- " jg 1b\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 1b,2b\n"
- ".previous\n"
-#else
- "diag %2,%4,0x288\n"
- "1: \n"
- ".section .fixup,\"ax\"\n"
- "2: lhi %0,%1\n"
- " bras 1,3f\n"
- " .long 1b\n"
- "3: l 1,0(1)\n"
- " br 1\n"
- ".previous\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 1b,2b\n"
- ".previous\n"
-#endif
- : "+&d"(err)
- : "i"(-EINVAL), "d"(__func), "d"(__timeout),
- "d"(__cmdp), "d"(__cmdl)
- : "1", "cc");
+ err = -EINVAL;
+ asm volatile(
+ " diag %1,%3,0x288\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (err) : "d"(__func), "d"(__timeout),
+ "d"(__cmdp), "d"(__cmdl), "0" (-EINVAL) : "1", "cc");
return err;
}
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c
index 3bb4e472d73d..2d78f0f4a40f 100644
--- a/drivers/s390/cio/chsc.c
+++ b/drivers/s390/cio/chsc.c
@@ -200,11 +200,13 @@ css_get_ssd_info(struct subchannel *sch)
spin_unlock_irq(&sch->lock);
free_page((unsigned long)page);
if (!ret) {
- int j, chpid;
+ int j, chpid, mask;
/* Allocate channel path structures, if needed. */
for (j = 0; j < 8; j++) {
+ mask = 0x80 >> j;
chpid = sch->ssd_info.chpid[j];
- if (chpid && (get_chp_status(chpid) < 0))
+ if ((sch->schib.pmcw.pim & mask) &&
+ (get_chp_status(chpid) < 0))
new_channel_path(chpid);
}
}
@@ -222,13 +224,15 @@ s390_subchannel_remove_chpid(struct device *dev, void *data)
sch = to_subchannel(dev);
chpid = data;
- for (j = 0; j < 8; j++)
- if (sch->schib.pmcw.chpid[j] == chpid->id)
+ for (j = 0; j < 8; j++) {
+ mask = 0x80 >> j;
+ if ((sch->schib.pmcw.pim & mask) &&
+ (sch->schib.pmcw.chpid[j] == chpid->id))
break;
+ }
if (j >= 8)
return 0;
- mask = 0x80 >> j;
spin_lock_irq(&sch->lock);
stsch(sch->schid, &schib);
@@ -366,7 +370,7 @@ __s390_process_res_acc(struct subchannel_id schid, void *data)
struct res_acc_data *res_data;
struct subchannel *sch;
- res_data = (struct res_acc_data *)data;
+ res_data = data;
sch = get_subchannel_by_schid(schid);
if (!sch)
/* Check if a subchannel is newly available. */
@@ -440,7 +444,7 @@ __get_chpid_from_lir(void *data)
u32 isinfo[28];
} *lir;
- lir = (struct lir*) data;
+ lir = data;
if (!(lir->iq&0x80))
/* NULL link incident record */
return -EINVAL;
@@ -620,18 +624,20 @@ __chp_add_new_sch(struct subchannel_id schid)
static int
__chp_add(struct subchannel_id schid, void *data)
{
- int i;
+ int i, mask;
struct channel_path *chp;
struct subchannel *sch;
- chp = (struct channel_path *)data;
+ chp = data;
sch = get_subchannel_by_schid(schid);
if (!sch)
/* Check if the subchannel is now available. */
return __chp_add_new_sch(schid);
spin_lock_irq(&sch->lock);
- for (i=0; i<8; i++)
- if (sch->schib.pmcw.chpid[i] == chp->id) {
+ for (i=0; i<8; i++) {
+ mask = 0x80 >> i;
+ if ((sch->schib.pmcw.pim & mask) &&
+ (sch->schib.pmcw.chpid[i] == chp->id)) {
if (stsch(sch->schid, &sch->schib) != 0) {
/* Endgame. */
spin_unlock_irq(&sch->lock);
@@ -639,6 +645,7 @@ __chp_add(struct subchannel_id schid, void *data)
}
break;
}
+ }
if (i==8) {
spin_unlock_irq(&sch->lock);
return 0;
@@ -646,7 +653,7 @@ __chp_add(struct subchannel_id schid, void *data)
sch->lpm = ((sch->schib.pmcw.pim &
sch->schib.pmcw.pam &
sch->schib.pmcw.pom)
- | 0x80 >> i) & sch->opm;
+ | mask) & sch->opm;
if (sch->driver && sch->driver->verify)
sch->driver->verify(&sch->dev);
@@ -700,8 +707,7 @@ chp_process_crw(int chpid, int on)
return chp_add(chpid);
}
-static inline int
-__check_for_io_and_kill(struct subchannel *sch, int index)
+static inline int check_for_io_on_path(struct subchannel *sch, int index)
{
int cc;
@@ -711,10 +717,8 @@ __check_for_io_and_kill(struct subchannel *sch, int index)
cc = stsch(sch->schid, &sch->schib);
if (cc)
return 0;
- if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index)) {
- device_set_waiting(sch);
+ if (sch->schib.scsw.actl && sch->schib.pmcw.lpum == (0x80 >> index))
return 1;
- }
return 0;
}
@@ -743,12 +747,10 @@ __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
} else {
sch->opm &= ~(0x80 >> chp);
sch->lpm &= ~(0x80 >> chp);
- /*
- * Give running I/O a grace period in which it
- * can successfully terminate, even using the
- * just varied off path. Then kill it.
- */
- if (!__check_for_io_and_kill(sch, chp) && !sch->lpm) {
+ if (check_for_io_on_path(sch, chp))
+ /* Path verification is done after killing. */
+ device_kill_io(sch);
+ else if (!sch->lpm) {
if (css_enqueue_subchannel_slow(sch->schid)) {
css_clear_subchannel_slow_list();
need_rescan = 1;
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 2e2882daefbb..8936e460a807 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -19,6 +19,7 @@
#include <asm/cio.h>
#include <asm/delay.h>
#include <asm/irq.h>
+#include <asm/irq_regs.h>
#include <asm/setup.h>
#include "airq.h"
#include "cio.h"
@@ -606,15 +607,17 @@ do_IRQ (struct pt_regs *regs)
struct tpi_info *tpi_info;
struct subchannel *sch;
struct irb *irb;
+ struct pt_regs *old_regs;
- irq_enter ();
+ old_regs = set_irq_regs(regs);
+ irq_enter();
asm volatile ("mc 0,0");
if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer)
/**
* Make sure that the i/o interrupt did not "overtake"
* the last HZ timer interrupt.
*/
- account_ticks(regs);
+ account_ticks();
/*
* Get interrupt information from lowcore
*/
@@ -652,7 +655,8 @@ do_IRQ (struct pt_regs *regs)
* out of the sie which costs more cycles than it saves.
*/
} while (!MACHINE_IS_VM && tpi (NULL) != 0);
- irq_exit ();
+ irq_exit();
+ set_irq_regs(old_regs);
}
#ifdef CONFIG_CCW_CONSOLE
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 7086a74e9871..a2dee5bf5a17 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -177,7 +177,7 @@ get_subchannel_by_schid(struct subchannel_id schid)
struct device *dev;
dev = bus_find_device(&css_bus_type, NULL,
- (void *)&schid, check_subchannel);
+ &schid, check_subchannel);
return dev ? to_subchannel(dev) : NULL;
}
diff --git a/drivers/s390/cio/css.h b/drivers/s390/cio/css.h
index 8aabb4adeb5f..4c2ff8336288 100644
--- a/drivers/s390/cio/css.h
+++ b/drivers/s390/cio/css.h
@@ -76,9 +76,8 @@ struct ccw_device_private {
int state; /* device state */
atomic_t onoff;
unsigned long registered;
- __u16 devno; /* device number */
- __u16 sch_no; /* subchannel number */
- __u8 ssid; /* subchannel set id */
+ struct ccw_dev_id dev_id; /* device id */
+ struct subchannel_id schid; /* subchannel number */
__u8 imask; /* lpm mask for SNID/SID/SPGID */
int iretry; /* retry counter SNID/SID/SPGID */
struct {
@@ -171,7 +170,7 @@ void device_trigger_reprobe(struct subchannel *);
/* Helper functions for vary on/off. */
int device_is_online(struct subchannel *);
-void device_set_waiting(struct subchannel *);
+void device_kill_io(struct subchannel *);
/* Machine check helper function. */
void device_kill_pending_timer(struct subchannel *);
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 688945662c15..94bdd4d8a4c9 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -552,21 +552,19 @@ ccw_device_register(struct ccw_device *cdev)
}
struct match_data {
- unsigned int devno;
- unsigned int ssid;
+ struct ccw_dev_id dev_id;
struct ccw_device * sibling;
};
static int
match_devno(struct device * dev, void * data)
{
- struct match_data * d = (struct match_data *)data;
+ struct match_data * d = data;
struct ccw_device * cdev;
cdev = to_ccwdev(dev);
if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
- (cdev->private->devno == d->devno) &&
- (cdev->private->ssid == d->ssid) &&
+ ccw_dev_id_is_equal(&cdev->private->dev_id, &d->dev_id) &&
(cdev != d->sibling)) {
cdev->private->state = DEV_STATE_NOT_OPER;
return 1;
@@ -574,15 +572,13 @@ match_devno(struct device * dev, void * data)
return 0;
}
-static struct ccw_device *
-get_disc_ccwdev_by_devno(unsigned int devno, unsigned int ssid,
- struct ccw_device *sibling)
+static struct ccw_device * get_disc_ccwdev_by_dev_id(struct ccw_dev_id *dev_id,
+ struct ccw_device *sibling)
{
struct device *dev;
struct match_data data;
- data.devno = devno;
- data.ssid = ssid;
+ data.dev_id = *dev_id;
data.sibling = sibling;
dev = bus_find_device(&ccw_bus_type, NULL, &data, match_devno);
@@ -595,7 +591,7 @@ ccw_device_add_changed(void *data)
struct ccw_device *cdev;
- cdev = (struct ccw_device *)data;
+ cdev = data;
if (device_add(&cdev->dev)) {
put_device(&cdev->dev);
return;
@@ -616,9 +612,9 @@ ccw_device_do_unreg_rereg(void *data)
struct subchannel *sch;
int need_rename;
- cdev = (struct ccw_device *)data;
+ cdev = data;
sch = to_subchannel(cdev->dev.parent);
- if (cdev->private->devno != sch->schib.pmcw.dev) {
+ if (cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
/*
* The device number has changed. This is usually only when
* a device has been detached under VM and then re-appeared
@@ -633,10 +629,12 @@ ccw_device_do_unreg_rereg(void *data)
* get possibly sick...
*/
struct ccw_device *other_cdev;
+ struct ccw_dev_id dev_id;
need_rename = 1;
- other_cdev = get_disc_ccwdev_by_devno(sch->schib.pmcw.dev,
- sch->schid.ssid, cdev);
+ dev_id.devno = sch->schib.pmcw.dev;
+ dev_id.ssid = sch->schid.ssid;
+ other_cdev = get_disc_ccwdev_by_dev_id(&dev_id, cdev);
if (other_cdev) {
struct subchannel *other_sch;
@@ -652,7 +650,7 @@ ccw_device_do_unreg_rereg(void *data)
}
/* Update ssd info here. */
css_get_ssd_info(sch);
- cdev->private->devno = sch->schib.pmcw.dev;
+ cdev->private->dev_id.devno = sch->schib.pmcw.dev;
} else
need_rename = 0;
device_remove_files(&cdev->dev);
@@ -662,7 +660,7 @@ ccw_device_do_unreg_rereg(void *data)
snprintf (cdev->dev.bus_id, BUS_ID_SIZE, "0.%x.%04x",
sch->schid.ssid, sch->schib.pmcw.dev);
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_add_changed, (void *)cdev);
+ ccw_device_add_changed, cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
@@ -687,7 +685,7 @@ io_subchannel_register(void *data)
int ret;
unsigned long flags;
- cdev = (struct ccw_device *) data;
+ cdev = data;
sch = to_subchannel(cdev->dev.parent);
if (klist_node_attached(&cdev->dev.knode_parent)) {
@@ -759,7 +757,7 @@ io_subchannel_recog_done(struct ccw_device *cdev)
break;
sch = to_subchannel(cdev->dev.parent);
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister, (void *) cdev);
+ ccw_device_call_sch_unregister, cdev);
queue_work(slow_path_wq, &cdev->private->kick_work);
if (atomic_dec_and_test(&ccw_device_init_count))
wake_up(&ccw_device_init_wq);
@@ -774,7 +772,7 @@ io_subchannel_recog_done(struct ccw_device *cdev)
if (!get_device(&cdev->dev))
break;
PREPARE_WORK(&cdev->private->kick_work,
- io_subchannel_register, (void *) cdev);
+ io_subchannel_register, cdev);
queue_work(slow_path_wq, &cdev->private->kick_work);
break;
}
@@ -792,9 +790,9 @@ io_subchannel_recog(struct ccw_device *cdev, struct subchannel *sch)
/* Init private data. */
priv = cdev->private;
- priv->devno = sch->schib.pmcw.dev;
- priv->ssid = sch->schid.ssid;
- priv->sch_no = sch->schid.sch_no;
+ priv->dev_id.devno = sch->schib.pmcw.dev;
+ priv->dev_id.ssid = sch->schid.ssid;
+ priv->schid = sch->schid;
priv->state = DEV_STATE_NOT_OPER;
INIT_LIST_HEAD(&priv->cmb_list);
init_waitqueue_head(&priv->wait_q);
@@ -912,7 +910,7 @@ io_subchannel_remove (struct subchannel *sch)
*/
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_unregister, (void *) cdev);
+ ccw_device_unregister, cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
return 0;
@@ -1055,7 +1053,7 @@ __ccwdev_check_busid(struct device *dev, void *id)
{
char *bus_id;
- bus_id = (char *)id;
+ bus_id = id;
return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0);
}
diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h
index 00be9a5b4acd..c6140cc97a80 100644
--- a/drivers/s390/cio/device.h
+++ b/drivers/s390/cio/device.h
@@ -21,7 +21,6 @@ enum dev_state {
/* states to wait for i/o completion before doing something */
DEV_STATE_CLEAR_VERIFY,
DEV_STATE_TIMEOUT_KILL,
- DEV_STATE_WAIT4IO,
DEV_STATE_QUIESCE,
/* special states for devices gone not operational */
DEV_STATE_DISCONNECTED,
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index dace46fc32e8..de3d0857db9f 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -59,18 +59,6 @@ device_set_disconnected(struct subchannel *sch)
cdev->private->state = DEV_STATE_DISCONNECTED;
}
-void
-device_set_waiting(struct subchannel *sch)
-{
- struct ccw_device *cdev;
-
- if (!sch->dev.driver_data)
- return;
- cdev = sch->dev.driver_data;
- ccw_device_set_timeout(cdev, 10*HZ);
- cdev->private->state = DEV_STATE_WAIT4IO;
-}
-
/*
* Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
*/
@@ -183,9 +171,9 @@ ccw_device_handle_oper(struct ccw_device *cdev)
cdev->id.cu_model != cdev->private->senseid.cu_model ||
cdev->id.dev_type != cdev->private->senseid.dev_type ||
cdev->id.dev_model != cdev->private->senseid.dev_model ||
- cdev->private->devno != sch->schib.pmcw.dev) {
+ cdev->private->dev_id.devno != sch->schib.pmcw.dev) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_do_unreg_rereg, (void *)cdev);
+ ccw_device_do_unreg_rereg, cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
return 0;
}
@@ -255,7 +243,7 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
case DEV_STATE_NOT_OPER:
CIO_DEBUG(KERN_WARNING, 2,
"SenseID : unknown device %04x on subchannel "
- "0.%x.%04x\n", cdev->private->devno,
+ "0.%x.%04x\n", cdev->private->dev_id.devno,
sch->schid.ssid, sch->schid.sch_no);
break;
case DEV_STATE_OFFLINE:
@@ -282,14 +270,15 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: "
"CU Type/Mod = %04X/%02X, Dev Type/Mod = "
"%04X/%02X\n",
- cdev->private->ssid, cdev->private->devno,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno,
cdev->id.cu_type, cdev->id.cu_model,
cdev->id.dev_type, cdev->id.dev_model);
break;
case DEV_STATE_BOXED:
CIO_DEBUG(KERN_WARNING, 2,
"SenseID : boxed device %04x on subchannel "
- "0.%x.%04x\n", cdev->private->devno,
+ "0.%x.%04x\n", cdev->private->dev_id.devno,
sch->schid.ssid, sch->schid.sch_no);
break;
}
@@ -325,13 +314,13 @@ ccw_device_oper_notify(void *data)
struct subchannel *sch;
int ret;
- cdev = (struct ccw_device *)data;
+ cdev = data;
sch = to_subchannel(cdev->dev.parent);
ret = (sch->driver && sch->driver->notify) ?
sch->driver->notify(&sch->dev, CIO_OPER) : 0;
if (!ret)
/* Driver doesn't want device back. */
- ccw_device_do_unreg_rereg((void *)cdev);
+ ccw_device_do_unreg_rereg(cdev);
else {
/* Reenable channel measurements, if needed. */
cmf_reenable(cdev);
@@ -349,6 +338,8 @@ ccw_device_done(struct ccw_device *cdev, int state)
sch = to_subchannel(cdev->dev.parent);
+ ccw_device_set_timeout(cdev, 0);
+
if (state != DEV_STATE_ONLINE)
cio_disable_subchannel(sch);
@@ -361,12 +352,12 @@ ccw_device_done(struct ccw_device *cdev, int state)
if (state == DEV_STATE_BOXED)
CIO_DEBUG(KERN_WARNING, 2,
"Boxed device %04x on subchannel %04x\n",
- cdev->private->devno, sch->schid.sch_no);
+ cdev->private->dev_id.devno, sch->schid.sch_no);
if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0;
PREPARE_WORK(&cdev->private->kick_work, ccw_device_oper_notify,
- (void *)cdev);
+ cdev);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
@@ -410,7 +401,8 @@ static void __ccw_device_get_common_pgid(struct ccw_device *cdev)
/* PGID mismatch, can't pathgroup. */
CIO_MSG_EVENT(0, "SNID - pgid mismatch for device "
"0.%x.%04x, can't pathgroup\n",
- cdev->private->ssid, cdev->private->devno);
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
cdev->private->options.pgroup = 0;
return;
}
@@ -521,7 +513,7 @@ ccw_device_nopath_notify(void *data)
struct subchannel *sch;
int ret;
- cdev = (struct ccw_device *)data;
+ cdev = data;
sch = to_subchannel(cdev->dev.parent);
/* Extra sanity. */
if (sch->lpm)
@@ -535,7 +527,7 @@ ccw_device_nopath_notify(void *data)
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
ccw_device_call_sch_unregister,
- (void *)cdev);
+ cdev);
queue_work(ccw_device_work,
&cdev->private->kick_work);
} else
@@ -586,11 +578,15 @@ ccw_device_verify_done(struct ccw_device *cdev, int err)
}
break;
case -ETIME:
+ /* Reset oper notify indication after verify error. */
+ cdev->private->flags.donotify = 0;
ccw_device_done(cdev, DEV_STATE_BOXED);
break;
default:
+ /* Reset oper notify indication after verify error. */
+ cdev->private->flags.donotify = 0;
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
+ ccw_device_nopath_notify, cdev);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
ccw_device_done(cdev, DEV_STATE_NOT_OPER);
break;
@@ -721,7 +717,7 @@ ccw_device_offline_notoper(struct ccw_device *cdev, enum dev_event dev_event)
sch = to_subchannel(cdev->dev.parent);
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister, (void *)cdev);
+ ccw_device_call_sch_unregister, cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
@@ -752,7 +748,7 @@ ccw_device_online_notoper(struct ccw_device *cdev, enum dev_event dev_event)
}
if (get_device(&cdev->dev)) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_call_sch_unregister, (void *)cdev);
+ ccw_device_call_sch_unregister, cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
}
wake_up(&cdev->private->wait_q);
@@ -857,7 +853,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
sch = to_subchannel(cdev->dev.parent);
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
+ ccw_device_nopath_notify, cdev);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
@@ -883,7 +879,8 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
/* Basic sense hasn't started. Try again. */
ccw_device_do_sense(cdev, irb);
else {
- printk("Huh? %s(%s): unsolicited interrupt...\n",
+ printk(KERN_INFO "Huh? %s(%s): unsolicited "
+ "interrupt...\n",
__FUNCTION__, cdev->dev.bus_id);
if (cdev->handler)
cdev->handler (cdev, 0, irb);
@@ -942,10 +939,10 @@ ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
cdev->private->state = DEV_STATE_ONLINE;
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
- ERR_PTR(-ETIMEDOUT));
+ ERR_PTR(-EIO));
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
+ ccw_device_nopath_notify, cdev);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
} else if (cdev->private->flags.doverify)
/* Start delayed path verification. */
@@ -968,7 +965,7 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
sch = to_subchannel(cdev->dev.parent);
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
+ ccw_device_nopath_notify, cdev);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
@@ -979,51 +976,15 @@ ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
cdev->private->state = DEV_STATE_ONLINE;
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
- ERR_PTR(-ETIMEDOUT));
-}
-
-static void
-ccw_device_wait4io_irq(struct ccw_device *cdev, enum dev_event dev_event)
-{
- struct irb *irb;
- struct subchannel *sch;
-
- irb = (struct irb *) __LC_IRB;
- /*
- * Accumulate status and find out if a basic sense is needed.
- * This is fine since we have already adapted the lpm.
- */
- ccw_device_accumulate_irb(cdev, irb);
- if (cdev->private->flags.dosense) {
- if (ccw_device_do_sense(cdev, irb) == 0) {
- cdev->private->state = DEV_STATE_W4SENSE;
- }
- return;
- }
-
- /* Iff device is idle, reset timeout. */
- sch = to_subchannel(cdev->dev.parent);
- if (!stsch(sch->schid, &sch->schib))
- if (sch->schib.scsw.actl == 0)
- ccw_device_set_timeout(cdev, 0);
- /* Call the handler. */
- ccw_device_call_handler(cdev);
- if (!sch->lpm) {
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
- queue_work(ccw_device_notify_work, &cdev->private->kick_work);
- } else if (cdev->private->flags.doverify)
- ccw_device_online_verify(cdev, 0);
+ ERR_PTR(-EIO));
}
-static void
-ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
+void device_kill_io(struct subchannel *sch)
{
int ret;
- struct subchannel *sch;
+ struct ccw_device *cdev;
- sch = to_subchannel(cdev->dev.parent);
- ccw_device_set_timeout(cdev, 0);
+ cdev = sch->dev.driver_data;
ret = ccw_device_cancel_halt_clear(cdev);
if (ret == -EBUSY) {
ccw_device_set_timeout(cdev, 3*HZ);
@@ -1033,7 +994,7 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
if (ret == -ENODEV) {
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
+ ccw_device_nopath_notify, cdev);
queue_work(ccw_device_notify_work,
&cdev->private->kick_work);
} else
@@ -1042,12 +1003,12 @@ ccw_device_wait4io_timeout(struct ccw_device *cdev, enum dev_event dev_event)
}
if (cdev->handler)
cdev->handler(cdev, cdev->private->intparm,
- ERR_PTR(-ETIMEDOUT));
+ ERR_PTR(-EIO));
if (!sch->lpm) {
PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
+ ccw_device_nopath_notify, cdev);
queue_work(ccw_device_notify_work, &cdev->private->kick_work);
- } else if (cdev->private->flags.doverify)
+ } else
/* Start delayed path verification. */
ccw_device_online_verify(cdev, 0);
}
@@ -1284,12 +1245,6 @@ fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
[DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
[DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
},
- [DEV_STATE_WAIT4IO] = {
- [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq,
- [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout,
- [DEV_EVENT_VERIFY] = ccw_device_delay_verify,
- },
[DEV_STATE_QUIESCE] = {
[DEV_EVENT_NOTOPER] = ccw_device_quiesce_done,
[DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done,
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index 438db483035d..a74785b9e4eb 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -42,18 +42,15 @@ diag210(struct diag210 * addr)
spin_lock_irqsave(&diag210_lock, flags);
diag210_tmp = *addr;
- asm volatile (
- " lhi %0,-1\n"
- " sam31\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
- "1: sam64\n"
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
- : "=&d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory" );
+ asm volatile(
+ " lhi %0,-1\n"
+ " sam31\n"
+ " diag %1,0,0x210\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1: sam64\n"
+ EX_TABLE(0b,1b)
+ : "=&d" (ccode) : "a" (__pa(&diag210_tmp)) : "cc", "memory");
*addr = diag210_tmp;
spin_unlock_irqrestore(&diag210_lock, flags);
@@ -66,17 +63,14 @@ diag210(struct diag210 * addr)
{
int ccode;
- asm volatile (
- " lhi %0,-1\n"
- " diag %1,0,0x210\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " lhi %0,-1\n"
+ " diag %1,0,0x210\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
- : "=&d" (ccode) : "a" (__pa(addr)) : "cc", "memory" );
+ EX_TABLE(0b,1b)
+ : "=&d" (ccode) : "a" (__pa(addr)) : "cc", "memory");
return ccode;
}
@@ -257,7 +251,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
*/
CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel "
"0.%x.%04x reports cmd reject\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no);
return -EOPNOTSUPP;
}
@@ -265,7 +259,8 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
CIO_MSG_EVENT(2, "SenseID : UC on dev 0.%x.%04x, "
"lpum %02X, cnt %02d, sns :"
" %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- cdev->private->ssid, cdev->private->devno,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno,
irb->esw.esw0.sublog.lpum,
irb->esw.esw0.erw.scnt,
irb->ecw[0], irb->ecw[1],
@@ -280,14 +275,15 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
"on subchannel 0.%x.%04x is "
"'not operational'\n", sch->orb.lpm,
- cdev->private->devno, sch->schid.ssid,
- sch->schid.sch_no);
+ cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
return -EACCES;
}
/* Hmm, whatever happened, try again. */
CIO_MSG_EVENT(2, "SenseID : start_IO() for device %04x on "
"subchannel 0.%x.%04x returns status %02X%02X\n",
- cdev->private->devno, sch->schid.ssid, sch->schid.sch_no,
+ cdev->private->dev_id.devno, sch->schid.ssid,
+ sch->schid.sch_no,
irb->scsw.dstat, irb->scsw.cstat);
return -EAGAIN;
}
@@ -336,7 +332,7 @@ ccw_device_sense_id_irq(struct ccw_device *cdev, enum dev_event dev_event)
/* fall through. */
default: /* Sense ID failed. Try asking VM. */
if (MACHINE_IS_VM) {
- VM_virtual_device_info (cdev->private->devno,
+ VM_virtual_device_info (cdev->private->dev_id.devno,
&cdev->private->senseid);
if (cdev->private->senseid.cu_type != 0xFFFF) {
/* Got the device information from VM. */
diff --git a/drivers/s390/cio/device_ops.c b/drivers/s390/cio/device_ops.c
index 93a897eebfff..b39c1fa48acd 100644
--- a/drivers/s390/cio/device_ops.c
+++ b/drivers/s390/cio/device_ops.c
@@ -50,7 +50,6 @@ ccw_device_clear(struct ccw_device *cdev, unsigned long intparm)
if (cdev->private->state == DEV_STATE_NOT_OPER)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
- cdev->private->state != DEV_STATE_WAIT4IO &&
cdev->private->state != DEV_STATE_W4SENSE)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
@@ -155,7 +154,6 @@ ccw_device_halt(struct ccw_device *cdev, unsigned long intparm)
if (cdev->private->state == DEV_STATE_NOT_OPER)
return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE &&
- cdev->private->state != DEV_STATE_WAIT4IO &&
cdev->private->state != DEV_STATE_W4SENSE)
return -EINVAL;
sch = to_subchannel(cdev->dev.parent);
@@ -216,6 +214,9 @@ ccw_device_call_handler(struct ccw_device *cdev)
(stctl & SCSW_STCTL_PRIM_STATUS)))
return 0;
+ /* Clear pending timers for device driver initiated I/O. */
+ if (ending_status)
+ ccw_device_set_timeout(cdev, 0);
/*
* Now we are ready to call the device driver interrupt handler.
*/
@@ -285,10 +286,10 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
if (cdev->private->flags.doverify ||
cdev->private->state == DEV_STATE_VERIFY)
cdev->private->intparm = -EAGAIN;
- if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
- !(irb->ecw[0] &
- (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
- cdev->private->intparm = -EAGAIN;
+ else if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+ !(irb->ecw[0] &
+ (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ)))
+ cdev->private->intparm = -EAGAIN;
else if ((irb->scsw.dstat & DEV_STAT_ATTENTION) &&
(irb->scsw.dstat & DEV_STAT_DEV_END) &&
(irb->scsw.dstat & DEV_STAT_UNIT_EXCEP))
@@ -309,7 +310,10 @@ __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, _
sch = to_subchannel(cdev->dev.parent);
do {
+ ccw_device_set_timeout(cdev, 60 * HZ);
ret = cio_start (sch, ccw, lpm);
+ if (ret != 0)
+ ccw_device_set_timeout(cdev, 0);
if (ret == -EBUSY) {
/* Try again later. */
spin_unlock_irq(&sch->lock);
@@ -586,13 +590,13 @@ ccw_device_get_chp_desc(struct ccw_device *cdev, int chp_no)
int
_ccw_device_get_subchannel_number(struct ccw_device *cdev)
{
- return cdev->private->sch_no;
+ return cdev->private->schid.sch_no;
}
int
_ccw_device_get_device_number(struct ccw_device *cdev)
{
- return cdev->private->devno;
+ return cdev->private->dev_id.devno;
}
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index 8ca2d078848c..2975ce888c19 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -79,7 +79,8 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not "
"operational'\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno,
+ sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
}
@@ -96,6 +97,9 @@ ccw_device_sense_pgid_start(struct ccw_device *cdev)
{
int ret;
+ /* Set a timeout of 60s */
+ ccw_device_set_timeout(cdev, 60*HZ);
+
cdev->private->state = DEV_STATE_SENSE_PGID;
cdev->private->imask = 0x80;
cdev->private->iretry = 5;
@@ -132,7 +136,8 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
CIO_MSG_EVENT(2, "SNID - device 0.%x.%04x, unit check, "
"lpum %02X, cnt %02d, sns : "
"%02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- cdev->private->ssid, cdev->private->devno,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno,
irb->esw.esw0.sublog.lpum,
irb->esw.esw0.erw.scnt,
irb->ecw[0], irb->ecw[1],
@@ -144,7 +149,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
if (irb->scsw.cc == 3) {
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, sch->orb.lpm);
return -EACCES;
}
@@ -152,7 +157,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
if (cdev->private->pgid[i].inf.ps.state2 == SNID_STATE2_RESVD_ELSE) {
CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x "
"is reserved by someone else\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no);
return -EUSERS;
}
@@ -258,7 +263,7 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
/* PGID command failed on this path. */
CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not operational'\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
return ret;
}
@@ -298,7 +303,7 @@ static int __ccw_device_do_nop(struct ccw_device *cdev)
/* nop command failed on this path. */
CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not operational'\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
return ret;
}
@@ -325,8 +330,9 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
CIO_MSG_EVENT(2, "SPID - device 0.%x.%04x, unit check, "
"cnt %02d, "
"sns : %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- cdev->private->ssid,
- cdev->private->devno, irb->esw.esw0.erw.scnt,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno,
+ irb->esw.esw0.erw.scnt,
irb->ecw[0], irb->ecw[1],
irb->ecw[2], irb->ecw[3],
irb->ecw[4], irb->ecw[5],
@@ -336,7 +342,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
if (irb->scsw.cc == 3) {
CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
return -EACCES;
}
@@ -359,7 +365,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev)
if (irb->scsw.cc == 3) {
CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
- cdev->private->devno, sch->schid.ssid,
+ cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
return -EACCES;
}
@@ -480,6 +486,8 @@ ccw_device_verify_start(struct ccw_device *cdev)
ccw_device_verify_done(cdev, -ENODEV);
return;
}
+ /* After 60s path verification is considered to have failed. */
+ ccw_device_set_timeout(cdev, 60*HZ);
__ccw_device_verify_start(cdev);
}
@@ -554,6 +562,9 @@ ccw_device_disband_irq(struct ccw_device *cdev, enum dev_event dev_event)
void
ccw_device_disband_start(struct ccw_device *cdev)
{
+ /* After 60s disbanding is considered to have failed. */
+ ccw_device_set_timeout(cdev, 60*HZ);
+
cdev->private->flags.pgid_single = 0;
cdev->private->iretry = 5;
cdev->private->imask = 0x80;
diff --git a/drivers/s390/cio/device_status.c b/drivers/s390/cio/device_status.c
index caf148d5caad..3f7cbce4cd87 100644
--- a/drivers/s390/cio/device_status.c
+++ b/drivers/s390/cio/device_status.c
@@ -32,19 +32,18 @@ ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
SCHN_STAT_CHN_CTRL_CHK |
SCHN_STAT_INTF_CTRL_CHK)))
return;
-
CIO_MSG_EVENT(0, "Channel-Check or Interface-Control-Check "
"received"
" ... device %04x on subchannel 0.%x.%04x, dev_stat "
": %02X sch_stat : %02X\n",
- cdev->private->devno, cdev->private->ssid,
- cdev->private->sch_no,
+ cdev->private->dev_id.devno, cdev->private->schid.ssid,
+ cdev->private->schid.sch_no,
irb->scsw.dstat, irb->scsw.cstat);
if (irb->scsw.cc != 3) {
char dbf_text[15];
- sprintf(dbf_text, "chk%x", cdev->private->sch_no);
+ sprintf(dbf_text, "chk%x", cdev->private->schid.sch_no);
CIO_TRACE_EVENT(0, dbf_text);
CIO_HEX_EVENT(0, irb, sizeof (struct irb));
}
diff --git a/drivers/s390/cio/ioasm.h b/drivers/s390/cio/ioasm.h
index 95a9462f9a91..ad6d82940069 100644
--- a/drivers/s390/cio/ioasm.h
+++ b/drivers/s390/cio/ioasm.h
@@ -25,106 +25,74 @@ struct tpi_info {
static inline int stsch(struct subchannel_id schid,
volatile struct schib *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " stsch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " stsch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int stsch_err(struct subchannel_id schid,
volatile struct schib *addr)
{
- int ccode;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
- __asm__ __volatile__(
- " lhi %0,%3\n"
- " lr 1,%1\n"
- " stsch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " stsch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifdef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (ccode)
- : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
- : "cc", "1" );
+ EX_TABLE(0b,1b)
+ : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int msch(struct subchannel_id schid,
volatile struct schib *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " msch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " msch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int msch_err(struct subchannel_id schid,
volatile struct schib *addr)
{
- int ccode;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ int ccode = -EIO;
- __asm__ __volatile__(
- " lhi %0,%3\n"
- " lr 1,%1\n"
- " msch 0(%2)\n"
- "0: ipm %0\n"
- " srl %0,28\n"
+ asm volatile(
+ " msch 0(%2)\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
"1:\n"
-#ifdef CONFIG_64BIT
- ".section __ex_table,\"a\"\n"
- " .align 8\n"
- " .quad 0b,1b\n"
- ".previous"
-#else
- ".section __ex_table,\"a\"\n"
- " .align 4\n"
- " .long 0b,1b\n"
- ".previous"
-#endif
- : "=&d" (ccode)
- : "d" (schid), "a" (addr), "K" (-EIO), "m" (*addr)
- : "cc", "1" );
+ EX_TABLE(0b,1b)
+ : "+d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int tsch(struct subchannel_id schid,
volatile struct irb *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " tsch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " tsch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
@@ -132,89 +100,77 @@ static inline int tpi( volatile struct tpi_info *addr)
{
int ccode;
- __asm__ __volatile__(
- " tpi 0(%1)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " tpi 0(%1)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int ssch(struct subchannel_id schid,
volatile struct orb *addr)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " ssch 0(%2)\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid), "a" (addr), "m" (*addr)
- : "cc", "1" );
+ asm volatile(
+ " ssch 0(%2)\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1), "a" (addr), "m" (*addr) : "cc");
return ccode;
}
static inline int rsch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " rsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " rsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
static inline int csch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " csch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " csch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
static inline int hsch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " hsch\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " hsch\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
static inline int xsch(struct subchannel_id schid)
{
+ register struct subchannel_id reg1 asm ("1") = schid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " .insn rre,0xb2760000,%1,0\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (schid)
- : "cc", "1" );
+ asm volatile(
+ " .insn rre,0xb2760000,%1,0\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
@@ -223,41 +179,27 @@ static inline int chsc(void *chsc_area)
typedef struct { char _[4096]; } addr_type;
int cc;
- __asm__ __volatile__ (
- ".insn rre,0xb25f0000,%2,0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
+ asm volatile(
+ " .insn rre,0xb25f0000,%2,0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
: "=d" (cc), "=m" (*(addr_type *) chsc_area)
: "d" (chsc_area), "m" (*(addr_type *) chsc_area)
- : "cc" );
-
+ : "cc");
return cc;
}
-static inline int iac( void)
-{
- int ccode;
-
- __asm__ __volatile__(
- " iac 1\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode) : : "cc", "1" );
- return ccode;
-}
-
static inline int rchp(int chpid)
{
+ register unsigned int reg1 asm ("1") = chpid;
int ccode;
- __asm__ __volatile__(
- " lr 1,%1\n"
- " rchp\n"
- " ipm %0\n"
- " srl %0,28"
- : "=d" (ccode)
- : "d" (chpid)
- : "cc", "1" );
+ asm volatile(
+ " lr 1,%1\n"
+ " rchp\n"
+ " ipm %0\n"
+ " srl %0,28"
+ : "=d" (ccode) : "d" (reg1) : "cc");
return ccode;
}
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index cde822d8b5c8..476aa1da5cbc 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -1741,7 +1741,7 @@ qdio_fill_qs(struct qdio_irq *irq_ptr, struct ccw_device *cdev,
void *ptr;
int available;
- sprintf(dbf_text,"qfqs%4x",cdev->private->sch_no);
+ sprintf(dbf_text,"qfqs%4x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
for (i=0;i<no_input_qs;i++) {
q=irq_ptr->input_qs[i];
@@ -2924,7 +2924,7 @@ qdio_establish_handle_irq(struct ccw_device *cdev, int cstat, int dstat)
irq_ptr = cdev->private->qdio_data;
- sprintf(dbf_text,"qehi%4x",cdev->private->sch_no);
+ sprintf(dbf_text,"qehi%4x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
@@ -2943,7 +2943,7 @@ qdio_initialize(struct qdio_initialize *init_data)
int rc;
char dbf_text[15];
- sprintf(dbf_text,"qini%4x",init_data->cdev->private->sch_no);
+ sprintf(dbf_text,"qini%4x",init_data->cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
@@ -2964,7 +2964,7 @@ qdio_allocate(struct qdio_initialize *init_data)
struct qdio_irq *irq_ptr;
char dbf_text[15];
- sprintf(dbf_text,"qalc%4x",init_data->cdev->private->sch_no);
+ sprintf(dbf_text,"qalc%4x",init_data->cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
if ( (init_data->no_input_qs>QDIO_MAX_QUEUES_PER_IRQ) ||
@@ -3187,7 +3187,7 @@ qdio_establish(struct qdio_initialize *init_data)
tiqdio_set_delay_target(irq_ptr,TIQDIO_DELAY_TARGET);
}
- sprintf(dbf_text,"qest%4x",cdev->private->sch_no);
+ sprintf(dbf_text,"qest%4x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT0(0,setup,dbf_text);
QDIO_DBF_TEXT0(0,trace,dbf_text);
@@ -3529,7 +3529,7 @@ do_QDIO(struct ccw_device *cdev,unsigned int callflags,
#ifdef CONFIG_QDIO_DEBUG
char dbf_text[20];
- sprintf(dbf_text,"doQD%04x",cdev->private->sch_no);
+ sprintf(dbf_text,"doQD%04x",cdev->private->schid.sch_no);
QDIO_DBF_TEXT3(0,trace,dbf_text);
#endif /* CONFIG_QDIO_DEBUG */
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index 124569362f02..49bb9e371c32 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -274,12 +274,11 @@ do_sqbs(unsigned long sch, unsigned char state, int queue,
register unsigned long _sch asm ("1") = sch;
unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
- asm volatile (
- " .insn rsy,0xeb000000008A,%1,0,0(%2)\n\t"
- : "+d" (_ccq), "+d" (_queuestart)
- : "d" ((unsigned long)state), "d" (_sch)
- : "memory", "cc"
- );
+ asm volatile(
+ " .insn rsy,0xeb000000008A,%1,0,0(%2)"
+ : "+d" (_ccq), "+d" (_queuestart)
+ : "d" ((unsigned long)state), "d" (_sch)
+ : "memory", "cc");
*count = _ccq & 0xff;
*start = _queuestart & 0xff;
@@ -299,12 +298,11 @@ do_eqbs(unsigned long sch, unsigned char *state, int queue,
unsigned long _queuestart = ((unsigned long)queue << 32) | *start;
unsigned long _state = 0;
- asm volatile (
- " .insn rrf,0xB99c0000,%1,%2,0,0 \n\t"
- : "+d" (_ccq), "+d" (_queuestart), "+d" (_state)
- : "d" (_sch)
- : "memory", "cc"
- );
+ asm volatile(
+ " .insn rrf,0xB99c0000,%1,%2,0,0"
+ : "+d" (_ccq), "+d" (_queuestart), "+d" (_state)
+ : "d" (_sch)
+ : "memory", "cc" );
*count = _ccq & 0xff;
*start = _queuestart & 0xff;
*state = _state & 0xff;
@@ -319,69 +317,35 @@ do_eqbs(unsigned long sch, unsigned char *state, int queue,
static inline int
do_siga_sync(struct subchannel_id schid, unsigned int mask1, unsigned int mask2)
{
+ register unsigned long reg0 asm ("0") = 2;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ register unsigned long reg2 asm ("2") = mask1;
+ register unsigned long reg3 asm ("3") = mask2;
int cc;
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 0,2 \n\t"
- "lr 1,%1 \n\t"
- "lr 2,%2 \n\t"
- "lr 3,%3 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
+ asm volatile(
+ " siga 0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
: "=d" (cc)
- : "d" (schid), "d" (mask1), "d" (mask2)
- : "cc", "0", "1", "2", "3"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "lghi 0,2 \n\t"
- "llgfr 1,%1 \n\t"
- "llgfr 2,%2 \n\t"
- "llgfr 3,%3 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- : "=d" (cc)
- : "d" (schid), "d" (mask1), "d" (mask2)
- : "cc", "0", "1", "2", "3"
- );
-#endif /* CONFIG_64BIT */
+ : "d" (reg0), "d" (reg1), "d" (reg2), "d" (reg3) : "cc");
return cc;
}
static inline int
do_siga_input(struct subchannel_id schid, unsigned int mask)
{
+ register unsigned long reg0 asm ("0") = 1;
+ register struct subchannel_id reg1 asm ("1") = schid;
+ register unsigned long reg2 asm ("2") = mask;
int cc;
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 0,1 \n\t"
- "lr 1,%1 \n\t"
- "lr 2,%2 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- : "=d" (cc)
- : "d" (schid), "d" (mask)
- : "cc", "0", "1", "2", "memory"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "lghi 0,1 \n\t"
- "llgfr 1,%1 \n\t"
- "llgfr 2,%2 \n\t"
- "siga 0 \n\t"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
+ asm volatile(
+ " siga 0\n"
+ " ipm %0\n"
+ " srl %0,28\n"
: "=d" (cc)
- : "d" (schid), "d" (mask)
- : "cc", "0", "1", "2", "memory"
- );
-#endif /* CONFIG_64BIT */
-
+ : "d" (reg0), "d" (reg1), "d" (reg2) : "cc", "memory");
return cc;
}
@@ -389,93 +353,35 @@ static inline int
do_siga_output(unsigned long schid, unsigned long mask, __u32 *bb,
unsigned int fc)
{
+ register unsigned long __fc asm("0") = fc;
+ register unsigned long __schid asm("1") = schid;
+ register unsigned long __mask asm("2") = mask;
int cc;
- __u32 busy_bit;
-
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 0,0 \n\t"
- "lr 1,%2 \n\t"
- "lr 2,%3 \n\t"
- "siga 0 \n\t"
- "0:"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- "srl 0,31 \n\t"
- "lr %1,0 \n\t"
- "1: \n\t"
- ".section .fixup,\"ax\"\n\t"
- "2: \n\t"
- "lhi %0,%4 \n\t"
- "bras 1,3f \n\t"
- ".long 1b \n\t"
- "3: \n\t"
- "l 1,0(1) \n\t"
- "br 1 \n\t"
- ".previous \n\t"
- ".section __ex_table,\"a\"\n\t"
- ".align 4 \n\t"
- ".long 0b,2b \n\t"
- ".previous \n\t"
- : "=d" (cc), "=d" (busy_bit)
- : "d" (schid), "d" (mask),
- "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
- : "cc", "0", "1", "2", "memory"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "llgfr 0,%5 \n\t"
- "lgr 1,%2 \n\t"
- "llgfr 2,%3 \n\t"
- "siga 0 \n\t"
- "0:"
- "ipm %0 \n\t"
- "srl %0,28 \n\t"
- "srl 0,31 \n\t"
- "llgfr %1,0 \n\t"
- "1: \n\t"
- ".section .fixup,\"ax\"\n\t"
- "lghi %0,%4 \n\t"
- "jg 1b \n\t"
- ".previous\n\t"
- ".section __ex_table,\"a\"\n\t"
- ".align 8 \n\t"
- ".quad 0b,1b \n\t"
- ".previous \n\t"
- : "=d" (cc), "=d" (busy_bit)
- : "d" (schid), "d" (mask),
- "i" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION), "d" (fc)
- : "cc", "0", "1", "2", "memory"
- );
-#endif /* CONFIG_64BIT */
-
- (*bb) = busy_bit;
+
+ asm volatile(
+ " siga 0\n"
+ "0: ipm %0\n"
+ " srl %0,28\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "=d" (cc), "+d" (__fc), "+d" (__schid), "+d" (__mask)
+ : "0" (QDIO_SIGA_ERROR_ACCESS_EXCEPTION)
+ : "cc", "memory");
+ (*bb) = ((unsigned int) __fc) >> 31;
return cc;
}
static inline unsigned long
do_clear_global_summary(void)
{
-
- unsigned long time;
-
-#ifndef CONFIG_64BIT
- asm volatile (
- "lhi 1,3 \n\t"
- ".insn rre,0xb2650000,2,0 \n\t"
- "lr %0,3 \n\t"
- : "=d" (time) : : "cc", "1", "2", "3"
- );
-#else /* CONFIG_64BIT */
- asm volatile (
- "lghi 1,3 \n\t"
- ".insn rre,0xb2650000,2,0 \n\t"
- "lgr %0,3 \n\t"
- : "=d" (time) : : "cc", "1", "2", "3"
- );
-#endif /* CONFIG_64BIT */
-
- return time;
+ register unsigned long __fn asm("1") = 3;
+ register unsigned long __tmp asm("2");
+ register unsigned long __time asm("3");
+
+ asm volatile(
+ " .insn rre,0xb2650000,2,0"
+ : "+d" (__fn), "=d" (__tmp), "=d" (__time));
+ return __time;
}
/*
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 6ed0985c0c91..c5ccd20b110c 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -449,8 +449,6 @@ static int ap_device_probe(struct device *dev)
ap_dev->drv = ap_drv;
rc = ap_drv->probe ? ap_drv->probe(ap_dev) : -ENODEV;
- if (rc)
- ap_dev->unregistered = 1;
return rc;
}
@@ -487,14 +485,7 @@ static int ap_device_remove(struct device *dev)
struct ap_device *ap_dev = to_ap_dev(dev);
struct ap_driver *ap_drv = ap_dev->drv;
- spin_lock_bh(&ap_dev->lock);
- __ap_flush_queue(ap_dev);
- /**
- * set ->unregistered to 1 while holding the lock. This prevents
- * new messages to be put on the queue from now on.
- */
- ap_dev->unregistered = 1;
- spin_unlock_bh(&ap_dev->lock);
+ ap_flush_queue(ap_dev);
if (ap_drv->remove)
ap_drv->remove(ap_dev);
return 0;
@@ -763,6 +754,7 @@ static void ap_scan_bus(void *data)
break;
ap_dev->qid = qid;
ap_dev->queue_depth = queue_depth;
+ ap_dev->unregistered = 1;
spin_lock_init(&ap_dev->lock);
INIT_LIST_HEAD(&ap_dev->pendingq);
INIT_LIST_HEAD(&ap_dev->requestq);
@@ -784,7 +776,12 @@ static void ap_scan_bus(void *data)
/* Add device attributes. */
rc = sysfs_create_group(&ap_dev->device.kobj,
&ap_dev_attr_group);
- if (rc)
+ if (!rc) {
+ spin_lock_bh(&ap_dev->lock);
+ ap_dev->unregistered = 0;
+ spin_unlock_bh(&ap_dev->lock);
+ }
+ else
device_unregister(&ap_dev->device);
}
}
@@ -970,6 +967,8 @@ void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg)
rc = __ap_queue_message(ap_dev, ap_msg);
if (!rc)
wake_up(&ap_poll_wait);
+ if (rc == -ENODEV)
+ ap_dev->unregistered = 1;
} else {
ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-ENODEV));
rc = 0;
@@ -1028,6 +1027,8 @@ static int __ap_poll_all(struct device *dev, void *data)
spin_lock(&ap_dev->lock);
if (!ap_dev->unregistered) {
rc = ap_poll_queue(to_ap_dev(dev), (unsigned long *) data);
+ if (rc)
+ ap_dev->unregistered = 1;
} else
rc = 0;
spin_unlock(&ap_dev->lock);
@@ -1061,7 +1062,7 @@ static int ap_poll_thread(void *data)
unsigned long flags;
int requests;
- set_user_nice(current, -20);
+ set_user_nice(current, 19);
while (1) {
if (need_resched()) {
schedule();
diff --git a/drivers/s390/net/iucv.c b/drivers/s390/net/iucv.c
index 821dde86e240..1476ce2b437c 100644
--- a/drivers/s390/net/iucv.c
+++ b/drivers/s390/net/iucv.c
@@ -116,7 +116,7 @@ static DEFINE_SPINLOCK(iucv_irq_queue_lock);
*Internal function prototypes
*/
static void iucv_tasklet_handler(unsigned long);
-static void iucv_irq_handler(struct pt_regs *, __u16);
+static void iucv_irq_handler(__u16);
static DECLARE_TASKLET(iucv_tasklet,iucv_tasklet_handler,0);
@@ -534,19 +534,15 @@ iucv_add_handler (handler *new)
*
* Returns: return code from CP's IUCV call
*/
-static __inline__ ulong
-b2f0(__u32 code, void *parm)
+static inline ulong b2f0(__u32 code, void *parm)
{
+ register unsigned long reg0 asm ("0");
+ register unsigned long reg1 asm ("1");
iucv_dumpit("iparml before b2f0 call:", parm, sizeof(iucv_param));
- asm volatile (
- "LRA 1,0(%1)\n\t"
- "LR 0,%0\n\t"
- ".long 0xb2f01000"
- :
- : "d" (code), "a" (parm)
- : "0", "1"
- );
+ reg0 = code;
+ reg1 = virt_to_phys(parm);
+ asm volatile(".long 0xb2f01000" : : "d" (reg0), "a" (reg1));
iucv_dumpit("iparml after b2f0 call:", parm, sizeof(iucv_param));
@@ -1248,6 +1244,8 @@ iucv_purge (__u16 pathid, __u32 msgid, __u32 srccls, __u32 *audit)
static int
iucv_query_generic(int want_maxconn)
{
+ register unsigned long reg0 asm ("0");
+ register unsigned long reg1 asm ("1");
iparml_purge *parm = (iparml_purge *)grab_param();
int bufsize, maxconn;
int ccode;
@@ -1256,18 +1254,15 @@ iucv_query_generic(int want_maxconn)
* Call b2f0 and store R0 (max buffer size),
* R1 (max connections) and CC.
*/
- asm volatile (
- "LRA 1,0(%4)\n\t"
- "LR 0,%3\n\t"
- ".long 0xb2f01000\n\t"
- "IPM %0\n\t"
- "SRL %0,28\n\t"
- "ST 0,%1\n\t"
- "ST 1,%2\n\t"
- : "=d" (ccode), "=m" (bufsize), "=m" (maxconn)
- : "d" (QUERY), "a" (parm)
- : "0", "1", "cc"
- );
+ reg0 = QUERY;
+ reg1 = virt_to_phys(parm);
+ asm volatile(
+ " .long 0xb2f01000\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "+d" (reg0), "+d" (reg1) : : "cc");
+ bufsize = reg0;
+ maxconn = reg1;
release_param(parm);
if (ccode)
@@ -2256,7 +2251,7 @@ iucv_sever(__u16 pathid, __u8 user_data[16])
* Places the interrupt buffer on a queue and schedules iucv_tasklet_handler().
*/
static void
-iucv_irq_handler(struct pt_regs *regs, __u16 code)
+iucv_irq_handler(__u16 code)
{
iucv_irqdata *irqdata;
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 5613b4564fa2..8364d5475ac7 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -8067,7 +8067,7 @@ qeth_arp_constructor(struct neighbour *neigh)
neigh->parms = neigh_parms_clone(parms);
rcu_read_unlock();
- neigh->type = inet_addr_type(*(u32 *) neigh->primary_key);
+ neigh->type = inet_addr_type(*(__be32 *) neigh->primary_key);
neigh->nud_state = NUD_NOARP;
neigh->ops = arp_direct_ops;
neigh->output = neigh->ops->queue_xmit;
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index a914129a4da9..e088b5e28711 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -208,7 +208,7 @@ s390_handle_mcck(void)
*/
__ctl_clear_bit(14, 24); /* Disable WARNING MCH */
if (xchg(&mchchk_wng_posted, 1) == 0)
- kill_proc(1, SIGPWR, 1);
+ kill_cad_pid(SIGPWR, 1);
}
#endif
@@ -253,11 +253,12 @@ s390_revalidate_registers(struct mci *mci)
kill_task = 1;
#ifndef CONFIG_64BIT
- asm volatile("ld 0,0(%0)\n"
- "ld 2,8(%0)\n"
- "ld 4,16(%0)\n"
- "ld 6,24(%0)"
- : : "a" (&S390_lowcore.floating_pt_save_area));
+ asm volatile(
+ " ld 0,0(%0)\n"
+ " ld 2,8(%0)\n"
+ " ld 4,16(%0)\n"
+ " ld 6,24(%0)"
+ : : "a" (&S390_lowcore.floating_pt_save_area));
#endif
if (MACHINE_HAS_IEEE) {
@@ -274,37 +275,36 @@ s390_revalidate_registers(struct mci *mci)
* Floating point control register can't be restored.
* Task will be terminated.
*/
- asm volatile ("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
+ asm volatile("lfpc 0(%0)" : : "a" (&zero), "m" (zero));
kill_task = 1;
- }
- else
- asm volatile (
- "lfpc 0(%0)"
- : : "a" (fpt_creg_save_area));
-
- asm volatile("ld 0,0(%0)\n"
- "ld 1,8(%0)\n"
- "ld 2,16(%0)\n"
- "ld 3,24(%0)\n"
- "ld 4,32(%0)\n"
- "ld 5,40(%0)\n"
- "ld 6,48(%0)\n"
- "ld 7,56(%0)\n"
- "ld 8,64(%0)\n"
- "ld 9,72(%0)\n"
- "ld 10,80(%0)\n"
- "ld 11,88(%0)\n"
- "ld 12,96(%0)\n"
- "ld 13,104(%0)\n"
- "ld 14,112(%0)\n"
- "ld 15,120(%0)\n"
- : : "a" (fpt_save_area));
+ } else
+ asm volatile("lfpc 0(%0)" : : "a" (fpt_creg_save_area));
+
+ asm volatile(
+ " ld 0,0(%0)\n"
+ " ld 1,8(%0)\n"
+ " ld 2,16(%0)\n"
+ " ld 3,24(%0)\n"
+ " ld 4,32(%0)\n"
+ " ld 5,40(%0)\n"
+ " ld 6,48(%0)\n"
+ " ld 7,56(%0)\n"
+ " ld 8,64(%0)\n"
+ " ld 9,72(%0)\n"
+ " ld 10,80(%0)\n"
+ " ld 11,88(%0)\n"
+ " ld 12,96(%0)\n"
+ " ld 13,104(%0)\n"
+ " ld 14,112(%0)\n"
+ " ld 15,120(%0)\n"
+ : : "a" (fpt_save_area));
}
/* Revalidate access registers */
- asm volatile("lam 0,15,0(%0)"
- : : "a" (&S390_lowcore.access_regs_save_area));
+ asm volatile(
+ " lam 0,15,0(%0)"
+ : : "a" (&S390_lowcore.access_regs_save_area));
if (!mci->ar)
/*
* Access registers have unknown contents.
@@ -321,11 +321,13 @@ s390_revalidate_registers(struct mci *mci)
s390_handle_damage("invalid control registers.");
else
#ifdef CONFIG_64BIT
- asm volatile("lctlg 0,15,0(%0)"
- : : "a" (&S390_lowcore.cregs_save_area));
+ asm volatile(
+ " lctlg 0,15,0(%0)"
+ : : "a" (&S390_lowcore.cregs_save_area));
#else
- asm volatile("lctl 0,15,0(%0)"
- : : "a" (&S390_lowcore.cregs_save_area));
+ asm volatile(
+ " lctl 0,15,0(%0)"
+ : : "a" (&S390_lowcore.cregs_save_area));
#endif
/*
@@ -339,20 +341,23 @@ s390_revalidate_registers(struct mci *mci)
* old contents (should be zero) otherwise set it to zero.
*/
if (!mci->pr)
- asm volatile("sr 0,0\n"
- "sckpf"
- : : : "0", "cc");
+ asm volatile(
+ " sr 0,0\n"
+ " sckpf"
+ : : : "0", "cc");
else
asm volatile(
- "l 0,0(%0)\n"
- "sckpf"
- : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc");
+ " l 0,0(%0)\n"
+ " sckpf"
+ : : "a" (&S390_lowcore.tod_progreg_save_area)
+ : "0", "cc");
#endif
/* Revalidate clock comparator register */
- asm volatile ("stck 0(%1)\n"
- "sckc 0(%1)"
- : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
+ asm volatile(
+ " stck 0(%1)\n"
+ " sckc 0(%1)"
+ : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
/* Check if old PSW is valid */
if (!mci->wp)
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index 862a411a4aa0..c88babce9bca 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -1987,7 +1987,7 @@ zfcp_erp_adapter_strategy_open_qdio(struct zfcp_erp_action *erp_action)
sbale = &(adapter->response_queue.buffer[i]->element[0]);
sbale->length = 0;
sbale->flags = SBAL_FLAGS_LAST_ENTRY;
- sbale->addr = 0;
+ sbale->addr = NULL;
}
ZFCP_LOG_TRACE("calling do_QDIO on adapter %s (flags=0x%x, "
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 7cafa34e4c7f..4d2bc7981324 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -301,7 +301,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
int use_timer)
{
int ret;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
scpnt->SCp.ptr = (void *) &wait; /* silent re-use */
scpnt->scsi_done = zfcp_scsi_command_sync_handler;
diff --git a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
index 4fdb2c932210..a54b4ac67568 100644
--- a/drivers/sbus/char/aurora.c
+++ b/drivers/sbus/char/aurora.c
@@ -254,7 +254,7 @@ for(i=0;i<TYPE_1_IRQS;i++)
return 0;
}
-static irqreturn_t aurora_interrupt(int irq, void * dev_id, struct pt_regs * regs);
+static irqreturn_t aurora_interrupt(int irq, void * dev_id);
/* Main probing routine, also sets irq. */
static int aurora_probe(void)
@@ -689,7 +689,7 @@ static void aurora_check_modem(struct Aurora_board const * bp, int chip)
}
/* The main interrupt processing routine */
-static irqreturn_t aurora_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+static irqreturn_t aurora_interrupt(int irq, void * dev_id)
{
unsigned char status;
unsigned char ack,chip/*,chip_id*/;
@@ -2187,7 +2187,7 @@ static void do_softint(void *private_)
#endif
}
-static struct tty_operations aurora_ops = {
+static const struct tty_operations aurora_ops = {
.open = aurora_open,
.close = aurora_close,
.write = aurora_write,
diff --git a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c
index 1cc706e11119..a54e4140683a 100644
--- a/drivers/sbus/char/bbc_envctrl.c
+++ b/drivers/sbus/char/bbc_envctrl.c
@@ -4,14 +4,9 @@
* Copyright (C) 2001 David S. Miller (davem@redhat.com)
*/
-#define __KERNEL_SYSCALLS__
-static int errno;
-
-#include <linux/kernel.h>
#include <linux/kthread.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/kmod.h>
#include <asm/oplib.h>
#include <asm/ebus.h>
@@ -200,7 +195,7 @@ static void do_envctrl_shutdown(struct bbc_cpu_temperature *tp)
printk(KERN_CRIT "kenvctrld: Shutting down the system now.\n");
shutting_down = 1;
- if (execve("/sbin/shutdown", argv, envp) < 0)
+ if (call_usermodehelper("/sbin/shutdown", argv, envp, 0) < 0)
printk(KERN_CRIT "envctrl: shutdown execution failed\n");
}
diff --git a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c
index 7186235594f9..22631f8b9b48 100644
--- a/drivers/sbus/char/bbc_i2c.c
+++ b/drivers/sbus/char/bbc_i2c.c
@@ -331,7 +331,7 @@ EXPORT_SYMBOL(bbc_i2c_readb);
EXPORT_SYMBOL(bbc_i2c_write_buf);
EXPORT_SYMBOL(bbc_i2c_read_buf);
-static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bbc_i2c_interrupt(int irq, void *dev_id)
{
struct bbc_i2c_bus *bp = dev_id;
diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
index 836a58bb0305..f5803ecb1999 100644
--- a/drivers/sbus/char/cpwatchdog.c
+++ b/drivers/sbus/char/cpwatchdog.c
@@ -10,8 +10,6 @@
* timer interrupts. We use a timer to periodically
* reset 'stopped' watchdogs on affected platforms.
*
- * TODO: DevFS support (/dev/watchdogs/0 ... /dev/watchdogs/2)
- *
* Copyright (c) 2000 Eric Brower (ebrower@usa.net)
*/
@@ -187,7 +185,7 @@ MODULE_SUPPORTED_DEVICE
#ifdef WD_DEBUG
static void wd_dumpregs(void);
#endif
-static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t wd_interrupt(int irq, void *dev_id);
static void wd_toggleintr(struct wd_timer* pTimer, int enable);
static void wd_pingtimer(struct wd_timer* pTimer);
static void wd_starttimer(struct wd_timer* pTimer);
@@ -446,7 +444,7 @@ static ssize_t wd_read(struct file * file, char __user *buffer,
#endif /* ifdef WD_DEBUG */
}
-static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wd_interrupt(int irq, void *dev_id)
{
/* Only WD0 will interrupt-- others are NMI and we won't
* see them here....
diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c
index 063e676a3ac0..fff4660cdf96 100644
--- a/drivers/sbus/char/envctrl.c
+++ b/drivers/sbus/char/envctrl.c
@@ -19,20 +19,13 @@
* Daniele Bellucci <bellucda@tiscali.it>
*/
-#define __KERNEL_SYSCALLS__
-static int errno;
-
#include <linux/module.h>
-#include <linux/sched.h>
+#include <linux/init.h>
#include <linux/kthread.h>
-#include <linux/errno.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/init.h>
#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
+#include <linux/kmod.h>
#include <asm/ebus.h>
#include <asm/uaccess.h>
@@ -976,13 +969,15 @@ static void envctrl_do_shutdown(void)
"HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
char *argv[] = {
"/sbin/shutdown", "-h", "now", NULL };
+ int ret;
if (inprog != 0)
return;
inprog = 1;
printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");
- if (0 > execve("/sbin/shutdown", argv, envp)) {
+ ret = call_usermodehelper("/sbin/shutdown", argv, envp, 0);
+ if (ret < 0) {
printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n");
inprog = 0; /* unlikely to succeed, but we could try again */
}
diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c
index 2f698763ba5d..81ba2d71cee2 100644
--- a/drivers/sbus/char/openprom.c
+++ b/drivers/sbus/char/openprom.c
@@ -630,7 +630,7 @@ static int openprom_ioctl(struct inode * inode, struct file * file,
case OPROMPATH2NODE:
if ((file->f_mode & FMODE_READ) == 0)
return -EPERM;
- return openprom_sunos_ioctl(inode, file, cmd, arg, 0);
+ return openprom_sunos_ioctl(inode, file, cmd, arg, NULL);
case OPIOCGET:
case OPIOCNEXTPROP:
diff --git a/drivers/sbus/char/uctrl.c b/drivers/sbus/char/uctrl.c
index 575b1f7ed410..b30372f17f1c 100644
--- a/drivers/sbus/char/uctrl.c
+++ b/drivers/sbus/char/uctrl.c
@@ -217,7 +217,7 @@ uctrl_open(struct inode *inode, struct file *file)
return 0;
}
-static irqreturn_t uctrl_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t uctrl_interrupt(int irq, void *dev_id)
{
struct uctrl_driver *driver = (struct uctrl_driver *)dev_id;
printk("in uctrl_interrupt\n");
@@ -400,7 +400,7 @@ static int __init ts102_uctrl_init(void)
}
driver->regs->uctrl_intr = UCTRL_INTR_RXNE_REQ|UCTRL_INTR_RXNE_MSK;
- printk("uctrl: 0x%x (irq %d)\n", driver->regs, driver->irq);
+ printk("uctrl: 0x%p (irq %d)\n", driver->regs, driver->irq);
uctrl_get_event_status();
uctrl_get_external_status();
return 0;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 5a9475e56d0e..5f8c26cd66ca 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1192,7 +1192,7 @@ out:
} /* End twa_initialize_device_extension() */
/* This function is the interrupt service routine */
-static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+static irqreturn_t twa_interrupt(int irq, void *dev_instance)
{
int request_id, error = 0;
u32 status_reg_value;
@@ -2211,7 +2211,7 @@ static int __init twa_init(void)
{
printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
- return pci_module_init(&twa_driver);
+ return pci_register_driver(&twa_driver);
} /* End twa_init() */
/* This function is called on driver exit */
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index f3a5f422a8e4..99a259c5a0c0 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -2078,8 +2078,7 @@ static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd
} /* End tw_scsi_queue() */
/* This function is the interrupt service routine */
-static irqreturn_t tw_interrupt(int irq, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t tw_interrupt(int irq, void *dev_instance)
{
int request_id;
u32 status_reg_value;
@@ -2486,7 +2485,7 @@ static int __init tw_init(void)
{
printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
- return pci_module_init(&tw_driver);
+ return pci_register_driver(&tw_driver);
} /* End tw_init() */
/* This function is called on driver exit */
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
index 31fe5ea15920..bbd654a2b9b1 100644
--- a/drivers/scsi/3w-xxxx.h
+++ b/drivers/scsi/3w-xxxx.h
@@ -74,7 +74,7 @@ static char *tw_aen_string[] = {
[0x00D] = "ERROR: Logical unit deleted: Unit #",
[0x00F] = "WARNING: SMART threshold exceeded: Port #",
[0x021] = "WARNING: ATA UDMA downgrade: Port #",
- [0x021] = "WARNING: ATA UDMA upgrade: Port #",
+ [0x022] = "WARNING: ATA UDMA upgrade: Port #",
[0x023] = "WARNING: Sector repair occurred: Port #",
[0x024] = "ERROR: SBUF integrity check failure",
[0x025] = "ERROR: Lost cached write: Port #",
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index 657a3ab75399..562432d017b0 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -1462,7 +1462,7 @@ NCR_700_start_command(struct scsi_cmnd *SCp)
}
irqreturn_t
-NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
+NCR_700_intr(int irq, void *dev_id)
{
struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
struct NCR_700_Host_Parameters *hostdata =
@@ -1939,7 +1939,7 @@ NCR_700_abort(struct scsi_cmnd * SCp)
STATIC int
NCR_700_bus_reset(struct scsi_cmnd * SCp)
{
- DECLARE_COMPLETION(complete);
+ DECLARE_COMPLETION_ONSTACK(complete);
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
index 97ebe71b701b..f5c3caf344a7 100644
--- a/drivers/scsi/53c700.h
+++ b/drivers/scsi/53c700.h
@@ -57,7 +57,7 @@ struct NCR_700_Host_Parameters;
struct Scsi_Host *NCR_700_detect(struct scsi_host_template *,
struct NCR_700_Host_Parameters *, struct device *);
int NCR_700_release(struct Scsi_Host *host);
-irqreturn_t NCR_700_intr(int, void *, struct pt_regs *);
+irqreturn_t NCR_700_intr(int, void *);
enum NCR_700_Host_State {
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index acf292736b4e..640536ef77dc 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -323,7 +323,7 @@ static int shutdown (struct Scsi_Host *host);
static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
static int disable (struct Scsi_Host *host);
static int NCR53c7xx_run_tests (struct Scsi_Host *host);
-static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id);
static void NCR53c7x0_intfly (struct Scsi_Host *host);
static int ncr_halt (struct Scsi_Host *host);
static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd
@@ -4227,7 +4227,7 @@ restart:
}
/*
- * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+ * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id)
*
* Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
* the same IRQ line.
@@ -4241,7 +4241,7 @@ restart:
*/
static irqreturn_t
-NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+NCR53c7x0_intr (int irq, void *dev_id)
{
NCR53c7x0_local_declare();
struct Scsi_Host *host; /* Host we are looking at */
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 4ea49fd7965e..cdd033724786 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2653,7 +2653,7 @@ static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapt
Adapters.
*/
-static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier, struct pt_regs *InterruptRegisters)
+static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier)
{
struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) DeviceIdentifier;
unsigned long ProcessorFlags;
@@ -3600,5 +3600,16 @@ static void __exit BusLogic_exit(void)
__setup("BusLogic=", BusLogic_Setup);
+static struct pci_device_id BusLogic_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+MODULE_DEVICE_TABLE(pci, BusLogic_pci_tbl);
+
module_init(BusLogic_init);
module_exit(BusLogic_exit);
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 9792e5af5252..cca6d45eee4d 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -237,10 +237,7 @@ enum BusLogic_BIOS_DiskGeometryTranslation {
Define a Boolean data type.
*/
-typedef enum {
- false,
- true
-} PACKED boolean;
+typedef bool boolean;
/*
Define a 10^18 Statistics Byte Counter data type.
@@ -1350,7 +1347,7 @@ static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device
static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
static int BusLogic_SlaveConfigure(struct scsi_device *);
static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *);
-static irqreturn_t BusLogic_InterruptHandler(int, void *, struct pt_regs *);
+static irqreturn_t BusLogic_InterruptHandler(int, void *);
static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset);
static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...);
static int __init BusLogic_Setup(char *);
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index c4dfcc91ddda..9540eb8efdcb 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -3,11 +3,13 @@ menu "SCSI device support"
config RAID_ATTRS
tristate "RAID Transport Class"
default n
+ depends on BLOCK
---help---
Provides RAID
config SCSI
tristate "SCSI device support"
+ depends on BLOCK
---help---
If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
any other SCSI device under Linux, say Y and make sure that you know
@@ -38,10 +40,10 @@ config SCSI_PROC_FS
default y
---help---
This option enables support for the various files in
- /proc/scsi. In Linux 2.6 this has been superceeded by
+ /proc/scsi. In Linux 2.6 this has been superseded by
files in sysfs but many legacy applications rely on this.
- If unusure say Y.
+ If unsure say Y.
comment "SCSI support type (disk, tape, CD-ROM)"
depends on SCSI
@@ -83,7 +85,7 @@ config CHR_DEV_OSST
tristate "SCSI OnStream SC-x0 tape support"
depends on SCSI
---help---
- The OnStream SC-x0 SCSI tape drives can not be driven by the
+ The OnStream SC-x0 SCSI tape drives cannot be driven by the
standard st driver, but instead need this special osst driver and
use the /dev/osstX char device nodes (major 206). Via usb-storage
and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
@@ -1014,7 +1016,7 @@ config SCSI_SYM53C8XX_MMIO
config SCSI_IPR
tristate "IBM Power Linux RAID adapter support"
- depends on PCI && SCSI
+ depends on PCI && SCSI && ATA
select FW_LOADER
---help---
This driver supports the IBM Power Linux family RAID adapters.
@@ -1244,6 +1246,7 @@ config SCSI_QLOGICPTI
module will be called qlogicpti.
source "drivers/scsi/qla2xxx/Kconfig"
+source "drivers/scsi/qla4xxx/Kconfig"
config SCSI_LPFC
tristate "Emulex LightPulse Fibre Channel Support"
@@ -1260,8 +1263,8 @@ config SCSI_SEAGATE
These are 8-bit SCSI controllers; the ST-01 is also supported by
this driver. It is explained in section 3.9 of the SCSI-HOWTO,
available from <http://www.tldp.org/docs.html#howto>. If it
- doesn't work out of the box, you may have to change some settings in
- <file:drivers/scsi/seagate.h>.
+ doesn't work out of the box, you may have to change some macros at
+ compiletime, which are described in <file:drivers/scsi/seagate.c>.
To compile this driver as a module, choose M here: the
module will be called seagate.
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 1ef951be7a5d..bcca39c3bcbf 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_SCSI_QLOGIC_FAS) += qlogicfas408.o qlogicfas.o
obj-$(CONFIG_PCMCIA_QLOGIC) += qlogicfas408.o
obj-$(CONFIG_SCSI_QLOGIC_1280) += qla1280.o
obj-$(CONFIG_SCSI_QLA_FC) += qla2xxx/
+obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx/
obj-$(CONFIG_SCSI_LPFC) += lpfc/
obj-$(CONFIG_SCSI_PAS16) += pas16.o
obj-$(CONFIG_SCSI_SEAGATE) += seagate.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 616810ad17d8..a6aa91072880 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -558,8 +558,7 @@ static int probe_irq __initdata = 0;
* used by the IRQ probe code.
*/
-static irqreturn_t __init probe_intr(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t __init probe_intr(int irq, void *dev_id)
{
probe_irq = irq;
return IRQ_HANDLED;
@@ -1148,7 +1147,6 @@ static void NCR5380_main(void *p)
* NCR5380_intr - generic NCR5380 irq handler
* @irq: interrupt number
* @dev_id: device info
- * @regs: registers (unused)
*
* Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
* from the disconnected queue, and restarting NCR5380_main()
@@ -1157,7 +1155,7 @@ static void NCR5380_main(void *p)
* Locks: takes the needed instance locks
*/
-static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
NCR5380_local_declare();
struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index c3462e358d1c..1bc73de496b0 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -296,7 +296,7 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags);
static void NCR5380_exit(struct Scsi_Host *instance);
static void NCR5380_information_transfer(struct Scsi_Host *instance);
#ifndef DONT_USE_INTR
-static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t NCR5380_intr(int irq, void *dev_id);
#endif
static void NCR5380_main(void *ptr);
static void NCR5380_print_options(struct Scsi_Host *instance);
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
index bdc6bb262bce..3c912ee29da0 100644
--- a/drivers/scsi/NCR53C9x.c
+++ b/drivers/scsi/NCR53C9x.c
@@ -96,7 +96,7 @@ enum {
static struct NCR_ESP *espchain;
int nesps = 0, esps_in_use = 0, esps_running = 0;
-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+irqreturn_t esp_intr(int irq, void *dev_id);
/* Debugging routines */
static struct esp_cmdstrings {
@@ -3533,7 +3533,7 @@ state_machine:
}
#ifndef CONFIG_SMP
-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+irqreturn_t esp_intr(int irq, void *dev_id)
{
struct NCR_ESP *esp;
unsigned long flags;
@@ -3570,7 +3570,7 @@ repeat:
}
#else
/* For SMP we only service one ESP on the list list at our IRQ level! */
-irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+irqreturn_t esp_intr(int irq, void *dev_id)
{
struct NCR_ESP *esp;
unsigned long flags;
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
index 481653c977cf..521e3f842cfd 100644
--- a/drivers/scsi/NCR53C9x.h
+++ b/drivers/scsi/NCR53C9x.h
@@ -656,7 +656,7 @@ extern struct NCR_ESP *esp_allocate(struct scsi_host_template *, void *);
extern void esp_deallocate(struct NCR_ESP *);
extern void esp_release(void);
extern void esp_initialize(struct NCR_ESP *);
-extern irqreturn_t esp_intr(int, void *, struct pt_regs *);
+extern irqreturn_t esp_intr(int, void *);
extern const char *esp_info(struct Scsi_Host *);
extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
extern int esp_abort(Scsi_Cmnd *);
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index 8472c5359023..d4613815f685 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -168,8 +168,8 @@ enum Phase {
};
/* Static function prototypes */
-static void NCR53c406a_intr(int, void *, struct pt_regs *);
-static irqreturn_t do_NCR53c406a_intr(int, void *, struct pt_regs *);
+static void NCR53c406a_intr(void *);
+static irqreturn_t do_NCR53c406a_intr(int, void *);
static void chip_init(void);
static void calc_port_addr(void);
#ifndef IRQ_LEV
@@ -685,7 +685,7 @@ static void wait_intr(void)
return;
}
- NCR53c406a_intr(0, NULL, NULL);
+ NCR53c406a_intr(NULL);
}
#endif
@@ -761,19 +761,18 @@ static int NCR53c406a_biosparm(struct scsi_device *disk,
return 0;
}
-static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave(dev->host_lock, flags);
- NCR53c406a_intr(0, dev_id, regs);
+ NCR53c406a_intr(dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
-static void NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs)
+static void NCR53c406a_intr(void *dev_id)
{
DEB(unsigned char fifo_size;
)
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
index d05681f9d81a..9859cd17fc57 100644
--- a/drivers/scsi/NCR_D700.c
+++ b/drivers/scsi/NCR_D700.c
@@ -226,14 +226,14 @@ NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
}
static int
-NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
+NCR_D700_intr(int irq, void *data)
{
struct NCR_D700_private *p = (struct NCR_D700_private *)data;
int i, found = 0;
for (i = 0; i < 2; i++)
if (p->hosts[i] &&
- NCR_700_intr(irq, p->hosts[i], regs) == IRQ_HANDLED)
+ NCR_700_intr(irq, p->hosts[i]) == IRQ_HANDLED)
found++;
return found ? IRQ_HANDLED : IRQ_NONE;
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
index c39ffbb86e39..778844c3544a 100644
--- a/drivers/scsi/NCR_Q720.c
+++ b/drivers/scsi/NCR_Q720.c
@@ -54,7 +54,7 @@ static struct scsi_host_template NCR_Q720_tpnt = {
};
static irqreturn_t
-NCR_Q720_intr(int irq, void *data, struct pt_regs * regs)
+NCR_Q720_intr(int irq, void *data)
{
struct NCR_Q720_private *p = (struct NCR_Q720_private *)data;
__u8 sir = (readb(p->mem_base + 0x0d) & 0xf0) >> 4;
@@ -68,7 +68,7 @@ NCR_Q720_intr(int irq, void *data, struct pt_regs * regs)
while((siop = ffz(sir)) < p->siops) {
sir |= 1<<siop;
- ncr53c8xx_intr(irq, p->hosts[siop], regs);
+ ncr53c8xx_intr(irq, p->hosts[siop]);
}
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
index d7e9fab54c60..2650a5d0a161 100644
--- a/drivers/scsi/a100u2w.c
+++ b/drivers/scsi/a100u2w.c
@@ -1013,7 +1013,7 @@ static void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
/*
* Interrupt handler (main routine of the driver)
*/
-static irqreturn_t inia100_intr(int irqno, void *devid, struct pt_regs *regs)
+static irqreturn_t inia100_intr(int irqno, void *devid)
{
struct Scsi_Host *host = (struct Scsi_Host *)devid;
ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
@@ -1187,7 +1187,7 @@ static struct pci_driver inia100_pci_driver = {
static int __init inia100_init(void)
{
- return pci_module_init(&inia100_pci_driver);
+ return pci_register_driver(&inia100_pci_driver);
}
static void __exit inia100_exit(void)
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
index 085406928605..f77016d31cab 100644
--- a/drivers/scsi/a2091.c
+++ b/drivers/scsi/a2091.c
@@ -24,7 +24,7 @@
#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
-static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
+static irqreturn_t a2091_intr (int irq, void *_instance)
{
unsigned long flags;
unsigned int status;
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
index 7bf46d40b561..1299bc8edef1 100644
--- a/drivers/scsi/a3000.c
+++ b/drivers/scsi/a3000.c
@@ -26,7 +26,7 @@
static struct Scsi_Host *a3000_host = NULL;
-static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t a3000_intr (int irq, void *dummy)
{
unsigned long flags;
unsigned int status = DMA(a3000_host)->ISTR;
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
index a1d214d770eb..dcc8b0ea7a9d 100644
--- a/drivers/scsi/aacraid/rx.c
+++ b/drivers/scsi/aacraid/rx.c
@@ -46,11 +46,11 @@
#include "aacraid.h"
-static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t aac_rx_intr(int irq, void *dev_id)
{
struct aac_dev *dev = dev_id;
- dprintk((KERN_DEBUG "aac_rx_intr(%d,%p,%p)\n", irq, dev_id, regs));
+ dprintk((KERN_DEBUG "aac_rx_intr(%d,%p)\n", irq, dev_id));
if (dev->new_comm_interface) {
u32 Index = rx_readl(dev, MUnit.OutboundQueue);
if (Index == 0xFFFFFFFFL)
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
index f906ead239dd..511b0a938fb1 100644
--- a/drivers/scsi/aacraid/sa.c
+++ b/drivers/scsi/aacraid/sa.c
@@ -46,7 +46,7 @@
#include "aacraid.h"
-static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t aac_sa_intr(int irq, void *dev_id)
{
struct aac_dev *dev = dev_id;
unsigned short intstat, mask;
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 773f02e3b10b..2b344356a29e 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -3881,7 +3881,7 @@ typedef struct asc_board {
/*
* The following fields are used only for Wide Boards.
*/
- void *ioremap_addr; /* I/O Memory remap address. */
+ void __iomem *ioremap_addr; /* I/O Memory remap address. */
ushort ioport; /* I/O Port address. */
ADV_CARR_T *orig_carrp; /* ADV_CARR_T memory block. */
adv_req_t *orig_reqp; /* adv_req_t memory block. */
@@ -3951,7 +3951,7 @@ typedef struct _PCI_CONFIG_SPACE_
/* Number of boards detected in system. */
STATIC int asc_board_count = 0;
-STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
+STATIC struct Scsi_Host *asc_host[ASC_NUM_BOARD_SUPPORTED] = { NULL };
/* Overrun buffer used by all narrow boards. */
STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
@@ -3999,7 +3999,7 @@ STATIC PortAddr _asc_def_iop_base[];
* advansys.h contains function prototypes for functions global to Linux.
*/
-STATIC irqreturn_t advansys_interrupt(int, void *, struct pt_regs *);
+STATIC irqreturn_t advansys_interrupt(int, void *);
STATIC int advansys_slave_configure(struct scsi_device *);
STATIC void asc_scsi_done_list(struct scsi_cmnd *);
STATIC int asc_execute_scsi_cmnd(struct scsi_cmnd *);
@@ -5997,7 +5997,7 @@ static struct scsi_host_template driver_template = {
* an AdvanSys adapter.
*/
STATIC irqreturn_t
-advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+advansys_interrupt(int irq, void *dev_id)
{
ulong flags;
int i;
@@ -6621,7 +6621,7 @@ adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
dma_map_single(dev, scp->request_buffer,
scp->request_bufflen, scp->sc_data_direction);
} else {
- scsiqp->vdata_addr = 0;
+ scsiqp->vdata_addr = NULL;
scp->SCp.dma_handle = 0;
}
scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index fb6a476eb873..306f46b85a55 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -238,7 +238,7 @@
#include <linux/module.h>
#include <linux/sched.h>
#include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/blkdev.h>
#include <asm/system.h>
#include <linux/errno.h>
@@ -673,7 +673,7 @@ static struct {
};
/* setup & interrupt */
-static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);
+static irqreturn_t intr(int irq, void *dev_id);
static void reset_ports(struct Scsi_Host *shpnt);
static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
static void done(struct Scsi_Host *shpnt, int error);
@@ -757,14 +757,9 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
return ptr;
}
-static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t swintr(int irqno, void *dev_id)
{
- struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
-
- if (!shpnt) {
- printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
- return IRQ_NONE;
- }
+ struct Scsi_Host *shpnt = dev_id;
HOSTDATA(shpnt)->swint++;
@@ -1463,7 +1458,7 @@ static void run(void)
* Interrupt handler
*
*/
-static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t intr(int irqno, void *dev_id)
{
struct Scsi_Host *shpnt = (struct Scsi_Host *)dev_id;
unsigned long flags;
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 24f0f5461792..d7a61a6bdaae 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -174,9 +174,8 @@ static DEFINE_SPINLOCK(aha1542_lock);
static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
static int aha1542_restart(struct Scsi_Host *shost);
-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs);
-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs);
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id);
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id);
#define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
@@ -416,8 +415,7 @@ fail:
}
/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
-static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *shost;
@@ -427,13 +425,13 @@ static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
panic("Splunge!");
spin_lock_irqsave(shost->host_lock, flags);
- aha1542_intr_handle(shost, dev_id, regs);
+ aha1542_intr_handle(shost, dev_id);
spin_unlock_irqrestore(shost->host_lock, flags);
return IRQ_HANDLED;
}
/* A "high" level interrupt handler */
-static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs)
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id)
{
void (*my_done) (Scsi_Cmnd *) = NULL;
int errstatus, mbi, mbo, mbistatus;
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 0e4a7ebe300a..c3c38a7e8d32 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -223,8 +223,7 @@ static int aha1740_test_port(unsigned int base)
}
/* A "high" level interrupt handler */
-static irqreturn_t aha1740_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t aha1740_intr_handle(int irq, void *dev_id)
{
struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
void (*my_done)(Scsi_Cmnd *);
@@ -681,6 +680,7 @@ static struct eisa_device_id aha1740_ids[] = {
{ "ADP0400" }, /* 1744 */
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, aha1740_ids);
static struct eisa_driver aha1740_driver = {
.id_table = aha1740_ids,
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
index 7955ebe8e1e8..911ea1756e55 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic79xx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -22,12 +22,12 @@ config AIC79XX_CMDS_PER_DEVICE
to be used for any device. The aic7xxx driver will automatically
vary this number based on device behavior. For devices with a
fixed maximum, the driver will eventually lock to this maximum
- and display a console message inidicating this value.
+ and display a console message indicating this value.
Due to resource allocation issues in the Linux SCSI mid-layer, using
a high number of commands per device may result in memory allocation
failures when many devices are attached to the system. For this reason,
- the default is set to 32. Higher values may result in higer performance
+ the default is set to 32. Higher values may result in higher performance
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
index 5517da5855f0..cd93f9a8611f 100644
--- a/drivers/scsi/aic7xxx/Kconfig.aic7xxx
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -27,12 +27,12 @@ config AIC7XXX_CMDS_PER_DEVICE
to be used for any device. The aic7xxx driver will automatically
vary this number based on device behavior. For devices with a
fixed maximum, the driver will eventually lock to this maximum
- and display a console message inidicating this value.
+ and display a console message indicating this value.
Due to resource allocation issues in the Linux SCSI mid-layer, using
a high number of commands per device may result in memory allocation
failures when many devices are attached to the system. For this reason,
- the default is set to 32. Higher values may result in higer performance
+ the default is set to 32. Higher values may result in higher performance
on some devices. The upper bound is 253. 0 disables tagged queueing.
Per device tag depth can be controlled via the kernel command line
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
index 867cbe23579b..1ac119733bac 100644
--- a/drivers/scsi/aic7xxx/aic7770_osm.c
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -132,7 +132,8 @@ static struct eisa_device_id aic7770_ids[] = {
{ "ADP7770", 5 }, /* AIC7770 generic */
{ "" }
};
-
+MODULE_DEVICE_TABLE(eisa, aic7770_ids);
+
static struct eisa_driver aic7770_driver = {
.id_table = aic7770_ids,
.driver = {
diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
index 8ad3ce945b9e..a3266e066c00 100644
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
@@ -527,7 +527,8 @@ ahd_inw(struct ahd_softc *ahd, u_int port)
* or have other side effects when the low byte is
* read.
*/
- return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
+ uint16_t r = ahd_inb(ahd, port+1) << 8;
+ return r | ahd_inb(ahd, port);
}
static __inline void
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index c7eeaced324a..f8e60486167d 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -646,7 +646,7 @@ ahd_linux_dev_reset(struct scsi_cmnd *cmd)
struct ahd_initiator_tinfo *tinfo;
struct ahd_tmode_tstate *tstate;
unsigned long flags;
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
reset_scb = NULL;
paused = FALSE;
@@ -1557,7 +1557,7 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
* SCSI controller interrupt handler.
*/
irqreturn_t
-ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
+ahd_linux_isr(int irq, void *dev_id)
{
struct ahd_softc *ahd;
u_long flags;
@@ -2251,7 +2251,7 @@ done:
if (paused)
ahd_unpause(ahd);
if (wait) {
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
ahd->platform_data->eh_done = &done;
ahd_unlock(ahd, &flags);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
index 601340d84410..fb3d4dd54413 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -862,7 +862,7 @@ int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target,
char channel, int lun, u_int tag,
role_t role, uint32_t status);
irqreturn_t
- ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+ ahd_linux_isr(int irq, void *dev_id);
void ahd_done(struct ahd_softc*, struct scb*);
void ahd_send_async(struct ahd_softc *, char channel,
u_int target, u_int lun, ac_code);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
index 50a41eda580e..4b5354201807 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -198,7 +198,7 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int
ahd_linux_pci_init(void)
{
- return (pci_module_init(&aic79xx_pci_driver));
+ return pci_register_driver(&aic79xx_pci_driver);
}
void
diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
index 2cc8a17ed8b4..8e1954cdd84f 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h
@@ -300,7 +300,8 @@ ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
static __inline uint16_t
ahc_inw(struct ahc_softc *ahc, u_int port)
{
- return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
+ uint16_t r = ahc_inb(ahc, port+1) << 8;
+ return r | ahc_inb(ahc, port);
}
static __inline void
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index 64c8b88a429f..43ab753d2739 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -1608,7 +1608,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
* SCSI controller interrupt handler.
*/
irqreturn_t
-ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
+ahc_linux_isr(int irq, void *dev_id)
{
struct ahc_softc *ahc;
u_long flags;
@@ -2335,7 +2335,7 @@ done:
if (paused)
ahc_unpause(ahc);
if (wait) {
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
ahc->platform_data->eh_done = &done;
ahc_unlock(ahc, &flags);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
index d42a71ee076d..a87a4ce090df 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -830,7 +830,7 @@ int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
char channel, int lun, u_int tag,
role_t role, uint32_t status);
irqreturn_t
- ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+ ahc_linux_isr(int irq, void *dev_id);
void ahc_platform_flushwork(struct ahc_softc *ahc);
void ahc_done(struct ahc_softc*, struct scb*);
void ahc_send_async(struct ahc_softc *, char channel,
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
index 7e42f07a27f3..d20ca514e9f3 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -246,8 +246,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
int
ahc_linux_pci_init(void)
{
- /* Translate error or zero return into zero or one */
- return pci_module_init(&aic7xxx_pci_driver) ? 0 : 1;
+ return pci_register_driver(&aic7xxx_pci_driver);
}
void
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
index 5dcef48d414f..bcd7fffab907 100644
--- a/drivers/scsi/aic7xxx_old.c
+++ b/drivers/scsi/aic7xxx_old.c
@@ -780,24 +780,26 @@ typedef enum {
} ahc_bugs;
struct aic7xxx_scb {
- struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
- Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
- struct aic7xxx_scb *q_next; /* next scb in queue */
- volatile scb_flag_type flags; /* current state of scb */
- struct hw_scatterlist *sg_list; /* SG list in adapter format */
- unsigned char tag_action;
- unsigned char sg_count;
- unsigned char *sense_cmd; /*
- * Allocate 6 characters for
- * sense command.
- */
- unsigned char *cmnd;
- unsigned int sg_length; /* We init this during buildscb so we
- * don't have to calculate anything
- * during underflow/overflow/stat code
- */
- void *kmalloc_ptr;
- struct aic7xxx_scb_dma *scb_dma;
+ struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
+ struct scsi_cmnd *cmd; /* scsi_cmnd for this scb */
+ struct aic7xxx_scb *q_next; /* next scb in queue */
+ volatile scb_flag_type flags; /* current state of scb */
+ struct hw_scatterlist *sg_list; /* SG list in adapter format */
+ unsigned char tag_action;
+ unsigned char sg_count;
+ unsigned char *sense_cmd; /*
+ * Allocate 6 characters for
+ * sense command.
+ */
+ unsigned char *cmnd;
+ unsigned int sg_length; /*
+ * We init this during
+ * buildscb so we don't have
+ * to calculate anything during
+ * underflow/overflow/stat code
+ */
+ void *kmalloc_ptr;
+ struct aic7xxx_scb_dma *scb_dma;
};
/*
@@ -918,79 +920,77 @@ struct aic7xxx_host {
* We are grouping things here....first, items that get either read or
* written with nearly every interrupt
*/
- volatile long flags;
- ahc_feature features; /* chip features */
- unsigned long base; /* card base address */
- volatile unsigned char __iomem *maddr; /* memory mapped address */
- unsigned long isr_count; /* Interrupt count */
- unsigned long spurious_int;
- scb_data_type *scb_data;
- struct aic7xxx_cmd_queue {
- Scsi_Cmnd *head;
- Scsi_Cmnd *tail;
- } completeq;
+ volatile long flags;
+ ahc_feature features; /* chip features */
+ unsigned long base; /* card base address */
+ volatile unsigned char __iomem *maddr; /* memory mapped address */
+ unsigned long isr_count; /* Interrupt count */
+ unsigned long spurious_int;
+ scb_data_type *scb_data;
+ struct aic7xxx_cmd_queue {
+ struct scsi_cmnd *head;
+ struct scsi_cmnd *tail;
+ } completeq;
- /*
- * Things read/written on nearly every entry into aic7xxx_queue()
- */
- volatile scb_queue_type waiting_scbs;
- unsigned char unpause; /* unpause value for HCNTRL */
- unsigned char pause; /* pause value for HCNTRL */
- volatile unsigned char qoutfifonext;
- volatile unsigned char activescbs; /* active scbs */
- volatile unsigned char max_activescbs;
- volatile unsigned char qinfifonext;
- volatile unsigned char *untagged_scbs;
- volatile unsigned char *qoutfifo;
- volatile unsigned char *qinfifo;
-
- unsigned char dev_last_queue_full[MAX_TARGETS];
- unsigned char dev_last_queue_full_count[MAX_TARGETS];
- unsigned short ultraenb; /* Gets downloaded to card as a
- bitmap */
- unsigned short discenable; /* Gets downloaded to card as a
- bitmap */
- transinfo_type user[MAX_TARGETS];
-
- unsigned char msg_buf[13]; /* The message for the target */
- unsigned char msg_type;
+ /*
+ * Things read/written on nearly every entry into aic7xxx_queue()
+ */
+ volatile scb_queue_type waiting_scbs;
+ unsigned char unpause; /* unpause value for HCNTRL */
+ unsigned char pause; /* pause value for HCNTRL */
+ volatile unsigned char qoutfifonext;
+ volatile unsigned char activescbs; /* active scbs */
+ volatile unsigned char max_activescbs;
+ volatile unsigned char qinfifonext;
+ volatile unsigned char *untagged_scbs;
+ volatile unsigned char *qoutfifo;
+ volatile unsigned char *qinfifo;
+
+ unsigned char dev_last_queue_full[MAX_TARGETS];
+ unsigned char dev_last_queue_full_count[MAX_TARGETS];
+ unsigned short ultraenb; /* Gets downloaded to card as a bitmap */
+ unsigned short discenable; /* Gets downloaded to card as a bitmap */
+ transinfo_type user[MAX_TARGETS];
+
+ unsigned char msg_buf[13]; /* The message for the target */
+ unsigned char msg_type;
#define MSG_TYPE_NONE 0x00
#define MSG_TYPE_INITIATOR_MSGOUT 0x01
#define MSG_TYPE_INITIATOR_MSGIN 0x02
- unsigned char msg_len; /* Length of message */
- unsigned char msg_index; /* Index into msg_buf array */
+ unsigned char msg_len; /* Length of message */
+ unsigned char msg_index; /* Index into msg_buf array */
- /*
- * We put the less frequently used host structure items after the more
- * frequently used items to try and ease the burden on the cache subsystem.
- * These entries are not *commonly* accessed, whereas the preceding entries
- * are accessed very often.
- */
-
- unsigned int irq; /* IRQ for this adapter */
- int instance; /* aic7xxx instance number */
- int scsi_id; /* host adapter SCSI ID */
- int scsi_id_b; /* channel B for twin adapters */
- unsigned int bios_address;
- int board_name_index;
- unsigned short bios_control; /* bios control - SEEPROM */
- unsigned short adapter_control; /* adapter control - SEEPROM */
- struct pci_dev *pdev;
- unsigned char pci_bus;
- unsigned char pci_device_fn;
- struct seeprom_config sc;
- unsigned short sc_type;
- unsigned short sc_size;
- struct aic7xxx_host *next; /* allow for multiple IRQs */
- struct Scsi_Host *host; /* pointer to scsi host */
- struct list_head aic_devs; /* all aic_dev structs on host */
- int host_no; /* SCSI host number */
- unsigned long mbase; /* I/O memory address */
- ahc_chip chip; /* chip type */
- ahc_bugs bugs;
- dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
+ /*
+ * We put the less frequently used host structure items
+ * after the more frequently used items to try and ease
+ * the burden on the cache subsystem.
+ * These entries are not *commonly* accessed, whereas
+ * the preceding entries are accessed very often.
+ */
+ unsigned int irq; /* IRQ for this adapter */
+ int instance; /* aic7xxx instance number */
+ int scsi_id; /* host adapter SCSI ID */
+ int scsi_id_b; /* channel B for twin adapters */
+ unsigned int bios_address;
+ int board_name_index;
+ unsigned short bios_control; /* bios control - SEEPROM */
+ unsigned short adapter_control; /* adapter control - SEEPROM */
+ struct pci_dev *pdev;
+ unsigned char pci_bus;
+ unsigned char pci_device_fn;
+ struct seeprom_config sc;
+ unsigned short sc_type;
+ unsigned short sc_size;
+ struct aic7xxx_host *next; /* allow for multiple IRQs */
+ struct Scsi_Host *host; /* pointer to scsi host */
+ struct list_head aic_devs; /* all aic_dev structs on host */
+ int host_no; /* SCSI host number */
+ unsigned long mbase; /* I/O memory address */
+ ahc_chip chip; /* chip type */
+ ahc_bugs bugs;
+ dma_addr_t fifo_dma; /* DMA handle for fifo arrays */
};
/*
@@ -1271,7 +1271,7 @@ static void aic7xxx_set_syncrate(struct aic7xxx_host *p,
static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel,
int lun, unsigned int width, unsigned int type,
struct aic_dev_data *aic_dev);
-static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
+static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd);
static void aic7xxx_print_card(struct aic7xxx_host *p);
static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
@@ -2626,7 +2626,7 @@ aic7xxx_allocate_scb(struct aic7xxx_host *p)
* we're finished. This function queues the completed commands.
*-F*************************************************************************/
static void
-aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
{
aic7xxx_position(cmd) = SCB_LIST_NULL;
cmd->host_scribble = (char *)p->completeq.head;
@@ -2640,18 +2640,16 @@ aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
* Description:
* Process the completed command queue.
*-F*************************************************************************/
-static void
-aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
+static void aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
{
- Scsi_Cmnd *cmd;
-
- while (p->completeq.head != NULL)
- {
- cmd = p->completeq.head;
- p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
- cmd->host_scribble = NULL;
- cmd->scsi_done(cmd);
- }
+ struct scsi_cmnd *cmd;
+
+ while (p->completeq.head != NULL) {
+ cmd = p->completeq.head;
+ p->completeq.head = (struct scsi_Cmnd *) cmd->host_scribble;
+ cmd->host_scribble = NULL;
+ cmd->scsi_done(cmd);
+ }
}
/*+F*************************************************************************
@@ -2687,11 +2685,11 @@ aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
static void
aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- Scsi_Cmnd *cmd = scb->cmd;
- struct aic_dev_data *aic_dev = cmd->device->hostdata;
- int tindex = TARGET_INDEX(cmd);
- struct aic7xxx_scb *scbp;
- unsigned char queue_depth;
+ struct scsi_cmnd *cmd = scb->cmd;
+ struct aic_dev_data *aic_dev = cmd->device->hostdata;
+ int tindex = TARGET_INDEX(cmd);
+ struct aic7xxx_scb *scbp;
+ unsigned char queue_depth;
if (cmd->use_sg > 1)
{
@@ -2862,7 +2860,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
aic_dev->r_total++;
ptr = aic_dev->r_bins;
}
- if(cmd->device->simple_tags && cmd->request->flags & REQ_HARDBARRIER)
+ if(cmd->device->simple_tags && cmd->request->cmd_flags & REQ_HARDBARRIER)
{
aic_dev->barrier_total++;
if(scb->tag_action == MSG_ORDERED_Q_TAG)
@@ -2891,7 +2889,7 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
* aic7xxx_run_done_queue
*
* Description:
- * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ * Calls the aic7xxx_done() for the scsi_cmnd of each scb in the
* aborted list, and adds each scb to the free list. If complete
* is TRUE, we also process the commands complete list.
*-F*************************************************************************/
@@ -3826,9 +3824,9 @@ aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
static void
aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- struct aic7xxx_hwscb *hscb;
- Scsi_Cmnd *cmd;
- int actual, i;
+ struct aic7xxx_hwscb *hscb;
+ struct scsi_cmnd *cmd;
+ int actual, i;
cmd = scb->cmd;
hscb = scb->hscb;
@@ -4219,20 +4217,20 @@ aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
case BAD_STATUS:
{
- unsigned char scb_index;
- struct aic7xxx_hwscb *hscb;
- Scsi_Cmnd *cmd;
-
- /* The sequencer will notify us when a command has an error that
- * would be of interest to the kernel. This allows us to leave
- * the sequencer running in the common case of command completes
- * without error. The sequencer will have DMA'd the SCB back
- * up to us, so we can reference the drivers SCB array.
- *
- * Set the default return value to 0 indicating not to send
- * sense. The sense code will change this if needed and this
- * reduces code duplication.
- */
+ unsigned char scb_index;
+ struct aic7xxx_hwscb *hscb;
+ struct scsi_cmnd *cmd;
+
+ /* The sequencer will notify us when a command has an error that
+ * would be of interest to the kernel. This allows us to leave
+ * the sequencer running in the common case of command completes
+ * without error. The sequencer will have DMA'd the SCB back
+ * up to us, so we can reference the drivers SCB array.
+ *
+ * Set the default return value to 0 indicating not to send
+ * sense. The sense code will change this if needed and this
+ * reduces code duplication.
+ */
aic_outb(p, 0, RETURN_1);
scb_index = aic_inb(p, SCB_TAG);
if (scb_index > p->scb_data->numscbs)
@@ -5800,9 +5798,9 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
}
else if ((status & SELTO) != 0)
{
- unsigned char scbptr;
- unsigned char nextscb;
- Scsi_Cmnd *cmd;
+ unsigned char scbptr;
+ unsigned char nextscb;
+ struct scsi_cmnd *cmd;
scbptr = aic_inb(p, WAITING_SCBH);
if (scbptr > p->scb_data->maxhscbs)
@@ -5941,11 +5939,11 @@ aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
/*
* Determine the bus phase and queue an appropriate message.
*/
- char *phase;
- Scsi_Cmnd *cmd;
- unsigned char mesg_out = MSG_NOOP;
- unsigned char lastphase = aic_inb(p, LASTPHASE);
- unsigned char sstat2 = aic_inb(p, SSTAT2);
+ char *phase;
+ struct scsi_cmnd *cmd;
+ unsigned char mesg_out = MSG_NOOP;
+ unsigned char lastphase = aic_inb(p, LASTPHASE);
+ unsigned char sstat2 = aic_inb(p, SSTAT2);
cmd = scb->cmd;
switch (lastphase)
@@ -6248,10 +6246,10 @@ aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
static void
aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
{
- struct aic7xxx_scb *scb = NULL;
- struct aic_dev_data *aic_dev;
- Scsi_Cmnd *cmd;
- unsigned char scb_index, tindex;
+ struct aic7xxx_scb *scb = NULL;
+ struct aic_dev_data *aic_dev;
+ struct scsi_cmnd *cmd;
+ unsigned char scb_index, tindex;
#ifdef AIC7XXX_VERBOSE_DEBUGGING
if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
@@ -6347,12 +6345,12 @@ aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
* SCSI controller interrupt handler.
*-F*************************************************************************/
static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_isr(void *dev_id)
{
struct aic7xxx_host *p;
unsigned char intstat;
- p = (struct aic7xxx_host *)dev_id;
+ p = dev_id;
/*
* Just a few sanity checks. Make sure that we have an int pending.
@@ -6479,7 +6477,7 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
* anything like it, please inform the Gross Hack Police immediately
*-F*************************************************************************/
static irqreturn_t
-do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+do_aic7xxx_isr(int irq, void *dev_id)
{
unsigned long cpu_flags;
struct aic7xxx_host *p;
@@ -6491,7 +6489,7 @@ do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
p->flags |= AHC_IN_ISR;
do
{
- aic7xxx_isr(irq, dev_id, regs);
+ aic7xxx_isr(dev_id);
} while ( (aic_inb(p, INTSTAT) & INT_PEND) );
aic7xxx_done_cmds_complete(p);
aic7xxx_run_waiting_queues(p);
@@ -10131,9 +10129,8 @@ skip_pci_controller:
* Description:
* Build a SCB.
*-F*************************************************************************/
-static void
-aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
- struct aic7xxx_scb *scb)
+static void aic7xxx_buildscb(struct aic7xxx_host *p, struct scsi_cmnd *cmd,
+ struct aic7xxx_scb *scb)
{
unsigned short mask;
struct aic7xxx_hwscb *hscb;
@@ -10158,7 +10155,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
/* We always force TEST_UNIT_READY to untagged */
if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags)
{
- if (req->flags & REQ_HARDBARRIER)
+ if (req->cmd_flags & REQ_HARDBARRIER)
{
if(sdptr->ordered_tags)
{
@@ -10285,8 +10282,7 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* Description:
* Queue a SCB to the controller.
*-F*************************************************************************/
-static int
-aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+static int aic7xxx_queue(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
{
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
@@ -10319,11 +10315,11 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
}
scb->cmd = cmd;
- /*
- * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
- * is set up properly, and the parity error flag is reset, then send
- * the SCB to the sequencer and watch the fun begin.
- */
+ /*
+ * Make sure the scsi_cmnd pointer is saved, the struct it points to
+ * is set up properly, and the parity error flag is reset, then send
+ * the SCB to the sequencer and watch the fun begin.
+ */
aic7xxx_position(cmd) = scb->hscb->tag;
cmd->scsi_done = fn;
cmd->result = DID_OK;
@@ -10356,8 +10352,7 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
* aborted, then we will reset the channel and have all devices renegotiate.
* Returns an enumerated type that indicates the status of the operation.
*-F*************************************************************************/
-static int
-__aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
+static int __aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
{
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
@@ -10382,7 +10377,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
hscb = scb->hscb;
- aic7xxx_isr(p->irq, (void *)p, NULL);
+ aic7xxx_isr(p);
aic7xxx_done_cmds_complete(p);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
@@ -10550,8 +10545,7 @@ __aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
return SUCCESS;
}
-static int
-aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
+static int aic7xxx_bus_device_reset(struct scsi_cmnd *cmd)
{
int rc;
@@ -10570,8 +10564,7 @@ aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
* Description:
* Abort the current SCSI command(s).
*-F*************************************************************************/
-static void
-aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+static void aic7xxx_panic_abort(struct aic7xxx_host *p, struct scsi_cmnd *cmd)
{
printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
@@ -10595,8 +10588,7 @@ aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
* Description:
* Abort the current SCSI command(s).
*-F*************************************************************************/
-static int
-__aic7xxx_abort(Scsi_Cmnd *cmd)
+static int __aic7xxx_abort(struct scsi_cmnd *cmd)
{
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
@@ -10616,7 +10608,7 @@ __aic7xxx_abort(Scsi_Cmnd *cmd)
else
return FAILED;
- aic7xxx_isr(p->irq, (void *)p, NULL);
+ aic7xxx_isr(p);
aic7xxx_done_cmds_complete(p);
/* If the command was already complete or just completed, then we didn't
* do a reset, return FAILED */
@@ -10813,8 +10805,7 @@ success:
return SUCCESS;
}
-static int
-aic7xxx_abort(Scsi_Cmnd *cmd)
+static int aic7xxx_abort(struct scsi_cmnd *cmd)
{
int rc;
@@ -10836,8 +10827,7 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
* DEVICE RESET message - on the offending target before pulling
* the SCSI bus reset line.
*-F*************************************************************************/
-static int
-aic7xxx_reset(Scsi_Cmnd *cmd)
+static int aic7xxx_reset(struct scsi_cmnd *cmd)
{
struct aic7xxx_scb *scb;
struct aic7xxx_host *p;
@@ -10873,7 +10863,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd)
while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
{
- aic7xxx_isr(p->irq, p, (void *)NULL );
+ aic7xxx_isr(p);
pause_sequencer(p);
}
aic7xxx_done_cmds_complete(p);
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig
index 0ed391d8ee84..c83fe751d0bb 100644
--- a/drivers/scsi/aic94xx/Kconfig
+++ b/drivers/scsi/aic94xx/Kconfig
@@ -28,6 +28,7 @@ config SCSI_AIC94XX
tristate "Adaptec AIC94xx SAS/SATA support"
depends on PCI
select SCSI_SAS_LIBSAS
+ select FW_LOADER
help
This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X
AIC94xx chip based host adapters.
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
index 1d8c5e5f442e..3c2d7a379931 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -996,11 +996,10 @@ static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha)
* asd_hw_isr -- host adapter interrupt service routine
* @irq: ignored
* @dev_id: pointer to host adapter structure
- * @regs: ignored
*
* The ISR processes done list entries and level 3 error handling.
*/
-irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t asd_hw_isr(int irq, void *dev_id)
{
struct asd_ha_struct *asd_ha = dev_id;
u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT);
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h
index 8498144aa5e1..14319d1d6804 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.h
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.h
@@ -371,7 +371,7 @@ static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
/* ---------- Function declarations ---------- */
int asd_init_hw(struct asd_ha_struct *asd_ha);
-irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t asd_hw_isr(int irq, void *dev_id);
struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index ee2ccad70487..99743ca29ca1 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -24,7 +24,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -310,11 +309,29 @@ static ssize_t asd_show_dev_pcba_sn(struct device *dev,
}
static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL);
-static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
+static int asd_create_dev_attrs(struct asd_ha_struct *asd_ha)
{
- device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
- device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
- device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+ int err;
+
+ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ if (err)
+ return err;
+
+ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+ if (err)
+ goto err_rev;
+
+ err = device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn);
+ if (err)
+ goto err_biosb;
+
+ return 0;
+
+err_biosb:
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build);
+err_rev:
+ device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision);
+ return err;
}
static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha)
@@ -646,7 +663,9 @@ static int __devinit asd_pci_probe(struct pci_dev *dev,
}
ASD_DPRINTK("escbs posted\n");
- asd_create_dev_attrs(asd_ha);
+ err = asd_create_dev_attrs(asd_ha);
+ if (err)
+ goto Err_dev_attrs;
err = asd_register_sas_ha(asd_ha);
if (err)
@@ -669,6 +688,7 @@ Err_en_phys:
asd_unregister_sas_ha(asd_ha);
Err_reg_sas:
asd_remove_dev_attrs(asd_ha);
+Err_dev_attrs:
Err_escbs:
asd_disable_ints(asd_ha);
free_irq(dev->irq, asd_ha);
@@ -755,9 +775,9 @@ static ssize_t asd_version_show(struct device_driver *driver, char *buf)
}
static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL);
-static void asd_create_driver_attrs(struct device_driver *driver)
+static int asd_create_driver_attrs(struct device_driver *driver)
{
- driver_create_file(driver, &driver_attr_version);
+ return driver_create_file(driver, &driver_attr_version);
}
static void asd_remove_driver_attrs(struct device_driver *driver)
@@ -835,10 +855,14 @@ static int __init aic94xx_init(void)
if (err)
goto out_release_transport;
- asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+ err = asd_create_driver_attrs(&aic94xx_pci_driver.driver);
+ if (err)
+ goto out_unregister_pcidrv;
return err;
+ out_unregister_pcidrv:
+ pci_unregister_driver(&aic94xx_pci_driver);
out_release_transport:
sas_release_transport(aic94xx_transport_template);
out_destroy_caches:
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
index 1b637592d5ae..7cd63a996886 100644
--- a/drivers/scsi/amiga7xx.h
+++ b/drivers/scsi/amiga7xx.h
@@ -8,7 +8,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c7xx_abort(Scsi_Cmnd *);
int NCR53c7x0_release (struct Scsi_Host *);
int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+void NCR53c7x0_intr(int irq, void *dev_id);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 3
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 475f978ff8f0..086cc97eee8c 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -147,8 +147,7 @@ static struct pci_driver arcmsr_pci_driver = {
.shutdown = arcmsr_shutdown
};
-static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id)
{
irqreturn_t handle_state;
struct AdapterControlBlock *acb;
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index 7621e3fa37b1..9cf902b7a126 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -194,7 +194,8 @@
unsigned int sdtr_period = SDTR_PERIOD;
unsigned int sdtr_size = SDTR_SIZE;
-static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
+static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
+ unsigned int result);
static int acornscsi_reconnect_finish(AS_Host *host);
static void acornscsi_dma_cleanup(AS_Host *host);
static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
@@ -712,7 +713,7 @@ static
intr_ret_t acornscsi_kick(AS_Host *host)
{
int from_queue = 0;
- Scsi_Cmnd *SCpnt;
+ struct scsi_cmnd *SCpnt;
/* first check to see if a command is waiting to be executed */
SCpnt = host->origSCpnt;
@@ -796,15 +797,15 @@ intr_ret_t acornscsi_kick(AS_Host *host)
}
/*
- * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+ * Function: void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp, unsigned int result)
* Purpose : complete processing for command
* Params : host - interface that completed
* result - driver byte of result
*/
-static
-void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
+ unsigned int result)
{
- Scsi_Cmnd *SCpnt = *SCpntp;
+ struct scsi_cmnd *SCpnt = *SCpntp;
/* clean up */
sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);
@@ -1318,7 +1319,7 @@ acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int
static void
acornscsi_sendcommand(AS_Host *host)
{
- Scsi_Cmnd *SCpnt = host->SCpnt;
+ struct scsi_cmnd *SCpnt = host->SCpnt;
sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);
sbic_arm_writenext(host->scsi.io_port, 0);
@@ -1693,7 +1694,7 @@ void acornscsi_message(AS_Host *host)
acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
} else {
- Scsi_Cmnd *SCpnt = host->SCpnt;
+ struct scsi_cmnd *SCpnt = host->SCpnt;
acornscsi_dma_cleanup(host);
@@ -2460,14 +2461,13 @@ intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
}
/*
- * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+ * Prototype: void acornscsi_intr(int irq, void *dev_id)
* Purpose : handle interrupts from Acorn SCSI card
* Params : irq - interrupt number
* dev_id - device specific data (AS_Host structure)
- * regs - processor registers when interrupt occurred
*/
static irqreturn_t
-acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+acornscsi_intr(int irq, void *dev_id)
{
AS_Host *host = (AS_Host *)dev_id;
intr_ret_t ret;
@@ -2509,13 +2509,14 @@ acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
*/
/*
- * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ * Function : acornscsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
* Purpose : queues a SCSI command
* Params : cmd - SCSI command
* done - function called on completion, with pointer to command descriptor
* Returns : 0, or < 0 on error.
*/
-int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int acornscsi_queuecmd(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
@@ -2565,17 +2566,18 @@ int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
}
/*
- * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+ * Prototype: void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1, struct scsi_cmnd **SCpntp2, int result)
* Purpose : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
* Params : SCpntp1 - pointer to command to return
* SCpntp2 - pointer to command to check
* result - result to pass back to mid-level done function
* Returns : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
*/
-static inline
-void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+static inline void acornscsi_reportstatus(struct scsi_cmnd **SCpntp1,
+ struct scsi_cmnd **SCpntp2,
+ int result)
{
- Scsi_Cmnd *SCpnt = *SCpntp1;
+ struct scsi_cmnd *SCpnt = *SCpntp1;
if (SCpnt) {
*SCpntp1 = NULL;
@@ -2591,13 +2593,12 @@ void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result
enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
/*
- * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
+ * Prototype: enum res acornscsi_do_abort(struct scsi_cmnd *SCpnt)
* Purpose : abort a command on this host
* Params : SCpnt - command to abort
* Returns : our abort status
*/
-static enum res_abort
-acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
+static enum res_abort acornscsi_do_abort(AS_Host *host, struct scsi_cmnd *SCpnt)
{
enum res_abort res = res_not_running;
@@ -2684,12 +2685,12 @@ acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
}
/*
- * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
+ * Prototype: int acornscsi_abort(struct scsi_cmnd *SCpnt)
* Purpose : abort a command on this host
* Params : SCpnt - command to abort
* Returns : one of SCSI_ABORT_ macros
*/
-int acornscsi_abort(Scsi_Cmnd *SCpnt)
+int acornscsi_abort(struct scsi_cmnd *SCpnt)
{
AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;
int result;
@@ -2770,16 +2771,16 @@ int acornscsi_abort(Scsi_Cmnd *SCpnt)
}
/*
- * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ * Prototype: int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
* Purpose : reset a command on this host/reset this host
* Params : SCpnt - command causing reset
* result - what type of reset to perform
* Returns : one of SCSI_RESET_ macros
*/
-int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+int acornscsi_reset(struct scsi_cmnd *SCpnt, unsigned int reset_flags)
{
- AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
- Scsi_Cmnd *SCptr;
+ AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+ struct scsi_cmnd *SCptr;
host->stats.resets += 1;
diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
index 2142290f8404..d11424b89f42 100644
--- a/drivers/scsi/arm/acornscsi.h
+++ b/drivers/scsi/arm/acornscsi.h
@@ -277,8 +277,8 @@ struct status_entry {
typedef struct acornscsi_hostdata {
/* miscellaneous */
struct Scsi_Host *host; /* host */
- Scsi_Cmnd *SCpnt; /* currently processing command */
- Scsi_Cmnd *origSCpnt; /* original connecting command */
+ struct scsi_cmnd *SCpnt; /* currently processing command */
+ struct scsi_cmnd *origSCpnt; /* original connecting command */
/* driver information */
struct {
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
index a28940156703..4385e9e3ded6 100644
--- a/drivers/scsi/arm/arxescsi.c
+++ b/drivers/scsi/arm/arxescsi.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/drivers/scsi/arxescsi.c
+ * linux/drivers/scsi/arm/arxescsi.c
*
* Copyright (C) 1997-2000 Russell King, Stefan Hanske
*
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
index 719af0dcc0e5..19edd9c853d9 100644
--- a/drivers/scsi/arm/cumana_2.c
+++ b/drivers/scsi/arm/cumana_2.c
@@ -137,10 +137,9 @@ cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off)
* Purpose : handle interrupts from Cumana SCSI 2 card
* Params : irq - interrupt number
* dev_id - user-defined (Scsi_Host structure)
- * regs - processor registers at interrupt
*/
static irqreturn_t
-cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs)
+cumanascsi_2_intr(int irq, void *dev_id)
{
struct cumanascsi2_info *info = dev_id;
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
index dcbb4b2b3fe0..3f876fb75469 100644
--- a/drivers/scsi/arm/eesox.c
+++ b/drivers/scsi/arm/eesox.c
@@ -138,10 +138,9 @@ eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
* Purpose : handle interrupts from EESOX SCSI card
* Params : irq - interrupt number
* dev_id - user-defined (Scsi_Host structure)
- * regs - processor registers at interrupt
*/
static irqreturn_t
-eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+eesoxscsi_intr(int irq, void *dev_id)
{
struct eesoxscsi_info *info = dev_id;
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 4cf7afc31cc7..e05f0c2fc912 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -297,8 +297,8 @@ fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap)
printk("scsi%d.%c: %s", info->host->host_no, target, buf);
}
-static void
-fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...)
+static void fas216_log_command(FAS216_Info *info, int level,
+ struct scsi_cmnd *SCpnt, char *fmt, ...)
{
va_list args;
@@ -1662,7 +1662,7 @@ irqreturn_t fas216_intr(FAS216_Info *info)
return handled;
}
-static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void __fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
{
int tot_msglen;
@@ -1754,7 +1754,7 @@ static int parity_test(FAS216_Info *info, int target)
return info->device[target].parity_check;
}
-static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void fas216_start_command(FAS216_Info *info, struct scsi_cmnd *SCpnt)
{
int disconnect_ok;
@@ -1808,7 +1808,7 @@ static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
__fas216_start_command(info, SCpnt);
}
-static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void fas216_allocate_tag(FAS216_Info *info, struct scsi_cmnd *SCpnt)
{
#ifdef SCSI2_TAG
/*
@@ -1842,7 +1842,8 @@ static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
}
}
-static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static void fas216_do_bus_device_reset(FAS216_Info *info,
+ struct scsi_cmnd *SCpnt)
{
struct message *msg;
@@ -1890,7 +1891,7 @@ static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
*/
static void fas216_kick(FAS216_Info *info)
{
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
#define TYPE_OTHER 0
#define TYPE_RESET 1
#define TYPE_QUEUE 2
@@ -1978,8 +1979,8 @@ static void fas216_kick(FAS216_Info *info)
/*
* Clean up from issuing a BUS DEVICE RESET message to a device.
*/
-static void
-fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+static void fas216_devicereset_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
+ unsigned int result)
{
fas216_log(info, LOG_ERROR, "fas216 device reset complete");
@@ -1996,8 +1997,8 @@ fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result
*
* Finish processing automatic request sense command
*/
-static void
-fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+static void fas216_rq_sns_done(FAS216_Info *info, struct scsi_cmnd *SCpnt,
+ unsigned int result)
{
fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
"request sense complete, result=0x%04x%02x%02x",
@@ -2030,7 +2031,7 @@ fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
* Finish processing of standard command
*/
static void
-fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
{
info->stats.fins += 1;
@@ -2142,8 +2143,8 @@ request_sense:
*/
static void fas216_done(FAS216_Info *info, unsigned int result)
{
- void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
- Scsi_Cmnd *SCpnt;
+ void (*fn)(FAS216_Info *, struct scsi_cmnd *, unsigned int);
+ struct scsi_cmnd *SCpnt;
unsigned long flags;
fas216_checkmagic(info);
@@ -2182,7 +2183,7 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
info->device[SCpnt->device->id].parity_check = 0;
clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
- fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
+ fn = (void (*)(FAS216_Info *, struct scsi_cmnd *, unsigned int))SCpnt->host_scribble;
fn(info, SCpnt, result);
if (info->scsi.irq != NO_IRQ) {
@@ -2207,7 +2208,8 @@ no_command:
* Returns: 0 on success, else error.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int fas216_queue_command(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
int result;
@@ -2254,7 +2256,7 @@ int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
*
* Trigger restart of a waiting thread in fas216_command
*/
-static void fas216_internal_done(Scsi_Cmnd *SCpnt)
+static void fas216_internal_done(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2271,7 +2273,8 @@ static void fas216_internal_done(Scsi_Cmnd *SCpnt)
* Returns: scsi result code.
* Notes: io_request_lock is held, interrupts are disabled.
*/
-int fas216_noqueue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+int fas216_noqueue_command(struct scsi_cmnd *SCpnt,
+ void (*done)(struct scsi_cmnd *))
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
@@ -2350,7 +2353,8 @@ enum res_find {
* Decide how to abort a command.
* Returns: abort status
*/
-static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+static enum res_find fas216_find_command(FAS216_Info *info,
+ struct scsi_cmnd *SCpnt)
{
enum res_find res = res_failed;
@@ -2417,7 +2421,7 @@ static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
* Returns: FAILED if unable to abort
* Notes: io_request_lock is taken, and irqs are disabled
*/
-int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+int fas216_eh_abort(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
int result = FAILED;
@@ -2474,7 +2478,7 @@ int fas216_eh_abort(Scsi_Cmnd *SCpnt)
* Notes: We won't be re-entered, so we'll only have one device
* reset on the go at one time.
*/
-int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
unsigned long flags;
@@ -2555,7 +2559,7 @@ int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
* Returns: FAILED if unable to reset.
* Notes: Further commands are blocked.
*/
-int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
unsigned long flags;
@@ -2655,7 +2659,7 @@ static void fas216_init_chip(FAS216_Info *info)
* Returns: FAILED if unable to reset.
* Notes: io_request_lock is taken, and irqs are disabled
*/
-int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
{
FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
index 540914d6fd32..00e5f055afdc 100644
--- a/drivers/scsi/arm/fas216.h
+++ b/drivers/scsi/arm/fas216.h
@@ -218,11 +218,11 @@ typedef struct {
unsigned long magic_start;
spinlock_t host_lock;
struct Scsi_Host *host; /* host */
- Scsi_Cmnd *SCpnt; /* currently processing command */
- Scsi_Cmnd *origSCpnt; /* original connecting command */
- Scsi_Cmnd *reqSCpnt; /* request sense command */
- Scsi_Cmnd *rstSCpnt; /* reset command */
- Scsi_Cmnd *pending_SCpnt[8]; /* per-device pending commands */
+ struct scsi_cmnd *SCpnt; /* currently processing command */
+ struct scsi_cmnd *origSCpnt; /* original connecting command */
+ struct scsi_cmnd *reqSCpnt; /* request sense command */
+ struct scsi_cmnd *rstSCpnt; /* reset command */
+ struct scsi_cmnd *pending_SCpnt[8]; /* per-device pending commands */
int next_pending; /* next pending device */
/*
@@ -328,21 +328,23 @@ extern int fas216_init (struct Scsi_Host *instance);
*/
extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
-/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+/* Function: int fas216_queue_command(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
* Purpose : queue a command for adapter to process.
* Params : SCpnt - Command to queue
* done - done function to call once command is complete
* Returns : 0 - success, else error
*/
-extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int fas216_queue_command(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
-/* Function: int fas216_noqueue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+/* Function: int fas216_noqueue_command(istruct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
* Purpose : queue a command for adapter to process, and process it to completion.
* Params : SCpnt - Command to queue
* done - done function to call once command is complete
* Returns : 0 - success, else error
*/
-extern int fas216_noqueue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int fas216_noqueue_command(struct scsi_cmnd *,
+ void (*done)(struct scsi_cmnd *));
/* Function: irqreturn_t fas216_intr (FAS216_Info *info)
* Purpose : handle interrupts from the interface to progress a command
@@ -363,32 +365,32 @@ extern int fas216_print_host(FAS216_Info *info, char *buffer);
extern int fas216_print_stats(FAS216_Info *info, char *buffer);
extern int fas216_print_devices(FAS216_Info *info, char *buffer);
-/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_abort(struct scsi_cmnd *SCpnt)
* Purpose : abort this command
* Params : SCpnt - command to abort
* Returns : FAILED if unable to abort
*/
-extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_abort(struct scsi_cmnd *SCpnt);
-/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_device_reset(struct scsi_cmnd *SCpnt)
* Purpose : Reset the device associated with this command
* Params : SCpnt - command specifing device to reset
* Returns : FAILED if unable to reset
*/
-extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_device_reset(struct scsi_cmnd *SCpnt);
-/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt)
* Purpose : Reset the complete bus associated with this command
* Params : SCpnt - command specifing bus to reset
* Returns : FAILED if unable to reset
*/
-extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_bus_reset(struct scsi_cmnd *SCpnt);
-/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+/* Function: int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
* Purpose : Reset the host associated with this command
* Params : SCpnt - command specifing host to reset
* Returns : FAILED if unable to reset
*/
-extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
+extern int fas216_eh_host_reset(struct scsi_cmnd *SCpnt);
#endif /* FAS216_H */
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
index b2c346a47052..ce159c15bc86 100644
--- a/drivers/scsi/arm/powertec.c
+++ b/drivers/scsi/arm/powertec.c
@@ -112,10 +112,8 @@ powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
* Purpose : handle interrupts from Powertec SCSI card
* Params : irq - interrupt number
* dev_id - user-defined (Scsi_Host structure)
- * regs - processor registers at interrupt
*/
-static irqreturn_t
-powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t powertecscsi_intr(int irq, void *dev_id)
{
struct powertec_info *info = dev_id;
diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
index 8caa5903ce38..cb11ccef54e5 100644
--- a/drivers/scsi/arm/queue.c
+++ b/drivers/scsi/arm/queue.c
@@ -29,7 +29,7 @@
typedef struct queue_entry {
struct list_head list;
- Scsi_Cmnd *SCpnt;
+ struct scsi_cmnd *SCpnt;
#ifdef DEBUG
unsigned long magic;
#endif
@@ -96,14 +96,14 @@ void queue_free (Queue_t *queue)
/*
- * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
* Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
* Params : queue - destination queue
* SCpnt - command to add
* head - add command to head of queue
* Returns : 0 on error, !0 on success
*/
-int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
{
unsigned long flags;
struct list_head *l;
@@ -134,7 +134,7 @@ empty:
return ret;
}
-static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
+static struct scsi_cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
{
QE_t *q;
@@ -152,17 +152,17 @@ static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
}
/*
- * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
+ * Function: struct scsi_cmnd *queue_remove_exclude (queue, exclude)
* Purpose : remove a SCSI command from a queue
* Params : queue - queue to remove command from
* exclude - bit array of target&lun which is busy
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
+struct scsi_cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
{
unsigned long flags;
struct list_head *l;
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
spin_lock_irqsave(&queue->queue_lock, flags);
list_for_each(l, &queue->head) {
@@ -178,15 +178,15 @@ Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
}
/*
- * Function: Scsi_Cmnd *queue_remove (queue)
+ * Function: struct scsi_cmnd *queue_remove (queue)
* Purpose : removes first SCSI command from a queue
* Params : queue - queue to remove command from
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-Scsi_Cmnd *queue_remove(Queue_t *queue)
+struct scsi_cmnd *queue_remove(Queue_t *queue)
{
unsigned long flags;
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
spin_lock_irqsave(&queue->queue_lock, flags);
if (!list_empty(&queue->head))
@@ -197,19 +197,20 @@ Scsi_Cmnd *queue_remove(Queue_t *queue)
}
/*
- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
* Purpose : remove a SCSI command from the queue for a specified target/lun/tag
* Params : queue - queue to remove command from
* target - target that we want
* lun - lun on device
* tag - tag on device
- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
*/
-Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
+struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target, int lun,
+ int tag)
{
unsigned long flags;
struct list_head *l;
- Scsi_Cmnd *SCpnt = NULL;
+ struct scsi_cmnd *SCpnt = NULL;
spin_lock_irqsave(&queue->queue_lock, flags);
list_for_each(l, &queue->head) {
@@ -275,13 +276,13 @@ int queue_probetgtlun (Queue_t *queue, int target, int lun)
}
/*
- * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Function: int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
* Purpose : remove a specific command from the queues
* Params : queue - queue to look in
* SCpnt - command to find
* Returns : 0 if not found
*/
-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt)
{
unsigned long flags;
struct list_head *l;
diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h
index 0c9dec4c1716..3c519c9237b2 100644
--- a/drivers/scsi/arm/queue.h
+++ b/drivers/scsi/arm/queue.h
@@ -32,46 +32,48 @@ extern int queue_initialise (Queue_t *queue);
extern void queue_free (Queue_t *queue);
/*
- * Function: Scsi_Cmnd *queue_remove (queue)
+ * Function: struct scsi_cmnd *queue_remove (queue)
* Purpose : removes first SCSI command from a queue
* Params : queue - queue to remove command from
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-extern Scsi_Cmnd *queue_remove (Queue_t *queue);
+extern struct scsi_cmnd *queue_remove (Queue_t *queue);
/*
- * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude)
+ * Function: struct scsi_cmnd *queue_remove_exclude_ref (queue, exclude)
* Purpose : remove a SCSI command from a queue
* Params : queue - queue to remove command from
* exclude - array of busy LUNs
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ * Returns : struct scsi_cmnd if successful (and a reference), or NULL if no command available
*/
-extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
+extern struct scsi_cmnd *queue_remove_exclude(Queue_t *queue,
+ unsigned long *exclude);
#define queue_add_cmd_ordered(queue,SCpnt) \
__queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
#define queue_add_cmd_tail(queue,SCpnt) \
__queue_add(queue,SCpnt,0)
/*
- * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Function: int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head)
* Purpose : Add a new command onto a queue
* Params : queue - destination queue
* SCpnt - command to add
* head - add command to head of queue
* Returns : 0 on error, !0 on success
*/
-extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head);
+extern int __queue_add(Queue_t *queue, struct scsi_cmnd *SCpnt, int head);
/*
- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Function: struct scsi_cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
* Purpose : remove a SCSI command from the queue for a specified target/lun/tag
* Params : queue - queue to remove command from
* target - target that we want
* lun - lun on device
* tag - tag on device
- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ * Returns : struct scsi_cmnd if successful, or NULL if no command satisfies requirements
*/
-extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag);
+extern struct scsi_cmnd *queue_remove_tgtluntag(Queue_t *queue, int target,
+ int lun, int tag);
/*
* Function: queue_remove_all_target(queue, target)
@@ -94,12 +96,12 @@ extern void queue_remove_all_target(Queue_t *queue, int target);
extern int queue_probetgtlun (Queue_t *queue, int target, int lun);
/*
- * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Function: int queue_remove_cmd (Queue_t *queue, struct scsi_cmnd *SCpnt)
* Purpose : remove a specific command from the queues
* Params : queue - queue to look in
* SCpnt - command to find
* Returns : 0 if not found
*/
-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt);
+int queue_remove_cmd(Queue_t *queue, struct scsi_cmnd *SCpnt);
#endif /* QUEUE_H */
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
index 8c2600ffc6af..3a39579bd08e 100644
--- a/drivers/scsi/arm/scsi.h
+++ b/drivers/scsi/arm/scsi.h
@@ -66,7 +66,7 @@ static inline void put_next_SCp_byte(struct scsi_pointer *SCp, unsigned char c)
SCp->this_residual -= 1;
}
-static inline void init_SCp(Scsi_Cmnd *SCpnt)
+static inline void init_SCp(struct scsi_cmnd *SCpnt)
{
memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index e397129c90d1..0f920c84ac0f 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -1262,7 +1262,7 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance )
*
*/
-static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t NCR5380_intr (int irq, void *dev_id)
{
struct Scsi_Host *instance = first_instance;
int done = 1, handled = 0;
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
index 8d5d2a5da961..cdc710ea00fa 100644
--- a/drivers/scsi/atari_dma_emul.c
+++ b/drivers/scsi/atari_dma_emul.c
@@ -110,7 +110,7 @@ static inline void set_restdata_reg(unsigned char *cur_addr)
}
/*
- * void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+ * void hades_dma_emulator(int irq, void *dummy)
*
* This code emulates TT SCSI DMA on the Hades.
*
@@ -140,7 +140,7 @@ static inline void set_restdata_reg(unsigned char *cur_addr)
* increased with one.
*/
-static irqreturn_t hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t hades_dma_emulator(int irq, void *dummy)
{
unsigned long dma_base;
register unsigned long dma_cnt asm ("d3");
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index e1be4a4387cd..dfb1bcfae82e 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -194,8 +194,8 @@ static int falcon_classify_cmd( Scsi_Cmnd *cmd );
static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
Scsi_Cmnd *cmd, int write_flag );
#endif
-static irqreturn_t scsi_tt_intr( int irq, void *dummy, struct pt_regs *fp);
-static irqreturn_t scsi_falcon_intr( int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t scsi_tt_intr( int irq, void *dummy);
+static irqreturn_t scsi_falcon_intr( int irq, void *dummy);
static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
hostdata );
static void falcon_get_lock( void );
@@ -285,7 +285,7 @@ static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
* end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
* to clear the DMA int pending bit before it allows other level 6 interrupts.
*/
-static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp)
+static void scsi_dma_buserr (int irq, void *dummy)
{
unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
@@ -314,7 +314,7 @@ static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp)
#endif
-static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_tt_intr (int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
@@ -406,7 +406,7 @@ static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp)
}
-static irqreturn_t scsi_falcon_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_falcon_intr (int irq, void *dummy)
{
#ifdef REAL_DMA
int dma_stat;
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index 0ec41f34f462..fec58cc47f1c 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -44,7 +44,7 @@ static void send_s870(struct atp_unit *dev,unsigned char c);
static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
static void tscam_885(void);
-static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t atp870u_intr_handle(int irq, void *dev_id)
{
unsigned long flags;
unsigned short int tmpcip, id;
diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
index 7c9c0366cc08..ea3e4b2b9220 100644
--- a/drivers/scsi/bvme6000.h
+++ b/drivers/scsi/bvme6000.h
@@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c7xx_abort(Scsi_Cmnd *);
int NCR53c7x0_release (struct Scsi_Host *);
int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+void NCR53c7x0_intr(int irq, void *dev_id);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 3
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index ff2b1796fa34..e95b367d09ed 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -1219,7 +1219,7 @@ static void dump_register_info(struct AdapterCtlBlk *acb,
srb, srb->cmd, srb->cmd->pid,
srb->cmd->cmnd[0], srb->cmd->device->id,
srb->cmd->device->lun);
- printk(" sglist=%p cnt=%i idx=%i len=%i\n",
+ printk(" sglist=%p cnt=%i idx=%i len=%zu\n",
srb->segment_x, srb->sg_count, srb->sg_index,
srb->total_xfer_length);
printk(" state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
@@ -1813,10 +1813,9 @@ static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
}
-static irqreturn_t dc395x_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t dc395x_interrupt(int irq, void *dev_id)
{
- struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id;
+ struct AdapterCtlBlk *acb = dev_id;
u16 scsi_status;
u8 dma_status;
irqreturn_t handled = IRQ_NONE;
@@ -4949,7 +4948,7 @@ static struct pci_driver dc395x_driver = {
**/
static int __init dc395x_module_init(void)
{
- return pci_module_init(&dc395x_driver);
+ return pci_register_driver(&dc395x_driver);
}
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
index eb32062f7e68..c29ccbc44693 100644
--- a/drivers/scsi/dec_esp.c
+++ b/drivers/scsi/dec_esp.c
@@ -94,9 +94,9 @@ volatile unsigned char pmaz_cmd_buffer[16];
* via PIO.
*/
-static irqreturn_t scsi_dma_merr_int(int, void *, struct pt_regs *);
-static irqreturn_t scsi_dma_err_int(int, void *, struct pt_regs *);
-static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *);
+static irqreturn_t scsi_dma_merr_int(int, void *);
+static irqreturn_t scsi_dma_err_int(int, void *);
+static irqreturn_t scsi_dma_int(int, void *);
static int dec_esp_detect(struct scsi_host_template * tpnt);
@@ -307,7 +307,7 @@ err_dealloc:
}
/************************************************************* DMA Functions */
-static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id)
{
printk("Got unexpected SCSI DMA Interrupt! < ");
printk("SCSI_DMA_MEMRDERR ");
@@ -316,14 +316,14 @@ static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs
return IRQ_HANDLED;
}
-static irqreturn_t scsi_dma_err_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scsi_dma_err_int(int irq, void *dev_id)
{
/* empty */
return IRQ_HANDLED;
}
-static irqreturn_t scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t scsi_dma_int(int irq, void *dev_id)
{
u32 scsi_next_ptr;
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 879a26657676..fa738ec8692a 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -155,7 +155,7 @@ static struct pci_driver dmx3191d_pci_driver = {
static int __init dmx3191d_init(void)
{
- return pci_module_init(&dmx3191d_pci_driver);
+ return pci_register_driver(&dmx3191d_pci_driver);
}
static void __exit dmx3191d_exit(void)
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
index d84a281ad944..b3fa7ed71faf 100644
--- a/drivers/scsi/dpt/dpti_i2o.h
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -47,21 +47,11 @@
* I2O Interface Objects
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-
-#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
-
-typedef struct wait_queue *adpt_wait_queue_head_t;
-#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) adpt_wait_queue_head_t wait = NULL
-typedef struct wait_queue adpt_wait_queue_t;
-#else
-
#include <linux/wait.h>
typedef wait_queue_head_t adpt_wait_queue_head_t;
#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait)
typedef wait_queue_t adpt_wait_queue_t;
-#endif
/*
* message structures
*/
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 7b3bd34faf47..60b1b434eba7 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1989,7 +1989,7 @@ static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
}
-static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t adpt_isr(int irq, void *dev_id)
{
struct scsi_cmnd* cmd;
adpt_hba* pHba = dev_id;
@@ -2212,7 +2212,7 @@ static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
*/
host->io_port = 0;
host->n_io_port = 0;
- /* see comments in hosts.h */
+ /* see comments in scsi_host.h */
host->max_id = 16;
host->max_lun = 256;
host->max_channel = pHba->top_scsi_channel + 1;
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 2ad2a89b5db4..fd79068c5869 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -44,7 +44,7 @@ static int adpt_device_reset(struct scsi_cmnd* cmd);
/*
- * struct scsi_host_template (see hosts.h)
+ * struct scsi_host_template (see scsi/scsi_host.h)
*/
#define DPT_DRIVER_NAME "Adaptec I2O RAID"
@@ -263,7 +263,7 @@ struct sg_simple_element {
static void adpt_i2o_sys_shutdown(void);
static int adpt_init(void);
static int adpt_i2o_build_sys_table(void);
-static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t adpt_isr(int irq, void *dev_id);
#ifdef REBOOT_NOTIFIER
static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
#endif
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 0d5713dfa204..54756722dd5f 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -82,7 +82,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/interrupt.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include "dtc.h"
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index a5ff43b1b263..2d38025861a5 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -875,7 +875,7 @@ static unsigned long io_port[] = {
/* But transfer orientation from the 16 bit data register is Little Endian */
#define REG2H(x) le16_to_cpu(x)
-static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
+static irqreturn_t do_interrupt_handler(int, void *);
static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *,
unsigned int);
static int do_trace = 0;
@@ -2555,8 +2555,7 @@ static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
return IRQ_NONE;
}
-static irqreturn_t do_interrupt_handler(int irq, void *shap,
- struct pt_regs *regs)
+static irqreturn_t do_interrupt_handler(int irq, void *shap)
{
struct Scsi_Host *shost;
unsigned int j;
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index d312633db92b..2dbb66d2f0a7 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -194,22 +194,21 @@ static void IncStat(struct scsi_pointer *SCp, unsigned int Increment)
}
}
-static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t eata_pio_int_handler(int irq, void *dev_id);
-static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
irqreturn_t ret;
spin_lock_irqsave(dev->host_lock, flags);
- ret = eata_pio_int_handler(irq, dev_id, regs);
+ ret = eata_pio_int_handler(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return ret;
}
-static irqreturn_t eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t eata_pio_int_handler(int irq, void *dev_id)
{
unsigned int eata_stat = 0xfffff;
struct scsi_cmnd *cmd;
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 5630868c1b25..2c2fe80bc42a 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -184,7 +184,7 @@ enum {
};
/* Forward declarations. */
-static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+static irqreturn_t esp_intr(int irq, void *dev_id);
/* Debugging routines */
struct esp_cmdstrings {
@@ -4282,7 +4282,7 @@ state_machine:
}
/* Service only the ESP described by dev_id. */
-static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+static irqreturn_t esp_intr(int irq, void *dev_id)
{
struct esp *esp = dev_id;
unsigned long flags;
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
index dde3edf35c03..ef8285c326e4 100644
--- a/drivers/scsi/fd_mcs.c
+++ b/drivers/scsi/fd_mcs.c
@@ -281,7 +281,7 @@ static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
#define FD_BRDS ARRAY_SIZE(fd_mcs_adapters)
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fd_mcs_intr(int irq, void *dev_id);
static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
@@ -617,7 +617,7 @@ static void my_done(struct Scsi_Host *shpnt, int error)
}
/* only my_done needs to be protected */
-static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t fd_mcs_intr(int irq, void *dev_id)
{
unsigned long flags;
int status;
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
index b0694dcce246..65e6e7b7ba07 100644
--- a/drivers/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -278,9 +278,9 @@
#include <linux/pci.h>
#include <linux/stat.h>
#include <linux/delay.h>
+#include <linux/io.h>
#include <scsi/scsicam.h>
-#include <asm/io.h>
#include <asm/system.h>
#include <scsi/scsi.h>
@@ -403,8 +403,7 @@ static volatile int in_interrupt_flag;
static int FIFO_Size = 0x2000; /* 8k FIFO for
pre-tmc18c30 chips */
-static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id,
- struct pt_regs * regs );
+static irqreturn_t do_fdomain_16x0_intr( int irq, void *dev_id );
/* Allow insmod parameters to be like LILO parameters. For example:
insmod fdomain fdomain=0x140,11 */
static char * fdomain = NULL;
@@ -1094,8 +1093,7 @@ static void my_done(int error)
#endif
}
-static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id,
- struct pt_regs * regs )
+static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id)
{
unsigned long flags;
int status;
@@ -1738,6 +1736,15 @@ struct scsi_host_template fdomain_driver_template = {
};
#ifndef PCMCIA
+
+static struct pci_device_id fdomain_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, fdomain_pci_tbl);
+
#define driver_template fdomain_driver_template
#include "scsi_module.c"
+
#endif
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 43afd476e606..4bc14ad92e22 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -424,7 +424,7 @@
static void gdth_delay(int milliseconds);
static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
-static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gdth_interrupt(int irq, void *dev_id);
static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
static int gdth_async_event(int hanum);
static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
@@ -724,7 +724,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
int timeout, u32 *info)
{
Scsi_Cmnd *scp;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
int rval;
scp = kmalloc(sizeof(*scp), GFP_KERNEL);
@@ -764,7 +764,7 @@ int __gdth_execute(struct scsi_device *sdev, gdth_cmd_str *gdtcmd, char *cmnd,
{
Scsi_Cmnd *scp = scsi_allocate_device(sdev, 1, FALSE);
unsigned bufflen = gdtcmd ? sizeof(gdth_cmd_str) : 0;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
int rval;
if (!scp)
@@ -1804,7 +1804,7 @@ static int gdth_wait(int hanum,int index,ulong32 time)
gdth_from_wait = TRUE;
do {
- gdth_interrupt((int)ha->irq,ha,NULL);
+ gdth_interrupt((int)ha->irq,ha);
if (wait_hanum==hanum && wait_index==index) {
answer_found = TRUE;
break;
@@ -3406,7 +3406,7 @@ static void gdth_clear_events(void)
/* SCSI interface functions */
-static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+static irqreturn_t gdth_interrupt(int irq,void *dev_id)
{
gdth_ha_str *ha2 = (gdth_ha_str *)dev_id;
register gdth_ha_str *ha;
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 47eae0299750..8c29eafd51c5 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -936,18 +936,12 @@ typedef struct {
gdth_binfo_str binfo; /* controller info */
gdth_evt_data dvr; /* event structure */
spinlock_t smp_lock;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
struct pci_dev *pdev;
-#endif
char oem_name[8];
#ifdef GDTH_DMA_STATISTICS
ulong dma32_cnt, dma64_cnt; /* statistics: DMA buffer */
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
struct scsi_device *sdev;
-#else
- struct scsi_device sdev;
-#endif
} gdth_ha_str;
/* structure for scsi_register(), SCSI bus != 0 */
@@ -1029,10 +1023,6 @@ typedef struct {
/* function prototyping */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
-#else
-int gdth_proc_info(char *,char **,off_t,int,int,int);
-#endif
#endif
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
index 18dbe5c27dac..2f6c1137a6e5 100644
--- a/drivers/scsi/gvp11.c
+++ b/drivers/scsi/gvp11.c
@@ -24,7 +24,7 @@
#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
-static irqreturn_t gvp11_intr (int irq, void *_instance, struct pt_regs *fp)
+static irqreturn_t gvp11_intr (int irq, void *_instance)
{
unsigned long flags;
unsigned int status;
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
deleted file mode 100644
index c27264bed5d4..000000000000
--- a/drivers/scsi/hosts.h
+++ /dev/null
@@ -1,2 +0,0 @@
-#warning "This file is obsolete, please use <scsi/scsi_host.h> instead"
-#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index 28bfb8f9f81d..bec83cbee59a 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -431,7 +431,7 @@ void hptiop_iop_request_callback(struct hptiop_hba *hba, u32 tag)
writel(tag, &hba->iop->outbound_queue);
}
-static irqreturn_t hptiop_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hptiop_intr(int irq, void *dev_id)
{
struct hptiop_hba *hba = dev_id;
int handled;
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 2be1dc5d852a..0e57fb6964d5 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -497,8 +497,7 @@ static int option_setup(char *);
static int ldn_access_load(int, int);
static int ldn_access_total_read_write(int);
-static irqreturn_t interrupt_handler(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t interrupt_handler(int irq, void *dev_id)
{
int host_index, ihost_index;
unsigned int intr_reg;
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
index 01b8ac641eb8..227c0f2f4d74 100644
--- a/drivers/scsi/ibmvscsi/rpa_vscsi.c
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -45,14 +45,11 @@ static unsigned int partition_number = -1;
* ibmvscsi_handle_event: - Interrupt handler for crq events
* @irq: number of irq to handle, not used
* @dev_instance: ibmvscsi_host_data of host that received interrupt
- * @regs: pt_regs with registers
*
* Disables interrupts and schedules srp_task
* Always returns IRQ_HANDLED
*/
-static irqreturn_t ibmvscsi_handle_event(int irq,
- void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t ibmvscsi_handle_event(int irq, void *dev_instance)
{
struct ibmvscsi_host_data *hostdata =
(struct ibmvscsi_host_data *)dev_instance;
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index 94d1de55607f..1427a41e8441 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -344,7 +344,7 @@ static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_co
pc->buffer = buf;
pc->c[0] = REQUEST_SENSE;
pc->c[4] = pc->request_transfer = pc->buffer_size = SCSI_SENSE_BUFFERSIZE;
- rq->flags = REQ_SENSE;
+ rq->cmd_type = REQ_TYPE_SENSE;
pc->timeout = jiffies + WAIT_READY;
/* NOTE! Save the failed packet command in "rq->buffer" */
rq->buffer = (void *) failed_command->special;
@@ -398,12 +398,12 @@ static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
int errors = rq->errors;
unsigned long flags;
- if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) {
+ if (!blk_special_request(rq) && !blk_sense_request(rq)) {
ide_end_request(drive, uptodate, nrsecs);
return 0;
}
ide_end_drive_cmd (drive, 0, 0);
- if (rq->flags & REQ_SENSE) {
+ if (blk_sense_request(rq)) {
idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer;
if (log) {
printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number);
@@ -708,11 +708,11 @@ static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
{
#if IDESCSI_DEBUG_LOG
- printk (KERN_INFO "rq_status: %d, dev: %s, cmd: %x, errors: %d\n",rq->rq_status, rq->rq_disk->disk_name,rq->cmd[0],rq->errors);
+ printk (KERN_INFO "dev: %s, cmd: %x, errors: %d\n", rq->rq_disk->disk_name,rq->cmd[0],rq->errors);
printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
#endif /* IDESCSI_DEBUG_LOG */
- if (rq->flags & (REQ_SPECIAL|REQ_SENSE)) {
+ if (blk_sense_request(rq) || blk_special_request(rq)) {
return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);
}
blk_dump_rq_flags(rq, "ide-scsi: unsup command");
@@ -938,7 +938,7 @@ static int idescsi_queue (struct scsi_cmnd *cmd,
ide_init_drive_cmd (rq);
rq->special = (char *) pc;
- rq->flags = REQ_SPECIAL;
+ rq->cmd_type = REQ_TYPE_SPECIAL;
spin_unlock_irq(host->host_lock);
rq->rq_disk = scsi->disk;
(void) ide_do_drive_cmd (drive, rq, ide_end);
@@ -992,7 +992,7 @@ static int idescsi_eh_abort (struct scsi_cmnd *cmd)
*/
printk (KERN_ERR "ide-scsi: cmd aborted!\n");
- if (scsi->pc->rq->flags & REQ_SENSE)
+ if (blk_sense_request(scsi->pc->rq))
kfree(scsi->pc->buffer);
kfree(scsi->pc->rq);
kfree(scsi->pc);
@@ -1042,7 +1042,7 @@ static int idescsi_eh_reset (struct scsi_cmnd *cmd)
/* kill current request */
blkdev_dequeue_request(req);
end_that_request_last(req, 0);
- if (req->flags & REQ_SENSE)
+ if (blk_sense_request(req))
kfree(scsi->pc->buffer);
kfree(scsi->pc);
scsi->pc = NULL;
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
index ece936ac29c7..8f6f32fc61ff 100644
--- a/drivers/scsi/imm.h
+++ b/drivers/scsi/imm.h
@@ -66,7 +66,6 @@
*/
/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index 59a4097f1254..312190a69389 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -829,7 +829,7 @@ static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir)
* but it _does_ need to be able to compile and run in an SMP kernel.)
*/
-static irqreturn_t in2000_intr(int irqnum, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t in2000_intr(int irqnum, void *dev_id)
{
struct Scsi_Host *instance = dev_id;
struct IN2000_hostdata *hostdata;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index 9e10dac61cfd..afed293dd7b9 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -142,8 +142,6 @@
#define i91u_MAXQUEUE 2
#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
-#define INI_VENDOR_ID 0x1101 /* Initio's PCI vendor ID */
-#define DMX_VENDOR_ID 0x134a /* Domex's PCI vendor ID */
#define I950_DEVICE_ID 0x9500 /* Initio's inic-950 product ID */
#define I940_DEVICE_ID 0x9400 /* Initio's inic-940 product ID */
#define I935_DEVICE_ID 0x9401 /* Initio's inic-935 product ID */
@@ -171,13 +169,16 @@ static int setup_debug = 0;
static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
-static const PCI_ID i91u_pci_devices[] = {
- { INI_VENDOR_ID, I950_DEVICE_ID },
- { INI_VENDOR_ID, I940_DEVICE_ID },
- { INI_VENDOR_ID, I935_DEVICE_ID },
- { INI_VENDOR_ID, I920_DEVICE_ID },
- { DMX_VENDOR_ID, I920_DEVICE_ID },
+/* PCI Devices supported by this driver */
+static struct pci_device_id i91u_pci_devices[] __devinitdata = {
+ { PCI_VENDOR_ID_INIT, I950_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_INIT, I940_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_INIT, I935_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_INIT, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_DOMEX, I920_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
};
+MODULE_DEVICE_TABLE(pci, i91u_pci_devices);
#define DEBUG_INTERRUPT 0
#define DEBUG_QUEUE 0
@@ -2748,7 +2749,7 @@ int tul_wait_done_disc(HCS * pCurHcb)
return (tul_bad_seq(pCurHcb));
}
-static irqreturn_t i91u_intr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i91u_intr(int irqno, void *dev_id)
{
struct Scsi_Host *dev = dev_id;
unsigned long flags;
@@ -2771,7 +2772,7 @@ static int tul_NewReturnNumberOfAdapters(void)
for (i = 0; i < ARRAY_SIZE(i91u_pci_devices); i++)
{
- while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) {
+ while ((pDev = pci_find_device(i91u_pci_devices[i].vendor, i91u_pci_devices[i].device, pDev)) != NULL) {
if (pci_enable_device(pDev))
continue;
pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 7ed4eef8347b..2dde821025f3 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -70,6 +70,7 @@
#include <linux/firmware.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
+#include <linux/libata.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/processor.h>
@@ -78,6 +79,7 @@
#include <scsi/scsi_tcq.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_transport.h>
#include "ipr.h"
/*
@@ -199,6 +201,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"FFFA: Undefined device response recovered by the IOA"},
{0x014A0000, 1, 1,
"FFF6: Device bus error, message or command phase"},
+ {0x014A8000, 0, 1,
+ "FFFE: Task Management Function failed"},
{0x015D0000, 0, 1,
"FFF6: Failure prediction threshold exceeded"},
{0x015D9200, 0, 1,
@@ -261,6 +265,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"Device bus status error"},
{0x04448600, 0, 1,
"8157: IOA error requiring IOA reset to recover"},
+ {0x04448700, 0, 0,
+ "ATA device status error"},
{0x04490000, 0, 0,
"Message reject received from the device"},
{0x04449200, 0, 1,
@@ -273,6 +279,8 @@ struct ipr_error_table_t ipr_error_table[] = {
"9082: IOA detected device error"},
{0x044A0000, 1, 1,
"3110: Device bus error, message or command phase"},
+ {0x044A8000, 1, 1,
+ "3110: SAS Command / Task Management Function failed"},
{0x04670400, 0, 1,
"9091: Incorrect hardware configuration change has been detected"},
{0x04678000, 0, 1,
@@ -453,7 +461,8 @@ static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
trace_entry->time = jiffies;
trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
trace_entry->type = type;
- trace_entry->cmd_index = ipr_cmd->cmd_index;
+ trace_entry->ata_op_code = ipr_cmd->ioarcb.add_data.u.regs.command;
+ trace_entry->cmd_index = ipr_cmd->cmd_index & 0xff;
trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
trace_entry->u.add_data = add_data;
}
@@ -480,8 +489,10 @@ static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
ioarcb->read_ioadl_len = 0;
ioasa->ioasc = 0;
ioasa->residual_data_len = 0;
+ ioasa->u.gata.status = 0;
ipr_cmd->scsi_cmd = NULL;
+ ipr_cmd->qc = NULL;
ipr_cmd->sense_buffer[0] = 0;
ipr_cmd->dma_use_sg = 0;
}
@@ -626,6 +637,28 @@ static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
}
/**
+ * ipr_sata_eh_done - done function for aborted SATA commands
+ * @ipr_cmd: ipr command struct
+ *
+ * This function is invoked for ops generated to SATA
+ * devices which are being aborted.
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_sata_eh_done(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ata_queued_cmd *qc = ipr_cmd->qc;
+ struct ipr_sata_port *sata_port = qc->ap->private_data;
+
+ qc->err_mask |= AC_ERR_OTHER;
+ sata_port->ioasa.status |= ATA_BUSY;
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+ ata_qc_complete(qc);
+}
+
+/**
* ipr_scsi_eh_done - mid-layer done function for aborted ops
* @ipr_cmd: ipr command struct
*
@@ -669,6 +702,8 @@ static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
if (ipr_cmd->scsi_cmd)
ipr_cmd->done = ipr_scsi_eh_done;
+ else if (ipr_cmd->qc)
+ ipr_cmd->done = ipr_sata_eh_done;
ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET);
del_timer(&ipr_cmd->timer);
@@ -825,6 +860,7 @@ static void ipr_init_res_entry(struct ipr_resource_entry *res)
res->del_from_ml = 0;
res->resetting_device = 0;
res->sdev = NULL;
+ res->sata_port = NULL;
}
/**
@@ -1316,7 +1352,7 @@ static u32 ipr_get_error(u32 ioasc)
int i;
for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++)
- if (ipr_error_table[i].ioasc == ioasc)
+ if (ipr_error_table[i].ioasc == (ioasc & IPR_IOASC_IOASC_MASK))
return i;
return 0;
@@ -3051,6 +3087,17 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; };
**/
static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
+ struct ipr_resource_entry *res;
+ unsigned long lock_flags = 0;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res = (struct ipr_resource_entry *)sdev->hostdata;
+
+ if (res && ipr_is_gata(res) && qdepth > IPR_MAX_CMD_PER_ATA_LUN)
+ qdepth = IPR_MAX_CMD_PER_ATA_LUN;
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
return sdev->queue_depth;
}
@@ -3166,6 +3213,122 @@ static int ipr_biosparam(struct scsi_device *sdev,
}
/**
+ * ipr_find_starget - Find target based on bus/target.
+ * @starget: scsi target struct
+ *
+ * Return value:
+ * resource entry pointer if found / NULL if not found
+ **/
+static struct ipr_resource_entry *ipr_find_starget(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
+ struct ipr_resource_entry *res;
+
+ list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+ if ((res->cfgte.res_addr.bus == starget->channel) &&
+ (res->cfgte.res_addr.target == starget->id) &&
+ (res->cfgte.res_addr.lun == 0)) {
+ return res;
+ }
+ }
+
+ return NULL;
+}
+
+static struct ata_port_info sata_port_info;
+
+/**
+ * ipr_target_alloc - Prepare for commands to a SCSI target
+ * @starget: scsi target struct
+ *
+ * If the device is a SATA device, this function allocates an
+ * ATA port with libata, else it does nothing.
+ *
+ * Return value:
+ * 0 on success / non-0 on failure
+ **/
+static int ipr_target_alloc(struct scsi_target *starget)
+{
+ struct Scsi_Host *shost = dev_to_shost(&starget->dev);
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) shost->hostdata;
+ struct ipr_sata_port *sata_port;
+ struct ata_port *ap;
+ struct ipr_resource_entry *res;
+ unsigned long lock_flags;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res = ipr_find_starget(starget);
+ starget->hostdata = NULL;
+
+ if (res && ipr_is_gata(res)) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ sata_port = kzalloc(sizeof(*sata_port), GFP_KERNEL);
+ if (!sata_port)
+ return -ENOMEM;
+
+ ap = ata_sas_port_alloc(&ioa_cfg->ata_host, &sata_port_info, shost);
+ if (ap) {
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ sata_port->ioa_cfg = ioa_cfg;
+ sata_port->ap = ap;
+ sata_port->res = res;
+
+ res->sata_port = sata_port;
+ ap->private_data = sata_port;
+ starget->hostdata = sata_port;
+ } else {
+ kfree(sata_port);
+ return -ENOMEM;
+ }
+ }
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+ return 0;
+}
+
+/**
+ * ipr_target_destroy - Destroy a SCSI target
+ * @starget: scsi target struct
+ *
+ * If the device was a SATA device, this function frees the libata
+ * ATA port, else it does nothing.
+ *
+ **/
+static void ipr_target_destroy(struct scsi_target *starget)
+{
+ struct ipr_sata_port *sata_port = starget->hostdata;
+
+ if (sata_port) {
+ starget->hostdata = NULL;
+ ata_sas_port_destroy(sata_port->ap);
+ kfree(sata_port);
+ }
+}
+
+/**
+ * ipr_find_sdev - Find device based on bus/target/lun.
+ * @sdev: scsi device struct
+ *
+ * Return value:
+ * resource entry pointer if found / NULL if not found
+ **/
+static struct ipr_resource_entry *ipr_find_sdev(struct scsi_device *sdev)
+{
+ struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
+ struct ipr_resource_entry *res;
+
+ list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+ if ((res->cfgte.res_addr.bus == sdev->channel) &&
+ (res->cfgte.res_addr.target == sdev->id) &&
+ (res->cfgte.res_addr.lun == sdev->lun))
+ return res;
+ }
+
+ return NULL;
+}
+
+/**
* ipr_slave_destroy - Unconfigure a SCSI device
* @sdev: scsi device struct
*
@@ -3183,8 +3346,11 @@ static void ipr_slave_destroy(struct scsi_device *sdev)
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
res = (struct ipr_resource_entry *) sdev->hostdata;
if (res) {
+ if (res->sata_port)
+ ata_port_disable(res->sata_port->ap);
sdev->hostdata = NULL;
res->sdev = NULL;
+ res->sata_port = NULL;
}
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
}
@@ -3219,13 +3385,45 @@ static int ipr_slave_configure(struct scsi_device *sdev)
}
if (ipr_is_vset_device(res) || ipr_is_scsi_disk(res))
sdev->allow_restart = 1;
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+ if (ipr_is_gata(res) && res->sata_port) {
+ scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN);
+ ata_sas_slave_configure(sdev, res->sata_port->ap);
+ } else {
+ scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+ }
}
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return 0;
}
/**
+ * ipr_ata_slave_alloc - Prepare for commands to a SATA device
+ * @sdev: scsi device struct
+ *
+ * This function initializes an ATA port so that future commands
+ * sent through queuecommand will work.
+ *
+ * Return value:
+ * 0 on success
+ **/
+static int ipr_ata_slave_alloc(struct scsi_device *sdev)
+{
+ struct ipr_sata_port *sata_port = NULL;
+ int rc = -ENXIO;
+
+ ENTER;
+ if (sdev->sdev_target)
+ sata_port = sdev->sdev_target->hostdata;
+ if (sata_port)
+ rc = ata_sas_port_init(sata_port->ap);
+ if (rc)
+ ipr_slave_destroy(sdev);
+
+ LEAVE;
+ return rc;
+}
+
+/**
* ipr_slave_alloc - Prepare for commands to a device.
* @sdev: scsi device struct
*
@@ -3248,18 +3446,18 @@ static int ipr_slave_alloc(struct scsi_device *sdev)
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
- list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
- if ((res->cfgte.res_addr.bus == sdev->channel) &&
- (res->cfgte.res_addr.target == sdev->id) &&
- (res->cfgte.res_addr.lun == sdev->lun)) {
- res->sdev = sdev;
- res->add_to_ml = 0;
- res->in_erp = 0;
- sdev->hostdata = res;
- if (!ipr_is_naca_model(res))
- res->needs_sync_complete = 1;
- rc = 0;
- break;
+ res = ipr_find_sdev(sdev);
+ if (res) {
+ res->sdev = sdev;
+ res->add_to_ml = 0;
+ res->in_erp = 0;
+ sdev->hostdata = res;
+ if (!ipr_is_naca_model(res))
+ res->needs_sync_complete = 1;
+ rc = 0;
+ if (ipr_is_gata(res)) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ return ipr_ata_slave_alloc(sdev);
}
}
@@ -3314,7 +3512,8 @@ static int ipr_eh_host_reset(struct scsi_cmnd * cmd)
* This function issues a device reset to the affected device.
* If the device is a SCSI device, a LUN reset will be sent
* to the device first. If that does not work, a target reset
- * will be sent.
+ * will be sent. If the device is a SATA device, a PHY reset will
+ * be sent.
*
* Return value:
* 0 on success / non-zero on failure
@@ -3325,26 +3524,79 @@ static int ipr_device_reset(struct ipr_ioa_cfg *ioa_cfg,
struct ipr_cmnd *ipr_cmd;
struct ipr_ioarcb *ioarcb;
struct ipr_cmd_pkt *cmd_pkt;
+ struct ipr_ioarcb_ata_regs *regs;
u32 ioasc;
ENTER;
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
cmd_pkt = &ioarcb->cmd_pkt;
+ regs = &ioarcb->add_data.u.regs;
ioarcb->res_handle = res->cfgte.res_handle;
cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
+ if (ipr_is_gata(res)) {
+ cmd_pkt->cdb[2] = IPR_ATA_PHY_RESET;
+ ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(regs->flags));
+ regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
+ }
ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+ if (ipr_is_gata(res) && res->sata_port && ioasc != IPR_IOASC_IOA_WAS_RESET)
+ memcpy(&res->sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
+ sizeof(struct ipr_ioasa_gata));
LEAVE;
return (IPR_IOASC_SENSE_KEY(ioasc) ? -EIO : 0);
}
/**
+ * ipr_sata_reset - Reset the SATA port
+ * @ap: SATA port to reset
+ * @classes: class of the attached device
+ *
+ * This function issues a SATA phy reset to the affected ATA port.
+ *
+ * Return value:
+ * 0 on success / non-zero on failure
+ **/
+static int ipr_sata_reset(struct ata_port *ap, unsigned int *classes)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ struct ipr_resource_entry *res;
+ unsigned long lock_flags = 0;
+ int rc = -ENXIO;
+
+ ENTER;
+ spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+ res = sata_port->res;
+ if (res) {
+ rc = ipr_device_reset(ioa_cfg, res);
+ switch(res->cfgte.proto) {
+ case IPR_PROTO_SATA:
+ case IPR_PROTO_SAS_STP:
+ *classes = ATA_DEV_ATA;
+ break;
+ case IPR_PROTO_SATA_ATAPI:
+ case IPR_PROTO_SAS_STP_ATAPI:
+ *classes = ATA_DEV_ATAPI;
+ break;
+ default:
+ *classes = ATA_DEV_UNKNOWN;
+ break;
+ };
+ }
+
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+ LEAVE;
+ return rc;
+}
+
+/**
* ipr_eh_dev_reset - Reset the device
* @scsi_cmd: scsi command struct
*
@@ -3360,7 +3612,8 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
struct ipr_cmnd *ipr_cmd;
struct ipr_ioa_cfg *ioa_cfg;
struct ipr_resource_entry *res;
- int rc;
+ struct ata_port *ap;
+ int rc = 0;
ENTER;
ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
@@ -3388,7 +3641,14 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
res->resetting_device = 1;
scmd_printk(KERN_ERR, scsi_cmd, "Resetting device\n");
- rc = ipr_device_reset(ioa_cfg, res);
+
+ if (ipr_is_gata(res) && res->sata_port) {
+ ap = res->sata_port->ap;
+ spin_unlock_irq(scsi_cmd->device->host->host_lock);
+ ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL);
+ spin_lock_irq(scsi_cmd->device->host->host_lock);
+ } else
+ rc = ipr_device_reset(ioa_cfg, res);
res->resetting_device = 0;
LEAVE;
@@ -3620,12 +3880,11 @@ static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
* ipr_isr - Interrupt service routine
* @irq: irq number
* @devp: pointer to ioa config struct
- * @regs: pt_regs struct
*
* Return value:
* IRQ_NONE / IRQ_HANDLED
**/
-static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs)
+static irqreturn_t ipr_isr(int irq, void *devp)
{
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
unsigned long lock_flags = 0;
@@ -4300,6 +4559,9 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
return 0;
}
+ if (ipr_is_gata(res) && res->sata_port)
+ return ata_sas_queuecmd(scsi_cmd, done, res->sata_port->ap);
+
ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
ioarcb = &ipr_cmd->ioarcb;
list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
@@ -4345,6 +4607,26 @@ static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
}
/**
+ * ipr_ioctl - IOCTL handler
+ * @sdev: scsi device struct
+ * @cmd: IOCTL cmd
+ * @arg: IOCTL arg
+ *
+ * Return value:
+ * 0 on success / other on failure
+ **/
+int ipr_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+ struct ipr_resource_entry *res;
+
+ res = (struct ipr_resource_entry *)sdev->hostdata;
+ if (res && ipr_is_gata(res))
+ return ata_scsi_ioctl(sdev, cmd, arg);
+
+ return -EINVAL;
+}
+
+/**
* ipr_info - Get information about the card/driver
* @scsi_host: scsi host struct
*
@@ -4366,10 +4648,45 @@ static const char * ipr_ioa_info(struct Scsi_Host *host)
return buffer;
}
+/**
+ * ipr_scsi_timed_out - Handle scsi command timeout
+ * @scsi_cmd: scsi command struct
+ *
+ * Return value:
+ * EH_NOT_HANDLED
+ **/
+enum scsi_eh_timer_return ipr_scsi_timed_out(struct scsi_cmnd *scsi_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg;
+ struct ipr_cmnd *ipr_cmd;
+ unsigned long flags;
+
+ ENTER;
+ spin_lock_irqsave(scsi_cmd->device->host->host_lock, flags);
+ ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
+
+ list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+ if (ipr_cmd->qc && ipr_cmd->qc->scsicmd == scsi_cmd) {
+ ipr_cmd->qc->err_mask |= AC_ERR_TIMEOUT;
+ ipr_cmd->qc->flags |= ATA_QCFLAG_FAILED;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(scsi_cmd->device->host->host_lock, flags);
+ LEAVE;
+ return EH_NOT_HANDLED;
+}
+
+static struct scsi_transport_template ipr_transport_template = {
+ .eh_timed_out = ipr_scsi_timed_out
+};
+
static struct scsi_host_template driver_template = {
.module = THIS_MODULE,
.name = "IPR",
.info = ipr_ioa_info,
+ .ioctl = ipr_ioctl,
.queuecommand = ipr_queuecommand,
.eh_abort_handler = ipr_eh_abort,
.eh_device_reset_handler = ipr_eh_dev_reset,
@@ -4377,6 +4694,8 @@ static struct scsi_host_template driver_template = {
.slave_alloc = ipr_slave_alloc,
.slave_configure = ipr_slave_configure,
.slave_destroy = ipr_slave_destroy,
+ .target_alloc = ipr_target_alloc,
+ .target_destroy = ipr_target_destroy,
.change_queue_depth = ipr_change_queue_depth,
.change_queue_type = ipr_change_queue_type,
.bios_param = ipr_biosparam,
@@ -4391,6 +4710,330 @@ static struct scsi_host_template driver_template = {
.proc_name = IPR_NAME
};
+/**
+ * ipr_ata_phy_reset - libata phy_reset handler
+ * @ap: ata port to reset
+ *
+ **/
+static void ipr_ata_phy_reset(struct ata_port *ap)
+{
+ unsigned long flags;
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_resource_entry *res = sata_port->res;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ int rc;
+
+ ENTER;
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ while(ioa_cfg->in_reset_reload) {
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ }
+
+ if (!ioa_cfg->allow_cmds)
+ goto out_unlock;
+
+ rc = ipr_device_reset(ioa_cfg, res);
+
+ if (rc) {
+ ap->ops->port_disable(ap);
+ goto out_unlock;
+ }
+
+ switch(res->cfgte.proto) {
+ case IPR_PROTO_SATA:
+ case IPR_PROTO_SAS_STP:
+ ap->device[0].class = ATA_DEV_ATA;
+ break;
+ case IPR_PROTO_SATA_ATAPI:
+ case IPR_PROTO_SAS_STP_ATAPI:
+ ap->device[0].class = ATA_DEV_ATAPI;
+ break;
+ default:
+ ap->device[0].class = ATA_DEV_UNKNOWN;
+ ap->ops->port_disable(ap);
+ break;
+ };
+
+out_unlock:
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+ LEAVE;
+}
+
+/**
+ * ipr_ata_post_internal - Cleanup after an internal command
+ * @qc: ATA queued command
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_ata_post_internal(struct ata_queued_cmd *qc)
+{
+ struct ipr_sata_port *sata_port = qc->ap->private_data;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ struct ipr_cmnd *ipr_cmd;
+ unsigned long flags;
+
+ spin_lock_irqsave(ioa_cfg->host->host_lock, flags);
+ list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+ if (ipr_cmd->qc == qc) {
+ ipr_device_reset(ioa_cfg, sata_port->res);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(ioa_cfg->host->host_lock, flags);
+}
+
+/**
+ * ipr_tf_read - Read the current ATA taskfile for the ATA port
+ * @ap: ATA port
+ * @tf: destination ATA taskfile
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_ioasa_gata *g = &sata_port->ioasa;
+
+ tf->feature = g->error;
+ tf->nsect = g->nsect;
+ tf->lbal = g->lbal;
+ tf->lbam = g->lbam;
+ tf->lbah = g->lbah;
+ tf->device = g->device;
+ tf->command = g->status;
+ tf->hob_nsect = g->hob_nsect;
+ tf->hob_lbal = g->hob_lbal;
+ tf->hob_lbam = g->hob_lbam;
+ tf->hob_lbah = g->hob_lbah;
+ tf->ctl = g->alt_status;
+}
+
+/**
+ * ipr_copy_sata_tf - Copy a SATA taskfile to an IOA data structure
+ * @regs: destination
+ * @tf: source ATA taskfile
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_copy_sata_tf(struct ipr_ioarcb_ata_regs *regs,
+ struct ata_taskfile *tf)
+{
+ regs->feature = tf->feature;
+ regs->nsect = tf->nsect;
+ regs->lbal = tf->lbal;
+ regs->lbam = tf->lbam;
+ regs->lbah = tf->lbah;
+ regs->device = tf->device;
+ regs->command = tf->command;
+ regs->hob_feature = tf->hob_feature;
+ regs->hob_nsect = tf->hob_nsect;
+ regs->hob_lbal = tf->hob_lbal;
+ regs->hob_lbam = tf->hob_lbam;
+ regs->hob_lbah = tf->hob_lbah;
+ regs->ctl = tf->ctl;
+}
+
+/**
+ * ipr_sata_done - done function for SATA commands
+ * @ipr_cmd: ipr command struct
+ *
+ * This function is invoked by the interrupt handler for
+ * ops generated by the SCSI mid-layer to SATA devices
+ *
+ * Return value:
+ * none
+ **/
+static void ipr_sata_done(struct ipr_cmnd *ipr_cmd)
+{
+ struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+ struct ata_queued_cmd *qc = ipr_cmd->qc;
+ struct ipr_sata_port *sata_port = qc->ap->private_data;
+ struct ipr_resource_entry *res = sata_port->res;
+ u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+ memcpy(&sata_port->ioasa, &ipr_cmd->ioasa.u.gata,
+ sizeof(struct ipr_ioasa_gata));
+ ipr_dump_ioasa(ioa_cfg, ipr_cmd, res);
+
+ if (be32_to_cpu(ipr_cmd->ioasa.ioasc_specific) & IPR_ATA_DEVICE_WAS_RESET)
+ scsi_report_device_reset(ioa_cfg->host, res->cfgte.res_addr.bus,
+ res->cfgte.res_addr.target);
+
+ if (IPR_IOASC_SENSE_KEY(ioasc) > RECOVERED_ERROR)
+ qc->err_mask |= __ac_err_mask(ipr_cmd->ioasa.u.gata.status);
+ else
+ qc->err_mask |= ac_err_mask(ipr_cmd->ioasa.u.gata.status);
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+ ata_qc_complete(qc);
+}
+
+/**
+ * ipr_build_ata_ioadl - Build an ATA scatter/gather list
+ * @ipr_cmd: ipr command struct
+ * @qc: ATA queued command
+ *
+ **/
+static void ipr_build_ata_ioadl(struct ipr_cmnd *ipr_cmd,
+ struct ata_queued_cmd *qc)
+{
+ u32 ioadl_flags = 0;
+ struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+ struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+ int len = qc->nbytes + qc->pad_len;
+ struct scatterlist *sg;
+
+ if (len == 0)
+ return;
+
+ if (qc->dma_dir == DMA_TO_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+ ioarcb->write_data_transfer_length = cpu_to_be32(len);
+ ioarcb->write_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ } else if (qc->dma_dir == DMA_FROM_DEVICE) {
+ ioadl_flags = IPR_IOADL_FLAGS_READ;
+ ioarcb->read_data_transfer_length = cpu_to_be32(len);
+ ioarcb->read_ioadl_len =
+ cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+ }
+
+ ata_for_each_sg(sg, qc) {
+ ioadl->flags_and_data_len = cpu_to_be32(ioadl_flags | sg_dma_len(sg));
+ ioadl->address = cpu_to_be32(sg_dma_address(sg));
+ if (ata_sg_is_last(sg, qc))
+ ioadl->flags_and_data_len |= cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+ else
+ ioadl++;
+ }
+}
+
+/**
+ * ipr_qc_issue - Issue a SATA qc to a device
+ * @qc: queued command
+ *
+ * Return value:
+ * 0 if success
+ **/
+static unsigned int ipr_qc_issue(struct ata_queued_cmd *qc)
+{
+ struct ata_port *ap = qc->ap;
+ struct ipr_sata_port *sata_port = ap->private_data;
+ struct ipr_resource_entry *res = sata_port->res;
+ struct ipr_ioa_cfg *ioa_cfg = sata_port->ioa_cfg;
+ struct ipr_cmnd *ipr_cmd;
+ struct ipr_ioarcb *ioarcb;
+ struct ipr_ioarcb_ata_regs *regs;
+
+ if (unlikely(!ioa_cfg->allow_cmds || ioa_cfg->ioa_is_dead))
+ return -EIO;
+
+ ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+ ioarcb = &ipr_cmd->ioarcb;
+ regs = &ioarcb->add_data.u.regs;
+
+ memset(&ioarcb->add_data, 0, sizeof(ioarcb->add_data));
+ ioarcb->add_cmd_parms_len = cpu_to_be32(sizeof(ioarcb->add_data.u.regs));
+
+ list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+ ipr_cmd->qc = qc;
+ ipr_cmd->done = ipr_sata_done;
+ ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
+ ioarcb->cmd_pkt.request_type = IPR_RQTYPE_ATA_PASSTHRU;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
+ ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
+ ipr_cmd->dma_use_sg = qc->pad_len ? qc->n_elem + 1 : qc->n_elem;
+
+ ipr_build_ata_ioadl(ipr_cmd, qc);
+ regs->flags |= IPR_ATA_FLAG_STATUS_ON_GOOD_COMPLETION;
+ ipr_copy_sata_tf(regs, &qc->tf);
+ memcpy(ioarcb->cmd_pkt.cdb, qc->cdb, IPR_MAX_CDB_LEN);
+ ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
+
+ switch (qc->tf.protocol) {
+ case ATA_PROT_NODATA:
+ case ATA_PROT_PIO:
+ break;
+
+ case ATA_PROT_DMA:
+ regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+ break;
+
+ case ATA_PROT_ATAPI:
+ case ATA_PROT_ATAPI_NODATA:
+ regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+ break;
+
+ case ATA_PROT_ATAPI_DMA:
+ regs->flags |= IPR_ATA_FLAG_PACKET_CMD;
+ regs->flags |= IPR_ATA_FLAG_XFER_TYPE_DMA;
+ break;
+
+ default:
+ WARN_ON(1);
+ return -1;
+ }
+
+ mb();
+ writel(be32_to_cpu(ioarcb->ioarcb_host_pci_addr),
+ ioa_cfg->regs.ioarrin_reg);
+ return 0;
+}
+
+/**
+ * ipr_ata_check_status - Return last ATA status
+ * @ap: ATA port
+ *
+ * Return value:
+ * ATA status
+ **/
+static u8 ipr_ata_check_status(struct ata_port *ap)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ return sata_port->ioasa.status;
+}
+
+/**
+ * ipr_ata_check_altstatus - Return last ATA altstatus
+ * @ap: ATA port
+ *
+ * Return value:
+ * Alt ATA status
+ **/
+static u8 ipr_ata_check_altstatus(struct ata_port *ap)
+{
+ struct ipr_sata_port *sata_port = ap->private_data;
+ return sata_port->ioasa.alt_status;
+}
+
+static struct ata_port_operations ipr_sata_ops = {
+ .port_disable = ata_port_disable,
+ .check_status = ipr_ata_check_status,
+ .check_altstatus = ipr_ata_check_altstatus,
+ .dev_select = ata_noop_dev_select,
+ .phy_reset = ipr_ata_phy_reset,
+ .post_internal_cmd = ipr_ata_post_internal,
+ .tf_read = ipr_tf_read,
+ .qc_prep = ata_noop_qc_prep,
+ .qc_issue = ipr_qc_issue,
+ .port_start = ata_sas_port_start,
+ .port_stop = ata_sas_port_stop
+};
+
+static struct ata_port_info sata_port_info = {
+ .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET |
+ ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA,
+ .pio_mask = 0x10, /* pio4 */
+ .mwdma_mask = 0x07,
+ .udma_mask = 0x7f, /* udma0-6 */
+ .port_ops = &ipr_sata_ops
+};
+
#ifdef CONFIG_PPC_PSERIES
static const u16 ipr_blocked_processors[] = {
PV_NORTHSTAR,
@@ -6352,7 +6995,7 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
struct Scsi_Host *host;
unsigned long ipr_regs_pci;
void __iomem *ipr_regs;
- u32 rc = PCIBIOS_SUCCESSFUL;
+ int rc = PCIBIOS_SUCCESSFUL;
volatile u32 mask, uproc;
ENTER;
@@ -6374,6 +7017,9 @@ static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
+ host->transportt = &ipr_transport_template;
+ ata_host_init(&ioa_cfg->ata_host, &pdev->dev,
+ sata_port_info.flags, &ipr_sata_ops);
ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
@@ -6749,7 +7395,7 @@ static int __init ipr_init(void)
ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n",
IPR_DRIVER_VERSION, IPR_DRIVER_DATE);
- return pci_module_init(&ipr_driver);
+ return pci_register_driver(&ipr_driver);
}
/**
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index 11eaff524327..6d035283af08 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -28,6 +28,7 @@
#include <linux/types.h>
#include <linux/completion.h>
+#include <linux/libata.h>
#include <linux/list.h>
#include <linux/kref.h>
#include <scsi/scsi.h>
@@ -36,8 +37,8 @@
/*
* Literals
*/
-#define IPR_DRIVER_VERSION "2.1.4"
-#define IPR_DRIVER_DATE "(August 2, 2006)"
+#define IPR_DRIVER_VERSION "2.2.0"
+#define IPR_DRIVER_DATE "(September 25, 2006)"
/*
* IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
@@ -849,6 +850,13 @@ struct ipr_bus_attributes {
u32 max_xfer_rate;
};
+struct ipr_sata_port {
+ struct ipr_ioa_cfg *ioa_cfg;
+ struct ata_port *ap;
+ struct ipr_resource_entry *res;
+ struct ipr_ioasa_gata ioasa;
+};
+
struct ipr_resource_entry {
struct ipr_config_table_entry cfgte;
u8 needs_sync_complete:1;
@@ -858,6 +866,7 @@ struct ipr_resource_entry {
u8 resetting_device:1;
struct scsi_device *sdev;
+ struct ipr_sata_port *sata_port;
struct list_head queue;
};
@@ -928,10 +937,11 @@ struct ipr_trace_entry {
u32 time;
u8 op_code;
+ u8 ata_op_code;
u8 type;
#define IPR_TRACE_START 0x00
#define IPR_TRACE_FINISH 0xff
- u16 cmd_index;
+ u8 cmd_index;
__be32 res_handle;
union {
@@ -1073,6 +1083,7 @@ struct ipr_ioa_cfg {
struct ipr_cmnd *reset_cmd;
+ struct ata_host ata_host;
char ipr_cmd_label[8];
#define IPR_CMD_LABEL "ipr_cmnd"
struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
@@ -1085,6 +1096,7 @@ struct ipr_cmnd {
struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
struct list_head queue;
struct scsi_cmnd *scsi_cmd;
+ struct ata_queued_cmd *qc;
struct completion completion;
struct timer_list timer;
void (*done) (struct ipr_cmnd *);
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 3c639286ec1e..f06a06ae6092 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -182,14 +182,8 @@
#include <linux/dma-mapping.h>
#include <scsi/sg.h>
-
#include "scsi.h"
-
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
-#include "hosts.h"
-#else
#include <scsi/scsi_host.h>
-#endif
#include "ips.h"
@@ -250,11 +244,11 @@ module_param(ips, charp, 0);
*/
static int ips_detect(struct scsi_host_template *);
static int ips_release(struct Scsi_Host *);
-static int ips_eh_abort(Scsi_Cmnd *);
-static int ips_eh_reset(Scsi_Cmnd *);
-static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static int ips_eh_abort(struct scsi_cmnd *);
+static int ips_eh_reset(struct scsi_cmnd *);
+static int ips_queue(struct scsi_cmnd *, void (*)(struct scsi_cmnd *));
static const char *ips_info(struct Scsi_Host *);
-static irqreturn_t do_ipsintr(int, void *, struct pt_regs *);
+static irqreturn_t do_ipsintr(int, void *);
static int ips_hainit(ips_ha_t *);
static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
@@ -325,24 +319,26 @@ static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
static uint32_t ips_statupd_morpheus(ips_ha_t *);
static ips_scb_t *ips_getscb(ips_ha_t *);
static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
-static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
+static void ips_putq_wait_tail(ips_wait_queue_t *, struct scsi_cmnd *);
static void ips_putq_copp_tail(ips_copp_queue_t *,
ips_copp_wait_item_t *);
static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
-static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
-static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
+static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
+static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *,
+ struct scsi_cmnd *);
static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
ips_copp_wait_item_t *);
static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
-static int ips_is_passthru(Scsi_Cmnd *);
-static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
+static int ips_is_passthru(struct scsi_cmnd *);
+static int ips_make_passthru(ips_ha_t *, struct scsi_cmnd *, ips_scb_t *, int);
static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
-static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
+static void ips_scmd_buf_write(struct scsi_cmnd * scmd, void *data,
unsigned int count);
-static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
+static void ips_scmd_buf_read(struct scsi_cmnd * scmd, void *data,
+ unsigned int count);
static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
static int ips_host_info(ips_ha_t *, char *, off_t, int);
@@ -812,8 +808,7 @@ ips_halt(struct notifier_block *nb, ulong event, void *buf)
/* Abort a command (using the new error code stuff) */
/* Note: this routine is called under the io_request_lock */
/****************************************************************************/
-int
-ips_eh_abort(Scsi_Cmnd * SC)
+int ips_eh_abort(struct scsi_cmnd *SC)
{
ips_ha_t *ha;
ips_copp_wait_item_t *item;
@@ -871,8 +866,7 @@ ips_eh_abort(Scsi_Cmnd * SC)
/* NOTE: this routine is called under the io_request_lock spinlock */
/* */
/****************************************************************************/
-static int
-__ips_eh_reset(Scsi_Cmnd * SC)
+static int __ips_eh_reset(struct scsi_cmnd *SC)
{
int ret;
int i;
@@ -968,7 +962,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
ret = (*ha->func.reset) (ha);
if (!ret) {
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
IPS_PRINTK(KERN_NOTICE, ha->pcidev,
"Controller reset failed - controller now offline.\n");
@@ -997,7 +991,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
}
if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
IPS_PRINTK(KERN_NOTICE, ha->pcidev,
"Controller reset failed - controller now offline.\n");
@@ -1059,8 +1053,7 @@ __ips_eh_reset(Scsi_Cmnd * SC)
}
-static int
-ips_eh_reset(Scsi_Cmnd * SC)
+static int ips_eh_reset(struct scsi_cmnd *SC)
{
int rc;
@@ -1083,8 +1076,7 @@ ips_eh_reset(Scsi_Cmnd * SC)
/* Linux obtains io_request_lock before calling this function */
/* */
/****************************************************************************/
-static int
-ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
+static int ips_queue(struct scsi_cmnd *SC, void (*done) (struct scsi_cmnd *))
{
ips_ha_t *ha;
ips_passthru_t *pt;
@@ -1336,7 +1328,7 @@ ips_slave_configure(struct scsi_device * SDptr)
/* */
/****************************************************************************/
static irqreturn_t
-do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
+do_ipsintr(int irq, void *dev_id)
{
ips_ha_t *ha;
unsigned long cpu_flags;
@@ -1602,8 +1594,7 @@ ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
/* Determine if the specified SCSI command is really a passthru command */
/* */
/****************************************************************************/
-static int
-ips_is_passthru(Scsi_Cmnd * SC)
+static int ips_is_passthru(struct scsi_cmnd *SC)
{
unsigned long flags;
@@ -1685,7 +1676,7 @@ ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
/* */
/****************************************************************************/
static int
-ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
+ips_make_passthru(ips_ha_t *ha, struct scsi_cmnd *SC, ips_scb_t *scb, int intr)
{
ips_passthru_t *pt;
int length = 0;
@@ -2734,9 +2725,9 @@ static void
ips_next(ips_ha_t * ha, int intr)
{
ips_scb_t *scb;
- Scsi_Cmnd *SC;
- Scsi_Cmnd *p;
- Scsi_Cmnd *q;
+ struct scsi_cmnd *SC;
+ struct scsi_cmnd *p;
+ struct scsi_cmnd *q;
ips_copp_wait_item_t *item;
int ret;
unsigned long cpu_flags = 0;
@@ -2847,7 +2838,7 @@ ips_next(ips_ha_t * ha, int intr)
dcdb_active[scmd_channel(p) -
1] & (1 << scmd_id(p)))) {
ips_freescb(ha, scb);
- p = (Scsi_Cmnd *) p->host_scribble;
+ p = (struct scsi_cmnd *) p->host_scribble;
continue;
}
@@ -2962,7 +2953,7 @@ ips_next(ips_ha_t * ha, int intr)
break;
} /* end case */
- p = (Scsi_Cmnd *) p->host_scribble;
+ p = (struct scsi_cmnd *) p->host_scribble;
} /* end while */
@@ -3090,8 +3081,7 @@ ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
/* ASSUMED to be called from within the HA lock */
/* */
/****************************************************************************/
-static void
-ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+static void ips_putq_wait_tail(ips_wait_queue_t *queue, struct scsi_cmnd *item)
{
METHOD_TRACE("ips_putq_wait_tail", 1);
@@ -3122,10 +3112,9 @@ ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
/* ASSUMED to be called from within the HA lock */
/* */
/****************************************************************************/
-static Scsi_Cmnd *
-ips_removeq_wait_head(ips_wait_queue_t * queue)
+static struct scsi_cmnd *ips_removeq_wait_head(ips_wait_queue_t *queue)
{
- Scsi_Cmnd *item;
+ struct scsi_cmnd *item;
METHOD_TRACE("ips_removeq_wait_head", 1);
@@ -3135,7 +3124,7 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
return (NULL);
}
- queue->head = (Scsi_Cmnd *) item->host_scribble;
+ queue->head = (struct scsi_cmnd *) item->host_scribble;
item->host_scribble = NULL;
if (queue->tail == item)
@@ -3157,10 +3146,10 @@ ips_removeq_wait_head(ips_wait_queue_t * queue)
/* ASSUMED to be called from within the HA lock */
/* */
/****************************************************************************/
-static Scsi_Cmnd *
-ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+static struct scsi_cmnd *ips_removeq_wait(ips_wait_queue_t *queue,
+ struct scsi_cmnd *item)
{
- Scsi_Cmnd *p;
+ struct scsi_cmnd *p;
METHOD_TRACE("ips_removeq_wait", 1);
@@ -3173,8 +3162,8 @@ ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
p = queue->head;
- while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
- p = (Scsi_Cmnd *) p->host_scribble;
+ while ((p) && (item != (struct scsi_cmnd *) p->host_scribble))
+ p = (struct scsi_cmnd *) p->host_scribble;
if (p) {
/* found a match */
@@ -3659,11 +3648,10 @@ ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
/* Routine Name: ips_scmd_buf_write */
/* */
/* Routine Description: */
-/* Write data to Scsi_Cmnd request_buffer at proper offsets */
+/* Write data to struct scsi_cmnd request_buffer at proper offsets */
/****************************************************************************/
static void
-ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
- int count)
+ips_scmd_buf_write(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
if (scmd->use_sg) {
int i;
@@ -3698,11 +3686,10 @@ ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
/* Routine Name: ips_scmd_buf_read */
/* */
/* Routine Description: */
-/* Copy data from a Scsi_Cmnd to a new, linear buffer */
+/* Copy data from a struct scsi_cmnd to a new, linear buffer */
/****************************************************************************/
static void
-ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
- int count)
+ips_scmd_buf_read(struct scsi_cmnd *scmd, void *data, unsigned int count)
{
if (scmd->use_sg) {
int i;
@@ -7078,7 +7065,7 @@ ips_remove_device(struct pci_dev *pci_dev)
static int __init
ips_module_init(void)
{
- if (pci_module_init(&ips_pci_driver) < 0)
+ if (pci_register_driver(&ips_pci_driver) < 0)
return -ENODEV;
ips_driver_template.module = THIS_MODULE;
ips_order_controllers();
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index f46c382e5599..34680f3dd452 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -6,7 +6,7 @@
/* David Jeffery, Adaptec, Inc. */
/* */
/* Copyright (C) 1999 IBM Corporation */
-/* Copyright (C) 2003 Adaptec, Inc. */
+/* Copyright (C) 2003 Adaptec, Inc. */
/* */
/* 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 */
@@ -1033,14 +1033,14 @@ typedef struct ips_scb_queue {
* Wait queue_format
*/
typedef struct ips_wait_queue {
- Scsi_Cmnd *head;
- Scsi_Cmnd *tail;
- int count;
+ struct scsi_cmnd *head;
+ struct scsi_cmnd *tail;
+ int count;
} ips_wait_queue_t;
typedef struct ips_copp_wait_item {
- Scsi_Cmnd *scsi_cmd;
- struct ips_copp_wait_item *next;
+ struct scsi_cmnd *scsi_cmd;
+ struct ips_copp_wait_item *next;
} ips_copp_wait_item_t;
typedef struct ips_copp_queue {
@@ -1149,7 +1149,7 @@ typedef struct ips_scb {
uint32_t flags;
uint32_t op_code;
IPS_SG_LIST sg_list;
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
struct ips_scb *q_next;
ips_scb_callback callback;
uint32_t sg_busaddr;
@@ -1175,7 +1175,7 @@ typedef struct ips_scb_pt {
uint32_t flags;
uint32_t op_code;
IPS_SG_LIST *sg_list;
- Scsi_Cmnd *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
struct ips_scb *q_next;
ips_scb_callback callback;
} ips_scb_pt_t;
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 7f9e89bcac7e..e46e79355b77 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -126,7 +126,7 @@ static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd)
enum task_attribute ta = TASK_ATTR_SIMPLE;
if (cmd->request && blk_rq_tagged(cmd->request)) {
if (cmd->device->ordered_tags &&
- (cmd->request->flags & REQ_HARDBARRIER))
+ (cmd->request->cmd_flags & REQ_HARDBARRIER))
ta = TASK_ATTR_HOQ;
}
return ta;
diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h
index 3d684496acde..1251788ce2a3 100644
--- a/drivers/scsi/lpfc/lpfc_crtn.h
+++ b/drivers/scsi/lpfc/lpfc_crtn.h
@@ -120,7 +120,7 @@ int lpfc_sli_queue_setup(struct lpfc_hba *);
void lpfc_handle_eratt(struct lpfc_hba *);
void lpfc_handle_latt(struct lpfc_hba *);
-irqreturn_t lpfc_intr_handler(int, void *, struct pt_regs *);
+irqreturn_t lpfc_intr_handler(int, void *);
void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *);
void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *);
diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c
index ae4106458991..1b53afb1cb57 100644
--- a/drivers/scsi/lpfc/lpfc_ct.c
+++ b/drivers/scsi/lpfc/lpfc_ct.c
@@ -933,8 +933,8 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
ae = (ATTRIBUTE_ENTRY *) ((uint8_t *) rh + size);
ae->ad.bits.AttrType = be16_to_cpu(OS_NAME_VERSION);
sprintf(ae->un.OsNameVersion, "%s %s %s",
- system_utsname.sysname, system_utsname.release,
- system_utsname.version);
+ init_utsname()->sysname, init_utsname()->release,
+ init_utsname()->version);
len = strlen(ae->un.OsNameVersion);
len += (len & 3) ? (4 - (len & 3)) : 4;
ae->ad.bits.AttrLen = be16_to_cpu(FOURBYTES + len);
@@ -1052,7 +1052,7 @@ lpfc_fdmi_cmd(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, int cmdcode)
size);
ae->ad.bits.AttrType = be16_to_cpu(HOST_NAME);
sprintf(ae->un.HostName, "%s",
- system_utsname.nodename);
+ init_utsname()->nodename);
len = strlen(ae->un.HostName);
len += (len & 3) ? (4 - (len & 3)) : 4;
ae->ad.bits.AttrLen =
@@ -1140,7 +1140,7 @@ lpfc_fdmi_tmo_handler(struct lpfc_hba *phba)
ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, FDMI_DID);
if (ndlp) {
- if (system_utsname.nodename[0] != '\0') {
+ if (init_utsname()->nodename[0] != '\0') {
lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA);
} else {
mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60);
diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c
index 4cdf3464267f..a5723ad0a099 100644
--- a/drivers/scsi/lpfc/lpfc_init.c
+++ b/drivers/scsi/lpfc/lpfc_init.c
@@ -389,7 +389,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
lpfc_init_link(phba, pmb, phba->cfg_topology, phba->cfg_link_speed);
pmb->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
- if (lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT) != MBX_SUCCESS) {
+ rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT);
+ if (rc != MBX_SUCCESS) {
lpfc_printf_log(phba,
KERN_ERR,
LOG_INIT,
@@ -406,7 +407,8 @@ lpfc_config_port_post(struct lpfc_hba * phba)
readl(phba->HAregaddr); /* flush */
phba->hba_state = LPFC_HBA_ERROR;
- mempool_free(pmb, phba->mbox_mem_pool);
+ if (rc != MBX_BUSY)
+ mempool_free(pmb, phba->mbox_mem_pool);
return -EIO;
}
/* MBOX buffer will be freed in mbox compl */
diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c
index 70f4d5a1348e..24a1779b9af4 100644
--- a/drivers/scsi/lpfc/lpfc_sli.c
+++ b/drivers/scsi/lpfc/lpfc_sli.c
@@ -3119,7 +3119,7 @@ lpfc_sli_flush_mbox_queue(struct lpfc_hba * phba)
}
irqreturn_t
-lpfc_intr_handler(int irq, void *dev_id, struct pt_regs * regs)
+lpfc_intr_handler(int irq, void *dev_id)
{
struct lpfc_hba *phba;
uint32_t ha_copy;
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index 6422de72bf43..753d88306cd1 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -60,8 +60,8 @@ struct fsc_state {
static void mac53c94_init(struct fsc_state *);
static void mac53c94_start(struct fsc_state *);
-static void mac53c94_interrupt(int, void *, struct pt_regs *);
-static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *);
+static void mac53c94_interrupt(int, void *);
+static irqreturn_t do_mac53c94_interrupt(int, void *);
static void cmd_done(struct fsc_state *, int result);
static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
@@ -177,18 +177,18 @@ static void mac53c94_start(struct fsc_state *state)
set_dma_cmds(state, cmd);
}
-static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host;
spin_lock_irqsave(dev->host_lock, flags);
- mac53c94_interrupt(irq, dev_id, ptregs);
+ mac53c94_interrupt(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
-static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static void mac53c94_interrupt(int irq, void *dev_id)
{
struct fsc_state *state = (struct fsc_state *) dev_id;
struct mac53c94_regs __iomem *regs = state->regs;
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
index 118206d68c6c..3586fac9be9a 100644
--- a/drivers/scsi/mac_esp.c
+++ b/drivers/scsi/mac_esp.c
@@ -44,7 +44,7 @@
/* #define DEBUG_MAC_ESP */
extern void esp_handle(struct NCR_ESP *esp);
-extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+extern void mac_esp_intr(int irq, void *dev_id);
static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count);
static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp);
@@ -88,7 +88,7 @@ static int setup_hostid = -1;
* set up properly!
*/
-void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+void mac_esp_intr(int irq, void *dev_id)
{
struct NCR_ESP *esp = (struct NCR_ESP *) dev_id;
int irq_p = 0;
@@ -122,24 +122,24 @@ void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
* acknowledge on the various machines
*/
-void scsi_esp_polled(int irq, void *dev_id, struct pt_regs *pregs)
+void scsi_esp_polled(int irq, void *dev_id)
{
if (esp_initialized == 0)
return;
- mac_esp_intr(irq, dev_id, pregs);
+ mac_esp_intr(irq, dev_id);
}
-void fake_intr(int irq, void *dev_id, struct pt_regs *pregs)
+void fake_intr(int irq, void *dev_id)
{
#ifdef DEBUG_MAC_ESP
printk("mac_esp: got irq\n");
#endif
- mac_esp_intr(irq, dev_id, pregs);
+ mac_esp_intr(irq, dev_id);
}
-irqreturn_t fake_drq(int irq, void *dev_id, struct pt_regs *pregs)
+irqreturn_t fake_drq(int irq, void *dev_id)
{
printk("mac_esp: got drq\n");
return IRQ_HANDLED;
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index b87bef69ba0f..86099fde1b2a 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1256,14 +1256,13 @@ bug_blocked_mailbox:
* megaraid_isr_iomapped()
* @irq - irq
* @devp - pointer to our soft state
- * @regs - unused
*
* Interrupt service routine for io-mapped controllers.
* Find out if our device is interrupting. If yes, acknowledge the interrupt
* and service the completed commands.
*/
static irqreturn_t
-megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr_iomapped(int irq, void *devp)
{
adapter_t *adapter = devp;
unsigned long flags;
@@ -1333,14 +1332,13 @@ megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
* megaraid_isr_memmapped()
* @irq - irq
* @devp - pointer to our soft state
- * @regs - unused
*
* Interrupt service routine for memory-mapped controllers.
* Find out if our device is interrupting. If yes, acknowledge the interrupt
* and service the completed commands.
*/
static irqreturn_t
-megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr_memmapped(int irq, void *devp)
{
adapter_t *adapter = devp;
unsigned long flags;
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
index 4b75fe619d9c..66529f11d23c 100644
--- a/drivers/scsi/megaraid.h
+++ b/drivers/scsi/megaraid.h
@@ -991,8 +991,8 @@ static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *);
static void __mega_runpendq(adapter_t *);
static int issue_scb_block(adapter_t *, u_char *);
-static irqreturn_t megaraid_isr_memmapped(int, void *, struct pt_regs *);
-static irqreturn_t megaraid_isr_iomapped(int, void *, struct pt_regs *);
+static irqreturn_t megaraid_isr_memmapped(int, void *);
+static irqreturn_t megaraid_isr_iomapped(int, void *);
static void mega_free_scb(adapter_t *, scb_t *);
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
index 8cd0bd1d0f7c..b50e27e66024 100644
--- a/drivers/scsi/megaraid/mega_common.h
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -175,7 +175,7 @@ typedef struct {
uint8_t max_lun;
uint32_t unique_id;
- uint8_t irq;
+ int irq;
uint8_t ito;
caddr_t ibuf;
dma_addr_t ibuf_dma_h;
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 266b3910846b..7bac86dda88f 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -120,7 +120,7 @@ static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *,
struct scsi_cmnd *);
-static irqreturn_t megaraid_isr(int, void *, struct pt_regs *);
+static irqreturn_t megaraid_isr(int, void *);
static void megaraid_mbox_dpc(unsigned long);
@@ -884,7 +884,7 @@ megaraid_init_mbox(adapter_t *adapter)
if (((magic64 == HBA_SIGNATURE_64_BIT) &&
((adapter->pdev->subsystem_device !=
- PCI_SUBSYS_ID_MEGARAID_SATA_150_6) ||
+ PCI_SUBSYS_ID_MEGARAID_SATA_150_6) &&
(adapter->pdev->subsystem_device !=
PCI_SUBSYS_ID_MEGARAID_SATA_150_4))) ||
(adapter->pdev->vendor == PCI_VENDOR_ID_LSI_LOGIC &&
@@ -2231,7 +2231,7 @@ megaraid_ack_sequence(adapter_t *adapter)
* Interrupt service routine for memory-mapped mailbox controllers.
*/
static irqreturn_t
-megaraid_isr(int irq, void *devp, struct pt_regs *regs)
+megaraid_isr(int irq, void *devp)
{
adapter_t *adapter = devp;
int handled;
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index 4cab5b534b25..7e4262f2af96 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.03.01
+ * Version : v00.00.03.05
*
* Authors:
* Sreenivas Bagalkote <Sreenivas.Bagalkote@lsil.com>
@@ -71,6 +71,8 @@ static struct megasas_mgmt_info megasas_mgmt_info;
static struct fasync_struct *megasas_async_queue;
static DEFINE_MUTEX(megasas_async_queue_mutex);
+static u32 megasas_dbg_lvl;
+
/**
* megasas_get_cmd - Get a command from the free pool
* @instance: Adapter soft state
@@ -135,6 +137,19 @@ megasas_enable_intr_xscale(struct megasas_register_set __iomem * regs)
}
/**
+ * megasas_disable_intr_xscale -Disables interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_xscale(struct megasas_register_set __iomem * regs)
+{
+ u32 mask = 0x1f;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
* megasas_read_fw_status_reg_xscale - returns the current FW status value
* @regs: MFI register set
*/
@@ -185,6 +200,7 @@ static struct megasas_instance_template megasas_instance_template_xscale = {
.fire_cmd = megasas_fire_cmd_xscale,
.enable_intr = megasas_enable_intr_xscale,
+ .disable_intr = megasas_disable_intr_xscale,
.clear_intr = megasas_clear_intr_xscale,
.read_fw_status_reg = megasas_read_fw_status_reg_xscale,
};
@@ -215,6 +231,19 @@ megasas_enable_intr_ppc(struct megasas_register_set __iomem * regs)
}
/**
+ * megasas_disable_intr_ppc - Disable interrupt
+ * @regs: MFI register set
+ */
+static inline void
+megasas_disable_intr_ppc(struct megasas_register_set __iomem * regs)
+{
+ u32 mask = 0xFFFFFFFF;
+ writel(mask, &regs->outbound_intr_mask);
+ /* Dummy readl to force pci flush */
+ readl(&regs->outbound_intr_mask);
+}
+
+/**
* megasas_read_fw_status_reg_ppc - returns the current FW status value
* @regs: MFI register set
*/
@@ -265,6 +294,7 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
.fire_cmd = megasas_fire_cmd_ppc,
.enable_intr = megasas_enable_intr_ppc,
+ .disable_intr = megasas_disable_intr_ppc,
.clear_intr = megasas_clear_intr_ppc,
.read_fw_status_reg = megasas_read_fw_status_reg_ppc,
};
@@ -275,25 +305,6 @@ static struct megasas_instance_template megasas_instance_template_ppc = {
*/
/**
- * megasas_disable_intr - Disables interrupts
- * @regs: MFI register set
- */
-static inline void
-megasas_disable_intr(struct megasas_instance *instance)
-{
- u32 mask = 0x1f;
- struct megasas_register_set __iomem *regs = instance->reg_set;
-
- if(instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1078R)
- mask = 0xffffffff;
-
- writel(mask, &regs->outbound_intr_mask);
-
- /* Dummy readl to force pci flush */
- readl(&regs->outbound_intr_mask);
-}
-
-/**
* megasas_issue_polled - Issues a polling command
* @instance: Adapter soft state
* @cmd: Command packet to be issued
@@ -336,6 +347,7 @@ megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd)
* @cmd: Command to be issued
*
* This function waits on an event for the command to be returned from ISR.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
* Used to issue ioctl commands.
*/
static int
@@ -346,7 +358,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
instance->instancet->fire_cmd(cmd->frame_phys_addr ,0,instance->reg_set);
- wait_event(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA));
+ wait_event_timeout(instance->int_cmd_wait_q, (cmd->cmd_status != ENODATA),
+ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
return 0;
}
@@ -358,7 +371,8 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance,
*
* MFI firmware can abort previously issued AEN comamnd (automatic event
* notification). The megasas_issue_blocked_abort_cmd() issues such abort
- * cmd and blocks till it is completed.
+ * cmd and waits for return status.
+ * Max wait time is MEGASAS_INTERNAL_CMD_WAIT_TIME secs
*/
static int
megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
@@ -392,7 +406,8 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
/*
* Wait for this cmd to complete
*/
- wait_event(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF));
+ wait_event_timeout(instance->abort_cmd_wait_q, (cmd->cmd_status != 0xFF),
+ MEGASAS_INTERNAL_CMD_WAIT_TIME*HZ);
megasas_return_cmd(instance, cmd);
return 0;
@@ -495,6 +510,46 @@ megasas_make_sgl64(struct megasas_instance *instance, struct scsi_cmnd *scp,
return sge_count;
}
+ /**
+ * megasas_get_frame_count - Computes the number of frames
+ * @sge_count : number of sg elements
+ *
+ * Returns the number of frames required for numnber of sge's (sge_count)
+ */
+
+u32 megasas_get_frame_count(u8 sge_count)
+{
+ int num_cnt;
+ int sge_bytes;
+ u32 sge_sz;
+ u32 frame_count=0;
+
+ sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
+ sizeof(struct megasas_sge32);
+
+ /*
+ * Main frame can contain 2 SGEs for 64-bit SGLs and
+ * 3 SGEs for 32-bit SGLs
+ */
+ if (IS_DMA64)
+ num_cnt = sge_count - 2;
+ else
+ num_cnt = sge_count - 3;
+
+ if(num_cnt>0){
+ sge_bytes = sge_sz * num_cnt;
+
+ frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
+ ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ;
+ }
+ /* Main frame */
+ frame_count +=1;
+
+ if (frame_count > 7)
+ frame_count = 8;
+ return frame_count;
+}
+
/**
* megasas_build_dcdb - Prepares a direct cdb (DCDB) command
* @instance: Adapter soft state
@@ -508,8 +563,6 @@ static int
megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
struct megasas_cmd *cmd)
{
- u32 sge_sz;
- int sge_bytes;
u32 is_logical;
u32 device_id;
u16 flags = 0;
@@ -544,9 +597,6 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
if (IS_DMA64) {
pthru->flags |= MFI_FRAME_SGL64;
pthru->sge_count = megasas_make_sgl64(instance, scp,
@@ -562,17 +612,11 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp,
pthru->sense_buf_phys_addr_hi = 0;
pthru->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
- sge_bytes = sge_sz * pthru->sge_count;
-
/*
* Compute the total number of frames this command consumes. FW uses
* this number to pull sufficient number of frames from host memory.
*/
- cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
- if (cmd->frame_count > 7)
- cmd->frame_count = 8;
+ cmd->frame_count = megasas_get_frame_count(pthru->sge_count);
return cmd->frame_count;
}
@@ -589,8 +633,6 @@ static int
megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
struct megasas_cmd *cmd)
{
- u32 sge_sz;
- int sge_bytes;
u32 device_id;
u8 sc = scp->cmnd[0];
u16 flags = 0;
@@ -605,7 +647,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
flags = MFI_FRAME_DIR_READ;
/*
- * Preare the Logical IO frame: 2nd bit is zero for all read cmds
+ * Prepare the Logical IO frame: 2nd bit is zero for all read cmds
*/
ldio->cmd = (sc & 0x02) ? MFI_CMD_LD_WRITE : MFI_CMD_LD_READ;
ldio->cmd_status = 0x0;
@@ -674,9 +716,6 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
/*
* Construct SGL
*/
- sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) :
- sizeof(struct megasas_sge32);
-
if (IS_DMA64) {
ldio->flags |= MFI_FRAME_SGL64;
ldio->sge_count = megasas_make_sgl64(instance, scp, &ldio->sgl);
@@ -690,13 +729,11 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
ldio->sense_buf_phys_addr_hi = 0;
ldio->sense_buf_phys_addr_lo = cmd->sense_phys_addr;
- sge_bytes = sge_sz * ldio->sge_count;
-
- cmd->frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) +
- ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) + 1;
-
- if (cmd->frame_count > 7)
- cmd->frame_count = 8;
+ /*
+ * Compute the total number of frames this command consumes. FW uses
+ * this number to pull sufficient number of frames from host memory.
+ */
+ cmd->frame_count = megasas_get_frame_count(ldio->sge_count);
return cmd->frame_count;
}
@@ -727,6 +764,69 @@ static inline int megasas_is_ldio(struct scsi_cmnd *cmd)
}
}
+ /**
+ * megasas_dump_pending_frames - Dumps the frame address of all pending cmds
+ * in FW
+ * @instance: Adapter soft state
+ */
+static inline void
+megasas_dump_pending_frames(struct megasas_instance *instance)
+{
+ struct megasas_cmd *cmd;
+ int i,n;
+ union megasas_sgl *mfi_sgl;
+ struct megasas_io_frame *ldio;
+ struct megasas_pthru_frame *pthru;
+ u32 sgcount;
+ u32 max_cmd = instance->max_fw_cmds;
+
+ printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no);
+ printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding));
+ if (IS_DMA64)
+ printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no);
+ else
+ printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no);
+
+ printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no);
+ for (i = 0; i < max_cmd; i++) {
+ cmd = instance->cmd_list[i];
+ if(!cmd->scmd)
+ continue;
+ printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
+ if (megasas_is_ldio(cmd->scmd)){
+ ldio = (struct megasas_io_frame *)cmd->frame;
+ mfi_sgl = &ldio->sgl;
+ sgcount = ldio->sge_count;
+ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no, cmd->frame_count,ldio->cmd,ldio->target_id, ldio->start_lba_lo,ldio->start_lba_hi,ldio->sense_buf_phys_addr_lo,sgcount);
+ }
+ else {
+ pthru = (struct megasas_pthru_frame *) cmd->frame;
+ mfi_sgl = &pthru->sgl;
+ sgcount = pthru->sge_count;
+ printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n",instance->host->host_no,cmd->frame_count,pthru->cmd,pthru->target_id,pthru->lun,pthru->cdb_len , pthru->data_xfer_len,pthru->sense_buf_phys_addr_lo,sgcount);
+ }
+ if(megasas_dbg_lvl & MEGASAS_DBG_LVL){
+ for (n = 0; n < sgcount; n++){
+ if (IS_DMA64)
+ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%08lx ",mfi_sgl->sge64[n].length , (unsigned long)mfi_sgl->sge64[n].phys_addr) ;
+ else
+ printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ",mfi_sgl->sge32[n].length , mfi_sgl->sge32[n].phys_addr) ;
+ }
+ }
+ printk(KERN_ERR "\n");
+ } /*for max_cmd*/
+ printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no);
+ for (i = 0; i < max_cmd; i++) {
+
+ cmd = instance->cmd_list[i];
+
+ if(cmd->sync_cmd == 1){
+ printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr);
+ }
+ }
+ printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no);
+}
+
/**
* megasas_queue_command - Queue entry point
* @scmd: SCSI command to be queued
@@ -832,6 +932,13 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
}
if (atomic_read(&instance->fw_outstanding)) {
+ /*
+ * Send signal to FW to stop processing any pending cmds.
+ * The controller will be taken offline by the OS now.
+ */
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->inbound_doorbell);
+ megasas_dump_pending_frames(instance);
instance->hw_crit_error = 1;
return FAILED;
}
@@ -1168,11 +1275,6 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
static int
megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
{
- u32 producer;
- u32 consumer;
- u32 context;
- struct megasas_cmd *cmd;
-
/*
* Check if it is our interrupt
* Clear the interrupt
@@ -1180,23 +1282,10 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
if(instance->instancet->clear_intr(instance->reg_set))
return IRQ_NONE;
- producer = *instance->producer;
- consumer = *instance->consumer;
-
- while (consumer != producer) {
- context = instance->reply_queue[consumer];
-
- cmd = instance->cmd_list[context];
-
- megasas_complete_cmd(instance, cmd, alt_status);
-
- consumer++;
- if (consumer == (instance->max_fw_cmds + 1)) {
- consumer = 0;
- }
- }
-
- *instance->consumer = producer;
+ /*
+ * Schedule the tasklet for cmd completion
+ */
+ tasklet_schedule(&instance->isr_tasklet);
return IRQ_HANDLED;
}
@@ -1204,7 +1293,7 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, u8 alt_status)
/**
* megasas_isr - isr entry point
*/
-static irqreturn_t megasas_isr(int irq, void *devp, struct pt_regs *regs)
+static irqreturn_t megasas_isr(int irq, void *devp)
{
return megasas_deplete_reply_queue((struct megasas_instance *)devp,
DID_OK);
@@ -1229,10 +1318,12 @@ megasas_transition_to_ready(struct megasas_instance* instance)
fw_state = instance->instancet->read_fw_status_reg(instance->reg_set) & MFI_STATE_MASK;
+ if (fw_state != MFI_STATE_READY)
+ printk(KERN_INFO "megasas: Waiting for FW to come to ready"
+ " state\n");
+
while (fw_state != MFI_STATE_READY) {
- printk(KERN_INFO "megasas: Waiting for FW to come to ready"
- " state\n");
switch (fw_state) {
case MFI_STATE_FAULT:
@@ -1244,19 +1335,27 @@ megasas_transition_to_ready(struct megasas_instance* instance)
/*
* Set the CLR bit in inbound doorbell
*/
- writel(MFI_INIT_CLEAR_HANDSHAKE,
+ writel(MFI_INIT_CLEAR_HANDSHAKE|MFI_INIT_HOTPLUG,
&instance->reg_set->inbound_doorbell);
max_wait = 2;
cur_state = MFI_STATE_WAIT_HANDSHAKE;
break;
+ case MFI_STATE_BOOT_MESSAGE_PENDING:
+ writel(MFI_INIT_HOTPLUG,
+ &instance->reg_set->inbound_doorbell);
+
+ max_wait = 10;
+ cur_state = MFI_STATE_BOOT_MESSAGE_PENDING;
+ break;
+
case MFI_STATE_OPERATIONAL:
/*
- * Bring it to READY state; assuming max wait 2 secs
+ * Bring it to READY state; assuming max wait 10 secs
*/
- megasas_disable_intr(instance);
- writel(MFI_INIT_READY, &instance->reg_set->inbound_doorbell);
+ instance->instancet->disable_intr(instance->reg_set);
+ writel(MFI_RESET_FLAGS, &instance->reg_set->inbound_doorbell);
max_wait = 10;
cur_state = MFI_STATE_OPERATIONAL;
@@ -1323,6 +1422,7 @@ megasas_transition_to_ready(struct megasas_instance* instance)
return -ENODEV;
}
};
+ printk(KERN_INFO "megasas: FW now in Ready state\n");
return 0;
}
@@ -1352,7 +1452,7 @@ static void megasas_teardown_frame_pool(struct megasas_instance *instance)
cmd->frame_phys_addr);
if (cmd->sense)
- pci_pool_free(instance->sense_dma_pool, cmd->frame,
+ pci_pool_free(instance->sense_dma_pool, cmd->sense,
cmd->sense_phys_addr);
}
@@ -1628,6 +1728,39 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
}
/**
+ * megasas_complete_cmd_dpc - Returns FW's controller structure
+ * @instance_addr: Address of adapter soft state
+ *
+ * Tasklet to complete cmds
+ */
+void megasas_complete_cmd_dpc(unsigned long instance_addr)
+{
+ u32 producer;
+ u32 consumer;
+ u32 context;
+ struct megasas_cmd *cmd;
+ struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
+
+ producer = *instance->producer;
+ consumer = *instance->consumer;
+
+ while (consumer != producer) {
+ context = instance->reply_queue[consumer];
+
+ cmd = instance->cmd_list[context];
+
+ megasas_complete_cmd(instance, cmd, DID_OK);
+
+ consumer++;
+ if (consumer == (instance->max_fw_cmds + 1)) {
+ consumer = 0;
+ }
+ }
+
+ *instance->consumer = producer;
+}
+
+/**
* megasas_init_mfi - Initializes the FW
* @instance: Adapter soft state
*
@@ -1690,6 +1823,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
* Get various operational parameters from status register
*/
instance->max_fw_cmds = instance->instancet->read_fw_status_reg(reg_set) & 0x00FFFF;
+ /*
+ * Reduce the max supported cmds by 1. This is to ensure that the
+ * reply_q_sz (1 more than the max cmd that driver may send)
+ * does not exceed max cmds that the FW can support
+ */
+ instance->max_fw_cmds = instance->max_fw_cmds-1;
instance->max_num_sge = (instance->instancet->read_fw_status_reg(reg_set) & 0xFF0000) >>
0x10;
/*
@@ -1754,7 +1893,7 @@ static int megasas_init_mfi(struct megasas_instance *instance)
/*
* disable the intr before firing the init frame to FW
*/
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
/*
* Issue the init frame in polled mode
@@ -1791,6 +1930,12 @@ static int megasas_init_mfi(struct megasas_instance *instance)
kfree(ctrl_info);
+ /*
+ * Setup tasklet for cmd completion
+ */
+
+ tasklet_init(&instance->isr_tasklet, megasas_complete_cmd_dpc,
+ (unsigned long)instance);
return 0;
fail_fw_init:
@@ -2182,6 +2327,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->unique_id = pdev->bus->number << 8 | pdev->devfn;
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
+ megasas_dbg_lvl = 0;
+
/*
* Initialize MFI Firmware
*/
@@ -2234,7 +2381,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
megasas_mgmt_info.max_index--;
pci_set_drvdata(pdev, NULL);
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
free_irq(instance->pdev->irq, instance);
megasas_release_mfi(instance);
@@ -2348,6 +2495,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
scsi_remove_host(instance->host);
megasas_flush_cache(instance);
megasas_shutdown_controller(instance);
+ tasklet_kill(&instance->isr_tasklet);
/*
* Take the instance off the instance array. Note that we will not
@@ -2364,7 +2512,7 @@ static void megasas_detach_one(struct pci_dev *pdev)
pci_set_drvdata(instance->pdev, NULL);
- megasas_disable_intr(instance);
+ instance->instancet->disable_intr(instance->reg_set);
free_irq(instance->pdev->irq, instance);
@@ -2716,7 +2864,8 @@ static int megasas_mgmt_compat_ioctl_fw(struct file *file, unsigned long arg)
int i;
int error = 0;
- clear_user(ioc, sizeof(*ioc));
+ if (clear_user(ioc, sizeof(*ioc)))
+ return -EFAULT;
if (copy_in_user(&ioc->host_no, &cioc->host_no, sizeof(u16)) ||
copy_in_user(&ioc->sgl_off, &cioc->sgl_off, sizeof(u32)) ||
@@ -2808,6 +2957,26 @@ megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
NULL);
+static ssize_t
+megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf,"%u",megasas_dbg_lvl);
+}
+
+static ssize_t
+megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count)
+{
+ int retval = count;
+ if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){
+ printk(KERN_ERR "megasas: could not set dbg_lvl\n");
+ retval = -EINVAL;
+ }
+ return retval;
+}
+
+static DRIVER_ATTR(dbg_lvl, S_IRUGO|S_IWUGO, megasas_sysfs_show_dbg_lvl,
+ megasas_sysfs_set_dbg_lvl);
+
/**
* megasas_init - Driver load entry point
*/
@@ -2842,14 +3011,33 @@ static int __init megasas_init(void)
if (rval) {
printk(KERN_DEBUG "megasas: PCI hotplug regisration failed \n");
- unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
- }
-
- driver_create_file(&megasas_pci_driver.driver, &driver_attr_version);
- driver_create_file(&megasas_pci_driver.driver,
- &driver_attr_release_date);
+ goto err_pcidrv;
+ }
+
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_version);
+ if (rval)
+ goto err_dcf_attr_ver;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_release_date);
+ if (rval)
+ goto err_dcf_rel_date;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
+ if (rval)
+ goto err_dcf_dbg_lvl;
return rval;
+err_dcf_dbg_lvl:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_release_date);
+err_dcf_rel_date:
+ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+err_dcf_attr_ver:
+ pci_unregister_driver(&megasas_pci_driver);
+err_pcidrv:
+ unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
+ return rval;
}
/**
@@ -2857,9 +3045,11 @@ static int __init megasas_init(void)
*/
static void __exit megasas_exit(void)
{
- driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_dbg_lvl);
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_release_date);
+ driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
pci_unregister_driver(&megasas_pci_driver);
unregister_chrdev(megasas_mgmt_majorno, "megaraid_sas_ioctl");
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 3531a14222a7..55eddcf8eb15 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -18,9 +18,9 @@
/**
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "00.00.03.01"
-#define MEGASAS_RELDATE "May 14, 2006"
-#define MEGASAS_EXT_VERSION "Sun May 14 22:49:52 PDT 2006"
+#define MEGASAS_VERSION "00.00.03.05"
+#define MEGASAS_RELDATE "Oct 02, 2006"
+#define MEGASAS_EXT_VERSION "Mon Oct 02 11:21:32 PDT 2006"
/*
* Device IDs
@@ -50,6 +50,7 @@
#define MFI_STATE_WAIT_HANDSHAKE 0x60000000
#define MFI_STATE_FW_INIT_2 0x70000000
#define MFI_STATE_DEVICE_SCAN 0x80000000
+#define MFI_STATE_BOOT_MESSAGE_PENDING 0x90000000
#define MFI_STATE_FLUSH_CACHE 0xA0000000
#define MFI_STATE_READY 0xB0000000
#define MFI_STATE_OPERATIONAL 0xC0000000
@@ -64,12 +65,18 @@
* READY : Move from OPERATIONAL to READY state; discard queue info
* MFIMODE : Discard (possible) low MFA posted in 64-bit mode (??)
* CLR_HANDSHAKE: FW is waiting for HANDSHAKE from BIOS or Driver
+ * HOTPLUG : Resume from Hotplug
+ * MFI_STOP_ADP : Send signal to FW to stop processing
*/
-#define MFI_INIT_ABORT 0x00000000
+#define MFI_INIT_ABORT 0x00000001
#define MFI_INIT_READY 0x00000002
#define MFI_INIT_MFIMODE 0x00000004
#define MFI_INIT_CLEAR_HANDSHAKE 0x00000008
-#define MFI_RESET_FLAGS MFI_INIT_READY|MFI_INIT_MFIMODE
+#define MFI_INIT_HOTPLUG 0x00000010
+#define MFI_STOP_ADP 0x00000020
+#define MFI_RESET_FLAGS MFI_INIT_READY| \
+ MFI_INIT_MFIMODE| \
+ MFI_INIT_ABORT
/**
* MFI frame flags
@@ -530,6 +537,8 @@ struct megasas_ctrl_info {
#define MEGASAS_MAX_LUN 8
#define MEGASAS_MAX_LD 64
+#define MEGASAS_DBG_LVL 1
+
/*
* When SCSI mid-layer calls driver's reset routine, driver waits for
* MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
@@ -538,6 +547,7 @@ struct megasas_ctrl_info {
* every MEGASAS_RESET_NOTICE_INTERVAL seconds
*/
#define MEGASAS_RESET_WAIT_TIME 180
+#define MEGASAS_INTERNAL_CMD_WAIT_TIME 180
#define MEGASAS_RESET_NOTICE_INTERVAL 5
#define MEGASAS_IOCTL_CMD 0
@@ -1042,6 +1052,7 @@ struct megasas_evt_detail {
void (*fire_cmd)(dma_addr_t ,u32 ,struct megasas_register_set __iomem *);
void (*enable_intr)(struct megasas_register_set __iomem *) ;
+ void (*disable_intr)(struct megasas_register_set __iomem *);
int (*clear_intr)(struct megasas_register_set __iomem *);
@@ -1092,6 +1103,7 @@ struct megasas_instance {
u32 hw_crit_error;
struct megasas_instance_template *instancet;
+ struct tasklet_struct isr_tasklet;
};
#define MEGASAS_IS_LOGICAL(scp) \
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index 683fc7ae4b8f..1fd3c7590d31 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -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, struct pt_regs *ptregs);
+static void mesh_interrupt(int irq, void *dev_id);
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, NULL);
+ mesh_interrupt(0, (void *)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, NULL);
+ mesh_interrupt(0, (void *)ms);
if (ms->phase != arbitrating)
return;
dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
@@ -1015,13 +1015,13 @@ static void handle_reset(struct mesh_state *ms)
out_8(&mr->sequence, SEQ_ENBRESEL);
}
-static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t do_mesh_interrupt(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
spin_lock_irqsave(dev->host_lock, flags);
- mesh_interrupt(irq, dev_id, ptregs);
+ mesh_interrupt(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
@@ -1661,7 +1661,7 @@ 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, struct pt_regs *ptregs)
+static void mesh_interrupt(int irq, void *dev_id)
{
struct mesh_state *ms = (struct mesh_state *) dev_id;
volatile struct mesh_regs __iomem *mr = ms->mesh;
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
index 9b991b746d1e..1ddd7a11a958 100644
--- a/drivers/scsi/mvme147.c
+++ b/drivers/scsi/mvme147.c
@@ -20,7 +20,7 @@
static struct Scsi_Host *mvme147_host = NULL;
-static irqreturn_t mvme147_intr (int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t mvme147_intr (int irq, void *dummy)
{
if (irq == MVME147_IRQ_SCSI_PORT)
wd33c93_intr (mvme147_host);
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
index c7a12533fb2c..73e33b37a3f8 100644
--- a/drivers/scsi/mvme16x.h
+++ b/drivers/scsi/mvme16x.h
@@ -9,7 +9,7 @@ int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int NCR53c7xx_abort(Scsi_Cmnd *);
int NCR53c7x0_release (struct Scsi_Host *);
int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
-void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+void NCR53c7x0_intr(int irq, void *dev_id);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 3
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index b28712df0b77..6cc2bc2f62be 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -8111,7 +8111,7 @@ printk("ncr53c8xx : command successfully queued\n");
return sts;
}
-irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t ncr53c8xx_intr(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *shost = (struct Scsi_Host *)dev_id;
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 78818b6684f8..cb8b7701431e 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -1322,7 +1322,7 @@ struct ncr_device {
extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device);
extern int ncr53c8xx_release(struct Scsi_Host *host);
-irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+irqreturn_t ncr53c8xx_intr(int irq, void *dev_id);
extern int ncr53c8xx_init(void);
extern void ncr53c8xx_exit(void);
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index bfb4f49e125d..7c13f6f4a4c6 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -256,7 +256,7 @@ static void nsp32_sack_negate (nsp32_hw_data *);
static void nsp32_do_bus_reset(nsp32_hw_data *);
/* hardware interrupt handler */
-static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *);
+static irqreturn_t do_nsp32_isr(int, void *);
/* initialize hardware */
static int nsp32hw_init(nsp32_hw_data *);
@@ -1201,7 +1201,7 @@ static int nsp32hw_init(nsp32_hw_data *data)
/* interrupt routine */
-static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
{
nsp32_hw_data *data = dev_id;
unsigned int base = data->BaseAddress;
@@ -3581,7 +3581,7 @@ static struct pci_driver nsp32_driver = {
*/
static int __init init_nsp32(void) {
nsp32_msg(KERN_INFO, "loading...");
- return pci_module_init(&nsp32_driver);
+ return pci_register_driver(&nsp32_driver);
}
static void __exit exit_nsp32(void) {
diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
index 5addf9fb1e15..a976e8193d16 100644
--- a/drivers/scsi/nsp32.h
+++ b/drivers/scsi/nsp32.h
@@ -619,47 +619,5 @@ typedef struct _nsp32_hw_data {
#define REQSACK_TIMEOUT_TIME 10000 /* max wait time for REQ/SACK assertion
or negation, 10000us == 10ms */
-/**************************************************************************
- * Compatibility functions
- */
-
-/* for Kernel 2.4 */
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
-# define scsi_register_host(template) scsi_register_module(MODULE_SCSI_HA, template)
-# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
-# define scsi_host_put(host) scsi_unregister(host)
-# define pci_name(pci_dev) ((pci_dev)->slot_name)
-
-typedef void irqreturn_t;
-# define IRQ_NONE /* */
-# define IRQ_HANDLED /* */
-# define IRQ_RETVAL(x) /* */
-
-/* This is ad-hoc version of scsi_host_get_next() */
-static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host)
-{
- if (host == NULL) {
- return scsi_hostlist;
- } else {
- return host->next;
- }
-}
-
-/* This is ad-hoc version of scsi_host_hn_get() */
-static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno)
-{
- struct Scsi_Host *host;
-
- for (host = scsi_host_get_next(NULL); host != NULL;
- host = scsi_host_get_next(host)) {
- if (host->host_no == hostno) {
- break;
- }
- }
-
- return host;
-}
-#endif
-
#endif /* _NSP32_H */
/* end */
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index 4a2fed350d4e..824fe080d1dc 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -4843,8 +4843,7 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp)
static int osst_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
{
- int i, cmd_nr, cmd_type, retval = 0;
- unsigned int blk;
+ int i, cmd_nr, cmd_type, blk, retval = 0;
struct st_modedef * STm;
struct st_partstat * STps;
struct osst_request * SRpnt = NULL;
@@ -5207,12 +5206,12 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d
priority = GFP_KERNEL;
i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
- tb = (struct osst_buffer *)kmalloc(i, priority);
+ tb = kzalloc(i, priority);
if (!tb) {
printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
return NULL;
}
- memset(tb, 0, i);
+
tb->sg_segs = tb->orig_sg_segs = 0;
tb->use_sg = max_sg;
tb->in_use = 1;
@@ -5575,9 +5574,9 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
-static void osst_create_driverfs_files(struct device_driver *driverfs)
+static int osst_create_driverfs_files(struct device_driver *driverfs)
{
- driver_create_file(driverfs, &driver_attr_version);
+ return driver_create_file(driverfs, &driver_attr_version);
}
static void osst_remove_driverfs_files(struct device_driver *driverfs)
@@ -5663,50 +5662,70 @@ CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
static struct class *osst_sysfs_class;
-static int osst_sysfs_valid = 0;
-
-static void osst_sysfs_init(void)
+static int osst_sysfs_init(void)
{
osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape");
- if ( IS_ERR(osst_sysfs_class) )
- printk(KERN_WARNING "osst :W: Unable to register sysfs class\n");
- else
- osst_sysfs_valid = 1;
+ if (IS_ERR(osst_sysfs_class)) {
+ printk(KERN_ERR "osst :W: Unable to register sysfs class\n");
+ return PTR_ERR(osst_sysfs_class);
+ }
+
+ return 0;
}
-static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
+static void osst_sysfs_destroy(dev_t dev)
{
- struct class_device *osst_class_member;
+ class_device_destroy(osst_sysfs_class, dev);
+}
- if (!osst_sysfs_valid) return;
+static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
+{
+ struct class_device *osst_class_member;
+ int err;
- osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name);
+ osst_class_member = class_device_create(osst_sysfs_class, NULL, dev,
+ device, "%s", name);
if (IS_ERR(osst_class_member)) {
printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
- return;
+ return PTR_ERR(osst_class_member);
}
+
class_set_devdata(osst_class_member, STp);
- class_device_create_file(osst_class_member, &class_device_attr_ADR_rev);
- class_device_create_file(osst_class_member, &class_device_attr_media_version);
- class_device_create_file(osst_class_member, &class_device_attr_capacity);
- class_device_create_file(osst_class_member, &class_device_attr_BOT_frame);
- class_device_create_file(osst_class_member, &class_device_attr_EOD_frame);
- class_device_create_file(osst_class_member, &class_device_attr_file_count);
-}
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_ADR_rev);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_media_version);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_capacity);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_BOT_frame);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_EOD_frame);
+ if (err)
+ goto err_out;
+ err = class_device_create_file(osst_class_member,
+ &class_device_attr_file_count);
+ if (err)
+ goto err_out;
-static void osst_sysfs_destroy(dev_t dev)
-{
- if (!osst_sysfs_valid) return;
+ return 0;
- class_device_destroy(osst_sysfs_class, dev);
+err_out:
+ osst_sysfs_destroy(dev);
+ return err;
}
static void osst_sysfs_cleanup(void)
{
- if (osst_sysfs_valid) {
- class_destroy(osst_sysfs_class);
- osst_sysfs_valid = 0;
- }
+ class_destroy(osst_sysfs_class);
}
/*
@@ -5721,7 +5740,7 @@ static int osst_probe(struct device *dev)
struct st_partstat * STps;
struct osst_buffer * buffer;
struct gendisk * drive;
- int i, dev_num;
+ int i, dev_num, err = -ENODEV;
if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
return -ENODEV;
@@ -5849,13 +5868,20 @@ static int osst_probe(struct device *dev)
init_MUTEX(&tpnt->lock);
osst_nr_dev++;
write_unlock(&os_scsi_tapes_lock);
+
{
char name[8];
+
/* Rewind entry */
- osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
+ err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
+ if (err)
+ goto out_free_buffer;
+
/* No-rewind entry */
snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
- osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
+ err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
+ if (err)
+ goto out_free_sysfs1;
}
sdev_printk(KERN_INFO, SDp,
@@ -5864,9 +5890,13 @@ static int osst_probe(struct device *dev)
return 0;
+out_free_sysfs1:
+ osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num));
+out_free_buffer:
+ kfree(buffer);
out_put_disk:
put_disk(drive);
- return -ENODEV;
+ return err;
};
static int osst_remove(struct device *dev)
@@ -5903,19 +5933,39 @@ static int osst_remove(struct device *dev)
static int __init init_osst(void)
{
+ int err;
+
printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
validate_options();
- osst_sysfs_init();
- if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
+ err = osst_sysfs_init();
+ if (err)
+ return err;
+
+ err = register_chrdev(OSST_MAJOR, "osst", &osst_fops);
+ if (err < 0) {
printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
- osst_sysfs_cleanup();
- return 1;
+ goto err_out;
}
- osst_create_driverfs_files(&osst_template.gendrv);
+
+ err = scsi_register_driver(&osst_template.gendrv);
+ if (err)
+ goto err_out_chrdev;
+
+ err = osst_create_driverfs_files(&osst_template.gendrv);
+ if (err)
+ goto err_out_scsidrv;
return 0;
+
+err_out_scsidrv:
+ scsi_unregister_driver(&osst_template.gendrv);
+err_out_chrdev:
+ unregister_chrdev(OSST_MAJOR, "osst");
+err_out:
+ osst_sysfs_cleanup();
+ return err;
}
static void __exit exit_osst (void)
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 0d4c04e1f3de..b1d346049525 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -80,7 +80,6 @@ static int free_ports = 0;
module_param(free_ports, bool, 0);
MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
-/* /usr/src/linux/drivers/scsi/hosts.h */
static struct scsi_host_template nsp_driver_template = {
.proc_name = "nsp_cs",
.proc_info = nsp_proc_info,
@@ -949,7 +948,7 @@ static int nsp_nexus(Scsi_Cmnd *SCpnt)
/*
* interrupt handler
*/
-static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t nspintr(int irq, void *dev_id)
{
unsigned int base;
unsigned char irq_status, irq_phase, phase;
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
index 8908b8e5b78a..a88714f4c05b 100644
--- a/drivers/scsi/pcmcia/nsp_cs.h
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -346,7 +346,7 @@ static int nsp_reselected (Scsi_Cmnd *SCpnt);
static struct Scsi_Host *nsp_detect(struct scsi_host_template *sht);
/* Interrupt handler */
-//static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs);
+//static irqreturn_t nspintr(int irq, void *dev_id);
/* Module entry point*/
static int __init nsp_cs_init(void);
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 0b65099acb1a..72fe5d055de1 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -363,7 +363,7 @@ SYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int
}
static irqreturn_t
-SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs)
+SYM53C500_intr(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index 0bd9c60e6455..aa60a5f1fbc3 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -67,7 +67,6 @@ static void __init pluto_detect_done(Scsi_Cmnd *SCpnt)
static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
{
- SCpnt->request->rq_status = RQ_SCSI_DONE;
PLND(("Detect done %08lx\n", (long)SCpnt))
if (atomic_dec_and_test (&fcss))
up(&fc_sem);
@@ -166,7 +165,7 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
- SCpnt->request->rq_status = RQ_SCSI_BUSY;
+ SCpnt->request->cmd_flags &= ~REQ_STARTED;
SCpnt->done = pluto_detect_done;
SCpnt->request_bufflen = 256;
@@ -178,7 +177,8 @@ int __init pluto_detect(struct scsi_host_template *tpnt)
for (retry = 0; retry < 5; retry++) {
for (i = 0; i < fcscount; i++) {
if (!fcs[i].fc) break;
- if (fcs[i].cmd.request->rq_status != RQ_SCSI_DONE) {
+ if (!(fcs[i].cmd.request->cmd_flags & REQ_STARTED)) {
+ fcs[i].cmd.request->cmd_flags |= REQ_STARTED;
disable_irq(fcs[i].fc->irq);
PLND(("queuecommand %d %d\n", retry, i))
fcp_scsi_queuecommand (&(fcs[i].cmd),
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index 7511df3588e4..ba8021427b88 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -73,7 +73,6 @@
*/
/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
-#include <linux/config.h>
#include <linux/stddef.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
index 5c2cdf523c3b..a720c9265e66 100644
--- a/drivers/scsi/psi240i.c
+++ b/drivers/scsi/psi240i.c
@@ -247,12 +247,11 @@ static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
*
* Parameters: irq - Hardware IRQ number.
* dev_id -
- * regs -
*
* Returns: TRUE if drive is not ready in time.
*
****************************************************************/
-static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+static void Irq_Handler (int irq, void *dev_id)
{
struct Scsi_Host *shost; // Pointer to host data block
PADAPTER240I padapter; // Pointer to adapter control structure
@@ -368,13 +367,13 @@ irqerror:;
SCpnt->scsi_done (SCpnt);
}
-static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_Irq_Handler (int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave(dev->host_lock, flags);
- Irq_Handler(irq, dev_id, regs);
+ Irq_Handler(irq, dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 8953991462d7..2521d548dd59 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -813,7 +813,7 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
uint16_t data;
unsigned char *handle;
int result, i;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
struct timer_list timer;
ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata);
@@ -1113,7 +1113,7 @@ qla1280_enable_intrs(struct scsi_qla_host *ha)
* Handles the H/W interrupt
**************************************************************************/
static irqreturn_t
-qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla1280_intr_handler(int irq, void *dev_id)
{
struct scsi_qla_host *ha;
struct device_reg __iomem *reg;
@@ -2406,7 +2406,7 @@ qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
uint16_t *optr, *iptr;
uint16_t __iomem *mptr;
uint16_t data;
- DECLARE_COMPLETION(wait);
+ DECLARE_COMPLETION_ONSTACK(wait);
struct timer_list timer;
ENTER("qla1280_mailbox_command");
@@ -2862,7 +2862,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
/* Set ISP command timeout. */
- pkt->timeout = cpu_to_le16(30);
+ pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
/* Set device target ID and LUN */
pkt->lun = SCSI_LUN_32(cmd);
@@ -3161,7 +3161,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
/* Set ISP command timeout. */
- pkt->timeout = cpu_to_le16(30);
+ pkt->timeout = cpu_to_le16(cmd->timeout_per_command/HZ);
/* Set device target ID and LUN */
pkt->lun = SCSI_LUN_32(cmd);
@@ -4484,7 +4484,7 @@ qla1280_init(void)
qla1280_setup(qla1280);
#endif
- return pci_module_init(&qla1280_pci_driver);
+ return pci_register_driver(&qla1280_pci_driver);
}
static void __exit
diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c
index 87f90c4f08e9..ee75a71f3c66 100644
--- a/drivers/scsi/qla2xxx/qla_attr.c
+++ b/drivers/scsi/qla2xxx/qla_attr.c
@@ -691,13 +691,13 @@ qla2x00_get_host_speed(struct Scsi_Host *shost)
uint32_t speed = 0;
switch (ha->link_data_rate) {
- case LDR_1GB:
+ case PORT_SPEED_1GB:
speed = 1;
break;
- case LDR_2GB:
+ case PORT_SPEED_2GB:
speed = 2;
break;
- case LDR_4GB:
+ case PORT_SPEED_4GB:
speed = 4;
break;
}
@@ -849,6 +849,49 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
return pfc_host_stat;
}
+static void
+qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+
+ qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
+}
+
+static void
+qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+
+ set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
+}
+
+static void
+qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+ u64 node_name;
+
+ if (ha->device_flags & SWITCH_FOUND)
+ node_name = wwn_to_u64(ha->fabric_node_name);
+ else
+ node_name = wwn_to_u64(ha->node_name);
+
+ fc_host_fabric_name(shost) = node_name;
+}
+
+static void
+qla2x00_get_host_port_state(struct Scsi_Host *shost)
+{
+ scsi_qla_host_t *ha = to_qla_host(shost);
+
+ if (!ha->flags.online)
+ fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
+ else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT)
+ fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+ else
+ fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
+}
+
struct fc_function_template qla2xxx_transport_functions = {
.show_host_node_name = 1,
@@ -861,6 +904,14 @@ struct fc_function_template qla2xxx_transport_functions = {
.show_host_speed = 1,
.get_host_port_type = qla2x00_get_host_port_type,
.show_host_port_type = 1,
+ .get_host_symbolic_name = qla2x00_get_host_symbolic_name,
+ .show_host_symbolic_name = 1,
+ .set_host_system_hostname = qla2x00_set_host_system_hostname,
+ .show_host_system_hostname = 1,
+ .get_host_fabric_name = qla2x00_get_host_fabric_name,
+ .show_host_fabric_name = 1,
+ .get_host_port_state = qla2x00_get_host_port_state,
+ .show_host_port_state = 1,
.dd_fcrport_size = sizeof(struct fc_port *),
.show_rport_supported_classes = 1,
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
index 533425338e05..90dad7e88985 100644
--- a/drivers/scsi/qla2xxx/qla_dbg.h
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -38,7 +38,7 @@
* Macros use for debugging the driver.
*/
-#define DEBUG(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG(x) do { if (qla2_extended_error_logging) { x; } } while (0)
#if defined(QL_DEBUG_LEVEL_1)
#define DEBUG1(x) do {x;} while (0)
@@ -46,12 +46,12 @@
#define DEBUG1(x) do {} while (0)
#endif
-#define DEBUG2(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_3(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_3_11(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_9_10(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_11(x) do { if (extended_error_logging) { x; } } while (0)
-#define DEBUG2_13(x) do { if (extended_error_logging) { x; } } while (0)
+#define DEBUG2(x) do { if (qla2_extended_error_logging) { x; } } while (0)
+#define DEBUG2_3(x) do { if (qla2_extended_error_logging) { x; } } while (0)
+#define DEBUG2_3_11(x) do { if (qla2_extended_error_logging) { x; } } while (0)
+#define DEBUG2_9_10(x) do { if (qla2_extended_error_logging) { x; } } while (0)
+#define DEBUG2_11(x) do { if (qla2_extended_error_logging) { x; } } while (0)
+#define DEBUG2_13(x) do { if (qla2_extended_error_logging) { x; } } while (0)
#if defined(QL_DEBUG_LEVEL_3)
#define DEBUG3(x) do {x;} while (0)
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
index 0930260aec2c..bab33f6d0bdb 100644
--- a/drivers/scsi/qla2xxx/qla_def.h
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -608,6 +608,7 @@ typedef struct {
*/
#define MBC_SERDES_PARAMS 0x10 /* Serdes Tx Parameters. */
#define MBC_GET_IOCB_STATUS 0x12 /* Get IOCB status command. */
+#define MBC_PORT_PARAMS 0x1A /* Port iDMA Parameters. */
#define MBC_GET_TIMEOUT_PARAMS 0x22 /* Get FW timeouts. */
#define MBC_TRACE_CONTROL 0x27 /* Trace control command. */
#define MBC_GEN_SYSTEM_ERROR 0x2a /* Generate System Error. */
@@ -1497,6 +1498,9 @@ typedef struct {
port_id_t d_id;
uint8_t node_name[WWN_SIZE];
uint8_t port_name[WWN_SIZE];
+ uint8_t fabric_port_name[WWN_SIZE];
+ uint16_t fp_speeds;
+ uint16_t fp_speed;
} sw_info_t;
/*
@@ -1524,6 +1528,9 @@ typedef struct fc_port {
uint16_t loop_id;
uint16_t old_loop_id;
+ uint8_t fabric_port_name[WWN_SIZE];
+ uint16_t fp_speed;
+
fc_port_type_t port_type;
atomic_t state;
@@ -1635,6 +1642,15 @@ typedef struct fc_port {
#define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255)
#define RSNN_NN_RSP_SIZE 16
+#define GFPN_ID_CMD 0x11C
+#define GFPN_ID_REQ_SIZE (16 + 4)
+#define GFPN_ID_RSP_SIZE (16 + 8)
+
+#define GPSC_CMD 0x127
+#define GPSC_REQ_SIZE (16 + 8)
+#define GPSC_RSP_SIZE (16 + 2 + 2)
+
+
/*
* HBA attribute types.
*/
@@ -1748,7 +1764,7 @@ struct ct_sns_req {
uint8_t reserved[3];
union {
- /* GA_NXT, GPN_ID, GNN_ID, GFT_ID */
+ /* GA_NXT, GPN_ID, GNN_ID, GFT_ID, GFPN_ID */
struct {
uint8_t reserved;
uint8_t port_id[3];
@@ -1823,6 +1839,10 @@ struct ct_sns_req {
struct {
uint8_t port_name[8];
} dpa;
+
+ struct {
+ uint8_t port_name[8];
+ } gpsc;
} req;
};
@@ -1886,6 +1906,15 @@ struct ct_sns_rsp {
uint8_t port_name[8];
struct ct_fdmi_hba_attributes attrs;
} ghat;
+
+ struct {
+ uint8_t port_name[8];
+ } gfpn_id;
+
+ struct {
+ uint16_t speeds;
+ uint16_t speed;
+ } gpsc;
} rsp;
};
@@ -1980,7 +2009,7 @@ struct isp_operations {
char * (*pci_info_str) (struct scsi_qla_host *, char *);
char * (*fw_version_str) (struct scsi_qla_host *, char *);
- irqreturn_t (*intr_handler) (int, void *, struct pt_regs *);
+ irq_handler_t intr_handler;
void (*enable_intrs) (struct scsi_qla_host *);
void (*disable_intrs) (struct scsi_qla_host *);
@@ -2182,11 +2211,11 @@ typedef struct scsi_qla_host {
uint16_t max_public_loop_ids;
uint16_t min_external_loopid; /* First external loop Id */
+#define PORT_SPEED_UNKNOWN 0xFFFF
+#define PORT_SPEED_1GB 0x00
+#define PORT_SPEED_2GB 0x01
+#define PORT_SPEED_4GB 0x03
uint16_t link_data_rate; /* F/W operating speed */
-#define LDR_1GB 0
-#define LDR_2GB 1
-#define LDR_4GB 3
-#define LDR_UNKNOWN 0xFFFF
uint8_t current_topology;
uint8_t prev_topology;
@@ -2333,6 +2362,7 @@ typedef struct scsi_qla_host {
uint8_t *node_name;
uint8_t *port_name;
+ uint8_t fabric_node_name[WWN_SIZE];
uint32_t isp_abort_cnt;
/* Option ROM information. */
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index 8311ac2b93a8..7da69832d74c 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -60,7 +60,7 @@ extern int ql2xplogiabsentdevice;
extern int ql2xloginretrycount;
extern int ql2xfdmienable;
extern int ql2xallocfwdump;
-extern int extended_error_logging;
+extern int qla2_extended_error_logging;
extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *);
@@ -208,12 +208,18 @@ qla2x00_trace_control(scsi_qla_host_t *, uint16_t, dma_addr_t, uint16_t);
extern int
qla2x00_read_sfp(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t, uint16_t);
+extern int
+qla2x00_get_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t *, uint16_t *);
+
+extern int
+qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
+
/*
* Global Function Prototypes in qla_isr.c source file.
*/
-extern irqreturn_t qla2100_intr_handler(int, void *, struct pt_regs *);
-extern irqreturn_t qla2300_intr_handler(int, void *, struct pt_regs *);
-extern irqreturn_t qla24xx_intr_handler(int, void *, struct pt_regs *);
+extern irqreturn_t qla2100_intr_handler(int, void *);
+extern irqreturn_t qla2300_intr_handler(int, void *);
+extern irqreturn_t qla24xx_intr_handler(int, void *);
extern void qla2x00_process_response_queue(struct scsi_qla_host *);
extern void qla24xx_process_response_queue(struct scsi_qla_host *);
@@ -279,6 +285,9 @@ extern int qla2x00_rsnn_nn(scsi_qla_host_t *);
extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
extern int qla2x00_fdmi_register(scsi_qla_host_t *);
+extern int qla2x00_gfpn_id(scsi_qla_host_t *, sw_info_t *);
+extern int qla2x00_gpsc(scsi_qla_host_t *, sw_info_t *);
+extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *);
/*
* Global Function Prototypes in qla_attr.c source file.
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
index 2ebf259fccb2..97fbc62ec669 100644
--- a/drivers/scsi/qla2xxx/qla_gs.c
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -612,6 +612,14 @@ qla2x00_rnn_id(scsi_qla_host_t *ha)
return (rval);
}
+void
+qla2x00_get_sym_node_name(scsi_qla_host_t *ha, uint8_t *snn)
+{
+ sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number,
+ ha->fw_major_version, ha->fw_minor_version,
+ ha->fw_subminor_version, qla2x00_version_str);
+}
+
/**
* qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
* @ha: HA context
@@ -622,9 +630,6 @@ int
qla2x00_rsnn_nn(scsi_qla_host_t *ha)
{
int rval;
- uint8_t *snn;
- uint8_t version[20];
-
ms_iocb_entry_t *ms_pkt;
struct ct_sns_req *ct_req;
struct ct_sns_rsp *ct_rsp;
@@ -649,20 +654,11 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
memcpy(ct_req->req.rsnn_nn.node_name, ha->node_name, WWN_SIZE);
/* Prepare the Symbolic Node Name */
- /* Board type */
- snn = ct_req->req.rsnn_nn.sym_node_name;
- strcpy(snn, ha->model_number);
- /* Firmware version */
- strcat(snn, " FW:v");
- sprintf(version, "%d.%02d.%02d", ha->fw_major_version,
- ha->fw_minor_version, ha->fw_subminor_version);
- strcat(snn, version);
- /* Driver version */
- strcat(snn, " DVR:v");
- strcat(snn, qla2x00_version_str);
+ qla2x00_get_sym_node_name(ha, ct_req->req.rsnn_nn.sym_node_name);
/* Calculate SNN length */
- ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn);
+ ct_req->req.rsnn_nn.name_len =
+ (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name);
/* Update MS IOCB request */
ms_pkt->req_bytecount =
@@ -687,7 +683,6 @@ qla2x00_rsnn_nn(scsi_qla_host_t *ha)
return (rval);
}
-
/**
* qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
* @ha: HA context
@@ -1585,6 +1580,21 @@ qla2x00_fdmi_rpa(scsi_qla_host_t *ha)
DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no,
eiter->a.os_dev_name));
+ /* Hostname. */
+ if (strlen(fc_host_system_hostname(ha->host))) {
+ eiter = (struct ct_fdmi_port_attr *) (entries + size);
+ eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
+ snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
+ "%s", fc_host_system_hostname(ha->host));
+ alen = strlen(eiter->a.host_name);
+ alen += (alen & 3) ? (4 - (alen & 3)) : 4;
+ eiter->len = cpu_to_be16(4 + alen);
+ size += 4 + alen;
+
+ DEBUG13(printk("%s(%ld): HOSTNAME=%s.\n", __func__,
+ ha->host_no, eiter->a.host_name));
+ }
+
/* Update MS request size. */
qla2x00_update_ms_fdmi_iocb(ha, size + 16);
@@ -1647,3 +1657,189 @@ qla2x00_fdmi_register(scsi_qla_host_t *ha)
return rval;
}
+
+/**
+ * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gfpn_id(scsi_qla_host_t *ha, sw_info_t *list)
+{
+ int rval;
+ uint16_t i;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+ /* Issue GFPN_ID */
+ memset(list[i].fabric_port_name, 0, WWN_SIZE);
+
+ /* Prepare common MS IOCB */
+ ms_pkt = qla2x00_prep_ms_iocb(ha, GFPN_ID_REQ_SIZE,
+ GFPN_ID_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
+ GFPN_ID_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare CT arguments -- port_id */
+ ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
+ ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
+ ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3(printk("scsi(%ld): GFPN_ID issue IOCB "
+ "failed (%d).\n", ha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
+ "GFPN_ID") != QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ /* Save fabric portname */
+ memcpy(list[i].fabric_port_name,
+ ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE);
+ }
+
+ /* Last device exit. */
+ if (list[i].d_id.b.rsvd_1 != 0)
+ break;
+ }
+
+ return (rval);
+}
+
+static inline void *
+qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *ha, uint32_t req_size,
+ uint32_t rsp_size)
+{
+ struct ct_entry_24xx *ct_pkt;
+
+ ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
+ memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
+
+ ct_pkt->entry_type = CT_IOCB_TYPE;
+ ct_pkt->entry_count = 1;
+ ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id);
+ ct_pkt->timeout = __constant_cpu_to_le16(59);
+ ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
+ ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
+ ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
+ ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
+
+ ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
+
+ ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+ ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+ ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
+
+ return ct_pkt;
+}
+
+
+static inline struct ct_sns_req *
+qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
+ uint16_t rsp_size)
+{
+ memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+
+ ct_req->header.revision = 0x01;
+ ct_req->header.gs_type = 0xFA;
+ ct_req->header.gs_subtype = 0x01;
+ ct_req->command = cpu_to_be16(cmd);
+ ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+
+ return ct_req;
+}
+
+/**
+ * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gpsc(scsi_qla_host_t *ha, sw_info_t *list)
+{
+ int rval;
+ uint16_t i;
+
+ ms_iocb_entry_t *ms_pkt;
+ struct ct_sns_req *ct_req;
+ struct ct_sns_rsp *ct_rsp;
+
+ if (!IS_QLA24XX(ha) && !IS_QLA54XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ rval = qla2x00_mgmt_svr_login(ha);
+ if (rval)
+ return rval;
+
+ for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+ /* Issue GFPN_ID */
+ list[i].fp_speeds = list[i].fp_speed = 0;
+
+ /* Prepare common MS IOCB */
+ ms_pkt = qla24xx_prep_ms_fm_iocb(ha, GPSC_REQ_SIZE,
+ GPSC_RSP_SIZE);
+
+ /* Prepare CT request */
+ ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
+ GPSC_CMD, GPSC_RSP_SIZE);
+ ct_rsp = &ha->ct_sns->p.rsp;
+
+ /* Prepare CT arguments -- port_name */
+ memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name,
+ WWN_SIZE);
+
+ /* Execute MS IOCB */
+ rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+ sizeof(ms_iocb_entry_t));
+ if (rval != QLA_SUCCESS) {
+ /*EMPTY*/
+ DEBUG2_3(printk("scsi(%ld): GPSC issue IOCB "
+ "failed (%d).\n", ha->host_no, rval));
+ } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp,
+ "GPSC") != QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ } else {
+ /* Save portname */
+ list[i].fp_speeds = ct_rsp->rsp.gpsc.speeds;
+ list[i].fp_speed = ct_rsp->rsp.gpsc.speed;
+
+ DEBUG2_3(printk("scsi(%ld): GPSC ext entry - "
+ "fpn %02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
+ "speed=%04x.\n", ha->host_no,
+ list[i].fabric_port_name[0],
+ list[i].fabric_port_name[1],
+ list[i].fabric_port_name[2],
+ list[i].fabric_port_name[3],
+ list[i].fabric_port_name[4],
+ list[i].fabric_port_name[5],
+ list[i].fabric_port_name[6],
+ list[i].fabric_port_name[7],
+ be16_to_cpu(list[i].fp_speeds),
+ be16_to_cpu(list[i].fp_speed)));
+ }
+
+ /* Last device exit. */
+ if (list[i].d_id.b.rsvd_1 != 0)
+ break;
+ }
+
+ return (rval);
+}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index 859649160caa..833b93085fd3 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -1644,7 +1644,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha)
* Set host adapter parameters.
*/
if (nv->host_p[0] & BIT_7)
- extended_error_logging = 1;
+ qla2_extended_error_logging = 1;
ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
/* Always load RISC code on non ISP2[12]00 chips. */
if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
@@ -2074,6 +2074,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha)
new_fcport->flags &= ~FCF_FABRIC_DEVICE;
}
+ /* Base iIDMA settings on HBA port speed. */
+ switch (ha->link_data_rate) {
+ case PORT_SPEED_1GB:
+ fcport->fp_speed = cpu_to_be16(BIT_15);
+ break;
+ case PORT_SPEED_2GB:
+ fcport->fp_speed = cpu_to_be16(BIT_14);
+ break;
+ case PORT_SPEED_4GB:
+ fcport->fp_speed = cpu_to_be16(BIT_13);
+ break;
+ }
+
qla2x00_update_fcport(ha, fcport);
found_devs++;
@@ -2109,6 +2122,62 @@ qla2x00_probe_for_all_luns(scsi_qla_host_t *ha)
}
}
+static void
+qla2x00_iidma_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+#define LS_UNKNOWN 2
+ static char *link_speeds[5] = { "1", "2", "?", "4" };
+ int rval;
+ uint16_t port_speed, mb[6];
+
+ if (!IS_QLA24XX(ha))
+ return;
+
+ switch (be16_to_cpu(fcport->fp_speed)) {
+ case BIT_15:
+ port_speed = PORT_SPEED_1GB;
+ break;
+ case BIT_14:
+ port_speed = PORT_SPEED_2GB;
+ break;
+ case BIT_13:
+ port_speed = PORT_SPEED_4GB;
+ break;
+ default:
+ DEBUG2(printk("scsi(%ld): %02x%02x%02x%02x%02x%02x%02x%02x -- "
+ "unsupported FM port operating speed (%04x).\n",
+ ha->host_no, fcport->port_name[0], fcport->port_name[1],
+ fcport->port_name[2], fcport->port_name[3],
+ fcport->port_name[4], fcport->port_name[5],
+ fcport->port_name[6], fcport->port_name[7],
+ be16_to_cpu(fcport->fp_speed)));
+ port_speed = PORT_SPEED_UNKNOWN;
+ break;
+ }
+ if (port_speed == PORT_SPEED_UNKNOWN)
+ return;
+
+ rval = qla2x00_set_idma_speed(ha, fcport->loop_id, port_speed, mb);
+ if (rval != QLA_SUCCESS) {
+ DEBUG2(printk("scsi(%ld): Unable to adjust iIDMA "
+ "%02x%02x%02x%02x%02x%02x%02x%02x -- %04x %x %04x %04x.\n",
+ ha->host_no, fcport->port_name[0], fcport->port_name[1],
+ fcport->port_name[2], fcport->port_name[3],
+ fcport->port_name[4], fcport->port_name[5],
+ fcport->port_name[6], fcport->port_name[7], rval,
+ port_speed, mb[0], mb[1]));
+ } else {
+ DEBUG2(qla_printk(KERN_INFO, ha,
+ "iIDMA adjusted to %s GB/s on "
+ "%02x%02x%02x%02x%02x%02x%02x%02x.\n",
+ link_speeds[port_speed], fcport->port_name[0],
+ fcport->port_name[1], fcport->port_name[2],
+ fcport->port_name[3], fcport->port_name[4],
+ fcport->port_name[5], fcport->port_name[6],
+ fcport->port_name[7]));
+ }
+}
+
/*
* qla2x00_update_fcport
* Updates device on list.
@@ -2135,6 +2204,8 @@ qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
PORT_RETRY_TIME);
fcport->flags &= ~FCF_LOGIN_NEEDED;
+ qla2x00_iidma_fcport(ha, fcport);
+
atomic_set(&fcport->state, FCS_ONLINE);
if (ha->flags.init_done)
@@ -2209,7 +2280,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
loop_id = NPH_F_PORT;
else
loop_id = SNS_FL_PORT;
- rval = qla2x00_get_port_name(ha, loop_id, NULL, 0);
+ rval = qla2x00_get_port_name(ha, loop_id, ha->fabric_node_name, 1);
if (rval != QLA_SUCCESS) {
DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
"Port\n", ha->host_no));
@@ -2217,6 +2288,7 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha)
ha->device_flags &= ~SWITCH_FOUND;
return (QLA_SUCCESS);
}
+ ha->device_flags |= SWITCH_FOUND;
/* Mark devices that need re-synchronization. */
rval2 = qla2x00_device_resync(ha);
@@ -2416,6 +2488,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
kfree(swl);
swl = NULL;
+ } else if (qla2x00_gfpn_id(ha, swl) == QLA_SUCCESS) {
+ qla2x00_gpsc(ha, swl);
}
}
swl_idx = 0;
@@ -2450,6 +2524,9 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
swl[swl_idx].node_name, WWN_SIZE);
memcpy(new_fcport->port_name,
swl[swl_idx].port_name, WWN_SIZE);
+ memcpy(new_fcport->fabric_port_name,
+ swl[swl_idx].fabric_port_name, WWN_SIZE);
+ new_fcport->fp_speed = swl[swl_idx].fp_speed;
if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
last_dev = 1;
@@ -2507,6 +2584,11 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
found++;
+ /* Update port state. */
+ memcpy(fcport->fabric_port_name,
+ new_fcport->fabric_port_name, WWN_SIZE);
+ fcport->fp_speed = new_fcport->fp_speed;
+
/*
* If address the same and state FCS_ONLINE, nothing
* changed.
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
index 45007ee58067..d3023338628f 100644
--- a/drivers/scsi/qla2xxx/qla_inline.h
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -104,7 +104,7 @@ static __inline__ void qla2x00_poll(scsi_qla_host_t *);
static inline void
qla2x00_poll(scsi_qla_host_t *ha)
{
- ha->isp_ops.intr_handler(0, ha, NULL);
+ ha->isp_ops.intr_handler(0, ha);
}
static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
index de0613135f70..626c7178a434 100644
--- a/drivers/scsi/qla2xxx/qla_isr.c
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -20,14 +20,13 @@ static void qla24xx_ms_entry(scsi_qla_host_t *, struct ct_entry_24xx *);
* qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
* @irq:
* @dev_id: SCSI driver HA context
- * @regs:
*
* Called by system whenever the host adapter generates an interrupt.
*
* Returns handled flag.
*/
irqreturn_t
-qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla2100_intr_handler(int irq, void *dev_id)
{
scsi_qla_host_t *ha;
struct device_reg_2xxx __iomem *reg;
@@ -100,14 +99,13 @@ qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
* qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
* @irq:
* @dev_id: SCSI driver HA context
- * @regs:
*
* Called by system whenever the host adapter generates an interrupt.
*
* Returns handled flag.
*/
irqreturn_t
-qla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla2300_intr_handler(int irq, void *dev_id)
{
scsi_qla_host_t *ha;
struct device_reg_2xxx __iomem *reg;
@@ -400,7 +398,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
case MBA_LOOP_UP: /* Loop Up Event */
if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
link_speed = link_speeds[0];
- ha->link_data_rate = LDR_1GB;
+ ha->link_data_rate = PORT_SPEED_1GB;
} else {
link_speed = link_speeds[LS_UNKNOWN];
if (mb[1] < 5)
@@ -429,7 +427,7 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb)
}
ha->flags.management_server_logged_in = 0;
- ha->link_data_rate = LDR_UNKNOWN;
+ ha->link_data_rate = PORT_SPEED_UNKNOWN;
if (ql2xfdmienable)
set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
break;
@@ -1338,14 +1336,13 @@ qla24xx_process_response_queue(struct scsi_qla_host *ha)
* qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
* @irq:
* @dev_id: SCSI driver HA context
- * @regs:
*
* Called by system whenever the host adapter generates an interrupt.
*
* Returns handled flag.
*/
irqreturn_t
-qla24xx_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+qla24xx_intr_handler(int irq, void *dev_id)
{
scsi_qla_host_t *ha;
struct device_reg_24xx __iomem *reg;
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
index 879f281e2ea2..4cde76c85cb3 100644
--- a/drivers/scsi/qla2xxx/qla_mbx.c
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -2540,3 +2540,89 @@ qla2x00_read_sfp(scsi_qla_host_t *ha, dma_addr_t sfp_dma, uint16_t addr,
return rval;
}
+
+int
+qla2x00_get_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+ uint16_t *port_speed, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_PORT_PARAMS;
+ mcp->mb[1] = loop_id;
+ mcp->mb[2] = mcp->mb[3] = mcp->mb[4] = mcp->mb[5] = 0;
+ mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ /* Return mailbox statuses. */
+ if (mb != NULL) {
+ mb[0] = mcp->mb[0];
+ mb[1] = mcp->mb[1];
+ mb[3] = mcp->mb[3];
+ mb[4] = mcp->mb[4];
+ mb[5] = mcp->mb[5];
+ }
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+ ha->host_no, rval));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ if (port_speed)
+ *port_speed = mcp->mb[3];
+ }
+
+ return rval;
+}
+
+int
+qla2x00_set_idma_speed(scsi_qla_host_t *ha, uint16_t loop_id,
+ uint16_t port_speed, uint16_t *mb)
+{
+ int rval;
+ mbx_cmd_t mc;
+ mbx_cmd_t *mcp = &mc;
+
+ if (!IS_QLA24XX(ha))
+ return QLA_FUNCTION_FAILED;
+
+ DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+ mcp->mb[0] = MBC_PORT_PARAMS;
+ mcp->mb[1] = loop_id;
+ mcp->mb[2] = BIT_0;
+ mcp->mb[3] = port_speed & (BIT_2|BIT_1|BIT_0);
+ mcp->mb[4] = mcp->mb[5] = 0;
+ mcp->out_mb = MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+ mcp->in_mb = MBX_5|MBX_4|MBX_3|MBX_1|MBX_0;
+ mcp->tov = 30;
+ mcp->flags = 0;
+ rval = qla2x00_mailbox_command(ha, mcp);
+
+ /* Return mailbox statuses. */
+ if (mb != NULL) {
+ mb[0] = mcp->mb[0];
+ mb[1] = mcp->mb[1];
+ mb[3] = mcp->mb[3];
+ mb[4] = mcp->mb[4];
+ mb[5] = mcp->mb[5];
+ }
+
+ if (rval != QLA_SUCCESS) {
+ DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+ ha->host_no, rval));
+ } else {
+ DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+ }
+
+ return rval;
+}
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 65cbe2f5eea2..3f20d765563e 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -61,9 +61,9 @@ MODULE_PARM_DESC(ql2xallocfwdump,
"during HBA initialization. Memory allocation requirements "
"vary by ISP type. Default is 1 - allocate memory.");
-int extended_error_logging;
-module_param(extended_error_logging, int, S_IRUGO|S_IRUSR);
-MODULE_PARM_DESC(extended_error_logging,
+int qla2_extended_error_logging;
+module_param(qla2_extended_error_logging, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(qla2_extended_error_logging,
"Option to enable extended error logging, "
"Default is 0 - no logging. 1 - log errors.");
@@ -589,6 +589,23 @@ qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
return (return_status);
}
+static void
+qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
+{
+ struct Scsi_Host *shost = cmnd->device->host;
+ struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
+ unsigned long flags;
+
+ spin_lock_irqsave(shost->host_lock, flags);
+ while (rport->port_state == FC_PORTSTATE_BLOCKED) {
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ msleep(1000);
+ spin_lock_irqsave(shost->host_lock, flags);
+ }
+ spin_unlock_irqrestore(shost->host_lock, flags);
+ return;
+}
+
/**************************************************************************
* qla2xxx_eh_abort
*
@@ -615,6 +632,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd)
unsigned long flags;
int wait = 0;
+ qla2x00_block_error_handler(cmd);
+
if (!CMD_SP(cmd))
return SUCCESS;
@@ -748,6 +767,8 @@ qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
@@ -877,6 +898,8 @@ qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
@@ -936,6 +959,8 @@ qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
unsigned int id, lun;
unsigned long serial;
+ qla2x00_block_error_handler(cmd);
+
ret = FAILED;
id = cmd->device->id;
@@ -1385,7 +1410,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
ha->prev_topology = 0;
ha->init_cb_size = sizeof(init_cb_t);
ha->mgmt_svr_loop_id = MANAGEMENT_SERVER;
- ha->link_data_rate = LDR_UNKNOWN;
+ ha->link_data_rate = PORT_SPEED_UNKNOWN;
ha->optrom_size = OPTROM_SIZE_2300;
/* Assign ISP specific operations. */
@@ -2564,14 +2589,20 @@ qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
#define FW_ISP2322 3
#define FW_ISP24XX 4
+#define FW_FILE_ISP21XX "ql2100_fw.bin"
+#define FW_FILE_ISP22XX "ql2200_fw.bin"
+#define FW_FILE_ISP2300 "ql2300_fw.bin"
+#define FW_FILE_ISP2322 "ql2322_fw.bin"
+#define FW_FILE_ISP24XX "ql2400_fw.bin"
+
static DECLARE_MUTEX(qla_fw_lock);
static struct fw_blob qla_fw_blobs[FW_BLOBS] = {
- { .name = "ql2100_fw.bin", .segs = { 0x1000, 0 }, },
- { .name = "ql2200_fw.bin", .segs = { 0x1000, 0 }, },
- { .name = "ql2300_fw.bin", .segs = { 0x800, 0 }, },
- { .name = "ql2322_fw.bin", .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
- { .name = "ql2400_fw.bin", },
+ { .name = FW_FILE_ISP21XX, .segs = { 0x1000, 0 }, },
+ { .name = FW_FILE_ISP22XX, .segs = { 0x1000, 0 }, },
+ { .name = FW_FILE_ISP2300, .segs = { 0x800, 0 }, },
+ { .name = FW_FILE_ISP2322, .segs = { 0x800, 0x1c000, 0x1e000, 0 }, },
+ { .name = FW_FILE_ISP24XX, },
};
struct fw_blob *
@@ -2666,7 +2697,7 @@ qla2x00_module_init(void)
/* Derive version string. */
strcpy(qla2x00_version_str, QLA2XXX_VERSION);
- if (extended_error_logging)
+ if (qla2_extended_error_logging)
strcat(qla2x00_version_str, "-debug");
qla2xxx_transport_template =
@@ -2702,3 +2733,8 @@ MODULE_AUTHOR("QLogic Corporation");
MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(QLA2XXX_VERSION);
+MODULE_FIRMWARE(FW_FILE_ISP21XX);
+MODULE_FIRMWARE(FW_FILE_ISP22XX);
+MODULE_FIRMWARE(FW_FILE_ISP2300);
+MODULE_FIRMWARE(FW_FILE_ISP2322);
+MODULE_FIRMWARE(FW_FILE_ISP24XX);
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
index 971259032ef7..e57bf45a3393 100644
--- a/drivers/scsi/qla2xxx/qla_version.h
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -7,7 +7,7 @@
/*
* Driver version
*/
-#define QLA2XXX_VERSION "8.01.07-k1"
+#define QLA2XXX_VERSION "8.01.07-k2"
#define QLA_DRIVER_MAJOR_VER 8
#define QLA_DRIVER_MINOR_VER 1
diff --git a/drivers/scsi/qla4xxx/Kconfig b/drivers/scsi/qla4xxx/Kconfig
new file mode 100644
index 000000000000..08a07f0b8d94
--- /dev/null
+++ b/drivers/scsi/qla4xxx/Kconfig
@@ -0,0 +1,7 @@
+config SCSI_QLA_ISCSI
+ tristate "QLogic ISP4XXX host adapter family support"
+ depends on PCI && SCSI
+ select SCSI_ISCSI_ATTRS
+ ---help---
+ This driver supports the QLogic 40xx (ISP4XXX) iSCSI host
+ adapter family.
diff --git a/drivers/scsi/qla4xxx/Makefile b/drivers/scsi/qla4xxx/Makefile
new file mode 100644
index 000000000000..86ea37baa0fc
--- /dev/null
+++ b/drivers/scsi/qla4xxx/Makefile
@@ -0,0 +1,5 @@
+qla4xxx-y := ql4_os.o ql4_init.o ql4_mbx.o ql4_iocb.o ql4_isr.o \
+ ql4_nvram.o ql4_dbg.o
+
+obj-$(CONFIG_SCSI_QLA_ISCSI) += qla4xxx.o
+
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.c b/drivers/scsi/qla4xxx/ql4_dbg.c
new file mode 100644
index 000000000000..752031fadfef
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_dbg.c
@@ -0,0 +1,197 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+#include <scsi/scsi_dbg.h>
+
+static void qla4xxx_print_srb_info(struct srb * srb)
+{
+ printk("%s: srb = 0x%p, flags=0x%02x\n", __func__, srb, srb->flags);
+ printk("%s: cmd = 0x%p, saved_dma_handle = 0x%lx\n",
+ __func__, srb->cmd, (unsigned long) srb->dma_handle);
+ printk("%s: fw_ddb_index = %d, lun = %d\n",
+ __func__, srb->fw_ddb_index, srb->cmd->device->lun);
+ printk("%s: iocb_tov = %d\n",
+ __func__, srb->iocb_tov);
+ printk("%s: cc_stat = 0x%x, r_start = 0x%lx, u_start = 0x%lx\n\n",
+ __func__, srb->cc_stat, srb->r_start, srb->u_start);
+}
+
+void qla4xxx_print_scsi_cmd(struct scsi_cmnd *cmd)
+{
+ printk("SCSI Command = 0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
+ printk(" b=%d, t=%02xh, l=%02xh, cmd_len = %02xh\n",
+ cmd->device->channel, cmd->device->id, cmd->device->lun,
+ cmd->cmd_len);
+ scsi_print_command(cmd);
+ printk(" seg_cnt = %d\n", cmd->use_sg);
+ printk(" request buffer = 0x%p, request buffer len = 0x%x\n",
+ cmd->request_buffer, cmd->request_bufflen);
+ if (cmd->use_sg) {
+ struct scatterlist *sg;
+ sg = (struct scatterlist *)cmd->request_buffer;
+ printk(" SG buffer: \n");
+ qla4xxx_dump_buffer((caddr_t) sg,
+ (cmd->use_sg * sizeof(*sg)));
+ }
+ printk(" tag = %d, transfersize = 0x%x \n", cmd->tag,
+ cmd->transfersize);
+ printk(" Pid = %d, SP = 0x%p\n", (int)cmd->pid, cmd->SCp.ptr);
+ printk(" underflow size = 0x%x, direction=0x%x\n", cmd->underflow,
+ cmd->sc_data_direction);
+ printk(" Current time (jiffies) = 0x%lx, "
+ "timeout expires = 0x%lx\n", jiffies, cmd->eh_timeout.expires);
+ qla4xxx_print_srb_info((struct srb *) cmd->SCp.ptr);
+}
+
+void __dump_registers(struct scsi_qla_host *ha)
+{
+ uint8_t i;
+ for (i = 0; i < MBOX_REG_COUNT; i++) {
+ printk(KERN_INFO "0x%02X mailbox[%d] = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, mailbox[i]), i,
+ readw(&ha->reg->mailbox[i]));
+ }
+ printk(KERN_INFO "0x%02X flash_address = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, flash_address),
+ readw(&ha->reg->flash_address));
+ printk(KERN_INFO "0x%02X flash_data = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, flash_data),
+ readw(&ha->reg->flash_data));
+ printk(KERN_INFO "0x%02X ctrl_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, ctrl_status),
+ readw(&ha->reg->ctrl_status));
+ if (is_qla4010(ha)) {
+ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4010.nvram),
+ readw(&ha->reg->u1.isp4010.nvram));
+ }
+
+ else if (is_qla4022(ha)) {
+ printk(KERN_INFO "0x%02X intr_mask = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u1.isp4022.intr_mask),
+ readw(&ha->reg->u1.isp4022.intr_mask));
+ printk(KERN_INFO "0x%02X nvram = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u1.isp4022.nvram),
+ readw(&ha->reg->u1.isp4022.nvram));
+ printk(KERN_INFO "0x%02X semaphore = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u1.isp4022.semaphore),
+ readw(&ha->reg->u1.isp4022.semaphore));
+ }
+ printk(KERN_INFO "0x%02X req_q_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, req_q_in),
+ readw(&ha->reg->req_q_in));
+ printk(KERN_INFO "0x%02X rsp_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, rsp_q_out),
+ readw(&ha->reg->rsp_q_out));
+ if (is_qla4010(ha)) {
+ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.ext_hw_conf),
+ readw(&ha->reg->u2.isp4010.ext_hw_conf));
+ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.port_ctrl),
+ readw(&ha->reg->u2.isp4010.port_ctrl));
+ printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.port_status),
+ readw(&ha->reg->u2.isp4010.port_status));
+ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.req_q_out),
+ readw(&ha->reg->u2.isp4010.req_q_out));
+ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_out),
+ readw(&ha->reg->u2.isp4010.gp_out));
+ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4010.gp_in),
+ readw(&ha->reg->u2.isp4010.gp_in));
+ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4010.port_err_status),
+ readw(&ha->reg->u2.isp4010.port_err_status));
+ }
+
+ else if (is_qla4022(ha)) {
+ printk(KERN_INFO "Page 0 Registers:\n");
+ printk(KERN_INFO "0x%02X ext_hw_conf = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.ext_hw_conf),
+ readw(&ha->reg->u2.isp4022.p0.ext_hw_conf));
+ printk(KERN_INFO "0x%02X port_ctrl = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.port_ctrl),
+ readw(&ha->reg->u2.isp4022.p0.port_ctrl));
+ printk(KERN_INFO "0x%02X port_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.port_status),
+ readw(&ha->reg->u2.isp4022.p0.port_status));
+ printk(KERN_INFO "0x%02X gp_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.gp_out),
+ readw(&ha->reg->u2.isp4022.p0.gp_out));
+ printk(KERN_INFO "0x%02X gp_in = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg, u2.isp4022.p0.gp_in),
+ readw(&ha->reg->u2.isp4022.p0.gp_in));
+ printk(KERN_INFO "0x%02X port_err_status = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p0.port_err_status),
+ readw(&ha->reg->u2.isp4022.p0.port_err_status));
+ printk(KERN_INFO "Page 1 Registers:\n");
+ writel(HOST_MEM_CFG_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+ &ha->reg->ctrl_status);
+ printk(KERN_INFO "0x%02X req_q_out = 0x%08X\n",
+ (uint8_t) offsetof(struct isp_reg,
+ u2.isp4022.p1.req_q_out),
+ readw(&ha->reg->u2.isp4022.p1.req_q_out));
+ writel(PORT_CTRL_STAT_PAGE & set_rmask(CSR_SCSI_PAGE_SELECT),
+ &ha->reg->ctrl_status);
+ }
+}
+
+void qla4xxx_dump_mbox_registers(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+ int i = 0;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (i = 1; i < MBOX_REG_COUNT; i++)
+ printk(KERN_INFO " Mailbox[%d] = %08x\n", i,
+ readw(&ha->reg->mailbox[i]));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void qla4xxx_dump_registers(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ __dump_registers(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+void qla4xxx_dump_buffer(void *b, uint32_t size)
+{
+ uint32_t cnt;
+ uint8_t *c = b;
+
+ printk(" 0 1 2 3 4 5 6 7 8 9 Ah Bh Ch Dh Eh "
+ "Fh\n");
+ printk("------------------------------------------------------------"
+ "--\n");
+ for (cnt = 0; cnt < size; cnt++, c++) {
+ printk(KERN_DEBUG "%02x", *c);
+ if (!(cnt % 16))
+ printk(KERN_DEBUG "\n");
+
+ else
+ printk(KERN_DEBUG " ");
+ }
+ if (cnt % 16)
+ printk(KERN_DEBUG "\n");
+}
diff --git a/drivers/scsi/qla4xxx/ql4_dbg.h b/drivers/scsi/qla4xxx/ql4_dbg.h
new file mode 100644
index 000000000000..3e99dcfd5a9f
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_dbg.h
@@ -0,0 +1,55 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+/*
+ * Driver debug definitions.
+ */
+/* #define QL_DEBUG */ /* DEBUG messages */
+/* #define QL_DEBUG_LEVEL_3 */ /* Output function tracing */
+/* #define QL_DEBUG_LEVEL_4 */
+/* #define QL_DEBUG_LEVEL_5 */
+/* #define QL_DEBUG_LEVEL_9 */
+
+#define QL_DEBUG_LEVEL_2 /* ALways enable error messagess */
+#if defined(QL_DEBUG)
+#define DEBUG(x) do {x;} while (0);
+#else
+#define DEBUG(x) do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_2)
+#define DEBUG2(x) do {if(qla4_extended_error_logging == 2) x;} while (0);
+#define DEBUG2_3(x) do {x;} while (0);
+#else /* */
+#define DEBUG2(x) do {} while (0);
+#endif /* */
+
+#if defined(QL_DEBUG_LEVEL_3)
+#define DEBUG3(x) do {if(qla4_extended_error_logging == 3) x;} while (0);
+#else /* */
+#define DEBUG3(x) do {} while (0);
+#if !defined(QL_DEBUG_LEVEL_2)
+#define DEBUG2_3(x) do {} while (0);
+#endif /* */
+#endif /* */
+#if defined(QL_DEBUG_LEVEL_4)
+#define DEBUG4(x) do {x;} while (0);
+#else /* */
+#define DEBUG4(x) do {} while (0);
+#endif /* */
+
+#if defined(QL_DEBUG_LEVEL_5)
+#define DEBUG5(x) do {x;} while (0);
+#else /* */
+#define DEBUG5(x) do {} while (0);
+#endif /* */
+
+#if defined(QL_DEBUG_LEVEL_9)
+#define DEBUG9(x) do {x;} while (0);
+#else /* */
+#define DEBUG9(x) do {} while (0);
+#endif /* */
diff --git a/drivers/scsi/qla4xxx/ql4_def.h b/drivers/scsi/qla4xxx/ql4_def.h
new file mode 100644
index 000000000000..a7f6c7b1c590
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_def.h
@@ -0,0 +1,586 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef __QL4_DEF_H
+#define __QL4_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/mempool.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
+#include <net/tcp.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP4010
+#define PCI_DEVICE_ID_QLOGIC_ISP4010 0x4010
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP4022
+#define PCI_DEVICE_ID_QLOGIC_ISP4022 0x4022
+#endif /* */
+
+#define QLA_SUCCESS 0
+#define QLA_ERROR 1
+
+/*
+ * Data bit definitions
+ */
+#define BIT_0 0x1
+#define BIT_1 0x2
+#define BIT_2 0x4
+#define BIT_3 0x8
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x100
+#define BIT_9 0x200
+#define BIT_10 0x400
+#define BIT_11 0x800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x10000
+#define BIT_17 0x20000
+#define BIT_18 0x40000
+#define BIT_19 0x80000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x1000000
+#define BIT_25 0x2000000
+#define BIT_26 0x4000000
+#define BIT_27 0x8000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
+/*
+ * Host adapter default definitions
+ ***********************************/
+#define MAX_HBAS 16
+#define MAX_BUSES 1
+#define MAX_TARGETS (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
+#define MAX_LUNS 0xffff
+#define MAX_AEN_ENTRIES 256 /* should be > EXT_DEF_MAX_AEN_QUEUE */
+#define MAX_DDB_ENTRIES (MAX_PRST_DEV_DB_ENTRIES + MAX_DEV_DB_ENTRIES)
+#define MAX_PDU_ENTRIES 32
+#define INVALID_ENTRY 0xFFFF
+#define MAX_CMDS_TO_RISC 1024
+#define MAX_SRBS MAX_CMDS_TO_RISC
+#define MBOX_AEN_REG_COUNT 5
+#define MAX_INIT_RETRIES 5
+#define IOCB_HIWAT_CUSHION 16
+
+/*
+ * Buffer sizes
+ */
+#define REQUEST_QUEUE_DEPTH MAX_CMDS_TO_RISC
+#define RESPONSE_QUEUE_DEPTH 64
+#define QUEUE_SIZE 64
+#define DMA_BUFFER_SIZE 512
+
+/*
+ * Misc
+ */
+#define MAC_ADDR_LEN 6 /* in bytes */
+#define IP_ADDR_LEN 4 /* in bytes */
+#define DRIVER_NAME "qla4xxx"
+
+#define MAX_LINKED_CMDS_PER_LUN 3
+#define MAX_REQS_SERVICED_PER_INTR 16
+
+#define ISCSI_IPADDR_SIZE 4 /* IP address size */
+#define ISCSI_ALIAS_SIZE 32 /* ISCSI Alais name size */
+#define ISCSI_NAME_SIZE 255 /* ISCSI Name size -
+ * usually a string */
+
+#define LSDW(x) ((u32)((u64)(x)))
+#define MSDW(x) ((u32)((((u64)(x)) >> 16) >> 16))
+
+/*
+ * Retry & Timeout Values
+ */
+#define MBOX_TOV 60
+#define SOFT_RESET_TOV 30
+#define RESET_INTR_TOV 3
+#define SEMAPHORE_TOV 10
+#define ADAPTER_INIT_TOV 120
+#define ADAPTER_RESET_TOV 180
+#define EXTEND_CMD_TOV 60
+#define WAIT_CMD_TOV 30
+#define EH_WAIT_CMD_TOV 120
+#define FIRMWARE_UP_TOV 60
+#define RESET_FIRMWARE_TOV 30
+#define LOGOUT_TOV 10
+#define IOCB_TOV_MARGIN 10
+#define RELOGIN_TOV 18
+#define ISNS_DEREG_TOV 5
+
+#define MAX_RESET_HA_RETRIES 2
+
+/*
+ * SCSI Request Block structure (srb) that is placed
+ * on cmd->SCp location of every I/O [We have 22 bytes available]
+ */
+struct srb {
+ struct list_head list; /* (8) */
+ struct scsi_qla_host *ha; /* HA the SP is queued on */
+ struct ddb_entry *ddb;
+ uint16_t flags; /* (1) Status flags. */
+
+#define SRB_DMA_VALID BIT_3 /* DMA Buffer mapped. */
+#define SRB_GOT_SENSE BIT_4 /* sense data recieved. */
+ uint8_t state; /* (1) Status flags. */
+
+#define SRB_NO_QUEUE_STATE 0 /* Request is in between states */
+#define SRB_FREE_STATE 1
+#define SRB_ACTIVE_STATE 3
+#define SRB_ACTIVE_TIMEOUT_STATE 4
+#define SRB_SUSPENDED_STATE 7 /* Request in suspended state */
+
+ struct scsi_cmnd *cmd; /* (4) SCSI command block */
+ dma_addr_t dma_handle; /* (4) for unmap of single transfers */
+ atomic_t ref_count; /* reference count for this srb */
+ uint32_t fw_ddb_index;
+ uint8_t err_id; /* error id */
+#define SRB_ERR_PORT 1 /* Request failed because "port down" */
+#define SRB_ERR_LOOP 2 /* Request failed because "loop down" */
+#define SRB_ERR_DEVICE 3 /* Request failed because "device error" */
+#define SRB_ERR_OTHER 4
+
+ uint16_t reserved;
+ uint16_t iocb_tov;
+ uint16_t iocb_cnt; /* Number of used iocbs */
+ uint16_t cc_stat;
+ u_long r_start; /* Time we recieve a cmd from OS */
+ u_long u_start; /* Time when we handed the cmd to F/W */
+};
+
+ /*
+ * Device Database (DDB) structure
+ */
+struct ddb_entry {
+ struct list_head list; /* ddb list */
+ struct scsi_qla_host *ha;
+ struct iscsi_cls_session *sess;
+ struct iscsi_cls_conn *conn;
+
+ atomic_t state; /* DDB State */
+
+ unsigned long flags; /* DDB Flags */
+
+ unsigned long dev_scan_wait_to_start_relogin;
+ unsigned long dev_scan_wait_to_complete_relogin;
+
+ uint16_t os_target_id; /* Target ID */
+ uint16_t fw_ddb_index; /* DDB firmware index */
+ uint8_t reserved[2];
+ uint32_t fw_ddb_device_state; /* F/W Device State -- see ql4_fw.h */
+
+ uint32_t CmdSn;
+ uint16_t target_session_id;
+ uint16_t connection_id;
+ uint16_t exe_throttle; /* Max mumber of cmds outstanding
+ * simultaneously */
+ uint16_t task_mgmt_timeout; /* Min time for task mgmt cmds to
+ * complete */
+ uint16_t default_relogin_timeout; /* Max time to wait for
+ * relogin to complete */
+ uint16_t tcp_source_port_num;
+ uint32_t default_time2wait; /* Default Min time between
+ * relogins (+aens) */
+
+ atomic_t port_down_timer; /* Device connection timer */
+ atomic_t retry_relogin_timer; /* Min Time between relogins
+ * (4000 only) */
+ atomic_t relogin_timer; /* Max Time to wait for relogin to complete */
+ atomic_t relogin_retry_count; /* Num of times relogin has been
+ * retried */
+
+ uint16_t port;
+ uint32_t tpgt;
+ uint8_t ip_addr[ISCSI_IPADDR_SIZE];
+ uint8_t iscsi_name[ISCSI_NAME_SIZE]; /* 72 x48 */
+ uint8_t iscsi_alias[0x20];
+};
+
+/*
+ * DDB states.
+ */
+#define DDB_STATE_DEAD 0 /* We can no longer talk to
+ * this device */
+#define DDB_STATE_ONLINE 1 /* Device ready to accept
+ * commands */
+#define DDB_STATE_MISSING 2 /* Device logged off, trying
+ * to re-login */
+
+/*
+ * DDB flags.
+ */
+#define DF_RELOGIN 0 /* Relogin to device */
+#define DF_NO_RELOGIN 1 /* Do not relogin if IOCTL
+ * logged it out */
+#define DF_ISNS_DISCOVERED 2 /* Device was discovered via iSNS */
+#define DF_FO_MASKED 3
+
+/*
+ * Asynchronous Event Queue structure
+ */
+struct aen {
+ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+};
+
+
+#include "ql4_fw.h"
+#include "ql4_nvram.h"
+
+/*
+ * Linux Host Adapter structure
+ */
+struct scsi_qla_host {
+ /* Linux adapter configuration data */
+ struct Scsi_Host *host; /* pointer to host data */
+ uint32_t tot_ddbs;
+ unsigned long flags;
+
+#define AF_ONLINE 0 /* 0x00000001 */
+#define AF_INIT_DONE 1 /* 0x00000002 */
+#define AF_MBOX_COMMAND 2 /* 0x00000004 */
+#define AF_MBOX_COMMAND_DONE 3 /* 0x00000008 */
+#define AF_INTERRUPTS_ON 6 /* 0x00000040 Not Used */
+#define AF_GET_CRASH_RECORD 7 /* 0x00000080 */
+#define AF_LINK_UP 8 /* 0x00000100 */
+#define AF_TOPCAT_CHIP_PRESENT 9 /* 0x00000200 */
+#define AF_IRQ_ATTACHED 10 /* 0x00000400 */
+#define AF_ISNS_CMD_IN_PROCESS 12 /* 0x00001000 */
+#define AF_ISNS_CMD_DONE 13 /* 0x00002000 */
+
+ unsigned long dpc_flags;
+
+#define DPC_RESET_HA 1 /* 0x00000002 */
+#define DPC_RETRY_RESET_HA 2 /* 0x00000004 */
+#define DPC_RELOGIN_DEVICE 3 /* 0x00000008 */
+#define DPC_RESET_HA_DESTROY_DDB_LIST 4 /* 0x00000010 */
+#define DPC_RESET_HA_INTR 5 /* 0x00000020 */
+#define DPC_ISNS_RESTART 7 /* 0x00000080 */
+#define DPC_AEN 9 /* 0x00000200 */
+#define DPC_GET_DHCP_IP_ADDR 15 /* 0x00008000 */
+
+ uint16_t iocb_cnt;
+ uint16_t iocb_hiwat;
+
+ /* SRB cache. */
+#define SRB_MIN_REQ 128
+ mempool_t *srb_mempool;
+
+ /* pci information */
+ struct pci_dev *pdev;
+
+ struct isp_reg __iomem *reg; /* Base I/O address */
+ unsigned long pio_address;
+ unsigned long pio_length;
+#define MIN_IOBASE_LEN 0x100
+
+ uint16_t req_q_count;
+ uint8_t marker_needed;
+ uint8_t rsvd1;
+
+ unsigned long host_no;
+
+ /* NVRAM registers */
+ struct eeprom_data *nvram;
+ spinlock_t hardware_lock ____cacheline_aligned;
+ spinlock_t list_lock;
+ uint32_t eeprom_cmd_data;
+
+ /* Counters for general statistics */
+ uint64_t adapter_error_count;
+ uint64_t device_error_count;
+ uint64_t total_io_count;
+ uint64_t total_mbytes_xferred;
+ uint64_t link_failure_count;
+ uint64_t invalid_crc_count;
+ uint32_t spurious_int_count;
+ uint32_t aborted_io_count;
+ uint32_t io_timeout_count;
+ uint32_t mailbox_timeout_count;
+ uint32_t seconds_since_last_intr;
+ uint32_t seconds_since_last_heartbeat;
+ uint32_t mac_index;
+
+ /* Info Needed for Management App */
+ /* --- From GetFwVersion --- */
+ uint32_t firmware_version[2];
+ uint32_t patch_number;
+ uint32_t build_number;
+
+ /* --- From Init_FW --- */
+ /* init_cb_t *init_cb; */
+ uint16_t firmware_options;
+ uint16_t tcp_options;
+ uint8_t ip_address[IP_ADDR_LEN];
+ uint8_t subnet_mask[IP_ADDR_LEN];
+ uint8_t gateway[IP_ADDR_LEN];
+ uint8_t alias[32];
+ uint8_t name_string[256];
+ uint8_t heartbeat_interval;
+ uint8_t rsvd;
+
+ /* --- From FlashSysInfo --- */
+ uint8_t my_mac[MAC_ADDR_LEN];
+ uint8_t serial_number[16];
+
+ /* --- From GetFwState --- */
+ uint32_t firmware_state;
+ uint32_t board_id;
+ uint32_t addl_fw_state;
+
+ /* Linux kernel thread */
+ struct workqueue_struct *dpc_thread;
+ struct work_struct dpc_work;
+
+ /* Linux timer thread */
+ struct timer_list timer;
+ uint32_t timer_active;
+
+ /* Recovery Timers */
+ uint32_t port_down_retry_count;
+ uint32_t discovery_wait;
+ atomic_t check_relogin_timeouts;
+ uint32_t retry_reset_ha_cnt;
+ uint32_t isp_reset_timer; /* reset test timer */
+ uint32_t nic_reset_timer; /* simulated nic reset test timer */
+ int eh_start;
+ struct list_head free_srb_q;
+ uint16_t free_srb_q_count;
+ uint16_t num_srbs_allocated;
+
+ /* DMA Memory Block */
+ void *queues;
+ dma_addr_t queues_dma;
+ unsigned long queues_len;
+
+#define MEM_ALIGN_VALUE \
+ ((max(REQUEST_QUEUE_DEPTH, RESPONSE_QUEUE_DEPTH)) * \
+ sizeof(struct queue_entry))
+ /* request and response queue variables */
+ dma_addr_t request_dma;
+ struct queue_entry *request_ring;
+ struct queue_entry *request_ptr;
+ dma_addr_t response_dma;
+ struct queue_entry *response_ring;
+ struct queue_entry *response_ptr;
+ dma_addr_t shadow_regs_dma;
+ struct shadow_regs *shadow_regs;
+ uint16_t request_in; /* Current indexes. */
+ uint16_t request_out;
+ uint16_t response_in;
+ uint16_t response_out;
+
+ /* aen queue variables */
+ uint16_t aen_q_count; /* Number of available aen_q entries */
+ uint16_t aen_in; /* Current indexes */
+ uint16_t aen_out;
+ struct aen aen_q[MAX_AEN_ENTRIES];
+
+ /* This mutex protects several threads to do mailbox commands
+ * concurrently.
+ */
+ struct mutex mbox_sem;
+ wait_queue_head_t mailbox_wait_queue;
+
+ /* temporary mailbox status registers */
+ volatile uint8_t mbox_status_count;
+ volatile uint32_t mbox_status[MBOX_REG_COUNT];
+
+ /* local device database list (contains internal ddb entries) */
+ struct list_head ddb_list;
+
+ /* Map ddb_list entry by FW ddb index */
+ struct ddb_entry *fw_ddb_index_map[MAX_DDB_ENTRIES];
+
+};
+
+static inline int is_qla4010(struct scsi_qla_host *ha)
+{
+ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4010;
+}
+
+static inline int is_qla4022(struct scsi_qla_host *ha)
+{
+ return ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP4022;
+}
+
+static inline int adapter_up(struct scsi_qla_host *ha)
+{
+ return (test_bit(AF_ONLINE, &ha->flags) != 0) &&
+ (test_bit(AF_LINK_UP, &ha->flags) != 0);
+}
+
+static inline struct scsi_qla_host* to_qla_host(struct Scsi_Host *shost)
+{
+ return (struct scsi_qla_host *)shost->hostdata;
+}
+
+static inline void __iomem* isp_semaphore(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ &ha->reg->u1.isp4022.semaphore :
+ &ha->reg->u1.isp4010.nvram);
+}
+
+static inline void __iomem* isp_nvram(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ &ha->reg->u1.isp4022.nvram :
+ &ha->reg->u1.isp4010.nvram);
+}
+
+static inline void __iomem* isp_ext_hw_conf(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ &ha->reg->u2.isp4022.p0.ext_hw_conf :
+ &ha->reg->u2.isp4010.ext_hw_conf);
+}
+
+static inline void __iomem* isp_port_status(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ &ha->reg->u2.isp4022.p0.port_status :
+ &ha->reg->u2.isp4010.port_status);
+}
+
+static inline void __iomem* isp_port_ctrl(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ &ha->reg->u2.isp4022.p0.port_ctrl :
+ &ha->reg->u2.isp4010.port_ctrl);
+}
+
+static inline void __iomem* isp_port_error_status(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ &ha->reg->u2.isp4022.p0.port_err_status :
+ &ha->reg->u2.isp4010.port_err_status);
+}
+
+static inline void __iomem * isp_gp_out(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ &ha->reg->u2.isp4022.p0.gp_out :
+ &ha->reg->u2.isp4010.gp_out);
+}
+
+static inline int eeprom_ext_hw_conf_offset(struct scsi_qla_host *ha)
+{
+ return (is_qla4022(ha) ?
+ offsetof(struct eeprom_data, isp4022.ext_hw_conf) / 2 :
+ offsetof(struct eeprom_data, isp4010.ext_hw_conf) / 2);
+}
+
+int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
+void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask);
+int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits);
+
+static inline int ql4xxx_lock_flash(struct scsi_qla_host *a)
+{
+ if (is_qla4022(a))
+ return ql4xxx_sem_spinlock(a, QL4022_FLASH_SEM_MASK,
+ (QL4022_RESOURCE_BITS_BASE_CODE |
+ (a->mac_index)) << 13);
+ else
+ return ql4xxx_sem_spinlock(a, QL4010_FLASH_SEM_MASK,
+ QL4010_FLASH_SEM_BITS);
+}
+
+static inline void ql4xxx_unlock_flash(struct scsi_qla_host *a)
+{
+ if (is_qla4022(a))
+ ql4xxx_sem_unlock(a, QL4022_FLASH_SEM_MASK);
+ else
+ ql4xxx_sem_unlock(a, QL4010_FLASH_SEM_MASK);
+}
+
+static inline int ql4xxx_lock_nvram(struct scsi_qla_host *a)
+{
+ if (is_qla4022(a))
+ return ql4xxx_sem_spinlock(a, QL4022_NVRAM_SEM_MASK,
+ (QL4022_RESOURCE_BITS_BASE_CODE |
+ (a->mac_index)) << 10);
+ else
+ return ql4xxx_sem_spinlock(a, QL4010_NVRAM_SEM_MASK,
+ QL4010_NVRAM_SEM_BITS);
+}
+
+static inline void ql4xxx_unlock_nvram(struct scsi_qla_host *a)
+{
+ if (is_qla4022(a))
+ ql4xxx_sem_unlock(a, QL4022_NVRAM_SEM_MASK);
+ else
+ ql4xxx_sem_unlock(a, QL4010_NVRAM_SEM_MASK);
+}
+
+static inline int ql4xxx_lock_drvr(struct scsi_qla_host *a)
+{
+ if (is_qla4022(a))
+ return ql4xxx_sem_lock(a, QL4022_DRVR_SEM_MASK,
+ (QL4022_RESOURCE_BITS_BASE_CODE |
+ (a->mac_index)) << 1);
+ else
+ return ql4xxx_sem_lock(a, QL4010_DRVR_SEM_MASK,
+ QL4010_DRVR_SEM_BITS);
+}
+
+static inline void ql4xxx_unlock_drvr(struct scsi_qla_host *a)
+{
+ if (is_qla4022(a))
+ ql4xxx_sem_unlock(a, QL4022_DRVR_SEM_MASK);
+ else
+ ql4xxx_sem_unlock(a, QL4010_DRVR_SEM_MASK);
+}
+
+/*---------------------------------------------------------------------------*/
+
+/* Defines for qla4xxx_initialize_adapter() and qla4xxx_recover_adapter() */
+#define PRESERVE_DDB_LIST 0
+#define REBUILD_DDB_LIST 1
+
+/* Defines for process_aen() */
+#define PROCESS_ALL_AENS 0
+#define FLUSH_DDB_CHANGED_AENS 1
+#define RELOGIN_DDB_CHANGED_AENS 2
+
+#include "ql4_version.h"
+#include "ql4_glbl.h"
+#include "ql4_dbg.h"
+#include "ql4_inline.h"
+
+
+#endif /*_QLA4XXX_H */
diff --git a/drivers/scsi/qla4xxx/ql4_fw.h b/drivers/scsi/qla4xxx/ql4_fw.h
new file mode 100644
index 000000000000..427489de64bc
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_fw.h
@@ -0,0 +1,843 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef _QLA4X_FW_H
+#define _QLA4X_FW_H
+
+
+#define MAX_PRST_DEV_DB_ENTRIES 64
+#define MIN_DISC_DEV_DB_ENTRY MAX_PRST_DEV_DB_ENTRIES
+#define MAX_DEV_DB_ENTRIES 512
+
+/*************************************************************************
+ *
+ * ISP 4010 I/O Register Set Structure and Definitions
+ *
+ *************************************************************************/
+
+struct port_ctrl_stat_regs {
+ __le32 ext_hw_conf; /* 80 x50 R/W */
+ __le32 intChipConfiguration; /* 84 x54 */
+ __le32 port_ctrl; /* 88 x58 */
+ __le32 port_status; /* 92 x5c */
+ __le32 HostPrimMACHi; /* 96 x60 */
+ __le32 HostPrimMACLow; /* 100 x64 */
+ __le32 HostSecMACHi; /* 104 x68 */
+ __le32 HostSecMACLow; /* 108 x6c */
+ __le32 EPPrimMACHi; /* 112 x70 */
+ __le32 EPPrimMACLow; /* 116 x74 */
+ __le32 EPSecMACHi; /* 120 x78 */
+ __le32 EPSecMACLow; /* 124 x7c */
+ __le32 HostPrimIPHi; /* 128 x80 */
+ __le32 HostPrimIPMidHi; /* 132 x84 */
+ __le32 HostPrimIPMidLow; /* 136 x88 */
+ __le32 HostPrimIPLow; /* 140 x8c */
+ __le32 HostSecIPHi; /* 144 x90 */
+ __le32 HostSecIPMidHi; /* 148 x94 */
+ __le32 HostSecIPMidLow; /* 152 x98 */
+ __le32 HostSecIPLow; /* 156 x9c */
+ __le32 EPPrimIPHi; /* 160 xa0 */
+ __le32 EPPrimIPMidHi; /* 164 xa4 */
+ __le32 EPPrimIPMidLow; /* 168 xa8 */
+ __le32 EPPrimIPLow; /* 172 xac */
+ __le32 EPSecIPHi; /* 176 xb0 */
+ __le32 EPSecIPMidHi; /* 180 xb4 */
+ __le32 EPSecIPMidLow; /* 184 xb8 */
+ __le32 EPSecIPLow; /* 188 xbc */
+ __le32 IPReassemblyTimeout; /* 192 xc0 */
+ __le32 EthMaxFramePayload; /* 196 xc4 */
+ __le32 TCPMaxWindowSize; /* 200 xc8 */
+ __le32 TCPCurrentTimestampHi; /* 204 xcc */
+ __le32 TCPCurrentTimestampLow; /* 208 xd0 */
+ __le32 LocalRAMAddress; /* 212 xd4 */
+ __le32 LocalRAMData; /* 216 xd8 */
+ __le32 PCSReserved1; /* 220 xdc */
+ __le32 gp_out; /* 224 xe0 */
+ __le32 gp_in; /* 228 xe4 */
+ __le32 ProbeMuxAddr; /* 232 xe8 */
+ __le32 ProbeMuxData; /* 236 xec */
+ __le32 ERMQueueBaseAddr0; /* 240 xf0 */
+ __le32 ERMQueueBaseAddr1; /* 244 xf4 */
+ __le32 MACConfiguration; /* 248 xf8 */
+ __le32 port_err_status; /* 252 xfc COR */
+};
+
+struct host_mem_cfg_regs {
+ __le32 NetRequestQueueOut; /* 80 x50 */
+ __le32 NetRequestQueueOutAddrHi; /* 84 x54 */
+ __le32 NetRequestQueueOutAddrLow; /* 88 x58 */
+ __le32 NetRequestQueueBaseAddrHi; /* 92 x5c */
+ __le32 NetRequestQueueBaseAddrLow; /* 96 x60 */
+ __le32 NetRequestQueueLength; /* 100 x64 */
+ __le32 NetResponseQueueIn; /* 104 x68 */
+ __le32 NetResponseQueueInAddrHi; /* 108 x6c */
+ __le32 NetResponseQueueInAddrLow; /* 112 x70 */
+ __le32 NetResponseQueueBaseAddrHi; /* 116 x74 */
+ __le32 NetResponseQueueBaseAddrLow; /* 120 x78 */
+ __le32 NetResponseQueueLength; /* 124 x7c */
+ __le32 req_q_out; /* 128 x80 */
+ __le32 RequestQueueOutAddrHi; /* 132 x84 */
+ __le32 RequestQueueOutAddrLow; /* 136 x88 */
+ __le32 RequestQueueBaseAddrHi; /* 140 x8c */
+ __le32 RequestQueueBaseAddrLow; /* 144 x90 */
+ __le32 RequestQueueLength; /* 148 x94 */
+ __le32 ResponseQueueIn; /* 152 x98 */
+ __le32 ResponseQueueInAddrHi; /* 156 x9c */
+ __le32 ResponseQueueInAddrLow; /* 160 xa0 */
+ __le32 ResponseQueueBaseAddrHi; /* 164 xa4 */
+ __le32 ResponseQueueBaseAddrLow; /* 168 xa8 */
+ __le32 ResponseQueueLength; /* 172 xac */
+ __le32 NetRxLargeBufferQueueOut; /* 176 xb0 */
+ __le32 NetRxLargeBufferQueueBaseAddrHi; /* 180 xb4 */
+ __le32 NetRxLargeBufferQueueBaseAddrLow; /* 184 xb8 */
+ __le32 NetRxLargeBufferQueueLength; /* 188 xbc */
+ __le32 NetRxLargeBufferLength; /* 192 xc0 */
+ __le32 NetRxSmallBufferQueueOut; /* 196 xc4 */
+ __le32 NetRxSmallBufferQueueBaseAddrHi; /* 200 xc8 */
+ __le32 NetRxSmallBufferQueueBaseAddrLow; /* 204 xcc */
+ __le32 NetRxSmallBufferQueueLength; /* 208 xd0 */
+ __le32 NetRxSmallBufferLength; /* 212 xd4 */
+ __le32 HMCReserved0[10]; /* 216 xd8 */
+};
+
+struct local_ram_cfg_regs {
+ __le32 BufletSize; /* 80 x50 */
+ __le32 BufletMaxCount; /* 84 x54 */
+ __le32 BufletCurrCount; /* 88 x58 */
+ __le32 BufletPauseThresholdCount; /* 92 x5c */
+ __le32 BufletTCPWinThresholdHi; /* 96 x60 */
+ __le32 BufletTCPWinThresholdLow; /* 100 x64 */
+ __le32 IPHashTableBaseAddr; /* 104 x68 */
+ __le32 IPHashTableSize; /* 108 x6c */
+ __le32 TCPHashTableBaseAddr; /* 112 x70 */
+ __le32 TCPHashTableSize; /* 116 x74 */
+ __le32 NCBAreaBaseAddr; /* 120 x78 */
+ __le32 NCBMaxCount; /* 124 x7c */
+ __le32 NCBCurrCount; /* 128 x80 */
+ __le32 DRBAreaBaseAddr; /* 132 x84 */
+ __le32 DRBMaxCount; /* 136 x88 */
+ __le32 DRBCurrCount; /* 140 x8c */
+ __le32 LRCReserved[28]; /* 144 x90 */
+};
+
+struct prot_stat_regs {
+ __le32 MACTxFrameCount; /* 80 x50 R */
+ __le32 MACTxByteCount; /* 84 x54 R */
+ __le32 MACRxFrameCount; /* 88 x58 R */
+ __le32 MACRxByteCount; /* 92 x5c R */
+ __le32 MACCRCErrCount; /* 96 x60 R */
+ __le32 MACEncErrCount; /* 100 x64 R */
+ __le32 MACRxLengthErrCount; /* 104 x68 R */
+ __le32 IPTxPacketCount; /* 108 x6c R */
+ __le32 IPTxByteCount; /* 112 x70 R */
+ __le32 IPTxFragmentCount; /* 116 x74 R */
+ __le32 IPRxPacketCount; /* 120 x78 R */
+ __le32 IPRxByteCount; /* 124 x7c R */
+ __le32 IPRxFragmentCount; /* 128 x80 R */
+ __le32 IPDatagramReassemblyCount; /* 132 x84 R */
+ __le32 IPV6RxPacketCount; /* 136 x88 R */
+ __le32 IPErrPacketCount; /* 140 x8c R */
+ __le32 IPReassemblyErrCount; /* 144 x90 R */
+ __le32 TCPTxSegmentCount; /* 148 x94 R */
+ __le32 TCPTxByteCount; /* 152 x98 R */
+ __le32 TCPRxSegmentCount; /* 156 x9c R */
+ __le32 TCPRxByteCount; /* 160 xa0 R */
+ __le32 TCPTimerExpCount; /* 164 xa4 R */
+ __le32 TCPRxAckCount; /* 168 xa8 R */
+ __le32 TCPTxAckCount; /* 172 xac R */
+ __le32 TCPRxErrOOOCount; /* 176 xb0 R */
+ __le32 PSReserved0; /* 180 xb4 */
+ __le32 TCPRxWindowProbeUpdateCount; /* 184 xb8 R */
+ __le32 ECCErrCorrectionCount; /* 188 xbc R */
+ __le32 PSReserved1[16]; /* 192 xc0 */
+};
+
+
+/* remote register set (access via PCI memory read/write) */
+struct isp_reg {
+#define MBOX_REG_COUNT 8
+ __le32 mailbox[MBOX_REG_COUNT];
+
+ __le32 flash_address; /* 0x20 */
+ __le32 flash_data;
+ __le32 ctrl_status;
+
+ union {
+ struct {
+ __le32 nvram;
+ __le32 reserved1[2]; /* 0x30 */
+ } __attribute__ ((packed)) isp4010;
+ struct {
+ __le32 intr_mask;
+ __le32 nvram; /* 0x30 */
+ __le32 semaphore;
+ } __attribute__ ((packed)) isp4022;
+ } u1;
+
+ __le32 req_q_in; /* SCSI Request Queue Producer Index */
+ __le32 rsp_q_out; /* SCSI Completion Queue Consumer Index */
+
+ __le32 reserved2[4]; /* 0x40 */
+
+ union {
+ struct {
+ __le32 ext_hw_conf; /* 0x50 */
+ __le32 flow_ctrl;
+ __le32 port_ctrl;
+ __le32 port_status;
+
+ __le32 reserved3[8]; /* 0x60 */
+
+ __le32 req_q_out; /* 0x80 */
+
+ __le32 reserved4[23]; /* 0x84 */
+
+ __le32 gp_out; /* 0xe0 */
+ __le32 gp_in;
+
+ __le32 reserved5[5];
+
+ __le32 port_err_status; /* 0xfc */
+ } __attribute__ ((packed)) isp4010;
+ struct {
+ union {
+ struct port_ctrl_stat_regs p0;
+ struct host_mem_cfg_regs p1;
+ struct local_ram_cfg_regs p2;
+ struct prot_stat_regs p3;
+ __le32 r_union[44];
+ };
+
+ } __attribute__ ((packed)) isp4022;
+ } u2;
+}; /* 256 x100 */
+
+
+/* Semaphore Defines for 4010 */
+#define QL4010_DRVR_SEM_BITS 0x00000030
+#define QL4010_GPIO_SEM_BITS 0x000000c0
+#define QL4010_SDRAM_SEM_BITS 0x00000300
+#define QL4010_PHY_SEM_BITS 0x00000c00
+#define QL4010_NVRAM_SEM_BITS 0x00003000
+#define QL4010_FLASH_SEM_BITS 0x0000c000
+
+#define QL4010_DRVR_SEM_MASK 0x00300000
+#define QL4010_GPIO_SEM_MASK 0x00c00000
+#define QL4010_SDRAM_SEM_MASK 0x03000000
+#define QL4010_PHY_SEM_MASK 0x0c000000
+#define QL4010_NVRAM_SEM_MASK 0x30000000
+#define QL4010_FLASH_SEM_MASK 0xc0000000
+
+/* Semaphore Defines for 4022 */
+#define QL4022_RESOURCE_MASK_BASE_CODE 0x7
+#define QL4022_RESOURCE_BITS_BASE_CODE 0x4
+
+
+#define QL4022_DRVR_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (1+16))
+#define QL4022_DDR_RAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (4+16))
+#define QL4022_PHY_GIO_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (7+16))
+#define QL4022_NVRAM_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (10+16))
+#define QL4022_FLASH_SEM_MASK (QL4022_RESOURCE_MASK_BASE_CODE << (13+16))
+
+
+
+/* Page # defines for 4022 */
+#define PORT_CTRL_STAT_PAGE 0 /* 4022 */
+#define HOST_MEM_CFG_PAGE 1 /* 4022 */
+#define LOCAL_RAM_CFG_PAGE 2 /* 4022 */
+#define PROT_STAT_PAGE 3 /* 4022 */
+
+/* Register Mask - sets corresponding mask bits in the upper word */
+static inline uint32_t set_rmask(uint32_t val)
+{
+ return (val & 0xffff) | (val << 16);
+}
+
+
+static inline uint32_t clr_rmask(uint32_t val)
+{
+ return 0 | (val << 16);
+}
+
+/* ctrl_status definitions */
+#define CSR_SCSI_PAGE_SELECT 0x00000003
+#define CSR_SCSI_INTR_ENABLE 0x00000004 /* 4010 */
+#define CSR_SCSI_RESET_INTR 0x00000008
+#define CSR_SCSI_COMPLETION_INTR 0x00000010
+#define CSR_SCSI_PROCESSOR_INTR 0x00000020
+#define CSR_INTR_RISC 0x00000040
+#define CSR_BOOT_ENABLE 0x00000080
+#define CSR_NET_PAGE_SELECT 0x00000300 /* 4010 */
+#define CSR_FUNC_NUM 0x00000700 /* 4022 */
+#define CSR_NET_RESET_INTR 0x00000800 /* 4010 */
+#define CSR_FORCE_SOFT_RESET 0x00002000 /* 4022 */
+#define CSR_FATAL_ERROR 0x00004000
+#define CSR_SOFT_RESET 0x00008000
+#define ISP_CONTROL_FN_MASK CSR_FUNC_NUM
+#define ISP_CONTROL_FN0_SCSI 0x0500
+#define ISP_CONTROL_FN1_SCSI 0x0700
+
+#define INTR_PENDING (CSR_SCSI_COMPLETION_INTR |\
+ CSR_SCSI_PROCESSOR_INTR |\
+ CSR_SCSI_RESET_INTR)
+
+/* ISP InterruptMask definitions */
+#define IMR_SCSI_INTR_ENABLE 0x00000004 /* 4022 */
+
+/* ISP 4022 nvram definitions */
+#define NVR_WRITE_ENABLE 0x00000010 /* 4022 */
+
+/* ISP port_status definitions */
+
+/* ISP Semaphore definitions */
+
+/* ISP General Purpose Output definitions */
+#define GPOR_TOPCAT_RESET 0x00000004
+
+/* shadow registers (DMA'd from HA to system memory. read only) */
+struct shadow_regs {
+ /* SCSI Request Queue Consumer Index */
+ __le32 req_q_out; /* 0 x0 R */
+
+ /* SCSI Completion Queue Producer Index */
+ __le32 rsp_q_in; /* 4 x4 R */
+}; /* 8 x8 */
+
+
+/* External hardware configuration register */
+union external_hw_config_reg {
+ struct {
+ /* FIXME: Do we even need this? All values are
+ * referred to by 16 bit quantities. Platform and
+ * endianess issues. */
+ __le32 bReserved0:1;
+ __le32 bSDRAMProtectionMethod:2;
+ __le32 bSDRAMBanks:1;
+ __le32 bSDRAMChipWidth:1;
+ __le32 bSDRAMChipSize:2;
+ __le32 bParityDisable:1;
+ __le32 bExternalMemoryType:1;
+ __le32 bFlashBIOSWriteEnable:1;
+ __le32 bFlashUpperBankSelect:1;
+ __le32 bWriteBurst:2;
+ __le32 bReserved1:3;
+ __le32 bMask:16;
+ };
+ uint32_t Asuint32_t;
+};
+
+/*************************************************************************
+ *
+ * Mailbox Commands Structures and Definitions
+ *
+ *************************************************************************/
+
+/* Mailbox command definitions */
+#define MBOX_CMD_ABOUT_FW 0x0009
+#define MBOX_CMD_LUN_RESET 0x0016
+#define MBOX_CMD_GET_FW_STATUS 0x001F
+#define MBOX_CMD_SET_ISNS_SERVICE 0x0021
+#define ISNS_DISABLE 0
+#define ISNS_ENABLE 1
+#define MBOX_CMD_READ_FLASH 0x0026
+#define MBOX_CMD_CLEAR_DATABASE_ENTRY 0x0031
+#define MBOX_CMD_CONN_CLOSE_SESS_LOGOUT 0x0056
+#define LOGOUT_OPTION_CLOSE_SESSION 0x01
+#define LOGOUT_OPTION_RELOGIN 0x02
+#define MBOX_CMD_EXECUTE_IOCB_A64 0x005A
+#define MBOX_CMD_INITIALIZE_FIRMWARE 0x0060
+#define MBOX_CMD_GET_INIT_FW_CTRL_BLOCK 0x0061
+#define MBOX_CMD_REQUEST_DATABASE_ENTRY 0x0062
+#define MBOX_CMD_SET_DATABASE_ENTRY 0x0063
+#define MBOX_CMD_GET_DATABASE_ENTRY 0x0064
+#define DDB_DS_UNASSIGNED 0x00
+#define DDB_DS_NO_CONNECTION_ACTIVE 0x01
+#define DDB_DS_SESSION_ACTIVE 0x04
+#define DDB_DS_SESSION_FAILED 0x06
+#define DDB_DS_LOGIN_IN_PROCESS 0x07
+#define MBOX_CMD_GET_FW_STATE 0x0069
+
+/* Mailbox 1 */
+#define FW_STATE_READY 0x0000
+#define FW_STATE_CONFIG_WAIT 0x0001
+#define FW_STATE_ERROR 0x0004
+#define FW_STATE_DHCP_IN_PROGRESS 0x0008
+
+/* Mailbox 3 */
+#define FW_ADDSTATE_OPTICAL_MEDIA 0x0001
+#define FW_ADDSTATE_DHCP_ENABLED 0x0002
+#define FW_ADDSTATE_LINK_UP 0x0010
+#define FW_ADDSTATE_ISNS_SVC_ENABLED 0x0020
+#define MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS 0x006B
+#define MBOX_CMD_CONN_OPEN_SESS_LOGIN 0x0074
+#define MBOX_CMD_GET_CRASH_RECORD 0x0076 /* 4010 only */
+#define MBOX_CMD_GET_CONN_EVENT_LOG 0x0077
+
+/* Mailbox status definitions */
+#define MBOX_COMPLETION_STATUS 4
+#define MBOX_STS_BUSY 0x0007
+#define MBOX_STS_INTERMEDIATE_COMPLETION 0x1000
+#define MBOX_STS_COMMAND_COMPLETE 0x4000
+#define MBOX_STS_COMMAND_ERROR 0x4005
+
+#define MBOX_ASYNC_EVENT_STATUS 8
+#define MBOX_ASTS_SYSTEM_ERROR 0x8002
+#define MBOX_ASTS_REQUEST_TRANSFER_ERROR 0x8003
+#define MBOX_ASTS_RESPONSE_TRANSFER_ERROR 0x8004
+#define MBOX_ASTS_PROTOCOL_STATISTIC_ALARM 0x8005
+#define MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED 0x8006
+#define MBOX_ASTS_LINK_UP 0x8010
+#define MBOX_ASTS_LINK_DOWN 0x8011
+#define MBOX_ASTS_DATABASE_CHANGED 0x8014
+#define MBOX_ASTS_UNSOLICITED_PDU_RECEIVED 0x8015
+#define MBOX_ASTS_SELF_TEST_FAILED 0x8016
+#define MBOX_ASTS_LOGIN_FAILED 0x8017
+#define MBOX_ASTS_DNS 0x8018
+#define MBOX_ASTS_HEARTBEAT 0x8019
+#define MBOX_ASTS_NVRAM_INVALID 0x801A
+#define MBOX_ASTS_MAC_ADDRESS_CHANGED 0x801B
+#define MBOX_ASTS_IP_ADDRESS_CHANGED 0x801C
+#define MBOX_ASTS_DHCP_LEASE_EXPIRED 0x801D
+#define MBOX_ASTS_DHCP_LEASE_ACQUIRED 0x801F
+#define MBOX_ASTS_ISNS_UNSOLICITED_PDU_RECEIVED 0x8021
+#define ISNS_EVENT_DATA_RECEIVED 0x0000
+#define ISNS_EVENT_CONNECTION_OPENED 0x0001
+#define ISNS_EVENT_CONNECTION_FAILED 0x0002
+#define MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR 0x8022
+#define MBOX_ASTS_SUBNET_STATE_CHANGE 0x8027
+
+/*************************************************************************/
+
+/* Host Adapter Initialization Control Block (from host) */
+struct init_fw_ctrl_blk {
+ uint8_t Version; /* 00 */
+ uint8_t Control; /* 01 */
+
+ uint16_t FwOptions; /* 02-03 */
+#define FWOPT_HEARTBEAT_ENABLE 0x1000
+#define FWOPT_SESSION_MODE 0x0040
+#define FWOPT_INITIATOR_MODE 0x0020
+#define FWOPT_TARGET_MODE 0x0010
+
+ uint16_t ExecThrottle; /* 04-05 */
+ uint8_t RetryCount; /* 06 */
+ uint8_t RetryDelay; /* 07 */
+ uint16_t MaxEthFrPayloadSize; /* 08-09 */
+ uint16_t AddFwOptions; /* 0A-0B */
+
+ uint8_t HeartbeatInterval; /* 0C */
+ uint8_t InstanceNumber; /* 0D */
+ uint16_t RES2; /* 0E-0F */
+ uint16_t ReqQConsumerIndex; /* 10-11 */
+ uint16_t ComplQProducerIndex; /* 12-13 */
+ uint16_t ReqQLen; /* 14-15 */
+ uint16_t ComplQLen; /* 16-17 */
+ uint32_t ReqQAddrLo; /* 18-1B */
+ uint32_t ReqQAddrHi; /* 1C-1F */
+ uint32_t ComplQAddrLo; /* 20-23 */
+ uint32_t ComplQAddrHi; /* 24-27 */
+ uint32_t ShadowRegBufAddrLo; /* 28-2B */
+ uint32_t ShadowRegBufAddrHi; /* 2C-2F */
+
+ uint16_t iSCSIOptions; /* 30-31 */
+
+ uint16_t TCPOptions; /* 32-33 */
+
+ uint16_t IPOptions; /* 34-35 */
+
+ uint16_t MaxPDUSize; /* 36-37 */
+ uint16_t RcvMarkerInt; /* 38-39 */
+ uint16_t SndMarkerInt; /* 3A-3B */
+ uint16_t InitMarkerlessInt; /* 3C-3D */
+ uint16_t FirstBurstSize; /* 3E-3F */
+ uint16_t DefaultTime2Wait; /* 40-41 */
+ uint16_t DefaultTime2Retain; /* 42-43 */
+ uint16_t MaxOutStndngR2T; /* 44-45 */
+ uint16_t KeepAliveTimeout; /* 46-47 */
+ uint16_t PortNumber; /* 48-49 */
+ uint16_t MaxBurstSize; /* 4A-4B */
+ uint32_t RES4; /* 4C-4F */
+ uint8_t IPAddr[4]; /* 50-53 */
+ uint8_t RES5[12]; /* 54-5F */
+ uint8_t SubnetMask[4]; /* 60-63 */
+ uint8_t RES6[12]; /* 64-6F */
+ uint8_t GatewayIPAddr[4]; /* 70-73 */
+ uint8_t RES7[12]; /* 74-7F */
+ uint8_t PriDNSIPAddr[4]; /* 80-83 */
+ uint8_t SecDNSIPAddr[4]; /* 84-87 */
+ uint8_t RES8[8]; /* 88-8F */
+ uint8_t Alias[32]; /* 90-AF */
+ uint8_t TargAddr[8]; /* B0-B7 *//* /FIXME: Remove?? */
+ uint8_t CHAPNameSecretsTable[8]; /* B8-BF */
+ uint8_t EthernetMACAddr[6]; /* C0-C5 */
+ uint16_t TargetPortalGroup; /* C6-C7 */
+ uint8_t SendScale; /* C8 */
+ uint8_t RecvScale; /* C9 */
+ uint8_t TypeOfService; /* CA */
+ uint8_t Time2Live; /* CB */
+ uint16_t VLANPriority; /* CC-CD */
+ uint16_t Reserved8; /* CE-CF */
+ uint8_t SecIPAddr[4]; /* D0-D3 */
+ uint8_t Reserved9[12]; /* D4-DF */
+ uint8_t iSNSIPAddr[4]; /* E0-E3 */
+ uint16_t iSNSServerPortNumber; /* E4-E5 */
+ uint8_t Reserved10[10]; /* E6-EF */
+ uint8_t SLPDAIPAddr[4]; /* F0-F3 */
+ uint8_t Reserved11[12]; /* F4-FF */
+ uint8_t iSCSINameString[256]; /* 100-1FF */
+};
+
+/*************************************************************************/
+
+struct dev_db_entry {
+ uint8_t options; /* 00 */
+#define DDB_OPT_DISC_SESSION 0x10
+#define DDB_OPT_TARGET 0x02 /* device is a target */
+
+ uint8_t control; /* 01 */
+
+ uint16_t exeThrottle; /* 02-03 */
+ uint16_t exeCount; /* 04-05 */
+ uint8_t retryCount; /* 06 */
+ uint8_t retryDelay; /* 07 */
+ uint16_t iSCSIOptions; /* 08-09 */
+
+ uint16_t TCPOptions; /* 0A-0B */
+
+ uint16_t IPOptions; /* 0C-0D */
+
+ uint16_t maxPDUSize; /* 0E-0F */
+ uint16_t rcvMarkerInt; /* 10-11 */
+ uint16_t sndMarkerInt; /* 12-13 */
+ uint16_t iSCSIMaxSndDataSegLen; /* 14-15 */
+ uint16_t firstBurstSize; /* 16-17 */
+ uint16_t minTime2Wait; /* 18-19 : RA :default_time2wait */
+ uint16_t maxTime2Retain; /* 1A-1B */
+ uint16_t maxOutstndngR2T; /* 1C-1D */
+ uint16_t keepAliveTimeout; /* 1E-1F */
+ uint8_t ISID[6]; /* 20-25 big-endian, must be converted
+ * to little-endian */
+ uint16_t TSID; /* 26-27 */
+ uint16_t portNumber; /* 28-29 */
+ uint16_t maxBurstSize; /* 2A-2B */
+ uint16_t taskMngmntTimeout; /* 2C-2D */
+ uint16_t reserved1; /* 2E-2F */
+ uint8_t ipAddr[0x10]; /* 30-3F */
+ uint8_t iSCSIAlias[0x20]; /* 40-5F */
+ uint8_t targetAddr[0x20]; /* 60-7F */
+ uint8_t userID[0x20]; /* 80-9F */
+ uint8_t password[0x20]; /* A0-BF */
+ uint8_t iscsiName[0x100]; /* C0-1BF : xxzzy Make this a
+ * pointer to a string so we
+ * don't have to reserve soooo
+ * much RAM */
+ uint16_t ddbLink; /* 1C0-1C1 */
+ uint16_t CHAPTableIndex; /* 1C2-1C3 */
+ uint16_t TargetPortalGroup; /* 1C4-1C5 */
+ uint16_t reserved2[2]; /* 1C6-1C7 */
+ uint32_t statSN; /* 1C8-1CB */
+ uint32_t expStatSN; /* 1CC-1CF */
+ uint16_t reserved3[0x2C]; /* 1D0-1FB */
+ uint16_t ddbValidCookie; /* 1FC-1FD */
+ uint16_t ddbValidSize; /* 1FE-1FF */
+};
+
+/*************************************************************************/
+
+/* Flash definitions */
+
+#define FLASH_OFFSET_SYS_INFO 0x02000000
+#define FLASH_DEFAULTBLOCKSIZE 0x20000
+#define FLASH_EOF_OFFSET (FLASH_DEFAULTBLOCKSIZE-8) /* 4 bytes
+ * for EOF
+ * signature */
+
+struct sys_info_phys_addr {
+ uint8_t address[6]; /* 00-05 */
+ uint8_t filler[2]; /* 06-07 */
+};
+
+struct flash_sys_info {
+ uint32_t cookie; /* 00-03 */
+ uint32_t physAddrCount; /* 04-07 */
+ struct sys_info_phys_addr physAddr[4]; /* 08-27 */
+ uint8_t vendorId[128]; /* 28-A7 */
+ uint8_t productId[128]; /* A8-127 */
+ uint32_t serialNumber; /* 128-12B */
+
+ /* PCI Configuration values */
+ uint32_t pciDeviceVendor; /* 12C-12F */
+ uint32_t pciDeviceId; /* 130-133 */
+ uint32_t pciSubsysVendor; /* 134-137 */
+ uint32_t pciSubsysId; /* 138-13B */
+
+ /* This validates version 1. */
+ uint32_t crumbs; /* 13C-13F */
+
+ uint32_t enterpriseNumber; /* 140-143 */
+
+ uint32_t mtu; /* 144-147 */
+ uint32_t reserved0; /* 148-14b */
+ uint32_t crumbs2; /* 14c-14f */
+ uint8_t acSerialNumber[16]; /* 150-15f */
+ uint32_t crumbs3; /* 160-16f */
+
+ /* Leave this last in the struct so it is declared invalid if
+ * any new items are added.
+ */
+ uint32_t reserved1[39]; /* 170-1ff */
+}; /* 200 */
+
+struct crash_record {
+ uint16_t fw_major_version; /* 00 - 01 */
+ uint16_t fw_minor_version; /* 02 - 03 */
+ uint16_t fw_patch_version; /* 04 - 05 */
+ uint16_t fw_build_version; /* 06 - 07 */
+
+ uint8_t build_date[16]; /* 08 - 17 */
+ uint8_t build_time[16]; /* 18 - 27 */
+ uint8_t build_user[16]; /* 28 - 37 */
+ uint8_t card_serial_num[16]; /* 38 - 47 */
+
+ uint32_t time_of_crash_in_secs; /* 48 - 4B */
+ uint32_t time_of_crash_in_ms; /* 4C - 4F */
+
+ uint16_t out_RISC_sd_num_frames; /* 50 - 51 */
+ uint16_t OAP_sd_num_words; /* 52 - 53 */
+ uint16_t IAP_sd_num_frames; /* 54 - 55 */
+ uint16_t in_RISC_sd_num_words; /* 56 - 57 */
+
+ uint8_t reserved1[28]; /* 58 - 7F */
+
+ uint8_t out_RISC_reg_dump[256]; /* 80 -17F */
+ uint8_t in_RISC_reg_dump[256]; /*180 -27F */
+ uint8_t in_out_RISC_stack_dump[0]; /*280 - ??? */
+};
+
+struct conn_event_log_entry {
+#define MAX_CONN_EVENT_LOG_ENTRIES 100
+ uint32_t timestamp_sec; /* 00 - 03 seconds since boot */
+ uint32_t timestamp_ms; /* 04 - 07 milliseconds since boot */
+ uint16_t device_index; /* 08 - 09 */
+ uint16_t fw_conn_state; /* 0A - 0B */
+ uint8_t event_type; /* 0C - 0C */
+ uint8_t error_code; /* 0D - 0D */
+ uint16_t error_code_detail; /* 0E - 0F */
+ uint8_t num_consecutive_events; /* 10 - 10 */
+ uint8_t rsvd[3]; /* 11 - 13 */
+};
+
+/*************************************************************************
+ *
+ * IOCB Commands Structures and Definitions
+ *
+ *************************************************************************/
+#define IOCB_MAX_CDB_LEN 16 /* Bytes in a CBD */
+#define IOCB_MAX_SENSEDATA_LEN 32 /* Bytes of sense data */
+
+/* IOCB header structure */
+struct qla4_header {
+ uint8_t entryType;
+#define ET_STATUS 0x03
+#define ET_MARKER 0x04
+#define ET_CONT_T1 0x0A
+#define ET_STATUS_CONTINUATION 0x10
+#define ET_CMND_T3 0x19
+#define ET_PASSTHRU0 0x3A
+#define ET_PASSTHRU_STATUS 0x3C
+
+ uint8_t entryStatus;
+ uint8_t systemDefined;
+ uint8_t entryCount;
+
+ /* SyetemDefined definition */
+};
+
+/* Generic queue entry structure*/
+struct queue_entry {
+ uint8_t data[60];
+ uint32_t signature;
+
+};
+
+/* 64 bit addressing segment counts*/
+
+#define COMMAND_SEG_A64 1
+#define CONTINUE_SEG_A64 5
+
+/* 64 bit addressing segment definition*/
+
+struct data_seg_a64 {
+ struct {
+ uint32_t addrLow;
+ uint32_t addrHigh;
+
+ } base;
+
+ uint32_t count;
+
+};
+
+/* Command Type 3 entry structure*/
+
+struct command_t3_entry {
+ struct qla4_header hdr; /* 00-03 */
+
+ uint32_t handle; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t connection_id; /* 0A-0B */
+
+ uint8_t control_flags; /* 0C */
+
+ /* data direction (bits 5-6) */
+#define CF_WRITE 0x20
+#define CF_READ 0x40
+#define CF_NO_DATA 0x00
+
+ /* task attributes (bits 2-0) */
+#define CF_HEAD_TAG 0x03
+#define CF_ORDERED_TAG 0x02
+#define CF_SIMPLE_TAG 0x01
+
+ /* STATE FLAGS FIELD IS A PLACE HOLDER. THE FW WILL SET BITS
+ * IN THIS FIELD AS THE COMMAND IS PROCESSED. WHEN THE IOCB IS
+ * CHANGED TO AN IOSB THIS FIELD WILL HAVE THE STATE FLAGS SET
+ * PROPERLY.
+ */
+ uint8_t state_flags; /* 0D */
+ uint8_t cmdRefNum; /* 0E */
+ uint8_t reserved1; /* 0F */
+ uint8_t cdb[IOCB_MAX_CDB_LEN]; /* 10-1F */
+ struct scsi_lun lun; /* FCP LUN (BE). */
+ uint32_t cmdSeqNum; /* 28-2B */
+ uint16_t timeout; /* 2C-2D */
+ uint16_t dataSegCnt; /* 2E-2F */
+ uint32_t ttlByteCnt; /* 30-33 */
+ struct data_seg_a64 dataseg[COMMAND_SEG_A64]; /* 34-3F */
+
+};
+
+
+/* Continuation Type 1 entry structure*/
+struct continuation_t1_entry {
+ struct qla4_header hdr;
+
+ struct data_seg_a64 dataseg[CONTINUE_SEG_A64];
+
+};
+
+/* Parameterize for 64 or 32 bits */
+#define COMMAND_SEG COMMAND_SEG_A64
+#define CONTINUE_SEG CONTINUE_SEG_A64
+
+#define ET_COMMAND ET_CMND_T3
+#define ET_CONTINUE ET_CONT_T1
+
+/* Marker entry structure*/
+struct marker_entry {
+ struct qla4_header hdr; /* 00-03 */
+
+ uint32_t system_defined; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t modifier; /* 0A-0B */
+#define MM_LUN_RESET 0
+
+ uint16_t flags; /* 0C-0D */
+ uint16_t reserved1; /* 0E-0F */
+ struct scsi_lun lun; /* FCP LUN (BE). */
+ uint64_t reserved2; /* 18-1F */
+ uint64_t reserved3; /* 20-27 */
+ uint64_t reserved4; /* 28-2F */
+ uint64_t reserved5; /* 30-37 */
+ uint64_t reserved6; /* 38-3F */
+};
+
+/* Status entry structure*/
+struct status_entry {
+ struct qla4_header hdr; /* 00-03 */
+
+ uint32_t handle; /* 04-07 */
+
+ uint8_t scsiStatus; /* 08 */
+#define SCSI_CHECK_CONDITION 0x02
+
+ uint8_t iscsiFlags; /* 09 */
+#define ISCSI_FLAG_RESIDUAL_UNDER 0x02
+#define ISCSI_FLAG_RESIDUAL_OVER 0x04
+
+ uint8_t iscsiResponse; /* 0A */
+
+ uint8_t completionStatus; /* 0B */
+#define SCS_COMPLETE 0x00
+#define SCS_INCOMPLETE 0x01
+#define SCS_RESET_OCCURRED 0x04
+#define SCS_ABORTED 0x05
+#define SCS_TIMEOUT 0x06
+#define SCS_DATA_OVERRUN 0x07
+#define SCS_DATA_UNDERRUN 0x15
+#define SCS_QUEUE_FULL 0x1C
+#define SCS_DEVICE_UNAVAILABLE 0x28
+#define SCS_DEVICE_LOGGED_OUT 0x29
+
+ uint8_t reserved1; /* 0C */
+
+ /* state_flags MUST be at the same location as state_flags in
+ * the Command_T3/4_Entry */
+ uint8_t state_flags; /* 0D */
+
+ uint16_t senseDataByteCnt; /* 0E-0F */
+ uint32_t residualByteCnt; /* 10-13 */
+ uint32_t bidiResidualByteCnt; /* 14-17 */
+ uint32_t expSeqNum; /* 18-1B */
+ uint32_t maxCmdSeqNum; /* 1C-1F */
+ uint8_t senseData[IOCB_MAX_SENSEDATA_LEN]; /* 20-3F */
+
+};
+
+struct passthru0 {
+ struct qla4_header hdr; /* 00-03 */
+ uint32_t handle; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t connectionID; /* 0A-0B */
+#define ISNS_DEFAULT_SERVER_CONN_ID ((uint16_t)0x8000)
+
+ uint16_t controlFlags; /* 0C-0D */
+#define PT_FLAG_ETHERNET_FRAME 0x8000
+#define PT_FLAG_ISNS_PDU 0x8000
+#define PT_FLAG_SEND_BUFFER 0x0200
+#define PT_FLAG_WAIT_4_RESPONSE 0x0100
+
+ uint16_t timeout; /* 0E-0F */
+#define PT_DEFAULT_TIMEOUT 30 /* seconds */
+
+ struct data_seg_a64 outDataSeg64; /* 10-1B */
+ uint32_t res1; /* 1C-1F */
+ struct data_seg_a64 inDataSeg64; /* 20-2B */
+ uint8_t res2[20]; /* 2C-3F */
+};
+
+struct passthru_status {
+ struct qla4_header hdr; /* 00-03 */
+ uint32_t handle; /* 04-07 */
+ uint16_t target; /* 08-09 */
+ uint16_t connectionID; /* 0A-0B */
+
+ uint8_t completionStatus; /* 0C */
+#define PASSTHRU_STATUS_COMPLETE 0x01
+
+ uint8_t residualFlags; /* 0D */
+
+ uint16_t timeout; /* 0E-0F */
+ uint16_t portNumber; /* 10-11 */
+ uint8_t res1[10]; /* 12-1B */
+ uint32_t outResidual; /* 1C-1F */
+ uint8_t res2[12]; /* 20-2B */
+ uint32_t inResidual; /* 2C-2F */
+ uint8_t res4[16]; /* 30-3F */
+};
+
+#endif /* _QLA4X_FW_H */
diff --git a/drivers/scsi/qla4xxx/ql4_glbl.h b/drivers/scsi/qla4xxx/ql4_glbl.h
new file mode 100644
index 000000000000..2c803edf2de8
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_glbl.h
@@ -0,0 +1,78 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef __QLA4x_GBL_H
+#define __QLA4x_GBL_H
+
+int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port);
+int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb);
+int qla4xxx_initialize_adapter(struct scsi_qla_host * ha,
+ uint8_t renew_ddb_list);
+int qla4xxx_soft_reset(struct scsi_qla_host *ha);
+irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id);
+
+void qla4xxx_free_ddb_list(struct scsi_qla_host * ha);
+void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen);
+
+int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha);
+int qla4xxx_relogin_device(struct scsi_qla_host * ha,
+ struct ddb_entry * ddb_entry);
+int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+ int lun);
+int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+ uint32_t offset, uint32_t len);
+int qla4xxx_get_firmware_status(struct scsi_qla_host * ha);
+int qla4xxx_get_firmware_state(struct scsi_qla_host * ha);
+int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha);
+
+/* FIXME: Goodness! this really wants a small struct to hold the
+ * parameters. On x86 the args will get passed on the stack! */
+int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
+ uint16_t fw_ddb_index,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma,
+ uint32_t *num_valid_ddb_entries,
+ uint32_t *next_ddb_index,
+ uint32_t *fw_ddb_device_state,
+ uint32_t *conn_err_detail,
+ 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);
+
+void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry);
+u16 rd_nvram_word(struct scsi_qla_host * ha, int offset);
+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);
+int qla4xxx_process_ddb_changed(struct scsi_qla_host * ha,
+ uint32_t fw_ddb_index, uint32_t state);
+
+extern int qla4_extended_error_logging;
+extern int ql4xdiscoverywait;
+extern int ql4xdontresethba;
+#endif /* _QLA4x_GBL_H */
diff --git a/drivers/scsi/qla4xxx/ql4_init.c b/drivers/scsi/qla4xxx/ql4_init.c
new file mode 100644
index 000000000000..bb3a1c11f44c
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_init.c
@@ -0,0 +1,1340 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+/*
+ * QLogic ISP4xxx Hardware Support Function Prototypes.
+ */
+
+static void ql4xxx_set_mac_number(struct scsi_qla_host *ha)
+{
+ uint32_t value;
+ uint8_t func_number;
+ unsigned long flags;
+
+ /* Get the function number */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ value = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ func_number = (uint8_t) ((value >> 4) & 0x30);
+ switch (value & ISP_CONTROL_FN_MASK) {
+ case ISP_CONTROL_FN0_SCSI:
+ ha->mac_index = 1;
+ break;
+ case ISP_CONTROL_FN1_SCSI:
+ ha->mac_index = 3;
+ break;
+ default:
+ DEBUG2(printk("scsi%ld: %s: Invalid function number, "
+ "ispControlStatus = 0x%x\n", ha->host_no,
+ __func__, value));
+ break;
+ }
+ DEBUG2(printk("scsi%ld: %s: mac_index %d.\n", ha->host_no, __func__,
+ ha->mac_index));
+}
+
+/**
+ * qla4xxx_free_ddb - deallocate ddb
+ * @ha: pointer to host adapter structure.
+ * @ddb_entry: pointer to device database entry
+ *
+ * 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)
+{
+ /* Remove device entry from list */
+ list_del_init(&ddb_entry->list);
+
+ /* Remove device pointer from index mapping arrays */
+ ha->fw_ddb_index_map[ddb_entry->fw_ddb_index] =
+ (struct ddb_entry *) INVALID_ENTRY;
+ ha->tot_ddbs--;
+
+ /* Free memory and scsi-ml struct for device entry */
+ qla4xxx_destroy_sess(ddb_entry);
+}
+
+/**
+ * qla4xxx_free_ddb_list - deallocate all ddbs
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine deallocates and removes all devices on the sppecified adapter.
+ **/
+void qla4xxx_free_ddb_list(struct scsi_qla_host *ha)
+{
+ struct list_head *ptr;
+ struct ddb_entry *ddb_entry;
+
+ while (!list_empty(&ha->ddb_list)) {
+ ptr = ha->ddb_list.next;
+ /* Free memory for device entry and remove */
+ ddb_entry = list_entry(ptr, struct ddb_entry, list);
+ qla4xxx_free_ddb(ha, ddb_entry);
+ }
+}
+
+/**
+ * qla4xxx_init_rings - initialize hw queues
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine initializes the internal queues for the specified adapter.
+ * The QLA4010 requires us to restart the queues at index 0.
+ * The QLA4000 doesn't care, so just default to QLA4010's requirement.
+ **/
+int qla4xxx_init_rings(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+
+ /* Initialize request queue. */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ha->request_out = 0;
+ ha->request_in = 0;
+ ha->request_ptr = &ha->request_ring[ha->request_in];
+ ha->req_q_count = REQUEST_QUEUE_DEPTH;
+
+ /* Initialize response queue. */
+ ha->response_in = 0;
+ ha->response_out = 0;
+ ha->response_ptr = &ha->response_ring[ha->response_out];
+
+ /*
+ * Initialize DMA Shadow registers. The firmware is really supposed to
+ * take care of this, but on some uniprocessor systems, the shadow
+ * registers aren't cleared-- causing the interrupt_handler to think
+ * there are responses to be processed when there aren't.
+ */
+ ha->shadow_regs->req_q_out = __constant_cpu_to_le32(0);
+ ha->shadow_regs->rsp_q_in = __constant_cpu_to_le32(0);
+ wmb();
+
+ writel(0, &ha->reg->req_q_in);
+ writel(0, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_validate_mac_address - validate adapter MAC address(es)
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+static int qla4xxx_validate_mac_address(struct scsi_qla_host *ha)
+{
+ struct flash_sys_info *sys_info;
+ dma_addr_t sys_info_dma;
+ int status = QLA_ERROR;
+
+ sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info),
+ &sys_info_dma, GFP_KERNEL);
+ if (sys_info == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+
+ goto exit_validate_mac_no_free;
+ }
+ memset(sys_info, 0, sizeof(*sys_info));
+
+ /* Get flash sys info */
+ if (qla4xxx_get_flash(ha, sys_info_dma, FLASH_OFFSET_SYS_INFO,
+ sizeof(*sys_info)) != QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: get_flash FLASH_OFFSET_SYS_INFO "
+ "failed\n", ha->host_no, __func__));
+
+ goto exit_validate_mac;
+ }
+
+ /* Save M.A.C. address & serial_number */
+ memcpy(ha->my_mac, &sys_info->physAddr[0].address[0],
+ min(sizeof(ha->my_mac),
+ sizeof(sys_info->physAddr[0].address)));
+ memcpy(ha->serial_number, &sys_info->acSerialNumber,
+ min(sizeof(ha->serial_number),
+ sizeof(sys_info->acSerialNumber)));
+
+ status = QLA_SUCCESS;
+
+ exit_validate_mac:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
+ sys_info_dma);
+
+ exit_validate_mac_no_free:
+ return status;
+}
+
+/**
+ * qla4xxx_init_local_data - initialize adapter specific local data
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+static int qla4xxx_init_local_data(struct scsi_qla_host *ha)
+{
+ /* Initilize aen queue */
+ ha->aen_q_count = MAX_AEN_ENTRIES;
+
+ return qla4xxx_get_firmware_status(ha);
+}
+
+static int qla4xxx_fw_ready(struct scsi_qla_host *ha)
+{
+ uint32_t timeout_count;
+ int ready = 0;
+
+ DEBUG2(dev_info(&ha->pdev->dev, "Waiting for Firmware Ready..\n"));
+ for (timeout_count = ADAPTER_INIT_TOV; timeout_count > 0;
+ timeout_count--) {
+ if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
+ qla4xxx_get_dhcp_ip_address(ha);
+
+ /* Get firmware state. */
+ if (qla4xxx_get_firmware_state(ha) != QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: unable to get firmware "
+ "state\n", ha->host_no, __func__));
+ break;
+
+ }
+
+ if (ha->firmware_state & FW_STATE_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: an unrecoverable error has"
+ " occurred\n", ha->host_no, __func__));
+ break;
+
+ }
+ if (ha->firmware_state & FW_STATE_CONFIG_WAIT) {
+ /*
+ * The firmware has not yet been issued an Initialize
+ * Firmware command, so issue it now.
+ */
+ if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR)
+ break;
+
+ /* Go back and test for ready state - no wait. */
+ continue;
+ }
+
+ if (ha->firmware_state == FW_STATE_READY) {
+ DEBUG2(dev_info(&ha->pdev->dev, "Firmware Ready..\n"));
+ /* The firmware is ready to process SCSI commands. */
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: MEDIA TYPE - %s\n",
+ ha->host_no,
+ __func__, (ha->addl_fw_state &
+ FW_ADDSTATE_OPTICAL_MEDIA)
+ != 0 ? "OPTICAL" : "COPPER"));
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: DHCP STATE Enabled "
+ "%s\n",
+ ha->host_no, __func__,
+ (ha->addl_fw_state &
+ FW_ADDSTATE_DHCP_ENABLED) != 0 ?
+ "YES" : "NO"));
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: LINK %s\n",
+ ha->host_no, __func__,
+ (ha->addl_fw_state &
+ FW_ADDSTATE_LINK_UP) != 0 ?
+ "UP" : "DOWN"));
+ DEBUG2(dev_info(&ha->pdev->dev,
+ "scsi%ld: %s: iSNS Service "
+ "Started %s\n",
+ ha->host_no, __func__,
+ (ha->addl_fw_state &
+ FW_ADDSTATE_ISNS_SVC_ENABLED) != 0 ?
+ "YES" : "NO"));
+
+ ready = 1;
+ break;
+ }
+ DEBUG2(printk("scsi%ld: %s: waiting on fw, state=%x:%x - "
+ "seconds expired= %d\n", ha->host_no, __func__,
+ ha->firmware_state, ha->addl_fw_state,
+ timeout_count));
+ msleep(1000);
+ } /* end of for */
+
+ if (timeout_count <= 0)
+ DEBUG2(printk("scsi%ld: %s: FW Initialization timed out!\n",
+ ha->host_no, __func__));
+
+ if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS) {
+ DEBUG2(printk("scsi%ld: %s: FW is reporting its waiting to"
+ " grab an IP address from DHCP server\n",
+ ha->host_no, __func__));
+ ready = 1;
+ }
+
+ return ready;
+}
+
+/**
+ * qla4xxx_init_firmware - initializes the firmware.
+ * @ha: pointer to host adapter structure.
+ *
+ **/
+static int qla4xxx_init_firmware(struct scsi_qla_host *ha)
+{
+ int status = QLA_ERROR;
+
+ dev_info(&ha->pdev->dev, "Initializing firmware..\n");
+ if (qla4xxx_initialize_fw_cb(ha) == QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: Failed to initialize firmware "
+ "control block\n", ha->host_no, __func__));
+ return status;
+ }
+ if (!qla4xxx_fw_ready(ha))
+ return status;
+
+ set_bit(AF_ONLINE, &ha->flags);
+ return qla4xxx_get_firmware_status(ha);
+}
+
+static struct ddb_entry* qla4xxx_get_ddb_entry(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ struct ddb_entry *ddb_entry = NULL;
+ int found = 0;
+ uint32_t device_state;
+
+ /* Make sure the dma buffer is valid */
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (fw_ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+ return NULL;
+ }
+
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
+ fw_ddb_entry_dma, NULL, NULL,
+ &device_state, NULL, NULL, NULL) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
+ "fw_ddb_index %d\n", ha->host_no, __func__,
+ fw_ddb_index));
+ return NULL;
+ }
+
+ /* Allocate DDB if not already allocated. */
+ DEBUG2(printk("scsi%ld: %s: Looking for ddb[%d]\n", ha->host_no,
+ __func__, fw_ddb_index));
+ list_for_each_entry(ddb_entry, &ha->ddb_list, list) {
+ if (memcmp(ddb_entry->iscsi_name, fw_ddb_entry->iscsiName,
+ ISCSI_NAME_SIZE) == 0) {
+ found++;
+ break;
+ }
+ }
+
+ if (!found) {
+ DEBUG2(printk("scsi%ld: %s: ddb[%d] not found - allocating "
+ "new ddb\n", ha->host_no, __func__,
+ fw_ddb_index));
+ ddb_entry = qla4xxx_alloc_ddb(ha, fw_ddb_index);
+ }
+
+ /* if not found allocate new ddb */
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry), fw_ddb_entry,
+ fw_ddb_entry_dma);
+
+ return ddb_entry;
+}
+
+/**
+ * qla4xxx_update_ddb_entry - update driver's internal ddb
+ * @ha: pointer to host adapter structure.
+ * @ddb_entry: pointer to device database structure to be filled
+ * @fw_ddb_index: index of the ddb entry in fw ddb table
+ *
+ * This routine updates the driver's internal device database entry
+ * with information retrieved from the firmware's device database
+ * entry for the specified device. The ddb_entry->fw_ddb_index field
+ * 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)
+{
+ struct dev_db_entry *fw_ddb_entry = NULL;
+ dma_addr_t fw_ddb_entry_dma;
+ int status = QLA_ERROR;
+
+ if (ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: ddb_entry is NULL\n", ha->host_no,
+ __func__));
+ goto exit_update_ddb;
+ }
+
+ /* Make sure the dma buffer is valid */
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (fw_ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+
+ goto exit_update_ddb;
+ }
+
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, fw_ddb_entry,
+ fw_ddb_entry_dma, NULL, NULL,
+ &ddb_entry->fw_ddb_device_state, NULL,
+ &ddb_entry->tcp_source_port_num,
+ &ddb_entry->connection_id) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: failed get_ddb_entry for "
+ "fw_ddb_index %d\n", ha->host_no, __func__,
+ fw_ddb_index));
+
+ goto exit_update_ddb;
+ }
+
+ status = QLA_SUCCESS;
+ ddb_entry->target_session_id = le16_to_cpu(fw_ddb_entry->TSID);
+ ddb_entry->task_mgmt_timeout =
+ le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
+ ddb_entry->CmdSn = 0;
+ ddb_entry->exe_throttle = le16_to_cpu(fw_ddb_entry->exeThrottle);
+ ddb_entry->default_relogin_timeout =
+ le16_to_cpu(fw_ddb_entry->taskMngmntTimeout);
+ ddb_entry->default_time2wait = le16_to_cpu(fw_ddb_entry->minTime2Wait);
+
+ /* Update index in case it changed */
+ ddb_entry->fw_ddb_index = fw_ddb_index;
+ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
+
+ ddb_entry->port = le16_to_cpu(fw_ddb_entry->portNumber);
+ ddb_entry->tpgt = le32_to_cpu(fw_ddb_entry->TargetPortalGroup);
+ memcpy(&ddb_entry->iscsi_name[0], &fw_ddb_entry->iscsiName[0],
+ min(sizeof(ddb_entry->iscsi_name),
+ sizeof(fw_ddb_entry->iscsiName)));
+ memcpy(&ddb_entry->ip_addr[0], &fw_ddb_entry->ipAddr[0],
+ min(sizeof(ddb_entry->ip_addr), sizeof(fw_ddb_entry->ipAddr)));
+
+ DEBUG2(printk("scsi%ld: %s: ddb[%d] - State= %x status= %d.\n",
+ ha->host_no, __func__, fw_ddb_index,
+ ddb_entry->fw_ddb_device_state, status));
+
+ exit_update_ddb:
+ if (fw_ddb_entry)
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+
+ return status;
+}
+
+/**
+ * qla4xxx_alloc_ddb - allocate device database entry
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ *
+ * 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)
+{
+ struct ddb_entry *ddb_entry;
+
+ DEBUG2(printk("scsi%ld: %s: fw_ddb_index [%d]\n", ha->host_no,
+ __func__, fw_ddb_index));
+
+ ddb_entry = qla4xxx_alloc_sess(ha);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
+ "to add fw_ddb_index [%d]\n",
+ ha->host_no, __func__, fw_ddb_index));
+ return ddb_entry;
+ }
+
+ ddb_entry->fw_ddb_index = fw_ddb_index;
+ atomic_set(&ddb_entry->port_down_timer, ha->port_down_retry_count);
+ atomic_set(&ddb_entry->retry_relogin_timer, INVALID_ENTRY);
+ atomic_set(&ddb_entry->relogin_timer, 0);
+ atomic_set(&ddb_entry->relogin_retry_count, 0);
+ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+ list_add_tail(&ddb_entry->list, &ha->ddb_list);
+ ha->fw_ddb_index_map[fw_ddb_index] = ddb_entry;
+ ha->tot_ddbs++;
+
+ return ddb_entry;
+}
+
+/**
+ * qla4xxx_configure_ddbs - builds driver ddb list
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine searches for all valid firmware ddb entries and builds
+ * an internal ddb list. Ddbs that are considered valid are those with
+ * a device state of SESSION_ACTIVE.
+ **/
+static int qla4xxx_build_ddb_list(struct scsi_qla_host *ha)
+{
+ int status = QLA_SUCCESS;
+ uint32_t fw_ddb_index = 0;
+ uint32_t next_fw_ddb_index = 0;
+ uint32_t ddb_state;
+ uint32_t conn_err, err_code;
+ struct ddb_entry *ddb_entry;
+
+ dev_info(&ha->pdev->dev, "Initializing DDBs ...\n");
+ for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES;
+ fw_ddb_index = next_fw_ddb_index) {
+ /* First, let's see if a device exists here */
+ if (qla4xxx_get_fwddb_entry(ha, fw_ddb_index, NULL, 0, NULL,
+ &next_fw_ddb_index, &ddb_state,
+ &conn_err, NULL, NULL) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: get_ddb_entry, "
+ "fw_ddb_index %d failed", ha->host_no,
+ __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+
+ DEBUG2(printk("scsi%ld: %s: Getting DDB[%d] ddbstate=0x%x, "
+ "next_fw_ddb_index=%d.\n", ha->host_no, __func__,
+ fw_ddb_index, ddb_state, next_fw_ddb_index));
+
+ /* Issue relogin, if necessary. */
+ if (ddb_state == DDB_DS_SESSION_FAILED ||
+ ddb_state == DDB_DS_NO_CONNECTION_ACTIVE) {
+ /* Try and login to device */
+ DEBUG2(printk("scsi%ld: %s: Login to DDB[%d]\n",
+ ha->host_no, __func__, fw_ddb_index));
+ err_code = ((conn_err & 0x00ff0000) >> 16);
+ if (err_code == 0x1c || err_code == 0x06) {
+ DEBUG2(printk("scsi%ld: %s send target "
+ "completed "
+ "or access denied failure\n",
+ ha->host_no, __func__));
+ } else
+ qla4xxx_set_ddb_entry(ha, fw_ddb_index, 0);
+ }
+
+ if (ddb_state != DDB_DS_SESSION_ACTIVE)
+ goto next_one;
+ /*
+ * if fw_ddb with session active state found,
+ * add to ddb_list
+ */
+ DEBUG2(printk("scsi%ld: %s: DDB[%d] added to list\n",
+ ha->host_no, __func__, fw_ddb_index));
+
+ /* Add DDB to internal our ddb list. */
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate memory "
+ "for device at fw_ddb_index %d\n",
+ ha->host_no, __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+ /* Fill in the device structure */
+ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
+ QLA_ERROR) {
+ ha->fw_ddb_index_map[fw_ddb_index] =
+ (struct ddb_entry *)INVALID_ENTRY;
+
+
+ DEBUG2(printk("scsi%ld: %s: update_ddb_entry failed "
+ "for fw_ddb_index %d.\n",
+ ha->host_no, __func__, fw_ddb_index));
+ return QLA_ERROR;
+ }
+
+next_one:
+ /* We know we've reached the last device when
+ * next_fw_ddb_index is 0 */
+ if (next_fw_ddb_index == 0)
+ break;
+ }
+
+ dev_info(&ha->pdev->dev, "DDB list done..\n");
+
+ return status;
+}
+
+struct qla4_relog_scan {
+ int halt_wait;
+ uint32_t conn_err;
+ uint32_t err_code;
+ uint32_t fw_ddb_index;
+ uint32_t next_fw_ddb_index;
+ uint32_t fw_ddb_device_state;
+};
+
+static int qla4_test_rdy(struct scsi_qla_host *ha, struct qla4_relog_scan *rs)
+{
+ struct ddb_entry *ddb_entry;
+
+ /*
+ * Don't want to do a relogin if connection
+ * error is 0x1c.
+ */
+ rs->err_code = ((rs->conn_err & 0x00ff0000) >> 16);
+ if (rs->err_code == 0x1c || rs->err_code == 0x06) {
+ DEBUG2(printk(
+ "scsi%ld: %s send target"
+ " completed or "
+ "access denied failure\n",
+ ha->host_no, __func__));
+ } else {
+ /* We either have a device that is in
+ * the process of relogging in or a
+ * device that is waiting to be
+ * relogged in */
+ rs->halt_wait = 0;
+
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha,
+ rs->fw_ddb_index);
+ if (ddb_entry == NULL)
+ return QLA_ERROR;
+
+ if (ddb_entry->dev_scan_wait_to_start_relogin != 0
+ && time_after_eq(jiffies,
+ ddb_entry->
+ dev_scan_wait_to_start_relogin))
+ {
+ ddb_entry->dev_scan_wait_to_start_relogin = 0;
+ qla4xxx_set_ddb_entry(ha, rs->fw_ddb_index, 0);
+ }
+ }
+ return QLA_SUCCESS;
+}
+
+static int qla4_scan_for_relogin(struct scsi_qla_host *ha,
+ struct qla4_relog_scan *rs)
+{
+ int error;
+
+ /* scan for relogins
+ * ----------------- */
+ for (rs->fw_ddb_index = 0; rs->fw_ddb_index < MAX_DDB_ENTRIES;
+ rs->fw_ddb_index = rs->next_fw_ddb_index) {
+ if (qla4xxx_get_fwddb_entry(ha, rs->fw_ddb_index, NULL, 0,
+ NULL, &rs->next_fw_ddb_index,
+ &rs->fw_ddb_device_state,
+ &rs->conn_err, NULL, NULL)
+ == QLA_ERROR)
+ return QLA_ERROR;
+
+ if (rs->fw_ddb_device_state == DDB_DS_LOGIN_IN_PROCESS)
+ rs->halt_wait = 0;
+
+ if (rs->fw_ddb_device_state == DDB_DS_SESSION_FAILED ||
+ rs->fw_ddb_device_state == DDB_DS_NO_CONNECTION_ACTIVE) {
+ error = qla4_test_rdy(ha, rs);
+ if (error)
+ return error;
+ }
+
+ /* We know we've reached the last device when
+ * next_fw_ddb_index is 0 */
+ if (rs->next_fw_ddb_index == 0)
+ break;
+ }
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_devices_ready - wait for target devices to be logged in
+ * @ha: pointer to adapter structure
+ *
+ * This routine waits up to ql4xdiscoverywait seconds
+ * F/W database during driver load time.
+ **/
+static int qla4xxx_devices_ready(struct scsi_qla_host *ha)
+{
+ int error;
+ unsigned long discovery_wtime;
+ struct qla4_relog_scan rs;
+
+ discovery_wtime = jiffies + (ql4xdiscoverywait * HZ);
+
+ DEBUG(printk("Waiting (%d) for devices ...\n", ql4xdiscoverywait));
+ do {
+ /* poll for AEN. */
+ qla4xxx_get_firmware_state(ha);
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags)) {
+ /* Set time-between-relogin timer */
+ qla4xxx_process_aen(ha, RELOGIN_DDB_CHANGED_AENS);
+ }
+
+ /* if no relogins active or needed, halt discvery wait */
+ rs.halt_wait = 1;
+
+ error = qla4_scan_for_relogin(ha, &rs);
+
+ if (rs.halt_wait) {
+ DEBUG2(printk("scsi%ld: %s: Delay halted. Devices "
+ "Ready.\n", ha->host_no, __func__));
+ return QLA_SUCCESS;
+ }
+
+ msleep(2000);
+ } while (!time_after_eq(jiffies, discovery_wtime));
+
+ DEBUG3(qla4xxx_get_conn_event_log(ha));
+
+ return QLA_SUCCESS;
+}
+
+static void qla4xxx_flush_AENS(struct scsi_qla_host *ha)
+{
+ unsigned long wtime;
+
+ /* Flush the 0x8014 AEN from the firmware as a result of
+ * Auto connect. We are basically doing get_firmware_ddb()
+ * to determine whether we need to log back in or not.
+ * Trying to do a set ddb before we have processed 0x8014
+ * will result in another set_ddb() for the same ddb. In other
+ * words there will be stale entries in the aen_q.
+ */
+ wtime = jiffies + (2 * HZ);
+ do {
+ if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS)
+ if (ha->firmware_state & (BIT_2 | BIT_0))
+ return;
+
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+
+ msleep(1000);
+ } while (!time_after_eq(jiffies, wtime));
+
+}
+
+static int qla4xxx_initialize_ddb_list(struct scsi_qla_host *ha)
+{
+ uint16_t fw_ddb_index;
+ int status = QLA_SUCCESS;
+
+ /* free the ddb list if is not empty */
+ if (!list_empty(&ha->ddb_list))
+ qla4xxx_free_ddb_list(ha);
+
+ for (fw_ddb_index = 0; fw_ddb_index < MAX_DDB_ENTRIES; fw_ddb_index++)
+ ha->fw_ddb_index_map[fw_ddb_index] =
+ (struct ddb_entry *)INVALID_ENTRY;
+
+ ha->tot_ddbs = 0;
+
+ qla4xxx_flush_AENS(ha);
+
+ /*
+ * First perform device discovery for active
+ * fw ddb indexes and build
+ * ddb list.
+ */
+ if ((status = qla4xxx_build_ddb_list(ha)) == QLA_ERROR)
+ return status;
+
+ /* Wait for an AEN */
+ qla4xxx_devices_ready(ha);
+
+ /*
+ * Targets can come online after the inital discovery, so processing
+ * the aens here will catch them.
+ */
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
+ qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
+
+ return status;
+}
+
+/**
+ * qla4xxx_update_ddb_list - update the driver ddb list
+ * @ha: pointer to host adapter structure.
+ *
+ * This routine obtains device information from the F/W database after
+ * firmware or adapter resets. The device table is preserved.
+ **/
+int qla4xxx_reinitialize_ddb_list(struct scsi_qla_host *ha)
+{
+ int status = QLA_SUCCESS;
+ struct ddb_entry *ddb_entry, *detemp;
+
+ /* Update the device information for all devices. */
+ list_for_each_entry_safe(ddb_entry, detemp, &ha->ddb_list, list) {
+ qla4xxx_update_ddb_entry(ha, ddb_entry,
+ ddb_entry->fw_ddb_index);
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
+ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+ DEBUG2(printk ("scsi%ld: %s: ddb index [%d] marked "
+ "ONLINE\n", ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ } else if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+ }
+ return status;
+}
+
+/**
+ * qla4xxx_relogin_device - re-establish session
+ * @ha: Pointer to host adapter structure.
+ * @ddb_entry: Pointer to device database entry
+ *
+ * This routine does a session relogin with the specified device.
+ * The ddb entry must be assigned prior to making this call.
+ **/
+int qla4xxx_relogin_device(struct scsi_qla_host *ha,
+ struct ddb_entry * ddb_entry)
+{
+ uint16_t relogin_timer;
+
+ relogin_timer = max(ddb_entry->default_relogin_timeout,
+ (uint16_t)RELOGIN_TOV);
+ atomic_set(&ddb_entry->relogin_timer, relogin_timer);
+
+ DEBUG2(printk("scsi%ld: Relogin index [%d]. TOV=%d\n", ha->host_no,
+ ddb_entry->fw_ddb_index, relogin_timer));
+
+ qla4xxx_set_ddb_entry(ha, ddb_entry->fw_ddb_index, 0);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4010_get_topcat_presence - check if it is QLA4040 TopCat Chip
+ * @ha: Pointer to host adapter structure.
+ *
+ **/
+static int qla4010_get_topcat_presence(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+ uint16_t topcat;
+
+ if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS)
+ return QLA_ERROR;
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ topcat = rd_nvram_word(ha, offsetof(struct eeprom_data,
+ isp4010.topcat));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if ((topcat & TOPCAT_MASK) == TOPCAT_PRESENT)
+ set_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags);
+ else
+ clear_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags);
+ ql4xxx_unlock_nvram(ha);
+ return QLA_SUCCESS;
+}
+
+
+static int qla4xxx_config_nvram(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+ union external_hw_config_reg extHwConfig;
+
+ DEBUG2(printk("scsi%ld: %s: Get EEProm parameters \n", ha->host_no,
+ __func__));
+ if (ql4xxx_lock_flash(ha) != QLA_SUCCESS)
+ return (QLA_ERROR);
+ if (ql4xxx_lock_nvram(ha) != QLA_SUCCESS) {
+ ql4xxx_unlock_flash(ha);
+ return (QLA_ERROR);
+ }
+
+ /* Get EEPRom Parameters from NVRAM and validate */
+ dev_info(&ha->pdev->dev, "Configuring NVRAM ...\n");
+ if (qla4xxx_is_nvram_configuration_valid(ha) == QLA_SUCCESS) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ extHwConfig.Asuint32_t =
+ rd_nvram_word(ha, eeprom_ext_hw_conf_offset(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ } else {
+ /*
+ * QLogic adapters should always have a valid NVRAM.
+ * If not valid, do not load.
+ */
+ dev_warn(&ha->pdev->dev,
+ "scsi%ld: %s: EEProm checksum invalid. "
+ "Please update your EEPROM\n", ha->host_no,
+ __func__);
+
+ /* set defaults */
+ if (is_qla4010(ha))
+ extHwConfig.Asuint32_t = 0x1912;
+ else if (is_qla4022(ha))
+ extHwConfig.Asuint32_t = 0x0023;
+ }
+ DEBUG(printk("scsi%ld: %s: Setting extHwConfig to 0xFFFF%04x\n",
+ ha->host_no, __func__, extHwConfig.Asuint32_t));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel((0xFFFF << 16) | extHwConfig.Asuint32_t, isp_ext_hw_conf(ha));
+ readl(isp_ext_hw_conf(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ ql4xxx_unlock_nvram(ha);
+ ql4xxx_unlock_flash(ha);
+
+ return (QLA_SUCCESS);
+}
+
+static void qla4x00_pci_config(struct scsi_qla_host *ha)
+{
+ uint16_t w, mwi;
+
+ dev_info(&ha->pdev->dev, "Configuring PCI space...\n");
+
+ pci_set_master(ha->pdev);
+ mwi = 0;
+ if (pci_set_mwi(ha->pdev))
+ mwi = PCI_COMMAND_INVALIDATE;
+ /*
+ * We want to respect framework's setting of PCI configuration space
+ * command register and also want to make sure that all bits of
+ * interest to us are properly set in command register.
+ */
+ pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+ w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+ w &= ~PCI_COMMAND_INTX_DISABLE;
+ pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+}
+
+static int qla4xxx_start_firmware_from_flash(struct scsi_qla_host *ha)
+{
+ int status = QLA_ERROR;
+ uint32_t max_wait_time;
+ unsigned long flags;
+ uint32_t mbox_status;
+
+ dev_info(&ha->pdev->dev, "Starting firmware ...\n");
+
+ /*
+ * Start firmware from flash ROM
+ *
+ * WORKAROUND: Stuff a non-constant value that the firmware can
+ * use as a seed for a random number generator in MB7 prior to
+ * setting BOOT_ENABLE. Fixes problem where the TCP
+ * connections use the same TCP ports after each reboot,
+ * causing some connections to not get re-established.
+ */
+ DEBUG(printk("scsi%d: %s: Start firmware from flash ROM\n",
+ ha->host_no, __func__));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(jiffies, &ha->reg->mailbox[7]);
+ if (is_qla4022(ha))
+ writel(set_rmask(NVR_WRITE_ENABLE),
+ &ha->reg->u1.isp4022.nvram);
+
+ writel(set_rmask(CSR_BOOT_ENABLE), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Wait for firmware to come UP. */
+ max_wait_time = FIRMWARE_UP_TOV * 4;
+ do {
+ uint32_t ctrl_status;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ mbox_status = readw(&ha->reg->mailbox[0]);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (ctrl_status & set_rmask(CSR_SCSI_PROCESSOR_INTR))
+ break;
+ if (mbox_status == MBOX_STS_COMMAND_COMPLETE)
+ break;
+
+ DEBUG2(printk("scsi%ld: %s: Waiting for boot firmware to "
+ "complete... ctrl_sts=0x%x, remaining=%d\n",
+ ha->host_no, __func__, ctrl_status,
+ max_wait_time));
+
+ msleep(250);
+ } while ((max_wait_time--));
+
+ if (mbox_status == MBOX_STS_COMMAND_COMPLETE) {
+ DEBUG(printk("scsi%ld: %s: Firmware has started\n",
+ ha->host_no, __func__));
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ status = QLA_SUCCESS;
+ } else {
+ printk(KERN_INFO "scsi%ld: %s: Boot firmware failed "
+ "- mbox status 0x%x\n", ha->host_no, __func__,
+ mbox_status);
+ status = QLA_ERROR;
+ }
+ return status;
+}
+
+static int ql4xxx_lock_drvr_wait(struct scsi_qla_host *a)
+{
+#define QL4_LOCK_DRVR_WAIT 300
+#define QL4_LOCK_DRVR_SLEEP 100
+
+ int drvr_wait = QL4_LOCK_DRVR_WAIT;
+ while (drvr_wait) {
+ if (ql4xxx_lock_drvr(a) == 0) {
+ msleep(QL4_LOCK_DRVR_SLEEP);
+ if (drvr_wait) {
+ DEBUG2(printk("scsi%ld: %s: Waiting for "
+ "Global Init Semaphore...n",
+ a->host_no,
+ __func__));
+ }
+ drvr_wait -= QL4_LOCK_DRVR_SLEEP;
+ } else {
+ DEBUG2(printk("scsi%ld: %s: Global Init Semaphore "
+ "acquired.n", a->host_no, __func__));
+ return QLA_SUCCESS;
+ }
+ }
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_start_firmware - starts qla4xxx firmware
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine performs the neccessary steps to start the firmware for
+ * the QLA4010 adapter.
+ **/
+static int qla4xxx_start_firmware(struct scsi_qla_host *ha)
+{
+ unsigned long flags = 0;
+ uint32_t mbox_status;
+ int status = QLA_ERROR;
+ int soft_reset = 1;
+ int config_chip = 0;
+
+ if (is_qla4010(ha)){
+ if (qla4010_get_topcat_presence(ha) != QLA_SUCCESS)
+ return QLA_ERROR;
+ }
+
+ if (is_qla4022(ha))
+ ql4xxx_set_mac_number(ha);
+
+ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
+ return QLA_ERROR;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ DEBUG2(printk("scsi%ld: %s: port_ctrl = 0x%08X\n", ha->host_no,
+ __func__, readw(isp_port_ctrl(ha))));
+ DEBUG(printk("scsi%ld: %s: port_status = 0x%08X\n", ha->host_no,
+ __func__, readw(isp_port_status(ha))));
+
+ /* Is Hardware already initialized? */
+ if ((readw(isp_port_ctrl(ha)) & 0x8000) != 0) {
+ DEBUG(printk("scsi%ld: %s: Hardware has already been "
+ "initialized\n", ha->host_no, __func__));
+
+ /* Receive firmware boot acknowledgement */
+ mbox_status = readw(&ha->reg->mailbox[0]);
+
+ DEBUG2(printk("scsi%ld: %s: H/W Config complete - mbox[0]= "
+ "0x%x\n", ha->host_no, __func__, mbox_status));
+
+ /* Is firmware already booted? */
+ if (mbox_status == 0) {
+ /* F/W not running, must be config by net driver */
+ config_chip = 1;
+ soft_reset = 0;
+ } else {
+ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if (qla4xxx_get_firmware_state(ha) == QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: Get firmware "
+ "state -- state = 0x%x\n",
+ ha->host_no,
+ __func__, ha->firmware_state));
+ /* F/W is running */
+ if (ha->firmware_state &
+ FW_STATE_CONFIG_WAIT) {
+ DEBUG2(printk("scsi%ld: %s: Firmware "
+ "in known state -- "
+ "config and "
+ "boot, state = 0x%x\n",
+ ha->host_no, __func__,
+ ha->firmware_state));
+ config_chip = 1;
+ soft_reset = 0;
+ }
+ } else {
+ DEBUG2(printk("scsi%ld: %s: Firmware in "
+ "unknown state -- resetting,"
+ " state = "
+ "0x%x\n", ha->host_no, __func__,
+ ha->firmware_state));
+ }
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ }
+ } else {
+ DEBUG(printk("scsi%ld: %s: H/W initialization hasn't been "
+ "started - resetting\n", ha->host_no, __func__));
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ DEBUG(printk("scsi%ld: %s: Flags soft_rest=%d, config= %d\n ",
+ ha->host_no, __func__, soft_reset, config_chip));
+ if (soft_reset) {
+ DEBUG(printk("scsi%ld: %s: Issue Soft Reset\n", ha->host_no,
+ __func__));
+ status = qla4xxx_soft_reset(ha);
+ if (status == QLA_ERROR) {
+ DEBUG(printk("scsi%d: %s: Soft Reset failed!\n",
+ ha->host_no, __func__));
+ ql4xxx_unlock_drvr(ha);
+ return QLA_ERROR;
+ }
+ config_chip = 1;
+
+ /* Reset clears the semaphore, so aquire again */
+ if (ql4xxx_lock_drvr_wait(ha) != QLA_SUCCESS)
+ return QLA_ERROR;
+ }
+
+ if (config_chip) {
+ if ((status = qla4xxx_config_nvram(ha)) == QLA_SUCCESS)
+ status = qla4xxx_start_firmware_from_flash(ha);
+ }
+
+ ql4xxx_unlock_drvr(ha);
+ if (status == QLA_SUCCESS) {
+ qla4xxx_get_fw_version(ha);
+ if (test_and_clear_bit(AF_GET_CRASH_RECORD, &ha->flags))
+ qla4xxx_get_crash_record(ha);
+ } else {
+ DEBUG(printk("scsi%ld: %s: Firmware has NOT started\n",
+ ha->host_no, __func__));
+ }
+ return status;
+}
+
+
+/**
+ * qla4xxx_initialize_adapter - initiailizes hba
+ * @ha: Pointer to host adapter structure.
+ * @renew_ddb_list: Indicates what to do with the adapter's ddb list
+ * after adapter recovery has completed.
+ * 0=preserve ddb list, 1=destroy and rebuild ddb list
+ *
+ * This routine parforms all of the steps necessary to initialize the adapter.
+ *
+ **/
+int qla4xxx_initialize_adapter(struct scsi_qla_host *ha,
+ uint8_t renew_ddb_list)
+{
+ int status = QLA_ERROR;
+ int8_t ip_address[IP_ADDR_LEN] = {0} ;
+
+ ha->eeprom_cmd_data = 0;
+
+ qla4x00_pci_config(ha);
+
+ qla4xxx_disable_intrs(ha);
+
+ /* Initialize the Host adapter request/response queues and firmware */
+ if (qla4xxx_start_firmware(ha) == QLA_ERROR)
+ return status;
+
+ if (qla4xxx_validate_mac_address(ha) == QLA_ERROR)
+ return status;
+
+ if (qla4xxx_init_local_data(ha) == QLA_ERROR)
+ return status;
+
+ status = qla4xxx_init_firmware(ha);
+ if (status == QLA_ERROR)
+ return status;
+
+ /*
+ * FW is waiting to get an IP address from DHCP server: Skip building
+ * the ddb_list and wait for DHCP lease acquired aen to come in
+ * followed by 0x8014 aen" to trigger the tgt discovery process.
+ */
+ if (ha->firmware_state & FW_STATE_DHCP_IN_PROGRESS)
+ return status;
+
+ /* Skip device discovery if ip and subnet is zero */
+ if (memcmp(ha->ip_address, ip_address, IP_ADDR_LEN) == 0 ||
+ memcmp(ha->subnet_mask, ip_address, IP_ADDR_LEN) == 0)
+ return status;
+
+ if (renew_ddb_list == PRESERVE_DDB_LIST) {
+ /*
+ * We want to preserve lun states (i.e. suspended, etc.)
+ * for recovery initiated by the driver. So just update
+ * the device states for the existing ddb_list.
+ */
+ qla4xxx_reinitialize_ddb_list(ha);
+ } else if (renew_ddb_list == REBUILD_DDB_LIST) {
+ /*
+ * We want to build the ddb_list from scratch during
+ * driver initialization and recovery initiated by the
+ * INT_HBA_RESET IOCTL.
+ */
+ status = qla4xxx_initialize_ddb_list(ha);
+ if (status == QLA_ERROR) {
+ DEBUG2(printk("%s(%ld) Error occurred during build"
+ "ddb list\n", __func__, ha->host_no));
+ goto exit_init_hba;
+ }
+
+ }
+ if (!ha->tot_ddbs) {
+ DEBUG2(printk("scsi%ld: Failed to initialize devices or none "
+ "present in Firmware device database\n",
+ ha->host_no));
+ }
+
+ exit_init_hba:
+ return status;
+
+}
+
+/**
+ * qla4xxx_add_device_dynamically - ddb addition due to an AEN
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ *
+ * This routine processes adds a device as a result of an 8014h AEN.
+ **/
+static void qla4xxx_add_device_dynamically(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index)
+{
+ struct ddb_entry * ddb_entry;
+
+ /* First allocate a device structure */
+ ddb_entry = qla4xxx_get_ddb_entry(ha, fw_ddb_index);
+ if (ddb_entry == NULL) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: Unable to allocate memory to add "
+ "fw_ddb_index %d\n", ha->host_no, fw_ddb_index));
+ return;
+ }
+
+ if (qla4xxx_update_ddb_entry(ha, ddb_entry, fw_ddb_index) ==
+ QLA_ERROR) {
+ ha->fw_ddb_index_map[fw_ddb_index] =
+ (struct ddb_entry *)INVALID_ENTRY;
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: failed to add new device at index "
+ "[%d]\n Unable to retrieve fw ddb entry\n",
+ ha->host_no, fw_ddb_index));
+ qla4xxx_free_ddb(ha, ddb_entry);
+ return;
+ }
+
+ if (qla4xxx_add_sess(ddb_entry)) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: failed to add new device at index "
+ "[%d]\n Unable to add connection and session\n",
+ ha->host_no, fw_ddb_index));
+ qla4xxx_free_ddb(ha, ddb_entry);
+ }
+}
+
+/**
+ * qla4xxx_process_ddb_changed - process ddb state change
+ * @ha - Pointer to host adapter structure.
+ * @fw_ddb_index - Firmware's device database index
+ * @state - Device state
+ *
+ * This routine processes a Decive Database Changed AEN Event.
+ **/
+int qla4xxx_process_ddb_changed(struct scsi_qla_host *ha,
+ uint32_t fw_ddb_index, uint32_t state)
+{
+ struct ddb_entry * ddb_entry;
+ uint32_t old_fw_ddb_device_state;
+
+ /* check for out of range index */
+ if (fw_ddb_index >= MAX_DDB_ENTRIES)
+ return QLA_ERROR;
+
+ /* Get the corresponging ddb entry */
+ ddb_entry = qla4xxx_lookup_ddb_by_fw_index(ha, fw_ddb_index);
+ /* Device does not currently exist in our database. */
+ if (ddb_entry == NULL) {
+ if (state == DDB_DS_SESSION_ACTIVE)
+ qla4xxx_add_device_dynamically(ha, fw_ddb_index);
+ return QLA_SUCCESS;
+ }
+
+ /* Device already exists in our database. */
+ old_fw_ddb_device_state = ddb_entry->fw_ddb_device_state;
+ DEBUG2(printk("scsi%ld: %s DDB - old state= 0x%x, new state=0x%x for "
+ "index [%d]\n", ha->host_no, __func__,
+ ddb_entry->fw_ddb_device_state, state, fw_ddb_index));
+ if (old_fw_ddb_device_state == state &&
+ state == DDB_DS_SESSION_ACTIVE) {
+ /* Do nothing, state not changed. */
+ return QLA_SUCCESS;
+ }
+
+ ddb_entry->fw_ddb_device_state = state;
+ /* Device is back online. */
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE) {
+ atomic_set(&ddb_entry->port_down_timer,
+ ha->port_down_retry_count);
+ atomic_set(&ddb_entry->state, DDB_STATE_ONLINE);
+ atomic_set(&ddb_entry->relogin_retry_count, 0);
+ atomic_set(&ddb_entry->relogin_timer, 0);
+ clear_bit(DF_RELOGIN, &ddb_entry->flags);
+ clear_bit(DF_NO_RELOGIN, &ddb_entry->flags);
+ iscsi_if_create_session_done(ddb_entry->conn);
+ /*
+ * Change the lun state to READY in case the lun TIMEOUT before
+ * the device came back.
+ */
+ } else {
+ /* Device went away, try to relogin. */
+ /* Mark device missing */
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+ /*
+ * Relogin if device state changed to a not active state.
+ * However, do not relogin if this aen is a result of an IOCTL
+ * logout (DF_NO_RELOGIN) or if this is a discovered device.
+ */
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_FAILED &&
+ !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
+ !test_bit(DF_NO_RELOGIN, &ddb_entry->flags) &&
+ !test_bit(DF_ISNS_DISCOVERED, &ddb_entry->flags)) {
+ /*
+ * This triggers a relogin. After the relogin_timer
+ * expires, the relogin gets scheduled. We must wait a
+ * minimum amount of time since receiving an 0x8014 AEN
+ * with failed device_state or a logout response before
+ * we can issue another relogin.
+ */
+ /* Firmware padds this timeout: (time2wait +1).
+ * Driver retry to login should be longer than F/W.
+ * Otherwise F/W will fail
+ * set_ddb() mbx cmd with 0x4005 since it still
+ * counting down its time2wait.
+ */
+ atomic_set(&ddb_entry->relogin_timer, 0);
+ atomic_set(&ddb_entry->retry_relogin_timer,
+ ddb_entry->default_time2wait + 4);
+ }
+ }
+
+ return QLA_SUCCESS;
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_inline.h b/drivers/scsi/qla4xxx/ql4_inline.h
new file mode 100644
index 000000000000..0d61797af7da
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_inline.h
@@ -0,0 +1,84 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+/*
+ *
+ * qla4xxx_lookup_ddb_by_fw_index
+ * This routine locates a device handle given the firmware device
+ * database index. If device doesn't exist, returns NULL.
+ *
+ * Input:
+ * ha - Pointer to host adapter structure.
+ * fw_ddb_index - Firmware's device database index
+ *
+ * Returns:
+ * Pointer to the corresponding internal device database structure
+ */
+static inline struct ddb_entry *
+qla4xxx_lookup_ddb_by_fw_index(struct scsi_qla_host *ha, uint32_t fw_ddb_index)
+{
+ struct ddb_entry *ddb_entry = NULL;
+
+ if ((fw_ddb_index < MAX_DDB_ENTRIES) &&
+ (ha->fw_ddb_index_map[fw_ddb_index] !=
+ (struct ddb_entry *) INVALID_ENTRY)) {
+ ddb_entry = ha->fw_ddb_index_map[fw_ddb_index];
+ }
+
+ DEBUG3(printk("scsi%d: %s: index [%d], ddb_entry = %p\n",
+ ha->host_no, __func__, fw_ddb_index, ddb_entry));
+
+ return ddb_entry;
+}
+
+static inline void
+__qla4xxx_enable_intrs(struct scsi_qla_host *ha)
+{
+ if (is_qla4022(ha)) {
+ writel(set_rmask(IMR_SCSI_INTR_ENABLE),
+ &ha->reg->u1.isp4022.intr_mask);
+ readl(&ha->reg->u1.isp4022.intr_mask);
+ } else {
+ writel(set_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+ set_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+static inline void
+__qla4xxx_disable_intrs(struct scsi_qla_host *ha)
+{
+ if (is_qla4022(ha)) {
+ writel(clr_rmask(IMR_SCSI_INTR_ENABLE),
+ &ha->reg->u1.isp4022.intr_mask);
+ readl(&ha->reg->u1.isp4022.intr_mask);
+ } else {
+ writel(clr_rmask(CSR_SCSI_INTR_ENABLE), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+ clear_bit(AF_INTERRUPTS_ON, &ha->flags);
+}
+
+static inline void
+qla4xxx_enable_intrs(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ __qla4xxx_enable_intrs(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+static inline void
+qla4xxx_disable_intrs(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ __qla4xxx_disable_intrs(ha);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
new file mode 100644
index 000000000000..c0a254b89a30
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -0,0 +1,368 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+#include <scsi/scsi_tcq.h>
+
+/**
+ * qla4xxx_get_req_pkt - returns a valid entry in request queue.
+ * @ha: Pointer to host adapter structure.
+ * @queue_entry: Pointer to pointer to queue entry structure
+ *
+ * This routine performs the following tasks:
+ * - returns the current request_in pointer (if queue not full)
+ * - advances the request_in pointer
+ * - checks for queue full
+ **/
+int qla4xxx_get_req_pkt(struct scsi_qla_host *ha,
+ struct queue_entry **queue_entry)
+{
+ uint16_t request_in;
+ uint8_t status = QLA_SUCCESS;
+
+ *queue_entry = ha->request_ptr;
+
+ /* get the latest request_in and request_out index */
+ request_in = ha->request_in;
+ ha->request_out = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
+
+ /* Advance request queue pointer and check for queue full */
+ if (request_in == (REQUEST_QUEUE_DEPTH - 1)) {
+ request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else {
+ request_in++;
+ ha->request_ptr++;
+ }
+
+ /* request queue is full, try again later */
+ if ((ha->iocb_cnt + 1) >= ha->iocb_hiwat) {
+ /* restore request pointer */
+ ha->request_ptr = *queue_entry;
+ status = QLA_ERROR;
+ } else {
+ ha->request_in = request_in;
+ memset(*queue_entry, 0, sizeof(**queue_entry));
+ }
+
+ return status;
+}
+
+/**
+ * qla4xxx_send_marker_iocb - issues marker iocb to HBA
+ * @ha: Pointer to host adapter structure.
+ * @ddb_entry: Pointer to device database entry
+ * @lun: SCSI LUN
+ * @marker_type: marker identifier
+ *
+ * This routine issues a marker IOCB.
+ **/
+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;
+ uint8_t status = QLA_SUCCESS;
+
+ /* Acquire hardware specific lock */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /* Get pointer to the queue entry for the marker */
+ if (qla4xxx_get_req_pkt(ha, (struct queue_entry **) &marker_entry) !=
+ QLA_SUCCESS) {
+ status = QLA_ERROR;
+ goto exit_send_marker;
+ }
+
+ /* Put the marker in the request queue */
+ marker_entry->hdr.entryType = ET_MARKER;
+ marker_entry->hdr.entryCount = 1;
+ marker_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
+ marker_entry->modifier = cpu_to_le16(MM_LUN_RESET);
+ int_to_scsilun(lun, &marker_entry->lun);
+ wmb();
+
+ /* Tell ISP it's got a new I/O request */
+ writel(ha->request_in, &ha->reg->req_q_in);
+ readl(&ha->reg->req_q_in);
+
+exit_send_marker:
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ return status;
+}
+
+struct continuation_t1_entry* qla4xxx_alloc_cont_entry(
+ struct scsi_qla_host *ha)
+{
+ struct continuation_t1_entry *cont_entry;
+
+ cont_entry = (struct continuation_t1_entry *)ha->request_ptr;
+
+ /* Advance request queue pointer */
+ if (ha->request_in == (REQUEST_QUEUE_DEPTH - 1)) {
+ ha->request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else {
+ ha->request_in++;
+ ha->request_ptr++;
+ }
+
+ /* Load packet defaults */
+ cont_entry->hdr.entryType = ET_CONTINUE;
+ cont_entry->hdr.entryCount = 1;
+ cont_entry->hdr.systemDefined = (uint8_t) cpu_to_le16(ha->request_in);
+
+ return cont_entry;
+}
+
+uint16_t qla4xxx_calc_request_entries(uint16_t dsds)
+{
+ uint16_t iocbs;
+
+ iocbs = 1;
+ if (dsds > COMMAND_SEG) {
+ iocbs += (dsds - COMMAND_SEG) / CONTINUE_SEG;
+ if ((dsds - COMMAND_SEG) % CONTINUE_SEG)
+ iocbs++;
+ }
+ return iocbs;
+}
+
+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;
+ struct data_seg_a64 *cur_dsd;
+ struct scsi_cmnd *cmd;
+
+ cmd = srb->cmd;
+ ha = srb->ha;
+
+ if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+ /* No data being transferred */
+ cmd_entry->ttlByteCnt = __constant_cpu_to_le32(0);
+ return;
+ }
+
+ avail_dsds = COMMAND_SEG;
+ cur_dsd = (struct data_seg_a64 *) & (cmd_entry->dataseg[0]);
+
+ /* Load data segments */
+ if (cmd->use_sg) {
+ struct scatterlist *cur_seg;
+ struct scatterlist *end_seg;
+
+ cur_seg = (struct scatterlist *)cmd->request_buffer;
+ end_seg = cur_seg + tot_dsds;
+ while (cur_seg < end_seg) {
+ dma_addr_t sle_dma;
+
+ /* Allocate additional continuation packets? */
+ if (avail_dsds == 0) {
+ struct continuation_t1_entry *cont_entry;
+
+ cont_entry = qla4xxx_alloc_cont_entry(ha);
+ cur_dsd =
+ (struct data_seg_a64 *)
+ &cont_entry->dataseg[0];
+ avail_dsds = CONTINUE_SEG;
+ }
+
+ sle_dma = sg_dma_address(cur_seg);
+ cur_dsd->base.addrLow = cpu_to_le32(LSDW(sle_dma));
+ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(sle_dma));
+ cur_dsd->count = cpu_to_le32(sg_dma_len(cur_seg));
+ avail_dsds--;
+
+ cur_dsd++;
+ cur_seg++;
+ }
+ } else {
+ cur_dsd->base.addrLow = cpu_to_le32(LSDW(srb->dma_handle));
+ cur_dsd->base.addrHigh = cpu_to_le32(MSDW(srb->dma_handle));
+ cur_dsd->count = cpu_to_le32(cmd->request_bufflen);
+ }
+}
+
+/**
+ * qla4xxx_send_command_to_isp - issues command to HBA
+ * @ha: pointer to host adapter structure.
+ * @srb: pointer to SCSI Request Block to be sent to ISP
+ *
+ * This routine is called by qla4xxx_queuecommand to build an ISP
+ * command and pass it to the ISP for execution.
+ **/
+int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+ struct ddb_entry *ddb_entry;
+ struct command_t3_entry *cmd_entry;
+ struct scatterlist *sg = NULL;
+
+ uint16_t tot_dsds;
+ uint16_t req_cnt;
+
+ unsigned long flags;
+ uint16_t cnt;
+ uint32_t index;
+ char tag[2];
+
+ /* Get real lun and adapter */
+ ddb_entry = srb->ddb;
+
+ /* Send marker(s) if needed. */
+ if (ha->marker_needed == 1) {
+ if (qla4xxx_send_marker_iocb(ha, ddb_entry,
+ cmd->device->lun) != QLA_SUCCESS)
+ return QLA_ERROR;
+
+ ha->marker_needed = 0;
+ }
+ tot_dsds = 0;
+
+ /* Acquire hardware specific lock */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ index = (uint32_t)cmd->request->tag;
+
+ /* Calculate the number of request entries needed. */
+ if (cmd->use_sg) {
+ sg = (struct scatterlist *)cmd->request_buffer;
+ tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+ cmd->sc_data_direction);
+ if (tot_dsds == 0)
+ goto queuing_error;
+ } else if (cmd->request_bufflen) {
+ dma_addr_t req_dma;
+
+ req_dma = pci_map_single(ha->pdev, cmd->request_buffer,
+ cmd->request_bufflen,
+ cmd->sc_data_direction);
+ if (dma_mapping_error(req_dma))
+ goto queuing_error;
+
+ srb->dma_handle = req_dma;
+ tot_dsds = 1;
+ }
+ req_cnt = qla4xxx_calc_request_entries(tot_dsds);
+
+ if (ha->req_q_count < (req_cnt + 2)) {
+ cnt = (uint16_t) le32_to_cpu(ha->shadow_regs->req_q_out);
+ if (ha->request_in < cnt)
+ ha->req_q_count = cnt - ha->request_in;
+ else
+ ha->req_q_count = REQUEST_QUEUE_DEPTH -
+ (ha->request_in - cnt);
+ }
+
+ if (ha->req_q_count < (req_cnt + 2))
+ goto queuing_error;
+
+ /* total iocbs active */
+ if ((ha->iocb_cnt + req_cnt) >= REQUEST_QUEUE_DEPTH)
+ goto queuing_error;
+
+ /* Build command packet */
+ cmd_entry = (struct command_t3_entry *) ha->request_ptr;
+ memset(cmd_entry, 0, sizeof(struct command_t3_entry));
+ cmd_entry->hdr.entryType = ET_COMMAND;
+ cmd_entry->handle = cpu_to_le32(index);
+ cmd_entry->target = cpu_to_le16(ddb_entry->fw_ddb_index);
+ cmd_entry->connection_id = cpu_to_le16(ddb_entry->connection_id);
+
+ int_to_scsilun(cmd->device->lun, &cmd_entry->lun);
+ cmd_entry->cmdSeqNum = cpu_to_le32(ddb_entry->CmdSn);
+ cmd_entry->ttlByteCnt = cpu_to_le32(cmd->request_bufflen);
+ memcpy(cmd_entry->cdb, cmd->cmnd, cmd->cmd_len);
+ cmd_entry->dataSegCnt = cpu_to_le16(tot_dsds);
+ cmd_entry->hdr.entryCount = req_cnt;
+
+ /* Set data transfer direction control flags
+ * NOTE: Look at data_direction bits iff there is data to be
+ * transferred, as the data direction bit is sometimed filled
+ * in when there is no data to be transferred */
+ cmd_entry->control_flags = CF_NO_DATA;
+ if (cmd->request_bufflen) {
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ cmd_entry->control_flags = CF_WRITE;
+ else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ cmd_entry->control_flags = CF_READ;
+ }
+
+ /* Set tagged queueing control flags */
+ cmd_entry->control_flags |= CF_SIMPLE_TAG;
+ if (scsi_populate_tag_msg(cmd, tag))
+ switch (tag[0]) {
+ case MSG_HEAD_TAG:
+ cmd_entry->control_flags |= CF_HEAD_TAG;
+ break;
+ case MSG_ORDERED_TAG:
+ cmd_entry->control_flags |= CF_ORDERED_TAG;
+ break;
+ }
+
+
+ /* Advance request queue pointer */
+ ha->request_in++;
+ if (ha->request_in == REQUEST_QUEUE_DEPTH) {
+ ha->request_in = 0;
+ ha->request_ptr = ha->request_ring;
+ } else
+ ha->request_ptr++;
+
+
+ qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
+ wmb();
+
+ /*
+ * Check to see if adapter is online before placing request on
+ * request queue. If a reset occurs and a request is in the queue,
+ * the firmware will still attempt to process the request, retrieving
+ * garbage for pointers.
+ */
+ if (!test_bit(AF_ONLINE, &ha->flags)) {
+ DEBUG2(printk("scsi%ld: %s: Adapter OFFLINE! "
+ "Do not issue command.\n",
+ ha->host_no, __func__));
+ goto queuing_error;
+ }
+
+ srb->cmd->host_scribble = (unsigned char *)srb;
+
+ /* update counters */
+ srb->state = SRB_ACTIVE_STATE;
+ srb->flags |= SRB_DMA_VALID;
+
+ /* Track IOCB used */
+ ha->iocb_cnt += req_cnt;
+ srb->iocb_cnt = req_cnt;
+ ha->req_q_count -= req_cnt;
+
+ /* Debug print statements */
+ writel(ha->request_in, &ha->reg->req_q_in);
+ readl(&ha->reg->req_q_in);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_SUCCESS;
+
+queuing_error:
+
+ if (cmd->use_sg && tot_dsds) {
+ sg = (struct scatterlist *) cmd->request_buffer;
+ pci_unmap_sg(ha->pdev, sg, cmd->use_sg,
+ cmd->sc_data_direction);
+ } else if (tot_dsds)
+ pci_unmap_single(ha->pdev, srb->dma_handle,
+ cmd->request_bufflen, cmd->sc_data_direction);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return QLA_ERROR;
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_isr.c b/drivers/scsi/qla4xxx/ql4_isr.c
new file mode 100644
index 000000000000..1e283321a59d
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_isr.c
@@ -0,0 +1,796 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+/**
+ * qla2x00_process_completed_request() - Process a Fast Post response.
+ * @ha: SCSI driver HA context
+ * @index: SRB index
+ **/
+static void qla4xxx_process_completed_request(struct scsi_qla_host *ha,
+ uint32_t index)
+{
+ struct srb *srb;
+
+ srb = qla4xxx_del_from_active_array(ha, index);
+ if (srb) {
+ /* Save ISP completion status */
+ srb->cmd->result = DID_OK << 16;
+ qla4xxx_srb_compl(ha, srb);
+ } else {
+ DEBUG2(printk("scsi%ld: Invalid ISP SCSI completion handle = "
+ "%d\n", ha->host_no, index));
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+}
+
+/**
+ * qla4xxx_status_entry - processes status IOCBs
+ * @ha: Pointer to host adapter structure.
+ * @sts_entry: Pointer to status entry structure.
+ **/
+static void qla4xxx_status_entry(struct scsi_qla_host *ha,
+ struct status_entry *sts_entry)
+{
+ uint8_t scsi_status;
+ struct scsi_cmnd *cmd;
+ struct srb *srb;
+ struct ddb_entry *ddb_entry;
+ uint32_t residual;
+ uint16_t sensebytecnt;
+
+ if (sts_entry->completionStatus == SCS_COMPLETE &&
+ sts_entry->scsiStatus == 0) {
+ qla4xxx_process_completed_request(ha,
+ le32_to_cpu(sts_entry->
+ handle));
+ return;
+ }
+
+ srb = qla4xxx_del_from_active_array(ha, le32_to_cpu(sts_entry->handle));
+ if (!srb) {
+ /* FIXMEdg: Don't we need to reset ISP in this case??? */
+ DEBUG2(printk(KERN_WARNING "scsi%ld: %s: Status Entry invalid "
+ "handle 0x%x, sp=%p. This cmd may have already "
+ "been completed.\n", ha->host_no, __func__,
+ le32_to_cpu(sts_entry->handle), srb));
+ return;
+ }
+
+ cmd = srb->cmd;
+ if (cmd == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Command already returned back to "
+ "OS pkt->handle=%d srb=%p srb->state:%d\n",
+ ha->host_no, __func__, sts_entry->handle,
+ srb, srb->state));
+ dev_warn(&ha->pdev->dev, "Command is NULL:"
+ " already returned to OS (srb=%p)\n", srb);
+ return;
+ }
+
+ ddb_entry = srb->ddb;
+ if (ddb_entry == NULL) {
+ cmd->result = DID_NO_CONNECT << 16;
+ goto status_entry_exit;
+ }
+
+ residual = le32_to_cpu(sts_entry->residualByteCnt);
+
+ /* Translate ISP error to a Linux SCSI error. */
+ scsi_status = sts_entry->scsiStatus;
+ switch (sts_entry->completionStatus) {
+ case SCS_COMPLETE:
+ if (scsi_status == 0) {
+ cmd->result = DID_OK << 16;
+ break;
+ }
+
+ if (sts_entry->iscsiFlags &
+ (ISCSI_FLAG_RESIDUAL_OVER|ISCSI_FLAG_RESIDUAL_UNDER))
+ cmd->resid = residual;
+
+ cmd->result = DID_OK << 16 | scsi_status;
+
+ if (scsi_status != SCSI_CHECK_CONDITION)
+ break;
+
+ /* Copy Sense Data into sense buffer. */
+ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+ sensebytecnt = le16_to_cpu(sts_entry->senseDataByteCnt);
+ if (sensebytecnt == 0)
+ break;
+
+ memcpy(cmd->sense_buffer, sts_entry->senseData,
+ min(sensebytecnt,
+ (uint16_t) sizeof(cmd->sense_buffer)));
+
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ "ASC/ASCQ = %02x/%02x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->senseData[2] & 0x0f,
+ sts_entry->senseData[12],
+ sts_entry->senseData[13]));
+
+ srb->flags |= SRB_GOT_SENSE;
+ break;
+
+ case SCS_INCOMPLETE:
+ /* Always set the status to DID_ERROR, since
+ * all conditions result in that status anyway */
+ cmd->result = DID_ERROR << 16;
+ break;
+
+ case SCS_RESET_OCCURRED:
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Device RESET occurred\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id, cmd->device->lun, __func__));
+
+ cmd->result = DID_RESET << 16;
+ break;
+
+ case SCS_ABORTED:
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: Abort occurred\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id, cmd->device->lun, __func__));
+
+ cmd->result = DID_RESET << 16;
+ break;
+
+ case SCS_TIMEOUT:
+ DEBUG2(printk(KERN_INFO "scsi%ld:%d:%d:%d: Timeout\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id, cmd->device->lun));
+
+ cmd->result = DID_BUS_BUSY << 16;
+
+ /*
+ * Mark device missing so that we won't continue to send
+ * I/O to this device. We should get a ddb state change
+ * AEN soon.
+ */
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+ break;
+
+ case SCS_DATA_UNDERRUN:
+ case SCS_DATA_OVERRUN:
+ if (sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_OVER) {
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: " "Data overrun, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__, residual));
+
+ cmd->result = DID_ERROR << 16;
+ break;
+ }
+
+ if ((sts_entry->iscsiFlags & ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
+ /*
+ * Firmware detected a SCSI transport underrun
+ * condition
+ */
+ cmd->resid = residual;
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: UNDERRUN status "
+ "detected, xferlen = 0x%x, residual = "
+ "0x%x\n",
+ ha->host_no, cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ cmd->request_bufflen,
+ residual));
+ }
+
+ /*
+ * If there is scsi_status, it takes precedense over
+ * underflow condition.
+ */
+ if (scsi_status != 0) {
+ cmd->result = DID_OK << 16 | scsi_status;
+
+ if (scsi_status != SCSI_CHECK_CONDITION)
+ break;
+
+ /* Copy Sense Data into sense buffer. */
+ memset(cmd->sense_buffer, 0,
+ sizeof(cmd->sense_buffer));
+
+ sensebytecnt =
+ le16_to_cpu(sts_entry->senseDataByteCnt);
+ if (sensebytecnt == 0)
+ break;
+
+ memcpy(cmd->sense_buffer, sts_entry->senseData,
+ min(sensebytecnt,
+ (uint16_t) sizeof(cmd->sense_buffer)));
+
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: sense key = %x, "
+ "ASC/ASCQ = %02x/%02x\n", ha->host_no,
+ cmd->device->channel, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->senseData[2] & 0x0f,
+ sts_entry->senseData[12],
+ sts_entry->senseData[13]));
+ } else {
+ /*
+ * If RISC reports underrun and target does not
+ * report it then we must have a lost frame, so
+ * tell upper layer to retry it by reporting a
+ * bus busy.
+ */
+ if ((sts_entry->iscsiFlags &
+ ISCSI_FLAG_RESIDUAL_UNDER) == 0) {
+ cmd->result = DID_BUS_BUSY << 16;
+ } else if ((cmd->request_bufflen - residual) <
+ cmd->underflow) {
+ /*
+ * Handle mid-layer underflow???
+ *
+ * For kernels less than 2.4, the driver must
+ * return an error if an underflow is detected.
+ * For kernels equal-to and above 2.4, the
+ * mid-layer will appearantly handle the
+ * underflow by detecting the residual count --
+ * unfortunately, we do not see where this is
+ * actually being done. In the interim, we
+ * will return DID_ERROR.
+ */
+ DEBUG2(printk("scsi%ld:%d:%d:%d: %s: "
+ "Mid-layer Data underrun, "
+ "xferlen = 0x%x, "
+ "residual = 0x%x\n", ha->host_no,
+ cmd->device->channel,
+ cmd->device->id,
+ cmd->device->lun, __func__,
+ cmd->request_bufflen, residual));
+
+ cmd->result = DID_ERROR << 16;
+ } else {
+ cmd->result = DID_OK << 16;
+ }
+ }
+ break;
+
+ case SCS_DEVICE_LOGGED_OUT:
+ case SCS_DEVICE_UNAVAILABLE:
+ /*
+ * Mark device missing so that we won't continue to
+ * send I/O to this device. We should get a ddb
+ * state change AEN soon.
+ */
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_ONLINE)
+ qla4xxx_mark_device_missing(ha, ddb_entry);
+
+ cmd->result = DID_BUS_BUSY << 16;
+ break;
+
+ case SCS_QUEUE_FULL:
+ /*
+ * SCSI Mid-Layer handles device queue full
+ */
+ cmd->result = DID_OK << 16 | sts_entry->scsiStatus;
+ DEBUG2(printk("scsi%ld:%d:%d: %s: QUEUE FULL detected "
+ "compl=%02x, scsi=%02x, state=%02x, iFlags=%02x,"
+ " iResp=%02x\n", ha->host_no, cmd->device->id,
+ cmd->device->lun, __func__,
+ sts_entry->completionStatus,
+ sts_entry->scsiStatus, sts_entry->state_flags,
+ sts_entry->iscsiFlags,
+ sts_entry->iscsiResponse));
+ break;
+
+ default:
+ cmd->result = DID_ERROR << 16;
+ break;
+ }
+
+status_entry_exit:
+
+ /* complete the request */
+ srb->cc_stat = sts_entry->completionStatus;
+ qla4xxx_srb_compl(ha, srb);
+}
+
+/**
+ * qla4xxx_process_response_queue - process response queue completions
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine process response queue completions in interrupt context.
+ * Hardware_lock locked upon entry
+ **/
+static void qla4xxx_process_response_queue(struct scsi_qla_host * ha)
+{
+ uint32_t count = 0;
+ struct srb *srb = NULL;
+ struct status_entry *sts_entry;
+
+ /* Process all responses from response queue */
+ while ((ha->response_in =
+ (uint16_t)le32_to_cpu(ha->shadow_regs->rsp_q_in)) !=
+ ha->response_out) {
+ sts_entry = (struct status_entry *) ha->response_ptr;
+ count++;
+
+ /* Advance pointers for next entry */
+ if (ha->response_out == (RESPONSE_QUEUE_DEPTH - 1)) {
+ ha->response_out = 0;
+ ha->response_ptr = ha->response_ring;
+ } else {
+ ha->response_out++;
+ ha->response_ptr++;
+ }
+
+ /* process entry */
+ switch (sts_entry->hdr.entryType) {
+ case ET_STATUS:
+ /*
+ * Common status - Single completion posted in single
+ * IOSB.
+ */
+ qla4xxx_status_entry(ha, sts_entry);
+ break;
+
+ case ET_PASSTHRU_STATUS:
+ break;
+
+ case ET_STATUS_CONTINUATION:
+ /* Just throw away the status continuation entries */
+ DEBUG2(printk("scsi%ld: %s: Status Continuation entry "
+ "- ignoring\n", ha->host_no, __func__));
+ break;
+
+ case ET_COMMAND:
+ /* ISP device queue is full. Command not
+ * accepted by ISP. Queue command for
+ * later */
+
+ srb = qla4xxx_del_from_active_array(ha,
+ le32_to_cpu(sts_entry->
+ handle));
+ if (srb == NULL)
+ goto exit_prq_invalid_handle;
+
+ DEBUG2(printk("scsi%ld: %s: FW device queue full, "
+ "srb %p\n", ha->host_no, __func__, srb));
+
+ /* ETRY normally by sending it back with
+ * DID_BUS_BUSY */
+ srb->cmd->result = DID_BUS_BUSY << 16;
+ qla4xxx_srb_compl(ha, srb);
+ break;
+
+ case ET_CONTINUE:
+ /* Just throw away the continuation entries */
+ DEBUG2(printk("scsi%ld: %s: Continuation entry - "
+ "ignoring\n", ha->host_no, __func__));
+ break;
+
+ default:
+ /*
+ * Invalid entry in response queue, reset RISC
+ * firmware.
+ */
+ DEBUG2(printk("scsi%ld: %s: Invalid entry %x in "
+ "response queue \n", ha->host_no,
+ __func__,
+ sts_entry->hdr.entryType));
+ goto exit_prq_error;
+ }
+ }
+
+ /*
+ * Done with responses, update the ISP For QLA4010, this also clears
+ * the interrupt.
+ */
+ writel(ha->response_out, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+
+ return;
+
+exit_prq_invalid_handle:
+ DEBUG2(printk("scsi%ld: %s: Invalid handle(srb)=%p type=%x IOCS=%x\n",
+ ha->host_no, __func__, srb, sts_entry->hdr.entryType,
+ sts_entry->completionStatus));
+
+exit_prq_error:
+ writel(ha->response_out, &ha->reg->rsp_q_out);
+ readl(&ha->reg->rsp_q_out);
+
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+}
+
+/**
+ * qla4xxx_isr_decode_mailbox - decodes mailbox status
+ * @ha: Pointer to host adapter structure.
+ * @mailbox_status: Mailbox status.
+ *
+ * This routine decodes the mailbox status during the ISR.
+ * Hardware_lock locked upon entry. runs in interrupt context.
+ **/
+static void qla4xxx_isr_decode_mailbox(struct scsi_qla_host * ha,
+ uint32_t mbox_status)
+{
+ int i;
+
+ if ((mbox_status == MBOX_STS_BUSY) ||
+ (mbox_status == MBOX_STS_INTERMEDIATE_COMPLETION) ||
+ (mbox_status >> 12 == MBOX_COMPLETION_STATUS)) {
+ ha->mbox_status[0] = mbox_status;
+
+ if (test_bit(AF_MBOX_COMMAND, &ha->flags)) {
+ /*
+ * Copy all mailbox registers to a temporary
+ * location and set mailbox command done flag
+ */
+ for (i = 1; i < ha->mbox_status_count; i++)
+ ha->mbox_status[i] =
+ readl(&ha->reg->mailbox[i]);
+
+ set_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ wake_up(&ha->mailbox_wait_queue);
+ }
+ } else if (mbox_status >> 12 == MBOX_ASYNC_EVENT_STATUS) {
+ /* Immediately process the AENs that don't require much work.
+ * Only queue the database_changed AENs */
+ switch (mbox_status) {
+ case MBOX_ASTS_SYSTEM_ERROR:
+ /* Log Mailbox registers */
+ if (ql4xdontresethba) {
+ DEBUG2(printk("%s:Dont Reset HBA\n",
+ __func__));
+ } else {
+ set_bit(AF_GET_CRASH_RECORD, &ha->flags);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+ break;
+
+ case MBOX_ASTS_REQUEST_TRANSFER_ERROR:
+ case MBOX_ASTS_RESPONSE_TRANSFER_ERROR:
+ case MBOX_ASTS_NVRAM_INVALID:
+ case MBOX_ASTS_IP_ADDRESS_CHANGED:
+ case MBOX_ASTS_DHCP_LEASE_EXPIRED:
+ DEBUG2(printk("scsi%ld: AEN %04x, ERROR Status, "
+ "Reset HA\n", ha->host_no, mbox_status));
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ break;
+
+ case MBOX_ASTS_LINK_UP:
+ DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK UP\n",
+ ha->host_no, mbox_status));
+ set_bit(AF_LINK_UP, &ha->flags);
+ break;
+
+ case MBOX_ASTS_LINK_DOWN:
+ DEBUG2(printk("scsi%ld: AEN %04x Adapter LINK DOWN\n",
+ ha->host_no, mbox_status));
+ clear_bit(AF_LINK_UP, &ha->flags);
+ break;
+
+ case MBOX_ASTS_HEARTBEAT:
+ ha->seconds_since_last_heartbeat = 0;
+ break;
+
+ case MBOX_ASTS_DHCP_LEASE_ACQUIRED:
+ DEBUG2(printk("scsi%ld: AEN %04x DHCP LEASE "
+ "ACQUIRED\n", ha->host_no, mbox_status));
+ set_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags);
+ break;
+
+ case MBOX_ASTS_PROTOCOL_STATISTIC_ALARM:
+ case MBOX_ASTS_SCSI_COMMAND_PDU_REJECTED: /* Target
+ * mode
+ * only */
+ case MBOX_ASTS_UNSOLICITED_PDU_RECEIVED: /* Connection mode */
+ case MBOX_ASTS_IPSEC_SYSTEM_FATAL_ERROR:
+ case MBOX_ASTS_SUBNET_STATE_CHANGE:
+ /* No action */
+ DEBUG2(printk("scsi%ld: AEN %04x\n", ha->host_no,
+ mbox_status));
+ break;
+
+ case MBOX_ASTS_MAC_ADDRESS_CHANGED:
+ case MBOX_ASTS_DNS:
+ /* No action */
+ DEBUG2(printk(KERN_INFO "scsi%ld: AEN %04x, "
+ "mbox_sts[1]=%04x, mbox_sts[2]=%04x\n",
+ ha->host_no, mbox_status,
+ readl(&ha->reg->mailbox[1]),
+ readl(&ha->reg->mailbox[2])));
+ break;
+
+ case MBOX_ASTS_SELF_TEST_FAILED:
+ case MBOX_ASTS_LOGIN_FAILED:
+ /* No action */
+ DEBUG2(printk("scsi%ld: AEN %04x, mbox_sts[1]=%04x, "
+ "mbox_sts[2]=%04x, mbox_sts[3]=%04x\n",
+ ha->host_no, mbox_status,
+ readl(&ha->reg->mailbox[1]),
+ readl(&ha->reg->mailbox[2]),
+ readl(&ha->reg->mailbox[3])));
+ break;
+
+ case MBOX_ASTS_DATABASE_CHANGED:
+ /* Queue AEN information and process it in the DPC
+ * routine */
+ if (ha->aen_q_count > 0) {
+ /* advance pointer */
+ if (ha->aen_in == (MAX_AEN_ENTRIES - 1))
+ ha->aen_in = 0;
+ else
+ ha->aen_in++;
+
+ /* decrement available counter */
+ ha->aen_q_count--;
+
+ for (i = 1; i < MBOX_AEN_REG_COUNT; i++)
+ ha->aen_q[ha->aen_in].mbox_sts[i] =
+ readl(&ha->reg->mailbox[i]);
+
+ ha->aen_q[ha->aen_in].mbox_sts[0] = mbox_status;
+
+ /* print debug message */
+ DEBUG2(printk("scsi%ld: AEN[%d] %04x queued"
+ " mb1:0x%x mb2:0x%x mb3:0x%x mb4:0x%x\n",
+ ha->host_no, ha->aen_in,
+ mbox_status,
+ ha->aen_q[ha->aen_in].mbox_sts[1],
+ ha->aen_q[ha->aen_in].mbox_sts[2],
+ ha->aen_q[ha->aen_in].mbox_sts[3],
+ ha->aen_q[ha->aen_in]. mbox_sts[4]));
+
+ /* The DPC routine will process the aen */
+ set_bit(DPC_AEN, &ha->dpc_flags);
+ } else {
+ DEBUG2(printk("scsi%ld: %s: aen %04x, queue "
+ "overflowed! AEN LOST!!\n",
+ ha->host_no, __func__,
+ mbox_status));
+
+ DEBUG2(printk("scsi%ld: DUMP AEN QUEUE\n",
+ ha->host_no));
+
+ for (i = 0; i < MAX_AEN_ENTRIES; i++) {
+ DEBUG2(printk("AEN[%d] %04x %04x %04x "
+ "%04x\n", i,
+ ha->aen_q[i].mbox_sts[0],
+ ha->aen_q[i].mbox_sts[1],
+ ha->aen_q[i].mbox_sts[2],
+ ha->aen_q[i].mbox_sts[3]));
+ }
+ }
+ break;
+
+ default:
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: AEN %04x UNKNOWN\n",
+ ha->host_no, mbox_status));
+ break;
+ }
+ } else {
+ DEBUG2(printk("scsi%ld: Unknown mailbox status %08X\n",
+ ha->host_no, mbox_status));
+
+ ha->mbox_status[0] = mbox_status;
+ }
+}
+
+/**
+ * qla4xxx_interrupt_service_routine - isr
+ * @ha: pointer to host adapter structure.
+ *
+ * This is the main interrupt service routine.
+ * hardware_lock locked upon entry. runs in interrupt context.
+ **/
+void qla4xxx_interrupt_service_routine(struct scsi_qla_host * ha,
+ uint32_t intr_status)
+{
+ /* Process response queue interrupt. */
+ if (intr_status & CSR_SCSI_COMPLETION_INTR)
+ qla4xxx_process_response_queue(ha);
+
+ /* Process mailbox/asynch event interrupt.*/
+ if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
+ qla4xxx_isr_decode_mailbox(ha,
+ readl(&ha->reg->mailbox[0]));
+
+ /* Clear Mailbox Interrupt */
+ writel(set_rmask(CSR_SCSI_PROCESSOR_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+}
+
+/**
+ * qla4xxx_intr_handler - hardware interrupt handler.
+ * @irq: Unused
+ * @dev_id: Pointer to host adapter structure
+ **/
+irqreturn_t qla4xxx_intr_handler(int irq, void *dev_id)
+{
+ struct scsi_qla_host *ha;
+ uint32_t intr_status;
+ unsigned long flags = 0;
+ uint8_t reqs_count = 0;
+
+ ha = (struct scsi_qla_host *) dev_id;
+ if (!ha) {
+ DEBUG2(printk(KERN_INFO
+ "qla4xxx: Interrupt with NULL host ptr\n"));
+ return IRQ_NONE;
+ }
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /*
+ * Repeatedly service interrupts up to a maximum of
+ * MAX_REQS_SERVICED_PER_INTR
+ */
+ while (1) {
+ /*
+ * Read interrupt status
+ */
+ if (le32_to_cpu(ha->shadow_regs->rsp_q_in) !=
+ ha->response_out)
+ intr_status = CSR_SCSI_COMPLETION_INTR;
+ else
+ intr_status = readl(&ha->reg->ctrl_status);
+
+ if ((intr_status &
+ (CSR_SCSI_RESET_INTR|CSR_FATAL_ERROR|INTR_PENDING)) ==
+ 0) {
+ if (reqs_count == 0)
+ ha->spurious_int_count++;
+ break;
+ }
+
+ if (intr_status & CSR_FATAL_ERROR) {
+ DEBUG2(printk(KERN_INFO "scsi%ld: Fatal Error, "
+ "Status 0x%04x\n", ha->host_no,
+ readl(isp_port_error_status (ha))));
+
+ /* Issue Soft Reset to clear this error condition.
+ * This will prevent the RISC from repeatedly
+ * interrupting the driver; thus, allowing the DPC to
+ * get scheduled to continue error recovery.
+ * NOTE: Disabling RISC interrupts does not work in
+ * this case, as CSR_FATAL_ERROR overrides
+ * CSR_SCSI_INTR_ENABLE */
+ if ((readl(&ha->reg->ctrl_status) &
+ CSR_SCSI_RESET_INTR) == 0) {
+ writel(set_rmask(CSR_SOFT_RESET),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+
+ writel(set_rmask(CSR_FATAL_ERROR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+
+ __qla4xxx_disable_intrs(ha);
+
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+
+ break;
+ } else if (intr_status & CSR_SCSI_RESET_INTR) {
+ clear_bit(AF_ONLINE, &ha->flags);
+ __qla4xxx_disable_intrs(ha);
+
+ writel(set_rmask(CSR_SCSI_RESET_INTR),
+ &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+
+ set_bit(DPC_RESET_HA_INTR, &ha->dpc_flags);
+
+ break;
+ } else if (intr_status & INTR_PENDING) {
+ qla4xxx_interrupt_service_routine(ha, intr_status);
+ ha->total_io_count++;
+ if (++reqs_count == MAX_REQS_SERVICED_PER_INTR)
+ break;
+
+ intr_status = 0;
+ }
+ }
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qla4xxx_process_aen - processes AENs generated by firmware
+ * @ha: pointer to host adapter structure.
+ * @process_aen: type of AENs to process
+ *
+ * Processes specific types of Asynchronous Events generated by firmware.
+ * The type of AENs to process is specified by process_aen and can be
+ * PROCESS_ALL_AENS 0
+ * FLUSH_DDB_CHANGED_AENS 1
+ * RELOGIN_DDB_CHANGED_AENS 2
+ **/
+void qla4xxx_process_aen(struct scsi_qla_host * ha, uint8_t process_aen)
+{
+ uint32_t mbox_sts[MBOX_AEN_REG_COUNT];
+ struct aen *aen;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ while (ha->aen_out != ha->aen_in) {
+ /* Advance pointers for next entry */
+ if (ha->aen_out == (MAX_AEN_ENTRIES - 1))
+ ha->aen_out = 0;
+ else
+ ha->aen_out++;
+
+ ha->aen_q_count++;
+ aen = &ha->aen_q[ha->aen_out];
+
+ /* copy aen information to local structure */
+ for (i = 0; i < MBOX_AEN_REG_COUNT; i++)
+ mbox_sts[i] = aen->mbox_sts[i];
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ DEBUG(printk("scsi%ld: AEN[%d] %04x, index [%d] state=%04x "
+ "mod=%x conerr=%08x \n", ha->host_no, ha->aen_out,
+ mbox_sts[0], mbox_sts[2], mbox_sts[3],
+ mbox_sts[1], mbox_sts[4]));
+
+ switch (mbox_sts[0]) {
+ case MBOX_ASTS_DATABASE_CHANGED:
+ if (process_aen == FLUSH_DDB_CHANGED_AENS) {
+ DEBUG2(printk("scsi%ld: AEN[%d] %04x, index "
+ "[%d] state=%04x FLUSHED!\n",
+ ha->host_no, ha->aen_out,
+ mbox_sts[0], mbox_sts[2],
+ mbox_sts[3]));
+ break;
+ } else if (process_aen == RELOGIN_DDB_CHANGED_AENS) {
+ /* for use during init time, we only want to
+ * relogin non-active ddbs */
+ struct ddb_entry *ddb_entry;
+
+ ddb_entry =
+ /* FIXME: name length? */
+ qla4xxx_lookup_ddb_by_fw_index(ha,
+ mbox_sts[2]);
+ if (!ddb_entry)
+ break;
+
+ ddb_entry->dev_scan_wait_to_complete_relogin =
+ 0;
+ ddb_entry->dev_scan_wait_to_start_relogin =
+ jiffies +
+ ((ddb_entry->default_time2wait +
+ 4) * HZ);
+
+ DEBUG2(printk("scsi%ld: ddb index [%d] initate"
+ " RELOGIN after %d seconds\n",
+ ha->host_no,
+ ddb_entry->fw_ddb_index,
+ ddb_entry->default_time2wait +
+ 4));
+ break;
+ }
+
+ if (mbox_sts[1] == 0) { /* Global DB change. */
+ qla4xxx_reinitialize_ddb_list(ha);
+ } else if (mbox_sts[1] == 1) { /* Specific device. */
+ qla4xxx_process_ddb_changed(ha, mbox_sts[2],
+ mbox_sts[3]);
+ }
+ break;
+ }
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c
new file mode 100644
index 000000000000..ef82399c0858
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_mbx.c
@@ -0,0 +1,930 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+
+/**
+ * qla4xxx_mailbox_command - issues mailbox commands
+ * @ha: Pointer to host adapter structure.
+ * @inCount: number of mailbox registers to load.
+ * @outCount: number of mailbox registers to return.
+ * @mbx_cmd: data pointer for mailbox in registers.
+ * @mbx_sts: data pointer for mailbox out registers.
+ *
+ * This routine sssue mailbox commands and waits for completion.
+ * 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)
+{
+ int status = QLA_ERROR;
+ uint8_t i;
+ u_long wait_count;
+ uint32_t intr_status;
+ unsigned long flags = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ mutex_lock(&ha->mbox_sem);
+
+ /* Mailbox code active */
+ set_bit(AF_MBOX_COMMAND, &ha->flags);
+
+ /* Make sure that pointers are valid */
+ if (!mbx_cmd || !mbx_sts) {
+ DEBUG2(printk("scsi%ld: %s: Invalid mbx_cmd or mbx_sts "
+ "pointer\n", ha->host_no, __func__));
+ goto mbox_exit;
+ }
+
+ /* To prevent overwriting mailbox registers for a command that has
+ * not yet been serviced, check to see if a previously issued
+ * mailbox command is interrupting.
+ * -----------------------------------------------------------------
+ */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ intr_status = readl(&ha->reg->ctrl_status);
+ if (intr_status & CSR_SCSI_PROCESSOR_INTR) {
+ /* Service existing interrupt */
+ qla4xxx_interrupt_service_routine(ha, intr_status);
+ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ }
+
+ /* Send the mailbox command to the firmware */
+ ha->mbox_status_count = outCount;
+ for (i = 0; i < outCount; i++)
+ ha->mbox_status[i] = 0;
+
+ /* Load all mailbox registers, except mailbox 0. */
+ for (i = 1; i < inCount; i++)
+ writel(mbx_cmd[i], &ha->reg->mailbox[i]);
+
+ /* Wakeup firmware */
+ writel(mbx_cmd[0], &ha->reg->mailbox[0]);
+ readl(&ha->reg->mailbox[0]);
+ writel(set_rmask(CSR_INTR_RISC), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Wait for completion */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&ha->mailbox_wait_queue, &wait);
+
+ /*
+ * If we don't want status, don't wait for the mailbox command to
+ * complete. For example, MBOX_CMD_RESET_FW doesn't return status,
+ * you must poll the inbound Interrupt Mask for completion.
+ */
+ if (outCount == 0) {
+ status = QLA_SUCCESS;
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&ha->mailbox_wait_queue, &wait);
+ goto mbox_exit;
+ }
+ /* Wait for command to complete */
+ wait_count = jiffies + MBOX_TOV * HZ;
+ while (test_bit(AF_MBOX_COMMAND_DONE, &ha->flags) == 0) {
+ if (time_after_eq(jiffies, wait_count))
+ break;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ intr_status = readl(&ha->reg->ctrl_status);
+ if (intr_status & INTR_PENDING) {
+ /*
+ * Service the interrupt.
+ * The ISR will save the mailbox status registers
+ * to a temporary storage location in the adapter
+ * structure.
+ */
+ ha->mbox_status_count = outCount;
+ qla4xxx_interrupt_service_routine(ha, intr_status);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ msleep(10);
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&ha->mailbox_wait_queue, &wait);
+
+ /* Check for mailbox timeout. */
+ if (!test_bit(AF_MBOX_COMMAND_DONE, &ha->flags)) {
+ DEBUG2(printk("scsi%ld: Mailbox Cmd 0x%08X timed out ...,"
+ " Scheduling Adapter Reset\n", ha->host_no,
+ mbx_cmd[0]));
+ ha->mailbox_timeout_count++;
+ mbx_sts[0] = (-1);
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ goto mbox_exit;
+ }
+
+ /*
+ * Copy the mailbox out registers to the caller's mailbox in/out
+ * structure.
+ */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (i = 0; i < outCount; i++)
+ mbx_sts[i] = ha->mbox_status[i];
+
+ /* Set return status and error flags (if applicable). */
+ switch (ha->mbox_status[0]) {
+ case MBOX_STS_COMMAND_COMPLETE:
+ status = QLA_SUCCESS;
+ break;
+
+ case MBOX_STS_INTERMEDIATE_COMPLETION:
+ status = QLA_SUCCESS;
+ break;
+
+ case MBOX_STS_BUSY:
+ DEBUG2( printk("scsi%ld: %s: Cmd = %08X, ISP BUSY\n",
+ ha->host_no, __func__, mbx_cmd[0]));
+ ha->mailbox_timeout_count++;
+ break;
+
+ default:
+ DEBUG2(printk("scsi%ld: %s: **** FAILED, cmd = %08X, "
+ "sts = %08X ****\n", ha->host_no, __func__,
+ mbx_cmd[0], mbx_sts[0]));
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+mbox_exit:
+ clear_bit(AF_MBOX_COMMAND, &ha->flags);
+ clear_bit(AF_MBOX_COMMAND_DONE, &ha->flags);
+ mutex_unlock(&ha->mbox_sem);
+
+ return status;
+}
+
+
+/**
+ * qla4xxx_issue_iocb - issue mailbox iocb command
+ * @ha: adapter state pointer.
+ * @buffer: buffer pointer.
+ * @phys_addr: physical address of buffer.
+ * @size: size of buffer.
+ *
+ * Issues iocbs via mailbox commands.
+ * TARGET_QUEUE_LOCK must be released.
+ * ADAPTER_STATE_LOCK must be released.
+ **/
+int
+qla4xxx_issue_iocb(struct scsi_qla_host * ha, void *buffer,
+ dma_addr_t phys_addr, size_t size)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status;
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_EXECUTE_IOCB_A64;
+ mbox_cmd[1] = 0;
+ mbox_cmd[2] = LSDW(phys_addr);
+ mbox_cmd[3] = MSDW(phys_addr);
+ status = qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
+ return status;
+}
+
+int qla4xxx_conn_close_sess_logout(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index,
+ uint16_t connection_id,
+ uint16_t option)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_CONN_CLOSE_SESS_LOGOUT;
+ mbox_cmd[1] = fw_ddb_index;
+ mbox_cmd[2] = connection_id;
+ mbox_cmd[3] = LOGOUT_OPTION_RELOGIN;
+ if (qla4xxx_mailbox_command(ha, 4, 2, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_CONN_CLOSE_SESS_LOGOUT "
+ "option %04x failed sts %04X %04X",
+ ha->host_no, __func__,
+ option, mbox_sts[0], mbox_sts[1]));
+ if (mbox_sts[0] == 0x4005)
+ DEBUG2(printk("%s reason %04X\n", __func__,
+ mbox_sts[1]));
+ }
+ return QLA_SUCCESS;
+}
+
+int qla4xxx_clear_database_entry(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_CLEAR_DATABASE_ENTRY;
+ mbox_cmd[1] = fw_ddb_index;
+ if (qla4xxx_mailbox_command(ha, 2, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS)
+ return QLA_ERROR;
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_initialize_fw_cb - initializes firmware control block.
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha)
+{
+ struct init_fw_ctrl_blk *init_fw_cb;
+ dma_addr_t init_fw_cb_dma;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status = QLA_ERROR;
+
+ init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ &init_fw_cb_dma, GFP_KERNEL);
+ if (init_fw_cb == NULL) {
+ DEBUG2(printk("scsi%ld: %s: Unable to alloc init_cb\n",
+ ha->host_no, __func__));
+ return 10;
+ }
+ memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
+
+ /* Get Initialize Firmware Control Block. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
+ mbox_cmd[2] = LSDW(init_fw_cb_dma);
+ mbox_cmd[3] = MSDW(init_fw_cb_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ dma_free_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+ return status;
+ }
+
+ /* Initialize request and response queues. */
+ qla4xxx_init_rings(ha);
+
+ /* Fill in the request and response queue information. */
+ init_fw_cb->ReqQConsumerIndex = cpu_to_le16(ha->request_out);
+ init_fw_cb->ComplQProducerIndex = cpu_to_le16(ha->response_in);
+ init_fw_cb->ReqQLen = __constant_cpu_to_le16(REQUEST_QUEUE_DEPTH);
+ init_fw_cb->ComplQLen = __constant_cpu_to_le16(RESPONSE_QUEUE_DEPTH);
+ init_fw_cb->ReqQAddrLo = cpu_to_le32(LSDW(ha->request_dma));
+ init_fw_cb->ReqQAddrHi = cpu_to_le32(MSDW(ha->request_dma));
+ init_fw_cb->ComplQAddrLo = cpu_to_le32(LSDW(ha->response_dma));
+ init_fw_cb->ComplQAddrHi = cpu_to_le32(MSDW(ha->response_dma));
+ init_fw_cb->ShadowRegBufAddrLo =
+ cpu_to_le32(LSDW(ha->shadow_regs_dma));
+ init_fw_cb->ShadowRegBufAddrHi =
+ cpu_to_le32(MSDW(ha->shadow_regs_dma));
+
+ /* Set up required options. */
+ init_fw_cb->FwOptions |=
+ __constant_cpu_to_le16(FWOPT_SESSION_MODE |
+ FWOPT_INITIATOR_MODE);
+ init_fw_cb->FwOptions &= __constant_cpu_to_le16(~FWOPT_TARGET_MODE);
+
+ /* Save some info in adapter structure. */
+ ha->firmware_options = le16_to_cpu(init_fw_cb->FwOptions);
+ ha->tcp_options = le16_to_cpu(init_fw_cb->TCPOptions);
+ ha->heartbeat_interval = init_fw_cb->HeartbeatInterval;
+ memcpy(ha->ip_address, init_fw_cb->IPAddr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
+ memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
+ memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
+ memcpy(ha->name_string, init_fw_cb->iSCSINameString,
+ min(sizeof(ha->name_string),
+ sizeof(init_fw_cb->iSCSINameString)));
+ memcpy(ha->alias, init_fw_cb->Alias,
+ min(sizeof(ha->alias), sizeof(init_fw_cb->Alias)));
+
+ /* Save Command Line Paramater info */
+ ha->port_down_retry_count = le16_to_cpu(init_fw_cb->KeepAliveTimeout);
+ ha->discovery_wait = ql4xdiscoverywait;
+
+ /* Send Initialize Firmware Control Block. */
+ mbox_cmd[0] = MBOX_CMD_INITIALIZE_FIRMWARE;
+ mbox_cmd[1] = 0;
+ mbox_cmd[2] = LSDW(init_fw_cb_dma);
+ mbox_cmd[3] = MSDW(init_fw_cb_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) ==
+ QLA_SUCCESS)
+ status = QLA_SUCCESS;
+ else {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_INITIALIZE_FIRMWARE "
+ "failed w/ status %04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ }
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+
+ return status;
+}
+
+/**
+ * qla4xxx_get_dhcp_ip_address - gets HBA ip address via DHCP
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_get_dhcp_ip_address(struct scsi_qla_host * ha)
+{
+ struct init_fw_ctrl_blk *init_fw_cb;
+ dma_addr_t init_fw_cb_dma;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ init_fw_cb = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ &init_fw_cb_dma, GFP_KERNEL);
+ if (init_fw_cb == NULL) {
+ printk("scsi%ld: %s: Unable to alloc init_cb\n", ha->host_no,
+ __func__);
+ return 10;
+ }
+
+ /* Get Initialize Firmware Control Block. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ memset(init_fw_cb, 0, sizeof(struct init_fw_ctrl_blk));
+ mbox_cmd[0] = MBOX_CMD_GET_INIT_FW_CTRL_BLOCK;
+ mbox_cmd[2] = LSDW(init_fw_cb_dma);
+ mbox_cmd[3] = MSDW(init_fw_cb_dma);
+
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: Failed to get init_fw_ctrl_blk\n",
+ ha->host_no, __func__));
+ dma_free_coherent(&ha->pdev->dev,
+ sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+ return QLA_ERROR;
+ }
+
+ /* Save IP Address. */
+ memcpy(ha->ip_address, init_fw_cb->IPAddr,
+ min(sizeof(ha->ip_address), sizeof(init_fw_cb->IPAddr)));
+ memcpy(ha->subnet_mask, init_fw_cb->SubnetMask,
+ min(sizeof(ha->subnet_mask), sizeof(init_fw_cb->SubnetMask)));
+ memcpy(ha->gateway, init_fw_cb->GatewayIPAddr,
+ min(sizeof(ha->gateway), sizeof(init_fw_cb->GatewayIPAddr)));
+
+ dma_free_coherent(&ha->pdev->dev, sizeof(struct init_fw_ctrl_blk),
+ init_fw_cb, init_fw_cb_dma);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_firmware_state - gets firmware state of HBA
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_get_firmware_state(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Get firmware version */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_FW_STATE;
+ if (qla4xxx_mailbox_command(ha, 1, 4, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATE failed w/ "
+ "status %04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ return QLA_ERROR;
+ }
+ ha->firmware_state = mbox_sts[1];
+ ha->board_id = mbox_sts[2];
+ ha->addl_fw_state = mbox_sts[3];
+ DEBUG2(printk("scsi%ld: %s firmware_state=0x%x\n",
+ ha->host_no, __func__, ha->firmware_state);)
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_firmware_status - retrieves firmware status
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_get_firmware_status(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Get firmware version */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_FW_STATUS;
+ if (qla4xxx_mailbox_command(ha, 1, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_FW_STATUS failed w/ "
+ "status %04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ return QLA_ERROR;
+ }
+
+ /* High-water mark of IOCBs */
+ ha->iocb_hiwat = mbox_sts[2];
+ if (ha->iocb_hiwat > IOCB_HIWAT_CUSHION)
+ ha->iocb_hiwat -= IOCB_HIWAT_CUSHION;
+ else
+ dev_info(&ha->pdev->dev, "WARNING!!! You have less than %d "
+ "firmare IOCBs available (%d).\n",
+ IOCB_HIWAT_CUSHION, ha->iocb_hiwat);
+
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_fwddb_entry - retrieves firmware ddb entry
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ * @fw_ddb_entry: Pointer to firmware's device database entry structure
+ * @num_valid_ddb_entries: Pointer to number of valid ddb entries
+ * @next_ddb_index: Pointer to next valid device database index
+ * @fw_ddb_device_state: Pointer to device state
+ **/
+int qla4xxx_get_fwddb_entry(struct scsi_qla_host *ha,
+ uint16_t fw_ddb_index,
+ struct dev_db_entry *fw_ddb_entry,
+ dma_addr_t fw_ddb_entry_dma,
+ uint32_t *num_valid_ddb_entries,
+ uint32_t *next_ddb_index,
+ uint32_t *fw_ddb_device_state,
+ uint32_t *conn_err_detail,
+ uint16_t *tcp_source_port_num,
+ uint16_t *connection_id)
+{
+ int status = QLA_ERROR;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Make sure the device index is valid */
+ if (fw_ddb_index >= MAX_DDB_ENTRIES) {
+ DEBUG2(printk("scsi%ld: %s: index [%d] out of range.\n",
+ ha->host_no, __func__, fw_ddb_index));
+ goto exit_get_fwddb;
+ }
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY;
+ mbox_cmd[1] = (uint32_t) fw_ddb_index;
+ mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
+ mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 7, &mbox_cmd[0], &mbox_sts[0]) ==
+ QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_GET_DATABASE_ENTRY failed"
+ " with status 0x%04X\n", ha->host_no, __func__,
+ mbox_sts[0]));
+ goto exit_get_fwddb;
+ }
+ if (fw_ddb_index != mbox_sts[1]) {
+ DEBUG2(printk("scsi%ld: %s: index mismatch [%d] != [%d].\n",
+ ha->host_no, __func__, fw_ddb_index,
+ mbox_sts[1]));
+ goto exit_get_fwddb;
+ }
+ if (fw_ddb_entry) {
+ dev_info(&ha->pdev->dev, "DDB[%d] MB0 %04x Tot %d Next %d "
+ "State %04x ConnErr %08x %d.%d.%d.%d:%04d \"%s\"\n",
+ fw_ddb_index, mbox_sts[0], mbox_sts[2], mbox_sts[3],
+ mbox_sts[4], mbox_sts[5], fw_ddb_entry->ipAddr[0],
+ fw_ddb_entry->ipAddr[1], fw_ddb_entry->ipAddr[2],
+ fw_ddb_entry->ipAddr[3],
+ le16_to_cpu(fw_ddb_entry->portNumber),
+ fw_ddb_entry->iscsiName);
+ }
+ if (num_valid_ddb_entries)
+ *num_valid_ddb_entries = mbox_sts[2];
+ if (next_ddb_index)
+ *next_ddb_index = mbox_sts[3];
+ if (fw_ddb_device_state)
+ *fw_ddb_device_state = mbox_sts[4];
+
+ /*
+ * RA: This mailbox has been changed to pass connection error and
+ * details. Its true for ISP4010 as per Version E - Not sure when it
+ * was changed. Get the time2wait from the fw_dd_entry field :
+ * default_time2wait which we call it as minTime2Wait DEV_DB_ENTRY
+ * struct.
+ */
+ if (conn_err_detail)
+ *conn_err_detail = mbox_sts[5];
+ if (tcp_source_port_num)
+ *tcp_source_port_num = (uint16_t) mbox_sts[6] >> 16;
+ if (connection_id)
+ *connection_id = (uint16_t) mbox_sts[6] & 0x00FF;
+ status = QLA_SUCCESS;
+
+exit_get_fwddb:
+ return status;
+}
+
+/**
+ * qla4xxx_set_fwddb_entry - sets a ddb entry.
+ * @ha: Pointer to host adapter structure.
+ * @fw_ddb_index: Firmware's device database index
+ * @fw_ddb_entry: Pointer to firmware's ddb entry structure, or NULL.
+ *
+ * This routine initializes or updates the adapter's device database
+ * entry for the specified device. It also triggers a login for the
+ * specified device. Therefore, it may also be used as a secondary
+ * login routine when a NULL pointer is specified for the fw_ddb_entry.
+ **/
+int qla4xxx_set_ddb_entry(struct scsi_qla_host * ha, uint16_t fw_ddb_index,
+ dma_addr_t fw_ddb_entry_dma)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Do not wait for completion. The firmware will send us an
+ * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
+ */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_SET_DATABASE_ENTRY;
+ mbox_cmd[1] = (uint32_t) fw_ddb_index;
+ mbox_cmd[2] = LSDW(fw_ddb_entry_dma);
+ mbox_cmd[3] = MSDW(fw_ddb_entry_dma);
+ return qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]);
+}
+
+int qla4xxx_conn_open_session_login(struct scsi_qla_host * ha,
+ uint16_t fw_ddb_index)
+{
+ int status = QLA_ERROR;
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Do not wait for completion. The firmware will send us an
+ * ASTS_DATABASE_CHANGED (0x8014) to notify us of the login status.
+ */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_CONN_OPEN_SESS_LOGIN;
+ mbox_cmd[1] = (uint32_t) fw_ddb_index;
+ mbox_cmd[2] = 0;
+ mbox_cmd[3] = 0;
+ mbox_cmd[4] = 0;
+ status = qla4xxx_mailbox_command(ha, 4, 0, &mbox_cmd[0], &mbox_sts[0]);
+ DEBUG2(printk("%s fw_ddb_index=%d status=%d mbx0_1=0x%x :0x%x\n",
+ __func__, fw_ddb_index, status, mbox_sts[0],
+ mbox_sts[1]);)
+
+ return status;
+}
+
+/**
+ * qla4xxx_get_crash_record - retrieves crash record.
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine retrieves a crash record from the QLA4010 after an 8002h aen.
+ **/
+void qla4xxx_get_crash_record(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ struct crash_record *crash_record = NULL;
+ dma_addr_t crash_record_dma = 0;
+ uint32_t crash_record_size = 0;
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
+ /* Get size of crash record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
+ if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve size!\n",
+ ha->host_no, __func__));
+ goto exit_get_crash_record;
+ }
+ crash_record_size = mbox_sts[4];
+ if (crash_record_size == 0) {
+ DEBUG2(printk("scsi%ld: %s: ERROR: Crash record size is 0!\n",
+ ha->host_no, __func__));
+ goto exit_get_crash_record;
+ }
+
+ /* Alloc Memory for Crash Record. */
+ crash_record = dma_alloc_coherent(&ha->pdev->dev, crash_record_size,
+ &crash_record_dma, GFP_KERNEL);
+ if (crash_record == NULL)
+ goto exit_get_crash_record;
+
+ /* Get Crash Record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CRASH_RECORD;
+ mbox_cmd[2] = LSDW(crash_record_dma);
+ mbox_cmd[3] = MSDW(crash_record_dma);
+ mbox_cmd[4] = crash_record_size;
+ if (qla4xxx_mailbox_command(ha, 5, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS)
+ goto exit_get_crash_record;
+
+ /* Dump Crash Record. */
+
+exit_get_crash_record:
+ if (crash_record)
+ dma_free_coherent(&ha->pdev->dev, crash_record_size,
+ crash_record, crash_record_dma);
+}
+
+/**
+ * qla4xxx_get_conn_event_log - retrieves connection event log
+ * @ha: Pointer to host adapter structure.
+ **/
+void qla4xxx_get_conn_event_log(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ struct conn_event_log_entry *event_log = NULL;
+ dma_addr_t event_log_dma = 0;
+ uint32_t event_log_size = 0;
+ uint32_t num_valid_entries;
+ uint32_t oldest_entry = 0;
+ uint32_t max_event_log_entries;
+ uint8_t i;
+
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_cmd));
+
+ /* Get size of crash record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
+ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS)
+ goto exit_get_event_log;
+
+ event_log_size = mbox_sts[4];
+ if (event_log_size == 0)
+ goto exit_get_event_log;
+
+ /* Alloc Memory for Crash Record. */
+ event_log = dma_alloc_coherent(&ha->pdev->dev, event_log_size,
+ &event_log_dma, GFP_KERNEL);
+ if (event_log == NULL)
+ goto exit_get_event_log;
+
+ /* Get Crash Record. */
+ mbox_cmd[0] = MBOX_CMD_GET_CONN_EVENT_LOG;
+ mbox_cmd[2] = LSDW(event_log_dma);
+ mbox_cmd[3] = MSDW(event_log_dma);
+ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: ERROR: Unable to retrieve event "
+ "log!\n", ha->host_no, __func__));
+ goto exit_get_event_log;
+ }
+
+ /* Dump Event Log. */
+ num_valid_entries = mbox_sts[1];
+
+ max_event_log_entries = event_log_size /
+ sizeof(struct conn_event_log_entry);
+
+ if (num_valid_entries > max_event_log_entries)
+ oldest_entry = num_valid_entries % max_event_log_entries;
+
+ DEBUG3(printk("scsi%ld: Connection Event Log Dump (%d entries):\n",
+ ha->host_no, num_valid_entries));
+
+ if (qla4_extended_error_logging == 3) {
+ if (oldest_entry == 0) {
+ /* Circular Buffer has not wrapped around */
+ for (i=0; i < num_valid_entries; i++) {
+ qla4xxx_dump_buffer((uint8_t *)event_log+
+ (i*sizeof(*event_log)),
+ sizeof(*event_log));
+ }
+ }
+ else {
+ /* Circular Buffer has wrapped around -
+ * display accordingly*/
+ for (i=oldest_entry; i < max_event_log_entries; i++) {
+ qla4xxx_dump_buffer((uint8_t *)event_log+
+ (i*sizeof(*event_log)),
+ sizeof(*event_log));
+ }
+ for (i=0; i < oldest_entry; i++) {
+ qla4xxx_dump_buffer((uint8_t *)event_log+
+ (i*sizeof(*event_log)),
+ sizeof(*event_log));
+ }
+ }
+ }
+
+exit_get_event_log:
+ if (event_log)
+ dma_free_coherent(&ha->pdev->dev, event_log_size, event_log,
+ event_log_dma);
+}
+
+/**
+ * qla4xxx_reset_lun - issues LUN Reset
+ * @ha: Pointer to host adapter structure.
+ * @db_entry: Pointer to device database entry
+ * @un_entry: Pointer to lun entry structure
+ *
+ * This routine performs a LUN RESET on the specified target/lun.
+ * The caller must ensure that the ddb_entry and lun_entry pointers
+ * are valid before calling this routine.
+ **/
+int qla4xxx_reset_lun(struct scsi_qla_host * ha, struct ddb_entry * ddb_entry,
+ int lun)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+ int status = QLA_SUCCESS;
+
+ DEBUG2(printk("scsi%ld:%d:%d: lun reset issued\n", ha->host_no,
+ ddb_entry->os_target_id, lun));
+
+ /*
+ * Send lun reset command to ISP, so that the ISP will return all
+ * outstanding requests with RESET status
+ */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_LUN_RESET;
+ mbox_cmd[1] = ddb_entry->fw_ddb_index;
+ mbox_cmd[2] = lun << 8;
+ mbox_cmd[5] = 0x01; /* Immediate Command Enable */
+ qla4xxx_mailbox_command(ha, 6, 1, &mbox_cmd[0], &mbox_sts[0]);
+ if (mbox_sts[0] != MBOX_STS_COMMAND_COMPLETE &&
+ mbox_sts[0] != MBOX_STS_COMMAND_ERROR)
+ status = QLA_ERROR;
+
+ return status;
+}
+
+
+int qla4xxx_get_flash(struct scsi_qla_host * ha, dma_addr_t dma_addr,
+ uint32_t offset, uint32_t len)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_READ_FLASH;
+ mbox_cmd[1] = LSDW(dma_addr);
+ mbox_cmd[2] = MSDW(dma_addr);
+ mbox_cmd[3] = offset;
+ mbox_cmd[4] = len;
+ if (qla4xxx_mailbox_command(ha, 5, 2, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_READ_FLASH, failed w/ "
+ "status %04X %04X, offset %08x, len %08x\n", ha->host_no,
+ __func__, mbox_sts[0], mbox_sts[1], offset, len));
+ return QLA_ERROR;
+ }
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_get_fw_version - gets firmware version
+ * @ha: Pointer to host adapter structure.
+ *
+ * Retrieves the firmware version on HBA. In QLA4010, mailboxes 2 & 3 may
+ * hold an address for data. Make sure that we write 0 to those mailboxes,
+ * if unused.
+ **/
+int qla4xxx_get_fw_version(struct scsi_qla_host * ha)
+{
+ uint32_t mbox_cmd[MBOX_REG_COUNT];
+ uint32_t mbox_sts[MBOX_REG_COUNT];
+
+ /* Get firmware version. */
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+ mbox_cmd[0] = MBOX_CMD_ABOUT_FW;
+ if (qla4xxx_mailbox_command(ha, 4, 5, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: MBOX_CMD_ABOUT_FW failed w/ "
+ "status %04X\n", ha->host_no, __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+
+ /* Save firmware version information. */
+ ha->firmware_version[0] = mbox_sts[1];
+ ha->firmware_version[1] = mbox_sts[2];
+ ha->patch_number = mbox_sts[3];
+ ha->build_number = mbox_sts[4];
+
+ return QLA_SUCCESS;
+}
+
+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];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_GET_DATABASE_ENTRY_DEFAULTS;
+ mbox_cmd[2] = LSDW(dma_addr);
+ mbox_cmd[3] = MSDW(dma_addr);
+
+ if (qla4xxx_mailbox_command(ha, 4, 1, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
+ ha->host_no, __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+ return QLA_SUCCESS;
+}
+
+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];
+
+ memset(&mbox_cmd, 0, sizeof(mbox_cmd));
+ memset(&mbox_sts, 0, sizeof(mbox_sts));
+
+ mbox_cmd[0] = MBOX_CMD_REQUEST_DATABASE_ENTRY;
+ mbox_cmd[1] = MAX_PRST_DEV_DB_ENTRIES;
+
+ if (qla4xxx_mailbox_command(ha, 2, 3, &mbox_cmd[0], &mbox_sts[0]) !=
+ QLA_SUCCESS) {
+ if (mbox_sts[0] == MBOX_STS_COMMAND_ERROR) {
+ *ddb_index = mbox_sts[2];
+ } else {
+ DEBUG2(printk("scsi%ld: %s: failed status %04X\n",
+ ha->host_no, __func__, mbox_sts[0]));
+ return QLA_ERROR;
+ }
+ } else {
+ *ddb_index = MAX_PRST_DEV_DB_ENTRIES;
+ }
+
+ return QLA_SUCCESS;
+}
+
+
+int qla4xxx_send_tgts(struct scsi_qla_host *ha, char *ip, uint16_t port)
+{
+ struct dev_db_entry *fw_ddb_entry;
+ dma_addr_t fw_ddb_entry_dma;
+ uint32_t ddb_index;
+ int ret_val = QLA_SUCCESS;
+
+
+ fw_ddb_entry = dma_alloc_coherent(&ha->pdev->dev,
+ sizeof(*fw_ddb_entry),
+ &fw_ddb_entry_dma, GFP_KERNEL);
+ if (!fw_ddb_entry) {
+ DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
+ ha->host_no, __func__));
+ ret_val = QLA_ERROR;
+ goto qla4xxx_send_tgts_exit;
+ }
+
+ ret_val = qla4xxx_get_default_ddb(ha, fw_ddb_entry_dma);
+ if (ret_val != QLA_SUCCESS)
+ goto qla4xxx_send_tgts_exit;
+
+ ret_val = qla4xxx_req_ddb_entry(ha, &ddb_index);
+ if (ret_val != QLA_SUCCESS)
+ goto qla4xxx_send_tgts_exit;
+
+ memset((void *)fw_ddb_entry->iSCSIAlias, 0,
+ sizeof(fw_ddb_entry->iSCSIAlias));
+
+ memset((void *)fw_ddb_entry->iscsiName, 0,
+ sizeof(fw_ddb_entry->iscsiName));
+
+ memset((void *)fw_ddb_entry->ipAddr, 0, sizeof(fw_ddb_entry->ipAddr));
+ memset((void *)fw_ddb_entry->targetAddr, 0,
+ sizeof(fw_ddb_entry->targetAddr));
+
+ fw_ddb_entry->options = (DDB_OPT_DISC_SESSION | DDB_OPT_TARGET);
+ fw_ddb_entry->portNumber = cpu_to_le16(ntohs(port));
+
+ fw_ddb_entry->ipAddr[0] = *ip;
+ fw_ddb_entry->ipAddr[1] = *(ip + 1);
+ fw_ddb_entry->ipAddr[2] = *(ip + 2);
+ fw_ddb_entry->ipAddr[3] = *(ip + 3);
+
+ ret_val = qla4xxx_set_ddb_entry(ha, ddb_index, fw_ddb_entry_dma);
+
+qla4xxx_send_tgts_exit:
+ dma_free_coherent(&ha->pdev->dev, sizeof(*fw_ddb_entry),
+ fw_ddb_entry, fw_ddb_entry_dma);
+ return ret_val;
+}
+
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.c b/drivers/scsi/qla4xxx/ql4_nvram.c
new file mode 100644
index 000000000000..e3957ca5b645
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nvram.c
@@ -0,0 +1,224 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#include "ql4_def.h"
+
+static inline int eeprom_size(struct scsi_qla_host *ha)
+{
+ return is_qla4022(ha) ? FM93C86A_SIZE_16 : FM93C66A_SIZE_16;
+}
+
+static inline int eeprom_no_addr_bits(struct scsi_qla_host *ha)
+{
+ return is_qla4022(ha) ? FM93C86A_NO_ADDR_BITS_16 :
+ FM93C56A_NO_ADDR_BITS_16;
+}
+
+static inline int eeprom_no_data_bits(struct scsi_qla_host *ha)
+{
+ return FM93C56A_DATA_BITS_16;
+}
+
+static int fm93c56a_select(struct scsi_qla_host * ha)
+{
+ DEBUG5(printk(KERN_ERR "fm93c56a_select:\n"));
+
+ ha->eeprom_cmd_data = AUBURN_EEPROM_CS_1 | 0x000f0000;
+ writel(ha->eeprom_cmd_data, isp_nvram(ha));
+ readl(isp_nvram(ha));
+ return 1;
+}
+
+static int fm93c56a_cmd(struct scsi_qla_host * ha, int cmd, int addr)
+{
+ int i;
+ int mask;
+ int dataBit;
+ int previousBit;
+
+ /* Clock in a zero, then do the start bit. */
+ writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1, isp_nvram(ha));
+ writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
+ writel(ha->eeprom_cmd_data | AUBURN_EEPROM_DO_1 |
+ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
+ readl(isp_nvram(ha));
+ mask = 1 << (FM93C56A_CMD_BITS - 1);
+
+ /* Force the previous data bit to be different. */
+ previousBit = 0xffff;
+ for (i = 0; i < FM93C56A_CMD_BITS; i++) {
+ dataBit =
+ (cmd & mask) ? AUBURN_EEPROM_DO_1 : AUBURN_EEPROM_DO_0;
+ if (previousBit != dataBit) {
+
+ /*
+ * If the bit changed, then change the DO state to
+ * match.
+ */
+ writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
+ previousBit = dataBit;
+ }
+ writel(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
+ writel(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
+ readl(isp_nvram(ha));
+ cmd = cmd << 1;
+ }
+ mask = 1 << (eeprom_no_addr_bits(ha) - 1);
+
+ /* Force the previous data bit to be different. */
+ previousBit = 0xffff;
+ for (i = 0; i < eeprom_no_addr_bits(ha); i++) {
+ dataBit = addr & mask ? AUBURN_EEPROM_DO_1 :
+ AUBURN_EEPROM_DO_0;
+ if (previousBit != dataBit) {
+ /*
+ * If the bit changed, then change the DO state to
+ * match.
+ */
+ writel(ha->eeprom_cmd_data | dataBit, isp_nvram(ha));
+ previousBit = dataBit;
+ }
+ writel(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
+ writel(ha->eeprom_cmd_data | dataBit |
+ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
+ readl(isp_nvram(ha));
+ addr = addr << 1;
+ }
+ return 1;
+}
+
+static int fm93c56a_deselect(struct scsi_qla_host * ha)
+{
+ ha->eeprom_cmd_data = AUBURN_EEPROM_CS_0 | 0x000f0000;
+ writel(ha->eeprom_cmd_data, isp_nvram(ha));
+ readl(isp_nvram(ha));
+ return 1;
+}
+
+static int fm93c56a_datain(struct scsi_qla_host * ha, unsigned short *value)
+{
+ int i;
+ int data = 0;
+ int dataBit;
+
+ /* Read the data bits
+ * The first bit is a dummy. Clock right over it. */
+ for (i = 0; i < eeprom_no_data_bits(ha); i++) {
+ writel(ha->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_RISE, isp_nvram(ha));
+ writel(ha->eeprom_cmd_data |
+ AUBURN_EEPROM_CLK_FALL, isp_nvram(ha));
+ dataBit =
+ (readw(isp_nvram(ha)) & AUBURN_EEPROM_DI_1) ? 1 : 0;
+ data = (data << 1) | dataBit;
+ }
+
+ *value = data;
+ return 1;
+}
+
+static int eeprom_readword(int eepromAddr, u16 * value,
+ struct scsi_qla_host * ha)
+{
+ fm93c56a_select(ha);
+ fm93c56a_cmd(ha, FM93C56A_READ, eepromAddr);
+ fm93c56a_datain(ha, value);
+ fm93c56a_deselect(ha);
+ return 1;
+}
+
+/* Hardware_lock must be set before calling */
+u16 rd_nvram_word(struct scsi_qla_host * ha, int offset)
+{
+ u16 val;
+
+ /* NOTE: NVRAM uses half-word addresses */
+ eeprom_readword(offset, &val, ha);
+ return val;
+}
+
+int qla4xxx_is_nvram_configuration_valid(struct scsi_qla_host * ha)
+{
+ int status = QLA_ERROR;
+ uint16_t checksum = 0;
+ uint32_t index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (index = 0; index < eeprom_size(ha); index++)
+ checksum += rd_nvram_word(ha, index);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (checksum == 0)
+ status = QLA_SUCCESS;
+
+ return status;
+}
+
+/*************************************************************************
+ *
+ * Hardware Semaphore routines
+ *
+ *************************************************************************/
+int ql4xxx_sem_spinlock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
+{
+ uint32_t value;
+ unsigned long flags;
+ unsigned int seconds = 30;
+
+ DEBUG2(printk("scsi%ld : Trying to get SEM lock - mask= 0x%x, code = "
+ "0x%x\n", ha->host_no, sem_mask, sem_bits));
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel((sem_mask | sem_bits), isp_semaphore(ha));
+ value = readw(isp_semaphore(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if ((value & (sem_mask >> 16)) == sem_bits) {
+ DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, "
+ "code = 0x%x\n", ha->host_no,
+ sem_mask, sem_bits));
+ return QLA_SUCCESS;
+ }
+ ssleep(1);
+ } while (--seconds);
+ return QLA_ERROR;
+}
+
+void ql4xxx_sem_unlock(struct scsi_qla_host * ha, u32 sem_mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(sem_mask, isp_semaphore(ha));
+ readl(isp_semaphore(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ DEBUG2(printk("scsi%ld : UNLOCK SEM - mask= 0x%x\n", ha->host_no,
+ sem_mask));
+}
+
+int ql4xxx_sem_lock(struct scsi_qla_host * ha, u32 sem_mask, u32 sem_bits)
+{
+ uint32_t value;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel((sem_mask | sem_bits), isp_semaphore(ha));
+ value = readw(isp_semaphore(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ if ((value & (sem_mask >> 16)) == sem_bits) {
+ DEBUG2(printk("scsi%ld : Got SEM LOCK - mask= 0x%x, code = "
+ "0x%x, sema code=0x%x\n", ha->host_no,
+ sem_mask, sem_bits, value));
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/scsi/qla4xxx/ql4_nvram.h b/drivers/scsi/qla4xxx/ql4_nvram.h
new file mode 100644
index 000000000000..08e2aed8c6cc
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_nvram.h
@@ -0,0 +1,256 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#ifndef _QL4XNVRM_H_
+#define _QL4XNVRM_H_
+
+/*
+ * AM29LV Flash definitions
+ */
+#define FM93C56A_SIZE_8 0x100
+#define FM93C56A_SIZE_16 0x80
+#define FM93C66A_SIZE_8 0x200
+#define FM93C66A_SIZE_16 0x100/* 4010 */
+#define FM93C86A_SIZE_16 0x400/* 4022 */
+
+#define FM93C56A_START 0x1
+
+// Commands
+#define FM93C56A_READ 0x2
+#define FM93C56A_WEN 0x0
+#define FM93C56A_WRITE 0x1
+#define FM93C56A_WRITE_ALL 0x0
+#define FM93C56A_WDS 0x0
+#define FM93C56A_ERASE 0x3
+#define FM93C56A_ERASE_ALL 0x0
+
+/* Command Extentions */
+#define FM93C56A_WEN_EXT 0x3
+#define FM93C56A_WRITE_ALL_EXT 0x1
+#define FM93C56A_WDS_EXT 0x0
+#define FM93C56A_ERASE_ALL_EXT 0x2
+
+/* Address Bits */
+#define FM93C56A_NO_ADDR_BITS_16 8 /* 4010 */
+#define FM93C56A_NO_ADDR_BITS_8 9 /* 4010 */
+#define FM93C86A_NO_ADDR_BITS_16 10 /* 4022 */
+
+/* Data Bits */
+#define FM93C56A_DATA_BITS_16 16
+#define FM93C56A_DATA_BITS_8 8
+
+/* Special Bits */
+#define FM93C56A_READ_DUMMY_BITS 1
+#define FM93C56A_READY 0
+#define FM93C56A_BUSY 1
+#define FM93C56A_CMD_BITS 2
+
+/* Auburn Bits */
+#define AUBURN_EEPROM_DI 0x8
+#define AUBURN_EEPROM_DI_0 0x0
+#define AUBURN_EEPROM_DI_1 0x8
+#define AUBURN_EEPROM_DO 0x4
+#define AUBURN_EEPROM_DO_0 0x0
+#define AUBURN_EEPROM_DO_1 0x4
+#define AUBURN_EEPROM_CS 0x2
+#define AUBURN_EEPROM_CS_0 0x0
+#define AUBURN_EEPROM_CS_1 0x2
+#define AUBURN_EEPROM_CLK_RISE 0x1
+#define AUBURN_EEPROM_CLK_FALL 0x0
+
+/* */
+/* EEPROM format */
+/* */
+struct bios_params {
+ uint16_t SpinUpDelay:1;
+ uint16_t BIOSDisable:1;
+ uint16_t MMAPEnable:1;
+ uint16_t BootEnable:1;
+ uint16_t Reserved0:12;
+ uint8_t bootID0:7;
+ uint8_t bootID0Valid:1;
+ uint8_t bootLUN0[8];
+ uint8_t bootID1:7;
+ uint8_t bootID1Valid:1;
+ uint8_t bootLUN1[8];
+ uint16_t MaxLunsPerTarget;
+ uint8_t Reserved1[10];
+};
+
+struct eeprom_port_cfg {
+
+ /* MTU MAC 0 */
+ u16 etherMtu_mac;
+
+ /* Flow Control MAC 0 */
+ u16 pauseThreshold_mac;
+ u16 resumeThreshold_mac;
+ u16 reserved[13];
+};
+
+struct eeprom_function_cfg {
+ u8 reserved[30];
+
+ /* MAC ADDR */
+ u8 macAddress[6];
+ u8 macAddressSecondary[6];
+ u16 subsysVendorId;
+ u16 subsysDeviceId;
+};
+
+struct eeprom_data {
+ union {
+ struct { /* isp4010 */
+ u8 asic_id[4]; /* x00 */
+ u8 version; /* x04 */
+ u8 reserved; /* x05 */
+ u16 board_id; /* x06 */
+#define EEPROM_BOARDID_ELDORADO 1
+#define EEPROM_BOARDID_PLACER 2
+
+#define EEPROM_SERIAL_NUM_SIZE 16
+ u8 serial_number[EEPROM_SERIAL_NUM_SIZE]; /* x08 */
+
+ /* ExtHwConfig: */
+ /* Offset = 24bytes
+ *
+ * | SSRAM Size| |ST|PD|SDRAM SZ| W| B| SP | |
+ * |15|14|13|12|11|10| 9| 8| 7| 6| 5| 4| 3| 2| 1| 0|
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+ u16 ext_hw_conf; /* x18 */
+ u8 mac0[6]; /* x1A */
+ u8 mac1[6]; /* x20 */
+ u8 mac2[6]; /* x26 */
+ u8 mac3[6]; /* x2C */
+ u16 etherMtu; /* x32 */
+ u16 macConfig; /* x34 */
+#define MAC_CONFIG_ENABLE_ANEG 0x0001
+#define MAC_CONFIG_ENABLE_PAUSE 0x0002
+ u16 phyConfig; /* x36 */
+#define PHY_CONFIG_PHY_ADDR_MASK 0x1f
+#define PHY_CONFIG_ENABLE_FW_MANAGEMENT_MASK 0x20
+ u16 topcat; /* x38 */
+#define TOPCAT_PRESENT 0x0100
+#define TOPCAT_MASK 0xFF00
+
+#define EEPROM_UNUSED_1_SIZE 2
+ u8 unused_1[EEPROM_UNUSED_1_SIZE]; /* x3A */
+ u16 bufletSize; /* x3C */
+ u16 bufletCount; /* x3E */
+ u16 bufletPauseThreshold; /* x40 */
+ u16 tcpWindowThreshold50; /* x42 */
+ u16 tcpWindowThreshold25; /* x44 */
+ u16 tcpWindowThreshold0; /* x46 */
+ u16 ipHashTableBaseHi; /* x48 */
+ u16 ipHashTableBaseLo; /* x4A */
+ u16 ipHashTableSize; /* x4C */
+ u16 tcpHashTableBaseHi; /* x4E */
+ u16 tcpHashTableBaseLo; /* x50 */
+ u16 tcpHashTableSize; /* x52 */
+ u16 ncbTableBaseHi; /* x54 */
+ u16 ncbTableBaseLo; /* x56 */
+ u16 ncbTableSize; /* x58 */
+ u16 drbTableBaseHi; /* x5A */
+ u16 drbTableBaseLo; /* x5C */
+ u16 drbTableSize; /* x5E */
+
+#define EEPROM_UNUSED_2_SIZE 4
+ u8 unused_2[EEPROM_UNUSED_2_SIZE]; /* x60 */
+ u16 ipReassemblyTimeout; /* x64 */
+ u16 tcpMaxWindowSizeHi; /* x66 */
+ u16 tcpMaxWindowSizeLo; /* x68 */
+ u32 net_ip_addr0; /* x6A Added for TOE
+ * functionality. */
+ u32 net_ip_addr1; /* x6E */
+ u32 scsi_ip_addr0; /* x72 */
+ u32 scsi_ip_addr1; /* x76 */
+#define EEPROM_UNUSED_3_SIZE 128 /* changed from 144 to account
+ * for ip addresses */
+ u8 unused_3[EEPROM_UNUSED_3_SIZE]; /* x7A */
+ u16 subsysVendorId_f0; /* xFA */
+ u16 subsysDeviceId_f0; /* xFC */
+
+ /* Address = 0x7F */
+#define FM93C56A_SIGNATURE 0x9356
+#define FM93C66A_SIGNATURE 0x9366
+ u16 signature; /* xFE */
+
+#define EEPROM_UNUSED_4_SIZE 250
+ u8 unused_4[EEPROM_UNUSED_4_SIZE]; /* x100 */
+ u16 subsysVendorId_f1; /* x1FA */
+ u16 subsysDeviceId_f1; /* x1FC */
+ u16 checksum; /* x1FE */
+ } __attribute__ ((packed)) isp4010;
+ struct { /* isp4022 */
+ u8 asicId[4]; /* x00 */
+ u8 version; /* x04 */
+ u8 reserved_5; /* x05 */
+ u16 boardId; /* x06 */
+ u8 boardIdStr[16]; /* x08 */
+ u8 serialNumber[16]; /* x18 */
+
+ /* External Hardware Configuration */
+ u16 ext_hw_conf; /* x28 */
+
+ /* MAC 0 CONFIGURATION */
+ struct eeprom_port_cfg macCfg_port0; /* x2A */
+
+ /* MAC 1 CONFIGURATION */
+ struct eeprom_port_cfg macCfg_port1; /* x4A */
+
+ /* DDR SDRAM Configuration */
+ u16 bufletSize; /* x6A */
+ u16 bufletCount; /* x6C */
+ u16 tcpWindowThreshold50; /* x6E */
+ u16 tcpWindowThreshold25; /* x70 */
+ u16 tcpWindowThreshold0; /* x72 */
+ u16 ipHashTableBaseHi; /* x74 */
+ u16 ipHashTableBaseLo; /* x76 */
+ u16 ipHashTableSize; /* x78 */
+ u16 tcpHashTableBaseHi; /* x7A */
+ u16 tcpHashTableBaseLo; /* x7C */
+ u16 tcpHashTableSize; /* x7E */
+ u16 ncbTableBaseHi; /* x80 */
+ u16 ncbTableBaseLo; /* x82 */
+ u16 ncbTableSize; /* x84 */
+ u16 drbTableBaseHi; /* x86 */
+ u16 drbTableBaseLo; /* x88 */
+ u16 drbTableSize; /* x8A */
+ u16 reserved_142[4]; /* x8C */
+
+ /* TCP/IP Parameters */
+ u16 ipReassemblyTimeout; /* x94 */
+ u16 tcpMaxWindowSize; /* x96 */
+ u16 ipSecurity; /* x98 */
+ u8 reserved_156[294]; /* x9A */
+ u16 qDebug[8]; /* QLOGIC USE ONLY x1C0 */
+ struct eeprom_function_cfg funcCfg_fn0; /* x1D0 */
+ u16 reserved_510; /* x1FE */
+
+ /* Address = 512 */
+ u8 oemSpace[432]; /* x200 */
+ struct bios_params sBIOSParams_fn1; /* x3B0 */
+ struct eeprom_function_cfg funcCfg_fn1; /* x3D0 */
+ u16 reserved_1022; /* x3FE */
+
+ /* Address = 1024 */
+ u8 reserved_1024[464]; /* x400 */
+ struct eeprom_function_cfg funcCfg_fn2; /* x5D0 */
+ u16 reserved_1534; /* x5FE */
+
+ /* Address = 1536 */
+ u8 reserved_1536[432]; /* x600 */
+ struct bios_params sBIOSParams_fn3; /* x7B0 */
+ struct eeprom_function_cfg funcCfg_fn3; /* x7D0 */
+ u16 checksum; /* x7FE */
+ } __attribute__ ((packed)) isp4022;
+ };
+};
+
+
+#endif /* _QL4XNVRM_H_ */
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
new file mode 100644
index 000000000000..178fcddcfd81
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -0,0 +1,1755 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+#include <linux/moduleparam.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+
+#include "ql4_def.h"
+
+/*
+ * Driver version
+ */
+char qla4xxx_version_str[40];
+
+/*
+ * SRB allocation cache
+ */
+static kmem_cache_t *srb_cachep;
+
+/*
+ * Module parameter information and variables
+ */
+int ql4xdiscoverywait = 60;
+module_param(ql4xdiscoverywait, int, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(ql4xdiscoverywait, "Discovery wait time");
+int ql4xdontresethba = 0;
+module_param(ql4xdontresethba, int, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(ql4xdontresethba,
+ "Dont reset the HBA when the driver gets 0x8002 AEN "
+ " default it will reset hba :0"
+ " set to 1 to avoid resetting HBA");
+
+int qla4_extended_error_logging = 0; /* 0 = off, 1 = log errors */
+module_param(qla4_extended_error_logging, int, S_IRUGO | S_IRUSR);
+MODULE_PARM_DESC(qla4_extended_error_logging,
+ "Option to enable extended error logging, "
+ "Default is 0 - no logging, 1 - debug logging");
+
+/*
+ * SCSI host template entry points
+ */
+
+void qla4xxx_config_dma_addressing(struct scsi_qla_host *ha);
+
+/*
+ * iSCSI template entry points
+ */
+static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
+ uint32_t enable, struct sockaddr *dst_addr);
+static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
+ enum iscsi_param param, char *buf);
+static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
+ enum iscsi_param param, char *buf);
+static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag);
+static int qla4xxx_conn_start(struct iscsi_cls_conn *conn);
+static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session);
+
+/*
+ * SCSI host template entry points
+ */
+static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+ void (*done) (struct scsi_cmnd *));
+static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
+static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
+static int qla4xxx_slave_alloc(struct scsi_device *device);
+static int qla4xxx_slave_configure(struct scsi_device *device);
+static void qla4xxx_slave_destroy(struct scsi_device *sdev);
+
+static struct scsi_host_template qla4xxx_driver_template = {
+ .module = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .proc_name = DRIVER_NAME,
+ .queuecommand = qla4xxx_queuecommand,
+
+ .eh_device_reset_handler = qla4xxx_eh_device_reset,
+ .eh_host_reset_handler = qla4xxx_eh_host_reset,
+
+ .slave_configure = qla4xxx_slave_configure,
+ .slave_alloc = qla4xxx_slave_alloc,
+ .slave_destroy = qla4xxx_slave_destroy,
+
+ .this_id = -1,
+ .cmd_per_lun = 3,
+ .use_clustering = ENABLE_CLUSTERING,
+ .sg_tablesize = SG_ALL,
+
+ .max_sectors = 0xFFFF,
+};
+
+static struct iscsi_transport qla4xxx_iscsi_transport = {
+ .owner = THIS_MODULE,
+ .name = DRIVER_NAME,
+ .param_mask = ISCSI_CONN_PORT |
+ ISCSI_CONN_ADDRESS |
+ ISCSI_TARGET_NAME |
+ ISCSI_TPGT,
+ .sessiondata_size = sizeof(struct ddb_entry),
+ .host_template = &qla4xxx_driver_template,
+
+ .tgt_dscvr = qla4xxx_tgt_dscvr,
+ .get_conn_param = qla4xxx_conn_get_param,
+ .get_session_param = qla4xxx_sess_get_param,
+ .start_conn = qla4xxx_conn_start,
+ .stop_conn = qla4xxx_conn_stop,
+ .session_recovery_timedout = qla4xxx_recovery_timedout,
+};
+
+static struct scsi_transport_template *qla4xxx_scsi_transport;
+
+static void qla4xxx_recovery_timedout(struct iscsi_cls_session *session)
+{
+ struct ddb_entry *ddb_entry = session->dd_data;
+ struct scsi_qla_host *ha = ddb_entry->ha;
+
+ DEBUG2(printk("scsi%ld: %s: index [%d] port down retry count of (%d) "
+ "secs exhausted, marking device DEAD.\n", ha->host_no,
+ __func__, ddb_entry->fw_ddb_index,
+ ha->port_down_retry_count));
+
+ atomic_set(&ddb_entry->state, DDB_STATE_DEAD);
+
+ DEBUG2(printk("scsi%ld: %s: scheduling dpc routine - dpc flags = "
+ "0x%lx\n", ha->host_no, __func__, ha->dpc_flags));
+ queue_work(ha->dpc_thread, &ha->dpc_work);
+}
+
+static int qla4xxx_conn_start(struct iscsi_cls_conn *conn)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ ddb_entry = session->dd_data;
+
+ DEBUG2(printk("scsi%ld: %s: index [%d] starting conn\n",
+ ddb_entry->ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ iscsi_unblock_session(session);
+ return 0;
+}
+
+static void qla4xxx_conn_stop(struct iscsi_cls_conn *conn, int flag)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ ddb_entry = session->dd_data;
+
+ DEBUG2(printk("scsi%ld: %s: index [%d] stopping conn\n",
+ ddb_entry->ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ if (flag == STOP_CONN_RECOVER)
+ iscsi_block_session(session);
+ else
+ printk(KERN_ERR "iscsi: invalid stop flag %d\n", flag);
+}
+
+static int qla4xxx_sess_get_param(struct iscsi_cls_session *sess,
+ enum iscsi_param param, char *buf)
+{
+ struct ddb_entry *ddb_entry = sess->dd_data;
+ int len;
+
+ switch (param) {
+ case ISCSI_PARAM_TARGET_NAME:
+ len = snprintf(buf, PAGE_SIZE - 1, "%s\n",
+ ddb_entry->iscsi_name);
+ break;
+ case ISCSI_PARAM_TPGT:
+ len = sprintf(buf, "%u\n", ddb_entry->tpgt);
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+
+static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn,
+ enum iscsi_param param, char *buf)
+{
+ struct iscsi_cls_session *session;
+ struct ddb_entry *ddb_entry;
+ int len;
+
+ session = iscsi_dev_to_session(conn->dev.parent);
+ ddb_entry = session->dd_data;
+
+ switch (param) {
+ case ISCSI_PARAM_CONN_PORT:
+ len = sprintf(buf, "%hu\n", ddb_entry->port);
+ break;
+ case ISCSI_PARAM_CONN_ADDRESS:
+ /* TODO: what are the ipv6 bits */
+ len = sprintf(buf, "%u.%u.%u.%u\n",
+ NIPQUAD(ddb_entry->ip_addr));
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ return len;
+}
+
+static int qla4xxx_tgt_dscvr(enum iscsi_tgt_dscvr type, uint32_t host_no,
+ uint32_t enable, struct sockaddr *dst_addr)
+{
+ struct scsi_qla_host *ha;
+ struct Scsi_Host *shost;
+ struct sockaddr_in *addr;
+ struct sockaddr_in6 *addr6;
+ int ret = 0;
+
+ shost = scsi_host_lookup(host_no);
+ if (IS_ERR(shost)) {
+ printk(KERN_ERR "Could not find host no %u\n", host_no);
+ return -ENODEV;
+ }
+
+ ha = (struct scsi_qla_host *) shost->hostdata;
+
+ switch (type) {
+ case ISCSI_TGT_DSCVR_SEND_TARGETS:
+ if (dst_addr->sa_family == AF_INET) {
+ addr = (struct sockaddr_in *)dst_addr;
+ if (qla4xxx_send_tgts(ha, (char *)&addr->sin_addr,
+ addr->sin_port) != QLA_SUCCESS)
+ ret = -EIO;
+ } else if (dst_addr->sa_family == AF_INET6) {
+ /*
+ * TODO: fix qla4xxx_send_tgts
+ */
+ addr6 = (struct sockaddr_in6 *)dst_addr;
+ if (qla4xxx_send_tgts(ha, (char *)&addr6->sin6_addr,
+ addr6->sin6_port) != QLA_SUCCESS)
+ ret = -EIO;
+ } else
+ ret = -ENOSYS;
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ scsi_host_put(shost);
+ return ret;
+}
+
+void qla4xxx_destroy_sess(struct ddb_entry *ddb_entry)
+{
+ if (!ddb_entry->sess)
+ return;
+
+ if (ddb_entry->conn) {
+ iscsi_if_destroy_session_done(ddb_entry->conn);
+ iscsi_destroy_conn(ddb_entry->conn);
+ iscsi_remove_session(ddb_entry->sess);
+ }
+ iscsi_free_session(ddb_entry->sess);
+}
+
+int qla4xxx_add_sess(struct ddb_entry *ddb_entry)
+{
+ int err;
+
+ err = iscsi_add_session(ddb_entry->sess, ddb_entry->fw_ddb_index);
+ if (err) {
+ DEBUG2(printk(KERN_ERR "Could not add session.\n"));
+ return err;
+ }
+
+ ddb_entry->conn = iscsi_create_conn(ddb_entry->sess, 0);
+ if (!ddb_entry->conn) {
+ iscsi_remove_session(ddb_entry->sess);
+ DEBUG2(printk(KERN_ERR "Could not add connection.\n"));
+ return -ENOMEM;
+ }
+
+ ddb_entry->sess->recovery_tmo = ddb_entry->ha->port_down_retry_count;
+ iscsi_if_create_session_done(ddb_entry->conn);
+ return 0;
+}
+
+struct ddb_entry *qla4xxx_alloc_sess(struct scsi_qla_host *ha)
+{
+ struct ddb_entry *ddb_entry;
+ struct iscsi_cls_session *sess;
+
+ sess = iscsi_alloc_session(ha->host, &qla4xxx_iscsi_transport);
+ if (!sess)
+ return NULL;
+
+ ddb_entry = sess->dd_data;
+ memset(ddb_entry, 0, sizeof(*ddb_entry));
+ ddb_entry->ha = ha;
+ ddb_entry->sess = sess;
+ return ddb_entry;
+}
+
+/*
+ * Timer routines
+ */
+
+static void qla4xxx_start_timer(struct scsi_qla_host *ha, void *func,
+ unsigned long interval)
+{
+ DEBUG(printk("scsi: %s: Starting timer thread for adapter %d\n",
+ __func__, ha->host->host_no));
+ init_timer(&ha->timer);
+ ha->timer.expires = jiffies + interval * HZ;
+ ha->timer.data = (unsigned long)ha;
+ ha->timer.function = (void (*)(unsigned long))func;
+ add_timer(&ha->timer);
+ ha->timer_active = 1;
+}
+
+static void qla4xxx_stop_timer(struct scsi_qla_host *ha)
+{
+ del_timer_sync(&ha->timer);
+ ha->timer_active = 0;
+}
+
+/***
+ * qla4xxx_mark_device_missing - mark a device as missing.
+ * @ha: Pointer to host adapter structure.
+ * @ddb_entry: Pointer to device database entry
+ *
+ * This routine marks a device missing and resets the relogin retry count.
+ **/
+void qla4xxx_mark_device_missing(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry)
+{
+ atomic_set(&ddb_entry->state, DDB_STATE_MISSING);
+ DEBUG3(printk("scsi%d:%d:%d: index [%d] marked MISSING\n",
+ ha->host_no, ddb_entry->bus, ddb_entry->target,
+ ddb_entry->fw_ddb_index));
+ iscsi_conn_error(ddb_entry->conn, ISCSI_ERR_CONN_FAILED);
+}
+
+static struct srb* qla4xxx_get_new_srb(struct scsi_qla_host *ha,
+ struct ddb_entry *ddb_entry,
+ struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct srb *srb;
+
+ srb = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
+ if (!srb)
+ return srb;
+
+ atomic_set(&srb->ref_count, 1);
+ srb->ha = ha;
+ srb->ddb = ddb_entry;
+ srb->cmd = cmd;
+ srb->flags = 0;
+ cmd->SCp.ptr = (void *)srb;
+ cmd->scsi_done = done;
+
+ return srb;
+}
+
+static void qla4xxx_srb_free_dma(struct scsi_qla_host *ha, struct srb *srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+
+ if (srb->flags & SRB_DMA_VALID) {
+ if (cmd->use_sg) {
+ pci_unmap_sg(ha->pdev, cmd->request_buffer,
+ cmd->use_sg, cmd->sc_data_direction);
+ } else if (cmd->request_bufflen) {
+ pci_unmap_single(ha->pdev, srb->dma_handle,
+ cmd->request_bufflen,
+ cmd->sc_data_direction);
+ }
+ srb->flags &= ~SRB_DMA_VALID;
+ }
+ cmd->SCp.ptr = NULL;
+}
+
+void qla4xxx_srb_compl(struct scsi_qla_host *ha, struct srb *srb)
+{
+ struct scsi_cmnd *cmd = srb->cmd;
+
+ qla4xxx_srb_free_dma(ha, srb);
+
+ mempool_free(srb, ha->srb_mempool);
+
+ cmd->scsi_done(cmd);
+}
+
+/**
+ * qla4xxx_queuecommand - scsi layer issues scsi command to driver.
+ * @cmd: Pointer to Linux's SCSI command structure
+ * @done_fn: Function that the driver calls to notify the SCSI mid-layer
+ * that the command has been processed.
+ *
+ * Remarks:
+ * This routine is invoked by Linux to send a SCSI command to the driver.
+ * The mid-level driver tries to ensure that queuecommand never gets
+ * invoked concurrently with itself or the interrupt handler (although
+ * the interrupt handler may call this routine as part of request-
+ * completion handling). Unfortunely, it sometimes calls the scheduler
+ * in interrupt context which is a big NO! NO!.
+ **/
+static int qla4xxx_queuecommand(struct scsi_cmnd *cmd,
+ void (*done)(struct scsi_cmnd *))
+{
+ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+ struct ddb_entry *ddb_entry = cmd->device->hostdata;
+ struct srb *srb;
+ int rval;
+
+ if (atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+ if (atomic_read(&ddb_entry->state) == DDB_STATE_DEAD) {
+ cmd->result = DID_NO_CONNECT << 16;
+ goto qc_fail_command;
+ }
+ goto qc_host_busy;
+ }
+
+ spin_unlock_irq(ha->host->host_lock);
+
+ srb = qla4xxx_get_new_srb(ha, ddb_entry, cmd, done);
+ if (!srb)
+ goto qc_host_busy_lock;
+
+ rval = qla4xxx_send_command_to_isp(ha, srb);
+ if (rval != QLA_SUCCESS)
+ goto qc_host_busy_free_sp;
+
+ spin_lock_irq(ha->host->host_lock);
+ return 0;
+
+qc_host_busy_free_sp:
+ qla4xxx_srb_free_dma(ha, srb);
+ mempool_free(srb, ha->srb_mempool);
+
+qc_host_busy_lock:
+ spin_lock_irq(ha->host->host_lock);
+
+qc_host_busy:
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+qc_fail_command:
+ done(cmd);
+
+ return 0;
+}
+
+/**
+ * qla4xxx_mem_free - frees memory allocated to adapter
+ * @ha: Pointer to host adapter structure.
+ *
+ * Frees memory previously allocated by qla4xxx_mem_alloc
+ **/
+static void qla4xxx_mem_free(struct scsi_qla_host *ha)
+{
+ if (ha->queues)
+ dma_free_coherent(&ha->pdev->dev, ha->queues_len, ha->queues,
+ ha->queues_dma);
+
+ ha->queues_len = 0;
+ ha->queues = NULL;
+ ha->queues_dma = 0;
+ ha->request_ring = NULL;
+ ha->request_dma = 0;
+ ha->response_ring = NULL;
+ ha->response_dma = 0;
+ ha->shadow_regs = NULL;
+ ha->shadow_regs_dma = 0;
+
+ /* Free srb pool. */
+ if (ha->srb_mempool)
+ mempool_destroy(ha->srb_mempool);
+
+ ha->srb_mempool = NULL;
+
+ /* release io space registers */
+ if (ha->reg)
+ iounmap(ha->reg);
+ pci_release_regions(ha->pdev);
+}
+
+/**
+ * qla4xxx_mem_alloc - allocates memory for use by adapter.
+ * @ha: Pointer to host adapter structure
+ *
+ * Allocates DMA memory for request and response queues. Also allocates memory
+ * for srbs.
+ **/
+static int qla4xxx_mem_alloc(struct scsi_qla_host *ha)
+{
+ unsigned long align;
+
+ /* Allocate contiguous block of DMA memory for queues. */
+ ha->queues_len = ((REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
+ (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE) +
+ sizeof(struct shadow_regs) +
+ MEM_ALIGN_VALUE +
+ (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+ ha->queues = dma_alloc_coherent(&ha->pdev->dev, ha->queues_len,
+ &ha->queues_dma, GFP_KERNEL);
+ if (ha->queues == NULL) {
+ dev_warn(&ha->pdev->dev,
+ "Memory Allocation failed - queues.\n");
+
+ goto mem_alloc_error_exit;
+ }
+ memset(ha->queues, 0, ha->queues_len);
+
+ /*
+ * As per RISC alignment requirements -- the bus-address must be a
+ * multiple of the request-ring size (in bytes).
+ */
+ align = 0;
+ if ((unsigned long)ha->queues_dma & (MEM_ALIGN_VALUE - 1))
+ align = MEM_ALIGN_VALUE - ((unsigned long)ha->queues_dma &
+ (MEM_ALIGN_VALUE - 1));
+
+ /* Update request and response queue pointers. */
+ ha->request_dma = ha->queues_dma + align;
+ ha->request_ring = (struct queue_entry *) (ha->queues + align);
+ ha->response_dma = ha->queues_dma + align +
+ (REQUEST_QUEUE_DEPTH * QUEUE_SIZE);
+ ha->response_ring = (struct queue_entry *) (ha->queues + align +
+ (REQUEST_QUEUE_DEPTH *
+ QUEUE_SIZE));
+ ha->shadow_regs_dma = ha->queues_dma + align +
+ (REQUEST_QUEUE_DEPTH * QUEUE_SIZE) +
+ (RESPONSE_QUEUE_DEPTH * QUEUE_SIZE);
+ ha->shadow_regs = (struct shadow_regs *) (ha->queues + align +
+ (REQUEST_QUEUE_DEPTH *
+ QUEUE_SIZE) +
+ (RESPONSE_QUEUE_DEPTH *
+ QUEUE_SIZE));
+
+ /* Allocate memory for srb pool. */
+ ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
+ mempool_free_slab, srb_cachep);
+ if (ha->srb_mempool == NULL) {
+ dev_warn(&ha->pdev->dev,
+ "Memory Allocation failed - SRB Pool.\n");
+
+ goto mem_alloc_error_exit;
+ }
+
+ return QLA_SUCCESS;
+
+mem_alloc_error_exit:
+ qla4xxx_mem_free(ha);
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_timer - checks every second for work to do.
+ * @ha: Pointer to host adapter structure.
+ **/
+static void qla4xxx_timer(struct scsi_qla_host *ha)
+{
+ struct ddb_entry *ddb_entry, *dtemp;
+ int start_dpc = 0;
+
+ /* Search for relogin's to time-out and port down retry. */
+ list_for_each_entry_safe(ddb_entry, dtemp, &ha->ddb_list, list) {
+ /* Count down time between sending relogins */
+ if (adapter_up(ha) &&
+ !test_bit(DF_RELOGIN, &ddb_entry->flags) &&
+ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE) {
+ if (atomic_read(&ddb_entry->retry_relogin_timer) !=
+ INVALID_ENTRY) {
+ if (atomic_read(&ddb_entry->retry_relogin_timer)
+ == 0) {
+ atomic_set(&ddb_entry->
+ retry_relogin_timer,
+ INVALID_ENTRY);
+ set_bit(DPC_RELOGIN_DEVICE,
+ &ha->dpc_flags);
+ set_bit(DF_RELOGIN, &ddb_entry->flags);
+ DEBUG2(printk("scsi%ld: %s: index [%d]"
+ " login device\n",
+ ha->host_no, __func__,
+ ddb_entry->fw_ddb_index));
+ } else
+ atomic_dec(&ddb_entry->
+ retry_relogin_timer);
+ }
+ }
+
+ /* Wait for relogin to timeout */
+ if (atomic_read(&ddb_entry->relogin_timer) &&
+ (atomic_dec_and_test(&ddb_entry->relogin_timer) != 0)) {
+ /*
+ * If the relogin times out and the device is
+ * still NOT ONLINE then try and relogin again.
+ */
+ if (atomic_read(&ddb_entry->state) !=
+ DDB_STATE_ONLINE &&
+ ddb_entry->fw_ddb_device_state ==
+ DDB_DS_SESSION_FAILED) {
+ /* Reset retry relogin timer */
+ atomic_inc(&ddb_entry->relogin_retry_count);
+ DEBUG2(printk("scsi%ld: index[%d] relogin"
+ " timed out-retrying"
+ " relogin (%d)\n",
+ ha->host_no,
+ ddb_entry->fw_ddb_index,
+ atomic_read(&ddb_entry->
+ relogin_retry_count))
+ );
+ start_dpc++;
+ DEBUG(printk("scsi%ld:%d:%d: index [%d] "
+ "initate relogin after"
+ " %d seconds\n",
+ ha->host_no, ddb_entry->bus,
+ ddb_entry->target,
+ ddb_entry->fw_ddb_index,
+ ddb_entry->default_time2wait + 4)
+ );
+
+ atomic_set(&ddb_entry->retry_relogin_timer,
+ ddb_entry->default_time2wait + 4);
+ }
+ }
+ }
+
+ /* Check for heartbeat interval. */
+ if (ha->firmware_options & FWOPT_HEARTBEAT_ENABLE &&
+ ha->heartbeat_interval != 0) {
+ ha->seconds_since_last_heartbeat++;
+ if (ha->seconds_since_last_heartbeat >
+ ha->heartbeat_interval + 2)
+ set_bit(DPC_RESET_HA, &ha->dpc_flags);
+ }
+
+
+ /* Wakeup the dpc routine for this adapter, if needed. */
+ if ((start_dpc ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+ test_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags) ||
+ test_bit(DPC_AEN, &ha->dpc_flags)) &&
+ ha->dpc_thread) {
+ DEBUG2(printk("scsi%ld: %s: scheduling dpc routine"
+ " - dpc flags = 0x%lx\n",
+ ha->host_no, __func__, ha->dpc_flags));
+ queue_work(ha->dpc_thread, &ha->dpc_work);
+ }
+
+ /* Reschedule timer thread to call us back in one second */
+ mod_timer(&ha->timer, jiffies + HZ);
+
+ DEBUG2(ha->seconds_since_last_intr++);
+}
+
+/**
+ * qla4xxx_cmd_wait - waits for all outstanding commands to complete
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine stalls the driver until all outstanding commands are returned.
+ * Caller must release the Hardware Lock prior to calling this routine.
+ **/
+static int qla4xxx_cmd_wait(struct scsi_qla_host *ha)
+{
+ uint32_t index = 0;
+ int stat = QLA_SUCCESS;
+ unsigned long flags;
+ struct scsi_cmnd *cmd;
+ int wait_cnt = WAIT_CMD_TOV; /*
+ * Initialized for 30 seconds as we
+ * expect all commands to retuned
+ * ASAP.
+ */
+
+ while (wait_cnt) {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ /* Find a command that hasn't completed. */
+ for (index = 0; index < ha->host->can_queue; index++) {
+ cmd = scsi_host_find_tag(ha->host, index);
+ if (cmd != NULL)
+ break;
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* If No Commands are pending, wait is complete */
+ if (index == ha->host->can_queue) {
+ break;
+ }
+
+ /* If we timed out on waiting for commands to come back
+ * return ERROR.
+ */
+ wait_cnt--;
+ if (wait_cnt == 0)
+ stat = QLA_ERROR;
+ else {
+ msleep(1000);
+ }
+ } /* End of While (wait_cnt) */
+
+ return stat;
+}
+
+/**
+ * qla4010_soft_reset - performs soft reset.
+ * @ha: Pointer to host adapter structure.
+ **/
+static int qla4010_soft_reset(struct scsi_qla_host *ha)
+{
+ uint32_t max_wait_time;
+ unsigned long flags = 0;
+ int status = QLA_ERROR;
+ uint32_t ctrl_status;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+
+ /*
+ * If the SCSI Reset Interrupt bit is set, clear it.
+ * Otherwise, the Soft Reset won't work.
+ */
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0)
+ writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
+
+ /* Issue Soft Reset */
+ writel(set_rmask(CSR_SOFT_RESET), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* Wait until the Network Reset Intr bit is cleared */
+ max_wait_time = RESET_INTR_TOV;
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if ((ctrl_status & CSR_NET_RESET_INTR) == 0)
+ break;
+
+ msleep(1000);
+ } while ((--max_wait_time));
+
+ if ((ctrl_status & CSR_NET_RESET_INTR) != 0) {
+ DEBUG2(printk(KERN_WARNING
+ "scsi%ld: Network Reset Intr not cleared by "
+ "Network function, clearing it now!\n",
+ ha->host_no));
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(set_rmask(CSR_NET_RESET_INTR), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ }
+
+ /* Wait until the firmware tells us the Soft Reset is done */
+ max_wait_time = SOFT_RESET_TOV;
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if ((ctrl_status & CSR_SOFT_RESET) == 0) {
+ status = QLA_SUCCESS;
+ break;
+ }
+
+ msleep(1000);
+ } while ((--max_wait_time));
+
+ /*
+ * Also, make sure that the SCSI Reset Interrupt bit has been cleared
+ * after the soft reset has taken place.
+ */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ if ((ctrl_status & CSR_SCSI_RESET_INTR) != 0) {
+ writel(set_rmask(CSR_SCSI_RESET_INTR), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ /* If soft reset fails then most probably the bios on other
+ * function is also enabled.
+ * Since the initialization is sequential the other fn
+ * wont be able to acknowledge the soft reset.
+ * Issue a force soft reset to workaround this scenario.
+ */
+ if (max_wait_time == 0) {
+ /* Issue Force Soft Reset */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(set_rmask(CSR_FORCE_SOFT_RESET), &ha->reg->ctrl_status);
+ readl(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ /* Wait until the firmware tells us the Soft Reset is done */
+ max_wait_time = SOFT_RESET_TOV;
+ do {
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ ctrl_status = readw(&ha->reg->ctrl_status);
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if ((ctrl_status & CSR_FORCE_SOFT_RESET) == 0) {
+ status = QLA_SUCCESS;
+ break;
+ }
+
+ msleep(1000);
+ } while ((--max_wait_time));
+ }
+
+ return status;
+}
+
+/**
+ * qla4xxx_topcat_reset - performs hard reset of TopCat Chip.
+ * @ha: Pointer to host adapter structure.
+ **/
+static int qla4xxx_topcat_reset(struct scsi_qla_host *ha)
+{
+ unsigned long flags;
+
+ ql4xxx_lock_nvram(ha);
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ writel(set_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
+ readl(isp_gp_out(ha));
+ mdelay(1);
+
+ writel(clr_rmask(GPOR_TOPCAT_RESET), isp_gp_out(ha));
+ readl(isp_gp_out(ha));
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+ mdelay(2523);
+
+ ql4xxx_unlock_nvram(ha);
+ return QLA_SUCCESS;
+}
+
+/**
+ * qla4xxx_flush_active_srbs - returns all outstanding i/o requests to O.S.
+ * @ha: Pointer to host adapter structure.
+ *
+ * This routine is called just prior to a HARD RESET to return all
+ * outstanding commands back to the Operating System.
+ * Caller should make sure that the following locks are released
+ * before this calling routine: Hardware lock, and io_request_lock.
+ **/
+static void qla4xxx_flush_active_srbs(struct scsi_qla_host *ha)
+{
+ struct srb *srb;
+ int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ for (i = 0; i < ha->host->can_queue; i++) {
+ srb = qla4xxx_del_from_active_array(ha, i);
+ if (srb != NULL) {
+ srb->cmd->result = DID_RESET << 16;
+ qla4xxx_srb_compl(ha, srb);
+ }
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
+/**
+ * qla4xxx_hard_reset - performs HBA Hard Reset
+ * @ha: Pointer to host adapter structure.
+ **/
+static int qla4xxx_hard_reset(struct scsi_qla_host *ha)
+{
+ /* The QLA4010 really doesn't have an equivalent to a hard reset */
+ qla4xxx_flush_active_srbs(ha);
+ if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
+ int status = QLA_ERROR;
+
+ if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
+ (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
+ (qla4010_soft_reset(ha) == QLA_SUCCESS))
+ status = QLA_SUCCESS;
+ return status;
+ } else
+ return qla4010_soft_reset(ha);
+}
+
+/**
+ * qla4xxx_recover_adapter - recovers adapter after a fatal error
+ * @ha: Pointer to host adapter structure.
+ * @renew_ddb_list: Indicates what to do with the adapter's ddb list
+ * after adapter recovery has completed.
+ * 0=preserve ddb list, 1=destroy and rebuild ddb list
+ **/
+static int qla4xxx_recover_adapter(struct scsi_qla_host *ha,
+ uint8_t renew_ddb_list)
+{
+ int status;
+
+ /* Stall incoming I/O until we are done */
+ clear_bit(AF_ONLINE, &ha->flags);
+ DEBUG2(printk("scsi%ld: %s calling qla4xxx_cmd_wait\n", ha->host_no,
+ __func__));
+
+ /* Wait for outstanding commands to complete.
+ * Stalls the driver for max 30 secs
+ */
+ status = qla4xxx_cmd_wait(ha);
+
+ qla4xxx_disable_intrs(ha);
+
+ /* Flush any pending ddb changed AENs */
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+
+ /* Reset the firmware. If successful, function
+ * returns with ISP interrupts enabled.
+ */
+ if (status == QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s - Performing soft reset..\n",
+ ha->host_no, __func__));
+ status = qla4xxx_soft_reset(ha);
+ }
+ /* FIXMEkaren: Do we want to keep interrupts enabled and process
+ AENs after soft reset */
+
+ /* If firmware (SOFT) reset failed, or if all outstanding
+ * commands have not returned, then do a HARD reset.
+ */
+ if (status == QLA_ERROR) {
+ DEBUG2(printk("scsi%ld: %s - Performing hard reset..\n",
+ ha->host_no, __func__));
+ status = qla4xxx_hard_reset(ha);
+ }
+
+ /* Flush any pending ddb changed AENs */
+ qla4xxx_process_aen(ha, FLUSH_DDB_CHANGED_AENS);
+
+ /* Re-initialize firmware. If successful, function returns
+ * with ISP interrupts enabled */
+ if (status == QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld: %s - Initializing adapter..\n",
+ ha->host_no, __func__));
+
+ /* If successful, AF_ONLINE flag set in
+ * qla4xxx_initialize_adapter */
+ status = qla4xxx_initialize_adapter(ha, renew_ddb_list);
+ }
+
+ /* Failed adapter initialization?
+ * Retry reset_ha only if invoked via DPC (DPC_RESET_HA) */
+ if ((test_bit(AF_ONLINE, &ha->flags) == 0) &&
+ (test_bit(DPC_RESET_HA, &ha->dpc_flags))) {
+ /* Adapter initialization failed, see if we can retry
+ * resetting the ha */
+ if (!test_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags)) {
+ ha->retry_reset_ha_cnt = MAX_RESET_HA_RETRIES;
+ DEBUG2(printk("scsi%ld: recover adapter - retrying "
+ "(%d) more times\n", ha->host_no,
+ ha->retry_reset_ha_cnt));
+ set_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ status = QLA_ERROR;
+ } else {
+ if (ha->retry_reset_ha_cnt > 0) {
+ /* Schedule another Reset HA--DPC will retry */
+ ha->retry_reset_ha_cnt--;
+ DEBUG2(printk("scsi%ld: recover adapter - "
+ "retry remaining %d\n",
+ ha->host_no,
+ ha->retry_reset_ha_cnt));
+ status = QLA_ERROR;
+ }
+
+ if (ha->retry_reset_ha_cnt == 0) {
+ /* Recover adapter retries have been exhausted.
+ * Adapter DEAD */
+ DEBUG2(printk("scsi%ld: recover adapter "
+ "failed - board disabled\n",
+ ha->host_no));
+ qla4xxx_flush_active_srbs(ha);
+ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST,
+ &ha->dpc_flags);
+ status = QLA_ERROR;
+ }
+ }
+ } else {
+ clear_bit(DPC_RESET_HA, &ha->dpc_flags);
+ clear_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags);
+ clear_bit(DPC_RETRY_RESET_HA, &ha->dpc_flags);
+ }
+
+ ha->adapter_error_count++;
+
+ if (status == QLA_SUCCESS)
+ qla4xxx_enable_intrs(ha);
+
+ DEBUG2(printk("scsi%ld: recover adapter .. DONE\n", ha->host_no));
+ return status;
+}
+
+/**
+ * qla4xxx_do_dpc - dpc routine
+ * @data: in our case pointer to adapter structure
+ *
+ * This routine is a task that is schedule by the interrupt handler
+ * to perform the background processing for interrupts. We put it
+ * on a task queue that is consumed whenever the scheduler runs; that's
+ * so you can do anything (i.e. put the process to sleep etc). In fact,
+ * the mid-level tries to sleep when it reaches the driver threshold
+ * "host->can_queue". This can cause a panic if we were in our interrupt code.
+ **/
+static void qla4xxx_do_dpc(void *data)
+{
+ struct scsi_qla_host *ha = (struct scsi_qla_host *) data;
+ struct ddb_entry *ddb_entry, *dtemp;
+
+ DEBUG2(printk("scsi%ld: %s: DPC handler waking up.\n",
+ ha->host_no, __func__));
+
+ DEBUG2(printk("scsi%ld: %s: ha->flags = 0x%08lx\n",
+ ha->host_no, __func__, ha->flags));
+ DEBUG2(printk("scsi%ld: %s: ha->dpc_flags = 0x%08lx\n",
+ ha->host_no, __func__, ha->dpc_flags));
+
+ /* Initialization not yet finished. Don't do anything yet. */
+ if (!test_bit(AF_INIT_DONE, &ha->flags))
+ return;
+
+ if (adapter_up(ha) ||
+ test_bit(DPC_RESET_HA, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_INTR, &ha->dpc_flags) ||
+ test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags)) {
+ if (test_bit(DPC_RESET_HA_DESTROY_DDB_LIST, &ha->dpc_flags))
+ /*
+ * dg 09/23 Never initialize ddb list
+ * once we up and running
+ * qla4xxx_recover_adapter(ha,
+ * REBUILD_DDB_LIST);
+ */
+ qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
+
+ if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
+ qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST);
+
+ if (test_and_clear_bit(DPC_RESET_HA_INTR, &ha->dpc_flags)) {
+ uint8_t wait_time = RESET_INTR_TOV;
+ unsigned long flags = 0;
+
+ qla4xxx_flush_active_srbs(ha);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ while ((readw(&ha->reg->ctrl_status) &
+ (CSR_SOFT_RESET | CSR_FORCE_SOFT_RESET)) != 0) {
+ if (--wait_time == 0)
+ break;
+
+ spin_unlock_irqrestore(&ha->hardware_lock,
+ flags);
+
+ msleep(1000);
+
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ }
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ if (wait_time == 0)
+ DEBUG2(printk("scsi%ld: %s: SR|FSR "
+ "bit not cleared-- resetting\n",
+ ha->host_no, __func__));
+ }
+ }
+
+ /* ---- process AEN? --- */
+ if (test_and_clear_bit(DPC_AEN, &ha->dpc_flags))
+ qla4xxx_process_aen(ha, PROCESS_ALL_AENS);
+
+ /* ---- Get DHCP IP Address? --- */
+ if (test_and_clear_bit(DPC_GET_DHCP_IP_ADDR, &ha->dpc_flags))
+ qla4xxx_get_dhcp_ip_address(ha);
+
+ /* ---- relogin device? --- */
+ if (adapter_up(ha) &&
+ test_and_clear_bit(DPC_RELOGIN_DEVICE, &ha->dpc_flags)) {
+ list_for_each_entry_safe(ddb_entry, dtemp,
+ &ha->ddb_list, list) {
+ if (test_and_clear_bit(DF_RELOGIN, &ddb_entry->flags) &&
+ atomic_read(&ddb_entry->state) != DDB_STATE_ONLINE)
+ qla4xxx_relogin_device(ha, ddb_entry);
+
+ /*
+ * If mbx cmd times out there is no point
+ * in continuing further.
+ * With large no of targets this can hang
+ * the system.
+ */
+ if (test_bit(DPC_RESET_HA, &ha->dpc_flags)) {
+ printk(KERN_WARNING "scsi%ld: %s: "
+ "need to reset hba\n",
+ ha->host_no, __func__);
+ break;
+ }
+ }
+ }
+}
+
+/**
+ * qla4xxx_free_adapter - release the adapter
+ * @ha: pointer to adapter structure
+ **/
+static void qla4xxx_free_adapter(struct scsi_qla_host *ha)
+{
+
+ if (test_bit(AF_INTERRUPTS_ON, &ha->flags)) {
+ /* Turn-off interrupts on the card. */
+ qla4xxx_disable_intrs(ha);
+ }
+
+ /* Kill the kernel thread for this host */
+ if (ha->dpc_thread)
+ destroy_workqueue(ha->dpc_thread);
+
+ /* Issue Soft Reset to put firmware in unknown state */
+ qla4xxx_soft_reset(ha);
+
+ /* Remove timer thread, if present */
+ if (ha->timer_active)
+ qla4xxx_stop_timer(ha);
+
+ /* free extra memory */
+ qla4xxx_mem_free(ha);
+
+ /* Detach interrupts */
+ if (test_and_clear_bit(AF_IRQ_ATTACHED, &ha->flags))
+ free_irq(ha->pdev->irq, ha);
+
+ pci_disable_device(ha->pdev);
+
+}
+
+/***
+ * qla4xxx_iospace_config - maps registers
+ * @ha: pointer to adapter structure
+ *
+ * This routines maps HBA's registers from the pci address space
+ * into the kernel virtual address space for memory mapped i/o.
+ **/
+static int qla4xxx_iospace_config(struct scsi_qla_host *ha)
+{
+ unsigned long pio, pio_len, pio_flags;
+ unsigned long mmio, mmio_len, mmio_flags;
+
+ pio = pci_resource_start(ha->pdev, 0);
+ pio_len = pci_resource_len(ha->pdev, 0);
+ pio_flags = pci_resource_flags(ha->pdev, 0);
+ if (pio_flags & IORESOURCE_IO) {
+ if (pio_len < MIN_IOBASE_LEN) {
+ dev_warn(&ha->pdev->dev,
+ "Invalid PCI I/O region size\n");
+ pio = 0;
+ }
+ } else {
+ dev_warn(&ha->pdev->dev, "region #0 not a PIO resource\n");
+ pio = 0;
+ }
+
+ /* Use MMIO operations for all accesses. */
+ mmio = pci_resource_start(ha->pdev, 1);
+ mmio_len = pci_resource_len(ha->pdev, 1);
+ mmio_flags = pci_resource_flags(ha->pdev, 1);
+
+ if (!(mmio_flags & IORESOURCE_MEM)) {
+ dev_err(&ha->pdev->dev,
+ "region #0 not an MMIO resource, aborting\n");
+
+ goto iospace_error_exit;
+ }
+ if (mmio_len < MIN_IOBASE_LEN) {
+ dev_err(&ha->pdev->dev,
+ "Invalid PCI mem region size, aborting\n");
+ goto iospace_error_exit;
+ }
+
+ if (pci_request_regions(ha->pdev, DRIVER_NAME)) {
+ dev_warn(&ha->pdev->dev,
+ "Failed to reserve PIO/MMIO regions\n");
+
+ goto iospace_error_exit;
+ }
+
+ ha->pio_address = pio;
+ ha->pio_length = pio_len;
+ ha->reg = ioremap(mmio, MIN_IOBASE_LEN);
+ if (!ha->reg) {
+ dev_err(&ha->pdev->dev,
+ "cannot remap MMIO, aborting\n");
+
+ goto iospace_error_exit;
+ }
+
+ return 0;
+
+iospace_error_exit:
+ return -ENOMEM;
+}
+
+/**
+ * qla4xxx_probe_adapter - callback function to probe HBA
+ * @pdev: pointer to pci_dev structure
+ * @pci_device_id: pointer to pci_device entry
+ *
+ * This routine will probe for Qlogic 4xxx iSCSI host adapters.
+ * It returns zero if successful. It also initializes all data necessary for
+ * the driver.
+ **/
+static int __devinit qla4xxx_probe_adapter(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ int ret = -ENODEV, status;
+ struct Scsi_Host *host;
+ struct scsi_qla_host *ha;
+ struct ddb_entry *ddb_entry, *ddbtemp;
+ uint8_t init_retry_count = 0;
+ char buf[34];
+
+ if (pci_enable_device(pdev))
+ return -1;
+
+ host = scsi_host_alloc(&qla4xxx_driver_template, sizeof(*ha));
+ if (host == NULL) {
+ printk(KERN_WARNING
+ "qla4xxx: Couldn't allocate host from scsi layer!\n");
+ goto probe_disable_device;
+ }
+
+ /* Clear our data area */
+ ha = (struct scsi_qla_host *) host->hostdata;
+ memset(ha, 0, sizeof(*ha));
+
+ /* Save the information from PCI BIOS. */
+ ha->pdev = pdev;
+ ha->host = host;
+ ha->host_no = host->host_no;
+
+ /* Configure PCI I/O space. */
+ ret = qla4xxx_iospace_config(ha);
+ if (ret)
+ goto probe_failed;
+
+ dev_info(&ha->pdev->dev, "Found an ISP%04x, irq %d, iobase 0x%p\n",
+ pdev->device, pdev->irq, ha->reg);
+
+ qla4xxx_config_dma_addressing(ha);
+
+ /* Initialize lists and spinlocks. */
+ INIT_LIST_HEAD(&ha->ddb_list);
+ INIT_LIST_HEAD(&ha->free_srb_q);
+
+ mutex_init(&ha->mbox_sem);
+ init_waitqueue_head(&ha->mailbox_wait_queue);
+
+ spin_lock_init(&ha->hardware_lock);
+ spin_lock_init(&ha->list_lock);
+
+ /* Allocate dma buffers */
+ if (qla4xxx_mem_alloc(ha)) {
+ dev_warn(&ha->pdev->dev,
+ "[ERROR] Failed to allocate memory for adapter\n");
+
+ ret = -ENOMEM;
+ goto probe_failed;
+ }
+
+ /*
+ * Initialize the Host adapter request/response queues and
+ * firmware
+ * NOTE: interrupts enabled upon successful completion
+ */
+ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
+ while (status == QLA_ERROR && init_retry_count++ < MAX_INIT_RETRIES) {
+ DEBUG2(printk("scsi: %s: retrying adapter initialization "
+ "(%d)\n", __func__, init_retry_count));
+ qla4xxx_soft_reset(ha);
+ status = qla4xxx_initialize_adapter(ha, REBUILD_DDB_LIST);
+ }
+ if (status == QLA_ERROR) {
+ dev_warn(&ha->pdev->dev, "Failed to initialize adapter\n");
+
+ ret = -ENODEV;
+ goto probe_failed;
+ }
+
+ host->cmd_per_lun = 3;
+ host->max_channel = 0;
+ host->max_lun = MAX_LUNS - 1;
+ host->max_id = MAX_TARGETS;
+ host->max_cmd_len = IOCB_MAX_CDB_LEN;
+ host->can_queue = MAX_SRBS ;
+ host->transportt = qla4xxx_scsi_transport;
+
+ ret = scsi_init_shared_tag_map(host, MAX_SRBS);
+ if (ret) {
+ dev_warn(&ha->pdev->dev, "scsi_init_shared_tag_map failed");
+ goto probe_failed;
+ }
+
+ /* Startup the kernel thread for this host adapter. */
+ DEBUG2(printk("scsi: %s: Starting kernel thread for "
+ "qla4xxx_dpc\n", __func__));
+ sprintf(buf, "qla4xxx_%lu_dpc", ha->host_no);
+ ha->dpc_thread = create_singlethread_workqueue(buf);
+ if (!ha->dpc_thread) {
+ dev_warn(&ha->pdev->dev, "Unable to start DPC thread!\n");
+ ret = -ENODEV;
+ goto probe_failed;
+ }
+ INIT_WORK(&ha->dpc_work, qla4xxx_do_dpc, ha);
+
+ ret = request_irq(pdev->irq, qla4xxx_intr_handler,
+ SA_INTERRUPT|SA_SHIRQ, "qla4xxx", ha);
+ if (ret) {
+ dev_warn(&ha->pdev->dev, "Failed to reserve interrupt %d"
+ " already in use.\n", pdev->irq);
+ goto probe_failed;
+ }
+ set_bit(AF_IRQ_ATTACHED, &ha->flags);
+ host->irq = pdev->irq;
+ DEBUG(printk("scsi%d: irq %d attached\n", ha->host_no, ha->pdev->irq));
+
+ qla4xxx_enable_intrs(ha);
+
+ /* Start timer thread. */
+ qla4xxx_start_timer(ha, qla4xxx_timer, 1);
+
+ set_bit(AF_INIT_DONE, &ha->flags);
+
+ pci_set_drvdata(pdev, ha);
+
+ ret = scsi_add_host(host, &pdev->dev);
+ if (ret)
+ goto probe_failed;
+
+ /* Update transport device information for all devices. */
+ list_for_each_entry_safe(ddb_entry, ddbtemp, &ha->ddb_list, list) {
+ if (ddb_entry->fw_ddb_device_state == DDB_DS_SESSION_ACTIVE)
+ if (qla4xxx_add_sess(ddb_entry))
+ goto remove_host;
+ }
+
+ printk(KERN_INFO
+ " QLogic iSCSI HBA Driver version: %s\n"
+ " QLogic ISP%04x @ %s, host#=%ld, fw=%02d.%02d.%02d.%02d\n",
+ qla4xxx_version_str, ha->pdev->device, pci_name(ha->pdev),
+ ha->host_no, ha->firmware_version[0], ha->firmware_version[1],
+ ha->patch_number, ha->build_number);
+
+ return 0;
+
+remove_host:
+ qla4xxx_free_ddb_list(ha);
+ scsi_remove_host(host);
+
+probe_failed:
+ qla4xxx_free_adapter(ha);
+ scsi_host_put(ha->host);
+
+probe_disable_device:
+ pci_disable_device(pdev);
+
+ return ret;
+}
+
+/**
+ * qla4xxx_remove_adapter - calback function to remove adapter.
+ * @pci_dev: PCI device pointer
+ **/
+static void __devexit qla4xxx_remove_adapter(struct pci_dev *pdev)
+{
+ struct scsi_qla_host *ha;
+
+ ha = pci_get_drvdata(pdev);
+
+ /* remove devs from iscsi_sessions to scsi_devices */
+ qla4xxx_free_ddb_list(ha);
+
+ scsi_remove_host(ha->host);
+
+ qla4xxx_free_adapter(ha);
+
+ scsi_host_put(ha->host);
+
+ pci_set_drvdata(pdev, NULL);
+}
+
+/**
+ * qla4xxx_config_dma_addressing() - Configure OS DMA addressing method.
+ * @ha: HA context
+ *
+ * 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)
+{
+ int retval;
+
+ /* Update our PCI device dma_mask for full 64 bit mask */
+ if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) {
+ if (pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
+ dev_dbg(&ha->pdev->dev,
+ "Failed to set 64 bit PCI consistent mask; "
+ "using 32 bit.\n");
+ retval = pci_set_consistent_dma_mask(ha->pdev,
+ DMA_32BIT_MASK);
+ }
+ } else
+ retval = pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
+}
+
+static int qla4xxx_slave_alloc(struct scsi_device *sdev)
+{
+ struct iscsi_cls_session *sess = starget_to_session(sdev->sdev_target);
+ struct ddb_entry *ddb = sess->dd_data;
+
+ sdev->hostdata = ddb;
+ sdev->tagged_supported = 1;
+ scsi_activate_tcq(sdev, sdev->host->can_queue);
+ return 0;
+}
+
+static int qla4xxx_slave_configure(struct scsi_device *sdev)
+{
+ sdev->tagged_supported = 1;
+ return 0;
+}
+
+static void qla4xxx_slave_destroy(struct scsi_device *sdev)
+{
+ scsi_deactivate_tcq(sdev, 1);
+}
+
+/**
+ * qla4xxx_del_from_active_array - returns an active srb
+ * @ha: Pointer to host adapter structure.
+ * @index: index into to the active_array
+ *
+ * This routine removes and returns the srb at the specified index
+ **/
+struct srb * qla4xxx_del_from_active_array(struct scsi_qla_host *ha, uint32_t index)
+{
+ struct srb *srb = NULL;
+ struct scsi_cmnd *cmd;
+
+ if (!(cmd = scsi_host_find_tag(ha->host, index)))
+ return srb;
+
+ if (!(srb = (struct srb *)cmd->host_scribble))
+ return srb;
+
+ /* update counters */
+ if (srb->flags & SRB_DMA_VALID) {
+ ha->req_q_count += srb->iocb_cnt;
+ ha->iocb_cnt -= srb->iocb_cnt;
+ if (srb->cmd)
+ srb->cmd->host_scribble = NULL;
+ }
+ return srb;
+}
+
+/**
+ * qla4xxx_soft_reset - performs a SOFT RESET of hba.
+ * @ha: Pointer to host adapter structure.
+ **/
+int qla4xxx_soft_reset(struct scsi_qla_host *ha)
+{
+
+ DEBUG2(printk(KERN_WARNING "scsi%ld: %s: chip reset!\n", ha->host_no,
+ __func__));
+ if (test_bit(AF_TOPCAT_CHIP_PRESENT, &ha->flags)) {
+ int status = QLA_ERROR;
+
+ if ((qla4010_soft_reset(ha) == QLA_SUCCESS) &&
+ (qla4xxx_topcat_reset(ha) == QLA_SUCCESS) &&
+ (qla4010_soft_reset(ha) == QLA_SUCCESS) )
+ status = QLA_SUCCESS;
+ return status;
+ } else
+ return qla4010_soft_reset(ha);
+}
+
+/**
+ * qla4xxx_eh_wait_on_command - waits for command to be returned by firmware
+ * @ha: actual ha whose done queue will contain the comd returned by firmware.
+ * @cmd: Scsi Command to wait on.
+ *
+ * This routine waits for the command to be returned by the Firmware
+ * for some max time.
+ **/
+static int qla4xxx_eh_wait_on_command(struct scsi_qla_host *ha,
+ struct scsi_cmnd *cmd)
+{
+ int done = 0;
+ struct srb *rp;
+ uint32_t max_wait_time = EH_WAIT_CMD_TOV;
+
+ do {
+ /* Checking to see if its returned to OS */
+ rp = (struct srb *) cmd->SCp.ptr;
+ if (rp == NULL) {
+ done++;
+ break;
+ }
+
+ msleep(2000);
+ } while (max_wait_time--);
+
+ return done;
+}
+
+/**
+ * qla4xxx_wait_for_hba_online - waits for HBA to come online
+ * @ha: Pointer to host adapter structure
+ **/
+static int qla4xxx_wait_for_hba_online(struct scsi_qla_host *ha)
+{
+ unsigned long wait_online;
+
+ wait_online = jiffies + (30 * HZ);
+ while (time_before(jiffies, wait_online)) {
+
+ if (adapter_up(ha))
+ return QLA_SUCCESS;
+ else if (ha->retry_reset_ha_cnt == 0)
+ return QLA_ERROR;
+
+ msleep(2000);
+ }
+
+ return QLA_ERROR;
+}
+
+/**
+ * qla4xxx_eh_wait_for_active_target_commands - wait for active cmds to finish.
+ * @ha: pointer to to HBA
+ * @t: target id
+ * @l: lun id
+ *
+ * This function waits for all outstanding commands to a lun to complete. It
+ * returns 0 if all pending commands are returned and 1 otherwise.
+ **/
+static int qla4xxx_eh_wait_for_active_target_commands(struct scsi_qla_host *ha,
+ int t, int l)
+{
+ int cnt;
+ int status = 0;
+ struct scsi_cmnd *cmd;
+
+ /*
+ * Waiting for all commands for the designated target in the active
+ * array
+ */
+ for (cnt = 0; cnt < ha->host->can_queue; cnt++) {
+ cmd = scsi_host_find_tag(ha->host, cnt);
+ if (cmd && cmd->device->id == t && cmd->device->lun == l) {
+ if (!qla4xxx_eh_wait_on_command(ha, cmd)) {
+ status++;
+ break;
+ }
+ }
+ }
+ return status;
+}
+
+/**
+ * qla4xxx_eh_device_reset - callback for target reset.
+ * @cmd: Pointer to Linux's SCSI command structure
+ *
+ * This routine is called by the Linux OS to reset all luns on the
+ * specified target.
+ **/
+static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd)
+{
+ struct scsi_qla_host *ha = to_qla_host(cmd->device->host);
+ struct ddb_entry *ddb_entry = cmd->device->hostdata;
+ struct srb *sp;
+ int ret = FAILED, stat;
+
+ sp = (struct srb *) cmd->SCp.ptr;
+ if (!sp || !ddb_entry)
+ return ret;
+
+ dev_info(&ha->pdev->dev,
+ "scsi%ld:%d:%d:%d: DEVICE RESET ISSUED.\n", ha->host_no,
+ cmd->device->channel, cmd->device->id, cmd->device->lun);
+
+ DEBUG2(printk(KERN_INFO
+ "scsi%ld: DEVICE_RESET cmd=%p jiffies = 0x%lx, to=%x,"
+ "dpc_flags=%lx, status=%x allowed=%d\n", ha->host_no,
+ cmd, jiffies, cmd->timeout_per_command / HZ,
+ ha->dpc_flags, cmd->result, cmd->allowed));
+
+ /* FIXME: wait for hba to go online */
+ stat = qla4xxx_reset_lun(ha, ddb_entry, cmd->device->lun);
+ if (stat != QLA_SUCCESS) {
+ dev_info(&ha->pdev->dev, "DEVICE RESET FAILED. %d\n", stat);
+ goto eh_dev_reset_done;
+ }
+
+ /* Send marker. */
+ ha->marker_needed = 1;
+
+ /*
+ * If we are coming down the EH path, wait for all commands to complete
+ * for the device.
+ */
+ if (cmd->device->host->shost_state == SHOST_RECOVERY) {
+ if (qla4xxx_eh_wait_for_active_target_commands(ha,
+ cmd->device->id,
+ cmd->device->lun)){
+ dev_info(&ha->pdev->dev,
+ "DEVICE RESET FAILED - waiting for "
+ "commands.\n");
+ goto eh_dev_reset_done;
+ }
+ }
+
+ dev_info(&ha->pdev->dev,
+ "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
+ ha->host_no, cmd->device->channel, cmd->device->id,
+ cmd->device->lun);
+
+ ret = SUCCESS;
+
+eh_dev_reset_done:
+
+ return ret;
+}
+
+/**
+ * qla4xxx_eh_host_reset - kernel callback
+ * @cmd: Pointer to Linux's SCSI command structure
+ *
+ * This routine is invoked by the Linux kernel to perform fatal error
+ * recovery on the specified adapter.
+ **/
+static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd)
+{
+ int return_status = FAILED;
+ struct scsi_qla_host *ha;
+
+ ha = (struct scsi_qla_host *) cmd->device->host->hostdata;
+
+ dev_info(&ha->pdev->dev,
+ "scsi(%ld:%d:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no,
+ cmd->device->channel, cmd->device->id, cmd->device->lun);
+
+ if (qla4xxx_wait_for_hba_online(ha) != QLA_SUCCESS) {
+ DEBUG2(printk("scsi%ld:%d: %s: Unable to reset host. Adapter "
+ "DEAD.\n", ha->host_no, cmd->device->channel,
+ __func__));
+
+ return FAILED;
+ }
+
+ if (qla4xxx_recover_adapter(ha, PRESERVE_DDB_LIST) == QLA_SUCCESS) {
+ return_status = SUCCESS;
+ }
+
+ dev_info(&ha->pdev->dev, "HOST RESET %s.\n",
+ return_status == FAILED ? "FAILED" : "SUCCEDED");
+
+ return return_status;
+}
+
+
+static struct pci_device_id qla4xxx_pci_tbl[] = {
+ {
+ .vendor = PCI_VENDOR_ID_QLOGIC,
+ .device = PCI_DEVICE_ID_QLOGIC_ISP4010,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {
+ .vendor = PCI_VENDOR_ID_QLOGIC,
+ .device = PCI_DEVICE_ID_QLOGIC_ISP4022,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
+ {0, 0},
+};
+MODULE_DEVICE_TABLE(pci, qla4xxx_pci_tbl);
+
+struct pci_driver qla4xxx_pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = qla4xxx_pci_tbl,
+ .probe = qla4xxx_probe_adapter,
+ .remove = qla4xxx_remove_adapter,
+};
+
+static int __init qla4xxx_module_init(void)
+{
+ int ret;
+
+ /* Allocate cache for SRBs. */
+ srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
+ SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (srb_cachep == NULL) {
+ printk(KERN_ERR
+ "%s: Unable to allocate SRB cache..."
+ "Failing load!\n", DRIVER_NAME);
+ ret = -ENOMEM;
+ goto no_srp_cache;
+ }
+
+ /* Derive version string. */
+ strcpy(qla4xxx_version_str, QLA4XXX_DRIVER_VERSION);
+ if (qla4_extended_error_logging)
+ strcat(qla4xxx_version_str, "-debug");
+
+ qla4xxx_scsi_transport =
+ iscsi_register_transport(&qla4xxx_iscsi_transport);
+ if (!qla4xxx_scsi_transport){
+ ret = -ENODEV;
+ goto release_srb_cache;
+ }
+
+ printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
+ ret = pci_register_driver(&qla4xxx_pci_driver);
+ if (ret)
+ goto unregister_transport;
+
+ printk(KERN_INFO "QLogic iSCSI HBA Driver\n");
+ return 0;
+unregister_transport:
+ iscsi_unregister_transport(&qla4xxx_iscsi_transport);
+release_srb_cache:
+ kmem_cache_destroy(srb_cachep);
+no_srp_cache:
+ return ret;
+}
+
+static void __exit qla4xxx_module_exit(void)
+{
+ pci_unregister_driver(&qla4xxx_pci_driver);
+ iscsi_unregister_transport(&qla4xxx_iscsi_transport);
+ kmem_cache_destroy(srb_cachep);
+}
+
+module_init(qla4xxx_module_init);
+module_exit(qla4xxx_module_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic iSCSI HBA Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA4XXX_DRIVER_VERSION);
diff --git a/drivers/scsi/qla4xxx/ql4_version.h b/drivers/scsi/qla4xxx/ql4_version.h
new file mode 100644
index 000000000000..b3fe7e68988e
--- /dev/null
+++ b/drivers/scsi/qla4xxx/ql4_version.h
@@ -0,0 +1,13 @@
+/*
+ * QLogic iSCSI HBA Driver
+ * Copyright (c) 2003-2006 QLogic Corporation
+ *
+ * See LICENSE.qla4xxx for copyright and licensing details.
+ */
+
+#define QLA4XXX_DRIVER_VERSION "5.00.05b9-k"
+
+#define QL4_DRIVER_MAJOR_VER 5
+#define QL4_DRIVER_MINOR_VER 0
+#define QL4_DRIVER_PATCH_VER 5
+#define QL4_DRIVER_BETA_VER 9
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
index 52fb2ec3da70..e0725353c99c 100644
--- a/drivers/scsi/qlogicfas408.c
+++ b/drivers/scsi/qlogicfas408.c
@@ -405,10 +405,10 @@ static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
* Interrupt handler
*/
-static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
+static void ql_ihandl(void *dev_id)
{
Scsi_Cmnd *icmd;
- struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+ struct Scsi_Host *host = dev_id;
struct qlogicfas408_priv *priv = get_priv_by_host(host);
int qbase = priv->qbase;
REG0;
@@ -432,13 +432,13 @@ static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
(icmd->scsi_done) (icmd);
}
-irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *host = dev_id;
spin_lock_irqsave(host->host_lock, flags);
- ql_ihandl(irq, dev_id, regs);
+ ql_ihandl(dev_id);
spin_unlock_irqrestore(host->host_lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h
index 4b3df2003660..8fd5555c75b1 100644
--- a/drivers/scsi/qlogicfas408.h
+++ b/drivers/scsi/qlogicfas408.h
@@ -102,7 +102,7 @@ struct qlogicfas408_priv {
#define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0])
#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0])
-irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id);
int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
int qlogicfas408_biosparam(struct scsi_device * disk,
struct block_device *dev,
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
index 5b2f0741a55b..9b827ceec501 100644
--- a/drivers/scsi/qlogicpti.c
+++ b/drivers/scsi/qlogicpti.c
@@ -461,7 +461,7 @@ static int qlogicpti_reset_hardware(struct Scsi_Host *host)
#define PTI_RESET_LIMIT 400
-static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
+static int __devinit qlogicpti_load_firmware(struct qlogicpti *qpti)
{
struct Scsi_Host *host = qpti->qhost;
unsigned short csum = 0;
@@ -649,7 +649,7 @@ static int qlogicpti_verify_tmon(struct qlogicpti *qpti)
return 0;
}
-static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t qpti_intr(int irq, void *dev_id);
static void __init qpti_chain_add(struct qlogicpti *qpti)
{
@@ -1297,7 +1297,7 @@ static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
return done_queue;
}
-static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t qpti_intr(int irq, void *dev_id)
{
struct qlogicpti *qpti = dev_id;
unsigned long flags;
diff --git a/drivers/scsi/qlogicpti_asm.c b/drivers/scsi/qlogicpti_asm.c
index 1545b30681b4..19aa84f46018 100644
--- a/drivers/scsi/qlogicpti_asm.c
+++ b/drivers/scsi/qlogicpti_asm.c
@@ -1,5 +1,5 @@
/* Version 1.31.00 ISP1000 Initiator RISC firmware */
-unsigned short sbus_risc_code01[] __initdata = {
+unsigned short sbus_risc_code01[] __devinitdata = {
0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50,
0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932,
0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749,
@@ -1157,4 +1157,4 @@ unsigned short sbus_risc_code01[] __initdata = {
0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c,
0x92a7
};
-unsigned short sbus_risc_code_length01 = 0x2419;
+unsigned short __devinitdata sbus_risc_code_length01 = 0x2419;
diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c
index 327b33a57b0a..86e13183c9ba 100644
--- a/drivers/scsi/raid_class.c
+++ b/drivers/scsi/raid_class.c
@@ -215,18 +215,19 @@ static void raid_component_release(struct class_device *cdev)
kfree(rc);
}
-void raid_component_add(struct raid_template *r,struct device *raid_dev,
- struct device *component_dev)
+int raid_component_add(struct raid_template *r,struct device *raid_dev,
+ struct device *component_dev)
{
struct class_device *cdev =
attribute_container_find_class_device(&r->raid_attrs.ac,
raid_dev);
struct raid_component *rc;
struct raid_data *rd = class_get_devdata(cdev);
+ int err;
rc = kzalloc(sizeof(*rc), GFP_KERNEL);
if (!rc)
- return;
+ return -ENOMEM;
INIT_LIST_HEAD(&rc->node);
class_device_initialize(&rc->cdev);
@@ -239,7 +240,18 @@ void raid_component_add(struct raid_template *r,struct device *raid_dev,
list_add_tail(&rc->node, &rd->component_list);
rc->cdev.parent = cdev;
rc->cdev.class = &raid_class.class;
- class_device_add(&rc->cdev);
+ err = class_device_add(&rc->cdev);
+ if (err)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ list_del(&rc->node);
+ rd->component_count--;
+ put_device(component_dev);
+ kfree(rc);
+ return err;
}
EXPORT_SYMBOL(raid_component_add);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 7a054f9d1ee3..c59f31533ab4 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -128,7 +128,7 @@ const char * scsi_device_type(unsigned type)
return "Well-known LUN ";
if (type == 0x1f)
return "No Device ";
- if (type > ARRAY_SIZE(scsi_device_types))
+ if (type >= ARRAY_SIZE(scsi_device_types))
return "Unknown ";
return scsi_device_types[type];
}
@@ -592,12 +592,6 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
return rtn;
}
-
-/*
- * Per-CPU I/O completion queue.
- */
-static DEFINE_PER_CPU(struct list_head, scsi_done_q);
-
/**
* scsi_req_abort_cmd -- Request command recovery for the specified command
* cmd: pointer to the SCSI command of interest
@@ -1065,7 +1059,7 @@ int scsi_device_cancel(struct scsi_device *sdev, int recovery)
spin_lock_irqsave(&sdev->list_lock, flags);
list_for_each_entry(scmd, &sdev->cmd_list, list) {
- if (scmd->request && scmd->request->rq_status != RQ_INACTIVE) {
+ if (scmd->request) {
/*
* If we are unable to remove the timer, it means
* that the command has already timed out or
@@ -1102,7 +1096,7 @@ MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels");
static int __init init_scsi(void)
{
- int error, i;
+ int error;
error = scsi_init_queue();
if (error)
@@ -1123,9 +1117,6 @@ static int __init init_scsi(void)
if (error)
goto cleanup_sysctl;
- for_each_possible_cpu(i)
- INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
-
scsi_netlink_init();
printk(KERN_NOTICE "SCSI subsystem initialized\n");
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
index 3d0429bc14ab..ce63044b1ec8 100644
--- a/drivers/scsi/scsi_devinfo.c
+++ b/drivers/scsi/scsi_devinfo.c
@@ -150,6 +150,7 @@ static struct {
{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
{"DGC", "RAID", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, storage on LUN 0 */
{"DGC", "DISK", NULL, BLIST_SPARSELUN}, /* Dell PV 650F, no storage on LUN 0 */
+ {"EMC", "Invista", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
{"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN},
{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
@@ -161,6 +162,11 @@ static struct {
{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
{"HITACHI", "DISK-SUBSYSTEM", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
{"HITACHI", "OPEN-E", "*", BLIST_ATTACH_PQ3 | BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HITACHI", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP VA7400 */
{"HP", "OPEN-", "*", BLIST_REPORTLUN2}, /* HP XP Arrays */
{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
@@ -168,6 +174,14 @@ static struct {
{"HP", "C1557A", NULL, BLIST_FORCELUN},
{"HP", "C3323-300", "4269", BLIST_NOTQ},
{"HP", "C5713A", NULL, BLIST_NOREPORTLUN},
+ {"HP", "DF400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "DF500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "DF600", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "OP-C-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "3380-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "3390-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "6586-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+ {"HP", "6588-", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
@@ -188,6 +202,7 @@ static struct {
{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+ {"NEC", "iStorage", NULL, BLIST_REPORTLUN2},
{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
@@ -210,6 +225,7 @@ static struct {
{"SUN", "T300", "*", BLIST_SPARSELUN},
{"SUN", "T4", "*", BLIST_SPARSELUN},
{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+ {"Tornado-", "F4", "*", BLIST_NOREPORTLUN},
{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
{"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36},
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 3d355d054612..aff1b0cfd4b2 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -495,7 +495,7 @@ static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, unsigned char *cmnd,
memcpy(scmd->cmnd, cmnd, cmnd_size);
if (copy_sense) {
- int gfp_mask = GFP_ATOMIC;
+ gfp_t gfp_mask = GFP_ATOMIC;
if (shost->hostt->unchecked_isa_dma)
gfp_mask |= __GFP_DMA;
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index d6743b959a72..743f67ed7640 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -82,7 +82,7 @@ static void scsi_unprep_request(struct request *req)
{
struct scsi_cmnd *cmd = req->special;
- req->flags &= ~REQ_DONTPREP;
+ req->cmd_flags &= ~REQ_DONTPREP;
req->special = NULL;
scsi_put_command(cmd);
@@ -196,7 +196,8 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
req->sense_len = 0;
req->retries = retries;
req->timeout = timeout;
- req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL | REQ_QUIET;
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= flags | REQ_QUIET | REQ_PREEMPT;
/*
* head injection *required* here otherwise quiesce won't work
@@ -397,7 +398,8 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
req = blk_get_request(sdev->request_queue, write, gfp);
if (!req)
goto free_sense;
- req->flags |= REQ_BLOCK_PC | REQ_QUIET;
+ req->cmd_type = REQ_TYPE_BLOCK_PC;
+ req->cmd_flags |= REQ_QUIET;
if (use_sg)
err = scsi_req_map_sg(req, buffer, use_sg, bufflen, gfp);
@@ -424,7 +426,7 @@ int scsi_execute_async(struct scsi_device *sdev, const unsigned char *cmd,
free_req:
blk_put_request(req);
free_sense:
- kfree(sioc);
+ kmem_cache_free(scsi_io_context_cache, sioc);
return DRIVER_ERROR << 24;
}
EXPORT_SYMBOL_GPL(scsi_execute_async);
@@ -933,7 +935,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
break;
}
}
- if (!(req->flags & REQ_QUIET)) {
+ if (!(req->cmd_flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
"Device not ready: ");
scsi_print_sense_hdr("", &sshdr);
@@ -941,7 +943,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
scsi_end_request(cmd, 0, this_count, 1);
return;
case VOLUME_OVERFLOW:
- if (!(req->flags & REQ_QUIET)) {
+ if (!(req->cmd_flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
"Volume overflow, CDB: ");
__scsi_print_command(cmd->cmnd);
@@ -963,7 +965,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
return;
}
if (result) {
- if (!(req->flags & REQ_QUIET)) {
+ if (!(req->cmd_flags & REQ_QUIET)) {
scmd_printk(KERN_INFO, cmd,
"SCSI error: return code = 0x%08x\n",
result);
@@ -995,7 +997,7 @@ static int scsi_init_io(struct scsi_cmnd *cmd)
/*
* if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
*/
- if ((req->flags & REQ_BLOCK_PC) && !req->bio) {
+ if (blk_pc_request(req) && !req->bio) {
cmd->request_bufflen = req->data_len;
cmd->request_buffer = req->data;
req->buffer = req->data;
@@ -1139,13 +1141,12 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
* these two cases differently. We differentiate by looking
* at request->cmd, as this tells us the real story.
*/
- if (req->flags & REQ_SPECIAL && req->special) {
+ if (blk_special_request(req) && req->special)
cmd = req->special;
- } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-
- if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) {
- if(specials_only == SDEV_QUIESCE ||
- specials_only == SDEV_BLOCK)
+ else if (blk_pc_request(req) || blk_fs_request(req)) {
+ if (unlikely(specials_only) && !(req->cmd_flags & REQ_PREEMPT)){
+ if (specials_only == SDEV_QUIESCE ||
+ specials_only == SDEV_BLOCK)
goto defer;
sdev_printk(KERN_ERR, sdev,
@@ -1153,7 +1154,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
goto kill;
}
-
/*
* Now try and find a command block that we can use.
*/
@@ -1184,7 +1184,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
* lock. We hope REQ_STARTED prevents anything untoward from
* happening now.
*/
- if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+ if (blk_fs_request(req) || blk_pc_request(req)) {
int ret;
/*
@@ -1216,7 +1216,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
/*
* Initialize the actual SCSI command for this request.
*/
- if (req->flags & REQ_BLOCK_PC) {
+ if (blk_pc_request(req)) {
scsi_setup_blk_pc_cmnd(cmd);
} else if (req->rq_disk) {
struct scsi_driver *drv;
@@ -1233,7 +1233,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req)
/*
* The request is now prepped, no need to come back here
*/
- req->flags |= REQ_DONTPREP;
+ req->cmd_flags |= REQ_DONTPREP;
return BLKPREP_OK;
defer:
@@ -1454,8 +1454,9 @@ static void scsi_request_fn(struct request_queue *q)
if (unlikely(cmd == NULL)) {
printk(KERN_CRIT "impossible request in %s.\n"
"please mail a stack trace to "
- "linux-scsi@vger.kernel.org",
+ "linux-scsi@vger.kernel.org\n",
__FUNCTION__);
+ blk_dump_rq_flags(req, "foo");
BUG();
}
spin_lock(shost->host_lock);
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 638cff41d436..84ff203ffedd 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -443,8 +443,7 @@ static int sd_init_command(struct scsi_cmnd * SCpnt)
SCpnt->cmnd[0] = READ_6;
SCpnt->sc_data_direction = DMA_FROM_DEVICE;
} else {
- printk(KERN_ERR "sd: Unknown command %lx\n", rq->flags);
-/* overkill panic("Unknown sd command %lx\n", rq->flags); */
+ printk(KERN_ERR "sd: Unknown command %x\n", rq->cmd_flags);
return 0;
}
@@ -840,7 +839,7 @@ static int sd_issue_flush(struct device *dev, sector_t *error_sector)
static void sd_prepare_flush(request_queue_t *q, struct request *rq)
{
memset(rq->cmd, 0, sizeof(rq->cmd));
- rq->flags |= REQ_BLOCK_PC;
+ rq->cmd_type = REQ_TYPE_BLOCK_PC;
rq->timeout = SD_TIMEOUT;
rq->cmd[0] = SYNCHRONIZE_CACHE;
rq->cmd_len = 10;
@@ -1795,7 +1794,7 @@ static void sd_shutdown(struct device *dev)
**/
static int __init init_sd(void)
{
- int majors = 0, i;
+ int majors = 0, i, err;
SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
@@ -1806,9 +1805,22 @@ static int __init init_sd(void)
if (!majors)
return -ENODEV;
- class_register(&sd_disk_class);
+ err = class_register(&sd_disk_class);
+ if (err)
+ goto err_out;
- return scsi_register_driver(&sd_template.gendrv);
+ err = scsi_register_driver(&sd_template.gendrv);
+ if (err)
+ goto err_out_class;
+
+ return 0;
+
+err_out_class:
+ class_unregister(&sd_disk_class);
+err_out:
+ for (i = 0; i < SD_MAJORS; i++)
+ unregister_blkdev(sd_major(i), "sd");
+ return err;
}
/**
@@ -1823,10 +1835,10 @@ static void __exit exit_sd(void)
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
scsi_unregister_driver(&sd_template.gendrv);
+ class_unregister(&sd_disk_class);
+
for (i = 0; i < SD_MAJORS; i++)
unregister_blkdev(sd_major(i), "sd");
-
- class_unregister(&sd_disk_class);
}
module_init(init_sd);
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
index 2679ea8bff1a..5ffec2721b28 100644
--- a/drivers/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -94,21 +94,21 @@
#include <linux/string.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
-#include <linux/delay.h>
#include <linux/blkdev.h>
#include <linux/stat.h>
#include <linux/delay.h>
+#include <linux/io.h>
-#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
-#include "scsi.h"
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_host.h>
-#include "seagate.h"
-#include <scsi/scsi_ioctl.h>
#ifdef DEBUG
#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
@@ -320,8 +320,9 @@ static Signature __initdata signatures[] = {
*/
static int hostno = -1;
-static void seagate_reconnect_intr (int, void *, struct pt_regs *);
-static irqreturn_t do_seagate_reconnect_intr (int, void *, struct pt_regs *);
+static void seagate_reconnect_intr (int, void *);
+static irqreturn_t do_seagate_reconnect_intr (int, void *);
+static int seagate_st0x_bus_reset(struct scsi_cmnd *);
#ifdef FAST
static int fast = 1;
@@ -585,8 +586,8 @@ static int linked_connected = 0;
static unsigned char linked_target, linked_lun;
#endif
-static void (*done_fn) (Scsi_Cmnd *) = NULL;
-static Scsi_Cmnd *SCint = NULL;
+static void (*done_fn) (struct scsi_cmnd *) = NULL;
+static struct scsi_cmnd *SCint = NULL;
/*
* These control whether or not disconnect / reconnect will be attempted,
@@ -618,22 +619,21 @@ static int should_reconnect = 0;
* asserting SEL.
*/
-static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave (dev->host_lock, flags);
- seagate_reconnect_intr (irq, dev_id, regs);
+ seagate_reconnect_intr (irq, dev_id);
spin_unlock_irqrestore (dev->host_lock, flags);
return IRQ_HANDLED;
}
-static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
+static void seagate_reconnect_intr (int irq, void *dev_id)
{
int temp;
- Scsi_Cmnd *SCtmp;
+ struct scsi_cmnd *SCtmp;
DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
@@ -675,10 +675,11 @@ static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
static int recursion_depth = 0;
-static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+static int seagate_st0x_queue_command(struct scsi_cmnd * SCpnt,
+ void (*done) (struct scsi_cmnd *))
{
int result, reconnect;
- Scsi_Cmnd *SCtmp;
+ struct scsi_cmnd *SCtmp;
DANY ("seagate: que_command");
done_fn = done;
@@ -1609,7 +1610,7 @@ connect_loop:
return retcode (st0x_aborted);
} /* end of internal_command */
-static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
+static int seagate_st0x_abort(struct scsi_cmnd * SCpnt)
{
st0x_aborted = DID_ABORT;
return SUCCESS;
@@ -1624,7 +1625,7 @@ static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
* May be called with SCpnt = NULL
*/
-static int seagate_st0x_bus_reset(Scsi_Cmnd * SCpnt)
+static int seagate_st0x_bus_reset(struct scsi_cmnd * SCpnt)
{
/* No timeouts - this command is going to fail because it was reset. */
DANY ("scsi%d: Reseting bus... ", hostno);
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
deleted file mode 100644
index fb5f380fa4b3..000000000000
--- a/drivers/scsi/seagate.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * seagate.h Copyright (C) 1992 Drew Eckhardt
- * low level scsi driver header for ST01/ST02 by
- * Drew Eckhardt
- *
- * <drew@colorado.edu>
- */
-
-#ifndef _SEAGATE_H
-#define SEAGATE_H
-
-static int seagate_st0x_detect(struct scsi_host_template *);
-static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-
-static int seagate_st0x_abort(Scsi_Cmnd *);
-static const char *seagate_st0x_info(struct Scsi_Host *);
-static int seagate_st0x_bus_reset(Scsi_Cmnd *);
-
-#endif /* _SEAGATE_H */
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 34f9343ed0af..3f8b93188567 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -60,7 +60,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */
#ifdef CONFIG_SCSI_PROC_FS
#include <linux/proc_fs.h>
-static char *sg_version_date = "20060818";
+static char *sg_version_date = "20060920";
static int sg_proc_init(void);
static void sg_proc_cleanup(void);
@@ -94,6 +94,9 @@ int sg_big_buff = SG_DEF_RESERVED_SIZE;
static int def_reserved_size = -1; /* picks up init parameter */
static int sg_allow_dio = SG_ALLOW_DIO_DEF;
+static int scatter_elem_sz = SG_SCATTER_SZ;
+static int scatter_elem_sz_prev = SG_SCATTER_SZ;
+
#define SG_SECTOR_SZ 512
#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
@@ -1537,11 +1540,9 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf)
msleep(10); /* dirty detach so delay device destruction */
}
-/* Set 'perm' (4th argument) to 0 to disable module_param's definition
- * of sysfs parameters (which module_param doesn't yet support).
- * Sysfs parameters defined explicitly below.
- */
-module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO);
+module_param_named(scatter_elem_sz, scatter_elem_sz, int, S_IRUGO | S_IWUSR);
+module_param_named(def_reserved_size, def_reserved_size, int,
+ S_IRUGO | S_IWUSR);
module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
MODULE_AUTHOR("Douglas Gilbert");
@@ -1550,6 +1551,8 @@ MODULE_LICENSE("GPL");
MODULE_VERSION(SG_VERSION_STR);
MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
+MODULE_PARM_DESC(scatter_elem_sz, "scatter gather element "
+ "size (default: max(SG_SCATTER_SZ, PAGE_SIZE))");
MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
@@ -1558,8 +1561,14 @@ init_sg(void)
{
int rc;
+ if (scatter_elem_sz < PAGE_SIZE) {
+ scatter_elem_sz = PAGE_SIZE;
+ scatter_elem_sz_prev = scatter_elem_sz;
+ }
if (def_reserved_size >= 0)
sg_big_buff = def_reserved_size;
+ else
+ def_reserved_size = sg_big_buff;
rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
SG_MAX_DEVS, "sg");
@@ -1842,15 +1851,30 @@ sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
if (mx_sc_elems < 0)
return mx_sc_elems; /* most likely -ENOMEM */
+ num = scatter_elem_sz;
+ if (unlikely(num != scatter_elem_sz_prev)) {
+ if (num < PAGE_SIZE) {
+ scatter_elem_sz = PAGE_SIZE;
+ scatter_elem_sz_prev = PAGE_SIZE;
+ } else
+ scatter_elem_sz_prev = num;
+ }
for (k = 0, sg = schp->buffer, rem_sz = blk_size;
(rem_sz > 0) && (k < mx_sc_elems);
++k, rem_sz -= ret_sz, ++sg) {
- num = (rem_sz > SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
+ num = (rem_sz > scatter_elem_sz_prev) ?
+ scatter_elem_sz_prev : rem_sz;
p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
if (!p)
return -ENOMEM;
+ if (num == scatter_elem_sz_prev) {
+ if (unlikely(ret_sz > scatter_elem_sz_prev)) {
+ scatter_elem_sz = ret_sz;
+ scatter_elem_sz_prev = ret_sz;
+ }
+ }
sg->page = p;
sg->length = ret_sz;
@@ -2341,6 +2365,9 @@ sg_add_sfp(Sg_device * sdp, int dev)
}
write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
+ if (unlikely(sg_big_buff != def_reserved_size))
+ sg_big_buff = def_reserved_size;
+
sg_build_reserve(sfp, sg_big_buff);
SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: bufflen=%d, k_use_sg=%d\n",
sfp->reserve.bufflen, sfp->reserve.k_use_sg));
@@ -2437,16 +2464,16 @@ sg_res_in_use(Sg_fd * sfp)
return srp ? 1 : 0;
}
-/* If retSzp==NULL want exact size or fail */
+/* The size fetched (value output via retSzp) set when non-NULL return */
static struct page *
sg_page_malloc(int rqSz, int lowDma, int *retSzp)
{
struct page *resp = NULL;
gfp_t page_mask;
int order, a_size;
- int resSz = rqSz;
+ int resSz;
- if (rqSz <= 0)
+ if ((rqSz <= 0) || (NULL == retSzp))
return resp;
if (lowDma)
@@ -2456,8 +2483,9 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
order++, a_size <<= 1) ;
+ resSz = a_size; /* rounded up if necessary */
resp = alloc_pages(page_mask, order);
- while ((!resp) && order && retSzp) {
+ while ((!resp) && order) {
--order;
a_size >>= 1; /* divide by 2, until PAGE_SIZE */
resp = alloc_pages(page_mask, order); /* try half */
@@ -2466,8 +2494,7 @@ sg_page_malloc(int rqSz, int lowDma, int *retSzp)
if (resp) {
if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
memset(page_address(resp), 0, resSz);
- if (retSzp)
- *retSzp = resSz;
+ *retSzp = resSz;
}
return resp;
}
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 4f1db6f2aae8..e81f97a35bc8 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -84,7 +84,7 @@ static inline unsigned long read_wd33c93_count(const wd33c93_regs regs)
return value;
}
-static irqreturn_t sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sgiwd93_intr(int irq, void *dev_id)
{
struct Scsi_Host * host = (struct Scsi_Host *) dev_id;
unsigned long flags;
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
index b27e85428daa..551baccec523 100644
--- a/drivers/scsi/sim710.c
+++ b/drivers/scsi/sim710.c
@@ -282,6 +282,7 @@ static struct eisa_device_id sim710_eisa_ids[] = {
{ "HWP0C80" },
{ "" }
};
+MODULE_DEVICE_TABLE(eisa, sim710_eisa_ids);
static __init int
sim710_eisa_probe(struct device *dev)
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 7f669b600677..3babdc76b3fb 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -195,9 +195,9 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
static int st_probe(struct device *);
static int st_remove(struct device *);
-static void do_create_driverfs_files(void);
+static int do_create_driverfs_files(void);
static void do_remove_driverfs_files(void);
-static void do_create_class_files(struct scsi_tape *, int, int);
+static int do_create_class_files(struct scsi_tape *, int, int);
static struct scsi_driver st_template = {
.owner = THIS_MODULE,
@@ -4048,7 +4048,9 @@ static int st_probe(struct device *dev)
STm->cdevs[j] = cdev;
}
- do_create_class_files(tpnt, dev_num, mode);
+ error = do_create_class_files(tpnt, dev_num, mode);
+ if (error)
+ goto out_free_tape;
}
sdev_printk(KERN_WARNING, SDp,
@@ -4157,32 +4159,45 @@ static void scsi_tape_release(struct kref *kref)
static int __init init_st(void)
{
+ int err;
+
validate_options();
- printk(KERN_INFO
- "st: Version %s, fixed bufsize %d, s/g segs %d\n",
+ printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
verstr, st_fixed_buffer_size, st_max_sg_segs);
st_sysfs_class = class_create(THIS_MODULE, "scsi_tape");
if (IS_ERR(st_sysfs_class)) {
- st_sysfs_class = NULL;
printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n");
- return 1;
+ return PTR_ERR(st_sysfs_class);
}
- if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
- ST_MAX_TAPE_ENTRIES, "st")) {
- if (scsi_register_driver(&st_template.gendrv) == 0) {
- do_create_driverfs_files();
- return 0;
- }
- unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
- ST_MAX_TAPE_ENTRIES);
+ err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+ ST_MAX_TAPE_ENTRIES, "st");
+ if (err) {
+ printk(KERN_ERR "Unable to get major %d for SCSI tapes\n",
+ SCSI_TAPE_MAJOR);
+ goto err_class;
}
- class_destroy(st_sysfs_class);
- printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
- return 1;
+ err = scsi_register_driver(&st_template.gendrv);
+ if (err)
+ goto err_chrdev;
+
+ err = do_create_driverfs_files();
+ if (err)
+ goto err_scsidrv;
+
+ return 0;
+
+err_scsidrv:
+ scsi_unregister_driver(&st_template.gendrv);
+err_chrdev:
+ unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+ ST_MAX_TAPE_ENTRIES);
+err_class:
+ class_destroy(st_sysfs_class);
+ return err;
}
static void __exit exit_st(void)
@@ -4225,14 +4240,33 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf)
}
static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
-static void do_create_driverfs_files(void)
+static int do_create_driverfs_files(void)
{
struct device_driver *driverfs = &st_template.gendrv;
+ int err;
+
+ err = driver_create_file(driverfs, &driver_attr_try_direct_io);
+ if (err)
+ return err;
+ err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
+ if (err)
+ goto err_try_direct_io;
+ err = driver_create_file(driverfs, &driver_attr_max_sg_segs);
+ if (err)
+ goto err_attr_fixed_buf;
+ err = driver_create_file(driverfs, &driver_attr_version);
+ if (err)
+ goto err_attr_max_sg;
- driver_create_file(driverfs, &driver_attr_try_direct_io);
- driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
- driver_create_file(driverfs, &driver_attr_max_sg_segs);
- driver_create_file(driverfs, &driver_attr_version);
+ return 0;
+
+err_attr_max_sg:
+ driver_remove_file(driverfs, &driver_attr_max_sg_segs);
+err_attr_fixed_buf:
+ driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
+err_try_direct_io:
+ driver_remove_file(driverfs, &driver_attr_try_direct_io);
+ return err;
}
static void do_remove_driverfs_files(void)
@@ -4293,15 +4327,12 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf)
CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
-static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
+static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
{
int i, rew, error;
char name[10];
struct class_device *st_class_member;
- if (!st_sysfs_class)
- return;
-
for (rew=0; rew < 2; rew++) {
/* Make sure that the minor numbers corresponding to the four
first modes always get the same names */
@@ -4316,18 +4347,24 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
if (IS_ERR(st_class_member)) {
printk(KERN_WARNING "st%d: class_device_create failed\n",
dev_num);
+ error = PTR_ERR(st_class_member);
goto out;
}
class_set_devdata(st_class_member, &STp->modes[mode]);
- class_device_create_file(st_class_member,
- &class_device_attr_defined);
- class_device_create_file(st_class_member,
- &class_device_attr_default_blksize);
- class_device_create_file(st_class_member,
- &class_device_attr_default_density);
- class_device_create_file(st_class_member,
- &class_device_attr_default_compression);
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_defined);
+ if (error) goto out;
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_default_blksize);
+ if (error) goto out;
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_default_density);
+ if (error) goto out;
+ error = class_device_create_file(st_class_member,
+ &class_device_attr_default_compression);
+ if (error) goto out;
+
if (mode == 0 && rew == 0) {
error = sysfs_create_link(&STp->device->sdev_gendev.kobj,
&st_class_member->kobj,
@@ -4336,11 +4373,15 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
printk(KERN_ERR
"st%d: Can't create sysfs link from SCSI device.\n",
dev_num);
+ goto out;
}
}
}
- out:
- return;
+
+ return 0;
+
+out:
+ return error;
}
/* The following functions may be useful for a larger audience. */
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 3cf3106a29b8..185c270bb043 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -11,7 +11,7 @@
* Written By:
* Ed Lin <promise_linux@promise.com>
*
- * Version: 2.9.0.13
+ * Version: 3.0.0.1
*
*/
@@ -37,11 +37,11 @@
#include <scsi/scsi_tcq.h>
#define DRV_NAME "stex"
-#define ST_DRIVER_VERSION "2.9.0.13"
-#define ST_VER_MAJOR 2
-#define ST_VER_MINOR 9
+#define ST_DRIVER_VERSION "3.0.0.1"
+#define ST_VER_MAJOR 3
+#define ST_VER_MINOR 0
#define ST_OEM 0
-#define ST_BUILD_VER 13
+#define ST_BUILD_VER 1
enum {
/* MU register offset */
@@ -120,12 +120,18 @@ enum {
st_shasta = 0,
st_vsc = 1,
+ st_yosemite = 2,
PASSTHRU_REQ_TYPE = 0x00000001,
PASSTHRU_REQ_NO_WAKEUP = 0x00000100,
ST_INTERNAL_TIMEOUT = 30,
+ ST_TO_CMD = 0,
+ ST_FROM_CMD = 1,
+
/* vendor specific commands of Promise */
+ MGT_CMD = 0xd8,
+ SINBAND_MGT_CMD = 0xd9,
ARRAY_CMD = 0xe0,
CONTROLLER_CMD = 0xe1,
DEBUGGING_CMD = 0xe2,
@@ -133,14 +139,48 @@ enum {
PASSTHRU_GET_ADAPTER = 0x05,
PASSTHRU_GET_DRVVER = 0x10,
+
+ CTLR_CONFIG_CMD = 0x03,
+ CTLR_SHUTDOWN = 0x0d,
+
CTLR_POWER_STATE_CHANGE = 0x0e,
CTLR_POWER_SAVING = 0x01,
PASSTHRU_SIGNATURE = 0x4e415041,
+ MGT_CMD_SIGNATURE = 0xba,
INQUIRY_EVPD = 0x01,
};
+/* SCSI inquiry data */
+typedef struct st_inq {
+ u8 DeviceType :5;
+ u8 DeviceTypeQualifier :3;
+ u8 DeviceTypeModifier :7;
+ u8 RemovableMedia :1;
+ u8 Versions;
+ u8 ResponseDataFormat :4;
+ u8 HiSupport :1;
+ u8 NormACA :1;
+ u8 ReservedBit :1;
+ u8 AERC :1;
+ u8 AdditionalLength;
+ u8 Reserved[2];
+ u8 SoftReset :1;
+ u8 CommandQueue :1;
+ u8 Reserved2 :1;
+ u8 LinkedCommands :1;
+ u8 Synchronous :1;
+ u8 Wide16Bit :1;
+ u8 Wide32Bit :1;
+ u8 RelativeAddressing :1;
+ u8 VendorId[8];
+ u8 ProductId[16];
+ u8 ProductRevisionLevel[4];
+ u8 VendorSpecific[20];
+ u8 Reserved3[40];
+} ST_INQ;
+
struct st_sgitem {
u8 ctrl; /* SG_CF_xxx */
u8 reserved[3];
@@ -181,7 +221,7 @@ struct req_msg {
u8 task_attr;
u8 task_manage;
u8 prd_entry;
- u8 payload_sz; /* payload size in 4-byte */
+ u8 payload_sz; /* payload size in 4-byte, not used */
u8 cdb[STEX_CDB_LENGTH];
u8 variable[REQ_VARIABLE_LEN];
};
@@ -242,7 +282,8 @@ struct st_drvver {
#define MU_REQ_BUFFER_SIZE (MU_REQ_COUNT * sizeof(struct req_msg))
#define MU_STATUS_BUFFER_SIZE (MU_STATUS_COUNT * sizeof(struct status_msg))
#define MU_BUFFER_SIZE (MU_REQ_BUFFER_SIZE + MU_STATUS_BUFFER_SIZE)
-#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + sizeof(struct st_frame))
+#define STEX_EXTRA_SIZE max(sizeof(struct st_frame), sizeof(ST_INQ))
+#define STEX_BUFFER_SIZE (MU_BUFFER_SIZE + STEX_EXTRA_SIZE)
struct st_ccb {
struct req_msg *req;
@@ -403,7 +444,7 @@ static int stex_map_sg(struct st_hba *hba,
}
static void stex_internal_copy(struct scsi_cmnd *cmd,
- const void *src, size_t *count, int sg_count)
+ const void *src, size_t *count, int sg_count, int direction)
{
size_t lcount;
size_t len;
@@ -427,7 +468,10 @@ static void stex_internal_copy(struct scsi_cmnd *cmd,
} else
d = cmd->request_buffer;
- memcpy(d, s, len);
+ if (direction == ST_TO_CMD)
+ memcpy(d, s, len);
+ else
+ memcpy(s, d, len);
lcount -= len;
if (cmd->use_sg)
@@ -449,7 +493,7 @@ static int stex_direct_copy(struct scsi_cmnd *cmd,
return 0;
}
- stex_internal_copy(cmd, src, &cp_len, n_elem);
+ stex_internal_copy(cmd, src, &cp_len, n_elem, ST_TO_CMD);
if (cmd->use_sg)
pci_unmap_sg(hba->pdev, cmd->request_buffer,
@@ -480,7 +524,7 @@ static void stex_controller_info(struct st_hba *hba, struct st_ccb *ccb)
p->subid =
hba->pdev->subsystem_vendor << 16 | hba->pdev->subsystem_device;
- stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count);
+ stex_internal_copy(ccb->cmd, p, &count, ccb->sg_count, ST_TO_CMD);
}
static void
@@ -489,7 +533,6 @@ stex_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
req->tag = cpu_to_le16(tag);
req->task_attr = TASK_ATTRIBUTE_SIMPLE;
req->task_manage = 0; /* not supported yet */
- req->payload_sz = (u8)(sizeof(struct req_msg)/sizeof(u32));
hba->ccb[tag].req = req;
hba->out_req_cnt++;
@@ -595,8 +638,14 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
return SCSI_MLQUEUE_HOST_BUSY;
req = stex_alloc_req(hba);
- req->lun = lun;
- req->target = id;
+
+ if (hba->cardtype == st_yosemite) {
+ req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id;
+ req->target = 0;
+ } else {
+ req->lun = lun;
+ req->target = id;
+ }
/* cdb */
memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH);
@@ -680,7 +729,51 @@ static void stex_copy_data(struct st_ccb *ccb,
if (ccb->cmd == NULL)
return;
- stex_internal_copy(ccb->cmd, resp->variable, &count, ccb->sg_count);
+ stex_internal_copy(ccb->cmd,
+ resp->variable, &count, ccb->sg_count, ST_TO_CMD);
+}
+
+static void stex_ys_commands(struct st_hba *hba,
+ struct st_ccb *ccb, struct status_msg *resp)
+{
+ size_t count;
+
+ if (ccb->cmd->cmnd[0] == MGT_CMD &&
+ resp->scsi_status != SAM_STAT_CHECK_CONDITION) {
+ ccb->cmd->request_bufflen =
+ le32_to_cpu(*(__le32 *)&resp->variable[0]);
+ return;
+ }
+
+ if (resp->srb_status != 0)
+ return;
+
+ /* determine inquiry command status by DeviceTypeQualifier */
+ if (ccb->cmd->cmnd[0] == INQUIRY &&
+ resp->scsi_status == SAM_STAT_GOOD) {
+ ST_INQ *inq_data;
+
+ count = STEX_EXTRA_SIZE;
+ stex_internal_copy(ccb->cmd, hba->copy_buffer,
+ &count, ccb->sg_count, ST_FROM_CMD);
+ inq_data = (ST_INQ *)hba->copy_buffer;
+ if (inq_data->DeviceTypeQualifier != 0)
+ ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT;
+ else
+ ccb->srb_status = SRB_STATUS_SUCCESS;
+ } else if (ccb->cmd->cmnd[0] == REPORT_LUNS) {
+ u8 *report_lun_data = (u8 *)hba->copy_buffer;
+
+ count = STEX_EXTRA_SIZE;
+ stex_internal_copy(ccb->cmd, report_lun_data,
+ &count, ccb->sg_count, ST_FROM_CMD);
+ if (report_lun_data[2] || report_lun_data[3]) {
+ report_lun_data[2] = 0x00;
+ report_lun_data[3] = 0x08;
+ stex_internal_copy(ccb->cmd, report_lun_data,
+ &count, ccb->sg_count, ST_TO_CMD);
+ }
+ }
}
static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
@@ -702,8 +795,17 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
return;
}
- if (unlikely(hba->mu_status != MU_STATE_STARTED ||
- hba->out_req_cnt <= 0)) {
+ /*
+ * it's not a valid status payload if:
+ * 1. there are no pending requests(e.g. during init stage)
+ * 2. there are some pending requests, but the controller is in
+ * reset status, and its type is not st_yosemite
+ * firmware of st_yosemite in reset status will return pending requests
+ * to driver, so we allow it to pass
+ */
+ if (unlikely(hba->out_req_cnt <= 0 ||
+ (hba->mu_status == MU_STATE_RESETTING &&
+ hba->cardtype != st_yosemite))) {
hba->status_tail = hba->status_head;
goto update_status;
}
@@ -723,6 +825,7 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
if (unlikely(ccb->req == NULL)) {
printk(KERN_WARNING DRV_NAME
"(%s): lagging req\n", pci_name(hba->pdev));
+ hba->out_req_cnt--;
continue;
}
@@ -741,9 +844,13 @@ static void stex_mu_intr(struct st_hba *hba, u32 doorbell)
ccb->scsi_status = resp->scsi_status;
if (likely(ccb->cmd != NULL)) {
+ if (hba->cardtype == st_yosemite)
+ stex_ys_commands(hba, ccb, resp);
+
if (unlikely(ccb->cmd->cmnd[0] == PASSTHRU_CMD &&
ccb->cmd->cmnd[1] == PASSTHRU_GET_ADAPTER))
stex_controller_info(hba, ccb);
+
stex_unmap_sg(hba, ccb->cmd);
stex_scsi_done(ccb);
hba->out_req_cnt--;
@@ -764,7 +871,7 @@ update_status:
readl(base + IMR1); /* flush */
}
-static irqreturn_t stex_intr(int irq, void *__hba, struct pt_regs *regs)
+static irqreturn_t stex_intr(int irq, void *__hba)
{
struct st_hba *hba = __hba;
void __iomem *base = hba->mmio_base;
@@ -948,6 +1055,7 @@ static int stex_reset(struct scsi_cmnd *cmd)
{
struct st_hba *hba;
unsigned long flags;
+ unsigned long before;
hba = (struct st_hba *) &cmd->device->host->hostdata[0];
hba->mu_status = MU_STATE_RESETTING;
@@ -955,20 +1063,37 @@ static int stex_reset(struct scsi_cmnd *cmd)
if (hba->cardtype == st_shasta)
stex_hard_reset(hba);
- if (stex_handshake(hba)) {
- printk(KERN_WARNING DRV_NAME
- "(%s): resetting: handshake failed\n",
- pci_name(hba->pdev));
- return FAILED;
+ if (hba->cardtype != st_yosemite) {
+ if (stex_handshake(hba)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): resetting: handshake failed\n",
+ pci_name(hba->pdev));
+ return FAILED;
+ }
+ spin_lock_irqsave(hba->host->host_lock, flags);
+ hba->req_head = 0;
+ hba->req_tail = 0;
+ hba->status_head = 0;
+ hba->status_tail = 0;
+ hba->out_req_cnt = 0;
+ spin_unlock_irqrestore(hba->host->host_lock, flags);
+ return SUCCESS;
+ }
+
+ /* st_yosemite */
+ writel(MU_INBOUND_DOORBELL_RESET, hba->mmio_base + IDBL);
+ readl(hba->mmio_base + IDBL); /* flush */
+ before = jiffies;
+ while (hba->out_req_cnt > 0) {
+ if (time_after(jiffies, before + ST_INTERNAL_TIMEOUT * HZ)) {
+ printk(KERN_WARNING DRV_NAME
+ "(%s): reset timeout\n", pci_name(hba->pdev));
+ return FAILED;
+ }
+ msleep(1);
}
- spin_lock_irqsave(hba->host->host_lock, flags);
- hba->req_head = 0;
- hba->req_tail = 0;
- hba->status_head = 0;
- hba->status_tail = 0;
- hba->out_req_cnt = 0;
- spin_unlock_irqrestore(hba->host->host_lock, flags);
+ hba->mu_status = MU_STATE_STARTED;
return SUCCESS;
}
@@ -1156,9 +1281,16 @@ static void stex_hba_stop(struct st_hba *hba)
req = stex_alloc_req(hba);
memset(req->cdb, 0, STEX_CDB_LENGTH);
- req->cdb[0] = CONTROLLER_CMD;
- req->cdb[1] = CTLR_POWER_STATE_CHANGE;
- req->cdb[2] = CTLR_POWER_SAVING;
+ if (hba->cardtype == st_yosemite) {
+ req->cdb[0] = MGT_CMD;
+ req->cdb[1] = MGT_CMD_SIGNATURE;
+ req->cdb[2] = CTLR_CONFIG_CMD;
+ req->cdb[3] = CTLR_SHUTDOWN;
+ } else {
+ req->cdb[0] = CONTROLLER_CMD;
+ req->cdb[1] = CTLR_POWER_STATE_CHANGE;
+ req->cdb[2] = CTLR_POWER_SAVING;
+ }
hba->ccb[tag].cmd = NULL;
hba->ccb[tag].sg_count = 0;
@@ -1222,6 +1354,7 @@ static struct pci_device_id stex_pci_tbl[] = {
{ 0x105a, 0x8301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
{ 0x105a, 0x8302, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_shasta },
{ 0x1725, 0x7250, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_vsc },
+ { 0x105a, 0x8650, PCI_ANY_ID, PCI_ANY_ID, 0, 0, st_yosemite },
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, stex_pci_tbl);
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
index 2f8073b73bf3..5ec5af8e3379 100644
--- a/drivers/scsi/sun3_NCR5380.c
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -1252,7 +1252,7 @@ static void NCR5380_dma_complete( struct Scsi_Host *instance )
*
*/
-static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t NCR5380_intr (int irq, void *dev_id)
{
struct Scsi_Host *instance = first_instance;
int done = 1, handled = 0;
@@ -2017,7 +2017,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance)
if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
!= cmd))
{
- if(cmd->request->flags & REQ_CMD) {
+ if(blk_fs_request(cmd->request)) {
sun3scsi_dma_setup(d, count,
rq_data_dir(cmd->request));
sun3_dma_setup_done = cmd;
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 837173415d4c..e625b4c5833a 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -102,7 +102,7 @@ static void NCR5380_print(struct Scsi_Host *instance);
#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI );
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
static inline unsigned char sun3scsi_read(int reg);
static inline void sun3scsi_write(int reg, int value);
@@ -371,7 +371,7 @@ const char * sun3scsi_info (struct Scsi_Host *spnt) {
// safe bits for the CSR
#define CSR_GOOD 0x060f
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
{
unsigned short csr = dregs->csr;
int handled = 0;
@@ -388,7 +388,7 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
}
if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
- NCR5380_intr(irq, dummy, fp);
+ NCR5380_intr(irq, dummy);
handled = 1;
}
@@ -524,7 +524,7 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
int write_flag)
{
- if(cmd->request->flags & REQ_CMD)
+ if(blk_fs_request(cmd->request))
return wanted;
else
return 0;
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
index 008a82ab8521..e8faab16567b 100644
--- a/drivers/scsi/sun3_scsi_vme.c
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -67,7 +67,7 @@ extern int sun3_map_test(unsigned long, char *);
#define ENABLE_IRQ()
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
static inline unsigned char sun3scsi_read(int reg);
static inline void sun3scsi_write(int reg, int value);
@@ -340,7 +340,7 @@ static const char * sun3scsi_info (struct Scsi_Host *spnt) {
// safe bits for the CSR
#define CSR_GOOD 0x060f
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
{
unsigned short csr = dregs->csr;
int handled = 0;
@@ -371,7 +371,7 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
}
if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
- NCR5380_intr(irq, dummy, fp);
+ NCR5380_intr(irq, dummy);
handled = 1;
}
@@ -458,7 +458,7 @@ static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
int write_flag)
{
- if(cmd->request->flags & REQ_CMD)
+ if(blk_fs_request(cmd->request))
return wanted;
else
return 0;
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
index 8640253d6215..32c883f1efa1 100644
--- a/drivers/scsi/sym53c416.c
+++ b/drivers/scsi/sym53c416.c
@@ -326,8 +326,7 @@ static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer,
return orig_len - len;
}
-static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id)
{
struct Scsi_Host *dev = dev_id;
int base = 0;
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 739d3ef46a40..4d78c7e87cca 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -652,7 +652,7 @@ static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
/*
* Linux entry point of the interrupt handler.
*/
-static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t sym53c8xx_intr(int irq, void *dev_id)
{
unsigned long flags;
struct sym_hcb *np = (struct sym_hcb *)dev_id;
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 2df6747cb76f..0b7a70f61e0d 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -109,7 +109,7 @@
#include <asm/system.h>
#include <linux/signal.h>
#include <linux/sched.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/stat.h>
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 9404ff3d4c79..d03aa6ce8fe8 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -279,6 +279,10 @@ static void dc390_ResetDevParam(struct dc390_acb* pACB);
static u32 dc390_laststatus = 0;
static u8 dc390_adapterCnt = 0;
+static int disable_clustering;
+module_param(disable_clustering, int, S_IRUGO);
+MODULE_PARM_DESC(disable_clustering, "If you experience problems with your devices, try setting to 1");
+
/* Startup values, to be overriden on the commandline */
static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
@@ -696,9 +700,9 @@ dc390_InvalidCmd(struct dc390_acb* pACB)
static irqreturn_t __inline__
-DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
+DC390_Interrupt(void *dev_id)
{
- struct dc390_acb *pACB = (struct dc390_acb*)dev_id;
+ struct dc390_acb *pACB = dev_id;
struct dc390_dcb *pDCB;
struct dc390_srb *pSRB;
u8 sstatus=0;
@@ -807,12 +811,12 @@ DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id)
{
irqreturn_t ret;
DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq));
/* Locking is done in DC390_Interrupt */
- ret = DC390_Interrupt(irq, dev_id, regs);
+ ret = DC390_Interrupt(dev_id);
DEBUG1(printk (".. IRQ returned\n"));
return ret;
}
@@ -2299,7 +2303,7 @@ static struct scsi_host_template driver_template = {
.this_id = 7,
.sg_tablesize = SG_ALL,
.cmd_per_lun = 1,
- .use_clustering = DISABLE_CLUSTERING,
+ .use_clustering = ENABLE_CLUSTERING,
};
/***********************************************************************
@@ -2525,6 +2529,8 @@ static int __devinit dc390_probe_one(struct pci_dev *pdev,
pci_set_master(pdev);
error = -ENOMEM;
+ if (disable_clustering)
+ driver_template.use_clustering = DISABLE_CLUSTERING;
shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb));
if (!shost)
goto out_disable_device;
@@ -2660,6 +2666,10 @@ static struct pci_driver dc390_driver = {
static int __init dc390_module_init(void)
{
+ if (!disable_clustering)
+ printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n"
+ "\twith \"disable_clustering=1\" and report to maintainers\n");
+
if (tmscsim[0] == -1 || tmscsim[0] > 15) {
tmscsim[0] = 7;
tmscsim[1] = 4;
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index 57449611e714..3de08a15de40 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -634,7 +634,7 @@ static unsigned long io_port[] = {
#define H2DEV(x) cpu_to_le32(x)
#define DEV2H(x) le32_to_cpu(x)
-static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
+static irqreturn_t do_interrupt_handler(int, void *);
static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int);
static int do_trace = FALSE;
static int setup_done = FALSE;
@@ -1932,8 +1932,7 @@ none:
return IRQ_NONE;
}
-static irqreturn_t do_interrupt_handler(int irq, void *shap,
- struct pt_regs *regs) {
+static irqreturn_t do_interrupt_handler(int irq, void *shap) {
unsigned int j;
unsigned long spin_flags;
irqreturn_t ret;
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
index 0372aa9fa190..56906aba5ee3 100644
--- a/drivers/scsi/ultrastor.c
+++ b/drivers/scsi/ultrastor.c
@@ -287,8 +287,8 @@ static const unsigned short ultrastor_ports_14f[] = {
};
#endif
-static void ultrastor_interrupt(int, void *, struct pt_regs *);
-static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *);
+static void ultrastor_interrupt(void *);
+static irqreturn_t do_ultrastor_interrupt(int, void *);
static inline void build_sg_list(struct mscp *, struct scsi_cmnd *SCpnt);
@@ -893,7 +893,7 @@ static int ultrastor_abort(struct scsi_cmnd *SCpnt)
spin_lock_irqsave(host->host_lock, flags);
/* FIXME: Ewww... need to think about passing host around properly */
- ultrastor_interrupt(0, NULL, NULL);
+ ultrastor_interrupt(NULL);
spin_unlock_irqrestore(host->host_lock, flags);
return SUCCESS;
}
@@ -1039,7 +1039,7 @@ int ultrastor_biosparam(struct scsi_device *sdev, struct block_device *bdev,
return 0;
}
-static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void ultrastor_interrupt(void *dev_id)
{
unsigned int status;
#if ULTRASTOR_MAX_CMDS > 1
@@ -1171,14 +1171,13 @@ static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
#endif
}
-static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id)
{
unsigned long flags;
struct Scsi_Host *dev = dev_id;
spin_lock_irqsave(dev->host_lock, flags);
- ultrastor_interrupt(irq, dev_id, regs);
+ ultrastor_interrupt(dev_id);
spin_unlock_irqrestore(dev->host_lock, flags);
return IRQ_HANDLED;
}
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index a0b61af48f1c..30be76514c43 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -178,10 +178,10 @@
#include <linux/blkdev.h>
#include <linux/init.h>
#include <linux/stat.h>
+#include <linux/io.h>
#include <asm/system.h>
#include <asm/dma.h>
-#include <asm/io.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -998,7 +998,7 @@ static int make_code(unsigned hosterr, unsigned scsierr)
#define wd7000_intr_ack(host) outb (0, host->iobase + ASC_INTR_ACK)
-static irqreturn_t wd7000_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t wd7000_intr(int irq, void *dev_id)
{
Adapter *host = (Adapter *) dev_id;
int flag, icmb, errstatus, icmb_status;
diff --git a/drivers/serial/21285.c b/drivers/serial/21285.c
index 57438326b07f..6a1a568ca649 100644
--- a/drivers/serial/21285.c
+++ b/drivers/serial/21285.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/char/21285.c
+ * linux/drivers/serial/21285.c
*
* Driver for the serial port on the 21285 StrongArm-110 core logic chip.
*
@@ -85,7 +85,7 @@ static void serial21285_enable_ms(struct uart_port *port)
{
}
-static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t serial21285_rx_chars(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct tty_struct *tty = port->info->tty;
@@ -123,7 +123,7 @@ static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *r
return IRQ_HANDLED;
}
-static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t serial21285_tx_chars(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct circ_buf *xmit = &port->info->xmit;
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index 993a702422ec..9b8b585513ec 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -275,8 +275,7 @@ static void status_handle(struct m68k_serial *info, unsigned short status)
return;
}
-static void receive_chars(struct m68k_serial *info, struct pt_regs *regs,
- unsigned short rx)
+static void receive_chars(struct m68k_serial *info, unsigned short rx)
{
struct tty_struct *tty = info->tty;
m68328_uart *uart = &uart_addr[info->line];
@@ -377,7 +376,7 @@ clear_and_return:
/*
* This is the serial driver's generic interrupt routine
*/
-irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+irqreturn_t rs_interrupt(int irq, void *dev_id)
{
struct m68k_serial * info;
m68328_uart *uart;
@@ -394,10 +393,10 @@ irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
#ifdef USE_INTS
tx = uart->utx.w;
- if (rx & URX_DATA_READY) receive_chars(info, regs, rx);
+ if (rx & URX_DATA_READY) receive_chars(info, rx);
if (tx & UTX_TX_AVAIL) transmit_chars(info);
#else
- receive_chars(info, regs, rx);
+ receive_chars(info, rx);
#endif
return IRQ_HANDLED;
}
@@ -1378,7 +1377,7 @@ void startup_console(void)
#endif /* CONFIG_PM_LEGACY */
-static struct tty_operations rs_ops = {
+static const struct tty_operations rs_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index e80e70e9b126..634ecca36a77 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -612,7 +612,7 @@ static _INLINE_ void check_modem_status(struct async_struct *info)
* This is the serial driver's interrupt routine for a single port
*/
/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
-static void rs_360_interrupt(int vec, void *dev_id, struct pt_regs *fp)
+static void rs_360_interrupt(int vec, void *dev_id)
{
u_char events;
int idx;
@@ -620,7 +620,7 @@ static void rs_360_interrupt(int vec, void *dev_id, struct pt_regs *fp)
volatile struct smc_regs *smcp;
volatile struct scc_regs *sccp;
- info = (ser_info_t *)dev_id;
+ info = dev_id;
idx = PORT_NUM(info->state->smc_scc_num);
if (info->state->smc_scc_num & NUM_IS_SCC) {
@@ -2424,7 +2424,7 @@ long console_360_init(long kmem_start, long kmem_end)
*/
static int baud_idx;
-static struct tty_operations rs_360_ops = {
+static const struct tty_operations rs_360_ops = {
.owner = THIS_MODULE,
.open = rs_360_open,
.close = rs_360_close,
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 0ae9ced00ed4..e34bd03cfce7 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -320,8 +320,8 @@ static unsigned int serial_in(struct uart_8250_port *up, int offset)
case UPIO_TSI:
if (offset == UART_IIR) {
- tmp = readl((u32 *)(up->port.membase + UART_RX));
- return (cpu_to_le32(tmp) >> 8) & 0xff;
+ tmp = readl(up->port.membase + (UART_IIR & ~3));
+ return (tmp >> 16) & 0xff; /* UART_IIR % 4 == 2 */
} else
return readb(up->port.membase + offset);
@@ -1175,7 +1175,7 @@ static void serial8250_enable_ms(struct uart_port *port)
}
static void
-receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
+receive_chars(struct uart_8250_port *up, int *status)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch, lsr = *status;
@@ -1233,7 +1233,7 @@ receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs)
else if (lsr & UART_LSR_FE)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto ignore_char;
uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag);
@@ -1309,7 +1309,7 @@ static unsigned int check_modem_status(struct uart_8250_port *up)
* This handles the interrupt from one port.
*/
static inline void
-serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
+serial8250_handle_port(struct uart_8250_port *up)
{
unsigned int status;
@@ -1320,7 +1320,7 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
DEBUG_INTR("status = %x...", status);
if (status & UART_LSR_DR)
- receive_chars(up, &status, regs);
+ receive_chars(up, &status);
check_modem_status(up);
if (status & UART_LSR_THRE)
transmit_chars(up);
@@ -1342,7 +1342,7 @@ serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs)
* This means we need to loop through all ports. checking that they
* don't have an interrupt pending.
*/
-static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t serial8250_interrupt(int irq, void *dev_id)
{
struct irq_info *i = dev_id;
struct list_head *l, *end = NULL;
@@ -1361,7 +1361,7 @@ static irqreturn_t serial8250_interrupt(int irq, void *dev_id, struct pt_regs *r
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT)) {
- serial8250_handle_port(up, regs);
+ serial8250_handle_port(up);
handled = 1;
@@ -1461,7 +1461,7 @@ static void serial8250_timeout(unsigned long data)
iir = serial_in(up, UART_IIR);
if (!(iir & UART_IIR_NO_INT))
- serial8250_handle_port(up, NULL);
+ serial8250_handle_port(up);
timeout = up->port.timeout;
timeout = timeout > 6 ? (timeout / 2 - 2) : 1;
@@ -1896,6 +1896,17 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
serial_outp(up, UART_EFR, efr);
}
+#ifdef CONFIG_ARCH_OMAP15XX
+ /* Workaround to enable 115200 baud on OMAP1510 internal ports */
+ if (cpu_is_omap1510() && is_omap_port((unsigned int)up->port.membase)) {
+ if (baud == 115200) {
+ quot = 1;
+ serial_out(up, UART_OMAP_OSC_12M_SEL, 1);
+ } else
+ serial_out(up, UART_OMAP_OSC_12M_SEL, 0);
+ }
+#endif
+
if (up->capabilities & UART_NATSEMI) {
/* Switch to bank 2 not bank 1, to avoid resetting EXCR2 */
serial_outp(up, UART_LCR, 0xe0);
@@ -1949,6 +1960,8 @@ static int serial8250_request_std_resource(struct uart_8250_port *up)
case UPIO_AU:
size = 0x100000;
/* fall thru */
+ case UPIO_TSI:
+ case UPIO_MEM32:
case UPIO_MEM:
if (!up->port.mapbase)
break;
@@ -1984,6 +1997,8 @@ static void serial8250_release_std_resource(struct uart_8250_port *up)
case UPIO_AU:
size = 0x100000;
/* fall thru */
+ case UPIO_TSI:
+ case UPIO_MEM32:
case UPIO_MEM:
if (!up->port.mapbase)
break;
@@ -2007,17 +2022,15 @@ static int serial8250_request_rsa_resource(struct uart_8250_port *up)
{
unsigned long start = UART_RSA_BASE << up->port.regshift;
unsigned int size = 8 << up->port.regshift;
- int ret = 0;
+ int ret = -EINVAL;
switch (up->port.iotype) {
- case UPIO_MEM:
- ret = -EINVAL;
- break;
-
case UPIO_HUB6:
case UPIO_PORT:
start += up->port.iobase;
- if (!request_region(start, size, "serial-rsa"))
+ if (request_region(start, size, "serial-rsa"))
+ ret = 0;
+ else
ret = -EBUSY;
break;
}
@@ -2031,9 +2044,6 @@ static void serial8250_release_rsa_resource(struct uart_8250_port *up)
unsigned int size = 8 << up->port.regshift;
switch (up->port.iotype) {
- case UPIO_MEM:
- break;
-
case UPIO_HUB6:
case UPIO_PORT:
release_region(up->port.iobase + offset, size);
@@ -2222,9 +2232,10 @@ static inline void wait_for_xmitr(struct uart_8250_port *up, int bits)
/* Wait up to 1s for flow control if necessary */
if (up->port.flags & UPF_CONS_FLOW) {
tmout = 1000000;
- while (--tmout &&
- ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0))
+ while (!(serial_in(up, UART_MSR) & UART_MSR_CTS) && --tmout) {
udelay(1);
+ touch_nmi_watchdog();
+ }
}
}
@@ -2397,7 +2408,6 @@ int __init early_serial_setup(struct uart_port *port)
/**
* serial8250_suspend_port - suspend one serial port
* @line: serial line number
- * @level: the level of port suspension, as per uart_suspend_port
*
* Suspend one serial port.
*/
@@ -2409,7 +2419,6 @@ void serial8250_suspend_port(int line)
/**
* serial8250_resume_port - resume one serial port
* @line: serial line number
- * @level: the level of port resumption, as per uart_resume_port
*
* Resume one serial port.
*/
diff --git a/drivers/serial/8250_acorn.c b/drivers/serial/8250_acorn.c
index 32af3650e8b4..ef8cc8a70c60 100644
--- a/drivers/serial/8250_acorn.c
+++ b/drivers/serial/8250_acorn.c
@@ -35,6 +35,7 @@ struct serial_card_type {
struct serial_card_info {
unsigned int num_ports;
int ports[MAX_PORTS];
+ void __iomem *vaddr;
};
static int __devinit
@@ -44,7 +45,6 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
struct serial_card_type *type = id->data;
struct uart_port port;
unsigned long bus_addr;
- unsigned char __iomem *virt_addr;
unsigned int i;
info = kmalloc(sizeof(struct serial_card_info), GFP_KERNEL);
@@ -55,8 +55,8 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
info->num_ports = type->num_ports;
bus_addr = ecard_resource_start(ec, type->type);
- virt_addr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
- if (!virt_addr) {
+ info->vaddr = ioremap(bus_addr, ecard_resource_len(ec, type->type));
+ if (!info->vaddr) {
kfree(info);
return -ENOMEM;
}
@@ -72,7 +72,7 @@ serial_card_probe(struct expansion_card *ec, const struct ecard_id *id)
port.dev = &ec->dev;
for (i = 0; i < info->num_ports; i ++) {
- port.membase = virt_addr + type->offset[i];
+ port.membase = info->vaddr + type->offset[i];
port.mapbase = bus_addr + type->offset[i];
info->ports[i] = serial8250_register_port(&port);
@@ -92,6 +92,7 @@ static void __devexit serial_card_remove(struct expansion_card *ec)
if (info->ports[i] > 0)
serial8250_unregister_port(info->ports[i]);
+ iounmap(info->vaddr);
kfree(info);
}
diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c
index 913c71cc0569..c5d0addfda4f 100644
--- a/drivers/serial/8250_gsc.c
+++ b/drivers/serial/8250_gsc.c
@@ -22,7 +22,6 @@
#include <asm/hardware.h>
#include <asm/parisc-device.h>
#include <asm/io.h>
-#include <asm/serial.h> /* for LASI_BASE_BAUD */
#include "8250.h"
@@ -54,7 +53,8 @@ serial_init_chip(struct parisc_device *dev)
memset(&port, 0, sizeof(port));
port.iotype = UPIO_MEM;
- port.uartclk = LASI_BASE_BAUD * 16;
+ /* 7.272727MHz on Lasi. Assumed the same for Dino, Wax and Timi. */
+ port.uartclk = 7272727;
port.mapbase = address;
port.membase = ioremap_nocache(address, 16);
port.irq = dev->irq;
@@ -64,6 +64,7 @@ serial_init_chip(struct parisc_device *dev)
err = serial8250_register_port(&port);
if (err < 0) {
printk(KERN_WARNING "serial8250_register_port returned error %d\n", err);
+ iounmap(port.membase);
return err;
}
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 851e4839d6d9..4d0ff8f4a01b 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -1789,6 +1789,7 @@ static void __devexit pciserial_remove_one(struct pci_dev *dev)
pci_disable_device(dev);
}
+#ifdef CONFIG_PM
static int pciserial_suspend_one(struct pci_dev *dev, pm_message_t state)
{
struct serial_private *priv = pci_get_drvdata(dev);
@@ -1818,6 +1819,7 @@ static int pciserial_resume_one(struct pci_dev *dev)
}
return 0;
}
+#endif
static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
@@ -2375,8 +2377,10 @@ static struct pci_driver serial_pci_driver = {
.name = "serial",
.probe = pciserial_init_one,
.remove = __devexit_p(pciserial_remove_one),
+#ifdef CONFIG_PM
.suspend = pciserial_suspend_one,
.resume = pciserial_resume_one,
+#endif
.id_table = serial_pci_tbl,
};
diff --git a/drivers/serial/8250_pnp.c b/drivers/serial/8250_pnp.c
index 632f62d6ec7e..71d907c8288b 100644
--- a/drivers/serial/8250_pnp.c
+++ b/drivers/serial/8250_pnp.c
@@ -327,6 +327,19 @@ static const struct pnp_device_id pnp_dev_table[] = {
{ "WACF004", 0 },
{ "WACF005", 0 },
{ "WACF006", 0 },
+ /* Compaq touchscreen */
+ { "FPI2002", 0 },
+ /* Fujitsu Stylistic touchscreens */
+ { "FUJ02B2", 0 },
+ { "FUJ02B3", 0 },
+ /* Fujitsu Stylistic LT touchscreens */
+ { "FUJ02B4", 0 },
+ /* Passive Fujitsu Stylistic touchscreens */
+ { "FUJ02B6", 0 },
+ { "FUJ02B7", 0 },
+ { "FUJ02B8", 0 },
+ { "FUJ02B9", 0 },
+ { "FUJ02BC", 0 },
/* Rockwell's (PORALiNK) 33600 INT PNP */
{ "WCI0003", 0 },
/* Unkown PnP modems */
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 5b48ac22c9c5..0b71e7d18903 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -121,7 +121,7 @@ config SERIAL_8250_RUNTIME_UARTS
default "4"
help
Set this to the maximum number of serial ports you want
- the kernel to register at boot time. This can be overriden
+ the kernel to register at boot time. This can be overridden
with the module parameter "nr_uarts", or boot-time parameter
8250.nr_uarts
@@ -205,7 +205,7 @@ config SERIAL_8250_BOCA
depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
help
Say Y here if you have a Boca serial board. Please read the Boca
- mini-HOWTO, avaialble from <http://www.tldp.org/docs.html#howto>
+ mini-HOWTO, available from <http://www.tldp.org/docs.html#howto>
To compile this driver as a module, choose M here: the module
will be called 8250_boca.
@@ -295,37 +295,37 @@ config SERIAL_AMBA_PL011_CONSOLE
Even if you say Y here, the currently visible framebuffer console
(/dev/tty0) will still be used as the system console by default, but
you can alter that using a kernel command line option such as
- "console=ttyAM0". (Try "man bootparam" or see the documentation of
+ "console=ttyAMA0". (Try "man bootparam" or see the documentation of
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
-config SERIAL_AT91
- bool "AT91RM9200 / AT91SAM9261 serial port support"
- depends on ARM && (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
+config SERIAL_ATMEL
+ bool "AT91 / AT32 on-chip serial port support"
+ depends on (ARM && ARCH_AT91) || AVR32
select SERIAL_CORE
help
This enables the driver for the on-chip UARTs of the Atmel
- AT91RM9200 and AT91SAM926 processor.
+ AT91 and AT32 processors.
-config SERIAL_AT91_CONSOLE
- bool "Support for console on AT91RM9200 / AT91SAM9261 serial port"
- depends on SERIAL_AT91=y
+config SERIAL_ATMEL_CONSOLE
+ bool "Support for console on AT91 / AT32 serial port"
+ depends on SERIAL_ATMEL=y
select SERIAL_CORE_CONSOLE
help
- Say Y here if you wish to use a UART on the Atmel AT91RM9200 or
- AT91SAM9261 as the system console (the system console is the device
- which receives all kernel messages and warnings and which allows
- logins in single user mode).
+ Say Y here if you wish to use an on-chip UART on a Atmel
+ AT91 or AT32 processor as the system console (the system
+ console is the device which receives all kernel messages and
+ warnings and which allows logins in single user mode).
-config SERIAL_AT91_TTYAT
- bool "Install as device ttyAT0-4 instead of ttyS0-4"
- depends on SERIAL_AT91=y
+config SERIAL_ATMEL_TTYAT
+ bool "Install as device ttyATn instead of ttySn"
+ depends on SERIAL_ATMEL=y
help
- Say Y here if you wish to have the five internal AT91RM9200 UARTs
- appear as /dev/ttyAT0-4 (major 204, minor 154-158) instead of the
- normal /dev/ttyS0-4 (major 4, minor 64-68). This is necessary if
- you also want other UARTs, such as external 8250/16C550 compatible
- UARTs.
+ Say Y here if you wish to have the internal AT91 / AT32 UARTs
+ appear as /dev/ttyATn (major 204, minor starting at 154)
+ instead of the normal /dev/ttySn (major 4, minor starting at
+ 64). This is necessary if you also want other UARTs, such as
+ external 8250/16C550 compatible UARTs.
The ttySn nodes are legally reserved for the 8250 serial driver
but are often misused by other serial drivers.
@@ -556,10 +556,11 @@ config SERIAL_MUX
default y
---help---
Saying Y here will enable the hardware MUX serial driver for
- the Nova and K class systems. The hardware MUX is not 8250/16550
- compatible therefore the /dev/ttyB0 device is shared between the
- Serial MUX and the PDC software console. The following steps
- need to be completed to use the Serial MUX:
+ the Nova, K class systems and D class with a 'remote control card'.
+ The hardware MUX is not 8250/16550 compatible therefore the
+ /dev/ttyB0 device is shared between the Serial MUX and the PDC
+ software console. The following steps need to be completed to use
+ the Serial MUX:
1. create the device entry (mknod /dev/ttyB0 c 11 0)
2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0
@@ -642,12 +643,17 @@ config V850E_UART_CONSOLE
select SERIAL_CORE_CONSOLE
config SERIAL_SH_SCI
- tristate "SH SCI(F) serial port support"
+ tristate "SuperH SCI(F) serial port support"
depends on SUPERH || H8300
select SERIAL_CORE
+config SERIAL_SH_SCI_NR_UARTS
+ int "Maximum number of SCI(F) serial ports"
+ depends on SERIAL_SH_SCI
+ default "2"
+
config SERIAL_SH_SCI_CONSOLE
- bool "Support for console on SH SCI(F)"
+ bool "Support for console on SuperH SCI(F)"
depends on SERIAL_SH_SCI=y
select SERIAL_CORE_CONSOLE
@@ -662,7 +668,7 @@ config SERIAL_68328
depends on M68328 || M68EZ328 || M68VZ328
help
This driver supports the built-in serial port of the Motorola 68328
- (standard, EZ and VZ varities).
+ (standard, EZ and VZ varieties).
config SERIAL_68328_RTS_CTS
bool "Support RTS/CTS on 68328 serial port"
@@ -761,37 +767,37 @@ config SERIAL_CPM_SCC1
bool "Support for SCC1 serial port"
depends on SERIAL_CPM=y
help
- Select the is option to use SCC1 as a serial port
+ Select this option to use SCC1 as a serial port
config SERIAL_CPM_SCC2
bool "Support for SCC2 serial port"
depends on SERIAL_CPM=y
help
- Select the is option to use SCC2 as a serial port
+ Select this option to use SCC2 as a serial port
config SERIAL_CPM_SCC3
bool "Support for SCC3 serial port"
depends on SERIAL_CPM=y
help
- Select the is option to use SCC3 as a serial port
+ Select this option to use SCC3 as a serial port
config SERIAL_CPM_SCC4
bool "Support for SCC4 serial port"
depends on SERIAL_CPM=y
help
- Select the is option to use SCC4 as a serial port
+ Select this option to use SCC4 as a serial port
config SERIAL_CPM_SMC1
bool "Support for SMC1 serial port"
depends on SERIAL_CPM=y
help
- Select the is option to use SMC1 as a serial port
+ Select this option to use SMC1 as a serial port
config SERIAL_CPM_SMC2
bool "Support for SMC2 serial port"
depends on SERIAL_CPM=y
help
- Select the is option to use SMC2 as a serial port
+ Select this option to use SMC2 as a serial port
config SERIAL_SGI_L1_CONSOLE
bool "SGI Altix L1 serial console support"
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 927faee0362e..b4d8a7c182e3 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -54,5 +54,5 @@ obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o
obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o
obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o
obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o
-obj-$(CONFIG_SERIAL_AT91) += at91_serial.o
+obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o
obj-$(CONFIG_SERIAL_NETX) += netx-serial.o
diff --git a/drivers/serial/amba-pl010.c b/drivers/serial/amba-pl010.c
index 7311d8487c96..4213fabc62bf 100644
--- a/drivers/serial/amba-pl010.c
+++ b/drivers/serial/amba-pl010.c
@@ -111,12 +111,7 @@ static void pl010_enable_ms(struct uart_port *port)
writel(cr, port->membase + UART010_CR);
}
-static void
-#ifdef SUPPORT_SYSRQ
-pl010_rx_chars(struct uart_port *port, struct pt_regs *regs)
-#else
-pl010_rx_chars(struct uart_port *port)
-#endif
+static void pl010_rx_chars(struct uart_port *port)
{
struct tty_struct *tty = port->info->tty;
unsigned int status, ch, flag, rsr, max_count = 256;
@@ -156,7 +151,7 @@ pl010_rx_chars(struct uart_port *port)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(port, ch, regs))
+ if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
uart_insert_char(port, rsr, UART01x_RSR_OE, ch, flag);
@@ -227,7 +222,7 @@ static void pl010_modem_status(struct uart_port *port)
wake_up_interruptible(&uap->port.info->delta_msr_wait);
}
-static irqreturn_t pl010_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pl010_int(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
@@ -239,11 +234,7 @@ static irqreturn_t pl010_int(int irq, void *dev_id, struct pt_regs *regs)
if (status) {
do {
if (status & (UART010_IIR_RTIS | UART010_IIR_RIS))
-#ifdef SUPPORT_SYSRQ
- pl010_rx_chars(port, regs);
-#else
pl010_rx_chars(port);
-#endif
if (status & UART010_IIR_MIS)
pl010_modem_status(port);
if (status & UART010_IIR_TIS)
diff --git a/drivers/serial/amba-pl011.c b/drivers/serial/amba-pl011.c
index a8d7124e84a1..d503625730df 100644
--- a/drivers/serial/amba-pl011.c
+++ b/drivers/serial/amba-pl011.c
@@ -107,12 +107,7 @@ static void pl011_enable_ms(struct uart_port *port)
writew(uap->im, uap->port.membase + UART011_IMSC);
}
-static void
-#ifdef SUPPORT_SYSRQ
-pl011_rx_chars(struct uart_amba_port *uap, struct pt_regs *regs)
-#else
-pl011_rx_chars(struct uart_amba_port *uap)
-#endif
+static void pl011_rx_chars(struct uart_amba_port *uap)
{
struct tty_struct *tty = uap->port.info->tty;
unsigned int status, ch, flag, max_count = 256;
@@ -150,7 +145,7 @@ pl011_rx_chars(struct uart_amba_port *uap)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&uap->port, ch & 255, regs))
+ if (uart_handle_sysrq_char(&uap->port, ch & 255))
goto ignore_char;
uart_insert_char(&uap->port, ch, UART011_DR_OE, ch, flag);
@@ -218,7 +213,7 @@ static void pl011_modem_status(struct uart_amba_port *uap)
wake_up_interruptible(&uap->port.info->delta_msr_wait);
}
-static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pl011_int(int irq, void *dev_id)
{
struct uart_amba_port *uap = dev_id;
unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
@@ -234,11 +229,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id, struct pt_regs *regs)
uap->port.membase + UART011_ICR);
if (status & (UART011_RTIS|UART011_RXIS))
-#ifdef SUPPORT_SYSRQ
- pl011_rx_chars(uap, regs);
-#else
pl011_rx_chars(uap);
-#endif
if (status & (UART011_DSRMIS|UART011_DCDMIS|
UART011_CTSMIS|UART011_RIMIS))
pl011_modem_status(uap);
diff --git a/drivers/serial/at91_serial.c b/drivers/serial/at91_serial.c
deleted file mode 100644
index 54c6b2adf7b7..000000000000
--- a/drivers/serial/at91_serial.c
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- * linux/drivers/char/at91_serial.c
- *
- * Driver for Atmel AT91RM9200 Serial ports
- * Copyright (C) 2003 Rick Bronson
- *
- * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
- * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
- *
- * 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/tty.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/serial.h>
-#include <linux/clk.h>
-#include <linux/console.h>
-#include <linux/sysrq.h>
-#include <linux/tty_flip.h>
-#include <linux/platform_device.h>
-
-#include <asm/io.h>
-
-#include <asm/arch/at91rm9200_usart.h>
-#include <asm/arch/at91rm9200_pdc.h>
-#include <asm/mach/serial_at91.h>
-#include <asm/arch/board.h>
-#include <asm/arch/system.h>
-#include <asm/arch/gpio.h>
-
-#if defined(CONFIG_SERIAL_AT91_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/serial_core.h>
-
-#ifdef CONFIG_SERIAL_AT91_TTYAT
-
-/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we
- * should coexist with the 8250 driver, such as if we have an external 16C550
- * UART. */
-#define SERIAL_AT91_MAJOR 204
-#define MINOR_START 154
-#define AT91_DEVICENAME "ttyAT"
-
-#else
-
-/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port
- * name, but it is legally reserved for the 8250 driver. */
-#define SERIAL_AT91_MAJOR TTY_MAJOR
-#define MINOR_START 64
-#define AT91_DEVICENAME "ttyS"
-
-#endif
-
-#define AT91_ISR_PASS_LIMIT 256
-
-#define UART_PUT_CR(port,v) writel(v, (port)->membase + AT91_US_CR)
-#define UART_GET_MR(port) readl((port)->membase + AT91_US_MR)
-#define UART_PUT_MR(port,v) writel(v, (port)->membase + AT91_US_MR)
-#define UART_PUT_IER(port,v) writel(v, (port)->membase + AT91_US_IER)
-#define UART_PUT_IDR(port,v) writel(v, (port)->membase + AT91_US_IDR)
-#define UART_GET_IMR(port) readl((port)->membase + AT91_US_IMR)
-#define UART_GET_CSR(port) readl((port)->membase + AT91_US_CSR)
-#define UART_GET_CHAR(port) readl((port)->membase + AT91_US_RHR)
-#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + AT91_US_THR)
-#define UART_GET_BRGR(port) readl((port)->membase + AT91_US_BRGR)
-#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + AT91_US_BRGR)
-#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + AT91_US_RTOR)
-
-// #define UART_GET_CR(port) readl((port)->membase + AT91_US_CR) // is write-only
-
- /* PDC registers */
-#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + AT91_PDC_PTCR)
-#define UART_GET_PTSR(port) readl((port)->membase + AT91_PDC_PTSR)
-
-#define UART_PUT_RPR(port,v) writel(v, (port)->membase + AT91_PDC_RPR)
-#define UART_GET_RPR(port) readl((port)->membase + AT91_PDC_RPR)
-#define UART_PUT_RCR(port,v) writel(v, (port)->membase + AT91_PDC_RCR)
-#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + AT91_PDC_RNPR)
-#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + AT91_PDC_RNCR)
-
-#define UART_PUT_TPR(port,v) writel(v, (port)->membase + AT91_PDC_TPR)
-#define UART_PUT_TCR(port,v) writel(v, (port)->membase + AT91_PDC_TCR)
-//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + AT91_PDC_TNPR)
-//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + AT91_PDC_TNCR)
-
-static int (*at91_open)(struct uart_port *);
-static void (*at91_close)(struct uart_port *);
-
-/*
- * We wrap our port structure around the generic uart_port.
- */
-struct at91_uart_port {
- struct uart_port uart; /* uart */
- struct clk *clk; /* uart clock */
- unsigned short suspended; /* is port suspended? */
-};
-
-static struct at91_uart_port at91_ports[AT91_NR_UART];
-
-#ifdef SUPPORT_SYSRQ
-static struct console at91_console;
-#endif
-
-/*
- * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
- */
-static u_int at91_tx_empty(struct uart_port *port)
-{
- return (UART_GET_CSR(port) & AT91_US_TXEMPTY) ? TIOCSER_TEMT : 0;
-}
-
-/*
- * Set state of the modem control output lines
- */
-static void at91_set_mctrl(struct uart_port *port, u_int mctrl)
-{
- unsigned int control = 0;
- unsigned int mode;
-
- if (arch_identify() == ARCH_ID_AT91RM9200) {
- /*
- * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
- * We need to drive the pin manually.
- */
- if (port->mapbase == AT91_BASE_US0) {
- if (mctrl & TIOCM_RTS)
- at91_set_gpio_value(AT91_PIN_PA21, 0);
- else
- at91_set_gpio_value(AT91_PIN_PA21, 1);
- }
- }
-
- if (mctrl & TIOCM_RTS)
- control |= AT91_US_RTSEN;
- else
- control |= AT91_US_RTSDIS;
-
- if (mctrl & TIOCM_DTR)
- control |= AT91_US_DTREN;
- else
- control |= AT91_US_DTRDIS;
-
- UART_PUT_CR(port, control);
-
- /* Local loopback mode? */
- mode = UART_GET_MR(port) & ~AT91_US_CHMODE;
- if (mctrl & TIOCM_LOOP)
- mode |= AT91_US_CHMODE_LOC_LOOP;
- else
- mode |= AT91_US_CHMODE_NORMAL;
- UART_PUT_MR(port, mode);
-}
-
-/*
- * Get state of the modem control input lines
- */
-static u_int at91_get_mctrl(struct uart_port *port)
-{
- unsigned int status, ret = 0;
-
- status = UART_GET_CSR(port);
-
- /*
- * The control signals are active low.
- */
- if (!(status & AT91_US_DCD))
- ret |= TIOCM_CD;
- if (!(status & AT91_US_CTS))
- ret |= TIOCM_CTS;
- if (!(status & AT91_US_DSR))
- ret |= TIOCM_DSR;
- if (!(status & AT91_US_RI))
- ret |= TIOCM_RI;
-
- return ret;
-}
-
-/*
- * Stop transmitting.
- */
-static void at91_stop_tx(struct uart_port *port)
-{
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
- UART_PUT_IDR(port, AT91_US_TXRDY);
-}
-
-/*
- * Start transmitting.
- */
-static void at91_start_tx(struct uart_port *port)
-{
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
- UART_PUT_IER(port, AT91_US_TXRDY);
-}
-
-/*
- * Stop receiving - port is in process of being closed.
- */
-static void at91_stop_rx(struct uart_port *port)
-{
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
- UART_PUT_IDR(port, AT91_US_RXRDY);
-}
-
-/*
- * Enable modem status interrupts
- */
-static void at91_enable_ms(struct uart_port *port)
-{
- UART_PUT_IER(port, AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC);
-}
-
-/*
- * Control the transmission of a break signal
- */
-static void at91_break_ctl(struct uart_port *port, int break_state)
-{
- if (break_state != 0)
- UART_PUT_CR(port, AT91_US_STTBRK); /* start break */
- else
- UART_PUT_CR(port, AT91_US_STPBRK); /* stop break */
-}
-
-/*
- * Characters received (called from interrupt handler)
- */
-static void at91_rx_chars(struct uart_port *port, struct pt_regs *regs)
-{
- struct tty_struct *tty = port->info->tty;
- unsigned int status, ch, flg;
-
- status = UART_GET_CSR(port);
- while (status & AT91_US_RXRDY) {
- ch = UART_GET_CHAR(port);
-
- port->icount.rx++;
-
- flg = TTY_NORMAL;
-
- /*
- * note that the error handling code is
- * out of the main execution path
- */
- if (unlikely(status & (AT91_US_PARE | AT91_US_FRAME | AT91_US_OVRE | AT91_US_RXBRK))) {
- UART_PUT_CR(port, AT91_US_RSTSTA); /* clear error */
- if (status & AT91_US_RXBRK) {
- status &= ~(AT91_US_PARE | AT91_US_FRAME); /* ignore side-effect */
- port->icount.brk++;
- if (uart_handle_break(port))
- goto ignore_char;
- }
- if (status & AT91_US_PARE)
- port->icount.parity++;
- if (status & AT91_US_FRAME)
- port->icount.frame++;
- if (status & AT91_US_OVRE)
- port->icount.overrun++;
-
- status &= port->read_status_mask;
-
- if (status & AT91_US_RXBRK)
- flg = TTY_BREAK;
- else if (status & AT91_US_PARE)
- flg = TTY_PARITY;
- else if (status & AT91_US_FRAME)
- flg = TTY_FRAME;
- }
-
- if (uart_handle_sysrq_char(port, ch, regs))
- goto ignore_char;
-
- uart_insert_char(port, status, AT91_US_OVRE, ch, flg);
-
- ignore_char:
- status = UART_GET_CSR(port);
- }
-
- tty_flip_buffer_push(tty);
-}
-
-/*
- * Transmit characters (called from interrupt handler)
- */
-static void at91_tx_chars(struct uart_port *port)
-{
- struct circ_buf *xmit = &port->info->xmit;
-
- if (port->x_char) {
- UART_PUT_CHAR(port, port->x_char);
- port->icount.tx++;
- port->x_char = 0;
- return;
- }
- if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
- at91_stop_tx(port);
- return;
- }
-
- while (UART_GET_CSR(port) & AT91_US_TXRDY) {
- UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
- xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
- port->icount.tx++;
- if (uart_circ_empty(xmit))
- break;
- }
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-
- if (uart_circ_empty(xmit))
- at91_stop_tx(port);
-}
-
-/*
- * Interrupt handler
- */
-static irqreturn_t at91_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct uart_port *port = dev_id;
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
- unsigned int status, pending, pass_counter = 0;
-
- status = UART_GET_CSR(port);
- pending = status & UART_GET_IMR(port);
- while (pending) {
- /* Interrupt receive */
- if (pending & AT91_US_RXRDY)
- at91_rx_chars(port, regs);
-
- // TODO: All reads to CSR will clear these interrupts!
- if (pending & AT91_US_RIIC) port->icount.rng++;
- if (pending & AT91_US_DSRIC) port->icount.dsr++;
- if (pending & AT91_US_DCDIC)
- uart_handle_dcd_change(port, !(status & AT91_US_DCD));
- if (pending & AT91_US_CTSIC)
- uart_handle_cts_change(port, !(status & AT91_US_CTS));
- if (pending & (AT91_US_RIIC | AT91_US_DSRIC | AT91_US_DCDIC | AT91_US_CTSIC))
- wake_up_interruptible(&port->info->delta_msr_wait);
-
- /* Interrupt transmit */
- if (pending & AT91_US_TXRDY)
- at91_tx_chars(port);
-
- if (pass_counter++ > AT91_ISR_PASS_LIMIT)
- break;
-
- status = UART_GET_CSR(port);
- pending = status & UART_GET_IMR(port);
- }
- return IRQ_HANDLED;
-}
-
-/*
- * Perform initialization and enable port for reception
- */
-static int at91_startup(struct uart_port *port)
-{
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
- int retval;
-
- /*
- * Ensure that no interrupts are enabled otherwise when
- * request_irq() is called we could get stuck trying to
- * handle an unexpected interrupt
- */
- UART_PUT_IDR(port, -1);
-
- /*
- * Allocate the IRQ
- */
- retval = request_irq(port->irq, at91_interrupt, IRQF_SHARED, "at91_serial", port);
- if (retval) {
- printk("at91_serial: at91_startup - Can't get irq\n");
- return retval;
- }
-
- /*
- * If there is a specific "open" function (to register
- * control line interrupts)
- */
- if (at91_open) {
- retval = at91_open(port);
- if (retval) {
- free_irq(port->irq, port);
- return retval;
- }
- }
-
- /*
- * Finally, enable the serial port
- */
- UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
- UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN); /* enable xmit & rcvr */
-
- UART_PUT_IER(port, AT91_US_RXRDY); /* enable receive only */
-
- return 0;
-}
-
-/*
- * Disable the port
- */
-static void at91_shutdown(struct uart_port *port)
-{
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
- /*
- * Disable all interrupts, port and break condition.
- */
- UART_PUT_CR(port, AT91_US_RSTSTA);
- UART_PUT_IDR(port, -1);
-
- /*
- * Free the interrupt
- */
- free_irq(port->irq, port);
-
- /*
- * If there is a specific "close" function (to unregister
- * control line interrupts)
- */
- if (at91_close)
- at91_close(port);
-}
-
-/*
- * Power / Clock management.
- */
-static void at91_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
-{
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
- switch (state) {
- case 0:
- /*
- * Enable the peripheral clock for this serial port.
- * This is called on uart_open() or a resume event.
- */
- clk_enable(at91_port->clk);
- break;
- case 3:
- /*
- * Disable the peripheral clock for this serial port.
- * This is called on uart_close() or a suspend event.
- */
- clk_disable(at91_port->clk);
- break;
- default:
- printk(KERN_ERR "at91_serial: unknown pm %d\n", state);
- }
-}
-
-/*
- * Change the port parameters
- */
-static void at91_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
-{
- unsigned long flags;
- unsigned int mode, imr, quot, baud;
-
- baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
- quot = uart_get_divisor(port, baud);
-
- /* Get current mode register */
- mode = UART_GET_MR(port) & ~(AT91_US_CHRL | AT91_US_NBSTOP | AT91_US_PAR);
-
- /* byte size */
- switch (termios->c_cflag & CSIZE) {
- case CS5:
- mode |= AT91_US_CHRL_5;
- break;
- case CS6:
- mode |= AT91_US_CHRL_6;
- break;
- case CS7:
- mode |= AT91_US_CHRL_7;
- break;
- default:
- mode |= AT91_US_CHRL_8;
- break;
- }
-
- /* stop bits */
- if (termios->c_cflag & CSTOPB)
- mode |= AT91_US_NBSTOP_2;
-
- /* parity */
- if (termios->c_cflag & PARENB) {
- if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */
- if (termios->c_cflag & PARODD)
- mode |= AT91_US_PAR_MARK;
- else
- mode |= AT91_US_PAR_SPACE;
- }
- else if (termios->c_cflag & PARODD)
- mode |= AT91_US_PAR_ODD;
- else
- mode |= AT91_US_PAR_EVEN;
- }
- else
- mode |= AT91_US_PAR_NONE;
-
- spin_lock_irqsave(&port->lock, flags);
-
- port->read_status_mask = AT91_US_OVRE;
- if (termios->c_iflag & INPCK)
- port->read_status_mask |= (AT91_US_FRAME | AT91_US_PARE);
- if (termios->c_iflag & (BRKINT | PARMRK))
- port->read_status_mask |= AT91_US_RXBRK;
-
- /*
- * Characters to ignore
- */
- port->ignore_status_mask = 0;
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= (AT91_US_FRAME | AT91_US_PARE);
- if (termios->c_iflag & IGNBRK) {
- port->ignore_status_mask |= AT91_US_RXBRK;
- /*
- * If we're ignoring parity and break indicators,
- * ignore overruns too (for real raw support).
- */
- if (termios->c_iflag & IGNPAR)
- port->ignore_status_mask |= AT91_US_OVRE;
- }
-
- // TODO: Ignore all characters if CREAD is set.
-
- /* update the per-port timeout */
- uart_update_timeout(port, termios->c_cflag, baud);
-
- /* disable interrupts and drain transmitter */
- imr = UART_GET_IMR(port); /* get interrupt mask */
- UART_PUT_IDR(port, -1); /* disable all interrupts */
- while (!(UART_GET_CSR(port) & AT91_US_TXEMPTY)) { barrier(); }
-
- /* disable receiver and transmitter */
- UART_PUT_CR(port, AT91_US_TXDIS | AT91_US_RXDIS);
-
- /* set the parity, stop bits and data size */
- UART_PUT_MR(port, mode);
-
- /* set the baud rate */
- UART_PUT_BRGR(port, quot);
- UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
- UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN);
-
- /* restore interrupts */
- UART_PUT_IER(port, imr);
-
- /* CTS flow-control and modem-status interrupts */
- if (UART_ENABLE_MS(port, termios->c_cflag))
- port->ops->enable_ms(port);
-
- spin_unlock_irqrestore(&port->lock, flags);
-}
-
-/*
- * Return string describing the specified port
- */
-static const char *at91_type(struct uart_port *port)
-{
- return (port->type == PORT_AT91) ? "AT91_SERIAL" : NULL;
-}
-
-/*
- * Release the memory region(s) being used by 'port'.
- */
-static void at91_release_port(struct uart_port *port)
-{
- struct platform_device *pdev = to_platform_device(port->dev);
- int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
- release_mem_region(port->mapbase, size);
-
- if (port->flags & UPF_IOREMAP) {
- iounmap(port->membase);
- port->membase = NULL;
- }
-}
-
-/*
- * Request the memory region(s) being used by 'port'.
- */
-static int at91_request_port(struct uart_port *port)
-{
- struct platform_device *pdev = to_platform_device(port->dev);
- int size = pdev->resource[0].end - pdev->resource[0].start + 1;
-
- if (!request_mem_region(port->mapbase, size, "at91_serial"))
- return -EBUSY;
-
- if (port->flags & UPF_IOREMAP) {
- port->membase = ioremap(port->mapbase, size);
- if (port->membase == NULL) {
- release_mem_region(port->mapbase, size);
- return -ENOMEM;
- }
- }
-
- return 0;
-}
-
-/*
- * Configure/autoconfigure the port.
- */
-static void at91_config_port(struct uart_port *port, int flags)
-{
- if (flags & UART_CONFIG_TYPE) {
- port->type = PORT_AT91;
- at91_request_port(port);
- }
-}
-
-/*
- * Verify the new serial_struct (for TIOCSSERIAL).
- */
-static int at91_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
- int ret = 0;
- if (ser->type != PORT_UNKNOWN && ser->type != PORT_AT91)
- ret = -EINVAL;
- if (port->irq != ser->irq)
- ret = -EINVAL;
- if (ser->io_type != SERIAL_IO_MEM)
- ret = -EINVAL;
- if (port->uartclk / 16 != ser->baud_base)
- ret = -EINVAL;
- if ((void *)port->mapbase != ser->iomem_base)
- ret = -EINVAL;
- if (port->iobase != ser->port)
- ret = -EINVAL;
- if (ser->hub6 != 0)
- ret = -EINVAL;
- return ret;
-}
-
-static struct uart_ops at91_pops = {
- .tx_empty = at91_tx_empty,
- .set_mctrl = at91_set_mctrl,
- .get_mctrl = at91_get_mctrl,
- .stop_tx = at91_stop_tx,
- .start_tx = at91_start_tx,
- .stop_rx = at91_stop_rx,
- .enable_ms = at91_enable_ms,
- .break_ctl = at91_break_ctl,
- .startup = at91_startup,
- .shutdown = at91_shutdown,
- .set_termios = at91_set_termios,
- .type = at91_type,
- .release_port = at91_release_port,
- .request_port = at91_request_port,
- .config_port = at91_config_port,
- .verify_port = at91_verify_port,
- .pm = at91_serial_pm,
-};
-
-/*
- * Configure the port from the platform device resource info.
- */
-static void __devinit at91_init_port(struct at91_uart_port *at91_port, struct platform_device *pdev)
-{
- struct uart_port *port = &at91_port->uart;
- struct at91_uart_data *data = pdev->dev.platform_data;
-
- port->iotype = UPIO_MEM;
- port->flags = UPF_BOOT_AUTOCONF;
- port->ops = &at91_pops;
- port->fifosize = 1;
- port->line = pdev->id;
- port->dev = &pdev->dev;
-
- port->mapbase = pdev->resource[0].start;
- port->irq = pdev->resource[1].start;
-
- if (port->mapbase == AT91_VA_BASE_SYS + AT91_DBGU) /* Part of system perpherals - already mapped */
- port->membase = (void __iomem *) port->mapbase;
- else {
- port->flags |= UPF_IOREMAP;
- port->membase = NULL;
- }
-
- if (!at91_port->clk) { /* for console, the clock could already be configured */
- at91_port->clk = clk_get(&pdev->dev, "usart");
- clk_enable(at91_port->clk);
- port->uartclk = clk_get_rate(at91_port->clk);
- }
-}
-
-/*
- * Register board-specific modem-control line handlers.
- */
-void __init at91_register_uart_fns(struct at91_port_fns *fns)
-{
- if (fns->enable_ms)
- at91_pops.enable_ms = fns->enable_ms;
- if (fns->get_mctrl)
- at91_pops.get_mctrl = fns->get_mctrl;
- if (fns->set_mctrl)
- at91_pops.set_mctrl = fns->set_mctrl;
- at91_open = fns->open;
- at91_close = fns->close;
- at91_pops.pm = fns->pm;
- at91_pops.set_wake = fns->set_wake;
-}
-
-
-#ifdef CONFIG_SERIAL_AT91_CONSOLE
-static void at91_console_putchar(struct uart_port *port, int ch)
-{
- while (!(UART_GET_CSR(port) & AT91_US_TXRDY))
- barrier();
- UART_PUT_CHAR(port, ch);
-}
-
-/*
- * Interrupts are disabled on entering
- */
-static void at91_console_write(struct console *co, const char *s, u_int count)
-{
- struct uart_port *port = &at91_ports[co->index].uart;
- unsigned int status, imr;
-
- /*
- * First, save IMR and then disable interrupts
- */
- imr = UART_GET_IMR(port); /* get interrupt mask */
- UART_PUT_IDR(port, AT91_US_RXRDY | AT91_US_TXRDY);
-
- uart_console_write(port, s, count, at91_console_putchar);
-
- /*
- * Finally, wait for transmitter to become empty
- * and restore IMR
- */
- do {
- status = UART_GET_CSR(port);
- } while (!(status & AT91_US_TXRDY));
- UART_PUT_IER(port, imr); /* set interrupts back the way they were */
-}
-
-/*
- * If the port was already initialised (eg, by a boot loader), try to determine
- * the current setup.
- */
-static void __init at91_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
-{
- unsigned int mr, quot;
-
-// TODO: CR is a write-only register
-// unsigned int cr;
-//
-// cr = UART_GET_CR(port) & (AT91_US_RXEN | AT91_US_TXEN);
-// if (cr == (AT91_US_RXEN | AT91_US_TXEN)) {
-// /* ok, the port was enabled */
-// }
-
- mr = UART_GET_MR(port) & AT91_US_CHRL;
- if (mr == AT91_US_CHRL_8)
- *bits = 8;
- else
- *bits = 7;
-
- mr = UART_GET_MR(port) & AT91_US_PAR;
- if (mr == AT91_US_PAR_EVEN)
- *parity = 'e';
- else if (mr == AT91_US_PAR_ODD)
- *parity = 'o';
-
- quot = UART_GET_BRGR(port);
- *baud = port->uartclk / (16 * (quot));
-}
-
-static int __init at91_console_setup(struct console *co, char *options)
-{
- struct uart_port *port = &at91_ports[co->index].uart;
- int baud = 115200;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- if (port->membase == 0) /* Port not initialized yet - delay setup */
- return -ENODEV;
-
- UART_PUT_IDR(port, -1); /* disable interrupts */
- UART_PUT_CR(port, AT91_US_RSTSTA | AT91_US_RSTRX);
- UART_PUT_CR(port, AT91_US_TXEN | AT91_US_RXEN);
-
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
- else
- at91_console_get_options(port, &baud, &parity, &bits);
-
- return uart_set_options(port, co, baud, parity, bits, flow);
-}
-
-static struct uart_driver at91_uart;
-
-static struct console at91_console = {
- .name = AT91_DEVICENAME,
- .write = at91_console_write,
- .device = uart_console_device,
- .setup = at91_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &at91_uart,
-};
-
-#define AT91_CONSOLE_DEVICE &at91_console
-
-/*
- * Early console initialization (before VM subsystem initialized).
- */
-static int __init at91_console_init(void)
-{
- if (at91_default_console_device) {
- add_preferred_console(AT91_DEVICENAME, at91_default_console_device->id, NULL);
- at91_init_port(&(at91_ports[at91_default_console_device->id]), at91_default_console_device);
- register_console(&at91_console);
- }
-
- return 0;
-}
-console_initcall(at91_console_init);
-
-/*
- * Late console initialization.
- */
-static int __init at91_late_console_init(void)
-{
- if (at91_default_console_device && !(at91_console.flags & CON_ENABLED))
- register_console(&at91_console);
-
- return 0;
-}
-core_initcall(at91_late_console_init);
-
-#else
-#define AT91_CONSOLE_DEVICE NULL
-#endif
-
-static struct uart_driver at91_uart = {
- .owner = THIS_MODULE,
- .driver_name = "at91_serial",
- .dev_name = AT91_DEVICENAME,
- .major = SERIAL_AT91_MAJOR,
- .minor = MINOR_START,
- .nr = AT91_NR_UART,
- .cons = AT91_CONSOLE_DEVICE,
-};
-
-#ifdef CONFIG_PM
-static int at91_serial_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct uart_port *port = platform_get_drvdata(pdev);
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
- if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
- enable_irq_wake(port->irq);
- else {
- disable_irq_wake(port->irq);
- uart_suspend_port(&at91_uart, port);
- at91_port->suspended = 1;
- }
-
- return 0;
-}
-
-static int at91_serial_resume(struct platform_device *pdev)
-{
- struct uart_port *port = platform_get_drvdata(pdev);
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
-
- if (at91_port->suspended) {
- uart_resume_port(&at91_uart, port);
- at91_port->suspended = 0;
- }
-
- return 0;
-}
-#else
-#define at91_serial_suspend NULL
-#define at91_serial_resume NULL
-#endif
-
-static int __devinit at91_serial_probe(struct platform_device *pdev)
-{
- struct at91_uart_port *port;
- int ret;
-
- port = &at91_ports[pdev->id];
- at91_init_port(port, pdev);
-
- ret = uart_add_one_port(&at91_uart, &port->uart);
- if (!ret) {
- device_init_wakeup(&pdev->dev, 1);
- platform_set_drvdata(pdev, port);
- }
-
- return ret;
-}
-
-static int __devexit at91_serial_remove(struct platform_device *pdev)
-{
- struct uart_port *port = platform_get_drvdata(pdev);
- struct at91_uart_port *at91_port = (struct at91_uart_port *) port;
- int ret = 0;
-
- clk_disable(at91_port->clk);
- clk_put(at91_port->clk);
-
- device_init_wakeup(&pdev->dev, 0);
- platform_set_drvdata(pdev, NULL);
-
- if (port) {
- ret = uart_remove_one_port(&at91_uart, port);
- kfree(port);
- }
-
- return ret;
-}
-
-static struct platform_driver at91_serial_driver = {
- .probe = at91_serial_probe,
- .remove = __devexit_p(at91_serial_remove),
- .suspend = at91_serial_suspend,
- .resume = at91_serial_resume,
- .driver = {
- .name = "at91_usart",
- .owner = THIS_MODULE,
- },
-};
-
-static int __init at91_serial_init(void)
-{
- int ret;
-
- ret = uart_register_driver(&at91_uart);
- if (ret)
- return ret;
-
- ret = platform_driver_register(&at91_serial_driver);
- if (ret)
- uart_unregister_driver(&at91_uart);
-
- return ret;
-}
-
-static void __exit at91_serial_exit(void)
-{
- platform_driver_unregister(&at91_serial_driver);
- uart_unregister_driver(&at91_uart);
-}
-
-module_init(at91_serial_init);
-module_exit(at91_serial_exit);
-
-MODULE_AUTHOR("Rick Bronson");
-MODULE_DESCRIPTION("AT91 generic serial port driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c
new file mode 100644
index 000000000000..391a1f4167a4
--- /dev/null
+++ b/drivers/serial/atmel_serial.c
@@ -0,0 +1,992 @@
+/*
+ * linux/drivers/char/at91_serial.c
+ *
+ * Driver for Atmel AT91 / AT32 Serial ports
+ * Copyright (C) 2003 Rick Bronson
+ *
+ * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
+ * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
+ *
+ * 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/tty.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/sysrq.h>
+#include <linux/tty_flip.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+
+#include <asm/arch/at91rm9200_pdc.h>
+#include <asm/mach/serial_at91.h>
+#include <asm/arch/board.h>
+#ifdef CONFIG_ARM
+#include <asm/arch/system.h>
+#include <asm/arch/gpio.h>
+#endif
+
+#include "atmel_serial.h"
+
+#if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/serial_core.h>
+
+#ifdef CONFIG_SERIAL_ATMEL_TTYAT
+
+/* Use device name ttyAT, major 204 and minor 154-169. This is necessary if we
+ * should coexist with the 8250 driver, such as if we have an external 16C550
+ * UART. */
+#define SERIAL_ATMEL_MAJOR 204
+#define MINOR_START 154
+#define ATMEL_DEVICENAME "ttyAT"
+
+#else
+
+/* Use device name ttyS, major 4, minor 64-68. This is the usual serial port
+ * name, but it is legally reserved for the 8250 driver. */
+#define SERIAL_ATMEL_MAJOR TTY_MAJOR
+#define MINOR_START 64
+#define ATMEL_DEVICENAME "ttyS"
+
+#endif
+
+#define ATMEL_ISR_PASS_LIMIT 256
+
+#define UART_PUT_CR(port,v) writel(v, (port)->membase + ATMEL_US_CR)
+#define UART_GET_MR(port) readl((port)->membase + ATMEL_US_MR)
+#define UART_PUT_MR(port,v) writel(v, (port)->membase + ATMEL_US_MR)
+#define UART_PUT_IER(port,v) writel(v, (port)->membase + ATMEL_US_IER)
+#define UART_PUT_IDR(port,v) writel(v, (port)->membase + ATMEL_US_IDR)
+#define UART_GET_IMR(port) readl((port)->membase + ATMEL_US_IMR)
+#define UART_GET_CSR(port) readl((port)->membase + ATMEL_US_CSR)
+#define UART_GET_CHAR(port) readl((port)->membase + ATMEL_US_RHR)
+#define UART_PUT_CHAR(port,v) writel(v, (port)->membase + ATMEL_US_THR)
+#define UART_GET_BRGR(port) readl((port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_BRGR(port,v) writel(v, (port)->membase + ATMEL_US_BRGR)
+#define UART_PUT_RTOR(port,v) writel(v, (port)->membase + ATMEL_US_RTOR)
+
+// #define UART_GET_CR(port) readl((port)->membase + ATMEL_US_CR) // is write-only
+
+ /* PDC registers */
+#define UART_PUT_PTCR(port,v) writel(v, (port)->membase + ATMEL_PDC_PTCR)
+#define UART_GET_PTSR(port) readl((port)->membase + ATMEL_PDC_PTSR)
+
+#define UART_PUT_RPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RPR)
+#define UART_GET_RPR(port) readl((port)->membase + ATMEL_PDC_RPR)
+#define UART_PUT_RCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RCR)
+#define UART_PUT_RNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNPR)
+#define UART_PUT_RNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_RNCR)
+
+#define UART_PUT_TPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TPR)
+#define UART_PUT_TCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TCR)
+//#define UART_PUT_TNPR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNPR)
+//#define UART_PUT_TNCR(port,v) writel(v, (port)->membase + ATMEL_PDC_TNCR)
+
+static int (*atmel_open_hook)(struct uart_port *);
+static void (*atmel_close_hook)(struct uart_port *);
+
+/*
+ * We wrap our port structure around the generic uart_port.
+ */
+struct atmel_uart_port {
+ struct uart_port uart; /* uart */
+ struct clk *clk; /* uart clock */
+ unsigned short suspended; /* is port suspended? */
+};
+
+static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
+
+#ifdef SUPPORT_SYSRQ
+static struct console atmel_console;
+#endif
+
+/*
+ * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty.
+ */
+static u_int atmel_tx_empty(struct uart_port *port)
+{
+ return (UART_GET_CSR(port) & ATMEL_US_TXEMPTY) ? TIOCSER_TEMT : 0;
+}
+
+/*
+ * Set state of the modem control output lines
+ */
+static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
+{
+ unsigned int control = 0;
+ unsigned int mode;
+
+#ifdef CONFIG_ARM
+ if (arch_identify() == ARCH_ID_AT91RM9200) {
+ /*
+ * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21.
+ * We need to drive the pin manually.
+ */
+ if (port->mapbase == AT91RM9200_BASE_US0) {
+ if (mctrl & TIOCM_RTS)
+ at91_set_gpio_value(AT91_PIN_PA21, 0);
+ else
+ at91_set_gpio_value(AT91_PIN_PA21, 1);
+ }
+ }
+#endif
+
+ if (mctrl & TIOCM_RTS)
+ control |= ATMEL_US_RTSEN;
+ else
+ control |= ATMEL_US_RTSDIS;
+
+ if (mctrl & TIOCM_DTR)
+ control |= ATMEL_US_DTREN;
+ else
+ control |= ATMEL_US_DTRDIS;
+
+ UART_PUT_CR(port, control);
+
+ /* Local loopback mode? */
+ mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+ if (mctrl & TIOCM_LOOP)
+ mode |= ATMEL_US_CHMODE_LOC_LOOP;
+ else
+ mode |= ATMEL_US_CHMODE_NORMAL;
+ UART_PUT_MR(port, mode);
+}
+
+/*
+ * Get state of the modem control input lines
+ */
+static u_int atmel_get_mctrl(struct uart_port *port)
+{
+ unsigned int status, ret = 0;
+
+ status = UART_GET_CSR(port);
+
+ /*
+ * The control signals are active low.
+ */
+ if (!(status & ATMEL_US_DCD))
+ ret |= TIOCM_CD;
+ if (!(status & ATMEL_US_CTS))
+ ret |= TIOCM_CTS;
+ if (!(status & ATMEL_US_DSR))
+ ret |= TIOCM_DSR;
+ if (!(status & ATMEL_US_RI))
+ ret |= TIOCM_RI;
+
+ return ret;
+}
+
+/*
+ * Stop transmitting.
+ */
+static void atmel_stop_tx(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+ UART_PUT_IDR(port, ATMEL_US_TXRDY);
+}
+
+/*
+ * Start transmitting.
+ */
+static void atmel_start_tx(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+ UART_PUT_IER(port, ATMEL_US_TXRDY);
+}
+
+/*
+ * Stop receiving - port is in process of being closed.
+ */
+static void atmel_stop_rx(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+ UART_PUT_IDR(port, ATMEL_US_RXRDY);
+}
+
+/*
+ * Enable modem status interrupts
+ */
+static void atmel_enable_ms(struct uart_port *port)
+{
+ UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC);
+}
+
+/*
+ * Control the transmission of a break signal
+ */
+static void atmel_break_ctl(struct uart_port *port, int break_state)
+{
+ if (break_state != 0)
+ UART_PUT_CR(port, ATMEL_US_STTBRK); /* start break */
+ else
+ UART_PUT_CR(port, ATMEL_US_STPBRK); /* stop break */
+}
+
+/*
+ * Characters received (called from interrupt handler)
+ */
+static void atmel_rx_chars(struct uart_port *port)
+{
+ struct tty_struct *tty = port->info->tty;
+ unsigned int status, ch, flg;
+
+ status = UART_GET_CSR(port);
+ while (status & ATMEL_US_RXRDY) {
+ ch = UART_GET_CHAR(port);
+
+ port->icount.rx++;
+
+ flg = TTY_NORMAL;
+
+ /*
+ * note that the error handling code is
+ * out of the main execution path
+ */
+ if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) {
+ UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */
+ if (status & ATMEL_US_RXBRK) {
+ status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */
+ port->icount.brk++;
+ if (uart_handle_break(port))
+ goto ignore_char;
+ }
+ if (status & ATMEL_US_PARE)
+ port->icount.parity++;
+ if (status & ATMEL_US_FRAME)
+ port->icount.frame++;
+ if (status & ATMEL_US_OVRE)
+ port->icount.overrun++;
+
+ status &= port->read_status_mask;
+
+ if (status & ATMEL_US_RXBRK)
+ flg = TTY_BREAK;
+ else if (status & ATMEL_US_PARE)
+ flg = TTY_PARITY;
+ else if (status & ATMEL_US_FRAME)
+ flg = TTY_FRAME;
+ }
+
+ if (uart_handle_sysrq_char(port, ch))
+ goto ignore_char;
+
+ uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg);
+
+ ignore_char:
+ status = UART_GET_CSR(port);
+ }
+
+ tty_flip_buffer_push(tty);
+}
+
+/*
+ * Transmit characters (called from interrupt handler)
+ */
+static void atmel_tx_chars(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->info->xmit;
+
+ if (port->x_char) {
+ UART_PUT_CHAR(port, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ atmel_stop_tx(port);
+ return;
+ }
+
+ while (UART_GET_CSR(port) & ATMEL_US_TXRDY) {
+ UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ atmel_stop_tx(port);
+}
+
+/*
+ * Interrupt handler
+ */
+static irqreturn_t atmel_interrupt(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+ unsigned int status, pending, pass_counter = 0;
+
+ status = UART_GET_CSR(port);
+ pending = status & UART_GET_IMR(port);
+ while (pending) {
+ /* Interrupt receive */
+ if (pending & ATMEL_US_RXRDY)
+ atmel_rx_chars(port);
+
+ // TODO: All reads to CSR will clear these interrupts!
+ if (pending & ATMEL_US_RIIC) port->icount.rng++;
+ if (pending & ATMEL_US_DSRIC) port->icount.dsr++;
+ if (pending & ATMEL_US_DCDIC)
+ uart_handle_dcd_change(port, !(status & ATMEL_US_DCD));
+ if (pending & ATMEL_US_CTSIC)
+ uart_handle_cts_change(port, !(status & ATMEL_US_CTS));
+ if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC))
+ wake_up_interruptible(&port->info->delta_msr_wait);
+
+ /* Interrupt transmit */
+ if (pending & ATMEL_US_TXRDY)
+ atmel_tx_chars(port);
+
+ if (pass_counter++ > ATMEL_ISR_PASS_LIMIT)
+ break;
+
+ status = UART_GET_CSR(port);
+ pending = status & UART_GET_IMR(port);
+ }
+ return IRQ_HANDLED;
+}
+
+/*
+ * Perform initialization and enable port for reception
+ */
+static int atmel_startup(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+ int retval;
+
+ /*
+ * Ensure that no interrupts are enabled otherwise when
+ * request_irq() is called we could get stuck trying to
+ * handle an unexpected interrupt
+ */
+ UART_PUT_IDR(port, -1);
+
+ /*
+ * Allocate the IRQ
+ */
+ retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port);
+ if (retval) {
+ printk("atmel_serial: atmel_startup - Can't get irq\n");
+ return retval;
+ }
+
+ /*
+ * If there is a specific "open" function (to register
+ * control line interrupts)
+ */
+ if (atmel_open_hook) {
+ retval = atmel_open_hook(port);
+ if (retval) {
+ free_irq(port->irq, port);
+ return retval;
+ }
+ }
+
+ /*
+ * Finally, enable the serial port
+ */
+ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */
+
+ UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */
+
+ return 0;
+}
+
+/*
+ * Disable the port
+ */
+static void atmel_shutdown(struct uart_port *port)
+{
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+ /*
+ * Disable all interrupts, port and break condition.
+ */
+ UART_PUT_CR(port, ATMEL_US_RSTSTA);
+ UART_PUT_IDR(port, -1);
+
+ /*
+ * Free the interrupt
+ */
+ free_irq(port->irq, port);
+
+ /*
+ * If there is a specific "close" function (to unregister
+ * control line interrupts)
+ */
+ if (atmel_close_hook)
+ atmel_close_hook(port);
+}
+
+/*
+ * Power / Clock management.
+ */
+static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate)
+{
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+ switch (state) {
+ case 0:
+ /*
+ * Enable the peripheral clock for this serial port.
+ * This is called on uart_open() or a resume event.
+ */
+ clk_enable(atmel_port->clk);
+ break;
+ case 3:
+ /*
+ * Disable the peripheral clock for this serial port.
+ * This is called on uart_close() or a suspend event.
+ */
+ clk_disable(atmel_port->clk);
+ break;
+ default:
+ printk(KERN_ERR "atmel_serial: unknown pm %d\n", state);
+ }
+}
+
+/*
+ * Change the port parameters
+ */
+static void atmel_set_termios(struct uart_port *port, struct termios * termios, struct termios * old)
+{
+ unsigned long flags;
+ unsigned int mode, imr, quot, baud;
+
+ baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ quot = uart_get_divisor(port, baud);
+
+ /* Get current mode register */
+ mode = UART_GET_MR(port) & ~(ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR);
+
+ /* byte size */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ mode |= ATMEL_US_CHRL_5;
+ break;
+ case CS6:
+ mode |= ATMEL_US_CHRL_6;
+ break;
+ case CS7:
+ mode |= ATMEL_US_CHRL_7;
+ break;
+ default:
+ mode |= ATMEL_US_CHRL_8;
+ break;
+ }
+
+ /* stop bits */
+ if (termios->c_cflag & CSTOPB)
+ mode |= ATMEL_US_NBSTOP_2;
+
+ /* parity */
+ if (termios->c_cflag & PARENB) {
+ if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */
+ if (termios->c_cflag & PARODD)
+ mode |= ATMEL_US_PAR_MARK;
+ else
+ mode |= ATMEL_US_PAR_SPACE;
+ }
+ else if (termios->c_cflag & PARODD)
+ mode |= ATMEL_US_PAR_ODD;
+ else
+ mode |= ATMEL_US_PAR_EVEN;
+ }
+ else
+ mode |= ATMEL_US_PAR_NONE;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ port->read_status_mask = ATMEL_US_OVRE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+ if (termios->c_iflag & (BRKINT | PARMRK))
+ port->read_status_mask |= ATMEL_US_RXBRK;
+
+ /*
+ * Characters to ignore
+ */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= (ATMEL_US_FRAME | ATMEL_US_PARE);
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= ATMEL_US_RXBRK;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= ATMEL_US_OVRE;
+ }
+
+ // TODO: Ignore all characters if CREAD is set.
+
+ /* update the per-port timeout */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ /* disable interrupts and drain transmitter */
+ imr = UART_GET_IMR(port); /* get interrupt mask */
+ UART_PUT_IDR(port, -1); /* disable all interrupts */
+ while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); }
+
+ /* disable receiver and transmitter */
+ UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
+
+ /* set the parity, stop bits and data size */
+ UART_PUT_MR(port, mode);
+
+ /* set the baud rate */
+ UART_PUT_BRGR(port, quot);
+ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+ /* restore interrupts */
+ UART_PUT_IER(port, imr);
+
+ /* CTS flow-control and modem-status interrupts */
+ if (UART_ENABLE_MS(port, termios->c_cflag))
+ port->ops->enable_ms(port);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Return string describing the specified port
+ */
+static const char *atmel_type(struct uart_port *port)
+{
+ return (port->type == PORT_ATMEL) ? "ATMEL_SERIAL" : NULL;
+}
+
+/*
+ * Release the memory region(s) being used by 'port'.
+ */
+static void atmel_release_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+ release_mem_region(port->mapbase, size);
+
+ if (port->flags & UPF_IOREMAP) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+}
+
+/*
+ * Request the memory region(s) being used by 'port'.
+ */
+static int atmel_request_port(struct uart_port *port)
+{
+ struct platform_device *pdev = to_platform_device(port->dev);
+ int size = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+ if (!request_mem_region(port->mapbase, size, "atmel_serial"))
+ return -EBUSY;
+
+ if (port->flags & UPF_IOREMAP) {
+ port->membase = ioremap(port->mapbase, size);
+ if (port->membase == NULL) {
+ release_mem_region(port->mapbase, size);
+ return -ENOMEM;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Configure/autoconfigure the port.
+ */
+static void atmel_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE) {
+ port->type = PORT_ATMEL;
+ atmel_request_port(port);
+ }
+}
+
+/*
+ * Verify the new serial_struct (for TIOCSSERIAL).
+ */
+static int atmel_verify_port(struct uart_port *port, struct serial_struct *ser)
+{
+ int ret = 0;
+ if (ser->type != PORT_UNKNOWN && ser->type != PORT_ATMEL)
+ ret = -EINVAL;
+ if (port->irq != ser->irq)
+ ret = -EINVAL;
+ if (ser->io_type != SERIAL_IO_MEM)
+ ret = -EINVAL;
+ if (port->uartclk / 16 != ser->baud_base)
+ ret = -EINVAL;
+ if ((void *)port->mapbase != ser->iomem_base)
+ ret = -EINVAL;
+ if (port->iobase != ser->port)
+ ret = -EINVAL;
+ if (ser->hub6 != 0)
+ ret = -EINVAL;
+ return ret;
+}
+
+static struct uart_ops atmel_pops = {
+ .tx_empty = atmel_tx_empty,
+ .set_mctrl = atmel_set_mctrl,
+ .get_mctrl = atmel_get_mctrl,
+ .stop_tx = atmel_stop_tx,
+ .start_tx = atmel_start_tx,
+ .stop_rx = atmel_stop_rx,
+ .enable_ms = atmel_enable_ms,
+ .break_ctl = atmel_break_ctl,
+ .startup = atmel_startup,
+ .shutdown = atmel_shutdown,
+ .set_termios = atmel_set_termios,
+ .type = atmel_type,
+ .release_port = atmel_release_port,
+ .request_port = atmel_request_port,
+ .config_port = atmel_config_port,
+ .verify_port = atmel_verify_port,
+ .pm = atmel_serial_pm,
+};
+
+/*
+ * Configure the port from the platform device resource info.
+ */
+static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev)
+{
+ struct uart_port *port = &atmel_port->uart;
+ struct atmel_uart_data *data = pdev->dev.platform_data;
+
+ port->iotype = UPIO_MEM;
+ port->flags = UPF_BOOT_AUTOCONF;
+ port->ops = &atmel_pops;
+ port->fifosize = 1;
+ port->line = pdev->id;
+ port->dev = &pdev->dev;
+
+ port->mapbase = pdev->resource[0].start;
+ port->irq = pdev->resource[1].start;
+
+ if (data->regs)
+ /* Already mapped by setup code */
+ port->membase = data->regs;
+ else {
+ port->flags |= UPF_IOREMAP;
+ port->membase = NULL;
+ }
+
+ if (!atmel_port->clk) { /* for console, the clock could already be configured */
+ atmel_port->clk = clk_get(&pdev->dev, "usart");
+ clk_enable(atmel_port->clk);
+ port->uartclk = clk_get_rate(atmel_port->clk);
+ }
+}
+
+/*
+ * Register board-specific modem-control line handlers.
+ */
+void __init atmel_register_uart_fns(struct atmel_port_fns *fns)
+{
+ if (fns->enable_ms)
+ atmel_pops.enable_ms = fns->enable_ms;
+ if (fns->get_mctrl)
+ atmel_pops.get_mctrl = fns->get_mctrl;
+ if (fns->set_mctrl)
+ atmel_pops.set_mctrl = fns->set_mctrl;
+ atmel_open_hook = fns->open;
+ atmel_close_hook = fns->close;
+ atmel_pops.pm = fns->pm;
+ atmel_pops.set_wake = fns->set_wake;
+}
+
+
+#ifdef CONFIG_SERIAL_ATMEL_CONSOLE
+static void atmel_console_putchar(struct uart_port *port, int ch)
+{
+ while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY))
+ barrier();
+ UART_PUT_CHAR(port, ch);
+}
+
+/*
+ * Interrupts are disabled on entering
+ */
+static void atmel_console_write(struct console *co, const char *s, u_int count)
+{
+ struct uart_port *port = &atmel_ports[co->index].uart;
+ unsigned int status, imr;
+
+ /*
+ * First, save IMR and then disable interrupts
+ */
+ imr = UART_GET_IMR(port); /* get interrupt mask */
+ UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY);
+
+ uart_console_write(port, s, count, atmel_console_putchar);
+
+ /*
+ * Finally, wait for transmitter to become empty
+ * and restore IMR
+ */
+ do {
+ status = UART_GET_CSR(port);
+ } while (!(status & ATMEL_US_TXRDY));
+ UART_PUT_IER(port, imr); /* set interrupts back the way they were */
+}
+
+/*
+ * If the port was already initialised (eg, by a boot loader), try to determine
+ * the current setup.
+ */
+static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits)
+{
+ unsigned int mr, quot;
+
+// TODO: CR is a write-only register
+// unsigned int cr;
+//
+// cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN);
+// if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) {
+// /* ok, the port was enabled */
+// }
+
+ mr = UART_GET_MR(port) & ATMEL_US_CHRL;
+ if (mr == ATMEL_US_CHRL_8)
+ *bits = 8;
+ else
+ *bits = 7;
+
+ mr = UART_GET_MR(port) & ATMEL_US_PAR;
+ if (mr == ATMEL_US_PAR_EVEN)
+ *parity = 'e';
+ else if (mr == ATMEL_US_PAR_ODD)
+ *parity = 'o';
+
+ /*
+ * The serial core only rounds down when matching this to a
+ * supported baud rate. Make sure we don't end up slightly
+ * lower than one of those, as it would make us fall through
+ * to a much lower baud rate than we really want.
+ */
+ quot = UART_GET_BRGR(port);
+ *baud = port->uartclk / (16 * (quot - 1));
+}
+
+static int __init atmel_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port = &atmel_ports[co->index].uart;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (port->membase == 0) /* Port not initialized yet - delay setup */
+ return -ENODEV;
+
+ UART_PUT_IDR(port, -1); /* disable interrupts */
+ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
+ UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ else
+ atmel_console_get_options(port, &baud, &parity, &bits);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver atmel_uart;
+
+static struct console atmel_console = {
+ .name = ATMEL_DEVICENAME,
+ .write = atmel_console_write,
+ .device = uart_console_device,
+ .setup = atmel_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &atmel_uart,
+};
+
+#define ATMEL_CONSOLE_DEVICE &atmel_console
+
+/*
+ * Early console initialization (before VM subsystem initialized).
+ */
+static int __init atmel_console_init(void)
+{
+ if (atmel_default_console_device) {
+ add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL);
+ atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device);
+ register_console(&atmel_console);
+ }
+
+ return 0;
+}
+console_initcall(atmel_console_init);
+
+/*
+ * Late console initialization.
+ */
+static int __init atmel_late_console_init(void)
+{
+ if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED))
+ register_console(&atmel_console);
+
+ return 0;
+}
+core_initcall(atmel_late_console_init);
+
+#else
+#define ATMEL_CONSOLE_DEVICE NULL
+#endif
+
+static struct uart_driver atmel_uart = {
+ .owner = THIS_MODULE,
+ .driver_name = "atmel_serial",
+ .dev_name = ATMEL_DEVICENAME,
+ .major = SERIAL_ATMEL_MAJOR,
+ .minor = MINOR_START,
+ .nr = ATMEL_MAX_UART,
+ .cons = ATMEL_CONSOLE_DEVICE,
+};
+
+#ifdef CONFIG_PM
+static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+ if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock())
+ enable_irq_wake(port->irq);
+ else {
+ disable_irq_wake(port->irq);
+ uart_suspend_port(&atmel_uart, port);
+ atmel_port->suspended = 1;
+ }
+
+ return 0;
+}
+
+static int atmel_serial_resume(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+
+ if (atmel_port->suspended) {
+ uart_resume_port(&atmel_uart, port);
+ atmel_port->suspended = 0;
+ }
+
+ return 0;
+}
+#else
+#define atmel_serial_suspend NULL
+#define atmel_serial_resume NULL
+#endif
+
+static int __devinit atmel_serial_probe(struct platform_device *pdev)
+{
+ struct atmel_uart_port *port;
+ int ret;
+
+ port = &atmel_ports[pdev->id];
+ atmel_init_port(port, pdev);
+
+ ret = uart_add_one_port(&atmel_uart, &port->uart);
+ if (!ret) {
+ device_init_wakeup(&pdev->dev, 1);
+ platform_set_drvdata(pdev, port);
+ }
+
+ return ret;
+}
+
+static int __devexit atmel_serial_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+ struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+ int ret = 0;
+
+ clk_disable(atmel_port->clk);
+ clk_put(atmel_port->clk);
+
+ device_init_wakeup(&pdev->dev, 0);
+ platform_set_drvdata(pdev, NULL);
+
+ if (port) {
+ ret = uart_remove_one_port(&atmel_uart, port);
+ kfree(port);
+ }
+
+ return ret;
+}
+
+static struct platform_driver atmel_serial_driver = {
+ .probe = atmel_serial_probe,
+ .remove = __devexit_p(atmel_serial_remove),
+ .suspend = atmel_serial_suspend,
+ .resume = atmel_serial_resume,
+ .driver = {
+ .name = "atmel_usart",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init atmel_serial_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&atmel_uart);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&atmel_serial_driver);
+ if (ret)
+ uart_unregister_driver(&atmel_uart);
+
+ return ret;
+}
+
+static void __exit atmel_serial_exit(void)
+{
+ platform_driver_unregister(&atmel_serial_driver);
+ uart_unregister_driver(&atmel_uart);
+}
+
+module_init(atmel_serial_init);
+module_exit(atmel_serial_exit);
+
+MODULE_AUTHOR("Rick Bronson");
+MODULE_DESCRIPTION("Atmel AT91 / AT32 serial port driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/atmel_serial.h b/drivers/serial/atmel_serial.h
new file mode 100644
index 000000000000..eced2ad1a8d9
--- /dev/null
+++ b/drivers/serial/atmel_serial.h
@@ -0,0 +1,123 @@
+/*
+ * drivers/serial/atmel_serial.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * USART registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * 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.
+ */
+
+#ifndef ATMEL_SERIAL_H
+#define ATMEL_SERIAL_H
+
+#define ATMEL_US_CR 0x00 /* Control Register */
+#define ATMEL_US_RSTRX (1 << 2) /* Reset Receiver */
+#define ATMEL_US_RSTTX (1 << 3) /* Reset Transmitter */
+#define ATMEL_US_RXEN (1 << 4) /* Receiver Enable */
+#define ATMEL_US_RXDIS (1 << 5) /* Receiver Disable */
+#define ATMEL_US_TXEN (1 << 6) /* Transmitter Enable */
+#define ATMEL_US_TXDIS (1 << 7) /* Transmitter Disable */
+#define ATMEL_US_RSTSTA (1 << 8) /* Reset Status Bits */
+#define ATMEL_US_STTBRK (1 << 9) /* Start Break */
+#define ATMEL_US_STPBRK (1 << 10) /* Stop Break */
+#define ATMEL_US_STTTO (1 << 11) /* Start Time-out */
+#define ATMEL_US_SENDA (1 << 12) /* Send Address */
+#define ATMEL_US_RSTIT (1 << 13) /* Reset Iterations */
+#define ATMEL_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */
+#define ATMEL_US_RETTO (1 << 15) /* Rearm Time-out */
+#define ATMEL_US_DTREN (1 << 16) /* Data Terminal Ready Enable */
+#define ATMEL_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */
+#define ATMEL_US_RTSEN (1 << 18) /* Request To Send Enable */
+#define ATMEL_US_RTSDIS (1 << 19) /* Request To Send Disable */
+
+#define ATMEL_US_MR 0x04 /* Mode Register */
+#define ATMEL_US_USMODE (0xf << 0) /* Mode of the USART */
+#define ATMEL_US_USMODE_NORMAL 0
+#define ATMEL_US_USMODE_RS485 1
+#define ATMEL_US_USMODE_HWHS 2
+#define ATMEL_US_USMODE_MODEM 3
+#define ATMEL_US_USMODE_ISO7816_T0 4
+#define ATMEL_US_USMODE_ISO7816_T1 6
+#define ATMEL_US_USMODE_IRDA 8
+#define ATMEL_US_USCLKS (3 << 4) /* Clock Selection */
+#define ATMEL_US_CHRL (3 << 6) /* Character Length */
+#define ATMEL_US_CHRL_5 (0 << 6)
+#define ATMEL_US_CHRL_6 (1 << 6)
+#define ATMEL_US_CHRL_7 (2 << 6)
+#define ATMEL_US_CHRL_8 (3 << 6)
+#define ATMEL_US_SYNC (1 << 8) /* Synchronous Mode Select */
+#define ATMEL_US_PAR (7 << 9) /* Parity Type */
+#define ATMEL_US_PAR_EVEN (0 << 9)
+#define ATMEL_US_PAR_ODD (1 << 9)
+#define ATMEL_US_PAR_SPACE (2 << 9)
+#define ATMEL_US_PAR_MARK (3 << 9)
+#define ATMEL_US_PAR_NONE (4 << 9)
+#define ATMEL_US_PAR_MULTI_DROP (6 << 9)
+#define ATMEL_US_NBSTOP (3 << 12) /* Number of Stop Bits */
+#define ATMEL_US_NBSTOP_1 (0 << 12)
+#define ATMEL_US_NBSTOP_1_5 (1 << 12)
+#define ATMEL_US_NBSTOP_2 (2 << 12)
+#define ATMEL_US_CHMODE (3 << 14) /* Channel Mode */
+#define ATMEL_US_CHMODE_NORMAL (0 << 14)
+#define ATMEL_US_CHMODE_ECHO (1 << 14)
+#define ATMEL_US_CHMODE_LOC_LOOP (2 << 14)
+#define ATMEL_US_CHMODE_REM_LOOP (3 << 14)
+#define ATMEL_US_MSBF (1 << 16) /* Bit Order */
+#define ATMEL_US_MODE9 (1 << 17) /* 9-bit Character Length */
+#define ATMEL_US_CLKO (1 << 18) /* Clock Output Select */
+#define ATMEL_US_OVER (1 << 19) /* Oversampling Mode */
+#define ATMEL_US_INACK (1 << 20) /* Inhibit Non Acknowledge */
+#define ATMEL_US_DSNACK (1 << 21) /* Disable Successive NACK */
+#define ATMEL_US_MAX_ITER (7 << 24) /* Max Iterations */
+#define ATMEL_US_FILTER (1 << 28) /* Infrared Receive Line Filter */
+
+#define ATMEL_US_IER 0x08 /* Interrupt Enable Register */
+#define ATMEL_US_RXRDY (1 << 0) /* Receiver Ready */
+#define ATMEL_US_TXRDY (1 << 1) /* Transmitter Ready */
+#define ATMEL_US_RXBRK (1 << 2) /* Break Received / End of Break */
+#define ATMEL_US_ENDRX (1 << 3) /* End of Receiver Transfer */
+#define ATMEL_US_ENDTX (1 << 4) /* End of Transmitter Transfer */
+#define ATMEL_US_OVRE (1 << 5) /* Overrun Error */
+#define ATMEL_US_FRAME (1 << 6) /* Framing Error */
+#define ATMEL_US_PARE (1 << 7) /* Parity Error */
+#define ATMEL_US_TIMEOUT (1 << 8) /* Receiver Time-out */
+#define ATMEL_US_TXEMPTY (1 << 9) /* Transmitter Empty */
+#define ATMEL_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */
+#define ATMEL_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */
+#define ATMEL_US_RXBUFF (1 << 12) /* Reception Buffer Full */
+#define ATMEL_US_NACK (1 << 13) /* Non Acknowledge */
+#define ATMEL_US_RIIC (1 << 16) /* Ring Indicator Input Change */
+#define ATMEL_US_DSRIC (1 << 17) /* Data Set Ready Input Change */
+#define ATMEL_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */
+#define ATMEL_US_CTSIC (1 << 19) /* Clear to Send Input Change */
+#define ATMEL_US_RI (1 << 20) /* RI */
+#define ATMEL_US_DSR (1 << 21) /* DSR */
+#define ATMEL_US_DCD (1 << 22) /* DCD */
+#define ATMEL_US_CTS (1 << 23) /* CTS */
+
+#define ATMEL_US_IDR 0x0c /* Interrupt Disable Register */
+#define ATMEL_US_IMR 0x10 /* Interrupt Mask Register */
+#define ATMEL_US_CSR 0x14 /* Channel Status Register */
+#define ATMEL_US_RHR 0x18 /* Receiver Holding Register */
+#define ATMEL_US_THR 0x1c /* Transmitter Holding Register */
+
+#define ATMEL_US_BRGR 0x20 /* Baud Rate Generator Register */
+#define ATMEL_US_CD (0xffff << 0) /* Clock Divider */
+
+#define ATMEL_US_RTOR 0x24 /* Receiver Time-out Register */
+#define ATMEL_US_TO (0xffff << 0) /* Time-out Value */
+
+#define ATMEL_US_TTGR 0x28 /* Transmitter Timeguard Register */
+#define ATMEL_US_TG (0xff << 0) /* Timeguard Value */
+
+#define ATMEL_US_FIDI 0x40 /* FI DI Ratio Register */
+#define ATMEL_US_NER 0x44 /* Number of Errors Register */
+#define ATMEL_US_IF 0x4c /* IrDA Filter Register */
+
+#endif
diff --git a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
index f27d852ce50d..598012714882 100644
--- a/drivers/serial/clps711x.c
+++ b/drivers/serial/clps711x.c
@@ -93,7 +93,7 @@ static void clps711xuart_enable_ms(struct uart_port *port)
{
}
-static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct tty_struct *tty = port->info->tty;
@@ -131,7 +131,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re
#endif
}
- if (uart_handle_sysrq_char(port, ch, regs))
+ if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
/*
@@ -147,7 +147,7 @@ static irqreturn_t clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *re
return IRQ_HANDLED;
}
-static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t clps711xuart_int_tx(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct circ_buf *xmit = &port->info->xmit;
diff --git a/drivers/serial/cpm_uart/cpm_uart.h b/drivers/serial/cpm_uart/cpm_uart.h
index 3b35cb779539..a8f894c78194 100644
--- a/drivers/serial/cpm_uart/cpm_uart.h
+++ b/drivers/serial/cpm_uart/cpm_uart.h
@@ -16,7 +16,6 @@
#ifndef CPM_UART_H
#define CPM_UART_H
-#include <linux/config.h>
#include <linux/platform_device.h>
#include <linux/fs_uart_pd.h>
diff --git a/drivers/serial/cpm_uart/cpm_uart_core.c b/drivers/serial/cpm_uart/cpm_uart_core.c
index 90ff96e3339b..0abb544ae63d 100644
--- a/drivers/serial/cpm_uart/cpm_uart_core.c
+++ b/drivers/serial/cpm_uart/cpm_uart_core.c
@@ -46,6 +46,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/delay.h>
+#include <asm/fs_pd.h>
#if defined(CONFIG_SERIAL_CPM_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
@@ -247,7 +248,7 @@ static void cpm_uart_break_ctl(struct uart_port *port, int break_state)
/*
* Transmit characters, refill buffer descriptor, if possible
*/
-static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs)
+static void cpm_uart_int_tx(struct uart_port *port)
{
pr_debug("CPM uart[%d]:TX INT\n", port->line);
@@ -257,7 +258,7 @@ static void cpm_uart_int_tx(struct uart_port *port, struct pt_regs *regs)
/*
* Receive characters
*/
-static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
+static void cpm_uart_int_rx(struct uart_port *port)
{
int i;
unsigned char ch, *cp;
@@ -303,7 +304,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
if (status &
(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV))
goto handle_error;
- if (uart_handle_sysrq_char(port, ch, regs))
+ if (uart_handle_sysrq_char(port, ch))
continue;
error_return:
@@ -372,7 +373,7 @@ static void cpm_uart_int_rx(struct uart_port *port, struct pt_regs *regs)
/*
* Asynchron mode interrupt handler
*/
-static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t cpm_uart_int(int irq, void *data)
{
u8 events;
struct uart_port *port = (struct uart_port *)data;
@@ -388,18 +389,18 @@ static irqreturn_t cpm_uart_int(int irq, void *data, struct pt_regs *regs)
if (events & SMCM_BRKE)
uart_handle_break(port);
if (events & SMCM_RX)
- cpm_uart_int_rx(port, regs);
+ cpm_uart_int_rx(port);
if (events & SMCM_TX)
- cpm_uart_int_tx(port, regs);
+ cpm_uart_int_tx(port);
} else {
events = sccp->scc_scce;
sccp->scc_scce = events;
if (events & UART_SCCM_BRKE)
uart_handle_break(port);
if (events & UART_SCCM_RX)
- cpm_uart_int_rx(port, regs);
+ cpm_uart_int_rx(port);
if (events & UART_SCCM_TX)
- cpm_uart_int_tx(port, regs);
+ cpm_uart_int_tx(port);
}
return (events) ? IRQ_HANDLED : IRQ_NONE;
}
@@ -1022,15 +1023,17 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
{
struct resource *r;
struct fs_uart_platform_info *pdata = pdev->dev.platform_data;
- int idx = pdata->fs_no; /* It is UART_SMCx or UART_SCCx index */
+ int idx; /* It is UART_SMCx or UART_SCCx index */
struct uart_cpm_port *pinfo;
int line;
u32 mem, pram;
+ idx = pdata->fs_no = fs_uart_get_id(pdata);
+
line = cpm_uart_id2nr(idx);
if(line < 0) {
printk(KERN_ERR"%s(): port %d is not registered", __FUNCTION__, idx);
- return -1;
+ return -EINVAL;
}
pinfo = (struct uart_cpm_port *) &cpm_uart_ports[idx];
@@ -1044,11 +1047,11 @@ int cpm_uart_drv_get_platform_data(struct platform_device *pdev, int is_con)
if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs")))
return -EINVAL;
- mem = r->start;
+ mem = (u32)ioremap(r->start, r->end - r->start + 1);
if (!(r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pram")))
return -EINVAL;
- pram = r->start;
+ pram = (u32)ioremap(r->start, r->end - r->start + 1);
if(idx > fsid_smc2_uart) {
pinfo->sccp = (scc_t *)mem;
@@ -1179,7 +1182,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
pdata = pdev->dev.platform_data;
if (pdata)
if (pdata->init_ioports)
- pdata->init_ioports();
+ pdata->init_ioports(pdata);
cpm_uart_drv_get_platform_data(pdev, 1);
}
@@ -1189,11 +1192,7 @@ static int __init cpm_uart_console_setup(struct console *co, char *options)
if (options) {
uart_parse_options(options, &baud, &parity, &bits, &flow);
} else {
- bd_t *bd = (bd_t *) __res;
-
- if (bd->bi_baudrate)
- baud = bd->bi_baudrate;
- else
+ if ((baud = uart_baudrate()) == -1)
baud = 9600;
}
@@ -1266,13 +1265,14 @@ static int cpm_uart_drv_probe(struct device *dev)
}
pdata = pdev->dev.platform_data;
- pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no));
if ((ret = cpm_uart_drv_get_platform_data(pdev, 0)))
return ret;
+ pr_debug("cpm_uart_drv_probe: Adding CPM UART %d\n", cpm_uart_id2nr(pdata->fs_no));
+
if (pdata->init_ioports)
- pdata->init_ioports();
+ pdata->init_ioports(pdata);
ret = uart_add_one_port(&cpm_reg, &cpm_uart_ports[pdata->fs_no].port);
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.h b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
index 5d867ab581b7..5eb49ea63bfe 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/serial/cpm_uart_cpm1.h
+ * linux/drivers/serial/cpm_uart/cpm_uart_cpm1.h
*
* Driver for CPM (SCC/SMC) serial ports
*
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.c b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
index ef3bb476c432..b691d3e14754 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.c
@@ -40,6 +40,7 @@
#include <asm/io.h>
#include <asm/irq.h>
+#include <asm/fs_pd.h>
#include <linux/serial_core.h>
#include <linux/kernel.h>
@@ -50,8 +51,9 @@
void cpm_line_cr_cmd(int line, int cmd)
{
- volatile cpm_cpm2_t *cp = cpmp;
ulong val;
+ volatile cpm_cpm2_t *cp = cpm2_map(im_cpm);
+
switch (line) {
case UART_SMC1:
@@ -84,11 +86,14 @@ void cpm_line_cr_cmd(int line, int cmd)
}
cp->cp_cpcr = val;
while (cp->cp_cpcr & CPM_CR_FLG) ;
+
+ cpm2_unmap(cp);
}
void smc1_lineif(struct uart_cpm_port *pinfo)
{
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
+ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
/* SMC1 is only on port D */
io->iop_ppard |= 0x00c00000;
@@ -97,13 +102,17 @@ void smc1_lineif(struct uart_cpm_port *pinfo)
io->iop_psord &= ~0x00c00000;
/* Wire BRG1 to SMC1 */
- cpm2_immr->im_cpmux.cmx_smr &= 0x0f;
+ cpmux->cmx_smr &= 0x0f;
pinfo->brg = 1;
+
+ cpm2_unmap(cpmux);
+ cpm2_unmap(io);
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
+ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
/* SMC2 is only on port A */
io->iop_ppara |= 0x00c00000;
@@ -112,13 +121,17 @@ void smc2_lineif(struct uart_cpm_port *pinfo)
io->iop_psora &= ~0x00c00000;
/* Wire BRG2 to SMC2 */
- cpm2_immr->im_cpmux.cmx_smr &= 0xf0;
+ cpmux->cmx_smr &= 0xf0;
pinfo->brg = 2;
+
+ cpm2_unmap(cpmux);
+ cpm2_unmap(io);
}
void scc1_lineif(struct uart_cpm_port *pinfo)
{
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
+ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
/* Use Port D for SCC1 instead of other functions. */
io->iop_ppard |= 0x00000003;
@@ -128,9 +141,12 @@ void scc1_lineif(struct uart_cpm_port *pinfo)
io->iop_pdird |= 0x00000002; /* Tx */
/* Wire BRG1 to SCC1 */
- cpm2_immr->im_cpmux.cmx_scr &= 0x00ffffff;
- cpm2_immr->im_cpmux.cmx_scr |= 0x00000000;
+ cpmux->cmx_scr &= 0x00ffffff;
+ cpmux->cmx_scr |= 0x00000000;
pinfo->brg = 1;
+
+ cpm2_unmap(cpmux);
+ cpm2_unmap(io);
}
void scc2_lineif(struct uart_cpm_port *pinfo)
@@ -143,43 +159,57 @@ void scc2_lineif(struct uart_cpm_port *pinfo)
* be supported in a sane fashion.
*/
#ifndef CONFIG_STX_GP3
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
+ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
+
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
#endif
- cpm2_immr->im_cpmux.cmx_scr &= 0xff00ffff;
- cpm2_immr->im_cpmux.cmx_scr |= 0x00090000;
+ cpmux->cmx_scr &= 0xff00ffff;
+ cpmux->cmx_scr |= 0x00090000;
pinfo->brg = 2;
+
+ cpm2_unmap(cpmux);
+ cpm2_unmap(io);
}
void scc3_lineif(struct uart_cpm_port *pinfo)
{
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
+ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
+
io->iop_pparb |= 0x008b0000;
io->iop_pdirb |= 0x00880000;
io->iop_psorb |= 0x00880000;
io->iop_pdirb &= ~0x00030000;
io->iop_psorb &= ~0x00030000;
- cpm2_immr->im_cpmux.cmx_scr &= 0xffff00ff;
- cpm2_immr->im_cpmux.cmx_scr |= 0x00001200;
+ cpmux->cmx_scr &= 0xffff00ff;
+ cpmux->cmx_scr |= 0x00001200;
pinfo->brg = 3;
+
+ cpm2_unmap(cpmux);
+ cpm2_unmap(io);
}
void scc4_lineif(struct uart_cpm_port *pinfo)
{
- volatile iop_cpm2_t *io = &cpm2_immr->im_ioport;
+ volatile iop_cpm2_t *io = cpm2_map(im_ioport);
+ volatile cpmux_t *cpmux = cpm2_map(im_cpmux);
io->iop_ppard |= 0x00000600;
io->iop_psord &= ~0x00000600; /* Tx/Rx */
io->iop_pdird &= ~0x00000200; /* Rx */
io->iop_pdird |= 0x00000400; /* Tx */
- cpm2_immr->im_cpmux.cmx_scr &= 0xffffff00;
- cpm2_immr->im_cpmux.cmx_scr |= 0x0000001b;
+ cpmux->cmx_scr &= 0xffffff00;
+ cpmux->cmx_scr |= 0x0000001b;
pinfo->brg = 4;
+
+ cpm2_unmap(cpmux);
+ cpm2_unmap(io);
}
/*
@@ -254,88 +284,103 @@ void cpm_uart_freebuf(struct uart_cpm_port *pinfo)
/* Setup any dynamic params in the uart desc */
int cpm_uart_init_portdesc(void)
{
+#if defined(CONFIG_SERIAL_CPM_SMC1) || defined(CONFIG_SERIAL_CPM_SMC2)
+ u32 addr;
+#endif
pr_debug("CPM uart[-]:init portdesc\n");
cpm_uart_nr = 0;
#ifdef CONFIG_SERIAL_CPM_SMC1
- cpm_uart_ports[UART_SMC1].smcp = (smc_t *) & cpm2_immr->im_smc[0];
- cpm_uart_ports[UART_SMC1].smcup =
- (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC1];
- *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC1_BASE]) = PROFF_SMC1;
+ cpm_uart_ports[UART_SMC1].smcp = (smc_t *) cpm2_map(im_smc[0]);
cpm_uart_ports[UART_SMC1].port.mapbase =
- (unsigned long)&cpm2_immr->im_smc[0];
+ (unsigned long)cpm_uart_ports[UART_SMC1].smcp;
+
+ cpm_uart_ports[UART_SMC1].smcup =
+ (smc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SMC1], PROFF_SMC_SIZE);
+ addr = (u16 *)cpm2_map_size(im_dprambase[PROFF_SMC1_BASE], 2);
+ *addr = PROFF_SMC1;
+ cpm2_unmap(addr);
+
cpm_uart_ports[UART_SMC1].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC1].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- cpm_uart_ports[UART_SMC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SMC1].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SMC2
- cpm_uart_ports[UART_SMC2].smcp = (smc_t *) & cpm2_immr->im_smc[1];
- cpm_uart_ports[UART_SMC2].smcup =
- (smc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SMC2];
- *(u16 *)(&cpm2_immr->im_dprambase[PROFF_SMC2_BASE]) = PROFF_SMC2;
+ cpm_uart_ports[UART_SMC2].smcp = (smc_t *) cpm2_map(im_smc[1]);
cpm_uart_ports[UART_SMC2].port.mapbase =
- (unsigned long)&cpm2_immr->im_smc[1];
+ (unsigned long)cpm_uart_ports[UART_SMC2].smcp;
+
+ cpm_uart_ports[UART_SMC2].smcup =
+ (smc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SMC2], PROFF_SMC_SIZE);
+ addr = (u16 *)cpm2_map_size(im_dprambase[PROFF_SMC2_BASE], 2);
+ *addr = PROFF_SMC2;
+ cpm2_unmap(addr);
+
cpm_uart_ports[UART_SMC2].smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
cpm_uart_ports[UART_SMC2].smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
- cpm_uart_ports[UART_SMC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SMC2].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SMC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC1
- cpm_uart_ports[UART_SCC1].sccp = (scc_t *) & cpm2_immr->im_scc[0];
- cpm_uart_ports[UART_SCC1].sccup =
- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC1];
+ cpm_uart_ports[UART_SCC1].sccp = (scc_t *) cpm2_map(im_scc[0]);
cpm_uart_ports[UART_SCC1].port.mapbase =
- (unsigned long)&cpm2_immr->im_scc[0];
+ (unsigned long)cpm_uart_ports[UART_SCC1].sccp;
+ cpm_uart_ports[UART_SCC1].sccup =
+ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC1], PROFF_SCC_SIZE);
+
cpm_uart_ports[UART_SCC1].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC1].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC1].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC1].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC1;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC2
- cpm_uart_ports[UART_SCC2].sccp = (scc_t *) & cpm2_immr->im_scc[1];
- cpm_uart_ports[UART_SCC2].sccup =
- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC2];
+ cpm_uart_ports[UART_SCC2].sccp = (scc_t *) cpm2_map(im_scc[1]);
cpm_uart_ports[UART_SCC2].port.mapbase =
- (unsigned long)&cpm2_immr->im_scc[1];
+ (unsigned long)cpm_uart_ports[UART_SCC2].sccp;
+ cpm_uart_ports[UART_SCC2].sccup =
+ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC2], PROFF_SCC_SIZE);
+
cpm_uart_ports[UART_SCC2].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC2].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC2].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC2].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC2;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC3
- cpm_uart_ports[UART_SCC3].sccp = (scc_t *) & cpm2_immr->im_scc[2];
- cpm_uart_ports[UART_SCC3].sccup =
- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC3];
+ cpm_uart_ports[UART_SCC3].sccp = (scc_t *) cpm2_map(im_scc[2]);
cpm_uart_ports[UART_SCC3].port.mapbase =
- (unsigned long)&cpm2_immr->im_scc[2];
+ (unsigned long)cpm_uart_ports[UART_SCC3].sccp;
+ cpm_uart_ports[UART_SCC3].sccup =
+ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC3], PROFF_SCC_SIZE);
+
cpm_uart_ports[UART_SCC3].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC3].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC3].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC3].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC3;
#endif
#ifdef CONFIG_SERIAL_CPM_SCC4
- cpm_uart_ports[UART_SCC4].sccp = (scc_t *) & cpm2_immr->im_scc[3];
- cpm_uart_ports[UART_SCC4].sccup =
- (scc_uart_t *) & cpm2_immr->im_dprambase[PROFF_SCC4];
+ cpm_uart_ports[UART_SCC4].sccp = (scc_t *) cpm2_map(im_scc[3]);
cpm_uart_ports[UART_SCC4].port.mapbase =
- (unsigned long)&cpm2_immr->im_scc[3];
+ (unsigned long)cpm_uart_ports[UART_SCC4].sccp;
+ cpm_uart_ports[UART_SCC4].sccup =
+ (scc_uart_t *) cpm2_map_size(im_dprambase[PROFF_SCC4], PROFF_SCC_SIZE);
+
cpm_uart_ports[UART_SCC4].sccp->scc_sccm &=
~(UART_SCCM_TX | UART_SCCM_RX);
cpm_uart_ports[UART_SCC4].sccp->scc_gsmrl &=
~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
- cpm_uart_ports[UART_SCC4].port.uartclk = (((bd_t *) __res)->bi_intfreq);
+ cpm_uart_ports[UART_SCC4].port.uartclk = uart_clock();
cpm_uart_port_map[cpm_uart_nr++] = UART_SCC4;
#endif
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm2.h b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
index 4793fecf8ece..4b779111eaf9 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm2.h
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm2.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/serial/cpm_uart_cpm2.h
+ * linux/drivers/serial/cpm_uart/cpm_uart_cpm2.h
*
* Driver for CPM (SCC/SMC) serial ports
*
@@ -40,6 +40,6 @@ static inline void cpm_set_smc_fcr(volatile smc_uart_t * up)
up->smc_tfcr = CPMFCR_GBL | CPMFCR_EB;
}
-#define DPRAM_BASE ((unsigned char *)&cpm2_immr->im_dprambase[0])
+#define DPRAM_BASE ((unsigned char *)cpm_dpram_addr(0))
#endif
diff --git a/drivers/serial/crisv10.c b/drivers/serial/crisv10.c
index cabd048c8636..7a24e53546c7 100644
--- a/drivers/serial/crisv10.c
+++ b/drivers/serial/crisv10.c
@@ -2346,7 +2346,7 @@ start_receive(struct e100_serial *info)
*/
static irqreturn_t
-tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+tr_interrupt(int irq, void *dev_id)
{
struct e100_serial *info;
unsigned long ireg;
@@ -2395,7 +2395,7 @@ tr_interrupt(int irq, void *dev_id, struct pt_regs * regs)
/* dma input channel interrupt handler */
static irqreturn_t
-rec_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+rec_interrupt(int irq, void *dev_id)
{
struct e100_serial *info;
unsigned long ireg;
@@ -3054,7 +3054,7 @@ static void handle_ser_tx_interrupt(struct e100_serial *info)
* ser_int duration: just sending: 8-15 us normally, up to 73 us
*/
static irqreturn_t
-ser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ser_interrupt(int irq, void *dev_id)
{
static volatile int tx_started = 0;
struct e100_serial *info;
@@ -4825,7 +4825,7 @@ show_serial_version(void)
/* rs_init inits the driver at boot (using the module_init chain) */
-static struct tty_operations rs_ops = {
+static const struct tty_operations rs_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
diff --git a/drivers/serial/dz.c b/drivers/serial/dz.c
index 8a98aae80e22..53662b33b841 100644
--- a/drivers/serial/dz.c
+++ b/drivers/serial/dz.c
@@ -339,7 +339,7 @@ static inline void check_modem_status(struct dz_port *dport)
* It deals with the multiple ports.
* ------------------------------------------------------------
*/
-static irqreturn_t dz_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t dz_interrupt(int irq, void *dev)
{
struct dz_port *dport;
unsigned short status;
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c
index a3c00a252149..8aa0f641866b 100644
--- a/drivers/serial/icom.c
+++ b/drivers/serial/icom.c
@@ -844,8 +844,7 @@ static void process_interrupt(u16 port_int_reg,
spin_unlock(&icom_port->uart_port.lock);
}
-static irqreturn_t icom_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t icom_interrupt(int irq, void *dev_id)
{
void __iomem * int_reg;
u32 adapter_interrupts;
diff --git a/drivers/serial/imx.c b/drivers/serial/imx.c
index 4a142d6b8f38..ee5c782597dd 100644
--- a/drivers/serial/imx.c
+++ b/drivers/serial/imx.c
@@ -182,7 +182,7 @@ static void imx_start_tx(struct uart_port *port)
imx_transmit_buffer(sport);
}
-static irqreturn_t imx_rtsint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t imx_rtsint(int irq, void *dev_id)
{
struct imx_port *sport = (struct imx_port *)dev_id;
unsigned int val = USR1((u32)sport->port.membase)&USR1_RTSS;
@@ -198,7 +198,7 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t imx_txint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t imx_txint(int irq, void *dev_id)
{
struct imx_port *sport = (struct imx_port *)dev_id;
struct circ_buf *xmit = &sport->port.info->xmit;
@@ -227,7 +227,7 @@ out:
return IRQ_HANDLED;
}
-static irqreturn_t imx_rxint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t imx_rxint(int irq, void *dev_id)
{
struct imx_port *sport = dev_id;
unsigned int rx,flg,ignored = 0;
@@ -248,7 +248,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id, struct pt_regs *regs)
}
if (uart_handle_sysrq_char
- (&sport->port, (unsigned char)rx, regs))
+ (&sport->port, (unsigned char)rx))
goto ignore_char;
if( rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) )
diff --git a/drivers/serial/ioc3_serial.c b/drivers/serial/ioc3_serial.c
index 8097cd91f16b..2308d26c8629 100644
--- a/drivers/serial/ioc3_serial.c
+++ b/drivers/serial/ioc3_serial.c
@@ -1428,13 +1428,12 @@ static int receive_chars(struct uart_port *the_port)
* @is : submodule
* @idd: driver data
* @pending: interrupts to handle
- * @regs: pt_regs
*/
static int inline
ioc3uart_intr_one(struct ioc3_submodule *is,
struct ioc3_driver_data *idd,
- unsigned int pending, struct pt_regs *regs)
+ unsigned int pending)
{
int port_num = GET_PORT_FROM_SIO_IR(pending);
struct port_hooks *hooks;
@@ -1628,13 +1627,12 @@ ioc3uart_intr_one(struct ioc3_submodule *is,
* @is : submodule
* @idd: driver data
* @pending: interrupts to handle
- * @regs: pt_regs
*
*/
static int ioc3uart_intr(struct ioc3_submodule *is,
struct ioc3_driver_data *idd,
- unsigned int pending, struct pt_regs *regs)
+ unsigned int pending)
{
int ret = 0;
@@ -1644,9 +1642,9 @@ static int ioc3uart_intr(struct ioc3_submodule *is,
*/
if (pending & SIO_IR_SA)
- ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA, regs);
+ ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SA);
if (pending & SIO_IR_SB)
- ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB, regs);
+ ret |= ioc3uart_intr_one(is, idd, pending & SIO_IR_SB);
return ret;
}
diff --git a/drivers/serial/ioc4_serial.c b/drivers/serial/ioc4_serial.c
index 576ca1eaa2b6..ff4fa25f9fd1 100644
--- a/drivers/serial/ioc4_serial.c
+++ b/drivers/serial/ioc4_serial.c
@@ -987,10 +987,9 @@ intr_connect(struct ioc4_soft *soft, int type,
* ioc4_intr - Top level IOC4 interrupt handler.
* @irq: irq value
* @arg: handler arg
- * @regs: registers
*/
-static irqreturn_t ioc4_intr(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t ioc4_intr(int irq, void *arg)
{
struct ioc4_soft *soft;
uint32_t this_ir, this_mir;
@@ -2685,6 +2684,7 @@ static int ioc4_serial_remove_one(struct ioc4_driver_data *idd)
if (soft) {
free_irq(control->ic_irq, soft);
if (soft->is_ioc4_serial_addr) {
+ iounmap(soft->is_ioc4_serial_addr);
release_region((unsigned long)
soft->is_ioc4_serial_addr,
sizeof(struct ioc4_serial));
@@ -2887,6 +2887,8 @@ out4:
out3:
kfree(control);
out2:
+ if (serial)
+ iounmap(serial);
release_region(tmp_addr1, sizeof(struct ioc4_serial));
out1:
@@ -2933,7 +2935,7 @@ static void __devexit ioc4_serial_exit(void)
uart_unregister_driver(&ioc4_uart_rs422);
}
-module_init(ioc4_serial_init);
+late_initcall(ioc4_serial_init); /* Call only after tty init is done */
module_exit(ioc4_serial_exit);
MODULE_AUTHOR("Pat Gefre - Silicon Graphics Inc. (SGI) <pfg@sgi.com>");
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index 5ff269fb604c..dca6c1bde8f9 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -252,8 +252,7 @@ static void ip22zilog_maybe_update_regs(struct uart_ip22zilog_port *up,
}
static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel,
- struct pt_regs *regs)
+ struct zilog_channel *channel)
{
struct tty_struct *tty = up->port.info->tty; /* XXX info==NULL? */
@@ -319,7 +318,7 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
else if (r1 & CRC_ERR)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto next_char;
if (up->port.ignore_status_mask == 0xff ||
@@ -339,8 +338,7 @@ static void ip22zilog_receive_chars(struct uart_ip22zilog_port *up,
}
static void ip22zilog_status_handle(struct uart_ip22zilog_port *up,
- struct zilog_channel *channel,
- struct pt_regs *regs)
+ struct zilog_channel *channel)
{
unsigned char status;
@@ -443,7 +441,7 @@ ack_tx_int:
ZS_WSYNC(channel);
}
-static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id)
{
struct uart_ip22zilog_port *up = dev_id;
@@ -462,9 +460,9 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re
ZS_WSYNC(channel);
if (r3 & CHARxIP)
- ip22zilog_receive_chars(up, channel, regs);
+ ip22zilog_receive_chars(up, channel);
if (r3 & CHAEXT)
- ip22zilog_status_handle(up, channel, regs);
+ ip22zilog_status_handle(up, channel);
if (r3 & CHATxIP)
ip22zilog_transmit_chars(up, channel);
}
@@ -481,9 +479,9 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re
ZS_WSYNC(channel);
if (r3 & CHBRxIP)
- ip22zilog_receive_chars(up, channel, regs);
+ ip22zilog_receive_chars(up, channel);
if (r3 & CHBEXT)
- ip22zilog_status_handle(up, channel, regs);
+ ip22zilog_status_handle(up, channel);
if (r3 & CHBTxIP)
ip22zilog_transmit_chars(up, channel);
}
@@ -1229,13 +1227,27 @@ static int __init ip22zilog_init(void)
static void __exit ip22zilog_exit(void)
{
int i;
+ struct uart_ip22zilog_port *up;
for (i = 0; i < NUM_CHANNELS; i++) {
- struct uart_ip22zilog_port *up = &ip22zilog_port_table[i];
+ up = &ip22zilog_port_table[i];
uart_remove_one_port(&ip22zilog_reg, &up->port);
}
+ /* Free IO mem */
+ up = &ip22zilog_port_table[0];
+ for (i = 0; i < NUM_IP22ZILOG; i++) {
+ if (up[(i * 2) + 0].port.mapbase) {
+ iounmap((void*)up[(i * 2) + 0].port.mapbase);
+ up[(i * 2) + 0].port.mapbase = 0;
+ }
+ if (up[(i * 2) + 1].port.mapbase) {
+ iounmap((void*)up[(i * 2) + 1].port.mapbase);
+ up[(i * 2) + 1].port.mapbase = 0;
+ }
+ }
+
uart_unregister_driver(&ip22zilog_reg);
}
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index 043f50b1d10c..12c934a1f274 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -99,7 +99,7 @@ struct jsm_channel;
* Per board operations structure *
************************************************************************/
struct board_ops {
- irqreturn_t (*intr) (int irq, void *voidbrd, struct pt_regs *regs);
+ irq_handler_t intr;
void (*uart_init) (struct jsm_channel *ch);
void (*uart_off) (struct jsm_channel *ch);
void (*param) (struct jsm_channel *ch);
diff --git a/drivers/serial/jsm/jsm_neo.c b/drivers/serial/jsm/jsm_neo.c
index a5fc589d6ef5..8be8da37f629 100644
--- a/drivers/serial/jsm/jsm_neo.c
+++ b/drivers/serial/jsm/jsm_neo.c
@@ -1114,9 +1114,9 @@ static void neo_param(struct jsm_channel *ch)
*
* Neo specific interrupt handler.
*/
-static irqreturn_t neo_intr(int irq, void *voidbrd, struct pt_regs *regs)
+static irqreturn_t neo_intr(int irq, void *voidbrd)
{
- struct jsm_board *brd = (struct jsm_board *) voidbrd;
+ struct jsm_board *brd = voidbrd;
struct jsm_channel *ch;
int port = 0;
int type = 0;
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index e7fe4bb46eca..7656a35f5e2f 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -76,7 +76,7 @@
*/
#define is_real_interrupt(irq) ((irq) != 0)
-#include <asm/serial.h>
+#define BASE_BAUD 115200
/* Standard COM flags */
#define STD_COM_FLAGS (UPF_BOOT_AUTOCONF | UPF_SKIP_TEST)
@@ -86,7 +86,6 @@
* standard enumeration mechanism. Platforms that can find all
* serial ports via mechanisms like ACPI or PCI need not supply it.
*/
-#undef SERIAL_PORT_DFNS
#if defined(CONFIG_PLAT_USRV)
#define SERIAL_PORT_DFNS \
@@ -109,7 +108,7 @@
#endif /* !CONFIG_PLAT_USRV */
static struct old_serial_port old_serial_port[] = {
- SERIAL_PORT_DFNS /* defined in asm/serial.h */
+ SERIAL_PORT_DFNS
};
#define UART_NR ARRAY_SIZE(old_serial_port)
@@ -324,8 +323,7 @@ static void m32r_sio_enable_ms(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
}
-static void receive_chars(struct uart_sio_port *up, int *status,
- struct pt_regs *regs)
+static void receive_chars(struct uart_sio_port *up, int *status)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch;
@@ -379,7 +377,7 @@ static void receive_chars(struct uart_sio_port *up, int *status,
else if (*status & UART_LSR_FE)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto ignore_char;
if ((*status & up->port.ignore_status_mask) == 0)
tty_insert_flip_char(tty, ch, flag);
@@ -440,12 +438,12 @@ static void transmit_chars(struct uart_sio_port *up)
* This handles the interrupt from one port.
*/
static inline void m32r_sio_handle_port(struct uart_sio_port *up,
- unsigned int status, struct pt_regs *regs)
+ unsigned int status)
{
DEBUG_INTR("status = %x...", status);
if (status & 0x04)
- receive_chars(up, &status, regs);
+ receive_chars(up, &status);
if (status & 0x01)
transmit_chars(up);
}
@@ -464,8 +462,7 @@ static inline void m32r_sio_handle_port(struct uart_sio_port *up,
* This means we need to loop through all ports. checking that they
* don't have an interrupt pending.
*/
-static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id)
{
struct irq_info *i = dev_id;
struct list_head *l, *end = NULL;
@@ -493,7 +490,7 @@ static irqreturn_t m32r_sio_interrupt(int irq, void *dev_id,
sts = sio_in(up, SIOSTS);
if (sts & 0x5) {
spin_lock(&up->port.lock);
- m32r_sio_handle_port(up, sts, regs);
+ m32r_sio_handle_port(up, sts);
spin_unlock(&up->port.lock);
end = NULL;
@@ -593,7 +590,7 @@ static void m32r_sio_timeout(unsigned long data)
sts = sio_in(up, SIOSTS);
if (sts & 0x5) {
spin_lock(&up->port.lock);
- m32r_sio_handle_port(up, sts, NULL);
+ m32r_sio_handle_port(up, sts);
spin_unlock(&up->port.lock);
}
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index 832abd3c4706..aee1b31f1a1c 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -385,7 +385,7 @@ static inline void transmit_chars(struct mcf_serial *info)
/*
* This is the serial driver's generic interrupt routine
*/
-irqreturn_t mcfrs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t mcfrs_interrupt(int irq, void *dev_id)
{
struct mcf_serial *info;
unsigned char isr;
@@ -1666,7 +1666,7 @@ static void show_serial_version(void)
printk(mcfrs_drivername);
}
-static struct tty_operations mcfrs_ops = {
+static const struct tty_operations mcfrs_ops = {
.open = mcfrs_open,
.close = mcfrs_close,
.write = mcfrs_write,
diff --git a/drivers/serial/mpc52xx_uart.c b/drivers/serial/mpc52xx_uart.c
index 7708e5dd3656..4f80c5b4a753 100644
--- a/drivers/serial/mpc52xx_uart.c
+++ b/drivers/serial/mpc52xx_uart.c
@@ -85,7 +85,7 @@ static struct uart_port mpc52xx_uart_ports[MPC52xx_PSC_MAXNUM];
/* Forward declaration of the interruption handling routine */
-static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id,struct pt_regs *regs);
+static irqreturn_t mpc52xx_uart_int(int irq,void *dev_id);
/* Simple macro to test if a port is console or not. This one is taken
@@ -338,14 +338,23 @@ mpc52xx_uart_release_port(struct uart_port *port)
static int
mpc52xx_uart_request_port(struct uart_port *port)
{
+ int err;
+
if (port->flags & UPF_IOREMAP) /* Need to remap ? */
port->membase = ioremap(port->mapbase, MPC52xx_PSC_SIZE);
if (!port->membase)
return -EINVAL;
- return request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
+ err = request_mem_region(port->mapbase, MPC52xx_PSC_SIZE,
"mpc52xx_psc_uart") != NULL ? 0 : -EBUSY;
+
+ if (err && (port->flags & UPF_IOREMAP)) {
+ iounmap(port->membase);
+ port->membase = NULL;
+ }
+
+ return err;
}
static void
@@ -401,7 +410,7 @@ static struct uart_ops mpc52xx_uart_ops = {
/* ======================================================================== */
static inline int
-mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
+mpc52xx_uart_int_rx_chars(struct uart_port *port)
{
struct tty_struct *tty = port->info->tty;
unsigned char ch, flag;
@@ -416,7 +425,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port, struct pt_regs *regs)
/* Handle sysreq char */
#ifdef SUPPORT_SYSRQ
- if (uart_handle_sysrq_char(port, ch, regs)) {
+ if (uart_handle_sysrq_char(port, ch)) {
port->sysrq = 0;
continue;
}
@@ -501,21 +510,13 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
}
static irqreturn_t
-mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs)
+mpc52xx_uart_int(int irq, void *dev_id)
{
- struct uart_port *port = (struct uart_port *) dev_id;
+ struct uart_port *port = dev_id;
unsigned long pass = ISR_PASS_LIMIT;
unsigned int keepgoing;
unsigned short status;
- if ( irq != port->irq ) {
- printk( KERN_WARNING
- "mpc52xx_uart_int : " \
- "Received wrong int %d. Waiting for %d\n",
- irq, port->irq);
- return IRQ_NONE;
- }
-
spin_lock(&port->lock);
/* While we have stuff to do, we continue */
@@ -530,7 +531,7 @@ mpc52xx_uart_int(int irq, void *dev_id, struct pt_regs *regs)
/* Do we need to receive chars ? */
/* For this RX interrupts must be on and some chars waiting */
if ( status & MPC52xx_PSC_IMR_RXRDY )
- keepgoing |= mpc52xx_uart_int_rx_chars(port, regs);
+ keepgoing |= mpc52xx_uart_int_rx_chars(port);
/* Do we need to send chars ? */
/* For this, TX must be ready and TX interrupt enabled */
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index 63d2a66e563b..8eea69f29989 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -992,7 +992,7 @@ mpsc_make_ready(struct mpsc_port_info *pi)
*/
static inline int
-mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs)
+mpsc_rx_intr(struct mpsc_port_info *pi)
{
struct mpsc_rx_desc *rxre;
struct tty_struct *tty = pi->port.info->tty;
@@ -1072,7 +1072,7 @@ mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs)
flag = TTY_PARITY;
}
- if (uart_handle_sysrq_char(&pi->port, *bp, regs)) {
+ if (uart_handle_sysrq_char(&pi->port, *bp)) {
bp++;
bytes_in--;
goto next_frame;
@@ -1257,7 +1257,7 @@ mpsc_tx_intr(struct mpsc_port_info *pi)
* handling those descriptors, we restart the Rx/Tx engines if they're stopped.
*/
static irqreturn_t
-mpsc_sdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+mpsc_sdma_intr(int irq, void *dev_id)
{
struct mpsc_port_info *pi = dev_id;
ulong iflags;
@@ -1267,7 +1267,7 @@ mpsc_sdma_intr(int irq, void *dev_id, struct pt_regs *regs)
spin_lock_irqsave(&pi->port.lock, iflags);
mpsc_sdma_intr_ack(pi);
- if (mpsc_rx_intr(pi, regs))
+ if (mpsc_rx_intr(pi))
rc = IRQ_HANDLED;
if (mpsc_tx_intr(pi))
rc = IRQ_HANDLED;
@@ -1893,6 +1893,10 @@ mpsc_drv_map_regs(struct mpsc_port_info *pi, struct platform_device *pd)
}
else {
mpsc_resource_err("SDMA base");
+ if (pi->mpsc_base) {
+ iounmap(pi->mpsc_base);
+ pi->mpsc_base = NULL;
+ }
return -ENOMEM;
}
@@ -1905,6 +1909,14 @@ mpsc_drv_map_regs(struct mpsc_port_info *pi, struct platform_device *pd)
}
else {
mpsc_resource_err("BRG base");
+ if (pi->mpsc_base) {
+ iounmap(pi->mpsc_base);
+ pi->mpsc_base = NULL;
+ }
+ if (pi->sdma_base) {
+ iounmap(pi->sdma_base);
+ pi->sdma_base = NULL;
+ }
return -ENOMEM;
}
diff --git a/drivers/serial/mux.c b/drivers/serial/mux.c
index 4a1c9983f38f..8ad1b8c5ec5d 100644
--- a/drivers/serial/mux.c
+++ b/drivers/serial/mux.c
@@ -230,7 +230,7 @@ static void mux_read(struct uart_port *port)
continue;
}
- if (uart_handle_sysrq_char(port, data & 0xffu, NULL))
+ if (uart_handle_sysrq_char(port, data & 0xffu))
continue;
tty_insert_flip_char(tty, data & 0xFF, TTY_NORMAL);
@@ -521,6 +521,8 @@ static void __exit mux_exit(void)
for (i = 0; i < port_cnt; i++) {
uart_remove_one_port(&mux_driver, &mux_ports[i]);
+ if (mux_ports[i].membase)
+ iounmap(mux_ports[i].membase);
}
uart_unregister_driver(&mux_driver);
diff --git a/drivers/serial/netx-serial.c b/drivers/serial/netx-serial.c
index c1adc9e4b239..062bad457b1a 100644
--- a/drivers/serial/netx-serial.c
+++ b/drivers/serial/netx-serial.c
@@ -17,8 +17,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#include <linux/config.h>
-
#if defined(CONFIG_SERIAL_NETX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
@@ -202,7 +200,7 @@ static void netx_txint(struct uart_port *port)
uart_write_wakeup(port);
}
-static void netx_rxint(struct uart_port *port, struct pt_regs *regs)
+static void netx_rxint(struct uart_port *port)
{
unsigned char rx, flg, status;
struct tty_struct *tty = port->info->tty;
@@ -237,7 +235,7 @@ static void netx_rxint(struct uart_port *port, struct pt_regs *regs)
flg = TTY_FRAME;
}
- if (uart_handle_sysrq_char(port, rx, regs))
+ if (uart_handle_sysrq_char(port, rx))
continue;
uart_insert_char(port, status, SR_OE, rx, flg);
@@ -247,9 +245,9 @@ static void netx_rxint(struct uart_port *port, struct pt_regs *regs)
return;
}
-static irqreturn_t netx_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t netx_int(int irq, void *dev_id)
{
- struct uart_port *port = (struct uart_port *)dev_id;
+ struct uart_port *port = dev_id;
unsigned long flags;
unsigned char status;
@@ -258,7 +256,7 @@ static irqreturn_t netx_int(int irq, void *dev_id, struct pt_regs *regs)
status = readl(port->membase + UART_IIR) & IIR_MASK;
while (status) {
if (status & IIR_RIS)
- netx_rxint(port, regs);
+ netx_rxint(port);
if (status & IIR_TIS)
netx_txint(port);
if (status & IIR_MIS) {
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index a3b99caf80e6..bf9809ed9c0b 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -204,8 +204,7 @@ static void pmz_maybe_update_regs(struct uart_pmac_port *uap)
}
}
-static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
- struct pt_regs *regs)
+static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap)
{
struct tty_struct *tty = NULL;
unsigned char ch, r1, drop, error, flag;
@@ -267,7 +266,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
if (uap->port.sysrq) {
int swallow;
spin_unlock(&uap->port.lock);
- swallow = uart_handle_sysrq_char(&uap->port, ch, regs);
+ swallow = uart_handle_sysrq_char(&uap->port, ch);
spin_lock(&uap->port.lock);
if (swallow)
goto next_char;
@@ -335,7 +334,7 @@ static struct tty_struct *pmz_receive_chars(struct uart_pmac_port *uap,
return tty;
}
-static void pmz_status_handle(struct uart_pmac_port *uap, struct pt_regs *regs)
+static void pmz_status_handle(struct uart_pmac_port *uap)
{
unsigned char status;
@@ -438,7 +437,7 @@ ack_tx_int:
}
/* Hrm... we register that twice, fixme later.... */
-static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pmz_interrupt(int irq, void *dev_id)
{
struct uart_pmac_port *uap = dev_id;
struct uart_pmac_port *uap_a;
@@ -462,9 +461,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
write_zsreg(uap_a, R0, RES_H_IUS);
zssync(uap_a);
if (r3 & CHAEXT)
- pmz_status_handle(uap_a, regs);
+ pmz_status_handle(uap_a);
if (r3 & CHARxIP)
- tty = pmz_receive_chars(uap_a, regs);
+ tty = pmz_receive_chars(uap_a);
if (r3 & CHATxIP)
pmz_transmit_chars(uap_a);
rc = IRQ_HANDLED;
@@ -482,9 +481,9 @@ static irqreturn_t pmz_interrupt(int irq, void *dev_id, struct pt_regs *regs)
write_zsreg(uap_b, R0, RES_H_IUS);
zssync(uap_b);
if (r3 & CHBEXT)
- pmz_status_handle(uap_b, regs);
+ pmz_status_handle(uap_b);
if (r3 & CHBRxIP)
- tty = pmz_receive_chars(uap_b, regs);
+ tty = pmz_receive_chars(uap_b);
if (r3 & CHBTxIP)
pmz_transmit_chars(uap_b);
rc = IRQ_HANDLED;
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index a720953a404e..415fe9633a9b 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -98,8 +98,7 @@ static void serial_pxa_stop_rx(struct uart_port *port)
serial_out(up, UART_IER, up->ier);
}
-static inline void
-receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
+static inline void receive_chars(struct uart_pxa_port *up, int *status)
{
struct tty_struct *tty = up->port.info->tty;
unsigned int ch, flag;
@@ -153,7 +152,7 @@ receive_chars(struct uart_pxa_port *up, int *status, struct pt_regs *regs)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto ignore_char;
uart_insert_char(&up->port, *status, UART_LSR_OE, ch, flag);
@@ -231,10 +230,9 @@ static inline void check_modem_status(struct uart_pxa_port *up)
/*
* This handles the interrupt from one port.
*/
-static inline irqreturn_t
-serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs)
+static inline irqreturn_t serial_pxa_irq(int irq, void *dev_id)
{
- struct uart_pxa_port *up = (struct uart_pxa_port *)dev_id;
+ struct uart_pxa_port *up = dev_id;
unsigned int iir, lsr;
iir = serial_in(up, UART_IIR);
@@ -242,7 +240,7 @@ serial_pxa_irq(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_NONE;
lsr = serial_in(up, UART_LSR);
if (lsr & UART_LSR_DR)
- receive_chars(up, &lsr, regs);
+ receive_chars(up, &lsr);
check_modem_status(up);
if (lsr & UART_LSR_THRE)
transmit_chars(up);
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 95738a19cde7..8dfc2dd058ca 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -310,7 +310,7 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
#define S3C2410_UERSTAT_PARITY (0x1000)
static irqreturn_t
-s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
+s3c24xx_serial_rx_chars(int irq, void *dev_id)
{
struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
@@ -379,7 +379,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(port, ch, regs))
+ if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
uart_insert_char(port, uerstat, S3C2410_UERSTAT_OVERRUN, ch, flag);
@@ -393,7 +393,7 @@ s3c24xx_serial_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id, struct pt_regs *regs)
+static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
{
struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
diff --git a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
index db3486d33870..d4065266b6fc 100644
--- a/drivers/serial/sa1100.c
+++ b/drivers/serial/sa1100.c
@@ -190,7 +190,7 @@ static void sa1100_enable_ms(struct uart_port *port)
}
static void
-sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
+sa1100_rx_chars(struct sa1100_port *sport)
{
struct tty_struct *tty = sport->port.info->tty;
unsigned int status, ch, flg;
@@ -228,7 +228,7 @@ sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs)
#endif
}
- if (uart_handle_sysrq_char(&sport->port, ch, regs))
+ if (uart_handle_sysrq_char(&sport->port, ch))
goto ignore_char;
uart_insert_char(&sport->port, status, UTSR1_TO_SM(UTSR1_ROR), ch, flg);
@@ -281,7 +281,7 @@ static void sa1100_tx_chars(struct sa1100_port *sport)
sa1100_stop_tx(&sport->port);
}
-static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sa1100_int(int irq, void *dev_id)
{
struct sa1100_port *sport = dev_id;
unsigned int status, pass_counter = 0;
@@ -294,7 +294,7 @@ static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
/* Clear the receiver idle bit, if set */
if (status & UTSR0_RID)
UART_PUT_UTSR0(sport, UTSR0_RID);
- sa1100_rx_chars(sport, regs);
+ sa1100_rx_chars(sport);
}
/* Clear the relevant break bits */
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 5f7ba1adb309..c67b05e9a451 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -792,6 +792,7 @@ static int uart_set_info(struct uart_state *state,
* We failed anyway.
*/
retval = -EBUSY;
+ goto exit; // Added to return the correct error -Ram Gupta
}
}
@@ -1662,16 +1663,16 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
struct uart_port *port = state->port;
char stat_buf[32];
unsigned int status;
- int ret;
+ int mmio, ret;
if (!port)
return 0;
+ mmio = port->iotype >= UPIO_MEM;
ret = sprintf(buf, "%d: uart:%s %s%08lX irq:%d",
port->line, uart_type(port),
- port->iotype == UPIO_MEM ? "mmio:0x" : "port:",
- port->iotype == UPIO_MEM ? port->mapbase :
- (unsigned long) port->iobase,
+ mmio ? "mmio:0x" : "port:",
+ mmio ? port->mapbase : (unsigned long) port->iobase,
port->irq);
if (port->type == PORT_UNKNOWN) {
@@ -1939,6 +1940,9 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port)
if (state->info && state->info->flags & UIF_INITIALIZED) {
const struct uart_ops *ops = port->ops;
+ state->info->flags = (state->info->flags & ~UIF_INITIALIZED)
+ | UIF_SUSPENDED;
+
spin_lock_irq(&port->lock);
ops->stop_tx(port);
ops->set_mctrl(port, 0);
@@ -2005,7 +2009,7 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
console_start(port->cons);
}
- if (state->info && state->info->flags & UIF_INITIALIZED) {
+ if (state->info && state->info->flags & UIF_SUSPENDED) {
const struct uart_ops *ops = port->ops;
int ret;
@@ -2017,15 +2021,17 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *port)
ops->set_mctrl(port, port->mctrl);
ops->start_tx(port);
spin_unlock_irq(&port->lock);
+ state->info->flags |= UIF_INITIALIZED;
} else {
/*
* Failed to resume - maybe hardware went away?
* Clear the "initialized" flag so we won't try
* to call the low level drivers shutdown method.
*/
- state->info->flags &= ~UIF_INITIALIZED;
uart_shutdown(state);
}
+
+ state->info->flags &= ~UIF_SUSPENDED;
}
mutex_unlock(&state->mutex);
@@ -2111,7 +2117,7 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
}
}
-static struct tty_operations uart_ops = {
+static const struct tty_operations uart_ops = {
.open = uart_open,
.close = uart_close,
.write = uart_write,
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index cbf260bc225d..00f9ffd69489 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -80,23 +80,16 @@ module_param(buggy_uart, int, 0444);
/* Table of multi-port card ID's */
-struct multi_id {
- u_short manfid;
- u_short prodid;
+struct serial_quirk {
+ unsigned int manfid;
+ unsigned int prodid;
int multi; /* 1 = multifunction, > 1 = # ports */
+ void (*config)(struct pcmcia_device *);
+ void (*setup)(struct pcmcia_device *, struct uart_port *);
+ void (*wakeup)(struct pcmcia_device *);
+ int (*post)(struct pcmcia_device *);
};
-static const struct multi_id multi_id[] = {
- { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
- { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
- { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
- { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
- { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
-};
-#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id))
-
struct serial_info {
struct pcmcia_device *p_dev;
int ndev;
@@ -107,6 +100,7 @@ struct serial_info {
int c950ctrl;
dev_node_t node[4];
int line[4];
+ const struct serial_quirk *quirk;
};
struct serial_cfg_mem {
@@ -115,37 +109,165 @@ struct serial_cfg_mem {
u_char buf[256];
};
+/*
+ * vers_1 5.0, "Brain Boxes", "2-Port RS232 card", "r6"
+ * manfid 0x0160, 0x0104
+ * This card appears to have a 14.7456MHz clock.
+ */
+static void quirk_setup_brainboxes_0104(struct pcmcia_device *link, struct uart_port *port)
+{
+ port->uartclk = 14745600;
+}
-static int serial_config(struct pcmcia_device * link);
+static int quirk_post_ibm(struct pcmcia_device *link)
+{
+ conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
+ int last_ret, last_fn;
+ last_ret = pcmcia_access_configuration_register(link, &reg);
+ if (last_ret) {
+ last_fn = AccessConfigurationRegister;
+ goto cs_failed;
+ }
+ reg.Action = CS_WRITE;
+ reg.Value = reg.Value | 1;
+ last_ret = pcmcia_access_configuration_register(link, &reg);
+ if (last_ret) {
+ last_fn = AccessConfigurationRegister;
+ goto cs_failed;
+ }
+ return 0;
-static void wakeup_card(struct serial_info *info)
+ cs_failed:
+ cs_error(link, last_fn, last_ret);
+ return -ENODEV;
+}
+
+/*
+ * Nokia cards are not really multiport cards. Shouldn't this
+ * be handled by setting the quirk entry .multi = 0 | 1 ?
+ */
+static void quirk_config_nokia(struct pcmcia_device *link)
{
- int ctrl = info->c950ctrl;
-
- if (info->manfid == MANFID_OXSEMI) {
- outb(12, ctrl + 1);
- } else if (info->manfid == MANFID_POSSIO && info->prodid == PRODID_POSSIO_GCC) {
- /* request_region? oxsemi branch does no request_region too... */
- /* This sequence is needed to properly initialize MC45 attached to OXCF950.
- * I tried decreasing these msleep()s, but it worked properly (survived
- * 1000 stop/start operations) with these timeouts (or bigger). */
- outb(0xA, ctrl + 1);
- msleep(100);
- outb(0xE, ctrl + 1);
- msleep(300);
- outb(0xC, ctrl + 1);
- msleep(100);
- outb(0xE, ctrl + 1);
- msleep(200);
- outb(0xF, ctrl + 1);
- msleep(100);
- outb(0xE, ctrl + 1);
- msleep(100);
- outb(0xC, ctrl + 1);
+ struct serial_info *info = link->priv;
+
+ if (info->multi > 1)
+ info->multi = 1;
+}
+
+static void quirk_wakeup_oxsemi(struct pcmcia_device *link)
+{
+ struct serial_info *info = link->priv;
+
+ outb(12, info->c950ctrl + 1);
+}
+
+/* request_region? oxsemi branch does no request_region too... */
+/*
+ * This sequence is needed to properly initialize MC45 attached to OXCF950.
+ * I tried decreasing these msleep()s, but it worked properly (survived
+ * 1000 stop/start operations) with these timeouts (or bigger).
+ */
+static void quirk_wakeup_possio_gcc(struct pcmcia_device *link)
+{
+ struct serial_info *info = link->priv;
+ unsigned int ctrl = info->c950ctrl;
+
+ outb(0xA, ctrl + 1);
+ msleep(100);
+ outb(0xE, ctrl + 1);
+ msleep(300);
+ outb(0xC, ctrl + 1);
+ msleep(100);
+ outb(0xE, ctrl + 1);
+ msleep(200);
+ outb(0xF, ctrl + 1);
+ msleep(100);
+ outb(0xE, ctrl + 1);
+ msleep(100);
+ outb(0xC, ctrl + 1);
+}
+
+/*
+ * Socket Dual IO: this enables irq's for second port
+ */
+static void quirk_config_socket(struct pcmcia_device *link)
+{
+ struct serial_info *info = link->priv;
+
+ if (info->multi) {
+ link->conf.Present |= PRESENT_EXT_STATUS;
+ link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
}
}
+static const struct serial_quirk quirks[] = {
+ {
+ .manfid = 0x0160,
+ .prodid = 0x0104,
+ .multi = -1,
+ .setup = quirk_setup_brainboxes_0104,
+ }, {
+ .manfid = MANFID_IBM,
+ .prodid = ~0,
+ .multi = -1,
+ .post = quirk_post_ibm,
+ }, {
+ .manfid = MANFID_INTEL,
+ .prodid = PRODID_INTEL_DUAL_RS232,
+ .multi = 2,
+ }, {
+ .manfid = MANFID_NATINST,
+ .prodid = PRODID_NATINST_QUAD_RS232,
+ .multi = 4,
+ }, {
+ .manfid = MANFID_NOKIA,
+ .prodid = ~0,
+ .multi = -1,
+ .config = quirk_config_nokia,
+ }, {
+ .manfid = MANFID_OMEGA,
+ .prodid = PRODID_OMEGA_QSP_100,
+ .multi = 4,
+ }, {
+ .manfid = MANFID_OXSEMI,
+ .prodid = ~0,
+ .multi = -1,
+ .wakeup = quirk_wakeup_oxsemi,
+ }, {
+ .manfid = MANFID_POSSIO,
+ .prodid = PRODID_POSSIO_GCC,
+ .multi = -1,
+ .wakeup = quirk_wakeup_possio_gcc,
+ }, {
+ .manfid = MANFID_QUATECH,
+ .prodid = PRODID_QUATECH_DUAL_RS232,
+ .multi = 2,
+ }, {
+ .manfid = MANFID_QUATECH,
+ .prodid = PRODID_QUATECH_DUAL_RS232_D1,
+ .multi = 2,
+ }, {
+ .manfid = MANFID_QUATECH,
+ .prodid = PRODID_QUATECH_QUAD_RS232,
+ .multi = 4,
+ }, {
+ .manfid = MANFID_SOCKET,
+ .prodid = PRODID_SOCKET_DUAL_RS232,
+ .multi = 2,
+ .config = quirk_config_socket,
+ }, {
+ .manfid = MANFID_SOCKET,
+ .prodid = ~0,
+ .multi = -1,
+ .config = quirk_config_socket,
+ }
+};
+
+
+static int serial_config(struct pcmcia_device * link);
+
+
/*======================================================================
After a card is removed, serial_remove() will unregister
@@ -185,14 +307,14 @@ static int serial_suspend(struct pcmcia_device *link)
static int serial_resume(struct pcmcia_device *link)
{
- if (pcmcia_dev_present(link)) {
- struct serial_info *info = link->priv;
- int i;
+ struct serial_info *info = link->priv;
+ int i;
- for (i = 0; i < info->ndev; i++)
- serial8250_resume_port(info->line[i]);
- wakeup_card(info);
- }
+ for (i = 0; i < info->ndev; i++)
+ serial8250_resume_port(info->line[i]);
+
+ if (info->quirk && info->quirk->wakeup)
+ info->quirk->wakeup(link);
return 0;
}
@@ -278,6 +400,10 @@ static int setup_serial(struct pcmcia_device *handle, struct serial_info * info,
port.dev = &handle_to_dev(handle);
if (buggy_uart)
port.flags |= UPF_BUGGY_UART;
+
+ if (info->quirk && info->quirk->setup)
+ info->quirk->setup(handle, &port);
+
line = serial8250_register_port(&port);
if (line < 0) {
printk(KERN_NOTICE "serial_cs: serial8250_register_port() at "
@@ -433,6 +559,13 @@ next_entry:
}
if (info->multi && (info->manfid == MANFID_3COM))
link->conf.ConfigIndex &= ~(0x08);
+
+ /*
+ * Apply any configuration quirks.
+ */
+ if (info->quirk && info->quirk->config)
+ info->quirk->config(link);
+
i = pcmcia_request_configuration(link, &link->conf);
if (i != CS_SUCCESS) {
cs_error(link, RequestConfiguration, i);
@@ -521,11 +654,13 @@ static int multi_config(struct pcmcia_device * link)
cs_error(link, RequestIRQ, i);
link->irq.AssignedIRQ = 0;
}
- /* Socket Dual IO: this enables irq's for second port */
- if (info->multi && (info->manfid == MANFID_SOCKET)) {
- link->conf.Present |= PRESENT_EXT_STATUS;
- link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
- }
+
+ /*
+ * Apply any configuration quirks.
+ */
+ if (info->quirk && info->quirk->config)
+ info->quirk->config(link);
+
i = pcmcia_request_configuration(link, &link->conf);
if (i != CS_SUCCESS) {
cs_error(link, RequestConfiguration, i);
@@ -550,17 +685,19 @@ static int multi_config(struct pcmcia_device * link)
link->irq.AssignedIRQ);
}
info->c950ctrl = base2;
- wakeup_card(info);
+
+ /*
+ * FIXME: We really should wake up the port prior to
+ * handing it over to the serial layer.
+ */
+ if (info->quirk && info->quirk->wakeup)
+ info->quirk->wakeup(link);
+
rc = 0;
goto free_cfg_mem;
}
setup_serial(link, info, link->io.BasePort1, link->irq.AssignedIRQ);
- /* The Nokia cards are not really multiport cards */
- if (info->manfid == MANFID_NOKIA) {
- rc = 0;
- goto free_cfg_mem;
- }
for (i = 0; i < info->multi - 1; i++)
setup_serial(link, info, base2 + (8 * i),
link->irq.AssignedIRQ);
@@ -622,13 +759,16 @@ static int serial_config(struct pcmcia_device * link)
tuple->DesiredTuple = CISTPL_MANFID;
if (first_tuple(link, tuple, parse) == CS_SUCCESS) {
info->manfid = parse->manfid.manf;
- info->prodid = le16_to_cpu(buf[1]);
- for (i = 0; i < MULTI_COUNT; i++)
- if ((info->manfid == multi_id[i].manfid) &&
- (parse->manfid.card == multi_id[i].prodid))
+ info->prodid = parse->manfid.card;
+
+ for (i = 0; i < ARRAY_SIZE(quirks); i++)
+ if ((quirks[i].manfid == ~0 ||
+ quirks[i].manfid == info->manfid) &&
+ (quirks[i].prodid == ~0 ||
+ quirks[i].prodid == info->prodid)) {
+ info->quirk = &quirks[i];
break;
- if (i < MULTI_COUNT)
- info->multi = multi_id[i].multi;
+ }
}
/* Another check for dual-serial cards: look for either serial or
@@ -648,6 +788,12 @@ static int serial_config(struct pcmcia_device * link)
}
}
+ /*
+ * Apply any multi-port quirk.
+ */
+ if (info->quirk && info->quirk->multi != -1)
+ info->multi = info->quirk->multi;
+
if (info->multi > 1)
multi_config(link);
else
@@ -656,21 +802,13 @@ static int serial_config(struct pcmcia_device * link)
if (info->ndev == 0)
goto failed;
- if (info->manfid == MANFID_IBM) {
- conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
- last_ret = pcmcia_access_configuration_register(link, &reg);
- if (last_ret) {
- last_fn = AccessConfigurationRegister;
- goto cs_failed;
- }
- reg.Action = CS_WRITE;
- reg.Value = reg.Value | 1;
- last_ret = pcmcia_access_configuration_register(link, &reg);
- if (last_ret) {
- last_fn = AccessConfigurationRegister;
- goto cs_failed;
- }
- }
+ /*
+ * Apply any post-init quirk. FIXME: This should really happen
+ * before we register the port, since it might already be in use.
+ */
+ if (info->quirk && info->quirk->post)
+ if (info->quirk->post(link))
+ goto failed;
link->dev_node = &info->node[0];
kfree(cfg_mem);
diff --git a/drivers/serial/serial_lh7a40x.c b/drivers/serial/serial_lh7a40x.c
index 23ddedbaec08..5e1ac356bbb0 100644
--- a/drivers/serial/serial_lh7a40x.c
+++ b/drivers/serial/serial_lh7a40x.c
@@ -135,12 +135,7 @@ static void lh7a40xuart_enable_ms (struct uart_port* port)
BIT_SET (port, UART_R_INTEN, ModemInt);
}
-static void
-#ifdef SUPPORT_SYSRQ
-lh7a40xuart_rx_chars (struct uart_port* port, struct pt_regs* regs)
-#else
-lh7a40xuart_rx_chars (struct uart_port* port)
-#endif
+static void lh7a40xuart_rx_chars (struct uart_port* port)
{
struct tty_struct* tty = port->info->tty;
int cbRxMax = 256; /* (Gross) limit on receive */
@@ -177,7 +172,7 @@ lh7a40xuart_rx_chars (struct uart_port* port)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char (port, (unsigned char) data, regs))
+ if (uart_handle_sysrq_char (port, (unsigned char) data))
continue;
uart_insert_char(port, data, RxOverrunError, data, flag);
@@ -248,8 +243,7 @@ static void lh7a40xuart_modem_status (struct uart_port* port)
wake_up_interruptible (&port->info->delta_msr_wait);
}
-static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
- struct pt_regs* regs)
+static irqreturn_t lh7a40xuart_int (int irq, void* dev_id)
{
struct uart_port* port = dev_id;
unsigned int cLoopLimit = ISR_LOOP_LIMIT;
@@ -258,11 +252,7 @@ static irqreturn_t lh7a40xuart_int (int irq, void* dev_id,
do {
if (isr & (RxInt | RxTimeoutInt))
-#ifdef SUPPORT_SYSRQ
- lh7a40xuart_rx_chars(port, regs);
-#else
lh7a40xuart_rx_chars(port);
-#endif
if (isr & ModemInt)
lh7a40xuart_modem_status (port);
if (isr & TxInt)
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index b361669f85a1..2a48289ac722 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -283,7 +283,7 @@ static void serial_txx9_enable_ms(struct uart_port *port)
}
static inline void
-receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *regs)
+receive_chars(struct uart_txx9_port *up, unsigned int *status)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch;
@@ -344,7 +344,7 @@ receive_chars(struct uart_txx9_port *up, unsigned int *status, struct pt_regs *r
else if (disr & TXX9_SIDISR_UFER)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto ignore_char;
uart_insert_char(&up->port, disr, TXX9_SIDISR_UOER, ch, flag);
@@ -391,7 +391,7 @@ static inline void transmit_chars(struct uart_txx9_port *up)
serial_txx9_stop_tx(&up->port);
}
-static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id)
{
int pass_counter = 0;
struct uart_txx9_port *up = dev_id;
@@ -409,7 +409,7 @@ static irqreturn_t serial_txx9_interrupt(int irq, void *dev_id, struct pt_regs *
}
if (status & TXX9_SIDISR_RDIS)
- receive_chars(up, &status, regs);
+ receive_chars(up, &status);
if (status & TXX9_SIDISR_TDIS)
transmit_chars(up);
/* Clear TX/RX Int. Status */
@@ -990,7 +990,6 @@ int __init early_serial_txx9_setup(struct uart_port *port)
/**
* serial_txx9_suspend_port - suspend one serial port
* @line: serial line number
- * @level: the level of port suspension, as per uart_suspend_port
*
* Suspend one serial port.
*/
@@ -1002,7 +1001,6 @@ static void serial_txx9_suspend_port(int line)
/**
* serial_txx9_resume_port - resume one serial port
* @line: serial line number
- * @level: the level of port resumption, as per uart_resume_port
*
* Resume one serial port.
*/
diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c
index cbede06cac27..cfcc3caf49d8 100644
--- a/drivers/serial/sh-sci.c
+++ b/drivers/serial/sh-sci.c
@@ -3,7 +3,7 @@
*
* SuperH on-chip serial module support. (SCI with no FIFO / with FIFO)
*
- * Copyright (C) 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2002 - 2006 Paul Mundt
*
* based off of the old drivers/char/sh-sci.c by:
*
@@ -22,8 +22,6 @@
#include <linux/module.h>
#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
@@ -32,71 +30,77 @@
#include <linux/major.h>
#include <linux/string.h>
#include <linux/sysrq.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
-#include <linux/slab.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/console.h>
-#include <linux/bitops.h>
-#include <linux/generic_serial.h>
+#include <linux/platform_device.h>
#ifdef CONFIG_CPU_FREQ
#include <linux/notifier.h>
#include <linux/cpufreq.h>
#endif
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
#include <asm/clock.h>
-#endif
-
-#ifdef CONFIG_SH_STANDARD_BIOS
#include <asm/sh_bios.h>
+#include <asm/kgdb.h>
#endif
+#include <asm/sci.h>
+
#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
#define SUPPORT_SYSRQ
#endif
#include "sh-sci.h"
-#ifdef CONFIG_SH_KGDB
-#include <asm/kgdb.h>
+struct sci_port {
+ struct uart_port port;
+
+ /* Port type */
+ unsigned int type;
+
+ /* Port IRQs: ERI, RXI, TXI, BRI (optional) */
+ unsigned int irqs[SCIx_NR_IRQS];
+
+ /* Port pin configuration */
+ void (*init_pins)(struct uart_port *port,
+ unsigned int cflag);
-static int kgdb_get_char(struct sci_port *port);
-static void kgdb_put_char(struct sci_port *port, char c);
-static void kgdb_handle_error(struct sci_port *port);
+ /* Port enable callback */
+ void (*enable)(struct uart_port *port);
+
+ /* Port disable callback */
+ void (*disable)(struct uart_port *port);
+
+ /* Break timer */
+ struct timer_list break_timer;
+ int break_flag;
+};
+
+#ifdef CONFIG_SH_KGDB
static struct sci_port *kgdb_sci_port;
-#endif /* CONFIG_SH_KGDB */
+#endif
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
-static struct sci_port *serial_console_port = 0;
-#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
+static struct sci_port *serial_console_port;
+#endif
/* Function prototypes */
static void sci_stop_tx(struct uart_port *port);
-static void sci_start_tx(struct uart_port *port);
-static void sci_start_rx(struct uart_port *port, unsigned int tty_start);
-static void sci_stop_rx(struct uart_port *port);
-static int sci_request_irq(struct sci_port *port);
-static void sci_free_irq(struct sci_port *port);
-
-static struct sci_port sci_ports[];
-static struct uart_driver sci_uart_driver;
-#define SCI_NPORTS sci_uart_driver.nr
+#define SCI_NPORTS CONFIG_SERIAL_SH_SCI_NR_UARTS
-#if defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+static struct sci_port sci_ports[SCI_NPORTS];
+static struct uart_driver sci_uart_driver;
-static void handle_error(struct uart_port *port)
-{ /* Clear error flags */
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) && \
+ defined(CONFIG_SH_STANDARD_BIOS) || defined(CONFIG_SH_KGDB)
+static inline void handle_error(struct uart_port *port)
+{
+ /* Clear error flags */
sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
}
@@ -106,8 +110,8 @@ static int get_char(struct uart_port *port)
unsigned short status;
int c;
- local_irq_save(flags);
- do {
+ spin_lock_irqsave(&port->lock, flags);
+ do {
status = sci_in(port, SCxSR);
if (status & SCxSR_ERRORS(port)) {
handle_error(port);
@@ -117,38 +121,19 @@ static int get_char(struct uart_port *port)
c = sci_in(port, SCxRDR);
sci_in(port, SCxSR); /* Dummy read */
sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
return c;
}
-
-/* Taken from sh-stub.c of GDB 4.18 */
-static const char hexchars[] = "0123456789abcdef";
-
-static __inline__ char highhex(int x)
-{
- return hexchars[(x >> 4) & 0xf];
-}
-
-static __inline__ char lowhex(int x)
-{
- return hexchars[x & 0xf];
-}
-
#endif /* CONFIG_SH_STANDARD_BIOS || CONFIG_SH_KGDB */
-/*
- * Send the packet in buffer. The host gets one chance to read it.
- * This routine does not wait for a positive acknowledge.
- */
-
-#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
+#if defined(CONFIG_SERIAL_SH_SCI_CONSOLE) || defined(CONFIG_SH_KGDB)
static void put_char(struct uart_port *port, char c)
{
unsigned long flags;
unsigned short status;
- local_irq_save(flags);
+ spin_lock_irqsave(&port->lock, flags);
do {
status = sci_in(port, SCxSR);
@@ -158,9 +143,11 @@ static void put_char(struct uart_port *port, char c)
sci_in(port, SCxSR); /* Dummy read */
sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
- local_irq_restore(flags);
+ spin_unlock_irqrestore(&port->lock, flags);
}
+#endif
+#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
static void put_string(struct sci_port *sci_port, const char *buffer, int count)
{
struct uart_port *port = &sci_port->port;
@@ -213,96 +200,28 @@ static void put_string(struct sci_port *sci_port, const char *buffer, int count)
}
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
-
#ifdef CONFIG_SH_KGDB
-
-/* Is the SCI ready, ie is there a char waiting? */
-static int kgdb_is_char_ready(struct sci_port *port)
-{
- unsigned short status = sci_in(port, SCxSR);
-
- if (status & (SCxSR_ERRORS(port) | SCxSR_BRK(port)))
- kgdb_handle_error(port);
-
- return (status & SCxSR_RDxF(port));
-}
-
-/* Write a char */
-static void kgdb_put_char(struct sci_port *port, char c)
-{
- unsigned short status;
-
- do
- status = sci_in(port, SCxSR);
- while (!(status & SCxSR_TDxE(port)));
-
- sci_out(port, SCxTDR, c);
- sci_in(port, SCxSR); /* Dummy read */
- sci_out(port, SCxSR, SCxSR_TDxE_CLEAR(port));
-}
-
-/* Get a char if there is one, else ret -1 */
-static int kgdb_get_char(struct sci_port *port)
-{
- int c;
-
- if (kgdb_is_char_ready(port) == 0)
- c = -1;
- else {
- c = sci_in(port, SCxRDR);
- sci_in(port, SCxSR); /* Dummy read */
- sci_out(port, SCxSR, SCxSR_RDxF_CLEAR(port));
- }
-
- return c;
-}
-
-/* Called from kgdbstub.c to get a character, i.e. is blocking */
static int kgdb_sci_getchar(void)
{
- volatile int c;
+ int c;
/* Keep trying to read a character, this could be neater */
- while ((c = kgdb_get_char(kgdb_sci_port)) < 0);
+ while ((c = get_char(kgdb_sci_port)) < 0)
+ cpu_relax();
return c;
}
-/* Called from kgdbstub.c to put a character, just a wrapper */
-static void kgdb_sci_putchar(int c)
-{
-
- kgdb_put_char(kgdb_sci_port, c);
-}
-
-/* Clear any errors on the SCI */
-static void kgdb_handle_error(struct sci_port *port)
+static inline void kgdb_sci_putchar(int c)
{
- sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port)); /* Clear error flags */
+ put_char(kgdb_sci_port, c);
}
-
-/* Breakpoint if there's a break sent on the serial port */
-static void kgdb_break_interrupt(int irq, void *ptr, struct pt_regs *regs)
-{
- struct sci_port *port = ptr;
- unsigned short status = sci_in(port, SCxSR);
-
- if (status & SCxSR_BRK(port)) {
-
- /* Break into the debugger if a break is detected */
- BREAKPOINT();
-
- /* Clear */
- sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
- }
-}
-
#endif /* CONFIG_SH_KGDB */
#if defined(__H8300S__)
enum { sci_disable, sci_enable };
-static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl)
+static void h8300_sci_config(struct uart_port* port, unsigned int ctrl)
{
volatile unsigned char *mstpcrl=(volatile unsigned char *)MSTPCRL;
int ch = (port->mapbase - SMR0) >> 3;
@@ -314,32 +233,66 @@ static void h8300_sci_enable(struct uart_port* port, unsigned int ctrl)
*mstpcrl &= ~mask;
}
}
+
+static inline void h8300_sci_enable(struct uart_port *port)
+{
+ h8300_sci_config(port, sci_enable);
+}
+
+static inline void h8300_sci_disable(struct uart_port *port)
+{
+ h8300_sci_config(port, sci_disable);
+}
#endif
-#if defined(SCI_ONLY) || defined(SCI_AND_SCIF)
-#if defined(__H8300H__) || defined(__H8300S__)
+#if defined(SCI_ONLY) || defined(SCI_AND_SCIF) && \
+ defined(__H8300H__) || defined(__H8300S__)
static void sci_init_pins_sci(struct uart_port* port, unsigned int cflag)
{
int ch = (port->mapbase - SMR0) >> 3;
/* set DDR regs */
- H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].rx,H8300_GPIO_INPUT);
- H8300_GPIO_DDR(h8300_sci_pins[ch].port,h8300_sci_pins[ch].tx,H8300_GPIO_OUTPUT);
+ H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+ h8300_sci_pins[ch].rx,
+ H8300_GPIO_INPUT);
+ H8300_GPIO_DDR(h8300_sci_pins[ch].port,
+ h8300_sci_pins[ch].tx,
+ H8300_GPIO_OUTPUT);
+
/* tx mark output*/
H8300_SCI_DR(ch) |= h8300_sci_pins[ch].tx;
}
+#else
+#define sci_init_pins_sci NULL
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
+{
+ unsigned int fcr_val = 0;
+
+ if (cflag & CRTSCTS)
+ fcr_val |= SCFCR_MCE;
+
+ sci_out(port, SCFCR, fcr_val);
+}
+#else
+#define sci_init_pins_irda NULL
#endif
+
+#ifdef SCI_ONLY
+#define sci_init_pins_scif NULL
#endif
#if defined(SCIF_ONLY) || defined(SCI_AND_SCIF)
-#if defined(CONFIG_CPU_SUBTYPE_SH7300)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
/* SH7300 doesn't use RTS/CTS */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
sci_out(port, SCFCR, 0);
}
#elif defined(CONFIG_CPU_SH3)
-/* For SH7705, SH7707, SH7709, SH7709A, SH7729 */
+/* For SH7705, SH7706, SH7707, SH7709, SH7709A, SH7729 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
unsigned int fcr_val = 0;
@@ -366,20 +319,7 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
sci_out(port, SCFCR, fcr_val);
}
-
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
-static void sci_init_pins_irda(struct uart_port *port, unsigned int cflag)
-{
- unsigned int fcr_val = 0;
-
- if (cflag & CRTSCTS)
- fcr_val |= SCFCR_MCE;
-
- sci_out(port, SCFCR, fcr_val);
-}
-#endif
#else
-
/* For SH7750 */
static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
{
@@ -388,7 +328,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
if (cflag & CRTSCTS) {
fcr_val |= SCFCR_MCE;
} else {
-#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#ifdef CONFIG_CPU_SUBTYPE_SH7343
+ /* Nothing */
+#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */
#else
ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */
@@ -396,10 +338,41 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag)
}
sci_out(port, SCFCR, fcr_val);
}
+#endif
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
+static inline int scif_txroom(struct uart_port *port)
+{
+ return SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
+}
+
+static inline int scif_rxroom(struct uart_port *port)
+{
+ return sci_in(port, SCRFDR) & 0x7f;
+}
+#else
+static inline int scif_txroom(struct uart_port *port)
+{
+ return SCIF_TXROOM_MAX - (sci_in(port, SCFDR) >> 8);
+}
+static inline int scif_rxroom(struct uart_port *port)
+{
+ return sci_in(port, SCFDR) & SCIF_RFDC_MASK;
+}
#endif
#endif /* SCIF_ONLY || SCI_AND_SCIF */
+static inline int sci_txroom(struct uart_port *port)
+{
+ return ((sci_in(port, SCxSR) & SCI_TDRE) != 0);
+}
+
+static inline int sci_rxroom(struct uart_port *port)
+{
+ return ((sci_in(port, SCxSR) & SCxSR_RDxF(port)) != 0);
+}
+
/* ********************************************************************** *
* the interrupt related routines *
* ********************************************************************** */
@@ -408,14 +381,12 @@ static void sci_transmit_chars(struct uart_port *port)
{
struct circ_buf *xmit = &port->info->xmit;
unsigned int stopped = uart_tx_stopped(port);
- unsigned long flags;
unsigned short status;
unsigned short ctrl;
- int count, txroom;
+ int count;
status = sci_in(port, SCxSR);
if (!(status & SCxSR_TDxE(port))) {
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
if (uart_circ_empty(xmit)) {
ctrl &= ~SCI_CTRL_FLAGS_TIE;
@@ -423,25 +394,15 @@ static void sci_transmit_chars(struct uart_port *port)
ctrl |= SCI_CTRL_FLAGS_TIE;
}
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
return;
}
-#if !defined(SCI_ONLY)
- if (port->type == PORT_SCIF) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
- txroom = SCIF_TXROOM_MAX - (sci_in(port, SCTFDR) & 0x7f);
-#else
- txroom = SCIF_TXROOM_MAX - (sci_in(port, SCFDR)>>8);
-#endif
- } else {
- txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
- }
-#else
- txroom = (sci_in(port, SCxSR) & SCI_TDRE)?1:0;
+#ifndef SCI_ONLY
+ if (port->type == PORT_SCIF)
+ count = scif_txroom(port);
+ else
#endif
-
- count = txroom;
+ count = sci_txroom(port);
do {
unsigned char c;
@@ -468,7 +429,6 @@ static void sci_transmit_chars(struct uart_port *port)
if (uart_circ_empty(xmit)) {
sci_stop_tx(port);
} else {
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
#if !defined(SCI_ONLY)
@@ -480,16 +440,15 @@ static void sci_transmit_chars(struct uart_port *port)
ctrl |= SCI_CTRL_FLAGS_TIE;
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
}
/* On SH3, SCIF may read end-of-break as a space->mark char */
#define STEPFN(c) ({int __c=(c); (((__c-1)|(__c)) == -1); })
-static inline void sci_receive_chars(struct uart_port *port,
- struct pt_regs *regs)
+static inline void sci_receive_chars(struct uart_port *port)
{
+ struct sci_port *sci_port = (struct sci_port *)port;
struct tty_struct *tty = port->info->tty;
int i, count, copied = 0;
unsigned short status;
@@ -501,18 +460,11 @@ static inline void sci_receive_chars(struct uart_port *port,
while (1) {
#if !defined(SCI_ONLY)
- if (port->type == PORT_SCIF) {
-#if defined(CONFIG_CPU_SUBTYPE_SH7760) || defined(CONFIG_CPU_SUBTYPE_SH7780)
- count = sci_in(port, SCRFDR) & 0x7f;
-#else
- count = sci_in(port, SCFDR)&SCIF_RFDC_MASK ;
-#endif
- } else {
- count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
- }
-#else
- count = (sci_in(port, SCxSR)&SCxSR_RDxF(port))?1:0;
+ if (port->type == PORT_SCIF)
+ count = scif_rxroom(port);
+ else
#endif
+ count = sci_rxroom(port);
/* Don't copy more bytes than there is room for in the buffer */
count = tty_buffer_request_room(tty, count);
@@ -523,11 +475,10 @@ static inline void sci_receive_chars(struct uart_port *port,
if (port->type == PORT_SCI) {
char c = sci_in(port, SCxRDR);
- if(((struct sci_port *)port)->break_flag
- || uart_handle_sysrq_char(port, c, regs)) {
+ if (uart_handle_sysrq_char(port, c) || sci_port->break_flag)
count = 0;
- } else {
- tty_insert_flip_char(tty, c, TTY_NORMAL);
+ else {
+ tty_insert_flip_char(tty, c, TTY_NORMAL);
}
} else {
for (i=0; i<count; i++) {
@@ -535,22 +486,24 @@ static inline void sci_receive_chars(struct uart_port *port,
status = sci_in(port, SCxSR);
#if defined(CONFIG_CPU_SH3)
/* Skip "chars" during break */
- if (((struct sci_port *)port)->break_flag) {
+ if (sci_port->break_flag) {
if ((c == 0) &&
(status & SCxSR_FER(port))) {
count--; i--;
continue;
}
+
/* Nonzero => end-of-break */
pr_debug("scif: debounce<%02x>\n", c);
- ((struct sci_port *)port)->break_flag = 0;
+ sci_port->break_flag = 0;
+
if (STEPFN(c)) {
count--; i--;
continue;
}
}
#endif /* CONFIG_CPU_SH3 */
- if (uart_handle_sysrq_char(port, c, regs)) {
+ if (uart_handle_sysrq_char(port, c)) {
count--; i--;
continue;
}
@@ -600,15 +553,17 @@ static void sci_schedule_break_timer(struct sci_port *port)
/* Ensure that two consecutive samples find the break over. */
static void sci_break_timer(unsigned long data)
{
- struct sci_port * port = (struct sci_port *)data;
- if(sci_rxd_in(&port->port) == 0) {
+ struct sci_port *port = (struct sci_port *)data;
+
+ if (sci_rxd_in(&port->port) == 0) {
port->break_flag = 1;
- sci_schedule_break_timer(port);
- } else if(port->break_flag == 1){
+ sci_schedule_break_timer(port);
+ } else if (port->break_flag == 1) {
/* break is over. */
port->break_flag = 2;
- sci_schedule_break_timer(port);
- } else port->break_flag = 0;
+ sci_schedule_break_timer(port);
+ } else
+ port->break_flag = 0;
}
static inline int sci_handle_errors(struct uart_port *port)
@@ -617,40 +572,41 @@ static inline int sci_handle_errors(struct uart_port *port)
unsigned short status = sci_in(port, SCxSR);
struct tty_struct *tty = port->info->tty;
- if (status&SCxSR_ORER(port)) {
+ if (status & SCxSR_ORER(port)) {
/* overrun error */
- if(tty_insert_flip_char(tty, 0, TTY_OVERRUN))
+ if (tty_insert_flip_char(tty, 0, TTY_OVERRUN))
copied++;
pr_debug("sci: overrun error\n");
}
- if (status&SCxSR_FER(port)) {
+ if (status & SCxSR_FER(port)) {
if (sci_rxd_in(port) == 0) {
/* Notify of BREAK */
- struct sci_port * sci_port = (struct sci_port *)port;
- if(!sci_port->break_flag) {
- sci_port->break_flag = 1;
- sci_schedule_break_timer((struct sci_port *)port);
+ struct sci_port *sci_port = (struct sci_port *)port;
+
+ if (!sci_port->break_flag) {
+ sci_port->break_flag = 1;
+ sci_schedule_break_timer(sci_port);
+
/* Do sysrq handling. */
- if(uart_handle_break(port))
+ if (uart_handle_break(port))
return 0;
pr_debug("sci: BREAK detected\n");
- if(tty_insert_flip_char(tty, 0, TTY_BREAK))
+ if (tty_insert_flip_char(tty, 0, TTY_BREAK))
copied++;
}
- }
- else {
+ } else {
/* frame error */
- if(tty_insert_flip_char(tty, 0, TTY_FRAME))
+ if (tty_insert_flip_char(tty, 0, TTY_FRAME))
copied++;
pr_debug("sci: frame error\n");
}
}
- if (status&SCxSR_PER(port)) {
- if(tty_insert_flip_char(tty, 0, TTY_PARITY))
- copied++;
+ if (status & SCxSR_PER(port)) {
/* parity error */
+ if (tty_insert_flip_char(tty, 0, TTY_PARITY))
+ copied++;
pr_debug("sci: parity error\n");
}
@@ -673,7 +629,7 @@ static inline int sci_handle_breaks(struct uart_port *port)
s->break_flag = 1;
#endif
/* Notify of BREAK */
- if(tty_insert_flip_char(tty, 0, TTY_BREAK))
+ if (tty_insert_flip_char(tty, 0, TTY_BREAK))
copied++;
pr_debug("sci: BREAK detected\n");
}
@@ -682,7 +638,7 @@ static inline int sci_handle_breaks(struct uart_port *port)
/* XXX: Handle SCIF overrun error */
if (port->type == PORT_SCIF && (sci_in(port, SCLSR) & SCIF_ORER) != 0) {
sci_out(port, SCLSR, 0);
- if(tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
+ if (tty_insert_flip_char(tty, 0, TTY_OVERRUN)) {
copied++;
pr_debug("sci: overrun error\n");
}
@@ -691,32 +647,33 @@ static inline int sci_handle_breaks(struct uart_port *port)
if (copied)
tty_flip_buffer_push(tty);
+
return copied;
}
-static irqreturn_t sci_rx_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sci_rx_interrupt(int irq, void *port)
{
- struct uart_port *port = ptr;
-
/* I think sci_receive_chars has to be called irrespective
* of whether the I_IXOFF is set, otherwise, how is the interrupt
* to be disabled?
*/
- sci_receive_chars(port, regs);
+ sci_receive_chars(port);
return IRQ_HANDLED;
}
-static irqreturn_t sci_tx_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sci_tx_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
+ spin_lock_irq(&port->lock);
sci_transmit_chars(port);
+ spin_unlock_irq(&port->lock);
return IRQ_HANDLED;
}
-static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sci_er_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
@@ -738,29 +695,35 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr, struct pt_regs *regs)
pr_debug("scif: overrun error\n");
}
#endif
- sci_rx_interrupt(irq, ptr, regs);
+ sci_rx_interrupt(irq, ptr);
}
sci_out(port, SCxSR, SCxSR_ERROR_CLEAR(port));
/* Kick the transmission */
- sci_tx_interrupt(irq, ptr, regs);
+ sci_tx_interrupt(irq, ptr);
return IRQ_HANDLED;
}
-static irqreturn_t sci_br_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sci_br_interrupt(int irq, void *ptr)
{
struct uart_port *port = ptr;
/* Handle BREAKs */
sci_handle_breaks(port);
+
+#ifdef CONFIG_SH_KGDB
+ /* Break into the debugger if a break is detected */
+ BREAKPOINT();
+#endif
+
sci_out(port, SCxSR, SCxSR_BREAK_CLEAR(port));
return IRQ_HANDLED;
}
-static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs)
+static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
{
unsigned short ssr_status, scr_status;
struct uart_port *port = ptr;
@@ -769,17 +732,17 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs)
scr_status = sci_in(port,SCSCR);
/* Tx Interrupt */
- if ((ssr_status&0x0020) && (scr_status&0x0080))
- sci_tx_interrupt(irq, ptr, regs);
+ if ((ssr_status & 0x0020) && (scr_status & 0x0080))
+ sci_tx_interrupt(irq, ptr);
/* Rx Interrupt */
- if ((ssr_status&0x0002) && (scr_status&0x0040))
- sci_rx_interrupt(irq, ptr, regs);
+ if ((ssr_status & 0x0002) && (scr_status & 0x0040))
+ sci_rx_interrupt(irq, ptr);
/* Error Interrupt */
- if ((ssr_status&0x0080) && (scr_status&0x0400))
- sci_er_interrupt(irq, ptr, regs);
+ if ((ssr_status & 0x0080) && (scr_status & 0x0400))
+ sci_er_interrupt(irq, ptr);
/* Break Interrupt */
- if ((ssr_status&0x0010) && (scr_status&0x0200))
- sci_br_interrupt(irq, ptr, regs);
+ if ((ssr_status & 0x0010) && (scr_status & 0x0200))
+ sci_br_interrupt(irq, ptr);
return IRQ_HANDLED;
}
@@ -789,7 +752,8 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr, struct pt_regs *regs)
* Here we define a transistion notifier so that we can update all of our
* ports' baud rate when the peripheral clock changes.
*/
-static int sci_notifier(struct notifier_block *self, unsigned long phase, void *p)
+static int sci_notifier(struct notifier_block *self,
+ unsigned long phase, void *p)
{
struct cpufreq_freqs *freqs = p;
int i;
@@ -816,8 +780,9 @@ static int sci_notifier(struct notifier_block *self, unsigned long phase, void *
clk_put(clk);
}
- printk("%s: got a postchange notification for cpu %d (old %d, new %d)\n",
- __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
+ printk(KERN_INFO "%s: got a postchange notification "
+ "for cpu %d (old %d, new %d)\n",
+ __FUNCTION__, freqs->cpu, freqs->old, freqs->new);
}
return NOTIFY_OK;
@@ -829,7 +794,7 @@ static struct notifier_block sci_nb = { &sci_notifier, NULL, 0 };
static int sci_request_irq(struct sci_port *port)
{
int i;
- irqreturn_t (*handlers[4])(int irq, void *ptr, struct pt_regs *regs) = {
+ irqreturn_t (*handlers[4])(int irq, void *ptr) = {
sci_er_interrupt, sci_rx_interrupt, sci_tx_interrupt,
sci_br_interrupt,
};
@@ -841,8 +806,9 @@ static int sci_request_irq(struct sci_port *port)
printk(KERN_ERR "sci: Cannot allocate irq.(IRQ=0)\n");
return -ENODEV;
}
- if (request_irq(port->irqs[0], sci_mpxed_interrupt, IRQF_DISABLED,
- "sci", port)) {
+
+ if (request_irq(port->irqs[0], sci_mpxed_interrupt,
+ IRQF_DISABLED, "sci", port)) {
printk(KERN_ERR "sci: Cannot allocate irq.\n");
return -ENODEV;
}
@@ -850,8 +816,8 @@ static int sci_request_irq(struct sci_port *port)
for (i = 0; i < ARRAY_SIZE(handlers); i++) {
if (!port->irqs[i])
continue;
- if (request_irq(port->irqs[i], handlers[i], IRQF_DISABLED,
- desc[i], port)) {
+ if (request_irq(port->irqs[i], handlers[i],
+ IRQF_DISABLED, desc[i], port)) {
printk(KERN_ERR "sci: Cannot allocate irq.\n");
return -ENODEV;
}
@@ -903,50 +869,42 @@ static unsigned int sci_get_mctrl(struct uart_port *port)
static void sci_start_tx(struct uart_port *port)
{
- struct sci_port *s = &sci_ports[port->line];
+ unsigned short ctrl;
- disable_irq(s->irqs[SCIx_TXI_IRQ]);
- sci_transmit_chars(port);
- enable_irq(s->irqs[SCIx_TXI_IRQ]);
+ /* Set TIE (Transmit Interrupt Enable) bit in SCSCR */
+ ctrl = sci_in(port, SCSCR);
+ ctrl |= SCI_CTRL_FLAGS_TIE;
+ sci_out(port, SCSCR, ctrl);
}
static void sci_stop_tx(struct uart_port *port)
{
- unsigned long flags;
unsigned short ctrl;
/* Clear TIE (Transmit Interrupt Enable) bit in SCSCR */
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
ctrl &= ~SCI_CTRL_FLAGS_TIE;
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
static void sci_start_rx(struct uart_port *port, unsigned int tty_start)
{
- unsigned long flags;
unsigned short ctrl;
/* Set RIE (Receive Interrupt Enable) bit in SCSCR */
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
ctrl |= SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE;
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
static void sci_stop_rx(struct uart_port *port)
{
- unsigned long flags;
unsigned short ctrl;
/* Clear RIE (Receive Interrupt Enable) bit in SCSCR */
- local_irq_save(flags);
ctrl = sci_in(port, SCSCR);
ctrl &= ~(SCI_CTRL_FLAGS_RIE | SCI_CTRL_FLAGS_REIE);
sci_out(port, SCSCR, ctrl);
- local_irq_restore(flags);
}
static void sci_enable_ms(struct uart_port *port)
@@ -963,9 +921,8 @@ static int sci_startup(struct uart_port *port)
{
struct sci_port *s = &sci_ports[port->line];
-#if defined(__H8300S__)
- h8300_sci_enable(port, sci_enable);
-#endif
+ if (s->enable)
+ s->enable(port);
sci_request_irq(s);
sci_start_tx(port);
@@ -982,9 +939,8 @@ static void sci_shutdown(struct uart_port *port)
sci_stop_tx(port);
sci_free_irq(s);
-#if defined(__H8300S__)
- h8300_sci_enable(port, sci_disable);
-#endif
+ if (s->disable)
+ s->disable(port);
}
static void sci_set_termios(struct uart_port *port, struct termios *termios,
@@ -997,6 +953,23 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16);
+ switch (baud) {
+ case 0:
+ t = -1;
+ break;
+ default:
+ {
+#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
+ struct clk *clk = clk_get("module_clk");
+ t = SCBRR_VALUE(baud, clk_get_rate(clk));
+ clk_put(clk);
+#else
+ t = SCBRR_VALUE(baud);
+#endif
+ }
+ break;
+ }
+
spin_lock_irqsave(&port->lock, flags);
do {
@@ -1006,9 +979,8 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
sci_out(port, SCSCR, 0x00); /* TE=0, RE=0, CKE1=0 */
#if !defined(SCI_ONLY)
- if (port->type == PORT_SCIF) {
+ if (port->type == PORT_SCIF)
sci_out(port, SCFCR, SCFCR_RFRST | SCFCR_TFRST);
- }
#endif
smr_val = sci_in(port, SCSMR) & 3;
@@ -1025,23 +997,6 @@ static void sci_set_termios(struct uart_port *port, struct termios *termios,
sci_out(port, SCSMR, smr_val);
- switch (baud) {
- case 0:
- t = -1;
- break;
- default:
- {
-#if defined(CONFIG_SUPERH) && !defined(CONFIG_SUPERH64)
- struct clk *clk = clk_get("module_clk");
- t = SCBRR_VALUE(baud, clk_get_rate(clk));
- clk_put(clk);
-#else
- t = SCBRR_VALUE(baud);
-#endif
- }
- break;
- }
-
if (t > 0) {
if(t >= 256) {
sci_out(port, SCSMR, (sci_in(port, SCSMR) & ~3) | 1);
@@ -1092,11 +1047,23 @@ static void sci_config_port(struct uart_port *port, int flags)
port->type = s->type;
+ switch (port->type) {
+ case PORT_SCI:
+ s->init_pins = sci_init_pins_sci;
+ break;
+ case PORT_SCIF:
+ s->init_pins = sci_init_pins_scif;
+ break;
+ case PORT_IRDA:
+ s->init_pins = sci_init_pins_irda;
+ break;
+ }
+
#if defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
if (port->mapbase == 0)
port->mapbase = onchip_remap(SCIF_ADDR_SH5, 1024, "SCIF");
- port->membase = (void *)port->mapbase;
+ port->membase = (void __iomem *)port->mapbase;
#endif
}
@@ -1132,412 +1099,61 @@ static struct uart_ops sci_uart_ops = {
.verify_port = sci_verify_port,
};
-static struct sci_port sci_ports[] = {
-#if defined(CONFIG_CPU_SUBTYPE_SH7708)
- {
- .port = {
- .membase = (void *)0xfffffe80,
- .mapbase = 0xfffffe80,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = SCI_IRQS,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7705)
- {
- .port = {
- .membase = (void *)SCIF0,
- .mapbase = SCIF0,
- .iotype = UPIO_MEM,
- .irq = 55,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH3_IRDA_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)SCIF2,
- .mapbase = SCIF2,
- .iotype = UPIO_MEM,
- .irq = 59,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH3_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
- {
- .port = {
- .membase = (void *)0xfffffe80,
- .mapbase = 0xfffffe80,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = SCI_IRQS,
- },
- {
- .port = {
- .membase = (void *)0xa4000150,
- .mapbase = 0xa4000150,
- .iotype = UPIO_MEM,
- .irq = 59,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH3_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xa4000140,
- .mapbase = 0xa4000140,
- .iotype = UPIO_MEM,
- .irq = 55,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_IRDA,
- .irqs = SH3_IRDA_IRQS,
- .init_pins = sci_init_pins_irda,
- }
-#elif defined(CONFIG_CPU_SUBTYPE_SH7300)
- {
- .port = {
- .membase = (void *)0xA4430000,
- .mapbase = 0xA4430000,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7300_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH73180_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
- {
- .port = {
- .membase = (void *)0xffe80000,
- .mapbase = 0xffe80000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH4_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 25,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = SCI_IRQS,
- },
- {
- .port = {
- .membase = (void *)0xffe80000,
- .mapbase = 0xffe80000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH4_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7760)
- {
- .port = {
- .membase = (void *)0xfe600000,
- .mapbase = 0xfe600000,
- .iotype = UPIO_MEM,
- .irq = 55,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7760_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xfe610000,
- .mapbase = 0xfe610000,
- .iotype = UPIO_MEM,
- .irq = 75,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH7760_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xfe620000,
- .mapbase = 0xfe620000,
- .iotype = UPIO_MEM,
- .irq = 79,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCIF,
- .irqs = SH7760_SCIF2_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 26,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = STB1_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xffe80000,
- .mapbase = 0xffe80000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH4_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH5_101) || defined(CONFIG_CPU_SUBTYPE_SH5_103)
- {
- .port = {
- .iotype = UPIO_MEM,
- .irq = 42,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH5_SCIF_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_H83007) || defined(CONFIG_H83068)
- {
- .port = {
- .membase = (void *)0x00ffffb0,
- .mapbase = 0x00ffffb0,
- .iotype = UPIO_MEM,
- .irq = 54,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = H8300H_SCI_IRQS0,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffffb8,
- .mapbase = 0x00ffffb8,
- .iotype = UPIO_MEM,
- .irq = 58,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCI,
- .irqs = H8300H_SCI_IRQS1,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffffc0,
- .mapbase = 0x00ffffc0,
- .iotype = UPIO_MEM,
- .irq = 62,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCI,
- .irqs = H8300H_SCI_IRQS2,
- .init_pins = sci_init_pins_sci,
- },
-#elif defined(CONFIG_H8S2678)
- {
- .port = {
- .membase = (void *)0x00ffff78,
- .mapbase = 0x00ffff78,
- .iotype = UPIO_MEM,
- .irq = 90,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCI,
- .irqs = H8S_SCI_IRQS0,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffff80,
- .mapbase = 0x00ffff80,
- .iotype = UPIO_MEM,
- .irq = 94,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCI,
- .irqs = H8S_SCI_IRQS1,
- .init_pins = sci_init_pins_sci,
- },
- {
- .port = {
- .membase = (void *)0x00ffff88,
- .mapbase = 0x00ffff88,
- .iotype = UPIO_MEM,
- .irq = 98,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCI,
- .irqs = H8S_SCI_IRQS2,
- .init_pins = sci_init_pins_sci,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7770)
- {
- .port = {
- .membase = (void *)0xff923000,
- .mapbase = 0xff923000,
- .iotype = UPIO_MEM,
- .irq = 61,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7770_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xff924000,
- .mapbase = 0xff924000,
- .iotype = UPIO_MEM,
- .irq = 62,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH7770_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xff925000,
- .mapbase = 0xff925000,
- .iotype = UPIO_MEM,
- .irq = 63,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 2,
- },
- .type = PORT_SCIF,
- .irqs = SH7770_SCIF2_IRQS,
- .init_pins = sci_init_pins_scif,
- },
-#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
- {
- .port = {
- .membase = (void *)0xffe00000,
- .mapbase = 0xffe00000,
- .iotype = UPIO_MEM,
- .irq = 43,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 0,
- },
- .type = PORT_SCIF,
- .irqs = SH7780_SCIF0_IRQS,
- .init_pins = sci_init_pins_scif,
- },
- {
- .port = {
- .membase = (void *)0xffe10000,
- .mapbase = 0xffe10000,
- .iotype = UPIO_MEM,
- .irq = 79,
- .ops = &sci_uart_ops,
- .flags = UPF_BOOT_AUTOCONF,
- .line = 1,
- },
- .type = PORT_SCIF,
- .irqs = SH7780_SCIF1_IRQS,
- .init_pins = sci_init_pins_scif,
- },
+static void __init sci_init_ports(void)
+{
+ static int first = 1;
+ int i;
+
+ if (!first)
+ return;
+
+ first = 0;
+
+ for (i = 0; i < SCI_NPORTS; i++) {
+ sci_ports[i].port.ops = &sci_uart_ops;
+ sci_ports[i].port.iotype = UPIO_MEM;
+ sci_ports[i].port.line = i;
+ sci_ports[i].port.fifosize = 1;
+
+#if defined(__H8300H__) || defined(__H8300S__)
+#ifdef __H8300S__
+ sci_ports[i].enable = h8300_sci_enable;
+ sci_ports[i].disable = h8300_sci_disable;
+#endif
+ sci_ports[i].port.uartclk = CONFIG_CPU_CLOCK;
+#elif defined(CONFIG_SUPERH64)
+ sci_ports[i].port.uartclk = current_cpu_data.module_clock * 16;
#else
-#error "CPU subtype not defined"
+ /*
+ * XXX: We should use a proper SCI/SCIF clock
+ */
+ {
+ struct clk *clk = clk_get("module_clk");
+ sci_ports[i].port.uartclk = clk_get_rate(clk) * 16;
+ clk_put(clk);
+ }
#endif
-};
+
+ sci_ports[i].break_timer.data = (unsigned long)&sci_ports[i];
+ sci_ports[i].break_timer.function = sci_break_timer;
+
+ init_timer(&sci_ports[i].break_timer);
+ }
+}
+
+int __init early_sci_setup(struct uart_port *port)
+{
+ if (unlikely(port->line > SCI_NPORTS))
+ return -ENODEV;
+
+ sci_init_ports();
+
+ sci_ports[port->line].port.membase = port->membase;
+ sci_ports[port->line].port.mapbase = port->mapbase;
+ sci_ports[port->line].port.type = port->type;
+
+ return 0;
+}
#ifdef CONFIG_SERIAL_SH_SCI_CONSOLE
/*
@@ -1559,34 +1175,38 @@ static int __init serial_console_setup(struct console *co, char *options)
int flow = 'n';
int ret;
+ /*
+ * Check whether an invalid uart number has been specified, and
+ * if so, search for the first available port that does have
+ * console support.
+ */
+ if (co->index >= SCI_NPORTS)
+ co->index = 0;
+
serial_console_port = &sci_ports[co->index];
port = &serial_console_port->port;
- port->type = serial_console_port->type;
-
-#ifdef CONFIG_SUPERH64
- /* This is especially needed on sh64 to remap the SCIF */
- sci_config_port(port, 0);
-#endif
/*
- * We need to set the initial uartclk here, since otherwise it will
- * only ever be setup at sci_init() time.
+ * Also need to check port->type, we don't actually have any
+ * UPIO_PORT ports, but uart_report_port() handily misreports
+ * it anyways if we don't have a port available by the time this is
+ * called.
*/
-#if defined(__H8300H__) || defined(__H8300S__)
- port->uartclk = CONFIG_CPU_CLOCK;
+ if (!port->type)
+ return -ENODEV;
+ if (!port->membase || !port->mapbase)
+ return -ENODEV;
+
+ spin_lock_init(&port->lock);
+
+ port->type = serial_console_port->type;
+
+ if (port->flags & UPF_IOREMAP)
+ sci_config_port(port, 0);
+
+ if (serial_console_port->enable)
+ serial_console_port->enable(port);
-#if defined(__H8300S__)
- h8300_sci_enable(port, sci_enable);
-#endif
-#elif defined(CONFIG_SUPERH64)
- port->uartclk = current_cpu_data.module_clock * 16;
-#else
- {
- struct clk *clk = clk_get("module_clk");
- port->uartclk = clk_get_rate(clk) * 16;
- clk_put(clk);
- }
-#endif
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
@@ -1604,17 +1224,17 @@ static struct console serial_console = {
.device = uart_console_device,
.write = serial_console_write,
.setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
+ .flags = CON_PRINTBUFFER,
.index = -1,
.data = &sci_uart_driver,
};
static int __init sci_console_init(void)
{
+ sci_init_ports();
register_console(&serial_console);
return 0;
}
-
console_initcall(sci_console_init);
#endif /* CONFIG_SERIAL_SH_SCI_CONSOLE */
@@ -1649,6 +1269,8 @@ int __init kgdb_console_setup(struct console *co, char *options)
int parity = 'n';
int flow = 'n';
+ spin_lock_init(&port->lock);
+
if (co->index != kgdb_portnum)
co->index = kgdb_portnum;
@@ -1677,10 +1299,10 @@ static struct console kgdb_console = {
/* Register the KGDB console so we get messages (d'oh!) */
static int __init kgdb_console_init(void)
{
+ sci_init_ports();
register_console(&kgdb_console);
return 0;
}
-
console_initcall(kgdb_console_init);
#endif /* CONFIG_SH_KGDB_CONSOLE */
@@ -1701,60 +1323,132 @@ static struct uart_driver sci_uart_driver = {
.dev_name = "ttySC",
.major = SCI_MAJOR,
.minor = SCI_MINOR_START,
+ .nr = SCI_NPORTS,
.cons = SCI_CONSOLE,
};
-static int __init sci_init(void)
+/*
+ * Register a set of serial devices attached to a platform device. The
+ * list is terminated with a zero flags entry, which means we expect
+ * all entries to have at least UPF_BOOT_AUTOCONF set. Platforms that need
+ * remapping (such as sh64) should also set UPF_IOREMAP.
+ */
+static int __devinit sci_probe(struct platform_device *dev)
{
- int chan, ret;
+ struct plat_sci_port *p = dev->dev.platform_data;
+ int i;
- printk("%s", banner);
+ for (i = 0; p && p->flags != 0 && i < SCI_NPORTS; p++, i++) {
+ struct sci_port *sciport = &sci_ports[i];
- sci_uart_driver.nr = ARRAY_SIZE(sci_ports);
+ sciport->port.mapbase = p->mapbase;
- ret = uart_register_driver(&sci_uart_driver);
- if (ret == 0) {
- for (chan = 0; chan < SCI_NPORTS; chan++) {
- struct sci_port *sciport = &sci_ports[chan];
+ /*
+ * For the simple (and majority of) cases where we don't need
+ * to do any remapping, just cast the cookie directly.
+ */
+ if (p->mapbase && !p->membase && !(p->flags & UPF_IOREMAP))
+ p->membase = (void __iomem *)p->mapbase;
-#if defined(__H8300H__) || defined(__H8300S__)
- sciport->port.uartclk = CONFIG_CPU_CLOCK;
-#elif defined(CONFIG_SUPERH64)
- sciport->port.uartclk = current_cpu_data.module_clock * 16;
-#else
- struct clk *clk = clk_get("module_clk");
- sciport->port.uartclk = clk_get_rate(clk) * 16;
- clk_put(clk);
-#endif
- uart_add_one_port(&sci_uart_driver, &sciport->port);
- sciport->break_timer.data = (unsigned long)sciport;
- sciport->break_timer.function = sci_break_timer;
- init_timer(&sciport->break_timer);
- }
+ sciport->port.membase = p->membase;
+
+ sciport->port.irq = p->irqs[SCIx_TXI_IRQ];
+ sciport->port.flags = p->flags;
+ sciport->port.dev = &dev->dev;
+
+ sciport->type = sciport->port.type = p->type;
+
+ memcpy(&sciport->irqs, &p->irqs, sizeof(p->irqs));
+
+ uart_add_one_port(&sci_uart_driver, &sciport->port);
}
#ifdef CONFIG_CPU_FREQ
cpufreq_register_notifier(&sci_nb, CPUFREQ_TRANSITION_NOTIFIER);
- printk("sci: CPU frequency notifier registered\n");
+ dev_info(&dev->dev, "sci: CPU frequency notifier registered\n");
#endif
#ifdef CONFIG_SH_STANDARD_BIOS
sh_bios_gdb_detach();
#endif
- return ret;
+ return 0;
}
-static void __exit sci_exit(void)
+static int __devexit sci_remove(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < SCI_NPORTS; i++)
+ uart_remove_one_port(&sci_uart_driver, &sci_ports[i].port);
+
+ return 0;
+}
+
+static int sci_suspend(struct platform_device *dev, pm_message_t state)
{
- int chan;
+ int i;
+
+ for (i = 0; i < SCI_NPORTS; i++) {
+ struct sci_port *p = &sci_ports[i];
+
+ if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
+ uart_suspend_port(&sci_uart_driver, &p->port);
+ }
- for (chan = 0; chan < SCI_NPORTS; chan++)
- uart_remove_one_port(&sci_uart_driver, &sci_ports[chan].port);
+ return 0;
+}
+static int sci_resume(struct platform_device *dev)
+{
+ int i;
+
+ for (i = 0; i < SCI_NPORTS; i++) {
+ struct sci_port *p = &sci_ports[i];
+
+ if (p->type != PORT_UNKNOWN && p->port.dev == &dev->dev)
+ uart_resume_port(&sci_uart_driver, &p->port);
+ }
+
+ return 0;
+}
+
+static struct platform_driver sci_driver = {
+ .probe = sci_probe,
+ .remove = __devexit_p(sci_remove),
+ .suspend = sci_suspend,
+ .resume = sci_resume,
+ .driver = {
+ .name = "sh-sci",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sci_init(void)
+{
+ int ret;
+
+ printk(banner);
+
+ sci_init_ports();
+
+ ret = uart_register_driver(&sci_uart_driver);
+ if (likely(ret == 0)) {
+ ret = platform_driver_register(&sci_driver);
+ if (unlikely(ret))
+ uart_unregister_driver(&sci_uart_driver);
+ }
+
+ return ret;
+}
+
+static void __exit sci_exit(void)
+{
+ platform_driver_unregister(&sci_driver);
uart_unregister_driver(&sci_uart_driver);
}
module_init(sci_init);
module_exit(sci_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h
index ab320fa3237c..7ee992146ae9 100644
--- a/drivers/serial/sh-sci.h
+++ b/drivers/serial/sh-sci.h
@@ -11,6 +11,7 @@
* Modified to support H8/300 Series Yoshinori Sato (Feb 2004).
*/
#include <linux/serial_core.h>
+#include <asm/io.h>
#if defined(__H8300H__) || defined(__H8300S__)
#include <asm/gpio.h>
@@ -22,40 +23,13 @@
#endif
#endif
-/* Offsets into the sci_port->irqs array */
-#define SCIx_ERI_IRQ 0
-#define SCIx_RXI_IRQ 1
-#define SCIx_TXI_IRQ 2
-
-/* ERI, RXI, TXI, BRI */
-#define SCI_IRQS { 23, 24, 25, 0 }
-#define SH3_SCIF_IRQS { 56, 57, 59, 58 }
-#define SH3_IRDA_IRQS { 52, 53, 55, 54 }
-#define SH4_SCIF_IRQS { 40, 41, 43, 42 }
-#define STB1_SCIF1_IRQS {23, 24, 26, 25 }
-#define SH7760_SCIF0_IRQS { 52, 53, 55, 54 }
-#define SH7760_SCIF1_IRQS { 72, 73, 75, 74 }
-#define SH7760_SCIF2_IRQS { 76, 77, 79, 78 }
-#define SH7300_SCIF0_IRQS {80, 80, 80, 80 }
-#define SH73180_SCIF_IRQS {80, 81, 83, 82 }
-#define H8300H_SCI_IRQS0 {52, 53, 54, 0 }
-#define H8300H_SCI_IRQS1 {56, 57, 58, 0 }
-#define H8300H_SCI_IRQS2 {60, 61, 62, 0 }
-#define H8S_SCI_IRQS0 {88, 89, 90, 0 }
-#define H8S_SCI_IRQS1 {92, 93, 94, 0 }
-#define H8S_SCI_IRQS2 {96, 97, 98, 0 }
-#define SH5_SCIF_IRQS {39, 40, 42, 0 }
-#define SH7770_SCIF0_IRQS {61, 61, 61, 61 }
-#define SH7770_SCIF1_IRQS {62, 62, 62, 62 }
-#define SH7770_SCIF2_IRQS {63, 63, 63, 63 }
-#define SH7780_SCIF0_IRQS {40, 41, 43, 42 }
-#define SH7780_SCIF1_IRQS {76, 77, 79, 78 }
-
#if defined(CONFIG_CPU_SUBTYPE_SH7708)
# define SCSPTR 0xffffff7c /* 8 bit */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCI_ONLY
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706)
# define SCPCR 0xA4000116 /* 16 bit SCI and SCIF */
# define SCPDR 0xA4000136 /* 8 bit SCI and SCIF */
# define SCSCR_INIT(port) 0x30 /* TIE=0,RIE=0,TE=1,RE=1 */
@@ -99,12 +73,23 @@
# define SCPDR 0xA4050136 /* 16 bit SCIF */
# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+# define SCSPTR0 0xA4400000 /* 16 bit SCIF */
+# define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */
+# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH73180)
# define SCPDR 0xA4050138 /* 16 bit SCIF */
# define SCSPTR2 SCPDR
# define SCIF_ORER 0x0001 /* overrun error bit */
# define SCSCR_INIT(port) 0x0038 /* TIE=0,RIE=0,TE=1,RE=1 */
# define SCIF_ONLY
+#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+# define SCSPTR0 0xffe00010 /* 16 bit SCIF */
+# define SCSPTR1 0xffe10010 /* 16 bit SCIF */
+# define SCSPTR2 0xffe20010 /* 16 bit SCIF */
+# define SCSPTR3 0xffe30010 /* 16 bit SCIF */
+# define SCSCR_INIT(port) 0x32 /* TIE=0,RIE=0,TE=1,RE=1,REIE=0,CKE=1 */
+# define SCIF_ONLY
#elif defined(CONFIG_CPU_SUBTYPE_SH4_202)
# define SCSPTR2 0xffe80020 /* 16 bit SCIF */
# define SCIF_ORER 0x0001 /* overrun error bit */
@@ -145,7 +130,7 @@
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
# define SCSPTR0 0xffe00024 /* 16 bit SCIF */
# define SCSPTR1 0xffe10024 /* 16 bit SCIF */
-# define SCIF_OPER 0x0001 /* Overrun error bit */
+# define SCIF_ORER 0x0001 /* Overrun error bit */
# define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
# define SCIF_ONLY
#else
@@ -273,15 +258,6 @@
*/
#define SCI_EVENT_WRITE_WAKEUP 0
-struct sci_port {
- struct uart_port port;
- int type;
- unsigned char irqs[4]; /* ERI, RXI, TXI, BRI */
- void (*init_pins)(struct uart_port *port, unsigned int cflag);
- int break_flag;
- struct timer_list break_timer;
-};
-
#define SCI_IN(size, offset) \
unsigned int addr = port->mapbase + (offset); \
if ((size) == 8) { \
@@ -336,7 +312,9 @@ struct sci_port {
}
#ifdef CONFIG_CPU_SH3
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710)
#define SCIF_FNS(name, scif_offset, scif_size) \
CPU_SCIF_FNS(name, scif_offset, scif_size)
#else
@@ -362,7 +340,9 @@ struct sci_port {
CPU_SCIF_FNS(name, sh4_scif_offset, sh4_scif_size)
#endif
-#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710)
SCIF_FNS(SCSMR, 0x00, 16)
SCIF_FNS(SCBRR, 0x04, 8)
SCIF_FNS(SCSCR, 0x08, 16)
@@ -447,7 +427,9 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inb(SCSPTR)&0x01 ? 1 : 0; /* SCI */
return 1;
}
-#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709)
+#elif defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706)
static inline int sci_rxd_in(struct uart_port *port)
{
if (port->mapbase == 0xfffffe80)
@@ -467,6 +449,13 @@ static inline int sci_rxd_in(struct uart_port *port)
return ctrl_inb(SCPDR)&0x10 ? 1 : 0; /* SCIF */
return 1;
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == SCSPTR0)
+ return ctrl_inw(SCSPTR0 + 0x10) & 0x01 ? 1 : 0;
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \
defined(CONFIG_CPU_SUBTYPE_SH7751) || \
defined(CONFIG_CPU_SUBTYPE_SH4_202)
@@ -504,6 +493,19 @@ static inline int sci_rxd_in(struct uart_port *port)
{
return ctrl_inb(SCPDR)&0x01 ? 1 : 0; /* SCIF0 */
}
+#elif defined(CONFIG_CPU_SUBTYPE_SH7343)
+static inline int sci_rxd_in(struct uart_port *port)
+{
+ if (port->mapbase == 0xffe00000)
+ return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffe10000)
+ return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffe20000)
+ return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */
+ if (port->mapbase == 0xffe30000)
+ return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */
+ return 1;
+}
#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
static inline int sci_rxd_in(struct uart_port *port)
{
@@ -587,4 +589,3 @@ static inline int sci_rxd_in(struct uart_port *port)
#else /* Generic SH */
#define SCBRR_VALUE(bps, clk) ((clk+16*bps)/(32*bps)-1)
#endif
-
diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c
index 2f148e5b9255..956b2cf08e1e 100644
--- a/drivers/serial/sn_console.c
+++ b/drivers/serial/sn_console.c
@@ -447,7 +447,6 @@ static int sn_debug_printf(const char *fmt, ...)
/**
* sn_receive_chars - Grab characters, pass them to tty layer
* @port: Port to operate on
- * @regs: Saved registers (needed by uart_handle_sysrq_char)
* @flags: irq flags
*
* Note: If we're not registered with the serial core infrastructure yet,
@@ -455,8 +454,7 @@ static int sn_debug_printf(const char *fmt, ...)
*
*/
static void
-sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs,
- unsigned long flags)
+sn_receive_chars(struct sn_cons_port *port, unsigned long flags)
{
int ch;
struct tty_struct *tty;
@@ -494,7 +492,7 @@ sn_receive_chars(struct sn_cons_port *port, struct pt_regs *regs,
sysrq_requested = 0;
if (ch && time_before(jiffies, sysrq_timeout)) {
spin_unlock_irqrestore(&port->sc_port.lock, flags);
- handle_sysrq(ch, regs, NULL);
+ handle_sysrq(ch, NULL);
spin_lock_irqsave(&port->sc_port.lock, flags);
/* ignore actual sysrq command char */
continue;
@@ -615,10 +613,9 @@ static void sn_transmit_chars(struct sn_cons_port *port, int raw)
* sn_sal_interrupt - Handle console interrupts
* @irq: irq #, useful for debug statements
* @dev_id: our pointer to our port (sn_cons_port which contains the uart port)
- * @regs: Saved registers, used by sn_receive_chars for uart_handle_sysrq_char
*
*/
-static irqreturn_t sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sn_sal_interrupt(int irq, void *dev_id)
{
struct sn_cons_port *port = (struct sn_cons_port *)dev_id;
unsigned long flags;
@@ -629,7 +626,7 @@ static irqreturn_t sn_sal_interrupt(int irq, void *dev_id, struct pt_regs *regs)
spin_lock_irqsave(&port->sc_port.lock, flags);
if (status & SAL_CONSOLE_INTR_RECV) {
- sn_receive_chars(port, regs, flags);
+ sn_receive_chars(port, flags);
}
if (status & SAL_CONSOLE_INTR_XMIT) {
sn_transmit_chars(port, TRANSMIT_BUFFERED);
@@ -677,7 +674,7 @@ static void sn_sal_timer_poll(unsigned long data)
if (!port->sc_port.irq) {
spin_lock_irqsave(&port->sc_port.lock, flags);
if (sn_process_input)
- sn_receive_chars(port, NULL, flags);
+ sn_receive_chars(port, flags);
sn_transmit_chars(port, TRANSMIT_RAW);
spin_unlock_irqrestore(&port->sc_port.lock, flags);
mod_timer(&port->sc_timer,
diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c
index f851f0f44f9b..03941d27d15d 100644
--- a/drivers/serial/sunhv.c
+++ b/drivers/serial/sunhv.c
@@ -73,7 +73,7 @@ static inline long hypervisor_con_putchar(long ch)
static int hung_up = 0;
-static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *regs)
+static struct tty_struct *receive_chars(struct uart_port *port)
{
struct tty_struct *tty = NULL;
int saw_console_brk = 0;
@@ -106,7 +106,7 @@ static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *
}
if (tty == NULL) {
- uart_handle_sysrq_char(port, c, regs);
+ uart_handle_sysrq_char(port, c);
continue;
}
@@ -119,7 +119,7 @@ static struct tty_struct *receive_chars(struct uart_port *port, struct pt_regs *
flag = TTY_BREAK;
}
- if (uart_handle_sysrq_char(port, c, regs))
+ if (uart_handle_sysrq_char(port, c))
continue;
if ((port->ignore_status_mask & IGNORE_ALL) ||
@@ -161,14 +161,14 @@ static void transmit_chars(struct uart_port *port)
uart_write_wakeup(port);
}
-static irqreturn_t sunhv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sunhv_interrupt(int irq, void *dev_id)
{
struct uart_port *port = dev_id;
struct tty_struct *tty;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
- tty = receive_chars(port, regs);
+ tty = receive_chars(port);
transmit_chars(port);
spin_unlock_irqrestore(&port->lock, flags);
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index cfe20f730436..08a7cd6a3a0c 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -108,8 +108,7 @@ static __inline__ void sunsab_cec_wait(struct uart_sunsab_port *up)
static struct tty_struct *
receive_chars(struct uart_sunsab_port *up,
- union sab82532_irq_status *stat,
- struct pt_regs *regs)
+ union sab82532_irq_status *stat)
{
struct tty_struct *tty = NULL;
unsigned char buf[32];
@@ -161,7 +160,7 @@ receive_chars(struct uart_sunsab_port *up,
unsigned char ch = buf[i], flag;
if (tty == NULL) {
- uart_handle_sysrq_char(&up->port, ch, regs);
+ uart_handle_sysrq_char(&up->port, ch);
continue;
}
@@ -208,7 +207,7 @@ receive_chars(struct uart_sunsab_port *up,
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
continue;
if ((stat->sreg.isr0 & (up->port.ignore_status_mask & 0xff)) == 0 &&
@@ -301,7 +300,7 @@ static void check_status(struct uart_sunsab_port *up,
wake_up_interruptible(&up->port.info->delta_msr_wait);
}
-static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sunsab_interrupt(int irq, void *dev_id)
{
struct uart_sunsab_port *up = dev_id;
struct tty_struct *tty;
@@ -321,7 +320,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if ((status.sreg.isr0 & (SAB82532_ISR0_TCD | SAB82532_ISR0_TIME |
SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
(status.sreg.isr1 & SAB82532_ISR1_BRK))
- tty = receive_chars(up, &status, regs);
+ tty = receive_chars(up, &status);
if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
(status.sreg.isr1 & SAB82532_ISR1_CSC))
check_status(up, &status);
@@ -350,7 +349,7 @@ static irqreturn_t sunsab_interrupt(int irq, void *dev_id, struct pt_regs *regs)
SAB82532_ISR0_RFO | SAB82532_ISR0_RPF)) ||
(status.sreg.isr1 & SAB82532_ISR1_BRK))
- tty = receive_chars(up, &status, regs);
+ tty = receive_chars(up, &status);
if ((status.sreg.isr0 & SAB82532_ISR0_CDSC) ||
(status.sreg.isr1 & (SAB82532_ISR1_BRK | SAB82532_ISR1_CSC)))
check_status(up, &status);
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index d3a5aeee73a3..c577faea60e8 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -310,7 +310,7 @@ static void sunsu_enable_ms(struct uart_port *port)
}
static struct tty_struct *
-receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs *regs)
+receive_chars(struct uart_sunsu_port *up, unsigned char *status)
{
struct tty_struct *tty = up->port.info->tty;
unsigned char ch, flag;
@@ -367,7 +367,7 @@ receive_chars(struct uart_sunsu_port *up, unsigned char *status, struct pt_regs
else if (*status & UART_LSR_FE)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
goto ignore_char;
if ((*status & up->port.ignore_status_mask) == 0)
tty_insert_flip_char(tty, ch, flag);
@@ -445,7 +445,7 @@ static void check_modem_status(struct uart_sunsu_port *up)
wake_up_interruptible(&up->port.info->delta_msr_wait);
}
-static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id)
{
struct uart_sunsu_port *up = dev_id;
unsigned long flags;
@@ -459,7 +459,7 @@ static irqreturn_t sunsu_serial_interrupt(int irq, void *dev_id, struct pt_regs
status = serial_inp(up, UART_LSR);
tty = NULL;
if (status & UART_LSR_DR)
- tty = receive_chars(up, &status, regs);
+ tty = receive_chars(up, &status);
check_modem_status(up);
if (status & UART_LSR_THRE)
transmit_chars(up);
@@ -497,7 +497,7 @@ static void sunsu_change_mouse_baud(struct uart_sunsu_port *up)
sunsu_change_speed(&up->port, up->cflag, 0, quot);
}
-static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *regs, int is_break)
+static void receive_kbd_ms_chars(struct uart_sunsu_port *up, int is_break)
{
do {
unsigned char ch = serial_inp(up, UART_RX);
@@ -505,7 +505,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
/* Stop-A is handled by drivers/char/keyboard.c now. */
if (up->su_type == SU_PORT_KBD) {
#ifdef CONFIG_SERIO
- serio_interrupt(&up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0);
#endif
} else if (up->su_type == SU_PORT_MS) {
int ret = suncore_mouse_baud_detection(ch, is_break);
@@ -519,7 +519,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
case 0:
#ifdef CONFIG_SERIO
- serio_interrupt(&up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0);
#endif
break;
};
@@ -527,7 +527,7 @@ static void receive_kbd_ms_chars(struct uart_sunsu_port *up, struct pt_regs *reg
} while (serial_in(up, UART_LSR) & UART_LSR_DR);
}
-static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id)
{
struct uart_sunsu_port *up = dev_id;
@@ -535,8 +535,7 @@ static irqreturn_t sunsu_kbd_ms_interrupt(int irq, void *dev_id, struct pt_regs
unsigned char status = serial_inp(up, UART_LSR);
if ((status & UART_LSR_DR) || (status & UART_LSR_BI))
- receive_kbd_ms_chars(up, regs,
- (status & UART_LSR_BI) != 0);
+ receive_kbd_ms_chars(up, (status & UART_LSR_BI) != 0);
}
return IRQ_HANDLED;
@@ -1499,6 +1498,9 @@ static int __devexit su_remove(struct of_device *dev)
uart_remove_one_port(&sunsu_reg, &up->port);
}
+ if (up->port.membase)
+ of_iounmap(up->port.membase, up->reg_size);
+
dev_set_drvdata(&dev->dev, NULL);
return 0;
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index d34f336d53d8..b2cc703b2b9e 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -277,14 +277,13 @@ static void sunzilog_change_mouse_baud(struct uart_sunzilog_port *up)
}
static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
- unsigned char ch, int is_break,
- struct pt_regs *regs)
+ unsigned char ch, int is_break)
{
if (ZS_IS_KEYB(up)) {
/* Stop-A is handled by drivers/char/keyboard.c now. */
#ifdef CONFIG_SERIO
if (up->serio_open)
- serio_interrupt(&up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0);
#endif
} else if (ZS_IS_MOUSE(up)) {
int ret = suncore_mouse_baud_detection(ch, is_break);
@@ -299,7 +298,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
case 0:
#ifdef CONFIG_SERIO
if (up->serio_open)
- serio_interrupt(&up->serio, ch, 0, regs);
+ serio_interrupt(&up->serio, ch, 0);
#endif
break;
};
@@ -308,8 +307,7 @@ static void sunzilog_kbdms_receive_chars(struct uart_sunzilog_port *up,
static struct tty_struct *
sunzilog_receive_chars(struct uart_sunzilog_port *up,
- struct zilog_channel __iomem *channel,
- struct pt_regs *regs)
+ struct zilog_channel __iomem *channel)
{
struct tty_struct *tty;
unsigned char ch, r1, flag;
@@ -346,12 +344,12 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
ch &= up->parity_mask;
if (unlikely(ZS_IS_KEYB(up)) || unlikely(ZS_IS_MOUSE(up))) {
- sunzilog_kbdms_receive_chars(up, ch, 0, regs);
+ sunzilog_kbdms_receive_chars(up, ch, 0);
continue;
}
if (tty == NULL) {
- uart_handle_sysrq_char(&up->port, ch, regs);
+ uart_handle_sysrq_char(&up->port, ch);
continue;
}
@@ -379,7 +377,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
else if (r1 & CRC_ERR)
flag = TTY_FRAME;
}
- if (uart_handle_sysrq_char(&up->port, ch, regs))
+ if (uart_handle_sysrq_char(&up->port, ch))
continue;
if (up->port.ignore_status_mask == 0xff ||
@@ -394,8 +392,7 @@ sunzilog_receive_chars(struct uart_sunzilog_port *up,
}
static void sunzilog_status_handle(struct uart_sunzilog_port *up,
- struct zilog_channel __iomem *channel,
- struct pt_regs *regs)
+ struct zilog_channel __iomem *channel)
{
unsigned char status;
@@ -408,7 +405,7 @@ static void sunzilog_status_handle(struct uart_sunzilog_port *up,
if (status & BRK_ABRT) {
if (ZS_IS_MOUSE(up))
- sunzilog_kbdms_receive_chars(up, 0, 1, regs);
+ sunzilog_kbdms_receive_chars(up, 0, 1);
if (ZS_IS_CONS(up)) {
/* Wait for BREAK to deassert to avoid potentially
* confusing the PROM.
@@ -517,7 +514,7 @@ ack_tx_int:
ZS_WSYNC(channel);
}
-static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sunzilog_interrupt(int irq, void *dev_id)
{
struct uart_sunzilog_port *up = dev_id;
@@ -538,9 +535,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
ZS_WSYNC(channel);
if (r3 & CHARxIP)
- tty = sunzilog_receive_chars(up, channel, regs);
+ tty = sunzilog_receive_chars(up, channel);
if (r3 & CHAEXT)
- sunzilog_status_handle(up, channel, regs);
+ sunzilog_status_handle(up, channel);
if (r3 & CHATxIP)
sunzilog_transmit_chars(up, channel);
}
@@ -561,9 +558,9 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
ZS_WSYNC(channel);
if (r3 & CHBRxIP)
- tty = sunzilog_receive_chars(up, channel, regs);
+ tty = sunzilog_receive_chars(up, channel);
if (r3 & CHBEXT)
- sunzilog_status_handle(up, channel, regs);
+ sunzilog_status_handle(up, channel);
if (r3 & CHBTxIP)
sunzilog_transmit_chars(up, channel);
}
@@ -1060,7 +1057,7 @@ static void sunzilog_free_tables(void)
static void sunzilog_putchar(struct uart_port *port, int ch)
{
- struct zilog_channel *channel = ZILOG_CHANNEL_FROM_PORT(port);
+ struct zilog_channel __iomem *channel = ZILOG_CHANNEL_FROM_PORT(port);
int loops = ZS_PUT_CHAR_MAX_DELAY;
/* This is a timed polling loop so do not switch the explicit
@@ -1185,7 +1182,7 @@ static int __init sunzilog_console_setup(struct console *con, char *options)
return 0;
}
-static struct console sunzilog_console = {
+static struct console sunzilog_console_ops = {
.name = "ttyS",
.write = sunzilog_console_write,
.device = uart_console_device,
@@ -1211,10 +1208,10 @@ static inline struct console *SUNZILOG_CONSOLE(void)
if (i == NUM_CHANNELS)
return NULL;
- sunzilog_console.index = i;
+ sunzilog_console_ops.index = i;
sunzilog_port_table[i].flags |= SUNZILOG_FLAG_IS_CONS;
- return &sunzilog_console;
+ return &sunzilog_console_ops;
}
#else
@@ -1270,7 +1267,7 @@ static void __init sunzilog_register_serio(struct uart_sunzilog_port *up)
}
#endif
-static void __init sunzilog_init_hw(struct uart_sunzilog_port *up)
+static void __devinit sunzilog_init_hw(struct uart_sunzilog_port *up)
{
struct zilog_channel __iomem *channel;
unsigned long flags;
diff --git a/drivers/serial/v850e_uart.c b/drivers/serial/v850e_uart.c
index f802867c95c5..28f3bbff87bf 100644
--- a/drivers/serial/v850e_uart.c
+++ b/drivers/serial/v850e_uart.c
@@ -271,14 +271,14 @@ void v850e_uart_tx (struct uart_port *port)
v850e_uart_stop_tx (port, stopped);
}
-static irqreturn_t v850e_uart_tx_irq(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t v850e_uart_tx_irq(int irq, void *data)
{
struct uart_port *port = data;
v850e_uart_tx (port);
return IRQ_HANDLED;
}
-static irqreturn_t v850e_uart_rx_irq(int irq, void *data, struct pt_regs *regs)
+static irqreturn_t v850e_uart_rx_irq(int irq, void *data)
{
struct uart_port *port = data;
unsigned ch_stat = TTY_NORMAL;
diff --git a/drivers/serial/vr41xx_siu.c b/drivers/serial/vr41xx_siu.c
index 6c8b0ea83c3c..fd51f8182dec 100644
--- a/drivers/serial/vr41xx_siu.c
+++ b/drivers/serial/vr41xx_siu.c
@@ -359,8 +359,7 @@ static void siu_break_ctl(struct uart_port *port, int ctl)
spin_unlock_irqrestore(&port->lock, flags);
}
-static inline void receive_chars(struct uart_port *port, uint8_t *status,
- struct pt_regs *regs)
+static inline void receive_chars(struct uart_port *port, uint8_t *status)
{
struct tty_struct *tty;
uint8_t lsr, ch;
@@ -405,7 +404,7 @@ static inline void receive_chars(struct uart_port *port, uint8_t *status,
flag = TTY_PARITY;
}
- if (uart_handle_sysrq_char(port, ch, regs))
+ if (uart_handle_sysrq_char(port, ch))
goto ignore_char;
uart_insert_char(port, lsr, UART_LSR_OE, ch, flag);
@@ -472,7 +471,7 @@ static inline void transmit_chars(struct uart_port *port)
siu_stop_tx(port);
}
-static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t siu_interrupt(int irq, void *dev_id)
{
struct uart_port *port;
uint8_t iir, lsr;
@@ -485,7 +484,7 @@ static irqreturn_t siu_interrupt(int irq, void *dev_id, struct pt_regs *regs)
lsr = siu_read(port, UART_LSR);
if (lsr & UART_LSR_DR)
- receive_chars(port, &lsr, regs);
+ receive_chars(port, &lsr);
check_modem_status(port);
diff --git a/drivers/sn/Kconfig b/drivers/sn/Kconfig
index a34731625877..c66ba9ad833d 100644
--- a/drivers/sn/Kconfig
+++ b/drivers/sn/Kconfig
@@ -5,19 +5,6 @@
menu "SN Devices"
depends on SGI_SN
-config SGI_IOC4
- tristate "SGI IOC4 Base IO support"
- depends on MMTIMER
- default m
- ---help---
- This option enables basic support for the SGI IOC4-based Base IO
- controller card. This option does not enable any specific
- functions on such a card, but provides necessary infrastructure
- for other drivers to utilize.
-
- If you have an SGI Altix with an IOC4-based
- I/O controller say Y. Otherwise say N.
-
config SGI_IOC3
tristate "SGI IOC3 Base IO support"
default m
diff --git a/drivers/sn/Makefile b/drivers/sn/Makefile
index 2cda011597c0..693db8bb8d9c 100644
--- a/drivers/sn/Makefile
+++ b/drivers/sn/Makefile
@@ -3,5 +3,4 @@
#
#
-obj-$(CONFIG_SGI_IOC4) += ioc4.o
obj-$(CONFIG_SGI_IOC3) += ioc3.o
diff --git a/drivers/sn/ioc3.c b/drivers/sn/ioc3.c
index 6c7e0352d561..cd6b65333b71 100644
--- a/drivers/sn/ioc3.c
+++ b/drivers/sn/ioc3.c
@@ -398,10 +398,10 @@ static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd)
return intrs;
}
-static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t ioc3_intr_io(int irq, void *arg)
{
unsigned long flags;
- struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
+ struct ioc3_driver_data *idd = arg;
int handled = 1, id;
unsigned int pending;
@@ -412,7 +412,7 @@ static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs)
if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&
ioc3_ethernet->intr) {
handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,
- idd, 0, regs);
+ idd, 0);
}
}
pending = get_pending_intrs(idd); /* look at the IO IRQs */
@@ -424,8 +424,7 @@ static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs)
write_ireg(idd, ioc3_submodules[id]->irq_mask,
IOC3_W_IEC);
if(!ioc3_submodules[id]->intr(ioc3_submodules[id],
- idd, pending & ioc3_submodules[id]->irq_mask,
- regs))
+ idd, pending & ioc3_submodules[id]->irq_mask))
pending &= ~ioc3_submodules[id]->irq_mask;
if (ioc3_submodules[id]->reset_mask)
write_ireg(idd, ioc3_submodules[id]->irq_mask,
@@ -442,7 +441,7 @@ static irqreturn_t ioc3_intr_io(int irq, void *arg, struct pt_regs *regs)
return handled?IRQ_HANDLED:IRQ_NONE;
}
-static irqreturn_t ioc3_intr_eth(int irq, void *arg, struct pt_regs *regs)
+static irqreturn_t ioc3_intr_eth(int irq, void *arg)
{
unsigned long flags;
struct ioc3_driver_data *idd = (struct ioc3_driver_data *)arg;
@@ -453,8 +452,7 @@ static irqreturn_t ioc3_intr_eth(int irq, void *arg, struct pt_regs *regs)
read_lock_irqsave(&ioc3_submodules_lock, flags);
if(ioc3_ethernet && idd->active[ioc3_ethernet->id]
&& ioc3_ethernet->intr)
- handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0,
- regs);
+ handled = handled && !ioc3_ethernet->intr(ioc3_ethernet, idd, 0);
read_unlock_irqrestore(&ioc3_submodules_lock, flags);
return handled?IRQ_HANDLED:IRQ_NONE;
}
diff --git a/drivers/spi/pxa2xx_spi.c b/drivers/spi/pxa2xx_spi.c
index 29aec77f98be..72025df5561d 100644
--- a/drivers/spi/pxa2xx_spi.c
+++ b/drivers/spi/pxa2xx_spi.c
@@ -409,7 +409,7 @@ static int wait_dma_channel_stop(int channel)
return limit;
}
-static void dma_handler(int channel, void *data, struct pt_regs *regs)
+static void dma_handler(int channel, void *data)
{
struct driver_data *drv_data = data;
struct spi_message *msg = drv_data->cur_msg;
@@ -667,9 +667,9 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
return IRQ_HANDLED;
}
-static irqreturn_t ssp_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ssp_int(int irq, void *dev_id)
{
- struct driver_data *drv_data = (struct driver_data *)dev_id;
+ struct driver_data *drv_data = dev_id;
void *reg = drv_data->ioaddr;
if (!drv_data->cur_msg) {
diff --git a/drivers/spi/spi_mpc83xx.c b/drivers/spi/spi_mpc83xx.c
index 5d92a7e5cb41..ff0b04895db0 100644
--- a/drivers/spi/spi_mpc83xx.c
+++ b/drivers/spi/spi_mpc83xx.c
@@ -296,8 +296,7 @@ static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
return t->len - mpc83xx_spi->count;
}
-irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data,
- struct pt_regs * ptregs)
+irqreturn_t mpc83xx_spi_irq(s32 irq, void *context_data)
{
struct mpc83xx_spi *mpc83xx_spi = context_data;
u32 event;
diff --git a/drivers/spi/spi_s3c24xx.c b/drivers/spi/spi_s3c24xx.c
index 5fc14563ee3a..2ebe1fc4c398 100644
--- a/drivers/spi/spi_s3c24xx.c
+++ b/drivers/spi/spi_s3c24xx.c
@@ -13,7 +13,6 @@
//#define DEBUG
-#include <linux/config.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/workqueue.h>
@@ -197,7 +196,7 @@ static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
return hw->count;
}
-static irqreturn_t s3c24xx_spi_irq(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
{
struct s3c24xx_spi *hw = dev;
unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
diff --git a/drivers/spi/spi_s3c24xx_gpio.c b/drivers/spi/spi_s3c24xx_gpio.c
index aacdceb8f44b..a5d2cdfff46f 100644
--- a/drivers/spi/spi_s3c24xx_gpio.c
+++ b/drivers/spi/spi_s3c24xx_gpio.c
@@ -11,7 +11,6 @@
*
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
diff --git a/drivers/tc/zs.c b/drivers/tc/zs.c
index 5e8a27620f6f..792becdfe6f8 100644
--- a/drivers/tc/zs.c
+++ b/drivers/tc/zs.c
@@ -347,7 +347,7 @@ static void rs_sched_event(struct dec_serial *info, int event)
tasklet_schedule(&info->tlet);
}
-static void receive_chars(struct dec_serial *info, struct pt_regs *regs)
+static void receive_chars(struct dec_serial *info)
{
struct tty_struct *tty = info->tty;
unsigned char ch, stat, flag;
@@ -389,7 +389,7 @@ static void receive_chars(struct dec_serial *info, struct pt_regs *regs)
if (ch == 0)
continue;
if (time_before(jiffies, break_pressed + HZ * 5)) {
- handle_sysrq(ch, regs, NULL);
+ handle_sysrq(ch, NULL);
break_pressed = 0;
continue;
}
@@ -490,7 +490,7 @@ static void status_handle(struct dec_serial *info)
/*
* This is the serial driver's generic interrupt routine
*/
-static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rs_interrupt(int irq, void *dev_id)
{
struct dec_serial *info = (struct dec_serial *) dev_id;
irqreturn_t status = IRQ_NONE;
@@ -518,7 +518,7 @@ static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = IRQ_HANDLED;
if (zs_intreg & CHBRxIP) {
- receive_chars(info, regs);
+ receive_chars(info);
}
if (zs_intreg & CHBTxIP) {
transmit_chars(info);
@@ -1701,7 +1701,7 @@ static void __init probe_sccs(void)
spin_unlock_irqrestore(&zs_lock, flags);
}
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
.write = rs_write,
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index f6b2948ab288..1b601b6cf2a2 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -284,6 +284,14 @@ static int samplerate = 100;
module_param(ixjdebug, int, 0);
+static struct pci_device_id ixj_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_QUICKNET, PCI_DEVICE_ID_QUICKNET_XJ,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, ixj_pci_tbl);
+
/************************************************************************
*
* ixjdebug meanings are now bit mapped instead of level based
@@ -7683,7 +7691,8 @@ static int __init ixj_probe_pci(int *cnt)
IXJ *j = NULL;
for (i = 0; i < IXJMAX - *cnt; i++) {
- pci = pci_find_device(0x15E2, 0x0500, pci);
+ pci = pci_find_device(PCI_VENDOR_ID_QUICKNET,
+ PCI_DEVICE_ID_QUICKNET_XJ, pci);
if (!pci)
break;
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 005043197527..f9b1719b9a37 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -25,6 +25,7 @@ config USB_ARCH_HAS_OHCI
default y if PXA27x
default y if ARCH_EP93XX
default y if (ARCH_AT91RM9200 || ARCH_AT91SAM9261)
+ default y if ARCH_PNX4008
# PPC:
default y if STB03xxx
default y if PPC_MPC52xx
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 4710eb02ed64..825bf884537a 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
+obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_ETRAX_USB_HOST) += host/
obj-$(CONFIG_USB_OHCI_AT91) += host/
@@ -23,6 +24,7 @@ obj-$(CONFIG_USB_PRINTER) += class/
obj-$(CONFIG_USB_STORAGE) += storage/
obj-$(CONFIG_USB) += storage/
+obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_AIPTEK) += input/
obj-$(CONFIG_USB_ATI_REMOTE) += input/
obj-$(CONFIG_USB_HID) += input/
@@ -32,7 +34,6 @@ obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_POWERMATE) += input/
obj-$(CONFIG_USB_WACOM) += input/
-obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_XPAD) += input/
obj-$(CONFIG_USB_CATC) += net/
@@ -47,22 +48,25 @@ obj-$(CONFIG_USB_MICROTEK) += image/
obj-$(CONFIG_USB_SERIAL) += serial/
+obj-$(CONFIG_USB_ADUTUX) += misc/
+obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_AUERSWALD) += misc/
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
obj-$(CONFIG_USB_CYTHERM) += misc/
obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_EMI62) += misc/
+obj-$(CONFIG_USB_FTDI_ELAN) += misc/
obj-$(CONFIG_USB_IDMOUSE) += misc/
obj-$(CONFIG_USB_LCD) += misc/
obj-$(CONFIG_USB_LD) += misc/
obj-$(CONFIG_USB_LED) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
+obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
+obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_TEST) += misc/
+obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
obj-$(CONFIG_USB_USS720) += misc/
-obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
-obj-$(CONFIG_USB_SISUSBVGA) += misc/
-obj-$(CONFIG_USB_APPLEDISPLAY) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index 550ddfa71a43..b450cbaa3a0b 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -64,7 +64,7 @@ config USB_XUSBATM
Say Y here if you have a DSL USB modem not explicitly supported by
another USB DSL drivers. In order to use your modem you will need to
pass the vendor ID, product ID, and endpoint numbers for transmission
- and reception as module parameters. You may need to initialize the
+ and reception as module parameters. You may need to initialize
the modem using a user space utility (a firmware loader for example).
To compile this driver as a module, choose M here: the
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
index 04631dcbabbc..e6565633ba0f 100644
--- a/drivers/usb/atm/cxacru.c
+++ b/drivers/usb/atm/cxacru.c
@@ -171,7 +171,7 @@ struct cxacru_data {
};
/* the following three functions are stolen from drivers/usb/core/message.c */
-static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs)
+static void cxacru_blocking_completion(struct urb *urb)
{
complete((struct completion *)urb->context);
}
@@ -793,6 +793,9 @@ static const struct usb_device_id cxacru_usb_ids[] = {
{ /* V = Conexant P = ADSL modem */
USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00
},
+ { /* V = Conexant P = ADSL modem (ZTE ZXDSL 852) */
+ USB_DEVICE(0x0572, 0xcb07), .driver_info = (unsigned long) &cxacru_cb00
+ },
{ /* V = Olitec P = ADSL modem version 2 */
USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe
},
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 956b7a1e8af9..c870c804470f 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -55,7 +55,6 @@ static const char speedtch_driver_name[] = "speedtch";
#define OFFSET_d 9 /* size 4 */
#define OFFSET_e 13 /* size 1 */
#define OFFSET_f 14 /* size 1 */
-#define TOTAL 15
#define SIZE_7 1
#define SIZE_b 8
@@ -79,6 +78,18 @@ static int dl_512_first = DEFAULT_DL_512_FIRST;
static int enable_isoc = DEFAULT_ENABLE_ISOC;
static int sw_buffering = DEFAULT_SW_BUFFERING;
+#define DEFAULT_B_MAX_DSL 8128
+#define DEFAULT_MODEM_MODE 11
+#define MODEM_OPTION_LENGTH 16
+static const unsigned char DEFAULT_MODEM_OPTION[MODEM_OPTION_LENGTH] = {
+ 0x10, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static unsigned int BMaxDSL = DEFAULT_B_MAX_DSL;
+static unsigned char ModemMode = DEFAULT_MODEM_MODE;
+static unsigned char ModemOption[MODEM_OPTION_LENGTH];
+static int num_ModemOption;
+
module_param(altsetting, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(altsetting,
"Alternative setting for data interface (bulk_default: "
@@ -100,6 +111,17 @@ MODULE_PARM_DESC(sw_buffering,
"Enable software buffering (default: "
__MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
+module_param(BMaxDSL, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(BMaxDSL,
+ "default: " __MODULE_STRING(DEFAULT_B_MAX_DSL));
+
+module_param(ModemMode, byte, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(ModemMode,
+ "default: " __MODULE_STRING(DEFAULT_MODEM_MODE));
+
+module_param_array(ModemOption, byte, &num_ModemOption, S_IRUGO);
+MODULE_PARM_DESC(ModemOption, "default: 0x10,0x00,0x00,0x00,0x20");
+
#define INTERFACE_DATA 1
#define ENDPOINT_INT 0x81
#define ENDPOINT_BULK_DATA 0x07
@@ -108,10 +130,17 @@ MODULE_PARM_DESC(sw_buffering,
#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
+struct speedtch_params {
+ unsigned int altsetting;
+ unsigned int BMaxDSL;
+ unsigned char ModemMode;
+ unsigned char ModemOption[MODEM_OPTION_LENGTH];
+};
+
struct speedtch_instance_data {
struct usbatm_data *usbatm;
- unsigned int altsetting;
+ struct speedtch_params params; /* set in probe, constant afterwards */
struct work_struct status_checker;
@@ -123,7 +152,7 @@ struct speedtch_instance_data {
struct urb *int_urb;
unsigned char int_data[16];
- unsigned char scratch_buffer[TOTAL];
+ unsigned char scratch_buffer[16];
};
/***************
@@ -186,6 +215,34 @@ static void speedtch_test_sequence(struct speedtch_instance_data *instance)
0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
if (ret < 0)
usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
+
+ /* Extra initialisation in recent drivers - gives higher speeds */
+
+ /* URBext1 */
+ buf[0] = instance->params.ModemMode;
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x01, 0x40, 0x11, 0x00, buf, 1, CTRL_TIMEOUT);
+ if (ret < 0)
+ usb_warn(usbatm, "%s failed on URBext1: %d\n", __func__, ret);
+
+ /* URBext2 */
+ /* This seems to be the one which actually triggers the higher sync
+ rate -- it does require the new firmware too, although it works OK
+ with older firmware */
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x01, 0x40, 0x14, 0x00,
+ instance->params.ModemOption,
+ MODEM_OPTION_LENGTH, CTRL_TIMEOUT);
+ if (ret < 0)
+ usb_warn(usbatm, "%s failed on URBext2: %d\n", __func__, ret);
+
+ /* URBext3 */
+ buf[0] = instance->params.BMaxDSL & 0xff;
+ buf[1] = instance->params.BMaxDSL >> 8;
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x01, 0x40, 0x12, 0x00, buf, 2, CTRL_TIMEOUT);
+ if (ret < 0)
+ usb_warn(usbatm, "%s failed on URBext3: %d\n", __func__, ret);
}
static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
@@ -285,8 +342,8 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
because we're in our own kernel thread anyway. */
msleep_interruptible(1000);
- if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
- usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->altsetting, ret);
+ if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
+ usb_err(usbatm, "%s: setting interface to %d failed (%d)!\n", __func__, instance->params.altsetting, ret);
goto out_free;
}
@@ -372,7 +429,7 @@ static int speedtch_read_status(struct speedtch_instance_data *instance)
unsigned char *buf = instance->scratch_buffer;
int ret;
- memset(buf, 0, TOTAL);
+ memset(buf, 0, 16);
ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
@@ -547,7 +604,7 @@ static void speedtch_resubmit_int(unsigned long data)
}
}
-static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs)
+static void speedtch_handle_int(struct urb *int_urb)
{
struct speedtch_instance_data *instance = int_urb->context;
struct usbatm_data *usbatm = instance->usbatm;
@@ -746,17 +803,21 @@ static int speedtch_bind(struct usbatm_data *usbatm,
instance->usbatm = usbatm;
- /* altsetting and enable_isoc may change at any moment, so take a snapshot */
- instance->altsetting = altsetting;
+ /* module parameters may change at any moment, so take a snapshot */
+ instance->params.altsetting = altsetting;
+ instance->params.BMaxDSL = BMaxDSL;
+ instance->params.ModemMode = ModemMode;
+ memcpy(instance->params.ModemOption, DEFAULT_MODEM_OPTION, MODEM_OPTION_LENGTH);
+ memcpy(instance->params.ModemOption, ModemOption, num_ModemOption);
use_isoc = enable_isoc;
- if (instance->altsetting)
- if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->altsetting)) < 0) {
- usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->altsetting, ret);
- instance->altsetting = 0; /* fall back to default */
+ if (instance->params.altsetting)
+ if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, instance->params.altsetting)) < 0) {
+ usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, instance->params.altsetting, ret);
+ instance->params.altsetting = 0; /* fall back to default */
}
- if (!instance->altsetting && use_isoc)
+ if (!instance->params.altsetting && use_isoc)
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_ISOC_ALTSETTING)) < 0) {
usb_dbg(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_ISOC_ALTSETTING, ret);
use_isoc = 0; /* fall back to bulk */
@@ -783,14 +844,14 @@ static int speedtch_bind(struct usbatm_data *usbatm,
usb_info(usbatm, "isochronous transfer not supported - using bulk\n");
}
- if (!use_isoc && !instance->altsetting)
+ if (!use_isoc && !instance->params.altsetting)
if ((ret = usb_set_interface(usb_dev, INTERFACE_DATA, DEFAULT_BULK_ALTSETTING)) < 0) {
usb_err(usbatm, "%s: setting interface to %2d failed (%d)!\n", __func__, DEFAULT_BULK_ALTSETTING, ret);
goto fail_free;
}
- if (!instance->altsetting)
- instance->altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
+ if (!instance->params.altsetting)
+ instance->params.altsetting = use_isoc ? DEFAULT_ISOC_ALTSETTING : DEFAULT_BULK_ALTSETTING;
usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0);
diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c
index b38990adf1cd..f6b9f7e1f716 100644
--- a/drivers/usb/atm/ueagle-atm.c
+++ b/drivers/usb/atm/ueagle-atm.c
@@ -68,7 +68,7 @@
#include "usbatm.h"
-#define EAGLEUSBVERSION "ueagle 1.3"
+#define EAGLEUSBVERSION "ueagle 1.4"
/*
@@ -80,14 +80,14 @@
dev_dbg(&(usb_dev)->dev, \
"[ueagle-atm dbg] %s: " format, \
__FUNCTION__, ##args); \
- } while (0)
+ } while (0)
#define uea_vdbg(usb_dev, format, args...) \
do { \
if (debug >= 2) \
dev_dbg(&(usb_dev)->dev, \
"[ueagle-atm vdbg] " format, ##args); \
- } while (0)
+ } while (0)
#define uea_enters(usb_dev) \
uea_vdbg(usb_dev, "entering %s\n", __FUNCTION__)
@@ -218,8 +218,8 @@ enum {
#define UEA_CHIP_VERSION(x) \
((x)->driver_info & 0xf)
-#define IS_ISDN(sc) \
- (le16_to_cpu(sc->usb_dev->descriptor.bcdDevice) & 0x80)
+#define IS_ISDN(usb_dev) \
+ (le16_to_cpu((usb_dev)->descriptor.bcdDevice) & 0x80)
#define INS_TO_USBDEV(ins) ins->usb_dev
@@ -625,12 +625,12 @@ static int request_dsp(struct uea_softc *sc)
char *dsp_name;
if (UEA_CHIP_VERSION(sc) == ADI930) {
- if (IS_ISDN(sc))
+ if (IS_ISDN(sc->usb_dev))
dsp_name = FW_DIR "DSP9i.bin";
else
dsp_name = FW_DIR "DSP9p.bin";
} else {
- if (IS_ISDN(sc))
+ if (IS_ISDN(sc->usb_dev))
dsp_name = FW_DIR "DSPei.bin";
else
dsp_name = FW_DIR "DSPep.bin";
@@ -744,7 +744,7 @@ static inline void wake_up_cmv_ack(struct uea_softc *sc)
static inline int wait_cmv_ack(struct uea_softc *sc)
{
- int ret = wait_event_timeout(sc->cmv_ack_wait,
+ int ret = wait_event_interruptible_timeout(sc->cmv_ack_wait,
sc->cmv_ack, ACK_TIMEOUT);
sc->cmv_ack = 0;
@@ -885,7 +885,8 @@ static int uea_stat(struct uea_softc *sc)
break;
case 3: /* fail ... */
- uea_info(INS_TO_USBDEV(sc), "modem synchronization failed\n");
+ uea_info(INS_TO_USBDEV(sc), "modem synchronization failed"
+ " (may be try other cmv/dsp)\n");
return -EAGAIN;
case 4 ... 6: /* test state */
@@ -913,12 +914,6 @@ static int uea_stat(struct uea_softc *sc)
release_firmware(sc->dsp_firm);
sc->dsp_firm = NULL;
}
-
- ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
- if (ret < 0)
- return ret;
- uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
- sc->stats.phy.firmid);
}
/* always update it as atm layer could not be init when we switch to
@@ -1033,9 +1028,9 @@ static int request_cmvs(struct uea_softc *sc,
if (cmv_file[sc->modem_index] == NULL) {
if (UEA_CHIP_VERSION(sc) == ADI930)
- file = (IS_ISDN(sc)) ? "CMV9i.bin" : "CMV9p.bin";
+ file = (IS_ISDN(sc->usb_dev)) ? "CMV9i.bin" : "CMV9p.bin";
else
- file = (IS_ISDN(sc)) ? "CMVei.bin" : "CMVep.bin";
+ file = (IS_ISDN(sc->usb_dev)) ? "CMVei.bin" : "CMVep.bin";
} else
file = cmv_file[sc->modem_index];
@@ -1131,6 +1126,13 @@ static int uea_start_reset(struct uea_softc *sc)
if (ret < 0)
return ret;
+ /* Dump firmware version */
+ ret = uea_read_cmv(sc, SA_INFO, 10, &sc->stats.phy.firmid);
+ if (ret < 0)
+ return ret;
+ uea_info(INS_TO_USBDEV(sc), "ATU-R firmware version : %x\n",
+ sc->stats.phy.firmid);
+
/* get options */
ret = len = request_cmvs(sc, &cmvs, &cmvs_fw);
if (ret < 0)
@@ -1147,6 +1149,8 @@ static int uea_start_reset(struct uea_softc *sc)
/* Enter in R-ACT-REQ */
ret = uea_write_cmv(sc, SA_CNTL, 0, 2);
uea_vdbg(INS_TO_USBDEV(sc), "Entering in R-ACT-REQ state\n");
+ uea_info(INS_TO_USBDEV(sc), "Modem started, "
+ "waiting synchronization\n");
out:
release_firmware(cmvs_fw);
sc->reset = 0;
@@ -1172,7 +1176,10 @@ static int uea_kthread(void *data)
if (!ret)
ret = uea_stat(sc);
if (ret != -EAGAIN)
- msleep(1000);
+ msleep_interruptible(1000);
+ if (try_to_freeze())
+ uea_err(INS_TO_USBDEV(sc), "suspend/resume not supported, "
+ "please unplug/replug your modem\n");
}
uea_leaves(INS_TO_USBDEV(sc));
return ret;
@@ -1297,7 +1304,7 @@ bad1:
/*
* interrupt handler
*/
-static void uea_intr(struct urb *urb, struct pt_regs *regs)
+static void uea_intr(struct urb *urb)
{
struct uea_softc *sc = urb->context;
struct intr_pkt *intr = urb->transfer_buffer;
@@ -1566,6 +1573,7 @@ UEA_ATTR(uscorr, 0);
UEA_ATTR(dscorr, 0);
UEA_ATTR(usunc, 0);
UEA_ATTR(dsunc, 0);
+UEA_ATTR(firmid, 0);
/* Retrieve the device End System Identifier (MAC) */
@@ -1597,7 +1605,7 @@ static int uea_heavy(struct usbatm_data *usbatm, struct usb_interface *intf)
{
struct uea_softc *sc = usbatm->driver_data;
- wait_event(sc->sync_q, IS_OPERATIONAL(sc));
+ wait_event_interruptible(sc->sync_q, IS_OPERATIONAL(sc));
return 0;
@@ -1621,27 +1629,30 @@ static int claim_interface(struct usb_device *usb_dev,
return ret;
}
-static void create_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
-{
- /* sysfs interface */
- device_create_file(&intf->dev, &dev_attr_stat_status);
- device_create_file(&intf->dev, &dev_attr_stat_mflags);
- device_create_file(&intf->dev, &dev_attr_stat_human_status);
- device_create_file(&intf->dev, &dev_attr_stat_delin);
- device_create_file(&intf->dev, &dev_attr_stat_vidcpe);
- device_create_file(&intf->dev, &dev_attr_stat_usrate);
- device_create_file(&intf->dev, &dev_attr_stat_dsrate);
- device_create_file(&intf->dev, &dev_attr_stat_usattenuation);
- device_create_file(&intf->dev, &dev_attr_stat_dsattenuation);
- device_create_file(&intf->dev, &dev_attr_stat_usmargin);
- device_create_file(&intf->dev, &dev_attr_stat_dsmargin);
- device_create_file(&intf->dev, &dev_attr_stat_txflow);
- device_create_file(&intf->dev, &dev_attr_stat_rxflow);
- device_create_file(&intf->dev, &dev_attr_stat_uscorr);
- device_create_file(&intf->dev, &dev_attr_stat_dscorr);
- device_create_file(&intf->dev, &dev_attr_stat_usunc);
- device_create_file(&intf->dev, &dev_attr_stat_dsunc);
-}
+static struct attribute *attrs[] = {
+ &dev_attr_stat_status.attr,
+ &dev_attr_stat_mflags.attr,
+ &dev_attr_stat_human_status.attr,
+ &dev_attr_stat_delin.attr,
+ &dev_attr_stat_vidcpe.attr,
+ &dev_attr_stat_usrate.attr,
+ &dev_attr_stat_dsrate.attr,
+ &dev_attr_stat_usattenuation.attr,
+ &dev_attr_stat_dsattenuation.attr,
+ &dev_attr_stat_usmargin.attr,
+ &dev_attr_stat_dsmargin.attr,
+ &dev_attr_stat_txflow.attr,
+ &dev_attr_stat_rxflow.attr,
+ &dev_attr_stat_uscorr.attr,
+ &dev_attr_stat_dscorr.attr,
+ &dev_attr_stat_usunc.attr,
+ &dev_attr_stat_dsunc.attr,
+ &dev_attr_stat_firmid.attr,
+ NULL,
+};
+static struct attribute_group attr_grp = {
+ .attrs = attrs,
+};
static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
const struct usb_device_id *id)
@@ -1702,43 +1713,25 @@ static int uea_bind(struct usbatm_data *usbatm, struct usb_interface *intf,
}
}
+ ret = sysfs_create_group(&intf->dev.kobj, &attr_grp);
+ if (ret < 0)
+ goto error;
+
ret = uea_boot(sc);
- if (ret < 0) {
- kfree(sc);
- return ret;
- }
+ if (ret < 0)
+ goto error;
- create_fs_entries(sc, intf);
return 0;
-}
-
-static void destroy_fs_entries(struct uea_softc *sc, struct usb_interface *intf)
-{
- /* sysfs interface */
- device_remove_file(&intf->dev, &dev_attr_stat_status);
- device_remove_file(&intf->dev, &dev_attr_stat_mflags);
- device_remove_file(&intf->dev, &dev_attr_stat_human_status);
- device_remove_file(&intf->dev, &dev_attr_stat_delin);
- device_remove_file(&intf->dev, &dev_attr_stat_vidcpe);
- device_remove_file(&intf->dev, &dev_attr_stat_usrate);
- device_remove_file(&intf->dev, &dev_attr_stat_dsrate);
- device_remove_file(&intf->dev, &dev_attr_stat_usattenuation);
- device_remove_file(&intf->dev, &dev_attr_stat_dsattenuation);
- device_remove_file(&intf->dev, &dev_attr_stat_usmargin);
- device_remove_file(&intf->dev, &dev_attr_stat_dsmargin);
- device_remove_file(&intf->dev, &dev_attr_stat_txflow);
- device_remove_file(&intf->dev, &dev_attr_stat_rxflow);
- device_remove_file(&intf->dev, &dev_attr_stat_uscorr);
- device_remove_file(&intf->dev, &dev_attr_stat_dscorr);
- device_remove_file(&intf->dev, &dev_attr_stat_usunc);
- device_remove_file(&intf->dev, &dev_attr_stat_dsunc);
+error:
+ kfree(sc);
+ return ret;
}
static void uea_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
{
struct uea_softc *sc = usbatm->driver_data;
- destroy_fs_entries(sc, intf);
+ sysfs_remove_group(&intf->dev.kobj, &attr_grp);
uea_stop(sc);
kfree(sc);
}
@@ -1759,10 +1752,10 @@ static int uea_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *usb = interface_to_usbdev(intf);
uea_enters(usb);
- uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s\n",
+ uea_info(usb, "ADSL device founded vid (%#X) pid (%#X) : %s %s\n",
le16_to_cpu(usb->descriptor.idVendor),
le16_to_cpu(usb->descriptor.idProduct),
- chip_name[UEA_CHIP_VERSION(id)]);
+ chip_name[UEA_CHIP_VERSION(id)], IS_ISDN(usb)?"isdn":"pots");
usb_reset_device(usb);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
index a38701c742c3..ec63b0ee0743 100644
--- a/drivers/usb/atm/usbatm.c
+++ b/drivers/usb/atm/usbatm.c
@@ -254,7 +254,7 @@ static int usbatm_submit_urb(struct urb *urb)
return ret;
}
-static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
+static void usbatm_complete(struct urb *urb)
{
struct usbatm_channel *channel = urb->context;
unsigned long flags;
@@ -1001,6 +1001,7 @@ static int usbatm_do_heavy_init(void *arg)
daemonize(instance->driver->driver_name);
allow_signal(SIGTERM);
+ instance->thread_pid = current->pid;
complete(&instance->thread_started);
@@ -1025,10 +1026,6 @@ static int usbatm_heavy_init(struct usbatm_data *instance)
return ret;
}
- mutex_lock(&instance->serialize);
- instance->thread_pid = ret;
- mutex_unlock(&instance->serialize);
-
wait_for_completion(&instance->thread_started);
return 0;
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index ca90326f2f5c..9a9012fd284b 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -218,7 +218,7 @@ static int acm_write_start(struct acm *acm)
*/
/* control interface reports status changes with "interrupt" transfers */
-static void acm_ctrl_irq(struct urb *urb, struct pt_regs *regs)
+static void acm_ctrl_irq(struct urb *urb)
{
struct acm *acm = urb->context;
struct usb_cdc_notification *dr = urb->transfer_buffer;
@@ -285,7 +285,7 @@ exit:
}
/* data interface returns incoming bytes, or we got unthrottled */
-static void acm_read_bulk(struct urb *urb, struct pt_regs *regs)
+static void acm_read_bulk(struct urb *urb)
{
struct acm_rb *buf;
struct acm_ru *rcv = urb->context;
@@ -325,7 +325,7 @@ static void acm_rx_tasklet(unsigned long _acm)
struct acm_rb *buf;
struct tty_struct *tty = acm->tty;
struct acm_ru *rcv;
- //unsigned long flags;
+ unsigned long flags;
int i = 0;
dbg("Entering acm_rx_tasklet");
@@ -333,15 +333,15 @@ static void acm_rx_tasklet(unsigned long _acm)
return;
next_buffer:
- spin_lock(&acm->read_lock);
+ spin_lock_irqsave(&acm->read_lock, flags);
if (list_empty(&acm->filled_read_bufs)) {
- spin_unlock(&acm->read_lock);
+ spin_unlock_irqrestore(&acm->read_lock, flags);
goto urbs;
}
buf = list_entry(acm->filled_read_bufs.next,
struct acm_rb, list);
list_del(&buf->list);
- spin_unlock(&acm->read_lock);
+ spin_unlock_irqrestore(&acm->read_lock, flags);
dbg("acm_rx_tasklet: procesing buf 0x%p, size = %d", buf, buf->size);
@@ -356,29 +356,29 @@ next_buffer:
memmove(buf->base, buf->base + i, buf->size - i);
buf->size -= i;
spin_unlock(&acm->throttle_lock);
- spin_lock(&acm->read_lock);
+ spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->filled_read_bufs);
- spin_unlock(&acm->read_lock);
+ spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
spin_unlock(&acm->throttle_lock);
- spin_lock(&acm->read_lock);
+ spin_lock_irqsave(&acm->read_lock, flags);
list_add(&buf->list, &acm->spare_read_bufs);
- spin_unlock(&acm->read_lock);
+ spin_unlock_irqrestore(&acm->read_lock, flags);
goto next_buffer;
urbs:
while (!list_empty(&acm->spare_read_bufs)) {
- spin_lock(&acm->read_lock);
+ spin_lock_irqsave(&acm->read_lock, flags);
if (list_empty(&acm->spare_read_urbs)) {
- spin_unlock(&acm->read_lock);
+ spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
rcv = list_entry(acm->spare_read_urbs.next,
struct acm_ru, list);
list_del(&rcv->list);
- spin_unlock(&acm->read_lock);
+ spin_unlock_irqrestore(&acm->read_lock, flags);
buf = list_entry(acm->spare_read_bufs.next,
struct acm_rb, list);
@@ -400,16 +400,16 @@ urbs:
free-urbs-pool and resubmited ASAP */
if (usb_submit_urb(rcv->urb, GFP_ATOMIC) < 0) {
list_add(&buf->list, &acm->spare_read_bufs);
- spin_lock(&acm->read_lock);
+ spin_lock_irqsave(&acm->read_lock, flags);
list_add(&rcv->list, &acm->spare_read_urbs);
- spin_unlock(&acm->read_lock);
+ spin_unlock_irqrestore(&acm->read_lock, flags);
return;
}
}
}
/* data interface wrote those outgoing bytes */
-static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
+static void acm_write_bulk(struct urb *urb)
{
struct acm *acm = (struct acm *)urb->context;
@@ -1083,6 +1083,9 @@ static struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
+ { USB_DEVICE(0x079b, 0x000f), /* BT On-Air USB MODEM */
+ .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+ },
{ USB_DEVICE(0x0ace, 0x1608), /* ZyDAS 56K USB MODEM */
.driver_info = SINGLE_RX_URB, /* firmware bug */
},
@@ -1120,7 +1123,7 @@ static struct usb_driver acm_driver = {
* TTY driver structures.
*/
-static struct tty_operations acm_ops = {
+static const struct tty_operations acm_ops = {
.open = acm_tty_open,
.close = acm_tty_close,
.write = acm_tty_write,
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 48dee4b8d8e5..809d465eb257 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -154,6 +154,7 @@ struct usblp {
unsigned char used; /* True if open */
unsigned char present; /* True if not disconnected */
unsigned char bidir; /* interface is bidirectional */
+ unsigned char sleeping; /* interface is suspended */
unsigned char *device_id_string; /* IEEE 1284 DEVICE ID string (ptr) */
/* first 2 bytes are (big-endian) length */
};
@@ -183,6 +184,7 @@ static void usblp_dump(struct usblp *usblp) {
dbg("quirks=%d", usblp->quirks);
dbg("used=%d", usblp->used);
dbg("bidir=%d", usblp->bidir);
+ dbg("sleeping=%d", usblp->sleeping);
dbg("device_id_string=\"%s\"",
usblp->device_id_string ?
usblp->device_id_string + 2 :
@@ -271,7 +273,7 @@ static int proto_bias = -1;
* URB callback.
*/
-static void usblp_bulk_read(struct urb *urb, struct pt_regs *regs)
+static void usblp_bulk_read(struct urb *urb)
{
struct usblp *usblp = urb->context;
@@ -288,7 +290,7 @@ unplug:
wake_up_interruptible(&usblp->wait);
}
-static void usblp_bulk_write(struct urb *urb, struct pt_regs *regs)
+static void usblp_bulk_write(struct urb *urb)
{
struct usblp *usblp = urb->context;
@@ -338,6 +340,20 @@ static int usblp_check_status(struct usblp *usblp, int err)
return newerr;
}
+static int handle_bidir (struct usblp *usblp)
+{
+ if (usblp->bidir && usblp->used && !usblp->sleeping) {
+ usblp->readcount = 0;
+ usblp->readurb->dev = usblp->dev;
+ if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
+ usblp->used = 0;
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
/*
* File op functions.
*/
@@ -390,14 +406,9 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->writeurb->status = 0;
usblp->readurb->status = 0;
- if (usblp->bidir) {
- usblp->readcount = 0;
- usblp->readurb->dev = usblp->dev;
- if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) {
- retval = -EIO;
- usblp->used = 0;
- file->private_data = NULL;
- }
+ if (handle_bidir(usblp) < 0) {
+ file->private_data = NULL;
+ retval = -EIO;
}
out:
mutex_unlock (&usblp_mutex);
@@ -460,6 +471,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
goto done;
}
+ if (usblp->sleeping) {
+ retval = -ENODEV;
+ goto done;
+ }
+
dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
@@ -658,6 +674,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
return -ENODEV;
}
+ if (usblp->sleeping) {
+ up (&usblp->sem);
+ return writecount ? writecount : -ENODEV;
+ }
+
if (usblp->writeurb->status != 0) {
if (usblp->quirks & USBLP_QUIRK_BIDIR) {
if (!usblp->wcomplete)
@@ -749,6 +770,11 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
goto done;
}
+ if (usblp->sleeping) {
+ count = -ENODEV;
+ goto done;
+ }
+
if (usblp->readurb->status) {
err("usblp%d: error %d reading from printer",
usblp->minor, usblp->readurb->status);
@@ -813,7 +839,7 @@ static unsigned int usblp_quirks (__u16 vendor, __u16 product)
return 0;
}
-static struct file_operations usblp_fops = {
+static const struct file_operations usblp_fops = {
.owner = THIS_MODULE,
.read = usblp_read,
.write = usblp_write,
@@ -927,7 +953,9 @@ static int usblp_probe(struct usb_interface *intf,
/* Retrieve and store the device ID string. */
usblp_cache_device_id_string(usblp);
- device_create_file(&intf->dev, &dev_attr_ieee1284_id);
+ retval = device_create_file(&intf->dev, &dev_attr_ieee1284_id);
+ if (retval)
+ goto abort_intfdata;
#ifdef DEBUG
usblp_check_status(usblp, 0);
@@ -1021,18 +1049,13 @@ static int usblp_select_alts(struct usblp *usblp)
for (e = 0; e < ifd->desc.bNumEndpoints; e++) {
epd = &ifd->endpoint[e].desc;
- if ((epd->bmAttributes&USB_ENDPOINT_XFERTYPE_MASK)!=
- USB_ENDPOINT_XFER_BULK)
- continue;
-
- if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
+ if (usb_endpoint_is_bulk_out(epd))
if (!epwrite)
epwrite = epd;
- } else {
+ if (usb_endpoint_is_bulk_in(epd))
if (!epread)
epread = epd;
- }
}
/* Ignore buggy hardware without the right endpoints. */
@@ -1170,6 +1193,41 @@ static void usblp_disconnect(struct usb_interface *intf)
mutex_unlock (&usblp_mutex);
}
+static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
+{
+ struct usblp *usblp = usb_get_intfdata (intf);
+
+ /* this races against normal access and open */
+ mutex_lock (&usblp_mutex);
+ down (&usblp->sem);
+ /* we take no more IO */
+ usblp->sleeping = 1;
+ /* we wait for anything printing */
+ wait_event (usblp->wait, usblp->wcomplete || !usblp->present);
+ usblp_unlink_urbs(usblp);
+ up (&usblp->sem);
+ mutex_unlock (&usblp_mutex);
+
+ return 0;
+}
+
+static int usblp_resume (struct usb_interface *intf)
+{
+ struct usblp *usblp = usb_get_intfdata (intf);
+ int r;
+
+ mutex_lock (&usblp_mutex);
+ down (&usblp->sem);
+
+ usblp->sleeping = 0;
+ r = handle_bidir (usblp);
+
+ up (&usblp->sem);
+ mutex_unlock (&usblp_mutex);
+
+ return r;
+}
+
static struct usb_device_id usblp_ids [] = {
{ USB_DEVICE_INFO(7, 1, 1) },
{ USB_DEVICE_INFO(7, 1, 2) },
@@ -1186,6 +1244,8 @@ static struct usb_driver usblp_driver = {
.name = "usblp",
.probe = usblp_probe,
.disconnect = usblp_disconnect,
+ .suspend = usblp_suspend,
+ .resume = usblp_resume,
.id_table = usblp_ids,
};
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index ec510922af63..34e9bac319b4 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -4,7 +4,7 @@
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o endpoint.o \
- devio.o notify.o
+ devio.o notify.o generic.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index f4f4ef0f377a..840442a25b61 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -104,7 +104,7 @@ void *hcd_buffer_alloc (
dma_addr_t *dma
)
{
- struct usb_hcd *hcd = bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
/* some USB hosts just use PIO */
@@ -127,7 +127,7 @@ void hcd_buffer_free (
dma_addr_t dma
)
{
- struct usb_hcd *hcd = bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(bus);
int i;
if (!addr)
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 4c9e63e665b6..bfb3731d42db 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -475,7 +475,9 @@ int usb_get_configuration(struct usb_device *dev)
if (result < 0) {
dev_err(ddev, "unable to read config index %d "
"descriptor/%s\n", cfgno, "start");
- goto err;
+ dev_err(ddev, "chopping to %d config(s)\n", cfgno);
+ dev->descriptor.bNumConfigurations = cfgno;
+ break;
} else if (result < 4) {
dev_err(ddev, "config index %d descriptor too short "
"(expected %i, got %i)\n", cfgno,
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index c0f37343a276..3538c2fdadfe 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -593,7 +593,7 @@ static ssize_t usb_device_read(struct file *file, char __user *buf, size_t nbyte
/* Kernel lock for "lastev" protection */
static unsigned int usb_device_poll(struct file *file, struct poll_table_struct *wait)
{
- struct usb_device_status *st = (struct usb_device_status *)file->private_data;
+ struct usb_device_status *st = file->private_data;
unsigned int mask = 0;
lock_kernel();
@@ -603,7 +603,7 @@ static unsigned int usb_device_poll(struct file *file, struct poll_table_struct
unlock_kernel();
return POLLIN;
}
-
+
/* we may have dropped BKL - need to check for having lost the race */
if (file->private_data) {
kfree(st);
@@ -667,7 +667,7 @@ static loff_t usb_device_lseek(struct file * file, loff_t offset, int orig)
return ret;
}
-struct file_operations usbfs_devices_fops = {
+const struct file_operations usbfs_devices_fops = {
.llseek = usb_device_lseek,
.read = usb_device_read,
.poll = usb_device_poll,
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 218621b9958e..fed92be63b5e 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -59,10 +59,13 @@
#define USB_DEVICE_MAX USB_MAXBUS * 128
static struct class *usb_device_class;
+/* Mutual exclusion for removal, open, and release */
+DEFINE_MUTEX(usbfs_mutex);
+
struct async {
struct list_head asynclist;
struct dev_state *ps;
- pid_t pid;
+ struct pid *pid;
uid_t uid, euid;
unsigned int signr;
unsigned int ifnum;
@@ -87,9 +90,10 @@ MODULE_PARM_DESC (usbfs_snoop, "true to log all usbfs traffic");
#define MAX_USBFS_BUFFER_SIZE 16384
-static inline int connected (struct usb_device *dev)
+static inline int connected (struct dev_state *ps)
{
- return dev->state != USB_STATE_NOTATTACHED;
+ return (!list_empty(&ps->list) &&
+ ps->dev->state != USB_STATE_NOTATTACHED);
}
static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
@@ -118,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
ssize_t ret = 0;
unsigned len;
@@ -127,7 +131,7 @@ static ssize_t usbdev_read(struct file *file, char __user *buf, size_t nbytes, l
pos = *ppos;
usb_lock_device(dev);
- if (!connected(dev)) {
+ if (!connected(ps)) {
ret = -ENODEV;
goto err;
} else if (pos < 0) {
@@ -221,6 +225,7 @@ static struct async *alloc_async(unsigned int numisoframes)
static void free_async(struct async *as)
{
+ put_pid(as->pid);
kfree(as->urb->transfer_buffer);
kfree(as->urb->setup_packet);
usb_free_urb(as->urb);
@@ -299,9 +304,9 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
printk("\n");
}
-static void async_completed(struct urb *urb, struct pt_regs *regs)
+static void async_completed(struct urb *urb)
{
- struct async *as = (struct async *)urb->context;
+ struct async *as = urb->context;
struct dev_state *ps = as->ps;
struct siginfo sinfo;
@@ -313,7 +318,7 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
sinfo.si_errno = as->urb->status;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = as->userurb;
- kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
+ kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
as->euid, as->secid);
}
snoop(&urb->dev->dev, "urb complete\n");
@@ -541,25 +546,25 @@ static int usbdev_open(struct inode *inode, struct file *file)
struct dev_state *ps;
int ret;
- /*
- * no locking necessary here, as chrdev_open has the kernel lock
- * (still acquire the kernel lock for safety)
- */
+ /* Protect against simultaneous removal or release */
+ mutex_lock(&usbfs_mutex);
+
ret = -ENOMEM;
if (!(ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL)))
- goto out_nolock;
+ goto out;
- lock_kernel();
ret = -ENOENT;
/* check if we are called from a real node or usbfs */
if (imajor(inode) == USB_DEVICE_MAJOR)
dev = usbdev_lookup_minor(iminor(inode));
if (!dev)
- dev = inode->u.generic_ip;
- if (!dev) {
- kfree(ps);
+ dev = inode->i_private;
+ if (!dev)
goto out;
- }
+ ret = usb_autoresume_device(dev, 1);
+ if (ret)
+ goto out;
+
usb_get_dev(dev);
ret = 0;
ps->dev = dev;
@@ -569,7 +574,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&ps->async_completed);
init_waitqueue_head(&ps->wait);
ps->discsignr = 0;
- ps->disc_pid = current->pid;
+ ps->disc_pid = get_pid(task_pid(current));
ps->disc_uid = current->uid;
ps->disc_euid = current->euid;
ps->disccontext = NULL;
@@ -579,30 +584,37 @@ static int usbdev_open(struct inode *inode, struct file *file)
list_add_tail(&ps->list, &dev->filelist);
file->private_data = ps;
out:
- unlock_kernel();
- out_nolock:
- return ret;
+ if (ret)
+ kfree(ps);
+ mutex_unlock(&usbfs_mutex);
+ return ret;
}
static int usbdev_release(struct inode *inode, struct file *file)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
unsigned int ifnum;
usb_lock_device(dev);
+
+ /* Protect against simultaneous open */
+ mutex_lock(&usbfs_mutex);
list_del_init(&ps->list);
+ mutex_unlock(&usbfs_mutex);
+
for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
ifnum++) {
if (test_bit(ifnum, &ps->ifclaimed))
releaseintf(ps, ifnum);
}
destroy_all_async(ps);
+ usb_autosuspend_device(dev, 1);
usb_unlock_device(dev);
usb_put_dev(dev);
- ps->dev = NULL;
+ put_pid(ps->disc_pid);
kfree(ps);
- return 0;
+ return 0;
}
static int proc_control(struct dev_state *ps, void __user *arg)
@@ -1053,7 +1065,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
as->userbuffer = NULL;
as->signr = uurb->signr;
as->ifnum = ifnum;
- as->pid = current->pid;
+ as->pid = get_pid(task_pid(current));
as->uid = current->uid;
as->euid = current->euid;
security_task_getsecid(current, &as->secid);
@@ -1204,7 +1216,7 @@ static int proc_submiturb_compat(struct dev_state *ps, void __user *arg)
{
struct usbdevfs_urb uurb;
- if (get_urb32(&uurb,(struct usbdevfs_urb32 *)arg))
+ if (get_urb32(&uurb,(struct usbdevfs_urb32 __user *)arg))
return -EFAULT;
return proc_do_submiturb(ps, &uurb, ((struct usbdevfs_urb32 __user *)arg)->iso_frame_desc, arg);
@@ -1239,7 +1251,7 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
}
free_async(as);
- if (put_user((u32)(u64)addr, (u32 __user *)arg))
+ if (put_user(ptr_to_compat(addr), (u32 __user *)arg))
return -EFAULT;
return 0;
}
@@ -1322,7 +1334,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
}
}
- if (!connected(ps->dev)) {
+ if (!connected(ps)) {
kfree(buf);
return -ENODEV;
}
@@ -1349,7 +1361,7 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
/* let kernel drivers try to (re)bind to the interface */
case USBDEVFS_CONNECT:
usb_unlock_device(ps->dev);
- bus_rescan_devices(intf->dev.bus);
+ retval = bus_rescan_devices(intf->dev.bus);
usb_lock_device(ps->dev);
break;
@@ -1413,7 +1425,7 @@ static int proc_ioctl_compat(struct dev_state *ps, compat_uptr_t arg)
*/
static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
+ struct dev_state *ps = file->private_data;
struct usb_device *dev = ps->dev;
void __user *p = (void __user *)arg;
int ret = -ENOTTY;
@@ -1421,7 +1433,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!(file->f_mode & FMODE_WRITE))
return -EPERM;
usb_lock_device(dev);
- if (!connected(dev)) {
+ if (!connected(ps)) {
usb_unlock_device(dev);
return -ENODEV;
}
@@ -1508,7 +1520,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
case USBDEVFS_IOCTL32:
snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
- ret = proc_ioctl_compat(ps, (compat_uptr_t)(long)p);
+ ret = proc_ioctl_compat(ps, ptr_to_compat(p));
break;
#endif
@@ -1556,18 +1568,18 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
/* No kernel lock - fine */
static unsigned int usbdev_poll(struct file *file, struct poll_table_struct *wait)
{
- struct dev_state *ps = (struct dev_state *)file->private_data;
- unsigned int mask = 0;
+ struct dev_state *ps = file->private_data;
+ unsigned int mask = 0;
poll_wait(file, &ps->wait, wait);
if (file->f_mode & FMODE_WRITE && !list_empty(&ps->async_completed))
mask |= POLLOUT | POLLWRNORM;
- if (!connected(ps->dev))
+ if (!connected(ps))
mask |= POLLERR | POLLHUP;
return mask;
}
-struct file_operations usbfs_device_file_operations = {
+const struct file_operations usbfs_device_file_operations = {
.llseek = usbdev_lseek,
.read = usbdev_read,
.poll = usbdev_poll,
@@ -1576,15 +1588,18 @@ struct file_operations usbfs_device_file_operations = {
.release = usbdev_release,
};
-static void usbdev_add(struct usb_device *dev)
+static int usbdev_add(struct usb_device *dev)
{
int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
dev->class_dev = class_device_create(usb_device_class, NULL,
MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
"usbdev%d.%d", dev->bus->busnum, dev->devnum);
+ if (IS_ERR(dev->class_dev))
+ return PTR_ERR(dev->class_dev);
dev->class_dev->class_data = dev;
+ return 0;
}
static void usbdev_remove(struct usb_device *dev)
@@ -1597,7 +1612,8 @@ static int usbdev_notify(struct notifier_block *self, unsigned long action,
{
switch (action) {
case USB_DEVICE_ADD:
- usbdev_add(dev);
+ if (usbdev_add(dev))
+ return NOTIFY_BAD;
break;
case USB_DEVICE_REMOVE:
usbdev_remove(dev);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index ec8906501415..113e484c763e 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -17,12 +17,14 @@
*
* NOTE! This is not actually a driver at all, rather this is
* just a collection of helper routines that implement the
- * generic USB things that the real drivers can use..
+ * matching, probing, releasing, suspending and resuming for
+ * real drivers.
*
*/
#include <linux/device.h>
#include <linux/usb.h>
+#include <linux/workqueue.h>
#include "hcd.h"
#include "usb.h"
@@ -34,38 +36,6 @@ struct usb_dynid {
struct usb_device_id id;
};
-
-static int generic_probe(struct device *dev)
-{
- return 0;
-}
-static int generic_remove(struct device *dev)
-{
- struct usb_device *udev = to_usb_device(dev);
-
- /* if this is only an unbind, not a physical disconnect, then
- * unconfigure the device */
- if (udev->state == USB_STATE_CONFIGURED)
- usb_set_configuration(udev, 0);
-
- /* in case the call failed or the device was suspended */
- if (udev->state >= USB_STATE_CONFIGURED)
- usb_disable_device(udev, 0);
- return 0;
-}
-
-struct device_driver usb_generic_driver = {
- .owner = THIS_MODULE,
- .name = "usb",
- .bus = &usb_bus_type,
- .probe = generic_probe,
- .remove = generic_remove,
-};
-
-/* Fun hack to determine if the struct device is a
- * usb device or a usb interface. */
-int usb_generic_driver_data;
-
#ifdef CONFIG_HOTPLUG
/*
@@ -80,6 +50,7 @@ static ssize_t store_new_id(struct device_driver *driver,
u32 idVendor = 0;
u32 idProduct = 0;
int fields = 0;
+ int retval = 0;
fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
if (fields < 2)
@@ -99,10 +70,12 @@ static ssize_t store_new_id(struct device_driver *driver,
spin_unlock(&usb_drv->dynids.lock);
if (get_driver(driver)) {
- driver_attach(driver);
+ retval = driver_attach(driver);
put_driver(driver);
}
+ if (retval)
+ return retval;
return count;
}
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
@@ -115,7 +88,7 @@ static int usb_create_newid_file(struct usb_driver *usb_drv)
goto exit;
if (usb_drv->probe != NULL)
- error = sysfs_create_file(&usb_drv->driver.kobj,
+ error = sysfs_create_file(&usb_drv->drvwrap.driver.kobj,
&driver_attr_new_id.attr);
exit:
return error;
@@ -127,7 +100,7 @@ static void usb_remove_newid_file(struct usb_driver *usb_drv)
return;
if (usb_drv->probe != NULL)
- sysfs_remove_file(&usb_drv->driver.kobj,
+ sysfs_remove_file(&usb_drv->drvwrap.driver.kobj,
&driver_attr_new_id.attr);
}
@@ -174,21 +147,57 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
}
-/* called from driver core with usb_bus_type.subsys writelock */
+/* called from driver core with dev locked */
+static int usb_probe_device(struct device *dev)
+{
+ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
+ struct usb_device *udev;
+ int error = -ENODEV;
+
+ dev_dbg(dev, "%s\n", __FUNCTION__);
+
+ if (!is_usb_device(dev)) /* Sanity check */
+ return error;
+
+ udev = to_usb_device(dev);
+
+ /* TODO: Add real matching code */
+
+ /* The device should always appear to be in use
+ * unless the driver suports autosuspend.
+ */
+ udev->pm_usage_cnt = !(udriver->supports_autosuspend);
+
+ error = udriver->probe(udev);
+ return error;
+}
+
+/* called from driver core with dev locked */
+static int usb_unbind_device(struct device *dev)
+{
+ struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
+
+ udriver->disconnect(to_usb_device(dev));
+ return 0;
+}
+
+
+/* called from driver core with dev locked */
static int usb_probe_interface(struct device *dev)
{
- struct usb_interface * intf = to_usb_interface(dev);
- struct usb_driver * driver = to_usb_driver(dev->driver);
+ struct usb_driver *driver = to_usb_driver(dev->driver);
+ struct usb_interface *intf;
+ struct usb_device *udev;
const struct usb_device_id *id;
int error = -ENODEV;
dev_dbg(dev, "%s\n", __FUNCTION__);
- if (!driver->probe)
+ if (is_usb_device(dev)) /* Sanity check */
return error;
- /* FIXME we'd much prefer to just resume it ... */
- if (interface_to_usbdev(intf)->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
+
+ intf = to_usb_interface(dev);
+ udev = interface_to_usbdev(intf);
id = usb_match_id(intf, driver->id_table);
if (!id)
@@ -196,48 +205,165 @@ static int usb_probe_interface(struct device *dev)
if (id) {
dev_dbg(dev, "%s - got id\n", __FUNCTION__);
+ error = usb_autoresume_device(udev, 1);
+ if (error)
+ return error;
+
/* Interface "power state" doesn't correspond to any hardware
* state whatsoever. We use it to record when it's bound to
* a driver that may start I/0: it's not frozen/quiesced.
*/
mark_active(intf);
intf->condition = USB_INTERFACE_BINDING;
+
+ /* The interface should always appear to be in use
+ * unless the driver suports autosuspend.
+ */
+ intf->pm_usage_cnt = !(driver->supports_autosuspend);
+
error = driver->probe(intf, id);
if (error) {
mark_quiesced(intf);
+ intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
} else
intf->condition = USB_INTERFACE_BOUND;
+
+ usb_autosuspend_device(udev, 1);
}
return error;
}
-/* called from driver core with usb_bus_type.subsys writelock */
+/* called from driver core with dev locked */
static int usb_unbind_interface(struct device *dev)
{
+ struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf = to_usb_interface(dev);
- struct usb_driver *driver = to_usb_driver(intf->dev.driver);
+ struct usb_device *udev;
+ int error;
intf->condition = USB_INTERFACE_UNBINDING;
+ /* Autoresume for set_interface call below */
+ udev = interface_to_usbdev(intf);
+ error = usb_autoresume_device(udev, 1);
+
/* release all urbs for this interface */
usb_disable_interface(interface_to_usbdev(intf), intf);
- if (driver && driver->disconnect)
- driver->disconnect(intf);
+ driver->disconnect(intf);
/* reset other interface state */
usb_set_interface(interface_to_usbdev(intf),
intf->altsetting[0].desc.bInterfaceNumber,
0);
usb_set_intfdata(intf, NULL);
+
intf->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(intf);
+ intf->needs_remote_wakeup = 0;
+
+ if (!error)
+ usb_autosuspend_device(udev, 1);
return 0;
}
+/**
+ * usb_driver_claim_interface - bind a driver to an interface
+ * @driver: the driver to be bound
+ * @iface: the interface to which it will be bound; must be in the
+ * usb device's active configuration
+ * @priv: driver data associated with that interface
+ *
+ * This is used by usb device drivers that need to claim more than one
+ * interface on a device when probing (audio and acm are current examples).
+ * No device driver should directly modify internal usb_interface or
+ * usb_device structure members.
+ *
+ * Few drivers should need to use this routine, since the most natural
+ * way to bind to an interface is to return the private data from
+ * the driver's probe() method.
+ *
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock. So driver probe() entries don't need extra locking,
+ * but other call contexts may need to explicitly claim those locks.
+ */
+int usb_driver_claim_interface(struct usb_driver *driver,
+ struct usb_interface *iface, void* priv)
+{
+ struct device *dev = &iface->dev;
+ struct usb_device *udev = interface_to_usbdev(iface);
+ int retval = 0;
+
+ if (dev->driver)
+ return -EBUSY;
+
+ dev->driver = &driver->drvwrap.driver;
+ usb_set_intfdata(iface, priv);
+
+ usb_pm_lock(udev);
+ iface->condition = USB_INTERFACE_BOUND;
+ mark_active(iface);
+ iface->pm_usage_cnt = !(driver->supports_autosuspend);
+ usb_pm_unlock(udev);
+
+ /* if interface was already added, bind now; else let
+ * the future device_add() bind it, bypassing probe()
+ */
+ if (device_is_registered(dev))
+ retval = device_bind_driver(dev);
+
+ return retval;
+}
+EXPORT_SYMBOL(usb_driver_claim_interface);
+
+/**
+ * usb_driver_release_interface - unbind a driver from an interface
+ * @driver: the driver to be unbound
+ * @iface: the interface from which it will be unbound
+ *
+ * This can be used by drivers to release an interface without waiting
+ * for their disconnect() methods to be called. In typical cases this
+ * also causes the driver disconnect() method to be called.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ * Callers must own the device lock and the driver model's usb_bus_type.subsys
+ * writelock. So driver disconnect() entries don't need extra locking,
+ * but other call contexts may need to explicitly claim those locks.
+ */
+void usb_driver_release_interface(struct usb_driver *driver,
+ struct usb_interface *iface)
+{
+ struct device *dev = &iface->dev;
+ struct usb_device *udev = interface_to_usbdev(iface);
+
+ /* this should never happen, don't release something that's not ours */
+ if (!dev->driver || dev->driver != &driver->drvwrap.driver)
+ return;
+
+ /* don't release from within disconnect() */
+ if (iface->condition != USB_INTERFACE_BOUND)
+ return;
+
+ /* don't release if the interface hasn't been added yet */
+ if (device_is_registered(dev)) {
+ iface->condition = USB_INTERFACE_UNBINDING;
+ device_release_driver(dev);
+ }
+
+ dev->driver = NULL;
+ usb_set_intfdata(iface, NULL);
+
+ usb_pm_lock(udev);
+ iface->condition = USB_INTERFACE_UNBOUND;
+ mark_quiesced(iface);
+ iface->needs_remote_wakeup = 0;
+ usb_pm_unlock(udev);
+}
+EXPORT_SYMBOL(usb_driver_release_interface);
+
/* returns 0 if no match, 1 if match */
static int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id)
@@ -381,35 +507,223 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_match_id);
int usb_device_match(struct device *dev, struct device_driver *drv)
{
+ /* devices and interfaces are handled separately */
+ if (is_usb_device(dev)) {
+
+ /* interface drivers never match devices */
+ if (!is_usb_device_driver(drv))
+ return 0;
+
+ /* TODO: Add real matching code */
+ return 1;
+
+ } else {
+ struct usb_interface *intf;
+ struct usb_driver *usb_drv;
+ const struct usb_device_id *id;
+
+ /* device drivers never match interfaces */
+ if (is_usb_device_driver(drv))
+ return 0;
+
+ intf = to_usb_interface(dev);
+ usb_drv = to_usb_driver(drv);
+
+ id = usb_match_id(intf, usb_drv->id_table);
+ if (id)
+ return 1;
+
+ id = usb_match_dynamic_id(intf, usb_drv);
+ if (id)
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG
+
+/*
+ * This sends an uevent to userspace, typically helping to load driver
+ * or other modules, configure the device, and more. Drivers can provide
+ * a MODULE_DEVICE_TABLE to help with module loading subtasks.
+ *
+ * We're called either from khubd (the typical case) or from root hub
+ * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
+ * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
+ * device (and this configuration!) are still present.
+ */
+static int usb_uevent(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
struct usb_interface *intf;
- struct usb_driver *usb_drv;
- const struct usb_device_id *id;
+ struct usb_device *usb_dev;
+ struct usb_host_interface *alt;
+ int i = 0;
+ int length = 0;
- /* check for generic driver, which we don't match any device with */
- if (drv == &usb_generic_driver)
- return 0;
+ if (!dev)
+ return -ENODEV;
- intf = to_usb_interface(dev);
- usb_drv = to_usb_driver(drv);
+ /* driver is often null here; dev_dbg() would oops */
+ pr_debug ("usb %s: uevent\n", dev->bus_id);
- id = usb_match_id(intf, usb_drv->id_table);
- if (id)
- return 1;
+ if (is_usb_device(dev)) {
+ usb_dev = to_usb_device(dev);
+ alt = NULL;
+ } else {
+ intf = to_usb_interface(dev);
+ usb_dev = interface_to_usbdev(intf);
+ alt = intf->cur_altsetting;
+ }
+
+ if (usb_dev->devnum < 0) {
+ pr_debug ("usb %s: already deleted?\n", dev->bus_id);
+ return -ENODEV;
+ }
+ if (!usb_dev->bus) {
+ pr_debug ("usb %s: bus removed?\n", dev->bus_id);
+ return -ENODEV;
+ }
+
+#ifdef CONFIG_USB_DEVICEFS
+ /* If this is available, userspace programs can directly read
+ * all the device descriptors we don't tell them about. Or
+ * even act as usermode drivers.
+ *
+ * FIXME reduce hardwired intelligence here
+ */
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "DEVICE=/proc/bus/usb/%03d/%03d",
+ usb_dev->bus->busnum, usb_dev->devnum))
+ return -ENOMEM;
+#endif
+
+ /* per-device configurations are common */
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "PRODUCT=%x/%x/%x",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice)))
+ return -ENOMEM;
+
+ /* class-based driver binding models */
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "TYPE=%d/%d/%d",
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol))
+ return -ENOMEM;
+
+ if (!is_usb_device(dev)) {
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "INTERFACE=%d/%d/%d",
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
+ return -ENOMEM;
+
+ if (add_uevent_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ le16_to_cpu(usb_dev->descriptor.bcdDevice),
+ usb_dev->descriptor.bDeviceClass,
+ usb_dev->descriptor.bDeviceSubClass,
+ usb_dev->descriptor.bDeviceProtocol,
+ alt->desc.bInterfaceClass,
+ alt->desc.bInterfaceSubClass,
+ alt->desc.bInterfaceProtocol))
+ return -ENOMEM;
+ }
+
+ envp[i] = NULL;
- id = usb_match_dynamic_id(intf, usb_drv);
- if (id)
- return 1;
return 0;
}
+#else
+
+static int usb_uevent(struct device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ return -ENODEV;
+}
+
+#endif /* CONFIG_HOTPLUG */
+
+/**
+ * usb_register_device_driver - register a USB device (not interface) driver
+ * @new_udriver: USB operations for the device driver
+ * @owner: module owner of this driver.
+ *
+ * Registers a USB device driver with the USB core. The list of
+ * unattached devices will be rescanned whenever a new driver is
+ * added, allowing the new driver to attach to any recognized devices.
+ * Returns a negative error code on failure and 0 on success.
+ */
+int usb_register_device_driver(struct usb_device_driver *new_udriver,
+ struct module *owner)
+{
+ int retval = 0;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ new_udriver->drvwrap.for_devices = 1;
+ new_udriver->drvwrap.driver.name = (char *) new_udriver->name;
+ new_udriver->drvwrap.driver.bus = &usb_bus_type;
+ new_udriver->drvwrap.driver.probe = usb_probe_device;
+ new_udriver->drvwrap.driver.remove = usb_unbind_device;
+ new_udriver->drvwrap.driver.owner = owner;
+
+ retval = driver_register(&new_udriver->drvwrap.driver);
+
+ if (!retval) {
+ pr_info("%s: registered new device driver %s\n",
+ usbcore_name, new_udriver->name);
+ usbfs_update_special();
+ } else {
+ printk(KERN_ERR "%s: error %d registering device "
+ " driver %s\n",
+ usbcore_name, retval, new_udriver->name);
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(usb_register_device_driver);
+
+/**
+ * usb_deregister_device_driver - unregister a USB device (not interface) driver
+ * @udriver: USB operations of the device driver to unregister
+ * Context: must be able to sleep
+ *
+ * Unlinks the specified driver from the internal USB driver list.
+ */
+void usb_deregister_device_driver(struct usb_device_driver *udriver)
+{
+ pr_info("%s: deregistering device driver %s\n",
+ usbcore_name, udriver->name);
+
+ driver_unregister(&udriver->drvwrap.driver);
+ usbfs_update_special();
+}
+EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
+
/**
- * usb_register_driver - register a USB driver
- * @new_driver: USB operations for the driver
+ * usb_register_driver - register a USB interface driver
+ * @new_driver: USB operations for the interface driver
* @owner: module owner of this driver.
*
- * Registers a USB driver with the USB core. The list of unattached
- * interfaces will be rescanned whenever a new driver is added, allowing
- * the new driver to attach to any recognized devices.
+ * Registers a USB interface driver with the USB core. The list of
+ * unattached interfaces will be rescanned whenever a new driver is
+ * added, allowing the new driver to attach to any recognized interfaces.
* Returns a negative error code on failure and 0 on success.
*
* NOTE: if you want your driver to use the USB major number, you must call
@@ -423,23 +737,25 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
if (usb_disabled())
return -ENODEV;
- new_driver->driver.name = (char *)new_driver->name;
- new_driver->driver.bus = &usb_bus_type;
- new_driver->driver.probe = usb_probe_interface;
- new_driver->driver.remove = usb_unbind_interface;
- new_driver->driver.owner = owner;
+ new_driver->drvwrap.for_devices = 0;
+ new_driver->drvwrap.driver.name = (char *) new_driver->name;
+ new_driver->drvwrap.driver.bus = &usb_bus_type;
+ new_driver->drvwrap.driver.probe = usb_probe_interface;
+ new_driver->drvwrap.driver.remove = usb_unbind_interface;
+ new_driver->drvwrap.driver.owner = owner;
spin_lock_init(&new_driver->dynids.lock);
INIT_LIST_HEAD(&new_driver->dynids.list);
- retval = driver_register(&new_driver->driver);
+ retval = driver_register(&new_driver->drvwrap.driver);
if (!retval) {
- pr_info("%s: registered new driver %s\n",
+ pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);
usbfs_update_special();
usb_create_newid_file(new_driver);
} else {
- printk(KERN_ERR "%s: error %d registering driver %s\n",
+ printk(KERN_ERR "%s: error %d registering interface "
+ " driver %s\n",
usbcore_name, retval, new_driver->name);
}
@@ -448,8 +764,8 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
/**
- * usb_deregister - unregister a USB driver
- * @driver: USB operations of the driver to unregister
+ * usb_deregister - unregister a USB interface driver
+ * @driver: USB operations of the interface driver to unregister
* Context: must be able to sleep
*
* Unlinks the specified driver from the internal USB driver list.
@@ -460,12 +776,554 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_register_driver);
*/
void usb_deregister(struct usb_driver *driver)
{
- pr_info("%s: deregistering driver %s\n", usbcore_name, driver->name);
+ pr_info("%s: deregistering interface driver %s\n",
+ usbcore_name, driver->name);
usb_remove_newid_file(driver);
usb_free_dynids(driver);
- driver_unregister(&driver->driver);
+ driver_unregister(&driver->drvwrap.driver);
usbfs_update_special();
}
EXPORT_SYMBOL_GPL_FUTURE(usb_deregister);
+
+#ifdef CONFIG_PM
+
+/* Caller has locked udev's pm_mutex */
+static int suspend_device(struct usb_device *udev, pm_message_t msg)
+{
+ struct usb_device_driver *udriver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state == USB_STATE_SUSPENDED)
+ goto done;
+
+ /* For devices that don't have a driver, we do a standard suspend. */
+ if (udev->dev.driver == NULL) {
+ udev->do_remote_wakeup = 0;
+ status = usb_port_suspend(udev);
+ goto done;
+ }
+
+ udriver = to_usb_device_driver(udev->dev.driver);
+ status = udriver->suspend(udev, msg);
+
+done:
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ udev->dev.power.power_state.event = msg.event;
+ return status;
+}
+
+/* Caller has locked udev's pm_mutex */
+static int resume_device(struct usb_device *udev)
+{
+ struct usb_device_driver *udriver;
+ int status = 0;
+
+ if (udev->state == USB_STATE_NOTATTACHED ||
+ udev->state != USB_STATE_SUSPENDED)
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+ if (udev->dev.driver == NULL) {
+ status = -ENOTCONN;
+ goto done;
+ }
+
+ udriver = to_usb_device_driver(udev->dev.driver);
+ status = udriver->resume(udev);
+
+done:
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ udev->dev.power.power_state.event = PM_EVENT_ON;
+ return status;
+}
+
+/* Caller has locked intf's usb_device's pm mutex */
+static int suspend_interface(struct usb_interface *intf, pm_message_t msg)
+{
+ struct usb_driver *driver;
+ int status = 0;
+
+ /* with no hardware, USB interfaces only use FREEZE and ON states */
+ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+ !is_active(intf))
+ goto done;
+
+ if (intf->condition == USB_INTERFACE_UNBOUND) /* This can't happen */
+ goto done;
+ driver = to_usb_driver(intf->dev.driver);
+
+ if (driver->suspend && driver->resume) {
+ status = driver->suspend(intf, msg);
+ if (status == 0)
+ mark_quiesced(intf);
+ else if (!interface_to_usbdev(intf)->auto_pm)
+ dev_err(&intf->dev, "%s error %d\n",
+ "suspend", status);
+ } else {
+ // FIXME else if there's no suspend method, disconnect...
+ // Not possible if auto_pm is set...
+ dev_warn(&intf->dev, "no suspend for driver %s?\n",
+ driver->name);
+ mark_quiesced(intf);
+ }
+
+done:
+ // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ intf->dev.power.power_state.event = msg.event;
+ return status;
+}
+
+/* Caller has locked intf's usb_device's pm_mutex */
+static int resume_interface(struct usb_interface *intf)
+{
+ struct usb_driver *driver;
+ int status = 0;
+
+ if (interface_to_usbdev(intf)->state == USB_STATE_NOTATTACHED ||
+ is_active(intf))
+ goto done;
+
+ /* Don't let autoresume interfere with unbinding */
+ if (intf->condition == USB_INTERFACE_UNBINDING)
+ goto done;
+
+ /* Can't resume it if it doesn't have a driver. */
+ if (intf->condition == USB_INTERFACE_UNBOUND) {
+ status = -ENOTCONN;
+ goto done;
+ }
+ driver = to_usb_driver(intf->dev.driver);
+
+ if (driver->resume) {
+ status = driver->resume(intf);
+ if (status)
+ dev_err(&intf->dev, "%s error %d\n",
+ "resume", status);
+ else
+ mark_active(intf);
+ } else {
+ dev_warn(&intf->dev, "no resume for driver %s?\n",
+ driver->name);
+ mark_active(intf);
+ }
+
+done:
+ // dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+ if (status == 0)
+ intf->dev.power.power_state.event = PM_EVENT_ON;
+ return status;
+}
+
+/**
+ * usb_suspend_both - suspend a USB device and its interfaces
+ * @udev: the usb_device to suspend
+ * @msg: Power Management message describing this state transition
+ *
+ * This is the central routine for suspending USB devices. It calls the
+ * suspend methods for all the interface drivers in @udev and then calls
+ * the suspend method for @udev itself. If an error occurs at any stage,
+ * all the interfaces which were suspended are resumed so that they remain
+ * in the same state as the device.
+ *
+ * If an autosuspend is in progress (@udev->auto_pm is set), the routine
+ * checks first to make sure that neither the device itself or any of its
+ * active interfaces is in use (pm_usage_cnt is greater than 0). If they
+ * are, the autosuspend fails.
+ *
+ * If the suspend succeeds, the routine recursively queues an autosuspend
+ * request for @udev's parent device, thereby propagating the change up
+ * the device tree. If all of the parent's children are now suspended,
+ * the parent will autosuspend in turn.
+ *
+ * The suspend method calls are subject to mutual exclusion under control
+ * of @udev's pm_mutex. Many of these calls are also under the protection
+ * of @udev's device lock (including all requests originating outside the
+ * USB subsystem), but autosuspend requests generated by a child device or
+ * interface driver may not be. Usbcore will insure that the method calls
+ * do not arrive during bind, unbind, or reset operations. However, drivers
+ * must be prepared to handle suspend calls arriving at unpredictable times.
+ * The only way to block such calls is to do an autoresume (preventing
+ * autosuspends) while holding @udev's device lock (preventing outside
+ * suspends).
+ *
+ * The caller must hold @udev->pm_mutex.
+ *
+ * This routine can run only in process context.
+ */
+int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
+{
+ int status = 0;
+ int i = 0;
+ struct usb_interface *intf;
+ struct usb_device *parent = udev->parent;
+
+ cancel_delayed_work(&udev->autosuspend);
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return 0;
+ if (udev->state == USB_STATE_SUSPENDED)
+ return 0;
+
+ udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+
+ /* For autosuspend, fail fast if anything is in use.
+ * Also fail if any interfaces require remote wakeup but it
+ * isn't available. */
+ if (udev->auto_pm) {
+ if (udev->pm_usage_cnt > 0)
+ return -EBUSY;
+ if (udev->actconfig) {
+ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ if (!is_active(intf))
+ continue;
+ if (intf->pm_usage_cnt > 0)
+ return -EBUSY;
+ if (intf->needs_remote_wakeup &&
+ !udev->do_remote_wakeup) {
+ dev_dbg(&udev->dev,
+ "remote wakeup needed for autosuspend\n");
+ return -EOPNOTSUPP;
+ }
+ }
+ i = 0;
+ }
+ }
+
+ /* Suspend all the interfaces and then udev itself */
+ if (udev->actconfig) {
+ for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ status = suspend_interface(intf, msg);
+ if (status != 0)
+ break;
+ }
+ }
+ if (status == 0)
+ status = suspend_device(udev, msg);
+
+ /* If the suspend failed, resume interfaces that did get suspended */
+ if (status != 0) {
+ while (--i >= 0) {
+ intf = udev->actconfig->interface[i];
+ resume_interface(intf);
+ }
+
+ /* If the suspend succeeded, propagate it up the tree */
+ } else if (parent)
+ usb_autosuspend_device(parent, 0);
+
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ return status;
+}
+
+/**
+ * usb_resume_both - resume a USB device and its interfaces
+ * @udev: the usb_device to resume
+ *
+ * This is the central routine for resuming USB devices. It calls the
+ * the resume method for @udev and then calls the resume methods for all
+ * the interface drivers in @udev.
+ *
+ * Before starting the resume, the routine calls itself recursively for
+ * the parent device of @udev, thereby propagating the change up the device
+ * tree and assuring that @udev will be able to resume. If the parent is
+ * unable to resume successfully, the routine fails.
+ *
+ * The resume method calls are subject to mutual exclusion under control
+ * of @udev's pm_mutex. Many of these calls are also under the protection
+ * of @udev's device lock (including all requests originating outside the
+ * USB subsystem), but autoresume requests generated by a child device or
+ * interface driver may not be. Usbcore will insure that the method calls
+ * do not arrive during bind, unbind, or reset operations. However, drivers
+ * must be prepared to handle resume calls arriving at unpredictable times.
+ * The only way to block such calls is to do an autoresume (preventing
+ * other autoresumes) while holding @udev's device lock (preventing outside
+ * resumes).
+ *
+ * The caller must hold @udev->pm_mutex.
+ *
+ * This routine can run only in process context.
+ */
+int usb_resume_both(struct usb_device *udev)
+{
+ int status = 0;
+ int i;
+ struct usb_interface *intf;
+ struct usb_device *parent = udev->parent;
+
+ cancel_delayed_work(&udev->autosuspend);
+ if (udev->state == USB_STATE_NOTATTACHED)
+ return -ENODEV;
+
+ /* Propagate the resume up the tree, if necessary */
+ if (udev->state == USB_STATE_SUSPENDED) {
+ if (parent) {
+ usb_pm_lock(parent);
+ parent->auto_pm = 1;
+ status = usb_resume_both(parent);
+ } else {
+
+ /* We can't progagate beyond the USB subsystem,
+ * so if a root hub's controller is suspended
+ * then we're stuck. */
+ if (udev->dev.parent->power.power_state.event !=
+ PM_EVENT_ON)
+ status = -EHOSTUNREACH;
+ }
+ if (status == 0)
+ status = resume_device(udev);
+ if (parent)
+ usb_pm_unlock(parent);
+ } else {
+
+ /* Needed only for setting udev->dev.power.power_state.event
+ * and for possible debugging message. */
+ status = resume_device(udev);
+ }
+
+ /* Now the parent won't suspend until we are finished */
+
+ if (status == 0 && udev->actconfig) {
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ resume_interface(intf);
+ }
+ }
+
+ // dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ return status;
+}
+
+#ifdef CONFIG_USB_SUSPEND
+
+/**
+ * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
+ * @udev: the usb_device to autosuspend
+ * @dec_usage_cnt: flag to decrement @udev's PM-usage counter
+ *
+ * This routine should be called when a core subsystem is finished using
+ * @udev and wants to allow it to autosuspend. Examples would be when
+ * @udev's device file in usbfs is closed or after a configuration change.
+ *
+ * @dec_usage_cnt should be 1 if the subsystem previously incremented
+ * @udev's usage counter (such as by passing 1 to usb_autoresume_device);
+ * otherwise it should be 0.
+ *
+ * If the usage counter for @udev or any of its active interfaces is greater
+ * than 0, the autosuspend request will not be queued. (If an interface
+ * driver does not support autosuspend then its usage counter is permanently
+ * positive.) Likewise, if an interface driver requires remote-wakeup
+ * capability during autosuspend but remote wakeup is disabled, the
+ * autosuspend will fail.
+ *
+ * Often the caller will hold @udev's device lock, but this is not
+ * necessary.
+ *
+ * This routine can run only in process context.
+ */
+void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt)
+{
+ usb_pm_lock(udev);
+ udev->pm_usage_cnt -= dec_usage_cnt;
+ if (udev->pm_usage_cnt <= 0)
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ USB_AUTOSUSPEND_DELAY);
+ usb_pm_unlock(udev);
+ // dev_dbg(&udev->dev, "%s: cnt %d\n",
+ // __FUNCTION__, udev->pm_usage_cnt);
+}
+
+/**
+ * usb_autoresume_device - immediately autoresume a USB device and its interfaces
+ * @udev: the usb_device to autoresume
+ * @inc_usage_cnt: flag to increment @udev's PM-usage counter
+ *
+ * This routine should be called when a core subsystem wants to use @udev
+ * and needs to guarantee that it is not suspended. In addition, the
+ * caller can prevent @udev from being autosuspended subsequently. (Note
+ * that this will not prevent suspend events originating in the PM core.)
+ * Examples would be when @udev's device file in usbfs is opened (autosuspend
+ * should be prevented until the file is closed) or when a remote-wakeup
+ * request is received (later autosuspends should not be prevented).
+ *
+ * @inc_usage_cnt should be 1 to increment @udev's usage counter and prevent
+ * autosuspends. This prevention will persist until the usage counter is
+ * decremented again (such as by passing 1 to usb_autosuspend_device).
+ * Otherwise @inc_usage_cnt should be 0 to leave the usage counter unchanged.
+ * Regardless, if the autoresume fails then the usage counter is not
+ * incremented.
+ *
+ * Often the caller will hold @udev's device lock, but this is not
+ * necessary (and attempting it might cause deadlock).
+ *
+ * This routine can run only in process context.
+ */
+int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt)
+{
+ int status;
+
+ usb_pm_lock(udev);
+ udev->pm_usage_cnt += inc_usage_cnt;
+ udev->auto_pm = 1;
+ status = usb_resume_both(udev);
+ if (status != 0)
+ udev->pm_usage_cnt -= inc_usage_cnt;
+ usb_pm_unlock(udev);
+ // dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
+ // __FUNCTION__, status, udev->pm_usage_cnt);
+ return status;
+}
+
+/**
+ * usb_autopm_put_interface - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine should be called by an interface driver when it is
+ * finished using @intf and wants to allow it to autosuspend. A typical
+ * example would be a character-device driver when its device file is
+ * closed.
+ *
+ * The routine decrements @intf's usage counter. When the counter reaches
+ * 0, a delayed autosuspend request for @intf's device is queued. When
+ * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all
+ * the other usage counters for the sibling interfaces and @intf's
+ * usb_device, the device and all its interfaces will be autosuspended.
+ *
+ * Note that @intf->pm_usage_cnt is owned by the interface driver. The
+ * core will not change its value other than the increment and decrement
+ * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
+ * may use this simple counter-oriented discipline or may set the value
+ * any way it likes.
+ *
+ * If the driver has set @intf->needs_remote_wakeup then autosuspend will
+ * take place only if the device's remote-wakeup facility is enabled.
+ *
+ * Suspend method calls queued by this routine can arrive at any time
+ * while @intf is resumed and its usage counter is equal to 0. They are
+ * not protected by the usb_device's lock but only by its pm_mutex.
+ * Drivers must provide their own synchronization.
+ *
+ * This routine can run only in process context.
+ */
+void usb_autopm_put_interface(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+
+ usb_pm_lock(udev);
+ if (intf->condition != USB_INTERFACE_UNBOUND &&
+ --intf->pm_usage_cnt <= 0) {
+ queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+ USB_AUTOSUSPEND_DELAY);
+ }
+ usb_pm_unlock(udev);
+ // dev_dbg(&intf->dev, "%s: cnt %d\n",
+ // __FUNCTION__, intf->pm_usage_cnt);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
+
+/**
+ * usb_autopm_get_interface - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
+ *
+ * This routine should be called by an interface driver when it wants to
+ * use @intf and needs to guarantee that it is not suspended. In addition,
+ * the routine prevents @intf from being autosuspended subsequently. (Note
+ * that this will not prevent suspend events originating in the PM core.)
+ * This prevention will persist until usb_autopm_put_interface() is called
+ * or @intf is unbound. A typical example would be a character-device
+ * driver when its device file is opened.
+ *
+ * The routine increments @intf's usage counter. So long as the counter
+ * is greater than 0, autosuspend will not be allowed for @intf or its
+ * usb_device. When the driver is finished using @intf it should call
+ * usb_autopm_put_interface() to decrement the usage counter and queue
+ * a delayed autosuspend request (if the counter is <= 0).
+ *
+ * Note that @intf->pm_usage_cnt is owned by the interface driver. The
+ * core will not change its value other than the increment and decrement
+ * in usb_autopm_get_interface and usb_autopm_put_interface. The driver
+ * may use this simple counter-oriented discipline or may set the value
+ * any way it likes.
+ *
+ * Resume method calls generated by this routine can arrive at any time
+ * while @intf is suspended. They are not protected by the usb_device's
+ * lock but only by its pm_mutex. Drivers must provide their own
+ * synchronization.
+ *
+ * This routine can run only in process context.
+ */
+int usb_autopm_get_interface(struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int status;
+
+ usb_pm_lock(udev);
+ if (intf->condition == USB_INTERFACE_UNBOUND)
+ status = -ENODEV;
+ else {
+ ++intf->pm_usage_cnt;
+ udev->auto_pm = 1;
+ status = usb_resume_both(udev);
+ if (status != 0)
+ --intf->pm_usage_cnt;
+ }
+ usb_pm_unlock(udev);
+ // dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
+ // __FUNCTION__, status, intf->pm_usage_cnt);
+ return status;
+}
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
+
+#endif /* CONFIG_USB_SUSPEND */
+
+static int usb_suspend(struct device *dev, pm_message_t message)
+{
+ int status;
+
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+
+ usb_pm_lock(udev);
+ udev->auto_pm = 0;
+ status = usb_suspend_both(udev, message);
+ usb_pm_unlock(udev);
+ } else
+ status = 0;
+ return status;
+}
+
+static int usb_resume(struct device *dev)
+{
+ int status;
+
+ if (is_usb_device(dev)) {
+ struct usb_device *udev = to_usb_device(dev);
+
+ usb_pm_lock(udev);
+ udev->auto_pm = 0;
+ status = usb_resume_both(udev);
+ usb_pm_unlock(udev);
+
+ /* Rebind drivers that had no suspend method? */
+ } else
+ status = 0;
+ return status;
+}
+
+#endif /* CONFIG_PM */
+
+struct bus_type usb_bus_type = {
+ .name = "usb",
+ .match = usb_device_match,
+ .uevent = usb_uevent,
+#ifdef CONFIG_PM
+ .suspend = usb_suspend,
+ .resume = usb_resume,
+#endif
+};
diff --git a/drivers/usb/core/endpoint.c b/drivers/usb/core/endpoint.c
index 247b5a4913a8..3b2d137912be 100644
--- a/drivers/usb/core/endpoint.c
+++ b/drivers/usb/core/endpoint.c
@@ -207,9 +207,9 @@ static void ep_device_release(struct device *dev)
kfree(ep_dev);
}
-void usb_create_ep_files(struct device *parent,
- struct usb_host_endpoint *endpoint,
- struct usb_device *udev)
+int usb_create_ep_files(struct device *parent,
+ struct usb_host_endpoint *endpoint,
+ struct usb_device *udev)
{
char name[8];
struct ep_device *ep_dev;
@@ -223,7 +223,7 @@ void usb_create_ep_files(struct device *parent,
ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
if (!ep_dev) {
retval = -ENOMEM;
- goto exit;
+ goto error_alloc;
}
/* fun calculation to determine the minor of this endpoint */
@@ -241,20 +241,32 @@ void usb_create_ep_files(struct device *parent,
retval = device_register(&ep_dev->dev);
if (retval)
- goto error;
- sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
-
- endpoint->ep_dev = ep_dev;
+ goto error_register;
+ retval = sysfs_create_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
+ if (retval)
+ goto error_group;
/* create the symlink to the old-style "ep_XX" directory */
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
- sysfs_create_link(&parent->kobj, &endpoint->ep_dev->dev.kobj, name);
+ retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
+ if (retval)
+ goto error_link;
+ endpoint->ep_dev = ep_dev;
+ return retval;
-exit:
- return;
-error:
+error_link:
+ sysfs_remove_group(&ep_dev->dev.kobj, &ep_dev_attr_grp);
+error_group:
+ device_unregister(&ep_dev->dev);
+ destroy_endpoint_class();
+ return retval;
+
+error_register:
kfree(ep_dev);
- return;
+error_alloc:
+ destroy_endpoint_class();
+exit:
+ return retval;
}
void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
@@ -268,8 +280,6 @@ void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
sysfs_remove_group(&endpoint->ep_dev->dev.kobj, &ep_dev_attr_grp);
device_unregister(&endpoint->ep_dev->dev);
endpoint->ep_dev = NULL;
+ destroy_endpoint_class();
}
- destroy_endpoint_class();
}
-
-
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 8de4f8c99d61..f794f07cfb33 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -1,5 +1,5 @@
/*
- * drivers/usb/file.c
+ * drivers/usb/core/file.c
*
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
@@ -55,7 +55,7 @@ static int usb_open(struct inode * inode, struct file * file)
return err;
}
-static struct file_operations usb_fops = {
+static const struct file_operations usb_fops = {
.owner = THIS_MODULE,
.open = usb_open,
};
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
new file mode 100644
index 000000000000..ebb20ff7ac58
--- /dev/null
+++ b/drivers/usb/core/generic.c
@@ -0,0 +1,207 @@
+/*
+ * drivers/usb/generic.c - generic driver for USB devices (not interfaces)
+ *
+ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * based on drivers/usb/usb.c which had the following copyrights:
+ * (C) Copyright Linus Torvalds 1999
+ * (C) Copyright Johannes Erdfelt 1999-2001
+ * (C) Copyright Andreas Gal 1999
+ * (C) Copyright Gregory P. Smith 1999
+ * (C) Copyright Deti Fliegl 1999 (new USB architecture)
+ * (C) Copyright Randy Dunlap 2000
+ * (C) Copyright David Brownell 2000-2004
+ * (C) Copyright Yggdrasil Computing, Inc. 2000
+ * (usb_device_id matching changes by Adam J. Richter)
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
+ *
+ */
+
+#include <linux/usb.h>
+#include "usb.h"
+
+static inline const char *plural(int n)
+{
+ return (n == 1 ? "" : "s");
+}
+
+static int choose_configuration(struct usb_device *udev)
+{
+ int i;
+ int num_configs;
+ int insufficient_power = 0;
+ struct usb_host_config *c, *best;
+
+ best = NULL;
+ c = udev->config;
+ num_configs = udev->descriptor.bNumConfigurations;
+ for (i = 0; i < num_configs; (i++, c++)) {
+ struct usb_interface_descriptor *desc = NULL;
+
+ /* It's possible that a config has no interfaces! */
+ if (c->desc.bNumInterfaces > 0)
+ desc = &c->intf_cache[0]->altsetting->desc;
+
+ /*
+ * HP's USB bus-powered keyboard has only one configuration
+ * and it claims to be self-powered; other devices may have
+ * similar errors in their descriptors. If the next test
+ * were allowed to execute, such configurations would always
+ * be rejected and the devices would not work as expected.
+ * In the meantime, we run the risk of selecting a config
+ * that requires external power at a time when that power
+ * isn't available. It seems to be the lesser of two evils.
+ *
+ * Bugzilla #6448 reports a device that appears to crash
+ * when it receives a GET_DEVICE_STATUS request! We don't
+ * have any other way to tell whether a device is self-powered,
+ * but since we don't use that information anywhere but here,
+ * the call has been removed.
+ *
+ * Maybe the GET_DEVICE_STATUS call and the test below can
+ * be reinstated when device firmwares become more reliable.
+ * Don't hold your breath.
+ */
+#if 0
+ /* Rule out self-powered configs for a bus-powered device */
+ if (bus_powered && (c->desc.bmAttributes &
+ USB_CONFIG_ATT_SELFPOWER))
+ continue;
+#endif
+
+ /*
+ * The next test may not be as effective as it should be.
+ * Some hubs have errors in their descriptor, claiming
+ * to be self-powered when they are really bus-powered.
+ * We will overestimate the amount of current such hubs
+ * make available for each port.
+ *
+ * This is a fairly benign sort of failure. It won't
+ * cause us to reject configurations that we should have
+ * accepted.
+ */
+
+ /* Rule out configs that draw too much bus current */
+ if (c->desc.bMaxPower * 2 > udev->bus_mA) {
+ insufficient_power++;
+ continue;
+ }
+
+ /* If the first config's first interface is COMM/2/0xff
+ * (MSFT RNDIS), rule it out unless Linux has host-side
+ * RNDIS support. */
+ if (i == 0 && desc
+ && desc->bInterfaceClass == USB_CLASS_COMM
+ && desc->bInterfaceSubClass == 2
+ && desc->bInterfaceProtocol == 0xff) {
+#ifndef CONFIG_USB_NET_RNDIS_HOST
+ continue;
+#else
+ best = c;
+#endif
+ }
+
+ /* From the remaining configs, choose the first one whose
+ * first interface is for a non-vendor-specific class.
+ * Reason: Linux is more likely to have a class driver
+ * than a vendor-specific driver. */
+ else if (udev->descriptor.bDeviceClass !=
+ USB_CLASS_VENDOR_SPEC &&
+ (!desc || desc->bInterfaceClass !=
+ USB_CLASS_VENDOR_SPEC)) {
+ best = c;
+ break;
+ }
+
+ /* If all the remaining configs are vendor-specific,
+ * choose the first one. */
+ else if (!best)
+ best = c;
+ }
+
+ if (insufficient_power > 0)
+ dev_info(&udev->dev, "rejected %d configuration%s "
+ "due to insufficient available bus power\n",
+ insufficient_power, plural(insufficient_power));
+
+ if (best) {
+ i = best->desc.bConfigurationValue;
+ dev_info(&udev->dev,
+ "configuration #%d chosen from %d choice%s\n",
+ i, num_configs, plural(num_configs));
+ } else {
+ i = -1;
+ dev_warn(&udev->dev,
+ "no configuration chosen from %d choice%s\n",
+ num_configs, plural(num_configs));
+ }
+ return i;
+}
+
+static int generic_probe(struct usb_device *udev)
+{
+ int err, c;
+
+ /* put device-specific files into sysfs */
+ usb_create_sysfs_dev_files(udev);
+
+ /* Choose and set the configuration. This registers the interfaces
+ * with the driver core and lets interface drivers bind to them.
+ */
+ c = choose_configuration(udev);
+ if (c >= 0) {
+ err = usb_set_configuration(udev, c);
+ if (err) {
+ dev_err(&udev->dev, "can't set config #%d, error %d\n",
+ c, err);
+ /* This need not be fatal. The user can try to
+ * set other configurations. */
+ }
+ }
+
+ /* USB device state == configured ... usable */
+ usb_notify_add_device(udev);
+
+ return 0;
+}
+
+static void generic_disconnect(struct usb_device *udev)
+{
+ usb_notify_remove_device(udev);
+
+ /* if this is only an unbind, not a physical disconnect, then
+ * unconfigure the device */
+ if (udev->actconfig)
+ usb_set_configuration(udev, 0);
+
+ usb_remove_sysfs_dev_files(udev);
+}
+
+#ifdef CONFIG_PM
+
+static int generic_suspend(struct usb_device *udev, pm_message_t msg)
+{
+ /* USB devices enter SUSPEND state through their hubs, but can be
+ * marked for FREEZE as soon as their children are already idled.
+ * But those semantics are useless, so we equate the two (sigh).
+ */
+ return usb_port_suspend(udev);
+}
+
+static int generic_resume(struct usb_device *udev)
+{
+ return usb_port_resume(udev);
+}
+
+#endif /* CONFIG_PM */
+
+struct usb_device_driver usb_generic_driver = {
+ .name = "usb",
+ .probe = generic_probe,
+ .disconnect = generic_disconnect,
+#ifdef CONFIG_PM
+ .suspend = generic_suspend,
+ .resume = generic_resume,
+#endif
+ .supports_autosuspend = 1,
+};
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index fa36391fedd3..edf4300a3f7a 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -413,4 +413,20 @@ EXPORT_SYMBOL (usb_hcd_pci_resume);
#endif /* CONFIG_PM */
+/**
+ * usb_hcd_pci_shutdown - shutdown host controller
+ * @dev: USB Host Controller being shutdown
+ */
+void usb_hcd_pci_shutdown (struct pci_dev *dev)
+{
+ struct usb_hcd *hcd;
+
+ hcd = pci_get_drvdata(dev);
+ if (!hcd)
+ return;
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+EXPORT_SYMBOL (usb_hcd_pci_shutdown);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index fb4d058bbde0..afa2dd203329 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <asm/irq.h>
#include <asm/byteorder.h>
+#include <linux/platform_device.h>
#include <linux/usb.h>
@@ -317,8 +318,8 @@ static int rh_string (
// id 3 == vendor description
} else if (id == 3) {
- snprintf (buf, sizeof buf, "%s %s %s", system_utsname.sysname,
- system_utsname.release, hcd->driver->description);
+ snprintf (buf, sizeof buf, "%s %s %s", init_utsname()->sysname,
+ init_utsname()->release, hcd->driver->description);
// unsupported IDs --> "protocol stall"
} else
@@ -344,7 +345,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer;
- u8 tbuf [sizeof (struct usb_hub_descriptor)];
+ u8 tbuf [sizeof (struct usb_hub_descriptor)]
+ __attribute__((aligned(4)));
const u8 *bufp = tbuf;
int len = 0;
int patch_wakeup = 0;
@@ -520,7 +522,7 @@ error:
if (urb->status == -EINPROGRESS)
urb->status = status;
spin_unlock (&urb->lock);
- usb_hcd_giveback_urb (hcd, urb, NULL);
+ usb_hcd_giveback_urb (hcd, urb);
local_irq_restore (flags);
return 0;
}
@@ -570,7 +572,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
/* local irqs are always blocked in completions */
if (length > 0)
- usb_hcd_giveback_urb (hcd, urb, NULL);
+ usb_hcd_giveback_urb (hcd, urb);
else
hcd->poll_pending = 1;
local_irq_restore (flags);
@@ -632,31 +634,20 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
/*-------------------------------------------------------------------------*/
-/* Asynchronous unlinks of root-hub control URBs are legal, but they
- * don't do anything. Status URB unlinks must be made in process context
- * with interrupts enabled.
+/* Unlinks of root-hub control URBs are legal, but they don't do anything
+ * since these URBs always execute synchronously.
*/
static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
- if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
- if (in_interrupt())
- return 0; /* nothing to do */
-
- spin_lock_irq(&urb->lock); /* from usb_kill_urb */
- ++urb->reject;
- spin_unlock_irq(&urb->lock);
-
- wait_event(usb_kill_urb_queue,
- atomic_read(&urb->use_count) == 0);
+ unsigned long flags;
- spin_lock_irq(&urb->lock);
- --urb->reject;
- spin_unlock_irq(&urb->lock);
+ if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+ ; /* Do nothing */
} else { /* Status URB */
if (!hcd->uses_new_polling)
- del_timer_sync (&hcd->rh_timer);
- local_irq_disable ();
+ del_timer (&hcd->rh_timer);
+ local_irq_save (flags);
spin_lock (&hcd_root_hub_lock);
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
@@ -665,8 +656,8 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
urb = NULL; /* wasn't fully queued */
spin_unlock (&hcd_root_hub_lock);
if (urb)
- usb_hcd_giveback_urb (hcd, urb, NULL);
- local_irq_enable ();
+ usb_hcd_giveback_urb (hcd, urb);
+ local_irq_restore (flags);
}
return 0;
@@ -674,31 +665,6 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
/*-------------------------------------------------------------------------*/
-/* exported only within usbcore */
-struct usb_bus *usb_bus_get(struct usb_bus *bus)
-{
- if (bus)
- kref_get(&bus->kref);
- return bus;
-}
-
-static void usb_host_release(struct kref *kref)
-{
- struct usb_bus *bus = container_of(kref, struct usb_bus, kref);
-
- if (bus->release)
- bus->release(bus);
-}
-
-/* exported only within usbcore */
-void usb_bus_put(struct usb_bus *bus)
-{
- if (bus)
- kref_put(&bus->kref, usb_host_release);
-}
-
-/*-------------------------------------------------------------------------*/
-
static struct class *usb_host_class;
int usb_host_init(void)
@@ -730,39 +696,12 @@ static void usb_bus_init (struct usb_bus *bus)
bus->devnum_next = 1;
bus->root_hub = NULL;
- bus->hcpriv = NULL;
bus->busnum = -1;
bus->bandwidth_allocated = 0;
bus->bandwidth_int_reqs = 0;
bus->bandwidth_isoc_reqs = 0;
INIT_LIST_HEAD (&bus->bus_list);
-
- kref_init(&bus->kref);
-}
-
-/**
- * usb_alloc_bus - creates a new USB host controller structure
- * @op: pointer to a struct usb_operations that this bus structure should use
- * Context: !in_interrupt()
- *
- * Creates a USB host controller bus structure with the specified
- * usb_operations and initializes all the necessary internal objects.
- *
- * If no memory is available, NULL is returned.
- *
- * The caller should call usb_put_bus() when it is finished with the structure.
- */
-struct usb_bus *usb_alloc_bus (struct usb_operations *op)
-{
- struct usb_bus *bus;
-
- bus = kzalloc (sizeof *bus, GFP_KERNEL);
- if (!bus)
- return NULL;
- usb_bus_init (bus);
- bus->op = op;
- return bus;
}
/*-------------------------------------------------------------------------*/
@@ -897,8 +836,7 @@ void usb_enable_root_hub_irq (struct usb_bus *bus)
struct usb_hcd *hcd;
hcd = container_of (bus, struct usb_hcd, self);
- if (hcd->driver->hub_irq_enable && !hcd->poll_rh &&
- hcd->state != HC_STATE_HALT)
+ if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT)
hcd->driver->hub_irq_enable (hcd);
}
@@ -1112,10 +1050,10 @@ static void urb_unlink (struct urb *urb)
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
*/
-static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
{
int status;
- struct usb_hcd *hcd = urb->dev->bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
struct usb_host_endpoint *ep;
unsigned long flags;
@@ -1186,7 +1124,7 @@ doit:
/* lower level hcd code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
*/
- if (hcd->self.controller->dma_mask) {
+ if (hcd->self.uses_dma) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
urb->setup_dma = dma_map_single (
@@ -1221,9 +1159,10 @@ done:
/*-------------------------------------------------------------------------*/
/* called in any context */
-static int hcd_get_frame_number (struct usb_device *udev)
+int usb_hcd_get_frame_number (struct usb_device *udev)
{
- struct usb_hcd *hcd = (struct usb_hcd *)udev->bus->hcpriv;
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
if (!HC_IS_RUNNING (hcd->state))
return -ESHUTDOWN;
return hcd->driver->get_frame_number (hcd);
@@ -1263,7 +1202,7 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
* caller guarantees urb won't be recycled till both unlink()
* and the urb's completion function return
*/
-static int hcd_unlink_urb (struct urb *urb, int status)
+int usb_hcd_unlink_urb (struct urb *urb, int status)
{
struct usb_host_endpoint *ep;
struct usb_hcd *hcd = NULL;
@@ -1296,7 +1235,7 @@ static int hcd_unlink_urb (struct urb *urb, int status)
spin_lock (&hcd_data_lock);
sys = &urb->dev->dev;
- hcd = urb->dev->bus->hcpriv;
+ hcd = bus_to_hcd(urb->dev->bus);
if (hcd == NULL) {
retval = -ENODEV;
goto done;
@@ -1354,41 +1293,33 @@ done:
/*-------------------------------------------------------------------------*/
/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware. use for
+ * the hcd to make sure all endpoint state is gone from hardware, and then
+ * waits until the endpoint's queue is completely drained. use for
* set_configuration, set_interface, driver removal, physical disconnect.
*
* example: a qh stored in ep->hcpriv, holding state related to endpoint
* type, maxpacket size, toggle, halt status, and scheduling.
*/
-static void
-hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
+void usb_hcd_endpoint_disable (struct usb_device *udev,
+ struct usb_host_endpoint *ep)
{
struct usb_hcd *hcd;
struct urb *urb;
- hcd = udev->bus->hcpriv;
+ hcd = bus_to_hcd(udev->bus);
WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
udev->state != USB_STATE_NOTATTACHED);
local_irq_disable ();
- /* FIXME move most of this into message.c as part of its
- * endpoint disable logic
- */
-
/* ep is already gone from udev->ep_{in,out}[]; no more submits */
rescan:
spin_lock (&hcd_data_lock);
list_for_each_entry (urb, &ep->urb_list, urb_list) {
int tmp;
- /* another cpu may be in hcd, spinning on hcd_data_lock
- * to giveback() this urb. the races here should be
- * small, but a full fix needs a new "can't submit"
- * urb state.
- * FIXME urb->reject should allow that...
- */
+ /* the urb may already have been unlinked */
if (urb->status != -EINPROGRESS)
continue;
usb_get_urb (urb);
@@ -1430,6 +1361,30 @@ rescan:
might_sleep ();
if (hcd->driver->endpoint_disable)
hcd->driver->endpoint_disable (hcd, ep);
+
+ /* Wait until the endpoint queue is completely empty. Most HCDs
+ * will have done this already in their endpoint_disable method,
+ * but some might not. And there could be root-hub control URBs
+ * still pending since they aren't affected by the HCDs'
+ * endpoint_disable methods.
+ */
+ while (!list_empty (&ep->urb_list)) {
+ spin_lock_irq (&hcd_data_lock);
+
+ /* The list may have changed while we acquired the spinlock */
+ urb = NULL;
+ if (!list_empty (&ep->urb_list)) {
+ urb = list_entry (ep->urb_list.prev, struct urb,
+ urb_list);
+ usb_get_urb (urb);
+ }
+ spin_unlock_irq (&hcd_data_lock);
+
+ if (urb) {
+ usb_kill_urb (urb);
+ usb_put_urb (urb);
+ }
+ }
}
/*-------------------------------------------------------------------------*/
@@ -1476,50 +1431,6 @@ int hcd_bus_resume (struct usb_bus *bus)
return status;
}
-/*
- * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
- * @hcd: host controller for this root hub
- *
- * This call arranges that usb_hcd_resume_root_hub() is safe to call later;
- * that the HCD's root hub polling is deactivated; and that the root's hub
- * driver is suspended. HCDs may call this to autosuspend when their root
- * hub's downstream ports are all inactive: unpowered, disconnected,
- * disabled, or suspended.
- *
- * The HCD will autoresume on device connect change detection (using SRP
- * or a D+/D- pullup). The HCD also autoresumes on remote wakeup signaling
- * from any ports that are suspended (if that is enabled). In most cases,
- * overcurrent signaling (on powered ports) will also start autoresume.
- *
- * Always called with IRQs blocked.
- */
-void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
-{
- struct urb *urb;
-
- spin_lock (&hcd_root_hub_lock);
- usb_suspend_root_hub (hcd->self.root_hub);
-
- /* force status urb to complete/unlink while suspended */
- if (hcd->status_urb) {
- urb = hcd->status_urb;
- urb->status = -ECONNRESET;
- urb->hcpriv = NULL;
- urb->actual_length = 0;
-
- del_timer (&hcd->rh_timer);
- hcd->poll_pending = 0;
- hcd->status_urb = NULL;
- } else
- urb = NULL;
- spin_unlock (&hcd_root_hub_lock);
- hcd->state = HC_STATE_SUSPENDED;
-
- if (urb)
- usb_hcd_giveback_urb (hcd, urb, NULL);
-}
-EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);
-
/**
* usb_hcd_resume_root_hub - called by HCD to resume its root hub
* @hcd: host controller for this root hub
@@ -1583,25 +1494,10 @@ EXPORT_SYMBOL (usb_bus_start_enum);
/*-------------------------------------------------------------------------*/
-/*
- * usb_hcd_operations - adapts usb_bus framework to HCD framework (bus glue)
- */
-static struct usb_operations usb_hcd_operations = {
- .get_frame_number = hcd_get_frame_number,
- .submit_urb = hcd_submit_urb,
- .unlink_urb = hcd_unlink_urb,
- .buffer_alloc = hcd_buffer_alloc,
- .buffer_free = hcd_buffer_free,
- .disable = hcd_endpoint_disable,
-};
-
-/*-------------------------------------------------------------------------*/
-
/**
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
* @urb: urb being returned to the USB device driver.
- * @regs: pt_regs, passed down to the URB completion handler
* Context: in_interrupt()
*
* This hands the URB from HCD to its USB device driver, using its
@@ -1610,15 +1506,16 @@ static struct usb_operations usb_hcd_operations = {
* the device driver won't cause problems if it frees, modifies,
* or resubmits this URB.
*/
-void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs)
+void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
{
int at_root_hub;
at_root_hub = (urb->dev == hcd->self.root_hub);
urb_unlink (urb);
- /* lower level hcd code should use *_dma exclusively */
- if (hcd->self.controller->dma_mask && !at_root_hub) {
+ /* lower level hcd code should use *_dma exclusively if the
+ * host controller does DMA */
+ if (hcd->self.uses_dma && !at_root_hub) {
if (usb_pipecontrol (urb->pipe)
&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
dma_unmap_single (hcd->self.controller, urb->setup_dma,
@@ -1636,7 +1533,7 @@ void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs
usbmon_urb_complete (&hcd->self, urb);
/* pass ownership to the completion handler */
- urb->complete (urb, regs);
+ urb->complete (urb);
atomic_dec (&urb->use_count);
if (unlikely (urb->reject))
wake_up (&usb_kill_urb_queue);
@@ -1655,7 +1552,7 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
* If the controller isn't HALTed, calls the driver's irq handler.
* Checks whether the controller is now dead.
*/
-irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
+irqreturn_t usb_hcd_irq (int irq, void *__hcd)
{
struct usb_hcd *hcd = __hcd;
int start = hcd->state;
@@ -1663,7 +1560,7 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs * r)
if (unlikely(start == HC_STATE_HALT ||
!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
return IRQ_NONE;
- if (hcd->driver->irq (hcd, r) == IRQ_NONE)
+ if (hcd->driver->irq (hcd) == IRQ_NONE)
return IRQ_NONE;
set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
@@ -1704,14 +1601,6 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
/*-------------------------------------------------------------------------*/
-static void hcd_release (struct usb_bus *bus)
-{
- struct usb_hcd *hcd;
-
- hcd = container_of(bus, struct usb_hcd, self);
- kfree(hcd);
-}
-
/**
* usb_create_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
@@ -1736,13 +1625,12 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
return NULL;
}
dev_set_drvdata(dev, hcd);
+ kref_init(&hcd->kref);
usb_bus_init(&hcd->self);
- hcd->self.op = &usb_hcd_operations;
- hcd->self.hcpriv = hcd;
- hcd->self.release = &hcd_release;
hcd->self.controller = dev;
hcd->self.bus_name = bus_name;
+ hcd->self.uses_dma = (dev->dma_mask != NULL);
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
@@ -1756,10 +1644,25 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
}
EXPORT_SYMBOL (usb_create_hcd);
+static void hcd_release (struct kref *kref)
+{
+ struct usb_hcd *hcd = container_of (kref, struct usb_hcd, kref);
+
+ kfree(hcd);
+}
+
+struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd)
+{
+ if (hcd)
+ kref_get (&hcd->kref);
+ return hcd;
+}
+EXPORT_SYMBOL (usb_get_hcd);
+
void usb_put_hcd (struct usb_hcd *hcd)
{
- dev_set_drvdata(hcd->self.controller, NULL);
- usb_bus_put(&hcd->self);
+ if (hcd)
+ kref_put (&hcd->kref, hcd_release);
}
EXPORT_SYMBOL (usb_put_hcd);
@@ -1915,6 +1818,16 @@ void usb_remove_hcd(struct usb_hcd *hcd)
}
EXPORT_SYMBOL (usb_remove_hcd);
+void
+usb_hcd_platform_shutdown(struct platform_device* dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ if (hcd->driver->shutdown)
+ hcd->driver->shutdown(hcd);
+}
+EXPORT_SYMBOL (usb_hcd_platform_shutdown);
+
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_USB_MON)
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 7022aafb2ae8..8f8df0d4382e 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -55,12 +55,13 @@
/*-------------------------------------------------------------------------*/
-struct usb_hcd { /* usb_bus.hcpriv points to this */
+struct usb_hcd {
/*
* housekeeping
*/
struct usb_bus self; /* hcd is-a bus */
+ struct kref kref; /* reference counter */
const char *product_desc; /* product/vendor string */
char irq_descr[24]; /* driver + bus # */
@@ -85,6 +86,7 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
unsigned uses_new_polling:1;
unsigned poll_rh:1; /* poll for rh status? */
unsigned poll_pending:1; /* status has changed? */
+ unsigned wireless:1; /* Wireless USB HCD */
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
@@ -128,8 +130,10 @@ static inline struct usb_bus *hcd_to_bus (struct usb_hcd *hcd)
return &hcd->self;
}
-
-// urb.hcpriv is really hardware-specific
+static inline struct usb_hcd *bus_to_hcd (struct usb_bus *bus)
+{
+ return container_of(bus, struct usb_hcd, self);
+}
struct hcd_timeout { /* timeouts we allocate */
struct list_head timeout_list;
@@ -138,30 +142,6 @@ struct hcd_timeout { /* timeouts we allocate */
/*-------------------------------------------------------------------------*/
-/*
- * FIXME usb_operations should vanish or become hc_driver,
- * when usb_bus and usb_hcd become the same thing.
- */
-
-struct usb_operations {
- int (*get_frame_number) (struct usb_device *usb_dev);
- int (*submit_urb) (struct urb *urb, gfp_t mem_flags);
- int (*unlink_urb) (struct urb *urb, int status);
-
- /* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
- void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
- gfp_t mem_flags,
- dma_addr_t *dma);
- void (*buffer_free)(struct usb_bus *bus, size_t size,
- void *addr, dma_addr_t dma);
-
- void (*disable)(struct usb_device *udev,
- struct usb_host_endpoint *ep);
-};
-
-/* each driver provides one of these, and hardware init support */
-
-struct pt_regs;
struct hc_driver {
const char *description; /* "ehci-hcd" etc */
@@ -169,7 +149,7 @@ struct hc_driver {
size_t hcd_priv_size; /* size of private data */
/* irq handler */
- irqreturn_t (*irq) (struct usb_hcd *hcd, struct pt_regs *regs);
+ irqreturn_t (*irq) (struct usb_hcd *hcd);
int flags;
#define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */
@@ -192,6 +172,9 @@ struct hc_driver {
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
+ /* shutdown HCD */
+ void (*shutdown) (struct usb_hcd *hcd);
+
/* return current frame number */
int (*get_frame_number) (struct usb_hcd *hcd);
@@ -218,15 +201,24 @@ struct hc_driver {
/* Needed only if port-change IRQs are level-triggered */
};
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
+extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
+extern int usb_hcd_unlink_urb (struct urb *urb, int status);
+extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
+extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+ struct usb_host_endpoint *ep);
+extern int usb_hcd_get_frame_number (struct usb_device *udev);
extern struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
struct device *dev, char *bus_name);
+extern struct usb_hcd *usb_get_hcd (struct usb_hcd *hcd);
extern void usb_put_hcd (struct usb_hcd *hcd);
extern int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags);
extern void usb_remove_hcd(struct usb_hcd *hcd);
+struct platform_device;
+extern void usb_hcd_platform_shutdown(struct platform_device* dev);
+
#ifdef CONFIG_PCI
struct pci_dev;
struct pci_device_id;
@@ -239,6 +231,8 @@ extern int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t state);
extern int usb_hcd_pci_resume (struct pci_dev *dev);
#endif /* CONFIG_PM */
+extern void usb_hcd_pci_shutdown (struct pci_dev *dev);
+
#endif /* CONFIG_PCI */
/* pci-ish (pdev null is ok) buffer alloc/mapping support */
@@ -251,7 +245,7 @@ void hcd_buffer_free (struct usb_bus *bus, size_t size,
void *addr, dma_addr_t dma);
/* generic bus glue, needed for host controllers that don't use PCI */
-extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+extern irqreturn_t usb_hcd_irq (int irq, void *__hcd);
extern void usb_hc_died (struct usb_hcd *hcd);
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
@@ -352,8 +346,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
/*-------------------------------------------------------------------------*/
-extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
-
extern void usb_set_device_state(struct usb_device *udev,
enum usb_device_state new_state);
@@ -365,9 +357,6 @@ extern struct list_head usb_bus_list;
extern struct mutex usb_bus_list_lock;
extern wait_queue_head_t usb_kill_urb_queue;
-extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
-extern void usb_bus_put (struct usb_bus *bus);
-
extern void usb_enable_root_hub_irq (struct usb_bus *bus);
extern int usb_find_interface_driver (struct usb_device *dev,
@@ -376,17 +365,11 @@ extern int usb_find_interface_driver (struct usb_device *dev,
#define usb_endpoint_out(ep_dir) (!((ep_dir) & USB_DIR_IN))
#ifdef CONFIG_PM
-extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_root_hub_lost_power (struct usb_device *rhdev);
extern int hcd_bus_suspend (struct usb_bus *bus);
extern int hcd_bus_resume (struct usb_bus *bus);
#else
-static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd)
-{
- return;
-}
-
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 26c8cb5f3e67..66bff184a30c 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -291,9 +291,9 @@ void usb_kick_khubd(struct usb_device *hdev)
/* completion function, fires on port status changes and various faults */
-static void hub_irq(struct urb *urb, struct pt_regs *regs)
+static void hub_irq(struct urb *urb)
{
- struct usb_hub *hub = (struct usb_hub *)urb->context;
+ struct usb_hub *hub = urb->context;
int status;
int i;
unsigned long bits;
@@ -311,7 +311,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs)
goto resubmit;
hub->error = urb->status;
/* FALL THROUGH */
-
+
/* let khubd handle things */
case 0: /* we got data: port status changed */
bits = 0;
@@ -452,18 +452,14 @@ static void hub_power_on(struct usb_hub *hub)
msleep(max(pgood_delay, (unsigned) 100));
}
-static inline void __hub_quiesce(struct usb_hub *hub)
+static void hub_quiesce(struct usb_hub *hub)
{
/* (nonblocking) khubd and related activity won't re-trigger */
hub->quiescing = 1;
hub->activating = 0;
hub->resume_root_hub = 0;
-}
-static void hub_quiesce(struct usb_hub *hub)
-{
/* (blocking) stop khubd and related activity */
- __hub_quiesce(hub);
usb_kill_urb(hub->urb);
if (hub->has_indicators)
cancel_delayed_work(&hub->leds);
@@ -868,13 +864,8 @@ descriptor_error:
endpoint = &desc->endpoint[0].desc;
- /* Output endpoint? Curiouser and curiouser.. */
- if (!(endpoint->bEndpointAddress & USB_DIR_IN))
- goto descriptor_error;
-
- /* If it's not an interrupt endpoint, we'd better punt! */
- if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_INT)
+ /* If it's not an interrupt in endpoint, we'd better punt! */
+ if (!usb_endpoint_is_int_in(endpoint))
goto descriptor_error;
/* We found a hub */
@@ -1022,26 +1013,29 @@ void usb_set_device_state(struct usb_device *udev,
if (udev->state == USB_STATE_NOTATTACHED)
; /* do nothing */
else if (new_state != USB_STATE_NOTATTACHED) {
- udev->state = new_state;
/* root hub wakeup capabilities are managed out-of-band
* and may involve silicon errata ... ignore them here.
*/
if (udev->parent) {
- if (new_state == USB_STATE_CONFIGURED)
+ if (udev->state == USB_STATE_SUSPENDED
+ || new_state == USB_STATE_SUSPENDED)
+ ; /* No change to wakeup settings */
+ else if (new_state == USB_STATE_CONFIGURED)
device_init_wakeup(&udev->dev,
(udev->actconfig->desc.bmAttributes
& USB_CONFIG_ATT_WAKEUP));
- else if (new_state != USB_STATE_SUSPENDED)
+ else
device_init_wakeup(&udev->dev, 0);
}
+ udev->state = new_state;
} else
recursively_mark_NOTATTACHED(udev);
spin_unlock_irqrestore(&device_state_lock, flags);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM
/**
* usb_root_hub_lost_power - called by HCD if the root hub lost Vbus power
@@ -1059,6 +1053,12 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
unsigned long flags;
dev_warn(&rhdev->dev, "root hub lost power or was reset\n");
+
+ /* Make sure no potential wakeup events get lost,
+ * by forcing the root hub to be resumed.
+ */
+ rhdev->dev.power.prev_state.event = PM_EVENT_ON;
+
spin_lock_irqsave(&device_state_lock, flags);
hub = hdev_to_hub(rhdev);
for (port1 = 1; port1 <= rhdev->maxchild; ++port1) {
@@ -1072,7 +1072,7 @@ void usb_root_hub_lost_power(struct usb_device *rhdev)
}
EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
-#endif
+#endif /* CONFIG_PM */
static void choose_address(struct usb_device *udev)
{
@@ -1148,144 +1148,28 @@ void usb_disconnect(struct usb_device **pdev)
* cleaning up all state associated with the current configuration
* so that the hardware is now fully quiesced.
*/
+ dev_dbg (&udev->dev, "unregistering device\n");
usb_disable_device(udev, 0);
- usb_notify_remove_device(udev);
+ usb_unlock_device(udev);
- /* Free the device number, remove the /proc/bus/usb entry and
- * the sysfs attributes, and delete the parent's children[]
+ /* Unregister the device. The device driver is responsible
+ * for removing the device files from usbfs and sysfs and for
+ * de-configuring the device.
+ */
+ device_del(&udev->dev);
+
+ /* Free the device number and delete the parent's children[]
* (or root_hub) pointer.
*/
- dev_dbg (&udev->dev, "unregistering device\n");
release_address(udev);
- usb_remove_sysfs_dev_files(udev);
/* Avoid races with recursively_mark_NOTATTACHED() */
spin_lock_irq(&device_state_lock);
*pdev = NULL;
spin_unlock_irq(&device_state_lock);
- usb_unlock_device(udev);
-
- device_unregister(&udev->dev);
-}
-
-static inline const char *plural(int n)
-{
- return (n == 1 ? "" : "s");
-}
-
-static int choose_configuration(struct usb_device *udev)
-{
- int i;
- int num_configs;
- int insufficient_power = 0;
- struct usb_host_config *c, *best;
-
- best = NULL;
- c = udev->config;
- num_configs = udev->descriptor.bNumConfigurations;
- for (i = 0; i < num_configs; (i++, c++)) {
- struct usb_interface_descriptor *desc = NULL;
-
- /* It's possible that a config has no interfaces! */
- if (c->desc.bNumInterfaces > 0)
- desc = &c->intf_cache[0]->altsetting->desc;
-
- /*
- * HP's USB bus-powered keyboard has only one configuration
- * and it claims to be self-powered; other devices may have
- * similar errors in their descriptors. If the next test
- * were allowed to execute, such configurations would always
- * be rejected and the devices would not work as expected.
- * In the meantime, we run the risk of selecting a config
- * that requires external power at a time when that power
- * isn't available. It seems to be the lesser of two evils.
- *
- * Bugzilla #6448 reports a device that appears to crash
- * when it receives a GET_DEVICE_STATUS request! We don't
- * have any other way to tell whether a device is self-powered,
- * but since we don't use that information anywhere but here,
- * the call has been removed.
- *
- * Maybe the GET_DEVICE_STATUS call and the test below can
- * be reinstated when device firmwares become more reliable.
- * Don't hold your breath.
- */
-#if 0
- /* Rule out self-powered configs for a bus-powered device */
- if (bus_powered && (c->desc.bmAttributes &
- USB_CONFIG_ATT_SELFPOWER))
- continue;
-#endif
-
- /*
- * The next test may not be as effective as it should be.
- * Some hubs have errors in their descriptor, claiming
- * to be self-powered when they are really bus-powered.
- * We will overestimate the amount of current such hubs
- * make available for each port.
- *
- * This is a fairly benign sort of failure. It won't
- * cause us to reject configurations that we should have
- * accepted.
- */
-
- /* Rule out configs that draw too much bus current */
- if (c->desc.bMaxPower * 2 > udev->bus_mA) {
- insufficient_power++;
- continue;
- }
-
- /* If the first config's first interface is COMM/2/0xff
- * (MSFT RNDIS), rule it out unless Linux has host-side
- * RNDIS support. */
- if (i == 0 && desc
- && desc->bInterfaceClass == USB_CLASS_COMM
- && desc->bInterfaceSubClass == 2
- && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
- continue;
-#else
- best = c;
-#endif
- }
-
- /* From the remaining configs, choose the first one whose
- * first interface is for a non-vendor-specific class.
- * Reason: Linux is more likely to have a class driver
- * than a vendor-specific driver. */
- else if (udev->descriptor.bDeviceClass !=
- USB_CLASS_VENDOR_SPEC &&
- (!desc || desc->bInterfaceClass !=
- USB_CLASS_VENDOR_SPEC)) {
- best = c;
- break;
- }
-
- /* If all the remaining configs are vendor-specific,
- * choose the first one. */
- else if (!best)
- best = c;
- }
-
- if (insufficient_power > 0)
- dev_info(&udev->dev, "rejected %d configuration%s "
- "due to insufficient available bus power\n",
- insufficient_power, plural(insufficient_power));
-
- if (best) {
- i = best->desc.bConfigurationValue;
- dev_info(&udev->dev,
- "configuration #%d chosen from %d choice%s\n",
- i, num_configs, plural(num_configs));
- } else {
- i = -1;
- dev_warn(&udev->dev,
- "no configuration chosen from %d choice%s\n",
- num_configs, plural(num_configs));
- }
- return i;
+ put_device(&udev->dev);
}
#ifdef DEBUG
@@ -1328,7 +1212,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
int usb_new_device(struct usb_device *udev)
{
int err;
- int c;
err = usb_get_configuration(udev);
if (err < 0) {
@@ -1371,8 +1254,7 @@ int usb_new_device(struct usb_device *udev)
USB_DT_OTG, (void **) &desc) == 0) {
if (desc->bmAttributes & USB_OTG_HNP) {
unsigned port1 = udev->portnum;
- struct usb_device *root = udev->parent;
-
+
dev_info(&udev->dev,
"Dual-Role OTG device on %sHNP port\n",
(port1 == bus->otg_port)
@@ -1407,9 +1289,9 @@ int usb_new_device(struct usb_device *udev)
* (Includes HNP test device.)
*/
if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
- static int __usb_suspend_device(struct usb_device *,
+ static int __usb_port_suspend(struct usb_device *,
int port1);
- err = __usb_suspend_device(udev, udev->bus->otg_port);
+ err = __usb_port_suspend(udev, udev->bus->otg_port);
if (err < 0)
dev_dbg(&udev->dev, "HNP fail, %d\n", err);
}
@@ -1418,34 +1300,15 @@ int usb_new_device(struct usb_device *udev)
}
#endif
- /* put device-specific files into sysfs */
+ /* Register the device. The device driver is responsible
+ * for adding the device files to usbfs and sysfs and for
+ * configuring the device.
+ */
err = device_add (&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
- usb_create_sysfs_dev_files (udev);
-
- usb_lock_device(udev);
-
- /* choose and set the configuration. that registers the interfaces
- * with the driver core, and lets usb device drivers bind to them.
- */
- c = choose_configuration(udev);
- if (c >= 0) {
- err = usb_set_configuration(udev, c);
- if (err) {
- dev_err(&udev->dev, "can't set config #%d, error %d\n",
- c, err);
- /* This need not be fatal. The user can try to
- * set other configurations. */
- }
- }
-
- /* USB device state == configured ... usable */
- usb_notify_add_device(udev);
-
- usb_unlock_device(udev);
return 0;
@@ -1472,6 +1335,18 @@ static int hub_port_status(struct usb_hub *hub, int port1,
return ret;
}
+
+/* Returns 1 if @hub is a WUSB root hub, 0 otherwise */
+static unsigned hub_is_wusb(struct usb_hub *hub)
+{
+ struct usb_hcd *hcd;
+ if (hub->hdev->parent != NULL) /* not a root hub? */
+ return 0;
+ hcd = container_of(hub->hdev->bus, struct usb_hcd, self);
+ return hcd->wireless;
+}
+
+
#define PORT_RESET_TRIES 5
#define SET_ADDRESS_TRIES 2
#define GET_DESCRIPTOR_TRIES 2
@@ -1512,7 +1387,9 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
/* if we`ve finished resetting, then break out of the loop */
if (!(portstatus & USB_PORT_STAT_RESET) &&
(portstatus & USB_PORT_STAT_ENABLE)) {
- if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+ if (hub_is_wusb(hub))
+ udev->speed = USB_SPEED_VARIABLE;
+ else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
udev->speed = USB_SPEED_HIGH;
else if (portstatus & USB_PORT_STAT_LOW_SPEED)
udev->speed = USB_SPEED_LOW;
@@ -1607,6 +1484,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
kick_khubd(hub);
}
+#ifdef CONFIG_PM
#ifdef CONFIG_USB_SUSPEND
@@ -1633,7 +1511,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* NOTE: OTG devices may issue remote wakeup (or SRP) even when
* we don't explicitly enable it here.
*/
- if (device_may_wakeup(&udev->dev)) {
+ if (udev->do_remote_wakeup) {
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0,
@@ -1659,7 +1537,8 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
USB_CTRL_SET_TIMEOUT);
} else {
/* device has up to 10 msec to fully suspend */
- dev_dbg(&udev->dev, "usb suspend\n");
+ dev_dbg(&udev->dev, "usb %ssuspend\n",
+ udev->auto_pm ? "auto-" : "");
usb_set_device_state(udev, USB_STATE_SUSPENDED);
msleep(10);
}
@@ -1684,7 +1563,7 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
* the root hub for their bus goes into global suspend ... so we don't
* (falsely) update the device power state to say it suspended.
*/
-static int __usb_suspend_device (struct usb_device *udev, int port1)
+static int __usb_port_suspend (struct usb_device *udev, int port1)
{
int status = 0;
@@ -1692,49 +1571,29 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
if (port1 < 0)
return port1;
- if (udev->state == USB_STATE_SUSPENDED
- || udev->state == USB_STATE_NOTATTACHED) {
- return 0;
- }
-
- /* all interfaces must already be suspended */
- if (udev->actconfig) {
- int i;
-
- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
- struct usb_interface *intf;
-
- intf = udev->actconfig->interface[i];
- if (is_active(intf)) {
- dev_dbg(&intf->dev, "nyet suspended\n");
- return -EBUSY;
- }
- }
- }
-
- /* we only change a device's upstream USB link.
- * root hubs have no upstream USB link.
+ /* we change the device's upstream USB link,
+ * but root hubs have no upstream USB link.
*/
if (udev->parent)
status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
udev);
-
- if (status == 0)
- udev->dev.power.power_state = PMSG_SUSPEND;
+ else {
+ dev_dbg(&udev->dev, "usb %ssuspend\n",
+ udev->auto_pm ? "auto-" : "");
+ usb_set_device_state(udev, USB_STATE_SUSPENDED);
+ }
return status;
}
-#endif
-
/*
- * usb_suspend_device - suspend a usb device
+ * usb_port_suspend - suspend a usb device's upstream port
* @udev: device that's no longer in active use
* Context: must be able to sleep; device not locked; pm locks held
*
* Suspends a USB device that isn't in active use, conserving power.
* Devices may wake out of a suspend, if anything important happens,
* using the remote wakeup mechanism. They may also be taken out of
- * suspend by the host, using usb_resume_device(). It's also routine
+ * suspend by the host, using usb_port_resume(). It's also routine
* to disconnect devices while they are suspended.
*
* This only affects the USB hardware for a device; its interfaces
@@ -1746,17 +1605,9 @@ static int __usb_suspend_device (struct usb_device *udev, int port1)
*
* Returns 0 on success, else negative errno.
*/
-int usb_suspend_device(struct usb_device *udev)
+int usb_port_suspend(struct usb_device *udev)
{
-#ifdef CONFIG_USB_SUSPEND
- if (udev->state == USB_STATE_NOTATTACHED)
- return -ENODEV;
- return __usb_suspend_device(udev, udev->portnum);
-#else
- /* NOTE: udev->state unchanged, it's not lying ... */
- udev->dev.power.power_state = PMSG_SUSPEND;
- return 0;
-#endif
+ return __usb_port_suspend(udev, udev->portnum);
}
/*
@@ -1767,7 +1618,7 @@ int usb_suspend_device(struct usb_device *udev)
* resume (by host) or remote wakeup (by device) ... now see what changed
* in the tree that's rooted at this device.
*/
-static int finish_device_resume(struct usb_device *udev)
+static int finish_port_resume(struct usb_device *udev)
{
int status;
u16 devstatus;
@@ -1783,7 +1634,6 @@ static int finish_device_resume(struct usb_device *udev)
usb_set_device_state(udev, udev->actconfig
? USB_STATE_CONFIGURED
: USB_STATE_ADDRESS);
- udev->dev.power.power_state = PMSG_ON;
/* 10.5.4.5 says be sure devices in the tree are still there.
* For now let's assume the device didn't go crazy on resume,
@@ -1798,9 +1648,6 @@ static int finish_device_resume(struct usb_device *udev)
"gone after usb resume? status %d\n",
status);
else if (udev->actconfig) {
- unsigned i;
- int (*resume)(struct device *);
-
le16_to_cpus(&devstatus);
if ((devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP))
&& udev->parent) {
@@ -1811,24 +1658,9 @@ static int finish_device_resume(struct usb_device *udev)
USB_DEVICE_REMOTE_WAKEUP, 0,
NULL, 0,
USB_CTRL_SET_TIMEOUT);
- if (status) {
+ if (status)
dev_dbg(&udev->dev, "disable remote "
"wakeup, status %d\n", status);
- status = 0;
- }
- }
-
- /* resume interface drivers; if this is a hub, it
- * may have a child resume event to deal with soon
- */
- resume = udev->dev.bus->resume;
- for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
- struct device *dev =
- &udev->actconfig->interface[i]->dev;
-
- down(&dev->sem);
- (void) resume(dev);
- up(&dev->sem);
}
status = 0;
@@ -1839,8 +1671,6 @@ static int finish_device_resume(struct usb_device *udev)
return status;
}
-#ifdef CONFIG_USB_SUSPEND
-
static int
hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
{
@@ -1848,6 +1678,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
// dev_dbg(hub->intfdev, "resume port %d\n", port1);
+ set_bit(port1, hub->busy_bits);
+
/* see 7.1.7.7; affects power usage, but not budgeting */
status = clear_port_feature(hub->hdev,
port1, USB_PORT_FEAT_SUSPEND);
@@ -1861,7 +1693,8 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
/* drive resume for at least 20 msec */
if (udev)
- dev_dbg(&udev->dev, "RESUME\n");
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ udev->auto_pm ? "auto-" : "");
msleep(25);
#define LIVE_FLAGS ( USB_PORT_STAT_POWER \
@@ -1891,19 +1724,21 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
/* TRSMRCY = 10 msec */
msleep(10);
if (udev)
- status = finish_device_resume(udev);
+ status = finish_port_resume(udev);
}
}
if (status < 0)
hub_port_logical_disconnect(hub, port1);
+ clear_bit(port1, hub->busy_bits);
+ if (!hub->hdev->parent && !hub->busy_bits[0])
+ usb_enable_root_hub_irq(hub->hdev->bus);
+
return status;
}
-#endif
-
/*
- * usb_resume_device - re-activate a suspended usb device
+ * usb_port_resume - re-activate a suspended usb device's upstream port
* @udev: device to re-activate
* Context: must be able to sleep; device not locked; pm locks held
*
@@ -1915,36 +1750,24 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
*
* Returns 0 on success, else negative errno.
*/
-int usb_resume_device(struct usb_device *udev)
+int usb_port_resume(struct usb_device *udev)
{
int status;
- if (udev->state == USB_STATE_NOTATTACHED)
- return -ENODEV;
-
- /* selective resume of one downstream hub-to-device port */
+ /* we change the device's upstream USB link,
+ * but root hubs have no upstream USB link.
+ */
if (udev->parent) {
-#ifdef CONFIG_USB_SUSPEND
- if (udev->state == USB_STATE_SUSPENDED) {
- // NOTE swsusp may bork us, device state being wrong...
- // NOTE this fails if parent is also suspended...
- status = hub_port_resume(hdev_to_hub(udev->parent),
- udev->portnum, udev);
- } else
-#endif
- status = 0;
- } else
- status = finish_device_resume(udev);
- if (status < 0)
- dev_dbg(&udev->dev, "can't resume, status %d\n",
- status);
-
- /* rebind drivers that had no suspend() */
- if (status == 0) {
- usb_unlock_device(udev);
- bus_rescan_devices(&usb_bus_type);
- usb_lock_device(udev);
+ // NOTE this fails if parent is also suspended...
+ status = hub_port_resume(hdev_to_hub(udev->parent),
+ udev->portnum, udev);
+ } else {
+ dev_dbg(&udev->dev, "usb %sresume\n",
+ udev->auto_pm ? "auto-" : "");
+ status = finish_port_resume(udev);
}
+ if (status < 0)
+ dev_dbg(&udev->dev, "can't resume, status %d\n", status);
return status;
}
@@ -1952,23 +1775,60 @@ static int remote_wakeup(struct usb_device *udev)
{
int status = 0;
-#ifdef CONFIG_USB_SUSPEND
+ /* All this just to avoid sending a port-resume message
+ * to the parent hub! */
- /* don't repeat RESUME sequence if this device
- * was already woken up by some other task
- */
usb_lock_device(udev);
+ usb_pm_lock(udev);
if (udev->state == USB_STATE_SUSPENDED) {
- dev_dbg(&udev->dev, "RESUME (wakeup)\n");
+ dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
/* TRSMRCY = 10 msec */
msleep(10);
- status = finish_device_resume(udev);
+ status = finish_port_resume(udev);
+ if (status == 0)
+ udev->dev.power.power_state.event = PM_EVENT_ON;
}
+ usb_pm_unlock(udev);
+
+ if (status == 0)
+ usb_autoresume_device(udev, 0);
usb_unlock_device(udev);
-#endif
return status;
}
+#else /* CONFIG_USB_SUSPEND */
+
+/* When CONFIG_USB_SUSPEND isn't set, we never suspend or resume any ports. */
+
+int usb_port_suspend(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int
+finish_port_resume(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int
+hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
+{
+ return 0;
+}
+
+int usb_port_resume(struct usb_device *udev)
+{
+ return 0;
+}
+
+static inline int remote_wakeup(struct usb_device *udev)
+{
+ return 0;
+}
+
+#endif
+
static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
{
struct usb_hub *hub = usb_get_intfdata (intf);
@@ -1980,13 +1840,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_device *udev;
udev = hdev->children [port1-1];
- if (udev && (udev->dev.power.power_state.event
- == PM_EVENT_ON
+ if (udev && msg.event == PM_EVENT_SUSPEND &&
#ifdef CONFIG_USB_SUSPEND
- || udev->state != USB_STATE_SUSPENDED
+ udev->state != USB_STATE_SUSPENDED
+#else
+ udev->dev.power.power_state.event
+ == PM_EVENT_ON
#endif
- )) {
- dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
+ ) {
+ if (!hdev->auto_pm)
+ dev_dbg(&intf->dev, "port %d nyet suspended\n",
+ port1);
return -EBUSY;
}
}
@@ -2035,66 +1899,22 @@ static int hub_resume(struct usb_interface *intf)
}
}
+ /* tell khubd to look for changes on this hub */
hub_activate(hub);
-
- /* REVISIT: this recursion probably shouldn't exist. Remove
- * this code sometime, after retesting with different root and
- * external hubs.
- */
-#ifdef CONFIG_USB_SUSPEND
- {
- unsigned port1;
-
- for (port1 = 1; port1 <= hdev->maxchild; port1++) {
- struct usb_device *udev;
- u16 portstat, portchange;
-
- udev = hdev->children [port1-1];
- status = hub_port_status(hub, port1, &portstat, &portchange);
- if (status == 0) {
- if (portchange & USB_PORT_STAT_C_SUSPEND) {
- clear_port_feature(hdev, port1,
- USB_PORT_FEAT_C_SUSPEND);
- portchange &= ~USB_PORT_STAT_C_SUSPEND;
- }
-
- /* let khubd handle disconnects etc */
- if (portchange)
- continue;
- }
-
- if (!udev || status < 0)
- continue;
- usb_lock_device(udev);
- if (portstat & USB_PORT_STAT_SUSPEND)
- status = hub_port_resume(hub, port1, udev);
- else {
- status = finish_device_resume(udev);
- if (status < 0) {
- dev_dbg(&intf->dev, "resume port %d --> %d\n",
- port1, status);
- hub_port_logical_disconnect(hub, port1);
- }
- }
- usb_unlock_device(udev);
- }
- }
-#endif
return 0;
}
-void usb_suspend_root_hub(struct usb_device *hdev)
-{
- struct usb_hub *hub = hdev_to_hub(hdev);
+#else /* CONFIG_PM */
- /* This also makes any led blinker stop retriggering. We're called
- * from irq, so the blinker might still be scheduled. Caller promises
- * that the root hub status URB will be canceled.
- */
- __hub_quiesce(hub);
- mark_quiesced(to_usb_interface(hub->intfdev));
+static inline int remote_wakeup(struct usb_device *udev)
+{
+ return 0;
}
+#define hub_suspend NULL
+#define hub_resume NULL
+#endif
+
void usb_resume_root_hub(struct usb_device *hdev)
{
struct usb_hub *hub = hdev_to_hub(hdev);
@@ -2214,6 +2034,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
+ char *speed, *type;
/* root hub ports have a slightly longer reset period
* (from USB 2.0 spec, section 7.1.7.5)
@@ -2246,8 +2067,13 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
* it's fixed size except for full speed devices.
+ * For Wireless USB devices, ep0 max packet is always 512 (tho
+ * reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
switch (udev->speed) {
+ case USB_SPEED_VARIABLE: /* fixed at 512 */
+ udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(512);
+ break;
case USB_SPEED_HIGH: /* fixed at 64 */
udev->ep0.desc.wMaxPacketSize = __constant_cpu_to_le16(64);
break;
@@ -2265,17 +2091,21 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
goto fail;
}
+ type = "";
+ switch (udev->speed) {
+ case USB_SPEED_LOW: speed = "low"; break;
+ case USB_SPEED_FULL: speed = "full"; break;
+ case USB_SPEED_HIGH: speed = "high"; break;
+ case USB_SPEED_VARIABLE:
+ speed = "variable";
+ type = "Wireless ";
+ break;
+ default: speed = "?"; break;
+ }
dev_info (&udev->dev,
- "%s %s speed USB device using %s and address %d\n",
- (udev->config) ? "reset" : "new",
- ({ char *speed; switch (udev->speed) {
- case USB_SPEED_LOW: speed = "low"; break;
- case USB_SPEED_FULL: speed = "full"; break;
- case USB_SPEED_HIGH: speed = "high"; break;
- default: speed = "?"; break;
- }; speed;}),
- udev->bus->controller->driver->name,
- udev->devnum);
+ "%s %s speed %sUSB device using %s and address %d\n",
+ (udev->config) ? "reset" : "new", speed, type,
+ udev->bus->controller->driver->name, udev->devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@@ -2317,6 +2147,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* down tremendously by NAKing the unexpectedly
* early status stage. Also, retry on all errors;
* some devices are flakey.
+ * 255 is for WUSB devices, we actually need to use 512.
+ * WUSB1.0[4.8.1].
*/
for (j = 0; j < 3; ++j) {
buf->bMaxPacketSize0 = 0;
@@ -2326,7 +2158,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
buf, GET_DESCRIPTOR_BUFSIZE,
(i ? USB_CTRL_GET_TIMEOUT : 1000));
switch (buf->bMaxPacketSize0) {
- case 8: case 16: case 32: case 64:
+ case 8: case 16: case 32: case 64: case 255:
if (buf->bDescriptorType ==
USB_DT_DEVICE) {
r = 0;
@@ -2400,7 +2232,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval)
goto fail;
- i = udev->descriptor.bMaxPacketSize0;
+ i = udev->descriptor.bMaxPacketSize0 == 0xff?
+ 512 : udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed != USB_SPEED_FULL ||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
@@ -2585,6 +2418,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
usb_set_device_state(udev, USB_STATE_POWERED);
udev->speed = USB_SPEED_UNKNOWN;
udev->bus_mA = hub->mA_per_port;
+ udev->level = hdev->level + 1;
/* set the address */
choose_address(udev);
@@ -2736,17 +2570,6 @@ static void hub_events(void)
usb_get_intf(intf);
spin_unlock_irq(&hub_event_lock);
- /* Is this is a root hub wanting to reactivate the downstream
- * ports? If so, be sure the interface resumes even if its
- * stub "device" node was never suspended.
- */
- if (i) {
- dpm_runtime_resume(&hdev->dev);
- dpm_runtime_resume(&intf->dev);
- usb_put_intf(intf);
- continue;
- }
-
/* Lock the device, then check to see if we were
* disconnected while waiting for the lock to succeed. */
if (locktree(hdev) < 0) {
@@ -2763,6 +2586,13 @@ static void hub_events(void)
goto loop;
}
+ /* Is this is a root hub wanting to reactivate the downstream
+ * ports? If so, be sure the interface resumes even if its
+ * stub "device" node was never suspended.
+ */
+ if (i)
+ usb_autoresume_device(hdev, 0);
+
/* If this is an inactive or suspended hub, do nothing */
if (hub->quiescing)
goto loop;
@@ -2900,7 +2730,7 @@ static void hub_events(void)
/* If this is a root hub, tell the HCD it's okay to
* re-enable port-change interrupts now. */
- if (!hdev->parent)
+ if (!hdev->parent && !hub->busy_bits[0])
usb_enable_root_hub_irq(hdev->bus);
loop:
@@ -3075,6 +2905,9 @@ int usb_reset_device(struct usb_device *udev)
break;
}
clear_bit(port1, parent_hub->busy_bits);
+ if (!parent_hdev->parent && !parent_hub->busy_bits[0])
+ usb_enable_root_hub_irq(parent_hdev->bus);
+
if (ret < 0)
goto re_enumerate;
@@ -3128,6 +2961,7 @@ re_enumerate:
hub_port_logical_disconnect(parent_hub, port1);
return -ENODEV;
}
+EXPORT_SYMBOL(usb_reset_device);
/**
* usb_reset_composite_device - warn interface drivers and perform a USB port reset
@@ -3163,6 +2997,9 @@ int usb_reset_composite_device(struct usb_device *udev,
return -EINVAL;
}
+ /* Prevent autosuspend during the reset */
+ usb_autoresume_device(udev, 1);
+
if (iface && iface->condition != USB_INTERFACE_BINDING)
iface = NULL;
@@ -3204,5 +3041,7 @@ int usb_reset_composite_device(struct usb_device *udev,
}
}
+ usb_autosuspend_device(udev, 1);
return ret;
}
+EXPORT_SYMBOL(usb_reset_composite_device);
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index 29d5f45a8456..0f8e82a4d480 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -212,7 +212,8 @@ struct usb_hub {
unsigned long event_bits[1]; /* status change bitmask */
unsigned long change_bits[1]; /* ports with logical connect
status change */
- unsigned long busy_bits[1]; /* ports being reset */
+ unsigned long busy_bits[1]; /* ports being reset or
+ resumed */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short!
#endif
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 3182c2224ba2..b5d6a79af0be 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -44,7 +44,7 @@
#include "hcd.h"
static struct super_operations usbfs_ops;
-static struct file_operations default_file_operations;
+static const struct file_operations default_file_operations;
static struct vfsmount *usbfs_mount;
static int usbfs_mount_count; /* = 0 */
static int ignore_mount = 0;
@@ -249,7 +249,6 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
@@ -264,7 +263,7 @@ static struct inode *usbfs_get_inode (struct super_block *sb, int mode, dev_t de
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
break;
}
}
@@ -296,7 +295,7 @@ static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, int mode)
mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
res = usbfs_mknod (dir, dentry, mode, 0);
if (!res)
- dir->i_nlink++;
+ inc_nlink(dir);
return res;
}
@@ -333,7 +332,7 @@ static int usbfs_unlink (struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
mutex_lock(&inode->i_mutex);
- dentry->d_inode->i_nlink--;
+ drop_nlink(dentry->d_inode);
dput(dentry);
mutex_unlock(&inode->i_mutex);
d_delete(dentry);
@@ -348,10 +347,11 @@ static int usbfs_rmdir(struct inode *dir, struct dentry *dentry)
mutex_lock(&inode->i_mutex);
dentry_unhash(dentry);
if (usbfs_empty(dentry)) {
- dentry->d_inode->i_nlink -= 2;
+ drop_nlink(dentry->d_inode);
+ drop_nlink(dentry->d_inode);
dput(dentry);
inode->i_flags |= S_DEAD;
- dir->i_nlink--;
+ drop_nlink(dir);
error = 0;
}
mutex_unlock(&inode->i_mutex);
@@ -402,13 +402,13 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
static int default_open (struct inode *inode, struct file *file)
{
- if (inode->u.generic_ip)
- file->private_data = inode->u.generic_ip;
+ if (inode->i_private)
+ file->private_data = inode->i_private;
return 0;
}
-static struct file_operations default_file_operations = {
+static const struct file_operations default_file_operations = {
.read = default_read_file,
.write = default_write_file,
.open = default_open,
@@ -495,7 +495,7 @@ static int fs_create_by_name (const char *name, mode_t mode,
static struct dentry *fs_create_file (const char *name, mode_t mode,
struct dentry *parent, void *data,
- struct file_operations *fops,
+ const struct file_operations *fops,
uid_t uid, gid_t gid)
{
struct dentry *dentry;
@@ -509,7 +509,7 @@ static struct dentry *fs_create_file (const char *name, mode_t mode,
} else {
if (dentry->d_inode) {
if (data)
- dentry->d_inode->u.generic_ip = data;
+ dentry->d_inode->i_private = data;
if (fops)
dentry->d_inode->i_fop = fops;
dentry->d_inode->i_uid = uid;
@@ -699,7 +699,7 @@ static void usbfs_remove_device(struct usb_device *dev)
sinfo.si_errno = EPIPE;
sinfo.si_code = SI_ASYNCIO;
sinfo.si_addr = ds->disccontext;
- kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid);
+ kill_pid_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid, ds->secid);
}
}
}
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 4cc8d3e67db7..fccd1952bad3 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -17,65 +17,50 @@
#include "hcd.h" /* for usbcore internals */
#include "usb.h"
-static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
+static void usb_api_blocking_completion(struct urb *urb)
{
complete((struct completion *)urb->context);
}
-static void timeout_kill(unsigned long data)
-{
- struct urb *urb = (struct urb *) data;
-
- usb_unlink_urb(urb);
-}
-
-// Starts urb and waits for completion or timeout
-// note that this call is NOT interruptible, while
-// many device driver i/o requests should be interruptible
-static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
+/*
+ * Starts urb and waits for completion or timeout. Note that this call
+ * is NOT interruptible. Many device driver i/o requests should be
+ * interruptible and therefore these drivers should implement their
+ * own interruptible routines.
+ */
+static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
{
- struct completion done;
- struct timer_list timer;
- int status;
+ struct completion done;
+ unsigned long expire;
+ int status;
init_completion(&done);
urb->context = &done;
urb->actual_length = 0;
status = usb_submit_urb(urb, GFP_NOIO);
-
- if (status == 0) {
- if (timeout > 0) {
- init_timer(&timer);
- timer.expires = jiffies + msecs_to_jiffies(timeout);
- timer.data = (unsigned long)urb;
- timer.function = timeout_kill;
- /* grr. timeout _should_ include submit delays. */
- add_timer(&timer);
- }
- wait_for_completion(&done);
+ if (unlikely(status))
+ goto out;
+
+ expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
+ if (!wait_for_completion_timeout(&done, expire)) {
+
+ dev_dbg(&urb->dev->dev,
+ "%s timed out on ep%d%s len=%d/%d\n",
+ current->comm,
+ usb_pipeendpoint(urb->pipe),
+ usb_pipein(urb->pipe) ? "in" : "out",
+ urb->actual_length,
+ urb->transfer_buffer_length);
+
+ usb_kill_urb(urb);
+ status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
+ } else
status = urb->status;
- /* note: HCDs return ETIMEDOUT for other reasons too */
- if (status == -ECONNRESET) {
- dev_dbg(&urb->dev->dev,
- "%s timed out on ep%d%s len=%d/%d\n",
- current->comm,
- usb_pipeendpoint(urb->pipe),
- usb_pipein(urb->pipe) ? "in" : "out",
- urb->actual_length,
- urb->transfer_buffer_length
- );
- if (urb->actual_length > 0)
- status = 0;
- else
- status = -ETIMEDOUT;
- }
- if (timeout > 0)
- del_timer_sync(&timer);
- }
-
+out:
if (actual_length)
*actual_length = urb->actual_length;
+
usb_free_urb(urb);
return status;
}
@@ -261,9 +246,9 @@ static void sg_clean (struct usb_sg_request *io)
io->dev = NULL;
}
-static void sg_complete (struct urb *urb, struct pt_regs *regs)
+static void sg_complete (struct urb *urb)
{
- struct usb_sg_request *io = (struct usb_sg_request *) urb->context;
+ struct usb_sg_request *io = urb->context;
spin_lock (&io->lock);
@@ -999,8 +984,8 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
ep = dev->ep_in[epnum];
dev->ep_in[epnum] = NULL;
}
- if (ep && dev->bus && dev->bus->op && dev->bus->op->disable)
- dev->bus->op->disable(dev, ep);
+ if (ep && dev->bus)
+ usb_hcd_endpoint_disable(dev, ep);
}
/**
@@ -1381,9 +1366,6 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
if (cp && configuration == 0)
dev_warn(&dev->dev, "config 0 descriptor??\n");
- if (dev->state == USB_STATE_SUSPENDED)
- return -EHOSTUNREACH;
-
/* Allocate memory for new interfaces before doing anything else,
* so that if we run out then nothing will have changed. */
n = nintf = 0;
@@ -1418,6 +1400,11 @@ free_interfaces:
configuration, -i);
}
+ /* Wake up the device so we can send it the Set-Config request */
+ ret = usb_autoresume_device(dev, 1);
+ if (ret)
+ goto free_interfaces;
+
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
@@ -1437,6 +1424,7 @@ free_interfaces:
dev->actconfig = cp;
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
+ usb_autosuspend_device(dev, 1);
goto free_interfaces;
}
usb_set_device_state(dev, USB_STATE_CONFIGURED);
@@ -1505,8 +1493,68 @@ free_interfaces:
usb_create_sysfs_intf_files (intf);
}
+ usb_autosuspend_device(dev, 1);
+ return 0;
+}
+
+struct set_config_request {
+ struct usb_device *udev;
+ int config;
+ struct work_struct work;
+};
+
+/* Worker routine for usb_driver_set_configuration() */
+static void driver_set_config_work(void *_req)
+{
+ struct set_config_request *req = _req;
+
+ usb_lock_device(req->udev);
+ usb_set_configuration(req->udev, req->config);
+ usb_unlock_device(req->udev);
+ usb_put_dev(req->udev);
+ kfree(req);
+}
+
+/**
+ * usb_driver_set_configuration - Provide a way for drivers to change device configurations
+ * @udev: the device whose configuration is being updated
+ * @config: the configuration being chosen.
+ * Context: In process context, must be able to sleep
+ *
+ * Device interface drivers are not allowed to change device configurations.
+ * This is because changing configurations will destroy the interface the
+ * driver is bound to and create new ones; it would be like a floppy-disk
+ * driver telling the computer to replace the floppy-disk drive with a
+ * tape drive!
+ *
+ * Still, in certain specialized circumstances the need may arise. This
+ * routine gets around the normal restrictions by using a work thread to
+ * submit the change-config request.
+ *
+ * Returns 0 if the request was succesfully queued, error code otherwise.
+ * The caller has no way to know whether the queued request will eventually
+ * succeed.
+ */
+int usb_driver_set_configuration(struct usb_device *udev, int config)
+{
+ struct set_config_request *req;
+
+ req = kmalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+ req->udev = udev;
+ req->config = config;
+ INIT_WORK(&req->work, driver_set_config_work, req);
+
+ usb_get_dev(udev);
+ if (!schedule_work(&req->work)) {
+ usb_put_dev(udev);
+ kfree(req);
+ return -EINVAL;
+ }
return 0;
}
+EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
// synchronous request completion model
EXPORT_SYMBOL(usb_control_msg);
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
index b042676af0a5..6b36897ca151 100644
--- a/drivers/usb/core/notify.c
+++ b/drivers/usb/core/notify.c
@@ -50,8 +50,11 @@ void usb_notify_add_device(struct usb_device *udev)
void usb_notify_remove_device(struct usb_device *udev)
{
+ /* Protect against simultaneous usbfs open */
+ mutex_lock(&usbfs_mutex);
blocking_notifier_call_chain(&usb_notifier_list,
USB_DEVICE_REMOVE, udev);
+ mutex_unlock(&usbfs_mutex);
}
void usb_notify_add_bus(struct usb_bus *ubus)
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index dec973affb0f..55d8f575206d 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -60,7 +60,7 @@ static ssize_t
set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
- struct usb_device *udev = udev = to_usb_device (dev);
+ struct usb_device *udev = to_usb_device (dev);
int config, value;
if (sscanf (buf, "%u", &config) != 1 || config > 255)
@@ -186,6 +186,7 @@ usb_descriptor_attr (bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
+ &dev_attr_configuration.attr,
&dev_attr_bNumInterfaces.attr,
&dev_attr_bConfigurationValue.attr,
&dev_attr_bmAttributes.attr,
@@ -209,20 +210,40 @@ static struct attribute_group dev_attr_grp = {
.attrs = dev_attrs,
};
-void usb_create_sysfs_dev_files (struct usb_device *udev)
+int usb_create_sysfs_dev_files(struct usb_device *udev)
{
struct device *dev = &udev->dev;
+ int retval;
- sysfs_create_group(&dev->kobj, &dev_attr_grp);
+ retval = sysfs_create_group(&dev->kobj, &dev_attr_grp);
+ if (retval)
+ return retval;
- if (udev->manufacturer)
- device_create_file (dev, &dev_attr_manufacturer);
- if (udev->product)
- device_create_file (dev, &dev_attr_product);
- if (udev->serial)
- device_create_file (dev, &dev_attr_serial);
- device_create_file (dev, &dev_attr_configuration);
- usb_create_ep_files(dev, &udev->ep0, udev);
+ if (udev->manufacturer) {
+ retval = device_create_file (dev, &dev_attr_manufacturer);
+ if (retval)
+ goto error;
+ }
+ if (udev->product) {
+ retval = device_create_file (dev, &dev_attr_product);
+ if (retval)
+ goto error;
+ }
+ if (udev->serial) {
+ retval = device_create_file (dev, &dev_attr_serial);
+ if (retval)
+ goto error;
+ }
+ retval = usb_create_ep_files(dev, &udev->ep0, udev);
+ if (retval)
+ goto error;
+ return 0;
+error:
+ usb_remove_ep_files(&udev->ep0);
+ device_remove_file(dev, &dev_attr_manufacturer);
+ device_remove_file(dev, &dev_attr_product);
+ device_remove_file(dev, &dev_attr_serial);
+ return retval;
}
void usb_remove_sysfs_dev_files (struct usb_device *udev)
@@ -238,7 +259,6 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
device_remove_file(dev, &dev_attr_product);
if (udev->serial)
device_remove_file(dev, &dev_attr_serial);
- device_remove_file (dev, &dev_attr_configuration);
}
/* Interface fields */
@@ -340,18 +360,28 @@ static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
usb_remove_ep_files(&iface_desc->endpoint[i]);
}
-void usb_create_sysfs_intf_files (struct usb_interface *intf)
+int usb_create_sysfs_intf_files(struct usb_interface *intf)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_host_interface *alt = intf->cur_altsetting;
+ int retval;
- sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+ retval = sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
+ if (retval)
+ goto error;
if (alt->string == NULL)
alt->string = usb_cache_string(udev, alt->desc.iInterface);
if (alt->string)
- device_create_file(&intf->dev, &dev_attr_interface);
+ retval = device_create_file(&intf->dev, &dev_attr_interface);
usb_create_intf_ep_files(intf, udev);
+ return 0;
+error:
+ if (alt->string)
+ device_remove_file(&intf->dev, &dev_attr_interface);
+ sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
+ usb_remove_intf_ep_files(intf);
+ return retval;
}
void usb_remove_sysfs_intf_files (struct usb_interface *intf)
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 9864988377c7..9801d08edacf 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -57,7 +57,7 @@ struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
struct urb *urb;
- urb = (struct urb *)kmalloc(sizeof(struct urb) +
+ urb = kmalloc(sizeof(struct urb) +
iso_packets * sizeof(struct usb_iso_packet_descriptor),
mem_flags);
if (!urb) {
@@ -221,7 +221,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
int pipe, temp, max;
struct usb_device *dev;
- struct usb_operations *op;
int is_out;
if (!urb || urb->hcpriv || !urb->complete)
@@ -233,8 +232,6 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
|| dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
- if (!(op = dev->bus->op) || !op->submit_urb)
- return -ENODEV;
urb->status = -EINPROGRESS;
urb->actual_length = 0;
@@ -376,7 +373,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
urb->interval = temp;
}
- return op->submit_urb (urb, mem_flags);
+ return usb_hcd_submit_urb (urb, mem_flags);
}
/*-------------------------------------------------------------------*/
@@ -440,9 +437,9 @@ int usb_unlink_urb(struct urb *urb)
{
if (!urb)
return -EINVAL;
- if (!(urb->dev && urb->dev->bus && urb->dev->bus->op))
+ if (!(urb->dev && urb->dev->bus))
return -ENODEV;
- return urb->dev->bus->op->unlink_urb(urb, -ECONNRESET);
+ return usb_hcd_unlink_urb(urb, -ECONNRESET);
}
/**
@@ -468,13 +465,13 @@ int usb_unlink_urb(struct urb *urb)
void usb_kill_urb(struct urb *urb)
{
might_sleep();
- if (!(urb && urb->dev && urb->dev->bus && urb->dev->bus->op))
+ if (!(urb && urb->dev && urb->dev->bus))
return;
spin_lock_irq(&urb->lock);
++urb->reject;
spin_unlock_irq(&urb->lock);
- urb->dev->bus->op->unlink_urb(urb, -ENOENT);
+ usb_hcd_unlink_urb(urb, -ENOENT);
wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
spin_lock_irq(&urb->lock);
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 184c24660a4c..467cb02832f3 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1,5 +1,5 @@
/*
- * drivers/usb/usb.c
+ * drivers/usb/core/usb.c
*
* (C) Copyright Linus Torvalds 1999
* (C) Copyright Johannes Erdfelt 1999-2001
@@ -33,6 +33,7 @@
#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <asm/io.h>
#include <asm/scatterlist.h>
@@ -47,6 +48,8 @@ const char *usbcore_name = "usbcore";
static int nousb; /* Disable USB when built into kernel image */
+struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */
+
/**
* usb_ifnum_to_if - get the interface object with a given interface number
@@ -67,7 +70,8 @@ static int nousb; /* Disable USB when built into kernel image */
* Don't call this function unless you are bound to one of the interfaces
* on this device or you have locked the device!
*/
-struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
+struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
+ unsigned ifnum)
{
struct usb_host_config *config = dev->actconfig;
int i;
@@ -100,8 +104,8 @@ struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum)
* Don't call this function unless you are bound to the intf interface
* or you have locked the device!
*/
-struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
- unsigned int altnum)
+struct usb_host_interface *usb_altnum_to_altsetting(const struct usb_interface *intf,
+ unsigned int altnum)
{
int i;
@@ -112,87 +116,6 @@ struct usb_host_interface *usb_altnum_to_altsetting(struct usb_interface *intf,
return NULL;
}
-/**
- * usb_driver_claim_interface - bind a driver to an interface
- * @driver: the driver to be bound
- * @iface: the interface to which it will be bound; must be in the
- * usb device's active configuration
- * @priv: driver data associated with that interface
- *
- * This is used by usb device drivers that need to claim more than one
- * interface on a device when probing (audio and acm are current examples).
- * No device driver should directly modify internal usb_interface or
- * usb_device structure members.
- *
- * Few drivers should need to use this routine, since the most natural
- * way to bind to an interface is to return the private data from
- * the driver's probe() method.
- *
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock. So driver probe() entries don't need extra locking,
- * but other call contexts may need to explicitly claim those locks.
- */
-int usb_driver_claim_interface(struct usb_driver *driver,
- struct usb_interface *iface, void* priv)
-{
- struct device *dev = &iface->dev;
-
- if (dev->driver)
- return -EBUSY;
-
- dev->driver = &driver->driver;
- usb_set_intfdata(iface, priv);
- iface->condition = USB_INTERFACE_BOUND;
- mark_active(iface);
-
- /* if interface was already added, bind now; else let
- * the future device_add() bind it, bypassing probe()
- */
- if (device_is_registered(dev))
- device_bind_driver(dev);
-
- return 0;
-}
-
-/**
- * usb_driver_release_interface - unbind a driver from an interface
- * @driver: the driver to be unbound
- * @iface: the interface from which it will be unbound
- *
- * This can be used by drivers to release an interface without waiting
- * for their disconnect() methods to be called. In typical cases this
- * also causes the driver disconnect() method to be called.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the device lock and the driver model's usb_bus_type.subsys
- * writelock. So driver disconnect() entries don't need extra locking,
- * but other call contexts may need to explicitly claim those locks.
- */
-void usb_driver_release_interface(struct usb_driver *driver,
- struct usb_interface *iface)
-{
- struct device *dev = &iface->dev;
-
- /* this should never happen, don't release something that's not ours */
- if (!dev->driver || dev->driver != &driver->driver)
- return;
-
- /* don't release from within disconnect() */
- if (iface->condition != USB_INTERFACE_BOUND)
- return;
-
- /* don't release if the interface hasn't been added yet */
- if (device_is_registered(dev)) {
- iface->condition = USB_INTERFACE_UNBINDING;
- device_release_driver(dev);
- }
-
- dev->driver = NULL;
- usb_set_intfdata(iface, NULL);
- iface->condition = USB_INTERFACE_UNBOUND;
- mark_quiesced(iface);
-}
-
struct find_interface_arg {
int minor;
struct usb_interface *interface;
@@ -204,7 +127,7 @@ static int __find_interface(struct device * dev, void * data)
struct usb_interface *intf;
/* can't look at usb devices, only interfaces */
- if (dev->driver == &usb_generic_driver)
+ if (is_usb_device(dev))
return 0;
intf = to_usb_interface(dev);
@@ -227,147 +150,82 @@ static int __find_interface(struct device * dev, void * data)
struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
{
struct find_interface_arg argb;
+ int retval;
argb.minor = minor;
argb.interface = NULL;
- driver_for_each_device(&drv->driver, NULL, &argb, __find_interface);
+ /* eat the error, it will be in argb.interface */
+ retval = driver_for_each_device(&drv->drvwrap.driver, NULL, &argb,
+ __find_interface);
return argb.interface;
}
-#ifdef CONFIG_HOTPLUG
-
-/*
- * This sends an uevent to userspace, typically helping to load driver
- * or other modules, configure the device, and more. Drivers can provide
- * a MODULE_DEVICE_TABLE to help with module loading subtasks.
+/**
+ * usb_release_dev - free a usb device structure when all users of it are finished.
+ * @dev: device that's been disconnected
*
- * We're called either from khubd (the typical case) or from root hub
- * (init, kapmd, modprobe, rmmod, etc), but the agents need to handle
- * delays in event delivery. Use sysfs (and DEVPATH) to make sure the
- * device (and this configuration!) are still present.
+ * Will be called only by the device core when all users of this usb device are
+ * done.
*/
-static int usb_uevent(struct device *dev, char **envp, int num_envp,
- char *buffer, int buffer_size)
+static void usb_release_dev(struct device *dev)
{
- struct usb_interface *intf;
- struct usb_device *usb_dev;
- struct usb_host_interface *alt;
- int i = 0;
- int length = 0;
-
- if (!dev)
- return -ENODEV;
-
- /* driver is often null here; dev_dbg() would oops */
- pr_debug ("usb %s: uevent\n", dev->bus_id);
-
- /* Must check driver_data here, as on remove driver is always NULL */
- if ((dev->driver == &usb_generic_driver) ||
- (dev->driver_data == &usb_generic_driver_data))
- return 0;
-
- intf = to_usb_interface(dev);
- usb_dev = interface_to_usbdev (intf);
- alt = intf->cur_altsetting;
+ struct usb_device *udev;
- if (usb_dev->devnum < 0) {
- pr_debug ("usb %s: already deleted?\n", dev->bus_id);
- return -ENODEV;
- }
- if (!usb_dev->bus) {
- pr_debug ("usb %s: bus removed?\n", dev->bus_id);
- return -ENODEV;
- }
+ udev = to_usb_device(dev);
-#ifdef CONFIG_USB_DEVICEFS
- /* If this is available, userspace programs can directly read
- * all the device descriptors we don't tell them about. Or
- * even act as usermode drivers.
- *
- * FIXME reduce hardwired intelligence here
- */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "DEVICE=/proc/bus/usb/%03d/%03d",
- usb_dev->bus->busnum, usb_dev->devnum))
- return -ENOMEM;
+#ifdef CONFIG_USB_SUSPEND
+ cancel_delayed_work(&udev->autosuspend);
+ flush_workqueue(ksuspend_usb_wq);
#endif
+ usb_destroy_configuration(udev);
+ usb_put_hcd(bus_to_hcd(udev->bus));
+ kfree(udev->product);
+ kfree(udev->manufacturer);
+ kfree(udev->serial);
+ kfree(udev);
+}
- /* per-device configurations are common */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "PRODUCT=%x/%x/%x",
- le16_to_cpu(usb_dev->descriptor.idVendor),
- le16_to_cpu(usb_dev->descriptor.idProduct),
- le16_to_cpu(usb_dev->descriptor.bcdDevice)))
- return -ENOMEM;
+#ifdef CONFIG_PM
- /* class-based driver binding models */
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "TYPE=%d/%d/%d",
- usb_dev->descriptor.bDeviceClass,
- usb_dev->descriptor.bDeviceSubClass,
- usb_dev->descriptor.bDeviceProtocol))
+static int ksuspend_usb_init(void)
+{
+ ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd");
+ if (!ksuspend_usb_wq)
return -ENOMEM;
+ return 0;
+}
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "INTERFACE=%d/%d/%d",
- alt->desc.bInterfaceClass,
- alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
- return -ENOMEM;
+static void ksuspend_usb_cleanup(void)
+{
+ destroy_workqueue(ksuspend_usb_wq);
+}
- if (add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
- le16_to_cpu(usb_dev->descriptor.idVendor),
- le16_to_cpu(usb_dev->descriptor.idProduct),
- le16_to_cpu(usb_dev->descriptor.bcdDevice),
- usb_dev->descriptor.bDeviceClass,
- usb_dev->descriptor.bDeviceSubClass,
- usb_dev->descriptor.bDeviceProtocol,
- alt->desc.bInterfaceClass,
- alt->desc.bInterfaceSubClass,
- alt->desc.bInterfaceProtocol))
- return -ENOMEM;
+#else
- envp[i] = NULL;
+#define ksuspend_usb_init() 0
+#define ksuspend_usb_cleanup() do {} while (0)
- return 0;
-}
+#endif
-#else
+#ifdef CONFIG_USB_SUSPEND
-static int usb_uevent(struct device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size)
+/* usb_autosuspend_work - callback routine to autosuspend a USB device */
+static void usb_autosuspend_work(void *_udev)
{
- return -ENODEV;
-}
+ struct usb_device *udev = _udev;
-#endif /* CONFIG_HOTPLUG */
+ usb_pm_lock(udev);
+ udev->auto_pm = 1;
+ usb_suspend_both(udev, PMSG_SUSPEND);
+ usb_pm_unlock(udev);
+}
-/**
- * usb_release_dev - free a usb device structure when all users of it are finished.
- * @dev: device that's been disconnected
- *
- * Will be called only by the device core when all users of this usb device are
- * done.
- */
-static void usb_release_dev(struct device *dev)
-{
- struct usb_device *udev;
+#else
- udev = to_usb_device(dev);
+static void usb_autosuspend_work(void *_udev)
+{}
- usb_destroy_configuration(udev);
- usb_bus_put(udev->bus);
- kfree(udev->product);
- kfree(udev->manufacturer);
- kfree(udev->serial);
- kfree(udev);
-}
+#endif
/**
* usb_alloc_dev - usb device constructor (usbcore-internal)
@@ -390,8 +248,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
if (!dev)
return NULL;
- bus = usb_bus_get(bus);
- if (!bus) {
+ if (!usb_get_hcd(bus_to_hcd(bus))) {
kfree(dev);
return NULL;
}
@@ -399,11 +256,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
dev->dev.dma_mask = bus->controller->dma_mask;
- dev->dev.driver_data = &usb_generic_driver_data;
- dev->dev.driver = &usb_generic_driver;
dev->dev.release = usb_release_dev;
dev->state = USB_STATE_ATTACHED;
+ /* This magic assignment distinguishes devices from interfaces */
+ dev->dev.platform_data = &usb_generic_driver;
+
INIT_LIST_HEAD(&dev->ep0.urb_list);
dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
@@ -444,6 +302,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
dev->parent = parent;
INIT_LIST_HEAD(&dev->filelist);
+#ifdef CONFIG_PM
+ mutex_init(&dev->pm_mutex);
+ INIT_WORK(&dev->autosuspend, usb_autosuspend_work, dev);
+#endif
return dev;
}
@@ -549,7 +411,7 @@ void usb_put_intf(struct usb_interface *intf)
* case the driver already owns the device lock.)
*/
int usb_lock_device_for_reset(struct usb_device *udev,
- struct usb_interface *iface)
+ const struct usb_interface *iface)
{
unsigned long jiffies_expire = jiffies + HZ;
@@ -672,7 +534,139 @@ exit:
*/
int usb_get_current_frame_number(struct usb_device *dev)
{
- return dev->bus->op->get_frame_number (dev);
+ return usb_hcd_get_frame_number (dev);
+}
+
+/**
+ * usb_endpoint_dir_in - check if the endpoint has IN direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type IN, otherwise it returns false.
+ */
+int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
+}
+
+/**
+ * usb_endpoint_dir_out - check if the endpoint has OUT direction
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type OUT, otherwise it returns false.
+ */
+int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT);
+}
+
+/**
+ * usb_endpoint_xfer_bulk - check if the endpoint has bulk transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type bulk, otherwise it returns false.
+ */
+int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_BULK);
+}
+
+/**
+ * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type interrupt, otherwise it returns
+ * false.
+ */
+int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_INT);
+}
+
+/**
+ * usb_endpoint_xfer_isoc - check if the endpoint has isochronous transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type isochronous, otherwise it returns
+ * false.
+ */
+int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd)
+{
+ return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+ USB_ENDPOINT_XFER_ISOC);
+}
+
+/**
+ * usb_endpoint_is_bulk_in - check if the endpoint is bulk IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has bulk transfer type and IN direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_bulk_out - check if the endpoint is bulk OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has bulk transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_bulk(epd) && usb_endpoint_dir_out(epd));
+}
+
+/**
+ * usb_endpoint_is_int_in - check if the endpoint is interrupt IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and IN direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_int_out - check if the endpoint is interrupt OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has interrupt transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_out(epd));
+}
+
+/**
+ * usb_endpoint_is_isoc_in - check if the endpoint is isochronous IN
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has isochronous transfer type and IN direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_in(epd));
+}
+
+/**
+ * usb_endpoint_is_isoc_out - check if the endpoint is isochronous OUT
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint has isochronous transfer type and OUT direction,
+ * otherwise it returns false.
+ */
+int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd)
+{
+ return (usb_endpoint_xfer_isoc(epd) && usb_endpoint_dir_out(epd));
}
/*-------------------------------------------------------------------*/
@@ -737,9 +731,9 @@ void *usb_buffer_alloc (
dma_addr_t *dma
)
{
- if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_alloc)
+ if (!dev || !dev->bus)
return NULL;
- return dev->bus->op->buffer_alloc (dev->bus, size, mem_flags, dma);
+ return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
}
/**
@@ -760,9 +754,11 @@ void usb_buffer_free (
dma_addr_t dma
)
{
- if (!dev || !dev->bus || !dev->bus->op || !dev->bus->op->buffer_free)
- return;
- dev->bus->op->buffer_free (dev->bus, size, addr, dma);
+ if (!dev || !dev->bus)
+ return;
+ if (!addr)
+ return;
+ hcd_buffer_free (dev->bus, size, addr, dma);
}
/**
@@ -911,8 +907,8 @@ void usb_buffer_unmap (struct urb *urb)
*
* Reverse the effect of this call with usb_buffer_unmap_sg().
*/
-int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int nents)
+int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int nents)
{
struct usb_bus *bus;
struct device *controller;
@@ -946,8 +942,8 @@ int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
* Use this when you are re-using a scatterlist's data buffers for
* another USB request.
*/
-void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int n_hw_ents)
+void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
@@ -972,8 +968,8 @@ void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
*
* Reverses the effect of usb_buffer_map_sg().
*/
-void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int n_hw_ents)
+void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents)
{
struct usb_bus *bus;
struct device *controller;
@@ -988,116 +984,6 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
-static int verify_suspended(struct device *dev, void *unused)
-{
- if (dev->driver == NULL)
- return 0;
- return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
-}
-
-static int usb_generic_suspend(struct device *dev, pm_message_t message)
-{
- struct usb_interface *intf;
- struct usb_driver *driver;
- int status;
-
- /* USB devices enter SUSPEND state through their hubs, but can be
- * marked for FREEZE as soon as their children are already idled.
- * But those semantics are useless, so we equate the two (sigh).
- */
- if (dev->driver == &usb_generic_driver) {
- if (dev->power.power_state.event == message.event)
- return 0;
- /* we need to rule out bogus requests through sysfs */
- status = device_for_each_child(dev, NULL, verify_suspended);
- if (status)
- return status;
- return usb_suspend_device (to_usb_device(dev));
- }
-
- if ((dev->driver == NULL) ||
- (dev->driver_data == &usb_generic_driver_data))
- return 0;
-
- intf = to_usb_interface(dev);
- driver = to_usb_driver(dev->driver);
-
- /* with no hardware, USB interfaces only use FREEZE and ON states */
- if (!is_active(intf))
- return 0;
-
- if (driver->suspend && driver->resume) {
- status = driver->suspend(intf, message);
- if (status)
- dev_err(dev, "%s error %d\n", "suspend", status);
- else
- mark_quiesced(intf);
- } else {
- // FIXME else if there's no suspend method, disconnect...
- dev_warn(dev, "no suspend for driver %s?\n", driver->name);
- mark_quiesced(intf);
- status = 0;
- }
- return status;
-}
-
-static int usb_generic_resume(struct device *dev)
-{
- struct usb_interface *intf;
- struct usb_driver *driver;
- struct usb_device *udev;
- int status;
-
- if (dev->power.power_state.event == PM_EVENT_ON)
- return 0;
-
- /* mark things as "on" immediately, no matter what errors crop up */
- dev->power.power_state.event = PM_EVENT_ON;
-
- /* devices resume through their hubs */
- if (dev->driver == &usb_generic_driver) {
- udev = to_usb_device(dev);
- if (udev->state == USB_STATE_NOTATTACHED)
- return 0;
- return usb_resume_device (to_usb_device(dev));
- }
-
- if ((dev->driver == NULL) ||
- (dev->driver_data == &usb_generic_driver_data)) {
- dev->power.power_state.event = PM_EVENT_FREEZE;
- return 0;
- }
-
- intf = to_usb_interface(dev);
- driver = to_usb_driver(dev->driver);
-
- udev = interface_to_usbdev(intf);
- if (udev->state == USB_STATE_NOTATTACHED)
- return 0;
-
- /* if driver was suspended, it has a resume method;
- * however, sysfs can wrongly mark things as suspended
- * (on the "no suspend method" FIXME path above)
- */
- if (driver->resume) {
- status = driver->resume(intf);
- if (status) {
- dev_err(dev, "%s error %d\n", "resume", status);
- mark_quiesced(intf);
- }
- } else
- dev_warn(dev, "no resume for driver %s?\n", driver->name);
- return 0;
-}
-
-struct bus_type usb_bus_type = {
- .name = "usb",
- .match = usb_device_match,
- .uevent = usb_uevent,
- .suspend = usb_generic_suspend,
- .resume = usb_generic_resume,
-};
-
/* format to disable USB on kernel command line is: nousb */
__module_param_call("", nousb, param_set_bool, param_get_bool, &nousb, 0444);
@@ -1120,9 +1006,12 @@ static int __init usb_init(void)
return 0;
}
+ retval = ksuspend_usb_init();
+ if (retval)
+ goto out;
retval = bus_register(&usb_bus_type);
if (retval)
- goto out;
+ goto bus_register_failed;
retval = usb_host_init();
if (retval)
goto host_init_failed;
@@ -1141,7 +1030,7 @@ static int __init usb_init(void)
retval = usb_hub_init();
if (retval)
goto hub_init_failed;
- retval = driver_register(&usb_generic_driver);
+ retval = usb_register_device_driver(&usb_generic_driver, THIS_MODULE);
if (!retval)
goto out;
@@ -1158,6 +1047,8 @@ major_init_failed:
usb_host_cleanup();
host_init_failed:
bus_unregister(&usb_bus_type);
+bus_register_failed:
+ ksuspend_usb_cleanup();
out:
return retval;
}
@@ -1171,7 +1062,7 @@ static void __exit usb_exit(void)
if (nousb)
return;
- driver_unregister(&usb_generic_driver);
+ usb_deregister_device_driver(&usb_generic_driver);
usb_major_cleanup();
usbfs_cleanup();
usb_deregister(&usbfs_driver);
@@ -1179,6 +1070,7 @@ static void __exit usb_exit(void)
usb_hub_cleanup();
usb_host_cleanup();
bus_unregister(&usb_bus_type);
+ ksuspend_usb_cleanup();
}
subsys_initcall(usb_init);
@@ -1201,20 +1093,27 @@ EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
EXPORT_SYMBOL(usb_lock_device_for_reset);
-EXPORT_SYMBOL(usb_driver_claim_interface);
-EXPORT_SYMBOL(usb_driver_release_interface);
EXPORT_SYMBOL(usb_find_interface);
EXPORT_SYMBOL(usb_ifnum_to_if);
EXPORT_SYMBOL(usb_altnum_to_altsetting);
-EXPORT_SYMBOL(usb_reset_device);
-EXPORT_SYMBOL(usb_reset_composite_device);
-
EXPORT_SYMBOL(__usb_get_extra_descriptor);
EXPORT_SYMBOL(usb_find_device);
EXPORT_SYMBOL(usb_get_current_frame_number);
+EXPORT_SYMBOL_GPL(usb_endpoint_dir_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_dir_out);
+EXPORT_SYMBOL_GPL(usb_endpoint_xfer_bulk);
+EXPORT_SYMBOL_GPL(usb_endpoint_xfer_int);
+EXPORT_SYMBOL_GPL(usb_endpoint_xfer_isoc);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_bulk_out);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_int_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_int_out);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_in);
+EXPORT_SYMBOL_GPL(usb_endpoint_is_isoc_out);
+
EXPORT_SYMBOL (usb_buffer_alloc);
EXPORT_SYMBOL (usb_buffer_free);
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 49f69236b420..13322e33f912 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -1,10 +1,10 @@
/* Functions local to drivers/usb/core/ */
-extern void usb_create_sysfs_dev_files (struct usb_device *dev);
+extern int usb_create_sysfs_dev_files (struct usb_device *dev);
extern void usb_remove_sysfs_dev_files (struct usb_device *dev);
-extern void usb_create_sysfs_intf_files (struct usb_interface *intf);
+extern int usb_create_sysfs_intf_files (struct usb_interface *intf);
extern void usb_remove_sysfs_intf_files (struct usb_interface *intf);
-extern void usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
+extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *endpoint,
struct usb_device *udev);
extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
@@ -20,7 +20,6 @@ extern char *usb_cache_string(struct usb_device *udev, int index);
extern int usb_set_configuration(struct usb_device *dev, int configuration);
extern void usb_kick_khubd(struct usb_device *dev);
-extern void usb_suspend_root_hub(struct usb_device *hdev);
extern void usb_resume_root_hub(struct usb_device *dev);
extern int usb_hub_init(void);
@@ -30,28 +29,91 @@ extern void usb_major_cleanup(void);
extern int usb_host_init(void);
extern void usb_host_cleanup(void);
-extern int usb_suspend_device(struct usb_device *dev);
-extern int usb_resume_device(struct usb_device *dev);
+#ifdef CONFIG_PM
-extern struct device_driver usb_generic_driver;
-extern int usb_generic_driver_data;
-extern int usb_device_match(struct device *dev, struct device_driver *drv);
+extern int usb_suspend_both(struct usb_device *udev, pm_message_t msg);
+extern int usb_resume_both(struct usb_device *udev);
+extern int usb_port_suspend(struct usb_device *dev);
+extern int usb_port_resume(struct usb_device *dev);
+
+static inline void usb_pm_lock(struct usb_device *udev)
+{
+ mutex_lock_nested(&udev->pm_mutex, udev->level);
+}
+
+static inline void usb_pm_unlock(struct usb_device *udev)
+{
+ mutex_unlock(&udev->pm_mutex);
+}
+
+#else
+
+#define usb_suspend_both(udev, msg) 0
+static inline int usb_resume_both(struct usb_device *udev)
+{
+ return 0;
+}
+#define usb_port_suspend(dev) 0
+#define usb_port_resume(dev) 0
+static inline void usb_pm_lock(struct usb_device *udev) {}
+static inline void usb_pm_unlock(struct usb_device *udev) {}
+
+#endif
+
+#ifdef CONFIG_USB_SUSPEND
+
+#define USB_AUTOSUSPEND_DELAY (HZ*2)
+
+extern void usb_autosuspend_device(struct usb_device *udev, int dec_busy_cnt);
+extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt);
+
+#else
+
+#define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0)
+static inline int usb_autoresume_device(struct usb_device *udev,
+ int inc_busy_cnt)
+{
+ return 0;
+}
+
+#endif
+
+extern struct workqueue_struct *ksuspend_usb_wq;
+extern struct bus_type usb_bus_type;
+extern struct usb_device_driver usb_generic_driver;
+
+/* Here's how we tell apart devices and interfaces. Luckily there's
+ * no such thing as a platform USB device, so we can steal the use
+ * of the platform_data field. */
+
+static inline int is_usb_device(const struct device *dev)
+{
+ return dev->platform_data == &usb_generic_driver;
+}
+
+/* Do the same for device drivers and interface drivers. */
+
+static inline int is_usb_device_driver(struct device_driver *drv)
+{
+ return container_of(drv, struct usbdrv_wrap, driver)->
+ for_devices;
+}
/* Interfaces and their "power state" are owned by usbcore */
static inline void mark_active(struct usb_interface *f)
{
- f->dev.power.power_state.event = PM_EVENT_ON;
+ f->is_active = 1;
}
static inline void mark_quiesced(struct usb_interface *f)
{
- f->dev.power.power_state.event = PM_EVENT_FREEZE;
+ f->is_active = 0;
}
-static inline int is_active(struct usb_interface *f)
+static inline int is_active(const struct usb_interface *f)
{
- return f->dev.power.power_state.event == PM_EVENT_ON;
+ return f->is_active;
}
@@ -59,9 +121,10 @@ static inline int is_active(struct usb_interface *f)
extern const char *usbcore_name;
/* usbfs stuff */
+extern struct mutex usbfs_mutex;
extern struct usb_driver usbfs_driver;
-extern struct file_operations usbfs_devices_fops;
-extern struct file_operations usbfs_device_file_operations;
+extern const struct file_operations usbfs_devices_fops;
+extern const struct file_operations usbfs_device_file_operations;
extern void usbfs_conn_disc_event(void);
extern int usbdev_init(void);
@@ -76,7 +139,7 @@ struct dev_state {
struct list_head async_completed;
wait_queue_head_t wait; /* wake up if a request completed */
unsigned int discsignr;
- pid_t disc_pid;
+ struct pid *disc_pid;
uid_t disc_uid, disc_euid;
void __user *disccontext;
unsigned long ifclaimed;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 1a32d96774b4..bbbc82a8336a 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -7,7 +7,7 @@
#
# - Host systems (like PCs) need CONFIG_USB (with "A" jacks).
# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks).
-# - Some systems have both kinds of of controller.
+# - Some systems have both kinds of controllers.
#
# With help from a special transceiver and a "Mini-AB" jack, systems with
# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG).
@@ -26,7 +26,7 @@ config USB_GADGET
you need a low level bus controller driver, and some software
talking to it. Peripheral controllers are often discrete silicon,
or are integrated with the CPU in a microcontroller. The more
- familiar host side controllers have names like like "EHCI", "OHCI",
+ familiar host side controllers have names like "EHCI", "OHCI",
or "UHCI", and are usually integrated into southbridges on PC
motherboards.
@@ -404,6 +404,20 @@ config USB_G_SERIAL
which includes instructions and a "driver info file" needed to
make MS-Windows work with this driver.
+config USB_MIDI_GADGET
+ tristate "MIDI Gadget (EXPERIMENTAL)"
+ depends on SND && EXPERIMENTAL
+ select SND_RAWMIDI
+ help
+ The MIDI Gadget acts as a USB Audio device, with one MIDI
+ input and one MIDI output. These MIDI jacks appear as
+ a sound "card" in the ALSA sound system. Other MIDI
+ connections can then be made on the gadget system, using
+ ALSA's aconnect utility etc.
+
+ Say "y" to link the driver statically, or "m" to build a
+ dynamically linked module called "g_midi".
+
# put drivers that need isochronous transfer support (for audio
# or video class gadget drivers), or specific hardware, here.
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index 5a28e61392ec..e71e086a1cfa 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o
g_zero-objs := zero.o usbstring.o config.o epautoconf.o
g_ether-objs := ether.o usbstring.o config.o epautoconf.o
g_serial-objs := serial.o usbstring.o config.o epautoconf.o
+g_midi-objs := gmidi.o usbstring.o config.o epautoconf.o
gadgetfs-objs := inode.o
g_file_storage-objs := file_storage.o usbstring.o config.o \
epautoconf.o
@@ -28,4 +29,5 @@ obj-$(CONFIG_USB_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o
obj-$(CONFIG_USB_G_SERIAL) += g_serial.o
+obj-$(CONFIG_USB_MIDI_GADGET) += g_midi.o
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index cfebca05ead5..72f3db99ff94 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -247,7 +247,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
return single_open(file, proc_udc_show, PDE(inode)->data);
}
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -1366,7 +1366,7 @@ static void handle_ep0(struct at91_udc *udc)
}
}
-static irqreturn_t at91_udc_irq (int irq, void *_udc, struct pt_regs *r)
+static irqreturn_t at91_udc_irq (int irq, void *_udc)
{
struct at91_udc *udc = _udc;
u32 rescans = 5;
@@ -1552,7 +1552,7 @@ static struct at91_udc controller = {
/* ep6 and ep7 are also reserved (custom silicon might use them) */
};
-static irqreturn_t at91_vbus_irq(int irq, void *_udc, struct pt_regs *r)
+static irqreturn_t at91_vbus_irq(int irq, void *_udc)
{
struct at91_udc *udc = _udc;
unsigned value;
@@ -1658,7 +1658,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
return -ENODEV;
}
- if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) {
+ if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) {
DBG("someone's using UDC memory\n");
return -EBUSY;
}
@@ -1720,7 +1720,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev)
fail1:
device_unregister(&udc->gadget.dev);
fail0:
- release_mem_region(AT91_BASE_UDP, SZ_16K);
+ release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
DBG("%s probe failed, %d\n", driver_name, retval);
return retval;
}
@@ -1742,7 +1742,7 @@ static int __devexit at91udc_remove(struct platform_device *pdev)
free_irq(udc->board.vbus_pin, udc);
free_irq(udc->udp_irq, udc);
device_unregister(&udc->gadget.dev);
- release_mem_region(AT91_BASE_UDP, SZ_16K);
+ release_mem_region(AT91RM9200_BASE_UDP, SZ_16K);
clk_put(udc->iclk);
clk_put(udc->fclk);
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 7d1c22c34957..f1f32d7be5f9 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -816,15 +816,14 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
dum->gadget.dev.driver = &driver->driver;
dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
- if ((retval = driver->bind (&dum->gadget)) != 0) {
- dum->driver = NULL;
- dum->gadget.dev.driver = NULL;
- return retval;
- }
+ if ((retval = driver->bind (&dum->gadget)) != 0)
+ goto err_bind_gadget;
driver->driver.bus = dum->gadget.dev.parent->bus;
- driver_register (&driver->driver);
- device_bind_driver (&dum->gadget.dev);
+ if ((retval = driver_register (&driver->driver)) != 0)
+ goto err_register;
+ if ((retval = device_bind_driver (&dum->gadget.dev)) != 0)
+ goto err_bind_driver;
/* khubd will enumerate this in a while */
spin_lock_irq (&dum->lock);
@@ -834,6 +833,19 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
+
+err_bind_driver:
+ driver_unregister (&driver->driver);
+err_register:
+ driver->unbind (&dum->gadget);
+ spin_lock_irq (&dum->lock);
+ dum->pullup = 0;
+ set_link_state (dum);
+ spin_unlock_irq (&dum->lock);
+err_bind_gadget:
+ dum->driver = NULL;
+ dum->gadget.dev.driver = NULL;
+ return retval;
}
EXPORT_SYMBOL (usb_gadget_register_driver);
@@ -889,11 +901,9 @@ EXPORT_SYMBOL (net2280_set_fifo_mode);
static void
dummy_gadget_release (struct device *dev)
{
-#if 0 /* usb_bus_put isn't EXPORTed! */
struct dummy *dum = gadget_dev_to_dummy (dev);
- usb_bus_put (&dummy_to_hcd (dum)->self);
-#endif
+ usb_put_hcd (dummy_to_hcd (dum));
}
static int dummy_udc_probe (struct platform_device *pdev)
@@ -915,12 +925,12 @@ static int dummy_udc_probe (struct platform_device *pdev)
if (rc < 0)
return rc;
-#if 0 /* usb_bus_get isn't EXPORTed! */
- usb_bus_get (&dummy_to_hcd (dum)->self);
-#endif
+ usb_get_hcd (dummy_to_hcd (dum));
platform_set_drvdata (pdev, dum);
- device_create_file (&dum->gadget.dev, &dev_attr_function);
+ rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
+ if (rc < 0)
+ device_unregister (&dum->gadget.dev);
return rc;
}
@@ -1541,7 +1551,7 @@ return_urb:
ep->already_seen = ep->setup_stage = 0;
spin_unlock (&dum->lock);
- usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL);
+ usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
spin_lock (&dum->lock);
goto restart;
@@ -1868,8 +1878,7 @@ static int dummy_start (struct usb_hcd *hcd)
#endif
/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
- device_create_file (dummy_dev(dum), &dev_attr_urbs);
- return 0;
+ return device_create_file (dummy_dev(dum), &dev_attr_urbs);
}
static void dummy_stop (struct usb_hcd *hcd)
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 30299c620d97..1c17d26d03b8 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -262,7 +262,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
#define DEV_CONFIG_CDC
#endif
-#ifdef CONFIG_USB_GADGET_MUSBHDRC
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
#define DEV_CONFIG_CDC
#endif
@@ -2014,7 +2014,7 @@ rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
static int rndis_control_ack (struct net_device *net)
{
struct eth_dev *dev = netdev_priv(net);
- u32 length;
+ int length;
struct usb_request *resp = dev->stat_req;
/* in case RNDIS calls this after disconnect */
@@ -2230,6 +2230,9 @@ eth_bind (struct usb_gadget *gadget)
if (gadget_is_pxa (gadget)) {
/* pxa doesn't support altsettings */
cdc = 0;
+ } else if (gadget_is_musbhdrc(gadget)) {
+ /* reduce tx dma overhead by avoiding special cases */
+ zlp = 0;
} else if (gadget_is_sh(gadget)) {
/* sh doesn't support multiple interfaces or configs */
cdc = 0;
@@ -2257,7 +2260,7 @@ eth_bind (struct usb_gadget *gadget)
return -ENODEV;
}
snprintf (manufacturer, sizeof manufacturer, "%s %s/%s",
- system_utsname.sysname, system_utsname.release,
+ init_utsname()->sysname, init_utsname()->release,
gadget->name);
/* If there's an RNDIS configuration, that's what Windows wants to
@@ -2564,7 +2567,7 @@ static struct usb_gadget_driver eth_driver = {
.function = (char *) driver_desc,
.bind = eth_bind,
- .unbind = __exit_p(eth_unbind),
+ .unbind = eth_unbind,
.setup = eth_setup,
.disconnect = eth_disconnect,
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 8d7f1e84cd7b..8b975d15538d 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -567,6 +567,7 @@ struct lun {
unsigned int ro : 1;
unsigned int prevent_medium_removal : 1;
unsigned int registered : 1;
+ unsigned int info_valid : 1;
u32 sense_data;
u32 sense_data_info;
@@ -1656,6 +1657,7 @@ static int do_read(struct fsg_dev *fsg)
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
bh->inreq->length = 0;
bh->state = BUF_STATE_FULL;
break;
@@ -1691,6 +1693,7 @@ static int do_read(struct fsg_dev *fsg)
if (nread < amount) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -1785,6 +1788,7 @@ static int do_write(struct fsg_dev *fsg)
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = usb_offset >> 9;
+ curlun->info_valid = 1;
continue;
}
amount -= (amount & 511);
@@ -1827,6 +1831,7 @@ static int do_write(struct fsg_dev *fsg)
if (bh->outreq->status != 0) {
curlun->sense_data = SS_COMMUNICATION_FAILURE;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -1868,6 +1873,7 @@ static int do_write(struct fsg_dev *fsg)
if (nwritten < amount) {
curlun->sense_data = SS_WRITE_ERROR;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -2010,6 +2016,7 @@ static int do_verify(struct fsg_dev *fsg)
curlun->sense_data =
SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
@@ -2036,6 +2043,7 @@ static int do_verify(struct fsg_dev *fsg)
if (nread == 0) {
curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
curlun->sense_data_info = file_offset >> 9;
+ curlun->info_valid = 1;
break;
}
file_offset += nread;
@@ -2079,6 +2087,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
struct lun *curlun = fsg->curlun;
u8 *buf = (u8 *) bh->buf;
u32 sd, sdinfo;
+ int valid;
/*
* From the SCSI-2 spec., section 7.9 (Unit attention condition):
@@ -2106,15 +2115,18 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
fsg->bad_lun_okay = 1;
sd = SS_LOGICAL_UNIT_NOT_SUPPORTED;
sdinfo = 0;
+ valid = 0;
} else {
sd = curlun->sense_data;
sdinfo = curlun->sense_data_info;
+ valid = curlun->info_valid << 7;
curlun->sense_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
}
memset(buf, 0, 18);
- buf[0] = 0x80 | 0x70; // Valid, current error
+ buf[0] = valid | 0x70; // Valid, current error
buf[2] = SK(sd);
put_be32(&buf[3], sdinfo); // Sense information
buf[7] = 18 - 8; // Additional sense length
@@ -2703,6 +2715,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
if (fsg->cmnd[0] != SC_REQUEST_SENSE) {
curlun->sense_data = SS_NO_SENSE;
curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
}
} else {
fsg->curlun = curlun = NULL;
@@ -3332,6 +3345,7 @@ static void handle_exception(struct fsg_dev *fsg)
curlun->sense_data = curlun->unit_attention_data =
SS_NO_SENSE;
curlun->sense_data_info = 0;
+ curlun->info_valid = 0;
}
fsg->state = FSG_STATE_IDLE;
}
@@ -3873,21 +3887,26 @@ static int __init fsg_bind(struct usb_gadget *gadget)
for (i = 0; i < fsg->nluns; ++i) {
curlun = &fsg->luns[i];
curlun->ro = mod_data.ro[i];
+ curlun->dev.release = lun_release;
curlun->dev.parent = &gadget->dev;
curlun->dev.driver = &fsg_driver.driver;
dev_set_drvdata(&curlun->dev, fsg);
snprintf(curlun->dev.bus_id, BUS_ID_SIZE,
"%s-lun%d", gadget->dev.bus_id, i);
- if ((rc = device_register(&curlun->dev)) != 0)
+ if ((rc = device_register(&curlun->dev)) != 0) {
INFO(fsg, "failed to register LUN%d: %d\n", i, rc);
- else {
- curlun->registered = 1;
- curlun->dev.release = lun_release;
- device_create_file(&curlun->dev, &dev_attr_ro);
- device_create_file(&curlun->dev, &dev_attr_file);
- kref_get(&fsg->ref);
+ goto out;
+ }
+ if ((rc = device_create_file(&curlun->dev,
+ &dev_attr_ro)) != 0 ||
+ (rc = device_create_file(&curlun->dev,
+ &dev_attr_file)) != 0) {
+ device_unregister(&curlun->dev);
+ goto out;
}
+ curlun->registered = 1;
+ kref_get(&fsg->ref);
if (mod_data.file[i] && *mod_data.file[i]) {
if ((rc = open_backing_file(curlun,
@@ -3982,7 +4001,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
usb_gadget_set_selfpowered(gadget);
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
- system_utsname.sysname, system_utsname.release,
+ init_utsname()->sysname, init_utsname()->release,
gadget->name);
/* On a real device, serial[] would be loaded from permanent
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
new file mode 100644
index 000000000000..64554acad63f
--- /dev/null
+++ b/drivers/usb/gadget/gmidi.c
@@ -0,0 +1,1336 @@
+/*
+ * gmidi.c -- USB MIDI Gadget Driver
+ *
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Developed for Thumtronics by Grey Innovation
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License ("GPL") version 2, as published by the Free Software Foundation.
+ *
+ * This code is based in part on:
+ *
+ * Gadget Zero driver, Copyright (C) 2003-2004 David Brownell.
+ * USB Audio driver, Copyright (C) 2002 by Takashi Iwai.
+ * USB MIDI driver, Copyright (C) 2002-2005 Clemens Ladisch.
+ *
+ * Refer to the USB Device Class Definition for MIDI Devices:
+ * http://www.usb.org/developers/devclass_docs/midi10.pdf
+ */
+
+#define DEBUG 1
+// #define VERBOSE
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
+
+#include "gadget_chips.h"
+
+MODULE_AUTHOR("Ben Williamson");
+MODULE_LICENSE("GPL v2");
+
+#define DRIVER_VERSION "25 Jul 2006"
+
+static const char shortname[] = "g_midi";
+static const char longname[] = "MIDI Gadget";
+
+static int index = SNDRV_DEFAULT_IDX1;
+static char *id = SNDRV_DEFAULT_STR1;
+
+module_param(index, int, 0444);
+MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
+module_param(id, charp, 0444);
+MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
+
+/* Some systems will want different product identifers published in the
+ * device descriptor, either numbers or strings or both. These string
+ * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
+ */
+
+static ushort idVendor;
+module_param(idVendor, ushort, S_IRUGO);
+MODULE_PARM_DESC(idVendor, "USB Vendor ID");
+
+static ushort idProduct;
+module_param(idProduct, ushort, S_IRUGO);
+MODULE_PARM_DESC(idProduct, "USB Product ID");
+
+static ushort bcdDevice;
+module_param(bcdDevice, ushort, S_IRUGO);
+MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
+
+static char *iManufacturer;
+module_param(iManufacturer, charp, S_IRUGO);
+MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
+
+static char *iProduct;
+module_param(iProduct, charp, S_IRUGO);
+MODULE_PARM_DESC(iProduct, "USB Product string");
+
+static char *iSerialNumber;
+module_param(iSerialNumber, charp, S_IRUGO);
+MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
+
+/*
+ * this version autoconfigures as much as possible,
+ * which is reasonable for most "bulk-only" drivers.
+ */
+static const char *EP_IN_NAME;
+static const char *EP_OUT_NAME;
+
+
+/* big enough to hold our biggest descriptor */
+#define USB_BUFSIZ 256
+
+
+/* This is a gadget, and the IN/OUT naming is from the host's perspective.
+ USB -> OUT endpoint -> rawmidi
+ USB <- IN endpoint <- rawmidi */
+struct gmidi_in_port {
+ struct gmidi_device* dev;
+ int active;
+ uint8_t cable; /* cable number << 4 */
+ uint8_t state;
+#define STATE_UNKNOWN 0
+#define STATE_1PARAM 1
+#define STATE_2PARAM_1 2
+#define STATE_2PARAM_2 3
+#define STATE_SYSEX_0 4
+#define STATE_SYSEX_1 5
+#define STATE_SYSEX_2 6
+ uint8_t data[2];
+};
+
+struct gmidi_device {
+ spinlock_t lock;
+ struct usb_gadget *gadget;
+ struct usb_request *req; /* for control responses */
+ u8 config;
+ struct usb_ep *in_ep, *out_ep;
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_substream *in_substream;
+ struct snd_rawmidi_substream *out_substream;
+
+ /* For the moment we only support one port in
+ each direction, but in_port is kept as a
+ separate struct so we can have more later. */
+ struct gmidi_in_port in_port;
+ unsigned long out_triggered;
+ struct tasklet_struct tasklet;
+};
+
+static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
+
+
+#define xprintk(d,level,fmt,args...) \
+ dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+
+#ifdef DEBUG
+#define DBG(dev,fmt,args...) \
+ xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DBG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDBG DBG
+#else
+#define VDBG(dev,fmt,args...) \
+ do { } while (0)
+#endif /* VERBOSE */
+
+#define ERROR(dev,fmt,args...) \
+ xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+ xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+ xprintk(dev , KERN_INFO , fmt , ## args)
+
+
+static unsigned buflen = 256;
+static unsigned qlen = 32;
+
+module_param(buflen, uint, S_IRUGO);
+module_param(qlen, uint, S_IRUGO);
+
+
+/* Thanks to Grey Innovation for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
+ * Instead: allocate your own, using normal USB-IF procedures.
+ */
+#define DRIVER_VENDOR_NUM 0x17b3 /* Grey Innovation */
+#define DRIVER_PRODUCT_NUM 0x0004 /* Linux-USB "MIDI Gadget" */
+
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full)
+ * configuration descriptors are built on demand.
+ */
+
+#define STRING_MANUFACTURER 25
+#define STRING_PRODUCT 42
+#define STRING_SERIAL 101
+#define STRING_MIDI_GADGET 250
+
+/* We only have the one configuration, it's number 1. */
+#define GMIDI_CONFIG 1
+
+/* We have two interfaces- AudioControl and MIDIStreaming */
+#define GMIDI_AC_INTERFACE 0
+#define GMIDI_MS_INTERFACE 1
+#define GMIDI_NUM_INTERFACES 2
+
+DECLARE_USB_AC_HEADER_DESCRIPTOR(1);
+DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
+DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
+
+/* B.1 Device Descriptor */
+static struct usb_device_descriptor device_desc = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = __constant_cpu_to_le16(0x0200),
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .idVendor = __constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+ .idProduct = __constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+ .iManufacturer = STRING_MANUFACTURER,
+ .iProduct = STRING_PRODUCT,
+ .bNumConfigurations = 1,
+};
+
+/* B.2 Configuration Descriptor */
+static struct usb_config_descriptor config_desc = {
+ .bLength = USB_DT_CONFIG_SIZE,
+ .bDescriptorType = USB_DT_CONFIG,
+ /* compute wTotalLength on the fly */
+ .bNumInterfaces = GMIDI_NUM_INTERFACES,
+ .bConfigurationValue = GMIDI_CONFIG,
+ .iConfiguration = STRING_MIDI_GADGET,
+ /*
+ * FIXME: When embedding this driver in a device,
+ * these need to be set to reflect the actual
+ * power properties of the device. Is it selfpowered?
+ */
+ .bmAttributes = USB_CONFIG_ATT_ONE,
+ .bMaxPower = 1,
+};
+
+/* B.3.1 Standard AC Interface Descriptor */
+static const struct usb_interface_descriptor ac_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = GMIDI_AC_INTERFACE,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+ .iInterface = STRING_MIDI_GADGET,
+};
+
+/* B.3.2 Class-Specific AC Interface Descriptor */
+static const struct usb_ac_header_descriptor_1 ac_header_desc = {
+ .bLength = USB_DT_AC_HEADER_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_HEADER,
+ .bcdADC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = USB_DT_AC_HEADER_SIZE(1),
+ .bInCollection = 1,
+ .baInterfaceNr = {
+ [0] = GMIDI_MS_INTERFACE,
+ }
+};
+
+/* B.4.1 Standard MS Interface Descriptor */
+static const struct usb_interface_descriptor ms_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = GMIDI_MS_INTERFACE,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
+ .iInterface = STRING_MIDI_GADGET,
+};
+
+/* B.4.2 Class-Specific MS Interface Descriptor */
+static const struct usb_ms_header_descriptor ms_header_desc = {
+ .bLength = USB_DT_MS_HEADER_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_HEADER,
+ .bcdMSC = __constant_cpu_to_le16(0x0100),
+ .wTotalLength = USB_DT_MS_HEADER_SIZE
+ + 2*USB_DT_MIDI_IN_SIZE
+ + 2*USB_DT_MIDI_OUT_SIZE(1),
+};
+
+#define JACK_IN_EMB 1
+#define JACK_IN_EXT 2
+#define JACK_OUT_EMB 3
+#define JACK_OUT_EXT 4
+
+/* B.4.3 MIDI IN Jack Descriptors */
+static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
+ .bLength = USB_DT_MIDI_IN_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
+ .bJackType = USB_MS_EMBEDDED,
+ .bJackID = JACK_IN_EMB,
+};
+
+static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = {
+ .bLength = USB_DT_MIDI_IN_SIZE,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_IN_JACK,
+ .bJackType = USB_MS_EXTERNAL,
+ .bJackID = JACK_IN_EXT,
+};
+
+/* B.4.4 MIDI OUT Jack Descriptors */
+static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = {
+ .bLength = USB_DT_MIDI_OUT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
+ .bJackType = USB_MS_EMBEDDED,
+ .bJackID = JACK_OUT_EMB,
+ .bNrInputPins = 1,
+ .pins = {
+ [0] = {
+ .baSourceID = JACK_IN_EXT,
+ .baSourcePin = 1,
+ }
+ }
+};
+
+static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = {
+ .bLength = USB_DT_MIDI_OUT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = USB_MS_MIDI_OUT_JACK,
+ .bJackType = USB_MS_EXTERNAL,
+ .bJackID = JACK_OUT_EXT,
+ .bNrInputPins = 1,
+ .pins = {
+ [0] = {
+ .baSourceID = JACK_IN_EMB,
+ .baSourcePin = 1,
+ }
+ }
+};
+
+/* B.5.1 Standard Bulk OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_out_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.5.2 Class-specific MS Bulk OUT Endpoint Descriptor */
+static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = {
+ .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = USB_MS_GENERAL,
+ .bNumEmbMIDIJack = 1,
+ .baAssocJackID = {
+ [0] = JACK_IN_EMB,
+ }
+};
+
+/* B.6.1 Standard Bulk IN Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_in_desc = {
+ .bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.6.2 Class-specific MS Bulk IN Endpoint Descriptor */
+static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = {
+ .bLength = USB_DT_MS_ENDPOINT_SIZE(1),
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+ .bDescriptorSubtype = USB_MS_GENERAL,
+ .bNumEmbMIDIJack = 1,
+ .baAssocJackID = {
+ [0] = JACK_OUT_EMB,
+ }
+};
+
+static const struct usb_descriptor_header *gmidi_function [] = {
+ (struct usb_descriptor_header *)&ac_interface_desc,
+ (struct usb_descriptor_header *)&ac_header_desc,
+ (struct usb_descriptor_header *)&ms_interface_desc,
+
+ (struct usb_descriptor_header *)&ms_header_desc,
+ (struct usb_descriptor_header *)&jack_in_emb_desc,
+ (struct usb_descriptor_header *)&jack_in_ext_desc,
+ (struct usb_descriptor_header *)&jack_out_emb_desc,
+ (struct usb_descriptor_header *)&jack_out_ext_desc,
+ /* If you add more jacks, update ms_header_desc.wTotalLength */
+
+ (struct usb_descriptor_header *)&bulk_out_desc,
+ (struct usb_descriptor_header *)&ms_out_desc,
+ (struct usb_descriptor_header *)&bulk_in_desc,
+ (struct usb_descriptor_header *)&ms_in_desc,
+ NULL,
+};
+
+static char manufacturer[50];
+static char product_desc[40] = "MIDI Gadget";
+static char serial_number[20];
+
+/* static strings, in UTF-8 */
+static struct usb_string strings [] = {
+ { STRING_MANUFACTURER, manufacturer, },
+ { STRING_PRODUCT, product_desc, },
+ { STRING_SERIAL, serial_number, },
+ { STRING_MIDI_GADGET, longname, },
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab = {
+ .language = 0x0409, /* en-us */
+ .strings = strings,
+};
+
+static int config_buf(struct usb_gadget *gadget,
+ u8 *buf, u8 type, unsigned index)
+{
+ int len;
+
+ /* only one configuration */
+ if (index != 0) {
+ return -EINVAL;
+ }
+ len = usb_gadget_config_buf(&config_desc,
+ buf, USB_BUFSIZ, gmidi_function);
+ if (len < 0) {
+ return len;
+ }
+ ((struct usb_config_descriptor *)buf)->bDescriptorType = type;
+ return len;
+}
+
+static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
+{
+ struct usb_request *req;
+
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (req) {
+ req->length = length;
+ req->buf = kmalloc(length, GFP_ATOMIC);
+ if (!req->buf) {
+ usb_ep_free_request(ep, req);
+ req = NULL;
+ }
+ }
+ return req;
+}
+
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+ kfree(req->buf);
+ usb_ep_free_request(ep, req);
+}
+
+static const uint8_t gmidi_cin_length[] = {
+ 0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
+};
+
+/*
+ * Receives a chunk of MIDI data.
+ */
+static void gmidi_read_data(struct usb_ep *ep, int cable,
+ uint8_t* data, int length)
+{
+ struct gmidi_device *dev = ep->driver_data;
+ /* cable is ignored, because for now we only have one. */
+
+ if (!dev->out_substream) {
+ /* Nobody is listening - throw it on the floor. */
+ return;
+ }
+ if (!test_bit(dev->out_substream->number, &dev->out_triggered)) {
+ return;
+ }
+ snd_rawmidi_receive(dev->out_substream, data, length);
+}
+
+static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
+{
+ unsigned i;
+ u8 *buf = req->buf;
+
+ for (i = 0; i + 3 < req->actual; i += 4) {
+ if (buf[i] != 0) {
+ int cable = buf[i] >> 4;
+ int length = gmidi_cin_length[buf[i] & 0x0f];
+ gmidi_read_data(ep, cable, &buf[i + 1], length);
+ }
+ }
+}
+
+static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ struct gmidi_device *dev = ep->driver_data;
+ int status = req->status;
+
+ switch (status) {
+ case 0: /* normal completion */
+ if (ep == dev->out_ep) {
+ /* we received stuff.
+ req is queued again, below */
+ gmidi_handle_out_data(ep, req);
+ } else if (ep == dev->in_ep) {
+ /* our transmit completed.
+ see if there's more to go.
+ gmidi_transmit eats req, don't queue it again. */
+ gmidi_transmit(dev, req);
+ return;
+ }
+ break;
+
+ /* this endpoint is normally active while we're configured */
+ case -ECONNABORTED: /* hardware forced ep reset */
+ case -ECONNRESET: /* request dequeued */
+ case -ESHUTDOWN: /* disconnect from host */
+ VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
+ req->actual, req->length);
+ if (ep == dev->out_ep) {
+ gmidi_handle_out_data(ep, req);
+ }
+ free_ep_req(ep, req);
+ return;
+
+ case -EOVERFLOW: /* buffer overrun on read means that
+ * we didn't provide a big enough
+ * buffer.
+ */
+ default:
+ DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
+ status, req->actual, req->length);
+ break;
+ case -EREMOTEIO: /* short read */
+ break;
+ }
+
+ status = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (status) {
+ ERROR(dev, "kill %s: resubmit %d bytes --> %d\n",
+ ep->name, req->length, status);
+ usb_ep_set_halt(ep);
+ /* FIXME recover later ... somehow */
+ }
+}
+
+static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
+{
+ int err = 0;
+ struct usb_request *req;
+ struct usb_ep* ep;
+ unsigned i;
+
+ err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
+ if (err) {
+ ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
+ goto fail;
+ }
+ dev->in_ep->driver_data = dev;
+
+ err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
+ if (err) {
+ ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
+ goto fail;
+ }
+ dev->out_ep->driver_data = dev;
+
+ /* allocate a bunch of read buffers and queue them all at once. */
+ ep = dev->out_ep;
+ for (i = 0; i < qlen && err == 0; i++) {
+ req = alloc_ep_req(ep, buflen);
+ if (req) {
+ req->complete = gmidi_complete;
+ err = usb_ep_queue(ep, req, GFP_ATOMIC);
+ if (err) {
+ DBG(dev, "%s queue req: %d\n", ep->name, err);
+ }
+ } else {
+ err = -ENOMEM;
+ }
+ }
+fail:
+ /* caller is responsible for cleanup on error */
+ return err;
+}
+
+
+static void gmidi_reset_config(struct gmidi_device *dev)
+{
+ if (dev->config == 0) {
+ return;
+ }
+
+ DBG(dev, "reset config\n");
+
+ /* just disable endpoints, forcing completion of pending i/o.
+ * all our completion handlers free their requests in this case.
+ */
+ usb_ep_disable(dev->in_ep);
+ usb_ep_disable(dev->out_ep);
+ dev->config = 0;
+}
+
+/* change our operational config. this code must agree with the code
+ * that returns config descriptors, and altsetting code.
+ *
+ * it's also responsible for power management interactions. some
+ * configurations might not work with our current power sources.
+ *
+ * note that some device controller hardware will constrain what this
+ * code can do, perhaps by disallowing more than one configuration or
+ * by limiting configuration choices (like the pxa2xx).
+ */
+static int
+gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
+{
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+#if 0
+ /* FIXME */
+ /* Hacking this bit out fixes a bug where on receipt of two
+ USB_REQ_SET_CONFIGURATION messages, we end up with no
+ buffered OUT requests waiting for data. This is clearly
+ hiding a bug elsewhere, because if the config didn't
+ change then we really shouldn't do anything. */
+ /* Having said that, when we do "change" from config 1
+ to config 1, we at least gmidi_reset_config() which
+ clears out any requests on endpoints, so it's not like
+ we leak or anything. */
+ if (number == dev->config) {
+ return 0;
+ }
+#endif
+
+ if (gadget_is_sa1100(gadget) && dev->config) {
+ /* tx fifo is full, but we can't clear it...*/
+ INFO(dev, "can't change configurations\n");
+ return -ESPIPE;
+ }
+ gmidi_reset_config(dev);
+
+ switch (number) {
+ case GMIDI_CONFIG:
+ result = set_gmidi_config(dev, gfp_flags);
+ break;
+ default:
+ result = -EINVAL;
+ /* FALL THROUGH */
+ case 0:
+ return result;
+ }
+
+ if (!result && (!dev->in_ep || !dev->out_ep)) {
+ result = -ENODEV;
+ }
+ if (result) {
+ gmidi_reset_config(dev);
+ } else {
+ char *speed;
+
+ switch (gadget->speed) {
+ case USB_SPEED_LOW: speed = "low"; break;
+ case USB_SPEED_FULL: speed = "full"; break;
+ case USB_SPEED_HIGH: speed = "high"; break;
+ default: speed = "?"; break;
+ }
+
+ dev->config = number;
+ INFO(dev, "%s speed\n", speed);
+ }
+ return result;
+}
+
+
+static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ if (req->status || req->actual != req->length) {
+ DBG((struct gmidi_device *) ep->driver_data,
+ "setup complete --> %d, %d/%d\n",
+ req->status, req->actual, req->length);
+ }
+}
+
+/*
+ * The setup() callback implements all the ep0 functionality that's
+ * not handled lower down, in hardware or the hardware driver (like
+ * device and endpoint feature flags, and their status). It's all
+ * housekeeping for the gadget function we're implementing. Most of
+ * the work is in config-specific setup.
+ */
+static int gmidi_setup(struct usb_gadget *gadget,
+ const struct usb_ctrlrequest *ctrl)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+ struct usb_request *req = dev->req;
+ int value = -EOPNOTSUPP;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
+
+ /* usually this stores reply data in the pre-allocated ep0 buffer,
+ * but config change events will reconfigure hardware.
+ */
+ req->zero = 0;
+ switch (ctrl->bRequest) {
+
+ case USB_REQ_GET_DESCRIPTOR:
+ if (ctrl->bRequestType != USB_DIR_IN) {
+ goto unknown;
+ }
+ switch (w_value >> 8) {
+
+ case USB_DT_DEVICE:
+ value = min(w_length, (u16) sizeof(device_desc));
+ memcpy(req->buf, &device_desc, value);
+ break;
+ case USB_DT_CONFIG:
+ value = config_buf(gadget, req->buf,
+ w_value >> 8,
+ w_value & 0xff);
+ if (value >= 0) {
+ value = min(w_length, (u16)value);
+ }
+ break;
+
+ case USB_DT_STRING:
+ /* wIndex == language code.
+ * this driver only handles one language, you can
+ * add string tables for other languages, using
+ * any UTF-8 characters
+ */
+ value = usb_gadget_get_string(&stringtab,
+ w_value & 0xff, req->buf);
+ if (value >= 0) {
+ value = min(w_length, (u16)value);
+ }
+ break;
+ }
+ break;
+
+ /* currently two configs, two speeds */
+ case USB_REQ_SET_CONFIGURATION:
+ if (ctrl->bRequestType != 0) {
+ goto unknown;
+ }
+ if (gadget->a_hnp_support) {
+ DBG(dev, "HNP available\n");
+ } else if (gadget->a_alt_hnp_support) {
+ DBG(dev, "HNP needs a different root port\n");
+ } else {
+ VDBG(dev, "HNP inactive\n");
+ }
+ spin_lock(&dev->lock);
+ value = gmidi_set_config(dev, w_value, GFP_ATOMIC);
+ spin_unlock(&dev->lock);
+ break;
+ case USB_REQ_GET_CONFIGURATION:
+ if (ctrl->bRequestType != USB_DIR_IN) {
+ goto unknown;
+ }
+ *(u8 *)req->buf = dev->config;
+ value = min(w_length, (u16)1);
+ break;
+
+ /* until we add altsetting support, or other interfaces,
+ * only 0/0 are possible. pxa2xx only supports 0/0 (poorly)
+ * and already killed pending endpoint I/O.
+ */
+ case USB_REQ_SET_INTERFACE:
+ if (ctrl->bRequestType != USB_RECIP_INTERFACE) {
+ goto unknown;
+ }
+ spin_lock(&dev->lock);
+ if (dev->config && w_index < GMIDI_NUM_INTERFACES
+ && w_value == 0)
+ {
+ u8 config = dev->config;
+
+ /* resets interface configuration, forgets about
+ * previous transaction state (queued bufs, etc)
+ * and re-inits endpoint state (toggle etc)
+ * no response queued, just zero status == success.
+ * if we had more than one interface we couldn't
+ * use this "reset the config" shortcut.
+ */
+ gmidi_reset_config(dev);
+ gmidi_set_config(dev, config, GFP_ATOMIC);
+ value = 0;
+ }
+ spin_unlock(&dev->lock);
+ break;
+ case USB_REQ_GET_INTERFACE:
+ if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {
+ goto unknown;
+ }
+ if (!dev->config) {
+ break;
+ }
+ if (w_index >= GMIDI_NUM_INTERFACES) {
+ value = -EDOM;
+ break;
+ }
+ *(u8 *)req->buf = 0;
+ value = min(w_length, (u16)1);
+ break;
+
+ default:
+unknown:
+ VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
+ ctrl->bRequestType, ctrl->bRequest,
+ w_value, w_index, w_length);
+ }
+
+ /* respond with data transfer before status phase? */
+ if (value >= 0) {
+ req->length = value;
+ req->zero = value < w_length;
+ value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ DBG(dev, "ep_queue --> %d\n", value);
+ req->status = 0;
+ gmidi_setup_complete(gadget->ep0, req);
+ }
+ }
+
+ /* device either stalls (value < 0) or reports success */
+ return value;
+}
+
+static void gmidi_disconnect(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->lock, flags);
+ gmidi_reset_config(dev);
+
+ /* a more significant application might have some non-usb
+ * activities to quiesce here, saving resources like power
+ * or pushing the notification up a network stack.
+ */
+ spin_unlock_irqrestore(&dev->lock, flags);
+
+ /* next we may get setup() calls to enumerate new connections;
+ * or an unbind() during shutdown (including removing module).
+ */
+}
+
+static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+ struct snd_card* card;
+
+ DBG(dev, "unbind\n");
+
+ card = dev->card;
+ dev->card = NULL;
+ if (card) {
+ snd_card_free(card);
+ }
+
+ /* we've already been disconnected ... no i/o is active */
+ if (dev->req) {
+ dev->req->length = USB_BUFSIZ;
+ free_ep_req(gadget->ep0, dev->req);
+ }
+ kfree(dev);
+ set_gadget_data(gadget, NULL);
+}
+
+static int gmidi_snd_free(struct snd_device *device)
+{
+ return 0;
+}
+
+static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+ uint8_t p1, uint8_t p2, uint8_t p3)
+{
+ unsigned length = req->length;
+
+ uint8_t* buf = (uint8_t*)req->buf + length;
+ buf[0] = p0;
+ buf[1] = p1;
+ buf[2] = p2;
+ buf[3] = p3;
+ req->length = length + 4;
+}
+
+/*
+ * Converts MIDI commands to USB MIDI packets.
+ */
+static void gmidi_transmit_byte(struct usb_request* req,
+ struct gmidi_in_port* port, uint8_t b)
+{
+ uint8_t p0 = port->cable;
+
+ if (b >= 0xf8) {
+ gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
+ } else if (b >= 0xf0) {
+ switch (b) {
+ case 0xf0:
+ port->data[0] = b;
+ port->state = STATE_SYSEX_1;
+ break;
+ case 0xf1:
+ case 0xf3:
+ port->data[0] = b;
+ port->state = STATE_1PARAM;
+ break;
+ case 0xf2:
+ port->data[0] = b;
+ port->state = STATE_2PARAM_1;
+ break;
+ case 0xf4:
+ case 0xf5:
+ port->state = STATE_UNKNOWN;
+ break;
+ case 0xf6:
+ gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
+ port->state = STATE_UNKNOWN;
+ break;
+ case 0xf7:
+ switch (port->state) {
+ case STATE_SYSEX_0:
+ gmidi_transmit_packet(req,
+ p0 | 0x05, 0xf7, 0, 0);
+ break;
+ case STATE_SYSEX_1:
+ gmidi_transmit_packet(req,
+ p0 | 0x06, port->data[0], 0xf7, 0);
+ break;
+ case STATE_SYSEX_2:
+ gmidi_transmit_packet(req,
+ p0 | 0x07, port->data[0],
+ port->data[1], 0xf7);
+ break;
+ }
+ port->state = STATE_UNKNOWN;
+ break;
+ }
+ } else if (b >= 0x80) {
+ port->data[0] = b;
+ if (b >= 0xc0 && b <= 0xdf)
+ port->state = STATE_1PARAM;
+ else
+ port->state = STATE_2PARAM_1;
+ } else { /* b < 0x80 */
+ switch (port->state) {
+ case STATE_1PARAM:
+ if (port->data[0] < 0xf0) {
+ p0 |= port->data[0] >> 4;
+ } else {
+ p0 |= 0x02;
+ port->state = STATE_UNKNOWN;
+ }
+ gmidi_transmit_packet(req, p0, port->data[0], b, 0);
+ break;
+ case STATE_2PARAM_1:
+ port->data[1] = b;
+ port->state = STATE_2PARAM_2;
+ break;
+ case STATE_2PARAM_2:
+ if (port->data[0] < 0xf0) {
+ p0 |= port->data[0] >> 4;
+ port->state = STATE_2PARAM_1;
+ } else {
+ p0 |= 0x03;
+ port->state = STATE_UNKNOWN;
+ }
+ gmidi_transmit_packet(req,
+ p0, port->data[0], port->data[1], b);
+ break;
+ case STATE_SYSEX_0:
+ port->data[0] = b;
+ port->state = STATE_SYSEX_1;
+ break;
+ case STATE_SYSEX_1:
+ port->data[1] = b;
+ port->state = STATE_SYSEX_2;
+ break;
+ case STATE_SYSEX_2:
+ gmidi_transmit_packet(req,
+ p0 | 0x04, port->data[0], port->data[1], b);
+ port->state = STATE_SYSEX_0;
+ break;
+ }
+ }
+}
+
+static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+{
+ struct usb_ep* ep = dev->in_ep;
+ struct gmidi_in_port* port = &dev->in_port;
+
+ if (!ep) {
+ return;
+ }
+ if (!req) {
+ req = alloc_ep_req(ep, buflen);
+ }
+ if (!req) {
+ ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n");
+ return;
+ }
+ req->length = 0;
+ req->complete = gmidi_complete;
+
+ if (port->active) {
+ while (req->length + 3 < buflen) {
+ uint8_t b;
+ if (snd_rawmidi_transmit(dev->in_substream, &b, 1)
+ != 1)
+ {
+ port->active = 0;
+ break;
+ }
+ gmidi_transmit_byte(req, port, b);
+ }
+ }
+ if (req->length > 0) {
+ usb_ep_queue(ep, req, GFP_ATOMIC);
+ } else {
+ free_ep_req(ep, req);
+ }
+}
+
+static void gmidi_in_tasklet(unsigned long data)
+{
+ struct gmidi_device* dev = (struct gmidi_device*)data;
+
+ gmidi_transmit(dev, NULL);
+}
+
+static int gmidi_in_open(struct snd_rawmidi_substream *substream)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_in_open\n");
+ dev->in_substream = substream;
+ dev->in_port.state = STATE_UNKNOWN;
+ return 0;
+}
+
+static int gmidi_in_close(struct snd_rawmidi_substream *substream)
+{
+ VDBG(dev, "gmidi_in_close\n");
+ return 0;
+}
+
+static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_in_trigger %d\n", up);
+ dev->in_port.active = up;
+ if (up) {
+ tasklet_hi_schedule(&dev->tasklet);
+ }
+}
+
+static int gmidi_out_open(struct snd_rawmidi_substream *substream)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_out_open\n");
+ dev->out_substream = substream;
+ return 0;
+}
+
+static int gmidi_out_close(struct snd_rawmidi_substream *substream)
+{
+ VDBG(dev, "gmidi_out_close\n");
+ return 0;
+}
+
+static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+ struct gmidi_device* dev = substream->rmidi->private_data;
+
+ VDBG(dev, "gmidi_out_trigger %d\n", up);
+ if (up) {
+ set_bit(substream->number, &dev->out_triggered);
+ } else {
+ clear_bit(substream->number, &dev->out_triggered);
+ }
+}
+
+static struct snd_rawmidi_ops gmidi_in_ops = {
+ .open = gmidi_in_open,
+ .close = gmidi_in_close,
+ .trigger = gmidi_in_trigger,
+};
+
+static struct snd_rawmidi_ops gmidi_out_ops = {
+ .open = gmidi_out_open,
+ .close = gmidi_out_close,
+ .trigger = gmidi_out_trigger
+};
+
+/* register as a sound "card" */
+static int gmidi_register_card(struct gmidi_device *dev)
+{
+ struct snd_card *card;
+ struct snd_rawmidi *rmidi;
+ int err;
+ int out_ports = 1;
+ int in_ports = 1;
+ static struct snd_device_ops ops = {
+ .dev_free = gmidi_snd_free,
+ };
+
+ card = snd_card_new(index, id, THIS_MODULE, 0);
+ if (!card) {
+ ERROR(dev, "snd_card_new failed\n");
+ err = -ENOMEM;
+ goto fail;
+ }
+ dev->card = card;
+
+ err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops);
+ if (err < 0) {
+ ERROR(dev, "snd_device_new failed: error %d\n", err);
+ goto fail;
+ }
+
+ strcpy(card->driver, longname);
+ strcpy(card->longname, longname);
+ strcpy(card->shortname, shortname);
+
+ /* Set up rawmidi */
+ dev->in_port.dev = dev;
+ dev->in_port.active = 0;
+ snd_component_add(card, "MIDI");
+ err = snd_rawmidi_new(card, "USB MIDI Gadget", 0,
+ out_ports, in_ports, &rmidi);
+ if (err < 0) {
+ ERROR(dev, "snd_rawmidi_new failed: error %d\n", err);
+ goto fail;
+ }
+ dev->rmidi = rmidi;
+ strcpy(rmidi->name, card->shortname);
+ rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+ SNDRV_RAWMIDI_INFO_INPUT |
+ SNDRV_RAWMIDI_INFO_DUPLEX;
+ rmidi->private_data = dev;
+
+ /* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
+ It's an upside-down world being a gadget. */
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
+
+ snd_card_set_dev(card, &dev->gadget->dev);
+
+ /* register it - we're ready to go */
+ err = snd_card_register(card);
+ if (err < 0) {
+ ERROR(dev, "snd_card_register failed\n");
+ goto fail;
+ }
+
+ VDBG(dev, "gmidi_register_card finished ok\n");
+ return 0;
+
+fail:
+ if (dev->card) {
+ snd_card_free(dev->card);
+ dev->card = NULL;
+ }
+ return err;
+}
+
+/*
+ * Creates an output endpoint, and initializes output ports.
+ */
+static int __devinit gmidi_bind(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev;
+ struct usb_ep *in_ep, *out_ep;
+ int gcnum, err = 0;
+
+ /* support optional vendor/distro customization */
+ if (idVendor) {
+ if (!idProduct) {
+ printk(KERN_ERR "idVendor needs idProduct!\n");
+ return -ENODEV;
+ }
+ device_desc.idVendor = cpu_to_le16(idVendor);
+ device_desc.idProduct = cpu_to_le16(idProduct);
+ if (bcdDevice) {
+ device_desc.bcdDevice = cpu_to_le16(bcdDevice);
+ }
+ }
+ if (iManufacturer) {
+ strlcpy(manufacturer, iManufacturer, sizeof(manufacturer));
+ } else {
+ snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+ init_utsname()->sysname, init_utsname()->release,
+ gadget->name);
+ }
+ if (iProduct) {
+ strlcpy(product_desc, iProduct, sizeof(product_desc));
+ }
+ if (iSerialNumber) {
+ device_desc.iSerialNumber = STRING_SERIAL,
+ strlcpy(serial_number, iSerialNumber, sizeof(serial_number));
+ }
+
+ /* Bulk-only drivers like this one SHOULD be able to
+ * autoconfigure on any sane usb controller driver,
+ * but there may also be important quirks to address.
+ */
+ usb_ep_autoconfig_reset(gadget);
+ in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
+ if (!in_ep) {
+autoconf_fail:
+ printk(KERN_ERR "%s: can't autoconfigure on %s\n",
+ shortname, gadget->name);
+ return -ENODEV;
+ }
+ EP_IN_NAME = in_ep->name;
+ in_ep->driver_data = in_ep; /* claim */
+
+ out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc);
+ if (!out_ep) {
+ goto autoconf_fail;
+ }
+ EP_OUT_NAME = out_ep->name;
+ out_ep->driver_data = out_ep; /* claim */
+
+ gcnum = usb_gadget_controller_number(gadget);
+ if (gcnum >= 0) {
+ device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
+ } else {
+ /* gmidi is so simple (no altsettings) that
+ * it SHOULD NOT have problems with bulk-capable hardware.
+ * so warn about unrecognized controllers, don't panic.
+ */
+ printk(KERN_WARNING "%s: controller '%s' not recognized\n",
+ shortname, gadget->name);
+ device_desc.bcdDevice = __constant_cpu_to_le16(0x9999);
+ }
+
+
+ /* ok, we made sense of the hardware ... */
+ dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
+ if (!dev) {
+ return -ENOMEM;
+ }
+ spin_lock_init(&dev->lock);
+ dev->gadget = gadget;
+ dev->in_ep = in_ep;
+ dev->out_ep = out_ep;
+ set_gadget_data(gadget, dev);
+ tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
+
+ /* preallocate control response and buffer */
+ dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+ if (!dev->req) {
+ err = -ENOMEM;
+ goto fail;
+ }
+ dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ,
+ &dev->req->dma, GFP_KERNEL);
+ if (!dev->req->buf) {
+ err = -ENOMEM;
+ goto fail;
+ }
+
+ dev->req->complete = gmidi_setup_complete;
+
+ device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
+
+ gadget->ep0->driver_data = dev;
+
+ INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
+ INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
+ EP_OUT_NAME, EP_IN_NAME);
+
+ /* register as an ALSA sound card */
+ err = gmidi_register_card(dev);
+ if (err < 0) {
+ goto fail;
+ }
+
+ VDBG(dev, "gmidi_bind finished ok\n");
+ return 0;
+
+fail:
+ gmidi_unbind(gadget);
+ return err;
+}
+
+
+static void gmidi_suspend(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+
+ if (gadget->speed == USB_SPEED_UNKNOWN) {
+ return;
+ }
+
+ DBG(dev, "suspend\n");
+}
+
+static void gmidi_resume(struct usb_gadget *gadget)
+{
+ struct gmidi_device *dev = get_gadget_data(gadget);
+
+ DBG(dev, "resume\n");
+}
+
+
+static struct usb_gadget_driver gmidi_driver = {
+ .speed = USB_SPEED_FULL,
+ .function = (char *)longname,
+ .bind = gmidi_bind,
+ .unbind = __exit_p(gmidi_unbind),
+
+ .setup = gmidi_setup,
+ .disconnect = gmidi_disconnect,
+
+ .suspend = gmidi_suspend,
+ .resume = gmidi_resume,
+
+ .driver = {
+ .name = (char *)shortname,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init gmidi_init(void)
+{
+ return usb_gadget_register_driver(&gmidi_driver);
+}
+module_init(gmidi_init);
+
+static void __exit gmidi_cleanup(void)
+{
+ usb_gadget_unregister_driver(&gmidi_driver);
+}
+module_exit(gmidi_cleanup);
+
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 7cf2999e8616..a3076da3f4eb 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -1628,7 +1628,7 @@ stall:
handled = 1; \
}
-static irqreturn_t goku_irq(int irq, void *_dev, struct pt_regs *r)
+static irqreturn_t goku_irq(int irq, void *_dev)
{
struct goku_udc *dev = _dev;
struct goku_udc_regs __iomem *regs = dev->regs;
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3bdc5e3ba234..86924f9cdd7e 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -32,6 +32,7 @@
#include <linux/compiler.h>
#include <asm/uaccess.h>
#include <linux/slab.h>
+#include <linux/poll.h>
#include <linux/device.h>
#include <linux/moduleparam.h>
@@ -222,7 +223,6 @@ static void put_ep (struct ep_data *data)
/* needs no more cleanup */
BUG_ON (!list_empty (&data->epfiles));
BUG_ON (waitqueue_active (&data->wait));
- BUG_ON (down_trylock (&data->lock) != 0);
kfree (data);
}
@@ -342,7 +342,7 @@ fail:
static ssize_t
ep_io (struct ep_data *epdata, void *buf, unsigned len)
{
- DECLARE_COMPLETION (done);
+ DECLARE_COMPLETION_ONSTACK (done);
int value;
spin_lock_irq (&epdata->dev->lock);
@@ -477,6 +477,10 @@ static int
ep_release (struct inode *inode, struct file *fd)
{
struct ep_data *data = fd->private_data;
+ int value;
+
+ if ((value = down_interruptible(&data->lock)) < 0)
+ return value;
/* clean up if this can be reopened */
if (data->state != STATE_EP_UNBOUND) {
@@ -485,6 +489,7 @@ ep_release (struct inode *inode, struct file *fd)
data->hs_desc.bDescriptorType = 0;
usb_ep_disable(data->ep);
}
+ up (&data->lock);
put_ep (data);
return 0;
}
@@ -528,7 +533,8 @@ struct kiocb_priv {
struct usb_request *req;
struct ep_data *epdata;
void *buf;
- char __user *ubuf; /* NULL for writes */
+ const struct iovec *iv;
+ unsigned long nr_segs;
unsigned actual;
};
@@ -556,17 +562,32 @@ static int ep_aio_cancel(struct kiocb *iocb, struct io_event *e)
static ssize_t ep_aio_read_retry(struct kiocb *iocb)
{
struct kiocb_priv *priv = iocb->private;
- ssize_t status = priv->actual;
-
- /* we "retry" to get the right mm context for this: */
- status = copy_to_user(priv->ubuf, priv->buf, priv->actual);
- if (unlikely(0 != status))
- status = -EFAULT;
- else
- status = priv->actual;
- kfree(priv->buf);
- kfree(priv);
- return status;
+ ssize_t len, total;
+ int i;
+
+ /* we "retry" to get the right mm context for this: */
+
+ /* copy stuff into user buffers */
+ total = priv->actual;
+ len = 0;
+ for (i=0; i < priv->nr_segs; i++) {
+ ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+ if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+ if (len == 0)
+ len = -EFAULT;
+ break;
+ }
+
+ total -= this;
+ len += this;
+ if (total == 0)
+ break;
+ }
+ kfree(priv->buf);
+ kfree(priv);
+ aio_put_req(iocb);
+ return len;
}
static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -579,7 +600,7 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
spin_lock(&epdata->dev->lock);
priv->req = NULL;
priv->epdata = NULL;
- if (priv->ubuf == NULL
+ if (priv->iv == NULL
|| unlikely(req->actual == 0)
|| unlikely(kiocbIsCancelled(iocb))) {
kfree(req->buf);
@@ -614,7 +635,8 @@ ep_aio_rwtail(
char *buf,
size_t len,
struct ep_data *epdata,
- char __user *ubuf
+ const struct iovec *iv,
+ unsigned long nr_segs
)
{
struct kiocb_priv *priv;
@@ -629,7 +651,8 @@ fail:
return value;
}
iocb->private = priv;
- priv->ubuf = ubuf;
+ priv->iv = iv;
+ priv->nr_segs = nr_segs;
value = get_ready_ep(iocb->ki_filp->f_flags, epdata);
if (unlikely(value < 0)) {
@@ -669,47 +692,59 @@ fail:
kfree(priv);
put_ep(epdata);
} else
- value = (ubuf ? -EIOCBRETRY : -EIOCBQUEUED);
+ value = (iv ? -EIOCBRETRY : -EIOCBQUEUED);
return value;
}
static ssize_t
-ep_aio_read(struct kiocb *iocb, char __user *ubuf, size_t len, loff_t o)
+ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t o)
{
struct ep_data *epdata = iocb->ki_filp->private_data;
char *buf;
if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
return -EINVAL;
- buf = kmalloc(len, GFP_KERNEL);
+
+ buf = kmalloc(iocb->ki_left, GFP_KERNEL);
if (unlikely(!buf))
return -ENOMEM;
+
iocb->ki_retry = ep_aio_read_retry;
- return ep_aio_rwtail(iocb, buf, len, epdata, ubuf);
+ return ep_aio_rwtail(iocb, buf, iocb->ki_left, epdata, iov, nr_segs);
}
static ssize_t
-ep_aio_write(struct kiocb *iocb, const char __user *ubuf, size_t len, loff_t o)
+ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t o)
{
struct ep_data *epdata = iocb->ki_filp->private_data;
char *buf;
+ size_t len = 0;
+ int i = 0;
if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
return -EINVAL;
- buf = kmalloc(len, GFP_KERNEL);
+
+ buf = kmalloc(iocb->ki_left, GFP_KERNEL);
if (unlikely(!buf))
return -ENOMEM;
- if (unlikely(copy_from_user(buf, ubuf, len) != 0)) {
- kfree(buf);
- return -EFAULT;
+
+ for (i=0; i < nr_segs; i++) {
+ if (unlikely(copy_from_user(&buf[len], iov[i].iov_base,
+ iov[i].iov_len) != 0)) {
+ kfree(buf);
+ return -EFAULT;
+ }
+ len += iov[i].iov_len;
}
- return ep_aio_rwtail(iocb, buf, len, epdata, NULL);
+ return ep_aio_rwtail(iocb, buf, len, epdata, NULL, 0);
}
/*----------------------------------------------------------------------*/
/* used after endpoint configuration */
-static struct file_operations ep_io_operations = {
+static const struct file_operations ep_io_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -741,7 +776,7 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
struct ep_data *data = fd->private_data;
struct usb_ep *ep;
u32 tag;
- int value;
+ int value, length = len;
if ((value = down_interruptible (&data->lock)) < 0)
return value;
@@ -792,7 +827,6 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
goto fail0;
}
}
- value = len;
spin_lock_irq (&data->dev->lock);
if (data->dev->state == STATE_DEV_UNBOUND) {
@@ -822,8 +856,10 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
data->name);
data->state = STATE_EP_DEFER_ENABLE;
}
- if (value == 0)
+ if (value == 0) {
fd->f_op = &ep_io_operations;
+ value = length;
+ }
gone:
spin_unlock_irq (&data->dev->lock);
if (value < 0) {
@@ -844,7 +880,7 @@ fail1:
static int
ep_open (struct inode *inode, struct file *fd)
{
- struct ep_data *data = inode->u.generic_ip;
+ struct ep_data *data = inode->i_private;
int value = -EBUSY;
if (down_interruptible (&data->lock) != 0)
@@ -867,7 +903,7 @@ ep_open (struct inode *inode, struct file *fd)
}
/* used before endpoint configuration */
-static struct file_operations ep_config_operations = {
+static const struct file_operations ep_config_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -1009,7 +1045,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
else {
len = min (len, (size_t)dev->req->actual);
// FIXME don't call this with the spinlock held ...
- if (copy_to_user (buf, &dev->req->buf, len))
+ if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT;
clean_req (dev->gadget->ep0, dev->req);
/* NOTE userspace can't yet choose to stall */
@@ -1229,6 +1265,35 @@ dev_release (struct inode *inode, struct file *fd)
return 0;
}
+static unsigned int
+ep0_poll (struct file *fd, poll_table *wait)
+{
+ struct dev_data *dev = fd->private_data;
+ int mask = 0;
+
+ poll_wait(fd, &dev->wait, wait);
+
+ spin_lock_irq (&dev->lock);
+
+ /* report fd mode change before acting on it */
+ if (dev->setup_abort) {
+ dev->setup_abort = 0;
+ mask = POLLHUP;
+ goto out;
+ }
+
+ if (dev->state == STATE_SETUP) {
+ if (dev->setup_in || dev->setup_can_stall)
+ mask = POLLOUT;
+ } else {
+ if (dev->ev_next != 0)
+ mask = POLLIN;
+ }
+out:
+ spin_unlock_irq(&dev->lock);
+ return mask;
+}
+
static int dev_ioctl (struct inode *inode, struct file *fd,
unsigned code, unsigned long value)
{
@@ -1241,14 +1306,14 @@ static int dev_ioctl (struct inode *inode, struct file *fd,
}
/* used after device configuration */
-static struct file_operations ep0_io_operations = {
+static const struct file_operations ep0_io_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = ep0_read,
.write = ep0_write,
.fasync = ep0_fasync,
- // .poll = ep0_poll,
+ .poll = ep0_poll,
.ioctl = dev_ioctl,
.release = dev_release,
};
@@ -1696,16 +1761,17 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
{
struct dev_data *dev = get_gadget_data (gadget);
+ spin_lock (&dev->lock);
if (dev->state == STATE_UNCONNECTED) {
DBG (dev, "already unconnected\n");
- return;
+ goto exit;
}
dev->state = STATE_UNCONNECTED;
INFO (dev, "disconnected\n");
- spin_lock (&dev->lock);
next_event (dev, GADGETFS_DISCONNECT);
ep0_readable (dev);
+exit:
spin_unlock (&dev->lock);
}
@@ -1909,7 +1975,7 @@ fail:
static int
dev_open (struct inode *inode, struct file *fd)
{
- struct dev_data *dev = inode->u.generic_ip;
+ struct dev_data *dev = inode->i_private;
int value = -EBUSY;
if (dev->state == STATE_DEV_DISABLED) {
@@ -1922,7 +1988,7 @@ dev_open (struct inode *inode, struct file *fd)
return value;
}
-static struct file_operations dev_init_operations = {
+static const struct file_operations dev_init_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
@@ -1966,11 +2032,10 @@ gadgetfs_make_inode (struct super_block *sb,
inode->i_mode = mode;
inode->i_uid = default_uid;
inode->i_gid = default_gid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime
= CURRENT_TIME;
- inode->u.generic_ip = data;
+ inode->i_private = data;
inode->i_fop = fops;
}
return inode;
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index 36db72579377..179259664c18 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -922,7 +922,7 @@ static void lh7a40x_reset_intr(struct lh7a40x_udc *dev)
/*
* lh7a40x usb client interrupt handler.
*/
-static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev, struct pt_regs *r)
+static irqreturn_t lh7a40x_udc_irq(int irq, void *_dev)
{
struct lh7a40x_udc *dev = _dev;
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 09243239d948..3acc896a5d4c 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -2,7 +2,7 @@
* Driver for the PLX NET2280 USB device controller.
* Specs and errata are available from <http://www.plxtech.com>.
*
- * PLX Technology Inc. (formerly NetChip Technology) supported the
+ * PLX Technology Inc. (formerly NetChip Technology) supported the
* development of this driver.
*
*
@@ -26,7 +26,8 @@
* Copyright (C) 2003 David Brownell
* Copyright (C) 2003-2005 PLX Technology, Inc.
*
- * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility with 2282 chip
+ * Modified Seth Levy 2005 PLX Technology, Inc. to provide compatibility
+ * with 2282 chip
*
* 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
@@ -85,7 +86,7 @@ static const char driver_name [] = "net2280";
static const char driver_desc [] = DRIVER_DESC;
static const char ep0name [] = "ep0";
-static const char *ep_name [] = {
+static const char *const ep_name [] = {
ep0name,
"ep-a", "ep-b", "ep-c", "ep-d",
"ep-e", "ep-f",
@@ -225,7 +226,9 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (!ep->is_in)
writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
else if (dev->pdev->device != 0x2280) {
- /* Added for 2282, Don't use nak packets on an in endpoint, this was ignored on 2280 */
+ /* Added for 2282, Don't use nak packets on an in endpoint,
+ * this was ignored on 2280
+ */
writel ((1 << CLEAR_NAK_OUT_PACKETS)
| (1 << CLEAR_NAK_OUT_PACKETS_MODE), &ep->regs->ep_rsp);
}
@@ -288,7 +291,7 @@ static int handshake (u32 __iomem *ptr, u32 mask, u32 done, int usec)
return -ETIMEDOUT;
}
-static struct usb_ep_ops net2280_ep_ops;
+static const struct usb_ep_ops net2280_ep_ops;
static void ep_reset (struct net2280_regs __iomem *regs, struct net2280_ep *ep)
{
@@ -449,34 +452,15 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
/*-------------------------------------------------------------------------*/
-#undef USE_KMALLOC
-
-/* many common platforms have dma-coherent caches, which means that it's
- * safe to use kmalloc() memory for all i/o buffers without using any
- * cache flushing calls. (unless you're trying to share cache lines
- * between dma and non-dma activities, which is a slow idea in any case.)
+/*
+ * dma-coherent memory allocation (for dma-capable endpoints)
*
- * other platforms need more care, with 2.5 having a moderately general
- * solution (which falls down for allocations smaller than one page)
- * that improves significantly on the 2.4 PCI allocators by removing
- * the restriction that memory never be freed in_interrupt().
+ * NOTE: the dma_*_coherent() API calls suck. Most implementations are
+ * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
+ * respect to calls with irqs disabled: alloc is safe, free is not.
+ * We currently work around (b), but not (a).
*/
-#if defined(CONFIG_X86)
-#define USE_KMALLOC
-
-#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
-#define USE_KMALLOC
-
-#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
-#define USE_KMALLOC
-/* FIXME there are other cases, including an x86-64 one ... */
-#endif
-
-/* allocating buffers this way eliminates dma mapping overhead, which
- * on some platforms will mean eliminating a per-io buffer copy. with
- * some kinds of system caches, further tweaks may still be needed.
- */
static void *
net2280_alloc_buffer (
struct usb_ep *_ep,
@@ -493,43 +477,71 @@ net2280_alloc_buffer (
return NULL;
*dma = DMA_ADDR_INVALID;
-#if defined(USE_KMALLOC)
- retval = kmalloc(bytes, gfp_flags);
- if (retval)
- *dma = virt_to_phys(retval);
-#else
- if (ep->dma) {
- /* the main problem with this call is that it wastes memory
- * on typical 1/N page allocations: it allocates 1-N pages.
- */
-#warning Using dma_alloc_coherent even with buffers smaller than a page.
+ if (ep->dma)
retval = dma_alloc_coherent(&ep->dev->pdev->dev,
bytes, dma, gfp_flags);
- } else
+ else
retval = kmalloc(bytes, gfp_flags);
-#endif
return retval;
}
+static DEFINE_SPINLOCK(buflock);
+static LIST_HEAD(buffers);
+
+struct free_record {
+ struct list_head list;
+ struct device *dev;
+ unsigned bytes;
+ dma_addr_t dma;
+};
+
+static void do_free(unsigned long ignored)
+{
+ spin_lock_irq(&buflock);
+ while (!list_empty(&buffers)) {
+ struct free_record *buf;
+
+ buf = list_entry(buffers.next, struct free_record, list);
+ list_del(&buf->list);
+ spin_unlock_irq(&buflock);
+
+ dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
+
+ spin_lock_irq(&buflock);
+ }
+ spin_unlock_irq(&buflock);
+}
+
+static DECLARE_TASKLET(deferred_free, do_free, 0);
+
static void
net2280_free_buffer (
struct usb_ep *_ep,
- void *buf,
+ void *address,
dma_addr_t dma,
unsigned bytes
) {
/* free memory into the right allocator */
-#ifndef USE_KMALLOC
if (dma != DMA_ADDR_INVALID) {
struct net2280_ep *ep;
+ struct free_record *buf = address;
+ unsigned long flags;
ep = container_of(_ep, struct net2280_ep, ep);
if (!_ep)
return;
- dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
+
+ ep = container_of (_ep, struct net2280_ep, ep);
+ buf->dev = &ep->dev->pdev->dev;
+ buf->bytes = bytes;
+ buf->dma = dma;
+
+ spin_lock_irqsave(&buflock, flags);
+ list_add_tail(&buf->list, &buffers);
+ tasklet_schedule(&deferred_free);
+ spin_unlock_irqrestore(&buflock, flags);
} else
-#endif
- kfree (buf);
+ kfree (address);
}
/*-------------------------------------------------------------------------*/
@@ -737,7 +749,8 @@ fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
*/
if (ep->is_in)
dmacount |= (1 << DMA_DIRECTION);
- if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0) || ep->dev->pdev->device != 0x2280)
+ if ((!ep->is_in && (dmacount % ep->ep.maxpacket) != 0)
+ || ep->dev->pdev->device != 0x2280)
dmacount |= (1 << END_OF_CHAIN);
req->valid = valid;
@@ -812,7 +825,7 @@ static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
/* previous OUT packet might have been short */
if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
- & (1 << NAK_OUT_PACKETS)) != 0) {
+ & (1 << NAK_OUT_PACKETS)) != 0) {
writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
&ep->regs->ep_stat);
@@ -1373,7 +1386,7 @@ net2280_fifo_flush (struct usb_ep *_ep)
(void) readl (&ep->regs->ep_rsp);
}
-static struct usb_ep_ops net2280_ep_ops = {
+static const struct usb_ep_ops net2280_ep_ops = {
.enable = net2280_enable,
.disable = net2280_disable,
@@ -1631,7 +1644,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
}
/* Indexed Registers */
- // none yet
+ // none yet
/* Statistics */
t = scnprintf (next, size, "\nirqs: ");
@@ -1691,11 +1704,11 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
({ char *val;
switch (d->bmAttributes & 0x03) {
case USB_ENDPOINT_XFER_BULK:
- val = "bulk"; break;
+ val = "bulk"; break;
case USB_ENDPOINT_XFER_INT:
- val = "intr"; break;
+ val = "intr"; break;
default:
- val = "iso"; break;
+ val = "iso"; break;
}; val; }),
le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
ep->dma ? "dma" : "pio", ep->fifo_size
@@ -1761,8 +1774,8 @@ static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
#else
-#define device_create_file(a,b) do {} while (0)
-#define device_remove_file device_create_file
+#define device_create_file(a,b) (0)
+#define device_remove_file(a,b) do { } while (0)
#endif
@@ -1808,8 +1821,8 @@ extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
* net2280_set_fifo_mode - change allocation of fifo buffers
* @gadget: access to the net2280 device that will be updated
* @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
- * 1 for two 2kB buffers (ep-a and ep-b only);
- * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
+ * 1 for two 2kB buffers (ep-a and ep-b only);
+ * 2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
*
* returns zero on success, else negative errno. when this succeeds,
* the contents of gadget->ep_list may have changed.
@@ -2031,8 +2044,10 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
return retval;
}
- device_create_file (&dev->pdev->dev, &dev_attr_function);
- device_create_file (&dev->pdev->dev, &dev_attr_queues);
+ retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
+ if (retval) goto err_unbind;
+ retval = device_create_file (&dev->pdev->dev, &dev_attr_queues);
+ if (retval) goto err_func;
/* ... then enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
@@ -2047,6 +2062,14 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
/* pci writes may still be posted */
return 0;
+
+err_func:
+ device_remove_file (&dev->pdev->dev, &dev_attr_function);
+err_unbind:
+ driver->unbind (&dev->gadget);
+ dev->gadget.dev.driver = NULL;
+ dev->driver = NULL;
+ return retval;
}
EXPORT_SYMBOL (usb_gadget_register_driver);
@@ -2241,7 +2264,8 @@ static void handle_ep_small (struct net2280_ep *ep)
req->td->dmacount = 0;
t = readl (&ep->regs->ep_avail);
dma_done (ep, req, count,
- (ep->out_overflow || t) ? -EOVERFLOW : 0);
+ (ep->out_overflow || t)
+ ? -EOVERFLOW : 0);
}
/* also flush to prevent erratum 0106 trouble */
@@ -2411,7 +2435,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
, &ep->regs->ep_stat);
u.raw [0] = readl (&dev->usb->setup0123);
u.raw [1] = readl (&dev->usb->setup4567);
-
+
cpu_to_le32s (&u.raw [0]);
cpu_to_le32s (&u.raw [1]);
@@ -2578,14 +2602,16 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
/* VBUS disconnect is indicated by VBUS_PIN and VBUS_INTERRUPT set.
* Root Port Reset is indicated by ROOT_PORT_RESET_INTERRRUPT set and
- * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
+ * both HIGH_SPEED and FULL_SPEED clear (as ROOT_PORT_RESET_INTERRUPT
* only indicates a change in the reset state).
*/
if (stat & tmp) {
writel (tmp, &dev->regs->irqstat1);
- if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
- ((readl (&dev->usb->usbstat) & mask) == 0))
- || ((readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0)
+ if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT))
+ && ((readl (&dev->usb->usbstat) & mask)
+ == 0))
+ || ((readl (&dev->usb->usbctl)
+ & (1 << VBUS_PIN)) == 0)
) && ( dev->gadget.speed != USB_SPEED_UNKNOWN)) {
DEBUG (dev, "disconnect %s\n",
dev->driver->driver.name);
@@ -2737,7 +2763,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
DEBUG (dev, "unhandled irqstat1 %08x\n", stat);
}
-static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r)
+static irqreturn_t net2280_irq (int irq, void *_dev)
{
struct net2280 *dev = _dev;
@@ -2852,7 +2878,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
/* now all the pci goodies ... */
if (pci_enable_device (pdev) < 0) {
- retval = -ENODEV;
+ retval = -ENODEV;
goto done;
}
dev->enabled = 1;
@@ -2870,6 +2896,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
}
dev->region = 1;
+ /* FIXME provide firmware download interface to put
+ * 8051 code into the chip, e.g. to turn on PCI PM.
+ */
+
base = ioremap_nocache (resource, len);
if (base == NULL) {
DEBUG (dev, "can't map memory\n");
@@ -2954,8 +2984,10 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
: "disabled");
the_controller = dev;
- device_register (&dev->gadget.dev);
- device_create_file (&pdev->dev, &dev_attr_registers);
+ retval = device_register (&dev->gadget.dev);
+ if (retval) goto done;
+ retval = device_create_file (&pdev->dev, &dev_attr_registers);
+ if (retval) goto done;
return 0;
@@ -2984,16 +3016,16 @@ static void net2280_shutdown (struct pci_dev *pdev)
/*-------------------------------------------------------------------------*/
-static struct pci_device_id pci_ids [] = { {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
+static const struct pci_device_id pci_ids [] = { {
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class_mask = ~0,
.vendor = 0x17cc,
.device = 0x2280,
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
}, {
- .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
- .class_mask = ~0,
+ .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+ .class_mask = ~0,
.vendor = 0x17cc,
.device = 0x2282,
.subvendor = PCI_ANY_ID,
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 2de9748ee673..48a09fd89d18 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -40,7 +40,7 @@
#include <linux/platform_device.h>
#include <linux/usb_ch9.h>
#include <linux/usb_gadget.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <asm/byteorder.h>
@@ -1815,8 +1815,7 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
UDC_IRQ_SRC_REG = UDC_DS_CHG;
}
-static irqreturn_t
-omap_udc_irq(int irq, void *_udc, struct pt_regs *r)
+static irqreturn_t omap_udc_irq(int irq, void *_udc)
{
struct omap_udc *udc = _udc;
u16 irq_src;
@@ -1888,8 +1887,7 @@ static void pio_out_timer(unsigned long _ep)
spin_unlock_irqrestore(&ep->udc->lock, flags);
}
-static irqreturn_t
-omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
+static irqreturn_t omap_udc_pio_irq(int irq, void *_dev)
{
u16 epn_stat, irq_src;
irqreturn_t status = IRQ_NONE;
@@ -1968,8 +1966,7 @@ omap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r)
}
#ifdef USE_ISO
-static irqreturn_t
-omap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r)
+static irqreturn_t omap_udc_iso_irq(int irq, void *_dev)
{
struct omap_udc *udc = _dev;
struct omap_ep *ep;
@@ -2437,7 +2434,7 @@ static int proc_udc_open(struct inode *inode, struct file *file)
return single_open(file, proc_udc_show, NULL);
}
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
.open = proc_udc_open,
.read = seq_read,
.llseek = seq_lseek,
@@ -2869,7 +2866,7 @@ cleanup0:
static int __exit omap_udc_remove(struct platform_device *pdev)
{
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
if (!udc)
return -ENODEV;
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index fff027d30a09..671c24bc6d75 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -43,11 +43,11 @@
#include <linux/mm.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/irq.h>
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/io.h>
-#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
@@ -110,7 +110,7 @@ static int use_dma = 1;
module_param(use_dma, bool, 0);
MODULE_PARM_DESC (use_dma, "true to use dma");
-static void dma_nodesc_handler (int dmach, void *_ep, struct pt_regs *r);
+static void dma_nodesc_handler (int dmach, void *_ep);
static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);
#ifdef USE_OUT_DMA
@@ -150,6 +150,39 @@ MODULE_PARM_DESC (fifo_mode, "pxa2xx udc fifo mode");
static void pxa2xx_ep_fifo_flush (struct usb_ep *ep);
static void nuke (struct pxa2xx_ep *, int status);
+/* one GPIO should be used to detect VBUS from the host */
+static int is_vbus_present(void)
+{
+ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+ if (mach->gpio_vbus)
+ return pxa_gpio_get(mach->gpio_vbus);
+ if (mach->udc_is_connected)
+ return mach->udc_is_connected();
+ return 1;
+}
+
+/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+static void pullup_off(void)
+{
+ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+ if (mach->gpio_pullup)
+ pxa_gpio_set(mach->gpio_pullup, 0);
+ else if (mach->udc_command)
+ mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
+}
+
+static void pullup_on(void)
+{
+ struct pxa2xx_udc_mach_info *mach = the_controller->mach;
+
+ if (mach->gpio_pullup)
+ pxa_gpio_set(mach->gpio_pullup, 1);
+ else if (mach->udc_command)
+ mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+}
+
static void pio_irq_enable(int bEndpointAddress)
{
bEndpointAddress &= 0xf;
@@ -795,7 +828,7 @@ static void cancel_dma(struct pxa2xx_ep *ep)
}
/* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */
-static void dma_nodesc_handler(int dmach, void *_ep, struct pt_regs *r)
+static void dma_nodesc_handler(int dmach, void *_ep)
{
struct pxa2xx_ep *ep = _ep;
struct pxa2xx_request *req;
@@ -1691,7 +1724,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
*/
static irqreturn_t
-lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
+lubbock_vbus_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
int vbus;
@@ -1721,6 +1754,15 @@ lubbock_vbus_irq(int irq, void *_dev, struct pt_regs *r)
#endif
+static irqreturn_t udc_vbus_irq(int irq, void *_dev)
+{
+ struct pxa2xx_udc *dev = _dev;
+ int vbus = pxa_gpio_get(dev->mach->gpio_vbus);
+
+ pxa2xx_udc_vbus_session(&dev->gadget, vbus);
+ return IRQ_HANDLED;
+}
+
/*-------------------------------------------------------------------------*/
@@ -2041,7 +2083,7 @@ static void handle_ep(struct pxa2xx_ep *ep)
* could cause usb protocol errors.
*/
static irqreturn_t
-pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
+pxa2xx_udc_irq(int irq, void *_dev)
{
struct pxa2xx_udc *dev = _dev;
int handled;
@@ -2438,7 +2480,7 @@ static struct pxa2xx_udc memory = {
static int __init pxa2xx_udc_probe(struct platform_device *pdev)
{
struct pxa2xx_udc *dev = &memory;
- int retval, out_dma = 1;
+ int retval, out_dma = 1, vbus_irq;
u32 chiprev;
/* insist on Intel/ARM/XScale */
@@ -2502,6 +2544,16 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
/* other non-static parts of init */
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
+ if (dev->mach->gpio_vbus) {
+ vbus_irq = IRQ_GPIO(dev->mach->gpio_vbus & GPIO_MD_MASK_NR);
+ pxa_gpio_mode((dev->mach->gpio_vbus & GPIO_MD_MASK_NR)
+ | GPIO_IN);
+ set_irq_type(vbus_irq, IRQT_BOTHEDGE);
+ } else
+ vbus_irq = 0;
+ if (dev->mach->gpio_pullup)
+ pxa_gpio_mode((dev->mach->gpio_pullup & GPIO_MD_MASK_NR)
+ | GPIO_OUT | GPIO_DFLT_LOW);
init_timer(&dev->timer);
dev->timer.function = udc_watchdog;
@@ -2557,8 +2609,19 @@ lubbock_fail0:
HEX_DISPLAY(dev->stats.irqs);
LUB_DISC_BLNK_LED &= 0xff;
#endif
- }
+ } else
#endif
+ if (vbus_irq) {
+ retval = request_irq(vbus_irq, udc_vbus_irq,
+ SA_INTERRUPT | SA_SAMPLE_RANDOM,
+ driver_name, dev);
+ if (retval != 0) {
+ printk(KERN_ERR "%s: can't get irq %i, err %d\n",
+ driver_name, vbus_irq, retval);
+ free_irq(IRQ_USB, dev);
+ return -EBUSY;
+ }
+ }
create_proc_files();
return 0;
@@ -2587,6 +2650,8 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
free_irq(LUBBOCK_USB_IRQ, dev);
}
#endif
+ if (dev->mach->gpio_vbus)
+ free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
platform_set_drvdata(pdev, NULL);
the_controller = NULL;
return 0;
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 19a883f7d1b8..8e598c8bf4e3 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,27 +177,19 @@ struct pxa2xx_udc {
static struct pxa2xx_udc *the_controller;
-/* one GPIO should be used to detect VBUS from the host */
-static inline int is_vbus_present(void)
+static inline int pxa_gpio_get(unsigned gpio)
{
- if (!the_controller->mach->udc_is_connected)
- return 1;
- return the_controller->mach->udc_is_connected();
+ return (GPLR(gpio) & GPIO_bit(gpio)) != 0;
}
-/* one GPIO should control a D+ pullup, so host sees this device (or not) */
-static inline void pullup_off(void)
+static inline void pxa_gpio_set(unsigned gpio, int is_on)
{
- if (!the_controller->mach->udc_command)
- return;
- the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
-}
+ int mask = GPIO_bit(gpio);
-static inline void pullup_on(void)
-{
- if (!the_controller->mach->udc_command)
- return;
- the_controller->mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
+ if (is_on)
+ GPSR(gpio) = mask;
+ else
+ GPCR(gpio) = mask;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index e762aa19ab0a..208e55a667ac 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -271,7 +271,7 @@ static unsigned int use_acm = GS_DEFAULT_USE_ACM;
/* tty driver struct */
-static struct tty_operations gs_tty_ops = {
+static const struct tty_operations gs_tty_ops = {
.open = gs_open,
.close = gs_close,
.write = gs_write,
@@ -1120,12 +1120,15 @@ static int gs_send(struct gs_dev *dev)
gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
list_del(&req_entry->re_entry);
req->length = len;
+ spin_unlock_irqrestore(&dev->dev_lock, flags);
if ((ret=usb_ep_queue(ep, req, GFP_ATOMIC))) {
printk(KERN_ERR
"gs_send: cannot queue read request, ret=%d\n",
ret);
+ spin_lock_irqsave(&dev->dev_lock, flags);
break;
}
+ spin_lock_irqsave(&dev->dev_lock, flags);
} else {
break;
}
@@ -1431,7 +1434,7 @@ static int __init gs_bind(struct usb_gadget *gadget)
return -ENOMEM;
snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
- system_utsname.sysname, system_utsname.release,
+ init_utsname()->sysname, init_utsname()->release,
gadget->name);
memset(dev, 0, sizeof(struct gs_dev));
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index b7018ee487ea..0f809dd68492 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1242,7 +1242,7 @@ autoconf_fail:
EP_OUT_NAME, EP_IN_NAME);
snprintf (manufacturer, sizeof manufacturer, "%s %s with %s",
- system_utsname.sysname, system_utsname.release,
+ init_utsname()->sysname, init_utsname()->release,
gadget->name);
return 0;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index b93d71d28db7..cf10cbc98f80 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -83,6 +83,7 @@ config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+ select I2C if ARCH_PNX4008
---help---
The Open Host Controller Interface (OHCI) is a standard for accessing
USB 1.1 host controller hardware. It does more in hardware than Intel's
@@ -141,6 +142,34 @@ config USB_UHCI_HCD
To compile this driver as a module, choose M here: the
module will be called uhci-hcd.
+config USB_U132_HCD
+ tristate "Elan U132 Adapter Host Controller"
+ depends on USB && USB_FTDI_ELAN
+ default M
+ help
+ The U132 adapter is a USB to CardBus adapter specifically designed
+ for PC cards that contain an OHCI host controller. Typical PC cards
+ are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132
+ adapter will *NOT* work with PC cards that do not contain an OHCI
+ controller.
+
+ For those PC cards that contain multiple OHCI controllers only ther
+ first one is used.
+
+ The driver consists of two modules, the "ftdi-elan" module is a
+ USB client driver that interfaces to the FTDI chip within ELAN's
+ USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host
+ controller driver that talks to the OHCI controller within the
+ CardBus cards that are inserted in the U132 adapter.
+
+ This driver has been tested with a CardBus OHCI USB adapter, and
+ worked with a USB PEN Drive inserted into the first USB port of
+ the PCCARD. A rather pointless thing to do, but useful for testing.
+
+ It is safe to say M here.
+
+ See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php>
+
config USB_SL811_HCD
tristate "SL811HS HCD support"
depends on USB
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index e3020f4b17be..a2e58c86849f 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -14,4 +14,5 @@ obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
+obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_ETRAX_ARCH_V10) += hc_crisv10.o
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 26ed757d22a6..5d1b12aad776 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -200,6 +200,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
.reset = ehci_init,
.start = ehci_run,
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -268,6 +269,7 @@ MODULE_ALIAS("au1xxx-ehci");
static struct platform_driver ehci_hcd_au1xxx_driver = {
.probe = ehci_hcd_au1xxx_drv_probe,
.remove = ehci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ehci_hcd_au1xxx_drv_suspend, */
/*.resume = ehci_hcd_au1xxx_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 65ac9fef3a7c..34b7a31cd85b 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2001-2002 by David Brownell
- *
+ *
* 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
@@ -65,7 +65,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
for (i = 0; i < HCS_N_PORTS (params); i++) {
// FIXME MIPS won't readb() ...
byte = readb (&ehci->caps->portroute[(i>>1)]);
- sprintf(tmp, "%d ",
+ sprintf(tmp, "%d ",
((i & 0x1) ? ((byte)&0xf) : ((byte>>4)&0xf)));
strcat(buf, tmp);
}
@@ -141,12 +141,12 @@ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
}
static void __attribute__((__unused__))
-dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
+dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
{
ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
ehci_dbg (ehci,
- " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ " trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_transaction[0]),
le32_to_cpu(itd->hw_transaction[1]),
le32_to_cpu(itd->hw_transaction[2]),
@@ -156,7 +156,7 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
le32_to_cpu(itd->hw_transaction[6]),
le32_to_cpu(itd->hw_transaction[7]));
ehci_dbg (ehci,
- " buf: %08x %08x %08x %08x %08x %08x %08x\n",
+ " buf: %08x %08x %08x %08x %08x %08x %08x\n",
le32_to_cpu(itd->hw_bufp[0]),
le32_to_cpu(itd->hw_bufp[1]),
le32_to_cpu(itd->hw_bufp[2]),
@@ -171,12 +171,12 @@ dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
}
static void __attribute__((__unused__))
-dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
+dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
{
ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
ehci_dbg (ehci,
- " addr %08x sched %04x result %08x buf %08x %08x\n",
+ " addr %08x sched %04x result %08x buf %08x %08x\n",
le32_to_cpu(sitd->hw_fullspeed_ep),
le32_to_cpu(sitd->hw_uframe),
le32_to_cpu(sitd->hw_results),
@@ -451,7 +451,7 @@ show_async (struct class_device *class_dev, char *buf)
*buf = 0;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@@ -497,7 +497,7 @@ show_periodic (struct class_device *class_dev, char *buf)
seen_count = 0;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@@ -634,7 +634,7 @@ show_registers (struct class_device *class_dev, char *buf)
static char label [] = "";
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ehci = hcd_to_ehci (hcd);
next = buf;
size = PAGE_SIZE;
@@ -785,10 +785,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static inline void create_debug_files (struct ehci_hcd *ehci)
{
struct class_device *cldev = ehci_to_hcd(ehci)->self.class_dev;
+ int retval;
- class_device_create_file(cldev, &class_device_attr_async);
- class_device_create_file(cldev, &class_device_attr_periodic);
- class_device_create_file(cldev, &class_device_attr_registers);
+ retval = class_device_create_file(cldev, &class_device_attr_async);
+ retval = class_device_create_file(cldev, &class_device_attr_periodic);
+ retval = class_device_create_file(cldev, &class_device_attr_registers);
}
static inline void remove_debug_files (struct ehci_hcd *ehci)
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index d030516edfb9..1a915e982c1c 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -285,6 +285,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
.resume = ehci_bus_resume,
#endif
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -329,6 +330,7 @@ MODULE_ALIAS("fsl-ehci");
static struct platform_driver ehci_fsl_driver = {
.probe = ehci_fsl_drv_probe,
.remove = ehci_fsl_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "fsl-ehci",
},
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index d63177a8eaea..9030994aba98 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2000-2004 by David Brownell
- *
+ *
* 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
@@ -70,7 +70,7 @@
* 2002-08-06 Handling for bulk and interrupt transfers is mostly shared;
* only scheduling is different, no arbitrary limitations.
* 2002-07-25 Sanity check PCI reads, mostly for better cardbus support,
- * clean up HC run state handshaking.
+ * clean up HC run state handshaking.
* 2002-05-24 Preliminary FS/LS interrupts, using scheduling shortcuts
* 2002-05-11 Clear TT errors for FS/LS ctrl/bulk. Fill in some other
* missing pieces: enabling 64bit dma, handoff from BIOS/SMM.
@@ -254,7 +254,7 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
/*-------------------------------------------------------------------------*/
-static void ehci_work(struct ehci_hcd *ehci, struct pt_regs *regs);
+static void ehci_work(struct ehci_hcd *ehci);
#include "ehci-hub.c"
#include "ehci-mem.c"
@@ -273,7 +273,6 @@ static void ehci_watchdog (unsigned long param)
/* lost IAA irqs wedge things badly; seen with a vt8235 */
if (ehci->reclaim) {
u32 status = readl (&ehci->regs->status);
-
if (status & STS_IAA) {
ehci_vdbg (ehci, "lost IAA\n");
COUNT (ehci->stats.lost_iaa);
@@ -284,29 +283,28 @@ static void ehci_watchdog (unsigned long param)
/* stop async processing after it's idled a bit */
if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
- start_unlink_async (ehci, ehci->async);
+ start_unlink_async (ehci, ehci->async);
/* ehci could run by timer, without IRQs ... */
- ehci_work (ehci, NULL);
+ ehci_work (ehci);
spin_unlock_irqrestore (&ehci->lock, flags);
}
-/* Reboot notifiers kick in for silicon on any bus (not just pci, etc).
+/* ehci_shutdown kick in for silicon on any bus (not just pci, etc).
* This forcibly disables dma and IRQs, helping kexec and other cases
* where the next system software may expect clean state.
*/
-static int
-ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
+static void
+ehci_shutdown (struct usb_hcd *hcd)
{
- struct ehci_hcd *ehci;
+ struct ehci_hcd *ehci;
- ehci = container_of (self, struct ehci_hcd, reboot_notifier);
+ ehci = hcd_to_ehci (hcd);
(void) ehci_halt (ehci);
/* make BIOS/etc use companion controller during reboot */
writel (0, &ehci->regs->configured_flag);
- return 0;
}
static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -331,11 +329,11 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
* ehci_work is called from some interrupts, timers, and so on.
* it calls driver completion functions, after dropping ehci->lock.
*/
-static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
+static void ehci_work (struct ehci_hcd *ehci)
{
timer_action_done (ehci, TIMER_IO_WATCHDOG);
if (ehci->reclaim_ready)
- end_unlink_async (ehci, regs);
+ end_unlink_async (ehci);
/* another CPU may drop ehci->lock during a schedule scan while
* it reports urb completions. this flag guards against bogus
@@ -344,9 +342,9 @@ static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
if (ehci->scanning)
return;
ehci->scanning = 1;
- scan_async (ehci, regs);
+ scan_async (ehci);
if (ehci->next_uframe != -1)
- scan_periodic (ehci, regs);
+ scan_periodic (ehci);
ehci->scanning = 0;
/* the IO watchdog guards against hardware or driver bugs that
@@ -381,14 +379,13 @@ static void ehci_stop (struct usb_hcd *hcd)
/* let companion controllers work when we aren't */
writel (0, &ehci->regs->configured_flag);
- unregister_reboot_notifier (&ehci->reboot_notifier);
remove_debug_files (ehci);
/* root hub is shut down separately (first, when possible) */
spin_lock_irq (&ehci->lock);
if (ehci->async)
- ehci_work (ehci, NULL);
+ ehci_work (ehci);
spin_unlock_irq (&ehci->lock);
ehci_mem_cleanup (ehci);
@@ -427,7 +424,7 @@ static int ehci_init(struct usb_hcd *hcd)
/* controllers may cache some of the periodic schedule ... */
hcc_params = readl(&ehci->caps->hcc_params);
- if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
+ if (HCC_ISOC_CACHE(hcc_params)) // full frame cache
ehci->i_thresh = 8;
else // N microframes cached
ehci->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
@@ -483,9 +480,6 @@ static int ehci_init(struct usb_hcd *hcd)
}
ehci->command = temp;
- ehci->reboot_notifier.notifier_call = ehci_reboot;
- register_reboot_notifier(&ehci->reboot_notifier);
-
return 0;
}
@@ -499,7 +493,6 @@ static int ehci_run (struct usb_hcd *hcd)
/* EHCI spec section 4.1 */
if ((retval = ehci_reset(ehci)) != 0) {
- unregister_reboot_notifier(&ehci->reboot_notifier);
ehci_mem_cleanup(ehci);
return retval;
}
@@ -565,7 +558,7 @@ static int ehci_run (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
+static irqreturn_t ehci_irq (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 status;
@@ -662,7 +655,7 @@ dead:
}
if (bh)
- ehci_work (ehci, regs);
+ ehci_work (ehci);
spin_unlock (&ehci->lock);
return IRQ_HANDLED;
}
@@ -730,7 +723,7 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/* bypass IAA if the hc can't care */
} else if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state) && ehci->reclaim)
- end_unlink_async (ehci, NULL);
+ end_unlink_async (ehci);
/* something else might have unlinked the qh by now */
if (qh->qh_state == QH_STATE_LINKED)
@@ -767,7 +760,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
intr_deschedule (ehci, qh);
/* FALL THROUGH */
case QH_STATE_IDLE:
- qh_completions (ehci, qh, NULL);
+ qh_completions (ehci, qh);
break;
default:
ehci_dbg (ehci, "bogus qh %p state %d\n",
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index d03e3cad5ca8..1b20722c102b 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 by David Brownell
- *
+ *
* 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
@@ -49,7 +49,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
ehci->command = readl (&ehci->regs->command);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
- ehci_work(ehci, NULL);
+ ehci_work(ehci);
/* suspend any active/unsuspended ports, maybe allow wakeup */
while (port--) {
@@ -103,10 +103,10 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
/* re-init operational registers in case we lost power */
if (readl (&ehci->regs->intr_enable) == 0) {
- /* at least some APM implementations will try to deliver
+ /* at least some APM implementations will try to deliver
* IRQs right away, so delay them until we're ready.
- */
- intr_enable = 1;
+ */
+ intr_enable = 1;
writel (0, &ehci->regs->segment);
writel (ehci->periodic_dma, &ehci->regs->frame_list);
writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
@@ -232,7 +232,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [1] = 0;
retval++;
}
-
+
/* no hub change reports (bit 0) for now (power, ...) */
/* port N changes (bit N)? */
@@ -304,7 +304,7 @@ ehci_hub_descriptor (
/*-------------------------------------------------------------------------*/
-#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
static int ehci_hub_control (
struct usb_hcd *hcd,
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index 766061e0260a..a8ba2e1497a4 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2001 by David Brownell
- *
+ *
* 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
@@ -25,7 +25,7 @@
* - data used only by the HCD ... kmalloc is fine
* - async and periodic schedules, shared by HC and HCD ... these
* need to use dma_pool or dma_alloc_coherent
- * - driver buffers, read/written by HC ... single shot DMA mapped
+ * - driver buffers, read/written by HC ... single shot DMA mapped
*
* There's also PCI "register" data, which is memory mapped.
* No memory seen by this driver is pageable.
@@ -119,7 +119,7 @@ static inline void qh_put (struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-/* The queue heads and transfer descriptors are managed from pools tied
+/* The queue heads and transfer descriptors are managed from pools tied
* to each of the "per device" structures.
* This is the initialisation and cleanup code.
*/
@@ -165,7 +165,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
int i;
/* QTDs for control/bulk/intr transfers */
- ehci->qtd_pool = dma_pool_create ("ehci_qtd",
+ ehci->qtd_pool = dma_pool_create ("ehci_qtd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qtd),
32 /* byte alignment (for hw parts) */,
@@ -175,7 +175,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* QHs for control/bulk/intr transfers */
- ehci->qh_pool = dma_pool_create ("ehci_qh",
+ ehci->qh_pool = dma_pool_create ("ehci_qh",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_qh),
32 /* byte alignment (for hw parts) */,
@@ -189,7 +189,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* ITD for high speed ISO transfers */
- ehci->itd_pool = dma_pool_create ("ehci_itd",
+ ehci->itd_pool = dma_pool_create ("ehci_itd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_itd),
32 /* byte alignment (for hw parts) */,
@@ -199,7 +199,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
}
/* SITD for full/low speed split ISO transfers */
- ehci->sitd_pool = dma_pool_create ("ehci_sitd",
+ ehci->sitd_pool = dma_pool_create ("ehci_sitd",
ehci_to_hcd(ehci)->self.controller,
sizeof (struct ehci_sitd),
32 /* byte alignment (for hw parts) */,
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 6967ab71e282..e51c1ed81ac4 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -304,7 +304,7 @@ restart:
spin_lock_irq(&ehci->lock);
if (ehci->reclaim)
ehci->reclaim_ready = 1;
- ehci_work(ehci, NULL);
+ ehci_work(ehci);
spin_unlock_irq(&ehci->lock);
/* restart; khubd will disconnect devices */
@@ -338,6 +338,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
.resume = ehci_pci_resume,
#endif
.stop = ehci_stop,
+ .shutdown = ehci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -384,4 +385,5 @@ static struct pci_driver ehci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
+ .shutdown = usb_hcd_pci_shutdown,
};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index e469221e7ec3..62e46dc60e86 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2001-2004 by David Brownell
- *
+ *
* 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
@@ -31,7 +31,7 @@
* ISO traffic uses "ISO TD" (itd, and sitd) records, and (along with
* interrupts) needs careful scheduling. Performance improvements can be
* an ongoing challenge. That's in "ehci-sched.c".
- *
+ *
* USB 1.1 devices are handled (a) by "companion" OHCI or UHCI root hubs,
* or otherwise through transaction translators (TTs) in USB 2.0 hubs using
* (b) special fields in qh entries or (c) split iso entries. TTs will
@@ -199,7 +199,7 @@ static void qtd_copy_status (
&& ((token & QTD_STS_MMF) != 0
|| QTD_CERR(token) == 0)
&& (!ehci_is_TDI(ehci)
- || urb->dev->tt->hub !=
+ || urb->dev->tt->hub !=
ehci_to_hcd(ehci)->self.root_hub)) {
#ifdef DEBUG
struct usb_device *tt = urb->dev->tt->hub;
@@ -214,7 +214,7 @@ static void qtd_copy_status (
}
static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb, struct pt_regs *regs)
+ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
__releases(ehci->lock)
__acquires(ehci->lock)
{
@@ -262,7 +262,7 @@ __acquires(ehci->lock)
/* complete() can reenter this HCD */
spin_unlock (&ehci->lock);
- usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb, regs);
+ usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
spin_lock (&ehci->lock);
}
@@ -279,7 +279,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
*/
#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
static unsigned
-qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
+qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
struct ehci_qtd *last = NULL, *end = qh->dummy;
struct list_head *entry, *tmp;
@@ -317,7 +317,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
/* clean up any state from previous QTD ...*/
if (last) {
if (likely (last->urb != urb)) {
- ehci_urb_done (ehci, last->urb, regs);
+ ehci_urb_done (ehci, last->urb);
count++;
}
ehci_qtd_free (ehci, last);
@@ -364,7 +364,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh, struct pt_regs *regs)
*/
if (likely (urb->status == -EINPROGRESS))
continue;
-
+
/* issue status after short control reads */
if (unlikely (do_status != 0)
&& QTD_PID (token) == 0 /* OUT */) {
@@ -388,7 +388,7 @@ halt:
wmb ();
}
}
-
+
/* remove it from the queue */
spin_lock (&urb->lock);
qtd_copy_status (ehci, urb, qtd->length, token);
@@ -407,7 +407,7 @@ halt:
/* last urb's completion might still need calling */
if (likely (last != NULL)) {
- ehci_urb_done (ehci, last->urb, regs);
+ ehci_urb_done (ehci, last->urb);
count++;
ehci_qtd_free (ehci, last);
}
@@ -518,7 +518,7 @@ qh_urb_transaction (
/* for zero length DATA stages, STATUS is always IN */
if (len == 0)
token |= (1 /* "in" */ << 8);
- }
+ }
/*
* data transfer stage: buffer setup
@@ -759,7 +759,7 @@ qh_make (
}
break;
default:
- dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
+ dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed);
done:
qh_put (qh);
return NULL;
@@ -962,7 +962,7 @@ submit_async (
/* the async qh for the qtds being reclaimed are now unlinked from the HC */
-static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+static void end_unlink_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh = ehci->reclaim;
struct ehci_qh *next;
@@ -972,7 +972,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
// qh->hw_next = cpu_to_le32 (qh->qh_dma);
qh->qh_state = QH_STATE_IDLE;
qh->qh_next.qh = NULL;
- qh_put (qh); // refcount from reclaim
+ qh_put (qh); // refcount from reclaim
/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
next = qh->reclaim;
@@ -980,7 +980,7 @@ static void end_unlink_async (struct ehci_hcd *ehci, struct pt_regs *regs)
ehci->reclaim_ready = 0;
qh->reclaim = NULL;
- qh_completions (ehci, qh, regs);
+ qh_completions (ehci, qh);
if (!list_empty (&qh->qtd_list)
&& HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
@@ -1031,7 +1031,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
timer_action_done (ehci, TIMER_ASYNC_OFF);
}
return;
- }
+ }
qh->qh_state = QH_STATE_UNLINK;
ehci->reclaim = qh = qh_get (qh);
@@ -1046,9 +1046,9 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
if (unlikely (ehci_to_hcd(ehci)->state == HC_STATE_HALT)) {
/* if (unlikely (qh->reclaim != 0))
- * this will recurse, probably not much
+ * this will recurse, probably not much
*/
- end_unlink_async (ehci, NULL);
+ end_unlink_async (ehci);
return;
}
@@ -1061,8 +1061,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
-static void
-scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
+static void scan_async (struct ehci_hcd *ehci)
{
struct ehci_qh *qh;
enum ehci_timer_action action = TIMER_IO_WATCHDOG;
@@ -1086,7 +1085,7 @@ rescan:
*/
qh = qh_get (qh);
qh->stamp = ehci->stamp;
- temp = qh_completions (ehci, qh, regs);
+ temp = qh_completions (ehci, qh);
qh_put (qh);
if (temp != 0) {
goto rescan;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 4859900bd135..65c402a0fa7a 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2001-2004 by David Brownell
* Copyright (c) 2003 Michal Sojka, for high-speed iso transfers
- *
+ *
* 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
@@ -613,7 +613,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
/*-------------------------------------------------------------------------*/
static int check_period (
- struct ehci_hcd *ehci,
+ struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
unsigned period,
@@ -629,7 +629,7 @@ static int check_period (
/*
* 80% periodic == 100 usec/uframe available
- * convert "usecs we need" to "max already claimed"
+ * convert "usecs we need" to "max already claimed"
*/
usecs = 100 - usecs;
@@ -659,14 +659,14 @@ static int check_period (
}
static int check_intr_schedule (
- struct ehci_hcd *ehci,
+ struct ehci_hcd *ehci,
unsigned frame,
unsigned uframe,
const struct ehci_qh *qh,
__le32 *c_maskp
)
{
- int retval = -ENOSPC;
+ int retval = -ENOSPC;
u8 mask = 0;
if (qh->c_usecs && uframe >= 6) /* FSTN territory? */
@@ -701,7 +701,7 @@ static int check_intr_schedule (
/* Make sure this tt's buffer is also available for CSPLITs.
* We pessimize a bit; probably the typical full speed case
* doesn't need the second CSPLIT.
- *
+ *
* NOTE: both SPLIT and CSPLIT could be checked in just
* one smart pass...
*/
@@ -728,7 +728,7 @@ done:
*/
static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
{
- int status;
+ int status;
unsigned uframe;
__le32 c_mask;
unsigned frame; /* 0..(qh->period - 1), or NO_FRAME */
@@ -784,7 +784,7 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
ehci_dbg (ehci, "reused qh %p schedule\n", qh);
/* stuff into the periodic schedule */
- status = qh_link_periodic (ehci, qh);
+ status = qh_link_periodic (ehci, qh);
done:
return status;
}
@@ -1553,8 +1553,7 @@ itd_link_urb (
static unsigned
itd_complete (
struct ehci_hcd *ehci,
- struct ehci_itd *itd,
- struct pt_regs *regs
+ struct ehci_itd *itd
) {
struct urb *urb = itd->urb;
struct usb_iso_packet_descriptor *desc;
@@ -1613,7 +1612,7 @@ itd_complete (
/* give urb back to the driver ... can be out-of-order */
dev = urb->dev;
- ehci_urb_done (ehci, urb, regs);
+ ehci_urb_done (ehci, urb);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -1681,7 +1680,7 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
- if (likely (status == 0))
+ if (likely (status == 0))
itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -1738,7 +1737,7 @@ sitd_sched_init (
if (packet->buf1 != (buf & ~(u64)0x0fff))
packet->cross = 1;
- /* OUT uses multiple start-splits */
+ /* OUT uses multiple start-splits */
if (stream->bEndpointAddress & USB_DIR_IN)
continue;
length = (length + 187) / 188;
@@ -1925,13 +1924,12 @@ sitd_link_urb (
/*-------------------------------------------------------------------------*/
#define SITD_ERRS (SITD_STS_ERR | SITD_STS_DBE | SITD_STS_BABBLE \
- | SITD_STS_XACT | SITD_STS_MMF)
+ | SITD_STS_XACT | SITD_STS_MMF)
static unsigned
sitd_complete (
struct ehci_hcd *ehci,
- struct ehci_sitd *sitd,
- struct pt_regs *regs
+ struct ehci_sitd *sitd
) {
struct urb *urb = sitd->urb;
struct usb_iso_packet_descriptor *desc;
@@ -1978,7 +1976,7 @@ sitd_complete (
/* give urb back to the driver */
dev = urb->dev;
- ehci_urb_done (ehci, urb, regs);
+ ehci_urb_done (ehci, urb);
urb = NULL;
/* defer stopping schedule; completion can submit */
@@ -2043,7 +2041,7 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
status = -ESHUTDOWN;
else
status = iso_stream_schedule (ehci, urb, stream);
- if (status == 0)
+ if (status == 0)
sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
spin_unlock_irqrestore (&ehci->lock, flags);
@@ -2065,8 +2063,7 @@ sitd_submit (struct ehci_hcd *ehci, struct urb *urb, gfp_t mem_flags)
static inline unsigned
sitd_complete (
struct ehci_hcd *ehci,
- struct ehci_sitd *sitd,
- struct pt_regs *regs
+ struct ehci_sitd *sitd
) {
ehci_err (ehci, "sitd_complete %p?\n", sitd);
return 0;
@@ -2077,7 +2074,7 @@ sitd_complete (
/*-------------------------------------------------------------------------*/
static void
-scan_periodic (struct ehci_hcd *ehci, struct pt_regs *regs)
+scan_periodic (struct ehci_hcd *ehci)
{
unsigned frame, clock, now_uframe, mod;
unsigned modified;
@@ -2131,7 +2128,7 @@ restart:
temp.qh = qh_get (q.qh);
type = Q_NEXT_TYPE (q.qh->hw_next);
q = q.qh->qh_next;
- modified = qh_completions (ehci, temp.qh, regs);
+ modified = qh_completions (ehci, temp.qh);
if (unlikely (list_empty (&temp.qh->qtd_list)))
intr_deschedule (ehci, temp.qh);
qh_put (temp.qh);
@@ -2169,7 +2166,7 @@ restart:
*hw_p = q.itd->hw_next;
type = Q_NEXT_TYPE (q.itd->hw_next);
wmb();
- modified = itd_complete (ehci, q.itd, regs);
+ modified = itd_complete (ehci, q.itd);
q = *q_p;
break;
case Q_TYPE_SITD:
@@ -2185,7 +2182,7 @@ restart:
*hw_p = q.sitd->hw_next;
type = Q_NEXT_TYPE (q.sitd->hw_next);
wmb();
- modified = sitd_complete (ehci, q.sitd, regs);
+ modified = sitd_complete (ehci, q.sitd);
q = *q_p;
break;
default:
@@ -2226,5 +2223,5 @@ restart:
now_uframe++;
now_uframe %= mod;
}
- }
+ }
}
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 679c1cdcc915..bbc3082a73d7 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2001-2002 by David Brownell
- *
+ *
* 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
@@ -82,7 +82,6 @@ struct ehci_hcd { /* one per controller */
struct dma_pool *sitd_pool; /* sitd per split iso urb */
struct timer_list watchdog;
- struct notifier_block reboot_notifier;
unsigned long actions;
unsigned stamp;
unsigned long next_statechange;
@@ -104,7 +103,7 @@ struct ehci_hcd { /* one per controller */
#endif
};
-/* convert between an HCD pointer and the corresponding EHCI_HCD */
+/* convert between an HCD pointer and the corresponding EHCI_HCD */
static inline struct ehci_hcd *hcd_to_ehci (struct usb_hcd *hcd)
{
return (struct ehci_hcd *) (hcd->hcd_priv);
@@ -179,8 +178,8 @@ struct ehci_caps {
#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
#define HCS_N_CC(p) (((p)>>12)&0xf) /* bits 15:12, #companion HCs */
#define HCS_N_PCC(p) (((p)>>8)&0xf) /* bits 11:8, ports per CC */
-#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
+#define HCS_PORTROUTED(p) ((p)&(1 << 7)) /* true: port routing */
+#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
u32 hcc_params; /* HCCPARAMS - offset 0x8 */
@@ -205,7 +204,7 @@ struct ehci_regs {
#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
#define CMD_IAAD (1<<6) /* "doorbell" interrupt async advance */
#define CMD_ASE (1<<5) /* async schedule enable */
-#define CMD_PSE (1<<4) /* periodic schedule enable */
+#define CMD_PSE (1<<4) /* periodic schedule enable */
/* 3:2 is periodic frame list size */
#define CMD_RESET (1<<1) /* reset HC not bus */
#define CMD_RUN (1<<0) /* start/stop HC */
@@ -231,9 +230,9 @@ struct ehci_regs {
/* FRINDEX: offset 0x0C */
u32 frame_index; /* current microframe number */
/* CTRLDSSEGMENT: offset 0x10 */
- u32 segment; /* address bits 63:32 if needed */
+ u32 segment; /* address bits 63:32 if needed */
/* PERIODICLISTBASE: offset 0x14 */
- u32 frame_list; /* points to periodic list */
+ u32 frame_list; /* points to periodic list */
/* ASYNCLISTADDR: offset 0x18 */
u32 async_next; /* address of next async queue head */
@@ -302,7 +301,7 @@ struct ehci_dbg_port {
/*
* EHCI Specification 0.95 Section 3.5
- * QTD: describe data transfer components (buffer, direction, ...)
+ * QTD: describe data transfer components (buffer, direction, ...)
* See Fig 3-6 "Queue Element Transfer Descriptor Block Diagram".
*
* These are associated only with "QH" (Queue Head) structures,
@@ -312,7 +311,7 @@ struct ehci_qtd {
/* first part defined by EHCI spec */
__le32 hw_next; /* see EHCI 3.5.1 */
__le32 hw_alt_next; /* see EHCI 3.5.2 */
- __le32 hw_token; /* see EHCI 3.5.3 */
+ __le32 hw_token; /* see EHCI 3.5.3 */
#define QTD_TOGGLE (1 << 31) /* data toggle */
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
#define QTD_IOC (1 << 15) /* interrupt on complete */
@@ -349,8 +348,8 @@ struct ehci_qtd {
/* values for that type tag */
#define Q_TYPE_ITD __constant_cpu_to_le32 (0 << 1)
#define Q_TYPE_QH __constant_cpu_to_le32 (1 << 1)
-#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
-#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
+#define Q_TYPE_SITD __constant_cpu_to_le32 (2 << 1)
+#define Q_TYPE_FSTN __constant_cpu_to_le32 (3 << 1)
/* next async queue entry, or pointer to interrupt/periodic QH */
#define QH_NEXT(dma) (cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
@@ -367,7 +366,7 @@ struct ehci_qtd {
* For entries in the async schedule, the type tag always says "qh".
*/
union ehci_shadow {
- struct ehci_qh *qh; /* Q_TYPE_QH */
+ struct ehci_qh *qh; /* Q_TYPE_QH */
struct ehci_itd *itd; /* Q_TYPE_ITD */
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
@@ -397,7 +396,7 @@ struct ehci_qh {
#define QH_HUBPORT 0x3f800000
#define QH_MULT 0xc0000000
__le32 hw_current; /* qtd list - see EHCI 3.6.4 */
-
+
/* qtd overlay (hardware parts of a struct ehci_qtd) */
__le32 hw_qtd_next;
__le32 hw_alt_next;
@@ -472,7 +471,7 @@ struct ehci_iso_stream {
struct list_head td_list; /* queued itds/sitds */
struct list_head free_list; /* list of unused itds/sitds */
struct usb_device *udev;
- struct usb_host_endpoint *ep;
+ struct usb_host_endpoint *ep;
/* output of (re)scheduling */
unsigned long start; /* jiffies */
@@ -492,8 +491,8 @@ struct ehci_iso_stream {
unsigned bandwidth;
/* This is used to initialize iTD's hw_bufp fields */
- __le32 buf0;
- __le32 buf1;
+ __le32 buf0;
+ __le32 buf1;
__le32 buf2;
/* this is used to initialize sITD's tt info */
@@ -521,7 +520,7 @@ struct ehci_itd {
#define ITD_ACTIVE __constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
- __le32 hw_bufp [7]; /* see EHCI 3.3.3 */
+ __le32 hw_bufp [7]; /* see EHCI 3.3.3 */
__le32 hw_bufp_hi [7]; /* Appendix B */
/* the rest is HCD-private */
@@ -542,7 +541,7 @@ struct ehci_itd {
/*-------------------------------------------------------------------------*/
/*
- * EHCI Specification 0.95 Section 3.4
+ * EHCI Specification 0.95 Section 3.4
* siTD, aka split-transaction isochronous Transfer Descriptor
* ... describe full speed iso xfers through TT in hubs
* see Figure 3-5 "Split-transaction Isochronous Transaction Descriptor (siTD)
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index 61e571782cf7..87eca6aeacf2 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -478,9 +478,9 @@ static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags);
static int etrax_usb_unlink_urb(struct urb *urb, int status);
static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
-static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs);
-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs);
-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs);
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc);
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc);
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc);
static void etrax_usb_hc_interrupt_bottom_half(void *data);
static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data);
@@ -1573,7 +1573,7 @@ static int etrax_usb_get_frame_number(struct usb_device *usb_dev)
return (*R_USB_FM_NUMBER & 0x7ff);
}
-static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+static irqreturn_t etrax_usb_tx_interrupt(int irq, void *vhc)
{
DBFENTER;
@@ -1839,7 +1839,7 @@ static void etrax_usb_isoc_descr_interrupt_bottom_half(void *data)
-static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs)
+static irqreturn_t etrax_usb_rx_interrupt(int irq, void *vhc)
{
struct urb *urb;
etrax_urb_priv_t *urb_priv;
@@ -3280,7 +3280,7 @@ static void etrax_usb_complete_urb(struct urb *urb, int status)
-static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc, struct pt_regs *regs)
+static irqreturn_t etrax_usb_hc_interrupt_top_half(int irq, void *vhc)
{
usb_interrupt_registers_t *reg;
unsigned long flags;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 5147ed4a6662..2718b5dc4ec1 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -418,7 +418,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
processed urbs.
*/
static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
- struct urb *urb, struct pt_regs *regs)
+ struct urb *urb)
__releases(isp116x->lock) __acquires(isp116x->lock)
{
unsigned i;
@@ -432,7 +432,7 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
urb_dbg(urb, "Finish");
spin_unlock(&isp116x->lock);
- usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, regs);
+ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
spin_lock(&isp116x->lock);
/* take idle endpoints out of the schedule */
@@ -568,7 +568,7 @@ static void start_atl_transfers(struct isp116x *isp116x)
/*
Finish the processed transfers
*/
-static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs)
+static void finish_atl_transfers(struct isp116x *isp116x)
{
struct isp116x_ep *ep;
struct urb *urb;
@@ -590,12 +590,12 @@ static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs)
occured, while URB_SHORT_NOT_OK was set */
if (urb && urb->status != -EINPROGRESS
&& ep->nextpid != USB_PID_ACK)
- finish_request(isp116x, ep, urb, regs);
+ finish_request(isp116x, ep, urb);
}
atomic_dec(&isp116x->atl_finishing);
}
-static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+static irqreturn_t isp116x_irq(struct usb_hcd *hcd)
{
struct isp116x *isp116x = hcd_to_isp116x(hcd);
u16 irqstat;
@@ -608,7 +608,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
ret = IRQ_HANDLED;
- finish_atl_transfers(isp116x, regs);
+ finish_atl_transfers(isp116x);
}
if (irqstat & HCuPINT_OPR) {
@@ -824,7 +824,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock(&urb->lock);
- finish_request(isp116x, ep, urb, NULL);
+ finish_request(isp116x, ep, urb);
ret = 0;
goto fail;
}
@@ -870,7 +870,7 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
}
if (urb)
- finish_request(isp116x, ep, urb, NULL);
+ finish_request(isp116x, ep, urb);
spin_unlock_irqrestore(&isp116x->lock, flags);
return 0;
@@ -1204,10 +1204,10 @@ static int isp116x_show_dbg(struct seq_file *s, void *unused)
static int isp116x_open_seq(struct inode *inode, struct file *file)
{
- return single_open(file, isp116x_show_dbg, inode->u.generic_ip);
+ return single_open(file, isp116x_show_dbg, inode->i_private);
}
-static struct file_operations isp116x_debug_fops = {
+static const struct file_operations isp116x_debug_fops = {
.open = isp116x_open_seq,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
index a1b7c3813d3a..b91e2edd9c5c 100644
--- a/drivers/usb/host/isp116x.h
+++ b/drivers/usb/host/isp116x.h
@@ -233,7 +233,7 @@ static const int cc_to_error[16] = {
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
- /* DevNotResp */ -ETIMEDOUT,
+ /* DevNotResp */ -ETIME,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 85cc059705a6..b466581beb4a 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -193,7 +193,7 @@ ohci_at91_start (struct usb_hcd *hcd)
if ((ret = ohci_init(ohci)) < 0)
return ret;
- root->maxchild = board->ports;
+ ohci->num_ports = board->ports;
if ((ret = ohci_run(ohci)) < 0) {
err("can't start %s", hcd->self.bus_name);
@@ -221,6 +221,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.start = ohci_at91_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -239,7 +240,7 @@ static const struct hc_driver ohci_at91_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
-
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -296,6 +297,7 @@ static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
if (!clocked) {
clk_enable(iclk);
clk_enable(fclk);
+ clocked = 1;
}
return 0;
@@ -310,6 +312,7 @@ MODULE_ALIAS("at91_ohci");
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver = {
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index f7a975d5db09..24e23c5783d8 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -268,11 +268,8 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_au1xxx_start,
-#ifdef CONFIG_PM
- /* suspend: ohci_au1xxx_suspend, -- tbd */
- /* resume: ohci_au1xxx_resume, -- tbd */
-#endif /*CONFIG_PM*/
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -291,6 +288,7 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -338,6 +336,7 @@ static int ohci_hcd_au1xxx_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_au1xxx_driver = {
.probe = ohci_hcd_au1xxx_drv_probe,
.remove = ohci_hcd_au1xxx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_au1xxx_drv_suspend, */
/*.resume = ohci_hcd_au1xxx_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 7bfffcbbd226..8293c1d4be3f 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -477,7 +477,7 @@ show_async (struct class_device *class_dev, char *buf)
unsigned long flags;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
/* display control and bulk lists together, for simplicity */
@@ -510,7 +510,7 @@ show_periodic (struct class_device *class_dev, char *buf)
seen_count = 0;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
next = buf;
size = PAGE_SIZE;
@@ -607,7 +607,7 @@ show_registers (struct class_device *class_dev, char *buf)
u32 rdata;
bus = class_get_devdata(class_dev);
- hcd = bus->hcpriv;
+ hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
regs = ohci->regs;
next = buf;
@@ -667,6 +667,11 @@ show_registers (struct class_device *class_dev, char *buf)
size -= temp;
next += temp;
+ temp = scnprintf (next, size, "hub poll timer %s\n",
+ ohci_to_hcd(ohci)->poll_rh ? "ON" : "off");
+ size -= temp;
+ next += temp;
+
/* roothub */
ohci_dump_roothub (ohci, 1, &next, &size);
@@ -680,10 +685,11 @@ static CLASS_DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
static inline void create_debug_files (struct ohci_hcd *ohci)
{
struct class_device *cldev = ohci_to_hcd(ohci)->self.class_dev;
+ int retval;
- class_device_create_file(cldev, &class_device_attr_async);
- class_device_create_file(cldev, &class_device_attr_periodic);
- class_device_create_file(cldev, &class_device_attr_registers);
+ retval = class_device_create_file(cldev, &class_device_attr_async);
+ retval = class_device_create_file(cldev, &class_device_attr_periodic);
+ retval = class_device_create_file(cldev, &class_device_attr_registers);
ohci_dbg (ohci, "created debug files\n");
}
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 6531c4d26527..1bf5e7a4e735 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -128,12 +128,14 @@ static struct hc_driver ohci_ep93xx_hc_driver = {
.flags = HCD_USB11 | HCD_MEMORY,
.start = ohci_ep93xx_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
.urb_enqueue = ohci_urb_enqueue,
.urb_dequeue = ohci_urb_dequeue,
.endpoint_disable = ohci_endpoint_disable,
.get_frame_number = ohci_get_frame,
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -202,6 +204,7 @@ static int ohci_hcd_ep93xx_drv_resume(struct platform_device *pdev)
static struct platform_driver ohci_hcd_ep93xx_driver = {
.probe = ohci_hcd_ep93xx_drv_probe,
.remove = ohci_hcd_ep93xx_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_ep93xx_drv_suspend,
.resume = ohci_hcd_ep93xx_drv_resume,
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 94d8cf4b36c1..9be6b303e784 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -88,7 +88,7 @@
#include <linux/timer.h>
#include <linux/list.h>
#include <linux/usb.h>
-#include <linux/usb_otg.h>
+#include <linux/usb/otg.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/reboot.h>
@@ -101,7 +101,7 @@
#include "../core/hcd.h"
-#define DRIVER_VERSION "2005 April 22"
+#define DRIVER_VERSION "2006 August 04"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -110,9 +110,10 @@
#undef OHCI_VERBOSE_DEBUG /* not always helpful */
/* For initializing controller (mask in an HCFS mode too) */
-#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
+#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
#define OHCI_INTR_INIT \
- (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_WDH)
+ (OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_UE \
+ | OHCI_INTR_RD | OHCI_INTR_WDH)
#ifdef __hppa__
/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
@@ -128,12 +129,13 @@
static const char hcd_name [] = "ohci_hcd";
+#define STATECHANGE_DELAY msecs_to_jiffies(300)
+
#include "ohci.h"
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
-static int ohci_reboot (struct notifier_block *, unsigned long , void *);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -259,7 +261,7 @@ static int ohci_urb_enqueue (
if (urb->status != -EINPROGRESS) {
spin_unlock (&urb->lock);
urb->hcpriv = urb_priv;
- finish_urb (ohci, urb, NULL);
+ finish_urb (ohci, urb);
retval = 0;
goto fail;
}
@@ -335,7 +337,7 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
* any more ... just clean up every urb's memory.
*/
if (urb->hcpriv)
- finish_urb (ohci, urb, NULL);
+ finish_urb (ohci, urb);
}
spin_unlock_irqrestore (&ohci->lock, flags);
return 0;
@@ -367,7 +369,7 @@ rescan:
if (!HC_IS_RUNNING (hcd->state)) {
sanitize:
ed->state = ED_IDLE;
- finish_unlinks (ohci, 0, NULL);
+ finish_unlinks (ohci, 0);
}
switch (ed->state) {
@@ -416,21 +418,20 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
}
-/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
+/* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and
* other cases where the next software may expect clean state from the
* "firmware". this is bus-neutral, unlike shutdown() methods.
*/
-static int
-ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
+static void
+ohci_shutdown (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci;
- ohci = container_of (block, struct ohci_hcd, reboot_notifier);
+ ohci = hcd_to_ohci (hcd);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
ohci_usb_reset (ohci);
/* flush the writes */
(void) ohci_readl (ohci, &ohci->regs->control);
- return 0;
}
/*-------------------------------------------------------------------------*
@@ -446,7 +447,6 @@ static int ohci_init (struct ohci_hcd *ohci)
disable (ohci);
ohci->regs = hcd->regs;
- ohci->next_statechange = jiffies;
/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
* was never needed for most non-PCI systems ... remove the code?
@@ -502,7 +502,6 @@ static int ohci_init (struct ohci_hcd *ohci)
if ((ret = ohci_mem_init (ohci)) < 0)
ohci_stop (hcd);
else {
- register_reboot_notifier (&ohci->reboot_notifier);
create_debug_files (ohci);
}
@@ -637,10 +636,14 @@ retry:
return -EOVERFLOW;
}
- /* start controller operations */
+ /* use rhsc irqs after khubd is fully initialized */
+ hcd->poll_rh = 1;
+ hcd->uses_new_polling = 1;
+
+ /* start controller operations */
ohci->hc_control &= OHCI_CTRL_RWC;
- ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
- ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+ ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
+ ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
hcd->state = HC_STATE_RUNNING;
/* wake on ConnectStatusChange, matching external hubs */
@@ -648,7 +651,7 @@ retry:
/* Choose the interrupts we care about now, others later on demand */
mask = OHCI_INTR_INIT;
- ohci_writel (ohci, mask, &ohci->regs->intrstatus);
+ ohci_writel (ohci, ~0, &ohci->regs->intrstatus);
ohci_writel (ohci, mask, &ohci->regs->intrenable);
/* handle root hub init quirks ... */
@@ -672,6 +675,7 @@ retry:
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
+ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
spin_unlock_irq (&ohci->lock);
// POTPGT delay is bits 24-31, in 2 ms units.
@@ -687,7 +691,7 @@ retry:
/* an interrupt happens */
-static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
+static irqreturn_t ohci_irq (struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ohci_regs __iomem *regs = ohci->regs;
@@ -709,7 +713,14 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
/* interrupt for some other device? */
} else if ((ints &= ohci_readl (ohci, &regs->intrenable)) == 0) {
return IRQ_NOTMINE;
- }
+ }
+
+ if (ints & OHCI_INTR_RHSC) {
+ ohci_vdbg (ohci, "rhsc\n");
+ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
+ ohci_writel (ohci, OHCI_INTR_RHSC, &regs->intrstatus);
+ usb_hcd_poll_rh_status(hcd);
+ }
if (ints & OHCI_INTR_UE) {
disable (ohci);
@@ -723,15 +734,20 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
if (ints & OHCI_INTR_RD) {
ohci_vdbg (ohci, "resume detect\n");
ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
- if (hcd->state != HC_STATE_QUIESCING)
+ hcd->poll_rh = 1;
+ if (ohci->autostop) {
+ spin_lock (&ohci->lock);
+ ohci_rh_resume (ohci);
+ spin_unlock (&ohci->lock);
+ } else
usb_hcd_resume_root_hub(hcd);
}
if (ints & OHCI_INTR_WDH) {
if (HC_IS_RUNNING(hcd->state))
- ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);
+ ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrdisable);
spin_lock (&ohci->lock);
- dl_done_list (ohci, ptregs);
+ dl_done_list (ohci);
spin_unlock (&ohci->lock);
if (HC_IS_RUNNING(hcd->state))
ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
@@ -744,7 +760,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
*/
spin_lock (&ohci->lock);
if (ohci->ed_rm_list)
- finish_unlinks (ohci, ohci_frame_no(ohci), ptregs);
+ finish_unlinks (ohci, ohci_frame_no(ohci));
if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
&& HC_IS_RUNNING(hcd->state))
ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
@@ -775,9 +791,10 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci_usb_reset (ohci);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
-
+ free_irq(hcd->irq, hcd);
+ hcd->irq = -1;
+
remove_debug_files (ohci);
- unregister_reboot_notifier (&ohci->reboot_notifier);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
dma_free_coherent (hcd->self.controller,
@@ -835,7 +852,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
urb->status = -ESHUTDOWN;
spin_unlock (&urb->lock);
}
- finish_unlinks (ohci, 0, NULL);
+ finish_unlinks (ohci, 0);
spin_unlock_irq(&ohci->lock);
/* paranoia, in case that didn't work: */
@@ -917,6 +934,10 @@ MODULE_LICENSE ("GPL");
#include "ohci-at91.c"
#endif
+#ifdef CONFIG_ARCH_PNX4008
+#include "ohci-pnx4008.c"
+#endif
+
#if !(defined(CONFIG_PCI) \
|| defined(CONFIG_SA1111) \
|| defined(CONFIG_ARCH_S3C2410) \
@@ -928,6 +949,7 @@ MODULE_LICENSE ("GPL");
|| defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
|| defined (CONFIG_ARCH_AT91RM9200) \
|| defined (CONFIG_ARCH_AT91SAM9261) \
+ || defined (CONFIG_ARCH_PNX4008) \
)
#error "missing bus glue for ohci-hcd"
#endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 5b0a23fd798b..6f113596af66 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -36,27 +36,25 @@
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_PM
+/* hcd->hub_irq_enable() */
+static void ohci_rhsc_enable (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable);
+}
#define OHCI_SCHED_ENABLES \
(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
-static void dl_done_list (struct ohci_hcd *, struct pt_regs *);
-static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
-static int ohci_restart (struct ohci_hcd *ohci);
+static void dl_done_list (struct ohci_hcd *);
+static void finish_unlinks (struct ohci_hcd *, u16);
-static int ohci_bus_suspend (struct usb_hcd *hcd)
+static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
+__releases(ohci->lock)
+__acquires(ohci->lock)
{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int status = 0;
- unsigned long flags;
-
- spin_lock_irqsave (&ohci->lock, flags);
-
- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
- spin_unlock_irqrestore (&ohci->lock, flags);
- return -ESHUTDOWN;
- }
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
@@ -72,15 +70,16 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
ohci_dbg (ohci, "needs reinit!\n");
goto done;
case OHCI_USB_SUSPEND:
- ohci_dbg (ohci, "already suspended\n");
- goto done;
+ if (!ohci->autostop) {
+ ohci_dbg (ohci, "already suspended\n");
+ goto done;
+ }
}
- ohci_dbg (ohci, "suspend root hub\n");
+ ohci_dbg (ohci, "%s root hub\n",
+ autostop ? "auto-stop" : "suspend");
/* First stop any processing */
- if (ohci->hc_control & OHCI_SCHED_ENABLES) {
- int limit;
-
+ if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) {
ohci->hc_control &= ~OHCI_SCHED_ENABLES;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
@@ -90,27 +89,22 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
* then the last WDH could take 6+ msec
*/
ohci_dbg (ohci, "stopping schedules ...\n");
- limit = 2000;
- while (limit > 0) {
- udelay (250);
- limit =- 250;
- if (ohci_readl (ohci, &ohci->regs->intrstatus)
- & OHCI_INTR_SF)
- break;
- }
- dl_done_list (ohci, NULL);
- mdelay (7);
+ ohci->autostop = 0;
+ spin_unlock_irq (&ohci->lock);
+ msleep (8);
+ spin_lock_irq (&ohci->lock);
}
- dl_done_list (ohci, NULL);
- finish_unlinks (ohci, ohci_frame_no(ohci), NULL);
- ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
- &ohci->regs->intrstatus);
+ dl_done_list (ohci);
+ finish_unlinks (ohci, ohci_frame_no(ohci));
/* maybe resume can wake root hub */
- if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev))
+ if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) ||
+ autostop)
ohci->hc_control |= OHCI_CTRL_RWE;
- else
+ else {
+ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
ohci->hc_control &= ~OHCI_CTRL_RWE;
+ }
/* Suspend hub ... this is the "global (to this bus) suspend" mode,
* which doesn't imply ports will first be individually suspended.
@@ -121,13 +115,12 @@ static int ohci_bus_suspend (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
/* no resumes until devices finish suspending */
- ohci->next_statechange = jiffies + msecs_to_jiffies (5);
+ if (!autostop) {
+ ohci->next_statechange = jiffies + msecs_to_jiffies (5);
+ ohci->autostop = 0;
+ }
done:
- /* external suspend vs self autosuspend ... same effect */
- if (status == 0)
- usb_hcd_suspend_root_hub(hcd);
- spin_unlock_irqrestore (&ohci->lock, flags);
return status;
}
@@ -139,25 +132,19 @@ static inline struct ed *find_head (struct ed *ed)
return ed;
}
+static int ohci_restart (struct ohci_hcd *ohci);
+
/* caller has locked the root hub */
-static int ohci_bus_resume (struct usb_hcd *hcd)
+static int ohci_rh_resume (struct ohci_hcd *ohci)
+__releases(ohci->lock)
+__acquires(ohci->lock)
{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ struct usb_hcd *hcd = ohci_to_hcd (ohci);
u32 temp, enables;
int status = -EINPROGRESS;
- unsigned long flags;
-
- if (time_before (jiffies, ohci->next_statechange))
- msleep(5);
-
- spin_lock_irqsave (&ohci->lock, flags);
-
- if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) {
- spin_unlock_irqrestore (&ohci->lock, flags);
- return -ESHUTDOWN;
- }
-
+ int autostopped = ohci->autostop;
+ ohci->autostop = 0;
ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
@@ -177,7 +164,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
ohci->hc_control |= OHCI_USB_RESUME;
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
(void) ohci_readl (ohci, &ohci->regs->control);
- ohci_dbg (ohci, "resume root hub\n");
+ ohci_dbg (ohci, "%s root hub\n",
+ autostopped ? "auto-start" : "resume");
break;
case OHCI_USB_RESUME:
/* HCFS changes sometime after INTR_RD */
@@ -192,16 +180,24 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
ohci_dbg (ohci, "lost power\n");
status = -EBUSY;
}
- spin_unlock_irqrestore (&ohci->lock, flags);
+#ifdef CONFIG_PM
if (status == -EBUSY) {
- (void) ohci_init (ohci);
- return ohci_restart (ohci);
+ if (!autostopped) {
+ spin_unlock_irq (&ohci->lock);
+ (void) ohci_init (ohci);
+ status = ohci_restart (ohci);
+ spin_lock_irq (&ohci->lock);
+ }
+ return status;
}
+#endif
if (status != -EINPROGRESS)
return status;
+ if (autostopped)
+ goto skip_resume;
+ spin_unlock_irq (&ohci->lock);
temp = ohci->num_ports;
- enables = 0;
while (temp--) {
u32 stat = ohci_readl (ohci,
&ohci->regs->roothub.portstatus [temp]);
@@ -234,17 +230,21 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
/* Sometimes PCI D3 suspend trashes frame timings ... */
periodic_reinit (ohci);
+ /* the following code is executed with ohci->lock held and
+ * irqs disabled if and only if autostopped is true
+ */
+
+skip_resume:
/* interrupts might have been disabled */
ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable);
if (ohci->ed_rm_list)
ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable);
- ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus),
- &ohci->regs->intrstatus);
/* Then re-enable operations */
ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control);
(void) ohci_readl (ohci, &ohci->regs->control);
- msleep (3);
+ if (!autostopped)
+ msleep (3);
temp = ohci->hc_control;
temp &= OHCI_CTRL_RWC;
@@ -254,10 +254,14 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
(void) ohci_readl (ohci, &ohci->regs->control);
/* TRSMRCY */
- msleep (10);
+ if (!autostopped) {
+ msleep (10);
+ spin_lock_irq (&ohci->lock);
+ }
+ /* now ohci->lock is always held and irqs are always disabled */
- /* keep it alive for ~5x suspend + resume costs */
- ohci->next_statechange = jiffies + msecs_to_jiffies (250);
+ /* keep it alive for more than ~5x suspend + resume costs */
+ ohci->next_statechange = jiffies + STATECHANGE_DELAY;
/* maybe turn schedules back on */
enables = 0;
@@ -291,6 +295,45 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
return 0;
}
+#ifdef CONFIG_PM
+
+static int ohci_bus_suspend (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int rc;
+
+ spin_lock_irq (&ohci->lock);
+
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+ rc = -ESHUTDOWN;
+ else
+ rc = ohci_rh_suspend (ohci, 0);
+ spin_unlock_irq (&ohci->lock);
+ return rc;
+}
+
+static int ohci_bus_resume (struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+ int rc;
+
+ if (time_before (jiffies, ohci->next_statechange))
+ msleep(5);
+
+ spin_lock_irq (&ohci->lock);
+
+ if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)))
+ rc = -ESHUTDOWN;
+ else
+ rc = ohci_rh_resume (ohci);
+ spin_unlock_irq (&ohci->lock);
+
+ /* poll until we know a device is connected or we autostop */
+ if (rc == 0)
+ usb_hcd_poll_rh_status(hcd);
+ return rc;
+}
+
#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@@ -302,20 +345,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int i, changed = 0, length = 1;
- int can_suspend = device_may_wakeup(&hcd->self.root_hub->dev);
+ int any_connected = 0, rhsc_enabled = 1;
unsigned long flags;
spin_lock_irqsave (&ohci->lock, flags);
- /* handle autosuspended root: finish resuming before
- * letting khubd or root hub timer see state changes.
- */
- if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER
- || !HC_IS_RUNNING(hcd->state))) {
- can_suspend = 0;
- goto done;
- }
-
/* undocumented erratum seen on at least rev D */
if ((ohci->flags & OHCI_QUIRK_AMD756)
&& (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) {
@@ -339,6 +373,9 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
for (i = 0; i < ohci->num_ports; i++) {
u32 status = roothub_portstatus (ohci, i);
+ /* can't autostop if ports are connected */
+ any_connected |= (status & RH_PS_CCS);
+
if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
| RH_PS_OCIC | RH_PS_PRSC)) {
changed = 1;
@@ -346,39 +383,72 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf)
buf [0] |= 1 << (i + 1);
else
buf [1] |= 1 << (i - 7);
- continue;
}
-
- /* can suspend if no ports are enabled; or if all all
- * enabled ports are suspended AND remote wakeup is on.
- */
- if (!(status & RH_PS_CCS))
- continue;
- if ((status & RH_PS_PSS) && can_suspend)
- continue;
- can_suspend = 0;
}
-done:
- spin_unlock_irqrestore (&ohci->lock, flags);
-#ifdef CONFIG_PM
- /* save power by suspending idle root hubs;
- * INTR_RD wakes us when there's work
+ /* NOTE: vendors didn't always make the same implementation
+ * choices for RHSC. Sometimes it triggers on an edge (like
+ * setting and maybe clearing a port status change bit); and
+ * it's level-triggered on other silicon, active until khubd
+ * clears all active port status change bits. If it's still
+ * set (level-triggered) we must disable it and rely on
+ * polling until khubd re-enables it.
*/
- if (can_suspend
- && !changed
- && !ohci->ed_rm_list
- && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES)
- & ohci->hc_control)
- == OHCI_USB_OPER
- && time_after (jiffies, ohci->next_statechange)
- && usb_trylock_device (hcd->self.root_hub) == 0
- ) {
- ohci_vdbg (ohci, "autosuspend\n");
- (void) ohci_bus_suspend (hcd);
- usb_unlock_device (hcd->self.root_hub);
+ if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) {
+ ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable);
+ (void) ohci_readl (ohci, &ohci->regs->intrdisable);
+ rhsc_enabled = 0;
}
-#endif
+ hcd->poll_rh = 1;
+
+ /* carry out appropriate state changes */
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+
+ case OHCI_USB_OPER:
+ /* keep on polling until we know a device is connected
+ * and RHSC is enabled */
+ if (!ohci->autostop) {
+ if (any_connected) {
+ if (rhsc_enabled)
+ hcd->poll_rh = 0;
+ } else {
+ ohci->autostop = 1;
+ ohci->next_statechange = jiffies + HZ;
+ }
+
+ /* if no devices have been attached for one second, autostop */
+ } else {
+ if (changed || any_connected) {
+ ohci->autostop = 0;
+ ohci->next_statechange = jiffies +
+ STATECHANGE_DELAY;
+ } else if (time_after_eq (jiffies,
+ ohci->next_statechange)
+ && !ohci->ed_rm_list
+ && !(ohci->hc_control &
+ OHCI_SCHED_ENABLES)) {
+ ohci_rh_suspend (ohci, 1);
+ }
+ }
+ break;
+
+ /* if there is a port change, autostart or ask to be resumed */
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ if (changed) {
+ if (ohci->autostop)
+ ohci_rh_resume (ohci);
+ else
+ usb_hcd_resume_root_hub (hcd);
+ } else {
+ /* everything is idle, no need for polling */
+ hcd->poll_rh = 0;
+ }
+ break;
+ }
+
+done:
+ spin_unlock_irqrestore (&ohci->lock, flags);
return changed ? length : 0;
}
@@ -550,9 +620,6 @@ static int ohci_hub_control (
break;
case USB_PORT_FEAT_SUSPEND:
temp = RH_PS_POCI;
- if ((ohci->hc_control & OHCI_CTRL_HCFS)
- != OHCI_USB_OPER)
- usb_hcd_resume_root_hub(hcd);
break;
case USB_PORT_FEAT_C_SUSPEND:
temp = RH_PS_PSSC;
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 5602da9bd52c..e121d97ed91c 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -173,11 +173,8 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_lh7a404_start,
-#ifdef CONFIG_PM
- /* suspend: ohci_lh7a404_suspend, -- tbd */
- /* resume: ohci_lh7a404_resume, -- tbd */
-#endif /*CONFIG_PM*/
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -196,6 +193,7 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -244,6 +242,7 @@ static int ohci_hcd_lh7a404_drv_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_lh7a404_driver = {
.probe = ohci_hcd_lh7a404_drv_probe,
.remove = ohci_hcd_lh7a404_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_lh7a404_drv_suspend, */
/*.resume = ohci_hcd_lh7a404_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index bfbe328a4788..d976614eebd3 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
ohci->next_statechange = jiffies;
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
- ohci->reboot_notifier.notifier_call = ohci_reboot;
}
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index c4c4babd4767..9c02177de50a 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -4,7 +4,7 @@
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
* (C) Copyright 2000-2005 David Brownell
* (C) Copyright 2002 Hewlett-Packard Company
- *
+ *
* OMAP Bus Glue
*
* Modified for OMAP by Tony Lindgren <tony@atomide.com>
@@ -66,15 +66,20 @@ extern int usb_disabled(void);
extern int ocpi_enable(void);
static struct clk *usb_host_ck;
+static struct clk *usb_dc_ck;
+static int host_enabled;
+static int host_initialized;
static void omap_ohci_clock_power(int on)
{
if (on) {
+ clk_enable(usb_dc_ck);
clk_enable(usb_host_ck);
/* guesstimate for T5 == 1x 32K clock + APLL lock time */
udelay(100);
} else {
clk_disable(usb_host_ck);
+ clk_disable(usb_dc_ck);
}
}
@@ -87,14 +92,14 @@ static int omap_ohci_transceiver_power(int on)
if (on) {
if (machine_is_omap_innovator() && cpu_is_omap1510())
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
- | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
+ | ((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (machine_is_omap_osk())
tps65010_set_gpio_out_value(GPIO1, LOW);
} else {
if (machine_is_omap_innovator() && cpu_is_omap1510())
fpga_write(fpga_read(INNOVATOR_FPGA_CAM_USB_CONTROL)
- & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
+ & ~((1 << 5/*usb1*/) | (1 << 3/*usb2*/)),
INNOVATOR_FPGA_CAM_USB_CONTROL);
else if (machine_is_omap_osk())
tps65010_set_gpio_out_value(GPIO1, HIGH);
@@ -103,6 +108,7 @@ static int omap_ohci_transceiver_power(int on)
return 0;
}
+#ifdef CONFIG_ARCH_OMAP15XX
/*
* OMAP-1510 specific Local Bus clock on/off
*/
@@ -121,8 +127,8 @@ static int omap_1510_local_bus_power(int on)
/*
* OMAP-1510 specific Local Bus initialization
* NOTE: This assumes 32MB memory size in OMAP1510LB_MEMSIZE.
- * See also arch/mach-omap/memory.h for __virt_to_dma() and
- * __dma_to_virt() which need to match with the physical
+ * See also arch/mach-omap/memory.h for __virt_to_dma() and
+ * __dma_to_virt() which need to match with the physical
* Local Bus address below.
*/
static int omap_1510_local_bus_init(void)
@@ -130,7 +136,7 @@ static int omap_1510_local_bus_init(void)
unsigned int tlb;
unsigned long lbaddr, physaddr;
- omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
+ omap_writel((omap_readl(OMAP1510_LB_CLOCK_DIV) & 0xfffffff8) | 0x4,
OMAP1510_LB_CLOCK_DIV);
/* Configure the Local Bus MMU table */
@@ -138,7 +144,7 @@ static int omap_1510_local_bus_init(void)
lbaddr = tlb * 0x00100000 + OMAP1510_LB_OFFSET;
physaddr = tlb * 0x00100000 + PHYS_OFFSET;
omap_writel((lbaddr & 0x0fffffff) >> 22, OMAP1510_LB_MMU_CAM_H);
- omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
+ omap_writel(((lbaddr & 0x003ffc00) >> 6) | 0xc,
OMAP1510_LB_MMU_CAM_L);
omap_writel(physaddr >> 16, OMAP1510_LB_MMU_RAM_H);
omap_writel((physaddr & 0x0000fc00) | 0x300, OMAP1510_LB_MMU_RAM_L);
@@ -152,6 +158,10 @@ static int omap_1510_local_bus_init(void)
return 0;
}
+#else
+#define omap_1510_local_bus_power(x) {}
+#define omap_1510_local_bus_init() {}
+#endif
#ifdef CONFIG_USB_OTG
@@ -173,13 +183,14 @@ static void start_hnp(struct ohci_hcd *ohci)
/*-------------------------------------------------------------------------*/
-static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
+static int ohci_omap_init(struct usb_hcd *hcd)
{
- struct omap_usb_config *config = pdev->dev.platform_data;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ struct omap_usb_config *config = hcd->self.controller->platform_data;
int need_transceiver = (config->otg != 0);
int ret;
- dev_dbg(&pdev->dev, "starting USB Controller\n");
+ dev_dbg(hcd->self.controller, "starting USB Controller\n");
if (config->otg) {
ohci_to_hcd(ohci)->self.otg_port = config->otg;
@@ -200,7 +211,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
if (ohci->transceiver) {
int status = otg_set_host(ohci->transceiver,
&ohci_to_hcd(ohci)->self);
- dev_dbg(&pdev->dev, "init %s transceiver, status %d\n",
+ dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
ohci->transceiver->label, status);
if (status) {
if (ohci->transceiver)
@@ -208,7 +219,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
return status;
}
} else {
- dev_err(&pdev->dev, "can't find transceiver\n");
+ dev_err(hcd->self.controller, "can't find transceiver\n");
return -ENODEV;
}
}
@@ -247,6 +258,10 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
}
ohci_writel(ohci, rh, &ohci->regs->roothub.a);
distrust_firmware = 0;
+ } else if (machine_is_nokia770()) {
+ /* We require a self-powered hub, which should have
+ * plenty of power. */
+ ohci_to_hcd(ohci)->power_budget = 0;
}
/* FIXME khubd hub requests should manage power switching */
@@ -260,21 +275,15 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
return 0;
}
-static void omap_stop_hc(struct platform_device *pdev)
+static void ohci_omap_stop(struct usb_hcd *hcd)
{
- dev_dbg(&pdev->dev, "stopping USB Controller\n");
+ dev_dbg(hcd->self.controller, "stopping USB Controller\n");
omap_ohci_clock_power(0);
}
/*-------------------------------------------------------------------------*/
-void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
-
/**
* usb_hcd_omap_probe - initialize OMAP-based HCDs
* Context: !in_interrupt()
@@ -283,7 +292,7 @@ void usb_hcd_omap_remove (struct usb_hcd *, struct platform_device *);
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
-int usb_hcd_omap_probe (const struct hc_driver *driver,
+static int usb_hcd_omap_probe (const struct hc_driver *driver,
struct platform_device *pdev)
{
int retval, irq;
@@ -291,12 +300,12 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
struct ohci_hcd *ohci;
if (pdev->num_resources != 2) {
- printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
+ printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
pdev->num_resources);
return -ENODEV;
}
- if (pdev->resource[0].flags != IORESOURCE_MEM
+ if (pdev->resource[0].flags != IORESOURCE_MEM
|| pdev->resource[1].flags != IORESOURCE_IRQ) {
printk(KERN_ERR "hcd probe: invalid resource type\n");
return -ENODEV;
@@ -306,6 +315,17 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
if (IS_ERR(usb_host_ck))
return PTR_ERR(usb_host_ck);
+ if (!cpu_is_omap1510())
+ usb_dc_ck = clk_get(0, "usb_dc_ck");
+ else
+ usb_dc_ck = clk_get(0, "lb_ck");
+
+ if (IS_ERR(usb_dc_ck)) {
+ clk_put(usb_host_ck);
+ return PTR_ERR(usb_dc_ck);
+ }
+
+
hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
if (!hcd) {
retval = -ENOMEM;
@@ -325,9 +345,8 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
- retval = omap_start_hc(ohci, pdev);
- if (retval < 0)
- goto err2;
+ host_initialized = 0;
+ host_enabled = 1;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -335,15 +354,21 @@ int usb_hcd_omap_probe (const struct hc_driver *driver,
goto err2;
}
retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
- if (retval == 0)
- return retval;
+ if (retval)
+ goto err2;
+
+ host_initialized = 1;
+
+ if (!host_enabled)
+ omap_ohci_clock_power(0);
- omap_stop_hc(pdev);
+ return 0;
err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
err0:
+ clk_put(usb_dc_ck);
clk_put(usb_host_ck);
return retval;
}
@@ -359,31 +384,41 @@ err0:
* Reverses the effect of usb_hcd_omap_probe(), first invoking
* the HCD's stop() method. It is always called from a thread
* context, normally "rmmod", "apmd", or something similar.
- *
*/
-void usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
+static inline void
+usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
{
+ struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
usb_remove_hcd(hcd);
+ if (ohci->transceiver) {
+ (void) otg_set_host(ohci->transceiver, 0);
+ put_device(ohci->transceiver->dev);
+ }
if (machine_is_omap_osk())
omap_free_gpio(9);
- omap_stop_hc(pdev);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
+ clk_put(usb_dc_ck);
clk_put(usb_host_ck);
}
/*-------------------------------------------------------------------------*/
-static int __devinit
+static int
ohci_omap_start (struct usb_hcd *hcd)
{
struct omap_usb_config *config;
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int ret;
+ if (!host_enabled)
+ return 0;
config = hcd->self.controller->platform_data;
- if (config->otg || config->rwc)
+ if (config->otg || config->rwc) {
+ ohci->hc_control = OHCI_CTRL_RWC;
writel(OHCI_CTRL_RWC, &ohci->regs->control);
+ }
if ((ret = ohci_run (ohci)) < 0) {
dev_err(hcd->self.controller, "can't start\n");
@@ -409,8 +444,10 @@ static const struct hc_driver ohci_omap_hc_driver = {
/*
* basic lifecycle operations
*/
+ .reset = ohci_omap_init,
.start = ohci_omap_start,
- .stop = ohci_stop,
+ .stop = ohci_omap_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -429,6 +466,7 @@ static const struct hc_driver ohci_omap_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -446,13 +484,8 @@ static int ohci_hcd_omap_drv_probe(struct platform_device *dev)
static int ohci_hcd_omap_drv_remove(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
usb_hcd_omap_remove(hcd, dev);
- if (ohci->transceiver) {
- (void) otg_set_host(ohci->transceiver, 0);
- put_device(ohci->transceiver->dev);
- }
platform_set_drvdata(dev, NULL);
return 0;
@@ -472,7 +505,7 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
omap_ohci_clock_power(0);
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
- dev->power.power_state = PMSG_SUSPEND;
+ dev->dev.power.power_state = PMSG_SUSPEND;
return 0;
}
@@ -485,8 +518,8 @@ static int ohci_omap_resume(struct platform_device *dev)
ohci->next_statechange = jiffies;
omap_ohci_clock_power(1);
- dev->power.power_state = PMSG_ON;
- usb_hcd_resume_root_hub(dev_get_drvdata(dev));
+ dev->dev.power.power_state = PMSG_ON;
+ usb_hcd_resume_root_hub(platform_get_drvdata(dev));
return 0;
}
@@ -500,6 +533,7 @@ static int ohci_omap_resume(struct platform_device *dev)
static struct platform_driver ohci_hcd_omap_driver = {
.probe = ohci_hcd_omap_drv_probe,
.remove = ohci_hcd_omap_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_omap_suspend,
.resume = ohci_omap_resume,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 37e122812b67..874418552789 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -73,13 +73,14 @@ ohci_pci_start (struct usb_hcd *hcd)
else if (pdev->vendor == PCI_VENDOR_ID_NS) {
struct pci_dev *b;
- b = pci_find_slot (pdev->bus->number,
+ b = pci_get_slot (pdev->bus,
PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
&& b->vendor == PCI_VENDOR_ID_NS) {
ohci->flags |= OHCI_QUIRK_SUPERIO;
ohci_dbg (ohci, "Using NSC SuperIO setup\n");
}
+ pci_dev_put(b);
}
/* Check for Compaq's ZFMicro chipset, which needs short
@@ -176,11 +177,14 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.reset = ohci_pci_reset,
.start = ohci_pci_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
#ifdef CONFIG_PM
+ /* these suspend/resume entries are for upstream PCI glue ONLY */
.suspend = ohci_pci_suspend,
.resume = ohci_pci_resume,
#endif
- .stop = ohci_stop,
/*
* managing i/o requests and associated device resources
@@ -199,6 +203,7 @@ static const struct hc_driver ohci_pci_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -229,6 +234,8 @@ static struct pci_driver ohci_pci_driver = {
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
+
+ .shutdown = usb_hcd_pci_shutdown,
};
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
new file mode 100644
index 000000000000..2dbb77414905
--- /dev/null
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -0,0 +1,479 @@
+/*
+ * drivers/usb/host/ohci-pnx4008.c
+ *
+ * driver for Philips PNX4008 USB Host
+ *
+ * Authors: Dmitry Chigirev <source@mvista.com>
+ * Vitaly Wool <vitalywool@gmail.com>
+ *
+ * register initialization is based on code examples provided by Philips
+ * Copyright (c) 2005 Koninklijke Philips Electronics N.V.
+ *
+ * NOTE: This driver does not have suspend/resume functionality
+ * This driver is intended for engineering development purposes only
+ *
+ * 2005-2006 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/platform.h>
+#include <asm/arch/irqs.h>
+#include <asm/arch/gpio.h>
+
+#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
+
+/* USB_CTRL bit defines */
+#define USB_SLAVE_HCLK_EN (1 << 24)
+#define USB_HOST_NEED_CLK_EN (1 << 21)
+
+#define USB_OTG_CLK_CTRL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF4)
+#define USB_OTG_CLK_STAT IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF8)
+
+/* USB_OTG_CLK_CTRL bit defines */
+#define AHB_M_CLOCK_ON (1 << 4)
+#define OTG_CLOCK_ON (1 << 3)
+#define I2C_CLOCK_ON (1 << 2)
+#define DEV_CLOCK_ON (1 << 1)
+#define HOST_CLOCK_ON (1 << 0)
+
+#define USB_OTG_STAT_CONTROL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x110)
+
+/* USB_OTG_STAT_CONTROL bit defines */
+#define TRANSPARENT_I2C_EN (1 << 7)
+#define HOST_EN (1 << 0)
+
+/* ISP1301 USB transceiver I2C registers */
+#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */
+
+#define MC1_SPEED_REG (1 << 0)
+#define MC1_SUSPEND_REG (1 << 1)
+#define MC1_DAT_SE0 (1 << 2)
+#define MC1_TRANSPARENT (1 << 3)
+#define MC1_BDIS_ACON_EN (1 << 4)
+#define MC1_OE_INT_EN (1 << 5)
+#define MC1_UART_EN (1 << 6)
+#define MC1_MASK 0x7f
+
+#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */
+
+#define MC2_GLOBAL_PWR_DN (1 << 0)
+#define MC2_SPD_SUSP_CTRL (1 << 1)
+#define MC2_BI_DI (1 << 2)
+#define MC2_TRANSP_BDIR0 (1 << 3)
+#define MC2_TRANSP_BDIR1 (1 << 4)
+#define MC2_AUDIO_EN (1 << 5)
+#define MC2_PSW_EN (1 << 6)
+#define MC2_EN2V7 (1 << 7)
+
+#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */
+# define OTG1_DP_PULLUP (1 << 0)
+# define OTG1_DM_PULLUP (1 << 1)
+# define OTG1_DP_PULLDOWN (1 << 2)
+# define OTG1_DM_PULLDOWN (1 << 3)
+# define OTG1_ID_PULLDOWN (1 << 4)
+# define OTG1_VBUS_DRV (1 << 5)
+# define OTG1_VBUS_DISCHRG (1 << 6)
+# define OTG1_VBUS_CHRG (1 << 7)
+#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */
+# define OTG_B_SESS_END (1 << 6)
+# define OTG_B_SESS_VLD (1 << 7)
+
+#define ISP1301_I2C_ADDR 0x2C
+
+#define ISP1301_I2C_MODE_CONTROL_1 0x4
+#define ISP1301_I2C_MODE_CONTROL_2 0x12
+#define ISP1301_I2C_OTG_CONTROL_1 0x6
+#define ISP1301_I2C_OTG_CONTROL_2 0x10
+#define ISP1301_I2C_INTERRUPT_SOURCE 0x8
+#define ISP1301_I2C_INTERRUPT_LATCH 0xA
+#define ISP1301_I2C_INTERRUPT_FALLING 0xC
+#define ISP1301_I2C_INTERRUPT_RISING 0xE
+#define ISP1301_I2C_REG_CLEAR_ADDR 1
+
+struct i2c_driver isp1301_driver;
+struct i2c_client *isp1301_i2c_client;
+
+extern int usb_disabled(void);
+extern int ocpi_enable(void);
+
+static struct clk *usb_clk;
+
+static int isp1301_probe(struct i2c_adapter *adap);
+static int isp1301_detach(struct i2c_client *client);
+static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+ void *arg);
+
+static unsigned short normal_i2c[] =
+ { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END };
+static unsigned short dummy_i2c_addrlist[] = { I2C_CLIENT_END };
+
+static struct i2c_client_address_data addr_data = {
+ .normal_i2c = normal_i2c,
+ .probe = dummy_i2c_addrlist,
+ .ignore = dummy_i2c_addrlist,
+};
+
+struct i2c_driver isp1301_driver = {
+ .id = I2C_DRIVERID_I2CDEV, /* Fake Id */
+ .class = I2C_CLASS_HWMON,
+ .attach_adapter = isp1301_probe,
+ .detach_client = isp1301_detach,
+ .command = isp1301_command
+};
+
+static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
+{
+ struct i2c_client *c;
+
+ c = (struct i2c_client *)kzalloc(sizeof(*c), SLAB_KERNEL);
+
+ if (!c)
+ return -ENOMEM;
+
+ strcpy(c->name, "isp1301");
+ c->flags = 0;
+ c->addr = addr;
+ c->adapter = adap;
+ c->driver = &isp1301_driver;
+
+ isp1301_i2c_client = c;
+
+ return i2c_attach_client(c);
+}
+
+static int isp1301_probe(struct i2c_adapter *adap)
+{
+ return i2c_probe(adap, &addr_data, isp1301_attach);
+}
+
+static int isp1301_detach(struct i2c_client *client)
+{
+ i2c_detach_client(client);
+ kfree(isp1301_i2c_client);
+ return 0;
+}
+
+/* No commands defined */
+static int isp1301_command(struct i2c_client *client, unsigned int cmd,
+ void *arg)
+{
+ return 0;
+}
+
+static void i2c_write(u8 buf, u8 subaddr)
+{
+ char tmpbuf[2];
+
+ tmpbuf[0] = subaddr; /*register number */
+ tmpbuf[1] = buf; /*register data */
+ i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2);
+}
+
+static void isp1301_configure(void)
+{
+ /* PNX4008 only supports DAT_SE0 USB mode */
+ /* PNX4008 R2A requires setting the MAX603 to output 3.6V */
+ /* Power up externel charge-pump */
+
+ i2c_write(MC1_DAT_SE0 | MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1);
+ i2c_write(~(MC1_DAT_SE0 | MC1_SPEED_REG),
+ ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL,
+ ISP1301_I2C_MODE_CONTROL_2);
+ i2c_write(~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL),
+ ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN,
+ ISP1301_I2C_OTG_CONTROL_1);
+ i2c_write(~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN),
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(0xFF,
+ ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(0xFF,
+ ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_write(0xFF,
+ ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);
+
+}
+
+static inline void isp1301_vbus_on(void)
+{
+ i2c_write(OTG1_VBUS_DRV, ISP1301_I2C_OTG_CONTROL_1);
+}
+
+static inline void isp1301_vbus_off(void)
+{
+ i2c_write(OTG1_VBUS_DRV,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
+}
+
+static void pnx4008_start_hc(void)
+{
+ unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
+ __raw_writel(tmp, USB_OTG_STAT_CONTROL);
+ isp1301_vbus_on();
+}
+
+static void pnx4008_stop_hc(void)
+{
+ unsigned long tmp;
+ isp1301_vbus_off();
+ tmp = __raw_readl(USB_OTG_STAT_CONTROL) & ~HOST_EN;
+ __raw_writel(tmp, USB_OTG_STAT_CONTROL);
+}
+
+static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
+
+ if ((ret = ohci_init(ohci)) < 0)
+ return ret;
+
+ if ((ret = ohci_run(ohci)) < 0) {
+ dev_err(hcd->self.controller, "can't start\n");
+ ohci_stop(hcd);
+ return ret;
+ }
+ return 0;
+}
+
+static const struct hc_driver ohci_pnx4008_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "pnx4008 OHCI",
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+ /*
+ * basic lifecycle operations
+ */
+ .start = ohci_pnx4008_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
+
+static void pnx4008_set_usb_bits(void)
+{
+ start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
+ start_int_ack(SE_USB_OTG_ATX_INT_N);
+ start_int_umask(SE_USB_OTG_ATX_INT_N);
+
+ start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
+ start_int_ack(SE_USB_OTG_TIMER_INT);
+ start_int_umask(SE_USB_OTG_TIMER_INT);
+
+ start_int_set_rising_edge(SE_USB_I2C_INT);
+ start_int_ack(SE_USB_I2C_INT);
+ start_int_umask(SE_USB_I2C_INT);
+
+ start_int_set_rising_edge(SE_USB_INT);
+ start_int_ack(SE_USB_INT);
+ start_int_umask(SE_USB_INT);
+
+ start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
+ start_int_ack(SE_USB_NEED_CLK_INT);
+ start_int_umask(SE_USB_NEED_CLK_INT);
+
+ start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
+ start_int_ack(SE_USB_AHB_NEED_CLK_INT);
+ start_int_umask(SE_USB_AHB_NEED_CLK_INT);
+}
+
+static void pnx4008_unset_usb_bits(void)
+{
+ start_int_mask(SE_USB_OTG_ATX_INT_N);
+ start_int_mask(SE_USB_OTG_TIMER_INT);
+ start_int_mask(SE_USB_I2C_INT);
+ start_int_mask(SE_USB_INT);
+ start_int_mask(SE_USB_NEED_CLK_INT);
+ start_int_mask(SE_USB_AHB_NEED_CLK_INT);
+}
+
+static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = 0;
+ struct ohci_hcd *ohci;
+ const struct hc_driver *driver = &ohci_pnx4008_hc_driver;
+
+ int ret = 0, irq;
+
+ dev_dbg(&pdev->dev, "%s: " DRIVER_INFO " (pnx4008)\n", hcd_name);
+ if (usb_disabled()) {
+ err("USB is disabled");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (pdev->num_resources != 2
+ || pdev->resource[0].flags != IORESOURCE_MEM
+ || pdev->resource[1].flags != IORESOURCE_IRQ) {
+ err("Invalid resource configuration");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* Enable AHB slave USB clock, needed for further USB clock control */
+ __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL);
+
+ ret = i2c_add_driver(&isp1301_driver);
+ if (ret < 0) {
+ err("failed to connect I2C to ISP1301 USB Transceiver");
+ goto out;
+ }
+
+ isp1301_configure();
+
+ /* Enable USB PLL */
+ usb_clk = clk_get(&pdev->dev, "ck_pll5");
+ if (IS_ERR(usb_clk)) {
+ err("failed to acquire USB PLL");
+ ret = PTR_ERR(usb_clk);
+ goto out1;
+ }
+
+ ret = clk_enable(usb_clk);
+ if (ret < 0) {
+ err("failed to start USB PLL");
+ goto out2;
+ }
+
+ ret = clk_set_rate(usb_clk, 48000);
+ if (ret < 0) {
+ err("failed to set USB clock rate");
+ goto out3;
+ }
+
+ __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL);
+
+ /* Set to enable all needed USB clocks */
+ __raw_writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL);
+
+ while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) !=
+ USB_CLOCK_MASK) ;
+
+ hcd = usb_create_hcd (driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ err("Failed to allocate HC buffer");
+ ret = -ENOMEM;
+ goto out3;
+ }
+
+ /* Set all USB bits in the Start Enable register */
+ pnx4008_set_usb_bits();
+
+ hcd->rsrc_start = pdev->resource[0].start;
+ hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "request_mem_region failed\n");
+ ret = -ENOMEM;
+ goto out4;
+ }
+ hcd->regs = (void __iomem *)pdev->resource[0].start;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = -ENXIO;
+ goto out4;
+ }
+
+ pnx4008_start_hc();
+ platform_set_drvdata(pdev, hcd);
+ ohci = hcd_to_ohci(hcd);
+ ohci_hcd_init(ohci);
+
+ dev_info(&pdev->dev, "at 0x%p, irq %d\n", hcd->regs, hcd->irq);
+ ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ if (ret == 0)
+ return ret;
+
+ pnx4008_stop_hc();
+out4:
+ pnx4008_unset_usb_bits();
+ usb_put_hcd(hcd);
+out3:
+ clk_disable(usb_clk);
+out2:
+ clk_put(usb_clk);
+out1:
+ i2c_del_driver(&isp1301_driver);
+out:
+ return ret;
+}
+
+static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ pnx4008_stop_hc();
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ pnx4008_unset_usb_bits();
+ clk_disable(usb_clk);
+ clk_put(usb_clk);
+ i2c_del_driver(&isp1301_driver);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver usb_hcd_pnx4008_driver = {
+ .driver = {
+ .name = "usb-ohci",
+ },
+ .probe = usb_hcd_pnx4008_probe,
+ .remove = usb_hcd_pnx4008_remove,
+};
+
+static int __init usb_hcd_pnx4008_init(void)
+{
+ return platform_driver_register(&usb_hcd_pnx4008_driver);
+}
+
+static void __exit usb_hcd_pnx4008_cleanup(void)
+{
+ return platform_driver_unregister(&usb_hcd_pnx4008_driver);
+}
+
+module_init(usb_hcd_pnx4008_init);
+module_exit(usb_hcd_pnx4008_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 9fe56ff1615d..d9d1ae236bd5 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -148,6 +148,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.start = ohci_ppc_soc_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -166,6 +167,7 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -195,6 +197,7 @@ static int ohci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_ppc_soc_driver = {
.probe = ohci_hcd_ppc_soc_drv_probe,
.remove = ohci_hcd_ppc_soc_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
/*.suspend = ohci_hcd_ppc_soc_drv_suspend,*/
/*.resume = ohci_hcd_ppc_soc_drv_resume,*/
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 6f559e102789..e176b04d7aeb 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -270,6 +270,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.start = ohci_pxa27x_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -288,6 +289,7 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -357,6 +359,7 @@ static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev)
static struct platform_driver ohci_hcd_pxa27x_driver = {
.probe = ohci_hcd_pxa27x_drv_probe,
.remove = ohci_hcd_pxa27x_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
#ifdef CONFIG_PM
.suspend = ohci_hcd_pxa27x_drv_suspend,
.resume = ohci_hcd_pxa27x_drv_resume,
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index e372306ed0da..fe1fe2f97cb5 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -7,6 +7,8 @@
* This file is licenced under the GPL.
*/
+#include <linux/irq.h>
+
static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
{
int last = urb_priv->length - 1;
@@ -34,7 +36,7 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
* PRECONDITION: ohci lock held, irqs blocked.
*/
static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb, struct pt_regs *regs)
+finish_urb (struct ohci_hcd *ohci, struct urb *urb)
__releases(ohci->lock)
__acquires(ohci->lock)
{
@@ -73,7 +75,7 @@ __acquires(ohci->lock)
/* urb->complete() can reenter this HCD */
spin_unlock (&ohci->lock);
- usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb, regs);
+ usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
spin_lock (&ohci->lock);
/* stop periodic dma if it's not needed */
@@ -910,7 +912,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
/* there are some urbs/eds to unlink; called in_irq(), with HCD locked */
static void
-finish_unlinks (struct ohci_hcd *ohci, u16 tick, struct pt_regs *regs)
+finish_unlinks (struct ohci_hcd *ohci, u16 tick)
{
struct ed *ed, **last;
@@ -923,7 +925,7 @@ rescan_all:
/* only take off EDs that the HC isn't using, accounting for
* frame counter wraps and EDs with partially retired TDs
*/
- if (likely (regs && HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
+ if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
if (tick_before (tick, ed->tick)) {
skip_ed:
last = &ed->ed_next;
@@ -990,7 +992,7 @@ rescan_this:
/* if URB is done, clean up */
if (urb_priv->td_cnt == urb_priv->length) {
modified = completed = 1;
- finish_urb (ohci, urb, regs);
+ finish_urb (ohci, urb);
}
}
if (completed && !list_empty (&ed->td_list))
@@ -1068,7 +1070,7 @@ rescan_this:
* scanning the (re-reversed) donelist as this does.
*/
static void
-dl_done_list (struct ohci_hcd *ohci, struct pt_regs *regs)
+dl_done_list (struct ohci_hcd *ohci)
{
struct td *td = dl_reverse_done_list (ohci);
@@ -1084,7 +1086,7 @@ dl_done_list (struct ohci_hcd *ohci, struct pt_regs *regs)
/* If all this urb's TDs are done, call complete() */
if (urb_priv->td_cnt == urb_priv->length)
- finish_urb (ohci, urb, regs);
+ finish_urb (ohci, urb);
/* clean schedule: unlink EDs that are no longer busy */
if (list_empty (&ed->td_list)) {
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index d2fc6969a9f7..59e436424d41 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -370,7 +370,7 @@ static int usb_hcd_s3c2410_probe (const struct hc_driver *driver,
goto err_mem;
}
- usb_clk = clk_get(&dev->dev, "upll");
+ usb_clk = clk_get(&dev->dev, "usb-bus-host");
if (IS_ERR(usb_clk)) {
dev_err(&dev->dev, "cannot get usb-host clock\n");
retval = -ENOENT;
@@ -447,6 +447,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.start = ohci_s3c2410_start,
.stop = ohci_stop,
+ .shutdown = ohci_shutdown,
/*
* managing i/o requests and associated device resources
@@ -465,6 +466,7 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
*/
.hub_status_data = ohci_s3c2410_hub_status_data,
.hub_control = ohci_s3c2410_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
@@ -490,6 +492,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
static struct platform_driver ohci_hcd_s3c2410_driver = {
.probe = ohci_hcd_s3c2410_drv_probe,
.remove = ohci_hcd_s3c2410_drv_remove,
+ .shutdown = usb_hcd_platform_shutdown,
/*.suspend = ohci_hcd_s3c2410_drv_suspend, */
/*.resume = ohci_hcd_s3c2410_drv_resume, */
.driver = {
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index ce3de106cadc..71371de32ada 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -212,10 +212,6 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
* basic lifecycle operations
*/
.start = ohci_sa1111_start,
-#ifdef CONFIG_PM
- /* suspend: ohci_sa1111_suspend, -- tbd */
- /* resume: ohci_sa1111_resume, -- tbd */
-#endif
.stop = ohci_stop,
/*
@@ -235,6 +231,7 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
*/
.hub_status_data = ohci_hub_status_data,
.hub_control = ohci_hub_control,
+ .hub_irq_enable = ohci_rhsc_enable,
#ifdef CONFIG_PM
.bus_suspend = ohci_bus_suspend,
.bus_resume = ohci_bus_resume,
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index caacf14371f5..a2f42a2f47c6 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -159,7 +159,7 @@ static const int cc_to_error [16] = {
/* Bit Stuff */ -EPROTO,
/* Data Togg */ -EILSEQ,
/* Stall */ -EPIPE,
- /* DevNotResp */ -ETIMEDOUT,
+ /* DevNotResp */ -ETIME,
/* PIDCheck */ -EPROTO,
/* UnExpPID */ -EPROTO,
/* DataOver */ -EOVERFLOW,
@@ -388,8 +388,7 @@ struct ohci_hcd {
u32 hc_control; /* copy of hc control reg */
unsigned long next_statechange; /* suspend/resume */
u32 fminterval; /* saved register */
-
- struct notifier_block reboot_notifier;
+ unsigned autostop:1; /* rh auto stopping/stopped */
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 9de115d9db27..5fa5647ea095 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -428,7 +428,6 @@ static void finish_request(
struct sl811 *sl811,
struct sl811h_ep *ep,
struct urb *urb,
- struct pt_regs *regs,
int status
) __releases(sl811->lock) __acquires(sl811->lock)
{
@@ -444,7 +443,7 @@ static void finish_request(
spin_unlock(&urb->lock);
spin_unlock(&sl811->lock);
- usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, regs);
+ usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
spin_lock(&sl811->lock);
/* leave active endpoints in the schedule */
@@ -484,7 +483,7 @@ static void finish_request(
}
static void
-done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
+done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
{
u8 status;
struct urb *urb;
@@ -597,7 +596,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
/* error? retry, until "3 strikes" */
} else if (++ep->error_count >= 3) {
if (status & SL11H_STATMASK_TMOUT)
- urbstat = -ETIMEDOUT;
+ urbstat = -ETIME;
else if (status & SL11H_STATMASK_OVF)
urbstat = -EOVERFLOW;
else
@@ -608,7 +607,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
}
if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
- finish_request(sl811, ep, urb, regs, urbstat);
+ finish_request(sl811, ep, urb, urbstat);
}
static inline u8 checkdone(struct sl811 *sl811)
@@ -641,7 +640,7 @@ static inline u8 checkdone(struct sl811 *sl811)
return irqstat;
}
-static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+static irqreturn_t sl811h_irq(struct usb_hcd *hcd)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
u8 irqstat;
@@ -670,13 +669,13 @@ retry:
* issued ... that's fine if they're different endpoints.
*/
if (irqstat & SL11H_INTMASK_DONE_A) {
- done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF), regs);
+ done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF));
sl811->active_a = NULL;
sl811->stat_a++;
}
#ifdef USE_B
if (irqstat & SL11H_INTMASK_DONE_B) {
- done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF), regs);
+ done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF));
sl811->active_b = NULL;
sl811->stat_b++;
}
@@ -723,7 +722,7 @@ retry:
container_of(sl811->active_a
->hep->urb_list.next,
struct urb, urb_list),
- NULL, -ESHUTDOWN);
+ -ESHUTDOWN);
sl811->active_a = NULL;
}
#ifdef USE_B
@@ -957,7 +956,7 @@ static int sl811h_urb_enqueue(
spin_lock(&urb->lock);
if (urb->status != -EINPROGRESS) {
spin_unlock(&urb->lock);
- finish_request(sl811, ep, urb, NULL, 0);
+ finish_request(sl811, ep, urb, 0);
retval = 0;
goto fail;
}
@@ -1026,7 +1025,7 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
}
if (urb)
- finish_request(sl811, ep, urb, NULL, 0);
+ finish_request(sl811, ep, urb, 0);
else
VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
(sl811->active_a == ep) ? "A" : "B");
@@ -1083,7 +1082,7 @@ sl811h_hub_status_data(struct usb_hcd *hcd, char *buf)
*/
local_irq_save(flags);
if (!timer_pending(&sl811->timer)) {
- if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE)
+ if (sl811h_irq( /* ~0, */ hcd) != IRQ_NONE)
sl811->stat_lost++;
}
local_irq_restore(flags);
@@ -1517,7 +1516,7 @@ static int proc_sl811h_open(struct inode *inode, struct file *file)
return single_open(file, proc_sl811h_show, PDE(inode)->data);
}
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
.open = proc_sl811h_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
new file mode 100644
index 000000000000..32c635ecbf31
--- /dev/null
+++ b/drivers/usb/host/u132-hcd.c
@@ -0,0 +1,3294 @@
+/*
+* Host Controller Driver for the Elan Digital Systems U132 adapter
+*
+* Copyright(C) 2006 Elan Digital Systems Limited
+* http://www.elandigitalsystems.com
+*
+* Author and Maintainer - Tony Olech - Elan Digital Systems
+* tony.olech@elandigitalsystems.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, version 2.
+*
+*
+* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
+* based on various USB host drivers in the 2.6.15 linux kernel
+* with constant reference to the 3rd Edition of Linux Device Drivers
+* published by O'Reilly
+*
+* The U132 adapter is a USB to CardBus adapter specifically designed
+* for PC cards that contain an OHCI host controller. Typical PC cards
+* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
+*
+* The U132 adapter will *NOT *work with PC cards that do not contain
+* an OHCI controller. A simple way to test whether a PC card has an
+* OHCI controller as an interface is to insert the PC card directly
+* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
+* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
+* then there is a good chance that the U132 adapter will support the
+* PC card.(you also need the specific client driver for the PC card)
+*
+* Please inform the Author and Maintainer about any PC cards that
+* contain OHCI Host Controller and work when directly connected to
+* an embedded CardBus slot but do not work when they are connected
+* via an ELAN U132 adapter.
+*
+*/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/pci_ids.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include "../core/hcd.h"
+#include "ohci.h"
+#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR
+#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \
+ OHCI_INTR_WDH)
+MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited");
+MODULE_DESCRIPTION("U132 USB Host Controller Driver");
+MODULE_LICENSE("GPL");
+#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
+INT_MODULE_PARM(testing, 0);
+/* Some boards misreport power switching/overcurrent*/
+static int distrust_firmware = 1;
+module_param(distrust_firmware, bool, 0);
+MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurren"
+ "t setup");
+DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait);
+/*
+* u132_module_lock exists to protect access to global variables
+*
+*/
+static struct semaphore u132_module_lock;
+static int u132_exiting = 0;
+static int u132_instances = 0;
+static struct list_head u132_static_list;
+/*
+* end of the global variables protected by u132_module_lock
+*/
+static struct workqueue_struct *workqueue;
+#define MAX_U132_PORTS 7
+#define MAX_U132_ADDRS 128
+#define MAX_U132_UDEVS 4
+#define MAX_U132_ENDPS 100
+#define MAX_U132_RINGS 4
+static const char *cc_to_text[16] = {
+ "No Error ",
+ "CRC Error ",
+ "Bit Stuff ",
+ "Data Togg ",
+ "Stall ",
+ "DevNotResp ",
+ "PIDCheck ",
+ "UnExpPID ",
+ "DataOver ",
+ "DataUnder ",
+ "(for hw) ",
+ "(for hw) ",
+ "BufferOver ",
+ "BuffUnder ",
+ "(for HCD) ",
+ "(for HCD) "
+};
+struct u132_port {
+ struct u132 *u132;
+ int reset;
+ int enable;
+ int power;
+ int Status;
+};
+struct u132_addr {
+ u8 address;
+};
+struct u132_udev {
+ struct kref kref;
+ struct usb_device *usb_device;
+ u8 enumeration;
+ u8 udev_number;
+ u8 usb_addr;
+ u8 portnumber;
+ u8 endp_number_in[16];
+ u8 endp_number_out[16];
+};
+#define ENDP_QUEUE_SHIFT 3
+#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT)
+#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1)
+struct u132_urbq {
+ struct list_head urb_more;
+ struct urb *urb;
+};
+struct u132_spin {
+ spinlock_t slock;
+};
+struct u132_endp {
+ struct kref kref;
+ u8 udev_number;
+ u8 endp_number;
+ u8 usb_addr;
+ u8 usb_endp;
+ struct u132 *u132;
+ struct list_head endp_ring;
+ struct u132_ring *ring;
+ unsigned toggle_bits:2;
+ unsigned active:1;
+ unsigned delayed:1;
+ unsigned input:1;
+ unsigned output:1;
+ unsigned pipetype:2;
+ unsigned dequeueing:1;
+ unsigned edset_flush:1;
+ unsigned spare_bits:14;
+ unsigned long jiffies;
+ struct usb_host_endpoint *hep;
+ struct u132_spin queue_lock;
+ u16 queue_size;
+ u16 queue_last;
+ u16 queue_next;
+ struct urb *urb_list[ENDP_QUEUE_SIZE];
+ struct list_head urb_more;
+ struct work_struct scheduler;
+};
+struct u132_ring {
+ unsigned in_use:1;
+ unsigned length:7;
+ u8 number;
+ struct u132 *u132;
+ struct u132_endp *curr_endp;
+ struct work_struct scheduler;
+};
+#define OHCI_QUIRK_AMD756 0x01
+#define OHCI_QUIRK_SUPERIO 0x02
+#define OHCI_QUIRK_INITRESET 0x04
+#define OHCI_BIG_ENDIAN 0x08
+#define OHCI_QUIRK_ZFMICRO 0x10
+struct u132 {
+ struct kref kref;
+ struct list_head u132_list;
+ struct semaphore sw_lock;
+ struct semaphore scheduler_lock;
+ struct u132_platform_data *board;
+ struct platform_device *platform_dev;
+ struct u132_ring ring[MAX_U132_RINGS];
+ int sequence_num;
+ int going;
+ int power;
+ int reset;
+ int num_ports;
+ u32 hc_control;
+ u32 hc_fminterval;
+ u32 hc_roothub_status;
+ u32 hc_roothub_a;
+ u32 hc_roothub_portstatus[MAX_ROOT_PORTS];
+ int flags;
+ unsigned long next_statechange;
+ struct work_struct monitor;
+ int num_endpoints;
+ struct u132_addr addr[MAX_U132_ADDRS];
+ struct u132_udev udev[MAX_U132_UDEVS];
+ struct u132_port port[MAX_U132_PORTS];
+ struct u132_endp *endp[MAX_U132_ENDPS];
+};
+int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data);
+int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, u8 addressofs,
+ u8 width, u32 *data);
+int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, u8 addressofs,
+ u8 width, u32 data);
+/*
+* these can not be inlines because we need the structure offset!!
+* Does anyone have a better way?????
+*/
+#define u132_read_pcimem(u132, member, data) \
+ usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0, data);
+#define u132_write_pcimem(u132, member, data) \
+ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0, data);
+#define u132_write_pcimem_byte(u132, member, data) \
+ usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \
+ ohci_regs, member), 0x0e, data);
+static inline struct u132 *udev_to_u132(struct u132_udev *udev)
+{
+ u8 udev_number = udev->udev_number;
+ return container_of(udev, struct u132, udev[udev_number]);
+}
+
+static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd)
+{
+ return (struct u132 *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *u132_to_hcd(struct u132 *u132)
+{
+ return container_of((void *)u132, struct usb_hcd, hcd_priv);
+}
+
+static inline void u132_disable(struct u132 *u132)
+{
+ u132_to_hcd(u132)->state = HC_STATE_HALT;
+}
+
+
+#define kref_to_u132(d) container_of(d, struct u132, kref)
+#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref)
+#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref)
+#include "../misc/usb_u132.h"
+static const char hcd_name[] = "u132_hcd";
+#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \
+ USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \
+ USB_PORT_STAT_C_RESET) << 16)
+static void u132_hcd_delete(struct kref *kref)
+{
+ struct u132 *u132 = kref_to_u132(kref);
+ struct platform_device *pdev = u132->platform_dev;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ u132->going += 1;
+ down(&u132_module_lock);
+ list_del_init(&u132->u132_list);
+ u132_instances -= 1;
+ up(&u132_module_lock);
+ dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13"
+ "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev);
+ usb_put_hcd(hcd);
+}
+
+static inline void u132_u132_put_kref(struct u132 *u132)
+{
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static inline void u132_u132_init_kref(struct u132 *u132)
+{
+ kref_init(&u132->kref);
+}
+
+static void u132_udev_delete(struct kref *kref)
+{
+ struct u132_udev *udev = kref_to_u132_udev(kref);
+ udev->udev_number = 0;
+ udev->usb_device = NULL;
+ udev->usb_addr = 0;
+ udev->enumeration = 0;
+}
+
+static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev)
+{
+ kref_put(&udev->kref, u132_udev_delete);
+}
+
+static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev)
+{
+ kref_get(&udev->kref);
+}
+
+static inline void u132_udev_init_kref(struct u132 *u132,
+ struct u132_udev *udev)
+{
+ kref_init(&udev->kref);
+}
+
+static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring)
+{
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring,
+ unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &ring->scheduler, delta))
+ return;
+ } else if (queue_work(workqueue, &ring->scheduler))
+ return;
+ kref_put(&u132->kref, u132_hcd_delete);
+ return;
+}
+
+static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring,
+ unsigned int delta)
+{
+ kref_get(&u132->kref);
+ u132_ring_requeue_work(u132, ring, delta);
+ return;
+}
+
+static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring)
+{
+ if (cancel_delayed_work(&ring->scheduler)) {
+ kref_put(&u132->kref, u132_hcd_delete);
+ }
+}
+
+static void u132_endp_delete(struct kref *kref)
+{
+ struct u132_endp *endp = kref_to_u132_endp(kref);
+ struct u132 *u132 = endp->u132;
+ u8 usb_addr = endp->usb_addr;
+ u8 usb_endp = endp->usb_endp;
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ u8 endp_number = endp->endp_number;
+ struct usb_host_endpoint *hep = endp->hep;
+ struct u132_ring *ring = endp->ring;
+ struct list_head *head = &endp->endp_ring;
+ ring->length -= 1;
+ if (endp == ring->curr_endp) {
+ if (list_empty(head)) {
+ ring->curr_endp = NULL;
+ list_del(head);
+ } else {
+ struct u132_endp *next_endp = list_entry(head->next,
+ struct u132_endp, endp_ring);
+ ring->curr_endp = next_endp;
+ list_del(head);
+ }} else
+ list_del(head);
+ if (endp->input) {
+ udev->endp_number_in[usb_endp] = 0;
+ u132_udev_put_kref(u132, udev);
+ }
+ if (endp->output) {
+ udev->endp_number_out[usb_endp] = 0;
+ u132_udev_put_kref(u132, udev);
+ }
+ u132->endp[endp_number - 1] = NULL;
+ hep->hcpriv = NULL;
+ kfree(endp);
+ u132_u132_put_kref(u132);
+}
+
+static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp)
+{
+ kref_put(&endp->kref, u132_endp_delete);
+}
+
+static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp)
+{
+ kref_get(&endp->kref);
+}
+
+static inline void u132_endp_init_kref(struct u132 *u132,
+ struct u132_endp *endp)
+{
+ kref_init(&endp->kref);
+ kref_get(&u132->kref);
+}
+
+static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp,
+ unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &endp->scheduler, delta))
+ kref_get(&endp->kref);
+ } else if (queue_work(workqueue, &endp->scheduler))
+ kref_get(&endp->kref);
+ return;
+}
+
+static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp)
+{
+ if (cancel_delayed_work(&endp->scheduler))
+ kref_put(&endp->kref, u132_endp_delete);
+}
+
+static inline void u132_monitor_put_kref(struct u132 *u132)
+{
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &u132->monitor, delta)) {
+ kref_get(&u132->kref);
+ }
+ } else if (queue_work(workqueue, &u132->monitor))
+ kref_get(&u132->kref);
+ return;
+}
+
+static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(workqueue, &u132->monitor, delta))
+ return;
+ } else if (queue_work(workqueue, &u132->monitor))
+ return;
+ kref_put(&u132->kref, u132_hcd_delete);
+ return;
+}
+
+static void u132_monitor_cancel_work(struct u132 *u132)
+{
+ if (cancel_delayed_work(&u132->monitor))
+ kref_put(&u132->kref, u132_hcd_delete);
+}
+
+static int read_roothub_info(struct u132 *u132)
+{
+ u32 revision;
+ int retval;
+ retval = u132_read_pcimem(u132, revision, &revision);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
+ "ntrol\n", retval);
+ return retval;
+ } else if ((revision & 0xFF) == 0x10) {
+ } else if ((revision & 0xFF) == 0x11) {
+ } else {
+ dev_err(&u132->platform_dev->dev, "device revision is not valid"
+ " %08X\n", revision);
+ return -ENODEV;
+ }
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device co"
+ "ntrol\n", retval);
+ return retval;
+ }
+ retval = u132_read_pcimem(u132, roothub.status,
+ &u132->hc_roothub_status);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
+ "g roothub.status\n", retval);
+ return retval;
+ }
+ retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d accessing device re"
+ "g roothub.a\n", retval);
+ return retval;
+ }
+ {
+ int I = u132->num_ports;
+ int i = 0;
+ while (I-- > 0) {
+ retval = u132_read_pcimem(u132, roothub.portstatus[i],
+ &u132->hc_roothub_portstatus[i]);
+ if (retval) {
+ dev_err(&u132->platform_dev->dev, "error %d acc"
+ "essing device roothub.portstatus[%d]\n"
+ , retval, i);
+ return retval;
+ } else
+ i += 1;
+ }
+ }
+ return 0;
+}
+
+static void u132_hcd_monitor_work(void *data)
+{
+ struct u132 *u132 = data;
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ u132_monitor_put_kref(u132);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ u132_monitor_put_kref(u132);
+ return;
+ } else {
+ int retval;
+ down(&u132->sw_lock);
+ retval = read_roothub_info(u132);
+ if (retval) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ u132_disable(u132);
+ u132->going = 1;
+ up(&u132->sw_lock);
+ usb_hc_died(hcd);
+ ftdi_elan_gone_away(u132->platform_dev);
+ u132_monitor_put_kref(u132);
+ return;
+ } else {
+ u132_monitor_requeue_work(u132, 500);
+ up(&u132->sw_lock);
+ return;
+ }
+ }
+}
+
+static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb, int status)
+{
+ struct u132_ring *ring;
+ unsigned long irqs;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ urb->error_count = 0;
+ urb->status = status;
+ urb->hcpriv = NULL;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_next += 1;
+ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
+ urb_more);
+ list_del(next);
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urbq->urb;
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(urbq);
+ } down(&u132->scheduler_lock);
+ ring = endp->ring;
+ ring->in_use = 0;
+ u132_ring_cancel_work(u132, ring);
+ u132_ring_queue_work(u132, ring, 0);
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ usb_hcd_giveback_urb(hcd, urb);
+ return;
+}
+
+static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb, int status)
+{
+ u132_endp_put_kref(u132, endp);
+}
+
+static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb, int status)
+{
+ unsigned long irqs;
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ urb->error_count = 0;
+ urb->status = status;
+ urb->hcpriv = NULL;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_next += 1;
+ if (ENDP_QUEUE_SIZE > --endp->queue_size) {
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next, struct u132_urbq,
+ urb_more);
+ list_del(next);
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urbq->urb;
+ endp->active = 0;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ kfree(urbq);
+ } usb_hcd_giveback_urb(hcd, urb);
+ return;
+}
+
+static inline int edset_input(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp,
+ urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+static inline int edset_setup(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp,
+ urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+static inline int edset_single(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number,
+ endp, urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+static inline int edset_output(struct u132 *u132, struct u132_ring *ring,
+ struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number,
+ endp, urb, address, endp->usb_endp, toggle_bits, callback);
+}
+
+
+/*
+* must not LOCK sw_lock
+*
+*/
+static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer + urb->actual_length;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length += len;
+ if ((condition_code == TD_CC_NOERROR) &&
+ (urb->transfer_buffer_length > urb->actual_length)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ if (urb->actual_length > 0) {
+ int retval;
+ up(&u132->scheduler_lock);
+ retval = edset_single(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_interrupt_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ } else {
+ ring->in_use = 0;
+ endp->active = 0;
+ endp->jiffies = jiffies +
+ msecs_to_jiffies(urb->interval);
+ u132_ring_cancel_work(u132, ring);
+ u132_ring_queue_work(u132, ring, 0);
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ }
+ return;
+ } else if ((condition_code == TD_DATAUNDERRUN) &&
+ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ if (condition_code == TD_CC_NOERROR) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 1 & toggle_bits);
+ } else if (condition_code == TD_CC_STALL) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 0);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp,
+ 0, 0);
+ dev_err(&u132->platform_dev->dev, "urb=%p givin"
+ "g back INTERRUPT %s\n", urb,
+ cc_to_text[condition_code]);
+ }
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ urb->actual_length += len;
+ endp->toggle_bits = toggle_bits;
+ if (urb->transfer_buffer_length > urb->actual_length) {
+ int retval;
+ up(&u132->scheduler_lock);
+ retval = edset_output(u132, ring, endp, urb, address,
+ endp->toggle_bits, u132_hcd_bulk_output_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer + urb->actual_length;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length += len;
+ if ((condition_code == TD_CC_NOERROR) &&
+ (urb->transfer_buffer_length > urb->actual_length)) {
+ int retval;
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, endp->toggle_bits,
+ u132_hcd_bulk_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (condition_code == TD_CC_NOERROR) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else if ((condition_code == TD_DATAUNDERRUN) &&
+ ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else if (condition_code == TD_DATAUNDERRUN) {
+ endp->toggle_bits = toggle_bits;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0,
+ 1 & toggle_bits);
+ dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK"
+ ") giving back BULK IN %s\n", urb,
+ cc_to_text[condition_code]);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else if (condition_code == TD_CC_STALL) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0);
+ dev_err(&u132->platform_dev->dev, "urb=%p giving back B"
+ "ULK IN code=%d %s\n", urb, condition_code,
+ cc_to_text[condition_code]);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length = len;
+ if ((condition_code == TD_CC_NOERROR) || ((condition_code ==
+ TD_DATAUNDERRUN) && ((urb->transfer_flags &
+ URB_SHORT_NOT_OK) == 0))) {
+ int retval;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0x3,
+ u132_hcd_configure_empty_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (condition_code == TD_CC_STALL) {
+ up(&u132->scheduler_lock);
+ dev_warn(&u132->platform_dev->dev, "giving back SETUP I"
+ "NPUT STALL urb %p\n", urb);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ } else {
+ up(&u132->scheduler_lock);
+ dev_err(&u132->platform_dev->dev, "giving back SETUP IN"
+ "PUT %s urb %p\n", cc_to_text[condition_code],
+ urb);
+ u132_hcd_giveback_urb(u132, endp, urb,
+ cc_to_error[condition_code]);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ if (usb_pipein(urb->pipe)) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0,
+ u132_hcd_configure_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address,
+ endp->usb_endp, 0,
+ u132_hcd_configure_empty_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
+ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ u132->addr[0].address = 0;
+ endp->usb_addr = udev->usb_addr;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
+ u8 *buf, int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, 0, endp->usb_endp, 0,
+ u132_hcd_enumeration_empty_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, 0);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ u8 *u = urb->transfer_buffer;
+ u8 *b = buf;
+ int L = len;
+ while (L-- > 0) {
+ *u++ = *b++;
+ }
+ urb->actual_length = len;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_empty(u132->platform_dev,
+ ring->number, endp, urb, address, endp->usb_endp, 0x3,
+ u132_hcd_initial_empty_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
+ int len, int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual, int non_null)
+{
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ u8 address = u132->addr[endp->usb_addr].address;
+ down(&u132->scheduler_lock);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ up(&u132->scheduler_lock);
+ u132_hcd_forget_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (endp->dequeueing) {
+ endp->dequeueing = 0;
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
+ return;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
+ return;
+ } else if (urb->status == -EINPROGRESS) {
+ int retval;
+ struct u132_ring *ring = endp->ring;
+ up(&u132->scheduler_lock);
+ retval = usb_ftdi_elan_edset_input(u132->platform_dev,
+ ring->number, endp, urb, address, endp->usb_endp, 0,
+ u132_hcd_initial_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
+ "s=%d\n", urb, urb->status);
+ up(&u132->scheduler_lock);
+ u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+ return;
+ }
+}
+
+static void u132_hcd_ring_work_scheduler(void *data);
+static void u132_hcd_endp_work_scheduler(void *data);
+/*
+* this work function is only executed from the work queue
+*
+*/
+static void u132_hcd_ring_work_scheduler(void *data)
+{
+ struct u132_ring *ring = data;
+ struct u132 *u132 = ring->u132;
+ down(&u132->scheduler_lock);
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else if (ring->curr_endp) {
+ struct u132_endp *last_endp = ring->curr_endp;
+ struct list_head *scan;
+ struct list_head *head = &last_endp->endp_ring;
+ unsigned long wakeup = 0;
+ list_for_each(scan, head) {
+ struct u132_endp *endp = list_entry(scan,
+ struct u132_endp, endp_ring);
+ if (endp->queue_next == endp->queue_last) {
+ } else if ((endp->delayed == 0)
+ || time_after_eq(jiffies, endp->jiffies)) {
+ ring->curr_endp = endp;
+ u132_endp_cancel_work(u132, last_endp);
+ u132_endp_queue_work(u132, last_endp, 0);
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else {
+ unsigned long delta = endp->jiffies - jiffies;
+ if (delta > wakeup)
+ wakeup = delta;
+ }
+ }
+ if (last_endp->queue_next == last_endp->queue_last) {
+ } else if ((last_endp->delayed == 0) || time_after_eq(jiffies,
+ last_endp->jiffies)) {
+ u132_endp_cancel_work(u132, last_endp);
+ u132_endp_queue_work(u132, last_endp, 0);
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ } else {
+ unsigned long delta = last_endp->jiffies - jiffies;
+ if (delta > wakeup)
+ wakeup = delta;
+ }
+ if (wakeup > 0) {
+ u132_ring_requeue_work(u132, ring, wakeup);
+ up(&u132->scheduler_lock);
+ return;
+ } else {
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ }
+ } else {
+ up(&u132->scheduler_lock);
+ u132_ring_put_kref(u132, ring);
+ return;
+ }
+}
+
+static void u132_hcd_endp_work_scheduler(void *data)
+{
+ struct u132_ring *ring;
+ struct u132_endp *endp = data;
+ struct u132 *u132 = endp->u132;
+ down(&u132->scheduler_lock);
+ ring = endp->ring;
+ if (endp->edset_flush) {
+ endp->edset_flush = 0;
+ if (endp->dequeueing)
+ usb_ftdi_elan_edset_flush(u132->platform_dev,
+ ring->number, endp);
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->active) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->queue_next == endp->queue_last) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (endp->pipetype == PIPE_INTERRUPT) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_single(u132, ring, endp, urb, address,
+ endp->toggle_bits, u132_hcd_interrupt_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else if (endp->pipetype == PIPE_CONTROL) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else if (address == 0) {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, address,
+ 0x2, u132_hcd_initial_setup_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else if (endp->usb_addr == 0) {
+ int retval;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, 0, 0x2,
+ u132_hcd_enumeration_address_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ } else {
+ int retval;
+ u8 address = u132->addr[endp->usb_addr].address;
+ struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_setup(u132, ring, endp, urb, address,
+ 0x2, u132_hcd_configure_setup_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb, retval);
+ return;
+ }
+ } else {
+ if (endp->input) {
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[
+ ENDP_QUEUE_MASK & endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_input(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_bulk_input_recv);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ return;
+ }
+ } else { /* output pipe */
+ u8 address = u132->addr[endp->usb_addr].address;
+ if (ring->in_use) {
+ up(&u132->scheduler_lock);
+ u132_endp_put_kref(u132, endp);
+ return;
+ } else {
+ int retval;
+ struct urb *urb = endp->urb_list[
+ ENDP_QUEUE_MASK & endp->queue_next];
+ endp->active = 1;
+ ring->curr_endp = endp;
+ ring->in_use = 1;
+ up(&u132->scheduler_lock);
+ retval = edset_output(u132, ring, endp, urb,
+ address, endp->toggle_bits,
+ u132_hcd_bulk_output_sent);
+ if (retval == 0) {
+ } else
+ u132_hcd_giveback_urb(u132, endp, urb,
+ retval);
+ return;
+ }
+ }
+ }
+}
+
+static void port_power(struct u132 *u132, int pn, int is_on)
+{
+ u132->port[pn].power = is_on;
+}
+
+static void u132_power(struct u132 *u132, int is_on)
+{
+ struct usb_hcd *hcd = u132_to_hcd(u132)
+ ; /* hub is inactive unless the port is powered */
+ if (is_on) {
+ if (u132->power)
+ return;
+ u132->power = 1;
+ hcd->self.controller->power.power_state = PMSG_ON;
+ } else {
+ u132->power = 0;
+ hcd->state = HC_STATE_HALT;
+ hcd->self.controller->power.power_state = PMSG_SUSPEND;
+ }
+}
+
+static int u132_periodic_reinit(struct u132 *u132)
+{
+ int retval;
+ u32 fi = u132->hc_fminterval & 0x03fff;
+ u32 fit;
+ u32 fminterval;
+ retval = u132_read_pcimem(u132, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ fit = fminterval & FIT;
+ retval = u132_write_pcimem(u132, fminterval,
+ (fit ^ FIT) | u132->hc_fminterval);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, periodicstart,
+ ((9 *fi) / 10) & 0x3fff);
+ if (retval)
+ return retval;
+ return 0;
+}
+
+static char *hcfs2string(int state)
+{
+ switch (state) {
+ case OHCI_USB_RESET:
+ return "reset";
+ case OHCI_USB_RESUME:
+ return "resume";
+ case OHCI_USB_OPER:
+ return "operational";
+ case OHCI_USB_SUSPEND:
+ return "suspend";
+ }
+ return "?";
+}
+
+static int u132_usb_reset(struct u132 *u132)
+{
+ int retval;
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval)
+ return retval;
+ u132->hc_control &= OHCI_CTRL_RWC;
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ return 0;
+}
+
+static int u132_init(struct u132 *u132)
+{
+ int retval;
+ u32 control;
+ u132_disable(u132);
+ u132->next_statechange =
+ jiffies; /* SMM owns the HC? not for long! */ {
+ u32 control;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ if (control & OHCI_CTRL_IR) {
+ u32 temp = 50;
+ retval = u132_write_pcimem(u132, intrenable,
+ OHCI_INTR_OC);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem_byte(u132, cmdstatus,
+ OHCI_OCR);
+ if (retval)
+ return retval;
+ check:{
+ retval = u132_read_pcimem(u132, control,
+ &control);
+ if (retval)
+ return retval;
+ }
+ if (control & OHCI_CTRL_IR) {
+ msleep(10);
+ if (--temp == 0) {
+ dev_err(&u132->platform_dev->dev, "USB "
+ "HC takeover failed!(BIOS/SMM b"
+ "ug) control=%08X\n", control);
+ return -EBUSY;
+ }
+ goto check;
+ }
+ u132_usb_reset(u132);
+ }
+ }
+ retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ if (u132->num_ports == 0) {
+ u32 rh_a = -1;
+ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ u132->num_ports = rh_a & RH_A_NDP;
+ retval = read_roothub_info(u132);
+ if (retval)
+ return retval;
+ }
+ if (u132->num_ports > MAX_U132_PORTS) {
+ return -EINVAL;
+ }
+ return 0;
+}
+
+
+/* Start an OHCI controller, set the BUS operational
+* resets USB and controller
+* enable interrupts
+*/
+static int u132_run(struct u132 *u132)
+{
+ int retval;
+ u32 control;
+ u32 status;
+ u32 fminterval;
+ u32 periodicstart;
+ u32 cmdstatus;
+ u32 roothub_a;
+ int mask = OHCI_INTR_INIT;
+ int first = u132->hc_fminterval == 0;
+ int sleep_time = 0;
+ int reset_timeout = 30; /* ... allow extra time */
+ u132_disable(u132);
+ if (first) {
+ u32 temp;
+ retval = u132_read_pcimem(u132, fminterval, &temp);
+ if (retval)
+ return retval;
+ u132->hc_fminterval = temp & 0x3fff;
+ if (u132->hc_fminterval != FI) {
+ }
+ u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16;
+ }
+ retval = u132_read_pcimem(u132, control, &u132->hc_control);
+ if (retval)
+ return retval;
+ dev_info(&u132->platform_dev->dev, "resetting from state '%s', control "
+ "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS),
+ u132->hc_control);
+ switch (u132->hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+ sleep_time = 0;
+ break;
+ case OHCI_USB_SUSPEND:
+ case OHCI_USB_RESUME:
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_USB_RESUME;
+ sleep_time = 10;
+ break;
+ default:
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_USB_RESET;
+ sleep_time = 50;
+ break;
+ }
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ msleep(sleep_time);
+ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ if (!(roothub_a & RH_A_NPS)) {
+ int temp; /* power down each port */
+ for (temp = 0; temp < u132->num_ports; temp++) {
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[temp], RH_PS_LSDA);
+ if (retval)
+ return retval;
+ }
+ }
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ retry:retval = u132_read_pcimem(u132, cmdstatus, &status);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_HCR);
+ if (retval)
+ return retval;
+ extra:{
+ retval = u132_read_pcimem(u132, cmdstatus, &status);
+ if (retval)
+ return retval;
+ if (0 != (status & OHCI_HCR)) {
+ if (--reset_timeout == 0) {
+ dev_err(&u132->platform_dev->dev, "USB HC reset"
+ " timed out!\n");
+ return -ENODEV;
+ } else {
+ msleep(5);
+ goto extra;
+ }
+ }
+ }
+ if (u132->flags & OHCI_QUIRK_INITRESET) {
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ }
+ retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, hcca, 0x00000000);
+ if (retval)
+ return retval;
+ retval = u132_periodic_reinit(u132);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, fminterval, &fminterval);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, periodicstart, &periodicstart);
+ if (retval)
+ return retval;
+ if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
+ if (!(u132->flags & OHCI_QUIRK_INITRESET)) {
+ u132->flags |= OHCI_QUIRK_INITRESET;
+ goto retry;
+ } else
+ dev_err(&u132->platform_dev->dev, "init err(%08x %04x)"
+ "\n", fminterval, periodicstart);
+ } /* start controller operations */
+ u132->hc_control &= OHCI_CTRL_RWC;
+ u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
+ retval = u132_write_pcimem(u132, control, u132->hc_control);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem_byte(u132, cmdstatus, OHCI_BLF);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
+ retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, intrstatus, mask);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, intrdisable,
+ OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
+ OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
+ OHCI_INTR_SO);
+ if (retval)
+ return retval; /* handle root hub init quirks ... */
+ retval = u132_read_pcimem(u132, roothub.a, &roothub_a);
+ if (retval)
+ return retval;
+ roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
+ if (u132->flags & OHCI_QUIRK_SUPERIO) {
+ roothub_a |= RH_A_NOCP;
+ roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
+ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) {
+ roothub_a |= RH_A_NPS;
+ retval = u132_write_pcimem(u132, roothub.a, roothub_a);
+ if (retval)
+ return retval;
+ }
+ retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC);
+ if (retval)
+ return retval;
+ retval = u132_write_pcimem(u132, roothub.b,
+ (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
+ if (retval)
+ return retval;
+ retval = u132_read_pcimem(u132, control, &control);
+ if (retval)
+ return retval;
+ mdelay((roothub_a >> 23) & 0x1fe);
+ u132_to_hcd(u132)->state = HC_STATE_RUNNING;
+ return 0;
+}
+
+static void u132_hcd_stop(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
+ "ed\n", hcd);
+ } else {
+ down(&u132->sw_lock);
+ msleep(100);
+ u132_power(u132, 0);
+ up(&u132->sw_lock);
+ }
+}
+
+static int u132_hcd_start(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else if (hcd->self.controller) {
+ int retval;
+ struct platform_device *pdev =
+ to_platform_device(hcd->self.controller);
+ u16 vendor = ((struct u132_platform_data *)
+ (pdev->dev.platform_data))->vendor;
+ u16 device = ((struct u132_platform_data *)
+ (pdev->dev.platform_data))->device;
+ down(&u132->sw_lock);
+ msleep(10);
+ if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
+ u132->flags = OHCI_QUIRK_AMD756;
+ } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) {
+ dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar"
+ "ounds unavailable\n");
+ } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8)
+ u132->flags |= OHCI_QUIRK_ZFMICRO;
+ retval = u132_run(u132);
+ if (retval) {
+ u132_disable(u132);
+ u132->going = 1;
+ }
+ msleep(100);
+ up(&u132->sw_lock);
+ return retval;
+ } else {
+ dev_err(&u132->platform_dev->dev, "platform_device missing\n");
+ return -ENODEV;
+ }
+}
+
+static int u132_hcd_reset(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval;
+ down(&u132->sw_lock);
+ retval = u132_init(u132);
+ if (retval) {
+ u132_disable(u132);
+ u132->going = 1;
+ }
+ up(&u132->sw_lock);
+ return retval;
+ }
+}
+
+static int create_endpoint_and_queue_int(struct u132 *u132,
+ struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
+ gfp_t mem_flags)
+{
+ struct u132_ring *ring;
+ unsigned long irqs;
+ u8 endp_number = ++u132->num_endpoints;
+ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
+ kmalloc(sizeof(struct u132_endp), mem_flags);
+ if (!endp) {
+ return -ENOMEM;
+ }
+ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
+ spin_lock_init(&endp->queue_lock.slock);
+ INIT_LIST_HEAD(&endp->urb_more);
+ ring = endp->ring = &u132->ring[0];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
+ endp->hep = hep;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_endp_init_kref(u132, endp);
+ if (usb_pipein(urb->pipe)) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
+ endp->input = 1;
+ endp->output = 0;
+ udev->endp_number_in[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
+ endp->input = 0;
+ endp->output = 1;
+ udev->endp_number_out[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ }
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->delayed = 1;
+ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval));
+ return 0;
+}
+
+static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp, u8 address)
+{
+ urb->hcpriv = u132;
+ endp->delayed = 1;
+ endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+}
+
+static int create_endpoint_and_queue_bulk(struct u132 *u132,
+ struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
+ gfp_t mem_flags)
+{
+ int ring_number;
+ struct u132_ring *ring;
+ unsigned long irqs;
+ u8 endp_number = ++u132->num_endpoints;
+ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
+ kmalloc(sizeof(struct u132_endp), mem_flags);
+ if (!endp) {
+ return -ENOMEM;
+ }
+ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
+ spin_lock_init(&endp->queue_lock.slock);
+ INIT_LIST_HEAD(&endp->urb_more);
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
+ endp->hep = hep;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_endp_init_kref(u132, endp);
+ if (usb_pipein(urb->pipe)) {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 0, 0);
+ ring_number = 3;
+ endp->input = 1;
+ endp->output = 0;
+ udev->endp_number_in[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ } else {
+ endp->toggle_bits = 0x2;
+ usb_settoggle(udev->usb_device, usb_endp, 1, 0);
+ ring_number = 2;
+ endp->input = 0;
+ endp->output = 1;
+ udev->endp_number_out[usb_endp] = endp_number;
+ u132_udev_get_kref(u132, udev);
+ }
+ ring = endp->ring = &u132->ring[ring_number - 1];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+}
+
+static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp, u8 address)
+{
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+}
+
+static int create_endpoint_and_queue_control(struct u132 *u132,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
+ gfp_t mem_flags)
+{
+ struct u132_ring *ring;
+ u8 endp_number = ++u132->num_endpoints;
+ struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
+ kmalloc(sizeof(struct u132_endp), mem_flags);
+ if (!endp) {
+ return -ENOMEM;
+ }
+ INIT_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler, (void *)endp);
+ spin_lock_init(&endp->queue_lock.slock);
+ INIT_LIST_HEAD(&endp->urb_more);
+ ring = endp->ring = &u132->ring[0];
+ if (ring->curr_endp) {
+ list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring);
+ } else {
+ INIT_LIST_HEAD(&endp->endp_ring);
+ ring->curr_endp = endp;
+ }
+ ring->length += 1;
+ endp->dequeueing = 0;
+ endp->edset_flush = 0;
+ endp->active = 0;
+ endp->delayed = 0;
+ endp->endp_number = endp_number;
+ endp->u132 = u132;
+ endp->hep = hep;
+ u132_endp_init_kref(u132, endp);
+ u132_endp_get_kref(u132, endp);
+ if (usb_addr == 0) {
+ unsigned long irqs;
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->input = 1;
+ endp->output = 1;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_udev_init_kref(u132, udev);
+ u132_udev_get_kref(u132, udev);
+ udev->endp_number_in[usb_endp] = endp_number;
+ udev->endp_number_out[usb_endp] = endp_number;
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ } else { /*(usb_addr > 0) */
+ unsigned long irqs;
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ endp->udev_number = address;
+ endp->usb_addr = usb_addr;
+ endp->usb_endp = usb_endp;
+ endp->input = 1;
+ endp->output = 1;
+ endp->pipetype = usb_pipetype(urb->pipe);
+ u132_udev_get_kref(u132, udev);
+ udev->enumeration = 2;
+ udev->endp_number_in[usb_endp] = endp_number;
+ udev->endp_number_out[usb_endp] = endp_number;
+ urb->hcpriv = u132;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ endp->queue_size = 1;
+ endp->queue_last = 0;
+ endp->queue_next = 0;
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
+}
+
+static int queue_control_on_old_endpoint(struct u132 *u132,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
+ u8 usb_endp)
+{
+ if (usb_addr == 0) {
+ if (usb_pipein(urb->pipe)) {
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more,
+ &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ } else { /* usb_pipeout(urb->pipe) */
+ struct u132_addr *addr = &u132->addr[usb_dev->devnum];
+ int I = MAX_U132_UDEVS;
+ int i = 0;
+ while (--I > 0) {
+ struct u132_udev *udev = &u132->udev[++i];
+ if (udev->usb_device) {
+ continue;
+ } else {
+ udev->enumeration = 1;
+ u132->addr[0].address = i;
+ endp->udev_number = i;
+ udev->udev_number = i;
+ udev->usb_addr = usb_dev->devnum;
+ u132_udev_init_kref(u132, udev);
+ udev->endp_number_in[usb_endp] =
+ endp->endp_number;
+ u132_udev_get_kref(u132, udev);
+ udev->endp_number_out[usb_endp] =
+ endp->endp_number;
+ udev->usb_device = usb_dev;
+ ((u8 *) (urb->setup_packet))[2] =
+ addr->address = i;
+ u132_udev_get_kref(u132, udev);
+ break;
+ }
+ }
+ if (I == 0) {
+ dev_err(&u132->platform_dev->dev, "run out of d"
+ "evice space\n");
+ return -EINVAL;
+ }
+ urb->hcpriv = u132;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK &
+ endp->queue_last++] = urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq),
+ GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more,
+ &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ }
+ } else { /*(usb_addr > 0) */
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ urb->hcpriv = u132;
+ if (udev->enumeration == 2) {
+ } else
+ udev->enumeration = 2;
+ if (endp->queue_size++ < ENDP_QUEUE_SIZE) {
+ endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] =
+ urb;
+ } else {
+ struct u132_urbq *urbq =
+ kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC);
+ if (urbq == NULL) {
+ endp->queue_size -= 1;
+ return -ENOMEM;
+ } else {
+ list_add_tail(&urbq->urb_more, &endp->urb_more);
+ urbq->urb = urb;
+ }
+ }
+ return 0;
+ }
+}
+
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
+ struct urb *urb, gfp_t mem_flags)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (irqs_disabled()) {
+ if (__GFP_WAIT & mem_flags) {
+ printk(KERN_ERR "invalid context for function that migh"
+ "t sleep\n");
+ return -EINVAL;
+ }
+ }
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed urb="
+ "%p status=%d\n", urb, urb->status);
+ return -ESHUTDOWN;
+ } else {
+ u8 usb_addr = usb_pipedevice(urb->pipe);
+ u8 usb_endp = usb_pipeendpoint(urb->pipe);
+ struct usb_device *usb_dev = urb->dev;
+ if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ struct u132_endp *endp = hep->hcpriv;
+ urb->actual_length = 0;
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
+ retval = queue_int_on_old_endpoint(u132, udev,
+ hep, urb, usb_dev, endp, usb_addr,
+ usb_endp, address);
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp,
+ msecs_to_jiffies(urb->interval))
+ ;
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else { /*(endp == NULL) */
+ return create_endpoint_and_queue_int(u132, udev,
+ hep, urb, usb_dev, usb_addr, usb_endp,
+ address, mem_flags);
+ }
+ } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
+ dev_err(&u132->platform_dev->dev, "the hardware does no"
+ "t support PIPE_ISOCHRONOUS\n");
+ return -EINVAL;
+ } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ struct u132_endp *endp = hep->hcpriv;
+ urb->actual_length = 0;
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
+ retval = queue_bulk_on_old_endpoint(u132, udev,
+ hep, urb, usb_dev, endp, usb_addr,
+ usb_endp, address);
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else
+ return create_endpoint_and_queue_bulk(u132,
+ udev, hep, urb, usb_dev, usb_addr,
+ usb_endp, address, mem_flags);
+ } else {
+ struct u132_endp *endp = hep->hcpriv;
+ u16 urb_size = 8;
+ u8 *b = urb->setup_packet;
+ int i = 0;
+ char data[30 *3 + 4];
+ char *d = data;
+ int m = (sizeof(data) - 1) / 3;
+ int l = 0;
+ data[0] = 0;
+ while (urb_size-- > 0) {
+ if (i > m) {
+ } else if (i++ < m) {
+ int w = sprintf(d, " %02X", *b++);
+ d += w;
+ l += w;
+ } else
+ d += sprintf(d, " ..");
+ }
+ if (endp) {
+ unsigned long irqs;
+ int retval;
+ spin_lock_irqsave(&endp->queue_lock.slock,
+ irqs);
+ retval = queue_control_on_old_endpoint(u132,
+ hep, urb, usb_dev, endp, usb_addr,
+ usb_endp);
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ if (retval) {
+ return retval;
+ } else {
+ u132_endp_queue_work(u132, endp, 0);
+ return 0;
+ }
+ } else if (u132->num_endpoints == MAX_U132_ENDPS) {
+ return -EINVAL;
+ } else
+ return create_endpoint_and_queue_control(u132,
+ hep, urb, usb_dev, usb_addr, usb_endp,
+ mem_flags);
+ }
+ }
+}
+
+static int dequeue_from_overflow_chain(struct u132 *u132,
+ struct u132_endp *endp, struct urb *urb)
+{
+ struct list_head *scan;
+ struct list_head *head = &endp->urb_more;
+ list_for_each(scan, head) {
+ struct u132_urbq *urbq = list_entry(scan, struct u132_urbq,
+ urb_more);
+ if (urbq->urb == urb) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ list_del(scan);
+ endp->queue_size -= 1;
+ urb->error_count = 0;
+ urb->hcpriv = NULL;
+ usb_hcd_giveback_urb(hcd, urb);
+ return 0;
+ } else
+ continue;
+ }
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring"
+ "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X"
+ "\n", urb, endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
+ endp->usb_endp, endp->usb_addr, endp->queue_size,
+ endp->queue_next, endp->queue_last);
+ return -EINVAL;
+}
+
+static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
+ struct urb *urb)
+{
+ unsigned long irqs;
+ spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+ if (endp->queue_size == 0) {
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
+ "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
+ endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ', endp->output ? 'O' : ' ',
+ endp->usb_endp, endp->usb_addr);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return -EINVAL;
+ }
+ if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) {
+ if (endp->active) {
+ endp->dequeueing = 1;
+ endp->edset_flush = 1;
+ u132_endp_queue_work(u132, endp, 0);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ urb->hcpriv = NULL;
+ return 0;
+ } else {
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+ return 0;
+ }
+ } else {
+ u16 queue_list = 0;
+ u16 queue_size = endp->queue_size;
+ u16 queue_scan = endp->queue_next;
+ struct urb **urb_slot = NULL;
+ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
+ if (urb == endp->urb_list[ENDP_QUEUE_MASK &
+ ++queue_scan]) {
+ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
+ queue_scan];
+ break;
+ } else
+ continue;
+ }
+ while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) {
+ *urb_slot = endp->urb_list[ENDP_QUEUE_MASK &
+ ++queue_scan];
+ urb_slot = &endp->urb_list[ENDP_QUEUE_MASK &
+ queue_scan];
+ }
+ if (urb_slot) {
+ struct usb_hcd *hcd = u132_to_hcd(u132);
+ endp->queue_size -= 1;
+ if (list_empty(&endp->urb_more)) {
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ } else {
+ struct list_head *next = endp->urb_more.next;
+ struct u132_urbq *urbq = list_entry(next,
+ struct u132_urbq, urb_more);
+ list_del(next);
+ *urb_slot = urbq->urb;
+ spin_unlock_irqrestore(&endp->queue_lock.slock,
+ irqs);
+ kfree(urbq);
+ } urb->error_count = 0;
+ urb->hcpriv = NULL;
+ usb_hcd_giveback_urb(hcd, urb);
+ return 0;
+ } else if (list_empty(&endp->urb_more)) {
+ dev_err(&u132->platform_dev->dev, "urb=%p not found in "
+ "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr"
+ "=%d size=%d next=%04X last=%04X\n", urb,
+ endp->endp_number, endp, endp->ring->number,
+ endp->input ? 'I' : ' ',
+ endp->output ? 'O' : ' ', endp->usb_endp,
+ endp->usb_addr, endp->queue_size,
+ endp->queue_next, endp->queue_last);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return -EINVAL;
+ } else {
+ int retval = dequeue_from_overflow_chain(u132, endp,
+ urb);
+ spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+ return retval;
+ }
+ }
+}
+
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 2) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else {
+ u8 usb_addr = usb_pipedevice(urb->pipe);
+ u8 usb_endp = usb_pipeendpoint(urb->pipe);
+ u8 address = u132->addr[usb_addr].address;
+ struct u132_udev *udev = &u132->udev[address];
+ if (usb_pipein(urb->pipe)) {
+ u8 endp_number = udev->endp_number_in[usb_endp];
+ struct u132_endp *endp = u132->endp[endp_number - 1];
+ return u132_endp_urb_dequeue(u132, endp, urb);
+ } else {
+ u8 endp_number = udev->endp_number_out[usb_endp];
+ struct u132_endp *endp = u132->endp[endp_number - 1];
+ return u132_endp_urb_dequeue(u132, endp, urb);
+ }
+ }
+}
+
+static void u132_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *hep)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 2) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ } else {
+ struct u132_endp *endp = hep->hcpriv;
+ if (endp)
+ u132_endp_put_kref(u132, endp);
+ }
+}
+
+static int u132_get_frame(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int frame = 0;
+ dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n");
+ msleep(100);
+ return frame;
+ }
+}
+
+static int u132_roothub_descriptor(struct u132 *u132,
+ struct usb_hub_descriptor *desc)
+{
+ int retval;
+ u16 temp;
+ u32 rh_a = -1;
+ u32 rh_b = -1;
+ retval = u132_read_pcimem(u132, roothub.a, &rh_a);
+ if (retval)
+ return retval;
+ desc->bDescriptorType = 0x29;
+ desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24;
+ desc->bHubContrCurrent = 0;
+ desc->bNbrPorts = u132->num_ports;
+ temp = 1 + (u132->num_ports / 8);
+ desc->bDescLength = 7 + 2 *temp;
+ temp = 0;
+ if (rh_a & RH_A_NPS)
+ temp |= 0x0002;
+ if (rh_a & RH_A_PSM)
+ temp |= 0x0001;
+ if (rh_a & RH_A_NOCP) {
+ temp |= 0x0010;
+ } else if (rh_a & RH_A_OCPM)
+ temp |= 0x0008;
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+ retval = u132_read_pcimem(u132, roothub.b, &rh_b);
+ if (retval)
+ return retval;
+ memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
+ desc->bitmap[0] = rh_b & RH_B_DR;
+ if (u132->num_ports > 7) {
+ desc->bitmap[1] = (rh_b & RH_B_DR) >> 8;
+ desc->bitmap[2] = 0xff;
+ } else
+ desc->bitmap[1] = 0xff;
+ return 0;
+}
+
+static int u132_roothub_status(struct u132 *u132, __le32 *desc)
+{
+ u32 rh_status = -1;
+ int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status);
+ *desc = cpu_to_le32(rh_status);
+ return ret_status;
+}
+
+static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int port = wIndex - 1;
+ u32 rh_portstatus = -1;
+ int ret_portstatus = u132_read_pcimem(u132,
+ roothub.portstatus[port], &rh_portstatus);
+ *desc = cpu_to_le32(rh_portstatus);
+ if (*(u16 *) (desc + 2)) {
+ dev_info(&u132->platform_dev->dev, "Port %d Status Chan"
+ "ge = %08X\n", port, *desc);
+ }
+ return ret_portstatus;
+ }
+}
+
+
+/* this timer value might be vendor-specific ... */
+#define PORT_RESET_HW_MSEC 10
+#define PORT_RESET_MSEC 10
+/* wrap-aware logic morphed from <linux/jiffies.h> */
+#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0)
+static int u132_roothub_portreset(struct u132 *u132, int port_index)
+{
+ int retval;
+ u32 fmnumber;
+ u16 now;
+ u16 reset_done;
+ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
+ if (retval)
+ return retval;
+ now = fmnumber;
+ reset_done = now + PORT_RESET_MSEC;
+ do {
+ u32 portstat;
+ do {
+ retval = u132_read_pcimem(u132,
+ roothub.portstatus[port_index], &portstat);
+ if (retval)
+ return retval;
+ if (RH_PS_PRS & portstat) {
+ continue;
+ } else
+ break;
+ } while (tick_before(now, reset_done));
+ if (RH_PS_PRS & portstat)
+ return -ENODEV;
+ if (RH_PS_CCS & portstat) {
+ if (RH_PS_PRSC & portstat) {
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index],
+ RH_PS_PRSC);
+ if (retval)
+ return retval;
+ }
+ } else
+ break; /* start the next reset,
+ sleep till it's probably done */
+ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
+ RH_PS_PRS);
+ if (retval)
+ return retval;
+ msleep(PORT_RESET_HW_MSEC);
+ retval = u132_read_pcimem(u132, fmnumber, &fmnumber);
+ if (retval)
+ return retval;
+ now = fmnumber;
+ } while (tick_before(now, reset_done));
+ return 0;
+}
+
+static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue,
+ u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int retval;
+ int port_index = wIndex - 1;
+ struct u132_port *port = &u132->port[port_index];
+ port->Status &= ~(1 << wValue);
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index], RH_PS_PSS);
+ if (retval)
+ return retval;
+ return 0;
+ case USB_PORT_FEAT_POWER:
+ retval = u132_write_pcimem(u132,
+ roothub.portstatus[port_index], RH_PS_PPS);
+ if (retval)
+ return retval;
+ return 0;
+ case USB_PORT_FEAT_RESET:
+ retval = u132_roothub_portreset(u132, port_index);
+ if (retval)
+ return retval;
+ return 0;
+ default:
+ return -EPIPE;
+ }
+ }
+}
+
+static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue,
+ u16 wIndex)
+{
+ if (wIndex == 0 || wIndex > u132->num_ports) {
+ return -EINVAL;
+ } else {
+ int port_index = wIndex - 1;
+ u32 temp;
+ int retval;
+ struct u132_port *port = &u132->port[port_index];
+ port->Status &= ~(1 << wValue);
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ temp = RH_PS_CCS;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ temp = RH_PS_PESC;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ temp = RH_PS_POCI;
+ if ((u132->hc_control & OHCI_CTRL_HCFS)
+ != OHCI_USB_OPER) {
+ dev_err(&u132->platform_dev->dev, "TODO resume_"
+ "root_hub\n");
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ temp = RH_PS_PSSC;
+ break;
+ case USB_PORT_FEAT_POWER:
+ temp = RH_PS_LSDA;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ temp = RH_PS_CSC;
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ temp = RH_PS_OCIC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ temp = RH_PS_PRSC;
+ break;
+ default:
+ return -EPIPE;
+ }
+ retval = u132_write_pcimem(u132, roothub.portstatus[port_index],
+ temp);
+ if (retval)
+ return retval;
+ return 0;
+ }
+}
+
+
+/* the virtual root hub timer IRQ checks for hub status*/
+static int u132_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov"
+ "ed %d\n", hcd, u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
+ "ed\n", hcd);
+ dump_stack();
+ return -ESHUTDOWN;
+ } else {
+ int i, changed = 0, length = 1;
+ if (u132->flags & OHCI_QUIRK_AMD756) {
+ if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) {
+ dev_err(&u132->platform_dev->dev, "bogus NDP, r"
+ "ereads as NDP=%d\n",
+ u132->hc_roothub_a & RH_A_NDP);
+ goto done;
+ }
+ }
+ if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) {
+ buf[0] = changed = 1;
+ } else
+ buf[0] = 0;
+ if (u132->num_ports > 7) {
+ buf[1] = 0;
+ length++;
+ }
+ for (i = 0; i < u132->num_ports; i++) {
+ if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC |
+ RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC |
+ RH_PS_PRSC)) {
+ changed = 1;
+ if (i < 7) {
+ buf[0] |= 1 << (i + 1);
+ } else
+ buf[1] |= 1 << (i - 7);
+ continue;
+ }
+ if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) {
+ continue;
+ }
+ if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) {
+ continue;
+ }
+ }
+ done:return changed ? length : 0;
+ }
+}
+
+static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+ u16 wIndex, char *buf, u16 wLength)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ down(&u132->sw_lock);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto stall;
+ }
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ break;
+ default:
+ goto stall;
+ }
+ break;
+ case ClearPortFeature:{
+ retval = u132_roothub_clearportfeature(u132,
+ wValue, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetHubDescriptor:{
+ retval = u132_roothub_descriptor(u132,
+ (struct usb_hub_descriptor *)buf);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetHubStatus:{
+ retval = u132_roothub_status(u132,
+ (__le32 *) buf);
+ if (retval)
+ goto error;
+ break;
+ }
+ case GetPortStatus:{
+ retval = u132_roothub_portstatus(u132,
+ (__le32 *) buf, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ case SetPortFeature:{
+ retval = u132_roothub_setportfeature(u132,
+ wValue, wIndex);
+ if (retval)
+ goto error;
+ break;
+ }
+ default:
+ goto stall;
+ error:u132_disable(u132);
+ u132->going = 1;
+ break;
+ stall:retval = -EPIPE;
+ break;
+ }
+ up(&u132->sw_lock);
+ return retval;
+ }
+}
+
+static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static void u132_hub_irq_enable(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ } else if (u132->going > 0)
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+}
+
+
+#ifdef CONFIG_PM
+static int u132_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static int u132_hcd_resume(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static int u132_bus_suspend(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+static int u132_bus_resume(struct usb_hcd *hcd)
+{
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else
+ return 0;
+}
+
+#else
+#define u132_hcd_suspend NULL
+#define u132_hcd_resume NULL
+#define u132_bus_suspend NULL
+#define u132_bus_resume NULL
+#endif
+static struct hc_driver u132_hc_driver = {
+ .description = hcd_name,
+ .hcd_priv_size = sizeof(struct u132),
+ .irq = NULL,
+ .flags = HCD_USB11 | HCD_MEMORY,
+ .reset = u132_hcd_reset,
+ .start = u132_hcd_start,
+ .suspend = u132_hcd_suspend,
+ .resume = u132_hcd_resume,
+ .stop = u132_hcd_stop,
+ .urb_enqueue = u132_urb_enqueue,
+ .urb_dequeue = u132_urb_dequeue,
+ .endpoint_disable = u132_endpoint_disable,
+ .get_frame_number = u132_get_frame,
+ .hub_status_data = u132_hub_status_data,
+ .hub_control = u132_hub_control,
+ .bus_suspend = u132_bus_suspend,
+ .bus_resume = u132_bus_resume,
+ .start_port_reset = u132_start_port_reset,
+ .hub_irq_enable = u132_hub_irq_enable,
+};
+
+/*
+* This function may be called by the USB core whilst the "usb_all_devices_rwsem"
+* is held for writing, thus this module must not call usb_remove_hcd()
+* synchronously - but instead should immediately stop activity to the
+* device and ansynchronously call usb_remove_hcd()
+*/
+static int __devexit u132_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ if (hcd) {
+ struct u132 *u132 = hcd_to_u132(hcd);
+ dump_stack();
+ if (u132->going++ > 1) {
+ return -ENODEV;
+ } else {
+ int rings = MAX_U132_RINGS;
+ int endps = MAX_U132_ENDPS;
+ msleep(100);
+ down(&u132->sw_lock);
+ u132_monitor_cancel_work(u132);
+ while (rings-- > 0) {
+ struct u132_ring *ring = &u132->ring[rings];
+ u132_ring_cancel_work(u132, ring);
+ } while (endps-- > 0) {
+ struct u132_endp *endp = u132->endp[endps];
+ if (endp)
+ u132_endp_cancel_work(u132, endp);
+ }
+ u132->going += 1;
+ printk(KERN_INFO "removing device u132.%d\n",
+ u132->sequence_num);
+ up(&u132->sw_lock);
+ usb_remove_hcd(hcd);
+ u132_u132_put_kref(u132);
+ return 0;
+ }
+ } else
+ return 0;
+}
+
+static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
+{
+ int rings = MAX_U132_RINGS;
+ int ports = MAX_U132_PORTS;
+ int addrs = MAX_U132_ADDRS;
+ int udevs = MAX_U132_UDEVS;
+ int endps = MAX_U132_ENDPS;
+ u132->board = pdev->dev.platform_data;
+ u132->platform_dev = pdev;
+ u132->power = 0;
+ u132->reset = 0;
+ init_MUTEX(&u132->sw_lock);
+ init_MUTEX(&u132->scheduler_lock);
+ while (rings-- > 0) {
+ struct u132_ring *ring = &u132->ring[rings];
+ ring->u132 = u132;
+ ring->number = rings + 1;
+ ring->length = 0;
+ ring->curr_endp = NULL;
+ INIT_WORK(&ring->scheduler, u132_hcd_ring_work_scheduler,
+ (void *)ring);
+ } down(&u132->sw_lock);
+ INIT_WORK(&u132->monitor, u132_hcd_monitor_work, (void *)u132);
+ while (ports-- > 0) {
+ struct u132_port *port = &u132->port[ports];
+ port->u132 = u132;
+ port->reset = 0;
+ port->enable = 0;
+ port->power = 0;
+ port->Status = 0;
+ } while (addrs-- > 0) {
+ struct u132_addr *addr = &u132->addr[addrs];
+ addr->address = 0;
+ } while (udevs-- > 0) {
+ struct u132_udev *udev = &u132->udev[udevs];
+ int i = ARRAY_SIZE(udev->endp_number_in);
+ int o = ARRAY_SIZE(udev->endp_number_out);
+ udev->usb_device = NULL;
+ udev->udev_number = 0;
+ udev->usb_addr = 0;
+ udev->portnumber = 0;
+ while (i-- > 0) {
+ udev->endp_number_in[i] = 0;
+ }
+ while (o-- > 0) {
+ udev->endp_number_out[o] = 0;
+ }
+ }
+ while (endps-- > 0) {
+ u132->endp[endps] = NULL;
+ }
+ up(&u132->sw_lock);
+ return;
+}
+
+static int __devinit u132_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ msleep(100);
+ if (u132_exiting > 0) {
+ return -ENODEV;
+ } /* refuse to confuse usbcore */
+ if (pdev->dev.dma_mask) {
+ return -EINVAL;
+ }
+ hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, pdev->dev.bus_id);
+ if (!hcd) {
+ printk(KERN_ERR "failed to create the usb hcd struct for U132\n"
+ );
+ ftdi_elan_gone_away(pdev);
+ return -ENOMEM;
+ } else {
+ int retval = 0;
+ struct u132 *u132 = hcd_to_u132(hcd);
+ hcd->rsrc_start = 0;
+ down(&u132_module_lock);
+ list_add_tail(&u132->u132_list, &u132_static_list);
+ u132->sequence_num = ++u132_instances;
+ up(&u132_module_lock);
+ u132_u132_init_kref(u132);
+ u132_initialise(u132, pdev);
+ hcd->product_desc = "ELAN U132 Host Controller";
+ retval = usb_add_hcd(hcd, 0, 0);
+ if (retval != 0) {
+ dev_err(&u132->platform_dev->dev, "init error %d\n",
+ retval);
+ u132_u132_put_kref(u132);
+ return retval;
+ } else {
+ u132_monitor_queue_work(u132, 100);
+ return 0;
+ }
+ }
+}
+
+
+#ifdef CONFIG_PM
+/* for this device there's no useful distinction between the controller
+* and its root hub, except that the root hub only gets direct PM calls
+* when CONFIG_USB_SUSPEND is enabled.
+*/
+static int u132_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ if (state.event == PM_EVENT_FREEZE) {
+ retval = u132_bus_suspend(hcd);
+ } else if (state.event == PM_EVENT_SUSPEND) {
+ int ports = MAX_U132_PORTS;
+ while (ports-- > 0) {
+ port_power(u132, ports, 0);
+ }
+ }
+ if (retval == 0)
+ pdev->dev.power.power_state = state;
+ return retval;
+ }
+}
+
+static int u132_resume(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct u132 *u132 = hcd_to_u132(hcd);
+ if (u132->going > 1) {
+ dev_err(&u132->platform_dev->dev, "device has been removed %d\n"
+ , u132->going);
+ return -ENODEV;
+ } else if (u132->going > 0) {
+ dev_err(&u132->platform_dev->dev, "device is being removed\n");
+ return -ESHUTDOWN;
+ } else {
+ int retval = 0;
+ if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
+ int ports = MAX_U132_PORTS;
+ while (ports-- > 0) {
+ port_power(u132, ports, 1);
+ }
+ retval = 0;
+ } else {
+ pdev->dev.power.power_state = PMSG_ON;
+ retval = u132_bus_resume(hcd);
+ }
+ return retval;
+ }
+}
+
+#else
+#define u132_suspend NULL
+#define u132_resume NULL
+#endif
+/*
+* this driver is loaded explicitely by ftdi_u132
+*
+* the platform_driver struct is static because it is per type of module
+*/
+static struct platform_driver u132_platform_driver = {
+ .probe = u132_probe,
+ .remove = __devexit_p(u132_remove),
+ .suspend = u132_suspend,
+ .resume = u132_resume,
+ .driver = {
+ .name = (char *)hcd_name,
+ .owner = THIS_MODULE,
+ },
+};
+static int __init u132_hcd_init(void)
+{
+ int retval;
+ INIT_LIST_HEAD(&u132_static_list);
+ u132_instances = 0;
+ u132_exiting = 0;
+ init_MUTEX(&u132_module_lock);
+ if (usb_disabled())
+ return -ENODEV;
+ printk(KERN_INFO "driver %s built at %s on %s\n", hcd_name, __TIME__,
+ __DATE__);
+ workqueue = create_singlethread_workqueue("u132");
+ retval = platform_driver_register(&u132_platform_driver);
+ return retval;
+}
+
+
+module_init(u132_hcd_init);
+static void __exit u132_hcd_exit(void)
+{
+ struct u132 *u132;
+ struct u132 *temp;
+ down(&u132_module_lock);
+ u132_exiting += 1;
+ up(&u132_module_lock);
+ list_for_each_entry_safe(u132, temp, &u132_static_list, u132_list) {
+ platform_device_unregister(u132->platform_dev);
+ } platform_driver_unregister(&u132_platform_driver);
+ printk(KERN_INFO "u132-hcd driver deregistered\n");
+ wait_event(u132_hcd_wait, u132_instances == 0);
+ flush_workqueue(workqueue);
+ destroy_workqueue(workqueue);
+}
+
+
+module_exit(u132_hcd_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index dc286a48cafd..e345f15b7d87 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -16,7 +16,7 @@
#include "uhci-hcd.h"
-#define uhci_debug_operations (* (struct file_operations *) NULL)
+#define uhci_debug_operations (* (const struct file_operations *) NULL)
static struct dentry *uhci_debugfs_root;
#ifdef DEBUG
@@ -428,7 +428,7 @@ struct uhci_debug {
static int uhci_debug_open(struct inode *inode, struct file *file)
{
- struct uhci_hcd *uhci = inode->u.generic_ip;
+ struct uhci_hcd *uhci = inode->i_private;
struct uhci_debug *up;
int ret = -ENOMEM;
unsigned long flags;
@@ -500,7 +500,7 @@ static int uhci_debug_release(struct inode *inode, struct file *file)
}
#undef uhci_debug_operations
-static struct file_operations uhci_debug_operations = {
+static const struct file_operations uhci_debug_operations = {
.owner = THIS_MODULE,
.open = uhci_debug_open,
.llseek = uhci_debug_lseek,
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index b7402ceb3e93..226bf3de8edd 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -40,6 +40,7 @@
#include <linux/dma-mapping.h>
#include <linux/usb.h>
#include <linux/bitops.h>
+#include <linux/dmi.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -196,12 +197,42 @@ static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
return 0;
}
+static int remote_wakeup_is_broken(struct uhci_hcd *uhci)
+{
+ static struct dmi_system_id broken_wakeup_table[] = {
+ {
+ .ident = "Asus A7V8X",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK"),
+ DMI_MATCH(DMI_BOARD_NAME, "A7V8X"),
+ DMI_MATCH(DMI_BOARD_VERSION, "REV 1.xx"),
+ }
+ },
+ { }
+ };
+ int port;
+
+ /* One of Asus's motherboards has a bug which causes it to
+ * wake up immediately from suspend-to-RAM if any of the ports
+ * are connected. In such cases we will not set EGSM.
+ */
+ if (dmi_check_system(broken_wakeup_table)) {
+ for (port = 0; port < uhci->rh_numports; ++port) {
+ if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+ USBPORTSC_CCS)
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
__releases(uhci->lock)
__acquires(uhci->lock)
{
int auto_stop;
- int int_enable;
+ int int_enable, egsm_enable;
auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
dev_dbg(&uhci_to_hcd(uhci)->self.root_hub->dev,
@@ -217,15 +248,18 @@ __acquires(uhci->lock)
}
/* Enable resume-detect interrupts if they work.
- * Then enter Global Suspend mode, still configured.
+ * Then enter Global Suspend mode if _it_ works, still configured.
*/
+ egsm_enable = USBCMD_EGSM;
uhci->working_RD = 1;
int_enable = USBINTR_RESUME;
- if (resume_detect_interrupts_are_broken(uhci)) {
+ if (remote_wakeup_is_broken(uhci))
+ egsm_enable = 0;
+ if (resume_detect_interrupts_are_broken(uhci) || !egsm_enable)
uhci->working_RD = int_enable = 0;
- }
+
outw(int_enable, uhci->io_addr + USBINTR);
- outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
+ outw(egsm_enable | USBCMD_CF, uhci->io_addr + USBCMD);
mb();
udelay(5);
@@ -252,7 +286,7 @@ __acquires(uhci->lock)
uhci->is_stopped = UHCI_IS_STOPPED;
uhci_to_hcd(uhci)->poll_rh = !int_enable;
- uhci_scan_schedule(uhci, NULL);
+ uhci_scan_schedule(uhci);
uhci_fsbr_off(uhci);
}
@@ -309,7 +343,7 @@ __acquires(uhci->lock)
mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
}
-static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+static irqreturn_t uhci_irq(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
unsigned short status;
@@ -358,7 +392,7 @@ static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
usb_hcd_poll_rh_status(hcd);
else {
spin_lock_irqsave(&uhci->lock, flags);
- uhci_scan_schedule(uhci, regs);
+ uhci_scan_schedule(uhci);
spin_unlock_irqrestore(&uhci->lock, flags);
}
@@ -671,7 +705,7 @@ static void uhci_stop(struct usb_hcd *hcd)
spin_lock_irq(&uhci->lock);
if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) && !uhci->dead)
uhci_hc_died(uhci);
- uhci_scan_schedule(uhci, NULL);
+ uhci_scan_schedule(uhci);
spin_unlock_irq(&uhci->lock);
del_timer_sync(&uhci->fsbr_timer);
@@ -913,8 +947,7 @@ static int __init uhci_hcd_init(void)
return 0;
init_failed:
- if (kmem_cache_destroy(uhci_up_cachep))
- warn("not all urb_privs were freed!");
+ kmem_cache_destroy(uhci_up_cachep);
up_failed:
debugfs_remove(uhci_debugfs_root);
@@ -930,10 +963,7 @@ errbuf_failed:
static void __exit uhci_hcd_cleanup(void)
{
pci_unregister_driver(&uhci_pci_driver);
-
- if (kmem_cache_destroy(uhci_up_cachep))
- warn("not all urb_privs were freed!");
-
+ kmem_cache_destroy(uhci_up_cachep);
debugfs_remove(uhci_debugfs_root);
kfree(errbuf);
}
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index c545ef92fe29..f8347f1a10b6 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -84,6 +84,7 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
unsigned long port_addr)
{
int status;
+ int i;
if (inw(port_addr) & (USBPORTSC_SUSP | USBPORTSC_RD)) {
CLR_RH_PORTSTAT(USBPORTSC_SUSP | USBPORTSC_RD);
@@ -92,9 +93,14 @@ static void uhci_finish_suspend(struct uhci_hcd *uhci, int port,
/* The controller won't actually turn off the RD bit until
* it has had a chance to send a low-speed EOP sequence,
- * which takes 3 bit times (= 2 microseconds). We'll delay
- * slightly longer for good luck. */
- udelay(4);
+ * which is supposed to take 3 bit times (= 2 microseconds).
+ * Experiments show that some controllers take longer, so
+ * we'll poll for completion. */
+ for (i = 0; i < 10; ++i) {
+ if (!(inw(port_addr) & USBPORTSC_RD))
+ break;
+ udelay(1);
+ }
}
clear_bit(port, &uhci->resuming_ports);
}
@@ -170,7 +176,7 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
spin_lock_irqsave(&uhci->lock, flags);
- uhci_scan_schedule(uhci, NULL);
+ uhci_scan_schedule(uhci);
if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead)
goto done;
uhci_check_ports(uhci);
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 431e8f31f1a9..06115f22a4fa 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -1244,7 +1244,7 @@ done:
* Finish unlinking an URB and give it back
*/
static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
- struct urb *urb, struct pt_regs *regs)
+ struct urb *urb)
__releases(uhci->lock)
__acquires(uhci->lock)
{
@@ -1293,7 +1293,7 @@ __acquires(uhci->lock)
}
spin_unlock(&uhci->lock);
- usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, regs);
+ usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
spin_lock(&uhci->lock);
/* If the queue is now empty, we can unlink the QH and give up its
@@ -1313,8 +1313,7 @@ __acquires(uhci->lock)
(qh->state == QH_STATE_UNLINKING && \
uhci->frame_number + uhci->is_stopped != qh->unlink_frame)
-static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
- struct pt_regs *regs)
+static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
{
struct urb_priv *urbp;
struct urb *urb;
@@ -1347,7 +1346,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh,
return;
}
- uhci_giveback_urb(uhci, qh, urb, regs);
+ uhci_giveback_urb(uhci, qh, urb);
if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
break;
}
@@ -1372,7 +1371,7 @@ restart:
qh->is_stopped = 0;
return;
}
- uhci_giveback_urb(uhci, qh, urb, regs);
+ uhci_giveback_urb(uhci, qh, urb);
goto restart;
}
}
@@ -1487,7 +1486,7 @@ done:
/*
* Process events in the schedule, but only in one thread at a time
*/
-static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
+static void uhci_scan_schedule(struct uhci_hcd *uhci)
{
int i;
struct uhci_qh *qh;
@@ -1515,7 +1514,7 @@ rescan:
struct uhci_qh, node);
if (uhci_advance_check(uhci, qh)) {
- uhci_scan_qh(uhci, qh, regs);
+ uhci_scan_qh(uhci, qh);
if (qh->state == QH_STATE_ACTIVE) {
uhci_urbp_wants_fsbr(uhci,
list_entry(qh->queue.next, struct urb_priv, node));
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 08daf400f985..63a84bbc310d 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -280,7 +280,7 @@ static int mdc800_isReady (char *ch)
/*
* USB IRQ Handler for InputLine
*/
-static void mdc800_usb_irq (struct urb *urb, struct pt_regs *res)
+static void mdc800_usb_irq (struct urb *urb)
{
int data_received=0, wake_up;
unsigned char* b=urb->transfer_buffer;
@@ -374,7 +374,7 @@ static int mdc800_usb_waitForIRQ (int mode, int msec)
/*
* The write_urb callback function
*/
-static void mdc800_usb_write_notify (struct urb *urb, struct pt_regs *res)
+static void mdc800_usb_write_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
@@ -394,7 +394,7 @@ static void mdc800_usb_write_notify (struct urb *urb, struct pt_regs *res)
/*
* The download_urb callback function
*/
-static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
+static void mdc800_usb_download_notify (struct urb *urb)
{
struct mdc800_data* mdc800=urb->context;
@@ -424,7 +424,7 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
***************************************************************************/
static struct usb_driver mdc800_usb_driver;
-static struct file_operations mdc800_device_ops;
+static const struct file_operations mdc800_device_ops;
static struct usb_class_driver mdc800_class = {
.name = "mdc800%d",
.fops = &mdc800_device_ops,
@@ -941,7 +941,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s
****************************************************************************/
/* File Operations of this drivers */
-static struct file_operations mdc800_device_ops =
+static const struct file_operations mdc800_device_ops =
{
.owner = THIS_MODULE,
.read = mdc800_device_read,
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index b2bafc37c414..3038ed0700d3 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -225,7 +225,7 @@ static inline void mts_debug_dump(struct mts_desc* desc) {
}
-static inline void mts_show_command(Scsi_Cmnd *srb)
+static inline void mts_show_command(struct scsi_cmnd *srb)
{
char *what = NULL;
@@ -309,7 +309,7 @@ static inline void mts_show_command(Scsi_Cmnd *srb)
#else
-static inline void mts_show_command(Scsi_Cmnd * dummy)
+static inline void mts_show_command(struct scsi_cmnd * dummy)
{
}
@@ -338,7 +338,7 @@ static int mts_slave_configure (struct scsi_device *s)
return 0;
}
-static int mts_scsi_abort (Scsi_Cmnd *srb)
+static int mts_scsi_abort(struct scsi_cmnd *srb)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
@@ -349,7 +349,7 @@ static int mts_scsi_abort (Scsi_Cmnd *srb)
return FAILED;
}
-static int mts_scsi_host_reset (Scsi_Cmnd *srb)
+static int mts_scsi_host_reset(struct scsi_cmnd *srb)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
int result, rc;
@@ -366,11 +366,11 @@ static int mts_scsi_host_reset (Scsi_Cmnd *srb)
return result ? FAILED : SUCCESS;
}
-static
-int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback );
+static int
+mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback);
static void mts_transfer_cleanup( struct urb *transfer );
-static void mts_do_sg(struct urb * transfer, struct pt_regs *regs);
+static void mts_do_sg(struct urb * transfer);
static inline
void mts_int_submit_urb (struct urb* transfer,
@@ -417,7 +417,7 @@ static void mts_transfer_cleanup( struct urb *transfer )
}
-static void mts_transfer_done( struct urb *transfer, struct pt_regs *regs )
+static void mts_transfer_done( struct urb *transfer )
{
MTS_INT_INIT();
@@ -443,7 +443,7 @@ static void mts_get_status( struct urb *transfer )
mts_transfer_done );
}
-static void mts_data_done( struct urb* transfer, struct pt_regs *regs )
+static void mts_data_done( struct urb* transfer )
/* Interrupt context! */
{
MTS_INT_INIT();
@@ -460,7 +460,7 @@ static void mts_data_done( struct urb* transfer, struct pt_regs *regs )
}
-static void mts_command_done( struct urb *transfer, struct pt_regs *regs )
+static void mts_command_done( struct urb *transfer )
/* Interrupt context! */
{
MTS_INT_INIT();
@@ -501,7 +501,7 @@ static void mts_command_done( struct urb *transfer, struct pt_regs *regs )
return;
}
-static void mts_do_sg (struct urb* transfer, struct pt_regs *regs)
+static void mts_do_sg (struct urb* transfer)
{
struct scatterlist * sg;
MTS_INT_INIT();
@@ -537,7 +537,7 @@ static const unsigned char mts_direction[256/8] = {
#define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1)
static void
-mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
+mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc)
{
int pipe;
struct scatterlist * sg;
@@ -588,8 +588,8 @@ mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc )
}
-static
-int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback )
+static int
+mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback)
{
struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]);
int err = 0;
diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h
index 926d4bdc6746..d5d62a939058 100644
--- a/drivers/usb/image/microtek.h
+++ b/drivers/usb/image/microtek.h
@@ -8,14 +8,14 @@
*
*/
-typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *);
+typedef void (*mts_scsi_cmnd_callback)(struct scsi_cmnd *);
struct mts_transfer_context
{
struct mts_desc* instance;
mts_scsi_cmnd_callback final_callback;
- Scsi_Cmnd *srb;
+ struct scsi_cmnd *srb;
void* data;
unsigned data_length;
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index 650103bc9618..20db36448ab3 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -60,16 +60,17 @@ config HID_FF
If unsure, say N.
config HID_PID
- bool "PID Devices (Microsoft Sidewinder Force Feedback 2)"
+ bool "PID device support"
depends on HID_FF
help
- Say Y here if you have a PID-compliant joystick and wish to enable force
- feedback for it. The Microsoft Sidewinder Force Feedback 2 is one such
- device.
+ Say Y here if you have a PID-compliant device and wish to enable force
+ feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such
+ devices.
config LOGITECH_FF
bool "Logitech WingMan *3D support"
depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have one of these devices:
- Logitech WingMan Cordless RumblePad
@@ -81,12 +82,21 @@ config LOGITECH_FF
config THRUSTMASTER_FF
bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
depends on HID_FF && EXPERIMENTAL
+ select INPUT_FF_MEMLESS if USB_HID
help
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2,
and want to enable force feedback support for it.
Note: if you say N here, this device will still be supported, but without
force feedback.
+config ZEROPLUS_FF
+ bool "Zeroplus based game controller support"
+ depends on HID_FF
+ select INPUT_FF_MEMLESS if USB_HID
+ help
+ Say Y here if you have a Zeroplus based game controller and want to
+ enable force feedback for it.
+
config USB_HIDDEV
bool "/dev/hiddev raw HID device support"
depends on USB_HID
@@ -205,10 +215,12 @@ config USB_TOUCHSCREEN
depends on USB && INPUT
---help---
USB Touchscreen driver for:
- - eGalax Touchkit USB
+ - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700)
- PanJit TouchSet USB
- - 3M MicroTouch USB
+ - 3M MicroTouch USB (EX II series)
- ITM
+ - some other eTurboTouch
+ - Gunze AHL61
Have a look at <http://linux.chapter7.ch/touchkit/> for
a usage description and the required user-space stuff.
@@ -218,7 +230,7 @@ config USB_TOUCHSCREEN
config USB_TOUCHSCREEN_EGALAX
default y
- bool "eGalax device support" if EMBEDDED
+ bool "eGalax, eTurboTouch CT-410/510/700 device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_PANJIT
@@ -228,7 +240,7 @@ config USB_TOUCHSCREEN_PANJIT
config USB_TOUCHSCREEN_3M
default y
- bool "3M/Microtouch device support" if EMBEDDED
+ bool "3M/Microtouch EX II series device support" if EMBEDDED
depends on USB_TOUCHSCREEN
config USB_TOUCHSCREEN_ITM
@@ -236,6 +248,16 @@ config USB_TOUCHSCREEN_ITM
bool "ITM device support" if EMBEDDED
depends on USB_TOUCHSCREEN
+config USB_TOUCHSCREEN_ETURBO
+ default y
+ bool "eTurboTouch (non-eGalax compatible) device support" if EMBEDDED
+ depends on USB_TOUCHSCREEN
+
+config USB_TOUCHSCREEN_GUNZE
+ default y
+ bool "Gunze AHL61 device support" if EMBEDDED
+ depends on USB_TOUCHSCREEN
+
config USB_YEALINK
tristate "Yealink usb-p1k voip phone"
depends on USB && INPUT && EXPERIMENTAL
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 764114529c56..d946d5213b30 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -3,6 +3,7 @@
#
# Multipart objects.
+wacom-objs := wacom_wac.o wacom_sys.o
usbhid-objs := hid-core.o
# Optional parts of multipart objects.
@@ -14,7 +15,7 @@ ifeq ($(CONFIG_USB_HIDINPUT),y)
usbhid-objs += hid-input.o
endif
ifeq ($(CONFIG_HID_PID),y)
- usbhid-objs += pid.o
+ usbhid-objs += hid-pidff.o
endif
ifeq ($(CONFIG_LOGITECH_FF),y)
usbhid-objs += hid-lgff.o
@@ -22,6 +23,9 @@ endif
ifeq ($(CONFIG_THRUSTMASTER_FF),y)
usbhid-objs += hid-tmff.o
endif
+ifeq ($(CONFIG_ZEROPLUS_FF),y)
+ usbhid-objs += hid-zpff.o
+endif
ifeq ($(CONFIG_HID_FF),y)
usbhid-objs += hid-ff.o
endif
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
index 18c10e150ef3..0096373b5f98 100644
--- a/drivers/usb/input/acecad.c
+++ b/drivers/usb/input/acecad.c
@@ -58,7 +58,7 @@ struct usb_acecad {
dma_addr_t data_dma;
};
-static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs)
+static void usb_acecad_irq(struct urb *urb)
{
struct usb_acecad *acecad = urb->context;
unsigned char *data = acecad->data;
@@ -141,10 +141,7 @@ static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_
endpoint = &interface->endpoint[0].desc;
- if (!(endpoint->bEndpointAddress & 0x80))
- return -ENODEV;
-
- if ((endpoint->bmAttributes & 3) != 3)
+ if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index b138dae2b055..bf428184608f 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -396,7 +396,7 @@ static int aiptek_convert_from_2s_complement(unsigned char c)
* replaced with the input_sync() method (which emits EV_SYN.)
*/
-static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
+static void aiptek_irq(struct urb *urb)
{
struct aiptek *aiptek = urb->context;
unsigned char *data = aiptek->data;
@@ -442,8 +442,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
aiptek->diagnostic =
AIPTEK_DIAGNOSTIC_SENDING_RELATIVE_IN_ABSOLUTE;
} else {
- input_regs(inputdev, regs);
-
x = aiptek_convert_from_2s_complement(data[2]);
y = aiptek_convert_from_2s_complement(data[3]);
@@ -488,8 +486,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
(aiptek->curSetting.pointerMode)) {
aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
} else {
- input_regs(inputdev, regs);
-
x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
z = le16_to_cpu(get_unaligned((__le16 *) (data + 6)));
@@ -568,7 +564,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
(aiptek->curSetting.pointerMode)) {
aiptek->diagnostic = AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED;
} else {
- input_regs(inputdev, regs);
x = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
y = le16_to_cpu(get_unaligned((__le16 *) (data + 3)));
@@ -631,8 +626,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
z = le16_to_cpu(get_unaligned((__le16 *) (data + 4)));
if (dv != 0) {
- input_regs(inputdev, regs);
-
/* If we've not already sent a tool_button_?? code, do
* so now. Then set FIRED_BIT so it won't be resent unless
* the user forces FIRED_BIT off.
@@ -681,8 +674,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
macro = data[3];
if (dv != 0) {
- input_regs(inputdev, regs);
-
/* If we've not already sent a tool_button_?? code, do
* so now. Then set FIRED_BIT so it won't be resent unless
* the user forces FIRED_BIT off.
@@ -726,8 +717,6 @@ static void aiptek_irq(struct urb *urb, struct pt_regs *regs)
*/
else if (data[0] == 6) {
macro = le16_to_cpu(get_unaligned((__le16 *) (data + 1)));
- input_regs(inputdev, regs);
-
if (macro > 0) {
input_report_key(inputdev, macroKeyEvents[macro - 1],
0);
diff --git a/drivers/usb/input/appletouch.c b/drivers/usb/input/appletouch.c
index 044faa07e297..4c213513484d 100644
--- a/drivers/usb/input/appletouch.c
+++ b/drivers/usb/input/appletouch.c
@@ -210,7 +210,7 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
}
-static void atp_complete(struct urb* urb, struct pt_regs* regs)
+static void atp_complete(struct urb* urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
@@ -436,10 +436,7 @@ static int atp_probe(struct usb_interface *iface, const struct usb_device_id *id
iface_desc = iface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
endpoint = &iface_desc->endpoint[i].desc;
- if (!int_in_endpointAddr &&
- (endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT)) {
+ if (!int_in_endpointAddr && usb_endpoint_is_int_in(endpoint)) {
/* we found an interrupt in endpoint */
int_in_endpointAddr = endpoint->bEndpointAddress;
break;
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index 3719fcb04b8f..f659f3028ad2 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -283,9 +283,9 @@ static void ati_remote_dump (unsigned char *data, unsigned int actual_length);
static int ati_remote_open (struct input_dev *inputdev);
static void ati_remote_close (struct input_dev *inputdev);
static int ati_remote_sendpacket (struct ati_remote *ati_remote, u16 cmd, unsigned char *data);
-static void ati_remote_irq_out (struct urb *urb, struct pt_regs *regs);
-static void ati_remote_irq_in (struct urb *urb, struct pt_regs *regs);
-static void ati_remote_input_report (struct urb *urb, struct pt_regs *regs);
+static void ati_remote_irq_out (struct urb *urb);
+static void ati_remote_irq_in (struct urb *urb);
+static void ati_remote_input_report (struct urb *urb);
static int ati_remote_initialize (struct ati_remote *ati_remote);
static int ati_remote_probe (struct usb_interface *interface, const struct usb_device_id *id);
static void ati_remote_disconnect (struct usb_interface *interface);
@@ -344,7 +344,7 @@ static void ati_remote_close(struct input_dev *inputdev)
/*
* ati_remote_irq_out
*/
-static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
+static void ati_remote_irq_out(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
@@ -453,7 +453,7 @@ static int ati_remote_compute_accel(struct ati_remote *ati_remote)
/*
* ati_remote_report_input
*/
-static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
+static void ati_remote_input_report(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
unsigned char *data= ati_remote->inbuf;
@@ -491,7 +491,6 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
if (ati_remote_tbl[index].kind == KIND_LITERAL) {
- input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code,
ati_remote_tbl[index].value);
@@ -520,7 +519,6 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
return;
- input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code, 1);
input_sync(dev);
@@ -537,7 +535,6 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
*/
acc = ati_remote_compute_accel(ati_remote);
- input_regs(dev, regs);
switch (ati_remote_tbl[index].kind) {
case KIND_ACCEL:
input_event(dev, ati_remote_tbl[index].type,
@@ -575,14 +572,14 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
/*
* ati_remote_irq_in
*/
-static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
+static void ati_remote_irq_in(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
int retval;
switch (urb->status) {
case 0: /* success */
- ati_remote_input_report(urb, regs);
+ ati_remote_input_report(urb);
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
@@ -732,12 +729,8 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
endpoint_in = &iface_host->endpoint[0].desc;
endpoint_out = &iface_host->endpoint[1].desc;
- if (!(endpoint_in->bEndpointAddress & USB_DIR_IN)) {
- err("%s: Unexpected endpoint_in->bEndpointAddress\n", __FUNCTION__);
- return -ENODEV;
- }
- if ((endpoint_in->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
- err("%s: Unexpected endpoint_in->bmAttributes\n", __FUNCTION__);
+ if (!usb_endpoint_is_int_in(endpoint_in)) {
+ err("%s: Unexpected endpoint_in\n", __FUNCTION__);
return -ENODEV;
}
if (le16_to_cpu(endpoint_in->wMaxPacketSize) == 0) {
diff --git a/drivers/usb/input/ati_remote2.c b/drivers/usb/input/ati_remote2.c
index ea71de81ca6b..f982a2b4a7f9 100644
--- a/drivers/usb/input/ati_remote2.c
+++ b/drivers/usb/input/ati_remote2.c
@@ -142,7 +142,7 @@ static void ati_remote2_close(struct input_dev *idev)
usb_kill_urb(ar2->urb[1]);
}
-static void ati_remote2_input_mouse(struct ati_remote2 *ar2, struct pt_regs *regs)
+static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
{
struct input_dev *idev = ar2->idev;
u8 *data = ar2->buf[0];
@@ -157,7 +157,6 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2, struct pt_regs *reg
if (!((1 << data[0]) & mode_mask))
return;
- input_regs(idev, regs);
input_event(idev, EV_REL, REL_X, (s8) data[1]);
input_event(idev, EV_REL, REL_Y, (s8) data[2]);
input_sync(idev);
@@ -174,7 +173,7 @@ static int ati_remote2_lookup(unsigned int hw_code)
return -1;
}
-static void ati_remote2_input_key(struct ati_remote2 *ar2, struct pt_regs *regs)
+static void ati_remote2_input_key(struct ati_remote2 *ar2)
{
struct input_dev *idev = ar2->idev;
u8 *data = ar2->buf[1];
@@ -245,19 +244,18 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2, struct pt_regs *regs)
return;
}
- input_regs(idev, regs);
input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
input_sync(idev);
}
-static void ati_remote2_complete_mouse(struct urb *urb, struct pt_regs *regs)
+static void ati_remote2_complete_mouse(struct urb *urb)
{
struct ati_remote2 *ar2 = urb->context;
int r;
switch (urb->status) {
case 0:
- ati_remote2_input_mouse(ar2, regs);
+ ati_remote2_input_mouse(ar2);
break;
case -ENOENT:
case -EILSEQ:
@@ -277,14 +275,14 @@ static void ati_remote2_complete_mouse(struct urb *urb, struct pt_regs *regs)
"%s(): usb_submit_urb() = %d\n", __FUNCTION__, r);
}
-static void ati_remote2_complete_key(struct urb *urb, struct pt_regs *regs)
+static void ati_remote2_complete_key(struct urb *urb)
{
struct ati_remote2 *ar2 = urb->context;
int r;
switch (urb->status) {
case 0:
- ati_remote2_input_key(ar2, regs);
+ ati_remote2_input_key(ar2);
break;
case -ENOENT:
case -EILSEQ:
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 3305fb6079eb..45f44fe33bfe 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -543,8 +543,6 @@ static void hid_free_device(struct hid_device *device)
{
unsigned i,j;
- hid_ff_exit(device);
-
for (i = 0; i < HID_REPORT_TYPES; i++) {
struct hid_report_enum *report_enum = device->report_enum + i;
@@ -752,21 +750,31 @@ static __inline__ __u32 s32ton(__s32 value, unsigned n)
}
/*
- * Extract/implement a data field from/to a report.
+ * Extract/implement a data field from/to a little endian report (bit array).
*/
static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
{
- report += (offset >> 5) << 2; offset &= 31;
- return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);
+ u32 x;
+
+ report += offset >> 3; /* adjust byte index */
+ offset &= 8 - 1;
+ x = get_unaligned((u32 *) report);
+ x = le32_to_cpu(x);
+ x = (x >> offset) & ((1 << n) - 1);
+ return x;
}
static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
{
- report += (offset >> 5) << 2; offset &= 31;
- put_unaligned((get_unaligned((__le64*)report)
- & cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)))
- | cpu_to_le64((__u64)value << offset), (__le64*)report);
+ u32 x;
+
+ report += offset >> 3;
+ offset &= 8 - 1;
+ x = get_unaligned((u32 *)report);
+ x &= cpu_to_le32(~((((__u32) 1 << n) - 1) << offset));
+ x |= cpu_to_le32(value << offset);
+ put_unaligned(x,(u32 *)report);
}
/*
@@ -782,13 +790,13 @@ static __inline__ int search(__s32 *array, __s32 value, unsigned n)
return -1;
}
-static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt, struct pt_regs *regs)
+static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, int interrupt)
{
hid_dump_input(usage, value);
if (hid->claimed & HID_CLAIMED_INPUT)
- hidinput_hid_event(hid, field, usage, value, regs);
+ hidinput_hid_event(hid, field, usage, value);
if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt)
- hiddev_hid_event(hid, field, usage, value, regs);
+ hiddev_hid_event(hid, field, usage, value);
}
/*
@@ -797,7 +805,7 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field, s
* reporting to the layer).
*/
-static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt, struct pt_regs *regs)
+static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data, int interrupt)
{
unsigned n;
unsigned count = field->report_count;
@@ -824,19 +832,19 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u
for (n = 0; n < count; n++) {
if (HID_MAIN_ITEM_VARIABLE & field->flags) {
- hid_process_event(hid, field, &field->usage[n], value[n], interrupt, regs);
+ hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
continue;
}
if (field->value[n] >= min && field->value[n] <= max
&& field->usage[field->value[n] - min].hid
&& search(value, field->value[n], count))
- hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt, regs);
+ hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
if (value[n] >= min && value[n] <= max
&& field->usage[value[n] - min].hid
&& search(field->value, value[n], count))
- hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt, regs);
+ hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
}
memcpy(field->value, value, count * sizeof(__s32));
@@ -844,7 +852,7 @@ exit:
kfree(value);
}
-static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_regs *regs)
+static int hid_input_report(int type, struct urb *urb, int interrupt)
{
struct hid_device *hid = urb->context;
struct hid_report_enum *report_enum = hid->report_enum + type;
@@ -894,7 +902,7 @@ static int hid_input_report(int type, struct urb *urb, int interrupt, struct pt_
hiddev_report_event(hid, report);
for (n = 0; n < report->maxfield; n++)
- hid_input_field(hid, report->field[n], data, interrupt, regs);
+ hid_input_field(hid, report->field[n], data, interrupt);
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_report_event(hid, report);
@@ -1006,7 +1014,7 @@ done:
* Input interrupt completion handler.
*/
-static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
+static void hid_irq_in(struct urb *urb)
{
struct hid_device *hid = urb->context;
int status;
@@ -1014,7 +1022,7 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
switch (urb->status) {
case 0: /* success */
hid->retry_delay = 0;
- hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
+ hid_input_report(HID_INPUT_REPORT, urb, 1);
break;
case -ECONNRESET: /* unlink */
case -ENOENT:
@@ -1023,7 +1031,8 @@ static void hid_irq_in(struct urb *urb, struct pt_regs *regs)
return;
case -EILSEQ: /* protocol error or unplug */
case -EPROTO: /* protocol error or unplug */
- case -ETIMEDOUT: /* NAK */
+ case -ETIME: /* protocol error or unplug */
+ case -ETIMEDOUT: /* Should never happen, but... */
clear_bit(HID_IN_RUNNING, &hid->iofl);
hid_io_error(hid);
return;
@@ -1108,7 +1117,7 @@ int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
/*
* Find a report field with a specified HID usage.
*/
-
+#if 0
struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
{
struct hid_report *report;
@@ -1120,6 +1129,7 @@ struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_u
return report->field[i];
return NULL;
}
+#endif /* 0 */
static int hid_submit_out(struct hid_device *hid)
{
@@ -1193,7 +1203,7 @@ static int hid_submit_ctrl(struct hid_device *hid)
* Output interrupt completion handler.
*/
-static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
+static void hid_irq_out(struct urb *urb)
{
struct hid_device *hid = urb->context;
unsigned long flags;
@@ -1238,7 +1248,7 @@ static void hid_irq_out(struct urb *urb, struct pt_regs *regs)
* Control pipe completion handler.
*/
-static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
+static void hid_ctrl(struct urb *urb)
{
struct hid_device *hid = urb->context;
unsigned long flags;
@@ -1249,7 +1259,7 @@ static void hid_ctrl(struct urb *urb, struct pt_regs *regs)
switch (urb->status) {
case 0: /* success */
if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN)
- hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0, regs);
+ hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb, 0);
break;
case -ESHUTDOWN: /* unplug */
unplug = 1;
@@ -1381,6 +1391,9 @@ void hid_close(struct hid_device *hid)
#define USB_VENDOR_ID_PANJIT 0x134c
+#define USB_VENDOR_ID_TURBOX 0x062a
+#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
+
/*
* Initialize all reports
*/
@@ -1535,13 +1548,17 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039
-#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040
+#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044
+#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045
+#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051
#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053
+#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058
#define USB_VENDOR_ID_WISEGROUP 0x0925
#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101
#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104
+#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201
#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866
#define USB_VENDOR_ID_WISEGROUP_LTD 0x6677
@@ -1591,6 +1608,13 @@ void hid_init_reports(struct hid_device *hid)
#define USB_VENDOR_ID_YEALINK 0x6993
#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
+
+#define USB_VENDOR_ID_ALCOR 0x058f
+#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720
+
+#define USB_VENDOR_ID_SUN 0x0430
+#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab
+
/*
* Alphabetically sorted blacklist by quirk type.
*/
@@ -1608,6 +1632,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24, HID_QUIRK_IGNORE },
@@ -1620,9 +1645,12 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30, HID_QUIRK_IGNORE },
- { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90, HID_QUIRK_IGNORE },
@@ -1690,7 +1718,11 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400, HID_QUIRK_IGNORE },
@@ -1701,6 +1733,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
@@ -1711,6 +1744,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
@@ -1747,6 +1781,8 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PANJIT, 0x0003, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_PANJIT, 0x0004, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
+
{ 0, 0 }
};
diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c
index d5c91ee67991..a8fc46c721c5 100644
--- a/drivers/usb/input/hid-ff.c
+++ b/drivers/usb/input/hid-ff.c
@@ -44,45 +44,38 @@ struct hid_ff_initializer {
int (*init)(struct hid_device*);
};
+/*
+ * We try pidff when no other driver is found because PID is the
+ * standards compliant way of implementing force feedback in HID.
+ * pidff_init() will quickly abort if the device doesn't appear to
+ * be a PID device
+ */
static struct hid_ff_initializer inits[] = {
#ifdef CONFIG_LOGITECH_FF
- {0x46d, 0xc211, hid_lgff_init}, // Logitech Cordless rumble pad
- {0x46d, 0xc283, hid_lgff_init}, // Logitech Wingman Force 3d
- {0x46d, 0xc295, hid_lgff_init}, // Logitech MOMO force wheel
- {0x46d, 0xc219, hid_lgff_init}, // Logitech Cordless rumble pad 2
-#endif
-#ifdef CONFIG_HID_PID
- {0x45e, 0x001b, hid_pid_init},
+ { 0x46d, 0xc211, hid_lgff_init }, /* Logitech Cordless rumble pad */
+ { 0x46d, 0xc283, hid_lgff_init }, /* Logitech Wingman Force 3d */
+ { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
+ { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
#endif
#ifdef CONFIG_THRUSTMASTER_FF
- {0x44f, 0xb304, hid_tmff_init},
+ { 0x44f, 0xb304, hid_tmff_init },
#endif
- {0, 0, NULL} /* Terminating entry */
+#ifdef CONFIG_ZEROPLUS_FF
+ { 0xc12, 0x0005, hid_zpff_init },
+ { 0xc12, 0x0030, hid_zpff_init },
+#endif
+ { 0, 0, hid_pidff_init} /* Matches anything */
};
-static struct hid_ff_initializer *hid_get_ff_init(__u16 idVendor,
- __u16 idProduct)
-{
- struct hid_ff_initializer *init;
- for (init = inits;
- init->idVendor
- && !(init->idVendor == idVendor
- && init->idProduct == idProduct);
- init++);
-
- return init->idVendor? init : NULL;
-}
-
int hid_ff_init(struct hid_device* hid)
{
struct hid_ff_initializer *init;
+ int vendor = le16_to_cpu(hid->dev->descriptor.idVendor);
+ int product = le16_to_cpu(hid->dev->descriptor.idProduct);
- init = hid_get_ff_init(le16_to_cpu(hid->dev->descriptor.idVendor),
- le16_to_cpu(hid->dev->descriptor.idProduct));
+ for (init = inits; init->idVendor; init++)
+ if (init->idVendor == vendor && init->idProduct == product)
+ break;
- if (!init) {
- dbg("hid_ff_init could not find initializer");
- return -ENOSYS;
- }
return init->init(hid);
}
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 7208839f2dbf..9a808a3b4d37 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -65,11 +65,9 @@ static const struct {
#define map_rel(c) do { usage->code = c; usage->type = EV_REL; bit = input->relbit; max = REL_MAX; } while (0)
#define map_key(c) do { usage->code = c; usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; } while (0)
#define map_led(c) do { usage->code = c; usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; } while (0)
-#define map_ff(c) do { usage->code = c; usage->type = EV_FF; bit = input->ffbit; max = FF_MAX; } while (0)
#define map_abs_clear(c) do { map_abs(c); clear_bit(c, bit); } while (0)
#define map_key_clear(c) do { map_key(c); clear_bit(c, bit); } while (0)
-#define map_ff_effect(c) do { set_bit(c, input->ffbit); } while (0)
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
@@ -525,23 +523,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_PID:
- set_bit(EV_FF, input->evbit);
switch(usage->hid & HID_USAGE) {
- case 0x26: map_ff_effect(FF_CONSTANT); goto ignore;
- case 0x27: map_ff_effect(FF_RAMP); goto ignore;
- case 0x28: map_ff_effect(FF_CUSTOM); goto ignore;
- case 0x30: map_ff_effect(FF_SQUARE); map_ff_effect(FF_PERIODIC); goto ignore;
- case 0x31: map_ff_effect(FF_SINE); map_ff_effect(FF_PERIODIC); goto ignore;
- case 0x32: map_ff_effect(FF_TRIANGLE); map_ff_effect(FF_PERIODIC); goto ignore;
- case 0x33: map_ff_effect(FF_SAW_UP); map_ff_effect(FF_PERIODIC); goto ignore;
- case 0x34: map_ff_effect(FF_SAW_DOWN); map_ff_effect(FF_PERIODIC); goto ignore;
- case 0x40: map_ff_effect(FF_SPRING); goto ignore;
- case 0x41: map_ff_effect(FF_DAMPER); goto ignore;
- case 0x42: map_ff_effect(FF_INERTIA); goto ignore;
- case 0x43: map_ff_effect(FF_FRICTION); goto ignore;
- case 0x7e: map_ff(FF_GAIN); break;
- case 0x83: input->ff_effects_max = field->value[0]; goto ignore;
- case 0x98: map_ff(FF_AUTOCENTER); break;
case 0xa4: map_key_clear(BTN_DEAD); break;
default: goto ignore;
}
@@ -631,7 +613,7 @@ ignore:
return;
}
-void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs)
+void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
struct input_dev *input;
int *quirks = &hid->quirks;
@@ -641,8 +623,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
input = field->hidinput->input;
- input_regs(input, regs);
-
if (!usage->type)
return;
@@ -698,8 +678,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
}
if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
- input->ff_effects_max = value;
- dbg("Maximum Effects - %d",input->ff_effects_max);
+ dbg("Maximum Effects - %d",value);
return;
}
@@ -748,7 +727,7 @@ static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsign
int offset;
if (type == EV_FF)
- return hid_ff_event(hid, dev, type, code, value);
+ return input_ff_event(dev, type, code, value);
if (type != EV_LED)
return -1;
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index f07d44357ff1..93da222b6da8 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -1,12 +1,11 @@
/*
- * $$
- *
* Force feedback support for hid-compliant for some of the devices from
* Logitech, namely:
* - WingMan Cordless RumblePad
* - WingMan Force 3D
*
* Copyright (c) 2002-2004 Johann Deneux
+ * Copyright (c) 2006 Anssi Hannula <anssi.hannula@gmail.com>
*/
/*
@@ -29,495 +28,117 @@
*/
#include <linux/input.h>
-#include <linux/sched.h>
-
-//#define DEBUG
#include <linux/usb.h>
-
-#include <linux/circ_buf.h>
-
#include "hid.h"
-#include "fixp-arith.h"
-
-
-/* Periodicity of the update */
-#define PERIOD (HZ/10)
-
-#define RUN_AT(t) (jiffies + (t))
-
-/* Effect status */
-#define EFFECT_STARTED 0 /* Effect is going to play after some time
- (ff_replay.delay) */
-#define EFFECT_PLAYING 1 /* Effect is being played */
-#define EFFECT_USED 2
-
-// For lgff_device::flags
-#define DEVICE_CLOSING 0 /* The driver is being unitialised */
-
-/* Check that the current process can access an effect */
-#define CHECK_OWNERSHIP(effect) (current->pid == 0 \
- || effect.owner == current->pid)
-
-#define LGFF_CHECK_OWNERSHIP(i, l) \
- (i>=0 && i<LGFF_EFFECTS \
- && test_bit(EFFECT_USED, l->effects[i].flags) \
- && CHECK_OWNERSHIP(l->effects[i]))
-
-#define LGFF_EFFECTS 8
struct device_type {
u16 idVendor;
u16 idProduct;
- signed short *ff;
-};
-
-struct lgff_effect {
- pid_t owner;
-
- struct ff_effect effect;
-
- unsigned long flags[1];
- unsigned int count; /* Number of times left to play */
- unsigned long started_at; /* When the effect started to play */
-};
-
-struct lgff_device {
- struct hid_device* hid;
-
- struct hid_report* constant;
- struct hid_report* rumble;
- struct hid_report* condition;
-
- struct lgff_effect effects[LGFF_EFFECTS];
- spinlock_t lock; /* device-level lock. Having locks on
- a per-effect basis could be nice, but
- isn't really necessary */
-
- unsigned long flags[1]; /* Contains various information about the
- state of the driver for this device */
-
- struct timer_list timer;
+ const signed short *ff;
};
-/* Callbacks */
-static void hid_lgff_exit(struct hid_device* hid);
-static int hid_lgff_event(struct hid_device *hid, struct input_dev *input,
- unsigned int type, unsigned int code, int value);
-static int hid_lgff_flush(struct input_dev *input, struct file *file);
-static int hid_lgff_upload_effect(struct input_dev *input,
- struct ff_effect *effect);
-static int hid_lgff_erase(struct input_dev *input, int id);
-
-/* Local functions */
-static void hid_lgff_input_init(struct hid_device* hid);
-static void hid_lgff_timer(unsigned long timer_data);
-static struct hid_report* hid_lgff_duplicate_report(struct hid_report*);
-static void hid_lgff_delete_report(struct hid_report*);
-
-static signed short ff_rumble[] = {
+static const signed short ff_rumble[] = {
FF_RUMBLE,
-1
};
-static signed short ff_joystick[] = {
+static const signed short ff_joystick[] = {
FF_CONSTANT,
-1
};
-static struct device_type devices[] = {
- {0x046d, 0xc211, ff_rumble},
- {0x046d, 0xc219, ff_rumble},
- {0x046d, 0xc283, ff_joystick},
- {0x0000, 0x0000, ff_joystick}
+static const struct device_type devices[] = {
+ { 0x046d, 0xc211, ff_rumble },
+ { 0x046d, 0xc219, ff_rumble },
+ { 0x046d, 0xc283, ff_joystick },
+ { 0x0000, 0x0000, ff_joystick }
};
+static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+ struct hid_device *hid = dev->private;
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
+ int x, y;
+ unsigned int left, right;
+
+#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
+
+ switch (effect->type) {
+ case FF_CONSTANT:
+ x = effect->u.ramp.start_level + 0x7f; /* 0x7f is center */
+ y = effect->u.ramp.end_level + 0x7f;
+ CLAMP(x);
+ CLAMP(y);
+ report->field[0]->value[0] = 0x51;
+ report->field[0]->value[1] = 0x08;
+ report->field[0]->value[2] = x;
+ report->field[0]->value[3] = y;
+ dbg("(x, y)=(%04x, %04x)", x, y);
+ hid_submit_report(hid, report, USB_DIR_OUT);
+ break;
+
+ case FF_RUMBLE:
+ right = effect->u.rumble.strong_magnitude;
+ left = effect->u.rumble.weak_magnitude;
+ right = right * 0xff / 0xffff;
+ left = left * 0xff / 0xffff;
+ CLAMP(left);
+ CLAMP(right);
+ report->field[0]->value[0] = 0x42;
+ report->field[0]->value[1] = 0x00;
+ report->field[0]->value[2] = left;
+ report->field[0]->value[3] = right;
+ dbg("(left, right)=(%04x, %04x)", left, right);
+ hid_submit_report(hid, report, USB_DIR_OUT);
+ break;
+ }
+ return 0;
+}
+
int hid_lgff_init(struct hid_device* hid)
{
- struct lgff_device *private;
- struct hid_report* report;
- struct hid_field* field;
+ struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+ struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ struct hid_report *report;
+ struct hid_field *field;
+ int error;
+ int i, j;
/* Find the report to use */
- if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
+ if (list_empty(report_list)) {
err("No output report found");
return -1;
}
+
/* Check that the report looks ok */
- report = (struct hid_report*)hid->report_enum[HID_OUTPUT_REPORT].report_list.next;
+ report = list_entry(report_list->next, struct hid_report, list);
if (!report) {
err("NULL output report");
return -1;
}
+
field = report->field[0];
if (!field) {
err("NULL field");
return -1;
}
- private = kzalloc(sizeof(struct lgff_device), GFP_KERNEL);
- if (!private)
- return -1;
- hid->ff_private = private;
-
- /* Input init */
- hid_lgff_input_init(hid);
-
-
- private->constant = hid_lgff_duplicate_report(report);
- if (!private->constant) {
- kfree(private);
- return -1;
- }
- private->constant->field[0]->value[0] = 0x51;
- private->constant->field[0]->value[1] = 0x08;
- private->constant->field[0]->value[2] = 0x7f;
- private->constant->field[0]->value[3] = 0x7f;
-
- private->rumble = hid_lgff_duplicate_report(report);
- if (!private->rumble) {
- hid_lgff_delete_report(private->constant);
- kfree(private);
- return -1;
- }
- private->rumble->field[0]->value[0] = 0x42;
-
-
- private->condition = hid_lgff_duplicate_report(report);
- if (!private->condition) {
- hid_lgff_delete_report(private->rumble);
- hid_lgff_delete_report(private->constant);
- kfree(private);
- return -1;
- }
-
- private->hid = hid;
-
- spin_lock_init(&private->lock);
- init_timer(&private->timer);
- private->timer.data = (unsigned long)private;
- private->timer.function = hid_lgff_timer;
-
- /* Event and exit callbacks */
- hid->ff_exit = hid_lgff_exit;
- hid->ff_event = hid_lgff_event;
-
- /* Start the update task */
- private->timer.expires = RUN_AT(PERIOD);
- add_timer(&private->timer); /*TODO: only run the timer when at least
- one effect is playing */
-
- printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
-
- return 0;
-}
-
-static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
-{
- struct hid_report* ret;
-
- ret = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
- if (!ret)
- return NULL;
- *ret = *report;
-
- ret->field[0] = kmalloc(sizeof(struct hid_field), GFP_KERNEL);
- if (!ret->field[0]) {
- kfree(ret);
- return NULL;
- }
- *ret->field[0] = *report->field[0];
-
- ret->field[0]->value = kzalloc(sizeof(s32[8]), GFP_KERNEL);
- if (!ret->field[0]->value) {
- kfree(ret->field[0]);
- kfree(ret);
- return NULL;
- }
-
- return ret;
-}
-
-static void hid_lgff_delete_report(struct hid_report* report)
-{
- if (report) {
- kfree(report->field[0]->value);
- kfree(report->field[0]);
- kfree(report);
- }
-}
-
-static void hid_lgff_input_init(struct hid_device* hid)
-{
- struct device_type* dev = devices;
- signed short* ff;
- u16 idVendor = le16_to_cpu(hid->dev->descriptor.idVendor);
- u16 idProduct = le16_to_cpu(hid->dev->descriptor.idProduct);
- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
- struct input_dev *input_dev = hidinput->input;
-
- while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct))
- dev++;
-
- for (ff = dev->ff; *ff >= 0; ff++)
- set_bit(*ff, input_dev->ffbit);
-
- input_dev->upload_effect = hid_lgff_upload_effect;
- input_dev->flush = hid_lgff_flush;
-
- set_bit(EV_FF, input_dev->evbit);
- input_dev->ff_effects_max = LGFF_EFFECTS;
-}
-
-static void hid_lgff_exit(struct hid_device* hid)
-{
- struct lgff_device *lgff = hid->ff_private;
-
- set_bit(DEVICE_CLOSING, lgff->flags);
- del_timer_sync(&lgff->timer);
-
- hid_lgff_delete_report(lgff->condition);
- hid_lgff_delete_report(lgff->rumble);
- hid_lgff_delete_report(lgff->constant);
-
- kfree(lgff);
-}
-
-static int hid_lgff_event(struct hid_device *hid, struct input_dev* input,
- unsigned int type, unsigned int code, int value)
-{
- struct lgff_device *lgff = hid->ff_private;
- struct lgff_effect *effect = lgff->effects + code;
- unsigned long flags;
-
- if (type != EV_FF) return -EINVAL;
- if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
- if (value < 0) return -EINVAL;
-
- spin_lock_irqsave(&lgff->lock, flags);
-
- if (value > 0) {
- if (test_bit(EFFECT_STARTED, effect->flags)) {
- spin_unlock_irqrestore(&lgff->lock, flags);
- return -EBUSY;
- }
- if (test_bit(EFFECT_PLAYING, effect->flags)) {
- spin_unlock_irqrestore(&lgff->lock, flags);
- return -EBUSY;
- }
-
- effect->count = value;
-
- if (effect->effect.replay.delay) {
- set_bit(EFFECT_STARTED, effect->flags);
- } else {
- set_bit(EFFECT_PLAYING, effect->flags);
- }
- effect->started_at = jiffies;
- }
- else { /* value == 0 */
- clear_bit(EFFECT_STARTED, effect->flags);
- clear_bit(EFFECT_PLAYING, effect->flags);
- }
-
- spin_unlock_irqrestore(&lgff->lock, flags);
-
- return 0;
-
-}
-
-/* Erase all effects this process owns */
-static int hid_lgff_flush(struct input_dev *dev, struct file *file)
-{
- struct hid_device *hid = dev->private;
- struct lgff_device *lgff = hid->ff_private;
- int i;
-
- for (i=0; i<dev->ff_effects_max; ++i) {
-
- /*NOTE: no need to lock here. The only times EFFECT_USED is
- modified is when effects are uploaded or when an effect is
- erased. But a process cannot close its dev/input/eventX fd
- and perform ioctls on the same fd all at the same time */
- if ( current->pid == lgff->effects[i].owner
- && test_bit(EFFECT_USED, lgff->effects[i].flags)) {
-
- if (hid_lgff_erase(dev, i))
- warn("erase effect %d failed", i);
- }
-
- }
-
- return 0;
-}
-
-static int hid_lgff_erase(struct input_dev *dev, int id)
-{
- struct hid_device *hid = dev->private;
- struct lgff_device *lgff = hid->ff_private;
- unsigned long flags;
-
- if (!LGFF_CHECK_OWNERSHIP(id, lgff)) return -EACCES;
-
- spin_lock_irqsave(&lgff->lock, flags);
- lgff->effects[id].flags[0] = 0;
- spin_unlock_irqrestore(&lgff->lock, flags);
-
- return 0;
-}
-
-static int hid_lgff_upload_effect(struct input_dev* input,
- struct ff_effect* effect)
-{
- struct hid_device *hid = input->private;
- struct lgff_device *lgff = hid->ff_private;
- struct lgff_effect new;
- int id;
- unsigned long flags;
-
- dbg("ioctl rumble");
-
- if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
-
- spin_lock_irqsave(&lgff->lock, flags);
-
- if (effect->id == -1) {
- int i;
-
- for (i=0; i<LGFF_EFFECTS && test_bit(EFFECT_USED, lgff->effects[i].flags); ++i);
- if (i >= LGFF_EFFECTS) {
- spin_unlock_irqrestore(&lgff->lock, flags);
- return -ENOSPC;
+ for (i = 0; i < ARRAY_SIZE(devices); i++) {
+ if (dev->id.vendor == devices[i].idVendor &&
+ dev->id.product == devices[i].idProduct) {
+ for (j = 0; devices[i].ff[j] >= 0; j++)
+ set_bit(devices[i].ff[j], dev->ffbit);
+ break;
}
-
- effect->id = i;
- lgff->effects[i].owner = current->pid;
- lgff->effects[i].flags[0] = 0;
- set_bit(EFFECT_USED, lgff->effects[i].flags);
}
- else if (!LGFF_CHECK_OWNERSHIP(effect->id, lgff)) {
- spin_unlock_irqrestore(&lgff->lock, flags);
- return -EACCES;
- }
-
- id = effect->id;
- new = lgff->effects[id];
-
- new.effect = *effect;
-
- if (test_bit(EFFECT_STARTED, lgff->effects[id].flags)
- || test_bit(EFFECT_STARTED, lgff->effects[id].flags)) {
-
- /* Changing replay parameters is not allowed (for the time
- being) */
- if (new.effect.replay.delay != lgff->effects[id].effect.replay.delay
- || new.effect.replay.length != lgff->effects[id].effect.replay.length) {
- spin_unlock_irqrestore(&lgff->lock, flags);
- return -ENOSYS;
- }
- lgff->effects[id] = new;
+ error = input_ff_create_memless(dev, NULL, hid_lgff_play);
+ if (error)
+ return error;
- } else {
- lgff->effects[id] = new;
- }
+ printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
- spin_unlock_irqrestore(&lgff->lock, flags);
return 0;
}
-
-static void hid_lgff_timer(unsigned long timer_data)
-{
- struct lgff_device *lgff = (struct lgff_device*)timer_data;
- struct hid_device *hid = lgff->hid;
- unsigned long flags;
- int x = 0x7f, y = 0x7f; // Coordinates of constant effects
- unsigned int left = 0, right = 0; // Rumbling
- int i;
-
- spin_lock_irqsave(&lgff->lock, flags);
-
- for (i=0; i<LGFF_EFFECTS; ++i) {
- struct lgff_effect* effect = lgff->effects +i;
-
- if (test_bit(EFFECT_PLAYING, effect->flags)) {
-
- switch (effect->effect.type) {
- case FF_CONSTANT: {
- //TODO: handle envelopes
- int degrees = effect->effect.direction * 360 >> 16;
- x += fixp_mult(fixp_sin(degrees),
- fixp_new16(effect->effect.u.constant.level));
- y += fixp_mult(-fixp_cos(degrees),
- fixp_new16(effect->effect.u.constant.level));
- } break;
- case FF_RUMBLE:
- right += effect->effect.u.rumble.strong_magnitude;
- left += effect->effect.u.rumble.weak_magnitude;
- break;
- };
-
- /* One run of the effect is finished playing */
- if (time_after(jiffies,
- effect->started_at
- + effect->effect.replay.delay*HZ/1000
- + effect->effect.replay.length*HZ/1000)) {
- dbg("Finished playing once %d", i);
- if (--effect->count <= 0) {
- dbg("Stopped %d", i);
- clear_bit(EFFECT_PLAYING, effect->flags);
- }
- else {
- dbg("Start again %d", i);
- if (effect->effect.replay.length != 0) {
- clear_bit(EFFECT_PLAYING, effect->flags);
- set_bit(EFFECT_STARTED, effect->flags);
- }
- effect->started_at = jiffies;
- }
- }
-
- } else if (test_bit(EFFECT_STARTED, lgff->effects[i].flags)) {
- /* Check if we should start playing the effect */
- if (time_after(jiffies,
- lgff->effects[i].started_at
- + lgff->effects[i].effect.replay.delay*HZ/1000)) {
- dbg("Now playing %d", i);
- clear_bit(EFFECT_STARTED, lgff->effects[i].flags);
- set_bit(EFFECT_PLAYING, lgff->effects[i].flags);
- }
- }
- }
-
-#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
-
- // Clamp values
- CLAMP(x);
- CLAMP(y);
- CLAMP(left);
- CLAMP(right);
-
-#undef CLAMP
-
- if (x != lgff->constant->field[0]->value[2]
- || y != lgff->constant->field[0]->value[3]) {
- lgff->constant->field[0]->value[2] = x;
- lgff->constant->field[0]->value[3] = y;
- dbg("(x,y)=(%04x, %04x)", x, y);
- hid_submit_report(hid, lgff->constant, USB_DIR_OUT);
- }
-
- if (left != lgff->rumble->field[0]->value[2]
- || right != lgff->rumble->field[0]->value[3]) {
- lgff->rumble->field[0]->value[2] = left;
- lgff->rumble->field[0]->value[3] = right;
- dbg("(left,right)=(%04x, %04x)", left, right);
- hid_submit_report(hid, lgff->rumble, USB_DIR_OUT);
- }
-
- if (!test_bit(DEVICE_CLOSING, lgff->flags)) {
- lgff->timer.expires = RUN_AT(PERIOD);
- add_timer(&lgff->timer);
- }
-
- spin_unlock_irqrestore(&lgff->lock, flags);
-}
diff --git a/drivers/usb/input/hid-pidff.c b/drivers/usb/input/hid-pidff.c
new file mode 100644
index 000000000000..5420c13eb8eb
--- /dev/null
+++ b/drivers/usb/input/hid-pidff.c
@@ -0,0 +1,1330 @@
+/*
+ * Force feedback driver for USB HID PID compliant devices
+ *
+ * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.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
+ */
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
+
+#include <linux/sched.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "hid.h"
+
+#define PID_EFFECTS_MAX 64
+
+/* Report usage table used to put reports into an array */
+
+#define PID_SET_EFFECT 0
+#define PID_EFFECT_OPERATION 1
+#define PID_DEVICE_GAIN 2
+#define PID_POOL 3
+#define PID_BLOCK_LOAD 4
+#define PID_BLOCK_FREE 5
+#define PID_DEVICE_CONTROL 6
+#define PID_CREATE_NEW_EFFECT 7
+
+#define PID_REQUIRED_REPORTS 7
+
+#define PID_SET_ENVELOPE 8
+#define PID_SET_CONDITION 9
+#define PID_SET_PERIODIC 10
+#define PID_SET_CONSTANT 11
+#define PID_SET_RAMP 12
+static const u8 pidff_reports[] = {
+ 0x21, 0x77, 0x7d, 0x7f, 0x89, 0x90, 0x96, 0xab,
+ 0x5a, 0x5f, 0x6e, 0x73, 0x74
+};
+
+/* device_control is really 0x95, but 0x96 specified as it is the usage of
+the only field in that report */
+
+/* Value usage tables used to put fields and values into arrays */
+
+#define PID_EFFECT_BLOCK_INDEX 0
+
+#define PID_DURATION 1
+#define PID_GAIN 2
+#define PID_TRIGGER_BUTTON 3
+#define PID_TRIGGER_REPEAT_INT 4
+#define PID_DIRECTION_ENABLE 5
+#define PID_START_DELAY 6
+static const u8 pidff_set_effect[] = {
+ 0x22, 0x50, 0x52, 0x53, 0x54, 0x56, 0xa7
+};
+
+#define PID_ATTACK_LEVEL 1
+#define PID_ATTACK_TIME 2
+#define PID_FADE_LEVEL 3
+#define PID_FADE_TIME 4
+static const u8 pidff_set_envelope[] = { 0x22, 0x5b, 0x5c, 0x5d, 0x5e };
+
+#define PID_PARAM_BLOCK_OFFSET 1
+#define PID_CP_OFFSET 2
+#define PID_POS_COEFFICIENT 3
+#define PID_NEG_COEFFICIENT 4
+#define PID_POS_SATURATION 5
+#define PID_NEG_SATURATION 6
+#define PID_DEAD_BAND 7
+static const u8 pidff_set_condition[] = {
+ 0x22, 0x23, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65
+};
+
+#define PID_MAGNITUDE 1
+#define PID_OFFSET 2
+#define PID_PHASE 3
+#define PID_PERIOD 4
+static const u8 pidff_set_periodic[] = { 0x22, 0x70, 0x6f, 0x71, 0x72 };
+static const u8 pidff_set_constant[] = { 0x22, 0x70 };
+
+#define PID_RAMP_START 1
+#define PID_RAMP_END 2
+static const u8 pidff_set_ramp[] = { 0x22, 0x75, 0x76 };
+
+#define PID_RAM_POOL_AVAILABLE 1
+static const u8 pidff_block_load[] = { 0x22, 0xac };
+
+#define PID_LOOP_COUNT 1
+static const u8 pidff_effect_operation[] = { 0x22, 0x7c };
+
+static const u8 pidff_block_free[] = { 0x22 };
+
+#define PID_DEVICE_GAIN_FIELD 0
+static const u8 pidff_device_gain[] = { 0x7e };
+
+#define PID_RAM_POOL_SIZE 0
+#define PID_SIMULTANEOUS_MAX 1
+#define PID_DEVICE_MANAGED_POOL 2
+static const u8 pidff_pool[] = { 0x80, 0x83, 0xa9 };
+
+/* Special field key tables used to put special field keys into arrays */
+
+#define PID_ENABLE_ACTUATORS 0
+#define PID_RESET 1
+static const u8 pidff_device_control[] = { 0x97, 0x9a };
+
+#define PID_CONSTANT 0
+#define PID_RAMP 1
+#define PID_SQUARE 2
+#define PID_SINE 3
+#define PID_TRIANGLE 4
+#define PID_SAW_UP 5
+#define PID_SAW_DOWN 6
+#define PID_SPRING 7
+#define PID_DAMPER 8
+#define PID_INERTIA 9
+#define PID_FRICTION 10
+static const u8 pidff_effect_types[] = {
+ 0x26, 0x27, 0x30, 0x31, 0x32, 0x33, 0x34,
+ 0x40, 0x41, 0x42, 0x43
+};
+
+#define PID_BLOCK_LOAD_SUCCESS 0
+#define PID_BLOCK_LOAD_FULL 1
+static const u8 pidff_block_load_status[] = { 0x8c, 0x8d };
+
+#define PID_EFFECT_START 0
+#define PID_EFFECT_STOP 1
+static const u8 pidff_effect_operation_status[] = { 0x79, 0x7b };
+
+struct pidff_usage {
+ struct hid_field *field;
+ s32 *value;
+};
+
+struct pidff_device {
+ struct hid_device *hid;
+
+ struct hid_report *reports[sizeof(pidff_reports)];
+
+ struct pidff_usage set_effect[sizeof(pidff_set_effect)];
+ struct pidff_usage set_envelope[sizeof(pidff_set_envelope)];
+ struct pidff_usage set_condition[sizeof(pidff_set_condition)];
+ struct pidff_usage set_periodic[sizeof(pidff_set_periodic)];
+ struct pidff_usage set_constant[sizeof(pidff_set_constant)];
+ struct pidff_usage set_ramp[sizeof(pidff_set_ramp)];
+
+ struct pidff_usage device_gain[sizeof(pidff_device_gain)];
+ struct pidff_usage block_load[sizeof(pidff_block_load)];
+ struct pidff_usage pool[sizeof(pidff_pool)];
+ struct pidff_usage effect_operation[sizeof(pidff_effect_operation)];
+ struct pidff_usage block_free[sizeof(pidff_block_free)];
+
+ /* Special field is a field that is not composed of
+ usage<->value pairs that pidff_usage values are */
+
+ /* Special field in create_new_effect */
+ struct hid_field *create_new_effect_type;
+
+ /* Special fields in set_effect */
+ struct hid_field *set_effect_type;
+ struct hid_field *effect_direction;
+
+ /* Special field in device_control */
+ struct hid_field *device_control;
+
+ /* Special field in block_load */
+ struct hid_field *block_load_status;
+
+ /* Special field in effect_operation */
+ struct hid_field *effect_operation_status;
+
+ int control_id[sizeof(pidff_device_control)];
+ int type_id[sizeof(pidff_effect_types)];
+ int status_id[sizeof(pidff_block_load_status)];
+ int operation_id[sizeof(pidff_effect_operation_status)];
+
+ int pid_id[PID_EFFECTS_MAX];
+};
+
+/*
+ * Scale an unsigned value with range 0..max for the given field
+ */
+static int pidff_rescale(int i, int max, struct hid_field *field)
+{
+ return i * (field->logical_maximum - field->logical_minimum) / max +
+ field->logical_minimum;
+}
+
+/*
+ * Scale a signed value in range -0x8000..0x7fff for the given field
+ */
+static int pidff_rescale_signed(int i, struct hid_field *field)
+{
+ return i == 0 ? 0 : i >
+ 0 ? i * field->logical_maximum / 0x7fff : i *
+ field->logical_minimum / -0x8000;
+}
+
+static void pidff_set(struct pidff_usage *usage, u16 value)
+{
+ usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
+ debug("calculated from %d to %d", value, usage->value[0]);
+}
+
+static void pidff_set_signed(struct pidff_usage *usage, s16 value)
+{
+ if (usage->field->logical_minimum < 0)
+ usage->value[0] = pidff_rescale_signed(value, usage->field);
+ else {
+ if (value < 0)
+ usage->value[0] =
+ pidff_rescale(-value, 0x8000, usage->field);
+ else
+ usage->value[0] =
+ pidff_rescale(value, 0x7fff, usage->field);
+ }
+ debug("calculated from %d to %d", value, usage->value[0]);
+}
+
+/*
+ * Send envelope report to the device
+ */
+static void pidff_set_envelope_report(struct pidff_device *pidff,
+ struct ff_envelope *envelope)
+{
+ pidff->set_envelope[PID_EFFECT_BLOCK_INDEX].value[0] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+
+ pidff->set_envelope[PID_ATTACK_LEVEL].value[0] =
+ pidff_rescale(envelope->attack_level >
+ 0x7fff ? 0x7fff : envelope->attack_level, 0x7fff,
+ pidff->set_envelope[PID_ATTACK_LEVEL].field);
+ pidff->set_envelope[PID_FADE_LEVEL].value[0] =
+ pidff_rescale(envelope->fade_level >
+ 0x7fff ? 0x7fff : envelope->fade_level, 0x7fff,
+ pidff->set_envelope[PID_FADE_LEVEL].field);
+
+ pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
+ pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
+
+ debug("attack %u => %d", envelope->attack_level,
+ pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
+
+ hid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
+ USB_DIR_OUT);
+}
+
+/*
+ * Test if the new envelope differs from old one
+ */
+static int pidff_needs_set_envelope(struct ff_envelope *envelope,
+ struct ff_envelope *old)
+{
+ return envelope->attack_level != old->attack_level ||
+ envelope->fade_level != old->fade_level ||
+ envelope->attack_length != old->attack_length ||
+ envelope->fade_length != old->fade_length;
+}
+
+/*
+ * Send constant force report to the device
+ */
+static void pidff_set_constant_force_report(struct pidff_device *pidff,
+ struct ff_effect *effect)
+{
+ pidff->set_constant[PID_EFFECT_BLOCK_INDEX].value[0] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+ pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
+ effect->u.constant.level);
+
+ hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
+ USB_DIR_OUT);
+}
+
+/*
+ * Test if the constant parameters have changed between effects
+ */
+static int pidff_needs_set_constant(struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ return effect->u.constant.level != old->u.constant.level;
+}
+
+/*
+ * Send set effect report to the device
+ */
+static void pidff_set_effect_report(struct pidff_device *pidff,
+ struct ff_effect *effect)
+{
+ pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+ pidff->set_effect_type->value[0] =
+ pidff->create_new_effect_type->value[0];
+ pidff->set_effect[PID_DURATION].value[0] = effect->replay.length;
+ pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = effect->trigger.button;
+ pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] =
+ effect->trigger.interval;
+ pidff->set_effect[PID_GAIN].value[0] =
+ pidff->set_effect[PID_GAIN].field->logical_maximum;
+ pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
+ pidff->effect_direction->value[0] =
+ pidff_rescale(effect->direction, 0xffff,
+ pidff->effect_direction);
+ pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
+
+ hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ USB_DIR_OUT);
+}
+
+/*
+ * Test if the values used in set_effect have changed
+ */
+static int pidff_needs_set_effect(struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ return effect->replay.length != old->replay.length ||
+ effect->trigger.interval != old->trigger.interval ||
+ effect->trigger.button != old->trigger.button ||
+ effect->direction != old->direction ||
+ effect->replay.delay != old->replay.delay;
+}
+
+/*
+ * Send periodic effect report to the device
+ */
+static void pidff_set_periodic_report(struct pidff_device *pidff,
+ struct ff_effect *effect)
+{
+ pidff->set_periodic[PID_EFFECT_BLOCK_INDEX].value[0] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+ pidff_set_signed(&pidff->set_periodic[PID_MAGNITUDE],
+ effect->u.periodic.magnitude);
+ pidff_set_signed(&pidff->set_periodic[PID_OFFSET],
+ effect->u.periodic.offset);
+ pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
+ pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
+
+ hid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
+ USB_DIR_OUT);
+
+}
+
+/*
+ * Test if periodic effect parameters have changed
+ */
+static int pidff_needs_set_periodic(struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ return effect->u.periodic.magnitude != old->u.periodic.magnitude ||
+ effect->u.periodic.offset != old->u.periodic.offset ||
+ effect->u.periodic.phase != old->u.periodic.phase ||
+ effect->u.periodic.period != old->u.periodic.period;
+}
+
+/*
+ * Send condition effect reports to the device
+ */
+static void pidff_set_condition_report(struct pidff_device *pidff,
+ struct ff_effect *effect)
+{
+ int i;
+
+ pidff->set_condition[PID_EFFECT_BLOCK_INDEX].value[0] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+
+ for (i = 0; i < 2; i++) {
+ pidff->set_condition[PID_PARAM_BLOCK_OFFSET].value[0] = i;
+ pidff_set_signed(&pidff->set_condition[PID_CP_OFFSET],
+ effect->u.condition[i].center);
+ pidff_set_signed(&pidff->set_condition[PID_POS_COEFFICIENT],
+ effect->u.condition[i].right_coeff);
+ pidff_set_signed(&pidff->set_condition[PID_NEG_COEFFICIENT],
+ effect->u.condition[i].left_coeff);
+ pidff_set(&pidff->set_condition[PID_POS_SATURATION],
+ effect->u.condition[i].right_saturation);
+ pidff_set(&pidff->set_condition[PID_NEG_SATURATION],
+ effect->u.condition[i].left_saturation);
+ pidff_set(&pidff->set_condition[PID_DEAD_BAND],
+ effect->u.condition[i].deadband);
+ hid_wait_io(pidff->hid);
+ hid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
+ USB_DIR_OUT);
+ }
+}
+
+/*
+ * Test if condition effect parameters have changed
+ */
+static int pidff_needs_set_condition(struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < 2; i++) {
+ struct ff_condition_effect *cond = &effect->u.condition[i];
+ struct ff_condition_effect *old_cond = &old->u.condition[i];
+
+ ret |= cond->center != old_cond->center ||
+ cond->right_coeff != old_cond->right_coeff ||
+ cond->left_coeff != old_cond->left_coeff ||
+ cond->right_saturation != old_cond->right_saturation ||
+ cond->left_saturation != old_cond->left_saturation ||
+ cond->deadband != old_cond->deadband;
+ }
+
+ return ret;
+}
+
+/*
+ * Send ramp force report to the device
+ */
+static void pidff_set_ramp_force_report(struct pidff_device *pidff,
+ struct ff_effect *effect)
+{
+ pidff->set_ramp[PID_EFFECT_BLOCK_INDEX].value[0] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+ pidff_set_signed(&pidff->set_ramp[PID_RAMP_START],
+ effect->u.ramp.start_level);
+ pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
+ effect->u.ramp.end_level);
+ hid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
+ USB_DIR_OUT);
+}
+
+/*
+ * Test if ramp force parameters have changed
+ */
+static int pidff_needs_set_ramp(struct ff_effect *effect, struct ff_effect *old)
+{
+ return effect->u.ramp.start_level != old->u.ramp.start_level ||
+ effect->u.ramp.end_level != old->u.ramp.end_level;
+}
+
+/*
+ * Send a request for effect upload to the device
+ *
+ * Returns 0 if device reported success, -ENOSPC if the device reported memory
+ * is full. Upon unknown response the function will retry for 60 times, if
+ * still unsuccessful -EIO is returned.
+ */
+static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
+{
+ int j;
+
+ pidff->create_new_effect_type->value[0] = efnum;
+ hid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
+ USB_DIR_OUT);
+ debug("create_new_effect sent, type: %d", efnum);
+
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
+ pidff->block_load_status->value[0] = 0;
+ hid_wait_io(pidff->hid);
+
+ for (j = 0; j < 60; j++) {
+ debug("pid_block_load requested");
+ hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
+ USB_DIR_IN);
+ hid_wait_io(pidff->hid);
+ if (pidff->block_load_status->value[0] ==
+ pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
+ debug("device reported free memory: %d bytes",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+ return 0;
+ }
+ if (pidff->block_load_status->value[0] ==
+ pidff->status_id[PID_BLOCK_LOAD_FULL]) {
+ debug("not enough memory free: %d bytes",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+ return -ENOSPC;
+ }
+ }
+ printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
+ return -EIO;
+}
+
+/*
+ * Play the effect with PID id n times
+ */
+static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
+{
+ pidff->effect_operation[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
+
+ if (n == 0) {
+ pidff->effect_operation_status->value[0] =
+ pidff->operation_id[PID_EFFECT_STOP];
+ } else {
+ pidff->effect_operation_status->value[0] =
+ pidff->operation_id[PID_EFFECT_START];
+ pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
+ }
+
+ hid_wait_io(pidff->hid);
+ hid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
+ USB_DIR_OUT);
+}
+
+/**
+ * Play the effect with effect id @effect_id for @value times
+ */
+static int pidff_playback(struct input_dev *dev, int effect_id, int value)
+{
+ struct pidff_device *pidff = dev->ff->private;
+
+ pidff_playback_pid(pidff, pidff->pid_id[effect_id], value);
+
+ return 0;
+}
+
+/*
+ * Erase effect with PID id
+ */
+static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
+{
+ pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
+ hid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
+ USB_DIR_OUT);
+}
+
+/*
+ * Stop and erase effect with effect_id
+ */
+static int pidff_erase_effect(struct input_dev *dev, int effect_id)
+{
+ struct pidff_device *pidff = dev->ff->private;
+ int pid_id = pidff->pid_id[effect_id];
+
+ debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+ pidff_playback_pid(pidff, pid_id, 0);
+ pidff_erase_pid(pidff, pid_id);
+
+ return 0;
+}
+
+/*
+ * Effect upload handler
+ */
+static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
+ struct ff_effect *old)
+{
+ struct pidff_device *pidff = dev->ff->private;
+ int type_id;
+ int error;
+
+ switch (effect->type) {
+ case FF_CONSTANT:
+ if (!old) {
+ error = pidff_request_effect_upload(pidff,
+ pidff->type_id[PID_CONSTANT]);
+ if (error)
+ return error;
+ }
+ if (!old || pidff_needs_set_effect(effect, old))
+ pidff_set_effect_report(pidff, effect);
+ if (!old || pidff_needs_set_constant(effect, old))
+ pidff_set_constant_force_report(pidff, effect);
+ if (!old ||
+ pidff_needs_set_envelope(&effect->u.constant.envelope,
+ &old->u.constant.envelope))
+ pidff_set_envelope_report(pidff,
+ &effect->u.constant.envelope);
+ break;
+
+ case FF_PERIODIC:
+ if (!old) {
+ switch (effect->u.periodic.waveform) {
+ case FF_SQUARE:
+ type_id = PID_SQUARE;
+ break;
+ case FF_TRIANGLE:
+ type_id = PID_TRIANGLE;
+ break;
+ case FF_SINE:
+ type_id = PID_SINE;
+ break;
+ case FF_SAW_UP:
+ type_id = PID_SAW_UP;
+ break;
+ case FF_SAW_DOWN:
+ type_id = PID_SAW_DOWN;
+ break;
+ default:
+ printk(KERN_ERR
+ "hid-pidff: invalid waveform\n");
+ return -EINVAL;
+ }
+
+ error = pidff_request_effect_upload(pidff,
+ pidff->type_id[type_id]);
+ if (error)
+ return error;
+ }
+ if (!old || pidff_needs_set_effect(effect, old))
+ pidff_set_effect_report(pidff, effect);
+ if (!old || pidff_needs_set_periodic(effect, old))
+ pidff_set_periodic_report(pidff, effect);
+ if (!old ||
+ pidff_needs_set_envelope(&effect->u.periodic.envelope,
+ &old->u.periodic.envelope))
+ pidff_set_envelope_report(pidff,
+ &effect->u.periodic.envelope);
+ break;
+
+ case FF_RAMP:
+ if (!old) {
+ error = pidff_request_effect_upload(pidff,
+ pidff->type_id[PID_RAMP]);
+ if (error)
+ return error;
+ }
+ if (!old || pidff_needs_set_effect(effect, old))
+ pidff_set_effect_report(pidff, effect);
+ if (!old || pidff_needs_set_ramp(effect, old))
+ pidff_set_ramp_force_report(pidff, effect);
+ if (!old ||
+ pidff_needs_set_envelope(&effect->u.ramp.envelope,
+ &old->u.ramp.envelope))
+ pidff_set_envelope_report(pidff,
+ &effect->u.ramp.envelope);
+ break;
+
+ case FF_SPRING:
+ if (!old) {
+ error = pidff_request_effect_upload(pidff,
+ pidff->type_id[PID_SPRING]);
+ if (error)
+ return error;
+ }
+ if (!old || pidff_needs_set_effect(effect, old))
+ pidff_set_effect_report(pidff, effect);
+ if (!old || pidff_needs_set_condition(effect, old))
+ pidff_set_condition_report(pidff, effect);
+ break;
+
+ case FF_FRICTION:
+ if (!old) {
+ error = pidff_request_effect_upload(pidff,
+ pidff->type_id[PID_FRICTION]);
+ if (error)
+ return error;
+ }
+ if (!old || pidff_needs_set_effect(effect, old))
+ pidff_set_effect_report(pidff, effect);
+ if (!old || pidff_needs_set_condition(effect, old))
+ pidff_set_condition_report(pidff, effect);
+ break;
+
+ case FF_DAMPER:
+ if (!old) {
+ error = pidff_request_effect_upload(pidff,
+ pidff->type_id[PID_DAMPER]);
+ if (error)
+ return error;
+ }
+ if (!old || pidff_needs_set_effect(effect, old))
+ pidff_set_effect_report(pidff, effect);
+ if (!old || pidff_needs_set_condition(effect, old))
+ pidff_set_condition_report(pidff, effect);
+ break;
+
+ case FF_INERTIA:
+ if (!old) {
+ error = pidff_request_effect_upload(pidff,
+ pidff->type_id[PID_INERTIA]);
+ if (error)
+ return error;
+ }
+ if (!old || pidff_needs_set_effect(effect, old))
+ pidff_set_effect_report(pidff, effect);
+ if (!old || pidff_needs_set_condition(effect, old))
+ pidff_set_condition_report(pidff, effect);
+ break;
+
+ default:
+ printk(KERN_ERR "hid-pidff: invalid type\n");
+ return -EINVAL;
+ }
+
+ if (!old)
+ pidff->pid_id[effect->id] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
+
+ debug("uploaded");
+
+ return 0;
+}
+
+/*
+ * set_gain() handler
+ */
+static void pidff_set_gain(struct input_dev *dev, u16 gain)
+{
+ struct pidff_device *pidff = dev->ff->private;
+
+ pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
+ hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+ USB_DIR_OUT);
+}
+
+static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
+{
+ struct hid_field *field =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field;
+
+ if (!magnitude) {
+ pidff_playback_pid(pidff, field->logical_minimum, 0);
+ return;
+ }
+
+ pidff_playback_pid(pidff, field->logical_minimum, 1);
+
+ pidff->set_effect[PID_EFFECT_BLOCK_INDEX].value[0] =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum;
+ pidff->set_effect_type->value[0] = pidff->type_id[PID_SPRING];
+ pidff->set_effect[PID_DURATION].value[0] = 0;
+ pidff->set_effect[PID_TRIGGER_BUTTON].value[0] = 0;
+ pidff->set_effect[PID_TRIGGER_REPEAT_INT].value[0] = 0;
+ pidff_set(&pidff->set_effect[PID_GAIN], magnitude);
+ pidff->set_effect[PID_START_DELAY].value[0] = 0;
+
+ hid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
+ USB_DIR_OUT);
+}
+
+/*
+ * pidff_set_autocenter() handler
+ */
+static void pidff_set_autocenter(struct input_dev *dev, u16 magnitude)
+{
+ struct pidff_device *pidff = dev->ff->private;
+
+ pidff_autocenter(pidff, magnitude);
+}
+
+/*
+ * Find fields from a report and fill a pidff_usage
+ */
+static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
+ struct hid_report *report, int count, int strict)
+{
+ int i, j, k, found;
+
+ for (k = 0; k < count; k++) {
+ found = 0;
+ for (i = 0; i < report->maxfield; i++) {
+ if (report->field[i]->maxusage !=
+ report->field[i]->report_count) {
+ debug("maxusage and report_count do not match, "
+ "skipping");
+ continue;
+ }
+ for (j = 0; j < report->field[i]->maxusage; j++) {
+ if (report->field[i]->usage[j].hid ==
+ (HID_UP_PID | table[k])) {
+ debug("found %d at %d->%d", k, i, j);
+ usage[k].field = report->field[i];
+ usage[k].value =
+ &report->field[i]->value[j];
+ found = 1;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+ if (!found && strict) {
+ debug("failed to locate %d", k);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Return index into pidff_reports for the given usage
+ */
+static int pidff_check_usage(int usage)
+{
+ int i;
+
+ for (i = 0; i < sizeof(pidff_reports); i++)
+ if (usage == (HID_UP_PID | pidff_reports[i]))
+ return i;
+
+ return -1;
+}
+
+/*
+ * Find the reports and fill pidff->reports[]
+ * report_type specifies either OUTPUT or FEATURE reports
+ */
+static void pidff_find_reports(struct hid_device *hid, int report_type,
+ struct pidff_device *pidff)
+{
+ struct hid_report *report;
+ int i, ret;
+
+ list_for_each_entry(report,
+ &hid->report_enum[report_type].report_list, list) {
+ if (report->maxfield < 1)
+ continue;
+ ret = pidff_check_usage(report->field[0]->logical);
+ if (ret != -1) {
+ debug("found usage 0x%02x from field->logical",
+ pidff_reports[ret]);
+ pidff->reports[ret] = report;
+ continue;
+ }
+
+ /*
+ * Sometimes logical collections are stacked to indicate
+ * different usages for the report and the field, in which
+ * case we want the usage of the parent. However, Linux HID
+ * implementation hides this fact, so we have to dig it up
+ * ourselves
+ */
+ i = report->field[0]->usage[0].collection_index;
+ if (i <= 0 ||
+ hid->collection[i - 1].type != HID_COLLECTION_LOGICAL)
+ continue;
+ ret = pidff_check_usage(hid->collection[i - 1].usage);
+ if (ret != -1 && !pidff->reports[ret]) {
+ debug("found usage 0x%02x from collection array",
+ pidff_reports[ret]);
+ pidff->reports[ret] = report;
+ }
+ }
+}
+
+/*
+ * Test if the required reports have been found
+ */
+static int pidff_reports_ok(struct pidff_device *pidff)
+{
+ int i;
+
+ for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
+ if (!pidff->reports[i]) {
+ debug("%d missing", i);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Find a field with a specific usage within a report
+ */
+static struct hid_field *pidff_find_special_field(struct hid_report *report,
+ int usage, int enforce_min)
+{
+ int i;
+
+ for (i = 0; i < report->maxfield; i++) {
+ if (report->field[i]->logical == (HID_UP_PID | usage) &&
+ report->field[i]->report_count > 0) {
+ if (!enforce_min ||
+ report->field[i]->logical_minimum == 1)
+ return report->field[i];
+ else {
+ printk(KERN_ERR "hid-pidff: logical_minimum "
+ "is not 1 as it should be\n");
+ return NULL;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Fill a pidff->*_id struct table
+ */
+static int pidff_find_special_keys(int *keys, struct hid_field *fld,
+ const u8 *usagetable, int count)
+{
+
+ int i, j;
+ int found = 0;
+
+ for (i = 0; i < count; i++) {
+ for (j = 0; j < fld->maxusage; j++) {
+ if (fld->usage[j].hid == (HID_UP_PID | usagetable[i])) {
+ keys[i] = j + 1;
+ found++;
+ break;
+ }
+ }
+ }
+ return found;
+}
+
+#define PIDFF_FIND_SPECIAL_KEYS(keys, field, name) \
+ pidff_find_special_keys(pidff->keys, pidff->field, pidff_ ## name, \
+ sizeof(pidff_ ## name))
+
+/*
+ * Find and check the special fields
+ */
+static int pidff_find_special_fields(struct pidff_device *pidff)
+{
+ debug("finding special fields");
+
+ pidff->create_new_effect_type =
+ pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
+ 0x25, 1);
+ pidff->set_effect_type =
+ pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
+ 0x25, 1);
+ pidff->effect_direction =
+ pidff_find_special_field(pidff->reports[PID_SET_EFFECT],
+ 0x57, 0);
+ pidff->device_control =
+ pidff_find_special_field(pidff->reports[PID_DEVICE_CONTROL],
+ 0x96, 1);
+ pidff->block_load_status =
+ pidff_find_special_field(pidff->reports[PID_BLOCK_LOAD],
+ 0x8b, 1);
+ pidff->effect_operation_status =
+ pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
+ 0x78, 1);
+
+ debug("search done");
+
+ if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
+ printk(KERN_ERR "hid-pidff: effect lists not found\n");
+ return -1;
+ }
+
+ if (!pidff->effect_direction) {
+ printk(KERN_ERR "hid-pidff: direction field not found\n");
+ return -1;
+ }
+
+ if (!pidff->device_control) {
+ printk(KERN_ERR "hid-pidff: device control field not found\n");
+ return -1;
+ }
+
+ if (!pidff->block_load_status) {
+ printk(KERN_ERR
+ "hid-pidff: block load status field not found\n");
+ return -1;
+ }
+
+ if (!pidff->effect_operation_status) {
+ printk(KERN_ERR
+ "hid-pidff: effect operation field not found\n");
+ return -1;
+ }
+
+ pidff_find_special_keys(pidff->control_id, pidff->device_control,
+ pidff_device_control,
+ sizeof(pidff_device_control));
+
+ PIDFF_FIND_SPECIAL_KEYS(control_id, device_control, device_control);
+
+ if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
+ effect_types)) {
+ printk(KERN_ERR "hid-pidff: no effect types found\n");
+ return -1;
+ }
+
+ if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
+ block_load_status) !=
+ sizeof(pidff_block_load_status)) {
+ printk(KERN_ERR
+ "hidpidff: block load status identifiers not found\n");
+ return -1;
+ }
+
+ if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
+ effect_operation_status) !=
+ sizeof(pidff_effect_operation_status)) {
+ printk(KERN_ERR
+ "hidpidff: effect operation identifiers not found\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Find the implemented effect types
+ */
+static int pidff_find_effects(struct pidff_device *pidff,
+ struct input_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < sizeof(pidff_effect_types); i++) {
+ int pidff_type = pidff->type_id[i];
+ if (pidff->set_effect_type->usage[pidff_type].hid !=
+ pidff->create_new_effect_type->usage[pidff_type].hid) {
+ printk(KERN_ERR "hid-pidff: "
+ "effect type number %d is invalid\n", i);
+ return -1;
+ }
+ }
+
+ if (pidff->type_id[PID_CONSTANT])
+ set_bit(FF_CONSTANT, dev->ffbit);
+ if (pidff->type_id[PID_RAMP])
+ set_bit(FF_RAMP, dev->ffbit);
+ if (pidff->type_id[PID_SQUARE]) {
+ set_bit(FF_SQUARE, dev->ffbit);
+ set_bit(FF_PERIODIC, dev->ffbit);
+ }
+ if (pidff->type_id[PID_SINE]) {
+ set_bit(FF_SINE, dev->ffbit);
+ set_bit(FF_PERIODIC, dev->ffbit);
+ }
+ if (pidff->type_id[PID_TRIANGLE]) {
+ set_bit(FF_TRIANGLE, dev->ffbit);
+ set_bit(FF_PERIODIC, dev->ffbit);
+ }
+ if (pidff->type_id[PID_SAW_UP]) {
+ set_bit(FF_SAW_UP, dev->ffbit);
+ set_bit(FF_PERIODIC, dev->ffbit);
+ }
+ if (pidff->type_id[PID_SAW_DOWN]) {
+ set_bit(FF_SAW_DOWN, dev->ffbit);
+ set_bit(FF_PERIODIC, dev->ffbit);
+ }
+ if (pidff->type_id[PID_SPRING])
+ set_bit(FF_SPRING, dev->ffbit);
+ if (pidff->type_id[PID_DAMPER])
+ set_bit(FF_DAMPER, dev->ffbit);
+ if (pidff->type_id[PID_INERTIA])
+ set_bit(FF_INERTIA, dev->ffbit);
+ if (pidff->type_id[PID_FRICTION])
+ set_bit(FF_FRICTION, dev->ffbit);
+
+ return 0;
+
+}
+
+#define PIDFF_FIND_FIELDS(name, report, strict) \
+ pidff_find_fields(pidff->name, pidff_ ## name, \
+ pidff->reports[report], \
+ sizeof(pidff_ ## name), strict)
+
+/*
+ * Fill and check the pidff_usages
+ */
+static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
+{
+ int envelope_ok = 0;
+
+ if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
+ printk(KERN_ERR
+ "hid-pidff: unknown set_effect report layout\n");
+ return -ENODEV;
+ }
+
+ PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
+ if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
+ printk(KERN_ERR
+ "hid-pidff: unknown pid_block_load report layout\n");
+ return -ENODEV;
+ }
+
+ if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
+ printk(KERN_ERR
+ "hid-pidff: unknown effect_operation report layout\n");
+ return -ENODEV;
+ }
+
+ if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
+ printk(KERN_ERR
+ "hid-pidff: unknown pid_block_free report layout\n");
+ return -ENODEV;
+ }
+
+ if (!PIDFF_FIND_FIELDS(set_envelope, PID_SET_ENVELOPE, 1))
+ envelope_ok = 1;
+
+ if (pidff_find_special_fields(pidff) || pidff_find_effects(pidff, dev))
+ return -ENODEV;
+
+ if (!envelope_ok) {
+ if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
+ printk(KERN_WARNING "hid-pidff: "
+ "has constant effect but no envelope\n");
+ if (test_and_clear_bit(FF_RAMP, dev->ffbit))
+ printk(KERN_WARNING "hid-pidff: "
+ "has ramp effect but no envelope\n");
+
+ if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
+ printk(KERN_WARNING "hid-pidff: "
+ "has periodic effect but no envelope\n");
+ }
+
+ if (test_bit(FF_CONSTANT, dev->ffbit) &&
+ PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
+ printk(KERN_WARNING
+ "hid-pidff: unknown constant effect layout\n");
+ clear_bit(FF_CONSTANT, dev->ffbit);
+ }
+
+ if (test_bit(FF_RAMP, dev->ffbit) &&
+ PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
+ printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
+ clear_bit(FF_RAMP, dev->ffbit);
+ }
+
+ if ((test_bit(FF_SPRING, dev->ffbit) ||
+ test_bit(FF_DAMPER, dev->ffbit) ||
+ test_bit(FF_FRICTION, dev->ffbit) ||
+ test_bit(FF_INERTIA, dev->ffbit)) &&
+ PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
+ printk(KERN_WARNING
+ "hid-pidff: unknown condition effect layout\n");
+ clear_bit(FF_SPRING, dev->ffbit);
+ clear_bit(FF_DAMPER, dev->ffbit);
+ clear_bit(FF_FRICTION, dev->ffbit);
+ clear_bit(FF_INERTIA, dev->ffbit);
+ }
+
+ if (test_bit(FF_PERIODIC, dev->ffbit) &&
+ PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
+ printk(KERN_WARNING
+ "hid-pidff: unknown periodic effect layout\n");
+ clear_bit(FF_PERIODIC, dev->ffbit);
+ }
+
+ PIDFF_FIND_FIELDS(pool, PID_POOL, 0);
+
+ if (!PIDFF_FIND_FIELDS(device_gain, PID_DEVICE_GAIN, 1))
+ set_bit(FF_GAIN, dev->ffbit);
+
+ return 0;
+}
+
+/*
+ * Reset the device
+ */
+static void pidff_reset(struct pidff_device *pidff)
+{
+ struct hid_device *hid = pidff->hid;
+ int i = 0;
+
+ pidff->device_control->value[0] = pidff->control_id[PID_RESET];
+ /* We reset twice as sometimes hid_wait_io isn't waiting long enough */
+ hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ hid_wait_io(hid);
+ hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ hid_wait_io(hid);
+
+ pidff->device_control->value[0] =
+ pidff->control_id[PID_ENABLE_ACTUATORS];
+ hid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
+ hid_wait_io(hid);
+
+ /* pool report is sometimes messed up, refetch it */
+ hid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
+ hid_wait_io(hid);
+
+ if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
+ int sim_effects = pidff->pool[PID_SIMULTANEOUS_MAX].value[0];
+ while (sim_effects < 2) {
+ if (i++ > 20) {
+ printk(KERN_WARNING "hid-pidff: device reports "
+ "%d simultaneous effects\n",
+ sim_effects);
+ break;
+ }
+ debug("pid_pool requested again");
+ hid_submit_report(hid, pidff->reports[PID_POOL],
+ USB_DIR_IN);
+ hid_wait_io(hid);
+ }
+ }
+}
+
+/*
+ * Test if autocenter modification is using the supported method
+ */
+static int pidff_check_autocenter(struct pidff_device *pidff,
+ struct input_dev *dev)
+{
+ int error;
+
+ /*
+ * Let's find out if autocenter modification is supported
+ * Specification doesn't specify anything, so we request an
+ * effect upload and cancel it immediately. If the approved
+ * effect id was one above the minimum, then we assume the first
+ * effect id is a built-in spring type effect used for autocenter
+ */
+
+ error = pidff_request_effect_upload(pidff, 1);
+ if (error) {
+ printk(KERN_ERR "hid-pidff: upload request failed\n");
+ return error;
+ }
+
+ if (pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] ==
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum + 1) {
+ pidff_autocenter(pidff, 0xffff);
+ set_bit(FF_AUTOCENTER, dev->ffbit);
+ } else {
+ printk(KERN_NOTICE "hid-pidff: "
+ "device has unknown autocenter control method\n");
+ }
+
+ pidff_erase_pid(pidff,
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0]);
+
+ return 0;
+
+}
+
+/*
+ * Check if the device is PID and initialize it
+ */
+int hid_pidff_init(struct hid_device *hid)
+{
+ struct pidff_device *pidff;
+ struct hid_input *hidinput = list_entry(hid->inputs.next,
+ struct hid_input, list);
+ struct input_dev *dev = hidinput->input;
+ struct ff_device *ff;
+ int max_effects;
+ int error;
+
+ debug("starting pid init");
+
+ if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
+ debug("not a PID device, no output report");
+ return -ENODEV;
+ }
+
+ pidff = kzalloc(sizeof(*pidff), GFP_KERNEL);
+ if (!pidff)
+ return -ENOMEM;
+
+ pidff->hid = hid;
+
+ pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
+ pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
+
+ if (!pidff_reports_ok(pidff)) {
+ debug("reports not ok, aborting");
+ error = -ENODEV;
+ goto fail;
+ }
+
+ error = pidff_init_fields(pidff, dev);
+ if (error)
+ goto fail;
+
+ pidff_reset(pidff);
+
+ if (test_bit(FF_GAIN, dev->ffbit)) {
+ pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
+ hid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
+ USB_DIR_OUT);
+ }
+
+ error = pidff_check_autocenter(pidff, dev);
+ if (error)
+ goto fail;
+
+ max_effects =
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
+ pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
+ 1;
+ debug("max effects is %d", max_effects);
+
+ if (max_effects > PID_EFFECTS_MAX)
+ max_effects = PID_EFFECTS_MAX;
+
+ if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
+ debug("max simultaneous effects is %d",
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+
+ if (pidff->pool[PID_RAM_POOL_SIZE].value)
+ debug("device memory size is %d bytes",
+ pidff->pool[PID_RAM_POOL_SIZE].value[0]);
+
+ if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
+ pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
+ printk(KERN_NOTICE "hid-pidff: "
+ "device does not support device managed pool\n");
+ goto fail;
+ }
+
+ error = input_ff_create(dev, max_effects);
+ if (error)
+ goto fail;
+
+ ff = dev->ff;
+ ff->private = pidff;
+ ff->upload = pidff_upload_effect;
+ ff->erase = pidff_erase_effect;
+ ff->set_gain = pidff_set_gain;
+ ff->set_autocenter = pidff_set_autocenter;
+ ff->playback = pidff_playback;
+
+ printk(KERN_INFO "Force feedback for USB HID PID devices by "
+ "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+ return 0;
+
+ fail:
+ kfree(pidff);
+ return error;
+}
diff --git a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
index 534425c69c0a..2d5be4c318ac 100644
--- a/drivers/usb/input/hid-tmff.c
+++ b/drivers/usb/input/hid-tmff.c
@@ -28,97 +28,65 @@
*/
#include <linux/input.h>
-#include <linux/sched.h>
#undef DEBUG
#include <linux/usb.h>
-#include <linux/circ_buf.h>
-
#include "hid.h"
-#include "fixp-arith.h"
/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_RUMBLE_LR (HID_UP_GENDESK | 0xbb)
-#define DELAY_CALC(t,delay) ((t) + (delay)*HZ/1000)
-
-/* Effect status */
-#define EFFECT_STARTED 0 /* Effect is going to play after some time */
-#define EFFECT_PLAYING 1 /* Effect is playing */
-#define EFFECT_USED 2
-
-/* For tmff_device::flags */
-#define DEVICE_CLOSING 0 /* The driver is being unitialised */
-
-/* Check that the current process can access an effect */
-#define CHECK_OWNERSHIP(effect) (current->pid == 0 \
- || effect.owner == current->pid)
-
-#define TMFF_CHECK_ID(id) ((id) >= 0 && (id) < TMFF_EFFECTS)
-#define TMFF_CHECK_OWNERSHIP(i, l) \
- (test_bit(EFFECT_USED, l->effects[i].flags) \
- && CHECK_OWNERSHIP(l->effects[i]))
-
-#define TMFF_EFFECTS 8
-
-struct tmff_effect {
- pid_t owner;
-
- struct ff_effect effect;
-
- unsigned long flags[1];
- unsigned int count; /* Number of times left to play */
-
- unsigned long play_at; /* When the effect starts to play */
- unsigned long stop_at; /* When the effect ends */
-};
struct tmff_device {
- struct hid_device *hid;
-
struct hid_report *report;
-
struct hid_field *rumble;
+};
- unsigned int effects_playing;
- struct tmff_effect effects[TMFF_EFFECTS];
- spinlock_t lock; /* device-level lock. Having locks on
- a per-effect basis could be nice, but
- isn't really necessary */
+/* Changes values from 0 to 0xffff into values from minimum to maximum */
+static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
+{
+ int ret;
- unsigned long flags[1]; /* Contains various information about the
- state of the driver for this device */
+ ret = (in * (maximum - minimum) / 0xffff) + minimum;
+ if (ret < minimum)
+ return minimum;
+ if (ret > maximum)
+ return maximum;
+ return ret;
+}
- struct timer_list timer;
-};
+static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
+{
+ struct hid_device *hid = dev->private;
+ struct tmff_device *tmff = data;
+ int left, right; /* Rumbling */
-/* Callbacks */
-static void hid_tmff_exit(struct hid_device *hid);
-static int hid_tmff_event(struct hid_device *hid, struct input_dev *input,
- unsigned int type, unsigned int code, int value);
-static int hid_tmff_flush(struct input_dev *input, struct file *file);
-static int hid_tmff_upload_effect(struct input_dev *input,
- struct ff_effect *effect);
-static int hid_tmff_erase(struct input_dev *input, int id);
+ left = hid_tmff_scale(effect->u.rumble.weak_magnitude,
+ tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
+ right = hid_tmff_scale(effect->u.rumble.strong_magnitude,
+ tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-/* Local functions */
-static void hid_tmff_recalculate_timer(struct tmff_device *tmff);
-static void hid_tmff_timer(unsigned long timer_data);
+ tmff->rumble->value[0] = left;
+ tmff->rumble->value[1] = right;
+ dbg("(left,right)=(%08x, %08x)", left, right);
+ hid_submit_report(hid, tmff->report, USB_DIR_OUT);
+
+ return 0;
+}
int hid_tmff_init(struct hid_device *hid)
{
- struct tmff_device *private;
+ struct tmff_device *tmff;
struct list_head *pos;
struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
+ int error;
- private = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
- if (!private)
+ tmff = kzalloc(sizeof(struct tmff_device), GFP_KERNEL);
+ if (!tmff)
return -ENOMEM;
- hid->ff_private = private;
-
/* Find the report to use */
__list_for_each(pos, &hid->report_enum[HID_OUTPUT_REPORT].report_list) {
struct hid_report *report = (struct hid_report *)pos;
@@ -142,18 +110,18 @@ int hid_tmff_init(struct hid_device *hid)
continue;
}
- if (private->report && private->report != report) {
+ if (tmff->report && tmff->report != report) {
warn("ignoring THRUSTMASTER_USAGE_RUMBLE_LR in other report");
continue;
}
- if (private->rumble && private->rumble != field) {
+ if (tmff->rumble && tmff->rumble != field) {
warn("ignoring duplicate THRUSTMASTER_USAGE_RUMBLE_LR");
continue;
}
- private->report = report;
- private->rumble = field;
+ tmff->report = report;
+ tmff->rumble = field;
set_bit(FF_RUMBLE, input_dev->ffbit);
break;
@@ -162,302 +130,17 @@ int hid_tmff_init(struct hid_device *hid)
warn("ignoring unknown output usage %08x", field->usage[0].hid);
continue;
}
-
- /* Fallthrough to here only when a valid usage is found */
- input_dev->upload_effect = hid_tmff_upload_effect;
- input_dev->flush = hid_tmff_flush;
-
- set_bit(EV_FF, input_dev->evbit);
- input_dev->ff_effects_max = TMFF_EFFECTS;
}
}
- private->hid = hid;
-
- spin_lock_init(&private->lock);
- init_timer(&private->timer);
- private->timer.data = (unsigned long)private;
- private->timer.function = hid_tmff_timer;
-
- /* Event and exit callbacks */
- hid->ff_exit = hid_tmff_exit;
- hid->ff_event = hid_tmff_event;
-
- info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
-
- return 0;
-}
-
-static void hid_tmff_exit(struct hid_device *hid)
-{
- struct tmff_device *tmff = hid->ff_private;
- unsigned long flags;
-
- spin_lock_irqsave(&tmff->lock, flags);
-
- set_bit(DEVICE_CLOSING, tmff->flags);
- del_timer_sync(&tmff->timer);
-
- spin_unlock_irqrestore(&tmff->lock, flags);
-
- kfree(tmff);
-}
-
-static int hid_tmff_event(struct hid_device *hid, struct input_dev *input,
- unsigned int type, unsigned int code, int value)
-{
- struct tmff_device *tmff = hid->ff_private;
- struct tmff_effect *effect = &tmff->effects[code];
- unsigned long flags;
-
- if (type != EV_FF)
- return -EINVAL;
- if (!TMFF_CHECK_ID(code))
- return -EINVAL;
- if (!TMFF_CHECK_OWNERSHIP(code, tmff))
- return -EACCES;
- if (value < 0)
- return -EINVAL;
-
- spin_lock_irqsave(&tmff->lock, flags);
-
- if (value > 0) {
- set_bit(EFFECT_STARTED, effect->flags);
- clear_bit(EFFECT_PLAYING, effect->flags);
- effect->count = value;
- effect->play_at = DELAY_CALC(jiffies, effect->effect.replay.delay);
- } else {
- clear_bit(EFFECT_STARTED, effect->flags);
- clear_bit(EFFECT_PLAYING, effect->flags);
- }
-
- hid_tmff_recalculate_timer(tmff);
-
- spin_unlock_irqrestore(&tmff->lock, flags);
-
- return 0;
-
-}
-
-/* Erase all effects this process owns */
-
-static int hid_tmff_flush(struct input_dev *dev, struct file *file)
-{
- struct hid_device *hid = dev->private;
- struct tmff_device *tmff = hid->ff_private;
- int i;
-
- for (i=0; i<dev->ff_effects_max; ++i)
-
- /* NOTE: no need to lock here. The only times EFFECT_USED is
- modified is when effects are uploaded or when an effect is
- erased. But a process cannot close its dev/input/eventX fd
- and perform ioctls on the same fd all at the same time */
-
- if (current->pid == tmff->effects[i].owner
- && test_bit(EFFECT_USED, tmff->effects[i].flags))
- if (hid_tmff_erase(dev, i))
- warn("erase effect %d failed", i);
-
-
- return 0;
-}
-
-static int hid_tmff_erase(struct input_dev *dev, int id)
-{
- struct hid_device *hid = dev->private;
- struct tmff_device *tmff = hid->ff_private;
- unsigned long flags;
-
- if (!TMFF_CHECK_ID(id))
- return -EINVAL;
- if (!TMFF_CHECK_OWNERSHIP(id, tmff))
- return -EACCES;
-
- spin_lock_irqsave(&tmff->lock, flags);
-
- tmff->effects[id].flags[0] = 0;
- hid_tmff_recalculate_timer(tmff);
-
- spin_unlock_irqrestore(&tmff->lock, flags);
-
- return 0;
-}
-
-static int hid_tmff_upload_effect(struct input_dev *input,
- struct ff_effect *effect)
-{
- struct hid_device *hid = input->private;
- struct tmff_device *tmff = hid->ff_private;
- int id;
- unsigned long flags;
-
- if (!test_bit(effect->type, input->ffbit))
- return -EINVAL;
- if (effect->id != -1 && !TMFF_CHECK_ID(effect->id))
- return -EINVAL;
-
- spin_lock_irqsave(&tmff->lock, flags);
-
- if (effect->id == -1) {
- /* Find a free effect */
- for (id = 0; id < TMFF_EFFECTS && test_bit(EFFECT_USED, tmff->effects[id].flags); ++id);
-
- if (id >= TMFF_EFFECTS) {
- spin_unlock_irqrestore(&tmff->lock, flags);
- return -ENOSPC;
- }
-
- effect->id = id;
- tmff->effects[id].owner = current->pid;
- tmff->effects[id].flags[0] = 0;
- set_bit(EFFECT_USED, tmff->effects[id].flags);
-
- } else {
- /* Re-uploading an owned effect, to change parameters */
- id = effect->id;
- clear_bit(EFFECT_PLAYING, tmff->effects[id].flags);
+ error = input_ff_create_memless(input_dev, tmff, hid_tmff_play);
+ if (error) {
+ kfree(tmff);
+ return error;
}
- tmff->effects[id].effect = *effect;
-
- hid_tmff_recalculate_timer(tmff);
+ info("Force feedback for ThrustMaster rumble pad devices by Zinx Verituse <zinx@epicsol.org>");
- spin_unlock_irqrestore(&tmff->lock, flags);
return 0;
}
-/* Start the timer for the next start/stop/delay */
-/* Always call this while tmff->lock is locked */
-
-static void hid_tmff_recalculate_timer(struct tmff_device *tmff)
-{
- int i;
- int events = 0;
- unsigned long next_time;
-
- next_time = 0; /* Shut up compiler's incorrect warning */
-
- /* Find the next change in an effect's status */
- for (i = 0; i < TMFF_EFFECTS; ++i) {
- struct tmff_effect *effect = &tmff->effects[i];
- unsigned long play_time;
-
- if (!test_bit(EFFECT_STARTED, effect->flags))
- continue;
-
- effect->stop_at = DELAY_CALC(effect->play_at, effect->effect.replay.length);
-
- if (!test_bit(EFFECT_PLAYING, effect->flags))
- play_time = effect->play_at;
- else
- play_time = effect->stop_at;
-
- events++;
-
- if (time_after(jiffies, play_time))
- play_time = jiffies;
-
- if (events == 1)
- next_time = play_time;
- else {
- if (time_after(next_time, play_time))
- next_time = play_time;
- }
- }
-
- if (!events && tmff->effects_playing) {
- /* Treat all effects turning off as an event */
- events = 1;
- next_time = jiffies;
- }
-
- if (!events) {
- /* No events, no time, no need for a timer. */
- del_timer_sync(&tmff->timer);
- return;
- }
-
- mod_timer(&tmff->timer, next_time);
-}
-
-/* Changes values from 0 to 0xffff into values from minimum to maximum */
-static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
-{
- int ret;
-
- ret = (in * (maximum - minimum) / 0xffff) + minimum;
- if (ret < minimum)
- return minimum;
- if (ret > maximum)
- return maximum;
- return ret;
-}
-
-static void hid_tmff_timer(unsigned long timer_data)
-{
- struct tmff_device *tmff = (struct tmff_device *) timer_data;
- struct hid_device *hid = tmff->hid;
- unsigned long flags;
- int left = 0, right = 0; /* Rumbling */
- int i;
-
- spin_lock_irqsave(&tmff->lock, flags);
-
- tmff->effects_playing = 0;
-
- for (i = 0; i < TMFF_EFFECTS; ++i) {
- struct tmff_effect *effect = &tmff->effects[i];
-
- if (!test_bit(EFFECT_STARTED, effect->flags))
- continue;
-
- if (!time_after(jiffies, effect->play_at))
- continue;
-
- if (time_after(jiffies, effect->stop_at)) {
-
- dbg("Finished playing once %d", i);
- clear_bit(EFFECT_PLAYING, effect->flags);
-
- if (--effect->count <= 0) {
- dbg("Stopped %d", i);
- clear_bit(EFFECT_STARTED, effect->flags);
- continue;
- } else {
- dbg("Start again %d", i);
- effect->play_at = DELAY_CALC(jiffies, effect->effect.replay.delay);
- continue;
- }
- }
-
- ++tmff->effects_playing;
-
- set_bit(EFFECT_PLAYING, effect->flags);
-
- switch (effect->effect.type) {
- case FF_RUMBLE:
- right += effect->effect.u.rumble.strong_magnitude;
- left += effect->effect.u.rumble.weak_magnitude;
- break;
- default:
- BUG();
- break;
- }
- }
-
- left = hid_tmff_scale(left, tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
- right = hid_tmff_scale(right, tmff->rumble->logical_minimum, tmff->rumble->logical_maximum);
-
- if (left != tmff->rumble->value[0] || right != tmff->rumble->value[1]) {
- tmff->rumble->value[0] = left;
- tmff->rumble->value[1] = right;
- dbg("(left,right)=(%08x, %08x)", left, right);
- hid_submit_report(hid, tmff->report, USB_DIR_OUT);
- }
-
- if (!test_bit(DEVICE_CLOSING, tmff->flags))
- hid_tmff_recalculate_timer(tmff);
-
- spin_unlock_irqrestore(&tmff->lock, flags);
-}
diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c
new file mode 100644
index 000000000000..d2ce3214572c
--- /dev/null
+++ b/drivers/usb/input/hid-zpff.c
@@ -0,0 +1,110 @@
+/*
+ * Force feedback support for Zeroplus based devices
+ *
+ * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.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
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include "hid.h"
+
+struct zpff_device {
+ struct hid_report *report;
+};
+
+static int hid_zpff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = dev->private;
+ struct zpff_device *zpff = data;
+ int left, right;
+
+ /*
+ * The following is specified the other way around in the Zeroplus
+ * datasheet but the order below is correct for the XFX Executioner;
+ * however it is possible that the XFX Executioner is an exception
+ */
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+ debug("called with 0x%04x 0x%04x", left, right);
+
+ left = left * 0x7f / 0xffff;
+ right = right * 0x7f / 0xffff;
+
+ zpff->report->field[2]->value[0] = left;
+ zpff->report->field[3]->value[0] = right;
+ debug("running with 0x%02x 0x%02x", left, right);
+ hid_submit_report(hid, zpff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+int hid_zpff_init(struct hid_device *hid)
+{
+ struct zpff_device *zpff;
+ struct hid_report *report;
+ struct hid_input *hidinput = list_entry(hid->inputs.next,
+ struct hid_input, list);
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int error;
+
+ if (list_empty(report_list)) {
+ printk(KERN_ERR "hid-zpff: no output report found\n");
+ return -ENODEV;
+ }
+
+ report = list_entry(report_list->next, struct hid_report, list);
+
+ if (report->maxfield < 4) {
+ printk(KERN_ERR "hid-zpff: not enough fields in report\n");
+ return -ENODEV;
+ }
+
+ zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL);
+ if (!zpff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, zpff, hid_zpff_play);
+ if (error) {
+ kfree(zpff);
+ return error;
+ }
+
+ zpff->report = report;
+ zpff->report->field[0]->value[0] = 0x00;
+ zpff->report->field[1]->value[0] = 0x02;
+ zpff->report->field[2]->value[0] = 0x00;
+ zpff->report->field[3]->value[0] = 0x00;
+ hid_submit_report(hid, zpff->report, USB_DIR_OUT);
+
+ printk(KERN_INFO "Force feedback for Zeroplus based devices by "
+ "Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+ return 0;
+}
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index 778e575de352..9b50effef758 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -449,11 +449,6 @@ struct hid_device { /* device report descriptor */
char phys[64]; /* Device physical location */
char uniq[64]; /* Device unique identifier (serial #) */
- void *ff_private; /* Private data for the force-feedback driver */
- void (*ff_exit)(struct hid_device*); /* Called by hid_exit_ff(hid) */
- int (*ff_event)(struct hid_device *hid, struct input_dev *input,
- unsigned int type, unsigned int code, int value);
-
#ifdef CONFIG_USB_HIDINPUT_POWERBOOK
unsigned long pb_pressed_fn[NBITS(KEY_MAX)];
unsigned long pb_pressed_numlock[NBITS(KEY_MAX)];
@@ -504,13 +499,13 @@ struct hid_descriptor {
/* Applications from HID Usage Tables 4/8/99 Version 1.1 */
/* We ignore a few input applications that are not widely used */
#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
-extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32, struct pt_regs *regs);
+extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report);
extern int hidinput_connect(struct hid_device *);
extern void hidinput_disconnect(struct hid_device *);
#else
#define IS_INPUT_APPLICATION(a) (0)
-static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) { }
+static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { }
static inline void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { }
static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; }
static inline void hidinput_disconnect(struct hid_device *hid) { }
@@ -521,29 +516,22 @@ void hid_close(struct hid_device *);
int hid_set_field(struct hid_field *, unsigned, __s32);
void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir);
void hid_init_reports(struct hid_device *hid);
-struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type);
int hid_wait_io(struct hid_device* hid);
#ifdef CONFIG_HID_FF
int hid_ff_init(struct hid_device *hid);
+
+int hid_lgff_init(struct hid_device *hid);
+int hid_tmff_init(struct hid_device *hid);
+int hid_zpff_init(struct hid_device *hid);
+#ifdef CONFIG_HID_PID
+int hid_pidff_init(struct hid_device *hid);
+#else
+static inline int hid_pidff_init(struct hid_device *hid) { return -ENODEV; }
+#endif
+
#else
static inline int hid_ff_init(struct hid_device *hid) { return -1; }
#endif
-static inline void hid_ff_exit(struct hid_device *hid)
-{
- if (hid->ff_exit)
- hid->ff_exit(hid);
-}
-static inline int hid_ff_event(struct hid_device *hid, struct input_dev *input,
- unsigned int type, unsigned int code, int value)
-{
- if (hid->ff_event)
- return hid->ff_event(hid, input, type, code, value);
- return -ENOSYS;
-}
-
-int hid_lgff_init(struct hid_device* hid);
-int hid_tmff_init(struct hid_device* hid);
-int hid_pid_init(struct hid_device* hid);
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index f6b839c257a7..7dc14d0cacc1 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -179,7 +179,7 @@ static void hiddev_send_event(struct hid_device *hid,
* the interrupt pipe
*/
void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value, struct pt_regs *regs)
+ struct hid_usage *usage, __s32 value)
{
unsigned type = field->report_type;
struct hiddev_usage_ref uref;
@@ -722,7 +722,7 @@ inval:
return -EINVAL;
}
-static struct file_operations hiddev_fops = {
+static const struct file_operations hiddev_fops = {
.owner = THIS_MODULE,
.read = hiddev_read,
.write = hiddev_write,
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
index 86acb5f1907a..aac968aab860 100644
--- a/drivers/usb/input/itmtouch.c
+++ b/drivers/usb/input/itmtouch.c
@@ -36,7 +36,11 @@
*
* 1.2.1 09/03/2005 (HCE) hc@mivu.no
* Code cleanup and adjusting syntax to start matching kernel standards
- *
+ *
+ * 1.2.2 10/05/2006 (MJA) massad@gmail.com
+ * Flag for detecting if the screen was being touch was incorrectly
+ * inverted, so no touch events were being detected.
+ *
*****************************************************************************/
#include <linux/kernel.h>
@@ -53,7 +57,7 @@
#define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9
#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>"
-#define DRIVER_VERSION "v1.2.1"
+#define DRIVER_VERSION "v1.2.2"
#define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
#define DRIVER_LICENSE "GPL"
@@ -76,7 +80,7 @@ static struct usb_device_id itmtouch_ids [] = {
{ }
};
-static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
+static void itmtouch_irq(struct urb *urb)
{
struct itmtouch_dev *itmtouch = urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -87,7 +91,7 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
@@ -105,10 +109,8 @@ static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- input_regs(dev, regs);
-
/* if pressure has been released, then don't report X/Y */
- if (data[7] & 0x20) {
+ if (!(data[7] & 0x20)) {
input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F));
input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F));
}
diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
index 604ade356ead..fedbcb127c21 100644
--- a/drivers/usb/input/kbtab.c
+++ b/drivers/usb/input/kbtab.c
@@ -41,7 +41,7 @@ struct kbtab {
char phys[32];
};
-static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
+static void kbtab_irq(struct urb *urb)
{
struct kbtab *kbtab = urb->context;
unsigned char *data = kbtab->data;
diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c
index 4723b310f277..50aa8108a50b 100644
--- a/drivers/usb/input/keyspan_remote.c
+++ b/drivers/usb/input/keyspan_remote.c
@@ -176,7 +176,7 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
/*
* Routine that handles all the logic needed to parse out the message from the remote.
*/
-static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs)
+static void keyspan_check_data(struct usb_keyspan *remote)
{
int i;
int found = 0;
@@ -311,7 +311,6 @@ static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs)
__FUNCTION__, message.system, message.button, message.toggle);
if (message.toggle != remote->toggle) {
- input_regs(remote->input, regs);
input_report_key(remote->input, keyspan_key_table[message.button], 1);
input_report_key(remote->input, keyspan_key_table[message.button], 0);
input_sync(remote->input);
@@ -361,7 +360,7 @@ static int keyspan_setup(struct usb_device* dev)
/*
* Routine used to handle a new message that has come in.
*/
-static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs)
+static void keyspan_irq_recv(struct urb *urb)
{
struct usb_keyspan *dev = urb->context;
int retval;
@@ -385,7 +384,7 @@ static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs)
if (debug)
keyspan_print(dev);
- keyspan_check_data(dev, regs);
+ keyspan_check_data(dev);
resubmit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -420,8 +419,7 @@ static struct usb_endpoint_descriptor *keyspan_get_in_endpoint(struct usb_host_i
for (i = 0; i < iface->desc.bNumEndpoints; ++i) {
endpoint = &iface->endpoint[i].desc;
- if ((endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ if (usb_endpoint_is_int_in(endpoint)) {
/* we found our interrupt in endpoint */
return endpoint;
}
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
index a9ccda8810e0..79a85d46cb13 100644
--- a/drivers/usb/input/mtouchusb.c
+++ b/drivers/usb/input/mtouchusb.c
@@ -98,7 +98,7 @@ static struct usb_device_id mtouchusb_devices[] = {
{ }
};
-static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
+static void mtouchusb_irq(struct urb *urb)
{
struct mtouch_usb *mtouch = urb->context;
int retval;
@@ -107,7 +107,7 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
@@ -125,7 +125,6 @@ static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- input_regs(mtouch->input, regs);
input_report_key(mtouch->input, BTN_TOUCH,
MTOUCHUSB_GET_TOUCHED(mtouch->data));
input_report_abs(mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data));
diff --git a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
deleted file mode 100644
index d9d9f656b8c9..000000000000
--- a/drivers/usb/input/pid.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * PID Force feedback support for hid devices.
- *
- * Copyright (c) 2002 Rodrigo Damazio.
- * Portions by Johann Deneux and Bjorn Augustson
- */
-
-/*
- * 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
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <rdamazio@lsi.usp.br>
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#include <linux/input.h>
-#include <linux/usb.h>
-#include "hid.h"
-#include "pid.h"
-
-#define CHECK_OWNERSHIP(i, hid_pid) \
- ((i) < FF_EFFECTS_MAX && i >= 0 && \
- test_bit(FF_PID_FLAGS_USED, &hid_pid->effects[(i)].flags) && \
- (current->pid == 0 || \
- (hid_pid)->effects[(i)].owner == current->pid))
-
-/* Called when a transfer is completed */
-static void hid_pid_ctrl_out(struct urb *u, struct pt_regs *regs)
-{
- dev_dbg(&u->dev->dev, "hid_pid_ctrl_out - Transfer Completed\n");
-}
-
-static void hid_pid_exit(struct hid_device *hid)
-{
- struct hid_ff_pid *private = hid->ff_private;
-
- if (private->urbffout) {
- usb_kill_urb(private->urbffout);
- usb_free_urb(private->urbffout);
- }
-}
-
-static int pid_upload_periodic(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
-{
- dev_info(&pid->hid->dev->dev, "requested periodic force upload\n");
- return 0;
-}
-
-static int pid_upload_constant(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
-{
- dev_info(&pid->hid->dev->dev, "requested constant force upload\n");
- return 0;
-}
-
-static int pid_upload_condition(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
-{
- dev_info(&pid->hid->dev->dev, "requested Condition force upload\n");
- return 0;
-}
-
-static int pid_upload_ramp(struct hid_ff_pid *pid, struct ff_effect *effect, int is_update)
-{
- dev_info(&pid->hid->dev->dev, "request ramp force upload\n");
- return 0;
-}
-
-static int hid_pid_event(struct hid_device *hid, struct input_dev *input,
- unsigned int type, unsigned int code, int value)
-{
- dev_dbg(&hid->dev->dev, "PID event received: type=%d,code=%d,value=%d.\n", type, code, value);
-
- if (type != EV_FF)
- return -1;
-
- return 0;
-}
-
-/* Lock must be held by caller */
-static void hid_pid_ctrl_playback(struct hid_device *hid, struct hid_pid_effect *effect, int play)
-{
- if (play)
- set_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
- else
- clear_bit(FF_PID_FLAGS_PLAYING, &effect->flags);
-}
-
-static int hid_pid_erase(struct input_dev *dev, int id)
-{
- struct hid_device *hid = dev->private;
- struct hid_ff_pid *pid = hid->ff_private;
- struct hid_field *field;
- unsigned long flags;
- int ret;
-
- if (!CHECK_OWNERSHIP(id, pid))
- return -EACCES;
-
- /* Find report */
- field = hid_find_field_by_usage(hid, HID_UP_PID | FF_PID_USAGE_BLOCK_FREE,
- HID_OUTPUT_REPORT);
- if (!field) {
- dev_err(&hid->dev->dev, "couldn't find report\n");
- return -EIO;
- }
-
- ret = hid_set_field(field, 0, pid->effects[id].device_id);
- if (ret) {
- dev_err(&hid->dev->dev, "couldn't set field\n");
- return ret;
- }
-
- hid_submit_report(hid, field->report, USB_DIR_OUT);
-
- spin_lock_irqsave(&pid->lock, flags);
- hid_pid_ctrl_playback(hid, pid->effects + id, 0);
- pid->effects[id].flags = 0;
- spin_unlock_irqrestore(&pid->lock, flags);
-
- return 0;
-}
-
-/* Erase all effects this process owns */
-static int hid_pid_flush(struct input_dev *dev, struct file *file)
-{
- struct hid_device *hid = dev->private;
- struct hid_ff_pid *pid = hid->ff_private;
- int i;
-
- /*NOTE: no need to lock here. The only times EFFECT_USED is
- modified is when effects are uploaded or when an effect is
- erased. But a process cannot close its dev/input/eventX fd
- and perform ioctls on the same fd all at the same time */
- /*FIXME: multiple threads, anyone? */
- for (i = 0; i < dev->ff_effects_max; ++i)
- if (current->pid == pid->effects[i].owner
- && test_bit(FF_PID_FLAGS_USED, &pid->effects[i].flags))
- if (hid_pid_erase(dev, i))
- dev_warn(&hid->dev->dev, "erase effect %d failed", i);
-
- return 0;
-}
-
-static int hid_pid_upload_effect(struct input_dev *dev,
- struct ff_effect *effect)
-{
- struct hid_ff_pid *pid_private = (struct hid_ff_pid *)(dev->private);
- int ret;
- int is_update;
- unsigned long flags;
-
- dev_dbg(&pid_private->hid->dev->dev, "upload effect called: effect_type=%x\n", effect->type);
- /* Check this effect type is supported by this device */
- if (!test_bit(effect->type, dev->ffbit)) {
- dev_dbg(&pid_private->hid->dev->dev,
- "invalid kind of effect requested.\n");
- return -EINVAL;
- }
-
- /*
- * If we want to create a new effect, get a free id
- */
- if (effect->id == -1) {
- int id = 0;
-
- // Spinlock so we don`t get a race condition when choosing IDs
- spin_lock_irqsave(&pid_private->lock, flags);
-
- while (id < FF_EFFECTS_MAX)
- if (!test_and_set_bit(FF_PID_FLAGS_USED, &pid_private->effects[id++].flags))
- break;
-
- if (id == FF_EFFECTS_MAX) {
- spin_unlock_irqrestore(&pid_private->lock, flags);
-// TEMP - We need to get ff_effects_max correctly first: || id >= dev->ff_effects_max) {
- dev_dbg(&pid_private->hid->dev->dev, "Not enough device memory\n");
- return -ENOMEM;
- }
-
- effect->id = id;
- dev_dbg(&pid_private->hid->dev->dev, "effect ID is %d.\n", id);
- pid_private->effects[id].owner = current->pid;
- pid_private->effects[id].flags = (1 << FF_PID_FLAGS_USED);
- spin_unlock_irqrestore(&pid_private->lock, flags);
-
- is_update = FF_PID_FALSE;
- } else {
- /* We want to update an effect */
- if (!CHECK_OWNERSHIP(effect->id, pid_private))
- return -EACCES;
-
- /* Parameter type cannot be updated */
- if (effect->type != pid_private->effects[effect->id].effect.type)
- return -EINVAL;
-
- /* Check the effect is not already being updated */
- if (test_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags))
- return -EAGAIN;
-
- is_update = FF_PID_TRUE;
- }
-
- /*
- * Upload the effect
- */
- switch (effect->type) {
- case FF_PERIODIC:
- ret = pid_upload_periodic(pid_private, effect, is_update);
- break;
-
- case FF_CONSTANT:
- ret = pid_upload_constant(pid_private, effect, is_update);
- break;
-
- case FF_SPRING:
- case FF_FRICTION:
- case FF_DAMPER:
- case FF_INERTIA:
- ret = pid_upload_condition(pid_private, effect, is_update);
- break;
-
- case FF_RAMP:
- ret = pid_upload_ramp(pid_private, effect, is_update);
- break;
-
- default:
- dev_dbg(&pid_private->hid->dev->dev,
- "invalid type of effect requested - %x.\n",
- effect->type);
- return -EINVAL;
- }
- /* If a packet was sent, forbid new updates until we are notified
- * that the packet was updated
- */
- if (ret == 0)
- set_bit(FF_PID_FLAGS_UPDATING, &pid_private->effects[effect->id].flags);
- pid_private->effects[effect->id].effect = *effect;
- return ret;
-}
-
-int hid_pid_init(struct hid_device *hid)
-{
- struct hid_ff_pid *private;
- struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list);
- struct input_dev *input_dev = hidinput->input;
-
- private = hid->ff_private = kzalloc(sizeof(struct hid_ff_pid), GFP_KERNEL);
- if (!private)
- return -ENOMEM;
-
- private->hid = hid;
-
- hid->ff_exit = hid_pid_exit;
- hid->ff_event = hid_pid_event;
-
- /* Open output URB */
- if (!(private->urbffout = usb_alloc_urb(0, GFP_KERNEL))) {
- kfree(private);
- return -1;
- }
-
- usb_fill_control_urb(private->urbffout, hid->dev, 0,
- (void *)&private->ffcr, private->ctrl_buffer, 8,
- hid_pid_ctrl_out, hid);
-
- input_dev->upload_effect = hid_pid_upload_effect;
- input_dev->flush = hid_pid_flush;
- input_dev->ff_effects_max = 8; // A random default
- set_bit(EV_FF, input_dev->evbit);
- set_bit(EV_FF_STATUS, input_dev->evbit);
-
- spin_lock_init(&private->lock);
-
- printk(KERN_INFO "Force feedback driver for PID devices by Rodrigo Damazio <rdamazio@lsi.usp.br>.\n");
-
- return 0;
-}
diff --git a/drivers/usb/input/pid.h b/drivers/usb/input/pid.h
deleted file mode 100644
index a2cb9627ed0e..000000000000
--- a/drivers/usb/input/pid.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * PID Force feedback support for hid devices.
- *
- * Copyright (c) 2002 Rodrigo Damazio.
- */
-
-/*
- * 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
- *
- * Should you need to contact me, the author, you can do so by
- * e-mail - mail your message to <rdamazio@lsi.usp.br>
- */
-
-#define FF_EFFECTS_MAX 64
-
-#define FF_PID_FLAGS_USED 1 /* If the effect exists */
-#define FF_PID_FLAGS_UPDATING 2 /* If the effect is being updated */
-#define FF_PID_FLAGS_PLAYING 3 /* If the effect is currently being played */
-
-#define FF_PID_FALSE 0
-#define FF_PID_TRUE 1
-
-struct hid_pid_effect {
- unsigned long flags;
- pid_t owner;
- unsigned int device_id; /* The device-assigned ID */
- struct ff_effect effect;
-};
-
-struct hid_ff_pid {
- struct hid_device *hid;
- unsigned long gain;
-
- struct urb *urbffout;
- struct usb_ctrlrequest ffcr;
- spinlock_t lock;
-
- unsigned char ctrl_buffer[8];
-
- struct hid_pid_effect effects[FF_EFFECTS_MAX];
-};
-
-/*
- * Constants from the PID usage table (still far from complete)
- */
-
-#define FF_PID_USAGE_BLOCK_LOAD 0x89UL
-#define FF_PID_USAGE_BLOCK_FREE 0x90UL
-#define FF_PID_USAGE_NEW_EFFECT 0xABUL
-#define FF_PID_USAGE_POOL_REPORT 0x7FUL
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
index b3c0d0c3eae9..0bf91778c40d 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -80,10 +80,10 @@ struct powermate_device {
static char pm_name_powermate[] = "Griffin PowerMate";
static char pm_name_soundknob[] = "Griffin SoundKnob";
-static void powermate_config_complete(struct urb *urb, struct pt_regs *regs);
+static void powermate_config_complete(struct urb *urb);
/* Callback for data arriving from the PowerMate over the USB interrupt pipe */
-static void powermate_irq(struct urb *urb, struct pt_regs *regs)
+static void powermate_irq(struct urb *urb)
{
struct powermate_device *pm = urb->context;
int retval;
@@ -104,7 +104,6 @@ static void powermate_irq(struct urb *urb, struct pt_regs *regs)
}
/* handle updates to device state */
- input_regs(pm->input, regs);
input_report_key(pm->input, BTN_0, pm->data[0] & 0x01);
input_report_rel(pm->input, REL_DIAL, pm->data[1]);
input_sync(pm->input);
@@ -191,7 +190,7 @@ static void powermate_sync_state(struct powermate_device *pm)
}
/* Called when our asynchronous control message completes. We may need to issue another immediately */
-static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
+static void powermate_config_complete(struct urb *urb)
{
struct powermate_device *pm = urb->context;
unsigned long flags;
@@ -313,9 +312,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
- if (!(endpoint->bEndpointAddress & 0x80))
- return -EIO;
- if ((endpoint->bmAttributes & 3) != 3)
+ if (!usb_endpoint_is_int_in(endpoint))
return -EIO;
usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
index 0149043ffb97..05c0d1ca39ab 100644
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -92,8 +92,7 @@ static inline int touchkit_get_y(char *data)
/* processes one input packet. */
-static void touchkit_process_pkt(struct touchkit_usb *touchkit,
- struct pt_regs *regs, char *pkt)
+static void touchkit_process_pkt(struct touchkit_usb *touchkit, char *pkt)
{
int x, y;
@@ -109,7 +108,6 @@ static void touchkit_process_pkt(struct touchkit_usb *touchkit,
y = touchkit_get_y(pkt);
}
- input_regs(touchkit->input, regs);
input_report_key(touchkit->input, BTN_TOUCH, touchkit_get_touched(pkt));
input_report_abs(touchkit->input, ABS_X, x);
input_report_abs(touchkit->input, ABS_Y, y);
@@ -130,8 +128,7 @@ static int touchkit_get_pkt_len(char *buf)
return 0;
}
-static void touchkit_process(struct touchkit_usb *touchkit, int len,
- struct pt_regs *regs)
+static void touchkit_process(struct touchkit_usb *touchkit, int len)
{
char *buffer;
int pkt_len, buf_len, pos;
@@ -153,7 +150,7 @@ static void touchkit_process(struct touchkit_usb *touchkit, int len,
/* append, process */
tmp = pkt_len - touchkit->buf_len;
memcpy(touchkit->buffer + touchkit->buf_len, touchkit->data, tmp);
- touchkit_process_pkt(touchkit, regs, touchkit->buffer);
+ touchkit_process_pkt(touchkit, touchkit->buffer);
buffer = touchkit->data + tmp;
buf_len = len - tmp;
@@ -181,7 +178,7 @@ static void touchkit_process(struct touchkit_usb *touchkit, int len,
/* full packet: process */
if (likely(pkt_len <= buf_len)) {
- touchkit_process_pkt(touchkit, regs, buffer + pos);
+ touchkit_process_pkt(touchkit, buffer + pos);
} else {
/* incomplete packet: save in buffer */
memcpy(touchkit->buffer, buffer + pos, buf_len - pos);
@@ -192,7 +189,7 @@ static void touchkit_process(struct touchkit_usb *touchkit, int len,
}
-static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
+static void touchkit_irq(struct urb *urb)
{
struct touchkit_usb *touchkit = urb->context;
int retval;
@@ -201,7 +198,7 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
@@ -219,7 +216,7 @@ static void touchkit_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- touchkit_process(touchkit, urb->actual_length, regs);
+ touchkit_process(touchkit, urb->actual_length);
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index 5067a6ae650f..c73285cf8558 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -80,7 +80,7 @@ struct usb_kbd {
dma_addr_t leds_dma;
};
-static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs)
+static void usb_kbd_irq(struct urb *urb)
{
struct usb_kbd *kbd = urb->context;
int i;
@@ -97,8 +97,6 @@ static void usb_kbd_irq(struct urb *urb, struct pt_regs *regs)
goto resubmit;
}
- input_regs(kbd->dev, regs);
-
for (i = 0; i < 8; i++)
input_report_key(kbd->dev, usb_kbd_keycode[i + 224], (kbd->new[0] >> i) & 1);
@@ -158,7 +156,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
return 0;
}
-static void usb_kbd_led(struct urb *urb, struct pt_regs *regs)
+static void usb_kbd_led(struct urb *urb)
{
struct usb_kbd *kbd = urb->context;
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 446935b671d9..cbbbea332ed7 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -55,7 +55,7 @@ struct usb_mouse {
dma_addr_t data_dma;
};
-static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs)
+static void usb_mouse_irq(struct urb *urb)
{
struct usb_mouse *mouse = urb->context;
signed char *data = mouse->data;
@@ -74,8 +74,6 @@ static void usb_mouse_irq(struct urb *urb, struct pt_regs *regs)
goto resubmit;
}
- input_regs(dev, regs);
-
input_report_key(dev, BTN_LEFT, data[0] & 0x01);
input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
input_report_key(dev, BTN_MIDDLE, data[0] & 0x04);
@@ -218,7 +216,7 @@ static void usb_mouse_disconnect(struct usb_interface *intf)
static struct usb_device_id usb_mouse_id_table [] = {
{ USB_INTERFACE_INFO(3, 1, 2) },
- { } /* Terminating entry */
+ { } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);
diff --git a/drivers/usb/input/usbtouchscreen.c b/drivers/usb/input/usbtouchscreen.c
index a338bf4c2d78..2902742895ad 100644
--- a/drivers/usb/input/usbtouchscreen.c
+++ b/drivers/usb/input/usbtouchscreen.c
@@ -2,9 +2,12 @@
* usbtouchscreen.c
* Driver for USB Touchscreens, supporting those devices:
* - eGalax Touchkit
- * - 3M/Microtouch
+ * includes eTurboTouch CT-410/510/700
+ * - 3M/Microtouch EX II series
* - ITM
* - PanJit TouchSet
+ * - eTurboTouch
+ * - Gunze AHL61
*
* Copyright (C) 2004-2006 by Daniel Ritz <daniel.ritz@gmx.ch>
* Copyright (C) by Todd E. Johnson (mtouchusb.c)
@@ -32,7 +35,6 @@
//#define DEBUG
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
@@ -42,7 +44,7 @@
#include <linux/usb/input.h>
-#define DRIVER_VERSION "v0.3"
+#define DRIVER_VERSION "v0.4"
#define DRIVER_AUTHOR "Daniel Ritz <daniel.ritz@gmx.ch>"
#define DRIVER_DESC "USB Touchscreen Driver"
@@ -59,7 +61,8 @@ struct usbtouch_device_info {
int rept_size;
int flags;
- void (*process_pkt) (struct usbtouch_usb *usbtouch, struct pt_regs *regs, unsigned char *pkt, int len);
+ void (*process_pkt) (struct usbtouch_usb *usbtouch, unsigned char *pkt, int len);
+ int (*get_pkt_len) (unsigned char *pkt, int len);
int (*read_data) (unsigned char *pkt, int *x, int *y, int *touch, int *press);
int (*init) (struct usbtouch_usb *usbtouch);
};
@@ -81,8 +84,15 @@ struct usbtouch_usb {
char phys[64];
};
-static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
- struct pt_regs *regs, unsigned char *pkt, int len);
+
+#if defined(CONFIG_USB_TOUCHSCREEN_EGALAX) || defined(CONFIG_USB_TOUCHSCREEN_ETURBO)
+#define MULTI_PACKET
+#endif
+
+#ifdef MULTI_PACKET
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+ unsigned char *pkt, int len);
+#endif
/* device types */
enum {
@@ -91,14 +101,19 @@ enum {
DEVTYPE_PANJIT,
DEVTYPE_3M,
DEVTYPE_ITM,
+ DEVTYPE_ETURBO,
+ DEVTYPE_GUNZE,
};
static struct usb_device_id usbtouch_devices[] = {
#ifdef CONFIG_USB_TOUCHSCREEN_EGALAX
{USB_DEVICE(0x3823, 0x0001), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x3823, 0x0002), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0123, 0x0001), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0eef, 0x0001), .driver_info = DEVTYPE_EGALAX},
{USB_DEVICE(0x0eef, 0x0002), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x1234, 0x0001), .driver_info = DEVTYPE_EGALAX},
+ {USB_DEVICE(0x1234, 0x0002), .driver_info = DEVTYPE_EGALAX},
#endif
#ifdef CONFIG_USB_TOUCHSCREEN_PANJIT
@@ -116,6 +131,14 @@ static struct usb_device_id usbtouch_devices[] = {
{USB_DEVICE(0x0403, 0xf9e9), .driver_info = DEVTYPE_ITM},
#endif
+#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
+ {USB_DEVICE(0x1234, 0x5678), .driver_info = DEVTYPE_ETURBO},
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
+ {USB_DEVICE(0x0637, 0x0001), .driver_info = DEVTYPE_GUNZE},
+#endif
+
{}
};
@@ -140,82 +163,23 @@ static int egalax_read_data(unsigned char *pkt, int *x, int *y, int *touch, int
*touch = pkt[0] & 0x01;
return 1;
-
}
-static int egalax_get_pkt_len(unsigned char *buf)
+static int egalax_get_pkt_len(unsigned char *buf, int len)
{
switch (buf[0] & EGALAX_PKT_TYPE_MASK) {
case EGALAX_PKT_TYPE_REPT:
return 5;
case EGALAX_PKT_TYPE_DIAG:
+ if (len < 2)
+ return -1;
+
return buf[1] + 2;
}
return 0;
}
-
-static void egalax_process(struct usbtouch_usb *usbtouch, struct pt_regs *regs,
- unsigned char *pkt, int len)
-{
- unsigned char *buffer;
- int pkt_len, buf_len, pos;
-
- /* if the buffer contains data, append */
- if (unlikely(usbtouch->buf_len)) {
- int tmp;
-
- /* if only 1 byte in buffer, add another one to get length */
- if (usbtouch->buf_len == 1)
- usbtouch->buffer[1] = pkt[0];
-
- pkt_len = egalax_get_pkt_len(usbtouch->buffer);
-
- /* unknown packet: drop everything */
- if (!pkt_len)
- return;
-
- /* append, process */
- tmp = pkt_len - usbtouch->buf_len;
- memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
- usbtouch_process_pkt(usbtouch, regs, usbtouch->buffer, pkt_len);
-
- buffer = pkt + tmp;
- buf_len = len - tmp;
- } else {
- buffer = pkt;
- buf_len = len;
- }
-
- /* only one byte left in buffer */
- if (unlikely(buf_len == 1)) {
- usbtouch->buffer[0] = buffer[0];
- usbtouch->buf_len = 1;
- return;
- }
-
- /* loop over the buffer */
- pos = 0;
- while (pos < buf_len) {
- /* get packet len */
- pkt_len = egalax_get_pkt_len(buffer + pos);
-
- /* unknown packet: drop everything */
- if (unlikely(!pkt_len))
- return;
-
- /* full packet: process */
- if (likely(pkt_len <= buf_len)) {
- usbtouch_process_pkt(usbtouch, regs, buffer + pos, pkt_len);
- } else {
- /* incomplete packet: save in buffer */
- memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
- usbtouch->buf_len = buf_len - pos;
- }
- pos += pkt_len;
- }
-}
#endif
@@ -254,7 +218,7 @@ static int mtouch_read_data(unsigned char *pkt, int *x, int *y, int *touch, int
static int mtouch_init(struct usbtouch_usb *usbtouch)
{
- int ret;
+ int ret, i;
ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
MTOUCHUSB_RESET,
@@ -264,15 +228,20 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
__FUNCTION__, ret);
if (ret < 0)
return ret;
-
- ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
- MTOUCHUSB_ASYNC_REPORT,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
- __FUNCTION__, ret);
- if (ret < 0)
- return ret;
+ msleep(150);
+
+ for (i = 0; i < 3; i++) {
+ ret = usb_control_msg(usbtouch->udev, usb_rcvctrlpipe(usbtouch->udev, 0),
+ MTOUCHUSB_ASYNC_REPORT,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
+ __FUNCTION__, ret);
+ if (ret >= 0)
+ break;
+ if (ret != -EPIPE)
+ return ret;
+ }
return 0;
}
@@ -287,15 +256,63 @@ static int itm_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *pr
{
*x = ((pkt[0] & 0x1F) << 7) | (pkt[3] & 0x7F);
*y = ((pkt[1] & 0x1F) << 7) | (pkt[4] & 0x7F);
- *press = ((pkt[2] & 0x1F) << 7) | (pkt[5] & 0x7F);
+ *press = ((pkt[2] & 0x01) << 7) | (pkt[5] & 0x7F);
*touch = ~pkt[7] & 0x20;
+ return *touch;
+}
+#endif
+
+
+/*****************************************************************************
+ * eTurboTouch part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
+static int eturbo_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+{
+ unsigned int shift;
+
+ /* packets should start with sync */
+ if (!(pkt[0] & 0x80))
+ return 0;
+
+ shift = (6 - (pkt[0] & 0x03));
+ *x = ((pkt[3] << 7) | pkt[4]) >> shift;
+ *y = ((pkt[1] << 7) | pkt[2]) >> shift;
+ *touch = (pkt[0] & 0x10) ? 1 : 0;
+
return 1;
}
+
+static int eturbo_get_pkt_len(unsigned char *buf, int len)
+{
+ if (buf[0] & 0x80)
+ return 5;
+ if (buf[0] == 0x01)
+ return 3;
+ return 0;
+}
#endif
/*****************************************************************************
+ * Gunze part
+ */
+#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
+static int gunze_read_data(unsigned char *pkt, int *x, int *y, int *touch, int *press)
+{
+ if (!(pkt[0] & 0x80) || ((pkt[1] | pkt[2] | pkt[3]) & 0x80))
+ return 0;
+
+ *x = ((pkt[0] & 0x1F) << 7) | (pkt[2] & 0x7F);
+ *y = ((pkt[1] & 0x1F) << 7) | (pkt[3] & 0x7F);
+ *touch = pkt[0] & 0x20;
+
+ return 1;
+}
+#endif
+
+/*****************************************************************************
* the different device descriptors
*/
static struct usbtouch_device_info usbtouch_dev_info[] = {
@@ -307,7 +324,8 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.max_yc = 0x07ff,
.rept_size = 16,
.flags = USBTOUCH_FLG_BUFFER,
- .process_pkt = egalax_process,
+ .process_pkt = usbtouch_process_multi,
+ .get_pkt_len = egalax_get_pkt_len,
.read_data = egalax_read_data,
},
#endif
@@ -346,6 +364,31 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
.read_data = itm_read_data,
},
#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_ETURBO
+ [DEVTYPE_ETURBO] = {
+ .min_xc = 0x0,
+ .max_xc = 0x07ff,
+ .min_yc = 0x0,
+ .max_yc = 0x07ff,
+ .rept_size = 8,
+ .flags = USBTOUCH_FLG_BUFFER,
+ .process_pkt = usbtouch_process_multi,
+ .get_pkt_len = eturbo_get_pkt_len,
+ .read_data = eturbo_read_data,
+ },
+#endif
+
+#ifdef CONFIG_USB_TOUCHSCREEN_GUNZE
+ [DEVTYPE_GUNZE] = {
+ .min_xc = 0x0,
+ .max_xc = 0x0fff,
+ .min_yc = 0x0,
+ .max_yc = 0x0fff,
+ .rept_size = 4,
+ .read_data = gunze_read_data,
+ },
+#endif
};
@@ -353,7 +396,7 @@ static struct usbtouch_device_info usbtouch_dev_info[] = {
* Generic Part
*/
static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
- struct pt_regs *regs, unsigned char *pkt, int len)
+ unsigned char *pkt, int len)
{
int x, y, touch, press;
struct usbtouch_device_info *type = usbtouch->type;
@@ -361,7 +404,6 @@ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
if (!type->read_data(pkt, &x, &y, &touch, &press))
return;
- input_regs(usbtouch->input, regs);
input_report_key(usbtouch->input, BTN_TOUCH, touch);
if (swap_xy) {
@@ -377,7 +419,83 @@ static void usbtouch_process_pkt(struct usbtouch_usb *usbtouch,
}
-static void usbtouch_irq(struct urb *urb, struct pt_regs *regs)
+#ifdef MULTI_PACKET
+static void usbtouch_process_multi(struct usbtouch_usb *usbtouch,
+ unsigned char *pkt, int len)
+{
+ unsigned char *buffer;
+ int pkt_len, pos, buf_len, tmp;
+
+ /* process buffer */
+ if (unlikely(usbtouch->buf_len)) {
+ /* try to get size */
+ pkt_len = usbtouch->type->get_pkt_len(
+ usbtouch->buffer, usbtouch->buf_len);
+
+ /* drop? */
+ if (unlikely(!pkt_len))
+ goto out_flush_buf;
+
+ /* need to append -pkt_len bytes before able to get size */
+ if (unlikely(pkt_len < 0)) {
+ int append = -pkt_len;
+ if (unlikely(append > len))
+ append = len;
+ if (usbtouch->buf_len + append >= usbtouch->type->rept_size)
+ goto out_flush_buf;
+ memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, append);
+ usbtouch->buf_len += append;
+
+ pkt_len = usbtouch->type->get_pkt_len(
+ usbtouch->buffer, usbtouch->buf_len);
+ if (pkt_len < 0)
+ return;
+ }
+
+ /* append */
+ tmp = pkt_len - usbtouch->buf_len;
+ if (usbtouch->buf_len + tmp >= usbtouch->type->rept_size)
+ goto out_flush_buf;
+ memcpy(usbtouch->buffer + usbtouch->buf_len, pkt, tmp);
+ usbtouch_process_pkt(usbtouch, usbtouch->buffer, pkt_len);
+
+ buffer = pkt + tmp;
+ buf_len = len - tmp;
+ } else {
+ buffer = pkt;
+ buf_len = len;
+ }
+
+ /* loop over the received packet, process */
+ pos = 0;
+ while (pos < buf_len) {
+ /* get packet len */
+ pkt_len = usbtouch->type->get_pkt_len(buffer + pos, len);
+
+ /* unknown packet: drop everything */
+ if (unlikely(!pkt_len))
+ goto out_flush_buf;
+
+ /* full packet: process */
+ if (likely((pkt_len > 0) && (pkt_len <= buf_len - pos))) {
+ usbtouch_process_pkt(usbtouch, buffer + pos, pkt_len);
+ } else {
+ /* incomplete packet: save in buffer */
+ memcpy(usbtouch->buffer, buffer + pos, buf_len - pos);
+ usbtouch->buf_len = buf_len - pos;
+ return;
+ }
+ pos += pkt_len;
+ }
+
+out_flush_buf:
+ usbtouch->buf_len = 0;
+ return;
+}
+#endif
+
+
+static void usbtouch_irq(struct urb *urb)
{
struct usbtouch_usb *usbtouch = urb->context;
int retval;
@@ -386,7 +504,7 @@ static void usbtouch_irq(struct urb *urb, struct pt_regs *regs)
case 0:
/* success */
break;
- case -ETIMEDOUT:
+ case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__FUNCTION__);
@@ -404,7 +522,7 @@ static void usbtouch_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- usbtouch->type->process_pkt(usbtouch, regs, usbtouch->data, urb->actual_length);
+ usbtouch->type->process_pkt(usbtouch, usbtouch->data, urb->actual_length);
exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -452,7 +570,7 @@ static int usbtouch_probe(struct usb_interface *intf,
struct usb_endpoint_descriptor *endpoint;
struct usb_device *udev = interface_to_usbdev(intf);
struct usbtouch_device_info *type;
- int err;
+ int err = -ENOMEM;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
@@ -526,6 +644,7 @@ static int usbtouch_probe(struct usb_interface *intf,
usbtouch->data, type->rept_size,
usbtouch_irq, usbtouch, endpoint->bInterval);
+ usbtouch->irq->dev = usbtouch->udev;
usbtouch->irq->transfer_dma = usbtouch->data_dma;
usbtouch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -553,7 +672,7 @@ out_free_buffers:
out_free:
input_free_device(input_dev);
kfree(usbtouch);
- return -ENOMEM;
+ return err;
}
static void usbtouch_disconnect(struct usb_interface *intf)
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
deleted file mode 100644
index 369461a70b72..000000000000
--- a/drivers/usb/input/wacom.c
+++ /dev/null
@@ -1,1003 +0,0 @@
-/*
- * USB Wacom Graphire and Wacom Intuos tablet support
- *
- * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz>
- * Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
- * Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
- * Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
- * Copyright (c) 2000 James E. Blair <corvus@gnu.org>
- * Copyright (c) 2000 Daniel Egger <egger@suse.de>
- * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
- * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
- * Copyright (c) 2002-2006 Ping Cheng <pingc@wacom.com>
- *
- * ChangeLog:
- * v0.1 (vp) - Initial release
- * v0.2 (aba) - Support for all buttons / combinations
- * v0.3 (vp) - Support for Intuos added
- * v0.4 (sm) - Support for more Intuos models, menustrip
- * relative mode, proximity.
- * v0.5 (vp) - Big cleanup, nifty features removed,
- * they belong in userspace
- * v1.8 (vp) - Submit URB only when operating, moved to CVS,
- * use input_report_key instead of report_btn and
- * other cleanups
- * v1.11 (vp) - Add URB ->dev setting for new kernels
- * v1.11 (jb) - Add support for the 4D Mouse & Lens
- * v1.12 (de) - Add support for two more inking pen IDs
- * v1.14 (vp) - Use new USB device id probing scheme.
- * Fix Wacom Graphire mouse wheel
- * v1.18 (vp) - Fix mouse wheel direction
- * Make mouse relative
- * v1.20 (fl) - Report tool id for Intuos devices
- * - Multi tools support
- * - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
- * - Add PL models support
- * - Fix Wacom Graphire mouse wheel again
- * v1.21 (vp) - Removed protocol descriptions
- * - Added MISC_SERIAL for tool serial numbers
- * (gb) - Identify version on module load.
- * v1.21.1 (fl) - added Graphire2 support
- * v1.21.2 (fl) - added Intuos2 support
- * - added all the PL ids
- * v1.21.3 (fl) - added another eraser id from Neil Okamoto
- * - added smooth filter for Graphire from Peri Hankey
- * - added PenPartner support from Olaf van Es
- * - new tool ids from Ole Martin Bjoerndalen
- * v1.29 (pc) - Add support for more tablets
- * - Fix pressure reporting
- * v1.30 (vp) - Merge 2.4 and 2.5 drivers
- * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
- * - Cleanups here and there
- * v1.30.1 (pi) - Added Graphire3 support
- * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
- * v1.43 (pc) - Added support for Cintiq 21UX
- * - Fixed a Graphire bug
- * - Merged wacom_intuos3_irq into wacom_intuos_irq
- * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
- * - Report Device IDs
- * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
- * - Minor data report fix
- */
-
-/*
- * 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/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <asm/unaligned.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.45"
-#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
-#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
-#define DRIVER_LICENSE "GPL"
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE(DRIVER_LICENSE);
-
-#define USB_VENDOR_ID_WACOM 0x056a
-#define STYLUS_DEVICE_ID 0x02
-#define CURSOR_DEVICE_ID 0x06
-#define ERASER_DEVICE_ID 0x0A
-
-enum {
- PENPARTNER = 0,
- GRAPHIRE,
- WACOM_G4,
- PL,
- INTUOS,
- INTUOS3,
- INTUOS312,
- INTUOS319,
- CINTIQ,
- MAX_TYPE
-};
-
-struct wacom_features {
- char *name;
- int pktlen;
- int x_max;
- int y_max;
- int pressure_max;
- int distance_max;
- int type;
- usb_complete_t irq;
-};
-
-struct wacom {
- signed char *data;
- dma_addr_t data_dma;
- struct input_dev *dev;
- struct usb_device *usbdev;
- struct urb *irq;
- struct wacom_features *features;
- int tool[2];
- int id[2];
- __u32 serial[2];
- char phys[32];
-};
-
-#define USB_REQ_GET_REPORT 0x01
-#define USB_REQ_SET_REPORT 0x09
-
-static int usb_get_report(struct usb_interface *intf, unsigned char type,
- unsigned char id, void *buf, int size)
-{
- return usb_control_msg(interface_to_usbdev(intf),
- usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
- USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
- buf, size, 100);
-}
-
-static int usb_set_report(struct usb_interface *intf, unsigned char type,
- unsigned char id, void *buf, int size)
-{
- return usb_control_msg(interface_to_usbdev(intf),
- usb_sndctrlpipe(interface_to_usbdev(intf), 0),
- USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
- buf, size, 1000);
-}
-
-static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int prox, pressure, id;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2) {
- dbg("wacom_pl_irq: received unknown report #%d", data[0]);
- goto exit;
- }
-
- prox = data[1] & 0x40;
-
- input_regs(dev, regs);
-
- id = ERASER_DEVICE_ID;
- if (prox) {
-
- pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
- if (wacom->features->pressure_max > 255)
- pressure = (pressure << 1) | ((data[4] >> 6) & 1);
- pressure += (wacom->features->pressure_max + 1) / 2;
-
- /*
- * if going from out of proximity into proximity select between the eraser
- * and the pen based on the state of the stylus2 button, choose eraser if
- * pressed else choose pen. if not a proximity change from out to in, send
- * an out of proximity for previous tool then a in for new tool.
- */
- if (!wacom->tool[0]) {
- /* Eraser bit set for DTF */
- if (data[1] & 0x10)
- wacom->tool[1] = BTN_TOOL_RUBBER;
- else
- /* Going into proximity select tool */
- wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
- } else {
- /* was entered with stylus2 pressed */
- if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
- /* report out proximity for previous tool */
- input_report_key(dev, wacom->tool[1], 0);
- input_sync(dev);
- wacom->tool[1] = BTN_TOOL_PEN;
- goto exit;
- }
- }
- if (wacom->tool[1] != BTN_TOOL_RUBBER) {
- /* Unknown tool selected default to pen tool */
- wacom->tool[1] = BTN_TOOL_PEN;
- id = STYLUS_DEVICE_ID;
- }
- input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
- input_report_abs(dev, ABS_MISC, id); /* report tool id */
- input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
- input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
- input_report_abs(dev, ABS_PRESSURE, pressure);
-
- input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
- input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
- /* Only allow the stylus2 button to be reported for the pen tool. */
- input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
- } else {
- /* report proximity-out of a (valid) tool */
- if (wacom->tool[1] != BTN_TOOL_RUBBER) {
- /* Unknown tool selected default to pen tool */
- wacom->tool[1] = BTN_TOOL_PEN;
- }
- input_report_key(dev, wacom->tool[1], prox);
- }
-
- wacom->tool[0] = prox; /* Save proximity state */
- input_sync(dev);
-
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int retval, id;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2) {
- printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
- if (data[1] & 0x04) {
- input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
- input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
- id = ERASER_DEVICE_ID;
- } else {
- input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
- input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
- id = STYLUS_DEVICE_ID;
- }
- input_report_abs(dev, ABS_MISC, id); /* report tool id */
- input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[2]));
- input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[4]));
- input_report_abs(dev, ABS_PRESSURE, le16_to_cpu(*(__le16 *) &data[6]));
- input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_key(dev, BTN_STYLUS2, data[1] & 0x10);
-
- input_sync(dev);
-
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2) {
- printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
- input_report_key(dev, BTN_TOOL_PEN, 1);
- input_report_abs(dev, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
- input_report_abs(dev, ABS_X, le16_to_cpu(*(__le16 *) &data[1]));
- input_report_abs(dev, ABS_Y, le16_to_cpu(*(__le16 *) &data[3]));
- input_report_abs(dev, ABS_PRESSURE, (signed char)data[6] + 127);
- input_report_key(dev, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
- input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
- input_sync(dev);
-
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int x, y, id, rw;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] == 99) return; /* for Volito tablets */
-
- if (data[0] != 2) {
- dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
-
- id = STYLUS_DEVICE_ID;
- if (data[1] & 0x10) { /* in prox */
-
- switch ((data[1] >> 5) & 3) {
-
- case 0: /* Pen */
- wacom->tool[0] = BTN_TOOL_PEN;
- break;
-
- case 1: /* Rubber */
- wacom->tool[0] = BTN_TOOL_RUBBER;
- id = ERASER_DEVICE_ID;
- break;
-
- case 2: /* Mouse with wheel */
- input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
- if (wacom->features->type == WACOM_G4) {
- rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
- input_report_rel(dev, REL_WHEEL, -rw);
- } else
- input_report_rel(dev, REL_WHEEL, -(signed char) data[6]);
- /* fall through */
-
- case 3: /* Mouse without wheel */
- wacom->tool[0] = BTN_TOOL_MOUSE;
- id = CURSOR_DEVICE_ID;
- input_report_key(dev, BTN_LEFT, data[1] & 0x01);
- input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
- if (wacom->features->type == WACOM_G4)
- input_report_abs(dev, ABS_DISTANCE, data[6]);
- else
- input_report_abs(dev, ABS_DISTANCE, data[7]);
- break;
- }
- }
-
- if (data[1] & 0x90) {
- x = le16_to_cpu(*(__le16 *) &data[2]);
- y = le16_to_cpu(*(__le16 *) &data[4]);
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
- if (wacom->tool[0] != BTN_TOOL_MOUSE) {
- input_report_abs(dev, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
- input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
- input_report_key(dev, BTN_STYLUS, data[1] & 0x02);
- input_report_key(dev, BTN_STYLUS2, data[1] & 0x04);
- }
- }
-
- if (data[1] & 0x10)
- input_report_abs(dev, ABS_MISC, id); /* report tool id */
- else
- input_report_abs(dev, ABS_MISC, 0); /* reset tool id */
- input_report_key(dev, wacom->tool[0], data[1] & 0x10);
- input_sync(dev);
-
- /* send pad data */
- if (wacom->features->type == WACOM_G4) {
- if ((wacom->serial[1] & 0xc0) != (data[7] & 0xf8)) {
- wacom->id[1] = 1;
- wacom->serial[1] = (data[7] & 0xf8);
- input_report_key(dev, BTN_0, (data[7] & 0x40));
- input_report_key(dev, BTN_4, (data[7] & 0x80));
- rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
- input_report_rel(dev, REL_WHEEL, rw);
- input_report_key(dev, BTN_TOOL_FINGER, 0xf0);
- input_event(dev, EV_MSC, MSC_SERIAL, 0xf0);
- } else if (wacom->id[1]) {
- wacom->id[1] = 0;
- input_report_key(dev, BTN_TOOL_FINGER, 0);
- input_event(dev, EV_MSC, MSC_SERIAL, 0xf0);
- }
- input_sync(dev);
- }
- exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static int wacom_intuos_inout(struct urb *urb)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- int idx;
-
- /* tool number */
- idx = data[1] & 0x01;
-
- /* Enter report */
- if ((data[1] & 0xfc) == 0xc0) {
- /* serial number of the tool */
- wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
- (data[4] << 20) + (data[5] << 12) +
- (data[6] << 4) + (data[7] >> 4);
-
- wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
- switch (wacom->id[idx]) {
- case 0x812: /* Inking pen */
- case 0x801: /* Intuos3 Inking pen */
- case 0x012:
- wacom->tool[idx] = BTN_TOOL_PENCIL;
- break;
- case 0x822: /* Pen */
- case 0x842:
- case 0x852:
- case 0x823: /* Intuos3 Grip Pen */
- case 0x813: /* Intuos3 Classic Pen */
- case 0x885: /* Intuos3 Marker Pen */
- case 0x022:
- wacom->tool[idx] = BTN_TOOL_PEN;
- break;
- case 0x832: /* Stroke pen */
- case 0x032:
- wacom->tool[idx] = BTN_TOOL_BRUSH;
- break;
- case 0x007: /* Mouse 4D and 2D */
- case 0x09c:
- case 0x094:
- case 0x017: /* Intuos3 2D Mouse */
- wacom->tool[idx] = BTN_TOOL_MOUSE;
- break;
- case 0x096: /* Lens cursor */
- case 0x097: /* Intuos3 Lens cursor */
- wacom->tool[idx] = BTN_TOOL_LENS;
- break;
- case 0x82a: /* Eraser */
- case 0x85a:
- case 0x91a:
- case 0xd1a:
- case 0x0fa:
- case 0x82b: /* Intuos3 Grip Pen Eraser */
- case 0x81b: /* Intuos3 Classic Pen Eraser */
- case 0x91b: /* Intuos3 Airbrush Eraser */
- wacom->tool[idx] = BTN_TOOL_RUBBER;
- break;
- case 0xd12:
- case 0x912:
- case 0x112:
- case 0x913: /* Intuos3 Airbrush */
- wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
- break;
- default: /* Unknown tool */
- wacom->tool[idx] = BTN_TOOL_PEN;
- }
- if(!((wacom->tool[idx] == BTN_TOOL_LENS) &&
- ((wacom->features->type == INTUOS312)
- || (wacom->features->type == INTUOS319)))) {
- input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */
- input_report_key(dev, wacom->tool[idx], 1);
- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- input_sync(dev);
- }
- return 1;
- }
-
- /* Exit report */
- if ((data[1] & 0xfe) == 0x80) {
- input_report_key(dev, wacom->tool[idx], 0);
- input_report_abs(dev, ABS_MISC, 0); /* reset tool id */
- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- input_sync(dev);
- return 1;
- }
-
- if((wacom->tool[idx] == BTN_TOOL_LENS) && ((wacom->features->type == INTUOS312)
- || (wacom->features->type == INTUOS319)))
- return 1;
- else
- return 0;
-}
-
-static void wacom_intuos_general(struct urb *urb)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- unsigned int t;
-
- /* general pen packet */
- if ((data[1] & 0xb8) == 0xa0) {
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- input_report_abs(dev, ABS_PRESSURE, t);
- input_report_abs(dev, ABS_TILT_X,
- ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
- input_report_key(dev, BTN_STYLUS, data[1] & 2);
- input_report_key(dev, BTN_STYLUS2, data[1] & 4);
- input_report_key(dev, BTN_TOUCH, t > 10);
- }
-
- /* airbrush second packet */
- if ((data[1] & 0xbc) == 0xb4) {
- input_report_abs(dev, ABS_WHEEL,
- (data[6] << 2) | ((data[7] >> 6) & 3));
- input_report_abs(dev, ABS_TILT_X,
- ((data[7] << 1) & 0x7e) | (data[8] >> 7));
- input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
- }
- return;
-}
-
-static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = wacom->dev;
- unsigned int t;
- int idx;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
- dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
-
- /* tool number */
- idx = data[1] & 0x01;
-
- /* pad packets. Works as a second tool and is always in prox */
- if (data[0] == 12) {
- /* initiate the pad as a device */
- if (wacom->tool[1] != BTN_TOOL_FINGER)
- wacom->tool[1] = BTN_TOOL_FINGER;
-
- input_report_key(dev, BTN_0, (data[5] & 0x01));
- input_report_key(dev, BTN_1, (data[5] & 0x02));
- input_report_key(dev, BTN_2, (data[5] & 0x04));
- input_report_key(dev, BTN_3, (data[5] & 0x08));
- input_report_key(dev, BTN_4, (data[6] & 0x01));
- input_report_key(dev, BTN_5, (data[6] & 0x02));
- input_report_key(dev, BTN_6, (data[6] & 0x04));
- input_report_key(dev, BTN_7, (data[6] & 0x08));
- input_report_abs(dev, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
- input_report_abs(dev, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
-
- if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) | data[2])
- input_report_key(dev, wacom->tool[1], 1);
- else
- input_report_key(dev, wacom->tool[1], 0);
- input_event(dev, EV_MSC, MSC_SERIAL, 0xffffffff);
- input_sync(dev);
- goto exit;
- }
-
- /* process in/out prox events */
- if (wacom_intuos_inout(urb))
- goto exit;
-
- /* Cintiq doesn't send data when RDY bit isn't set */
- if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
- goto exit;
-
- if (wacom->features->type >= INTUOS3) {
- input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
- input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
- input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
- } else {
- input_report_abs(dev, ABS_X, be16_to_cpu(*(__be16 *) &data[2]));
- input_report_abs(dev, ABS_Y, be16_to_cpu(*(__be16 *) &data[4]));
- input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
- }
-
- /* process general packets */
- wacom_intuos_general(urb);
-
- /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
- if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
-
- if (data[1] & 0x02) {
- /* Rotation packet */
- if (wacom->features->type >= INTUOS3) {
- /* I3 marker pen rotation reported as wheel
- * due to valuator limitation
- */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
- ((t-1) / 2 + 450)) : (450 - t / 2) ;
- input_report_abs(dev, ABS_WHEEL, t);
- } else {
- /* 4D mouse rotation packet */
- t = (data[6] << 3) | ((data[7] >> 5) & 7);
- input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
- ((t - 1) / 2) : -t / 2);
- }
-
- } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
- /* 4D mouse packet */
- input_report_key(dev, BTN_LEFT, data[8] & 0x01);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
-
- input_report_key(dev, BTN_SIDE, data[8] & 0x20);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
- t = (data[6] << 2) | ((data[7] >> 6) & 3);
- input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
- } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
- /* 2D mouse packet */
- input_report_key(dev, BTN_LEFT, data[8] & 0x04);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x10);
- input_report_rel(dev, REL_WHEEL, (data[8] & 0x01)
- - ((data[8] & 0x02) >> 1));
-
- /* I3 2D mouse side buttons */
- if (wacom->features->type == INTUOS3) {
- input_report_key(dev, BTN_SIDE, data[8] & 0x40);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x20);
- }
-
- } else if (wacom->features->type < INTUOS3) {
- /* Lens cursor packets */
- input_report_key(dev, BTN_LEFT, data[8] & 0x01);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
- input_report_key(dev, BTN_SIDE, data[8] & 0x10);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x08);
- }
- }
-
- input_report_abs(dev, ABS_MISC, wacom->id[idx]); /* report tool id */
- input_report_key(dev, wacom->tool[idx], 1);
- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- input_sync(dev);
-
-exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static struct wacom_features wacom_features[] = {
- { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_penpartner_irq },
- { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 32, WACOM_G4, wacom_graphire_irq },
- { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 32, WACOM_G4, wacom_graphire_irq },
- { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom PenStation2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom PenPartner2", 8, 3250, 2320, 255, 32, GRAPHIRE, wacom_graphire_irq },
- { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_pl_irq },
- { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_pl_irq },
- { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq },
- { "Wacom PL700", 8, 6758, 5406, 511, 32, PL, wacom_pl_irq },
- { "Wacom PL510", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq },
- { "Wacom DTU710", 8, 34080, 27660, 511, 32, PL, wacom_pl_irq },
- { "Wacom DTF521", 8, 6282, 4762, 511, 32, PL, wacom_pl_irq },
- { "Wacom DTF720", 8, 6858, 5506, 511, 32, PL, wacom_pl_irq },
- { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_irq },
- { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
- { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 15, INTUOS312, wacom_intuos_irq },
- { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 15, INTUOS319, wacom_intuos_irq },
- { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 15, INTUOS3, wacom_intuos_irq },
- { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_intuos_irq },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
- { }
-};
-
-static struct usb_device_id wacom_ids[] = {
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC3) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
- { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, wacom_ids);
-
-static int wacom_open(struct input_dev *dev)
-{
- struct wacom *wacom = dev->private;
-
- wacom->irq->dev = wacom->usbdev;
- if (usb_submit_urb(wacom->irq, GFP_KERNEL))
- return -EIO;
-
- return 0;
-}
-
-static void wacom_close(struct input_dev *dev)
-{
- struct wacom *wacom = dev->private;
-
- usb_kill_urb(wacom->irq);
-}
-
-static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_endpoint_descriptor *endpoint;
- struct wacom *wacom;
- struct input_dev *input_dev;
- char rep_data[2], limit = 0;
-
- wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!wacom || !input_dev)
- goto fail1;
-
- wacom->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
- if (!wacom->data)
- goto fail1;
-
- wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!wacom->irq)
- goto fail2;
-
- wacom->usbdev = dev;
- wacom->dev = input_dev;
- usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
- strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
-
- wacom->features = wacom_features + (id - wacom_ids);
- if (wacom->features->pktlen > 10)
- BUG();
-
- input_dev->name = wacom->features->name;
- usb_to_input_id(dev, &input_dev->id);
-
- input_dev->cdev.dev = &intf->dev;
- input_dev->private = wacom;
- input_dev->open = wacom_open;
- input_dev->close = wacom_close;
-
- input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
- input_set_abs_params(input_dev, ABS_X, 0, wacom->features->x_max, 4, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, wacom->features->y_max, 4, 0);
- input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom->features->pressure_max, 0, 0);
- input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
-
- switch (wacom->features->type) {
- case WACOM_G4:
- input_dev->evbit[0] |= BIT(EV_MSC);
- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
- /* fall through */
-
- case GRAPHIRE:
- input_dev->evbit[0] |= BIT(EV_REL);
- input_dev->relbit[0] |= BIT(REL_WHEEL);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0);
- break;
-
- case INTUOS3:
- case INTUOS312:
- case INTUOS319:
- case CINTIQ:
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
- input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
- input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
- /* fall through */
-
- case INTUOS:
- input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
- input_dev->mscbit[0] |= BIT(MSC_SERIAL);
- input_dev->relbit[0] |= BIT(REL_WHEEL);
- input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
- | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
- input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom->features->distance_max, 0, 0);
- input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
- input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
- input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
- input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
- break;
-
- case PL:
- input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
- break;
- }
-
- endpoint = &intf->cur_altsetting->endpoint[0].desc;
-
- if (wacom->features->pktlen > 10)
- BUG();
-
- usb_fill_int_urb(wacom->irq, dev,
- usb_rcvintpipe(dev, endpoint->bEndpointAddress),
- wacom->data, wacom->features->pktlen,
- wacom->features->irq, wacom, endpoint->bInterval);
- wacom->irq->transfer_dma = wacom->data_dma;
- wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
- input_register_device(wacom->dev);
-
- /* Ask the tablet to report tablet data. Repeat until it succeeds */
- do {
- rep_data[0] = 2;
- rep_data[1] = 2;
- usb_set_report(intf, 3, 2, rep_data, 2);
- usb_get_report(intf, 3, 2, rep_data, 2);
- } while (rep_data[1] != 2 && limit++ < 5);
-
- usb_set_intfdata(intf, wacom);
- return 0;
-
-fail2: usb_buffer_free(dev, 10, wacom->data, wacom->data_dma);
-fail1: input_free_device(input_dev);
- kfree(wacom);
- return -ENOMEM;
-}
-
-static void wacom_disconnect(struct usb_interface *intf)
-{
- struct wacom *wacom = usb_get_intfdata (intf);
-
- usb_set_intfdata(intf, NULL);
- if (wacom) {
- usb_kill_urb(wacom->irq);
- input_unregister_device(wacom->dev);
- usb_free_urb(wacom->irq);
- usb_buffer_free(interface_to_usbdev(intf), 10, wacom->data, wacom->data_dma);
- kfree(wacom);
- }
-}
-
-static struct usb_driver wacom_driver = {
- .name = "wacom",
- .probe = wacom_probe,
- .disconnect = wacom_disconnect,
- .id_table = wacom_ids,
-};
-
-static int __init wacom_init(void)
-{
- int result = usb_register(&wacom_driver);
- if (result == 0)
- info(DRIVER_VERSION ":" DRIVER_DESC);
- return result;
-}
-
-static void __exit wacom_exit(void)
-{
- usb_deregister(&wacom_driver);
-}
-
-module_init(wacom_init);
-module_exit(wacom_exit);
diff --git a/drivers/usb/input/wacom.h b/drivers/usb/input/wacom.h
new file mode 100644
index 000000000000..1cf08f02c50e
--- /dev/null
+++ b/drivers/usb/input/wacom.h
@@ -0,0 +1,132 @@
+/*
+ * drivers/usb/input/wacom.h
+ *
+ * USB Wacom Graphire and Wacom Intuos tablet support
+ *
+ * Copyright (c) 2000-2004 Vojtech Pavlik <vojtech@ucw.cz>
+ * Copyright (c) 2000 Andreas Bach Aaen <abach@stofanet.dk>
+ * Copyright (c) 2000 Clifford Wolf <clifford@clifford.at>
+ * Copyright (c) 2000 Sam Mosel <sam.mosel@computer.org>
+ * Copyright (c) 2000 James E. Blair <corvus@gnu.org>
+ * Copyright (c) 2000 Daniel Egger <egger@suse.de>
+ * Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
+ * Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
+ * Copyright (c) 2002-2006 Ping Cheng <pingc@wacom.com>
+ *
+ * ChangeLog:
+ * v0.1 (vp) - Initial release
+ * v0.2 (aba) - Support for all buttons / combinations
+ * v0.3 (vp) - Support for Intuos added
+ * v0.4 (sm) - Support for more Intuos models, menustrip
+ * relative mode, proximity.
+ * v0.5 (vp) - Big cleanup, nifty features removed,
+ * they belong in userspace
+ * v1.8 (vp) - Submit URB only when operating, moved to CVS,
+ * use input_report_key instead of report_btn and
+ * other cleanups
+ * v1.11 (vp) - Add URB ->dev setting for new kernels
+ * v1.11 (jb) - Add support for the 4D Mouse & Lens
+ * v1.12 (de) - Add support for two more inking pen IDs
+ * v1.14 (vp) - Use new USB device id probing scheme.
+ * Fix Wacom Graphire mouse wheel
+ * v1.18 (vp) - Fix mouse wheel direction
+ * Make mouse relative
+ * v1.20 (fl) - Report tool id for Intuos devices
+ * - Multi tools support
+ * - Corrected Intuos protocol decoding (airbrush, 4D mouse, lens cursor...)
+ * - Add PL models support
+ * - Fix Wacom Graphire mouse wheel again
+ * v1.21 (vp) - Removed protocol descriptions
+ * - Added MISC_SERIAL for tool serial numbers
+ * (gb) - Identify version on module load.
+ * v1.21.1 (fl) - added Graphire2 support
+ * v1.21.2 (fl) - added Intuos2 support
+ * - added all the PL ids
+ * v1.21.3 (fl) - added another eraser id from Neil Okamoto
+ * - added smooth filter for Graphire from Peri Hankey
+ * - added PenPartner support from Olaf van Es
+ * - new tool ids from Ole Martin Bjoerndalen
+ * v1.29 (pc) - Add support for more tablets
+ * - Fix pressure reporting
+ * v1.30 (vp) - Merge 2.4 and 2.5 drivers
+ * - Since 2.5 now has input_sync(), remove MSC_SERIAL abuse
+ * - Cleanups here and there
+ * v1.30.1 (pi) - Added Graphire3 support
+ * v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
+ * v1.43 (pc) - Added support for Cintiq 21UX
+ * - Fixed a Graphire bug
+ * - Merged wacom_intuos3_irq into wacom_intuos_irq
+ * v1.44 (pc) - Added support for Graphire4, Cintiq 710, Intuos3 6x11, etc.
+ * - Report Device IDs
+ * v1.45 (pc) - Added support for DTF 521, Intuos3 12x12 and 12x19
+ * - Minor data report fix
+ * v1.46 (pc) - Split wacom.c into wacom_sys.c and wacom_wac.c,
+ * - where wacom_sys.c deals with system specific code,
+ * - and wacom_wac.c deals with Wacom specific code
+ * - Support Intuos3 4x6
+ */
+
+/*
+ * 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.
+ */
+#ifndef WACOM_H
+#define WACOM_H
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb/input.h>
+#include <asm/unaligned.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.46"
+#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
+#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_WACOM 0x056a
+
+struct wacom {
+ dma_addr_t data_dma;
+ struct input_dev *dev;
+ struct usb_device *usbdev;
+ struct urb *irq;
+ struct wacom_wac * wacom_wac;
+ char phys[32];
+};
+
+struct wacom_combo {
+ struct wacom * wacom;
+ struct urb * urb;
+};
+
+extern int wacom_wac_irq(struct wacom_wac * wacom_wac, void * wcombo);
+extern void wacom_sys_irq(struct urb *urb);
+extern void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data);
+extern void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data);
+extern void wacom_report_key(void *wcombo, unsigned int key_type, int key_data);
+extern void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value);
+extern void wacom_input_sync(void *wcombo);
+extern void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac);
+extern __u16 wacom_le16_to_cpu(unsigned char *data);
+extern __u16 wacom_be16_to_cpu(unsigned char *data);
+extern struct wacom_features * get_wacom_feature(const struct usb_device_id *id);
+extern const struct usb_device_id * get_device_table(void);
+
+#endif
diff --git a/drivers/usb/input/wacom_sys.c b/drivers/usb/input/wacom_sys.c
new file mode 100644
index 000000000000..3498b893b53b
--- /dev/null
+++ b/drivers/usb/input/wacom_sys.c
@@ -0,0 +1,312 @@
+/*
+ * drivers/usb/input/wacom_sys.c
+ *
+ * USB Wacom Graphire and Wacom Intuos tablet support - system specific code
+ */
+
+/*
+ * 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 "wacom.h"
+#include "wacom_wac.h"
+
+#define USB_REQ_GET_REPORT 0x01
+#define USB_REQ_SET_REPORT 0x09
+
+static int usb_get_report(struct usb_interface *intf, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(interface_to_usbdev(intf),
+ usb_rcvctrlpipe(interface_to_usbdev(intf), 0),
+ USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
+ buf, size, 100);
+}
+
+static int usb_set_report(struct usb_interface *intf, unsigned char type,
+ unsigned char id, void *buf, int size)
+{
+ return usb_control_msg(interface_to_usbdev(intf),
+ usb_sndctrlpipe(interface_to_usbdev(intf), 0),
+ USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ (type << 8) + id, intf->altsetting[0].desc.bInterfaceNumber,
+ buf, size, 1000);
+}
+
+static struct input_dev * get_input_dev(struct wacom_combo *wcombo)
+{
+ return wcombo->wacom->dev;
+}
+
+void wacom_sys_irq(struct urb *urb)
+{
+ struct wacom *wacom = urb->context;
+ struct wacom_combo wcombo;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ goto exit;
+ }
+
+ wcombo.wacom = wacom;
+ wcombo.urb = urb;
+
+ if (wacom_wac_irq(wacom->wacom_wac, (void *)&wcombo))
+ input_sync(get_input_dev(&wcombo));
+
+ exit:
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ err ("%s - usb_submit_urb failed with result %d",
+ __FUNCTION__, retval);
+}
+
+void wacom_report_key(void *wcombo, unsigned int key_type, int key_data)
+{
+ input_report_key(get_input_dev((struct wacom_combo *)wcombo), key_type, key_data);
+ return;
+}
+
+void wacom_report_abs(void *wcombo, unsigned int abs_type, int abs_data)
+{
+ input_report_abs(get_input_dev((struct wacom_combo *)wcombo), abs_type, abs_data);
+ return;
+}
+
+void wacom_report_rel(void *wcombo, unsigned int rel_type, int rel_data)
+{
+ input_report_rel(get_input_dev((struct wacom_combo *)wcombo), rel_type, rel_data);
+ return;
+}
+
+void wacom_input_event(void *wcombo, unsigned int type, unsigned int code, int value)
+{
+ input_event(get_input_dev((struct wacom_combo *)wcombo), type, code, value);
+ return;
+}
+
+__u16 wacom_be16_to_cpu(unsigned char *data)
+{
+ __u16 value;
+ value = be16_to_cpu(*(__be16 *) data);
+ return value;
+}
+
+__u16 wacom_le16_to_cpu(unsigned char *data)
+{
+ __u16 value;
+ value = le16_to_cpu(*(__le16 *) data);
+ return value;
+}
+
+void wacom_input_sync(void *wcombo)
+{
+ input_sync(get_input_dev((struct wacom_combo *)wcombo));
+ return;
+}
+
+static int wacom_open(struct input_dev *dev)
+{
+ struct wacom *wacom = dev->private;
+
+ wacom->irq->dev = wacom->usbdev;
+ if (usb_submit_urb(wacom->irq, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void wacom_close(struct input_dev *dev)
+{
+ struct wacom *wacom = dev->private;
+
+ usb_kill_urb(wacom->irq);
+}
+
+void input_dev_g4(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->evbit[0] |= BIT(EV_MSC);
+ input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_4);
+}
+
+void input_dev_g(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->evbit[0] |= BIT(EV_REL);
+ input_dev->relbit[0] |= BIT(REL_WHEEL);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+ input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+}
+
+void input_dev_i3s(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3);
+ input_set_abs_params(input_dev, ABS_RX, 0, 4097, 0, 0);
+}
+
+void input_dev_i3(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
+ input_set_abs_params(input_dev, ABS_RY, 0, 4097, 0, 0);
+}
+
+void input_dev_i(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
+ input_dev->mscbit[0] |= BIT(MSC_SERIAL);
+ input_dev->relbit[0] |= BIT(REL_WHEEL);
+ input_dev->keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
+ | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
+ input_set_abs_params(input_dev, ABS_DISTANCE, 0, wacom_wac->features->distance_max, 0, 0);
+ input_set_abs_params(input_dev, ABS_WHEEL, 0, 1023, 0, 0);
+ input_set_abs_params(input_dev, ABS_TILT_X, 0, 127, 0, 0);
+ input_set_abs_params(input_dev, ABS_TILT_Y, 0, 127, 0, 0);
+ input_set_abs_params(input_dev, ABS_RZ, -900, 899, 0, 0);
+ input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0);
+}
+
+void input_dev_pl(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+}
+
+void input_dev_pt(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER);
+}
+
+static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_endpoint_descriptor *endpoint;
+ struct wacom *wacom;
+ struct wacom_wac *wacom_wac;
+ struct input_dev *input_dev;
+ char rep_data[2], limit = 0;
+
+ wacom = kzalloc(sizeof(struct wacom), GFP_KERNEL);
+ wacom_wac = kzalloc(sizeof(struct wacom_wac), GFP_KERNEL);
+ input_dev = input_allocate_device();
+ if (!wacom || !input_dev || !wacom_wac)
+ goto fail1;
+
+ wacom_wac->data = usb_buffer_alloc(dev, 10, GFP_KERNEL, &wacom->data_dma);
+ if (!wacom_wac->data)
+ goto fail1;
+
+ wacom->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!wacom->irq)
+ goto fail2;
+
+ wacom->usbdev = dev;
+ wacom->dev = input_dev;
+ usb_make_path(dev, wacom->phys, sizeof(wacom->phys));
+ strlcat(wacom->phys, "/input0", sizeof(wacom->phys));
+
+ wacom_wac->features = get_wacom_feature(id);
+ BUG_ON(wacom_wac->features->pktlen > 10);
+
+ input_dev->name = wacom_wac->features->name;
+ wacom->wacom_wac = wacom_wac;
+ usb_to_input_id(dev, &input_dev->id);
+
+ input_dev->cdev.dev = &intf->dev;
+ input_dev->private = wacom;
+ input_dev->open = wacom_open;
+ input_dev->close = wacom_close;
+
+ input_dev->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS);
+ input_dev->keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
+ input_set_abs_params(input_dev, ABS_X, 0, wacom_wac->features->x_max, 4, 0);
+ input_set_abs_params(input_dev, ABS_Y, 0, wacom_wac->features->y_max, 4, 0);
+ input_set_abs_params(input_dev, ABS_PRESSURE, 0, wacom_wac->features->pressure_max, 0, 0);
+ input_dev->absbit[LONG(ABS_MISC)] |= BIT(ABS_MISC);
+
+ wacom_init_input_dev(input_dev, wacom_wac);
+
+ endpoint = &intf->cur_altsetting->endpoint[0].desc;
+
+ usb_fill_int_urb(wacom->irq, dev,
+ usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+ wacom_wac->data, wacom_wac->features->pktlen,
+ wacom_sys_irq, wacom, endpoint->bInterval);
+ wacom->irq->transfer_dma = wacom->data_dma;
+ wacom->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ input_register_device(wacom->dev);
+
+ /* Ask the tablet to report tablet data. Repeat until it succeeds */
+ do {
+ rep_data[0] = 2;
+ rep_data[1] = 2;
+ usb_set_report(intf, 3, 2, rep_data, 2);
+ usb_get_report(intf, 3, 2, rep_data, 2);
+ } while (rep_data[1] != 2 && limit++ < 5);
+
+ usb_set_intfdata(intf, wacom);
+ return 0;
+
+fail2: usb_buffer_free(dev, 10, wacom_wac->data, wacom->data_dma);
+fail1: input_free_device(input_dev);
+ kfree(wacom);
+ kfree(wacom_wac);
+ return -ENOMEM;
+}
+
+static void wacom_disconnect(struct usb_interface *intf)
+{
+ struct wacom *wacom = usb_get_intfdata (intf);
+
+ usb_set_intfdata(intf, NULL);
+ if (wacom) {
+ usb_kill_urb(wacom->irq);
+ input_unregister_device(wacom->dev);
+ usb_free_urb(wacom->irq);
+ usb_buffer_free(interface_to_usbdev(intf), 10, wacom->wacom_wac->data, wacom->data_dma);
+ kfree(wacom->wacom_wac);
+ kfree(wacom);
+ }
+}
+
+static struct usb_driver wacom_driver = {
+ .name = "wacom",
+ .probe = wacom_probe,
+ .disconnect = wacom_disconnect,
+};
+
+static int __init wacom_init(void)
+{
+ int result;
+ wacom_driver.id_table = get_device_table();
+ result = usb_register(&wacom_driver);
+ if (result == 0)
+ info(DRIVER_VERSION ":" DRIVER_DESC);
+ return result;
+}
+
+static void __exit wacom_exit(void)
+{
+ usb_deregister(&wacom_driver);
+}
+
+module_init(wacom_init);
+module_exit(wacom_exit);
diff --git a/drivers/usb/input/wacom_wac.c b/drivers/usb/input/wacom_wac.c
new file mode 100644
index 000000000000..92726fe89379
--- /dev/null
+++ b/drivers/usb/input/wacom_wac.c
@@ -0,0 +1,648 @@
+/*
+ * drivers/usb/input/wacom_wac.c
+ *
+ * USB Wacom Graphire and Wacom Intuos tablet support - Wacom specific code
+ *
+ */
+
+/*
+ * 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 "wacom.h"
+#include "wacom_wac.h"
+
+static int wacom_penpartner_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+
+ switch (data[0]) {
+ case 1:
+ if (data[5] & 0x80) {
+ wacom->tool[0] = (data[5] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ wacom->id[0] = (data[5] & 0x20) ? ERASER_DEVICE_ID : STYLUS_DEVICE_ID;
+ wacom_report_key(wcombo, wacom->tool[0], 1);
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[0]); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
+ wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
+ wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -127));
+ wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
+ } else {
+ wacom_report_key(wcombo, wacom->tool[0], 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* report tool id */
+ wacom_report_abs(wcombo, ABS_PRESSURE, -1);
+ wacom_report_key(wcombo, BTN_TOUCH, 0);
+ }
+ break;
+ case 2:
+ wacom_report_key(wcombo, BTN_TOOL_PEN, 1);
+ wacom_report_abs(wcombo, ABS_MISC, STYLUS_DEVICE_ID); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[1]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[3]));
+ wacom_report_abs(wcombo, ABS_PRESSURE, (signed char)data[6] + 127);
+ wacom_report_key(wcombo, BTN_TOUCH, ((signed char)data[6] > -80) && !(data[5] & 0x20));
+ wacom_report_key(wcombo, BTN_STYLUS, (data[5] & 0x40));
+ break;
+ default:
+ printk(KERN_INFO "wacom_penpartner_irq: received unknown report #%d\n", data[0]);
+ return 0;
+ }
+ return 1;
+}
+
+static int wacom_pl_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int prox, id, pressure;
+
+ if (data[0] != 2) {
+ dbg("wacom_pl_irq: received unknown report #%d", data[0]);
+ return 0;
+ }
+
+ prox = data[1] & 0x40;
+
+ id = ERASER_DEVICE_ID;
+ if (prox) {
+
+ pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
+ if (wacom->features->pressure_max > 255)
+ pressure = (pressure << 1) | ((data[4] >> 6) & 1);
+ pressure += (wacom->features->pressure_max + 1) / 2;
+
+ /*
+ * if going from out of proximity into proximity select between the eraser
+ * and the pen based on the state of the stylus2 button, choose eraser if
+ * pressed else choose pen. if not a proximity change from out to in, send
+ * an out of proximity for previous tool then a in for new tool.
+ */
+ if (!wacom->tool[0]) {
+ /* Eraser bit set for DTF */
+ if (data[1] & 0x10)
+ wacom->tool[1] = BTN_TOOL_RUBBER;
+ else
+ /* Going into proximity select tool */
+ wacom->tool[1] = (data[4] & 0x20) ? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
+ } else {
+ /* was entered with stylus2 pressed */
+ if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20)) {
+ /* report out proximity for previous tool */
+ wacom_report_key(wcombo, wacom->tool[1], 0);
+ wacom_input_sync(wcombo);
+ wacom->tool[1] = BTN_TOOL_PEN;
+ return 0;
+ }
+ }
+ if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+ /* Unknown tool selected default to pen tool */
+ wacom->tool[1] = BTN_TOOL_PEN;
+ id = STYLUS_DEVICE_ID;
+ }
+ wacom_report_key(wcombo, wacom->tool[1], prox); /* report in proximity for tool */
+ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+ wacom_report_abs(wcombo, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
+ wacom_report_abs(wcombo, ABS_PRESSURE, pressure);
+
+ wacom_report_key(wcombo, BTN_TOUCH, data[4] & 0x08);
+ wacom_report_key(wcombo, BTN_STYLUS, data[4] & 0x10);
+ /* Only allow the stylus2 button to be reported for the pen tool. */
+ wacom_report_key(wcombo, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
+ } else {
+ /* report proximity-out of a (valid) tool */
+ if (wacom->tool[1] != BTN_TOOL_RUBBER) {
+ /* Unknown tool selected default to pen tool */
+ wacom->tool[1] = BTN_TOOL_PEN;
+ }
+ wacom_report_key(wcombo, wacom->tool[1], prox);
+ }
+
+ wacom->tool[0] = prox; /* Save proximity state */
+ return 1;
+}
+
+static int wacom_ptu_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int id;
+
+ if (data[0] != 2) {
+ printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
+ return 0;
+ }
+
+ if (data[1] & 0x04) {
+ wacom_report_key(wcombo, BTN_TOOL_RUBBER, data[1] & 0x20);
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x08);
+ id = ERASER_DEVICE_ID;
+ } else {
+ wacom_report_key(wcombo, BTN_TOOL_PEN, data[1] & 0x20);
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
+ id = STYLUS_DEVICE_ID;
+ }
+ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+ wacom_report_abs(wcombo, ABS_X, wacom_le16_to_cpu(&data[2]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_le16_to_cpu(&data[4]));
+ wacom_report_abs(wcombo, ABS_PRESSURE, wacom_le16_to_cpu(&data[6]));
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x10);
+ return 1;
+}
+
+static int wacom_graphire_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int x, y, id, rw;
+
+ if (data[0] != 2) {
+ dbg("wacom_graphire_irq: received unknown report #%d", data[0]);
+ return 0;
+ }
+
+ id = STYLUS_DEVICE_ID;
+ if (data[1] & 0x10) { /* in prox */
+
+ switch ((data[1] >> 5) & 3) {
+
+ case 0: /* Pen */
+ wacom->tool[0] = BTN_TOOL_PEN;
+ break;
+
+ case 1: /* Rubber */
+ wacom->tool[0] = BTN_TOOL_RUBBER;
+ id = ERASER_DEVICE_ID;
+ break;
+
+ case 2: /* Mouse with wheel */
+ wacom_report_key(wcombo, BTN_MIDDLE, data[1] & 0x04);
+ if (wacom->features->type == WACOM_G4) {
+ rw = data[7] & 0x04 ? (data[7] & 0x03)-4 : (data[7] & 0x03);
+ wacom_report_rel(wcombo, REL_WHEEL, -rw);
+ } else
+ wacom_report_rel(wcombo, REL_WHEEL, -(signed char) data[6]);
+ /* fall through */
+
+ case 3: /* Mouse without wheel */
+ wacom->tool[0] = BTN_TOOL_MOUSE;
+ id = CURSOR_DEVICE_ID;
+ wacom_report_key(wcombo, BTN_LEFT, data[1] & 0x01);
+ wacom_report_key(wcombo, BTN_RIGHT, data[1] & 0x02);
+ if (wacom->features->type == WACOM_G4)
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[6] & 0x3f);
+ else
+ wacom_report_abs(wcombo, ABS_DISTANCE, data[7] & 0x3f);
+ break;
+ }
+ }
+
+ if (data[1] & 0x90) {
+ x = wacom_le16_to_cpu(&data[2]);
+ y = wacom_le16_to_cpu(&data[4]);
+ wacom_report_abs(wcombo, ABS_X, x);
+ wacom_report_abs(wcombo, ABS_Y, y);
+ if (wacom->tool[0] != BTN_TOOL_MOUSE) {
+ wacom_report_abs(wcombo, ABS_PRESSURE, data[6] | ((data[7] & 0x01) << 8));
+ wacom_report_key(wcombo, BTN_TOUCH, data[1] & 0x01);
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 0x02);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 0x04);
+ }
+ }
+
+ if (data[1] & 0x10)
+ wacom_report_abs(wcombo, ABS_MISC, id); /* report tool id */
+ else
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+ wacom_report_key(wcombo, wacom->tool[0], data[1] & 0x10);
+ wacom_input_sync(wcombo);
+
+ /* send pad data */
+ if (wacom->features->type == WACOM_G4) {
+ if ( (wacom->serial[1] & 0xc0) != (data[7] & 0xf8) ) {
+ wacom->id[1] = 1;
+ wacom->serial[1] = (data[7] & 0xf8);
+ wacom_report_key(wcombo, BTN_0, (data[7] & 0x40));
+ wacom_report_key(wcombo, BTN_4, (data[7] & 0x80));
+ rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3);
+ wacom_report_rel(wcombo, REL_WHEEL, rw);
+ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0xf0);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+ } else if (wacom->id[1]) {
+ wacom->id[1] = 0;
+ wacom_report_key(wcombo, BTN_TOOL_FINGER, 0);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xf0);
+ }
+ }
+ return 1;
+}
+
+static int wacom_intuos_inout(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ int idx;
+
+ /* tool number */
+ idx = data[1] & 0x01;
+
+ /* Enter report */
+ if ((data[1] & 0xfc) == 0xc0) {
+ /* serial number of the tool */
+ wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+ (data[4] << 20) + (data[5] << 12) +
+ (data[6] << 4) + (data[7] >> 4);
+
+ wacom->id[idx] = (data[2] << 4) | (data[3] >> 4);
+ switch (wacom->id[idx]) {
+ case 0x812: /* Inking pen */
+ case 0x801: /* Intuos3 Inking pen */
+ case 0x012:
+ wacom->tool[idx] = BTN_TOOL_PENCIL;
+ break;
+ case 0x822: /* Pen */
+ case 0x842:
+ case 0x852:
+ case 0x823: /* Intuos3 Grip Pen */
+ case 0x813: /* Intuos3 Classic Pen */
+ case 0x885: /* Intuos3 Marker Pen */
+ case 0x022:
+ wacom->tool[idx] = BTN_TOOL_PEN;
+ break;
+ case 0x832: /* Stroke pen */
+ case 0x032:
+ wacom->tool[idx] = BTN_TOOL_BRUSH;
+ break;
+ case 0x007: /* Mouse 4D and 2D */
+ case 0x09c:
+ case 0x094:
+ case 0x017: /* Intuos3 2D Mouse */
+ wacom->tool[idx] = BTN_TOOL_MOUSE;
+ break;
+ case 0x096: /* Lens cursor */
+ case 0x097: /* Intuos3 Lens cursor */
+ wacom->tool[idx] = BTN_TOOL_LENS;
+ break;
+ case 0x82a: /* Eraser */
+ case 0x85a:
+ case 0x91a:
+ case 0xd1a:
+ case 0x0fa:
+ case 0x82b: /* Intuos3 Grip Pen Eraser */
+ case 0x81b: /* Intuos3 Classic Pen Eraser */
+ case 0x91b: /* Intuos3 Airbrush Eraser */
+ wacom->tool[idx] = BTN_TOOL_RUBBER;
+ break;
+ case 0xd12:
+ case 0x912:
+ case 0x112:
+ case 0x913: /* Intuos3 Airbrush */
+ wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
+ break;
+ default: /* Unknown tool */
+ wacom->tool[idx] = BTN_TOOL_PEN;
+ }
+ /* only large I3 support Lens Cursor */
+ if(!((wacom->tool[idx] == BTN_TOOL_LENS)
+ && ((wacom->features->type == INTUOS3)
+ || (wacom->features->type == INTUOS3S)))) {
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
+ wacom_report_key(wcombo, wacom->tool[idx], 1);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 2;
+ }
+ return 1;
+ }
+
+ /* Exit report */
+ if ((data[1] & 0xfe) == 0x80) {
+ if(!((wacom->tool[idx] == BTN_TOOL_LENS)
+ && ((wacom->features->type == INTUOS3)
+ || (wacom->features->type == INTUOS3S)))) {
+ wacom_report_key(wcombo, wacom->tool[idx], 0);
+ wacom_report_abs(wcombo, ABS_MISC, 0); /* reset tool id */
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 2;
+ }
+ }
+ return 0;
+}
+
+static void wacom_intuos_general(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ unsigned int t;
+
+ /* general pen packet */
+ if ((data[1] & 0xb8) == 0xa0) {
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
+ wacom_report_abs(wcombo, ABS_PRESSURE, t);
+ wacom_report_abs(wcombo, ABS_TILT_X,
+ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+ wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+ wacom_report_key(wcombo, BTN_STYLUS, data[1] & 2);
+ wacom_report_key(wcombo, BTN_STYLUS2, data[1] & 4);
+ wacom_report_key(wcombo, BTN_TOUCH, t > 10);
+ }
+
+ /* airbrush second packet */
+ if ((data[1] & 0xbc) == 0xb4) {
+ wacom_report_abs(wcombo, ABS_WHEEL,
+ (data[6] << 2) | ((data[7] >> 6) & 3));
+ wacom_report_abs(wcombo, ABS_TILT_X,
+ ((data[7] << 1) & 0x7e) | (data[8] >> 7));
+ wacom_report_abs(wcombo, ABS_TILT_Y, data[8] & 0x7f);
+ }
+ return;
+}
+
+static int wacom_intuos_irq(struct wacom_wac *wacom, void *wcombo)
+{
+ unsigned char *data = wacom->data;
+ unsigned int t;
+ int idx, result;
+
+ if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
+ dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
+ return 0;
+ }
+
+ /* tool number */
+ idx = data[1] & 0x01;
+
+ /* pad packets. Works as a second tool and is always in prox */
+ if (data[0] == 12) {
+ /* initiate the pad as a device */
+ if (wacom->tool[1] != BTN_TOOL_FINGER)
+ wacom->tool[1] = BTN_TOOL_FINGER;
+
+ wacom_report_key(wcombo, BTN_0, (data[5] & 0x01));
+ wacom_report_key(wcombo, BTN_1, (data[5] & 0x02));
+ wacom_report_key(wcombo, BTN_2, (data[5] & 0x04));
+ wacom_report_key(wcombo, BTN_3, (data[5] & 0x08));
+ wacom_report_key(wcombo, BTN_4, (data[6] & 0x01));
+ wacom_report_key(wcombo, BTN_5, (data[6] & 0x02));
+ wacom_report_key(wcombo, BTN_6, (data[6] & 0x04));
+ wacom_report_key(wcombo, BTN_7, (data[6] & 0x08));
+ wacom_report_abs(wcombo, ABS_RX, ((data[1] & 0x1f) << 8) | data[2]);
+ wacom_report_abs(wcombo, ABS_RY, ((data[3] & 0x1f) << 8) | data[4]);
+
+ if((data[5] & 0x0f) | (data[6] & 0x0f) | (data[1] & 0x1f) |
+ data[2] | (data[3] & 0x1f) | data[4])
+ wacom_report_key(wcombo, wacom->tool[1], 1);
+ else
+ wacom_report_key(wcombo, wacom->tool[1], 0);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, 0xffffffff);
+ return 1;
+ }
+
+ /* process in/out prox events */
+ result = wacom_intuos_inout(wacom, wcombo);
+ if (result)
+ return result-1;
+
+ /* Cintiq doesn't send data when RDY bit isn't set */
+ if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+ return 0;
+
+ if (wacom->features->type >= INTUOS3) {
+ wacom_report_abs(wcombo, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
+ wacom_report_abs(wcombo, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
+ wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+ } else {
+ wacom_report_abs(wcombo, ABS_X, wacom_be16_to_cpu(&data[2]));
+ wacom_report_abs(wcombo, ABS_Y, wacom_be16_to_cpu(&data[4]));
+ wacom_report_abs(wcombo, ABS_DISTANCE, ((data[9] >> 3) & 0x1f));
+ }
+
+ /* process general packets */
+ wacom_intuos_general(wacom, wcombo);
+
+ /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
+ if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
+
+ if (data[1] & 0x02) {
+ /* Rotation packet */
+ if (wacom->features->type >= INTUOS3) {
+ /* I3 marker pen rotation reported as wheel
+ * due to valuator limitation
+ */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+ ((t-1) / 2 + 450)) : (450 - t / 2) ;
+ wacom_report_abs(wcombo, ABS_WHEEL, t);
+ } else {
+ /* 4D mouse rotation packet */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ wacom_report_abs(wcombo, ABS_RZ, (data[7] & 0x20) ?
+ ((t - 1) / 2) : -t / 2);
+ }
+
+ } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3S) {
+ /* 4D mouse packet */
+ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
+ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
+ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04);
+
+ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x20);
+ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x10);
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
+ wacom_report_abs(wcombo, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+
+ } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+ /* 2D mouse packet */
+ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x04);
+ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x08);
+ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x10);
+ wacom_report_rel(wcombo, REL_WHEEL, (data[8] & 0x01)
+ - ((data[8] & 0x02) >> 1));
+
+ /* I3 2D mouse side buttons */
+ if (wacom->features->type >= INTUOS3S && wacom->features->type <= INTUOS3L) {
+ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x40);
+ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x20);
+ }
+
+ } else if (wacom->features->type < INTUOS3S || wacom->features->type == INTUOS3L) {
+ /* Lens cursor packets */
+ wacom_report_key(wcombo, BTN_LEFT, data[8] & 0x01);
+ wacom_report_key(wcombo, BTN_MIDDLE, data[8] & 0x02);
+ wacom_report_key(wcombo, BTN_RIGHT, data[8] & 0x04);
+ wacom_report_key(wcombo, BTN_SIDE, data[8] & 0x10);
+ wacom_report_key(wcombo, BTN_EXTRA, data[8] & 0x08);
+ }
+ }
+
+ wacom_report_abs(wcombo, ABS_MISC, wacom->id[idx]); /* report tool id */
+ wacom_report_key(wcombo, wacom->tool[idx], 1);
+ wacom_input_event(wcombo, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ return 1;
+}
+
+int wacom_wac_irq(struct wacom_wac *wacom_wac, void *wcombo)
+{
+ switch (wacom_wac->features->type) {
+ case PENPARTNER:
+ return (wacom_penpartner_irq(wacom_wac, wcombo));
+ break;
+ case PL:
+ return (wacom_pl_irq(wacom_wac, wcombo));
+ break;
+ case WACOM_G4:
+ case GRAPHIRE:
+ return (wacom_graphire_irq(wacom_wac, wcombo));
+ break;
+ case PTU:
+ return (wacom_ptu_irq(wacom_wac, wcombo));
+ break;
+ case INTUOS:
+ case INTUOS3S:
+ case INTUOS3:
+ case INTUOS3L:
+ case CINTIQ:
+ return (wacom_intuos_irq(wacom_wac, wcombo));
+ break;
+ default:
+ return 0;
+ }
+ return 0;
+}
+
+void wacom_init_input_dev(struct input_dev *input_dev, struct wacom_wac *wacom_wac)
+{
+ switch (wacom_wac->features->type) {
+ case WACOM_G4:
+ input_dev_g4(input_dev, wacom_wac);
+ /* fall through */
+ case GRAPHIRE:
+ input_dev_g(input_dev, wacom_wac);
+ break;
+ case INTUOS3:
+ case INTUOS3L:
+ case CINTIQ:
+ input_dev_i3(input_dev, wacom_wac);
+ /* fall through */
+ case INTUOS3S:
+ input_dev_i3s(input_dev, wacom_wac);
+ case INTUOS:
+ input_dev_i(input_dev, wacom_wac);
+ break;
+ case PL:
+ case PTU:
+ input_dev_pl(input_dev, wacom_wac);
+ break;
+ case PENPARTNER:
+ input_dev_pt(input_dev, wacom_wac);
+ break;
+ }
+ return;
+}
+
+static struct wacom_features wacom_features[] = {
+ { "Wacom Penpartner", 7, 5040, 3780, 255, 0, PENPARTNER },
+ { "Wacom Graphire", 8, 10206, 7422, 511, 63, GRAPHIRE },
+ { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 63, GRAPHIRE },
+ { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 63, GRAPHIRE },
+ { "Wacom Graphire3", 8, 10208, 7424, 511, 63, GRAPHIRE },
+ { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 63, GRAPHIRE },
+ { "Wacom Graphire4 4x5", 8, 10208, 7424, 511, 63, WACOM_G4 },
+ { "Wacom Graphire4 6x8", 8, 16704, 12064, 511, 63, WACOM_G4 },
+ { "Wacom Volito", 8, 5104, 3712, 511, 0, GRAPHIRE },
+ { "Wacom PenStation2", 8, 3250, 2320, 255, 0, GRAPHIRE },
+ { "Wacom Volito2 4x5", 8, 5104, 3712, 511, 0, GRAPHIRE },
+ { "Wacom Volito2 2x3", 8, 3248, 2320, 511, 0, GRAPHIRE },
+ { "Wacom PenPartner2", 8, 3250, 2320, 255, 0, GRAPHIRE },
+ { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
+ { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
+ { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
+ { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
+ { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+ { "Wacom PL400", 8, 5408, 4056, 255, 0, PL },
+ { "Wacom PL500", 8, 6144, 4608, 255, 0, PL },
+ { "Wacom PL600", 8, 6126, 4604, 255, 0, PL },
+ { "Wacom PL600SX", 8, 6260, 5016, 255, 0, PL },
+ { "Wacom PL550", 8, 6144, 4608, 511, 0, PL },
+ { "Wacom PL800", 8, 7220, 5780, 511, 0, PL },
+ { "Wacom PL700", 8, 6758, 5406, 511, 0, PL },
+ { "Wacom PL510", 8, 6282, 4762, 511, 0, PL },
+ { "Wacom DTU710", 8, 34080, 27660, 511, 0, PL },
+ { "Wacom DTF521", 8, 6282, 4762, 511, 0, PL },
+ { "Wacom DTF720", 8, 6858, 5506, 511, 0, PL },
+ { "Wacom Cintiq Partner",8, 20480, 15360, 511, 0, PTU },
+ { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 63, INTUOS },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
+ { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 63, INTUOS },
+ { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 63, INTUOS },
+ { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 63, INTUOS },
+ { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 63, INTUOS3S },
+ { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 63, INTUOS3 },
+ { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 63, INTUOS3 },
+ { "Wacom Intuos3 12x12", 10, 60960, 60960, 1023, 63, INTUOS3L },
+ { "Wacom Intuos3 12x19", 10, 97536, 60960, 1023, 63, INTUOS3L },
+ { "Wacom Intuos3 6x11", 10, 54204, 31750, 1023, 63, INTUOS3 },
+ { "Wacom Intuos3 4x6", 10, 31496, 19685, 1023, 15, INTUOS3S },
+ { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 63, CINTIQ },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 63, INTUOS },
+ { }
+};
+
+static struct usb_device_id wacom_ids[] = {
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x00) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x10) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x11) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x12) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x13) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x14) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x15) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x16) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x60) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x61) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x62) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x63) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x64) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x20) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x21) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x22) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x23) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x24) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x30) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x31) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x32) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x33) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x34) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x35) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x37) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x38) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x39) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC0) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xC4) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x03) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x41) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x42) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x43) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x44) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x45) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB3) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB4) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB5) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB7) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
+ { }
+};
+
+const struct usb_device_id * get_device_table(void) {
+ const struct usb_device_id * id_table = wacom_ids;
+ return id_table;
+}
+
+struct wacom_features * get_wacom_feature(const struct usb_device_id * id) {
+ int index = id - wacom_ids;
+ struct wacom_features *wf = &wacom_features[index];
+ return wf;
+}
+
+MODULE_DEVICE_TABLE(usb, wacom_ids);
diff --git a/drivers/usb/input/wacom_wac.h b/drivers/usb/input/wacom_wac.h
new file mode 100644
index 000000000000..a1d9ce007970
--- /dev/null
+++ b/drivers/usb/input/wacom_wac.h
@@ -0,0 +1,48 @@
+/*
+ * drivers/usb/input/wacom_wac.h
+ *
+ * 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.
+ */
+#ifndef WACOM_WAC_H
+#define WACOM_WAC_H
+
+#define STYLUS_DEVICE_ID 0x02
+#define CURSOR_DEVICE_ID 0x06
+#define ERASER_DEVICE_ID 0x0A
+
+enum {
+ PENPARTNER = 0,
+ GRAPHIRE,
+ WACOM_G4,
+ PTU,
+ PL,
+ INTUOS,
+ INTUOS3S,
+ INTUOS3,
+ INTUOS3L,
+ CINTIQ,
+ MAX_TYPE
+};
+
+struct wacom_features {
+ char *name;
+ int pktlen;
+ int x_max;
+ int y_max;
+ int pressure_max;
+ int distance_max;
+ int type;
+};
+
+struct wacom_wac {
+ signed char *data;
+ int tool[2];
+ int id[2];
+ __u32 serial[2];
+ struct wacom_features *features;
+};
+
+#endif
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
index 9889b1cda05b..6a12a943b938 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/usb/input/xpad.c
@@ -1,8 +1,9 @@
/*
- * X-Box gamepad - v0.0.5
+ * X-Box gamepad - v0.0.6
*
* Copyright (c) 2002 Marko Friedemann <mfr@bmx-chemnitz.de>
- *
+ * 2005 Dominic Cerquetti <binary1230@yahoo.com>
+ * 2006 Adam Buchbinder <adam.buchbinder@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -30,9 +31,10 @@
* - Greg Kroah-Hartman - usb-skeleton driver
*
* TODO:
- * - fine tune axes
+ * - fine tune axes (especially trigger axes)
* - fix "analog" buttons (reported as digital now)
* - get rumble working
+ * - need USB IDs for other dance pads
*
* History:
*
@@ -57,25 +59,40 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/stat.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/smp_lock.h>
#include <linux/usb/input.h>
-#define DRIVER_VERSION "v0.0.5"
+#define DRIVER_VERSION "v0.0.6"
#define DRIVER_AUTHOR "Marko Friedemann <mfr@bmx-chemnitz.de>"
#define DRIVER_DESC "X-Box pad driver"
#define XPAD_PKT_LEN 32
+/* xbox d-pads should map to buttons, as is required for DDR pads
+ but we map them to axes when possible to simplify things */
+#define MAP_DPAD_TO_BUTTONS 0
+#define MAP_DPAD_TO_AXES 1
+#define MAP_DPAD_UNKNOWN -1
+
+static int dpad_to_buttons;
+module_param(dpad_to_buttons, bool, S_IRUGO);
+MODULE_PARM_DESC(dpad_to_buttons, "Map D-PAD to buttons rather than axes for unknown pads");
+
static const struct xpad_device {
u16 idVendor;
u16 idProduct;
char *name;
+ u8 dpad_mapping;
} xpad_device[] = {
- { 0x045e, 0x0202, "Microsoft X-Box pad (US)" },
- { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)" },
- { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)" },
- { 0x0000, 0x0000, "X-Box pad" }
+ { 0x045e, 0x0202, "Microsoft X-Box pad v1 (US)", MAP_DPAD_TO_AXES },
+ { 0x045e, 0x0289, "Microsoft X-Box pad v2 (US)", MAP_DPAD_TO_AXES },
+ { 0x045e, 0x0285, "Microsoft X-Box pad (Japan)", MAP_DPAD_TO_AXES },
+ { 0x05fd, 0x107a, "InterAct 'PowerPad Pro' X-Box pad (Germany)", MAP_DPAD_TO_AXES },
+ { 0x0c12, 0x8809, "RedOctane Xbox Dance Pad", MAP_DPAD_TO_BUTTONS },
+ { 0x0000, 0x0000, "Generic X-Box pad", MAP_DPAD_UNKNOWN }
};
static const signed short xpad_btn[] = {
@@ -84,11 +101,23 @@ static const signed short xpad_btn[] = {
-1 /* terminating entry */
};
+/* only used if MAP_DPAD_TO_BUTTONS */
+static const signed short xpad_btn_pad[] = {
+ BTN_LEFT, BTN_RIGHT, /* d-pad left, right */
+ BTN_0, BTN_1, /* d-pad up, down (XXX names??) */
+ -1 /* terminating entry */
+};
+
static const signed short xpad_abs[] = {
ABS_X, ABS_Y, /* left stick */
ABS_RX, ABS_RY, /* right stick */
ABS_Z, ABS_RZ, /* triggers left/right */
- ABS_HAT0X, ABS_HAT0Y, /* digital pad */
+ -1 /* terminating entry */
+};
+
+/* only used if MAP_DPAD_TO_AXES */
+static const signed short xpad_abs_pad[] = {
+ ABS_HAT0X, ABS_HAT0Y, /* d-pad axes */
-1 /* terminating entry */
};
@@ -100,14 +129,16 @@ static struct usb_device_id xpad_table [] = {
MODULE_DEVICE_TABLE (usb, xpad_table);
struct usb_xpad {
- struct input_dev *dev; /* input device interface */
- struct usb_device *udev; /* usb device */
+ struct input_dev *dev; /* input device interface */
+ struct usb_device *udev; /* usb device */
- struct urb *irq_in; /* urb for interrupt in report */
- unsigned char *idata; /* input data */
+ struct urb *irq_in; /* urb for interrupt in report */
+ unsigned char *idata; /* input data */
dma_addr_t idata_dma;
- char phys[65]; /* physical device path */
+ char phys[65]; /* physical device path */
+
+ int dpad_mapping; /* map d-pad to buttons or to axes */
};
/*
@@ -120,12 +151,10 @@ struct usb_xpad {
* http://euc.jp/periphs/xbox-controller.ja.html
*/
-static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data, struct pt_regs *regs)
+static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *data)
{
struct input_dev *dev = xpad->dev;
- input_regs(dev, regs);
-
/* left stick */
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
@@ -139,14 +168,21 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
input_report_abs(dev, ABS_RZ, data[11]);
/* digital pad */
- input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
- input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+ if (xpad->dpad_mapping == MAP_DPAD_TO_AXES) {
+ input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
+ input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
+ } else /* xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS */ {
+ input_report_key(dev, BTN_LEFT, data[2] & 0x04);
+ input_report_key(dev, BTN_RIGHT, data[2] & 0x08);
+ input_report_key(dev, BTN_0, data[2] & 0x01); // up
+ input_report_key(dev, BTN_1, data[2] & 0x02); // down
+ }
/* start/back buttons and stick press left/right */
- input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
- input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
- input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
- input_report_key(dev, BTN_THUMBR, data[2] >> 7);
+ input_report_key(dev, BTN_START, data[2] & 0x10);
+ input_report_key(dev, BTN_BACK, data[2] & 0x20);
+ input_report_key(dev, BTN_THUMBL, data[2] & 0x40);
+ input_report_key(dev, BTN_THUMBR, data[2] & 0x80);
/* "analog" buttons A, B, X, Y */
input_report_key(dev, BTN_A, data[4]);
@@ -161,7 +197,7 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
input_sync(dev);
}
-static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
+static void xpad_irq_in(struct urb *urb)
{
struct usb_xpad *xpad = urb->context;
int retval;
@@ -181,7 +217,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- xpad_process_packet(xpad, 0, xpad->idata, regs);
+ xpad_process_packet(xpad, 0, xpad->idata);
exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
@@ -208,6 +244,28 @@ static void xpad_close (struct input_dev *dev)
usb_kill_urb(xpad->irq_in);
}
+static void xpad_set_up_abs(struct input_dev *input_dev, signed short abs)
+{
+ set_bit(abs, input_dev->absbit);
+
+ switch (abs) {
+ case ABS_X:
+ case ABS_Y:
+ case ABS_RX:
+ case ABS_RY: /* the two sticks */
+ input_set_abs_params(input_dev, abs, -32768, 32767, 16, 128);
+ break;
+ case ABS_Z:
+ case ABS_RZ: /* the triggers */
+ input_set_abs_params(input_dev, abs, 0, 255, 0, 0);
+ break;
+ case ABS_HAT0X:
+ case ABS_HAT0Y: /* the d-pad (only if MAP_DPAD_TO_AXES) */
+ input_set_abs_params(input_dev, abs, -1, 1, 0, 0);
+ break;
+ }
+}
+
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev (intf);
@@ -237,6 +295,9 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
goto fail2;
xpad->udev = udev;
+ xpad->dpad_mapping = xpad_device[i].dpad_mapping;
+ if (xpad->dpad_mapping == MAP_DPAD_UNKNOWN)
+ xpad->dpad_mapping = dpad_to_buttons;
xpad->dev = input_dev;
usb_make_path(udev, xpad->phys, sizeof(xpad->phys));
strlcat(xpad->phys, "/input0", sizeof(xpad->phys));
@@ -251,32 +312,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ /* set up buttons */
for (i = 0; xpad_btn[i] >= 0; i++)
set_bit(xpad_btn[i], input_dev->keybit);
+ if (xpad->dpad_mapping == MAP_DPAD_TO_BUTTONS)
+ for (i = 0; xpad_btn_pad[i] >= 0; i++)
+ set_bit(xpad_btn_pad[i], input_dev->keybit);
- for (i = 0; xpad_abs[i] >= 0; i++) {
-
- signed short t = xpad_abs[i];
-
- set_bit(t, input_dev->absbit);
-
- switch (t) {
- case ABS_X:
- case ABS_Y:
- case ABS_RX:
- case ABS_RY: /* the two sticks */
- input_set_abs_params(input_dev, t, -32768, 32767, 16, 128);
- break;
- case ABS_Z:
- case ABS_RZ: /* the triggers */
- input_set_abs_params(input_dev, t, 0, 255, 0, 0);
- break;
- case ABS_HAT0X:
- case ABS_HAT0Y: /* the d-pad */
- input_set_abs_params(input_dev, t, -1, 1, 0, 0);
- break;
- }
- }
+ /* set up axes */
+ for (i = 0; xpad_abs[i] >= 0; i++)
+ xpad_set_up_abs(input_dev, xpad_abs[i]);
+ if (xpad->dpad_mapping == MAP_DPAD_TO_AXES)
+ for (i = 0; xpad_abs_pad[i] >= 0; i++)
+ xpad_set_up_abs(input_dev, xpad_abs_pad[i]);
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
usb_fill_int_urb(xpad->irq_in, udev,
@@ -307,7 +355,8 @@ static void xpad_disconnect(struct usb_interface *intf)
usb_kill_urb(xpad->irq_in);
input_unregister_device(xpad->dev);
usb_free_urb(xpad->irq_in);
- usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN, xpad->idata, xpad->idata_dma);
+ usb_buffer_free(interface_to_usbdev(intf), XPAD_PKT_LEN,
+ xpad->idata, xpad->idata_dma);
kfree(xpad);
}
}
diff --git a/drivers/usb/input/yealink.c b/drivers/usb/input/yealink.c
index 7b45fd3de911..905bf6398257 100644
--- a/drivers/usb/input/yealink.c
+++ b/drivers/usb/input/yealink.c
@@ -233,11 +233,10 @@ static int map_p1k_to_key(int scancode)
*
* The key parameter can be cascaded: key2 << 8 | key1
*/
-static void report_key(struct yealink_dev *yld, int key, struct pt_regs *regs)
+static void report_key(struct yealink_dev *yld, int key)
{
struct input_dev *idev = yld->idev;
- input_regs(idev, regs);
if (yld->key_code >= 0) {
/* old key up */
input_report_key(idev, yld->key_code & 0xff, 0);
@@ -422,7 +421,7 @@ send_update:
* error,start
*
*/
-static void urb_irq_callback(struct urb *urb, struct pt_regs *regs)
+static void urb_irq_callback(struct urb *urb)
{
struct yealink_dev *yld = urb->context;
int ret;
@@ -439,7 +438,7 @@ static void urb_irq_callback(struct urb *urb, struct pt_regs *regs)
case CMD_SCANCODE:
dbg("get scancode %x", yld->irq_data->data[0]);
- report_key(yld, map_p1k_to_key(yld->irq_data->data[0]), regs);
+ report_key(yld, map_p1k_to_key(yld->irq_data->data[0]));
break;
default:
@@ -453,7 +452,7 @@ static void urb_irq_callback(struct urb *urb, struct pt_regs *regs)
err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
}
-static void urb_ctl_callback(struct urb *urb, struct pt_regs *regs)
+static void urb_ctl_callback(struct urb *urb)
{
struct yealink_dev *yld = urb->context;
int ret;
@@ -971,7 +970,7 @@ static int usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
DRIVER_VERSION, sizeof(DRIVER_VERSION));
/* Register sysfs hooks (don't care about failure) */
- sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
+ ret = sysfs_create_group(&intf->dev.kobj, &yld_attr_group);
return 0;
}
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 88928a4be805..a74bf8617e7f 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -32,6 +32,16 @@ config USB_EMI26
To compile this driver as a module, choose M here: the
module will be called emi26.
+config USB_ADUTUX
+ tristate "ADU devices from Ontrak Control Systems (EXPERIMENTAL)"
+ depends on USB && EXPERIMENTAL
+ help
+ Say Y if you want to use an ADU device from Ontrak Control
+ Systems.
+
+ To compile this driver as a module, choose M here. The module
+ will be called adutux.
+
config USB_AUERSWALD
tristate "USB Auerswald ISDN support (EXPERIMENTAL)"
depends on USB && EXPERIMENTAL
@@ -115,19 +125,36 @@ config USB_CYTHERM
To compile this driver as a module, choose M here: the
module will be called cytherm.
-config USB_PHIDGETKIT
- tristate "USB PhidgetKit support"
+config USB_PHIDGET
+ tristate "USB Phidgets drivers"
depends on USB
help
- Say Y here if you want to connect a PhidgetKit USB device from
- Phidgets Inc.
+ Say Y here to enable the various drivers for devices from
+ Phidgets inc.
+
+config USB_PHIDGETKIT
+ tristate "USB PhidgetInterfaceKit support"
+ depends on USB_PHIDGET
+ help
+ Say Y here if you want to connect a PhidgetInterfaceKit USB device
+ from Phidgets Inc.
To compile this driver as a module, choose M here: the
module will be called phidgetkit.
+config USB_PHIDGETMOTORCONTROL
+ tristate "USB PhidgetMotorControl support"
+ depends on USB_PHIDGET
+ help
+ Say Y here if you want to connect a PhidgetMotorControl USB device
+ from Phidgets Inc.
+
+ To compile this driver as a module, choose M here: the
+ module will be called phidgetmotorcontrol.
+
config USB_PHIDGETSERVO
tristate "USB PhidgetServo support"
- depends on USB
+ depends on USB_PHIDGET
help
Say Y here if you want to connect an 1 or 4 Motor PhidgetServo
servo controller version 2.0 or 3.0.
@@ -151,6 +178,30 @@ config USB_IDMOUSE
See also <http://www.fs.tum.de/~echtler/idmouse/>.
+config USB_FTDI_ELAN
+ tristate "Elan PCMCIA CardBus Adapter USB Client"
+ depends on USB
+ default M
+ help
+ ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters.
+ Currently only the U132 adapter is available.
+
+ The U132 is specifically designed for CardBus PC cards that contain
+ an OHCI host controller. Typical PC cards are the Orange Mobile 3G
+ Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work
+ with PC cards that do not contain an OHCI controller. To use a U132
+ adapter you will need this "ftdi-elan" module as well as the "u132-hcd"
+ module which is a USB host controller driver that talks to the OHCI
+ controller within CardBus card that are inserted in the U132 adapter.
+
+ This driver has been tested with a CardBus OHCI USB adapter, and
+ worked with a USB PEN Drive inserted into the first USB port of
+ the PCCARD. A rather pointless thing to do, but useful for testing.
+
+ See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller"
+
+ It is safe to say M here.
+
config USB_APPLEDISPLAY
tristate "Apple Cinema Display support"
depends on USB
@@ -172,6 +223,16 @@ config USB_LD
To compile this driver as a module, choose M here: the
module will be called ldusb.
+config USB_TRANCEVIBRATOR
+ tristate "PlayStation 2 Trance Vibrator driver support"
+ depends on USB
+ help
+ Say Y here if you want to connect a PlayStation 2 Trance Vibrator
+ device to your computer's USB port.
+
+ To compile this driver as a module, choose M here: the
+ module will be called trancevibrator.
+
config USB_TEST
tristate "USB testing driver (DEVELOPMENT)"
depends on USB && USB_DEVICEFS && EXPERIMENTAL
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 2927260c5812..11dc59540cda 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -3,22 +3,26 @@
# (the ones that don't fit into any other categories)
#
+obj-$(CONFIG_USB_ADUTUX) += adutux.o
obj-$(CONFIG_USB_AUERSWALD) += auerswald.o
obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o
obj-$(CONFIG_USB_CYTHERM) += cytherm.o
obj-$(CONFIG_USB_EMI26) += emi26.o
obj-$(CONFIG_USB_EMI62) += emi62.o
+obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
obj-$(CONFIG_USB_LCD) += usblcd.o
obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LED) += usbled.o
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
+obj-$(CONFIG_USB_PHIDGET) += phidget.o
obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o
+obj-$(CONFIG_USB_PHIDGETMOTORCONTROL) += phidgetmotorcontrol.o
obj-$(CONFIG_USB_PHIDGETSERVO) += phidgetservo.o
obj-$(CONFIG_USB_RIO500) += rio500.o
obj-$(CONFIG_USB_TEST) += usbtest.o
+obj-$(CONFIG_USB_TRANCEVIBRATOR) += trancevibrator.o
obj-$(CONFIG_USB_USS720) += uss720.o
-obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
obj-$(CONFIG_USB_SISUSBVGA) += sisusbvga/
diff --git a/drivers/usb/misc/adutux.c b/drivers/usb/misc/adutux.c
new file mode 100644
index 000000000000..af2934e016a7
--- /dev/null
+++ b/drivers/usb/misc/adutux.c
@@ -0,0 +1,901 @@
+/*
+ * adutux - driver for ADU devices from Ontrak Control Systems
+ * This is an experimental driver. Use at your own risk.
+ * This driver is not supported by Ontrak Control Systems.
+ *
+ * Copyright (c) 2003 John Homppi (SCO, leave this notice here)
+ *
+ * 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.
+ *
+ * derived from the Lego USB Tower driver 0.56:
+ * Copyright (c) 2003 David Glance <davidgsf@sourceforge.net>
+ * 2001 Juergen Stuber <stuber@loria.fr>
+ * that was derived from USB Skeleton driver - 0.5
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+
+#ifdef CONFIG_USB_DEBUG
+static int debug = 5;
+#else
+static int debug = 1;
+#endif
+
+/* Use our own dbg macro */
+#undef dbg
+#define dbg(lvl, format, arg...) \
+do { \
+ if (debug >= lvl) \
+ printk(KERN_DEBUG __FILE__ " : " format " \n", ## arg); \
+} while (0)
+
+
+/* Version Information */
+#define DRIVER_VERSION "v0.0.13"
+#define DRIVER_AUTHOR "John Homppi"
+#define DRIVER_DESC "adutux (see www.ontrak.net)"
+
+/* Module parameters */
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* Define these values to match your device */
+#define ADU_VENDOR_ID 0x0a07
+#define ADU_PRODUCT_ID 0x0064
+
+/* table of devices that work with this driver */
+static struct usb_device_id device_table [] = {
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) }, /* ADU100 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) }, /* ADU120 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) }, /* ADU130 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+100) }, /* ADU200 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+108) }, /* ADU208 */
+ { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+118) }, /* ADU218 */
+ { }/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define ADU_MINOR_BASE 0
+#else
+#define ADU_MINOR_BASE 67
+#endif
+
+/* we can have up to this number of device plugged in at once */
+#define MAX_DEVICES 16
+
+#define COMMAND_TIMEOUT (2*HZ) /* 60 second timeout for a command */
+
+/* Structure to hold all of our device specific stuff */
+struct adu_device {
+ struct semaphore sem; /* locks this structure */
+ struct usb_device* udev; /* save off the usb device pointer */
+ struct usb_interface* interface;
+ unsigned char minor; /* the starting minor number for this device */
+ char serial_number[8];
+
+ int open_count; /* number of times this port has been opened */
+
+ char* read_buffer_primary;
+ int read_buffer_length;
+ char* read_buffer_secondary;
+ int secondary_head;
+ int secondary_tail;
+ spinlock_t buflock;
+
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ char* interrupt_in_buffer;
+ struct usb_endpoint_descriptor* interrupt_in_endpoint;
+ struct urb* interrupt_in_urb;
+ int read_urb_finished;
+
+ char* interrupt_out_buffer;
+ struct usb_endpoint_descriptor* interrupt_out_endpoint;
+ struct urb* interrupt_out_urb;
+};
+
+/* prevent races between open() and disconnect */
+static DEFINE_MUTEX(disconnect_mutex);
+static struct usb_driver adu_driver;
+
+static void adu_debug_data(int level, const char *function, int size,
+ const unsigned char *data)
+{
+ int i;
+
+ if (debug < level)
+ return;
+
+ printk(KERN_DEBUG __FILE__": %s - length = %d, data = ",
+ function, size);
+ for (i = 0; i < size; ++i)
+ printk("%.2x ", data[i]);
+ printk("\n");
+}
+
+/**
+ * adu_abort_transfers
+ * aborts transfers and frees associated data structures
+ */
+static void adu_abort_transfers(struct adu_device *dev)
+{
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (dev == NULL) {
+ dbg(1," %s : dev is null", __FUNCTION__);
+ goto exit;
+ }
+
+ if (dev->udev == NULL) {
+ dbg(1," %s : udev is null", __FUNCTION__);
+ goto exit;
+ }
+
+ dbg(2," %s : udev state %d", __FUNCTION__, dev->udev->state);
+ if (dev->udev->state == USB_STATE_NOTATTACHED) {
+ dbg(1," %s : udev is not attached", __FUNCTION__);
+ goto exit;
+ }
+
+ /* shutdown transfer */
+ usb_unlink_urb(dev->interrupt_in_urb);
+ usb_unlink_urb(dev->interrupt_out_urb);
+
+exit:
+ dbg(2," %s : leave", __FUNCTION__);
+}
+
+static void adu_delete(struct adu_device *dev)
+{
+ dbg(2, "%s enter", __FUNCTION__);
+
+ adu_abort_transfers(dev);
+
+ /* free data structures */
+ usb_free_urb(dev->interrupt_in_urb);
+ usb_free_urb(dev->interrupt_out_urb);
+ kfree(dev->read_buffer_primary);
+ kfree(dev->read_buffer_secondary);
+ kfree(dev->interrupt_in_buffer);
+ kfree(dev->interrupt_out_buffer);
+ kfree(dev);
+
+ dbg(2, "%s : leave", __FUNCTION__);
+}
+
+static void adu_interrupt_in_callback(struct urb *urb)
+{
+ struct adu_device *dev = urb->context;
+
+ dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ urb->transfer_buffer);
+
+ spin_lock(&dev->buflock);
+
+ if (urb->status != 0) {
+ if ((urb->status != -ENOENT) && (urb->status != -ECONNRESET)) {
+ dbg(1," %s : nonzero status received: %d",
+ __FUNCTION__, urb->status);
+ }
+ goto exit;
+ }
+
+ if (urb->actual_length > 0 && dev->interrupt_in_buffer[0] != 0x00) {
+ if (dev->read_buffer_length <
+ (4 * le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize)) -
+ (urb->actual_length)) {
+ memcpy (dev->read_buffer_primary +
+ dev->read_buffer_length,
+ dev->interrupt_in_buffer, urb->actual_length);
+
+ dev->read_buffer_length += urb->actual_length;
+ dbg(2," %s reading %d ", __FUNCTION__,
+ urb->actual_length);
+ } else {
+ dbg(1," %s : read_buffer overflow", __FUNCTION__);
+ }
+ }
+
+exit:
+ dev->read_urb_finished = 1;
+ spin_unlock(&dev->buflock);
+ /* always wake up so we recover from errors */
+ wake_up_interruptible(&dev->read_wait);
+ adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ urb->transfer_buffer);
+ dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+}
+
+static void adu_interrupt_out_callback(struct urb *urb)
+{
+ struct adu_device *dev = urb->context;
+
+ dbg(4," %s : enter, status %d", __FUNCTION__, urb->status);
+ adu_debug_data(5,__FUNCTION__, urb->actual_length, urb->transfer_buffer);
+
+ if (urb->status != 0) {
+ if ((urb->status != -ENOENT) &&
+ (urb->status != -ECONNRESET)) {
+ dbg(1, " %s :nonzero status received: %d",
+ __FUNCTION__, urb->status);
+ }
+ goto exit;
+ }
+
+ wake_up_interruptible(&dev->write_wait);
+exit:
+
+ adu_debug_data(5, __FUNCTION__, urb->actual_length,
+ urb->transfer_buffer);
+ dbg(4," %s : leave, status %d", __FUNCTION__, urb->status);
+}
+
+static int adu_open(struct inode *inode, struct file *file)
+{
+ struct adu_device *dev = NULL;
+ struct usb_interface *interface;
+ int subminor;
+ int retval = 0;
+
+ dbg(2,"%s : enter", __FUNCTION__);
+
+ subminor = iminor(inode);
+
+ mutex_lock(&disconnect_mutex);
+
+ interface = usb_find_interface(&adu_driver, subminor);
+ if (!interface) {
+ err("%s - error, can't find device for minor %d",
+ __FUNCTION__, subminor);
+ retval = -ENODEV;
+ goto exit_no_device;
+ }
+
+ dev = usb_get_intfdata(interface);
+ if (!dev) {
+ retval = -ENODEV;
+ goto exit_no_device;
+ }
+
+ /* lock this device */
+ if ((retval = down_interruptible(&dev->sem))) {
+ dbg(2, "%s : sem down failed", __FUNCTION__);
+ goto exit_no_device;
+ }
+
+ /* increment our usage count for the device */
+ ++dev->open_count;
+ dbg(2,"%s : open count %d", __FUNCTION__, dev->open_count);
+
+ /* save device in the file's private structure */
+ file->private_data = dev;
+
+ /* initialize in direction */
+ dev->read_buffer_length = 0;
+
+ /* fixup first read by having urb waiting for it */
+ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ adu_interrupt_in_callback, dev,
+ dev->interrupt_in_endpoint->bInterval);
+ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
+ dev->read_urb_finished = 0;
+ usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ /* we ignore failure */
+ /* end of fixup for first read */
+
+ up(&dev->sem);
+
+exit_no_device:
+ mutex_unlock(&disconnect_mutex);
+ dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
+
+ return retval;
+}
+
+static int adu_release_internal(struct adu_device *dev)
+{
+ int retval = 0;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (dev->udev == NULL) {
+ /* the device was unplugged before the file was released */
+ adu_delete(dev);
+ goto exit;
+ }
+
+ /* decrement our usage count for the device */
+ --dev->open_count;
+ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
+ if (dev->open_count <= 0) {
+ adu_abort_transfers(dev);
+ dev->open_count = 0;
+ }
+
+exit:
+ dbg(2," %s : leave", __FUNCTION__);
+ return retval;
+}
+
+static int adu_release(struct inode *inode, struct file *file)
+{
+ struct adu_device *dev = NULL;
+ int retval = 0;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (file == NULL) {
+ dbg(1," %s : file is NULL", __FUNCTION__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ dev = file->private_data;
+
+ if (dev == NULL) {
+ dbg(1," %s : object is NULL", __FUNCTION__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* lock our device */
+ down(&dev->sem); /* not interruptible */
+
+ if (dev->open_count <= 0) {
+ dbg(1," %s : device not opened", __FUNCTION__);
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* do the work */
+ retval = adu_release_internal(dev);
+
+exit:
+ if (dev)
+ up(&dev->sem);
+ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+ return retval;
+}
+
+static ssize_t adu_read(struct file *file, __user char *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct adu_device *dev;
+ size_t bytes_read = 0;
+ size_t bytes_to_read = count;
+ int i;
+ int retval = 0;
+ int timeout = 0;
+ int should_submit = 0;
+ unsigned long flags;
+ DECLARE_WAITQUEUE(wait, current);
+
+ dbg(2," %s : enter, count = %Zd, file=%p", __FUNCTION__, count, file);
+
+ dev = file->private_data;
+ dbg(2," %s : dev=%p", __FUNCTION__, dev);
+ /* lock this object */
+ if (down_interruptible(&dev->sem))
+ return -ERESTARTSYS;
+
+ /* verify that the device wasn't unplugged */
+ if (dev->udev == NULL || dev->minor == 0) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d", retval);
+ goto exit;
+ }
+
+ /* verify that some data was requested */
+ if (count == 0) {
+ dbg(1," %s : read request of 0 bytes", __FUNCTION__);
+ goto exit;
+ }
+
+ timeout = COMMAND_TIMEOUT;
+ dbg(2," %s : about to start looping", __FUNCTION__);
+ while (bytes_to_read) {
+ int data_in_secondary = dev->secondary_tail - dev->secondary_head;
+ dbg(2," %s : while, data_in_secondary=%d, status=%d",
+ __FUNCTION__, data_in_secondary,
+ dev->interrupt_in_urb->status);
+
+ if (data_in_secondary) {
+ /* drain secondary buffer */
+ int amount = bytes_to_read < data_in_secondary ? bytes_to_read : data_in_secondary;
+ i = copy_to_user(buffer, dev->read_buffer_secondary+dev->secondary_head, amount);
+ if (i < 0) {
+ retval = -EFAULT;
+ goto exit;
+ }
+ dev->secondary_head += (amount - i);
+ bytes_read += (amount - i);
+ bytes_to_read -= (amount - i);
+ if (i) {
+ retval = bytes_read ? bytes_read : -EFAULT;
+ goto exit;
+ }
+ } else {
+ /* we check the primary buffer */
+ spin_lock_irqsave (&dev->buflock, flags);
+ if (dev->read_buffer_length) {
+ /* we secure access to the primary */
+ char *tmp;
+ dbg(2," %s : swap, read_buffer_length = %d",
+ __FUNCTION__, dev->read_buffer_length);
+ tmp = dev->read_buffer_secondary;
+ dev->read_buffer_secondary = dev->read_buffer_primary;
+ dev->read_buffer_primary = tmp;
+ dev->secondary_head = 0;
+ dev->secondary_tail = dev->read_buffer_length;
+ dev->read_buffer_length = 0;
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ /* we have a free buffer so use it */
+ should_submit = 1;
+ } else {
+ /* even the primary was empty - we may need to do IO */
+ if (dev->interrupt_in_urb->status == -EINPROGRESS) {
+ /* somebody is doing IO */
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ dbg(2," %s : submitted already", __FUNCTION__);
+ } else {
+ /* we must initiate input */
+ dbg(2," %s : initiate input", __FUNCTION__);
+ dev->read_urb_finished = 0;
+
+ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ adu_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_endpoint->bInterval);
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ if (!retval) {
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ dbg(2," %s : submitted OK", __FUNCTION__);
+ } else {
+ if (retval == -ENOMEM) {
+ retval = bytes_read ? bytes_read : -ENOMEM;
+ }
+ spin_unlock_irqrestore(&dev->buflock, flags);
+ dbg(2," %s : submit failed", __FUNCTION__);
+ goto exit;
+ }
+ }
+
+ /* we wait for I/O to complete */
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&dev->read_wait, &wait);
+ if (!dev->read_urb_finished)
+ timeout = schedule_timeout(COMMAND_TIMEOUT);
+ else
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&dev->read_wait, &wait);
+
+ if (timeout <= 0) {
+ dbg(2," %s : timeout", __FUNCTION__);
+ retval = bytes_read ? bytes_read : -ETIMEDOUT;
+ goto exit;
+ }
+
+ if (signal_pending(current)) {
+ dbg(2," %s : signal pending", __FUNCTION__);
+ retval = bytes_read ? bytes_read : -EINTR;
+ goto exit;
+ }
+ }
+ }
+ }
+
+ retval = bytes_read;
+ /* if the primary buffer is empty then use it */
+ if (should_submit && !dev->interrupt_in_urb->status==-EINPROGRESS) {
+ usb_fill_int_urb(dev->interrupt_in_urb,dev->udev,
+ usb_rcvintpipe(dev->udev,
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize),
+ adu_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_endpoint->bInterval);
+ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
+ dev->read_urb_finished = 0;
+ usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ /* we ignore failure */
+ }
+
+exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+ return retval;
+}
+
+static ssize_t adu_write(struct file *file, const __user char *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct adu_device *dev;
+ size_t bytes_written = 0;
+ size_t bytes_to_write;
+ size_t buffer_size;
+ int retval = 0;
+ int timeout = 0;
+
+ dbg(2," %s : enter, count = %Zd", __FUNCTION__, count);
+
+ dev = file->private_data;
+
+ /* lock this object */
+ down_interruptible(&dev->sem);
+
+ /* verify that the device wasn't unplugged */
+ if (dev->udev == NULL || dev->minor == 0) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d", retval);
+ goto exit;
+ }
+
+ /* verify that we actually have some data to write */
+ if (count == 0) {
+ dbg(1," %s : write request of 0 bytes", __FUNCTION__);
+ goto exit;
+ }
+
+
+ while (count > 0) {
+ if (dev->interrupt_out_urb->status == -EINPROGRESS) {
+ timeout = COMMAND_TIMEOUT;
+
+ while (timeout > 0) {
+ if (signal_pending(current)) {
+ dbg(1," %s : interrupted", __FUNCTION__);
+ retval = -EINTR;
+ goto exit;
+ }
+ up(&dev->sem);
+ timeout = interruptible_sleep_on_timeout(&dev->write_wait, timeout);
+ down_interruptible(&dev->sem);
+ if (timeout > 0) {
+ break;
+ }
+ dbg(1," %s : interrupted timeout: %d", __FUNCTION__, timeout);
+ }
+
+
+ dbg(1," %s : final timeout: %d", __FUNCTION__, timeout);
+
+ if (timeout == 0) {
+ dbg(1, "%s - command timed out.", __FUNCTION__);
+ retval = -ETIMEDOUT;
+ goto exit;
+ }
+
+ dbg(4," %s : in progress, count = %Zd", __FUNCTION__, count);
+
+ } else {
+ dbg(4," %s : sending, count = %Zd", __FUNCTION__, count);
+
+ /* write the data into interrupt_out_buffer from userspace */
+ buffer_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+ bytes_to_write = count > buffer_size ? buffer_size : count;
+ dbg(4," %s : buffer_size = %Zd, count = %Zd, bytes_to_write = %Zd",
+ __FUNCTION__, buffer_size, count, bytes_to_write);
+
+ if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write) != 0) {
+ retval = -EFAULT;
+ goto exit;
+ }
+
+ /* send off the urb */
+ usb_fill_int_urb(
+ dev->interrupt_out_urb,
+ dev->udev,
+ usb_sndintpipe(dev->udev, dev->interrupt_out_endpoint->bEndpointAddress),
+ dev->interrupt_out_buffer,
+ bytes_to_write,
+ adu_interrupt_out_callback,
+ dev,
+ dev->interrupt_in_endpoint->bInterval);
+ /* dev->interrupt_in_urb->transfer_flags |= URB_ASYNC_UNLINK; */
+ dev->interrupt_out_urb->actual_length = bytes_to_write;
+ retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
+ if (retval < 0) {
+ err("Couldn't submit interrupt_out_urb %d", retval);
+ goto exit;
+ }
+
+ buffer += bytes_to_write;
+ count -= bytes_to_write;
+
+ bytes_written += bytes_to_write;
+ }
+ }
+
+ retval = bytes_written;
+
+exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+ dbg(2," %s : leave, return value %d", __FUNCTION__, retval);
+
+ return retval;
+}
+
+/* file operations needed when we register this driver */
+static struct file_operations adu_fops = {
+ .owner = THIS_MODULE,
+ .read = adu_read,
+ .write = adu_write,
+ .open = adu_open,
+ .release = adu_release,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver adu_class = {
+ .name = "usb/adutux%d",
+ .fops = &adu_fops,
+ .minor_base = ADU_MINOR_BASE,
+};
+
+/**
+ * adu_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int adu_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct adu_device *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ int retval = -ENODEV;
+ int in_end_size;
+ int out_end_size;
+ int i;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ if (udev == NULL) {
+ dev_err(&interface->dev, "udev is NULL.\n");
+ goto exit;
+ }
+
+ /* allocate memory for our device state and intialize it */
+ dev = kzalloc(sizeof(struct adu_device), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ retval = -ENOMEM;
+ goto exit;
+ }
+
+ init_MUTEX(&dev->sem);
+ spin_lock_init(&dev->buflock);
+ dev->udev = udev;
+ init_waitqueue_head(&dev->read_wait);
+ init_waitqueue_head(&dev->write_wait);
+
+ iface_desc = &interface->altsetting[0];
+
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (usb_endpoint_is_int_in(endpoint))
+ dev->interrupt_in_endpoint = endpoint;
+
+ if (usb_endpoint_is_int_out(endpoint))
+ dev->interrupt_out_endpoint = endpoint;
+ }
+ if (dev->interrupt_in_endpoint == NULL) {
+ dev_err(&interface->dev, "interrupt in endpoint not found\n");
+ goto error;
+ }
+ if (dev->interrupt_out_endpoint == NULL) {
+ dev_err(&interface->dev, "interrupt out endpoint not found\n");
+ goto error;
+ }
+
+ in_end_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
+ out_end_size = le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize);
+
+ dev->read_buffer_primary = kmalloc((4 * in_end_size), GFP_KERNEL);
+ if (!dev->read_buffer_primary) {
+ dev_err(&interface->dev, "Couldn't allocate read_buffer_primary\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ /* debug code prime the buffer */
+ memset(dev->read_buffer_primary, 'a', in_end_size);
+ memset(dev->read_buffer_primary + in_end_size, 'b', in_end_size);
+ memset(dev->read_buffer_primary + (2 * in_end_size), 'c', in_end_size);
+ memset(dev->read_buffer_primary + (3 * in_end_size), 'd', in_end_size);
+
+ dev->read_buffer_secondary = kmalloc((4 * in_end_size), GFP_KERNEL);
+ if (!dev->read_buffer_secondary) {
+ dev_err(&interface->dev, "Couldn't allocate read_buffer_secondary\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ /* debug code prime the buffer */
+ memset(dev->read_buffer_secondary, 'e', in_end_size);
+ memset(dev->read_buffer_secondary + in_end_size, 'f', in_end_size);
+ memset(dev->read_buffer_secondary + (2 * in_end_size), 'g', in_end_size);
+ memset(dev->read_buffer_secondary + (3 * in_end_size), 'h', in_end_size);
+
+ dev->interrupt_in_buffer = kmalloc(in_end_size, GFP_KERNEL);
+ if (!dev->interrupt_in_buffer) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_in_buffer\n");
+ goto error;
+ }
+
+ /* debug code prime the buffer */
+ memset(dev->interrupt_in_buffer, 'i', in_end_size);
+
+ dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_in_urb) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_in_urb\n");
+ goto error;
+ }
+ dev->interrupt_out_buffer = kmalloc(out_end_size, GFP_KERNEL);
+ if (!dev->interrupt_out_buffer) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_out_buffer\n");
+ goto error;
+ }
+ dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_out_urb) {
+ dev_err(&interface->dev, "Couldn't allocate interrupt_out_urb\n");
+ goto error;
+ }
+
+ if (!usb_string(udev, udev->descriptor.iSerialNumber, dev->serial_number,
+ sizeof(dev->serial_number))) {
+ dev_err(&interface->dev, "Could not retrieve serial number\n");
+ goto error;
+ }
+ dbg(2," %s : serial_number=%s", __FUNCTION__, dev->serial_number);
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(interface, dev);
+
+ retval = usb_register_dev(interface, &adu_class);
+
+ if (retval) {
+ /* something prevented us from registering this driver */
+ dev_err(&interface->dev, "Not able to get a minor for this device.\n");
+ usb_set_intfdata(interface, NULL);
+ goto error;
+ }
+
+ dev->minor = interface->minor;
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&interface->dev, "ADU%d %s now attached to /dev/usb/adutux%d",
+ udev->descriptor.idProduct, dev->serial_number,
+ (dev->minor - ADU_MINOR_BASE));
+exit:
+ dbg(2," %s : leave, return value %p (dev)", __FUNCTION__, dev);
+
+ return retval;
+
+error:
+ adu_delete(dev);
+ return retval;
+}
+
+/**
+ * adu_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void adu_disconnect(struct usb_interface *interface)
+{
+ struct adu_device *dev;
+ int minor;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ mutex_lock(&disconnect_mutex); /* not interruptible */
+
+ dev = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ down(&dev->sem); /* not interruptible */
+
+ minor = dev->minor;
+
+ /* give back our minor */
+ usb_deregister_dev(interface, &adu_class);
+ dev->minor = 0;
+
+ /* if the device is not opened, then we clean up right now */
+ dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
+ if (!dev->open_count) {
+ up(&dev->sem);
+ adu_delete(dev);
+ } else {
+ dev->udev = NULL;
+ up(&dev->sem);
+ }
+
+ mutex_unlock(&disconnect_mutex);
+
+ dev_info(&interface->dev, "ADU device adutux%d now disconnected",
+ (minor - ADU_MINOR_BASE));
+
+ dbg(2," %s : leave", __FUNCTION__);
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver adu_driver = {
+ .name = "adutux",
+ .probe = adu_probe,
+ .disconnect = adu_disconnect,
+ .id_table = device_table,
+};
+
+static int __init adu_init(void)
+{
+ int result;
+
+ dbg(2," %s : enter", __FUNCTION__);
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&adu_driver);
+ if (result < 0) {
+ err("usb_register failed for the "__FILE__" driver. "
+ "Error number %d", result);
+ goto exit;
+ }
+
+ info("adutux " DRIVER_DESC " " DRIVER_VERSION);
+ info("adutux is an experimental driver. Use at your own risk");
+
+exit:
+ dbg(2," %s : leave, return value %d", __FUNCTION__, result);
+
+ return result;
+}
+
+static void __exit adu_exit(void)
+{
+ dbg(2," %s : enter", __FUNCTION__);
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&adu_driver);
+ dbg(2," %s : leave", __FUNCTION__);
+}
+
+module_init(adu_init);
+module_exit(adu_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c
index bfde82f5d180..6b23a1def9fe 100644
--- a/drivers/usb/misc/appledisplay.c
+++ b/drivers/usb/misc/appledisplay.c
@@ -20,7 +20,6 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -85,7 +84,7 @@ struct appledisplay {
static atomic_t count_displays = ATOMIC_INIT(0);
static struct workqueue_struct *wq;
-static void appledisplay_complete(struct urb *urb, struct pt_regs *regs)
+static void appledisplay_complete(struct urb *urb)
{
struct appledisplay *pdata = urb->context;
unsigned long flags;
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index 1fef36e71c57..0be9d62d62ae 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -267,7 +267,7 @@ typedef struct
/*-------------------------------------------------------------------*/
/* Forwards */
-static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs);
+static void auerswald_ctrlread_complete (struct urb * urb);
static void auerswald_removeservice (pauerswald_t cp, pauerscon_t scp);
static struct usb_driver auerswald_driver;
@@ -277,7 +277,7 @@ static struct usb_driver auerswald_driver;
/* -------------------------- */
/* completion function for chained urbs */
-static void auerchain_complete (struct urb * urb, struct pt_regs *regs)
+static void auerchain_complete (struct urb * urb)
{
unsigned long flags;
int result;
@@ -296,7 +296,7 @@ static void auerchain_complete (struct urb * urb, struct pt_regs *regs)
NOTE: this function may lead to more urbs submitted into the chain.
(no chain lock at calling complete()!)
acp->active != NULL is protecting us against recursion.*/
- urb->complete (urb, regs);
+ urb->complete (urb);
/* detach element from chain data structure */
spin_lock_irqsave (&acp->lock, flags);
@@ -331,7 +331,7 @@ static void auerchain_complete (struct urb * urb, struct pt_regs *regs)
urb->status = result;
dbg("auerchain_complete: usb_submit_urb with error code %d", result);
/* and do error handling via *this* completion function (recursive) */
- auerchain_complete( urb, NULL);
+ auerchain_complete( urb);
}
} else {
/* simple return without submitting a new urb.
@@ -408,7 +408,7 @@ static int auerchain_submit_urb_list (pauerchain_t acp, struct urb * urb, int ea
urb->status = result;
dbg("auerchain_submit_urb: usb_submit_urb with error code %d", result);
/* and do error handling via completion function */
- auerchain_complete( urb, NULL);
+ auerchain_complete( urb);
}
}
@@ -448,7 +448,7 @@ static int auerchain_unlink_urb (pauerchain_t acp, struct urb * urb)
spin_unlock_irqrestore (&acp->lock, flags);
dbg ("unlink waiting urb");
urb->status = -ENOENT;
- urb->complete (urb, NULL);
+ urb->complete (urb);
return 0;
}
}
@@ -505,7 +505,7 @@ static void auerchain_unlink_all (pauerchain_t acp)
spin_unlock_irqrestore (&acp->lock, flags);
dbg ("unlink waiting urb");
urbp->status = -ENOENT;
- urbp->complete (urbp, NULL);
+ urbp->complete (urbp);
spin_lock_irqsave (&acp->lock, flags);
}
spin_unlock_irqrestore (&acp->lock, flags);
@@ -591,7 +591,7 @@ ac_fail:/* free the elements */
/* completion handler for synchronous chained URBs */
-static void auerchain_blocking_completion (struct urb *urb, struct pt_regs *regs)
+static void auerchain_blocking_completion (struct urb *urb)
{
pauerchain_chs_t pchs = (pauerchain_chs_t)urb->context;
pchs->done = 1;
@@ -806,7 +806,7 @@ static void auerbuf_releasebuf( pauerbuf_t bp)
0 Initial, OK
-EINPROGRESS during submission until end
-ENOENT if urb is unlinked
--ETIMEDOUT Transfer timed out, NAK
+-ETIME Device did not respond
-ENOMEM Memory Overflow
-ENODEV Specified USB-device or bus doesn't exist
-ENXIO URB already queued
@@ -832,7 +832,7 @@ static int auerswald_status_retry (int status)
{
switch (status) {
case 0:
- case -ETIMEDOUT:
+ case -ETIME:
case -EOVERFLOW:
case -EAGAIN:
case -EPIPE:
@@ -846,7 +846,7 @@ static int auerswald_status_retry (int status)
}
/* Completion of asynchronous write block */
-static void auerchar_ctrlwrite_complete (struct urb * urb, struct pt_regs *regs)
+static void auerchar_ctrlwrite_complete (struct urb * urb)
{
pauerbuf_t bp = (pauerbuf_t) urb->context;
pauerswald_t cp = ((pauerswald_t)((char *)(bp->list)-(unsigned long)(&((pauerswald_t)0)->bufctl)));
@@ -859,7 +859,7 @@ static void auerchar_ctrlwrite_complete (struct urb * urb, struct pt_regs *regs)
}
/* Completion handler for dummy retry packet */
-static void auerswald_ctrlread_wretcomplete (struct urb * urb, struct pt_regs *regs)
+static void auerswald_ctrlread_wretcomplete (struct urb * urb)
{
pauerbuf_t bp = (pauerbuf_t) urb->context;
pauerswald_t cp;
@@ -893,12 +893,12 @@ static void auerswald_ctrlread_wretcomplete (struct urb * urb, struct pt_regs *r
if (ret) {
dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
bp->urbp->status = ret;
- auerswald_ctrlread_complete (bp->urbp, NULL);
+ auerswald_ctrlread_complete (bp->urbp);
}
}
/* completion handler for receiving of control messages */
-static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs)
+static void auerswald_ctrlread_complete (struct urb * urb)
{
unsigned int serviceid;
pauerswald_t cp;
@@ -941,7 +941,7 @@ static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs)
if (ret) {
dbg ("auerswald_ctrlread_complete: nonzero result of auerchain_submit_urb_list %d", ret);
bp->urbp->status = ret;
- auerswald_ctrlread_wretcomplete (bp->urbp, regs);
+ auerswald_ctrlread_wretcomplete (bp->urbp);
}
return;
}
@@ -970,7 +970,7 @@ static void auerswald_ctrlread_complete (struct urb * urb, struct pt_regs *regs)
messages from the USB device.
*/
/* int completion handler. */
-static void auerswald_int_complete (struct urb * urb, struct pt_regs *regs)
+static void auerswald_int_complete (struct urb * urb)
{
unsigned long flags;
unsigned int channelid;
@@ -1070,7 +1070,7 @@ static void auerswald_int_complete (struct urb * urb, struct pt_regs *regs)
if (ret) {
dbg ("auerswald_int_complete: nonzero result of auerchain_submit_urb %d", ret);
bp->urbp->status = ret;
- auerswald_ctrlread_complete( bp->urbp, NULL);
+ auerswald_ctrlread_complete( bp->urbp);
/* here applies the same problem as above: device locking! */
}
exit:
@@ -1858,7 +1858,7 @@ static int auerchar_release (struct inode *inode, struct file *file)
/*----------------------------------------------------------------------*/
/* File operation structure */
-static struct file_operations auerswald_fops =
+static const struct file_operations auerswald_fops =
{
.owner = THIS_MODULE,
.llseek = no_llseek,
diff --git a/drivers/usb/misc/cypress_cy7c63.c b/drivers/usb/misc/cypress_cy7c63.c
index 9c46746d5d00..b63b5f34b2aa 100644
--- a/drivers/usb/misc/cypress_cy7c63.c
+++ b/drivers/usb/misc/cypress_cy7c63.c
@@ -209,7 +209,7 @@ static int cypress_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "Out of memory!\n");
- goto error;
+ goto error_mem;
}
dev->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -218,15 +218,26 @@ static int cypress_probe(struct usb_interface *interface,
usb_set_intfdata(interface, dev);
/* create device attribute files */
- device_create_file(&interface->dev, &dev_attr_port0);
- device_create_file(&interface->dev, &dev_attr_port1);
+ retval = device_create_file(&interface->dev, &dev_attr_port0);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_port1);
+ if (retval)
+ goto error;
/* let the user know that the device is now attached */
dev_info(&interface->dev,
"Cypress CY7C63xxx device now attached\n");
+ return 0;
- retval = 0;
error:
+ device_remove_file(&interface->dev, &dev_attr_port0);
+ device_remove_file(&interface->dev, &dev_attr_port1);
+ usb_set_intfdata(interface, NULL);
+ usb_put_dev(dev->udev);
+ kfree(dev);
+
+error_mem:
return retval;
}
diff --git a/drivers/usb/misc/cytherm.c b/drivers/usb/misc/cytherm.c
index b20bec445552..04e87acd6e46 100644
--- a/drivers/usb/misc/cytherm.c
+++ b/drivers/usb/misc/cytherm.c
@@ -353,7 +353,7 @@ static int cytherm_probe(struct usb_interface *interface,
dev = kzalloc (sizeof(struct usb_cytherm), GFP_KERNEL);
if (dev == NULL) {
dev_err (&interface->dev, "Out of memory\n");
- goto error;
+ goto error_mem;
}
dev->udev = usb_get_dev(udev);
@@ -362,18 +362,35 @@ static int cytherm_probe(struct usb_interface *interface,
dev->brightness = 0xFF;
- device_create_file(&interface->dev, &dev_attr_brightness);
- device_create_file(&interface->dev, &dev_attr_temp);
- device_create_file(&interface->dev, &dev_attr_button);
- device_create_file(&interface->dev, &dev_attr_port0);
- device_create_file(&interface->dev, &dev_attr_port1);
+ retval = device_create_file(&interface->dev, &dev_attr_brightness);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_temp);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_button);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_port0);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_port1);
+ if (retval)
+ goto error;
- dev_info (&interface->dev,
+ dev_info (&interface->dev,
"Cypress thermometer device now attached\n");
return 0;
-
- error:
+error:
+ device_remove_file(&interface->dev, &dev_attr_brightness);
+ device_remove_file(&interface->dev, &dev_attr_temp);
+ device_remove_file(&interface->dev, &dev_attr_button);
+ device_remove_file(&interface->dev, &dev_attr_port0);
+ device_remove_file(&interface->dev, &dev_attr_port1);
+ usb_set_intfdata (interface, NULL);
+ usb_put_dev(dev->udev);
kfree(dev);
+error_mem:
return retval;
}
diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c
new file mode 100644
index 000000000000..9b591b8b9369
--- /dev/null
+++ b/drivers/usb/misc/ftdi-elan.c
@@ -0,0 +1,2794 @@
+/*
+* USB FTDI client driver for Elan Digital Systems's Uxxx adapters
+*
+* Copyright(C) 2006 Elan Digital Systems Limited
+* http://www.elandigitalsystems.com
+*
+* Author and Maintainer - Tony Olech - Elan Digital Systems
+* tony.olech@elandigitalsystems.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, version 2.
+*
+*
+* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
+* based on various USB client drivers in the 2.6.15 linux kernel
+* with constant reference to the 3rd Edition of Linux Device Drivers
+* published by O'Reilly
+*
+* The U132 adapter is a USB to CardBus adapter specifically designed
+* for PC cards that contain an OHCI host controller. Typical PC cards
+* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
+*
+* The U132 adapter will *NOT *work with PC cards that do not contain
+* an OHCI controller. A simple way to test whether a PC card has an
+* OHCI controller as an interface is to insert the PC card directly
+* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
+* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
+* then there is a good chance that the U132 adapter will support the
+* PC card.(you also need the specific client driver for the PC card)
+*
+* Please inform the Author and Maintainer about any PC cards that
+* contain OHCI Host Controller and work when directly connected to
+* an embedded CardBus slot but do not work when they are connected
+* via an ELAN U132 adapter.
+*
+*/
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/ioctl.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <asm/uaccess.h>
+#include <linux/usb.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+MODULE_AUTHOR("Tony Olech");
+MODULE_DESCRIPTION("FTDI ELAN driver");
+MODULE_LICENSE("GPL");
+#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444)
+extern struct platform_driver u132_platform_driver;
+static struct workqueue_struct *status_queue;
+static struct workqueue_struct *command_queue;
+static struct workqueue_struct *respond_queue;
+/*
+* ftdi_module_lock exists to protect access to global variables
+*
+*/
+static struct semaphore ftdi_module_lock;
+static int ftdi_instances = 0;
+static struct list_head ftdi_static_list;
+/*
+* end of the global variables protected by ftdi_module_lock
+*/
+#include "usb_u132.h"
+#define TD_DEVNOTRESP 5
+/* Define these values to match your devices*/
+#define USB_FTDI_ELAN_VENDOR_ID 0x0403
+#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
+/* table of devices that work with this driver*/
+static struct usb_device_id ftdi_elan_table[] = {
+ {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)},
+ { /* Terminating entry */ }
+};
+
+MODULE_DEVICE_TABLE(usb, ftdi_elan_table);
+/* only the jtag(firmware upgrade device) interface requires
+* a device file and corresponding minor number, but the
+* interface is created unconditionally - I suppose it could
+* be configured or not according to a module parameter.
+* But since we(now) require one interface per device,
+* and since it unlikely that a normal installation would
+* require more than a couple of elan-ftdi devices, 8 seems
+* like a reasonable limit to have here, and if someone
+* really requires more than 8 devices, then they can frig the
+* code and recompile
+*/
+#define USB_FTDI_ELAN_MINOR_BASE 192
+#define COMMAND_BITS 5
+#define COMMAND_SIZE (1<<COMMAND_BITS)
+#define COMMAND_MASK (COMMAND_SIZE-1)
+struct u132_command {
+ u8 header;
+ u16 length;
+ u8 address;
+ u8 width;
+ u32 value;
+ int follows;
+ void *buffer;
+};
+#define RESPOND_BITS 5
+#define RESPOND_SIZE (1<<RESPOND_BITS)
+#define RESPOND_MASK (RESPOND_SIZE-1)
+struct u132_respond {
+ u8 header;
+ u8 address;
+ u32 *value;
+ int *result;
+ struct completion wait_completion;
+};
+struct u132_target {
+ void *endp;
+ struct urb *urb;
+ int toggle_bits;
+ int error_count;
+ int condition_code;
+ int repeat_number;
+ int halted;
+ int skipped;
+ int actual;
+ int non_null;
+ int active;
+ int abandoning;
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code,
+ int repeat_number, int halted, int skipped, int actual,
+ int non_null);
+};
+/* Structure to hold all of our device specific stuff*/
+struct usb_ftdi {
+ struct list_head ftdi_list;
+ struct semaphore u132_lock;
+ int command_next;
+ int command_head;
+ struct u132_command command[COMMAND_SIZE];
+ int respond_next;
+ int respond_head;
+ struct u132_respond respond[RESPOND_SIZE];
+ struct u132_target target[4];
+ char device_name[16];
+ unsigned synchronized:1;
+ unsigned enumerated:1;
+ unsigned registered:1;
+ unsigned initialized:1;
+ unsigned card_ejected:1;
+ int function;
+ int sequence_num;
+ int disconnected;
+ int gone_away;
+ int stuck_status;
+ int status_queue_delay;
+ struct semaphore sw_lock;
+ struct usb_device *udev;
+ struct usb_interface *interface;
+ struct usb_class_driver *class;
+ struct work_struct status_work;
+ struct work_struct command_work;
+ struct work_struct respond_work;
+ struct u132_platform_data platform_data;
+ struct resource resources[0];
+ struct platform_device platform_dev;
+ unsigned char *bulk_in_buffer;
+ size_t bulk_in_size;
+ size_t bulk_in_last;
+ size_t bulk_in_left;
+ __u8 bulk_in_endpointAddr;
+ __u8 bulk_out_endpointAddr;
+ struct kref kref;
+ u32 controlreg;
+ u8 response[4 + 1024];
+ int expected;
+ int recieved;
+ int ed_found;
+};
+#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref)
+#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \
+ platform_dev)
+static struct usb_driver ftdi_elan_driver;
+static void ftdi_elan_delete(struct kref *kref)
+{
+ struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref);
+ dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi);
+ usb_put_dev(ftdi->udev);
+ ftdi->disconnected += 1;
+ down(&ftdi_module_lock);
+ list_del_init(&ftdi->ftdi_list);
+ ftdi_instances -= 1;
+ up(&ftdi_module_lock);
+ kfree(ftdi->bulk_in_buffer);
+ ftdi->bulk_in_buffer = NULL;
+}
+
+static void ftdi_elan_put_kref(struct usb_ftdi *ftdi)
+{
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+static void ftdi_elan_get_kref(struct usb_ftdi *ftdi)
+{
+ kref_get(&ftdi->kref);
+}
+
+static void ftdi_elan_init_kref(struct usb_ftdi *ftdi)
+{
+ kref_init(&ftdi->kref);
+}
+
+static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(status_queue, &ftdi->status_work, delta))
+ return;
+ } else if (queue_work(status_queue, &ftdi->status_work))
+ return;
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+ return;
+}
+
+static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(status_queue, &ftdi->status_work, delta))
+ kref_get(&ftdi->kref);
+ } else if (queue_work(status_queue, &ftdi->status_work))
+ kref_get(&ftdi->kref);
+ return;
+}
+
+static void ftdi_status_cancel_work(struct usb_ftdi *ftdi)
+{
+ if (cancel_delayed_work(&ftdi->status_work))
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(command_queue, &ftdi->command_work,
+ delta))
+ return;
+ } else if (queue_work(command_queue, &ftdi->command_work))
+ return;
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+ return;
+}
+
+static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(command_queue, &ftdi->command_work,
+ delta))
+ kref_get(&ftdi->kref);
+ } else if (queue_work(command_queue, &ftdi->command_work))
+ kref_get(&ftdi->kref);
+ return;
+}
+
+static void ftdi_command_cancel_work(struct usb_ftdi *ftdi)
+{
+ if (cancel_delayed_work(&ftdi->command_work))
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+static void ftdi_response_requeue_work(struct usb_ftdi *ftdi,
+ unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(respond_queue, &ftdi->respond_work,
+ delta))
+ return;
+ } else if (queue_work(respond_queue, &ftdi->respond_work))
+ return;
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+ return;
+}
+
+static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta)
+{
+ if (delta > 0) {
+ if (queue_delayed_work(respond_queue, &ftdi->respond_work,
+ delta))
+ kref_get(&ftdi->kref);
+ } else if (queue_work(respond_queue, &ftdi->respond_work))
+ kref_get(&ftdi->kref);
+ return;
+}
+
+static void ftdi_response_cancel_work(struct usb_ftdi *ftdi)
+{
+ if (cancel_delayed_work(&ftdi->respond_work))
+ kref_put(&ftdi->kref, ftdi_elan_delete);
+}
+
+void ftdi_elan_gone_away(struct platform_device *pdev)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ ftdi->gone_away += 1;
+ ftdi_elan_put_kref(ftdi);
+}
+
+
+EXPORT_SYMBOL_GPL(ftdi_elan_gone_away);
+void ftdi_release_platform_dev(struct device *dev)
+{
+ dev->parent = NULL;
+}
+
+static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
+ struct u132_target *target, u8 *buffer, int length);
+static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi);
+static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi);
+static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi);
+static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi);
+static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi);
+static int ftdi_elan_synchronize(struct usb_ftdi *ftdi);
+static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi);
+static int ftdi_elan_command_engine(struct usb_ftdi *ftdi);
+static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi);
+static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi)
+{
+ int result;
+ if (ftdi->platform_dev.dev.parent)
+ return -EBUSY;
+ ftdi_elan_get_kref(ftdi);
+ ftdi->platform_data.potpg = 100;
+ ftdi->platform_data.reset = NULL;
+ ftdi->platform_dev.id = ftdi->sequence_num;
+ ftdi->platform_dev.resource = ftdi->resources;
+ ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources);
+ ftdi->platform_dev.dev.platform_data = &ftdi->platform_data;
+ ftdi->platform_dev.dev.parent = NULL;
+ ftdi->platform_dev.dev.release = ftdi_release_platform_dev;
+ ftdi->platform_dev.dev.dma_mask = NULL;
+ snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd");
+ ftdi->platform_dev.name = ftdi->device_name;
+ dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd");
+ request_module("u132_hcd");
+ dev_info(&ftdi->udev->dev, "registering '%s'\n",
+ ftdi->platform_dev.name);
+ result = platform_device_register(&ftdi->platform_dev);
+ return result;
+}
+
+static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi)
+{
+ down(&ftdi->u132_lock);
+ while (ftdi->respond_next > ftdi->respond_head) {
+ struct u132_respond *respond = &ftdi->respond[RESPOND_MASK &
+ ftdi->respond_head++];
+ *respond->result = -ESHUTDOWN;
+ *respond->value = 0;
+ complete(&respond->wait_completion);
+ } up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi)
+{
+ int ed_number = 4;
+ down(&ftdi->u132_lock);
+ while (ed_number-- > 0) {
+ struct u132_target *target = &ftdi->target[ed_number];
+ if (target->active == 1) {
+ target->condition_code = TD_DEVNOTRESP;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, NULL, 0);
+ down(&ftdi->u132_lock);
+ }
+ }
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi)
+{
+ int ed_number = 4;
+ down(&ftdi->u132_lock);
+ while (ed_number-- > 0) {
+ struct u132_target *target = &ftdi->target[ed_number];
+ target->abandoning = 1;
+ wait_1:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x80 | (ed_number << 5) | 0x4;
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait_1;
+ }
+ }
+ wait_2:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x90 | (ed_number << 5);
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait_2;
+ }
+ }
+ }
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi)
+{
+ int ed_number = 4;
+ down(&ftdi->u132_lock);
+ while (ed_number-- > 0) {
+ struct u132_target *target = &ftdi->target[ed_number];
+ target->abandoning = 1;
+ wait:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x80 | (ed_number << 5) | 0x4;
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait;
+ }
+ }
+ }
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ up(&ftdi->u132_lock);
+}
+
+static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi)
+{
+ ftdi_command_queue_work(ftdi, 0);
+ return;
+}
+
+static void ftdi_elan_command_work(void *data)
+{
+ struct usb_ftdi *ftdi = data;
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else {
+ int retval = ftdi_elan_command_engine(ftdi);
+ if (retval == -ESHUTDOWN) {
+ ftdi->disconnected += 1;
+ } else if (retval == -ENODEV) {
+ ftdi->disconnected += 1;
+ } else if (retval)
+ dev_err(&ftdi->udev->dev, "command error %d\n", retval);
+ ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10));
+ return;
+ }
+}
+
+static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi)
+{
+ ftdi_respond_queue_work(ftdi, 0);
+ return;
+}
+
+static void ftdi_elan_respond_work(void *data)
+{
+ struct usb_ftdi *ftdi = data;
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else {
+ int retval = ftdi_elan_respond_engine(ftdi);
+ if (retval == 0) {
+ } else if (retval == -ESHUTDOWN) {
+ ftdi->disconnected += 1;
+ } else if (retval == -ENODEV) {
+ ftdi->disconnected += 1;
+ } else if (retval == -EILSEQ) {
+ ftdi->disconnected += 1;
+ } else {
+ ftdi->disconnected += 1;
+ dev_err(&ftdi->udev->dev, "respond error %d\n", retval);
+ }
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_abandon_completions(ftdi);
+ ftdi_elan_abandon_targets(ftdi);
+ }
+ ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10));
+ return;
+ }
+}
+
+
+/*
+* the sw_lock is initially held and will be freed
+* after the FTDI has been synchronized
+*
+*/
+static void ftdi_elan_status_work(void *data)
+{
+ struct usb_ftdi *ftdi = data;
+ int work_delay_in_msec = 0;
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else if (ftdi->synchronized == 0) {
+ down(&ftdi->sw_lock);
+ if (ftdi_elan_synchronize(ftdi) == 0) {
+ ftdi->synchronized = 1;
+ ftdi_command_queue_work(ftdi, 1);
+ ftdi_respond_queue_work(ftdi, 1);
+ up(&ftdi->sw_lock);
+ work_delay_in_msec = 100;
+ } else {
+ dev_err(&ftdi->udev->dev, "synchronize failed\n");
+ up(&ftdi->sw_lock);
+ work_delay_in_msec = 10 *1000;
+ }
+ } else if (ftdi->stuck_status > 0) {
+ if (ftdi_elan_stuck_waiting(ftdi) == 0) {
+ ftdi->stuck_status = 0;
+ ftdi->synchronized = 0;
+ } else if ((ftdi->stuck_status++ % 60) == 1) {
+ dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
+ "- please remove\n");
+ } else
+ dev_err(&ftdi->udev->dev, "WRONG type of card inserted "
+ "- checked %d times\n", ftdi->stuck_status);
+ work_delay_in_msec = 100;
+ } else if (ftdi->enumerated == 0) {
+ if (ftdi_elan_enumeratePCI(ftdi) == 0) {
+ ftdi->enumerated = 1;
+ work_delay_in_msec = 250;
+ } else
+ work_delay_in_msec = 1000;
+ } else if (ftdi->initialized == 0) {
+ if (ftdi_elan_setupOHCI(ftdi) == 0) {
+ ftdi->initialized = 1;
+ work_delay_in_msec = 500;
+ } else {
+ dev_err(&ftdi->udev->dev, "initialized failed - trying "
+ "again in 10 seconds\n");
+ work_delay_in_msec = 10 *1000;
+ }
+ } else if (ftdi->registered == 0) {
+ work_delay_in_msec = 10;
+ if (ftdi_elan_hcd_init(ftdi) == 0) {
+ ftdi->registered = 1;
+ } else
+ dev_err(&ftdi->udev->dev, "register failed\n");
+ work_delay_in_msec = 250;
+ } else {
+ if (ftdi_elan_checkingPCI(ftdi) == 0) {
+ work_delay_in_msec = 250;
+ } else if (ftdi->controlreg & 0x00400000) {
+ if (ftdi->gone_away > 0) {
+ dev_err(&ftdi->udev->dev, "PCI device eject con"
+ "firmed platform_dev.dev.parent=%p plat"
+ "form_dev.dev=%p\n",
+ ftdi->platform_dev.dev.parent,
+ &ftdi->platform_dev.dev);
+ platform_device_unregister(&ftdi->platform_dev);
+ ftdi->platform_dev.dev.parent = NULL;
+ ftdi->registered = 0;
+ ftdi->enumerated = 0;
+ ftdi->card_ejected = 0;
+ ftdi->initialized = 0;
+ ftdi->gone_away = 0;
+ } else
+ ftdi_elan_flush_targets(ftdi);
+ work_delay_in_msec = 250;
+ } else {
+ dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"
+ );
+ ftdi_elan_cancel_targets(ftdi);
+ work_delay_in_msec = 500;
+ ftdi->enumerated = 0;
+ ftdi->initialized = 0;
+ }
+ }
+ if (ftdi->disconnected > 0) {
+ ftdi_elan_put_kref(ftdi);
+ return;
+ } else {
+ ftdi_status_requeue_work(ftdi,
+ msecs_to_jiffies(work_delay_in_msec));
+ return;
+ }
+}
+
+
+/*
+* file_operations for the jtag interface
+*
+* the usage count for the device is incremented on open()
+* and decremented on release()
+*/
+static int ftdi_elan_open(struct inode *inode, struct file *file)
+{
+ int subminor = iminor(inode);
+ struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver,
+ subminor);
+ if (!interface) {
+ printk(KERN_ERR "can't find device for minor %d\n", subminor);
+ return -ENODEV;
+ } else {
+ struct usb_ftdi *ftdi = usb_get_intfdata(interface);
+ if (!ftdi) {
+ return -ENODEV;
+ } else {
+ if (down_interruptible(&ftdi->sw_lock)) {
+ return -EINTR;
+ } else {
+ ftdi_elan_get_kref(ftdi);
+ file->private_data = ftdi;
+ return 0;
+ }
+ }
+ }
+}
+
+static int ftdi_elan_release(struct inode *inode, struct file *file)
+{
+ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
+ if (ftdi == NULL)
+ return -ENODEV;
+ up(&ftdi->sw_lock); /* decrement the count on our device */
+ ftdi_elan_put_kref(ftdi);
+ return 0;
+}
+
+
+#define FTDI_ELAN_IOC_MAGIC 0xA1
+#define FTDI_ELAN_IOCDEBUG _IOC(_IOC_WRITE, FTDI_ELAN_IOC_MAGIC, 1, 132)
+static int ftdi_elan_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+ case FTDI_ELAN_IOCDEBUG:{
+ char line[132];
+ int size = strncpy_from_user(line,
+ (const char __user *)arg, sizeof(line));
+ if (size < 0) {
+ return -EINVAL;
+ } else {
+ printk(KERN_ERR "TODO: ioctl %s\n", line);
+ return 0;
+ }
+ }
+ default:
+ return -EFAULT;
+ }
+}
+
+
+/*
+*
+* blocking bulk reads are used to get data from the device
+*
+*/
+static ssize_t ftdi_elan_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char data[30 *3 + 4];
+ char *d = data;
+ int m = (sizeof(data) - 1) / 3;
+ int bytes_read = 0;
+ int retry_on_empty = 10;
+ int retry_on_timeout = 5;
+ struct usb_ftdi *ftdi = (struct usb_ftdi *)file->private_data;
+ if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ }
+ data[0] = 0;
+ have:if (ftdi->bulk_in_left > 0) {
+ if (count-- > 0) {
+ char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer;
+ ftdi->bulk_in_left -= 1;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X", 0x000000FF & *p);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ if (copy_to_user(buffer++, p, 1)) {
+ return -EFAULT;
+ } else {
+ bytes_read += 1;
+ goto have;
+ }
+ } else
+ return bytes_read;
+ }
+ more:if (count > 0) {
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(50));
+ if (packet_bytes > 2) {
+ ftdi->bulk_in_left = packet_bytes - 2;
+ ftdi->bulk_in_last = 1;
+ goto have;
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto more;
+ } else if (bytes_read > 0) {
+ return bytes_read;
+ } else
+ return retval;
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return bytes_read;
+ } else
+ return retval;
+ } else
+ return bytes_read;
+}
+
+static void ftdi_elan_write_bulk_callback(struct urb *urb)
+{
+ struct usb_ftdi *ftdi = (struct usb_ftdi *)urb->context;
+ if (urb->status && !(urb->status == -ENOENT || urb->status ==
+ -ECONNRESET || urb->status == -ESHUTDOWN)) {
+ dev_err(&ftdi->udev->dev, "urb=%p write bulk status received: %"
+ "d\n", urb, urb->status);
+ }
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ urb->transfer_buffer, urb->transfer_dma);
+}
+
+static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi,
+ char *buf, int command_size, int total_size)
+{
+ int ed_commands = 0;
+ int b = 0;
+ int I = command_size;
+ int i = ftdi->command_head;
+ while (I-- > 0) {
+ struct u132_command *command = &ftdi->command[COMMAND_MASK &
+ i++];
+ int F = command->follows;
+ u8 *f = command->buffer;
+ if (command->header & 0x80) {
+ ed_commands |= 1 << (0x3 & (command->header >> 5));
+ }
+ buf[b++] = command->header;
+ buf[b++] = (command->length >> 0) & 0x00FF;
+ buf[b++] = (command->length >> 8) & 0x00FF;
+ buf[b++] = command->address;
+ buf[b++] = command->width;
+ while (F-- > 0) {
+ buf[b++] = *f++;
+ }
+ }
+ return ed_commands;
+}
+
+static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size)
+{
+ int total_size = 0;
+ int I = command_size;
+ int i = ftdi->command_head;
+ while (I-- > 0) {
+ struct u132_command *command = &ftdi->command[COMMAND_MASK &
+ i++];
+ total_size += 5 + command->follows;
+ } return total_size;
+}
+
+static int ftdi_elan_command_engine(struct usb_ftdi *ftdi)
+{
+ int retval;
+ char *buf;
+ int ed_commands;
+ int total_size;
+ struct urb *urb;
+ int command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size == 0)
+ return 0;
+ total_size = ftdi_elan_total_command_size(ftdi, command_size);
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_err(&ftdi->udev->dev, "could not get a urb to write %d comm"
+ "ands totaling %d bytes to the Uxxx\n", command_size,
+ total_size);
+ return -ENOMEM;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, total_size, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ dev_err(&ftdi->udev->dev, "could not get a buffer to write %d c"
+ "ommands totaling %d bytes to the Uxxx\n", command_size,
+ total_size);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf,
+ command_size, total_size);
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, total_size,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ if (ed_commands) {
+ char diag[40 *3 + 4];
+ char *d = diag;
+ int m = total_size;
+ u8 *c = buf;
+ int s = (sizeof(diag) - 1) / 3;
+ diag[0] = 0;
+ while (s-- > 0 && m-- > 0) {
+ if (s > 0 || m == 0) {
+ d += sprintf(d, " %02X", *c++);
+ } else
+ d += sprintf(d, " ..");
+ }
+ }
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write "
+ "%d commands totaling %d bytes to the Uxxx\n", retval,
+ urb, command_size, total_size);
+ usb_buffer_free(ftdi->udev, total_size, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ return retval;
+ }
+ usb_free_urb(urb); /* release our reference to this urb,
+ the USB core will eventually free it entirely */
+ ftdi->command_head += command_size;
+ ftdi_elan_kick_respond_queue(ftdi);
+ return 0;
+}
+
+static void ftdi_elan_do_callback(struct usb_ftdi *ftdi,
+ struct u132_target *target, u8 *buffer, int length)
+{
+ struct urb *urb = target->urb;
+ int halted = target->halted;
+ int skipped = target->skipped;
+ int actual = target->actual;
+ int non_null = target->non_null;
+ int toggle_bits = target->toggle_bits;
+ int error_count = target->error_count;
+ int condition_code = target->condition_code;
+ int repeat_number = target->repeat_number;
+ void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int,
+ int, int, int, int) = target->callback;
+ target->active -= 1;
+ target->callback = NULL;
+ (*callback) (target->endp, urb, buffer, length, toggle_bits,
+ error_count, condition_code, repeat_number, halted, skipped,
+ actual, non_null);
+}
+
+static char *have_ed_set_response(struct usb_ftdi *ftdi,
+ struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
+ char *b)
+{
+ int payload = (ed_length >> 0) & 0x07FF;
+ down(&ftdi->u132_lock);
+ target->actual = 0;
+ target->non_null = (ed_length >> 15) & 0x0001;
+ target->repeat_number = (ed_length >> 11) & 0x000F;
+ if (ed_type == 0x02) {
+ if (payload == 0 || target->abandoning > 0) {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ } else {
+ ftdi->expected = 4 + payload;
+ ftdi->ed_found = 1;
+ up(&ftdi->u132_lock);
+ return b;
+ }
+ } else if (ed_type == 0x03) {
+ if (payload == 0 || target->abandoning > 0) {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ } else {
+ ftdi->expected = 4 + payload;
+ ftdi->ed_found = 1;
+ up(&ftdi->u132_lock);
+ return b;
+ }
+ } else if (ed_type == 0x01) {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ } else {
+ target->abandoning = 0;
+ up(&ftdi->u132_lock);
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+ }
+}
+
+static char *have_ed_get_response(struct usb_ftdi *ftdi,
+ struct u132_target *target, u16 ed_length, int ed_number, int ed_type,
+ char *b)
+{
+ down(&ftdi->u132_lock);
+ target->condition_code = TD_DEVNOTRESP;
+ target->actual = (ed_length >> 0) & 0x01FF;
+ target->non_null = (ed_length >> 15) & 0x0001;
+ target->repeat_number = (ed_length >> 11) & 0x000F;
+ up(&ftdi->u132_lock);
+ if (target->active)
+ ftdi_elan_do_callback(ftdi, target, NULL, 0);
+ target->abandoning = 0;
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ return ftdi->response;
+}
+
+
+/*
+* The engine tries to empty the FTDI fifo
+*
+* all responses found in the fifo data are dispatched thus
+* the response buffer can only ever hold a maximum sized
+* response from the Uxxx.
+*
+*/
+static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi)
+{
+ u8 *b = ftdi->response + ftdi->recieved;
+ int bytes_read = 0;
+ int retry_on_empty = 1;
+ int retry_on_timeout = 3;
+ int empty_packets = 0;
+ read:{
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(500));
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = packet_bytes;
+ u8 *c = ftdi->bulk_in_buffer;
+ int s = (sizeof(diag) - 1) / 3;
+ diag[0] = 0;
+ while (s-- > 0 && m-- > 0) {
+ if (s > 0 || m == 0) {
+ d += sprintf(d, " %02X", *c++);
+ } else
+ d += sprintf(d, " ..");
+ }
+ if (packet_bytes > 2) {
+ ftdi->bulk_in_left = packet_bytes - 2;
+ ftdi->bulk_in_last = 1;
+ goto have;
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
+ "t_bytes = %d with total %d bytes%s\n",
+ packet_bytes, bytes_read, diag);
+ goto more;
+ } else if (bytes_read > 0) {
+ dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n",
+ bytes_read, diag);
+ return -ENOMEM;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT with packe"
+ "t_bytes = %d with total %d bytes%s\n",
+ packet_bytes, bytes_read, diag);
+ return -ENOMEM;
+ }
+ } else if (retval == -EILSEQ) {
+ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
+ " = %d with total %d bytes%s\n", retval,
+ packet_bytes, bytes_read, diag);
+ return retval;
+ } else if (retval) {
+ dev_err(&ftdi->udev->dev, "error = %d with packet_bytes"
+ " = %d with total %d bytes%s\n", retval,
+ packet_bytes, bytes_read, diag);
+ return retval;
+ } else if (packet_bytes == 2) {
+ unsigned char s0 = ftdi->bulk_in_buffer[0];
+ unsigned char s1 = ftdi->bulk_in_buffer[1];
+ empty_packets += 1;
+ if (s0 == 0x31 && s1 == 0x60) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ } else if (s0 == 0x31 && s1 == 0x00) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ } else {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ }
+ } else if (packet_bytes == 1) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ } else {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else
+ return 0;
+ }
+ }
+ more:{
+ goto read;
+ }
+ have:if (ftdi->bulk_in_left > 0) {
+ u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last];
+ bytes_read += 1;
+ ftdi->bulk_in_left -= 1;
+ if (ftdi->recieved == 0 && c == 0xFF) {
+ goto have;
+ } else
+ *b++ = c;
+ if (++ftdi->recieved < ftdi->expected) {
+ goto have;
+ } else if (ftdi->ed_found) {
+ int ed_number = (ftdi->response[0] >> 5) & 0x03;
+ u16 ed_length = (ftdi->response[2] << 8) |
+ ftdi->response[1];
+ struct u132_target *target = &ftdi->target[ed_number];
+ int payload = (ed_length >> 0) & 0x07FF;
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = payload;
+ u8 *c = 4 + ftdi->response;
+ int s = (sizeof(diag) - 1) / 3;
+ diag[0] = 0;
+ while (s-- > 0 && m-- > 0) {
+ if (s > 0 || m == 0) {
+ d += sprintf(d, " %02X", *c++);
+ } else
+ d += sprintf(d, " ..");
+ }
+ ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response,
+ payload);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ b = ftdi->response;
+ goto have;
+ } else if (ftdi->expected == 8) {
+ u8 buscmd;
+ int respond_head = ftdi->respond_head++;
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & respond_head];
+ u32 data = ftdi->response[7];
+ data <<= 8;
+ data |= ftdi->response[6];
+ data <<= 8;
+ data |= ftdi->response[5];
+ data <<= 8;
+ data |= ftdi->response[4];
+ *respond->value = data;
+ *respond->result = 0;
+ complete(&respond->wait_completion);
+ ftdi->recieved = 0;
+ ftdi->expected = 4;
+ ftdi->ed_found = 0;
+ b = ftdi->response;
+ buscmd = (ftdi->response[0] >> 0) & 0x0F;
+ if (buscmd == 0x00) {
+ } else if (buscmd == 0x02) {
+ } else if (buscmd == 0x06) {
+ } else if (buscmd == 0x0A) {
+ } else
+ dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) va"
+ "lue = %08X\n", buscmd, data);
+ goto have;
+ } else {
+ if ((ftdi->response[0] & 0x80) == 0x00) {
+ ftdi->expected = 8;
+ goto have;
+ } else {
+ int ed_number = (ftdi->response[0] >> 5) & 0x03;
+ int ed_type = (ftdi->response[0] >> 0) & 0x03;
+ u16 ed_length = (ftdi->response[2] << 8) |
+ ftdi->response[1];
+ struct u132_target *target = &ftdi->target[
+ ed_number];
+ target->halted = (ftdi->response[0] >> 3) &
+ 0x01;
+ target->skipped = (ftdi->response[0] >> 2) &
+ 0x01;
+ target->toggle_bits = (ftdi->response[3] >> 6)
+ & 0x03;
+ target->error_count = (ftdi->response[3] >> 4)
+ & 0x03;
+ target->condition_code = (ftdi->response[
+ 3] >> 0) & 0x0F;
+ if ((ftdi->response[0] & 0x10) == 0x00) {
+ b = have_ed_set_response(ftdi, target,
+ ed_length, ed_number, ed_type,
+ b);
+ goto have;
+ } else {
+ b = have_ed_get_response(ftdi, target,
+ ed_length, ed_number, ed_type,
+ b);
+ goto have;
+ }
+ }
+ }
+ } else
+ goto more;
+}
+
+
+/*
+* create a urb, and a buffer for it, and copy the data to the urb
+*
+*/
+static ssize_t ftdi_elan_write(struct file *file,
+ const char __user *user_buffer, size_t count,
+ loff_t *ppos)
+{
+ int retval = 0;
+ struct urb *urb;
+ char *buf;
+ struct usb_ftdi *ftdi = file->private_data;
+
+ if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ }
+ if (count == 0) {
+ goto exit;
+ }
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ retval = -ENOMEM;
+ goto error_1;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, count, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!buf) {
+ retval = -ENOMEM;
+ goto error_2;
+ }
+ if (copy_from_user(buf, user_buffer, count)) {
+ retval = -EFAULT;
+ goto error_3;
+ }
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, count,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed submitting write urb, error %"
+ "d\n", retval);
+ goto error_3;
+ }
+ usb_free_urb(urb);
+
+exit:
+ return count;
+error_3:
+ usb_buffer_free(ftdi->udev, count, buf, urb->transfer_dma);
+error_2:
+ usb_free_urb(urb);
+error_1:
+ return retval;
+}
+
+static struct file_operations ftdi_elan_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .ioctl = ftdi_elan_ioctl,
+ .read = ftdi_elan_read,
+ .write = ftdi_elan_write,
+ .open = ftdi_elan_open,
+ .release = ftdi_elan_release,
+};
+
+/*
+* usb class driver info in order to get a minor number from the usb core,
+* and to have the device registered with the driver core
+*/
+static struct usb_class_driver ftdi_elan_jtag_class = {
+ .name = "ftdi-%d-jtag",
+ .fops = &ftdi_elan_fops,
+ .minor_base = USB_FTDI_ELAN_MINOR_BASE,
+};
+
+/*
+* the following definitions are for the
+* ELAN FPGA state machgine processor that
+* lies on the other side of the FTDI chip
+*/
+#define cPCIu132rd 0x0
+#define cPCIu132wr 0x1
+#define cPCIiord 0x2
+#define cPCIiowr 0x3
+#define cPCImemrd 0x6
+#define cPCImemwr 0x7
+#define cPCIcfgrd 0xA
+#define cPCIcfgwr 0xB
+#define cPCInull 0xF
+#define cU132cmd_status 0x0
+#define cU132flash 0x1
+#define cPIDsetup 0x0
+#define cPIDout 0x1
+#define cPIDin 0x2
+#define cPIDinonce 0x3
+#define cCCnoerror 0x0
+#define cCCcrc 0x1
+#define cCCbitstuff 0x2
+#define cCCtoggle 0x3
+#define cCCstall 0x4
+#define cCCnoresp 0x5
+#define cCCbadpid1 0x6
+#define cCCbadpid2 0x7
+#define cCCdataoverrun 0x8
+#define cCCdataunderrun 0x9
+#define cCCbuffoverrun 0xC
+#define cCCbuffunderrun 0xD
+#define cCCnotaccessed 0xF
+static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data)
+{
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x00 | cPCIu132wr;
+ command->length = 0x04;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 4;
+ command->value = data;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset,
+ u8 width, u32 data)
+{
+ u8 addressofs = config_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x00 | (cPCIcfgwr & 0x0F);
+ command->length = 0x04;
+ command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 4;
+ command->value = data;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset,
+ u8 width, u32 data)
+{
+ u8 addressofs = mem_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x00 | (cPCImemwr & 0x0F);
+ command->length = 0x04;
+ command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 4;
+ command->value = data;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset,
+ u8 width, u32 data)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem);
+static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data)
+{
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ int respond_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ respond_size = ftdi->respond_next - ftdi->respond_head;
+ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
+ {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & ftdi->respond_next];
+ int result = -ENODEV;
+ respond->result = &result;
+ respond->header = command->header = 0x00 | cPCIu132rd;
+ command->length = 0x04;
+ respond->address = command->address = cU132cmd_status;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ respond->value = data;
+ init_completion(&respond->wait_completion);
+ ftdi->command_next += 1;
+ ftdi->respond_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ wait_for_completion(&respond->wait_completion);
+ return result;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_read_reg(struct platform_device *pdev, u32 *data)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_read_reg(ftdi, data);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_reg);
+static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset,
+ u8 width, u32 *data)
+{
+ u8 addressofs = config_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ int respond_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ respond_size = ftdi->respond_next - ftdi->respond_head;
+ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
+ {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & ftdi->respond_next];
+ int result = -ENODEV;
+ respond->result = &result;
+ respond->header = command->header = 0x00 | (cPCIcfgrd &
+ 0x0F);
+ command->length = 0x04;
+ respond->address = command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ respond->value = data;
+ init_completion(&respond->wait_completion);
+ ftdi->command_next += 1;
+ ftdi->respond_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ wait_for_completion(&respond->wait_completion);
+ return result;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset,
+ u8 width, u32 *data)
+{
+ u8 addressofs = mem_offset / 4;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ int respond_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ respond_size = ftdi->respond_next - ftdi->respond_head;
+ if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE)
+ {
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ struct u132_respond *respond = &ftdi->respond[
+ RESPOND_MASK & ftdi->respond_next];
+ int result = -ENODEV;
+ respond->result = &result;
+ respond->header = command->header = 0x00 | (cPCImemrd &
+ 0x0F);
+ command->length = 0x04;
+ respond->address = command->address = addressofs;
+ command->width = 0x00 | (width & 0x0F);
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ respond->value = data;
+ init_completion(&respond->wait_completion);
+ ftdi->command_next += 1;
+ ftdi->respond_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ wait_for_completion(&respond->wait_completion);
+ return result;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset,
+ u8 width, u32 *data)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else
+ return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem);
+static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x80 | (ed << 5);
+ command->length = 0x8007;
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 8;
+ command->value = 0;
+ command->buffer = urb->setup_packet;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup);
+static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ int remaining_length = urb->transfer_buffer_length -
+ urb->actual_length;
+ command->header = 0x82 | (ed << 5);
+ if (remaining_length == 0) {
+ command->length = 0x0000;
+ } else if (remaining_length > 1024) {
+ command->length = 0x8000 | 1023;
+ } else
+ command->length = 0x8000 | (remaining_length -
+ 1);
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input);
+static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x81 | (ed << 5);
+ command->length = 0x0000;
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty);
+static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ u8 *b;
+ u16 urb_size;
+ int i = 0;
+ char data[30 *3 + 4];
+ char *d = data;
+ int m = (sizeof(data) - 1) / 3;
+ int l = 0;
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x81 | (ed << 5);
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = min(1024,
+ urb->transfer_buffer_length -
+ urb->actual_length);
+ command->value = 0;
+ command->buffer = urb->transfer_buffer +
+ urb->actual_length;
+ command->length = 0x8000 | (command->follows - 1);
+ b = command->buffer;
+ urb_size = command->follows;
+ data[0] = 0;
+ while (urb_size-- > 0) {
+ if (i > m) {
+ } else if (i++ < m) {
+ int w = sprintf(d, " %02X", *b++);
+ d += w;
+ l += w;
+ } else
+ d += sprintf(d, " ..");
+ }
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output);
+static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ u8 ed = ed_number - 1;
+ wait:if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ int command_size;
+ down(&ftdi->u132_lock);
+ command_size = ftdi->command_next - ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ int remaining_length = urb->transfer_buffer_length -
+ urb->actual_length;
+ struct u132_target *target = &ftdi->target[ed];
+ struct u132_command *command = &ftdi->command[
+ COMMAND_MASK & ftdi->command_next];
+ command->header = 0x83 | (ed << 5);
+ if (remaining_length == 0) {
+ command->length = 0x0000;
+ } else if (remaining_length > 1024) {
+ command->length = 0x8000 | 1023;
+ } else
+ command->length = 0x8000 | (remaining_length -
+ 1);
+ command->address = (toggle_bits << 6) | (ep_number << 2)
+ | (address << 0);
+ command->width = usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe));
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = NULL;
+ target->callback = callback;
+ target->endp = endp;
+ target->urb = urb;
+ target->active = 1;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ goto wait;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null))
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address,
+ ep_number, toggle_bits, callback);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single);
+static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number,
+ void *endp)
+{
+ u8 ed = ed_number - 1;
+ if (ftdi->disconnected > 0) {
+ return -ENODEV;
+ } else if (ftdi->initialized == 0) {
+ return -ENODEV;
+ } else {
+ struct u132_target *target = &ftdi->target[ed];
+ down(&ftdi->u132_lock);
+ if (target->abandoning > 0) {
+ up(&ftdi->u132_lock);
+ return 0;
+ } else {
+ target->abandoning = 1;
+ wait_1:if (target->active == 1) {
+ int command_size = ftdi->command_next -
+ ftdi->command_head;
+ if (command_size < COMMAND_SIZE) {
+ struct u132_command *command =
+ &ftdi->command[COMMAND_MASK &
+ ftdi->command_next];
+ command->header = 0x80 | (ed << 5) |
+ 0x4;
+ command->length = 0x00;
+ command->address = 0x00;
+ command->width = 0x00;
+ command->follows = 0;
+ command->value = 0;
+ command->buffer = &command->value;
+ ftdi->command_next += 1;
+ ftdi_elan_kick_command_queue(ftdi);
+ } else {
+ up(&ftdi->u132_lock);
+ msleep(100);
+ down(&ftdi->u132_lock);
+ goto wait_1;
+ }
+ }
+ up(&ftdi->u132_lock);
+ return 0;
+ }
+ }
+}
+
+int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
+ void *endp)
+{
+ struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev);
+ return ftdi_elan_edset_flush(ftdi, ed_number, endp);
+}
+
+
+EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush);
+static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi)
+{
+ int retry_on_empty = 10;
+ int retry_on_timeout = 5;
+ int retry_on_status = 20;
+ more:{
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(100));
+ if (packet_bytes > 2) {
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = (sizeof(diag) - 1) / 3;
+ char *b = ftdi->bulk_in_buffer;
+ int bytes_read = 0;
+ diag[0] = 0;
+ while (packet_bytes-- > 0) {
+ char c = *b++;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X",
+ 0x000000FF & c);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ bytes_read += 1;
+ continue;
+ }
+ goto more;
+ } else if (packet_bytes > 1) {
+ char s1 = ftdi->bulk_in_buffer[0];
+ char s2 = ftdi->bulk_in_buffer[1];
+ if (s1 == 0x31 && s2 == 0x60) {
+ return 0;
+ } else if (retry_on_status-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
+ "imit reached\n");
+ return -EFAULT;
+ }
+ } else if (packet_bytes > 0) {
+ char b1 = ftdi->bulk_in_buffer[0];
+ dev_err(&ftdi->udev->dev, "only one byte flushed from F"
+ "TDI = %02X\n", b1);
+ if (retry_on_status-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
+ "imit reached\n");
+ return -EFAULT;
+ }
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
+ "t reached\n");
+ return -ENOMEM;
+ }
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "empty packet retry l"
+ "imit reached\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(&ftdi->udev->dev, "error = %d\n", retval);
+ return retval;
+ }
+ }
+ return -1;
+}
+
+
+/*
+* send the long flush sequence
+*
+*/
+static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi)
+{
+ int retval;
+ struct urb *urb;
+ char *buf;
+ int I = 257;
+ int i = 0;
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_err(&ftdi->udev->dev, "could not alloc a urb for flush sequ"
+ "ence\n");
+ return -ENOMEM;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
+ if (!buf) {
+ dev_err(&ftdi->udev->dev, "could not get a buffer for flush seq"
+ "uence\n");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ while (I-- > 0)
+ buf[i++] = 0x55;
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, i,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
+ "flush sequence\n");
+ usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ usb_free_urb(urb);
+ return 0;
+}
+
+
+/*
+* send the reset sequence
+*
+*/
+static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi)
+{
+ int retval;
+ struct urb *urb;
+ char *buf;
+ int I = 4;
+ int i = 0;
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ dev_err(&ftdi->udev->dev, "could not get a urb for the reset se"
+ "quence\n");
+ return -ENOMEM;
+ }
+ buf = usb_buffer_alloc(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma);
+ if (!buf) {
+ dev_err(&ftdi->udev->dev, "could not get a buffer for the reset"
+ " sequence\n");
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ buf[i++] = 0x55;
+ buf[i++] = 0xAA;
+ buf[i++] = 0x5A;
+ buf[i++] = 0xA5;
+ usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev,
+ ftdi->bulk_out_endpointAddr), buf, i,
+ ftdi_elan_write_bulk_callback, ftdi);
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ retval = usb_submit_urb(urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "failed to submit urb containing the "
+ "reset sequence\n");
+ usb_buffer_free(ftdi->udev, i, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ return -ENOMEM;
+ }
+ usb_free_urb(urb);
+ return 0;
+}
+
+static int ftdi_elan_synchronize(struct usb_ftdi *ftdi)
+{
+ int retval;
+ int long_stop = 10;
+ int retry_on_timeout = 5;
+ int retry_on_empty = 10;
+ int err_count = 0;
+ retval = ftdi_elan_flush_input_fifo(ftdi);
+ if (retval)
+ return retval;
+ ftdi->bulk_in_left = 0;
+ ftdi->bulk_in_last = -1;
+ while (long_stop-- > 0) {
+ int read_stop;
+ int read_stuck;
+ retval = ftdi_elan_synchronize_flush(ftdi);
+ if (retval)
+ return retval;
+ retval = ftdi_elan_flush_input_fifo(ftdi);
+ if (retval)
+ return retval;
+ reset:retval = ftdi_elan_synchronize_reset(ftdi);
+ if (retval)
+ return retval;
+ read_stop = 100;
+ read_stuck = 10;
+ read:{
+ int packet_bytes = 0;
+ retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev,
+ ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(500));
+ if (packet_bytes > 2) {
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = (sizeof(diag) - 1) / 3;
+ char *b = ftdi->bulk_in_buffer;
+ int bytes_read = 0;
+ unsigned char c = 0;
+ diag[0] = 0;
+ while (packet_bytes-- > 0) {
+ c = *b++;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X", c);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ bytes_read += 1;
+ continue;
+ }
+ if (c == 0x7E) {
+ return 0;
+ } else {
+ if (c == 0x55) {
+ goto read;
+ } else if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retr"
+ "y limit reached\n");
+ continue;
+ }
+ }
+ } else if (packet_bytes > 1) {
+ unsigned char s1 = ftdi->bulk_in_buffer[0];
+ unsigned char s2 = ftdi->bulk_in_buffer[1];
+ if (s1 == 0x31 && s2 == 0x00) {
+ if (read_stuck-- > 0) {
+ goto read;
+ } else
+ goto reset;
+ } else if (s1 == 0x31 && s2 == 0x60) {
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retr"
+ "y limit reached\n");
+ continue;
+ }
+ } else {
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retr"
+ "y limit reached\n");
+ continue;
+ }
+ }
+ } else if (packet_bytes > 0) {
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retry limit "
+ "reached\n");
+ continue;
+ }
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT re"
+ "try limit reached\n");
+ continue;
+ }
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "empty packet"
+ " retry limit reached\n");
+ continue;
+ }
+ } else {
+ err_count += 1;
+ dev_err(&ftdi->udev->dev, "error = %d\n",
+ retval);
+ if (read_stop-- > 0) {
+ goto read;
+ } else {
+ dev_err(&ftdi->udev->dev, "retry limit "
+ "reached\n");
+ continue;
+ }
+ }
+ }
+ }
+ dev_err(&ftdi->udev->dev, "failed to synchronize\n");
+ return -EFAULT;
+}
+
+static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi)
+{
+ int retry_on_empty = 10;
+ int retry_on_timeout = 5;
+ int retry_on_status = 50;
+ more:{
+ int packet_bytes = 0;
+ int retval = usb_bulk_msg(ftdi->udev,
+ usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr),
+ ftdi->bulk_in_buffer, ftdi->bulk_in_size,
+ &packet_bytes, msecs_to_jiffies(1000));
+ if (packet_bytes > 2) {
+ char diag[30 *3 + 4];
+ char *d = diag;
+ int m = (sizeof(diag) - 1) / 3;
+ char *b = ftdi->bulk_in_buffer;
+ int bytes_read = 0;
+ diag[0] = 0;
+ while (packet_bytes-- > 0) {
+ char c = *b++;
+ if (bytes_read < m) {
+ d += sprintf(d, " %02X",
+ 0x000000FF & c);
+ } else if (bytes_read > m) {
+ } else
+ d += sprintf(d, " ..");
+ bytes_read += 1;
+ continue;
+ }
+ goto more;
+ } else if (packet_bytes > 1) {
+ char s1 = ftdi->bulk_in_buffer[0];
+ char s2 = ftdi->bulk_in_buffer[1];
+ if (s1 == 0x31 && s2 == 0x60) {
+ return 0;
+ } else if (retry_on_status-- > 0) {
+ msleep(5);
+ goto more;
+ } else
+ return -EFAULT;
+ } else if (packet_bytes > 0) {
+ char b1 = ftdi->bulk_in_buffer[0];
+ dev_err(&ftdi->udev->dev, "only one byte flushed from F"
+ "TDI = %02X\n", b1);
+ if (retry_on_status-- > 0) {
+ msleep(5);
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "STATUS ERROR retry l"
+ "imit reached\n");
+ return -EFAULT;
+ }
+ } else if (retval == -ETIMEDOUT) {
+ if (retry_on_timeout-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "TIMED OUT retry limi"
+ "t reached\n");
+ return -ENOMEM;
+ }
+ } else if (retval == 0) {
+ if (retry_on_empty-- > 0) {
+ goto more;
+ } else {
+ dev_err(&ftdi->udev->dev, "empty packet retry l"
+ "imit reached\n");
+ return -ENOMEM;
+ }
+ } else {
+ dev_err(&ftdi->udev->dev, "error = %d\n", retval);
+ return -ENOMEM;
+ }
+ }
+ return -1;
+}
+
+static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi)
+{
+ int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ if (ftdi->controlreg & 0x00400000) {
+ if (ftdi->card_ejected) {
+ } else {
+ ftdi->card_ejected = 1;
+ dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = "
+ "%08X\n", ftdi->controlreg);
+ }
+ return -ENODEV;
+ } else {
+ u8 fn = ftdi->function - 1;
+ int activePCIfn = fn << 8;
+ u32 pcidata;
+ u32 pciVID;
+ u32 pciPID;
+ int reg = 0;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ pciVID = pcidata & 0xFFFF;
+ pciPID = (pcidata >> 16) & 0xFFFF;
+ if (pciVID == ftdi->platform_data.vendor && pciPID ==
+ ftdi->platform_data.device) {
+ return 0;
+ } else {
+ dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X devi"
+ "ce=%04X pciPID=%04X\n",
+ ftdi->platform_data.vendor, pciVID,
+ ftdi->platform_data.device, pciPID);
+ return -ENODEV;
+ }
+ }
+}
+
+static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi)
+{
+ u32 latence_timer;
+ u32 controlreg;
+ int UxxxStatus;
+ u32 pcidata;
+ int reg = 0;
+ int foundOHCI = 0;
+ u8 fn;
+ int activePCIfn = 0;
+ u32 pciVID = 0;
+ u32 pciPID = 0;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L);
+ if (UxxxStatus)
+ return UxxxStatus;
+ msleep(750);
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ msleep(250);
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg);
+ if (UxxxStatus)
+ return UxxxStatus;
+ msleep(1000);
+ for (fn = 0; (fn < 4) && (!foundOHCI); fn++) {
+ activePCIfn = fn << 8;
+ ftdi->function = fn + 1;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ pciVID = pcidata & 0xFFFF;
+ pciPID = (pcidata >> 16) & 0xFFFF;
+ if ((pciVID == 0x1045) && (pciPID == 0xc861)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x1033) && (pciPID == 0x0035)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x10b9) && (pciPID == 0x5237)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x11c1) && (pciPID == 0x5802)) {
+ foundOHCI = 1;
+ } else if ((pciVID == 0x11AB) && (pciPID == 0x1FA6)) {
+ }
+ }
+ if (foundOHCI == 0) {
+ return -ENXIO;
+ }
+ ftdi->platform_data.vendor = pciVID;
+ ftdi->platform_data.device = pciPID;
+ UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800);
+ if (UxxxStatus)
+ return UxxxStatus;
+ reg = 16;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
+ 0xFFFFFFFF);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0,
+ 0xF0000000);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ reg = 12;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &latence_timer);
+ if (UxxxStatus)
+ return UxxxStatus;
+ latence_timer &= 0xFFFF00FF;
+ latence_timer |= 0x00001600;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
+ latence_timer);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ reg = 4;
+ UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00,
+ 0x06);
+ if (UxxxStatus)
+ return UxxxStatus;
+ UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0,
+ &pcidata);
+ if (UxxxStatus)
+ return UxxxStatus;
+ return 0;
+}
+
+static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi)
+{
+ u32 pcidata;
+ int U132Status;
+ int reg;
+ int reset_repeat = 0;
+ do_reset:reg = 8;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x01);
+ if (U132Status)
+ return U132Status;
+ reset_check:{
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ if (pcidata & 1) {
+ msleep(500);
+ if (reset_repeat++ > 100) {
+ reset_repeat = 0;
+ goto do_reset;
+ } else
+ goto reset_check;
+ }
+ }
+ goto dump_regs;
+ msleep(500);
+ reg = 0x28;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x11000000);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x40;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x34;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x2edf2edf);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 4;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0xA0);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ msleep(250);
+ reg = 8;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x0e, 0x04);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x28;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 8;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x48;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x00001200);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x58;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x34;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x28002edf);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ msleep(100);
+ reg = 0x50;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10000);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ power_check:U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ if (!(pcidata & 1)) {
+ msleep(500);
+ goto power_check;
+ }
+ msleep(3000);
+ reg = 0x54;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x58;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x54;
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x10);
+ if (U132Status)
+ return U132Status;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ msleep(750);
+ reg = 0x54;
+ if (0) {
+ U132Status = ftdi_elan_write_pcimem(ftdi, reg, 0x00, 0x02);
+ if (U132Status)
+ return U132Status;
+ }
+ if (0) {
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ }
+ reg = 0x54;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ reg = 0x58;
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ dump_regs:for (reg = 0; reg <= 0x54; reg += 4) {
+ U132Status = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata);
+ if (U132Status)
+ return U132Status;
+ }
+ return 0;
+}
+
+
+/*
+* we use only the first bulk-in and bulk-out endpoints
+*/
+static int ftdi_elan_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ size_t buffer_size;
+ int i;
+ int retval = -ENOMEM;
+ struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+ if (ftdi == NULL) {
+ printk(KERN_ERR "Out of memory\n");
+ return -ENOMEM;
+ }
+ memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+ down(&ftdi_module_lock);
+ list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
+ ftdi->sequence_num = ++ftdi_instances;
+ up(&ftdi_module_lock);
+ ftdi_elan_init_kref(ftdi);
+ init_MUTEX(&ftdi->sw_lock);
+ ftdi->udev = usb_get_dev(interface_to_usbdev(interface));
+ ftdi->interface = interface;
+ init_MUTEX(&ftdi->u132_lock);
+ ftdi->expected = 4;
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (!ftdi->bulk_in_endpointAddr &&
+ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN) && ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
+ {
+ buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ ftdi->bulk_in_size = buffer_size;
+ ftdi->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+ ftdi->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!ftdi->bulk_in_buffer) {
+ dev_err(&ftdi->udev->dev, "Could not allocate b"
+ "ulk_in_buffer\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+ }
+ if (!ftdi->bulk_out_endpointAddr &&
+ ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_OUT) && ((endpoint->bmAttributes &
+ USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK))
+ {
+ ftdi->bulk_out_endpointAddr =
+ endpoint->bEndpointAddress;
+ }
+ }
+ if (!(ftdi->bulk_in_endpointAddr && ftdi->bulk_out_endpointAddr)) {
+ dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk"
+ "-out endpoints\n");
+ retval = -ENODEV;
+ goto error;
+ }
+ dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n",
+ iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr,
+ ftdi->bulk_out_endpointAddr);
+ usb_set_intfdata(interface, ftdi);
+ if (iface_desc->desc.bInterfaceNumber == 0 &&
+ ftdi->bulk_in_endpointAddr == 0x81 &&
+ ftdi->bulk_out_endpointAddr == 0x02) {
+ retval = usb_register_dev(interface, &ftdi_elan_jtag_class);
+ if (retval) {
+ dev_err(&ftdi->udev->dev, "Not able to get a minor for "
+ "this device.\n");
+ usb_set_intfdata(interface, NULL);
+ retval = -ENOMEM;
+ goto error;
+ } else {
+ ftdi->class = &ftdi_elan_jtag_class;
+ dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface "
+ "%d now attached to ftdi%d\n", ftdi,
+ iface_desc->desc.bInterfaceNumber,
+ interface->minor);
+ return 0;
+ }
+ } else if (iface_desc->desc.bInterfaceNumber == 1 &&
+ ftdi->bulk_in_endpointAddr == 0x83 &&
+ ftdi->bulk_out_endpointAddr == 0x04) {
+ ftdi->class = NULL;
+ dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now a"
+ "ctivated\n", ftdi, iface_desc->desc.bInterfaceNumber);
+ INIT_WORK(&ftdi->status_work, ftdi_elan_status_work,
+ (void *)ftdi);
+ INIT_WORK(&ftdi->command_work, ftdi_elan_command_work,
+ (void *)ftdi);
+ INIT_WORK(&ftdi->respond_work, ftdi_elan_respond_work,
+ (void *)ftdi);
+ ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000));
+ return 0;
+ } else {
+ dev_err(&ftdi->udev->dev,
+ "Could not find ELAN's U132 device\n");
+ retval = -ENODEV;
+ goto error;
+ }
+ error:if (ftdi) {
+ ftdi_elan_put_kref(ftdi);
+ }
+ return retval;
+}
+
+static void ftdi_elan_disconnect(struct usb_interface *interface)
+{
+ struct usb_ftdi *ftdi = usb_get_intfdata(interface);
+ ftdi->disconnected += 1;
+ if (ftdi->class) {
+ int minor = interface->minor;
+ struct usb_class_driver *class = ftdi->class;
+ usb_set_intfdata(interface, NULL);
+ usb_deregister_dev(interface, class);
+ dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on min"
+ "or %d now disconnected\n", minor);
+ } else {
+ ftdi_status_cancel_work(ftdi);
+ ftdi_command_cancel_work(ftdi);
+ ftdi_response_cancel_work(ftdi);
+ ftdi_elan_abandon_completions(ftdi);
+ ftdi_elan_abandon_targets(ftdi);
+ if (ftdi->registered) {
+ platform_device_unregister(&ftdi->platform_dev);
+ ftdi->synchronized = 0;
+ ftdi->enumerated = 0;
+ ftdi->registered = 0;
+ }
+ flush_workqueue(status_queue);
+ flush_workqueue(command_queue);
+ flush_workqueue(respond_queue);
+ ftdi->disconnected += 1;
+ usb_set_intfdata(interface, NULL);
+ dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller inter"
+ "face now disconnected\n");
+ }
+ ftdi_elan_put_kref(ftdi);
+}
+
+static struct usb_driver ftdi_elan_driver = {
+ .name = "ftdi-elan",
+ .probe = ftdi_elan_probe,
+ .disconnect = ftdi_elan_disconnect,
+ .id_table = ftdi_elan_table,
+};
+static int __init ftdi_elan_init(void)
+{
+ int result;
+ printk(KERN_INFO "driver %s built at %s on %s\n", ftdi_elan_driver.name,
+ __TIME__, __DATE__);
+ init_MUTEX(&ftdi_module_lock);
+ INIT_LIST_HEAD(&ftdi_static_list);
+ status_queue = create_singlethread_workqueue("ftdi-status-control");
+ command_queue = create_singlethread_workqueue("ftdi-command-engine");
+ respond_queue = create_singlethread_workqueue("ftdi-respond-engine");
+ result = usb_register(&ftdi_elan_driver);
+ if (result)
+ printk(KERN_ERR "usb_register failed. Error number %d\n",
+ result);
+ return result;
+}
+
+static void __exit ftdi_elan_exit(void)
+{
+ struct usb_ftdi *ftdi;
+ struct usb_ftdi *temp;
+ usb_deregister(&ftdi_elan_driver);
+ printk(KERN_INFO "ftdi_u132 driver deregistered\n");
+ list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) {
+ ftdi_status_cancel_work(ftdi);
+ ftdi_command_cancel_work(ftdi);
+ ftdi_response_cancel_work(ftdi);
+ } flush_workqueue(status_queue);
+ destroy_workqueue(status_queue);
+ status_queue = NULL;
+ flush_workqueue(command_queue);
+ destroy_workqueue(command_queue);
+ command_queue = NULL;
+ flush_workqueue(respond_queue);
+ destroy_workqueue(respond_queue);
+ respond_queue = NULL;
+}
+
+
+module_init(ftdi_elan_init);
+module_exit(ftdi_elan_exit);
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index fcd69c52aea9..8e6e195a22ba 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -98,7 +98,7 @@ static int idmouse_probe(struct usb_interface *interface,
static void idmouse_disconnect(struct usb_interface *interface);
/* file operation pointers */
-static struct file_operations idmouse_fops = {
+static const struct file_operations idmouse_fops = {
.owner = THIS_MODULE,
.read = idmouse_read,
.open = idmouse_open,
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
index f30ab1fbb3c8..788a11e6772f 100644
--- a/drivers/usb/misc/ldusb.c
+++ b/drivers/usb/misc/ldusb.c
@@ -212,7 +212,7 @@ static void ld_usb_delete(struct ld_usb *dev)
/**
* ld_usb_interrupt_in_callback
*/
-static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs)
+static void ld_usb_interrupt_in_callback(struct urb *urb)
{
struct ld_usb *dev = urb->context;
size_t *actual_buffer;
@@ -264,7 +264,7 @@ exit:
/**
* ld_usb_interrupt_out_callback
*/
-static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs)
+static void ld_usb_interrupt_out_callback(struct urb *urb)
{
struct ld_usb *dev = urb->context;
@@ -589,7 +589,7 @@ exit:
}
/* file operations needed when we register this driver */
-static struct file_operations ld_usb_fops = {
+static const struct file_operations ld_usb_fops = {
.owner = THIS_MODULE,
.read = ld_usb_read,
.write = ld_usb_write,
@@ -657,15 +657,11 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ if (usb_endpoint_is_int_in(endpoint))
dev->interrupt_in_endpoint = endpoint;
- }
- if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ if (usb_endpoint_is_int_out(endpoint))
dev->interrupt_out_endpoint = endpoint;
- }
}
if (dev->interrupt_in_endpoint == NULL) {
dev_err(&intf->dev, "Interrupt in endpoint not found\n");
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 7699d970e680..27089497e717 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -248,8 +248,8 @@ static loff_t tower_llseek (struct file *file, loff_t off, int whence);
static void tower_abort_transfers (struct lego_usb_tower *dev);
static void tower_check_for_read_packet (struct lego_usb_tower *dev);
-static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs);
-static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs);
+static void tower_interrupt_in_callback (struct urb *urb);
+static void tower_interrupt_out_callback (struct urb *urb);
static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id);
static void tower_disconnect (struct usb_interface *interface);
@@ -259,7 +259,7 @@ static void tower_disconnect (struct usb_interface *interface);
static DEFINE_MUTEX (disconnect_mutex);
/* file operations needed when we register this driver */
-static struct file_operations tower_fops = {
+static const struct file_operations tower_fops = {
.owner = THIS_MODULE,
.read = tower_read,
.write = tower_write,
@@ -755,7 +755,7 @@ exit:
/**
* tower_interrupt_in_callback
*/
-static void tower_interrupt_in_callback (struct urb *urb, struct pt_regs *regs)
+static void tower_interrupt_in_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
int retval;
@@ -811,7 +811,7 @@ exit:
/**
* tower_interrupt_out_callback
*/
-static void tower_interrupt_out_callback (struct urb *urb, struct pt_regs *regs)
+static void tower_interrupt_out_callback (struct urb *urb)
{
struct lego_usb_tower *dev = (struct lego_usb_tower *)urb->context;
diff --git a/drivers/usb/misc/phidget.c b/drivers/usb/misc/phidget.c
new file mode 100644
index 000000000000..735ed33f4f7f
--- /dev/null
+++ b/drivers/usb/misc/phidget.c
@@ -0,0 +1,43 @@
+/*
+ * USB Phidgets class
+ *
+ * Copyright (C) 2006 Sean Young <sean@mess.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/device.h>
+
+struct class *phidget_class;
+
+static int __init init_phidget(void)
+{
+ phidget_class = class_create(THIS_MODULE, "phidget");
+
+ if (IS_ERR(phidget_class))
+ return PTR_ERR(phidget_class);
+
+ return 0;
+}
+
+static void __exit cleanup_phidget(void)
+{
+ class_destroy(phidget_class);
+}
+
+EXPORT_SYMBOL_GPL(phidget_class);
+
+module_init(init_phidget);
+module_exit(cleanup_phidget);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_DESCRIPTION("Container module for phidget class");
+
diff --git a/drivers/usb/misc/phidget.h b/drivers/usb/misc/phidget.h
new file mode 100644
index 000000000000..c4011907d431
--- /dev/null
+++ b/drivers/usb/misc/phidget.h
@@ -0,0 +1,12 @@
+/*
+ * USB Phidgets class
+ *
+ * Copyright (C) 2006 Sean Young <sean@mess.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.
+ */
+
+extern struct class *phidget_class;
diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c
index bfbbbfbb92bc..abb4dcd811ac 100644
--- a/drivers/usb/misc/phidgetkit.c
+++ b/drivers/usb/misc/phidgetkit.c
@@ -20,6 +20,8 @@
#include <linux/module.h>
#include <linux/usb.h>
+#include "phidget.h"
+
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
#define DRIVER_DESC "USB PhidgetInterfaceKit Driver"
@@ -42,26 +44,35 @@ struct driver_interfacekit {
int inputs;
int outputs;
int has_lcd;
+ int amnesiac;
};
-#define ifkit(_sensors, _inputs, _outputs, _lcd) \
-static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = { \
+
+#define ifkit(_sensors, _inputs, _outputs, _lcd, _amnesiac) \
+{ \
.sensors = _sensors, \
.inputs = _inputs, \
.outputs = _outputs, \
.has_lcd = _lcd, \
+ .amnesiac = _amnesiac \
};
-ifkit(0, 0, 4, 0);
-ifkit(8, 8, 8, 0);
-ifkit(0, 4, 7, 1);
-ifkit(8, 8, 4, 0);
-ifkit(0, 8, 8, 1);
-ifkit(0, 16, 16, 0);
+
+static const struct driver_interfacekit ph_004 = ifkit(0, 0, 4, 0, 0);
+static const struct driver_interfacekit ph_888n = ifkit(8, 8, 8, 0, 1);
+static const struct driver_interfacekit ph_888o = ifkit(8, 8, 8, 0, 0);
+static const struct driver_interfacekit ph_047 = ifkit(0, 4, 7, 1, 0);
+static const struct driver_interfacekit ph_884 = ifkit(8, 8, 4, 0, 0);
+static const struct driver_interfacekit ph_088 = ifkit(0, 8, 8, 1, 0);
+static const struct driver_interfacekit ph_01616 = ifkit(0, 16, 16, 0, 0);
+
+static unsigned long device_no;
struct interfacekit {
struct usb_device *udev;
struct usb_interface *intf;
struct driver_interfacekit *ifkit;
+ struct device *dev;
unsigned long outputs;
+ int dev_no;
u8 inputs[MAX_INTERFACES];
u16 sensors[MAX_INTERFACES];
u8 lcd_files_on;
@@ -71,6 +82,7 @@ struct interfacekit {
dma_addr_t data_dma;
struct work_struct do_notify;
+ struct work_struct do_resubmit;
unsigned long input_events;
unsigned long sensor_events;
};
@@ -78,8 +90,10 @@ struct interfacekit {
static struct usb_device_id id_table[] = {
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004),
.driver_info = (kernel_ulong_t)&ph_004},
- {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888),
- .driver_info = (kernel_ulong_t)&ph_888},
+ {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0, 0x814),
+ .driver_info = (kernel_ulong_t)&ph_888o},
+ {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0x0815, 0xffff),
+ .driver_info = (kernel_ulong_t)&ph_888n},
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047),
.driver_info = (kernel_ulong_t)&ph_047},
{USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088),
@@ -92,16 +106,11 @@ static struct usb_device_id id_table[] = {
};
MODULE_DEVICE_TABLE(usb, id_table);
-static int change_outputs(struct interfacekit *kit, int output_num, int enable)
+static int set_outputs(struct interfacekit *kit)
{
u8 *buffer;
int retval;
- if (enable)
- set_bit(output_num, &kit->outputs);
- else
- clear_bit(output_num, &kit->outputs);
-
buffer = kzalloc(4, GFP_KERNEL);
if (!buffer) {
dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__);
@@ -121,6 +130,9 @@ static int change_outputs(struct interfacekit *kit, int output_num, int enable)
retval);
kfree(buffer);
+ if (kit->ifkit->amnesiac)
+ schedule_delayed_work(&kit->do_resubmit, HZ / 2);
+
return retval < 0 ? retval : 0;
}
@@ -180,21 +192,24 @@ exit:
}
#define set_lcd_line(number) \
-static ssize_t lcd_line_##number(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
- change_string(kit, buf, number - 1); \
- return count; \
-} \
-static DEVICE_ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number);
+static ssize_t lcd_line_##number(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
+ change_string(kit, buf, number - 1); \
+ return count; \
+}
+
+#define lcd_line_attr(number) \
+ __ATTR(lcd_line_##number, S_IWUGO, NULL, lcd_line_##number)
+
set_lcd_line(1);
set_lcd_line(2);
static ssize_t set_backlight(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct interfacekit *kit = usb_get_intfdata(intf);
+ struct interfacekit *kit = dev_get_drvdata(dev);
int enabled;
unsigned char *buffer;
int retval = -ENOMEM;
@@ -226,23 +241,30 @@ exit:
kfree(buffer);
return retval;
}
-static DEVICE_ATTR(backlight, S_IWUGO, NULL, set_backlight);
+
+static struct device_attribute dev_lcd_line_attrs[] = {
+ lcd_line_attr(1),
+ lcd_line_attr(2),
+ __ATTR(backlight, S_IWUGO, NULL, set_backlight)
+};
static void remove_lcd_files(struct interfacekit *kit)
{
+ int i;
+
if (kit->lcd_files_on) {
dev_dbg(&kit->udev->dev, "Removing lcd files\n");
- device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_1);
- device_remove_file(&kit->intf->dev, &dev_attr_lcd_line_2);
- device_remove_file(&kit->intf->dev, &dev_attr_backlight);
+
+ for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++)
+ device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
}
}
static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
- struct usb_interface *intf = to_usb_interface(dev);
- struct interfacekit *kit = usb_get_intfdata(intf);
+ struct interfacekit *kit = dev_get_drvdata(dev);
int enable;
+ int i, rc;
if (kit->ifkit->has_lcd == 0)
return -ENODEV;
@@ -253,9 +275,12 @@ static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *att
if (enable) {
if (!kit->lcd_files_on) {
dev_dbg(&kit->udev->dev, "Adding lcd files\n");
- device_create_file(&kit->intf->dev, &dev_attr_lcd_line_1);
- device_create_file(&kit->intf->dev, &dev_attr_lcd_line_2);
- device_create_file(&kit->intf->dev, &dev_attr_backlight);
+ for (i=0; i<ARRAY_SIZE(dev_lcd_line_attrs); i++) {
+ rc = device_create_file(kit->dev,
+ &dev_lcd_line_attrs[i]);
+ if (rc)
+ goto out;
+ }
kit->lcd_files_on = 1;
}
} else {
@@ -266,10 +291,16 @@ static ssize_t enable_lcd_files(struct device *dev, struct device_attribute *att
}
return count;
+out:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_lcd_line_attrs[i]);
+
+ return rc;
}
+
static DEVICE_ATTR(lcd, S_IWUGO, NULL, enable_lcd_files);
-static void interfacekit_irq(struct urb *urb, struct pt_regs *regs)
+static void interfacekit_irq(struct urb *urb)
{
struct interfacekit *kit = urb->context;
unsigned char *buffer = kit->data;
@@ -362,44 +393,58 @@ static void do_notify(void *data)
for (i=0; i<kit->ifkit->inputs; i++) {
if (test_and_clear_bit(i, &kit->input_events)) {
sprintf(sysfs_file, "input%d", i + 1);
- sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
+ sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
}
}
for (i=0; i<kit->ifkit->sensors; i++) {
if (test_and_clear_bit(i, &kit->sensor_events)) {
sprintf(sysfs_file, "sensor%d", i + 1);
- sysfs_notify(&kit->intf->dev.kobj, NULL, sysfs_file);
+ sysfs_notify(&kit->dev->kobj, NULL, sysfs_file);
}
}
}
+static void do_resubmit(void *data)
+{
+ set_outputs(data);
+}
+
#define show_set_output(value) \
-static ssize_t set_output##value(struct device *dev, struct device_attribute *attr, const char *buf, \
- size_t count) \
+static ssize_t set_output##value(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
- int enabled; \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
+ int enable; \
int retval; \
\
- if (sscanf(buf, "%d", &enabled) < 1) \
+ if (sscanf(buf, "%d", &enable) < 1) \
return -EINVAL; \
\
- retval = change_outputs(kit, value - 1, enabled); \
+ if (enable) \
+ set_bit(value - 1, &kit->outputs); \
+ else \
+ clear_bit(value - 1, &kit->outputs); \
+ \
+ retval = set_outputs(kit); \
\
return retval ? retval : count; \
} \
\
-static ssize_t show_output##value(struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_output##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
\
return sprintf(buf, "%d\n", !!test_bit(value - 1, &kit->outputs));\
-} \
-static DEVICE_ATTR(output##value, S_IWUGO | S_IRUGO, \
- show_output##value, set_output##value);
+}
+
+#define output_attr(value) \
+ __ATTR(output##value, S_IWUGO | S_IRUGO, \
+ show_output##value, set_output##value)
+
show_set_output(1);
show_set_output(2);
show_set_output(3);
@@ -417,15 +462,24 @@ show_set_output(14);
show_set_output(15);
show_set_output(16);
+static struct device_attribute dev_output_attrs[] = {
+ output_attr(1), output_attr(2), output_attr(3), output_attr(4),
+ output_attr(5), output_attr(6), output_attr(7), output_attr(8),
+ output_attr(9), output_attr(10), output_attr(11), output_attr(12),
+ output_attr(13), output_attr(14), output_attr(15), output_attr(16)
+};
+
#define show_input(value) \
-static ssize_t show_input##value(struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_input##value(struct device *dev, \
+ struct device_attribute *attr, char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
\
return sprintf(buf, "%d\n", (int)kit->inputs[value - 1]); \
-} \
-static DEVICE_ATTR(input##value, S_IRUGO, show_input##value, NULL);
+}
+
+#define input_attr(value) \
+ __ATTR(input##value, S_IRUGO, show_input##value, NULL)
show_input(1);
show_input(2);
@@ -444,15 +498,25 @@ show_input(14);
show_input(15);
show_input(16);
+static struct device_attribute dev_input_attrs[] = {
+ input_attr(1), input_attr(2), input_attr(3), input_attr(4),
+ input_attr(5), input_attr(6), input_attr(7), input_attr(8),
+ input_attr(9), input_attr(10), input_attr(11), input_attr(12),
+ input_attr(13), input_attr(14), input_attr(15), input_attr(16)
+};
+
#define show_sensor(value) \
-static ssize_t show_sensor##value(struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_sensor##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface(dev); \
- struct interfacekit *kit = usb_get_intfdata(intf); \
+ struct interfacekit *kit = dev_get_drvdata(dev); \
\
return sprintf(buf, "%d\n", (int)kit->sensors[value - 1]); \
-} \
-static DEVICE_ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL);
+}
+
+#define sensor_attr(value) \
+ __ATTR(sensor##value, S_IRUGO, show_sensor##value, NULL)
show_sensor(1);
show_sensor(2);
@@ -463,6 +527,11 @@ show_sensor(6);
show_sensor(7);
show_sensor(8);
+static struct device_attribute dev_sensor_attrs[] = {
+ sensor_attr(1), sensor_attr(2), sensor_attr(3), sensor_attr(4),
+ sensor_attr(5), sensor_attr(6), sensor_attr(7), sensor_attr(8)
+};
+
static int interfacekit_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
@@ -471,6 +540,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
struct interfacekit *kit;
struct driver_interfacekit *ifkit;
int pipe, maxp, rc = -ENOMEM;
+ int bit, value, i;
ifkit = (struct driver_interfacekit *)id->driver_info;
if (!ifkit)
@@ -493,6 +563,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
if (!kit)
goto out;
+ kit->dev_no = -1;
kit->ifkit = ifkit;
kit->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &kit->data_dma);
if (!kit->data)
@@ -505,6 +576,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
kit->udev = usb_get_dev(dev);
kit->intf = intf;
INIT_WORK(&kit->do_notify, do_notify, kit);
+ INIT_WORK(&kit->do_resubmit, do_resubmit, kit);
usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data,
maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
interfacekit_irq, kit, endpoint->bInterval);
@@ -513,85 +585,80 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic
usb_set_intfdata(intf, kit);
+ do {
+ bit = find_first_zero_bit(&device_no, sizeof(device_no));
+ value = test_and_set_bit(bit, &device_no);
+ } while(value);
+ kit->dev_no = bit;
+
+ kit->dev = device_create(phidget_class, &kit->udev->dev, 0,
+ "interfacekit%d", kit->dev_no);
+ if (IS_ERR(kit->dev)) {
+ rc = PTR_ERR(kit->dev);
+ kit->dev = NULL;
+ goto out;
+ }
+ dev_set_drvdata(kit->dev, kit);
+
if (usb_submit_urb(kit->irq, GFP_KERNEL)) {
rc = -EIO;
goto out;
}
- if (ifkit->outputs >= 4) {
- device_create_file(&intf->dev, &dev_attr_output1);
- device_create_file(&intf->dev, &dev_attr_output2);
- device_create_file(&intf->dev, &dev_attr_output3);
- device_create_file(&intf->dev, &dev_attr_output4);
- }
- if (ifkit->outputs >= 8) {
- device_create_file(&intf->dev, &dev_attr_output5);
- device_create_file(&intf->dev, &dev_attr_output6);
- device_create_file(&intf->dev, &dev_attr_output7);
- device_create_file(&intf->dev, &dev_attr_output8);
- }
- if (ifkit->outputs == 16) {
- device_create_file(&intf->dev, &dev_attr_output9);
- device_create_file(&intf->dev, &dev_attr_output10);
- device_create_file(&intf->dev, &dev_attr_output11);
- device_create_file(&intf->dev, &dev_attr_output12);
- device_create_file(&intf->dev, &dev_attr_output13);
- device_create_file(&intf->dev, &dev_attr_output14);
- device_create_file(&intf->dev, &dev_attr_output15);
- device_create_file(&intf->dev, &dev_attr_output16);
+ for (i=0; i<ifkit->outputs; i++ ) {
+ rc = device_create_file(kit->dev, &dev_output_attrs[i]);
+ if (rc)
+ goto out2;
}
- if (ifkit->inputs >= 4) {
- device_create_file(&intf->dev, &dev_attr_input1);
- device_create_file(&intf->dev, &dev_attr_input2);
- device_create_file(&intf->dev, &dev_attr_input3);
- device_create_file(&intf->dev, &dev_attr_input4);
- }
- if (ifkit->inputs >= 8) {
- device_create_file(&intf->dev, &dev_attr_input5);
- device_create_file(&intf->dev, &dev_attr_input6);
- device_create_file(&intf->dev, &dev_attr_input7);
- device_create_file(&intf->dev, &dev_attr_input8);
- }
- if (ifkit->inputs == 16) {
- device_create_file(&intf->dev, &dev_attr_input9);
- device_create_file(&intf->dev, &dev_attr_input10);
- device_create_file(&intf->dev, &dev_attr_input11);
- device_create_file(&intf->dev, &dev_attr_input12);
- device_create_file(&intf->dev, &dev_attr_input13);
- device_create_file(&intf->dev, &dev_attr_input14);
- device_create_file(&intf->dev, &dev_attr_input15);
- device_create_file(&intf->dev, &dev_attr_input16);
+ for (i=0; i<ifkit->inputs; i++ ) {
+ rc = device_create_file(kit->dev, &dev_input_attrs[i]);
+ if (rc)
+ goto out3;
}
- if (ifkit->sensors >= 4) {
- device_create_file(&intf->dev, &dev_attr_sensor1);
- device_create_file(&intf->dev, &dev_attr_sensor2);
- device_create_file(&intf->dev, &dev_attr_sensor3);
- device_create_file(&intf->dev, &dev_attr_sensor4);
+ for (i=0; i<ifkit->sensors; i++ ) {
+ rc = device_create_file(kit->dev, &dev_sensor_attrs[i]);
+ if (rc)
+ goto out4;
}
- if (ifkit->sensors >= 7) {
- device_create_file(&intf->dev, &dev_attr_sensor5);
- device_create_file(&intf->dev, &dev_attr_sensor6);
- device_create_file(&intf->dev, &dev_attr_sensor7);
- }
- if (ifkit->sensors == 8)
- device_create_file(&intf->dev, &dev_attr_sensor8);
- if (ifkit->has_lcd)
- device_create_file(&intf->dev, &dev_attr_lcd);
+ if (ifkit->has_lcd) {
+ rc = device_create_file(kit->dev, &dev_attr_lcd);
+ if (rc)
+ goto out4;
+
+ }
dev_info(&intf->dev, "USB PhidgetInterfaceKit %d/%d/%d attached\n",
ifkit->sensors, ifkit->inputs, ifkit->outputs);
return 0;
+out4:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_sensor_attrs[i]);
+
+ i = ifkit->inputs;
+out3:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_input_attrs[i]);
+
+ i = ifkit->outputs;
+out2:
+ while (i-- > 0)
+ device_remove_file(kit->dev, &dev_output_attrs[i]);
out:
if (kit) {
if (kit->irq)
usb_free_urb(kit->irq);
if (kit->data)
usb_buffer_free(dev, URB_INT_SIZE, kit->data, kit->data_dma);
+ if (kit->dev)
+ device_unregister(kit->dev);
+ if (kit->dev_no >= 0)
+ clear_bit(kit->dev_no, &device_no);
+
kfree(kit);
}
@@ -601,6 +668,7 @@ out:
static void interfacekit_disconnect(struct usb_interface *interface)
{
struct interfacekit *kit;
+ int i;
kit = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
@@ -612,74 +680,30 @@ static void interfacekit_disconnect(struct usb_interface *interface)
usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma);
cancel_delayed_work(&kit->do_notify);
+ cancel_delayed_work(&kit->do_resubmit);
- if (kit->ifkit->outputs >= 4) {
- device_remove_file(&interface->dev, &dev_attr_output1);
- device_remove_file(&interface->dev, &dev_attr_output2);
- device_remove_file(&interface->dev, &dev_attr_output3);
- device_remove_file(&interface->dev, &dev_attr_output4);
- }
- if (kit->ifkit->outputs >= 8) {
- device_remove_file(&interface->dev, &dev_attr_output5);
- device_remove_file(&interface->dev, &dev_attr_output6);
- device_remove_file(&interface->dev, &dev_attr_output7);
- device_remove_file(&interface->dev, &dev_attr_output8);
- }
- if (kit->ifkit->outputs == 16) {
- device_remove_file(&interface->dev, &dev_attr_output9);
- device_remove_file(&interface->dev, &dev_attr_output10);
- device_remove_file(&interface->dev, &dev_attr_output11);
- device_remove_file(&interface->dev, &dev_attr_output12);
- device_remove_file(&interface->dev, &dev_attr_output13);
- device_remove_file(&interface->dev, &dev_attr_output14);
- device_remove_file(&interface->dev, &dev_attr_output15);
- device_remove_file(&interface->dev, &dev_attr_output16);
- }
+ for (i=0; i<kit->ifkit->outputs; i++)
+ device_remove_file(kit->dev, &dev_output_attrs[i]);
- if (kit->ifkit->inputs >= 4) {
- device_remove_file(&interface->dev, &dev_attr_input1);
- device_remove_file(&interface->dev, &dev_attr_input2);
- device_remove_file(&interface->dev, &dev_attr_input3);
- device_remove_file(&interface->dev, &dev_attr_input4);
- }
- if (kit->ifkit->inputs >= 8) {
- device_remove_file(&interface->dev, &dev_attr_input5);
- device_remove_file(&interface->dev, &dev_attr_input6);
- device_remove_file(&interface->dev, &dev_attr_input7);
- device_remove_file(&interface->dev, &dev_attr_input8);
- }
- if (kit->ifkit->inputs == 16) {
- device_remove_file(&interface->dev, &dev_attr_input9);
- device_remove_file(&interface->dev, &dev_attr_input10);
- device_remove_file(&interface->dev, &dev_attr_input11);
- device_remove_file(&interface->dev, &dev_attr_input12);
- device_remove_file(&interface->dev, &dev_attr_input13);
- device_remove_file(&interface->dev, &dev_attr_input14);
- device_remove_file(&interface->dev, &dev_attr_input15);
- device_remove_file(&interface->dev, &dev_attr_input16);
- }
+ for (i=0; i<kit->ifkit->inputs; i++)
+ device_remove_file(kit->dev, &dev_input_attrs[i]);
- if (kit->ifkit->sensors >= 4) {
- device_remove_file(&interface->dev, &dev_attr_sensor1);
- device_remove_file(&interface->dev, &dev_attr_sensor2);
- device_remove_file(&interface->dev, &dev_attr_sensor3);
- device_remove_file(&interface->dev, &dev_attr_sensor4);
- }
- if (kit->ifkit->sensors >= 7) {
- device_remove_file(&interface->dev, &dev_attr_sensor5);
- device_remove_file(&interface->dev, &dev_attr_sensor6);
- device_remove_file(&interface->dev, &dev_attr_sensor7);
+ for (i=0; i<kit->ifkit->sensors; i++)
+ device_remove_file(kit->dev, &dev_sensor_attrs[i]);
+
+ if (kit->ifkit->has_lcd) {
+ device_remove_file(kit->dev, &dev_attr_lcd);
+ remove_lcd_files(kit);
}
- if (kit->ifkit->sensors == 8)
- device_remove_file(&interface->dev, &dev_attr_sensor8);
- if (kit->ifkit->has_lcd)
- device_remove_file(&interface->dev, &dev_attr_lcd);
+ device_unregister(kit->dev);
dev_info(&interface->dev, "USB PhidgetInterfaceKit %d/%d/%d detached\n",
kit->ifkit->sensors, kit->ifkit->inputs, kit->ifkit->outputs);
usb_put_dev(kit->udev);
+ clear_bit(kit->dev_no, &device_no);
+
kfree(kit);
}
diff --git a/drivers/usb/misc/phidgetmotorcontrol.c b/drivers/usb/misc/phidgetmotorcontrol.c
new file mode 100644
index 000000000000..5c780cab92e0
--- /dev/null
+++ b/drivers/usb/misc/phidgetmotorcontrol.c
@@ -0,0 +1,466 @@
+/*
+ * USB Phidget MotorControl driver
+ *
+ * Copyright (C) 2006 Sean Young <sean@mess.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "phidget.h"
+
+#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
+#define DRIVER_DESC "USB PhidgetMotorControl Driver"
+
+#define USB_VENDOR_ID_GLAB 0x06c2
+#define USB_DEVICE_ID_MOTORCONTROL 0x0058
+
+#define URB_INT_SIZE 8
+
+static unsigned long device_no;
+
+struct motorcontrol {
+ struct usb_device *udev;
+ struct usb_interface *intf;
+ struct device *dev;
+ int dev_no;
+ u8 inputs[4];
+ s8 desired_speed[2];
+ s8 speed[2];
+ s16 _current[2];
+ s8 acceleration[2];
+ struct urb *irq;
+ unsigned char *data;
+ dma_addr_t data_dma;
+
+ struct work_struct do_notify;
+ unsigned long input_events;
+ unsigned long speed_events;
+ unsigned long exceed_events;
+};
+
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_MOTORCONTROL) },
+ {}
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static int set_motor(struct motorcontrol *mc, int motor)
+{
+ u8 *buffer;
+ int speed, speed2, acceleration;
+ int retval;
+
+ buffer = kzalloc(8, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&mc->intf->dev, "%s - out of memory\n", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ acceleration = mc->acceleration[motor] * 10;
+ /* -127 <= speed <= 127 */
+ speed = (mc->desired_speed[motor] * 127) / 100;
+ /* -0x7300 <= speed2 <= 0x7300 */
+ speed2 = (mc->desired_speed[motor] * 230 * 128) / 100;
+
+ buffer[0] = motor;
+ buffer[1] = speed;
+ buffer[2] = acceleration >> 8;
+ buffer[3] = acceleration;
+ buffer[4] = speed2 >> 8;
+ buffer[5] = speed2;
+
+ retval = usb_control_msg(mc->udev,
+ usb_sndctrlpipe(mc->udev, 0),
+ 0x09, 0x21, 0x0200, 0x0000, buffer, 8, 2000);
+
+ if (retval != 8)
+ dev_err(&mc->intf->dev, "usb_control_msg returned %d\n",
+ retval);
+ kfree(buffer);
+
+ return retval < 0 ? retval : 0;
+}
+
+static void motorcontrol_irq(struct urb *urb)
+{
+ struct motorcontrol *mc = urb->context;
+ unsigned char *buffer = mc->data;
+ int i, level;
+ int status;
+
+ switch (urb->status) {
+ case 0: /* success */
+ break;
+ case -ECONNRESET: /* unlink */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ /* -EPIPE: should clear the halt */
+ default: /* error */
+ goto resubmit;
+ }
+
+ /* digital inputs */
+ for (i=0; i<4; i++) {
+ level = (buffer[0] >> i) & 1;
+ if (mc->inputs[i] != level) {
+ mc->inputs[i] = level;
+ set_bit(i, &mc->input_events);
+ }
+ }
+
+ /* motor speed */
+ if (buffer[2] == 0) {
+ for (i=0; i<2; i++) {
+ level = ((s8)buffer[4+i]) * 100 / 127;
+ if (mc->speed[i] != level) {
+ mc->speed[i] = level;
+ set_bit(i, &mc->speed_events);
+ }
+ }
+ } else {
+ int index = buffer[3] & 1;
+
+ level = ((s8)buffer[4] << 8) | buffer[5];
+ level = level * 100 / 29440;
+ if (mc->speed[index] != level) {
+ mc->speed[index] = level;
+ set_bit(index, &mc->speed_events);
+ }
+
+ level = ((s8)buffer[6] << 8) | buffer[7];
+ mc->_current[index] = level * 100 / 1572;
+ }
+
+ if (buffer[1] & 1)
+ set_bit(0, &mc->exceed_events);
+
+ if (buffer[1] & 2)
+ set_bit(1, &mc->exceed_events);
+
+ if (mc->input_events || mc->exceed_events || mc->speed_events)
+ schedule_work(&mc->do_notify);
+
+resubmit:
+ status = usb_submit_urb(urb, SLAB_ATOMIC);
+ if (status)
+ dev_err(&mc->intf->dev,
+ "can't resubmit intr, %s-%s/motorcontrol0, status %d",
+ mc->udev->bus->bus_name,
+ mc->udev->devpath, status);
+}
+
+static void do_notify(void *data)
+{
+ struct motorcontrol *mc = data;
+ int i;
+ char sysfs_file[8];
+
+ for (i=0; i<4; i++) {
+ if (test_and_clear_bit(i, &mc->input_events)) {
+ sprintf(sysfs_file, "input%d", i);
+ sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
+ }
+ }
+
+ for (i=0; i<2; i++) {
+ if (test_and_clear_bit(i, &mc->speed_events)) {
+ sprintf(sysfs_file, "speed%d", i);
+ sysfs_notify(&mc->dev->kobj, NULL, sysfs_file);
+ }
+ }
+
+ for (i=0; i<2; i++) {
+ if (test_and_clear_bit(i, &mc->exceed_events))
+ dev_warn(&mc->intf->dev,
+ "motor #%d exceeds 1.5 Amp current limit\n", i);
+ }
+}
+
+#define show_set_speed(value) \
+static ssize_t set_speed##value(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ int speed; \
+ int retval; \
+ \
+ if (sscanf(buf, "%d", &speed) < 1) \
+ return -EINVAL; \
+ \
+ if (speed < -100 || speed > 100) \
+ return -EINVAL; \
+ \
+ mc->desired_speed[value] = speed; \
+ \
+ retval = set_motor(mc, value); \
+ \
+ return retval ? retval : count; \
+} \
+ \
+static ssize_t show_speed##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", mc->speed[value]); \
+}
+
+#define speed_attr(value) \
+ __ATTR(speed##value, S_IWUGO | S_IRUGO, \
+ show_speed##value, set_speed##value)
+
+show_set_speed(0);
+show_set_speed(1);
+
+#define show_set_acceleration(value) \
+static ssize_t set_acceleration##value(struct device *dev, \
+ struct device_attribute *attr, \
+ const char *buf, size_t count) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ int acceleration; \
+ int retval; \
+ \
+ if (sscanf(buf, "%d", &acceleration) < 1) \
+ return -EINVAL; \
+ \
+ if (acceleration < 0 || acceleration > 100) \
+ return -EINVAL; \
+ \
+ mc->acceleration[value] = acceleration; \
+ \
+ retval = set_motor(mc, value); \
+ \
+ return retval ? retval : count; \
+} \
+ \
+static ssize_t show_acceleration##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", mc->acceleration[value]); \
+}
+
+#define acceleration_attr(value) \
+ __ATTR(acceleration##value, S_IWUGO | S_IRUGO, \
+ show_acceleration##value, set_acceleration##value)
+
+show_set_acceleration(0);
+show_set_acceleration(1);
+
+#define show_current(value) \
+static ssize_t show_current##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%dmA\n", (int)mc->_current[value]); \
+}
+
+#define current_attr(value) \
+ __ATTR(current##value, S_IRUGO, show_current##value, NULL)
+
+show_current(0);
+show_current(1);
+
+#define show_input(value) \
+static ssize_t show_input##value(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct motorcontrol *mc = dev_get_drvdata(dev); \
+ \
+ return sprintf(buf, "%d\n", (int)mc->inputs[value]); \
+}
+
+#define input_attr(value) \
+ __ATTR(input##value, S_IRUGO, show_input##value, NULL)
+
+show_input(0);
+show_input(1);
+show_input(2);
+show_input(3);
+
+static struct device_attribute dev_attrs[] = {
+ input_attr(0),
+ input_attr(1),
+ input_attr(2),
+ input_attr(3),
+ speed_attr(0),
+ speed_attr(1),
+ acceleration_attr(0),
+ acceleration_attr(1),
+ current_attr(0),
+ current_attr(1)
+};
+
+static int motorcontrol_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct motorcontrol *mc;
+ int pipe, maxp, rc = -ENOMEM;
+ int bit, value, i;
+
+ interface = intf->cur_altsetting;
+ if (interface->desc.bNumEndpoints != 1)
+ return -ENODEV;
+
+ endpoint = &interface->endpoint[0].desc;
+ if (!(endpoint->bEndpointAddress & 0x80))
+ return -ENODEV;
+
+ /*
+ * bmAttributes
+ */
+ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ mc = kzalloc(sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ goto out;
+
+ mc->dev_no = -1;
+ mc->data = usb_buffer_alloc(dev, URB_INT_SIZE, SLAB_ATOMIC, &mc->data_dma);
+ if (!mc->data)
+ goto out;
+
+ mc->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mc->irq)
+ goto out;
+
+ mc->udev = usb_get_dev(dev);
+ mc->intf = intf;
+ mc->acceleration[0] = mc->acceleration[1] = 10;
+ INIT_WORK(&mc->do_notify, do_notify, mc);
+ usb_fill_int_urb(mc->irq, mc->udev, pipe, mc->data,
+ maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp,
+ motorcontrol_irq, mc, endpoint->bInterval);
+ mc->irq->transfer_dma = mc->data_dma;
+ mc->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_set_intfdata(intf, mc);
+
+ do {
+ bit = find_first_zero_bit(&device_no, sizeof(device_no));
+ value = test_and_set_bit(bit, &device_no);
+ } while(value);
+ mc->dev_no = bit;
+
+ mc->dev = device_create(phidget_class, &mc->udev->dev, 0,
+ "motorcontrol%d", mc->dev_no);
+ if (IS_ERR(mc->dev)) {
+ rc = PTR_ERR(mc->dev);
+ mc->dev = NULL;
+ goto out;
+ }
+
+ dev_set_drvdata(mc->dev, mc);
+
+ if (usb_submit_urb(mc->irq, GFP_KERNEL)) {
+ rc = -EIO;
+ goto out;
+ }
+
+ for (i=0; i<ARRAY_SIZE(dev_attrs); i++) {
+ rc = device_create_file(mc->dev, &dev_attrs[i]);
+ if (rc)
+ goto out2;
+ }
+
+ dev_info(&intf->dev, "USB PhidgetMotorControl attached\n");
+
+ return 0;
+out2:
+ while (i-- > 0)
+ device_remove_file(mc->dev, &dev_attrs[i]);
+out:
+ if (mc) {
+ if (mc->irq)
+ usb_free_urb(mc->irq);
+ if (mc->data)
+ usb_buffer_free(dev, URB_INT_SIZE, mc->data, mc->data_dma);
+ if (mc->dev)
+ device_unregister(mc->dev);
+ if (mc->dev_no >= 0)
+ clear_bit(mc->dev_no, &device_no);
+
+ kfree(mc);
+ }
+
+ return rc;
+}
+
+static void motorcontrol_disconnect(struct usb_interface *interface)
+{
+ struct motorcontrol *mc;
+ int i;
+
+ mc = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+ if (!mc)
+ return;
+
+ usb_kill_urb(mc->irq);
+ usb_free_urb(mc->irq);
+ usb_buffer_free(mc->udev, URB_INT_SIZE, mc->data, mc->data_dma);
+
+ cancel_delayed_work(&mc->do_notify);
+
+ for (i=0; i<ARRAY_SIZE(dev_attrs); i++)
+ device_remove_file(mc->dev, &dev_attrs[i]);
+
+ device_unregister(mc->dev);
+
+ usb_put_dev(mc->udev);
+ clear_bit(mc->dev_no, &device_no);
+ kfree(mc);
+
+ dev_info(&interface->dev, "USB PhidgetMotorControl detached\n");
+}
+
+static struct usb_driver motorcontrol_driver = {
+ .name = "phidgetmotorcontrol",
+ .probe = motorcontrol_probe,
+ .disconnect = motorcontrol_disconnect,
+ .id_table = id_table
+};
+
+static int __init motorcontrol_init(void)
+{
+ int retval = 0;
+
+ retval = usb_register(&motorcontrol_driver);
+ if (retval)
+ err("usb_register failed. Error number %d", retval);
+
+ return retval;
+}
+
+static void __exit motorcontrol_exit(void)
+{
+ usb_deregister(&motorcontrol_driver);
+}
+
+module_init(motorcontrol_init);
+module_exit(motorcontrol_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/phidgetservo.c b/drivers/usb/misc/phidgetservo.c
index c0df79c96538..7163f05c5b27 100644
--- a/drivers/usb/misc/phidgetservo.c
+++ b/drivers/usb/misc/phidgetservo.c
@@ -1,7 +1,7 @@
/*
* USB PhidgetServo driver 1.0
*
- * Copyright (C) 2004 Sean Young <sean@mess.org>
+ * Copyright (C) 2004, 2006 Sean Young <sean@mess.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
@@ -15,14 +15,6 @@
*
* CAUTION: Generally you should use 0 < degrees < 180 as anything else
* is probably beyond the range of your servo and may damage it.
- *
- * Jun 16, 2004: Sean Young <sean@mess.org>
- * - cleanups
- * - was using memory after kfree()
- * Aug 8, 2004: Sean Young <sean@mess.org>
- * - set the highest angle as high as the hardware allows, there are
- * some odd servos out there
- *
*/
#include <linux/kernel.h>
@@ -32,6 +24,8 @@
#include <linux/module.h>
#include <linux/usb.h>
+#include "phidget.h"
+
#define DRIVER_AUTHOR "Sean Young <sean@mess.org>"
#define DRIVER_DESC "USB PhidgetServo Driver"
@@ -70,8 +64,12 @@ static struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
+static int unsigned long device_no;
+
struct phidget_servo {
struct usb_device *udev;
+ struct device *dev;
+ int dev_no;
ulong type;
int pulse[4];
int degrees[4];
@@ -203,16 +201,16 @@ change_position_v20(struct phidget_servo *servo, int servo_no, int degrees,
}
#define show_set(value) \
-static ssize_t set_servo##value (struct device *dev, struct device_attribute *attr, \
+static ssize_t set_servo##value (struct device *dev, \
+ struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
int degrees, minutes, retval; \
- struct usb_interface *intf = to_usb_interface (dev); \
- struct phidget_servo *servo = usb_get_intfdata (intf); \
+ struct phidget_servo *servo = dev_get_drvdata(dev); \
\
minutes = 0; \
/* must at least convert degrees */ \
- if (sscanf (buf, "%d.%d", &degrees, &minutes) < 1) { \
+ if (sscanf(buf, "%d.%d", &degrees, &minutes) < 1) { \
return -EINVAL; \
} \
\
@@ -220,86 +218,127 @@ static ssize_t set_servo##value (struct device *dev, struct device_attribute *at
return -EINVAL; \
\
if (servo->type & SERVO_VERSION_30) \
- retval = change_position_v30 (servo, value, degrees, \
+ retval = change_position_v30(servo, value, degrees, \
minutes); \
else \
- retval = change_position_v20 (servo, value, degrees, \
+ retval = change_position_v20(servo, value, degrees, \
minutes); \
\
return retval < 0 ? retval : count; \
} \
\
-static ssize_t show_servo##value (struct device *dev, struct device_attribute *attr, char *buf) \
+static ssize_t show_servo##value (struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
{ \
- struct usb_interface *intf = to_usb_interface (dev); \
- struct phidget_servo *servo = usb_get_intfdata (intf); \
+ struct phidget_servo *servo = dev_get_drvdata(dev); \
\
- return sprintf (buf, "%d.%02d\n", servo->degrees[value], \
+ return sprintf(buf, "%d.%02d\n", servo->degrees[value], \
servo->minutes[value]); \
-} \
-static DEVICE_ATTR(servo##value, S_IWUGO | S_IRUGO, \
- show_servo##value, set_servo##value);
+}
+#define servo_attr(value) \
+ __ATTR(servo##value, S_IWUGO | S_IRUGO, \
+ show_servo##value, set_servo##value)
show_set(0);
show_set(1);
show_set(2);
show_set(3);
+static struct device_attribute dev_attrs[] = {
+ servo_attr(0), servo_attr(1), servo_attr(2), servo_attr(3)
+};
+
static int
servo_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(interface);
struct phidget_servo *dev;
+ int bit, value, rc;
+ int servo_count, i;
dev = kzalloc(sizeof (struct phidget_servo), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
- return -ENOMEM;
+ rc = -ENOMEM;
+ goto out;
}
dev->udev = usb_get_dev(udev);
dev->type = id->driver_info;
+ dev->dev_no = -1;
usb_set_intfdata(interface, dev);
- device_create_file(&interface->dev, &dev_attr_servo0);
- if (dev->type & SERVO_COUNT_QUAD) {
- device_create_file(&interface->dev, &dev_attr_servo1);
- device_create_file(&interface->dev, &dev_attr_servo2);
- device_create_file(&interface->dev, &dev_attr_servo3);
+ do {
+ bit = find_first_zero_bit(&device_no, sizeof(device_no));
+ value = test_and_set_bit(bit, &device_no);
+ } while (value);
+ dev->dev_no = bit;
+
+ dev->dev = device_create(phidget_class, &dev->udev->dev, 0,
+ "servo%d", dev->dev_no);
+ if (IS_ERR(dev->dev)) {
+ rc = PTR_ERR(dev->dev);
+ dev->dev = NULL;
+ goto out;
+ }
+
+ servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
+
+ for (i=0; i<servo_count; i++) {
+ rc = device_create_file(dev->dev, &dev_attrs[i]);
+ if (rc)
+ goto out2;
}
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 attached\n",
- dev->type & SERVO_COUNT_QUAD ? 4 : 1,
- dev->type & SERVO_VERSION_30 ? 3 : 2);
+ servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
- if(!(dev->type & SERVO_VERSION_30))
+ if (!(dev->type & SERVO_VERSION_30))
dev_info(&interface->dev,
"WARNING: v2.0 not tested! Please report if it works.\n");
return 0;
+out2:
+ while (i-- > 0)
+ device_remove_file(dev->dev, &dev_attrs[i]);
+out:
+ if (dev) {
+ if (dev->dev)
+ device_unregister(dev->dev);
+ if (dev->dev_no >= 0)
+ clear_bit(dev->dev_no, &device_no);
+
+ kfree(dev);
+ }
+
+ return rc;
}
static void
servo_disconnect(struct usb_interface *interface)
{
struct phidget_servo *dev;
+ int servo_count, i;
dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
- device_remove_file(&interface->dev, &dev_attr_servo0);
- if (dev->type & SERVO_COUNT_QUAD) {
- device_remove_file(&interface->dev, &dev_attr_servo1);
- device_remove_file(&interface->dev, &dev_attr_servo2);
- device_remove_file(&interface->dev, &dev_attr_servo3);
- }
+ if (!dev)
+ return;
+
+ servo_count = dev->type & SERVO_COUNT_QUAD ? 4 : 1;
+
+ for (i=0; i<servo_count; i++)
+ device_remove_file(dev->dev, &dev_attrs[i]);
+ device_unregister(dev->dev);
usb_put_dev(dev->udev);
dev_info(&interface->dev, "USB %d-Motor PhidgetServo v%d.0 detached\n",
- dev->type & SERVO_COUNT_QUAD ? 4 : 1,
- dev->type & SERVO_VERSION_30 ? 3 : 2);
+ servo_count, dev->type & SERVO_VERSION_30 ? 3 : 2);
+ clear_bit(dev->dev_no, &device_no);
kfree(dev);
}
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index e16582f3733c..b99ca9c79821 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -36,7 +36,6 @@
*
*/
-#include <linux/config.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/kernel.h>
@@ -210,7 +209,7 @@ sisusb_free_outbuf(struct sisusb_usb_data *sisusb, int index)
/* completion callback */
static void
-sisusb_bulk_completeout(struct urb *urb, struct pt_regs *regs)
+sisusb_bulk_completeout(struct urb *urb)
{
struct sisusb_urb_context *context = urb->context;
struct sisusb_usb_data *sisusb;
@@ -289,7 +288,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
/* completion callback */
static void
-sisusb_bulk_completein(struct urb *urb, struct pt_regs *regs)
+sisusb_bulk_completein(struct urb *urb)
{
struct sisusb_usb_data *sisusb = urb->context;
@@ -3179,7 +3178,7 @@ sisusb_compat_ioctl(struct file *f, unsigned int cmd, unsigned long arg)
}
#endif
-static struct file_operations usb_sisusb_fops = {
+static const struct file_operations usb_sisusb_fops = {
.owner = THIS_MODULE,
.open = sisusb_open,
.release = sisusb_release,
diff --git a/drivers/usb/misc/sisusbvga/sisusb_con.c b/drivers/usb/misc/sisusbvga/sisusb_con.c
index fb48feca8353..bf26c3c56990 100644
--- a/drivers/usb/misc/sisusbvga/sisusb_con.c
+++ b/drivers/usb/misc/sisusbvga/sisusb_con.c
@@ -47,7 +47,6 @@
*
*/
-#include <linux/config.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/kernel.h>
diff --git a/drivers/usb/misc/trancevibrator.c b/drivers/usb/misc/trancevibrator.c
new file mode 100644
index 000000000000..33cd91d11eca
--- /dev/null
+++ b/drivers/usb/misc/trancevibrator.c
@@ -0,0 +1,159 @@
+/*
+ * PlayStation 2 Trance Vibrator driver
+ *
+ * Copyright (C) 2006 Sam Hocevar <sam@zoy.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.
+ *
+ * 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.
+ */
+
+/* Standard include files */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v1.1"
+#define DRIVER_AUTHOR "Sam Hocevar, sam@zoy.org"
+#define DRIVER_DESC "PlayStation 2 Trance Vibrator driver"
+
+#define TRANCEVIBRATOR_VENDOR_ID 0x0b49 /* ASCII Corporation */
+#define TRANCEVIBRATOR_PRODUCT_ID 0x064f /* Trance Vibrator */
+
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) },
+ { },
+};
+MODULE_DEVICE_TABLE (usb, id_table);
+
+/* Driver-local specific stuff */
+struct trancevibrator {
+ struct usb_device *udev;
+ unsigned int speed;
+};
+
+static ssize_t show_speed(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct trancevibrator *tv = usb_get_intfdata(intf);
+
+ return sprintf(buf, "%d\n", tv->speed);
+}
+
+static ssize_t set_speed(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct usb_interface *intf = to_usb_interface(dev);
+ struct trancevibrator *tv = usb_get_intfdata(intf);
+ int temp, retval;
+
+ temp = simple_strtoul(buf, NULL, 10);
+ if (temp > 255)
+ temp = 255;
+ else if (temp < 0)
+ temp = 0;
+ tv->speed = temp;
+
+ dev_dbg(&tv->udev->dev, "speed = %d\n", tv->speed);
+
+ /* Set speed */
+ retval = usb_control_msg(tv->udev, usb_sndctrlpipe(tv->udev, 0),
+ 0x01, /* vendor request: set speed */
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ tv->speed, /* speed value */
+ 0, NULL, 0, USB_CTRL_GET_TIMEOUT);
+ if (retval) {
+ dev_dbg(&tv->udev->dev, "retval = %d\n", retval);
+ return retval;
+ }
+ return count;
+}
+
+static DEVICE_ATTR(speed, S_IWUGO | S_IRUGO, show_speed, set_speed);
+
+static int tv_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(interface);
+ struct trancevibrator *dev;
+ int retval;
+
+ dev = kzalloc(sizeof(struct trancevibrator), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&interface->dev, "Out of memory\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ dev->udev = usb_get_dev(udev);
+ usb_set_intfdata(interface, dev);
+ retval = device_create_file(&interface->dev, &dev_attr_speed);
+ if (retval)
+ goto error_create_file;
+
+ return 0;
+
+error_create_file:
+ usb_put_dev(udev);
+ usb_set_intfdata(interface, NULL);
+error:
+ kfree(dev);
+ return retval;
+}
+
+static void tv_disconnect(struct usb_interface *interface)
+{
+ struct trancevibrator *dev;
+
+ dev = usb_get_intfdata (interface);
+ usb_set_intfdata(interface, NULL);
+ device_remove_file(&interface->dev, &dev_attr_speed);
+ usb_put_dev(dev->udev);
+ kfree(dev);
+}
+
+/* USB subsystem object */
+static struct usb_driver tv_driver = {
+ .name = "trancevibrator",
+ .probe = tv_probe,
+ .disconnect = tv_disconnect,
+ .id_table = id_table,
+};
+
+static int __init tv_init(void)
+{
+ int retval = usb_register(&tv_driver);
+ if (retval) {
+ err("usb_register failed. Error number %d", retval);
+ return retval;
+ }
+
+ info(DRIVER_VERSION ":" DRIVER_DESC);
+ return 0;
+}
+
+static void __exit tv_exit(void)
+{
+ usb_deregister(&tv_driver);
+}
+
+module_init (tv_init);
+module_exit (tv_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/misc/usb_u132.h b/drivers/usb/misc/usb_u132.h
new file mode 100644
index 000000000000..551ba8906d62
--- /dev/null
+++ b/drivers/usb/misc/usb_u132.h
@@ -0,0 +1,97 @@
+/*
+* Common Header File for the Elan Digital Systems U132 adapter
+* this file should be included by both the "ftdi-u132" and
+* the "u132-hcd" modules.
+*
+* Copyright(C) 2006 Elan Digital Systems Limited
+*(http://www.elandigitalsystems.com)
+*
+* Author and Maintainer - Tony Olech - Elan Digital Systems
+*(tony.olech@elandigitalsystems.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, version 2.
+*
+*
+* The driver was written by Tony Olech(tony.olech@elandigitalsystems.com)
+* based on various USB client drivers in the 2.6.15 linux kernel
+* with constant reference to the 3rd Edition of Linux Device Drivers
+* published by O'Reilly
+*
+* The U132 adapter is a USB to CardBus adapter specifically designed
+* for PC cards that contain an OHCI host controller. Typical PC cards
+* are the Orange Mobile 3G Option GlobeTrotter Fusion card.
+*
+* The U132 adapter will *NOT *work with PC cards that do not contain
+* an OHCI controller. A simple way to test whether a PC card has an
+* OHCI controller as an interface is to insert the PC card directly
+* into a laptop(or desktop) with a CardBus slot and if "lspci" shows
+* a new USB controller and "lsusb -v" shows a new OHCI Host Controller
+* then there is a good chance that the U132 adapter will support the
+* PC card.(you also need the specific client driver for the PC card)
+*
+* Please inform the Author and Maintainer about any PC cards that
+* contain OHCI Host Controller and work when directly connected to
+* an embedded CardBus slot but do not work when they are connected
+* via an ELAN U132 adapter.
+*
+* The driver consists of two modules, the "ftdi-u132" module is
+* a USB client driver that interfaces to the FTDI chip within
+* the U132 adapter manufactured by Elan Digital Systems, and the
+* "u132-hcd" module is a USB host controller driver that talks
+* to the OHCI controller within CardBus card that are inserted
+* in the U132 adapter.
+*
+* The "ftdi-u132" module should be loaded automatically by the
+* hot plug system when the U132 adapter is plugged in. The module
+* initialises the adapter which mostly consists of synchronising
+* the FTDI chip, before continuously polling the adapter to detect
+* PC card insertions. As soon as a PC card containing a recognised
+* OHCI controller is seen the "ftdi-u132" module explicitly requests
+* the kernel to load the "u132-hcd" module.
+*
+* The "ftdi-u132" module provides the interface to the inserted
+* PC card and the "u132-hcd" module uses the API to send and recieve
+* data. The API features call-backs, so that part of the "u132-hcd"
+* module code will run in the context of one of the kernel threads
+* of the "ftdi-u132" module.
+*
+*/
+int ftdi_elan_switch_on_diagnostics(int number);
+void ftdi_elan_gone_away(struct platform_device *pdev);
+void start_usb_lock_device_tracing(void);
+struct u132_platform_data {
+ u16 vendor;
+ u16 device;
+ u8 potpg;
+ void (*port_power) (struct device *dev, int is_on);
+ void (*reset) (struct device *dev);
+};
+int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number,
+ void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits,
+ void (*callback) (void *endp, struct urb *urb, u8 *buf, int len,
+ int toggle_bits, int error_count, int condition_code, int repeat_number,
+ int halted, int skipped, int actual, int non_null));
+int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number,
+ void *endp);
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index e095772dd8e9..ada2ebc464ae 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -165,7 +165,7 @@ static int lcd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
return 0;
}
-static void lcd_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void lcd_write_bulk_callback(struct urb *urb)
{
struct usb_lcd *dev;
@@ -239,7 +239,7 @@ error:
return retval;
}
-static struct file_operations lcd_fops = {
+static const struct file_operations lcd_fops = {
.owner = THIS_MODULE,
.read = lcd_read,
.write = lcd_write,
@@ -290,9 +290,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
endpoint = &iface_desc->endpoint[i].desc;
if (!dev->bulk_in_endpointAddr &&
- (endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = buffer_size;
@@ -305,9 +303,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
}
if (!dev->bulk_out_endpointAddr &&
- !(endpoint->bEndpointAddress & USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
diff --git a/drivers/usb/misc/usbled.c b/drivers/usb/misc/usbled.c
index 0c5ee0ad6bb9..49c5c5c4c431 100644
--- a/drivers/usb/misc/usbled.c
+++ b/drivers/usb/misc/usbled.c
@@ -108,22 +108,34 @@ static int led_probe(struct usb_interface *interface, const struct usb_device_id
dev = kzalloc(sizeof(struct usb_led), GFP_KERNEL);
if (dev == NULL) {
dev_err(&interface->dev, "Out of memory\n");
- goto error;
+ goto error_mem;
}
dev->udev = usb_get_dev(udev);
usb_set_intfdata (interface, dev);
- device_create_file(&interface->dev, &dev_attr_blue);
- device_create_file(&interface->dev, &dev_attr_red);
- device_create_file(&interface->dev, &dev_attr_green);
+ retval = device_create_file(&interface->dev, &dev_attr_blue);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_red);
+ if (retval)
+ goto error;
+ retval = device_create_file(&interface->dev, &dev_attr_green);
+ if (retval)
+ goto error;
dev_info(&interface->dev, "USB LED device now attached\n");
return 0;
error:
+ device_remove_file(&interface->dev, &dev_attr_blue);
+ device_remove_file(&interface->dev, &dev_attr_red);
+ device_remove_file(&interface->dev, &dev_attr_green);
+ usb_set_intfdata (interface, NULL);
+ usb_put_dev(dev->udev);
kfree(dev);
+error_mem:
return retval;
}
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 983e104dd452..7c2cbdf81d20 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -198,7 +198,7 @@ found:
* them with non-zero test data (or test for it) when appropriate.
*/
-static void simple_callback (struct urb *urb, struct pt_regs *regs)
+static void simple_callback (struct urb *urb)
{
complete ((struct completion *) urb->context);
}
@@ -730,7 +730,7 @@ struct subcase {
int expected;
};
-static void ctrl_complete (struct urb *urb, struct pt_regs *regs)
+static void ctrl_complete (struct urb *urb)
{
struct ctrl_ctx *ctx = urb->context;
struct usb_ctrlrequest *reqp;
@@ -1035,7 +1035,7 @@ cleanup:
/*-------------------------------------------------------------------------*/
-static void unlink1_callback (struct urb *urb, struct pt_regs *regs)
+static void unlink1_callback (struct urb *urb)
{
int status = urb->status;
@@ -1343,7 +1343,7 @@ struct iso_context {
struct usbtest_dev *dev;
};
-static void iso_callback (struct urb *urb, struct pt_regs *regs)
+static void iso_callback (struct urb *urb)
{
struct iso_context *ctx = urb->context;
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 4081990b7d1a..7e8a0acd52ee 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -106,7 +106,7 @@ static void destroy_async(struct kref *kref)
/* --------------------------------------------------------------------- */
-static void async_complete(struct urb *urb, struct pt_regs *ptregs)
+static void async_complete(struct urb *urb)
{
struct uss720_async_request *rq;
struct parport *pp;
@@ -127,7 +127,7 @@ static void async_complete(struct urb *urb, struct pt_regs *ptregs)
#endif
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
- parport_generic_irq(0, pp, NULL);
+ parport_generic_irq(0, pp);
}
complete(&rq->compl);
kref_put(&rq->ref_count, destroy_async);
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 275a66f83058..394bbf2f68d4 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -265,7 +265,6 @@ static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus)
ubus->mon_bus = NULL;
mbus->u_bus = NULL;
mb();
- // usb_bus_put(ubus);
}
/*
@@ -297,12 +296,12 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
INIT_LIST_HEAD(&mbus->r_list);
/*
- * This usb_bus_get here is superfluous, because we receive
- * a notification if usb_bus is about to be removed.
+ * We don't need to take a reference to ubus, because we receive
+ * a notification if the bus is about to be removed.
*/
- // usb_bus_get(ubus);
mbus->u_bus = ubus;
ubus->mon_bus = mbus;
+ mbus->uses_dma = ubus->uses_dma;
rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
if (rc <= 0 || rc >= NAMESZ)
diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c
index 1fe01d994a79..f6d1491256c4 100644
--- a/drivers/usb/mon/mon_stat.c
+++ b/drivers/usb/mon/mon_stat.c
@@ -28,7 +28,7 @@ static int mon_stat_open(struct inode *inode, struct file *file)
if ((sp = kmalloc(sizeof(struct snap), GFP_KERNEL)) == NULL)
return -ENOMEM;
- mbus = inode->u.generic_ip;
+ mbus = inode->i_private;
sp->slen = snprintf(sp->str, STAT_BUF_SIZE,
"nreaders %d events %u text_lost %u\n",
@@ -62,7 +62,7 @@ static int mon_stat_release(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations mon_fops_stat = {
+const struct file_operations mon_fops_stat = {
.owner = THIS_MODULE,
.open = mon_stat_open,
.llseek = no_llseek,
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index f961a770cee2..7a2346c53284 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -75,13 +75,13 @@ static void mon_text_ctor(void *, kmem_cache_t *, unsigned long);
*/
static inline char mon_text_get_setup(struct mon_event_text *ep,
- struct urb *urb, char ev_type)
+ struct urb *urb, char ev_type, struct mon_bus *mbus)
{
if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
return '-';
- if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ if (mbus->uses_dma && (urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
if (urb->setup_packet == NULL)
return 'Z'; /* '0' would be not as pretty. */
@@ -91,7 +91,7 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
}
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
- int len, char ev_type)
+ int len, char ev_type, struct mon_bus *mbus)
{
int pipe = urb->pipe;
@@ -117,7 +117,7 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
* contain non-NULL garbage in case the upper level promised to
* set DMA for the HCD.
*/
- if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
+ if (mbus->uses_dma && (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
return mon_dmapeek(ep->data, urb->transfer_dma, len);
if (urb->transfer_buffer == NULL)
@@ -161,8 +161,9 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
/* Collecting status makes debugging sense for submits, too */
ep->status = urb->status;
- ep->setup_flag = mon_text_get_setup(ep, urb, ev_type);
- ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);
+ ep->setup_flag = mon_text_get_setup(ep, urb, ev_type, rp->r.m_bus);
+ ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type,
+ rp->r.m_bus);
rp->nevents++;
list_add_tail(&ep->e_link, &rp->e_list);
@@ -238,7 +239,7 @@ static int mon_text_open(struct inode *inode, struct file *file)
int rc;
mutex_lock(&mon_lock);
- mbus = inode->u.generic_ip;
+ mbus = inode->i_private;
ubus = mbus->u_bus;
rp = kzalloc(sizeof(struct mon_reader_text), GFP_KERNEL);
@@ -401,7 +402,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
struct mon_event_text *ep;
mutex_lock(&mon_lock);
- mbus = inode->u.generic_ip;
+ mbus = inode->i_private;
if (mbus->nreaders <= 0) {
printk(KERN_ERR TAG ": consistency error on close\n");
@@ -435,7 +436,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations mon_fops_text = {
+const struct file_operations mon_fops_text = {
.owner = THIS_MODULE,
.open = mon_text_open,
.llseek = no_llseek,
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index 33678c24ebee..ab9d02d5df77 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -20,6 +20,7 @@ struct mon_bus {
struct dentry *dent_s; /* Debugging file */
struct dentry *dent_t; /* Text interface file */
struct usb_bus *u_bus;
+ int uses_dma;
/* Ref */
int nreaders; /* Under mon_lock AND mbus->lock */
@@ -53,7 +54,7 @@ extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
extern struct mutex mon_lock;
-extern struct file_operations mon_fops_text;
-extern struct file_operations mon_fops_stat;
+extern const struct file_operations mon_fops_text;
+extern const struct file_operations mon_fops_stat;
#endif /* __USB_MON_H */
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index 054059632a21..454a186b64ad 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -207,6 +207,14 @@ config USB_NET_PLUSB
Choose this option if you're using a host-to-host cable
with one of these chips.
+config USB_NET_MCS7830
+ tristate "MosChip MCS7830 based Ethernet adapters"
+ depends on USB_USBNET
+ help
+ Choose this option if you're using a 10/100 Ethernet USB2
+ adapter based on the MosChip 7830 controller. This includes
+ adapters marketed under the DeLOCK brand.
+
config USB_NET_RNDIS_HOST
tristate "Host for RNDIS devices (EXPERIMENTAL)"
depends on USB_USBNET && EXPERIMENTAL
diff --git a/drivers/usb/net/Makefile b/drivers/usb/net/Makefile
index 160f19dbdf12..7b51964de171 100644
--- a/drivers/usb/net/Makefile
+++ b/drivers/usb/net/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_NET_PLUSB) += plusb.o
obj-$(CONFIG_USB_NET_RNDIS_HOST) += rndis_host.o
obj-$(CONFIG_USB_NET_CDC_SUBSET) += cdc_subset.o
obj-$(CONFIG_USB_NET_ZAURUS) += zaurus.o
+obj-$(CONFIG_USB_NET_MCS7830) += mcs7830.o
obj-$(CONFIG_USB_USBNET) += usbnet.o
ifeq ($(CONFIG_USB_DEBUG),y)
diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c
index 2e2bbc003e93..881841e600de 100644
--- a/drivers/usb/net/asix.c
+++ b/drivers/usb/net/asix.c
@@ -1,7 +1,8 @@
/*
* ASIX AX8817X based USB 2.0 Ethernet Devices
- * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2003-2006 David Hollis <dhollis@davehollis.com>
* Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (C) 2006 James Painter <jamie.painter@iname.com>
* Copyright (c) 2002-2003 TiVo Inc.
*
* This program is free software; you can redistribute it and/or modify
@@ -36,6 +37,9 @@
#include "usbnet.h"
+#define DRIVER_VERSION "14-Jun-2006"
+static const char driver_name [] = "asix";
+
/* ASIX AX8817X based USB 2.0 Ethernet Devices */
#define AX_CMD_SET_SW_MII 0x06
@@ -46,23 +50,25 @@
#define AX_CMD_WRITE_EEPROM 0x0c
#define AX_CMD_WRITE_ENABLE 0x0d
#define AX_CMD_WRITE_DISABLE 0x0e
+#define AX_CMD_READ_RX_CTL 0x0f
#define AX_CMD_WRITE_RX_CTL 0x10
#define AX_CMD_READ_IPG012 0x11
#define AX_CMD_WRITE_IPG0 0x12
#define AX_CMD_WRITE_IPG1 0x13
+#define AX_CMD_READ_NODE_ID 0x13
#define AX_CMD_WRITE_IPG2 0x14
#define AX_CMD_WRITE_MULTI_FILTER 0x16
-#define AX_CMD_READ_NODE_ID 0x17
+#define AX88172_CMD_READ_NODE_ID 0x17
#define AX_CMD_READ_PHY_ID 0x19
#define AX_CMD_READ_MEDIUM_STATUS 0x1a
#define AX_CMD_WRITE_MEDIUM_MODE 0x1b
#define AX_CMD_READ_MONITOR_MODE 0x1c
#define AX_CMD_WRITE_MONITOR_MODE 0x1d
+#define AX_CMD_READ_GPIOS 0x1e
#define AX_CMD_WRITE_GPIOS 0x1f
#define AX_CMD_SW_RESET 0x20
#define AX_CMD_SW_PHY_STATUS 0x21
#define AX_CMD_SW_PHY_SELECT 0x22
-#define AX88772_CMD_READ_NODE_ID 0x13
#define AX_MONITOR_MODE 0x01
#define AX_MONITOR_LINK 0x02
@@ -70,15 +76,15 @@
#define AX_MONITOR_HSFS 0x10
/* AX88172 Medium Status Register values */
-#define AX_MEDIUM_FULL_DUPLEX 0x02
-#define AX_MEDIUM_TX_ABORT_ALLOW 0x04
-#define AX_MEDIUM_FLOW_CONTROL_EN 0x10
+#define AX88172_MEDIUM_FD 0x02
+#define AX88172_MEDIUM_TX 0x04
+#define AX88172_MEDIUM_FC 0x10
+#define AX88172_MEDIUM_DEFAULT \
+ ( AX88172_MEDIUM_FD | AX88172_MEDIUM_TX | AX88172_MEDIUM_FC )
#define AX_MCAST_FILTER_SIZE 8
#define AX_MAX_MCAST 64
-#define AX_EEPROM_LEN 0x40
-
#define AX_SWRESET_CLEAR 0x00
#define AX_SWRESET_RR 0x01
#define AX_SWRESET_RT 0x02
@@ -92,23 +98,78 @@
#define AX88772_IPG1_DEFAULT 0x0c
#define AX88772_IPG2_DEFAULT 0x12
-#define AX88772_MEDIUM_FULL_DUPLEX 0x0002
-#define AX88772_MEDIUM_RESERVED 0x0004
-#define AX88772_MEDIUM_RX_FC_ENABLE 0x0010
-#define AX88772_MEDIUM_TX_FC_ENABLE 0x0020
-#define AX88772_MEDIUM_PAUSE_FORMAT 0x0080
-#define AX88772_MEDIUM_RX_ENABLE 0x0100
-#define AX88772_MEDIUM_100MB 0x0200
-#define AX88772_MEDIUM_DEFAULT \
- (AX88772_MEDIUM_FULL_DUPLEX | AX88772_MEDIUM_RX_FC_ENABLE | \
- AX88772_MEDIUM_TX_FC_ENABLE | AX88772_MEDIUM_100MB | \
- AX88772_MEDIUM_RESERVED | AX88772_MEDIUM_RX_ENABLE )
+/* AX88772 & AX88178 Medium Mode Register */
+#define AX_MEDIUM_PF 0x0080
+#define AX_MEDIUM_JFE 0x0040
+#define AX_MEDIUM_TFC 0x0020
+#define AX_MEDIUM_RFC 0x0010
+#define AX_MEDIUM_ENCK 0x0008
+#define AX_MEDIUM_AC 0x0004
+#define AX_MEDIUM_FD 0x0002
+#define AX_MEDIUM_GM 0x0001
+#define AX_MEDIUM_SM 0x1000
+#define AX_MEDIUM_SBP 0x0800
+#define AX_MEDIUM_PS 0x0200
+#define AX_MEDIUM_RE 0x0100
+
+#define AX88178_MEDIUM_DEFAULT \
+ (AX_MEDIUM_PS | AX_MEDIUM_FD | AX_MEDIUM_AC | \
+ AX_MEDIUM_RFC | AX_MEDIUM_TFC | AX_MEDIUM_JFE | \
+ AX_MEDIUM_RE )
-#define AX_EEPROM_MAGIC 0xdeadbeef
+#define AX88772_MEDIUM_DEFAULT \
+ (AX_MEDIUM_FD | AX_MEDIUM_RFC | \
+ AX_MEDIUM_TFC | AX_MEDIUM_PS | \
+ AX_MEDIUM_AC | AX_MEDIUM_RE )
+
+/* AX88772 & AX88178 RX_CTL values */
+#define AX_RX_CTL_SO 0x0080
+#define AX_RX_CTL_AP 0x0020
+#define AX_RX_CTL_AM 0x0010
+#define AX_RX_CTL_AB 0x0008
+#define AX_RX_CTL_SEP 0x0004
+#define AX_RX_CTL_AMALL 0x0002
+#define AX_RX_CTL_PRO 0x0001
+#define AX_RX_CTL_MFB_2048 0x0000
+#define AX_RX_CTL_MFB_4096 0x0100
+#define AX_RX_CTL_MFB_8192 0x0200
+#define AX_RX_CTL_MFB_16384 0x0300
+
+#define AX_DEFAULT_RX_CTL \
+ (AX_RX_CTL_SO | AX_RX_CTL_AB )
+
+/* GPIO 0 .. 2 toggles */
+#define AX_GPIO_GPO0EN 0x01 /* GPIO0 Output enable */
+#define AX_GPIO_GPO_0 0x02 /* GPIO0 Output value */
+#define AX_GPIO_GPO1EN 0x04 /* GPIO1 Output enable */
+#define AX_GPIO_GPO_1 0x08 /* GPIO1 Output value */
+#define AX_GPIO_GPO2EN 0x10 /* GPIO2 Output enable */
+#define AX_GPIO_GPO_2 0x20 /* GPIO2 Output value */
+#define AX_GPIO_RESERVED 0x40 /* Reserved */
+#define AX_GPIO_RSE 0x80 /* Reload serial EEPROM */
+
+#define AX_EEPROM_MAGIC 0xdeadbeef
+#define AX88172_EEPROM_LEN 0x40
+#define AX88772_EEPROM_LEN 0xff
+
+#define PHY_MODE_MARVELL 0x0000
+#define MII_MARVELL_LED_CTRL 0x0018
+#define MII_MARVELL_STATUS 0x001b
+#define MII_MARVELL_CTRL 0x0014
+
+#define MARVELL_LED_MANUAL 0x0019
+
+#define MARVELL_STATUS_HWCFG 0x0004
+
+#define MARVELL_CTRL_TXDELAY 0x0002
+#define MARVELL_CTRL_RXDELAY 0x0080
/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
struct asix_data {
u8 multi_filter[AX_MCAST_FILTER_SIZE];
+ u8 phymode;
+ u8 ledmode;
+ u8 eeprom_len;
};
struct ax88172_int_data {
@@ -122,6 +183,8 @@ struct ax88172_int_data {
static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
+ devdbg(dev,"asix_read_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
+ cmd, value, index, size);
return usb_control_msg(
dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
@@ -137,6 +200,8 @@ static int asix_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
u16 size, void *data)
{
+ devdbg(dev,"asix_write_cmd() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
+ cmd, value, index, size);
return usb_control_msg(
dev->udev,
usb_sndctrlpipe(dev->udev, 0),
@@ -149,7 +214,7 @@ static int asix_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
USB_CTRL_SET_TIMEOUT);
}
-static void asix_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
+static void asix_async_cmd_callback(struct urb *urb)
{
struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
@@ -161,12 +226,167 @@ static void asix_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
usb_free_urb(urb);
}
+static void
+asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ struct usb_ctrlrequest *req;
+ int status;
+ struct urb *urb;
+
+ devdbg(dev,"asix_write_cmd_async() cmd=0x%02x value=0x%04x index=0x%04x size=%d",
+ cmd, value, index, size);
+ if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
+ deverr(dev, "Error allocating URB in write_cmd_async!");
+ return;
+ }
+
+ if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
+ deverr(dev, "Failed to allocate memory for control request");
+ usb_free_urb(urb);
+ return;
+ }
+
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ req->bRequest = cmd;
+ req->wValue = value;
+ req->wIndex = index;
+ req->wLength = size;
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, data, size,
+ asix_async_cmd_callback, req);
+
+ if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
+ deverr(dev, "Error submitting the control message: status=%d",
+ status);
+ kfree(req);
+ usb_free_urb(urb);
+ }
+}
+
+static int asix_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ u8 *head;
+ u32 header;
+ char *packet;
+ struct sk_buff *ax_skb;
+ u16 size;
+
+ head = (u8 *) skb->data;
+ memcpy(&header, head, sizeof(header));
+ le32_to_cpus(&header);
+ packet = head + sizeof(header);
+
+ skb_pull(skb, 4);
+
+ while (skb->len > 0) {
+ if ((short)(header & 0x0000ffff) !=
+ ~((short)((header & 0xffff0000) >> 16))) {
+ deverr(dev,"asix_rx_fixup() Bad Header Length");
+ }
+ /* get the packet length */
+ size = (u16) (header & 0x0000ffff);
+
+ if ((skb->len) - ((size + 1) & 0xfffe) == 0)
+ return 2;
+ if (size > ETH_FRAME_LEN) {
+ deverr(dev,"asix_rx_fixup() Bad RX Length %d", size);
+ return 0;
+ }
+ ax_skb = skb_clone(skb, GFP_ATOMIC);
+ if (ax_skb) {
+ ax_skb->len = size;
+ ax_skb->data = packet;
+ ax_skb->tail = packet + size;
+ usbnet_skb_return(dev, ax_skb);
+ } else {
+ return 0;
+ }
+
+ skb_pull(skb, (size + 1) & 0xfffe);
+
+ if (skb->len == 0)
+ break;
+
+ head = (u8 *) skb->data;
+ memcpy(&header, head, sizeof(header));
+ le32_to_cpus(&header);
+ packet = head + sizeof(header);
+ skb_pull(skb, 4);
+ }
+
+ if (skb->len < 0) {
+ deverr(dev,"asix_rx_fixup() Bad SKB Length %d", skb->len);
+ return 0;
+ }
+ return 1;
+}
+
+static struct sk_buff *asix_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ int padlen;
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
+ u32 packet_len;
+ u32 padbytes = 0xffff0000;
+
+ padlen = ((skb->len + 4) % 512) ? 0 : 4;
+
+ if ((!skb_cloned(skb))
+ && ((headroom + tailroom) >= (4 + padlen))) {
+ if ((headroom < 4) || (tailroom < padlen)) {
+ skb->data = memmove(skb->head + 4, skb->data, skb->len);
+ skb->tail = skb->data + skb->len;
+ }
+ } else {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ skb_push(skb, 4);
+ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+ memcpy(skb->data, &packet_len, sizeof(packet_len));
+
+ if ((skb->len % 512) == 0) {
+ memcpy( skb->tail, &padbytes, sizeof(padbytes));
+ skb_put(skb, sizeof(padbytes));
+ }
+ return skb;
+}
+
+static void asix_status(struct usbnet *dev, struct urb *urb)
+{
+ struct ax88172_int_data *event;
+ int link;
+
+ if (urb->actual_length < 8)
+ return;
+
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ if (link) {
+ netif_carrier_on(dev->net);
+ usbnet_defer_kevent (dev, EVENT_LINK_RESET );
+ } else
+ netif_carrier_off(dev->net);
+ devdbg(dev, "Link Status is: %d", link);
+ }
+}
+
static inline int asix_set_sw_mii(struct usbnet *dev)
{
int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
if (ret < 0)
- devdbg(dev, "Failed to enable software MII access");
+ deverr(dev, "Failed to enable software MII access");
return ret;
}
@@ -175,24 +395,27 @@ static inline int asix_set_hw_mii(struct usbnet *dev)
int ret;
ret = asix_write_cmd(dev, AX_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
if (ret < 0)
- devdbg(dev, "Failed to enable hardware MII access");
+ deverr(dev, "Failed to enable hardware MII access");
return ret;
}
-static inline int asix_get_phyid(struct usbnet *dev)
+static inline int asix_get_phy_addr(struct usbnet *dev)
{
int ret = 0;
void *buf;
+ devdbg(dev, "asix_get_phy_addr()");
+
buf = kmalloc(2, GFP_KERNEL);
if (!buf)
goto out1;
if ((ret = asix_read_cmd(dev, AX_CMD_READ_PHY_ID,
0, 0, 2, buf)) < 2) {
- devdbg(dev, "Error reading PHYID register: %02x", ret);
+ deverr(dev, "Error reading PHYID register: %02x", ret);
goto out2;
}
+ devdbg(dev, "asix_get_phy_addr() returning 0x%04x", *((u16 *)buf));
ret = *((u8 *)buf + 1);
out2:
kfree(buf);
@@ -206,91 +429,109 @@ static int asix_sw_reset(struct usbnet *dev, u8 flags)
ret = asix_write_cmd(dev, AX_CMD_SW_RESET, flags, 0, 0, NULL);
if (ret < 0)
- devdbg(dev,"Failed to send software reset: %02x", ret);
+ deverr(dev,"Failed to send software reset: %02x", ret);
return ret;
}
+static u16 asix_read_rx_ctl(struct usbnet *dev)
+{
+ u16 ret = 0;
+ void *buf;
+
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ goto out1;
+
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_RX_CTL,
+ 0, 0, 2, buf)) < 2) {
+ deverr(dev, "Error reading RX_CTL register: %02x", ret);
+ goto out2;
+ }
+ ret = le16_to_cpu(*((u16 *)buf));
+out2:
+ kfree(buf);
+out1:
+ return ret;
+}
+
static int asix_write_rx_ctl(struct usbnet *dev, u16 mode)
{
int ret;
+ devdbg(dev,"asix_write_rx_ctl() - mode = 0x%04x", mode);
ret = asix_write_cmd(dev, AX_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
if (ret < 0)
- devdbg(dev, "Failed to write RX_CTL mode: %02x", ret);
+ deverr(dev, "Failed to write RX_CTL mode to 0x%04x: %02x",
+ mode, ret);
return ret;
}
-static void asix_status(struct usbnet *dev, struct urb *urb)
+static u16 asix_read_medium_status(struct usbnet *dev)
{
- struct ax88172_int_data *event;
- int link;
+ u16 ret = 0;
+ void *buf;
- if (urb->actual_length < 8)
- return;
+ buf = kmalloc(2, GFP_KERNEL);
+ if (!buf)
+ goto out1;
- event = urb->transfer_buffer;
- link = event->link & 0x01;
- if (netif_carrier_ok(dev->net) != link) {
- if (link) {
- netif_carrier_on(dev->net);
- usbnet_defer_kevent (dev, EVENT_LINK_RESET );
- } else
- netif_carrier_off(dev->net);
- devdbg(dev, "Link Status is: %d", link);
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_MEDIUM_STATUS,
+ 0, 0, 2, buf)) < 2) {
+ deverr(dev, "Error reading Medium Status register: %02x", ret);
+ goto out2;
}
+ ret = le16_to_cpu(*((u16 *)buf));
+out2:
+ kfree(buf);
+out1:
+ return ret;
}
-static void
-asix_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
- u16 size, void *data)
+static int asix_write_medium_mode(struct usbnet *dev, u16 mode)
{
- struct usb_ctrlrequest *req;
- int status;
- struct urb *urb;
+ int ret;
- if ((urb = usb_alloc_urb(0, GFP_ATOMIC)) == NULL) {
- devdbg(dev, "Error allocating URB in write_cmd_async!");
- return;
- }
+ devdbg(dev,"asix_write_medium_mode() - mode = 0x%04x", mode);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ if (ret < 0)
+ deverr(dev, "Failed to write Medium Mode mode to 0x%04x: %02x",
+ mode, ret);
- if ((req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC)) == NULL) {
- deverr(dev, "Failed to allocate memory for control request");
- usb_free_urb(urb);
- return;
- }
+ return ret;
+}
- req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
- req->bRequest = cmd;
- req->wValue = cpu_to_le16(value);
- req->wIndex = cpu_to_le16(index);
- req->wLength = cpu_to_le16(size);
+static int asix_write_gpio(struct usbnet *dev, u16 value, int sleep)
+{
+ int ret;
- usb_fill_control_urb(urb, dev->udev,
- usb_sndctrlpipe(dev->udev, 0),
- (void *)req, data, size,
- asix_async_cmd_callback, req);
+ devdbg(dev,"asix_write_gpio() - value = 0x%04x", value);
+ ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+ if (ret < 0)
+ deverr(dev, "Failed to write GPIO value 0x%04x: %02x",
+ value, ret);
- if((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- deverr(dev, "Error submitting the control message: status=%d",
- status);
- kfree(req);
- usb_free_urb(urb);
- }
+ if (sleep)
+ msleep(sleep);
+
+ return ret;
}
+/*
+ * AX88772 & AX88178 have a 16-bit RX_CTL value
+ */
static void asix_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
struct asix_data *data = (struct asix_data *)&dev->data;
- u8 rx_ctl = 0x8c;
+ u16 rx_ctl = AX_DEFAULT_RX_CTL;
if (net->flags & IFF_PROMISC) {
- rx_ctl |= 0x01;
+ rx_ctl |= AX_RX_CTL_PRO;
} else if (net->flags & IFF_ALLMULTI
|| net->mc_count > AX_MAX_MCAST) {
- rx_ctl |= 0x02;
+ rx_ctl |= AX_RX_CTL_AMALL;
} else if (net->mc_count == 0) {
/* just broadcast and directed */
} else {
@@ -317,7 +558,7 @@ static void asix_set_multicast(struct net_device *net)
asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
AX_MCAST_FILTER_SIZE, data->multi_filter);
- rx_ctl |= 0x10;
+ rx_ctl |= AX_RX_CTL_AM;
}
asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
@@ -328,55 +569,52 @@ static int asix_mdio_read(struct net_device *netdev, int phy_id, int loc)
struct usbnet *dev = netdev_priv(netdev);
u16 res;
+ mutex_lock(&dev->phy_mutex);
asix_set_sw_mii(dev);
asix_read_cmd(dev, AX_CMD_READ_MII_REG, phy_id,
(__u16)loc, 2, (u16 *)&res);
asix_set_hw_mii(dev);
+ mutex_unlock(&dev->phy_mutex);
- return res & 0xffff;
-}
+ devdbg(dev, "asix_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x", phy_id, loc, le16_to_cpu(res & 0xffff));
-/* same as above, but converts resulting value to cpu byte order */
-static int asix_mdio_read_le(struct net_device *netdev, int phy_id, int loc)
-{
- return le16_to_cpu(asix_mdio_read(netdev,phy_id, loc));
+ return le16_to_cpu(res & 0xffff);
}
static void
asix_mdio_write(struct net_device *netdev, int phy_id, int loc, int val)
{
struct usbnet *dev = netdev_priv(netdev);
- u16 res = val;
+ u16 res = cpu_to_le16(val);
+ devdbg(dev, "asix_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x", phy_id, loc, val);
+ mutex_lock(&dev->phy_mutex);
asix_set_sw_mii(dev);
asix_write_cmd(dev, AX_CMD_WRITE_MII_REG, phy_id,
(__u16)loc, 2, (u16 *)&res);
asix_set_hw_mii(dev);
+ mutex_unlock(&dev->phy_mutex);
}
-/* same as above, but converts new value to le16 byte order before writing */
-static void
-asix_mdio_write_le(struct net_device *netdev, int phy_id, int loc, int val)
+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
+static u32 asix_get_phyid(struct usbnet *dev)
{
- asix_mdio_write( netdev, phy_id, loc, cpu_to_le16(val) );
-}
+ int phy_reg;
+ u32 phy_id;
-static int ax88172_link_reset(struct usbnet *dev)
-{
- u16 lpa;
- u16 adv;
- u16 res;
- u8 mode;
+ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
+ if (phy_reg < 0)
+ return 0;
- mode = AX_MEDIUM_TX_ABORT_ALLOW | AX_MEDIUM_FLOW_CONTROL_EN;
- lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
- adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
- res = mii_nway_result(lpa|adv);
- if (res & LPA_DUPLEX)
- mode |= AX_MEDIUM_FULL_DUPLEX;
- asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ phy_id = (phy_reg & 0xffff) << 16;
- return 0;
+ phy_reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
+ if (phy_reg < 0)
+ return 0;
+
+ phy_id |= (phy_reg & 0xffff);
+
+ return phy_id;
}
static void
@@ -423,7 +661,10 @@ asix_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
static int asix_get_eeprom_len(struct net_device *net)
{
- return AX_EEPROM_LEN;
+ struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
+ return data->eeprom_len;
}
static int asix_get_eeprom(struct net_device *net,
@@ -453,23 +694,28 @@ static int asix_get_eeprom(struct net_device *net,
static void asix_get_drvinfo (struct net_device *net,
struct ethtool_drvinfo *info)
{
+ struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
/* Inherit standard device info */
usbnet_get_drvinfo(net, info);
- info->eedump_len = 0x3e;
+ strncpy (info->driver, driver_name, sizeof info->driver);
+ strncpy (info->version, DRIVER_VERSION, sizeof info->version);
+ info->eedump_len = data->eeprom_len;
}
-static int asix_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
+static u32 asix_get_link(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
- return mii_ethtool_gset(&dev->mii,cmd);
+ return mii_link_ok(&dev->mii);
}
-static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
+static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
{
struct usbnet *dev = netdev_priv(net);
- return mii_ethtool_sset(&dev->mii,cmd);
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
}
/* We need to override some ethtool_ops so we require our
@@ -477,22 +723,78 @@ static int asix_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
devices that may be connected at the same time. */
static struct ethtool_ops ax88172_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
- .get_link = ethtool_op_get_link,
+ .get_link = asix_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
.set_wol = asix_set_wol,
.get_eeprom_len = asix_get_eeprom_len,
.get_eeprom = asix_get_eeprom,
- .get_settings = asix_get_settings,
- .set_settings = asix_set_settings,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
};
-static int asix_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+static void ax88172_set_multicast(struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ u8 rx_ctl = 0x8c;
- return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= 0x01;
+ } else if (net->flags & IFF_ALLMULTI
+ || net->mc_count > AX_MAX_MCAST) {
+ rx_ctl |= 0x02;
+ } else if (net->mc_count == 0) {
+ /* just broadcast and directed */
+ } else {
+ /* We use the 20 byte dev->data
+ * for our 8 byte filter buffer
+ * to avoid allocating memory that
+ * is tricky to free later */
+ struct dev_mc_list *mc_list = net->mc_list;
+ u32 crc_bits;
+ int i;
+
+ memset(data->multi_filter, 0, AX_MCAST_FILTER_SIZE);
+
+ /* Build the multicast hash filter. */
+ for (i = 0; i < net->mc_count; i++) {
+ crc_bits =
+ ether_crc(ETH_ALEN,
+ mc_list->dmi_addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ mc_list = mc_list->next;
+ }
+
+ asix_write_cmd_async(dev, AX_CMD_WRITE_MULTI_FILTER, 0, 0,
+ AX_MCAST_FILTER_SIZE, data->multi_filter);
+
+ rx_ctl |= 0x10;
+ }
+
+ asix_write_cmd_async(dev, AX_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+}
+
+static int ax88172_link_reset(struct usbnet *dev)
+{
+ u8 mode;
+ struct ethtool_cmd ecmd;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = AX88172_MEDIUM_DEFAULT;
+
+ if (ecmd.duplex != DUPLEX_FULL)
+ mode |= ~AX88172_MEDIUM_FD;
+
+ devdbg(dev, "ax88172_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+
+ asix_write_medium_mode(dev, mode);
+
+ return 0;
}
static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
@@ -501,6 +803,9 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
void *buf;
int i;
unsigned long gpio_bits = dev->driver_info->data;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
+ data->eeprom_len = AX88172_EEPROM_LEN;
usbnet_get_endpoints(dev,intf);
@@ -519,12 +824,12 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
msleep(5);
}
- if ((ret = asix_write_rx_ctl(dev,0x80)) < 0)
+ if ((ret = asix_write_rx_ctl(dev, 0x80)) < 0)
goto out2;
/* Get the MAC address */
memset(buf, 0, ETH_ALEN);
- if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+ if ((ret = asix_read_cmd(dev, AX88172_CMD_READ_NODE_ID,
0, 0, 6, buf)) < 0) {
dbg("read AX_CMD_READ_NODE_ID failed: %d", ret);
goto out2;
@@ -537,14 +842,14 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
dev->mii.mdio_write = asix_mdio_write;
dev->mii.phy_id_mask = 0x3f;
dev->mii.reg_num_mask = 0x1f;
- dev->mii.phy_id = asix_get_phyid(dev);
+ dev->mii.phy_id = asix_get_phy_addr(dev);
dev->net->do_ioctl = asix_ioctl;
- dev->net->set_multicast_list = asix_set_multicast;
+ dev->net->set_multicast_list = ax88172_set_multicast;
dev->net->ethtool_ops = &ax88172_ethtool_ops;
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
mii_nway_restart(&dev->mii);
@@ -557,21 +862,49 @@ out1:
static struct ethtool_ops ax88772_ethtool_ops = {
.get_drvinfo = asix_get_drvinfo,
- .get_link = ethtool_op_get_link,
+ .get_link = asix_get_link,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
.get_wol = asix_get_wol,
.set_wol = asix_set_wol,
.get_eeprom_len = asix_get_eeprom_len,
.get_eeprom = asix_get_eeprom,
- .get_settings = asix_get_settings,
- .set_settings = asix_set_settings,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
};
+static int ax88772_link_reset(struct usbnet *dev)
+{
+ u16 mode;
+ struct ethtool_cmd ecmd;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = AX88772_MEDIUM_DEFAULT;
+
+ if (ecmd.speed != SPEED_100)
+ mode &= ~AX_MEDIUM_PS;
+
+ if (ecmd.duplex != DUPLEX_FULL)
+ mode &= ~AX_MEDIUM_FD;
+
+ devdbg(dev, "ax88772_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+
+ asix_write_medium_mode(dev, mode);
+
+ return 0;
+}
+
static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
{
int ret;
void *buf;
+ u16 rx_ctl;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ u32 phyid;
+
+ data->eeprom_len = AX88772_EEPROM_LEN;
usbnet_get_endpoints(dev,intf);
@@ -582,13 +915,12 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
goto out1;
}
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_GPIOS,
- 0x00B0, 0, 0, buf)) < 0)
+ if ((ret = asix_write_gpio(dev,
+ AX_GPIO_RSE | AX_GPIO_GPO_2 | AX_GPIO_GPO2EN, 5)) < 0)
goto out2;
- msleep(5);
if ((ret = asix_write_cmd(dev, AX_CMD_SW_PHY_SELECT,
- 0x0001, 0, 0, buf)) < 0) {
+ 0x0000, 0, 0, buf)) < 0) {
dbg("Select PHY #1 failed: %d", ret);
goto out2;
}
@@ -605,36 +937,34 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
goto out2;
msleep(150);
- if ((ret = asix_write_rx_ctl(dev, 0x00)) < 0)
+ rx_ctl = asix_read_rx_ctl(dev);
+ dbg("RX_CTL is 0x%04x after software reset", rx_ctl);
+ if ((ret = asix_write_rx_ctl(dev, 0x0000)) < 0)
goto out2;
+ rx_ctl = asix_read_rx_ctl(dev);
+ dbg("RX_CTL is 0x%04x setting to 0x0000", rx_ctl);
+
/* Get the MAC address */
memset(buf, 0, ETH_ALEN);
- if ((ret = asix_read_cmd(dev, AX88772_CMD_READ_NODE_ID,
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
0, 0, ETH_ALEN, buf)) < 0) {
dbg("Failed to read MAC address: %d", ret);
goto out2;
}
memcpy(dev->net->dev_addr, buf, ETH_ALEN);
- if ((ret = asix_set_sw_mii(dev)) < 0)
- goto out2;
-
- if (((ret = asix_read_cmd(dev, AX_CMD_READ_MII_REG,
- 0x0010, 2, 2, buf)) < 0)
- || (*((u16 *)buf) != 0x003b)) {
- dbg("Read PHY register 2 must be 0x3b00: %d", ret);
- goto out2;
- }
-
/* Initialize MII structure */
dev->mii.dev = dev->net;
dev->mii.mdio_read = asix_mdio_read;
dev->mii.mdio_write = asix_mdio_write;
- dev->mii.phy_id_mask = 0xff;
- dev->mii.reg_num_mask = 0xff;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
dev->net->do_ioctl = asix_ioctl;
- dev->mii.phy_id = asix_get_phyid(dev);
+ dev->mii.phy_id = asix_get_phy_addr(dev);
+
+ phyid = asix_get_phyid(dev);
+ dbg("PHYID=0x%08x", phyid);
if ((ret = asix_sw_reset(dev, AX_SWRESET_PRL)) < 0)
goto out2;
@@ -649,16 +979,13 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dev->net->set_multicast_list = asix_set_multicast;
dev->net->ethtool_ops = &ax88772_ethtool_ops;
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
- asix_mdio_write_le(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
ADVERTISE_ALL | ADVERTISE_CSMA);
mii_nway_restart(&dev->mii);
- if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE,
- AX88772_MEDIUM_DEFAULT, 0, 0, buf)) < 0) {
- dbg("Write medium mode register: %d", ret);
+ if ((ret = asix_write_medium_mode(dev, AX88772_MEDIUM_DEFAULT)) < 0)
goto out2;
- }
if ((ret = asix_write_cmd(dev, AX_CMD_WRITE_IPG0,
AX88772_IPG0_DEFAULT | AX88772_IPG1_DEFAULT,
@@ -666,13 +993,17 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
dbg("Write IPG,IPG1,IPG2 failed: %d", ret);
goto out2;
}
- if ((ret = asix_set_hw_mii(dev)) < 0)
- goto out2;
/* Set RX_CTL to default values with 2k buffer, and enable cactus */
- if ((ret = asix_write_rx_ctl(dev, 0x0088)) < 0)
+ if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
goto out2;
+ rx_ctl = asix_read_rx_ctl(dev);
+ dbg("RX_CTL is 0x%04x after all initializations", rx_ctl);
+
+ rx_ctl = asix_read_medium_status(dev);
+ dbg("Medium Status is 0x%04x after all initializations", rx_ctl);
+
kfree(buf);
/* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
@@ -690,120 +1021,285 @@ out1:
return ret;
}
-static int ax88772_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+static struct ethtool_ops ax88178_ethtool_ops = {
+ .get_drvinfo = asix_get_drvinfo,
+ .get_link = asix_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_wol = asix_get_wol,
+ .set_wol = asix_set_wol,
+ .get_eeprom_len = asix_get_eeprom_len,
+ .get_eeprom = asix_get_eeprom,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static int marvell_phy_init(struct usbnet *dev)
{
- u8 *head;
- u32 header;
- char *packet;
- struct sk_buff *ax_skb;
- u16 size;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ u16 reg;
- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
+ devdbg(dev,"marvell_phy_init()");
- skb_pull(skb, 4);
+ reg = asix_mdio_read(dev->net, dev->mii.phy_id, MII_MARVELL_STATUS);
+ devdbg(dev,"MII_MARVELL_STATUS = 0x%04x", reg);
- while (skb->len > 0) {
- if ((short)(header & 0x0000ffff) !=
- ~((short)((header & 0xffff0000) >> 16))) {
- devdbg(dev,"header length data is error");
- }
- /* get the packet length */
- size = (u16) (header & 0x0000ffff);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_MARVELL_CTRL,
+ MARVELL_CTRL_RXDELAY | MARVELL_CTRL_TXDELAY);
- if ((skb->len) - ((size + 1) & 0xfffe) == 0)
- return 2;
- if (size > ETH_FRAME_LEN) {
- devdbg(dev,"invalid rx length %d", size);
- return 0;
- }
- ax_skb = skb_clone(skb, GFP_ATOMIC);
- if (ax_skb) {
- ax_skb->len = size;
- ax_skb->data = packet;
- ax_skb->tail = packet + size;
- usbnet_skb_return(dev, ax_skb);
- } else {
- return 0;
- }
+ if (data->ledmode) {
+ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
+ MII_MARVELL_LED_CTRL);
+ devdbg(dev,"MII_MARVELL_LED_CTRL (1) = 0x%04x", reg);
- skb_pull(skb, (size + 1) & 0xfffe);
+ reg &= 0xf8ff;
+ reg |= (1 + 0x0100);
+ asix_mdio_write(dev->net, dev->mii.phy_id,
+ MII_MARVELL_LED_CTRL, reg);
- if (skb->len == 0)
- break;
+ reg = asix_mdio_read(dev->net, dev->mii.phy_id,
+ MII_MARVELL_LED_CTRL);
+ devdbg(dev,"MII_MARVELL_LED_CTRL (2) = 0x%04x", reg);
+ reg &= 0xfc0f;
+ }
- head = (u8 *) skb->data;
- memcpy(&header, head, sizeof(header));
- le32_to_cpus(&header);
- packet = head + sizeof(header);
- skb_pull(skb, 4);
+ return 0;
+}
+
+static int marvell_led_status(struct usbnet *dev, u16 speed)
+{
+ u16 reg = asix_mdio_read(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL);
+
+ devdbg(dev, "marvell_led_status() read 0x%04x", reg);
+
+ /* Clear out the center LED bits - 0x03F0 */
+ reg &= 0xfc0f;
+
+ switch (speed) {
+ case SPEED_1000:
+ reg |= 0x03e0;
+ break;
+ case SPEED_100:
+ reg |= 0x03b0;
+ break;
+ default:
+ reg |= 0x02f0;
}
- if (skb->len < 0) {
- devdbg(dev,"invalid rx length %d", skb->len);
- return 0;
+ devdbg(dev, "marvell_led_status() writing 0x%04x", reg);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MARVELL_LED_MANUAL, reg);
+
+ return 0;
+}
+
+static int ax88178_link_reset(struct usbnet *dev)
+{
+ u16 mode;
+ struct ethtool_cmd ecmd;
+ struct asix_data *data = (struct asix_data *)&dev->data;
+
+ devdbg(dev,"ax88178_link_reset()");
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = AX88178_MEDIUM_DEFAULT;
+
+ if (ecmd.speed == SPEED_1000)
+ mode |= AX_MEDIUM_GM | AX_MEDIUM_ENCK;
+ else if (ecmd.speed == SPEED_100)
+ mode |= AX_MEDIUM_PS;
+ else
+ mode &= ~(AX_MEDIUM_PS | AX_MEDIUM_GM);
+
+ if (ecmd.duplex == DUPLEX_FULL)
+ mode |= AX_MEDIUM_FD;
+ else
+ mode &= ~AX_MEDIUM_FD;
+
+ devdbg(dev, "ax88178_link_reset() speed: %d duplex: %d setting mode to 0x%04x", ecmd.speed, ecmd.duplex, mode);
+
+ asix_write_medium_mode(dev, mode);
+
+ if (data->phymode == PHY_MODE_MARVELL && data->ledmode)
+ marvell_led_status(dev, ecmd.speed);
+
+ return 0;
+}
+
+static void ax88178_set_mfb(struct usbnet *dev)
+{
+ u16 mfb = AX_RX_CTL_MFB_16384;
+ u16 rxctl;
+ u16 medium;
+ int old_rx_urb_size = dev->rx_urb_size;
+
+ if (dev->hard_mtu < 2048) {
+ dev->rx_urb_size = 2048;
+ mfb = AX_RX_CTL_MFB_2048;
+ } else if (dev->hard_mtu < 4096) {
+ dev->rx_urb_size = 4096;
+ mfb = AX_RX_CTL_MFB_4096;
+ } else if (dev->hard_mtu < 8192) {
+ dev->rx_urb_size = 8192;
+ mfb = AX_RX_CTL_MFB_8192;
+ } else if (dev->hard_mtu < 16384) {
+ dev->rx_urb_size = 16384;
+ mfb = AX_RX_CTL_MFB_16384;
}
- return 1;
+
+ rxctl = asix_read_rx_ctl(dev);
+ asix_write_rx_ctl(dev, (rxctl & ~AX_RX_CTL_MFB_16384) | mfb);
+
+ medium = asix_read_medium_status(dev);
+ if (dev->net->mtu > 1500)
+ medium |= AX_MEDIUM_JFE;
+ else
+ medium &= ~AX_MEDIUM_JFE;
+ asix_write_medium_mode(dev, medium);
+
+ if (dev->rx_urb_size > old_rx_urb_size)
+ usbnet_unlink_rx_urbs(dev);
}
-static struct sk_buff *ax88772_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
- gfp_t flags)
+static int ax88178_change_mtu(struct net_device *net, int new_mtu)
{
- int padlen;
- int headroom = skb_headroom(skb);
- int tailroom = skb_tailroom(skb);
- u32 packet_len;
- u32 padbytes = 0xffff0000;
+ struct usbnet *dev = netdev_priv(net);
+ int ll_mtu = new_mtu + net->hard_header_len + 4;
- padlen = ((skb->len + 4) % 512) ? 0 : 4;
+ devdbg(dev, "ax88178_change_mtu() new_mtu=%d", new_mtu);
- if ((!skb_cloned(skb))
- && ((headroom + tailroom) >= (4 + padlen))) {
- if ((headroom < 4) || (tailroom < padlen)) {
- skb->data = memmove(skb->head + 4, skb->data, skb->len);
- skb->tail = skb->data + skb->len;
- }
+ if (new_mtu <= 0 || ll_mtu > 16384)
+ return -EINVAL;
+
+ if ((ll_mtu % dev->maxpacket) == 0)
+ return -EDOM;
+
+ net->mtu = new_mtu;
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+ ax88178_set_mfb(dev);
+
+ return 0;
+}
+
+static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct asix_data *data = (struct asix_data *)&dev->data;
+ int ret;
+ void *buf;
+ u16 eeprom;
+ int gpio0 = 0;
+ u32 phyid;
+
+ usbnet_get_endpoints(dev,intf);
+
+ buf = kmalloc(6, GFP_KERNEL);
+ if(!buf) {
+ dbg ("Cannot allocate memory for buffer");
+ ret = -ENOMEM;
+ goto out1;
+ }
+
+ eeprom = 0;
+ asix_read_cmd(dev, AX_CMD_READ_GPIOS, 0, 0, 1, &eeprom);
+ dbg("GPIO Status: 0x%04x", eeprom);
+
+ asix_write_cmd(dev, AX_CMD_WRITE_ENABLE, 0, 0, 0, NULL);
+ asix_read_cmd(dev, AX_CMD_READ_EEPROM, 0x0017, 0, 2, &eeprom);
+ asix_write_cmd(dev, AX_CMD_WRITE_DISABLE, 0, 0, 0, NULL);
+
+ dbg("EEPROM index 0x17 is 0x%04x", eeprom);
+
+ if (eeprom == 0xffff) {
+ data->phymode = PHY_MODE_MARVELL;
+ data->ledmode = 0;
+ gpio0 = 1;
} else {
- struct sk_buff *skb2;
- skb2 = skb_copy_expand(skb, 4, padlen, flags);
- dev_kfree_skb_any(skb);
- skb = skb2;
- if (!skb)
- return NULL;
+ data->phymode = eeprom & 7;
+ data->ledmode = eeprom >> 8;
+ gpio0 = (eeprom & 0x80) ? 0 : 1;
}
+ dbg("GPIO0: %d, PhyMode: %d", gpio0, data->phymode);
- skb_push(skb, 4);
- packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
- memcpy(skb->data, &packet_len, sizeof(packet_len));
+ asix_write_gpio(dev, AX_GPIO_RSE | AX_GPIO_GPO_1 | AX_GPIO_GPO1EN, 40);
+ if ((eeprom >> 8) != 1) {
+ asix_write_gpio(dev, 0x003c, 30);
+ asix_write_gpio(dev, 0x001c, 300);
+ asix_write_gpio(dev, 0x003c, 30);
+ } else {
+ dbg("gpio phymode == 1 path");
+ asix_write_gpio(dev, AX_GPIO_GPO1EN, 30);
+ asix_write_gpio(dev, AX_GPIO_GPO1EN | AX_GPIO_GPO_1, 30);
+ }
- if ((skb->len % 512) == 0) {
- memcpy( skb->tail, &padbytes, sizeof(padbytes));
- skb_put(skb, sizeof(padbytes));
+ asix_sw_reset(dev, 0);
+ msleep(150);
+
+ asix_sw_reset(dev, AX_SWRESET_PRL | AX_SWRESET_IPPD);
+ msleep(150);
+
+ asix_write_rx_ctl(dev, 0);
+
+ /* Get the MAC address */
+ memset(buf, 0, ETH_ALEN);
+ if ((ret = asix_read_cmd(dev, AX_CMD_READ_NODE_ID,
+ 0, 0, ETH_ALEN, buf)) < 0) {
+ dbg("Failed to read MAC address: %d", ret);
+ goto out2;
}
- return skb;
-}
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
-static int ax88772_link_reset(struct usbnet *dev)
-{
- u16 lpa;
- u16 adv;
- u16 res;
- u16 mode;
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = asix_mdio_read;
+ dev->mii.mdio_write = asix_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0xff;
+ dev->mii.supports_gmii = 1;
+ dev->net->do_ioctl = asix_ioctl;
+ dev->mii.phy_id = asix_get_phy_addr(dev);
+ dev->net->set_multicast_list = asix_set_multicast;
+ dev->net->ethtool_ops = &ax88178_ethtool_ops;
+ dev->net->change_mtu = &ax88178_change_mtu;
- mode = AX88772_MEDIUM_DEFAULT;
- lpa = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_LPA);
- adv = asix_mdio_read_le(dev->net, dev->mii.phy_id, MII_ADVERTISE);
- res = mii_nway_result(lpa|adv);
+ phyid = asix_get_phyid(dev);
+ dbg("PHYID=0x%08x", phyid);
+
+ if (data->phymode == PHY_MODE_MARVELL) {
+ marvell_phy_init(dev);
+ msleep(60);
+ }
- if ((res & LPA_DUPLEX) == 0)
- mode &= ~AX88772_MEDIUM_FULL_DUPLEX;
- if ((res & LPA_100) == 0)
- mode &= ~AX88772_MEDIUM_100MB;
- asix_write_cmd(dev, AX_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR,
+ BMCR_RESET | BMCR_ANENABLE);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP);
+ asix_mdio_write(dev->net, dev->mii.phy_id, MII_CTRL1000,
+ ADVERTISE_1000FULL);
+
+ mii_nway_restart(&dev->mii);
+
+ if ((ret = asix_write_medium_mode(dev, AX88178_MEDIUM_DEFAULT)) < 0)
+ goto out2;
+
+ if ((ret = asix_write_rx_ctl(dev, AX_DEFAULT_RX_CTL)) < 0)
+ goto out2;
+
+ kfree(buf);
+
+ /* Asix framing packs multiple eth frames into a 2K usb bulk transfer */
+ if (dev->driver_info->flags & FLAG_FRAMING_AX) {
+ /* hard_mtu is still the default - the device does not support
+ jumbo eth frames */
+ dev->rx_urb_size = 2048;
+ }
return 0;
+
+out2:
+ kfree(buf);
+out1:
+ return ret;
}
static const struct driver_info ax8817x_info = {
@@ -853,8 +1349,19 @@ static const struct driver_info ax88772_info = {
.link_reset = ax88772_link_reset,
.reset = ax88772_link_reset,
.flags = FLAG_ETHER | FLAG_FRAMING_AX,
- .rx_fixup = ax88772_rx_fixup,
- .tx_fixup = ax88772_tx_fixup,
+ .rx_fixup = asix_rx_fixup,
+ .tx_fixup = asix_tx_fixup,
+};
+
+static const struct driver_info ax88178_info = {
+ .description = "ASIX AX88178 USB 2.0 Ethernet",
+ .bind = ax88178_bind,
+ .status = asix_status,
+ .link_reset = ax88178_link_reset,
+ .reset = ax88178_link_reset,
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
+ .rx_fixup = asix_rx_fixup,
+ .tx_fixup = asix_tx_fixup,
};
static const struct usb_device_id products [] = {
@@ -913,7 +1420,7 @@ static const struct usb_device_id products [] = {
}, {
// ASIX AX88178 10/100/1000
USB_DEVICE (0x0b95, 0x1780),
- .driver_info = (unsigned long) &ax88772_info,
+ .driver_info = (unsigned long) &ax88178_info,
}, {
// Linksys USB200M Rev 2
USB_DEVICE (0x13b1, 0x0018),
@@ -922,6 +1429,18 @@ static const struct usb_device_id products [] = {
// 0Q0 cable ethernet
USB_DEVICE (0x1557, 0x7720),
.driver_info = (unsigned long) &ax88772_info,
+}, {
+ // DLink DUB-E100 H/W Ver B1
+ USB_DEVICE (0x07d1, 0x3c05),
+ .driver_info = (unsigned long) &ax88772_info,
+}, {
+ // DLink DUB-E100 H/W Ver B1 Alternate
+ USB_DEVICE (0x2001, 0x3c05),
+ .driver_info = (unsigned long) &ax88772_info,
+}, {
+ // Linksys USB1000
+ USB_DEVICE (0x1737, 0x0039),
+ .driver_info = (unsigned long) &ax88178_info,
},
{ }, // END
};
diff --git a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
index be5f5e142dd0..f740325abac4 100644
--- a/drivers/usb/net/catc.c
+++ b/drivers/usb/net/catc.c
@@ -223,7 +223,7 @@ struct catc {
* Receive routines.
*/
-static void catc_rx_done(struct urb *urb, struct pt_regs *regs)
+static void catc_rx_done(struct urb *urb)
{
struct catc *catc = urb->context;
u8 *pkt_start = urb->transfer_buffer;
@@ -289,7 +289,7 @@ static void catc_rx_done(struct urb *urb, struct pt_regs *regs)
}
}
-static void catc_irq_done(struct urb *urb, struct pt_regs *regs)
+static void catc_irq_done(struct urb *urb)
{
struct catc *catc = urb->context;
u8 *data = urb->transfer_buffer;
@@ -376,7 +376,7 @@ static void catc_tx_run(struct catc *catc)
catc->netdev->trans_start = jiffies;
}
-static void catc_tx_done(struct urb *urb, struct pt_regs *regs)
+static void catc_tx_done(struct urb *urb)
{
struct catc *catc = urb->context;
unsigned long flags;
@@ -486,7 +486,7 @@ static void catc_ctrl_run(struct catc *catc)
err("submit(ctrl_urb) status %d", status);
}
-static void catc_ctrl_done(struct urb *urb, struct pt_regs *regs)
+static void catc_ctrl_done(struct urb *urb)
{
struct catc *catc = urb->context;
struct ctrl_queue *q;
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index 82ce0358d9a3..f6971b88349d 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -498,7 +498,7 @@ static struct usb_driver cdc_driver = {
static int __init cdc_init(void)
{
- BUG_ON((sizeof(((struct usbnet *)0)->data)
+ BUILD_BUG_ON((sizeof(((struct usbnet *)0)->data)
< sizeof(struct cdc_state)));
return usb_register(&cdc_driver);
diff --git a/drivers/usb/net/gl620a.c b/drivers/usb/net/gl620a.c
index 3155f25f1d48..a3242be21959 100644
--- a/drivers/usb/net/gl620a.c
+++ b/drivers/usb/net/gl620a.c
@@ -106,7 +106,7 @@ static inline int gl_control_write(struct usbnet *dev, u8 request, u16 value)
return retval;
}
-static void gl_interrupt_complete(struct urb *urb, struct pt_regs *regs)
+static void gl_interrupt_complete(struct urb *urb)
{
int status = urb->status;
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index def3bb8e2290..7c906a43e497 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -65,16 +65,6 @@
#undef DEBUG
-#ifdef DEBUG
-#define kaweth_dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" ,##arg)
-#else
-#define kaweth_dbg(format, arg...) do {} while (0)
-#endif
-#define kaweth_err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" ,##arg)
-#define kaweth_info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ##arg)
-#define kaweth_warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ##arg)
-
-
#include "kawethfw.h"
#define KAWETH_MTU 1514
@@ -86,6 +76,9 @@
#define KAWETH_STATUS_BROKEN 0x0000001
#define KAWETH_STATUS_CLOSING 0x0000002
+#define KAWETH_STATUS_SUSPENDING 0x0000004
+
+#define KAWETH_STATUS_BLOCKED (KAWETH_STATUS_CLOSING | KAWETH_STATUS_SUSPENDING)
#define KAWETH_PACKET_FILTER_PROMISCUOUS 0x01
#define KAWETH_PACKET_FILTER_ALL_MULTICAST 0x02
@@ -112,6 +105,8 @@
#define STATE_MASK 0x40
#define STATE_SHIFT 5
+#define IS_BLOCKED(s) (s & KAWETH_STATUS_BLOCKED)
+
MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-picardie.fr>, Brad Hards <bhards@bigpond.net.au> and Oliver Neukum <oliver@neukum.org>");
MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
@@ -128,6 +123,8 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
unsigned int pipe,
struct usb_ctrlrequest *cmd, void *data,
int len, int timeout);
+static int kaweth_suspend(struct usb_interface *intf, pm_message_t message);
+static int kaweth_resume(struct usb_interface *intf);
/****************************************************************
* usb_device_id
@@ -165,6 +162,7 @@ static struct usb_device_id usb_klsi_table[] = {
{ USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */
{ USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */
{ USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */
+ { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */
{ USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */
{} /* Null terminator */
};
@@ -178,6 +176,8 @@ static struct usb_driver kaweth_driver = {
.name = driver_name,
.probe = kaweth_probe,
.disconnect = kaweth_disconnect,
+ .suspend = kaweth_suspend,
+ .resume = kaweth_resume,
.id_table = usb_klsi_table,
};
@@ -221,6 +221,7 @@ struct kaweth_device
int suspend_lowmem_rx;
int suspend_lowmem_ctrl;
int linkstate;
+ int opened;
struct work_struct lowmem_work;
struct usb_device *dev;
@@ -264,17 +265,17 @@ static int kaweth_control(struct kaweth_device *kaweth,
{
struct usb_ctrlrequest *dr;
- kaweth_dbg("kaweth_control()");
+ dbg("kaweth_control()");
if(in_interrupt()) {
- kaweth_dbg("in_interrupt()");
+ dbg("in_interrupt()");
return -EBUSY;
}
dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
if (!dr) {
- kaweth_dbg("kmalloc() failed");
+ dbg("kmalloc() failed");
return -ENOMEM;
}
@@ -299,7 +300,7 @@ static int kaweth_read_configuration(struct kaweth_device *kaweth)
{
int retval;
- kaweth_dbg("Reading kaweth configuration");
+ dbg("Reading kaweth configuration");
retval = kaweth_control(kaweth,
usb_rcvctrlpipe(kaweth->dev, 0),
@@ -321,7 +322,7 @@ static int kaweth_set_urb_size(struct kaweth_device *kaweth, __u16 urb_size)
{
int retval;
- kaweth_dbg("Setting URB size to %d", (unsigned)urb_size);
+ dbg("Setting URB size to %d", (unsigned)urb_size);
retval = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@@ -343,7 +344,7 @@ static int kaweth_set_sofs_wait(struct kaweth_device *kaweth, __u16 sofs_wait)
{
int retval;
- kaweth_dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
+ dbg("Set SOFS wait to %d", (unsigned)sofs_wait);
retval = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@@ -366,7 +367,7 @@ static int kaweth_set_receive_filter(struct kaweth_device *kaweth,
{
int retval;
- kaweth_dbg("Set receive filter to %d", (unsigned)receive_filter);
+ dbg("Set receive filter to %d", (unsigned)receive_filter);
retval = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@@ -391,7 +392,7 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
__u8 type)
{
if(data_len > KAWETH_FIRMWARE_BUF_SIZE) {
- kaweth_err("Firmware too big: %d", data_len);
+ err("Firmware too big: %d", data_len);
return -ENOSPC;
}
@@ -402,13 +403,13 @@ static int kaweth_download_firmware(struct kaweth_device *kaweth,
kaweth->firmware_buf[4] = type;
kaweth->firmware_buf[5] = interrupt;
- kaweth_dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
+ dbg("High: %i, Low:%i", kaweth->firmware_buf[3],
kaweth->firmware_buf[2]);
- kaweth_dbg("Downloading firmware at %p to kaweth device at %p",
+ dbg("Downloading firmware at %p to kaweth device at %p",
data,
kaweth);
- kaweth_dbg("Firmware length: %d", data_len);
+ dbg("Firmware length: %d", data_len);
return kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@@ -436,7 +437,7 @@ static int kaweth_trigger_firmware(struct kaweth_device *kaweth,
kaweth->firmware_buf[6] = 0x00;
kaweth->firmware_buf[7] = 0x00;
- kaweth_dbg("Triggering firmware");
+ dbg("Triggering firmware");
return kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
@@ -456,7 +457,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
{
int result;
- kaweth_dbg("kaweth_reset(%p)", kaweth);
+ dbg("kaweth_reset(%p)", kaweth);
result = kaweth_control(kaweth,
usb_sndctrlpipe(kaweth->dev, 0),
USB_REQ_SET_CONFIGURATION,
@@ -469,12 +470,12 @@ static int kaweth_reset(struct kaweth_device *kaweth)
mdelay(10);
- kaweth_dbg("kaweth_reset() returns %d.",result);
+ dbg("kaweth_reset() returns %d.",result);
return result;
}
-static void kaweth_usb_receive(struct urb *, struct pt_regs *regs);
+static void kaweth_usb_receive(struct urb *);
static int kaweth_resubmit_rx_urb(struct kaweth_device *, gfp_t);
/****************************************************************
@@ -499,7 +500,7 @@ static void kaweth_resubmit_int_urb(struct kaweth_device *kaweth, gfp_t mf)
kaweth->dev->devpath, status);
}
-static void int_callback(struct urb *u, struct pt_regs *regs)
+static void int_callback(struct urb *u)
{
struct kaweth_device *kaweth = u->context;
int act_state;
@@ -533,7 +534,7 @@ static void kaweth_resubmit_tl(void *d)
{
struct kaweth_device *kaweth = (struct kaweth_device *)d;
- if (kaweth->status | KAWETH_STATUS_CLOSING)
+ if (IS_BLOCKED(kaweth->status))
return;
if (kaweth->suspend_lowmem_rx)
@@ -567,7 +568,7 @@ static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
kaweth->suspend_lowmem_rx = 1;
schedule_delayed_work(&kaweth->lowmem_work, HZ/4);
}
- kaweth_err("resubmitting rx_urb %d failed", result);
+ err("resubmitting rx_urb %d failed", result);
} else {
kaweth->suspend_lowmem_rx = 0;
}
@@ -580,7 +581,7 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth);
/****************************************************************
* kaweth_usb_receive
****************************************************************/
-static void kaweth_usb_receive(struct urb *urb, struct pt_regs *regs)
+static void kaweth_usb_receive(struct urb *urb)
{
struct kaweth_device *kaweth = urb->context;
struct net_device *net = kaweth->net;
@@ -600,11 +601,15 @@ static void kaweth_usb_receive(struct urb *urb, struct pt_regs *regs)
return;
}
- if (kaweth->status & KAWETH_STATUS_CLOSING)
+ spin_lock(&kaweth->device_lock);
+ if (IS_BLOCKED(kaweth->status)) {
+ spin_unlock(&kaweth->device_lock);
return;
+ }
+ spin_unlock(&kaweth->device_lock);
if(urb->status && urb->status != -EREMOTEIO && count != 1) {
- kaweth_err("%s RX status: %d count: %d packet_len: %d",
+ err("%s RX status: %d count: %d packet_len: %d",
net->name,
urb->status,
count,
@@ -615,9 +620,9 @@ static void kaweth_usb_receive(struct urb *urb, struct pt_regs *regs)
if(kaweth->net && (count > 2)) {
if(pkt_len > (count - 2)) {
- kaweth_err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
- kaweth_err("Packet len & 2047: %x", pkt_len & 2047);
- kaweth_err("Count 2: %x", count2);
+ err("Packet length too long for USB frame (pkt_len: %x, count: %x)",pkt_len, count);
+ err("Packet len & 2047: %x", pkt_len & 2047);
+ err("Count 2: %x", count2);
kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC);
return;
}
@@ -654,7 +659,7 @@ static int kaweth_open(struct net_device *net)
struct kaweth_device *kaweth = netdev_priv(net);
int res;
- kaweth_dbg("Opening network device.");
+ dbg("Opening network device.");
res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
if (res)
@@ -677,6 +682,7 @@ static int kaweth_open(struct net_device *net)
usb_kill_urb(kaweth->rx_urb);
return -EIO;
}
+ kaweth->opened = 1;
netif_start_queue(net);
@@ -687,14 +693,8 @@ static int kaweth_open(struct net_device *net)
/****************************************************************
* kaweth_close
****************************************************************/
-static int kaweth_close(struct net_device *net)
+static void kaweth_kill_urbs(struct kaweth_device *kaweth)
{
- struct kaweth_device *kaweth = netdev_priv(net);
-
- netif_stop_queue(net);
-
- kaweth->status |= KAWETH_STATUS_CLOSING;
-
usb_kill_urb(kaweth->irq_urb);
usb_kill_urb(kaweth->rx_urb);
usb_kill_urb(kaweth->tx_urb);
@@ -705,6 +705,21 @@ static int kaweth_close(struct net_device *net)
we hit them again */
usb_kill_urb(kaweth->irq_urb);
usb_kill_urb(kaweth->rx_urb);
+}
+
+/****************************************************************
+ * kaweth_close
+ ****************************************************************/
+static int kaweth_close(struct net_device *net)
+{
+ struct kaweth_device *kaweth = netdev_priv(net);
+
+ netif_stop_queue(net);
+ kaweth->opened = 0;
+
+ kaweth->status |= KAWETH_STATUS_CLOSING;
+
+ kaweth_kill_urbs(kaweth);
kaweth->status &= ~KAWETH_STATUS_CLOSING;
@@ -724,14 +739,14 @@ static struct ethtool_ops ops = {
/****************************************************************
* kaweth_usb_transmit_complete
****************************************************************/
-static void kaweth_usb_transmit_complete(struct urb *urb, struct pt_regs *regs)
+static void kaweth_usb_transmit_complete(struct urb *urb)
{
struct kaweth_device *kaweth = urb->context;
struct sk_buff *skb = kaweth->tx_skb;
if (unlikely(urb->status != 0))
if (urb->status != -ENOENT)
- kaweth_dbg("%s: TX status %d.", kaweth->net->name, urb->status);
+ dbg("%s: TX status %d.", kaweth->net->name, urb->status);
netif_wake_queue(kaweth->net);
dev_kfree_skb_irq(skb);
@@ -751,6 +766,9 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
kaweth_async_set_rx_mode(kaweth);
netif_stop_queue(net);
+ if (IS_BLOCKED(kaweth->status)) {
+ goto skip;
+ }
/* We now decide whether we can put our special header into the sk_buff */
if (skb_cloned(skb) || skb_headroom(skb) < 2) {
@@ -782,7 +800,8 @@ static int kaweth_start_xmit(struct sk_buff *skb, struct net_device *net)
if((res = usb_submit_urb(kaweth->tx_urb, GFP_ATOMIC)))
{
- kaweth_warn("kaweth failed tx_urb %d", res);
+ warn("kaweth failed tx_urb %d", res);
+skip:
kaweth->stats.tx_errors++;
netif_start_queue(net);
@@ -811,7 +830,7 @@ static void kaweth_set_rx_mode(struct net_device *net)
KAWETH_PACKET_FILTER_BROADCAST |
KAWETH_PACKET_FILTER_MULTICAST;
- kaweth_dbg("Setting Rx mode to %d", packet_filter_bitmap);
+ dbg("Setting Rx mode to %d", packet_filter_bitmap);
netif_stop_queue(net);
@@ -849,10 +868,10 @@ static void kaweth_async_set_rx_mode(struct kaweth_device *kaweth)
KAWETH_CONTROL_TIMEOUT);
if(result < 0) {
- kaweth_err("Failed to set Rx mode: %d", result);
+ err("Failed to set Rx mode: %d", result);
}
else {
- kaweth_dbg("Set Rx mode to %d", packet_filter_bitmap);
+ dbg("Set Rx mode to %d", packet_filter_bitmap);
}
}
}
@@ -873,7 +892,7 @@ static void kaweth_tx_timeout(struct net_device *net)
{
struct kaweth_device *kaweth = netdev_priv(net);
- kaweth_warn("%s: Tx timed out. Resetting.", net->name);
+ warn("%s: Tx timed out. Resetting.", net->name);
kaweth->stats.tx_errors++;
net->trans_start = jiffies;
@@ -881,6 +900,42 @@ static void kaweth_tx_timeout(struct net_device *net)
}
/****************************************************************
+ * kaweth_suspend
+ ****************************************************************/
+static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct kaweth_device *kaweth = usb_get_intfdata(intf);
+ unsigned long flags;
+
+ spin_lock_irqsave(&kaweth->device_lock, flags);
+ kaweth->status |= KAWETH_STATUS_SUSPENDING;
+ spin_unlock_irqrestore(&kaweth->device_lock, flags);
+
+ kaweth_kill_urbs(kaweth);
+ return 0;
+}
+
+/****************************************************************
+ * kaweth_resume
+ ****************************************************************/
+static int kaweth_resume(struct usb_interface *intf)
+{
+ struct kaweth_device *kaweth = usb_get_intfdata(intf);
+ unsigned long flags;
+
+ spin_lock_irqsave(&kaweth->device_lock, flags);
+ kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
+ spin_unlock_irqrestore(&kaweth->device_lock, flags);
+
+ if (!kaweth->opened)
+ return 0;
+ kaweth_resubmit_rx_urb(kaweth, GFP_NOIO);
+ kaweth_resubmit_int_urb(kaweth, GFP_NOIO);
+
+ return 0;
+}
+
+/****************************************************************
* kaweth_probe
****************************************************************/
static int kaweth_probe(
@@ -894,15 +949,15 @@ static int kaweth_probe(
const eth_addr_t bcast_addr = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
int result = 0;
- kaweth_dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
+ dbg("Kawasaki Device Probe (Device number:%d): 0x%4.4x:0x%4.4x:0x%4.4x",
dev->devnum,
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct),
le16_to_cpu(dev->descriptor.bcdDevice));
- kaweth_dbg("Device at %p", dev);
+ dbg("Device at %p", dev);
- kaweth_dbg("Descriptor length: %x type: %x",
+ dbg("Descriptor length: %x type: %x",
(int)dev->descriptor.bLength,
(int)dev->descriptor.bDescriptorType);
@@ -917,7 +972,7 @@ static int kaweth_probe(
spin_lock_init(&kaweth->device_lock);
init_waitqueue_head(&kaweth->term_wait);
- kaweth_dbg("Resetting.");
+ dbg("Resetting.");
kaweth_reset(kaweth);
@@ -927,17 +982,17 @@ static int kaweth_probe(
*/
if (le16_to_cpu(dev->descriptor.bcdDevice) >> 8) {
- kaweth_info("Firmware present in device.");
+ info("Firmware present in device.");
} else {
/* Download the firmware */
- kaweth_info("Downloading firmware...");
+ info("Downloading firmware...");
kaweth->firmware_buf = (__u8 *)__get_free_page(GFP_KERNEL);
if ((result = kaweth_download_firmware(kaweth,
kaweth_new_code,
len_kaweth_new_code,
100,
2)) < 0) {
- kaweth_err("Error downloading firmware (%d)", result);
+ err("Error downloading firmware (%d)", result);
goto err_fw;
}
@@ -946,7 +1001,7 @@ static int kaweth_probe(
len_kaweth_new_code_fix,
100,
3)) < 0) {
- kaweth_err("Error downloading firmware fix (%d)", result);
+ err("Error downloading firmware fix (%d)", result);
goto err_fw;
}
@@ -955,7 +1010,7 @@ static int kaweth_probe(
len_kaweth_trigger_code,
126,
2)) < 0) {
- kaweth_err("Error downloading trigger code (%d)", result);
+ err("Error downloading trigger code (%d)", result);
goto err_fw;
}
@@ -965,18 +1020,18 @@ static int kaweth_probe(
len_kaweth_trigger_code_fix,
126,
3)) < 0) {
- kaweth_err("Error downloading trigger code fix (%d)", result);
+ err("Error downloading trigger code fix (%d)", result);
goto err_fw;
}
if ((result = kaweth_trigger_firmware(kaweth, 126)) < 0) {
- kaweth_err("Error triggering firmware (%d)", result);
+ err("Error triggering firmware (%d)", result);
goto err_fw;
}
/* Device will now disappear for a moment... */
- kaweth_info("Firmware loaded. I'll be back...");
+ info("Firmware loaded. I'll be back...");
err_fw:
free_page((unsigned long)kaweth->firmware_buf);
free_netdev(netdev);
@@ -986,14 +1041,14 @@ err_fw:
result = kaweth_read_configuration(kaweth);
if(result < 0) {
- kaweth_err("Error reading configuration (%d), no net device created", result);
+ err("Error reading configuration (%d), no net device created", result);
goto err_free_netdev;
}
- kaweth_info("Statistics collection: %x", kaweth->configuration.statistics_mask);
- kaweth_info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
- kaweth_info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
- kaweth_info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
+ info("Statistics collection: %x", kaweth->configuration.statistics_mask);
+ info("Multicast filter limit: %x", kaweth->configuration.max_multicast_filters & ((1 << 15) - 1));
+ info("MTU: %d", le16_to_cpu(kaweth->configuration.segment_size));
+ info("Read MAC address %2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x",
(int)kaweth->configuration.hw_addr[0],
(int)kaweth->configuration.hw_addr[1],
(int)kaweth->configuration.hw_addr[2],
@@ -1004,17 +1059,17 @@ err_fw:
if(!memcmp(&kaweth->configuration.hw_addr,
&bcast_addr,
sizeof(bcast_addr))) {
- kaweth_err("Firmware not functioning properly, no net device created");
+ err("Firmware not functioning properly, no net device created");
goto err_free_netdev;
}
if(kaweth_set_urb_size(kaweth, KAWETH_BUF_SIZE) < 0) {
- kaweth_dbg("Error setting URB size");
+ dbg("Error setting URB size");
goto err_free_netdev;
}
if(kaweth_set_sofs_wait(kaweth, KAWETH_SOFS_TO_WAIT) < 0) {
- kaweth_err("Error setting SOFS wait");
+ err("Error setting SOFS wait");
goto err_free_netdev;
}
@@ -1024,11 +1079,11 @@ err_fw:
KAWETH_PACKET_FILTER_MULTICAST);
if(result < 0) {
- kaweth_err("Error setting receive filter");
+ err("Error setting receive filter");
goto err_free_netdev;
}
- kaweth_dbg("Initializing net device.");
+ dbg("Initializing net device.");
kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kaweth->tx_urb)
@@ -1085,13 +1140,13 @@ err_fw:
SET_NETDEV_DEV(netdev, &intf->dev);
if (register_netdev(netdev) != 0) {
- kaweth_err("Error registering netdev.");
+ err("Error registering netdev.");
goto err_intfdata;
}
- kaweth_info("kaweth interface created at %s", kaweth->net->name);
+ info("kaweth interface created at %s", kaweth->net->name);
- kaweth_dbg("Kaweth probe returning.");
+ dbg("Kaweth probe returning.");
return 0;
@@ -1120,16 +1175,16 @@ static void kaweth_disconnect(struct usb_interface *intf)
struct kaweth_device *kaweth = usb_get_intfdata(intf);
struct net_device *netdev;
- kaweth_info("Unregistering");
+ info("Unregistering");
usb_set_intfdata(intf, NULL);
if (!kaweth) {
- kaweth_warn("unregistering non-existant device");
+ warn("unregistering non-existant device");
return;
}
netdev = kaweth->net;
- kaweth_dbg("Unregistering net device");
+ dbg("Unregistering net device");
unregister_netdev(netdev);
usb_free_urb(kaweth->rx_urb);
@@ -1153,7 +1208,7 @@ struct usb_api_data {
/*-------------------------------------------------------------------*
* completion handler for compatibility wrappers (sync control/bulk) *
*-------------------------------------------------------------------*/
-static void usb_api_blocking_completion(struct urb *urb, struct pt_regs *regs)
+static void usb_api_blocking_completion(struct urb *urb)
{
struct usb_api_data *awd = (struct usb_api_data *)urb->context;
@@ -1184,7 +1239,7 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int* actual_length)
if (!wait_event_timeout(awd.wqh, awd.done, timeout)) {
// timeout
- kaweth_warn("usb_control/bulk_msg: timeout");
+ warn("usb_control/bulk_msg: timeout");
usb_kill_urb(urb); // remove urb safely
status = -ETIMEDOUT;
}
@@ -1233,7 +1288,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
****************************************************************/
static int __init kaweth_init(void)
{
- kaweth_dbg("Driver loading");
+ dbg("Driver loading");
return usb_register(&kaweth_driver);
}
diff --git a/drivers/usb/net/mcs7830.c b/drivers/usb/net/mcs7830.c
new file mode 100644
index 000000000000..6240b978fe3d
--- /dev/null
+++ b/drivers/usb/net/mcs7830.c
@@ -0,0 +1,534 @@
+/*
+ * MosChips MCS7830 based USB 2.0 Ethernet Devices
+ *
+ * based on usbnet.c, asix.c and the vendor provided mcs7830 driver
+ *
+ * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
+ * Copyright (c) 2002-2003 TiVo Inc.
+ *
+ * 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/crc32.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/init.h>
+#include <linux/mii.h>
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/usb.h>
+
+#include "usbnet.h"
+
+/* requests */
+#define MCS7830_RD_BMREQ (USB_DIR_IN | USB_TYPE_VENDOR | \
+ USB_RECIP_DEVICE)
+#define MCS7830_WR_BMREQ (USB_DIR_OUT | USB_TYPE_VENDOR | \
+ USB_RECIP_DEVICE)
+#define MCS7830_RD_BREQ 0x0E
+#define MCS7830_WR_BREQ 0x0D
+
+#define MCS7830_CTRL_TIMEOUT 1000
+#define MCS7830_MAX_MCAST 64
+
+#define MCS7830_VENDOR_ID 0x9710
+#define MCS7830_PRODUCT_ID 0x7830
+
+#define MCS7830_MII_ADVERTISE (ADVERTISE_PAUSE_CAP | ADVERTISE_100FULL | \
+ ADVERTISE_100HALF | ADVERTISE_10FULL | \
+ ADVERTISE_10HALF | ADVERTISE_CSMA)
+
+/* HIF_REG_XX coressponding index value */
+enum {
+ HIF_REG_MULTICAST_HASH = 0x00,
+ HIF_REG_PACKET_GAP1 = 0x08,
+ HIF_REG_PACKET_GAP2 = 0x09,
+ HIF_REG_PHY_DATA = 0x0a,
+ HIF_REG_PHY_CMD1 = 0x0c,
+ HIF_REG_PHY_CMD1_READ = 0x40,
+ HIF_REG_PHY_CMD1_WRITE = 0x20,
+ HIF_REG_PHY_CMD1_PHYADDR = 0x01,
+ HIF_REG_PHY_CMD2 = 0x0d,
+ HIF_REG_PHY_CMD2_PEND_FLAG_BIT = 0x80,
+ HIF_REG_PHY_CMD2_READY_FLAG_BIT = 0x40,
+ HIF_REG_CONFIG = 0x0e,
+ HIF_REG_CONFIG_CFG = 0x80,
+ HIF_REG_CONFIG_SPEED100 = 0x40,
+ HIF_REG_CONFIG_FULLDUPLEX_ENABLE = 0x20,
+ HIF_REG_CONFIG_RXENABLE = 0x10,
+ HIF_REG_CONFIG_TXENABLE = 0x08,
+ HIF_REG_CONFIG_SLEEPMODE = 0x04,
+ HIF_REG_CONFIG_ALLMULTICAST = 0x02,
+ HIF_REG_CONFIG_PROMISCIOUS = 0x01,
+ HIF_REG_ETHERNET_ADDR = 0x0f,
+ HIF_REG_22 = 0x15,
+ HIF_REG_PAUSE_THRESHOLD = 0x16,
+ HIF_REG_PAUSE_THRESHOLD_DEFAULT = 0,
+};
+
+struct mcs7830_data {
+ u8 multi_filter[8];
+ u8 config;
+};
+
+static const char driver_name[] = "MOSCHIP usb-ethernet driver";
+
+static int mcs7830_get_reg(struct usbnet *dev, u16 index, u16 size, void *data)
+{
+ struct usb_device *xdev = dev->udev;
+ int ret;
+
+ ret = usb_control_msg(xdev, usb_rcvctrlpipe(xdev, 0), MCS7830_RD_BREQ,
+ MCS7830_RD_BMREQ, 0x0000, index, data,
+ size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
+ return ret;
+}
+
+static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data)
+{
+ struct usb_device *xdev = dev->udev;
+ int ret;
+
+ ret = usb_control_msg(xdev, usb_sndctrlpipe(xdev, 0), MCS7830_WR_BREQ,
+ MCS7830_WR_BMREQ, 0x0000, index, data,
+ size, msecs_to_jiffies(MCS7830_CTRL_TIMEOUT));
+ return ret;
+}
+
+static void mcs7830_async_cmd_callback(struct urb *urb)
+{
+ struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context;
+
+ if (urb->status < 0)
+ printk(KERN_DEBUG "mcs7830_async_cmd_callback() failed with %d",
+ urb->status);
+
+ kfree(req);
+ usb_free_urb(urb);
+}
+
+static void mcs7830_set_reg_async(struct usbnet *dev, u16 index, u16 size, void *data)
+{
+ struct usb_ctrlrequest *req;
+ int ret;
+ struct urb *urb;
+
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ dev_dbg(&dev->udev->dev, "Error allocating URB "
+ "in write_cmd_async!");
+ return;
+ }
+
+ req = kmalloc(sizeof *req, GFP_ATOMIC);
+ if (!req) {
+ dev_err(&dev->udev->dev, "Failed to allocate memory for "
+ "control request");
+ goto out;
+ }
+ req->bRequestType = MCS7830_WR_BMREQ;
+ req->bRequest = MCS7830_WR_BREQ;
+ req->wValue = 0;
+ req->wIndex = cpu_to_le16(index);
+ req->wLength = cpu_to_le16(size);
+
+ usb_fill_control_urb(urb, dev->udev,
+ usb_sndctrlpipe(dev->udev, 0),
+ (void *)req, data, size,
+ mcs7830_async_cmd_callback, req);
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret < 0) {
+ dev_err(&dev->udev->dev, "Error submitting the control "
+ "message: ret=%d", ret);
+ goto out;
+ }
+ return;
+out:
+ kfree(req);
+ usb_free_urb(urb);
+}
+
+static int mcs7830_get_address(struct usbnet *dev)
+{
+ int ret;
+ ret = mcs7830_get_reg(dev, HIF_REG_ETHERNET_ADDR, ETH_ALEN,
+ dev->net->dev_addr);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+static int mcs7830_read_phy(struct usbnet *dev, u8 index)
+{
+ int ret;
+ int i;
+ __le16 val;
+
+ u8 cmd[2] = {
+ HIF_REG_PHY_CMD1_READ | HIF_REG_PHY_CMD1_PHYADDR,
+ HIF_REG_PHY_CMD2_PEND_FLAG_BIT | index,
+ };
+
+ mutex_lock(&dev->phy_mutex);
+ /* write the MII command */
+ ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+ if (ret < 0)
+ goto out;
+
+ /* wait for the data to become valid, should be within < 1ms */
+ for (i = 0; i < 10; i++) {
+ ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+ if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
+ break;
+ ret = -EIO;
+ msleep(1);
+ }
+ if (ret < 0)
+ goto out;
+
+ /* read actual register contents */
+ ret = mcs7830_get_reg(dev, HIF_REG_PHY_DATA, 2, &val);
+ if (ret < 0)
+ goto out;
+ ret = le16_to_cpu(val);
+ dev_dbg(&dev->udev->dev, "read PHY reg %02x: %04x (%d tries)\n",
+ index, val, i);
+out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+static int mcs7830_write_phy(struct usbnet *dev, u8 index, u16 val)
+{
+ int ret;
+ int i;
+ __le16 le_val;
+
+ u8 cmd[2] = {
+ HIF_REG_PHY_CMD1_WRITE | HIF_REG_PHY_CMD1_PHYADDR,
+ HIF_REG_PHY_CMD2_PEND_FLAG_BIT | (index & 0x1F),
+ };
+
+ mutex_lock(&dev->phy_mutex);
+
+ /* write the new register contents */
+ le_val = cpu_to_le16(val);
+ ret = mcs7830_set_reg(dev, HIF_REG_PHY_DATA, 2, &le_val);
+ if (ret < 0)
+ goto out;
+
+ /* write the MII command */
+ ret = mcs7830_set_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+ if (ret < 0)
+ goto out;
+
+ /* wait for the command to be accepted by the PHY */
+ for (i = 0; i < 10; i++) {
+ ret = mcs7830_get_reg(dev, HIF_REG_PHY_CMD1, 2, cmd);
+ if ((ret < 0) || (cmd[1] & HIF_REG_PHY_CMD2_READY_FLAG_BIT))
+ break;
+ ret = -EIO;
+ msleep(1);
+ }
+ if (ret < 0)
+ goto out;
+
+ ret = 0;
+ dev_dbg(&dev->udev->dev, "write PHY reg %02x: %04x (%d tries)\n",
+ index, val, i);
+out:
+ mutex_unlock(&dev->phy_mutex);
+ return ret;
+}
+
+/*
+ * This algorithm comes from the original mcs7830 version 1.4 driver,
+ * not sure if it is needed.
+ */
+static int mcs7830_set_autoneg(struct usbnet *dev, int ptrUserPhyMode)
+{
+ int ret;
+ /* Enable all media types */
+ ret = mcs7830_write_phy(dev, MII_ADVERTISE, MCS7830_MII_ADVERTISE);
+
+ /* First reset BMCR */
+ if (!ret)
+ ret = mcs7830_write_phy(dev, MII_BMCR, 0x0000);
+ /* Enable Auto Neg */
+ if (!ret)
+ ret = mcs7830_write_phy(dev, MII_BMCR, BMCR_ANENABLE);
+ /* Restart Auto Neg (Keep the Enable Auto Neg Bit Set) */
+ if (!ret)
+ ret = mcs7830_write_phy(dev, MII_BMCR,
+ BMCR_ANENABLE | BMCR_ANRESTART );
+ return ret < 0 ? : 0;
+}
+
+
+/*
+ * if we can read register 22, the chip revision is C or higher
+ */
+static int mcs7830_get_rev(struct usbnet *dev)
+{
+ u8 dummy[2];
+ int ret;
+ ret = mcs7830_get_reg(dev, HIF_REG_22, 2, dummy);
+ if (ret > 0)
+ return 2; /* Rev C or later */
+ return 1; /* earlier revision */
+}
+
+/*
+ * On rev. C we need to set the pause threshold
+ */
+static void mcs7830_rev_C_fixup(struct usbnet *dev)
+{
+ u8 pause_threshold = HIF_REG_PAUSE_THRESHOLD_DEFAULT;
+ int retry;
+
+ for (retry = 0; retry < 2; retry++) {
+ if (mcs7830_get_rev(dev) == 2) {
+ dev_info(&dev->udev->dev, "applying rev.C fixup\n");
+ mcs7830_set_reg(dev, HIF_REG_PAUSE_THRESHOLD,
+ 1, &pause_threshold);
+ }
+ msleep(1);
+ }
+}
+
+static int mcs7830_init_dev(struct usbnet *dev)
+{
+ int ret;
+ int retry;
+
+ /* Read MAC address from EEPROM */
+ ret = -EINVAL;
+ for (retry = 0; retry < 5 && ret; retry++)
+ ret = mcs7830_get_address(dev);
+ if (ret) {
+ dev_warn(&dev->udev->dev, "Cannot read MAC address\n");
+ goto out;
+ }
+
+ /* Set up PHY */
+ ret = mcs7830_set_autoneg(dev, 0);
+ if (ret) {
+ dev_info(&dev->udev->dev, "Cannot set autoneg\n");
+ goto out;
+ }
+
+ mcs7830_rev_C_fixup(dev);
+ ret = 0;
+out:
+ return ret;
+}
+
+static int mcs7830_mdio_read(struct net_device *netdev, int phy_id,
+ int location)
+{
+ struct usbnet *dev = netdev->priv;
+ return mcs7830_read_phy(dev, location);
+}
+
+static void mcs7830_mdio_write(struct net_device *netdev, int phy_id,
+ int location, int val)
+{
+ struct usbnet *dev = netdev->priv;
+ mcs7830_write_phy(dev, location, val);
+}
+
+static int mcs7830_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+/* credits go to asix_set_multicast */
+static void mcs7830_set_multicast(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct mcs7830_data *data = (struct mcs7830_data *)&dev->data;
+
+ data->config = HIF_REG_CONFIG_TXENABLE;
+
+ /* this should not be needed, but it doesn't work otherwise */
+ data->config |= HIF_REG_CONFIG_ALLMULTICAST;
+
+ if (net->flags & IFF_PROMISC) {
+ data->config |= HIF_REG_CONFIG_PROMISCIOUS;
+ } else if (net->flags & IFF_ALLMULTI
+ || net->mc_count > MCS7830_MAX_MCAST) {
+ data->config |= HIF_REG_CONFIG_ALLMULTICAST;
+ } else if (net->mc_count == 0) {
+ /* just broadcast and directed */
+ } else {
+ /* We use the 20 byte dev->data
+ * for our 8 byte filter buffer
+ * to avoid allocating memory that
+ * is tricky to free later */
+ struct dev_mc_list *mc_list = net->mc_list;
+ u32 crc_bits;
+ int i;
+
+ memset(data->multi_filter, 0, sizeof data->multi_filter);
+
+ /* Build the multicast hash filter. */
+ for (i = 0; i < net->mc_count; i++) {
+ crc_bits = ether_crc(ETH_ALEN, mc_list->dmi_addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |= 1 << (crc_bits & 7);
+ mc_list = mc_list->next;
+ }
+
+ mcs7830_set_reg_async(dev, HIF_REG_MULTICAST_HASH,
+ sizeof data->multi_filter,
+ data->multi_filter);
+ }
+
+ mcs7830_set_reg_async(dev, HIF_REG_CONFIG, 1, &data->config);
+}
+
+static int mcs7830_get_regs_len(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ switch (mcs7830_get_rev(dev)) {
+ case 1:
+ return 21;
+ case 2:
+ return 32;
+ }
+ return 0;
+}
+
+static void mcs7830_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *drvinfo)
+{
+ usbnet_get_drvinfo(net, drvinfo);
+ drvinfo->regdump_len = mcs7830_get_regs_len(net);
+}
+
+static void mcs7830_get_regs(struct net_device *net, struct ethtool_regs *regs, void *data)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ regs->version = mcs7830_get_rev(dev);
+ mcs7830_get_reg(dev, 0, regs->len, data);
+}
+
+static struct ethtool_ops mcs7830_ethtool_ops = {
+ .get_drvinfo = mcs7830_get_drvinfo,
+ .get_regs_len = mcs7830_get_regs_len,
+ .get_regs = mcs7830_get_regs,
+
+ /* common usbnet calls */
+ .get_link = usbnet_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
+{
+ struct net_device *net = dev->net;
+ int ret;
+
+ ret = mcs7830_init_dev(dev);
+ if (ret)
+ goto out;
+
+ net->do_ioctl = mcs7830_ioctl;
+ net->ethtool_ops = &mcs7830_ethtool_ops;
+ net->set_multicast_list = mcs7830_set_multicast;
+ mcs7830_set_multicast(net);
+
+ /* reserve space for the status byte on rx */
+ dev->rx_urb_size = ETH_FRAME_LEN + 1;
+
+ dev->mii.mdio_read = mcs7830_mdio_read;
+ dev->mii.mdio_write = mcs7830_mdio_write;
+ dev->mii.dev = net;
+ dev->mii.phy_id_mask = 0x3f;
+ dev->mii.reg_num_mask = 0x1f;
+ dev->mii.phy_id = *((u8 *) net->dev_addr + 1);
+
+ ret = usbnet_get_endpoints(dev, udev);
+out:
+ return ret;
+}
+
+/* The chip always appends a status bytes that we need to strip */
+static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ u8 status;
+
+ if (skb->len == 0) {
+ dev_err(&dev->udev->dev, "unexpected empty rx frame\n");
+ return 0;
+ }
+
+ skb_trim(skb, skb->len - 1);
+ status = skb->data[skb->len];
+
+ if (status != 0x20)
+ dev_dbg(&dev->udev->dev, "rx fixup status %x\n", status);
+
+ return skb->len > 0;
+}
+
+static const struct driver_info moschip_info = {
+ .description = "MOSCHIP 7830 usb-NET adapter",
+ .bind = mcs7830_bind,
+ .rx_fixup = mcs7830_rx_fixup,
+ .flags = FLAG_ETHER,
+ .in = 1,
+ .out = 2,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ USB_DEVICE(MCS7830_VENDOR_ID, MCS7830_PRODUCT_ID),
+ .driver_info = (unsigned long) &moschip_info,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver mcs7830_driver = {
+ .name = driver_name,
+ .id_table = products,
+ .probe = usbnet_probe,
+ .disconnect = usbnet_disconnect,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+};
+
+static int __init mcs7830_init(void)
+{
+ return usb_register(&mcs7830_driver);
+}
+module_init(mcs7830_init);
+
+static void __exit mcs7830_exit(void)
+{
+ usb_deregister(&mcs7830_driver);
+}
+module_exit(mcs7830_exit);
+
+MODULE_DESCRIPTION("USB to network adapter MCS7830)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/net/net1080.c b/drivers/usb/net/net1080.c
index a9b6eeac3e3f..ce00de8f13a1 100644
--- a/drivers/usb/net/net1080.c
+++ b/drivers/usb/net/net1080.c
@@ -368,7 +368,7 @@ static int net1080_check_connect(struct usbnet *dev)
return 0;
}
-static void nc_flush_complete(struct urb *urb, struct pt_regs *regs)
+static void nc_flush_complete(struct urb *urb)
{
kfree(urb->context);
usb_free_urb(urb);
@@ -498,25 +498,24 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
static struct sk_buff *
net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
{
- int padlen;
struct sk_buff *skb2;
struct nc_header *header = NULL;
struct nc_trailer *trailer = NULL;
+ int padlen = sizeof (struct nc_trailer);
int len = skb->len;
- padlen = ((len + sizeof (struct nc_header)
- + sizeof (struct nc_trailer)) & 0x01) ? 0 : 1;
+ if (!((len + padlen + sizeof (struct nc_header)) & 0x01))
+ padlen++;
if (!skb_cloned(skb)) {
int headroom = skb_headroom(skb);
int tailroom = skb_tailroom(skb);
- if ((padlen + sizeof (struct nc_trailer)) <= tailroom
- && sizeof (struct nc_header) <= headroom)
+ if (padlen <= tailroom &&
+ sizeof(struct nc_header) <= headroom)
/* There's enough head and tail room */
goto encapsulate;
- if ((sizeof (struct nc_header) + padlen
- + sizeof (struct nc_trailer)) <
+ if ((sizeof (struct nc_header) + padlen) <
(headroom + tailroom)) {
/* There's enough total room, so just readjust */
skb->data = memmove(skb->head
@@ -530,7 +529,7 @@ net1080_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
/* Create a new skb to use with the correct size */
skb2 = skb_copy_expand(skb,
sizeof (struct nc_header),
- sizeof (struct nc_trailer) + padlen,
+ padlen,
flags);
dev_kfree_skb_any(skb);
if (!skb2)
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index ab21f960d255..33abbd2176b6 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -45,7 +45,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v0.6.13 (2005/11/13)"
+#define DRIVER_VERSION "v0.6.14 (2006/09/27)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
@@ -96,7 +96,7 @@ MODULE_DEVICE_TABLE(usb, pegasus_ids);
static int update_eth_regs_async(pegasus_t *);
/* Aargh!!! I _really_ hate such tweaks */
-static void ctrl_callback(struct urb *urb, struct pt_regs *regs)
+static void ctrl_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
@@ -339,7 +339,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
}
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return ret;
}
@@ -376,7 +376,7 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return -ETIMEDOUT;
}
@@ -413,7 +413,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return -ETIMEDOUT;
}
@@ -461,7 +461,7 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
return ret;
fail:
if (netif_msg_drv(pegasus))
- dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__);
+ dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
return -ETIMEDOUT;
}
#endif /* PEGASUS_WRITE_EEPROM */
@@ -481,8 +481,12 @@ static void set_ethernet_addr(pegasus_t * pegasus)
{
__u8 node_id[6];
- get_node_id(pegasus, node_id);
- set_registers(pegasus, EthID, sizeof (node_id), node_id);
+ if (pegasus->features & PEGASUS_II) {
+ get_registers(pegasus, 0x10, sizeof(node_id), node_id);
+ } else {
+ get_node_id(pegasus, node_id);
+ set_registers(pegasus, EthID, sizeof (node_id), node_id);
+ }
memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id));
}
@@ -601,7 +605,7 @@ static inline struct sk_buff *pull_skb(pegasus_t * pegasus)
return NULL;
}
-static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void read_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
struct net_device *net;
@@ -619,7 +623,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
switch (urb->status) {
case 0:
break;
- case -ETIMEDOUT:
+ case -ETIME:
if (netif_msg_rx_err(pegasus))
pr_debug("%s: reset MAC\n", net->name);
pegasus->flags &= ~PEGASUS_RX_BUSY;
@@ -760,7 +764,7 @@ done:
spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);
}
-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void write_bulk_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
struct net_device *net = pegasus->net;
@@ -797,7 +801,7 @@ static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
netif_wake_queue(net);
}
-static void intr_callback(struct urb *urb, struct pt_regs *regs)
+static void intr_callback(struct urb *urb)
{
pegasus_t *pegasus = urb->context;
struct net_device *net;
@@ -1222,7 +1226,7 @@ static void pegasus_set_multicast(struct net_device *net)
}
pegasus->flags |= ETH_REGS_CHANGE;
- ctrl_callback(pegasus->ctrl_urb, NULL);
+ ctrl_callback(pegasus->ctrl_urb);
}
static __u8 mii_phy_probe(pegasus_t * pegasus)
@@ -1429,11 +1433,11 @@ static int pegasus_resume (struct usb_interface *intf)
if (netif_running(pegasus->net)) {
pegasus->rx_urb->status = 0;
pegasus->rx_urb->actual_length = 0;
- read_bulk_callback(pegasus->rx_urb, NULL);
+ read_bulk_callback(pegasus->rx_urb);
pegasus->intr_urb->status = 0;
pegasus->intr_urb->actual_length = 0;
- intr_callback(pegasus->intr_urb, NULL);
+ intr_callback(pegasus->intr_urb);
}
queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
CARRIER_CHECK_DELAY);
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index a72685b96061..72171f94ded4 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -208,7 +208,7 @@ static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
indx, 0, data, size, 500);
}
-static void ctrl_callback(struct urb *urb, struct pt_regs *regs)
+static void ctrl_callback(struct urb *urb)
{
rtl8150_t *dev;
@@ -415,7 +415,7 @@ static inline struct sk_buff *pull_skb(rtl8150_t *dev)
return NULL;
}
-static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void read_bulk_callback(struct urb *urb)
{
rtl8150_t *dev;
unsigned pkt_len, res;
@@ -438,7 +438,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
break;
case -ENOENT:
return; /* the urb is in unlink state */
- case -ETIMEDOUT:
+ case -ETIME:
warn("may be reset is needed?..");
goto goon;
default:
@@ -525,7 +525,7 @@ tlsched:
tasklet_schedule(&dev->tl);
}
-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void write_bulk_callback(struct urb *urb)
{
rtl8150_t *dev;
@@ -541,7 +541,7 @@ static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
netif_wake_queue(dev->netdev);
}
-static void intr_callback(struct urb *urb, struct pt_regs *regs)
+static void intr_callback(struct urb *urb)
{
rtl8150_t *dev;
__u8 *d;
@@ -617,11 +617,11 @@ static int rtl8150_resume(struct usb_interface *intf)
if (netif_running(dev->netdev)) {
dev->rx_urb->status = 0;
dev->rx_urb->actual_length = 0;
- read_bulk_callback(dev->rx_urb, NULL);
+ read_bulk_callback(dev->rx_urb);
dev->intr_urb->status = 0;
dev->intr_urb->actual_length = 0;
- intr_callback(dev->intr_urb, NULL);
+ intr_callback(dev->intr_urb);
}
return 0;
}
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index 54183e173a6d..cf3d20eb781c 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -61,8 +61,11 @@
* let the USB host controller be busy for 5msec or more before an irq
* is required, under load. Jumbograms change the equation.
*/
-#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
-#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? 60 : 4)
+#define RX_MAX_QUEUE_MEMORY (60 * 1518)
+#define RX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+ (RX_MAX_QUEUE_MEMORY/(dev)->rx_urb_size) : 4)
+#define TX_QLEN(dev) (((dev)->udev->speed == USB_SPEED_HIGH) ? \
+ (RX_MAX_QUEUE_MEMORY/(dev)->hard_mtu) : 4)
// reawaken network queue this soon after stopping; else watchdog barks
#define TX_TIMEOUT_JIFFIES (5*HZ)
@@ -155,7 +158,7 @@ int usbnet_get_endpoints(struct usbnet *dev, struct usb_interface *intf)
}
EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
-static void intr_complete (struct urb *urb, struct pt_regs *regs);
+static void intr_complete (struct urb *urb);
static int init_status (struct usbnet *dev, struct usb_interface *intf)
{
@@ -227,13 +230,23 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
{
struct usbnet *dev = netdev_priv(net);
int ll_mtu = new_mtu + net->hard_header_len;
+ int old_hard_mtu = dev->hard_mtu;
+ int old_rx_urb_size = dev->rx_urb_size;
- if (new_mtu <= 0 || ll_mtu > dev->hard_mtu)
+ if (new_mtu <= 0)
return -EINVAL;
// no second zero-length packet read wanted after mtu-sized packets
if ((ll_mtu % dev->maxpacket) == 0)
return -EDOM;
net->mtu = new_mtu;
+
+ dev->hard_mtu = net->mtu + net->hard_header_len;
+ if (dev->rx_urb_size == old_hard_mtu) {
+ dev->rx_urb_size = dev->hard_mtu;
+ if (dev->rx_urb_size > old_rx_urb_size)
+ usbnet_unlink_rx_urbs(dev);
+ }
+
return 0;
}
@@ -282,7 +295,7 @@ EXPORT_SYMBOL_GPL(usbnet_defer_kevent);
/*-------------------------------------------------------------------------*/
-static void rx_complete (struct urb *urb, struct pt_regs *regs);
+static void rx_complete (struct urb *urb);
static void rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
{
@@ -370,7 +383,7 @@ error:
/*-------------------------------------------------------------------------*/
-static void rx_complete (struct urb *urb, struct pt_regs *regs)
+static void rx_complete (struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
struct skb_data *entry = (struct skb_data *) skb->cb;
@@ -412,9 +425,9 @@ static void rx_complete (struct urb *urb, struct pt_regs *regs)
// we get controller i/o faults during khubd disconnect() delays.
// throttle down resubmits, to avoid log floods; just temporarily,
// so we still recover when the fault isn't a khubd delay.
- case -EPROTO: // ehci
- case -ETIMEDOUT: // ohci
- case -EILSEQ: // uhci
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
dev->stats.rx_errors++;
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay, jiffies + THROTTLE_JIFFIES);
@@ -454,7 +467,7 @@ block:
devdbg (dev, "no read resubmitted");
}
-static void intr_complete (struct urb *urb, struct pt_regs *regs)
+static void intr_complete (struct urb *urb)
{
struct usbnet *dev = urb->context;
int status = urb->status;
@@ -521,6 +534,17 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
return count;
}
+// Flush all pending rx urbs
+// minidrivers may need to do this when the MTU changes
+
+void usbnet_unlink_rx_urbs(struct usbnet *dev)
+{
+ if (netif_running(dev->net)) {
+ (void) unlink_urbs (dev, &dev->rxq);
+ tasklet_schedule(&dev->bh);
+ }
+}
+EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
/*-------------------------------------------------------------------------*/
@@ -629,7 +653,7 @@ static int usbnet_open (struct net_device *net)
devinfo (dev, "open: enable queueing "
"(rx %d, tx %d) mtu %d %s framing",
- RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu,
+ (int)RX_QLEN (dev), (int)TX_QLEN (dev), dev->net->mtu,
framing);
}
@@ -645,6 +669,37 @@ done:
* they'll probably want to use this base set.
*/
+int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ if (!dev->mii.mdio_read)
+ return -EOPNOTSUPP;
+
+ return mii_ethtool_gset(&dev->mii, cmd);
+}
+EXPORT_SYMBOL_GPL(usbnet_get_settings);
+
+int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+ int retval;
+
+ if (!dev->mii.mdio_write)
+ return -EOPNOTSUPP;
+
+ retval = mii_ethtool_sset(&dev->mii, cmd);
+
+ /* link speed/duplex might have changed */
+ if (dev->driver_info->link_reset)
+ dev->driver_info->link_reset(dev);
+
+ return retval;
+
+}
+EXPORT_SYMBOL_GPL(usbnet_set_settings);
+
+
void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
{
struct usbnet *dev = netdev_priv(net);
@@ -658,7 +713,7 @@ void usbnet_get_drvinfo (struct net_device *net, struct ethtool_drvinfo *info)
}
EXPORT_SYMBOL_GPL(usbnet_get_drvinfo);
-static u32 usbnet_get_link (struct net_device *net)
+u32 usbnet_get_link (struct net_device *net)
{
struct usbnet *dev = netdev_priv(net);
@@ -666,9 +721,14 @@ static u32 usbnet_get_link (struct net_device *net)
if (dev->driver_info->check_connect)
return dev->driver_info->check_connect (dev) == 0;
+ /* if the device has mii operations, use those */
+ if (dev->mii.mdio_read)
+ return mii_link_ok(&dev->mii);
+
/* Otherwise, say we're up (to avoid breaking scripts) */
return 1;
}
+EXPORT_SYMBOL_GPL(usbnet_get_link);
u32 usbnet_get_msglevel (struct net_device *net)
{
@@ -686,10 +746,24 @@ void usbnet_set_msglevel (struct net_device *net, u32 level)
}
EXPORT_SYMBOL_GPL(usbnet_set_msglevel);
+int usbnet_nway_reset(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ if (!dev->mii.mdio_write)
+ return -EOPNOTSUPP;
+
+ return mii_nway_restart(&dev->mii);
+}
+EXPORT_SYMBOL_GPL(usbnet_nway_reset);
+
/* drivers may override default ethtool_ops in their bind() routine */
static struct ethtool_ops usbnet_ethtool_ops = {
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
.get_drvinfo = usbnet_get_drvinfo,
.get_link = usbnet_get_link,
+ .nway_reset = usbnet_nway_reset,
.get_msglevel = usbnet_get_msglevel,
.set_msglevel = usbnet_set_msglevel,
};
@@ -773,7 +847,7 @@ kevent (void *data)
/*-------------------------------------------------------------------------*/
-static void tx_complete (struct urb *urb, struct pt_regs *regs)
+static void tx_complete (struct urb *urb)
{
struct sk_buff *skb = (struct sk_buff *) urb->context;
struct skb_data *entry = (struct skb_data *) skb->cb;
@@ -797,9 +871,9 @@ static void tx_complete (struct urb *urb, struct pt_regs *regs)
// like rx, tx gets controller i/o faults during khubd delays
// and so it uses the same throttling mechanism.
- case -EPROTO: // ehci
- case -ETIMEDOUT: // ohci
- case -EILSEQ: // uhci
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
if (!timer_pending (&dev->delay)) {
mod_timer (&dev->delay,
jiffies + THROTTLE_JIFFIES);
@@ -1070,6 +1144,7 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
dev->delay.function = usbnet_bh;
dev->delay.data = (unsigned long) dev;
init_timer (&dev->delay);
+ mutex_init (&dev->phy_mutex);
SET_MODULE_OWNER (net);
dev->net = net;
@@ -1201,7 +1276,7 @@ EXPORT_SYMBOL_GPL(usbnet_resume);
static int __init usbnet_init(void)
{
/* compiler should optimize this out */
- BUG_ON (sizeof (((struct sk_buff *)0)->cb)
+ BUILD_BUG_ON (sizeof (((struct sk_buff *)0)->cb)
< sizeof (struct skb_data));
random_ether_addr(node_id);
diff --git a/drivers/usb/net/usbnet.h b/drivers/usb/net/usbnet.h
index 89fc4958eecf..07c70abbe0ec 100644
--- a/drivers/usb/net/usbnet.h
+++ b/drivers/usb/net/usbnet.h
@@ -30,6 +30,7 @@ struct usbnet {
struct usb_device *udev;
struct driver_info *driver_info;
wait_queue_head_t *wait;
+ struct mutex phy_mutex;
/* i/o info: pipes etc */
unsigned in, out;
@@ -166,10 +167,15 @@ struct skb_data { /* skb->cb is one of these */
extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
extern void usbnet_defer_kevent (struct usbnet *, int);
extern void usbnet_skb_return (struct usbnet *, struct sk_buff *);
+extern void usbnet_unlink_rx_urbs(struct usbnet *);
+extern int usbnet_get_settings (struct net_device *net, struct ethtool_cmd *cmd);
+extern int usbnet_set_settings (struct net_device *net, struct ethtool_cmd *cmd);
+extern u32 usbnet_get_link (struct net_device *net);
extern u32 usbnet_get_msglevel (struct net_device *);
extern void usbnet_set_msglevel (struct net_device *, u32);
extern void usbnet_get_drvinfo (struct net_device *, struct ethtool_drvinfo *);
+extern int usbnet_nway_reset(struct net_device *net);
/* messaging support includes the interface name, so it must not be
* used before it has one ... notably, in minidriver bind() calls.
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index f5b9438c94f0..9a6ec1b5e3d5 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -53,6 +53,15 @@ config USB_SERIAL_GENERIC
support" be compiled as a module for this driver to be used
properly.
+config USB_SERIAL_AIRCABLE
+ tristate "AIRcable USB Bluetooth Dongle Driver (EXPERIMENTAL)"
+ depends on USB_SERIAL && EXPERIMENTAL
+ help
+ Say Y here if you want to use AIRcable USB Bluetoot Dongle.
+
+ To compile this driver as a module, choose M here: the module
+ will be called aircable.
+
config USB_SERIAL_AIRPRIME
tristate "USB AirPrime CDMA Wireless Driver"
depends on USB_SERIAL
@@ -413,6 +422,31 @@ config USB_SERIAL_MCT_U232
To compile this driver as a module, choose M here: the
module will be called mct_u232.
+config USB_SERIAL_MOS7720
+ tristate "USB Moschip 7720 Single Port Serial Driver"
+ depends on USB_SERIAL
+ ---help---
+ Say Y here if you want to use a USB Serial single port adapter from
+ Moschip Semiconductor Tech.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mos7720.
+
+config USB_SERIAL_MOS7840
+ tristate "USB Moschip 7840/7820 USB Serial Driver"
+ depends on USB_SERIAL
+ ---help---
+ Say Y here if you want to use a MCS7840 Quad-Serial or MCS7820
+ Dual-Serial port device from MosChip Semiconductor.
+
+ The MCS7840 and MCS7820 have been developed to connect a wide range
+ of standard serial devices to a USB host. The MCS7840 has a USB
+ device controller connected to four (4) individual UARTs while the
+ MCS7820 controller connects to two (2) individual UARTs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mos7840. If unsure, choose N.
+
config USB_SERIAL_NAVMAN
tristate "USB Navman GPS device"
depends on USB_SERIAL
@@ -503,8 +537,7 @@ config USB_SERIAL_OPTION
The USB bus on these cards is not accessible externally.
Supported devices include (some of?) those made by:
- Option, Huawei, Audiovox, Sierra Wireless, Novatel Wireless, or
- Anydata.
+ Option, Huawei, Audiovox, Novatel Wireless, or Anydata.
To compile this driver as a module, choose M here: the
module will be called option.
@@ -526,5 +559,6 @@ config USB_EZUSB
depends on USB_SERIAL_KEYSPAN_PDA || USB_SERIAL_XIRCOM || USB_SERIAL_KEYSPAN || USB_SERIAL_WHITEHEAT
default y
+
endmenu
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 8efed2ce1ba3..a5047dc599bb 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -11,6 +11,7 @@ usbserial-obj-$(CONFIG_USB_EZUSB) += ezusb.o
usbserial-objs := usb-serial.o generic.o bus.o $(usbserial-obj-y)
+obj-$(CONFIG_USB_SERIAL_AIRCABLE) += aircable.o
obj-$(CONFIG_USB_SERIAL_AIRPRIME) += airprime.o
obj-$(CONFIG_USB_SERIAL_ARK3116) += ark3116.o
obj-$(CONFIG_USB_SERIAL_BELKIN) += belkin_sa.o
@@ -33,6 +34,8 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
+obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
+obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_NAVMAN) += navman.o
obj-$(CONFIG_USB_SERIAL_OMNINET) += omninet.o
obj-$(CONFIG_USB_SERIAL_OPTION) += option.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
new file mode 100644
index 000000000000..812275509137
--- /dev/null
+++ b/drivers/usb/serial/aircable.c
@@ -0,0 +1,625 @@
+/*
+ * AIRcable USB Bluetooth Dongle Driver.
+ *
+ * Copyright (C) 2006 Manuel Francisco Naranjo (naranjo.manuel@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.
+ *
+ * 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
+ * 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.
+ *
+ * The device simply need some stuff to understand data comming from the usb
+ * 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 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,
+ * if there is data coming that does not contain any header, then that is data
+ * that must go directly to the tty, as there is no documentation about if there
+ * is any other control code, I will simply check for the first
+ * one.
+ *
+ * The driver registers himself with the USB-serial core and the USB Core. I had
+ * to implement a probe function agains USB-serial, because other way, the
+ * driver was attaching himself to both interfaces. I have tryed with different
+ * configurations of usb_serial_driver with out exit, only the probe function
+ * could handle this correctly.
+ *
+ * I have taken some info from a Greg Kroah-Hartman article:
+ * http://www.linuxjournal.com/article/6573
+ * And from Linux Device Driver Kit CD, which is a great work, the authors taken
+ * the work to recompile lots of information an knowladge in drivers development
+ * and made it all avaible inside a cd.
+ * URL: http://kernel.org/pub/linux/kernel/people/gregkh/ddk/
+ *
+ */
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/circ_buf.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static int debug;
+
+/* Vendor and Product ID */
+#define AIRCABLE_VID 0x16CA
+#define AIRCABLE_USB_PID 0x1502
+
+/* write buffer size defines */
+#define AIRCABLE_BUF_SIZE 2048
+
+/* Protocol Stuff */
+#define HCI_HEADER_LENGTH 0x4
+#define TX_HEADER_0 0x20
+#define TX_HEADER_1 0x29
+#define RX_HEADER_0 0x00
+#define RX_HEADER_1 0x20
+#define MAX_HCI_FRAMESIZE 60
+#define HCI_COMPLETE_FRAME 64
+
+/* rx_flags */
+#define THROTTLED 0x01
+#define ACTUALLY_THROTTLED 0x02
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v1.0b2"
+#define DRIVER_AUTHOR "Naranjo, Manuel Francisco <naranjo.manuel@gmail.com>"
+#define DRIVER_DESC "AIRcable USB Driver"
+
+/* ID table that will be registered with USB core */
+static struct usb_device_id id_table [] = {
+ { USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) },
+ { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+
+/* Internal Structure */
+struct aircable_private {
+ spinlock_t rx_lock; /* spinlock for the receive lines */
+ struct circ_buf *tx_buf; /* write buffer */
+ struct circ_buf *rx_buf; /* read buffer */
+ int rx_flags; /* for throttilng */
+ struct work_struct rx_work; /* work cue for the receiving line */
+};
+
+/* Private methods */
+
+/* Circular Buffer Methods, code from ti_usb_3410_5052 used */
+/*
+ * serial_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+static void serial_buf_clear(struct circ_buf *cb)
+{
+ cb->head = cb->tail = 0;
+}
+
+/*
+ * serial_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+static struct circ_buf *serial_buf_alloc(void)
+{
+ struct circ_buf *cb;
+ cb = kmalloc(sizeof(struct circ_buf), GFP_KERNEL);
+ if (cb == NULL)
+ return NULL;
+ cb->buf = kmalloc(AIRCABLE_BUF_SIZE, GFP_KERNEL);
+ if (cb->buf == NULL) {
+ kfree(cb);
+ return NULL;
+ }
+ serial_buf_clear(cb);
+ return cb;
+}
+
+/*
+ * serial_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+static void serial_buf_free(struct circ_buf *cb)
+{
+ kfree(cb->buf);
+ kfree(cb);
+}
+
+/*
+ * serial_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+static int serial_buf_data_avail(struct circ_buf *cb)
+{
+ return CIRC_CNT(cb->head,cb->tail,AIRCABLE_BUF_SIZE);
+}
+
+/*
+ * serial_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+static int serial_buf_put(struct circ_buf *cb, const char *buf, int count)
+{
+ int c, ret = 0;
+ while (1) {
+ c = CIRC_SPACE_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(cb->buf + cb->head, buf, c);
+ cb->head = (cb->head + c) & (AIRCABLE_BUF_SIZE-1);
+ buf += c;
+ count -= c;
+ ret= c;
+ }
+ return ret;
+}
+
+/*
+ * serial_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
+{
+ int c, ret = 0;
+ while (1) {
+ c = CIRC_CNT_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
+ if (count < c)
+ c = count;
+ if (c <= 0)
+ break;
+ memcpy(buf, cb->buf + cb->tail, c);
+ cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
+ buf += c;
+ count -= c;
+ ret= c;
+ }
+ return ret;
+}
+
+/* End of circula buffer methods */
+
+static void aircable_send(struct usb_serial_port *port)
+{
+ int count, result;
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ unsigned char* buf;
+ dbg("%s - port %d", __FUNCTION__, port->number);
+ if (port->write_urb_busy)
+ return;
+
+ count = min(serial_buf_data_avail(priv->tx_buf), MAX_HCI_FRAMESIZE);
+ if (count == 0)
+ return;
+
+ buf = kzalloc(count + HCI_HEADER_LENGTH, GFP_ATOMIC);
+ if (!buf) {
+ err("%s- kzalloc(%d) failed.", __FUNCTION__,
+ count + HCI_HEADER_LENGTH);
+ return;
+ }
+
+ buf[0] = TX_HEADER_0;
+ buf[1] = TX_HEADER_1;
+ buf[2] = (unsigned char)count;
+ buf[3] = (unsigned char)(count >> 8);
+ serial_buf_get(priv->tx_buf,buf + HCI_HEADER_LENGTH, MAX_HCI_FRAMESIZE);
+
+ memcpy(port->write_urb->transfer_buffer, buf,
+ count + HCI_HEADER_LENGTH);
+
+ kfree(buf);
+ port->write_urb_busy = 1;
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ count + HCI_HEADER_LENGTH,
+ port->write_urb->transfer_buffer);
+ port->write_urb->transfer_buffer_length = count + HCI_HEADER_LENGTH;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
+
+ if (result) {
+ dev_err(&port->dev,
+ "%s - failed submitting write urb, error %d\n",
+ __FUNCTION__, result);
+ port->write_urb_busy = 0;
+ }
+
+ schedule_work(&port->work);
+}
+
+static void aircable_read(void *params)
+{
+ struct usb_serial_port *port = params;
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned char *data;
+ int count;
+ if (priv->rx_flags & THROTTLED){
+ if (priv->rx_flags & ACTUALLY_THROTTLED)
+ schedule_work(&priv->rx_work);
+ return;
+ }
+
+ /* By now I will flush data to the tty in packages of no more than
+ * 64 bytes, to ensure I do not get throttled.
+ * Ask USB mailing list for better aproach.
+ */
+ tty = port->tty;
+
+ if (!tty)
+ schedule_work(&priv->rx_work);
+
+ count = min(64, serial_buf_data_avail(priv->rx_buf));
+
+ if (count <= 0)
+ return; //We have finished sending everything.
+
+ tty_prepare_flip_string(tty, &data, count);
+ if (!data){
+ err("%s- kzalloc(%d) failed.", __FUNCTION__, count);
+ return;
+ }
+
+ serial_buf_get(priv->rx_buf, data, count);
+
+ tty_flip_buffer_push(tty);
+
+ if (serial_buf_data_avail(priv->rx_buf))
+ schedule_work(&priv->rx_work);
+
+ return;
+}
+/* End of private methods */
+
+static int aircable_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+ struct usb_host_interface *iface_desc = serial->interface->cur_altsetting;
+ struct usb_endpoint_descriptor *endpoint;
+ int num_bulk_out=0;
+ int i;
+
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+ endpoint = &iface_desc->endpoint[i].desc;
+ if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
+ ((endpoint->bmAttributes & 3) == 0x02)) {
+ /* we found our bulk out endpoint */
+ dbg("found bulk out on endpoint %d", i);
+ ++num_bulk_out;
+ }
+ }
+
+ if (num_bulk_out == 0) {
+ dbg("Invalid interface, discarding");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int aircable_attach (struct usb_serial *serial)
+{
+ struct usb_serial_port *port = serial->port[0];
+ struct aircable_private *priv;
+
+ priv = kzalloc(sizeof(struct aircable_private), GFP_KERNEL);
+ if (!priv){
+ err("%s- kmalloc(%Zd) failed.", __FUNCTION__,
+ sizeof(struct aircable_private));
+ return -ENOMEM;
+ }
+
+ /* Allocation of Circular Buffers */
+ priv->tx_buf = serial_buf_alloc();
+ if (priv->tx_buf == NULL) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->rx_buf = serial_buf_alloc();
+ if (priv->rx_buf == NULL) {
+ kfree(priv->tx_buf);
+ kfree(priv);
+ return -ENOMEM;
+ }
+
+ priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
+ INIT_WORK(&priv->rx_work, aircable_read, port);
+
+ usb_set_serial_port_data(serial->port[0], priv);
+
+ return 0;
+}
+
+static void aircable_shutdown(struct usb_serial *serial)
+{
+
+ struct usb_serial_port *port = serial->port[0];
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+
+ dbg("%s", __FUNCTION__);
+
+ if (priv) {
+ serial_buf_free(priv->tx_buf);
+ serial_buf_free(priv->rx_buf);
+ usb_set_serial_port_data(port, NULL);
+ kfree(priv);
+ }
+}
+
+static int aircable_write_room(struct usb_serial_port *port)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ return serial_buf_data_avail(priv->tx_buf);
+}
+
+static int aircable_write(struct usb_serial_port *port,
+ const unsigned char *source, int count)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ int temp;
+
+ dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, source);
+
+ if (!count){
+ dbg("%s - write request of 0 bytes", __FUNCTION__);
+ return count;
+ }
+
+ temp = serial_buf_put(priv->tx_buf, source, count);
+
+ aircable_send(port);
+
+ if (count > AIRCABLE_BUF_SIZE)
+ count = AIRCABLE_BUF_SIZE;
+
+ return count;
+
+}
+
+static void aircable_write_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ int result;
+
+ dbg("%s - urb->status: %d", __FUNCTION__ , urb->status);
+
+ /* This has been taken from cypress_m8.c cypress_write_int_callback */
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
+ port->write_urb_busy = 0;
+ return;
+ default:
+ /* error in the urb, so we have to resubmit it */
+ dbg("%s - Overflow in write", __FUNCTION__);
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ port->write_urb->transfer_buffer_length = 1;
+ port->write_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->write_urb, GFP_KERNEL);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting write urb, error %d\n",
+ __FUNCTION__, result);
+ else
+ return;
+ }
+
+ port->write_urb_busy = 0;
+
+ aircable_send(port);
+}
+
+static void aircable_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned long no_packages, remaining, package_length, i;
+ int result, shift = 0;
+ unsigned char *temp;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (urb->status) {
+ dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+ if (!port->open_count) {
+ dbg("%s - port is closed, exiting.", __FUNCTION__);
+ return;
+ }
+ if (urb->status == -EPROTO) {
+ dbg("%s - caught -EPROTO, resubmitting the urb",
+ __FUNCTION__);
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
+
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
+ return;
+ }
+ dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
+ return;
+ }
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ urb->actual_length,urb->transfer_buffer);
+
+ tty = port->tty;
+ if (tty && urb->actual_length) {
+ if (urb->actual_length <= 2) {
+ /* This is an incomplete package */
+ serial_buf_put(priv->rx_buf, urb->transfer_buffer,
+ urb->actual_length);
+ } else {
+ temp = urb->transfer_buffer;
+ if (temp[0] == RX_HEADER_0)
+ shift = HCI_HEADER_LENGTH;
+
+ remaining = urb->actual_length;
+ no_packages = urb->actual_length / (HCI_COMPLETE_FRAME);
+
+ if (urb->actual_length % HCI_COMPLETE_FRAME != 0)
+ no_packages+=1;
+
+ for (i = 0; i < no_packages ;i++) {
+ if (remaining > (HCI_COMPLETE_FRAME))
+ package_length = HCI_COMPLETE_FRAME;
+ else
+ package_length = remaining;
+ remaining -= package_length;
+
+ serial_buf_put(priv->rx_buf,
+ urb->transfer_buffer + shift +
+ (HCI_COMPLETE_FRAME) * (i),
+ package_length - shift);
+ }
+ }
+ aircable_read(port);
+ }
+
+ /* Schedule the next read _if_ we are still open */
+ if (port->open_count) {
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_rcvbulkpipe(port->serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ aircable_read_bulk_callback, port);
+
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
+ }
+
+ return;
+}
+
+/* Based on ftdi_sio.c throttle */
+static void aircable_throttle(struct usb_serial_port *port)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ priv->rx_flags |= THROTTLED;
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+}
+
+/* Based on ftdi_sio.c unthrottle */
+static void aircable_unthrottle(struct usb_serial_port *port)
+{
+ struct aircable_private *priv = usb_get_serial_port_data(port);
+ int actually_throttled;
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->rx_lock, flags);
+ actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED;
+ priv->rx_flags &= ~(THROTTLED | ACTUALLY_THROTTLED);
+ spin_unlock_irqrestore(&priv->rx_lock, flags);
+
+ if (actually_throttled)
+ schedule_work(&priv->rx_work);
+}
+
+static struct usb_serial_driver aircable_device = {
+ .description = "aircable",
+ .id_table = id_table,
+ .num_ports = 1,
+ .attach = aircable_attach,
+ .probe = aircable_probe,
+ .shutdown = aircable_shutdown,
+ .write = aircable_write,
+ .write_room = aircable_write_room,
+ .write_bulk_callback = aircable_write_bulk_callback,
+ .read_bulk_callback = aircable_read_bulk_callback,
+ .throttle = aircable_throttle,
+ .unthrottle = aircable_unthrottle,
+};
+
+static struct usb_driver aircable_driver = {
+ .name = "aircable",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+};
+
+static int __init aircable_init (void)
+{
+ int retval;
+ retval = usb_serial_register(&aircable_device);
+ if (retval)
+ goto failed_serial_register;
+ retval = usb_register(&aircable_driver);
+ if (retval)
+ goto failed_usb_register;
+ return 0;
+
+failed_serial_register:
+ usb_serial_deregister(&aircable_device);
+failed_usb_register:
+ return retval;
+}
+
+static void __exit aircable_exit (void)
+{
+ usb_deregister(&aircable_driver);
+ usb_serial_deregister(&aircable_device);
+}
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+module_init(aircable_init);
+module_exit(aircable_exit);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 62082532a8b3..7f5d546da39a 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -1,7 +1,7 @@
/*
* AirPrime CDMA Wireless Serial USB driver
*
- * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
@@ -11,26 +11,261 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x0c88, 0x17da) }, /* Kyocera Wireless KPC650/Passport */
- { USB_DEVICE(0xf3d, 0x0112) }, /* AirPrime CDMA Wireless PC Card */
{ USB_DEVICE(0x1410, 0x1110) }, /* Novatel Wireless Merlin CDMA */
- { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless Aircard 580 */
- { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1410, 0x1100) }, /* ExpressCard34 Qualcomm 3G CDMA */
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
+#define URB_TRANSFER_BUFFER_SIZE 4096
+#define NUM_READ_URBS 4
+#define NUM_WRITE_URBS 4
+#define NUM_BULK_EPS 3
+#define MAX_BULK_EPS 6
+
+/* if overridden by the user, then use their value for the size of the
+ * read and write urbs, and the number of endpoints */
+static int buffer_size = URB_TRANSFER_BUFFER_SIZE;
+static int endpoints = NUM_BULK_EPS;
+static int debug;
+struct airprime_private {
+ spinlock_t lock;
+ int outstanding_urbs;
+ int throttled;
+ struct urb *read_urbp[NUM_READ_URBS];
+};
+
+static void airprime_read_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ struct tty_struct *tty;
+ int result;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (urb->status) {
+ dbg("%s - nonzero read bulk status received: %d",
+ __FUNCTION__, urb->status);
+ /* something happened, so free up the memory for this urb */
+ if (urb->transfer_buffer) {
+ kfree (urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+ }
+ return;
+ }
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+
+ tty = port->tty;
+ if (tty && urb->actual_length) {
+ tty_insert_flip_string (tty, data, urb->actual_length);
+ tty_flip_buffer_push (tty);
+ }
+
+ result = usb_submit_urb (urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&port->dev, "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
+ return;
+}
+
+static void airprime_write_bulk_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* free up the transfer buffer, as usb_free_urb() does not do this */
+ kfree (urb->transfer_buffer);
+
+ if (urb->status)
+ dbg("%s - nonzero write bulk status received: %d",
+ __FUNCTION__, urb->status);
+ spin_lock_irqsave(&priv->lock, flags);
+ --priv->outstanding_urbs;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ usb_serial_port_softint(port);
+}
+
+static int airprime_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ struct urb *urb;
+ char *buffer = NULL;
+ int i;
+ int result = 0;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* initialize our private data structure if it isn't already created */
+ if (!priv) {
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ result = -ENOMEM;
+ goto out;
+ }
+ spin_lock_init(&priv->lock);
+ usb_set_serial_port_data(port, priv);
+ }
+
+ for (i = 0; i < NUM_READ_URBS; ++i) {
+ buffer = kmalloc(buffer_size, GFP_KERNEL);
+ if (!buffer) {
+ dev_err(&port->dev, "%s - out of memory.\n",
+ __FUNCTION__);
+ result = -ENOMEM;
+ goto errout;
+ }
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ kfree(buffer);
+ dev_err(&port->dev, "%s - no more urbs?\n",
+ __FUNCTION__);
+ result = -ENOMEM;
+ goto errout;
+ }
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ buffer, buffer_size,
+ airprime_read_bulk_callback, port);
+ result = usb_submit_urb(urb, GFP_KERNEL);
+ if (result) {
+ dev_err(&port->dev,
+ "%s - failed submitting read urb %d for port %d, error %d\n",
+ __FUNCTION__, i, port->number, result);
+ goto errout;
+ }
+ /* remember this urb so we can kill it when the port is closed */
+ priv->read_urbp[i] = urb;
+ }
+ goto out;
+
+ errout:
+ /* some error happened, cancel any submitted urbs and clean up anything that
+ got allocated successfully */
+
+ for ( ; i >= 0; --i) {
+ urb = priv->read_urbp[i];
+ if (urb) {
+ /* This urb was submitted successfully. So we have to
+ cancel it.
+ Unlinking the urb will invoke read_bulk_callback()
+ with an error status, so its transfer buffer will
+ be freed there */
+ if (usb_unlink_urb (urb) != -EINPROGRESS) {
+ /* comments in drivers/usb/core/urb.c say this
+ can only happen if the urb was never submitted,
+ or has completed already.
+ Either way we may have to free the transfer
+ buffer here. */
+ if (urb->transfer_buffer) {
+ kfree (urb->transfer_buffer);
+ urb->transfer_buffer = NULL;
+ }
+ }
+ usb_free_urb (urb);
+ }
+ }
+
+ out:
+ return result;
+}
+
+static void airprime_close(struct usb_serial_port *port, struct file * filp)
+{
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ int i;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* killing the urb will invoke read_bulk_callback() with an error status,
+ so the transfer buffer will be freed there */
+ for (i = 0; i < NUM_READ_URBS; ++i) {
+ usb_kill_urb (priv->read_urbp[i]);
+ usb_free_urb (priv->read_urbp[i]);
+ }
+
+ /* free up private structure */
+ kfree (priv);
+ usb_set_serial_port_data(port, NULL);
+}
+
+static int airprime_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct airprime_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ struct urb *urb;
+ unsigned char *buffer;
+ unsigned long flags;
+ int status;
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->outstanding_urbs > NUM_WRITE_URBS) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ dbg("%s - write limit hit\n", __FUNCTION__);
+ return 0;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ buffer = kmalloc(count, GFP_ATOMIC);
+ if (!buffer) {
+ dev_err(&port->dev, "out of memory\n");
+ return -ENOMEM;
+ }
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!urb) {
+ dev_err(&port->dev, "no more free urbs\n");
+ kfree (buffer);
+ return -ENOMEM;
+ }
+ memcpy (buffer, buf, count);
+
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, buffer);
+
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ buffer, count,
+ airprime_write_bulk_callback, port);
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&port->dev,
+ "%s - usb_submit_urb(write bulk) failed with status = %d\n",
+ __FUNCTION__, status);
+ count = status;
+ kfree (buffer);
+ } else {
+ spin_lock_irqsave(&priv->lock, flags);
+ ++priv->outstanding_urbs;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ }
+ /* we are done with this urb, so let the host driver
+ * really free it when it is finished with it */
+ usb_free_urb (urb);
+ return count;
+}
+
static struct usb_driver airprime_driver = {
.name = "airprime",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
+ .no_dynamic_id = 1,
};
static struct usb_serial_driver airprime_device = {
@@ -42,13 +277,17 @@ static struct usb_serial_driver airprime_device = {
.num_interrupt_in = NUM_DONT_CARE,
.num_bulk_in = NUM_DONT_CARE,
.num_bulk_out = NUM_DONT_CARE,
- .num_ports = 1,
+ .open = airprime_open,
+ .close = airprime_close,
+ .write = airprime_write,
};
static int __init airprime_init(void)
{
int retval;
+ airprime_device.num_ports =
+ (endpoints > 0 && endpoints <= MAX_BULK_EPS) ? endpoints : NUM_BULK_EPS;
retval = usb_serial_register(&airprime_device);
if (retval)
return retval;
@@ -60,6 +299,8 @@ static int __init airprime_init(void)
static void __exit airprime_exit(void)
{
+ dbg("%s", __FUNCTION__);
+
usb_deregister(&airprime_driver);
usb_serial_deregister(&airprime_device);
}
@@ -67,3 +308,10 @@ static void __exit airprime_exit(void)
module_init(airprime_init);
module_exit(airprime_exit);
MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled");
+module_param(buffer_size, int, 0);
+MODULE_PARM_DESC(buffer_size, "Size of the transfer buffers in bytes (default 4096)");
+module_param(endpoints, int, 0);
+MODULE_PARM_DESC(endpoints, "Number of bulk EPs to configure (default 3)");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 970d9ef0a7a5..ca52f12f0e24 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -1,4 +1,7 @@
/*
+ * Copyright (C) 2006
+ * Simon Schulz (ark3116_driver <at> auctionant.de)
+ *
* ark3116
* - implements a driver for the arkmicro ark3116 chipset (vendor=0x6547,
* productid=0x0232) (used in a datacable called KQ-U8A)
@@ -8,8 +11,6 @@
*
* - based on logs created by usbsnoopy
*
- * Author : Simon Schulz [ark3116_driver<AT>auctionant.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
@@ -22,6 +23,8 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <linux/serial.h>
+#include <asm/uaccess.h>
static int debug;
@@ -43,10 +46,10 @@ static inline void ARK3116_SND(struct usb_serial *serial, int seq,
{
int result;
result = usb_control_msg(serial->dev,
- usb_sndctrlpipe(serial->dev,0),
+ usb_sndctrlpipe(serial->dev, 0),
request, requesttype, value, index,
- NULL,0x00, 1000);
- dbg("%03d > ok",seq);
+ NULL, 0x00, 1000);
+ dbg("%03d > ok", seq);
}
static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
@@ -56,27 +59,25 @@ static inline void ARK3116_RCV(struct usb_serial *serial, int seq,
{
int result;
result = usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev,0),
- request, requesttype, value, index,
- buf, 0x0000001, 1000);
+ usb_rcvctrlpipe(serial->dev, 0),
+ request, requesttype, value, index,
+ buf, 0x0000001, 1000);
if (result)
- dbg("%03d < %d bytes [0x%02X]",seq, result, buf[0]);
+ dbg("%03d < %d bytes [0x%02X]", seq, result, buf[0]);
else
dbg("%03d < 0 bytes", seq);
}
-
static inline void ARK3116_RCV_QUIET(struct usb_serial *serial,
__u8 request, __u8 requesttype,
__u16 value, __u16 index, char *buf)
{
usb_control_msg(serial->dev,
- usb_rcvctrlpipe(serial->dev,0),
+ usb_rcvctrlpipe(serial->dev, 0),
request, requesttype, value, index,
buf, 0x0000001, 1000);
}
-
static int ark3116_attach(struct usb_serial *serial)
{
char *buf;
@@ -84,10 +85,10 @@ static int ark3116_attach(struct usb_serial *serial)
int i;
for (i = 0; i < serial->num_ports; ++i) {
- priv = kmalloc (sizeof (struct ark3116_private), GFP_KERNEL);
+ priv = kmalloc(sizeof (struct ark3116_private), GFP_KERNEL);
if (!priv)
goto cleanup;
- memset (priv, 0x00, sizeof (struct ark3116_private));
+ memset(priv, 0x00, sizeof (struct ark3116_private));
spin_lock_init(&priv->lock);
usb_set_serial_port_data(serial->port[i], priv);
@@ -95,63 +96,62 @@ static int ark3116_attach(struct usb_serial *serial)
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
- dbg("error kmalloc -> out of mem ?");
+ dbg("error kmalloc -> out of mem?");
goto cleanup;
}
/* 3 */
- ARK3116_SND(serial, 3,0xFE,0x40,0x0008,0x0002);
- ARK3116_SND(serial, 4,0xFE,0x40,0x0008,0x0001);
- ARK3116_SND(serial, 5,0xFE,0x40,0x0000,0x0008);
- ARK3116_SND(serial, 6,0xFE,0x40,0x0000,0x000B);
+ ARK3116_SND(serial, 3, 0xFE, 0x40, 0x0008, 0x0002);
+ ARK3116_SND(serial, 4, 0xFE, 0x40, 0x0008, 0x0001);
+ ARK3116_SND(serial, 5, 0xFE, 0x40, 0x0000, 0x0008);
+ ARK3116_SND(serial, 6, 0xFE, 0x40, 0x0000, 0x000B);
/* <-- seq7 */
- ARK3116_RCV(serial, 7,0xFE,0xC0,0x0000,0x0003, 0x00, buf);
- ARK3116_SND(serial, 8,0xFE,0x40,0x0080,0x0003);
- ARK3116_SND(serial, 9,0xFE,0x40,0x001A,0x0000);
- ARK3116_SND(serial,10,0xFE,0x40,0x0000,0x0001);
- ARK3116_SND(serial,11,0xFE,0x40,0x0000,0x0003);
+ ARK3116_RCV(serial, 7, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
+ ARK3116_SND(serial, 8, 0xFE, 0x40, 0x0080, 0x0003);
+ ARK3116_SND(serial, 9, 0xFE, 0x40, 0x001A, 0x0000);
+ ARK3116_SND(serial, 10, 0xFE, 0x40, 0x0000, 0x0001);
+ ARK3116_SND(serial, 11, 0xFE, 0x40, 0x0000, 0x0003);
/* <-- seq12 */
- ARK3116_RCV(serial,12,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
- ARK3116_SND(serial,13,0xFE,0x40,0x0000,0x0004);
+ ARK3116_RCV(serial, 12, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
+ ARK3116_SND(serial, 13, 0xFE, 0x40, 0x0000, 0x0004);
/* 14 */
- ARK3116_RCV(serial,14,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
- ARK3116_SND(serial,15,0xFE,0x40,0x0000,0x0004);
+ ARK3116_RCV(serial, 14, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
+ ARK3116_SND(serial, 15, 0xFE, 0x40, 0x0000, 0x0004);
/* 16 */
- ARK3116_RCV(serial,16,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+ ARK3116_RCV(serial, 16, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
/* --> seq17 */
- ARK3116_SND(serial,17,0xFE,0x40,0x0001,0x0004);
+ ARK3116_SND(serial, 17, 0xFE, 0x40, 0x0001, 0x0004);
/* <-- seq18 */
- ARK3116_RCV(serial,18,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
+ ARK3116_RCV(serial, 18, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
/* --> seq19 */
- ARK3116_SND(serial,19,0xFE,0x40,0x0003,0x0004);
-
+ ARK3116_SND(serial, 19, 0xFE, 0x40, 0x0003, 0x0004);
/* <-- seq20 */
- /* seems like serial port status info (RTS, CTS,...) */
- /* returns modem control line status ?! */
- ARK3116_RCV(serial,20,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
-
- /* set 9600 baud & do some init ?! */
- ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
- ARK3116_SND(serial,148,0xFE,0x40,0x0038,0x0000);
- ARK3116_SND(serial,149,0xFE,0x40,0x0001,0x0001);
- ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
- ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
- ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
- ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
- ARK3116_SND(serial,154,0xFE,0x40,0x0003,0x0003);
+ /* seems like serial port status info (RTS, CTS, ...) */
+ /* returns modem control line status?! */
+ ARK3116_RCV(serial, 20, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
+
+ /* set 9600 baud & do some init?! */
+ ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
+ ARK3116_SND(serial, 148, 0xFE, 0x40, 0x0038, 0x0000);
+ ARK3116_SND(serial, 149, 0xFE, 0x40, 0x0001, 0x0001);
+ ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
+ ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
+ ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
+ ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
+ ARK3116_SND(serial, 154, 0xFE, 0x40, 0x0003, 0x0003);
kfree(buf);
- return(0);
+ return 0;
cleanup:
- for (--i; i>=0; --i)
+ for (--i; i >= 0; --i)
usb_set_serial_port_data(serial->port[i], NULL);
return -ENOMEM;
}
@@ -180,7 +180,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
- port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ port->tty->termios->c_cflag = B9600 | CS8
+ | CREAD | HUPCL | CLOCAL;
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -204,8 +205,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
}
/* set data bit count (8/7/6/5) */
- if (cflag & CSIZE){
- switch (cflag & CSIZE){
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
case CS5:
config |= 0x00;
dbg("setting CS5");
@@ -219,7 +220,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("setting CS7");
break;
default:
- err ("CSIZE was set but not CS5-CS8, using CS8!");
+ err("CSIZE was set but not CS5-CS8, using CS8!");
+ /* fall through */
case CS8:
config |= 0x03;
dbg("setting CS8");
@@ -227,8 +229,8 @@ static void ark3116_set_termios(struct usb_serial_port *port,
}
}
- /* set parity (NONE,EVEN,ODD) */
- if (cflag & PARENB){
+ /* set parity (NONE/EVEN/ODD) */
+ if (cflag & PARENB) {
if (cflag & PARODD) {
config |= 0x08;
dbg("setting parity to ODD");
@@ -240,20 +242,19 @@ static void ark3116_set_termios(struct usb_serial_port *port,
dbg("setting parity to NONE");
}
- /* SET STOPBIT (1/2) */
+ /* set stop bit (1/2) */
if (cflag & CSTOPB) {
config |= 0x04;
- dbg ("setting 2 stop bits");
+ dbg("setting 2 stop bits");
} else {
- dbg ("setting 1 stop bit");
+ dbg("setting 1 stop bit");
}
-
- /* set baudrate: */
+ /* set baudrate */
baud = 0;
- switch (cflag & CBAUD){
+ switch (cflag & CBAUD) {
case B0:
- err("can't set 0baud, using 9600 instead");
+ err("can't set 0 baud, using 9600 instead");
break;
case B75: baud = 75; break;
case B150: baud = 150; break;
@@ -285,38 +286,40 @@ static void ark3116_set_termios(struct usb_serial_port *port,
*/
if (baud == 460800)
/* strange, for 460800 the formula is wrong
- * (dont use round(), then 9600baud is wrong) */
+ * if using round() then 9600baud is wrong) */
ark3116_baud = 7;
else
ark3116_baud = 3000000 / baud;
/* ? */
- ARK3116_RCV(serial,0,0xFE,0xC0,0x0000,0x0003, 0x03, buf);
+ ARK3116_RCV(serial, 0, 0xFE, 0xC0, 0x0000, 0x0003, 0x03, buf);
+
/* offset = buf[0]; */
/* offset = 0x03; */
- /* dbg("using 0x%04X as target for 0x0003:",0x0080+offset); */
-
+ /* dbg("using 0x%04X as target for 0x0003:", 0x0080 + offset); */
/* set baudrate */
- dbg("setting baudrate to %d (->reg=%d)",baud,ark3116_baud);
- ARK3116_SND(serial,147,0xFE,0x40,0x0083,0x0003);
- ARK3116_SND(serial,148,0xFE,0x40,(ark3116_baud & 0x00FF) ,0x0000);
- ARK3116_SND(serial,149,0xFE,0x40,(ark3116_baud & 0xFF00)>>8,0x0001);
- ARK3116_SND(serial,150,0xFE,0x40,0x0003,0x0003);
+ dbg("setting baudrate to %d (->reg=%d)", baud, ark3116_baud);
+ ARK3116_SND(serial, 147, 0xFE, 0x40, 0x0083, 0x0003);
+ ARK3116_SND(serial, 148, 0xFE, 0x40,
+ (ark3116_baud & 0x00FF), 0x0000);
+ ARK3116_SND(serial, 149, 0xFE, 0x40,
+ (ark3116_baud & 0xFF00) >> 8, 0x0001);
+ ARK3116_SND(serial, 150, 0xFE, 0x40, 0x0003, 0x0003);
/* ? */
- ARK3116_RCV(serial,151,0xFE,0xC0,0x0000,0x0004,0x03, buf);
- ARK3116_SND(serial,152,0xFE,0x40,0x0000,0x0003);
+ ARK3116_RCV(serial, 151, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
+ ARK3116_SND(serial, 152, 0xFE, 0x40, 0x0000, 0x0003);
/* set data bit count, stop bit count & parity: */
dbg("updating bit count, stop bit or parity (cfg=0x%02X)", config);
- ARK3116_RCV(serial,153,0xFE,0xC0,0x0000,0x0003,0x00, buf);
- ARK3116_SND(serial,154,0xFE,0x40,config,0x0003);
+ ARK3116_RCV(serial, 153, 0xFE, 0xC0, 0x0000, 0x0003, 0x00, buf);
+ ARK3116_SND(serial, 154, 0xFE, 0x40, config, 0x0003);
if (cflag & CRTSCTS)
- dbg("CRTSCTS not supported by chipset ?!");
+ dbg("CRTSCTS not supported by chipset?!");
- /* TEST ARK3116_SND(154,0xFE,0x40,0xFFFF, 0x0006); */
+ /* TEST ARK3116_SND(154, 0xFE, 0x40, 0xFFFF, 0x0006); */
kfree(buf);
return;
@@ -329,11 +332,11 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp)
char *buf;
int result = 0;
- dbg("%s - port %d", __FUNCTION__, port->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
buf = kmalloc(1, GFP_KERNEL);
if (!buf) {
- dbg("error kmalloc -> out of mem ?");
+ dbg("error kmalloc -> out of mem?");
return -ENOMEM;
}
@@ -342,44 +345,68 @@ static int ark3116_open(struct usb_serial_port *port, struct file *filp)
return result;
/* open */
- ARK3116_RCV(serial,111,0xFE,0xC0,0x0000,0x0003, 0x02, buf);
+ ARK3116_RCV(serial, 111, 0xFE, 0xC0, 0x0000, 0x0003, 0x02, buf);
- ARK3116_SND(serial,112,0xFE,0x40,0x0082,0x0003);
- ARK3116_SND(serial,113,0xFE,0x40,0x001A,0x0000);
- ARK3116_SND(serial,114,0xFE,0x40,0x0000,0x0001);
- ARK3116_SND(serial,115,0xFE,0x40,0x0002,0x0003);
+ ARK3116_SND(serial, 112, 0xFE, 0x40, 0x0082, 0x0003);
+ ARK3116_SND(serial, 113, 0xFE, 0x40, 0x001A, 0x0000);
+ ARK3116_SND(serial, 114, 0xFE, 0x40, 0x0000, 0x0001);
+ ARK3116_SND(serial, 115, 0xFE, 0x40, 0x0002, 0x0003);
- ARK3116_RCV(serial,116,0xFE,0xC0,0x0000,0x0004, 0x03, buf);
- ARK3116_SND(serial,117,0xFE,0x40,0x0002,0x0004);
+ ARK3116_RCV(serial, 116, 0xFE, 0xC0, 0x0000, 0x0004, 0x03, buf);
+ ARK3116_SND(serial, 117, 0xFE, 0x40, 0x0002, 0x0004);
- ARK3116_RCV(serial,118,0xFE,0xC0,0x0000,0x0004, 0x02, buf);
- ARK3116_SND(serial,119,0xFE,0x40,0x0000,0x0004);
+ ARK3116_RCV(serial, 118, 0xFE, 0xC0, 0x0000, 0x0004, 0x02, buf);
+ ARK3116_SND(serial, 119, 0xFE, 0x40, 0x0000, 0x0004);
- ARK3116_RCV(serial,120,0xFE,0xC0,0x0000,0x0004, 0x00, buf);
+ ARK3116_RCV(serial, 120, 0xFE, 0xC0, 0x0000, 0x0004, 0x00, buf);
- ARK3116_SND(serial,121,0xFE,0x40,0x0001,0x0004);
+ ARK3116_SND(serial, 121, 0xFE, 0x40, 0x0001, 0x0004);
- ARK3116_RCV(serial,122,0xFE,0xC0,0x0000,0x0004, 0x01, buf);
+ ARK3116_RCV(serial, 122, 0xFE, 0xC0, 0x0000, 0x0004, 0x01, buf);
- ARK3116_SND(serial,123,0xFE,0x40,0x0003,0x0004);
+ ARK3116_SND(serial, 123, 0xFE, 0x40, 0x0003, 0x0004);
- /* returns different values (control lines ?!) */
- ARK3116_RCV(serial,124,0xFE,0xC0,0x0000,0x0006, 0xFF, buf);
+ /* returns different values (control lines?!) */
+ ARK3116_RCV(serial, 124, 0xFE, 0xC0, 0x0000, 0x0006, 0xFF, buf);
- /* initialise termios: */
+ /* initialise termios */
if (port->tty)
ark3116_set_termios(port, &tmp_termios);
kfree(buf);
return result;
-
}
static int ark3116_ioctl(struct usb_serial_port *port, struct file *file,
unsigned int cmd, unsigned long arg)
{
- dbg("ioctl not supported yet...");
+ struct serial_struct serstruct;
+ void __user *user_arg = (void __user *)arg;
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ /* XXX: Some of these values are probably wrong. */
+ memset(&serstruct, 0, sizeof (serstruct));
+ serstruct.type = PORT_16654;
+ serstruct.line = port->serial->minor;
+ serstruct.port = port->number;
+ serstruct.custom_divisor = 0;
+ serstruct.baud_base = 460800;
+
+ if (copy_to_user(user_arg, &serstruct, sizeof (serstruct)))
+ return -EFAULT;
+
+ return 0;
+ case TIOCSSERIAL:
+ if (copy_from_user(&serstruct, user_arg, sizeof (serstruct)))
+ return -EFAULT;
+ return 0;
+ default:
+ dbg("%s cmd 0x%04x not supported", __FUNCTION__, cmd);
+ break;
+ }
+
return -ENOIOCTLCMD;
}
@@ -389,7 +416,7 @@ static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file)
char *buf;
char temp;
- /* seems like serial port status info (RTS, CTS,...) is stored
+ /* seems like serial port status info (RTS, CTS, ...) is stored
* in reg(?) 0x0006
* pcb connection point 11 = GND -> sets bit4 of response
* pcb connection point 7 = GND -> sets bit6 of response
@@ -401,16 +428,16 @@ static int ark3116_tiocmget(struct usb_serial_port *port, struct file *file)
return -ENOMEM;
}
- /* read register: */
- ARK3116_RCV_QUIET(serial,0xFE,0xC0,0x0000,0x0006,buf);
+ /* read register */
+ ARK3116_RCV_QUIET(serial, 0xFE, 0xC0, 0x0000, 0x0006, buf);
temp = buf[0];
kfree(buf);
- /* i do not really know if bit4=CTS and bit6=DSR... was just a
- * quick guess !!
+ /* i do not really know if bit4=CTS and bit6=DSR... just a
+ * quick guess!
*/
- return (temp & (1<<4) ? TIOCM_CTS : 0) |
- (temp & (1<<6) ? TIOCM_DSR : 0);
+ return (temp & (1<<4) ? TIOCM_CTS : 0)
+ | (temp & (1<<6) ? TIOCM_DSR : 0);
}
static struct usb_driver ark3116_driver = {
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 70ece9e01ce4..8835bb58ca9b 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -91,7 +91,7 @@ static int belkin_sa_startup (struct usb_serial *serial);
static void belkin_sa_shutdown (struct usb_serial *serial);
static int belkin_sa_open (struct usb_serial_port *port, struct file *filp);
static void belkin_sa_close (struct usb_serial_port *port, struct file *filp);
-static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs);
+static void belkin_sa_read_int_callback (struct urb *urb);
static void belkin_sa_set_termios (struct usb_serial_port *port, struct termios * old);
static int belkin_sa_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void belkin_sa_break_ctl (struct usb_serial_port *port, int break_state );
@@ -248,7 +248,7 @@ static void belkin_sa_close (struct usb_serial_port *port, struct file *filp)
} /* belkin_sa_close */
-static void belkin_sa_read_int_callback (struct urb *urb, struct pt_regs *regs)
+static void belkin_sa_read_int_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct belkin_sa_private *priv;
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 486c7411b9a7..bbf6532c26e5 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -65,6 +65,7 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x10C4, 0x813D) }, /* Burnside Telecom Deskmobile */
{ USB_DEVICE(0x10C4, 0x815E) }, /* Helicomm IP-Link 1220-DVM */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x16D6, 0x0001) }, /* Jablotron serial interface */
{ } /* Terminating Entry */
};
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 6286aba86fae..a63c3286caa0 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -63,9 +63,9 @@ static int cyberjack_open (struct usb_serial_port *port, struct file *filp);
static void cyberjack_close (struct usb_serial_port *port, struct file *filp);
static int cyberjack_write (struct usb_serial_port *port, const unsigned char *buf, int count);
static int cyberjack_write_room( struct usb_serial_port *port );
-static void cyberjack_read_int_callback (struct urb *urb, struct pt_regs *regs);
-static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+static void cyberjack_read_int_callback (struct urb *urb);
+static void cyberjack_read_bulk_callback (struct urb *urb);
+static void cyberjack_write_bulk_callback (struct urb *urb);
static struct usb_device_id id_table [] = {
{ USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
@@ -214,14 +214,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
return (0);
}
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
spin_lock_irqsave(&priv->lock, flags);
@@ -299,7 +299,7 @@ static int cyberjack_write_room( struct usb_serial_port *port )
return CYBERJACK_LOCAL_BUF_SIZE;
}
-static void cyberjack_read_int_callback( struct urb *urb, struct pt_regs *regs )
+static void cyberjack_read_int_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
@@ -356,7 +356,7 @@ resubmit:
dbg("%s - usb_submit_urb(int urb)", __FUNCTION__);
}
-static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void cyberjack_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
@@ -406,7 +406,7 @@ static void cyberjack_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
}
}
-static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void cyberjack_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cyberjack_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index ee70fddcab60..f2e89a083659 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -129,6 +129,9 @@ struct cypress_private {
int cmd_ctrl; /* always set this to 1 before issuing a command */
struct cypress_buf *buf; /* write buffer */
int write_urb_in_use; /* write urb in use indicator */
+ int write_urb_interval; /* interval to use for write urb */
+ int read_urb_interval; /* interval to use for read urb */
+ int comm_is_ok; /* true if communication is (still) ok */
int termios_initialized;
__u8 line_control; /* holds dtr / rts value */
__u8 current_status; /* received from last read - info on dsr,cts,cd,ri,etc */
@@ -168,8 +171,9 @@ static int cypress_tiocmset (struct usb_serial_port *port, struct file *file,
static int cypress_chars_in_buffer (struct usb_serial_port *port);
static void cypress_throttle (struct usb_serial_port *port);
static void cypress_unthrottle (struct usb_serial_port *port);
-static void cypress_read_int_callback (struct urb *urb, struct pt_regs *regs);
-static void cypress_write_int_callback (struct urb *urb, struct pt_regs *regs);
+static void cypress_set_dead (struct usb_serial_port *port);
+static void cypress_read_int_callback (struct urb *urb);
+static void cypress_write_int_callback (struct urb *urb);
/* baud helper functions */
static int mask_to_rate (unsigned mask);
static unsigned rate_to_mask (int rate);
@@ -288,6 +292,9 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
priv = usb_get_serial_port_data(port);
+ if (!priv->comm_is_ok)
+ return -ENODEV;
+
switch(cypress_request_type) {
case CYPRESS_SET_CONFIG:
@@ -365,13 +372,12 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
if (tries++ >= 3)
break;
- if (retval == EPIPE)
- usb_clear_halt(port->serial->dev, 0x00);
- } while (retval != 8 && retval != ENODEV);
+ } while (retval != 8 && retval != -ENODEV);
- if (retval != 8)
+ if (retval != 8) {
err("%s - failed sending serial line settings - %d", __FUNCTION__, retval);
- else {
+ cypress_set_dead(port);
+ } else {
spin_lock_irqsave(&priv->lock, flags);
priv->baud_rate = new_baudrate;
priv->cbr_mask = baud_mask;
@@ -392,12 +398,11 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
if (tries++ >= 3)
break;
- if (retval == EPIPE)
- usb_clear_halt(port->serial->dev, 0x00);
- } while (retval != 5 && retval != ENODEV);
+ } while (retval != 5 && retval != -ENODEV);
if (retval != 5) {
err("%s - failed to retrieve serial line settings - %d", __FUNCTION__, retval);
+ cypress_set_dead(port);
return retval;
} else {
spin_lock_irqsave(&priv->lock, flags);
@@ -419,6 +424,24 @@ static int cypress_serial_control (struct usb_serial_port *port, unsigned baud_m
} /* cypress_serial_control */
+static void cypress_set_dead(struct usb_serial_port *port)
+{
+ struct cypress_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!priv->comm_is_ok) {
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return;
+ }
+ priv->comm_is_ok = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ err("cypress_m8 suspending failing port %d - interval might be too short",
+ port->number);
+}
+
+
/* given a baud mask, it will return integer baud on success */
static int mask_to_rate (unsigned mask)
{
@@ -472,13 +495,15 @@ static unsigned rate_to_mask (int rate)
static int generic_startup (struct usb_serial *serial)
{
struct cypress_private *priv;
+ struct usb_serial_port *port = serial->port[0];
- dbg("%s - port %d", __FUNCTION__, serial->port[0]->number);
+ dbg("%s - port %d", __FUNCTION__, port->number);
priv = kzalloc(sizeof (struct cypress_private), GFP_KERNEL);
if (!priv)
return -ENOMEM;
+ priv->comm_is_ok = !0;
spin_lock_init(&priv->lock);
priv->buf = cypress_buf_alloc(CYPRESS_BUF_SIZE);
if (priv->buf == NULL) {
@@ -489,13 +514,24 @@ static int generic_startup (struct usb_serial *serial)
usb_reset_configuration (serial->dev);
- interval = 1;
priv->cmd_ctrl = 0;
priv->line_control = 0;
priv->termios_initialized = 0;
priv->rx_flags = 0;
priv->cbr_mask = B300;
- usb_set_serial_port_data(serial->port[0], priv);
+ if (interval > 0) {
+ priv->write_urb_interval = interval;
+ priv->read_urb_interval = interval;
+ dbg("%s - port %d read & write intervals forced to %d",
+ __FUNCTION__,port->number,interval);
+ } else {
+ priv->write_urb_interval = port->interrupt_out_urb->interval;
+ priv->read_urb_interval = port->interrupt_in_urb->interval;
+ dbg("%s - port %d intervals: read=%d write=%d",
+ __FUNCTION__,port->number,
+ priv->read_urb_interval,priv->write_urb_interval);
+ }
+ usb_set_serial_port_data(port, priv);
return 0;
}
@@ -585,6 +621,9 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
dbg("%s - port %d", __FUNCTION__, port->number);
+ if (!priv->comm_is_ok)
+ return -EIO;
+
/* clear halts before open */
usb_clear_halt(serial->dev, 0x81);
usb_clear_halt(serial->dev, 0x02);
@@ -624,11 +663,12 @@ static int cypress_open (struct usb_serial_port *port, struct file *filp)
usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length,
- cypress_read_int_callback, port, interval);
+ cypress_read_int_callback, port, priv->read_urb_interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result){
dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
+ cypress_set_dead(port);
}
return result;
@@ -733,6 +773,9 @@ static void cypress_send(struct usb_serial_port *port)
struct cypress_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
+ if (!priv->comm_is_ok)
+ return;
+
dbg("%s - port %d", __FUNCTION__, port->number);
dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size);
@@ -806,14 +849,16 @@ send:
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size,
port->interrupt_out_urb->transfer_buffer);
- port->interrupt_out_urb->transfer_buffer_length = actual_size;
- port->interrupt_out_urb->dev = port->serial->dev;
- port->interrupt_out_urb->interval = interval;
+ usb_fill_int_urb(port->interrupt_out_urb, port->serial->dev,
+ usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress),
+ port->interrupt_out_buffer, port->interrupt_out_size,
+ cypress_write_int_callback, port, priv->write_urb_interval);
result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC);
if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__,
result);
priv->write_urb_in_use = 0;
+ cypress_set_dead(port);
}
spin_lock_irqsave(&priv->lock, flags);
@@ -1214,18 +1259,23 @@ static void cypress_unthrottle (struct usb_serial_port *port)
priv->rx_flags = 0;
spin_unlock_irqrestore(&priv->lock, flags);
+ if (!priv->comm_is_ok)
+ return;
+
if (actually_throttled) {
port->interrupt_in_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&port->dev, "%s - failed submitting read urb, "
"error %d\n", __FUNCTION__, result);
+ cypress_set_dead(port);
+ }
}
}
-static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
+static void cypress_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cypress_private *priv = usb_get_serial_port_data(port);
@@ -1240,9 +1290,22 @@ static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s - port %d", __FUNCTION__, port->number);
- if (urb->status) {
- dbg("%s - nonzero read status received: %d", __FUNCTION__,
- urb->status);
+ switch (urb->status) {
+ case 0: /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* precursor to disconnect so just go away */
+ return;
+ case -EPIPE:
+ usb_clear_halt(port->serial->dev,0x81);
+ break;
+ default:
+ /* something ugly is going on... */
+ dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
+ __FUNCTION__,urb->status);
+ cypress_set_dead(port);
return;
}
@@ -1343,25 +1406,27 @@ continue_read:
/* Continue trying to always read... unless the port has closed. */
- if (port->open_count > 0) {
+ if (port->open_count > 0 && priv->comm_is_ok) {
usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
usb_rcvintpipe(port->serial->dev,
port->interrupt_in_endpointAddress),
port->interrupt_in_urb->transfer_buffer,
port->interrupt_in_urb->transfer_buffer_length,
- cypress_read_int_callback, port, interval);
+ cypress_read_int_callback, port, priv->read_urb_interval);
result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&urb->dev->dev, "%s - failed resubmitting "
"read urb, error %d\n", __FUNCTION__,
result);
+ cypress_set_dead(port);
+ }
}
return;
} /* cypress_read_int_callback */
-static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
+static void cypress_write_int_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct cypress_private *priv = usb_get_serial_port_data(port);
@@ -1380,20 +1445,26 @@ static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
priv->write_urb_in_use = 0;
return;
- case -EPIPE: /* no break needed */
+ case -EPIPE: /* no break needed; clear halt and resubmit */
+ if (!priv->comm_is_ok)
+ break;
usb_clear_halt(port->serial->dev, 0x02);
- default:
/* error in the urb, so we have to resubmit it */
- dbg("%s - Overflow in write", __FUNCTION__);
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
port->interrupt_out_urb->transfer_buffer_length = 1;
port->interrupt_out_urb->dev = port->serial->dev;
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
- if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
- __FUNCTION__, result);
- else
+ if (!result)
return;
+ dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n",
+ __FUNCTION__, result);
+ cypress_set_dead(port);
+ break;
+ default:
+ dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
+ __FUNCTION__,urb->status);
+ cypress_set_dead(port);
+ break;
}
priv->write_urb_in_use = 0;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index 9b225183fc7a..bdb58100fc1d 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -456,7 +456,7 @@ static int digi_tiocmget( struct usb_serial_port *port, struct file *file );
static int digi_tiocmset( struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear );
static int digi_write( struct usb_serial_port *port, const unsigned char *buf, int count );
-static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs );
+static void digi_write_bulk_callback( struct urb *urb );
static int digi_write_room( struct usb_serial_port *port );
static int digi_chars_in_buffer( struct usb_serial_port *port );
static int digi_open( struct usb_serial_port *port, struct file *filp );
@@ -464,7 +464,7 @@ static void digi_close( struct usb_serial_port *port, struct file *filp );
static int digi_startup_device( struct usb_serial *serial );
static int digi_startup( struct usb_serial *serial );
static void digi_shutdown( struct usb_serial *serial );
-static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs );
+static void digi_read_bulk_callback( struct urb *urb );
static int digi_read_inb_callback( struct urb *urb );
static int digi_read_oob_callback( struct urb *urb );
@@ -1336,7 +1336,7 @@ dbg( "digi_write: returning %d", ret );
}
-static void digi_write_bulk_callback( struct urb *urb, struct pt_regs *regs )
+static void digi_write_bulk_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1754,7 +1754,7 @@ dbg( "digi_shutdown: TOP, in_interrupt()=%ld", in_interrupt() );
}
-static void digi_read_bulk_callback( struct urb *urb, struct pt_regs *regs )
+static void digi_read_bulk_callback( struct urb *urb )
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index daafe405d86d..4ce10a831953 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -93,8 +93,8 @@ static int empeg_ioctl (struct usb_serial_port *port,
unsigned int cmd,
unsigned long arg);
static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios);
-static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+static void empeg_write_bulk_callback (struct urb *urb);
+static void empeg_read_bulk_callback (struct urb *urb);
static struct usb_device_id id_table [] = {
{ USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) },
@@ -323,7 +323,7 @@ static int empeg_chars_in_buffer (struct usb_serial_port *port)
}
-static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void empeg_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -338,7 +338,7 @@ static void empeg_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
}
-static void empeg_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void empeg_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty;
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index c6115aa1b445..bd76b4c11fcc 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -1,16 +1,16 @@
/*
* USB FTDI SIO driver
*
- * Copyright (C) 1999 - 2001
- * Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2001
+ * Greg Kroah-Hartman (greg@kroah.com)
* Bill Ryder (bryder@sgi.com)
* Copyright (C) 2002
* Kuba Ober (kuba@mareimbrium.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.
+ * 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.
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
@@ -32,7 +32,7 @@
* Changed full name of USB-UIRT device to avoid "/" character.
* Added FTDI's alternate PID (0x6006) for FT232/245 devices.
* Added PID for "ELV USB Module UO100" from Stefan Frings.
- *
+ *
* (21/Oct/2003) Ian Abbott
* Renamed some VID/PID macros for Matrix Orbital and Perle Systems
* devices. Removed Matrix Orbital and Perle Systems devices from the
@@ -69,7 +69,7 @@
* does not incure any measurable overhead. This also relies on the fact
* that we have proper reference counting logic for urbs. I nicked this
* from Greg KH's Visor driver.
- *
+ *
* (23/Jun/2003) Ian Abbott
* Reduced flip buffer pushes and corrected a data length test in
* ftdi_read_bulk_callback.
@@ -77,7 +77,7 @@
*
* (21/Jun/2003) Erik Nygren
* Added support for Home Electronics Tira-1 IR transceiver using FT232BM chip.
- * See <http://www.home-electro.com/tira1.htm>. Only operates properly
+ * See <http://www.home-electro.com/tira1.htm>. Only operates properly
* at 100000 and RTS-CTS, so set custom divisor mode on startup.
* Also force the Tira-1 and USB-UIRT to only use their custom baud rates.
*
@@ -137,17 +137,17 @@
* (17/Feb/2003) Bill Ryder
* Added write urb buffer pool on a per device basis
* Added more checking for open file on callbacks (fixed OOPS)
- * Added CrystalFontz 632 and 634 PIDs
+ * Added CrystalFontz 632 and 634 PIDs
* (thanx to CrystalFontz for the sample devices - they flushed out
* some driver bugs)
* Minor debugging message changes
* Added throttle, unthrottle and chars_in_buffer functions
* Fixed FTDI_SIO (the original device) bug
* Fixed some shutdown handling
- *
- *
- *
- *
+ *
+ *
+ *
+ *
* (07/Jun/2002) Kuba Ober
* Changed FTDI_SIO_BASE_BAUD_TO_DIVISOR macro into ftdi_baud_to_divisor
* function. It was getting too complex.
@@ -158,7 +158,7 @@
*
* (25/Jul/2002) Bill Ryder inserted Dmitri's TIOCMIWAIT patch
* Not tested by me but it doesn't break anything I use.
- *
+ *
* (04/Jan/2002) Kuba Ober
* Implemented 38400 baudrate kludge, where it can be substituted with other
* values. That's the only way to set custom baudrates.
@@ -179,7 +179,7 @@
* (the previous version caused panics)
* Removed port iteration code since the device only has one I/O port and it
* was wrong anyway.
- *
+ *
* (31/May/2001) gkh
* Switched from using spinlock to a semaphore, which fixes lots of problems.
*
@@ -188,16 +188,16 @@
* Cleaned up comments for 8U232
* Added parity, framing and overrun error handling
* Added receive break handling.
- *
+ *
* (04/08/2001) gb
* Identify version on module load.
- *
+ *
* (18/March/2001) Bill Ryder
* (Not released)
* Added send break handling. (requires kernel patch too)
* Fixed 8U232AM hardware RTS/CTS etc status reporting.
* Added flipbuf fix copied from generic device
- *
+ *
* (12/3/2000) Bill Ryder
* Added support for 8U232AM device.
* Moved PID and VIDs into header file only.
@@ -211,14 +211,14 @@
* Cleaned up comments. Removed multiple PID/VID definitions.
* Factorised cts/dtr code
* Made use of __FUNCTION__ in dbg's
- *
+ *
* (11/01/2000) Adam J. Richter
* usb_device_id table support
- *
+ *
* (10/05/2000) gkh
* Fixed bug with urb->dev not being set properly, now that the usb
* core needs it.
- *
+ *
* (09/11/2000) gkh
* Removed DEBUG #ifdefs with call to usb_serial_debug_data
*
@@ -226,11 +226,11 @@
* Added module_init and module_exit functions to handle the fact that this
* driver is a loadable module now.
*
- * (04/04/2000) Bill Ryder
+ * (04/04/2000) Bill Ryder
* Fixed bugs in TCGET/TCSET ioctls (by removing them - they are
* handled elsewhere in the tty io driver chain).
*
- * (03/30/2000) Bill Ryder
+ * (03/30/2000) Bill Ryder
* Implemented lots of ioctls
* Fixed a race condition in write
* Changed some dbg's to errs
@@ -344,6 +344,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) },
@@ -443,13 +444,13 @@ static struct usb_device_id id_table_combined [] = {
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS300PC_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1300PC_PID) }, */
/* { USB_DEVICE(FTDI_VID, FTDI_ELV_WS500_PID) }, */
- { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
- { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
- { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
{ USB_DEVICE(INTREPID_VID, INTREPID_VALUECAN_PID) },
{ USB_DEVICE(INTREPID_VID, INTREPID_NEOVI_PID) },
@@ -507,6 +508,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) },
{ USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -518,7 +522,7 @@ static struct usb_driver ftdi_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
+ .no_dynamic_id = 1,
};
static const char *ftdi_chip_name[] = {
@@ -544,13 +548,13 @@ struct ftdi_private {
int custom_divisor; /* custom_divisor kludge, this is for baud_base (different from what goes to the chip!) */
__u16 last_set_data_urb_value ;
/* the last data state set - needed for doing a break */
- int write_offset; /* This is the offset in the usb data block to write the serial data -
+ int write_offset; /* This is the offset in the usb data block to write the serial data -
* it is different between devices
*/
int flags; /* some ASYNC_xxxx flags are supported */
unsigned long last_dtr_rts; /* saved modem control outputs */
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- char prev_status, diff_status; /* Used for TIOCMIWAIT */
+ char prev_status, diff_status; /* Used for TIOCMIWAIT */
__u8 rx_flags; /* receive state flags (throttling) */
spinlock_t rx_lock; /* spinlock for receive state */
struct work_struct rx_work;
@@ -585,8 +589,8 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp);
static int ftdi_write (struct usb_serial_port *port, const unsigned char *buf, int count);
static int ftdi_write_room (struct usb_serial_port *port);
static int ftdi_chars_in_buffer (struct usb_serial_port *port);
-static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+static void ftdi_write_bulk_callback (struct urb *urb);
+static void ftdi_read_bulk_callback (struct urb *urb);
static void ftdi_process_read (void *param);
static void ftdi_set_termios (struct usb_serial_port *port, struct termios * old);
static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file);
@@ -717,7 +721,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set, unsigned
urb_value |= FTDI_SIO_SET_RTS_HIGH;
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
- FTDI_SIO_SET_MODEM_CTRL_REQUEST,
+ FTDI_SIO_SET_MODEM_CTRL_REQUEST,
FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
urb_value, priv->interface,
buf, 0, WDR_TIMEOUT);
@@ -764,7 +768,7 @@ static int change_speed(struct usb_serial_port *port)
if (priv->interface) { /* FT2232C */
urb_index = (__u16)((urb_index << 8) | priv->interface);
}
-
+
rv = usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_BAUDRATE_REQUEST,
@@ -823,7 +827,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
/* 3. Convert baudrate to device-specific divisor */
- if (!baud) baud = 9600;
+ if (!baud) baud = 9600;
switch(priv->chip_type) {
case SIO: /* SIO chip */
switch(baud) {
@@ -839,7 +843,7 @@ static __u32 get_ftdi_divisor(struct usb_serial_port * port)
case 115200: div_value = ftdi_sio_b115200; break;
} /* baud */
if (div_value == 0) {
- dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
+ dbg("%s - Baudrate (%d) requested is not supported", __FUNCTION__, baud);
div_value = ftdi_sio_b9600;
div_okay = 0;
}
@@ -921,7 +925,7 @@ static int set_serial_info(struct usb_serial_port * port, struct serial_struct _
/* Make the changes - these are privileged changes! */
priv->flags = ((priv->flags & ~ASYNC_FLAGS) |
- (new_serial.flags & ASYNC_FLAGS));
+ (new_serial.flags & ASYNC_FLAGS));
priv->custom_divisor = new_serial.custom_divisor;
port->tty->low_latency = (priv->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
@@ -946,7 +950,7 @@ check_and_exit:
(old_priv.custom_divisor != priv->custom_divisor))) {
change_speed(port);
}
-
+
return (0);
} /* set_serial_info */
@@ -1018,18 +1022,18 @@ static ssize_t show_latency_timer(struct device *dev, struct device_attribute *a
struct usb_device *udev;
unsigned short latency = 0;
int rv = 0;
-
+
udev = to_usb_device(dev);
-
+
dbg("%s",__FUNCTION__);
-
+
rv = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
(char*) &latency, 1, WDR_TIMEOUT);
-
+
if (rv < 0) {
dev_err(dev, "Unable to read latency timer: %i", rv);
return -EIO;
@@ -1047,23 +1051,23 @@ static ssize_t store_latency_timer(struct device *dev, struct device_attribute *
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
-
+
udev = to_usb_device(dev);
-
+
dbg("%s: setting latency timer = %i", __FUNCTION__, v);
-
+
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
- v, priv->interface,
+ v, priv->interface,
buf, 0, WDR_TIMEOUT);
-
+
if (rv < 0) {
dev_err(dev, "Unable to write latency timer: %i", rv);
return -EIO;
}
-
+
return count;
}
@@ -1078,48 +1082,52 @@ static ssize_t store_event_char(struct device *dev, struct device_attribute *att
char buf[1];
int v = simple_strtoul(valbuf, NULL, 10);
int rv = 0;
-
+
udev = to_usb_device(dev);
-
+
dbg("%s: setting event char = %i", __FUNCTION__, v);
-
+
rv = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
FTDI_SIO_SET_EVENT_CHAR_REQUEST,
FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
- v, priv->interface,
+ v, priv->interface,
buf, 0, WDR_TIMEOUT);
-
+
if (rv < 0) {
dbg("Unable to write event character: %i", rv);
return -EIO;
}
-
+
return count;
}
static DEVICE_ATTR(latency_timer, S_IWUSR | S_IRUGO, show_latency_timer, store_latency_timer);
static DEVICE_ATTR(event_char, S_IWUSR, NULL, store_event_char);
-static void create_sysfs_attrs(struct usb_serial *serial)
-{
+static int create_sysfs_attrs(struct usb_serial *serial)
+{
struct ftdi_private *priv;
struct usb_device *udev;
+ int retval = 0;
dbg("%s",__FUNCTION__);
-
+
priv = usb_get_serial_port_data(serial->port[0]);
udev = serial->dev;
-
+
/* XXX I've no idea if the original SIO supports the event_char
* sysfs parameter, so I'm playing it safe. */
if (priv->chip_type != SIO) {
dbg("sysfs attributes for %s", ftdi_chip_name[priv->chip_type]);
- device_create_file(&udev->dev, &dev_attr_event_char);
- if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
- device_create_file(&udev->dev, &dev_attr_latency_timer);
+ retval = device_create_file(&udev->dev, &dev_attr_event_char);
+ if ((!retval) &&
+ (priv->chip_type == FT232BM || priv->chip_type == FT2232C)) {
+ retval = device_create_file(&udev->dev,
+ &dev_attr_latency_timer);
}
}
+ return retval;
}
static void remove_sysfs_attrs(struct usb_serial *serial)
@@ -1127,11 +1135,11 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
struct ftdi_private *priv;
struct usb_device *udev;
- dbg("%s",__FUNCTION__);
+ dbg("%s",__FUNCTION__);
priv = usb_get_serial_port_data(serial->port[0]);
udev = serial->dev;
-
+
/* XXX see create_sysfs_attrs */
if (priv->chip_type != SIO) {
device_remove_file(&udev->dev, &dev_attr_event_char);
@@ -1139,7 +1147,7 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
device_remove_file(&udev->dev, &dev_attr_latency_timer);
}
}
-
+
}
/*
@@ -1162,7 +1170,8 @@ static int ftdi_sio_attach (struct usb_serial *serial)
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv;
struct ftdi_sio_quirk *quirk;
-
+ int retval;
+
dbg("%s",__FUNCTION__);
priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL);
@@ -1203,15 +1212,18 @@ static int ftdi_sio_attach (struct usb_serial *serial)
usb_set_serial_port_data(serial->port[0], priv);
ftdi_determine_type (serial->port[0]);
- create_sysfs_attrs(serial);
+ retval = create_sysfs_attrs(serial);
+ if (retval)
+ dev_err(&serial->dev->dev, "Error creating sysfs files, "
+ "continuing\n");
/* Check for device requiring special set up. */
quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
if (quirk && quirk->setup) {
quirk->setup(serial);
}
-
- return (0);
+
+ return 0;
} /* ftdi_sio_attach */
@@ -1246,7 +1258,7 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
} /* ftdi_HE_TIRA1_setup */
-/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
+/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
* it is called when the usb device is disconnected
*
* usbserial:usb_serial_disconnect
@@ -1257,16 +1269,16 @@ static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
static void ftdi_shutdown (struct usb_serial *serial)
{ /* ftdi_shutdown */
-
+
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv = usb_get_serial_port_data(port);
dbg("%s", __FUNCTION__);
remove_sysfs_attrs(serial);
-
- /* all open ports are closed at this point
- * (by usbserial.c:__serial_close, which calls ftdi_close)
+
+ /* all open ports are closed at this point
+ * (by usbserial.c:__serial_close, which calls ftdi_close)
*/
if (priv) {
@@ -1281,7 +1293,7 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
struct usb_device *dev = port->serial->dev;
struct ftdi_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
-
+
int result = 0;
char buf[1]; /* Needed for the usb_control_msg I think */
@@ -1300,8 +1312,8 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
/* No error checking for this (will get errors later anyway) */
/* See ftdi_sio.h for description of what is reset */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
- FTDI_SIO_RESET_SIO,
+ FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
+ FTDI_SIO_RESET_SIO,
priv->interface, buf, 0, WDR_TIMEOUT);
/* Termios defaults are set by usb_serial_init. We don't change
@@ -1338,12 +1350,12 @@ static int ftdi_open (struct usb_serial_port *port, struct file *filp)
-/*
+/*
* usbserial:__serial_close only calls ftdi_close if the point is open
*
* This only gets called when it is the last close
- *
- *
+ *
+ *
*/
static void ftdi_close (struct usb_serial_port *port, struct file *filp)
@@ -1356,14 +1368,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
if (c_cflag & HUPCL){
/* Disable flow control */
- if (usb_control_msg(port->serial->dev,
+ if (usb_control_msg(port->serial->dev,
usb_sndctrlpipe(port->serial->dev, 0),
FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0, priv->interface, buf, 0,
WDR_TIMEOUT) < 0) {
err("error from flowcontrol urb");
- }
+ }
/* drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
@@ -1372,14 +1384,14 @@ static void ftdi_close (struct usb_serial_port *port, struct file *filp)
/* cancel any scheduled reading */
cancel_delayed_work(&priv->rx_work);
flush_scheduled_work();
-
+
/* shutdown our bulk read */
if (port->read_urb)
usb_kill_urb(port->read_urb);
} /* ftdi_close */
-
+
/* The SIO requires the first byte to have:
* B0 1
* B1 0
@@ -1411,7 +1423,7 @@ static int ftdi_write (struct usb_serial_port *port,
return 0;
}
spin_unlock_irqrestore(&priv->tx_lock, flags);
-
+
data_offset = priv->write_offset;
dbg("data_offset set to %d",data_offset);
@@ -1450,7 +1462,7 @@ static int ftdi_write (struct usb_serial_port *port,
user_pktsz = todo;
}
/* Write the control byte at the front of the packet*/
- *first_byte = 1 | ((user_pktsz) << 2);
+ *first_byte = 1 | ((user_pktsz) << 2);
/* Copy data for packet */
memcpy (first_byte + data_offset,
current_position, user_pktsz);
@@ -1467,7 +1479,7 @@ static int ftdi_write (struct usb_serial_port *port,
usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size, buffer);
/* fill the buffer and send it */
- usb_fill_bulk_urb(urb, port->serial->dev,
+ usb_fill_bulk_urb(urb, port->serial->dev,
usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
buffer, transfer_size,
ftdi_write_bulk_callback, port);
@@ -1496,7 +1508,7 @@ static int ftdi_write (struct usb_serial_port *port,
/* This function may get called when the device is closed */
-static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void ftdi_write_bulk_callback (struct urb *urb)
{
unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -1508,7 +1520,7 @@ static void ftdi_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
kfree (urb->transfer_buffer);
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
if (urb->status) {
dbg("nonzero write bulk status received: %d", urb->status);
return;
@@ -1579,7 +1591,7 @@ static int ftdi_chars_in_buffer (struct usb_serial_port *port)
-static void ftdi_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void ftdi_read_bulk_callback (struct urb *urb)
{ /* ftdi_read_bulk_callback */
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty;
@@ -1639,7 +1651,7 @@ static void ftdi_process_read (void *param)
struct tty_struct *tty;
struct ftdi_private *priv;
char error_flag;
- unsigned char *data;
+ unsigned char *data;
int i;
int result;
@@ -1747,7 +1759,7 @@ static void ftdi_process_read (void *param)
}
if (length > 0) {
for (i = 2; i < length+2; i++) {
- /* Note that the error flag is duplicated for
+ /* Note that the error flag is duplicated for
every character received since we don't know
which character it applied to */
tty_insert_flip_char(tty, data[packet_offset+i], error_flag);
@@ -1761,7 +1773,7 @@ static void ftdi_process_read (void *param)
This doesn't work well since the application receives a never
ending stream of bad data - even though new data hasn't been sent.
Therefore I (bill) have taken this out.
- However - this might make sense for framing errors and so on
+ However - this might make sense for framing errors and so on
so I am leaving the code in for now.
*/
else {
@@ -1815,7 +1827,7 @@ static void ftdi_process_read (void *param)
/* if the port is closed stop trying to read */
if (port->open_count > 0){
/* Continue trying to always read */
- usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+ usb_fill_bulk_urb(port->read_urb, port->serial->dev,
usb_rcvbulkpipe(port->serial->dev, port->bulk_in_endpointAddress),
port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
ftdi_read_bulk_callback, port);
@@ -1832,9 +1844,9 @@ static void ftdi_process_read (void *param)
static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- __u16 urb_value = 0;
+ __u16 urb_value = 0;
char buf[1];
-
+
/* break_state = -1 to turn on break, and 0 to turn off break */
/* see drivers/char/tty_io.c to see it used */
/* last_set_data_urb_value NEVER has the break bit set in it */
@@ -1842,20 +1854,20 @@ static void ftdi_break_ctl( struct usb_serial_port *port, int break_state )
if (break_state) {
urb_value = priv->last_set_data_urb_value | FTDI_SIO_SET_BREAK;
} else {
- urb_value = priv->last_set_data_urb_value;
+ urb_value = priv->last_set_data_urb_value;
}
-
+
if (usb_control_msg(port->serial->dev, usb_sndctrlpipe(port->serial->dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("%s FAILED to enable/disable break state (state was %d)", __FUNCTION__,break_state);
- }
+ }
dbg("%s break state is %d - urb is %d", __FUNCTION__,break_state, urb_value);
-
+
}
@@ -1871,12 +1883,12 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
struct ftdi_private *priv = usb_get_serial_port_data(port);
__u16 urb_value; /* will hold the new flags */
char buf[1]; /* Perhaps I should dynamically alloc this? */
-
+
// Added for xon/xoff support
unsigned int iflag = port->tty->termios->c_iflag;
unsigned char vstop;
unsigned char vstart;
-
+
dbg("%s", __FUNCTION__);
/* Force baud rate if this device requires it, unless it is set to B0. */
@@ -1894,20 +1906,20 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
cflag = port->tty->termios->c_cflag;
- /* FIXME -For this cut I don't care if the line is really changing or
- not - so just do the change regardless - should be able to
+ /* FIXME -For this cut I don't care if the line is really changing or
+ not - so just do the change regardless - should be able to
compare old_termios and tty->termios */
- /* NOTE These routines can get interrupted by
- ftdi_sio_read_bulk_callback - need to examine what this
+ /* NOTE These routines can get interrupted by
+ ftdi_sio_read_bulk_callback - need to examine what this
means - don't see any problems yet */
-
+
/* Set number of data bits, parity, stop bits */
-
+
urb_value = 0;
urb_value |= (cflag & CSTOPB ? FTDI_SIO_SET_DATA_STOP_BITS_2 :
FTDI_SIO_SET_DATA_STOP_BITS_1);
- urb_value |= (cflag & PARENB ?
- (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
+ urb_value |= (cflag & PARENB ?
+ (cflag & PARODD ? FTDI_SIO_SET_DATA_PARITY_ODD :
FTDI_SIO_SET_DATA_PARITY_EVEN) :
FTDI_SIO_SET_DATA_PARITY_NONE);
if (cflag & CSIZE) {
@@ -1924,25 +1936,25 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* This is needed by the break command since it uses the same command - but is
* or'ed with this value */
priv->last_set_data_urb_value = urb_value;
-
+
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_DATA_REQUEST,
+ FTDI_SIO_SET_DATA_REQUEST,
FTDI_SIO_SET_DATA_REQUEST_TYPE,
urb_value , priv->interface,
buf, 0, WDR_SHORT_TIMEOUT) < 0) {
err("%s FAILED to set databits/stopbits/parity", __FUNCTION__);
- }
+ }
/* Now do the baudrate */
if ((cflag & CBAUD) == B0 ) {
/* Disable flow control */
if (usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("%s error from disable flowcontrol urb", __FUNCTION__);
- }
+ }
/* Drop RTS and DTR */
clear_mctrl(port, TIOCM_DTR | TIOCM_RTS);
} else {
@@ -1960,16 +1972,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* Note device also supports DTR/CD (ugh) and Xon/Xoff in hardware */
if (cflag & CRTSCTS) {
dbg("%s Setting to CRTSCTS flow control", __FUNCTION__);
- if (usb_control_msg(dev,
+ if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to set to rts/cts flow control");
- }
-
- } else {
+ }
+
+ } else {
/*
* Xon/Xoff code
*
@@ -1999,16 +2011,16 @@ static void ftdi_set_termios (struct usb_serial_port *port, struct termios *old_
/* else clause to only run if cfag ! CRTSCTS and iflag ! XOFF */
/* CHECKME Assuming XON/XOFF handled by tty stack - not by device */
dbg("%s Turning off hardware flow control", __FUNCTION__);
- if (usb_control_msg(dev,
+ if (usb_control_msg(dev,
usb_sndctrlpipe(dev, 0),
- FTDI_SIO_SET_FLOW_CTRL_REQUEST,
+ FTDI_SIO_SET_FLOW_CTRL_REQUEST,
FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
buf, 0, WDR_TIMEOUT) < 0) {
err("urb failed to clear flow control");
- }
+ }
}
-
+
}
return;
} /* ftdi_termios */
@@ -2024,11 +2036,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
switch (priv->chip_type) {
case SIO:
/* Request the status from the device */
- if ((ret = usb_control_msg(port->serial->dev,
+ if ((ret = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, 0,
+ 0, 0,
buf, 1, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
@@ -2040,11 +2052,11 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
case FT2232C:
/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
format as the data returned from the in point */
- if ((ret = usb_control_msg(port->serial->dev,
+ if ((ret = usb_control_msg(port->serial->dev,
usb_rcvctrlpipe(port->serial->dev, 0),
- FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+ FTDI_SIO_GET_MODEM_STATUS_REQUEST,
FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
- 0, priv->interface,
+ 0, priv->interface,
buf, 2, WDR_TIMEOUT)) < 0 ) {
err("%s Could not get modem status of device - err: %d", __FUNCTION__,
ret);
@@ -2055,12 +2067,12 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
return -EFAULT;
break;
}
-
+
return (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
(buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
(buf[0] & FTDI_SIO_RI_MASK ? TIOCM_RI : 0) |
(buf[0] & FTDI_SIO_RLSD_MASK ? TIOCM_CD : 0) |
- priv->last_dtr_rts;
+ priv->last_dtr_rts;
}
static int ftdi_tiocmset(struct usb_serial_port *port, struct file * file, unsigned int set, unsigned int clear)
@@ -2126,11 +2138,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
break;
default:
break;
-
+
}
- /* This is not necessarily an error - turns out the higher layers will do
+ /* This is not necessarily an error - turns out the higher layers will do
* some ioctls itself (see comment above)
*/
dbg("%s arg not supported - it was 0x%04x - check /usr/include/asm/ioctls.h", __FUNCTION__, cmd);
@@ -2187,7 +2199,7 @@ static int __init ftdi_init (void)
if (retval)
goto failed_sio_register;
retval = usb_register(&ftdi_driver);
- if (retval)
+ if (retval)
goto failed_usb_register;
info(DRIVER_VERSION ":" DRIVER_DESC);
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 77299996f7ee..f0edb87d2dd5 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -111,6 +111,7 @@
#define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */
#define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */
#define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */
+#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */
#define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */
#define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */
#define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */
@@ -472,6 +473,15 @@
*/
#define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */
+/*
+ * Tactrix OpenPort (ECU) devices.
+ * OpenPort 1.3M submitted by Donour Sizemore.
+ * OpenPort 1.3S and 1.3U submitted by Ian Abbott.
+ */
+#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */
+#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
+#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
+
/* Commands */
#define FTDI_SIO_RESET 0 /* Reset the port */
#define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 727852634be9..4543152a9966 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1,7 +1,7 @@
/*
* Garmin GPS driver
*
- * Copyright (C) 2004 Hermann Kneissel herkne@users.sourceforge.net
+ * Copyright (C) 2006 Hermann Kneissel herkne@users.sourceforge.net
*
* The latest version of the driver can be found at
* http://sourceforge.net/projects/garmin-gps/
@@ -37,6 +37,8 @@
#include <linux/usb.h>
#include <linux/usb/serial.h>
+#include <linux/version.h>
+
/* the mode to be set when the port ist opened */
static int initial_mode = 1;
@@ -50,7 +52,7 @@ static int debug = 0;
*/
#define VERSION_MAJOR 0
-#define VERSION_MINOR 23
+#define VERSION_MINOR 28
#define _STR(s) #s
#define _DRIVER_VERSION(a,b) "v" _STR(a) "." _STR(b)
@@ -164,7 +166,8 @@ struct garmin_data {
#define FLAGS_SESSION_REPLY1_SEEN 0x0080
#define FLAGS_SESSION_REPLY2_SEEN 0x0040
#define FLAGS_BULK_IN_ACTIVE 0x0020
-#define FLAGS_THROTTLED 0x0010
+#define FLAGS_BULK_IN_RESTART 0x0010
+#define FLAGS_THROTTLED 0x0008
#define CLEAR_HALT_REQUIRED 0x0001
#define FLAGS_QUEUING 0x0100
@@ -224,7 +227,7 @@ static struct usb_driver garmin_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
+ .no_dynamic_id = 1,
};
@@ -270,7 +273,7 @@ static inline int isAbortTrfCmnd(const unsigned char *buf)
static void send_to_tty(struct usb_serial_port *port,
- char *data, unsigned int actual_length)
+ char *data, unsigned int actual_length)
{
struct tty_struct *tty = port->tty;
@@ -294,15 +297,15 @@ static void send_to_tty(struct usb_serial_port *port,
* queue a received (usb-)packet for later processing
*/
static int pkt_add(struct garmin_data * garmin_data_p,
- unsigned char *data, unsigned int data_length)
+ unsigned char *data, unsigned int data_length)
{
+ int state = 0;
int result = 0;
unsigned long flags;
struct garmin_packet *pkt;
/* process only packets containg data ... */
if (data_length) {
- garmin_data_p->flags |= FLAGS_QUEUING;
pkt = kmalloc(sizeof(struct garmin_packet)+data_length,
GFP_ATOMIC);
if (pkt == NULL) {
@@ -313,14 +316,16 @@ static int pkt_add(struct garmin_data * garmin_data_p,
memcpy(pkt->data, data, data_length);
spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_QUEUING;
result = list_empty(&garmin_data_p->pktlist);
pkt->seq = garmin_data_p->seq_counter++;
list_add_tail(&pkt->list, &garmin_data_p->pktlist);
+ state = garmin_data_p->state;
spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* in serial mode, if someone is waiting for data from
the device, iconvert and send the next packet to tty. */
- if (result && (garmin_data_p->state == STATE_GSP_WAIT_DATA)) {
+ if (result && (state == STATE_GSP_WAIT_DATA)) {
gsp_next_packet(garmin_data_p);
}
}
@@ -370,9 +375,9 @@ static void pkt_clear(struct garmin_data * garmin_data_p)
static int gsp_send_ack(struct garmin_data * garmin_data_p, __u8 pkt_id)
{
__u8 pkt[10];
- __u8 cksum = 0;
- __u8 *ptr = pkt;
- unsigned l = 0;
+ __u8 cksum = 0;
+ __u8 *ptr = pkt;
+ unsigned l = 0;
dbg("%s - pkt-id: 0x%X.", __FUNCTION__, 0xFF & pkt_id);
@@ -416,7 +421,7 @@ static int gsp_send_ack(struct garmin_data * garmin_data_p, __u8 pkt_id)
static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
{
const __u8* recpkt = garmin_data_p->inbuffer+GSP_INITIAL_OFFSET;
- __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
+ __le32 *usbdata = (__le32 *) garmin_data_p->inbuffer;
int cksum = 0;
int n = 0;
@@ -447,11 +452,11 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
n++;
}
- if ((0xff & (cksum + *recpkt)) != 0) {
- dbg("%s - invalid checksum, expected %02x, got %02x",
- __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
- return -EINVPKT;
- }
+ if ((0xff & (cksum + *recpkt)) != 0) {
+ dbg("%s - invalid checksum, expected %02x, got %02x",
+ __FUNCTION__, 0xff & -cksum, 0xff & *recpkt);
+ return -EINVPKT;
+ }
usbdata[0] = __cpu_to_le32(GARMIN_LAYERID_APPL);
usbdata[1] = __cpu_to_le32(pktid);
@@ -491,20 +496,28 @@ static int gsp_rec_packet(struct garmin_data * garmin_data_p, int count)
*/
static int gsp_receive(struct garmin_data * garmin_data_p,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
int offs = 0;
int ack_or_nak_seen = 0;
int i = 0;
- __u8 *dest = garmin_data_p->inbuffer;
- int size = garmin_data_p->insize;
+ __u8 *dest;
+ int size;
// dleSeen: set if last byte read was a DLE
- int dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
+ int dleSeen;
// skip: if set, skip incoming data until possible start of
// new packet
- int skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
+ int skip;
__u8 data;
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ dest = garmin_data_p->inbuffer;
+ size = garmin_data_p->insize;
+ dleSeen = garmin_data_p->flags & FLAGS_GSP_DLESEEN;
+ skip = garmin_data_p->flags & FLAGS_GSP_SKIP;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
dbg("%s - dle=%d skip=%d size=%d count=%d",
__FUNCTION__, dleSeen, skip, size, count);
@@ -572,6 +585,8 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
}
}
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+
garmin_data_p->insize = size;
// copy flags back to structure
@@ -587,6 +602,11 @@ static int gsp_receive(struct garmin_data * garmin_data_p,
if (ack_or_nak_seen) {
garmin_data_p->state = STATE_GSP_WAIT_DATA;
+ }
+
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+
+ if (ack_or_nak_seen) {
gsp_next_packet(garmin_data_p);
}
@@ -676,7 +696,7 @@ static int gsp_send(struct garmin_data * garmin_data_p,
src = garmin_data_p->outbuffer+GARMIN_PKTHDR_LENGTH;
if (k > (GARMIN_PKTHDR_LENGTH-2)) {
/* can't add stuffing DLEs in place, move data to end
- of buffer ... */
+ of buffer ... */
dst = garmin_data_p->outbuffer+GPS_OUT_BUFSIZ-datalen;
memcpy(dst, src, datalen);
src = dst;
@@ -755,8 +775,9 @@ static void gsp_next_packet(struct garmin_data * garmin_data_p)
* or even incomplete packets
*/
static int nat_receive(struct garmin_data * garmin_data_p,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
__u8 * dest;
int offs = 0;
int result = count;
@@ -803,7 +824,9 @@ static int nat_receive(struct garmin_data * garmin_data_p,
/* if this was an abort-transfer command,
flush all queued data. */
if (isAbortTrfCmnd(garmin_data_p->inbuffer)) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_DROP_DATA;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
pkt_clear(garmin_data_p);
}
}
@@ -839,12 +862,15 @@ static void priv_status_resp(struct usb_serial_port *port)
static int process_resetdev_request(struct usb_serial_port *port)
{
+ unsigned long flags;
int status;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~(CLEAR_HALT_REQUIRED);
garmin_data_p->state = STATE_RESET;
garmin_data_p->serial_num = 0;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
usb_kill_urb (port->interrupt_in_urb);
dbg("%s - usb_reset_device", __FUNCTION__ );
@@ -862,6 +888,7 @@ static int process_resetdev_request(struct usb_serial_port *port)
*/
static int garmin_clear(struct garmin_data * garmin_data_p)
{
+ unsigned long flags;
int status = 0;
struct usb_serial_port *port = garmin_data_p->port;
@@ -875,8 +902,10 @@ static int garmin_clear(struct garmin_data * garmin_data_p)
/* flush all queued data */
pkt_clear(garmin_data_p);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->insize = 0;
garmin_data_p->outsize = 0;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
return status;
}
@@ -888,6 +917,7 @@ static int garmin_clear(struct garmin_data * garmin_data_p)
static int garmin_init_session(struct usb_serial_port *port)
{
+ unsigned long flags;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
int status = 0;
@@ -913,7 +943,9 @@ static int garmin_init_session(struct usb_serial_port *port)
if (status >= 0) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->ignorePkts++;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* not needed, but the win32 driver does it too ... */
status = garmin_write_bulk(port,
@@ -921,7 +953,9 @@ static int garmin_init_session(struct usb_serial_port *port)
sizeof(GARMIN_START_SESSION_REQ2));
if (status >= 0) {
status = 0;
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->ignorePkts++;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
}
}
@@ -935,6 +969,7 @@ static int garmin_init_session(struct usb_serial_port *port)
static int garmin_open (struct usb_serial_port *port, struct file *filp)
{
+ unsigned long flags;
int status = 0;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
@@ -948,9 +983,11 @@ static int garmin_open (struct usb_serial_port *port, struct file *filp)
if (port->tty)
port->tty->low_latency = 1;
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->mode = initial_mode;
garmin_data_p->count = 0;
garmin_data_p->flags = 0;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* shutdown any bulk reads that might be going on */
usb_kill_urb (port->write_urb);
@@ -994,8 +1031,9 @@ static void garmin_close (struct usb_serial_port *port, struct file * filp)
}
-static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void garmin_write_bulk_callback (struct urb *urb)
{
+ unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
@@ -1007,7 +1045,9 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= CLEAR_HALT_REQUIRED;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
usb_serial_port_softint(port);
@@ -1015,8 +1055,9 @@ static void garmin_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
static int garmin_write_bulk (struct usb_serial_port *port,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
struct urb *urb;
@@ -1026,7 +1067,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
dbg("%s - port %d, state %d", __FUNCTION__, port->number,
garmin_data_p->state);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_DROP_DATA;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
buffer = kmalloc (count, GFP_ATOMIC);
if (!buffer) {
@@ -1053,7 +1096,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
urb->transfer_flags |= URB_ZERO_PACKET;
if (GARMIN_LAYERID_APPL == getLayerId(buffer)) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
pkt_clear(garmin_data_p);
garmin_data_p->state = STATE_GSP_WAIT_DATA;
@@ -1087,8 +1132,9 @@ static int garmin_write_bulk (struct usb_serial_port *port,
static int garmin_write (struct usb_serial_port *port,
- const unsigned char *buf, int count)
+ const unsigned char *buf, int count)
{
+ unsigned long flags;
int pktid, pktsiz, len;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
__le32 *privpkt = (__le32 *)garmin_data_p->privpkt;
@@ -1139,7 +1185,9 @@ static int garmin_write (struct usb_serial_port *port,
break;
case PRIV_PKTID_RESET_REQ:
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_APP_REQ_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
break;
case PRIV_PKTID_SET_DEF_MODE:
@@ -1155,6 +1203,8 @@ static int garmin_write (struct usb_serial_port *port,
}
}
+ garmin_data_p->ignorePkts = 0;
+
if (garmin_data_p->mode == MODE_GARMIN_SERIAL) {
return gsp_receive(garmin_data_p, buf, count);
} else { /* MODE_NATIVE */
@@ -1177,10 +1227,10 @@ static int garmin_chars_in_buffer (struct usb_serial_port *port)
{
/*
* Report back the number of bytes currently in our input buffer.
- * Will this lock up the driver - the buffer contains an incomplete
- * package which will not be written to the device until it
- * has been completed ?
- */
+ * Will this lock up the driver - the buffer contains an incomplete
+ * package which will not be written to the device until it
+ * has been completed ?
+ */
//struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
//return garmin_data_p->insize;
return 0;
@@ -1190,6 +1240,8 @@ static int garmin_chars_in_buffer (struct usb_serial_port *port)
static void garmin_read_process(struct garmin_data * garmin_data_p,
unsigned char *data, unsigned data_length)
{
+ unsigned long flags;
+
if (garmin_data_p->flags & FLAGS_DROP_DATA) {
/* abort-transfer cmd is actice */
dbg("%s - pkt dropped", __FUNCTION__);
@@ -1200,11 +1252,14 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
if a reset is required or not when closing
the device */
if (0 == memcmp(data, GARMIN_APP_LAYER_REPLY,
- sizeof(GARMIN_APP_LAYER_REPLY)))
+ sizeof(GARMIN_APP_LAYER_REPLY))) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_APP_RESP_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
/* if throttling is active or postprecessing is required
- put the received data in th input queue, otherwise
+ put the received data in the input queue, otherwise
send it directly to the tty port */
if (garmin_data_p->flags & FLAGS_QUEUING) {
pkt_add(garmin_data_p, data, data_length);
@@ -1219,8 +1274,9 @@ static void garmin_read_process(struct garmin_data * garmin_data_p,
}
-static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void garmin_read_bulk_callback (struct urb *urb)
{
+ unsigned long flags;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
@@ -1245,26 +1301,38 @@ static void garmin_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
garmin_read_process(garmin_data_p, data, urb->actual_length);
- /* Continue trying to read until nothing more is received */
- if (urb->actual_length > 0) {
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- garmin_read_bulk_callback, port);
+ if (urb->actual_length == 0 &&
+ 0 != (garmin_data_p->flags & FLAGS_BULK_IN_RESTART)) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~FLAGS_BULK_IN_RESTART;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
if (status)
dev_err(&port->dev,
"%s - failed resubmitting read urb, error %d\n",
__FUNCTION__, status);
+ } else if (urb->actual_length > 0) {
+ /* Continue trying to read until nothing more is received */
+ if (0 == (garmin_data_p->flags & FLAGS_THROTTLED)) {
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, status);
+ }
+ } else {
+ dbg("%s - end of bulk data", __FUNCTION__);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags &= ~FLAGS_BULK_IN_ACTIVE;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
return;
}
-static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
+static void garmin_read_int_callback (struct urb *urb)
{
+ unsigned long flags;
int status;
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
@@ -1297,25 +1365,41 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
dbg("%s - bulk data available.", __FUNCTION__);
- /* bulk data available */
- usb_fill_bulk_urb (port->read_urb, serial->dev,
- usb_rcvbulkpipe (serial->dev,
- port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer,
- port->read_urb->transfer_buffer_length,
- garmin_read_bulk_callback, port);
- status = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (status) {
- dev_err(&port->dev,
- "%s - failed submitting read urb, error %d\n",
- __FUNCTION__, status);
+ if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+
+ /* bulk data available */
+ usb_fill_bulk_urb (port->read_urb, serial->dev,
+ usb_rcvbulkpipe (serial->dev,
+ port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer,
+ port->read_urb->transfer_buffer_length,
+ garmin_read_bulk_callback, port);
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status) {
+ dev_err(&port->dev,
+ "%s - failed submitting read urb, error %d\n",
+ __FUNCTION__, status);
+ } else {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_BULK_IN_ACTIVE;
+ /* do not send this packet to the user */
+ garmin_data_p->ignorePkts = 1;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
+ }
+ } else {
+ /* bulk-in transfer still active */
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
+ garmin_data_p->flags |= FLAGS_BULK_IN_RESTART;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
} else if (urb->actual_length == (4+sizeof(GARMIN_START_SESSION_REPLY))
&& 0 == memcmp(data, GARMIN_START_SESSION_REPLY,
sizeof(GARMIN_START_SESSION_REPLY))) {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_SESSION_REPLY1_SEEN;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* save the serial number */
garmin_data_p->serial_num
@@ -1330,7 +1414,9 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
ignore it. */
dbg("%s - pkt ignored (%d)",
__FUNCTION__, garmin_data_p->ignorePkts);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->ignorePkts--;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
} else {
garmin_read_process(garmin_data_p, data, urb->actual_length);
}
@@ -1351,18 +1437,20 @@ static void garmin_read_int_callback (struct urb *urb, struct pt_regs *regs)
*/
static int garmin_flush_queue(struct garmin_data * garmin_data_p)
{
+ unsigned long flags;
struct garmin_packet *pkt;
if ((garmin_data_p->flags & FLAGS_THROTTLED) == 0) {
pkt = pkt_pop(garmin_data_p);
if (pkt != NULL) {
-
send_to_tty(garmin_data_p->port, pkt->data, pkt->size);
kfree(pkt);
mod_timer(&garmin_data_p->timer, (1)+jiffies);
} else {
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_QUEUING;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
}
return 0;
@@ -1371,26 +1459,41 @@ static int garmin_flush_queue(struct garmin_data * garmin_data_p)
static void garmin_throttle (struct usb_serial_port *port)
{
+ unsigned long flags;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
dbg("%s - port %d", __FUNCTION__, port->number);
/* set flag, data received will be put into a queue
for later processing */
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags |= FLAGS_QUEUING|FLAGS_THROTTLED;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
}
static void garmin_unthrottle (struct usb_serial_port *port)
{
+ unsigned long flags;
struct garmin_data * garmin_data_p = usb_get_serial_port_data(port);
+ int status;
dbg("%s - port %d", __FUNCTION__, port->number);
+ spin_lock_irqsave(&garmin_data_p->lock, flags);
garmin_data_p->flags &= ~FLAGS_THROTTLED;
+ spin_unlock_irqrestore(&garmin_data_p->lock, flags);
/* in native mode send queued data to tty, in
serial mode nothing needs to be done here */
if (garmin_data_p->mode == MODE_NATIVE)
garmin_flush_queue(garmin_data_p);
+
+ if (0 != (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dev_err(&port->dev,
+ "%s - failed resubmitting read urb, error %d\n",
+ __FUNCTION__, status);
+ }
}
@@ -1420,11 +1523,12 @@ static int garmin_attach (struct usb_serial *serial)
dbg("%s", __FUNCTION__);
- garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL);
+ garmin_data_p = kmalloc (sizeof(struct garmin_data), GFP_KERNEL);
if (garmin_data_p == NULL) {
dev_err(&port->dev, "%s - Out of memory\n", __FUNCTION__);
return -ENOMEM;
}
+ memset (garmin_data_p, 0, sizeof(struct garmin_data));
init_timer(&garmin_data_p->timer);
spin_lock_init(&garmin_data_p->lock);
INIT_LIST_HEAD(&garmin_data_p->pktlist);
@@ -1459,10 +1563,10 @@ static void garmin_shutdown (struct usb_serial *serial)
/* All of the device info needed */
static struct usb_serial_driver garmin_device = {
.driver = {
- .owner = THIS_MODULE,
- .name = "garmin_gps",
+ .owner = THIS_MODULE,
+ .name = "garmin_gps",
},
- .description = "Garmin GPS usb/tty",
+ .description = "Garmin GPS usb/tty",
.id_table = id_table,
.num_interrupt_in = 1,
.num_bulk_in = 1,
@@ -1483,6 +1587,7 @@ static struct usb_serial_driver garmin_device = {
};
+
static int __init garmin_init (void)
{
int retval;
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 172713556393..36042937e77f 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -175,14 +175,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
@@ -248,7 +248,7 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
return (chars);
}
-void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+void usb_serial_generic_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct usb_serial *serial = port->serial;
@@ -287,7 +287,7 @@ void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *reg
}
EXPORT_SYMBOL_GPL(usb_serial_generic_read_bulk_callback);
-void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+void usb_serial_generic_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index c49976c3ad52..91bd3014ef1e 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -216,10 +216,10 @@ static int CmdUrbs = 0; /* Number of outstanding Command Write Urbs */
/* local function prototypes */
/* function prototypes for all URB callbacks */
-static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs);
-static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs);
-static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs);
-static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs);
+static void edge_interrupt_callback (struct urb *urb);
+static void edge_bulk_in_callback (struct urb *urb);
+static void edge_bulk_out_data_callback (struct urb *urb);
+static void edge_bulk_out_cmd_callback (struct urb *urb);
/* function prototypes for the usbserial callbacks */
static int edge_open (struct usb_serial_port *port, struct file *filp);
@@ -534,7 +534,7 @@ static void get_product_info(struct edgeport_serial *edge_serial)
* this is the callback function for when we have received data on the
* interrupt endpoint.
*****************************************************************************/
-static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_interrupt_callback (struct urb *urb)
{
struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
struct edgeport_port *edge_port;
@@ -631,7 +631,7 @@ exit:
* this is the callback function for when we have received data on the
* bulk in endpoint.
*****************************************************************************/
-static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_bulk_in_callback (struct urb *urb)
{
struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -687,7 +687,7 @@ static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
* this is the callback function for when we have finished sending serial data
* on the bulk out endpoint.
*****************************************************************************/
-static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_bulk_out_data_callback (struct urb *urb)
{
struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
struct tty_struct *tty;
@@ -718,7 +718,7 @@ static void edge_bulk_out_data_callback (struct urb *urb, struct pt_regs *regs)
* this is the callback function for when we have finished sending a command
* on the bulk out endpoint.
*****************************************************************************/
-static void edge_bulk_out_cmd_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_bulk_out_cmd_callback (struct urb *urb)
{
struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
struct tty_struct *tty;
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 17c5b1d2311a..ee0c921e1520 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -1697,7 +1697,7 @@ static void handle_new_lsr (struct edgeport_port *edge_port, int lsr_data, __u8
}
-static void edge_interrupt_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_interrupt_callback (struct urb *urb)
{
struct edgeport_serial *edge_serial = (struct edgeport_serial *)urb->context;
struct usb_serial_port *port;
@@ -1787,7 +1787,7 @@ exit:
__FUNCTION__, status);
}
-static void edge_bulk_in_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_bulk_in_callback (struct urb *urb)
{
struct edgeport_port *edge_port = (struct edgeport_port *)urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -1879,7 +1879,7 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty, unsigned c
tty_flip_buffer_push(tty);
}
-static void edge_bulk_out_callback (struct urb *urb, struct pt_regs *regs)
+static void edge_bulk_out_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct edgeport_port *edge_port = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 9840bade79f9..6238aff1e772 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -83,8 +83,8 @@ static int ipaq_write(struct usb_serial_port *port, const unsigned char *buf,
static int ipaq_write_bulk(struct usb_serial_port *port, const unsigned char *buf,
int count);
static void ipaq_write_gather(struct usb_serial_port *port);
-static void ipaq_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs);
+static void ipaq_read_bulk_callback (struct urb *urb);
+static void ipaq_write_bulk_callback(struct urb *urb);
static int ipaq_write_room(struct usb_serial_port *port);
static int ipaq_chars_in_buffer(struct usb_serial_port *port);
static void ipaq_destroy_lists(struct usb_serial_port *port);
@@ -479,6 +479,7 @@ static struct usb_device_id ipaq_id_table [] = {
{ USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */
{ USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */
{ USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */
+ { USB_DEVICE(0x0BB4, 0x0BCE) }, /* "High Tech Computer Corp" */
{ USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */
{ USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */
{ USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */
@@ -652,11 +653,6 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
port->bulk_out_size = port->write_urb->transfer_buffer_length = URBDATA_SIZE;
msleep(1000*initial_wait);
- /* Start reading from the device */
- usb_fill_bulk_urb(port->read_urb, serial->dev,
- usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
- port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
- ipaq_read_bulk_callback, port);
/*
* Send out control message observed in win98 sniffs. Not sure what
@@ -670,18 +666,31 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0), 0x22, 0x21,
0x1, 0, NULL, 0, 100);
- if (result == 0) {
- result = usb_submit_urb(port->read_urb, GFP_KERNEL);
- if (result) {
- err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
- goto error;
- }
- return 0;
- }
+ if (!result)
+ break;
+
msleep(1000);
}
- err("%s - failed doing control urb, error %d", __FUNCTION__, result);
- goto error;
+
+ if (!retries && result) {
+ err("%s - failed doing control urb, error %d", __FUNCTION__,
+ result);
+ goto error;
+ }
+
+ /* Start reading from the device */
+ usb_fill_bulk_urb(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+ port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+ ipaq_read_bulk_callback, port);
+
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (result) {
+ err("%s - failed submitting read urb, error %d", __FUNCTION__, result);
+ goto error;
+ }
+
+ return 0;
enomem:
result = -ENOMEM;
@@ -712,7 +721,7 @@ static void ipaq_close(struct usb_serial_port *port, struct file *filp)
/* info ("Bytes In = %d Bytes Out = %d", bytes_in, bytes_out); */
}
-static void ipaq_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void ipaq_read_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty;
@@ -850,7 +859,7 @@ static void ipaq_write_gather(struct usb_serial_port *port)
return;
}
-static void ipaq_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void ipaq_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct ipaq_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 87306cb6f9f5..2a4bb66691ad 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -161,7 +161,7 @@ static struct usb_driver usb_ipw_driver = {
static int debug;
-static void ipw_read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void ipw_read_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -367,7 +367,7 @@ static void ipw_close(struct usb_serial_port *port, struct file * filp)
usb_kill_urb(port->write_urb);
}
-static void ipw_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void ipw_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
@@ -394,14 +394,14 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
return 0;
}
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
count = min(count, port->bulk_out_size);
memcpy(port->bulk_out_buffer, buf, count);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 1738b0b6a376..331bf81556fc 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -105,8 +105,8 @@ static int ir_startup (struct usb_serial *serial);
static int ir_open (struct usb_serial_port *port, struct file *filep);
static void ir_close (struct usb_serial_port *port, struct file *filep);
static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int count);
-static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+static void ir_write_bulk_callback (struct urb *urb);
+static void ir_read_bulk_callback (struct urb *urb);
static void ir_set_termios (struct usb_serial_port *port, struct termios *old_termios);
static u8 ir_baud = 0;
@@ -342,14 +342,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
if (count == 0)
return 0;
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
transfer_buffer = port->write_urb->transfer_buffer;
transfer_size = min(count, port->bulk_out_size - 1);
@@ -388,7 +388,7 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
return result;
}
-static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void ir_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -410,7 +410,7 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
usb_serial_port_softint(port);
}
-static void ir_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void ir_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty;
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 015ad6cc1bbb..53be824eb1bf 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -412,7 +412,7 @@ static int keyspan_write(struct usb_serial_port *port,
return count - left;
}
-static void usa26_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_indat_callback(struct urb *urb)
{
int i, err;
int endpoint;
@@ -470,7 +470,7 @@ static void usa26_indat_callback(struct urb *urb, struct pt_regs *regs)
}
/* Outdat handling is common for all devices */
-static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa2x_outdat_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
@@ -483,13 +483,13 @@ static void usa2x_outdat_callback(struct urb *urb, struct pt_regs *regs)
usb_serial_port_softint(port);
}
-static void usa26_inack_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_inack_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa26_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_outcont_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
@@ -503,7 +503,7 @@ static void usa26_outcont_callback(struct urb *urb, struct pt_regs *regs)
}
}
-static void usa26_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_instat_callback(struct urb *urb)
{
unsigned char *data = urb->transfer_buffer;
struct keyspan_usa26_portStatusMessage *msg;
@@ -565,14 +565,14 @@ static void usa26_instat_callback(struct urb *urb, struct pt_regs *regs)
exit: ;
}
-static void usa26_glocont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa26_glocont_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_indat_callback(struct urb *urb)
{
int i, err;
struct usb_serial_port *port;
@@ -620,12 +620,12 @@ static void usa28_indat_callback(struct urb *urb, struct pt_regs *regs)
} while (urb->status != -EINPROGRESS);
}
-static void usa28_inack_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_inack_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa28_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_outcont_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
@@ -639,7 +639,7 @@ static void usa28_outcont_callback(struct urb *urb, struct pt_regs *regs)
}
}
-static void usa28_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_instat_callback(struct urb *urb)
{
int err;
unsigned char *data = urb->transfer_buffer;
@@ -700,13 +700,13 @@ static void usa28_instat_callback(struct urb *urb, struct pt_regs *regs)
exit: ;
}
-static void usa28_glocont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa28_glocont_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa49_glocont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_glocont_callback(struct urb *urb)
{
struct usb_serial *serial;
struct usb_serial_port *port;
@@ -730,7 +730,7 @@ static void usa49_glocont_callback(struct urb *urb, struct pt_regs *regs)
/* This is actually called glostat in the Keyspan
doco */
-static void usa49_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_instat_callback(struct urb *urb)
{
int err;
unsigned char *data = urb->transfer_buffer;
@@ -793,12 +793,12 @@ static void usa49_instat_callback(struct urb *urb, struct pt_regs *regs)
exit: ;
}
-static void usa49_inack_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_inack_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa49_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_indat_callback(struct urb *urb)
{
int i, err;
int endpoint;
@@ -851,12 +851,12 @@ static void usa49_indat_callback(struct urb *urb, struct pt_regs *regs)
}
/* not used, usa-49 doesn't have per-port control endpoints */
-static void usa49_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa49_outcont_callback(struct urb *urb)
{
dbg ("%s", __FUNCTION__);
}
-static void usa90_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa90_indat_callback(struct urb *urb)
{
int i, err;
int endpoint;
@@ -930,7 +930,7 @@ static void usa90_indat_callback(struct urb *urb, struct pt_regs *regs)
}
-static void usa90_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void usa90_instat_callback(struct urb *urb)
{
unsigned char *data = urb->transfer_buffer;
struct keyspan_usa90_portStatusMessage *msg;
@@ -981,7 +981,7 @@ exit:
;
}
-static void usa90_outcont_callback(struct urb *urb, struct pt_regs *regs)
+static void usa90_outcont_callback(struct urb *urb)
{
struct usb_serial_port *port;
struct keyspan_port_private *p_priv;
@@ -1277,7 +1277,7 @@ static int keyspan_fake_startup (struct usb_serial *serial)
/* Helper functions used by keyspan_setup_urbs */
static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
- void (*callback)(struct urb *, struct pt_regs *regs))
+ void (*callback)(struct urb *))
{
struct urb *urb;
@@ -1300,12 +1300,12 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
}
static struct callbacks {
- void (*instat_callback)(struct urb *, struct pt_regs *regs);
- void (*glocont_callback)(struct urb *, struct pt_regs *regs);
- void (*indat_callback)(struct urb *, struct pt_regs *regs);
- void (*outdat_callback)(struct urb *, struct pt_regs *regs);
- void (*inack_callback)(struct urb *, struct pt_regs *regs);
- void (*outcont_callback)(struct urb *, struct pt_regs *regs);
+ void (*instat_callback)(struct urb *);
+ void (*glocont_callback)(struct urb *);
+ void (*indat_callback)(struct urb *);
+ void (*outdat_callback)(struct urb *);
+ void (*inack_callback)(struct urb *);
+ void (*outcont_callback)(struct urb *);
} keyspan_callbacks[] = {
{
/* msg_usa26 callbacks */
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 49b8dc039d1f..909005107ea2 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -210,7 +210,7 @@ static void keyspan_pda_request_unthrottle( struct usb_serial *serial )
}
-static void keyspan_pda_rx_interrupt (struct urb *urb, struct pt_regs *regs)
+static void keyspan_pda_rx_interrupt (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct tty_struct *tty = port->tty;
@@ -518,13 +518,13 @@ static int keyspan_pda_write(struct usb_serial_port *port,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy || priv->tx_throttled) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
/* At this point the URB is in our control, nobody else can submit it
again (the only sudden transition was the one from EINPROGRESS to
@@ -601,7 +601,7 @@ exit:
}
-static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void keyspan_pda_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct keyspan_pda_private *priv;
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 2a2f3e2da055..17e205699c2b 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -80,11 +80,11 @@ static void klsi_105_close (struct usb_serial_port *port,
static int klsi_105_write (struct usb_serial_port *port,
const unsigned char *buf,
int count);
-static void klsi_105_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+static void klsi_105_write_bulk_callback (struct urb *urb);
static int klsi_105_chars_in_buffer (struct usb_serial_port *port);
static int klsi_105_write_room (struct usb_serial_port *port);
-static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
+static void klsi_105_read_bulk_callback (struct urb *urb);
static void klsi_105_set_termios (struct usb_serial_port *port,
struct termios * old);
static int klsi_105_ioctl (struct usb_serial_port *port,
@@ -556,7 +556,7 @@ exit:
return bytes_sent; /* that's how much we wrote */
} /* klsi_105_write */
-static void klsi_105_write_bulk_callback ( struct urb *urb, struct pt_regs *regs)
+static void klsi_105_write_bulk_callback ( struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -616,7 +616,7 @@ static int klsi_105_write_room (struct usb_serial_port *port)
-static void klsi_105_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void klsi_105_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct klsi_105_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index d50dce034958..ff03331e0bcf 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -80,8 +80,8 @@ static int kobil_ioctl(struct usb_serial_port *port, struct file *file,
static int kobil_tiocmget(struct usb_serial_port *port, struct file *file);
static int kobil_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
-static void kobil_read_int_callback( struct urb *urb, struct pt_regs *regs );
-static void kobil_write_callback( struct urb *purb, struct pt_regs *regs );
+static void kobil_read_int_callback( struct urb *urb );
+static void kobil_write_callback( struct urb *purb );
static struct usb_device_id id_table [] = {
@@ -360,7 +360,7 @@ static void kobil_close (struct usb_serial_port *port, struct file *filp)
}
-static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
+static void kobil_read_int_callback( struct urb *purb)
{
int result;
struct usb_serial_port *port = (struct usb_serial_port *) purb->context;
@@ -405,7 +405,7 @@ static void kobil_read_int_callback( struct urb *purb, struct pt_regs *regs)
}
-static void kobil_write_callback( struct urb *purb, struct pt_regs *regs )
+static void kobil_write_callback( struct urb *purb )
{
}
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index f4d4305c2c02..b7582cc496dc 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -96,7 +96,7 @@ static int mct_u232_open (struct usb_serial_port *port,
struct file *filp);
static void mct_u232_close (struct usb_serial_port *port,
struct file *filp);
-static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs);
+static void mct_u232_read_int_callback (struct urb *urb);
static void mct_u232_set_termios (struct usb_serial_port *port,
struct termios * old);
static int mct_u232_ioctl (struct usb_serial_port *port,
@@ -466,7 +466,7 @@ static void mct_u232_close (struct usb_serial_port *port, struct file *filp)
} /* mct_u232_close */
-static void mct_u232_read_int_callback (struct urb *urb, struct pt_regs *regs)
+static void mct_u232_read_int_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct mct_u232_private *priv = usb_get_serial_port_data(port);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
new file mode 100644
index 000000000000..82cd15b894b0
--- /dev/null
+++ b/drivers/usb/serial/mos7720.c
@@ -0,0 +1,1683 @@
+/*
+ * mos7720.c
+ * Controls the Moschip 7720 usb to dual port serial convertor
+ *
+ * Copyright 2006 Moschip Semiconductor Tech. Ltd.
+ *
+ * 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, version 2 of the License.
+ *
+ * Developed by:
+ * VijayaKumar.G.N. <vijaykumar@aspirecom.net>
+ * AjayKumar <ajay@aspirecom.net>
+ * Gurudeva.N. <gurudev@aspirecom.net>
+ *
+ * Cleaned up from the original by:
+ * Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * Originally based on drivers/usb/serial/io_edgeport.c which is:
+ * Copyright (C) 2000 Inside Out Networks, All rights reserved.
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.0.0.4F"
+#define DRIVER_AUTHOR "Aspire Communications pvt Ltd."
+#define DRIVER_DESC "Moschip USB Serial Driver"
+
+/* default urb timeout */
+#define MOS_WDR_TIMEOUT (HZ * 5)
+
+#define MOS_PORT1 0x0200
+#define MOS_PORT2 0x0300
+#define MOS_VENREG 0x0000
+#define MOS_MAX_PORT 0x02
+#define MOS_WRITE 0x0E
+#define MOS_READ 0x0D
+
+/* Interrupt Rotinue Defines */
+#define SERIAL_IIR_RLS 0x06
+#define SERIAL_IIR_RDA 0x04
+#define SERIAL_IIR_CTI 0x0c
+#define SERIAL_IIR_THR 0x02
+#define SERIAL_IIR_MS 0x00
+
+#define NUM_URBS 16 /* URB Count */
+#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
+
+/* This structure holds all of the local port information */
+struct moschip_port
+{
+ __u8 shadowLCR; /* last LCR value received */
+ __u8 shadowMCR; /* last MCR value received */
+ __u8 shadowMSR; /* last MSR value received */
+ char open;
+ struct async_icount icount;
+ struct usb_serial_port *port; /* loop back to the owner */
+ struct urb *write_urb_pool[NUM_URBS];
+};
+
+/* This structure holds all of the individual serial device information */
+struct moschip_serial
+{
+ int interrupt_started;
+};
+
+static int debug;
+
+#define USB_VENDOR_ID_MOSCHIP 0x9710
+#define MOSCHIP_DEVICE_ID_7720 0x7720
+#define MOSCHIP_DEVICE_ID_7715 0x7715
+
+static struct usb_device_id moschip_port_id_table [] = {
+ { USB_DEVICE(USB_VENDOR_ID_MOSCHIP,MOSCHIP_DEVICE_ID_7720) },
+ { } /* terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
+
+
+/*
+ * mos7720_interrupt_callback
+ * this is the callback function for when we have received data on the
+ * interrupt endpoint.
+ */
+static void mos7720_interrupt_callback(struct urb *urb)
+{
+ int result;
+ int length;
+ __u32 *data;
+ unsigned int status;
+ __u8 sp1;
+ __u8 sp2;
+ __u8 st;
+
+ dbg("%s"," : Entering\n");
+
+ if (!urb) {
+ dbg("%s","Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
+ goto exit;
+ }
+
+ length = urb->actual_length;
+ data = urb->transfer_buffer;
+
+ /* Moschip get 4 bytes
+ * Byte 1 IIR Port 1 (port.number is 0)
+ * Byte 2 IIR Port 2 (port.number is 1)
+ * Byte 3 --------------
+ * Byte 4 FIFO status for both */
+ if (length && length > 4) {
+ dbg("Wrong data !!!");
+ return;
+ }
+
+ status = *data;
+
+ sp1 = (status & 0xff000000)>>24;
+ sp2 = (status & 0x00ff0000)>>16;
+ st = status & 0x000000ff;
+
+ if ((sp1 & 0x01) || (sp2 & 0x01)) {
+ /* No Interrupt Pending in both the ports */
+ dbg("No Interrupt !!!");
+ } else {
+ switch (sp1 & 0x0f) {
+ case SERIAL_IIR_RLS:
+ dbg("Serial Port 1: Receiver status error or address "
+ "bit detected in 9-bit mode\n");
+ break;
+ case SERIAL_IIR_CTI:
+ dbg("Serial Port 1: Receiver time out");
+ break;
+ case SERIAL_IIR_MS:
+ dbg("Serial Port 1: Modem status change");
+ break;
+ }
+
+ switch (sp2 & 0x0f) {
+ case SERIAL_IIR_RLS:
+ dbg("Serial Port 2: Receiver status error or address "
+ "bit detected in 9-bit mode");
+ break;
+ case SERIAL_IIR_CTI:
+ dbg("Serial Port 2: Receiver time out");
+ break;
+ case SERIAL_IIR_MS:
+ dbg("Serial Port 2: Modem status change");
+ break;
+ }
+ }
+
+exit:
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_err(&urb->dev->dev,
+ "%s - Error %d submitting control urb\n",
+ __FUNCTION__, result);
+ return;
+}
+
+/*
+ * mos7720_bulk_in_callback
+ * this is the callback function for when we have received data on the
+ * bulk in endpoint.
+ */
+static void mos7720_bulk_in_callback(struct urb *urb)
+{
+ int status;
+ unsigned char *data ;
+ struct usb_serial_port *port;
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d",urb->status);
+ return;
+ }
+
+ mos7720_port = urb->context;
+ if (!mos7720_port) {
+ dbg("%s","NULL mos7720_port pointer \n");
+ return ;
+ }
+
+ port = mos7720_port->port;
+
+ dbg("Entering...%s", __FUNCTION__);
+
+ data = urb->transfer_buffer;
+
+ tty = port->tty;
+ if (tty && urb->actual_length) {
+ tty_buffer_request_room(tty, urb->actual_length);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
+ }
+
+ if (!port->read_urb) {
+ dbg("URB KILLED !!!");
+ return;
+ }
+
+ if (port->read_urb->status != -EINPROGRESS) {
+ port->read_urb->dev = port->serial->dev;
+
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+}
+
+/*
+ * mos7720_bulk_out_data_callback
+ * this is the callback function for when we have finished sending serial
+ * data on the bulk out endpoint.
+ */
+static void mos7720_bulk_out_data_callback(struct urb *urb)
+{
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received:%d", urb->status);
+ return;
+ }
+
+ mos7720_port = urb->context;
+ if (!mos7720_port) {
+ dbg("NULL mos7720_port pointer");
+ return ;
+ }
+
+ dbg("Entering .........");
+
+ tty = mos7720_port->port->tty;
+
+ if (tty && mos7720_port->open) {
+ /* let the tty driver wakeup if it has a special *
+ * write_wakeup function */
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+
+ /* tell the tty driver that something has changed */
+ wake_up_interruptible(&tty->write_wait);
+ }
+
+ /* schedule_work(&mos7720_port->port->work); */
+}
+
+/*
+ * send_mos_cmd
+ * this function will be used for sending command to device
+ */
+static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
+ __u16 index, void *data)
+{
+ int status;
+ unsigned int pipe;
+ u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+ __u8 requesttype;
+ __u16 size = 0x0000;
+
+ if (value < MOS_MAX_PORT) {
+ if (product == MOSCHIP_DEVICE_ID_7715) {
+ value = value*0x100+0x100;
+ } else {
+ value = value*0x100+0x200;
+ }
+ } else {
+ value = 0x0000;
+ if ((product == MOSCHIP_DEVICE_ID_7715) &&
+ (index != 0x08)) {
+ dbg("serial->product== MOSCHIP_DEVICE_ID_7715");
+ //index = 0x01 ;
+ }
+ }
+
+ if (request == MOS_WRITE) {
+ request = (__u8)MOS_WRITE;
+ requesttype = (__u8)0x40;
+ value = value + (__u16)*((unsigned char *)data);
+ data = NULL;
+ pipe = usb_sndctrlpipe(serial->dev, 0);
+ } else {
+ request = (__u8)MOS_READ;
+ requesttype = (__u8)0xC0;
+ size = 0x01;
+ pipe = usb_rcvctrlpipe(serial->dev,0);
+ }
+
+ status = usb_control_msg(serial->dev, pipe, request, requesttype,
+ value, index, data, size, MOS_WDR_TIMEOUT);
+
+ if (status < 0)
+ dbg("Command Write failed Value %x index %x\n",value,index);
+
+ return status;
+}
+
+static int mos7720_open(struct usb_serial_port *port, struct file * filp)
+{
+ struct usb_serial *serial;
+ struct usb_serial_port *port0;
+ struct urb *urb;
+ struct moschip_serial *mos7720_serial;
+ struct moschip_port *mos7720_port;
+ int response;
+ int port_number;
+ char data;
+ int j;
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return -ENODEV;
+
+ port0 = serial->port[0];
+
+ mos7720_serial = usb_get_serial_data(serial);
+
+ if (mos7720_serial == NULL || port0 == NULL)
+ return -ENODEV;
+
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ /* Initialising the write urb pool */
+ for (j = 0; j < NUM_URBS; ++j) {
+ urb = usb_alloc_urb(0,SLAB_ATOMIC);
+ mos7720_port->write_urb_pool[j] = urb;
+
+ if (urb == NULL) {
+ err("No more urbs???");
+ continue;
+ }
+
+ urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("%s-out of memory for urb buffers.", __FUNCTION__);
+ continue;
+ }
+ }
+
+ /* Initialize MCS7720 -- Write Init values to corresponding Registers
+ *
+ * Register Index
+ * 1 : IER
+ * 2 : FCR
+ * 3 : LCR
+ * 4 : MCR
+ *
+ * 0x08 : SP1/2 Control Reg
+ */
+ port_number = port->number - port->serial->minor;
+ send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
+ dbg("SS::%p LSR:%x\n",mos7720_port, data);
+
+ dbg("Check:Sending Command ..........");
+
+ data = 0x02;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x01, &data);
+ data = 0x02;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x02, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+
+ data = 0xCF;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+ data = 0x03;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+ data = 0x0b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x0b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+/* data = 0x00;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, port_number + 1, &data);
+ data = 0x03;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
+ data = 0x00;
+ send_mos_cmd(port->serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1, &data);
+*/
+ data = 0x00;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+
+ data = data | (port->number - port->serial->minor + 1);
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+ data = 0x83;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x03;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+
+//Matrix
+
+ /* force low_latency on so that our tty_push actually forces *
+ * the data through,otherwise it is scheduled, and with *
+ * high data rates (like with OHCI) data can get lost. */
+
+ if (port->tty)
+ port->tty->low_latency = 1;
+
+ /* see if we've set up our endpoint info yet *
+ * (can't set it up in mos7720_startup as the *
+ * structures were not set up at that time.) */
+ if (!mos7720_serial->interrupt_started) {
+ dbg("Interrupt buffer NULL !!!");
+
+ /* not set up yet, so do it now */
+ mos7720_serial->interrupt_started = 1;
+
+ dbg("To Submit URB !!!");
+
+ /* set up our interrupt urb */
+ usb_fill_int_urb(port0->interrupt_in_urb, serial->dev,
+ usb_rcvintpipe(serial->dev,
+ port->interrupt_in_endpointAddress),
+ port0->interrupt_in_buffer,
+ port0->interrupt_in_urb->transfer_buffer_length,
+ mos7720_interrupt_callback, mos7720_port,
+ port0->interrupt_in_urb->interval);
+
+ /* start interrupt read for this mos7720 this interrupt *
+ * will continue as long as the mos7720 is connected */
+ dbg("Submit URB over !!!");
+ response = usb_submit_urb(port0->interrupt_in_urb, GFP_KERNEL);
+ if (response)
+ dev_err(&port->dev,
+ "%s - Error %d submitting control urb",
+ __FUNCTION__, response);
+ }
+
+ /* set up our bulk in urb */
+ usb_fill_bulk_urb(port->read_urb, serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->bulk_in_buffer,
+ port->read_urb->transfer_buffer_length,
+ mos7720_bulk_in_callback, mos7720_port);
+ response = usb_submit_urb(port->read_urb, GFP_KERNEL);
+ if (response)
+ dev_err(&port->dev,
+ "%s - Error %d submitting read urb", __FUNCTION__, response);
+
+ /* initialize our icount structure */
+ memset(&(mos7720_port->icount), 0x00, sizeof(mos7720_port->icount));
+
+ /* initialize our port settings */
+ mos7720_port->shadowMCR = UART_MCR_OUT2; /* Must set to enable ints! */
+
+ /* send a open port command */
+ mos7720_port->open = 1;
+
+ return 0;
+}
+
+/*
+ * mos7720_chars_in_buffer
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we currently have outstanding in the port (data that has
+ * been written, but hasn't made it out the port yet)
+ * If successful, we return the number of bytes left to be written in the
+ * system,
+ * Otherwise we return a negative error number.
+ */
+static int mos7720_chars_in_buffer(struct usb_serial_port *port)
+{
+ int i;
+ int chars = 0;
+ struct moschip_port *mos7720_port;
+
+ dbg("%s:entering ...........", __FUNCTION__);
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL) {
+ dbg("%s:leaving ...........", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7720_port->write_urb_pool[i]->status == -EINPROGRESS)
+ chars += URB_TRANSFER_BUFFER_SIZE;
+ }
+ dbg("%s - returns %d", __FUNCTION__, chars);
+ return chars;
+}
+
+static void mos7720_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial;
+ struct moschip_port *mos7720_port;
+ char data;
+ int j;
+
+ dbg("mos7720_close:entering...");
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return;
+
+ for (j = 0; j < NUM_URBS; ++j)
+ usb_kill_urb(mos7720_port->write_urb_pool[j]);
+
+ /* Freeing Write URBs */
+ for (j = 0; j < NUM_URBS; ++j) {
+ if (mos7720_port->write_urb_pool[j]) {
+ kfree(mos7720_port->write_urb_pool[j]->transfer_buffer);
+ usb_free_urb(mos7720_port->write_urb_pool[j]);
+ }
+ }
+
+ /* While closing port, shutdown all bulk read, write *
+ * and interrupt read if they exists */
+ if (serial->dev) {
+ dbg("Shutdown bulk write");
+ usb_kill_urb(port->write_urb);
+ dbg("Shutdown bulk read");
+ usb_kill_urb(port->read_urb);
+ }
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x04, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x01, &data);
+
+ mos7720_port->open = 0;
+
+ dbg("Leaving %s", __FUNCTION__);
+}
+
+static void mos7720_break(struct usb_serial_port *port, int break_state)
+{
+ unsigned char data;
+ struct usb_serial *serial;
+ struct moschip_port *mos7720_port;
+
+ dbg("Entering %s", __FUNCTION__);
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return;
+
+ if (break_state == -1)
+ data = mos7720_port->shadowLCR | UART_LCR_SBC;
+ else
+ data = mos7720_port->shadowLCR & ~UART_LCR_SBC;
+
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port->number - port->serial->minor,
+ 0x03, &data);
+
+ return;
+}
+
+/*
+ * mos7720_write_room
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we can accept for a specific port.
+ * If successful, we return the amount of room that we have for this port
+ * Otherwise we return a negative error number.
+ */
+static int mos7720_write_room(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7720_port;
+ int room = 0;
+ int i;
+
+ dbg("%s:entering ...........", __FUNCTION__);
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL) {
+ dbg("%s:leaving ...........", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS)
+ room += URB_TRANSFER_BUFFER_SIZE;
+ }
+
+ dbg("%s - returns %d", __FUNCTION__, room);
+ return room;
+}
+
+static int mos7720_write(struct usb_serial_port *port,
+ const unsigned char *data, int count)
+{
+ int status;
+ int i;
+ int bytes_sent = 0;
+ int transfer_size;
+
+ struct moschip_port *mos7720_port;
+ struct usb_serial *serial;
+ struct urb *urb;
+ const unsigned char *current_position = data;
+
+ dbg("%s:entering ...........", __FUNCTION__);
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL) {
+ dbg("mos7720_port is NULL");
+ return -ENODEV;
+ }
+
+ /* try to find a free urb in the list */
+ urb = NULL;
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7720_port->write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = mos7720_port->write_urb_pool[i];
+ dbg("URB:%d",i);
+ break;
+ }
+ }
+
+ if (urb == NULL) {
+ dbg("%s - no more free urbs", __FUNCTION__);
+ goto exit;
+ }
+
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (urb->transfer_buffer == NULL) {
+ err("%s no more kernel memory...", __FUNCTION__);
+ goto exit;
+ }
+ }
+ transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
+
+ memcpy(urb->transfer_buffer, current_position, transfer_size);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, transfer_size,
+ urb->transfer_buffer);
+
+ /* fill urb with data and submit */
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ urb->transfer_buffer, transfer_size,
+ mos7720_bulk_out_data_callback, mos7720_port);
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb,GFP_ATOMIC);
+ if (status) {
+ err("%s - usb_submit_urb(write bulk) failed with status = %d",
+ __FUNCTION__, status);
+ bytes_sent = status;
+ goto exit;
+ }
+ bytes_sent = transfer_size;
+
+exit:
+ return bytes_sent;
+}
+
+static void mos7720_throttle(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+ int status;
+
+ dbg("%s- port %d\n", __FUNCTION__, port->number);
+
+ mos7720_port = usb_get_serial_port_data(port);
+
+ if (mos7720_port == NULL)
+ return;
+
+ if (!mos7720_port->open) {
+ dbg("port not opened");
+ return;
+ }
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the stop character */
+ if (I_IXOFF(tty)) {
+ unsigned char stop_char = STOP_CHAR(tty);
+ status = mos7720_write(port, &stop_char, 1);
+ if (status <= 0)
+ return;
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7720_port->shadowMCR &= ~UART_MCR_RTS;
+ status = send_mos_cmd(port->serial, MOS_WRITE,
+ port->number - port->serial->minor,
+ UART_MCR, &mos7720_port->shadowMCR);
+ if (status != 0)
+ return;
+ }
+}
+
+static void mos7720_unthrottle(struct usb_serial_port *port)
+{
+ struct tty_struct *tty;
+ int status;
+ struct moschip_port *mos7720_port = usb_get_serial_port_data(port);
+
+ if (mos7720_port == NULL)
+ return;
+
+ if (!mos7720_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the start character */
+ if (I_IXOFF(tty)) {
+ unsigned char start_char = START_CHAR(tty);
+ status = mos7720_write(port, &start_char, 1);
+ if (status <= 0)
+ return;
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7720_port->shadowMCR |= UART_MCR_RTS;
+ status = send_mos_cmd(port->serial, MOS_WRITE,
+ port->number - port->serial->minor,
+ UART_MCR, &mos7720_port->shadowMCR);
+ if (status != 0)
+ return;
+ }
+}
+
+static int set_higher_rates(struct moschip_port *mos7720_port,
+ unsigned int baud)
+{
+ unsigned char data;
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+ int port_number;
+
+ if (mos7720_port == NULL)
+ return -EINVAL;
+
+ port = mos7720_port->port;
+ serial = port->serial;
+
+ /***********************************************
+ * Init Sequence for higher rates
+ ***********************************************/
+ dbg("Sending Setting Commands ..........");
+ port_number = port->number - port->serial->minor;
+
+ data = 0x000;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+ data = 0x000;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x02, &data);
+ data = 0x0CF;
+ send_mos_cmd(serial, MOS_WRITE, port->number, 0x02, &data);
+ data = 0x00b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x00b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ data = 0x000;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+ data = 0x000;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+
+ /***********************************************
+ * Set for higher rates *
+ ***********************************************/
+
+ data = baud * 0x10;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, port_number + 1,&data);
+
+ data = 0x003;
+ send_mos_cmd(serial, MOS_READ, MOS_MAX_PORT, 0x08, &data);
+ data = 0x003;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT, 0x08, &data);
+
+ data = 0x02b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x02b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ /***********************************************
+ * Set DLL/DLM
+ ***********************************************/
+
+ data = mos7720_port->shadowLCR | UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+
+ data = 0x001; /* DLL */
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x00, &data);
+ data = 0x000; /* DLM */
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x01, &data);
+
+ data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x03, &data);
+
+ return 0;
+}
+
+/* baud rate information */
+struct divisor_table_entry
+{
+ __u32 baudrate;
+ __u16 divisor;
+};
+
+/* Define table of divisors for moschip 7720 hardware *
+ * These assume a 3.6864MHz crystal, the standard /16, and *
+ * MCR.7 = 0. */
+static struct divisor_table_entry divisor_table[] = {
+ { 50, 2304},
+ { 110, 1047}, /* 2094.545455 => 230450 => .0217 % over */
+ { 134, 857}, /* 1713.011152 => 230398.5 => .00065% under */
+ { 150, 768},
+ { 300, 384},
+ { 600, 192},
+ { 1200, 96},
+ { 1800, 64},
+ { 2400, 48},
+ { 4800, 24},
+ { 7200, 16},
+ { 9600, 12},
+ { 19200, 6},
+ { 38400, 3},
+ { 57600, 2},
+ { 115200, 1},
+};
+
+/*****************************************************************************
+ * calc_baud_rate_divisor
+ * this function calculates the proper baud rate divisor for the specified
+ * baud rate.
+ *****************************************************************************/
+static int calc_baud_rate_divisor(int baudrate, int *divisor)
+{
+ int i;
+ __u16 custom;
+ __u16 round1;
+ __u16 round;
+
+
+ dbg("%s - %d", __FUNCTION__, baudrate);
+
+ for (i = 0; i < ARRAY_SIZE(divisor_table); i++) {
+ if (divisor_table[i].baudrate == baudrate) {
+ *divisor = divisor_table[i].divisor;
+ return 0;
+ }
+ }
+
+ /* After trying for all the standard baud rates *
+ * Try calculating the divisor for this baud rate */
+ if (baudrate > 75 && baudrate < 230400) {
+ /* get the divisor */
+ custom = (__u16)(230400L / baudrate);
+
+ /* Check for round off */
+ round1 = (__u16)(2304000L / baudrate);
+ round = (__u16)(round1 - (custom * 10));
+ if (round > 4)
+ custom++;
+ *divisor = custom;
+
+ dbg("Baud %d = %d",baudrate, custom);
+ return 0;
+ }
+
+ dbg("Baud calculation Failed...");
+ return -EINVAL;
+}
+
+/*
+ * send_cmd_write_baud_rate
+ * this function sends the proper command to change the baud rate of the
+ * specified port.
+ */
+static int send_cmd_write_baud_rate(struct moschip_port *mos7720_port,
+ int baudrate)
+{
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+ int divisor;
+ int status;
+ unsigned char data;
+ unsigned char number;
+
+ if (mos7720_port == NULL)
+ return -1;
+
+ port = mos7720_port->port;
+ serial = port->serial;
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ number = port->number - port->serial->minor;
+ dbg("%s - port = %d, baud = %d", __FUNCTION__, port->number, baudrate);
+
+ /* Calculate the Divisor */
+ status = calc_baud_rate_divisor(baudrate, &divisor);
+ if (status) {
+ err("%s - bad baud rate", __FUNCTION__);
+ return status;
+ }
+
+ /* Enable access to divisor latch */
+ data = mos7720_port->shadowLCR | UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, number, UART_LCR, &data);
+
+ /* Write the divisor */
+ data = ((unsigned char)(divisor & 0xff));
+ send_mos_cmd(serial, MOS_WRITE, number, 0x00, &data);
+
+ data = ((unsigned char)((divisor & 0xff00) >> 8));
+ send_mos_cmd(serial, MOS_WRITE, number, 0x01, &data);
+
+ /* Disable access to divisor latch */
+ data = mos7720_port->shadowLCR & ~UART_LCR_DLAB;
+ mos7720_port->shadowLCR = data;
+ send_mos_cmd(serial, MOS_WRITE, number, 0x03, &data);
+
+ return status;
+}
+
+/*
+ * change_port_settings
+ * This routine is called to set the UART on the device to match
+ * the specified new settings.
+ */
+static void change_port_settings(struct moschip_port *mos7720_port,
+ struct termios *old_termios)
+{
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+ struct tty_struct *tty;
+ int baud;
+ unsigned cflag;
+ unsigned iflag;
+ __u8 mask = 0xff;
+ __u8 lData;
+ __u8 lParity;
+ __u8 lStop;
+ int status;
+ int port_number;
+ char data;
+
+ if (mos7720_port == NULL)
+ return ;
+
+ port = mos7720_port->port;
+ serial = port->serial;
+ port_number = port->number - port->serial->minor;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (!mos7720_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ tty = mos7720_port->port->tty;
+
+ if ((!tty) || (!tty->termios)) {
+ dbg("%s - no tty structures", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ lData = UART_LCR_WLEN8;
+ lStop = 0x00; /* 1 stop bit */
+ lParity = 0x00; /* No parity */
+
+ cflag = tty->termios->c_cflag;
+ iflag = tty->termios->c_iflag;
+
+ /* Change the number of bits */
+ switch (cflag & CSIZE) {
+ case CS5:
+ lData = UART_LCR_WLEN5;
+ mask = 0x1f;
+ break;
+
+ case CS6:
+ lData = UART_LCR_WLEN6;
+ mask = 0x3f;
+ break;
+
+ case CS7:
+ lData = UART_LCR_WLEN7;
+ mask = 0x7f;
+ break;
+ default:
+ case CS8:
+ lData = UART_LCR_WLEN8;
+ break;
+ }
+
+ /* Change the Parity bit */
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ lParity = UART_LCR_PARITY;
+ dbg("%s - parity = odd", __FUNCTION__);
+ } else {
+ lParity = (UART_LCR_EPAR | UART_LCR_PARITY);
+ dbg("%s - parity = even", __FUNCTION__);
+ }
+
+ } else {
+ dbg("%s - parity = none", __FUNCTION__);
+ }
+
+ if (cflag & CMSPAR)
+ lParity = lParity | 0x20;
+
+ /* Change the Stop bit */
+ if (cflag & CSTOPB) {
+ lStop = UART_LCR_STOP;
+ dbg("%s - stop bits = 2", __FUNCTION__);
+ } else {
+ lStop = 0x00;
+ dbg("%s - stop bits = 1", __FUNCTION__);
+ }
+
+#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
+#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
+#define LCR_PAR_MASK 0x38 /* Mask for parity field */
+
+ /* Update the LCR with the correct value */
+ mos7720_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
+ mos7720_port->shadowLCR |= (lData | lParity | lStop);
+
+
+ /* Disable Interrupts */
+ data = 0x00;
+ send_mos_cmd(serial,MOS_WRITE,port->number - port->serial->minor, UART_IER, &data);
+
+ data = 0x00;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
+
+ data = 0xcf;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_FCR, &data);
+
+ /* Send the updated LCR value to the mos7720 */
+ data = mos7720_port->shadowLCR;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_LCR, &data);
+
+ data = 0x00b;
+ mos7720_port->shadowMCR = data;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+ data = 0x00b;
+ send_mos_cmd(serial, MOS_WRITE, port_number, 0x04, &data);
+
+ /* set up the MCR register and send it to the mos7720 */
+ mos7720_port->shadowMCR = UART_MCR_OUT2;
+ if (cflag & CBAUD)
+ mos7720_port->shadowMCR |= (UART_MCR_DTR | UART_MCR_RTS);
+
+ if (cflag & CRTSCTS) {
+ mos7720_port->shadowMCR |= (UART_MCR_XONANY);
+
+ /* To set hardware flow control to the specified *
+ * serial port, in SP1/2_CONTROL_REG */
+ if (port->number) {
+ data = 0x001;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
+ 0x08, &data);
+ } else {
+ data = 0x002;
+ send_mos_cmd(serial, MOS_WRITE, MOS_MAX_PORT,
+ 0x08, &data);
+ }
+ } else {
+ mos7720_port->shadowMCR &= ~(UART_MCR_XONANY);
+ }
+
+ data = mos7720_port->shadowMCR;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_MCR, &data);
+
+ /* Determine divisor based on baud rate */
+ baud = tty_get_baud_rate(tty);
+ if (!baud) {
+ /* pick a default, any default... */
+ dbg("Picked default baud...");
+ baud = 9600;
+ }
+
+ if (baud >= 230400) {
+ set_higher_rates(mos7720_port, baud);
+ /* Enable Interrupts */
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+ return;
+ }
+
+ dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ status = send_cmd_write_baud_rate(mos7720_port, baud);
+
+ /* Enable Interrupts */
+ data = 0x0c;
+ send_mos_cmd(serial, MOS_WRITE, port_number, UART_IER, &data);
+
+ if (port->read_urb->status != -EINPROGRESS) {
+ port->read_urb->dev = serial->dev;
+
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ return;
+}
+
+/*
+ * mos7720_set_termios
+ * this function is called by the tty driver when it wants to change the
+ * termios structure.
+ */
+static void mos7720_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ int status;
+ unsigned int cflag;
+ struct usb_serial *serial;
+ struct moschip_port *mos7720_port;
+ struct tty_struct *tty;
+
+ serial = port->serial;
+
+ mos7720_port = usb_get_serial_port_data(port);
+
+ if (mos7720_port == NULL)
+ return;
+
+ tty = port->tty;
+
+ if (!port->tty || !port->tty->termios) {
+ dbg("%s - no tty or termios", __FUNCTION__);
+ return;
+ }
+
+ if (!mos7720_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s\n","setting termios - ASPIRE");
+
+ cflag = tty->termios->c_cflag;
+
+ if (!cflag) {
+ printk("%s %s\n",__FUNCTION__,"cflag is NULL");
+ return;
+ }
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("Nothing to change");
+ return;
+ }
+ }
+
+ dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ tty->termios->c_cflag,
+ RELEVANT_IFLAG(tty->termios->c_iflag));
+
+ if (old_termios)
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag,
+ RELEVANT_IFLAG(old_termios->c_iflag));
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* change the port settings to the new ones specified */
+ change_port_settings(mos7720_port, old_termios);
+
+ if(!port->read_urb) {
+ dbg("%s","URB KILLED !!!!!\n");
+ return;
+ }
+
+ if(port->read_urb->status != -EINPROGRESS) {
+ port->read_urb->dev = serial->dev;
+ status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
+ if (status)
+ dbg("usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ return;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ */
+static int get_lsr_info(struct moschip_port *mos7720_port,
+ unsigned int __user *value)
+{
+ int count;
+ unsigned int result = 0;
+
+ count = mos7720_chars_in_buffer(mos7720_port->port);
+ if (count == 0) {
+ dbg("%s -- Empty", __FUNCTION__);
+ result = TIOCSER_TEMT;
+ }
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * get_number_bytes_avail - get number of bytes available
+ *
+ * Purpose: Let user call ioctl to get the count of number of bytes available.
+ */
+static int get_number_bytes_avail(struct moschip_port *mos7720_port,
+ unsigned int __user *value)
+{
+ unsigned int result = 0;
+ struct tty_struct *tty = mos7720_port->port->tty;
+
+ if (!tty)
+ return -ENOIOCTLCMD;
+
+ result = tty->read_cnt;
+
+ dbg("%s(%d) = %d", __FUNCTION__, mos7720_port->port->number, result);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+
+ return -ENOIOCTLCMD;
+}
+
+static int set_modem_info(struct moschip_port *mos7720_port, unsigned int cmd,
+ unsigned int __user *value)
+{
+ unsigned int mcr ;
+ unsigned int arg;
+ unsigned char data;
+
+ struct usb_serial_port *port;
+
+ if (mos7720_port == NULL)
+ return -1;
+
+ port = (struct usb_serial_port*)mos7720_port->port;
+ mcr = mos7720_port->shadowMCR;
+
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ mcr |= UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr |= UART_MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr |= UART_MCR_LOOP;
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ mcr &= ~UART_MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr &= ~UART_MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr &= ~UART_MCR_LOOP;
+ break;
+
+ case TIOCMSET:
+ /* turn off the RTS and DTR and LOOPBACK
+ * and then only turn on what was asked to */
+ mcr &= ~(UART_MCR_RTS | UART_MCR_DTR | UART_MCR_LOOP);
+ mcr |= ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0);
+ mcr |= ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
+ mcr |= ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0);
+ break;
+ }
+
+ mos7720_port->shadowMCR = mcr;
+
+ data = mos7720_port->shadowMCR;
+ send_mos_cmd(port->serial, MOS_WRITE,
+ port->number - port->serial->minor, UART_MCR, &data);
+
+ return 0;
+}
+
+static int get_modem_info(struct moschip_port *mos7720_port,
+ unsigned int __user *value)
+{
+ unsigned int result = 0;
+ unsigned int msr = mos7720_port->shadowMSR;
+ unsigned int mcr = mos7720_port->shadowMCR;
+
+ result = ((mcr & UART_MCR_DTR) ? TIOCM_DTR: 0) /* 0x002 */
+ | ((mcr & UART_MCR_RTS) ? TIOCM_RTS: 0) /* 0x004 */
+ | ((msr & UART_MSR_CTS) ? TIOCM_CTS: 0) /* 0x020 */
+ | ((msr & UART_MSR_DCD) ? TIOCM_CAR: 0) /* 0x040 */
+ | ((msr & UART_MSR_RI) ? TIOCM_RI: 0) /* 0x080 */
+ | ((msr & UART_MSR_DSR) ? TIOCM_DSR: 0); /* 0x100 */
+
+
+ dbg("%s -- %x", __FUNCTION__, result);
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+static int get_serial_info(struct moschip_port *mos7720_port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ tmp.type = PORT_16550A;
+ tmp.line = mos7720_port->port->serial->minor;
+ tmp.port = mos7720_port->port->number;
+ tmp.irq = 0;
+ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+ tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
+ tmp.baud_base = 9600;
+ tmp.close_delay = 5*HZ;
+ tmp.closing_wait = 30*HZ;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+static int mos7720_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct moschip_port *mos7720_port;
+ struct async_icount cnow;
+ struct async_icount cprev;
+ struct serial_icounter_struct icount;
+
+ mos7720_port = usb_get_serial_port_data(port);
+ if (mos7720_port == NULL)
+ return -ENODEV;
+
+ dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+
+ switch (cmd) {
+ case TIOCINQ:
+ /* return number of bytes available */
+ dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
+ return get_number_bytes_avail(mos7720_port,
+ (unsigned int __user *)arg);
+ break;
+
+ case TIOCSERGETLSR:
+ dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+ return get_lsr_info(mos7720_port, (unsigned int __user *)arg);
+ return 0;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+ port->number);
+ return set_modem_info(mos7720_port, cmd,
+ (unsigned int __user *)arg);
+
+ case TIOCMGET:
+ dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
+ return get_modem_info(mos7720_port,
+ (unsigned int __user *)arg);
+
+ case TIOCGSERIAL:
+ dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ return get_serial_info(mos7720_port,
+ (struct serial_struct __user *)arg);
+
+ case TIOCSSERIAL:
+ dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ break;
+
+ case TIOCMIWAIT:
+ dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ cprev = mos7720_port->icount;
+ while (1) {
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ cnow = mos7720_port->icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ break;
+
+ case TIOCGICOUNT:
+ cnow = mos7720_port->icount;
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+ port->number, icount.rx, icount.tx );
+ if (copy_to_user((void __user *)arg, &icount, sizeof(icount)))
+ return -EFAULT;
+ return 0;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int mos7720_startup(struct usb_serial *serial)
+{
+ struct moschip_serial *mos7720_serial;
+ struct moschip_port *mos7720_port;
+ struct usb_device *dev;
+ int i;
+ char data;
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ if (!serial) {
+ dbg("Invalid Handler");
+ return -ENODEV;
+ }
+
+ dev = serial->dev;
+
+ /* create our private serial structure */
+ mos7720_serial = kzalloc(sizeof(struct moschip_serial), GFP_KERNEL);
+ if (mos7720_serial == NULL) {
+ err("%s - Out of memory", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ usb_set_serial_data(serial, mos7720_serial);
+
+ /* we set up the pointers to the endpoints in the mos7720_open *
+ * function, as the structures aren't created yet. */
+
+ /* set up port private structures */
+ for (i = 0; i < serial->num_ports; ++i) {
+ mos7720_port = kzalloc(sizeof(struct moschip_port), GFP_KERNEL);
+ if (mos7720_port == NULL) {
+ err("%s - Out of memory", __FUNCTION__);
+ usb_set_serial_data(serial, NULL);
+ kfree(mos7720_serial);
+ return -ENOMEM;
+ }
+
+ /* Initialize all port interrupt end point to port 0 int
+ * endpoint. Our device has only one interrupt endpoint
+ * comman to all ports */
+ serial->port[i]->interrupt_in_endpointAddress = serial->port[0]->interrupt_in_endpointAddress;
+
+ mos7720_port->port = serial->port[i];
+ usb_set_serial_port_data(serial->port[i], mos7720_port);
+
+ dbg("port number is %d", serial->port[i]->number);
+ dbg("serial number is %d", serial->minor);
+ }
+
+
+ /* setting configuration feature to one */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ (__u8)0x03, 0x00,0x01,0x00, NULL, 0x00, 5*HZ);
+
+ send_mos_cmd(serial,MOS_READ,0x00, UART_LSR, &data); // LSR For Port 1
+ dbg("LSR:%x",data);
+
+ send_mos_cmd(serial,MOS_READ,0x01, UART_LSR, &data); // LSR For Port 2
+ dbg("LSR:%x",data);
+
+ return 0;
+}
+
+static void mos7720_shutdown(struct usb_serial *serial)
+{
+ int i;
+
+ /* free private structure allocated for serial port */
+ for (i=0; i < serial->num_ports; ++i) {
+ kfree(usb_get_serial_port_data(serial->port[i]));
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+
+ /* free private structure allocated for serial device */
+ kfree(usb_get_serial_data(serial));
+ usb_set_serial_data(serial, NULL);
+}
+
+static struct usb_serial_driver moschip7720_2port_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "moschip7720",
+ },
+ .description = "Moschip 2 port adapter",
+ .id_table = moschip_port_id_table,
+ .num_interrupt_in = 1,
+ .num_bulk_in = 2,
+ .num_bulk_out = 2,
+ .num_ports = 2,
+ .open = mos7720_open,
+ .close = mos7720_close,
+ .throttle = mos7720_throttle,
+ .unthrottle = mos7720_unthrottle,
+ .attach = mos7720_startup,
+ .shutdown = mos7720_shutdown,
+ .ioctl = mos7720_ioctl,
+ .set_termios = mos7720_set_termios,
+ .write = mos7720_write,
+ .write_room = mos7720_write_room,
+ .chars_in_buffer = mos7720_chars_in_buffer,
+ .break_ctl = mos7720_break,
+ .read_bulk_callback = mos7720_bulk_in_callback,
+};
+
+static struct usb_driver usb_driver = {
+ .name = "moschip7720",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_port_id_table,
+};
+
+static int __init moschip7720_init(void)
+{
+ int retval;
+
+ dbg("%s: Entering ..........", __FUNCTION__);
+
+ /* Register with the usb serial */
+ retval = usb_serial_register(&moschip7720_2port_driver);
+ if (retval)
+ goto failed_port_device_register;
+
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ /* Register with the usb */
+ retval = usb_register(&usb_driver);
+ if (retval)
+ goto failed_usb_register;
+
+ return 0;
+
+failed_usb_register:
+ usb_serial_deregister(&moschip7720_2port_driver);
+
+failed_port_device_register:
+ return retval;
+}
+
+static void __exit moschip7720_exit(void)
+{
+ usb_deregister(&usb_driver);
+ usb_serial_deregister(&moschip7720_2port_driver);
+}
+
+module_init(moschip7720_init);
+module_exit(moschip7720_exit);
+
+/* Module information */
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
new file mode 100644
index 000000000000..5b71962d0351
--- /dev/null
+++ b/drivers/usb/serial/mos7840.c
@@ -0,0 +1,2948 @@
+/*
+ * 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
+ *
+ * Clean ups from Moschip version and a few ioctl implementations by:
+ * Paul B Schroeder <pschroeder "at" uplogix "dot" com>
+ *
+ * Originally based on drivers/usb/serial/io_edgeport.c which is:
+ * Copyright (C) 2000 Inside Out Networks, All rights reserved.
+ * Copyright (C) 2001-2002 Greg Kroah-Hartman <greg@kroah.com>
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/serial.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <asm/uaccess.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "1.3.1"
+#define DRIVER_DESC "Moschip 7840/7820 USB Serial Driver"
+
+/*
+ * 16C50 UART register defines
+ */
+
+#define LCR_BITS_5 0x00 /* 5 bits/char */
+#define LCR_BITS_6 0x01 /* 6 bits/char */
+#define LCR_BITS_7 0x02 /* 7 bits/char */
+#define LCR_BITS_8 0x03 /* 8 bits/char */
+#define LCR_BITS_MASK 0x03 /* Mask for bits/char field */
+
+#define LCR_STOP_1 0x00 /* 1 stop bit */
+#define LCR_STOP_1_5 0x04 /* 1.5 stop bits (if 5 bits/char) */
+#define LCR_STOP_2 0x04 /* 2 stop bits (if 6-8 bits/char) */
+#define LCR_STOP_MASK 0x04 /* Mask for stop bits field */
+
+#define LCR_PAR_NONE 0x00 /* No parity */
+#define LCR_PAR_ODD 0x08 /* Odd parity */
+#define LCR_PAR_EVEN 0x18 /* Even parity */
+#define LCR_PAR_MARK 0x28 /* Force parity bit to 1 */
+#define LCR_PAR_SPACE 0x38 /* Force parity bit to 0 */
+#define LCR_PAR_MASK 0x38 /* Mask for parity field */
+
+#define LCR_SET_BREAK 0x40 /* Set Break condition */
+#define LCR_DL_ENABLE 0x80 /* Enable access to divisor latch */
+
+#define MCR_DTR 0x01 /* Assert DTR */
+#define MCR_RTS 0x02 /* Assert RTS */
+#define MCR_OUT1 0x04 /* Loopback only: Sets state of RI */
+#define MCR_MASTER_IE 0x08 /* Enable interrupt outputs */
+#define MCR_LOOPBACK 0x10 /* Set internal (digital) loopback mode */
+#define MCR_XON_ANY 0x20 /* Enable any char to exit XOFF mode */
+
+#define MOS7840_MSR_CTS 0x10 /* Current state of CTS */
+#define MOS7840_MSR_DSR 0x20 /* Current state of DSR */
+#define MOS7840_MSR_RI 0x40 /* Current state of RI */
+#define MOS7840_MSR_CD 0x80 /* Current state of CD */
+
+/*
+ * Defines used for sending commands to port
+ */
+
+#define WAIT_FOR_EVER (HZ * 0 ) /* timeout urb is wait for ever */
+#define MOS_WDR_TIMEOUT (HZ * 5 ) /* default urb timeout */
+
+#define MOS_PORT1 0x0200
+#define MOS_PORT2 0x0300
+#define MOS_VENREG 0x0000
+#define MOS_MAX_PORT 0x02
+#define MOS_WRITE 0x0E
+#define MOS_READ 0x0D
+
+/* Requests */
+#define MCS_RD_RTYPE 0xC0
+#define MCS_WR_RTYPE 0x40
+#define MCS_RDREQ 0x0D
+#define MCS_WRREQ 0x0E
+#define MCS_CTRL_TIMEOUT 500
+#define VENDOR_READ_LENGTH (0x01)
+
+#define MAX_NAME_LEN 64
+
+#define ZLP_REG1 0x3A //Zero_Flag_Reg1 58
+#define ZLP_REG5 0x3E //Zero_Flag_Reg5 62
+
+/* For higher baud Rates use TIOCEXBAUD */
+#define TIOCEXBAUD 0x5462
+
+/* vendor id and device id defines */
+
+#define USB_VENDOR_ID_MOSCHIP 0x9710
+#define MOSCHIP_DEVICE_ID_7840 0x7840
+#define MOSCHIP_DEVICE_ID_7820 0x7820
+
+/* Interrupt Rotinue Defines */
+
+#define SERIAL_IIR_RLS 0x06
+#define SERIAL_IIR_MS 0x00
+
+/*
+ * Emulation of the bit mask on the LINE STATUS REGISTER.
+ */
+#define SERIAL_LSR_DR 0x0001
+#define SERIAL_LSR_OE 0x0002
+#define SERIAL_LSR_PE 0x0004
+#define SERIAL_LSR_FE 0x0008
+#define SERIAL_LSR_BI 0x0010
+
+#define MOS_MSR_DELTA_CTS 0x10
+#define MOS_MSR_DELTA_DSR 0x20
+#define MOS_MSR_DELTA_RI 0x40
+#define MOS_MSR_DELTA_CD 0x80
+
+// Serial Port register Address
+#define INTERRUPT_ENABLE_REGISTER ((__u16)(0x01))
+#define FIFO_CONTROL_REGISTER ((__u16)(0x02))
+#define LINE_CONTROL_REGISTER ((__u16)(0x03))
+#define MODEM_CONTROL_REGISTER ((__u16)(0x04))
+#define LINE_STATUS_REGISTER ((__u16)(0x05))
+#define MODEM_STATUS_REGISTER ((__u16)(0x06))
+#define SCRATCH_PAD_REGISTER ((__u16)(0x07))
+#define DIVISOR_LATCH_LSB ((__u16)(0x00))
+#define DIVISOR_LATCH_MSB ((__u16)(0x01))
+
+#define CLK_MULTI_REGISTER ((__u16)(0x02))
+#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
+
+#define SERIAL_LCR_DLAB ((__u16)(0x0080))
+
+/*
+ * URB POOL related defines
+ */
+#define NUM_URBS 16 /* URB Count */
+#define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */
+
+
+static struct usb_device_id moschip_port_id_table[] = {
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
+ {} /* terminating entry */
+};
+
+static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
+ {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
+ {} /* terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, moschip_id_table_combined);
+
+/* This structure holds all of the local port information */
+
+struct moschip_port {
+ int port_num; /*Actual port number in the device(1,2,etc) */
+ struct urb *write_urb; /* write URB for this port */
+ struct urb *read_urb; /* read URB for this port */
+ __u8 shadowLCR; /* last LCR value received */
+ __u8 shadowMCR; /* last MCR value received */
+ char open;
+ wait_queue_head_t wait_chase; /* for handling sleeping while waiting for chase to finish */
+ wait_queue_head_t delta_msr_wait; /* for handling sleeping while waiting for msr change to happen */
+ int delta_msr_cond;
+ struct async_icount icount;
+ struct usb_serial_port *port; /* loop back to the owner of this object */
+
+ /*Offsets */
+ __u8 SpRegOffset;
+ __u8 ControlRegOffset;
+ __u8 DcrRegOffset;
+ //for processing control URBS in interrupt context
+ struct urb *control_urb;
+ char *ctrl_buf;
+ int MsrLsr;
+
+ struct urb *write_urb_pool[NUM_URBS];
+};
+
+
+static int debug;
+static int mos7840_num_ports; //this says the number of ports in the device
+static int mos7840_num_open_ports;
+
+
+/*
+ * mos7840_set_reg_sync
+ * To set the Control register by calling usb_fill_control_urb function
+ * by passing usb_sndctrlpipe function as parameter.
+ */
+
+static int mos7840_set_reg_sync(struct usb_serial_port *port, __u16 reg,
+ __u16 val)
+{
+ struct usb_device *dev = port->serial->dev;
+ val = val & 0x00ff;
+ dbg("mos7840_set_reg_sync offset is %x, value %x\n", reg, val);
+
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
+ MCS_WR_RTYPE, val, reg, NULL, 0,
+ MOS_WDR_TIMEOUT);
+}
+
+/*
+ * mos7840_get_reg_sync
+ * To set the Uart register by calling usb_fill_control_urb function by
+ * passing usb_rcvctrlpipe function as parameter.
+ */
+
+static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
+ __u16 * val)
+{
+ struct usb_device *dev = port->serial->dev;
+ int ret = 0;
+
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
+ MOS_WDR_TIMEOUT);
+ dbg("mos7840_get_reg_sync offset is %x, return val %x\n", reg, *val);
+ *val = (*val) & 0x00ff;
+ return ret;
+}
+
+/*
+ * mos7840_set_uart_reg
+ * To set the Uart register by calling usb_fill_control_urb function by
+ * passing usb_sndctrlpipe function as parameter.
+ */
+
+static int mos7840_set_uart_reg(struct usb_serial_port *port, __u16 reg,
+ __u16 val)
+{
+
+ struct usb_device *dev = port->serial->dev;
+ val = val & 0x00ff;
+ // For the UART control registers, the application number need to be Or'ed
+ if (mos7840_num_ports == 4) {
+ val |=
+ (((__u16) port->number - (__u16) (port->serial->minor)) +
+ 1) << 8;
+ dbg("mos7840_set_uart_reg application number is %x\n", val);
+ } else {
+ if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
+ val |=
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 1) << 8;
+ dbg("mos7840_set_uart_reg application number is %x\n",
+ val);
+ } else {
+ val |=
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 2) << 8;
+ dbg("mos7840_set_uart_reg application number is %x\n",
+ val);
+ }
+ }
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ,
+ MCS_WR_RTYPE, val, reg, NULL, 0,
+ MOS_WDR_TIMEOUT);
+
+}
+
+/*
+ * mos7840_get_uart_reg
+ * To set the Control register by calling usb_fill_control_urb function
+ * by passing usb_rcvctrlpipe function as parameter.
+ */
+static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
+ __u16 * val)
+{
+ struct usb_device *dev = port->serial->dev;
+ int ret = 0;
+ __u16 Wval;
+
+ //dbg("application number is %4x \n",(((__u16)port->number - (__u16)(port->serial->minor))+1)<<8);
+ /*Wval is same as application number */
+ if (mos7840_num_ports == 4) {
+ Wval =
+ (((__u16) port->number - (__u16) (port->serial->minor)) +
+ 1) << 8;
+ dbg("mos7840_get_uart_reg application number is %x\n", Wval);
+ } else {
+ if (((__u16) port->number - (__u16) (port->serial->minor)) == 0) {
+ Wval =
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 1) << 8;
+ dbg("mos7840_get_uart_reg application number is %x\n",
+ Wval);
+ } else {
+ Wval =
+ (((__u16) port->number -
+ (__u16) (port->serial->minor)) + 2) << 8;
+ dbg("mos7840_get_uart_reg application number is %x\n",
+ Wval);
+ }
+ }
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
+ MCS_RD_RTYPE, Wval, reg, val, VENDOR_READ_LENGTH,
+ MOS_WDR_TIMEOUT);
+ *val = (*val) & 0x00ff;
+ return ret;
+}
+
+static void mos7840_dump_serial_port(struct moschip_port *mos7840_port)
+{
+
+ dbg("***************************************\n");
+ dbg("SpRegOffset is %2x\n", mos7840_port->SpRegOffset);
+ dbg("ControlRegOffset is %2x \n", mos7840_port->ControlRegOffset);
+ dbg("DCRRegOffset is %2x \n", mos7840_port->DcrRegOffset);
+ dbg("***************************************\n");
+
+}
+
+/************************************************************************/
+/************************************************************************/
+/* I N T E R F A C E F U N C T I O N S */
+/* I N T E R F A C E F U N C T I O N S */
+/************************************************************************/
+/************************************************************************/
+
+static inline void mos7840_set_port_private(struct usb_serial_port *port,
+ struct moschip_port *data)
+{
+ usb_set_serial_port_data(port, (void *)data);
+}
+
+static inline struct moschip_port *mos7840_get_port_private(struct
+ usb_serial_port
+ *port)
+{
+ return (struct moschip_port *)usb_get_serial_port_data(port);
+}
+
+static int mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr)
+{
+ struct moschip_port *mos7840_port;
+ struct async_icount *icount;
+ mos7840_port = port;
+ icount = &mos7840_port->icount;
+ if (new_msr &
+ (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI |
+ MOS_MSR_DELTA_CD)) {
+ icount = &mos7840_port->icount;
+
+ /* update input line counters */
+ if (new_msr & MOS_MSR_DELTA_CTS) {
+ icount->cts++;
+ }
+ if (new_msr & MOS_MSR_DELTA_DSR) {
+ icount->dsr++;
+ }
+ if (new_msr & MOS_MSR_DELTA_CD) {
+ icount->dcd++;
+ }
+ if (new_msr & MOS_MSR_DELTA_RI) {
+ icount->rng++;
+ }
+ }
+
+ return 0;
+}
+
+static int mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr)
+{
+ struct async_icount *icount;
+
+ dbg("%s - %02x", __FUNCTION__, new_lsr);
+
+ if (new_lsr & SERIAL_LSR_BI) {
+ //
+ // Parity and Framing errors only count if they
+ // occur exclusive of a break being
+ // received.
+ //
+ new_lsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI);
+ }
+
+ /* update input line counters */
+ icount = &port->icount;
+ if (new_lsr & SERIAL_LSR_BI) {
+ icount->brk++;
+ }
+ if (new_lsr & SERIAL_LSR_OE) {
+ icount->overrun++;
+ }
+ if (new_lsr & SERIAL_LSR_PE) {
+ icount->parity++;
+ }
+ if (new_lsr & SERIAL_LSR_FE) {
+ icount->frame++;
+ }
+
+ return 0;
+}
+
+/************************************************************************/
+/************************************************************************/
+/* U S B C A L L B A C K F U N C T I O N S */
+/* U S B C A L L B A C K F U N C T I O N S */
+/************************************************************************/
+/************************************************************************/
+
+static void mos7840_control_callback(struct urb *urb)
+{
+ unsigned char *data;
+ struct moschip_port *mos7840_port;
+ __u8 regval = 0x0;
+
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
+ goto exit;
+ }
+
+ mos7840_port = (struct moschip_port *)urb->context;
+
+ dbg("%s urb buffer size is %d\n", __FUNCTION__, urb->actual_length);
+ dbg("%s mos7840_port->MsrLsr is %d port %d\n", __FUNCTION__,
+ mos7840_port->MsrLsr, mos7840_port->port_num);
+ data = urb->transfer_buffer;
+ regval = (__u8) data[0];
+ dbg("%s data is %x\n", __FUNCTION__, regval);
+ if (mos7840_port->MsrLsr == 0)
+ mos7840_handle_new_msr(mos7840_port, regval);
+ else if (mos7840_port->MsrLsr == 1)
+ mos7840_handle_new_lsr(mos7840_port, regval);
+
+ exit:
+ return;
+}
+
+static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg,
+ __u16 * val)
+{
+ struct usb_device *dev = mcs->port->serial->dev;
+ struct usb_ctrlrequest *dr = NULL;
+ unsigned char *buffer = NULL;
+ int ret = 0;
+ buffer = (__u8 *) mcs->ctrl_buf;
+
+// dr=(struct usb_ctrlrequest *)(buffer);
+ dr = (void *)(buffer + 2);
+ dr->bRequestType = MCS_RD_RTYPE;
+ dr->bRequest = MCS_RDREQ;
+ dr->wValue = cpu_to_le16(Wval); //0;
+ dr->wIndex = cpu_to_le16(reg);
+ dr->wLength = cpu_to_le16(2);
+
+ usb_fill_control_urb(mcs->control_urb, dev, usb_rcvctrlpipe(dev, 0),
+ (unsigned char *)dr, buffer, 2,
+ mos7840_control_callback, mcs);
+ mcs->control_urb->transfer_buffer_length = 2;
+ ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC);
+ return ret;
+}
+
+/*****************************************************************************
+ * mos7840_interrupt_callback
+ * this is the callback function for when we have received data on the
+ * interrupt endpoint.
+ *****************************************************************************/
+
+static void mos7840_interrupt_callback(struct urb *urb)
+{
+ int result;
+ int length;
+ struct moschip_port *mos7840_port;
+ struct usb_serial *serial;
+ __u16 Data;
+ unsigned char *data;
+ __u8 sp[5], st;
+ int i;
+ __u16 wval;
+
+ dbg("%s", " : Entering\n");
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
+ goto exit;
+ }
+
+ length = urb->actual_length;
+ data = urb->transfer_buffer;
+
+ serial = (struct usb_serial *)urb->context;
+
+ /* Moschip get 5 bytes
+ * Byte 1 IIR Port 1 (port.number is 0)
+ * Byte 2 IIR Port 2 (port.number is 1)
+ * Byte 3 IIR Port 3 (port.number is 2)
+ * Byte 4 IIR Port 4 (port.number is 3)
+ * Byte 5 FIFO status for both */
+
+ if (length && length > 5) {
+ dbg("%s \n", "Wrong data !!!");
+ return;
+ }
+
+ sp[0] = (__u8) data[0];
+ sp[1] = (__u8) data[1];
+ sp[2] = (__u8) data[2];
+ sp[3] = (__u8) data[3];
+ st = (__u8) data[4];
+
+ for (i = 0; i < serial->num_ports; i++) {
+ mos7840_port = mos7840_get_port_private(serial->port[i]);
+ wval =
+ (((__u16) serial->port[i]->number -
+ (__u16) (serial->minor)) + 1) << 8;
+ if (mos7840_port->open) {
+ if (sp[i] & 0x01) {
+ dbg("SP%d No Interrupt !!!\n", i);
+ } else {
+ switch (sp[i] & 0x0f) {
+ case SERIAL_IIR_RLS:
+ dbg("Serial Port %d: Receiver status error or ", i);
+ dbg("address bit detected in 9-bit mode\n");
+ mos7840_port->MsrLsr = 1;
+ mos7840_get_reg(mos7840_port, wval,
+ LINE_STATUS_REGISTER,
+ &Data);
+ break;
+ case SERIAL_IIR_MS:
+ dbg("Serial Port %d: Modem status change\n", i);
+ mos7840_port->MsrLsr = 0;
+ mos7840_get_reg(mos7840_port, wval,
+ MODEM_STATUS_REGISTER,
+ &Data);
+ break;
+ }
+ }
+ }
+ }
+ exit:
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result) {
+ dev_err(&urb->dev->dev,
+ "%s - Error %d submitting interrupt urb\n",
+ __FUNCTION__, result);
+ }
+
+ return;
+
+}
+
+static int mos7840_port_paranoia_check(struct usb_serial_port *port,
+ const char *function)
+{
+ if (!port) {
+ dbg("%s - port == NULL", function);
+ return -1;
+ }
+ if (!port->serial) {
+ dbg("%s - port->serial == NULL", function);
+ return -1;
+ }
+
+ return 0;
+}
+
+/* Inline functions to check the sanity of a pointer that is passed to us */
+static int mos7840_serial_paranoia_check(struct usb_serial *serial,
+ const char *function)
+{
+ if (!serial) {
+ dbg("%s - serial == NULL", function);
+ return -1;
+ }
+ if (!serial->type) {
+ dbg("%s - serial->type == NULL!", function);
+ return -1;
+ }
+
+ return 0;
+}
+
+static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port,
+ const char *function)
+{
+ /* if no port was specified, or it fails a paranoia check */
+ if (!port ||
+ mos7840_port_paranoia_check(port, function) ||
+ mos7840_serial_paranoia_check(port->serial, function)) {
+ /* then say that we don't have a valid usb_serial thing, which will * end up genrating -ENODEV return values */
+ return NULL;
+ }
+
+ return port->serial;
+}
+
+/*****************************************************************************
+ * mos7840_bulk_in_callback
+ * this is the callback function for when we have received data on the
+ * bulk in endpoint.
+ *****************************************************************************/
+
+static void mos7840_bulk_in_callback(struct urb *urb)
+{
+ int status;
+ unsigned char *data;
+ struct usb_serial *serial;
+ struct usb_serial_port *port;
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero read bulk status received: %d", urb->status);
+ return;
+ }
+
+ mos7840_port = (struct moschip_port *)urb->context;
+ if (!mos7840_port) {
+ dbg("%s", "NULL mos7840_port pointer \n");
+ return;
+ }
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ if (!serial) {
+ dbg("%s\n", "Bad serial pointer ");
+ return;
+ }
+
+ dbg("%s\n", "Entering... \n");
+
+ data = urb->transfer_buffer;
+
+ dbg("%s", "Entering ........... \n");
+
+ if (urb->actual_length) {
+ tty = mos7840_port->port->tty;
+ if (tty) {
+ tty_buffer_request_room(tty, urb->actual_length);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ dbg(" %s \n", data);
+ tty_flip_buffer_push(tty);
+ }
+ mos7840_port->icount.rx += urb->actual_length;
+ dbg("mos7840_port->icount.rx is %d:\n",
+ mos7840_port->icount.rx);
+ }
+
+ if (!mos7840_port->read_urb) {
+ dbg("%s", "URB KILLED !!!\n");
+ return;
+ }
+
+ if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ mos7840_port->read_urb->dev = serial->dev;
+
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+
+ if (status) {
+ dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ }
+}
+
+/*****************************************************************************
+ * mos7840_bulk_out_data_callback
+ * this is the callback function for when we have finished sending serial data
+ * on the bulk out endpoint.
+ *****************************************************************************/
+
+static void mos7840_bulk_out_data_callback(struct urb *urb)
+{
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+ if (!urb) {
+ dbg("%s", "Invalid Pointer !!!!:\n");
+ return;
+ }
+
+ if (urb->status) {
+ dbg("nonzero write bulk status received:%d\n", urb->status);
+ return;
+ }
+
+ mos7840_port = (struct moschip_port *)urb->context;
+ if (!mos7840_port) {
+ dbg("%s", "NULL mos7840_port pointer \n");
+ return;
+ }
+
+ if (mos7840_port_paranoia_check(mos7840_port->port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ dbg("%s \n", "Entering .........");
+
+ tty = mos7840_port->port->tty;
+
+ if (tty && mos7840_port->open) {
+ /* let the tty driver wakeup if it has a special *
+ * write_wakeup function */
+
+ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
+ && tty->ldisc.write_wakeup) {
+ (tty->ldisc.write_wakeup) (tty);
+ }
+
+ /* tell the tty driver that something has changed */
+ wake_up_interruptible(&tty->write_wait);
+ }
+
+}
+
+/************************************************************************/
+/* D R I V E R T T Y I N T E R F A C E F U N C T I O N S */
+/************************************************************************/
+#ifdef MCSSerialProbe
+static int mos7840_serial_probe(struct usb_serial *serial,
+ const struct usb_device_id *id)
+{
+
+ /*need to implement the mode_reg reading and updating\
+ structures usb_serial_ device_type\
+ (i.e num_ports, num_bulkin,bulkout etc) */
+ /* Also we can update the changes attach */
+ return 1;
+}
+#endif
+
+/*****************************************************************************
+ * mos7840_open
+ * this function is called by the tty driver when a port is opened
+ * If successful, we return 0
+ * Otherwise we return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_open(struct usb_serial_port *port, struct file *filp)
+{
+ int response;
+ int j;
+ struct usb_serial *serial;
+ struct urb *urb;
+ __u16 Data;
+ int status;
+ struct moschip_port *mos7840_port;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return -ENODEV;
+ }
+
+ mos7840_num_open_ports++;
+ serial = port->serial;
+
+ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return -ENODEV;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return -ENODEV;
+
+ usb_clear_halt(serial->dev, port->write_urb->pipe);
+ usb_clear_halt(serial->dev, port->read_urb->pipe);
+
+ /* Initialising the write urb pool */
+ for (j = 0; j < NUM_URBS; ++j) {
+ urb = usb_alloc_urb(0, SLAB_ATOMIC);
+ mos7840_port->write_urb_pool[j] = urb;
+
+ if (urb == NULL) {
+ err("No more urbs???");
+ continue;
+ }
+
+ urb->transfer_buffer = NULL;
+ urb->transfer_buffer =
+ kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+ if (!urb->transfer_buffer) {
+ err("%s-out of memory for urb buffers.", __FUNCTION__);
+ continue;
+ }
+ }
+
+/*****************************************************************************
+ * Initialize MCS7840 -- Write Init values to corresponding Registers
+ *
+ * Register Index
+ * 1 : IER
+ * 2 : FCR
+ * 3 : LCR
+ * 4 : MCR
+ *
+ * 0x08 : SP1/2 Control Reg
+ *****************************************************************************/
+
+//NEED to check the following Block
+
+ status = 0;
+ Data = 0x0;
+ status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
+ if (status < 0) {
+ dbg("Reading Spreg failed\n");
+ return -1;
+ }
+ Data |= 0x80;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ if (status < 0) {
+ dbg("writing Spreg failed\n");
+ return -1;
+ }
+
+ Data &= ~0x80;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ if (status < 0) {
+ dbg("writing Spreg failed\n");
+ return -1;
+ }
+//End of block to be checked
+
+ status = 0;
+ Data = 0x0;
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
+ if (status < 0) {
+ dbg("Reading Controlreg failed\n");
+ return -1;
+ }
+ Data |= 0x08; //Driver done bit
+ Data |= 0x20; //rx_disable
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
+ if (status < 0) {
+ dbg("writing Controlreg failed\n");
+ return -1;
+ }
+ //do register settings here
+ // Set all regs to the device default values.
+ ////////////////////////////////////
+ // First Disable all interrupts.
+ ////////////////////////////////////
+
+ Data = 0x00;
+ status = 0;
+ status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+ if (status < 0) {
+ dbg("disableing interrupts failed\n");
+ return -1;
+ }
+ // Set FIFO_CONTROL_REGISTER to the default value
+ Data = 0x00;
+ status = 0;
+ status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing FIFO_CONTROL_REGISTER failed\n");
+ return -1;
+ }
+
+ Data = 0xcf;
+ status = 0;
+ status = mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing FIFO_CONTROL_REGISTER failed\n");
+ return -1;
+ }
+
+ Data = 0x03;
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+ mos7840_port->shadowLCR = Data;
+
+ Data = 0x0b;
+ status = 0;
+ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ mos7840_port->shadowMCR = Data;
+
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
+ mos7840_port->shadowLCR = Data;
+
+ Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ Data = 0x0c;
+ status = 0;
+ status = mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
+
+ Data = 0x0;
+ status = 0;
+ status = mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
+
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
+
+ Data = Data & ~SERIAL_LCR_DLAB;
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+ mos7840_port->shadowLCR = Data;
+
+ //clearing Bulkin and Bulkout Fifo
+ Data = 0x0;
+ status = 0;
+ status = mos7840_get_reg_sync(port, mos7840_port->SpRegOffset, &Data);
+
+ Data = Data | 0x0c;
+ status = 0;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+
+ Data = Data & ~0x0c;
+ status = 0;
+ status = mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ //Finally enable all interrupts
+ Data = 0x0;
+ Data = 0x0c;
+ status = 0;
+ status = mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ //clearing rx_disable
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
+ Data = Data & ~0x20;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
+
+ // rx_negate
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data);
+ Data = Data | 0x10;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data);
+
+ /* force low_latency on so that our tty_push actually forces *
+ * the data through,otherwise it is scheduled, and with *
+ * high data rates (like with OHCI) data can get lost. */
+
+ if (port->tty)
+ port->tty->low_latency = 1;
+/* Check to see if we've set up our endpoint info yet *
+ * (can't set it up in mos7840_startup as the structures *
+ * were not set up at that time.) */
+ if (mos7840_num_open_ports == 1) {
+ if (serial->port[0]->interrupt_in_buffer == NULL) {
+
+ /* set up interrupt urb */
+
+ usb_fill_int_urb(serial->port[0]->interrupt_in_urb,
+ serial->dev,
+ usb_rcvintpipe(serial->dev,
+ serial->port[0]->
+ interrupt_in_endpointAddress),
+ serial->port[0]->interrupt_in_buffer,
+ serial->port[0]->interrupt_in_urb->
+ transfer_buffer_length,
+ mos7840_interrupt_callback,
+ serial,
+ serial->port[0]->interrupt_in_urb->
+ interval);
+
+ /* start interrupt read for mos7840 *
+ * will continue as long as mos7840 is connected */
+
+ response =
+ usb_submit_urb(serial->port[0]->interrupt_in_urb,
+ GFP_KERNEL);
+ if (response) {
+ err("%s - Error %d submitting interrupt urb",
+ __FUNCTION__, response);
+ }
+
+ }
+
+ }
+
+ /* see if we've set up our endpoint info yet *
+ * (can't set it up in mos7840_startup as the *
+ * structures were not set up at that time.) */
+
+ dbg("port number is %d \n", port->number);
+ dbg("serial number is %d \n", port->serial->minor);
+ dbg("Bulkin endpoint is %d \n", port->bulk_in_endpointAddress);
+ dbg("BulkOut endpoint is %d \n", port->bulk_out_endpointAddress);
+ dbg("Interrupt endpoint is %d \n", port->interrupt_in_endpointAddress);
+ dbg("port's number in the device is %d\n", mos7840_port->port_num);
+ mos7840_port->read_urb = port->read_urb;
+
+ /* set up our bulk in urb */
+
+ usb_fill_bulk_urb(mos7840_port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->bulk_in_buffer,
+ mos7840_port->read_urb->transfer_buffer_length,
+ mos7840_bulk_in_callback, mos7840_port);
+
+ dbg("mos7840_open: bulkin endpoint is %d\n",
+ port->bulk_in_endpointAddress);
+ response = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL);
+ if (response) {
+ err("%s - Error %d submitting control urb", __FUNCTION__,
+ response);
+ }
+
+ /* initialize our wait queues */
+ init_waitqueue_head(&mos7840_port->wait_chase);
+ init_waitqueue_head(&mos7840_port->delta_msr_wait);
+
+ /* initialize our icount structure */
+ memset(&(mos7840_port->icount), 0x00, sizeof(mos7840_port->icount));
+
+ /* initialize our port settings */
+ mos7840_port->shadowMCR = MCR_MASTER_IE; /* Must set to enable ints! */
+ /* send a open port command */
+ mos7840_port->open = 1;
+ //mos7840_change_port_settings(mos7840_port,old_termios);
+ mos7840_port->icount.tx = 0;
+ mos7840_port->icount.rx = 0;
+
+ dbg("\n\nusb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p\n\n", serial, mos7840_port, port);
+
+ return 0;
+
+}
+
+/*****************************************************************************
+ * mos7840_chars_in_buffer
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we currently have outstanding in the port (data that has
+ * been written, but hasn't made it out the port yet)
+ * If successful, we return the number of bytes left to be written in the
+ * system,
+ * Otherwise we return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_chars_in_buffer(struct usb_serial_port *port)
+{
+ int i;
+ int chars = 0;
+ struct moschip_port *mos7840_port;
+
+ dbg("%s \n", " mos7840_chars_in_buffer:entering ...........");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+ if (mos7840_port == NULL) {
+ dbg("%s \n", "mos7840_break:leaving ...........");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7840_port->write_urb_pool[i]->status == -EINPROGRESS) {
+ chars += URB_TRANSFER_BUFFER_SIZE;
+ }
+ }
+ dbg("%s - returns %d", __FUNCTION__, chars);
+ return (chars);
+
+}
+
+/************************************************************************
+ *
+ * mos7840_block_until_tx_empty
+ *
+ * This function will block the close until one of the following:
+ * 1. TX count are 0
+ * 2. The mos7840 has stopped
+ * 3. A timout of 3 seconds without activity has expired
+ *
+ ************************************************************************/
+static void mos7840_block_until_tx_empty(struct moschip_port *mos7840_port)
+{
+ int timeout = HZ / 10;
+ int wait = 30;
+ int count;
+
+ while (1) {
+
+ count = mos7840_chars_in_buffer(mos7840_port->port);
+
+ /* Check for Buffer status */
+ if (count <= 0) {
+ return;
+ }
+
+ /* Block the thread for a while */
+ interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
+ timeout);
+
+ /* No activity.. count down section */
+ wait--;
+ if (wait == 0) {
+ dbg("%s - TIMEOUT", __FUNCTION__);
+ return;
+ } else {
+ /* Reset timout value back to seconds */
+ wait = 30;
+ }
+ }
+}
+
+/*****************************************************************************
+ * mos7840_close
+ * this function is called by the tty driver when a port is closed
+ *****************************************************************************/
+
+static void mos7840_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct usb_serial *serial;
+ struct moschip_port *mos7840_port;
+ int j;
+ __u16 Data;
+
+ dbg("%s\n", "mos7840_close:entering...");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ if (!serial) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL) {
+ return;
+ }
+
+ for (j = 0; j < NUM_URBS; ++j)
+ usb_kill_urb(mos7840_port->write_urb_pool[j]);
+
+ /* Freeing Write URBs */
+ for (j = 0; j < NUM_URBS; ++j) {
+ if (mos7840_port->write_urb_pool[j]) {
+ if (mos7840_port->write_urb_pool[j]->transfer_buffer)
+ kfree(mos7840_port->write_urb_pool[j]->
+ transfer_buffer);
+
+ usb_free_urb(mos7840_port->write_urb_pool[j]);
+ }
+ }
+
+ if (serial->dev) {
+ /* flush and block until tx is empty */
+ mos7840_block_until_tx_empty(mos7840_port);
+ }
+
+ /* While closing port, shutdown all bulk read, write *
+ * and interrupt read if they exists */
+ if (serial->dev) {
+
+ if (mos7840_port->write_urb) {
+ dbg("%s", "Shutdown bulk write\n");
+ usb_kill_urb(mos7840_port->write_urb);
+ }
+
+ if (mos7840_port->read_urb) {
+ dbg("%s", "Shutdown bulk read\n");
+ usb_kill_urb(mos7840_port->read_urb);
+ }
+ if ((&mos7840_port->control_urb)) {
+ dbg("%s", "Shutdown control read\n");
+ // usb_kill_urb (mos7840_port->control_urb);
+
+ }
+ }
+// if(mos7840_port->ctrl_buf != NULL)
+// kfree(mos7840_port->ctrl_buf);
+ mos7840_num_open_ports--;
+ dbg("mos7840_num_open_ports in close%d:in port%d\n",
+ mos7840_num_open_ports, port->number);
+ if (mos7840_num_open_ports == 0) {
+ if (serial->port[0]->interrupt_in_urb) {
+ dbg("%s", "Shutdown interrupt_in_urb\n");
+ }
+ }
+
+ if (mos7840_port->write_urb) {
+ /* if this urb had a transfer buffer already (old tx) free it */
+
+ if (mos7840_port->write_urb->transfer_buffer != NULL) {
+ kfree(mos7840_port->write_urb->transfer_buffer);
+ }
+ usb_free_urb(mos7840_port->write_urb);
+ }
+
+ Data = 0x0;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+
+ Data = 0x00;
+ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ mos7840_port->open = 0;
+
+ dbg("%s \n", "Leaving ............");
+}
+
+/************************************************************************
+ *
+ * mos7840_block_until_chase_response
+ *
+ * This function will block the close until one of the following:
+ * 1. Response to our Chase comes from mos7840
+ * 2. A timout of 10 seconds without activity has expired
+ * (1K of mos7840 data @ 2400 baud ==> 4 sec to empty)
+ *
+ ************************************************************************/
+
+static void mos7840_block_until_chase_response(struct moschip_port
+ *mos7840_port)
+{
+ int timeout = 1 * HZ;
+ int wait = 10;
+ int count;
+
+ while (1) {
+ count = mos7840_chars_in_buffer(mos7840_port->port);
+
+ /* Check for Buffer status */
+ if (count <= 0) {
+ return;
+ }
+
+ /* Block the thread for a while */
+ interruptible_sleep_on_timeout(&mos7840_port->wait_chase,
+ timeout);
+ /* No activity.. count down section */
+ wait--;
+ if (wait == 0) {
+ dbg("%s - TIMEOUT", __FUNCTION__);
+ return;
+ } else {
+ /* Reset timout value back to seconds */
+ wait = 10;
+ }
+ }
+
+}
+
+/*****************************************************************************
+ * mos7840_break
+ * this function sends a break to the port
+ *****************************************************************************/
+static void mos7840_break(struct usb_serial_port *port, int break_state)
+{
+ unsigned char data;
+ struct usb_serial *serial;
+ struct moschip_port *mos7840_port;
+
+ dbg("%s \n", "Entering ...........");
+ dbg("mos7840_break: Start\n");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return;
+ }
+
+ serial = mos7840_get_usb_serial(port, __FUNCTION__);
+ if (!serial) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL) {
+ return;
+ }
+
+ if (serial->dev) {
+
+ /* flush and block until tx is empty */
+ mos7840_block_until_chase_response(mos7840_port);
+ }
+
+ if (break_state == -1) {
+ data = mos7840_port->shadowLCR | LCR_SET_BREAK;
+ } else {
+ data = mos7840_port->shadowLCR & ~LCR_SET_BREAK;
+ }
+
+ mos7840_port->shadowLCR = data;
+ dbg("mcs7840_break mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER,
+ mos7840_port->shadowLCR);
+
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_write_room
+ * this function is called by the tty driver when it wants to know how many
+ * bytes of data we can accept for a specific port.
+ * If successful, we return the amount of room that we have for this port
+ * Otherwise we return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_write_room(struct usb_serial_port *port)
+{
+ int i;
+ int room = 0;
+ struct moschip_port *mos7840_port;
+
+ dbg("%s \n", " mos7840_write_room:entering ...........");
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ dbg("%s \n", " mos7840_write_room:leaving ...........");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+ if (mos7840_port == NULL) {
+ dbg("%s \n", "mos7840_break:leaving ...........");
+ return -1;
+ }
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
+ room += URB_TRANSFER_BUFFER_SIZE;
+ }
+ }
+
+ dbg("%s - returns %d", __FUNCTION__, room);
+ return (room);
+
+}
+
+/*****************************************************************************
+ * mos7840_write
+ * this function is called by the tty driver when data should be written to
+ * the port.
+ * If successful, we return the number of bytes written, otherwise we
+ * return a negative error number.
+ *****************************************************************************/
+
+static int mos7840_write(struct usb_serial_port *port,
+ const unsigned char *data, int count)
+{
+ int status;
+ int i;
+ int bytes_sent = 0;
+ int transfer_size;
+
+ struct moschip_port *mos7840_port;
+ struct usb_serial *serial;
+ struct urb *urb;
+ //__u16 Data;
+ const unsigned char *current_position = data;
+ unsigned char *data1;
+ dbg("%s \n", "entering ...........");
+ //dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",mos7840_port->shadowLCR);
+
+#ifdef NOTMOS7840
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
+ mos7840_port->shadowLCR = Data;
+ dbg("mos7840_write: LINE_CONTROL_REGISTER is %x\n", Data);
+ dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+
+ //Data = 0x03;
+ //status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data);
+ //mos7840_port->shadowLCR=Data;//Need to add later
+
+ Data |= SERIAL_LCR_DLAB; //data latch enable in LCR 0x80
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ //Data = 0x0c;
+ //status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data);
+ Data = 0x00;
+ status = 0;
+ status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
+ dbg("mos7840_write:DLL value is %x\n", Data);
+
+ Data = 0x0;
+ status = 0;
+ status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
+ dbg("mos7840_write:DLM value is %x\n", Data);
+
+ Data = Data & ~SERIAL_LCR_DLAB;
+ dbg("mos7840_write: mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+ status = 0;
+ status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+#endif
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Port Paranoia failed \n");
+ return -1;
+ }
+
+ serial = port->serial;
+ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ dbg("%s", "Serial Paranoia failed \n");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+ if (mos7840_port == NULL) {
+ dbg("%s", "mos7840_port is NULL\n");
+ return -1;
+ }
+
+ /* try to find a free urb in the list */
+ urb = NULL;
+
+ for (i = 0; i < NUM_URBS; ++i) {
+ if (mos7840_port->write_urb_pool[i]->status != -EINPROGRESS) {
+ urb = mos7840_port->write_urb_pool[i];
+ dbg("\nURB:%d", i);
+ break;
+ }
+ }
+
+ if (urb == NULL) {
+ dbg("%s - no more free urbs", __FUNCTION__);
+ goto exit;
+ }
+
+ if (urb->transfer_buffer == NULL) {
+ urb->transfer_buffer =
+ kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
+
+ if (urb->transfer_buffer == NULL) {
+ err("%s no more kernel memory...", __FUNCTION__);
+ goto exit;
+ }
+ }
+ transfer_size = min(count, URB_TRANSFER_BUFFER_SIZE);
+
+ memcpy(urb->transfer_buffer, current_position, transfer_size);
+
+ /* fill urb with data and submit */
+ usb_fill_bulk_urb(urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ urb->transfer_buffer,
+ transfer_size,
+ mos7840_bulk_out_data_callback, mos7840_port);
+
+ data1 = urb->transfer_buffer;
+ dbg("\nbulkout endpoint is %d", port->bulk_out_endpointAddress);
+
+ /* send it down the pipe */
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+
+ if (status) {
+ err("%s - usb_submit_urb(write bulk) failed with status = %d",
+ __FUNCTION__, status);
+ bytes_sent = status;
+ goto exit;
+ }
+ bytes_sent = transfer_size;
+ mos7840_port->icount.tx += transfer_size;
+ dbg("mos7840_port->icount.tx is %d:\n", mos7840_port->icount.tx);
+ exit:
+
+ return bytes_sent;
+
+}
+
+/*****************************************************************************
+ * mos7840_throttle
+ * this function is called by the tty driver when it wants to stop the data
+ * being read from the port.
+ *****************************************************************************/
+
+static void mos7840_throttle(struct usb_serial_port *port)
+{
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+ int status;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ dbg("- port %d\n", port->number);
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return;
+
+ if (!mos7840_port->open) {
+ dbg("%s\n", "port not opened");
+ return;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the stop character */
+ if (I_IXOFF(tty)) {
+ unsigned char stop_char = STOP_CHAR(tty);
+ status = mos7840_write(port, &stop_char, 1);
+ if (status <= 0) {
+ return;
+ }
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7840_port->shadowMCR &= ~MCR_RTS;
+ status = 0;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
+ mos7840_port->shadowMCR);
+
+ if (status < 0) {
+ return;
+ }
+ }
+
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_unthrottle
+ * this function is called by the tty driver when it wants to resume the data
+ * being read from the port (called after SerialThrottle is called)
+ *****************************************************************************/
+static void mos7840_unthrottle(struct usb_serial_port *port)
+{
+ struct tty_struct *tty;
+ int status;
+ struct moschip_port *mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ if (mos7840_port == NULL)
+ return;
+
+ if (!mos7840_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ tty = port->tty;
+ if (!tty) {
+ dbg("%s - no tty available", __FUNCTION__);
+ return;
+ }
+
+ /* if we are implementing XON/XOFF, send the start character */
+ if (I_IXOFF(tty)) {
+ unsigned char start_char = START_CHAR(tty);
+ status = mos7840_write(port, &start_char, 1);
+ if (status <= 0) {
+ return;
+ }
+ }
+
+ /* if we are implementing RTS/CTS, toggle that line */
+ if (tty->termios->c_cflag & CRTSCTS) {
+ mos7840_port->shadowMCR |= MCR_RTS;
+ status = 0;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
+ mos7840_port->shadowMCR);
+ if (status < 0) {
+ return;
+ }
+ }
+
+ return;
+}
+
+static int mos7840_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ struct moschip_port *mos7840_port;
+ unsigned int result;
+ __u16 msr;
+ __u16 mcr;
+ int status = 0;
+ mos7840_port = mos7840_get_port_private(port);
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ if (mos7840_port == NULL)
+ return -ENODEV;
+
+ status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr);
+ status = mos7840_get_uart_reg(port, MODEM_CONTROL_REGISTER, &mcr);
+ result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0)
+ | ((mcr & MCR_RTS) ? TIOCM_RTS : 0)
+ | ((mcr & MCR_LOOPBACK) ? TIOCM_LOOP : 0)
+ | ((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0)
+ | ((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0)
+ | ((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0)
+ | ((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0);
+
+ dbg("%s - 0x%04X", __FUNCTION__, result);
+
+ return result;
+}
+
+static int mos7840_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct moschip_port *mos7840_port;
+ unsigned int mcr;
+ unsigned int status;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return -ENODEV;
+
+ mcr = mos7840_port->shadowMCR;
+ if (clear & TIOCM_RTS)
+ mcr &= ~MCR_RTS;
+ if (clear & TIOCM_DTR)
+ mcr &= ~MCR_DTR;
+ if (clear & TIOCM_LOOP)
+ mcr &= ~MCR_LOOPBACK;
+
+ if (set & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ if (set & TIOCM_DTR)
+ mcr |= MCR_DTR;
+ if (set & TIOCM_LOOP)
+ mcr |= MCR_LOOPBACK;
+
+ mos7840_port->shadowMCR = mcr;
+
+ status = 0;
+ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, mcr);
+ if (status < 0) {
+ dbg("setting MODEM_CONTROL_REGISTER Failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_calc_baud_rate_divisor
+ * this function calculates the proper baud rate divisor for the specified
+ * baud rate.
+ *****************************************************************************/
+static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor,
+ __u16 * clk_sel_val)
+{
+
+ dbg("%s - %d", __FUNCTION__, baudRate);
+
+ if (baudRate <= 115200) {
+ *divisor = 115200 / baudRate;
+ *clk_sel_val = 0x0;
+ }
+ if ((baudRate > 115200) && (baudRate <= 230400)) {
+ *divisor = 230400 / baudRate;
+ *clk_sel_val = 0x10;
+ } else if ((baudRate > 230400) && (baudRate <= 403200)) {
+ *divisor = 403200 / baudRate;
+ *clk_sel_val = 0x20;
+ } else if ((baudRate > 403200) && (baudRate <= 460800)) {
+ *divisor = 460800 / baudRate;
+ *clk_sel_val = 0x30;
+ } else if ((baudRate > 460800) && (baudRate <= 806400)) {
+ *divisor = 806400 / baudRate;
+ *clk_sel_val = 0x40;
+ } else if ((baudRate > 806400) && (baudRate <= 921600)) {
+ *divisor = 921600 / baudRate;
+ *clk_sel_val = 0x50;
+ } else if ((baudRate > 921600) && (baudRate <= 1572864)) {
+ *divisor = 1572864 / baudRate;
+ *clk_sel_val = 0x60;
+ } else if ((baudRate > 1572864) && (baudRate <= 3145728)) {
+ *divisor = 3145728 / baudRate;
+ *clk_sel_val = 0x70;
+ }
+ return 0;
+
+#ifdef NOTMCS7840
+
+ for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) {
+ if (mos7840_divisor_table[i].BaudRate == baudrate) {
+ *divisor = mos7840_divisor_table[i].Divisor;
+ return 0;
+ }
+ }
+
+ /* After trying for all the standard baud rates *
+ * Try calculating the divisor for this baud rate */
+
+ if (baudrate > 75 && baudrate < 230400) {
+ /* get the divisor */
+ custom = (__u16) (230400L / baudrate);
+
+ /* Check for round off */
+ round1 = (__u16) (2304000L / baudrate);
+ round = (__u16) (round1 - (custom * 10));
+ if (round > 4) {
+ custom++;
+ }
+ *divisor = custom;
+
+ dbg(" Baud %d = %d\n", baudrate, custom);
+ return 0;
+ }
+
+ dbg("%s\n", " Baud calculation Failed...");
+ return -1;
+#endif
+}
+
+/*****************************************************************************
+ * mos7840_send_cmd_write_baud_rate
+ * this function sends the proper command to change the baud rate of the
+ * specified port.
+ *****************************************************************************/
+
+static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
+ int baudRate)
+{
+ int divisor = 0;
+ int status;
+ __u16 Data;
+ unsigned char number;
+ __u16 clk_sel_val;
+ struct usb_serial_port *port;
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
+ dbg("%s", "Invalid Serial \n");
+ return -1;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ number = mos7840_port->port->number - mos7840_port->port->serial->minor;
+
+ dbg("%s - port = %d, baud = %d", __FUNCTION__,
+ mos7840_port->port->number, baudRate);
+ //reset clk_uart_sel in spregOffset
+ if (baudRate > 115200) {
+#ifdef HW_flow_control
+ //NOTE: need to see the pther register to modify
+ //setting h/w flow control bit to 1;
+ status = 0;
+ Data = 0x2b;
+ mos7840_port->shadowMCR = Data;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing spreg failed in set_serial_baud\n");
+ return -1;
+ }
+#endif
+
+ } else {
+#ifdef HW_flow_control
+ //setting h/w flow control bit to 0;
+ status = 0;
+ Data = 0xb;
+ mos7840_port->shadowMCR = Data;
+ status =
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing spreg failed in set_serial_baud\n");
+ return -1;
+ }
+#endif
+
+ }
+
+ if (1) //baudRate <= 115200)
+ {
+ clk_sel_val = 0x0;
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_calc_baud_rate_divisor(baudRate, &divisor,
+ &clk_sel_val);
+ status =
+ mos7840_get_reg_sync(port, mos7840_port->SpRegOffset,
+ &Data);
+ if (status < 0) {
+ dbg("reading spreg failed in set_serial_baud\n");
+ return -1;
+ }
+ Data = (Data & 0x8f) | clk_sel_val;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(port, mos7840_port->SpRegOffset, Data);
+ if (status < 0) {
+ dbg("Writing spreg failed in set_serial_baud\n");
+ return -1;
+ }
+ /* Calculate the Divisor */
+
+ if (status) {
+ err("%s - bad baud rate", __FUNCTION__);
+ dbg("%s\n", "bad baud rate");
+ return status;
+ }
+ /* Enable access to divisor latch */
+ Data = mos7840_port->shadowLCR | SERIAL_LCR_DLAB;
+ mos7840_port->shadowLCR = Data;
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ /* Write the divisor */
+ Data = (unsigned char)(divisor & 0xff);
+ dbg("set_serial_baud Value to write DLL is %x\n", Data);
+ mos7840_set_uart_reg(port, DIVISOR_LATCH_LSB, Data);
+
+ Data = (unsigned char)((divisor & 0xff00) >> 8);
+ dbg("set_serial_baud Value to write DLM is %x\n", Data);
+ mos7840_set_uart_reg(port, DIVISOR_LATCH_MSB, Data);
+
+ /* Disable access to divisor latch */
+ Data = mos7840_port->shadowLCR & ~SERIAL_LCR_DLAB;
+ mos7840_port->shadowLCR = Data;
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ }
+
+ return status;
+}
+
+/*****************************************************************************
+ * mos7840_change_port_settings
+ * This routine is called to set the UART on the device to match
+ * the specified new settings.
+ *****************************************************************************/
+
+static void mos7840_change_port_settings(struct moschip_port *mos7840_port,
+ struct termios *old_termios)
+{
+ struct tty_struct *tty;
+ int baud;
+ unsigned cflag;
+ unsigned iflag;
+ __u8 lData;
+ __u8 lParity;
+ __u8 lStop;
+ int status;
+ __u16 Data;
+ struct usb_serial_port *port;
+ struct usb_serial *serial;
+
+ if (mos7840_port == NULL)
+ return;
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ if (mos7840_serial_paranoia_check(port->serial, __FUNCTION__)) {
+ dbg("%s", "Invalid Serial \n");
+ return;
+ }
+
+ serial = port->serial;
+
+ dbg("%s - port %d", __FUNCTION__, mos7840_port->port->number);
+
+ if (!mos7840_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ tty = mos7840_port->port->tty;
+
+ if ((!tty) || (!tty->termios)) {
+ dbg("%s - no tty structures", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s", "Entering .......... \n");
+
+ lData = LCR_BITS_8;
+ lStop = LCR_STOP_1;
+ lParity = LCR_PAR_NONE;
+
+ cflag = tty->termios->c_cflag;
+ iflag = tty->termios->c_iflag;
+
+ /* Change the number of bits */
+ if (cflag & CSIZE) {
+ switch (cflag & CSIZE) {
+ case CS5:
+ lData = LCR_BITS_5;
+ break;
+
+ case CS6:
+ lData = LCR_BITS_6;
+ break;
+
+ case CS7:
+ lData = LCR_BITS_7;
+ break;
+ default:
+ case CS8:
+ lData = LCR_BITS_8;
+ break;
+ }
+ }
+ /* Change the Parity bit */
+ if (cflag & PARENB) {
+ if (cflag & PARODD) {
+ lParity = LCR_PAR_ODD;
+ dbg("%s - parity = odd", __FUNCTION__);
+ } else {
+ lParity = LCR_PAR_EVEN;
+ dbg("%s - parity = even", __FUNCTION__);
+ }
+
+ } else {
+ dbg("%s - parity = none", __FUNCTION__);
+ }
+
+ if (cflag & CMSPAR) {
+ lParity = lParity | 0x20;
+ }
+
+ /* Change the Stop bit */
+ if (cflag & CSTOPB) {
+ lStop = LCR_STOP_2;
+ dbg("%s - stop bits = 2", __FUNCTION__);
+ } else {
+ lStop = LCR_STOP_1;
+ dbg("%s - stop bits = 1", __FUNCTION__);
+ }
+
+ /* Update the LCR with the correct value */
+ mos7840_port->shadowLCR &=
+ ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
+ mos7840_port->shadowLCR |= (lData | lParity | lStop);
+
+ dbg("mos7840_change_port_settings mos7840_port->shadowLCR is %x\n",
+ mos7840_port->shadowLCR);
+ /* Disable Interrupts */
+ Data = 0x00;
+ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ Data = 0x00;
+ mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+
+ Data = 0xcf;
+ mos7840_set_uart_reg(port, FIFO_CONTROL_REGISTER, Data);
+
+ /* Send the updated LCR value to the mos7840 */
+ Data = mos7840_port->shadowLCR;
+
+ mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
+
+ Data = 0x00b;
+ mos7840_port->shadowMCR = Data;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ Data = 0x00b;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+
+ /* set up the MCR register and send it to the mos7840 */
+
+ mos7840_port->shadowMCR = MCR_MASTER_IE;
+ if (cflag & CBAUD) {
+ mos7840_port->shadowMCR |= (MCR_DTR | MCR_RTS);
+ }
+
+ if (cflag & CRTSCTS) {
+ mos7840_port->shadowMCR |= (MCR_XON_ANY);
+
+ } else {
+ mos7840_port->shadowMCR &= ~(MCR_XON_ANY);
+ }
+
+ Data = mos7840_port->shadowMCR;
+ mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+
+ /* Determine divisor based on baud rate */
+ baud = tty_get_baud_rate(tty);
+
+ if (!baud) {
+ /* pick a default, any default... */
+ dbg("%s\n", "Picked default baud...");
+ baud = 9600;
+ }
+
+ dbg("%s - baud rate = %d", __FUNCTION__, baud);
+ status = mos7840_send_cmd_write_baud_rate(mos7840_port, baud);
+
+ /* Enable Interrupts */
+ Data = 0x0c;
+ mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
+
+ if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ mos7840_port->read_urb->dev = serial->dev;
+
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+
+ if (status) {
+ dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ }
+ wake_up(&mos7840_port->delta_msr_wait);
+ mos7840_port->delta_msr_cond = 1;
+ dbg("mos7840_change_port_settings mos7840_port->shadowLCR is End %x\n",
+ mos7840_port->shadowLCR);
+
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_set_termios
+ * this function is called by the tty driver when it wants to change
+ * the termios structure
+ *****************************************************************************/
+
+static void mos7840_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ int status;
+ unsigned int cflag;
+ struct usb_serial *serial;
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+ dbg("mos7840_set_termios: START\n");
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return;
+ }
+
+ serial = port->serial;
+
+ if (mos7840_serial_paranoia_check(serial, __FUNCTION__)) {
+ dbg("%s", "Invalid Serial \n");
+ return;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return;
+
+ tty = port->tty;
+
+ if (!port->tty || !port->tty->termios) {
+ dbg("%s - no tty or termios", __FUNCTION__);
+ return;
+ }
+
+ if (!mos7840_port->open) {
+ dbg("%s - port not opened", __FUNCTION__);
+ return;
+ }
+
+ dbg("%s\n", "setting termios - ");
+
+ cflag = tty->termios->c_cflag;
+
+ if (!cflag) {
+ dbg("%s %s\n", __FUNCTION__, "cflag is NULL");
+ return;
+ }
+
+ /* check that they really want us to change something */
+ if (old_termios) {
+ if ((cflag == old_termios->c_cflag) &&
+ (RELEVANT_IFLAG(tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("%s\n", "Nothing to change");
+ return;
+ }
+ }
+
+ dbg("%s - clfag %08x iflag %08x", __FUNCTION__,
+ tty->termios->c_cflag, RELEVANT_IFLAG(tty->termios->c_iflag));
+
+ if (old_termios) {
+ dbg("%s - old clfag %08x old iflag %08x", __FUNCTION__,
+ old_termios->c_cflag, RELEVANT_IFLAG(old_termios->c_iflag));
+ }
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* change the port settings to the new ones specified */
+
+ mos7840_change_port_settings(mos7840_port, old_termios);
+
+ if (!mos7840_port->read_urb) {
+ dbg("%s", "URB KILLED !!!!!\n");
+ return;
+ }
+
+ if (mos7840_port->read_urb->status != -EINPROGRESS) {
+ mos7840_port->read_urb->dev = serial->dev;
+ status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
+ if (status) {
+ dbg(" usb_submit_urb(read bulk) failed, status = %d",
+ status);
+ }
+ }
+ return;
+}
+
+/*****************************************************************************
+ * mos7840_get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * is emptied. On bus types like RS485, the transmitter must
+ * release the bus after transmitting. This must be done when
+ * the transmit shift register is empty, not be done when the
+ * transmit holding register is empty. This functionality
+ * allows an RS485 driver to be written in user space.
+ *****************************************************************************/
+
+static int mos7840_get_lsr_info(struct moschip_port *mos7840_port,
+ unsigned int __user *value)
+{
+ int count;
+ unsigned int result = 0;
+
+ count = mos7840_chars_in_buffer(mos7840_port->port);
+ if (count == 0) {
+ dbg("%s -- Empty", __FUNCTION__);
+ result = TIOCSER_TEMT;
+ }
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_get_bytes_avail - get number of bytes available
+ *
+ * Purpose: Let user call ioctl to get the count of number of bytes available.
+ *****************************************************************************/
+
+static int mos7840_get_bytes_avail(struct moschip_port *mos7840_port,
+ unsigned int __user *value)
+{
+ unsigned int result = 0;
+ struct tty_struct *tty = mos7840_port->port->tty;
+
+ if (!tty)
+ return -ENOIOCTLCMD;
+
+ result = tty->read_cnt;
+
+ dbg("%s(%d) = %d", __FUNCTION__, mos7840_port->port->number, result);
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+
+ return -ENOIOCTLCMD;
+}
+
+/*****************************************************************************
+ * mos7840_set_modem_info
+ * function to set modem info
+ *****************************************************************************/
+
+static int mos7840_set_modem_info(struct moschip_port *mos7840_port,
+ unsigned int cmd, unsigned int __user *value)
+{
+ unsigned int mcr;
+ unsigned int arg;
+ __u16 Data;
+ int status;
+ struct usb_serial_port *port;
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ port = (struct usb_serial_port *)mos7840_port->port;
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ mcr = mos7840_port->shadowMCR;
+
+ if (copy_from_user(&arg, value, sizeof(int)))
+ return -EFAULT;
+
+ switch (cmd) {
+ case TIOCMBIS:
+ if (arg & TIOCM_RTS)
+ mcr |= MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr |= MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr |= MCR_LOOPBACK;
+ break;
+
+ case TIOCMBIC:
+ if (arg & TIOCM_RTS)
+ mcr &= ~MCR_RTS;
+ if (arg & TIOCM_DTR)
+ mcr &= ~MCR_RTS;
+ if (arg & TIOCM_LOOP)
+ mcr &= ~MCR_LOOPBACK;
+ break;
+
+ case TIOCMSET:
+ /* turn off the RTS and DTR and LOOPBACK
+ * and then only turn on what was asked to */
+ mcr &= ~(MCR_RTS | MCR_DTR | MCR_LOOPBACK);
+ mcr |= ((arg & TIOCM_RTS) ? MCR_RTS : 0);
+ mcr |= ((arg & TIOCM_DTR) ? MCR_DTR : 0);
+ mcr |= ((arg & TIOCM_LOOP) ? MCR_LOOPBACK : 0);
+ break;
+ }
+
+ mos7840_port->shadowMCR = mcr;
+
+ Data = mos7840_port->shadowMCR;
+ status = 0;
+ status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data);
+ if (status < 0) {
+ dbg("setting MODEM_CONTROL_REGISTER Failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_get_modem_info
+ * function to get modem info
+ *****************************************************************************/
+
+static int mos7840_get_modem_info(struct moschip_port *mos7840_port,
+ unsigned int __user *value)
+{
+ unsigned int result = 0;
+ __u16 msr;
+ unsigned int mcr = mos7840_port->shadowMCR;
+ int status = 0;
+ status =
+ mos7840_get_uart_reg(mos7840_port->port, MODEM_STATUS_REGISTER,
+ &msr);
+ result = ((mcr & MCR_DTR) ? TIOCM_DTR : 0) /* 0x002 */
+ |((mcr & MCR_RTS) ? TIOCM_RTS : 0) /* 0x004 */
+ |((msr & MOS7840_MSR_CTS) ? TIOCM_CTS : 0) /* 0x020 */
+ |((msr & MOS7840_MSR_CD) ? TIOCM_CAR : 0) /* 0x040 */
+ |((msr & MOS7840_MSR_RI) ? TIOCM_RI : 0) /* 0x080 */
+ |((msr & MOS7840_MSR_DSR) ? TIOCM_DSR : 0); /* 0x100 */
+
+ dbg("%s -- %x", __FUNCTION__, result);
+
+ if (copy_to_user(value, &result, sizeof(int)))
+ return -EFAULT;
+ return 0;
+}
+
+/*****************************************************************************
+ * mos7840_get_serial_info
+ * function to get information about serial port
+ *****************************************************************************/
+
+static int mos7840_get_serial_info(struct moschip_port *mos7840_port,
+ struct serial_struct __user *retinfo)
+{
+ struct serial_struct tmp;
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ if (!retinfo)
+ return -EFAULT;
+
+ memset(&tmp, 0, sizeof(tmp));
+
+ tmp.type = PORT_16550A;
+ tmp.line = mos7840_port->port->serial->minor;
+ tmp.port = mos7840_port->port->number;
+ tmp.irq = 0;
+ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+ tmp.xmit_fifo_size = NUM_URBS * URB_TRANSFER_BUFFER_SIZE;
+ tmp.baud_base = 9600;
+ tmp.close_delay = 5 * HZ;
+ tmp.closing_wait = 30 * HZ;
+
+ if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
+ return -EFAULT;
+ return 0;
+}
+
+/*****************************************************************************
+ * SerialIoctl
+ * this function handles any ioctl calls to the driver
+ *****************************************************************************/
+
+static int mos7840_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ void __user *argp = (void __user *)arg;
+ struct moschip_port *mos7840_port;
+ struct tty_struct *tty;
+
+ struct async_icount cnow;
+ struct async_icount cprev;
+ struct serial_icounter_struct icount;
+ int mosret = 0;
+ int retval;
+ struct tty_ldisc *ld;
+
+ if (mos7840_port_paranoia_check(port, __FUNCTION__)) {
+ dbg("%s", "Invalid port \n");
+ return -1;
+ }
+
+ mos7840_port = mos7840_get_port_private(port);
+
+ if (mos7840_port == NULL)
+ return -1;
+
+ tty = mos7840_port->port->tty;
+
+ dbg("%s - port %d, cmd = 0x%x", __FUNCTION__, port->number, cmd);
+
+ switch (cmd) {
+ /* return number of bytes available */
+
+ case TIOCINQ:
+ dbg("%s (%d) TIOCINQ", __FUNCTION__, port->number);
+ return mos7840_get_bytes_avail(mos7840_port, argp);
+
+ case TIOCOUTQ:
+ dbg("%s (%d) TIOCOUTQ", __FUNCTION__, port->number);
+ return put_user(tty->driver->chars_in_buffer ?
+ tty->driver->chars_in_buffer(tty) : 0,
+ (int __user *)arg);
+
+ case TCFLSH:
+ retval = tty_check_change(tty);
+ if (retval)
+ return retval;
+
+ ld = tty_ldisc_ref(tty);
+ switch (arg) {
+ case TCIFLUSH:
+ if (ld && ld->flush_buffer)
+ ld->flush_buffer(tty);
+ break;
+ case TCIOFLUSH:
+ if (ld && ld->flush_buffer)
+ ld->flush_buffer(tty);
+ /* fall through */
+ case TCOFLUSH:
+ if (tty->driver->flush_buffer)
+ tty->driver->flush_buffer(tty);
+ break;
+ default:
+ tty_ldisc_deref(ld);
+ return -EINVAL;
+ }
+ tty_ldisc_deref(ld);
+ return 0;
+
+ case TCGETS:
+ if (kernel_termios_to_user_termios
+ ((struct termios __user *)argp, tty->termios))
+ return -EFAULT;
+ return 0;
+
+ case TIOCSERGETLSR:
+ dbg("%s (%d) TIOCSERGETLSR", __FUNCTION__, port->number);
+ return mos7840_get_lsr_info(mos7840_port, argp);
+ return 0;
+
+ case TIOCMBIS:
+ case TIOCMBIC:
+ case TIOCMSET:
+ dbg("%s (%d) TIOCMSET/TIOCMBIC/TIOCMSET", __FUNCTION__,
+ port->number);
+ mosret =
+ mos7840_set_modem_info(mos7840_port, cmd, argp);
+ return mosret;
+
+ case TIOCMGET:
+ dbg("%s (%d) TIOCMGET", __FUNCTION__, port->number);
+ return mos7840_get_modem_info(mos7840_port, argp);
+
+ case TIOCGSERIAL:
+ dbg("%s (%d) TIOCGSERIAL", __FUNCTION__, port->number);
+ return mos7840_get_serial_info(mos7840_port, argp);
+
+ case TIOCSSERIAL:
+ dbg("%s (%d) TIOCSSERIAL", __FUNCTION__, port->number);
+ break;
+
+ case TIOCMIWAIT:
+ dbg("%s (%d) TIOCMIWAIT", __FUNCTION__, port->number);
+ cprev = mos7840_port->icount;
+ while (1) {
+ //interruptible_sleep_on(&mos7840_port->delta_msr_wait);
+ mos7840_port->delta_msr_cond = 0;
+ wait_event_interruptible(mos7840_port->delta_msr_wait,
+ (mos7840_port->
+ delta_msr_cond == 1));
+
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ cnow = mos7840_port->icount;
+ if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
+ cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
+ return -EIO; /* no change => error */
+ if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
+ ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
+ ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
+ ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) {
+ return 0;
+ }
+ cprev = cnow;
+ }
+ /* NOTREACHED */
+ break;
+
+ case TIOCGICOUNT:
+ cnow = mos7840_port->icount;
+ icount.cts = cnow.cts;
+ icount.dsr = cnow.dsr;
+ icount.rng = cnow.rng;
+ icount.dcd = cnow.dcd;
+ icount.rx = cnow.rx;
+ icount.tx = cnow.tx;
+ icount.frame = cnow.frame;
+ icount.overrun = cnow.overrun;
+ icount.parity = cnow.parity;
+ icount.brk = cnow.brk;
+ icount.buf_overrun = cnow.buf_overrun;
+
+ dbg("%s (%d) TIOCGICOUNT RX=%d, TX=%d", __FUNCTION__,
+ port->number, icount.rx, icount.tx);
+ if (copy_to_user(argp, &icount, sizeof(icount)))
+ return -EFAULT;
+ return 0;
+
+ case TIOCEXBAUD:
+ return 0;
+ default:
+ break;
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static int mos7840_calc_num_ports(struct usb_serial *serial)
+{
+
+ dbg("numberofendpoints: %d \n",
+ (int)serial->interface->cur_altsetting->desc.bNumEndpoints);
+ dbg("numberofendpoints: %d \n",
+ (int)serial->interface->altsetting->desc.bNumEndpoints);
+ if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) {
+ mos7840_num_ports = 2;
+ serial->type->num_ports = 2;
+ } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) {
+ mos7840_num_ports = 4;
+ serial->type->num_bulk_in = 4;
+ serial->type->num_bulk_out = 4;
+ serial->type->num_ports = 4;
+ }
+
+ return mos7840_num_ports;
+}
+
+/****************************************************************************
+ * mos7840_startup
+ ****************************************************************************/
+
+static int mos7840_startup(struct usb_serial *serial)
+{
+ struct moschip_port *mos7840_port;
+ struct usb_device *dev;
+ int i, status;
+
+ __u16 Data;
+ dbg("%s \n", " mos7840_startup :entering..........");
+
+ if (!serial) {
+ dbg("%s\n", "Invalid Handler");
+ return -1;
+ }
+
+ dev = serial->dev;
+
+ dbg("%s\n", "Entering...");
+
+ /* we set up the pointers to the endpoints in the mos7840_open *
+ * function, as the structures aren't created yet. */
+
+ /* set up port private structures */
+ for (i = 0; i < serial->num_ports; ++i) {
+ mos7840_port = kmalloc(sizeof(struct moschip_port), GFP_KERNEL);
+ if (mos7840_port == NULL) {
+ err("%s - Out of memory", __FUNCTION__);
+ return -ENOMEM;
+ }
+ memset(mos7840_port, 0, sizeof(struct moschip_port));
+
+ /* Initialize all port interrupt end point to port 0 int endpoint *
+ * Our device has only one interrupt end point comman to all port */
+
+ mos7840_port->port = serial->port[i];
+ mos7840_set_port_private(serial->port[i], mos7840_port);
+
+ mos7840_port->port_num = ((serial->port[i]->number -
+ (serial->port[i]->serial->minor)) +
+ 1);
+
+ if (mos7840_port->port_num == 1) {
+ mos7840_port->SpRegOffset = 0x0;
+ mos7840_port->ControlRegOffset = 0x1;
+ mos7840_port->DcrRegOffset = 0x4;
+ } else if ((mos7840_port->port_num == 2)
+ && (mos7840_num_ports == 4)) {
+ mos7840_port->SpRegOffset = 0x8;
+ mos7840_port->ControlRegOffset = 0x9;
+ mos7840_port->DcrRegOffset = 0x16;
+ } else if ((mos7840_port->port_num == 2)
+ && (mos7840_num_ports == 2)) {
+ mos7840_port->SpRegOffset = 0xa;
+ mos7840_port->ControlRegOffset = 0xb;
+ mos7840_port->DcrRegOffset = 0x19;
+ } else if ((mos7840_port->port_num == 3)
+ && (mos7840_num_ports == 4)) {
+ mos7840_port->SpRegOffset = 0xa;
+ mos7840_port->ControlRegOffset = 0xb;
+ mos7840_port->DcrRegOffset = 0x19;
+ } else if ((mos7840_port->port_num == 4)
+ && (mos7840_num_ports == 4)) {
+ mos7840_port->SpRegOffset = 0xc;
+ mos7840_port->ControlRegOffset = 0xd;
+ mos7840_port->DcrRegOffset = 0x1c;
+ }
+ mos7840_dump_serial_port(mos7840_port);
+
+ mos7840_set_port_private(serial->port[i], mos7840_port);
+
+ //enable rx_disable bit in control register
+
+ status =
+ mos7840_get_reg_sync(serial->port[i],
+ mos7840_port->ControlRegOffset, &Data);
+ if (status < 0) {
+ dbg("Reading ControlReg failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("ControlReg Reading success val is %x, status%d\n",
+ Data, status);
+ Data |= 0x08; //setting driver done bit
+ Data |= 0x04; //sp1_bit to have cts change reflect in modem status reg
+
+ //Data |= 0x20; //rx_disable bit
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ mos7840_port->ControlRegOffset, Data);
+ if (status < 0) {
+ dbg("Writing ControlReg failed(rx_disable) status-0x%x\n", status);
+ break;
+ } else
+ dbg("ControlReg Writing success(rx_disable) status%d\n",
+ status);
+
+ //Write default values in DCR (i.e 0x01 in DCR0, 0x05 in DCR2 and 0x24 in DCR3
+ Data = 0x01;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ (__u16) (mos7840_port->DcrRegOffset +
+ 0), Data);
+ if (status < 0) {
+ dbg("Writing DCR0 failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("DCR0 Writing success status%d\n", status);
+
+ Data = 0x05;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ (__u16) (mos7840_port->DcrRegOffset +
+ 1), Data);
+ if (status < 0) {
+ dbg("Writing DCR1 failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("DCR1 Writing success status%d\n", status);
+
+ Data = 0x24;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ (__u16) (mos7840_port->DcrRegOffset +
+ 2), Data);
+ if (status < 0) {
+ dbg("Writing DCR2 failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("DCR2 Writing success status%d\n", status);
+
+ // write values in clkstart0x0 and clkmulti 0x20
+ Data = 0x0;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i],
+ CLK_START_VALUE_REGISTER, Data);
+ if (status < 0) {
+ dbg("Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status);
+ break;
+ } else
+ dbg("CLK_START_VALUE_REGISTER Writing success status%d\n", status);
+
+ Data = 0x20;
+ status = 0;
+ status =
+ mos7840_set_reg_sync(serial->port[i], CLK_MULTI_REGISTER,
+ Data);
+ if (status < 0) {
+ dbg("Writing CLK_MULTI_REGISTER failed status-0x%x\n",
+ status);
+ break;
+ } else
+ dbg("CLK_MULTI_REGISTER Writing success status%d\n",
+ status);
+
+ //write value 0x0 to scratchpad register
+ Data = 0x00;
+ status = 0;
+ status =
+ mos7840_set_uart_reg(serial->port[i], SCRATCH_PAD_REGISTER,
+ Data);
+ if (status < 0) {
+ dbg("Writing SCRATCH_PAD_REGISTER failed status-0x%x\n",
+ status);
+ break;
+ } else
+ dbg("SCRATCH_PAD_REGISTER Writing success status%d\n",
+ status);
+
+ //Zero Length flag register
+ if ((mos7840_port->port_num != 1)
+ && (mos7840_num_ports == 2)) {
+
+ Data = 0xff;
+ status = 0;
+ status = mos7840_set_reg_sync(serial->port[i],
+ (__u16) (ZLP_REG1 +
+ ((__u16)
+ mos7840_port->
+ port_num)),
+ Data);
+ dbg("ZLIP offset%x\n",
+ (__u16) (ZLP_REG1 +
+ ((__u16) mos7840_port->port_num)));
+ if (status < 0) {
+ dbg("Writing ZLP_REG%d failed status-0x%x\n",
+ i + 2, status);
+ break;
+ } else
+ dbg("ZLP_REG%d Writing success status%d\n",
+ i + 2, status);
+ } else {
+ Data = 0xff;
+ status = 0;
+ status = mos7840_set_reg_sync(serial->port[i],
+ (__u16) (ZLP_REG1 +
+ ((__u16)
+ mos7840_port->
+ port_num) -
+ 0x1), Data);
+ dbg("ZLIP offset%x\n",
+ (__u16) (ZLP_REG1 +
+ ((__u16) mos7840_port->port_num) - 0x1));
+ if (status < 0) {
+ dbg("Writing ZLP_REG%d failed status-0x%x\n",
+ i + 1, status);
+ break;
+ } else
+ dbg("ZLP_REG%d Writing success status%d\n",
+ i + 1, status);
+
+ }
+ mos7840_port->control_urb = usb_alloc_urb(0, SLAB_ATOMIC);
+ mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL);
+
+ }
+
+ //Zero Length flag enable
+ Data = 0x0f;
+ status = 0;
+ status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data);
+ if (status < 0) {
+ dbg("Writing ZLP_REG5 failed status-0x%x\n", status);
+ return -1;
+ } else
+ dbg("ZLP_REG5 Writing success status%d\n", status);
+
+ /* setting configuration feature to one */
+ usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ (__u8) 0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5 * HZ);
+ return 0;
+}
+
+/****************************************************************************
+ * mos7840_shutdown
+ * This function is called whenever the device is removed from the usb bus.
+ ****************************************************************************/
+
+static void mos7840_shutdown(struct usb_serial *serial)
+{
+ int i;
+ struct moschip_port *mos7840_port;
+ dbg("%s \n", " shutdown :entering..........");
+
+ if (!serial) {
+ dbg("%s", "Invalid Handler \n");
+ return;
+ }
+
+ /* check for the ports to be closed,close the ports and disconnect */
+
+ /* free private structure allocated for serial port *
+ * stop reads and writes on all ports */
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ mos7840_port = mos7840_get_port_private(serial->port[i]);
+ kfree(mos7840_port->ctrl_buf);
+ usb_kill_urb(mos7840_port->control_urb);
+ kfree(mos7840_port);
+ mos7840_set_port_private(serial->port[i], NULL);
+ }
+
+ dbg("%s\n", "Thank u :: ");
+
+}
+
+static struct usb_serial_driver moschip7840_4port_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mos7840",
+ },
+ .description = DRIVER_DESC,
+ .id_table = moschip_port_id_table,
+ .num_interrupt_in = 1, //NUM_DONT_CARE,//1,
+#ifdef check
+ .num_bulk_in = 4,
+ .num_bulk_out = 4,
+ .num_ports = 4,
+#endif
+ .open = mos7840_open,
+ .close = mos7840_close,
+ .write = mos7840_write,
+ .write_room = mos7840_write_room,
+ .chars_in_buffer = mos7840_chars_in_buffer,
+ .throttle = mos7840_throttle,
+ .unthrottle = mos7840_unthrottle,
+ .calc_num_ports = mos7840_calc_num_ports,
+#ifdef MCSSerialProbe
+ .probe = mos7840_serial_probe,
+#endif
+ .ioctl = mos7840_ioctl,
+ .set_termios = mos7840_set_termios,
+ .break_ctl = mos7840_break,
+ .tiocmget = mos7840_tiocmget,
+ .tiocmset = mos7840_tiocmset,
+ .attach = mos7840_startup,
+ .shutdown = mos7840_shutdown,
+ .read_bulk_callback = mos7840_bulk_in_callback,
+ .read_int_callback = mos7840_interrupt_callback,
+};
+
+static struct usb_driver io_driver = {
+ .name = "mos7840",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = moschip_id_table_combined,
+};
+
+/****************************************************************************
+ * moschip7840_init
+ * This is called by the module subsystem, or on startup to initialize us
+ ****************************************************************************/
+static int __init moschip7840_init(void)
+{
+ int retval;
+
+ dbg("%s \n", " mos7840_init :entering..........");
+
+ /* Register with the usb serial */
+ retval = usb_serial_register(&moschip7840_4port_device);
+
+ if (retval)
+ goto failed_port_device_register;
+
+ dbg("%s\n", "Entring...");
+ info(DRIVER_DESC " " DRIVER_VERSION);
+
+ /* Register with the usb */
+ retval = usb_register(&io_driver);
+
+ if (retval)
+ goto failed_usb_register;
+
+ if (retval == 0) {
+ dbg("%s\n", "Leaving...");
+ return 0;
+ }
+
+ failed_usb_register:
+ usb_serial_deregister(&moschip7840_4port_device);
+
+ failed_port_device_register:
+
+ return retval;
+}
+
+/****************************************************************************
+ * moschip7840_exit
+ * Called when the driver is about to be unloaded.
+ ****************************************************************************/
+static void __exit moschip7840_exit(void)
+{
+
+ dbg("%s \n", " mos7840_exit :entering..........");
+
+ usb_deregister(&io_driver);
+
+ usb_serial_deregister(&moschip7840_4port_device);
+
+ dbg("%s\n", "Entring...");
+}
+
+module_init(moschip7840_init);
+module_exit(moschip7840_exit);
+
+/* Module information */
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index ac3f8b5d2c49..0610409a6568 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -32,7 +32,7 @@ static struct usb_driver navman_driver = {
.no_dynamic_id = 1,
};
-static void navman_read_int_callback(struct urb *urb, struct pt_regs *regs)
+static void navman_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
unsigned char *data = urb->transfer_buffer;
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index e49f40913c27..bc91d3b726fc 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -64,8 +64,8 @@ static int debug;
/* function prototypes */
static int omninet_open (struct usb_serial_port *port, struct file *filp);
static void omninet_close (struct usb_serial_port *port, struct file *filp);
-static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+static void omninet_read_bulk_callback (struct urb *urb);
+static void omninet_write_bulk_callback (struct urb *urb);
static int omninet_write (struct usb_serial_port *port, const unsigned char *buf, int count);
static int omninet_write_room (struct usb_serial_port *port);
static void omninet_shutdown (struct usb_serial *serial);
@@ -194,7 +194,7 @@ static void omninet_close (struct usb_serial_port *port, struct file * filp)
#define OMNINET_HEADERLEN sizeof(struct omninet_header)
#define OMNINET_BULKOUTSIZE (64 - OMNINET_HEADERLEN)
-static void omninet_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void omninet_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -256,14 +256,14 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
return (0);
}
- spin_lock(&wport->lock);
+ spin_lock_bh(&wport->lock);
if (wport->write_urb_busy) {
- spin_unlock(&wport->lock);
+ spin_unlock_bh(&wport->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
wport->write_urb_busy = 1;
- spin_unlock(&wport->lock);
+ spin_unlock_bh(&wport->lock);
count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
@@ -306,7 +306,7 @@ static int omninet_write_room (struct usb_serial_port *port)
return (room);
}
-static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void omninet_write_bulk_callback (struct urb *urb)
{
/* struct omninet_header *header = (struct omninet_header *) urb->transfer_buffer; */
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index c856e6f40e22..130afbbd3fca 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -50,7 +50,7 @@ static void option_rx_throttle(struct usb_serial_port *port);
static void option_rx_unthrottle(struct usb_serial_port *port);
static int option_write_room(struct usb_serial_port *port);
-static void option_instat_callback(struct urb *urb, struct pt_regs *regs);
+static void option_instat_callback(struct urb *urb);
static int option_write(struct usb_serial_port *port,
const unsigned char *buf, int count);
@@ -337,7 +337,7 @@ static int option_write(struct usb_serial_port *port,
return count;
}
-static void option_indat_callback(struct urb *urb, struct pt_regs *regs)
+static void option_indat_callback(struct urb *urb)
{
int err;
int endpoint;
@@ -374,7 +374,7 @@ static void option_indat_callback(struct urb *urb, struct pt_regs *regs)
return;
}
-static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
+static void option_outdat_callback(struct urb *urb)
{
struct usb_serial_port *port;
@@ -385,7 +385,7 @@ static void option_outdat_callback(struct urb *urb, struct pt_regs *regs)
usb_serial_port_softint(port);
}
-static void option_instat_callback(struct urb *urb, struct pt_regs *regs)
+static void option_instat_callback(struct urb *urb)
{
int err;
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
@@ -565,7 +565,7 @@ static void option_close(struct usb_serial_port *port, struct file *filp)
/* Helper functions used by option_setup_urbs */
static struct urb *option_setup_urb(struct usb_serial *serial, int endpoint,
int dir, void *ctx, char *buf, int len,
- void (*callback)(struct urb *, struct pt_regs *regs))
+ void (*callback)(struct urb *))
{
struct urb *urb;
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 65e4d046951a..bc800c8787a8 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -81,10 +81,12 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(SPEEDDRAGON_VENDOR_ID, SPEEDDRAGON_PRODUCT_ID) },
{ USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) },
{ USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) },
+ { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) },
+ { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, id_table);
+MODULE_DEVICE_TABLE(usb, id_table);
static struct usb_driver pl2303_driver = {
.name = "pl2303",
@@ -127,65 +129,6 @@ static struct usb_driver pl2303_driver = {
#define UART_OVERRUN_ERROR 0x40
#define UART_CTS 0x80
-/* function prototypes for a PL2303 serial converter */
-static int pl2303_open (struct usb_serial_port *port, struct file *filp);
-static void pl2303_close (struct usb_serial_port *port, struct file *filp);
-static void pl2303_set_termios (struct usb_serial_port *port,
- struct termios *old);
-static int pl2303_ioctl (struct usb_serial_port *port, struct file *file,
- unsigned int cmd, unsigned long arg);
-static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs);
-static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static int pl2303_write (struct usb_serial_port *port,
- const unsigned char *buf, int count);
-static void pl2303_send (struct usb_serial_port *port);
-static int pl2303_write_room(struct usb_serial_port *port);
-static int pl2303_chars_in_buffer(struct usb_serial_port *port);
-static void pl2303_break_ctl(struct usb_serial_port *port,int break_state);
-static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file);
-static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
- unsigned int set, unsigned int clear);
-static int pl2303_startup (struct usb_serial *serial);
-static void pl2303_shutdown (struct usb_serial *serial);
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size);
-static void pl2303_buf_free(struct pl2303_buf *pb);
-static void pl2303_buf_clear(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb);
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
- unsigned int count);
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
- unsigned int count);
-
-
-/* All of the device info needed for the PL2303 SIO serial converter */
-static struct usb_serial_driver pl2303_device = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "pl2303",
- },
- .id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = 1,
- .num_bulk_out = 1,
- .num_ports = 1,
- .open = pl2303_open,
- .close = pl2303_close,
- .write = pl2303_write,
- .ioctl = pl2303_ioctl,
- .break_ctl = pl2303_break_ctl,
- .set_termios = pl2303_set_termios,
- .tiocmget = pl2303_tiocmget,
- .tiocmset = pl2303_tiocmset,
- .read_bulk_callback = pl2303_read_bulk_callback,
- .read_int_callback = pl2303_read_int_callback,
- .write_bulk_callback = pl2303_write_bulk_callback,
- .write_room = pl2303_write_room,
- .chars_in_buffer = pl2303_chars_in_buffer,
- .attach = pl2303_startup,
- .shutdown = pl2303_shutdown,
-};
enum pl2303_type {
type_0, /* don't know the difference between type 0 and */
@@ -204,8 +147,166 @@ struct pl2303_private {
enum pl2303_type type;
};
+/*
+ * pl2303_buf_alloc
+ *
+ * Allocate a circular buffer and all associated memory.
+ */
+static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
+{
+ struct pl2303_buf *pb;
+
+ if (size == 0)
+ return NULL;
+
+ pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
+ if (pb == NULL)
+ return NULL;
+
+ pb->buf_buf = kmalloc(size, GFP_KERNEL);
+ if (pb->buf_buf == NULL) {
+ kfree(pb);
+ return NULL;
+ }
+
+ pb->buf_size = size;
+ pb->buf_get = pb->buf_put = pb->buf_buf;
-static int pl2303_startup (struct usb_serial *serial)
+ return pb;
+}
+
+/*
+ * pl2303_buf_free
+ *
+ * Free the buffer and all associated memory.
+ */
+static void pl2303_buf_free(struct pl2303_buf *pb)
+{
+ if (pb) {
+ kfree(pb->buf_buf);
+ kfree(pb);
+ }
+}
+
+/*
+ * pl2303_buf_clear
+ *
+ * Clear out all data in the circular buffer.
+ */
+static void pl2303_buf_clear(struct pl2303_buf *pb)
+{
+ if (pb != NULL)
+ pb->buf_get = pb->buf_put;
+ /* equivalent to a get of all data available */
+}
+
+/*
+ * pl2303_buf_data_avail
+ *
+ * Return the number of bytes of data available in the circular
+ * buffer.
+ */
+static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
+{
+ if (pb == NULL)
+ return 0;
+
+ return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
+}
+
+/*
+ * pl2303_buf_space_avail
+ *
+ * Return the number of bytes of space available in the circular
+ * buffer.
+ */
+static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
+{
+ if (pb == NULL)
+ return 0;
+
+ return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
+}
+
+/*
+ * pl2303_buf_put
+ *
+ * Copy data data from a user buffer and put it into the circular buffer.
+ * Restrict to the amount of space available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_space_avail(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_put;
+ if (count > len) {
+ memcpy(pb->buf_put, buf, len);
+ memcpy(pb->buf_buf, buf+len, count - len);
+ pb->buf_put = pb->buf_buf + count - len;
+ } else {
+ memcpy(pb->buf_put, buf, count);
+ if (count < len)
+ pb->buf_put += count;
+ else /* count == len */
+ pb->buf_put = pb->buf_buf;
+ }
+
+ return count;
+}
+
+/*
+ * pl2303_buf_get
+ *
+ * Get data from the circular buffer and copy to the given buffer.
+ * Restrict to the amount of data available.
+ *
+ * Return the number of bytes copied.
+ */
+static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
+ unsigned int count)
+{
+ unsigned int len;
+
+ if (pb == NULL)
+ return 0;
+
+ len = pl2303_buf_data_avail(pb);
+ if (count > len)
+ count = len;
+
+ if (count == 0)
+ return 0;
+
+ len = pb->buf_buf + pb->buf_size - pb->buf_get;
+ if (count > len) {
+ memcpy(buf, pb->buf_get, len);
+ memcpy(buf+len, pb->buf_buf, count - len);
+ pb->buf_get = pb->buf_buf + count - len;
+ } else {
+ memcpy(buf, pb->buf_get, count);
+ if (count < len)
+ pb->buf_get += count;
+ else /* count == len */
+ pb->buf_get = pb->buf_buf;
+ }
+
+ return count;
+}
+
+static int pl2303_startup(struct usb_serial *serial)
{
struct pl2303_private *priv;
enum pl2303_type type = type_0;
@@ -247,36 +348,17 @@ cleanup:
return -ENOMEM;
}
-static int set_control_lines (struct usb_device *dev, u8 value)
+static int set_control_lines(struct usb_device *dev, u8 value)
{
int retval;
- retval = usb_control_msg (dev, usb_sndctrlpipe (dev, 0),
- SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
- value, 0, NULL, 0, 100);
+ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE,
+ value, 0, NULL, 0, 100);
dbg("%s - value = %d, retval = %d", __FUNCTION__, value, retval);
return retval;
}
-static int pl2303_write (struct usb_serial_port *port, const unsigned char *buf, int count)
-{
- struct pl2303_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
-
- dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
-
- if (!count)
- return count;
-
- spin_lock_irqsave(&priv->lock, flags);
- count = pl2303_buf_put(priv->buf, buf, count);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- pl2303_send(port);
-
- return count;
-}
-
static void pl2303_send(struct usb_serial_port *port)
{
int count, result;
@@ -293,7 +375,7 @@ static void pl2303_send(struct usb_serial_port *port)
}
count = pl2303_buf_get(priv->buf, port->write_urb->transfer_buffer,
- port->bulk_out_size);
+ port->bulk_out_size);
if (count == 0) {
spin_unlock_irqrestore(&priv->lock, flags);
@@ -304,13 +386,15 @@ static void pl2303_send(struct usb_serial_port *port)
spin_unlock_irqrestore(&priv->lock, flags);
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count, port->write_urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__, count,
+ port->write_urb->transfer_buffer);
port->write_urb->transfer_buffer_length = count;
port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&port->dev, "%s - failed submitting write urb,"
+ " error %d\n", __FUNCTION__, result);
priv->write_urb_in_use = 0;
// TODO: reschedule pl2303_send
}
@@ -318,6 +402,26 @@ static void pl2303_send(struct usb_serial_port *port)
usb_serial_port_softint(port);
}
+static int pl2303_write(struct usb_serial_port *port, const unsigned char *buf,
+ int count)
+{
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+
+ dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count);
+
+ if (!count)
+ return count;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ count = pl2303_buf_put(priv->buf, buf, count);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ pl2303_send(port);
+
+ return count;
+}
+
static int pl2303_write_room(struct usb_serial_port *port)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -350,7 +454,8 @@ static int pl2303_chars_in_buffer(struct usb_serial_port *port)
return chars;
}
-static void pl2303_set_termios (struct usb_serial_port *port, struct termios *old_termios)
+static void pl2303_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
{
struct usb_serial *serial = port->serial;
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -371,7 +476,8 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
spin_lock_irqsave(&priv->lock, flags);
if (!priv->termios_initialized) {
*(port->tty->termios) = tty_std_termios;
- port->tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ port->tty->termios->c_cflag = B9600 | CS8 | CREAD |
+ HUPCL | CLOCAL;
priv->termios_initialized = 1;
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -380,24 +486,24 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
/* check that they really want us to change something */
if (old_termios) {
if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg("%s - nothing to change...", __FUNCTION__);
- return;
+ (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
+ RELEVANT_IFLAG(old_termios->c_iflag))) {
+ dbg("%s - nothing to change...", __FUNCTION__);
+ return;
}
}
- buf = kzalloc (7, GFP_KERNEL);
+ buf = kzalloc(7, GFP_KERNEL);
if (!buf) {
dev_err(&port->dev, "%s - out of memory.\n", __FUNCTION__);
return;
}
-
- i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
+ i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CSIZE) {
switch (cflag & CSIZE) {
@@ -429,7 +535,8 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
case B230400: baud = 230400; break;
case B460800: baud = 460800; break;
default:
- dev_err(&port->dev, "pl2303 driver does not support the baudrate requested (fix it)\n");
+ dev_err(&port->dev, "pl2303 driver does not support"
+ " the baudrate requested (fix it)\n");
break;
}
dbg("%s - baud = %d", __FUNCTION__, baud);
@@ -469,10 +576,10 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
dbg("%s - parity = none", __FUNCTION__);
}
- i = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
- SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dbg ("0x21:0x20:0:0 %d", i);
+ i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ dbg("0x21:0x20:0:0 %d", i);
/* change control lines if we are switching to or from B0 */
spin_lock_irqsave(&priv->lock, flags);
@@ -488,13 +595,13 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
} else {
spin_unlock_irqrestore(&priv->lock, flags);
}
-
+
buf[0] = buf[1] = buf[2] = buf[3] = buf[4] = buf[5] = buf[6] = 0;
- i = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
- GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
- 0, 0, buf, 7, 100);
- dbg ("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
+ i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE,
+ 0, 0, buf, 7, 100);
+ dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i,
buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
if (cflag & CRTSCTS) {
@@ -503,18 +610,82 @@ static void pl2303_set_termios (struct usb_serial_port *port, struct termios *ol
index = 0x61;
else
index = 0x41;
- i = usb_control_msg(serial->dev,
+ i = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
VENDOR_WRITE_REQUEST,
VENDOR_WRITE_REQUEST_TYPE,
0x0, index, NULL, 0, 100);
- dbg ("0x40:0x1:0x0:0x%x %d", index, i);
+ dbg("0x40:0x1:0x0:0x%x %d", index, i);
+ }
+
+ kfree(buf);
+}
+
+static void pl2303_close(struct usb_serial_port *port, struct file *filp)
+{
+ struct pl2303_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int c_cflag;
+ int bps;
+ long timeout;
+ wait_queue_t wait;
+
+ dbg("%s - port %d", __FUNCTION__, port->number);
+
+ /* wait for data to drain from the buffer */
+ spin_lock_irqsave(&priv->lock, flags);
+ timeout = PL2303_CLOSING_WAIT;
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&port->tty->write_wait, &wait);
+ for (;;) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (pl2303_buf_data_avail(priv->buf) == 0 ||
+ timeout == 0 || signal_pending(current) ||
+ !usb_get_intfdata(port->serial->interface)) /* disconnect */
+ break;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ timeout = schedule_timeout(timeout);
+ spin_lock_irqsave(&priv->lock, flags);
}
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&port->tty->write_wait, &wait);
+ /* clear out any remaining data in the buffer */
+ pl2303_buf_clear(priv->buf);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* wait for characters to drain from the device */
+ /* (this is long enough for the entire 256 byte */
+ /* pl2303 hardware buffer to drain with no flow */
+ /* control for data rates of 1200 bps or more, */
+ /* for lower rates we should really know how much */
+ /* data is in the buffer to compute a delay */
+ /* that is not unnecessarily long) */
+ bps = tty_get_baud_rate(port->tty);
+ if (bps > 1200)
+ timeout = max((HZ*2560)/bps,HZ/10);
+ else
+ timeout = 2*HZ;
+ schedule_timeout_interruptible(timeout);
- kfree (buf);
+ /* shutdown our urbs */
+ dbg("%s - shutting down urbs", __FUNCTION__);
+ usb_kill_urb(port->write_urb);
+ usb_kill_urb(port->read_urb);
+ usb_kill_urb(port->interrupt_in_urb);
+
+ if (port->tty) {
+ c_cflag = port->tty->termios->c_cflag;
+ if (c_cflag & HUPCL) {
+ /* drop DTR and RTS */
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->line_control = 0;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ set_control_lines(port->serial->dev, 0);
+ }
+ }
}
-static int pl2303_open (struct usb_serial_port *port, struct file *filp)
+static int pl2303_open(struct usb_serial_port *port, struct file *filp)
{
struct termios tmp_termios;
struct usb_serial *serial = port->serial;
@@ -568,98 +739,35 @@ static int pl2303_open (struct usb_serial_port *port, struct file *filp)
/* Setup termios */
if (port->tty) {
- pl2303_set_termios (port, &tmp_termios);
+ pl2303_set_termios(port, &tmp_termios);
}
//FIXME: need to assert RTS and DTR if CRTSCTS off
dbg("%s - submitting read urb", __FUNCTION__);
port->read_urb->dev = serial->dev;
- result = usb_submit_urb (port->read_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->read_urb, GFP_KERNEL);
if (result) {
- dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result);
- pl2303_close (port, NULL);
+ dev_err(&port->dev, "%s - failed submitting read urb,"
+ " error %d\n", __FUNCTION__, result);
+ pl2303_close(port, NULL);
return -EPROTO;
}
dbg("%s - submitting interrupt urb", __FUNCTION__);
port->interrupt_in_urb->dev = serial->dev;
- result = usb_submit_urb (port->interrupt_in_urb, GFP_KERNEL);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
if (result) {
- dev_err(&port->dev, "%s - failed submitting interrupt urb, error %d\n", __FUNCTION__, result);
- pl2303_close (port, NULL);
+ dev_err(&port->dev, "%s - failed submitting interrupt urb,"
+ " error %d\n", __FUNCTION__, result);
+ pl2303_close(port, NULL);
return -EPROTO;
}
return 0;
}
-
-static void pl2303_close (struct usb_serial_port *port, struct file *filp)
-{
- struct pl2303_private *priv = usb_get_serial_port_data(port);
- unsigned long flags;
- unsigned int c_cflag;
- int bps;
- long timeout;
- wait_queue_t wait;
-
- dbg("%s - port %d", __FUNCTION__, port->number);
-
- /* wait for data to drain from the buffer */
- spin_lock_irqsave(&priv->lock, flags);
- timeout = PL2303_CLOSING_WAIT;
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&port->tty->write_wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (pl2303_buf_data_avail(priv->buf) == 0
- || timeout == 0 || signal_pending(current)
- || !usb_get_intfdata(port->serial->interface)) /* disconnect */
- break;
- spin_unlock_irqrestore(&priv->lock, flags);
- timeout = schedule_timeout(timeout);
- spin_lock_irqsave(&priv->lock, flags);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&port->tty->write_wait, &wait);
- /* clear out any remaining data in the buffer */
- pl2303_buf_clear(priv->buf);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* wait for characters to drain from the device */
- /* (this is long enough for the entire 256 byte */
- /* pl2303 hardware buffer to drain with no flow */
- /* control for data rates of 1200 bps or more, */
- /* for lower rates we should really know how much */
- /* data is in the buffer to compute a delay */
- /* that is not unnecessarily long) */
- bps = tty_get_baud_rate(port->tty);
- if (bps > 1200)
- timeout = max((HZ*2560)/bps,HZ/10);
- else
- timeout = 2*HZ;
- schedule_timeout_interruptible(timeout);
-
- /* shutdown our urbs */
- dbg("%s - shutting down urbs", __FUNCTION__);
- usb_kill_urb(port->write_urb);
- usb_kill_urb(port->read_urb);
- usb_kill_urb(port->interrupt_in_urb);
-
- if (port->tty) {
- c_cflag = port->tty->termios->c_cflag;
- if (c_cflag & HUPCL) {
- /* drop DTR and RTS */
- spin_lock_irqsave(&priv->lock, flags);
- priv->line_control = 0;
- spin_unlock_irqrestore (&priv->lock, flags);
- set_control_lines (port->serial->dev, 0);
- }
- }
-}
-
-static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
- unsigned int set, unsigned int clear)
+static int pl2303_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
@@ -668,7 +776,7 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
if (!usb_get_intfdata(port->serial->interface))
return -ENODEV;
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
if (set & TIOCM_RTS)
priv->line_control |= CONTROL_RTS;
if (set & TIOCM_DTR)
@@ -678,12 +786,12 @@ static int pl2303_tiocmset (struct usb_serial_port *port, struct file *file,
if (clear & TIOCM_DTR)
priv->line_control &= ~CONTROL_DTR;
control = priv->line_control;
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
- return set_control_lines (port->serial->dev, control);
+ return set_control_lines(port->serial->dev, control);
}
-static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
+static int pl2303_tiocmget(struct usb_serial_port *port, struct file *file)
{
struct pl2303_private *priv = usb_get_serial_port_data(port);
unsigned long flags;
@@ -696,10 +804,10 @@ static int pl2303_tiocmget (struct usb_serial_port *port, struct file *file)
if (!usb_get_intfdata(port->serial->interface))
return -ENODEV;
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
mcr = priv->line_control;
status = priv->line_status;
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
result = ((mcr & CONTROL_DTR) ? TIOCM_DTR : 0)
| ((mcr & CONTROL_RTS) ? TIOCM_RTS : 0)
@@ -721,22 +829,22 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
unsigned int status;
unsigned int changed;
- spin_lock_irqsave (&priv->lock, flags);
+ spin_lock_irqsave(&priv->lock, flags);
prevstatus = priv->line_status;
- spin_unlock_irqrestore (&priv->lock, flags);
+ spin_unlock_irqrestore(&priv->lock, flags);
while (1) {
interruptible_sleep_on(&priv->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
-
- spin_lock_irqsave (&priv->lock, flags);
+
+ spin_lock_irqsave(&priv->lock, flags);
status = priv->line_status;
- spin_unlock_irqrestore (&priv->lock, flags);
-
+ spin_unlock_irqrestore(&priv->lock, flags);
+
changed=prevstatus^status;
-
+
if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
((arg & TIOCM_CD) && (changed & UART_DCD)) ||
@@ -749,7 +857,8 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
return 0;
}
-static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg)
+static int pl2303_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
{
dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
@@ -766,7 +875,7 @@ static int pl2303_ioctl (struct usb_serial_port *port, struct file *file, unsign
return -ENOIOCTLCMD;
}
-static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
+static void pl2303_break_ctl(struct usb_serial_port *port, int break_state)
{
struct usb_serial *serial = port->serial;
u16 state;
@@ -780,15 +889,14 @@ static void pl2303_break_ctl (struct usb_serial_port *port, int break_state)
state = BREAK_ON;
dbg("%s - turning break %s", __FUNCTION__, state==BREAK_OFF ? "off" : "on");
- result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
- BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
- 0, NULL, 0, 100);
+ result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ BREAK_REQUEST, BREAK_REQUEST_TYPE, state,
+ 0, NULL, 0, 100);
if (result)
dbg("%s - error sending break = %d", __FUNCTION__, result);
}
-
-static void pl2303_shutdown (struct usb_serial *serial)
+static void pl2303_shutdown(struct usb_serial *serial)
{
int i;
struct pl2303_private *priv;
@@ -802,7 +910,7 @@ static void pl2303_shutdown (struct usb_serial *serial)
kfree(priv);
usb_set_serial_port_data(serial->port[i], NULL);
}
- }
+ }
}
static void pl2303_update_line_status(struct usb_serial_port *port,
@@ -814,29 +922,33 @@ static void pl2303_update_line_status(struct usb_serial_port *port,
unsigned long flags;
u8 status_idx = UART_STATE;
u8 length = UART_STATE + 1;
+ u16 idv, idp;
+
+ idv = le16_to_cpu(port->serial->dev->descriptor.idVendor);
+ idp = le16_to_cpu(port->serial->dev->descriptor.idProduct);
- if ((le16_to_cpu(port->serial->dev->descriptor.idVendor) == SIEMENS_VENDOR_ID) &&
- (le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X65 ||
- le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_SX1 ||
- le16_to_cpu(port->serial->dev->descriptor.idProduct) == SIEMENS_PRODUCT_ID_X75)) {
- length = 1;
- status_idx = 0;
+
+ if (idv == SIEMENS_VENDOR_ID) {
+ if (idp == SIEMENS_PRODUCT_ID_X65 ||
+ idp == SIEMENS_PRODUCT_ID_SX1 ||
+ idp == SIEMENS_PRODUCT_ID_X75) {
+
+ length = 1;
+ status_idx = 0;
+ }
}
if (actual_length < length)
- goto exit;
+ return;
/* Save off the uart status for others to look at */
spin_lock_irqsave(&priv->lock, flags);
priv->line_status = data[status_idx];
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible (&priv->delta_msr_wait);
-
-exit:
- return;
+ wake_up_interruptible(&priv->delta_msr_wait);
}
-static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
+static void pl2303_read_int_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -853,25 +965,29 @@ static void pl2303_read_int_callback (struct urb *urb, struct pt_regs *regs)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__,
+ urb->status);
goto exit;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, urb->transfer_buffer);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ urb->actual_length, urb->transfer_buffer);
+
pl2303_update_line_status(port, data, actual_length);
exit:
- status = usb_submit_urb (urb, GFP_ATOMIC);
+ status = usb_submit_urb(urb, GFP_ATOMIC);
if (status)
- dev_err(&urb->dev->dev, "%s - usb_submit_urb failed with result %d\n",
+ dev_err(&urb->dev->dev,
+ "%s - usb_submit_urb failed with result %d\n",
__FUNCTION__, status);
}
-
-static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void pl2303_read_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -892,20 +1008,25 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
return;
}
if (urb->status == -EPROTO) {
- /* PL2303 mysteriously fails with -EPROTO reschedule the read */
- dbg("%s - caught -EPROTO, resubmitting the urb", __FUNCTION__);
+ /* PL2303 mysteriously fails with -EPROTO reschedule
+ * the read */
+ dbg("%s - caught -EPROTO, resubmitting the urb",
+ __FUNCTION__);
urb->status = 0;
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed"
+ " resubmitting read urb, error %d\n",
+ __FUNCTION__, result);
return;
}
dbg("%s - unable to handle the error, exiting.", __FUNCTION__);
return;
}
- usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
+ usb_serial_debug_data(debug, &port->dev, __FUNCTION__,
+ urb->actual_length, data);
/* get tty_flag from status */
tty_flag = TTY_NORMAL;
@@ -914,7 +1035,7 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
status = priv->line_status;
priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
spin_unlock_irqrestore(&priv->lock, flags);
- wake_up_interruptible (&priv->delta_msr_wait);
+ wake_up_interruptible(&priv->delta_msr_wait);
/* break takes precedence over parity, */
/* which takes precedence over framing errors */
@@ -933,8 +1054,8 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
if (status & UART_OVERRUN_ERROR)
tty_insert_flip_char(tty, 0, TTY_OVERRUN);
for (i = 0; i < urb->actual_length; ++i)
- tty_insert_flip_char (tty, data[i], tty_flag);
- tty_flip_buffer_push (tty);
+ tty_insert_flip_char(tty, data[i], tty_flag);
+ tty_flip_buffer_push(tty);
}
/* Schedule the next read _if_ we are still open */
@@ -942,15 +1063,14 @@ static void pl2303_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
urb->dev = port->serial->dev;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed resubmitting"
+ " read urb, error %d\n", __FUNCTION__, result);
}
return;
}
-
-
-static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void pl2303_write_bulk_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
struct pl2303_private *priv = usb_get_serial_port_data(port);
@@ -966,18 +1086,21 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__,
+ urb->status);
priv->write_urb_in_use = 0;
return;
default:
/* error in the urb, so we have to resubmit it */
dbg("%s - Overflow in write", __FUNCTION__);
- dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero write bulk status received: %d", __FUNCTION__,
+ urb->status);
port->write_urb->transfer_buffer_length = 1;
port->write_urb->dev = port->serial->dev;
- result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
+ result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result)
- dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result);
+ dev_err(&urb->dev->dev, "%s - failed resubmitting write"
+ " urb, error %d\n", __FUNCTION__, result);
else
return;
}
@@ -988,191 +1111,38 @@ static void pl2303_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
pl2303_send(port);
}
+/* All of the device info needed for the PL2303 SIO serial converter */
+static struct usb_serial_driver pl2303_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pl2303",
+ },
+ .id_table = id_table,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = pl2303_open,
+ .close = pl2303_close,
+ .write = pl2303_write,
+ .ioctl = pl2303_ioctl,
+ .break_ctl = pl2303_break_ctl,
+ .set_termios = pl2303_set_termios,
+ .tiocmget = pl2303_tiocmget,
+ .tiocmset = pl2303_tiocmset,
+ .read_bulk_callback = pl2303_read_bulk_callback,
+ .read_int_callback = pl2303_read_int_callback,
+ .write_bulk_callback = pl2303_write_bulk_callback,
+ .write_room = pl2303_write_room,
+ .chars_in_buffer = pl2303_chars_in_buffer,
+ .attach = pl2303_startup,
+ .shutdown = pl2303_shutdown,
+};
-/*
- * pl2303_buf_alloc
- *
- * Allocate a circular buffer and all associated memory.
- */
-
-static struct pl2303_buf *pl2303_buf_alloc(unsigned int size)
-{
-
- struct pl2303_buf *pb;
-
-
- if (size == 0)
- return NULL;
-
- pb = (struct pl2303_buf *)kmalloc(sizeof(struct pl2303_buf), GFP_KERNEL);
- if (pb == NULL)
- return NULL;
-
- pb->buf_buf = kmalloc(size, GFP_KERNEL);
- if (pb->buf_buf == NULL) {
- kfree(pb);
- return NULL;
- }
-
- pb->buf_size = size;
- pb->buf_get = pb->buf_put = pb->buf_buf;
-
- return pb;
-
-}
-
-
-/*
- * pl2303_buf_free
- *
- * Free the buffer and all associated memory.
- */
-
-static void pl2303_buf_free(struct pl2303_buf *pb)
-{
- if (pb) {
- kfree(pb->buf_buf);
- kfree(pb);
- }
-}
-
-
-/*
- * pl2303_buf_clear
- *
- * Clear out all data in the circular buffer.
- */
-
-static void pl2303_buf_clear(struct pl2303_buf *pb)
-{
- if (pb != NULL)
- pb->buf_get = pb->buf_put;
- /* equivalent to a get of all data available */
-}
-
-
-/*
- * pl2303_buf_data_avail
- *
- * Return the number of bytes of data available in the circular
- * buffer.
- */
-
-static unsigned int pl2303_buf_data_avail(struct pl2303_buf *pb)
-{
- if (pb != NULL)
- return ((pb->buf_size + pb->buf_put - pb->buf_get) % pb->buf_size);
- else
- return 0;
-}
-
-
-/*
- * pl2303_buf_space_avail
- *
- * Return the number of bytes of space available in the circular
- * buffer.
- */
-
-static unsigned int pl2303_buf_space_avail(struct pl2303_buf *pb)
-{
- if (pb != NULL)
- return ((pb->buf_size + pb->buf_get - pb->buf_put - 1) % pb->buf_size);
- else
- return 0;
-}
-
-
-/*
- * pl2303_buf_put
- *
- * Copy data data from a user buffer and put it into the circular buffer.
- * Restrict to the amount of space available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int pl2303_buf_put(struct pl2303_buf *pb, const char *buf,
- unsigned int count)
-{
-
- unsigned int len;
-
-
- if (pb == NULL)
- return 0;
-
- len = pl2303_buf_space_avail(pb);
- if (count > len)
- count = len;
-
- if (count == 0)
- return 0;
-
- len = pb->buf_buf + pb->buf_size - pb->buf_put;
- if (count > len) {
- memcpy(pb->buf_put, buf, len);
- memcpy(pb->buf_buf, buf+len, count - len);
- pb->buf_put = pb->buf_buf + count - len;
- } else {
- memcpy(pb->buf_put, buf, count);
- if (count < len)
- pb->buf_put += count;
- else /* count == len */
- pb->buf_put = pb->buf_buf;
- }
-
- return count;
-
-}
-
-
-/*
- * pl2303_buf_get
- *
- * Get data from the circular buffer and copy to the given buffer.
- * Restrict to the amount of data available.
- *
- * Return the number of bytes copied.
- */
-
-static unsigned int pl2303_buf_get(struct pl2303_buf *pb, char *buf,
- unsigned int count)
-{
-
- unsigned int len;
-
-
- if (pb == NULL)
- return 0;
-
- len = pl2303_buf_data_avail(pb);
- if (count > len)
- count = len;
-
- if (count == 0)
- return 0;
-
- len = pb->buf_buf + pb->buf_size - pb->buf_get;
- if (count > len) {
- memcpy(buf, pb->buf_get, len);
- memcpy(buf+len, pb->buf_buf, count - len);
- pb->buf_get = pb->buf_buf + count - len;
- } else {
- memcpy(buf, pb->buf_get, count);
- if (count < len)
- pb->buf_get += count;
- else /* count == len */
- pb->buf_get = pb->buf_buf;
- }
-
- return count;
-
-}
-
-static int __init pl2303_init (void)
+static int __init pl2303_init(void)
{
int retval;
+
retval = usb_serial_register(&pl2303_device);
if (retval)
goto failed_usb_serial_register;
@@ -1187,14 +1157,12 @@ failed_usb_serial_register:
return retval;
}
-
-static void __exit pl2303_exit (void)
+static void __exit pl2303_exit(void)
{
- usb_deregister (&pl2303_driver);
- usb_serial_deregister (&pl2303_device);
+ usb_deregister(&pl2303_driver);
+ usb_serial_deregister(&pl2303_device);
}
-
module_init(pl2303_init);
module_exit(pl2303_exit);
diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h
index 55195e76eb6f..65a5039665e7 100644
--- a/drivers/usb/serial/pl2303.h
+++ b/drivers/usb/serial/pl2303.h
@@ -89,3 +89,11 @@
/* Belkin "F5U257" Serial Adapter */
#define BELKIN_VENDOR_ID 0x050d
#define BELKIN_PRODUCT_ID 0x0257
+
+/* Alcor Micro Corp. USB 2.0 TO RS-232 */
+#define ALCOR_VENDOR_ID 0x058F
+#define ALCOR_PRODUCT_ID 0x9720
+
+/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */
+#define HUAWEI_VENDOR_ID 0x12d1
+#define HUAWEI_PRODUCT_ID 0x1001
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 789771ecdb11..30b7ebc8d45d 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -204,7 +204,7 @@ static __u16 __inline__ fcs_compute10 (unsigned char *sp, int len, __u16 fcs)
return fcs;
}
-static void safe_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void safe_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
unsigned char *data = urb->transfer_buffer;
@@ -298,14 +298,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
dbg ("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- spin_lock(&port->lock);
+ spin_lock_bh(&port->lock);
if (port->write_urb_busy) {
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
dbg("%s - already writing", __FUNCTION__);
return 0;
}
port->write_urb_busy = 1;
- spin_unlock(&port->lock);
+ spin_unlock_bh(&port->lock);
packet_length = port->bulk_out_size; // get max packetsize
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index d29638daa987..ea16572d19f8 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1,21 +1,35 @@
/*
- * Sierra Wireless CDMA Wireless Serial USB driver
- *
- * Current Copy modified by: Kevin Lloyd <linux@sierrawireless.com>
- * Original Copyright (C) 2005-2006 Greg Kroah-Hartman <gregkh@suse.de>
- *
- * 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.
- */
+ USB Driver for Sierra Wireless
+
+ Copyright (C) 2006 Kevin Lloyd <linux@sierrawireless.com>
+
+ IMPORTANT DISCLAIMER: This driver is not commercially supported by
+ Sierra Wireless. Use at your own risk.
+
+ This driver is free software; you can redistribute it and/or modify
+ it under the terms of Version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
+ Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
+
+ History:
+*/
+
+#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
+#define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
#include <linux/kernel.h>
-#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/errno.h>
#include <linux/tty.h>
+#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/serial.h>
+
static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
{ USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
@@ -23,53 +37,674 @@ static struct usb_device_id id_table [] = {
{ USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
{ USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
{ USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+ { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
{ USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
{ USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
- /* Following devices are supported in the airprime.c driver */
- /* { USB_DEVICE(0x1199, 0x0112) }, */ /* Sierra Wireless AirCard 580 */
- /* { USB_DEVICE(0x0F3D, 0x0112) }, */ /* AirPrime/Sierra PC 5220 */
+
+ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
+ { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
{ }
};
MODULE_DEVICE_TABLE(usb, id_table);
+static struct usb_device_id id_table_1port [] = {
+ { USB_DEVICE(0x1199, 0x0112) }, /* Sierra Wireless AirCard 580 */
+ { USB_DEVICE(0x0F3D, 0x0112) }, /* AirPrime/Sierra PC 5220 */
+ { }
+};
+
+static struct usb_device_id id_table_3port [] = {
+ { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+ { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
+ { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
+ { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
+ { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+ { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
+ { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
+ { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
+ { }
+};
+
static struct usb_driver sierra_driver = {
- .name = "sierra_wireless",
- .probe = usb_serial_probe,
- .disconnect = usb_serial_disconnect,
- .id_table = id_table,
+ .name = "sierra",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .no_dynamic_id = 1,
+};
+
+
+static int debug;
+
+/* per port private data */
+#define N_IN_URB 4
+#define N_OUT_URB 1
+#define IN_BUFLEN 4096
+#define OUT_BUFLEN 128
+
+struct sierra_port_private {
+ /* Input endpoints and buffer for this port */
+ struct urb *in_urbs[N_IN_URB];
+ char in_buffer[N_IN_URB][IN_BUFLEN];
+ /* Output endpoints and buffer for this port */
+ struct urb *out_urbs[N_OUT_URB];
+ char out_buffer[N_OUT_URB][OUT_BUFLEN];
+
+ /* Settings for the port */
+ int rts_state; /* Handshaking pins (outputs) */
+ int dtr_state;
+ int cts_state; /* Handshaking pins (inputs) */
+ int dsr_state;
+ int dcd_state;
+ int ri_state;
+
+ unsigned long tx_start_time[N_OUT_URB];
+};
+
+static int sierra_send_setup(struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ portdata = usb_get_serial_port_data(port);
+
+ if (port->tty) {
+ int val = 0;
+ if (portdata->dtr_state)
+ val |= 0x01;
+ if (portdata->rts_state)
+ val |= 0x02;
+
+ return usb_control_msg(serial->dev,
+ usb_rcvctrlpipe(serial->dev, 0),
+ 0x22,0x21,val,0,NULL,0,USB_CTRL_SET_TIMEOUT);
+ }
+
+ return 0;
+}
+
+static void sierra_rx_throttle(struct usb_serial_port *port)
+{
+ dbg("%s", __FUNCTION__);
+}
+
+static void sierra_rx_unthrottle(struct usb_serial_port *port)
+{
+ dbg("%s", __FUNCTION__);
+}
+
+static void sierra_break_ctl(struct usb_serial_port *port, int break_state)
+{
+ /* Unfortunately, I don't know how to send a break */
+ dbg("%s", __FUNCTION__);
+}
+
+static void sierra_set_termios(struct usb_serial_port *port,
+ struct termios *old_termios)
+{
+ dbg("%s", __FUNCTION__);
+
+ sierra_send_setup(port);
+}
+
+static int sierra_tiocmget(struct usb_serial_port *port, struct file *file)
+{
+ unsigned int value;
+ struct sierra_port_private *portdata;
+
+ portdata = usb_get_serial_port_data(port);
+
+ value = ((portdata->rts_state) ? TIOCM_RTS : 0) |
+ ((portdata->dtr_state) ? TIOCM_DTR : 0) |
+ ((portdata->cts_state) ? TIOCM_CTS : 0) |
+ ((portdata->dsr_state) ? TIOCM_DSR : 0) |
+ ((portdata->dcd_state) ? TIOCM_CAR : 0) |
+ ((portdata->ri_state) ? TIOCM_RNG : 0);
+
+ return value;
+}
+
+static int sierra_tiocmset(struct usb_serial_port *port, struct file *file,
+ unsigned int set, unsigned int clear)
+{
+ struct sierra_port_private *portdata;
+
+ portdata = usb_get_serial_port_data(port);
+
+ if (set & TIOCM_RTS)
+ portdata->rts_state = 1;
+ if (set & TIOCM_DTR)
+ portdata->dtr_state = 1;
+
+ if (clear & TIOCM_RTS)
+ portdata->rts_state = 0;
+ if (clear & TIOCM_DTR)
+ portdata->dtr_state = 0;
+ return sierra_send_setup(port);
+}
+
+static int sierra_ioctl(struct usb_serial_port *port, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return -ENOIOCTLCMD;
+}
+
+/* Write */
+static int sierra_write(struct usb_serial_port *port,
+ const unsigned char *buf, int count)
+{
+ struct sierra_port_private *portdata;
+ int i;
+ int left, todo;
+ struct urb *this_urb = NULL; /* spurious */
+ int err;
+
+ portdata = usb_get_serial_port_data(port);
+
+ dbg("%s: write (%d chars)", __FUNCTION__, count);
+
+ i = 0;
+ left = count;
+ for (i=0; left > 0 && i < N_OUT_URB; i++) {
+ todo = left;
+ if (todo > OUT_BUFLEN)
+ todo = OUT_BUFLEN;
+
+ this_urb = portdata->out_urbs[i];
+ if (this_urb->status == -EINPROGRESS) {
+ if (time_before(jiffies,
+ portdata->tx_start_time[i] + 10 * HZ))
+ continue;
+ usb_unlink_urb(this_urb);
+ continue;
+ }
+ if (this_urb->status != 0)
+ dbg("usb_write %p failed (err=%d)",
+ this_urb, this_urb->status);
+
+ dbg("%s: endpoint %d buf %d", __FUNCTION__,
+ usb_pipeendpoint(this_urb->pipe), i);
+
+ /* send the data */
+ memcpy (this_urb->transfer_buffer, buf, todo);
+ this_urb->transfer_buffer_length = todo;
+
+ this_urb->dev = port->serial->dev;
+ err = usb_submit_urb(this_urb, GFP_ATOMIC);
+ if (err) {
+ dbg("usb_submit_urb %p (write bulk) failed "
+ "(%d, has %d)", this_urb,
+ err, this_urb->status);
+ continue;
+ }
+ portdata->tx_start_time[i] = jiffies;
+ buf += todo;
+ left -= todo;
+ }
+
+ count -= left;
+ dbg("%s: wrote (did %d)", __FUNCTION__, count);
+ return count;
+}
+
+static void sierra_indat_callback(struct urb *urb)
+{
+ int err;
+ int endpoint;
+ struct usb_serial_port *port;
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+
+ dbg("%s: %p", __FUNCTION__, urb);
+
+ endpoint = usb_pipeendpoint(urb->pipe);
+ port = (struct usb_serial_port *) urb->context;
+
+ if (urb->status) {
+ dbg("%s: nonzero status: %d on endpoint %02x.",
+ __FUNCTION__, urb->status, endpoint);
+ } else {
+ tty = port->tty;
+ if (urb->actual_length) {
+ tty_buffer_request_room(tty, urb->actual_length);
+ tty_insert_flip_string(tty, data, urb->actual_length);
+ tty_flip_buffer_push(tty);
+ } else {
+ dbg("%s: empty read urb received", __FUNCTION__);
+ }
+
+ /* Resubmit urb so we continue receiving */
+ if (port->open_count && urb->status != -ESHUTDOWN) {
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err)
+ printk(KERN_ERR "%s: resubmit read urb failed. "
+ "(%d)", __FUNCTION__, err);
+ }
+ }
+ return;
+}
+
+static void sierra_outdat_callback(struct urb *urb)
+{
+ struct usb_serial_port *port;
+
+ dbg("%s", __FUNCTION__);
+
+ port = (struct usb_serial_port *) urb->context;
+
+ usb_serial_port_softint(port);
+}
+
+static void sierra_instat_callback(struct urb *urb)
+{
+ int err;
+ struct usb_serial_port *port = (struct usb_serial_port *) urb->context;
+ struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+
+ dbg("%s", __FUNCTION__);
+ dbg("%s: urb %p port %p has data %p", __FUNCTION__,urb,port,portdata);
+
+ if (urb->status == 0) {
+ struct usb_ctrlrequest *req_pkt =
+ (struct usb_ctrlrequest *)urb->transfer_buffer;
+
+ if (!req_pkt) {
+ dbg("%s: NULL req_pkt\n", __FUNCTION__);
+ return;
+ }
+ if ((req_pkt->bRequestType == 0xA1) &&
+ (req_pkt->bRequest == 0x20)) {
+ int old_dcd_state;
+ unsigned char signals = *((unsigned char *)
+ urb->transfer_buffer +
+ sizeof(struct usb_ctrlrequest));
+
+ dbg("%s: signal x%x", __FUNCTION__, signals);
+
+ old_dcd_state = portdata->dcd_state;
+ portdata->cts_state = 1;
+ portdata->dcd_state = ((signals & 0x01) ? 1 : 0);
+ portdata->dsr_state = ((signals & 0x02) ? 1 : 0);
+ portdata->ri_state = ((signals & 0x08) ? 1 : 0);
+
+ if (port->tty && !C_CLOCAL(port->tty) &&
+ old_dcd_state && !portdata->dcd_state)
+ tty_hangup(port->tty);
+ } else {
+ dbg("%s: type %x req %x", __FUNCTION__,
+ req_pkt->bRequestType,req_pkt->bRequest);
+ }
+ } else
+ dbg("%s: error %d", __FUNCTION__, urb->status);
+
+ /* Resubmit urb so we continue receiving IRQ data */
+ if (urb->status != -ESHUTDOWN) {
+ urb->dev = serial->dev;
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err)
+ dbg("%s: resubmit intr urb failed. (%d)",
+ __FUNCTION__, err);
+ }
+}
+
+static int sierra_write_room(struct usb_serial_port *port)
+{
+ struct sierra_port_private *portdata;
+ int i;
+ int data_len = 0;
+ struct urb *this_urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ for (i=0; i < N_OUT_URB; i++) {
+ this_urb = portdata->out_urbs[i];
+ if (this_urb && this_urb->status != -EINPROGRESS)
+ data_len += OUT_BUFLEN;
+ }
+
+ dbg("%s: %d", __FUNCTION__, data_len);
+ return data_len;
+}
+
+static int sierra_chars_in_buffer(struct usb_serial_port *port)
+{
+ struct sierra_port_private *portdata;
+ int i;
+ int data_len = 0;
+ struct urb *this_urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ for (i=0; i < N_OUT_URB; i++) {
+ this_urb = portdata->out_urbs[i];
+ if (this_urb && this_urb->status == -EINPROGRESS)
+ data_len += this_urb->transfer_buffer_length;
+ }
+ dbg("%s: %d", __FUNCTION__, data_len);
+ return data_len;
+}
+
+static int sierra_open(struct usb_serial_port *port, struct file *filp)
+{
+ struct sierra_port_private *portdata;
+ struct usb_serial *serial = port->serial;
+ int i, err;
+ struct urb *urb;
+
+ portdata = usb_get_serial_port_data(port);
+
+ dbg("%s", __FUNCTION__);
+
+ /* Set some sane defaults */
+ portdata->rts_state = 1;
+ portdata->dtr_state = 1;
+
+ /* Reset low level data toggle and start reading from endpoints */
+ for (i = 0; i < N_IN_URB; i++) {
+ urb = portdata->in_urbs[i];
+ if (! urb)
+ continue;
+ if (urb->dev != serial->dev) {
+ dbg("%s: dev %p != %p", __FUNCTION__,
+ urb->dev, serial->dev);
+ continue;
+ }
+
+ /*
+ * make sure endpoint data toggle is synchronized with the
+ * device
+ */
+ usb_clear_halt(urb->dev, urb->pipe);
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err) {
+ dbg("%s: submit urb %d failed (%d) %d",
+ __FUNCTION__, i, err,
+ urb->transfer_buffer_length);
+ }
+ }
+
+ /* Reset low level data toggle on out endpoints */
+ for (i = 0; i < N_OUT_URB; i++) {
+ urb = portdata->out_urbs[i];
+ if (! urb)
+ continue;
+ urb->dev = serial->dev;
+ /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+ usb_pipeout(urb->pipe), 0); */
+ }
+
+ port->tty->low_latency = 1;
+
+ sierra_send_setup(port);
+
+ return (0);
+}
+
+static inline void stop_urb(struct urb *urb)
+{
+ if (urb && urb->status == -EINPROGRESS)
+ usb_kill_urb(urb);
+}
+
+static void sierra_close(struct usb_serial_port *port, struct file *filp)
+{
+ int i;
+ struct usb_serial *serial = port->serial;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+ portdata = usb_get_serial_port_data(port);
+
+ portdata->rts_state = 0;
+ portdata->dtr_state = 0;
+
+ if (serial->dev) {
+ sierra_send_setup(port);
+
+ /* Stop reading/writing urbs */
+ for (i = 0; i < N_IN_URB; i++)
+ stop_urb(portdata->in_urbs[i]);
+ for (i = 0; i < N_OUT_URB; i++)
+ stop_urb(portdata->out_urbs[i]);
+ }
+ port->tty = NULL;
+}
+
+/* Helper functions used by sierra_setup_urbs */
+static struct urb *sierra_setup_urb(struct usb_serial *serial, int endpoint,
+ int dir, void *ctx, char *buf, int len,
+ usb_complete_t callback)
+{
+ struct urb *urb;
+
+ if (endpoint == -1)
+ return NULL; /* endpoint not needed */
+
+ urb = usb_alloc_urb(0, GFP_KERNEL); /* No ISO */
+ if (urb == NULL) {
+ dbg("%s: alloc for endpoint %d failed.", __FUNCTION__, endpoint);
+ return NULL;
+ }
+
+ /* Fill URB using supplied data. */
+ usb_fill_bulk_urb(urb, serial->dev,
+ usb_sndbulkpipe(serial->dev, endpoint) | dir,
+ buf, len, callback, ctx);
+
+ return urb;
+}
+
+/* Setup urbs */
+static void sierra_setup_urbs(struct usb_serial *serial)
+{
+ int i,j;
+ struct usb_serial_port *port;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+
+ /* Do indat endpoints first */
+ for (j = 0; j < N_IN_URB; ++j) {
+ portdata->in_urbs[j] = sierra_setup_urb (serial,
+ port->bulk_in_endpointAddress, USB_DIR_IN, port,
+ portdata->in_buffer[j], IN_BUFLEN, sierra_indat_callback);
+ }
+
+ /* outdat endpoints */
+ for (j = 0; j < N_OUT_URB; ++j) {
+ portdata->out_urbs[j] = sierra_setup_urb (serial,
+ port->bulk_out_endpointAddress, USB_DIR_OUT, port,
+ portdata->out_buffer[j], OUT_BUFLEN, sierra_outdat_callback);
+ }
+ }
+}
+
+static int sierra_startup(struct usb_serial *serial)
+{
+ int i, err;
+ struct usb_serial_port *port;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ /* Now setup per port private data */
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ portdata = kzalloc(sizeof(*portdata), GFP_KERNEL);
+ if (!portdata) {
+ dbg("%s: kmalloc for sierra_port_private (%d) failed!.",
+ __FUNCTION__, i);
+ return (1);
+ }
+
+ usb_set_serial_port_data(port, portdata);
+
+ if (! port->interrupt_in_urb)
+ continue;
+ err = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+ if (err)
+ dbg("%s: submit irq_in urb failed %d",
+ __FUNCTION__, err);
+ }
+
+ sierra_setup_urbs(serial);
+
+ return (0);
+}
+
+static void sierra_shutdown(struct usb_serial *serial)
+{
+ int i, j;
+ struct usb_serial_port *port;
+ struct sierra_port_private *portdata;
+
+ dbg("%s", __FUNCTION__);
+
+ /* Stop reading/writing urbs */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+ for (j = 0; j < N_IN_URB; j++)
+ stop_urb(portdata->in_urbs[j]);
+ for (j = 0; j < N_OUT_URB; j++)
+ stop_urb(portdata->out_urbs[j]);
+ }
+
+ /* Now free them */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+ portdata = usb_get_serial_port_data(port);
+
+ for (j = 0; j < N_IN_URB; j++) {
+ if (portdata->in_urbs[j]) {
+ usb_free_urb(portdata->in_urbs[j]);
+ portdata->in_urbs[j] = NULL;
+ }
+ }
+ for (j = 0; j < N_OUT_URB; j++) {
+ if (portdata->out_urbs[j]) {
+ usb_free_urb(portdata->out_urbs[j]);
+ portdata->out_urbs[j] = NULL;
+ }
+ }
+ }
+
+ /* Now free per port private data */
+ for (i = 0; i < serial->num_ports; i++) {
+ port = serial->port[i];
+ kfree(usb_get_serial_port_data(port));
+ }
+}
+
+static struct usb_serial_driver sierra_1port_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "sierra1",
+ },
+ .description = "Sierra USB modem (1 port)",
+ .id_table = id_table_1port,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 1,
+ .num_bulk_out = 1,
+ .num_ports = 1,
+ .open = sierra_open,
+ .close = sierra_close,
+ .write = sierra_write,
+ .write_room = sierra_write_room,
+ .chars_in_buffer = sierra_chars_in_buffer,
+ .throttle = sierra_rx_throttle,
+ .unthrottle = sierra_rx_unthrottle,
+ .ioctl = sierra_ioctl,
+ .set_termios = sierra_set_termios,
+ .break_ctl = sierra_break_ctl,
+ .tiocmget = sierra_tiocmget,
+ .tiocmset = sierra_tiocmset,
+ .attach = sierra_startup,
+ .shutdown = sierra_shutdown,
+ .read_int_callback = sierra_instat_callback,
};
-static struct usb_serial_driver sierra_device = {
+static struct usb_serial_driver sierra_3port_device = {
.driver = {
- .owner = THIS_MODULE,
- .name = "Sierra_Wireless",
+ .owner = THIS_MODULE,
+ .name = "sierra3",
},
- .id_table = id_table,
- .num_interrupt_in = NUM_DONT_CARE,
- .num_bulk_in = NUM_DONT_CARE,
- .num_bulk_out = NUM_DONT_CARE,
- .num_ports = 3,
+ .description = "Sierra USB modem (3 port)",
+ .id_table = id_table_3port,
+ .num_interrupt_in = NUM_DONT_CARE,
+ .num_bulk_in = 3,
+ .num_bulk_out = 3,
+ .num_ports = 3,
+ .open = sierra_open,
+ .close = sierra_close,
+ .write = sierra_write,
+ .write_room = sierra_write_room,
+ .chars_in_buffer = sierra_chars_in_buffer,
+ .throttle = sierra_rx_throttle,
+ .unthrottle = sierra_rx_unthrottle,
+ .ioctl = sierra_ioctl,
+ .set_termios = sierra_set_termios,
+ .break_ctl = sierra_break_ctl,
+ .tiocmget = sierra_tiocmget,
+ .tiocmset = sierra_tiocmset,
+ .attach = sierra_startup,
+ .shutdown = sierra_shutdown,
+ .read_int_callback = sierra_instat_callback,
};
+/* Functions used by new usb-serial code. */
static int __init sierra_init(void)
{
int retval;
-
- retval = usb_serial_register(&sierra_device);
+ retval = usb_serial_register(&sierra_1port_device);
+ if (retval)
+ goto failed_1port_device_register;
+ retval = usb_serial_register(&sierra_3port_device);
if (retval)
- return retval;
+ goto failed_3port_device_register;
+
+
retval = usb_register(&sierra_driver);
if (retval)
- usb_serial_deregister(&sierra_device);
+ goto failed_driver_register;
+
+ info(DRIVER_DESC ": " DRIVER_VERSION);
+
+ return 0;
+
+failed_driver_register:
+ usb_serial_deregister(&sierra_3port_device);
+failed_3port_device_register:
+ usb_serial_deregister(&sierra_1port_device);
+failed_1port_device_register:
return retval;
}
static void __exit sierra_exit(void)
{
- usb_deregister(&sierra_driver);
- usb_serial_deregister(&sierra_device);
+ usb_deregister (&sierra_driver);
+ usb_serial_deregister(&sierra_1port_device);
+ usb_serial_deregister(&sierra_3port_device);
}
module_init(sierra_init);
module_exit(sierra_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
+
+#ifdef CONFIG_USB_DEBUG
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug messages");
+#endif
+
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ac9b8ee52d44..07400c0c8a8c 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -166,9 +166,9 @@ static int ti_tiocmget(struct usb_serial_port *port, struct file *file);
static int ti_tiocmset(struct usb_serial_port *port, struct file *file,
unsigned int set, unsigned int clear);
static void ti_break(struct usb_serial_port *port, int break_state);
-static void ti_interrupt_callback(struct urb *urb, struct pt_regs *regs);
-static void ti_bulk_in_callback(struct urb *urb, struct pt_regs *regs);
-static void ti_bulk_out_callback(struct urb *urb, struct pt_regs *regs);
+static void ti_interrupt_callback(struct urb *urb);
+static void ti_bulk_in_callback(struct urb *urb);
+static void ti_bulk_out_callback(struct urb *urb);
static void ti_recv(struct device *dev, struct tty_struct *tty,
unsigned char *data, int length);
@@ -1098,7 +1098,7 @@ static void ti_break(struct usb_serial_port *port, int break_state)
}
-static void ti_interrupt_callback(struct urb *urb, struct pt_regs *regs)
+static void ti_interrupt_callback(struct urb *urb)
{
struct ti_device *tdev = (struct ti_device *)urb->context;
struct usb_serial_port *port;
@@ -1178,7 +1178,7 @@ exit:
}
-static void ti_bulk_in_callback(struct urb *urb, struct pt_regs *regs)
+static void ti_bulk_in_callback(struct urb *urb)
{
struct ti_port *tport = (struct ti_port *)urb->context;
struct usb_serial_port *port = tport->tp_port;
@@ -1241,7 +1241,7 @@ exit:
}
-static void ti_bulk_out_callback(struct urb *urb, struct pt_regs *regs)
+static void ti_bulk_out_callback(struct urb *urb)
{
struct ti_port *tport = (struct ti_port *)urb->context;
struct usb_serial_port *port = tport->tp_port;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index e06a41bd0f3b..8006e51c34bb 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -676,33 +676,29 @@ int usb_serial_probe(struct usb_interface *interface,
iface_desc = interface->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
+
+ if (usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
dbg("found bulk in on endpoint %d", i);
bulk_in_endpoint[num_bulk_in] = endpoint;
++num_bulk_in;
}
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x02)) {
+ if (usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dbg("found bulk out on endpoint %d", i);
bulk_out_endpoint[num_bulk_out] = endpoint;
++num_bulk_out;
}
-
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
+
+ if (usb_endpoint_is_int_in(endpoint)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in on endpoint %d", i);
interrupt_in_endpoint[num_interrupt_in] = endpoint;
++num_interrupt_in;
}
- if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
+ if (usb_endpoint_is_int_out(endpoint)) {
/* we found an interrupt out endpoint */
dbg("found interrupt out on endpoint %d", i);
interrupt_out_endpoint[num_interrupt_out] = endpoint;
@@ -716,14 +712,15 @@ int usb_serial_probe(struct usb_interface *interface,
if (((le16_to_cpu(dev->descriptor.idVendor) == PL2303_VENDOR_ID) &&
(le16_to_cpu(dev->descriptor.idProduct) == PL2303_PRODUCT_ID)) ||
((le16_to_cpu(dev->descriptor.idVendor) == ATEN_VENDOR_ID) &&
- (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID))) {
+ (le16_to_cpu(dev->descriptor.idProduct) == ATEN_PRODUCT_ID)) ||
+ ((le16_to_cpu(dev->descriptor.idVendor) == ALCOR_VENDOR_ID) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == ALCOR_PRODUCT_ID))) {
if (interface != dev->actconfig->interface[0]) {
/* check out the endpoints of the other interface*/
iface_desc = dev->actconfig->interface[0]->cur_altsetting;
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc;
- if ((endpoint->bEndpointAddress & 0x80) &&
- ((endpoint->bmAttributes & 3) == 0x03)) {
+ if (usb_endpoint_is_int_in(endpoint)) {
/* we found a interrupt in endpoint */
dbg("found interrupt in for Prolific device on separate interface");
interrupt_in_endpoint[num_interrupt_in] = endpoint;
@@ -937,7 +934,10 @@ int usb_serial_probe(struct usb_interface *interface,
snprintf (&port->dev.bus_id[0], sizeof(port->dev.bus_id), "ttyUSB%d", port->number);
dbg ("%s - registering %s", __FUNCTION__, port->dev.bus_id);
- device_register (&port->dev);
+ retval = device_register(&port->dev);
+ if (retval)
+ dev_err(&port->dev, "Error registering port device, "
+ "continuing\n");
}
usb_serial_console_init (debug, minor);
@@ -1015,7 +1015,7 @@ void usb_serial_disconnect(struct usb_interface *interface)
dev_info(dev, "device disconnected\n");
}
-static struct tty_operations serial_ops = {
+static const struct tty_operations serial_ops = {
.open = serial_open,
.close = serial_close,
.write = serial_write,
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 88949f7884ca..befe2e11a041 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -47,9 +47,9 @@ static int visor_calc_num_ports(struct usb_serial *serial);
static void visor_shutdown (struct usb_serial *serial);
static int visor_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
static void visor_set_termios (struct usb_serial_port *port, struct termios *old_termios);
-static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs);
+static void visor_write_bulk_callback (struct urb *urb);
+static void visor_read_bulk_callback (struct urb *urb);
+static void visor_read_int_callback (struct urb *urb);
static int clie_3_5_startup (struct usb_serial *serial);
static int treo_attach (struct usb_serial *serial);
static int clie_5_attach (struct usb_serial *serial);
@@ -471,7 +471,7 @@ static int visor_chars_in_buffer (struct usb_serial_port *port)
}
-static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void visor_write_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct visor_private *priv = usb_get_serial_port_data(port);
@@ -494,7 +494,7 @@ static void visor_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
}
-static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
+static void visor_read_bulk_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct visor_private *priv = usb_get_serial_port_data(port);
@@ -539,7 +539,7 @@ static void visor_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
return;
}
-static void visor_read_int_callback (struct urb *urb, struct pt_regs *regs)
+static void visor_read_int_callback (struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
int result;
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 6e6c7934be32..4d1cd7aeccd3 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -152,8 +152,8 @@ static void whiteheat_break_ctl (struct usb_serial_port *port, int break_state)
static int whiteheat_chars_in_buffer (struct usb_serial_port *port);
static void whiteheat_throttle (struct usb_serial_port *port);
static void whiteheat_unthrottle (struct usb_serial_port *port);
-static void whiteheat_read_callback (struct urb *urb, struct pt_regs *regs);
-static void whiteheat_write_callback (struct urb *urb, struct pt_regs *regs);
+static void whiteheat_read_callback (struct urb *urb);
+static void whiteheat_write_callback (struct urb *urb);
static struct usb_serial_driver whiteheat_fake_device = {
.driver = {
@@ -235,8 +235,8 @@ struct whiteheat_private {
/* local function prototypes */
static int start_command_port(struct usb_serial *serial);
static void stop_command_port(struct usb_serial *serial);
-static void command_port_write_callback(struct urb *urb, struct pt_regs *regs);
-static void command_port_read_callback(struct urb *urb, struct pt_regs *regs);
+static void command_port_write_callback(struct urb *urb);
+static void command_port_read_callback(struct urb *urb);
static int start_port_read(struct usb_serial_port *port);
static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, struct list_head *head);
@@ -958,7 +958,7 @@ static void whiteheat_unthrottle (struct usb_serial_port *port)
/*****************************************************************************
* Connect Tech's White Heat callback routines
*****************************************************************************/
-static void command_port_write_callback (struct urb *urb, struct pt_regs *regs)
+static void command_port_write_callback (struct urb *urb)
{
dbg("%s", __FUNCTION__);
@@ -969,7 +969,7 @@ static void command_port_write_callback (struct urb *urb, struct pt_regs *regs)
}
-static void command_port_read_callback (struct urb *urb, struct pt_regs *regs)
+static void command_port_read_callback (struct urb *urb)
{
struct usb_serial_port *command_port = (struct usb_serial_port *)urb->context;
struct whiteheat_command_private *command_info;
@@ -1019,7 +1019,7 @@ static void command_port_read_callback (struct urb *urb, struct pt_regs *regs)
}
-static void whiteheat_read_callback(struct urb *urb, struct pt_regs *regs)
+static void whiteheat_read_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct whiteheat_urb_wrap *wrap;
@@ -1061,7 +1061,7 @@ static void whiteheat_read_callback(struct urb *urb, struct pt_regs *regs)
}
-static void whiteheat_write_callback(struct urb *urb, struct pt_regs *regs)
+static void whiteheat_write_callback(struct urb *urb)
{
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct whiteheat_private *info = usb_get_serial_port_data(port);
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index be9eec225743..fe2c4cd53f5a 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -8,8 +8,7 @@ comment "may also be needed; see USB_STORAGE Help for more information"
config USB_STORAGE
tristate "USB Mass Storage support"
- depends on USB
- select SCSI
+ depends on USB && SCSI
---help---
Say Y here if you want to connect USB mass storage devices to your
computer's USB port. This is the driver you need for USB
@@ -18,7 +17,7 @@ config USB_STORAGE
similar devices. This driver may also be used for some cameras
and card readers.
- This option 'selects' (turns on, enables) 'SCSI', but you
+ This option depends on 'SCSI' support being enabled, but you
probably also need 'SCSI device support: SCSI disk support'
(BLK_DEV_SD) for most USB storage devices.
@@ -120,7 +119,7 @@ config USB_STORAGE_ALAUDA
Say Y here to include additional code to support the Olympus MAUSB-10
and Fujifilm DPC-R1 USB Card reader/writer devices.
- These devices are based on the Alauda chip and support support both
+ These devices are based on the Alauda chip and support both
XD and SmartMedia cards.
config USB_STORAGE_ONETOUCH
@@ -135,6 +134,18 @@ config USB_STORAGE_ONETOUCH
this input in any keybinding software. (e.g. gnome's keyboard short-
cuts)
+config USB_STORAGE_KARMA
+ bool "Support for Rio Karma music player"
+ depends on USB_STORAGE
+ help
+ Say Y here to include additional code to support the Rio Karma
+ USB interface.
+
+ This code places the Rio Karma into mass storage mode, enabling
+ it to be mounted as an ordinary filesystem. Performing an eject
+ on the resulting scsi device node returns the Karma to normal
+ operation.
+
config USB_LIBUSUAL
bool "The shared table of common (or usual) storage devices"
depends on USB
diff --git a/drivers/usb/storage/Makefile b/drivers/usb/storage/Makefile
index 8cbba22508a4..023969b4385b 100644
--- a/drivers/usb/storage/Makefile
+++ b/drivers/usb/storage/Makefile
@@ -20,6 +20,7 @@ usb-storage-obj-$(CONFIG_USB_STORAGE_DATAFAB) += datafab.o
usb-storage-obj-$(CONFIG_USB_STORAGE_JUMPSHOT) += jumpshot.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ALAUDA) += alauda.o
usb-storage-obj-$(CONFIG_USB_STORAGE_ONETOUCH) += onetouch.o
+usb-storage-obj-$(CONFIG_USB_STORAGE_KARMA) += karma.o
usb-storage-objs := scsiglue.o protocol.o transport.o usb.o \
initializers.o $(usb-storage-obj-y)
diff --git a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c
index ab173b30076e..5b06f9240d05 100644
--- a/drivers/usb/storage/initializers.c
+++ b/drivers/usb/storage/initializers.c
@@ -45,12 +45,6 @@
#include "debug.h"
#include "transport.h"
-#define RIO_MSC 0x08
-#define RIOP_INIT "RIOP\x00\x01\x08"
-#define RIOP_INIT_LEN 7
-#define RIO_SEND_LEN 40
-#define RIO_RECV_LEN 0x200
-
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
* mode */
int usb_stor_euscsi_init(struct us_data *us)
@@ -97,70 +91,3 @@ int usb_stor_ucr61s2b_init(struct us_data *us)
return (res ? -1 : 0);
}
-
-/* Place the Rio Karma into mass storage mode.
- *
- * The initialization begins by sending 40 bytes starting
- * RIOP\x00\x01\x08\x00, which the device will ack with a 512-byte
- * packet with the high four bits set and everything else null.
- *
- * Next, we send RIOP\x80\x00\x08\x00. Each time, a 512 byte response
- * must be read, but we must loop until byte 5 in the response is 0x08,
- * indicating success. */
-int rio_karma_init(struct us_data *us)
-{
- int result, partial;
- char *recv;
- unsigned long timeout;
-
- // us->iobuf is big enough to hold cmd but not receive
- if (!(recv = kmalloc(RIO_RECV_LEN, GFP_KERNEL)))
- goto die_nomem;
-
- US_DEBUGP("Initializing Karma...\n");
-
- memset(us->iobuf, 0, RIO_SEND_LEN);
- memcpy(us->iobuf, RIOP_INIT, RIOP_INIT_LEN);
-
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
- us->iobuf, RIO_SEND_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
- recv, RIO_RECV_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- us->iobuf[4] = 0x80;
- us->iobuf[5] = 0;
- timeout = jiffies + msecs_to_jiffies(3000);
- for (;;) {
- US_DEBUGP("Sending init command\n");
- result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
- us->iobuf, RIO_SEND_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
- recv, RIO_RECV_LEN, &partial);
- if (result != USB_STOR_XFER_GOOD)
- goto die;
-
- if (recv[5] == RIO_MSC)
- break;
- if (time_after(jiffies, timeout))
- goto die;
- msleep(10);
- }
- US_DEBUGP("Karma initialized.\n");
- kfree(recv);
- return 0;
-
-die:
- kfree(recv);
-die_nomem:
- US_DEBUGP("Could not initialize karma.\n");
- return USB_STOR_TRANSPORT_FAILED;
-}
-
diff --git a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h
index 927f7781080f..e2967a4d48a2 100644
--- a/drivers/usb/storage/initializers.h
+++ b/drivers/usb/storage/initializers.h
@@ -47,4 +47,3 @@ int usb_stor_euscsi_init(struct us_data *us);
/* This function is required to activate all four slots on the UCR-61S2B
* flash reader */
int usb_stor_ucr61s2b_init(struct us_data *us);
-int rio_karma_init(struct us_data *us);
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
new file mode 100644
index 000000000000..0d79ae5683f7
--- /dev/null
+++ b/drivers/usb/storage/karma.c
@@ -0,0 +1,155 @@
+/* Driver for Rio Karma
+ *
+ * (c) 2006 Bob Copeland <me@bobcopeland.com>
+ * (c) 2006 Keith Bennett <keith@mcs.st-and.ac.uk>
+ *
+ * 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.
+ */
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+
+#include "usb.h"
+#include "transport.h"
+#include "debug.h"
+#include "karma.h"
+
+#define RIO_PREFIX "RIOP\x00"
+#define RIO_PREFIX_LEN 5
+#define RIO_SEND_LEN 40
+#define RIO_RECV_LEN 0x200
+
+#define RIO_ENTER_STORAGE 0x1
+#define RIO_LEAVE_STORAGE 0x2
+#define RIO_RESET 0xC
+
+extern int usb_stor_Bulk_transport(struct scsi_cmnd *, struct us_data *);
+
+struct karma_data {
+ int in_storage;
+ char *recv;
+};
+
+/*
+ * Send commands to Rio Karma.
+ *
+ * For each command we send 40 bytes starting 'RIOP\0' followed by
+ * the command number and a sequence number, which the device will ack
+ * with a 512-byte packet with the high four bits set and everything
+ * else null. Then we send 'RIOP\x80' followed by a zero and the
+ * sequence number, until byte 5 in the response repeats the sequence
+ * number.
+ */
+static int rio_karma_send_command(char cmd, struct us_data *us)
+{
+ int result, partial;
+ unsigned long timeout;
+ static unsigned char seq = 1;
+ struct karma_data *data = (struct karma_data *) us->extra;
+
+ US_DEBUGP("karma: sending command %04x\n", cmd);
+ memset(us->iobuf, 0, RIO_SEND_LEN);
+ memcpy(us->iobuf, RIO_PREFIX, RIO_PREFIX_LEN);
+ us->iobuf[5] = cmd;
+ us->iobuf[6] = seq;
+
+ timeout = jiffies + msecs_to_jiffies(6000);
+ for (;;) {
+ result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+ us->iobuf, RIO_SEND_LEN, &partial);
+ if (result != USB_STOR_XFER_GOOD)
+ goto err;
+
+ result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+ data->recv, RIO_RECV_LEN, &partial);
+ if (result != USB_STOR_XFER_GOOD)
+ goto err;
+
+ if (data->recv[5] == seq)
+ break;
+
+ if (time_after(jiffies, timeout))
+ goto err;
+
+ us->iobuf[4] = 0x80;
+ us->iobuf[5] = 0;
+ msleep(50);
+ }
+
+ seq++;
+ if (seq == 0)
+ seq = 1;
+
+ US_DEBUGP("karma: sent command %04x\n", cmd);
+ return 0;
+err:
+ US_DEBUGP("karma: command %04x failed\n", cmd);
+ return USB_STOR_TRANSPORT_FAILED;
+}
+
+/*
+ * Trap START_STOP and READ_10 to leave/re-enter storage mode.
+ * Everything else is propagated to the normal bulk layer.
+ */
+int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us)
+{
+ int ret;
+ struct karma_data *data = (struct karma_data *) us->extra;
+
+ if (srb->cmnd[0] == READ_10 && !data->in_storage) {
+ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+ if (ret)
+ return ret;
+
+ data->in_storage = 1;
+ return usb_stor_Bulk_transport(srb, us);
+ } else if (srb->cmnd[0] == START_STOP) {
+ ret = rio_karma_send_command(RIO_LEAVE_STORAGE, us);
+ if (ret)
+ return ret;
+
+ data->in_storage = 0;
+ return rio_karma_send_command(RIO_RESET, us);
+ }
+ return usb_stor_Bulk_transport(srb, us);
+}
+
+static void rio_karma_destructor(void *extra)
+{
+ struct karma_data *data = (struct karma_data *) extra;
+ kfree(data->recv);
+}
+
+int rio_karma_init(struct us_data *us)
+{
+ int ret = 0;
+ struct karma_data *data = kzalloc(sizeof(struct karma_data), GFP_NOIO);
+ if (!data)
+ goto out;
+
+ data->recv = kmalloc(RIO_RECV_LEN, GFP_NOIO);
+ if (!data->recv) {
+ kfree(data);
+ goto out;
+ }
+
+ us->extra = data;
+ us->extra_destructor = rio_karma_destructor;
+ ret = rio_karma_send_command(RIO_ENTER_STORAGE, us);
+ data->in_storage = (ret == 0);
+out:
+ return ret;
+}
diff --git a/drivers/usb/storage/karma.h b/drivers/usb/storage/karma.h
new file mode 100644
index 000000000000..8a60972af8c5
--- /dev/null
+++ b/drivers/usb/storage/karma.h
@@ -0,0 +1,7 @@
+#ifndef _KARMA_USB_H
+#define _KARMA_USB_H
+
+extern int rio_karma_init(struct us_data *us);
+extern int rio_karma_transport(struct scsi_cmnd *srb, struct us_data *us);
+
+#endif
diff --git a/drivers/usb/storage/libusual.c b/drivers/usb/storage/libusual.c
index b1ec4a718547..599ad10a761b 100644
--- a/drivers/usb/storage/libusual.c
+++ b/drivers/usb/storage/libusual.c
@@ -8,6 +8,7 @@
#include <linux/usb.h>
#include <linux/usb_usual.h>
#include <linux/vmalloc.h>
+#include <linux/kthread.h>
/*
*/
@@ -117,7 +118,7 @@ static int usu_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
unsigned long type;
- int rc;
+ struct task_struct* task;
unsigned long flags;
type = USB_US_TYPE(id->driver_info);
@@ -132,8 +133,9 @@ static int usu_probe(struct usb_interface *intf,
stat[type].fls |= USU_MOD_FL_THREAD;
spin_unlock_irqrestore(&usu_lock, flags);
- rc = kernel_thread(usu_probe_thread, (void*)type, CLONE_VM);
- if (rc < 0) {
+ task = kthread_run(usu_probe_thread, (void*)type, "libusual_%d", type);
+ if (IS_ERR(task)) {
+ int rc = PTR_ERR(task);
printk(KERN_WARNING "libusual: "
"Unable to start the thread for %s: %d\n",
bias_names[type], rc);
@@ -175,8 +177,6 @@ static int usu_probe_thread(void *arg)
int rc;
unsigned long flags;
- daemonize("libusual_%d", type); /* "usb-storage" is kinda too long */
-
/* A completion does not work here because it's counted. */
down(&usu_init_notify);
up(&usu_init_notify);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 313920d980c9..3baf448e300d 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -53,7 +53,7 @@ struct usb_onetouch {
unsigned int is_open:1;
};
-static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
+static void usb_onetouch_irq(struct urb *urb)
{
struct usb_onetouch *onetouch = urb->context;
signed char *data = onetouch->data;
@@ -72,7 +72,6 @@ static void usb_onetouch_irq(struct urb *urb, struct pt_regs *regs)
goto resubmit;
}
- input_regs(dev, regs);
input_report_key(dev, ONETOUCH_BUTTON, data[0] & 0x02);
input_sync(dev);
@@ -135,6 +134,7 @@ int onetouch_connect_input(struct us_data *ss)
struct usb_onetouch *onetouch;
struct input_dev *input_dev;
int pipe, maxp;
+ int error = -ENOMEM;
interface = ss->pusb_intf->cur_altsetting;
@@ -211,15 +211,18 @@ int onetouch_connect_input(struct us_data *ss)
ss->suspend_resume_hook = usb_onetouch_pm_hook;
#endif
- input_register_device(onetouch->dev);
+ error = input_register_device(onetouch->dev);
+ if (error)
+ goto fail3;
return 0;
+ fail3: usb_free_urb(onetouch->irq);
fail2: usb_buffer_free(udev, ONETOUCH_PKT_LEN,
onetouch->data, onetouch->data_dma);
fail1: kfree(onetouch);
input_free_device(input_dev);
- return -ENOMEM;
+ return error;
}
void onetouch_release_input(void *onetouch_)
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index a4b7df9ff8c1..e1072d52d641 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -72,12 +72,27 @@ static const char* host_info(struct Scsi_Host *host)
static int slave_alloc (struct scsi_device *sdev)
{
+ struct us_data *us = host_to_us(sdev->host);
+
/*
* Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or
* less than 36 bytes.
*/
sdev->inquiry_len = 36;
+
+ /*
+ * The UFI spec treates the Peripheral Qualifier bits in an
+ * INQUIRY result as reserved and requires devices to set them
+ * to 0. However the SCSI spec requires these bits to be set
+ * to 3 to indicate when a LUN is not present.
+ *
+ * Let the scanning code know if this target merely sets
+ * Peripheral Device Type to 0x1f to indicate no LUN.
+ */
+ if (us->subclass == US_SC_UFI)
+ sdev->sdev_target->pdt_1f_for_no_lun = 1;
+
return 0;
}
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index d6acc92a4ae3..47644b5b6155 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -108,7 +108,7 @@
/* This is the completion handler which will wake us up when an URB
* completes.
*/
-static void usb_stor_blocking_completion(struct urb *urb, struct pt_regs *regs)
+static void usb_stor_blocking_completion(struct urb *urb)
{
struct completion *urb_done_ptr = (struct completion *)urb->context;
@@ -294,11 +294,6 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
return USB_STOR_XFER_ERROR;
return USB_STOR_XFER_STALLED;
- /* timeout or excessively long NAK */
- case -ETIMEDOUT:
- US_DEBUGP("-- timeout or NAK\n");
- return USB_STOR_XFER_ERROR;
-
/* babble - the device tried to send more than we wanted to read */
case -EOVERFLOW:
US_DEBUGP("-- babble\n");
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b130e170b4a8..37ed8e0f2dc8 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -55,7 +55,8 @@ UNUSUAL_DEV( 0x03eb, 0x2002, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE),
-UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0100,
+/* modified by Tobias Lorenz <tobias.lorenz@gmx.net> */
+UNUSUAL_DEV( 0x03ee, 0x6901, 0x0000, 0x0200,
"Mitsumi",
"USB FDD",
US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -152,6 +153,13 @@ UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+/* Reported by Jon Hart <Jon.Hart@web.de> */
+UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100,
+ "Nokia",
+ "E60",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ),
+
/* Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and
* Einar Th. Einarsson <einarthered@gmail.com> */
UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100,
@@ -175,6 +183,20 @@ UNUSUAL_DEV( 0x0421, 0x044e, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ),
+/* Reported by Bardur Arantsson <bardur@scientician.net> */
+UNUSUAL_DEV( 0x0421, 0x047c, 0x0370, 0x0370,
+ "Nokia",
+ "6131",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
+/* Reported by Alex Corcoles <alex@corcoles.net> */
+UNUSUAL_DEV( 0x0421, 0x0495, 0x0370, 0x0370,
+ "Nokia",
+ "6234",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_MAX_SECTORS_64 ),
+
/* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
UNUSUAL_DEV( 0x0424, 0x0fdc, 0x0210, 0x0210,
"SMSC",
@@ -218,10 +240,12 @@ UNUSUAL_DEV( 0x0457, 0x0151, 0x0100, 0x0100,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_NOT_LOCKABLE ),
+#ifdef CONFIG_USB_STORAGE_KARMA
UNUSUAL_DEV( 0x045a, 0x5210, 0x0101, 0x0101,
"Rio",
"Rio Karma",
- US_SC_SCSI, US_PR_BULK, rio_karma_init, 0),
+ US_SC_SCSI, US_PR_KARMA, rio_karma_init, 0),
+#endif
/* Patch submitted by Philipp Friedrich <philipp@void.at> */
UNUSUAL_DEV( 0x0482, 0x0100, 0x0100, 0x0100,
@@ -631,6 +655,13 @@ UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210,
"Digital Camera EX-20 DSC",
US_SC_8070, US_PR_DEVICE, NULL, 0 ),
+/* Reported by <Hendryk.Pfeiffer@gmx.de> */
+UNUSUAL_DEV( 0x059f, 0x0643, 0x0000, 0x0000,
+ "LaCie",
+ "DVD+-RW",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_GO_SLOW ),
+
/* Submitted by Joel Bourquard <numlock@freesurf.ch>
* Some versions of this device need the SubClass and Protocol overrides
* while others don't.
@@ -1254,6 +1285,13 @@ UNUSUAL_DEV( 0x0fce, 0xd008, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_NO_WP_DETECT ),
+/* Reported by Jan Mate <mate@fiit.stuba.sk> */
+UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P990i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/* Reported by Emmanuel Vasilakis <evas@forthnet.gr> */
UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
"Sony Ericsson",
@@ -1261,6 +1299,20 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000,
US_SC_DEVICE, US_PR_DEVICE, NULL,
US_FL_FIX_CAPACITY ),
+/* Reported by Jan Mate <mate@fiit.stuba.sk> */
+UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P990i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
+/* Reported by Jan Mate <mate@fiit.stuba.sk> */
+UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000,
+ "Sony Ericsson",
+ "P990i",
+ US_SC_DEVICE, US_PR_DEVICE, NULL,
+ US_FL_FIX_CAPACITY ),
+
/* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
* Tested on hardware version 1.10.
* Entry is needed only for the initializer function override.
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 8d7bdcb5924d..b8d6031b0975 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -98,6 +98,9 @@
#ifdef CONFIG_USB_STORAGE_ALAUDA
#include "alauda.h"
#endif
+#ifdef CONFIG_USB_STORAGE_KARMA
+#include "karma.h"
+#endif
/* Some informational data */
MODULE_AUTHOR("Matthew Dharm <mdharm-usb@one-eyed-alien.net>");
@@ -646,6 +649,14 @@ static int get_transport(struct us_data *us)
break;
#endif
+#ifdef CONFIG_USB_STORAGE_KARMA
+ case US_PR_KARMA:
+ us->transport_name = "Rio Karma/Bulk";
+ us->transport = rio_karma_transport;
+ us->transport_reset = usb_stor_Bulk_reset;
+ break;
+#endif
+
default:
return -EIO;
}
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index b362039792b3..296b091cf168 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -1,5 +1,5 @@
/*
- * USB Skeleton driver - 2.0
+ * USB Skeleton driver - 2.2
*
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
*
@@ -7,9 +7,8 @@
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
- * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
- * but has been rewritten to be easy to read and use, as no locks are now
- * needed anymore.
+ * This driver is based on the 2.6.3 version of drivers/usb/usb-skeleton.c
+ * but has been rewritten to be easier to read and use.
*
*/
@@ -21,6 +20,7 @@
#include <linux/kref.h>
#include <asm/uaccess.h>
#include <linux/usb.h>
+#include <linux/mutex.h>
/* Define these values to match your devices */
@@ -32,38 +32,39 @@ static struct usb_device_id skel_table [] = {
{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
{ } /* Terminating entry */
};
-MODULE_DEVICE_TABLE (usb, skel_table);
+MODULE_DEVICE_TABLE(usb, skel_table);
/* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192
/* our private defines. if this grows any larger, use your own .h file */
-#define MAX_TRANSFER ( PAGE_SIZE - 512 )
+#define MAX_TRANSFER (PAGE_SIZE - 512)
#define WRITES_IN_FLIGHT 8
/* Structure to hold all of our device specific stuff */
struct usb_skel {
- struct usb_device * udev; /* the usb device for this device */
- struct usb_interface * interface; /* the interface for this device */
+ struct usb_device *dev; /* the usb device for this device */
+ struct usb_interface *interface; /* the interface for this device */
struct semaphore limit_sem; /* limiting the number of writes in progress */
- unsigned char * bulk_in_buffer; /* the buffer to receive data */
+ unsigned char *bulk_in_buffer; /* the buffer to receive data */
size_t bulk_in_size; /* the size of the receive buffer */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
__u8 bulk_out_endpointAddr; /* the address of the bulk out endpoint */
struct kref kref;
+ struct mutex io_mutex; /* synchronize I/O with disconnect */
};
#define to_skel_dev(d) container_of(d, struct usb_skel, kref)
static struct usb_driver skel_driver;
static void skel_delete(struct kref *kref)
-{
+{
struct usb_skel *dev = to_skel_dev(kref);
usb_put_dev(dev->udev);
- kfree (dev->bulk_in_buffer);
- kfree (dev);
+ kfree(dev->bulk_in_buffer);
+ kfree(dev);
}
static int skel_open(struct inode *inode, struct file *file)
@@ -89,6 +90,11 @@ static int skel_open(struct inode *inode, struct file *file)
goto exit;
}
+ /* prevent the device from being autosuspended */
+ retval = usb_autopm_get_interface(interface);
+ if (retval)
+ goto exit;
+
/* increment our usage count for the device */
kref_get(&dev->kref);
@@ -107,6 +113,12 @@ static int skel_release(struct inode *inode, struct file *file)
if (dev == NULL)
return -ENODEV;
+ /* allow the device to be autosuspended */
+ mutex_lock(&dev->io_mutex);
+ if (dev->interface)
+ usb_autopm_put_interface(dev->interface);
+ mutex_unlock(&dev->io_mutex);
+
/* decrement the count on our device */
kref_put(&dev->kref, skel_delete);
return 0;
@@ -115,11 +127,17 @@ static int skel_release(struct inode *inode, struct file *file)
static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
{
struct usb_skel *dev;
- int retval = 0;
+ int retval;
int bytes_read;
dev = (struct usb_skel *)file->private_data;
-
+
+ mutex_lock(&dev->io_mutex);
+ if (!dev->interface) { /* disconnect() was called */
+ retval = -ENODEV;
+ goto exit;
+ }
+
/* do a blocking bulk read to get data from the device */
retval = usb_bulk_msg(dev->udev,
usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
@@ -135,26 +153,28 @@ static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *
retval = bytes_read;
}
+exit:
+ mutex_unlock(&dev->io_mutex);
return retval;
}
-static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void skel_write_bulk_callback(struct urb *urb)
{
struct usb_skel *dev;
dev = (struct usb_skel *)urb->context;
/* sync/async unlink faults aren't errors */
- if (urb->status &&
- !(urb->status == -ENOENT ||
+ if (urb->status &&
+ !(urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN)) {
- dbg("%s - nonzero write bulk status received: %d",
+ err("%s - nonzero write bulk status received: %d",
__FUNCTION__, urb->status);
}
/* free up our allocated buffer */
- usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+ usb_buffer_free(urb->dev, urb->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_dma);
up(&dev->limit_sem);
}
@@ -179,6 +199,12 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
goto exit;
}
+ mutex_lock(&dev->io_mutex);
+ if (!dev->interface) { /* disconnect() was called */
+ retval = -ENODEV;
+ goto error;
+ }
+
/* create a urb, and a buffer for it, and copy the data to the urb */
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
@@ -213,17 +239,22 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, size_t cou
/* release our reference to this urb, the USB core will eventually free it entirely */
usb_free_urb(urb);
-exit:
+ mutex_unlock(&dev->io_mutex);
return writesize;
error:
- usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
- usb_free_urb(urb);
+ if (urb) {
+ usb_buffer_free(dev->udev, writesize, buf, urb->transfer_dma);
+ usb_free_urb(urb);
+ }
+ mutex_unlock(&dev->io_mutex);
up(&dev->limit_sem);
+
+exit:
return retval;
}
-static struct file_operations skel_fops = {
+static const struct file_operations skel_fops = {
.owner = THIS_MODULE,
.read = skel_read,
.write = skel_write,
@@ -231,7 +262,7 @@ static struct file_operations skel_fops = {
.release = skel_release,
};
-/*
+/*
* usb class driver info in order to get a minor number from the usb core,
* and to have the device registered with the driver core
*/
@@ -243,7 +274,7 @@ static struct usb_class_driver skel_class = {
static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
- struct usb_skel *dev = NULL;
+ struct usb_skel *dev;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
size_t buffer_size;
@@ -252,12 +283,13 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL) {
+ if (!dev) {
err("Out of memory");
goto error;
}
kref_init(&dev->kref);
sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
+ mutex_init(&dev->io_mutex);
dev->udev = usb_get_dev(interface_to_usbdev(interface));
dev->interface = interface;
@@ -269,10 +301,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
endpoint = &iface_desc->endpoint[i].desc;
if (!dev->bulk_in_endpointAddr &&
- ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_in(endpoint)) {
/* we found a bulk in endpoint */
buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
dev->bulk_in_size = buffer_size;
@@ -285,10 +314,7 @@ static int skel_probe(struct usb_interface *interface, const struct usb_device_i
}
if (!dev->bulk_out_endpointAddr &&
- ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_OUT) &&
- ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)) {
+ usb_endpoint_is_bulk_out(endpoint)) {
/* we found a bulk out endpoint */
dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
}
@@ -334,6 +360,11 @@ static void skel_disconnect(struct usb_interface *interface)
/* give back our minor */
usb_deregister_dev(interface, &skel_class);
+ /* prevent more I/O from starting */
+ mutex_lock(&dev->io_mutex);
+ dev->interface = NULL;
+ mutex_unlock(&dev->io_mutex);
+
unlock_kernel();
/* decrement our usage count */
@@ -367,7 +398,7 @@ static void __exit usb_skel_exit(void)
usb_deregister(&skel_driver);
}
-module_init (usb_skel_init);
-module_exit (usb_skel_exit);
+module_init(usb_skel_init);
+module_exit(usb_skel_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 702eb933cf88..7a43020fa583 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -53,6 +53,11 @@ config FB
(e.g. an accelerated X server) and that are not frame buffer
device-aware may cause unexpected results. If unsure, say N.
+config FB_DDC
+ tristate
+ depends on FB && I2C && I2C_ALGOBIT
+ default n
+
config FB_CFB_FILLRECT
tristate
depends on FB
@@ -183,7 +188,7 @@ config FB_ARMCLCD_SHARP_LQ035Q7DB02_HRTFT
bool "LogicPD LCD 3.5\" QVGA w/HRTFT IC"
help
This is an implementation of the Sharp LQ035Q7DB02, a 3.5"
- color QVGA, HRTFT panel. The LogicPD device includes an
+ color QVGA, HRTFT panel. The LogicPD device includes
an integrated HRTFT controller IC.
The native resolution is 240x320.
@@ -398,7 +403,7 @@ config FB_ARC
is based on the KS-108 lcd controller and is typically a matrix
of 2*n chips. This driver was tested with a 128x64 panel. This
driver supports it for use with x86 SBCs through a 16 bit GPIO
- interface (8 bit data, 8 bit control). If you anticpate using
+ interface (8 bit data, 8 bit control). If you anticipate using
this driver, say Y or M; otherwise say N. You must specify the
GPIO IO address to be used for setting control and data.
@@ -734,6 +739,7 @@ config FB_RIVA
depends on FB && PCI
select I2C_ALGOBIT if FB_RIVA_I2C
select I2C if FB_RIVA_I2C
+ select FB_DDC if FB_RIVA_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -764,7 +770,7 @@ config FB_RIVA_DEBUG
default n
help
Say Y here if you want the Riva driver to output all sorts
- of debugging informations to provide to the maintainer when
+ of debugging information to provide to the maintainer when
something goes wrong.
config FB_RIVA_BACKLIGHT
@@ -822,33 +828,52 @@ config FB_I810_I2C
depends on FB_I810 && FB_I810_GTF
select I2C
select I2C_ALGOBIT
+ select FB_DDC
help
config FB_INTEL
- tristate "Intel 830M/845G/852GM/855GM/865G support (EXPERIMENTAL)"
+ tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G support (EXPERIMENTAL)"
depends on FB && EXPERIMENTAL && PCI && X86
select AGP
select AGP_INTEL
+ select I2C_ALGOBIT if FB_INTEL_I2C
+ select I2C if FB_INTEL_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
help
This driver supports the on-board graphics built in to the Intel
- 830M/845G/852GM/855GM/865G chipsets.
+ 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM chipsets.
Say Y if you have and plan to use such a board.
- To compile this driver as a module, choose M here: the
+ If you say Y here and want DDC/I2C support you must first say Y to
+ "I2C support" and "I2C bit-banging support" in the character devices
+ section.
+
+ If you say M here then "I2C support" and "I2C bit-banging support"
+ can be build either as modules or built-in.
+
+ To compile this driver as a module, choose M here: the
module will be called intelfb.
+ For more information, please read <file:Documentation/fb/intelfb.txt>
+
config FB_INTEL_DEBUG
- bool "Intel driver Debug Messages"
+ bool "Intel driver Debug Messages"
depends on FB_INTEL
---help---
Say Y here if you want the Intel driver to output all sorts
- of debugging informations to provide to the maintainer when
+ of debugging information to provide to the maintainer when
something goes wrong.
+config FB_INTEL_I2C
+ bool "DDC/I2C for Intel framebuffer support"
+ depends on FB_INTEL
+ default y
+ help
+ Say Y here if you want DDC/I2C support for your on-board Intel graphics.
+
config FB_MATROX
tristate "Matrox acceleration"
depends on FB && PCI
@@ -994,6 +1019,7 @@ config FB_RADEON
depends on FB && PCI
select I2C_ALGOBIT if FB_RADEON_I2C
select I2C if FB_RADEON_I2C
+ select FB_DDC if FB_RADEON_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -1035,7 +1061,7 @@ config FB_RADEON_DEBUG
default n
help
Say Y here if you want the Radeon driver to output all sorts
- of debugging informations to provide to the maintainer when
+ of debugging information to provide to the maintainer when
something goes wrong.
config FB_ATY128
@@ -1122,6 +1148,7 @@ config FB_SAVAGE
depends on FB && PCI && EXPERIMENTAL
select I2C_ALGOBIT if FB_SAVAGE_I2C
select I2C if FB_SAVAGE_I2C
+ select FB_DDC if FB_SAVAGE_I2C
select FB_MODE_HELPERS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -1601,7 +1628,8 @@ config FB_VIRTUAL
kernel option `video=vfb:'.
To compile this driver as a module, choose M here: the
- module will be called vfb.
+ module will be called vfb. In order to load it, you must use
+ the vfb_enable=1 option.
If unsure, say N.
if VT
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 481c6c9695f8..a6980e9a2481 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o
obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o
obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o
obj-$(CONFIG_FB_MACMODES) += macmodes.o
+obj-$(CONFIG_FB_DDC) += fb_ddc.o
# Hardware specific drivers go first
obj-$(CONFIG_FB_RETINAZ3) += retz3fb.o
diff --git a/drivers/video/amifb.c b/drivers/video/amifb.c
index f1ba54f4fc39..a4e3fca05891 100644
--- a/drivers/video/amifb.c
+++ b/drivers/video/amifb.c
@@ -1144,7 +1144,7 @@ static void amifb_deinit(void);
*/
static int flash_cursor(void);
-static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t amifb_interrupt(int irq, void *dev_id);
static u_long chipalloc(u_long size);
static void chipfree(void);
@@ -2492,7 +2492,7 @@ static int flash_cursor(void)
* VBlank Display Interrupt
*/
-static irqreturn_t amifb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t amifb_interrupt(int irq, void *dev_id)
{
if (do_vmode_pan || do_vmode_full)
ami_update_display();
diff --git a/drivers/video/arcfb.c b/drivers/video/arcfb.c
index 70dd8115a4d8..ab34b96acc31 100644
--- a/drivers/video/arcfb.c
+++ b/drivers/video/arcfb.c
@@ -218,8 +218,7 @@ static int arcfb_pan_display(struct fb_var_screeninfo *var,
return -EINVAL;
}
-static irqreturn_t arcfb_interrupt(int vec, void *dev_instance,
- struct pt_regs *regs)
+static irqreturn_t arcfb_interrupt(int vec, void *dev_instance)
{
struct fb_info *info = dev_instance;
unsigned char ctl2status;
diff --git a/drivers/video/atafb.c b/drivers/video/atafb.c
index 5831893bf7a0..02c41a626fa2 100644
--- a/drivers/video/atafb.c
+++ b/drivers/video/atafb.c
@@ -1521,7 +1521,7 @@ static void falcon_set_par( struct atafb_par *par )
}
-static irqreturn_t falcon_vbl_switcher( int irq, void *dummy, struct pt_regs *fp )
+static irqreturn_t falcon_vbl_switcher( int irq, void *dummy )
{
struct falcon_hw *hw = &f_new_mode;
diff --git a/drivers/video/aty/atyfb.h b/drivers/video/aty/atyfb.h
index 55fb8b04489b..b04f49fb976a 100644
--- a/drivers/video/aty/atyfb.h
+++ b/drivers/video/aty/atyfb.h
@@ -355,5 +355,9 @@ static inline void wait_for_idle(struct atyfb_par *par)
extern void aty_reset_engine(const struct atyfb_par *par);
extern void aty_init_engine(struct atyfb_par *par, struct fb_info *info);
-extern void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par);
extern u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par);
+
+void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
+void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
+void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
+
diff --git a/drivers/video/aty/atyfb_base.c b/drivers/video/aty/atyfb_base.c
index 19a71f045784..b77b30923928 100644
--- a/drivers/video/aty/atyfb_base.c
+++ b/drivers/video/aty/atyfb_base.c
@@ -240,9 +240,6 @@ static int atyfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
static int atyfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info);
static int atyfb_blank(int blank, struct fb_info *info);
static int atyfb_ioctl(struct fb_info *info, u_int cmd, u_long arg);
-extern void atyfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
-extern void atyfb_copyarea(struct fb_info *info, const struct fb_copyarea *area);
-extern void atyfb_imageblit(struct fb_info *info, const struct fb_image *image);
#ifdef __sparc__
static int atyfb_mmap(struct fb_info *info, struct vm_area_struct *vma);
#endif
@@ -1535,7 +1532,7 @@ static int atyfb_open(struct fb_info *info, int user)
return (0);
}
-static irqreturn_t aty_irq(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t aty_irq(int irq, void *dev_id)
{
struct atyfb_par *par = dev_id;
int handled = 0;
@@ -3863,6 +3860,7 @@ static int __devinit atyfb_setup(char *options)
static int __devinit atyfb_init(void)
{
+ int err1 = 1, err2 = 1;
#ifndef MODULE
char *option = NULL;
@@ -3872,12 +3870,13 @@ static int __devinit atyfb_init(void)
#endif
#ifdef CONFIG_PCI
- pci_register_driver(&atyfb_driver);
+ err1 = pci_register_driver(&atyfb_driver);
#endif
#ifdef CONFIG_ATARI
- atyfb_atari_probe();
+ err2 = atyfb_atari_probe();
#endif
- return 0;
+
+ return (err1 && err2) ? -ENODEV : 0;
}
static void __exit atyfb_exit(void)
diff --git a/drivers/video/aty/mach64_ct.c b/drivers/video/aty/mach64_ct.c
index e7056934c6a8..5080816be653 100644
--- a/drivers/video/aty/mach64_ct.c
+++ b/drivers/video/aty/mach64_ct.c
@@ -27,7 +27,7 @@ u8 aty_ld_pll_ct(int offset, const struct atyfb_par *par)
return res;
}
-void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
+static void aty_st_pll_ct(int offset, u8 val, const struct atyfb_par *par)
{
/* write addr byte */
aty_st_8(CLOCK_CNTL_ADDR, ((offset << 2) & PLL_ADDR) | PLL_WR_EN, par);
diff --git a/drivers/video/aty/radeon_i2c.c b/drivers/video/aty/radeon_i2c.c
index 9aaca58c074a..676754520099 100644
--- a/drivers/video/aty/radeon_i2c.c
+++ b/drivers/video/aty/radeon_i2c.c
@@ -16,8 +16,6 @@
#include "radeonfb.h"
#include "../edid.h"
-#define RADEON_DDC 0x50
-
static void radeon_gpio_setscl(void* data, int state)
{
struct radeon_i2c_chan *chan = data;
@@ -138,108 +136,10 @@ void radeon_delete_i2c_busses(struct radeonfb_info *rinfo)
rinfo->i2c[3].rinfo = NULL;
}
-
-static u8 *radeon_do_probe_i2c_edid(struct radeon_i2c_chan *chan)
-{
- u8 start = 0x0;
- struct i2c_msg msgs[] = {
- {
- .addr = RADEON_DDC,
- .len = 1,
- .buf = &start,
- }, {
- .addr = RADEON_DDC,
- .flags = I2C_M_RD,
- .len = EDID_LENGTH,
- },
- };
- u8 *buf;
-
- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (!buf) {
- dev_warn(&chan->rinfo->pdev->dev, "Out of memory!\n");
- return NULL;
- }
- msgs[1].buf = buf;
-
- if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
- return buf;
- dev_dbg(&chan->rinfo->pdev->dev, "Unable to read EDID block.\n");
- kfree(buf);
- return NULL;
-}
-
-
-int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn, u8 **out_edid)
+int radeon_probe_i2c_connector(struct radeonfb_info *rinfo, int conn,
+ u8 **out_edid)
{
- u32 reg = rinfo->i2c[conn-1].ddc_reg;
- u8 *edid = NULL;
- int i, j;
-
- OUTREG(reg, INREG(reg) &
- ~(VGA_DDC_DATA_OUTPUT | VGA_DDC_CLK_OUTPUT));
-
- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
- (void)INREG(reg);
-
- for (i = 0; i < 3; i++) {
- /* For some old monitors we need the
- * following process to initialize/stop DDC
- */
- OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
- (void)INREG(reg);
- msleep(13);
-
- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
- (void)INREG(reg);
- for (j = 0; j < 5; j++) {
- msleep(10);
- if (INREG(reg) & VGA_DDC_CLK_INPUT)
- break;
- }
- if (j == 5)
- continue;
-
- OUTREG(reg, INREG(reg) | VGA_DDC_DATA_OUT_EN);
- (void)INREG(reg);
- msleep(15);
- OUTREG(reg, INREG(reg) | VGA_DDC_CLK_OUT_EN);
- (void)INREG(reg);
- msleep(15);
- OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
- (void)INREG(reg);
- msleep(15);
-
- /* Do the real work */
- edid = radeon_do_probe_i2c_edid(&rinfo->i2c[conn-1]);
-
- OUTREG(reg, INREG(reg) |
- (VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
- (void)INREG(reg);
- msleep(15);
-
- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN));
- (void)INREG(reg);
- for (j = 0; j < 10; j++) {
- msleep(10);
- if (INREG(reg) & VGA_DDC_CLK_INPUT)
- break;
- }
-
- OUTREG(reg, INREG(reg) & ~(VGA_DDC_DATA_OUT_EN));
- (void)INREG(reg);
- msleep(15);
- OUTREG(reg, INREG(reg) |
- (VGA_DDC_DATA_OUT_EN | VGA_DDC_CLK_OUT_EN));
- (void)INREG(reg);
- if (edid)
- break;
- }
- /* Release the DDC lines when done or the Apple Cinema HD display
- * will switch off
- */
- OUTREG(reg, INREG(reg) & ~(VGA_DDC_CLK_OUT_EN | VGA_DDC_DATA_OUT_EN));
- (void)INREG(reg);
+ u8 *edid = fb_ddc_read(&rinfo->i2c[conn-1].adapter);
if (out_edid)
*out_edid = edid;
diff --git a/drivers/video/aty/radeon_pm.c b/drivers/video/aty/radeon_pm.c
index 365de5dcc888..9a2b0d69b0ae 100644
--- a/drivers/video/aty/radeon_pm.c
+++ b/drivers/video/aty/radeon_pm.c
@@ -86,6 +86,9 @@ static struct radeon_device_id radeon_workaround_list[] = {
BUGFIX("Samsung P35",
PCI_VENDOR_ID_SAMSUNG, 0xc00c,
radeon_pm_off, radeon_reinitialize_M10),
+ BUGFIX("Acer Aspire 2010",
+ PCI_VENDOR_ID_AI, 0x0061,
+ radeon_pm_off, radeon_reinitialize_M10),
{ .ident = NULL }
};
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index f25d5d648333..ef5c16f7f5a6 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -8,6 +8,7 @@
* <c.pellegrin@exadron.com>
*
* PM support added by Rodolfo Giometti <giometti@linux.it>
+ * Cursor enable/disable by Rodolfo Giometti <giometti@linux.it>
*
* Copyright 2002 MontaVista Software
* Author: MontaVista Software, Inc.
@@ -110,6 +111,10 @@ static struct fb_var_screeninfo au1100fb_var __initdata = {
static struct au1100fb_drv_info drv_info;
+static int nocursor = 0;
+module_param(nocursor, int, 0644);
+MODULE_PARM_DESC(nocursor, "cursor enable/disable");
+
/*
* Set hardware with var settings. This will enable the controller with a specific
* mode, normally validated with the fb_check_var method
@@ -422,6 +427,17 @@ int au1100fb_fb_mmap(struct fb_info *fbi, struct vm_area_struct *vma)
return 0;
}
+/* fb_cursor
+ * Used to disable cursor drawing...
+ */
+int au1100fb_fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
+{
+ if (nocursor)
+ return 0;
+ else
+ return -EINVAL; /* just to force soft_cursor() call */
+}
+
static struct fb_ops au1100fb_ops =
{
.owner = THIS_MODULE,
@@ -433,6 +449,7 @@ static struct fb_ops au1100fb_ops =
.fb_imageblit = cfb_imageblit,
.fb_rotate = au1100fb_fb_rotate,
.fb_mmap = au1100fb_fb_mmap,
+ .fb_cursor = au1100fb_fb_cursor,
};
@@ -677,7 +694,7 @@ int au1100fb_setup(char *options)
if (options) {
while ((this_opt = strsep(&options,",")) != NULL) {
/* Panel option */
- if (!strncmp(this_opt, "panel:", 6)) {
+ if (!strncmp(this_opt, "panel:", 6)) {
int i;
this_opt += 6;
for (i = 0; i < num_panels; i++) {
@@ -685,13 +702,18 @@ int au1100fb_setup(char *options)
known_lcd_panels[i].name,
strlen(this_opt))) {
panel_idx = i;
- break;
+ break;
+ }
}
- }
if (i >= num_panels) {
print_warn("Panel %s not supported!", this_opt);
}
}
+ if (!strncmp(this_opt, "nocursor", 8)) {
+ this_opt += 8;
+ nocursor = 1;
+ print_info("Cursor disabled");
+ }
/* Mode option (only option that start with digit) */
else if (isdigit(this_opt[0])) {
mode = kmalloc(strlen(this_opt) + 1, GFP_KERNEL);
@@ -700,7 +722,7 @@ int au1100fb_setup(char *options)
/* Unsupported option */
else {
print_warn("Unsupported option \"%s\"", this_opt);
- }
+ }
}
}
diff --git a/drivers/video/au1200fb.c b/drivers/video/au1200fb.c
index c6a5f0ccc107..dbf4ec3f6d57 100644
--- a/drivers/video/au1200fb.c
+++ b/drivers/video/au1200fb.c
@@ -1545,7 +1545,7 @@ static struct fb_ops au1200fb_fb_ops = {
/*-------------------------------------------------------------------------*/
-static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id, struct pt_regs *regs)
+static irqreturn_t au1200fb_handle_irq(int irq, void* dev_id)
{
/* Nothing to do for now, just clear any pending interrupt */
lcd->intstatus = lcd->intstatus;
diff --git a/drivers/video/backlight/hp680_bl.c b/drivers/video/backlight/hp680_bl.c
index ffc72ae3ada8..fe1488374f62 100644
--- a/drivers/video/backlight/hp680_bl.c
+++ b/drivers/video/backlight/hp680_bl.c
@@ -20,7 +20,7 @@
#include <asm/cpu/dac.h>
#include <asm/hp6xx/hp6xx.h>
-#include <asm/hd64461/hd64461.h>
+#include <asm/hd64461.h>
#define HP680_MAX_INTENSITY 255
#define HP680_DEFAULT_INTENSITY 10
@@ -163,6 +163,6 @@ static void __exit hp680bl_exit(void)
module_init(hp680bl_init);
module_exit(hp680bl_exit);
-MODULE_AUTHOR("Andriy Skulysh <askulysh@image.kiev.ua>");
+MODULE_AUTHOR("Andriy Skulysh <askulysh@gmail.com>");
MODULE_DESCRIPTION("HP Jornada 680 Backlight Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c
index caf1eca199b0..628571c63bac 100644
--- a/drivers/video/backlight/locomolcd.c
+++ b/drivers/video/backlight/locomolcd.c
@@ -33,19 +33,19 @@ static unsigned long locomolcd_flags;
static void locomolcd_on(int comadj)
{
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1);
mdelay(2);
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1);
mdelay(2);
locomo_m62332_senddata(locomolcd_dev, comadj, 0);
mdelay(5);
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1);
mdelay(10);
/* TFTCRST | CPSOUT=0 | CPSEN */
@@ -58,8 +58,8 @@ static void locomolcd_on(int comadj)
locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC);
mdelay(10);
- locomo_gpio_set_dir(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 1);
+ locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1);
}
static void locomolcd_off(int comadj)
@@ -68,16 +68,16 @@ static void locomolcd_off(int comadj)
locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC);
mdelay(1);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHA_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0);
mdelay(110);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VEE_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0);
mdelay(700);
/* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */
locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_MOD, 0);
- locomo_gpio_write(locomolcd_dev, LOCOMO_GPIO_LCD_VSHD_ON, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0);
+ locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0);
}
void locomolcd_power(int on)
@@ -167,14 +167,14 @@ static int locomolcd_resume(struct locomo_dev *dev)
#define locomolcd_resume NULL
#endif
-static int locomolcd_probe(struct locomo_dev *dev)
+static int locomolcd_probe(struct locomo_dev *ldev)
{
unsigned long flags;
local_irq_save(flags);
- locomolcd_dev = dev;
+ locomolcd_dev = ldev;
- locomo_gpio_set_dir(dev, LOCOMO_GPIO_FL_VR, 0);
+ locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0);
/* the poodle_lcd_power function is called for the first time
* from fs_initcall, which is before locomo is activated.
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 4444bef68fba..aa3935df852a 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -6,7 +6,7 @@ menu "Console display driver support"
config VGA_CONSOLE
bool "VGA text console" if EMBEDDED || !X86
- depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE
+ depends on !ARCH_ACORN && !ARCH_EBSA110 && !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && !ARCH_VERSATILE && !SUPERH
default y
help
Saying Y here will allow you to use Linux in text mode through a
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index 1b4f75d1f8a9..302174b8e477 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -133,6 +133,7 @@ static int info_idx = -1;
/* console rotation */
static int rotate;
+static int fbcon_has_sysfs;
static const struct consw fb_con;
@@ -203,7 +204,7 @@ static struct class_device *fbcon_class_device;
*/
static int vbl_detected;
-static irqreturn_t fb_vbl_detect(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t fb_vbl_detect(int irq, void *dummy)
{
vbl_detected++;
return IRQ_HANDLED;
@@ -396,9 +397,8 @@ static void fb_flashcursor(void *private)
vc = vc_cons[ops->currcon].d;
if (!vc || !CON_IS_VISIBLE(vc) ||
- fbcon_is_inactive(vc, info) ||
registered_fb[con2fb_map[vc->vc_num]] != info ||
- vc_cons[ops->currcon].d->vc_deccm != 1) {
+ vc->vc_deccm != 1) {
release_console_sem();
return;
}
@@ -414,7 +414,7 @@ static void fb_flashcursor(void *private)
#if defined(CONFIG_ATARI) || defined(CONFIG_MAC)
static int cursor_blink_rate;
-static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t fb_vbl_handler(int irq, void *dev_id)
{
struct fb_info *info = dev_id;
@@ -2166,7 +2166,12 @@ static int fbcon_switch(struct vc_data *vc)
fbcon_del_cursor_timer(old_info);
}
- fbcon_add_cursor_timer(info);
+ if (fbcon_is_inactive(vc, info) ||
+ ops->blank_state != FB_BLANK_UNBLANK)
+ fbcon_del_cursor_timer(info);
+ else
+ fbcon_add_cursor_timer(info);
+
set_blitting_type(vc, info);
ops->cursor_reset = 1;
@@ -2276,10 +2281,11 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
update_screen(vc);
}
- if (!blank)
- fbcon_add_cursor_timer(info);
- else
+ if (fbcon_is_inactive(vc, info) ||
+ ops->blank_state != FB_BLANK_UNBLANK)
fbcon_del_cursor_timer(info);
+ else
+ fbcon_add_cursor_timer(info);
return 0;
}
@@ -3161,11 +3167,26 @@ static struct class_device_attribute class_device_attrs[] = {
static int fbcon_init_class_device(void)
{
- int i;
+ int i, error = 0;
+
+ fbcon_has_sysfs = 1;
+
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
+ error = class_device_create_file(fbcon_class_device,
+ &class_device_attrs[i]);
+
+ if (error)
+ break;
+ }
+
+ if (error) {
+ while (--i >= 0)
+ class_device_remove_file(fbcon_class_device,
+ &class_device_attrs[i]);
+
+ fbcon_has_sysfs = 0;
+ }
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_create_file(fbcon_class_device,
- &class_device_attrs[i]);
return 0;
}
@@ -3225,7 +3246,10 @@ static void fbcon_exit(void)
module_put(info->fbops->owner);
if (info->fbcon_par) {
+ struct fbcon_ops *ops = info->fbcon_par;
+
fbcon_del_cursor_timer(info);
+ kfree(ops->cursor_src);
kfree(info->fbcon_par);
info->fbcon_par = NULL;
}
@@ -3271,9 +3295,13 @@ static void __exit fbcon_deinit_class_device(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_remove_file(fbcon_class_device,
- &class_device_attrs[i]);
+ if (fbcon_has_sysfs) {
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_remove_file(fbcon_class_device,
+ &class_device_attrs[i]);
+
+ fbcon_has_sysfs = 0;
+ }
}
static void __exit fb_console_exit(void)
diff --git a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
index f244ad066d68..b9386d168c04 100644
--- a/drivers/video/console/fbcon.h
+++ b/drivers/video/console/fbcon.h
@@ -80,6 +80,8 @@ struct fbcon_ops {
char *cursor_data;
u8 *fontbuffer;
u8 *fontdata;
+ u8 *cursor_src;
+ u32 cursor_size;
u32 fd_size;
};
/*
diff --git a/drivers/video/console/fbcon_ccw.c b/drivers/video/console/fbcon_ccw.c
index 4481c80b8b2a..825e6d6972a7 100644
--- a/drivers/video/console/fbcon_ccw.c
+++ b/drivers/video/console/fbcon_ccw.c
@@ -391,7 +391,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
ops->cursor_reset = 0;
}
-int ccw_update_start(struct fb_info *info)
+static int ccw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
u32 yoffset;
diff --git a/drivers/video/console/fbcon_cw.c b/drivers/video/console/fbcon_cw.c
index 7f92c06afea7..c637e6318803 100644
--- a/drivers/video/console/fbcon_cw.c
+++ b/drivers/video/console/fbcon_cw.c
@@ -375,7 +375,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
ops->cursor_reset = 0;
}
-int cw_update_start(struct fb_info *info)
+static int cw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
u32 vxres = GETVXRES(ops->p->scrollmode, info);
diff --git a/drivers/video/console/fbcon_ud.c b/drivers/video/console/fbcon_ud.c
index ab91005e64dc..1473506df5d0 100644
--- a/drivers/video/console/fbcon_ud.c
+++ b/drivers/video/console/fbcon_ud.c
@@ -415,7 +415,7 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
ops->cursor_reset = 0;
}
-int ud_update_start(struct fb_info *info)
+static int ud_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
int xoffset, yoffset;
diff --git a/drivers/video/console/softcursor.c b/drivers/video/console/softcursor.c
index 557c563e4aed..7d07d8383569 100644
--- a/drivers/video/console/softcursor.c
+++ b/drivers/video/console/softcursor.c
@@ -20,11 +20,12 @@
int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
{
+ struct fbcon_ops *ops = info->fbcon_par;
unsigned int scan_align = info->pixmap.scan_align - 1;
unsigned int buf_align = info->pixmap.buf_align - 1;
unsigned int i, size, dsize, s_pitch, d_pitch;
struct fb_image *image;
- u8 *dst, *src;
+ u8 *dst;
if (info->state != FBINFO_STATE_RUNNING)
return 0;
@@ -32,11 +33,19 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
s_pitch = (cursor->image.width + 7) >> 3;
dsize = s_pitch * cursor->image.height;
- src = kmalloc(dsize + sizeof(struct fb_image), GFP_ATOMIC);
- if (!src)
- return -ENOMEM;
+ if (dsize + sizeof(struct fb_image) != ops->cursor_size) {
+ if (ops->cursor_src != NULL)
+ kfree(ops->cursor_src);
+ ops->cursor_size = dsize + sizeof(struct fb_image);
- image = (struct fb_image *) (src + dsize);
+ ops->cursor_src = kmalloc(ops->cursor_size, GFP_ATOMIC);
+ if (!ops->cursor_src) {
+ ops->cursor_size = 0;
+ return -ENOMEM;
+ }
+ }
+
+ image = (struct fb_image *) (ops->cursor_src + dsize);
*image = cursor->image;
d_pitch = (s_pitch + scan_align) & ~scan_align;
@@ -48,21 +57,23 @@ int soft_cursor(struct fb_info *info, struct fb_cursor *cursor)
switch (cursor->rop) {
case ROP_XOR:
for (i = 0; i < dsize; i++)
- src[i] = image->data[i] ^ cursor->mask[i];
+ ops->cursor_src[i] = image->data[i] ^
+ cursor->mask[i];
break;
case ROP_COPY:
default:
for (i = 0; i < dsize; i++)
- src[i] = image->data[i] & cursor->mask[i];
+ ops->cursor_src[i] = image->data[i] &
+ cursor->mask[i];
break;
}
} else
- memcpy(src, image->data, dsize);
+ memcpy(ops->cursor_src, image->data, dsize);
- fb_pad_aligned_buffer(dst, d_pitch, src, s_pitch, image->height);
+ fb_pad_aligned_buffer(dst, d_pitch, ops->cursor_src, s_pitch,
+ image->height);
image->data = dst;
info->fbops->fb_imageblit(info, image);
- kfree(src);
return 0;
}
diff --git a/drivers/video/controlfb.c b/drivers/video/controlfb.c
index 8cc6c0e2d27a..04c6d928189b 100644
--- a/drivers/video/controlfb.c
+++ b/drivers/video/controlfb.c
@@ -415,13 +415,15 @@ static int __init init_control(struct fb_info_control *p)
full = p->total_vram == 0x400000;
/* Try to pick a video mode out of NVRAM if we have one. */
+#ifdef CONFIG_NVRAM
if (default_cmode == CMODE_NVRAM){
cmode = nvram_read_byte(NV_CMODE);
if(cmode < CMODE_8 || cmode > CMODE_32)
cmode = CMODE_8;
} else
+#endif
cmode=default_cmode;
-
+#ifdef CONFIG_NVRAM
if (default_vmode == VMODE_NVRAM) {
vmode = nvram_read_byte(NV_VMODE);
if (vmode < 1 || vmode > VMODE_MAX ||
@@ -432,7 +434,9 @@ static int __init init_control(struct fb_info_control *p)
if (control_mac_modes[vmode - 1].m[full] < cmode)
vmode = VMODE_640_480_60;
}
- } else {
+ } else
+#endif
+ {
vmode=default_vmode;
if (control_mac_modes[vmode - 1].m[full] < cmode) {
if (cmode > CMODE_8)
diff --git a/drivers/video/fb_ddc.c b/drivers/video/fb_ddc.c
new file mode 100644
index 000000000000..3aa6ebf68f17
--- /dev/null
+++ b/drivers/video/fb_ddc.c
@@ -0,0 +1,116 @@
+/*
+ * driver/vide/fb_ddc.c - DDC/EDID read support.
+ *
+ * Copyright (C) 2006 Dennis Munsie <dmunsie@cecropia.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/delay.h>
+#include <linux/device.h>
+#include <linux/fb.h>
+#include <linux/i2c-algo-bit.h>
+
+#include "edid.h"
+
+#define DDC_ADDR 0x50
+
+static unsigned char *fb_do_probe_ddc_edid(struct i2c_adapter *adapter)
+{
+ unsigned char start = 0x0;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = DDC_ADDR,
+ .len = 1,
+ .buf = &start,
+ }, {
+ .addr = DDC_ADDR,
+ .flags = I2C_M_RD,
+ .len = EDID_LENGTH,
+ }
+ };
+ unsigned char *buf;
+
+ buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
+ if (!buf) {
+ dev_warn(&adapter->dev, "unable to allocate memory for EDID "
+ "block.\n");
+ return NULL;
+ }
+ msgs[1].buf = buf;
+
+ if (i2c_transfer(adapter, msgs, 2) == 2)
+ return buf;
+
+ dev_warn(&adapter->dev, "unable to read EDID block.\n");
+ kfree(buf);
+ return NULL;
+}
+
+unsigned char *fb_ddc_read(struct i2c_adapter *adapter)
+{
+ struct i2c_algo_bit_data *algo_data = adapter->algo_data;
+ unsigned char *edid = NULL;
+ int i, j;
+
+ algo_data->setscl(algo_data->data, 1);
+ algo_data->setscl(algo_data->data, 0);
+
+ for (i = 0; i < 3; i++) {
+ /* For some old monitors we need the
+ * following process to initialize/stop DDC
+ */
+ algo_data->setsda(algo_data->data, 0);
+ msleep(13);
+
+ algo_data->setscl(algo_data->data, 1);
+ for (j = 0; j < 5; j++) {
+ msleep(10);
+ if (algo_data->getscl(algo_data->data))
+ break;
+ }
+ if (j == 5)
+ continue;
+
+ algo_data->setsda(algo_data->data, 0);
+ msleep(15);
+ algo_data->setscl(algo_data->data, 0);
+ msleep(15);
+ algo_data->setsda(algo_data->data, 1);
+ msleep(15);
+
+ /* Do the real work */
+ edid = fb_do_probe_ddc_edid(adapter);
+ algo_data->setsda(algo_data->data, 0);
+ algo_data->setscl(algo_data->data, 0);
+ msleep(15);
+
+ algo_data->setscl(algo_data->data, 1);
+ for (j = 0; j < 10; j++) {
+ msleep(10);
+ if (algo_data->getscl(algo_data->data))
+ break;
+ }
+
+ algo_data->setsda(algo_data->data, 1);
+ msleep(15);
+ algo_data->setscl(algo_data->data, 0);
+ if (edid)
+ break;
+ }
+ /* Release the DDC lines when done or the Apple Cinema HD display
+ * will switch off
+ */
+ algo_data->setsda(algo_data->data, 0);
+ algo_data->setscl(algo_data->data, 0);
+
+ return edid;
+}
+
+EXPORT_SYMBOL_GPL(fb_ddc_read);
+
+MODULE_AUTHOR("Dennis Munsie <dmunsie@cecropia.com>");
+MODULE_DESCRIPTION("DDC/EDID reading support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 17961e3ecaa0..93ffcdd95f50 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -554,7 +554,8 @@ static int fbmem_read_proc(char *buf, char **start, off_t offset,
int clen;
clen = 0;
- for (fi = registered_fb; fi < &registered_fb[FB_MAX] && len < 4000; fi++)
+ for (fi = registered_fb; fi < &registered_fb[FB_MAX] && clen < 4000;
+ fi++)
if (*fi)
clen += sprintf(buf + clen, "%d %s\n",
(*fi)->node,
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index c151dcf68786..d3a50417ed9a 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -20,6 +20,8 @@
#include <linux/console.h>
#include <linux/module.h>
+#define FB_SYSFS_FLAG_ATTR 1
+
/**
* framebuffer_alloc - creates a new frame buffer info structure
*
@@ -483,12 +485,27 @@ static struct class_device_attribute class_device_attrs[] = {
int fb_init_class_device(struct fb_info *fb_info)
{
- unsigned int i;
+ int i, error = 0;
+
class_set_devdata(fb_info->class_device, fb_info);
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_create_file(fb_info->class_device,
- &class_device_attrs[i]);
+ fb_info->class_flag |= FB_SYSFS_FLAG_ATTR;
+
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++) {
+ error = class_device_create_file(fb_info->class_device,
+ &class_device_attrs[i]);
+
+ if (error)
+ break;
+ }
+
+ if (error) {
+ while (--i >= 0)
+ class_device_remove_file(fb_info->class_device,
+ &class_device_attrs[i]);
+ fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
+ }
+
return 0;
}
@@ -496,9 +513,13 @@ void fb_cleanup_class_device(struct fb_info *fb_info)
{
unsigned int i;
- for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
- class_device_remove_file(fb_info->class_device,
- &class_device_attrs[i]);
+ if (fb_info->class_flag & FB_SYSFS_FLAG_ATTR) {
+ for (i = 0; i < ARRAY_SIZE(class_device_attrs); i++)
+ class_device_remove_file(fb_info->class_device,
+ &class_device_attrs[i]);
+
+ fb_info->class_flag &= ~FB_SYSFS_FLAG_ATTR;
+ }
}
#ifdef CONFIG_FB_BACKLIGHT
diff --git a/drivers/video/hitfb.c b/drivers/video/hitfb.c
index 4cc6b454265e..3afb472763c0 100644
--- a/drivers/video/hitfb.c
+++ b/drivers/video/hitfb.c
@@ -4,7 +4,7 @@
* (C) 1999 Mihai Spatar
* (C) 2000 YAEGASHI Takeshi
* (C) 2003, 2004 Paul Mundt
- * (C) 2003, 2004 Andriy Skulysh
+ * (C) 2003, 2004, 2006 Andriy Skulysh
*
* 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
@@ -20,18 +20,16 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/platform_device.h>
#include <linux/fb.h>
#include <asm/machvec.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
-#include <asm/hd64461/hd64461.h>
-
-#ifdef MACH_HP600
+#include <asm/hd64461.h>
#include <asm/cpu/dac.h>
#include <asm/hp6xx/hp6xx.h>
-#endif
#define WIDTH 640
@@ -45,7 +43,6 @@ static struct fb_var_screeninfo hitfb_var __initdata = {
static struct fb_fix_screeninfo hitfb_fix __initdata = {
.id = "Hitachi HD64461",
.type = FB_TYPE_PACKED_PIXELS,
- .ypanstep = 8,
.accel = FB_ACCEL_NONE,
};
@@ -73,26 +70,14 @@ static inline void hitfb_accel_set_dest(int truecolor, u16 dx, u16 dy,
if (truecolor)
saddr <<= 1;
- fb_writew(width, HD64461_BBTDWR);
- fb_writew(height, HD64461_BBTDHR);
+ fb_writew(width-1, HD64461_BBTDWR);
+ fb_writew(height-1, HD64461_BBTDHR);
fb_writew(saddr & 0xffff, HD64461_BBTDSARL);
fb_writew(saddr >> 16, HD64461_BBTDSARH);
}
-static inline void hitfb_accel_solidfill(int truecolor, u16 dx, u16 dy,
- u16 width, u16 height, u16 color)
-{
- hitfb_accel_set_dest(truecolor, dx, dy, width, height);
-
- fb_writew(0x00f0, HD64461_BBTROPR);
- fb_writew(16, HD64461_BBTMDR);
- fb_writew(color, HD64461_GRSCR);
-
- hitfb_accel_start(truecolor);
-}
-
static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,
u16 dy, u16 width, u16 height, u16 rop,
u32 mask_addr)
@@ -100,6 +85,8 @@ static inline void hitfb_accel_bitblt(int truecolor, u16 sx, u16 sy, u16 dx,
u32 saddr, daddr;
u32 maddr = 0;
+ height--;
+ width--;
fb_writew(rop, HD64461_BBTROPR);
if ((sy < dy) || ((sy == dy) && (sx <= dx))) {
saddr = WIDTH * (sy + height) + sx + width;
@@ -146,6 +133,7 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
if (rect->rop != ROP_COPY)
cfb_fillrect(p, rect);
else {
+ hitfb_accel_wait();
fb_writew(0x00f0, HD64461_BBTROPR);
fb_writew(16, HD64461_BBTMDR);
@@ -161,16 +149,15 @@ static void hitfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
rect->height);
hitfb_accel_start(0);
}
- hitfb_accel_wait();
}
}
static void hitfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
{
+ hitfb_accel_wait();
hitfb_accel_bitblt(p->var.bits_per_pixel == 16, area->sx, area->sy,
area->dx, area->dy, area->width, area->height,
0x00cc, 0);
- hitfb_accel_wait();
}
static int hitfb_pan_display(struct fb_var_screeninfo *var,
@@ -182,7 +169,7 @@ static int hitfb_pan_display(struct fb_var_screeninfo *var,
if (xoffset != 0)
return -EINVAL;
- fb_writew(yoffset, HD64461_LCDCBAR);
+ fb_writew((yoffset*info->fix.line_length)>>10, HD64461_LCDCBAR);
return 0;
}
@@ -192,12 +179,6 @@ int hitfb_blank(int blank_mode, struct fb_info *info)
unsigned short v;
if (blank_mode) {
-#ifdef MACH_HP600
- sh_dac_disable(DAC_LCD_BRIGHTNESS);
- v = fb_readw(HD64461_GPBDR);
- v |= HD64461_GPBDR_LCDOFF;
- fb_writew(v, HD64461_GPBDR);
-#endif
v = fb_readw(HD64461_LDR1);
v &= ~HD64461_LDR1_DON;
fb_writew(v, HD64461_LDR1);
@@ -213,19 +194,18 @@ int hitfb_blank(int blank_mode, struct fb_info *info)
v = fb_readw(HD64461_STBCR);
v &= ~HD64461_STBCR_SLCDST;
fb_writew(v, HD64461_STBCR);
-#ifdef MACH_HP600
- sh_dac_enable(DAC_LCD_BRIGHTNESS);
- v = fb_readw(HD64461_GPBDR);
- v &= ~HD64461_GPBDR_LCDOFF;
- fb_writew(v, HD64461_GPBDR);
-#endif
- v = fb_readw(HD64461_LDR1);
- v |= HD64461_LDR1_DON;
- fb_writew(v, HD64461_LDR1);
v = fb_readw(HD64461_LCDCCR);
- v &= ~HD64461_LCDCCR_MOFF;
+ v &= ~(HD64461_LCDCCR_MOFF | HD64461_LCDCCR_STREQ);
fb_writew(v, HD64461_LCDCCR);
+
+ do {
+ v = fb_readw(HD64461_LCDCCR);
+ } while(v&HD64461_LCDCCR_STBACK);
+
+ v = fb_readw(HD64461_LDR1);
+ v |= HD64461_LDR1_DON;
+ fb_writew(v, HD64461_LDR1);
}
return 0;
}
@@ -233,7 +213,7 @@ int hitfb_blank(int blank_mode, struct fb_info *info)
static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info)
{
- if (regno >= info->cmap.len)
+ if (regno >= 256)
return 1;
switch (info->var.bits_per_pixel) {
@@ -244,6 +224,8 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
fb_writew(blue >> 10, HD64461_CPTWDR);
break;
case 16:
+ if (regno >= 16)
+ return 1;
((u32 *) (info->pseudo_palette))[regno] =
((red & 0xf800)) |
((green & 0xfc00) >> 5) | ((blue & 0xf800) >> 11);
@@ -252,26 +234,113 @@ static int hitfb_setcolreg(unsigned regno, unsigned red, unsigned green,
return 0;
}
+static int hitfb_sync(struct fb_info *info)
+{
+ hitfb_accel_wait();
+
+ return 0;
+}
+
+static int hitfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ int maxy;
+
+ var->xres = info->var.xres;
+ var->xres_virtual = info->var.xres;
+ var->yres = info->var.yres;
+
+ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16))
+ var->bits_per_pixel = info->var.bits_per_pixel;
+
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ maxy = info->fix.smem_len / var->xres;
+
+ if (var->bits_per_pixel == 16)
+ maxy /= 2;
+
+ if (var->yres_virtual > maxy)
+ var->yres_virtual = maxy;
+
+ var->xoffset = 0;
+ var->yoffset = 0;
+
+ switch (var->bits_per_pixel) {
+ case 8:
+ var->red.offset = 0;
+ var->red.length = 8;
+ var->green.offset = 0;
+ var->green.length = 8;
+ var->blue.offset = 0;
+ var->blue.length = 8;
+ var->transp.offset = 0;
+ var->transp.length = 0;
+ break;
+ case 16: /* RGB 565 */
+ 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 = 0;
+ var->transp.length = 0;
+ break;
+ }
+
+ return 0;
+}
+
+static int hitfb_set_par(struct fb_info *info)
+{
+ unsigned short ldr3;
+
+ switch (info->var.bits_per_pixel) {
+ case 8:
+ info->fix.line_length = info->var.xres;
+ info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ info->fix.ypanstep = 16;
+ break;
+ case 16:
+ info->fix.line_length = info->var.xres*2;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.ypanstep = 8;
+ break;
+ }
+
+ fb_writew(info->fix.line_length, HD64461_LCDCLOR);
+ ldr3 = fb_readw(HD64461_LDR3);
+ ldr3 &= ~15;
+ ldr3 |= (info->var.bits_per_pixel == 8) ? 4 : 8;
+ fb_writew(ldr3, HD64461_LDR3);
+ return 0;
+}
+
static struct fb_ops hitfb_ops = {
.owner = THIS_MODULE,
+ .fb_check_var = hitfb_check_var,
+ .fb_set_par = hitfb_set_par,
.fb_setcolreg = hitfb_setcolreg,
.fb_blank = hitfb_blank,
+ .fb_sync = hitfb_sync,
.fb_pan_display = hitfb_pan_display,
.fb_fillrect = hitfb_fillrect,
.fb_copyarea = hitfb_copyarea,
.fb_imageblit = cfb_imageblit,
};
-int __init hitfb_init(void)
+static int __init hitfb_probe(struct platform_device *dev)
{
unsigned short lcdclor, ldr3, ldvndr;
- int size;
if (fb_get_options("hitfb", NULL))
return -ENODEV;
+ hitfb_fix.mmio_start = CONFIG_HD64461_IOBASE+0x1000;
+ hitfb_fix.mmio_len = 0x1000;
hitfb_fix.smem_start = CONFIG_HD64461_IOBASE + 0x02000000;
- hitfb_fix.smem_len = (MACH_HP690) ? 1024 * 1024 : 512 * 1024;
+ hitfb_fix.smem_len = 512 * 1024;
lcdclor = fb_readw(HD64461_LCDCLOR);
ldvndr = fb_readw(HD64461_LDVNDR);
@@ -321,12 +390,12 @@ int __init hitfb_init(void)
fb_info.var = hitfb_var;
fb_info.fix = hitfb_fix;
fb_info.pseudo_palette = pseudo_palette;
- fb_info.flags = FBINFO_DEFAULT;
+ fb_info.flags = FBINFO_DEFAULT | FBINFO_HWACCEL_YPAN |
+ FBINFO_HWACCEL_FILLRECT | FBINFO_HWACCEL_COPYAREA;
fb_info.screen_base = (void *)hitfb_fix.smem_start;
- size = (fb_info.var.bits_per_pixel == 8) ? 256 : 16;
- fb_alloc_cmap(&fb_info.cmap, size, 0);
+ fb_alloc_cmap(&fb_info.cmap, 256, 0);
if (register_framebuffer(&fb_info) < 0)
return -EINVAL;
@@ -336,9 +405,75 @@ int __init hitfb_init(void)
return 0;
}
+static int __devexit hitfb_remove(struct platform_device *dev)
+{
+ return unregister_framebuffer(&fb_info);
+}
+
+#ifdef CONFIG_PM
+static int hitfb_suspend(struct platform_device *dev, pm_message_t state)
+{
+ u16 v;
+
+ hitfb_blank(1,0);
+ v = fb_readw(HD64461_STBCR);
+ v |= HD64461_STBCR_SLCKE_IST;
+ fb_writew(v, HD64461_STBCR);
+
+ return 0;
+}
+
+static int hitfb_resume(struct platform_device *dev)
+{
+ u16 v;
+
+ v = fb_readw(HD64461_STBCR);
+ v &= ~HD64461_STBCR_SLCKE_OST;
+ msleep(100);
+ v = fb_readw(HD64461_STBCR);
+ v &= ~HD64461_STBCR_SLCKE_IST;
+ fb_writew(v, HD64461_STBCR);
+ hitfb_blank(0,0);
+
+ return 0;
+}
+#endif
+
+static struct platform_driver hitfb_driver = {
+ .probe = hitfb_probe,
+ .remove = __devexit_p(hitfb_remove),
+#ifdef CONFIG_PM
+ .suspend = hitfb_suspend,
+ .resume = hitfb_resume,
+#endif
+ .driver = {
+ .name = "hitfb",
+ },
+};
+
+static struct platform_device hitfb_device = {
+ .name = "hitfb",
+ .id = -1,
+};
+
+static int __init hitfb_init(void)
+{
+ int ret;
+
+ ret = platform_driver_register(&hitfb_driver);
+ if (!ret) {
+ ret = platform_device_register(&hitfb_device);
+ if (ret)
+ platform_driver_unregister(&hitfb_driver);
+ }
+ return ret;
+}
+
+
static void __exit hitfb_exit(void)
{
- unregister_framebuffer(&fb_info);
+ platform_device_unregister(&hitfb_device);
+ platform_driver_unregister(&hitfb_driver);
}
module_init(hitfb_init);
diff --git a/drivers/video/i810/i810-i2c.c b/drivers/video/i810/i810-i2c.c
index c1f7b49975dd..b38d805db313 100644
--- a/drivers/video/i810/i810-i2c.c
+++ b/drivers/video/i810/i810-i2c.c
@@ -19,7 +19,6 @@
#include "i810_main.h"
#include "../edid.h"
-#define I810_DDC 0x50
/* bit locations in the registers */
#define SCL_DIR_MASK 0x0001
#define SCL_DIR 0x0002
@@ -98,7 +97,6 @@ static int i810_setup_i2c_bus(struct i810fb_i2c_chan *chan, const char *name)
chan->algo.getsda = i810i2c_getsda;
chan->algo.getscl = i810i2c_getscl;
chan->algo.udelay = 10;
- chan->algo.mdelay = 10;
chan->algo.timeout = (HZ/2);
chan->algo.data = chan;
@@ -151,53 +149,14 @@ void i810_delete_i2c_busses(struct i810fb_par *par)
par->chan[2].par = NULL;
}
-static u8 *i810_do_probe_i2c_edid(struct i810fb_i2c_chan *chan)
-{
- u8 start = 0x0;
- struct i2c_msg msgs[] = {
- {
- .addr = I810_DDC,
- .len = 1,
- .buf = &start,
- }, {
- .addr = I810_DDC,
- .flags = I2C_M_RD,
- .len = EDID_LENGTH,
- },
- };
- u8 *buf;
-
- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (!buf) {
- DPRINTK("i810-i2c: Failed to allocate memory\n");
- return NULL;
- }
- msgs[1].buf = buf;
-
- if (i2c_transfer(&chan->adapter, msgs, 2) == 2) {
- DPRINTK("i810-i2c: I2C Transfer successful\n");
- return buf;
- }
-
- DPRINTK("i810-i2c: Unable to read EDID block.\n");
- kfree(buf);
- return NULL;
-}
-
int i810_probe_i2c_connector(struct fb_info *info, u8 **out_edid, int conn)
{
struct i810fb_par *par = info->par;
u8 *edid = NULL;
- int i;
DPRINTK("i810-i2c: Probe DDC%i Bus\n", conn+1);
if (conn < par->ddc_num) {
- for (i = 0; i < 3; i++) {
- /* Do the real work */
- edid = i810_do_probe_i2c_edid(&par->chan[conn]);
- if (edid)
- break;
- }
+ edid = fb_ddc_read(&par->chan[conn].adapter);
} else {
const u8 *e = fb_firmware_edid(info->device);
diff --git a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c
index d42edaccb84c..b55a12d95eb2 100644
--- a/drivers/video/i810/i810_main.c
+++ b/drivers/video/i810/i810_main.c
@@ -1602,7 +1602,10 @@ static int i810fb_resume(struct pci_dev *dev)
acquire_console_sem();
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- pci_enable_device(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
pci_set_master(dev);
agp_bind_memory(par->i810_gtt.i810_fb_memory,
par->fb.offset);
@@ -1611,6 +1614,7 @@ static int i810fb_resume(struct pci_dev *dev)
i810fb_set_par(info);
fb_set_suspend (info, 0);
info->fbops->fb_blank(VESA_NO_BLANKING, info);
+fail:
release_console_sem();
return 0;
}
diff --git a/drivers/video/igafb.c b/drivers/video/igafb.c
index 67f384f86758..e6df492c22a5 100644
--- a/drivers/video/igafb.c
+++ b/drivers/video/igafb.c
@@ -573,3 +573,10 @@ int __init igafb_setup(char *options)
module_init(igafb_init);
MODULE_LICENSE("GPL");
+static struct pci_device_id igafb_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_INTERG, PCI_DEVICE_ID_INTERG_1682,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { }
+};
+
+MODULE_DEVICE_TABLE(pci, igafb_pci_tbl);
diff --git a/drivers/video/intelfb/Makefile b/drivers/video/intelfb/Makefile
index 722d21d6e5cd..6c782d3ae1be 100644
--- a/drivers/video/intelfb/Makefile
+++ b/drivers/video/intelfb/Makefile
@@ -1,6 +1,8 @@
obj-$(CONFIG_FB_INTEL) += intelfb.o
-intelfb-objs := intelfbdrv.o intelfbhw.o
+intelfb-y := intelfbdrv.o intelfbhw.o
+intelfb-$(CONFIG_FB_INTEL_I2C) += intelfb_i2c.o
+intelfb-objs := $(intelfb-y)
ifdef CONFIG_FB_INTEL_DEBUG
#EXTRA_CFLAGS += -DDEBUG -DVERBOSE -DREGDUMP
diff --git a/drivers/video/intelfb/intelfb.h b/drivers/video/intelfb/intelfb.h
index e290d7460e1b..80b94c19a9fa 100644
--- a/drivers/video/intelfb/intelfb.h
+++ b/drivers/video/intelfb/intelfb.h
@@ -6,6 +6,10 @@
#include <linux/agp_backend.h>
#include <linux/fb.h>
+#ifdef CONFIG_FB_INTEL_I2C
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#endif
/*** Version/name ***/
#define INTELFB_VERSION "0.9.4"
@@ -115,6 +119,29 @@
/* Intel agpgart driver */
#define AGP_PHYSICAL_MEMORY 2
+/* store information about an Ixxx DVO */
+/* The i830->i865 use multiple DVOs with multiple i2cs */
+/* the i915, i945 have a single sDVO i2c bus - which is different */
+#define MAX_OUTPUTS 6
+
+/* these are outputs from the chip - integrated only
+ external chips are via DVO or SDVO output */
+#define INTELFB_OUTPUT_UNUSED 0
+#define INTELFB_OUTPUT_ANALOG 1
+#define INTELFB_OUTPUT_DVO 2
+#define INTELFB_OUTPUT_SDVO 3
+#define INTELFB_OUTPUT_LVDS 4
+#define INTELFB_OUTPUT_TVOUT 5
+
+#define INTELFB_DVO_CHIP_NONE 0
+#define INTELFB_DVO_CHIP_LVDS 1
+#define INTELFB_DVO_CHIP_TMDS 2
+#define INTELFB_DVO_CHIP_TVOUT 4
+
+#define INTELFB_OUTPUT_PIPE_NC 0
+#define INTELFB_OUTPUT_PIPE_A 1
+#define INTELFB_OUTPUT_PIPE_B 2
+
/*** Data Types ***/
/* supported chipsets */
@@ -195,6 +222,10 @@ struct intelfb_hwstate {
u32 mem_mode;
u32 fw_blc_0;
u32 fw_blc_1;
+ u16 hwstam;
+ u16 ier;
+ u16 iir;
+ u16 imr;
};
struct intelfb_heap_data {
@@ -204,6 +235,33 @@ struct intelfb_heap_data {
u32 size; // in bytes
};
+#ifdef CONFIG_FB_INTEL_I2C
+struct intelfb_i2c_chan {
+ struct intelfb_info *dinfo;
+ u32 reg;
+ struct i2c_adapter adapter;
+ struct i2c_algo_bit_data algo;
+};
+#endif
+
+struct intelfb_output_rec {
+ int type;
+ int pipe;
+ int flags;
+
+#ifdef CONFIG_FB_INTEL_I2C
+ struct intelfb_i2c_chan i2c_bus;
+ struct intelfb_i2c_chan ddc_bus;
+#endif
+};
+
+struct intelfb_vsync {
+ wait_queue_head_t wait;
+ unsigned int count;
+ int pan_display;
+ u32 pan_offset;
+};
+
struct intelfb_info {
struct fb_info *info;
struct fb_ops *fbops;
@@ -220,7 +278,7 @@ struct intelfb_info {
u8 fbmem_gart;
/* mtrr support */
- u32 mtrr_reg;
+ int mtrr_reg;
u32 has_mtrr;
/* heap data */
@@ -267,6 +325,12 @@ struct intelfb_info {
int fixed_mode;
int ring_active;
int flag;
+ unsigned long irq_flags;
+ int open;
+
+ /* vsync */
+ struct intelfb_vsync vsync;
+ spinlock_t int_lock;
/* hw cursor */
int cursor_on;
@@ -285,12 +349,25 @@ struct intelfb_info {
/* index into plls */
int pll_index;
+
+ /* outputs */
+ int num_outputs;
+ struct intelfb_output_rec output[MAX_OUTPUTS];
};
#define IS_I9XX(dinfo) (((dinfo)->chipset == INTEL_915G)||(dinfo->chipset == INTEL_915GM)||((dinfo)->chipset == INTEL_945G)||(dinfo->chipset==INTEL_945GM))
+#ifndef FBIO_WAITFORVSYNC
+#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32)
+#endif
+
/*** function prototypes ***/
extern int intelfb_var_to_depth(const struct fb_var_screeninfo *var);
+#ifdef CONFIG_FB_INTEL_I2C
+extern void intelfb_create_i2c_busses(struct intelfb_info *dinfo);
+extern void intelfb_delete_i2c_busses(struct intelfb_info *dinfo);
+#endif
+
#endif /* _INTELFB_H */
diff --git a/drivers/video/intelfb/intelfb_i2c.c b/drivers/video/intelfb/intelfb_i2c.c
new file mode 100644
index 000000000000..5686e2164e39
--- /dev/null
+++ b/drivers/video/intelfb/intelfb_i2c.c
@@ -0,0 +1,199 @@
+/**************************************************************************
+
+ Copyright 2006 Dave Airlie <airlied@linux.ie>
+
+All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+on the rights to use, copy, modify, merge, publish, distribute, sub
+license, and/or sell copies of the Software, and to permit persons to whom
+the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+THE COPYRIGHT HOLDERS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+**************************************************************************/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fb.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c-id.h>
+#include <linux/i2c-algo-bit.h>
+
+#include <asm/io.h>
+
+#include "intelfb.h"
+#include "intelfbhw.h"
+
+/* bit locations in the registers */
+#define SCL_DIR_MASK 0x0001
+#define SCL_DIR 0x0002
+#define SCL_VAL_MASK 0x0004
+#define SCL_VAL_OUT 0x0008
+#define SCL_VAL_IN 0x0010
+#define SDA_DIR_MASK 0x0100
+#define SDA_DIR 0x0200
+#define SDA_VAL_MASK 0x0400
+#define SDA_VAL_OUT 0x0800
+#define SDA_VAL_IN 0x1000
+
+static void intelfb_gpio_setscl(void *data, int state)
+{
+ struct intelfb_i2c_chan *chan = data;
+ struct intelfb_info *dinfo = chan->dinfo;
+ u32 val;
+
+ OUTREG(chan->reg, (state ? SCL_VAL_OUT : 0) | SCL_DIR | SCL_DIR_MASK | SCL_VAL_MASK);
+ val = INREG(chan->reg);
+}
+
+static void intelfb_gpio_setsda(void *data, int state)
+{
+ struct intelfb_i2c_chan *chan = data;
+ struct intelfb_info *dinfo = chan->dinfo;
+ u32 val;
+
+ OUTREG(chan->reg, (state ? SDA_VAL_OUT : 0) | SDA_DIR | SDA_DIR_MASK | SDA_VAL_MASK);
+ val = INREG(chan->reg);
+}
+
+static int intelfb_gpio_getscl(void *data)
+{
+ struct intelfb_i2c_chan *chan = data;
+ struct intelfb_info *dinfo = chan->dinfo;
+ u32 val;
+
+ OUTREG(chan->reg, SCL_DIR_MASK);
+ OUTREG(chan->reg, 0);
+ val = INREG(chan->reg);
+ return ((val & SCL_VAL_IN) != 0);
+}
+
+static int intelfb_gpio_getsda(void *data)
+{
+ struct intelfb_i2c_chan *chan = data;
+ struct intelfb_info *dinfo = chan->dinfo;
+ u32 val;
+
+ OUTREG(chan->reg, SDA_DIR_MASK);
+ OUTREG(chan->reg, 0);
+ val = INREG(chan->reg);
+ return ((val & SDA_VAL_IN) != 0);
+}
+
+static int intelfb_setup_i2c_bus(struct intelfb_info *dinfo,
+ struct intelfb_i2c_chan *chan,
+ const u32 reg, const char *name)
+{
+ int rc;
+
+ chan->dinfo = dinfo;
+ chan->reg = reg;
+ snprintf(chan->adapter.name, I2C_NAME_SIZE, "intelfb %s", name);
+ chan->adapter.owner = THIS_MODULE;
+ chan->adapter.id = I2C_HW_B_INTELFB;
+ chan->adapter.algo_data = &chan->algo;
+ chan->adapter.dev.parent = &chan->dinfo->pdev->dev;
+ chan->algo.setsda = intelfb_gpio_setsda;
+ chan->algo.setscl = intelfb_gpio_setscl;
+ chan->algo.getsda = intelfb_gpio_getsda;
+ chan->algo.getscl = intelfb_gpio_getscl;
+ chan->algo.udelay = 40;
+ chan->algo.timeout = 20;
+ chan->algo.data = chan;
+
+ i2c_set_adapdata(&chan->adapter, chan);
+
+ /* Raise SCL and SDA */
+ intelfb_gpio_setsda(chan, 1);
+ intelfb_gpio_setscl(chan, 1);
+ udelay(20);
+
+ rc = i2c_bit_add_bus(&chan->adapter);
+ if (rc == 0)
+ DBG_MSG("I2C bus %s registered.\n", name);
+ else
+ WRN_MSG("Failed to register I2C bus %s.\n", name);
+ return rc;
+}
+
+void intelfb_create_i2c_busses(struct intelfb_info *dinfo)
+{
+ int i = 0;
+
+ /* everyone has at least a single analog output */
+ dinfo->num_outputs = 1;
+ dinfo->output[i].type = INTELFB_OUTPUT_ANALOG;
+
+ /* setup the DDC bus for analog output */
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOA, "CRTDDC_A");
+ i++;
+
+ /* need to add the output busses for each device
+ - this function is very incomplete
+ - i915GM has LVDS and TVOUT for example
+ */
+ switch(dinfo->chipset) {
+ case INTEL_830M:
+ case INTEL_845G:
+ case INTEL_855GM:
+ case INTEL_865G:
+ dinfo->output[i].type = INTELFB_OUTPUT_DVO;
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].ddc_bus, GPIOD, "DVODDC_D");
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "DVOI2C_E");
+ i++;
+ break;
+ case INTEL_915G:
+ case INTEL_915GM:
+ /* has some LVDS + tv-out */
+ case INTEL_945G:
+ case INTEL_945GM:
+ /* SDVO ports have a single control bus - 2 devices */
+ dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
+ intelfb_setup_i2c_bus(dinfo, &dinfo->output[i].i2c_bus, GPIOE, "SDVOCTRL_E");
+ /* TODO: initialize the SDVO */
+// I830SDVOInit(pScrn, i, DVOB);
+ i++;
+
+ /* set up SDVOC */
+ dinfo->output[i].type = INTELFB_OUTPUT_SDVO;
+ dinfo->output[i].i2c_bus = dinfo->output[i - 1].i2c_bus;
+ /* TODO: initialize the SDVO */
+// I830SDVOInit(pScrn, i, DVOC);
+ i++;
+ break;
+ }
+ dinfo->num_outputs = i;
+}
+
+void intelfb_delete_i2c_busses(struct intelfb_info *dinfo)
+{
+ int i;
+
+ for (i = 0; i < MAX_OUTPUTS; i++) {
+ if (dinfo->output[i].i2c_bus.dinfo) {
+ i2c_bit_del_bus(&dinfo->output[i].i2c_bus.adapter);
+ dinfo->output[i].i2c_bus.dinfo = NULL;
+ }
+ if (dinfo->output[i].ddc_bus.dinfo) {
+ i2c_bit_del_bus(&dinfo->output[i].ddc_bus.adapter);
+ dinfo->output[i].ddc_bus.dinfo = NULL;
+ }
+ }
+}
diff --git a/drivers/video/intelfb/intelfbdrv.c b/drivers/video/intelfb/intelfbdrv.c
index 06af89d44a0d..6f9de04193d2 100644
--- a/drivers/video/intelfb/intelfbdrv.c
+++ b/drivers/video/intelfb/intelfbdrv.c
@@ -136,6 +136,8 @@
static void __devinit get_initial_mode(struct intelfb_info *dinfo);
static void update_dinfo(struct intelfb_info *dinfo,
struct fb_var_screeninfo *var);
+static int intelfb_open(struct fb_info *info, int user);
+static int intelfb_release(struct fb_info *info, int user);
static int intelfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);
static int intelfb_set_par(struct fb_info *info);
@@ -194,6 +196,8 @@ static int num_registered = 0;
/* fb ops */
static struct fb_ops intel_fb_ops = {
.owner = THIS_MODULE,
+ .fb_open = intelfb_open,
+ .fb_release = intelfb_release,
.fb_check_var = intelfb_check_var,
.fb_set_par = intelfb_set_par,
.fb_setcolreg = intelfb_setcolreg,
@@ -446,6 +450,8 @@ cleanup(struct intelfb_info *dinfo)
if (!dinfo)
return;
+ intelfbhw_disable_irq(dinfo);
+
fb_dealloc_cmap(&dinfo->info->cmap);
kfree(dinfo->info->pixmap.addr);
@@ -467,6 +473,11 @@ cleanup(struct intelfb_info *dinfo)
agp_free_memory(dinfo->gtt_ring_mem);
}
+#ifdef CONFIG_FB_INTEL_I2C
+ /* un-register I2C bus */
+ intelfb_delete_i2c_busses(dinfo);
+#endif
+
if (dinfo->mmio_base)
iounmap((void __iomem *)dinfo->mmio_base);
if (dinfo->aperture.virtual)
@@ -844,6 +855,11 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
if (bailearly == 5)
bailout(dinfo);
+#ifdef CONFIG_FB_INTEL_I2C
+ /* register I2C bus */
+ intelfb_create_i2c_busses(dinfo);
+#endif
+
if (bailearly == 6)
bailout(dinfo);
@@ -888,6 +904,13 @@ intelfb_pci_register(struct pci_dev *pdev, const struct pci_device_id *ent)
}
dinfo->registered = 1;
+ dinfo->open = 0;
+
+ init_waitqueue_head(&dinfo->vsync.wait);
+ spin_lock_init(&dinfo->int_lock);
+ dinfo->irq_flags = 0;
+ dinfo->vsync.pan_display = 0;
+ dinfo->vsync.pan_offset = 0;
return 0;
@@ -1188,6 +1211,34 @@ update_dinfo(struct intelfb_info *dinfo, struct fb_var_screeninfo *var)
***************************************************************/
static int
+intelfb_open(struct fb_info *info, int user)
+{
+ struct intelfb_info *dinfo = GET_DINFO(info);
+
+ if (user) {
+ dinfo->open++;
+ }
+
+ return 0;
+}
+
+static int
+intelfb_release(struct fb_info *info, int user)
+{
+ struct intelfb_info *dinfo = GET_DINFO(info);
+
+ if (user) {
+ dinfo->open--;
+ msleep(1);
+ if (!dinfo->open) {
+ intelfbhw_disable_irq(dinfo);
+ }
+ }
+
+ return 0;
+}
+
+static int
intelfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
int change_var = 0;
@@ -1433,6 +1484,19 @@ static int
intelfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
{
int retval = 0;
+ struct intelfb_info *dinfo = GET_DINFO(info);
+ u32 pipe = 0;
+
+ switch (cmd) {
+ case FBIO_WAITFORVSYNC:
+ if (get_user(pipe, (__u32 __user *)arg))
+ return -EFAULT;
+
+ retval = intelfbhw_wait_for_vsync(dinfo, pipe);
+ break;
+ default:
+ break;
+ }
return retval;
}
diff --git a/drivers/video/intelfb/intelfbhw.c b/drivers/video/intelfb/intelfbhw.c
index 2a9322f9cfdc..eeeeff9a09eb 100644
--- a/drivers/video/intelfb/intelfbhw.c
+++ b/drivers/video/intelfb/intelfbhw.c
@@ -32,6 +32,7 @@
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
@@ -368,7 +369,13 @@ intelfbhw_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
offset += dinfo->fb.offset << 12;
- OUTREG(DSPABASE, offset);
+ dinfo->vsync.pan_offset = offset;
+ if ((var->activate & FB_ACTIVATE_VBL) && !intelfbhw_enable_irq(dinfo, 0)) {
+ dinfo->vsync.pan_display = 1;
+ } else {
+ dinfo->vsync.pan_display = 0;
+ OUTREG(DSPABASE, offset);
+ }
return 0;
}
@@ -585,6 +592,11 @@ intelfbhw_read_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw,
hw->fw_blc_0 = INREG(FW_BLC_0);
hw->fw_blc_1 = INREG(FW_BLC_1);
+ hw->hwstam = INREG16(HWSTAM);
+ hw->ier = INREG16(IER);
+ hw->iir = INREG16(IIR);
+ hw->imr = INREG16(IMR);
+
return 0;
}
@@ -613,6 +625,7 @@ static int calc_vclock(int index, int m1, int m2, int n, int p1, int p2, int lvd
return vco / p;
}
+#if REGDUMP
static void
intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
{
@@ -638,6 +651,7 @@ intelfbhw_get_p1p2(struct intelfb_info *dinfo, int dpll, int *o_p1, int *o_p2)
*o_p1 = p1;
*o_p2 = p2;
}
+#endif
void
@@ -794,6 +808,10 @@ intelfbhw_print_hw_state(struct intelfb_info *dinfo, struct intelfb_hwstate *hw)
printk(" FW_BLC_0 0x%08x\n", hw->fw_blc_0);
printk(" FW_BLC_1 0x%08x\n", hw->fw_blc_1);
+ printk(" HWSTAM 0x%04x\n", hw->hwstam);
+ printk(" IER 0x%04x\n", hw->ier);
+ printk(" IIR 0x%04x\n", hw->iir);
+ printk(" IMR 0x%04x\n", hw->imr);
printk("hw state dump end\n");
#endif
}
@@ -1932,3 +1950,119 @@ intelfbhw_cursor_reset(struct intelfb_info *dinfo) {
addr += 16;
}
}
+
+static irqreturn_t
+intelfbhw_irq(int irq, void *dev_id) {
+ int handled = 0;
+ u16 tmp;
+ struct intelfb_info *dinfo = (struct intelfb_info *)dev_id;
+
+ spin_lock(&dinfo->int_lock);
+
+ tmp = INREG16(IIR);
+ tmp &= VSYNC_PIPE_A_INTERRUPT;
+
+ if (tmp == 0) {
+ spin_unlock(&dinfo->int_lock);
+ return IRQ_RETVAL(handled);
+ }
+
+ OUTREG16(IIR, tmp);
+
+ if (tmp & VSYNC_PIPE_A_INTERRUPT) {
+ dinfo->vsync.count++;
+ if (dinfo->vsync.pan_display) {
+ dinfo->vsync.pan_display = 0;
+ OUTREG(DSPABASE, dinfo->vsync.pan_offset);
+ }
+ wake_up_interruptible(&dinfo->vsync.wait);
+ handled = 1;
+ }
+
+ spin_unlock(&dinfo->int_lock);
+
+ return IRQ_RETVAL(handled);
+}
+
+int
+intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable) {
+
+ if (!test_and_set_bit(0, &dinfo->irq_flags)) {
+ if (request_irq(dinfo->pdev->irq, intelfbhw_irq, SA_SHIRQ, "intelfb", dinfo)) {
+ clear_bit(0, &dinfo->irq_flags);
+ return -EINVAL;
+ }
+
+ spin_lock_irq(&dinfo->int_lock);
+ OUTREG16(HWSTAM, 0xfffe);
+ OUTREG16(IMR, 0x0);
+ OUTREG16(IER, VSYNC_PIPE_A_INTERRUPT);
+ spin_unlock_irq(&dinfo->int_lock);
+ } else if (reenable) {
+ u16 ier;
+
+ spin_lock_irq(&dinfo->int_lock);
+ ier = INREG16(IER);
+ if ((ier & VSYNC_PIPE_A_INTERRUPT)) {
+ DBG_MSG("someone disabled the IRQ [%08X]\n", ier);
+ OUTREG(IER, VSYNC_PIPE_A_INTERRUPT);
+ }
+ spin_unlock_irq(&dinfo->int_lock);
+ }
+ return 0;
+}
+
+void
+intelfbhw_disable_irq(struct intelfb_info *dinfo) {
+ u16 tmp;
+
+ if (test_and_clear_bit(0, &dinfo->irq_flags)) {
+ if (dinfo->vsync.pan_display) {
+ dinfo->vsync.pan_display = 0;
+ OUTREG(DSPABASE, dinfo->vsync.pan_offset);
+ }
+ spin_lock_irq(&dinfo->int_lock);
+ OUTREG16(HWSTAM, 0xffff);
+ OUTREG16(IMR, 0xffff);
+ OUTREG16(IER, 0x0);
+
+ tmp = INREG16(IIR);
+ OUTREG16(IIR, tmp);
+ spin_unlock_irq(&dinfo->int_lock);
+
+ free_irq(dinfo->pdev->irq, dinfo);
+ }
+}
+
+int
+intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe) {
+ struct intelfb_vsync *vsync;
+ unsigned int count;
+ int ret;
+
+ switch (pipe) {
+ case 0:
+ vsync = &dinfo->vsync;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ ret = intelfbhw_enable_irq(dinfo, 0);
+ if (ret) {
+ return ret;
+ }
+
+ count = vsync->count;
+ ret = wait_event_interruptible_timeout(vsync->wait, count != vsync->count, HZ/10);
+ if (ret < 0) {
+ return ret;
+ }
+ if (ret == 0) {
+ intelfbhw_enable_irq(dinfo, 1);
+ DBG_MSG("wait_for_vsync timed out!\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
diff --git a/drivers/video/intelfb/intelfbhw.h b/drivers/video/intelfb/intelfbhw.h
index 10acda098b71..8c54ba8fbdda 100644
--- a/drivers/video/intelfb/intelfbhw.h
+++ b/drivers/video/intelfb/intelfbhw.h
@@ -88,6 +88,19 @@
#define INSTDONE 0x2090
#define PRI_RING_EMPTY 1
+#define HWSTAM 0x2098
+#define IER 0x20A0
+#define IIR 0x20A4
+#define IMR 0x20A8
+#define VSYNC_PIPE_A_INTERRUPT (1 << 7)
+#define PIPE_A_EVENT_INTERRUPT (1 << 4)
+#define VSYNC_PIPE_B_INTERRUPT (1 << 5)
+#define PIPE_B_EVENT_INTERRUPT (1 << 4)
+#define HOST_PORT_EVENT_INTERRUPT (1 << 3)
+#define CAPTURE_EVENT_INTERRUPT (1 << 2)
+#define USER_DEFINED_INTERRUPT (1 << 1)
+#define BREAKPOINT_INTERRUPT 1
+
#define INSTPM 0x20c0
#define SYNC_FLUSH_ENABLE (1 << 5)
@@ -113,6 +126,12 @@
#define FW_DISPC_BL_SHIFT 8
#define FW_DISPC_BL_MASK 0x7
+#define GPIOA 0x5010
+#define GPIOB 0x5014
+#define GPIOC 0x5018 // this may be external DDC on i830
+#define GPIOD 0x501C // this is DVO DDC
+#define GPIOE 0x5020 // this is DVO i2C
+#define GPIOF 0x5024
/* PLL registers */
#define VGA0_DIVISOR 0x06000
@@ -468,9 +487,12 @@
/* I/O macros */
#define INREG8(addr) readb((u8 __iomem *)(dinfo->mmio_base + (addr)))
+#define INREG16(addr) readw((u16 __iomem *)(dinfo->mmio_base + (addr)))
#define INREG(addr) readl((u32 __iomem *)(dinfo->mmio_base + (addr)))
#define OUTREG8(addr, val) writeb((val),(u8 __iomem *)(dinfo->mmio_base + \
(addr)))
+#define OUTREG16(addr, val) writew((val),(u16 __iomem *)(dinfo->mmio_base + \
+ (addr)))
#define OUTREG(addr, val) writel((val),(u32 __iomem *)(dinfo->mmio_base + \
(addr)))
@@ -545,5 +567,8 @@ extern void intelfbhw_cursor_setcolor(struct intelfb_info *dinfo, u32 bg,
extern void intelfbhw_cursor_load(struct intelfb_info *dinfo, int width,
int height, u8 *data);
extern void intelfbhw_cursor_reset(struct intelfb_info *dinfo);
+extern int intelfbhw_enable_irq(struct intelfb_info *dinfo, int reenable);
+extern void intelfbhw_disable_irq(struct intelfb_info *dinfo);
+extern int intelfbhw_wait_for_vsync(struct intelfb_info *dinfo, u32 pipe);
#endif /* _INTELFBHW_H */
diff --git a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c
index 57abbae5520f..795c1a99a680 100644
--- a/drivers/video/matrox/i2c-matroxfb.c
+++ b/drivers/video/matrox/i2c-matroxfb.c
@@ -95,12 +95,12 @@ static struct i2c_adapter matrox_i2c_adapter_template =
static struct i2c_algo_bit_data matrox_i2c_algo_template =
{
- NULL,
- matroxfb_gpio_setsda,
- matroxfb_gpio_setscl,
- matroxfb_gpio_getsda,
- matroxfb_gpio_getscl,
- 10, 10, 100,
+ .setsda = matroxfb_gpio_setsda,
+ .setscl = matroxfb_gpio_setscl,
+ .getsda = matroxfb_gpio_getsda,
+ .getscl = matroxfb_gpio_getscl,
+ .udelay = 10,
+ .timeout = 100,
};
static int i2c_bus_reg(struct i2c_bit_adapter* b, struct matrox_fb_info* minfo,
diff --git a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c
index 4a57dabb77d4..e9b4115fcad0 100644
--- a/drivers/video/matrox/matroxfb_base.c
+++ b/drivers/video/matrox/matroxfb_base.c
@@ -198,7 +198,7 @@ static void matroxfb_crtc1_panpos(WPMINFO2) {
}
}
-static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t matrox_irq(int irq, void *dev_id)
{
u_int32_t status;
int handled = 0;
@@ -2277,10 +2277,13 @@ static void __init matroxfb_init_params(void) {
}
}
-static void __init matrox_init(void) {
+static int __init matrox_init(void) {
+ int err;
+
matroxfb_init_params();
- pci_register_driver(&matroxfb_driver);
+ err = pci_register_driver(&matroxfb_driver);
dev = -1; /* accept all new devices... */
+ return err;
}
/* **************************** exit-time only **************************** */
@@ -2437,6 +2440,7 @@ static int __initdata initialized = 0;
static int __init matroxfb_init(void)
{
char *option = NULL;
+ int err = 0;
DBG(__FUNCTION__)
@@ -2448,11 +2452,11 @@ static int __init matroxfb_init(void)
return -ENXIO;
if (!initialized) {
initialized = 1;
- matrox_init();
+ err = matrox_init();
}
hotplug = 1;
/* never return failure, user can hotplug matrox later... */
- return 0;
+ return err;
}
module_init(matroxfb_init);
diff --git a/drivers/video/mbx/mbxfb.c b/drivers/video/mbx/mbxfb.c
index 6849ab75d403..a32d1af79e07 100644
--- a/drivers/video/mbx/mbxfb.c
+++ b/drivers/video/mbx/mbxfb.c
@@ -118,8 +118,19 @@ static unsigned int mbxfb_get_pixclock(unsigned int pixclock_ps,
/* convert pixclock to KHz */
pixclock = PICOS2KHZ(pixclock_ps);
+ /* PLL output freq = (ref_clk * M) / (N * 2^P)
+ *
+ * M: 1 to 63
+ * N: 1 to 7
+ * P: 0 to 7
+ */
+
+ /* RAPH: When N==1, the resulting pixel clock appears to
+ * get divided by 2. Preventing N=1 by starting the following
+ * loop at 2 prevents this. Is this a bug with my chip
+ * revision or something I dont understand? */
for (m = 1; m < 64; m++) {
- for (n = 1; n < 8; n++) {
+ for (n = 2; n < 8; n++) {
for (p = 0; p < 8; p++) {
clk = (ref_clk * m) / (n * (1 << p));
err = (clk > pixclock) ? (clk - pixclock) :
@@ -244,8 +255,8 @@ static int mbxfb_set_par(struct fb_info *info)
/* setup resolution */
gsctrl &= ~(FMsk(GSCTRL_GSWIDTH) | FMsk(GSCTRL_GSHEIGHT));
- gsctrl |= Gsctrl_Width(info->var.xres - 1) |
- Gsctrl_Height(info->var.yres - 1);
+ gsctrl |= Gsctrl_Width(info->var.xres) |
+ Gsctrl_Height(info->var.yres);
writel(gsctrl, GSCTRL);
udelay(1000);
@@ -402,8 +413,8 @@ static void __devinit setup_graphics(struct fb_info *fbi)
{
unsigned long gsctrl;
- gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres - 1) |
- Gsctrl_Height(fbi->var.yres - 1);
+ gsctrl = GSCTRL_GAMMA_EN | Gsctrl_Width(fbi->var.xres) |
+ Gsctrl_Height(fbi->var.yres);
switch (fbi->var.bits_per_pixel) {
case 16:
if (fbi->var.green.length == 5)
diff --git a/drivers/video/nvidia/nvidia.c b/drivers/video/nvidia/nvidia.c
index f8cd4c519aeb..eb24107bcc81 100644
--- a/drivers/video/nvidia/nvidia.c
+++ b/drivers/video/nvidia/nvidia.c
@@ -28,6 +28,9 @@
#include <asm/prom.h>
#include <asm/pci-bridge.h>
#endif
+#ifdef CONFIG_BOOTX_TEXT
+#include <asm/btext.h>
+#endif
#include "nv_local.h"
#include "nv_type.h"
@@ -681,6 +684,13 @@ static int nvidiafb_set_par(struct fb_info *info)
nvidia_vga_protect(par, 0);
+#ifdef CONFIG_BOOTX_TEXT
+ /* Update debug text engine */
+ btext_update_display(info->fix.smem_start,
+ info->var.xres, info->var.yres,
+ info->var.bits_per_pixel, info->fix.line_length);
+#endif
+
NVTRACE_LEAVE();
return 0;
}
@@ -984,7 +994,10 @@ static int nvidiafb_resume(struct pci_dev *dev)
if (par->pm_state != PM_EVENT_FREEZE) {
pci_restore_state(dev);
- pci_enable_device(dev);
+
+ if (pci_enable_device(dev))
+ goto fail;
+
pci_set_master(dev);
}
@@ -993,6 +1006,7 @@ static int nvidiafb_resume(struct pci_dev *dev)
fb_set_suspend (info, 0);
nvidiafb_blank(FB_BLANK_UNBLANK, info);
+fail:
release_console_sem();
return 0;
}
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 983be3ec2345..fdb33cd21a27 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -339,11 +339,12 @@ static int __devinit platinum_init_fb(struct fb_info *info)
sense = read_platinum_sense(pinfo);
printk(KERN_INFO "platinumfb: Monitor sense value = 0x%x, ", sense);
-
if (default_vmode == VMODE_NVRAM) {
+#ifdef CONFIG_NVRAM
default_vmode = nvram_read_byte(NV_VMODE);
if (default_vmode <= 0 || default_vmode > VMODE_MAX ||
!platinum_reg_init[default_vmode-1])
+#endif
default_vmode = VMODE_CHOOSE;
}
if (default_vmode == VMODE_CHOOSE) {
@@ -351,8 +352,10 @@ static int __devinit platinum_init_fb(struct fb_info *info)
}
if (default_vmode <= 0 || default_vmode > VMODE_MAX)
default_vmode = VMODE_640_480_60;
+#ifdef CONFIG_NVRAM
if (default_cmode == CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
+#endif
if (default_cmode < CMODE_8 || default_cmode > CMODE_32)
default_cmode = CMODE_8;
/*
diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c
index 940ba2be55e9..c7bc80921f16 100644
--- a/drivers/video/pvr2fb.c
+++ b/drivers/video/pvr2fb.c
@@ -187,7 +187,7 @@ static short do_blank = 0; /* (Un)Blank the screen */
static unsigned int is_blanked = 0; /* Is the screen blanked? */
#ifdef CONFIG_SH_STORE_QUEUES
-static struct sq_mapping *pvr2fb_map;
+static unsigned long pvr2fb_map;
#endif
#ifdef CONFIG_SH_DMA
@@ -209,19 +209,21 @@ static int pvr2fb_set_par(struct fb_info *info);
static void pvr2_update_display(struct fb_info *info);
static void pvr2_init_display(struct fb_info *info);
static void pvr2_do_blank(void);
-static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp);
+static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id);
static int pvr2_init_cable(void);
static int pvr2_get_param(const struct pvr2_params *p, const char *s,
int val, int size);
+#ifdef CONFIG_SH_DMA
static ssize_t pvr2fb_write(struct file *file, const char *buf,
size_t count, loff_t *ppos);
+#endif
static struct fb_ops pvr2fb_ops = {
- .owner = THIS_MODULE,
- .fb_setcolreg = pvr2fb_setcolreg,
- .fb_blank = pvr2fb_blank,
- .fb_check_var = pvr2fb_check_var,
- .fb_set_par = pvr2fb_set_par,
+ .owner = THIS_MODULE,
+ .fb_setcolreg = pvr2fb_setcolreg,
+ .fb_blank = pvr2fb_blank,
+ .fb_check_var = pvr2fb_check_var,
+ .fb_set_par = pvr2fb_set_par,
#ifdef CONFIG_SH_DMA
.fb_write = pvr2fb_write,
#endif
@@ -624,7 +626,7 @@ static void pvr2_do_blank(void)
is_blanked = do_blank > 0 ? do_blank : 0;
}
-static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id, struct pt_regs *fp)
+static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id)
{
struct fb_info *info = dev_id;
@@ -783,7 +785,7 @@ static int __init pvr2fb_common_init(void)
goto out_err;
}
- fb_memset((unsigned long)fb_info->screen_base, 0, pvr2_fix.smem_len);
+ fb_memset(fb_info->screen_base, 0, pvr2_fix.smem_len);
pvr2_fix.ypanstep = nopan ? 0 : 1;
pvr2_fix.ywrapstep = nowrap ? 0 : 1;
@@ -820,7 +822,7 @@ static int __init pvr2fb_common_init(void)
modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10));
printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n",
fb_info->node, fb_info->var.xres, fb_info->var.yres,
- fb_info->var.bits_per_pixel,
+ fb_info->var.bits_per_pixel,
get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel),
(char *)pvr2_get_param(cables, NULL, cable_type, 3),
(char *)pvr2_get_param(outputs, NULL, video_output, 3));
@@ -829,10 +831,10 @@ static int __init pvr2fb_common_init(void)
printk(KERN_NOTICE "fb%d: registering with SQ API\n", fb_info->node);
pvr2fb_map = sq_remap(fb_info->fix.smem_start, fb_info->fix.smem_len,
- fb_info->fix.id);
+ fb_info->fix.id, pgprot_val(PAGE_SHARED));
printk(KERN_NOTICE "fb%d: Mapped video memory to SQ addr 0x%lx\n",
- fb_info->node, pvr2fb_map->sq_addr);
+ fb_info->node, pvr2fb_map);
#endif
return 0;
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index bbb07106cd54..8a8ae55a7403 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -59,7 +59,7 @@
#define LCCR3_INVALID_CONFIG_MASK (LCCR3_HSP|LCCR3_VSP|LCCR3_PCD|LCCR3_BPP)
static void (*pxafb_backlight_power)(int);
-static void (*pxafb_lcd_power)(int);
+static void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
static int pxafb_activate_var(struct fb_var_screeninfo *var, struct pxafb_info *);
static void set_ctrlr_state(struct pxafb_info *fbi, u_int state);
@@ -214,6 +214,48 @@ extern unsigned int get_clk_frequency_khz(int info);
#endif
/*
+ * Select the smallest mode that allows the desired resolution to be
+ * displayed. If desired parameters can be rounded up.
+ */
+static struct pxafb_mode_info *pxafb_getmode(struct pxafb_mach_info *mach, struct fb_var_screeninfo *var)
+{
+ struct pxafb_mode_info *mode = NULL;
+ struct pxafb_mode_info *modelist = mach->modes;
+ unsigned int best_x = 0xffffffff, best_y = 0xffffffff;
+ unsigned int i;
+
+ for (i = 0 ; i < mach->num_modes ; i++) {
+ if (modelist[i].xres >= var->xres && modelist[i].yres >= var->yres &&
+ modelist[i].xres < best_x && modelist[i].yres < best_y &&
+ modelist[i].bpp >= var->bits_per_pixel ) {
+ best_x = modelist[i].xres;
+ best_y = modelist[i].yres;
+ mode = &modelist[i];
+ }
+ }
+
+ return mode;
+}
+
+static void pxafb_setmode(struct fb_var_screeninfo *var, struct pxafb_mode_info *mode)
+{
+ var->xres = mode->xres;
+ var->yres = mode->yres;
+ var->bits_per_pixel = mode->bpp;
+ var->pixclock = mode->pixclock;
+ var->hsync_len = mode->hsync_len;
+ var->left_margin = mode->left_margin;
+ var->right_margin = mode->right_margin;
+ var->vsync_len = mode->vsync_len;
+ var->upper_margin = mode->upper_margin;
+ var->lower_margin = mode->lower_margin;
+ var->sync = mode->sync;
+ var->grayscale = mode->cmap_greyscale;
+ var->xres_virtual = var->xres;
+ var->yres_virtual = var->yres;
+}
+
+/*
* pxafb_check_var():
* Get the video params out of 'var'. If a value doesn't fit, round it up,
* if it's too big, return -EINVAL.
@@ -225,15 +267,29 @@ extern unsigned int get_clk_frequency_khz(int info);
static int pxafb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
{
struct pxafb_info *fbi = (struct pxafb_info *)info;
+ struct pxafb_mach_info *inf = fbi->dev->platform_data;
if (var->xres < MIN_XRES)
var->xres = MIN_XRES;
if (var->yres < MIN_YRES)
var->yres = MIN_YRES;
- if (var->xres > fbi->max_xres)
- return -EINVAL;
- if (var->yres > fbi->max_yres)
- return -EINVAL;
+
+ if (inf->fixed_modes) {
+ struct pxafb_mode_info *mode;
+
+ mode = pxafb_getmode(inf, var);
+ if (!mode)
+ return -EINVAL;
+ pxafb_setmode(var, mode);
+ } else {
+ if (var->xres > inf->modes->xres)
+ return -EINVAL;
+ if (var->yres > inf->modes->yres)
+ return -EINVAL;
+ if (var->bits_per_pixel > inf->modes->bpp)
+ return -EINVAL;
+ }
+
var->xres_virtual =
max(var->xres_virtual, var->xres);
var->yres_virtual =
@@ -693,7 +749,7 @@ static inline void __pxafb_lcd_power(struct pxafb_info *fbi, int on)
pr_debug("pxafb: LCD power o%s\n", on ? "n" : "ff");
if (pxafb_lcd_power)
- pxafb_lcd_power(on);
+ pxafb_lcd_power(on, &fbi->fb.var);
}
static void pxafb_setup_gpio(struct pxafb_info *fbi)
@@ -790,7 +846,7 @@ static void pxafb_disable_controller(struct pxafb_info *fbi)
/*
* pxafb_handle_irq: Handle 'LCD DONE' interrupts.
*/
-static irqreturn_t pxafb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pxafb_handle_irq(int irq, void *dev_id)
{
struct pxafb_info *fbi = dev_id;
unsigned int lcsr = LCSR;
@@ -869,9 +925,11 @@ static void set_ctrlr_state(struct pxafb_info *fbi, u_int state)
* registers.
*/
if (old_state == C_ENABLE) {
+ __pxafb_lcd_power(fbi, 0);
pxafb_disable_controller(fbi);
pxafb_setup_gpio(fbi);
pxafb_enable_controller(fbi);
+ __pxafb_lcd_power(fbi, 1);
}
break;
@@ -1049,6 +1107,8 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
struct pxafb_info *fbi;
void *addr;
struct pxafb_mach_info *inf = dev->platform_data;
+ struct pxafb_mode_info *mode = inf->modes;
+ int i, smemlen;
/* Alloc the pxafb_info and pseudo_palette in one step */
fbi = kmalloc(sizeof(struct pxafb_info) + sizeof(u32) * 16, GFP_KERNEL);
@@ -1082,31 +1142,21 @@ static struct pxafb_info * __init pxafb_init_fbinfo(struct device *dev)
addr = addr + sizeof(struct pxafb_info);
fbi->fb.pseudo_palette = addr;
- fbi->max_xres = inf->xres;
- fbi->fb.var.xres = inf->xres;
- fbi->fb.var.xres_virtual = inf->xres;
- fbi->max_yres = inf->yres;
- fbi->fb.var.yres = inf->yres;
- fbi->fb.var.yres_virtual = inf->yres;
- fbi->max_bpp = inf->bpp;
- fbi->fb.var.bits_per_pixel = inf->bpp;
- fbi->fb.var.pixclock = inf->pixclock;
- fbi->fb.var.hsync_len = inf->hsync_len;
- fbi->fb.var.left_margin = inf->left_margin;
- fbi->fb.var.right_margin = inf->right_margin;
- fbi->fb.var.vsync_len = inf->vsync_len;
- fbi->fb.var.upper_margin = inf->upper_margin;
- fbi->fb.var.lower_margin = inf->lower_margin;
- fbi->fb.var.sync = inf->sync;
- fbi->fb.var.grayscale = inf->cmap_greyscale;
+ pxafb_setmode(&fbi->fb.var, mode);
+
fbi->cmap_inverse = inf->cmap_inverse;
fbi->cmap_static = inf->cmap_static;
+
fbi->lccr0 = inf->lccr0;
fbi->lccr3 = inf->lccr3;
fbi->state = C_STARTUP;
fbi->task_state = (u_char)-1;
- fbi->fb.fix.smem_len = fbi->max_xres * fbi->max_yres *
- fbi->max_bpp / 8;
+
+ for (i = 0; i < inf->num_modes; i++) {
+ smemlen = mode[i].xres * mode[i].yres * mode[i].bpp / 8;
+ if (smemlen > fbi->fb.fix.smem_len)
+ fbi->fb.fix.smem_len = smemlen;
+ }
init_waitqueue_head(&fbi->ctrlr_wait);
INIT_WORK(&fbi->task, pxafb_task, fbi);
@@ -1307,12 +1357,12 @@ int __init pxafb_probe(struct platform_device *dev)
(inf->lccr0 & LCCR0_SDS) == LCCR0_Dual)
dev_warn(&dev->dev, "Dual panel only valid in passive mode\n");
if ((inf->lccr0 & LCCR0_PAS) == LCCR0_Pas &&
- (inf->upper_margin || inf->lower_margin))
+ (inf->modes->upper_margin || inf->modes->lower_margin))
dev_warn(&dev->dev, "Upper and lower margins must be 0 in passive mode\n");
#endif
- dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->xres, inf->yres, inf->bpp);
- if (inf->xres == 0 || inf->yres == 0 || inf->bpp == 0) {
+ dev_dbg(&dev->dev, "got a %dx%dx%d LCD\n",inf->modes->xres, inf->modes->yres, inf->modes->bpp);
+ if (inf->modes->xres == 0 || inf->modes->yres == 0 || inf->modes->bpp == 0) {
dev_err(&dev->dev, "Invalid resolution or bit depth\n");
ret = -EINVAL;
goto failed;
diff --git a/drivers/video/pxafb.h b/drivers/video/pxafb.h
index 47f41f70db7a..7499a1c4bf79 100644
--- a/drivers/video/pxafb.h
+++ b/drivers/video/pxafb.h
@@ -41,10 +41,6 @@ struct pxafb_info {
struct fb_info fb;
struct device *dev;
- u_int max_bpp;
- u_int max_xres;
- u_int max_yres;
-
/*
* These are the addresses we mapped
* the framebuffer memory region to.
diff --git a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
index 4acde4f7dbf8..a433cc78ef90 100644
--- a/drivers/video/riva/fbdev.c
+++ b/drivers/video/riva/fbdev.c
@@ -393,8 +393,8 @@ static void riva_bl_init(struct riva_par *par)
mutex_lock(&info->bl_mutex);
info->bl_dev = bd;
fb_bl_default_curve(info, 0,
- 0x158 * FB_BACKLIGHT_MAX / MAX_LEVEL,
- 0x534 * FB_BACKLIGHT_MAX / MAX_LEVEL);
+ MIN_LEVEL * FB_BACKLIGHT_MAX / MAX_LEVEL,
+ FB_BACKLIGHT_MAX);
mutex_unlock(&info->bl_mutex);
down(&bd->sem);
@@ -784,7 +784,7 @@ static void riva_load_video_mode(struct fb_info *info)
NVTRACE_ENTER();
/* time to calculate */
- rivafb_blank(1, info);
+ rivafb_blank(FB_BLANK_NORMAL, info);
bpp = info->var.bits_per_pixel;
if (bpp == 16 && info->var.green.length == 5)
@@ -917,7 +917,7 @@ static void riva_load_video_mode(struct fb_info *info)
par->current_state = newmode;
riva_load_state(par, &par->current_state);
par->riva.LockUnlock(&par->riva, 0); /* important for HW cursor */
- rivafb_blank(0, info);
+ rivafb_blank(FB_BLANK_UNBLANK, info);
NVTRACE_LEAVE();
}
@@ -1843,7 +1843,7 @@ static int __devinit riva_get_EDID_OF(struct fb_info *info, struct pci_dev *pd)
for (i = 0; propnames[i] != NULL; ++i) {
pedid = get_property(dp, propnames[i], NULL);
if (pedid != NULL) {
- par->EDID = pedid;
+ par->EDID = (unsigned char *)pedid;
NVTRACE("LCD found.\n");
return 1;
}
diff --git a/drivers/video/riva/rivafb-i2c.c b/drivers/video/riva/rivafb-i2c.c
index 9751c37c0bfd..c15b259af644 100644
--- a/drivers/video/riva/rivafb-i2c.c
+++ b/drivers/video/riva/rivafb-i2c.c
@@ -25,8 +25,6 @@
#include "rivafb.h"
#include "../edid.h"
-#define RIVA_DDC 0x50
-
static void riva_gpio_setscl(void* data, int state)
{
struct riva_i2c_chan *chan = data;
@@ -158,50 +156,12 @@ void riva_delete_i2c_busses(struct riva_par *par)
par->chan[2].par = NULL;
}
-static u8 *riva_do_probe_i2c_edid(struct riva_i2c_chan *chan)
-{
- u8 start = 0x0;
- struct i2c_msg msgs[] = {
- {
- .addr = RIVA_DDC,
- .len = 1,
- .buf = &start,
- }, {
- .addr = RIVA_DDC,
- .flags = I2C_M_RD,
- .len = EDID_LENGTH,
- },
- };
- u8 *buf;
-
- if (!chan->par)
- return NULL;
-
- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
- if (!buf) {
- dev_warn(&chan->par->pdev->dev, "Out of memory!\n");
- return NULL;
- }
- msgs[1].buf = buf;
-
- if (i2c_transfer(&chan->adapter, msgs, 2) == 2)
- return buf;
- dev_dbg(&chan->par->pdev->dev, "Unable to read EDID block.\n");
- kfree(buf);
- return NULL;
-}
-
int riva_probe_i2c_connector(struct riva_par *par, int conn, u8 **out_edid)
{
u8 *edid = NULL;
- int i;
- for (i = 0; i < 3; i++) {
- /* Do the real work */
- edid = riva_do_probe_i2c_edid(&par->chan[conn-1]);
- if (edid)
- break;
- }
+ edid = fb_ddc_read(&par->chan[conn-1].adapter);
+
if (out_edid)
*out_edid = edid;
if (!edid)
diff --git a/drivers/video/s3c2410fb.c b/drivers/video/s3c2410fb.c
index ad3bdd6f1ac1..59407343cc73 100644
--- a/drivers/video/s3c2410fb.c
+++ b/drivers/video/s3c2410fb.c
@@ -614,7 +614,7 @@ static void s3c2410fb_write_palette(struct s3c2410fb_info *fbi)
}
}
-static irqreturn_t s3c2410fb_irq(int irq, void *dev_id, struct pt_regs *r)
+static irqreturn_t s3c2410fb_irq(int irq, void *dev_id)
{
struct s3c2410fb_info *fbi = dev_id;
unsigned long lcdirq = readl(S3C2410_LCDINTPND);
diff --git a/drivers/video/s3c2410fb.h b/drivers/video/s3c2410fb.h
index be40968f899e..f3f8a8e15012 100644
--- a/drivers/video/s3c2410fb.h
+++ b/drivers/video/s3c2410fb.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/s3c2410fb.h
+ * linux/drivers/video/s3c2410fb.h
* Copyright (c) Arnaud Patard
*
* This file is subject to the terms and conditions of the GNU General Public
diff --git a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c
index a2e6e7205d7e..cd10b18150b8 100644
--- a/drivers/video/sa1100fb.c
+++ b/drivers/video/sa1100fb.c
@@ -1085,7 +1085,7 @@ static void sa1100fb_disable_controller(struct sa1100fb_info *fbi)
/*
* sa1100fb_handle_irq: Handle 'LCD DONE' interrupts.
*/
-static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sa1100fb_handle_irq(int irq, void *dev_id)
{
struct sa1100fb_info *fbi = dev_id;
unsigned int lcsr = LCSR;
diff --git a/drivers/video/savage/savagefb-i2c.c b/drivers/video/savage/savagefb-i2c.c
index e83befd16d63..3f94223b7f0c 100644
--- a/drivers/video/savage/savagefb-i2c.c
+++ b/drivers/video/savage/savagefb-i2c.c
@@ -148,7 +148,6 @@ static int savage_setup_i2c_bus(struct savagefb_i2c_chan *chan,
chan->adapter.algo_data = &chan->algo;
chan->adapter.dev.parent = &chan->par->pcidev->dev;
chan->algo.udelay = 40;
- chan->algo.mdelay = 5;
chan->algo.timeout = 20;
chan->algo.data = chan;
@@ -214,52 +213,15 @@ void savagefb_delete_i2c_busses(struct fb_info *info)
par->chan.par = NULL;
}
-static u8 *savage_do_probe_i2c_edid(struct savagefb_i2c_chan *chan)
-{
- u8 start = 0x0;
- struct i2c_msg msgs[] = {
- {
- .addr = SAVAGE_DDC,
- .len = 1,
- .buf = &start,
- }, {
- .addr = SAVAGE_DDC,
- .flags = I2C_M_RD,
- .len = EDID_LENGTH,
- },
- };
- u8 *buf = NULL;
-
- if (chan->par) {
- buf = kmalloc(EDID_LENGTH, GFP_KERNEL);
-
- if (buf) {
- msgs[1].buf = buf;
-
- if (i2c_transfer(&chan->adapter, msgs, 2) != 2) {
- dev_dbg(&chan->par->pcidev->dev,
- "Unable to read EDID block.\n");
- kfree(buf);
- buf = NULL;
- }
- }
- }
-
- return buf;
-}
-
int savagefb_probe_i2c_connector(struct fb_info *info, u8 **out_edid)
{
struct savagefb_par *par = info->par;
- u8 *edid = NULL;
- int i;
-
- for (i = 0; i < 3; i++) {
- /* Do the real work */
- edid = savage_do_probe_i2c_edid(&par->chan);
- if (edid)
- break;
- }
+ u8 *edid;
+
+ if (par->chan.par)
+ edid = fb_ddc_read(&par->chan.adapter);
+ else
+ edid = NULL;
if (!edid) {
/* try to get from firmware */
diff --git a/drivers/video/sis/init.h b/drivers/video/sis/init.h
index 7ecab87cef02..59d12844b4dd 100644
--- a/drivers/video/sis/init.h
+++ b/drivers/video/sis/init.h
@@ -77,16 +77,9 @@
#include <linux/types.h>
#include <asm/io.h>
#include <linux/fb.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <video/fbcon.h>
-#endif
#include "sis.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/sisfb.h>
-#else
#include <video/sisfb.h>
#endif
-#endif
/* Mode numbers */
static const unsigned short ModeIndex_320x200[] = {0x59, 0x41, 0x00, 0x4f};
diff --git a/drivers/video/sis/init301.h b/drivers/video/sis/init301.h
index bc321dc57e92..4f3a28699d37 100644
--- a/drivers/video/sis/init301.h
+++ b/drivers/video/sis/init301.h
@@ -71,16 +71,9 @@
#include <linux/types.h>
#include <asm/io.h>
#include <linux/fb.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <video/fbcon.h>
-#endif
#include "sis.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/sisfb.h>
-#else
#include <video/sisfb.h>
#endif
-#endif
static const unsigned char SiS_YPbPrTable[3][64] = {
{
diff --git a/drivers/video/sis/initextlfb.c b/drivers/video/sis/initextlfb.c
index 09f5d758b6c0..c3884a29f4c5 100644
--- a/drivers/video/sis/initextlfb.c
+++ b/drivers/video/sis/initextlfb.c
@@ -34,12 +34,10 @@
#include <linux/types.h>
#include <linux/fb.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
unsigned char modeno, unsigned char rateindex);
int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
unsigned char rateindex, struct fb_var_screeninfo *var);
-#endif
BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
int *htotal, int *vtotal, unsigned char rateindex);
@@ -49,7 +47,6 @@ extern BOOLEAN SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *Mode
extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata,
int xres, int yres, struct fb_var_screeninfo *var, BOOLEAN writeres);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
int
sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr, unsigned char modeno,
unsigned char rateindex)
@@ -177,7 +174,6 @@ sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
return 1;
}
-#endif /* Linux >= 2.5 */
BOOLEAN
sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno, int *htotal,
diff --git a/drivers/video/sis/osdef.h b/drivers/video/sis/osdef.h
index f59568020eb2..d048bd39961b 100644
--- a/drivers/video/sis/osdef.h
+++ b/drivers/video/sis/osdef.h
@@ -100,11 +100,7 @@
#define SIS315H
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#define SIS_LINUX_KERNEL_26
-#else
-#define SIS_LINUX_KERNEL_24
-#endif
#if !defined(SIS300) && !defined(SIS315H)
#warning Neither CONFIG_FB_SIS_300 nor CONFIG_FB_SIS_315 is set
diff --git a/drivers/video/sis/sis_accel.c b/drivers/video/sis/sis_accel.c
index 3b7ce032e2ed..7addf91d2fea 100644
--- a/drivers/video/sis/sis_accel.c
+++ b/drivers/video/sis/sis_accel.c
@@ -32,22 +32,10 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fb.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/console.h>
-#endif
#include <linux/ioport.h>
#include <linux/types.h>
-
#include <asm/io.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#endif
-
#include "sis.h"
#include "sis_accel.h"
@@ -91,11 +79,9 @@ static const u8 sisPatALUConv[] =
0xFF, /* dest = 0xFF; 1, GXset, 0xF */
};
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
static const int myrops[] = {
3, 10, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
};
-#endif
/* 300 series ----------------------------------------------------- */
#ifdef CONFIG_FB_SIS_300
@@ -315,8 +301,6 @@ void sisfb_syncaccel(struct sis_video_info *ivideo)
}
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) /* --------------- 2.5 --------------- */
-
int fbcon_sis_sync(struct fb_info *info)
{
struct sis_video_info *ivideo = (struct sis_video_info *)info->par;
@@ -438,13 +422,3 @@ void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area)
sisfb_syncaccel(ivideo);
}
-
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* -------------- 2.4 --------------- */
-
-#include "sisfb_accel_2_4.h"
-
-#endif /* KERNEL VERSION */
-
-
diff --git a/drivers/video/sis/sis_accel.h b/drivers/video/sis/sis_accel.h
index 046e2c4a8e09..30e03cdf6b85 100644
--- a/drivers/video/sis/sis_accel.h
+++ b/drivers/video/sis/sis_accel.h
@@ -390,25 +390,11 @@
MMIO_OUT32(ivideo->mmio_vbase, FIRE_TRIGGER, 0); \
CmdQueLen -= 2;
-
int sisfb_initaccel(struct sis_video_info *ivideo);
void sisfb_syncaccel(struct sis_video_info *ivideo);
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,33)
-void fbcon_sis_bmove(struct display *p, int srcy, int srcx, int dsty,
- int dstx, int height, int width);
-void fbcon_sis_revc(struct display *p, int srcy, int srcx);
-void fbcon_sis_clear8(struct vc_data *conp, struct display *p, int srcy,
- int srcx, int height, int width);
-void fbcon_sis_clear16(struct vc_data *conp, struct display *p, int srcy,
- int srcx, int height, int width);
-void fbcon_sis_clear32(struct vc_data *conp, struct display *p, int srcy,
- int srcx, int height, int width);
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,34)
int fbcon_sis_sync(struct fb_info *info);
void fbcon_sis_fillrect(struct fb_info *info, const struct fb_fillrect *rect);
void fbcon_sis_copyarea(struct fb_info *info, const struct fb_copyarea *area);
-#endif
#endif
diff --git a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c
index 895ebda7d9e3..baaf495a0a6d 100644
--- a/drivers/video/sis/sis_main.c
+++ b/drivers/video/sis/sis_main.c
@@ -35,9 +35,7 @@
#include <linux/version.h>
#include <linux/module.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
#include <linux/moduleparam.h>
-#endif
#include <linux/kernel.h>
#include <linux/smp_lock.h>
#include <linux/spinlock.h>
@@ -58,9 +56,6 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <linux/vt_kern.h>
-#endif
#include <linux/capability.h>
#include <linux/fs.h>
#include <linux/types.h>
@@ -70,35 +65,9 @@
#include <asm/mtrr.h>
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#include <video/fbcon.h>
-#include <video/fbcon-cfb8.h>
-#include <video/fbcon-cfb16.h>
-#include <video/fbcon-cfb24.h>
-#include <video/fbcon-cfb32.h>
-#endif
-
#include "sis.h"
#include "sis_main.h"
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,3)
-#error "This version of sisfb requires at least 2.6.3"
-#endif
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#ifdef FBCON_HAS_CFB8
-extern struct display_switch fbcon_sis8;
-#endif
-#ifdef FBCON_HAS_CFB16
-extern struct display_switch fbcon_sis16;
-#endif
-#ifdef FBCON_HAS_CFB32
-extern struct display_switch fbcon_sis32;
-#endif
-#endif
-
static void sisfb_handle_command(struct sis_video_info *ivideo,
struct sisfb_cmd *sisfb_command);
@@ -114,17 +83,7 @@ sisfb_setdefaultparms(void)
sisfb_max = -1;
sisfb_userom = -1;
sisfb_useoem = -1;
-#ifdef MODULE
- /* Module: "None" for 2.4, default mode for 2.5+ */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
- sisfb_mode_idx = -1;
-#else
- sisfb_mode_idx = MODE_INDEX_NONE;
-#endif
-#else
- /* Static: Default mode */
sisfb_mode_idx = -1;
-#endif
sisfb_parm_rate = -1;
sisfb_crt1off = 0;
sisfb_forcecrt1 = -1;
@@ -142,10 +101,6 @@ sisfb_setdefaultparms(void)
sisfb_tvxposoffset = 0;
sisfb_tvyposoffset = 0;
sisfb_nocrt2rate = 0;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- sisfb_inverse = 0;
- sisfb_fontname[0] = 0;
-#endif
#if !defined(__i386__) && !defined(__x86_64__)
sisfb_resetcard = 0;
sisfb_videoram = 0;
@@ -162,14 +117,11 @@ sisfb_search_vesamode(unsigned int vesamode, BOOLEAN quiet)
/* We don't know the hardware specs yet and there is no ivideo */
if(vesamode == 0) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- sisfb_mode_idx = MODE_INDEX_NONE;
-#else
if(!quiet)
printk(KERN_ERR "sisfb: Invalid mode. Using default.\n");
sisfb_mode_idx = DEFAULT_MODE;
-#endif
+
return;
}
@@ -215,7 +167,6 @@ sisfb_search_mode(char *name, BOOLEAN quiet)
return;
}
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
if(!strnicmp(name, sisbios_mode[MODE_INDEX_NONE].name, strlen(name))) {
if(!quiet)
printk(KERN_ERR "sisfb: Mode 'none' not supported anymore. Using default.\n");
@@ -223,7 +174,7 @@ sisfb_search_mode(char *name, BOOLEAN quiet)
sisfb_mode_idx = DEFAULT_MODE;
return;
}
-#endif
+
if(strlen(name) <= 19) {
strcpy(strbuf1, name);
for(i = 0; i < strlen(strbuf1); i++) {
@@ -1315,20 +1266,7 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
ivideo->refresh_rate = 60;
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- if(ivideo->sisfb_thismonitor.datavalid) {
- if(!sisfb_verify_rate(ivideo, &ivideo->sisfb_thismonitor, ivideo->sisfb_mode_idx,
- ivideo->rate_idx, ivideo->refresh_rate)) {
- printk(KERN_INFO "sisfb: WARNING: Refresh rate exceeds monitor specs!\n");
- }
- }
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- if(((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) && isactive) {
-#else
if(isactive) {
-#endif
/* If acceleration to be used? Need to know
* before pre/post_set_mode()
*/
@@ -1367,9 +1305,7 @@ sisfb_do_set_var(struct fb_var_screeninfo *var, int isactive, struct fb_info *in
ivideo->current_linelength = ivideo->video_linelength;
ivideo->current_pixclock = var->pixclock;
ivideo->current_refresh_rate = ivideo->refresh_rate;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
ivideo->sisfb_lastrates[ivideo->mode_no] = ivideo->refresh_rate;
-#endif
}
return 0;
@@ -1435,18 +1371,6 @@ sisfb_pan_var(struct sis_video_info *ivideo, struct fb_var_screeninfo *var)
return 0;
}
-/* ------------ FBDev related routines for 2.4 series ----------- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-
-#include "sisfb_fbdev_2_4.h"
-
-#endif
-
-/* ------------ FBDev related routines for 2.6 series ----------- */
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-
static int
sisfb_open(struct fb_info *info, int user)
{
@@ -1744,8 +1668,6 @@ sisfb_blank(int blank, struct fb_info *info)
return sisfb_myblank(ivideo, blank);
}
-#endif
-
/* ----------- FBDev related routines for all series ---------- */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
@@ -1969,20 +1891,6 @@ sisfb_get_fix(struct fb_fix_screeninfo *fix, int con, struct fb_info *info)
/* ---------------- fb_ops structures ----------------- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static struct fb_ops sisfb_ops = {
- .owner = THIS_MODULE,
- .fb_get_fix = sisfb_get_fix,
- .fb_get_var = sisfb_get_var,
- .fb_set_var = sisfb_set_var,
- .fb_get_cmap = sisfb_get_cmap,
- .fb_set_cmap = sisfb_set_cmap,
- .fb_pan_display = sisfb_pan_display,
- .fb_ioctl = sisfb_ioctl
-};
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
static struct fb_ops sisfb_ops = {
.owner = THIS_MODULE,
.fb_open = sisfb_open,
@@ -2004,7 +1912,6 @@ static struct fb_ops sisfb_ops = {
#endif
.fb_ioctl = sisfb_ioctl
};
-#endif
/* ---------------- Chip generation dependent routines ---------------- */
@@ -4100,16 +4007,6 @@ sisfb_setup(char *options)
sisfb_search_mode(this_opt + 5, FALSE);
} else if(!strnicmp(this_opt, "vesa:", 5)) {
sisfb_search_vesamode(simple_strtoul(this_opt + 5, NULL, 0), FALSE);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- } else if(!strnicmp(this_opt, "inverse", 7)) {
- sisfb_inverse = 1;
- /* fb_invert_cmaps(); */
- } else if(!strnicmp(this_opt, "font:", 5)) {
- if(strlen(this_opt + 5) < 40) {
- strncpy(sisfb_fontname, this_opt + 5, sizeof(sisfb_fontname) - 1);
- sisfb_fontname[sizeof(sisfb_fontname) - 1] = '\0';
- }
-#endif
} else if(!strnicmp(this_opt, "rate:", 5)) {
sisfb_parm_rate = simple_strtoul(this_opt + 5, NULL, 0);
} else if(!strnicmp(this_opt, "forcecrt1:", 10)) {
@@ -5870,17 +5767,9 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if(sisfb_off)
return -ENXIO;
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
sis_fb_info = framebuffer_alloc(sizeof(*ivideo), &pdev->dev);
if(!sis_fb_info)
return -ENOMEM;
-#else
- sis_fb_info = kmalloc(sizeof(*sis_fb_info) + sizeof(*ivideo), GFP_KERNEL);
- if(!sis_fb_info)
- return -ENOMEM;
- memset(sis_fb_info, 0, sizeof(*sis_fb_info) + sizeof(*ivideo));
- sis_fb_info->par = ((char *)sis_fb_info + sizeof(*sis_fb_info));
-#endif
ivideo = (struct sis_video_info *)sis_fb_info->par;
ivideo->memyselfandi = sis_fb_info;
@@ -5970,10 +5859,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ivideo->tvxpos = sisfb_tvxposoffset;
ivideo->tvypos = sisfb_tvyposoffset;
ivideo->sisfb_nocrt2rate = sisfb_nocrt2rate;
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
- ivideo->sisfb_inverse = sisfb_inverse;
-#endif
-
ivideo->refresh_rate = 0;
if(ivideo->sisfb_parm_rate != -1) {
ivideo->refresh_rate = ivideo->sisfb_parm_rate;
@@ -6049,10 +5934,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
}
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- strcpy(sis_fb_info->modename, ivideo->myid);
-#endif
-
ivideo->SiS_Pr.ChipType = ivideo->chip;
ivideo->SiS_Pr.ivideo = (void *)ivideo;
@@ -6134,20 +6015,6 @@ sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#endif
}
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-#ifdef MODULE
- if((reg & 0x80) && (reg != 0xff)) {
- if((sisbios_mode[ivideo->sisfb_mode_idx].mode_no[ivideo->mni])
- != 0xFF) {
- printk(KERN_INFO "sisfb: Cannot initialize display mode, "
- "X server is active\n");
- ret = -EBUSY;
- goto error_4;
- }
- }
-#endif
-#endif
-
/* Search and copy ROM image */
ivideo->bios_abase = NULL;
ivideo->SiS_Pr.VirtualRomBase = NULL;
@@ -6281,9 +6148,6 @@ error_0: iounmap(ivideo->video_vbase);
error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
error_3: vfree(ivideo->bios_abase);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-error_4:
-#endif
if(ivideo->lpcdev)
SIS_PCI_PUT_DEVICE(ivideo->lpcdev);
if(ivideo->nbridge)
@@ -6586,7 +6450,6 @@ error_4:
sis_fb_info->fix = ivideo->sisfb_fix;
sis_fb_info->screen_base = ivideo->video_vbase + ivideo->video_offset;
sis_fb_info->fbops = &sisfb_ops;
-
sisfb_get_fix(&sis_fb_info->fix, -1, sis_fb_info);
sis_fb_info->pseudo_palette = ivideo->pseudo_palette;
@@ -6603,10 +6466,6 @@ error_4:
}
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- vc_resize_con(1, 1, 0);
-#endif
-
if(register_framebuffer(sis_fb_info) < 0) {
printk(KERN_ERR "sisfb: Fatal error: Failed to register framebuffer\n");
ret = -EINVAL;
@@ -6653,12 +6512,7 @@ error_4:
printk(KERN_INFO "fb%d: %s frame buffer device version %d.%d.%d\n",
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- GET_FB_IDX(sis_fb_info->node),
-#else
- sis_fb_info->node,
-#endif
- ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
+ sis_fb_info->node, ivideo->myid, VER_MAJOR, VER_MINOR, VER_LEVEL);
printk(KERN_INFO "sisfb: Copyright (C) 2001-2005 Thomas Winischhofer\n");
@@ -6732,11 +6586,7 @@ static void __devexit sisfb_remove(struct pci_dev *pdev)
/* Unregister the framebuffer */
if(ivideo->registered) {
unregister_framebuffer(sis_fb_info);
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,3))
framebuffer_release(sis_fb_info);
-#else
- kfree(sis_fb_info);
-#endif
}
/* OK, our ivideo is gone for good from here. */
@@ -6762,7 +6612,6 @@ static struct pci_driver sisfb_driver = {
SISINITSTATIC int __init sisfb_init(void)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
#ifndef MODULE
char *options = NULL;
@@ -6771,15 +6620,12 @@ SISINITSTATIC int __init sisfb_init(void)
sisfb_setup(options);
#endif
-#endif
return pci_register_driver(&sisfb_driver);
}
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
#ifndef MODULE
module_init(sisfb_init);
#endif
-#endif
/*****************************************************/
/* MODULE */
@@ -6799,9 +6645,6 @@ static int pdc1 = -1;
static int noaccel = -1;
static int noypan = -1;
static int nomax = -1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static int inverse = 0;
-#endif
static int userom = -1;
static int useoem = -1;
static char *tvstandard = NULL;
@@ -6861,10 +6704,6 @@ static int __init sisfb_init_module(void)
else if(nomax == 0)
sisfb_max = 1;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- if(inverse) sisfb_inverse = 1;
-#endif
-
if(mem)
sisfb_parm_mem = mem;
@@ -6913,35 +6752,6 @@ MODULE_DESCRIPTION("SiS 300/540/630/730/315/55x/65x/661/74x/330/76x/34x, XGI V3X
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Thomas Winischhofer <thomas@winischhofer.net>, Others");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM(mem, "i");
-MODULE_PARM(noaccel, "i");
-MODULE_PARM(noypan, "i");
-MODULE_PARM(nomax, "i");
-MODULE_PARM(userom, "i");
-MODULE_PARM(useoem, "i");
-MODULE_PARM(mode, "s");
-MODULE_PARM(vesa, "i");
-MODULE_PARM(rate, "i");
-MODULE_PARM(forcecrt1, "i");
-MODULE_PARM(forcecrt2type, "s");
-MODULE_PARM(scalelcd, "i");
-MODULE_PARM(pdc, "i");
-MODULE_PARM(pdc1, "i");
-MODULE_PARM(specialtiming, "s");
-MODULE_PARM(lvdshl, "i");
-MODULE_PARM(tvstandard, "s");
-MODULE_PARM(tvxposoffset, "i");
-MODULE_PARM(tvyposoffset, "i");
-MODULE_PARM(nocrt2rate, "i");
-MODULE_PARM(inverse, "i");
-#if !defined(__i386__) && !defined(__x86_64__)
-MODULE_PARM(resetcard, "i");
-MODULE_PARM(videoram, "i");
-#endif
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
module_param(mem, int, 0);
module_param(noaccel, int, 0);
module_param(noypan, int, 0);
@@ -6966,18 +6776,7 @@ module_param(nocrt2rate, int, 0);
module_param(resetcard, int, 0);
module_param(videoram, int, 0);
#endif
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM_DESC(mem,
- "\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
- "for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
- "on the amount of video RAM available. If 8MB of video RAM or less is available,\n"
- "the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
- "otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
- "The value is to be specified without 'KB' and must match the MaxXFBMem setting\n"
- "for XFree86 4.x/X.org 6.7 and later.\n");
-#else
MODULE_PARM_DESC(mem,
"\nDetermines the beginning of the video memory heap in KB. This heap is used\n"
"for video RAM management for eg. DRM/DRI. On 300 series, the default depends\n"
@@ -6985,7 +6784,6 @@ MODULE_PARM_DESC(mem,
"the heap starts at 4096KB, if between 8 and 16MB are available at 8192KB,\n"
"otherwise at 12288KB. On 315/330/340 series, the heap size is 32KB by default.\n"
"The value is to be specified without 'KB'.\n");
-#endif
MODULE_PARM_DESC(noaccel,
"\nIf set to anything other than 0, 2D acceleration will be disabled.\n"
@@ -7002,23 +6800,6 @@ MODULE_PARM_DESC(nomax,
"enable the user to positively specify a virtual Y size of the screen using\n"
"fbset. (default: 0)\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM_DESC(mode,
- "\nSelects the desired display mode in the format [X]x[Y]x[Depth], eg.\n"
- "1024x768x16. Other formats supported include XxY-Depth and\n"
- "XxY-Depth@Rate. If the parameter is only one (decimal or hexadecimal)\n"
- "number, it will be interpreted as a VESA mode number. (default: none if\n"
- "sisfb is a module; this leaves the console untouched and the driver will\n"
- "only do the video memory management for eg. DRM/DRI; 800x600x8 if sisfb\n"
- "is in the kernel)\n");
-MODULE_PARM_DESC(vesa,
- "\nSelects the desired display mode by VESA defined mode number, eg. 0x117\n"
- "(default: 0x0000 if sisfb is a module; this leaves the console untouched\n"
- "and the driver will only do the video memory management for eg. DRM/DRI;\n"
- "0x0103 if sisfb is in the kernel)\n");
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
MODULE_PARM_DESC(mode,
"\nSelects the desired default display mode in the format XxYxDepth,\n"
"eg. 1024x768x16. Other formats supported include XxY-Depth and\n"
@@ -7028,7 +6809,6 @@ MODULE_PARM_DESC(mode,
MODULE_PARM_DESC(vesa,
"\nSelects the desired default display mode by VESA defined mode number, eg.\n"
"0x117 (default: 0x0103)\n");
-#endif
MODULE_PARM_DESC(rate,
"\nSelects the desired vertical refresh rate for CRT1 (external VGA) in Hz.\n"
@@ -7094,12 +6874,6 @@ MODULE_PARM_DESC(nocrt2rate,
"\nSetting this to 1 will force the driver to use the default refresh rate for\n"
"CRT2 if CRT2 type is VGA. (default: 0, use same rate as CRT1)\n");
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-MODULE_PARM_DESC(inverse,
- "\nSetting this to anything but 0 should invert the display colors, but this\n"
- "does not seem to work. (default: 0)\n");
-#endif
-
#if !defined(__i386__) && !defined(__x86_64__)
#ifdef CONFIG_FB_SIS_300
MODULE_PARM_DESC(resetcard,
diff --git a/drivers/video/sis/sis_main.h b/drivers/video/sis/sis_main.h
index 70b6df371b8e..88e4f1e41470 100644
--- a/drivers/video/sis/sis_main.h
+++ b/drivers/video/sis/sis_main.h
@@ -67,15 +67,7 @@ static int sisfb_ypan = -1;
static int sisfb_max = -1;
static int sisfb_userom = 1;
static int sisfb_useoem = -1;
-#ifdef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-static int sisfb_mode_idx = -1;
-#else
-static int sisfb_mode_idx = MODE_INDEX_NONE; /* Don't use a mode by default if we are a module */
-#endif
-#else
static int sisfb_mode_idx = -1; /* Use a default mode if we are inside the kernel */
-#endif
static int sisfb_parm_rate = -1;
static int sisfb_crt1off = 0;
static int sisfb_forcecrt1 = -1;
@@ -93,10 +85,6 @@ static int sisfb_tvstd = -1;
static int sisfb_tvxposoffset = 0;
static int sisfb_tvyposoffset = 0;
static int sisfb_nocrt2rate = 0;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static int sisfb_inverse = 0;
-static char sisfb_fontname[40];
-#endif
#if !defined(__i386__) && !defined(__x86_64__)
static int sisfb_resetcard = 0;
static int sisfb_videoram = 0;
@@ -687,54 +675,8 @@ SISINITSTATIC int sisfb_init(void);
static int sisfb_get_fix(struct fb_fix_screeninfo *fix, int con,
struct fb_info *info);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-static int sisfb_get_fix(struct fb_fix_screeninfo *fix,
- int con,
- struct fb_info *info);
-static int sisfb_get_var(struct fb_var_screeninfo *var,
- int con,
- struct fb_info *info);
-static int sisfb_set_var(struct fb_var_screeninfo *var,
- int con,
- struct fb_info *info);
-static void sisfb_crtc_to_var(struct sis_video_info *ivideo,
- struct fb_var_screeninfo *var);
-static int sisfb_get_cmap(struct fb_cmap *cmap,
- int kspc,
- int con,
- struct fb_info *info);
-static int sisfb_set_cmap(struct fb_cmap *cmap,
- int kspc,
- int con,
- struct fb_info *info);
-static int sisfb_update_var(int con,
- struct fb_info *info);
-static int sisfb_switch(int con,
- struct fb_info *info);
-static void sisfb_blank(int blank,
- struct fb_info *info);
-static void sisfb_set_disp(int con,
- struct fb_var_screeninfo *var,
- struct fb_info *info);
-static int sis_getcolreg(unsigned regno, unsigned *red, unsigned *green,
- unsigned *blue, unsigned *transp,
- struct fb_info *fb_info);
-static void sisfb_do_install_cmap(int con,
- struct fb_info *info);
-static int sisfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg, int con,
- struct fb_info *info);
-#endif
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
static int sisfb_ioctl(struct fb_info *info, unsigned int cmd,
unsigned long arg);
-#else
-static int sisfb_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg,
- struct fb_info *info);
-#endif
static int sisfb_set_par(struct fb_info *info);
static int sisfb_blank(int blank,
struct fb_info *info);
@@ -743,7 +685,6 @@ extern void fbcon_sis_fillrect(struct fb_info *info,
extern void fbcon_sis_copyarea(struct fb_info *info,
const struct fb_copyarea *area);
extern int fbcon_sis_sync(struct fb_info *info);
-#endif
/* Internal 2D accelerator functions */
extern int sisfb_initaccel(struct sis_video_info *ivideo);
@@ -811,16 +752,10 @@ extern BOOLEAN SiSDetermineROMLayout661(struct SiS_Private *SiS_Pr);
extern BOOLEAN sisfb_gettotalfrommode(struct SiS_Private *SiS_Pr, unsigned char modeno,
int *htotal, int *vtotal, unsigned char rateindex);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
extern int sisfb_mode_rate_to_dclock(struct SiS_Private *SiS_Pr,
unsigned char modeno, unsigned char rateindex);
extern int sisfb_mode_rate_to_ddata(struct SiS_Private *SiS_Pr, unsigned char modeno,
unsigned char rateindex, struct fb_var_screeninfo *var);
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-extern void SiS_Generic_ConvertCRData(struct SiS_Private *SiS_Pr, unsigned char *crdata, int xres,
- int yres, struct fb_var_screeninfo *var, BOOLEAN writeres);
-#endif
/* Chrontel TV, DDC and DPMS functions */
extern unsigned short SiS_GetCH700x(struct SiS_Private *SiS_Pr, unsigned short reg);
diff --git a/drivers/video/sis/vgatypes.h b/drivers/video/sis/vgatypes.h
index 831b9f42264b..05d08b7889a1 100644
--- a/drivers/video/sis/vgatypes.h
+++ b/drivers/video/sis/vgatypes.h
@@ -73,12 +73,10 @@ typedef unsigned int BOOLEAN;
#ifdef SIS_LINUX_KERNEL
typedef unsigned long SISIOADDRESS;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)
#include <linux/types.h> /* Need __iomem */
#undef SISIOMEMTYPE
#define SISIOMEMTYPE __iomem
#endif
-#endif
#ifdef SIS_XORG_XF86
#if XF86_VERSION_CURRENT < XF86_VERSION_NUMERIC(4,2,0,0,0)
diff --git a/drivers/video/sstfb.c b/drivers/video/sstfb.c
index dad54e73147b..711cb11d6eb3 100644
--- a/drivers/video/sstfb.c
+++ b/drivers/video/sstfb.c
@@ -17,7 +17,10 @@
* (port driver to new frambuffer infrastructure)
* 01/2003 Helge Deller <deller@gmx.de>
* (initial work on fb hardware acceleration for voodoo2)
- *
+ * 08/2006 Alan Cox <alan@redhat.com>
+ * Remove never finished and bogus 24/32bit support
+ * Clean up macro abuse
+ * Minor tidying for format.
*/
/*
@@ -40,6 +43,7 @@
through the fifo. warning: issuing a nop command seems to need pci_fifo
-FIXME: in case of failure in the init sequence, be sure we return to a safe
state.
+- FIXME: Use accelerator for 2D scroll
-FIXME: 4MB boards have banked memory (FbiInit2 bits 1 & 20)
*/
@@ -67,9 +71,6 @@
#undef SST_DEBUG
-/* enable 24/32 bpp functions ? (completely untested!) */
-#undef EN_24_32_BPP
-
/*
Default video mode .
0 800x600@60 took from glide
@@ -377,7 +378,11 @@ static void sstfb_clear_screen(struct fb_info *info)
* sstfb_check_var - Optional function. Validates a var passed in.
* @var: frame buffer variable screen structure
* @info: frame buffer structure that represents a single frame buffer
+ *
+ * Limit to the abilities of a single chip as SLI is not supported
+ * by this driver.
*/
+
static int sstfb_check_var(struct fb_var_screeninfo *var,
struct fb_info *info)
{
@@ -390,7 +395,7 @@ static int sstfb_check_var(struct fb_var_screeninfo *var,
unsigned int freq;
if (sst_calc_pll(PICOS2KHZ(var->pixclock), &freq, &par->pll)) {
- eprintk("Pixclock at %ld KHZ out of range\n",
+ printk(KERN_ERR "sstfb: Pixclock at %ld KHZ out of range\n",
PICOS2KHZ(var->pixclock));
return -EINVAL;
}
@@ -409,27 +414,15 @@ static int sstfb_check_var(struct fb_var_screeninfo *var,
case 0 ... 16 :
var->bits_per_pixel = 16;
break;
-#ifdef EN_24_32_BPP
- case 17 ... 24 :
- var->bits_per_pixel = 24;
- break;
- case 25 ... 32 :
- var->bits_per_pixel = 32;
- break;
-#endif
default :
- eprintk("Unsupported bpp %d\n", var->bits_per_pixel);
+ printk(KERN_ERR "sstfb: Unsupported bpp %d\n", var->bits_per_pixel);
return -EINVAL;
}
/* validity tests */
- if ((var->xres <= 1) || (yDim <= 0 )
- || (var->hsync_len <= 1)
- || (hSyncOff <= 1)
- || (var->left_margin <= 2)
- || (vSyncOn <= 0)
- || (vSyncOff <= 0)
- || (vBackPorch <= 0)) {
+ if (var->xres <= 1 || yDim <= 0 || var->hsync_len <= 1 ||
+ hSyncOff <= 1 || var->left_margin <= 2 || vSyncOn <= 0 ||
+ vSyncOff <= 0 || vBackPorch <= 0) {
return -EINVAL;
}
@@ -437,21 +430,17 @@ static int sstfb_check_var(struct fb_var_screeninfo *var,
/* Voodoo 2 limits */
tiles_in_X = (var->xres + 63 ) / 64 * 2;
- if (((var->xres - 1) >= POW2(11)) || (yDim >= POW2(11))) {
- eprintk("Unsupported resolution %dx%d\n",
+ if (var->xres > POW2(11) || yDim >= POW2(11)) {
+ printk(KERN_ERR "sstfb: Unsupported resolution %dx%d\n",
var->xres, var->yres);
return -EINVAL;
}
- if (((var->hsync_len-1) >= POW2(9))
- || ((hSyncOff-1) >= POW2(11))
- || ((var->left_margin - 2) >= POW2(9))
- || (vSyncOn >= POW2(13))
- || (vSyncOff >= POW2(13))
- || (vBackPorch >= POW2(9))
- || (tiles_in_X >= POW2(6))
- || (tiles_in_X <= 0)) {
- eprintk("Unsupported Timings\n");
+ if (var->hsync_len > POW2(9) || hSyncOff > POW2(11) ||
+ var->left_margin - 2 >= POW2(9) || vSyncOn >= POW2(13) ||
+ vSyncOff >= POW2(13) || vBackPorch >= POW2(9) ||
+ tiles_in_X >= POW2(6) || tiles_in_X <= 0) {
+ printk(KERN_ERR "sstfb: Unsupported timings\n");
return -EINVAL;
}
} else {
@@ -459,24 +448,20 @@ static int sstfb_check_var(struct fb_var_screeninfo *var,
tiles_in_X = (var->xres + 63 ) / 64;
if (var->vmode) {
- eprintk("Interlace/Doublescan not supported %#x\n",
+ printk(KERN_ERR "sstfb: Interlace/doublescan not supported %#x\n",
var->vmode);
return -EINVAL;
}
- if (((var->xres - 1) >= POW2(10)) || (var->yres >= POW2(10))) {
- eprintk("Unsupported resolution %dx%d\n",
+ if (var->xres > POW2(10) || var->yres >= POW2(10)) {
+ printk(KERN_ERR "sstfb: Unsupported resolution %dx%d\n",
var->xres, var->yres);
return -EINVAL;
}
- if (((var->hsync_len - 1) >= POW2(8))
- || ((hSyncOff-1) >= POW2(10))
- || ((var->left_margin - 2) >= POW2(8))
- || (vSyncOn >= POW2(12))
- || (vSyncOff >= POW2(12))
- || (vBackPorch >= POW2(8))
- || (tiles_in_X >= POW2(4))
- || (tiles_in_X <= 0)) {
- eprintk("Unsupported Timings\n");
+ if (var->hsync_len > POW2(8) || hSyncOff - 1 > POW2(10) ||
+ var->left_margin - 2 >= POW2(8) || vSyncOn >= POW2(12) ||
+ vSyncOff >= POW2(12) || vBackPorch >= POW2(8) ||
+ tiles_in_X >= POW2(4) || tiles_in_X <= 0) {
+ printk(KERN_ERR "sstfb: Unsupported timings\n");
return -EINVAL;
}
}
@@ -486,8 +471,8 @@ static int sstfb_check_var(struct fb_var_screeninfo *var,
real_length = tiles_in_X * (IS_VOODOO2(par) ? 32 : 64 )
* ((var->bits_per_pixel == 16) ? 2 : 4);
- if ((real_length * yDim) > info->fix.smem_len) {
- eprintk("Not enough video memory\n");
+ if (real_length * yDim > info->fix.smem_len) {
+ printk(KERN_ERR "sstfb: Not enough video memory\n");
return -ENOMEM;
}
@@ -515,20 +500,6 @@ static int sstfb_check_var(struct fb_var_screeninfo *var,
var->blue.offset = 0;
var->transp.offset = 0;
break;
-#ifdef EN_24_32_BPP
- case 24: /* RGB 888 LfbMode 4 */
- case 32: /* ARGB 8888 LfbMode 5 */
- var->red.length = 8;
- var->green.length = 8;
- var->blue.length = 8;
- var->transp.length = 0;
-
- var->red.offset = 16;
- var->green.offset = 8;
- var->blue.offset = 0;
- var->transp.offset = 0; /* in 24bpp we fake a 32 bpp mode */
- break;
-#endif
default:
return -EINVAL;
}
@@ -653,13 +624,6 @@ static int sstfb_set_par(struct fb_info *info)
case 16:
fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL;
break;
-#ifdef EN_24_32_BPP
- case 24:
- case 32:
- /* sst_set_bits(FBIINIT1, SEL_SOURCE_VCLK_2X_DIV2 | EN_24BPP);*/
- fbiinit1 |= SEL_SOURCE_VCLK_2X_SEL | EN_24BPP;
- break;
-#endif
default:
return -EINVAL;
}
@@ -690,14 +654,6 @@ static int sstfb_set_par(struct fb_info *info)
case 16:
lfbmode = LFB_565;
break;
-#ifdef EN_24_32_BPP
- case 24:
- lfbmode = LFB_888;
- break;
- case 32:
- lfbmode = LFB_8888;
- break;
-#endif
default:
return -EINVAL;
}
@@ -789,8 +745,7 @@ static int sstfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
return -EFAULT;
if (val > info->fix.smem_len)
val = info->fix.smem_len;
- printk("filling %#x \n", val);
- for (p=0 ; p<val; p+=2)
+ for (p = 0 ; p < val; p += 2)
writew(p >> 6, info->screen_base + p);
return 0;
@@ -802,13 +757,10 @@ static int sstfb_ioctl(struct fb_info *info, u_int cmd, u_long arg)
pci_write_config_dword(sst_dev, PCI_INIT_ENABLE,
tmp | PCI_EN_INIT_WR );
fbiinit0 = sst_read (FBIINIT0);
- if (val) {
+ if (val)
sst_write(FBIINIT0, fbiinit0 & ~EN_VGA_PASSTHROUGH);
- iprintk("Disabling VGA pass-through\n");
- } else {
+ else
sst_write(FBIINIT0, fbiinit0 | EN_VGA_PASSTHROUGH);
- iprintk("Enabling VGA pass-through\n");
- }
pci_write_config_dword(sst_dev, PCI_INIT_ENABLE, tmp);
return 0;
@@ -884,9 +836,9 @@ static int __devinit sst_get_memsize(struct fb_info *info, __u32 *memsize)
u8 __iomem *fbbase_virt = info->screen_base;
/* force memsize */
- if ((mem >= 1 ) && (mem <= 4)) {
+ if (mem >= 1 && mem <= 4) {
*memsize = (mem * 0x100000);
- iprintk("supplied memsize: %#x\n", *memsize);
+ printk(KERN_INFO "supplied memsize: %#x\n", *memsize);
return 1;
}
@@ -927,7 +879,7 @@ static int __devinit sst_detect_att(struct fb_info *info)
struct sstfb_par *par = info->par;
int i, mir, dir;
- for (i=0; i<3; i++) {
+ for (i = 0; i < 3; i++) {
sst_dac_write(DACREG_WMA, 0); /* backdoor */
sst_dac_read(DACREG_RMR); /* read 4 times RMR */
sst_dac_read(DACREG_RMR);
@@ -940,7 +892,7 @@ static int __devinit sst_detect_att(struct fb_info *info)
/*the 7th, device ID register */
dir = sst_dac_read(DACREG_RMR);
f_ddprintk("mir: %#x, dir: %#x\n", mir, dir);
- if ((mir == DACREG_MIR_ATT ) && (dir == DACREG_DIR_ATT)) {
+ if (mir == DACREG_MIR_ATT && dir == DACREG_DIR_ATT) {
return 1;
}
}
@@ -1134,12 +1086,6 @@ static void sst_set_vidmod_att_ti(struct fb_info *info, const int bpp)
case 16:
sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_16BPP);
break;
-#ifdef EN_24_32_BPP
- case 24:
- case 32:
- sst_dac_write(DACREG_RMR, (cr0 & 0x0f) | DACREG_CR0_24BPP);
- break;
-#endif
default:
dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
break;
@@ -1154,12 +1100,6 @@ static void sst_set_vidmod_ics(struct fb_info *info, const int bpp)
case 16:
sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_16BPP);
break;
-#ifdef EN_24_32_BPP
- case 24:
- case 32:
- sst_dac_write(DACREG_ICS_CMD, DACREG_ICS_CMD_24BPP);
- break;
-#endif
default:
dprintk("%s: bad depth '%u'\n", __FUNCTION__, bpp);
break;
@@ -1250,7 +1190,7 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
PCI_EN_INIT_WR | PCI_REMAP_DAC );
/* detect dac type */
if (!sst_detect_dactype(info, par)) {
- eprintk("Unknown dac type\n");
+ printk(KERN_ERR "sstfb: unknown dac type.\n");
//FIXME watch it: we are not in a safe state, bad bad bad.
return 0;
}
@@ -1258,10 +1198,10 @@ static int __devinit sst_init(struct fb_info *info, struct sstfb_par *par)
/* set graphic clock */
par->gfx_clock = spec->default_gfx_clock;
if ((gfxclk >10 ) && (gfxclk < spec->max_gfxclk)) {
- iprintk("Using supplied graphic freq : %dMHz\n", gfxclk);
+ printk(KERN_INFO "sstfb: Using supplied graphic freq : %dMHz\n", gfxclk);
par->gfx_clock = gfxclk *1000;
} else if (gfxclk) {
- wprintk ("%dMhz is way out of spec! Using default\n", gfxclk);
+ printk(KERN_WARNING "sstfb: %dMhz is way out of spec! Using default\n", gfxclk);
}
sst_calc_pll(par->gfx_clock, &Fout, &gfx_timings);
@@ -1396,7 +1336,7 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
/* Enable device in PCI config. */
if ((err=pci_enable_device(pdev))) {
- eprintk("cannot enable device\n");
+ printk(KERN_ERR "cannot enable device\n");
return err;
}
@@ -1422,39 +1362,39 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
fix->smem_start = fix->mmio_start + 0x400000;
if (!request_mem_region(fix->mmio_start, fix->mmio_len, "sstfb MMIO")) {
- eprintk("cannot reserve mmio memory\n");
+ printk(KERN_ERR "sstfb: cannot reserve mmio memory\n");
goto fail_mmio_mem;
}
if (!request_mem_region(fix->smem_start, 0x400000,"sstfb FB")) {
- eprintk("cannot reserve fb memory\n");
+ printk(KERN_ERR "sstfb: cannot reserve fb memory\n");
goto fail_fb_mem;
}
par->mmio_vbase = ioremap_nocache(fix->mmio_start,
fix->mmio_len);
if (!par->mmio_vbase) {
- eprintk("cannot remap register area %#lx\n",
+ printk(KERN_ERR "sstfb: cannot remap register area %#lx\n",
fix->mmio_start);
goto fail_mmio_remap;
}
info->screen_base = ioremap_nocache(fix->smem_start, 0x400000);
if (!info->screen_base) {
- eprintk("cannot remap framebuffer %#lx\n",
+ printk(KERN_ERR "sstfb: cannot remap framebuffer %#lx\n",
fix->smem_start);
goto fail_fb_remap;
}
if (!sst_init(info, par)) {
- eprintk("Init failed\n");
+ printk(KERN_ERR "sstfb: Init failed\n");
goto fail;
}
sst_get_memsize(info, &fix->smem_len);
strlcpy(fix->id, spec->name, sizeof(fix->id));
- iprintk("%s (revision %d) with %s dac\n",
+ printk(KERN_INFO "%s (revision %d) with %s dac\n",
fix->id, par->revision, par->dac_sw.name);
- iprintk("framebuffer at %#lx, mapped to 0x%p, size %dMB\n",
+ printk(KERN_INFO "framebuffer at %#lx, mapped to 0x%p, size %dMB\n",
fix->smem_start, info->screen_base,
fix->smem_len >> 20);
@@ -1471,24 +1411,25 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
fix->accel = FB_ACCEL_NONE; /* FIXME */
/*
* According to the specs, the linelength must be of 1024 *pixels*
- * and the 24bpp mode is in fact a 32 bpp mode.
+ * and the 24bpp mode is in fact a 32 bpp mode (and both are in
+ * fact dithered to 16bit).
*/
fix->line_length = 2048; /* default value, for 24 or 32bit: 4096 */
if ( mode_option &&
fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 16)) {
- eprintk("can't set supplied video mode. Using default\n");
+ printk(KERN_ERR "sstfb: can't set supplied video mode. Using default\n");
info->var = sstfb_default;
} else
info->var = sstfb_default;
if (sstfb_check_var(&info->var, info)) {
- eprintk("invalid default video mode.\n");
+ printk(KERN_ERR "sstfb: invalid default video mode.\n");
goto fail;
}
if (sstfb_set_par(info)) {
- eprintk("can't set default video mode.\n");
+ printk(KERN_ERR "sstfb: can't set default video mode.\n");
goto fail;
}
@@ -1497,7 +1438,7 @@ static int __devinit sstfb_probe(struct pci_dev *pdev,
/* register fb */
info->device = &pdev->dev;
if (register_framebuffer(info) < 0) {
- eprintk("can't register framebuffer.\n");
+ printk(KERN_ERR "sstfb: can't register framebuffer.\n");
goto fail;
}
@@ -1711,4 +1652,3 @@ module_param(gfxclk, int, 0);
MODULE_PARM_DESC(gfxclk, "Force graphic chip frequency in MHz. DANGEROUS. (default=auto)");
module_param(slowpci, bool, 0);
MODULE_PARM_DESC(slowpci, "Uses slow PCI settings (0 or 1) (default=0)");
-
diff --git a/drivers/video/valkyriefb.c b/drivers/video/valkyriefb.c
index 47f27924a7d7..06fc19a61192 100644
--- a/drivers/video/valkyriefb.c
+++ b/drivers/video/valkyriefb.c
@@ -284,7 +284,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
printk(KERN_INFO "Monitor sense value = 0x%x\n", p->sense);
/* Try to pick a video mode out of NVRAM if we have one. */
-#ifndef CONFIG_MAC
+#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
if (default_vmode == VMODE_NVRAM) {
default_vmode = nvram_read_byte(NV_VMODE);
if (default_vmode <= 0
@@ -297,7 +297,7 @@ static void __init valkyrie_choose_mode(struct fb_info_valkyrie *p)
default_vmode = mac_map_monitor_sense(p->sense);
if (!valkyrie_reg_init[default_vmode - 1])
default_vmode = VMODE_640_480_67;
-#ifndef CONFIG_MAC
+#if !defined(CONFIG_MAC) && defined(CONFIG_NVRAM)
if (default_cmode == CMODE_NVRAM)
default_cmode = nvram_read_byte(NV_CMODE);
#endif
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index 8b3d0f0c7bd5..c287a9ae4fdd 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -2,7 +2,6 @@ menu "Dallas's 1-wire bus"
config W1
tristate "Dallas's 1-wire support"
- depends on CONNECTOR
---help---
Dallas' 1-wire bus is useful to connect slow 1-pin devices
such as iButtons and thermal sensors.
@@ -21,7 +20,7 @@ config W1_CON
There are three types of messages between w1 core and userspace:
1. Events. They are generated each time new master or slave device found
either due to automatic or requested search.
- 2. Userspace commands. Includes read/write and search/alarm search comamnds.
+ 2. Userspace commands. Includes read/write and search/alarm search commands.
3. Replies to userspace commands.
source drivers/w1/masters/Kconfig
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c
index 22f7ccd58d38..0f628041e3f7 100644
--- a/fs/9p/v9fs.c
+++ b/fs/9p/v9fs.c
@@ -460,8 +460,10 @@ static int __init init_v9fs(void)
ret = v9fs_mux_global_init();
if (!ret)
- ret = register_filesystem(&v9fs_fs_type);
-
+ return ret;
+ ret = register_filesystem(&v9fs_fs_type);
+ if (!ret)
+ v9fs_mux_global_exit();
return ret;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index eae50c9d6dc4..5241c600ce28 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -204,7 +204,6 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = sb->s_blocksize;
inode->i_blocks = 0;
inode->i_rdev = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -234,7 +233,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode)
inode->i_op = &v9fs_symlink_inode_operations;
break;
case S_IFDIR:
- inode->i_nlink++;
+ inc_nlink(inode);
if(v9ses->extended)
inode->i_op = &v9fs_dir_inode_operations_ext;
else
@@ -950,9 +949,8 @@ v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
inode->i_size = stat->length;
- inode->i_blksize = sb->s_blocksize;
inode->i_blocks =
- (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits;
+ (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
}
/**
diff --git a/fs/Kconfig b/fs/Kconfig
index a27002668bd3..fee318e6f4bb 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -4,6 +4,8 @@
menu "File systems"
+if BLOCK
+
config EXT2_FS
tristate "Second extended fs support"
help
@@ -72,11 +74,11 @@ config EXT3_FS
tristate "Ext3 journalling file system support"
select JBD
help
- This is the journaling version of the Second extended file system
+ This is the journalling version of the Second extended file system
(often called ext3), the de facto standard Linux file system
(method to organize files on a storage device) for hard disks.
- The journaling code included in this driver means you do not have
+ The journalling code included in this driver means you do not have
to run e2fsck (file system checker) on your file systems after a
crash. The journal keeps track of any changes that were being made
at the time the system crashed, and can ensure that your file system
@@ -138,10 +140,77 @@ config EXT3_FS_SECURITY
If you are not using a security module that requires using
extended attributes for file security labels, say N.
+config EXT4DEV_FS
+ tristate "Ext4dev/ext4 extended fs support development (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ select JBD2
+ help
+ Ext4dev is a predecessor filesystem of the next generation
+ extended fs ext4, based on ext3 filesystem code. It will be
+ renamed ext4 fs later, once ext4dev is mature and stabilized.
+
+ Unlike the change from ext2 filesystem to ext3 filesystem,
+ the on-disk format of ext4dev is not the same as ext3 any more:
+ it is based on extent maps and it supports 48-bit physical block
+ numbers. These combined on-disk format changes will allow
+ ext4dev/ext4 to handle more than 16 TB filesystem volumes --
+ a hard limit that ext3 cannot overcome without changing the
+ on-disk format.
+
+ Other than extent maps and 48-bit block numbers, ext4dev also is
+ likely to have other new features such as persistent preallocation,
+ high resolution time stamps, and larger file support etc. These
+ features will be added to ext4dev gradually.
+
+ To compile this file system support as a module, choose M here. The
+ module will be called ext4dev. Be aware, however, that the filesystem
+ of your root partition (the one containing the directory /) cannot
+ be compiled as a module, and so this could be dangerous.
+
+ If unsure, say N.
+
+config EXT4DEV_FS_XATTR
+ bool "Ext4dev extended attributes"
+ depends on EXT4DEV_FS
+ default y
+ help
+ Extended attributes are name:value pairs associated with inodes by
+ the kernel or by users (see the attr(5) manual page, or visit
+ <http://acl.bestbits.at/> for details).
+
+ If unsure, say N.
+
+ You need this for POSIX ACL support on ext4dev/ext4.
+
+config EXT4DEV_FS_POSIX_ACL
+ bool "Ext4dev POSIX Access Control Lists"
+ depends on EXT4DEV_FS_XATTR
+ select FS_POSIX_ACL
+ help
+ POSIX Access Control Lists (ACLs) support permissions for users and
+ groups beyond the owner/group/world scheme.
+
+ To learn more about Access Control Lists, visit the POSIX ACLs for
+ Linux website <http://acl.bestbits.at/>.
+
+ If you don't know what Access Control Lists are, say N
+
+config EXT4DEV_FS_SECURITY
+ bool "Ext4dev Security Labels"
+ depends on EXT4DEV_FS_XATTR
+ help
+ Security labels support alternative access control models
+ implemented by security modules like SELinux. This option
+ enables an extended attribute handler for file security
+ labels in the ext4dev/ext4 filesystem.
+
+ If you are not using a security module that requires using
+ extended attributes for file security labels, say N.
+
config JBD
tristate
help
- This is a generic journaling layer for block devices. It is
+ This is a generic journalling layer for block devices. It is
currently used by the ext3 and OCFS2 file systems, but it could
also be used to add journal support to other file systems or block
devices such as RAID or LVM.
@@ -170,18 +239,50 @@ config JBD_DEBUG
generated. To turn debugging off again, do
"echo 0 > /proc/sys/fs/jbd-debug".
+config JBD2
+ tristate
+ help
+ This is a generic journaling layer for block devices that support
+ both 32-bit and 64-bit block numbers. It is currently used by
+ the ext4dev/ext4 filesystem, but it could also be used to add
+ journal support to other file systems or block devices such
+ as RAID or LVM.
+
+ If you are using ext4dev/ext4, you need to say Y here. If you are not
+ using ext4dev/ext4 then you will probably want to say N.
+
+ To compile this device as a module, choose M here. The module will be
+ called jbd2. If you are compiling ext4dev/ext4 into the kernel,
+ you cannot compile this code as a module.
+
+config JBD2_DEBUG
+ bool "JBD2 (ext4dev/ext4) debugging support"
+ depends on JBD2
+ help
+ If you are using the ext4dev/ext4 journaled file system (or
+ potentially any other filesystem/device using JBD2), this option
+ allows you to enable debugging output while the system is running,
+ in order to help track down any problems you are having.
+ By default, the debugging output will be turned off.
+
+ If you select Y here, then you will be able to turn on debugging
+ with "echo N > /proc/sys/fs/jbd2-debug", where N is a number between
+ 1 and 5. The higher the number, the more debugging output is
+ generated. To turn debugging off again, do
+ "echo 0 > /proc/sys/fs/jbd2-debug".
+
config FS_MBCACHE
-# Meta block cache for Extended Attributes (ext2/ext3)
+# Meta block cache for Extended Attributes (ext2/ext3/ext4)
tristate
- depends on EXT2_FS_XATTR || EXT3_FS_XATTR
- default y if EXT2_FS=y || EXT3_FS=y
- default m if EXT2_FS=m || EXT3_FS=m
+ depends on EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4DEV_FS_XATTR
+ default y if EXT2_FS=y || EXT3_FS=y || EXT4DEV_FS=y
+ default m if EXT2_FS=m || EXT3_FS=m || EXT4DEV_FS=m
config REISERFS_FS
tristate "Reiserfs support"
help
Stores not just filenames but the files themselves in a balanced
- tree. Uses journaling.
+ tree. Uses journalling.
Balanced trees are more efficient than traditional file system
architectural foundations.
@@ -323,6 +424,7 @@ config FS_POSIX_ACL
default n
source "fs/xfs/Kconfig"
+source "fs/gfs2/Kconfig"
config OCFS2_FS
tristate "OCFS2 file system support"
@@ -399,6 +501,8 @@ config ROMFS_FS
If you don't know whether you need it, then you don't need it:
answer N.
+endif
+
config INOTIFY
bool "Inotify file change notification support"
default y
@@ -530,6 +634,11 @@ config FUSE_FS
If you want to develop a userspace FS, or if you want to use
a filesystem based on FUSE, answer Y or M.
+config GENERIC_ACL
+ bool
+ select FS_POSIX_ACL
+
+if BLOCK
menu "CD-ROM/DVD Filesystems"
config ISO9660_FS
@@ -597,7 +706,9 @@ config UDF_NLS
depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y)
endmenu
+endif
+if BLOCK
menu "DOS/FAT/NT Filesystems"
config FAT_FS
@@ -782,6 +893,7 @@ config NTFS_RW
It is perfectly safe to say N here.
endmenu
+endif
menu "Pseudo filesystems"
@@ -826,6 +938,25 @@ config PROC_VMCORE
help
Exports the dump image of crashed kernel in ELF format.
+config PROC_SYSCTL
+ bool "Sysctl support (/proc/sys)" if EMBEDDED
+ depends on PROC_FS
+ select SYSCTL
+ default y
+ ---help---
+ The sysctl interface provides a means of dynamically changing
+ certain kernel parameters and variables on the fly without requiring
+ a recompile of the kernel or reboot of the system. The primary
+ interface is through /proc/sys. If you say Y here a tree of
+ modifiable sysctl entries will be generated beneath the
+ /proc/sys directory. They are explained in the files
+ in <file:Documentation/sysctl/>. Note that enabling this
+ option will enlarge the kernel by at least 8 KB.
+
+ As it is generally a good thing, you should say Y here unless
+ building a kernel for install/rescue disks or your system is very
+ limited in memory.
+
config SYSFS
bool "sysfs file system support" if EMBEDDED
default y
@@ -862,6 +993,19 @@ config TMPFS
See <file:Documentation/filesystems/tmpfs.txt> for details.
+config TMPFS_POSIX_ACL
+ bool "Tmpfs POSIX Access Control Lists"
+ depends on TMPFS
+ select GENERIC_ACL
+ help
+ POSIX Access Control Lists (ACLs) support permissions for users and
+ groups beyond the owner/group/world scheme.
+
+ To learn more about Access Control Lists, visit the POSIX ACLs for
+ Linux website <http://acl.bestbits.at/>.
+
+ If you don't know what Access Control Lists are, say N.
+
config HUGETLBFS
bool "HugeTLB file system support"
depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
@@ -907,7 +1051,7 @@ menu "Miscellaneous filesystems"
config ADFS_FS
tristate "ADFS file system support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on BLOCK && EXPERIMENTAL
help
The Acorn Disc Filing System is the standard file system of the
RiscOS operating system which runs on Acorn's ARM-based Risc PC
@@ -935,7 +1079,7 @@ config ADFS_FS_RW
config AFFS_FS
tristate "Amiga FFS file system support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on BLOCK && EXPERIMENTAL
help
The Fast File System (FFS) is the common file system used on hard
disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y
@@ -955,9 +1099,21 @@ config AFFS_FS
To compile this file system support as a module, choose M here: the
module will be called affs. If unsure, say N.
+config ECRYPT_FS
+ tristate "eCrypt filesystem layer support (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && KEYS && CRYPTO
+ help
+ Encrypted filesystem that operates on the VFS layer. See
+ <file:Documentation/ecryptfs.txt> to learn more about
+ eCryptfs. Userspace components are required and can be
+ obtained from <http://ecryptfs.sf.net>.
+
+ To compile this file system support as a module, choose M here: the
+ module will be called ecryptfs.
+
config HFS_FS
tristate "Apple Macintosh file system support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on BLOCK && EXPERIMENTAL
select NLS
help
If you say Y here, you will be able to mount Macintosh-formatted
@@ -970,6 +1126,7 @@ config HFS_FS
config HFSPLUS_FS
tristate "Apple Extended HFS file system support"
+ depends on BLOCK
select NLS
select NLS_UTF8
help
@@ -983,7 +1140,7 @@ config HFSPLUS_FS
config BEFS_FS
tristate "BeOS file system (BeFS) support (read only) (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on BLOCK && EXPERIMENTAL
select NLS
help
The BeOS File System (BeFS) is the native file system of Be, Inc's
@@ -991,7 +1148,7 @@ config BEFS_FS
on files and directories, and database-like indeces on selected
attributes. (Also note that this driver doesn't make those features
available at this time). It is a 64 bit filesystem, so it supports
- extremly large volumes and files.
+ extremely large volumes and files.
If you use this filesystem, you should also say Y to at least one
of the NLS (native language support) options below.
@@ -1010,7 +1167,7 @@ config BEFS_DEBUG
config BFS_FS
tristate "BFS file system support (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on BLOCK && EXPERIMENTAL
help
Boot File System (BFS) is a file system used under SCO UnixWare to
allow the bootloader access to the kernel image and other important
@@ -1032,7 +1189,7 @@ config BFS_FS
config EFS_FS
tristate "EFS file system support (read only) (EXPERIMENTAL)"
- depends on EXPERIMENTAL
+ depends on BLOCK && EXPERIMENTAL
help
EFS is an older file system used for non-ISO9660 CD-ROMs and hard
disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer
@@ -1047,9 +1204,9 @@ config EFS_FS
config JFFS_FS
tristate "Journalling Flash File System (JFFS) support"
- depends on MTD
+ depends on MTD && BLOCK
help
- JFFS is the Journaling Flash File System developed by Axis
+ JFFS is the Journalling Flash File System developed by Axis
Communications in Sweden, aimed at providing a crash/powerdown-safe
file system for disk-less embedded devices. Further information is
available at (<http://developer.axis.com/software/jffs/>).
@@ -1219,7 +1376,7 @@ config JFFS2_CMODE_NONE
config JFFS2_CMODE_PRIORITY
bool "priority"
help
- Tries the compressors in a predefinied order and chooses the first
+ Tries the compressors in a predefined order and chooses the first
successful one.
config JFFS2_CMODE_SIZE
@@ -1232,6 +1389,7 @@ endchoice
config CRAMFS
tristate "Compressed ROM file system support (cramfs)"
+ depends on BLOCK
select ZLIB_INFLATE
help
Saying Y here includes support for CramFs (Compressed ROM File
@@ -1251,6 +1409,7 @@ config CRAMFS
config VXFS_FS
tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
+ depends on BLOCK
help
FreeVxFS is a file system driver that support the VERITAS VxFS(TM)
file system format. VERITAS VxFS(TM) is the standard file system
@@ -1268,6 +1427,7 @@ config VXFS_FS
config HPFS_FS
tristate "OS/2 HPFS file system support"
+ depends on BLOCK
help
OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS
is the file system used for organizing files on OS/2 hard disk
@@ -1284,6 +1444,7 @@ config HPFS_FS
config QNX4FS_FS
tristate "QNX4 file system support (read only)"
+ depends on BLOCK
help
This is the file system used by the real-time operating systems
QNX 4 and QNX 6 (the latter is also called QNX RTP).
@@ -1311,6 +1472,7 @@ config QNX4FS_RW
config SYSV_FS
tristate "System V/Xenix/V7/Coherent file system support"
+ depends on BLOCK
help
SCO, Xenix and Coherent are commercial Unix systems for Intel
machines, and Version 7 was used on the DEC PDP-11. Saying Y
@@ -1319,7 +1481,7 @@ config SYSV_FS
If you have floppies or hard disk partitions like that, it is likely
that they contain binaries from those other Unix systems; in order
- to run these binaries, you will want to install linux-abi which is a
+ to run these binaries, you will want to install linux-abi which is
a set of kernel modules that lets you run SCO, Xenix, Wyse,
UnixWare, Dell Unix and System V programs under Linux. It is
available via FTP (user: ftp) from
@@ -1349,6 +1511,7 @@ config SYSV_FS
config UFS_FS
tristate "UFS file system support (read only)"
+ depends on BLOCK
help
BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
OpenBSD and NeXTstep) use a file system called UFS. Some System V
@@ -1827,7 +1990,7 @@ config CIFS_EXPERIMENTAL
config CIFS_UPCALL
bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)"
depends on CIFS_EXPERIMENTAL
- select CONNECTOR
+ depends on CONNECTOR
help
Enables an upcall mechanism for CIFS which will be used to contact
userspace helper utilities to provide SPNEGO packaged Kerberos
@@ -1903,7 +2066,7 @@ config AFS_FS
If you say Y here, you will get an experimental Andrew File System
driver. It currently only supports unsecured read-only AFS access.
- See <file:Documentation/filesystems/afs.txt> for more intormation.
+ See <file:Documentation/filesystems/afs.txt> for more information.
If unsure, say N.
@@ -1923,13 +2086,16 @@ config 9P_FS
endmenu
+if BLOCK
menu "Partition Types"
source "fs/partitions/Kconfig"
endmenu
+endif
source "fs/nls/Kconfig"
+source "fs/dlm/Kconfig"
endmenu
diff --git a/fs/Makefile b/fs/Makefile
index 89135428a539..9a5ce9323bfd 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -5,12 +5,18 @@
# Rewritten to use lists instead of if-statements.
#
-obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \
- block_dev.o char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
+obj-y := open.o read_write.o file_table.o super.o \
+ char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
- seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
- ioprio.o pnode.o drop_caches.o splice.o sync.o
+ seq_file.o xattr.o libfs.o fs-writeback.o \
+ pnode.o drop_caches.o splice.o sync.o utimes.o
+
+ifeq ($(CONFIG_BLOCK),y)
+obj-y += buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
+else
+obj-y += no-block.o
+endif
obj-$(CONFIG_INOTIFY) += inotify.o
obj-$(CONFIG_INOTIFY_USER) += inotify_user.o
@@ -35,6 +41,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o
obj-$(CONFIG_FS_MBCACHE) += mbcache.o
obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
obj-$(CONFIG_NFS_COMMON) += nfs_common/
+obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
obj-$(CONFIG_QUOTA) += dquot.o
obj-$(CONFIG_QFMT_V1) += quota_v1.o
@@ -50,11 +57,14 @@ obj-$(CONFIG_CONFIGFS_FS) += configfs/
obj-y += devpts/
obj-$(CONFIG_PROFILING) += dcookies.o
+obj-$(CONFIG_DLM) += dlm/
# Do not add any filesystems before this line
obj-$(CONFIG_REISERFS_FS) += reiserfs/
obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3
+obj-$(CONFIG_EXT4DEV_FS) += ext4/ # Before ext2 so root fs can be ext4dev
obj-$(CONFIG_JBD) += jbd/
+obj-$(CONFIG_JBD2) += jbd2/
obj-$(CONFIG_EXT2_FS) += ext2/
obj-$(CONFIG_CRAMFS) += cramfs/
obj-$(CONFIG_RAMFS) += ramfs/
@@ -68,6 +78,7 @@ obj-$(CONFIG_BFS_FS) += bfs/
obj-$(CONFIG_ISO9660_FS) += isofs/
obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+
obj-$(CONFIG_HFS_FS) += hfs/
+obj-$(CONFIG_ECRYPT_FS) += ecryptfs/
obj-$(CONFIG_VXFS_FS) += freevxfs/
obj-$(CONFIG_NFS_FS) += nfs/
obj-$(CONFIG_EXPORTFS) += exportfs/
@@ -102,3 +113,4 @@ obj-$(CONFIG_HOSTFS) += hostfs/
obj-$(CONFIG_HPPFS) += hppfs/
obj-$(CONFIG_DEBUG_FS) += debugfs/
obj-$(CONFIG_OCFS2_FS) += ocfs2/
+obj-$(CONFIG_GFS2_FS) += gfs2/
diff --git a/fs/adfs/file.c b/fs/adfs/file.c
index 1014b9f2117b..6101ea679cb1 100644
--- a/fs/adfs/file.c
+++ b/fs/adfs/file.c
@@ -27,10 +27,12 @@
const struct file_operations adfs_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
.mmap = generic_file_mmap,
.fsync = file_fsync,
- .write = generic_file_write,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.sendfile = generic_file_sendfile,
};
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c
index 534f3eecc985..7e7a04be1278 100644
--- a/fs/adfs/inode.c
+++ b/fs/adfs/inode.c
@@ -269,7 +269,6 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
inode->i_ino = obj->file_id;
inode->i_size = obj->size;
inode->i_nlink = 2;
- inode->i_blksize = PAGE_SIZE;
inode->i_blocks = (inode->i_size + sb->s_blocksize - 1) >>
sb->s_blocksize_bits;
diff --git a/fs/adfs/super.c b/fs/adfs/super.c
index 82011019494c..9ade139086fc 100644
--- a/fs/adfs/super.c
+++ b/fs/adfs/super.c
@@ -251,8 +251,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(adfs_inode_cachep))
- printk(KERN_INFO "adfs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(adfs_inode_cachep);
}
static struct super_operations adfs_sops = {
@@ -339,11 +338,10 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_flags |= MS_NODIRATIME;
- asb = kmalloc(sizeof(*asb), GFP_KERNEL);
+ asb = kzalloc(sizeof(*asb), GFP_KERNEL);
if (!asb)
return -ENOMEM;
sb->s_fs_info = asb;
- memset(asb, 0, sizeof(*asb));
/* set default options */
asb->s_uid = 0;
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 3de8590e4f6a..05b5e22de759 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -27,8 +27,10 @@ static int affs_file_release(struct inode *inode, struct file *filp);
const struct file_operations affs_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.open = affs_file_open,
.release = affs_file_release,
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 17352011ab67..5ea72c3a16c3 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -109,8 +109,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(affs_inode_cachep))
- printk(KERN_INFO "affs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(affs_inode_cachep);
}
static struct super_operations affs_sops = {
@@ -280,11 +279,10 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_op = &affs_sops;
sb->s_flags |= MS_NODIRATIME;
- sbi = kmalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct affs_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_fs_info = sbi;
- memset(sbi, 0, sizeof(*sbi));
init_MUTEX(&sbi->s_bmlock);
if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block,
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 2fc99877cb0d..a6ec75c56fcf 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -30,7 +30,7 @@ static int afs_dir_readdir(struct file *file, void *dirent, filldir_t filldir);
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
static int afs_d_delete(struct dentry *dentry);
static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
- loff_t fpos, ino_t ino, unsigned dtype);
+ loff_t fpos, u64 ino, unsigned dtype);
const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
@@ -211,8 +211,8 @@ static int afs_dir_open(struct inode *inode, struct file *file)
{
_enter("{%lu}", inode->i_ino);
- BUG_ON(sizeof(union afs_dir_block) != 2048);
- BUG_ON(sizeof(union afs_dirent) != 32);
+ BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
+ BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
if (AFS_FS_I(inode)->flags & AFS_VNODE_DELETED)
return -ENOENT;
@@ -409,7 +409,7 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
* uniquifier through dtype
*/
static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
- loff_t fpos, ino_t ino, unsigned dtype)
+ loff_t fpos, u64 ino, unsigned dtype)
{
struct afs_dir_lookup_cookie *cookie = _cookie;
@@ -446,8 +446,8 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
_enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name);
/* insanity checks first */
- BUG_ON(sizeof(union afs_dir_block) != 2048);
- BUG_ON(sizeof(union afs_dirent) != 32);
+ BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);
+ BUILD_BUG_ON(sizeof(union afs_dirent) != 32);
if (dentry->d_name.len > 255) {
_leave(" = -ENAMETOOLONG");
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 67d6634101fd..2e8c42639eaa 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -16,7 +16,6 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
-#include <linux/buffer_head.h>
#include "volume.h"
#include "vnode.h"
#include <rxrpc/call.h>
@@ -37,7 +36,6 @@ struct inode_operations afs_file_inode_operations = {
const struct address_space_operations afs_fs_aops = {
.readpage = afs_file_readpage,
- .sync_page = block_sync_page,
.set_page_dirty = __set_page_dirty_nobuffers,
.releasepage = afs_file_releasepage,
.invalidatepage = afs_file_invalidatepage,
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 4ebb30a50ed5..6f37754906c2 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -72,7 +72,6 @@ static int afs_inode_map_status(struct afs_vnode *vnode)
inode->i_ctime.tv_sec = vnode->status.mtime_server;
inode->i_ctime.tv_nsec = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_version = vnode->fid.unique;
inode->i_mapping->a_ops = &afs_fs_aops;
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 101d21b6c037..86463ec9ccb4 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -775,6 +775,7 @@ static int afs_proc_cell_servers_release(struct inode *inode,
* first item
*/
static void *afs_proc_cell_servers_start(struct seq_file *m, loff_t *_pos)
+ __acquires(m->private->sv_lock)
{
struct list_head *_p;
struct afs_cell *cell = m->private;
@@ -823,6 +824,7 @@ static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
* clean up after reading from the cells list
*/
static void afs_proc_cell_servers_stop(struct seq_file *p, void *v)
+ __releases(p->private->sv_lock)
{
struct afs_cell *cell = p->private;
diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c
index 331f730a1fb3..782ee7c600ca 100644
--- a/fs/afs/vlocation.c
+++ b/fs/afs/vlocation.c
@@ -281,11 +281,10 @@ int afs_vlocation_lookup(struct afs_cell *cell,
spin_unlock(&cell->vl_gylock);
/* not in the cell's in-memory lists - create a new record */
- vlocation = kmalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
+ vlocation = kzalloc(sizeof(struct afs_vlocation), GFP_KERNEL);
if (!vlocation)
return -ENOMEM;
- memset(vlocation, 0, sizeof(struct afs_vlocation));
atomic_set(&vlocation->usage, 1);
INIT_LIST_HEAD(&vlocation->link);
rwlock_init(&vlocation->lock);
diff --git a/fs/afs/volume.c b/fs/afs/volume.c
index 0ff4b86476e3..768c6dbd323a 100644
--- a/fs/afs/volume.c
+++ b/fs/afs/volume.c
@@ -186,11 +186,10 @@ int afs_volume_lookup(const char *name, struct afs_cell *cell, int rwpath,
_debug("creating new volume record");
ret = -ENOMEM;
- volume = kmalloc(sizeof(struct afs_volume), GFP_KERNEL);
+ volume = kzalloc(sizeof(struct afs_volume), GFP_KERNEL);
if (!volume)
goto error_up;
- memset(volume, 0, sizeof(struct afs_volume));
atomic_set(&volume->usage, 1);
volume->type = type;
volume->type_force = force;
diff --git a/fs/aio.c b/fs/aio.c
index 950630187acc..94766599db00 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -15,6 +15,7 @@
#include <linux/aio_abi.h>
#include <linux/module.h>
#include <linux/syscalls.h>
+#include <linux/uio.h>
#define DEBUG 0
@@ -414,6 +415,7 @@ static struct kiocb fastcall *__aio_get_req(struct kioctx *ctx)
req->ki_retry = NULL;
req->ki_dtor = NULL;
req->private = NULL;
+ req->ki_iovec = NULL;
INIT_LIST_HEAD(&req->ki_run_list);
/* Check if the completion queue has enough free space to
@@ -459,6 +461,8 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
if (req->ki_dtor)
req->ki_dtor(req);
+ if (req->ki_iovec != &req->ki_inline_vec)
+ kfree(req->ki_iovec);
kmem_cache_free(kiocb_cachep, req);
ctx->reqs_active--;
@@ -671,7 +675,7 @@ static ssize_t aio_run_iocb(struct kiocb *iocb)
}
if (!(iocb->ki_retried & 0xff)) {
- pr_debug("%ld retry: %d of %d\n", iocb->ki_retried,
+ pr_debug("%ld retry: %zd of %zd\n", iocb->ki_retried,
iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
}
@@ -1004,7 +1008,7 @@ int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
pr_debug("added to ring %p at [%lu]\n", iocb, tail);
- pr_debug("%ld retries: %d of %d\n", iocb->ki_retried,
+ pr_debug("%ld retries: %zd of %zd\n", iocb->ki_retried,
iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
put_rq:
/* everything turned out well, dispose of the aiocb. */
@@ -1300,63 +1304,63 @@ asmlinkage long sys_io_destroy(aio_context_t ctx)
return -EINVAL;
}
-/*
- * aio_p{read,write} are the default ki_retry methods for
- * IO_CMD_P{READ,WRITE}. They maintains kiocb retry state around potentially
- * multiple calls to f_op->aio_read(). They loop around partial progress
- * instead of returning -EIOCBRETRY because they don't have the means to call
- * kick_iocb().
- */
-static ssize_t aio_pread(struct kiocb *iocb)
+static void aio_advance_iovec(struct kiocb *iocb, ssize_t ret)
{
- struct file *file = iocb->ki_filp;
- struct address_space *mapping = file->f_mapping;
- struct inode *inode = mapping->host;
- ssize_t ret = 0;
-
- do {
- ret = file->f_op->aio_read(iocb, iocb->ki_buf,
- iocb->ki_left, iocb->ki_pos);
- /*
- * Can't just depend on iocb->ki_left to determine
- * whether we are done. This may have been a short read.
- */
- if (ret > 0) {
- iocb->ki_buf += ret;
- iocb->ki_left -= ret;
+ struct iovec *iov = &iocb->ki_iovec[iocb->ki_cur_seg];
+
+ BUG_ON(ret <= 0);
+
+ while (iocb->ki_cur_seg < iocb->ki_nr_segs && ret > 0) {
+ ssize_t this = min((ssize_t)iov->iov_len, ret);
+ iov->iov_base += this;
+ iov->iov_len -= this;
+ iocb->ki_left -= this;
+ ret -= this;
+ if (iov->iov_len == 0) {
+ iocb->ki_cur_seg++;
+ iov++;
}
+ }
- /*
- * For pipes and sockets we return once we have some data; for
- * regular files we retry till we complete the entire read or
- * find that we can't read any more data (e.g short reads).
- */
- } while (ret > 0 && iocb->ki_left > 0 &&
- !S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode));
-
- /* This means we must have transferred all that we could */
- /* No need to retry anymore */
- if ((ret == 0) || (iocb->ki_left == 0))
- ret = iocb->ki_nbytes - iocb->ki_left;
-
- return ret;
+ /* the caller should not have done more io than what fit in
+ * the remaining iovecs */
+ BUG_ON(ret > 0 && iocb->ki_left == 0);
}
-/* see aio_pread() */
-static ssize_t aio_pwrite(struct kiocb *iocb)
+static ssize_t aio_rw_vect_retry(struct kiocb *iocb)
{
struct file *file = iocb->ki_filp;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ ssize_t (*rw_op)(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t);
ssize_t ret = 0;
+ unsigned short opcode;
+
+ if ((iocb->ki_opcode == IOCB_CMD_PREADV) ||
+ (iocb->ki_opcode == IOCB_CMD_PREAD)) {
+ rw_op = file->f_op->aio_read;
+ opcode = IOCB_CMD_PREADV;
+ } else {
+ rw_op = file->f_op->aio_write;
+ opcode = IOCB_CMD_PWRITEV;
+ }
do {
- ret = file->f_op->aio_write(iocb, iocb->ki_buf,
- iocb->ki_left, iocb->ki_pos);
- if (ret > 0) {
- iocb->ki_buf += ret;
- iocb->ki_left -= ret;
- }
- } while (ret > 0 && iocb->ki_left > 0);
+ ret = rw_op(iocb, &iocb->ki_iovec[iocb->ki_cur_seg],
+ iocb->ki_nr_segs - iocb->ki_cur_seg,
+ iocb->ki_pos);
+ if (ret > 0)
+ aio_advance_iovec(iocb, ret);
+
+ /* retry all partial writes. retry partial reads as long as its a
+ * regular file. */
+ } while (ret > 0 && iocb->ki_left > 0 &&
+ (opcode == IOCB_CMD_PWRITEV ||
+ (!S_ISFIFO(inode->i_mode) && !S_ISSOCK(inode->i_mode))));
+ /* This means we must have transferred all that we could */
+ /* No need to retry anymore */
if ((ret == 0) || (iocb->ki_left == 0))
ret = iocb->ki_nbytes - iocb->ki_left;
@@ -1383,6 +1387,38 @@ static ssize_t aio_fsync(struct kiocb *iocb)
return ret;
}
+static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb)
+{
+ ssize_t ret;
+
+ ret = rw_copy_check_uvector(type, (struct iovec __user *)kiocb->ki_buf,
+ kiocb->ki_nbytes, 1,
+ &kiocb->ki_inline_vec, &kiocb->ki_iovec);
+ if (ret < 0)
+ goto out;
+
+ kiocb->ki_nr_segs = kiocb->ki_nbytes;
+ kiocb->ki_cur_seg = 0;
+ /* ki_nbytes/left now reflect bytes instead of segs */
+ kiocb->ki_nbytes = ret;
+ kiocb->ki_left = ret;
+
+ ret = 0;
+out:
+ return ret;
+}
+
+static ssize_t aio_setup_single_vector(struct kiocb *kiocb)
+{
+ kiocb->ki_iovec = &kiocb->ki_inline_vec;
+ kiocb->ki_iovec->iov_base = kiocb->ki_buf;
+ kiocb->ki_iovec->iov_len = kiocb->ki_left;
+ kiocb->ki_nr_segs = 1;
+ kiocb->ki_cur_seg = 0;
+ kiocb->ki_nbytes = kiocb->ki_left;
+ return 0;
+}
+
/*
* aio_setup_iocb:
* Performs the initial checks and aio retry method
@@ -1405,9 +1441,12 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb)
ret = security_file_permission(file, MAY_READ);
if (unlikely(ret))
break;
+ ret = aio_setup_single_vector(kiocb);
+ if (ret)
+ break;
ret = -EINVAL;
if (file->f_op->aio_read)
- kiocb->ki_retry = aio_pread;
+ kiocb->ki_retry = aio_rw_vect_retry;
break;
case IOCB_CMD_PWRITE:
ret = -EBADF;
@@ -1420,9 +1459,40 @@ static ssize_t aio_setup_iocb(struct kiocb *kiocb)
ret = security_file_permission(file, MAY_WRITE);
if (unlikely(ret))
break;
+ ret = aio_setup_single_vector(kiocb);
+ if (ret)
+ break;
+ ret = -EINVAL;
+ if (file->f_op->aio_write)
+ kiocb->ki_retry = aio_rw_vect_retry;
+ break;
+ case IOCB_CMD_PREADV:
+ ret = -EBADF;
+ if (unlikely(!(file->f_mode & FMODE_READ)))
+ break;
+ ret = security_file_permission(file, MAY_READ);
+ if (unlikely(ret))
+ break;
+ ret = aio_setup_vectored_rw(READ, kiocb);
+ if (ret)
+ break;
+ ret = -EINVAL;
+ if (file->f_op->aio_read)
+ kiocb->ki_retry = aio_rw_vect_retry;
+ break;
+ case IOCB_CMD_PWRITEV:
+ ret = -EBADF;
+ if (unlikely(!(file->f_mode & FMODE_WRITE)))
+ break;
+ ret = security_file_permission(file, MAY_WRITE);
+ if (unlikely(ret))
+ break;
+ ret = aio_setup_vectored_rw(WRITE, kiocb);
+ if (ret)
+ break;
ret = -EINVAL;
if (file->f_op->aio_write)
- kiocb->ki_retry = aio_pwrite;
+ kiocb->ki_retry = aio_rw_vect_retry;
break;
case IOCB_CMD_FDSYNC:
ret = -EINVAL;
diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h
index c7700d9b3f96..906ba5ce2261 100644
--- a/fs/autofs/autofs_i.h
+++ b/fs/autofs/autofs_i.h
@@ -149,6 +149,7 @@ extern const struct file_operations autofs_root_operations;
/* Initializing function */
int autofs_fill_super(struct super_block *, void *, int);
+void autofs_kill_sb(struct super_block *sb);
/* Queue management functions */
diff --git a/fs/autofs/dirhash.c b/fs/autofs/dirhash.c
index 3fded389d06b..bf8c8af98004 100644
--- a/fs/autofs/dirhash.c
+++ b/fs/autofs/dirhash.c
@@ -246,5 +246,4 @@ void autofs_hash_nuke(struct autofs_sb_info *sbi)
kfree(ent);
}
}
- shrink_dcache_sb(sbi->sb);
}
diff --git a/fs/autofs/init.c b/fs/autofs/init.c
index aca123752406..cea5219b4f37 100644
--- a/fs/autofs/init.c
+++ b/fs/autofs/init.c
@@ -24,7 +24,7 @@ static struct file_system_type autofs_fs_type = {
.owner = THIS_MODULE,
.name = "autofs",
.get_sb = autofs_get_sb,
- .kill_sb = kill_anon_super,
+ .kill_sb = autofs_kill_sb,
};
static int __init init_autofs_fs(void)
diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index af2efbbb5d76..54c518c89e4c 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -20,7 +20,7 @@
#include "autofs_i.h"
#include <linux/module.h>
-static void autofs_put_super(struct super_block *sb)
+void autofs_kill_sb(struct super_block *sb)
{
struct autofs_sb_info *sbi = autofs_sbi(sb);
unsigned int n;
@@ -37,13 +37,13 @@ static void autofs_put_super(struct super_block *sb)
kfree(sb->s_fs_info);
DPRINTK(("autofs: shutting down\n"));
+ kill_anon_super(sb);
}
static void autofs_read_inode(struct inode *inode);
static struct super_operations autofs_sops = {
.read_inode = autofs_read_inode,
- .put_super = autofs_put_super,
.statfs = simple_statfs,
};
@@ -129,10 +129,9 @@ int autofs_fill_super(struct super_block *s, void *data, int silent)
struct autofs_sb_info *sbi;
int minproto, maxproto;
- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if ( !sbi )
goto fail_unlock;
- memset(sbi, 0, sizeof(*sbi));
DPRINTK(("autofs: starting up, sbi = %p\n",sbi));
s->s_fs_info = sbi;
@@ -217,7 +216,6 @@ static void autofs_read_inode(struct inode *inode)
inode->i_nlink = 2;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
- inode->i_blksize = 1024;
if ( ino == AUTOFS_ROOT_INO ) {
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
@@ -242,7 +240,7 @@ static void autofs_read_inode(struct inode *inode)
inode->i_op = &autofs_symlink_inode_operations;
sl = &sbi->symlink[n];
- inode->u.generic_ip = sl;
+ inode->i_private = sl;
inode->i_mode = S_IFLNK | S_IRWXUGO;
inode->i_mtime.tv_sec = inode->i_ctime.tv_sec = sl->mtime;
inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0;
diff --git a/fs/autofs/root.c b/fs/autofs/root.c
index 9cac08d6a873..368a1c33a3c8 100644
--- a/fs/autofs/root.c
+++ b/fs/autofs/root.c
@@ -414,7 +414,7 @@ static int autofs_root_rmdir(struct inode *dir, struct dentry *dentry)
dentry->d_time = (unsigned long)(struct autofs_dir_ent *)NULL;
autofs_hash_delete(ent);
- dir->i_nlink--;
+ drop_nlink(dir);
d_drop(dentry);
unlock_kernel();
@@ -466,7 +466,7 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
ent->dentry = dentry;
autofs_hash_insert(dh,ent);
- dir->i_nlink++;
+ inc_nlink(dir);
d_instantiate(dentry, iget(dir->i_sb,ino));
unlock_kernel();
diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c
index 52e8772b066e..c74f2eb65775 100644
--- a/fs/autofs/symlink.c
+++ b/fs/autofs/symlink.c
@@ -15,7 +15,7 @@
/* Nothing to release.. */
static void *autofs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- char *s=((struct autofs_symlink *)dentry->d_inode->u.generic_ip)->data;
+ char *s=((struct autofs_symlink *)dentry->d_inode->i_private)->data;
nd_set_link(nd, s);
return NULL;
}
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h
index 480ab178cba5..b13f32c8aeee 100644
--- a/fs/autofs4/autofs_i.h
+++ b/fs/autofs4/autofs_i.h
@@ -94,7 +94,6 @@ struct autofs_wait_queue {
struct autofs_sb_info {
u32 magic;
- struct dentry *root;
int pipefd;
struct file *pipe;
pid_t oz_pgrp;
@@ -229,4 +228,4 @@ out:
}
void autofs4_dentry_release(struct dentry *);
-
+extern void autofs4_kill_sb(struct super_block *);
diff --git a/fs/autofs4/init.c b/fs/autofs4/init.c
index 5d9193332bef..723a1c5e361b 100644
--- a/fs/autofs4/init.c
+++ b/fs/autofs4/init.c
@@ -24,7 +24,7 @@ static struct file_system_type autofs_fs_type = {
.owner = THIS_MODULE,
.name = "autofs",
.get_sb = autofs_get_sb,
- .kill_sb = kill_anon_super,
+ .kill_sb = autofs4_kill_sb,
};
static int __init init_autofs4_fs(void)
diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c
index 11a6a9ae51b7..51fd8595bf85 100644
--- a/fs/autofs4/inode.c
+++ b/fs/autofs4/inode.c
@@ -96,7 +96,7 @@ void autofs4_free_ino(struct autofs_info *ino)
*/
static void autofs4_force_release(struct autofs_sb_info *sbi)
{
- struct dentry *this_parent = sbi->root;
+ struct dentry *this_parent = sbi->sb->s_root;
struct list_head *next;
spin_lock(&dcache_lock);
@@ -127,7 +127,7 @@ resume:
spin_lock(&dcache_lock);
}
- if (this_parent != sbi->root) {
+ if (this_parent != sbi->sb->s_root) {
struct dentry *dentry = this_parent;
next = this_parent->d_u.d_child.next;
@@ -140,15 +140,9 @@ resume:
goto resume;
}
spin_unlock(&dcache_lock);
-
- dput(sbi->root);
- sbi->root = NULL;
- shrink_dcache_sb(sbi->sb);
-
- return;
}
-static void autofs4_put_super(struct super_block *sb)
+void autofs4_kill_sb(struct super_block *sb)
{
struct autofs_sb_info *sbi = autofs4_sbi(sb);
@@ -163,6 +157,7 @@ static void autofs4_put_super(struct super_block *sb)
kfree(sbi);
DPRINTK("shutting down");
+ kill_anon_super(sb);
}
static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)
@@ -189,7 +184,6 @@ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)
}
static struct super_operations autofs4_sops = {
- .put_super = autofs4_put_super,
.statfs = simple_statfs,
.show_options = autofs4_show_options,
};
@@ -315,7 +309,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
s->s_fs_info = sbi;
sbi->magic = AUTOFS_SBI_MAGIC;
- sbi->root = NULL;
sbi->pipefd = -1;
sbi->catatonic = 0;
sbi->exp_timeout = 0;
@@ -397,13 +390,6 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
sbi->pipefd = pipefd;
/*
- * Take a reference to the root dentry so we get a chance to
- * clean up the dentry tree on umount.
- * See autofs4_force_release.
- */
- sbi->root = dget(root);
-
- /*
* Success! Install the root dentry now to indicate completion.
*/
s->s_root = root;
@@ -447,7 +433,6 @@ struct inode *autofs4_get_inode(struct super_block *sb,
inode->i_uid = 0;
inode->i_gid = 0;
}
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 5100f984783f..c1493524da4d 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -137,7 +137,9 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
nd.flags = LOOKUP_DIRECTORY;
ret = (dentry->d_op->d_revalidate)(dentry, &nd);
- if (!ret) {
+ if (ret <= 0) {
+ if (ret < 0)
+ status = ret;
dcache_dir_close(inode, file);
goto out;
}
@@ -279,9 +281,6 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags)
DPRINTK("mount done status=%d", status);
- if (status && dentry->d_inode)
- return status; /* Try to get the kernel to invalidate this dentry */
-
/* Turn this into a real negative dentry? */
if (status == -ENOENT) {
spin_lock(&dentry->d_lock);
@@ -357,7 +356,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
* don't try to mount it again.
*/
spin_lock(&dcache_lock);
- if (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
+ if (!d_mountpoint(dentry) && __simple_empty(dentry)) {
spin_unlock(&dcache_lock);
status = try_to_fill_dentry(dentry, 0);
@@ -400,13 +399,23 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
int oz_mode = autofs4_oz_mode(sbi);
int flags = nd ? nd->flags : 0;
- int status = 0;
+ int status = 1;
/* Pending dentry */
if (autofs4_ispending(dentry)) {
- if (!oz_mode)
- status = try_to_fill_dentry(dentry, flags);
- return !status;
+ /* The daemon never causes a mount to trigger */
+ if (oz_mode)
+ return 1;
+
+ /*
+ * A zero status is success otherwise we have a
+ * negative error code.
+ */
+ status = try_to_fill_dentry(dentry, flags);
+ if (status == 0)
+ return 1;
+
+ return status;
}
/* Negative dentry.. invalidate if "old" */
@@ -421,9 +430,19 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
DPRINTK("dentry=%p %.*s, emptydir",
dentry, dentry->d_name.len, dentry->d_name.name);
spin_unlock(&dcache_lock);
- if (!oz_mode)
- status = try_to_fill_dentry(dentry, flags);
- return !status;
+ /* The daemon never causes a mount to trigger */
+ if (oz_mode)
+ return 1;
+
+ /*
+ * A zero status is success otherwise we have a
+ * negative error code.
+ */
+ status = try_to_fill_dentry(dentry, flags);
+ if (status == 0)
+ return 1;
+
+ return status;
}
spin_unlock(&dcache_lock);
@@ -518,6 +537,9 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
return ERR_PTR(-ERESTARTNOINTR);
}
}
+ spin_lock(&dentry->d_lock);
+ dentry->d_flags &= ~DCACHE_AUTOFS_PENDING;
+ spin_unlock(&dentry->d_lock);
}
/*
@@ -616,7 +638,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
dput(ino->dentry);
dentry->d_inode->i_size = 0;
- dentry->d_inode->i_nlink = 0;
+ clear_nlink(dentry->d_inode);
dir->i_mtime = CURRENT_TIME;
@@ -651,10 +673,10 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
}
dput(ino->dentry);
dentry->d_inode->i_size = 0;
- dentry->d_inode->i_nlink = 0;
+ clear_nlink(dentry->d_inode);
if (dir->i_nlink)
- dir->i_nlink--;
+ drop_nlink(dir);
return 0;
}
@@ -691,7 +713,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (p_ino && dentry->d_parent != dentry)
atomic_inc(&p_ino->count);
ino->inode = inode;
- dir->i_nlink++;
+ inc_nlink(dir);
dir->i_mtime = CURRENT_TIME;
return 0;
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index ce103e7b0bc3..c0a6c8d445c7 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -45,7 +45,6 @@ void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
fput(sbi->pipe); /* Close the pipe */
sbi->pipe = NULL;
}
- shrink_dcache_sb(sbi->sb);
}
static int autofs4_write(struct file *file, const void *addr, int bytes)
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 80599ae33966..34e6d7b220c3 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -40,8 +40,6 @@ static const struct file_operations bad_file_ops =
.aio_fsync = EIO_ERROR,
.fasync = EIO_ERROR,
.lock = EIO_ERROR,
- .readv = EIO_ERROR,
- .writev = EIO_ERROR,
.sendfile = EIO_ERROR,
.sendpage = EIO_ERROR,
.get_unmapped_area = EIO_ERROR,
diff --git a/fs/befs/befs.h b/fs/befs/befs.h
index 057a2c3d73b7..d9a40abda6b7 100644
--- a/fs/befs/befs.h
+++ b/fs/befs/befs.h
@@ -94,7 +94,7 @@ void befs_debug(const struct super_block *sb, const char *fmt, ...);
void befs_dump_super_block(const struct super_block *sb, befs_super_block *);
void befs_dump_inode(const struct super_block *sb, befs_inode *);
-void befs_dump_index_entry(const struct super_block *sb, befs_btree_super *);
+void befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super *);
void befs_dump_index_node(const struct super_block *sb, befs_btree_nodehead *);
/****************************/
@@ -136,7 +136,7 @@ blockno2iaddr(struct super_block *sb, befs_blocknr_t blockno)
static inline unsigned int
befs_iaddrs_per_block(struct super_block *sb)
{
- return BEFS_SB(sb)->block_size / sizeof (befs_inode_addr);
+ return BEFS_SB(sb)->block_size / sizeof (befs_disk_inode_addr);
}
static inline int
@@ -151,4 +151,6 @@ befs_brun_size(struct super_block *sb, befs_block_run run)
return BEFS_SB(sb)->block_size * run.len;
}
+#include "endian.h"
+
#endif /* _LINUX_BEFS_H */
diff --git a/fs/befs/befs_fs_types.h b/fs/befs/befs_fs_types.h
index 9095518e918d..e2595c2c403a 100644
--- a/fs/befs/befs_fs_types.h
+++ b/fs/befs/befs_fs_types.h
@@ -1,5 +1,5 @@
/*
- * include/linux/befs_fs_types.h
+ * fs/befs/befs_fs_types.h
*
* Copyright (C) 2001 Will Dyson (will@cs.earlham.edu)
*
@@ -79,17 +79,27 @@ enum inode_flags {
* On-Disk datastructures of BeFS
*/
+typedef u64 __bitwise fs64;
+typedef u32 __bitwise fs32;
+typedef u16 __bitwise fs16;
+
typedef u64 befs_off_t;
-typedef u64 befs_time_t;
-typedef void befs_binode_etc;
+typedef fs64 befs_time_t;
/* Block runs */
typedef struct {
+ fs32 allocation_group;
+ fs16 start;
+ fs16 len;
+} PACKED befs_disk_block_run;
+
+typedef struct {
u32 allocation_group;
u16 start;
u16 len;
} PACKED befs_block_run;
+typedef befs_disk_block_run befs_disk_inode_addr;
typedef befs_block_run befs_inode_addr;
/*
@@ -97,31 +107,31 @@ typedef befs_block_run befs_inode_addr;
*/
typedef struct {
char name[B_OS_NAME_LENGTH];
- u32 magic1;
- u32 fs_byte_order;
+ fs32 magic1;
+ fs32 fs_byte_order;
- u32 block_size;
- u32 block_shift;
+ fs32 block_size;
+ fs32 block_shift;
- befs_off_t num_blocks;
- befs_off_t used_blocks;
+ fs64 num_blocks;
+ fs64 used_blocks;
- u32 inode_size;
+ fs32 inode_size;
- u32 magic2;
- u32 blocks_per_ag;
- u32 ag_shift;
- u32 num_ags;
+ fs32 magic2;
+ fs32 blocks_per_ag;
+ fs32 ag_shift;
+ fs32 num_ags;
- u32 flags;
+ fs32 flags;
- befs_block_run log_blocks;
- befs_off_t log_start;
- befs_off_t log_end;
+ befs_disk_block_run log_blocks;
+ fs64 log_start;
+ fs64 log_end;
- u32 magic3;
- befs_inode_addr root_dir;
- befs_inode_addr indices;
+ fs32 magic3;
+ befs_disk_inode_addr root_dir;
+ befs_disk_inode_addr indices;
} PACKED befs_super_block;
@@ -130,6 +140,16 @@ typedef struct {
* be longer than one block!
*/
typedef struct {
+ befs_disk_block_run direct[BEFS_NUM_DIRECT_BLOCKS];
+ fs64 max_direct_range;
+ befs_disk_block_run indirect;
+ fs64 max_indirect_range;
+ befs_disk_block_run double_indirect;
+ fs64 max_double_indirect_range;
+ fs64 size;
+} PACKED befs_disk_data_stream;
+
+typedef struct {
befs_block_run direct[BEFS_NUM_DIRECT_BLOCKS];
befs_off_t max_direct_range;
befs_block_run indirect;
@@ -141,35 +161,35 @@ typedef struct {
/* Attribute */
typedef struct {
- u32 type;
- u16 name_size;
- u16 data_size;
+ fs32 type;
+ fs16 name_size;
+ fs16 data_size;
char name[1];
} PACKED befs_small_data;
/* Inode structure */
typedef struct {
- u32 magic1;
- befs_inode_addr inode_num;
- u32 uid;
- u32 gid;
- u32 mode;
- u32 flags;
+ fs32 magic1;
+ befs_disk_inode_addr inode_num;
+ fs32 uid;
+ fs32 gid;
+ fs32 mode;
+ fs32 flags;
befs_time_t create_time;
befs_time_t last_modified_time;
- befs_inode_addr parent;
- befs_inode_addr attributes;
- u32 type;
+ befs_disk_inode_addr parent;
+ befs_disk_inode_addr attributes;
+ fs32 type;
- u32 inode_size;
- u32 etc; /* not use */
+ fs32 inode_size;
+ fs32 etc; /* not use */
union {
- befs_data_stream datastream;
+ befs_disk_data_stream datastream;
char symlink[BEFS_SYMLINK_LEN];
} data;
- u32 pad[4]; /* not use */
+ fs32 pad[4]; /* not use */
befs_small_data small_data[1];
} PACKED befs_inode;
@@ -190,6 +210,16 @@ enum btree_types {
};
typedef struct {
+ fs32 magic;
+ fs32 node_size;
+ fs32 max_depth;
+ fs32 data_type;
+ fs64 root_node_ptr;
+ fs64 free_node_ptr;
+ fs64 max_size;
+} PACKED befs_disk_btree_super;
+
+typedef struct {
u32 magic;
u32 node_size;
u32 max_depth;
@@ -203,11 +233,19 @@ typedef struct {
* Header stucture of each btree node
*/
typedef struct {
+ fs64 left;
+ fs64 right;
+ fs64 overflow;
+ fs16 all_key_count;
+ fs16 all_key_length;
+} PACKED befs_btree_nodehead;
+
+typedef struct {
befs_off_t left;
befs_off_t right;
befs_off_t overflow;
u16 all_key_count;
u16 all_key_length;
-} PACKED befs_btree_nodehead;
+} PACKED befs_host_btree_nodehead;
#endif /* _LINUX_BEFS_FS_TYPES */
diff --git a/fs/befs/btree.c b/fs/befs/btree.c
index 76e219799409..81b042ee24e6 100644
--- a/fs/befs/btree.c
+++ b/fs/befs/btree.c
@@ -30,7 +30,6 @@
#include "befs.h"
#include "btree.h"
#include "datastream.h"
-#include "endian.h"
/*
* The btree functions in this file are built on top of the
@@ -80,7 +79,7 @@
* In memory structure of each btree node
*/
typedef struct {
- befs_btree_nodehead head; /* head of node converted to cpu byteorder */
+ befs_host_btree_nodehead head; /* head of node converted to cpu byteorder */
struct buffer_head *bh;
befs_btree_nodehead *od_node; /* on disk node */
} befs_btree_node;
@@ -102,9 +101,9 @@ static int befs_bt_read_node(struct super_block *sb, befs_data_stream * ds,
static int befs_leafnode(befs_btree_node * node);
-static u16 *befs_bt_keylen_index(befs_btree_node * node);
+static fs16 *befs_bt_keylen_index(befs_btree_node * node);
-static befs_off_t *befs_bt_valarray(befs_btree_node * node);
+static fs64 *befs_bt_valarray(befs_btree_node * node);
static char *befs_bt_keydata(befs_btree_node * node);
@@ -136,7 +135,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
befs_btree_super * sup)
{
struct buffer_head *bh = NULL;
- befs_btree_super *od_sup = NULL;
+ befs_disk_btree_super *od_sup = NULL;
befs_debug(sb, "---> befs_btree_read_super()");
@@ -146,7 +145,7 @@ befs_bt_read_super(struct super_block *sb, befs_data_stream * ds,
befs_error(sb, "Couldn't read index header.");
goto error;
}
- od_sup = (befs_btree_super *) bh->b_data;
+ od_sup = (befs_disk_btree_super *) bh->b_data;
befs_dump_index_entry(sb, od_sup);
sup->magic = fs32_to_cpu(sb, od_sup->magic);
@@ -342,7 +341,7 @@ befs_find_key(struct super_block *sb, befs_btree_node * node,
u16 keylen;
int findkey_len;
char *thiskey;
- befs_off_t *valarray;
+ fs64 *valarray;
befs_debug(sb, "---> befs_find_key() %s", findkey);
@@ -422,7 +421,7 @@ befs_btree_read(struct super_block *sb, befs_data_stream * ds,
befs_btree_super bt_super;
befs_off_t node_off = 0;
int cur_key;
- befs_off_t *valarray;
+ fs64 *valarray;
char *keystart;
u16 keylen;
int res;
@@ -572,7 +571,7 @@ befs_btree_seekleaf(struct super_block *sb, befs_data_stream * ds,
this_node->head.overflow);
*node_off = this_node->head.overflow;
} else {
- befs_off_t *valarray = befs_bt_valarray(this_node);
+ fs64 *valarray = befs_bt_valarray(this_node);
*node_off = fs64_to_cpu(sb, valarray[0]);
}
if (befs_bt_read_node(sb, ds, this_node, *node_off) != BEFS_OK) {
@@ -622,7 +621,7 @@ befs_leafnode(befs_btree_node * node)
*
* Except that rounding up to 8 works, and rounding up to 4 doesn't.
*/
-static u16 *
+static fs16 *
befs_bt_keylen_index(befs_btree_node * node)
{
const int keylen_align = 8;
@@ -633,7 +632,7 @@ befs_bt_keylen_index(befs_btree_node * node)
if (tmp)
off += keylen_align - tmp;
- return (u16 *) ((void *) node->od_node + off);
+ return (fs16 *) ((void *) node->od_node + off);
}
/**
@@ -643,13 +642,13 @@ befs_bt_keylen_index(befs_btree_node * node)
* Returns a pointer to the start of the value array
* of the node pointed to by the node header
*/
-static befs_off_t *
+static fs64 *
befs_bt_valarray(befs_btree_node * node)
{
void *keylen_index_start = (void *) befs_bt_keylen_index(node);
- size_t keylen_index_size = node->head.all_key_count * sizeof (u16);
+ size_t keylen_index_size = node->head.all_key_count * sizeof (fs16);
- return (befs_off_t *) (keylen_index_start + keylen_index_size);
+ return (fs64 *) (keylen_index_start + keylen_index_size);
}
/**
@@ -681,7 +680,7 @@ befs_bt_get_key(struct super_block *sb, befs_btree_node * node,
{
int prev_key_end;
char *keystart;
- u16 *keylen_index;
+ fs16 *keylen_index;
if (index < 0 || index > node->head.all_key_count) {
*keylen = 0;
diff --git a/fs/befs/datastream.c b/fs/befs/datastream.c
index b7d6b920f65f..aacb4da6298a 100644
--- a/fs/befs/datastream.c
+++ b/fs/befs/datastream.c
@@ -18,7 +18,6 @@
#include "befs.h"
#include "datastream.h"
#include "io.h"
-#include "endian.h"
const befs_inode_addr BAD_IADDR = { 0, 0, 0 };
@@ -312,7 +311,7 @@ befs_find_brun_indirect(struct super_block *sb,
befs_blocknr_t indir_start_blk;
befs_blocknr_t search_blk;
struct buffer_head *indirblock;
- befs_block_run *array;
+ befs_disk_block_run *array;
befs_block_run indirect = data->indirect;
befs_blocknr_t indirblockno = iaddr2blockno(sb, &indirect);
@@ -334,7 +333,7 @@ befs_find_brun_indirect(struct super_block *sb,
return BEFS_ERR;
}
- array = (befs_block_run *) indirblock->b_data;
+ array = (befs_disk_block_run *) indirblock->b_data;
for (j = 0; j < arraylen; ++j) {
int len = fs16_to_cpu(sb, array[j].len);
@@ -427,7 +426,7 @@ befs_find_brun_dblindirect(struct super_block *sb,
struct buffer_head *dbl_indir_block;
struct buffer_head *indir_block;
befs_block_run indir_run;
- befs_inode_addr *iaddr_array = NULL;
+ befs_disk_inode_addr *iaddr_array = NULL;
befs_sb_info *befs_sb = BEFS_SB(sb);
befs_blocknr_t indir_start_blk =
@@ -482,7 +481,7 @@ befs_find_brun_dblindirect(struct super_block *sb,
dbl_block_indx =
dblindir_indx - (dbl_which_block * befs_iaddrs_per_block(sb));
- iaddr_array = (befs_inode_addr *) dbl_indir_block->b_data;
+ iaddr_array = (befs_disk_inode_addr *) dbl_indir_block->b_data;
indir_run = fsrun_to_cpu(sb, iaddr_array[dbl_block_indx]);
brelse(dbl_indir_block);
iaddr_array = NULL;
@@ -507,7 +506,7 @@ befs_find_brun_dblindirect(struct super_block *sb,
}
block_indx = indir_indx - (which_block * befs_iaddrs_per_block(sb));
- iaddr_array = (befs_inode_addr *) indir_block->b_data;
+ iaddr_array = (befs_disk_inode_addr *) indir_block->b_data;
*run = fsrun_to_cpu(sb, iaddr_array[block_indx]);
brelse(indir_block);
iaddr_array = NULL;
diff --git a/fs/befs/debug.c b/fs/befs/debug.c
index 875cc0aa318c..e831a8f30849 100644
--- a/fs/befs/debug.c
+++ b/fs/befs/debug.c
@@ -21,7 +21,6 @@
#endif /* __KERNEL__ */
#include "befs.h"
-#include "endian.h"
#define ERRBUFSIZE 1024
@@ -125,7 +124,7 @@ befs_dump_inode(const struct super_block *sb, befs_inode * inode)
befs_debug(sb, " type %08x", fs32_to_cpu(sb, inode->type));
befs_debug(sb, " inode_size %u", fs32_to_cpu(sb, inode->inode_size));
- if (S_ISLNK(inode->mode)) {
+ if (S_ISLNK(fs32_to_cpu(sb, inode->mode))) {
befs_debug(sb, " Symbolic link [%s]", inode->data.symlink);
} else {
int i;
@@ -231,21 +230,20 @@ befs_dump_small_data(const struct super_block *sb, befs_small_data * sd)
/* unused */
void
-befs_dump_run(const struct super_block *sb, befs_block_run run)
+befs_dump_run(const struct super_block *sb, befs_disk_block_run run)
{
#ifdef CONFIG_BEFS_DEBUG
- run = fsrun_to_cpu(sb, run);
+ befs_block_run n = fsrun_to_cpu(sb, run);
- befs_debug(sb, "[%u, %hu, %hu]",
- run.allocation_group, run.start, run.len);
+ befs_debug(sb, "[%u, %hu, %hu]", n.allocation_group, n.start, n.len);
#endif //CONFIG_BEFS_DEBUG
}
#endif /* 0 */
void
-befs_dump_index_entry(const struct super_block *sb, befs_btree_super * super)
+befs_dump_index_entry(const struct super_block *sb, befs_disk_btree_super * super)
{
#ifdef CONFIG_BEFS_DEBUG
diff --git a/fs/befs/endian.h b/fs/befs/endian.h
index 9ecaea4e3325..e254a20869f4 100644
--- a/fs/befs/endian.h
+++ b/fs/befs/endian.h
@@ -10,85 +10,84 @@
#define LINUX_BEFS_ENDIAN
#include <linux/byteorder/generic.h>
-#include "befs.h"
static inline u64
-fs64_to_cpu(const struct super_block *sb, u64 n)
+fs64_to_cpu(const struct super_block *sb, fs64 n)
{
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
- return le64_to_cpu(n);
+ return le64_to_cpu((__force __le64)n);
else
- return be64_to_cpu(n);
+ return be64_to_cpu((__force __be64)n);
}
-static inline u64
+static inline fs64
cpu_to_fs64(const struct super_block *sb, u64 n)
{
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
- return cpu_to_le64(n);
+ return (__force fs64)cpu_to_le64(n);
else
- return cpu_to_be64(n);
+ return (__force fs64)cpu_to_be64(n);
}
static inline u32
-fs32_to_cpu(const struct super_block *sb, u32 n)
+fs32_to_cpu(const struct super_block *sb, fs32 n)
{
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
- return le32_to_cpu(n);
+ return le32_to_cpu((__force __le32)n);
else
- return be32_to_cpu(n);
+ return be32_to_cpu((__force __be32)n);
}
-static inline u32
+static inline fs32
cpu_to_fs32(const struct super_block *sb, u32 n)
{
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
- return cpu_to_le32(n);
+ return (__force fs32)cpu_to_le32(n);
else
- return cpu_to_be32(n);
+ return (__force fs32)cpu_to_be32(n);
}
static inline u16
-fs16_to_cpu(const struct super_block *sb, u16 n)
+fs16_to_cpu(const struct super_block *sb, fs16 n)
{
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
- return le16_to_cpu(n);
+ return le16_to_cpu((__force __le16)n);
else
- return be16_to_cpu(n);
+ return be16_to_cpu((__force __be16)n);
}
-static inline u16
+static inline fs16
cpu_to_fs16(const struct super_block *sb, u16 n)
{
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE)
- return cpu_to_le16(n);
+ return (__force fs16)cpu_to_le16(n);
else
- return cpu_to_be16(n);
+ return (__force fs16)cpu_to_be16(n);
}
/* Composite types below here */
static inline befs_block_run
-fsrun_to_cpu(const struct super_block *sb, befs_block_run n)
+fsrun_to_cpu(const struct super_block *sb, befs_disk_block_run n)
{
befs_block_run run;
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
- run.allocation_group = le32_to_cpu(n.allocation_group);
- run.start = le16_to_cpu(n.start);
- run.len = le16_to_cpu(n.len);
+ run.allocation_group = le32_to_cpu((__force __le32)n.allocation_group);
+ run.start = le16_to_cpu((__force __le16)n.start);
+ run.len = le16_to_cpu((__force __le16)n.len);
} else {
- run.allocation_group = be32_to_cpu(n.allocation_group);
- run.start = be16_to_cpu(n.start);
- run.len = be16_to_cpu(n.len);
+ run.allocation_group = be32_to_cpu((__force __be32)n.allocation_group);
+ run.start = be16_to_cpu((__force __be16)n.start);
+ run.len = be16_to_cpu((__force __be16)n.len);
}
return run;
}
-static inline befs_block_run
+static inline befs_disk_block_run
cpu_to_fsrun(const struct super_block *sb, befs_block_run n)
{
- befs_block_run run;
+ befs_disk_block_run run;
if (BEFS_SB(sb)->byte_order == BEFS_BYTESEX_LE) {
run.allocation_group = cpu_to_le32(n.allocation_group);
@@ -103,7 +102,7 @@ cpu_to_fsrun(const struct super_block *sb, befs_block_run n)
}
static inline befs_data_stream
-fsds_to_cpu(const struct super_block *sb, befs_data_stream n)
+fsds_to_cpu(const struct super_block *sb, befs_disk_data_stream n)
{
befs_data_stream data;
int i;
diff --git a/fs/befs/inode.c b/fs/befs/inode.c
index d41c9247ae8a..94c17f9a9576 100644
--- a/fs/befs/inode.c
+++ b/fs/befs/inode.c
@@ -8,7 +8,6 @@
#include "befs.h"
#include "inode.h"
-#include "endian.h"
/*
Validates the correctness of the befs inode
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 50cfca5c7efd..07f7144f0e2e 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -22,7 +22,6 @@
#include "datastream.h"
#include "super.h"
#include "io.h"
-#include "endian.h"
MODULE_DESCRIPTION("BeOS File System (BeFS) driver");
MODULE_AUTHOR("Will Dyson");
@@ -365,7 +364,6 @@ befs_read_inode(struct inode *inode)
inode->i_mtime.tv_nsec = 0; /* lower 16 bits are not a time */
inode->i_ctime = inode->i_mtime;
inode->i_atime = inode->i_mtime;
- inode->i_blksize = befs_sb->block_size;
befs_ino->i_inode_num = fsrun_to_cpu(sb, raw_inode->inode_num);
befs_ino->i_parent = fsrun_to_cpu(sb, raw_inode->parent);
@@ -446,9 +444,7 @@ befs_init_inodecache(void)
static void
befs_destroy_inodecache(void)
{
- if (kmem_cache_destroy(befs_inode_cachep))
- printk(KERN_ERR "befs_destroy_inodecache: "
- "not all structures were freed\n");
+ kmem_cache_destroy(befs_inode_cachep);
}
/*
diff --git a/fs/befs/super.c b/fs/befs/super.c
index 4557acbac528..8c3401ff6d6a 100644
--- a/fs/befs/super.c
+++ b/fs/befs/super.c
@@ -11,7 +11,6 @@
#include "befs.h"
#include "super.h"
-#include "endian.h"
/**
* load_befs_sb -- Read from disk and properly byteswap all the fields
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 26fad9621738..a650f1d0b85e 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -102,7 +102,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
inode->i_op = &bfs_file_inops;
inode->i_fop = &bfs_file_operations;
inode->i_mapping->a_ops = &bfs_aops;
@@ -117,8 +117,7 @@ static int bfs_create(struct inode * dir, struct dentry * dentry, int mode,
err = bfs_add_entry(dir, dentry->d_name.name, dentry->d_name.len, inode->i_ino);
if (err) {
- inode->i_nlink--;
- mark_inode_dirty(inode);
+ inode_dec_link_count(inode);
iput(inode);
unlock_kernel();
return err;
@@ -164,7 +163,7 @@ static int bfs_link(struct dentry * old, struct inode * dir, struct dentry * new
unlock_kernel();
return err;
}
- inode->i_nlink++;
+ inc_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
atomic_inc(&inode->i_count);
@@ -196,9 +195,8 @@ static int bfs_unlink(struct inode * dir, struct dentry * dentry)
mark_buffer_dirty(bh);
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
- inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
- mark_inode_dirty(inode);
+ inode_dec_link_count(inode);
error = 0;
out_brelse:
@@ -249,9 +247,8 @@ static int bfs_rename(struct inode * old_dir, struct dentry * old_dentry,
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(old_dir);
if (new_inode) {
- new_inode->i_nlink--;
new_inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(new_inode);
+ inode_dec_link_count(new_inode);
}
mark_buffer_dirty(old_bh);
error = 0;
diff --git a/fs/bfs/file.c b/fs/bfs/file.c
index 3d5aca28a0a0..a9164a87f8de 100644
--- a/fs/bfs/file.c
+++ b/fs/bfs/file.c
@@ -19,8 +19,10 @@
const struct file_operations bfs_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.sendfile = generic_file_sendfile,
};
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c
index cf74f3d4d966..ed27ffb3459e 100644
--- a/fs/bfs/inode.c
+++ b/fs/bfs/inode.c
@@ -76,7 +76,6 @@ static void bfs_read_inode(struct inode * inode)
inode->i_size = BFS_FILESIZE(di);
inode->i_blocks = BFS_FILEBLOCKS(di);
if (inode->i_size || inode->i_blocks) dprintf("Registered inode with %lld size, %ld blocks\n", inode->i_size, inode->i_blocks);
- inode->i_blksize = PAGE_SIZE;
inode->i_atime.tv_sec = le32_to_cpu(di->i_atime);
inode->i_mtime.tv_sec = le32_to_cpu(di->i_mtime);
inode->i_ctime.tv_sec = le32_to_cpu(di->i_ctime);
@@ -268,8 +267,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(bfs_inode_cachep))
- printk(KERN_INFO "bfs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(bfs_inode_cachep);
}
static struct super_operations bfs_sops = {
@@ -311,11 +309,10 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
unsigned i, imap_len;
struct bfs_sb_info * info;
- info = kmalloc(sizeof(*info), GFP_KERNEL);
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
if (!info)
return -ENOMEM;
s->s_fs_info = info;
- memset(info, 0, sizeof(*info));
sb_set_blocksize(s, BFS_BSIZE);
@@ -338,10 +335,9 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent)
+ BFS_ROOT_INO - 1;
imap_len = info->si_lasti/8 + 1;
- info->si_imap = kmalloc(imap_len, GFP_KERNEL);
+ info->si_imap = kzalloc(imap_len, GFP_KERNEL);
if (!info->si_imap)
goto out;
- memset(info->si_imap, 0, imap_len);
for (i=0; i<BFS_ROOT_INO; i++)
set_bit(i, info->si_imap);
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index f312103434d4..517e111bb7ef 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -278,6 +278,13 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
return -ENOEXEC;
}
+ /*
+ * Requires a mmap handler. This prevents people from using a.out
+ * as part of an exploit attack against /proc-related vulnerabilities.
+ */
+ if (!bprm->file->f_op || !bprm->file->f_op->mmap)
+ return -ENOEXEC;
+
fd_offset = N_TXTOFF(ex);
/* Check initial limits. This avoids letting people circumvent
@@ -476,6 +483,13 @@ static int load_aout_library(struct file *file)
goto out;
}
+ /*
+ * Requires a mmap handler. This prevents people from using a.out
+ * as part of an exploit attack against /proc-related vulnerabilities.
+ */
+ if (!file->f_op || !file->f_op->mmap)
+ goto out;
+
if (N_FLAGS(ex))
goto out;
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index dfd8cfb7fb5d..79b05a1a4365 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -46,7 +46,6 @@
static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs);
static int load_elf_library(struct file *);
static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, int, int);
-extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
#ifndef elf_addr_t
#define elf_addr_t unsigned long
@@ -1038,10 +1037,8 @@ out_free_interp:
out_free_file:
sys_close(elf_exec_fileno);
out_free_fh:
- if (files) {
- put_files_struct(current->files);
- current->files = files;
- }
+ if (files)
+ reset_files_struct(current, files);
out_free_ph:
kfree(elf_phdata);
goto out;
@@ -1154,11 +1151,23 @@ static int dump_write(struct file *file, const void *addr, int nr)
static int dump_seek(struct file *file, loff_t off)
{
- if (file->f_op->llseek) {
- if (file->f_op->llseek(file, off, 0) != off)
+ if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
+ if (file->f_op->llseek(file, off, SEEK_CUR) < 0)
return 0;
- } else
- file->f_pos = off;
+ } else {
+ char *buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf)
+ return 0;
+ while (off > 0) {
+ unsigned long n = off;
+ if (n > PAGE_SIZE)
+ n = PAGE_SIZE;
+ if (!dump_write(file, buf, n))
+ return 0;
+ off -= n;
+ }
+ free_page((unsigned long)buf);
+ }
return 1;
}
@@ -1206,30 +1215,35 @@ static int notesize(struct memelfnote *en)
return sz;
}
-#define DUMP_WRITE(addr, nr) \
- do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
-#define DUMP_SEEK(off) \
- do { if (!dump_seek(file, (off))) return 0; } while(0)
+#define DUMP_WRITE(addr, nr, foffset) \
+ do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0)
-static int writenote(struct memelfnote *men, struct file *file)
+static int alignfile(struct file *file, loff_t *foffset)
{
- struct elf_note en;
+ static const char buf[4] = { 0, };
+ DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
+ return 1;
+}
+static int writenote(struct memelfnote *men, struct file *file,
+ loff_t *foffset)
+{
+ struct elf_note en;
en.n_namesz = strlen(men->name) + 1;
en.n_descsz = men->datasz;
en.n_type = men->type;
- DUMP_WRITE(&en, sizeof(en));
- DUMP_WRITE(men->name, en.n_namesz);
- /* XXX - cast from long long to long to avoid need for libgcc.a */
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
- DUMP_WRITE(men->data, men->datasz);
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+ DUMP_WRITE(&en, sizeof(en), foffset);
+ DUMP_WRITE(men->name, en.n_namesz, foffset);
+ if (!alignfile(file, foffset))
+ return 0;
+ DUMP_WRITE(men->data, men->datasz, foffset);
+ if (!alignfile(file, foffset))
+ return 0;
return 1;
}
#undef DUMP_WRITE
-#undef DUMP_SEEK
#define DUMP_WRITE(addr, nr) \
if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
@@ -1429,7 +1443,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
int i;
struct vm_area_struct *vma;
struct elfhdr *elf = NULL;
- loff_t offset = 0, dataoff;
+ loff_t offset = 0, dataoff, foffset;
unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
int numnote;
struct memelfnote *notes = NULL;
@@ -1481,20 +1495,19 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
if (signr) {
struct elf_thread_status *tmp;
- read_lock(&tasklist_lock);
+ rcu_read_lock();
do_each_thread(g,p)
if (current->mm == p->mm && current != p) {
tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
if (!tmp) {
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
goto cleanup;
}
- INIT_LIST_HEAD(&tmp->list);
tmp->thread = p;
list_add(&tmp->list, &thread_list);
}
while_each_thread(g,p);
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
list_for_each(t, &thread_list) {
struct elf_thread_status *tmp;
int sz;
@@ -1556,7 +1569,8 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
DUMP_WRITE(elf, sizeof(*elf));
offset += sizeof(*elf); /* Elf header */
- offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
+ offset += (segs + 1) * sizeof(struct elf_phdr); /* Program headers */
+ foffset = offset;
/* Write notes phdr entry */
{
@@ -1573,7 +1587,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
DUMP_WRITE(&phdr, sizeof(phdr));
}
- /* Page-align dumped data */
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
/* Write program headers for segments dump */
@@ -1606,7 +1619,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
/* write out the notes section */
for (i = 0; i < numnote; i++)
- if (!writenote(notes + i, file))
+ if (!writenote(notes + i, file, &foffset))
goto end_coredump;
/* write out the thread status notes section */
@@ -1615,11 +1628,12 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
list_entry(t, struct elf_thread_status, list);
for (i = 0; i < tmp->num_notes; i++)
- if (!writenote(&tmp->notes[i], file))
+ if (!writenote(&tmp->notes[i], file, &foffset))
goto end_coredump;
}
-
- DUMP_SEEK(dataoff);
+
+ /* Align to page */
+ DUMP_SEEK(dataoff - foffset);
for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
unsigned long addr;
@@ -1635,10 +1649,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
if (get_user_pages(current, current->mm, addr, 1, 0, 1,
&page, &vma) <= 0) {
- DUMP_SEEK(file->f_pos + PAGE_SIZE);
+ DUMP_SEEK(PAGE_SIZE);
} else {
if (page == ZERO_PAGE(addr)) {
- DUMP_SEEK(file->f_pos + PAGE_SIZE);
+ DUMP_SEEK(PAGE_SIZE);
} else {
void *kaddr;
flush_cache_page(vma, addr,
@@ -1662,13 +1676,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
ELF_CORE_WRITE_EXTRA_DATA;
#endif
- if (file->f_pos != offset) {
- /* Sanity check */
- printk(KERN_WARNING
- "elf_core_dump: file->f_pos (%Ld) != offset (%Ld)\n",
- file->f_pos, offset);
- }
-
end_coredump:
set_fs(fs);
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 2f3365829229..f86d5c9ce5eb 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -1597,20 +1597,19 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
if (signr) {
struct elf_thread_status *tmp;
- read_lock(&tasklist_lock);
+ rcu_read_lock();
do_each_thread(g,p)
if (current->mm == p->mm && current != p) {
tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
if (!tmp) {
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
goto cleanup;
}
- INIT_LIST_HEAD(&tmp->list);
tmp->thread = p;
list_add(&tmp->list, &thread_list);
}
while_each_thread(g,p);
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
list_for_each(t, &thread_list) {
struct elf_thread_status *tmp;
int sz;
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index 34ebbc191e46..1713c48fef54 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -215,10 +215,8 @@ _error:
bprm->interp_flags = 0;
bprm->interp_data = 0;
_unshare:
- if (files) {
- put_files_struct(current->files);
- current->files = files;
- }
+ if (files)
+ reset_files_struct(current, files);
goto _ret;
}
@@ -507,7 +505,6 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime =
current_fs_time(inode->i_sb);
@@ -517,7 +514,7 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode)
static void bm_clear_inode(struct inode *inode)
{
- kfree(inode->u.generic_ip);
+ kfree(inode->i_private);
}
static void kill_node(Node *e)
@@ -545,7 +542,7 @@ static void kill_node(Node *e)
static ssize_t
bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
{
- Node *e = file->f_dentry->d_inode->u.generic_ip;
+ Node *e = file->f_dentry->d_inode->i_private;
loff_t pos = *ppos;
ssize_t res;
char *page;
@@ -579,7 +576,7 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
struct dentry *root;
- Node *e = file->f_dentry->d_inode->u.generic_ip;
+ Node *e = file->f_dentry->d_inode->i_private;
int res = parse_command(buffer, count);
switch (res) {
@@ -646,7 +643,7 @@ static ssize_t bm_register_write(struct file *file, const char __user *buffer,
}
e->dentry = dget(dentry);
- inode->u.generic_ip = e;
+ inode->i_private = e;
inode->i_fop = &bm_entry_operations;
d_instantiate(dentry, inode);
diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c
index 32b5d625ce9c..5bcdaaf4eae0 100644
--- a/fs/binfmt_som.c
+++ b/fs/binfmt_som.c
@@ -29,6 +29,7 @@
#include <linux/personality.h>
#include <linux/init.h>
+#include <asm/a.out.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -194,6 +195,7 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
unsigned long som_entry;
struct som_hdr *som_ex;
struct som_exec_auxhdr *hpuxhdr;
+ struct files_struct *files;
/* Get the exec-header */
som_ex = (struct som_hdr *) bprm->buf;
@@ -208,15 +210,27 @@ load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs)
size = som_ex->aux_header_size;
if (size > SOM_PAGESIZE)
goto out;
- hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL);
+ hpuxhdr = kmalloc(size, GFP_KERNEL);
if (!hpuxhdr)
goto out;
retval = kernel_read(bprm->file, som_ex->aux_header_location,
(char *) hpuxhdr, size);
+ if (retval != size) {
+ if (retval >= 0)
+ retval = -EIO;
+ goto out_free;
+ }
+
+ files = current->files; /* Refcounted so ok */
+ retval = unshare_files();
if (retval < 0)
goto out_free;
-#error "Fix security hole before enabling me"
+ if (files == current->files) {
+ put_files_struct(files);
+ files = NULL;
+ }
+
retval = get_unused_fd();
if (retval < 0)
goto out_free;
diff --git a/fs/bio.c b/fs/bio.c
index 6a0b9ad8f8c9..f95c8749499f 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2001 Jens Axboe <axboe@kernel.dk>
*
* 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
@@ -79,7 +79,6 @@ static struct bio_set *fs_bio_set;
static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
{
struct bio_vec *bvl;
- struct biovec_slab *bp;
/*
* see comment near bvec_array define!
@@ -98,10 +97,12 @@ static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned lon
* idx now points to the pool we want to allocate from
*/
- bp = bvec_slabs + *idx;
bvl = mempool_alloc(bs->bvec_pools[*idx], gfp_mask);
- if (bvl)
+ if (bvl) {
+ struct biovec_slab *bp = bvec_slabs + *idx;
+
memset(bvl, 0, bp->nr_vecs * sizeof(struct bio_vec));
+ }
return bvl;
}
@@ -166,7 +167,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
bio_init(bio);
if (likely(nr_iovecs)) {
- unsigned long idx;
+ unsigned long idx = 0; /* shut up gcc */
bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
if (unlikely(!bvl)) {
@@ -1142,7 +1143,7 @@ static int biovec_create_pools(struct bio_set *bs, int pool_entries, int scale)
struct biovec_slab *bp = bvec_slabs + i;
mempool_t **bvp = bs->bvec_pools + i;
- if (i >= scale)
+ if (pool_entries > 1 && i >= scale)
pool_entries >>= 1;
*bvp = mempool_create_slab_pool(pool_entries, bp->slab);
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 045f98854f14..bc8f27cc4483 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -17,11 +17,13 @@
#include <linux/module.h>
#include <linux/blkpg.h>
#include <linux/buffer_head.h>
+#include <linux/writeback.h>
#include <linux/mpage.h>
#include <linux/mount.h>
#include <linux/uio.h>
#include <linux/namei.h>
#include <asm/uaccess.h>
+#include "internal.h"
struct bdev_inode {
struct block_device bdev;
@@ -543,11 +545,11 @@ static struct kobject *bdev_get_holder(struct block_device *bdev)
return kobject_get(bdev->bd_disk->holder_dir);
}
-static void add_symlink(struct kobject *from, struct kobject *to)
+static int add_symlink(struct kobject *from, struct kobject *to)
{
if (!from || !to)
- return;
- sysfs_create_link(from, to, kobject_name(to));
+ return 0;
+ return sysfs_create_link(from, to, kobject_name(to));
}
static void del_symlink(struct kobject *from, struct kobject *to)
@@ -648,30 +650,38 @@ static void free_bd_holder(struct bd_holder *bo)
* If there is no matching entry with @bo in @bdev->bd_holder_list,
* add @bo to the list, create symlinks.
*
- * Returns 1 if @bo was added to the list.
- * Returns 0 if @bo wasn't used by any reason and should be freed.
+ * Returns 0 if symlinks are created or already there.
+ * Returns -ve if something fails and @bo can be freed.
*/
static int add_bd_holder(struct block_device *bdev, struct bd_holder *bo)
{
struct bd_holder *tmp;
+ int ret;
if (!bo)
- return 0;
+ return -EINVAL;
list_for_each_entry(tmp, &bdev->bd_holder_list, list) {
if (tmp->sdir == bo->sdir) {
tmp->count++;
+ /* We've already done what we need to do here. */
+ free_bd_holder(bo);
return 0;
}
}
if (!bd_holder_grab_dirs(bdev, bo))
- return 0;
+ return -EBUSY;
- add_symlink(bo->sdir, bo->sdev);
- add_symlink(bo->hdir, bo->hdev);
- list_add_tail(&bo->list, &bdev->bd_holder_list);
- return 1;
+ ret = add_symlink(bo->sdir, bo->sdev);
+ if (ret == 0) {
+ ret = add_symlink(bo->hdir, bo->hdev);
+ if (ret)
+ del_symlink(bo->sdir, bo->sdev);
+ }
+ if (ret == 0)
+ list_add_tail(&bo->list, &bdev->bd_holder_list);
+ return ret;
}
/**
@@ -741,7 +751,9 @@ static int bd_claim_by_kobject(struct block_device *bdev, void *holder,
mutex_lock_nested(&bdev->bd_mutex, BD_MUTEX_PARTITION);
res = bd_claim(bdev, holder);
- if (res || !add_bd_holder(bdev, bo))
+ if (res == 0)
+ res = add_bd_holder(bdev, bo);
+ if (res)
free_bd_holder(bo);
mutex_unlock(&bdev->bd_mutex);
@@ -1021,7 +1033,7 @@ do_open(struct block_device *bdev, struct file *file, unsigned int subclass)
rescan_partitions(bdev->bd_disk, bdev);
} else {
mutex_lock_nested(&bdev->bd_contains->bd_mutex,
- BD_MUTEX_PARTITION);
+ BD_MUTEX_WHOLE);
bdev->bd_contains->bd_part_count++;
mutex_unlock(&bdev->bd_contains->bd_mutex);
}
@@ -1142,22 +1154,6 @@ static int blkdev_close(struct inode * inode, struct file * filp)
return blkdev_put(bdev);
}
-static ssize_t blkdev_file_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
-
- return generic_file_write_nolock(file, &local_iov, 1, ppos);
-}
-
-static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
-{
- struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
-
- return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
-}
-
static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg)
{
return blkdev_ioctl(file->f_mapping->host, file, cmd, arg);
@@ -1177,18 +1173,16 @@ const struct file_operations def_blk_fops = {
.open = blkdev_open,
.release = blkdev_close,
.llseek = block_llseek,
- .read = generic_file_read,
- .write = blkdev_file_write,
+ .read = do_sync_read,
+ .write = do_sync_write,
.aio_read = generic_file_aio_read,
- .aio_write = blkdev_file_aio_write,
+ .aio_write = generic_file_aio_write_nolock,
.mmap = generic_file_mmap,
.fsync = block_fsync,
.unlocked_ioctl = block_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = compat_blkdev_ioctl,
#endif
- .readv = generic_file_readv,
- .writev = generic_file_write_nolock,
.sendfile = generic_file_sendfile,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
@@ -1303,3 +1297,24 @@ void close_bdev_excl(struct block_device *bdev)
}
EXPORT_SYMBOL(close_bdev_excl);
+
+int __invalidate_device(struct block_device *bdev)
+{
+ struct super_block *sb = get_super(bdev);
+ int res = 0;
+
+ if (sb) {
+ /*
+ * no need to lock the super, get_super holds the
+ * read mutex so the filesystem cannot go away
+ * under us (->put_super runs with the write lock
+ * hold).
+ */
+ shrink_dcache_sb(sb);
+ res = invalidate_inodes(sb);
+ drop_super(sb);
+ }
+ invalidate_bdev(bdev, 0);
+ return res;
+}
+EXPORT_SYMBOL(__invalidate_device);
diff --git a/fs/buffer.c b/fs/buffer.c
index 3b6d701073e7..35527dca1dbc 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -159,31 +159,6 @@ int sync_blockdev(struct block_device *bdev)
}
EXPORT_SYMBOL(sync_blockdev);
-static void __fsync_super(struct super_block *sb)
-{
- sync_inodes_sb(sb, 0);
- DQUOT_SYNC(sb);
- lock_super(sb);
- if (sb->s_dirt && sb->s_op->write_super)
- sb->s_op->write_super(sb);
- unlock_super(sb);
- if (sb->s_op->sync_fs)
- sb->s_op->sync_fs(sb, 1);
- sync_blockdev(sb->s_bdev);
- sync_inodes_sb(sb, 1);
-}
-
-/*
- * Write out and wait upon all dirty data associated with this
- * superblock. Filesystem data as well as the underlying block
- * device. Takes the superblock lock.
- */
-int fsync_super(struct super_block *sb)
-{
- __fsync_super(sb);
- return sync_blockdev(sb->s_bdev);
-}
-
/*
* Write out and wait upon all dirty data associated with this
* device. Filesystem data as well as the underlying block
@@ -260,118 +235,6 @@ void thaw_bdev(struct block_device *bdev, struct super_block *sb)
EXPORT_SYMBOL(thaw_bdev);
/*
- * sync everything. Start out by waking pdflush, because that writes back
- * all queues in parallel.
- */
-static void do_sync(unsigned long wait)
-{
- wakeup_pdflush(0);
- sync_inodes(0); /* All mappings, inodes and their blockdevs */
- DQUOT_SYNC(NULL);
- sync_supers(); /* Write the superblocks */
- sync_filesystems(0); /* Start syncing the filesystems */
- sync_filesystems(wait); /* Waitingly sync the filesystems */
- sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */
- if (!wait)
- printk("Emergency Sync complete\n");
- if (unlikely(laptop_mode))
- laptop_sync_completion();
-}
-
-asmlinkage long sys_sync(void)
-{
- do_sync(1);
- return 0;
-}
-
-void emergency_sync(void)
-{
- pdflush_operation(do_sync, 0);
-}
-
-/*
- * Generic function to fsync a file.
- *
- * filp may be NULL if called via the msync of a vma.
- */
-
-int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
-{
- struct inode * inode = dentry->d_inode;
- struct super_block * sb;
- int ret, err;
-
- /* sync the inode to buffers */
- ret = write_inode_now(inode, 0);
-
- /* sync the superblock to buffers */
- sb = inode->i_sb;
- lock_super(sb);
- if (sb->s_op->write_super)
- sb->s_op->write_super(sb);
- unlock_super(sb);
-
- /* .. finally sync the buffers to disk */
- err = sync_blockdev(sb->s_bdev);
- if (!ret)
- ret = err;
- return ret;
-}
-
-long do_fsync(struct file *file, int datasync)
-{
- int ret;
- int err;
- struct address_space *mapping = file->f_mapping;
-
- if (!file->f_op || !file->f_op->fsync) {
- /* Why? We can still call filemap_fdatawrite */
- ret = -EINVAL;
- goto out;
- }
-
- ret = filemap_fdatawrite(mapping);
-
- /*
- * We need to protect against concurrent writers, which could cause
- * livelocks in fsync_buffers_list().
- */
- mutex_lock(&mapping->host->i_mutex);
- err = file->f_op->fsync(file, file->f_dentry, datasync);
- if (!ret)
- ret = err;
- mutex_unlock(&mapping->host->i_mutex);
- err = filemap_fdatawait(mapping);
- if (!ret)
- ret = err;
-out:
- return ret;
-}
-
-static long __do_fsync(unsigned int fd, int datasync)
-{
- struct file *file;
- int ret = -EBADF;
-
- file = fget(fd);
- if (file) {
- ret = do_fsync(file, datasync);
- fput(file);
- }
- return ret;
-}
-
-asmlinkage long sys_fsync(unsigned int fd)
-{
- return __do_fsync(fd, 0);
-}
-
-asmlinkage long sys_fdatasync(unsigned int fd)
-{
- return __do_fsync(fd, 1);
-}
-
-/*
* Various filesystems appear to want __find_get_block to be non-blocking.
* But it's the page lock which protects the buffers. To get around this,
* we get exclusion from try_to_free_buffers with the blockdev mapping's
@@ -589,6 +452,7 @@ static void end_buffer_async_write(struct buffer_head *bh, int uptodate)
bdevname(bh->b_bdev, b));
}
set_bit(AS_EIO, &page->mapping->flags);
+ set_buffer_write_io_error(bh);
clear_buffer_uptodate(bh);
SetPageError(page);
}
@@ -708,6 +572,10 @@ EXPORT_SYMBOL(mark_buffer_async_write);
static inline void __remove_assoc_queue(struct buffer_head *bh)
{
list_del_init(&bh->b_assoc_buffers);
+ WARN_ON(!bh->b_assoc_map);
+ if (buffer_write_io_error(bh))
+ set_bit(AS_EIO, &bh->b_assoc_map->flags);
+ bh->b_assoc_map = NULL;
}
int inode_has_buffers(struct inode *inode)
@@ -806,6 +674,7 @@ void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)
spin_lock(&buffer_mapping->private_lock);
list_move_tail(&bh->b_assoc_buffers,
&mapping->private_list);
+ bh->b_assoc_map = mapping;
spin_unlock(&buffer_mapping->private_lock);
}
}
@@ -838,7 +707,10 @@ EXPORT_SYMBOL(mark_buffer_dirty_inode);
*/
int __set_page_dirty_buffers(struct page *page)
{
- struct address_space * const mapping = page->mapping;
+ struct address_space * const mapping = page_mapping(page);
+
+ if (unlikely(!mapping))
+ return !TestSetPageDirty(page);
spin_lock(&mapping->private_lock);
if (page_has_buffers(page)) {
@@ -899,7 +771,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
spin_lock(lock);
while (!list_empty(list)) {
bh = BH_ENTRY(list->next);
- list_del_init(&bh->b_assoc_buffers);
+ __remove_assoc_queue(bh);
if (buffer_dirty(bh) || buffer_locked(bh)) {
list_add(&bh->b_assoc_buffers, &tmp);
if (buffer_dirty(bh)) {
@@ -920,7 +792,7 @@ static int fsync_buffers_list(spinlock_t *lock, struct list_head *list)
while (!list_empty(&tmp)) {
bh = BH_ENTRY(tmp.prev);
- __remove_assoc_queue(bh);
+ list_del_init(&bh->b_assoc_buffers);
get_bh(bh);
spin_unlock(lock);
wait_on_buffer(bh);
@@ -1176,8 +1048,21 @@ grow_buffers(struct block_device *bdev, sector_t block, int size)
} while ((size << sizebits) < PAGE_SIZE);
index = block >> sizebits;
- block = index << sizebits;
+ /*
+ * Check for a block which wants to lie outside our maximum possible
+ * pagecache index. (this comparison is done using sector_t types).
+ */
+ if (unlikely(index != block >> sizebits)) {
+ char b[BDEVNAME_SIZE];
+
+ printk(KERN_ERR "%s: requested out-of-range block %llu for "
+ "device %s\n",
+ __FUNCTION__, (unsigned long long)block,
+ bdevname(bdev, b));
+ return -EIO;
+ }
+ block = index << sizebits;
/* Create a page with the proper size buffers.. */
page = grow_dev_page(bdev, block, index, size);
if (!page)
@@ -1204,12 +1089,16 @@ __getblk_slow(struct block_device *bdev, sector_t block, int size)
for (;;) {
struct buffer_head * bh;
+ int ret;
bh = __find_get_block(bdev, block, size);
if (bh)
return bh;
- if (!grow_buffers(bdev, block, size))
+ ret = grow_buffers(bdev, block, size);
+ if (ret < 0)
+ return NULL;
+ if (ret == 0)
free_more_memory();
}
}
@@ -1284,6 +1173,7 @@ void __bforget(struct buffer_head *bh)
spin_lock(&buffer_mapping->private_lock);
list_del_init(&bh->b_assoc_buffers);
+ bh->b_assoc_map = NULL;
spin_unlock(&buffer_mapping->private_lock);
}
__brelse(bh);
@@ -1551,35 +1441,6 @@ static void discard_buffer(struct buffer_head * bh)
}
/**
- * try_to_release_page() - release old fs-specific metadata on a page
- *
- * @page: the page which the kernel is trying to free
- * @gfp_mask: memory allocation flags (and I/O mode)
- *
- * The address_space is to try to release any data against the page
- * (presumably at page->private). If the release was successful, return `1'.
- * Otherwise return zero.
- *
- * The @gfp_mask argument specifies whether I/O may be performed to release
- * this page (__GFP_IO), and whether the call may block (__GFP_WAIT).
- *
- * NOTE: @gfp_mask may go away, and this function may become non-blocking.
- */
-int try_to_release_page(struct page *page, gfp_t gfp_mask)
-{
- struct address_space * const mapping = page->mapping;
-
- BUG_ON(!PageLocked(page));
- if (PageWriteback(page))
- return 0;
-
- if (mapping && mapping->a_ops->releasepage)
- return mapping->a_ops->releasepage(page, gfp_mask);
- return try_to_free_buffers(page);
-}
-EXPORT_SYMBOL(try_to_release_page);
-
-/**
* block_invalidatepage - invalidate part of all of a buffer-backed page
*
* @page: the page which is affected
@@ -1630,14 +1491,6 @@ out:
}
EXPORT_SYMBOL(block_invalidatepage);
-void do_invalidatepage(struct page *page, unsigned long offset)
-{
- void (*invalidatepage)(struct page *, unsigned long);
- invalidatepage = page->mapping->a_ops->invalidatepage ? :
- block_invalidatepage;
- (*invalidatepage)(page, offset);
-}
-
/*
* We attach and possibly dirty the buffers atomically wrt
* __set_page_dirty_buffers() via private_lock. try_to_free_buffers
@@ -2008,6 +1861,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page,
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);
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
@@ -2514,6 +2368,7 @@ failed:
*/
kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr, 0, PAGE_CACHE_SIZE);
+ flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
SetPageUptodate(page);
set_page_dirty(page);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 3483d3cf8087..a885f46ca001 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -19,10 +19,30 @@
#include <linux/kobj_map.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
+#include <linux/backing-dev.h>
#ifdef CONFIG_KMOD
#include <linux/kmod.h>
#endif
+#include "internal.h"
+
+/*
+ * capabilities for /dev/mem, /dev/kmem and similar directly mappable character
+ * devices
+ * - permits shared-mmap for read, write and/or exec
+ * - does not permit private mmap in NOMMU mode (can't do COW)
+ * - no readahead or I/O queue unplugging required
+ */
+struct backing_dev_info directly_mappable_cdev_bdi = {
+ .capabilities = (
+#ifdef CONFIG_MMU
+ /* permit private copies of the data to be taken */
+ BDI_CAP_MAP_COPY |
+#endif
+ /* permit direct mmap, for read, write or exec */
+ BDI_CAP_MAP_DIRECT |
+ BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP),
+};
static struct kobj_map *cdev_map;
@@ -109,13 +129,31 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major > major ||
- ((*cp)->major == major && (*cp)->baseminor >= baseminor))
+ ((*cp)->major == major &&
+ (((*cp)->baseminor >= baseminor) ||
+ ((*cp)->baseminor + (*cp)->minorct > baseminor))))
break;
- if (*cp && (*cp)->major == major &&
- (*cp)->baseminor < baseminor + minorct) {
- ret = -EBUSY;
- goto out;
+
+ /* Check for overlapping minor ranges. */
+ if (*cp && (*cp)->major == major) {
+ int old_min = (*cp)->baseminor;
+ int old_max = (*cp)->baseminor + (*cp)->minorct - 1;
+ int new_min = baseminor;
+ int new_max = baseminor + minorct - 1;
+
+ /* New driver overlaps from the left. */
+ if (new_max >= old_min && new_max <= old_max) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* New driver overlaps from the right. */
+ if (new_min <= old_max && new_min >= old_min) {
+ ret = -EBUSY;
+ goto out;
+ }
}
+
cd->next = *cp;
*cp = cd;
mutex_unlock(&chrdevs_lock);
@@ -146,6 +184,15 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
return cd;
}
+/**
+ * register_chrdev_region() - register a range of device numbers
+ * @from: the first in the desired range of device numbers; must include
+ * the major number.
+ * @count: the number of consecutive device numbers required
+ * @name: the name of the device or driver.
+ *
+ * Return value is zero on success, a negative error code on failure.
+ */
int register_chrdev_region(dev_t from, unsigned count, const char *name)
{
struct char_device_struct *cd;
@@ -171,6 +218,17 @@ fail:
return PTR_ERR(cd);
}
+/**
+ * alloc_chrdev_region() - register a range of char device numbers
+ * @dev: output parameter for first assigned number
+ * @baseminor: first of the requested range of minor numbers
+ * @count: the number of minor numbers required
+ * @name: the name of the associated device or driver
+ *
+ * Allocates a range of char device numbers. The major number will be
+ * chosen dynamically, and returned (along with the first minor number)
+ * in @dev. Returns zero or a negative error code.
+ */
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
const char *name)
{
@@ -240,6 +298,15 @@ out2:
return err;
}
+/**
+ * unregister_chrdev_region() - return a range of device numbers
+ * @from: the first in the range of numbers to unregister
+ * @count: the number of device numbers to unregister
+ *
+ * This function will unregister a range of @count device numbers,
+ * starting with @from. The caller should normally be the one who
+ * allocated those numbers in the first place...
+ */
void unregister_chrdev_region(dev_t from, unsigned count)
{
dev_t to = from + count;
@@ -377,6 +444,16 @@ static int exact_lock(dev_t dev, void *data)
return cdev_get(p) ? 0 : -1;
}
+/**
+ * cdev_add() - add a char device to the system
+ * @p: the cdev structure for the device
+ * @dev: the first device number for which this device is responsible
+ * @count: the number of consecutive minor numbers corresponding to this
+ * device
+ *
+ * cdev_add() adds the device represented by @p to the system, making it
+ * live immediately. A negative error code is returned on failure.
+ */
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
p->dev = dev;
@@ -389,6 +466,13 @@ static void cdev_unmap(dev_t dev, unsigned count)
kobj_unmap(cdev_map, dev, count);
}
+/**
+ * cdev_del() - remove a cdev from the system
+ * @p: the cdev structure to be removed
+ *
+ * cdev_del() removes @p from the system, possibly freeing the structure
+ * itself.
+ */
void cdev_del(struct cdev *p)
{
cdev_unmap(p->dev, p->count);
@@ -417,6 +501,11 @@ static struct kobj_type ktype_cdev_dynamic = {
.release = cdev_dynamic_release,
};
+/**
+ * cdev_alloc() - allocate a cdev structure
+ *
+ * Allocates and returns a cdev structure, or NULL on failure.
+ */
struct cdev *cdev_alloc(void)
{
struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
@@ -428,6 +517,14 @@ struct cdev *cdev_alloc(void)
return p;
}
+/**
+ * cdev_init() - initialize a cdev structure
+ * @cdev: the structure to initialize
+ * @fops: the file_operations for this device
+ *
+ * Initializes @cdev, remembering @fops, making it ready to add to the
+ * system with cdev_add().
+ */
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
{
memset(cdev, 0, sizeof *cdev);
@@ -461,3 +558,4 @@ EXPORT_SYMBOL(cdev_del);
EXPORT_SYMBOL(cdev_add);
EXPORT_SYMBOL(register_chrdev);
EXPORT_SYMBOL(unregister_chrdev);
+EXPORT_SYMBOL(directly_mappable_cdev_bdi);
diff --git a/fs/cifs/README b/fs/cifs/README
index 5f0e1bd64fee..432e515431c4 100644
--- a/fs/cifs/README
+++ b/fs/cifs/README
@@ -269,7 +269,7 @@ A partial list of the supported mount options follows:
(gid) mount option is specified. For the uid (gid) of newly
created files and directories, ie files created since
the last mount of the server share, the expected uid
- (gid) is cached as as long as the inode remains in
+ (gid) is cached as long as the inode remains in
memory on the client. Also note that permission
checks (authorization checks) on accesses to a file occur
at the server, but there are cases in which an administrator
@@ -375,7 +375,7 @@ A partial list of the supported mount options follows:
the local process on newly created files, directories, and
devices (create, mkdir, mknod). If the CIFS Unix Extensions
are not negotiated, for newly created files and directories
- instead of using the default uid and gid specified on the
+ instead of using the default uid and gid specified on
the mount, cache the new file's uid and gid locally which means
that the uid for the file can change when the inode is
reloaded (or the user remounts the share).
@@ -440,7 +440,7 @@ A partial list of the supported mount options follows:
create device files and fifos in a format compatible with
Services for Unix (SFU). In addition retrieve bits 10-12
of the mode via the SETFILEBITS extended attribute (as
- SFU does). In the future the bottom 9 bits of the mode
+ SFU does). In the future the bottom 9 bits of the
mode also will be emulated using queries of the security
descriptor (ACL).
sign Must use packet signing (helps avoid unwanted data modification
diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h
index d0776ac2b804..5eff35d6e564 100644
--- a/fs/cifs/cifsacl.h
+++ b/fs/cifs/cifsacl.h
@@ -31,8 +31,8 @@ struct cifs_sid {
} __attribute__((packed));
/* everyone */
-extern const struct cifs_sid sid_everyone;
+/* extern const struct cifs_sid sid_everyone;*/
/* group users */
-extern const struct cifs_sid sid_user;
+/* extern const struct cifs_sid sid_user;*/
#endif /* _CIFSACL_H */
diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h
index 03e359b32861..152fa2dcfc6c 100644
--- a/fs/cifs/cifsencrypt.h
+++ b/fs/cifs/cifsencrypt.h
@@ -27,8 +27,6 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n);
/* smbdes.c */
extern void E_P16(unsigned char *p14, unsigned char *p16);
extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24);
-extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out);
-extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *);
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index c3ef1c0d0e68..84976cdbe713 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -63,6 +63,7 @@ extern struct task_struct * oplockThread; /* remove sparse warning */
struct task_struct * oplockThread = NULL;
extern struct task_struct * dnotifyThread; /* remove sparse warning */
struct task_struct * dnotifyThread = NULL;
+static struct super_operations cifs_super_ops;
unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE;
module_param(CIFSMaxBufSize, int, 0);
MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048");
@@ -198,10 +199,12 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
/* Only need to call the old QFSInfo if failed
on newer one */
if(rc)
- rc = CIFSSMBQFSInfo(xid, pTcon, buf);
+ if(pTcon->ses->capabilities & CAP_NT_SMBS)
+ rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */
- /* Old Windows servers do not support level 103, retry with level
- one if old server failed the previous call */
+ /* Some old Windows servers also do not support level 103, retry with
+ older level one if old server failed the previous call or we
+ bypassed it because we detected that this was an older LANMAN sess */
if(rc)
rc = SMBOldQFSInfo(xid, pTcon, buf);
/*
@@ -253,7 +256,6 @@ cifs_alloc_inode(struct super_block *sb)
file data or metadata */
cifs_inode->clientCanCacheRead = FALSE;
cifs_inode->clientCanCacheAll = FALSE;
- cifs_inode->vfs_inode.i_blksize = CIFS_MAX_MSGSIZE;
cifs_inode->vfs_inode.i_blkbits = 14; /* 2**14 = CIFS_MAX_MSGSIZE */
cifs_inode->vfs_inode.i_flags = S_NOATIME | S_NOCMTIME;
INIT_LIST_HEAD(&cifs_inode->openFileList);
@@ -436,13 +438,21 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags)
return;
}
+#ifdef CONFIG_CIFS_STATS2
+static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt)
+{
+ /* BB FIXME */
+ return 0;
+}
+#endif
+
static int cifs_remount(struct super_block *sb, int *flags, char *data)
{
*flags |= MS_NODIRATIME;
return 0;
}
-struct super_operations cifs_super_ops = {
+static struct super_operations cifs_super_ops = {
.read_inode = cifs_read_inode,
.put_super = cifs_put_super,
.statfs = cifs_statfs,
@@ -455,6 +465,9 @@ struct super_operations cifs_super_ops = {
.show_options = cifs_show_options,
.umount_begin = cifs_umount_begin,
.remount_fs = cifs_remount,
+#ifdef CONFIG_CIFS_STATS2
+ .show_stats = cifs_show_stats,
+#endif
};
static int
@@ -481,25 +494,13 @@ cifs_get_sb(struct file_system_type *fs_type,
return simple_set_mnt(mnt, sb);
}
-static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
-{
- struct inode *inode = file->f_dentry->d_inode;
- ssize_t written;
-
- written = generic_file_writev(file, iov, nr_segs, ppos);
- if (!CIFS_I(inode)->clientCanCacheAll)
- filemap_fdatawrite(inode->i_mapping);
- return written;
-}
-
-static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
+static ssize_t cifs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
ssize_t written;
- written = generic_file_aio_write(iocb, buf, count, pos);
+ written = generic_file_aio_write(iocb, iov, nr_segs, pos);
if (!CIFS_I(inode)->clientCanCacheAll)
filemap_fdatawrite(inode->i_mapping);
return written;
@@ -508,7 +509,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf,
static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
{
/* origin == SEEK_END => we must revalidate the cached file length */
- if (origin == 2) {
+ if (origin == SEEK_END) {
int retval = cifs_revalidate(file->f_dentry);
if (retval < 0)
return (loff_t)retval;
@@ -578,8 +579,6 @@ struct inode_operations cifs_symlink_inode_ops = {
const struct file_operations cifs_file_ops = {
.read = do_sync_read,
.write = do_sync_write,
- .readv = generic_file_readv,
- .writev = cifs_file_writev,
.aio_read = generic_file_aio_read,
.aio_write = cifs_file_aio_write,
.open = cifs_open,
@@ -621,8 +620,6 @@ const struct file_operations cifs_file_direct_ops = {
const struct file_operations cifs_file_nobrl_ops = {
.read = do_sync_read,
.write = do_sync_write,
- .readv = generic_file_readv,
- .writev = cifs_file_writev,
.aio_read = generic_file_aio_read,
.aio_write = cifs_file_aio_write,
.open = cifs_open,
@@ -699,8 +696,7 @@ cifs_init_inodecache(void)
static void
cifs_destroy_inodecache(void)
{
- if (kmem_cache_destroy(cifs_inode_cachep))
- printk(KERN_WARNING "cifs_inode_cache: error freeing\n");
+ kmem_cache_destroy(cifs_inode_cachep);
}
static int
@@ -778,13 +774,9 @@ static void
cifs_destroy_request_bufs(void)
{
mempool_destroy(cifs_req_poolp);
- if (kmem_cache_destroy(cifs_req_cachep))
- printk(KERN_WARNING
- "cifs_destroy_request_cache: error not all structures were freed\n");
+ kmem_cache_destroy(cifs_req_cachep);
mempool_destroy(cifs_sm_req_poolp);
- if (kmem_cache_destroy(cifs_sm_req_cachep))
- printk(KERN_WARNING
- "cifs_destroy_request_cache: cifs_small_rq free error\n");
+ kmem_cache_destroy(cifs_sm_req_cachep);
}
static int
@@ -819,13 +811,8 @@ static void
cifs_destroy_mids(void)
{
mempool_destroy(cifs_mid_poolp);
- if (kmem_cache_destroy(cifs_mid_cachep))
- printk(KERN_WARNING
- "cifs_destroy_mids: error not all structures were freed\n");
-
- if (kmem_cache_destroy(cifs_oplock_cachep))
- printk(KERN_WARNING
- "error not all oplock structures were freed\n");
+ kmem_cache_destroy(cifs_mid_cachep);
+ kmem_cache_destroy(cifs_oplock_cachep);
}
static int cifs_oplock_thread(void * dummyarg)
@@ -930,7 +917,7 @@ init_cifs(void)
#ifdef CONFIG_PROC_FS
cifs_proc_init();
#endif
- INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */
+/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */
INIT_LIST_HEAD(&GlobalSMBSessionList);
INIT_LIST_HEAD(&GlobalTreeConnectionList);
INIT_LIST_HEAD(&GlobalOplock_Q);
@@ -958,6 +945,7 @@ init_cifs(void)
GlobalCurrentXid = 0;
GlobalTotalActiveXid = 0;
GlobalMaxActiveXid = 0;
+ memset(Local_System_Name, 0, 15);
rwlock_init(&GlobalSMBSeslock);
spin_lock_init(&GlobalMid_Lock);
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index bea875d9a46a..a243f779b363 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -36,7 +36,7 @@ extern const struct address_space_operations cifs_addr_ops;
extern const struct address_space_operations cifs_addr_ops_smallbuf;
/* Functions related to super block operations */
-extern struct super_operations cifs_super_ops;
+/* extern struct super_operations cifs_super_ops;*/
extern void cifs_read_inode(struct inode *);
extern void cifs_delete_inode(struct inode *);
/* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index b24006c47df1..74d3ccbb103b 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -153,7 +153,7 @@ struct TCP_Server_Info {
char sessid[4]; /* unique token id for this session */
/* (returned on Negotiate */
int capabilities; /* allow selective disabling of caps by smb sess */
- __u16 timeZone;
+ int timeAdj; /* Adjust for difference in server time zone in sec */
__u16 CurrentMid; /* multiplex id - rotating counter */
char cryptKey[CIFS_CRYPTO_KEY_SIZE];
/* 16th byte of RFC1001 workstation name is always null */
@@ -203,9 +203,14 @@ struct cifsSesInfo {
char * domainName;
char * password;
};
-/* session flags */
+/* no more than one of the following three session flags may be set */
#define CIFS_SES_NT4 1
-
+#define CIFS_SES_OS2 2
+#define CIFS_SES_W9X 4
+/* following flag is set for old servers such as OS2 (and Win95?)
+ which do not negotiate NTLM or POSIX dialects, but instead
+ negotiate one of the older LANMAN dialects */
+#define CIFS_SES_LANMAN 8
/*
* there is one of these for each connection to a resource on a particular
* session
@@ -512,7 +517,8 @@ require use of the stronger protocol */
* This list helps improve performance and eliminate the messages indicating
* that we had a communications error talking to the server in this list.
*/
-GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */
+/* Feature not supported */
+/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */
/*
* The following is a hash table of all the users we know about.
@@ -568,7 +574,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEnabled;
GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent
with more secure ntlmssp2 challenge/resp */
GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */
-GLOBAL_EXTERN unsigned int secFlags;
GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/
GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */
GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 81df2bf8e75a..6df9dadba647 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -26,7 +26,8 @@
#ifdef CONFIG_CIFS_WEAK_PW_HASH
#define LANMAN_PROT 0
-#define CIFS_PROT 1
+#define LANMAN2_PROT 1
+#define CIFS_PROT 2
#else
#define CIFS_PROT 0
#endif
@@ -408,6 +409,8 @@ typedef struct negotiate_req {
/* Dialect index is 13 for LANMAN */
+#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */
+
typedef struct lanman_neg_rsp {
struct smb_hdr hdr; /* wct = 13 */
__le16 DialectIndex;
@@ -417,7 +420,10 @@ typedef struct lanman_neg_rsp {
__le16 MaxNumberVcs;
__le16 RawMode;
__le32 SessionKey;
- __le32 ServerTime;
+ struct {
+ __le16 Time;
+ __le16 Date;
+ } __attribute__((packed)) SrvTime;
__le16 ServerTimeZone;
__le16 EncryptionKeyLength;
__le16 Reserved;
@@ -674,7 +680,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on
typedef struct smb_com_close_req {
struct smb_hdr hdr; /* wct = 3 */
__u16 FileID;
- __u32 LastWriteTime; /* should be zero */
+ __u32 LastWriteTime; /* should be zero or -1 */
__u16 ByteCount; /* 0 */
} __attribute__((packed)) CLOSE_REQ;
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index b35c55c3c8bb..f1f8225102f0 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -50,12 +50,12 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *,
struct kvec *, int /* nvec to send */,
int * /* type of buf returned */ , const int long_op);
-extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *,
+extern int SendReceiveBlockingLock(const unsigned int /* xid */ ,
+ struct cifsTconInfo *,
struct smb_hdr * /* input */ ,
struct smb_hdr * /* out */ ,
int * /* bytes returned */);
-extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid);
-extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length);
+extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length);
extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *);
extern int is_size_safe_to_change(struct cifsInodeInfo *);
extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *);
@@ -80,6 +80,9 @@ extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16,
extern void DeleteOplockQEntry(struct oplock_q_entry *);
extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ );
extern u64 cifs_UnixTimeToNT(struct timespec);
+extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
+extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
+
extern int cifs_get_inode_info(struct inode **pinode,
const unsigned char *search_path,
FILE_ALL_INFO * pfile_info,
@@ -116,6 +119,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon,
extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * findData,
+ int legacy /* whether to use old info level */,
const struct nls_table *nls_codepage, int remap);
extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
@@ -279,8 +283,6 @@ extern void sesInfoFree(struct cifsSesInfo *);
extern struct cifsTconInfo *tconInfoAlloc(void);
extern void tconInfoFree(struct cifsTconInfo *);
-extern int cifs_reconnect(struct TCP_Server_Info *server);
-
extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *);
extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *,
__u32 *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 075d8fb3d376..098790eb2aa1 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -46,6 +46,7 @@ static struct {
} protocols[] = {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
{LANMAN_PROT, "\2LM1.2X002"},
+ {LANMAN2_PROT, "\2LANMAN2.1"},
#endif /* weak password hashing for legacy clients */
{CIFS_PROT, "\2NT LM 0.12"},
{POSIX_PROT, "\2POSIX 2"},
@@ -58,6 +59,7 @@ static struct {
} protocols[] = {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
{LANMAN_PROT, "\2LM1.2X002"},
+ {LANMAN2_PROT, "\2LANMAN2.1"},
#endif /* weak password hashing for legacy clients */
{CIFS_PROT, "\2NT LM 0.12"},
{BAD_PROT, "\2"}
@@ -67,13 +69,13 @@ static struct {
/* define the number of elements in the cifs dialect array */
#ifdef CONFIG_CIFS_POSIX
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-#define CIFS_NUM_PROT 3
+#define CIFS_NUM_PROT 4
#else
#define CIFS_NUM_PROT 2
#endif /* CIFS_WEAK_PW_HASH */
#else /* not posix */
#ifdef CONFIG_CIFS_WEAK_PW_HASH
-#define CIFS_NUM_PROT 2
+#define CIFS_NUM_PROT 3
#else
#define CIFS_NUM_PROT 1
#endif /* CONFIG_CIFS_WEAK_PW_HASH */
@@ -397,6 +399,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
struct TCP_Server_Info * server;
u16 count;
unsigned int secFlags;
+ u16 dialect;
if(ses->server)
server = ses->server;
@@ -436,9 +439,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
if (rc != 0)
goto neg_err_exit;
- cFYI(1,("Dialect: %d", pSMBr->DialectIndex));
+ dialect = le16_to_cpu(pSMBr->DialectIndex);
+ cFYI(1,("Dialect: %d", dialect));
/* Check wct = 1 error case */
- if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) {
+ if((pSMBr->hdr.WordCount < 13) || (dialect == BAD_PROT)) {
/* core returns wct = 1, but we do not ask for core - otherwise
small wct just comes when dialect index is -1 indicating we
could not negotiate a common dialect */
@@ -446,7 +450,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
goto neg_err_exit;
#ifdef CONFIG_CIFS_WEAK_PW_HASH
} else if((pSMBr->hdr.WordCount == 13)
- && (pSMBr->DialectIndex == LANMAN_PROT)) {
+ && ((dialect == LANMAN_PROT)
+ || (dialect == LANMAN2_PROT))) {
+ __s16 tmp;
struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr;
if((secFlags & CIFSSEC_MAY_LANMAN) ||
@@ -472,12 +478,44 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
server->maxRw = 0;/* we do not need to use raw anyway */
server->capabilities = CAP_MPX_MODE;
}
- server->timeZone = le16_to_cpu(rsp->ServerTimeZone);
+ tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
+ if (tmp == -1) {
+ /* OS/2 often does not set timezone therefore
+ * we must use server time to calc time zone.
+ * Could deviate slightly from the right zone.
+ * Smallest defined timezone difference is 15 minutes
+ * (i.e. Nepal). Rounding up/down is done to match
+ * this requirement.
+ */
+ int val, seconds, remain, result;
+ struct timespec ts, utc;
+ utc = CURRENT_TIME;
+ ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date),
+ le16_to_cpu(rsp->SrvTime.Time));
+ cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d",
+ (int)ts.tv_sec, (int)utc.tv_sec,
+ (int)(utc.tv_sec - ts.tv_sec)));
+ val = (int)(utc.tv_sec - ts.tv_sec);
+ seconds = val < 0 ? -val : val;
+ result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ;
+ remain = seconds % MIN_TZ_ADJ;
+ if(remain >= (MIN_TZ_ADJ / 2))
+ result += MIN_TZ_ADJ;
+ if(val < 0)
+ result = - result;
+ server->timeAdj = result;
+ } else {
+ server->timeAdj = (int)tmp;
+ server->timeAdj *= 60; /* also in seconds */
+ }
+ cFYI(1,("server->timeAdj: %d seconds", server->timeAdj));
+
/* BB get server time for time conversions and add
code to use it and timezone since this is not UTC */
- if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
+ if (rsp->EncryptionKeyLength ==
+ cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) {
memcpy(server->cryptKey, rsp->EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
} else if (server->secMode & SECMODE_PW_ENCRYPT) {
@@ -531,7 +569,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
cFYI(0, ("Max buf = %d", ses->server->maxBuf));
GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
server->capabilities = le32_to_cpu(pSMBr->Capabilities);
- server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone);
+ server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone);
+ server->timeAdj *= 60;
if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) {
memcpy(server->cryptKey, pSMBr->u.EncryptionKey,
CIFS_CRYPTO_KEY_SIZE);
@@ -1617,7 +1656,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id)
pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */
pSMB->FileID = (__u16) smb_file_id;
- pSMB->LastWriteTime = 0;
+ pSMB->LastWriteTime = 0xFFFFFFFF;
pSMB->ByteCount = 0;
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
(struct smb_hdr *) pSMBr, &bytes_returned, 0);
@@ -2773,9 +2812,11 @@ GetExtAttrOut:
/* security id for everyone */
-const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
+const static struct cifs_sid sid_everyone =
+ {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}};
/* group users */
-const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
+const static struct cifs_sid sid_user =
+ {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}};
/* Convert CIFS ACL to POSIX form */
static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len)
@@ -2856,7 +2897,6 @@ qsec_out:
return rc;
}
-
/* Legacy Query Path Information call for lookup to old servers such
as Win9x/WinME */
int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon,
@@ -2898,7 +2938,16 @@ QInfRetry:
if (rc) {
cFYI(1, ("Send error in QueryInfo = %d", rc));
} else if (pFinfo) { /* decode response */
+ struct timespec ts;
+ __u32 time = le32_to_cpu(pSMBr->last_write_time);
+ /* BB FIXME - add time zone adjustment BB */
memset(pFinfo, 0, sizeof(FILE_ALL_INFO));
+ ts.tv_nsec = 0;
+ ts.tv_sec = time;
+ /* decode time fields */
+ pFinfo->ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(ts));
+ pFinfo->LastWriteTime = pFinfo->ChangeTime;
+ pFinfo->LastAccessTime = 0;
pFinfo->AllocationSize =
cpu_to_le64(le32_to_cpu(pSMBr->size));
pFinfo->EndOfFile = pFinfo->AllocationSize;
@@ -2922,6 +2971,7 @@ int
CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon,
const unsigned char *searchName,
FILE_ALL_INFO * pFindData,
+ int legacy /* old style infolevel */,
const struct nls_table *nls_codepage, int remap)
{
/* level 263 SMB_QUERY_FILE_ALL_INFO */
@@ -2970,7 +3020,10 @@ QPathInfoRetry:
byte_count = params + 1 /* pad */ ;
pSMB->TotalParameterCount = cpu_to_le16(params);
pSMB->ParameterCount = pSMB->TotalParameterCount;
- pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
+ if(legacy)
+ pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD);
+ else
+ pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO);
pSMB->Reserved4 = 0;
pSMB->hdr.smb_buf_length += byte_count;
pSMB->ByteCount = cpu_to_le16(byte_count);
@@ -2982,13 +3035,24 @@ QPathInfoRetry:
} else { /* decode response */
rc = validate_t2((struct smb_t2_rsp *)pSMBr);
- if (rc || (pSMBr->ByteCount < 40))
+ if (rc) /* BB add auto retry on EOPNOTSUPP? */
+ rc = -EIO;
+ else if (!legacy && (pSMBr->ByteCount < 40))
rc = -EIO; /* bad smb */
+ else if(legacy && (pSMBr->ByteCount < 24))
+ rc = -EIO; /* 24 or 26 expected but we do not read last field */
else if (pFindData){
+ int size;
__u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset);
+ if(legacy) /* we do not read the last field, EAsize, fortunately
+ since it varies by subdialect and on Set vs. Get, is
+ two bytes or 4 bytes depending but we don't care here */
+ size = sizeof(FILE_INFO_STANDARD);
+ else
+ size = sizeof(FILE_ALL_INFO);
memcpy((char *) pFindData,
(char *) &pSMBr->hdr.Protocol +
- data_offset, sizeof (FILE_ALL_INFO));
+ data_offset, size);
} else
rc = -ENOMEM;
}
@@ -3613,6 +3677,14 @@ getDFSRetry:
strncpy(pSMB->RequestFileName, searchName, name_len);
}
+ if(ses->server) {
+ if(ses->server->secMode &
+ (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+ pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+ }
+
+ pSMB->hdr.Uid = ses->Suid;
+
params = 2 /* level */ + name_len /*includes null */ ;
pSMB->TotalDataCount = 0;
pSMB->DataCount = 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 0e9ba0b9d71e..4093d5332930 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -109,7 +109,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
* wake up waiters on reconnection? - (not needed currently)
*/
-int
+static int
cifs_reconnect(struct TCP_Server_Info *server)
{
int rc = 0;
@@ -771,13 +771,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
separator[0] = ',';
separator[1] = 0;
- memset(vol->source_rfc1001_name,0x20,15);
- for(i=0;i < strnlen(system_utsname.nodename,15);i++) {
- /* does not have to be a perfect mapping since the field is
- informational, only used for servers that do not support
- port 445 and it can be overridden at mount time */
- vol->source_rfc1001_name[i] =
- toupper(system_utsname.nodename[i]);
+ if (Local_System_Name[0] != 0)
+ memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+ else {
+ char *nodename = utsname()->nodename;
+ int n = strnlen(nodename,15);
+ memset(vol->source_rfc1001_name,0x20,15);
+ for(i=0 ; i < n ; i++) {
+ /* does not have to be perfect mapping since field is
+ informational, only used for servers that do not support
+ port 445 and it can be overridden at mount time */
+ vol->source_rfc1001_name[i] = toupper(nodename[i]);
+ }
}
vol->source_rfc1001_name[15] = 0;
/* null target name indicates to use *SMBSERVR default called name
@@ -2153,7 +2158,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release,
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2;
@@ -2180,8 +2185,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
}
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, system_utsname.release);
- bcc_ptr += strlen(system_utsname.release) + 1;
+ strcpy(bcc_ptr, utsname()->release);
+ bcc_ptr += strlen(utsname()->release) + 1;
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
}
@@ -2445,7 +2450,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
+ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2; /* null terminate Linux version */
@@ -2462,8 +2467,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
} else { /* ASCII */
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, system_utsname.release);
- bcc_ptr += strlen(system_utsname.release) + 1;
+ strcpy(bcc_ptr, utsname()->release);
+ bcc_ptr += strlen(utsname()->release) + 1;
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
bcc_ptr++; /* empty domain field */
@@ -2836,7 +2841,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
32, nls_codepage);
bcc_ptr += 2 * bytes_returned;
bytes_returned =
- cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32,
+ cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32,
nls_codepage);
bcc_ptr += 2 * bytes_returned;
bcc_ptr += 2; /* null term version string */
@@ -2888,8 +2893,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, system_utsname.release);
- bcc_ptr += strlen(system_utsname.release) + 1;
+ strcpy(bcc_ptr, utsname()->release);
+ bcc_ptr += strlen(utsname()->release) + 1;
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
bcc_ptr++; /* null domain */
@@ -3215,7 +3220,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
}
/* else do not bother copying these informational fields */
}
- if(smb_buffer_response->WordCount == 3)
+ if((smb_buffer_response->WordCount == 3) ||
+ (smb_buffer_response->WordCount == 7))
+ /* field is in same location */
tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
else
tcon->Flags = 0;
@@ -3312,19 +3319,21 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
first_time = 1;
}
if (!rc) {
+ pSesInfo->flags = 0;
pSesInfo->capabilities = pSesInfo->server->capabilities;
if(linuxExtEnabled == 0)
pSesInfo->capabilities &= (~CAP_UNIX);
/* pSesInfo->sequence_number = 0;*/
- cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
+ cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
pSesInfo->server->secMode,
pSesInfo->server->capabilities,
- pSesInfo->server->timeZone));
+ pSesInfo->server->timeAdj));
if(experimEnabled < 2)
rc = CIFS_SessSetup(xid, pSesInfo,
first_time, nls_info);
else if (extended_security
- && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+ && (pSesInfo->capabilities
+ & CAP_EXTENDED_SECURITY)
&& (pSesInfo->server->secType == NTLMSSP)) {
rc = -EOPNOTSUPP;
} else if (extended_security
@@ -3338,7 +3347,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
if (!rc) {
if(ntlmv2_flag) {
char * v2_response;
- cFYI(1,("Can use more secure NTLM version 2 password hash"));
+ cFYI(1,("more secure NTLM ver2 hash"));
if(CalcNTLMv2_partial_mac_key(pSesInfo,
nls_info)) {
rc = -ENOMEM;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index ddb012a68023..976a691c5a68 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -25,7 +25,6 @@
#include <linux/backing-dev.h>
#include <linux/stat.h>
#include <linux/fcntl.h>
-#include <linux/mpage.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
#include <linux/smp_lock.h>
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index b88147c1dc27..35d54bb0869a 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -19,7 +19,6 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/fs.h>
-#include <linux/buffer_head.h>
#include <linux/stat.h>
#include <linux/pagemap.h>
#include <asm/div64.h>
@@ -338,6 +337,7 @@ int cifs_get_inode_info(struct inode **pinode,
pfindData = (FILE_ALL_INFO *)buf;
/* could do find first instead but this returns more info */
rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData,
+ 0 /* not legacy */,
cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
CIFS_MOUNT_MAP_SPECIAL_CHR);
/* BB optimize code so we do not make the above call
@@ -385,8 +385,10 @@ int cifs_get_inode_info(struct inode **pinode,
/* get new inode */
if (*pinode == NULL) {
*pinode = new_inode(sb);
- if (*pinode == NULL)
+ if (*pinode == NULL) {
+ kfree(buf);
return -ENOMEM;
+ }
/* Is an i_ino of zero legal? Can we use that to check
if the server supports returning inode numbers? Are
there other sanity checks we can use to ensure that
@@ -432,8 +434,11 @@ int cifs_get_inode_info(struct inode **pinode,
(pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/
/* Linux can not store file creation time so ignore it */
- inode->i_atime =
- cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime));
+ if(pfindData->LastAccessTime)
+ inode->i_atime = cifs_NTtimeToUnix
+ (le64_to_cpu(pfindData->LastAccessTime));
+ else /* do not need to use current_fs_time - time not stored */
+ inode->i_atime = CURRENT_TIME;
inode->i_mtime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime));
inode->i_ctime =
@@ -591,7 +596,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
if (!rc) {
if (direntry->d_inode)
- direntry->d_inode->i_nlink--;
+ drop_nlink(direntry->d_inode);
} else if (rc == -ENOENT) {
d_drop(direntry);
} else if (rc == -ETXTBSY) {
@@ -610,7 +615,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
if (direntry->d_inode)
- direntry->d_inode->i_nlink--;
+ drop_nlink(direntry->d_inode);
}
} else if (rc == -EACCES) {
/* try only if r/o attribute set in local lookup data? */
@@ -664,7 +669,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) {
if (direntry->d_inode)
- direntry->d_inode->i_nlink--;
+ drop_nlink(direntry->d_inode);
} else if (rc == -ETXTBSY) {
int oplock = FALSE;
__u16 netfid;
@@ -685,7 +690,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry)
CIFS_MOUNT_MAP_SPECIAL_CHR);
CIFSSMBClose(xid, pTcon, netfid);
if (direntry->d_inode)
- direntry->d_inode->i_nlink--;
+ drop_nlink(direntry->d_inode);
}
/* BB if rc = -ETXTBUSY goto the rename logic BB */
}
@@ -736,7 +741,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
cFYI(1, ("cifs_mkdir returned 0x%x", rc));
d_drop(direntry);
} else {
- inode->i_nlink++;
+ inc_nlink(inode);
if (pTcon->ses->capabilities & CAP_UNIX)
rc = cifs_get_inode_info_unix(&newinode, full_path,
inode->i_sb,xid);
@@ -817,9 +822,9 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
if (!rc) {
- inode->i_nlink--;
+ drop_nlink(inode);
i_size_write(direntry->d_inode,0);
- direntry->d_inode->i_nlink = 0;
+ clear_nlink(direntry->d_inode);
}
cifsInode = CIFS_I(direntry->d_inode);
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c
index b0ea6687ab55..e34c7db00f6f 100644
--- a/fs/cifs/ioctl.c
+++ b/fs/cifs/ioctl.c
@@ -22,7 +22,6 @@
*/
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
#include "cifspdu.h"
#include "cifsglob.h"
#include "cifsproto.h"
@@ -74,7 +73,7 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
}
break;
#ifdef CONFIG_CIFS_POSIX
- case EXT2_IOC_GETFLAGS:
+ case FS_IOC_GETFLAGS:
if(CIFS_UNIX_EXTATTR_CAP & caps) {
if (pSMBFile == NULL)
break;
@@ -82,12 +81,12 @@ int cifs_ioctl (struct inode * inode, struct file * filep,
&ExtAttrBits, &ExtAttrMask);
if(rc == 0)
rc = put_user(ExtAttrBits &
- EXT2_FL_USER_VISIBLE,
+ FS_FL_USER_VISIBLE,
(int __user *)arg);
}
break;
- case EXT2_IOC_SETFLAGS:
+ case FS_IOC_SETFLAGS:
if(CIFS_UNIX_EXTATTR_CAP & caps) {
if(get_user(ExtAttrBits,(int __user *)arg)) {
rc = -EFAULT;
diff --git a/fs/cifs/link.c b/fs/cifs/link.c
index a57f5d6e6213..0bee8b7e521a 100644
--- a/fs/cifs/link.c
+++ b/fs/cifs/link.c
@@ -254,7 +254,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen)
tmpbuffer,
len - 1,
cifs_sb->local_nls);
- else {
+ else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) {
+ cERROR(1,("SFU style symlinks not implemented yet"));
+ /* add open and read as in fs/cifs/inode.c */
+
+ } else {
rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ,
OPEN_REPARSE_POINT,&fid, &oplock, NULL,
cifs_sb->local_nls,
diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c
index 7aa23490541f..ccebf9b7eb86 100644
--- a/fs/cifs/md5.c
+++ b/fs/cifs/md5.c
@@ -252,10 +252,11 @@ MD5Transform(__u32 buf[4], __u32 const in[16])
buf[3] += d;
}
+#if 0 /* currently unused */
/***********************************************************************
the rfc 2104 version of hmac_md5 initialisation.
***********************************************************************/
-void
+static void
hmac_md5_init_rfc2104(unsigned char *key, int key_len,
struct HMACMD5Context *ctx)
{
@@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len,
MD5Init(&ctx->ctx);
MD5Update(&ctx->ctx, ctx->k_ipad, 64);
}
+#endif
/***********************************************************************
the microsoft version of hmac_md5 initialisation.
@@ -350,7 +352,8 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx)
single function to calculate an HMAC MD5 digest from data.
use the microsoft hmacmd5 init method because the key is 16 bytes.
************************************************************/
-void
+#if 0 /* currently unused */
+static void
hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
unsigned char *digest)
{
@@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
}
hmac_md5_final(digest, &ctx);
}
+#endif
diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h
index 00e1c5394fe1..f7d4f4197bac 100644
--- a/fs/cifs/md5.h
+++ b/fs/cifs/md5.h
@@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context);
/* The following definitions come from lib/hmacmd5.c */
-void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
- struct HMACMD5Context *ctx);
+/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len,
+ struct HMACMD5Context *ctx);*/
void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len,
struct HMACMD5Context *ctx);
void hmac_md5_update(const unsigned char *text, int text_len,
struct HMACMD5Context *ctx);
void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx);
-void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
- unsigned char *digest);
+/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len,
+ unsigned char *digest);*/
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 22c937e5884f..bbc9cd34b6ea 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -389,7 +389,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,
return;
}
-int
+static int
checkSMBhdr(struct smb_hdr *smb, __u16 mid)
{
/* Make sure that this really is an SMB, that it is a response,
@@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid)
}
int
-checkSMB(struct smb_hdr *smb, __u16 mid, int length)
+checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length)
{
__u32 len = smb->smb_buf_length;
__u32 clc_len; /* calculated length */
cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len));
- if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) ||
- (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) {
- if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) {
- if (((unsigned int)length >=
- sizeof (struct smb_hdr) - 1)
+
+ if (length < 2 + sizeof (struct smb_hdr)) {
+ if ((length >= sizeof (struct smb_hdr) - 1)
&& (smb->Status.CifsError != 0)) {
- smb->WordCount = 0;
- /* some error cases do not return wct and bcc */
+ smb->WordCount = 0;
+ /* some error cases do not return wct and bcc */
+ return 0;
+ } else if ((length == sizeof(struct smb_hdr) + 1) &&
+ (smb->WordCount == 0)) {
+ char * tmp = (char *)smb;
+ /* Need to work around a bug in two servers here */
+ /* First, check if the part of bcc they sent was zero */
+ if (tmp[sizeof(struct smb_hdr)] == 0) {
+ /* some servers return only half of bcc
+ * on simple responses (wct, bcc both zero)
+ * in particular have seen this on
+ * ulogoffX and FindClose. This leaves
+ * one byte of bcc potentially unitialized
+ */
+ /* zero rest of bcc */
+ tmp[sizeof(struct smb_hdr)+1] = 0;
return 0;
- } else {
- cERROR(1, ("Length less than smb header size"));
}
+ cERROR(1,("rcvd invalid byte count (bcc)"));
+ } else {
+ cERROR(1, ("Length less than smb header size"));
}
- if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)
- cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
+ return 1;
+ }
+ if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) {
+ cERROR(1, ("smb length greater than MaxBufSize, mid=%d",
smb->Mid));
return 1;
}
@@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length)
return 1;
clc_len = smbCalcSize_LE(smb);
- if(4 + len != (unsigned int)length) {
+ if(4 + len != length) {
cERROR(1, ("Length read does not match RFC1001 length %d",len));
return 1;
}
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index ce87550e918f..992e80edc720 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -909,3 +909,61 @@ cifs_UnixTimeToNT(struct timespec t)
/* Convert to 100ns intervals and then add the NTFS time offset. */
return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET;
}
+
+static int total_days_of_prev_months[] =
+{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
+
+
+__le64 cnvrtDosCifsTm(__u16 date, __u16 time)
+{
+ return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time)));
+}
+
+struct timespec cnvrtDosUnixTm(__u16 date, __u16 time)
+{
+ struct timespec ts;
+ int sec, min, days, month, year;
+ SMB_TIME * st = (SMB_TIME *)&time;
+ SMB_DATE * sd = (SMB_DATE *)&date;
+
+ cFYI(1,("date %d time %d",date, time));
+
+ sec = 2 * st->TwoSeconds;
+ min = st->Minutes;
+ if((sec > 59) || (min > 59))
+ cERROR(1,("illegal time min %d sec %d", min, sec));
+ sec += (min * 60);
+ sec += 60 * 60 * st->Hours;
+ if(st->Hours > 24)
+ cERROR(1,("illegal hours %d",st->Hours));
+ days = sd->Day;
+ month = sd->Month;
+ if((days > 31) || (month > 12))
+ cERROR(1,("illegal date, month %d day: %d", month, days));
+ month -= 1;
+ days += total_days_of_prev_months[month];
+ days += 3652; /* account for difference in days between 1980 and 1970 */
+ year = sd->Year;
+ days += year * 365;
+ days += (year/4); /* leap year */
+ /* generalized leap year calculation is more complex, ie no leap year
+ for years/100 except for years/400, but since the maximum number for DOS
+ year is 2**7, the last year is 1980+127, which means we need only
+ consider 2 special case years, ie the years 2000 and 2100, and only
+ adjust for the lack of leap year for the year 2100, as 2000 was a
+ leap year (divisable by 400) */
+ if(year >= 120) /* the year 2100 */
+ days = days - 1; /* do not count leap year for the year 2100 */
+
+ /* adjust for leap year where we are still before leap day */
+ if(year != 120)
+ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0);
+ sec += 24 * 60 * 60 * days;
+
+ ts.tv_sec = sec;
+
+ /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */
+
+ ts.tv_nsec = 0;
+ return ts;
+}
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 9aeb58a7d369..b5b0a2a41bef 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -106,6 +106,17 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
return rc;
}
+static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode)
+{
+ if((tcon) && (tcon->ses) && (tcon->ses->server)) {
+ inode->i_ctime.tv_sec += tcon->ses->server->timeAdj;
+ inode->i_mtime.tv_sec += tcon->ses->server->timeAdj;
+ inode->i_atime.tv_sec += tcon->ses->server->timeAdj;
+ }
+ return;
+}
+
+
static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
char * buf, int *pobject_type, int isNewInode)
{
@@ -135,16 +146,23 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
tmp_inode->i_ctime =
cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime));
} else { /* legacy, OS2 and DOS style */
+/* struct timespec ts;*/
FIND_FILE_STANDARD_INFO * pfindData =
(FIND_FILE_STANDARD_INFO *)buf;
+ tmp_inode->i_mtime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastWriteDate),
+ le16_to_cpu(pfindData->LastWriteTime));
+ tmp_inode->i_atime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastAccessDate),
+ le16_to_cpu(pfindData->LastAccessTime));
+ tmp_inode->i_ctime = cnvrtDosUnixTm(
+ le16_to_cpu(pfindData->LastWriteDate),
+ le16_to_cpu(pfindData->LastWriteTime));
+ AdjustForTZ(cifs_sb->tcon, tmp_inode);
attr = le16_to_cpu(pfindData->Attributes);
allocation_size = le32_to_cpu(pfindData->AllocationSize);
end_of_file = le32_to_cpu(pfindData->DataSize);
- tmp_inode->i_atime = CURRENT_TIME;
- /* tmp_inode->i_mtime = BB FIXME - add dos time handling
- tmp_inode->i_ctime = 0; BB FIXME */
-
}
/* Linux can not store file creation time unfortunately so ignore it */
@@ -216,10 +234,9 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
if (allocation_size < end_of_file)
cFYI(1, ("May be sparse file, allocation less than file size"));
- cFYI(1, ("File Size %ld and blocks %llu and blocksize %ld",
+ cFYI(1, ("File Size %ld and blocks %llu",
(unsigned long)tmp_inode->i_size,
- (unsigned long long)tmp_inode->i_blocks,
- tmp_inode->i_blksize));
+ (unsigned long long)tmp_inode->i_blocks));
if (S_ISREG(tmp_inode->i_mode)) {
cFYI(1, ("File inode"));
tmp_inode->i_op = &cifs_file_inode_ops;
@@ -939,6 +956,7 @@ static int cifs_save_resume_key(const char *current_entry,
filename = &pFindData->FileName[0];
/* one byte length, no name conversion */
len = (unsigned int)pFindData->FileNameLength;
+ cifsFile->srch_inf.resume_key = pFindData->ResumeKey;
} else {
cFYI(1,("Unknown findfirst level %d",level));
return -EINVAL;
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index d1705ab8136e..a8a083543ba0 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -111,7 +111,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
nls_cp);
bcc_ptr += 2 * bytes_ret;
- bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+ bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release,
32, nls_cp);
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* trailing null */
@@ -158,8 +158,8 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, system_utsname.release);
- bcc_ptr += strlen(system_utsname.release) + 1;
+ strcpy(bcc_ptr, init_utsname()->release);
+ bcc_ptr += strlen(init_utsname()->release) + 1;
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
@@ -268,6 +268,10 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
if(ses->serverOS)
strncpy(ses->serverOS, bcc_ptr, len);
+ if(strncmp(ses->serverOS, "OS/2",4) == 0) {
+ cFYI(1,("OS/2 server"));
+ ses->flags |= CIFS_SES_OS2;
+ }
bcc_ptr += len + 1;
bleft -= len + 1;
@@ -290,16 +294,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo
if(len > bleft)
return rc;
- if(ses->serverDomain)
- kfree(ses->serverDomain);
-
- ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
- if(ses->serverOS)
- strncpy(ses->serverOS, bcc_ptr, len);
-
- bcc_ptr += len + 1;
- bleft -= len + 1;
-
+ /* No domain field in LANMAN case. Domain is
+ returned by old servers in the SMB negprot response */
+ /* BB For newer servers which do not support Unicode,
+ but thus do return domain here we could add parsing
+ for it later, but it is not very important */
cFYI(1,("ascii: bytes left %d",bleft));
return rc;
@@ -366,6 +365,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
str_area = kmalloc(2000, GFP_KERNEL);
bcc_ptr = str_area;
+ ses->flags &= ~CIFS_SES_LANMAN;
+
if(type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
char lnm_session_key[CIFS_SESS_KEY_SIZE];
@@ -377,7 +378,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
/* and copy into bcc */
calc_lanman_hash(ses, lnm_session_key);
-
+ ses->flags |= CIFS_SES_LANMAN;
/* #ifdef CONFIG_CIFS_DEBUG2
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
CIFS_SESS_KEY_SIZE);
diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c
index efaa044523a7..7a1b2b961ec8 100644
--- a/fs/cifs/smbdes.c
+++ b/fs/cifs/smbdes.c
@@ -364,20 +364,20 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24)
smbhash(p24 + 16, c8, p21 + 14, 1);
}
-void
+#if 0 /* currently unsued */
+static void
D_P16(unsigned char *p14, unsigned char *in, unsigned char *out)
{
smbhash(out, in, p14, 0);
smbhash(out + 8, in + 8, p14 + 7, 0);
}
-void
+static void
E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out)
{
smbhash(out, in, p14, 1);
smbhash(out + 8, in + 8, p14 + 7, 1);
}
-#if 0
/* these routines are currently unneeded, but may be
needed later */
void
diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c
index f518c5e45035..4b25ba92180d 100644
--- a/fs/cifs/smbencrypt.c
+++ b/fs/cifs/smbencrypt.c
@@ -51,11 +51,8 @@
void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
void E_md4hash(const unsigned char *passwd, unsigned char *p16);
-void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]);
static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
unsigned char p24[24]);
-void NTLMSSPOWFencrypt(unsigned char passwd[8],
- unsigned char *ntlmchalresp, unsigned char p24[24]);
void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24);
/*
@@ -144,8 +141,9 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16)
memset(wpwd,0,129 * 2);
}
+#if 0 /* currently unused */
/* Does both the NT and LM owfs of a user's password */
-void
+static void
nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
{
char passwd[514];
@@ -171,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16])
/* clear out local copy of user's password (just being paranoid). */
memset(passwd, '\0', sizeof (passwd));
}
+#endif
/* Does the NTLMv2 owfs of a user's password */
#if 0 /* function not needed yet - but will be soon */
@@ -223,7 +222,8 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8,
}
/* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */
-void
+#if 0 /* currently unused */
+static void
NTLMSSPOWFencrypt(unsigned char passwd[8],
unsigned char *ntlmchalresp, unsigned char p24[24])
{
@@ -235,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8],
E_P24(p21, ntlmchalresp, p24);
}
+#endif
/* Does the NT MD4 hash then des encryption. */
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 5597080cb811..95a54253c047 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -110,8 +110,6 @@ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr)
inode->i_nlink = attr->va_nlink;
if (attr->va_size != -1)
inode->i_size = attr->va_size;
- if (attr->va_blocksize != -1)
- inode->i_blksize = attr->va_blocksize;
if (attr->va_size != -1)
inode->i_blocks = (attr->va_size + 511) >> 9;
if (attr->va_atime.tv_sec != -1)
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 71f2ea632e53..0102b28a15fb 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -304,7 +304,7 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
coda_dir_changed(dir_inode, 0);
atomic_inc(&inode->i_count);
d_instantiate(de, inode);
- inode->i_nlink++;
+ inc_nlink(inode);
out:
unlock_kernel();
@@ -367,7 +367,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
}
coda_dir_changed(dir, 0);
- de->d_inode->i_nlink--;
+ drop_nlink(de->d_inode);
unlock_kernel();
return 0;
@@ -394,7 +394,7 @@ int coda_rmdir(struct inode *dir, struct dentry *de)
}
coda_dir_changed(dir, -1);
- de->d_inode->i_nlink--;
+ drop_nlink(de->d_inode);
d_delete(de);
unlock_kernel();
@@ -513,7 +513,7 @@ static int coda_venus_readdir(struct file *filp, filldir_t filldir,
ino_t ino;
int ret, i;
- vdir = (struct venus_dirent *)kmalloc(sizeof(*vdir), GFP_KERNEL);
+ vdir = kmalloc(sizeof(*vdir), GFP_KERNEL);
if (!vdir) return -ENOMEM;
i = filp->f_pos;
diff --git a/fs/coda/inode.c b/fs/coda/inode.c
index 87f1dc8aa24b..88d123321164 100644
--- a/fs/coda/inode.c
+++ b/fs/coda/inode.c
@@ -80,8 +80,7 @@ int coda_init_inodecache(void)
void coda_destroy_inodecache(void)
{
- if (kmem_cache_destroy(coda_inode_cachep))
- printk(KERN_INFO "coda_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(coda_inode_cachep);
}
static int coda_remount(struct super_block *sb, int *flags, char *data)
diff --git a/fs/compat.c b/fs/compat.c
index ce982f6e8c80..50624d4a70c6 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -44,7 +44,7 @@
#include <linux/nfsd/syscall.h>
#include <linux/personality.h>
#include <linux/rwsem.h>
-#include <linux/acct.h>
+#include <linux/tsacct_kern.h>
#include <linux/mm.h>
#include <net/sock.h> /* siocdevprivate_ioctl */
@@ -52,8 +52,7 @@
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/ioctls.h>
-
-extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
+#include "internal.h"
int compat_log = 1;
@@ -69,6 +68,8 @@ int compat_printk(const char *fmt, ...)
return ret;
}
+#include "read_write.h"
+
/*
* Not all architectures have sys_utime, so implement this in terms
* of sys_utimes.
@@ -313,9 +314,6 @@ out:
#define IOCTL_HASHSIZE 256
static struct ioctl_trans *ioctl32_hash_table[IOCTL_HASHSIZE];
-extern struct ioctl_trans ioctl_start[];
-extern int ioctl_table_size;
-
static inline unsigned long ioctl32_hash(unsigned long cmd)
{
return (((cmd >> 6) ^ (cmd >> 4) ^ cmd)) % IOCTL_HASHSIZE;
@@ -838,8 +836,6 @@ static int do_nfs4_super_data_conv(void *raw_data)
return 0;
}
-extern int copy_mount_options (const void __user *, unsigned long *);
-
#define SMBFS_NAME "smbfs"
#define NCPFS_NAME "ncpfs"
#define NFS4_NAME "nfs4"
@@ -918,20 +914,24 @@ struct compat_readdir_callback {
};
static int compat_fillonedir(void *__buf, const char *name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct compat_readdir_callback *buf = __buf;
struct compat_old_linux_dirent __user *dirent;
+ compat_ulong_t d_ino;
if (buf->result)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
buf->result++;
dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent,
(unsigned long)(dirent->d_name + namlen + 1) -
(unsigned long)dirent))
goto efault;
- if ( __put_user(ino, &dirent->d_ino) ||
+ if ( __put_user(d_ino, &dirent->d_ino) ||
__put_user(offset, &dirent->d_offset) ||
__put_user(namlen, &dirent->d_namlen) ||
__copy_to_user(dirent->d_name, name, namlen) ||
@@ -982,22 +982,26 @@ struct compat_getdents_callback {
};
static int compat_filldir(void *__buf, const char *name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct compat_linux_dirent __user * dirent;
struct compat_getdents_callback *buf = __buf;
+ compat_ulong_t d_ino;
int reclen = COMPAT_ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
if (dirent) {
if (__put_user(offset, &dirent->d_off))
goto efault;
}
dirent = buf->current_dir;
- if (__put_user(ino, &dirent->d_ino))
+ if (__put_user(d_ino, &dirent->d_ino))
goto efault;
if (__put_user(reclen, &dirent->d_reclen))
goto efault;
@@ -1068,7 +1072,7 @@ struct compat_getdents_callback64 {
};
static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
- ino_t ino, unsigned int d_type)
+ u64 ino, unsigned int d_type)
{
struct linux_dirent64 __user *dirent;
struct compat_getdents_callback64 *buf = __buf;
@@ -1153,9 +1157,6 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
const struct compat_iovec __user *uvector,
unsigned long nr_segs, loff_t *pos)
{
- typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
- typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
-
compat_ssize_t tot_len;
struct iovec iovstack[UIO_FASTIOV];
struct iovec *iov=iovstack, *vector;
@@ -1238,39 +1239,18 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
fnv = NULL;
if (type == READ) {
fn = file->f_op->read;
- fnv = file->f_op->readv;
+ fnv = file->f_op->aio_read;
} else {
fn = (io_fn_t)file->f_op->write;
- fnv = file->f_op->writev;
- }
- if (fnv) {
- ret = fnv(file, iov, nr_segs, pos);
- goto out;
+ fnv = file->f_op->aio_write;
}
- /* Do it by hand, with file-ops */
- ret = 0;
- vector = iov;
- while (nr_segs > 0) {
- void __user * base;
- size_t len;
- ssize_t nr;
-
- base = vector->iov_base;
- len = vector->iov_len;
- vector++;
- nr_segs--;
-
- nr = fn(file, base, len, pos);
+ if (fnv)
+ ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
+ pos, fnv);
+ else
+ ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
- if (nr < 0) {
- if (!ret) ret = nr;
- break;
- }
- ret += nr;
- if (nr != len)
- break;
- }
out:
if (iov != iovstack)
kfree(iov);
@@ -1298,7 +1278,7 @@ compat_sys_readv(unsigned long fd, const struct compat_iovec __user *vec, unsign
goto out;
ret = -EINVAL;
- if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
+ if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
goto out;
ret = compat_do_readv_writev(READ, file, vec, vlen, &file->f_pos);
@@ -1321,7 +1301,7 @@ compat_sys_writev(unsigned long fd, const struct compat_iovec __user *vec, unsig
goto out;
ret = -EINVAL;
- if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
+ if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
goto out;
ret = compat_do_readv_writev(WRITE, file, vec, vlen, &file->f_pos);
@@ -1336,7 +1316,7 @@ compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32,
unsigned int nr_segs, unsigned int flags)
{
unsigned i;
- struct iovec *iov;
+ struct iovec __user *iov;
if (nr_segs > UIO_MAXIOV)
return -EINVAL;
iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec));
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index 4063a9396977..a91f2628c981 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -40,15 +40,11 @@
#include <linux/if_pppox.h>
#include <linux/mtio.h>
#include <linux/cdrom.h>
-#include <linux/loop.h>
#include <linux/auto_fs.h>
#include <linux/auto_fs4.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
#include <linux/fb.h>
-#include <linux/ext2_fs.h>
-#include <linux/ext3_jbd.h>
-#include <linux/ext3_fs.h>
#include <linux/videodev.h>
#include <linux/netdevice.h>
#include <linux/raw.h>
@@ -60,12 +56,10 @@
#include <linux/pci.h>
#include <linux/module.h>
#include <linux/serial.h>
-#include <linux/reiserfs_fs.h>
#include <linux/if_tun.h>
#include <linux/ctype.h>
#include <linux/ioctl32.h>
#include <linux/syscalls.h>
-#include <linux/ncp_fs.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/wireless.h>
@@ -113,7 +107,6 @@
#include <linux/nbd.h>
#include <linux/random.h>
#include <linux/filter.h>
-#include <linux/msdos_fs.h>
#include <linux/pktcdvd.h>
#include <linux/hiddev.h>
@@ -124,21 +117,6 @@
#include <linux/dvb/video.h>
#include <linux/lp.h>
-/* Aiee. Someone does not find a difference between int and long */
-#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int)
-#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int)
-#define EXT3_IOC32_GETVERSION _IOR('f', 3, int)
-#define EXT3_IOC32_SETVERSION _IOW('f', 4, int)
-#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int)
-#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int)
-#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
-#ifdef CONFIG_JBD_DEBUG
-#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
-#endif
-
-#define EXT2_IOC32_GETVERSION _IOR('v', 1, int)
-#define EXT2_IOC32_SETVERSION _IOW('v', 2, int)
-
static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd,
unsigned long arg, struct file *f)
{
@@ -176,34 +154,6 @@ static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg)
return err;
}
-static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- /* These are just misnamed, they actually get/put from/to user an int */
- switch (cmd) {
- case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break;
- case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break;
- case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break;
- case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break;
- }
- return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
-}
-
-static int do_ext3_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- /* These are just misnamed, they actually get/put from/to user an int */
- switch (cmd) {
- case EXT3_IOC32_GETVERSION: cmd = EXT3_IOC_GETVERSION; break;
- case EXT3_IOC32_SETVERSION: cmd = EXT3_IOC_SETVERSION; break;
- case EXT3_IOC32_GETRSVSZ: cmd = EXT3_IOC_GETRSVSZ; break;
- case EXT3_IOC32_SETRSVSZ: cmd = EXT3_IOC_SETRSVSZ; break;
- case EXT3_IOC32_GROUP_EXTEND: cmd = EXT3_IOC_GROUP_EXTEND; break;
-#ifdef CONFIG_JBD_DEBUG
- case EXT3_IOC32_WAIT_FOR_READONLY: cmd = EXT3_IOC_WAIT_FOR_READONLY; break;
-#endif
- }
- return sys_ioctl(fd, cmd, (unsigned long)compat_ptr(arg));
-}
-
struct compat_video_event {
int32_t type;
compat_time_t timestamp;
@@ -694,6 +644,7 @@ out:
}
#endif
+#ifdef CONFIG_BLOCK
struct hd_geometry32 {
unsigned char heads;
unsigned char sectors;
@@ -918,6 +869,7 @@ static int sg_grt_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
}
return err;
}
+#endif /* CONFIG_BLOCK */
struct sock_fprog32 {
unsigned short len;
@@ -1041,6 +993,7 @@ static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
}
+#ifdef CONFIG_BLOCK
struct mtget32 {
compat_long_t mt_type;
compat_long_t mt_resid;
@@ -1213,73 +1166,7 @@ static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar
return err;
}
-
-struct loop_info32 {
- compat_int_t lo_number; /* ioctl r/o */
- compat_dev_t lo_device; /* ioctl r/o */
- compat_ulong_t lo_inode; /* ioctl r/o */
- compat_dev_t lo_rdevice; /* ioctl r/o */
- compat_int_t lo_offset;
- compat_int_t lo_encrypt_type;
- compat_int_t lo_encrypt_key_size; /* ioctl w/o */
- compat_int_t lo_flags; /* ioctl r/o */
- char lo_name[LO_NAME_SIZE];
- unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */
- compat_ulong_t lo_init[2];
- char reserved[4];
-};
-
-static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- mm_segment_t old_fs = get_fs();
- struct loop_info l;
- struct loop_info32 __user *ul;
- int err = -EINVAL;
-
- ul = compat_ptr(arg);
- switch(cmd) {
- case LOOP_SET_STATUS:
- err = get_user(l.lo_number, &ul->lo_number);
- err |= __get_user(l.lo_device, &ul->lo_device);
- err |= __get_user(l.lo_inode, &ul->lo_inode);
- err |= __get_user(l.lo_rdevice, &ul->lo_rdevice);
- err |= __copy_from_user(&l.lo_offset, &ul->lo_offset,
- 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
- if (err) {
- err = -EFAULT;
- } else {
- set_fs (KERNEL_DS);
- err = sys_ioctl (fd, cmd, (unsigned long)&l);
- set_fs (old_fs);
- }
- break;
- case LOOP_GET_STATUS:
- set_fs (KERNEL_DS);
- err = sys_ioctl (fd, cmd, (unsigned long)&l);
- set_fs (old_fs);
- if (!err) {
- err = put_user(l.lo_number, &ul->lo_number);
- err |= __put_user(l.lo_device, &ul->lo_device);
- err |= __put_user(l.lo_inode, &ul->lo_inode);
- err |= __put_user(l.lo_rdevice, &ul->lo_rdevice);
- err |= __copy_to_user(&ul->lo_offset, &l.lo_offset,
- (unsigned long)l.lo_init - (unsigned long)&l.lo_offset);
- if (err)
- err = -EFAULT;
- }
- break;
- default: {
- static int count;
- if (++count <= 20)
- printk("%s: Unknown loop ioctl cmd, fd(%d) "
- "cmd(%08x) arg(%08lx)\n",
- __FUNCTION__, fd, cmd, arg);
- }
- }
- return err;
-}
-
-extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg);
+#endif /* CONFIG_BLOCK */
#ifdef CONFIG_VT
@@ -1607,6 +1494,7 @@ ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg)
return -EINVAL;
}
+#ifdef CONFIG_BLOCK
static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg)
{
/* The mkswap binary hard codes it to Intel value :-((( */
@@ -1641,12 +1529,14 @@ static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long ar
return sys_ioctl(fd, cmd, (unsigned long)a);
}
+#endif
static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
{
return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
}
+#ifdef CONFIG_BLOCK
/* Fix sizeof(sizeof()) breakage */
#define BLKBSZGET_32 _IOR(0x12,112,int)
#define BLKBSZSET_32 _IOW(0x12,113,int)
@@ -1667,6 +1557,7 @@ static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
{
return sys_ioctl(fd, BLKGETSIZE64, (unsigned long)compat_ptr(arg));
}
+#endif
/* Bluetooth ioctls */
#define HCIUARTSETPROTO _IOW('U', 200, int)
@@ -1687,6 +1578,7 @@ static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
#define HIDPGETCONNLIST _IOR('H', 210, int)
#define HIDPGETCONNINFO _IOR('H', 211, int)
+#ifdef CONFIG_BLOCK
struct floppy_struct32 {
compat_uint_t size;
compat_uint_t sect;
@@ -2011,6 +1903,7 @@ out:
kfree(karg);
return err;
}
+#endif
struct mtd_oob_buf32 {
u_int32_t start;
@@ -2052,61 +1945,7 @@ static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
return err;
}
-#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
-#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
-
-static long
-put_dirent32 (struct dirent *d, struct compat_dirent __user *d32)
-{
- if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent)))
- return -EFAULT;
-
- __put_user(d->d_ino, &d32->d_ino);
- __put_user(d->d_off, &d32->d_off);
- __put_user(d->d_reclen, &d32->d_reclen);
- if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
- return -EFAULT;
-
- return 0;
-}
-
-static int vfat_ioctl32(unsigned fd, unsigned cmd, unsigned long arg)
-{
- struct compat_dirent __user *p = compat_ptr(arg);
- int ret;
- mm_segment_t oldfs = get_fs();
- struct dirent d[2];
-
- switch(cmd)
- {
- case VFAT_IOCTL_READDIR_BOTH32:
- cmd = VFAT_IOCTL_READDIR_BOTH;
- break;
- case VFAT_IOCTL_READDIR_SHORT32:
- cmd = VFAT_IOCTL_READDIR_SHORT;
- break;
- }
-
- set_fs(KERNEL_DS);
- ret = sys_ioctl(fd,cmd,(unsigned long)&d);
- set_fs(oldfs);
- if (ret >= 0) {
- ret |= put_dirent32(&d[0], p);
- ret |= put_dirent32(&d[1], p + 1);
- }
- return ret;
-}
-
-#define REISERFS_IOC_UNPACK32 _IOW(0xCD,1,int)
-
-static int reiserfs_ioctl32(unsigned fd, unsigned cmd, unsigned long ptr)
-{
- if (cmd == REISERFS_IOC_UNPACK32)
- cmd = REISERFS_IOC_UNPACK;
-
- return sys_ioctl(fd,cmd,ptr);
-}
-
+#ifdef CONFIG_BLOCK
struct raw32_config_request
{
compat_int_t raw_minor;
@@ -2171,6 +2010,7 @@ static int raw_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
}
return ret;
}
+#endif /* CONFIG_BLOCK */
struct serial_struct32 {
compat_int_t type;
@@ -2507,193 +2347,6 @@ static int rtc_ioctl(unsigned fd, unsigned cmd, unsigned long arg)
}
}
-#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE)
-struct ncp_ioctl_request_32 {
- u32 function;
- u32 size;
- compat_caddr_t data;
-};
-
-struct ncp_fs_info_v2_32 {
- s32 version;
- u32 mounted_uid;
- u32 connection;
- u32 buffer_size;
-
- u32 volume_number;
- u32 directory_id;
-
- u32 dummy1;
- u32 dummy2;
- u32 dummy3;
-};
-
-struct ncp_objectname_ioctl_32
-{
- s32 auth_type;
- u32 object_name_len;
- compat_caddr_t object_name; /* an userspace data, in most cases user name */
-};
-
-struct ncp_privatedata_ioctl_32
-{
- u32 len;
- compat_caddr_t data; /* ~1000 for NDS */
-};
-
-#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct ncp_ioctl_request_32)
-#define NCP_IOC_GETMOUNTUID2_32 _IOW('n', 2, u32)
-#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct ncp_fs_info_v2_32)
-#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct ncp_objectname_ioctl_32)
-#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct ncp_objectname_ioctl_32)
-#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct ncp_privatedata_ioctl_32)
-#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct ncp_privatedata_ioctl_32)
-
-static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct ncp_ioctl_request_32 n32;
- struct ncp_ioctl_request __user *p = compat_alloc_user_space(sizeof(*p));
-
- if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32)) ||
- put_user(n32.function, &p->function) ||
- put_user(n32.size, &p->size) ||
- put_user(compat_ptr(n32.data), &p->data))
- return -EFAULT;
-
- return sys_ioctl(fd, NCP_IOC_NCPREQUEST, (unsigned long)p);
-}
-
-static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- mm_segment_t old_fs = get_fs();
- __kernel_uid_t kuid;
- int err;
-
- cmd = NCP_IOC_GETMOUNTUID2;
-
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
- set_fs(old_fs);
-
- if (!err)
- err = put_user(kuid,
- (unsigned int __user *) compat_ptr(arg));
-
- return err;
-}
-
-static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- mm_segment_t old_fs = get_fs();
- struct ncp_fs_info_v2_32 n32;
- struct ncp_fs_info_v2 n;
- int err;
-
- if (copy_from_user(&n32, compat_ptr(arg), sizeof(n32)))
- return -EFAULT;
- if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
- return -EINVAL;
- n.version = NCP_GET_FS_INFO_VERSION_V2;
-
- set_fs(KERNEL_DS);
- err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
- set_fs(old_fs);
-
- if (!err) {
- n32.version = n.version;
- n32.mounted_uid = n.mounted_uid;
- n32.connection = n.connection;
- n32.buffer_size = n.buffer_size;
- n32.volume_number = n.volume_number;
- n32.directory_id = n.directory_id;
- n32.dummy1 = n.dummy1;
- n32.dummy2 = n.dummy2;
- n32.dummy3 = n.dummy3;
- err = copy_to_user(compat_ptr(arg), &n32, sizeof(n32)) ? -EFAULT : 0;
- }
- return err;
-}
-
-static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct ncp_objectname_ioctl_32 n32, __user *p32 = compat_ptr(arg);
- struct ncp_objectname_ioctl __user *p = compat_alloc_user_space(sizeof(*p));
- s32 auth_type;
- u32 name_len;
- int err;
-
- if (copy_from_user(&n32, p32, sizeof(n32)) ||
- put_user(n32.object_name_len, &p->object_name_len) ||
- put_user(compat_ptr(n32.object_name), &p->object_name))
- return -EFAULT;
-
- err = sys_ioctl(fd, NCP_IOC_GETOBJECTNAME, (unsigned long)p);
- if (err)
- return err;
-
- if (get_user(auth_type, &p->auth_type) ||
- put_user(auth_type, &p32->auth_type) ||
- get_user(name_len, &p->object_name_len) ||
- put_user(name_len, &p32->object_name_len))
- return -EFAULT;
-
- return 0;
-}
-
-static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct ncp_objectname_ioctl_32 n32, __user *p32 = compat_ptr(arg);
- struct ncp_objectname_ioctl __user *p = compat_alloc_user_space(sizeof(*p));
-
- if (copy_from_user(&n32, p32, sizeof(n32)) ||
- put_user(n32.auth_type, &p->auth_type) ||
- put_user(n32.object_name_len, &p->object_name_len) ||
- put_user(compat_ptr(n32.object_name), &p->object_name))
- return -EFAULT;
-
- return sys_ioctl(fd, NCP_IOC_SETOBJECTNAME, (unsigned long)p);
-}
-
-static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct ncp_privatedata_ioctl_32 n32, __user *p32 = compat_ptr(arg);
- struct ncp_privatedata_ioctl __user *p =
- compat_alloc_user_space(sizeof(*p));
- u32 len;
- int err;
-
- if (copy_from_user(&n32, p32, sizeof(n32)) ||
- put_user(n32.len, &p->len) ||
- put_user(compat_ptr(n32.data), &p->data))
- return -EFAULT;
-
- err = sys_ioctl(fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)p);
- if (err)
- return err;
-
- if (get_user(len, &p->len) ||
- put_user(len, &p32->len))
- return -EFAULT;
-
- return 0;
-}
-
-static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
-{
- struct ncp_privatedata_ioctl_32 n32;
- struct ncp_privatedata_ioctl_32 __user *p32 = compat_ptr(arg);
- struct ncp_privatedata_ioctl __user *p =
- compat_alloc_user_space(sizeof(*p));
-
- if (copy_from_user(&n32, p32, sizeof(n32)) ||
- put_user(n32.len, &p->len) ||
- put_user(compat_ptr(n32.data), &p->data))
- return -EFAULT;
-
- return sys_ioctl(fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)p);
-}
-#endif
-
static int
lp_timeout_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
{
@@ -2777,6 +2430,7 @@ HANDLE_IOCTL(SIOCBRDELIF, dev_ifsioc)
HANDLE_IOCTL(SIOCRTMSG, ret_einval)
HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp)
#endif
+#ifdef CONFIG_BLOCK
HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo)
HANDLE_IOCTL(BLKRAGET, w_long)
HANDLE_IOCTL(BLKGETSIZE, w_long)
@@ -2784,13 +2438,17 @@ HANDLE_IOCTL(0x1260, broken_blkgetsize)
HANDLE_IOCTL(BLKFRAGET, w_long)
HANDLE_IOCTL(BLKSECTGET, w_long)
HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans)
-HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans)
-HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
-HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans)
HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans)
HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_WCACHE, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_ACOUSTIC, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_ADDRESS, hdio_ioctl_trans)
+HANDLE_IOCTL(HDIO_GET_BUSSTATE, hdio_ioctl_trans)
HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans)
HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans)
HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans)
@@ -2802,16 +2460,17 @@ HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans)
HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans)
HANDLE_IOCTL(SG_IO,sg_ioctl_trans)
HANDLE_IOCTL(SG_GET_REQUEST_TABLE, sg_grt_trans)
+#endif
HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans)
HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans)
HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans)
HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans)
+#ifdef CONFIG_BLOCK
HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans)
HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans)
HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans)
HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans)
-HANDLE_IOCTL(LOOP_SET_STATUS, loop_status)
-HANDLE_IOCTL(LOOP_GET_STATUS, loop_status)
+#endif
#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout)
#ifdef CONFIG_VT
@@ -2821,19 +2480,6 @@ HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl)
HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl)
HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl)
#endif
-HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl)
-HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl)
-HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl)
-HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl)
-HANDLE_IOCTL(EXT3_IOC32_GETVERSION, do_ext3_ioctl)
-HANDLE_IOCTL(EXT3_IOC32_SETVERSION, do_ext3_ioctl)
-HANDLE_IOCTL(EXT3_IOC32_GETRSVSZ, do_ext3_ioctl)
-HANDLE_IOCTL(EXT3_IOC32_SETRSVSZ, do_ext3_ioctl)
-HANDLE_IOCTL(EXT3_IOC32_GROUP_EXTEND, do_ext3_ioctl)
-COMPATIBLE_IOCTL(EXT3_IOC_GROUP_ADD)
-#ifdef CONFIG_JBD_DEBUG
-HANDLE_IOCTL(EXT3_IOC32_WAIT_FOR_READONLY, do_ext3_ioctl)
-#endif
/* One SMB ioctl needs translations. */
#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid)
@@ -2863,16 +2509,14 @@ HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl)
HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl)
/* block stuff */
+#ifdef CONFIG_BLOCK
HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
-/* vfat */
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32)
-HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32)
-HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32)
/* Raw devices */
HANDLE_IOCTL(RAW_SETBIND, raw_ioctl)
HANDLE_IOCTL(RAW_GETBIND, raw_ioctl)
+#endif
/* Serial */
HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl)
HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl)
@@ -2920,16 +2564,6 @@ HANDLE_IOCTL(RTC_IRQP_SET32, rtc_ioctl)
HANDLE_IOCTL(RTC_EPOCH_READ32, rtc_ioctl)
HANDLE_IOCTL(RTC_EPOCH_SET32, rtc_ioctl)
-#if defined(CONFIG_NCP_FS) || defined(CONFIG_NCP_FS_MODULE)
-HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest)
-HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2)
-HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2)
-HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname)
-HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname)
-HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata)
-HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata)
-#endif
-
/* dvb */
HANDLE_IOCTL(VIDEO_GET_EVENT, do_video_get_event)
HANDLE_IOCTL(VIDEO_STILLPICTURE, do_video_stillpicture)
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 816e8ef64560..8a3b6a1a6ad1 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -139,7 +139,7 @@ static int init_dir(struct inode * inode)
inode->i_fop = &configfs_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
return 0;
}
@@ -169,7 +169,7 @@ static int create_dir(struct config_item * k, struct dentry * p,
if (!error) {
error = configfs_create(d, mode, init_dir);
if (!error) {
- p->d_inode->i_nlink++;
+ inc_nlink(p->d_inode);
(d)->d_op = &configfs_dentry_ops;
} else {
struct configfs_dirent *sd = d->d_fsdata;
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index f499803743e0..cf33fac68c84 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -137,8 +137,8 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
if ((retval = fill_read_buffer(file->f_dentry,buffer)))
goto out;
}
- pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
- __FUNCTION__,count,*ppos,buffer->page);
+ pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
+ __FUNCTION__, count, *ppos, buffer->page);
retval = flush_read_buffer(buffer,buf,count,ppos);
out:
up(&buffer->sem);
@@ -274,15 +274,15 @@ static int check_perm(struct inode * inode, struct file * file)
/* No error? Great, allocate a buffer for the file, and store it
* it in file->private_data for easy access.
*/
- buffer = kmalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
- if (buffer) {
- memset(buffer,0,sizeof(struct configfs_buffer));
- init_MUTEX(&buffer->sem);
- buffer->needs_read_fill = 1;
- buffer->ops = ops;
- file->private_data = buffer;
- } else
+ buffer = kzalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
+ if (!buffer) {
error = -ENOMEM;
+ goto Enomem;
+ }
+ init_MUTEX(&buffer->sem);
+ buffer->needs_read_fill = 1;
+ buffer->ops = ops;
+ file->private_data = buffer;
goto Done;
Einval:
@@ -290,6 +290,7 @@ static int check_perm(struct inode * inode, struct file * file)
goto Done;
Eaccess:
error = -EACCES;
+ Enomem:
module_put(attr->ca_owner);
Done:
if (error && item)
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index e14488ca6411..fb18917954a9 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -76,11 +76,10 @@ int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
if (!sd_iattr) {
/* setting attributes for the first time, allocate now */
- sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
+ sd_iattr = kzalloc(sizeof(struct iattr), GFP_KERNEL);
if (!sd_iattr)
return -ENOMEM;
/* assign default attributes */
- memset(sd_iattr, 0, sizeof(struct iattr));
sd_iattr->ia_mode = sd->s_mode;
sd_iattr->ia_uid = 0;
sd_iattr->ia_gid = 0;
@@ -136,7 +135,6 @@ struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
{
struct inode * inode = new_inode(configfs_sb);
if (inode) {
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->a_ops = &configfs_aops;
inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
diff --git a/fs/configfs/item.c b/fs/configfs/item.c
index e07485ac50ad..24421209f854 100644
--- a/fs/configfs/item.c
+++ b/fs/configfs/item.c
@@ -224,4 +224,4 @@ EXPORT_SYMBOL(config_item_init);
EXPORT_SYMBOL(config_group_init);
EXPORT_SYMBOL(config_item_get);
EXPORT_SYMBOL(config_item_put);
-
+EXPORT_SYMBOL(config_group_find_obj);
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 3e5fe843e1df..68bd5c93ca52 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -84,7 +84,7 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
inode->i_op = &configfs_dir_inode_operations;
inode->i_fop = &configfs_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
} else {
pr_debug("configfs: could not get root inode\n");
return -ENOMEM;
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c
index 223c0431042d..a624c3ec8189 100644
--- a/fs/cramfs/inode.c
+++ b/fs/cramfs/inode.c
@@ -73,7 +73,6 @@ static int cramfs_iget5_set(struct inode *inode, void *opaque)
inode->i_uid = cramfs_inode->uid;
inode->i_size = cramfs_inode->size;
inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_gid = cramfs_inode->gid;
/* Struct copy intentional */
inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
@@ -242,11 +241,10 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_flags |= MS_RDONLY;
- sbi = kmalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct cramfs_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_fs_info = sbi;
- memset(sbi, 0, sizeof(struct cramfs_sb_info));
/* Invalidate the read buffers on mount: think disk change.. */
mutex_lock(&read_mutex);
@@ -545,8 +543,15 @@ static struct file_system_type cramfs_fs_type = {
static int __init init_cramfs_fs(void)
{
- cramfs_uncompress_init();
- return register_filesystem(&cramfs_fs_type);
+ int rv;
+
+ rv = cramfs_uncompress_init();
+ if (rv < 0)
+ return rv;
+ rv = register_filesystem(&cramfs_fs_type);
+ if (rv < 0)
+ cramfs_uncompress_exit();
+ return rv;
}
static void __exit exit_cramfs_fs(void)
diff --git a/fs/cramfs/uncompress.c b/fs/cramfs/uncompress.c
index 8def89f2c438..fc3ccb74626f 100644
--- a/fs/cramfs/uncompress.c
+++ b/fs/cramfs/uncompress.c
@@ -68,11 +68,10 @@ int cramfs_uncompress_init(void)
return 0;
}
-int cramfs_uncompress_exit(void)
+void cramfs_uncompress_exit(void)
{
if (!--initialized) {
zlib_inflateEnd(&stream);
vfree(stream.workspace);
}
- return 0;
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 17b392a2049e..a1ff91eef108 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -32,6 +32,7 @@
#include <linux/seqlock.h>
#include <linux/swap.h>
#include <linux/bootmem.h>
+#include "internal.h"
int sysctl_vfs_cache_pressure __read_mostly = 100;
@@ -290,9 +291,9 @@ struct dentry * dget_locked(struct dentry *dentry)
* it can be unhashed only if it has no children, or if it is the root
* of a filesystem.
*
- * If the inode has a DCACHE_DISCONNECTED alias, then prefer
+ * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer
* any other hashed alias over that one unless @want_discon is set,
- * in which case only return a DCACHE_DISCONNECTED alias.
+ * in which case only return an IS_ROOT, DCACHE_DISCONNECTED alias.
*/
static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
@@ -308,7 +309,8 @@ static struct dentry * __d_find_alias(struct inode *inode, int want_discon)
prefetch(next);
alias = list_entry(tmp, struct dentry, d_alias);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
- if (alias->d_flags & DCACHE_DISCONNECTED)
+ if (IS_ROOT(alias) &&
+ (alias->d_flags & DCACHE_DISCONNECTED))
discon_alias = alias;
else if (!want_discon) {
__dget_locked(alias);
@@ -547,6 +549,136 @@ repeat:
}
/*
+ * destroy a single subtree of dentries for unmount
+ * - see the comments on shrink_dcache_for_umount() for a description of the
+ * locking
+ */
+static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
+{
+ struct dentry *parent;
+
+ BUG_ON(!IS_ROOT(dentry));
+
+ /* detach this root from the system */
+ spin_lock(&dcache_lock);
+ if (!list_empty(&dentry->d_lru)) {
+ dentry_stat.nr_unused--;
+ list_del_init(&dentry->d_lru);
+ }
+ __d_drop(dentry);
+ spin_unlock(&dcache_lock);
+
+ for (;;) {
+ /* descend to the first leaf in the current subtree */
+ while (!list_empty(&dentry->d_subdirs)) {
+ struct dentry *loop;
+
+ /* this is a branch with children - detach all of them
+ * from the system in one go */
+ spin_lock(&dcache_lock);
+ list_for_each_entry(loop, &dentry->d_subdirs,
+ d_u.d_child) {
+ if (!list_empty(&loop->d_lru)) {
+ dentry_stat.nr_unused--;
+ list_del_init(&loop->d_lru);
+ }
+
+ __d_drop(loop);
+ cond_resched_lock(&dcache_lock);
+ }
+ spin_unlock(&dcache_lock);
+
+ /* move to the first child */
+ dentry = list_entry(dentry->d_subdirs.next,
+ struct dentry, d_u.d_child);
+ }
+
+ /* consume the dentries from this leaf up through its parents
+ * until we find one with children or run out altogether */
+ do {
+ struct inode *inode;
+
+ if (atomic_read(&dentry->d_count) != 0) {
+ printk(KERN_ERR
+ "BUG: Dentry %p{i=%lx,n=%s}"
+ " still in use (%d)"
+ " [unmount of %s %s]\n",
+ dentry,
+ dentry->d_inode ?
+ dentry->d_inode->i_ino : 0UL,
+ dentry->d_name.name,
+ atomic_read(&dentry->d_count),
+ dentry->d_sb->s_type->name,
+ dentry->d_sb->s_id);
+ BUG();
+ }
+
+ parent = dentry->d_parent;
+ if (parent == dentry)
+ parent = NULL;
+ else
+ atomic_dec(&parent->d_count);
+
+ list_del(&dentry->d_u.d_child);
+ dentry_stat.nr_dentry--; /* For d_free, below */
+
+ inode = dentry->d_inode;
+ if (inode) {
+ dentry->d_inode = NULL;
+ list_del_init(&dentry->d_alias);
+ if (dentry->d_op && dentry->d_op->d_iput)
+ dentry->d_op->d_iput(dentry, inode);
+ else
+ iput(inode);
+ }
+
+ d_free(dentry);
+
+ /* finished when we fall off the top of the tree,
+ * otherwise we ascend to the parent and move to the
+ * next sibling if there is one */
+ if (!parent)
+ return;
+
+ dentry = parent;
+
+ } while (list_empty(&dentry->d_subdirs));
+
+ dentry = list_entry(dentry->d_subdirs.next,
+ struct dentry, d_u.d_child);
+ }
+}
+
+/*
+ * destroy the dentries attached to a superblock on unmounting
+ * - we don't need to use dentry->d_lock, and only need dcache_lock when
+ * removing the dentry from the system lists and hashes because:
+ * - the superblock is detached from all mountings and open files, so the
+ * dentry trees will not be rearranged by the VFS
+ * - s_umount is write-locked, so the memory pressure shrinker will ignore
+ * any dentries belonging to this superblock that it comes across
+ * - the filesystem itself is no longer permitted to rearrange the dentries
+ * in this superblock
+ */
+void shrink_dcache_for_umount(struct super_block *sb)
+{
+ struct dentry *dentry;
+
+ if (down_read_trylock(&sb->s_umount))
+ BUG();
+
+ dentry = sb->s_root;
+ sb->s_root = NULL;
+ atomic_dec(&dentry->d_count);
+ shrink_dcache_for_umount_subtree(dentry);
+
+ while (!hlist_empty(&sb->s_anon)) {
+ dentry = hlist_entry(sb->s_anon.first, struct dentry, d_hash);
+ shrink_dcache_for_umount_subtree(dentry);
+ }
+}
+
+/*
* Search for at least 1 mount point in the dentry's subdirs.
* We descend to the next level whenever the d_subdirs
* list is non-empty and continue searching.
@@ -1003,7 +1135,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
{
struct dentry *new = NULL;
- if (inode) {
+ if (inode && S_ISDIR(inode->i_mode)) {
spin_lock(&dcache_lock);
new = __d_find_alias(inode, 1);
if (new) {
@@ -1337,23 +1469,21 @@ static void switch_names(struct dentry *dentry, struct dentry *target)
* deleted it.
*/
-/**
- * d_move - move a dentry
+/*
+ * d_move_locked - move a dentry
* @dentry: entry to move
* @target: new dentry
*
* Update the dcache to reflect the move of a file name. Negative
* dcache entries should not be moved in this way.
*/
-
-void d_move(struct dentry * dentry, struct dentry * target)
+static void d_move_locked(struct dentry * dentry, struct dentry * target)
{
struct hlist_head *list;
if (!dentry->d_inode)
printk(KERN_WARNING "VFS: moving negative dcache entry\n");
- spin_lock(&dcache_lock);
write_seqlock(&rename_lock);
/*
* XXXX: do we really need to take target->d_lock?
@@ -1404,7 +1534,81 @@ already_unhashed:
fsnotify_d_move(dentry);
spin_unlock(&dentry->d_lock);
write_sequnlock(&rename_lock);
+}
+
+/**
+ * d_move - move a dentry
+ * @dentry: entry to move
+ * @target: new dentry
+ *
+ * Update the dcache to reflect the move of a file name. Negative
+ * dcache entries should not be moved in this way.
+ */
+
+void d_move(struct dentry * dentry, struct dentry * target)
+{
+ spin_lock(&dcache_lock);
+ d_move_locked(dentry, target);
+ spin_unlock(&dcache_lock);
+}
+
+/*
+ * Helper that returns 1 if p1 is a parent of p2, else 0
+ */
+static int d_isparent(struct dentry *p1, struct dentry *p2)
+{
+ struct dentry *p;
+
+ for (p = p2; p->d_parent != p; p = p->d_parent) {
+ if (p->d_parent == p1)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * This helper attempts to cope with remotely renamed directories
+ *
+ * It assumes that the caller is already holding
+ * dentry->d_parent->d_inode->i_mutex and the dcache_lock
+ *
+ * Note: If ever the locking in lock_rename() changes, then please
+ * remember to update this too...
+ *
+ * On return, dcache_lock will have been unlocked.
+ */
+static struct dentry *__d_unalias(struct dentry *dentry, struct dentry *alias)
+{
+ struct mutex *m1 = NULL, *m2 = NULL;
+ struct dentry *ret;
+
+ /* If alias and dentry share a parent, then no extra locks required */
+ if (alias->d_parent == dentry->d_parent)
+ goto out_unalias;
+
+ /* Check for loops */
+ ret = ERR_PTR(-ELOOP);
+ if (d_isparent(alias, dentry))
+ goto out_err;
+
+ /* See lock_rename() */
+ ret = ERR_PTR(-EBUSY);
+ if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex))
+ goto out_err;
+ m1 = &dentry->d_sb->s_vfs_rename_mutex;
+ if (!mutex_trylock(&alias->d_parent->d_inode->i_mutex))
+ goto out_err;
+ m2 = &alias->d_parent->d_inode->i_mutex;
+out_unalias:
+ d_move_locked(alias, dentry);
+ ret = alias;
+out_err:
spin_unlock(&dcache_lock);
+ if (m2)
+ mutex_unlock(m2);
+ if (m1)
+ mutex_unlock(m1);
+ return ret;
}
/*
@@ -1449,7 +1653,7 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon)
*/
struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
{
- struct dentry *alias, *actual;
+ struct dentry *actual;
BUG_ON(!d_unhashed(dentry));
@@ -1461,26 +1665,27 @@ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
goto found_lock;
}
- /* See if a disconnected directory already exists as an anonymous root
- * that we should splice into the tree instead */
- if (S_ISDIR(inode->i_mode) && (alias = __d_find_alias(inode, 1))) {
- spin_lock(&alias->d_lock);
-
- /* Is this a mountpoint that we could splice into our tree? */
- if (IS_ROOT(alias))
- goto connect_mountpoint;
-
- if (alias->d_name.len == dentry->d_name.len &&
- alias->d_parent == dentry->d_parent &&
- memcmp(alias->d_name.name,
- dentry->d_name.name,
- dentry->d_name.len) == 0)
- goto replace_with_alias;
-
- spin_unlock(&alias->d_lock);
-
- /* Doh! Seem to be aliasing directories for some reason... */
- dput(alias);
+ if (S_ISDIR(inode->i_mode)) {
+ struct dentry *alias;
+
+ /* Does an aliased dentry already exist? */
+ alias = __d_find_alias(inode, 0);
+ if (alias) {
+ actual = alias;
+ /* Is this an anonymous mountpoint that we could splice
+ * into our tree? */
+ if (IS_ROOT(alias)) {
+ spin_lock(&alias->d_lock);
+ __d_materialise_dentry(dentry, alias);
+ __d_drop(alias);
+ goto found;
+ }
+ /* Nope, but we must(!) avoid directory aliasing */
+ actual = __d_unalias(dentry, alias);
+ if (IS_ERR(actual))
+ dput(alias);
+ goto out_nolock;
+ }
}
/* Add a unique reference */
@@ -1496,7 +1701,7 @@ found:
_d_rehash(actual);
spin_unlock(&actual->d_lock);
spin_unlock(&dcache_lock);
-
+out_nolock:
if (actual == dentry) {
security_d_instantiate(dentry, inode);
return NULL;
@@ -1505,16 +1710,6 @@ found:
iput(inode);
return actual;
- /* Convert the anonymous/root alias into an ordinary dentry */
-connect_mountpoint:
- __d_materialise_dentry(dentry, alias);
-
- /* Replace the candidate dentry with the alias in the tree */
-replace_with_alias:
- __d_drop(alias);
- actual = alias;
- goto found;
-
shouldnt_be_hashed:
spin_unlock(&dcache_lock);
BUG();
@@ -1877,9 +2072,6 @@ kmem_cache_t *filp_cachep __read_mostly;
EXPORT_SYMBOL(d_genocide);
-extern void bdev_cache_init(void);
-extern void chrdev_init(void);
-
void __init vfs_caches_init_early(void)
{
dcache_init_early();
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index e4b430552c88..bf3901ab1744 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -32,8 +32,8 @@ static ssize_t default_write_file(struct file *file, const char __user *buf,
static int default_open(struct inode *inode, struct file *file)
{
- if (inode->u.generic_ip)
- file->private_data = inode->u.generic_ip;
+ if (inode->i_private)
+ file->private_data = inode->i_private;
return 0;
}
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 3ca268d2e5a2..e77676df6713 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -40,7 +40,6 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
@@ -55,7 +54,7 @@ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t d
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
break;
}
}
@@ -88,7 +87,7 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
res = debugfs_mknod(dir, dentry, mode, 0);
if (!res)
- dir->i_nlink++;
+ inc_nlink(dir);
return res;
}
@@ -168,7 +167,7 @@ static int debugfs_create_by_name(const char *name, mode_t mode,
* directory dentry if set. If this paramater is NULL, then the
* file will be created in the root of the debugfs filesystem.
* @data: a pointer to something that the caller will want to get to later
- * on. The inode.u.generic_ip pointer will point to this value on
+ * on. The inode.i_private pointer will point to this value on
* the open() call.
* @fops: a pointer to a struct file_operations that should be used for
* this file.
@@ -209,7 +208,7 @@ struct dentry *debugfs_create_file(const char *name, mode_t mode,
if (dentry->d_inode) {
if (data)
- dentry->d_inode->u.generic_ip = data;
+ dentry->d_inode->i_private = data;
if (fops)
dentry->d_inode->i_fop = fops;
}
@@ -253,7 +252,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_dir);
*
* This function removes a file or directory in debugfs that was previously
* created with a call to another debugfs function (like
- * debufs_create_file() or variants thereof.)
+ * debugfs_create_file() or variants thereof.)
*
* This function is required to be called in order for the file to be
* removed, no automatic cleanup of files will happen when a module is
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c
index f7aef5bb584a..5f7b5a6025bf 100644
--- a/fs/devpts/inode.c
+++ b/fs/devpts/inode.c
@@ -113,7 +113,6 @@ devpts_fill_super(struct super_block *s, void *data, int silent)
inode->i_ino = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = 0;
- inode->i_blksize = 1024;
inode->i_uid = inode->i_gid = 0;
inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR;
inode->i_op = &simple_dir_inode_operations;
@@ -172,12 +171,11 @@ int devpts_pty_new(struct tty_struct *tty)
return -ENOMEM;
inode->i_ino = number+2;
- inode->i_blksize = 1024;
inode->i_uid = config.setuid ? config.uid : current->fsuid;
inode->i_gid = config.setgid ? config.gid : current->fsgid;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
init_special_inode(inode, S_IFCHR|config.mode, device);
- inode->u.generic_ip = tty;
+ inode->i_private = tty;
dentry = get_node(number);
if (!IS_ERR(dentry) && !dentry->d_inode)
@@ -196,7 +194,7 @@ struct tty_struct *devpts_get_tty(int number)
tty = NULL;
if (!IS_ERR(dentry)) {
if (dentry->d_inode)
- tty = dentry->d_inode->u.generic_ip;
+ tty = dentry->d_inode->i_private;
dput(dentry);
}
diff --git a/fs/dlm/Kconfig b/fs/dlm/Kconfig
new file mode 100644
index 000000000000..81b2c6465eeb
--- /dev/null
+++ b/fs/dlm/Kconfig
@@ -0,0 +1,20 @@
+menu "Distributed Lock Manager"
+ depends on INET && IP_SCTP && EXPERIMENTAL
+
+config DLM
+ tristate "Distributed Lock Manager (DLM)"
+ depends on IPV6 || IPV6=n
+ select CONFIGFS_FS
+ help
+ A general purpose distributed lock manager for kernel or userspace
+ applications.
+
+config DLM_DEBUG
+ bool "DLM debugging"
+ depends on DLM
+ help
+ Under the debugfs mount point, the name of each lockspace will
+ appear as a file in the "dlm" directory. The output is the
+ list of resource and locks the local node knows about.
+
+endmenu
diff --git a/fs/dlm/Makefile b/fs/dlm/Makefile
new file mode 100644
index 000000000000..1832e0297f7d
--- /dev/null
+++ b/fs/dlm/Makefile
@@ -0,0 +1,19 @@
+obj-$(CONFIG_DLM) += dlm.o
+dlm-y := ast.o \
+ config.o \
+ dir.o \
+ lock.o \
+ lockspace.o \
+ lowcomms.o \
+ main.o \
+ member.o \
+ memory.o \
+ midcomms.o \
+ rcom.o \
+ recover.o \
+ recoverd.o \
+ requestqueue.o \
+ user.o \
+ util.o
+dlm-$(CONFIG_DLM_DEBUG) += debug_fs.o
+
diff --git a/fs/dlm/ast.c b/fs/dlm/ast.c
new file mode 100644
index 000000000000..f91d39cb1e0b
--- /dev/null
+++ b/fs/dlm/ast.c
@@ -0,0 +1,173 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lock.h"
+#include "user.h"
+
+#define WAKE_ASTS 0
+
+static struct list_head ast_queue;
+static spinlock_t ast_queue_lock;
+static struct task_struct * astd_task;
+static unsigned long astd_wakeflags;
+static struct mutex astd_running;
+
+
+void dlm_del_ast(struct dlm_lkb *lkb)
+{
+ spin_lock(&ast_queue_lock);
+ if (lkb->lkb_ast_type & (AST_COMP | AST_BAST))
+ list_del(&lkb->lkb_astqueue);
+ spin_unlock(&ast_queue_lock);
+}
+
+void dlm_add_ast(struct dlm_lkb *lkb, int type)
+{
+ if (lkb->lkb_flags & DLM_IFL_USER) {
+ dlm_user_add_ast(lkb, type);
+ return;
+ }
+ DLM_ASSERT(lkb->lkb_astaddr != DLM_FAKE_USER_AST, dlm_print_lkb(lkb););
+
+ spin_lock(&ast_queue_lock);
+ if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+ kref_get(&lkb->lkb_ref);
+ list_add_tail(&lkb->lkb_astqueue, &ast_queue);
+ }
+ lkb->lkb_ast_type |= type;
+ spin_unlock(&ast_queue_lock);
+
+ set_bit(WAKE_ASTS, &astd_wakeflags);
+ wake_up_process(astd_task);
+}
+
+static void process_asts(void)
+{
+ struct dlm_ls *ls = NULL;
+ struct dlm_rsb *r = NULL;
+ struct dlm_lkb *lkb;
+ void (*cast) (long param);
+ void (*bast) (long param, int mode);
+ int type = 0, found, bmode;
+
+ for (;;) {
+ found = 0;
+ spin_lock(&ast_queue_lock);
+ list_for_each_entry(lkb, &ast_queue, lkb_astqueue) {
+ r = lkb->lkb_resource;
+ ls = r->res_ls;
+
+ if (dlm_locking_stopped(ls))
+ continue;
+
+ list_del(&lkb->lkb_astqueue);
+ type = lkb->lkb_ast_type;
+ lkb->lkb_ast_type = 0;
+ found = 1;
+ break;
+ }
+ spin_unlock(&ast_queue_lock);
+
+ if (!found)
+ break;
+
+ cast = lkb->lkb_astaddr;
+ bast = lkb->lkb_bastaddr;
+ bmode = lkb->lkb_bastmode;
+
+ if ((type & AST_COMP) && cast)
+ cast(lkb->lkb_astparam);
+
+ /* FIXME: Is it safe to look at lkb_grmode here
+ without doing a lock_rsb() ?
+ Look at other checks in v1 to avoid basts. */
+
+ if ((type & AST_BAST) && bast)
+ if (!dlm_modes_compat(lkb->lkb_grmode, bmode))
+ bast(lkb->lkb_astparam, bmode);
+
+ /* this removes the reference added by dlm_add_ast
+ and may result in the lkb being freed */
+ dlm_put_lkb(lkb);
+
+ schedule();
+ }
+}
+
+static inline int no_asts(void)
+{
+ int ret;
+
+ spin_lock(&ast_queue_lock);
+ ret = list_empty(&ast_queue);
+ spin_unlock(&ast_queue_lock);
+ return ret;
+}
+
+static int dlm_astd(void *data)
+{
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!test_bit(WAKE_ASTS, &astd_wakeflags))
+ schedule();
+ set_current_state(TASK_RUNNING);
+
+ mutex_lock(&astd_running);
+ if (test_and_clear_bit(WAKE_ASTS, &astd_wakeflags))
+ process_asts();
+ mutex_unlock(&astd_running);
+ }
+ return 0;
+}
+
+void dlm_astd_wake(void)
+{
+ if (!no_asts()) {
+ set_bit(WAKE_ASTS, &astd_wakeflags);
+ wake_up_process(astd_task);
+ }
+}
+
+int dlm_astd_start(void)
+{
+ struct task_struct *p;
+ int error = 0;
+
+ INIT_LIST_HEAD(&ast_queue);
+ spin_lock_init(&ast_queue_lock);
+ mutex_init(&astd_running);
+
+ p = kthread_run(dlm_astd, NULL, "dlm_astd");
+ if (IS_ERR(p))
+ error = PTR_ERR(p);
+ else
+ astd_task = p;
+ return error;
+}
+
+void dlm_astd_stop(void)
+{
+ kthread_stop(astd_task);
+}
+
+void dlm_astd_suspend(void)
+{
+ mutex_lock(&astd_running);
+}
+
+void dlm_astd_resume(void)
+{
+ mutex_unlock(&astd_running);
+}
+
diff --git a/fs/dlm/ast.h b/fs/dlm/ast.h
new file mode 100644
index 000000000000..6ee276c74c52
--- /dev/null
+++ b/fs/dlm/ast.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __ASTD_DOT_H__
+#define __ASTD_DOT_H__
+
+void dlm_add_ast(struct dlm_lkb *lkb, int type);
+void dlm_del_ast(struct dlm_lkb *lkb);
+
+void dlm_astd_wake(void);
+int dlm_astd_start(void);
+void dlm_astd_stop(void);
+void dlm_astd_suspend(void);
+void dlm_astd_resume(void);
+
+#endif
+
diff --git a/fs/dlm/config.c b/fs/dlm/config.c
new file mode 100644
index 000000000000..88553054bbfa
--- /dev/null
+++ b/fs/dlm/config.c
@@ -0,0 +1,789 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/configfs.h>
+#include <net/sock.h>
+
+#include "config.h"
+#include "lowcomms.h"
+
+/*
+ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/nodeid
+ * /config/dlm/<cluster>/spaces/<space>/nodes/<node>/weight
+ * /config/dlm/<cluster>/comms/<comm>/nodeid
+ * /config/dlm/<cluster>/comms/<comm>/local
+ * /config/dlm/<cluster>/comms/<comm>/addr
+ * The <cluster> level is useless, but I haven't figured out how to avoid it.
+ */
+
+static struct config_group *space_list;
+static struct config_group *comm_list;
+static struct comm *local_comm;
+
+struct clusters;
+struct cluster;
+struct spaces;
+struct space;
+struct comms;
+struct comm;
+struct nodes;
+struct node;
+
+static struct config_group *make_cluster(struct config_group *, const char *);
+static void drop_cluster(struct config_group *, struct config_item *);
+static void release_cluster(struct config_item *);
+static struct config_group *make_space(struct config_group *, const char *);
+static void drop_space(struct config_group *, struct config_item *);
+static void release_space(struct config_item *);
+static struct config_item *make_comm(struct config_group *, const char *);
+static void drop_comm(struct config_group *, struct config_item *);
+static void release_comm(struct config_item *);
+static struct config_item *make_node(struct config_group *, const char *);
+static void drop_node(struct config_group *, struct config_item *);
+static void release_node(struct config_item *);
+
+static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
+ char *buf);
+static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
+ const char *buf, size_t len);
+static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
+ char *buf);
+static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
+ const char *buf, size_t len);
+
+static ssize_t comm_nodeid_read(struct comm *cm, char *buf);
+static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t comm_local_read(struct comm *cm, char *buf);
+static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len);
+static ssize_t node_nodeid_read(struct node *nd, char *buf);
+static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len);
+static ssize_t node_weight_read(struct node *nd, char *buf);
+static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len);
+
+enum {
+ COMM_ATTR_NODEID = 0,
+ COMM_ATTR_LOCAL,
+ COMM_ATTR_ADDR,
+};
+
+struct comm_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct comm *, char *);
+ ssize_t (*store)(struct comm *, const char *, size_t);
+};
+
+static struct comm_attribute comm_attr_nodeid = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "nodeid",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = comm_nodeid_read,
+ .store = comm_nodeid_write,
+};
+
+static struct comm_attribute comm_attr_local = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "local",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = comm_local_read,
+ .store = comm_local_write,
+};
+
+static struct comm_attribute comm_attr_addr = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "addr",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .store = comm_addr_write,
+};
+
+static struct configfs_attribute *comm_attrs[] = {
+ [COMM_ATTR_NODEID] = &comm_attr_nodeid.attr,
+ [COMM_ATTR_LOCAL] = &comm_attr_local.attr,
+ [COMM_ATTR_ADDR] = &comm_attr_addr.attr,
+ NULL,
+};
+
+enum {
+ NODE_ATTR_NODEID = 0,
+ NODE_ATTR_WEIGHT,
+};
+
+struct node_attribute {
+ struct configfs_attribute attr;
+ ssize_t (*show)(struct node *, char *);
+ ssize_t (*store)(struct node *, const char *, size_t);
+};
+
+static struct node_attribute node_attr_nodeid = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "nodeid",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = node_nodeid_read,
+ .store = node_nodeid_write,
+};
+
+static struct node_attribute node_attr_weight = {
+ .attr = { .ca_owner = THIS_MODULE,
+ .ca_name = "weight",
+ .ca_mode = S_IRUGO | S_IWUSR },
+ .show = node_weight_read,
+ .store = node_weight_write,
+};
+
+static struct configfs_attribute *node_attrs[] = {
+ [NODE_ATTR_NODEID] = &node_attr_nodeid.attr,
+ [NODE_ATTR_WEIGHT] = &node_attr_weight.attr,
+ NULL,
+};
+
+struct clusters {
+ struct configfs_subsystem subsys;
+};
+
+struct cluster {
+ struct config_group group;
+};
+
+struct spaces {
+ struct config_group ss_group;
+};
+
+struct space {
+ struct config_group group;
+ struct list_head members;
+ struct mutex members_lock;
+ int members_count;
+};
+
+struct comms {
+ struct config_group cs_group;
+};
+
+struct comm {
+ struct config_item item;
+ int nodeid;
+ int local;
+ int addr_count;
+ struct sockaddr_storage *addr[DLM_MAX_ADDR_COUNT];
+};
+
+struct nodes {
+ struct config_group ns_group;
+};
+
+struct node {
+ struct config_item item;
+ struct list_head list; /* space->members */
+ int nodeid;
+ int weight;
+};
+
+static struct configfs_group_operations clusters_ops = {
+ .make_group = make_cluster,
+ .drop_item = drop_cluster,
+};
+
+static struct configfs_item_operations cluster_ops = {
+ .release = release_cluster,
+};
+
+static struct configfs_group_operations spaces_ops = {
+ .make_group = make_space,
+ .drop_item = drop_space,
+};
+
+static struct configfs_item_operations space_ops = {
+ .release = release_space,
+};
+
+static struct configfs_group_operations comms_ops = {
+ .make_item = make_comm,
+ .drop_item = drop_comm,
+};
+
+static struct configfs_item_operations comm_ops = {
+ .release = release_comm,
+ .show_attribute = show_comm,
+ .store_attribute = store_comm,
+};
+
+static struct configfs_group_operations nodes_ops = {
+ .make_item = make_node,
+ .drop_item = drop_node,
+};
+
+static struct configfs_item_operations node_ops = {
+ .release = release_node,
+ .show_attribute = show_node,
+ .store_attribute = store_node,
+};
+
+static struct config_item_type clusters_type = {
+ .ct_group_ops = &clusters_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type cluster_type = {
+ .ct_item_ops = &cluster_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type spaces_type = {
+ .ct_group_ops = &spaces_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type space_type = {
+ .ct_item_ops = &space_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type comms_type = {
+ .ct_group_ops = &comms_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type comm_type = {
+ .ct_item_ops = &comm_ops,
+ .ct_attrs = comm_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type nodes_type = {
+ .ct_group_ops = &nodes_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item_type node_type = {
+ .ct_item_ops = &node_ops,
+ .ct_attrs = node_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct cluster *to_cluster(struct config_item *i)
+{
+ return i ? container_of(to_config_group(i), struct cluster, group):NULL;
+}
+
+static struct space *to_space(struct config_item *i)
+{
+ return i ? container_of(to_config_group(i), struct space, group) : NULL;
+}
+
+static struct comm *to_comm(struct config_item *i)
+{
+ return i ? container_of(i, struct comm, item) : NULL;
+}
+
+static struct node *to_node(struct config_item *i)
+{
+ return i ? container_of(i, struct node, item) : NULL;
+}
+
+static struct config_group *make_cluster(struct config_group *g,
+ const char *name)
+{
+ struct cluster *cl = NULL;
+ struct spaces *sps = NULL;
+ struct comms *cms = NULL;
+ void *gps = NULL;
+
+ cl = kzalloc(sizeof(struct cluster), GFP_KERNEL);
+ gps = kcalloc(3, sizeof(struct config_group *), GFP_KERNEL);
+ sps = kzalloc(sizeof(struct spaces), GFP_KERNEL);
+ cms = kzalloc(sizeof(struct comms), GFP_KERNEL);
+
+ if (!cl || !gps || !sps || !cms)
+ goto fail;
+
+ config_group_init_type_name(&cl->group, name, &cluster_type);
+ config_group_init_type_name(&sps->ss_group, "spaces", &spaces_type);
+ config_group_init_type_name(&cms->cs_group, "comms", &comms_type);
+
+ cl->group.default_groups = gps;
+ cl->group.default_groups[0] = &sps->ss_group;
+ cl->group.default_groups[1] = &cms->cs_group;
+ cl->group.default_groups[2] = NULL;
+
+ space_list = &sps->ss_group;
+ comm_list = &cms->cs_group;
+ return &cl->group;
+
+ fail:
+ kfree(cl);
+ kfree(gps);
+ kfree(sps);
+ kfree(cms);
+ return NULL;
+}
+
+static void drop_cluster(struct config_group *g, struct config_item *i)
+{
+ struct cluster *cl = to_cluster(i);
+ struct config_item *tmp;
+ int j;
+
+ for (j = 0; cl->group.default_groups[j]; j++) {
+ tmp = &cl->group.default_groups[j]->cg_item;
+ cl->group.default_groups[j] = NULL;
+ config_item_put(tmp);
+ }
+
+ space_list = NULL;
+ comm_list = NULL;
+
+ config_item_put(i);
+}
+
+static void release_cluster(struct config_item *i)
+{
+ struct cluster *cl = to_cluster(i);
+ kfree(cl->group.default_groups);
+ kfree(cl);
+}
+
+static struct config_group *make_space(struct config_group *g, const char *name)
+{
+ struct space *sp = NULL;
+ struct nodes *nds = NULL;
+ void *gps = NULL;
+
+ sp = kzalloc(sizeof(struct space), GFP_KERNEL);
+ gps = kcalloc(2, sizeof(struct config_group *), GFP_KERNEL);
+ nds = kzalloc(sizeof(struct nodes), GFP_KERNEL);
+
+ if (!sp || !gps || !nds)
+ goto fail;
+
+ config_group_init_type_name(&sp->group, name, &space_type);
+ config_group_init_type_name(&nds->ns_group, "nodes", &nodes_type);
+
+ sp->group.default_groups = gps;
+ sp->group.default_groups[0] = &nds->ns_group;
+ sp->group.default_groups[1] = NULL;
+
+ INIT_LIST_HEAD(&sp->members);
+ mutex_init(&sp->members_lock);
+ sp->members_count = 0;
+ return &sp->group;
+
+ fail:
+ kfree(sp);
+ kfree(gps);
+ kfree(nds);
+ return NULL;
+}
+
+static void drop_space(struct config_group *g, struct config_item *i)
+{
+ struct space *sp = to_space(i);
+ struct config_item *tmp;
+ int j;
+
+ /* assert list_empty(&sp->members) */
+
+ for (j = 0; sp->group.default_groups[j]; j++) {
+ tmp = &sp->group.default_groups[j]->cg_item;
+ sp->group.default_groups[j] = NULL;
+ config_item_put(tmp);
+ }
+
+ config_item_put(i);
+}
+
+static void release_space(struct config_item *i)
+{
+ struct space *sp = to_space(i);
+ kfree(sp->group.default_groups);
+ kfree(sp);
+}
+
+static struct config_item *make_comm(struct config_group *g, const char *name)
+{
+ struct comm *cm;
+
+ cm = kzalloc(sizeof(struct comm), GFP_KERNEL);
+ if (!cm)
+ return NULL;
+
+ config_item_init_type_name(&cm->item, name, &comm_type);
+ cm->nodeid = -1;
+ cm->local = 0;
+ cm->addr_count = 0;
+ return &cm->item;
+}
+
+static void drop_comm(struct config_group *g, struct config_item *i)
+{
+ struct comm *cm = to_comm(i);
+ if (local_comm == cm)
+ local_comm = NULL;
+ dlm_lowcomms_close(cm->nodeid);
+ while (cm->addr_count--)
+ kfree(cm->addr[cm->addr_count]);
+ config_item_put(i);
+}
+
+static void release_comm(struct config_item *i)
+{
+ struct comm *cm = to_comm(i);
+ kfree(cm);
+}
+
+static struct config_item *make_node(struct config_group *g, const char *name)
+{
+ struct space *sp = to_space(g->cg_item.ci_parent);
+ struct node *nd;
+
+ nd = kzalloc(sizeof(struct node), GFP_KERNEL);
+ if (!nd)
+ return NULL;
+
+ config_item_init_type_name(&nd->item, name, &node_type);
+ nd->nodeid = -1;
+ nd->weight = 1; /* default weight of 1 if none is set */
+
+ mutex_lock(&sp->members_lock);
+ list_add(&nd->list, &sp->members);
+ sp->members_count++;
+ mutex_unlock(&sp->members_lock);
+
+ return &nd->item;
+}
+
+static void drop_node(struct config_group *g, struct config_item *i)
+{
+ struct space *sp = to_space(g->cg_item.ci_parent);
+ struct node *nd = to_node(i);
+
+ mutex_lock(&sp->members_lock);
+ list_del(&nd->list);
+ sp->members_count--;
+ mutex_unlock(&sp->members_lock);
+
+ config_item_put(i);
+}
+
+static void release_node(struct config_item *i)
+{
+ struct node *nd = to_node(i);
+ kfree(nd);
+}
+
+static struct clusters clusters_root = {
+ .subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = "dlm",
+ .ci_type = &clusters_type,
+ },
+ },
+ },
+};
+
+int dlm_config_init(void)
+{
+ config_group_init(&clusters_root.subsys.su_group);
+ init_MUTEX(&clusters_root.subsys.su_sem);
+ return configfs_register_subsystem(&clusters_root.subsys);
+}
+
+void dlm_config_exit(void)
+{
+ configfs_unregister_subsystem(&clusters_root.subsys);
+}
+
+/*
+ * Functions for user space to read/write attributes
+ */
+
+static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
+ char *buf)
+{
+ struct comm *cm = to_comm(i);
+ struct comm_attribute *cma =
+ container_of(a, struct comm_attribute, attr);
+ return cma->show ? cma->show(cm, buf) : 0;
+}
+
+static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
+ const char *buf, size_t len)
+{
+ struct comm *cm = to_comm(i);
+ struct comm_attribute *cma =
+ container_of(a, struct comm_attribute, attr);
+ return cma->store ? cma->store(cm, buf, len) : -EINVAL;
+}
+
+static ssize_t comm_nodeid_read(struct comm *cm, char *buf)
+{
+ return sprintf(buf, "%d\n", cm->nodeid);
+}
+
+static ssize_t comm_nodeid_write(struct comm *cm, const char *buf, size_t len)
+{
+ cm->nodeid = simple_strtol(buf, NULL, 0);
+ return len;
+}
+
+static ssize_t comm_local_read(struct comm *cm, char *buf)
+{
+ return sprintf(buf, "%d\n", cm->local);
+}
+
+static ssize_t comm_local_write(struct comm *cm, const char *buf, size_t len)
+{
+ cm->local= simple_strtol(buf, NULL, 0);
+ if (cm->local && !local_comm)
+ local_comm = cm;
+ return len;
+}
+
+static ssize_t comm_addr_write(struct comm *cm, const char *buf, size_t len)
+{
+ struct sockaddr_storage *addr;
+
+ if (len != sizeof(struct sockaddr_storage))
+ return -EINVAL;
+
+ if (cm->addr_count >= DLM_MAX_ADDR_COUNT)
+ return -ENOSPC;
+
+ addr = kzalloc(sizeof(*addr), GFP_KERNEL);
+ if (!addr)
+ return -ENOMEM;
+
+ memcpy(addr, buf, len);
+ cm->addr[cm->addr_count++] = addr;
+ return len;
+}
+
+static ssize_t show_node(struct config_item *i, struct configfs_attribute *a,
+ char *buf)
+{
+ struct node *nd = to_node(i);
+ struct node_attribute *nda =
+ container_of(a, struct node_attribute, attr);
+ return nda->show ? nda->show(nd, buf) : 0;
+}
+
+static ssize_t store_node(struct config_item *i, struct configfs_attribute *a,
+ const char *buf, size_t len)
+{
+ struct node *nd = to_node(i);
+ struct node_attribute *nda =
+ container_of(a, struct node_attribute, attr);
+ return nda->store ? nda->store(nd, buf, len) : -EINVAL;
+}
+
+static ssize_t node_nodeid_read(struct node *nd, char *buf)
+{
+ return sprintf(buf, "%d\n", nd->nodeid);
+}
+
+static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len)
+{
+ nd->nodeid = simple_strtol(buf, NULL, 0);
+ return len;
+}
+
+static ssize_t node_weight_read(struct node *nd, char *buf)
+{
+ return sprintf(buf, "%d\n", nd->weight);
+}
+
+static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len)
+{
+ nd->weight = simple_strtol(buf, NULL, 0);
+ return len;
+}
+
+/*
+ * Functions for the dlm to get the info that's been configured
+ */
+
+static struct space *get_space(char *name)
+{
+ if (!space_list)
+ return NULL;
+ return to_space(config_group_find_obj(space_list, name));
+}
+
+static void put_space(struct space *sp)
+{
+ config_item_put(&sp->group.cg_item);
+}
+
+static struct comm *get_comm(int nodeid, struct sockaddr_storage *addr)
+{
+ struct config_item *i;
+ struct comm *cm = NULL;
+ int found = 0;
+
+ if (!comm_list)
+ return NULL;
+
+ down(&clusters_root.subsys.su_sem);
+
+ list_for_each_entry(i, &comm_list->cg_children, ci_entry) {
+ cm = to_comm(i);
+
+ if (nodeid) {
+ if (cm->nodeid != nodeid)
+ continue;
+ found = 1;
+ break;
+ } else {
+ if (!cm->addr_count ||
+ memcmp(cm->addr[0], addr, sizeof(*addr)))
+ continue;
+ found = 1;
+ break;
+ }
+ }
+ up(&clusters_root.subsys.su_sem);
+
+ if (found)
+ config_item_get(i);
+ else
+ cm = NULL;
+ return cm;
+}
+
+static void put_comm(struct comm *cm)
+{
+ config_item_put(&cm->item);
+}
+
+/* caller must free mem */
+int dlm_nodeid_list(char *lsname, int **ids_out)
+{
+ struct space *sp;
+ struct node *nd;
+ int i = 0, rv = 0;
+ int *ids;
+
+ sp = get_space(lsname);
+ if (!sp)
+ return -EEXIST;
+
+ mutex_lock(&sp->members_lock);
+ if (!sp->members_count) {
+ rv = 0;
+ goto out;
+ }
+
+ ids = kcalloc(sp->members_count, sizeof(int), GFP_KERNEL);
+ if (!ids) {
+ rv = -ENOMEM;
+ goto out;
+ }
+
+ rv = sp->members_count;
+ list_for_each_entry(nd, &sp->members, list)
+ ids[i++] = nd->nodeid;
+
+ if (rv != i)
+ printk("bad nodeid count %d %d\n", rv, i);
+
+ *ids_out = ids;
+ out:
+ mutex_unlock(&sp->members_lock);
+ put_space(sp);
+ return rv;
+}
+
+int dlm_node_weight(char *lsname, int nodeid)
+{
+ struct space *sp;
+ struct node *nd;
+ int w = -EEXIST;
+
+ sp = get_space(lsname);
+ if (!sp)
+ goto out;
+
+ mutex_lock(&sp->members_lock);
+ list_for_each_entry(nd, &sp->members, list) {
+ if (nd->nodeid != nodeid)
+ continue;
+ w = nd->weight;
+ break;
+ }
+ mutex_unlock(&sp->members_lock);
+ put_space(sp);
+ out:
+ return w;
+}
+
+int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr)
+{
+ struct comm *cm = get_comm(nodeid, NULL);
+ if (!cm)
+ return -EEXIST;
+ if (!cm->addr_count)
+ return -ENOENT;
+ memcpy(addr, cm->addr[0], sizeof(*addr));
+ put_comm(cm);
+ return 0;
+}
+
+int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid)
+{
+ struct comm *cm = get_comm(0, addr);
+ if (!cm)
+ return -EEXIST;
+ *nodeid = cm->nodeid;
+ put_comm(cm);
+ return 0;
+}
+
+int dlm_our_nodeid(void)
+{
+ return local_comm ? local_comm->nodeid : 0;
+}
+
+/* num 0 is first addr, num 1 is second addr */
+int dlm_our_addr(struct sockaddr_storage *addr, int num)
+{
+ if (!local_comm)
+ return -1;
+ if (num + 1 > local_comm->addr_count)
+ return -1;
+ memcpy(addr, local_comm->addr[num], sizeof(*addr));
+ return 0;
+}
+
+/* Config file defaults */
+#define DEFAULT_TCP_PORT 21064
+#define DEFAULT_BUFFER_SIZE 4096
+#define DEFAULT_RSBTBL_SIZE 256
+#define DEFAULT_LKBTBL_SIZE 1024
+#define DEFAULT_DIRTBL_SIZE 512
+#define DEFAULT_RECOVER_TIMER 5
+#define DEFAULT_TOSS_SECS 10
+#define DEFAULT_SCAN_SECS 5
+
+struct dlm_config_info dlm_config = {
+ .tcp_port = DEFAULT_TCP_PORT,
+ .buffer_size = DEFAULT_BUFFER_SIZE,
+ .rsbtbl_size = DEFAULT_RSBTBL_SIZE,
+ .lkbtbl_size = DEFAULT_LKBTBL_SIZE,
+ .dirtbl_size = DEFAULT_DIRTBL_SIZE,
+ .recover_timer = DEFAULT_RECOVER_TIMER,
+ .toss_secs = DEFAULT_TOSS_SECS,
+ .scan_secs = DEFAULT_SCAN_SECS
+};
+
diff --git a/fs/dlm/config.h b/fs/dlm/config.h
new file mode 100644
index 000000000000..9da7839958a9
--- /dev/null
+++ b/fs/dlm/config.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __CONFIG_DOT_H__
+#define __CONFIG_DOT_H__
+
+#define DLM_MAX_ADDR_COUNT 3
+
+struct dlm_config_info {
+ int tcp_port;
+ int buffer_size;
+ int rsbtbl_size;
+ int lkbtbl_size;
+ int dirtbl_size;
+ int recover_timer;
+ int toss_secs;
+ int scan_secs;
+};
+
+extern struct dlm_config_info dlm_config;
+
+int dlm_config_init(void);
+void dlm_config_exit(void);
+int dlm_node_weight(char *lsname, int nodeid);
+int dlm_nodeid_list(char *lsname, int **ids_out);
+int dlm_nodeid_to_addr(int nodeid, struct sockaddr_storage *addr);
+int dlm_addr_to_nodeid(struct sockaddr_storage *addr, int *nodeid);
+int dlm_our_nodeid(void);
+int dlm_our_addr(struct sockaddr_storage *addr, int num);
+
+#endif /* __CONFIG_DOT_H__ */
+
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
new file mode 100644
index 000000000000..ca94a837a5bb
--- /dev/null
+++ b/fs/dlm/debug_fs.c
@@ -0,0 +1,387 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include <linux/pagemap.h>
+#include <linux/seq_file.h>
+#include <linux/module.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+
+#include "dlm_internal.h"
+
+#define DLM_DEBUG_BUF_LEN 4096
+static char debug_buf[DLM_DEBUG_BUF_LEN];
+static struct mutex debug_buf_lock;
+
+static struct dentry *dlm_root;
+
+struct rsb_iter {
+ int entry;
+ struct dlm_ls *ls;
+ struct list_head *next;
+ struct dlm_rsb *rsb;
+};
+
+/*
+ * dump all rsb's in the lockspace hash table
+ */
+
+static char *print_lockmode(int mode)
+{
+ switch (mode) {
+ case DLM_LOCK_IV:
+ return "--";
+ case DLM_LOCK_NL:
+ return "NL";
+ case DLM_LOCK_CR:
+ return "CR";
+ case DLM_LOCK_CW:
+ return "CW";
+ case DLM_LOCK_PR:
+ return "PR";
+ case DLM_LOCK_PW:
+ return "PW";
+ case DLM_LOCK_EX:
+ return "EX";
+ default:
+ return "??";
+ }
+}
+
+static void print_lock(struct seq_file *s, struct dlm_lkb *lkb,
+ struct dlm_rsb *res)
+{
+ seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
+
+ if (lkb->lkb_status == DLM_LKSTS_CONVERT
+ || lkb->lkb_status == DLM_LKSTS_WAITING)
+ seq_printf(s, " (%s)", print_lockmode(lkb->lkb_rqmode));
+
+ if (lkb->lkb_nodeid) {
+ if (lkb->lkb_nodeid != res->res_nodeid)
+ seq_printf(s, " Remote: %3d %08x", lkb->lkb_nodeid,
+ lkb->lkb_remid);
+ else
+ seq_printf(s, " Master: %08x", lkb->lkb_remid);
+ }
+
+ if (lkb->lkb_wait_type)
+ seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
+
+ seq_printf(s, "\n");
+}
+
+static int print_resource(struct dlm_rsb *res, struct seq_file *s)
+{
+ struct dlm_lkb *lkb;
+ int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
+
+ seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
+ for (i = 0; i < res->res_length; i++) {
+ if (isprint(res->res_name[i]))
+ seq_printf(s, "%c", res->res_name[i]);
+ else
+ seq_printf(s, "%c", '.');
+ }
+ if (res->res_nodeid > 0)
+ seq_printf(s, "\" \nLocal Copy, Master is node %d\n",
+ res->res_nodeid);
+ else if (res->res_nodeid == 0)
+ seq_printf(s, "\" \nMaster Copy\n");
+ else if (res->res_nodeid == -1)
+ seq_printf(s, "\" \nLooking up master (lkid %x)\n",
+ res->res_first_lkid);
+ else
+ seq_printf(s, "\" \nInvalid master %d\n", res->res_nodeid);
+
+ /* Print the LVB: */
+ if (res->res_lvbptr) {
+ seq_printf(s, "LVB: ");
+ for (i = 0; i < lvblen; i++) {
+ if (i == lvblen / 2)
+ seq_printf(s, "\n ");
+ seq_printf(s, "%02x ",
+ (unsigned char) res->res_lvbptr[i]);
+ }
+ if (rsb_flag(res, RSB_VALNOTVALID))
+ seq_printf(s, " (INVALID)");
+ seq_printf(s, "\n");
+ }
+
+ root_list = !list_empty(&res->res_root_list);
+ recover_list = !list_empty(&res->res_recover_list);
+
+ if (root_list || recover_list) {
+ seq_printf(s, "Recovery: root %d recover %d flags %lx "
+ "count %d\n", root_list, recover_list,
+ res->res_flags, res->res_recover_locks_count);
+ }
+
+ /* Print the locks attached to this resource */
+ seq_printf(s, "Granted Queue\n");
+ list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue)
+ print_lock(s, lkb, res);
+
+ seq_printf(s, "Conversion Queue\n");
+ list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue)
+ print_lock(s, lkb, res);
+
+ seq_printf(s, "Waiting Queue\n");
+ list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue)
+ print_lock(s, lkb, res);
+
+ if (list_empty(&res->res_lookup))
+ goto out;
+
+ seq_printf(s, "Lookup Queue\n");
+ list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
+ seq_printf(s, "%08x %s", lkb->lkb_id,
+ print_lockmode(lkb->lkb_rqmode));
+ if (lkb->lkb_wait_type)
+ seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
+ seq_printf(s, "\n");
+ }
+ out:
+ return 0;
+}
+
+static int rsb_iter_next(struct rsb_iter *ri)
+{
+ struct dlm_ls *ls = ri->ls;
+ int i;
+
+ if (!ri->next) {
+ top:
+ /* Find the next non-empty hash bucket */
+ for (i = ri->entry; i < ls->ls_rsbtbl_size; i++) {
+ read_lock(&ls->ls_rsbtbl[i].lock);
+ if (!list_empty(&ls->ls_rsbtbl[i].list)) {
+ ri->next = ls->ls_rsbtbl[i].list.next;
+ read_unlock(&ls->ls_rsbtbl[i].lock);
+ break;
+ }
+ read_unlock(&ls->ls_rsbtbl[i].lock);
+ }
+ ri->entry = i;
+
+ if (ri->entry >= ls->ls_rsbtbl_size)
+ return 1;
+ } else {
+ i = ri->entry;
+ read_lock(&ls->ls_rsbtbl[i].lock);
+ ri->next = ri->next->next;
+ if (ri->next->next == ls->ls_rsbtbl[i].list.next) {
+ /* End of list - move to next bucket */
+ ri->next = NULL;
+ ri->entry++;
+ read_unlock(&ls->ls_rsbtbl[i].lock);
+ goto top;
+ }
+ read_unlock(&ls->ls_rsbtbl[i].lock);
+ }
+ ri->rsb = list_entry(ri->next, struct dlm_rsb, res_hashchain);
+
+ return 0;
+}
+
+static void rsb_iter_free(struct rsb_iter *ri)
+{
+ kfree(ri);
+}
+
+static struct rsb_iter *rsb_iter_init(struct dlm_ls *ls)
+{
+ struct rsb_iter *ri;
+
+ ri = kmalloc(sizeof *ri, GFP_KERNEL);
+ if (!ri)
+ return NULL;
+
+ ri->ls = ls;
+ ri->entry = 0;
+ ri->next = NULL;
+
+ if (rsb_iter_next(ri)) {
+ rsb_iter_free(ri);
+ return NULL;
+ }
+
+ return ri;
+}
+
+static void *rsb_seq_start(struct seq_file *file, loff_t *pos)
+{
+ struct rsb_iter *ri;
+ loff_t n = *pos;
+
+ ri = rsb_iter_init(file->private);
+ if (!ri)
+ return NULL;
+
+ while (n--) {
+ if (rsb_iter_next(ri)) {
+ rsb_iter_free(ri);
+ return NULL;
+ }
+ }
+
+ return ri;
+}
+
+static void *rsb_seq_next(struct seq_file *file, void *iter_ptr, loff_t *pos)
+{
+ struct rsb_iter *ri = iter_ptr;
+
+ (*pos)++;
+
+ if (rsb_iter_next(ri)) {
+ rsb_iter_free(ri);
+ return NULL;
+ }
+
+ return ri;
+}
+
+static void rsb_seq_stop(struct seq_file *file, void *iter_ptr)
+{
+ /* nothing for now */
+}
+
+static int rsb_seq_show(struct seq_file *file, void *iter_ptr)
+{
+ struct rsb_iter *ri = iter_ptr;
+
+ print_resource(ri->rsb, file);
+
+ return 0;
+}
+
+static struct seq_operations rsb_seq_ops = {
+ .start = rsb_seq_start,
+ .next = rsb_seq_next,
+ .stop = rsb_seq_stop,
+ .show = rsb_seq_show,
+};
+
+static int rsb_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int ret;
+
+ ret = seq_open(file, &rsb_seq_ops);
+ if (ret)
+ return ret;
+
+ seq = file->private_data;
+ seq->private = inode->i_private;
+
+ return 0;
+}
+
+static struct file_operations rsb_fops = {
+ .owner = THIS_MODULE,
+ .open = rsb_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+/*
+ * dump lkb's on the ls_waiters list
+ */
+
+static int waiters_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+ return 0;
+}
+
+static ssize_t waiters_read(struct file *file, char __user *userbuf,
+ size_t count, loff_t *ppos)
+{
+ struct dlm_ls *ls = file->private_data;
+ struct dlm_lkb *lkb;
+ size_t len = DLM_DEBUG_BUF_LEN, pos = 0, ret, rv;
+
+ mutex_lock(&debug_buf_lock);
+ mutex_lock(&ls->ls_waiters_mutex);
+ memset(debug_buf, 0, sizeof(debug_buf));
+
+ list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+ ret = snprintf(debug_buf + pos, len - pos, "%x %d %d %s\n",
+ lkb->lkb_id, lkb->lkb_wait_type,
+ lkb->lkb_nodeid, lkb->lkb_resource->res_name);
+ if (ret >= len - pos)
+ break;
+ pos += ret;
+ }
+ mutex_unlock(&ls->ls_waiters_mutex);
+
+ rv = simple_read_from_buffer(userbuf, count, ppos, debug_buf, pos);
+ mutex_unlock(&debug_buf_lock);
+ return rv;
+}
+
+static struct file_operations waiters_fops = {
+ .owner = THIS_MODULE,
+ .open = waiters_open,
+ .read = waiters_read
+};
+
+int dlm_create_debug_file(struct dlm_ls *ls)
+{
+ char name[DLM_LOCKSPACE_LEN+8];
+
+ ls->ls_debug_rsb_dentry = debugfs_create_file(ls->ls_name,
+ S_IFREG | S_IRUGO,
+ dlm_root,
+ ls,
+ &rsb_fops);
+ if (!ls->ls_debug_rsb_dentry)
+ return -ENOMEM;
+
+ memset(name, 0, sizeof(name));
+ snprintf(name, DLM_LOCKSPACE_LEN+8, "%s_waiters", ls->ls_name);
+
+ ls->ls_debug_waiters_dentry = debugfs_create_file(name,
+ S_IFREG | S_IRUGO,
+ dlm_root,
+ ls,
+ &waiters_fops);
+ if (!ls->ls_debug_waiters_dentry) {
+ debugfs_remove(ls->ls_debug_rsb_dentry);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void dlm_delete_debug_file(struct dlm_ls *ls)
+{
+ if (ls->ls_debug_rsb_dentry)
+ debugfs_remove(ls->ls_debug_rsb_dentry);
+ if (ls->ls_debug_waiters_dentry)
+ debugfs_remove(ls->ls_debug_waiters_dentry);
+}
+
+int dlm_register_debugfs(void)
+{
+ mutex_init(&debug_buf_lock);
+ dlm_root = debugfs_create_dir("dlm", NULL);
+ return dlm_root ? 0 : -ENOMEM;
+}
+
+void dlm_unregister_debugfs(void)
+{
+ debugfs_remove(dlm_root);
+}
+
diff --git a/fs/dlm/dir.c b/fs/dlm/dir.c
new file mode 100644
index 000000000000..46754553fdcc
--- /dev/null
+++ b/fs/dlm/dir.c
@@ -0,0 +1,423 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "lowcomms.h"
+#include "rcom.h"
+#include "config.h"
+#include "memory.h"
+#include "recover.h"
+#include "util.h"
+#include "lock.h"
+#include "dir.h"
+
+
+static void put_free_de(struct dlm_ls *ls, struct dlm_direntry *de)
+{
+ spin_lock(&ls->ls_recover_list_lock);
+ list_add(&de->list, &ls->ls_recover_list);
+ spin_unlock(&ls->ls_recover_list_lock);
+}
+
+static struct dlm_direntry *get_free_de(struct dlm_ls *ls, int len)
+{
+ int found = 0;
+ struct dlm_direntry *de;
+
+ spin_lock(&ls->ls_recover_list_lock);
+ list_for_each_entry(de, &ls->ls_recover_list, list) {
+ if (de->length == len) {
+ list_del(&de->list);
+ de->master_nodeid = 0;
+ memset(de->name, 0, len);
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock(&ls->ls_recover_list_lock);
+
+ if (!found)
+ de = allocate_direntry(ls, len);
+ return de;
+}
+
+void dlm_clear_free_entries(struct dlm_ls *ls)
+{
+ struct dlm_direntry *de;
+
+ spin_lock(&ls->ls_recover_list_lock);
+ while (!list_empty(&ls->ls_recover_list)) {
+ de = list_entry(ls->ls_recover_list.next, struct dlm_direntry,
+ list);
+ list_del(&de->list);
+ free_direntry(de);
+ }
+ spin_unlock(&ls->ls_recover_list_lock);
+}
+
+/*
+ * We use the upper 16 bits of the hash value to select the directory node.
+ * Low bits are used for distribution of rsb's among hash buckets on each node.
+ *
+ * To give the exact range wanted (0 to num_nodes-1), we apply a modulus of
+ * num_nodes to the hash value. This value in the desired range is used as an
+ * offset into the sorted list of nodeid's to give the particular nodeid.
+ */
+
+int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash)
+{
+ struct list_head *tmp;
+ struct dlm_member *memb = NULL;
+ uint32_t node, n = 0;
+ int nodeid;
+
+ if (ls->ls_num_nodes == 1) {
+ nodeid = dlm_our_nodeid();
+ goto out;
+ }
+
+ if (ls->ls_node_array) {
+ node = (hash >> 16) % ls->ls_total_weight;
+ nodeid = ls->ls_node_array[node];
+ goto out;
+ }
+
+ /* make_member_array() failed to kmalloc ls_node_array... */
+
+ node = (hash >> 16) % ls->ls_num_nodes;
+
+ list_for_each(tmp, &ls->ls_nodes) {
+ if (n++ != node)
+ continue;
+ memb = list_entry(tmp, struct dlm_member, list);
+ break;
+ }
+
+ DLM_ASSERT(memb , printk("num_nodes=%u n=%u node=%u\n",
+ ls->ls_num_nodes, n, node););
+ nodeid = memb->nodeid;
+ out:
+ return nodeid;
+}
+
+int dlm_dir_nodeid(struct dlm_rsb *r)
+{
+ return dlm_hash2nodeid(r->res_ls, r->res_hash);
+}
+
+static inline uint32_t dir_hash(struct dlm_ls *ls, char *name, int len)
+{
+ uint32_t val;
+
+ val = jhash(name, len, 0);
+ val &= (ls->ls_dirtbl_size - 1);
+
+ return val;
+}
+
+static void add_entry_to_hash(struct dlm_ls *ls, struct dlm_direntry *de)
+{
+ uint32_t bucket;
+
+ bucket = dir_hash(ls, de->name, de->length);
+ list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
+}
+
+static struct dlm_direntry *search_bucket(struct dlm_ls *ls, char *name,
+ int namelen, uint32_t bucket)
+{
+ struct dlm_direntry *de;
+
+ list_for_each_entry(de, &ls->ls_dirtbl[bucket].list, list) {
+ if (de->length == namelen && !memcmp(name, de->name, namelen))
+ goto out;
+ }
+ de = NULL;
+ out:
+ return de;
+}
+
+void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int namelen)
+{
+ struct dlm_direntry *de;
+ uint32_t bucket;
+
+ bucket = dir_hash(ls, name, namelen);
+
+ write_lock(&ls->ls_dirtbl[bucket].lock);
+
+ de = search_bucket(ls, name, namelen, bucket);
+
+ if (!de) {
+ log_error(ls, "remove fr %u none", nodeid);
+ goto out;
+ }
+
+ if (de->master_nodeid != nodeid) {
+ log_error(ls, "remove fr %u ID %u", nodeid, de->master_nodeid);
+ goto out;
+ }
+
+ list_del(&de->list);
+ free_direntry(de);
+ out:
+ write_unlock(&ls->ls_dirtbl[bucket].lock);
+}
+
+void dlm_dir_clear(struct dlm_ls *ls)
+{
+ struct list_head *head;
+ struct dlm_direntry *de;
+ int i;
+
+ DLM_ASSERT(list_empty(&ls->ls_recover_list), );
+
+ for (i = 0; i < ls->ls_dirtbl_size; i++) {
+ write_lock(&ls->ls_dirtbl[i].lock);
+ head = &ls->ls_dirtbl[i].list;
+ while (!list_empty(head)) {
+ de = list_entry(head->next, struct dlm_direntry, list);
+ list_del(&de->list);
+ put_free_de(ls, de);
+ }
+ write_unlock(&ls->ls_dirtbl[i].lock);
+ }
+}
+
+int dlm_recover_directory(struct dlm_ls *ls)
+{
+ struct dlm_member *memb;
+ struct dlm_direntry *de;
+ char *b, *last_name = NULL;
+ int error = -ENOMEM, last_len, count = 0;
+ uint16_t namelen;
+
+ log_debug(ls, "dlm_recover_directory");
+
+ if (dlm_no_directory(ls))
+ goto out_status;
+
+ dlm_dir_clear(ls);
+
+ last_name = kmalloc(DLM_RESNAME_MAXLEN, GFP_KERNEL);
+ if (!last_name)
+ goto out;
+
+ list_for_each_entry(memb, &ls->ls_nodes, list) {
+ memset(last_name, 0, DLM_RESNAME_MAXLEN);
+ last_len = 0;
+
+ for (;;) {
+ error = dlm_recovery_stopped(ls);
+ if (error)
+ goto out_free;
+
+ error = dlm_rcom_names(ls, memb->nodeid,
+ last_name, last_len);
+ if (error)
+ goto out_free;
+
+ schedule();
+
+ /*
+ * pick namelen/name pairs out of received buffer
+ */
+
+ b = ls->ls_recover_buf + sizeof(struct dlm_rcom);
+
+ for (;;) {
+ memcpy(&namelen, b, sizeof(uint16_t));
+ namelen = be16_to_cpu(namelen);
+ b += sizeof(uint16_t);
+
+ /* namelen of 0xFFFFF marks end of names for
+ this node; namelen of 0 marks end of the
+ buffer */
+
+ if (namelen == 0xFFFF)
+ goto done;
+ if (!namelen)
+ break;
+
+ error = -ENOMEM;
+ de = get_free_de(ls, namelen);
+ if (!de)
+ goto out_free;
+
+ de->master_nodeid = memb->nodeid;
+ de->length = namelen;
+ last_len = namelen;
+ memcpy(de->name, b, namelen);
+ memcpy(last_name, b, namelen);
+ b += namelen;
+
+ add_entry_to_hash(ls, de);
+ count++;
+ }
+ }
+ done:
+ ;
+ }
+
+ out_status:
+ error = 0;
+ dlm_set_recover_status(ls, DLM_RS_DIR);
+ log_debug(ls, "dlm_recover_directory %d entries", count);
+ out_free:
+ kfree(last_name);
+ out:
+ dlm_clear_free_entries(ls);
+ return error;
+}
+
+static int get_entry(struct dlm_ls *ls, int nodeid, char *name,
+ int namelen, int *r_nodeid)
+{
+ struct dlm_direntry *de, *tmp;
+ uint32_t bucket;
+
+ bucket = dir_hash(ls, name, namelen);
+
+ write_lock(&ls->ls_dirtbl[bucket].lock);
+ de = search_bucket(ls, name, namelen, bucket);
+ if (de) {
+ *r_nodeid = de->master_nodeid;
+ write_unlock(&ls->ls_dirtbl[bucket].lock);
+ if (*r_nodeid == nodeid)
+ return -EEXIST;
+ return 0;
+ }
+
+ write_unlock(&ls->ls_dirtbl[bucket].lock);
+
+ de = allocate_direntry(ls, namelen);
+ if (!de)
+ return -ENOMEM;
+
+ de->master_nodeid = nodeid;
+ de->length = namelen;
+ memcpy(de->name, name, namelen);
+
+ write_lock(&ls->ls_dirtbl[bucket].lock);
+ tmp = search_bucket(ls, name, namelen, bucket);
+ if (tmp) {
+ free_direntry(de);
+ de = tmp;
+ } else {
+ list_add_tail(&de->list, &ls->ls_dirtbl[bucket].list);
+ }
+ *r_nodeid = de->master_nodeid;
+ write_unlock(&ls->ls_dirtbl[bucket].lock);
+ return 0;
+}
+
+int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
+ int *r_nodeid)
+{
+ return get_entry(ls, nodeid, name, namelen, r_nodeid);
+}
+
+/* Copy the names of master rsb's into the buffer provided.
+ Only select names whose dir node is the given nodeid. */
+
+void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
+ char *outbuf, int outlen, int nodeid)
+{
+ struct list_head *list;
+ struct dlm_rsb *start_r = NULL, *r = NULL;
+ int offset = 0, start_namelen, error, dir_nodeid;
+ char *start_name;
+ uint16_t be_namelen;
+
+ /*
+ * Find the rsb where we left off (or start again)
+ */
+
+ start_namelen = inlen;
+ start_name = inbuf;
+
+ if (start_namelen > 1) {
+ /*
+ * We could also use a find_rsb_root() function here that
+ * searched the ls_root_list.
+ */
+ error = dlm_find_rsb(ls, start_name, start_namelen, R_MASTER,
+ &start_r);
+ DLM_ASSERT(!error && start_r,
+ printk("error %d\n", error););
+ DLM_ASSERT(!list_empty(&start_r->res_root_list),
+ dlm_print_rsb(start_r););
+ dlm_put_rsb(start_r);
+ }
+
+ /*
+ * Send rsb names for rsb's we're master of and whose directory node
+ * matches the requesting node.
+ */
+
+ down_read(&ls->ls_root_sem);
+ if (start_r)
+ list = start_r->res_root_list.next;
+ else
+ list = ls->ls_root_list.next;
+
+ for (offset = 0; list != &ls->ls_root_list; list = list->next) {
+ r = list_entry(list, struct dlm_rsb, res_root_list);
+ if (r->res_nodeid)
+ continue;
+
+ dir_nodeid = dlm_dir_nodeid(r);
+ if (dir_nodeid != nodeid)
+ continue;
+
+ /*
+ * The block ends when we can't fit the following in the
+ * remaining buffer space:
+ * namelen (uint16_t) +
+ * name (r->res_length) +
+ * end-of-block record 0x0000 (uint16_t)
+ */
+
+ if (offset + sizeof(uint16_t)*2 + r->res_length > outlen) {
+ /* Write end-of-block record */
+ be_namelen = 0;
+ memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ goto out;
+ }
+
+ be_namelen = cpu_to_be16(r->res_length);
+ memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ memcpy(outbuf + offset, r->res_name, r->res_length);
+ offset += r->res_length;
+ }
+
+ /*
+ * If we've reached the end of the list (and there's room) write a
+ * terminating record.
+ */
+
+ if ((list == &ls->ls_root_list) &&
+ (offset + sizeof(uint16_t) <= outlen)) {
+ be_namelen = 0xFFFF;
+ memcpy(outbuf + offset, &be_namelen, sizeof(uint16_t));
+ offset += sizeof(uint16_t);
+ }
+
+ out:
+ up_read(&ls->ls_root_sem);
+}
+
diff --git a/fs/dlm/dir.h b/fs/dlm/dir.h
new file mode 100644
index 000000000000..0b0eb1267b6e
--- /dev/null
+++ b/fs/dlm/dir.h
@@ -0,0 +1,30 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DIR_DOT_H__
+#define __DIR_DOT_H__
+
+
+int dlm_dir_nodeid(struct dlm_rsb *rsb);
+int dlm_hash2nodeid(struct dlm_ls *ls, uint32_t hash);
+void dlm_dir_remove_entry(struct dlm_ls *ls, int nodeid, char *name, int len);
+void dlm_dir_clear(struct dlm_ls *ls);
+void dlm_clear_free_entries(struct dlm_ls *ls);
+int dlm_recover_directory(struct dlm_ls *ls);
+int dlm_dir_lookup(struct dlm_ls *ls, int nodeid, char *name, int namelen,
+ int *r_nodeid);
+void dlm_copy_master_names(struct dlm_ls *ls, char *inbuf, int inlen,
+ char *outbuf, int outlen, int nodeid);
+
+#endif /* __DIR_DOT_H__ */
+
diff --git a/fs/dlm/dlm_internal.h b/fs/dlm/dlm_internal.h
new file mode 100644
index 000000000000..1e5cd67e1b7a
--- /dev/null
+++ b/fs/dlm/dlm_internal.h
@@ -0,0 +1,543 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DLM_INTERNAL_DOT_H__
+#define __DLM_INTERNAL_DOT_H__
+
+/*
+ * This is the main header file to be included in each DLM source file.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/random.h>
+#include <linux/delay.h>
+#include <linux/socket.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/kref.h>
+#include <linux/kernel.h>
+#include <linux/jhash.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <linux/dlm.h>
+
+#define DLM_LOCKSPACE_LEN 64
+
+/* Size of the temp buffer midcomms allocates on the stack.
+ We try to make this large enough so most messages fit.
+ FIXME: should sctp make this unnecessary? */
+
+#define DLM_INBUF_LEN 148
+
+struct dlm_ls;
+struct dlm_lkb;
+struct dlm_rsb;
+struct dlm_member;
+struct dlm_lkbtable;
+struct dlm_rsbtable;
+struct dlm_dirtable;
+struct dlm_direntry;
+struct dlm_recover;
+struct dlm_header;
+struct dlm_message;
+struct dlm_rcom;
+struct dlm_mhandle;
+
+#define log_print(fmt, args...) \
+ printk(KERN_ERR "dlm: "fmt"\n" , ##args)
+#define log_error(ls, fmt, args...) \
+ printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args)
+
+#define DLM_LOG_DEBUG
+#ifdef DLM_LOG_DEBUG
+#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args)
+#else
+#define log_debug(ls, fmt, args...)
+#endif
+
+#define DLM_ASSERT(x, do) \
+{ \
+ if (!(x)) \
+ { \
+ printk(KERN_ERR "\nDLM: Assertion failed on line %d of file %s\n" \
+ "DLM: assertion: \"%s\"\n" \
+ "DLM: time = %lu\n", \
+ __LINE__, __FILE__, #x, jiffies); \
+ {do} \
+ printk("\n"); \
+ BUG(); \
+ panic("DLM: Record message above and reboot.\n"); \
+ } \
+}
+
+#define DLM_FAKE_USER_AST ERR_PTR(-EINVAL)
+
+
+struct dlm_direntry {
+ struct list_head list;
+ uint32_t master_nodeid;
+ uint16_t length;
+ char name[1];
+};
+
+struct dlm_dirtable {
+ struct list_head list;
+ rwlock_t lock;
+};
+
+struct dlm_rsbtable {
+ struct list_head list;
+ struct list_head toss;
+ rwlock_t lock;
+};
+
+struct dlm_lkbtable {
+ struct list_head list;
+ rwlock_t lock;
+ uint16_t counter;
+};
+
+/*
+ * Lockspace member (per node in a ls)
+ */
+
+struct dlm_member {
+ struct list_head list;
+ int nodeid;
+ int weight;
+};
+
+/*
+ * Save and manage recovery state for a lockspace.
+ */
+
+struct dlm_recover {
+ struct list_head list;
+ int *nodeids;
+ int node_count;
+ uint64_t seq;
+};
+
+/*
+ * Pass input args to second stage locking function.
+ */
+
+struct dlm_args {
+ uint32_t flags;
+ void *astaddr;
+ long astparam;
+ void *bastaddr;
+ int mode;
+ struct dlm_lksb *lksb;
+};
+
+
+/*
+ * Lock block
+ *
+ * A lock can be one of three types:
+ *
+ * local copy lock is mastered locally
+ * (lkb_nodeid is zero and DLM_LKF_MSTCPY is not set)
+ * process copy lock is mastered on a remote node
+ * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is not set)
+ * master copy master node's copy of a lock owned by remote node
+ * (lkb_nodeid is non-zero and DLM_LKF_MSTCPY is set)
+ *
+ * lkb_exflags: a copy of the most recent flags arg provided to dlm_lock or
+ * dlm_unlock. The dlm does not modify these or use any private flags in
+ * this field; it only contains DLM_LKF_ flags from dlm.h. These flags
+ * are sent as-is to the remote master when the lock is remote.
+ *
+ * lkb_flags: internal dlm flags (DLM_IFL_ prefix) from dlm_internal.h.
+ * Some internal flags are shared between the master and process nodes;
+ * these shared flags are kept in the lower two bytes. One of these
+ * flags set on the master copy will be propagated to the process copy
+ * and v.v. Other internal flags are private to the master or process
+ * node (e.g. DLM_IFL_MSTCPY). These are kept in the high two bytes.
+ *
+ * lkb_sbflags: status block flags. These flags are copied directly into
+ * the caller's lksb.sb_flags prior to the dlm_lock/dlm_unlock completion
+ * ast. All defined in dlm.h with DLM_SBF_ prefix.
+ *
+ * lkb_status: the lock status indicates which rsb queue the lock is
+ * on, grant, convert, or wait. DLM_LKSTS_ WAITING/GRANTED/CONVERT
+ *
+ * lkb_wait_type: the dlm message type (DLM_MSG_ prefix) for which a
+ * reply is needed. Only set when the lkb is on the lockspace waiters
+ * list awaiting a reply from a remote node.
+ *
+ * lkb_nodeid: when the lkb is a local copy, nodeid is 0; when the lkb
+ * is a master copy, nodeid specifies the remote lock holder, when the
+ * lkb is a process copy, the nodeid specifies the lock master.
+ */
+
+/* lkb_ast_type */
+
+#define AST_COMP 1
+#define AST_BAST 2
+
+/* lkb_status */
+
+#define DLM_LKSTS_WAITING 1
+#define DLM_LKSTS_GRANTED 2
+#define DLM_LKSTS_CONVERT 3
+
+/* lkb_flags */
+
+#define DLM_IFL_MSTCPY 0x00010000
+#define DLM_IFL_RESEND 0x00020000
+#define DLM_IFL_DEAD 0x00040000
+#define DLM_IFL_USER 0x00000001
+#define DLM_IFL_ORPHAN 0x00000002
+
+struct dlm_lkb {
+ struct dlm_rsb *lkb_resource; /* the rsb */
+ struct kref lkb_ref;
+ int lkb_nodeid; /* copied from rsb */
+ int lkb_ownpid; /* pid of lock owner */
+ uint32_t lkb_id; /* our lock ID */
+ uint32_t lkb_remid; /* lock ID on remote partner */
+ uint32_t lkb_exflags; /* external flags from caller */
+ uint32_t lkb_sbflags; /* lksb flags */
+ uint32_t lkb_flags; /* internal flags */
+ uint32_t lkb_lvbseq; /* lvb sequence number */
+
+ int8_t lkb_status; /* granted, waiting, convert */
+ int8_t lkb_rqmode; /* requested lock mode */
+ int8_t lkb_grmode; /* granted lock mode */
+ int8_t lkb_bastmode; /* requested mode */
+ int8_t lkb_highbast; /* highest mode bast sent for */
+
+ int8_t lkb_wait_type; /* type of reply waiting for */
+ int8_t lkb_ast_type; /* type of ast queued for */
+
+ struct list_head lkb_idtbl_list; /* lockspace lkbtbl */
+ struct list_head lkb_statequeue; /* rsb g/c/w list */
+ struct list_head lkb_rsb_lookup; /* waiting for rsb lookup */
+ struct list_head lkb_wait_reply; /* waiting for remote reply */
+ struct list_head lkb_astqueue; /* need ast to be sent */
+ struct list_head lkb_ownqueue; /* list of locks for a process */
+
+ char *lkb_lvbptr;
+ struct dlm_lksb *lkb_lksb; /* caller's status block */
+ void *lkb_astaddr; /* caller's ast function */
+ void *lkb_bastaddr; /* caller's bast function */
+ long lkb_astparam; /* caller's ast arg */
+};
+
+
+struct dlm_rsb {
+ struct dlm_ls *res_ls; /* the lockspace */
+ struct kref res_ref;
+ struct mutex res_mutex;
+ unsigned long res_flags;
+ int res_length; /* length of rsb name */
+ int res_nodeid;
+ uint32_t res_lvbseq;
+ uint32_t res_hash;
+ uint32_t res_bucket; /* rsbtbl */
+ unsigned long res_toss_time;
+ uint32_t res_first_lkid;
+ struct list_head res_lookup; /* lkbs waiting on first */
+ struct list_head res_hashchain; /* rsbtbl */
+ struct list_head res_grantqueue;
+ struct list_head res_convertqueue;
+ struct list_head res_waitqueue;
+
+ struct list_head res_root_list; /* used for recovery */
+ struct list_head res_recover_list; /* used for recovery */
+ int res_recover_locks_count;
+
+ char *res_lvbptr;
+ char res_name[1];
+};
+
+/* find_rsb() flags */
+
+#define R_MASTER 1 /* only return rsb if it's a master */
+#define R_CREATE 2 /* create/add rsb if not found */
+
+/* rsb_flags */
+
+enum rsb_flags {
+ RSB_MASTER_UNCERTAIN,
+ RSB_VALNOTVALID,
+ RSB_VALNOTVALID_PREV,
+ RSB_NEW_MASTER,
+ RSB_NEW_MASTER2,
+ RSB_RECOVER_CONVERT,
+ RSB_LOCKS_PURGED,
+};
+
+static inline void rsb_set_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+ __set_bit(flag, &r->res_flags);
+}
+
+static inline void rsb_clear_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+ __clear_bit(flag, &r->res_flags);
+}
+
+static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)
+{
+ return test_bit(flag, &r->res_flags);
+}
+
+
+/* dlm_header is first element of all structs sent between nodes */
+
+#define DLM_HEADER_MAJOR 0x00020000
+#define DLM_HEADER_MINOR 0x00000001
+
+#define DLM_MSG 1
+#define DLM_RCOM 2
+
+struct dlm_header {
+ uint32_t h_version;
+ uint32_t h_lockspace;
+ uint32_t h_nodeid; /* nodeid of sender */
+ uint16_t h_length;
+ uint8_t h_cmd; /* DLM_MSG, DLM_RCOM */
+ uint8_t h_pad;
+};
+
+
+#define DLM_MSG_REQUEST 1
+#define DLM_MSG_CONVERT 2
+#define DLM_MSG_UNLOCK 3
+#define DLM_MSG_CANCEL 4
+#define DLM_MSG_REQUEST_REPLY 5
+#define DLM_MSG_CONVERT_REPLY 6
+#define DLM_MSG_UNLOCK_REPLY 7
+#define DLM_MSG_CANCEL_REPLY 8
+#define DLM_MSG_GRANT 9
+#define DLM_MSG_BAST 10
+#define DLM_MSG_LOOKUP 11
+#define DLM_MSG_REMOVE 12
+#define DLM_MSG_LOOKUP_REPLY 13
+
+struct dlm_message {
+ struct dlm_header m_header;
+ uint32_t m_type; /* DLM_MSG_ */
+ uint32_t m_nodeid;
+ uint32_t m_pid;
+ uint32_t m_lkid; /* lkid on sender */
+ uint32_t m_remid; /* lkid on receiver */
+ uint32_t m_parent_lkid;
+ uint32_t m_parent_remid;
+ uint32_t m_exflags;
+ uint32_t m_sbflags;
+ uint32_t m_flags;
+ uint32_t m_lvbseq;
+ uint32_t m_hash;
+ int m_status;
+ int m_grmode;
+ int m_rqmode;
+ int m_bastmode;
+ int m_asts;
+ int m_result; /* 0 or -EXXX */
+ char m_extra[0]; /* name or lvb */
+};
+
+
+#define DLM_RS_NODES 0x00000001
+#define DLM_RS_NODES_ALL 0x00000002
+#define DLM_RS_DIR 0x00000004
+#define DLM_RS_DIR_ALL 0x00000008
+#define DLM_RS_LOCKS 0x00000010
+#define DLM_RS_LOCKS_ALL 0x00000020
+#define DLM_RS_DONE 0x00000040
+#define DLM_RS_DONE_ALL 0x00000080
+
+#define DLM_RCOM_STATUS 1
+#define DLM_RCOM_NAMES 2
+#define DLM_RCOM_LOOKUP 3
+#define DLM_RCOM_LOCK 4
+#define DLM_RCOM_STATUS_REPLY 5
+#define DLM_RCOM_NAMES_REPLY 6
+#define DLM_RCOM_LOOKUP_REPLY 7
+#define DLM_RCOM_LOCK_REPLY 8
+
+struct dlm_rcom {
+ struct dlm_header rc_header;
+ uint32_t rc_type; /* DLM_RCOM_ */
+ int rc_result; /* multi-purpose */
+ uint64_t rc_id; /* match reply with request */
+ char rc_buf[0];
+};
+
+struct rcom_config {
+ uint32_t rf_lvblen;
+ uint32_t rf_lsflags;
+ uint64_t rf_unused;
+};
+
+struct rcom_lock {
+ uint32_t rl_ownpid;
+ uint32_t rl_lkid;
+ uint32_t rl_remid;
+ uint32_t rl_parent_lkid;
+ uint32_t rl_parent_remid;
+ uint32_t rl_exflags;
+ uint32_t rl_flags;
+ uint32_t rl_lvbseq;
+ int rl_result;
+ int8_t rl_rqmode;
+ int8_t rl_grmode;
+ int8_t rl_status;
+ int8_t rl_asts;
+ uint16_t rl_wait_type;
+ uint16_t rl_namelen;
+ char rl_name[DLM_RESNAME_MAXLEN];
+ char rl_lvb[0];
+};
+
+struct dlm_ls {
+ struct list_head ls_list; /* list of lockspaces */
+ dlm_lockspace_t *ls_local_handle;
+ uint32_t ls_global_id; /* global unique lockspace ID */
+ uint32_t ls_exflags;
+ int ls_lvblen;
+ int ls_count; /* reference count */
+ unsigned long ls_flags; /* LSFL_ */
+ struct kobject ls_kobj;
+
+ struct dlm_rsbtable *ls_rsbtbl;
+ uint32_t ls_rsbtbl_size;
+
+ struct dlm_lkbtable *ls_lkbtbl;
+ uint32_t ls_lkbtbl_size;
+
+ struct dlm_dirtable *ls_dirtbl;
+ uint32_t ls_dirtbl_size;
+
+ struct mutex ls_waiters_mutex;
+ struct list_head ls_waiters; /* lkbs needing a reply */
+
+ struct list_head ls_nodes; /* current nodes in ls */
+ struct list_head ls_nodes_gone; /* dead node list, recovery */
+ int ls_num_nodes; /* number of nodes in ls */
+ int ls_low_nodeid;
+ int ls_total_weight;
+ int *ls_node_array;
+
+ struct dlm_rsb ls_stub_rsb; /* for returning errors */
+ struct dlm_lkb ls_stub_lkb; /* for returning errors */
+ struct dlm_message ls_stub_ms; /* for faking a reply */
+
+ struct dentry *ls_debug_rsb_dentry; /* debugfs */
+ struct dentry *ls_debug_waiters_dentry; /* debugfs */
+
+ wait_queue_head_t ls_uevent_wait; /* user part of join/leave */
+ int ls_uevent_result;
+
+ struct miscdevice ls_device;
+
+ /* recovery related */
+
+ struct timer_list ls_timer;
+ struct task_struct *ls_recoverd_task;
+ struct mutex ls_recoverd_active;
+ spinlock_t ls_recover_lock;
+ uint32_t ls_recover_status; /* DLM_RS_ */
+ uint64_t ls_recover_seq;
+ struct dlm_recover *ls_recover_args;
+ struct rw_semaphore ls_in_recovery; /* block local requests */
+ struct list_head ls_requestqueue;/* queue remote requests */
+ struct mutex ls_requestqueue_mutex;
+ char *ls_recover_buf;
+ int ls_recover_nodeid; /* for debugging */
+ uint64_t ls_rcom_seq;
+ struct list_head ls_recover_list;
+ spinlock_t ls_recover_list_lock;
+ int ls_recover_list_count;
+ wait_queue_head_t ls_wait_general;
+ struct mutex ls_clear_proc_locks;
+
+ struct list_head ls_root_list; /* root resources */
+ struct rw_semaphore ls_root_sem; /* protect root_list */
+
+ int ls_namelen;
+ char ls_name[1];
+};
+
+#define LSFL_WORK 0
+#define LSFL_RUNNING 1
+#define LSFL_RECOVERY_STOP 2
+#define LSFL_RCOM_READY 3
+#define LSFL_UEVENT_WAIT 4
+
+/* much of this is just saving user space pointers associated with the
+ lock that we pass back to the user lib with an ast */
+
+struct dlm_user_args {
+ struct dlm_user_proc *proc; /* each process that opens the lockspace
+ device has private data
+ (dlm_user_proc) on the struct file,
+ the process's locks point back to it*/
+ struct dlm_lksb lksb;
+ int old_mode;
+ int update_user_lvb;
+ struct dlm_lksb __user *user_lksb;
+ void __user *castparam;
+ void __user *castaddr;
+ void __user *bastparam;
+ void __user *bastaddr;
+};
+
+#define DLM_PROC_FLAGS_CLOSING 1
+#define DLM_PROC_FLAGS_COMPAT 2
+
+/* locks list is kept so we can remove all a process's locks when it
+ exits (or orphan those that are persistent) */
+
+struct dlm_user_proc {
+ dlm_lockspace_t *lockspace;
+ unsigned long flags; /* DLM_PROC_FLAGS */
+ struct list_head asts;
+ spinlock_t asts_spin;
+ struct list_head locks;
+ spinlock_t locks_spin;
+ wait_queue_head_t wait;
+};
+
+static inline int dlm_locking_stopped(struct dlm_ls *ls)
+{
+ return !test_bit(LSFL_RUNNING, &ls->ls_flags);
+}
+
+static inline int dlm_recovery_stopped(struct dlm_ls *ls)
+{
+ return test_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+}
+
+static inline int dlm_no_directory(struct dlm_ls *ls)
+{
+ return (ls->ls_exflags & DLM_LSFL_NODIR) ? 1 : 0;
+}
+
+#endif /* __DLM_INTERNAL_DOT_H__ */
+
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
new file mode 100644
index 000000000000..3f2befa4797b
--- /dev/null
+++ b/fs/dlm/lock.c
@@ -0,0 +1,3871 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/* Central locking logic has four stages:
+
+ dlm_lock()
+ dlm_unlock()
+
+ request_lock(ls, lkb)
+ convert_lock(ls, lkb)
+ unlock_lock(ls, lkb)
+ cancel_lock(ls, lkb)
+
+ _request_lock(r, lkb)
+ _convert_lock(r, lkb)
+ _unlock_lock(r, lkb)
+ _cancel_lock(r, lkb)
+
+ do_request(r, lkb)
+ do_convert(r, lkb)
+ do_unlock(r, lkb)
+ do_cancel(r, lkb)
+
+ Stage 1 (lock, unlock) is mainly about checking input args and
+ splitting into one of the four main operations:
+
+ dlm_lock = request_lock
+ dlm_lock+CONVERT = convert_lock
+ dlm_unlock = unlock_lock
+ dlm_unlock+CANCEL = cancel_lock
+
+ Stage 2, xxxx_lock(), just finds and locks the relevant rsb which is
+ provided to the next stage.
+
+ Stage 3, _xxxx_lock(), determines if the operation is local or remote.
+ When remote, it calls send_xxxx(), when local it calls do_xxxx().
+
+ Stage 4, do_xxxx(), is the guts of the operation. It manipulates the
+ given rsb and lkb and queues callbacks.
+
+ For remote operations, send_xxxx() results in the corresponding do_xxxx()
+ function being executed on the remote node. The connecting send/receive
+ calls on local (L) and remote (R) nodes:
+
+ L: send_xxxx() -> R: receive_xxxx()
+ R: do_xxxx()
+ L: receive_xxxx_reply() <- R: send_xxxx_reply()
+*/
+#include <linux/types.h>
+#include "dlm_internal.h"
+#include <linux/dlm_device.h>
+#include "memory.h"
+#include "lowcomms.h"
+#include "requestqueue.h"
+#include "util.h"
+#include "dir.h"
+#include "member.h"
+#include "lockspace.h"
+#include "ast.h"
+#include "lock.h"
+#include "rcom.h"
+#include "recover.h"
+#include "lvb_table.h"
+#include "user.h"
+#include "config.h"
+
+static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode);
+static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static int send_remove(struct dlm_rsb *r);
+static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ struct dlm_message *ms);
+static int receive_extralen(struct dlm_message *ms);
+
+/*
+ * Lock compatibilty matrix - thanks Steve
+ * UN = Unlocked state. Not really a state, used as a flag
+ * PD = Padding. Used to make the matrix a nice power of two in size
+ * Other states are the same as the VMS DLM.
+ * Usage: matrix[grmode+1][rqmode+1] (although m[rq+1][gr+1] is the same)
+ */
+
+static const int __dlm_compat_matrix[8][8] = {
+ /* UN NL CR CW PR PW EX PD */
+ {1, 1, 1, 1, 1, 1, 1, 0}, /* UN */
+ {1, 1, 1, 1, 1, 1, 1, 0}, /* NL */
+ {1, 1, 1, 1, 1, 1, 0, 0}, /* CR */
+ {1, 1, 1, 1, 0, 0, 0, 0}, /* CW */
+ {1, 1, 1, 0, 1, 0, 0, 0}, /* PR */
+ {1, 1, 1, 0, 0, 0, 0, 0}, /* PW */
+ {1, 1, 0, 0, 0, 0, 0, 0}, /* EX */
+ {0, 0, 0, 0, 0, 0, 0, 0} /* PD */
+};
+
+/*
+ * This defines the direction of transfer of LVB data.
+ * Granted mode is the row; requested mode is the column.
+ * Usage: matrix[grmode+1][rqmode+1]
+ * 1 = LVB is returned to the caller
+ * 0 = LVB is written to the resource
+ * -1 = nothing happens to the LVB
+ */
+
+const int dlm_lvb_operations[8][8] = {
+ /* UN NL CR CW PR PW EX PD*/
+ { -1, 1, 1, 1, 1, 1, 1, -1 }, /* UN */
+ { -1, 1, 1, 1, 1, 1, 1, 0 }, /* NL */
+ { -1, -1, 1, 1, 1, 1, 1, 0 }, /* CR */
+ { -1, -1, -1, 1, 1, 1, 1, 0 }, /* CW */
+ { -1, -1, -1, -1, 1, 1, 1, 0 }, /* PR */
+ { -1, 0, 0, 0, 0, 0, 1, 0 }, /* PW */
+ { -1, 0, 0, 0, 0, 0, 0, 0 }, /* EX */
+ { -1, 0, 0, 0, 0, 0, 0, 0 } /* PD */
+};
+
+#define modes_compat(gr, rq) \
+ __dlm_compat_matrix[(gr)->lkb_grmode + 1][(rq)->lkb_rqmode + 1]
+
+int dlm_modes_compat(int mode1, int mode2)
+{
+ return __dlm_compat_matrix[mode1 + 1][mode2 + 1];
+}
+
+/*
+ * Compatibility matrix for conversions with QUECVT set.
+ * Granted mode is the row; requested mode is the column.
+ * Usage: matrix[grmode+1][rqmode+1]
+ */
+
+static const int __quecvt_compat_matrix[8][8] = {
+ /* UN NL CR CW PR PW EX PD */
+ {0, 0, 0, 0, 0, 0, 0, 0}, /* UN */
+ {0, 0, 1, 1, 1, 1, 1, 0}, /* NL */
+ {0, 0, 0, 1, 1, 1, 1, 0}, /* CR */
+ {0, 0, 0, 0, 1, 1, 1, 0}, /* CW */
+ {0, 0, 0, 1, 0, 1, 1, 0}, /* PR */
+ {0, 0, 0, 0, 0, 0, 1, 0}, /* PW */
+ {0, 0, 0, 0, 0, 0, 0, 0}, /* EX */
+ {0, 0, 0, 0, 0, 0, 0, 0} /* PD */
+};
+
+void dlm_print_lkb(struct dlm_lkb *lkb)
+{
+ printk(KERN_ERR "lkb: nodeid %d id %x remid %x exflags %x flags %x\n"
+ " status %d rqmode %d grmode %d wait_type %d ast_type %d\n",
+ lkb->lkb_nodeid, lkb->lkb_id, lkb->lkb_remid, lkb->lkb_exflags,
+ lkb->lkb_flags, lkb->lkb_status, lkb->lkb_rqmode,
+ lkb->lkb_grmode, lkb->lkb_wait_type, lkb->lkb_ast_type);
+}
+
+void dlm_print_rsb(struct dlm_rsb *r)
+{
+ printk(KERN_ERR "rsb: nodeid %d flags %lx first %x rlc %d name %s\n",
+ r->res_nodeid, r->res_flags, r->res_first_lkid,
+ r->res_recover_locks_count, r->res_name);
+}
+
+void dlm_dump_rsb(struct dlm_rsb *r)
+{
+ struct dlm_lkb *lkb;
+
+ dlm_print_rsb(r);
+
+ printk(KERN_ERR "rsb: root_list empty %d recover_list empty %d\n",
+ list_empty(&r->res_root_list), list_empty(&r->res_recover_list));
+ printk(KERN_ERR "rsb lookup list\n");
+ list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup)
+ dlm_print_lkb(lkb);
+ printk(KERN_ERR "rsb grant queue:\n");
+ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue)
+ dlm_print_lkb(lkb);
+ printk(KERN_ERR "rsb convert queue:\n");
+ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue)
+ dlm_print_lkb(lkb);
+ printk(KERN_ERR "rsb wait queue:\n");
+ list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue)
+ dlm_print_lkb(lkb);
+}
+
+/* Threads cannot use the lockspace while it's being recovered */
+
+static inline void lock_recovery(struct dlm_ls *ls)
+{
+ down_read(&ls->ls_in_recovery);
+}
+
+static inline void unlock_recovery(struct dlm_ls *ls)
+{
+ up_read(&ls->ls_in_recovery);
+}
+
+static inline int lock_recovery_try(struct dlm_ls *ls)
+{
+ return down_read_trylock(&ls->ls_in_recovery);
+}
+
+static inline int can_be_queued(struct dlm_lkb *lkb)
+{
+ return !(lkb->lkb_exflags & DLM_LKF_NOQUEUE);
+}
+
+static inline int force_blocking_asts(struct dlm_lkb *lkb)
+{
+ return (lkb->lkb_exflags & DLM_LKF_NOQUEUEBAST);
+}
+
+static inline int is_demoted(struct dlm_lkb *lkb)
+{
+ return (lkb->lkb_sbflags & DLM_SBF_DEMOTED);
+}
+
+static inline int is_remote(struct dlm_rsb *r)
+{
+ DLM_ASSERT(r->res_nodeid >= 0, dlm_print_rsb(r););
+ return !!r->res_nodeid;
+}
+
+static inline int is_process_copy(struct dlm_lkb *lkb)
+{
+ return (lkb->lkb_nodeid && !(lkb->lkb_flags & DLM_IFL_MSTCPY));
+}
+
+static inline int is_master_copy(struct dlm_lkb *lkb)
+{
+ if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+ DLM_ASSERT(lkb->lkb_nodeid, dlm_print_lkb(lkb););
+ return (lkb->lkb_flags & DLM_IFL_MSTCPY) ? 1 : 0;
+}
+
+static inline int middle_conversion(struct dlm_lkb *lkb)
+{
+ if ((lkb->lkb_grmode==DLM_LOCK_PR && lkb->lkb_rqmode==DLM_LOCK_CW) ||
+ (lkb->lkb_rqmode==DLM_LOCK_PR && lkb->lkb_grmode==DLM_LOCK_CW))
+ return 1;
+ return 0;
+}
+
+static inline int down_conversion(struct dlm_lkb *lkb)
+{
+ return (!middle_conversion(lkb) && lkb->lkb_rqmode < lkb->lkb_grmode);
+}
+
+static void queue_cast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+ if (is_master_copy(lkb))
+ return;
+
+ DLM_ASSERT(lkb->lkb_lksb, dlm_print_lkb(lkb););
+
+ lkb->lkb_lksb->sb_status = rv;
+ lkb->lkb_lksb->sb_flags = lkb->lkb_sbflags;
+
+ dlm_add_ast(lkb, AST_COMP);
+}
+
+static void queue_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int rqmode)
+{
+ if (is_master_copy(lkb))
+ send_bast(r, lkb, rqmode);
+ else {
+ lkb->lkb_bastmode = rqmode;
+ dlm_add_ast(lkb, AST_BAST);
+ }
+}
+
+/*
+ * Basic operations on rsb's and lkb's
+ */
+
+static struct dlm_rsb *create_rsb(struct dlm_ls *ls, char *name, int len)
+{
+ struct dlm_rsb *r;
+
+ r = allocate_rsb(ls, len);
+ if (!r)
+ return NULL;
+
+ r->res_ls = ls;
+ r->res_length = len;
+ memcpy(r->res_name, name, len);
+ mutex_init(&r->res_mutex);
+
+ INIT_LIST_HEAD(&r->res_lookup);
+ INIT_LIST_HEAD(&r->res_grantqueue);
+ INIT_LIST_HEAD(&r->res_convertqueue);
+ INIT_LIST_HEAD(&r->res_waitqueue);
+ INIT_LIST_HEAD(&r->res_root_list);
+ INIT_LIST_HEAD(&r->res_recover_list);
+
+ return r;
+}
+
+static int search_rsb_list(struct list_head *head, char *name, int len,
+ unsigned int flags, struct dlm_rsb **r_ret)
+{
+ struct dlm_rsb *r;
+ int error = 0;
+
+ list_for_each_entry(r, head, res_hashchain) {
+ if (len == r->res_length && !memcmp(name, r->res_name, len))
+ goto found;
+ }
+ return -EBADR;
+
+ found:
+ if (r->res_nodeid && (flags & R_MASTER))
+ error = -ENOTBLK;
+ *r_ret = r;
+ return error;
+}
+
+static int _search_rsb(struct dlm_ls *ls, char *name, int len, int b,
+ unsigned int flags, struct dlm_rsb **r_ret)
+{
+ struct dlm_rsb *r;
+ int error;
+
+ error = search_rsb_list(&ls->ls_rsbtbl[b].list, name, len, flags, &r);
+ if (!error) {
+ kref_get(&r->res_ref);
+ goto out;
+ }
+ error = search_rsb_list(&ls->ls_rsbtbl[b].toss, name, len, flags, &r);
+ if (error)
+ goto out;
+
+ list_move(&r->res_hashchain, &ls->ls_rsbtbl[b].list);
+
+ if (dlm_no_directory(ls))
+ goto out;
+
+ if (r->res_nodeid == -1) {
+ rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
+ r->res_first_lkid = 0;
+ } else if (r->res_nodeid > 0) {
+ rsb_set_flag(r, RSB_MASTER_UNCERTAIN);
+ r->res_first_lkid = 0;
+ } else {
+ DLM_ASSERT(r->res_nodeid == 0, dlm_print_rsb(r););
+ DLM_ASSERT(!rsb_flag(r, RSB_MASTER_UNCERTAIN),);
+ }
+ out:
+ *r_ret = r;
+ return error;
+}
+
+static int search_rsb(struct dlm_ls *ls, char *name, int len, int b,
+ unsigned int flags, struct dlm_rsb **r_ret)
+{
+ int error;
+ write_lock(&ls->ls_rsbtbl[b].lock);
+ error = _search_rsb(ls, name, len, b, flags, r_ret);
+ write_unlock(&ls->ls_rsbtbl[b].lock);
+ return error;
+}
+
+/*
+ * Find rsb in rsbtbl and potentially create/add one
+ *
+ * Delaying the release of rsb's has a similar benefit to applications keeping
+ * NL locks on an rsb, but without the guarantee that the cached master value
+ * will still be valid when the rsb is reused. Apps aren't always smart enough
+ * to keep NL locks on an rsb that they may lock again shortly; this can lead
+ * to excessive master lookups and removals if we don't delay the release.
+ *
+ * Searching for an rsb means looking through both the normal list and toss
+ * list. When found on the toss list the rsb is moved to the normal list with
+ * ref count of 1; when found on normal list the ref count is incremented.
+ */
+
+static int find_rsb(struct dlm_ls *ls, char *name, int namelen,
+ unsigned int flags, struct dlm_rsb **r_ret)
+{
+ struct dlm_rsb *r, *tmp;
+ uint32_t hash, bucket;
+ int error = 0;
+
+ if (dlm_no_directory(ls))
+ flags |= R_CREATE;
+
+ hash = jhash(name, namelen, 0);
+ bucket = hash & (ls->ls_rsbtbl_size - 1);
+
+ error = search_rsb(ls, name, namelen, bucket, flags, &r);
+ if (!error)
+ goto out;
+
+ if (error == -EBADR && !(flags & R_CREATE))
+ goto out;
+
+ /* the rsb was found but wasn't a master copy */
+ if (error == -ENOTBLK)
+ goto out;
+
+ error = -ENOMEM;
+ r = create_rsb(ls, name, namelen);
+ if (!r)
+ goto out;
+
+ r->res_hash = hash;
+ r->res_bucket = bucket;
+ r->res_nodeid = -1;
+ kref_init(&r->res_ref);
+
+ /* With no directory, the master can be set immediately */
+ if (dlm_no_directory(ls)) {
+ int nodeid = dlm_dir_nodeid(r);
+ if (nodeid == dlm_our_nodeid())
+ nodeid = 0;
+ r->res_nodeid = nodeid;
+ }
+
+ write_lock(&ls->ls_rsbtbl[bucket].lock);
+ error = _search_rsb(ls, name, namelen, bucket, 0, &tmp);
+ if (!error) {
+ write_unlock(&ls->ls_rsbtbl[bucket].lock);
+ free_rsb(r);
+ r = tmp;
+ goto out;
+ }
+ list_add(&r->res_hashchain, &ls->ls_rsbtbl[bucket].list);
+ write_unlock(&ls->ls_rsbtbl[bucket].lock);
+ error = 0;
+ out:
+ *r_ret = r;
+ return error;
+}
+
+int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
+ unsigned int flags, struct dlm_rsb **r_ret)
+{
+ return find_rsb(ls, name, namelen, flags, r_ret);
+}
+
+/* This is only called to add a reference when the code already holds
+ a valid reference to the rsb, so there's no need for locking. */
+
+static inline void hold_rsb(struct dlm_rsb *r)
+{
+ kref_get(&r->res_ref);
+}
+
+void dlm_hold_rsb(struct dlm_rsb *r)
+{
+ hold_rsb(r);
+}
+
+static void toss_rsb(struct kref *kref)
+{
+ struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
+ struct dlm_ls *ls = r->res_ls;
+
+ DLM_ASSERT(list_empty(&r->res_root_list), dlm_print_rsb(r););
+ kref_init(&r->res_ref);
+ list_move(&r->res_hashchain, &ls->ls_rsbtbl[r->res_bucket].toss);
+ r->res_toss_time = jiffies;
+ if (r->res_lvbptr) {
+ free_lvb(r->res_lvbptr);
+ r->res_lvbptr = NULL;
+ }
+}
+
+/* When all references to the rsb are gone it's transfered to
+ the tossed list for later disposal. */
+
+static void put_rsb(struct dlm_rsb *r)
+{
+ struct dlm_ls *ls = r->res_ls;
+ uint32_t bucket = r->res_bucket;
+
+ write_lock(&ls->ls_rsbtbl[bucket].lock);
+ kref_put(&r->res_ref, toss_rsb);
+ write_unlock(&ls->ls_rsbtbl[bucket].lock);
+}
+
+void dlm_put_rsb(struct dlm_rsb *r)
+{
+ put_rsb(r);
+}
+
+/* See comment for unhold_lkb */
+
+static void unhold_rsb(struct dlm_rsb *r)
+{
+ int rv;
+ rv = kref_put(&r->res_ref, toss_rsb);
+ DLM_ASSERT(!rv, dlm_dump_rsb(r););
+}
+
+static void kill_rsb(struct kref *kref)
+{
+ struct dlm_rsb *r = container_of(kref, struct dlm_rsb, res_ref);
+
+ /* All work is done after the return from kref_put() so we
+ can release the write_lock before the remove and free. */
+
+ DLM_ASSERT(list_empty(&r->res_lookup), dlm_dump_rsb(r););
+ DLM_ASSERT(list_empty(&r->res_grantqueue), dlm_dump_rsb(r););
+ DLM_ASSERT(list_empty(&r->res_convertqueue), dlm_dump_rsb(r););
+ DLM_ASSERT(list_empty(&r->res_waitqueue), dlm_dump_rsb(r););
+ DLM_ASSERT(list_empty(&r->res_root_list), dlm_dump_rsb(r););
+ DLM_ASSERT(list_empty(&r->res_recover_list), dlm_dump_rsb(r););
+}
+
+/* Attaching/detaching lkb's from rsb's is for rsb reference counting.
+ The rsb must exist as long as any lkb's for it do. */
+
+static void attach_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ hold_rsb(r);
+ lkb->lkb_resource = r;
+}
+
+static void detach_lkb(struct dlm_lkb *lkb)
+{
+ if (lkb->lkb_resource) {
+ put_rsb(lkb->lkb_resource);
+ lkb->lkb_resource = NULL;
+ }
+}
+
+static int create_lkb(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+{
+ struct dlm_lkb *lkb, *tmp;
+ uint32_t lkid = 0;
+ uint16_t bucket;
+
+ lkb = allocate_lkb(ls);
+ if (!lkb)
+ return -ENOMEM;
+
+ lkb->lkb_nodeid = -1;
+ lkb->lkb_grmode = DLM_LOCK_IV;
+ kref_init(&lkb->lkb_ref);
+ INIT_LIST_HEAD(&lkb->lkb_ownqueue);
+
+ get_random_bytes(&bucket, sizeof(bucket));
+ bucket &= (ls->ls_lkbtbl_size - 1);
+
+ write_lock(&ls->ls_lkbtbl[bucket].lock);
+
+ /* counter can roll over so we must verify lkid is not in use */
+
+ while (lkid == 0) {
+ lkid = bucket | (ls->ls_lkbtbl[bucket].counter++ << 16);
+
+ list_for_each_entry(tmp, &ls->ls_lkbtbl[bucket].list,
+ lkb_idtbl_list) {
+ if (tmp->lkb_id != lkid)
+ continue;
+ lkid = 0;
+ break;
+ }
+ }
+
+ lkb->lkb_id = lkid;
+ list_add(&lkb->lkb_idtbl_list, &ls->ls_lkbtbl[bucket].list);
+ write_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+ *lkb_ret = lkb;
+ return 0;
+}
+
+static struct dlm_lkb *__find_lkb(struct dlm_ls *ls, uint32_t lkid)
+{
+ uint16_t bucket = lkid & 0xFFFF;
+ struct dlm_lkb *lkb;
+
+ list_for_each_entry(lkb, &ls->ls_lkbtbl[bucket].list, lkb_idtbl_list) {
+ if (lkb->lkb_id == lkid)
+ return lkb;
+ }
+ return NULL;
+}
+
+static int find_lkb(struct dlm_ls *ls, uint32_t lkid, struct dlm_lkb **lkb_ret)
+{
+ struct dlm_lkb *lkb;
+ uint16_t bucket = lkid & 0xFFFF;
+
+ if (bucket >= ls->ls_lkbtbl_size)
+ return -EBADSLT;
+
+ read_lock(&ls->ls_lkbtbl[bucket].lock);
+ lkb = __find_lkb(ls, lkid);
+ if (lkb)
+ kref_get(&lkb->lkb_ref);
+ read_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+ *lkb_ret = lkb;
+ return lkb ? 0 : -ENOENT;
+}
+
+static void kill_lkb(struct kref *kref)
+{
+ struct dlm_lkb *lkb = container_of(kref, struct dlm_lkb, lkb_ref);
+
+ /* All work is done after the return from kref_put() so we
+ can release the write_lock before the detach_lkb */
+
+ DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
+}
+
+/* __put_lkb() is used when an lkb may not have an rsb attached to
+ it so we need to provide the lockspace explicitly */
+
+static int __put_lkb(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+ uint16_t bucket = lkb->lkb_id & 0xFFFF;
+
+ write_lock(&ls->ls_lkbtbl[bucket].lock);
+ if (kref_put(&lkb->lkb_ref, kill_lkb)) {
+ list_del(&lkb->lkb_idtbl_list);
+ write_unlock(&ls->ls_lkbtbl[bucket].lock);
+
+ detach_lkb(lkb);
+
+ /* for local/process lkbs, lvbptr points to caller's lksb */
+ if (lkb->lkb_lvbptr && is_master_copy(lkb))
+ free_lvb(lkb->lkb_lvbptr);
+ free_lkb(lkb);
+ return 1;
+ } else {
+ write_unlock(&ls->ls_lkbtbl[bucket].lock);
+ return 0;
+ }
+}
+
+int dlm_put_lkb(struct dlm_lkb *lkb)
+{
+ struct dlm_ls *ls;
+
+ DLM_ASSERT(lkb->lkb_resource, dlm_print_lkb(lkb););
+ DLM_ASSERT(lkb->lkb_resource->res_ls, dlm_print_lkb(lkb););
+
+ ls = lkb->lkb_resource->res_ls;
+ return __put_lkb(ls, lkb);
+}
+
+/* This is only called to add a reference when the code already holds
+ a valid reference to the lkb, so there's no need for locking. */
+
+static inline void hold_lkb(struct dlm_lkb *lkb)
+{
+ kref_get(&lkb->lkb_ref);
+}
+
+/* This is called when we need to remove a reference and are certain
+ it's not the last ref. e.g. del_lkb is always called between a
+ find_lkb/put_lkb and is always the inverse of a previous add_lkb.
+ put_lkb would work fine, but would involve unnecessary locking */
+
+static inline void unhold_lkb(struct dlm_lkb *lkb)
+{
+ int rv;
+ rv = kref_put(&lkb->lkb_ref, kill_lkb);
+ DLM_ASSERT(!rv, dlm_print_lkb(lkb););
+}
+
+static void lkb_add_ordered(struct list_head *new, struct list_head *head,
+ int mode)
+{
+ struct dlm_lkb *lkb = NULL;
+
+ list_for_each_entry(lkb, head, lkb_statequeue)
+ if (lkb->lkb_rqmode < mode)
+ break;
+
+ if (!lkb)
+ list_add_tail(new, head);
+ else
+ __list_add(new, lkb->lkb_statequeue.prev, &lkb->lkb_statequeue);
+}
+
+/* add/remove lkb to rsb's grant/convert/wait queue */
+
+static void add_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int status)
+{
+ kref_get(&lkb->lkb_ref);
+
+ DLM_ASSERT(!lkb->lkb_status, dlm_print_lkb(lkb););
+
+ lkb->lkb_status = status;
+
+ switch (status) {
+ case DLM_LKSTS_WAITING:
+ if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
+ list_add(&lkb->lkb_statequeue, &r->res_waitqueue);
+ else
+ list_add_tail(&lkb->lkb_statequeue, &r->res_waitqueue);
+ break;
+ case DLM_LKSTS_GRANTED:
+ /* convention says granted locks kept in order of grmode */
+ lkb_add_ordered(&lkb->lkb_statequeue, &r->res_grantqueue,
+ lkb->lkb_grmode);
+ break;
+ case DLM_LKSTS_CONVERT:
+ if (lkb->lkb_exflags & DLM_LKF_HEADQUE)
+ list_add(&lkb->lkb_statequeue, &r->res_convertqueue);
+ else
+ list_add_tail(&lkb->lkb_statequeue,
+ &r->res_convertqueue);
+ break;
+ default:
+ DLM_ASSERT(0, dlm_print_lkb(lkb); printk("sts=%d\n", status););
+ }
+}
+
+static void del_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ lkb->lkb_status = 0;
+ list_del(&lkb->lkb_statequeue);
+ unhold_lkb(lkb);
+}
+
+static void move_lkb(struct dlm_rsb *r, struct dlm_lkb *lkb, int sts)
+{
+ hold_lkb(lkb);
+ del_lkb(r, lkb);
+ add_lkb(r, lkb, sts);
+ unhold_lkb(lkb);
+}
+
+/* add/remove lkb from global waiters list of lkb's waiting for
+ a reply from a remote node */
+
+static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
+{
+ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+
+ mutex_lock(&ls->ls_waiters_mutex);
+ if (lkb->lkb_wait_type) {
+ log_print("add_to_waiters error %d", lkb->lkb_wait_type);
+ goto out;
+ }
+ lkb->lkb_wait_type = mstype;
+ kref_get(&lkb->lkb_ref);
+ list_add(&lkb->lkb_wait_reply, &ls->ls_waiters);
+ out:
+ mutex_unlock(&ls->ls_waiters_mutex);
+}
+
+static int _remove_from_waiters(struct dlm_lkb *lkb)
+{
+ int error = 0;
+
+ if (!lkb->lkb_wait_type) {
+ log_print("remove_from_waiters error");
+ error = -EINVAL;
+ goto out;
+ }
+ lkb->lkb_wait_type = 0;
+ list_del(&lkb->lkb_wait_reply);
+ unhold_lkb(lkb);
+ out:
+ return error;
+}
+
+static int remove_from_waiters(struct dlm_lkb *lkb)
+{
+ struct dlm_ls *ls = lkb->lkb_resource->res_ls;
+ int error;
+
+ mutex_lock(&ls->ls_waiters_mutex);
+ error = _remove_from_waiters(lkb);
+ mutex_unlock(&ls->ls_waiters_mutex);
+ return error;
+}
+
+static void dir_remove(struct dlm_rsb *r)
+{
+ int to_nodeid;
+
+ if (dlm_no_directory(r->res_ls))
+ return;
+
+ to_nodeid = dlm_dir_nodeid(r);
+ if (to_nodeid != dlm_our_nodeid())
+ send_remove(r);
+ else
+ dlm_dir_remove_entry(r->res_ls, to_nodeid,
+ r->res_name, r->res_length);
+}
+
+/* FIXME: shouldn't this be able to exit as soon as one non-due rsb is
+ found since they are in order of newest to oldest? */
+
+static int shrink_bucket(struct dlm_ls *ls, int b)
+{
+ struct dlm_rsb *r;
+ int count = 0, found;
+
+ for (;;) {
+ found = 0;
+ write_lock(&ls->ls_rsbtbl[b].lock);
+ list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
+ res_hashchain) {
+ if (!time_after_eq(jiffies, r->res_toss_time +
+ dlm_config.toss_secs * HZ))
+ continue;
+ found = 1;
+ break;
+ }
+
+ if (!found) {
+ write_unlock(&ls->ls_rsbtbl[b].lock);
+ break;
+ }
+
+ if (kref_put(&r->res_ref, kill_rsb)) {
+ list_del(&r->res_hashchain);
+ write_unlock(&ls->ls_rsbtbl[b].lock);
+
+ if (is_master(r))
+ dir_remove(r);
+ free_rsb(r);
+ count++;
+ } else {
+ write_unlock(&ls->ls_rsbtbl[b].lock);
+ log_error(ls, "tossed rsb in use %s", r->res_name);
+ }
+ }
+
+ return count;
+}
+
+void dlm_scan_rsbs(struct dlm_ls *ls)
+{
+ int i;
+
+ if (dlm_locking_stopped(ls))
+ return;
+
+ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+ shrink_bucket(ls, i);
+ cond_resched();
+ }
+}
+
+/* lkb is master or local copy */
+
+static void set_lvb_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int b, len = r->res_ls->ls_lvblen;
+
+ /* b=1 lvb returned to caller
+ b=0 lvb written to rsb or invalidated
+ b=-1 do nothing */
+
+ b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
+
+ if (b == 1) {
+ if (!lkb->lkb_lvbptr)
+ return;
+
+ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+ return;
+
+ if (!r->res_lvbptr)
+ return;
+
+ memcpy(lkb->lkb_lvbptr, r->res_lvbptr, len);
+ lkb->lkb_lvbseq = r->res_lvbseq;
+
+ } else if (b == 0) {
+ if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
+ rsb_set_flag(r, RSB_VALNOTVALID);
+ return;
+ }
+
+ if (!lkb->lkb_lvbptr)
+ return;
+
+ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+ return;
+
+ if (!r->res_lvbptr)
+ r->res_lvbptr = allocate_lvb(r->res_ls);
+
+ if (!r->res_lvbptr)
+ return;
+
+ memcpy(r->res_lvbptr, lkb->lkb_lvbptr, len);
+ r->res_lvbseq++;
+ lkb->lkb_lvbseq = r->res_lvbseq;
+ rsb_clear_flag(r, RSB_VALNOTVALID);
+ }
+
+ if (rsb_flag(r, RSB_VALNOTVALID))
+ lkb->lkb_sbflags |= DLM_SBF_VALNOTVALID;
+}
+
+static void set_lvb_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ if (lkb->lkb_grmode < DLM_LOCK_PW)
+ return;
+
+ if (lkb->lkb_exflags & DLM_LKF_IVVALBLK) {
+ rsb_set_flag(r, RSB_VALNOTVALID);
+ return;
+ }
+
+ if (!lkb->lkb_lvbptr)
+ return;
+
+ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+ return;
+
+ if (!r->res_lvbptr)
+ r->res_lvbptr = allocate_lvb(r->res_ls);
+
+ if (!r->res_lvbptr)
+ return;
+
+ memcpy(r->res_lvbptr, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+ r->res_lvbseq++;
+ rsb_clear_flag(r, RSB_VALNOTVALID);
+}
+
+/* lkb is process copy (pc) */
+
+static void set_lvb_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ int b;
+
+ if (!lkb->lkb_lvbptr)
+ return;
+
+ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+ return;
+
+ b = dlm_lvb_operations[lkb->lkb_grmode + 1][lkb->lkb_rqmode + 1];
+ if (b == 1) {
+ int len = receive_extralen(ms);
+ memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
+ lkb->lkb_lvbseq = ms->m_lvbseq;
+ }
+}
+
+/* Manipulate lkb's on rsb's convert/granted/waiting queues
+ remove_lock -- used for unlock, removes lkb from granted
+ revert_lock -- used for cancel, moves lkb from convert to granted
+ grant_lock -- used for request and convert, adds lkb to granted or
+ moves lkb from convert or waiting to granted
+
+ Each of these is used for master or local copy lkb's. There is
+ also a _pc() variation used to make the corresponding change on
+ a process copy (pc) lkb. */
+
+static void _remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ del_lkb(r, lkb);
+ lkb->lkb_grmode = DLM_LOCK_IV;
+ /* this unhold undoes the original ref from create_lkb()
+ so this leads to the lkb being freed */
+ unhold_lkb(lkb);
+}
+
+static void remove_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ set_lvb_unlock(r, lkb);
+ _remove_lock(r, lkb);
+}
+
+static void remove_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ _remove_lock(r, lkb);
+}
+
+static void revert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ lkb->lkb_rqmode = DLM_LOCK_IV;
+
+ switch (lkb->lkb_status) {
+ case DLM_LKSTS_GRANTED:
+ break;
+ case DLM_LKSTS_CONVERT:
+ move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+ break;
+ case DLM_LKSTS_WAITING:
+ del_lkb(r, lkb);
+ lkb->lkb_grmode = DLM_LOCK_IV;
+ /* this unhold undoes the original ref from create_lkb()
+ so this leads to the lkb being freed */
+ unhold_lkb(lkb);
+ break;
+ default:
+ log_print("invalid status for revert %d", lkb->lkb_status);
+ }
+}
+
+static void revert_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ revert_lock(r, lkb);
+}
+
+static void _grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ if (lkb->lkb_grmode != lkb->lkb_rqmode) {
+ lkb->lkb_grmode = lkb->lkb_rqmode;
+ if (lkb->lkb_status)
+ move_lkb(r, lkb, DLM_LKSTS_GRANTED);
+ else
+ add_lkb(r, lkb, DLM_LKSTS_GRANTED);
+ }
+
+ lkb->lkb_rqmode = DLM_LOCK_IV;
+}
+
+static void grant_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ set_lvb_lock(r, lkb);
+ _grant_lock(r, lkb);
+ lkb->lkb_highbast = 0;
+}
+
+static void grant_lock_pc(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ set_lvb_lock_pc(r, lkb, ms);
+ _grant_lock(r, lkb);
+}
+
+/* called by grant_pending_locks() which means an async grant message must
+ be sent to the requesting node in addition to granting the lock if the
+ lkb belongs to a remote node. */
+
+static void grant_lock_pending(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ grant_lock(r, lkb);
+ if (is_master_copy(lkb))
+ send_grant(r, lkb);
+ else
+ queue_cast(r, lkb, 0);
+}
+
+static inline int first_in_list(struct dlm_lkb *lkb, struct list_head *head)
+{
+ struct dlm_lkb *first = list_entry(head->next, struct dlm_lkb,
+ lkb_statequeue);
+ if (lkb->lkb_id == first->lkb_id)
+ return 1;
+
+ return 0;
+}
+
+/* Check if the given lkb conflicts with another lkb on the queue. */
+
+static int queue_conflict(struct list_head *head, struct dlm_lkb *lkb)
+{
+ struct dlm_lkb *this;
+
+ list_for_each_entry(this, head, lkb_statequeue) {
+ if (this == lkb)
+ continue;
+ if (!modes_compat(this, lkb))
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * "A conversion deadlock arises with a pair of lock requests in the converting
+ * queue for one resource. The granted mode of each lock blocks the requested
+ * mode of the other lock."
+ *
+ * Part 2: if the granted mode of lkb is preventing the first lkb in the
+ * convert queue from being granted, then demote lkb (set grmode to NL).
+ * This second form requires that we check for conv-deadlk even when
+ * now == 0 in _can_be_granted().
+ *
+ * Example:
+ * Granted Queue: empty
+ * Convert Queue: NL->EX (first lock)
+ * PR->EX (second lock)
+ *
+ * The first lock can't be granted because of the granted mode of the second
+ * lock and the second lock can't be granted because it's not first in the
+ * list. We demote the granted mode of the second lock (the lkb passed to this
+ * function).
+ *
+ * After the resolution, the "grant pending" function needs to go back and try
+ * to grant locks on the convert queue again since the first lock can now be
+ * granted.
+ */
+
+static int conversion_deadlock_detect(struct dlm_rsb *rsb, struct dlm_lkb *lkb)
+{
+ struct dlm_lkb *this, *first = NULL, *self = NULL;
+
+ list_for_each_entry(this, &rsb->res_convertqueue, lkb_statequeue) {
+ if (!first)
+ first = this;
+ if (this == lkb) {
+ self = lkb;
+ continue;
+ }
+
+ if (!modes_compat(this, lkb) && !modes_compat(lkb, this))
+ return 1;
+ }
+
+ /* if lkb is on the convert queue and is preventing the first
+ from being granted, then there's deadlock and we demote lkb.
+ multiple converting locks may need to do this before the first
+ converting lock can be granted. */
+
+ if (self && self != first) {
+ if (!modes_compat(lkb, first) &&
+ !queue_conflict(&rsb->res_grantqueue, first))
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * Return 1 if the lock can be granted, 0 otherwise.
+ * Also detect and resolve conversion deadlocks.
+ *
+ * lkb is the lock to be granted
+ *
+ * now is 1 if the function is being called in the context of the
+ * immediate request, it is 0 if called later, after the lock has been
+ * queued.
+ *
+ * References are from chapter 6 of "VAXcluster Principles" by Roy Davis
+ */
+
+static int _can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
+{
+ int8_t conv = (lkb->lkb_grmode != DLM_LOCK_IV);
+
+ /*
+ * 6-10: Version 5.4 introduced an option to address the phenomenon of
+ * a new request for a NL mode lock being blocked.
+ *
+ * 6-11: If the optional EXPEDITE flag is used with the new NL mode
+ * request, then it would be granted. In essence, the use of this flag
+ * tells the Lock Manager to expedite theis request by not considering
+ * what may be in the CONVERTING or WAITING queues... As of this
+ * writing, the EXPEDITE flag can be used only with new requests for NL
+ * mode locks. This flag is not valid for conversion requests.
+ *
+ * A shortcut. Earlier checks return an error if EXPEDITE is used in a
+ * conversion or used with a non-NL requested mode. We also know an
+ * EXPEDITE request is always granted immediately, so now must always
+ * be 1. The full condition to grant an expedite request: (now &&
+ * !conv && lkb->rqmode == DLM_LOCK_NL && (flags & EXPEDITE)) can
+ * therefore be shortened to just checking the flag.
+ */
+
+ if (lkb->lkb_exflags & DLM_LKF_EXPEDITE)
+ return 1;
+
+ /*
+ * A shortcut. Without this, !queue_conflict(grantqueue, lkb) would be
+ * added to the remaining conditions.
+ */
+
+ if (queue_conflict(&r->res_grantqueue, lkb))
+ goto out;
+
+ /*
+ * 6-3: By default, a conversion request is immediately granted if the
+ * requested mode is compatible with the modes of all other granted
+ * locks
+ */
+
+ if (queue_conflict(&r->res_convertqueue, lkb))
+ goto out;
+
+ /*
+ * 6-5: But the default algorithm for deciding whether to grant or
+ * queue conversion requests does not by itself guarantee that such
+ * requests are serviced on a "first come first serve" basis. This, in
+ * turn, can lead to a phenomenon known as "indefinate postponement".
+ *
+ * 6-7: This issue is dealt with by using the optional QUECVT flag with
+ * the system service employed to request a lock conversion. This flag
+ * forces certain conversion requests to be queued, even if they are
+ * compatible with the granted modes of other locks on the same
+ * resource. Thus, the use of this flag results in conversion requests
+ * being ordered on a "first come first servce" basis.
+ *
+ * DCT: This condition is all about new conversions being able to occur
+ * "in place" while the lock remains on the granted queue (assuming
+ * nothing else conflicts.) IOW if QUECVT isn't set, a conversion
+ * doesn't _have_ to go onto the convert queue where it's processed in
+ * order. The "now" variable is necessary to distinguish converts
+ * being received and processed for the first time now, because once a
+ * convert is moved to the conversion queue the condition below applies
+ * requiring fifo granting.
+ */
+
+ if (now && conv && !(lkb->lkb_exflags & DLM_LKF_QUECVT))
+ return 1;
+
+ /*
+ * The NOORDER flag is set to avoid the standard vms rules on grant
+ * order.
+ */
+
+ if (lkb->lkb_exflags & DLM_LKF_NOORDER)
+ return 1;
+
+ /*
+ * 6-3: Once in that queue [CONVERTING], a conversion request cannot be
+ * granted until all other conversion requests ahead of it are granted
+ * and/or canceled.
+ */
+
+ if (!now && conv && first_in_list(lkb, &r->res_convertqueue))
+ return 1;
+
+ /*
+ * 6-4: By default, a new request is immediately granted only if all
+ * three of the following conditions are satisfied when the request is
+ * issued:
+ * - The queue of ungranted conversion requests for the resource is
+ * empty.
+ * - The queue of ungranted new requests for the resource is empty.
+ * - The mode of the new request is compatible with the most
+ * restrictive mode of all granted locks on the resource.
+ */
+
+ if (now && !conv && list_empty(&r->res_convertqueue) &&
+ list_empty(&r->res_waitqueue))
+ return 1;
+
+ /*
+ * 6-4: Once a lock request is in the queue of ungranted new requests,
+ * it cannot be granted until the queue of ungranted conversion
+ * requests is empty, all ungranted new requests ahead of it are
+ * granted and/or canceled, and it is compatible with the granted mode
+ * of the most restrictive lock granted on the resource.
+ */
+
+ if (!now && !conv && list_empty(&r->res_convertqueue) &&
+ first_in_list(lkb, &r->res_waitqueue))
+ return 1;
+
+ out:
+ /*
+ * The following, enabled by CONVDEADLK, departs from VMS.
+ */
+
+ if (conv && (lkb->lkb_exflags & DLM_LKF_CONVDEADLK) &&
+ conversion_deadlock_detect(r, lkb)) {
+ lkb->lkb_grmode = DLM_LOCK_NL;
+ lkb->lkb_sbflags |= DLM_SBF_DEMOTED;
+ }
+
+ return 0;
+}
+
+/*
+ * The ALTPR and ALTCW flags aren't traditional lock manager flags, but are a
+ * simple way to provide a big optimization to applications that can use them.
+ */
+
+static int can_be_granted(struct dlm_rsb *r, struct dlm_lkb *lkb, int now)
+{
+ uint32_t flags = lkb->lkb_exflags;
+ int rv;
+ int8_t alt = 0, rqmode = lkb->lkb_rqmode;
+
+ rv = _can_be_granted(r, lkb, now);
+ if (rv)
+ goto out;
+
+ if (lkb->lkb_sbflags & DLM_SBF_DEMOTED)
+ goto out;
+
+ if (rqmode != DLM_LOCK_PR && flags & DLM_LKF_ALTPR)
+ alt = DLM_LOCK_PR;
+ else if (rqmode != DLM_LOCK_CW && flags & DLM_LKF_ALTCW)
+ alt = DLM_LOCK_CW;
+
+ if (alt) {
+ lkb->lkb_rqmode = alt;
+ rv = _can_be_granted(r, lkb, now);
+ if (rv)
+ lkb->lkb_sbflags |= DLM_SBF_ALTMODE;
+ else
+ lkb->lkb_rqmode = rqmode;
+ }
+ out:
+ return rv;
+}
+
+static int grant_pending_convert(struct dlm_rsb *r, int high)
+{
+ struct dlm_lkb *lkb, *s;
+ int hi, demoted, quit, grant_restart, demote_restart;
+
+ quit = 0;
+ restart:
+ grant_restart = 0;
+ demote_restart = 0;
+ hi = DLM_LOCK_IV;
+
+ list_for_each_entry_safe(lkb, s, &r->res_convertqueue, lkb_statequeue) {
+ demoted = is_demoted(lkb);
+ if (can_be_granted(r, lkb, 0)) {
+ grant_lock_pending(r, lkb);
+ grant_restart = 1;
+ } else {
+ hi = max_t(int, lkb->lkb_rqmode, hi);
+ if (!demoted && is_demoted(lkb))
+ demote_restart = 1;
+ }
+ }
+
+ if (grant_restart)
+ goto restart;
+ if (demote_restart && !quit) {
+ quit = 1;
+ goto restart;
+ }
+
+ return max_t(int, high, hi);
+}
+
+static int grant_pending_wait(struct dlm_rsb *r, int high)
+{
+ struct dlm_lkb *lkb, *s;
+
+ list_for_each_entry_safe(lkb, s, &r->res_waitqueue, lkb_statequeue) {
+ if (can_be_granted(r, lkb, 0))
+ grant_lock_pending(r, lkb);
+ else
+ high = max_t(int, lkb->lkb_rqmode, high);
+ }
+
+ return high;
+}
+
+static void grant_pending_locks(struct dlm_rsb *r)
+{
+ struct dlm_lkb *lkb, *s;
+ int high = DLM_LOCK_IV;
+
+ DLM_ASSERT(is_master(r), dlm_dump_rsb(r););
+
+ high = grant_pending_convert(r, high);
+ high = grant_pending_wait(r, high);
+
+ if (high == DLM_LOCK_IV)
+ return;
+
+ /*
+ * If there are locks left on the wait/convert queue then send blocking
+ * ASTs to granted locks based on the largest requested mode (high)
+ * found above. FIXME: highbast < high comparison not valid for PR/CW.
+ */
+
+ list_for_each_entry_safe(lkb, s, &r->res_grantqueue, lkb_statequeue) {
+ if (lkb->lkb_bastaddr && (lkb->lkb_highbast < high) &&
+ !__dlm_compat_matrix[lkb->lkb_grmode+1][high+1]) {
+ queue_bast(r, lkb, high);
+ lkb->lkb_highbast = high;
+ }
+ }
+}
+
+static void send_bast_queue(struct dlm_rsb *r, struct list_head *head,
+ struct dlm_lkb *lkb)
+{
+ struct dlm_lkb *gr;
+
+ list_for_each_entry(gr, head, lkb_statequeue) {
+ if (gr->lkb_bastaddr &&
+ gr->lkb_highbast < lkb->lkb_rqmode &&
+ !modes_compat(gr, lkb)) {
+ queue_bast(r, gr, lkb->lkb_rqmode);
+ gr->lkb_highbast = lkb->lkb_rqmode;
+ }
+ }
+}
+
+static void send_blocking_asts(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ send_bast_queue(r, &r->res_grantqueue, lkb);
+}
+
+static void send_blocking_asts_all(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ send_bast_queue(r, &r->res_grantqueue, lkb);
+ send_bast_queue(r, &r->res_convertqueue, lkb);
+}
+
+/* set_master(r, lkb) -- set the master nodeid of a resource
+
+ The purpose of this function is to set the nodeid field in the given
+ lkb using the nodeid field in the given rsb. If the rsb's nodeid is
+ known, it can just be copied to the lkb and the function will return
+ 0. If the rsb's nodeid is _not_ known, it needs to be looked up
+ before it can be copied to the lkb.
+
+ When the rsb nodeid is being looked up remotely, the initial lkb
+ causing the lookup is kept on the ls_waiters list waiting for the
+ lookup reply. Other lkb's waiting for the same rsb lookup are kept
+ on the rsb's res_lookup list until the master is verified.
+
+ Return values:
+ 0: nodeid is set in rsb/lkb and the caller should go ahead and use it
+ 1: the rsb master is not available and the lkb has been placed on
+ a wait queue
+*/
+
+static int set_master(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ struct dlm_ls *ls = r->res_ls;
+ int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+
+ if (rsb_flag(r, RSB_MASTER_UNCERTAIN)) {
+ rsb_clear_flag(r, RSB_MASTER_UNCERTAIN);
+ r->res_first_lkid = lkb->lkb_id;
+ lkb->lkb_nodeid = r->res_nodeid;
+ return 0;
+ }
+
+ if (r->res_first_lkid && r->res_first_lkid != lkb->lkb_id) {
+ list_add_tail(&lkb->lkb_rsb_lookup, &r->res_lookup);
+ return 1;
+ }
+
+ if (r->res_nodeid == 0) {
+ lkb->lkb_nodeid = 0;
+ return 0;
+ }
+
+ if (r->res_nodeid > 0) {
+ lkb->lkb_nodeid = r->res_nodeid;
+ return 0;
+ }
+
+ DLM_ASSERT(r->res_nodeid == -1, dlm_dump_rsb(r););
+
+ dir_nodeid = dlm_dir_nodeid(r);
+
+ if (dir_nodeid != our_nodeid) {
+ r->res_first_lkid = lkb->lkb_id;
+ send_lookup(r, lkb);
+ return 1;
+ }
+
+ for (;;) {
+ /* It's possible for dlm_scand to remove an old rsb for
+ this same resource from the toss list, us to create
+ a new one, look up the master locally, and find it
+ already exists just before dlm_scand does the
+ dir_remove() on the previous rsb. */
+
+ error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
+ r->res_length, &ret_nodeid);
+ if (!error)
+ break;
+ log_debug(ls, "dir_lookup error %d %s", error, r->res_name);
+ schedule();
+ }
+
+ if (ret_nodeid == our_nodeid) {
+ r->res_first_lkid = 0;
+ r->res_nodeid = 0;
+ lkb->lkb_nodeid = 0;
+ } else {
+ r->res_first_lkid = lkb->lkb_id;
+ r->res_nodeid = ret_nodeid;
+ lkb->lkb_nodeid = ret_nodeid;
+ }
+ return 0;
+}
+
+static void process_lookup_list(struct dlm_rsb *r)
+{
+ struct dlm_lkb *lkb, *safe;
+
+ list_for_each_entry_safe(lkb, safe, &r->res_lookup, lkb_rsb_lookup) {
+ list_del(&lkb->lkb_rsb_lookup);
+ _request_lock(r, lkb);
+ schedule();
+ }
+}
+
+/* confirm_master -- confirm (or deny) an rsb's master nodeid */
+
+static void confirm_master(struct dlm_rsb *r, int error)
+{
+ struct dlm_lkb *lkb;
+
+ if (!r->res_first_lkid)
+ return;
+
+ switch (error) {
+ case 0:
+ case -EINPROGRESS:
+ r->res_first_lkid = 0;
+ process_lookup_list(r);
+ break;
+
+ case -EAGAIN:
+ /* the remote master didn't queue our NOQUEUE request;
+ make a waiting lkb the first_lkid */
+
+ r->res_first_lkid = 0;
+
+ if (!list_empty(&r->res_lookup)) {
+ lkb = list_entry(r->res_lookup.next, struct dlm_lkb,
+ lkb_rsb_lookup);
+ list_del(&lkb->lkb_rsb_lookup);
+ r->res_first_lkid = lkb->lkb_id;
+ _request_lock(r, lkb);
+ } else
+ r->res_nodeid = -1;
+ break;
+
+ default:
+ log_error(r->res_ls, "confirm_master unknown error %d", error);
+ }
+}
+
+static int set_lock_args(int mode, struct dlm_lksb *lksb, uint32_t flags,
+ int namelen, uint32_t parent_lkid, void *ast,
+ void *astarg, void *bast, struct dlm_args *args)
+{
+ int rv = -EINVAL;
+
+ /* check for invalid arg usage */
+
+ if (mode < 0 || mode > DLM_LOCK_EX)
+ goto out;
+
+ if (!(flags & DLM_LKF_CONVERT) && (namelen > DLM_RESNAME_MAXLEN))
+ goto out;
+
+ if (flags & DLM_LKF_CANCEL)
+ goto out;
+
+ if (flags & DLM_LKF_QUECVT && !(flags & DLM_LKF_CONVERT))
+ goto out;
+
+ if (flags & DLM_LKF_CONVDEADLK && !(flags & DLM_LKF_CONVERT))
+ goto out;
+
+ if (flags & DLM_LKF_CONVDEADLK && flags & DLM_LKF_NOQUEUE)
+ goto out;
+
+ if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_CONVERT)
+ goto out;
+
+ if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_QUECVT)
+ goto out;
+
+ if (flags & DLM_LKF_EXPEDITE && flags & DLM_LKF_NOQUEUE)
+ goto out;
+
+ if (flags & DLM_LKF_EXPEDITE && mode != DLM_LOCK_NL)
+ goto out;
+
+ if (!ast || !lksb)
+ goto out;
+
+ if (flags & DLM_LKF_VALBLK && !lksb->sb_lvbptr)
+ goto out;
+
+ /* parent/child locks not yet supported */
+ if (parent_lkid)
+ goto out;
+
+ if (flags & DLM_LKF_CONVERT && !lksb->sb_lkid)
+ goto out;
+
+ /* these args will be copied to the lkb in validate_lock_args,
+ it cannot be done now because when converting locks, fields in
+ an active lkb cannot be modified before locking the rsb */
+
+ args->flags = flags;
+ args->astaddr = ast;
+ args->astparam = (long) astarg;
+ args->bastaddr = bast;
+ args->mode = mode;
+ args->lksb = lksb;
+ rv = 0;
+ out:
+ return rv;
+}
+
+static int set_unlock_args(uint32_t flags, void *astarg, struct dlm_args *args)
+{
+ if (flags & ~(DLM_LKF_CANCEL | DLM_LKF_VALBLK | DLM_LKF_IVVALBLK |
+ DLM_LKF_FORCEUNLOCK))
+ return -EINVAL;
+
+ args->flags = flags;
+ args->astparam = (long) astarg;
+ return 0;
+}
+
+static int validate_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_args *args)
+{
+ int rv = -EINVAL;
+
+ if (args->flags & DLM_LKF_CONVERT) {
+ if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+ goto out;
+
+ if (args->flags & DLM_LKF_QUECVT &&
+ !__quecvt_compat_matrix[lkb->lkb_grmode+1][args->mode+1])
+ goto out;
+
+ rv = -EBUSY;
+ if (lkb->lkb_status != DLM_LKSTS_GRANTED)
+ goto out;
+
+ if (lkb->lkb_wait_type)
+ goto out;
+ }
+
+ lkb->lkb_exflags = args->flags;
+ lkb->lkb_sbflags = 0;
+ lkb->lkb_astaddr = args->astaddr;
+ lkb->lkb_astparam = args->astparam;
+ lkb->lkb_bastaddr = args->bastaddr;
+ lkb->lkb_rqmode = args->mode;
+ lkb->lkb_lksb = args->lksb;
+ lkb->lkb_lvbptr = args->lksb->sb_lvbptr;
+ lkb->lkb_ownpid = (int) current->pid;
+ rv = 0;
+ out:
+ return rv;
+}
+
+static int validate_unlock_args(struct dlm_lkb *lkb, struct dlm_args *args)
+{
+ int rv = -EINVAL;
+
+ if (lkb->lkb_flags & DLM_IFL_MSTCPY)
+ goto out;
+
+ if (args->flags & DLM_LKF_FORCEUNLOCK)
+ goto out_ok;
+
+ if (args->flags & DLM_LKF_CANCEL &&
+ lkb->lkb_status == DLM_LKSTS_GRANTED)
+ goto out;
+
+ if (!(args->flags & DLM_LKF_CANCEL) &&
+ lkb->lkb_status != DLM_LKSTS_GRANTED)
+ goto out;
+
+ rv = -EBUSY;
+ if (lkb->lkb_wait_type)
+ goto out;
+
+ out_ok:
+ lkb->lkb_exflags = args->flags;
+ lkb->lkb_sbflags = 0;
+ lkb->lkb_astparam = args->astparam;
+
+ rv = 0;
+ out:
+ return rv;
+}
+
+/*
+ * Four stage 4 varieties:
+ * do_request(), do_convert(), do_unlock(), do_cancel()
+ * These are called on the master node for the given lock and
+ * from the central locking logic.
+ */
+
+static int do_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int error = 0;
+
+ if (can_be_granted(r, lkb, 1)) {
+ grant_lock(r, lkb);
+ queue_cast(r, lkb, 0);
+ goto out;
+ }
+
+ if (can_be_queued(lkb)) {
+ error = -EINPROGRESS;
+ add_lkb(r, lkb, DLM_LKSTS_WAITING);
+ send_blocking_asts(r, lkb);
+ goto out;
+ }
+
+ error = -EAGAIN;
+ if (force_blocking_asts(lkb))
+ send_blocking_asts_all(r, lkb);
+ queue_cast(r, lkb, -EAGAIN);
+
+ out:
+ return error;
+}
+
+static int do_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int error = 0;
+
+ /* changing an existing lock may allow others to be granted */
+
+ if (can_be_granted(r, lkb, 1)) {
+ grant_lock(r, lkb);
+ queue_cast(r, lkb, 0);
+ grant_pending_locks(r);
+ goto out;
+ }
+
+ if (can_be_queued(lkb)) {
+ if (is_demoted(lkb))
+ grant_pending_locks(r);
+ error = -EINPROGRESS;
+ del_lkb(r, lkb);
+ add_lkb(r, lkb, DLM_LKSTS_CONVERT);
+ send_blocking_asts(r, lkb);
+ goto out;
+ }
+
+ error = -EAGAIN;
+ if (force_blocking_asts(lkb))
+ send_blocking_asts_all(r, lkb);
+ queue_cast(r, lkb, -EAGAIN);
+
+ out:
+ return error;
+}
+
+static int do_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ remove_lock(r, lkb);
+ queue_cast(r, lkb, -DLM_EUNLOCK);
+ grant_pending_locks(r);
+ return -DLM_EUNLOCK;
+}
+
+/* FIXME: if revert_lock() finds that the lkb is granted, we should
+ skip the queue_cast(ECANCEL). It indicates that the request/convert
+ completed (and queued a normal ast) just before the cancel; we don't
+ want to clobber the sb_result for the normal ast with ECANCEL. */
+
+static int do_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ revert_lock(r, lkb);
+ queue_cast(r, lkb, -DLM_ECANCEL);
+ grant_pending_locks(r);
+ return -DLM_ECANCEL;
+}
+
+/*
+ * Four stage 3 varieties:
+ * _request_lock(), _convert_lock(), _unlock_lock(), _cancel_lock()
+ */
+
+/* add a new lkb to a possibly new rsb, called by requesting process */
+
+static int _request_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int error;
+
+ /* set_master: sets lkb nodeid from r */
+
+ error = set_master(r, lkb);
+ if (error < 0)
+ goto out;
+ if (error) {
+ error = 0;
+ goto out;
+ }
+
+ if (is_remote(r))
+ /* receive_request() calls do_request() on remote node */
+ error = send_request(r, lkb);
+ else
+ error = do_request(r, lkb);
+ out:
+ return error;
+}
+
+/* change some property of an existing lkb, e.g. mode */
+
+static int _convert_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int error;
+
+ if (is_remote(r))
+ /* receive_convert() calls do_convert() on remote node */
+ error = send_convert(r, lkb);
+ else
+ error = do_convert(r, lkb);
+
+ return error;
+}
+
+/* remove an existing lkb from the granted queue */
+
+static int _unlock_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int error;
+
+ if (is_remote(r))
+ /* receive_unlock() calls do_unlock() on remote node */
+ error = send_unlock(r, lkb);
+ else
+ error = do_unlock(r, lkb);
+
+ return error;
+}
+
+/* remove an existing lkb from the convert or wait queue */
+
+static int _cancel_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int error;
+
+ if (is_remote(r))
+ /* receive_cancel() calls do_cancel() on remote node */
+ error = send_cancel(r, lkb);
+ else
+ error = do_cancel(r, lkb);
+
+ return error;
+}
+
+/*
+ * Four stage 2 varieties:
+ * request_lock(), convert_lock(), unlock_lock(), cancel_lock()
+ */
+
+static int request_lock(struct dlm_ls *ls, struct dlm_lkb *lkb, char *name,
+ int len, struct dlm_args *args)
+{
+ struct dlm_rsb *r;
+ int error;
+
+ error = validate_lock_args(ls, lkb, args);
+ if (error)
+ goto out;
+
+ error = find_rsb(ls, name, len, R_CREATE, &r);
+ if (error)
+ goto out;
+
+ lock_rsb(r);
+
+ attach_lkb(r, lkb);
+ lkb->lkb_lksb->sb_lkid = lkb->lkb_id;
+
+ error = _request_lock(r, lkb);
+
+ unlock_rsb(r);
+ put_rsb(r);
+
+ out:
+ return error;
+}
+
+static int convert_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_args *args)
+{
+ struct dlm_rsb *r;
+ int error;
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ error = validate_lock_args(ls, lkb, args);
+ if (error)
+ goto out;
+
+ error = _convert_lock(r, lkb);
+ out:
+ unlock_rsb(r);
+ put_rsb(r);
+ return error;
+}
+
+static int unlock_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_args *args)
+{
+ struct dlm_rsb *r;
+ int error;
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ error = validate_unlock_args(lkb, args);
+ if (error)
+ goto out;
+
+ error = _unlock_lock(r, lkb);
+ out:
+ unlock_rsb(r);
+ put_rsb(r);
+ return error;
+}
+
+static int cancel_lock(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_args *args)
+{
+ struct dlm_rsb *r;
+ int error;
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ error = validate_unlock_args(lkb, args);
+ if (error)
+ goto out;
+
+ error = _cancel_lock(r, lkb);
+ out:
+ unlock_rsb(r);
+ put_rsb(r);
+ return error;
+}
+
+/*
+ * Two stage 1 varieties: dlm_lock() and dlm_unlock()
+ */
+
+int dlm_lock(dlm_lockspace_t *lockspace,
+ int mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ void *name,
+ unsigned int namelen,
+ uint32_t parent_lkid,
+ void (*ast) (void *astarg),
+ void *astarg,
+ void (*bast) (void *astarg, int mode))
+{
+ struct dlm_ls *ls;
+ struct dlm_lkb *lkb;
+ struct dlm_args args;
+ int error, convert = flags & DLM_LKF_CONVERT;
+
+ ls = dlm_find_lockspace_local(lockspace);
+ if (!ls)
+ return -EINVAL;
+
+ lock_recovery(ls);
+
+ if (convert)
+ error = find_lkb(ls, lksb->sb_lkid, &lkb);
+ else
+ error = create_lkb(ls, &lkb);
+
+ if (error)
+ goto out;
+
+ error = set_lock_args(mode, lksb, flags, namelen, parent_lkid, ast,
+ astarg, bast, &args);
+ if (error)
+ goto out_put;
+
+ if (convert)
+ error = convert_lock(ls, lkb, &args);
+ else
+ error = request_lock(ls, lkb, name, namelen, &args);
+
+ if (error == -EINPROGRESS)
+ error = 0;
+ out_put:
+ if (convert || error)
+ __put_lkb(ls, lkb);
+ if (error == -EAGAIN)
+ error = 0;
+ out:
+ unlock_recovery(ls);
+ dlm_put_lockspace(ls);
+ return error;
+}
+
+int dlm_unlock(dlm_lockspace_t *lockspace,
+ uint32_t lkid,
+ uint32_t flags,
+ struct dlm_lksb *lksb,
+ void *astarg)
+{
+ struct dlm_ls *ls;
+ struct dlm_lkb *lkb;
+ struct dlm_args args;
+ int error;
+
+ ls = dlm_find_lockspace_local(lockspace);
+ if (!ls)
+ return -EINVAL;
+
+ lock_recovery(ls);
+
+ error = find_lkb(ls, lkid, &lkb);
+ if (error)
+ goto out;
+
+ error = set_unlock_args(flags, astarg, &args);
+ if (error)
+ goto out_put;
+
+ if (flags & DLM_LKF_CANCEL)
+ error = cancel_lock(ls, lkb, &args);
+ else
+ error = unlock_lock(ls, lkb, &args);
+
+ if (error == -DLM_EUNLOCK || error == -DLM_ECANCEL)
+ error = 0;
+ out_put:
+ dlm_put_lkb(lkb);
+ out:
+ unlock_recovery(ls);
+ dlm_put_lockspace(ls);
+ return error;
+}
+
+/*
+ * send/receive routines for remote operations and replies
+ *
+ * send_args
+ * send_common
+ * send_request receive_request
+ * send_convert receive_convert
+ * send_unlock receive_unlock
+ * send_cancel receive_cancel
+ * send_grant receive_grant
+ * send_bast receive_bast
+ * send_lookup receive_lookup
+ * send_remove receive_remove
+ *
+ * send_common_reply
+ * receive_request_reply send_request_reply
+ * receive_convert_reply send_convert_reply
+ * receive_unlock_reply send_unlock_reply
+ * receive_cancel_reply send_cancel_reply
+ * receive_lookup_reply send_lookup_reply
+ */
+
+static int create_message(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ int to_nodeid, int mstype,
+ struct dlm_message **ms_ret,
+ struct dlm_mhandle **mh_ret)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ char *mb;
+ int mb_len = sizeof(struct dlm_message);
+
+ switch (mstype) {
+ case DLM_MSG_REQUEST:
+ case DLM_MSG_LOOKUP:
+ case DLM_MSG_REMOVE:
+ mb_len += r->res_length;
+ break;
+ case DLM_MSG_CONVERT:
+ case DLM_MSG_UNLOCK:
+ case DLM_MSG_REQUEST_REPLY:
+ case DLM_MSG_CONVERT_REPLY:
+ case DLM_MSG_GRANT:
+ if (lkb && lkb->lkb_lvbptr)
+ mb_len += r->res_ls->ls_lvblen;
+ break;
+ }
+
+ /* get_buffer gives us a message handle (mh) that we need to
+ pass into lowcomms_commit and a message buffer (mb) that we
+ write our data into */
+
+ mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
+ if (!mh)
+ return -ENOBUFS;
+
+ memset(mb, 0, mb_len);
+
+ ms = (struct dlm_message *) mb;
+
+ ms->m_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+ ms->m_header.h_lockspace = r->res_ls->ls_global_id;
+ ms->m_header.h_nodeid = dlm_our_nodeid();
+ ms->m_header.h_length = mb_len;
+ ms->m_header.h_cmd = DLM_MSG;
+
+ ms->m_type = mstype;
+
+ *mh_ret = mh;
+ *ms_ret = ms;
+ return 0;
+}
+
+/* further lowcomms enhancements or alternate implementations may make
+ the return value from this function useful at some point */
+
+static int send_message(struct dlm_mhandle *mh, struct dlm_message *ms)
+{
+ dlm_message_out(ms);
+ dlm_lowcomms_commit_buffer(mh);
+ return 0;
+}
+
+static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ ms->m_nodeid = lkb->lkb_nodeid;
+ ms->m_pid = lkb->lkb_ownpid;
+ ms->m_lkid = lkb->lkb_id;
+ ms->m_remid = lkb->lkb_remid;
+ ms->m_exflags = lkb->lkb_exflags;
+ ms->m_sbflags = lkb->lkb_sbflags;
+ ms->m_flags = lkb->lkb_flags;
+ ms->m_lvbseq = lkb->lkb_lvbseq;
+ ms->m_status = lkb->lkb_status;
+ ms->m_grmode = lkb->lkb_grmode;
+ ms->m_rqmode = lkb->lkb_rqmode;
+ ms->m_hash = r->res_hash;
+
+ /* m_result and m_bastmode are set from function args,
+ not from lkb fields */
+
+ if (lkb->lkb_bastaddr)
+ ms->m_asts |= AST_BAST;
+ if (lkb->lkb_astaddr)
+ ms->m_asts |= AST_COMP;
+
+ if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP)
+ memcpy(ms->m_extra, r->res_name, r->res_length);
+
+ else if (lkb->lkb_lvbptr)
+ memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+
+}
+
+static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int to_nodeid, error;
+
+ add_to_waiters(lkb, mstype);
+
+ to_nodeid = r->res_nodeid;
+
+ error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+ if (error)
+ goto fail;
+
+ send_args(r, lkb, ms);
+
+ error = send_message(mh, ms);
+ if (error)
+ goto fail;
+ return 0;
+
+ fail:
+ remove_from_waiters(lkb);
+ return error;
+}
+
+static int send_request(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ return send_common(r, lkb, DLM_MSG_REQUEST);
+}
+
+static int send_convert(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ int error;
+
+ error = send_common(r, lkb, DLM_MSG_CONVERT);
+
+ /* down conversions go without a reply from the master */
+ if (!error && down_conversion(lkb)) {
+ remove_from_waiters(lkb);
+ r->res_ls->ls_stub_ms.m_result = 0;
+ r->res_ls->ls_stub_ms.m_flags = lkb->lkb_flags;
+ __receive_convert_reply(r, lkb, &r->res_ls->ls_stub_ms);
+ }
+
+ return error;
+}
+
+/* FIXME: if this lkb is the only lock we hold on the rsb, then set
+ MASTER_UNCERTAIN to force the next request on the rsb to confirm
+ that the master is still correct. */
+
+static int send_unlock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ return send_common(r, lkb, DLM_MSG_UNLOCK);
+}
+
+static int send_cancel(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ return send_common(r, lkb, DLM_MSG_CANCEL);
+}
+
+static int send_grant(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int to_nodeid, error;
+
+ to_nodeid = lkb->lkb_nodeid;
+
+ error = create_message(r, lkb, to_nodeid, DLM_MSG_GRANT, &ms, &mh);
+ if (error)
+ goto out;
+
+ send_args(r, lkb, ms);
+
+ ms->m_result = 0;
+
+ error = send_message(mh, ms);
+ out:
+ return error;
+}
+
+static int send_bast(struct dlm_rsb *r, struct dlm_lkb *lkb, int mode)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int to_nodeid, error;
+
+ to_nodeid = lkb->lkb_nodeid;
+
+ error = create_message(r, NULL, to_nodeid, DLM_MSG_BAST, &ms, &mh);
+ if (error)
+ goto out;
+
+ send_args(r, lkb, ms);
+
+ ms->m_bastmode = mode;
+
+ error = send_message(mh, ms);
+ out:
+ return error;
+}
+
+static int send_lookup(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int to_nodeid, error;
+
+ add_to_waiters(lkb, DLM_MSG_LOOKUP);
+
+ to_nodeid = dlm_dir_nodeid(r);
+
+ error = create_message(r, NULL, to_nodeid, DLM_MSG_LOOKUP, &ms, &mh);
+ if (error)
+ goto fail;
+
+ send_args(r, lkb, ms);
+
+ error = send_message(mh, ms);
+ if (error)
+ goto fail;
+ return 0;
+
+ fail:
+ remove_from_waiters(lkb);
+ return error;
+}
+
+static int send_remove(struct dlm_rsb *r)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int to_nodeid, error;
+
+ to_nodeid = dlm_dir_nodeid(r);
+
+ error = create_message(r, NULL, to_nodeid, DLM_MSG_REMOVE, &ms, &mh);
+ if (error)
+ goto out;
+
+ memcpy(ms->m_extra, r->res_name, r->res_length);
+ ms->m_hash = r->res_hash;
+
+ error = send_message(mh, ms);
+ out:
+ return error;
+}
+
+static int send_common_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ int mstype, int rv)
+{
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int to_nodeid, error;
+
+ to_nodeid = lkb->lkb_nodeid;
+
+ error = create_message(r, lkb, to_nodeid, mstype, &ms, &mh);
+ if (error)
+ goto out;
+
+ send_args(r, lkb, ms);
+
+ ms->m_result = rv;
+
+ error = send_message(mh, ms);
+ out:
+ return error;
+}
+
+static int send_request_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+ return send_common_reply(r, lkb, DLM_MSG_REQUEST_REPLY, rv);
+}
+
+static int send_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+ return send_common_reply(r, lkb, DLM_MSG_CONVERT_REPLY, rv);
+}
+
+static int send_unlock_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+ return send_common_reply(r, lkb, DLM_MSG_UNLOCK_REPLY, rv);
+}
+
+static int send_cancel_reply(struct dlm_rsb *r, struct dlm_lkb *lkb, int rv)
+{
+ return send_common_reply(r, lkb, DLM_MSG_CANCEL_REPLY, rv);
+}
+
+static int send_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms_in,
+ int ret_nodeid, int rv)
+{
+ struct dlm_rsb *r = &ls->ls_stub_rsb;
+ struct dlm_message *ms;
+ struct dlm_mhandle *mh;
+ int error, nodeid = ms_in->m_header.h_nodeid;
+
+ error = create_message(r, NULL, nodeid, DLM_MSG_LOOKUP_REPLY, &ms, &mh);
+ if (error)
+ goto out;
+
+ ms->m_lkid = ms_in->m_lkid;
+ ms->m_result = rv;
+ ms->m_nodeid = ret_nodeid;
+
+ error = send_message(mh, ms);
+ out:
+ return error;
+}
+
+/* which args we save from a received message depends heavily on the type
+ of message, unlike the send side where we can safely send everything about
+ the lkb for any type of message */
+
+static void receive_flags(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ lkb->lkb_exflags = ms->m_exflags;
+ lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
+ (ms->m_flags & 0x0000FFFF);
+}
+
+static void receive_flags_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ lkb->lkb_sbflags = ms->m_sbflags;
+ lkb->lkb_flags = (lkb->lkb_flags & 0xFFFF0000) |
+ (ms->m_flags & 0x0000FFFF);
+}
+
+static int receive_extralen(struct dlm_message *ms)
+{
+ return (ms->m_header.h_length - sizeof(struct dlm_message));
+}
+
+static int receive_lvb(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ int len;
+
+ if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+ if (!lkb->lkb_lvbptr)
+ lkb->lkb_lvbptr = allocate_lvb(ls);
+ if (!lkb->lkb_lvbptr)
+ return -ENOMEM;
+ len = receive_extralen(ms);
+ memcpy(lkb->lkb_lvbptr, ms->m_extra, len);
+ }
+ return 0;
+}
+
+static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ lkb->lkb_nodeid = ms->m_header.h_nodeid;
+ lkb->lkb_ownpid = ms->m_pid;
+ lkb->lkb_remid = ms->m_lkid;
+ lkb->lkb_grmode = DLM_LOCK_IV;
+ lkb->lkb_rqmode = ms->m_rqmode;
+ lkb->lkb_bastaddr = (void *) (long) (ms->m_asts & AST_BAST);
+ lkb->lkb_astaddr = (void *) (long) (ms->m_asts & AST_COMP);
+
+ DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
+
+ if (receive_lvb(ls, lkb, ms))
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int receive_convert_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ if (lkb->lkb_nodeid != ms->m_header.h_nodeid) {
+ log_error(ls, "convert_args nodeid %d %d lkid %x %x",
+ lkb->lkb_nodeid, ms->m_header.h_nodeid,
+ lkb->lkb_id, lkb->lkb_remid);
+ return -EINVAL;
+ }
+
+ if (!is_master_copy(lkb))
+ return -EINVAL;
+
+ if (lkb->lkb_status != DLM_LKSTS_GRANTED)
+ return -EBUSY;
+
+ if (receive_lvb(ls, lkb, ms))
+ return -ENOMEM;
+
+ lkb->lkb_rqmode = ms->m_rqmode;
+ lkb->lkb_lvbseq = ms->m_lvbseq;
+
+ return 0;
+}
+
+static int receive_unlock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ if (!is_master_copy(lkb))
+ return -EINVAL;
+ if (receive_lvb(ls, lkb, ms))
+ return -ENOMEM;
+ return 0;
+}
+
+/* We fill in the stub-lkb fields with the info that send_xxxx_reply()
+ uses to send a reply and that the remote end uses to process the reply. */
+
+static void setup_stub_lkb(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb = &ls->ls_stub_lkb;
+ lkb->lkb_nodeid = ms->m_header.h_nodeid;
+ lkb->lkb_remid = ms->m_lkid;
+}
+
+static void receive_request(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error, namelen;
+
+ error = create_lkb(ls, &lkb);
+ if (error)
+ goto fail;
+
+ receive_flags(lkb, ms);
+ lkb->lkb_flags |= DLM_IFL_MSTCPY;
+ error = receive_request_args(ls, lkb, ms);
+ if (error) {
+ __put_lkb(ls, lkb);
+ goto fail;
+ }
+
+ namelen = receive_extralen(ms);
+
+ error = find_rsb(ls, ms->m_extra, namelen, R_MASTER, &r);
+ if (error) {
+ __put_lkb(ls, lkb);
+ goto fail;
+ }
+
+ lock_rsb(r);
+
+ attach_lkb(r, lkb);
+ error = do_request(r, lkb);
+ send_request_reply(r, lkb, error);
+
+ unlock_rsb(r);
+ put_rsb(r);
+
+ if (error == -EINPROGRESS)
+ error = 0;
+ if (error)
+ dlm_put_lkb(lkb);
+ return;
+
+ fail:
+ setup_stub_lkb(ls, ms);
+ send_request_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_convert(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error, reply = 1;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error)
+ goto fail;
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ receive_flags(lkb, ms);
+ error = receive_convert_args(ls, lkb, ms);
+ if (error)
+ goto out;
+ reply = !down_conversion(lkb);
+
+ error = do_convert(r, lkb);
+ out:
+ if (reply)
+ send_convert_reply(r, lkb, error);
+
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
+ return;
+
+ fail:
+ setup_stub_lkb(ls, ms);
+ send_convert_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_unlock(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error)
+ goto fail;
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ receive_flags(lkb, ms);
+ error = receive_unlock_args(ls, lkb, ms);
+ if (error)
+ goto out;
+
+ error = do_unlock(r, lkb);
+ out:
+ send_unlock_reply(r, lkb, error);
+
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
+ return;
+
+ fail:
+ setup_stub_lkb(ls, ms);
+ send_unlock_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_cancel(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error)
+ goto fail;
+
+ receive_flags(lkb, ms);
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ error = do_cancel(r, lkb);
+ send_cancel_reply(r, lkb, error);
+
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
+ return;
+
+ fail:
+ setup_stub_lkb(ls, ms);
+ send_cancel_reply(&ls->ls_stub_rsb, &ls->ls_stub_lkb, error);
+}
+
+static void receive_grant(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error) {
+ log_error(ls, "receive_grant no lkb");
+ return;
+ }
+ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ receive_flags_reply(lkb, ms);
+ grant_lock_pc(r, lkb, ms);
+ queue_cast(r, lkb, 0);
+
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
+}
+
+static void receive_bast(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error) {
+ log_error(ls, "receive_bast no lkb");
+ return;
+ }
+ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+ r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ queue_bast(r, lkb, ms->m_bastmode);
+
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
+}
+
+static void receive_lookup(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ int len, error, ret_nodeid, dir_nodeid, from_nodeid, our_nodeid;
+
+ from_nodeid = ms->m_header.h_nodeid;
+ our_nodeid = dlm_our_nodeid();
+
+ len = receive_extralen(ms);
+
+ dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
+ if (dir_nodeid != our_nodeid) {
+ log_error(ls, "lookup dir_nodeid %d from %d",
+ dir_nodeid, from_nodeid);
+ error = -EINVAL;
+ ret_nodeid = -1;
+ goto out;
+ }
+
+ error = dlm_dir_lookup(ls, from_nodeid, ms->m_extra, len, &ret_nodeid);
+
+ /* Optimization: we're master so treat lookup as a request */
+ if (!error && ret_nodeid == our_nodeid) {
+ receive_request(ls, ms);
+ return;
+ }
+ out:
+ send_lookup_reply(ls, ms, ret_nodeid, error);
+}
+
+static void receive_remove(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ int len, dir_nodeid, from_nodeid;
+
+ from_nodeid = ms->m_header.h_nodeid;
+
+ len = receive_extralen(ms);
+
+ dir_nodeid = dlm_hash2nodeid(ls, ms->m_hash);
+ if (dir_nodeid != dlm_our_nodeid()) {
+ log_error(ls, "remove dir entry dir_nodeid %d from %d",
+ dir_nodeid, from_nodeid);
+ return;
+ }
+
+ dlm_dir_remove_entry(ls, from_nodeid, ms->m_extra, len);
+}
+
+static void receive_request_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error, mstype;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error) {
+ log_error(ls, "receive_request_reply no lkb");
+ return;
+ }
+ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+ mstype = lkb->lkb_wait_type;
+ error = remove_from_waiters(lkb);
+ if (error) {
+ log_error(ls, "receive_request_reply not on waiters");
+ goto out;
+ }
+
+ /* this is the value returned from do_request() on the master */
+ error = ms->m_result;
+
+ r = lkb->lkb_resource;
+ hold_rsb(r);
+ lock_rsb(r);
+
+ /* Optimization: the dir node was also the master, so it took our
+ lookup as a request and sent request reply instead of lookup reply */
+ if (mstype == DLM_MSG_LOOKUP) {
+ r->res_nodeid = ms->m_header.h_nodeid;
+ lkb->lkb_nodeid = r->res_nodeid;
+ }
+
+ switch (error) {
+ case -EAGAIN:
+ /* request would block (be queued) on remote master;
+ the unhold undoes the original ref from create_lkb()
+ so it leads to the lkb being freed */
+ queue_cast(r, lkb, -EAGAIN);
+ confirm_master(r, -EAGAIN);
+ unhold_lkb(lkb);
+ break;
+
+ case -EINPROGRESS:
+ case 0:
+ /* request was queued or granted on remote master */
+ receive_flags_reply(lkb, ms);
+ lkb->lkb_remid = ms->m_lkid;
+ if (error)
+ add_lkb(r, lkb, DLM_LKSTS_WAITING);
+ else {
+ grant_lock_pc(r, lkb, ms);
+ queue_cast(r, lkb, 0);
+ }
+ confirm_master(r, error);
+ break;
+
+ case -EBADR:
+ case -ENOTBLK:
+ /* find_rsb failed to find rsb or rsb wasn't master */
+ r->res_nodeid = -1;
+ lkb->lkb_nodeid = -1;
+ _request_lock(r, lkb);
+ break;
+
+ default:
+ log_error(ls, "receive_request_reply error %d", error);
+ }
+
+ unlock_rsb(r);
+ put_rsb(r);
+ out:
+ dlm_put_lkb(lkb);
+}
+
+static void __receive_convert_reply(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ struct dlm_message *ms)
+{
+ int error = ms->m_result;
+
+ /* this is the value returned from do_convert() on the master */
+
+ switch (error) {
+ case -EAGAIN:
+ /* convert would block (be queued) on remote master */
+ queue_cast(r, lkb, -EAGAIN);
+ break;
+
+ case -EINPROGRESS:
+ /* convert was queued on remote master */
+ del_lkb(r, lkb);
+ add_lkb(r, lkb, DLM_LKSTS_CONVERT);
+ break;
+
+ case 0:
+ /* convert was granted on remote master */
+ receive_flags_reply(lkb, ms);
+ grant_lock_pc(r, lkb, ms);
+ queue_cast(r, lkb, 0);
+ break;
+
+ default:
+ log_error(r->res_ls, "receive_convert_reply error %d", error);
+ }
+}
+
+static void _receive_convert_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ struct dlm_rsb *r = lkb->lkb_resource;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ __receive_convert_reply(r, lkb, ms);
+
+ unlock_rsb(r);
+ put_rsb(r);
+}
+
+static void receive_convert_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ int error;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error) {
+ log_error(ls, "receive_convert_reply no lkb");
+ return;
+ }
+ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+ error = remove_from_waiters(lkb);
+ if (error) {
+ log_error(ls, "receive_convert_reply not on waiters");
+ goto out;
+ }
+
+ _receive_convert_reply(lkb, ms);
+ out:
+ dlm_put_lkb(lkb);
+}
+
+static void _receive_unlock_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ struct dlm_rsb *r = lkb->lkb_resource;
+ int error = ms->m_result;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ /* this is the value returned from do_unlock() on the master */
+
+ switch (error) {
+ case -DLM_EUNLOCK:
+ receive_flags_reply(lkb, ms);
+ remove_lock_pc(r, lkb);
+ queue_cast(r, lkb, -DLM_EUNLOCK);
+ break;
+ default:
+ log_error(r->res_ls, "receive_unlock_reply error %d", error);
+ }
+
+ unlock_rsb(r);
+ put_rsb(r);
+}
+
+static void receive_unlock_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ int error;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error) {
+ log_error(ls, "receive_unlock_reply no lkb");
+ return;
+ }
+ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+ error = remove_from_waiters(lkb);
+ if (error) {
+ log_error(ls, "receive_unlock_reply not on waiters");
+ goto out;
+ }
+
+ _receive_unlock_reply(lkb, ms);
+ out:
+ dlm_put_lkb(lkb);
+}
+
+static void _receive_cancel_reply(struct dlm_lkb *lkb, struct dlm_message *ms)
+{
+ struct dlm_rsb *r = lkb->lkb_resource;
+ int error = ms->m_result;
+
+ hold_rsb(r);
+ lock_rsb(r);
+
+ /* this is the value returned from do_cancel() on the master */
+
+ switch (error) {
+ case -DLM_ECANCEL:
+ receive_flags_reply(lkb, ms);
+ revert_lock_pc(r, lkb);
+ queue_cast(r, lkb, -DLM_ECANCEL);
+ break;
+ default:
+ log_error(r->res_ls, "receive_cancel_reply error %d", error);
+ }
+
+ unlock_rsb(r);
+ put_rsb(r);
+}
+
+static void receive_cancel_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ int error;
+
+ error = find_lkb(ls, ms->m_remid, &lkb);
+ if (error) {
+ log_error(ls, "receive_cancel_reply no lkb");
+ return;
+ }
+ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+ error = remove_from_waiters(lkb);
+ if (error) {
+ log_error(ls, "receive_cancel_reply not on waiters");
+ goto out;
+ }
+
+ _receive_cancel_reply(lkb, ms);
+ out:
+ dlm_put_lkb(lkb);
+}
+
+static void receive_lookup_reply(struct dlm_ls *ls, struct dlm_message *ms)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error, ret_nodeid;
+
+ error = find_lkb(ls, ms->m_lkid, &lkb);
+ if (error) {
+ log_error(ls, "receive_lookup_reply no lkb");
+ return;
+ }
+
+ error = remove_from_waiters(lkb);
+ if (error) {
+ log_error(ls, "receive_lookup_reply not on waiters");
+ goto out;
+ }
+
+ /* this is the value returned by dlm_dir_lookup on dir node
+ FIXME: will a non-zero error ever be returned? */
+ error = ms->m_result;
+
+ r = lkb->lkb_resource;
+ hold_rsb(r);
+ lock_rsb(r);
+
+ ret_nodeid = ms->m_nodeid;
+ if (ret_nodeid == dlm_our_nodeid()) {
+ r->res_nodeid = 0;
+ ret_nodeid = 0;
+ r->res_first_lkid = 0;
+ } else {
+ /* set_master() will copy res_nodeid to lkb_nodeid */
+ r->res_nodeid = ret_nodeid;
+ }
+
+ _request_lock(r, lkb);
+
+ if (!ret_nodeid)
+ process_lookup_list(r);
+
+ unlock_rsb(r);
+ put_rsb(r);
+ out:
+ dlm_put_lkb(lkb);
+}
+
+int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
+{
+ struct dlm_message *ms = (struct dlm_message *) hd;
+ struct dlm_ls *ls;
+ int error;
+
+ if (!recovery)
+ dlm_message_in(ms);
+
+ ls = dlm_find_lockspace_global(hd->h_lockspace);
+ if (!ls) {
+ log_print("drop message %d from %d for unknown lockspace %d",
+ ms->m_type, nodeid, hd->h_lockspace);
+ return -EINVAL;
+ }
+
+ /* recovery may have just ended leaving a bunch of backed-up requests
+ in the requestqueue; wait while dlm_recoverd clears them */
+
+ if (!recovery)
+ dlm_wait_requestqueue(ls);
+
+ /* recovery may have just started while there were a bunch of
+ in-flight requests -- save them in requestqueue to be processed
+ after recovery. we can't let dlm_recvd block on the recovery
+ lock. if dlm_recoverd is calling this function to clear the
+ requestqueue, it needs to be interrupted (-EINTR) if another
+ recovery operation is starting. */
+
+ while (1) {
+ if (dlm_locking_stopped(ls)) {
+ if (!recovery)
+ dlm_add_requestqueue(ls, nodeid, hd);
+ error = -EINTR;
+ goto out;
+ }
+
+ if (lock_recovery_try(ls))
+ break;
+ schedule();
+ }
+
+ switch (ms->m_type) {
+
+ /* messages sent to a master node */
+
+ case DLM_MSG_REQUEST:
+ receive_request(ls, ms);
+ break;
+
+ case DLM_MSG_CONVERT:
+ receive_convert(ls, ms);
+ break;
+
+ case DLM_MSG_UNLOCK:
+ receive_unlock(ls, ms);
+ break;
+
+ case DLM_MSG_CANCEL:
+ receive_cancel(ls, ms);
+ break;
+
+ /* messages sent from a master node (replies to above) */
+
+ case DLM_MSG_REQUEST_REPLY:
+ receive_request_reply(ls, ms);
+ break;
+
+ case DLM_MSG_CONVERT_REPLY:
+ receive_convert_reply(ls, ms);
+ break;
+
+ case DLM_MSG_UNLOCK_REPLY:
+ receive_unlock_reply(ls, ms);
+ break;
+
+ case DLM_MSG_CANCEL_REPLY:
+ receive_cancel_reply(ls, ms);
+ break;
+
+ /* messages sent from a master node (only two types of async msg) */
+
+ case DLM_MSG_GRANT:
+ receive_grant(ls, ms);
+ break;
+
+ case DLM_MSG_BAST:
+ receive_bast(ls, ms);
+ break;
+
+ /* messages sent to a dir node */
+
+ case DLM_MSG_LOOKUP:
+ receive_lookup(ls, ms);
+ break;
+
+ case DLM_MSG_REMOVE:
+ receive_remove(ls, ms);
+ break;
+
+ /* messages sent from a dir node (remove has no reply) */
+
+ case DLM_MSG_LOOKUP_REPLY:
+ receive_lookup_reply(ls, ms);
+ break;
+
+ default:
+ log_error(ls, "unknown message type %d", ms->m_type);
+ }
+
+ unlock_recovery(ls);
+ out:
+ dlm_put_lockspace(ls);
+ dlm_astd_wake();
+ return 0;
+}
+
+
+/*
+ * Recovery related
+ */
+
+static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+ if (middle_conversion(lkb)) {
+ hold_lkb(lkb);
+ ls->ls_stub_ms.m_result = -EINPROGRESS;
+ _remove_from_waiters(lkb);
+ _receive_convert_reply(lkb, &ls->ls_stub_ms);
+
+ /* Same special case as in receive_rcom_lock_args() */
+ lkb->lkb_grmode = DLM_LOCK_IV;
+ rsb_set_flag(lkb->lkb_resource, RSB_RECOVER_CONVERT);
+ unhold_lkb(lkb);
+
+ } else if (lkb->lkb_rqmode >= lkb->lkb_grmode) {
+ lkb->lkb_flags |= DLM_IFL_RESEND;
+ }
+
+ /* lkb->lkb_rqmode < lkb->lkb_grmode shouldn't happen since down
+ conversions are async; there's no reply from the remote master */
+}
+
+/* A waiting lkb needs recovery if the master node has failed, or
+ the master node is changing (only when no directory is used) */
+
+static int waiter_needs_recovery(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+ if (dlm_is_removed(ls, lkb->lkb_nodeid))
+ return 1;
+
+ if (!dlm_no_directory(ls))
+ return 0;
+
+ if (dlm_dir_nodeid(lkb->lkb_resource) != lkb->lkb_nodeid)
+ return 1;
+
+ return 0;
+}
+
+/* Recovery for locks that are waiting for replies from nodes that are now
+ gone. We can just complete unlocks and cancels by faking a reply from the
+ dead node. Requests and up-conversions we flag to be resent after
+ recovery. Down-conversions can just be completed with a fake reply like
+ unlocks. Conversions between PR and CW need special attention. */
+
+void dlm_recover_waiters_pre(struct dlm_ls *ls)
+{
+ struct dlm_lkb *lkb, *safe;
+
+ mutex_lock(&ls->ls_waiters_mutex);
+
+ list_for_each_entry_safe(lkb, safe, &ls->ls_waiters, lkb_wait_reply) {
+ log_debug(ls, "pre recover waiter lkid %x type %d flags %x",
+ lkb->lkb_id, lkb->lkb_wait_type, lkb->lkb_flags);
+
+ /* all outstanding lookups, regardless of destination will be
+ resent after recovery is done */
+
+ if (lkb->lkb_wait_type == DLM_MSG_LOOKUP) {
+ lkb->lkb_flags |= DLM_IFL_RESEND;
+ continue;
+ }
+
+ if (!waiter_needs_recovery(ls, lkb))
+ continue;
+
+ switch (lkb->lkb_wait_type) {
+
+ case DLM_MSG_REQUEST:
+ lkb->lkb_flags |= DLM_IFL_RESEND;
+ break;
+
+ case DLM_MSG_CONVERT:
+ recover_convert_waiter(ls, lkb);
+ break;
+
+ case DLM_MSG_UNLOCK:
+ hold_lkb(lkb);
+ ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
+ _remove_from_waiters(lkb);
+ _receive_unlock_reply(lkb, &ls->ls_stub_ms);
+ dlm_put_lkb(lkb);
+ break;
+
+ case DLM_MSG_CANCEL:
+ hold_lkb(lkb);
+ ls->ls_stub_ms.m_result = -DLM_ECANCEL;
+ _remove_from_waiters(lkb);
+ _receive_cancel_reply(lkb, &ls->ls_stub_ms);
+ dlm_put_lkb(lkb);
+ break;
+
+ default:
+ log_error(ls, "invalid lkb wait_type %d",
+ lkb->lkb_wait_type);
+ }
+ schedule();
+ }
+ mutex_unlock(&ls->ls_waiters_mutex);
+}
+
+static int remove_resend_waiter(struct dlm_ls *ls, struct dlm_lkb **lkb_ret)
+{
+ struct dlm_lkb *lkb;
+ int rv = 0;
+
+ mutex_lock(&ls->ls_waiters_mutex);
+ list_for_each_entry(lkb, &ls->ls_waiters, lkb_wait_reply) {
+ if (lkb->lkb_flags & DLM_IFL_RESEND) {
+ rv = lkb->lkb_wait_type;
+ _remove_from_waiters(lkb);
+ lkb->lkb_flags &= ~DLM_IFL_RESEND;
+ break;
+ }
+ }
+ mutex_unlock(&ls->ls_waiters_mutex);
+
+ if (!rv)
+ lkb = NULL;
+ *lkb_ret = lkb;
+ return rv;
+}
+
+/* Deal with lookups and lkb's marked RESEND from _pre. We may now be the
+ master or dir-node for r. Processing the lkb may result in it being placed
+ back on waiters. */
+
+int dlm_recover_waiters_post(struct dlm_ls *ls)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *r;
+ int error = 0, mstype;
+
+ while (1) {
+ if (dlm_locking_stopped(ls)) {
+ log_debug(ls, "recover_waiters_post aborted");
+ error = -EINTR;
+ break;
+ }
+
+ mstype = remove_resend_waiter(ls, &lkb);
+ if (!mstype)
+ break;
+
+ r = lkb->lkb_resource;
+
+ log_debug(ls, "recover_waiters_post %x type %d flags %x %s",
+ lkb->lkb_id, mstype, lkb->lkb_flags, r->res_name);
+
+ switch (mstype) {
+
+ case DLM_MSG_LOOKUP:
+ hold_rsb(r);
+ lock_rsb(r);
+ _request_lock(r, lkb);
+ if (is_master(r))
+ confirm_master(r, 0);
+ unlock_rsb(r);
+ put_rsb(r);
+ break;
+
+ case DLM_MSG_REQUEST:
+ hold_rsb(r);
+ lock_rsb(r);
+ _request_lock(r, lkb);
+ if (is_master(r))
+ confirm_master(r, 0);
+ unlock_rsb(r);
+ put_rsb(r);
+ break;
+
+ case DLM_MSG_CONVERT:
+ hold_rsb(r);
+ lock_rsb(r);
+ _convert_lock(r, lkb);
+ unlock_rsb(r);
+ put_rsb(r);
+ break;
+
+ default:
+ log_error(ls, "recover_waiters_post type %d", mstype);
+ }
+ }
+
+ return error;
+}
+
+static void purge_queue(struct dlm_rsb *r, struct list_head *queue,
+ int (*test)(struct dlm_ls *ls, struct dlm_lkb *lkb))
+{
+ struct dlm_ls *ls = r->res_ls;
+ struct dlm_lkb *lkb, *safe;
+
+ list_for_each_entry_safe(lkb, safe, queue, lkb_statequeue) {
+ if (test(ls, lkb)) {
+ rsb_set_flag(r, RSB_LOCKS_PURGED);
+ del_lkb(r, lkb);
+ /* this put should free the lkb */
+ if (!dlm_put_lkb(lkb))
+ log_error(ls, "purged lkb not released");
+ }
+ }
+}
+
+static int purge_dead_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+ return (is_master_copy(lkb) && dlm_is_removed(ls, lkb->lkb_nodeid));
+}
+
+static int purge_mstcpy_test(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+ return is_master_copy(lkb);
+}
+
+static void purge_dead_locks(struct dlm_rsb *r)
+{
+ purge_queue(r, &r->res_grantqueue, &purge_dead_test);
+ purge_queue(r, &r->res_convertqueue, &purge_dead_test);
+ purge_queue(r, &r->res_waitqueue, &purge_dead_test);
+}
+
+void dlm_purge_mstcpy_locks(struct dlm_rsb *r)
+{
+ purge_queue(r, &r->res_grantqueue, &purge_mstcpy_test);
+ purge_queue(r, &r->res_convertqueue, &purge_mstcpy_test);
+ purge_queue(r, &r->res_waitqueue, &purge_mstcpy_test);
+}
+
+/* Get rid of locks held by nodes that are gone. */
+
+int dlm_purge_locks(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r;
+
+ log_debug(ls, "dlm_purge_locks");
+
+ down_write(&ls->ls_root_sem);
+ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+ hold_rsb(r);
+ lock_rsb(r);
+ if (is_master(r))
+ purge_dead_locks(r);
+ unlock_rsb(r);
+ unhold_rsb(r);
+
+ schedule();
+ }
+ up_write(&ls->ls_root_sem);
+
+ return 0;
+}
+
+static struct dlm_rsb *find_purged_rsb(struct dlm_ls *ls, int bucket)
+{
+ struct dlm_rsb *r, *r_ret = NULL;
+
+ read_lock(&ls->ls_rsbtbl[bucket].lock);
+ list_for_each_entry(r, &ls->ls_rsbtbl[bucket].list, res_hashchain) {
+ if (!rsb_flag(r, RSB_LOCKS_PURGED))
+ continue;
+ hold_rsb(r);
+ rsb_clear_flag(r, RSB_LOCKS_PURGED);
+ r_ret = r;
+ break;
+ }
+ read_unlock(&ls->ls_rsbtbl[bucket].lock);
+ return r_ret;
+}
+
+void dlm_grant_after_purge(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r;
+ int bucket = 0;
+
+ while (1) {
+ r = find_purged_rsb(ls, bucket);
+ if (!r) {
+ if (bucket == ls->ls_rsbtbl_size - 1)
+ break;
+ bucket++;
+ continue;
+ }
+ lock_rsb(r);
+ if (is_master(r)) {
+ grant_pending_locks(r);
+ confirm_master(r, 0);
+ }
+ unlock_rsb(r);
+ put_rsb(r);
+ schedule();
+ }
+}
+
+static struct dlm_lkb *search_remid_list(struct list_head *head, int nodeid,
+ uint32_t remid)
+{
+ struct dlm_lkb *lkb;
+
+ list_for_each_entry(lkb, head, lkb_statequeue) {
+ if (lkb->lkb_nodeid == nodeid && lkb->lkb_remid == remid)
+ return lkb;
+ }
+ return NULL;
+}
+
+static struct dlm_lkb *search_remid(struct dlm_rsb *r, int nodeid,
+ uint32_t remid)
+{
+ struct dlm_lkb *lkb;
+
+ lkb = search_remid_list(&r->res_grantqueue, nodeid, remid);
+ if (lkb)
+ return lkb;
+ lkb = search_remid_list(&r->res_convertqueue, nodeid, remid);
+ if (lkb)
+ return lkb;
+ lkb = search_remid_list(&r->res_waitqueue, nodeid, remid);
+ if (lkb)
+ return lkb;
+ return NULL;
+}
+
+static int receive_rcom_lock_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
+ struct dlm_rsb *r, struct dlm_rcom *rc)
+{
+ struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+ int lvblen;
+
+ lkb->lkb_nodeid = rc->rc_header.h_nodeid;
+ lkb->lkb_ownpid = rl->rl_ownpid;
+ lkb->lkb_remid = rl->rl_lkid;
+ lkb->lkb_exflags = rl->rl_exflags;
+ lkb->lkb_flags = rl->rl_flags & 0x0000FFFF;
+ lkb->lkb_flags |= DLM_IFL_MSTCPY;
+ lkb->lkb_lvbseq = rl->rl_lvbseq;
+ lkb->lkb_rqmode = rl->rl_rqmode;
+ lkb->lkb_grmode = rl->rl_grmode;
+ /* don't set lkb_status because add_lkb wants to itself */
+
+ lkb->lkb_bastaddr = (void *) (long) (rl->rl_asts & AST_BAST);
+ lkb->lkb_astaddr = (void *) (long) (rl->rl_asts & AST_COMP);
+
+ if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+ lkb->lkb_lvbptr = allocate_lvb(ls);
+ if (!lkb->lkb_lvbptr)
+ return -ENOMEM;
+ lvblen = rc->rc_header.h_length - sizeof(struct dlm_rcom) -
+ sizeof(struct rcom_lock);
+ memcpy(lkb->lkb_lvbptr, rl->rl_lvb, lvblen);
+ }
+
+ /* Conversions between PR and CW (middle modes) need special handling.
+ The real granted mode of these converting locks cannot be determined
+ until all locks have been rebuilt on the rsb (recover_conversion) */
+
+ if (rl->rl_wait_type == DLM_MSG_CONVERT && middle_conversion(lkb)) {
+ rl->rl_status = DLM_LKSTS_CONVERT;
+ lkb->lkb_grmode = DLM_LOCK_IV;
+ rsb_set_flag(r, RSB_RECOVER_CONVERT);
+ }
+
+ return 0;
+}
+
+/* This lkb may have been recovered in a previous aborted recovery so we need
+ to check if the rsb already has an lkb with the given remote nodeid/lkid.
+ If so we just send back a standard reply. If not, we create a new lkb with
+ the given values and send back our lkid. We send back our lkid by sending
+ back the rcom_lock struct we got but with the remid field filled in. */
+
+int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+ struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+ struct dlm_rsb *r;
+ struct dlm_lkb *lkb;
+ int error;
+
+ if (rl->rl_parent_lkid) {
+ error = -EOPNOTSUPP;
+ goto out;
+ }
+
+ error = find_rsb(ls, rl->rl_name, rl->rl_namelen, R_MASTER, &r);
+ if (error)
+ goto out;
+
+ lock_rsb(r);
+
+ lkb = search_remid(r, rc->rc_header.h_nodeid, rl->rl_lkid);
+ if (lkb) {
+ error = -EEXIST;
+ goto out_remid;
+ }
+
+ error = create_lkb(ls, &lkb);
+ if (error)
+ goto out_unlock;
+
+ error = receive_rcom_lock_args(ls, lkb, r, rc);
+ if (error) {
+ __put_lkb(ls, lkb);
+ goto out_unlock;
+ }
+
+ attach_lkb(r, lkb);
+ add_lkb(r, lkb, rl->rl_status);
+ error = 0;
+
+ out_remid:
+ /* this is the new value returned to the lock holder for
+ saving in its process-copy lkb */
+ rl->rl_remid = lkb->lkb_id;
+
+ out_unlock:
+ unlock_rsb(r);
+ put_rsb(r);
+ out:
+ if (error)
+ log_print("recover_master_copy %d %x", error, rl->rl_lkid);
+ rl->rl_result = error;
+ return error;
+}
+
+int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+ struct rcom_lock *rl = (struct rcom_lock *) rc->rc_buf;
+ struct dlm_rsb *r;
+ struct dlm_lkb *lkb;
+ int error;
+
+ error = find_lkb(ls, rl->rl_lkid, &lkb);
+ if (error) {
+ log_error(ls, "recover_process_copy no lkid %x", rl->rl_lkid);
+ return error;
+ }
+
+ DLM_ASSERT(is_process_copy(lkb), dlm_print_lkb(lkb););
+
+ error = rl->rl_result;
+
+ r = lkb->lkb_resource;
+ hold_rsb(r);
+ lock_rsb(r);
+
+ switch (error) {
+ case -EEXIST:
+ log_debug(ls, "master copy exists %x", lkb->lkb_id);
+ /* fall through */
+ case 0:
+ lkb->lkb_remid = rl->rl_remid;
+ break;
+ default:
+ log_error(ls, "dlm_recover_process_copy unknown error %d %x",
+ error, lkb->lkb_id);
+ }
+
+ /* an ack for dlm_recover_locks() which waits for replies from
+ all the locks it sends to new masters */
+ dlm_recovered_lock(r);
+
+ unlock_rsb(r);
+ put_rsb(r);
+ dlm_put_lkb(lkb);
+
+ return 0;
+}
+
+int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
+ int mode, uint32_t flags, void *name, unsigned int namelen,
+ uint32_t parent_lkid)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_args args;
+ int error;
+
+ lock_recovery(ls);
+
+ error = create_lkb(ls, &lkb);
+ if (error) {
+ kfree(ua);
+ goto out;
+ }
+
+ if (flags & DLM_LKF_VALBLK) {
+ ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+ if (!ua->lksb.sb_lvbptr) {
+ kfree(ua);
+ __put_lkb(ls, lkb);
+ error = -ENOMEM;
+ goto out;
+ }
+ }
+
+ /* After ua is attached to lkb it will be freed by free_lkb().
+ When DLM_IFL_USER is set, the dlm knows that this is a userspace
+ lock and that lkb_astparam is the dlm_user_args structure. */
+
+ error = set_lock_args(mode, &ua->lksb, flags, namelen, parent_lkid,
+ DLM_FAKE_USER_AST, ua, DLM_FAKE_USER_AST, &args);
+ lkb->lkb_flags |= DLM_IFL_USER;
+ ua->old_mode = DLM_LOCK_IV;
+
+ if (error) {
+ __put_lkb(ls, lkb);
+ goto out;
+ }
+
+ error = request_lock(ls, lkb, name, namelen, &args);
+
+ switch (error) {
+ case 0:
+ break;
+ case -EINPROGRESS:
+ error = 0;
+ break;
+ case -EAGAIN:
+ error = 0;
+ /* fall through */
+ default:
+ __put_lkb(ls, lkb);
+ goto out;
+ }
+
+ /* add this new lkb to the per-process list of locks */
+ spin_lock(&ua->proc->locks_spin);
+ kref_get(&lkb->lkb_ref);
+ list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
+ spin_unlock(&ua->proc->locks_spin);
+ out:
+ unlock_recovery(ls);
+ return error;
+}
+
+int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ int mode, uint32_t flags, uint32_t lkid, char *lvb_in)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_args args;
+ struct dlm_user_args *ua;
+ int error;
+
+ lock_recovery(ls);
+
+ error = find_lkb(ls, lkid, &lkb);
+ if (error)
+ goto out;
+
+ /* user can change the params on its lock when it converts it, or
+ add an lvb that didn't exist before */
+
+ ua = (struct dlm_user_args *)lkb->lkb_astparam;
+
+ if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) {
+ ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+ if (!ua->lksb.sb_lvbptr) {
+ error = -ENOMEM;
+ goto out_put;
+ }
+ }
+ if (lvb_in && ua->lksb.sb_lvbptr)
+ memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
+
+ ua->castparam = ua_tmp->castparam;
+ ua->castaddr = ua_tmp->castaddr;
+ ua->bastparam = ua_tmp->bastparam;
+ ua->bastaddr = ua_tmp->bastaddr;
+ ua->user_lksb = ua_tmp->user_lksb;
+ ua->old_mode = lkb->lkb_grmode;
+
+ error = set_lock_args(mode, &ua->lksb, flags, 0, 0, DLM_FAKE_USER_AST,
+ ua, DLM_FAKE_USER_AST, &args);
+ if (error)
+ goto out_put;
+
+ error = convert_lock(ls, lkb, &args);
+
+ if (error == -EINPROGRESS || error == -EAGAIN)
+ error = 0;
+ out_put:
+ dlm_put_lkb(lkb);
+ out:
+ unlock_recovery(ls);
+ kfree(ua_tmp);
+ return error;
+}
+
+int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ uint32_t flags, uint32_t lkid, char *lvb_in)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_args args;
+ struct dlm_user_args *ua;
+ int error;
+
+ lock_recovery(ls);
+
+ error = find_lkb(ls, lkid, &lkb);
+ if (error)
+ goto out;
+
+ ua = (struct dlm_user_args *)lkb->lkb_astparam;
+
+ if (lvb_in && ua->lksb.sb_lvbptr)
+ memcpy(ua->lksb.sb_lvbptr, lvb_in, DLM_USER_LVB_LEN);
+ ua->castparam = ua_tmp->castparam;
+ ua->user_lksb = ua_tmp->user_lksb;
+
+ error = set_unlock_args(flags, ua, &args);
+ if (error)
+ goto out_put;
+
+ error = unlock_lock(ls, lkb, &args);
+
+ if (error == -DLM_EUNLOCK)
+ error = 0;
+ if (error)
+ goto out_put;
+
+ spin_lock(&ua->proc->locks_spin);
+ list_del_init(&lkb->lkb_ownqueue);
+ spin_unlock(&ua->proc->locks_spin);
+
+ /* this removes the reference for the proc->locks list added by
+ dlm_user_request */
+ unhold_lkb(lkb);
+ out_put:
+ dlm_put_lkb(lkb);
+ out:
+ unlock_recovery(ls);
+ return error;
+}
+
+int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ uint32_t flags, uint32_t lkid)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_args args;
+ struct dlm_user_args *ua;
+ int error;
+
+ lock_recovery(ls);
+
+ error = find_lkb(ls, lkid, &lkb);
+ if (error)
+ goto out;
+
+ ua = (struct dlm_user_args *)lkb->lkb_astparam;
+ ua->castparam = ua_tmp->castparam;
+ ua->user_lksb = ua_tmp->user_lksb;
+
+ error = set_unlock_args(flags, ua, &args);
+ if (error)
+ goto out_put;
+
+ error = cancel_lock(ls, lkb, &args);
+
+ if (error == -DLM_ECANCEL)
+ error = 0;
+ if (error)
+ goto out_put;
+
+ /* this lkb was removed from the WAITING queue */
+ if (lkb->lkb_grmode == DLM_LOCK_IV) {
+ spin_lock(&ua->proc->locks_spin);
+ list_del_init(&lkb->lkb_ownqueue);
+ spin_unlock(&ua->proc->locks_spin);
+ unhold_lkb(lkb);
+ }
+ out_put:
+ dlm_put_lkb(lkb);
+ out:
+ unlock_recovery(ls);
+ return error;
+}
+
+static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+ struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
+
+ if (ua->lksb.sb_lvbptr)
+ kfree(ua->lksb.sb_lvbptr);
+ kfree(ua);
+ lkb->lkb_astparam = (long)NULL;
+
+ /* TODO: propogate to master if needed */
+ return 0;
+}
+
+/* The force flag allows the unlock to go ahead even if the lkb isn't granted.
+ Regardless of what rsb queue the lock is on, it's removed and freed. */
+
+static int unlock_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
+{
+ struct dlm_user_args *ua = (struct dlm_user_args *)lkb->lkb_astparam;
+ struct dlm_args args;
+ int error;
+
+ /* FIXME: we need to handle the case where the lkb is in limbo
+ while the rsb is being looked up, currently we assert in
+ _unlock_lock/is_remote because rsb nodeid is -1. */
+
+ set_unlock_args(DLM_LKF_FORCEUNLOCK, ua, &args);
+
+ error = unlock_lock(ls, lkb, &args);
+ if (error == -DLM_EUNLOCK)
+ error = 0;
+ return error;
+}
+
+/* The ls_clear_proc_locks mutex protects against dlm_user_add_asts() which
+ 1) references lkb->ua which we free here and 2) adds lkbs to proc->asts,
+ which we clear here. */
+
+/* proc CLOSING flag is set so no more device_reads should look at proc->asts
+ list, and no more device_writes should add lkb's to proc->locks list; so we
+ shouldn't need to take asts_spin or locks_spin here. this assumes that
+ device reads/writes/closes are serialized -- FIXME: we may need to serialize
+ them ourself. */
+
+void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
+{
+ struct dlm_lkb *lkb, *safe;
+
+ lock_recovery(ls);
+ mutex_lock(&ls->ls_clear_proc_locks);
+
+ list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) {
+ if (lkb->lkb_ast_type) {
+ list_del(&lkb->lkb_astqueue);
+ unhold_lkb(lkb);
+ }
+
+ list_del_init(&lkb->lkb_ownqueue);
+
+ if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
+ lkb->lkb_flags |= DLM_IFL_ORPHAN;
+ orphan_proc_lock(ls, lkb);
+ } else {
+ lkb->lkb_flags |= DLM_IFL_DEAD;
+ unlock_proc_lock(ls, lkb);
+ }
+
+ /* this removes the reference for the proc->locks list
+ added by dlm_user_request, it may result in the lkb
+ being freed */
+
+ dlm_put_lkb(lkb);
+ }
+ mutex_unlock(&ls->ls_clear_proc_locks);
+ unlock_recovery(ls);
+}
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
new file mode 100644
index 000000000000..0843a3073ec3
--- /dev/null
+++ b/fs/dlm/lock.h
@@ -0,0 +1,62 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOCK_DOT_H__
+#define __LOCK_DOT_H__
+
+void dlm_print_rsb(struct dlm_rsb *r);
+void dlm_dump_rsb(struct dlm_rsb *r);
+void dlm_print_lkb(struct dlm_lkb *lkb);
+int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery);
+int dlm_modes_compat(int mode1, int mode2);
+int dlm_find_rsb(struct dlm_ls *ls, char *name, int namelen,
+ unsigned int flags, struct dlm_rsb **r_ret);
+void dlm_put_rsb(struct dlm_rsb *r);
+void dlm_hold_rsb(struct dlm_rsb *r);
+int dlm_put_lkb(struct dlm_lkb *lkb);
+void dlm_scan_rsbs(struct dlm_ls *ls);
+
+int dlm_purge_locks(struct dlm_ls *ls);
+void dlm_purge_mstcpy_locks(struct dlm_rsb *r);
+void dlm_grant_after_purge(struct dlm_ls *ls);
+int dlm_recover_waiters_post(struct dlm_ls *ls);
+void dlm_recover_waiters_pre(struct dlm_ls *ls);
+int dlm_recover_master_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
+int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc);
+
+int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode,
+ uint32_t flags, void *name, unsigned int namelen, uint32_t parent_lkid);
+int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ int mode, uint32_t flags, uint32_t lkid, char *lvb_in);
+int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ uint32_t flags, uint32_t lkid, char *lvb_in);
+int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ uint32_t flags, uint32_t lkid);
+void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc);
+
+static inline int is_master(struct dlm_rsb *r)
+{
+ return !r->res_nodeid;
+}
+
+static inline void lock_rsb(struct dlm_rsb *r)
+{
+ mutex_lock(&r->res_mutex);
+}
+
+static inline void unlock_rsb(struct dlm_rsb *r)
+{
+ mutex_unlock(&r->res_mutex);
+}
+
+#endif
+
diff --git a/fs/dlm/lockspace.c b/fs/dlm/lockspace.c
new file mode 100644
index 000000000000..109333c8ecb9
--- /dev/null
+++ b/fs/dlm/lockspace.c
@@ -0,0 +1,717 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "recoverd.h"
+#include "ast.h"
+#include "dir.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "memory.h"
+#include "lock.h"
+#include "recover.h"
+
+#ifdef CONFIG_DLM_DEBUG
+int dlm_create_debug_file(struct dlm_ls *ls);
+void dlm_delete_debug_file(struct dlm_ls *ls);
+#else
+static inline int dlm_create_debug_file(struct dlm_ls *ls) { return 0; }
+static inline void dlm_delete_debug_file(struct dlm_ls *ls) { }
+#endif
+
+static int ls_count;
+static struct mutex ls_lock;
+static struct list_head lslist;
+static spinlock_t lslist_lock;
+static struct task_struct * scand_task;
+
+
+static ssize_t dlm_control_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+ ssize_t ret = len;
+ int n = simple_strtol(buf, NULL, 0);
+
+ switch (n) {
+ case 0:
+ dlm_ls_stop(ls);
+ break;
+ case 1:
+ dlm_ls_start(ls);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static ssize_t dlm_event_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+ ls->ls_uevent_result = simple_strtol(buf, NULL, 0);
+ set_bit(LSFL_UEVENT_WAIT, &ls->ls_flags);
+ wake_up(&ls->ls_uevent_wait);
+ return len;
+}
+
+static ssize_t dlm_id_show(struct dlm_ls *ls, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u\n", ls->ls_global_id);
+}
+
+static ssize_t dlm_id_store(struct dlm_ls *ls, const char *buf, size_t len)
+{
+ ls->ls_global_id = simple_strtoul(buf, NULL, 0);
+ return len;
+}
+
+static ssize_t dlm_recover_status_show(struct dlm_ls *ls, char *buf)
+{
+ uint32_t status = dlm_recover_status(ls);
+ return snprintf(buf, PAGE_SIZE, "%x\n", status);
+}
+
+static ssize_t dlm_recover_nodeid_show(struct dlm_ls *ls, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n", ls->ls_recover_nodeid);
+}
+
+struct dlm_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct dlm_ls *, char *);
+ ssize_t (*store)(struct dlm_ls *, const char *, size_t);
+};
+
+static struct dlm_attr dlm_attr_control = {
+ .attr = {.name = "control", .mode = S_IWUSR},
+ .store = dlm_control_store
+};
+
+static struct dlm_attr dlm_attr_event = {
+ .attr = {.name = "event_done", .mode = S_IWUSR},
+ .store = dlm_event_store
+};
+
+static struct dlm_attr dlm_attr_id = {
+ .attr = {.name = "id", .mode = S_IRUGO | S_IWUSR},
+ .show = dlm_id_show,
+ .store = dlm_id_store
+};
+
+static struct dlm_attr dlm_attr_recover_status = {
+ .attr = {.name = "recover_status", .mode = S_IRUGO},
+ .show = dlm_recover_status_show
+};
+
+static struct dlm_attr dlm_attr_recover_nodeid = {
+ .attr = {.name = "recover_nodeid", .mode = S_IRUGO},
+ .show = dlm_recover_nodeid_show
+};
+
+static struct attribute *dlm_attrs[] = {
+ &dlm_attr_control.attr,
+ &dlm_attr_event.attr,
+ &dlm_attr_id.attr,
+ &dlm_attr_recover_status.attr,
+ &dlm_attr_recover_nodeid.attr,
+ NULL,
+};
+
+static ssize_t dlm_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
+ struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
+ return a->show ? a->show(ls, buf) : 0;
+}
+
+static ssize_t dlm_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct dlm_ls *ls = container_of(kobj, struct dlm_ls, ls_kobj);
+ struct dlm_attr *a = container_of(attr, struct dlm_attr, attr);
+ return a->store ? a->store(ls, buf, len) : len;
+}
+
+static struct sysfs_ops dlm_attr_ops = {
+ .show = dlm_attr_show,
+ .store = dlm_attr_store,
+};
+
+static struct kobj_type dlm_ktype = {
+ .default_attrs = dlm_attrs,
+ .sysfs_ops = &dlm_attr_ops,
+};
+
+static struct kset dlm_kset = {
+ .subsys = &kernel_subsys,
+ .kobj = {.name = "dlm",},
+ .ktype = &dlm_ktype,
+};
+
+static int kobject_setup(struct dlm_ls *ls)
+{
+ char lsname[DLM_LOCKSPACE_LEN];
+ int error;
+
+ memset(lsname, 0, DLM_LOCKSPACE_LEN);
+ snprintf(lsname, DLM_LOCKSPACE_LEN, "%s", ls->ls_name);
+
+ error = kobject_set_name(&ls->ls_kobj, "%s", lsname);
+ if (error)
+ return error;
+
+ ls->ls_kobj.kset = &dlm_kset;
+ ls->ls_kobj.ktype = &dlm_ktype;
+ return 0;
+}
+
+static int do_uevent(struct dlm_ls *ls, int in)
+{
+ int error;
+
+ if (in)
+ kobject_uevent(&ls->ls_kobj, KOBJ_ONLINE);
+ else
+ kobject_uevent(&ls->ls_kobj, KOBJ_OFFLINE);
+
+ error = wait_event_interruptible(ls->ls_uevent_wait,
+ test_and_clear_bit(LSFL_UEVENT_WAIT, &ls->ls_flags));
+ if (error)
+ goto out;
+
+ error = ls->ls_uevent_result;
+ out:
+ return error;
+}
+
+
+int dlm_lockspace_init(void)
+{
+ int error;
+
+ ls_count = 0;
+ mutex_init(&ls_lock);
+ INIT_LIST_HEAD(&lslist);
+ spin_lock_init(&lslist_lock);
+
+ error = kset_register(&dlm_kset);
+ if (error)
+ printk("dlm_lockspace_init: cannot register kset %d\n", error);
+ return error;
+}
+
+void dlm_lockspace_exit(void)
+{
+ kset_unregister(&dlm_kset);
+}
+
+static int dlm_scand(void *data)
+{
+ struct dlm_ls *ls;
+
+ while (!kthread_should_stop()) {
+ list_for_each_entry(ls, &lslist, ls_list)
+ dlm_scan_rsbs(ls);
+ schedule_timeout_interruptible(dlm_config.scan_secs * HZ);
+ }
+ return 0;
+}
+
+static int dlm_scand_start(void)
+{
+ struct task_struct *p;
+ int error = 0;
+
+ p = kthread_run(dlm_scand, NULL, "dlm_scand");
+ if (IS_ERR(p))
+ error = PTR_ERR(p);
+ else
+ scand_task = p;
+ return error;
+}
+
+static void dlm_scand_stop(void)
+{
+ kthread_stop(scand_task);
+}
+
+static struct dlm_ls *dlm_find_lockspace_name(char *name, int namelen)
+{
+ struct dlm_ls *ls;
+
+ spin_lock(&lslist_lock);
+
+ list_for_each_entry(ls, &lslist, ls_list) {
+ if (ls->ls_namelen == namelen &&
+ memcmp(ls->ls_name, name, namelen) == 0)
+ goto out;
+ }
+ ls = NULL;
+ out:
+ spin_unlock(&lslist_lock);
+ return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_global(uint32_t id)
+{
+ struct dlm_ls *ls;
+
+ spin_lock(&lslist_lock);
+
+ list_for_each_entry(ls, &lslist, ls_list) {
+ if (ls->ls_global_id == id) {
+ ls->ls_count++;
+ goto out;
+ }
+ }
+ ls = NULL;
+ out:
+ spin_unlock(&lslist_lock);
+ return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_local(dlm_lockspace_t *lockspace)
+{
+ struct dlm_ls *ls;
+
+ spin_lock(&lslist_lock);
+ list_for_each_entry(ls, &lslist, ls_list) {
+ if (ls->ls_local_handle == lockspace) {
+ ls->ls_count++;
+ goto out;
+ }
+ }
+ ls = NULL;
+ out:
+ spin_unlock(&lslist_lock);
+ return ls;
+}
+
+struct dlm_ls *dlm_find_lockspace_device(int minor)
+{
+ struct dlm_ls *ls;
+
+ spin_lock(&lslist_lock);
+ list_for_each_entry(ls, &lslist, ls_list) {
+ if (ls->ls_device.minor == minor) {
+ ls->ls_count++;
+ goto out;
+ }
+ }
+ ls = NULL;
+ out:
+ spin_unlock(&lslist_lock);
+ return ls;
+}
+
+void dlm_put_lockspace(struct dlm_ls *ls)
+{
+ spin_lock(&lslist_lock);
+ ls->ls_count--;
+ spin_unlock(&lslist_lock);
+}
+
+static void remove_lockspace(struct dlm_ls *ls)
+{
+ for (;;) {
+ spin_lock(&lslist_lock);
+ if (ls->ls_count == 0) {
+ list_del(&ls->ls_list);
+ spin_unlock(&lslist_lock);
+ return;
+ }
+ spin_unlock(&lslist_lock);
+ ssleep(1);
+ }
+}
+
+static int threads_start(void)
+{
+ int error;
+
+ /* Thread which process lock requests for all lockspace's */
+ error = dlm_astd_start();
+ if (error) {
+ log_print("cannot start dlm_astd thread %d", error);
+ goto fail;
+ }
+
+ error = dlm_scand_start();
+ if (error) {
+ log_print("cannot start dlm_scand thread %d", error);
+ goto astd_fail;
+ }
+
+ /* Thread for sending/receiving messages for all lockspace's */
+ error = dlm_lowcomms_start();
+ if (error) {
+ log_print("cannot start dlm lowcomms %d", error);
+ goto scand_fail;
+ }
+
+ return 0;
+
+ scand_fail:
+ dlm_scand_stop();
+ astd_fail:
+ dlm_astd_stop();
+ fail:
+ return error;
+}
+
+static void threads_stop(void)
+{
+ dlm_scand_stop();
+ dlm_lowcomms_stop();
+ dlm_astd_stop();
+}
+
+static int new_lockspace(char *name, int namelen, void **lockspace,
+ uint32_t flags, int lvblen)
+{
+ struct dlm_ls *ls;
+ int i, size, error = -ENOMEM;
+
+ if (namelen > DLM_LOCKSPACE_LEN)
+ return -EINVAL;
+
+ if (!lvblen || (lvblen % 8))
+ return -EINVAL;
+
+ if (!try_module_get(THIS_MODULE))
+ return -EINVAL;
+
+ ls = dlm_find_lockspace_name(name, namelen);
+ if (ls) {
+ *lockspace = ls;
+ module_put(THIS_MODULE);
+ return -EEXIST;
+ }
+
+ ls = kzalloc(sizeof(struct dlm_ls) + namelen, GFP_KERNEL);
+ if (!ls)
+ goto out;
+ memcpy(ls->ls_name, name, namelen);
+ ls->ls_namelen = namelen;
+ ls->ls_exflags = flags;
+ ls->ls_lvblen = lvblen;
+ ls->ls_count = 0;
+ ls->ls_flags = 0;
+
+ size = dlm_config.rsbtbl_size;
+ ls->ls_rsbtbl_size = size;
+
+ ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);
+ if (!ls->ls_rsbtbl)
+ goto out_lsfree;
+ for (i = 0; i < size; i++) {
+ INIT_LIST_HEAD(&ls->ls_rsbtbl[i].list);
+ INIT_LIST_HEAD(&ls->ls_rsbtbl[i].toss);
+ rwlock_init(&ls->ls_rsbtbl[i].lock);
+ }
+
+ size = dlm_config.lkbtbl_size;
+ ls->ls_lkbtbl_size = size;
+
+ ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);
+ if (!ls->ls_lkbtbl)
+ goto out_rsbfree;
+ for (i = 0; i < size; i++) {
+ INIT_LIST_HEAD(&ls->ls_lkbtbl[i].list);
+ rwlock_init(&ls->ls_lkbtbl[i].lock);
+ ls->ls_lkbtbl[i].counter = 1;
+ }
+
+ size = dlm_config.dirtbl_size;
+ ls->ls_dirtbl_size = size;
+
+ ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);
+ if (!ls->ls_dirtbl)
+ goto out_lkbfree;
+ for (i = 0; i < size; i++) {
+ INIT_LIST_HEAD(&ls->ls_dirtbl[i].list);
+ rwlock_init(&ls->ls_dirtbl[i].lock);
+ }
+
+ INIT_LIST_HEAD(&ls->ls_waiters);
+ mutex_init(&ls->ls_waiters_mutex);
+
+ INIT_LIST_HEAD(&ls->ls_nodes);
+ INIT_LIST_HEAD(&ls->ls_nodes_gone);
+ ls->ls_num_nodes = 0;
+ ls->ls_low_nodeid = 0;
+ ls->ls_total_weight = 0;
+ ls->ls_node_array = NULL;
+
+ memset(&ls->ls_stub_rsb, 0, sizeof(struct dlm_rsb));
+ ls->ls_stub_rsb.res_ls = ls;
+
+ ls->ls_debug_rsb_dentry = NULL;
+ ls->ls_debug_waiters_dentry = NULL;
+
+ init_waitqueue_head(&ls->ls_uevent_wait);
+ ls->ls_uevent_result = 0;
+
+ ls->ls_recoverd_task = NULL;
+ mutex_init(&ls->ls_recoverd_active);
+ spin_lock_init(&ls->ls_recover_lock);
+ ls->ls_recover_status = 0;
+ ls->ls_recover_seq = 0;
+ ls->ls_recover_args = NULL;
+ init_rwsem(&ls->ls_in_recovery);
+ INIT_LIST_HEAD(&ls->ls_requestqueue);
+ mutex_init(&ls->ls_requestqueue_mutex);
+ mutex_init(&ls->ls_clear_proc_locks);
+
+ ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+ if (!ls->ls_recover_buf)
+ goto out_dirfree;
+
+ INIT_LIST_HEAD(&ls->ls_recover_list);
+ spin_lock_init(&ls->ls_recover_list_lock);
+ ls->ls_recover_list_count = 0;
+ ls->ls_local_handle = ls;
+ init_waitqueue_head(&ls->ls_wait_general);
+ INIT_LIST_HEAD(&ls->ls_root_list);
+ init_rwsem(&ls->ls_root_sem);
+
+ down_write(&ls->ls_in_recovery);
+
+ spin_lock(&lslist_lock);
+ list_add(&ls->ls_list, &lslist);
+ spin_unlock(&lslist_lock);
+
+ /* needs to find ls in lslist */
+ error = dlm_recoverd_start(ls);
+ if (error) {
+ log_error(ls, "can't start dlm_recoverd %d", error);
+ goto out_rcomfree;
+ }
+
+ dlm_create_debug_file(ls);
+
+ error = kobject_setup(ls);
+ if (error)
+ goto out_del;
+
+ error = kobject_register(&ls->ls_kobj);
+ if (error)
+ goto out_del;
+
+ error = do_uevent(ls, 1);
+ if (error)
+ goto out_unreg;
+
+ *lockspace = ls;
+ return 0;
+
+ out_unreg:
+ kobject_unregister(&ls->ls_kobj);
+ out_del:
+ dlm_delete_debug_file(ls);
+ dlm_recoverd_stop(ls);
+ out_rcomfree:
+ spin_lock(&lslist_lock);
+ list_del(&ls->ls_list);
+ spin_unlock(&lslist_lock);
+ kfree(ls->ls_recover_buf);
+ out_dirfree:
+ kfree(ls->ls_dirtbl);
+ out_lkbfree:
+ kfree(ls->ls_lkbtbl);
+ out_rsbfree:
+ kfree(ls->ls_rsbtbl);
+ out_lsfree:
+ kfree(ls);
+ out:
+ module_put(THIS_MODULE);
+ return error;
+}
+
+int dlm_new_lockspace(char *name, int namelen, void **lockspace,
+ uint32_t flags, int lvblen)
+{
+ int error = 0;
+
+ mutex_lock(&ls_lock);
+ if (!ls_count)
+ error = threads_start();
+ if (error)
+ goto out;
+
+ error = new_lockspace(name, namelen, lockspace, flags, lvblen);
+ if (!error)
+ ls_count++;
+ out:
+ mutex_unlock(&ls_lock);
+ return error;
+}
+
+/* Return 1 if the lockspace still has active remote locks,
+ * 2 if the lockspace still has active local locks.
+ */
+static int lockspace_busy(struct dlm_ls *ls)
+{
+ int i, lkb_found = 0;
+ struct dlm_lkb *lkb;
+
+ /* NOTE: We check the lockidtbl here rather than the resource table.
+ This is because there may be LKBs queued as ASTs that have been
+ unlinked from their RSBs and are pending deletion once the AST has
+ been delivered */
+
+ for (i = 0; i < ls->ls_lkbtbl_size; i++) {
+ read_lock(&ls->ls_lkbtbl[i].lock);
+ if (!list_empty(&ls->ls_lkbtbl[i].list)) {
+ lkb_found = 1;
+ list_for_each_entry(lkb, &ls->ls_lkbtbl[i].list,
+ lkb_idtbl_list) {
+ if (!lkb->lkb_nodeid) {
+ read_unlock(&ls->ls_lkbtbl[i].lock);
+ return 2;
+ }
+ }
+ }
+ read_unlock(&ls->ls_lkbtbl[i].lock);
+ }
+ return lkb_found;
+}
+
+static int release_lockspace(struct dlm_ls *ls, int force)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_rsb *rsb;
+ struct list_head *head;
+ int i;
+ int busy = lockspace_busy(ls);
+
+ if (busy > force)
+ return -EBUSY;
+
+ if (force < 3)
+ do_uevent(ls, 0);
+
+ dlm_recoverd_stop(ls);
+
+ remove_lockspace(ls);
+
+ dlm_delete_debug_file(ls);
+
+ dlm_astd_suspend();
+
+ kfree(ls->ls_recover_buf);
+
+ /*
+ * Free direntry structs.
+ */
+
+ dlm_dir_clear(ls);
+ kfree(ls->ls_dirtbl);
+
+ /*
+ * Free all lkb's on lkbtbl[] lists.
+ */
+
+ for (i = 0; i < ls->ls_lkbtbl_size; i++) {
+ head = &ls->ls_lkbtbl[i].list;
+ while (!list_empty(head)) {
+ lkb = list_entry(head->next, struct dlm_lkb,
+ lkb_idtbl_list);
+
+ list_del(&lkb->lkb_idtbl_list);
+
+ dlm_del_ast(lkb);
+
+ if (lkb->lkb_lvbptr && lkb->lkb_flags & DLM_IFL_MSTCPY)
+ free_lvb(lkb->lkb_lvbptr);
+
+ free_lkb(lkb);
+ }
+ }
+ dlm_astd_resume();
+
+ kfree(ls->ls_lkbtbl);
+
+ /*
+ * Free all rsb's on rsbtbl[] lists
+ */
+
+ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+ head = &ls->ls_rsbtbl[i].list;
+ while (!list_empty(head)) {
+ rsb = list_entry(head->next, struct dlm_rsb,
+ res_hashchain);
+
+ list_del(&rsb->res_hashchain);
+ free_rsb(rsb);
+ }
+
+ head = &ls->ls_rsbtbl[i].toss;
+ while (!list_empty(head)) {
+ rsb = list_entry(head->next, struct dlm_rsb,
+ res_hashchain);
+ list_del(&rsb->res_hashchain);
+ free_rsb(rsb);
+ }
+ }
+
+ kfree(ls->ls_rsbtbl);
+
+ /*
+ * Free structures on any other lists
+ */
+
+ kfree(ls->ls_recover_args);
+ dlm_clear_free_entries(ls);
+ dlm_clear_members(ls);
+ dlm_clear_members_gone(ls);
+ kfree(ls->ls_node_array);
+ kobject_unregister(&ls->ls_kobj);
+ kfree(ls);
+
+ mutex_lock(&ls_lock);
+ ls_count--;
+ if (!ls_count)
+ threads_stop();
+ mutex_unlock(&ls_lock);
+
+ module_put(THIS_MODULE);
+ return 0;
+}
+
+/*
+ * Called when a system has released all its locks and is not going to use the
+ * lockspace any longer. We free everything we're managing for this lockspace.
+ * Remaining nodes will go through the recovery process as if we'd died. The
+ * lockspace must continue to function as usual, participating in recoveries,
+ * until this returns.
+ *
+ * Force has 4 possible values:
+ * 0 - don't destroy locksapce if it has any LKBs
+ * 1 - destroy lockspace if it has remote LKBs but not if it has local LKBs
+ * 2 - destroy lockspace regardless of LKBs
+ * 3 - destroy lockspace as part of a forced shutdown
+ */
+
+int dlm_release_lockspace(void *lockspace, int force)
+{
+ struct dlm_ls *ls;
+
+ ls = dlm_find_lockspace_local(lockspace);
+ if (!ls)
+ return -EINVAL;
+ dlm_put_lockspace(ls);
+ return release_lockspace(ls, force);
+}
+
diff --git a/fs/dlm/lockspace.h b/fs/dlm/lockspace.h
new file mode 100644
index 000000000000..891eabbdd021
--- /dev/null
+++ b/fs/dlm/lockspace.h
@@ -0,0 +1,25 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOCKSPACE_DOT_H__
+#define __LOCKSPACE_DOT_H__
+
+int dlm_lockspace_init(void);
+void dlm_lockspace_exit(void);
+struct dlm_ls *dlm_find_lockspace_global(uint32_t id);
+struct dlm_ls *dlm_find_lockspace_local(void *id);
+struct dlm_ls *dlm_find_lockspace_device(int minor);
+void dlm_put_lockspace(struct dlm_ls *ls);
+
+#endif /* __LOCKSPACE_DOT_H__ */
+
diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c
new file mode 100644
index 000000000000..6da6b14d5a61
--- /dev/null
+++ b/fs/dlm/lowcomms.c
@@ -0,0 +1,1239 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * lowcomms.c
+ *
+ * This is the "low-level" comms layer.
+ *
+ * It is responsible for sending/receiving messages
+ * from other nodes in the cluster.
+ *
+ * Cluster nodes are referred to by their nodeids. nodeids are
+ * simply 32 bit numbers to the locking module - if they need to
+ * be expanded for the cluster infrastructure then that is it's
+ * responsibility. It is this layer's
+ * responsibility to resolve these into IP address or
+ * whatever it needs for inter-node communication.
+ *
+ * The comms level is two kernel threads that deal mainly with
+ * the receiving of messages from other nodes and passing them
+ * up to the mid-level comms layer (which understands the
+ * message format) for execution by the locking core, and
+ * a send thread which does all the setting up of connections
+ * to remote nodes and the sending of data. Threads are not allowed
+ * to send their own data because it may cause them to wait in times
+ * of high load. Also, this way, the sending thread can collect together
+ * messages bound for one node and send them in one block.
+ *
+ * I don't see any problem with the recv thread executing the locking
+ * code on behalf of remote processes as the locking code is
+ * short, efficient and never (well, hardly ever) waits.
+ *
+ */
+
+#include <asm/ioctls.h>
+#include <net/sock.h>
+#include <net/tcp.h>
+#include <net/sctp/user.h>
+#include <linux/pagemap.h>
+#include <linux/socket.h>
+#include <linux/idr.h>
+
+#include "dlm_internal.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "midcomms.h"
+
+static struct sockaddr_storage *dlm_local_addr[DLM_MAX_ADDR_COUNT];
+static int dlm_local_count;
+static int dlm_local_nodeid;
+
+/* One of these per connected node */
+
+#define NI_INIT_PENDING 1
+#define NI_WRITE_PENDING 2
+
+struct nodeinfo {
+ spinlock_t lock;
+ sctp_assoc_t assoc_id;
+ unsigned long flags;
+ struct list_head write_list; /* nodes with pending writes */
+ struct list_head writequeue; /* outgoing writequeue_entries */
+ spinlock_t writequeue_lock;
+ int nodeid;
+};
+
+static DEFINE_IDR(nodeinfo_idr);
+static struct rw_semaphore nodeinfo_lock;
+static int max_nodeid;
+
+struct cbuf {
+ unsigned base;
+ unsigned len;
+ unsigned mask;
+};
+
+/* Just the one of these, now. But this struct keeps
+ the connection-specific variables together */
+
+#define CF_READ_PENDING 1
+
+struct connection {
+ struct socket *sock;
+ unsigned long flags;
+ struct page *rx_page;
+ atomic_t waiting_requests;
+ struct cbuf cb;
+ int eagain_flag;
+};
+
+/* An entry waiting to be sent */
+
+struct writequeue_entry {
+ struct list_head list;
+ struct page *page;
+ int offset;
+ int len;
+ int end;
+ int users;
+ struct nodeinfo *ni;
+};
+
+#define CBUF_ADD(cb, n) do { (cb)->len += n; } while(0)
+#define CBUF_EMPTY(cb) ((cb)->len == 0)
+#define CBUF_MAY_ADD(cb, n) (((cb)->len + (n)) < ((cb)->mask + 1))
+#define CBUF_DATA(cb) (((cb)->base + (cb)->len) & (cb)->mask)
+
+#define CBUF_INIT(cb, size) \
+do { \
+ (cb)->base = (cb)->len = 0; \
+ (cb)->mask = ((size)-1); \
+} while(0)
+
+#define CBUF_EAT(cb, n) \
+do { \
+ (cb)->len -= (n); \
+ (cb)->base += (n); \
+ (cb)->base &= (cb)->mask; \
+} while(0)
+
+
+/* List of nodes which have writes pending */
+static struct list_head write_nodes;
+static spinlock_t write_nodes_lock;
+
+/* Maximum number of incoming messages to process before
+ * doing a schedule()
+ */
+#define MAX_RX_MSG_COUNT 25
+
+/* Manage daemons */
+static struct task_struct *recv_task;
+static struct task_struct *send_task;
+static wait_queue_head_t lowcomms_recv_wait;
+static atomic_t accepting;
+
+/* The SCTP connection */
+static struct connection sctp_con;
+
+
+static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
+{
+ struct sockaddr_storage addr;
+ int error;
+
+ if (!dlm_local_count)
+ return -1;
+
+ error = dlm_nodeid_to_addr(nodeid, &addr);
+ if (error)
+ return error;
+
+ if (dlm_local_addr[0]->ss_family == AF_INET) {
+ struct sockaddr_in *in4 = (struct sockaddr_in *) &addr;
+ struct sockaddr_in *ret4 = (struct sockaddr_in *) retaddr;
+ ret4->sin_addr.s_addr = in4->sin_addr.s_addr;
+ } else {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *) &addr;
+ struct sockaddr_in6 *ret6 = (struct sockaddr_in6 *) retaddr;
+ memcpy(&ret6->sin6_addr, &in6->sin6_addr,
+ sizeof(in6->sin6_addr));
+ }
+
+ return 0;
+}
+
+static struct nodeinfo *nodeid2nodeinfo(int nodeid, gfp_t alloc)
+{
+ struct nodeinfo *ni;
+ int r;
+ int n;
+
+ down_read(&nodeinfo_lock);
+ ni = idr_find(&nodeinfo_idr, nodeid);
+ up_read(&nodeinfo_lock);
+
+ if (!ni && alloc) {
+ down_write(&nodeinfo_lock);
+
+ ni = idr_find(&nodeinfo_idr, nodeid);
+ if (ni)
+ goto out_up;
+
+ r = idr_pre_get(&nodeinfo_idr, alloc);
+ if (!r)
+ goto out_up;
+
+ ni = kmalloc(sizeof(struct nodeinfo), alloc);
+ if (!ni)
+ goto out_up;
+
+ r = idr_get_new_above(&nodeinfo_idr, ni, nodeid, &n);
+ if (r) {
+ kfree(ni);
+ ni = NULL;
+ goto out_up;
+ }
+ if (n != nodeid) {
+ idr_remove(&nodeinfo_idr, n);
+ kfree(ni);
+ ni = NULL;
+ goto out_up;
+ }
+ memset(ni, 0, sizeof(struct nodeinfo));
+ spin_lock_init(&ni->lock);
+ INIT_LIST_HEAD(&ni->writequeue);
+ spin_lock_init(&ni->writequeue_lock);
+ ni->nodeid = nodeid;
+
+ if (nodeid > max_nodeid)
+ max_nodeid = nodeid;
+ out_up:
+ up_write(&nodeinfo_lock);
+ }
+
+ return ni;
+}
+
+/* Don't call this too often... */
+static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc)
+{
+ int i;
+ struct nodeinfo *ni;
+
+ for (i=1; i<=max_nodeid; i++) {
+ ni = nodeid2nodeinfo(i, 0);
+ if (ni && ni->assoc_id == assoc)
+ return ni;
+ }
+ return NULL;
+}
+
+/* Data or notification available on socket */
+static void lowcomms_data_ready(struct sock *sk, int count_unused)
+{
+ atomic_inc(&sctp_con.waiting_requests);
+ if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
+ return;
+
+ wake_up_interruptible(&lowcomms_recv_wait);
+}
+
+
+/* Add the port number to an IP6 or 4 sockaddr and return the address length.
+ Also padd out the struct with zeros to make comparisons meaningful */
+
+static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
+ int *addr_len)
+{
+ struct sockaddr_in *local4_addr;
+ struct sockaddr_in6 *local6_addr;
+
+ if (!dlm_local_count)
+ return;
+
+ if (!port) {
+ if (dlm_local_addr[0]->ss_family == AF_INET) {
+ local4_addr = (struct sockaddr_in *)dlm_local_addr[0];
+ port = be16_to_cpu(local4_addr->sin_port);
+ } else {
+ local6_addr = (struct sockaddr_in6 *)dlm_local_addr[0];
+ port = be16_to_cpu(local6_addr->sin6_port);
+ }
+ }
+
+ saddr->ss_family = dlm_local_addr[0]->ss_family;
+ if (dlm_local_addr[0]->ss_family == AF_INET) {
+ struct sockaddr_in *in4_addr = (struct sockaddr_in *)saddr;
+ in4_addr->sin_port = cpu_to_be16(port);
+ memset(&in4_addr->sin_zero, 0, sizeof(in4_addr->sin_zero));
+ memset(in4_addr+1, 0, sizeof(struct sockaddr_storage) -
+ sizeof(struct sockaddr_in));
+ *addr_len = sizeof(struct sockaddr_in);
+ } else {
+ struct sockaddr_in6 *in6_addr = (struct sockaddr_in6 *)saddr;
+ in6_addr->sin6_port = cpu_to_be16(port);
+ memset(in6_addr+1, 0, sizeof(struct sockaddr_storage) -
+ sizeof(struct sockaddr_in6));
+ *addr_len = sizeof(struct sockaddr_in6);
+ }
+}
+
+/* Close the connection and tidy up */
+static void close_connection(void)
+{
+ if (sctp_con.sock) {
+ sock_release(sctp_con.sock);
+ sctp_con.sock = NULL;
+ }
+
+ if (sctp_con.rx_page) {
+ __free_page(sctp_con.rx_page);
+ sctp_con.rx_page = NULL;
+ }
+}
+
+/* We only send shutdown messages to nodes that are not part of the cluster */
+static void send_shutdown(sctp_assoc_t associd)
+{
+ static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct msghdr outmessage;
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ int ret;
+
+ outmessage.msg_name = NULL;
+ outmessage.msg_namelen = 0;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = MSG_EOR;
+
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+
+ sinfo->sinfo_flags |= MSG_EOF;
+ sinfo->sinfo_assoc_id = associd;
+
+ ret = kernel_sendmsg(sctp_con.sock, &outmessage, NULL, 0, 0);
+
+ if (ret != 0)
+ log_print("send EOF to node failed: %d", ret);
+}
+
+
+/* INIT failed but we don't know which node...
+ restart INIT on all pending nodes */
+static void init_failed(void)
+{
+ int i;
+ struct nodeinfo *ni;
+
+ for (i=1; i<=max_nodeid; i++) {
+ ni = nodeid2nodeinfo(i, 0);
+ if (!ni)
+ continue;
+
+ if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
+ ni->assoc_id = 0;
+ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+ spin_lock_bh(&write_nodes_lock);
+ list_add_tail(&ni->write_list, &write_nodes);
+ spin_unlock_bh(&write_nodes_lock);
+ }
+ }
+ }
+ wake_up_process(send_task);
+}
+
+/* Something happened to an association */
+static void process_sctp_notification(struct msghdr *msg, char *buf)
+{
+ union sctp_notification *sn = (union sctp_notification *)buf;
+
+ if (sn->sn_header.sn_type == SCTP_ASSOC_CHANGE) {
+ switch (sn->sn_assoc_change.sac_state) {
+
+ case SCTP_COMM_UP:
+ case SCTP_RESTART:
+ {
+ /* Check that the new node is in the lockspace */
+ struct sctp_prim prim;
+ mm_segment_t fs;
+ int nodeid;
+ int prim_len, ret;
+ int addr_len;
+ struct nodeinfo *ni;
+
+ /* This seems to happen when we received a connection
+ * too early... or something... anyway, it happens but
+ * we always seem to get a real message too, see
+ * receive_from_sock */
+
+ if ((int)sn->sn_assoc_change.sac_assoc_id <= 0) {
+ log_print("COMM_UP for invalid assoc ID %d",
+ (int)sn->sn_assoc_change.sac_assoc_id);
+ init_failed();
+ return;
+ }
+ memset(&prim, 0, sizeof(struct sctp_prim));
+ prim_len = sizeof(struct sctp_prim);
+ prim.ssp_assoc_id = sn->sn_assoc_change.sac_assoc_id;
+
+ fs = get_fs();
+ set_fs(get_ds());
+ ret = sctp_con.sock->ops->getsockopt(sctp_con.sock,
+ IPPROTO_SCTP, SCTP_PRIMARY_ADDR,
+ (char*)&prim, &prim_len);
+ set_fs(fs);
+ if (ret < 0) {
+ struct nodeinfo *ni;
+
+ log_print("getsockopt/sctp_primary_addr on "
+ "new assoc %d failed : %d",
+ (int)sn->sn_assoc_change.sac_assoc_id, ret);
+
+ /* Retry INIT later */
+ ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
+ if (ni)
+ clear_bit(NI_INIT_PENDING, &ni->flags);
+ return;
+ }
+ make_sockaddr(&prim.ssp_addr, 0, &addr_len);
+ if (dlm_addr_to_nodeid(&prim.ssp_addr, &nodeid)) {
+ log_print("reject connect from unknown addr");
+ send_shutdown(prim.ssp_assoc_id);
+ return;
+ }
+
+ ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
+ if (!ni)
+ return;
+
+ /* Save the assoc ID */
+ spin_lock(&ni->lock);
+ ni->assoc_id = sn->sn_assoc_change.sac_assoc_id;
+ spin_unlock(&ni->lock);
+
+ log_print("got new/restarted association %d nodeid %d",
+ (int)sn->sn_assoc_change.sac_assoc_id, nodeid);
+
+ /* Send any pending writes */
+ clear_bit(NI_INIT_PENDING, &ni->flags);
+ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+ spin_lock_bh(&write_nodes_lock);
+ list_add_tail(&ni->write_list, &write_nodes);
+ spin_unlock_bh(&write_nodes_lock);
+ }
+ wake_up_process(send_task);
+ }
+ break;
+
+ case SCTP_COMM_LOST:
+ case SCTP_SHUTDOWN_COMP:
+ {
+ struct nodeinfo *ni;
+
+ ni = assoc2nodeinfo(sn->sn_assoc_change.sac_assoc_id);
+ if (ni) {
+ spin_lock(&ni->lock);
+ ni->assoc_id = 0;
+ spin_unlock(&ni->lock);
+ }
+ }
+ break;
+
+ /* We don't know which INIT failed, so clear the PENDING flags
+ * on them all. if assoc_id is zero then it will then try
+ * again */
+
+ case SCTP_CANT_STR_ASSOC:
+ {
+ log_print("Can't start SCTP association - retrying");
+ init_failed();
+ }
+ break;
+
+ default:
+ log_print("unexpected SCTP assoc change id=%d state=%d",
+ (int)sn->sn_assoc_change.sac_assoc_id,
+ sn->sn_assoc_change.sac_state);
+ }
+ }
+}
+
+/* Data received from remote end */
+static int receive_from_sock(void)
+{
+ int ret = 0;
+ struct msghdr msg;
+ struct kvec iov[2];
+ unsigned len;
+ int r;
+ struct sctp_sndrcvinfo *sinfo;
+ struct cmsghdr *cmsg;
+ struct nodeinfo *ni;
+
+ /* These two are marginally too big for stack allocation, but this
+ * function is (currently) only called by dlm_recvd so static should be
+ * OK.
+ */
+ static struct sockaddr_storage msgname;
+ static char incmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+
+ if (sctp_con.sock == NULL)
+ goto out;
+
+ if (sctp_con.rx_page == NULL) {
+ /*
+ * This doesn't need to be atomic, but I think it should
+ * improve performance if it is.
+ */
+ sctp_con.rx_page = alloc_page(GFP_ATOMIC);
+ if (sctp_con.rx_page == NULL)
+ goto out_resched;
+ CBUF_INIT(&sctp_con.cb, PAGE_CACHE_SIZE);
+ }
+
+ memset(&incmsg, 0, sizeof(incmsg));
+ memset(&msgname, 0, sizeof(msgname));
+
+ memset(incmsg, 0, sizeof(incmsg));
+ msg.msg_name = &msgname;
+ msg.msg_namelen = sizeof(msgname);
+ msg.msg_flags = 0;
+ msg.msg_control = incmsg;
+ msg.msg_controllen = sizeof(incmsg);
+ msg.msg_iovlen = 1;
+
+ /* I don't see why this circular buffer stuff is necessary for SCTP
+ * which is a packet-based protocol, but the whole thing breaks under
+ * load without it! The overhead is minimal (and is in the TCP lowcomms
+ * anyway, of course) so I'll leave it in until I can figure out what's
+ * really happening.
+ */
+
+ /*
+ * iov[0] is the bit of the circular buffer between the current end
+ * point (cb.base + cb.len) and the end of the buffer.
+ */
+ iov[0].iov_len = sctp_con.cb.base - CBUF_DATA(&sctp_con.cb);
+ iov[0].iov_base = page_address(sctp_con.rx_page) +
+ CBUF_DATA(&sctp_con.cb);
+ iov[1].iov_len = 0;
+
+ /*
+ * iov[1] is the bit of the circular buffer between the start of the
+ * buffer and the start of the currently used section (cb.base)
+ */
+ if (CBUF_DATA(&sctp_con.cb) >= sctp_con.cb.base) {
+ iov[0].iov_len = PAGE_CACHE_SIZE - CBUF_DATA(&sctp_con.cb);
+ iov[1].iov_len = sctp_con.cb.base;
+ iov[1].iov_base = page_address(sctp_con.rx_page);
+ msg.msg_iovlen = 2;
+ }
+ len = iov[0].iov_len + iov[1].iov_len;
+
+ r = ret = kernel_recvmsg(sctp_con.sock, &msg, iov, msg.msg_iovlen, len,
+ MSG_NOSIGNAL | MSG_DONTWAIT);
+ if (ret <= 0)
+ goto out_close;
+
+ msg.msg_control = incmsg;
+ msg.msg_controllen = sizeof(incmsg);
+ cmsg = CMSG_FIRSTHDR(&msg);
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+
+ if (msg.msg_flags & MSG_NOTIFICATION) {
+ process_sctp_notification(&msg, page_address(sctp_con.rx_page));
+ return 0;
+ }
+
+ /* Is this a new association ? */
+ ni = nodeid2nodeinfo(le32_to_cpu(sinfo->sinfo_ppid), GFP_KERNEL);
+ if (ni) {
+ ni->assoc_id = sinfo->sinfo_assoc_id;
+ if (test_and_clear_bit(NI_INIT_PENDING, &ni->flags)) {
+
+ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+ spin_lock_bh(&write_nodes_lock);
+ list_add_tail(&ni->write_list, &write_nodes);
+ spin_unlock_bh(&write_nodes_lock);
+ }
+ wake_up_process(send_task);
+ }
+ }
+
+ /* INIT sends a message with length of 1 - ignore it */
+ if (r == 1)
+ return 0;
+
+ CBUF_ADD(&sctp_con.cb, ret);
+ ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid),
+ page_address(sctp_con.rx_page),
+ sctp_con.cb.base, sctp_con.cb.len,
+ PAGE_CACHE_SIZE);
+ if (ret < 0)
+ goto out_close;
+ CBUF_EAT(&sctp_con.cb, ret);
+
+ out:
+ ret = 0;
+ goto out_ret;
+
+ out_resched:
+ lowcomms_data_ready(sctp_con.sock->sk, 0);
+ ret = 0;
+ schedule();
+ goto out_ret;
+
+ out_close:
+ if (ret != -EAGAIN)
+ log_print("error reading from sctp socket: %d", ret);
+ out_ret:
+ return ret;
+}
+
+/* Bind to an IP address. SCTP allows multiple address so it can do multi-homing */
+static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num)
+{
+ mm_segment_t fs;
+ int result = 0;
+
+ fs = get_fs();
+ set_fs(get_ds());
+ if (num == 1)
+ result = sctp_con.sock->ops->bind(sctp_con.sock,
+ (struct sockaddr *) addr, addr_len);
+ else
+ result = sctp_con.sock->ops->setsockopt(sctp_con.sock, SOL_SCTP,
+ SCTP_SOCKOPT_BINDX_ADD, (char *)addr, addr_len);
+ set_fs(fs);
+
+ if (result < 0)
+ log_print("Can't bind to port %d addr number %d",
+ dlm_config.tcp_port, num);
+
+ return result;
+}
+
+static void init_local(void)
+{
+ struct sockaddr_storage sas, *addr;
+ int i;
+
+ dlm_local_nodeid = dlm_our_nodeid();
+
+ for (i = 0; i < DLM_MAX_ADDR_COUNT - 1; i++) {
+ if (dlm_our_addr(&sas, i))
+ break;
+
+ addr = kmalloc(sizeof(*addr), GFP_KERNEL);
+ if (!addr)
+ break;
+ memcpy(addr, &sas, sizeof(*addr));
+ dlm_local_addr[dlm_local_count++] = addr;
+ }
+}
+
+/* Initialise SCTP socket and bind to all interfaces */
+static int init_sock(void)
+{
+ mm_segment_t fs;
+ struct socket *sock = NULL;
+ struct sockaddr_storage localaddr;
+ struct sctp_event_subscribe subscribe;
+ int result = -EINVAL, num = 1, i, addr_len;
+
+ if (!dlm_local_count) {
+ init_local();
+ if (!dlm_local_count) {
+ log_print("no local IP address has been set");
+ goto out;
+ }
+ }
+
+ result = sock_create_kern(dlm_local_addr[0]->ss_family, SOCK_SEQPACKET,
+ IPPROTO_SCTP, &sock);
+ if (result < 0) {
+ log_print("Can't create comms socket, check SCTP is loaded");
+ goto out;
+ }
+
+ /* Listen for events */
+ memset(&subscribe, 0, sizeof(subscribe));
+ subscribe.sctp_data_io_event = 1;
+ subscribe.sctp_association_event = 1;
+ subscribe.sctp_send_failure_event = 1;
+ subscribe.sctp_shutdown_event = 1;
+ subscribe.sctp_partial_delivery_event = 1;
+
+ fs = get_fs();
+ set_fs(get_ds());
+ result = sock->ops->setsockopt(sock, SOL_SCTP, SCTP_EVENTS,
+ (char *)&subscribe, sizeof(subscribe));
+ set_fs(fs);
+
+ if (result < 0) {
+ log_print("Failed to set SCTP_EVENTS on socket: result=%d",
+ result);
+ goto create_delsock;
+ }
+
+ /* Init con struct */
+ sock->sk->sk_user_data = &sctp_con;
+ sctp_con.sock = sock;
+ sctp_con.sock->sk->sk_data_ready = lowcomms_data_ready;
+
+ /* Bind to all interfaces. */
+ for (i = 0; i < dlm_local_count; i++) {
+ memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
+ make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len);
+
+ result = add_bind_addr(&localaddr, addr_len, num);
+ if (result)
+ goto create_delsock;
+ ++num;
+ }
+
+ result = sock->ops->listen(sock, 5);
+ if (result < 0) {
+ log_print("Can't set socket listening");
+ goto create_delsock;
+ }
+
+ return 0;
+
+ create_delsock:
+ sock_release(sock);
+ sctp_con.sock = NULL;
+ out:
+ return result;
+}
+
+
+static struct writequeue_entry *new_writequeue_entry(gfp_t allocation)
+{
+ struct writequeue_entry *entry;
+
+ entry = kmalloc(sizeof(struct writequeue_entry), allocation);
+ if (!entry)
+ return NULL;
+
+ entry->page = alloc_page(allocation);
+ if (!entry->page) {
+ kfree(entry);
+ return NULL;
+ }
+
+ entry->offset = 0;
+ entry->len = 0;
+ entry->end = 0;
+ entry->users = 0;
+
+ return entry;
+}
+
+void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc)
+{
+ struct writequeue_entry *e;
+ int offset = 0;
+ int users = 0;
+ struct nodeinfo *ni;
+
+ if (!atomic_read(&accepting))
+ return NULL;
+
+ ni = nodeid2nodeinfo(nodeid, allocation);
+ if (!ni)
+ return NULL;
+
+ spin_lock(&ni->writequeue_lock);
+ e = list_entry(ni->writequeue.prev, struct writequeue_entry, list);
+ if (((struct list_head *) e == &ni->writequeue) ||
+ (PAGE_CACHE_SIZE - e->end < len)) {
+ e = NULL;
+ } else {
+ offset = e->end;
+ e->end += len;
+ users = e->users++;
+ }
+ spin_unlock(&ni->writequeue_lock);
+
+ if (e) {
+ got_one:
+ if (users == 0)
+ kmap(e->page);
+ *ppc = page_address(e->page) + offset;
+ return e;
+ }
+
+ e = new_writequeue_entry(allocation);
+ if (e) {
+ spin_lock(&ni->writequeue_lock);
+ offset = e->end;
+ e->end += len;
+ e->ni = ni;
+ users = e->users++;
+ list_add_tail(&e->list, &ni->writequeue);
+ spin_unlock(&ni->writequeue_lock);
+ goto got_one;
+ }
+ return NULL;
+}
+
+void dlm_lowcomms_commit_buffer(void *arg)
+{
+ struct writequeue_entry *e = (struct writequeue_entry *) arg;
+ int users;
+ struct nodeinfo *ni = e->ni;
+
+ if (!atomic_read(&accepting))
+ return;
+
+ spin_lock(&ni->writequeue_lock);
+ users = --e->users;
+ if (users)
+ goto out;
+ e->len = e->end - e->offset;
+ kunmap(e->page);
+ spin_unlock(&ni->writequeue_lock);
+
+ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+ spin_lock_bh(&write_nodes_lock);
+ list_add_tail(&ni->write_list, &write_nodes);
+ spin_unlock_bh(&write_nodes_lock);
+ wake_up_process(send_task);
+ }
+ return;
+
+ out:
+ spin_unlock(&ni->writequeue_lock);
+ return;
+}
+
+static void free_entry(struct writequeue_entry *e)
+{
+ __free_page(e->page);
+ kfree(e);
+}
+
+/* Initiate an SCTP association. In theory we could just use sendmsg() on
+ the first IP address and it should work, but this allows us to set up the
+ association before sending any valuable data that we can't afford to lose.
+ It also keeps the send path clean as it can now always use the association ID */
+static void initiate_association(int nodeid)
+{
+ struct sockaddr_storage rem_addr;
+ static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct msghdr outmessage;
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ int ret;
+ int addrlen;
+ char buf[1];
+ struct kvec iov[1];
+ struct nodeinfo *ni;
+
+ log_print("Initiating association with node %d", nodeid);
+
+ ni = nodeid2nodeinfo(nodeid, GFP_KERNEL);
+ if (!ni)
+ return;
+
+ if (nodeid_to_addr(nodeid, (struct sockaddr *)&rem_addr)) {
+ log_print("no address for nodeid %d", nodeid);
+ return;
+ }
+
+ make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen);
+
+ outmessage.msg_name = &rem_addr;
+ outmessage.msg_namelen = addrlen;
+ outmessage.msg_control = outcmsg;
+ outmessage.msg_controllen = sizeof(outcmsg);
+ outmessage.msg_flags = MSG_EOR;
+
+ iov[0].iov_base = buf;
+ iov[0].iov_len = 1;
+
+ /* Real INIT messages seem to cause trouble. Just send a 1 byte message
+ we can afford to lose */
+ cmsg = CMSG_FIRSTHDR(&outmessage);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
+
+ outmessage.msg_controllen = cmsg->cmsg_len;
+ ret = kernel_sendmsg(sctp_con.sock, &outmessage, iov, 1, 1);
+ if (ret < 0) {
+ log_print("send INIT to node failed: %d", ret);
+ /* Try again later */
+ clear_bit(NI_INIT_PENDING, &ni->flags);
+ }
+}
+
+/* Send a message */
+static int send_to_sock(struct nodeinfo *ni)
+{
+ int ret = 0;
+ struct writequeue_entry *e;
+ int len, offset;
+ struct msghdr outmsg;
+ static char outcmsg[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
+ struct cmsghdr *cmsg;
+ struct sctp_sndrcvinfo *sinfo;
+ struct kvec iov;
+
+ /* See if we need to init an association before we start
+ sending precious messages */
+ spin_lock(&ni->lock);
+ if (!ni->assoc_id && !test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
+ spin_unlock(&ni->lock);
+ initiate_association(ni->nodeid);
+ return 0;
+ }
+ spin_unlock(&ni->lock);
+
+ outmsg.msg_name = NULL; /* We use assoc_id */
+ outmsg.msg_namelen = 0;
+ outmsg.msg_control = outcmsg;
+ outmsg.msg_controllen = sizeof(outcmsg);
+ outmsg.msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL | MSG_EOR;
+
+ cmsg = CMSG_FIRSTHDR(&outmsg);
+ cmsg->cmsg_level = IPPROTO_SCTP;
+ cmsg->cmsg_type = SCTP_SNDRCV;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
+ sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0x00, sizeof(struct sctp_sndrcvinfo));
+ sinfo->sinfo_ppid = cpu_to_le32(dlm_local_nodeid);
+ sinfo->sinfo_assoc_id = ni->assoc_id;
+ outmsg.msg_controllen = cmsg->cmsg_len;
+
+ spin_lock(&ni->writequeue_lock);
+ for (;;) {
+ if (list_empty(&ni->writequeue))
+ break;
+ e = list_entry(ni->writequeue.next, struct writequeue_entry,
+ list);
+ len = e->len;
+ offset = e->offset;
+ BUG_ON(len == 0 && e->users == 0);
+ spin_unlock(&ni->writequeue_lock);
+ kmap(e->page);
+
+ ret = 0;
+ if (len) {
+ iov.iov_base = page_address(e->page)+offset;
+ iov.iov_len = len;
+
+ ret = kernel_sendmsg(sctp_con.sock, &outmsg, &iov, 1,
+ len);
+ if (ret == -EAGAIN) {
+ sctp_con.eagain_flag = 1;
+ goto out;
+ } else if (ret < 0)
+ goto send_error;
+ } else {
+ /* Don't starve people filling buffers */
+ schedule();
+ }
+
+ spin_lock(&ni->writequeue_lock);
+ e->offset += ret;
+ e->len -= ret;
+
+ if (e->len == 0 && e->users == 0) {
+ list_del(&e->list);
+ free_entry(e);
+ continue;
+ }
+ }
+ spin_unlock(&ni->writequeue_lock);
+ out:
+ return ret;
+
+ send_error:
+ log_print("Error sending to node %d %d", ni->nodeid, ret);
+ spin_lock(&ni->lock);
+ if (!test_and_set_bit(NI_INIT_PENDING, &ni->flags)) {
+ ni->assoc_id = 0;
+ spin_unlock(&ni->lock);
+ initiate_association(ni->nodeid);
+ } else
+ spin_unlock(&ni->lock);
+
+ return ret;
+}
+
+/* Try to send any messages that are pending */
+static void process_output_queue(void)
+{
+ struct list_head *list;
+ struct list_head *temp;
+
+ spin_lock_bh(&write_nodes_lock);
+ list_for_each_safe(list, temp, &write_nodes) {
+ struct nodeinfo *ni =
+ list_entry(list, struct nodeinfo, write_list);
+ clear_bit(NI_WRITE_PENDING, &ni->flags);
+ list_del(&ni->write_list);
+
+ spin_unlock_bh(&write_nodes_lock);
+
+ send_to_sock(ni);
+ spin_lock_bh(&write_nodes_lock);
+ }
+ spin_unlock_bh(&write_nodes_lock);
+}
+
+/* Called after we've had -EAGAIN and been woken up */
+static void refill_write_queue(void)
+{
+ int i;
+
+ for (i=1; i<=max_nodeid; i++) {
+ struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+
+ if (ni) {
+ if (!test_and_set_bit(NI_WRITE_PENDING, &ni->flags)) {
+ spin_lock_bh(&write_nodes_lock);
+ list_add_tail(&ni->write_list, &write_nodes);
+ spin_unlock_bh(&write_nodes_lock);
+ }
+ }
+ }
+}
+
+static void clean_one_writequeue(struct nodeinfo *ni)
+{
+ struct list_head *list;
+ struct list_head *temp;
+
+ spin_lock(&ni->writequeue_lock);
+ list_for_each_safe(list, temp, &ni->writequeue) {
+ struct writequeue_entry *e =
+ list_entry(list, struct writequeue_entry, list);
+ list_del(&e->list);
+ free_entry(e);
+ }
+ spin_unlock(&ni->writequeue_lock);
+}
+
+static void clean_writequeues(void)
+{
+ int i;
+
+ for (i=1; i<=max_nodeid; i++) {
+ struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+ if (ni)
+ clean_one_writequeue(ni);
+ }
+}
+
+
+static void dealloc_nodeinfo(void)
+{
+ int i;
+
+ for (i=1; i<=max_nodeid; i++) {
+ struct nodeinfo *ni = nodeid2nodeinfo(i, 0);
+ if (ni) {
+ idr_remove(&nodeinfo_idr, i);
+ kfree(ni);
+ }
+ }
+}
+
+int dlm_lowcomms_close(int nodeid)
+{
+ struct nodeinfo *ni;
+
+ ni = nodeid2nodeinfo(nodeid, 0);
+ if (!ni)
+ return -1;
+
+ spin_lock(&ni->lock);
+ if (ni->assoc_id) {
+ ni->assoc_id = 0;
+ /* Don't send shutdown here, sctp will just queue it
+ till the node comes back up! */
+ }
+ spin_unlock(&ni->lock);
+
+ clean_one_writequeue(ni);
+ clear_bit(NI_INIT_PENDING, &ni->flags);
+ return 0;
+}
+
+static int write_list_empty(void)
+{
+ int status;
+
+ spin_lock_bh(&write_nodes_lock);
+ status = list_empty(&write_nodes);
+ spin_unlock_bh(&write_nodes_lock);
+
+ return status;
+}
+
+static int dlm_recvd(void *data)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ while (!kthread_should_stop()) {
+ int count = 0;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&lowcomms_recv_wait, &wait);
+ if (!test_bit(CF_READ_PENDING, &sctp_con.flags))
+ schedule();
+ remove_wait_queue(&lowcomms_recv_wait, &wait);
+ set_current_state(TASK_RUNNING);
+
+ if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
+ int ret;
+
+ do {
+ ret = receive_from_sock();
+
+ /* Don't starve out everyone else */
+ if (++count >= MAX_RX_MSG_COUNT) {
+ schedule();
+ count = 0;
+ }
+ } while (!kthread_should_stop() && ret >=0);
+ }
+ schedule();
+ }
+
+ return 0;
+}
+
+static int dlm_sendd(void *data)
+{
+ DECLARE_WAITQUEUE(wait, current);
+
+ add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (write_list_empty())
+ schedule();
+ set_current_state(TASK_RUNNING);
+
+ if (sctp_con.eagain_flag) {
+ sctp_con.eagain_flag = 0;
+ refill_write_queue();
+ }
+ process_output_queue();
+ }
+
+ remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
+
+ return 0;
+}
+
+static void daemons_stop(void)
+{
+ kthread_stop(recv_task);
+ kthread_stop(send_task);
+}
+
+static int daemons_start(void)
+{
+ struct task_struct *p;
+ int error;
+
+ p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
+ error = IS_ERR(p);
+ if (error) {
+ log_print("can't start dlm_recvd %d", error);
+ return error;
+ }
+ recv_task = p;
+
+ p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
+ error = IS_ERR(p);
+ if (error) {
+ log_print("can't start dlm_sendd %d", error);
+ kthread_stop(recv_task);
+ return error;
+ }
+ send_task = p;
+
+ return 0;
+}
+
+/*
+ * This is quite likely to sleep...
+ */
+int dlm_lowcomms_start(void)
+{
+ int error;
+
+ error = init_sock();
+ if (error)
+ goto fail_sock;
+ error = daemons_start();
+ if (error)
+ goto fail_sock;
+ atomic_set(&accepting, 1);
+ return 0;
+
+ fail_sock:
+ close_connection();
+ return error;
+}
+
+/* Set all the activity flags to prevent any socket activity. */
+
+void dlm_lowcomms_stop(void)
+{
+ atomic_set(&accepting, 0);
+ sctp_con.flags = 0x7;
+ daemons_stop();
+ clean_writequeues();
+ close_connection();
+ dealloc_nodeinfo();
+ max_nodeid = 0;
+}
+
+int dlm_lowcomms_init(void)
+{
+ init_waitqueue_head(&lowcomms_recv_wait);
+ spin_lock_init(&write_nodes_lock);
+ INIT_LIST_HEAD(&write_nodes);
+ init_rwsem(&nodeinfo_lock);
+ return 0;
+}
+
+void dlm_lowcomms_exit(void)
+{
+ int i;
+
+ for (i = 0; i < dlm_local_count; i++)
+ kfree(dlm_local_addr[i]);
+ dlm_local_count = 0;
+ dlm_local_nodeid = 0;
+}
+
diff --git a/fs/dlm/lowcomms.h b/fs/dlm/lowcomms.h
new file mode 100644
index 000000000000..2d045e0daae1
--- /dev/null
+++ b/fs/dlm/lowcomms.h
@@ -0,0 +1,26 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LOWCOMMS_DOT_H__
+#define __LOWCOMMS_DOT_H__
+
+int dlm_lowcomms_init(void);
+void dlm_lowcomms_exit(void);
+int dlm_lowcomms_start(void);
+void dlm_lowcomms_stop(void);
+int dlm_lowcomms_close(int nodeid);
+void *dlm_lowcomms_get_buffer(int nodeid, int len, gfp_t allocation, char **ppc);
+void dlm_lowcomms_commit_buffer(void *mh);
+
+#endif /* __LOWCOMMS_DOT_H__ */
+
diff --git a/fs/dlm/lvb_table.h b/fs/dlm/lvb_table.h
new file mode 100644
index 000000000000..cc3e92f3feef
--- /dev/null
+++ b/fs/dlm/lvb_table.h
@@ -0,0 +1,18 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __LVB_TABLE_DOT_H__
+#define __LVB_TABLE_DOT_H__
+
+extern const int dlm_lvb_operations[8][8];
+
+#endif
diff --git a/fs/dlm/main.c b/fs/dlm/main.c
new file mode 100644
index 000000000000..a8da8dc36b2e
--- /dev/null
+++ b/fs/dlm/main.c
@@ -0,0 +1,97 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "lock.h"
+#include "user.h"
+#include "memory.h"
+#include "lowcomms.h"
+#include "config.h"
+
+#ifdef CONFIG_DLM_DEBUG
+int dlm_register_debugfs(void);
+void dlm_unregister_debugfs(void);
+#else
+static inline int dlm_register_debugfs(void) { return 0; }
+static inline void dlm_unregister_debugfs(void) { }
+#endif
+
+static int __init init_dlm(void)
+{
+ int error;
+
+ error = dlm_memory_init();
+ if (error)
+ goto out;
+
+ error = dlm_lockspace_init();
+ if (error)
+ goto out_mem;
+
+ error = dlm_config_init();
+ if (error)
+ goto out_lockspace;
+
+ error = dlm_register_debugfs();
+ if (error)
+ goto out_config;
+
+ error = dlm_lowcomms_init();
+ if (error)
+ goto out_debug;
+
+ error = dlm_user_init();
+ if (error)
+ goto out_lowcomms;
+
+ printk("DLM (built %s %s) installed\n", __DATE__, __TIME__);
+
+ return 0;
+
+ out_lowcomms:
+ dlm_lowcomms_exit();
+ out_debug:
+ dlm_unregister_debugfs();
+ out_config:
+ dlm_config_exit();
+ out_lockspace:
+ dlm_lockspace_exit();
+ out_mem:
+ dlm_memory_exit();
+ out:
+ return error;
+}
+
+static void __exit exit_dlm(void)
+{
+ dlm_user_exit();
+ dlm_lowcomms_exit();
+ dlm_config_exit();
+ dlm_memory_exit();
+ dlm_lockspace_exit();
+ dlm_unregister_debugfs();
+}
+
+module_init(init_dlm);
+module_exit(exit_dlm);
+
+MODULE_DESCRIPTION("Distributed Lock Manager");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL_GPL(dlm_new_lockspace);
+EXPORT_SYMBOL_GPL(dlm_release_lockspace);
+EXPORT_SYMBOL_GPL(dlm_lock);
+EXPORT_SYMBOL_GPL(dlm_unlock);
+
diff --git a/fs/dlm/member.c b/fs/dlm/member.c
new file mode 100644
index 000000000000..a3f7de7f3a8f
--- /dev/null
+++ b/fs/dlm/member.c
@@ -0,0 +1,327 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "recoverd.h"
+#include "recover.h"
+#include "rcom.h"
+#include "config.h"
+
+/*
+ * Following called by dlm_recoverd thread
+ */
+
+static void add_ordered_member(struct dlm_ls *ls, struct dlm_member *new)
+{
+ struct dlm_member *memb = NULL;
+ struct list_head *tmp;
+ struct list_head *newlist = &new->list;
+ struct list_head *head = &ls->ls_nodes;
+
+ list_for_each(tmp, head) {
+ memb = list_entry(tmp, struct dlm_member, list);
+ if (new->nodeid < memb->nodeid)
+ break;
+ }
+
+ if (!memb)
+ list_add_tail(newlist, head);
+ else {
+ /* FIXME: can use list macro here */
+ newlist->prev = tmp->prev;
+ newlist->next = tmp;
+ tmp->prev->next = newlist;
+ tmp->prev = newlist;
+ }
+}
+
+static int dlm_add_member(struct dlm_ls *ls, int nodeid)
+{
+ struct dlm_member *memb;
+ int w;
+
+ memb = kzalloc(sizeof(struct dlm_member), GFP_KERNEL);
+ if (!memb)
+ return -ENOMEM;
+
+ w = dlm_node_weight(ls->ls_name, nodeid);
+ if (w < 0)
+ return w;
+
+ memb->nodeid = nodeid;
+ memb->weight = w;
+ add_ordered_member(ls, memb);
+ ls->ls_num_nodes++;
+ return 0;
+}
+
+static void dlm_remove_member(struct dlm_ls *ls, struct dlm_member *memb)
+{
+ list_move(&memb->list, &ls->ls_nodes_gone);
+ ls->ls_num_nodes--;
+}
+
+static int dlm_is_member(struct dlm_ls *ls, int nodeid)
+{
+ struct dlm_member *memb;
+
+ list_for_each_entry(memb, &ls->ls_nodes, list) {
+ if (memb->nodeid == nodeid)
+ return 1;
+ }
+ return 0;
+}
+
+int dlm_is_removed(struct dlm_ls *ls, int nodeid)
+{
+ struct dlm_member *memb;
+
+ list_for_each_entry(memb, &ls->ls_nodes_gone, list) {
+ if (memb->nodeid == nodeid)
+ return 1;
+ }
+ return 0;
+}
+
+static void clear_memb_list(struct list_head *head)
+{
+ struct dlm_member *memb;
+
+ while (!list_empty(head)) {
+ memb = list_entry(head->next, struct dlm_member, list);
+ list_del(&memb->list);
+ kfree(memb);
+ }
+}
+
+void dlm_clear_members(struct dlm_ls *ls)
+{
+ clear_memb_list(&ls->ls_nodes);
+ ls->ls_num_nodes = 0;
+}
+
+void dlm_clear_members_gone(struct dlm_ls *ls)
+{
+ clear_memb_list(&ls->ls_nodes_gone);
+}
+
+static void make_member_array(struct dlm_ls *ls)
+{
+ struct dlm_member *memb;
+ int i, w, x = 0, total = 0, all_zero = 0, *array;
+
+ kfree(ls->ls_node_array);
+ ls->ls_node_array = NULL;
+
+ list_for_each_entry(memb, &ls->ls_nodes, list) {
+ if (memb->weight)
+ total += memb->weight;
+ }
+
+ /* all nodes revert to weight of 1 if all have weight 0 */
+
+ if (!total) {
+ total = ls->ls_num_nodes;
+ all_zero = 1;
+ }
+
+ ls->ls_total_weight = total;
+
+ array = kmalloc(sizeof(int) * total, GFP_KERNEL);
+ if (!array)
+ return;
+
+ list_for_each_entry(memb, &ls->ls_nodes, list) {
+ if (!all_zero && !memb->weight)
+ continue;
+
+ if (all_zero)
+ w = 1;
+ else
+ w = memb->weight;
+
+ DLM_ASSERT(x < total, printk("total %d x %d\n", total, x););
+
+ for (i = 0; i < w; i++)
+ array[x++] = memb->nodeid;
+ }
+
+ ls->ls_node_array = array;
+}
+
+/* send a status request to all members just to establish comms connections */
+
+static int ping_members(struct dlm_ls *ls)
+{
+ struct dlm_member *memb;
+ int error = 0;
+
+ list_for_each_entry(memb, &ls->ls_nodes, list) {
+ error = dlm_recovery_stopped(ls);
+ if (error)
+ break;
+ error = dlm_rcom_status(ls, memb->nodeid);
+ if (error)
+ break;
+ }
+ if (error)
+ log_debug(ls, "ping_members aborted %d last nodeid %d",
+ error, ls->ls_recover_nodeid);
+ return error;
+}
+
+int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv, int *neg_out)
+{
+ struct dlm_member *memb, *safe;
+ int i, error, found, pos = 0, neg = 0, low = -1;
+
+ /* move departed members from ls_nodes to ls_nodes_gone */
+
+ list_for_each_entry_safe(memb, safe, &ls->ls_nodes, list) {
+ found = 0;
+ for (i = 0; i < rv->node_count; i++) {
+ if (memb->nodeid == rv->nodeids[i]) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ neg++;
+ dlm_remove_member(ls, memb);
+ log_debug(ls, "remove member %d", memb->nodeid);
+ }
+ }
+
+ /* add new members to ls_nodes */
+
+ for (i = 0; i < rv->node_count; i++) {
+ if (dlm_is_member(ls, rv->nodeids[i]))
+ continue;
+ dlm_add_member(ls, rv->nodeids[i]);
+ pos++;
+ log_debug(ls, "add member %d", rv->nodeids[i]);
+ }
+
+ list_for_each_entry(memb, &ls->ls_nodes, list) {
+ if (low == -1 || memb->nodeid < low)
+ low = memb->nodeid;
+ }
+ ls->ls_low_nodeid = low;
+
+ make_member_array(ls);
+ dlm_set_recover_status(ls, DLM_RS_NODES);
+ *neg_out = neg;
+
+ error = ping_members(ls);
+ if (error)
+ goto out;
+
+ error = dlm_recover_members_wait(ls);
+ out:
+ log_debug(ls, "total members %d error %d", ls->ls_num_nodes, error);
+ return error;
+}
+
+/*
+ * Following called from lockspace.c
+ */
+
+int dlm_ls_stop(struct dlm_ls *ls)
+{
+ int new;
+
+ /*
+ * A stop cancels any recovery that's in progress (see RECOVERY_STOP,
+ * dlm_recovery_stopped()) and prevents any new locks from being
+ * processed (see RUNNING, dlm_locking_stopped()).
+ */
+
+ spin_lock(&ls->ls_recover_lock);
+ set_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+ new = test_and_clear_bit(LSFL_RUNNING, &ls->ls_flags);
+ ls->ls_recover_seq++;
+ spin_unlock(&ls->ls_recover_lock);
+
+ /*
+ * This in_recovery lock does two things:
+ *
+ * 1) Keeps this function from returning until all threads are out
+ * of locking routines and locking is truely stopped.
+ * 2) Keeps any new requests from being processed until it's unlocked
+ * when recovery is complete.
+ */
+
+ if (new)
+ down_write(&ls->ls_in_recovery);
+
+ /*
+ * The recoverd suspend/resume makes sure that dlm_recoverd (if
+ * running) has noticed the clearing of RUNNING above and quit
+ * processing the previous recovery. This will be true for all nodes
+ * before any nodes start the new recovery.
+ */
+
+ dlm_recoverd_suspend(ls);
+ ls->ls_recover_status = 0;
+ dlm_recoverd_resume(ls);
+ return 0;
+}
+
+int dlm_ls_start(struct dlm_ls *ls)
+{
+ struct dlm_recover *rv = NULL, *rv_old;
+ int *ids = NULL;
+ int error, count;
+
+ rv = kzalloc(sizeof(struct dlm_recover), GFP_KERNEL);
+ if (!rv)
+ return -ENOMEM;
+
+ error = count = dlm_nodeid_list(ls->ls_name, &ids);
+ if (error <= 0)
+ goto fail;
+
+ spin_lock(&ls->ls_recover_lock);
+
+ /* the lockspace needs to be stopped before it can be started */
+
+ if (!dlm_locking_stopped(ls)) {
+ spin_unlock(&ls->ls_recover_lock);
+ log_error(ls, "start ignored: lockspace running");
+ error = -EINVAL;
+ goto fail;
+ }
+
+ rv->nodeids = ids;
+ rv->node_count = count;
+ rv->seq = ++ls->ls_recover_seq;
+ rv_old = ls->ls_recover_args;
+ ls->ls_recover_args = rv;
+ spin_unlock(&ls->ls_recover_lock);
+
+ if (rv_old) {
+ kfree(rv_old->nodeids);
+ kfree(rv_old);
+ }
+
+ dlm_recoverd_kick(ls);
+ return 0;
+
+ fail:
+ kfree(rv);
+ kfree(ids);
+ return error;
+}
+
diff --git a/fs/dlm/member.h b/fs/dlm/member.h
new file mode 100644
index 000000000000..927c08c19214
--- /dev/null
+++ b/fs/dlm/member.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MEMBER_DOT_H__
+#define __MEMBER_DOT_H__
+
+int dlm_ls_stop(struct dlm_ls *ls);
+int dlm_ls_start(struct dlm_ls *ls);
+void dlm_clear_members(struct dlm_ls *ls);
+void dlm_clear_members_gone(struct dlm_ls *ls);
+int dlm_recover_members(struct dlm_ls *ls, struct dlm_recover *rv,int *neg_out);
+int dlm_is_removed(struct dlm_ls *ls, int nodeid);
+
+#endif /* __MEMBER_DOT_H__ */
+
diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c
new file mode 100644
index 000000000000..989b608fd836
--- /dev/null
+++ b/fs/dlm/memory.c
@@ -0,0 +1,116 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "config.h"
+#include "memory.h"
+
+static kmem_cache_t *lkb_cache;
+
+
+int dlm_memory_init(void)
+{
+ int ret = 0;
+
+ lkb_cache = kmem_cache_create("dlm_lkb", sizeof(struct dlm_lkb),
+ __alignof__(struct dlm_lkb), 0, NULL, NULL);
+ if (!lkb_cache)
+ ret = -ENOMEM;
+ return ret;
+}
+
+void dlm_memory_exit(void)
+{
+ if (lkb_cache)
+ kmem_cache_destroy(lkb_cache);
+}
+
+char *allocate_lvb(struct dlm_ls *ls)
+{
+ char *p;
+
+ p = kmalloc(ls->ls_lvblen, GFP_KERNEL);
+ if (p)
+ memset(p, 0, ls->ls_lvblen);
+ return p;
+}
+
+void free_lvb(char *p)
+{
+ kfree(p);
+}
+
+/* FIXME: have some minimal space built-in to rsb for the name and
+ kmalloc a separate name if needed, like dentries are done */
+
+struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen)
+{
+ struct dlm_rsb *r;
+
+ DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,);
+
+ r = kmalloc(sizeof(*r) + namelen, GFP_KERNEL);
+ if (r)
+ memset(r, 0, sizeof(*r) + namelen);
+ return r;
+}
+
+void free_rsb(struct dlm_rsb *r)
+{
+ if (r->res_lvbptr)
+ free_lvb(r->res_lvbptr);
+ kfree(r);
+}
+
+struct dlm_lkb *allocate_lkb(struct dlm_ls *ls)
+{
+ struct dlm_lkb *lkb;
+
+ lkb = kmem_cache_alloc(lkb_cache, GFP_KERNEL);
+ if (lkb)
+ memset(lkb, 0, sizeof(*lkb));
+ return lkb;
+}
+
+void free_lkb(struct dlm_lkb *lkb)
+{
+ if (lkb->lkb_flags & DLM_IFL_USER) {
+ struct dlm_user_args *ua;
+ ua = (struct dlm_user_args *)lkb->lkb_astparam;
+ if (ua) {
+ if (ua->lksb.sb_lvbptr)
+ kfree(ua->lksb.sb_lvbptr);
+ kfree(ua);
+ }
+ }
+ kmem_cache_free(lkb_cache, lkb);
+}
+
+struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen)
+{
+ struct dlm_direntry *de;
+
+ DLM_ASSERT(namelen <= DLM_RESNAME_MAXLEN,
+ printk("namelen = %d\n", namelen););
+
+ de = kmalloc(sizeof(*de) + namelen, GFP_KERNEL);
+ if (de)
+ memset(de, 0, sizeof(*de) + namelen);
+ return de;
+}
+
+void free_direntry(struct dlm_direntry *de)
+{
+ kfree(de);
+}
+
diff --git a/fs/dlm/memory.h b/fs/dlm/memory.h
new file mode 100644
index 000000000000..6ead158ccc5c
--- /dev/null
+++ b/fs/dlm/memory.h
@@ -0,0 +1,29 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MEMORY_DOT_H__
+#define __MEMORY_DOT_H__
+
+int dlm_memory_init(void);
+void dlm_memory_exit(void);
+struct dlm_rsb *allocate_rsb(struct dlm_ls *ls, int namelen);
+void free_rsb(struct dlm_rsb *r);
+struct dlm_lkb *allocate_lkb(struct dlm_ls *ls);
+void free_lkb(struct dlm_lkb *l);
+struct dlm_direntry *allocate_direntry(struct dlm_ls *ls, int namelen);
+void free_direntry(struct dlm_direntry *de);
+char *allocate_lvb(struct dlm_ls *ls);
+void free_lvb(char *l);
+
+#endif /* __MEMORY_DOT_H__ */
+
diff --git a/fs/dlm/midcomms.c b/fs/dlm/midcomms.c
new file mode 100644
index 000000000000..c9b1c3d535f4
--- /dev/null
+++ b/fs/dlm/midcomms.c
@@ -0,0 +1,140 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/*
+ * midcomms.c
+ *
+ * This is the appallingly named "mid-level" comms layer.
+ *
+ * Its purpose is to take packets from the "real" comms layer,
+ * split them up into packets and pass them to the interested
+ * part of the locking mechanism.
+ *
+ * It also takes messages from the locking layer, formats them
+ * into packets and sends them to the comms layer.
+ */
+
+#include "dlm_internal.h"
+#include "lowcomms.h"
+#include "config.h"
+#include "rcom.h"
+#include "lock.h"
+#include "midcomms.h"
+
+
+static void copy_from_cb(void *dst, const void *base, unsigned offset,
+ unsigned len, unsigned limit)
+{
+ unsigned copy = len;
+
+ if ((copy + offset) > limit)
+ copy = limit - offset;
+ memcpy(dst, base + offset, copy);
+ len -= copy;
+ if (len)
+ memcpy(dst + copy, base, len);
+}
+
+/*
+ * Called from the low-level comms layer to process a buffer of
+ * commands.
+ *
+ * Only complete messages are processed here, any "spare" bytes from
+ * the end of a buffer are saved and tacked onto the front of the next
+ * message that comes in. I doubt this will happen very often but we
+ * need to be able to cope with it and I don't want the task to be waiting
+ * for packets to come in when there is useful work to be done.
+ */
+
+int dlm_process_incoming_buffer(int nodeid, const void *base,
+ unsigned offset, unsigned len, unsigned limit)
+{
+ unsigned char __tmp[DLM_INBUF_LEN];
+ struct dlm_header *msg = (struct dlm_header *) __tmp;
+ int ret = 0;
+ int err = 0;
+ uint16_t msglen;
+ uint32_t lockspace;
+
+ while (len > sizeof(struct dlm_header)) {
+
+ /* Copy just the header to check the total length. The
+ message may wrap around the end of the buffer back to the
+ start, so we need to use a temp buffer and copy_from_cb. */
+
+ copy_from_cb(msg, base, offset, sizeof(struct dlm_header),
+ limit);
+
+ msglen = le16_to_cpu(msg->h_length);
+ lockspace = msg->h_lockspace;
+
+ err = -EINVAL;
+ if (msglen < sizeof(struct dlm_header))
+ break;
+ err = -E2BIG;
+ if (msglen > dlm_config.buffer_size) {
+ log_print("message size %d from %d too big, buf len %d",
+ msglen, nodeid, len);
+ break;
+ }
+ err = 0;
+
+ /* If only part of the full message is contained in this
+ buffer, then do nothing and wait for lowcomms to call
+ us again later with more data. We return 0 meaning
+ we've consumed none of the input buffer. */
+
+ if (msglen > len)
+ break;
+
+ /* Allocate a larger temp buffer if the full message won't fit
+ in the buffer on the stack (which should work for most
+ ordinary messages). */
+
+ if (msglen > sizeof(__tmp) &&
+ msg == (struct dlm_header *) __tmp) {
+ msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+ if (msg == NULL)
+ return ret;
+ }
+
+ copy_from_cb(msg, base, offset, msglen, limit);
+
+ BUG_ON(lockspace != msg->h_lockspace);
+
+ ret += msglen;
+ offset += msglen;
+ offset &= (limit - 1);
+ len -= msglen;
+
+ switch (msg->h_cmd) {
+ case DLM_MSG:
+ dlm_receive_message(msg, nodeid, 0);
+ break;
+
+ case DLM_RCOM:
+ dlm_receive_rcom(msg, nodeid);
+ break;
+
+ default:
+ log_print("unknown msg type %x from %u: %u %u %u %u",
+ msg->h_cmd, nodeid, msglen, len, offset, ret);
+ }
+ }
+
+ if (msg != (struct dlm_header *) __tmp)
+ kfree(msg);
+
+ return err ? err : ret;
+}
+
diff --git a/fs/dlm/midcomms.h b/fs/dlm/midcomms.h
new file mode 100644
index 000000000000..95852a5f111d
--- /dev/null
+++ b/fs/dlm/midcomms.h
@@ -0,0 +1,21 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __MIDCOMMS_DOT_H__
+#define __MIDCOMMS_DOT_H__
+
+int dlm_process_incoming_buffer(int nodeid, const void *base, unsigned offset,
+ unsigned len, unsigned limit);
+
+#endif /* __MIDCOMMS_DOT_H__ */
+
diff --git a/fs/dlm/rcom.c b/fs/dlm/rcom.c
new file mode 100644
index 000000000000..518239a8b1e9
--- /dev/null
+++ b/fs/dlm/rcom.c
@@ -0,0 +1,472 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "lowcomms.h"
+#include "midcomms.h"
+#include "rcom.h"
+#include "recover.h"
+#include "dir.h"
+#include "config.h"
+#include "memory.h"
+#include "lock.h"
+#include "util.h"
+
+
+static int rcom_response(struct dlm_ls *ls)
+{
+ return test_bit(LSFL_RCOM_READY, &ls->ls_flags);
+}
+
+static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len,
+ struct dlm_rcom **rc_ret, struct dlm_mhandle **mh_ret)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ char *mb;
+ int mb_len = sizeof(struct dlm_rcom) + len;
+
+ mh = dlm_lowcomms_get_buffer(to_nodeid, mb_len, GFP_KERNEL, &mb);
+ if (!mh) {
+ log_print("create_rcom to %d type %d len %d ENOBUFS",
+ to_nodeid, type, len);
+ return -ENOBUFS;
+ }
+ memset(mb, 0, mb_len);
+
+ rc = (struct dlm_rcom *) mb;
+
+ rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+ rc->rc_header.h_lockspace = ls->ls_global_id;
+ rc->rc_header.h_nodeid = dlm_our_nodeid();
+ rc->rc_header.h_length = mb_len;
+ rc->rc_header.h_cmd = DLM_RCOM;
+
+ rc->rc_type = type;
+
+ *mh_ret = mh;
+ *rc_ret = rc;
+ return 0;
+}
+
+static void send_rcom(struct dlm_ls *ls, struct dlm_mhandle *mh,
+ struct dlm_rcom *rc)
+{
+ dlm_rcom_out(rc);
+ dlm_lowcomms_commit_buffer(mh);
+}
+
+/* When replying to a status request, a node also sends back its
+ configuration values. The requesting node then checks that the remote
+ node is configured the same way as itself. */
+
+static void make_config(struct dlm_ls *ls, struct rcom_config *rf)
+{
+ rf->rf_lvblen = ls->ls_lvblen;
+ rf->rf_lsflags = ls->ls_exflags;
+}
+
+static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid)
+{
+ if (rf->rf_lvblen != ls->ls_lvblen ||
+ rf->rf_lsflags != ls->ls_exflags) {
+ log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
+ ls->ls_lvblen, ls->ls_exflags,
+ nodeid, rf->rf_lvblen, rf->rf_lsflags);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ int error = 0;
+
+ memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+ ls->ls_recover_nodeid = nodeid;
+
+ if (nodeid == dlm_our_nodeid()) {
+ rc = (struct dlm_rcom *) ls->ls_recover_buf;
+ rc->rc_result = dlm_recover_status(ls);
+ goto out;
+ }
+
+ error = create_rcom(ls, nodeid, DLM_RCOM_STATUS, 0, &rc, &mh);
+ if (error)
+ goto out;
+ rc->rc_id = ++ls->ls_rcom_seq;
+
+ send_rcom(ls, mh, rc);
+
+ error = dlm_wait_function(ls, &rcom_response);
+ clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
+ if (error)
+ goto out;
+
+ rc = (struct dlm_rcom *) ls->ls_recover_buf;
+
+ if (rc->rc_result == -ESRCH) {
+ /* we pretend the remote lockspace exists with 0 status */
+ log_debug(ls, "remote node %d not ready", nodeid);
+ rc->rc_result = 0;
+ } else
+ error = check_config(ls, (struct rcom_config *) rc->rc_buf,
+ nodeid);
+ /* the caller looks at rc_result for the remote recovery status */
+ out:
+ return error;
+}
+
+static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ int error, nodeid = rc_in->rc_header.h_nodeid;
+
+ error = create_rcom(ls, nodeid, DLM_RCOM_STATUS_REPLY,
+ sizeof(struct rcom_config), &rc, &mh);
+ if (error)
+ return;
+ rc->rc_id = rc_in->rc_id;
+ rc->rc_result = dlm_recover_status(ls);
+ make_config(ls, (struct rcom_config *) rc->rc_buf);
+
+ send_rcom(ls, mh, rc);
+}
+
+static void receive_sync_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ if (rc_in->rc_id != ls->ls_rcom_seq) {
+ log_debug(ls, "reject old reply %d got %llx wanted %llx",
+ rc_in->rc_type, rc_in->rc_id, ls->ls_rcom_seq);
+ return;
+ }
+ memcpy(ls->ls_recover_buf, rc_in, rc_in->rc_header.h_length);
+ set_bit(LSFL_RCOM_READY, &ls->ls_flags);
+ wake_up(&ls->ls_wait_general);
+}
+
+static void receive_rcom_status_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ receive_sync_reply(ls, rc_in);
+}
+
+int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ int error = 0, len = sizeof(struct dlm_rcom);
+
+ memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+ ls->ls_recover_nodeid = nodeid;
+
+ if (nodeid == dlm_our_nodeid()) {
+ dlm_copy_master_names(ls, last_name, last_len,
+ ls->ls_recover_buf + len,
+ dlm_config.buffer_size - len, nodeid);
+ goto out;
+ }
+
+ error = create_rcom(ls, nodeid, DLM_RCOM_NAMES, last_len, &rc, &mh);
+ if (error)
+ goto out;
+ memcpy(rc->rc_buf, last_name, last_len);
+ rc->rc_id = ++ls->ls_rcom_seq;
+
+ send_rcom(ls, mh, rc);
+
+ error = dlm_wait_function(ls, &rcom_response);
+ clear_bit(LSFL_RCOM_READY, &ls->ls_flags);
+ out:
+ return error;
+}
+
+static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ int error, inlen, outlen;
+ int nodeid = rc_in->rc_header.h_nodeid;
+ uint32_t status = dlm_recover_status(ls);
+
+ /*
+ * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while
+ * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes).
+ * It could only happen in rare cases where we get a late NAMES
+ * message from a previous instance of recovery.
+ */
+
+ if (!(status & DLM_RS_NODES)) {
+ log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid);
+ return;
+ }
+
+ nodeid = rc_in->rc_header.h_nodeid;
+ inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
+ outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom);
+
+ error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh);
+ if (error)
+ return;
+ rc->rc_id = rc_in->rc_id;
+
+ dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen,
+ nodeid);
+ send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_names_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ receive_sync_reply(ls, rc_in);
+}
+
+int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ struct dlm_ls *ls = r->res_ls;
+ int error;
+
+ error = create_rcom(ls, dir_nodeid, DLM_RCOM_LOOKUP, r->res_length,
+ &rc, &mh);
+ if (error)
+ goto out;
+ memcpy(rc->rc_buf, r->res_name, r->res_length);
+ rc->rc_id = (unsigned long) r;
+
+ send_rcom(ls, mh, rc);
+ out:
+ return error;
+}
+
+static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ int error, ret_nodeid, nodeid = rc_in->rc_header.h_nodeid;
+ int len = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
+
+ error = create_rcom(ls, nodeid, DLM_RCOM_LOOKUP_REPLY, 0, &rc, &mh);
+ if (error)
+ return;
+
+ error = dlm_dir_lookup(ls, nodeid, rc_in->rc_buf, len, &ret_nodeid);
+ if (error)
+ ret_nodeid = error;
+ rc->rc_result = ret_nodeid;
+ rc->rc_id = rc_in->rc_id;
+
+ send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_lookup_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ dlm_recover_master_reply(ls, rc_in);
+}
+
+static void pack_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb,
+ struct rcom_lock *rl)
+{
+ memset(rl, 0, sizeof(*rl));
+
+ rl->rl_ownpid = lkb->lkb_ownpid;
+ rl->rl_lkid = lkb->lkb_id;
+ rl->rl_exflags = lkb->lkb_exflags;
+ rl->rl_flags = lkb->lkb_flags;
+ rl->rl_lvbseq = lkb->lkb_lvbseq;
+ rl->rl_rqmode = lkb->lkb_rqmode;
+ rl->rl_grmode = lkb->lkb_grmode;
+ rl->rl_status = lkb->lkb_status;
+ rl->rl_wait_type = lkb->lkb_wait_type;
+
+ if (lkb->lkb_bastaddr)
+ rl->rl_asts |= AST_BAST;
+ if (lkb->lkb_astaddr)
+ rl->rl_asts |= AST_COMP;
+
+ rl->rl_namelen = r->res_length;
+ memcpy(rl->rl_name, r->res_name, r->res_length);
+
+ /* FIXME: might we have an lvb without DLM_LKF_VALBLK set ?
+ If so, receive_rcom_lock_args() won't take this copy. */
+
+ if (lkb->lkb_lvbptr)
+ memcpy(rl->rl_lvb, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
+}
+
+int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb)
+{
+ struct dlm_ls *ls = r->res_ls;
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ struct rcom_lock *rl;
+ int error, len = sizeof(struct rcom_lock);
+
+ if (lkb->lkb_lvbptr)
+ len += ls->ls_lvblen;
+
+ error = create_rcom(ls, r->res_nodeid, DLM_RCOM_LOCK, len, &rc, &mh);
+ if (error)
+ goto out;
+
+ rl = (struct rcom_lock *) rc->rc_buf;
+ pack_rcom_lock(r, lkb, rl);
+ rc->rc_id = (unsigned long) r;
+
+ send_rcom(ls, mh, rc);
+ out:
+ return error;
+}
+
+static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ int error, nodeid = rc_in->rc_header.h_nodeid;
+
+ dlm_recover_master_copy(ls, rc_in);
+
+ error = create_rcom(ls, nodeid, DLM_RCOM_LOCK_REPLY,
+ sizeof(struct rcom_lock), &rc, &mh);
+ if (error)
+ return;
+
+ /* We send back the same rcom_lock struct we received, but
+ dlm_recover_master_copy() has filled in rl_remid and rl_result */
+
+ memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock));
+ rc->rc_id = rc_in->rc_id;
+
+ send_rcom(ls, mh, rc);
+}
+
+static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
+{
+ uint32_t status = dlm_recover_status(ls);
+
+ if (!(status & DLM_RS_DIR)) {
+ log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u",
+ rc_in->rc_header.h_nodeid);
+ return;
+ }
+
+ dlm_recover_process_copy(ls, rc_in);
+}
+
+static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
+{
+ struct dlm_rcom *rc;
+ struct dlm_mhandle *mh;
+ char *mb;
+ int mb_len = sizeof(struct dlm_rcom);
+
+ mh = dlm_lowcomms_get_buffer(nodeid, mb_len, GFP_KERNEL, &mb);
+ if (!mh)
+ return -ENOBUFS;
+ memset(mb, 0, mb_len);
+
+ rc = (struct dlm_rcom *) mb;
+
+ rc->rc_header.h_version = (DLM_HEADER_MAJOR | DLM_HEADER_MINOR);
+ rc->rc_header.h_lockspace = rc_in->rc_header.h_lockspace;
+ rc->rc_header.h_nodeid = dlm_our_nodeid();
+ rc->rc_header.h_length = mb_len;
+ rc->rc_header.h_cmd = DLM_RCOM;
+
+ rc->rc_type = DLM_RCOM_STATUS_REPLY;
+ rc->rc_id = rc_in->rc_id;
+ rc->rc_result = -ESRCH;
+
+ dlm_rcom_out(rc);
+ dlm_lowcomms_commit_buffer(mh);
+
+ return 0;
+}
+
+/* Called by dlm_recvd; corresponds to dlm_receive_message() but special
+ recovery-only comms are sent through here. */
+
+void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
+{
+ struct dlm_rcom *rc = (struct dlm_rcom *) hd;
+ struct dlm_ls *ls;
+
+ dlm_rcom_in(rc);
+
+ /* If the lockspace doesn't exist then still send a status message
+ back; it's possible that it just doesn't have its global_id yet. */
+
+ ls = dlm_find_lockspace_global(hd->h_lockspace);
+ if (!ls) {
+ log_print("lockspace %x from %d not found",
+ hd->h_lockspace, nodeid);
+ send_ls_not_ready(nodeid, rc);
+ return;
+ }
+
+ if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
+ log_error(ls, "ignoring recovery message %x from %d",
+ rc->rc_type, nodeid);
+ goto out;
+ }
+
+ if (nodeid != rc->rc_header.h_nodeid) {
+ log_error(ls, "bad rcom nodeid %d from %d",
+ rc->rc_header.h_nodeid, nodeid);
+ goto out;
+ }
+
+ switch (rc->rc_type) {
+ case DLM_RCOM_STATUS:
+ receive_rcom_status(ls, rc);
+ break;
+
+ case DLM_RCOM_NAMES:
+ receive_rcom_names(ls, rc);
+ break;
+
+ case DLM_RCOM_LOOKUP:
+ receive_rcom_lookup(ls, rc);
+ break;
+
+ case DLM_RCOM_LOCK:
+ receive_rcom_lock(ls, rc);
+ break;
+
+ case DLM_RCOM_STATUS_REPLY:
+ receive_rcom_status_reply(ls, rc);
+ break;
+
+ case DLM_RCOM_NAMES_REPLY:
+ receive_rcom_names_reply(ls, rc);
+ break;
+
+ case DLM_RCOM_LOOKUP_REPLY:
+ receive_rcom_lookup_reply(ls, rc);
+ break;
+
+ case DLM_RCOM_LOCK_REPLY:
+ receive_rcom_lock_reply(ls, rc);
+ break;
+
+ default:
+ DLM_ASSERT(0, printk("rc_type=%x\n", rc->rc_type););
+ }
+ out:
+ dlm_put_lockspace(ls);
+}
+
diff --git a/fs/dlm/rcom.h b/fs/dlm/rcom.h
new file mode 100644
index 000000000000..d7984321ff41
--- /dev/null
+++ b/fs/dlm/rcom.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RCOM_DOT_H__
+#define __RCOM_DOT_H__
+
+int dlm_rcom_status(struct dlm_ls *ls, int nodeid);
+int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);
+int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);
+int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);
+void dlm_receive_rcom(struct dlm_header *hd, int nodeid);
+
+#endif
+
diff --git a/fs/dlm/recover.c b/fs/dlm/recover.c
new file mode 100644
index 000000000000..a5e6d184872e
--- /dev/null
+++ b/fs/dlm/recover.c
@@ -0,0 +1,765 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "dir.h"
+#include "config.h"
+#include "ast.h"
+#include "memory.h"
+#include "rcom.h"
+#include "lock.h"
+#include "lowcomms.h"
+#include "member.h"
+#include "recover.h"
+
+
+/*
+ * Recovery waiting routines: these functions wait for a particular reply from
+ * a remote node, or for the remote node to report a certain status. They need
+ * to abort if the lockspace is stopped indicating a node has failed (perhaps
+ * the one being waited for).
+ */
+
+/*
+ * Wait until given function returns non-zero or lockspace is stopped
+ * (LS_RECOVERY_STOP set due to failure of a node in ls_nodes). When another
+ * function thinks it could have completed the waited-on task, they should wake
+ * up ls_wait_general to get an immediate response rather than waiting for the
+ * timer to detect the result. A timer wakes us up periodically while waiting
+ * to see if we should abort due to a node failure. This should only be called
+ * by the dlm_recoverd thread.
+ */
+
+static void dlm_wait_timer_fn(unsigned long data)
+{
+ struct dlm_ls *ls = (struct dlm_ls *) data;
+ mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ));
+ wake_up(&ls->ls_wait_general);
+}
+
+int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))
+{
+ int error = 0;
+
+ init_timer(&ls->ls_timer);
+ ls->ls_timer.function = dlm_wait_timer_fn;
+ ls->ls_timer.data = (long) ls;
+ ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ);
+ add_timer(&ls->ls_timer);
+
+ wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
+ del_timer_sync(&ls->ls_timer);
+
+ if (dlm_recovery_stopped(ls)) {
+ log_debug(ls, "dlm_wait_function aborted");
+ error = -EINTR;
+ }
+ return error;
+}
+
+/*
+ * An efficient way for all nodes to wait for all others to have a certain
+ * status. The node with the lowest nodeid polls all the others for their
+ * status (wait_status_all) and all the others poll the node with the low id
+ * for its accumulated result (wait_status_low). When all nodes have set
+ * status flag X, then status flag X_ALL will be set on the low nodeid.
+ */
+
+uint32_t dlm_recover_status(struct dlm_ls *ls)
+{
+ uint32_t status;
+ spin_lock(&ls->ls_recover_lock);
+ status = ls->ls_recover_status;
+ spin_unlock(&ls->ls_recover_lock);
+ return status;
+}
+
+void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status)
+{
+ spin_lock(&ls->ls_recover_lock);
+ ls->ls_recover_status |= status;
+ spin_unlock(&ls->ls_recover_lock);
+}
+
+static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)
+{
+ struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
+ struct dlm_member *memb;
+ int error = 0, delay;
+
+ list_for_each_entry(memb, &ls->ls_nodes, list) {
+ delay = 0;
+ for (;;) {
+ if (dlm_recovery_stopped(ls)) {
+ error = -EINTR;
+ goto out;
+ }
+
+ error = dlm_rcom_status(ls, memb->nodeid);
+ if (error)
+ goto out;
+
+ if (rc->rc_result & wait_status)
+ break;
+ if (delay < 1000)
+ delay += 20;
+ msleep(delay);
+ }
+ }
+ out:
+ return error;
+}
+
+static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status)
+{
+ struct dlm_rcom *rc = (struct dlm_rcom *) ls->ls_recover_buf;
+ int error = 0, delay = 0, nodeid = ls->ls_low_nodeid;
+
+ for (;;) {
+ if (dlm_recovery_stopped(ls)) {
+ error = -EINTR;
+ goto out;
+ }
+
+ error = dlm_rcom_status(ls, nodeid);
+ if (error)
+ break;
+
+ if (rc->rc_result & wait_status)
+ break;
+ if (delay < 1000)
+ delay += 20;
+ msleep(delay);
+ }
+ out:
+ return error;
+}
+
+static int wait_status(struct dlm_ls *ls, uint32_t status)
+{
+ uint32_t status_all = status << 1;
+ int error;
+
+ if (ls->ls_low_nodeid == dlm_our_nodeid()) {
+ error = wait_status_all(ls, status);
+ if (!error)
+ dlm_set_recover_status(ls, status_all);
+ } else
+ error = wait_status_low(ls, status_all);
+
+ return error;
+}
+
+int dlm_recover_members_wait(struct dlm_ls *ls)
+{
+ return wait_status(ls, DLM_RS_NODES);
+}
+
+int dlm_recover_directory_wait(struct dlm_ls *ls)
+{
+ return wait_status(ls, DLM_RS_DIR);
+}
+
+int dlm_recover_locks_wait(struct dlm_ls *ls)
+{
+ return wait_status(ls, DLM_RS_LOCKS);
+}
+
+int dlm_recover_done_wait(struct dlm_ls *ls)
+{
+ return wait_status(ls, DLM_RS_DONE);
+}
+
+/*
+ * The recover_list contains all the rsb's for which we've requested the new
+ * master nodeid. As replies are returned from the resource directories the
+ * rsb's are removed from the list. When the list is empty we're done.
+ *
+ * The recover_list is later similarly used for all rsb's for which we've sent
+ * new lkb's and need to receive new corresponding lkid's.
+ *
+ * We use the address of the rsb struct as a simple local identifier for the
+ * rsb so we can match an rcom reply with the rsb it was sent for.
+ */
+
+static int recover_list_empty(struct dlm_ls *ls)
+{
+ int empty;
+
+ spin_lock(&ls->ls_recover_list_lock);
+ empty = list_empty(&ls->ls_recover_list);
+ spin_unlock(&ls->ls_recover_list_lock);
+
+ return empty;
+}
+
+static void recover_list_add(struct dlm_rsb *r)
+{
+ struct dlm_ls *ls = r->res_ls;
+
+ spin_lock(&ls->ls_recover_list_lock);
+ if (list_empty(&r->res_recover_list)) {
+ list_add_tail(&r->res_recover_list, &ls->ls_recover_list);
+ ls->ls_recover_list_count++;
+ dlm_hold_rsb(r);
+ }
+ spin_unlock(&ls->ls_recover_list_lock);
+}
+
+static void recover_list_del(struct dlm_rsb *r)
+{
+ struct dlm_ls *ls = r->res_ls;
+
+ spin_lock(&ls->ls_recover_list_lock);
+ list_del_init(&r->res_recover_list);
+ ls->ls_recover_list_count--;
+ spin_unlock(&ls->ls_recover_list_lock);
+
+ dlm_put_rsb(r);
+}
+
+static struct dlm_rsb *recover_list_find(struct dlm_ls *ls, uint64_t id)
+{
+ struct dlm_rsb *r = NULL;
+
+ spin_lock(&ls->ls_recover_list_lock);
+
+ list_for_each_entry(r, &ls->ls_recover_list, res_recover_list) {
+ if (id == (unsigned long) r)
+ goto out;
+ }
+ r = NULL;
+ out:
+ spin_unlock(&ls->ls_recover_list_lock);
+ return r;
+}
+
+static void recover_list_clear(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r, *s;
+
+ spin_lock(&ls->ls_recover_list_lock);
+ list_for_each_entry_safe(r, s, &ls->ls_recover_list, res_recover_list) {
+ list_del_init(&r->res_recover_list);
+ dlm_put_rsb(r);
+ ls->ls_recover_list_count--;
+ }
+
+ if (ls->ls_recover_list_count != 0) {
+ log_error(ls, "warning: recover_list_count %d",
+ ls->ls_recover_list_count);
+ ls->ls_recover_list_count = 0;
+ }
+ spin_unlock(&ls->ls_recover_list_lock);
+}
+
+
+/* Master recovery: find new master node for rsb's that were
+ mastered on nodes that have been removed.
+
+ dlm_recover_masters
+ recover_master
+ dlm_send_rcom_lookup -> receive_rcom_lookup
+ dlm_dir_lookup
+ receive_rcom_lookup_reply <-
+ dlm_recover_master_reply
+ set_new_master
+ set_master_lkbs
+ set_lock_master
+*/
+
+/*
+ * Set the lock master for all LKBs in a lock queue
+ * If we are the new master of the rsb, we may have received new
+ * MSTCPY locks from other nodes already which we need to ignore
+ * when setting the new nodeid.
+ */
+
+static void set_lock_master(struct list_head *queue, int nodeid)
+{
+ struct dlm_lkb *lkb;
+
+ list_for_each_entry(lkb, queue, lkb_statequeue)
+ if (!(lkb->lkb_flags & DLM_IFL_MSTCPY))
+ lkb->lkb_nodeid = nodeid;
+}
+
+static void set_master_lkbs(struct dlm_rsb *r)
+{
+ set_lock_master(&r->res_grantqueue, r->res_nodeid);
+ set_lock_master(&r->res_convertqueue, r->res_nodeid);
+ set_lock_master(&r->res_waitqueue, r->res_nodeid);
+}
+
+/*
+ * Propogate the new master nodeid to locks
+ * The NEW_MASTER flag tells dlm_recover_locks() which rsb's to consider.
+ * The NEW_MASTER2 flag tells recover_lvb() and set_locks_purged() which
+ * rsb's to consider.
+ */
+
+static void set_new_master(struct dlm_rsb *r, int nodeid)
+{
+ lock_rsb(r);
+ r->res_nodeid = nodeid;
+ set_master_lkbs(r);
+ rsb_set_flag(r, RSB_NEW_MASTER);
+ rsb_set_flag(r, RSB_NEW_MASTER2);
+ unlock_rsb(r);
+}
+
+/*
+ * We do async lookups on rsb's that need new masters. The rsb's
+ * waiting for a lookup reply are kept on the recover_list.
+ */
+
+static int recover_master(struct dlm_rsb *r)
+{
+ struct dlm_ls *ls = r->res_ls;
+ int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();
+
+ dir_nodeid = dlm_dir_nodeid(r);
+
+ if (dir_nodeid == our_nodeid) {
+ error = dlm_dir_lookup(ls, our_nodeid, r->res_name,
+ r->res_length, &ret_nodeid);
+ if (error)
+ log_error(ls, "recover dir lookup error %d", error);
+
+ if (ret_nodeid == our_nodeid)
+ ret_nodeid = 0;
+ set_new_master(r, ret_nodeid);
+ } else {
+ recover_list_add(r);
+ error = dlm_send_rcom_lookup(r, dir_nodeid);
+ }
+
+ return error;
+}
+
+/*
+ * When not using a directory, most resource names will hash to a new static
+ * master nodeid and the resource will need to be remastered.
+ */
+
+static int recover_master_static(struct dlm_rsb *r)
+{
+ int master = dlm_dir_nodeid(r);
+
+ if (master == dlm_our_nodeid())
+ master = 0;
+
+ if (r->res_nodeid != master) {
+ if (is_master(r))
+ dlm_purge_mstcpy_locks(r);
+ set_new_master(r, master);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Go through local root resources and for each rsb which has a master which
+ * has departed, get the new master nodeid from the directory. The dir will
+ * assign mastery to the first node to look up the new master. That means
+ * we'll discover in this lookup if we're the new master of any rsb's.
+ *
+ * We fire off all the dir lookup requests individually and asynchronously to
+ * the correct dir node.
+ */
+
+int dlm_recover_masters(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r;
+ int error = 0, count = 0;
+
+ log_debug(ls, "dlm_recover_masters");
+
+ down_read(&ls->ls_root_sem);
+ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+ if (dlm_recovery_stopped(ls)) {
+ up_read(&ls->ls_root_sem);
+ error = -EINTR;
+ goto out;
+ }
+
+ if (dlm_no_directory(ls))
+ count += recover_master_static(r);
+ else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) {
+ recover_master(r);
+ count++;
+ }
+
+ schedule();
+ }
+ up_read(&ls->ls_root_sem);
+
+ log_debug(ls, "dlm_recover_masters %d resources", count);
+
+ error = dlm_wait_function(ls, &recover_list_empty);
+ out:
+ if (error)
+ recover_list_clear(ls);
+ return error;
+}
+
+int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+ struct dlm_rsb *r;
+ int nodeid;
+
+ r = recover_list_find(ls, rc->rc_id);
+ if (!r) {
+ log_error(ls, "dlm_recover_master_reply no id %llx",
+ (unsigned long long)rc->rc_id);
+ goto out;
+ }
+
+ nodeid = rc->rc_result;
+ if (nodeid == dlm_our_nodeid())
+ nodeid = 0;
+
+ set_new_master(r, nodeid);
+ recover_list_del(r);
+
+ if (recover_list_empty(ls))
+ wake_up(&ls->ls_wait_general);
+ out:
+ return 0;
+}
+
+
+/* Lock recovery: rebuild the process-copy locks we hold on a
+ remastered rsb on the new rsb master.
+
+ dlm_recover_locks
+ recover_locks
+ recover_locks_queue
+ dlm_send_rcom_lock -> receive_rcom_lock
+ dlm_recover_master_copy
+ receive_rcom_lock_reply <-
+ dlm_recover_process_copy
+*/
+
+
+/*
+ * keep a count of the number of lkb's we send to the new master; when we get
+ * an equal number of replies then recovery for the rsb is done
+ */
+
+static int recover_locks_queue(struct dlm_rsb *r, struct list_head *head)
+{
+ struct dlm_lkb *lkb;
+ int error = 0;
+
+ list_for_each_entry(lkb, head, lkb_statequeue) {
+ error = dlm_send_rcom_lock(r, lkb);
+ if (error)
+ break;
+ r->res_recover_locks_count++;
+ }
+
+ return error;
+}
+
+static int recover_locks(struct dlm_rsb *r)
+{
+ int error = 0;
+
+ lock_rsb(r);
+
+ DLM_ASSERT(!r->res_recover_locks_count, dlm_dump_rsb(r););
+
+ error = recover_locks_queue(r, &r->res_grantqueue);
+ if (error)
+ goto out;
+ error = recover_locks_queue(r, &r->res_convertqueue);
+ if (error)
+ goto out;
+ error = recover_locks_queue(r, &r->res_waitqueue);
+ if (error)
+ goto out;
+
+ if (r->res_recover_locks_count)
+ recover_list_add(r);
+ else
+ rsb_clear_flag(r, RSB_NEW_MASTER);
+ out:
+ unlock_rsb(r);
+ return error;
+}
+
+int dlm_recover_locks(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r;
+ int error, count = 0;
+
+ log_debug(ls, "dlm_recover_locks");
+
+ down_read(&ls->ls_root_sem);
+ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+ if (is_master(r)) {
+ rsb_clear_flag(r, RSB_NEW_MASTER);
+ continue;
+ }
+
+ if (!rsb_flag(r, RSB_NEW_MASTER))
+ continue;
+
+ if (dlm_recovery_stopped(ls)) {
+ error = -EINTR;
+ up_read(&ls->ls_root_sem);
+ goto out;
+ }
+
+ error = recover_locks(r);
+ if (error) {
+ up_read(&ls->ls_root_sem);
+ goto out;
+ }
+
+ count += r->res_recover_locks_count;
+ }
+ up_read(&ls->ls_root_sem);
+
+ log_debug(ls, "dlm_recover_locks %d locks", count);
+
+ error = dlm_wait_function(ls, &recover_list_empty);
+ out:
+ if (error)
+ recover_list_clear(ls);
+ else
+ dlm_set_recover_status(ls, DLM_RS_LOCKS);
+ return error;
+}
+
+void dlm_recovered_lock(struct dlm_rsb *r)
+{
+ DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_dump_rsb(r););
+
+ r->res_recover_locks_count--;
+ if (!r->res_recover_locks_count) {
+ rsb_clear_flag(r, RSB_NEW_MASTER);
+ recover_list_del(r);
+ }
+
+ if (recover_list_empty(r->res_ls))
+ wake_up(&r->res_ls->ls_wait_general);
+}
+
+/*
+ * The lvb needs to be recovered on all master rsb's. This includes setting
+ * the VALNOTVALID flag if necessary, and determining the correct lvb contents
+ * based on the lvb's of the locks held on the rsb.
+ *
+ * RSB_VALNOTVALID is set if there are only NL/CR locks on the rsb. If it
+ * was already set prior to recovery, it's not cleared, regardless of locks.
+ *
+ * The LVB contents are only considered for changing when this is a new master
+ * of the rsb (NEW_MASTER2). Then, the rsb's lvb is taken from any lkb with
+ * mode > CR. If no lkb's exist with mode above CR, the lvb contents are taken
+ * from the lkb with the largest lvb sequence number.
+ */
+
+static void recover_lvb(struct dlm_rsb *r)
+{
+ struct dlm_lkb *lkb, *high_lkb = NULL;
+ uint32_t high_seq = 0;
+ int lock_lvb_exists = 0;
+ int big_lock_exists = 0;
+ int lvblen = r->res_ls->ls_lvblen;
+
+ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+ continue;
+
+ lock_lvb_exists = 1;
+
+ if (lkb->lkb_grmode > DLM_LOCK_CR) {
+ big_lock_exists = 1;
+ goto setflag;
+ }
+
+ if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
+ high_lkb = lkb;
+ high_seq = lkb->lkb_lvbseq;
+ }
+ }
+
+ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+ if (!(lkb->lkb_exflags & DLM_LKF_VALBLK))
+ continue;
+
+ lock_lvb_exists = 1;
+
+ if (lkb->lkb_grmode > DLM_LOCK_CR) {
+ big_lock_exists = 1;
+ goto setflag;
+ }
+
+ if (((int)lkb->lkb_lvbseq - (int)high_seq) >= 0) {
+ high_lkb = lkb;
+ high_seq = lkb->lkb_lvbseq;
+ }
+ }
+
+ setflag:
+ if (!lock_lvb_exists)
+ goto out;
+
+ if (!big_lock_exists)
+ rsb_set_flag(r, RSB_VALNOTVALID);
+
+ /* don't mess with the lvb unless we're the new master */
+ if (!rsb_flag(r, RSB_NEW_MASTER2))
+ goto out;
+
+ if (!r->res_lvbptr) {
+ r->res_lvbptr = allocate_lvb(r->res_ls);
+ if (!r->res_lvbptr)
+ goto out;
+ }
+
+ if (big_lock_exists) {
+ r->res_lvbseq = lkb->lkb_lvbseq;
+ memcpy(r->res_lvbptr, lkb->lkb_lvbptr, lvblen);
+ } else if (high_lkb) {
+ r->res_lvbseq = high_lkb->lkb_lvbseq;
+ memcpy(r->res_lvbptr, high_lkb->lkb_lvbptr, lvblen);
+ } else {
+ r->res_lvbseq = 0;
+ memset(r->res_lvbptr, 0, lvblen);
+ }
+ out:
+ return;
+}
+
+/* All master rsb's flagged RECOVER_CONVERT need to be looked at. The locks
+ converting PR->CW or CW->PR need to have their lkb_grmode set. */
+
+static void recover_conversion(struct dlm_rsb *r)
+{
+ struct dlm_lkb *lkb;
+ int grmode = -1;
+
+ list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
+ if (lkb->lkb_grmode == DLM_LOCK_PR ||
+ lkb->lkb_grmode == DLM_LOCK_CW) {
+ grmode = lkb->lkb_grmode;
+ break;
+ }
+ }
+
+ list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
+ if (lkb->lkb_grmode != DLM_LOCK_IV)
+ continue;
+ if (grmode == -1)
+ lkb->lkb_grmode = lkb->lkb_rqmode;
+ else
+ lkb->lkb_grmode = grmode;
+ }
+}
+
+/* We've become the new master for this rsb and waiting/converting locks may
+ need to be granted in dlm_grant_after_purge() due to locks that may have
+ existed from a removed node. */
+
+static void set_locks_purged(struct dlm_rsb *r)
+{
+ if (!list_empty(&r->res_waitqueue) || !list_empty(&r->res_convertqueue))
+ rsb_set_flag(r, RSB_LOCKS_PURGED);
+}
+
+void dlm_recover_rsbs(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r;
+ int count = 0;
+
+ log_debug(ls, "dlm_recover_rsbs");
+
+ down_read(&ls->ls_root_sem);
+ list_for_each_entry(r, &ls->ls_root_list, res_root_list) {
+ lock_rsb(r);
+ if (is_master(r)) {
+ if (rsb_flag(r, RSB_RECOVER_CONVERT))
+ recover_conversion(r);
+ if (rsb_flag(r, RSB_NEW_MASTER2))
+ set_locks_purged(r);
+ recover_lvb(r);
+ count++;
+ }
+ rsb_clear_flag(r, RSB_RECOVER_CONVERT);
+ rsb_clear_flag(r, RSB_NEW_MASTER2);
+ unlock_rsb(r);
+ }
+ up_read(&ls->ls_root_sem);
+
+ log_debug(ls, "dlm_recover_rsbs %d rsbs", count);
+}
+
+/* Create a single list of all root rsb's to be used during recovery */
+
+int dlm_create_root_list(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r;
+ int i, error = 0;
+
+ down_write(&ls->ls_root_sem);
+ if (!list_empty(&ls->ls_root_list)) {
+ log_error(ls, "root list not empty");
+ error = -EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+ read_lock(&ls->ls_rsbtbl[i].lock);
+ list_for_each_entry(r, &ls->ls_rsbtbl[i].list, res_hashchain) {
+ list_add(&r->res_root_list, &ls->ls_root_list);
+ dlm_hold_rsb(r);
+ }
+ read_unlock(&ls->ls_rsbtbl[i].lock);
+ }
+ out:
+ up_write(&ls->ls_root_sem);
+ return error;
+}
+
+void dlm_release_root_list(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r, *safe;
+
+ down_write(&ls->ls_root_sem);
+ list_for_each_entry_safe(r, safe, &ls->ls_root_list, res_root_list) {
+ list_del_init(&r->res_root_list);
+ dlm_put_rsb(r);
+ }
+ up_write(&ls->ls_root_sem);
+}
+
+void dlm_clear_toss_list(struct dlm_ls *ls)
+{
+ struct dlm_rsb *r, *safe;
+ int i;
+
+ for (i = 0; i < ls->ls_rsbtbl_size; i++) {
+ write_lock(&ls->ls_rsbtbl[i].lock);
+ list_for_each_entry_safe(r, safe, &ls->ls_rsbtbl[i].toss,
+ res_hashchain) {
+ list_del(&r->res_hashchain);
+ free_rsb(r);
+ }
+ write_unlock(&ls->ls_rsbtbl[i].lock);
+ }
+}
+
diff --git a/fs/dlm/recover.h b/fs/dlm/recover.h
new file mode 100644
index 000000000000..ebd0363f1e08
--- /dev/null
+++ b/fs/dlm/recover.h
@@ -0,0 +1,34 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RECOVER_DOT_H__
+#define __RECOVER_DOT_H__
+
+int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls));
+uint32_t dlm_recover_status(struct dlm_ls *ls);
+void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status);
+int dlm_recover_members_wait(struct dlm_ls *ls);
+int dlm_recover_directory_wait(struct dlm_ls *ls);
+int dlm_recover_locks_wait(struct dlm_ls *ls);
+int dlm_recover_done_wait(struct dlm_ls *ls);
+int dlm_recover_masters(struct dlm_ls *ls);
+int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc);
+int dlm_recover_locks(struct dlm_ls *ls);
+void dlm_recovered_lock(struct dlm_rsb *r);
+int dlm_create_root_list(struct dlm_ls *ls);
+void dlm_release_root_list(struct dlm_ls *ls);
+void dlm_clear_toss_list(struct dlm_ls *ls);
+void dlm_recover_rsbs(struct dlm_ls *ls);
+
+#endif /* __RECOVER_DOT_H__ */
+
diff --git a/fs/dlm/recoverd.c b/fs/dlm/recoverd.c
new file mode 100644
index 000000000000..362e3eff4dc9
--- /dev/null
+++ b/fs/dlm/recoverd.c
@@ -0,0 +1,290 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "member.h"
+#include "dir.h"
+#include "ast.h"
+#include "recover.h"
+#include "lowcomms.h"
+#include "lock.h"
+#include "requestqueue.h"
+#include "recoverd.h"
+
+
+/* If the start for which we're re-enabling locking (seq) has been superseded
+ by a newer stop (ls_recover_seq), we need to leave locking disabled. */
+
+static int enable_locking(struct dlm_ls *ls, uint64_t seq)
+{
+ int error = -EINTR;
+
+ spin_lock(&ls->ls_recover_lock);
+ if (ls->ls_recover_seq == seq) {
+ set_bit(LSFL_RUNNING, &ls->ls_flags);
+ up_write(&ls->ls_in_recovery);
+ error = 0;
+ }
+ spin_unlock(&ls->ls_recover_lock);
+ return error;
+}
+
+static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
+{
+ unsigned long start;
+ int error, neg = 0;
+
+ log_debug(ls, "recover %llx", rv->seq);
+
+ mutex_lock(&ls->ls_recoverd_active);
+
+ /*
+ * Suspending and resuming dlm_astd ensures that no lkb's from this ls
+ * will be processed by dlm_astd during recovery.
+ */
+
+ dlm_astd_suspend();
+ dlm_astd_resume();
+
+ /*
+ * This list of root rsb's will be the basis of most of the recovery
+ * routines.
+ */
+
+ dlm_create_root_list(ls);
+
+ /*
+ * Free all the tossed rsb's so we don't have to recover them.
+ */
+
+ dlm_clear_toss_list(ls);
+
+ /*
+ * Add or remove nodes from the lockspace's ls_nodes list.
+ * Also waits for all nodes to complete dlm_recover_members.
+ */
+
+ error = dlm_recover_members(ls, rv, &neg);
+ if (error) {
+ log_error(ls, "recover_members failed %d", error);
+ goto fail;
+ }
+ start = jiffies;
+
+ /*
+ * Rebuild our own share of the directory by collecting from all other
+ * nodes their master rsb names that hash to us.
+ */
+
+ error = dlm_recover_directory(ls);
+ if (error) {
+ log_error(ls, "recover_directory failed %d", error);
+ goto fail;
+ }
+
+ /*
+ * Purge directory-related requests that are saved in requestqueue.
+ * All dir requests from before recovery are invalid now due to the dir
+ * rebuild and will be resent by the requesting nodes.
+ */
+
+ dlm_purge_requestqueue(ls);
+
+ /*
+ * Wait for all nodes to complete directory rebuild.
+ */
+
+ error = dlm_recover_directory_wait(ls);
+ if (error) {
+ log_error(ls, "recover_directory_wait failed %d", error);
+ goto fail;
+ }
+
+ /*
+ * We may have outstanding operations that are waiting for a reply from
+ * a failed node. Mark these to be resent after recovery. Unlock and
+ * cancel ops can just be completed.
+ */
+
+ dlm_recover_waiters_pre(ls);
+
+ error = dlm_recovery_stopped(ls);
+ if (error)
+ goto fail;
+
+ if (neg || dlm_no_directory(ls)) {
+ /*
+ * Clear lkb's for departed nodes.
+ */
+
+ dlm_purge_locks(ls);
+
+ /*
+ * Get new master nodeid's for rsb's that were mastered on
+ * departed nodes.
+ */
+
+ error = dlm_recover_masters(ls);
+ if (error) {
+ log_error(ls, "recover_masters failed %d", error);
+ goto fail;
+ }
+
+ /*
+ * Send our locks on remastered rsb's to the new masters.
+ */
+
+ error = dlm_recover_locks(ls);
+ if (error) {
+ log_error(ls, "recover_locks failed %d", error);
+ goto fail;
+ }
+
+ error = dlm_recover_locks_wait(ls);
+ if (error) {
+ log_error(ls, "recover_locks_wait failed %d", error);
+ goto fail;
+ }
+
+ /*
+ * Finalize state in master rsb's now that all locks can be
+ * checked. This includes conversion resolution and lvb
+ * settings.
+ */
+
+ dlm_recover_rsbs(ls);
+ }
+
+ dlm_release_root_list(ls);
+
+ dlm_set_recover_status(ls, DLM_RS_DONE);
+ error = dlm_recover_done_wait(ls);
+ if (error) {
+ log_error(ls, "recover_done_wait failed %d", error);
+ goto fail;
+ }
+
+ dlm_clear_members_gone(ls);
+
+ error = enable_locking(ls, rv->seq);
+ if (error) {
+ log_error(ls, "enable_locking failed %d", error);
+ goto fail;
+ }
+
+ error = dlm_process_requestqueue(ls);
+ if (error) {
+ log_error(ls, "process_requestqueue failed %d", error);
+ goto fail;
+ }
+
+ error = dlm_recover_waiters_post(ls);
+ if (error) {
+ log_error(ls, "recover_waiters_post failed %d", error);
+ goto fail;
+ }
+
+ dlm_grant_after_purge(ls);
+
+ dlm_astd_wake();
+
+ log_debug(ls, "recover %llx done: %u ms", rv->seq,
+ jiffies_to_msecs(jiffies - start));
+ mutex_unlock(&ls->ls_recoverd_active);
+
+ return 0;
+
+ fail:
+ dlm_release_root_list(ls);
+ log_debug(ls, "recover %llx error %d", rv->seq, error);
+ mutex_unlock(&ls->ls_recoverd_active);
+ return error;
+}
+
+static void do_ls_recovery(struct dlm_ls *ls)
+{
+ struct dlm_recover *rv = NULL;
+
+ spin_lock(&ls->ls_recover_lock);
+ rv = ls->ls_recover_args;
+ ls->ls_recover_args = NULL;
+ clear_bit(LSFL_RECOVERY_STOP, &ls->ls_flags);
+ spin_unlock(&ls->ls_recover_lock);
+
+ if (rv) {
+ ls_recover(ls, rv);
+ kfree(rv->nodeids);
+ kfree(rv);
+ }
+}
+
+static int dlm_recoverd(void *arg)
+{
+ struct dlm_ls *ls;
+
+ ls = dlm_find_lockspace_local(arg);
+ if (!ls) {
+ log_print("dlm_recoverd: no lockspace %p", arg);
+ return -1;
+ }
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!test_bit(LSFL_WORK, &ls->ls_flags))
+ schedule();
+ set_current_state(TASK_RUNNING);
+
+ if (test_and_clear_bit(LSFL_WORK, &ls->ls_flags))
+ do_ls_recovery(ls);
+ }
+
+ dlm_put_lockspace(ls);
+ return 0;
+}
+
+void dlm_recoverd_kick(struct dlm_ls *ls)
+{
+ set_bit(LSFL_WORK, &ls->ls_flags);
+ wake_up_process(ls->ls_recoverd_task);
+}
+
+int dlm_recoverd_start(struct dlm_ls *ls)
+{
+ struct task_struct *p;
+ int error = 0;
+
+ p = kthread_run(dlm_recoverd, ls, "dlm_recoverd");
+ if (IS_ERR(p))
+ error = PTR_ERR(p);
+ else
+ ls->ls_recoverd_task = p;
+ return error;
+}
+
+void dlm_recoverd_stop(struct dlm_ls *ls)
+{
+ kthread_stop(ls->ls_recoverd_task);
+}
+
+void dlm_recoverd_suspend(struct dlm_ls *ls)
+{
+ wake_up(&ls->ls_wait_general);
+ mutex_lock(&ls->ls_recoverd_active);
+}
+
+void dlm_recoverd_resume(struct dlm_ls *ls)
+{
+ mutex_unlock(&ls->ls_recoverd_active);
+}
+
diff --git a/fs/dlm/recoverd.h b/fs/dlm/recoverd.h
new file mode 100644
index 000000000000..866657c5d69d
--- /dev/null
+++ b/fs/dlm/recoverd.h
@@ -0,0 +1,24 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __RECOVERD_DOT_H__
+#define __RECOVERD_DOT_H__
+
+void dlm_recoverd_kick(struct dlm_ls *ls);
+void dlm_recoverd_stop(struct dlm_ls *ls);
+int dlm_recoverd_start(struct dlm_ls *ls);
+void dlm_recoverd_suspend(struct dlm_ls *ls);
+void dlm_recoverd_resume(struct dlm_ls *ls);
+
+#endif /* __RECOVERD_DOT_H__ */
+
diff --git a/fs/dlm/requestqueue.c b/fs/dlm/requestqueue.c
new file mode 100644
index 000000000000..7b2b089634a2
--- /dev/null
+++ b/fs/dlm/requestqueue.c
@@ -0,0 +1,184 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "member.h"
+#include "lock.h"
+#include "dir.h"
+#include "config.h"
+#include "requestqueue.h"
+
+struct rq_entry {
+ struct list_head list;
+ int nodeid;
+ char request[1];
+};
+
+/*
+ * Requests received while the lockspace is in recovery get added to the
+ * request queue and processed when recovery is complete. This happens when
+ * the lockspace is suspended on some nodes before it is on others, or the
+ * lockspace is enabled on some while still suspended on others.
+ */
+
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd)
+{
+ struct rq_entry *e;
+ int length = hd->h_length;
+
+ if (dlm_is_removed(ls, nodeid))
+ return;
+
+ e = kmalloc(sizeof(struct rq_entry) + length, GFP_KERNEL);
+ if (!e) {
+ log_print("dlm_add_requestqueue: out of memory\n");
+ return;
+ }
+
+ e->nodeid = nodeid;
+ memcpy(e->request, hd, length);
+
+ mutex_lock(&ls->ls_requestqueue_mutex);
+ list_add_tail(&e->list, &ls->ls_requestqueue);
+ mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
+int dlm_process_requestqueue(struct dlm_ls *ls)
+{
+ struct rq_entry *e;
+ struct dlm_header *hd;
+ int error = 0;
+
+ mutex_lock(&ls->ls_requestqueue_mutex);
+
+ for (;;) {
+ if (list_empty(&ls->ls_requestqueue)) {
+ mutex_unlock(&ls->ls_requestqueue_mutex);
+ error = 0;
+ break;
+ }
+ e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);
+ mutex_unlock(&ls->ls_requestqueue_mutex);
+
+ hd = (struct dlm_header *) e->request;
+ error = dlm_receive_message(hd, e->nodeid, 1);
+
+ if (error == -EINTR) {
+ /* entry is left on requestqueue */
+ log_debug(ls, "process_requestqueue abort eintr");
+ break;
+ }
+
+ mutex_lock(&ls->ls_requestqueue_mutex);
+ list_del(&e->list);
+ kfree(e);
+
+ if (dlm_locking_stopped(ls)) {
+ log_debug(ls, "process_requestqueue abort running");
+ mutex_unlock(&ls->ls_requestqueue_mutex);
+ error = -EINTR;
+ break;
+ }
+ schedule();
+ }
+
+ return error;
+}
+
+/*
+ * After recovery is done, locking is resumed and dlm_recoverd takes all the
+ * saved requests and processes them as they would have been by dlm_recvd. At
+ * the same time, dlm_recvd will start receiving new requests from remote
+ * nodes. We want to delay dlm_recvd processing new requests until
+ * dlm_recoverd has finished processing the old saved requests.
+ */
+
+void dlm_wait_requestqueue(struct dlm_ls *ls)
+{
+ for (;;) {
+ mutex_lock(&ls->ls_requestqueue_mutex);
+ if (list_empty(&ls->ls_requestqueue))
+ break;
+ if (dlm_locking_stopped(ls))
+ break;
+ mutex_unlock(&ls->ls_requestqueue_mutex);
+ schedule();
+ }
+ mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
+static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid)
+{
+ uint32_t type = ms->m_type;
+
+ if (dlm_is_removed(ls, nodeid))
+ return 1;
+
+ /* directory operations are always purged because the directory is
+ always rebuilt during recovery and the lookups resent */
+
+ if (type == DLM_MSG_REMOVE ||
+ type == DLM_MSG_LOOKUP ||
+ type == DLM_MSG_LOOKUP_REPLY)
+ return 1;
+
+ if (!dlm_no_directory(ls))
+ return 0;
+
+ /* with no directory, the master is likely to change as a part of
+ recovery; requests to/from the defunct master need to be purged */
+
+ switch (type) {
+ case DLM_MSG_REQUEST:
+ case DLM_MSG_CONVERT:
+ case DLM_MSG_UNLOCK:
+ case DLM_MSG_CANCEL:
+ /* we're no longer the master of this resource, the sender
+ will resend to the new master (see waiter_needs_recovery) */
+
+ if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())
+ return 1;
+ break;
+
+ case DLM_MSG_REQUEST_REPLY:
+ case DLM_MSG_CONVERT_REPLY:
+ case DLM_MSG_UNLOCK_REPLY:
+ case DLM_MSG_CANCEL_REPLY:
+ case DLM_MSG_GRANT:
+ /* this reply is from the former master of the resource,
+ we'll resend to the new master if needed */
+
+ if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)
+ return 1;
+ break;
+ }
+
+ return 0;
+}
+
+void dlm_purge_requestqueue(struct dlm_ls *ls)
+{
+ struct dlm_message *ms;
+ struct rq_entry *e, *safe;
+
+ mutex_lock(&ls->ls_requestqueue_mutex);
+ list_for_each_entry_safe(e, safe, &ls->ls_requestqueue, list) {
+ ms = (struct dlm_message *) e->request;
+
+ if (purge_request(ls, ms, e->nodeid)) {
+ list_del(&e->list);
+ kfree(e);
+ }
+ }
+ mutex_unlock(&ls->ls_requestqueue_mutex);
+}
+
diff --git a/fs/dlm/requestqueue.h b/fs/dlm/requestqueue.h
new file mode 100644
index 000000000000..349f0d292d95
--- /dev/null
+++ b/fs/dlm/requestqueue.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __REQUESTQUEUE_DOT_H__
+#define __REQUESTQUEUE_DOT_H__
+
+void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_header *hd);
+int dlm_process_requestqueue(struct dlm_ls *ls);
+void dlm_wait_requestqueue(struct dlm_ls *ls);
+void dlm_purge_requestqueue(struct dlm_ls *ls);
+
+#endif
+
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
new file mode 100644
index 000000000000..c37e93e4f2df
--- /dev/null
+++ b/fs/dlm/user.c
@@ -0,0 +1,788 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/dlm.h>
+#include <linux/dlm_device.h>
+
+#include "dlm_internal.h"
+#include "lockspace.h"
+#include "lock.h"
+#include "lvb_table.h"
+
+static const char *name_prefix="dlm";
+static struct miscdevice ctl_device;
+static struct file_operations device_fops;
+
+#ifdef CONFIG_COMPAT
+
+struct dlm_lock_params32 {
+ __u8 mode;
+ __u8 namelen;
+ __u16 flags;
+ __u32 lkid;
+ __u32 parent;
+
+ __u32 castparam;
+ __u32 castaddr;
+ __u32 bastparam;
+ __u32 bastaddr;
+ __u32 lksb;
+
+ char lvb[DLM_USER_LVB_LEN];
+ char name[0];
+};
+
+struct dlm_write_request32 {
+ __u32 version[3];
+ __u8 cmd;
+ __u8 is64bit;
+ __u8 unused[2];
+
+ union {
+ struct dlm_lock_params32 lock;
+ struct dlm_lspace_params lspace;
+ } i;
+};
+
+struct dlm_lksb32 {
+ __u32 sb_status;
+ __u32 sb_lkid;
+ __u8 sb_flags;
+ __u32 sb_lvbptr;
+};
+
+struct dlm_lock_result32 {
+ __u32 length;
+ __u32 user_astaddr;
+ __u32 user_astparam;
+ __u32 user_lksb;
+ struct dlm_lksb32 lksb;
+ __u8 bast_mode;
+ __u8 unused[3];
+ /* Offsets may be zero if no data is present */
+ __u32 lvb_offset;
+};
+
+static void compat_input(struct dlm_write_request *kb,
+ struct dlm_write_request32 *kb32)
+{
+ kb->version[0] = kb32->version[0];
+ kb->version[1] = kb32->version[1];
+ kb->version[2] = kb32->version[2];
+
+ kb->cmd = kb32->cmd;
+ kb->is64bit = kb32->is64bit;
+ if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||
+ kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {
+ kb->i.lspace.flags = kb32->i.lspace.flags;
+ kb->i.lspace.minor = kb32->i.lspace.minor;
+ strcpy(kb->i.lspace.name, kb32->i.lspace.name);
+ } else {
+ kb->i.lock.mode = kb32->i.lock.mode;
+ kb->i.lock.namelen = kb32->i.lock.namelen;
+ kb->i.lock.flags = kb32->i.lock.flags;
+ kb->i.lock.lkid = kb32->i.lock.lkid;
+ kb->i.lock.parent = kb32->i.lock.parent;
+ kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;
+ kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;
+ kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;
+ kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;
+ kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;
+ memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);
+ memcpy(kb->i.lock.name, kb32->i.lock.name, kb->i.lock.namelen);
+ }
+}
+
+static void compat_output(struct dlm_lock_result *res,
+ struct dlm_lock_result32 *res32)
+{
+ res32->length = res->length - (sizeof(struct dlm_lock_result) -
+ sizeof(struct dlm_lock_result32));
+ res32->user_astaddr = (__u32)(long)res->user_astaddr;
+ res32->user_astparam = (__u32)(long)res->user_astparam;
+ res32->user_lksb = (__u32)(long)res->user_lksb;
+ res32->bast_mode = res->bast_mode;
+
+ res32->lvb_offset = res->lvb_offset;
+ res32->length = res->length;
+
+ res32->lksb.sb_status = res->lksb.sb_status;
+ res32->lksb.sb_flags = res->lksb.sb_flags;
+ res32->lksb.sb_lkid = res->lksb.sb_lkid;
+ res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;
+}
+#endif
+
+
+void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
+{
+ struct dlm_ls *ls;
+ struct dlm_user_args *ua;
+ struct dlm_user_proc *proc;
+ int remove_ownqueue = 0;
+
+ /* dlm_clear_proc_locks() sets ORPHAN/DEAD flag on each
+ lkb before dealing with it. We need to check this
+ flag before taking ls_clear_proc_locks mutex because if
+ it's set, dlm_clear_proc_locks() holds the mutex. */
+
+ if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
+ /* log_print("user_add_ast skip1 %x", lkb->lkb_flags); */
+ return;
+ }
+
+ ls = lkb->lkb_resource->res_ls;
+ mutex_lock(&ls->ls_clear_proc_locks);
+
+ /* If ORPHAN/DEAD flag is set, it means the process is dead so an ast
+ can't be delivered. For ORPHAN's, dlm_clear_proc_locks() freed
+ lkb->ua so we can't try to use it. */
+
+ if (lkb->lkb_flags & (DLM_IFL_ORPHAN | DLM_IFL_DEAD)) {
+ /* log_print("user_add_ast skip2 %x", lkb->lkb_flags); */
+ goto out;
+ }
+
+ DLM_ASSERT(lkb->lkb_astparam, dlm_print_lkb(lkb););
+ ua = (struct dlm_user_args *)lkb->lkb_astparam;
+ proc = ua->proc;
+
+ if (type == AST_BAST && ua->bastaddr == NULL)
+ goto out;
+
+ spin_lock(&proc->asts_spin);
+ if (!(lkb->lkb_ast_type & (AST_COMP | AST_BAST))) {
+ kref_get(&lkb->lkb_ref);
+ list_add_tail(&lkb->lkb_astqueue, &proc->asts);
+ lkb->lkb_ast_type |= type;
+ wake_up_interruptible(&proc->wait);
+ }
+
+ /* noqueue requests that fail may need to be removed from the
+ proc's locks list, there should be a better way of detecting
+ this situation than checking all these things... */
+
+ if (type == AST_COMP && lkb->lkb_grmode == DLM_LOCK_IV &&
+ ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
+ remove_ownqueue = 1;
+
+ /* We want to copy the lvb to userspace when the completion
+ ast is read if the status is 0, the lock has an lvb and
+ lvb_ops says we should. We could probably have set_lvb_lock()
+ set update_user_lvb instead and not need old_mode */
+
+ if ((lkb->lkb_ast_type & AST_COMP) &&
+ (lkb->lkb_lksb->sb_status == 0) &&
+ lkb->lkb_lksb->sb_lvbptr &&
+ dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])
+ ua->update_user_lvb = 1;
+ else
+ ua->update_user_lvb = 0;
+
+ spin_unlock(&proc->asts_spin);
+
+ if (remove_ownqueue) {
+ spin_lock(&ua->proc->locks_spin);
+ list_del_init(&lkb->lkb_ownqueue);
+ spin_unlock(&ua->proc->locks_spin);
+ dlm_put_lkb(lkb);
+ }
+ out:
+ mutex_unlock(&ls->ls_clear_proc_locks);
+}
+
+static int device_user_lock(struct dlm_user_proc *proc,
+ struct dlm_lock_params *params)
+{
+ struct dlm_ls *ls;
+ struct dlm_user_args *ua;
+ int error = -ENOMEM;
+
+ ls = dlm_find_lockspace_local(proc->lockspace);
+ if (!ls)
+ return -ENOENT;
+
+ if (!params->castaddr || !params->lksb) {
+ error = -EINVAL;
+ goto out;
+ }
+
+ ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
+ if (!ua)
+ goto out;
+ ua->proc = proc;
+ ua->user_lksb = params->lksb;
+ ua->castparam = params->castparam;
+ ua->castaddr = params->castaddr;
+ ua->bastparam = params->bastparam;
+ ua->bastaddr = params->bastaddr;
+
+ if (params->flags & DLM_LKF_CONVERT)
+ error = dlm_user_convert(ls, ua,
+ params->mode, params->flags,
+ params->lkid, params->lvb);
+ else {
+ error = dlm_user_request(ls, ua,
+ params->mode, params->flags,
+ params->name, params->namelen,
+ params->parent);
+ if (!error)
+ error = ua->lksb.sb_lkid;
+ }
+ out:
+ dlm_put_lockspace(ls);
+ return error;
+}
+
+static int device_user_unlock(struct dlm_user_proc *proc,
+ struct dlm_lock_params *params)
+{
+ struct dlm_ls *ls;
+ struct dlm_user_args *ua;
+ int error = -ENOMEM;
+
+ ls = dlm_find_lockspace_local(proc->lockspace);
+ if (!ls)
+ return -ENOENT;
+
+ ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);
+ if (!ua)
+ goto out;
+ ua->proc = proc;
+ ua->user_lksb = params->lksb;
+ ua->castparam = params->castparam;
+ ua->castaddr = params->castaddr;
+
+ if (params->flags & DLM_LKF_CANCEL)
+ error = dlm_user_cancel(ls, ua, params->flags, params->lkid);
+ else
+ error = dlm_user_unlock(ls, ua, params->flags, params->lkid,
+ params->lvb);
+ out:
+ dlm_put_lockspace(ls);
+ return error;
+}
+
+static int device_create_lockspace(struct dlm_lspace_params *params)
+{
+ dlm_lockspace_t *lockspace;
+ struct dlm_ls *ls;
+ int error, len;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ error = dlm_new_lockspace(params->name, strlen(params->name),
+ &lockspace, 0, DLM_USER_LVB_LEN);
+ if (error)
+ return error;
+
+ ls = dlm_find_lockspace_local(lockspace);
+ if (!ls)
+ return -ENOENT;
+
+ error = -ENOMEM;
+ len = strlen(params->name) + strlen(name_prefix) + 2;
+ ls->ls_device.name = kzalloc(len, GFP_KERNEL);
+ if (!ls->ls_device.name)
+ goto fail;
+ snprintf((char *)ls->ls_device.name, len, "%s_%s", name_prefix,
+ params->name);
+ ls->ls_device.fops = &device_fops;
+ ls->ls_device.minor = MISC_DYNAMIC_MINOR;
+
+ error = misc_register(&ls->ls_device);
+ if (error) {
+ kfree(ls->ls_device.name);
+ goto fail;
+ }
+
+ error = ls->ls_device.minor;
+ dlm_put_lockspace(ls);
+ return error;
+
+ fail:
+ dlm_put_lockspace(ls);
+ dlm_release_lockspace(lockspace, 0);
+ return error;
+}
+
+static int device_remove_lockspace(struct dlm_lspace_params *params)
+{
+ dlm_lockspace_t *lockspace;
+ struct dlm_ls *ls;
+ int error, force = 0;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ls = dlm_find_lockspace_device(params->minor);
+ if (!ls)
+ return -ENOENT;
+
+ error = misc_deregister(&ls->ls_device);
+ if (error) {
+ dlm_put_lockspace(ls);
+ goto out;
+ }
+ kfree(ls->ls_device.name);
+
+ if (params->flags & DLM_USER_LSFLG_FORCEFREE)
+ force = 2;
+
+ lockspace = ls->ls_local_handle;
+
+ /* dlm_release_lockspace waits for references to go to zero,
+ so all processes will need to close their device for the ls
+ before the release will procede */
+
+ dlm_put_lockspace(ls);
+ error = dlm_release_lockspace(lockspace, force);
+ out:
+ return error;
+}
+
+/* Check the user's version matches ours */
+static int check_version(struct dlm_write_request *req)
+{
+ if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||
+ (req->version[0] == DLM_DEVICE_VERSION_MAJOR &&
+ req->version[1] > DLM_DEVICE_VERSION_MINOR)) {
+
+ printk(KERN_DEBUG "dlm: process %s (%d) version mismatch "
+ "user (%d.%d.%d) kernel (%d.%d.%d)\n",
+ current->comm,
+ current->pid,
+ req->version[0],
+ req->version[1],
+ req->version[2],
+ DLM_DEVICE_VERSION_MAJOR,
+ DLM_DEVICE_VERSION_MINOR,
+ DLM_DEVICE_VERSION_PATCH);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * device_write
+ *
+ * device_user_lock
+ * dlm_user_request -> request_lock
+ * dlm_user_convert -> convert_lock
+ *
+ * device_user_unlock
+ * dlm_user_unlock -> unlock_lock
+ * dlm_user_cancel -> cancel_lock
+ *
+ * device_create_lockspace
+ * dlm_new_lockspace
+ *
+ * device_remove_lockspace
+ * dlm_release_lockspace
+ */
+
+/* a write to a lockspace device is a lock or unlock request, a write
+ to the control device is to create/remove a lockspace */
+
+static ssize_t device_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct dlm_user_proc *proc = file->private_data;
+ struct dlm_write_request *kbuf;
+ sigset_t tmpsig, allsigs;
+ int error;
+
+#ifdef CONFIG_COMPAT
+ if (count < sizeof(struct dlm_write_request32))
+#else
+ if (count < sizeof(struct dlm_write_request))
+#endif
+ return -EINVAL;
+
+ kbuf = kmalloc(count, GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(kbuf, buf, count)) {
+ error = -EFAULT;
+ goto out_free;
+ }
+
+ if (check_version(kbuf)) {
+ error = -EBADE;
+ goto out_free;
+ }
+
+#ifdef CONFIG_COMPAT
+ if (!kbuf->is64bit) {
+ struct dlm_write_request32 *k32buf;
+ k32buf = (struct dlm_write_request32 *)kbuf;
+ kbuf = kmalloc(count + (sizeof(struct dlm_write_request) -
+ sizeof(struct dlm_write_request32)), GFP_KERNEL);
+ if (!kbuf)
+ return -ENOMEM;
+
+ if (proc)
+ set_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags);
+ compat_input(kbuf, k32buf);
+ kfree(k32buf);
+ }
+#endif
+
+ /* do we really need this? can a write happen after a close? */
+ if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &&
+ test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
+ return -EINVAL;
+
+ sigfillset(&allsigs);
+ sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
+
+ error = -EINVAL;
+
+ switch (kbuf->cmd)
+ {
+ case DLM_USER_LOCK:
+ if (!proc) {
+ log_print("no locking on control device");
+ goto out_sig;
+ }
+ error = device_user_lock(proc, &kbuf->i.lock);
+ break;
+
+ case DLM_USER_UNLOCK:
+ if (!proc) {
+ log_print("no locking on control device");
+ goto out_sig;
+ }
+ error = device_user_unlock(proc, &kbuf->i.lock);
+ break;
+
+ case DLM_USER_CREATE_LOCKSPACE:
+ if (proc) {
+ log_print("create/remove only on control device");
+ goto out_sig;
+ }
+ error = device_create_lockspace(&kbuf->i.lspace);
+ break;
+
+ case DLM_USER_REMOVE_LOCKSPACE:
+ if (proc) {
+ log_print("create/remove only on control device");
+ goto out_sig;
+ }
+ error = device_remove_lockspace(&kbuf->i.lspace);
+ break;
+
+ default:
+ log_print("Unknown command passed to DLM device : %d\n",
+ kbuf->cmd);
+ }
+
+ out_sig:
+ sigprocmask(SIG_SETMASK, &tmpsig, NULL);
+ recalc_sigpending();
+ out_free:
+ kfree(kbuf);
+ return error;
+}
+
+/* Every process that opens the lockspace device has its own "proc" structure
+ hanging off the open file that's used to keep track of locks owned by the
+ process and asts that need to be delivered to the process. */
+
+static int device_open(struct inode *inode, struct file *file)
+{
+ struct dlm_user_proc *proc;
+ struct dlm_ls *ls;
+
+ ls = dlm_find_lockspace_device(iminor(inode));
+ if (!ls)
+ return -ENOENT;
+
+ proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);
+ if (!proc) {
+ dlm_put_lockspace(ls);
+ return -ENOMEM;
+ }
+
+ proc->lockspace = ls->ls_local_handle;
+ INIT_LIST_HEAD(&proc->asts);
+ INIT_LIST_HEAD(&proc->locks);
+ spin_lock_init(&proc->asts_spin);
+ spin_lock_init(&proc->locks_spin);
+ init_waitqueue_head(&proc->wait);
+ file->private_data = proc;
+
+ return 0;
+}
+
+static int device_close(struct inode *inode, struct file *file)
+{
+ struct dlm_user_proc *proc = file->private_data;
+ struct dlm_ls *ls;
+ sigset_t tmpsig, allsigs;
+
+ ls = dlm_find_lockspace_local(proc->lockspace);
+ if (!ls)
+ return -ENOENT;
+
+ sigfillset(&allsigs);
+ sigprocmask(SIG_BLOCK, &allsigs, &tmpsig);
+
+ set_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags);
+
+ dlm_clear_proc_locks(ls, proc);
+
+ /* at this point no more lkb's should exist for this lockspace,
+ so there's no chance of dlm_user_add_ast() being called and
+ looking for lkb->ua->proc */
+
+ kfree(proc);
+ file->private_data = NULL;
+
+ dlm_put_lockspace(ls);
+ dlm_put_lockspace(ls); /* for the find in device_open() */
+
+ /* FIXME: AUTOFREE: if this ls is no longer used do
+ device_remove_lockspace() */
+
+ sigprocmask(SIG_SETMASK, &tmpsig, NULL);
+ recalc_sigpending();
+
+ return 0;
+}
+
+static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,
+ int bmode, char __user *buf, size_t count)
+{
+#ifdef CONFIG_COMPAT
+ struct dlm_lock_result32 result32;
+#endif
+ struct dlm_lock_result result;
+ void *resultptr;
+ int error=0;
+ int len;
+ int struct_len;
+
+ memset(&result, 0, sizeof(struct dlm_lock_result));
+ memcpy(&result.lksb, &ua->lksb, sizeof(struct dlm_lksb));
+ result.user_lksb = ua->user_lksb;
+
+ /* FIXME: dlm1 provides for the user's bastparam/addr to not be updated
+ in a conversion unless the conversion is successful. See code
+ in dlm_user_convert() for updating ua from ua_tmp. OpenVMS, though,
+ notes that a new blocking AST address and parameter are set even if
+ the conversion fails, so maybe we should just do that. */
+
+ if (type == AST_BAST) {
+ result.user_astaddr = ua->bastaddr;
+ result.user_astparam = ua->bastparam;
+ result.bast_mode = bmode;
+ } else {
+ result.user_astaddr = ua->castaddr;
+ result.user_astparam = ua->castparam;
+ }
+
+#ifdef CONFIG_COMPAT
+ if (compat)
+ len = sizeof(struct dlm_lock_result32);
+ else
+#endif
+ len = sizeof(struct dlm_lock_result);
+ struct_len = len;
+
+ /* copy lvb to userspace if there is one, it's been updated, and
+ the user buffer has space for it */
+
+ if (ua->update_user_lvb && ua->lksb.sb_lvbptr &&
+ count >= len + DLM_USER_LVB_LEN) {
+ if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,
+ DLM_USER_LVB_LEN)) {
+ error = -EFAULT;
+ goto out;
+ }
+
+ result.lvb_offset = len;
+ len += DLM_USER_LVB_LEN;
+ }
+
+ result.length = len;
+ resultptr = &result;
+#ifdef CONFIG_COMPAT
+ if (compat) {
+ compat_output(&result, &result32);
+ resultptr = &result32;
+ }
+#endif
+
+ if (copy_to_user(buf, resultptr, struct_len))
+ error = -EFAULT;
+ else
+ error = len;
+ out:
+ return error;
+}
+
+/* a read returns a single ast described in a struct dlm_lock_result */
+
+static ssize_t device_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct dlm_user_proc *proc = file->private_data;
+ struct dlm_lkb *lkb;
+ struct dlm_user_args *ua;
+ DECLARE_WAITQUEUE(wait, current);
+ int error, type=0, bmode=0, removed = 0;
+
+#ifdef CONFIG_COMPAT
+ if (count < sizeof(struct dlm_lock_result32))
+#else
+ if (count < sizeof(struct dlm_lock_result))
+#endif
+ return -EINVAL;
+
+ /* do we really need this? can a read happen after a close? */
+ if (test_bit(DLM_PROC_FLAGS_CLOSING, &proc->flags))
+ return -EINVAL;
+
+ spin_lock(&proc->asts_spin);
+ if (list_empty(&proc->asts)) {
+ if (file->f_flags & O_NONBLOCK) {
+ spin_unlock(&proc->asts_spin);
+ return -EAGAIN;
+ }
+
+ add_wait_queue(&proc->wait, &wait);
+
+ repeat:
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (list_empty(&proc->asts) && !signal_pending(current)) {
+ spin_unlock(&proc->asts_spin);
+ schedule();
+ spin_lock(&proc->asts_spin);
+ goto repeat;
+ }
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&proc->wait, &wait);
+
+ if (signal_pending(current)) {
+ spin_unlock(&proc->asts_spin);
+ return -ERESTARTSYS;
+ }
+ }
+
+ if (list_empty(&proc->asts)) {
+ spin_unlock(&proc->asts_spin);
+ return -EAGAIN;
+ }
+
+ /* there may be both completion and blocking asts to return for
+ the lkb, don't remove lkb from asts list unless no asts remain */
+
+ lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);
+
+ if (lkb->lkb_ast_type & AST_COMP) {
+ lkb->lkb_ast_type &= ~AST_COMP;
+ type = AST_COMP;
+ } else if (lkb->lkb_ast_type & AST_BAST) {
+ lkb->lkb_ast_type &= ~AST_BAST;
+ type = AST_BAST;
+ bmode = lkb->lkb_bastmode;
+ }
+
+ if (!lkb->lkb_ast_type) {
+ list_del(&lkb->lkb_astqueue);
+ removed = 1;
+ }
+ spin_unlock(&proc->asts_spin);
+
+ ua = (struct dlm_user_args *)lkb->lkb_astparam;
+ error = copy_result_to_user(ua,
+ test_bit(DLM_PROC_FLAGS_COMPAT, &proc->flags),
+ type, bmode, buf, count);
+
+ /* removes reference for the proc->asts lists added by
+ dlm_user_add_ast() and may result in the lkb being freed */
+ if (removed)
+ dlm_put_lkb(lkb);
+
+ return error;
+}
+
+static unsigned int device_poll(struct file *file, poll_table *wait)
+{
+ struct dlm_user_proc *proc = file->private_data;
+
+ poll_wait(file, &proc->wait, wait);
+
+ spin_lock(&proc->asts_spin);
+ if (!list_empty(&proc->asts)) {
+ spin_unlock(&proc->asts_spin);
+ return POLLIN | POLLRDNORM;
+ }
+ spin_unlock(&proc->asts_spin);
+ return 0;
+}
+
+static int ctl_device_open(struct inode *inode, struct file *file)
+{
+ file->private_data = NULL;
+ return 0;
+}
+
+static int ctl_device_close(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static struct file_operations device_fops = {
+ .open = device_open,
+ .release = device_close,
+ .read = device_read,
+ .write = device_write,
+ .poll = device_poll,
+ .owner = THIS_MODULE,
+};
+
+static struct file_operations ctl_device_fops = {
+ .open = ctl_device_open,
+ .release = ctl_device_close,
+ .write = device_write,
+ .owner = THIS_MODULE,
+};
+
+int dlm_user_init(void)
+{
+ int error;
+
+ ctl_device.name = "dlm-control";
+ ctl_device.fops = &ctl_device_fops;
+ ctl_device.minor = MISC_DYNAMIC_MINOR;
+
+ error = misc_register(&ctl_device);
+ if (error)
+ log_print("misc_register failed for control device");
+
+ return error;
+}
+
+void dlm_user_exit(void)
+{
+ misc_deregister(&ctl_device);
+}
+
diff --git a/fs/dlm/user.h b/fs/dlm/user.h
new file mode 100644
index 000000000000..d38e9f3e4151
--- /dev/null
+++ b/fs/dlm/user.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __USER_DOT_H__
+#define __USER_DOT_H__
+
+void dlm_user_add_ast(struct dlm_lkb *lkb, int type);
+int dlm_user_init(void);
+void dlm_user_exit(void);
+
+#endif
diff --git a/fs/dlm/util.c b/fs/dlm/util.c
new file mode 100644
index 000000000000..767197db9944
--- /dev/null
+++ b/fs/dlm/util.c
@@ -0,0 +1,161 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#include "dlm_internal.h"
+#include "rcom.h"
+#include "util.h"
+
+static void header_out(struct dlm_header *hd)
+{
+ hd->h_version = cpu_to_le32(hd->h_version);
+ hd->h_lockspace = cpu_to_le32(hd->h_lockspace);
+ hd->h_nodeid = cpu_to_le32(hd->h_nodeid);
+ hd->h_length = cpu_to_le16(hd->h_length);
+}
+
+static void header_in(struct dlm_header *hd)
+{
+ hd->h_version = le32_to_cpu(hd->h_version);
+ hd->h_lockspace = le32_to_cpu(hd->h_lockspace);
+ hd->h_nodeid = le32_to_cpu(hd->h_nodeid);
+ hd->h_length = le16_to_cpu(hd->h_length);
+}
+
+void dlm_message_out(struct dlm_message *ms)
+{
+ struct dlm_header *hd = (struct dlm_header *) ms;
+
+ header_out(hd);
+
+ ms->m_type = cpu_to_le32(ms->m_type);
+ ms->m_nodeid = cpu_to_le32(ms->m_nodeid);
+ ms->m_pid = cpu_to_le32(ms->m_pid);
+ ms->m_lkid = cpu_to_le32(ms->m_lkid);
+ ms->m_remid = cpu_to_le32(ms->m_remid);
+ ms->m_parent_lkid = cpu_to_le32(ms->m_parent_lkid);
+ ms->m_parent_remid = cpu_to_le32(ms->m_parent_remid);
+ ms->m_exflags = cpu_to_le32(ms->m_exflags);
+ ms->m_sbflags = cpu_to_le32(ms->m_sbflags);
+ ms->m_flags = cpu_to_le32(ms->m_flags);
+ ms->m_lvbseq = cpu_to_le32(ms->m_lvbseq);
+ ms->m_hash = cpu_to_le32(ms->m_hash);
+ ms->m_status = cpu_to_le32(ms->m_status);
+ ms->m_grmode = cpu_to_le32(ms->m_grmode);
+ ms->m_rqmode = cpu_to_le32(ms->m_rqmode);
+ ms->m_bastmode = cpu_to_le32(ms->m_bastmode);
+ ms->m_asts = cpu_to_le32(ms->m_asts);
+ ms->m_result = cpu_to_le32(ms->m_result);
+}
+
+void dlm_message_in(struct dlm_message *ms)
+{
+ struct dlm_header *hd = (struct dlm_header *) ms;
+
+ header_in(hd);
+
+ ms->m_type = le32_to_cpu(ms->m_type);
+ ms->m_nodeid = le32_to_cpu(ms->m_nodeid);
+ ms->m_pid = le32_to_cpu(ms->m_pid);
+ ms->m_lkid = le32_to_cpu(ms->m_lkid);
+ ms->m_remid = le32_to_cpu(ms->m_remid);
+ ms->m_parent_lkid = le32_to_cpu(ms->m_parent_lkid);
+ ms->m_parent_remid = le32_to_cpu(ms->m_parent_remid);
+ ms->m_exflags = le32_to_cpu(ms->m_exflags);
+ ms->m_sbflags = le32_to_cpu(ms->m_sbflags);
+ ms->m_flags = le32_to_cpu(ms->m_flags);
+ ms->m_lvbseq = le32_to_cpu(ms->m_lvbseq);
+ ms->m_hash = le32_to_cpu(ms->m_hash);
+ ms->m_status = le32_to_cpu(ms->m_status);
+ ms->m_grmode = le32_to_cpu(ms->m_grmode);
+ ms->m_rqmode = le32_to_cpu(ms->m_rqmode);
+ ms->m_bastmode = le32_to_cpu(ms->m_bastmode);
+ ms->m_asts = le32_to_cpu(ms->m_asts);
+ ms->m_result = le32_to_cpu(ms->m_result);
+}
+
+static void rcom_lock_out(struct rcom_lock *rl)
+{
+ rl->rl_ownpid = cpu_to_le32(rl->rl_ownpid);
+ rl->rl_lkid = cpu_to_le32(rl->rl_lkid);
+ rl->rl_remid = cpu_to_le32(rl->rl_remid);
+ rl->rl_parent_lkid = cpu_to_le32(rl->rl_parent_lkid);
+ rl->rl_parent_remid = cpu_to_le32(rl->rl_parent_remid);
+ rl->rl_exflags = cpu_to_le32(rl->rl_exflags);
+ rl->rl_flags = cpu_to_le32(rl->rl_flags);
+ rl->rl_lvbseq = cpu_to_le32(rl->rl_lvbseq);
+ rl->rl_result = cpu_to_le32(rl->rl_result);
+ rl->rl_wait_type = cpu_to_le16(rl->rl_wait_type);
+ rl->rl_namelen = cpu_to_le16(rl->rl_namelen);
+}
+
+static void rcom_lock_in(struct rcom_lock *rl)
+{
+ rl->rl_ownpid = le32_to_cpu(rl->rl_ownpid);
+ rl->rl_lkid = le32_to_cpu(rl->rl_lkid);
+ rl->rl_remid = le32_to_cpu(rl->rl_remid);
+ rl->rl_parent_lkid = le32_to_cpu(rl->rl_parent_lkid);
+ rl->rl_parent_remid = le32_to_cpu(rl->rl_parent_remid);
+ rl->rl_exflags = le32_to_cpu(rl->rl_exflags);
+ rl->rl_flags = le32_to_cpu(rl->rl_flags);
+ rl->rl_lvbseq = le32_to_cpu(rl->rl_lvbseq);
+ rl->rl_result = le32_to_cpu(rl->rl_result);
+ rl->rl_wait_type = le16_to_cpu(rl->rl_wait_type);
+ rl->rl_namelen = le16_to_cpu(rl->rl_namelen);
+}
+
+static void rcom_config_out(struct rcom_config *rf)
+{
+ rf->rf_lvblen = cpu_to_le32(rf->rf_lvblen);
+ rf->rf_lsflags = cpu_to_le32(rf->rf_lsflags);
+}
+
+static void rcom_config_in(struct rcom_config *rf)
+{
+ rf->rf_lvblen = le32_to_cpu(rf->rf_lvblen);
+ rf->rf_lsflags = le32_to_cpu(rf->rf_lsflags);
+}
+
+void dlm_rcom_out(struct dlm_rcom *rc)
+{
+ struct dlm_header *hd = (struct dlm_header *) rc;
+ int type = rc->rc_type;
+
+ header_out(hd);
+
+ rc->rc_type = cpu_to_le32(rc->rc_type);
+ rc->rc_result = cpu_to_le32(rc->rc_result);
+ rc->rc_id = cpu_to_le64(rc->rc_id);
+
+ if (type == DLM_RCOM_LOCK)
+ rcom_lock_out((struct rcom_lock *) rc->rc_buf);
+
+ else if (type == DLM_RCOM_STATUS_REPLY)
+ rcom_config_out((struct rcom_config *) rc->rc_buf);
+}
+
+void dlm_rcom_in(struct dlm_rcom *rc)
+{
+ struct dlm_header *hd = (struct dlm_header *) rc;
+
+ header_in(hd);
+
+ rc->rc_type = le32_to_cpu(rc->rc_type);
+ rc->rc_result = le32_to_cpu(rc->rc_result);
+ rc->rc_id = le64_to_cpu(rc->rc_id);
+
+ if (rc->rc_type == DLM_RCOM_LOCK)
+ rcom_lock_in((struct rcom_lock *) rc->rc_buf);
+
+ else if (rc->rc_type == DLM_RCOM_STATUS_REPLY)
+ rcom_config_in((struct rcom_config *) rc->rc_buf);
+}
+
diff --git a/fs/dlm/util.h b/fs/dlm/util.h
new file mode 100644
index 000000000000..2b25915161c0
--- /dev/null
+++ b/fs/dlm/util.h
@@ -0,0 +1,22 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __UTIL_DOT_H__
+#define __UTIL_DOT_H__
+
+void dlm_message_out(struct dlm_message *ms);
+void dlm_message_in(struct dlm_message *ms);
+void dlm_rcom_out(struct dlm_rcom *rc);
+void dlm_rcom_in(struct dlm_rcom *rc);
+
+#endif
+
diff --git a/fs/dnotify.c b/fs/dnotify.c
index f932591df5a4..2b0442db67e0 100644
--- a/fs/dnotify.c
+++ b/fs/dnotify.c
@@ -92,7 +92,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
prev = &odn->dn_next;
}
- error = f_setown(filp, current->pid, 0);
+ error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
if (error)
goto out_free;
diff --git a/fs/dquot.c b/fs/dquot.c
index 0122a279106a..9af789567e51 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -834,6 +834,9 @@ static void print_warning(struct dquot *dquot, const char warntype)
if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags)))
return;
+ mutex_lock(&tty_mutex);
+ if (!current->signal->tty)
+ goto out_lock;
tty_write_message(current->signal->tty, dquot->dq_sb->s_id);
if (warntype == ISOFTWARN || warntype == BSOFTWARN)
tty_write_message(current->signal->tty, ": warning, ");
@@ -861,6 +864,8 @@ static void print_warning(struct dquot *dquot, const char warntype)
break;
}
tty_write_message(current->signal->tty, msg);
+out_lock:
+ mutex_unlock(&tty_mutex);
}
static inline void flush_warnings(struct dquot **dquots, char *warntype)
diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
new file mode 100644
index 000000000000..ca6562451eeb
--- /dev/null
+++ b/fs/ecryptfs/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux 2.6 eCryptfs
+#
+
+obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
+
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o debug.o
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
new file mode 100644
index 000000000000..ed35a9712fa1
--- /dev/null
+++ b/fs/ecryptfs/crypto.c
@@ -0,0 +1,1659 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.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/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/random.h>
+#include <linux/compiler.h>
+#include <linux/key.h>
+#include <linux/namei.h>
+#include <linux/crypto.h>
+#include <linux/file.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+static int
+ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv);
+static int
+ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv);
+
+/**
+ * ecryptfs_to_hex
+ * @dst: Buffer to take hex character representation of contents of
+ * src; must be at least of size (src_size * 2)
+ * @src: Buffer to be converted to a hex string respresentation
+ * @src_size: number of bytes to convert
+ */
+void ecryptfs_to_hex(char *dst, char *src, size_t src_size)
+{
+ int x;
+
+ for (x = 0; x < src_size; x++)
+ sprintf(&dst[x * 2], "%.2x", (unsigned char)src[x]);
+}
+
+/**
+ * ecryptfs_from_hex
+ * @dst: Buffer to take the bytes from src hex; must be at least of
+ * size (src_size / 2)
+ * @src: Buffer to be converted from a hex string respresentation to raw value
+ * @dst_size: size of dst buffer, or number of hex characters pairs to convert
+ */
+void ecryptfs_from_hex(char *dst, char *src, int dst_size)
+{
+ int x;
+ char tmp[3] = { 0, };
+
+ for (x = 0; x < dst_size; x++) {
+ tmp[0] = src[x * 2];
+ tmp[1] = src[x * 2 + 1];
+ dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16);
+ }
+}
+
+/**
+ * ecryptfs_calculate_md5 - calculates the md5 of @src
+ * @dst: Pointer to 16 bytes of allocated memory
+ * @crypt_stat: Pointer to crypt_stat struct for the current inode
+ * @src: Data to be md5'd
+ * @len: Length of @src
+ *
+ * Uses the allocated crypto context that crypt_stat references to
+ * generate the MD5 sum of the contents of src.
+ */
+static int ecryptfs_calculate_md5(char *dst,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ char *src, int len)
+{
+ int rc = 0;
+ struct scatterlist sg;
+
+ mutex_lock(&crypt_stat->cs_md5_tfm_mutex);
+ sg_init_one(&sg, (u8 *)src, len);
+ if (!crypt_stat->md5_tfm) {
+ crypt_stat->md5_tfm =
+ crypto_alloc_tfm("md5", CRYPTO_TFM_REQ_MAY_SLEEP);
+ if (!crypt_stat->md5_tfm) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "allocate crypto context\n");
+ goto out;
+ }
+ }
+ crypto_digest_init(crypt_stat->md5_tfm);
+ crypto_digest_update(crypt_stat->md5_tfm, &sg, 1);
+ crypto_digest_final(crypt_stat->md5_tfm, dst);
+ mutex_unlock(&crypt_stat->cs_md5_tfm_mutex);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_derive_iv
+ * @iv: destination for the derived iv vale
+ * @crypt_stat: Pointer to crypt_stat struct for the current inode
+ * @offset: Offset of the page whose's iv we are to derive
+ *
+ * Generate the initialization vector from the given root IV and page
+ * offset.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
+ pgoff_t offset)
+{
+ int rc = 0;
+ char dst[MD5_DIGEST_SIZE];
+ char src[ECRYPTFS_MAX_IV_BYTES + 16];
+
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "root iv:\n");
+ ecryptfs_dump_hex(crypt_stat->root_iv, crypt_stat->iv_bytes);
+ }
+ /* TODO: It is probably secure to just cast the least
+ * significant bits of the root IV into an unsigned long and
+ * add the offset to that rather than go through all this
+ * hashing business. -Halcrow */
+ memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);
+ memset((src + crypt_stat->iv_bytes), 0, 16);
+ snprintf((src + crypt_stat->iv_bytes), 16, "%ld", offset);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "source:\n");
+ ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));
+ }
+ rc = ecryptfs_calculate_md5(dst, crypt_stat, src,
+ (crypt_stat->iv_bytes + 16));
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
+ "MD5 while generating IV for a page\n");
+ goto out;
+ }
+ memcpy(iv, dst, crypt_stat->iv_bytes);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "derived iv:\n");
+ ecryptfs_dump_hex(iv, crypt_stat->iv_bytes);
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_init_crypt_stat
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ *
+ * Initialize the crypt_stat structure.
+ */
+void
+ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
+ mutex_init(&crypt_stat->cs_mutex);
+ mutex_init(&crypt_stat->cs_tfm_mutex);
+ mutex_init(&crypt_stat->cs_md5_tfm_mutex);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_STRUCT_INITIALIZED);
+}
+
+/**
+ * ecryptfs_destruct_crypt_stat
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ *
+ * Releases all memory associated with a crypt_stat struct.
+ */
+void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ if (crypt_stat->tfm)
+ crypto_free_tfm(crypt_stat->tfm);
+ if (crypt_stat->md5_tfm)
+ crypto_free_tfm(crypt_stat->md5_tfm);
+ memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));
+}
+
+void ecryptfs_destruct_mount_crypt_stat(
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
+{
+ if (mount_crypt_stat->global_auth_tok_key)
+ key_put(mount_crypt_stat->global_auth_tok_key);
+ if (mount_crypt_stat->global_key_tfm)
+ crypto_free_tfm(mount_crypt_stat->global_key_tfm);
+ memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));
+}
+
+/**
+ * virt_to_scatterlist
+ * @addr: Virtual address
+ * @size: Size of data; should be an even multiple of the block size
+ * @sg: Pointer to scatterlist array; set to NULL to obtain only
+ * the number of scatterlist structs required in array
+ * @sg_size: Max array size
+ *
+ * Fills in a scatterlist array with page references for a passed
+ * virtual address.
+ *
+ * Returns the number of scatterlist structs in array used
+ */
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+ int sg_size)
+{
+ int i = 0;
+ struct page *pg;
+ int offset;
+ int remainder_of_page;
+
+ while (size > 0 && i < sg_size) {
+ pg = virt_to_page(addr);
+ offset = offset_in_page(addr);
+ if (sg) {
+ sg[i].page = pg;
+ sg[i].offset = offset;
+ }
+ remainder_of_page = PAGE_CACHE_SIZE - offset;
+ if (size >= remainder_of_page) {
+ if (sg)
+ sg[i].length = remainder_of_page;
+ addr += remainder_of_page;
+ size -= remainder_of_page;
+ } else {
+ if (sg)
+ sg[i].length = size;
+ addr += size;
+ size = 0;
+ }
+ i++;
+ }
+ if (size > 0)
+ return -ENOMEM;
+ return i;
+}
+
+/**
+ * encrypt_scatterlist
+ * @crypt_stat: Pointer to the crypt_stat struct to initialize.
+ * @dest_sg: Destination of encrypted data
+ * @src_sg: Data to be encrypted
+ * @size: Length of data to be encrypted
+ * @iv: iv to use during encryption
+ *
+ * Returns the number of bytes encrypted; negative value on error
+ */
+static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
+ struct scatterlist *dest_sg,
+ struct scatterlist *src_sg, int size,
+ unsigned char *iv)
+{
+ int rc = 0;
+
+ BUG_ON(!crypt_stat || !crypt_stat->tfm
+ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_STRUCT_INITIALIZED));
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n",
+ crypt_stat->key_size);
+ ecryptfs_dump_hex(crypt_stat->key,
+ crypt_stat->key_size);
+ }
+ /* Consider doing this once, when the file is opened */
+ mutex_lock(&crypt_stat->cs_tfm_mutex);
+ rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
+ crypt_stat->key_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
+ rc);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ rc = -EINVAL;
+ goto out;
+ }
+ ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes.\n", size);
+ crypto_cipher_encrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size, iv);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+out:
+ return rc;
+}
+
+static void
+ecryptfs_extent_to_lwr_pg_idx_and_offset(unsigned long *lower_page_idx,
+ int *byte_offset,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned long extent_num)
+{
+ unsigned long lower_extent_num;
+ int extents_occupied_by_headers_at_front;
+ int bytes_occupied_by_headers_at_front;
+ int extent_offset;
+ int extents_per_page;
+
+ bytes_occupied_by_headers_at_front =
+ ( crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front );
+ extents_occupied_by_headers_at_front =
+ ( bytes_occupied_by_headers_at_front
+ / crypt_stat->extent_size );
+ lower_extent_num = extents_occupied_by_headers_at_front + extent_num;
+ extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+ (*lower_page_idx) = lower_extent_num / extents_per_page;
+ extent_offset = lower_extent_num % extents_per_page;
+ (*byte_offset) = extent_offset * crypt_stat->extent_size;
+ ecryptfs_printk(KERN_DEBUG, " * crypt_stat->header_extent_size = "
+ "[%d]\n", crypt_stat->header_extent_size);
+ ecryptfs_printk(KERN_DEBUG, " * crypt_stat->"
+ "num_header_extents_at_front = [%d]\n",
+ crypt_stat->num_header_extents_at_front);
+ ecryptfs_printk(KERN_DEBUG, " * extents_occupied_by_headers_at_"
+ "front = [%d]\n", extents_occupied_by_headers_at_front);
+ ecryptfs_printk(KERN_DEBUG, " * lower_extent_num = [0x%.16x]\n",
+ lower_extent_num);
+ ecryptfs_printk(KERN_DEBUG, " * extents_per_page = [%d]\n",
+ extents_per_page);
+ ecryptfs_printk(KERN_DEBUG, " * (*lower_page_idx) = [0x%.16x]\n",
+ (*lower_page_idx));
+ ecryptfs_printk(KERN_DEBUG, " * extent_offset = [%d]\n",
+ extent_offset);
+ ecryptfs_printk(KERN_DEBUG, " * (*byte_offset) = [%d]\n",
+ (*byte_offset));
+}
+
+static int ecryptfs_write_out_page(struct ecryptfs_page_crypt_context *ctx,
+ struct page *lower_page,
+ struct inode *lower_inode,
+ int byte_offset_in_page, int bytes_to_write)
+{
+ int rc = 0;
+
+ if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
+ rc = ecryptfs_commit_lower_page(lower_page, lower_inode,
+ ctx->param.lower_file,
+ byte_offset_in_page,
+ bytes_to_write);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error calling lower "
+ "commit; rc = [%d]\n", rc);
+ goto out;
+ }
+ } else {
+ rc = ecryptfs_writepage_and_release_lower_page(lower_page,
+ lower_inode,
+ ctx->param.wbc);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error calling lower "
+ "writepage(); rc = [%d]\n", rc);
+ goto out;
+ }
+ }
+out:
+ return rc;
+}
+
+static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx,
+ struct page **lower_page,
+ struct inode *lower_inode,
+ unsigned long lower_page_idx,
+ int byte_offset_in_page)
+{
+ int rc = 0;
+
+ if (ctx->mode == ECRYPTFS_PREPARE_COMMIT_MODE) {
+ /* TODO: Limit this to only the data extents that are
+ * needed */
+ rc = ecryptfs_get_lower_page(lower_page, lower_inode,
+ ctx->param.lower_file,
+ lower_page_idx,
+ byte_offset_in_page,
+ (PAGE_CACHE_SIZE
+ - byte_offset_in_page));
+ if (rc) {
+ ecryptfs_printk(
+ KERN_ERR, "Error attempting to grab, map, "
+ "and prepare_write lower page with index "
+ "[0x%.16x]; rc = [%d]\n", lower_page_idx, rc);
+ goto out;
+ }
+ } else {
+ rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL,
+ lower_inode,
+ lower_page_idx);
+ if (rc) {
+ ecryptfs_printk(
+ KERN_ERR, "Error attempting to grab and map "
+ "lower page with index [0x%.16x]; rc = [%d]\n",
+ lower_page_idx, rc);
+ goto out;
+ }
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_encrypt_page
+ * @ctx: The context of the page
+ *
+ * Encrypt an eCryptfs page. This is done on a per-extent basis. Note
+ * that eCryptfs pages may straddle the lower pages -- for instance,
+ * if the file was created on a machine with an 8K page size
+ * (resulting in an 8K header), and then the file is copied onto a
+ * host with a 32K page size, then when reading page 0 of the eCryptfs
+ * file, 24K of page 0 of the lower file will be read and decrypted,
+ * and then 8K of page 1 of the lower file will be read and decrypted.
+ *
+ * The actual operations performed on each page depends on the
+ * contents of the ecryptfs_page_crypt_context struct.
+ *
+ * Returns zero on success; negative on error
+ */
+int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx)
+{
+ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+ unsigned long base_extent;
+ unsigned long extent_offset = 0;
+ unsigned long lower_page_idx = 0;
+ unsigned long prior_lower_page_idx = 0;
+ struct page *lower_page;
+ struct inode *lower_inode;
+ struct ecryptfs_inode_info *inode_info;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ int rc = 0;
+ int lower_byte_offset = 0;
+ int orig_byte_offset = 0;
+ int num_extents_per_page;
+#define ECRYPTFS_PAGE_STATE_UNREAD 0
+#define ECRYPTFS_PAGE_STATE_READ 1
+#define ECRYPTFS_PAGE_STATE_MODIFIED 2
+#define ECRYPTFS_PAGE_STATE_WRITTEN 3
+ int page_state;
+
+ lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host);
+ inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host);
+ crypt_stat = &inode_info->crypt_stat;
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
+ rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode,
+ ctx->param.lower_file);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error attempting to copy "
+ "page at index [0x%.16x]\n",
+ ctx->page->index);
+ goto out;
+ }
+ num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+ base_extent = (ctx->page->index * num_extents_per_page);
+ page_state = ECRYPTFS_PAGE_STATE_UNREAD;
+ while (extent_offset < num_extents_per_page) {
+ ecryptfs_extent_to_lwr_pg_idx_and_offset(
+ &lower_page_idx, &lower_byte_offset, crypt_stat,
+ (base_extent + extent_offset));
+ if (prior_lower_page_idx != lower_page_idx
+ && page_state == ECRYPTFS_PAGE_STATE_MODIFIED) {
+ rc = ecryptfs_write_out_page(ctx, lower_page,
+ lower_inode,
+ orig_byte_offset,
+ (PAGE_CACHE_SIZE
+ - orig_byte_offset));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting "
+ "to write out page; rc = [%d]"
+ "\n", rc);
+ goto out;
+ }
+ page_state = ECRYPTFS_PAGE_STATE_WRITTEN;
+ }
+ if (page_state == ECRYPTFS_PAGE_STATE_UNREAD
+ || page_state == ECRYPTFS_PAGE_STATE_WRITTEN) {
+ rc = ecryptfs_read_in_page(ctx, &lower_page,
+ lower_inode, lower_page_idx,
+ lower_byte_offset);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting "
+ "to read in lower page with "
+ "index [0x%.16x]; rc = [%d]\n",
+ lower_page_idx, rc);
+ goto out;
+ }
+ orig_byte_offset = lower_byte_offset;
+ prior_lower_page_idx = lower_page_idx;
+ page_state = ECRYPTFS_PAGE_STATE_READ;
+ }
+ BUG_ON(!(page_state == ECRYPTFS_PAGE_STATE_MODIFIED
+ || page_state == ECRYPTFS_PAGE_STATE_READ));
+ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+ (base_extent + extent_offset));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "derive IV for extent [0x%.16x]; "
+ "rc = [%d]\n",
+ (base_extent + extent_offset), rc);
+ goto out;
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Encrypting extent "
+ "with iv:\n");
+ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+ "encryption:\n");
+ ecryptfs_dump_hex((char *)
+ (page_address(ctx->page)
+ + (extent_offset
+ * crypt_stat->extent_size)), 8);
+ }
+ rc = ecryptfs_encrypt_page_offset(
+ crypt_stat, lower_page, lower_byte_offset, ctx->page,
+ (extent_offset * crypt_stat->extent_size),
+ crypt_stat->extent_size, extent_iv);
+ ecryptfs_printk(KERN_DEBUG, "Encrypt extent [0x%.16x]; "
+ "rc = [%d]\n",
+ (base_extent + extent_offset), rc);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+ "encryption:\n");
+ ecryptfs_dump_hex((char *)(page_address(lower_page)
+ + lower_byte_offset), 8);
+ }
+ page_state = ECRYPTFS_PAGE_STATE_MODIFIED;
+ extent_offset++;
+ }
+ BUG_ON(orig_byte_offset != 0);
+ rc = ecryptfs_write_out_page(ctx, lower_page, lower_inode, 0,
+ (lower_byte_offset
+ + crypt_stat->extent_size));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to write out "
+ "page; rc = [%d]\n", rc);
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_decrypt_page
+ * @file: The ecryptfs file
+ * @page: The page in ecryptfs to decrypt
+ *
+ * Decrypt an eCryptfs page. This is done on a per-extent basis. Note
+ * that eCryptfs pages may straddle the lower pages -- for instance,
+ * if the file was created on a machine with an 8K page size
+ * (resulting in an 8K header), and then the file is copied onto a
+ * host with a 32K page size, then when reading page 0 of the eCryptfs
+ * file, 24K of page 0 of the lower file will be read and decrypted,
+ * and then 8K of page 1 of the lower file will be read and decrypted.
+ *
+ * Returns zero on success; negative on error
+ */
+int ecryptfs_decrypt_page(struct file *file, struct page *page)
+{
+ char extent_iv[ECRYPTFS_MAX_IV_BYTES];
+ unsigned long base_extent;
+ unsigned long extent_offset = 0;
+ unsigned long lower_page_idx = 0;
+ unsigned long prior_lower_page_idx = 0;
+ struct page *lower_page;
+ char *lower_page_virt = NULL;
+ struct inode *lower_inode;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ int rc = 0;
+ int byte_offset;
+ int num_extents_per_page;
+ int page_state;
+
+ crypt_stat = &(ecryptfs_inode_to_private(
+ page->mapping->host)->crypt_stat);
+ lower_inode = ecryptfs_inode_to_lower(page->mapping->host);
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) {
+ rc = ecryptfs_do_readpage(file, page, page->index);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error attempting to copy "
+ "page at index [0x%.16x]\n",
+ page->index);
+ goto out;
+ }
+ num_extents_per_page = PAGE_CACHE_SIZE / crypt_stat->extent_size;
+ base_extent = (page->index * num_extents_per_page);
+ lower_page_virt = kmem_cache_alloc(ecryptfs_lower_page_cache,
+ SLAB_KERNEL);
+ if (!lower_page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error getting page for encrypted "
+ "lower page(s)\n");
+ goto out;
+ }
+ lower_page = virt_to_page(lower_page_virt);
+ page_state = ECRYPTFS_PAGE_STATE_UNREAD;
+ while (extent_offset < num_extents_per_page) {
+ ecryptfs_extent_to_lwr_pg_idx_and_offset(
+ &lower_page_idx, &byte_offset, crypt_stat,
+ (base_extent + extent_offset));
+ if (prior_lower_page_idx != lower_page_idx
+ || page_state == ECRYPTFS_PAGE_STATE_UNREAD) {
+ rc = ecryptfs_do_readpage(file, lower_page,
+ lower_page_idx);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error reading "
+ "lower encrypted page; rc = "
+ "[%d]\n", rc);
+ goto out;
+ }
+ prior_lower_page_idx = lower_page_idx;
+ page_state = ECRYPTFS_PAGE_STATE_READ;
+ }
+ rc = ecryptfs_derive_iv(extent_iv, crypt_stat,
+ (base_extent + extent_offset));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "derive IV for extent [0x%.16x]; rc = "
+ "[%d]\n",
+ (base_extent + extent_offset), rc);
+ goto out;
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Decrypting extent "
+ "with iv:\n");
+ ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes before "
+ "decryption:\n");
+ ecryptfs_dump_hex((lower_page_virt + byte_offset), 8);
+ }
+ rc = ecryptfs_decrypt_page_offset(crypt_stat, page,
+ (extent_offset
+ * crypt_stat->extent_size),
+ lower_page, byte_offset,
+ crypt_stat->extent_size,
+ extent_iv);
+ if (rc != crypt_stat->extent_size) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to "
+ "decrypt extent [0x%.16x]\n",
+ (base_extent + extent_offset));
+ goto out;
+ }
+ rc = 0;
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "First 8 bytes after "
+ "decryption:\n");
+ ecryptfs_dump_hex((char *)(page_address(page)
+ + byte_offset), 8);
+ }
+ extent_offset++;
+ }
+out:
+ if (lower_page_virt)
+ kmem_cache_free(ecryptfs_lower_page_cache, lower_page_virt);
+ return rc;
+}
+
+/**
+ * decrypt_scatterlist
+ *
+ * Returns the number of bytes decrypted; negative value on error
+ */
+static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,
+ struct scatterlist *dest_sg,
+ struct scatterlist *src_sg, int size,
+ unsigned char *iv)
+{
+ int rc = 0;
+
+ /* Consider doing this once, when the file is opened */
+ mutex_lock(&crypt_stat->cs_tfm_mutex);
+ rc = crypto_cipher_setkey(crypt_stat->tfm, crypt_stat->key,
+ crypt_stat->key_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error setting key; rc = [%d]\n",
+ rc);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ rc = -EINVAL;
+ goto out;
+ }
+ ecryptfs_printk(KERN_DEBUG, "Decrypting [%d] bytes.\n", size);
+ rc = crypto_cipher_decrypt_iv(crypt_stat->tfm, dest_sg, src_sg, size,
+ iv);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error decrypting; rc = [%d]\n",
+ rc);
+ goto out;
+ }
+ rc = size;
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_encrypt_page_offset
+ *
+ * Returns the number of bytes encrypted
+ */
+static int
+ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv)
+{
+ struct scatterlist src_sg, dst_sg;
+
+ src_sg.page = src_page;
+ src_sg.offset = src_offset;
+ src_sg.length = size;
+ dst_sg.page = dst_page;
+ dst_sg.offset = dst_offset;
+ dst_sg.length = size;
+ return encrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
+}
+
+/**
+ * ecryptfs_decrypt_page_offset
+ *
+ * Returns the number of bytes decrypted
+ */
+static int
+ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,
+ struct page *dst_page, int dst_offset,
+ struct page *src_page, int src_offset, int size,
+ unsigned char *iv)
+{
+ struct scatterlist src_sg, dst_sg;
+
+ src_sg.page = src_page;
+ src_sg.offset = src_offset;
+ src_sg.length = size;
+ dst_sg.page = dst_page;
+ dst_sg.offset = dst_offset;
+ dst_sg.length = size;
+ return decrypt_scatterlist(crypt_stat, &dst_sg, &src_sg, size, iv);
+}
+
+#define ECRYPTFS_MAX_SCATTERLIST_LEN 4
+
+/**
+ * ecryptfs_init_crypt_ctx
+ * @crypt_stat: Uninitilized crypt stats structure
+ *
+ * Initialize the crypto context.
+ *
+ * TODO: Performance: Keep a cache of initialized cipher contexts;
+ * only init if needed
+ */
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int rc = -EINVAL;
+
+ if (!crypt_stat->cipher) {
+ ecryptfs_printk(KERN_ERR, "No cipher specified\n");
+ goto out;
+ }
+ ecryptfs_printk(KERN_DEBUG,
+ "Initializing cipher [%s]; strlen = [%d]; "
+ "key_size_bits = [%d]\n",
+ crypt_stat->cipher, (int)strlen(crypt_stat->cipher),
+ crypt_stat->key_size << 3);
+ if (crypt_stat->tfm) {
+ rc = 0;
+ goto out;
+ }
+ mutex_lock(&crypt_stat->cs_tfm_mutex);
+ crypt_stat->tfm = crypto_alloc_tfm(crypt_stat->cipher,
+ ECRYPTFS_DEFAULT_CHAINING_MODE
+ | CRYPTO_TFM_REQ_WEAK_KEY);
+ mutex_unlock(&crypt_stat->cs_tfm_mutex);
+ if (!crypt_stat->tfm) {
+ ecryptfs_printk(KERN_ERR, "cryptfs: init_crypt_ctx(): "
+ "Error initializing cipher [%s]\n",
+ crypt_stat->cipher);
+ goto out;
+ }
+ rc = 0;
+out:
+ return rc;
+}
+
+static void set_extent_mask_and_shift(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int extent_size_tmp;
+
+ crypt_stat->extent_mask = 0xFFFFFFFF;
+ crypt_stat->extent_shift = 0;
+ if (crypt_stat->extent_size == 0)
+ return;
+ extent_size_tmp = crypt_stat->extent_size;
+ while ((extent_size_tmp & 0x01) == 0) {
+ extent_size_tmp >>= 1;
+ crypt_stat->extent_mask <<= 1;
+ crypt_stat->extent_shift++;
+ }
+}
+
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ /* Default values; may be overwritten as we are parsing the
+ * packets. */
+ crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;
+ set_extent_mask_and_shift(crypt_stat);
+ crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;
+ if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+ crypt_stat->header_extent_size =
+ ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;
+ } else
+ crypt_stat->header_extent_size = PAGE_CACHE_SIZE;
+ crypt_stat->num_header_extents_at_front = 1;
+}
+
+/**
+ * ecryptfs_compute_root_iv
+ * @crypt_stats
+ *
+ * On error, sets the root IV to all 0's.
+ */
+int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int rc = 0;
+ char dst[MD5_DIGEST_SIZE];
+
+ BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE);
+ BUG_ON(crypt_stat->iv_bytes <= 0);
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING, "Session key not valid; "
+ "cannot generate root IV\n");
+ goto out;
+ }
+ rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key,
+ crypt_stat->key_size);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error attempting to compute "
+ "MD5 while generating root IV\n");
+ goto out;
+ }
+ memcpy(crypt_stat->root_iv, dst, crypt_stat->iv_bytes);
+out:
+ if (rc) {
+ memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags,
+ ECRYPTFS_SECURITY_WARNING);
+ }
+ return rc;
+}
+
+static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ get_random_bytes(crypt_stat->key, crypt_stat->key_size);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ ecryptfs_compute_root_iv(crypt_stat);
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n");
+ ecryptfs_dump_hex(crypt_stat->key,
+ crypt_stat->key_size);
+ }
+}
+
+/**
+ * ecryptfs_set_default_crypt_stat_vals
+ * @crypt_stat
+ *
+ * Default values in the event that policy does not override them.
+ */
+static void ecryptfs_set_default_crypt_stat_vals(
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat)
+{
+ ecryptfs_set_default_sizes(crypt_stat);
+ strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER);
+ crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES;
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ crypt_stat->file_version = ECRYPTFS_FILE_VERSION;
+ crypt_stat->mount_crypt_stat = mount_crypt_stat;
+}
+
+/**
+ * ecryptfs_new_file_context
+ * @ecryptfs_dentry
+ *
+ * If the crypto context for the file has not yet been established,
+ * this is where we do that. Establishing a new crypto context
+ * involves the following decisions:
+ * - What cipher to use?
+ * - What set of authentication tokens to use?
+ * Here we just worry about getting enough information into the
+ * authentication tokens so that we know that they are available.
+ * We associate the available authentication tokens with the new file
+ * via the set of signatures in the crypt_stat struct. Later, when
+ * the headers are actually written out, we may again defer to
+ * userspace to perform the encryption of the session key; for the
+ * foreseeable future, this will be the case with public key packets.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+/* Associate an authentication token(s) with the file */
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry)
+{
+ int rc = 0;
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ int cipher_name_len;
+
+ ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat);
+ /* See if there are mount crypt options */
+ if (mount_crypt_stat->global_auth_tok) {
+ ecryptfs_printk(KERN_DEBUG, "Initializing context for new "
+ "file using mount_crypt_stat\n");
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++],
+ mount_crypt_stat->global_auth_tok_sig,
+ ECRYPTFS_SIG_SIZE_HEX);
+ cipher_name_len =
+ strlen(mount_crypt_stat->global_default_cipher_name);
+ memcpy(crypt_stat->cipher,
+ mount_crypt_stat->global_default_cipher_name,
+ cipher_name_len);
+ crypt_stat->cipher[cipher_name_len] = '\0';
+ crypt_stat->key_size =
+ mount_crypt_stat->global_default_cipher_key_size;
+ ecryptfs_generate_new_key(crypt_stat);
+ } else
+ /* We should not encounter this scenario since we
+ * should detect lack of global_auth_tok at mount time
+ * TODO: Applies to 0.1 release only; remove in future
+ * release */
+ BUG();
+ rc = ecryptfs_init_crypt_ctx(crypt_stat);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error initializing cryptographic "
+ "context for cipher [%s]: rc = [%d]\n",
+ crypt_stat->cipher, rc);
+ return rc;
+}
+
+/**
+ * contains_ecryptfs_marker - check for the ecryptfs marker
+ * @data: The data block in which to check
+ *
+ * Returns one if marker found; zero if not found
+ */
+int contains_ecryptfs_marker(char *data)
+{
+ u32 m_1, m_2;
+
+ memcpy(&m_1, data, 4);
+ m_1 = be32_to_cpu(m_1);
+ memcpy(&m_2, (data + 4), 4);
+ m_2 = be32_to_cpu(m_2);
+ if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2)
+ return 1;
+ ecryptfs_printk(KERN_DEBUG, "m_1 = [0x%.8x]; m_2 = [0x%.8x]; "
+ "MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n", m_1, m_2,
+ MAGIC_ECRYPTFS_MARKER);
+ ecryptfs_printk(KERN_DEBUG, "(m_1 ^ MAGIC_ECRYPTFS_MARKER) = "
+ "[0x%.8x]\n", (m_1 ^ MAGIC_ECRYPTFS_MARKER));
+ return 0;
+}
+
+struct ecryptfs_flag_map_elem {
+ u32 file_flag;
+ u32 local_flag;
+};
+
+/* Add support for additional flags by adding elements here. */
+static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = {
+ {0x00000001, ECRYPTFS_ENABLE_HMAC},
+ {0x00000002, ECRYPTFS_ENCRYPTED}
+};
+
+/**
+ * ecryptfs_process_flags
+ * @crypt_stat
+ * @page_virt: Source data to be parsed
+ * @bytes_read: Updated with the number of bytes read
+ *
+ * Returns zero on success; non-zero if the flag set is invalid
+ */
+static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat,
+ char *page_virt, int *bytes_read)
+{
+ int rc = 0;
+ int i;
+ u32 flags;
+
+ memcpy(&flags, page_virt, 4);
+ flags = be32_to_cpu(flags);
+ for (i = 0; i < ((sizeof(ecryptfs_flag_map)
+ / sizeof(struct ecryptfs_flag_map_elem))); i++)
+ if (flags & ecryptfs_flag_map[i].file_flag) {
+ ECRYPTFS_SET_FLAG(crypt_stat->flags,
+ ecryptfs_flag_map[i].local_flag);
+ } else
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
+ ecryptfs_flag_map[i].local_flag);
+ /* Version is in top 8 bits of the 32-bit flag vector */
+ crypt_stat->file_version = ((flags >> 24) & 0xFF);
+ (*bytes_read) = 4;
+ return rc;
+}
+
+/**
+ * write_ecryptfs_marker
+ * @page_virt: The pointer to in a page to begin writing the marker
+ * @written: Number of bytes written
+ *
+ * Marker = 0x3c81b7f5
+ */
+static void write_ecryptfs_marker(char *page_virt, size_t *written)
+{
+ u32 m_1, m_2;
+
+ get_random_bytes(&m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+ m_2 = (m_1 ^ MAGIC_ECRYPTFS_MARKER);
+ m_1 = cpu_to_be32(m_1);
+ memcpy(page_virt, &m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+ m_2 = cpu_to_be32(m_2);
+ memcpy(page_virt + (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2), &m_2,
+ (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));
+ (*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+}
+
+static void
+write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,
+ size_t *written)
+{
+ u32 flags = 0;
+ int i;
+
+ for (i = 0; i < ((sizeof(ecryptfs_flag_map)
+ / sizeof(struct ecryptfs_flag_map_elem))); i++)
+ if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ecryptfs_flag_map[i].local_flag))
+ flags |= ecryptfs_flag_map[i].file_flag;
+ /* Version is in top 8 bits of the 32-bit flag vector */
+ flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000);
+ flags = cpu_to_be32(flags);
+ memcpy(page_virt, &flags, 4);
+ (*written) = 4;
+}
+
+struct ecryptfs_cipher_code_str_map_elem {
+ char cipher_str[16];
+ u16 cipher_code;
+};
+
+/* Add support for additional ciphers by adding elements here. The
+ * cipher_code is whatever OpenPGP applicatoins use to identify the
+ * ciphers. List in order of probability. */
+static struct ecryptfs_cipher_code_str_map_elem
+ecryptfs_cipher_code_str_map[] = {
+ {"aes",RFC2440_CIPHER_AES_128 },
+ {"blowfish", RFC2440_CIPHER_BLOWFISH},
+ {"des3_ede", RFC2440_CIPHER_DES3_EDE},
+ {"cast5", RFC2440_CIPHER_CAST_5},
+ {"twofish", RFC2440_CIPHER_TWOFISH},
+ {"cast6", RFC2440_CIPHER_CAST_6},
+ {"aes", RFC2440_CIPHER_AES_192},
+ {"aes", RFC2440_CIPHER_AES_256}
+};
+
+/**
+ * ecryptfs_code_for_cipher_string
+ * @str: The string representing the cipher name
+ *
+ * Returns zero on no match, or the cipher code on match
+ */
+u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int i;
+ u16 code = 0;
+ struct ecryptfs_cipher_code_str_map_elem *map =
+ ecryptfs_cipher_code_str_map;
+
+ if (strcmp(crypt_stat->cipher, "aes") == 0) {
+ switch (crypt_stat->key_size) {
+ case 16:
+ code = RFC2440_CIPHER_AES_128;
+ break;
+ case 24:
+ code = RFC2440_CIPHER_AES_192;
+ break;
+ case 32:
+ code = RFC2440_CIPHER_AES_256;
+ }
+ } else {
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
+ if (strcmp(crypt_stat->cipher, map[i].cipher_str) == 0){
+ code = map[i].cipher_code;
+ break;
+ }
+ }
+ return code;
+}
+
+/**
+ * ecryptfs_cipher_code_to_string
+ * @str: Destination to write out the cipher name
+ * @cipher_code: The code to convert to cipher name string
+ *
+ * Returns zero on success
+ */
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code)
+{
+ int rc = 0;
+ int i;
+
+ str[0] = '\0';
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)
+ if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code)
+ strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str);
+ if (str[0] == '\0') {
+ ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: "
+ "[%d]\n", cipher_code);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+/**
+ * ecryptfs_read_header_region
+ * @data
+ * @dentry
+ * @nd
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+ struct vfsmount *mnt)
+{
+ struct file *file;
+ mm_segment_t oldfs;
+ int rc;
+
+ mnt = mntget(mnt);
+ file = dentry_open(dentry, mnt, O_RDONLY);
+ if (IS_ERR(file)) {
+ ecryptfs_printk(KERN_DEBUG, "Error opening file to "
+ "read header region\n");
+ mntput(mnt);
+ rc = PTR_ERR(file);
+ goto out;
+ }
+ file->f_pos = 0;
+ oldfs = get_fs();
+ set_fs(get_ds());
+ /* For releases 0.1 and 0.2, all of the header information
+ * fits in the first data extent-sized region. */
+ rc = file->f_op->read(file, (char __user *)data,
+ ECRYPTFS_DEFAULT_EXTENT_SIZE, &file->f_pos);
+ set_fs(oldfs);
+ fput(file);
+ rc = 0;
+out:
+ return rc;
+}
+
+static void
+write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat,
+ size_t *written)
+{
+ u32 header_extent_size;
+ u16 num_header_extents_at_front;
+
+ header_extent_size = (u32)crypt_stat->header_extent_size;
+ num_header_extents_at_front =
+ (u16)crypt_stat->num_header_extents_at_front;
+ header_extent_size = cpu_to_be32(header_extent_size);
+ memcpy(virt, &header_extent_size, 4);
+ virt += 4;
+ num_header_extents_at_front = cpu_to_be16(num_header_extents_at_front);
+ memcpy(virt, &num_header_extents_at_front, 2);
+ (*written) = 6;
+}
+
+struct kmem_cache *ecryptfs_header_cache_0;
+struct kmem_cache *ecryptfs_header_cache_1;
+struct kmem_cache *ecryptfs_header_cache_2;
+
+/**
+ * ecryptfs_write_headers_virt
+ * @page_virt
+ * @crypt_stat
+ * @ecryptfs_dentry
+ *
+ * Format version: 1
+ *
+ * Header Extent:
+ * Octets 0-7: Unencrypted file size (big-endian)
+ * Octets 8-15: eCryptfs special marker
+ * Octets 16-19: Flags
+ * Octet 16: File format version number (between 0 and 255)
+ * Octets 17-18: Reserved
+ * Octet 19: Bit 1 (lsb): Reserved
+ * Bit 2: Encrypted?
+ * Bits 3-8: Reserved
+ * Octets 20-23: Header extent size (big-endian)
+ * Octets 24-25: Number of header extents at front of file
+ * (big-endian)
+ * Octet 26: Begin RFC 2440 authentication token packet set
+ * Data Extent 0:
+ * Lower data (CBC encrypted)
+ * Data Extent 1:
+ * Lower data (CBC encrypted)
+ * ...
+ *
+ * Returns zero on success
+ */
+int ecryptfs_write_headers_virt(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry)
+{
+ int rc;
+ size_t written;
+ size_t offset;
+
+ offset = ECRYPTFS_FILE_SIZE_BYTES;
+ write_ecryptfs_marker((page_virt + offset), &written);
+ offset += written;
+ write_ecryptfs_flags((page_virt + offset), crypt_stat, &written);
+ offset += written;
+ write_header_metadata((page_virt + offset), crypt_stat, &written);
+ offset += written;
+ rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat,
+ ecryptfs_dentry, &written,
+ PAGE_CACHE_SIZE - offset);
+ if (rc)
+ ecryptfs_printk(KERN_WARNING, "Error generating key packet "
+ "set; rc = [%d]\n", rc);
+ return rc;
+}
+
+/**
+ * ecryptfs_write_headers
+ * @lower_file: The lower file struct, which was returned from dentry_open
+ *
+ * Write the file headers out. This will likely involve a userspace
+ * callout, in which the session key is encrypted with one or more
+ * public keys and/or the passphrase necessary to do the encryption is
+ * retrieved via a prompt. Exactly what happens at this point should
+ * be policy-dependent.
+ *
+ * Returns zero on success; non-zero on error
+ */
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file)
+{
+ mm_segment_t oldfs;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ char *page_virt;
+ int current_header_page;
+ int header_pages;
+ int rc = 0;
+
+ crypt_stat = &ecryptfs_inode_to_private(
+ ecryptfs_dentry->d_inode)->crypt_stat;
+ if (likely(ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_ENCRYPTED))) {
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_KEY_VALID)) {
+ ecryptfs_printk(KERN_DEBUG, "Key is "
+ "invalid; bailing out\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ } else {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING,
+ "Called with crypt_stat->encrypted == 0\n");
+ goto out;
+ }
+ /* Released in this function */
+ page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, SLAB_USER);
+ if (!page_virt) {
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ rc = ecryptfs_write_headers_virt(page_virt, crypt_stat,
+ ecryptfs_dentry);
+ if (unlikely(rc)) {
+ ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n");
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ goto out_free;
+ }
+ ecryptfs_printk(KERN_DEBUG,
+ "Writing key packet set to underlying file\n");
+ lower_file->f_pos = 0;
+ oldfs = get_fs();
+ set_fs(get_ds());
+ ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
+ "write() w/ header page; lower_file->f_pos = "
+ "[0x%.16x]\n", lower_file->f_pos);
+ lower_file->f_op->write(lower_file, (char __user *)page_virt,
+ PAGE_CACHE_SIZE, &lower_file->f_pos);
+ header_pages = ((crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front)
+ / PAGE_CACHE_SIZE);
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ current_header_page = 1;
+ while (current_header_page < header_pages) {
+ ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->"
+ "write() w/ zero'd page; lower_file->f_pos = "
+ "[0x%.16x]\n", lower_file->f_pos);
+ lower_file->f_op->write(lower_file, (char __user *)page_virt,
+ PAGE_CACHE_SIZE, &lower_file->f_pos);
+ current_header_page++;
+ }
+ set_fs(oldfs);
+ ecryptfs_printk(KERN_DEBUG,
+ "Done writing key packet set to underlying file.\n");
+out_free:
+ kmem_cache_free(ecryptfs_header_cache_0, page_virt);
+out:
+ return rc;
+}
+
+static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,
+ char *virt, int *bytes_read)
+{
+ int rc = 0;
+ u32 header_extent_size;
+ u16 num_header_extents_at_front;
+
+ memcpy(&header_extent_size, virt, 4);
+ header_extent_size = be32_to_cpu(header_extent_size);
+ virt += 4;
+ memcpy(&num_header_extents_at_front, virt, 2);
+ num_header_extents_at_front = be16_to_cpu(num_header_extents_at_front);
+ crypt_stat->header_extent_size = (int)header_extent_size;
+ crypt_stat->num_header_extents_at_front =
+ (int)num_header_extents_at_front;
+ (*bytes_read) = 6;
+ if ((crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front)
+ < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING, "Invalid header extent size: "
+ "[%d]\n", crypt_stat->header_extent_size);
+ }
+ return rc;
+}
+
+/**
+ * set_default_header_data
+ *
+ * For version 0 file format; this function is only for backwards
+ * compatibility for files created with the prior versions of
+ * eCryptfs.
+ */
+static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)
+{
+ crypt_stat->header_extent_size = 4096;
+ crypt_stat->num_header_extents_at_front = 1;
+}
+
+/**
+ * ecryptfs_read_headers_virt
+ *
+ * Read/parse the header data. The header format is detailed in the
+ * comment block for the ecryptfs_write_headers_virt() function.
+ *
+ * Returns zero on success
+ */
+static int ecryptfs_read_headers_virt(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry)
+{
+ int rc = 0;
+ int offset;
+ int bytes_read;
+
+ ecryptfs_set_default_sizes(crypt_stat);
+ crypt_stat->mount_crypt_stat = &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ offset = ECRYPTFS_FILE_SIZE_BYTES;
+ rc = contains_ecryptfs_marker(page_virt + offset);
+ if (rc == 0) {
+ rc = -EINVAL;
+ goto out;
+ }
+ offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;
+ rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),
+ &bytes_read);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error processing flags\n");
+ goto out;
+ }
+ if (crypt_stat->file_version > ECRYPTFS_SUPPORTED_FILE_VERSION) {
+ ecryptfs_printk(KERN_WARNING, "File version is [%d]; only "
+ "file version [%d] is supported by this "
+ "version of eCryptfs\n",
+ crypt_stat->file_version,
+ ECRYPTFS_SUPPORTED_FILE_VERSION);
+ rc = -EINVAL;
+ goto out;
+ }
+ offset += bytes_read;
+ if (crypt_stat->file_version >= 1) {
+ rc = parse_header_metadata(crypt_stat, (page_virt + offset),
+ &bytes_read);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error reading header "
+ "metadata; rc = [%d]\n", rc);
+ }
+ offset += bytes_read;
+ } else
+ set_default_header_data(crypt_stat);
+ rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset),
+ ecryptfs_dentry);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_read_headers
+ *
+ * Returns zero if valid headers found and parsed; non-zero otherwise
+ */
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file)
+{
+ int rc = 0;
+ char *page_virt = NULL;
+ mm_segment_t oldfs;
+ ssize_t bytes_read;
+ struct ecryptfs_crypt_stat *crypt_stat =
+ &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;
+
+ /* Read the first page from the underlying file */
+ page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, SLAB_USER);
+ if (!page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Unable to allocate page_virt\n");
+ goto out;
+ }
+ lower_file->f_pos = 0;
+ oldfs = get_fs();
+ set_fs(get_ds());
+ bytes_read = lower_file->f_op->read(lower_file,
+ (char __user *)page_virt,
+ ECRYPTFS_DEFAULT_EXTENT_SIZE,
+ &lower_file->f_pos);
+ set_fs(oldfs);
+ if (bytes_read != ECRYPTFS_DEFAULT_EXTENT_SIZE) {
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,
+ ecryptfs_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG, "Valid eCryptfs headers not "
+ "found\n");
+ rc = -EINVAL;
+ }
+out:
+ if (page_virt) {
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ kmem_cache_free(ecryptfs_header_cache_1, page_virt);
+ }
+ return rc;
+}
+
+/**
+ * ecryptfs_encode_filename - converts a plaintext file name to cipher text
+ * @crypt_stat: The crypt_stat struct associated with the file anem to encode
+ * @name: The plaintext name
+ * @length: The length of the plaintext
+ * @encoded_name: The encypted name
+ *
+ * Encrypts and encodes a filename into something that constitutes a
+ * valid filename for a filesystem, with printable characters.
+ *
+ * We assume that we have a properly initialized crypto context,
+ * pointed to by crypt_stat->tfm.
+ *
+ * TODO: Implement filename decoding and decryption here, in place of
+ * memcpy. We are keeping the framework around for now to (1)
+ * facilitate testing of the components needed to implement filename
+ * encryption and (2) to provide a code base from which other
+ * developers in the community can easily implement this feature.
+ *
+ * Returns the length of encoded filename; negative if error
+ */
+int
+ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length, char **encoded_name)
+{
+ int error = 0;
+
+ (*encoded_name) = kmalloc(length + 2, GFP_KERNEL);
+ if (!(*encoded_name)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ /* TODO: Filename encryption is a scheduled feature for a
+ * future version of eCryptfs. This function is here only for
+ * the purpose of providing a framework for other developers
+ * to easily implement filename encryption. Hint: Replace this
+ * memcpy() with a call to encrypt and encode the
+ * filename, the set the length accordingly. */
+ memcpy((void *)(*encoded_name), (void *)name, length);
+ (*encoded_name)[length] = '\0';
+ error = length + 1;
+out:
+ return error;
+}
+
+/**
+ * ecryptfs_decode_filename - converts the cipher text name to plaintext
+ * @crypt_stat: The crypt_stat struct associated with the file
+ * @name: The filename in cipher text
+ * @length: The length of the cipher text name
+ * @decrypted_name: The plaintext name
+ *
+ * Decodes and decrypts the filename.
+ *
+ * We assume that we have a properly initialized crypto context,
+ * pointed to by crypt_stat->tfm.
+ *
+ * TODO: Implement filename decoding and decryption here, in place of
+ * memcpy. We are keeping the framework around for now to (1)
+ * facilitate testing of the components needed to implement filename
+ * encryption and (2) to provide a code base from which other
+ * developers in the community can easily implement this feature.
+ *
+ * Returns the length of decoded filename; negative if error
+ */
+int
+ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length, char **decrypted_name)
+{
+ int error = 0;
+
+ (*decrypted_name) = kmalloc(length + 2, GFP_KERNEL);
+ if (!(*decrypted_name)) {
+ error = -ENOMEM;
+ goto out;
+ }
+ /* TODO: Filename encryption is a scheduled feature for a
+ * future version of eCryptfs. This function is here only for
+ * the purpose of providing a framework for other developers
+ * to easily implement filename encryption. Hint: Replace this
+ * memcpy() with a call to decode and decrypt the
+ * filename, the set the length accordingly. */
+ memcpy((void *)(*decrypted_name), (void *)name, length);
+ (*decrypted_name)[length + 1] = '\0'; /* Only for convenience
+ * in printing out the
+ * string in debug
+ * messages */
+ error = length;
+out:
+ return error;
+}
+
+/**
+ * ecryptfs_process_cipher - Perform cipher initialization.
+ * @tfm: Crypto context set by this function
+ * @key_tfm: Crypto context for key material, set by this function
+ * @cipher_name: Name of the cipher.
+ * @key_size: Size of the key in bytes.
+ *
+ * Returns zero on success. Any crypto_tfm structs allocated here
+ * should be released by other functions, such as on a superblock put
+ * event, regardless of whether this function succeeds for fails.
+ */
+int
+ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm,
+ char *cipher_name, size_t key_size)
+{
+ char dummy_key[ECRYPTFS_MAX_KEY_BYTES];
+ int rc;
+
+ *tfm = *key_tfm = NULL;
+ if (key_size > ECRYPTFS_MAX_KEY_BYTES) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Requested key size is [%Zd] bytes; maximum "
+ "allowable is [%d]\n", key_size, ECRYPTFS_MAX_KEY_BYTES);
+ goto out;
+ }
+ *tfm = crypto_alloc_tfm(cipher_name, (ECRYPTFS_DEFAULT_CHAINING_MODE
+ | CRYPTO_TFM_REQ_WEAK_KEY));
+ if (!(*tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Unable to allocate crypto cipher with name "
+ "[%s]\n", cipher_name);
+ goto out;
+ }
+ *key_tfm = crypto_alloc_tfm(cipher_name, CRYPTO_TFM_REQ_WEAK_KEY);
+ if (!(*key_tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Unable to allocate crypto cipher with name "
+ "[%s]\n", cipher_name);
+ goto out;
+ }
+ if (key_size < crypto_tfm_alg_min_keysize(*tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; minimum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*tfm));
+ goto out;
+ }
+ if (key_size < crypto_tfm_alg_min_keysize(*key_tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; minimum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*key_tfm));
+ goto out;
+ }
+ if (key_size > crypto_tfm_alg_max_keysize(*tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; maximum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*tfm));
+ goto out;
+ }
+ if (key_size > crypto_tfm_alg_max_keysize(*key_tfm)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "Request key size is [%Zd]; maximum key size "
+ "supported by cipher [%s] is [%d]\n", key_size,
+ cipher_name, crypto_tfm_alg_min_keysize(*key_tfm));
+ goto out;
+ }
+ get_random_bytes(dummy_key, key_size);
+ rc = crypto_cipher_setkey(*tfm, dummy_key, key_size);
+ if (rc) {
+ printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
+ "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = crypto_cipher_setkey(*key_tfm, dummy_key, key_size);
+ if (rc) {
+ printk(KERN_ERR "Error attempting to set key of size [%Zd] for "
+ "cipher [%s]; rc = [%d]\n", key_size, cipher_name, rc);
+ rc = -EINVAL;
+ goto out;
+ }
+out:
+ return rc;
+}
diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c
new file mode 100644
index 000000000000..61f8e894284f
--- /dev/null
+++ b/fs/ecryptfs/debug.c
@@ -0,0 +1,123 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * Functions only useful for debugging.
+ *
+ * Copyright (C) 2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.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 "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_dump_auth_tok - debug function to print auth toks
+ *
+ * This function will print the contents of an ecryptfs authentication
+ * token.
+ */
+void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok)
+{
+ char salt[ECRYPTFS_SALT_SIZE * 2 + 1];
+ char sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+
+ ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n",
+ auth_tok);
+ if (ECRYPTFS_CHECK_FLAG(auth_tok->flags, ECRYPTFS_PRIVATE_KEY)) {
+ ecryptfs_printk(KERN_DEBUG, " * private key type\n");
+ ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT "
+ "IN ECRYPTFS VERSION 0.1)\n");
+ } else {
+ ecryptfs_printk(KERN_DEBUG, " * passphrase type\n");
+ ecryptfs_to_hex(salt, auth_tok->token.password.salt,
+ ECRYPTFS_SALT_SIZE);
+ salt[ECRYPTFS_SALT_SIZE * 2] = '\0';
+ ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt);
+ if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
+ ECRYPTFS_PERSISTENT_PASSWORD)) {
+ ecryptfs_printk(KERN_DEBUG, " * persistent\n");
+ }
+ memcpy(sig, auth_tok->token.password.signature,
+ ECRYPTFS_SIG_SIZE_HEX);
+ sig[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+ ecryptfs_printk(KERN_DEBUG, " * signature = [%s]\n", sig);
+ }
+ ecryptfs_printk(KERN_DEBUG, " * session_key.flags = [0x%x]\n",
+ auth_tok->session_key.flags);
+ if (auth_tok->session_key.flags
+ & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT)
+ ecryptfs_printk(KERN_DEBUG,
+ " * Userspace decrypt request set\n");
+ if (auth_tok->session_key.flags
+ & ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT)
+ ecryptfs_printk(KERN_DEBUG,
+ " * Userspace encrypt request set\n");
+ if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_DECRYPTED_KEY) {
+ ecryptfs_printk(KERN_DEBUG, " * Contains decrypted key\n");
+ ecryptfs_printk(KERN_DEBUG,
+ " * session_key.decrypted_key_size = [0x%x]\n",
+ auth_tok->session_key.decrypted_key_size);
+ ecryptfs_printk(KERN_DEBUG, " * Decrypted session key "
+ "dump:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(auth_tok->session_key.decrypted_key,
+ ECRYPTFS_DEFAULT_KEY_BYTES);
+ }
+ if (auth_tok->session_key.flags & ECRYPTFS_CONTAINS_ENCRYPTED_KEY) {
+ ecryptfs_printk(KERN_DEBUG, " * Contains encrypted key\n");
+ ecryptfs_printk(KERN_DEBUG,
+ " * session_key.encrypted_key_size = [0x%x]\n",
+ auth_tok->session_key.encrypted_key_size);
+ ecryptfs_printk(KERN_DEBUG, " * Encrypted session key "
+ "dump:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.
+ encrypted_key_size);
+ }
+}
+
+/**
+ * ecryptfs_dump_hex - debug hex printer
+ * @data: string of bytes to be printed
+ * @bytes: number of bytes to print
+ *
+ * Dump hexadecimal representation of char array
+ */
+void ecryptfs_dump_hex(char *data, int bytes)
+{
+ int i = 0;
+ int add_newline = 1;
+
+ if (ecryptfs_verbosity < 1)
+ return;
+ if (bytes != 0) {
+ printk(KERN_DEBUG "0x%.2x.", (unsigned char)data[i]);
+ i++;
+ }
+ while (i < bytes) {
+ printk("0x%.2x.", (unsigned char)data[i]);
+ i++;
+ if (i % 16 == 0) {
+ printk("\n");
+ add_newline = 0;
+ } else
+ add_newline = 1;
+ }
+ if (add_newline)
+ printk("\n");
+}
+
diff --git a/fs/ecryptfs/dentry.c b/fs/ecryptfs/dentry.c
new file mode 100644
index 000000000000..f0d2a433242b
--- /dev/null
+++ b/fs/ecryptfs/dentry.c
@@ -0,0 +1,87 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.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/dcache.h>
+#include <linux/namei.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_d_revalidate - revalidate an ecryptfs dentry
+ * @dentry: The ecryptfs dentry
+ * @nd: The associated nameidata
+ *
+ * Called when the VFS needs to revalidate a dentry. This
+ * is called whenever a name lookup finds a dentry in the
+ * dcache. Most filesystems leave this as NULL, because all their
+ * dentries in the dcache are valid.
+ *
+ * Returns 1 if valid, 0 otherwise.
+ *
+ */
+static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+ struct dentry *dentry_save;
+ struct vfsmount *vfsmount_save;
+ int rc = 1;
+
+ if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
+ goto out;
+ dentry_save = nd->dentry;
+ vfsmount_save = nd->mnt;
+ nd->dentry = lower_dentry;
+ nd->mnt = lower_mnt;
+ rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
+ nd->dentry = dentry_save;
+ nd->mnt = vfsmount_save;
+out:
+ return rc;
+}
+
+struct kmem_cache *ecryptfs_dentry_info_cache;
+
+/**
+ * ecryptfs_d_release
+ * @dentry: The ecryptfs dentry
+ *
+ * Called when a dentry is really deallocated.
+ */
+static void ecryptfs_d_release(struct dentry *dentry)
+{
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (ecryptfs_dentry_to_private(dentry))
+ kmem_cache_free(ecryptfs_dentry_info_cache,
+ ecryptfs_dentry_to_private(dentry));
+ if (lower_dentry)
+ dput(lower_dentry);
+ return;
+}
+
+struct dentry_operations ecryptfs_dops = {
+ .d_revalidate = ecryptfs_d_revalidate,
+ .d_release = ecryptfs_d_release,
+};
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
new file mode 100644
index 000000000000..872c9958531a
--- /dev/null
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -0,0 +1,482 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * Kernel declarations.
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.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.
+ */
+
+#ifndef ECRYPTFS_KERNEL_H
+#define ECRYPTFS_KERNEL_H
+
+#include <keys/user-type.h>
+#include <linux/fs.h>
+#include <linux/scatterlist.h>
+
+/* Version verification for shared data structures w/ userspace */
+#define ECRYPTFS_VERSION_MAJOR 0x00
+#define ECRYPTFS_VERSION_MINOR 0x04
+#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x01
+/* These flags indicate which features are supported by the kernel
+ * module; userspace tools such as the mount helper read
+ * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine
+ * how to behave. */
+#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001
+#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002
+#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004
+#define ECRYPTFS_VERSIONING_POLICY 0x00000008
+#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
+ | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH)
+
+#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
+#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
+#define ECRYPTFS_SALT_SIZE 8
+#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)
+/* The original signature size is only for what is stored on disk; all
+ * in-memory representations are expanded hex, so it better adapted to
+ * be passed around or referenced on the command line */
+#define ECRYPTFS_SIG_SIZE 8
+#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)
+#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX
+#define ECRYPTFS_MAX_KEY_BYTES 64
+#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512
+#define ECRYPTFS_DEFAULT_IV_BYTES 16
+#define ECRYPTFS_FILE_VERSION 0x01
+#define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192
+#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096
+#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192
+
+#define RFC2440_CIPHER_DES3_EDE 0x02
+#define RFC2440_CIPHER_CAST_5 0x03
+#define RFC2440_CIPHER_BLOWFISH 0x04
+#define RFC2440_CIPHER_AES_128 0x07
+#define RFC2440_CIPHER_AES_192 0x08
+#define RFC2440_CIPHER_AES_256 0x09
+#define RFC2440_CIPHER_TWOFISH 0x0a
+#define RFC2440_CIPHER_CAST_6 0x0b
+
+#define ECRYPTFS_SET_FLAG(flag_bit_vector, flag) (flag_bit_vector |= (flag))
+#define ECRYPTFS_CLEAR_FLAG(flag_bit_vector, flag) (flag_bit_vector &= ~(flag))
+#define ECRYPTFS_CHECK_FLAG(flag_bit_vector, flag) (flag_bit_vector & (flag))
+
+/**
+ * For convenience, we may need to pass around the encrypted session
+ * key between kernel and userspace because the authentication token
+ * may not be extractable. For example, the TPM may not release the
+ * private key, instead requiring the encrypted data and returning the
+ * decrypted data.
+ */
+struct ecryptfs_session_key {
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0x00000001
+#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0x00000002
+#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0x00000004
+#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0x00000008
+ u32 flags;
+ u32 encrypted_key_size;
+ u32 decrypted_key_size;
+ u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+ u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];
+};
+
+struct ecryptfs_password {
+ u32 password_bytes;
+ s32 hash_algo;
+ u32 hash_iterations;
+ u32 session_key_encryption_key_bytes;
+#define ECRYPTFS_PERSISTENT_PASSWORD 0x01
+#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0x02
+ u32 flags;
+ /* Iterated-hash concatenation of salt and passphrase */
+ u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+ u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];
+ /* Always in expanded hex */
+ u8 salt[ECRYPTFS_SALT_SIZE];
+};
+
+enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};
+
+/* May be a password or a private key */
+struct ecryptfs_auth_tok {
+ u16 version; /* 8-bit major and 8-bit minor */
+ u16 token_type;
+ u32 flags;
+ struct ecryptfs_session_key session_key;
+ u8 reserved[32];
+ union {
+ struct ecryptfs_password password;
+ /* Private key is in future eCryptfs releases */
+ } token;
+} __attribute__ ((packed));
+
+void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);
+extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);
+extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);
+
+struct ecryptfs_key_record {
+ unsigned char type;
+ size_t enc_key_size;
+ unsigned char sig[ECRYPTFS_SIG_SIZE];
+ unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];
+};
+
+struct ecryptfs_auth_tok_list {
+ struct ecryptfs_auth_tok *auth_tok;
+ struct list_head list;
+};
+
+struct ecryptfs_crypt_stat;
+struct ecryptfs_mount_crypt_stat;
+
+struct ecryptfs_page_crypt_context {
+ struct page *page;
+#define ECRYPTFS_PREPARE_COMMIT_MODE 0
+#define ECRYPTFS_WRITEPAGE_MODE 1
+ unsigned int mode;
+ union {
+ struct file *lower_file;
+ struct writeback_control *wbc;
+ } param;
+};
+
+static inline struct ecryptfs_auth_tok *
+ecryptfs_get_key_payload_data(struct key *key)
+{
+ return (struct ecryptfs_auth_tok *)
+ (((struct user_key_payload*)key->payload.data)->data);
+}
+
+#define ECRYPTFS_SUPER_MAGIC 0xf15f
+#define ECRYPTFS_MAX_KEYSET_SIZE 1024
+#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32
+#define ECRYPTFS_MAX_NUM_ENC_KEYS 64
+#define ECRYPTFS_MAX_NUM_KEYSIGS 2 /* TODO: Make this a linked list */
+#define ECRYPTFS_MAX_IV_BYTES 16 /* 128 bits */
+#define ECRYPTFS_SALT_BYTES 2
+#define MAGIC_ECRYPTFS_MARKER 0x3c81b7f5
+#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8 /* 4*2 */
+#define ECRYPTFS_FILE_SIZE_BYTES 8
+#define ECRYPTFS_DEFAULT_CIPHER "aes"
+#define ECRYPTFS_DEFAULT_KEY_BYTES 16
+#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC
+#define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C
+#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED
+#define MD5_DIGEST_SIZE 16
+
+/**
+ * This is the primary struct associated with each encrypted file.
+ *
+ * TODO: cache align/pack?
+ */
+struct ecryptfs_crypt_stat {
+#define ECRYPTFS_STRUCT_INITIALIZED 0x00000001
+#define ECRYPTFS_POLICY_APPLIED 0x00000002
+#define ECRYPTFS_NEW_FILE 0x00000004
+#define ECRYPTFS_ENCRYPTED 0x00000008
+#define ECRYPTFS_SECURITY_WARNING 0x00000010
+#define ECRYPTFS_ENABLE_HMAC 0x00000020
+#define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000040
+#define ECRYPTFS_KEY_VALID 0x00000080
+ u32 flags;
+ unsigned int file_version;
+ size_t iv_bytes;
+ size_t num_keysigs;
+ size_t header_extent_size;
+ size_t num_header_extents_at_front;
+ size_t extent_size; /* Data extent size; default is 4096 */
+ size_t key_size;
+ size_t extent_shift;
+ unsigned int extent_mask;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+ struct crypto_tfm *tfm;
+ struct crypto_tfm *md5_tfm; /* Crypto context for generating
+ * the initialization vectors */
+ unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];
+ unsigned char key[ECRYPTFS_MAX_KEY_BYTES];
+ unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];
+ unsigned char keysigs[ECRYPTFS_MAX_NUM_KEYSIGS][ECRYPTFS_SIG_SIZE_HEX];
+ struct mutex cs_tfm_mutex;
+ struct mutex cs_md5_tfm_mutex;
+ struct mutex cs_mutex;
+};
+
+/* inode private data. */
+struct ecryptfs_inode_info {
+ struct inode vfs_inode;
+ struct inode *wii_inode;
+ struct ecryptfs_crypt_stat crypt_stat;
+};
+
+/* dentry private data. Each dentry must keep track of a lower
+ * vfsmount too. */
+struct ecryptfs_dentry_info {
+ struct dentry *wdi_dentry;
+ struct vfsmount *lower_mnt;
+ struct ecryptfs_crypt_stat *crypt_stat;
+};
+
+/**
+ * This struct is to enable a mount-wide passphrase/salt combo. This
+ * is more or less a stopgap to provide similar functionality to other
+ * crypto filesystems like EncFS or CFS until full policy support is
+ * implemented in eCryptfs.
+ */
+struct ecryptfs_mount_crypt_stat {
+ /* Pointers to memory we do not own, do not free these */
+#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001
+ u32 flags;
+ struct ecryptfs_auth_tok *global_auth_tok;
+ struct key *global_auth_tok_key;
+ size_t global_default_cipher_key_size;
+ struct crypto_tfm *global_key_tfm;
+ struct mutex global_key_tfm_mutex;
+ unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE
+ + 1];
+ unsigned char global_auth_tok_sig[ECRYPTFS_SIG_SIZE_HEX + 1];
+};
+
+/* superblock private data. */
+struct ecryptfs_sb_info {
+ struct super_block *wsi_sb;
+ struct ecryptfs_mount_crypt_stat mount_crypt_stat;
+};
+
+/* file private data. */
+struct ecryptfs_file_info {
+ struct file *wfi_file;
+ struct ecryptfs_crypt_stat *crypt_stat;
+};
+
+/* auth_tok <=> encrypted_session_key mappings */
+struct ecryptfs_auth_tok_list_item {
+ unsigned char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES];
+ struct list_head list;
+ struct ecryptfs_auth_tok auth_tok;
+};
+
+static inline struct ecryptfs_file_info *
+ecryptfs_file_to_private(struct file *file)
+{
+ return (struct ecryptfs_file_info *)file->private_data;
+}
+
+static inline void
+ecryptfs_set_file_private(struct file *file,
+ struct ecryptfs_file_info *file_info)
+{
+ file->private_data = file_info;
+}
+
+static inline struct file *ecryptfs_file_to_lower(struct file *file)
+{
+ return ((struct ecryptfs_file_info *)file->private_data)->wfi_file;
+}
+
+static inline void
+ecryptfs_set_file_lower(struct file *file, struct file *lower_file)
+{
+ ((struct ecryptfs_file_info *)file->private_data)->wfi_file =
+ lower_file;
+}
+
+static inline struct ecryptfs_inode_info *
+ecryptfs_inode_to_private(struct inode *inode)
+{
+ return container_of(inode, struct ecryptfs_inode_info, vfs_inode);
+}
+
+static inline struct inode *ecryptfs_inode_to_lower(struct inode *inode)
+{
+ return ecryptfs_inode_to_private(inode)->wii_inode;
+}
+
+static inline void
+ecryptfs_set_inode_lower(struct inode *inode, struct inode *lower_inode)
+{
+ ecryptfs_inode_to_private(inode)->wii_inode = lower_inode;
+}
+
+static inline struct ecryptfs_sb_info *
+ecryptfs_superblock_to_private(struct super_block *sb)
+{
+ return (struct ecryptfs_sb_info *)sb->s_fs_info;
+}
+
+static inline void
+ecryptfs_set_superblock_private(struct super_block *sb,
+ struct ecryptfs_sb_info *sb_info)
+{
+ sb->s_fs_info = sb_info;
+}
+
+static inline struct super_block *
+ecryptfs_superblock_to_lower(struct super_block *sb)
+{
+ return ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb;
+}
+
+static inline void
+ecryptfs_set_superblock_lower(struct super_block *sb,
+ struct super_block *lower_sb)
+{
+ ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb = lower_sb;
+}
+
+static inline struct ecryptfs_dentry_info *
+ecryptfs_dentry_to_private(struct dentry *dentry)
+{
+ return (struct ecryptfs_dentry_info *)dentry->d_fsdata;
+}
+
+static inline void
+ecryptfs_set_dentry_private(struct dentry *dentry,
+ struct ecryptfs_dentry_info *dentry_info)
+{
+ dentry->d_fsdata = dentry_info;
+}
+
+static inline struct dentry *
+ecryptfs_dentry_to_lower(struct dentry *dentry)
+{
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry;
+}
+
+static inline void
+ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)
+{
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->wdi_dentry =
+ lower_dentry;
+}
+
+static inline struct vfsmount *
+ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)
+{
+ return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt;
+}
+
+static inline void
+ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
+{
+ ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_mnt =
+ lower_mnt;
+}
+
+#define ecryptfs_printk(type, fmt, arg...) \
+ __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
+void __ecryptfs_printk(const char *fmt, ...);
+
+extern const struct file_operations ecryptfs_main_fops;
+extern const struct file_operations ecryptfs_dir_fops;
+extern struct inode_operations ecryptfs_main_iops;
+extern struct inode_operations ecryptfs_dir_iops;
+extern struct inode_operations ecryptfs_symlink_iops;
+extern struct super_operations ecryptfs_sops;
+extern struct dentry_operations ecryptfs_dops;
+extern struct address_space_operations ecryptfs_aops;
+extern int ecryptfs_verbosity;
+
+extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
+extern struct kmem_cache *ecryptfs_file_info_cache;
+extern struct kmem_cache *ecryptfs_dentry_info_cache;
+extern struct kmem_cache *ecryptfs_inode_info_cache;
+extern struct kmem_cache *ecryptfs_sb_info_cache;
+extern struct kmem_cache *ecryptfs_header_cache_0;
+extern struct kmem_cache *ecryptfs_header_cache_1;
+extern struct kmem_cache *ecryptfs_header_cache_2;
+extern struct kmem_cache *ecryptfs_lower_page_cache;
+
+int ecryptfs_interpose(struct dentry *hidden_dentry,
+ struct dentry *this_dentry, struct super_block *sb,
+ int flag);
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length);
+int ecryptfs_decode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length,
+ char **decrypted_name);
+int ecryptfs_encode_filename(struct ecryptfs_crypt_stat *crypt_stat,
+ const char *name, int length,
+ char **encoded_name);
+struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src);
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src);
+void ecryptfs_dump_hex(char *data, int bytes);
+int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,
+ int sg_size);
+int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_rotate_iv(unsigned char *iv);
+void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_destruct_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);
+void ecryptfs_destruct_mount_crypt_stat(
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat);
+int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_write_inode_size_to_header(struct file *lower_file,
+ struct inode *lower_inode,
+ struct inode *inode);
+int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
+ struct file *lower_file,
+ unsigned long lower_page_index, int byte_offset,
+ int region_bytes);
+int
+ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
+ struct file *lower_file, int byte_offset,
+ int region_size);
+int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
+ struct file *lower_file);
+int ecryptfs_do_readpage(struct file *file, struct page *page,
+ pgoff_t lower_page_index);
+int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
+ char **lower_virt,
+ struct inode *lower_inode,
+ unsigned long lower_page_index);
+int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
+ struct inode *lower_inode,
+ struct writeback_control *wbc);
+int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx);
+int ecryptfs_decrypt_page(struct file *file, struct page *page);
+int ecryptfs_write_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file);
+int ecryptfs_write_headers_virt(char *page_virt,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry);
+int ecryptfs_read_headers(struct dentry *ecryptfs_dentry,
+ struct file *lower_file);
+int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);
+int contains_ecryptfs_marker(char *data);
+int ecryptfs_read_header_region(char *data, struct dentry *dentry,
+ struct vfsmount *mnt);
+u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code);
+void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);
+int ecryptfs_generate_key_packet_set(char *dest_base,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry,
+ size_t *len, size_t max);
+int process_request_key_err(long err_code);
+int
+ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned char *src, struct dentry *ecryptfs_dentry);
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);
+int
+ecryptfs_process_cipher(struct crypto_tfm **tfm, struct crypto_tfm **key_tfm,
+ char *cipher_name, size_t key_size);
+int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);
+int ecryptfs_inode_set(struct inode *inode, void *lower_inode);
+void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);
+
+#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
new file mode 100644
index 000000000000..c8550c9f9cd2
--- /dev/null
+++ b/fs/ecryptfs/file.c
@@ -0,0 +1,440 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.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/file.h>
+#include <linux/poll.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/security.h>
+#include <linux/smp_lock.h>
+#include <linux/compat.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * ecryptfs_llseek
+ * @file: File we are seeking in
+ * @offset: The offset to seek to
+ * @origin: 2 - offset from i_size; 1 - offset from f_pos
+ *
+ * Returns the position we have seeked to, or negative on error
+ */
+static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin)
+{
+ loff_t rv;
+ loff_t new_end_pos;
+ int rc;
+ int expanding_file = 0;
+ struct inode *inode = file->f_mapping->host;
+
+ /* If our offset is past the end of our file, we're going to
+ * need to grow it so we have a valid length of 0's */
+ new_end_pos = offset;
+ switch (origin) {
+ case 2:
+ new_end_pos += i_size_read(inode);
+ expanding_file = 1;
+ break;
+ case 1:
+ new_end_pos += file->f_pos;
+ if (new_end_pos > i_size_read(inode)) {
+ ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
+ "> i_size_read(inode)(=[0x%.16x])\n",
+ new_end_pos, i_size_read(inode));
+ expanding_file = 1;
+ }
+ break;
+ default:
+ if (new_end_pos > i_size_read(inode)) {
+ ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) "
+ "> i_size_read(inode)(=[0x%.16x])\n",
+ new_end_pos, i_size_read(inode));
+ expanding_file = 1;
+ }
+ }
+ ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos);
+ if (expanding_file) {
+ rc = ecryptfs_truncate(file->f_dentry, new_end_pos);
+ if (rc) {
+ rv = rc;
+ ecryptfs_printk(KERN_ERR, "Error on attempt to "
+ "truncate to (higher) offset [0x%.16x];"
+ " rc = [%d]\n", new_end_pos, rc);
+ goto out;
+ }
+ }
+ rv = generic_file_llseek(file, offset, origin);
+out:
+ return rv;
+}
+
+/**
+ * ecryptfs_read_update_atime
+ *
+ * generic_file_read updates the atime of upper layer inode. But, it
+ * doesn't give us a chance to update the atime of the lower layer
+ * inode. This function is a wrapper to generic_file_read. It
+ * updates the atime of the lower level inode if generic_file_read
+ * returns without any errors. This is to be used only for file reads.
+ * The function to be used for directory reads is ecryptfs_read.
+ */
+static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
+ const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct vfsmount *lower_vfsmount;
+ struct file *file = iocb->ki_filp;
+
+ rc = generic_file_aio_read(iocb, iov, nr_segs, pos);
+ /*
+ * Even though this is a async interface, we need to wait
+ * for IO to finish to update atime
+ */
+ if (-EIOCBQUEUED == rc)
+ rc = wait_on_sync_kiocb(iocb);
+ if (rc >= 0) {
+ lower_dentry = ecryptfs_dentry_to_lower(file->f_dentry);
+ lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_dentry);
+ touch_atime(lower_vfsmount, lower_dentry);
+ }
+ return rc;
+}
+
+struct ecryptfs_getdents_callback {
+ void *dirent;
+ struct dentry *dentry;
+ filldir_t filldir;
+ int err;
+ int filldir_called;
+ int entries_written;
+};
+
+/* Inspired by generic filldir in fs/readir.c */
+static int
+ecryptfs_filldir(void *dirent, const char *name, int namelen, loff_t offset,
+ u64 ino, unsigned int d_type)
+{
+ struct ecryptfs_crypt_stat *crypt_stat;
+ struct ecryptfs_getdents_callback *buf =
+ (struct ecryptfs_getdents_callback *)dirent;
+ int rc;
+ int decoded_length;
+ char *decoded_name;
+
+ crypt_stat = ecryptfs_dentry_to_private(buf->dentry)->crypt_stat;
+ buf->filldir_called++;
+ decoded_length = ecryptfs_decode_filename(crypt_stat, name, namelen,
+ &decoded_name);
+ if (decoded_length < 0) {
+ rc = decoded_length;
+ goto out;
+ }
+ rc = buf->filldir(buf->dirent, decoded_name, decoded_length, offset,
+ ino, d_type);
+ kfree(decoded_name);
+ if (rc >= 0)
+ buf->entries_written++;
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_readdir
+ * @file: The ecryptfs file struct
+ * @dirent: Directory entry
+ * @filldir: The filldir callback function
+ */
+static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+ int rc;
+ struct file *lower_file;
+ struct inode *inode;
+ struct ecryptfs_getdents_callback buf;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ lower_file->f_pos = file->f_pos;
+ inode = file->f_dentry->d_inode;
+ memset(&buf, 0, sizeof(buf));
+ buf.dirent = dirent;
+ buf.dentry = file->f_dentry;
+ buf.filldir = filldir;
+retry:
+ buf.filldir_called = 0;
+ buf.entries_written = 0;
+ buf.err = 0;
+ rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
+ if (buf.err)
+ rc = buf.err;
+ if (buf.filldir_called && !buf.entries_written)
+ goto retry;
+ file->f_pos = lower_file->f_pos;
+ if (rc >= 0)
+ ecryptfs_copy_attr_atime(inode, lower_file->f_dentry->d_inode);
+ return rc;
+}
+
+struct kmem_cache *ecryptfs_file_info_cache;
+
+/**
+ * ecryptfs_open
+ * @inode: inode speciying file to open
+ * @file: Structure to return filled in
+ *
+ * Opens the file specified by inode.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ struct ecryptfs_crypt_stat *crypt_stat = NULL;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
+ struct dentry *ecryptfs_dentry = file->f_dentry;
+ /* Private value of ecryptfs_dentry allocated in
+ * ecryptfs_lookup() */
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ struct inode *lower_inode = NULL;
+ struct file *lower_file = NULL;
+ struct vfsmount *lower_mnt;
+ struct ecryptfs_file_info *file_info;
+ int lower_flags;
+
+ /* Released in ecryptfs_release or end of function if failure */
+ file_info = kmem_cache_alloc(ecryptfs_file_info_cache, SLAB_KERNEL);
+ ecryptfs_set_file_private(file, file_info);
+ if (!file_info) {
+ ecryptfs_printk(KERN_ERR,
+ "Error attempting to allocate memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(file_info, 0, sizeof(*file_info));
+ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+ mount_crypt_stat = &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ mutex_lock(&crypt_stat->cs_mutex);
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) {
+ ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
+ /* Policy code enabled in future release */
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ }
+ mutex_unlock(&crypt_stat->cs_mutex);
+ /* This mntget & dget is undone via fput when the file is released */
+ dget(lower_dentry);
+ lower_flags = file->f_flags;
+ if ((lower_flags & O_ACCMODE) == O_WRONLY)
+ lower_flags = (lower_flags & O_ACCMODE) | O_RDWR;
+ if (file->f_flags & O_APPEND)
+ lower_flags &= ~O_APPEND;
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+ mntget(lower_mnt);
+ /* Corresponding fput() in ecryptfs_release() */
+ lower_file = dentry_open(lower_dentry, lower_mnt, lower_flags);
+ if (IS_ERR(lower_file)) {
+ rc = PTR_ERR(lower_file);
+ ecryptfs_printk(KERN_ERR, "Error opening lower file\n");
+ goto out_puts;
+ }
+ ecryptfs_set_file_lower(file, lower_file);
+ /* Isn't this check the same as the one in lookup? */
+ lower_inode = lower_dentry->d_inode;
+ if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ rc = 0;
+ goto out;
+ }
+ mutex_lock(&crypt_stat->cs_mutex);
+ if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) {
+ if (!(mount_crypt_stat->flags
+ & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+ rc = -EIO;
+ printk(KERN_WARNING "Attempt to read file that is "
+ "not in a valid eCryptfs format, and plaintext "
+ "passthrough mode is not enabled; returning "
+ "-EIO\n");
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out_puts;
+ }
+ crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+ rc = 0;
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out;
+ } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_POLICY_APPLIED)
+ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags,
+ ECRYPTFS_KEY_VALID)) {
+ rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG,
+ "Valid headers not found\n");
+ if (!(mount_crypt_stat->flags
+ & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {
+ rc = -EIO;
+ printk(KERN_WARNING "Attempt to read file that "
+ "is not in a valid eCryptfs format, "
+ "and plaintext passthrough mode is not "
+ "enabled; returning -EIO\n");
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out_puts;
+ }
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags,
+ ECRYPTFS_ENCRYPTED);
+ rc = 0;
+ mutex_unlock(&crypt_stat->cs_mutex);
+ goto out;
+ }
+ }
+ mutex_unlock(&crypt_stat->cs_mutex);
+ ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = [0x%.16x] "
+ "size: [0x%.16x]\n", inode, inode->i_ino,
+ i_size_read(inode));
+ ecryptfs_set_file_lower(file, lower_file);
+ goto out;
+out_puts:
+ mntput(lower_mnt);
+ dput(lower_dentry);
+ kmem_cache_free(ecryptfs_file_info_cache,
+ ecryptfs_file_to_private(file));
+out:
+ return rc;
+}
+
+static int ecryptfs_flush(struct file *file, fl_owner_t td)
+{
+ int rc = 0;
+ struct file *lower_file = NULL;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file->f_op && lower_file->f_op->flush)
+ rc = lower_file->f_op->flush(lower_file, td);
+ return rc;
+}
+
+static int ecryptfs_release(struct inode *inode, struct file *file)
+{
+ struct file *lower_file = ecryptfs_file_to_lower(file);
+ struct ecryptfs_file_info *file_info = ecryptfs_file_to_private(file);
+ struct inode *lower_inode = ecryptfs_inode_to_lower(inode);
+
+ fput(lower_file);
+ inode->i_blocks = lower_inode->i_blocks;
+ kmem_cache_free(ecryptfs_file_info_cache, file_info);
+ return 0;
+}
+
+static int
+ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ struct file *lower_file = ecryptfs_file_to_lower(file);
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct inode *lower_inode = lower_dentry->d_inode;
+ int rc = -EINVAL;
+
+ if (lower_inode->i_fop->fsync) {
+ mutex_lock(&lower_inode->i_mutex);
+ rc = lower_inode->i_fop->fsync(lower_file, lower_dentry,
+ datasync);
+ mutex_unlock(&lower_inode->i_mutex);
+ }
+ return rc;
+}
+
+static int ecryptfs_fasync(int fd, struct file *file, int flag)
+{
+ int rc = 0;
+ struct file *lower_file = NULL;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file->f_op && lower_file->f_op->fasync)
+ rc = lower_file->f_op->fasync(fd, lower_file, flag);
+ return rc;
+}
+
+static ssize_t ecryptfs_sendfile(struct file *file, loff_t * ppos,
+ size_t count, read_actor_t actor, void *target)
+{
+ struct file *lower_file = NULL;
+ int rc = -EINVAL;
+
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file->f_op && lower_file->f_op->sendfile)
+ rc = lower_file->f_op->sendfile(lower_file, ppos, count,
+ actor, target);
+
+ return rc;
+}
+
+static int ecryptfs_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg);
+
+const struct file_operations ecryptfs_dir_fops = {
+ .readdir = ecryptfs_readdir,
+ .ioctl = ecryptfs_ioctl,
+ .mmap = generic_file_mmap,
+ .open = ecryptfs_open,
+ .flush = ecryptfs_flush,
+ .release = ecryptfs_release,
+ .fsync = ecryptfs_fsync,
+ .fasync = ecryptfs_fasync,
+ .sendfile = ecryptfs_sendfile,
+};
+
+const struct file_operations ecryptfs_main_fops = {
+ .llseek = ecryptfs_llseek,
+ .read = do_sync_read,
+ .aio_read = ecryptfs_read_update_atime,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
+ .readdir = ecryptfs_readdir,
+ .ioctl = ecryptfs_ioctl,
+ .mmap = generic_file_mmap,
+ .open = ecryptfs_open,
+ .flush = ecryptfs_flush,
+ .release = ecryptfs_release,
+ .fsync = ecryptfs_fsync,
+ .fasync = ecryptfs_fasync,
+ .sendfile = ecryptfs_sendfile,
+};
+
+static int
+ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc = 0;
+ struct file *lower_file = NULL;
+
+ if (ecryptfs_file_to_private(file))
+ lower_file = ecryptfs_file_to_lower(file);
+ if (lower_file && lower_file->f_op && lower_file->f_op->ioctl)
+ rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode),
+ lower_file, cmd, arg);
+ else
+ rc = -ENOTTY;
+ return rc;
+}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
new file mode 100644
index 000000000000..efdd2b7b62d7
--- /dev/null
+++ b/fs/ecryptfs/inode.c
@@ -0,0 +1,1079 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2004 Erez Zadok
+ * Copyright (C) 2001-2004 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompsion <mcthomps@us.ibm.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/file.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/crypto.h>
+#include "ecryptfs_kernel.h"
+
+static struct dentry *lock_parent(struct dentry *dentry)
+{
+ struct dentry *dir;
+
+ dir = dget(dentry->d_parent);
+ mutex_lock(&(dir->d_inode->i_mutex));
+ return dir;
+}
+
+static void unlock_parent(struct dentry *dentry)
+{
+ mutex_unlock(&(dentry->d_parent->d_inode->i_mutex));
+ dput(dentry->d_parent);
+}
+
+static void unlock_dir(struct dentry *dir)
+{
+ mutex_unlock(&dir->d_inode->i_mutex);
+ dput(dir);
+}
+
+void ecryptfs_copy_inode_size(struct inode *dst, const struct inode *src)
+{
+ i_size_write(dst, i_size_read((struct inode *)src));
+ dst->i_blocks = src->i_blocks;
+}
+
+void ecryptfs_copy_attr_atime(struct inode *dest, const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+}
+
+static void ecryptfs_copy_attr_times(struct inode *dest,
+ const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+}
+
+static void ecryptfs_copy_attr_timesizes(struct inode *dest,
+ const struct inode *src)
+{
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+ ecryptfs_copy_inode_size(dest, src);
+}
+
+void ecryptfs_copy_attr_all(struct inode *dest, const struct inode *src)
+{
+ dest->i_mode = src->i_mode;
+ dest->i_nlink = src->i_nlink;
+ dest->i_uid = src->i_uid;
+ dest->i_gid = src->i_gid;
+ dest->i_rdev = src->i_rdev;
+ dest->i_atime = src->i_atime;
+ dest->i_mtime = src->i_mtime;
+ dest->i_ctime = src->i_ctime;
+ dest->i_blkbits = src->i_blkbits;
+ dest->i_flags = src->i_flags;
+}
+
+/**
+ * ecryptfs_create_underlying_file
+ * @lower_dir_inode: inode of the parent in the lower fs of the new file
+ * @lower_dentry: New file's dentry in the lower fs
+ * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @mode: The mode of the new file
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
+ *
+ * Creates the file in the lower file system.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_create_underlying_file(struct inode *lower_dir_inode,
+ struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+ struct dentry *dentry_save;
+ struct vfsmount *vfsmount_save;
+ int rc;
+
+ dentry_save = nd->dentry;
+ vfsmount_save = nd->mnt;
+ nd->dentry = lower_dentry;
+ nd->mnt = lower_mnt;
+ rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);
+ nd->dentry = dentry_save;
+ nd->mnt = vfsmount_save;
+ return rc;
+}
+
+/**
+ * ecryptfs_do_create
+ * @directory_inode: inode of the new file's dentry's parent in ecryptfs
+ * @ecryptfs_dentry: New file's dentry in ecryptfs
+ * @mode: The mode of the new file
+ * @nd: nameidata of ecryptfs' parent's dentry & vfsmount
+ *
+ * Creates the underlying file and the eCryptfs inode which will link to
+ * it. It will also update the eCryptfs directory inode to mimic the
+ * stat of the lower directory inode.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_do_create(struct inode *directory_inode,
+ struct dentry *ecryptfs_dentry, int mode,
+ struct nameidata *nd)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ if (unlikely(IS_ERR(lower_dir_dentry))) {
+ ecryptfs_printk(KERN_ERR, "Error locking directory of "
+ "dentry\n");
+ rc = PTR_ERR(lower_dir_dentry);
+ goto out;
+ }
+ rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,
+ ecryptfs_dentry, mode, nd);
+ if (unlikely(rc)) {
+ ecryptfs_printk(KERN_ERR,
+ "Failure to create underlying file\n");
+ goto out_lock;
+ }
+ rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
+ directory_inode->i_sb, 0);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Failure in ecryptfs_interpose\n");
+ goto out_lock;
+ }
+ ecryptfs_copy_attr_timesizes(directory_inode,
+ lower_dir_dentry->d_inode);
+out_lock:
+ unlock_dir(lower_dir_dentry);
+out:
+ return rc;
+}
+
+/**
+ * grow_file
+ * @ecryptfs_dentry: the ecryptfs dentry
+ * @lower_file: The lower file
+ * @inode: The ecryptfs inode
+ * @lower_inode: The lower inode
+ *
+ * This is the code which will grow the file to its correct size.
+ */
+static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file,
+ struct inode *inode, struct inode *lower_inode)
+{
+ int rc = 0;
+ struct file fake_file;
+ struct ecryptfs_file_info tmp_file_info;
+
+ memset(&fake_file, 0, sizeof(fake_file));
+ fake_file.f_dentry = ecryptfs_dentry;
+ memset(&tmp_file_info, 0, sizeof(tmp_file_info));
+ ecryptfs_set_file_private(&fake_file, &tmp_file_info);
+ ecryptfs_set_file_lower(&fake_file, lower_file);
+ rc = ecryptfs_fill_zeros(&fake_file, 1);
+ if (rc) {
+ ECRYPTFS_SET_FLAG(
+ ecryptfs_inode_to_private(inode)->crypt_stat.flags,
+ ECRYPTFS_SECURITY_WARNING);
+ ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros "
+ "in file; rc = [%d]\n", rc);
+ goto out;
+ }
+ i_size_write(inode, 0);
+ ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+ ECRYPTFS_SET_FLAG(ecryptfs_inode_to_private(inode)->crypt_stat.flags,
+ ECRYPTFS_NEW_FILE);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_initialize_file
+ *
+ * Cause the file to be changed from a basic empty file to an ecryptfs
+ * file with a header and first data page.
+ *
+ * Returns zero on success
+ */
+static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)
+{
+ int rc = 0;
+ int lower_flags;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ struct dentry *lower_dentry;
+ struct dentry *tlower_dentry = NULL;
+ struct file *lower_file;
+ struct inode *inode, *lower_inode;
+ struct vfsmount *lower_mnt;
+
+ lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
+ ecryptfs_printk(KERN_DEBUG, "lower_dentry->d_name.name = [%s]\n",
+ lower_dentry->d_name.name);
+ inode = ecryptfs_dentry->d_inode;
+ crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
+ tlower_dentry = dget(lower_dentry);
+ if (!tlower_dentry) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry\n");
+ goto out;
+ }
+ lower_flags = ((O_CREAT | O_WRONLY | O_TRUNC) & O_ACCMODE) | O_RDWR;
+#if BITS_PER_LONG != 32
+ lower_flags |= O_LARGEFILE;
+#endif
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);
+ mntget(lower_mnt);
+ /* Corresponding fput() at end of this function */
+ lower_file = dentry_open(tlower_dentry, lower_mnt, lower_flags);
+ if (IS_ERR(lower_file)) {
+ rc = PTR_ERR(lower_file);
+ ecryptfs_printk(KERN_ERR,
+ "Error opening dentry; rc = [%i]\n", rc);
+ goto out;
+ }
+ /* fput(lower_file) should handle the puts if we do this */
+ lower_file->f_dentry = tlower_dentry;
+ lower_file->f_vfsmnt = lower_mnt;
+ lower_inode = tlower_dentry->d_inode;
+ if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED);
+ goto out_fput;
+ }
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
+ ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n");
+ rc = ecryptfs_new_file_context(ecryptfs_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG, "Error creating new file "
+ "context\n");
+ goto out_fput;
+ }
+ rc = ecryptfs_write_headers(ecryptfs_dentry, lower_file);
+ if (rc) {
+ ecryptfs_printk(KERN_DEBUG, "Error writing headers\n");
+ goto out_fput;
+ }
+ rc = grow_file(ecryptfs_dentry, lower_file, inode, lower_inode);
+out_fput:
+ fput(lower_file);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_create
+ * @dir: The inode of the directory in which to create the file.
+ * @dentry: The eCryptfs dentry
+ * @mode: The mode of the new file.
+ * @nd: nameidata
+ *
+ * Creates a new file.
+ *
+ * Returns zero on success; non-zero on error condition
+ */
+static int
+ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
+ int mode, struct nameidata *nd)
+{
+ int rc;
+
+ rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);
+ if (unlikely(rc)) {
+ ecryptfs_printk(KERN_WARNING, "Failed to create file in"
+ "lower filesystem\n");
+ goto out;
+ }
+ /* At this point, a file exists on "disk"; we need to make sure
+ * that this on disk file is prepared to be an ecryptfs file */
+ rc = ecryptfs_initialize_file(ecryptfs_dentry);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_lookup
+ * @dir: inode
+ * @dentry: The dentry
+ * @nd: nameidata, may be NULL
+ *
+ * Find a file on disk. If the file does not exist, then we'll add it to the
+ * dentry cache and continue on to read it from the disk.
+ */
+static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ int rc = 0;
+ struct dentry *lower_dir_dentry;
+ struct dentry *lower_dentry;
+ struct vfsmount *lower_mnt;
+ struct dentry *tlower_dentry = NULL;
+ char *encoded_name;
+ unsigned int encoded_namelen;
+ struct ecryptfs_crypt_stat *crypt_stat = NULL;
+ char *page_virt = NULL;
+ struct inode *lower_inode;
+ u64 file_size;
+
+ lower_dir_dentry = ecryptfs_dentry_to_lower(dentry->d_parent);
+ dentry->d_op = &ecryptfs_dops;
+ if ((dentry->d_name.len == 1 && !strcmp(dentry->d_name.name, "."))
+ || (dentry->d_name.len == 2 && !strcmp(dentry->d_name.name, "..")))
+ goto out_drop;
+ encoded_namelen = ecryptfs_encode_filename(crypt_stat,
+ dentry->d_name.name,
+ dentry->d_name.len,
+ &encoded_name);
+ if (encoded_namelen < 0) {
+ rc = encoded_namelen;
+ goto out_drop;
+ }
+ ecryptfs_printk(KERN_DEBUG, "encoded_name = [%s]; encoded_namelen "
+ "= [%d]\n", encoded_name, encoded_namelen);
+ lower_dentry = lookup_one_len(encoded_name, lower_dir_dentry,
+ encoded_namelen - 1);
+ kfree(encoded_name);
+ lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(dentry->d_parent));
+ if (IS_ERR(lower_dentry)) {
+ ecryptfs_printk(KERN_ERR, "ERR from lower_dentry\n");
+ rc = PTR_ERR(lower_dentry);
+ goto out_drop;
+ }
+ ecryptfs_printk(KERN_DEBUG, "lower_dentry = [%p]; lower_dentry->"
+ "d_name.name = [%s]\n", lower_dentry,
+ lower_dentry->d_name.name);
+ lower_inode = lower_dentry->d_inode;
+ ecryptfs_copy_attr_atime(dir, lower_dir_dentry->d_inode);
+ BUG_ON(!atomic_read(&lower_dentry->d_count));
+ ecryptfs_set_dentry_private(dentry,
+ kmem_cache_alloc(ecryptfs_dentry_info_cache,
+ SLAB_KERNEL));
+ if (!ecryptfs_dentry_to_private(dentry)) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Out of memory whilst attempting "
+ "to allocate ecryptfs_dentry_info struct\n");
+ goto out_dput;
+ }
+ ecryptfs_set_dentry_lower(dentry, lower_dentry);
+ ecryptfs_set_dentry_lower_mnt(dentry, lower_mnt);
+ if (!lower_dentry->d_inode) {
+ /* We want to add because we couldn't find in lower */
+ d_add(dentry, NULL);
+ goto out;
+ }
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 1);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error interposing\n");
+ goto out_dput;
+ }
+ if (S_ISDIR(lower_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "Is a directory; returning\n");
+ goto out;
+ }
+ if (S_ISLNK(lower_inode->i_mode)) {
+ ecryptfs_printk(KERN_DEBUG, "Is a symlink; returning\n");
+ goto out;
+ }
+ if (!nd) {
+ ecryptfs_printk(KERN_DEBUG, "We have a NULL nd, just leave"
+ "as we *think* we are about to unlink\n");
+ goto out;
+ }
+ tlower_dentry = dget(lower_dentry);
+ if (!tlower_dentry || IS_ERR(tlower_dentry)) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Cannot dget lower_dentry\n");
+ goto out_dput;
+ }
+ /* Released in this function */
+ page_virt =
+ (char *)kmem_cache_alloc(ecryptfs_header_cache_2,
+ SLAB_USER);
+ if (!page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR,
+ "Cannot ecryptfs_kmalloc a page\n");
+ goto out_dput;
+ }
+ memset(page_virt, 0, PAGE_CACHE_SIZE);
+ rc = ecryptfs_read_header_region(page_virt, tlower_dentry, nd->mnt);
+ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+ if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED))
+ ecryptfs_set_default_sizes(crypt_stat);
+ if (rc) {
+ rc = 0;
+ ecryptfs_printk(KERN_WARNING, "Error reading header region;"
+ " assuming unencrypted\n");
+ } else {
+ if (!contains_ecryptfs_marker(page_virt
+ + ECRYPTFS_FILE_SIZE_BYTES)) {
+ kmem_cache_free(ecryptfs_header_cache_2, page_virt);
+ goto out;
+ }
+ memcpy(&file_size, page_virt, sizeof(file_size));
+ file_size = be64_to_cpu(file_size);
+ i_size_write(dentry->d_inode, (loff_t)file_size);
+ }
+ kmem_cache_free(ecryptfs_header_cache_2, page_virt);
+ goto out;
+
+out_dput:
+ dput(lower_dentry);
+ if (tlower_dentry)
+ dput(tlower_dentry);
+out_drop:
+ d_drop(dentry);
+out:
+ return ERR_PTR(rc);
+}
+
+static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *new_dentry)
+{
+ struct dentry *lower_old_dentry;
+ struct dentry *lower_new_dentry;
+ struct dentry *lower_dir_dentry;
+ u64 file_size_save;
+ int rc;
+
+ file_size_save = i_size_read(old_dentry->d_inode);
+ lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+ lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+ dget(lower_old_dentry);
+ dget(lower_new_dentry);
+ lower_dir_dentry = lock_parent(lower_new_dentry);
+ rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,
+ lower_new_dentry);
+ if (rc || !lower_new_dentry->d_inode)
+ goto out_lock;
+ rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);
+ if (rc)
+ goto out_lock;
+ ecryptfs_copy_attr_timesizes(dir, lower_new_dentry->d_inode);
+ old_dentry->d_inode->i_nlink =
+ ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;
+ i_size_write(new_dentry->d_inode, file_size_save);
+out_lock:
+ unlock_dir(lower_dir_dentry);
+ dput(lower_new_dentry);
+ dput(lower_old_dentry);
+ if (!new_dentry->d_inode)
+ d_drop(new_dentry);
+ return rc;
+}
+
+static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ int rc = 0;
+ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);
+
+ lock_parent(lower_dentry);
+ rc = vfs_unlink(lower_dir_inode, lower_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error in vfs_unlink\n");
+ goto out_unlock;
+ }
+ ecryptfs_copy_attr_times(dir, lower_dir_inode);
+ dentry->d_inode->i_nlink =
+ ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;
+ dentry->d_inode->i_ctime = dir->i_ctime;
+out_unlock:
+ unlock_parent(lower_dentry);
+ return rc;
+}
+
+static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+ umode_t mode;
+ char *encoded_symname;
+ unsigned int encoded_symlen;
+ struct ecryptfs_crypt_stat *crypt_stat = NULL;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ dget(lower_dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ mode = S_IALLUGO;
+ encoded_symlen = ecryptfs_encode_filename(crypt_stat, symname,
+ strlen(symname),
+ &encoded_symname);
+ if (encoded_symlen < 0) {
+ rc = encoded_symlen;
+ goto out_lock;
+ }
+ rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,
+ encoded_symname, mode);
+ kfree(encoded_symname);
+ if (rc || !lower_dentry->d_inode)
+ goto out_lock;
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+ if (rc)
+ goto out_lock;
+ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out_lock:
+ unlock_dir(lower_dir_dentry);
+ dput(lower_dentry);
+ if (!dentry->d_inode)
+ d_drop(dentry);
+ return rc;
+}
+
+static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);
+ if (rc || !lower_dentry->d_inode)
+ goto out;
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+ if (rc)
+ goto out;
+ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+ dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+out:
+ unlock_dir(lower_dir_dentry);
+ if (!dentry->d_inode)
+ d_drop(dentry);
+ return rc;
+}
+
+static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ int rc = 0;
+ struct dentry *tdentry = NULL;
+ struct dentry *lower_dentry;
+ struct dentry *tlower_dentry = NULL;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!(tdentry = dget(dentry))) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "Error dget'ing dentry [%p]\n",
+ dentry);
+ goto out;
+ }
+ lower_dir_dentry = lock_parent(lower_dentry);
+ if (!(tlower_dentry = dget(lower_dentry))) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "Error dget'ing lower_dentry "
+ "[%p]\n", lower_dentry);
+ goto out;
+ }
+ rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);
+ if (!rc) {
+ d_delete(tlower_dentry);
+ tlower_dentry = NULL;
+ }
+ ecryptfs_copy_attr_times(dir, lower_dir_dentry->d_inode);
+ dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;
+ unlock_dir(lower_dir_dentry);
+ if (!rc)
+ d_drop(dentry);
+out:
+ if (tdentry)
+ dput(tdentry);
+ if (tlower_dentry)
+ dput(tlower_dentry);
+ return rc;
+}
+
+static int
+ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ struct dentry *lower_dir_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ lower_dir_dentry = lock_parent(lower_dentry);
+ rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);
+ if (rc || !lower_dentry->d_inode)
+ goto out;
+ rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);
+ if (rc)
+ goto out;
+ ecryptfs_copy_attr_timesizes(dir, lower_dir_dentry->d_inode);
+out:
+ unlock_dir(lower_dir_dentry);
+ if (!dentry->d_inode)
+ d_drop(dentry);
+ return rc;
+}
+
+static int
+ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ int rc;
+ struct dentry *lower_old_dentry;
+ struct dentry *lower_new_dentry;
+ struct dentry *lower_old_dir_dentry;
+ struct dentry *lower_new_dir_dentry;
+
+ lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
+ lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
+ dget(lower_old_dentry);
+ dget(lower_new_dentry);
+ lower_old_dir_dentry = dget_parent(lower_old_dentry);
+ lower_new_dir_dentry = dget_parent(lower_new_dentry);
+ lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+ rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,
+ lower_new_dir_dentry->d_inode, lower_new_dentry);
+ if (rc)
+ goto out_lock;
+ ecryptfs_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode);
+ if (new_dir != old_dir)
+ ecryptfs_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode);
+out_lock:
+ unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+ dput(lower_new_dentry);
+ dput(lower_old_dentry);
+ return rc;
+}
+
+static int
+ecryptfs_readlink(struct dentry *dentry, char __user * buf, int bufsiz)
+{
+ int rc;
+ struct dentry *lower_dentry;
+ char *decoded_name;
+ char *lower_buf;
+ mm_segment_t old_fs;
+ struct ecryptfs_crypt_stat *crypt_stat;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op ||
+ !lower_dentry->d_inode->i_op->readlink) {
+ rc = -EINVAL;
+ goto out;
+ }
+ /* Released in this function */
+ lower_buf = kmalloc(bufsiz, GFP_KERNEL);
+ if (lower_buf == NULL) {
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
+ "lower_dentry->d_name.name = [%s]\n",
+ lower_dentry->d_name.name);
+ rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
+ (char __user *)lower_buf,
+ bufsiz);
+ set_fs(old_fs);
+ if (rc >= 0) {
+ crypt_stat = NULL;
+ rc = ecryptfs_decode_filename(crypt_stat, lower_buf, rc,
+ &decoded_name);
+ if (rc == -ENOMEM)
+ goto out_free_lower_buf;
+ if (rc > 0) {
+ ecryptfs_printk(KERN_DEBUG, "Copying [%d] bytes "
+ "to userspace: [%*s]\n", rc,
+ decoded_name);
+ if (copy_to_user(buf, decoded_name, rc))
+ rc = -EFAULT;
+ }
+ kfree(decoded_name);
+ ecryptfs_copy_attr_atime(dentry->d_inode,
+ lower_dentry->d_inode);
+ }
+out_free_lower_buf:
+ kfree(lower_buf);
+out:
+ return rc;
+}
+
+static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ char *buf;
+ int len = PAGE_SIZE, rc;
+ mm_segment_t old_fs;
+
+ /* Released in ecryptfs_put_link(); only release here on error */
+ buf = kmalloc(len, GFP_KERNEL);
+ if (!buf) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ old_fs = get_fs();
+ set_fs(get_ds());
+ ecryptfs_printk(KERN_DEBUG, "Calling readlink w/ "
+ "dentry->d_name.name = [%s]\n", dentry->d_name.name);
+ rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);
+ buf[rc] = '\0';
+ set_fs(old_fs);
+ if (rc < 0)
+ goto out_free;
+ rc = 0;
+ nd_set_link(nd, buf);
+ goto out;
+out_free:
+ kfree(buf);
+out:
+ return ERR_PTR(rc);
+}
+
+static void
+ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)
+{
+ /* Free the char* */
+ kfree(nd_get_link(nd));
+}
+
+/**
+ * upper_size_to_lower_size
+ * @crypt_stat: Crypt_stat associated with file
+ * @upper_size: Size of the upper file
+ *
+ * Calculate the requried size of the lower file based on the
+ * specified size of the upper file. This calculation is based on the
+ * number of headers in the underlying file and the extent size.
+ *
+ * Returns Calculated size of the lower file.
+ */
+static loff_t
+upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,
+ loff_t upper_size)
+{
+ loff_t lower_size;
+
+ lower_size = ( crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front );
+ if (upper_size != 0) {
+ loff_t num_extents;
+
+ num_extents = upper_size >> crypt_stat->extent_shift;
+ if (upper_size & ~crypt_stat->extent_mask)
+ num_extents++;
+ lower_size += (num_extents * crypt_stat->extent_size);
+ }
+ return lower_size;
+}
+
+/**
+ * ecryptfs_truncate
+ * @dentry: The ecryptfs layer dentry
+ * @new_length: The length to expand the file to
+ *
+ * Function to handle truncations modifying the size of the file. Note
+ * that the file sizes are interpolated. When expanding, we are simply
+ * writing strings of 0's out. When truncating, we need to modify the
+ * underlying file size according to the page index interpolations.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
+{
+ int rc = 0;
+ struct inode *inode = dentry->d_inode;
+ struct dentry *lower_dentry;
+ struct vfsmount *lower_mnt;
+ struct file fake_ecryptfs_file, *lower_file = NULL;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ loff_t i_size = i_size_read(inode);
+ loff_t lower_size_before_truncate;
+ loff_t lower_size_after_truncate;
+
+ if (unlikely((new_length == i_size)))
+ goto out;
+ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+ /* Set up a fake ecryptfs file, this is used to interface with
+ * the file in the underlying filesystem so that the
+ * truncation has an effect there as well. */
+ memset(&fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file));
+ fake_ecryptfs_file.f_dentry = dentry;
+ /* Released at out_free: label */
+ ecryptfs_set_file_private(&fake_ecryptfs_file,
+ kmem_cache_alloc(ecryptfs_file_info_cache,
+ SLAB_KERNEL));
+ if (unlikely(!ecryptfs_file_to_private(&fake_ecryptfs_file))) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ /* This dget & mntget is released through fput at out_fput: */
+ dget(lower_dentry);
+ lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
+ mntget(lower_mnt);
+ lower_file = dentry_open(lower_dentry, lower_mnt, O_RDWR);
+ if (unlikely(IS_ERR(lower_file))) {
+ rc = PTR_ERR(lower_file);
+ goto out_free;
+ }
+ ecryptfs_set_file_lower(&fake_ecryptfs_file, lower_file);
+ /* Switch on growing or shrinking file */
+ if (new_length > i_size) {
+ rc = ecryptfs_fill_zeros(&fake_ecryptfs_file, new_length);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR,
+ "Problem with fill_zeros\n");
+ goto out_fput;
+ }
+ i_size_write(inode, new_length);
+ rc = ecryptfs_write_inode_size_to_header(lower_file,
+ lower_dentry->d_inode,
+ inode);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR,
+ "Problem with ecryptfs_write"
+ "_inode_size\n");
+ goto out_fput;
+ }
+ } else { /* new_length < i_size_read(inode) */
+ vmtruncate(inode, new_length);
+ ecryptfs_write_inode_size_to_header(lower_file,
+ lower_dentry->d_inode,
+ inode);
+ /* We are reducing the size of the ecryptfs file, and need to
+ * know if we need to reduce the size of the lower file. */
+ lower_size_before_truncate =
+ upper_size_to_lower_size(crypt_stat, i_size);
+ lower_size_after_truncate =
+ upper_size_to_lower_size(crypt_stat, new_length);
+ if (lower_size_after_truncate < lower_size_before_truncate)
+ vmtruncate(lower_dentry->d_inode,
+ lower_size_after_truncate);
+ }
+ /* Update the access times */
+ lower_dentry->d_inode->i_mtime = lower_dentry->d_inode->i_ctime
+ = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+out_fput:
+ fput(lower_file);
+out_free:
+ if (ecryptfs_file_to_private(&fake_ecryptfs_file))
+ kmem_cache_free(ecryptfs_file_info_cache,
+ ecryptfs_file_to_private(&fake_ecryptfs_file));
+out:
+ return rc;
+}
+
+static int
+ecryptfs_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ int rc;
+
+ if (nd) {
+ struct vfsmount *vfsmnt_save = nd->mnt;
+ struct dentry *dentry_save = nd->dentry;
+
+ nd->mnt = ecryptfs_dentry_to_lower_mnt(nd->dentry);
+ nd->dentry = ecryptfs_dentry_to_lower(nd->dentry);
+ rc = permission(ecryptfs_inode_to_lower(inode), mask, nd);
+ nd->mnt = vfsmnt_save;
+ nd->dentry = dentry_save;
+ } else
+ rc = permission(ecryptfs_inode_to_lower(inode), mask, NULL);
+ return rc;
+}
+
+/**
+ * ecryptfs_setattr
+ * @dentry: dentry handle to the inode to modify
+ * @ia: Structure with flags of what to change and values
+ *
+ * Updates the metadata of an inode. If the update is to the size
+ * i.e. truncation, then ecryptfs_truncate will handle the size modification
+ * of both the ecryptfs inode and the lower inode.
+ *
+ * All other metadata changes will be passed right to the lower filesystem,
+ * and we will just update our inode to look like the lower.
+ */
+static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+ struct inode *inode;
+ struct inode *lower_inode;
+ struct ecryptfs_crypt_stat *crypt_stat;
+
+ crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ inode = dentry->d_inode;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ if (ia->ia_valid & ATTR_SIZE) {
+ ecryptfs_printk(KERN_DEBUG,
+ "ia->ia_valid = [0x%x] ATTR_SIZE" " = [0x%x]\n",
+ ia->ia_valid, ATTR_SIZE);
+ rc = ecryptfs_truncate(dentry, ia->ia_size);
+ /* ecryptfs_truncate handles resizing of the lower file */
+ ia->ia_valid &= ~ATTR_SIZE;
+ ecryptfs_printk(KERN_DEBUG, "ia->ia_valid = [%x]\n",
+ ia->ia_valid);
+ if (rc < 0)
+ goto out;
+ }
+ rc = notify_change(lower_dentry, ia);
+out:
+ ecryptfs_copy_attr_all(inode, lower_inode);
+ return rc;
+}
+
+static int
+ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+ size_t size, int flags)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->setxattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value,
+ size, flags);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+static ssize_t
+ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,
+ size_t size)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->getxattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value,
+ size);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+static ssize_t
+ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->listxattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+static int ecryptfs_removexattr(struct dentry *dentry, const char *name)
+{
+ int rc = 0;
+ struct dentry *lower_dentry;
+
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ if (!lower_dentry->d_inode->i_op->removexattr) {
+ rc = -ENOSYS;
+ goto out;
+ }
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
+ rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
+out:
+ return rc;
+}
+
+int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode)
+{
+ if ((ecryptfs_inode_to_lower(inode)
+ == (struct inode *)candidate_lower_inode))
+ return 1;
+ else
+ return 0;
+}
+
+int ecryptfs_inode_set(struct inode *inode, void *lower_inode)
+{
+ ecryptfs_init_inode(inode, (struct inode *)lower_inode);
+ return 0;
+}
+
+struct inode_operations ecryptfs_symlink_iops = {
+ .readlink = ecryptfs_readlink,
+ .follow_link = ecryptfs_follow_link,
+ .put_link = ecryptfs_put_link,
+ .permission = ecryptfs_permission,
+ .setattr = ecryptfs_setattr,
+ .setxattr = ecryptfs_setxattr,
+ .getxattr = ecryptfs_getxattr,
+ .listxattr = ecryptfs_listxattr,
+ .removexattr = ecryptfs_removexattr
+};
+
+struct inode_operations ecryptfs_dir_iops = {
+ .create = ecryptfs_create,
+ .lookup = ecryptfs_lookup,
+ .link = ecryptfs_link,
+ .unlink = ecryptfs_unlink,
+ .symlink = ecryptfs_symlink,
+ .mkdir = ecryptfs_mkdir,
+ .rmdir = ecryptfs_rmdir,
+ .mknod = ecryptfs_mknod,
+ .rename = ecryptfs_rename,
+ .permission = ecryptfs_permission,
+ .setattr = ecryptfs_setattr,
+ .setxattr = ecryptfs_setxattr,
+ .getxattr = ecryptfs_getxattr,
+ .listxattr = ecryptfs_listxattr,
+ .removexattr = ecryptfs_removexattr
+};
+
+struct inode_operations ecryptfs_main_iops = {
+ .permission = ecryptfs_permission,
+ .setattr = ecryptfs_setattr,
+ .setxattr = ecryptfs_setxattr,
+ .getxattr = ecryptfs_getxattr,
+ .listxattr = ecryptfs_listxattr,
+ .removexattr = ecryptfs_removexattr
+};
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
new file mode 100644
index 000000000000..ba454785a0c5
--- /dev/null
+++ b/fs/ecryptfs/keystore.c
@@ -0,0 +1,1061 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * In-kernel key management code. Includes functions to parse and
+ * write authentication token-related packets with the underlying
+ * file.
+ *
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.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/string.h>
+#include <linux/sched.h>
+#include <linux/syscalls.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/random.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * request_key returned an error instead of a valid key address;
+ * determine the type of error, make appropriate log entries, and
+ * return an error code.
+ */
+int process_request_key_err(long err_code)
+{
+ int rc = 0;
+
+ switch (err_code) {
+ case ENOKEY:
+ ecryptfs_printk(KERN_WARNING, "No key\n");
+ rc = -ENOENT;
+ break;
+ case EKEYEXPIRED:
+ ecryptfs_printk(KERN_WARNING, "Key expired\n");
+ rc = -ETIME;
+ break;
+ case EKEYREVOKED:
+ ecryptfs_printk(KERN_WARNING, "Key revoked\n");
+ rc = -EINVAL;
+ break;
+ default:
+ ecryptfs_printk(KERN_WARNING, "Unknown error code: "
+ "[0x%.16x]\n", err_code);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static void wipe_auth_tok_list(struct list_head *auth_tok_list_head)
+{
+ struct list_head *walker;
+ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+
+ walker = auth_tok_list_head->next;
+ while (walker != auth_tok_list_head) {
+ auth_tok_list_item =
+ list_entry(walker, struct ecryptfs_auth_tok_list_item,
+ list);
+ walker = auth_tok_list_item->list.next;
+ memset(auth_tok_list_item, 0,
+ sizeof(struct ecryptfs_auth_tok_list_item));
+ kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+ auth_tok_list_item);
+ }
+}
+
+struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
+
+/**
+ * parse_packet_length
+ * @data: Pointer to memory containing length at offset
+ * @size: This function writes the decoded size to this memory
+ * address; zero on error
+ * @length_size: The number of bytes occupied by the encoded length
+ *
+ * Returns Zero on success
+ */
+static int parse_packet_length(unsigned char *data, size_t *size,
+ size_t *length_size)
+{
+ int rc = 0;
+
+ (*length_size) = 0;
+ (*size) = 0;
+ if (data[0] < 192) {
+ /* One-byte length */
+ (*size) = data[0];
+ (*length_size) = 1;
+ } else if (data[0] < 224) {
+ /* Two-byte length */
+ (*size) = ((data[0] - 192) * 256);
+ (*size) += (data[1] + 192);
+ (*length_size) = 2;
+ } else if (data[0] == 255) {
+ /* Five-byte length; we're not supposed to see this */
+ ecryptfs_printk(KERN_ERR, "Five-byte packet length not "
+ "supported\n");
+ rc = -EINVAL;
+ goto out;
+ } else {
+ ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");
+ rc = -EINVAL;
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * write_packet_length
+ * @dest: The byte array target into which to write the
+ * length. Must have at least 5 bytes allocated.
+ * @size: The length to write.
+ * @packet_size_length: The number of bytes used to encode the
+ * packet length is written to this address.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int write_packet_length(char *dest, size_t size,
+ size_t *packet_size_length)
+{
+ int rc = 0;
+
+ if (size < 192) {
+ dest[0] = size;
+ (*packet_size_length) = 1;
+ } else if (size < 65536) {
+ dest[0] = (((size - 192) / 256) + 192);
+ dest[1] = ((size - 192) % 256);
+ (*packet_size_length) = 2;
+ } else {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_WARNING,
+ "Unsupported packet size: [%d]\n", size);
+ }
+ return rc;
+}
+
+/**
+ * parse_tag_3_packet
+ * @crypt_stat: The cryptographic context to modify based on packet
+ * contents.
+ * @data: The raw bytes of the packet.
+ * @auth_tok_list: eCryptfs parses packets into authentication tokens;
+ * a new authentication token will be placed at the end
+ * of this list for this packet.
+ * @new_auth_tok: Pointer to a pointer to memory that this function
+ * allocates; sets the memory address of the pointer to
+ * NULL on error. This object is added to the
+ * auth_tok_list.
+ * @packet_size: This function writes the size of the parsed packet
+ * into this memory location; zero on error.
+ * @max_packet_size: maximum number of bytes to parse
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned char *data, struct list_head *auth_tok_list,
+ struct ecryptfs_auth_tok **new_auth_tok,
+ size_t *packet_size, size_t max_packet_size)
+{
+ int rc = 0;
+ size_t body_size;
+ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+ size_t length_size;
+
+ (*packet_size) = 0;
+ (*new_auth_tok) = NULL;
+
+ /* we check that:
+ * one byte for the Tag 3 ID flag
+ * two bytes for the body size
+ * do not exceed the maximum_packet_size
+ */
+ if (unlikely((*packet_size) + 3 > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* check for Tag 3 identifyer - one byte */
+ if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {
+ ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n",
+ ECRYPTFS_TAG_3_PACKET_TYPE);
+ rc = -EINVAL;
+ goto out;
+ }
+ /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or
+ * at end of function upon failure */
+ auth_tok_list_item =
+ kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, SLAB_KERNEL);
+ if (!auth_tok_list_item) {
+ ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(auth_tok_list_item, 0,
+ sizeof(struct ecryptfs_auth_tok_list_item));
+ (*new_auth_tok) = &auth_tok_list_item->auth_tok;
+
+ /* check for body size - one to two bytes */
+ rc = parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
+ "rc = [%d]\n", rc);
+ goto out_free;
+ }
+ if (unlikely(body_size < (0x05 + ECRYPTFS_SALT_SIZE))) {
+ ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
+ body_size);
+ rc = -EINVAL;
+ goto out_free;
+ }
+ (*packet_size) += length_size;
+
+ /* now we know the length of the remainting Tag 3 packet size:
+ * 5 fix bytes for: version string, cipher, S2K ID, hash algo,
+ * number of hash iterations
+ * ECRYPTFS_SALT_SIZE bytes for salt
+ * body_size bytes minus the stuff above is the encrypted key size
+ */
+ if (unlikely((*packet_size) + body_size > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out_free;
+ }
+
+ /* There are 5 characters of additional information in the
+ * packet */
+ (*new_auth_tok)->session_key.encrypted_key_size =
+ body_size - (0x05 + ECRYPTFS_SALT_SIZE);
+ ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n",
+ (*new_auth_tok)->session_key.encrypted_key_size);
+
+ /* Version 4 (from RFC2440) - one byte */
+ if (unlikely(data[(*packet_size)++] != 0x04)) {
+ ecryptfs_printk(KERN_DEBUG, "Unknown version number "
+ "[%d]\n", data[(*packet_size) - 1]);
+ rc = -EINVAL;
+ goto out_free;
+ }
+
+ /* cipher - one byte */
+ ecryptfs_cipher_code_to_string(crypt_stat->cipher,
+ (u16)data[(*packet_size)]);
+ /* A little extra work to differentiate among the AES key
+ * sizes; see RFC2440 */
+ switch(data[(*packet_size)++]) {
+ case RFC2440_CIPHER_AES_192:
+ crypt_stat->key_size = 24;
+ break;
+ default:
+ crypt_stat->key_size =
+ (*new_auth_tok)->session_key.encrypted_key_size;
+ }
+ ecryptfs_init_crypt_ctx(crypt_stat);
+ /* S2K identifier 3 (from RFC2440) */
+ if (unlikely(data[(*packet_size)++] != 0x03)) {
+ ecryptfs_printk(KERN_ERR, "Only S2K ID 3 is currently "
+ "supported\n");
+ rc = -ENOSYS;
+ goto out_free;
+ }
+
+ /* TODO: finish the hash mapping */
+ /* hash algorithm - one byte */
+ switch (data[(*packet_size)++]) {
+ case 0x01: /* See RFC2440 for these numbers and their mappings */
+ /* Choose MD5 */
+ /* salt - ECRYPTFS_SALT_SIZE bytes */
+ memcpy((*new_auth_tok)->token.password.salt,
+ &data[(*packet_size)], ECRYPTFS_SALT_SIZE);
+ (*packet_size) += ECRYPTFS_SALT_SIZE;
+
+ /* This conversion was taken straight from RFC2440 */
+ /* number of hash iterations - one byte */
+ (*new_auth_tok)->token.password.hash_iterations =
+ ((u32) 16 + (data[(*packet_size)] & 15))
+ << ((data[(*packet_size)] >> 4) + 6);
+ (*packet_size)++;
+
+ /* encrypted session key -
+ * (body_size-5-ECRYPTFS_SALT_SIZE) bytes */
+ memcpy((*new_auth_tok)->session_key.encrypted_key,
+ &data[(*packet_size)],
+ (*new_auth_tok)->session_key.encrypted_key_size);
+ (*packet_size) +=
+ (*new_auth_tok)->session_key.encrypted_key_size;
+ (*new_auth_tok)->session_key.flags &=
+ ~ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+ (*new_auth_tok)->session_key.flags |=
+ ECRYPTFS_CONTAINS_ENCRYPTED_KEY;
+ (*new_auth_tok)->token.password.hash_algo = 0x01;
+ break;
+ default:
+ ecryptfs_printk(KERN_ERR, "Unsupported hash algorithm: "
+ "[%d]\n", data[(*packet_size) - 1]);
+ rc = -ENOSYS;
+ goto out_free;
+ }
+ (*new_auth_tok)->token_type = ECRYPTFS_PASSWORD;
+ /* TODO: Parametarize; we might actually want userspace to
+ * decrypt the session key. */
+ ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
+ ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);
+ ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags,
+ ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);
+ list_add(&auth_tok_list_item->list, auth_tok_list);
+ goto out;
+out_free:
+ (*new_auth_tok) = NULL;
+ memset(auth_tok_list_item, 0,
+ sizeof(struct ecryptfs_auth_tok_list_item));
+ kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
+ auth_tok_list_item);
+out:
+ if (rc)
+ (*packet_size) = 0;
+ return rc;
+}
+
+/**
+ * parse_tag_11_packet
+ * @data: The raw bytes of the packet
+ * @contents: This function writes the data contents of the literal
+ * packet into this memory location
+ * @max_contents_bytes: The maximum number of bytes that this function
+ * is allowed to write into contents
+ * @tag_11_contents_size: This function writes the size of the parsed
+ * contents into this memory location; zero on
+ * error
+ * @packet_size: This function writes the size of the parsed packet
+ * into this memory location; zero on error
+ * @max_packet_size: maximum number of bytes to parse
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+parse_tag_11_packet(unsigned char *data, unsigned char *contents,
+ size_t max_contents_bytes, size_t *tag_11_contents_size,
+ size_t *packet_size, size_t max_packet_size)
+{
+ int rc = 0;
+ size_t body_size;
+ size_t length_size;
+
+ (*packet_size) = 0;
+ (*tag_11_contents_size) = 0;
+
+ /* check that:
+ * one byte for the Tag 11 ID flag
+ * two bytes for the Tag 11 length
+ * do not exceed the maximum_packet_size
+ */
+ if (unlikely((*packet_size) + 3 > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* check for Tag 11 identifyer - one byte */
+ if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) {
+ ecryptfs_printk(KERN_WARNING,
+ "Invalid tag 11 packet format\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* get Tag 11 content length - one or two bytes */
+ rc = parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING,
+ "Invalid tag 11 packet format\n");
+ goto out;
+ }
+ (*packet_size) += length_size;
+
+ if (body_size < 13) {
+ ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n",
+ body_size);
+ rc = -EINVAL;
+ goto out;
+ }
+ /* We have 13 bytes of surrounding packet values */
+ (*tag_11_contents_size) = (body_size - 13);
+
+ /* now we know the length of the remainting Tag 11 packet size:
+ * 14 fix bytes for: special flag one, special flag two,
+ * 12 skipped bytes
+ * body_size bytes minus the stuff above is the Tag 11 content
+ */
+ /* FIXME why is the body size one byte smaller than the actual
+ * size of the body?
+ * this seems to be an error here as well as in
+ * write_tag_11_packet() */
+ if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {
+ ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* special flag one - one byte */
+ if (data[(*packet_size)++] != 0x62) {
+ ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* special flag two - one byte */
+ if (data[(*packet_size)++] != 0x08) {
+ ecryptfs_printk(KERN_WARNING, "Unrecognizable packet\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ /* skip the next 12 bytes */
+ (*packet_size) += 12; /* We don't care about the filename or
+ * the timestamp */
+
+ /* get the Tag 11 contents - tag_11_contents_size bytes */
+ memcpy(contents, &data[(*packet_size)], (*tag_11_contents_size));
+ (*packet_size) += (*tag_11_contents_size);
+
+out:
+ if (rc) {
+ (*packet_size) = 0;
+ (*tag_11_contents_size) = 0;
+ }
+ return rc;
+}
+
+/**
+ * decrypt_session_key - Decrypt the session key with the given auth_tok.
+ *
+ * Returns Zero on success; non-zero error otherwise.
+ */
+static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok,
+ struct ecryptfs_crypt_stat *crypt_stat)
+{
+ int rc = 0;
+ struct ecryptfs_password *password_s_ptr;
+ struct crypto_tfm *tfm = NULL;
+ struct scatterlist src_sg[2], dst_sg[2];
+ struct mutex *tfm_mutex = NULL;
+ /* TODO: Use virt_to_scatterlist for these */
+ char *encrypted_session_key;
+ char *session_key;
+
+ password_s_ptr = &auth_tok->token.password;
+ if (ECRYPTFS_CHECK_FLAG(password_s_ptr->flags,
+ ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET))
+ ecryptfs_printk(KERN_DEBUG, "Session key encryption key "
+ "set; skipping key generation\n");
+ ecryptfs_printk(KERN_DEBUG, "Session key encryption key (size [%d])"
+ ":\n",
+ password_s_ptr->session_key_encryption_key_bytes);
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(password_s_ptr->session_key_encryption_key,
+ password_s_ptr->
+ session_key_encryption_key_bytes);
+ if (!strcmp(crypt_stat->cipher,
+ crypt_stat->mount_crypt_stat->global_default_cipher_name)
+ && crypt_stat->mount_crypt_stat->global_key_tfm) {
+ tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
+ tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
+ } else {
+ tfm = crypto_alloc_tfm(crypt_stat->cipher,
+ CRYPTO_TFM_REQ_WEAK_KEY);
+ if (!tfm) {
+ printk(KERN_ERR "Error allocating crypto context\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ }
+ if (password_s_ptr->session_key_encryption_key_bytes
+ < crypto_tfm_alg_min_keysize(tfm)) {
+ printk(KERN_WARNING "Session key encryption key is [%d] bytes; "
+ "minimum keysize for selected cipher is [%d] bytes.\n",
+ password_s_ptr->session_key_encryption_key_bytes,
+ crypto_tfm_alg_min_keysize(tfm));
+ rc = -EINVAL;
+ goto out;
+ }
+ if (tfm_mutex)
+ mutex_lock(tfm_mutex);
+ crypto_cipher_setkey(tfm, password_s_ptr->session_key_encryption_key,
+ crypt_stat->key_size);
+ /* TODO: virt_to_scatterlist */
+ encrypted_session_key = (char *)__get_free_page(GFP_KERNEL);
+ if (!encrypted_session_key) {
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out_free_tfm;
+ }
+ session_key = (char *)__get_free_page(GFP_KERNEL);
+ if (!session_key) {
+ kfree(encrypted_session_key);
+ ecryptfs_printk(KERN_ERR, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out_free_tfm;
+ }
+ memcpy(encrypted_session_key, auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.encrypted_key_size);
+ src_sg[0].page = virt_to_page(encrypted_session_key);
+ src_sg[0].offset = 0;
+ BUG_ON(auth_tok->session_key.encrypted_key_size > PAGE_CACHE_SIZE);
+ src_sg[0].length = auth_tok->session_key.encrypted_key_size;
+ dst_sg[0].page = virt_to_page(session_key);
+ dst_sg[0].offset = 0;
+ auth_tok->session_key.decrypted_key_size =
+ auth_tok->session_key.encrypted_key_size;
+ dst_sg[0].length = auth_tok->session_key.encrypted_key_size;
+ /* TODO: Handle error condition */
+ crypto_cipher_decrypt(tfm, dst_sg, src_sg,
+ auth_tok->session_key.encrypted_key_size);
+ auth_tok->session_key.decrypted_key_size =
+ auth_tok->session_key.encrypted_key_size;
+ memcpy(auth_tok->session_key.decrypted_key, session_key,
+ auth_tok->session_key.decrypted_key_size);
+ auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;
+ memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,
+ auth_tok->session_key.decrypted_key_size);
+ ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID);
+ ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(crypt_stat->key,
+ crypt_stat->key_size);
+ memset(encrypted_session_key, 0, PAGE_CACHE_SIZE);
+ free_page((unsigned long)encrypted_session_key);
+ memset(session_key, 0, PAGE_CACHE_SIZE);
+ free_page((unsigned long)session_key);
+out_free_tfm:
+ if (tfm_mutex)
+ mutex_unlock(tfm_mutex);
+ else
+ crypto_free_tfm(tfm);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_parse_packet_set
+ * @dest: The header page in memory
+ * @version: Version of file format, to guide parsing behavior
+ *
+ * Get crypt_stat to have the file's session key if the requisite key
+ * is available to decrypt the session key.
+ *
+ * Returns Zero if a valid authentication token was retrieved and
+ * processed; negative value for file not encrypted or for error
+ * conditions.
+ */
+int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,
+ unsigned char *src,
+ struct dentry *ecryptfs_dentry)
+{
+ size_t i = 0;
+ int rc = 0;
+ size_t found_auth_tok = 0;
+ size_t next_packet_is_auth_tok_packet;
+ char sig[ECRYPTFS_SIG_SIZE_HEX];
+ struct list_head auth_tok_list;
+ struct list_head *walker;
+ struct ecryptfs_auth_tok *chosen_auth_tok = NULL;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ struct ecryptfs_auth_tok *candidate_auth_tok = NULL;
+ size_t packet_size;
+ struct ecryptfs_auth_tok *new_auth_tok;
+ unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE];
+ size_t tag_11_contents_size;
+ size_t tag_11_packet_size;
+
+ INIT_LIST_HEAD(&auth_tok_list);
+ /* Parse the header to find as many packets as we can, these will be
+ * added the our &auth_tok_list */
+ next_packet_is_auth_tok_packet = 1;
+ while (next_packet_is_auth_tok_packet) {
+ size_t max_packet_size = ((PAGE_CACHE_SIZE - 8) - i);
+
+ switch (src[i]) {
+ case ECRYPTFS_TAG_3_PACKET_TYPE:
+ rc = parse_tag_3_packet(crypt_stat,
+ (unsigned char *)&src[i],
+ &auth_tok_list, &new_auth_tok,
+ &packet_size, max_packet_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error parsing "
+ "tag 3 packet\n");
+ rc = -EIO;
+ goto out_wipe_list;
+ }
+ i += packet_size;
+ rc = parse_tag_11_packet((unsigned char *)&src[i],
+ sig_tmp_space,
+ ECRYPTFS_SIG_SIZE,
+ &tag_11_contents_size,
+ &tag_11_packet_size,
+ max_packet_size);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "No valid "
+ "(ecryptfs-specific) literal "
+ "packet containing "
+ "authentication token "
+ "signature found after "
+ "tag 3 packet\n");
+ rc = -EIO;
+ goto out_wipe_list;
+ }
+ i += tag_11_packet_size;
+ if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {
+ ecryptfs_printk(KERN_ERR, "Expected "
+ "signature of size [%d]; "
+ "read size [%d]\n",
+ ECRYPTFS_SIG_SIZE,
+ tag_11_contents_size);
+ rc = -EIO;
+ goto out_wipe_list;
+ }
+ ecryptfs_to_hex(new_auth_tok->token.password.signature,
+ sig_tmp_space, tag_11_contents_size);
+ new_auth_tok->token.password.signature[
+ ECRYPTFS_PASSWORD_SIG_SIZE] = '\0';
+ ECRYPTFS_SET_FLAG(crypt_stat->flags,
+ ECRYPTFS_ENCRYPTED);
+ break;
+ case ECRYPTFS_TAG_11_PACKET_TYPE:
+ ecryptfs_printk(KERN_WARNING, "Invalid packet set "
+ "(Tag 11 not allowed by itself)\n");
+ rc = -EIO;
+ goto out_wipe_list;
+ break;
+ default:
+ ecryptfs_printk(KERN_DEBUG, "No packet at offset "
+ "[%d] of the file header; hex value of "
+ "character is [0x%.2x]\n", i, src[i]);
+ next_packet_is_auth_tok_packet = 0;
+ }
+ }
+ if (list_empty(&auth_tok_list)) {
+ rc = -EINVAL; /* Do not support non-encrypted files in
+ * the 0.1 release */
+ goto out;
+ }
+ /* If we have a global auth tok, then we should try to use
+ * it */
+ if (mount_crypt_stat->global_auth_tok) {
+ memcpy(sig, mount_crypt_stat->global_auth_tok_sig,
+ ECRYPTFS_SIG_SIZE_HEX);
+ chosen_auth_tok = mount_crypt_stat->global_auth_tok;
+ } else
+ BUG(); /* We should always have a global auth tok in
+ * the 0.1 release */
+ /* Scan list to see if our chosen_auth_tok works */
+ list_for_each(walker, &auth_tok_list) {
+ struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
+ auth_tok_list_item =
+ list_entry(walker, struct ecryptfs_auth_tok_list_item,
+ list);
+ candidate_auth_tok = &auth_tok_list_item->auth_tok;
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG,
+ "Considering cadidate auth tok:\n");
+ ecryptfs_dump_auth_tok(candidate_auth_tok);
+ }
+ /* TODO: Replace ECRYPTFS_SIG_SIZE_HEX w/ dynamic value */
+ if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD
+ && !strncmp(candidate_auth_tok->token.password.signature,
+ sig, ECRYPTFS_SIG_SIZE_HEX)) {
+ found_auth_tok = 1;
+ goto leave_list;
+ /* TODO: Transfer the common salt into the
+ * crypt_stat salt */
+ }
+ }
+leave_list:
+ if (!found_auth_tok) {
+ ecryptfs_printk(KERN_ERR, "Could not find authentication "
+ "token on temporary list for sig [%.*s]\n",
+ ECRYPTFS_SIG_SIZE_HEX, sig);
+ rc = -EIO;
+ goto out_wipe_list;
+ } else {
+ memcpy(&(candidate_auth_tok->token.password),
+ &(chosen_auth_tok->token.password),
+ sizeof(struct ecryptfs_password));
+ rc = decrypt_session_key(candidate_auth_tok, crypt_stat);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error decrypting the "
+ "session key\n");
+ goto out_wipe_list;
+ }
+ rc = ecryptfs_compute_root_iv(crypt_stat);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error computing "
+ "the root IV\n");
+ goto out_wipe_list;
+ }
+ }
+ rc = ecryptfs_init_crypt_ctx(crypt_stat);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error initializing crypto "
+ "context for cipher [%s]; rc = [%d]\n",
+ crypt_stat->cipher, rc);
+ }
+out_wipe_list:
+ wipe_auth_tok_list(&auth_tok_list);
+out:
+ return rc;
+}
+
+/**
+ * write_tag_11_packet
+ * @dest: Target into which Tag 11 packet is to be written
+ * @max: Maximum packet length
+ * @contents: Byte array of contents to copy in
+ * @contents_length: Number of bytes in contents
+ * @packet_length: Length of the Tag 11 packet written; zero on error
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length,
+ size_t *packet_length)
+{
+ int rc = 0;
+ size_t packet_size_length;
+
+ (*packet_length) = 0;
+ if ((13 + contents_length) > max) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "Packet length larger than "
+ "maximum allowable\n");
+ goto out;
+ }
+ /* General packet header */
+ /* Packet tag */
+ dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
+ /* Packet length */
+ rc = write_packet_length(&dest[(*packet_length)],
+ (13 + contents_length), &packet_size_length);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating tag 11 packet "
+ "header; cannot generate packet length\n");
+ goto out;
+ }
+ (*packet_length) += packet_size_length;
+ /* Tag 11 specific */
+ /* One-octet field that describes how the data is formatted */
+ dest[(*packet_length)++] = 0x62; /* binary data */
+ /* One-octet filename length followed by filename */
+ dest[(*packet_length)++] = 8;
+ memcpy(&dest[(*packet_length)], "_CONSOLE", 8);
+ (*packet_length) += 8;
+ /* Four-octet number indicating modification date */
+ memset(&dest[(*packet_length)], 0x00, 4);
+ (*packet_length) += 4;
+ /* Remainder is literal data */
+ memcpy(&dest[(*packet_length)], contents, contents_length);
+ (*packet_length) += contents_length;
+ out:
+ if (rc)
+ (*packet_length) = 0;
+ return rc;
+}
+
+/**
+ * write_tag_3_packet
+ * @dest: Buffer into which to write the packet
+ * @max: Maximum number of bytes that can be written
+ * @auth_tok: Authentication token
+ * @crypt_stat: The cryptographic context
+ * @key_rec: encrypted key
+ * @packet_size: This function will write the number of bytes that end
+ * up constituting the packet; set to zero on error
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int
+write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct ecryptfs_key_record *key_rec, size_t *packet_size)
+{
+ int rc = 0;
+
+ size_t i;
+ size_t signature_is_valid = 0;
+ size_t encrypted_session_key_valid = 0;
+ char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];
+ struct scatterlist dest_sg[2];
+ struct scatterlist src_sg[2];
+ struct crypto_tfm *tfm = NULL;
+ struct mutex *tfm_mutex = NULL;
+ size_t key_rec_size;
+ size_t packet_size_length;
+ size_t cipher_code;
+
+ (*packet_size) = 0;
+ /* Check for a valid signature on the auth_tok */
+ for (i = 0; i < ECRYPTFS_SIG_SIZE_HEX; i++)
+ signature_is_valid |= auth_tok->token.password.signature[i];
+ if (!signature_is_valid)
+ BUG();
+ ecryptfs_from_hex((*key_rec).sig, auth_tok->token.password.signature,
+ ECRYPTFS_SIG_SIZE);
+ encrypted_session_key_valid = 0;
+ for (i = 0; i < crypt_stat->key_size; i++)
+ encrypted_session_key_valid |=
+ auth_tok->session_key.encrypted_key[i];
+ if (encrypted_session_key_valid) {
+ memcpy((*key_rec).enc_key,
+ auth_tok->session_key.encrypted_key,
+ auth_tok->session_key.encrypted_key_size);
+ goto encrypted_session_key_set;
+ }
+ if (auth_tok->session_key.encrypted_key_size == 0)
+ auth_tok->session_key.encrypted_key_size =
+ crypt_stat->key_size;
+ if (crypt_stat->key_size == 24
+ && strcmp("aes", crypt_stat->cipher) == 0) {
+ memset((crypt_stat->key + 24), 0, 8);
+ auth_tok->session_key.encrypted_key_size = 32;
+ }
+ (*key_rec).enc_key_size =
+ auth_tok->session_key.encrypted_key_size;
+ if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags,
+ ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) {
+ ecryptfs_printk(KERN_DEBUG, "Using previously generated "
+ "session key encryption key of size [%d]\n",
+ auth_tok->token.password.
+ session_key_encryption_key_bytes);
+ memcpy(session_key_encryption_key,
+ auth_tok->token.password.session_key_encryption_key,
+ crypt_stat->key_size);
+ ecryptfs_printk(KERN_DEBUG,
+ "Cached session key " "encryption key: \n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex(session_key_encryption_key, 16);
+ }
+ if (unlikely(ecryptfs_verbosity > 0)) {
+ ecryptfs_printk(KERN_DEBUG, "Session key encryption key:\n");
+ ecryptfs_dump_hex(session_key_encryption_key, 16);
+ }
+ rc = virt_to_scatterlist(crypt_stat->key,
+ (*key_rec).enc_key_size, src_sg, 2);
+ if (!rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+ "for crypt_stat session key\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ rc = virt_to_scatterlist((*key_rec).enc_key,
+ (*key_rec).enc_key_size, dest_sg, 2);
+ if (!rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating scatterlist "
+ "for crypt_stat encrypted session key\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ if (!strcmp(crypt_stat->cipher,
+ crypt_stat->mount_crypt_stat->global_default_cipher_name)
+ && crypt_stat->mount_crypt_stat->global_key_tfm) {
+ tfm = crypt_stat->mount_crypt_stat->global_key_tfm;
+ tfm_mutex = &crypt_stat->mount_crypt_stat->global_key_tfm_mutex;
+ } else
+ tfm = crypto_alloc_tfm(crypt_stat->cipher, 0);
+ if (!tfm) {
+ ecryptfs_printk(KERN_ERR, "Could not initialize crypto "
+ "context for cipher [%s]\n",
+ crypt_stat->cipher);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (tfm_mutex)
+ mutex_lock(tfm_mutex);
+ rc = crypto_cipher_setkey(tfm, session_key_encryption_key,
+ crypt_stat->key_size);
+ if (rc < 0) {
+ if (tfm_mutex)
+ mutex_unlock(tfm_mutex);
+ ecryptfs_printk(KERN_ERR, "Error setting key for crypto "
+ "context\n");
+ goto out;
+ }
+ rc = 0;
+ ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",
+ crypt_stat->key_size);
+ crypto_cipher_encrypt(tfm, dest_sg, src_sg,
+ (*key_rec).enc_key_size);
+ if (tfm_mutex)
+ mutex_unlock(tfm_mutex);
+ ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n");
+ if (ecryptfs_verbosity > 0)
+ ecryptfs_dump_hex((*key_rec).enc_key,
+ (*key_rec).enc_key_size);
+encrypted_session_key_set:
+ /* Now we have a valid key_rec. Append it to the
+ * key_rec set. */
+ key_rec_size = (sizeof(struct ecryptfs_key_record)
+ - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES
+ + ((*key_rec).enc_key_size));
+ /* TODO: Include a packet size limit as a parameter to this
+ * function once we have multi-packet headers (for versions
+ * later than 0.1 */
+ if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) {
+ ecryptfs_printk(KERN_ERR, "Keyset too large\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ /* TODO: Packet size limit */
+ /* We have 5 bytes of surrounding packet data */
+ if ((0x05 + ECRYPTFS_SALT_SIZE
+ + (*key_rec).enc_key_size) >= max) {
+ ecryptfs_printk(KERN_ERR, "Authentication token is too "
+ "large\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ /* This format is inspired by OpenPGP; see RFC 2440
+ * packet tag 3 */
+ dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
+ /* ver+cipher+s2k+hash+salt+iter+enc_key */
+ rc = write_packet_length(&dest[(*packet_size)],
+ (0x05 + ECRYPTFS_SALT_SIZE
+ + (*key_rec).enc_key_size),
+ &packet_size_length);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error generating tag 3 packet "
+ "header; cannot generate packet length\n");
+ goto out;
+ }
+ (*packet_size) += packet_size_length;
+ dest[(*packet_size)++] = 0x04; /* version 4 */
+ cipher_code = ecryptfs_code_for_cipher_string(crypt_stat);
+ if (cipher_code == 0) {
+ ecryptfs_printk(KERN_WARNING, "Unable to generate code for "
+ "cipher [%s]\n", crypt_stat->cipher);
+ rc = -EINVAL;
+ goto out;
+ }
+ dest[(*packet_size)++] = cipher_code;
+ dest[(*packet_size)++] = 0x03; /* S2K */
+ dest[(*packet_size)++] = 0x01; /* MD5 (TODO: parameterize) */
+ memcpy(&dest[(*packet_size)], auth_tok->token.password.salt,
+ ECRYPTFS_SALT_SIZE);
+ (*packet_size) += ECRYPTFS_SALT_SIZE; /* salt */
+ dest[(*packet_size)++] = 0x60; /* hash iterations (65536) */
+ memcpy(&dest[(*packet_size)], (*key_rec).enc_key,
+ (*key_rec).enc_key_size);
+ (*packet_size) += (*key_rec).enc_key_size;
+out:
+ if (tfm && !tfm_mutex)
+ crypto_free_tfm(tfm);
+ if (rc)
+ (*packet_size) = 0;
+ return rc;
+}
+
+/**
+ * ecryptfs_generate_key_packet_set
+ * @dest: Virtual address from which to write the key record set
+ * @crypt_stat: The cryptographic context from which the
+ * authentication tokens will be retrieved
+ * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat
+ * for the global parameters
+ * @len: The amount written
+ * @max: The maximum amount of data allowed to be written
+ *
+ * Generates a key packet set and writes it to the virtual address
+ * passed in.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+int
+ecryptfs_generate_key_packet_set(char *dest_base,
+ struct ecryptfs_crypt_stat *crypt_stat,
+ struct dentry *ecryptfs_dentry, size_t *len,
+ size_t max)
+{
+ int rc = 0;
+ struct ecryptfs_auth_tok *auth_tok;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(
+ ecryptfs_dentry->d_sb)->mount_crypt_stat;
+ size_t written;
+ struct ecryptfs_key_record key_rec;
+
+ (*len) = 0;
+ if (mount_crypt_stat->global_auth_tok) {
+ auth_tok = mount_crypt_stat->global_auth_tok;
+ if (auth_tok->token_type == ECRYPTFS_PASSWORD) {
+ rc = write_tag_3_packet((dest_base + (*len)),
+ max, auth_tok,
+ crypt_stat, &key_rec,
+ &written);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error "
+ "writing tag 3 packet\n");
+ goto out;
+ }
+ (*len) += written;
+ /* Write auth tok signature packet */
+ rc = write_tag_11_packet(
+ (dest_base + (*len)),
+ (max - (*len)),
+ key_rec.sig, ECRYPTFS_SIG_SIZE, &written);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error writing "
+ "auth tok signature packet\n");
+ goto out;
+ }
+ (*len) += written;
+ } else {
+ ecryptfs_printk(KERN_WARNING, "Unsupported "
+ "authentication token type\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error writing "
+ "authentication token packet with sig "
+ "= [%s]\n",
+ mount_crypt_stat->global_auth_tok_sig);
+ rc = -EIO;
+ goto out;
+ }
+ } else
+ BUG();
+ if (likely((max - (*len)) > 0)) {
+ dest_base[(*len)] = 0x00;
+ } else {
+ ecryptfs_printk(KERN_ERR, "Error writing boundary byte\n");
+ rc = -EIO;
+ }
+out:
+ if (rc)
+ (*len) = 0;
+ return rc;
+}
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
new file mode 100644
index 000000000000..5938a232d11b
--- /dev/null
+++ b/fs/ecryptfs/main.c
@@ -0,0 +1,828 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.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/dcache.h>
+#include <linux/file.h>
+#include <linux/module.h>
+#include <linux/namei.h>
+#include <linux/skbuff.h>
+#include <linux/crypto.h>
+#include <linux/netlink.h>
+#include <linux/mount.h>
+#include <linux/dcache.h>
+#include <linux/pagemap.h>
+#include <linux/key.h>
+#include <linux/parser.h>
+#include "ecryptfs_kernel.h"
+
+/**
+ * Module parameter that defines the ecryptfs_verbosity level.
+ */
+int ecryptfs_verbosity = 0;
+
+module_param(ecryptfs_verbosity, int, 0);
+MODULE_PARM_DESC(ecryptfs_verbosity,
+ "Initial verbosity level (0 or 1; defaults to "
+ "0, which is Quiet)");
+
+void __ecryptfs_printk(const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (fmt[1] == '7') { /* KERN_DEBUG */
+ if (ecryptfs_verbosity >= 1)
+ vprintk(fmt, args);
+ } else
+ vprintk(fmt, args);
+ va_end(args);
+}
+
+/**
+ * ecryptfs_interpose
+ * @lower_dentry: Existing dentry in the lower filesystem
+ * @dentry: ecryptfs' dentry
+ * @sb: ecryptfs's super_block
+ * @flag: If set to true, then d_add is called, else d_instantiate is called
+ *
+ * Interposes upper and lower dentries.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
+ struct super_block *sb, int flag)
+{
+ struct inode *lower_inode;
+ struct inode *inode;
+ int rc = 0;
+
+ lower_inode = lower_dentry->d_inode;
+ if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {
+ rc = -EXDEV;
+ goto out;
+ }
+ if (!igrab(lower_inode)) {
+ rc = -ESTALE;
+ goto out;
+ }
+ inode = iget5_locked(sb, (unsigned long)lower_inode,
+ ecryptfs_inode_test, ecryptfs_inode_set,
+ lower_inode);
+ if (!inode) {
+ rc = -EACCES;
+ iput(lower_inode);
+ goto out;
+ }
+ if (inode->i_state & I_NEW)
+ unlock_new_inode(inode);
+ else
+ iput(lower_inode);
+ if (S_ISLNK(lower_inode->i_mode))
+ inode->i_op = &ecryptfs_symlink_iops;
+ else if (S_ISDIR(lower_inode->i_mode))
+ inode->i_op = &ecryptfs_dir_iops;
+ if (S_ISDIR(lower_inode->i_mode))
+ inode->i_fop = &ecryptfs_dir_fops;
+ if (special_file(lower_inode->i_mode))
+ init_special_inode(inode, lower_inode->i_mode,
+ lower_inode->i_rdev);
+ dentry->d_op = &ecryptfs_dops;
+ if (flag)
+ d_add(dentry, inode);
+ else
+ d_instantiate(dentry, inode);
+ ecryptfs_copy_attr_all(inode, lower_inode);
+ /* This size will be overwritten for real files w/ headers and
+ * other metadata */
+ ecryptfs_copy_inode_size(inode, lower_inode);
+out:
+ return rc;
+}
+
+enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug,
+ ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher,
+ ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes,
+ ecryptfs_opt_passthrough, ecryptfs_opt_err };
+
+static match_table_t tokens = {
+ {ecryptfs_opt_sig, "sig=%s"},
+ {ecryptfs_opt_ecryptfs_sig, "ecryptfs_sig=%s"},
+ {ecryptfs_opt_debug, "debug=%u"},
+ {ecryptfs_opt_ecryptfs_debug, "ecryptfs_debug=%u"},
+ {ecryptfs_opt_cipher, "cipher=%s"},
+ {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"},
+ {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"},
+ {ecryptfs_opt_passthrough, "ecryptfs_passthrough"},
+ {ecryptfs_opt_err, NULL}
+};
+
+/**
+ * ecryptfs_verify_version
+ * @version: The version number to confirm
+ *
+ * Returns zero on good version; non-zero otherwise
+ */
+static int ecryptfs_verify_version(u16 version)
+{
+ int rc = 0;
+ unsigned char major;
+ unsigned char minor;
+
+ major = ((version >> 8) & 0xFF);
+ minor = (version & 0xFF);
+ if (major != ECRYPTFS_VERSION_MAJOR) {
+ ecryptfs_printk(KERN_ERR, "Major version number mismatch. "
+ "Expected [%d]; got [%d]\n",
+ ECRYPTFS_VERSION_MAJOR, major);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (minor != ECRYPTFS_VERSION_MINOR) {
+ ecryptfs_printk(KERN_ERR, "Minor version number mismatch. "
+ "Expected [%d]; got [%d]\n",
+ ECRYPTFS_VERSION_MINOR, minor);
+ rc = -EINVAL;
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_parse_options
+ * @sb: The ecryptfs super block
+ * @options: The options pased to the kernel
+ *
+ * Parse mount options:
+ * debug=N - ecryptfs_verbosity level for debug output
+ * sig=XXX - description(signature) of the key to use
+ *
+ * Returns the dentry object of the lower-level (lower/interposed)
+ * directory; We want to mount our stackable file system on top of
+ * that lower directory.
+ *
+ * The signature of the key to use must be the description of a key
+ * already in the keyring. Mounting will fail if the key can not be
+ * found.
+ *
+ * Returns zero on success; non-zero on error
+ */
+static int ecryptfs_parse_options(struct super_block *sb, char *options)
+{
+ char *p;
+ int rc = 0;
+ int sig_set = 0;
+ int cipher_name_set = 0;
+ int cipher_key_bytes;
+ int cipher_key_bytes_set = 0;
+ struct key *auth_tok_key = NULL;
+ struct ecryptfs_auth_tok *auth_tok = NULL;
+ struct ecryptfs_mount_crypt_stat *mount_crypt_stat =
+ &ecryptfs_superblock_to_private(sb)->mount_crypt_stat;
+ substring_t args[MAX_OPT_ARGS];
+ int token;
+ char *sig_src;
+ char *sig_dst;
+ char *debug_src;
+ char *cipher_name_dst;
+ char *cipher_name_src;
+ char *cipher_key_bytes_src;
+ struct crypto_tfm *tmp_tfm;
+ int cipher_name_len;
+
+ if (!options) {
+ rc = -EINVAL;
+ goto out;
+ }
+ while ((p = strsep(&options, ",")) != NULL) {
+ if (!*p)
+ continue;
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case ecryptfs_opt_sig:
+ case ecryptfs_opt_ecryptfs_sig:
+ sig_src = args[0].from;
+ sig_dst =
+ mount_crypt_stat->global_auth_tok_sig;
+ memcpy(sig_dst, sig_src, ECRYPTFS_SIG_SIZE_HEX);
+ sig_dst[ECRYPTFS_SIG_SIZE_HEX] = '\0';
+ ecryptfs_printk(KERN_DEBUG,
+ "The mount_crypt_stat "
+ "global_auth_tok_sig set to: "
+ "[%s]\n", sig_dst);
+ sig_set = 1;
+ break;
+ case ecryptfs_opt_debug:
+ case ecryptfs_opt_ecryptfs_debug:
+ debug_src = args[0].from;
+ ecryptfs_verbosity =
+ (int)simple_strtol(debug_src, &debug_src,
+ 0);
+ ecryptfs_printk(KERN_DEBUG,
+ "Verbosity set to [%d]" "\n",
+ ecryptfs_verbosity);
+ break;
+ case ecryptfs_opt_cipher:
+ case ecryptfs_opt_ecryptfs_cipher:
+ cipher_name_src = args[0].from;
+ cipher_name_dst =
+ mount_crypt_stat->
+ global_default_cipher_name;
+ strncpy(cipher_name_dst, cipher_name_src,
+ ECRYPTFS_MAX_CIPHER_NAME_SIZE);
+ ecryptfs_printk(KERN_DEBUG,
+ "The mount_crypt_stat "
+ "global_default_cipher_name set to: "
+ "[%s]\n", cipher_name_dst);
+ cipher_name_set = 1;
+ break;
+ case ecryptfs_opt_ecryptfs_key_bytes:
+ cipher_key_bytes_src = args[0].from;
+ cipher_key_bytes =
+ (int)simple_strtol(cipher_key_bytes_src,
+ &cipher_key_bytes_src, 0);
+ mount_crypt_stat->global_default_cipher_key_size =
+ cipher_key_bytes;
+ ecryptfs_printk(KERN_DEBUG,
+ "The mount_crypt_stat "
+ "global_default_cipher_key_size "
+ "set to: [%d]\n", mount_crypt_stat->
+ global_default_cipher_key_size);
+ cipher_key_bytes_set = 1;
+ break;
+ case ecryptfs_opt_passthrough:
+ mount_crypt_stat->flags |=
+ ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED;
+ break;
+ case ecryptfs_opt_err:
+ default:
+ ecryptfs_printk(KERN_WARNING,
+ "eCryptfs: unrecognized option '%s'\n",
+ p);
+ }
+ }
+ /* Do not support lack of mount-wide signature in 0.1
+ * release */
+ if (!sig_set) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "You must supply a valid "
+ "passphrase auth tok signature as a mount "
+ "parameter; see the eCryptfs README\n");
+ goto out;
+ }
+ if (!cipher_name_set) {
+ cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);
+ if (unlikely(cipher_name_len
+ >= ECRYPTFS_MAX_CIPHER_NAME_SIZE)) {
+ rc = -EINVAL;
+ BUG();
+ goto out;
+ }
+ memcpy(mount_crypt_stat->global_default_cipher_name,
+ ECRYPTFS_DEFAULT_CIPHER, cipher_name_len);
+ mount_crypt_stat->global_default_cipher_name[cipher_name_len]
+ = '\0';
+ }
+ if (!cipher_key_bytes_set) {
+ mount_crypt_stat->global_default_cipher_key_size =
+ ECRYPTFS_DEFAULT_KEY_BYTES;
+ ecryptfs_printk(KERN_DEBUG, "Cipher key size was not "
+ "specified. Defaulting to [%d]\n",
+ mount_crypt_stat->
+ global_default_cipher_key_size);
+ }
+ rc = ecryptfs_process_cipher(
+ &tmp_tfm,
+ &mount_crypt_stat->global_key_tfm,
+ mount_crypt_stat->global_default_cipher_name,
+ mount_crypt_stat->global_default_cipher_key_size);
+ if (tmp_tfm)
+ crypto_free_tfm(tmp_tfm);
+ if (rc) {
+ printk(KERN_ERR "Error attempting to initialize cipher [%s] "
+ "with key size [%Zd] bytes; rc = [%d]\n",
+ mount_crypt_stat->global_default_cipher_name,
+ mount_crypt_stat->global_default_cipher_key_size, rc);
+ rc = -EINVAL;
+ goto out;
+ }
+ mutex_init(&mount_crypt_stat->global_key_tfm_mutex);
+ ecryptfs_printk(KERN_DEBUG, "Requesting the key with description: "
+ "[%s]\n", mount_crypt_stat->global_auth_tok_sig);
+ /* The reference to this key is held until umount is done The
+ * call to key_put is done in ecryptfs_put_super() */
+ auth_tok_key = request_key(&key_type_user,
+ mount_crypt_stat->global_auth_tok_sig,
+ NULL);
+ if (!auth_tok_key || IS_ERR(auth_tok_key)) {
+ ecryptfs_printk(KERN_ERR, "Could not find key with "
+ "description: [%s]\n",
+ mount_crypt_stat->global_auth_tok_sig);
+ process_request_key_err(PTR_ERR(auth_tok_key));
+ rc = -EINVAL;
+ goto out;
+ }
+ auth_tok = ecryptfs_get_key_payload_data(auth_tok_key);
+ if (ecryptfs_verify_version(auth_tok->version)) {
+ ecryptfs_printk(KERN_ERR, "Data structure version mismatch. "
+ "Userspace tools must match eCryptfs kernel "
+ "module with major version [%d] and minor "
+ "version [%d]\n", ECRYPTFS_VERSION_MAJOR,
+ ECRYPTFS_VERSION_MINOR);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (auth_tok->token_type != ECRYPTFS_PASSWORD) {
+ ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure "
+ "returned from key\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ mount_crypt_stat->global_auth_tok_key = auth_tok_key;
+ mount_crypt_stat->global_auth_tok = auth_tok;
+out:
+ return rc;
+}
+
+struct kmem_cache *ecryptfs_sb_info_cache;
+
+/**
+ * ecryptfs_fill_super
+ * @sb: The ecryptfs super block
+ * @raw_data: The options passed to mount
+ * @silent: Not used but required by function prototype
+ *
+ * Sets up what we can of the sb, rest is done in ecryptfs_read_super
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)
+{
+ int rc = 0;
+
+ /* Released in ecryptfs_put_super() */
+ ecryptfs_set_superblock_private(sb,
+ kmem_cache_alloc(ecryptfs_sb_info_cache,
+ SLAB_KERNEL));
+ if (!ecryptfs_superblock_to_private(sb)) {
+ ecryptfs_printk(KERN_WARNING, "Out of memory\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(ecryptfs_superblock_to_private(sb), 0,
+ sizeof(struct ecryptfs_sb_info));
+ sb->s_op = &ecryptfs_sops;
+ /* Released through deactivate_super(sb) from get_sb_nodev */
+ sb->s_root = d_alloc(NULL, &(const struct qstr) {
+ .hash = 0,.name = "/",.len = 1});
+ if (!sb->s_root) {
+ ecryptfs_printk(KERN_ERR, "d_alloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ sb->s_root->d_op = &ecryptfs_dops;
+ sb->s_root->d_sb = sb;
+ sb->s_root->d_parent = sb->s_root;
+ /* Released in d_release when dput(sb->s_root) is called */
+ /* through deactivate_super(sb) from get_sb_nodev() */
+ ecryptfs_set_dentry_private(sb->s_root,
+ kmem_cache_alloc(ecryptfs_dentry_info_cache,
+ SLAB_KERNEL));
+ if (!ecryptfs_dentry_to_private(sb->s_root)) {
+ ecryptfs_printk(KERN_ERR,
+ "dentry_info_cache alloc failed\n");
+ rc = -ENOMEM;
+ goto out;
+ }
+ memset(ecryptfs_dentry_to_private(sb->s_root), 0,
+ sizeof(struct ecryptfs_dentry_info));
+ rc = 0;
+out:
+ /* Should be able to rely on deactivate_super called from
+ * get_sb_nodev */
+ return rc;
+}
+
+/**
+ * ecryptfs_read_super
+ * @sb: The ecryptfs super block
+ * @dev_name: The path to mount over
+ *
+ * Read the super block of the lower filesystem, and use
+ * ecryptfs_interpose to create our initial inode and super block
+ * struct.
+ */
+static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)
+{
+ int rc;
+ struct nameidata nd;
+ struct dentry *lower_root;
+ struct vfsmount *lower_mnt;
+
+ memset(&nd, 0, sizeof(struct nameidata));
+ rc = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n");
+ goto out_free;
+ }
+ lower_root = nd.dentry;
+ if (!lower_root->d_inode) {
+ ecryptfs_printk(KERN_WARNING,
+ "No directory to interpose on\n");
+ rc = -ENOENT;
+ goto out_free;
+ }
+ lower_mnt = nd.mnt;
+ ecryptfs_set_superblock_lower(sb, lower_root->d_sb);
+ sb->s_maxbytes = lower_root->d_sb->s_maxbytes;
+ ecryptfs_set_dentry_lower(sb->s_root, lower_root);
+ ecryptfs_set_dentry_lower_mnt(sb->s_root, lower_mnt);
+ if ((rc = ecryptfs_interpose(lower_root, sb->s_root, sb, 0)))
+ goto out_free;
+ rc = 0;
+ goto out;
+out_free:
+ path_release(&nd);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_get_sb
+ * @fs_type
+ * @flags
+ * @dev_name: The path to mount over
+ * @raw_data: The options passed into the kernel
+ *
+ * The whole ecryptfs_get_sb process is broken into 4 functions:
+ * ecryptfs_parse_options(): handle options passed to ecryptfs, if any
+ * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block
+ * with as much information as it can before needing
+ * the lower filesystem.
+ * ecryptfs_read_super(): this accesses the lower filesystem and uses
+ * ecryptfs_interpolate to perform most of the linking
+ * ecryptfs_interpolate(): links the lower filesystem into ecryptfs
+ */
+static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *raw_data,
+ struct vfsmount *mnt)
+{
+ int rc;
+ struct super_block *sb;
+
+ rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt);
+ if (rc < 0) {
+ printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc);
+ goto out;
+ }
+ sb = mnt->mnt_sb;
+ rc = ecryptfs_parse_options(sb, raw_data);
+ if (rc) {
+ printk(KERN_ERR "Error parsing options; rc = [%d]\n", rc);
+ goto out_abort;
+ }
+ rc = ecryptfs_read_super(sb, dev_name);
+ if (rc) {
+ printk(KERN_ERR "Reading sb failed; rc = [%d]\n", rc);
+ goto out_abort;
+ }
+ goto out;
+out_abort:
+ dput(sb->s_root);
+ up_write(&sb->s_umount);
+ deactivate_super(sb);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_kill_block_super
+ * @sb: The ecryptfs super block
+ *
+ * Used to bring the superblock down and free the private data.
+ * Private data is free'd in ecryptfs_put_super()
+ */
+static void ecryptfs_kill_block_super(struct super_block *sb)
+{
+ generic_shutdown_super(sb);
+}
+
+static struct file_system_type ecryptfs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "ecryptfs",
+ .get_sb = ecryptfs_get_sb,
+ .kill_sb = ecryptfs_kill_block_super,
+ .fs_flags = 0
+};
+
+/**
+ * inode_info_init_once
+ *
+ * Initializes the ecryptfs_inode_info_cache when it is created
+ */
+static void
+inode_info_init_once(void *vptr, struct kmem_cache *cachep, unsigned long flags)
+{
+ struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;
+
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ei->vfs_inode);
+}
+
+static struct ecryptfs_cache_info {
+ kmem_cache_t **cache;
+ const char *name;
+ size_t size;
+ void (*ctor)(void*, struct kmem_cache *, unsigned long);
+} ecryptfs_cache_infos[] = {
+ {
+ .cache = &ecryptfs_auth_tok_list_item_cache,
+ .name = "ecryptfs_auth_tok_list_item",
+ .size = sizeof(struct ecryptfs_auth_tok_list_item),
+ },
+ {
+ .cache = &ecryptfs_file_info_cache,
+ .name = "ecryptfs_file_cache",
+ .size = sizeof(struct ecryptfs_file_info),
+ },
+ {
+ .cache = &ecryptfs_dentry_info_cache,
+ .name = "ecryptfs_dentry_info_cache",
+ .size = sizeof(struct ecryptfs_dentry_info),
+ },
+ {
+ .cache = &ecryptfs_inode_info_cache,
+ .name = "ecryptfs_inode_cache",
+ .size = sizeof(struct ecryptfs_inode_info),
+ .ctor = inode_info_init_once,
+ },
+ {
+ .cache = &ecryptfs_sb_info_cache,
+ .name = "ecryptfs_sb_cache",
+ .size = sizeof(struct ecryptfs_sb_info),
+ },
+ {
+ .cache = &ecryptfs_header_cache_0,
+ .name = "ecryptfs_headers_0",
+ .size = PAGE_CACHE_SIZE,
+ },
+ {
+ .cache = &ecryptfs_header_cache_1,
+ .name = "ecryptfs_headers_1",
+ .size = PAGE_CACHE_SIZE,
+ },
+ {
+ .cache = &ecryptfs_header_cache_2,
+ .name = "ecryptfs_headers_2",
+ .size = PAGE_CACHE_SIZE,
+ },
+ {
+ .cache = &ecryptfs_lower_page_cache,
+ .name = "ecryptfs_lower_page_cache",
+ .size = PAGE_CACHE_SIZE,
+ },
+};
+
+static void ecryptfs_free_kmem_caches(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
+ struct ecryptfs_cache_info *info;
+
+ info = &ecryptfs_cache_infos[i];
+ if (*(info->cache))
+ kmem_cache_destroy(*(info->cache));
+ }
+}
+
+/**
+ * ecryptfs_init_kmem_caches
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_init_kmem_caches(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {
+ struct ecryptfs_cache_info *info;
+
+ info = &ecryptfs_cache_infos[i];
+ *(info->cache) = kmem_cache_create(info->name, info->size,
+ 0, SLAB_HWCACHE_ALIGN, info->ctor, NULL);
+ if (!*(info->cache)) {
+ ecryptfs_free_kmem_caches();
+ ecryptfs_printk(KERN_WARNING, "%s: "
+ "kmem_cache_create failed\n",
+ info->name);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+struct ecryptfs_obj {
+ char *name;
+ struct list_head slot_list;
+ struct kobject kobj;
+};
+
+struct ecryptfs_attribute {
+ struct attribute attr;
+ ssize_t(*show) (struct ecryptfs_obj *, char *);
+ ssize_t(*store) (struct ecryptfs_obj *, const char *, size_t);
+};
+
+static ssize_t
+ecryptfs_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+ kobj);
+ struct ecryptfs_attribute *attribute =
+ container_of(attr, struct ecryptfs_attribute, attr);
+
+ return (attribute->store ? attribute->store(obj, buf, len) : 0);
+}
+
+static ssize_t
+ecryptfs_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+ struct ecryptfs_obj *obj = container_of(kobj, struct ecryptfs_obj,
+ kobj);
+ struct ecryptfs_attribute *attribute =
+ container_of(attr, struct ecryptfs_attribute, attr);
+
+ return (attribute->show ? attribute->show(obj, buf) : 0);
+}
+
+static struct sysfs_ops ecryptfs_sysfs_ops = {
+ .show = ecryptfs_attr_show,
+ .store = ecryptfs_attr_store
+};
+
+static struct kobj_type ecryptfs_ktype = {
+ .sysfs_ops = &ecryptfs_sysfs_ops
+};
+
+static decl_subsys(ecryptfs, &ecryptfs_ktype, NULL);
+
+static ssize_t version_show(struct ecryptfs_obj *obj, char *buff)
+{
+ return snprintf(buff, PAGE_SIZE, "%d\n", ECRYPTFS_VERSIONING_MASK);
+}
+
+static struct ecryptfs_attribute sysfs_attr_version = __ATTR_RO(version);
+
+struct ecryptfs_version_str_map_elem {
+ u32 flag;
+ char *str;
+} ecryptfs_version_str_map[] = {
+ {ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"},
+ {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"},
+ {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"},
+ {ECRYPTFS_VERSIONING_POLICY, "policy"}
+};
+
+static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff)
+{
+ int i;
+ int remaining = PAGE_SIZE;
+ int total_written = 0;
+
+ buff[0] = '\0';
+ for (i = 0; i < ARRAY_SIZE(ecryptfs_version_str_map); i++) {
+ int entry_size;
+
+ if (!(ECRYPTFS_VERSIONING_MASK
+ & ecryptfs_version_str_map[i].flag))
+ continue;
+ entry_size = strlen(ecryptfs_version_str_map[i].str);
+ if ((entry_size + 2) > remaining)
+ goto out;
+ memcpy(buff, ecryptfs_version_str_map[i].str, entry_size);
+ buff[entry_size++] = '\n';
+ buff[entry_size] = '\0';
+ buff += entry_size;
+ total_written += entry_size;
+ remaining -= entry_size;
+ }
+out:
+ return total_written;
+}
+
+static struct ecryptfs_attribute sysfs_attr_version_str = __ATTR_RO(version_str);
+
+static int do_sysfs_registration(void)
+{
+ int rc;
+
+ if ((rc = subsystem_register(&ecryptfs_subsys))) {
+ printk(KERN_ERR
+ "Unable to register ecryptfs sysfs subsystem\n");
+ goto out;
+ }
+ rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version.attr);
+ if (rc) {
+ printk(KERN_ERR
+ "Unable to create ecryptfs version attribute\n");
+ subsystem_unregister(&ecryptfs_subsys);
+ goto out;
+ }
+ rc = sysfs_create_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version_str.attr);
+ if (rc) {
+ printk(KERN_ERR
+ "Unable to create ecryptfs version_str attribute\n");
+ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version.attr);
+ subsystem_unregister(&ecryptfs_subsys);
+ goto out;
+ }
+out:
+ return rc;
+}
+
+static int __init ecryptfs_init(void)
+{
+ int rc;
+
+ if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_CACHE_SIZE) {
+ rc = -EINVAL;
+ ecryptfs_printk(KERN_ERR, "The eCryptfs extent size is "
+ "larger than the host's page size, and so "
+ "eCryptfs cannot run on this system. The "
+ "default eCryptfs extent size is [%d] bytes; "
+ "the page size is [%d] bytes.\n",
+ ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE);
+ goto out;
+ }
+ rc = ecryptfs_init_kmem_caches();
+ if (rc) {
+ printk(KERN_ERR
+ "Failed to allocate one or more kmem_cache objects\n");
+ goto out;
+ }
+ rc = register_filesystem(&ecryptfs_fs_type);
+ if (rc) {
+ printk(KERN_ERR "Failed to register filesystem\n");
+ ecryptfs_free_kmem_caches();
+ goto out;
+ }
+ kset_set_kset_s(&ecryptfs_subsys, fs_subsys);
+ sysfs_attr_version.attr.owner = THIS_MODULE;
+ sysfs_attr_version_str.attr.owner = THIS_MODULE;
+ rc = do_sysfs_registration();
+ if (rc) {
+ printk(KERN_ERR "sysfs registration failed\n");
+ unregister_filesystem(&ecryptfs_fs_type);
+ ecryptfs_free_kmem_caches();
+ goto out;
+ }
+out:
+ return rc;
+}
+
+static void __exit ecryptfs_exit(void)
+{
+ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version.attr);
+ sysfs_remove_file(&ecryptfs_subsys.kset.kobj,
+ &sysfs_attr_version_str.attr);
+ subsystem_unregister(&ecryptfs_subsys);
+ unregister_filesystem(&ecryptfs_fs_type);
+ ecryptfs_free_kmem_caches();
+}
+
+MODULE_AUTHOR("Michael A. Halcrow <mhalcrow@us.ibm.com>");
+MODULE_DESCRIPTION("eCryptfs");
+
+MODULE_LICENSE("GPL");
+
+module_init(ecryptfs_init)
+module_exit(ecryptfs_exit)
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
new file mode 100644
index 000000000000..924dd90a4cf5
--- /dev/null
+++ b/fs/ecryptfs/mmap.c
@@ -0,0 +1,788 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ * This is where eCryptfs coordinates the symmetric encryption and
+ * decryption of the file data as it passes between the lower
+ * encrypted file and the upper decrypted file.
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.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/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/page-flags.h>
+#include <linux/mount.h>
+#include <linux/file.h>
+#include <linux/crypto.h>
+#include <linux/scatterlist.h>
+#include "ecryptfs_kernel.h"
+
+struct kmem_cache *ecryptfs_lower_page_cache;
+
+/**
+ * ecryptfs_get1page
+ *
+ * Get one page from cache or lower f/s, return error otherwise.
+ *
+ * Returns unlocked and up-to-date page (if ok), with increased
+ * refcnt.
+ */
+static struct page *ecryptfs_get1page(struct file *file, int index)
+{
+ struct page *page;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct address_space *mapping;
+
+ dentry = file->f_dentry;
+ inode = dentry->d_inode;
+ mapping = inode->i_mapping;
+ page = read_cache_page(mapping, index,
+ (filler_t *)mapping->a_ops->readpage,
+ (void *)file);
+ if (IS_ERR(page))
+ goto out;
+ wait_on_page_locked(page);
+out:
+ return page;
+}
+
+static
+int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros);
+
+/**
+ * ecryptfs_fill_zeros
+ * @file: The ecryptfs file
+ * @new_length: The new length of the data in the underlying file;
+ * everything between the prior end of the file and the
+ * new end of the file will be filled with zero's.
+ * new_length must be greater than current length
+ *
+ * Function for handling lseek-ing past the end of the file.
+ *
+ * This function does not support shrinking, only growing a file.
+ *
+ * Returns zero on success; non-zero otherwise.
+ */
+int ecryptfs_fill_zeros(struct file *file, loff_t new_length)
+{
+ int rc = 0;
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ pgoff_t old_end_page_index = 0;
+ pgoff_t index = old_end_page_index;
+ int old_end_pos_in_page = -1;
+ pgoff_t new_end_page_index;
+ int new_end_pos_in_page;
+ loff_t cur_length = i_size_read(inode);
+
+ if (cur_length != 0) {
+ index = old_end_page_index =
+ ((cur_length - 1) >> PAGE_CACHE_SHIFT);
+ old_end_pos_in_page = ((cur_length - 1) & ~PAGE_CACHE_MASK);
+ }
+ new_end_page_index = ((new_length - 1) >> PAGE_CACHE_SHIFT);
+ new_end_pos_in_page = ((new_length - 1) & ~PAGE_CACHE_MASK);
+ ecryptfs_printk(KERN_DEBUG, "old_end_page_index = [0x%.16x]; "
+ "old_end_pos_in_page = [%d]; "
+ "new_end_page_index = [0x%.16x]; "
+ "new_end_pos_in_page = [%d]\n",
+ old_end_page_index, old_end_pos_in_page,
+ new_end_page_index, new_end_pos_in_page);
+ if (old_end_page_index == new_end_page_index) {
+ /* Start and end are in the same page; we just need to
+ * set a portion of the existing page to zero's */
+ rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+ (new_end_pos_in_page - old_end_pos_in_page));
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+ "index=[0x%.16x], "
+ "old_end_pos_in_page=[d], "
+ "(PAGE_CACHE_SIZE - new_end_pos_in_page"
+ "=[%d]"
+ ")=[d]) returned [%d]\n", file, index,
+ old_end_pos_in_page,
+ new_end_pos_in_page,
+ (PAGE_CACHE_SIZE - new_end_pos_in_page),
+ rc);
+ goto out;
+ }
+ /* Fill the remainder of the previous last page with zeros */
+ rc = write_zeros(file, index, (old_end_pos_in_page + 1),
+ ((PAGE_CACHE_SIZE - 1) - old_end_pos_in_page));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+ "index=[0x%.16x], old_end_pos_in_page=[d], "
+ "(PAGE_CACHE_SIZE - old_end_pos_in_page)=[d]) "
+ "returned [%d]\n", file, index,
+ old_end_pos_in_page,
+ (PAGE_CACHE_SIZE - old_end_pos_in_page), rc);
+ goto out;
+ }
+ index++;
+ while (index < new_end_page_index) {
+ /* Fill all intermediate pages with zeros */
+ rc = write_zeros(file, index, 0, PAGE_CACHE_SIZE);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "write_zeros(file=[%p], "
+ "index=[0x%.16x], "
+ "old_end_pos_in_page=[d], "
+ "(PAGE_CACHE_SIZE - new_end_pos_in_page"
+ "=[%d]"
+ ")=[d]) returned [%d]\n", file, index,
+ old_end_pos_in_page,
+ new_end_pos_in_page,
+ (PAGE_CACHE_SIZE - new_end_pos_in_page),
+ rc);
+ goto out;
+ }
+ index++;
+ }
+ /* Fill the portion at the beginning of the last new page with
+ * zero's */
+ rc = write_zeros(file, index, 0, (new_end_pos_in_page + 1));
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "write_zeros(file="
+ "[%p], index=[0x%.16x], 0, "
+ "new_end_pos_in_page=[%d]"
+ "returned [%d]\n", file, index,
+ new_end_pos_in_page, rc);
+ goto out;
+ }
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_writepage
+ * @page: Page that is locked before this call is made
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct ecryptfs_page_crypt_context ctx;
+ int rc;
+
+ ctx.page = page;
+ ctx.mode = ECRYPTFS_WRITEPAGE_MODE;
+ ctx.param.wbc = wbc;
+ rc = ecryptfs_encrypt_page(&ctx);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error encrypting "
+ "page (upper index [0x%.16x])\n", page->index);
+ ClearPageUptodate(page);
+ goto out;
+ }
+ SetPageUptodate(page);
+ unlock_page(page);
+out:
+ return rc;
+}
+
+/**
+ * Reads the data from the lower file file at index lower_page_index
+ * and copies that data into page.
+ *
+ * @param page Page to fill
+ * @param lower_page_index Index of the page in the lower file to get
+ */
+int ecryptfs_do_readpage(struct file *file, struct page *page,
+ pgoff_t lower_page_index)
+{
+ int rc;
+ struct dentry *dentry;
+ struct file *lower_file;
+ struct dentry *lower_dentry;
+ struct inode *inode;
+ struct inode *lower_inode;
+ char *page_data;
+ struct page *lower_page = NULL;
+ char *lower_page_data;
+ const struct address_space_operations *lower_a_ops;
+
+ dentry = file->f_dentry;
+ lower_file = ecryptfs_file_to_lower(file);
+ lower_dentry = ecryptfs_dentry_to_lower(dentry);
+ inode = dentry->d_inode;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ lower_a_ops = lower_inode->i_mapping->a_ops;
+ lower_page = read_cache_page(lower_inode->i_mapping, lower_page_index,
+ (filler_t *)lower_a_ops->readpage,
+ (void *)lower_file);
+ if (IS_ERR(lower_page)) {
+ rc = PTR_ERR(lower_page);
+ lower_page = NULL;
+ ecryptfs_printk(KERN_ERR, "Error reading from page cache\n");
+ goto out;
+ }
+ wait_on_page_locked(lower_page);
+ page_data = (char *)kmap(page);
+ if (!page_data) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error mapping page\n");
+ goto out;
+ }
+ lower_page_data = (char *)kmap(lower_page);
+ if (!lower_page_data) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_ERR, "Error mapping page\n");
+ kunmap(page);
+ goto out;
+ }
+ memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE);
+ kunmap(lower_page);
+ kunmap(page);
+ rc = 0;
+out:
+ if (likely(lower_page))
+ page_cache_release(lower_page);
+ if (rc == 0)
+ SetPageUptodate(page);
+ else
+ ClearPageUptodate(page);
+ return rc;
+}
+
+/**
+ * ecryptfs_readpage
+ * @file: This is an ecryptfs file
+ * @page: ecryptfs associated page to stick the read data into
+ *
+ * Read in a page, decrypting if necessary.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+static int ecryptfs_readpage(struct file *file, struct page *page)
+{
+ int rc = 0;
+ struct ecryptfs_crypt_stat *crypt_stat;
+
+ BUG_ON(!(file && file->f_dentry && file->f_dentry->d_inode));
+ crypt_stat =
+ &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+ if (!crypt_stat
+ || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)
+ || ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
+ ecryptfs_printk(KERN_DEBUG,
+ "Passing through unencrypted page\n");
+ rc = ecryptfs_do_readpage(file, page, page->index);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error reading page; rc = "
+ "[%d]\n", rc);
+ goto out;
+ }
+ } else {
+ rc = ecryptfs_decrypt_page(file, page);
+ if (rc) {
+
+ ecryptfs_printk(KERN_ERR, "Error decrypting page; "
+ "rc = [%d]\n", rc);
+ goto out;
+ }
+ }
+ SetPageUptodate(page);
+out:
+ if (rc)
+ ClearPageUptodate(page);
+ ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
+ page->index);
+ unlock_page(page);
+ return rc;
+}
+
+static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)
+{
+ struct inode *inode = page->mapping->host;
+ int end_byte_in_page;
+ int rc = 0;
+ char *page_virt;
+
+ if ((i_size_read(inode) / PAGE_CACHE_SIZE) == page->index) {
+ end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;
+ if (to > end_byte_in_page)
+ end_byte_in_page = to;
+ page_virt = kmap(page);
+ if (!page_virt) {
+ rc = -ENOMEM;
+ ecryptfs_printk(KERN_WARNING,
+ "Could not map page\n");
+ goto out;
+ }
+ memset((page_virt + end_byte_in_page), 0,
+ (PAGE_CACHE_SIZE - end_byte_in_page));
+ kunmap(page);
+ }
+out:
+ return rc;
+}
+
+static int ecryptfs_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ int rc = 0;
+
+ kmap(page);
+ if (from == 0 && to == PAGE_CACHE_SIZE)
+ goto out; /* If we are writing a full page, it will be
+ up to date. */
+ if (!PageUptodate(page))
+ rc = ecryptfs_do_readpage(file, page, page->index);
+out:
+ return rc;
+}
+
+int ecryptfs_grab_and_map_lower_page(struct page **lower_page,
+ char **lower_virt,
+ struct inode *lower_inode,
+ unsigned long lower_page_index)
+{
+ int rc = 0;
+
+ (*lower_page) = grab_cache_page(lower_inode->i_mapping,
+ lower_page_index);
+ if (!(*lower_page)) {
+ ecryptfs_printk(KERN_ERR, "grab_cache_page for "
+ "lower_page_index = [0x%.16x] failed\n",
+ lower_page_index);
+ rc = -EINVAL;
+ goto out;
+ }
+ if (lower_virt)
+ (*lower_virt) = kmap((*lower_page));
+ else
+ kmap((*lower_page));
+out:
+ return rc;
+}
+
+int ecryptfs_writepage_and_release_lower_page(struct page *lower_page,
+ struct inode *lower_inode,
+ struct writeback_control *wbc)
+{
+ int rc = 0;
+
+ rc = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error calling lower writepage(); "
+ "rc = [%d]\n", rc);
+ goto out;
+ }
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ page_cache_release(lower_page);
+out:
+ return rc;
+}
+
+static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page)
+{
+ kunmap(lower_page);
+ ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = "
+ "[0x%.16x]\n", lower_page->index);
+ unlock_page(lower_page);
+ page_cache_release(lower_page);
+}
+
+/**
+ * ecryptfs_write_inode_size_to_header
+ *
+ * Writes the lower file size to the first 8 bytes of the header.
+ *
+ * Returns zero on success; non-zero on error.
+ */
+int
+ecryptfs_write_inode_size_to_header(struct file *lower_file,
+ struct inode *lower_inode,
+ struct inode *inode)
+{
+ int rc = 0;
+ struct page *header_page;
+ char *header_virt;
+ const struct address_space_operations *lower_a_ops;
+ u64 file_size;
+
+ rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt,
+ lower_inode, 0);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "grab_cache_page for header page "
+ "failed\n");
+ goto out;
+ }
+ lower_a_ops = lower_inode->i_mapping->a_ops;
+ rc = lower_a_ops->prepare_write(lower_file, header_page, 0, 8);
+ file_size = (u64)i_size_read(inode);
+ ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size);
+ file_size = cpu_to_be64(file_size);
+ memcpy(header_virt, &file_size, sizeof(u64));
+ rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8);
+ if (rc < 0)
+ ecryptfs_printk(KERN_ERR, "Error commiting header page "
+ "write\n");
+ ecryptfs_unmap_and_release_lower_page(header_page);
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+out:
+ return rc;
+}
+
+int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode,
+ struct file *lower_file,
+ unsigned long lower_page_index, int byte_offset,
+ int region_bytes)
+{
+ int rc = 0;
+
+ rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, lower_inode,
+ lower_page_index);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to grab and map "
+ "lower page with index [0x%.16x]\n",
+ lower_page_index);
+ goto out;
+ }
+ rc = lower_inode->i_mapping->a_ops->prepare_write(lower_file,
+ (*lower_page),
+ byte_offset,
+ region_bytes);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "prepare_write for "
+ "lower_page_index = [0x%.16x] failed; rc = "
+ "[%d]\n", lower_page_index, rc);
+ }
+out:
+ if (rc && (*lower_page)) {
+ ecryptfs_unmap_and_release_lower_page(*lower_page);
+ (*lower_page) = NULL;
+ }
+ return rc;
+}
+
+/**
+ * ecryptfs_commit_lower_page
+ *
+ * Returns zero on success; non-zero on error
+ */
+int
+ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode,
+ struct file *lower_file, int byte_offset,
+ int region_size)
+{
+ int rc = 0;
+
+ rc = lower_inode->i_mapping->a_ops->commit_write(
+ lower_file, lower_page, byte_offset, region_size);
+ if (rc < 0) {
+ ecryptfs_printk(KERN_ERR,
+ "Error committing write; rc = [%d]\n", rc);
+ } else
+ rc = 0;
+ ecryptfs_unmap_and_release_lower_page(lower_page);
+ return rc;
+}
+
+/**
+ * ecryptfs_copy_page_to_lower
+ *
+ * Used for plaintext pass-through; no page index interpolation
+ * required.
+ */
+int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode,
+ struct file *lower_file)
+{
+ int rc = 0;
+ struct page *lower_page;
+
+ rc = ecryptfs_get_lower_page(&lower_page, lower_inode, lower_file,
+ page->index, 0, PAGE_CACHE_SIZE);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to get page "
+ "at index [0x%.16x]\n", page->index);
+ goto out;
+ }
+ /* TODO: aops */
+ memcpy((char *)page_address(lower_page), page_address(page),
+ PAGE_CACHE_SIZE);
+ rc = ecryptfs_commit_lower_page(lower_page, lower_inode, lower_file,
+ 0, PAGE_CACHE_SIZE);
+ if (rc)
+ ecryptfs_printk(KERN_ERR, "Error attempting to commit page "
+ "at index [0x%.16x]\n", page->index);
+out:
+ return rc;
+}
+
+static int
+process_new_file(struct ecryptfs_crypt_stat *crypt_stat,
+ struct file *file, struct inode *inode)
+{
+ struct page *header_page;
+ const struct address_space_operations *lower_a_ops;
+ struct inode *lower_inode;
+ struct file *lower_file;
+ char *header_virt;
+ int rc = 0;
+ int current_header_page = 0;
+ int header_pages;
+ int more_header_data_to_be_written = 1;
+
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ lower_file = ecryptfs_file_to_lower(file);
+ lower_a_ops = lower_inode->i_mapping->a_ops;
+ header_pages = ((crypt_stat->header_extent_size
+ * crypt_stat->num_header_extents_at_front)
+ / PAGE_CACHE_SIZE);
+ BUG_ON(header_pages < 1);
+ while (current_header_page < header_pages) {
+ rc = ecryptfs_grab_and_map_lower_page(&header_page,
+ &header_virt,
+ lower_inode,
+ current_header_page);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "grab_cache_page for "
+ "header page [%d] failed; rc = [%d]\n",
+ current_header_page, rc);
+ goto out;
+ }
+ rc = lower_a_ops->prepare_write(lower_file, header_page, 0,
+ PAGE_CACHE_SIZE);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error preparing to write "
+ "header page out; rc = [%d]\n", rc);
+ goto out;
+ }
+ memset(header_virt, 0, PAGE_CACHE_SIZE);
+ if (more_header_data_to_be_written) {
+ rc = ecryptfs_write_headers_virt(header_virt,
+ crypt_stat,
+ file->f_dentry);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error "
+ "generating header; rc = "
+ "[%d]\n", rc);
+ rc = -EIO;
+ memset(header_virt, 0, PAGE_CACHE_SIZE);
+ ecryptfs_unmap_and_release_lower_page(
+ header_page);
+ goto out;
+ }
+ if (current_header_page == 0)
+ memset(header_virt, 0, 8);
+ more_header_data_to_be_written = 0;
+ }
+ rc = lower_a_ops->commit_write(lower_file, header_page, 0,
+ PAGE_CACHE_SIZE);
+ ecryptfs_unmap_and_release_lower_page(header_page);
+ if (rc < 0) {
+ ecryptfs_printk(KERN_ERR,
+ "Error commiting header page write; "
+ "rc = [%d]\n", rc);
+ break;
+ }
+ current_header_page++;
+ }
+ if (rc >= 0) {
+ rc = 0;
+ ecryptfs_printk(KERN_DEBUG, "lower_inode->i_blocks = "
+ "[0x%.16x]\n", lower_inode->i_blocks);
+ i_size_write(inode, 0);
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+ }
+ ecryptfs_printk(KERN_DEBUG, "Clearing ECRYPTFS_NEW_FILE flag in "
+ "crypt_stat at memory location [%p]\n", crypt_stat);
+ ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_commit_write
+ * @file: The eCryptfs file object
+ * @page: The eCryptfs page
+ * @from: Ignored (we rotate the page IV on each write)
+ * @to: Ignored
+ *
+ * This is where we encrypt the data and pass the encrypted data to
+ * the lower filesystem. In OpenPGP-compatible mode, we operate on
+ * entire underlying packets.
+ */
+static int ecryptfs_commit_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ struct ecryptfs_page_crypt_context ctx;
+ loff_t pos;
+ struct inode *inode;
+ struct inode *lower_inode;
+ struct file *lower_file;
+ struct ecryptfs_crypt_stat *crypt_stat;
+ int rc;
+
+ inode = page->mapping->host;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ lower_file = ecryptfs_file_to_lower(file);
+ mutex_lock(&lower_inode->i_mutex);
+ crypt_stat =
+ &ecryptfs_inode_to_private(file->f_dentry->d_inode)->crypt_stat;
+ if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) {
+ ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in "
+ "crypt_stat at memory location [%p]\n", crypt_stat);
+ rc = process_new_file(crypt_stat, file, inode);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error processing new "
+ "file; rc = [%d]\n", rc);
+ goto out;
+ }
+ } else
+ ecryptfs_printk(KERN_DEBUG, "Not a new file\n");
+ ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page"
+ "(page w/ index = [0x%.16x], to = [%d])\n", page->index,
+ to);
+ rc = fill_zeros_to_end_of_page(page, to);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error attempting to fill "
+ "zeros in page with index = [0x%.16x]\n",
+ page->index);
+ goto out;
+ }
+ ctx.page = page;
+ ctx.mode = ECRYPTFS_PREPARE_COMMIT_MODE;
+ ctx.param.lower_file = lower_file;
+ rc = ecryptfs_encrypt_page(&ctx);
+ if (rc) {
+ ecryptfs_printk(KERN_WARNING, "Error encrypting page (upper "
+ "index [0x%.16x])\n", page->index);
+ goto out;
+ }
+ rc = 0;
+ inode->i_blocks = lower_inode->i_blocks;
+ pos = (page->index << PAGE_CACHE_SHIFT) + to;
+ if (pos > i_size_read(inode)) {
+ i_size_write(inode, pos);
+ ecryptfs_printk(KERN_DEBUG, "Expanded file size to "
+ "[0x%.16x]\n", i_size_read(inode));
+ }
+ ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode);
+ lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty_sync(inode);
+out:
+ kunmap(page); /* mapped in prior call (prepare_write) */
+ if (rc < 0)
+ ClearPageUptodate(page);
+ else
+ SetPageUptodate(page);
+ mutex_unlock(&lower_inode->i_mutex);
+ return rc;
+}
+
+/**
+ * write_zeros
+ * @file: The ecryptfs file
+ * @index: The index in which we are writing
+ * @start: The position after the last block of data
+ * @num_zeros: The number of zeros to write
+ *
+ * Write a specified number of zero's to a page.
+ *
+ * (start + num_zeros) must be less than or equal to PAGE_CACHE_SIZE
+ */
+static
+int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros)
+{
+ int rc = 0;
+ struct page *tmp_page;
+
+ tmp_page = ecryptfs_get1page(file, index);
+ if (IS_ERR(tmp_page)) {
+ ecryptfs_printk(KERN_ERR, "Error getting page at index "
+ "[0x%.16x]\n", index);
+ rc = PTR_ERR(tmp_page);
+ goto out;
+ }
+ kmap(tmp_page);
+ rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros);
+ if (rc) {
+ ecryptfs_printk(KERN_ERR, "Error preparing to write zero's "
+ "to remainder of page at index [0x%.16x]\n",
+ index);
+ kunmap(tmp_page);
+ page_cache_release(tmp_page);
+ goto out;
+ }
+ memset(((char *)page_address(tmp_page) + start), 0, num_zeros);
+ rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros);
+ if (rc < 0) {
+ ecryptfs_printk(KERN_ERR, "Error attempting to write zero's "
+ "to remainder of page at index [0x%.16x]\n",
+ index);
+ kunmap(tmp_page);
+ page_cache_release(tmp_page);
+ goto out;
+ }
+ rc = 0;
+ kunmap(tmp_page);
+ page_cache_release(tmp_page);
+out:
+ return rc;
+}
+
+static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)
+{
+ int rc = 0;
+ struct inode *inode;
+ struct inode *lower_inode;
+
+ inode = (struct inode *)mapping->host;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ if (lower_inode->i_mapping->a_ops->bmap)
+ rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,
+ block);
+ return rc;
+}
+
+static void ecryptfs_sync_page(struct page *page)
+{
+ struct inode *inode;
+ struct inode *lower_inode;
+ struct page *lower_page;
+
+ inode = page->mapping->host;
+ lower_inode = ecryptfs_inode_to_lower(inode);
+ /* NOTE: Recently swapped with grab_cache_page(), since
+ * sync_page() just makes sure that pending I/O gets done. */
+ lower_page = find_lock_page(lower_inode->i_mapping, page->index);
+ if (!lower_page) {
+ ecryptfs_printk(KERN_DEBUG, "find_lock_page failed\n");
+ return;
+ }
+ lower_page->mapping->a_ops->sync_page(lower_page);
+ ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16x]\n",
+ lower_page->index);
+ unlock_page(lower_page);
+ page_cache_release(lower_page);
+}
+
+struct address_space_operations ecryptfs_aops = {
+ .writepage = ecryptfs_writepage,
+ .readpage = ecryptfs_readpage,
+ .prepare_write = ecryptfs_prepare_write,
+ .commit_write = ecryptfs_commit_write,
+ .bmap = ecryptfs_bmap,
+ .sync_page = ecryptfs_sync_page,
+};
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c
new file mode 100644
index 000000000000..c337c0410fb1
--- /dev/null
+++ b/fs/ecryptfs/super.c
@@ -0,0 +1,198 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 1997-2003 Erez Zadok
+ * Copyright (C) 2001-2003 Stony Brook University
+ * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
+ * Michael C. Thompson <mcthomps@us.ibm.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/fs.h>
+#include <linux/mount.h>
+#include <linux/key.h>
+#include <linux/seq_file.h>
+#include <linux/crypto.h>
+#include "ecryptfs_kernel.h"
+
+struct kmem_cache *ecryptfs_inode_info_cache;
+
+/**
+ * ecryptfs_alloc_inode - allocate an ecryptfs inode
+ * @sb: Pointer to the ecryptfs super block
+ *
+ * Called to bring an inode into existence.
+ *
+ * Only handle allocation, setting up structures should be done in
+ * ecryptfs_read_inode. This is because the kernel, between now and
+ * then, will 0 out the private data pointer.
+ *
+ * Returns a pointer to a newly allocated inode, NULL otherwise
+ */
+static struct inode *ecryptfs_alloc_inode(struct super_block *sb)
+{
+ struct ecryptfs_inode_info *ecryptfs_inode;
+ struct inode *inode = NULL;
+
+ ecryptfs_inode = kmem_cache_alloc(ecryptfs_inode_info_cache,
+ SLAB_KERNEL);
+ if (unlikely(!ecryptfs_inode))
+ goto out;
+ ecryptfs_init_crypt_stat(&ecryptfs_inode->crypt_stat);
+ inode = &ecryptfs_inode->vfs_inode;
+out:
+ return inode;
+}
+
+/**
+ * ecryptfs_destroy_inode
+ * @inode: The ecryptfs inode
+ *
+ * This is used during the final destruction of the inode.
+ * All allocation of memory related to the inode, including allocated
+ * memory in the crypt_stat struct, will be released here.
+ * There should be no chance that this deallocation will be missed.
+ */
+static void ecryptfs_destroy_inode(struct inode *inode)
+{
+ struct ecryptfs_inode_info *inode_info;
+
+ inode_info = ecryptfs_inode_to_private(inode);
+ ecryptfs_destruct_crypt_stat(&inode_info->crypt_stat);
+ kmem_cache_free(ecryptfs_inode_info_cache, inode_info);
+}
+
+/**
+ * ecryptfs_init_inode
+ * @inode: The ecryptfs inode
+ *
+ * Set up the ecryptfs inode.
+ */
+void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)
+{
+ ecryptfs_set_inode_lower(inode, lower_inode);
+ inode->i_ino = lower_inode->i_ino;
+ inode->i_version++;
+ inode->i_op = &ecryptfs_main_iops;
+ inode->i_fop = &ecryptfs_main_fops;
+ inode->i_mapping->a_ops = &ecryptfs_aops;
+}
+
+/**
+ * ecryptfs_put_super
+ * @sb: Pointer to the ecryptfs super block
+ *
+ * Final actions when unmounting a file system.
+ * This will handle deallocation and release of our private data.
+ */
+static void ecryptfs_put_super(struct super_block *sb)
+{
+ struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);
+
+ ecryptfs_destruct_mount_crypt_stat(&sb_info->mount_crypt_stat);
+ kmem_cache_free(ecryptfs_sb_info_cache, sb_info);
+ ecryptfs_set_superblock_private(sb, NULL);
+}
+
+/**
+ * ecryptfs_statfs
+ * @sb: The ecryptfs super block
+ * @buf: The struct kstatfs to fill in with stats
+ *
+ * Get the filesystem statistics. Currently, we let this pass right through
+ * to the lower filesystem and take no action ourselves.
+ */
+static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);
+}
+
+/**
+ * ecryptfs_clear_inode
+ * @inode - The ecryptfs inode
+ *
+ * Called by iput() when the inode reference count reached zero
+ * and the inode is not hashed anywhere. Used to clear anything
+ * that needs to be, before the inode is completely destroyed and put
+ * on the inode free list. We use this to drop out reference to the
+ * lower inode.
+ */
+static void ecryptfs_clear_inode(struct inode *inode)
+{
+ iput(ecryptfs_inode_to_lower(inode));
+}
+
+/**
+ * ecryptfs_umount_begin
+ *
+ * Called in do_umount().
+ */
+static void ecryptfs_umount_begin(struct vfsmount *vfsmnt, int flags)
+{
+ struct vfsmount *lower_mnt =
+ ecryptfs_dentry_to_lower_mnt(vfsmnt->mnt_sb->s_root);
+ struct super_block *lower_sb;
+
+ mntput(lower_mnt);
+ lower_sb = lower_mnt->mnt_sb;
+ if (lower_sb->s_op->umount_begin)
+ lower_sb->s_op->umount_begin(lower_mnt, flags);
+}
+
+/**
+ * ecryptfs_show_options
+ *
+ * Prints the directory we are currently mounted over.
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+ struct super_block *sb = mnt->mnt_sb;
+ struct dentry *lower_root_dentry = ecryptfs_dentry_to_lower(sb->s_root);
+ struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(sb->s_root);
+ char *tmp_page;
+ char *path;
+ int rc = 0;
+
+ tmp_page = (char *)__get_free_page(GFP_KERNEL);
+ if (!tmp_page) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ path = d_path(lower_root_dentry, lower_mnt, tmp_page, PAGE_SIZE);
+ if (IS_ERR(path)) {
+ rc = PTR_ERR(path);
+ goto out;
+ }
+ seq_printf(m, ",dir=%s", path);
+ free_page((unsigned long)tmp_page);
+out:
+ return rc;
+}
+
+struct super_operations ecryptfs_sops = {
+ .alloc_inode = ecryptfs_alloc_inode,
+ .destroy_inode = ecryptfs_destroy_inode,
+ .drop_inode = generic_delete_inode,
+ .put_super = ecryptfs_put_super,
+ .statfs = ecryptfs_statfs,
+ .remount_fs = NULL,
+ .clear_inode = ecryptfs_clear_inode,
+ .umount_begin = ecryptfs_umount_begin,
+ .show_options = ecryptfs_show_options
+};
diff --git a/fs/efs/super.c b/fs/efs/super.c
index 8ac2462ae5dd..b3f50651eb6b 100644
--- a/fs/efs/super.c
+++ b/fs/efs/super.c
@@ -90,8 +90,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(efs_inode_cachep))
- printk(KERN_INFO "efs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(efs_inode_cachep);
}
static void efs_put_super(struct super_block *s)
@@ -248,11 +247,10 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
struct buffer_head *bh;
struct inode *root;
- sb = kmalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
+ sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
if (!sb)
return -ENOMEM;
s->s_fs_info = sb;
- memset(sb, 0, sizeof(struct efs_sb_info));
s->s_magic = EFS_SUPER_MAGIC;
if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) {
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 3a3567433b92..ae228ec54e94 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -105,6 +105,8 @@
/* Maximum msec timeout value storeable in a long int */
#define EP_MAX_MSTIMEO min(1000ULL * MAX_SCHEDULE_TIMEOUT / HZ, (LONG_MAX - 999ULL) / HZ)
+#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
+
struct epoll_filefd {
struct file *file;
@@ -497,7 +499,7 @@ void eventpoll_release_file(struct file *file)
*/
asmlinkage long sys_epoll_create(int size)
{
- int error, fd;
+ int error, fd = -1;
struct eventpoll *ep;
struct inode *inode;
struct file *file;
@@ -640,7 +642,6 @@ eexit_1:
return error;
}
-#define MAX_EVENTS (INT_MAX / sizeof(struct epoll_event))
/*
* Implement the event wait interface for the eventpoll file. It is the kernel
@@ -657,7 +658,7 @@ asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
current, epfd, events, maxevents, timeout));
/* The maximum number of event must be greater than zero */
- if (maxevents <= 0 || maxevents > MAX_EVENTS)
+ if (maxevents <= 0 || maxevents > EP_MAX_EVENTS)
return -EINVAL;
/* Verify that the area passed by the user is writeable */
@@ -699,6 +700,55 @@ eexit_1:
}
+#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)
+{
+ 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 */
+
+
/*
* Creates the file descriptor to be used by the epoll interface.
*/
@@ -720,9 +770,10 @@ static int ep_getfd(int *efd, struct inode **einode, struct file **efile,
/* Allocates an inode from the eventpoll file system */
inode = ep_eventpoll_inode();
- error = PTR_ERR(inode);
- if (IS_ERR(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();
@@ -1590,7 +1641,6 @@ static struct inode *ep_eventpoll_inode(void)
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_blksize = PAGE_SIZE;
return inode;
eexit_1:
diff --git a/fs/exec.c b/fs/exec.c
index 54135df2a966..d993ea1a81ae 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -46,7 +46,7 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/rmap.h>
-#include <linux/acct.h>
+#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
#include <linux/audit.h>
@@ -58,7 +58,7 @@
#endif
int core_uses_pid;
-char core_pattern[65] = "core";
+char core_pattern[128] = "core";
int suid_dumpable = 0;
EXPORT_SYMBOL(suid_dumpable);
@@ -595,7 +595,7 @@ static int de_thread(struct task_struct *tsk)
if (!newsighand)
return -ENOMEM;
- if (thread_group_empty(current))
+ if (thread_group_empty(tsk))
goto no_thread_group;
/*
@@ -620,17 +620,17 @@ static int de_thread(struct task_struct *tsk)
* Reparenting needs write_lock on tasklist_lock,
* so it is safe to do it under read_lock.
*/
- if (unlikely(current->group_leader == child_reaper))
- child_reaper = current;
+ if (unlikely(tsk->group_leader == child_reaper))
+ child_reaper = tsk;
- zap_other_threads(current);
+ zap_other_threads(tsk);
read_unlock(&tasklist_lock);
/*
* Account for the thread group leader hanging around:
*/
count = 1;
- if (!thread_group_leader(current)) {
+ if (!thread_group_leader(tsk)) {
count = 2;
/*
* The SIGALRM timer survives the exec, but needs to point
@@ -639,14 +639,14 @@ static int de_thread(struct task_struct *tsk)
* synchronize with any firing (by calling del_timer_sync)
* before we can safely let the old group leader die.
*/
- sig->tsk = current;
+ sig->tsk = tsk;
spin_unlock_irq(lock);
if (hrtimer_cancel(&sig->real_timer))
hrtimer_restart(&sig->real_timer);
spin_lock_irq(lock);
}
while (atomic_read(&sig->count) > count) {
- sig->group_exit_task = current;
+ sig->group_exit_task = tsk;
sig->notify_count = count;
__set_current_state(TASK_UNINTERRUPTIBLE);
spin_unlock_irq(lock);
@@ -662,13 +662,13 @@ static int de_thread(struct task_struct *tsk)
* do is to wait for the thread group leader to become inactive,
* and to assume its PID:
*/
- if (!thread_group_leader(current)) {
+ if (!thread_group_leader(tsk)) {
/*
* Wait for the thread group leader to be a zombie.
* It should already be zombie at this point, most
* of the time.
*/
- leader = current->group_leader;
+ leader = tsk->group_leader;
while (leader->exit_state != EXIT_ZOMBIE)
yield();
@@ -682,12 +682,12 @@ static int de_thread(struct task_struct *tsk)
* When we take on its identity by switching to its PID, we
* also take its birthdate (always earlier than our own).
*/
- current->start_time = leader->start_time;
+ tsk->start_time = leader->start_time;
write_lock_irq(&tasklist_lock);
- BUG_ON(leader->tgid != current->tgid);
- BUG_ON(current->pid == current->tgid);
+ BUG_ON(leader->tgid != tsk->tgid);
+ BUG_ON(tsk->pid == tsk->tgid);
/*
* An exec() starts a new thread group with the
* TGID of the previous thread group. Rehash the
@@ -696,24 +696,21 @@ static int de_thread(struct task_struct *tsk)
*/
/* Become a process group leader with the old leader's pid.
- * Note: The old leader also uses thispid until release_task
+ * The old leader becomes a thread of the this thread group.
+ * Note: The old leader also uses this pid until release_task
* is called. Odd but simple and correct.
*/
- detach_pid(current, PIDTYPE_PID);
- current->pid = leader->pid;
- attach_pid(current, PIDTYPE_PID, current->pid);
- attach_pid(current, PIDTYPE_PGID, current->signal->pgrp);
- attach_pid(current, PIDTYPE_SID, current->signal->session);
- list_replace_rcu(&leader->tasks, &current->tasks);
+ detach_pid(tsk, PIDTYPE_PID);
+ tsk->pid = leader->pid;
+ attach_pid(tsk, PIDTYPE_PID, tsk->pid);
+ transfer_pid(leader, tsk, PIDTYPE_PGID);
+ transfer_pid(leader, tsk, PIDTYPE_SID);
+ list_replace_rcu(&leader->tasks, &tsk->tasks);
- current->group_leader = current;
- leader->group_leader = current;
+ tsk->group_leader = tsk;
+ leader->group_leader = tsk;
- /* Reduce leader to a thread */
- detach_pid(leader, PIDTYPE_PGID);
- detach_pid(leader, PIDTYPE_SID);
-
- current->exit_signal = SIGCHLD;
+ tsk->exit_signal = SIGCHLD;
BUG_ON(leader->exit_state != EXIT_ZOMBIE);
leader->exit_state = EXIT_DEAD;
@@ -753,7 +750,7 @@ no_thread_group:
spin_lock(&oldsighand->siglock);
spin_lock_nested(&newsighand->siglock, SINGLE_DEPTH_NESTING);
- rcu_assign_pointer(current->sighand, newsighand);
+ rcu_assign_pointer(tsk->sighand, newsighand);
recalc_sigpending();
spin_unlock(&newsighand->siglock);
@@ -764,7 +761,7 @@ no_thread_group:
kmem_cache_free(sighand_cachep, oldsighand);
}
- BUG_ON(!thread_group_leader(current));
+ BUG_ON(!thread_group_leader(tsk));
return 0;
}
@@ -901,8 +898,7 @@ int flush_old_exec(struct linux_binprm * bprm)
return 0;
mmap_failed:
- put_files_struct(current->files);
- current->files = files;
+ reset_files_struct(current, files);
out:
return retval;
}
@@ -1322,7 +1318,7 @@ static void format_corename(char *corename, const char *pattern, long signr)
case 'h':
down_read(&uts_sem);
rc = snprintf(out_ptr, out_end - out_ptr,
- "%s", system_utsname.nodename);
+ "%s", utsname()->nodename);
up_read(&uts_sem);
if (rc > out_end - out_ptr)
goto out;
@@ -1467,6 +1463,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
int retval = 0;
int fsuid = current->fsuid;
int flag = 0;
+ int ispipe = 0;
binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
@@ -1508,22 +1505,34 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
lock_kernel();
format_corename(corename, core_pattern, signr);
unlock_kernel();
- file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600);
+ if (corename[0] == '|') {
+ /* SIGPIPE can happen, but it's just never processed */
+ if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
+ printk(KERN_INFO "Core dump to %s pipe failed\n",
+ corename);
+ goto fail_unlock;
+ }
+ ispipe = 1;
+ } else
+ file = filp_open(corename,
+ O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600);
if (IS_ERR(file))
goto fail_unlock;
inode = file->f_dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
- if (d_unhashed(file->f_dentry))
+ if (!ispipe && d_unhashed(file->f_dentry))
goto close_fail;
- if (!S_ISREG(inode->i_mode))
+ /* AK: actually i see no reason to not allow this for named pipes etc.,
+ but keep the previous behaviour for now. */
+ if (!ispipe && !S_ISREG(inode->i_mode))
goto close_fail;
if (!file->f_op)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
- if (do_truncate(file->f_dentry, 0, 0, file) != 0)
+ if (!ispipe && do_truncate(file->f_dentry, 0, 0, file) != 0)
goto close_fail;
retval = binfmt->core_dump(signr, regs, file);
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index 4c39009350f3..93e77c3d2490 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -315,7 +315,7 @@ struct getdents_callback {
* the name matching the specified inode number.
*/
static int filldir_one(void * __buf, const char * name, int len,
- loff_t pos, ino_t ino, unsigned int d_type)
+ loff_t pos, u64 ino, unsigned int d_type)
{
struct getdents_callback *buf = __buf;
int result = 0;
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index da52b4a5db64..7c420b800c34 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -89,8 +89,8 @@ ext2_acl_to_disk(const struct posix_acl *acl, size_t *size)
size_t n;
*size = ext2_acl_size(acl->a_count);
- ext_acl = (ext2_acl_header *)kmalloc(sizeof(ext2_acl_header) +
- acl->a_count * sizeof(ext2_acl_entry), GFP_KERNEL);
+ ext_acl = kmalloc(sizeof(ext2_acl_header) + acl->a_count *
+ sizeof(ext2_acl_entry), GFP_KERNEL);
if (!ext_acl)
return ERR_PTR(-ENOMEM);
ext_acl->a_version = cpu_to_le32(EXT2_ACL_VERSION);
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 92ea8265d7d5..3e7a84a1e509 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -661,5 +661,8 @@ const struct file_operations ext2_dir_operations = {
.read = generic_read_dir,
.readdir = ext2_readdir,
.ioctl = ext2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ext2_compat_ioctl,
+#endif
.fsync = ext2_sync_file,
};
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index e65a019fc7a5..c19ac153f56b 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -137,6 +137,7 @@ extern void ext2_set_inode_flags(struct inode *inode);
/* ioctl.c */
extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
unsigned long);
+extern long ext2_compat_ioctl(struct file *, unsigned int, unsigned long);
/* namei.c */
struct dentry *ext2_get_parent(struct dentry *child);
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 23e2c7ccec1d..2dba473c524a 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -41,17 +41,18 @@ static int ext2_release_file (struct inode * inode, struct file * filp)
*/
const struct file_operations ext2_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.ioctl = ext2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ext2_compat_ioctl,
+#endif
.mmap = generic_file_mmap,
.open = generic_file_open,
.release = ext2_release_file,
.fsync = ext2_sync_file,
- .readv = generic_file_readv,
- .writev = generic_file_writev,
.sendfile = generic_file_sendfile,
.splice_read = generic_file_splice_read,
.splice_write = generic_file_splice_write,
@@ -63,6 +64,9 @@ const struct file_operations ext2_xip_file_operations = {
.read = xip_file_read,
.write = xip_file_write,
.ioctl = ext2_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ext2_compat_ioctl,
+#endif
.mmap = xip_file_mmap,
.open = generic_file_open,
.release = ext2_release_file,
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 695f69ccf908..2cb545bf0f3c 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -574,7 +574,6 @@ got:
inode->i_mode = mode;
inode->i_ino = ino;
- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
memset(ei->i_data, 0, sizeof(ei->i_data));
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index fb4d3220eb8d..dd4e14c221e0 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -1094,7 +1094,6 @@ void ext2_read_inode (struct inode * inode)
brelse (bh);
goto bad_inode;
}
- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
ei->i_flags = le32_to_cpu(raw_inode->i_flags);
ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c
index 3ca9afdf713d..1dfba77eab10 100644
--- a/fs/ext2/ioctl.c
+++ b/fs/ext2/ioctl.c
@@ -11,6 +11,8 @@
#include <linux/capability.h>
#include <linux/time.h>
#include <linux/sched.h>
+#include <linux/compat.h>
+#include <linux/smp_lock.h>
#include <asm/current.h>
#include <asm/uaccess.h>
@@ -80,3 +82,33 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
return -ENOTTY;
}
}
+
+#ifdef CONFIG_COMPAT
+long ext2_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ /* These are just misnamed, they actually get/put from/to user an int */
+ switch (cmd) {
+ case EXT2_IOC32_GETFLAGS:
+ cmd = EXT2_IOC_GETFLAGS;
+ break;
+ case EXT2_IOC32_SETFLAGS:
+ cmd = EXT2_IOC_SETFLAGS;
+ break;
+ case EXT2_IOC32_GETVERSION:
+ cmd = EXT2_IOC_GETVERSION;
+ break;
+ case EXT2_IOC32_SETVERSION:
+ cmd = EXT2_IOC_SETVERSION;
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ lock_kernel();
+ ret = ext2_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
+ unlock_kernel();
+ return ret;
+}
+#endif
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 4ca824985321..e1af5b4cf80c 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -326,7 +326,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
ext2_set_link(new_dir, new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
inode_dec_link_count(new_inode);
} else {
if (dir_de) {
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 4286ff6330b6..d8b9abd95d07 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -184,8 +184,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(ext2_inode_cachep))
- printk(KERN_INFO "ext2_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(ext2_inode_cachep);
}
static void ext2_clear_inode(struct inode *inode)
@@ -365,7 +364,6 @@ static int parse_options (char * options,
{
char * p;
substring_t args[MAX_OPT_ARGS];
- unsigned long kind = EXT2_MOUNT_ERRORS_CONT;
int option;
if (!options)
@@ -405,13 +403,19 @@ static int parse_options (char * options,
/* *sb_block = match_int(&args[0]); */
break;
case Opt_err_panic:
- kind = EXT2_MOUNT_ERRORS_PANIC;
+ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+ clear_opt (sbi->s_mount_opt, ERRORS_RO);
+ set_opt (sbi->s_mount_opt, ERRORS_PANIC);
break;
case Opt_err_ro:
- kind = EXT2_MOUNT_ERRORS_RO;
+ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+ set_opt (sbi->s_mount_opt, ERRORS_RO);
break;
case Opt_err_cont:
- kind = EXT2_MOUNT_ERRORS_CONT;
+ clear_opt (sbi->s_mount_opt, ERRORS_RO);
+ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+ set_opt (sbi->s_mount_opt, ERRORS_CONT);
break;
case Opt_nouid32:
set_opt (sbi->s_mount_opt, NO_UID32);
@@ -490,7 +494,6 @@ static int parse_options (char * options,
return 0;
}
}
- sbi->s_mount_opt |= kind;
return 1;
}
@@ -544,17 +547,24 @@ static int ext2_check_descriptors (struct super_block * sb)
int i;
int desc_block = 0;
struct ext2_sb_info *sbi = EXT2_SB(sb);
- unsigned long block = le32_to_cpu(sbi->s_es->s_first_data_block);
+ unsigned long first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
+ unsigned long last_block;
struct ext2_group_desc * gdp = NULL;
ext2_debug ("Checking group descriptors");
for (i = 0; i < sbi->s_groups_count; i++)
{
+ if (i == sbi->s_groups_count - 1)
+ last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
+ else
+ last_block = first_block +
+ (EXT2_BLOCKS_PER_GROUP(sb) - 1);
+
if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0)
gdp = (struct ext2_group_desc *) sbi->s_group_desc[desc_block++]->b_data;
- if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
- le32_to_cpu(gdp->bg_block_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb))
+ if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
+ le32_to_cpu(gdp->bg_block_bitmap) > last_block)
{
ext2_error (sb, "ext2_check_descriptors",
"Block bitmap for group %d"
@@ -562,8 +572,8 @@ static int ext2_check_descriptors (struct super_block * sb)
i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
return 0;
}
- if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
- le32_to_cpu(gdp->bg_inode_bitmap) >= block + EXT2_BLOCKS_PER_GROUP(sb))
+ if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block ||
+ le32_to_cpu(gdp->bg_inode_bitmap) > last_block)
{
ext2_error (sb, "ext2_check_descriptors",
"Inode bitmap for group %d"
@@ -571,9 +581,9 @@ static int ext2_check_descriptors (struct super_block * sb)
i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap));
return 0;
}
- if (le32_to_cpu(gdp->bg_inode_table) < block ||
- le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >=
- block + EXT2_BLOCKS_PER_GROUP(sb))
+ if (le32_to_cpu(gdp->bg_inode_table) < first_block ||
+ le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >
+ last_block)
{
ext2_error (sb, "ext2_check_descriptors",
"Inode table for group %d"
@@ -581,7 +591,7 @@ static int ext2_check_descriptors (struct super_block * sb)
i, (unsigned long) le32_to_cpu(gdp->bg_inode_table));
return 0;
}
- block += EXT2_BLOCKS_PER_GROUP(sb);
+ first_block += EXT2_BLOCKS_PER_GROUP(sb);
gdp++;
}
return 1;
@@ -648,11 +658,10 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
int i, j;
__le32 features;
- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_fs_info = sbi;
- memset(sbi, 0, sizeof(*sbi));
/*
* See what the current blocksize for the device is, and
@@ -710,6 +719,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
set_opt(sbi->s_mount_opt, ERRORS_PANIC);
else if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_RO)
set_opt(sbi->s_mount_opt, ERRORS_RO);
+ else
+ set_opt(sbi->s_mount_opt, ERRORS_CONT);
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -861,10 +872,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
if (EXT2_BLOCKS_PER_GROUP(sb) == 0)
goto cantfind_ext2;
- sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
- le32_to_cpu(es->s_first_data_block) +
- EXT2_BLOCKS_PER_GROUP(sb) - 1) /
- EXT2_BLOCKS_PER_GROUP(sb);
+ sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
+ le32_to_cpu(es->s_first_data_block) - 1)
+ / EXT2_BLOCKS_PER_GROUP(sb)) + 1;
db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /
EXT2_DESC_PER_BLOCK(sb);
sbi->s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index 86ae8e93adb9..af52a7f8b291 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -521,11 +521,10 @@ bad_block: ext2_error(sb, "ext2_xattr_set",
}
} else {
/* Allocate a buffer where we construct the new block. */
- header = kmalloc(sb->s_blocksize, GFP_KERNEL);
+ header = kzalloc(sb->s_blocksize, GFP_KERNEL);
error = -ENOMEM;
if (header == NULL)
goto cleanup;
- memset(header, 0, sb->s_blocksize);
end = (char *)header + sb->s_blocksize;
header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC);
header->h_blocks = header->h_refcount = cpu_to_le32(1);
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 0d21d558b87a..1e5038d9a01b 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -90,8 +90,8 @@ ext3_acl_to_disk(const struct posix_acl *acl, size_t *size)
size_t n;
*size = ext3_acl_size(acl->a_count);
- ext_acl = (ext3_acl_header *)kmalloc(sizeof(ext3_acl_header) +
- acl->a_count * sizeof(ext3_acl_entry), GFP_KERNEL);
+ ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count *
+ sizeof(ext3_acl_entry), GFP_KERNEL);
if (!ext_acl)
return ERR_PTR(-ENOMEM);
ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION);
@@ -258,7 +258,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
default:
return -EINVAL;
}
- if (acl) {
+ if (acl) {
value = ext3_acl_to_disk(acl, &size);
if (IS_ERR(value))
return (int)PTR_ERR(value);
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index 063d994bda0b..b41a7d7e20f0 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -38,6 +38,13 @@
#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
+/**
+ * ext3_get_group_desc() -- load group descriptor from disk
+ * @sb: super block
+ * @block_group: given block group
+ * @bh: pointer to the buffer head to store the block
+ * group descriptor
+ */
struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
unsigned int block_group,
struct buffer_head ** bh)
@@ -73,8 +80,12 @@ struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
return desc + offset;
}
-/*
- * Read the bitmap for a given block_group, reading into the specified
+/**
+ * read_block_bitmap()
+ * @sb: super block
+ * @block_group: given block group
+ *
+ * Read the bitmap for a given block_group, reading into the specified
* slot in the superblock's bitmap cache.
*
* Return buffer_head on success or NULL in case of failure.
@@ -103,15 +114,22 @@ error_out:
* Operations include:
* dump, find, add, remove, is_empty, find_next_reservable_window, etc.
*
- * We use sorted double linked list for the per-filesystem reservation
- * window list. (like in vm_region).
+ * We use a red-black tree to represent per-filesystem reservation
+ * windows.
+ *
+ */
+
+/**
+ * __rsv_window_dump() -- Dump the filesystem block allocation reservation map
+ * @rb_root: root of per-filesystem reservation rb tree
+ * @verbose: verbose mode
+ * @fn: function which wishes to dump the reservation map
*
- * Initially, we keep those small operations in the abstract functions,
- * so later if we need a better searching tree than double linked-list,
- * we could easily switch to that without changing too much
- * code.
+ * If verbose is turned on, it will print the whole block reservation
+ * windows(start, end). Otherwise, it will only print out the "bad" windows,
+ * those windows that overlap with their immediate neighbors.
*/
-#if 0
+#if 1
static void __rsv_window_dump(struct rb_root *root, int verbose,
const char *fn)
{
@@ -129,7 +147,7 @@ restart:
rsv = list_entry(n, struct ext3_reserve_window_node, rsv_node);
if (verbose)
printk("reservation window 0x%p "
- "start: %d, end: %d\n",
+ "start: %lu, end: %lu\n",
rsv, rsv->rsv_start, rsv->rsv_end);
if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
printk("Bad reservation %p (start >= end)\n",
@@ -161,6 +179,22 @@ restart:
#define rsv_window_dump(root, verbose) do {} while (0)
#endif
+/**
+ * goal_in_my_reservation()
+ * @rsv: inode's reservation window
+ * @grp_goal: given goal block relative to the allocation block group
+ * @group: the current allocation block group
+ * @sb: filesystem super block
+ *
+ * Test if the given goal block (group relative) is within the file's
+ * own block reservation window range.
+ *
+ * If the reservation window is outside the goal allocation group, return 0;
+ * grp_goal (given goal block) could be -1, which means no specific
+ * goal block. In this case, always return 1.
+ * If the goal block is within the reservation window, return 1;
+ * otherwise, return 0;
+ */
static int
goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,
unsigned int group, struct super_block * sb)
@@ -168,7 +202,7 @@ goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,
ext3_fsblk_t group_first_block, group_last_block;
group_first_block = ext3_group_first_block_no(sb, group);
- group_last_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
+ group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1);
if ((rsv->_rsv_start > group_last_block) ||
(rsv->_rsv_end < group_first_block))
@@ -179,7 +213,11 @@ goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal,
return 1;
}
-/*
+/**
+ * search_reserve_window()
+ * @rb_root: root of reservation tree
+ * @goal: target allocation block
+ *
* Find the reserved window which includes the goal, or the previous one
* if the goal is not in any window.
* Returns NULL if there are no windows or if all windows start after the goal.
@@ -216,6 +254,13 @@ search_reserve_window(struct rb_root *root, ext3_fsblk_t goal)
return rsv;
}
+/**
+ * ext3_rsv_window_add() -- Insert a window to the block reservation rb tree.
+ * @sb: super block
+ * @rsv: reservation window to add
+ *
+ * Must be called with rsv_lock hold.
+ */
void ext3_rsv_window_add(struct super_block *sb,
struct ext3_reserve_window_node *rsv)
{
@@ -236,14 +281,25 @@ void ext3_rsv_window_add(struct super_block *sb,
p = &(*p)->rb_left;
else if (start > this->rsv_end)
p = &(*p)->rb_right;
- else
+ else {
+ rsv_window_dump(root, 1);
BUG();
+ }
}
rb_link_node(node, parent, p);
rb_insert_color(node, root);
}
+/**
+ * ext3_rsv_window_remove() -- unlink a window from the reservation rb tree
+ * @sb: super block
+ * @rsv: reservation window to remove
+ *
+ * Mark the block reservation window as not allocated, and unlink it
+ * from the filesystem reservation window rb tree. Must be called with
+ * rsv_lock hold.
+ */
static void rsv_window_remove(struct super_block *sb,
struct ext3_reserve_window_node *rsv)
{
@@ -253,11 +309,39 @@ static void rsv_window_remove(struct super_block *sb,
rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root);
}
+/*
+ * rsv_is_empty() -- Check if the reservation window is allocated.
+ * @rsv: given reservation window to check
+ *
+ * returns 1 if the end block is EXT3_RESERVE_WINDOW_NOT_ALLOCATED.
+ */
static inline int rsv_is_empty(struct ext3_reserve_window *rsv)
{
/* a valid reservation end block could not be 0 */
- return (rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED);
+ return rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
}
+
+/**
+ * ext3_init_block_alloc_info()
+ * @inode: file inode structure
+ *
+ * Allocate and initialize the reservation window structure, and
+ * link the window to the ext3 inode structure at last
+ *
+ * The reservation window structure is only dynamically allocated
+ * and linked to ext3 inode the first time the open file
+ * needs a new block. So, before every ext3_new_block(s) call, for
+ * regular files, we should check whether the reservation window
+ * structure exists or not. In the latter case, this function is called.
+ * Fail to do so will result in block reservation being turned off for that
+ * open file.
+ *
+ * This function is called from ext3_get_blocks_handle(), also called
+ * when setting the reservation window size through ioctl before the file
+ * is open for write (needs block allocation).
+ *
+ * Needs truncate_mutex protection prior to call this function.
+ */
void ext3_init_block_alloc_info(struct inode *inode)
{
struct ext3_inode_info *ei = EXT3_I(inode);
@@ -271,7 +355,7 @@ void ext3_init_block_alloc_info(struct inode *inode)
rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED;
- /*
+ /*
* if filesystem is mounted with NORESERVATION, the goal
* reservation window size is set to zero to indicate
* block reservation is off
@@ -287,6 +371,19 @@ void ext3_init_block_alloc_info(struct inode *inode)
ei->i_block_alloc_info = block_i;
}
+/**
+ * ext3_discard_reservation()
+ * @inode: inode
+ *
+ * Discard(free) block reservation window on last file close, or truncate
+ * or at last iput().
+ *
+ * It is being called in three cases:
+ * ext3_release_file(): last writer close the file
+ * ext3_clear_inode(): last iput(), when nobody link to this file.
+ * ext3_truncate(): when the block indirect map is about to change.
+ *
+ */
void ext3_discard_reservation(struct inode *inode)
{
struct ext3_inode_info *ei = EXT3_I(inode);
@@ -306,7 +403,14 @@ void ext3_discard_reservation(struct inode *inode)
}
}
-/* Free given blocks, update quota and i_blocks field */
+/**
+ * ext3_free_blocks_sb() -- Free given blocks and update quota
+ * @handle: handle to this transaction
+ * @sb: super block
+ * @block: start physcial block to free
+ * @count: number of blocks to free
+ * @pdquot_freed_blocks: pointer to quota
+ */
void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
ext3_fsblk_t block, unsigned long count,
unsigned long *pdquot_freed_blocks)
@@ -419,8 +523,8 @@ do_more:
}
/* @@@ This prevents newly-allocated data from being
* freed and then reallocated within the same
- * transaction.
- *
+ * transaction.
+ *
* Ideally we would want to allow that to happen, but to
* do so requires making journal_forget() capable of
* revoking the queued write of a data block, which
@@ -433,7 +537,7 @@ do_more:
* safe not to set the allocation bit in the committed
* bitmap, because we know that there is no outstanding
* activity on the buffer any more and so it is safe to
- * reallocate it.
+ * reallocate it.
*/
BUFFER_TRACE(bitmap_bh, "set in b_committed_data");
J_ASSERT_BH(bitmap_bh,
@@ -490,7 +594,13 @@ error_return:
return;
}
-/* Free given blocks, update quota and i_blocks field */
+/**
+ * ext3_free_blocks() -- Free given blocks and update quota
+ * @handle: handle for this transaction
+ * @inode: inode
+ * @block: start physical block to free
+ * @count: number of blocks to count
+ */
void ext3_free_blocks(handle_t *handle, struct inode *inode,
ext3_fsblk_t block, unsigned long count)
{
@@ -508,7 +618,11 @@ void ext3_free_blocks(handle_t *handle, struct inode *inode,
return;
}
-/*
+/**
+ * ext3_test_allocatable()
+ * @nr: given allocation block group
+ * @bh: bufferhead contains the bitmap of the given block group
+ *
* For ext3 allocations, we must not reuse any blocks which are
* allocated in the bitmap buffer's "last committed data" copy. This
* prevents deletes from freeing up the page for reuse until we have
@@ -518,7 +632,7 @@ void ext3_free_blocks(handle_t *handle, struct inode *inode,
* data would allow the old block to be overwritten before the
* transaction committed (because we force data to disk before commit).
* This would lead to corruption if we crashed between overwriting the
- * data and committing the delete.
+ * data and committing the delete.
*
* @@@ We may want to make this allocation behaviour conditional on
* data-writes at some point, and disable it for metadata allocations or
@@ -541,6 +655,16 @@ static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh)
return ret;
}
+/**
+ * bitmap_search_next_usable_block()
+ * @start: the starting block (group relative) of the search
+ * @bh: bufferhead contains the block group bitmap
+ * @maxblocks: the ending block (group relative) of the reservation
+ *
+ * The bitmap search --- search forward alternately through the actual
+ * bitmap on disk and the last-committed copy in journal, until we find a
+ * bit free in both bitmaps.
+ */
static ext3_grpblk_t
bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
ext3_grpblk_t maxblocks)
@@ -548,11 +672,6 @@ bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
ext3_grpblk_t next;
struct journal_head *jh = bh2jh(bh);
- /*
- * The bitmap search --- search forward alternately through the actual
- * bitmap and the last-committed copy until we find a bit free in
- * both
- */
while (start < maxblocks) {
next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start);
if (next >= maxblocks)
@@ -562,14 +681,20 @@ bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
jbd_lock_bh_state(bh);
if (jh->b_committed_data)
start = ext3_find_next_zero_bit(jh->b_committed_data,
- maxblocks, next);
+ maxblocks, next);
jbd_unlock_bh_state(bh);
}
return -1;
}
-/*
- * Find an allocatable block in a bitmap. We honour both the bitmap and
+/**
+ * find_next_usable_block()
+ * @start: the starting block (group relative) to find next
+ * allocatable block in bitmap.
+ * @bh: bufferhead contains the block group bitmap
+ * @maxblocks: the ending block (group relative) for the search
+ *
+ * Find an allocatable block in a bitmap. We honor both the bitmap and
* its last-committed copy (if that exists), and perform the "most
* appropriate allocation" algorithm of looking for a free block near
* the initial goal; then for a free byte somewhere in the bitmap; then
@@ -584,7 +709,7 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
if (start > 0) {
/*
- * The goal was occupied; search forward for a free
+ * The goal was occupied; search forward for a free
* block within the next XX blocks.
*
* end_goal is more or less random, but it has to be
@@ -620,7 +745,11 @@ find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh,
return here;
}
-/*
+/**
+ * claim_block()
+ * @block: the free block (group relative) to allocate
+ * @bh: the bufferhead containts the block group bitmap
+ *
* We think we can allocate this block in this bitmap. Try to set the bit.
* If that succeeds then check that nobody has allocated and then freed the
* block since we saw that is was not marked in b_committed_data. If it _was_
@@ -646,7 +775,26 @@ claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh)
return ret;
}
-/*
+/**
+ * ext3_try_to_allocate()
+ * @sb: superblock
+ * @handle: handle to this transaction
+ * @group: given allocation block group
+ * @bitmap_bh: bufferhead holds the block bitmap
+ * @grp_goal: given target block within the group
+ * @count: target number of blocks to allocate
+ * @my_rsv: reservation window
+ *
+ * Attempt to allocate blocks within a give range. Set the range of allocation
+ * first, then find the first free bit(s) from the bitmap (within the range),
+ * and at last, allocate the blocks by claiming the found free bit as allocated.
+ *
+ * To set the range of this allocation:
+ * if there is a reservation window, only try to allocate block(s) from the
+ * file's own reservation window;
+ * Otherwise, the allocation range starts from the give goal block, ends at
+ * the block group's last block.
+ *
* If we failed to allocate the desired block then we may end up crossing to a
* new bitmap. In that case we must release write access to the old one via
* ext3_journal_release_buffer(), else we'll run out of credits.
@@ -703,7 +851,8 @@ repeat:
}
start = grp_goal;
- if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
+ if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group),
+ grp_goal, bitmap_bh)) {
/*
* The block was allocated by another thread, or it was
* allocated and then freed by another thread
@@ -718,7 +867,8 @@ repeat:
grp_goal++;
while (num < *count && grp_goal < end
&& ext3_test_allocatable(grp_goal, bitmap_bh)
- && claim_block(sb_bgl_lock(EXT3_SB(sb), group), grp_goal, bitmap_bh)) {
+ && claim_block(sb_bgl_lock(EXT3_SB(sb), group),
+ grp_goal, bitmap_bh)) {
num++;
grp_goal++;
}
@@ -730,12 +880,12 @@ fail_access:
}
/**
- * find_next_reservable_window():
+ * find_next_reservable_window():
* find a reservable space within the given range.
* It does not allocate the reservation window for now:
* alloc_new_reservation() will do the work later.
*
- * @search_head: the head of the searching list;
+ * @search_head: the head of the searching list;
* This is not necessarily the list head of the whole filesystem
*
* We have both head and start_block to assist the search
@@ -743,12 +893,12 @@ fail_access:
* but we will shift to the place where start_block is,
* then start from there, when looking for a reservable space.
*
- * @size: the target new reservation window size
+ * @size: the target new reservation window size
*
- * @group_first_block: the first block we consider to start
+ * @group_first_block: the first block we consider to start
* the real search from
*
- * @last_block:
+ * @last_block:
* the maximum block number that our goal reservable space
* could start from. This is normally the last block in this
* group. The search will end when we found the start of next
@@ -756,10 +906,10 @@ fail_access:
* This could handle the cross boundary reservation window
* request.
*
- * basically we search from the given range, rather than the whole
- * reservation double linked list, (start_block, last_block)
- * to find a free region that is of my size and has not
- * been reserved.
+ * basically we search from the given range, rather than the whole
+ * reservation double linked list, (start_block, last_block)
+ * to find a free region that is of my size and has not
+ * been reserved.
*
*/
static int find_next_reservable_window(
@@ -812,7 +962,7 @@ static int find_next_reservable_window(
/*
* Found a reserveable space big enough. We could
* have a reservation across the group boundary here
- */
+ */
break;
}
}
@@ -848,7 +998,7 @@ static int find_next_reservable_window(
}
/**
- * alloc_new_reservation()--allocate a new reservation window
+ * alloc_new_reservation()--allocate a new reservation window
*
* To make a new reservation, we search part of the filesystem
* reservation list (the list that inside the group). We try to
@@ -897,7 +1047,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
group_first_block = ext3_group_first_block_no(sb, group);
- group_end_block = group_first_block + EXT3_BLOCKS_PER_GROUP(sb) - 1;
+ group_end_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1);
if (grp_goal < 0)
start_block = group_first_block;
@@ -929,9 +1079,10 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
if ((my_rsv->rsv_alloc_hit >
(my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
/*
- * if we previously allocation hit ration is greater than half
- * we double the size of reservation window next time
- * otherwise keep the same
+ * if the previously allocation hit ratio is
+ * greater than 1/2, then we double the size of
+ * the reservation window the next time,
+ * otherwise we keep the same size window
*/
size = size * 2;
if (size > EXT3_MAX_RESERVE_BLOCKS)
@@ -1010,6 +1161,23 @@ retry:
goto retry;
}
+/**
+ * try_to_extend_reservation()
+ * @my_rsv: given reservation window
+ * @sb: super block
+ * @size: the delta to extend
+ *
+ * Attempt to expand the reservation window large enough to have
+ * required number of free blocks
+ *
+ * Since ext3_try_to_allocate() will always allocate blocks within
+ * the reservation window range, if the window size is too small,
+ * multiple blocks allocation has to stop at the end of the reservation
+ * window. To make this more efficient, given the total number of
+ * blocks needed and the current size of the window, we try to
+ * expand the reservation window size if necessary on a best-effort
+ * basis before ext3_new_blocks() tries to allocate blocks,
+ */
static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
struct super_block *sb, int size)
{
@@ -1035,7 +1203,17 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
spin_unlock(rsv_lock);
}
-/*
+/**
+ * ext3_try_to_allocate_with_rsv()
+ * @sb: superblock
+ * @handle: handle to this transaction
+ * @group: given allocation block group
+ * @bitmap_bh: bufferhead holds the block bitmap
+ * @grp_goal: given target block within the group
+ * @count: target number of blocks to allocate
+ * @my_rsv: reservation window
+ * @errp: pointer to store the error code
+ *
* This is the main function used to allocate a new block and its reservation
* window.
*
@@ -1051,9 +1229,7 @@ static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv,
* reservation), and there are lots of free blocks, but they are all
* being reserved.
*
- * We use a sorted double linked list for the per-filesystem reservation list.
- * The insert, remove and find a free space(non-reserved) operations for the
- * sorted double linked list should be fast.
+ * We use a red-black tree for the per-filesystem reservation list.
*
*/
static ext3_grpblk_t
@@ -1063,7 +1239,7 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
struct ext3_reserve_window_node * my_rsv,
unsigned long *count, int *errp)
{
- ext3_fsblk_t group_first_block;
+ ext3_fsblk_t group_first_block, group_last_block;
ext3_grpblk_t ret = 0;
int fatal;
unsigned long num = *count;
@@ -1100,6 +1276,7 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
* first block is the block number of the first block in this group
*/
group_first_block = ext3_group_first_block_no(sb, group);
+ group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1);
/*
* Basically we will allocate a new block from inode's reservation
@@ -1118,7 +1295,8 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
*/
while (1) {
if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
- !goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb)) {
+ !goal_in_my_reservation(&my_rsv->rsv_window,
+ grp_goal, group, sb)) {
if (my_rsv->rsv_goal_size < *count)
my_rsv->rsv_goal_size = *count;
ret = alloc_new_reservation(my_rsv, grp_goal, sb,
@@ -1126,17 +1304,21 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
if (ret < 0)
break; /* failed */
- if (!goal_in_my_reservation(&my_rsv->rsv_window, grp_goal, group, sb))
+ if (!goal_in_my_reservation(&my_rsv->rsv_window,
+ grp_goal, group, sb))
grp_goal = -1;
- } else if (grp_goal > 0 && (my_rsv->rsv_end-grp_goal+1) < *count)
+ } else if (grp_goal > 0 &&
+ (my_rsv->rsv_end-grp_goal+1) < *count)
try_to_extend_reservation(my_rsv, sb,
*count-my_rsv->rsv_end + grp_goal - 1);
- if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
- || (my_rsv->rsv_end < group_first_block))
+ if ((my_rsv->rsv_start > group_last_block) ||
+ (my_rsv->rsv_end < group_first_block)) {
+ rsv_window_dump(&EXT3_SB(sb)->s_rsv_window_root, 1);
BUG();
- ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, grp_goal,
- &num, &my_rsv->rsv_window);
+ }
+ ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh,
+ grp_goal, &num, &my_rsv->rsv_window);
if (ret >= 0) {
my_rsv->rsv_alloc_hit += num;
*count = num;
@@ -1161,6 +1343,12 @@ out:
return ret;
}
+/**
+ * ext3_has_free_blocks()
+ * @sbi: in-core super block structure.
+ *
+ * Check if filesystem has at least 1 free block available for allocation.
+ */
static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
{
ext3_fsblk_t free_blocks, root_blocks;
@@ -1175,11 +1363,17 @@ static int ext3_has_free_blocks(struct ext3_sb_info *sbi)
return 1;
}
-/*
+/**
+ * ext3_should_retry_alloc()
+ * @sb: super block
+ * @retries number of attemps has been made
+ *
* ext3_should_retry_alloc() is called when ENOSPC is returned, and if
* it is profitable to retry the operation, this function will wait
* for the current or commiting transaction to complete, and then
* return TRUE.
+ *
+ * if the total number of retries exceed three times, return FALSE.
*/
int ext3_should_retry_alloc(struct super_block *sb, int *retries)
{
@@ -1191,13 +1385,19 @@ int ext3_should_retry_alloc(struct super_block *sb, int *retries)
return journal_force_commit_nested(EXT3_SB(sb)->s_journal);
}
-/*
- * ext3_new_block uses a goal block to assist allocation. If the goal is
- * free, or there is a free block within 32 blocks of the goal, that block
- * is allocated. Otherwise a forward search is made for a free block; within
- * each block group the search first looks for an entire free byte in the block
- * bitmap, and then for any free bit if that fails.
- * This function also updates quota and i_blocks field.
+/**
+ * ext3_new_blocks() -- core block(s) allocation function
+ * @handle: handle to this transaction
+ * @inode: file inode
+ * @goal: given target block(filesystem wide)
+ * @count: target number of blocks to allocate
+ * @errp: error code
+ *
+ * ext3_new_blocks uses a goal block to assist allocation. It tries to
+ * allocate block(s) from the block group contains the goal block first. If that
+ * fails, it will try to allocate block(s) from other block groups without
+ * any specific goal block.
+ *
*/
ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
ext3_fsblk_t goal, unsigned long *count, int *errp)
@@ -1303,7 +1503,7 @@ retry_alloc:
smp_rmb();
/*
- * Now search the rest of the groups. We assume that
+ * Now search the rest of the groups. We assume that
* i and gdp correctly point to the last group visited.
*/
for (bgi = 0; bgi < ngroups; bgi++) {
@@ -1428,7 +1628,7 @@ allocated:
spin_lock(sb_bgl_lock(sbi, group_no));
gdp->bg_free_blocks_count =
- cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - num);
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num);
spin_unlock(sb_bgl_lock(sbi, group_no));
percpu_counter_mod(&sbi->s_freeblocks_counter, -num);
@@ -1471,6 +1671,12 @@ ext3_fsblk_t ext3_new_block(handle_t *handle, struct inode *inode,
return ext3_new_blocks(handle, inode, goal, &count, errp);
}
+/**
+ * ext3_count_free_blocks() -- count filesystem free blocks
+ * @sb: superblock
+ *
+ * Adds up the number of free blocks from each block group.
+ */
ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb)
{
ext3_fsblk_t desc_count;
diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c
index ce4f82b9e528..b9176eed98d1 100644
--- a/fs/ext3/bitmap.c
+++ b/fs/ext3/bitmap.c
@@ -20,7 +20,7 @@ unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars)
unsigned int i;
unsigned long sum = 0;
- if (!map)
+ if (!map)
return (0);
for (i = 0; i < numchars; i++)
sum += nibblemap[map->b_data[i] & 0xf] +
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c
index fbb0d4ed07d4..d0b54f30b914 100644
--- a/fs/ext3/dir.c
+++ b/fs/ext3/dir.c
@@ -44,6 +44,9 @@ const struct file_operations ext3_dir_operations = {
.read = generic_read_dir,
.readdir = ext3_readdir, /* we take BKL. needed?*/
.ioctl = ext3_ioctl, /* BKL held */
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ext3_compat_ioctl,
+#endif
.fsync = ext3_sync_file, /* BKL held */
#ifdef CONFIG_EXT3_INDEX
.release = ext3_release_dir,
@@ -59,7 +62,7 @@ static unsigned char get_dtype(struct super_block *sb, int filetype)
return (ext3_filetype_table[filetype]);
}
-
+
int ext3_check_dir_entry (const char * function, struct inode * dir,
struct ext3_dir_entry_2 * de,
@@ -67,7 +70,7 @@ int ext3_check_dir_entry (const char * function, struct inode * dir,
unsigned long offset)
{
const char * error_msg = NULL;
- const int rlen = le16_to_cpu(de->rec_len);
+ const int rlen = le16_to_cpu(de->rec_len);
if (rlen < EXT3_DIR_REC_LEN(1))
error_msg = "rec_len is smaller than minimal";
@@ -162,7 +165,7 @@ revalidate:
* to make sure. */
if (filp->f_version != inode->i_version) {
for (i = 0; i < sb->s_blocksize && i < offset; ) {
- de = (struct ext3_dir_entry_2 *)
+ de = (struct ext3_dir_entry_2 *)
(bh->b_data + i);
/* It's too expensive to do a full
* dirent test each time round this
@@ -181,7 +184,7 @@ revalidate:
filp->f_version = inode->i_version;
}
- while (!error && filp->f_pos < inode->i_size
+ while (!error && filp->f_pos < inode->i_size
&& offset < sb->s_blocksize) {
de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
@@ -229,7 +232,7 @@ out:
/*
* These functions convert from the major/minor hash to an f_pos
* value.
- *
+ *
* Currently we only use major hash numer. This is unfortunate, but
* on 32-bit machines, the same VFS interface is used for lseek and
* llseek, so if we use the 64 bit offset, then the 32-bit versions of
@@ -250,7 +253,7 @@ out:
struct fname {
__u32 hash;
__u32 minor_hash;
- struct rb_node rb_hash;
+ struct rb_node rb_hash;
struct fname *next;
__u32 inode;
__u8 name_len;
@@ -343,10 +346,9 @@ int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
/* Create and allocate the fname structure */
len = sizeof(struct fname) + dirent->name_len + 1;
- new_fn = kmalloc(len, GFP_KERNEL);
+ new_fn = kzalloc(len, GFP_KERNEL);
if (!new_fn)
return -ENOMEM;
- memset(new_fn, 0, len);
new_fn->hash = hash;
new_fn->minor_hash = minor_hash;
new_fn->inode = le32_to_cpu(dirent->inode);
@@ -410,7 +412,7 @@ static int call_filldir(struct file * filp, void * dirent,
curr_pos = hash2pos(fname->hash, fname->minor_hash);
while (fname) {
error = filldir(dirent, fname->name,
- fname->name_len, curr_pos,
+ fname->name_len, curr_pos,
fname->inode,
get_dtype(sb, fname->file_type));
if (error) {
@@ -465,7 +467,7 @@ static int ext3_dx_readdir(struct file * filp,
/*
* Fill the rbtree if we have no more entries,
* or the inode has changed since we last read in the
- * cached entries.
+ * cached entries.
*/
if ((!info->curr_node) ||
(filp->f_version != inode->i_version)) {
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index 1efefb630ea9..e96c388047e0 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -48,14 +48,15 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
}
static ssize_t
-ext3_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
+ext3_file_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_dentry->d_inode;
ssize_t ret;
int err;
- ret = generic_file_aio_write(iocb, buf, count, pos);
+ ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
/*
* Skip flushing if there was an error, or if nothing was written.
@@ -100,7 +101,7 @@ ext3_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
force_commit:
err = ext3_force_commit(inode->i_sb);
- if (err)
+ if (err)
return err;
return ret;
}
@@ -111,9 +112,10 @@ const struct file_operations ext3_file_operations = {
.write = do_sync_write,
.aio_read = generic_file_aio_read,
.aio_write = ext3_file_write,
- .readv = generic_file_readv,
- .writev = generic_file_writev,
.ioctl = ext3_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ext3_compat_ioctl,
+#endif
.mmap = generic_file_mmap,
.open = generic_file_open,
.release = ext3_release_file,
diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c
index 49382a208e05..dd1fd3c0fc05 100644
--- a/fs/ext3/fsync.c
+++ b/fs/ext3/fsync.c
@@ -8,14 +8,14 @@
* Universite Pierre et Marie Curie (Paris VI)
* from
* linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
- *
+ *
* ext3fs fsync primitive
*
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
- *
+ *
* Removed unnecessary code duplication for little endian machines
- * and excessive __inline__s.
+ * and excessive __inline__s.
* Andi Kleen, 1997
*
* Major simplications and cleanup - we only need to do the metadata, because
diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c
index 5a2d1235ead0..deeb27b5ba83 100644
--- a/fs/ext3/hash.c
+++ b/fs/ext3/hash.c
@@ -4,7 +4,7 @@
* Copyright (C) 2002 by Theodore Ts'o
*
* This file is released under the GPL v2.
- *
+ *
* This file may be redistributed under the terms of the GNU Public
* License.
*/
@@ -80,11 +80,11 @@ static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
* Returns the hash of a filename. If len is 0 and name is NULL, then
* this function can be used to test whether or not a hash version is
* supported.
- *
+ *
* The seed is an 4 longword (32 bits) "secret" which can be used to
* uniquify a hash. If the seed is all zero's, then some default seed
* may be used.
- *
+ *
* A particular hash version specifies whether or not the seed is
* represented, and whether or not the returned hash is 32 bits or 64
* bits. 32 bit hashes will return 0 for the minor hash.
@@ -95,7 +95,7 @@ int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
__u32 minor_hash = 0;
const char *p;
int i;
- __u32 in[8], buf[4];
+ __u32 in[8], buf[4];
/* Initialize the default seed for the hash checksum functions */
buf[0] = 0x67452301;
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
index 36546ed36a14..e45dbd651736 100644
--- a/fs/ext3/ialloc.c
+++ b/fs/ext3/ialloc.c
@@ -202,7 +202,7 @@ error_return:
static int find_group_dir(struct super_block *sb, struct inode *parent)
{
int ngroups = EXT3_SB(sb)->s_groups_count;
- int freei, avefreei;
+ unsigned int freei, avefreei;
struct ext3_group_desc *desc, *best_desc = NULL;
struct buffer_head *bh;
int group, best_group = -1;
@@ -216,7 +216,7 @@ static int find_group_dir(struct super_block *sb, struct inode *parent)
continue;
if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
continue;
- if (!best_desc ||
+ if (!best_desc ||
(le16_to_cpu(desc->bg_free_blocks_count) >
le16_to_cpu(best_desc->bg_free_blocks_count))) {
best_group = group;
@@ -226,30 +226,30 @@ static int find_group_dir(struct super_block *sb, struct inode *parent)
return best_group;
}
-/*
- * Orlov's allocator for directories.
- *
+/*
+ * Orlov's allocator for directories.
+ *
* We always try to spread first-level directories.
*
- * If there are blockgroups with both free inodes and free blocks counts
- * not worse than average we return one with smallest directory count.
- * Otherwise we simply return a random group.
- *
- * For the rest rules look so:
- *
- * It's OK to put directory into a group unless
- * it has too many directories already (max_dirs) or
- * it has too few free inodes left (min_inodes) or
- * it has too few free blocks left (min_blocks) or
- * it's already running too large debt (max_debt).
- * Parent's group is prefered, if it doesn't satisfy these
- * conditions we search cyclically through the rest. If none
- * of the groups look good we just look for a group with more
- * free inodes than average (starting at parent's group).
- *
- * Debt is incremented each time we allocate a directory and decremented
- * when we allocate an inode, within 0--255.
- */
+ * If there are blockgroups with both free inodes and free blocks counts
+ * not worse than average we return one with smallest directory count.
+ * Otherwise we simply return a random group.
+ *
+ * For the rest rules look so:
+ *
+ * It's OK to put directory into a group unless
+ * it has too many directories already (max_dirs) or
+ * it has too few free inodes left (min_inodes) or
+ * it has too few free blocks left (min_blocks) or
+ * it's already running too large debt (max_debt).
+ * Parent's group is prefered, if it doesn't satisfy these
+ * conditions we search cyclically through the rest. If none
+ * of the groups look good we just look for a group with more
+ * free inodes than average (starting at parent's group).
+ *
+ * Debt is incremented each time we allocate a directory and decremented
+ * when we allocate an inode, within 0--255.
+ */
#define INODE_COST 64
#define BLOCK_COST 256
@@ -261,10 +261,10 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
struct ext3_super_block *es = sbi->s_es;
int ngroups = sbi->s_groups_count;
int inodes_per_group = EXT3_INODES_PER_GROUP(sb);
- int freei, avefreei;
+ unsigned int freei, avefreei;
ext3_fsblk_t freeb, avefreeb;
ext3_fsblk_t blocks_per_dir;
- int ndirs;
+ unsigned int ndirs;
int max_debt, max_dirs, min_inodes;
ext3_grpblk_t min_blocks;
int group = -1, i;
@@ -454,7 +454,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, int mode)
group = find_group_dir(sb, dir);
else
group = find_group_orlov(sb, dir);
- } else
+ } else
group = find_group_other(sb, dir);
err = -ENOSPC;
@@ -559,7 +559,6 @@ got:
inode->i_ino = ino;
/* This is the optimal IO size (for stat), not the fs block size */
- inode->i_blksize = PAGE_SIZE;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 84be02e93652..03ba5bcab186 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -13,11 +13,11 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*
* Goal-directed block allocation by Stephen Tweedie
- * (sct@redhat.com), 1993, 1998
+ * (sct@redhat.com), 1993, 1998
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
* 64-bit file support on 64-bit platforms by Jakub Jelinek
- * (jj@sunsite.ms.mff.cuni.cz)
+ * (jj@sunsite.ms.mff.cuni.cz)
*
* Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000
*/
@@ -36,6 +36,7 @@
#include <linux/writeback.h>
#include <linux/mpage.h>
#include <linux/uio.h>
+#include <linux/bio.h>
#include "xattr.h"
#include "acl.h"
@@ -55,7 +56,7 @@ static int ext3_inode_is_fast_symlink(struct inode *inode)
/*
* The ext3 forget function must perform a revoke if we are freeing data
* which has been journaled. Metadata (eg. indirect blocks) must be
- * revoked in all cases.
+ * revoked in all cases.
*
* "bh" may be NULL: a metadata block may have been freed from memory
* but there may still be a record of it in the journal, and that record
@@ -105,7 +106,7 @@ int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode,
* Work out how many blocks we need to proceed with the next chunk of a
* truncate transaction.
*/
-static unsigned long blocks_for_truncate(struct inode *inode)
+static unsigned long blocks_for_truncate(struct inode *inode)
{
unsigned long needed;
@@ -122,13 +123,13 @@ static unsigned long blocks_for_truncate(struct inode *inode)
/* But we need to bound the transaction so we don't overflow the
* journal. */
- if (needed > EXT3_MAX_TRANS_DATA)
+ if (needed > EXT3_MAX_TRANS_DATA)
needed = EXT3_MAX_TRANS_DATA;
return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
}
-/*
+/*
* Truncate transactions can be complex and absolutely huge. So we need to
* be able to restart the transaction at a conventient checkpoint to make
* sure we don't overflow the journal.
@@ -136,9 +137,9 @@ static unsigned long blocks_for_truncate(struct inode *inode)
* start_transaction gets us a new handle for a truncate transaction,
* and extend_transaction tries to extend the existing one a bit. If
* extend fails, we need to propagate the failure up and restart the
- * transaction in the top-level truncate loop. --sct
+ * transaction in the top-level truncate loop. --sct
*/
-static handle_t *start_transaction(struct inode *inode)
+static handle_t *start_transaction(struct inode *inode)
{
handle_t *result;
@@ -215,12 +216,12 @@ void ext3_delete_inode (struct inode * inode)
ext3_orphan_del(handle, inode);
EXT3_I(inode)->i_dtime = get_seconds();
- /*
+ /*
* One subtle ordering requirement: if anything has gone wrong
* (transaction abort, IO errors, whatever), then we can still
* do these next steps (the fs will already have been marked as
* having errors), but we can't free the inode if the mark_dirty
- * fails.
+ * fails.
*/
if (ext3_mark_inode_dirty(handle, inode))
/* If that failed, just do the required in-core inode clear. */
@@ -398,7 +399,7 @@ no_block:
* + if there is a block to the left of our position - allocate near it.
* + if pointer will live in indirect block - allocate near that block.
* + if pointer will live in inode - allocate in the same
- * cylinder group.
+ * cylinder group.
*
* In the latter case we colour the starting block by the callers PID to
* prevent it from clashing with concurrent allocations for a different inode
@@ -470,7 +471,7 @@ static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block,
* ext3_blks_to_allocate: Look up the block map and count the number
* of direct blocks need to be allocated for the given branch.
*
- * @branch: chain of indirect blocks
+ * @branch: chain of indirect blocks
* @k: number of blocks need for indirect blocks
* @blks: number of data blocks to be mapped.
* @blocks_to_boundary: the offset in the indirect block
@@ -744,7 +745,7 @@ static int ext3_splice_branch(handle_t *handle, struct inode *inode,
jbd_debug(5, "splicing indirect only\n");
BUFFER_TRACE(where->bh, "call ext3_journal_dirty_metadata");
err = ext3_journal_dirty_metadata(handle, where->bh);
- if (err)
+ if (err)
goto err_out;
} else {
/*
@@ -1073,7 +1074,7 @@ struct buffer_head *ext3_bread(handle_t *handle, struct inode *inode,
return bh;
if (buffer_uptodate(bh))
return bh;
- ll_rw_block(READ, 1, &bh);
+ ll_rw_block(READ_META, 1, &bh);
wait_on_buffer(bh);
if (buffer_uptodate(bh))
return bh;
@@ -1098,7 +1099,7 @@ static int walk_page_buffers( handle_t *handle,
for ( bh = head, block_start = 0;
ret == 0 && (bh != head || !block_start);
- block_start = block_end, bh = next)
+ block_start = block_end, bh = next)
{
next = bh->b_this_page;
block_end = block_start + blocksize;
@@ -1137,7 +1138,7 @@ static int walk_page_buffers( handle_t *handle,
* So what we do is to rely on the fact that journal_stop/journal_start
* will _not_ run commit under these circumstances because handle->h_ref
* is elevated. We'll still have enough credits for the tiny quotafile
- * write.
+ * write.
*/
static int do_journal_get_write_access(handle_t *handle,
struct buffer_head *bh)
@@ -1282,7 +1283,7 @@ static int ext3_journalled_commit_write(struct file *file,
if (inode->i_size > EXT3_I(inode)->i_disksize) {
EXT3_I(inode)->i_disksize = inode->i_size;
ret2 = ext3_mark_inode_dirty(handle, inode);
- if (!ret)
+ if (!ret)
ret = ret2;
}
ret2 = ext3_journal_stop(handle);
@@ -1291,7 +1292,7 @@ static int ext3_journalled_commit_write(struct file *file,
return ret;
}
-/*
+/*
* bmap() is special. It gets used by applications such as lilo and by
* the swapper to find the on-disk block of a specific piece of data.
*
@@ -1300,10 +1301,10 @@ static int ext3_journalled_commit_write(struct file *file,
* filesystem and enables swap, then they may get a nasty shock when the
* data getting swapped to that swapfile suddenly gets overwritten by
* the original zero's written out previously to the journal and
- * awaiting writeback in the kernel's buffer cache.
+ * awaiting writeback in the kernel's buffer cache.
*
* So, if we see any bmap calls here on a modified, data-journaled file,
- * take extra steps to flush any blocks which might be in the cache.
+ * take extra steps to flush any blocks which might be in the cache.
*/
static sector_t ext3_bmap(struct address_space *mapping, sector_t block)
{
@@ -1312,16 +1313,16 @@ static sector_t ext3_bmap(struct address_space *mapping, sector_t block)
int err;
if (EXT3_I(inode)->i_state & EXT3_STATE_JDATA) {
- /*
+ /*
* This is a REALLY heavyweight approach, but the use of
* bmap on dirty files is expected to be extremely rare:
* only if we run lilo or swapon on a freshly made file
- * do we expect this to happen.
+ * do we expect this to happen.
*
* (bmap requires CAP_SYS_RAWIO so this does not
* represent an unprivileged user DOS attack --- we'd be
* in trouble if mortal users could trigger this path at
- * will.)
+ * will.)
*
* NB. EXT3_STATE_JDATA is not set on files other than
* regular files. If somebody wants to bmap a directory
@@ -1457,7 +1458,7 @@ static int ext3_ordered_writepage(struct page *page,
*/
/*
- * And attach them to the current transaction. But only if
+ * And attach them to the current transaction. But only if
* block_write_full_page() succeeded. Otherwise they are unmapped,
* and generally junk.
*/
@@ -1644,7 +1645,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb,
}
}
- ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
offset, nr_segs,
ext3_get_block, NULL);
@@ -2025,7 +2026,7 @@ static void ext3_free_data(handle_t *handle, struct inode *inode,
__le32 *first, __le32 *last)
{
ext3_fsblk_t block_to_free = 0; /* Starting block # of a run */
- unsigned long count = 0; /* Number of blocks in the run */
+ unsigned long count = 0; /* Number of blocks in the run */
__le32 *block_to_free_p = NULL; /* Pointer into inode/ind
corresponding to
block_to_free */
@@ -2054,7 +2055,7 @@ static void ext3_free_data(handle_t *handle, struct inode *inode,
} else if (nr == block_to_free + count) {
count++;
} else {
- ext3_clear_blocks(handle, inode, this_bh,
+ ext3_clear_blocks(handle, inode, this_bh,
block_to_free,
count, block_to_free_p, p);
block_to_free = nr;
@@ -2115,7 +2116,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
*/
if (!bh) {
ext3_error(inode->i_sb, "ext3_free_branches",
- "Read failure, inode=%ld, block="E3FSBLK,
+ "Read failure, inode=%lu, block="E3FSBLK,
inode->i_ino, nr);
continue;
}
@@ -2184,7 +2185,7 @@ static void ext3_free_branches(handle_t *handle, struct inode *inode,
*p = 0;
BUFFER_TRACE(parent_bh,
"call ext3_journal_dirty_metadata");
- ext3_journal_dirty_metadata(handle,
+ ext3_journal_dirty_metadata(handle,
parent_bh);
}
}
@@ -2540,7 +2541,7 @@ make_io:
*/
get_bh(bh);
bh->b_end_io = end_buffer_read_sync;
- submit_bh(READ, bh);
+ submit_bh(READ_META, bh);
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
ext3_error(inode->i_sb, "ext3_get_inode_loc",
@@ -2632,9 +2633,6 @@ void ext3_read_inode(struct inode * inode)
* recovery code: that's fine, we're about to complete
* the process of deleting those. */
}
- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size
- * (for stat), not the fs block
- * size */
inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
ei->i_flags = le32_to_cpu(raw_inode->i_flags);
#ifdef EXT3_FRAGMENTS
@@ -2704,7 +2702,7 @@ void ext3_read_inode(struct inode * inode)
if (raw_inode->i_block[0])
init_special_inode(inode, inode->i_mode,
old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));
- else
+ else
init_special_inode(inode, inode->i_mode,
new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
}
@@ -2724,8 +2722,8 @@ bad_inode:
*
* The caller must have write access to iloc->bh.
*/
-static int ext3_do_update_inode(handle_t *handle,
- struct inode *inode,
+static int ext3_do_update_inode(handle_t *handle,
+ struct inode *inode,
struct ext3_iloc *iloc)
{
struct ext3_inode *raw_inode = ext3_raw_inode(iloc);
@@ -2900,7 +2898,7 @@ int ext3_write_inode(struct inode *inode, int wait)
* commit will leave the blocks being flushed in an unused state on
* disk. (On recovery, the inode will get truncated and the blocks will
* be freed, so we have a strong guarantee that no future commit will
- * leave these blocks visible to the user.)
+ * leave these blocks visible to the user.)
*
* Called with inode->sem down.
*/
@@ -3043,13 +3041,13 @@ int ext3_mark_iloc_dirty(handle_t *handle,
return err;
}
-/*
+/*
* On success, We end up with an outstanding reference count against
- * iloc->bh. This _must_ be cleaned up later.
+ * iloc->bh. This _must_ be cleaned up later.
*/
int
-ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
+ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
struct ext3_iloc *iloc)
{
int err = 0;
@@ -3139,7 +3137,7 @@ out:
}
#if 0
-/*
+/*
* Bind an inode's backing buffer_head into this transaction, to prevent
* it from being flushed to disk early. Unlike
* ext3_reserve_inode_write, this leaves behind no bh reference and
@@ -3157,7 +3155,7 @@ static int ext3_pin_inode(handle_t *handle, struct inode *inode)
BUFFER_TRACE(iloc.bh, "get_write_access");
err = journal_get_write_access(handle, iloc.bh);
if (!err)
- err = ext3_journal_dirty_metadata(handle,
+ err = ext3_journal_dirty_metadata(handle,
iloc.bh);
brelse(iloc.bh);
}
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c
index 3a6b012d120c..12daa6869572 100644
--- a/fs/ext3/ioctl.c
+++ b/fs/ext3/ioctl.c
@@ -13,9 +13,10 @@
#include <linux/ext3_fs.h>
#include <linux/ext3_jbd.h>
#include <linux/time.h>
+#include <linux/compat.h>
+#include <linux/smp_lock.h>
#include <asm/uaccess.h>
-
int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
unsigned long arg)
{
@@ -252,3 +253,55 @@ flags_err:
return -ENOTTY;
}
}
+
+#ifdef CONFIG_COMPAT
+long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ /* These are just misnamed, they actually get/put from/to user an int */
+ switch (cmd) {
+ case EXT3_IOC32_GETFLAGS:
+ cmd = EXT3_IOC_GETFLAGS;
+ break;
+ case EXT3_IOC32_SETFLAGS:
+ cmd = EXT3_IOC_SETFLAGS;
+ break;
+ case EXT3_IOC32_GETVERSION:
+ cmd = EXT3_IOC_GETVERSION;
+ break;
+ case EXT3_IOC32_SETVERSION:
+ cmd = EXT3_IOC_SETVERSION;
+ break;
+ case EXT3_IOC32_GROUP_EXTEND:
+ cmd = EXT3_IOC_GROUP_EXTEND;
+ break;
+ case EXT3_IOC32_GETVERSION_OLD:
+ cmd = EXT3_IOC_GETVERSION_OLD;
+ break;
+ case EXT3_IOC32_SETVERSION_OLD:
+ cmd = EXT3_IOC_SETVERSION_OLD;
+ break;
+#ifdef CONFIG_JBD_DEBUG
+ case EXT3_IOC32_WAIT_FOR_READONLY:
+ cmd = EXT3_IOC_WAIT_FOR_READONLY;
+ break;
+#endif
+ case EXT3_IOC32_GETRSVSZ:
+ cmd = EXT3_IOC_GETRSVSZ;
+ break;
+ case EXT3_IOC32_SETRSVSZ:
+ cmd = EXT3_IOC_SETRSVSZ;
+ break;
+ case EXT3_IOC_GROUP_ADD:
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ lock_kernel();
+ ret = ext3_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
+ unlock_kernel();
+ return ret;
+}
+#endif
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 2aa7101b27cd..906731a20f1a 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -15,13 +15,13 @@
* Big-endian to little-endian byte-swapping/bitmaps by
* David S. Miller (davem@caip.rutgers.edu), 1995
* Directory entry file type support and forward compatibility hooks
- * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
+ * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
* Hash Tree Directory indexing (c)
- * Daniel Phillips, 2001
+ * Daniel Phillips, 2001
* Hash Tree Directory indexing porting
- * Christopher Li, 2002
+ * Christopher Li, 2002
* Hash Tree Directory indexing cleanup
- * Theodore Ts'o, 2002
+ * Theodore Ts'o, 2002
*/
#include <linux/fs.h>
@@ -35,6 +35,7 @@
#include <linux/string.h>
#include <linux/quotaops.h>
#include <linux/buffer_head.h>
+#include <linux/bio.h>
#include <linux/smp_lock.h>
#include "namei.h"
@@ -76,7 +77,7 @@ static struct buffer_head *ext3_append(handle_t *handle,
#ifdef DX_DEBUG
#define dxtrace(command) command
#else
-#define dxtrace(command)
+#define dxtrace(command)
#endif
struct fake_dirent
@@ -169,7 +170,7 @@ static struct ext3_dir_entry_2* dx_pack_dirents (char *base, int size);
static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
static int ext3_htree_next_block(struct inode *dir, __u32 hash,
struct dx_frame *frame,
- struct dx_frame *frames,
+ struct dx_frame *frames,
__u32 *start_hash);
static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
struct ext3_dir_entry_2 **res_dir, int *err);
@@ -250,7 +251,7 @@ static void dx_show_index (char * label, struct dx_entry *entries)
}
struct stats
-{
+{
unsigned names;
unsigned space;
unsigned bcount;
@@ -278,7 +279,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent
((char *) de - base));
}
space += EXT3_DIR_REC_LEN(de->name_len);
- names++;
+ names++;
}
de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
}
@@ -464,7 +465,7 @@ static void dx_release (struct dx_frame *frames)
*/
static int ext3_htree_next_block(struct inode *dir, __u32 hash,
struct dx_frame *frame,
- struct dx_frame *frames,
+ struct dx_frame *frames,
__u32 *start_hash)
{
struct dx_frame *p;
@@ -632,7 +633,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
}
count += ret;
hashval = ~0;
- ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS,
+ ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS,
frame, frames, &hashval);
*next_hash = hashval;
if (ret < 0) {
@@ -649,7 +650,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash,
break;
}
dx_release(frames);
- dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
+ dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
count, *next_hash));
return count;
errout:
@@ -870,7 +871,7 @@ restart:
bh = ext3_getblk(NULL, dir, b++, 0, &err);
bh_use[ra_max] = bh;
if (bh)
- ll_rw_block(READ, 1, &bh);
+ ll_rw_block(READ_META, 1, &bh);
}
}
if ((bh = bh_use[ra_ptr++]) == NULL)
@@ -1050,7 +1051,7 @@ struct dentry *ext3_get_parent(struct dentry *child)
parent = ERR_PTR(-ENOMEM);
}
return parent;
-}
+}
#define S_SHIFT 12
static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = {
@@ -1198,7 +1199,7 @@ errout:
* add_dirent_to_buf will attempt search the directory block for
* space. It will return -ENOSPC if no space is available, and -EIO
* and -EEXIST if directory entry already exists.
- *
+ *
* NOTE! bh is NOT released in the case where ENOSPC is returned. In
* all other cases bh is released.
*/
@@ -1572,7 +1573,7 @@ cleanup:
* ext3_delete_entry deletes a directory entry by merging it with the
* previous entry
*/
-static int ext3_delete_entry (handle_t *handle,
+static int ext3_delete_entry (handle_t *handle,
struct inode * dir,
struct ext3_dir_entry_2 * de_del,
struct buffer_head * bh)
@@ -1615,12 +1616,12 @@ static int ext3_delete_entry (handle_t *handle,
*/
static inline void ext3_inc_count(handle_t *handle, struct inode *inode)
{
- inode->i_nlink++;
+ inc_nlink(inode);
}
static inline void ext3_dec_count(handle_t *handle, struct inode *inode)
{
- inode->i_nlink--;
+ drop_nlink(inode);
}
static int ext3_add_nondir(handle_t *handle,
@@ -1643,12 +1644,12 @@ static int ext3_add_nondir(handle_t *handle,
* is so far negative - it has no inode.
*
* If the create succeeds, we fill in the inode information
- * with d_instantiate().
+ * with d_instantiate().
*/
static int ext3_create (struct inode * dir, struct dentry * dentry, int mode,
struct nameidata *nd)
{
- handle_t *handle;
+ handle_t *handle;
struct inode * inode;
int err, retries = 0;
@@ -1688,7 +1689,7 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry,
retry:
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
- EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+ EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -1742,7 +1743,7 @@ retry:
inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize;
dir_block = ext3_bread (handle, inode, 0, 1, &err);
if (!dir_block) {
- inode->i_nlink--; /* is this nlink == 0? */
+ drop_nlink(inode); /* is this nlink == 0? */
ext3_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
@@ -1774,7 +1775,7 @@ retry:
iput (inode);
goto out_stop;
}
- dir->i_nlink++;
+ inc_nlink(dir);
ext3_update_dx_flag(dir);
ext3_mark_inode_dirty(handle, dir);
d_instantiate(dentry, inode);
@@ -1813,10 +1814,10 @@ static int empty_dir (struct inode * inode)
de1 = (struct ext3_dir_entry_2 *)
((char *) de + le16_to_cpu(de->rec_len));
if (le32_to_cpu(de->inode) != inode->i_ino ||
- !le32_to_cpu(de1->inode) ||
+ !le32_to_cpu(de1->inode) ||
strcmp (".", de->name) ||
strcmp ("..", de1->name)) {
- ext3_warning (inode->i_sb, "empty_dir",
+ ext3_warning (inode->i_sb, "empty_dir",
"bad directory (dir #%lu) - no `.' or `..'",
inode->i_ino);
brelse (bh);
@@ -1883,7 +1884,7 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode)
* being truncated, or files being unlinked. */
/* @@@ FIXME: Observation from aviro:
- * I think I can trigger J_ASSERT in ext3_orphan_add(). We block
+ * I think I can trigger J_ASSERT in ext3_orphan_add(). We block
* here (on lock_super()), so race with ext3_link() which might bump
* ->i_nlink. For, say it, character device. Not a regular file,
* not a directory, not a symlink and ->i_nlink > 0.
@@ -1919,8 +1920,8 @@ int ext3_orphan_add(handle_t *handle, struct inode *inode)
if (!err)
list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan);
- jbd_debug(4, "superblock will point to %ld\n", inode->i_ino);
- jbd_debug(4, "orphan inode %ld will point to %d\n",
+ jbd_debug(4, "superblock will point to %lu\n", inode->i_ino);
+ jbd_debug(4, "orphan inode %lu will point to %d\n",
inode->i_ino, NEXT_ORPHAN(inode));
out_unlock:
unlock_super(sb);
@@ -2044,7 +2045,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
"empty directory has nlink!=2 (%d)",
inode->i_nlink);
inode->i_version++;
- inode->i_nlink = 0;
+ clear_nlink(inode);
/* There's no need to set i_disksize: the fact that i_nlink is
* zero will ensure that the right thing happens during any
* recovery. */
@@ -2052,7 +2053,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
ext3_orphan_add(handle, inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
ext3_mark_inode_dirty(handle, inode);
- dir->i_nlink--;
+ drop_nlink(dir);
ext3_update_dx_flag(dir);
ext3_mark_inode_dirty(handle, dir);
@@ -2103,7 +2104,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
ext3_update_dx_flag(dir);
ext3_mark_inode_dirty(handle, dir);
- inode->i_nlink--;
+ drop_nlink(inode);
if (!inode->i_nlink)
ext3_orphan_add(handle, inode);
inode->i_ctime = dir->i_ctime;
@@ -2129,7 +2130,7 @@ static int ext3_symlink (struct inode * dir,
retry:
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
- EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
+ EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -2227,7 +2228,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
DQUOT_INIT(new_dentry->d_inode);
handle = ext3_journal_start(old_dir, 2 *
EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) +
- EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
+ EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -2325,7 +2326,7 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
}
if (new_inode) {
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
@@ -2336,11 +2337,11 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata");
ext3_journal_dirty_metadata(handle, dir_bh);
- old_dir->i_nlink--;
+ drop_nlink(old_dir);
if (new_inode) {
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
} else {
- new_dir->i_nlink++;
+ inc_nlink(new_dir);
ext3_update_dx_flag(new_dir);
ext3_mark_inode_dirty(handle, new_dir);
}
@@ -2393,4 +2394,4 @@ struct inode_operations ext3_special_inode_operations = {
.removexattr = generic_removexattr,
#endif
.permission = ext3_permission,
-};
+};
diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c
index 5e1337fd878a..b73cba12f79c 100644
--- a/fs/ext3/resize.c
+++ b/fs/ext3/resize.c
@@ -336,7 +336,7 @@ static int verify_reserved_gdb(struct super_block *sb,
unsigned five = 5;
unsigned seven = 7;
unsigned grp;
- __u32 *p = (__u32 *)primary->b_data;
+ __le32 *p = (__le32 *)primary->b_data;
int gdbackups = 0;
while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) {
@@ -380,7 +380,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
struct buffer_head *dind;
int gdbackups;
struct ext3_iloc iloc;
- __u32 *data;
+ __le32 *data;
int err;
if (test_opt(sb, DEBUG))
@@ -417,7 +417,7 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
goto exit_bh;
}
- data = (__u32 *)dind->b_data;
+ data = (__le32 *)dind->b_data;
if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) {
ext3_warning(sb, __FUNCTION__,
"new group %u GDT block "E3FSBLK" not reserved",
@@ -439,8 +439,8 @@ static int add_new_gdb(handle_t *handle, struct inode *inode,
if ((err = ext3_reserve_inode_write(handle, inode, &iloc)))
goto exit_dindj;
- n_group_desc = (struct buffer_head **)kmalloc((gdb_num + 1) *
- sizeof(struct buffer_head *), GFP_KERNEL);
+ n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
+ GFP_KERNEL);
if (!n_group_desc) {
err = -ENOMEM;
ext3_warning (sb, __FUNCTION__,
@@ -519,7 +519,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
struct buffer_head *dind;
struct ext3_iloc iloc;
ext3_fsblk_t blk;
- __u32 *data, *end;
+ __le32 *data, *end;
int gdbackups = 0;
int res, i;
int err;
@@ -536,8 +536,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
}
blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count;
- data = (__u32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count;
- end = (__u32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb);
+ data = (__le32 *)dind->b_data + EXT3_SB(sb)->s_gdb_count;
+ end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb);
/* Get each reserved primary GDT block and verify it holds backups */
for (res = 0; res < reserved_gdb; res++, blk++) {
@@ -545,7 +545,8 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
ext3_warning(sb, __FUNCTION__,
"reserved block "E3FSBLK
" not at offset %ld",
- blk, (long)(data - (__u32 *)dind->b_data));
+ blk,
+ (long)(data - (__le32 *)dind->b_data));
err = -EINVAL;
goto exit_bh;
}
@@ -560,7 +561,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
goto exit_bh;
}
if (++data >= end)
- data = (__u32 *)dind->b_data;
+ data = (__le32 *)dind->b_data;
}
for (i = 0; i < reserved_gdb; i++) {
@@ -584,7 +585,7 @@ static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
blk = input->group * EXT3_BLOCKS_PER_GROUP(sb);
for (i = 0; i < reserved_gdb; i++) {
int err2;
- data = (__u32 *)primary[i]->b_data;
+ data = (__le32 *)primary[i]->b_data;
/* printk("reserving backup %lu[%u] = %lu\n",
primary[i]->b_blocknr, gdbackups,
blk + primary[i]->b_blocknr); */
@@ -689,7 +690,7 @@ exit_err:
"can't update backup for group %d (err %d), "
"forcing fsck on next reboot", group, err);
sbi->s_mount_state &= ~EXT3_VALID_FS;
- sbi->s_es->s_state &= ~cpu_to_le16(EXT3_VALID_FS);
+ sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS);
mark_buffer_dirty(sbi->s_sbh);
}
}
@@ -730,6 +731,18 @@ int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input)
return -EPERM;
}
+ if (le32_to_cpu(es->s_blocks_count) + input->blocks_count <
+ le32_to_cpu(es->s_blocks_count)) {
+ ext3_warning(sb, __FUNCTION__, "blocks_count overflow\n");
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) <
+ le32_to_cpu(es->s_inodes_count)) {
+ ext3_warning(sb, __FUNCTION__, "inodes_count overflow\n");
+ return -EINVAL;
+ }
+
if (reserved_gdb || gdb_off == 0) {
if (!EXT3_HAS_COMPAT_FEATURE(sb,
EXT3_FEATURE_COMPAT_RESIZE_INODE)){
@@ -958,6 +971,11 @@ int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es,
add = EXT3_BLOCKS_PER_GROUP(sb) - last;
+ if (o_blocks_count + add < o_blocks_count) {
+ ext3_warning(sb, __FUNCTION__, "blocks_count overflow");
+ return -EINVAL;
+ }
+
if (o_blocks_count + add > n_blocks_count)
add = n_blocks_count - o_blocks_count;
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 3559086eee5f..afc2d4f42d77 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -45,7 +45,7 @@
static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
unsigned long journal_devnum);
static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
- int);
+ unsigned int);
static void ext3_commit_super (struct super_block * sb,
struct ext3_super_block * es,
int sync);
@@ -62,13 +62,13 @@ static void ext3_unlockfs(struct super_block *sb);
static void ext3_write_super (struct super_block * sb);
static void ext3_write_super_lockfs(struct super_block *sb);
-/*
+/*
* Wrappers for journal_start/end.
*
* The only special thing we need to do here is to make sure that all
* journal_end calls result in the superblock being marked dirty, so
* that sync() will call the filesystem's write_super callback if
- * appropriate.
+ * appropriate.
*/
handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
{
@@ -90,11 +90,11 @@ handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks)
return journal_start(journal, nblocks);
}
-/*
+/*
* The only special thing we need to do here is to make sure that all
* journal_stop calls result in the superblock being marked dirty, so
* that sync() will call the filesystem's write_super callback if
- * appropriate.
+ * appropriate.
*/
int __ext3_journal_stop(const char *where, handle_t *handle)
{
@@ -159,20 +159,21 @@ static void ext3_handle_error(struct super_block *sb)
if (sb->s_flags & MS_RDONLY)
return;
- if (test_opt (sb, ERRORS_RO)) {
- printk (KERN_CRIT "Remounting filesystem read-only\n");
- sb->s_flags |= MS_RDONLY;
- } else {
+ if (!test_opt (sb, ERRORS_CONT)) {
journal_t *journal = EXT3_SB(sb)->s_journal;
EXT3_SB(sb)->s_mount_opt |= EXT3_MOUNT_ABORT;
if (journal)
journal_abort(journal, -EIO);
}
+ if (test_opt (sb, ERRORS_RO)) {
+ printk (KERN_CRIT "Remounting filesystem read-only\n");
+ sb->s_flags |= MS_RDONLY;
+ }
+ ext3_commit_super(sb, es, 1);
if (test_opt(sb, ERRORS_PANIC))
panic("EXT3-fs (device %s): panic forced after error\n",
sb->s_id);
- ext3_commit_super(sb, es, 1);
}
void ext3_error (struct super_block * sb, const char * function,
@@ -369,16 +370,16 @@ static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi)
{
struct list_head *l;
- printk(KERN_ERR "sb orphan head is %d\n",
+ printk(KERN_ERR "sb orphan head is %d\n",
le32_to_cpu(sbi->s_es->s_last_orphan));
printk(KERN_ERR "sb_info orphan list:\n");
list_for_each(l, &sbi->s_orphan) {
struct inode *inode = orphan_list_entry(l);
printk(KERN_ERR " "
- "inode %s:%ld at %p: mode %o, nlink %d, next %d\n",
+ "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
inode->i_sb->s_id, inode->i_ino, inode,
- inode->i_mode, inode->i_nlink,
+ inode->i_mode, inode->i_nlink,
NEXT_ORPHAN(inode));
}
}
@@ -475,7 +476,7 @@ static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
inode_init_once(&ei->vfs_inode);
}
}
-
+
static int init_inodecache(void)
{
ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
@@ -490,8 +491,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(ext3_inode_cachep))
- printk(KERN_INFO "ext3_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(ext3_inode_cachep);
}
static void ext3_clear_inode(struct inode *inode)
@@ -733,8 +733,8 @@ static match_table_t tokens = {
static ext3_fsblk_t get_sb_block(void **data)
{
- ext3_fsblk_t sb_block;
- char *options = (char *) *data;
+ ext3_fsblk_t sb_block;
+ char *options = (char *) *data;
if (!options || strncmp(options, "sb=", 3) != 0)
return 1; /* Default location */
@@ -753,7 +753,7 @@ static ext3_fsblk_t get_sb_block(void **data)
}
static int parse_options (char *options, struct super_block *sb,
- unsigned long *inum, unsigned long *journal_devnum,
+ unsigned int *inum, unsigned long *journal_devnum,
ext3_fsblk_t *n_blocks_count, int is_remount)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
@@ -1174,7 +1174,8 @@ static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es,
static int ext3_check_descriptors (struct super_block * sb)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
- ext3_fsblk_t block = le32_to_cpu(sbi->s_es->s_first_data_block);
+ ext3_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
+ ext3_fsblk_t last_block;
struct ext3_group_desc * gdp = NULL;
int desc_block = 0;
int i;
@@ -1183,12 +1184,17 @@ static int ext3_check_descriptors (struct super_block * sb)
for (i = 0; i < sbi->s_groups_count; i++)
{
+ if (i == sbi->s_groups_count - 1)
+ last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1;
+ else
+ last_block = first_block +
+ (EXT3_BLOCKS_PER_GROUP(sb) - 1);
+
if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
gdp = (struct ext3_group_desc *)
sbi->s_group_desc[desc_block++]->b_data;
- if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
- le32_to_cpu(gdp->bg_block_bitmap) >=
- block + EXT3_BLOCKS_PER_GROUP(sb))
+ if (le32_to_cpu(gdp->bg_block_bitmap) < first_block ||
+ le32_to_cpu(gdp->bg_block_bitmap) > last_block)
{
ext3_error (sb, "ext3_check_descriptors",
"Block bitmap for group %d"
@@ -1197,9 +1203,8 @@ static int ext3_check_descriptors (struct super_block * sb)
le32_to_cpu(gdp->bg_block_bitmap));
return 0;
}
- if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
- le32_to_cpu(gdp->bg_inode_bitmap) >=
- block + EXT3_BLOCKS_PER_GROUP(sb))
+ if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block ||
+ le32_to_cpu(gdp->bg_inode_bitmap) > last_block)
{
ext3_error (sb, "ext3_check_descriptors",
"Inode bitmap for group %d"
@@ -1208,9 +1213,9 @@ static int ext3_check_descriptors (struct super_block * sb)
le32_to_cpu(gdp->bg_inode_bitmap));
return 0;
}
- if (le32_to_cpu(gdp->bg_inode_table) < block ||
- le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >=
- block + EXT3_BLOCKS_PER_GROUP(sb))
+ if (le32_to_cpu(gdp->bg_inode_table) < first_block ||
+ le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group >
+ last_block)
{
ext3_error (sb, "ext3_check_descriptors",
"Inode table for group %d"
@@ -1219,7 +1224,7 @@ static int ext3_check_descriptors (struct super_block * sb)
le32_to_cpu(gdp->bg_inode_table));
return 0;
}
- block += EXT3_BLOCKS_PER_GROUP(sb);
+ first_block += EXT3_BLOCKS_PER_GROUP(sb);
gdp++;
}
@@ -1301,17 +1306,17 @@ static void ext3_orphan_cleanup (struct super_block * sb,
DQUOT_INIT(inode);
if (inode->i_nlink) {
printk(KERN_DEBUG
- "%s: truncating inode %ld to %Ld bytes\n",
+ "%s: truncating inode %lu to %Ld bytes\n",
__FUNCTION__, inode->i_ino, inode->i_size);
- jbd_debug(2, "truncating inode %ld to %Ld bytes\n",
+ jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
inode->i_ino, inode->i_size);
ext3_truncate(inode);
nr_truncates++;
} else {
printk(KERN_DEBUG
- "%s: deleting unreferenced inode %ld\n",
+ "%s: deleting unreferenced inode %lu\n",
__FUNCTION__, inode->i_ino);
- jbd_debug(2, "deleting unreferenced inode %ld\n",
+ jbd_debug(2, "deleting unreferenced inode %lu\n",
inode->i_ino);
nr_orphans++;
}
@@ -1390,7 +1395,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
ext3_fsblk_t sb_block = get_sb_block(&data);
ext3_fsblk_t logic_sb_block;
unsigned long offset = 0;
- unsigned long journal_inum = 0;
+ unsigned int journal_inum = 0;
unsigned long journal_devnum = 0;
unsigned long def_mount_opts;
struct inode *root;
@@ -1401,11 +1406,10 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
int needs_recovery;
__le32 features;
- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_fs_info = sbi;
- memset(sbi, 0, sizeof(*sbi));
sbi->s_mount_opt = 0;
sbi->s_resuid = EXT3_DEF_RESUID;
sbi->s_resgid = EXT3_DEF_RESGID;
@@ -1466,6 +1470,8 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
set_opt(sbi->s_mount_opt, ERRORS_PANIC);
else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_RO)
set_opt(sbi->s_mount_opt, ERRORS_RO);
+ else
+ set_opt(sbi->s_mount_opt, ERRORS_CONT);
sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
@@ -1483,7 +1489,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
(EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U)))
- printk(KERN_WARNING
+ printk(KERN_WARNING
"EXT3-fs warning: feature flags set on rev 0 fs, "
"running e2fsck is recommended\n");
/*
@@ -1509,7 +1515,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
if (blocksize < EXT3_MIN_BLOCK_SIZE ||
blocksize > EXT3_MAX_BLOCK_SIZE) {
- printk(KERN_ERR
+ printk(KERN_ERR
"EXT3-fs: Unsupported filesystem blocksize %d on %s.\n",
blocksize, sb->s_id);
goto failed_mount;
@@ -1533,14 +1539,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize;
bh = sb_bread(sb, logic_sb_block);
if (!bh) {
- printk(KERN_ERR
+ printk(KERN_ERR
"EXT3-fs: Can't read superblock on 2nd try.\n");
goto failed_mount;
}
es = (struct ext3_super_block *)(((char *)bh->b_data) + offset);
sbi->s_es = es;
if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) {
- printk (KERN_ERR
+ printk (KERN_ERR
"EXT3-fs: Magic mismatch, very weird !\n");
goto failed_mount;
}
@@ -1622,10 +1628,9 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
if (EXT3_BLOCKS_PER_GROUP(sb) == 0)
goto cantfind_ext3;
- sbi->s_groups_count = (le32_to_cpu(es->s_blocks_count) -
- le32_to_cpu(es->s_first_data_block) +
- EXT3_BLOCKS_PER_GROUP(sb) - 1) /
- EXT3_BLOCKS_PER_GROUP(sb);
+ sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -
+ le32_to_cpu(es->s_first_data_block) - 1)
+ / EXT3_BLOCKS_PER_GROUP(sb)) + 1;
db_count = (sbi->s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
EXT3_DESC_PER_BLOCK(sb);
sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
@@ -1820,7 +1825,7 @@ out_fail:
/*
* Setup any per-fs journal parameters now. We'll do this both on
* initial mount, once the journal has been initialised but before we've
- * done any recovery; and again on any subsequent remount.
+ * done any recovery; and again on any subsequent remount.
*/
static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
{
@@ -1840,7 +1845,8 @@ static void ext3_init_journal_params(struct super_block *sb, journal_t *journal)
spin_unlock(&journal->j_state_lock);
}
-static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
+static journal_t *ext3_get_journal(struct super_block *sb,
+ unsigned int journal_inum)
{
struct inode *journal_inode;
journal_t *journal;
@@ -1975,7 +1981,7 @@ static int ext3_load_journal(struct super_block *sb,
unsigned long journal_devnum)
{
journal_t *journal;
- int journal_inum = le32_to_cpu(es->s_journal_inum);
+ unsigned int journal_inum = le32_to_cpu(es->s_journal_inum);
dev_t journal_dev;
int err = 0;
int really_read_only;
@@ -2061,7 +2067,7 @@ static int ext3_load_journal(struct super_block *sb,
static int ext3_create_journal(struct super_block * sb,
struct ext3_super_block * es,
- int journal_inum)
+ unsigned int journal_inum)
{
journal_t *journal;
@@ -2074,7 +2080,7 @@ static int ext3_create_journal(struct super_block * sb,
if (!(journal = ext3_get_journal(sb, journal_inum)))
return -EINVAL;
- printk(KERN_INFO "EXT3-fs: creating new journal on inode %d\n",
+ printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n",
journal_inum);
if (journal_create(journal)) {
@@ -2342,10 +2348,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
*/
ext3_clear_journal_err(sb, es);
sbi->s_mount_state = le16_to_cpu(es->s_state);
- if ((ret = ext3_group_extend(sb, es, n_blocks_count))) {
- err = ret;
+ if ((err = ext3_group_extend(sb, es, n_blocks_count)))
goto restore_opts;
- }
if (!ext3_setup_super (sb, es, 0))
sb->s_flags &= ~MS_RDONLY;
}
@@ -2734,7 +2738,7 @@ static int __init init_ext3_fs(void)
out:
destroy_inodecache();
out1:
- exit_ext3_xattr();
+ exit_ext3_xattr();
return err;
}
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index a44a0562203a..f86f2482f01d 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -75,7 +75,7 @@
#ifdef EXT3_XATTR_DEBUG
# define ea_idebug(inode, f...) do { \
- printk(KERN_DEBUG "inode %s:%ld: ", \
+ printk(KERN_DEBUG "inode %s:%lu: ", \
inode->i_sb->s_id, inode->i_ino); \
printk(f); \
printk("\n"); \
@@ -233,7 +233,7 @@ ext3_xattr_block_get(struct inode *inode, int name_index, const char *name,
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext3_xattr_check_block(bh)) {
bad_block: ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block "E3FSBLK, inode->i_ino,
+ "inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
goto cleanup;
@@ -375,7 +375,7 @@ ext3_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
if (ext3_xattr_check_block(bh)) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block "E3FSBLK, inode->i_ino,
+ "inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
goto cleanup;
@@ -647,7 +647,7 @@ ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i,
le32_to_cpu(BHDR(bs->bh)->h_refcount));
if (ext3_xattr_check_block(bs->bh)) {
ext3_error(sb, __FUNCTION__,
- "inode %ld: bad block "E3FSBLK, inode->i_ino,
+ "inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
error = -EIO;
goto cleanup;
@@ -848,7 +848,7 @@ cleanup_dquot:
bad_block:
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block "E3FSBLK, inode->i_ino,
+ "inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
@@ -1077,14 +1077,14 @@ ext3_xattr_delete_inode(handle_t *handle, struct inode *inode)
bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl);
if (!bh) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: block "E3FSBLK" read error", inode->i_ino,
+ "inode %lu: block "E3FSBLK" read error", inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
}
if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) ||
BHDR(bh)->h_blocks != cpu_to_le32(1)) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: bad block "E3FSBLK, inode->i_ino,
+ "inode %lu: bad block "E3FSBLK, inode->i_ino,
EXT3_I(inode)->i_file_acl);
goto cleanup;
}
@@ -1211,7 +1211,7 @@ again:
bh = sb_bread(inode->i_sb, ce->e_block);
if (!bh) {
ext3_error(inode->i_sb, __FUNCTION__,
- "inode %ld: block %lu read error",
+ "inode %lu: block %lu read error",
inode->i_ino, (unsigned long) ce->e_block);
} else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
EXT3_XATTR_REFCOUNT_MAX) {
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
new file mode 100644
index 000000000000..a6acb96ebeb9
--- /dev/null
+++ b/fs/ext4/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux ext4-filesystem routines.
+#
+
+obj-$(CONFIG_EXT4DEV_FS) += ext4dev.o
+
+ext4dev-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+ ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o
+
+ext4dev-$(CONFIG_EXT4DEV_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
+ext4dev-$(CONFIG_EXT4DEV_FS_POSIX_ACL) += acl.o
+ext4dev-$(CONFIG_EXT4DEV_FS_SECURITY) += xattr_security.o
diff --git a/fs/ext4/acl.c b/fs/ext4/acl.c
new file mode 100644
index 000000000000..9e882546d91a
--- /dev/null
+++ b/fs/ext4/acl.c
@@ -0,0 +1,551 @@
+/*
+ * linux/fs/ext4/acl.c
+ *
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/ext4_fs.h>
+#include "xattr.h"
+#include "acl.h"
+
+/*
+ * Convert from filesystem to in-memory representation.
+ */
+static struct posix_acl *
+ext4_acl_from_disk(const void *value, size_t size)
+{
+ const char *end = (char *)value + size;
+ int n, count;
+ struct posix_acl *acl;
+
+ if (!value)
+ return NULL;
+ if (size < sizeof(ext4_acl_header))
+ return ERR_PTR(-EINVAL);
+ if (((ext4_acl_header *)value)->a_version !=
+ cpu_to_le32(EXT4_ACL_VERSION))
+ return ERR_PTR(-EINVAL);
+ value = (char *)value + sizeof(ext4_acl_header);
+ count = ext4_acl_count(size);
+ if (count < 0)
+ return ERR_PTR(-EINVAL);
+ if (count == 0)
+ return NULL;
+ acl = posix_acl_alloc(count, GFP_KERNEL);
+ if (!acl)
+ return ERR_PTR(-ENOMEM);
+ for (n=0; n < count; n++) {
+ ext4_acl_entry *entry =
+ (ext4_acl_entry *)value;
+ if ((char *)value + sizeof(ext4_acl_entry_short) > end)
+ goto fail;
+ acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
+ acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
+ switch(acl->a_entries[n].e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ value = (char *)value +
+ sizeof(ext4_acl_entry_short);
+ acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ value = (char *)value + sizeof(ext4_acl_entry);
+ if ((char *)value > end)
+ goto fail;
+ acl->a_entries[n].e_id =
+ le32_to_cpu(entry->e_id);
+ break;
+
+ default:
+ goto fail;
+ }
+ }
+ if (value != end)
+ goto fail;
+ return acl;
+
+fail:
+ posix_acl_release(acl);
+ return ERR_PTR(-EINVAL);
+}
+
+/*
+ * Convert from in-memory to filesystem representation.
+ */
+static void *
+ext4_acl_to_disk(const struct posix_acl *acl, size_t *size)
+{
+ ext4_acl_header *ext_acl;
+ char *e;
+ size_t n;
+
+ *size = ext4_acl_size(acl->a_count);
+ ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count *
+ sizeof(ext4_acl_entry), GFP_KERNEL);
+ if (!ext_acl)
+ return ERR_PTR(-ENOMEM);
+ ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION);
+ e = (char *)ext_acl + sizeof(ext4_acl_header);
+ for (n=0; n < acl->a_count; n++) {
+ ext4_acl_entry *entry = (ext4_acl_entry *)e;
+ entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
+ entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
+ switch(acl->a_entries[n].e_tag) {
+ case ACL_USER:
+ case ACL_GROUP:
+ entry->e_id =
+ cpu_to_le32(acl->a_entries[n].e_id);
+ e += sizeof(ext4_acl_entry);
+ break;
+
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ e += sizeof(ext4_acl_entry_short);
+ break;
+
+ default:
+ goto fail;
+ }
+ }
+ return (char *)ext_acl;
+
+fail:
+ kfree(ext_acl);
+ return ERR_PTR(-EINVAL);
+}
+
+static inline struct posix_acl *
+ext4_iget_acl(struct inode *inode, struct posix_acl **i_acl)
+{
+ struct posix_acl *acl = EXT4_ACL_NOT_CACHED;
+
+ spin_lock(&inode->i_lock);
+ if (*i_acl != EXT4_ACL_NOT_CACHED)
+ acl = posix_acl_dup(*i_acl);
+ spin_unlock(&inode->i_lock);
+
+ return acl;
+}
+
+static inline void
+ext4_iset_acl(struct inode *inode, struct posix_acl **i_acl,
+ struct posix_acl *acl)
+{
+ spin_lock(&inode->i_lock);
+ if (*i_acl != EXT4_ACL_NOT_CACHED)
+ posix_acl_release(*i_acl);
+ *i_acl = posix_acl_dup(acl);
+ spin_unlock(&inode->i_lock);
+}
+
+/*
+ * Inode operation get_posix_acl().
+ *
+ * inode->i_mutex: don't care
+ */
+static struct posix_acl *
+ext4_get_acl(struct inode *inode, int type)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ int name_index;
+ char *value = NULL;
+ struct posix_acl *acl;
+ int retval;
+
+ if (!test_opt(inode->i_sb, POSIX_ACL))
+ return NULL;
+
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ acl = ext4_iget_acl(inode, &ei->i_acl);
+ if (acl != EXT4_ACL_NOT_CACHED)
+ return acl;
+ name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ acl = ext4_iget_acl(inode, &ei->i_default_acl);
+ if (acl != EXT4_ACL_NOT_CACHED)
+ return acl;
+ name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
+ break;
+
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ retval = ext4_xattr_get(inode, name_index, "", NULL, 0);
+ if (retval > 0) {
+ value = kmalloc(retval, GFP_KERNEL);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
+ retval = ext4_xattr_get(inode, name_index, "", value, retval);
+ }
+ if (retval > 0)
+ acl = ext4_acl_from_disk(value, retval);
+ else if (retval == -ENODATA || retval == -ENOSYS)
+ acl = NULL;
+ else
+ acl = ERR_PTR(retval);
+ kfree(value);
+
+ if (!IS_ERR(acl)) {
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ ext4_iset_acl(inode, &ei->i_acl, acl);
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ ext4_iset_acl(inode, &ei->i_default_acl, acl);
+ break;
+ }
+ }
+ return acl;
+}
+
+/*
+ * Set the access or default ACL of an inode.
+ *
+ * inode->i_mutex: down unless called from ext4_new_inode
+ */
+static int
+ext4_set_acl(handle_t *handle, struct inode *inode, int type,
+ struct posix_acl *acl)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ int name_index;
+ void *value = NULL;
+ size_t size = 0;
+ int error;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
+ if (acl) {
+ mode_t mode = inode->i_mode;
+ error = posix_acl_equiv_mode(acl, &mode);
+ if (error < 0)
+ return error;
+ else {
+ inode->i_mode = mode;
+ ext4_mark_inode_dirty(handle, inode);
+ if (error == 0)
+ acl = NULL;
+ }
+ }
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT;
+ if (!S_ISDIR(inode->i_mode))
+ return acl ? -EACCES : 0;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ if (acl) {
+ value = ext4_acl_to_disk(acl, &size);
+ if (IS_ERR(value))
+ return (int)PTR_ERR(value);
+ }
+
+ error = ext4_xattr_set_handle(handle, inode, name_index, "",
+ value, size, 0);
+
+ kfree(value);
+ if (!error) {
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ ext4_iset_acl(inode, &ei->i_acl, acl);
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ ext4_iset_acl(inode, &ei->i_default_acl, acl);
+ break;
+ }
+ }
+ return error;
+}
+
+static int
+ext4_check_acl(struct inode *inode, int mask)
+{
+ struct posix_acl *acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
+
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ int error = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return error;
+ }
+
+ return -EAGAIN;
+}
+
+int
+ext4_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ return generic_permission(inode, mask, ext4_check_acl);
+}
+
+/*
+ * Initialize the ACLs of a new inode. Called from ext4_new_inode.
+ *
+ * dir->i_mutex: down
+ * inode->i_mutex: up (access to inode is still exclusive)
+ */
+int
+ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ struct posix_acl *acl = NULL;
+ int error = 0;
+
+ if (!S_ISLNK(inode->i_mode)) {
+ if (test_opt(dir->i_sb, POSIX_ACL)) {
+ acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ }
+ if (!acl)
+ inode->i_mode &= ~current->fs->umask;
+ }
+ if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
+ struct posix_acl *clone;
+ mode_t mode;
+
+ if (S_ISDIR(inode->i_mode)) {
+ error = ext4_set_acl(handle, inode,
+ ACL_TYPE_DEFAULT, acl);
+ if (error)
+ goto cleanup;
+ }
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!clone)
+ goto cleanup;
+
+ mode = inode->i_mode;
+ error = posix_acl_create_masq(clone, &mode);
+ if (error >= 0) {
+ inode->i_mode = mode;
+ if (error > 0) {
+ /* This is an extended ACL */
+ error = ext4_set_acl(handle, inode,
+ ACL_TYPE_ACCESS, clone);
+ }
+ }
+ posix_acl_release(clone);
+ }
+cleanup:
+ posix_acl_release(acl);
+ return error;
+}
+
+/*
+ * Does chmod for an inode that may have an Access Control List. The
+ * inode->i_mode field must be updated to the desired value by the caller
+ * before calling this function.
+ * Returns 0 on success, or a negative error number.
+ *
+ * We change the ACL rather than storing some ACL entries in the file
+ * mode permission bits (which would be more efficient), because that
+ * would break once additional permissions (like ACL_APPEND, ACL_DELETE
+ * for directories) are added. There are no more bits available in the
+ * file mode.
+ *
+ * inode->i_mutex: down
+ */
+int
+ext4_acl_chmod(struct inode *inode)
+{
+ struct posix_acl *acl, *clone;
+ int error;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+ if (!test_opt(inode->i_sb, POSIX_ACL))
+ return 0;
+ acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl) || !acl)
+ return PTR_ERR(acl);
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ posix_acl_release(acl);
+ if (!clone)
+ return -ENOMEM;
+ error = posix_acl_chmod_masq(clone, inode->i_mode);
+ if (!error) {
+ handle_t *handle;
+ int retries = 0;
+
+ retry:
+ handle = ext4_journal_start(inode,
+ EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
+ if (IS_ERR(handle)) {
+ error = PTR_ERR(handle);
+ ext4_std_error(inode->i_sb, error);
+ goto out;
+ }
+ error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, clone);
+ ext4_journal_stop(handle);
+ if (error == -ENOSPC &&
+ ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+ }
+out:
+ posix_acl_release(clone);
+ return error;
+}
+
+/*
+ * Extended attribute handlers
+ */
+static size_t
+ext4_xattr_list_acl_access(struct inode *inode, char *list, size_t list_len,
+ const char *name, size_t name_len)
+{
+ const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
+
+ if (!test_opt(inode->i_sb, POSIX_ACL))
+ return 0;
+ if (list && size <= list_len)
+ memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
+ return size;
+}
+
+static size_t
+ext4_xattr_list_acl_default(struct inode *inode, char *list, size_t list_len,
+ const char *name, size_t name_len)
+{
+ const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
+
+ if (!test_opt(inode->i_sb, POSIX_ACL))
+ return 0;
+ if (list && size <= list_len)
+ memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
+ return size;
+}
+
+static int
+ext4_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
+{
+ struct posix_acl *acl;
+ int error;
+
+ if (!test_opt(inode->i_sb, POSIX_ACL))
+ return -EOPNOTSUPP;
+
+ acl = ext4_get_acl(inode, type);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl == NULL)
+ return -ENODATA;
+ error = posix_acl_to_xattr(acl, buffer, size);
+ posix_acl_release(acl);
+
+ return error;
+}
+
+static int
+ext4_xattr_get_acl_access(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return ext4_xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
+}
+
+static int
+ext4_xattr_get_acl_default(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return ext4_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
+}
+
+static int
+ext4_xattr_set_acl(struct inode *inode, int type, const void *value,
+ size_t size)
+{
+ handle_t *handle;
+ struct posix_acl *acl;
+ int error, retries = 0;
+
+ if (!test_opt(inode->i_sb, POSIX_ACL))
+ return -EOPNOTSUPP;
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EPERM;
+
+ if (value) {
+ acl = posix_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ else if (acl) {
+ error = posix_acl_valid(acl);
+ if (error)
+ goto release_and_out;
+ }
+ } else
+ acl = NULL;
+
+retry:
+ handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ error = ext4_set_acl(handle, inode, type, acl);
+ ext4_journal_stop(handle);
+ if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+
+release_and_out:
+ posix_acl_release(acl);
+ return error;
+}
+
+static int
+ext4_xattr_set_acl_access(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return ext4_xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
+}
+
+static int
+ext4_xattr_set_acl_default(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return ext4_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
+}
+
+struct xattr_handler ext4_xattr_acl_access_handler = {
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .list = ext4_xattr_list_acl_access,
+ .get = ext4_xattr_get_acl_access,
+ .set = ext4_xattr_set_acl_access,
+};
+
+struct xattr_handler ext4_xattr_acl_default_handler = {
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .list = ext4_xattr_list_acl_default,
+ .get = ext4_xattr_get_acl_default,
+ .set = ext4_xattr_set_acl_default,
+};
diff --git a/fs/ext4/acl.h b/fs/ext4/acl.h
new file mode 100644
index 000000000000..26a5c1abf147
--- /dev/null
+++ b/fs/ext4/acl.h
@@ -0,0 +1,81 @@
+/*
+ File: fs/ext4/acl.h
+
+ (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
+*/
+
+#include <linux/posix_acl_xattr.h>
+
+#define EXT4_ACL_VERSION 0x0001
+
+typedef struct {
+ __le16 e_tag;
+ __le16 e_perm;
+ __le32 e_id;
+} ext4_acl_entry;
+
+typedef struct {
+ __le16 e_tag;
+ __le16 e_perm;
+} ext4_acl_entry_short;
+
+typedef struct {
+ __le32 a_version;
+} ext4_acl_header;
+
+static inline size_t ext4_acl_size(int count)
+{
+ if (count <= 4) {
+ return sizeof(ext4_acl_header) +
+ count * sizeof(ext4_acl_entry_short);
+ } else {
+ return sizeof(ext4_acl_header) +
+ 4 * sizeof(ext4_acl_entry_short) +
+ (count - 4) * sizeof(ext4_acl_entry);
+ }
+}
+
+static inline int ext4_acl_count(size_t size)
+{
+ ssize_t s;
+ size -= sizeof(ext4_acl_header);
+ s = size - 4 * sizeof(ext4_acl_entry_short);
+ if (s < 0) {
+ if (size % sizeof(ext4_acl_entry_short))
+ return -1;
+ return size / sizeof(ext4_acl_entry_short);
+ } else {
+ if (s % sizeof(ext4_acl_entry))
+ return -1;
+ return s / sizeof(ext4_acl_entry) + 4;
+ }
+}
+
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+
+/* Value for inode->u.ext4_i.i_acl and inode->u.ext4_i.i_default_acl
+ if the ACL has not been cached */
+#define EXT4_ACL_NOT_CACHED ((void *)-1)
+
+/* acl.c */
+extern int ext4_permission (struct inode *, int, struct nameidata *);
+extern int ext4_acl_chmod (struct inode *);
+extern int ext4_init_acl (handle_t *, struct inode *, struct inode *);
+
+#else /* CONFIG_EXT4DEV_FS_POSIX_ACL */
+#include <linux/sched.h>
+#define ext4_permission NULL
+
+static inline int
+ext4_acl_chmod(struct inode *inode)
+{
+ return 0;
+}
+
+static inline int
+ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ return 0;
+}
+#endif /* CONFIG_EXT4DEV_FS_POSIX_ACL */
+
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
new file mode 100644
index 000000000000..5d45582f9517
--- /dev/null
+++ b/fs/ext4/balloc.c
@@ -0,0 +1,1833 @@
+/*
+ * linux/fs/ext4/balloc.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <linux/time.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/quotaops.h>
+#include <linux/buffer_head.h>
+
+/*
+ * balloc.c contains the blocks allocation and deallocation routines
+ */
+
+/*
+ * Calculate the block group number and offset, given a block number
+ */
+void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
+ unsigned long *blockgrpp, ext4_grpblk_t *offsetp)
+{
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+ ext4_grpblk_t offset;
+
+ blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
+ offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
+ if (offsetp)
+ *offsetp = offset;
+ if (blockgrpp)
+ *blockgrpp = blocknr;
+
+}
+
+/*
+ * The free blocks are managed by bitmaps. A file system contains several
+ * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
+ * block for inodes, N blocks for the inode table and data blocks.
+ *
+ * The file system contains group descriptors which are located after the
+ * super block. Each descriptor contains the number of the bitmap block and
+ * the free blocks count in the block. The descriptors are loaded in memory
+ * when a file system is mounted (see ext4_read_super).
+ */
+
+
+#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
+
+/**
+ * ext4_get_group_desc() -- load group descriptor from disk
+ * @sb: super block
+ * @block_group: given block group
+ * @bh: pointer to the buffer head to store the block
+ * group descriptor
+ */
+struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh)
+{
+ unsigned long group_desc;
+ unsigned long offset;
+ struct ext4_group_desc * desc;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (block_group >= sbi->s_groups_count) {
+ ext4_error (sb, "ext4_get_group_desc",
+ "block_group >= groups_count - "
+ "block_group = %d, groups_count = %lu",
+ block_group, sbi->s_groups_count);
+
+ return NULL;
+ }
+ smp_rmb();
+
+ group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
+ offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
+ if (!sbi->s_group_desc[group_desc]) {
+ ext4_error (sb, "ext4_get_group_desc",
+ "Group descriptor not loaded - "
+ "block_group = %d, group_desc = %lu, desc = %lu",
+ block_group, group_desc, offset);
+ return NULL;
+ }
+
+ desc = (struct ext4_group_desc *)(
+ (__u8 *)sbi->s_group_desc[group_desc]->b_data +
+ offset * EXT4_DESC_SIZE(sb));
+ if (bh)
+ *bh = sbi->s_group_desc[group_desc];
+ return desc;
+}
+
+/**
+ * read_block_bitmap()
+ * @sb: super block
+ * @block_group: given block group
+ *
+ * Read the bitmap for a given block_group, reading into the specified
+ * slot in the superblock's bitmap cache.
+ *
+ * Return buffer_head on success or NULL in case of failure.
+ */
+static struct buffer_head *
+read_block_bitmap(struct super_block *sb, unsigned int block_group)
+{
+ struct ext4_group_desc * desc;
+ struct buffer_head * bh = NULL;
+
+ desc = ext4_get_group_desc (sb, block_group, NULL);
+ if (!desc)
+ goto error_out;
+ bh = sb_bread(sb, ext4_block_bitmap(sb, desc));
+ if (!bh)
+ ext4_error (sb, "read_block_bitmap",
+ "Cannot read block bitmap - "
+ "block_group = %d, block_bitmap = %llu",
+ block_group,
+ ext4_block_bitmap(sb, desc));
+error_out:
+ return bh;
+}
+/*
+ * The reservation window structure operations
+ * --------------------------------------------
+ * Operations include:
+ * dump, find, add, remove, is_empty, find_next_reservable_window, etc.
+ *
+ * We use a red-black tree to represent per-filesystem reservation
+ * windows.
+ *
+ */
+
+/**
+ * __rsv_window_dump() -- Dump the filesystem block allocation reservation map
+ * @rb_root: root of per-filesystem reservation rb tree
+ * @verbose: verbose mode
+ * @fn: function which wishes to dump the reservation map
+ *
+ * If verbose is turned on, it will print the whole block reservation
+ * windows(start, end). Otherwise, it will only print out the "bad" windows,
+ * those windows that overlap with their immediate neighbors.
+ */
+#if 1
+static void __rsv_window_dump(struct rb_root *root, int verbose,
+ const char *fn)
+{
+ struct rb_node *n;
+ struct ext4_reserve_window_node *rsv, *prev;
+ int bad;
+
+restart:
+ n = rb_first(root);
+ bad = 0;
+ prev = NULL;
+
+ printk("Block Allocation Reservation Windows Map (%s):\n", fn);
+ while (n) {
+ rsv = list_entry(n, struct ext4_reserve_window_node, rsv_node);
+ if (verbose)
+ printk("reservation window 0x%p "
+ "start: %llu, end: %llu\n",
+ rsv, rsv->rsv_start, rsv->rsv_end);
+ if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) {
+ printk("Bad reservation %p (start >= end)\n",
+ rsv);
+ bad = 1;
+ }
+ if (prev && prev->rsv_end >= rsv->rsv_start) {
+ printk("Bad reservation %p (prev->end >= start)\n",
+ rsv);
+ bad = 1;
+ }
+ if (bad) {
+ if (!verbose) {
+ printk("Restarting reservation walk in verbose mode\n");
+ verbose = 1;
+ goto restart;
+ }
+ }
+ n = rb_next(n);
+ prev = rsv;
+ }
+ printk("Window map complete.\n");
+ if (bad)
+ BUG();
+}
+#define rsv_window_dump(root, verbose) \
+ __rsv_window_dump((root), (verbose), __FUNCTION__)
+#else
+#define rsv_window_dump(root, verbose) do {} while (0)
+#endif
+
+/**
+ * goal_in_my_reservation()
+ * @rsv: inode's reservation window
+ * @grp_goal: given goal block relative to the allocation block group
+ * @group: the current allocation block group
+ * @sb: filesystem super block
+ *
+ * Test if the given goal block (group relative) is within the file's
+ * own block reservation window range.
+ *
+ * If the reservation window is outside the goal allocation group, return 0;
+ * grp_goal (given goal block) could be -1, which means no specific
+ * goal block. In this case, always return 1.
+ * If the goal block is within the reservation window, return 1;
+ * otherwise, return 0;
+ */
+static int
+goal_in_my_reservation(struct ext4_reserve_window *rsv, ext4_grpblk_t grp_goal,
+ unsigned int group, struct super_block * sb)
+{
+ ext4_fsblk_t group_first_block, group_last_block;
+
+ group_first_block = ext4_group_first_block_no(sb, group);
+ group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
+
+ if ((rsv->_rsv_start > group_last_block) ||
+ (rsv->_rsv_end < group_first_block))
+ return 0;
+ if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start)
+ || (grp_goal + group_first_block > rsv->_rsv_end)))
+ return 0;
+ return 1;
+}
+
+/**
+ * search_reserve_window()
+ * @rb_root: root of reservation tree
+ * @goal: target allocation block
+ *
+ * Find the reserved window which includes the goal, or the previous one
+ * if the goal is not in any window.
+ * Returns NULL if there are no windows or if all windows start after the goal.
+ */
+static struct ext4_reserve_window_node *
+search_reserve_window(struct rb_root *root, ext4_fsblk_t goal)
+{
+ struct rb_node *n = root->rb_node;
+ struct ext4_reserve_window_node *rsv;
+
+ if (!n)
+ return NULL;
+
+ do {
+ rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
+
+ if (goal < rsv->rsv_start)
+ n = n->rb_left;
+ else if (goal > rsv->rsv_end)
+ n = n->rb_right;
+ else
+ return rsv;
+ } while (n);
+ /*
+ * We've fallen off the end of the tree: the goal wasn't inside
+ * any particular node. OK, the previous node must be to one
+ * side of the interval containing the goal. If it's the RHS,
+ * we need to back up one.
+ */
+ if (rsv->rsv_start > goal) {
+ n = rb_prev(&rsv->rsv_node);
+ rsv = rb_entry(n, struct ext4_reserve_window_node, rsv_node);
+ }
+ return rsv;
+}
+
+/**
+ * ext4_rsv_window_add() -- Insert a window to the block reservation rb tree.
+ * @sb: super block
+ * @rsv: reservation window to add
+ *
+ * Must be called with rsv_lock hold.
+ */
+void ext4_rsv_window_add(struct super_block *sb,
+ struct ext4_reserve_window_node *rsv)
+{
+ struct rb_root *root = &EXT4_SB(sb)->s_rsv_window_root;
+ struct rb_node *node = &rsv->rsv_node;
+ ext4_fsblk_t start = rsv->rsv_start;
+
+ struct rb_node ** p = &root->rb_node;
+ struct rb_node * parent = NULL;
+ struct ext4_reserve_window_node *this;
+
+ while (*p)
+ {
+ parent = *p;
+ this = rb_entry(parent, struct ext4_reserve_window_node, rsv_node);
+
+ if (start < this->rsv_start)
+ p = &(*p)->rb_left;
+ else if (start > this->rsv_end)
+ p = &(*p)->rb_right;
+ else {
+ rsv_window_dump(root, 1);
+ BUG();
+ }
+ }
+
+ rb_link_node(node, parent, p);
+ rb_insert_color(node, root);
+}
+
+/**
+ * ext4_rsv_window_remove() -- unlink a window from the reservation rb tree
+ * @sb: super block
+ * @rsv: reservation window to remove
+ *
+ * Mark the block reservation window as not allocated, and unlink it
+ * from the filesystem reservation window rb tree. Must be called with
+ * rsv_lock hold.
+ */
+static void rsv_window_remove(struct super_block *sb,
+ struct ext4_reserve_window_node *rsv)
+{
+ rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
+ rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
+ rsv->rsv_alloc_hit = 0;
+ rb_erase(&rsv->rsv_node, &EXT4_SB(sb)->s_rsv_window_root);
+}
+
+/*
+ * rsv_is_empty() -- Check if the reservation window is allocated.
+ * @rsv: given reservation window to check
+ *
+ * returns 1 if the end block is EXT4_RESERVE_WINDOW_NOT_ALLOCATED.
+ */
+static inline int rsv_is_empty(struct ext4_reserve_window *rsv)
+{
+ /* a valid reservation end block could not be 0 */
+ return rsv->_rsv_end == EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
+}
+
+/**
+ * ext4_init_block_alloc_info()
+ * @inode: file inode structure
+ *
+ * Allocate and initialize the reservation window structure, and
+ * link the window to the ext4 inode structure at last
+ *
+ * The reservation window structure is only dynamically allocated
+ * and linked to ext4 inode the first time the open file
+ * needs a new block. So, before every ext4_new_block(s) call, for
+ * regular files, we should check whether the reservation window
+ * structure exists or not. In the latter case, this function is called.
+ * Fail to do so will result in block reservation being turned off for that
+ * open file.
+ *
+ * This function is called from ext4_get_blocks_handle(), also called
+ * when setting the reservation window size through ioctl before the file
+ * is open for write (needs block allocation).
+ *
+ * Needs truncate_mutex protection prior to call this function.
+ */
+void ext4_init_block_alloc_info(struct inode *inode)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
+ struct super_block *sb = inode->i_sb;
+
+ block_i = kmalloc(sizeof(*block_i), GFP_NOFS);
+ if (block_i) {
+ struct ext4_reserve_window_node *rsv = &block_i->rsv_window_node;
+
+ rsv->rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
+ rsv->rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
+
+ /*
+ * if filesystem is mounted with NORESERVATION, the goal
+ * reservation window size is set to zero to indicate
+ * block reservation is off
+ */
+ if (!test_opt(sb, RESERVATION))
+ rsv->rsv_goal_size = 0;
+ else
+ rsv->rsv_goal_size = EXT4_DEFAULT_RESERVE_BLOCKS;
+ rsv->rsv_alloc_hit = 0;
+ block_i->last_alloc_logical_block = 0;
+ block_i->last_alloc_physical_block = 0;
+ }
+ ei->i_block_alloc_info = block_i;
+}
+
+/**
+ * ext4_discard_reservation()
+ * @inode: inode
+ *
+ * Discard(free) block reservation window on last file close, or truncate
+ * or at last iput().
+ *
+ * It is being called in three cases:
+ * ext4_release_file(): last writer close the file
+ * ext4_clear_inode(): last iput(), when nobody link to this file.
+ * ext4_truncate(): when the block indirect map is about to change.
+ *
+ */
+void ext4_discard_reservation(struct inode *inode)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct ext4_block_alloc_info *block_i = ei->i_block_alloc_info;
+ struct ext4_reserve_window_node *rsv;
+ spinlock_t *rsv_lock = &EXT4_SB(inode->i_sb)->s_rsv_window_lock;
+
+ if (!block_i)
+ return;
+
+ rsv = &block_i->rsv_window_node;
+ if (!rsv_is_empty(&rsv->rsv_window)) {
+ spin_lock(rsv_lock);
+ if (!rsv_is_empty(&rsv->rsv_window))
+ rsv_window_remove(inode->i_sb, rsv);
+ spin_unlock(rsv_lock);
+ }
+}
+
+/**
+ * ext4_free_blocks_sb() -- Free given blocks and update quota
+ * @handle: handle to this transaction
+ * @sb: super block
+ * @block: start physcial block to free
+ * @count: number of blocks to free
+ * @pdquot_freed_blocks: pointer to quota
+ */
+void ext4_free_blocks_sb(handle_t *handle, struct super_block *sb,
+ ext4_fsblk_t block, unsigned long count,
+ unsigned long *pdquot_freed_blocks)
+{
+ struct buffer_head *bitmap_bh = NULL;
+ struct buffer_head *gd_bh;
+ unsigned long block_group;
+ ext4_grpblk_t bit;
+ unsigned long i;
+ unsigned long overflow;
+ struct ext4_group_desc * desc;
+ struct ext4_super_block * es;
+ struct ext4_sb_info *sbi;
+ int err = 0, ret;
+ ext4_grpblk_t group_freed;
+
+ *pdquot_freed_blocks = 0;
+ sbi = EXT4_SB(sb);
+ es = sbi->s_es;
+ if (block < le32_to_cpu(es->s_first_data_block) ||
+ block + count < block ||
+ block + count > ext4_blocks_count(es)) {
+ ext4_error (sb, "ext4_free_blocks",
+ "Freeing blocks not in datazone - "
+ "block = %llu, count = %lu", block, count);
+ goto error_return;
+ }
+
+ ext4_debug ("freeing block(s) %llu-%llu\n", block, block + count - 1);
+
+do_more:
+ overflow = 0;
+ ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
+ /*
+ * Check to see if we are freeing blocks across a group
+ * boundary.
+ */
+ if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) {
+ overflow = bit + count - EXT4_BLOCKS_PER_GROUP(sb);
+ count -= overflow;
+ }
+ brelse(bitmap_bh);
+ bitmap_bh = read_block_bitmap(sb, block_group);
+ if (!bitmap_bh)
+ goto error_return;
+ desc = ext4_get_group_desc (sb, block_group, &gd_bh);
+ if (!desc)
+ goto error_return;
+
+ if (in_range(ext4_block_bitmap(sb, desc), block, count) ||
+ in_range(ext4_inode_bitmap(sb, desc), block, count) ||
+ in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) ||
+ in_range(block + count - 1, ext4_inode_table(sb, desc),
+ sbi->s_itb_per_group))
+ ext4_error (sb, "ext4_free_blocks",
+ "Freeing blocks in system zones - "
+ "Block = %llu, count = %lu",
+ block, count);
+
+ /*
+ * We are about to start releasing blocks in the bitmap,
+ * so we need undo access.
+ */
+ /* @@@ check errors */
+ BUFFER_TRACE(bitmap_bh, "getting undo access");
+ err = ext4_journal_get_undo_access(handle, bitmap_bh);
+ if (err)
+ goto error_return;
+
+ /*
+ * We are about to modify some metadata. Call the journal APIs
+ * to unshare ->b_data if a currently-committing transaction is
+ * using it
+ */
+ BUFFER_TRACE(gd_bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, gd_bh);
+ if (err)
+ goto error_return;
+
+ jbd_lock_bh_state(bitmap_bh);
+
+ for (i = 0, group_freed = 0; i < count; i++) {
+ /*
+ * An HJ special. This is expensive...
+ */
+#ifdef CONFIG_JBD_DEBUG
+ jbd_unlock_bh_state(bitmap_bh);
+ {
+ struct buffer_head *debug_bh;
+ debug_bh = sb_find_get_block(sb, block + i);
+ if (debug_bh) {
+ BUFFER_TRACE(debug_bh, "Deleted!");
+ if (!bh2jh(bitmap_bh)->b_committed_data)
+ BUFFER_TRACE(debug_bh,
+ "No commited data in bitmap");
+ BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap");
+ __brelse(debug_bh);
+ }
+ }
+ jbd_lock_bh_state(bitmap_bh);
+#endif
+ if (need_resched()) {
+ jbd_unlock_bh_state(bitmap_bh);
+ cond_resched();
+ jbd_lock_bh_state(bitmap_bh);
+ }
+ /* @@@ This prevents newly-allocated data from being
+ * freed and then reallocated within the same
+ * transaction.
+ *
+ * Ideally we would want to allow that to happen, but to
+ * do so requires making jbd2_journal_forget() capable of
+ * revoking the queued write of a data block, which
+ * implies blocking on the journal lock. *forget()
+ * cannot block due to truncate races.
+ *
+ * Eventually we can fix this by making jbd2_journal_forget()
+ * return a status indicating whether or not it was able
+ * to revoke the buffer. On successful revoke, it is
+ * safe not to set the allocation bit in the committed
+ * bitmap, because we know that there is no outstanding
+ * activity on the buffer any more and so it is safe to
+ * reallocate it.
+ */
+ BUFFER_TRACE(bitmap_bh, "set in b_committed_data");
+ J_ASSERT_BH(bitmap_bh,
+ bh2jh(bitmap_bh)->b_committed_data != NULL);
+ ext4_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i,
+ bh2jh(bitmap_bh)->b_committed_data);
+
+ /*
+ * We clear the bit in the bitmap after setting the committed
+ * data bit, because this is the reverse order to that which
+ * the allocator uses.
+ */
+ BUFFER_TRACE(bitmap_bh, "clear bit");
+ if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
+ bit + i, bitmap_bh->b_data)) {
+ jbd_unlock_bh_state(bitmap_bh);
+ ext4_error(sb, __FUNCTION__,
+ "bit already cleared for block %llu",
+ (ext4_fsblk_t)(block + i));
+ jbd_lock_bh_state(bitmap_bh);
+ BUFFER_TRACE(bitmap_bh, "bit already cleared");
+ } else {
+ group_freed++;
+ }
+ }
+ jbd_unlock_bh_state(bitmap_bh);
+
+ spin_lock(sb_bgl_lock(sbi, block_group));
+ desc->bg_free_blocks_count =
+ cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) +
+ group_freed);
+ spin_unlock(sb_bgl_lock(sbi, block_group));
+ percpu_counter_mod(&sbi->s_freeblocks_counter, count);
+
+ /* We dirtied the bitmap block */
+ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
+ err = ext4_journal_dirty_metadata(handle, bitmap_bh);
+
+ /* And the group descriptor block */
+ BUFFER_TRACE(gd_bh, "dirtied group descriptor block");
+ ret = ext4_journal_dirty_metadata(handle, gd_bh);
+ if (!err) err = ret;
+ *pdquot_freed_blocks += group_freed;
+
+ if (overflow && !err) {
+ block += count;
+ count = overflow;
+ goto do_more;
+ }
+ sb->s_dirt = 1;
+error_return:
+ brelse(bitmap_bh);
+ ext4_std_error(sb, err);
+ return;
+}
+
+/**
+ * ext4_free_blocks() -- Free given blocks and update quota
+ * @handle: handle for this transaction
+ * @inode: inode
+ * @block: start physical block to free
+ * @count: number of blocks to count
+ */
+void ext4_free_blocks(handle_t *handle, struct inode *inode,
+ ext4_fsblk_t block, unsigned long count)
+{
+ struct super_block * sb;
+ unsigned long dquot_freed_blocks;
+
+ sb = inode->i_sb;
+ if (!sb) {
+ printk ("ext4_free_blocks: nonexistent device");
+ return;
+ }
+ ext4_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks);
+ if (dquot_freed_blocks)
+ DQUOT_FREE_BLOCK(inode, dquot_freed_blocks);
+ return;
+}
+
+/**
+ * ext4_test_allocatable()
+ * @nr: given allocation block group
+ * @bh: bufferhead contains the bitmap of the given block group
+ *
+ * For ext4 allocations, we must not reuse any blocks which are
+ * allocated in the bitmap buffer's "last committed data" copy. This
+ * prevents deletes from freeing up the page for reuse until we have
+ * committed the delete transaction.
+ *
+ * If we didn't do this, then deleting something and reallocating it as
+ * data would allow the old block to be overwritten before the
+ * transaction committed (because we force data to disk before commit).
+ * This would lead to corruption if we crashed between overwriting the
+ * data and committing the delete.
+ *
+ * @@@ We may want to make this allocation behaviour conditional on
+ * data-writes at some point, and disable it for metadata allocations or
+ * sync-data inodes.
+ */
+static int ext4_test_allocatable(ext4_grpblk_t nr, struct buffer_head *bh)
+{
+ int ret;
+ struct journal_head *jh = bh2jh(bh);
+
+ if (ext4_test_bit(nr, bh->b_data))
+ return 0;
+
+ jbd_lock_bh_state(bh);
+ if (!jh->b_committed_data)
+ ret = 1;
+ else
+ ret = !ext4_test_bit(nr, jh->b_committed_data);
+ jbd_unlock_bh_state(bh);
+ return ret;
+}
+
+/**
+ * bitmap_search_next_usable_block()
+ * @start: the starting block (group relative) of the search
+ * @bh: bufferhead contains the block group bitmap
+ * @maxblocks: the ending block (group relative) of the reservation
+ *
+ * The bitmap search --- search forward alternately through the actual
+ * bitmap on disk and the last-committed copy in journal, until we find a
+ * bit free in both bitmaps.
+ */
+static ext4_grpblk_t
+bitmap_search_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
+ ext4_grpblk_t maxblocks)
+{
+ ext4_grpblk_t next;
+ struct journal_head *jh = bh2jh(bh);
+
+ while (start < maxblocks) {
+ next = ext4_find_next_zero_bit(bh->b_data, maxblocks, start);
+ if (next >= maxblocks)
+ return -1;
+ if (ext4_test_allocatable(next, bh))
+ return next;
+ jbd_lock_bh_state(bh);
+ if (jh->b_committed_data)
+ start = ext4_find_next_zero_bit(jh->b_committed_data,
+ maxblocks, next);
+ jbd_unlock_bh_state(bh);
+ }
+ return -1;
+}
+
+/**
+ * find_next_usable_block()
+ * @start: the starting block (group relative) to find next
+ * allocatable block in bitmap.
+ * @bh: bufferhead contains the block group bitmap
+ * @maxblocks: the ending block (group relative) for the search
+ *
+ * Find an allocatable block in a bitmap. We honor both the bitmap and
+ * its last-committed copy (if that exists), and perform the "most
+ * appropriate allocation" algorithm of looking for a free block near
+ * the initial goal; then for a free byte somewhere in the bitmap; then
+ * for any free bit in the bitmap.
+ */
+static ext4_grpblk_t
+find_next_usable_block(ext4_grpblk_t start, struct buffer_head *bh,
+ ext4_grpblk_t maxblocks)
+{
+ ext4_grpblk_t here, next;
+ char *p, *r;
+
+ if (start > 0) {
+ /*
+ * The goal was occupied; search forward for a free
+ * block within the next XX blocks.
+ *
+ * end_goal is more or less random, but it has to be
+ * less than EXT4_BLOCKS_PER_GROUP. Aligning up to the
+ * next 64-bit boundary is simple..
+ */
+ ext4_grpblk_t end_goal = (start + 63) & ~63;
+ if (end_goal > maxblocks)
+ end_goal = maxblocks;
+ here = ext4_find_next_zero_bit(bh->b_data, end_goal, start);
+ if (here < end_goal && ext4_test_allocatable(here, bh))
+ return here;
+ ext4_debug("Bit not found near goal\n");
+ }
+
+ here = start;
+ if (here < 0)
+ here = 0;
+
+ p = ((char *)bh->b_data) + (here >> 3);
+ r = memscan(p, 0, (maxblocks - here + 7) >> 3);
+ next = (r - ((char *)bh->b_data)) << 3;
+
+ if (next < maxblocks && next >= start && ext4_test_allocatable(next, bh))
+ return next;
+
+ /*
+ * The bitmap search --- search forward alternately through the actual
+ * bitmap and the last-committed copy until we find a bit free in
+ * both
+ */
+ here = bitmap_search_next_usable_block(here, bh, maxblocks);
+ return here;
+}
+
+/**
+ * claim_block()
+ * @block: the free block (group relative) to allocate
+ * @bh: the bufferhead containts the block group bitmap
+ *
+ * We think we can allocate this block in this bitmap. Try to set the bit.
+ * If that succeeds then check that nobody has allocated and then freed the
+ * block since we saw that is was not marked in b_committed_data. If it _was_
+ * allocated and freed then clear the bit in the bitmap again and return
+ * zero (failure).
+ */
+static inline int
+claim_block(spinlock_t *lock, ext4_grpblk_t block, struct buffer_head *bh)
+{
+ struct journal_head *jh = bh2jh(bh);
+ int ret;
+
+ if (ext4_set_bit_atomic(lock, block, bh->b_data))
+ return 0;
+ jbd_lock_bh_state(bh);
+ if (jh->b_committed_data && ext4_test_bit(block,jh->b_committed_data)) {
+ ext4_clear_bit_atomic(lock, block, bh->b_data);
+ ret = 0;
+ } else {
+ ret = 1;
+ }
+ jbd_unlock_bh_state(bh);
+ return ret;
+}
+
+/**
+ * ext4_try_to_allocate()
+ * @sb: superblock
+ * @handle: handle to this transaction
+ * @group: given allocation block group
+ * @bitmap_bh: bufferhead holds the block bitmap
+ * @grp_goal: given target block within the group
+ * @count: target number of blocks to allocate
+ * @my_rsv: reservation window
+ *
+ * Attempt to allocate blocks within a give range. Set the range of allocation
+ * first, then find the first free bit(s) from the bitmap (within the range),
+ * and at last, allocate the blocks by claiming the found free bit as allocated.
+ *
+ * To set the range of this allocation:
+ * if there is a reservation window, only try to allocate block(s) from the
+ * file's own reservation window;
+ * Otherwise, the allocation range starts from the give goal block, ends at
+ * the block group's last block.
+ *
+ * If we failed to allocate the desired block then we may end up crossing to a
+ * new bitmap. In that case we must release write access to the old one via
+ * ext4_journal_release_buffer(), else we'll run out of credits.
+ */
+static ext4_grpblk_t
+ext4_try_to_allocate(struct super_block *sb, handle_t *handle, int group,
+ struct buffer_head *bitmap_bh, ext4_grpblk_t grp_goal,
+ unsigned long *count, struct ext4_reserve_window *my_rsv)
+{
+ ext4_fsblk_t group_first_block;
+ ext4_grpblk_t start, end;
+ unsigned long num = 0;
+
+ /* we do allocation within the reservation window if we have a window */
+ if (my_rsv) {
+ group_first_block = ext4_group_first_block_no(sb, group);
+ if (my_rsv->_rsv_start >= group_first_block)
+ start = my_rsv->_rsv_start - group_first_block;
+ else
+ /* reservation window cross group boundary */
+ start = 0;
+ end = my_rsv->_rsv_end - group_first_block + 1;
+ if (end > EXT4_BLOCKS_PER_GROUP(sb))
+ /* reservation window crosses group boundary */
+ end = EXT4_BLOCKS_PER_GROUP(sb);
+ if ((start <= grp_goal) && (grp_goal < end))
+ start = grp_goal;
+ else
+ grp_goal = -1;
+ } else {
+ if (grp_goal > 0)
+ start = grp_goal;
+ else
+ start = 0;
+ end = EXT4_BLOCKS_PER_GROUP(sb);
+ }
+
+ BUG_ON(start > EXT4_BLOCKS_PER_GROUP(sb));
+
+repeat:
+ if (grp_goal < 0 || !ext4_test_allocatable(grp_goal, bitmap_bh)) {
+ grp_goal = find_next_usable_block(start, bitmap_bh, end);
+ if (grp_goal < 0)
+ goto fail_access;
+ if (!my_rsv) {
+ int i;
+
+ for (i = 0; i < 7 && grp_goal > start &&
+ ext4_test_allocatable(grp_goal - 1,
+ bitmap_bh);
+ i++, grp_goal--)
+ ;
+ }
+ }
+ start = grp_goal;
+
+ if (!claim_block(sb_bgl_lock(EXT4_SB(sb), group),
+ grp_goal, bitmap_bh)) {
+ /*
+ * The block was allocated by another thread, or it was
+ * allocated and then freed by another thread
+ */
+ start++;
+ grp_goal++;
+ if (start >= end)
+ goto fail_access;
+ goto repeat;
+ }
+ num++;
+ grp_goal++;
+ while (num < *count && grp_goal < end
+ && ext4_test_allocatable(grp_goal, bitmap_bh)
+ && claim_block(sb_bgl_lock(EXT4_SB(sb), group),
+ grp_goal, bitmap_bh)) {
+ num++;
+ grp_goal++;
+ }
+ *count = num;
+ return grp_goal - num;
+fail_access:
+ *count = num;
+ return -1;
+}
+
+/**
+ * find_next_reservable_window():
+ * find a reservable space within the given range.
+ * It does not allocate the reservation window for now:
+ * alloc_new_reservation() will do the work later.
+ *
+ * @search_head: the head of the searching list;
+ * This is not necessarily the list head of the whole filesystem
+ *
+ * We have both head and start_block to assist the search
+ * for the reservable space. The list starts from head,
+ * but we will shift to the place where start_block is,
+ * then start from there, when looking for a reservable space.
+ *
+ * @size: the target new reservation window size
+ *
+ * @group_first_block: the first block we consider to start
+ * the real search from
+ *
+ * @last_block:
+ * the maximum block number that our goal reservable space
+ * could start from. This is normally the last block in this
+ * group. The search will end when we found the start of next
+ * possible reservable space is out of this boundary.
+ * This could handle the cross boundary reservation window
+ * request.
+ *
+ * basically we search from the given range, rather than the whole
+ * reservation double linked list, (start_block, last_block)
+ * to find a free region that is of my size and has not
+ * been reserved.
+ *
+ */
+static int find_next_reservable_window(
+ struct ext4_reserve_window_node *search_head,
+ struct ext4_reserve_window_node *my_rsv,
+ struct super_block * sb,
+ ext4_fsblk_t start_block,
+ ext4_fsblk_t last_block)
+{
+ struct rb_node *next;
+ struct ext4_reserve_window_node *rsv, *prev;
+ ext4_fsblk_t cur;
+ int size = my_rsv->rsv_goal_size;
+
+ /* TODO: make the start of the reservation window byte-aligned */
+ /* cur = *start_block & ~7;*/
+ cur = start_block;
+ rsv = search_head;
+ if (!rsv)
+ return -1;
+
+ while (1) {
+ if (cur <= rsv->rsv_end)
+ cur = rsv->rsv_end + 1;
+
+ /* TODO?
+ * in the case we could not find a reservable space
+ * that is what is expected, during the re-search, we could
+ * remember what's the largest reservable space we could have
+ * and return that one.
+ *
+ * For now it will fail if we could not find the reservable
+ * space with expected-size (or more)...
+ */
+ if (cur > last_block)
+ return -1; /* fail */
+
+ prev = rsv;
+ next = rb_next(&rsv->rsv_node);
+ rsv = list_entry(next,struct ext4_reserve_window_node,rsv_node);
+
+ /*
+ * Reached the last reservation, we can just append to the
+ * previous one.
+ */
+ if (!next)
+ break;
+
+ if (cur + size <= rsv->rsv_start) {
+ /*
+ * Found a reserveable space big enough. We could
+ * have a reservation across the group boundary here
+ */
+ break;
+ }
+ }
+ /*
+ * we come here either :
+ * when we reach the end of the whole list,
+ * and there is empty reservable space after last entry in the list.
+ * append it to the end of the list.
+ *
+ * or we found one reservable space in the middle of the list,
+ * return the reservation window that we could append to.
+ * succeed.
+ */
+
+ if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window)))
+ rsv_window_remove(sb, my_rsv);
+
+ /*
+ * Let's book the whole avaliable window for now. We will check the
+ * disk bitmap later and then, if there are free blocks then we adjust
+ * the window size if it's larger than requested.
+ * Otherwise, we will remove this node from the tree next time
+ * call find_next_reservable_window.
+ */
+ my_rsv->rsv_start = cur;
+ my_rsv->rsv_end = cur + size - 1;
+ my_rsv->rsv_alloc_hit = 0;
+
+ if (prev != my_rsv)
+ ext4_rsv_window_add(sb, my_rsv);
+
+ return 0;
+}
+
+/**
+ * alloc_new_reservation()--allocate a new reservation window
+ *
+ * To make a new reservation, we search part of the filesystem
+ * reservation list (the list that inside the group). We try to
+ * allocate a new reservation window near the allocation goal,
+ * or the beginning of the group, if there is no goal.
+ *
+ * We first find a reservable space after the goal, then from
+ * there, we check the bitmap for the first free block after
+ * it. If there is no free block until the end of group, then the
+ * whole group is full, we failed. Otherwise, check if the free
+ * block is inside the expected reservable space, if so, we
+ * succeed.
+ * If the first free block is outside the reservable space, then
+ * start from the first free block, we search for next available
+ * space, and go on.
+ *
+ * on succeed, a new reservation will be found and inserted into the list
+ * It contains at least one free block, and it does not overlap with other
+ * reservation windows.
+ *
+ * failed: we failed to find a reservation window in this group
+ *
+ * @rsv: the reservation
+ *
+ * @grp_goal: The goal (group-relative). It is where the search for a
+ * free reservable space should start from.
+ * if we have a grp_goal(grp_goal >0 ), then start from there,
+ * no grp_goal(grp_goal = -1), we start from the first block
+ * of the group.
+ *
+ * @sb: the super block
+ * @group: the group we are trying to allocate in
+ * @bitmap_bh: the block group block bitmap
+ *
+ */
+static int alloc_new_reservation(struct ext4_reserve_window_node *my_rsv,
+ ext4_grpblk_t grp_goal, struct super_block *sb,
+ unsigned int group, struct buffer_head *bitmap_bh)
+{
+ struct ext4_reserve_window_node *search_head;
+ ext4_fsblk_t group_first_block, group_end_block, start_block;
+ ext4_grpblk_t first_free_block;
+ struct rb_root *fs_rsv_root = &EXT4_SB(sb)->s_rsv_window_root;
+ unsigned long size;
+ int ret;
+ spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
+
+ group_first_block = ext4_group_first_block_no(sb, group);
+ group_end_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
+
+ if (grp_goal < 0)
+ start_block = group_first_block;
+ else
+ start_block = grp_goal + group_first_block;
+
+ size = my_rsv->rsv_goal_size;
+
+ if (!rsv_is_empty(&my_rsv->rsv_window)) {
+ /*
+ * if the old reservation is cross group boundary
+ * and if the goal is inside the old reservation window,
+ * we will come here when we just failed to allocate from
+ * the first part of the window. We still have another part
+ * that belongs to the next group. In this case, there is no
+ * point to discard our window and try to allocate a new one
+ * in this group(which will fail). we should
+ * keep the reservation window, just simply move on.
+ *
+ * Maybe we could shift the start block of the reservation
+ * window to the first block of next group.
+ */
+
+ if ((my_rsv->rsv_start <= group_end_block) &&
+ (my_rsv->rsv_end > group_end_block) &&
+ (start_block >= my_rsv->rsv_start))
+ return -1;
+
+ if ((my_rsv->rsv_alloc_hit >
+ (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) {
+ /*
+ * if the previously allocation hit ratio is
+ * greater than 1/2, then we double the size of
+ * the reservation window the next time,
+ * otherwise we keep the same size window
+ */
+ size = size * 2;
+ if (size > EXT4_MAX_RESERVE_BLOCKS)
+ size = EXT4_MAX_RESERVE_BLOCKS;
+ my_rsv->rsv_goal_size= size;
+ }
+ }
+
+ spin_lock(rsv_lock);
+ /*
+ * shift the search start to the window near the goal block
+ */
+ search_head = search_reserve_window(fs_rsv_root, start_block);
+
+ /*
+ * find_next_reservable_window() simply finds a reservable window
+ * inside the given range(start_block, group_end_block).
+ *
+ * To make sure the reservation window has a free bit inside it, we
+ * need to check the bitmap after we found a reservable window.
+ */
+retry:
+ ret = find_next_reservable_window(search_head, my_rsv, sb,
+ start_block, group_end_block);
+
+ if (ret == -1) {
+ if (!rsv_is_empty(&my_rsv->rsv_window))
+ rsv_window_remove(sb, my_rsv);
+ spin_unlock(rsv_lock);
+ return -1;
+ }
+
+ /*
+ * On success, find_next_reservable_window() returns the
+ * reservation window where there is a reservable space after it.
+ * Before we reserve this reservable space, we need
+ * to make sure there is at least a free block inside this region.
+ *
+ * searching the first free bit on the block bitmap and copy of
+ * last committed bitmap alternatively, until we found a allocatable
+ * block. Search start from the start block of the reservable space
+ * we just found.
+ */
+ spin_unlock(rsv_lock);
+ first_free_block = bitmap_search_next_usable_block(
+ my_rsv->rsv_start - group_first_block,
+ bitmap_bh, group_end_block - group_first_block + 1);
+
+ if (first_free_block < 0) {
+ /*
+ * no free block left on the bitmap, no point
+ * to reserve the space. return failed.
+ */
+ spin_lock(rsv_lock);
+ if (!rsv_is_empty(&my_rsv->rsv_window))
+ rsv_window_remove(sb, my_rsv);
+ spin_unlock(rsv_lock);
+ return -1; /* failed */
+ }
+
+ start_block = first_free_block + group_first_block;
+ /*
+ * check if the first free block is within the
+ * free space we just reserved
+ */
+ if (start_block >= my_rsv->rsv_start && start_block < my_rsv->rsv_end)
+ return 0; /* success */
+ /*
+ * if the first free bit we found is out of the reservable space
+ * continue search for next reservable space,
+ * start from where the free block is,
+ * we also shift the list head to where we stopped last time
+ */
+ search_head = my_rsv;
+ spin_lock(rsv_lock);
+ goto retry;
+}
+
+/**
+ * try_to_extend_reservation()
+ * @my_rsv: given reservation window
+ * @sb: super block
+ * @size: the delta to extend
+ *
+ * Attempt to expand the reservation window large enough to have
+ * required number of free blocks
+ *
+ * Since ext4_try_to_allocate() will always allocate blocks within
+ * the reservation window range, if the window size is too small,
+ * multiple blocks allocation has to stop at the end of the reservation
+ * window. To make this more efficient, given the total number of
+ * blocks needed and the current size of the window, we try to
+ * expand the reservation window size if necessary on a best-effort
+ * basis before ext4_new_blocks() tries to allocate blocks,
+ */
+static void try_to_extend_reservation(struct ext4_reserve_window_node *my_rsv,
+ struct super_block *sb, int size)
+{
+ struct ext4_reserve_window_node *next_rsv;
+ struct rb_node *next;
+ spinlock_t *rsv_lock = &EXT4_SB(sb)->s_rsv_window_lock;
+
+ if (!spin_trylock(rsv_lock))
+ return;
+
+ next = rb_next(&my_rsv->rsv_node);
+
+ if (!next)
+ my_rsv->rsv_end += size;
+ else {
+ next_rsv = list_entry(next, struct ext4_reserve_window_node, rsv_node);
+
+ if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size)
+ my_rsv->rsv_end += size;
+ else
+ my_rsv->rsv_end = next_rsv->rsv_start - 1;
+ }
+ spin_unlock(rsv_lock);
+}
+
+/**
+ * ext4_try_to_allocate_with_rsv()
+ * @sb: superblock
+ * @handle: handle to this transaction
+ * @group: given allocation block group
+ * @bitmap_bh: bufferhead holds the block bitmap
+ * @grp_goal: given target block within the group
+ * @count: target number of blocks to allocate
+ * @my_rsv: reservation window
+ * @errp: pointer to store the error code
+ *
+ * This is the main function used to allocate a new block and its reservation
+ * window.
+ *
+ * Each time when a new block allocation is need, first try to allocate from
+ * its own reservation. If it does not have a reservation window, instead of
+ * looking for a free bit on bitmap first, then look up the reservation list to
+ * see if it is inside somebody else's reservation window, we try to allocate a
+ * reservation window for it starting from the goal first. Then do the block
+ * allocation within the reservation window.
+ *
+ * This will avoid keeping on searching the reservation list again and
+ * again when somebody is looking for a free block (without
+ * reservation), and there are lots of free blocks, but they are all
+ * being reserved.
+ *
+ * We use a red-black tree for the per-filesystem reservation list.
+ *
+ */
+static ext4_grpblk_t
+ext4_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
+ unsigned int group, struct buffer_head *bitmap_bh,
+ ext4_grpblk_t grp_goal,
+ struct ext4_reserve_window_node * my_rsv,
+ unsigned long *count, int *errp)
+{
+ ext4_fsblk_t group_first_block, group_last_block;
+ ext4_grpblk_t ret = 0;
+ int fatal;
+ unsigned long num = *count;
+
+ *errp = 0;
+
+ /*
+ * Make sure we use undo access for the bitmap, because it is critical
+ * that we do the frozen_data COW on bitmap buffers in all cases even
+ * if the buffer is in BJ_Forget state in the committing transaction.
+ */
+ BUFFER_TRACE(bitmap_bh, "get undo access for new block");
+ fatal = ext4_journal_get_undo_access(handle, bitmap_bh);
+ if (fatal) {
+ *errp = fatal;
+ return -1;
+ }
+
+ /*
+ * we don't deal with reservation when
+ * filesystem is mounted without reservation
+ * or the file is not a regular file
+ * or last attempt to allocate a block with reservation turned on failed
+ */
+ if (my_rsv == NULL ) {
+ ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
+ grp_goal, count, NULL);
+ goto out;
+ }
+ /*
+ * grp_goal is a group relative block number (if there is a goal)
+ * 0 < grp_goal < EXT4_BLOCKS_PER_GROUP(sb)
+ * first block is a filesystem wide block number
+ * first block is the block number of the first block in this group
+ */
+ group_first_block = ext4_group_first_block_no(sb, group);
+ group_last_block = group_first_block + (EXT4_BLOCKS_PER_GROUP(sb) - 1);
+
+ /*
+ * Basically we will allocate a new block from inode's reservation
+ * window.
+ *
+ * We need to allocate a new reservation window, if:
+ * a) inode does not have a reservation window; or
+ * b) last attempt to allocate a block from existing reservation
+ * failed; or
+ * c) we come here with a goal and with a reservation window
+ *
+ * We do not need to allocate a new reservation window if we come here
+ * at the beginning with a goal and the goal is inside the window, or
+ * we don't have a goal but already have a reservation window.
+ * then we could go to allocate from the reservation window directly.
+ */
+ while (1) {
+ if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
+ !goal_in_my_reservation(&my_rsv->rsv_window,
+ grp_goal, group, sb)) {
+ if (my_rsv->rsv_goal_size < *count)
+ my_rsv->rsv_goal_size = *count;
+ ret = alloc_new_reservation(my_rsv, grp_goal, sb,
+ group, bitmap_bh);
+ if (ret < 0)
+ break; /* failed */
+
+ if (!goal_in_my_reservation(&my_rsv->rsv_window,
+ grp_goal, group, sb))
+ grp_goal = -1;
+ } else if (grp_goal > 0 &&
+ (my_rsv->rsv_end-grp_goal+1) < *count)
+ try_to_extend_reservation(my_rsv, sb,
+ *count-my_rsv->rsv_end + grp_goal - 1);
+
+ if ((my_rsv->rsv_start > group_last_block) ||
+ (my_rsv->rsv_end < group_first_block)) {
+ rsv_window_dump(&EXT4_SB(sb)->s_rsv_window_root, 1);
+ BUG();
+ }
+ ret = ext4_try_to_allocate(sb, handle, group, bitmap_bh,
+ grp_goal, &num, &my_rsv->rsv_window);
+ if (ret >= 0) {
+ my_rsv->rsv_alloc_hit += num;
+ *count = num;
+ break; /* succeed */
+ }
+ num = *count;
+ }
+out:
+ if (ret >= 0) {
+ BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for "
+ "bitmap block");
+ fatal = ext4_journal_dirty_metadata(handle, bitmap_bh);
+ if (fatal) {
+ *errp = fatal;
+ return -1;
+ }
+ return ret;
+ }
+
+ BUFFER_TRACE(bitmap_bh, "journal_release_buffer");
+ ext4_journal_release_buffer(handle, bitmap_bh);
+ return ret;
+}
+
+/**
+ * ext4_has_free_blocks()
+ * @sbi: in-core super block structure.
+ *
+ * Check if filesystem has at least 1 free block available for allocation.
+ */
+static int ext4_has_free_blocks(struct ext4_sb_info *sbi)
+{
+ ext4_fsblk_t free_blocks, root_blocks;
+
+ free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+ root_blocks = ext4_r_blocks_count(sbi->s_es);
+ if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) &&
+ sbi->s_resuid != current->fsuid &&
+ (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) {
+ return 0;
+ }
+ return 1;
+}
+
+/**
+ * ext4_should_retry_alloc()
+ * @sb: super block
+ * @retries number of attemps has been made
+ *
+ * ext4_should_retry_alloc() is called when ENOSPC is returned, and if
+ * it is profitable to retry the operation, this function will wait
+ * for the current or commiting transaction to complete, and then
+ * return TRUE.
+ *
+ * if the total number of retries exceed three times, return FALSE.
+ */
+int ext4_should_retry_alloc(struct super_block *sb, int *retries)
+{
+ if (!ext4_has_free_blocks(EXT4_SB(sb)) || (*retries)++ > 3)
+ return 0;
+
+ jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
+
+ return jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal);
+}
+
+/**
+ * ext4_new_blocks() -- core block(s) allocation function
+ * @handle: handle to this transaction
+ * @inode: file inode
+ * @goal: given target block(filesystem wide)
+ * @count: target number of blocks to allocate
+ * @errp: error code
+ *
+ * ext4_new_blocks uses a goal block to assist allocation. It tries to
+ * allocate block(s) from the block group contains the goal block first. If that
+ * fails, it will try to allocate block(s) from other block groups without
+ * any specific goal block.
+ *
+ */
+ext4_fsblk_t ext4_new_blocks(handle_t *handle, struct inode *inode,
+ ext4_fsblk_t goal, unsigned long *count, int *errp)
+{
+ struct buffer_head *bitmap_bh = NULL;
+ struct buffer_head *gdp_bh;
+ unsigned long group_no;
+ int goal_group;
+ ext4_grpblk_t grp_target_blk; /* blockgroup relative goal block */
+ ext4_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/
+ ext4_fsblk_t ret_block; /* filesyetem-wide allocated block */
+ int bgi; /* blockgroup iteration index */
+ int fatal = 0, err;
+ int performed_allocation = 0;
+ ext4_grpblk_t free_blocks; /* number of free blocks in a group */
+ struct super_block *sb;
+ struct ext4_group_desc *gdp;
+ struct ext4_super_block *es;
+ struct ext4_sb_info *sbi;
+ struct ext4_reserve_window_node *my_rsv = NULL;
+ struct ext4_block_alloc_info *block_i;
+ unsigned short windowsz = 0;
+#ifdef EXT4FS_DEBUG
+ static int goal_hits, goal_attempts;
+#endif
+ unsigned long ngroups;
+ unsigned long num = *count;
+
+ *errp = -ENOSPC;
+ sb = inode->i_sb;
+ if (!sb) {
+ printk("ext4_new_block: nonexistent device");
+ return 0;
+ }
+
+ /*
+ * Check quota for allocation of this block.
+ */
+ if (DQUOT_ALLOC_BLOCK(inode, num)) {
+ *errp = -EDQUOT;
+ return 0;
+ }
+
+ sbi = EXT4_SB(sb);
+ es = EXT4_SB(sb)->s_es;
+ ext4_debug("goal=%lu.\n", goal);
+ /*
+ * Allocate a block from reservation only when
+ * filesystem is mounted with reservation(default,-o reservation), and
+ * it's a regular file, and
+ * the desired window size is greater than 0 (One could use ioctl
+ * command EXT4_IOC_SETRSVSZ to set the window size to 0 to turn off
+ * reservation on that particular file)
+ */
+ block_i = EXT4_I(inode)->i_block_alloc_info;
+ if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0))
+ my_rsv = &block_i->rsv_window_node;
+
+ if (!ext4_has_free_blocks(sbi)) {
+ *errp = -ENOSPC;
+ goto out;
+ }
+
+ /*
+ * First, test whether the goal block is free.
+ */
+ if (goal < le32_to_cpu(es->s_first_data_block) ||
+ goal >= ext4_blocks_count(es))
+ goal = le32_to_cpu(es->s_first_data_block);
+ ext4_get_group_no_and_offset(sb, goal, &group_no, &grp_target_blk);
+ goal_group = group_no;
+retry_alloc:
+ gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
+ if (!gdp)
+ goto io_error;
+
+ free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
+ /*
+ * if there is not enough free blocks to make a new resevation
+ * turn off reservation for this allocation
+ */
+ if (my_rsv && (free_blocks < windowsz)
+ && (rsv_is_empty(&my_rsv->rsv_window)))
+ my_rsv = NULL;
+
+ if (free_blocks > 0) {
+ bitmap_bh = read_block_bitmap(sb, group_no);
+ if (!bitmap_bh)
+ goto io_error;
+ grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
+ group_no, bitmap_bh, grp_target_blk,
+ my_rsv, &num, &fatal);
+ if (fatal)
+ goto out;
+ if (grp_alloc_blk >= 0)
+ goto allocated;
+ }
+
+ ngroups = EXT4_SB(sb)->s_groups_count;
+ smp_rmb();
+
+ /*
+ * Now search the rest of the groups. We assume that
+ * i and gdp correctly point to the last group visited.
+ */
+ for (bgi = 0; bgi < ngroups; bgi++) {
+ group_no++;
+ if (group_no >= ngroups)
+ group_no = 0;
+ gdp = ext4_get_group_desc(sb, group_no, &gdp_bh);
+ if (!gdp) {
+ *errp = -EIO;
+ goto out;
+ }
+ free_blocks = le16_to_cpu(gdp->bg_free_blocks_count);
+ /*
+ * skip this group if the number of
+ * free blocks is less than half of the reservation
+ * window size.
+ */
+ if (free_blocks <= (windowsz/2))
+ continue;
+
+ brelse(bitmap_bh);
+ bitmap_bh = read_block_bitmap(sb, group_no);
+ if (!bitmap_bh)
+ goto io_error;
+ /*
+ * try to allocate block(s) from this group, without a goal(-1).
+ */
+ grp_alloc_blk = ext4_try_to_allocate_with_rsv(sb, handle,
+ group_no, bitmap_bh, -1, my_rsv,
+ &num, &fatal);
+ if (fatal)
+ goto out;
+ if (grp_alloc_blk >= 0)
+ goto allocated;
+ }
+ /*
+ * We may end up a bogus ealier ENOSPC error due to
+ * filesystem is "full" of reservations, but
+ * there maybe indeed free blocks avaliable on disk
+ * In this case, we just forget about the reservations
+ * just do block allocation as without reservations.
+ */
+ if (my_rsv) {
+ my_rsv = NULL;
+ group_no = goal_group;
+ goto retry_alloc;
+ }
+ /* No space left on the device */
+ *errp = -ENOSPC;
+ goto out;
+
+allocated:
+
+ ext4_debug("using block group %d(%d)\n",
+ group_no, gdp->bg_free_blocks_count);
+
+ BUFFER_TRACE(gdp_bh, "get_write_access");
+ fatal = ext4_journal_get_write_access(handle, gdp_bh);
+ if (fatal)
+ goto out;
+
+ ret_block = grp_alloc_blk + ext4_group_first_block_no(sb, group_no);
+
+ if (in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
+ in_range(ext4_block_bitmap(sb, gdp), ret_block, num) ||
+ in_range(ret_block, ext4_inode_table(sb, gdp),
+ EXT4_SB(sb)->s_itb_per_group) ||
+ in_range(ret_block + num - 1, ext4_inode_table(sb, gdp),
+ EXT4_SB(sb)->s_itb_per_group))
+ ext4_error(sb, "ext4_new_block",
+ "Allocating block in system zone - "
+ "blocks from %llu, length %lu",
+ ret_block, num);
+
+ performed_allocation = 1;
+
+#ifdef CONFIG_JBD_DEBUG
+ {
+ struct buffer_head *debug_bh;
+
+ /* Record bitmap buffer state in the newly allocated block */
+ debug_bh = sb_find_get_block(sb, ret_block);
+ if (debug_bh) {
+ BUFFER_TRACE(debug_bh, "state when allocated");
+ BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state");
+ brelse(debug_bh);
+ }
+ }
+ jbd_lock_bh_state(bitmap_bh);
+ spin_lock(sb_bgl_lock(sbi, group_no));
+ if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) {
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (ext4_test_bit(grp_alloc_blk+i,
+ bh2jh(bitmap_bh)->b_committed_data)) {
+ printk("%s: block was unexpectedly set in "
+ "b_committed_data\n", __FUNCTION__);
+ }
+ }
+ }
+ ext4_debug("found bit %d\n", grp_alloc_blk);
+ spin_unlock(sb_bgl_lock(sbi, group_no));
+ jbd_unlock_bh_state(bitmap_bh);
+#endif
+
+ if (ret_block + num - 1 >= ext4_blocks_count(es)) {
+ ext4_error(sb, "ext4_new_block",
+ "block(%llu) >= blocks count(%llu) - "
+ "block_group = %lu, es == %p ", ret_block,
+ ext4_blocks_count(es), group_no, es);
+ goto out;
+ }
+
+ /*
+ * It is up to the caller to add the new buffer to a journal
+ * list of some description. We don't know in advance whether
+ * the caller wants to use it as metadata or data.
+ */
+ ext4_debug("allocating block %lu. Goal hits %d of %d.\n",
+ ret_block, goal_hits, goal_attempts);
+
+ spin_lock(sb_bgl_lock(sbi, group_no));
+ gdp->bg_free_blocks_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num);
+ spin_unlock(sb_bgl_lock(sbi, group_no));
+ percpu_counter_mod(&sbi->s_freeblocks_counter, -num);
+
+ BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
+ err = ext4_journal_dirty_metadata(handle, gdp_bh);
+ if (!fatal)
+ fatal = err;
+
+ sb->s_dirt = 1;
+ if (fatal)
+ goto out;
+
+ *errp = 0;
+ brelse(bitmap_bh);
+ DQUOT_FREE_BLOCK(inode, *count-num);
+ *count = num;
+ return ret_block;
+
+io_error:
+ *errp = -EIO;
+out:
+ if (fatal) {
+ *errp = fatal;
+ ext4_std_error(sb, fatal);
+ }
+ /*
+ * Undo the block allocation
+ */
+ if (!performed_allocation)
+ DQUOT_FREE_BLOCK(inode, *count);
+ brelse(bitmap_bh);
+ return 0;
+}
+
+ext4_fsblk_t ext4_new_block(handle_t *handle, struct inode *inode,
+ ext4_fsblk_t goal, int *errp)
+{
+ unsigned long count = 1;
+
+ return ext4_new_blocks(handle, inode, goal, &count, errp);
+}
+
+/**
+ * ext4_count_free_blocks() -- count filesystem free blocks
+ * @sb: superblock
+ *
+ * Adds up the number of free blocks from each block group.
+ */
+ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
+{
+ ext4_fsblk_t desc_count;
+ struct ext4_group_desc *gdp;
+ int i;
+ unsigned long ngroups = EXT4_SB(sb)->s_groups_count;
+#ifdef EXT4FS_DEBUG
+ struct ext4_super_block *es;
+ ext4_fsblk_t bitmap_count;
+ unsigned long x;
+ struct buffer_head *bitmap_bh = NULL;
+
+ es = EXT4_SB(sb)->s_es;
+ desc_count = 0;
+ bitmap_count = 0;
+ gdp = NULL;
+
+ smp_rmb();
+ for (i = 0; i < ngroups; i++) {
+ gdp = ext4_get_group_desc(sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
+ brelse(bitmap_bh);
+ bitmap_bh = read_block_bitmap(sb, i);
+ if (bitmap_bh == NULL)
+ continue;
+
+ x = ext4_count_free(bitmap_bh, sb->s_blocksize);
+ printk("group %d: stored = %d, counted = %lu\n",
+ i, le16_to_cpu(gdp->bg_free_blocks_count), x);
+ bitmap_count += x;
+ }
+ brelse(bitmap_bh);
+ printk("ext4_count_free_blocks: stored = %llu"
+ ", computed = %llu, %llu\n",
+ EXT4_FREE_BLOCKS_COUNT(es),
+ desc_count, bitmap_count);
+ return bitmap_count;
+#else
+ desc_count = 0;
+ smp_rmb();
+ for (i = 0; i < ngroups; i++) {
+ gdp = ext4_get_group_desc(sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
+ }
+
+ return desc_count;
+#endif
+}
+
+static inline int
+block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map)
+{
+ ext4_grpblk_t offset;
+
+ ext4_get_group_no_and_offset(sb, block, NULL, &offset);
+ return ext4_test_bit (offset, map);
+}
+
+static inline int test_root(int a, int b)
+{
+ int num = b;
+
+ while (a > num)
+ num *= b;
+ return num == a;
+}
+
+static int ext4_group_sparse(int group)
+{
+ if (group <= 1)
+ return 1;
+ if (!(group & 1))
+ return 0;
+ return (test_root(group, 7) || test_root(group, 5) ||
+ test_root(group, 3));
+}
+
+/**
+ * ext4_bg_has_super - number of blocks used by the superblock in group
+ * @sb: superblock for filesystem
+ * @group: group number to check
+ *
+ * Return the number of blocks used by the superblock (primary or backup)
+ * in this group. Currently this will be only 0 or 1.
+ */
+int ext4_bg_has_super(struct super_block *sb, int group)
+{
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
+ !ext4_group_sparse(group))
+ return 0;
+ return 1;
+}
+
+static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, int group)
+{
+ unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
+ unsigned long first = metagroup * EXT4_DESC_PER_BLOCK(sb);
+ unsigned long last = first + EXT4_DESC_PER_BLOCK(sb) - 1;
+
+ if (group == first || group == first + 1 || group == last)
+ return 1;
+ return 0;
+}
+
+static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, int group)
+{
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
+ !ext4_group_sparse(group))
+ return 0;
+ return EXT4_SB(sb)->s_gdb_count;
+}
+
+/**
+ * ext4_bg_num_gdb - number of blocks used by the group table in group
+ * @sb: superblock for filesystem
+ * @group: group number to check
+ *
+ * Return the number of blocks used by the group descriptor table
+ * (primary or backup) in this group. In the future there may be a
+ * different number of descriptor blocks in each group.
+ */
+unsigned long ext4_bg_num_gdb(struct super_block *sb, int group)
+{
+ unsigned long first_meta_bg =
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg);
+ unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
+ metagroup < first_meta_bg)
+ return ext4_bg_num_gdb_nometa(sb,group);
+
+ return ext4_bg_num_gdb_meta(sb,group);
+
+}
diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c
new file mode 100644
index 000000000000..11e93c169bcf
--- /dev/null
+++ b/fs/ext4/bitmap.c
@@ -0,0 +1,32 @@
+/*
+ * linux/fs/ext4/bitmap.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ */
+
+#include <linux/buffer_head.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+
+#ifdef EXT4FS_DEBUG
+
+static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
+
+unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars)
+{
+ unsigned int i;
+ unsigned long sum = 0;
+
+ if (!map)
+ return (0);
+ for (i = 0; i < numchars; i++)
+ sum += nibblemap[map->b_data[i] & 0xf] +
+ nibblemap[(map->b_data[i] >> 4) & 0xf];
+ return (sum);
+}
+
+#endif /* EXT4FS_DEBUG */
+
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c
new file mode 100644
index 000000000000..f8595787a70e
--- /dev/null
+++ b/fs/ext4/dir.c
@@ -0,0 +1,518 @@
+/*
+ * linux/fs/ext4/dir.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/dir.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext4 directory handling functions
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ *
+ * Hash Tree Directory indexing (c) 2001 Daniel Phillips
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/buffer_head.h>
+#include <linux/smp_lock.h>
+#include <linux/slab.h>
+#include <linux/rbtree.h>
+
+static unsigned char ext4_filetype_table[] = {
+ DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
+};
+
+static int ext4_readdir(struct file *, void *, filldir_t);
+static int ext4_dx_readdir(struct file * filp,
+ void * dirent, filldir_t filldir);
+static int ext4_release_dir (struct inode * inode,
+ struct file * filp);
+
+const struct file_operations ext4_dir_operations = {
+ .llseek = generic_file_llseek,
+ .read = generic_read_dir,
+ .readdir = ext4_readdir, /* we take BKL. needed?*/
+ .ioctl = ext4_ioctl, /* BKL held */
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ext4_compat_ioctl,
+#endif
+ .fsync = ext4_sync_file, /* BKL held */
+#ifdef CONFIG_EXT4_INDEX
+ .release = ext4_release_dir,
+#endif
+};
+
+
+static unsigned char get_dtype(struct super_block *sb, int filetype)
+{
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE) ||
+ (filetype >= EXT4_FT_MAX))
+ return DT_UNKNOWN;
+
+ return (ext4_filetype_table[filetype]);
+}
+
+
+int ext4_check_dir_entry (const char * function, struct inode * dir,
+ struct ext4_dir_entry_2 * de,
+ struct buffer_head * bh,
+ unsigned long offset)
+{
+ const char * error_msg = NULL;
+ const int rlen = le16_to_cpu(de->rec_len);
+
+ if (rlen < EXT4_DIR_REC_LEN(1))
+ error_msg = "rec_len is smaller than minimal";
+ else if (rlen % 4 != 0)
+ error_msg = "rec_len % 4 != 0";
+ else if (rlen < EXT4_DIR_REC_LEN(de->name_len))
+ error_msg = "rec_len is too small for name_len";
+ else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
+ error_msg = "directory entry across blocks";
+ else if (le32_to_cpu(de->inode) >
+ le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))
+ error_msg = "inode out of bounds";
+
+ if (error_msg != NULL)
+ ext4_error (dir->i_sb, function,
+ "bad entry in directory #%lu: %s - "
+ "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+ dir->i_ino, error_msg, offset,
+ (unsigned long) le32_to_cpu(de->inode),
+ rlen, de->name_len);
+ return error_msg == NULL ? 1 : 0;
+}
+
+static int ext4_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ int error = 0;
+ unsigned long offset;
+ int i, stored;
+ struct ext4_dir_entry_2 *de;
+ struct super_block *sb;
+ int err;
+ struct inode *inode = filp->f_dentry->d_inode;
+ int ret = 0;
+
+ sb = inode->i_sb;
+
+#ifdef CONFIG_EXT4_INDEX
+ if (EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_COMPAT_DIR_INDEX) &&
+ ((EXT4_I(inode)->i_flags & EXT4_INDEX_FL) ||
+ ((inode->i_size >> sb->s_blocksize_bits) == 1))) {
+ err = ext4_dx_readdir(filp, dirent, filldir);
+ if (err != ERR_BAD_DX_DIR) {
+ ret = err;
+ goto out;
+ }
+ /*
+ * We don't set the inode dirty flag since it's not
+ * critical that it get flushed back to the disk.
+ */
+ EXT4_I(filp->f_dentry->d_inode)->i_flags &= ~EXT4_INDEX_FL;
+ }
+#endif
+ stored = 0;
+ offset = filp->f_pos & (sb->s_blocksize - 1);
+
+ while (!error && !stored && filp->f_pos < inode->i_size) {
+ unsigned long blk = filp->f_pos >> EXT4_BLOCK_SIZE_BITS(sb);
+ struct buffer_head map_bh;
+ struct buffer_head *bh = NULL;
+
+ map_bh.b_state = 0;
+ err = ext4_get_blocks_wrap(NULL, inode, blk, 1, &map_bh, 0, 0);
+ if (err > 0) {
+ page_cache_readahead(sb->s_bdev->bd_inode->i_mapping,
+ &filp->f_ra,
+ filp,
+ map_bh.b_blocknr >>
+ (PAGE_CACHE_SHIFT - inode->i_blkbits),
+ 1);
+ bh = ext4_bread(NULL, inode, blk, 0, &err);
+ }
+
+ /*
+ * We ignore I/O errors on directories so users have a chance
+ * of recovering data when there's a bad sector
+ */
+ if (!bh) {
+ ext4_error (sb, "ext4_readdir",
+ "directory #%lu contains a hole at offset %lu",
+ inode->i_ino, (unsigned long)filp->f_pos);
+ filp->f_pos += sb->s_blocksize - offset;
+ continue;
+ }
+
+revalidate:
+ /* If the dir block has changed since the last call to
+ * readdir(2), then we might be pointing to an invalid
+ * dirent right now. Scan from the start of the block
+ * to make sure. */
+ if (filp->f_version != inode->i_version) {
+ for (i = 0; i < sb->s_blocksize && i < offset; ) {
+ de = (struct ext4_dir_entry_2 *)
+ (bh->b_data + i);
+ /* It's too expensive to do a full
+ * dirent test each time round this
+ * loop, but we do have to test at
+ * least that it is non-zero. A
+ * failure will be detected in the
+ * dirent test below. */
+ if (le16_to_cpu(de->rec_len) <
+ EXT4_DIR_REC_LEN(1))
+ break;
+ i += le16_to_cpu(de->rec_len);
+ }
+ offset = i;
+ filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+ | offset;
+ filp->f_version = inode->i_version;
+ }
+
+ while (!error && filp->f_pos < inode->i_size
+ && offset < sb->s_blocksize) {
+ de = (struct ext4_dir_entry_2 *) (bh->b_data + offset);
+ if (!ext4_check_dir_entry ("ext4_readdir", inode, de,
+ bh, offset)) {
+ /*
+ * On error, skip the f_pos to the next block
+ */
+ filp->f_pos = (filp->f_pos |
+ (sb->s_blocksize - 1)) + 1;
+ brelse (bh);
+ ret = stored;
+ goto out;
+ }
+ offset += le16_to_cpu(de->rec_len);
+ if (le32_to_cpu(de->inode)) {
+ /* We might block in the next section
+ * if the data destination is
+ * currently swapped out. So, use a
+ * version stamp to detect whether or
+ * not the directory has been modified
+ * during the copy operation.
+ */
+ unsigned long version = filp->f_version;
+
+ error = filldir(dirent, de->name,
+ de->name_len,
+ filp->f_pos,
+ le32_to_cpu(de->inode),
+ get_dtype(sb, de->file_type));
+ if (error)
+ break;
+ if (version != filp->f_version)
+ goto revalidate;
+ stored ++;
+ }
+ filp->f_pos += le16_to_cpu(de->rec_len);
+ }
+ offset = 0;
+ brelse (bh);
+ }
+out:
+ return ret;
+}
+
+#ifdef CONFIG_EXT4_INDEX
+/*
+ * These functions convert from the major/minor hash to an f_pos
+ * value.
+ *
+ * Currently we only use major hash numer. This is unfortunate, but
+ * on 32-bit machines, the same VFS interface is used for lseek and
+ * llseek, so if we use the 64 bit offset, then the 32-bit versions of
+ * lseek/telldir/seekdir will blow out spectacularly, and from within
+ * the ext2 low-level routine, we don't know if we're being called by
+ * a 64-bit version of the system call or the 32-bit version of the
+ * system call. Worse yet, NFSv2 only allows for a 32-bit readdir
+ * cookie. Sigh.
+ */
+#define hash2pos(major, minor) (major >> 1)
+#define pos2maj_hash(pos) ((pos << 1) & 0xffffffff)
+#define pos2min_hash(pos) (0)
+
+/*
+ * This structure holds the nodes of the red-black tree used to store
+ * the directory entry in hash order.
+ */
+struct fname {
+ __u32 hash;
+ __u32 minor_hash;
+ struct rb_node rb_hash;
+ struct fname *next;
+ __u32 inode;
+ __u8 name_len;
+ __u8 file_type;
+ char name[0];
+};
+
+/*
+ * This functoin implements a non-recursive way of freeing all of the
+ * nodes in the red-black tree.
+ */
+static void free_rb_tree_fname(struct rb_root *root)
+{
+ struct rb_node *n = root->rb_node;
+ struct rb_node *parent;
+ struct fname *fname;
+
+ while (n) {
+ /* Do the node's children first */
+ if ((n)->rb_left) {
+ n = n->rb_left;
+ continue;
+ }
+ if (n->rb_right) {
+ n = n->rb_right;
+ continue;
+ }
+ /*
+ * The node has no children; free it, and then zero
+ * out parent's link to it. Finally go to the
+ * beginning of the loop and try to free the parent
+ * node.
+ */
+ parent = rb_parent(n);
+ fname = rb_entry(n, struct fname, rb_hash);
+ while (fname) {
+ struct fname * old = fname;
+ fname = fname->next;
+ kfree (old);
+ }
+ if (!parent)
+ root->rb_node = NULL;
+ else if (parent->rb_left == n)
+ parent->rb_left = NULL;
+ else if (parent->rb_right == n)
+ parent->rb_right = NULL;
+ n = parent;
+ }
+ root->rb_node = NULL;
+}
+
+
+static struct dir_private_info *create_dir_info(loff_t pos)
+{
+ struct dir_private_info *p;
+
+ p = kmalloc(sizeof(struct dir_private_info), GFP_KERNEL);
+ if (!p)
+ return NULL;
+ p->root.rb_node = NULL;
+ p->curr_node = NULL;
+ p->extra_fname = NULL;
+ p->last_pos = 0;
+ p->curr_hash = pos2maj_hash(pos);
+ p->curr_minor_hash = pos2min_hash(pos);
+ p->next_hash = 0;
+ return p;
+}
+
+void ext4_htree_free_dir_info(struct dir_private_info *p)
+{
+ free_rb_tree_fname(&p->root);
+ kfree(p);
+}
+
+/*
+ * Given a directory entry, enter it into the fname rb tree.
+ */
+int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
+ __u32 minor_hash,
+ struct ext4_dir_entry_2 *dirent)
+{
+ struct rb_node **p, *parent = NULL;
+ struct fname * fname, *new_fn;
+ struct dir_private_info *info;
+ int len;
+
+ info = (struct dir_private_info *) dir_file->private_data;
+ p = &info->root.rb_node;
+
+ /* Create and allocate the fname structure */
+ len = sizeof(struct fname) + dirent->name_len + 1;
+ new_fn = kzalloc(len, GFP_KERNEL);
+ if (!new_fn)
+ return -ENOMEM;
+ new_fn->hash = hash;
+ new_fn->minor_hash = minor_hash;
+ new_fn->inode = le32_to_cpu(dirent->inode);
+ new_fn->name_len = dirent->name_len;
+ new_fn->file_type = dirent->file_type;
+ memcpy(new_fn->name, dirent->name, dirent->name_len);
+ new_fn->name[dirent->name_len] = 0;
+
+ while (*p) {
+ parent = *p;
+ fname = rb_entry(parent, struct fname, rb_hash);
+
+ /*
+ * If the hash and minor hash match up, then we put
+ * them on a linked list. This rarely happens...
+ */
+ if ((new_fn->hash == fname->hash) &&
+ (new_fn->minor_hash == fname->minor_hash)) {
+ new_fn->next = fname->next;
+ fname->next = new_fn;
+ return 0;
+ }
+
+ if (new_fn->hash < fname->hash)
+ p = &(*p)->rb_left;
+ else if (new_fn->hash > fname->hash)
+ p = &(*p)->rb_right;
+ else if (new_fn->minor_hash < fname->minor_hash)
+ p = &(*p)->rb_left;
+ else /* if (new_fn->minor_hash > fname->minor_hash) */
+ p = &(*p)->rb_right;
+ }
+
+ rb_link_node(&new_fn->rb_hash, parent, p);
+ rb_insert_color(&new_fn->rb_hash, &info->root);
+ return 0;
+}
+
+
+
+/*
+ * This is a helper function for ext4_dx_readdir. It calls filldir
+ * for all entres on the fname linked list. (Normally there is only
+ * one entry on the linked list, unless there are 62 bit hash collisions.)
+ */
+static int call_filldir(struct file * filp, void * dirent,
+ filldir_t filldir, struct fname *fname)
+{
+ struct dir_private_info *info = filp->private_data;
+ loff_t curr_pos;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct super_block * sb;
+ int error;
+
+ sb = inode->i_sb;
+
+ if (!fname) {
+ printk("call_filldir: called with null fname?!?\n");
+ return 0;
+ }
+ curr_pos = hash2pos(fname->hash, fname->minor_hash);
+ while (fname) {
+ error = filldir(dirent, fname->name,
+ fname->name_len, curr_pos,
+ fname->inode,
+ get_dtype(sb, fname->file_type));
+ if (error) {
+ filp->f_pos = curr_pos;
+ info->extra_fname = fname->next;
+ return error;
+ }
+ fname = fname->next;
+ }
+ return 0;
+}
+
+static int ext4_dx_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ struct dir_private_info *info = filp->private_data;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct fname *fname;
+ int ret;
+
+ if (!info) {
+ info = create_dir_info(filp->f_pos);
+ if (!info)
+ return -ENOMEM;
+ filp->private_data = info;
+ }
+
+ if (filp->f_pos == EXT4_HTREE_EOF)
+ return 0; /* EOF */
+
+ /* Some one has messed with f_pos; reset the world */
+ if (info->last_pos != filp->f_pos) {
+ free_rb_tree_fname(&info->root);
+ info->curr_node = NULL;
+ info->extra_fname = NULL;
+ info->curr_hash = pos2maj_hash(filp->f_pos);
+ info->curr_minor_hash = pos2min_hash(filp->f_pos);
+ }
+
+ /*
+ * If there are any leftover names on the hash collision
+ * chain, return them first.
+ */
+ if (info->extra_fname &&
+ call_filldir(filp, dirent, filldir, info->extra_fname))
+ goto finished;
+
+ if (!info->curr_node)
+ info->curr_node = rb_first(&info->root);
+
+ while (1) {
+ /*
+ * Fill the rbtree if we have no more entries,
+ * or the inode has changed since we last read in the
+ * cached entries.
+ */
+ if ((!info->curr_node) ||
+ (filp->f_version != inode->i_version)) {
+ info->curr_node = NULL;
+ free_rb_tree_fname(&info->root);
+ filp->f_version = inode->i_version;
+ ret = ext4_htree_fill_tree(filp, info->curr_hash,
+ info->curr_minor_hash,
+ &info->next_hash);
+ if (ret < 0)
+ return ret;
+ if (ret == 0) {
+ filp->f_pos = EXT4_HTREE_EOF;
+ break;
+ }
+ info->curr_node = rb_first(&info->root);
+ }
+
+ fname = rb_entry(info->curr_node, struct fname, rb_hash);
+ info->curr_hash = fname->hash;
+ info->curr_minor_hash = fname->minor_hash;
+ if (call_filldir(filp, dirent, filldir, fname))
+ break;
+
+ info->curr_node = rb_next(info->curr_node);
+ if (!info->curr_node) {
+ if (info->next_hash == ~0) {
+ filp->f_pos = EXT4_HTREE_EOF;
+ break;
+ }
+ info->curr_hash = info->next_hash;
+ info->curr_minor_hash = 0;
+ }
+ }
+finished:
+ info->last_pos = filp->f_pos;
+ return 0;
+}
+
+static int ext4_release_dir (struct inode * inode, struct file * filp)
+{
+ if (filp->private_data)
+ ext4_htree_free_dir_info(filp->private_data);
+
+ return 0;
+}
+
+#endif
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
new file mode 100644
index 000000000000..2608dce18f3e
--- /dev/null
+++ b/fs/ext4/extents.c
@@ -0,0 +1,2152 @@
+/*
+ * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
+ * Written by Alex Tomas <alex@clusterfs.com>
+ *
+ * Architecture independence:
+ * Copyright (c) 2005, Bull S.A.
+ * Written by Pierre Peiffer <pierre.peiffer@bull.net>
+ *
+ * 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 Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
+ */
+
+/*
+ * Extents support for EXT4
+ *
+ * TODO:
+ * - ext4*_error() should be used in some situations
+ * - analyze all BUG()/BUG_ON(), use -EIO where appropriate
+ * - smart tree reduction
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/jbd.h>
+#include <linux/smp_lock.h>
+#include <linux/highuid.h>
+#include <linux/pagemap.h>
+#include <linux/quotaops.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/ext4_fs_extents.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * ext_pblock:
+ * combine low and high parts of physical block number into ext4_fsblk_t
+ */
+static inline ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
+{
+ ext4_fsblk_t block;
+
+ block = le32_to_cpu(ex->ee_start);
+ block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1;
+ return block;
+}
+
+/*
+ * idx_pblock:
+ * combine low and high parts of a leaf physical block number into ext4_fsblk_t
+ */
+static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix)
+{
+ ext4_fsblk_t block;
+
+ block = le32_to_cpu(ix->ei_leaf);
+ block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1;
+ return block;
+}
+
+/*
+ * ext4_ext_store_pblock:
+ * stores a large physical block number into an extent struct,
+ * breaking it into parts
+ */
+static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb)
+{
+ ex->ee_start = cpu_to_le32((unsigned long) (pb & 0xffffffff));
+ ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
+}
+
+/*
+ * ext4_idx_store_pblock:
+ * stores a large physical block number into an index struct,
+ * breaking it into parts
+ */
+static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
+{
+ ix->ei_leaf = cpu_to_le32((unsigned long) (pb & 0xffffffff));
+ ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
+}
+
+static int ext4_ext_check_header(const char *function, struct inode *inode,
+ struct ext4_extent_header *eh)
+{
+ const char *error_msg = NULL;
+
+ if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) {
+ error_msg = "invalid magic";
+ goto corrupted;
+ }
+ if (unlikely(eh->eh_max == 0)) {
+ error_msg = "invalid eh_max";
+ goto corrupted;
+ }
+ if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) {
+ error_msg = "invalid eh_entries";
+ goto corrupted;
+ }
+ return 0;
+
+corrupted:
+ ext4_error(inode->i_sb, function,
+ "bad header in inode #%lu: %s - magic %x, "
+ "entries %u, max %u, depth %u",
+ inode->i_ino, error_msg, le16_to_cpu(eh->eh_magic),
+ le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max),
+ le16_to_cpu(eh->eh_depth));
+
+ return -EIO;
+}
+
+static handle_t *ext4_ext_journal_restart(handle_t *handle, int needed)
+{
+ int err;
+
+ if (handle->h_buffer_credits > needed)
+ return handle;
+ if (!ext4_journal_extend(handle, needed))
+ return handle;
+ err = ext4_journal_restart(handle, needed);
+
+ return handle;
+}
+
+/*
+ * could return:
+ * - EROFS
+ * - ENOMEM
+ */
+static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path)
+{
+ if (path->p_bh) {
+ /* path points to block */
+ return ext4_journal_get_write_access(handle, path->p_bh);
+ }
+ /* path points to leaf/index in inode body */
+ /* we use in-core data, no need to protect them */
+ return 0;
+}
+
+/*
+ * could return:
+ * - EROFS
+ * - ENOMEM
+ * - EIO
+ */
+static int ext4_ext_dirty(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path)
+{
+ int err;
+ if (path->p_bh) {
+ /* path points to block */
+ err = ext4_journal_dirty_metadata(handle, path->p_bh);
+ } else {
+ /* path points to leaf/index in inode body */
+ err = ext4_mark_inode_dirty(handle, inode);
+ }
+ return err;
+}
+
+static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
+ struct ext4_ext_path *path,
+ ext4_fsblk_t block)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ ext4_fsblk_t bg_start;
+ ext4_grpblk_t colour;
+ int depth;
+
+ if (path) {
+ struct ext4_extent *ex;
+ depth = path->p_depth;
+
+ /* try to predict block placement */
+ if ((ex = path[depth].p_ext))
+ return ext_pblock(ex)+(block-le32_to_cpu(ex->ee_block));
+
+ /* it looks like index is empty;
+ * try to find starting block from index itself */
+ if (path[depth].p_bh)
+ return path[depth].p_bh->b_blocknr;
+ }
+
+ /* OK. use inode's group */
+ bg_start = (ei->i_block_group * EXT4_BLOCKS_PER_GROUP(inode->i_sb)) +
+ le32_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_first_data_block);
+ colour = (current->pid % 16) *
+ (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
+ return bg_start + colour + block;
+}
+
+static ext4_fsblk_t
+ext4_ext_new_block(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *ex, int *err)
+{
+ ext4_fsblk_t goal, newblock;
+
+ goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block));
+ newblock = ext4_new_block(handle, inode, goal, err);
+ return newblock;
+}
+
+static inline int ext4_ext_space_block(struct inode *inode)
+{
+ int size;
+
+ size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
+ / sizeof(struct ext4_extent);
+#ifdef AGRESSIVE_TEST
+ if (size > 6)
+ size = 6;
+#endif
+ return size;
+}
+
+static inline int ext4_ext_space_block_idx(struct inode *inode)
+{
+ int size;
+
+ size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
+ / sizeof(struct ext4_extent_idx);
+#ifdef AGRESSIVE_TEST
+ if (size > 5)
+ size = 5;
+#endif
+ return size;
+}
+
+static inline int ext4_ext_space_root(struct inode *inode)
+{
+ int size;
+
+ size = sizeof(EXT4_I(inode)->i_data);
+ size -= sizeof(struct ext4_extent_header);
+ size /= sizeof(struct ext4_extent);
+#ifdef AGRESSIVE_TEST
+ if (size > 3)
+ size = 3;
+#endif
+ return size;
+}
+
+static inline int ext4_ext_space_root_idx(struct inode *inode)
+{
+ int size;
+
+ size = sizeof(EXT4_I(inode)->i_data);
+ size -= sizeof(struct ext4_extent_header);
+ size /= sizeof(struct ext4_extent_idx);
+#ifdef AGRESSIVE_TEST
+ if (size > 4)
+ size = 4;
+#endif
+ return size;
+}
+
+#ifdef EXT_DEBUG
+static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
+{
+ int k, l = path->p_depth;
+
+ ext_debug("path:");
+ for (k = 0; k <= l; k++, path++) {
+ if (path->p_idx) {
+ ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block),
+ idx_pblock(path->p_idx));
+ } else if (path->p_ext) {
+ ext_debug(" %d:%d:%llu ",
+ le32_to_cpu(path->p_ext->ee_block),
+ le16_to_cpu(path->p_ext->ee_len),
+ ext_pblock(path->p_ext));
+ } else
+ ext_debug(" []");
+ }
+ ext_debug("\n");
+}
+
+static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
+{
+ int depth = ext_depth(inode);
+ struct ext4_extent_header *eh;
+ struct ext4_extent *ex;
+ int i;
+
+ if (!path)
+ return;
+
+ eh = path[depth].p_hdr;
+ ex = EXT_FIRST_EXTENT(eh);
+
+ for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
+ ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),
+ le16_to_cpu(ex->ee_len), ext_pblock(ex));
+ }
+ ext_debug("\n");
+}
+#else
+#define ext4_ext_show_path(inode,path)
+#define ext4_ext_show_leaf(inode,path)
+#endif
+
+static void ext4_ext_drop_refs(struct ext4_ext_path *path)
+{
+ int depth = path->p_depth;
+ int i;
+
+ for (i = 0; i <= depth; i++, path++)
+ if (path->p_bh) {
+ brelse(path->p_bh);
+ path->p_bh = NULL;
+ }
+}
+
+/*
+ * ext4_ext_binsearch_idx:
+ * binary search for the closest index of the given block
+ */
+static void
+ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int block)
+{
+ struct ext4_extent_header *eh = path->p_hdr;
+ struct ext4_extent_idx *r, *l, *m;
+
+ BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
+ BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
+ BUG_ON(le16_to_cpu(eh->eh_entries) <= 0);
+
+ ext_debug("binsearch for %d(idx): ", block);
+
+ l = EXT_FIRST_INDEX(eh) + 1;
+ r = EXT_FIRST_INDEX(eh) + le16_to_cpu(eh->eh_entries) - 1;
+ while (l <= r) {
+ m = l + (r - l) / 2;
+ if (block < le32_to_cpu(m->ei_block))
+ r = m - 1;
+ else
+ l = m + 1;
+ ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ei_block,
+ m, m->ei_block, r, r->ei_block);
+ }
+
+ path->p_idx = l - 1;
+ ext_debug(" -> %d->%lld ", le32_to_cpu(path->p_idx->ei_block),
+ idx_block(path->p_idx));
+
+#ifdef CHECK_BINSEARCH
+ {
+ struct ext4_extent_idx *chix, *ix;
+ int k;
+
+ chix = ix = EXT_FIRST_INDEX(eh);
+ for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) {
+ if (k != 0 &&
+ le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) {
+ printk("k=%d, ix=0x%p, first=0x%p\n", k,
+ ix, EXT_FIRST_INDEX(eh));
+ printk("%u <= %u\n",
+ le32_to_cpu(ix->ei_block),
+ le32_to_cpu(ix[-1].ei_block));
+ }
+ BUG_ON(k && le32_to_cpu(ix->ei_block)
+ <= le32_to_cpu(ix[-1].ei_block));
+ if (block < le32_to_cpu(ix->ei_block))
+ break;
+ chix = ix;
+ }
+ BUG_ON(chix != path->p_idx);
+ }
+#endif
+
+}
+
+/*
+ * ext4_ext_binsearch:
+ * binary search for closest extent of the given block
+ */
+static void
+ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
+{
+ struct ext4_extent_header *eh = path->p_hdr;
+ struct ext4_extent *r, *l, *m;
+
+ BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
+ BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
+
+ if (eh->eh_entries == 0) {
+ /*
+ * this leaf is empty:
+ * we get such a leaf in split/add case
+ */
+ return;
+ }
+
+ ext_debug("binsearch for %d: ", block);
+
+ l = EXT_FIRST_EXTENT(eh) + 1;
+ r = EXT_FIRST_EXTENT(eh) + le16_to_cpu(eh->eh_entries) - 1;
+
+ while (l <= r) {
+ m = l + (r - l) / 2;
+ if (block < le32_to_cpu(m->ee_block))
+ r = m - 1;
+ else
+ l = m + 1;
+ ext_debug("%p(%u):%p(%u):%p(%u) ", l, l->ee_block,
+ m, m->ee_block, r, r->ee_block);
+ }
+
+ path->p_ext = l - 1;
+ ext_debug(" -> %d:%llu:%d ",
+ le32_to_cpu(path->p_ext->ee_block),
+ ext_pblock(path->p_ext),
+ le16_to_cpu(path->p_ext->ee_len));
+
+#ifdef CHECK_BINSEARCH
+ {
+ struct ext4_extent *chex, *ex;
+ int k;
+
+ chex = ex = EXT_FIRST_EXTENT(eh);
+ for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) {
+ BUG_ON(k && le32_to_cpu(ex->ee_block)
+ <= le32_to_cpu(ex[-1].ee_block));
+ if (block < le32_to_cpu(ex->ee_block))
+ break;
+ chex = ex;
+ }
+ BUG_ON(chex != path->p_ext);
+ }
+#endif
+
+}
+
+int ext4_ext_tree_init(handle_t *handle, struct inode *inode)
+{
+ struct ext4_extent_header *eh;
+
+ eh = ext_inode_hdr(inode);
+ eh->eh_depth = 0;
+ eh->eh_entries = 0;
+ eh->eh_magic = EXT4_EXT_MAGIC;
+ eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode));
+ ext4_mark_inode_dirty(handle, inode);
+ ext4_ext_invalidate_cache(inode);
+ return 0;
+}
+
+struct ext4_ext_path *
+ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
+{
+ struct ext4_extent_header *eh;
+ struct buffer_head *bh;
+ short int depth, i, ppos = 0, alloc = 0;
+
+ eh = ext_inode_hdr(inode);
+ BUG_ON(eh == NULL);
+ if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+ return ERR_PTR(-EIO);
+
+ i = depth = ext_depth(inode);
+
+ /* account possible depth increase */
+ if (!path) {
+ path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 2),
+ GFP_NOFS);
+ if (!path)
+ return ERR_PTR(-ENOMEM);
+ alloc = 1;
+ }
+ memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
+ path[0].p_hdr = eh;
+
+ /* walk through the tree */
+ while (i) {
+ ext_debug("depth %d: num %d, max %d\n",
+ ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
+ ext4_ext_binsearch_idx(inode, path + ppos, block);
+ path[ppos].p_block = idx_pblock(path[ppos].p_idx);
+ path[ppos].p_depth = i;
+ path[ppos].p_ext = NULL;
+
+ bh = sb_bread(inode->i_sb, path[ppos].p_block);
+ if (!bh)
+ goto err;
+
+ eh = ext_block_hdr(bh);
+ ppos++;
+ BUG_ON(ppos > depth);
+ path[ppos].p_bh = bh;
+ path[ppos].p_hdr = eh;
+ i--;
+
+ if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+ goto err;
+ }
+
+ path[ppos].p_depth = i;
+ path[ppos].p_hdr = eh;
+ path[ppos].p_ext = NULL;
+ path[ppos].p_idx = NULL;
+
+ if (ext4_ext_check_header(__FUNCTION__, inode, eh))
+ goto err;
+
+ /* find extent */
+ ext4_ext_binsearch(inode, path + ppos, block);
+
+ ext4_ext_show_path(inode, path);
+
+ return path;
+
+err:
+ ext4_ext_drop_refs(path);
+ if (alloc)
+ kfree(path);
+ return ERR_PTR(-EIO);
+}
+
+/*
+ * ext4_ext_insert_index:
+ * insert new index [@logical;@ptr] into the block at @curp;
+ * check where to insert: before @curp or after @curp
+ */
+static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *curp,
+ int logical, ext4_fsblk_t ptr)
+{
+ struct ext4_extent_idx *ix;
+ int len, err;
+
+ if ((err = ext4_ext_get_access(handle, inode, curp)))
+ return err;
+
+ BUG_ON(logical == le32_to_cpu(curp->p_idx->ei_block));
+ len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx;
+ if (logical > le32_to_cpu(curp->p_idx->ei_block)) {
+ /* insert after */
+ if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {
+ len = (len - 1) * sizeof(struct ext4_extent_idx);
+ len = len < 0 ? 0 : len;
+ ext_debug("insert new index %d after: %d. "
+ "move %d from 0x%p to 0x%p\n",
+ logical, ptr, len,
+ (curp->p_idx + 1), (curp->p_idx + 2));
+ memmove(curp->p_idx + 2, curp->p_idx + 1, len);
+ }
+ ix = curp->p_idx + 1;
+ } else {
+ /* insert before */
+ len = len * sizeof(struct ext4_extent_idx);
+ len = len < 0 ? 0 : len;
+ ext_debug("insert new index %d before: %d. "
+ "move %d from 0x%p to 0x%p\n",
+ logical, ptr, len,
+ curp->p_idx, (curp->p_idx + 1));
+ memmove(curp->p_idx + 1, curp->p_idx, len);
+ ix = curp->p_idx;
+ }
+
+ ix->ei_block = cpu_to_le32(logical);
+ ext4_idx_store_pblock(ix, ptr);
+ curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1);
+
+ BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries)
+ > le16_to_cpu(curp->p_hdr->eh_max));
+ BUG_ON(ix > EXT_LAST_INDEX(curp->p_hdr));
+
+ err = ext4_ext_dirty(handle, inode, curp);
+ ext4_std_error(inode->i_sb, err);
+
+ return err;
+}
+
+/*
+ * ext4_ext_split:
+ * inserts new subtree into the path, using free index entry
+ * at depth @at:
+ * - allocates all needed blocks (new leaf and all intermediate index blocks)
+ * - makes decision where to split
+ * - moves remaining extents and index entries (right to the split point)
+ * into the newly allocated blocks
+ * - initializes subtree
+ */
+static int ext4_ext_split(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *newext, int at)
+{
+ struct buffer_head *bh = NULL;
+ int depth = ext_depth(inode);
+ struct ext4_extent_header *neh;
+ struct ext4_extent_idx *fidx;
+ struct ext4_extent *ex;
+ int i = at, k, m, a;
+ ext4_fsblk_t newblock, oldblock;
+ __le32 border;
+ ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */
+ int err = 0;
+
+ /* make decision: where to split? */
+ /* FIXME: now decision is simplest: at current extent */
+
+ /* if current leaf will be split, then we should use
+ * border from split point */
+ BUG_ON(path[depth].p_ext > EXT_MAX_EXTENT(path[depth].p_hdr));
+ if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) {
+ border = path[depth].p_ext[1].ee_block;
+ ext_debug("leaf will be split."
+ " next leaf starts at %d\n",
+ le32_to_cpu(border));
+ } else {
+ border = newext->ee_block;
+ ext_debug("leaf will be added."
+ " next leaf starts at %d\n",
+ le32_to_cpu(border));
+ }
+
+ /*
+ * If error occurs, then we break processing
+ * and mark filesystem read-only. index won't
+ * be inserted and tree will be in consistent
+ * state. Next mount will repair buffers too.
+ */
+
+ /*
+ * Get array to track all allocated blocks.
+ * We need this to handle errors and free blocks
+ * upon them.
+ */
+ ablocks = kmalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS);
+ if (!ablocks)
+ return -ENOMEM;
+ memset(ablocks, 0, sizeof(ext4_fsblk_t) * depth);
+
+ /* allocate all needed blocks */
+ ext_debug("allocate %d blocks for indexes/leaf\n", depth - at);
+ for (a = 0; a < depth - at; a++) {
+ newblock = ext4_ext_new_block(handle, inode, path, newext, &err);
+ if (newblock == 0)
+ goto cleanup;
+ ablocks[a] = newblock;
+ }
+
+ /* initialize new leaf */
+ newblock = ablocks[--a];
+ BUG_ON(newblock == 0);
+ bh = sb_getblk(inode->i_sb, newblock);
+ if (!bh) {
+ err = -EIO;
+ goto cleanup;
+ }
+ lock_buffer(bh);
+
+ if ((err = ext4_journal_get_create_access(handle, bh)))
+ goto cleanup;
+
+ neh = ext_block_hdr(bh);
+ neh->eh_entries = 0;
+ neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode));
+ neh->eh_magic = EXT4_EXT_MAGIC;
+ neh->eh_depth = 0;
+ ex = EXT_FIRST_EXTENT(neh);
+
+ /* move remainder of path[depth] to the new leaf */
+ BUG_ON(path[depth].p_hdr->eh_entries != path[depth].p_hdr->eh_max);
+ /* start copy from next extent */
+ /* TODO: we could do it by single memmove */
+ m = 0;
+ path[depth].p_ext++;
+ while (path[depth].p_ext <=
+ EXT_MAX_EXTENT(path[depth].p_hdr)) {
+ ext_debug("move %d:%llu:%d in new leaf %llu\n",
+ le32_to_cpu(path[depth].p_ext->ee_block),
+ ext_pblock(path[depth].p_ext),
+ le16_to_cpu(path[depth].p_ext->ee_len),
+ newblock);
+ /*memmove(ex++, path[depth].p_ext++,
+ sizeof(struct ext4_extent));
+ neh->eh_entries++;*/
+ path[depth].p_ext++;
+ m++;
+ }
+ if (m) {
+ memmove(ex, path[depth].p_ext-m, sizeof(struct ext4_extent)*m);
+ neh->eh_entries = cpu_to_le16(le16_to_cpu(neh->eh_entries)+m);
+ }
+
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+
+ if ((err = ext4_journal_dirty_metadata(handle, bh)))
+ goto cleanup;
+ brelse(bh);
+ bh = NULL;
+
+ /* correct old leaf */
+ if (m) {
+ if ((err = ext4_ext_get_access(handle, inode, path + depth)))
+ goto cleanup;
+ path[depth].p_hdr->eh_entries =
+ cpu_to_le16(le16_to_cpu(path[depth].p_hdr->eh_entries)-m);
+ if ((err = ext4_ext_dirty(handle, inode, path + depth)))
+ goto cleanup;
+
+ }
+
+ /* create intermediate indexes */
+ k = depth - at - 1;
+ BUG_ON(k < 0);
+ if (k)
+ ext_debug("create %d intermediate indices\n", k);
+ /* insert new index into current index block */
+ /* current depth stored in i var */
+ i = depth - 1;
+ while (k--) {
+ oldblock = newblock;
+ newblock = ablocks[--a];
+ bh = sb_getblk(inode->i_sb, (ext4_fsblk_t)newblock);
+ if (!bh) {
+ err = -EIO;
+ goto cleanup;
+ }
+ lock_buffer(bh);
+
+ if ((err = ext4_journal_get_create_access(handle, bh)))
+ goto cleanup;
+
+ neh = ext_block_hdr(bh);
+ neh->eh_entries = cpu_to_le16(1);
+ neh->eh_magic = EXT4_EXT_MAGIC;
+ neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode));
+ neh->eh_depth = cpu_to_le16(depth - i);
+ fidx = EXT_FIRST_INDEX(neh);
+ fidx->ei_block = border;
+ ext4_idx_store_pblock(fidx, oldblock);
+
+ ext_debug("int.index at %d (block %llu): %lu -> %llu\n", i,
+ newblock, (unsigned long) le32_to_cpu(border),
+ oldblock);
+ /* copy indexes */
+ m = 0;
+ path[i].p_idx++;
+
+ ext_debug("cur 0x%p, last 0x%p\n", path[i].p_idx,
+ EXT_MAX_INDEX(path[i].p_hdr));
+ BUG_ON(EXT_MAX_INDEX(path[i].p_hdr) !=
+ EXT_LAST_INDEX(path[i].p_hdr));
+ while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
+ ext_debug("%d: move %d:%d in new index %llu\n", i,
+ le32_to_cpu(path[i].p_idx->ei_block),
+ idx_pblock(path[i].p_idx),
+ newblock);
+ /*memmove(++fidx, path[i].p_idx++,
+ sizeof(struct ext4_extent_idx));
+ neh->eh_entries++;
+ BUG_ON(neh->eh_entries > neh->eh_max);*/
+ path[i].p_idx++;
+ m++;
+ }
+ if (m) {
+ memmove(++fidx, path[i].p_idx - m,
+ sizeof(struct ext4_extent_idx) * m);
+ neh->eh_entries =
+ cpu_to_le16(le16_to_cpu(neh->eh_entries) + m);
+ }
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+
+ if ((err = ext4_journal_dirty_metadata(handle, bh)))
+ goto cleanup;
+ brelse(bh);
+ bh = NULL;
+
+ /* correct old index */
+ if (m) {
+ err = ext4_ext_get_access(handle, inode, path + i);
+ if (err)
+ goto cleanup;
+ path[i].p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path[i].p_hdr->eh_entries)-m);
+ err = ext4_ext_dirty(handle, inode, path + i);
+ if (err)
+ goto cleanup;
+ }
+
+ i--;
+ }
+
+ /* insert new index */
+ if (err)
+ goto cleanup;
+
+ err = ext4_ext_insert_index(handle, inode, path + at,
+ le32_to_cpu(border), newblock);
+
+cleanup:
+ if (bh) {
+ if (buffer_locked(bh))
+ unlock_buffer(bh);
+ brelse(bh);
+ }
+
+ if (err) {
+ /* free all allocated blocks in error case */
+ for (i = 0; i < depth; i++) {
+ if (!ablocks[i])
+ continue;
+ ext4_free_blocks(handle, inode, ablocks[i], 1);
+ }
+ }
+ kfree(ablocks);
+
+ return err;
+}
+
+/*
+ * ext4_ext_grow_indepth:
+ * implements tree growing procedure:
+ * - allocates new block
+ * - moves top-level data (index block or leaf) into the new block
+ * - initializes new top-level, creating index that points to the
+ * just created block
+ */
+static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *newext)
+{
+ struct ext4_ext_path *curp = path;
+ struct ext4_extent_header *neh;
+ struct ext4_extent_idx *fidx;
+ struct buffer_head *bh;
+ ext4_fsblk_t newblock;
+ int err = 0;
+
+ newblock = ext4_ext_new_block(handle, inode, path, newext, &err);
+ if (newblock == 0)
+ return err;
+
+ bh = sb_getblk(inode->i_sb, newblock);
+ if (!bh) {
+ err = -EIO;
+ ext4_std_error(inode->i_sb, err);
+ return err;
+ }
+ lock_buffer(bh);
+
+ if ((err = ext4_journal_get_create_access(handle, bh))) {
+ unlock_buffer(bh);
+ goto out;
+ }
+
+ /* move top-level index/leaf into new block */
+ memmove(bh->b_data, curp->p_hdr, sizeof(EXT4_I(inode)->i_data));
+
+ /* set size of new block */
+ neh = ext_block_hdr(bh);
+ /* old root could have indexes or leaves
+ * so calculate e_max right way */
+ if (ext_depth(inode))
+ neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode));
+ else
+ neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode));
+ neh->eh_magic = EXT4_EXT_MAGIC;
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+
+ if ((err = ext4_journal_dirty_metadata(handle, bh)))
+ goto out;
+
+ /* create index in new top-level index: num,max,pointer */
+ if ((err = ext4_ext_get_access(handle, inode, curp)))
+ goto out;
+
+ curp->p_hdr->eh_magic = EXT4_EXT_MAGIC;
+ curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode));
+ curp->p_hdr->eh_entries = cpu_to_le16(1);
+ curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
+ /* FIXME: it works, but actually path[0] can be index */
+ curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;
+ ext4_idx_store_pblock(curp->p_idx, newblock);
+
+ neh = ext_inode_hdr(inode);
+ fidx = EXT_FIRST_INDEX(neh);
+ ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n",
+ le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max),
+ le32_to_cpu(fidx->ei_block), idx_pblock(fidx));
+
+ neh->eh_depth = cpu_to_le16(path->p_depth + 1);
+ err = ext4_ext_dirty(handle, inode, curp);
+out:
+ brelse(bh);
+
+ return err;
+}
+
+/*
+ * ext4_ext_create_new_leaf:
+ * finds empty index and adds new leaf.
+ * if no free index is found, then it requests in-depth growing.
+ */
+static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *newext)
+{
+ struct ext4_ext_path *curp;
+ int depth, i, err = 0;
+
+repeat:
+ i = depth = ext_depth(inode);
+
+ /* walk up to the tree and look for free index entry */
+ curp = path + depth;
+ while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) {
+ i--;
+ curp--;
+ }
+
+ /* we use already allocated block for index block,
+ * so subsequent data blocks should be contiguous */
+ if (EXT_HAS_FREE_INDEX(curp)) {
+ /* if we found index with free entry, then use that
+ * entry: create all needed subtree and add new leaf */
+ err = ext4_ext_split(handle, inode, path, newext, i);
+
+ /* refill path */
+ ext4_ext_drop_refs(path);
+ path = ext4_ext_find_extent(inode,
+ le32_to_cpu(newext->ee_block),
+ path);
+ if (IS_ERR(path))
+ err = PTR_ERR(path);
+ } else {
+ /* tree is full, time to grow in depth */
+ err = ext4_ext_grow_indepth(handle, inode, path, newext);
+ if (err)
+ goto out;
+
+ /* refill path */
+ ext4_ext_drop_refs(path);
+ path = ext4_ext_find_extent(inode,
+ le32_to_cpu(newext->ee_block),
+ path);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ goto out;
+ }
+
+ /*
+ * only first (depth 0 -> 1) produces free space;
+ * in all other cases we have to split the grown tree
+ */
+ depth = ext_depth(inode);
+ if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {
+ /* now we need to split */
+ goto repeat;
+ }
+ }
+
+out:
+ return err;
+}
+
+/*
+ * ext4_ext_next_allocated_block:
+ * returns allocated block in subsequent extent or EXT_MAX_BLOCK.
+ * NOTE: it considers block number from index entry as
+ * allocated block. Thus, index entries have to be consistent
+ * with leaves.
+ */
+static unsigned long
+ext4_ext_next_allocated_block(struct ext4_ext_path *path)
+{
+ int depth;
+
+ BUG_ON(path == NULL);
+ depth = path->p_depth;
+
+ if (depth == 0 && path->p_ext == NULL)
+ return EXT_MAX_BLOCK;
+
+ while (depth >= 0) {
+ if (depth == path->p_depth) {
+ /* leaf */
+ if (path[depth].p_ext !=
+ EXT_LAST_EXTENT(path[depth].p_hdr))
+ return le32_to_cpu(path[depth].p_ext[1].ee_block);
+ } else {
+ /* index */
+ if (path[depth].p_idx !=
+ EXT_LAST_INDEX(path[depth].p_hdr))
+ return le32_to_cpu(path[depth].p_idx[1].ei_block);
+ }
+ depth--;
+ }
+
+ return EXT_MAX_BLOCK;
+}
+
+/*
+ * ext4_ext_next_leaf_block:
+ * returns first allocated block from next leaf or EXT_MAX_BLOCK
+ */
+static unsigned ext4_ext_next_leaf_block(struct inode *inode,
+ struct ext4_ext_path *path)
+{
+ int depth;
+
+ BUG_ON(path == NULL);
+ depth = path->p_depth;
+
+ /* zero-tree has no leaf blocks at all */
+ if (depth == 0)
+ return EXT_MAX_BLOCK;
+
+ /* go to index block */
+ depth--;
+
+ while (depth >= 0) {
+ if (path[depth].p_idx !=
+ EXT_LAST_INDEX(path[depth].p_hdr))
+ return le32_to_cpu(path[depth].p_idx[1].ei_block);
+ depth--;
+ }
+
+ return EXT_MAX_BLOCK;
+}
+
+/*
+ * ext4_ext_correct_indexes:
+ * if leaf gets modified and modified extent is first in the leaf,
+ * then we have to correct all indexes above.
+ * TODO: do we need to correct tree in all cases?
+ */
+int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path)
+{
+ struct ext4_extent_header *eh;
+ int depth = ext_depth(inode);
+ struct ext4_extent *ex;
+ __le32 border;
+ int k, err = 0;
+
+ eh = path[depth].p_hdr;
+ ex = path[depth].p_ext;
+ BUG_ON(ex == NULL);
+ BUG_ON(eh == NULL);
+
+ if (depth == 0) {
+ /* there is no tree at all */
+ return 0;
+ }
+
+ if (ex != EXT_FIRST_EXTENT(eh)) {
+ /* we correct tree if first leaf got modified only */
+ return 0;
+ }
+
+ /*
+ * TODO: we need correction if border is smaller than current one
+ */
+ k = depth - 1;
+ border = path[depth].p_ext->ee_block;
+ if ((err = ext4_ext_get_access(handle, inode, path + k)))
+ return err;
+ path[k].p_idx->ei_block = border;
+ if ((err = ext4_ext_dirty(handle, inode, path + k)))
+ return err;
+
+ while (k--) {
+ /* change all left-side indexes */
+ if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))
+ break;
+ if ((err = ext4_ext_get_access(handle, inode, path + k)))
+ break;
+ path[k].p_idx->ei_block = border;
+ if ((err = ext4_ext_dirty(handle, inode, path + k)))
+ break;
+ }
+
+ return err;
+}
+
+static int inline
+ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
+ struct ext4_extent *ex2)
+{
+ if (le32_to_cpu(ex1->ee_block) + le16_to_cpu(ex1->ee_len) !=
+ le32_to_cpu(ex2->ee_block))
+ return 0;
+
+ /*
+ * To allow future support for preallocated extents to be added
+ * as an RO_COMPAT feature, refuse to merge to extents if
+ * this can result in the top bit of ee_len being set.
+ */
+ if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN)
+ return 0;
+#ifdef AGRESSIVE_TEST
+ if (le16_to_cpu(ex1->ee_len) >= 4)
+ return 0;
+#endif
+
+ if (ext_pblock(ex1) + le16_to_cpu(ex1->ee_len) == ext_pblock(ex2))
+ return 1;
+ return 0;
+}
+
+/*
+ * ext4_ext_insert_extent:
+ * tries to merge requsted extent into the existing extent or
+ * inserts requested extent as new one into the tree,
+ * creating new leaf in the no-space case.
+ */
+int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path,
+ struct ext4_extent *newext)
+{
+ struct ext4_extent_header * eh;
+ struct ext4_extent *ex, *fex;
+ struct ext4_extent *nearex; /* nearest extent */
+ struct ext4_ext_path *npath = NULL;
+ int depth, len, err, next;
+
+ BUG_ON(newext->ee_len == 0);
+ depth = ext_depth(inode);
+ ex = path[depth].p_ext;
+ BUG_ON(path[depth].p_hdr == NULL);
+
+ /* try to insert block into found extent and return */
+ if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {
+ ext_debug("append %d block to %d:%d (from %llu)\n",
+ le16_to_cpu(newext->ee_len),
+ le32_to_cpu(ex->ee_block),
+ le16_to_cpu(ex->ee_len), ext_pblock(ex));
+ if ((err = ext4_ext_get_access(handle, inode, path + depth)))
+ return err;
+ ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len)
+ + le16_to_cpu(newext->ee_len));
+ eh = path[depth].p_hdr;
+ nearex = ex;
+ goto merge;
+ }
+
+repeat:
+ depth = ext_depth(inode);
+ eh = path[depth].p_hdr;
+ if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max))
+ goto has_space;
+
+ /* probably next leaf has space for us? */
+ fex = EXT_LAST_EXTENT(eh);
+ next = ext4_ext_next_leaf_block(inode, path);
+ if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)
+ && next != EXT_MAX_BLOCK) {
+ ext_debug("next leaf block - %d\n", next);
+ BUG_ON(npath != NULL);
+ npath = ext4_ext_find_extent(inode, next, NULL);
+ if (IS_ERR(npath))
+ return PTR_ERR(npath);
+ BUG_ON(npath->p_depth != path->p_depth);
+ eh = npath[depth].p_hdr;
+ if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) {
+ ext_debug("next leaf isnt full(%d)\n",
+ le16_to_cpu(eh->eh_entries));
+ path = npath;
+ goto repeat;
+ }
+ ext_debug("next leaf has no free space(%d,%d)\n",
+ le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));
+ }
+
+ /*
+ * There is no free space in the found leaf.
+ * We're gonna add a new leaf in the tree.
+ */
+ err = ext4_ext_create_new_leaf(handle, inode, path, newext);
+ if (err)
+ goto cleanup;
+ depth = ext_depth(inode);
+ eh = path[depth].p_hdr;
+
+has_space:
+ nearex = path[depth].p_ext;
+
+ if ((err = ext4_ext_get_access(handle, inode, path + depth)))
+ goto cleanup;
+
+ if (!nearex) {
+ /* there is no extent in this leaf, create first one */
+ ext_debug("first extent in the leaf: %d:%llu:%d\n",
+ le32_to_cpu(newext->ee_block),
+ ext_pblock(newext),
+ le16_to_cpu(newext->ee_len));
+ path[depth].p_ext = EXT_FIRST_EXTENT(eh);
+ } else if (le32_to_cpu(newext->ee_block)
+ > le32_to_cpu(nearex->ee_block)) {
+/* BUG_ON(newext->ee_block == nearex->ee_block); */
+ if (nearex != EXT_LAST_EXTENT(eh)) {
+ len = EXT_MAX_EXTENT(eh) - nearex;
+ len = (len - 1) * sizeof(struct ext4_extent);
+ len = len < 0 ? 0 : len;
+ ext_debug("insert %d:%llu:%d after: nearest 0x%p, "
+ "move %d from 0x%p to 0x%p\n",
+ le32_to_cpu(newext->ee_block),
+ ext_pblock(newext),
+ le16_to_cpu(newext->ee_len),
+ nearex, len, nearex + 1, nearex + 2);
+ memmove(nearex + 2, nearex + 1, len);
+ }
+ path[depth].p_ext = nearex + 1;
+ } else {
+ BUG_ON(newext->ee_block == nearex->ee_block);
+ len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent);
+ len = len < 0 ? 0 : len;
+ ext_debug("insert %d:%llu:%d before: nearest 0x%p, "
+ "move %d from 0x%p to 0x%p\n",
+ le32_to_cpu(newext->ee_block),
+ ext_pblock(newext),
+ le16_to_cpu(newext->ee_len),
+ nearex, len, nearex + 1, nearex + 2);
+ memmove(nearex + 1, nearex, len);
+ path[depth].p_ext = nearex;
+ }
+
+ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1);
+ nearex = path[depth].p_ext;
+ nearex->ee_block = newext->ee_block;
+ nearex->ee_start = newext->ee_start;
+ nearex->ee_start_hi = newext->ee_start_hi;
+ nearex->ee_len = newext->ee_len;
+
+merge:
+ /* try to merge extents to the right */
+ while (nearex < EXT_LAST_EXTENT(eh)) {
+ if (!ext4_can_extents_be_merged(inode, nearex, nearex + 1))
+ break;
+ /* merge with next extent! */
+ nearex->ee_len = cpu_to_le16(le16_to_cpu(nearex->ee_len)
+ + le16_to_cpu(nearex[1].ee_len));
+ if (nearex + 1 < EXT_LAST_EXTENT(eh)) {
+ len = (EXT_LAST_EXTENT(eh) - nearex - 1)
+ * sizeof(struct ext4_extent);
+ memmove(nearex + 1, nearex + 2, len);
+ }
+ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
+ BUG_ON(eh->eh_entries == 0);
+ }
+
+ /* try to merge extents to the left */
+
+ /* time to correct all indexes above */
+ err = ext4_ext_correct_indexes(handle, inode, path);
+ if (err)
+ goto cleanup;
+
+ err = ext4_ext_dirty(handle, inode, path + depth);
+
+cleanup:
+ if (npath) {
+ ext4_ext_drop_refs(npath);
+ kfree(npath);
+ }
+ ext4_ext_tree_changed(inode);
+ ext4_ext_invalidate_cache(inode);
+ return err;
+}
+
+int ext4_ext_walk_space(struct inode *inode, unsigned long block,
+ unsigned long num, ext_prepare_callback func,
+ void *cbdata)
+{
+ struct ext4_ext_path *path = NULL;
+ struct ext4_ext_cache cbex;
+ struct ext4_extent *ex;
+ unsigned long next, start = 0, end = 0;
+ unsigned long last = block + num;
+ int depth, exists, err = 0;
+
+ BUG_ON(func == NULL);
+ BUG_ON(inode == NULL);
+
+ while (block < last && block != EXT_MAX_BLOCK) {
+ num = last - block;
+ /* find extent for this block */
+ path = ext4_ext_find_extent(inode, block, path);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ path = NULL;
+ break;
+ }
+
+ depth = ext_depth(inode);
+ BUG_ON(path[depth].p_hdr == NULL);
+ ex = path[depth].p_ext;
+ next = ext4_ext_next_allocated_block(path);
+
+ exists = 0;
+ if (!ex) {
+ /* there is no extent yet, so try to allocate
+ * all requested space */
+ start = block;
+ end = block + num;
+ } else if (le32_to_cpu(ex->ee_block) > block) {
+ /* need to allocate space before found extent */
+ start = block;
+ end = le32_to_cpu(ex->ee_block);
+ if (block + num < end)
+ end = block + num;
+ } else if (block >=
+ le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len)) {
+ /* need to allocate space after found extent */
+ start = block;
+ end = block + num;
+ if (end >= next)
+ end = next;
+ } else if (block >= le32_to_cpu(ex->ee_block)) {
+ /*
+ * some part of requested space is covered
+ * by found extent
+ */
+ start = block;
+ end = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len);
+ if (block + num < end)
+ end = block + num;
+ exists = 1;
+ } else {
+ BUG();
+ }
+ BUG_ON(end <= start);
+
+ if (!exists) {
+ cbex.ec_block = start;
+ cbex.ec_len = end - start;
+ cbex.ec_start = 0;
+ cbex.ec_type = EXT4_EXT_CACHE_GAP;
+ } else {
+ cbex.ec_block = le32_to_cpu(ex->ee_block);
+ cbex.ec_len = le16_to_cpu(ex->ee_len);
+ cbex.ec_start = ext_pblock(ex);
+ cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
+ }
+
+ BUG_ON(cbex.ec_len == 0);
+ err = func(inode, path, &cbex, cbdata);
+ ext4_ext_drop_refs(path);
+
+ if (err < 0)
+ break;
+ if (err == EXT_REPEAT)
+ continue;
+ else if (err == EXT_BREAK) {
+ err = 0;
+ break;
+ }
+
+ if (ext_depth(inode) != depth) {
+ /* depth was changed. we have to realloc path */
+ kfree(path);
+ path = NULL;
+ }
+
+ block = cbex.ec_block + cbex.ec_len;
+ }
+
+ if (path) {
+ ext4_ext_drop_refs(path);
+ kfree(path);
+ }
+
+ return err;
+}
+
+static inline void
+ext4_ext_put_in_cache(struct inode *inode, __u32 block,
+ __u32 len, __u32 start, int type)
+{
+ struct ext4_ext_cache *cex;
+ BUG_ON(len == 0);
+ cex = &EXT4_I(inode)->i_cached_extent;
+ cex->ec_type = type;
+ cex->ec_block = block;
+ cex->ec_len = len;
+ cex->ec_start = start;
+}
+
+/*
+ * ext4_ext_put_gap_in_cache:
+ * calculate boundaries of the gap that the requested block fits into
+ * and cache this gap
+ */
+static inline void
+ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
+ unsigned long block)
+{
+ int depth = ext_depth(inode);
+ unsigned long lblock, len;
+ struct ext4_extent *ex;
+
+ ex = path[depth].p_ext;
+ if (ex == NULL) {
+ /* there is no extent yet, so gap is [0;-] */
+ lblock = 0;
+ len = EXT_MAX_BLOCK;
+ ext_debug("cache gap(whole file):");
+ } else if (block < le32_to_cpu(ex->ee_block)) {
+ lblock = block;
+ len = le32_to_cpu(ex->ee_block) - block;
+ ext_debug("cache gap(before): %lu [%lu:%lu]",
+ (unsigned long) block,
+ (unsigned long) le32_to_cpu(ex->ee_block),
+ (unsigned long) le16_to_cpu(ex->ee_len));
+ } else if (block >= le32_to_cpu(ex->ee_block)
+ + le16_to_cpu(ex->ee_len)) {
+ lblock = le32_to_cpu(ex->ee_block)
+ + le16_to_cpu(ex->ee_len);
+ len = ext4_ext_next_allocated_block(path);
+ ext_debug("cache gap(after): [%lu:%lu] %lu",
+ (unsigned long) le32_to_cpu(ex->ee_block),
+ (unsigned long) le16_to_cpu(ex->ee_len),
+ (unsigned long) block);
+ BUG_ON(len == lblock);
+ len = len - lblock;
+ } else {
+ lblock = len = 0;
+ BUG();
+ }
+
+ ext_debug(" -> %lu:%lu\n", (unsigned long) lblock, len);
+ ext4_ext_put_in_cache(inode, lblock, len, 0, EXT4_EXT_CACHE_GAP);
+}
+
+static inline int
+ext4_ext_in_cache(struct inode *inode, unsigned long block,
+ struct ext4_extent *ex)
+{
+ struct ext4_ext_cache *cex;
+
+ cex = &EXT4_I(inode)->i_cached_extent;
+
+ /* has cache valid data? */
+ if (cex->ec_type == EXT4_EXT_CACHE_NO)
+ return EXT4_EXT_CACHE_NO;
+
+ BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP &&
+ cex->ec_type != EXT4_EXT_CACHE_EXTENT);
+ if (block >= cex->ec_block && block < cex->ec_block + cex->ec_len) {
+ ex->ee_block = cpu_to_le32(cex->ec_block);
+ ext4_ext_store_pblock(ex, cex->ec_start);
+ ex->ee_len = cpu_to_le16(cex->ec_len);
+ ext_debug("%lu cached by %lu:%lu:%llu\n",
+ (unsigned long) block,
+ (unsigned long) cex->ec_block,
+ (unsigned long) cex->ec_len,
+ cex->ec_start);
+ return cex->ec_type;
+ }
+
+ /* not in cache */
+ return EXT4_EXT_CACHE_NO;
+}
+
+/*
+ * ext4_ext_rm_idx:
+ * removes index from the index block.
+ * It's used in truncate case only, thus all requests are for
+ * last index in the block only.
+ */
+int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path)
+{
+ struct buffer_head *bh;
+ int err;
+ ext4_fsblk_t leaf;
+
+ /* free index block */
+ path--;
+ leaf = idx_pblock(path->p_idx);
+ BUG_ON(path->p_hdr->eh_entries == 0);
+ if ((err = ext4_ext_get_access(handle, inode, path)))
+ return err;
+ path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1);
+ if ((err = ext4_ext_dirty(handle, inode, path)))
+ return err;
+ ext_debug("index is empty, remove it, free block %llu\n", leaf);
+ bh = sb_find_get_block(inode->i_sb, leaf);
+ ext4_forget(handle, 1, inode, bh, leaf);
+ ext4_free_blocks(handle, inode, leaf, 1);
+ return err;
+}
+
+/*
+ * ext4_ext_calc_credits_for_insert:
+ * This routine returns max. credits that the extent tree can consume.
+ * It should be OK for low-performance paths like ->writepage()
+ * To allow many writing processes to fit into a single transaction,
+ * the caller should calculate credits under truncate_mutex and
+ * pass the actual path.
+ */
+int inline ext4_ext_calc_credits_for_insert(struct inode *inode,
+ struct ext4_ext_path *path)
+{
+ int depth, needed;
+
+ if (path) {
+ /* probably there is space in leaf? */
+ depth = ext_depth(inode);
+ if (le16_to_cpu(path[depth].p_hdr->eh_entries)
+ < le16_to_cpu(path[depth].p_hdr->eh_max))
+ return 1;
+ }
+
+ /*
+ * given 32-bit logical block (4294967296 blocks), max. tree
+ * can be 4 levels in depth -- 4 * 340^4 == 53453440000.
+ * Let's also add one more level for imbalance.
+ */
+ depth = 5;
+
+ /* allocation of new data block(s) */
+ needed = 2;
+
+ /*
+ * tree can be full, so it would need to grow in depth:
+ * allocation + old root + new root
+ */
+ needed += 2 + 1 + 1;
+
+ /*
+ * Index split can happen, we would need:
+ * allocate intermediate indexes (bitmap + group)
+ * + change two blocks at each level, but root (already included)
+ */
+ needed = (depth * 2) + (depth * 2);
+
+ /* any allocation modifies superblock */
+ needed += 1;
+
+ return needed;
+}
+
+static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
+ struct ext4_extent *ex,
+ unsigned long from, unsigned long to)
+{
+ struct buffer_head *bh;
+ int i;
+
+#ifdef EXTENTS_STATS
+ {
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ unsigned short ee_len = le16_to_cpu(ex->ee_len);
+ spin_lock(&sbi->s_ext_stats_lock);
+ sbi->s_ext_blocks += ee_len;
+ sbi->s_ext_extents++;
+ if (ee_len < sbi->s_ext_min)
+ sbi->s_ext_min = ee_len;
+ if (ee_len > sbi->s_ext_max)
+ sbi->s_ext_max = ee_len;
+ if (ext_depth(inode) > sbi->s_depth_max)
+ sbi->s_depth_max = ext_depth(inode);
+ spin_unlock(&sbi->s_ext_stats_lock);
+ }
+#endif
+ if (from >= le32_to_cpu(ex->ee_block)
+ && to == le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+ /* tail removal */
+ unsigned long num;
+ ext4_fsblk_t start;
+ num = le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - from;
+ start = ext_pblock(ex) + le16_to_cpu(ex->ee_len) - num;
+ ext_debug("free last %lu blocks starting %llu\n", num, start);
+ for (i = 0; i < num; i++) {
+ bh = sb_find_get_block(inode->i_sb, start + i);
+ ext4_forget(handle, 0, inode, bh, start + i);
+ }
+ ext4_free_blocks(handle, inode, start, num);
+ } else if (from == le32_to_cpu(ex->ee_block)
+ && to <= le32_to_cpu(ex->ee_block) + le16_to_cpu(ex->ee_len) - 1) {
+ printk("strange request: removal %lu-%lu from %u:%u\n",
+ from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+ } else {
+ printk("strange request: removal(2) %lu-%lu from %u:%u\n",
+ from, to, le32_to_cpu(ex->ee_block), le16_to_cpu(ex->ee_len));
+ }
+ return 0;
+}
+
+static int
+ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
+ struct ext4_ext_path *path, unsigned long start)
+{
+ int err = 0, correct_index = 0;
+ int depth = ext_depth(inode), credits;
+ struct ext4_extent_header *eh;
+ unsigned a, b, block, num;
+ unsigned long ex_ee_block;
+ unsigned short ex_ee_len;
+ struct ext4_extent *ex;
+
+ ext_debug("truncate since %lu in leaf\n", start);
+ if (!path[depth].p_hdr)
+ path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
+ eh = path[depth].p_hdr;
+ BUG_ON(eh == NULL);
+ BUG_ON(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max));
+ BUG_ON(eh->eh_magic != EXT4_EXT_MAGIC);
+
+ /* find where to start removing */
+ ex = EXT_LAST_EXTENT(eh);
+
+ ex_ee_block = le32_to_cpu(ex->ee_block);
+ ex_ee_len = le16_to_cpu(ex->ee_len);
+
+ while (ex >= EXT_FIRST_EXTENT(eh) &&
+ ex_ee_block + ex_ee_len > start) {
+ ext_debug("remove ext %lu:%u\n", ex_ee_block, ex_ee_len);
+ path[depth].p_ext = ex;
+
+ a = ex_ee_block > start ? ex_ee_block : start;
+ b = ex_ee_block + ex_ee_len - 1 < EXT_MAX_BLOCK ?
+ ex_ee_block + ex_ee_len - 1 : EXT_MAX_BLOCK;
+
+ ext_debug(" border %u:%u\n", a, b);
+
+ if (a != ex_ee_block && b != ex_ee_block + ex_ee_len - 1) {
+ block = 0;
+ num = 0;
+ BUG();
+ } else if (a != ex_ee_block) {
+ /* remove tail of the extent */
+ block = ex_ee_block;
+ num = a - block;
+ } else if (b != ex_ee_block + ex_ee_len - 1) {
+ /* remove head of the extent */
+ block = a;
+ num = b - a;
+ /* there is no "make a hole" API yet */
+ BUG();
+ } else {
+ /* remove whole extent: excellent! */
+ block = ex_ee_block;
+ num = 0;
+ BUG_ON(a != ex_ee_block);
+ BUG_ON(b != ex_ee_block + ex_ee_len - 1);
+ }
+
+ /* at present, extent can't cross block group: */
+ /* leaf + bitmap + group desc + sb + inode */
+ credits = 5;
+ if (ex == EXT_FIRST_EXTENT(eh)) {
+ correct_index = 1;
+ credits += (ext_depth(inode)) + 1;
+ }
+#ifdef CONFIG_QUOTA
+ credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
+#endif
+
+ handle = ext4_ext_journal_restart(handle, credits);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ goto out;
+ }
+
+ err = ext4_ext_get_access(handle, inode, path + depth);
+ if (err)
+ goto out;
+
+ err = ext4_remove_blocks(handle, inode, ex, a, b);
+ if (err)
+ goto out;
+
+ if (num == 0) {
+ /* this extent is removed; mark slot entirely unused */
+ ext4_ext_store_pblock(ex, 0);
+ eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)-1);
+ }
+
+ ex->ee_block = cpu_to_le32(block);
+ ex->ee_len = cpu_to_le16(num);
+
+ err = ext4_ext_dirty(handle, inode, path + depth);
+ if (err)
+ goto out;
+
+ ext_debug("new extent: %u:%u:%llu\n", block, num,
+ ext_pblock(ex));
+ ex--;
+ ex_ee_block = le32_to_cpu(ex->ee_block);
+ ex_ee_len = le16_to_cpu(ex->ee_len);
+ }
+
+ if (correct_index && eh->eh_entries)
+ err = ext4_ext_correct_indexes(handle, inode, path);
+
+ /* if this leaf is free, then we should
+ * remove it from index block above */
+ if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL)
+ err = ext4_ext_rm_idx(handle, inode, path + depth);
+
+out:
+ return err;
+}
+
+/*
+ * ext4_ext_more_to_rm:
+ * returns 1 if current index has to be freed (even partial)
+ */
+static int inline
+ext4_ext_more_to_rm(struct ext4_ext_path *path)
+{
+ BUG_ON(path->p_idx == NULL);
+
+ if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr))
+ return 0;
+
+ /*
+ * if truncate on deeper level happened, it wasn't partial,
+ * so we have to consider current index for truncation
+ */
+ if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block)
+ return 0;
+ return 1;
+}
+
+int ext4_ext_remove_space(struct inode *inode, unsigned long start)
+{
+ struct super_block *sb = inode->i_sb;
+ int depth = ext_depth(inode);
+ struct ext4_ext_path *path;
+ handle_t *handle;
+ int i = 0, err = 0;
+
+ ext_debug("truncate since %lu\n", start);
+
+ /* probably first extent we're gonna free will be last in block */
+ handle = ext4_journal_start(inode, depth + 1);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ ext4_ext_invalidate_cache(inode);
+
+ /*
+ * We start scanning from right side, freeing all the blocks
+ * after i_size and walking into the tree depth-wise.
+ */
+ path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
+ if (path == NULL) {
+ ext4_journal_stop(handle);
+ return -ENOMEM;
+ }
+ memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
+ path[0].p_hdr = ext_inode_hdr(inode);
+ if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) {
+ err = -EIO;
+ goto out;
+ }
+ path[0].p_depth = depth;
+
+ while (i >= 0 && err == 0) {
+ if (i == depth) {
+ /* this is leaf block */
+ err = ext4_ext_rm_leaf(handle, inode, path, start);
+ /* root level has p_bh == NULL, brelse() eats this */
+ brelse(path[i].p_bh);
+ path[i].p_bh = NULL;
+ i--;
+ continue;
+ }
+
+ /* this is index block */
+ if (!path[i].p_hdr) {
+ ext_debug("initialize header\n");
+ path[i].p_hdr = ext_block_hdr(path[i].p_bh);
+ if (ext4_ext_check_header(__FUNCTION__, inode,
+ path[i].p_hdr)) {
+ err = -EIO;
+ goto out;
+ }
+ }
+
+ BUG_ON(le16_to_cpu(path[i].p_hdr->eh_entries)
+ > le16_to_cpu(path[i].p_hdr->eh_max));
+ BUG_ON(path[i].p_hdr->eh_magic != EXT4_EXT_MAGIC);
+
+ if (!path[i].p_idx) {
+ /* this level hasn't been touched yet */
+ path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr);
+ path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1;
+ ext_debug("init index ptr: hdr 0x%p, num %d\n",
+ path[i].p_hdr,
+ le16_to_cpu(path[i].p_hdr->eh_entries));
+ } else {
+ /* we were already here, see at next index */
+ path[i].p_idx--;
+ }
+
+ ext_debug("level %d - index, first 0x%p, cur 0x%p\n",
+ i, EXT_FIRST_INDEX(path[i].p_hdr),
+ path[i].p_idx);
+ if (ext4_ext_more_to_rm(path + i)) {
+ /* go to the next level */
+ ext_debug("move to level %d (block %llu)\n",
+ i + 1, idx_pblock(path[i].p_idx));
+ memset(path + i + 1, 0, sizeof(*path));
+ path[i+1].p_bh =
+ sb_bread(sb, idx_pblock(path[i].p_idx));
+ if (!path[i+1].p_bh) {
+ /* should we reset i_size? */
+ err = -EIO;
+ break;
+ }
+
+ /* save actual number of indexes since this
+ * number is changed at the next iteration */
+ path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries);
+ i++;
+ } else {
+ /* we finished processing this index, go up */
+ if (path[i].p_hdr->eh_entries == 0 && i > 0) {
+ /* index is empty, remove it;
+ * handle must be already prepared by the
+ * truncatei_leaf() */
+ err = ext4_ext_rm_idx(handle, inode, path + i);
+ }
+ /* root level has p_bh == NULL, brelse() eats this */
+ brelse(path[i].p_bh);
+ path[i].p_bh = NULL;
+ i--;
+ ext_debug("return to level %d\n", i);
+ }
+ }
+
+ /* TODO: flexible tree reduction should be here */
+ if (path->p_hdr->eh_entries == 0) {
+ /*
+ * truncate to zero freed all the tree,
+ * so we need to correct eh_depth
+ */
+ err = ext4_ext_get_access(handle, inode, path);
+ if (err == 0) {
+ ext_inode_hdr(inode)->eh_depth = 0;
+ ext_inode_hdr(inode)->eh_max =
+ cpu_to_le16(ext4_ext_space_root(inode));
+ err = ext4_ext_dirty(handle, inode, path);
+ }
+ }
+out:
+ ext4_ext_tree_changed(inode);
+ ext4_ext_drop_refs(path);
+ kfree(path);
+ ext4_journal_stop(handle);
+
+ return err;
+}
+
+/*
+ * called at mount time
+ */
+void ext4_ext_init(struct super_block *sb)
+{
+ /*
+ * possible initialization would be here
+ */
+
+ if (test_opt(sb, EXTENTS)) {
+ printk("EXT4-fs: file extents enabled");
+#ifdef AGRESSIVE_TEST
+ printk(", agressive tests");
+#endif
+#ifdef CHECK_BINSEARCH
+ printk(", check binsearch");
+#endif
+#ifdef EXTENTS_STATS
+ printk(", stats");
+#endif
+ printk("\n");
+#ifdef EXTENTS_STATS
+ spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock);
+ EXT4_SB(sb)->s_ext_min = 1 << 30;
+ EXT4_SB(sb)->s_ext_max = 0;
+#endif
+ }
+}
+
+/*
+ * called at umount time
+ */
+void ext4_ext_release(struct super_block *sb)
+{
+ if (!test_opt(sb, EXTENTS))
+ return;
+
+#ifdef EXTENTS_STATS
+ if (EXT4_SB(sb)->s_ext_blocks && EXT4_SB(sb)->s_ext_extents) {
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ printk(KERN_ERR "EXT4-fs: %lu blocks in %lu extents (%lu ave)\n",
+ sbi->s_ext_blocks, sbi->s_ext_extents,
+ sbi->s_ext_blocks / sbi->s_ext_extents);
+ printk(KERN_ERR "EXT4-fs: extents: %lu min, %lu max, max depth %lu\n",
+ sbi->s_ext_min, sbi->s_ext_max, sbi->s_depth_max);
+ }
+#endif
+}
+
+int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
+ ext4_fsblk_t iblock,
+ unsigned long max_blocks, struct buffer_head *bh_result,
+ int create, int extend_disksize)
+{
+ struct ext4_ext_path *path = NULL;
+ struct ext4_extent newex, *ex;
+ ext4_fsblk_t goal, newblock;
+ int err = 0, depth;
+ unsigned long allocated = 0;
+
+ __clear_bit(BH_New, &bh_result->b_state);
+ ext_debug("blocks %d/%lu requested for inode %u\n", (int) iblock,
+ max_blocks, (unsigned) inode->i_ino);
+ mutex_lock(&EXT4_I(inode)->truncate_mutex);
+
+ /* check in cache */
+ if ((goal = ext4_ext_in_cache(inode, iblock, &newex))) {
+ if (goal == EXT4_EXT_CACHE_GAP) {
+ if (!create) {
+ /* block isn't allocated yet and
+ * user doesn't want to allocate it */
+ goto out2;
+ }
+ /* we should allocate requested block */
+ } else if (goal == EXT4_EXT_CACHE_EXTENT) {
+ /* block is already allocated */
+ newblock = iblock
+ - le32_to_cpu(newex.ee_block)
+ + ext_pblock(&newex);
+ /* number of remaining blocks in the extent */
+ allocated = le16_to_cpu(newex.ee_len) -
+ (iblock - le32_to_cpu(newex.ee_block));
+ goto out;
+ } else {
+ BUG();
+ }
+ }
+
+ /* find extent for this block */
+ path = ext4_ext_find_extent(inode, iblock, NULL);
+ if (IS_ERR(path)) {
+ err = PTR_ERR(path);
+ path = NULL;
+ goto out2;
+ }
+
+ depth = ext_depth(inode);
+
+ /*
+ * consistent leaf must not be empty;
+ * this situation is possible, though, _during_ tree modification;
+ * this is why assert can't be put in ext4_ext_find_extent()
+ */
+ BUG_ON(path[depth].p_ext == NULL && depth != 0);
+
+ if ((ex = path[depth].p_ext)) {
+ unsigned long ee_block = le32_to_cpu(ex->ee_block);
+ ext4_fsblk_t ee_start = ext_pblock(ex);
+ unsigned short ee_len = le16_to_cpu(ex->ee_len);
+
+ /*
+ * Allow future support for preallocated extents to be added
+ * as an RO_COMPAT feature:
+ * Uninitialized extents are treated as holes, except that
+ * we avoid (fail) allocating new blocks during a write.
+ */
+ if (ee_len > EXT_MAX_LEN)
+ goto out2;
+ /* if found extent covers block, simply return it */
+ if (iblock >= ee_block && iblock < ee_block + ee_len) {
+ newblock = iblock - ee_block + ee_start;
+ /* number of remaining blocks in the extent */
+ allocated = ee_len - (iblock - ee_block);
+ ext_debug("%d fit into %lu:%d -> %llu\n", (int) iblock,
+ ee_block, ee_len, newblock);
+ ext4_ext_put_in_cache(inode, ee_block, ee_len,
+ ee_start, EXT4_EXT_CACHE_EXTENT);
+ goto out;
+ }
+ }
+
+ /*
+ * requested block isn't allocated yet;
+ * we couldn't try to create block if create flag is zero
+ */
+ if (!create) {
+ /* put just found gap into cache to speed up
+ * subsequent requests */
+ ext4_ext_put_gap_in_cache(inode, path, iblock);
+ goto out2;
+ }
+ /*
+ * Okay, we need to do block allocation. Lazily initialize the block
+ * allocation info here if necessary.
+ */
+ if (S_ISREG(inode->i_mode) && (!EXT4_I(inode)->i_block_alloc_info))
+ ext4_init_block_alloc_info(inode);
+
+ /* allocate new block */
+ goal = ext4_ext_find_goal(inode, path, iblock);
+ allocated = max_blocks;
+ newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err);
+ if (!newblock)
+ goto out2;
+ ext_debug("allocate new block: goal %llu, found %llu/%lu\n",
+ goal, newblock, allocated);
+
+ /* try to insert new extent into found leaf and return */
+ newex.ee_block = cpu_to_le32(iblock);
+ ext4_ext_store_pblock(&newex, newblock);
+ newex.ee_len = cpu_to_le16(allocated);
+ err = ext4_ext_insert_extent(handle, inode, path, &newex);
+ if (err)
+ goto out2;
+
+ if (extend_disksize && inode->i_size > EXT4_I(inode)->i_disksize)
+ EXT4_I(inode)->i_disksize = inode->i_size;
+
+ /* previous routine could use block we allocated */
+ newblock = ext_pblock(&newex);
+ __set_bit(BH_New, &bh_result->b_state);
+
+ ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
+ EXT4_EXT_CACHE_EXTENT);
+out:
+ if (allocated > max_blocks)
+ allocated = max_blocks;
+ ext4_ext_show_leaf(inode, path);
+ __set_bit(BH_Mapped, &bh_result->b_state);
+ bh_result->b_bdev = inode->i_sb->s_bdev;
+ bh_result->b_blocknr = newblock;
+out2:
+ if (path) {
+ ext4_ext_drop_refs(path);
+ kfree(path);
+ }
+ mutex_unlock(&EXT4_I(inode)->truncate_mutex);
+
+ return err ? err : allocated;
+}
+
+void ext4_ext_truncate(struct inode * inode, struct page *page)
+{
+ struct address_space *mapping = inode->i_mapping;
+ struct super_block *sb = inode->i_sb;
+ unsigned long last_block;
+ handle_t *handle;
+ int err = 0;
+
+ /*
+ * probably first extent we're gonna free will be last in block
+ */
+ err = ext4_writepage_trans_blocks(inode) + 3;
+ handle = ext4_journal_start(inode, err);
+ if (IS_ERR(handle)) {
+ if (page) {
+ clear_highpage(page);
+ flush_dcache_page(page);
+ unlock_page(page);
+ page_cache_release(page);
+ }
+ return;
+ }
+
+ if (page)
+ ext4_block_truncate_page(handle, page, mapping, inode->i_size);
+
+ mutex_lock(&EXT4_I(inode)->truncate_mutex);
+ ext4_ext_invalidate_cache(inode);
+
+ /*
+ * TODO: optimization is possible here.
+ * Probably we need not scan at all,
+ * because page truncation is enough.
+ */
+ if (ext4_orphan_add(handle, inode))
+ goto out_stop;
+
+ /* we have to know where to truncate from in crash case */
+ EXT4_I(inode)->i_disksize = inode->i_size;
+ ext4_mark_inode_dirty(handle, inode);
+
+ last_block = (inode->i_size + sb->s_blocksize - 1)
+ >> EXT4_BLOCK_SIZE_BITS(sb);
+ err = ext4_ext_remove_space(inode, last_block);
+
+ /* In a multi-transaction truncate, we only make the final
+ * transaction synchronous. */
+ if (IS_SYNC(inode))
+ handle->h_sync = 1;
+
+out_stop:
+ /*
+ * If this was a simple ftruncate() and the file will remain alive,
+ * then we need to clear up the orphan record which we created above.
+ * However, if this was a real unlink then we were called by
+ * ext4_delete_inode(), and we allow that function to clean up the
+ * orphan info for us.
+ */
+ if (inode->i_nlink)
+ ext4_orphan_del(handle, inode);
+
+ mutex_unlock(&EXT4_I(inode)->truncate_mutex);
+ ext4_journal_stop(handle);
+}
+
+/*
+ * ext4_ext_writepage_trans_blocks:
+ * calculate max number of blocks we could modify
+ * in order to allocate new block for an inode
+ */
+int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
+{
+ int needed;
+
+ needed = ext4_ext_calc_credits_for_insert(inode, NULL);
+
+ /* caller wants to allocate num blocks, but note it includes sb */
+ needed = needed * num - (num - 1);
+
+#ifdef CONFIG_QUOTA
+ needed += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
+#endif
+
+ return needed;
+}
+
+EXPORT_SYMBOL(ext4_mark_inode_dirty);
+EXPORT_SYMBOL(ext4_ext_invalidate_cache);
+EXPORT_SYMBOL(ext4_ext_insert_extent);
+EXPORT_SYMBOL(ext4_ext_walk_space);
+EXPORT_SYMBOL(ext4_ext_find_goal);
+EXPORT_SYMBOL(ext4_ext_calc_credits_for_insert);
+
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
new file mode 100644
index 000000000000..0b622c0624b7
--- /dev/null
+++ b/fs/ext4/file.c
@@ -0,0 +1,139 @@
+/*
+ * linux/fs/ext4/file.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/file.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext4 fs regular file handling primitives
+ *
+ * 64-bit file support on 64-bit platforms by Jakub Jelinek
+ * (jj@sunsite.ms.mff.cuni.cz)
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/ext4_jbd2.h>
+#include "xattr.h"
+#include "acl.h"
+
+/*
+ * Called when an inode is released. Note that this is different
+ * from ext4_file_open: open gets called at every open, but release
+ * gets called only when /all/ the files are closed.
+ */
+static int ext4_release_file (struct inode * inode, struct file * filp)
+{
+ /* if we are the last writer on the inode, drop the block reservation */
+ if ((filp->f_mode & FMODE_WRITE) &&
+ (atomic_read(&inode->i_writecount) == 1))
+ {
+ mutex_lock(&EXT4_I(inode)->truncate_mutex);
+ ext4_discard_reservation(inode);
+ mutex_unlock(&EXT4_I(inode)->truncate_mutex);
+ }
+ if (is_dx(inode) && filp->private_data)
+ ext4_htree_free_dir_info(filp->private_data);
+
+ return 0;
+}
+
+static ssize_t
+ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
+{
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_dentry->d_inode;
+ ssize_t ret;
+ int err;
+
+ ret = generic_file_aio_write(iocb, iov, nr_segs, pos);
+
+ /*
+ * Skip flushing if there was an error, or if nothing was written.
+ */
+ if (ret <= 0)
+ return ret;
+
+ /*
+ * If the inode is IS_SYNC, or is O_SYNC and we are doing data
+ * journalling then we need to make sure that we force the transaction
+ * to disk to keep all metadata uptodate synchronously.
+ */
+ if (file->f_flags & O_SYNC) {
+ /*
+ * If we are non-data-journaled, then the dirty data has
+ * already been flushed to backing store by generic_osync_inode,
+ * and the inode has been flushed too if there have been any
+ * modifications other than mere timestamp updates.
+ *
+ * Open question --- do we care about flushing timestamps too
+ * if the inode is IS_SYNC?
+ */
+ if (!ext4_should_journal_data(inode))
+ return ret;
+
+ goto force_commit;
+ }
+
+ /*
+ * So we know that there has been no forced data flush. If the inode
+ * is marked IS_SYNC, we need to force one ourselves.
+ */
+ if (!IS_SYNC(inode))
+ return ret;
+
+ /*
+ * Open question #2 --- should we force data to disk here too? If we
+ * don't, the only impact is that data=writeback filesystems won't
+ * flush data to disk automatically on IS_SYNC, only metadata (but
+ * historically, that is what ext2 has done.)
+ */
+
+force_commit:
+ err = ext4_force_commit(inode->i_sb);
+ if (err)
+ return err;
+ return ret;
+}
+
+const struct file_operations ext4_file_operations = {
+ .llseek = generic_file_llseek,
+ .read = do_sync_read,
+ .write = do_sync_write,
+ .aio_read = generic_file_aio_read,
+ .aio_write = ext4_file_write,
+ .ioctl = ext4_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ext4_compat_ioctl,
+#endif
+ .mmap = generic_file_mmap,
+ .open = generic_file_open,
+ .release = ext4_release_file,
+ .fsync = ext4_sync_file,
+ .sendfile = generic_file_sendfile,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+};
+
+struct inode_operations ext4_file_inode_operations = {
+ .truncate = ext4_truncate,
+ .setattr = ext4_setattr,
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ext4_listxattr,
+ .removexattr = generic_removexattr,
+#endif
+ .permission = ext4_permission,
+};
+
diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
new file mode 100644
index 000000000000..2a167d7131fa
--- /dev/null
+++ b/fs/ext4/fsync.c
@@ -0,0 +1,88 @@
+/*
+ * linux/fs/ext4/fsync.c
+ *
+ * Copyright (C) 1993 Stephen Tweedie (sct@redhat.com)
+ * from
+ * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ * from
+ * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext4fs fsync primitive
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ *
+ * Removed unnecessary code duplication for little endian machines
+ * and excessive __inline__s.
+ * Andi Kleen, 1997
+ *
+ * Major simplications and cleanup - we only need to do the metadata, because
+ * we can depend on generic_block_fdatasync() to sync the data blocks.
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/writeback.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/ext4_jbd2.h>
+
+/*
+ * akpm: A new design for ext4_sync_file().
+ *
+ * This is only called from sys_fsync(), sys_fdatasync() and sys_msync().
+ * There cannot be a transaction open by this task.
+ * Another task could have dirtied this inode. Its data can be in any
+ * state in the journalling system.
+ *
+ * What we do is just kick off a commit and wait on it. This will snapshot the
+ * inode to disk.
+ */
+
+int ext4_sync_file(struct file * file, struct dentry *dentry, int datasync)
+{
+ struct inode *inode = dentry->d_inode;
+ int ret = 0;
+
+ J_ASSERT(ext4_journal_current_handle() == 0);
+
+ /*
+ * data=writeback:
+ * The caller's filemap_fdatawrite()/wait will sync the data.
+ * sync_inode() will sync the metadata
+ *
+ * data=ordered:
+ * The caller's filemap_fdatawrite() will write the data and
+ * sync_inode() will write the inode if it is dirty. Then the caller's
+ * filemap_fdatawait() will wait on the pages.
+ *
+ * data=journal:
+ * filemap_fdatawrite won't do anything (the buffers are clean).
+ * ext4_force_commit will write the file data into the journal and
+ * will wait on that.
+ * filemap_fdatawait() will encounter a ton of newly-dirtied pages
+ * (they were dirtied by commit). But that's OK - the blocks are
+ * safe in-journal, which is all fsync() needs to ensure.
+ */
+ if (ext4_should_journal_data(inode)) {
+ ret = ext4_force_commit(inode->i_sb);
+ goto out;
+ }
+
+ /*
+ * The VFS has written the file data. If the inode is unaltered
+ * then we need not start a commit.
+ */
+ if (inode->i_state & (I_DIRTY_SYNC|I_DIRTY_DATASYNC)) {
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_ALL,
+ .nr_to_write = 0, /* sys_fsync did this */
+ };
+ ret = sync_inode(inode, &wbc);
+ }
+out:
+ return ret;
+}
diff --git a/fs/ext4/hash.c b/fs/ext4/hash.c
new file mode 100644
index 000000000000..a67966385e06
--- /dev/null
+++ b/fs/ext4/hash.c
@@ -0,0 +1,152 @@
+/*
+ * linux/fs/ext4/hash.c
+ *
+ * Copyright (C) 2002 by Theodore Ts'o
+ *
+ * This file is released under the GPL v2.
+ *
+ * This file may be redistributed under the terms of the GNU Public
+ * License.
+ */
+
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/sched.h>
+#include <linux/ext4_fs.h>
+#include <linux/cryptohash.h>
+
+#define DELTA 0x9E3779B9
+
+static void TEA_transform(__u32 buf[4], __u32 const in[])
+{
+ __u32 sum = 0;
+ __u32 b0 = buf[0], b1 = buf[1];
+ __u32 a = in[0], b = in[1], c = in[2], d = in[3];
+ int n = 16;
+
+ do {
+ sum += DELTA;
+ b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b);
+ b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d);
+ } while(--n);
+
+ buf[0] += b0;
+ buf[1] += b1;
+}
+
+
+/* The old legacy hash */
+static __u32 dx_hack_hash (const char *name, int len)
+{
+ __u32 hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9;
+ while (len--) {
+ __u32 hash = hash1 + (hash0 ^ (*name++ * 7152373));
+
+ if (hash & 0x80000000) hash -= 0x7fffffff;
+ hash1 = hash0;
+ hash0 = hash;
+ }
+ return (hash0 << 1);
+}
+
+static void str2hashbuf(const char *msg, int len, __u32 *buf, int num)
+{
+ __u32 pad, val;
+ int i;
+
+ pad = (__u32)len | ((__u32)len << 8);
+ pad |= pad << 16;
+
+ val = pad;
+ if (len > num*4)
+ len = num * 4;
+ for (i=0; i < len; i++) {
+ if ((i % 4) == 0)
+ val = pad;
+ val = msg[i] + (val << 8);
+ if ((i % 4) == 3) {
+ *buf++ = val;
+ val = pad;
+ num--;
+ }
+ }
+ if (--num >= 0)
+ *buf++ = val;
+ while (--num >= 0)
+ *buf++ = pad;
+}
+
+/*
+ * Returns the hash of a filename. If len is 0 and name is NULL, then
+ * this function can be used to test whether or not a hash version is
+ * supported.
+ *
+ * The seed is an 4 longword (32 bits) "secret" which can be used to
+ * uniquify a hash. If the seed is all zero's, then some default seed
+ * may be used.
+ *
+ * A particular hash version specifies whether or not the seed is
+ * represented, and whether or not the returned hash is 32 bits or 64
+ * bits. 32 bit hashes will return 0 for the minor hash.
+ */
+int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo)
+{
+ __u32 hash;
+ __u32 minor_hash = 0;
+ const char *p;
+ int i;
+ __u32 in[8], buf[4];
+
+ /* Initialize the default seed for the hash checksum functions */
+ buf[0] = 0x67452301;
+ buf[1] = 0xefcdab89;
+ buf[2] = 0x98badcfe;
+ buf[3] = 0x10325476;
+
+ /* Check to see if the seed is all zero's */
+ if (hinfo->seed) {
+ for (i=0; i < 4; i++) {
+ if (hinfo->seed[i])
+ break;
+ }
+ if (i < 4)
+ memcpy(buf, hinfo->seed, sizeof(buf));
+ }
+
+ switch (hinfo->hash_version) {
+ case DX_HASH_LEGACY:
+ hash = dx_hack_hash(name, len);
+ break;
+ case DX_HASH_HALF_MD4:
+ p = name;
+ while (len > 0) {
+ str2hashbuf(p, len, in, 8);
+ half_md4_transform(buf, in);
+ len -= 32;
+ p += 32;
+ }
+ minor_hash = buf[2];
+ hash = buf[1];
+ break;
+ case DX_HASH_TEA:
+ p = name;
+ while (len > 0) {
+ str2hashbuf(p, len, in, 4);
+ TEA_transform(buf, in);
+ len -= 16;
+ p += 16;
+ }
+ hash = buf[0];
+ minor_hash = buf[1];
+ break;
+ default:
+ hinfo->hash = 0;
+ return -1;
+ }
+ hash = hash & ~1;
+ if (hash == (EXT4_HTREE_EOF << 1))
+ hash = (EXT4_HTREE_EOF-1) << 1;
+ hinfo->hash = hash;
+ hinfo->minor_hash = minor_hash;
+ return 0;
+}
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
new file mode 100644
index 000000000000..c88b439ba5cd
--- /dev/null
+++ b/fs/ext4/ialloc.c
@@ -0,0 +1,772 @@
+/*
+ * linux/fs/ext4/ialloc.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * BSD ufs-inspired inode and directory allocation by
+ * Stephen Tweedie (sct@redhat.com), 1993
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/quotaops.h>
+#include <linux/buffer_head.h>
+#include <linux/random.h>
+#include <linux/bitops.h>
+#include <linux/blkdev.h>
+#include <asm/byteorder.h>
+
+#include "xattr.h"
+#include "acl.h"
+
+/*
+ * ialloc.c contains the inodes allocation and deallocation routines
+ */
+
+/*
+ * The free inodes are managed by bitmaps. A file system contains several
+ * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
+ * block for inodes, N blocks for the inode table and data blocks.
+ *
+ * The file system contains group descriptors which are located after the
+ * super block. Each descriptor contains the number of the bitmap block and
+ * the free blocks count in the block.
+ */
+
+
+/*
+ * Read the inode allocation bitmap for a given block_group, reading
+ * into the specified slot in the superblock's bitmap cache.
+ *
+ * Return buffer_head of bitmap on success or NULL.
+ */
+static struct buffer_head *
+read_inode_bitmap(struct super_block * sb, unsigned long block_group)
+{
+ struct ext4_group_desc *desc;
+ struct buffer_head *bh = NULL;
+
+ desc = ext4_get_group_desc(sb, block_group, NULL);
+ if (!desc)
+ goto error_out;
+
+ bh = sb_bread(sb, ext4_inode_bitmap(sb, desc));
+ if (!bh)
+ ext4_error(sb, "read_inode_bitmap",
+ "Cannot read inode bitmap - "
+ "block_group = %lu, inode_bitmap = %llu",
+ block_group, ext4_inode_bitmap(sb, desc));
+error_out:
+ return bh;
+}
+
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ *
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
+ */
+void ext4_free_inode (handle_t *handle, struct inode * inode)
+{
+ struct super_block * sb = inode->i_sb;
+ int is_directory;
+ unsigned long ino;
+ struct buffer_head *bitmap_bh = NULL;
+ struct buffer_head *bh2;
+ unsigned long block_group;
+ unsigned long bit;
+ struct ext4_group_desc * gdp;
+ struct ext4_super_block * es;
+ struct ext4_sb_info *sbi;
+ int fatal = 0, err;
+
+ if (atomic_read(&inode->i_count) > 1) {
+ printk ("ext4_free_inode: inode has count=%d\n",
+ atomic_read(&inode->i_count));
+ return;
+ }
+ if (inode->i_nlink) {
+ printk ("ext4_free_inode: inode has nlink=%d\n",
+ inode->i_nlink);
+ return;
+ }
+ if (!sb) {
+ printk("ext4_free_inode: inode on nonexistent device\n");
+ return;
+ }
+ sbi = EXT4_SB(sb);
+
+ ino = inode->i_ino;
+ ext4_debug ("freeing inode %lu\n", ino);
+
+ /*
+ * Note: we must free any quota before locking the superblock,
+ * as writing the quota to disk may need the lock as well.
+ */
+ DQUOT_INIT(inode);
+ ext4_xattr_delete_inode(handle, inode);
+ DQUOT_FREE_INODE(inode);
+ DQUOT_DROP(inode);
+
+ is_directory = S_ISDIR(inode->i_mode);
+
+ /* Do this BEFORE marking the inode not in use or returning an error */
+ clear_inode (inode);
+
+ es = EXT4_SB(sb)->s_es;
+ if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
+ ext4_error (sb, "ext4_free_inode",
+ "reserved or nonexistent inode %lu", ino);
+ goto error_return;
+ }
+ block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
+ bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
+ bitmap_bh = read_inode_bitmap(sb, block_group);
+ if (!bitmap_bh)
+ goto error_return;
+
+ BUFFER_TRACE(bitmap_bh, "get_write_access");
+ fatal = ext4_journal_get_write_access(handle, bitmap_bh);
+ if (fatal)
+ goto error_return;
+
+ /* Ok, now we can actually update the inode bitmaps.. */
+ if (!ext4_clear_bit_atomic(sb_bgl_lock(sbi, block_group),
+ bit, bitmap_bh->b_data))
+ ext4_error (sb, "ext4_free_inode",
+ "bit already cleared for inode %lu", ino);
+ else {
+ gdp = ext4_get_group_desc (sb, block_group, &bh2);
+
+ BUFFER_TRACE(bh2, "get_write_access");
+ fatal = ext4_journal_get_write_access(handle, bh2);
+ if (fatal) goto error_return;
+
+ if (gdp) {
+ spin_lock(sb_bgl_lock(sbi, block_group));
+ gdp->bg_free_inodes_count = cpu_to_le16(
+ le16_to_cpu(gdp->bg_free_inodes_count) + 1);
+ if (is_directory)
+ gdp->bg_used_dirs_count = cpu_to_le16(
+ le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+ spin_unlock(sb_bgl_lock(sbi, block_group));
+ percpu_counter_inc(&sbi->s_freeinodes_counter);
+ if (is_directory)
+ percpu_counter_dec(&sbi->s_dirs_counter);
+
+ }
+ BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, bh2);
+ if (!fatal) fatal = err;
+ }
+ BUFFER_TRACE(bitmap_bh, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, bitmap_bh);
+ if (!fatal)
+ fatal = err;
+ sb->s_dirt = 1;
+error_return:
+ brelse(bitmap_bh);
+ ext4_std_error(sb, fatal);
+}
+
+/*
+ * There are two policies for allocating an inode. If the new inode is
+ * a directory, then a forward search is made for a block group with both
+ * free space and a low directory-to-inode ratio; if that fails, then of
+ * the groups with above-average free space, that group with the fewest
+ * directories already is chosen.
+ *
+ * For other inodes, search forward from the parent directory\'s block
+ * group to find a free inode.
+ */
+static int find_group_dir(struct super_block *sb, struct inode *parent)
+{
+ int ngroups = EXT4_SB(sb)->s_groups_count;
+ unsigned int freei, avefreei;
+ struct ext4_group_desc *desc, *best_desc = NULL;
+ struct buffer_head *bh;
+ int group, best_group = -1;
+
+ freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter);
+ avefreei = freei / ngroups;
+
+ for (group = 0; group < ngroups; group++) {
+ desc = ext4_get_group_desc (sb, group, &bh);
+ if (!desc || !desc->bg_free_inodes_count)
+ continue;
+ if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
+ continue;
+ if (!best_desc ||
+ (le16_to_cpu(desc->bg_free_blocks_count) >
+ le16_to_cpu(best_desc->bg_free_blocks_count))) {
+ best_group = group;
+ best_desc = desc;
+ }
+ }
+ return best_group;
+}
+
+/*
+ * Orlov's allocator for directories.
+ *
+ * We always try to spread first-level directories.
+ *
+ * If there are blockgroups with both free inodes and free blocks counts
+ * not worse than average we return one with smallest directory count.
+ * Otherwise we simply return a random group.
+ *
+ * For the rest rules look so:
+ *
+ * It's OK to put directory into a group unless
+ * it has too many directories already (max_dirs) or
+ * it has too few free inodes left (min_inodes) or
+ * it has too few free blocks left (min_blocks) or
+ * it's already running too large debt (max_debt).
+ * Parent's group is prefered, if it doesn't satisfy these
+ * conditions we search cyclically through the rest. If none
+ * of the groups look good we just look for a group with more
+ * free inodes than average (starting at parent's group).
+ *
+ * Debt is incremented each time we allocate a directory and decremented
+ * when we allocate an inode, within 0--255.
+ */
+
+#define INODE_COST 64
+#define BLOCK_COST 256
+
+static int find_group_orlov(struct super_block *sb, struct inode *parent)
+{
+ int parent_group = EXT4_I(parent)->i_block_group;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_super_block *es = sbi->s_es;
+ int ngroups = sbi->s_groups_count;
+ int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
+ unsigned int freei, avefreei;
+ ext4_fsblk_t freeb, avefreeb;
+ ext4_fsblk_t blocks_per_dir;
+ unsigned int ndirs;
+ int max_debt, max_dirs, min_inodes;
+ ext4_grpblk_t min_blocks;
+ int group = -1, i;
+ struct ext4_group_desc *desc;
+ struct buffer_head *bh;
+
+ freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter);
+ avefreei = freei / ngroups;
+ freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter);
+ avefreeb = freeb;
+ do_div(avefreeb, ngroups);
+ ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter);
+
+ if ((parent == sb->s_root->d_inode) ||
+ (EXT4_I(parent)->i_flags & EXT4_TOPDIR_FL)) {
+ int best_ndir = inodes_per_group;
+ int best_group = -1;
+
+ get_random_bytes(&group, sizeof(group));
+ parent_group = (unsigned)group % ngroups;
+ for (i = 0; i < ngroups; i++) {
+ group = (parent_group + i) % ngroups;
+ desc = ext4_get_group_desc (sb, group, &bh);
+ if (!desc || !desc->bg_free_inodes_count)
+ continue;
+ if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir)
+ continue;
+ if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei)
+ continue;
+ if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb)
+ continue;
+ best_group = group;
+ best_ndir = le16_to_cpu(desc->bg_used_dirs_count);
+ }
+ if (best_group >= 0)
+ return best_group;
+ goto fallback;
+ }
+
+ blocks_per_dir = ext4_blocks_count(es) - freeb;
+ do_div(blocks_per_dir, ndirs);
+
+ max_dirs = ndirs / ngroups + inodes_per_group / 16;
+ min_inodes = avefreei - inodes_per_group / 4;
+ min_blocks = avefreeb - EXT4_BLOCKS_PER_GROUP(sb) / 4;
+
+ max_debt = EXT4_BLOCKS_PER_GROUP(sb);
+ max_debt /= max_t(int, blocks_per_dir, BLOCK_COST);
+ if (max_debt * INODE_COST > inodes_per_group)
+ max_debt = inodes_per_group / INODE_COST;
+ if (max_debt > 255)
+ max_debt = 255;
+ if (max_debt == 0)
+ max_debt = 1;
+
+ for (i = 0; i < ngroups; i++) {
+ group = (parent_group + i) % ngroups;
+ desc = ext4_get_group_desc (sb, group, &bh);
+ if (!desc || !desc->bg_free_inodes_count)
+ continue;
+ if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs)
+ continue;
+ if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes)
+ continue;
+ if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks)
+ continue;
+ return group;
+ }
+
+fallback:
+ for (i = 0; i < ngroups; i++) {
+ group = (parent_group + i) % ngroups;
+ desc = ext4_get_group_desc (sb, group, &bh);
+ if (!desc || !desc->bg_free_inodes_count)
+ continue;
+ if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei)
+ return group;
+ }
+
+ if (avefreei) {
+ /*
+ * The free-inodes counter is approximate, and for really small
+ * filesystems the above test can fail to find any blockgroups
+ */
+ avefreei = 0;
+ goto fallback;
+ }
+
+ return -1;
+}
+
+static int find_group_other(struct super_block *sb, struct inode *parent)
+{
+ int parent_group = EXT4_I(parent)->i_block_group;
+ int ngroups = EXT4_SB(sb)->s_groups_count;
+ struct ext4_group_desc *desc;
+ struct buffer_head *bh;
+ int group, i;
+
+ /*
+ * Try to place the inode in its parent directory
+ */
+ group = parent_group;
+ desc = ext4_get_group_desc (sb, group, &bh);
+ if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
+ le16_to_cpu(desc->bg_free_blocks_count))
+ return group;
+
+ /*
+ * We're going to place this inode in a different blockgroup from its
+ * parent. We want to cause files in a common directory to all land in
+ * the same blockgroup. But we want files which are in a different
+ * directory which shares a blockgroup with our parent to land in a
+ * different blockgroup.
+ *
+ * So add our directory's i_ino into the starting point for the hash.
+ */
+ group = (group + parent->i_ino) % ngroups;
+
+ /*
+ * Use a quadratic hash to find a group with a free inode and some free
+ * blocks.
+ */
+ for (i = 1; i < ngroups; i <<= 1) {
+ group += i;
+ if (group >= ngroups)
+ group -= ngroups;
+ desc = ext4_get_group_desc (sb, group, &bh);
+ if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
+ le16_to_cpu(desc->bg_free_blocks_count))
+ return group;
+ }
+
+ /*
+ * That failed: try linear search for a free inode, even if that group
+ * has no free blocks.
+ */
+ group = parent_group;
+ for (i = 0; i < ngroups; i++) {
+ if (++group >= ngroups)
+ group = 0;
+ desc = ext4_get_group_desc (sb, group, &bh);
+ if (desc && le16_to_cpu(desc->bg_free_inodes_count))
+ return group;
+ }
+
+ return -1;
+}
+
+/*
+ * There are two policies for allocating an inode. If the new inode is
+ * a directory, then a forward search is made for a block group with both
+ * free space and a low directory-to-inode ratio; if that fails, then of
+ * the groups with above-average free space, that group with the fewest
+ * directories already is chosen.
+ *
+ * For other inodes, search forward from the parent directory's block
+ * group to find a free inode.
+ */
+struct inode *ext4_new_inode(handle_t *handle, struct inode * dir, int mode)
+{
+ struct super_block *sb;
+ struct buffer_head *bitmap_bh = NULL;
+ struct buffer_head *bh2;
+ int group;
+ unsigned long ino = 0;
+ struct inode * inode;
+ struct ext4_group_desc * gdp = NULL;
+ struct ext4_super_block * es;
+ struct ext4_inode_info *ei;
+ struct ext4_sb_info *sbi;
+ int err = 0;
+ struct inode *ret;
+ int i;
+
+ /* Cannot create files in a deleted directory */
+ if (!dir || !dir->i_nlink)
+ return ERR_PTR(-EPERM);
+
+ sb = dir->i_sb;
+ inode = new_inode(sb);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ ei = EXT4_I(inode);
+
+ sbi = EXT4_SB(sb);
+ es = sbi->s_es;
+ if (S_ISDIR(mode)) {
+ if (test_opt (sb, OLDALLOC))
+ group = find_group_dir(sb, dir);
+ else
+ group = find_group_orlov(sb, dir);
+ } else
+ group = find_group_other(sb, dir);
+
+ err = -ENOSPC;
+ if (group == -1)
+ goto out;
+
+ for (i = 0; i < sbi->s_groups_count; i++) {
+ err = -EIO;
+
+ gdp = ext4_get_group_desc(sb, group, &bh2);
+ if (!gdp)
+ goto fail;
+
+ brelse(bitmap_bh);
+ bitmap_bh = read_inode_bitmap(sb, group);
+ if (!bitmap_bh)
+ goto fail;
+
+ ino = 0;
+
+repeat_in_this_group:
+ ino = ext4_find_next_zero_bit((unsigned long *)
+ bitmap_bh->b_data, EXT4_INODES_PER_GROUP(sb), ino);
+ if (ino < EXT4_INODES_PER_GROUP(sb)) {
+
+ BUFFER_TRACE(bitmap_bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, bitmap_bh);
+ if (err)
+ goto fail;
+
+ if (!ext4_set_bit_atomic(sb_bgl_lock(sbi, group),
+ ino, bitmap_bh->b_data)) {
+ /* we won it */
+ BUFFER_TRACE(bitmap_bh,
+ "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle,
+ bitmap_bh);
+ if (err)
+ goto fail;
+ goto got;
+ }
+ /* we lost it */
+ jbd2_journal_release_buffer(handle, bitmap_bh);
+
+ if (++ino < EXT4_INODES_PER_GROUP(sb))
+ goto repeat_in_this_group;
+ }
+
+ /*
+ * This case is possible in concurrent environment. It is very
+ * rare. We cannot repeat the find_group_xxx() call because
+ * that will simply return the same blockgroup, because the
+ * group descriptor metadata has not yet been updated.
+ * So we just go onto the next blockgroup.
+ */
+ if (++group == sbi->s_groups_count)
+ group = 0;
+ }
+ err = -ENOSPC;
+ goto out;
+
+got:
+ ino += group * EXT4_INODES_PER_GROUP(sb) + 1;
+ if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
+ ext4_error (sb, "ext4_new_inode",
+ "reserved inode or inode > inodes count - "
+ "block_group = %d, inode=%lu", group, ino);
+ err = -EIO;
+ goto fail;
+ }
+
+ BUFFER_TRACE(bh2, "get_write_access");
+ err = ext4_journal_get_write_access(handle, bh2);
+ if (err) goto fail;
+ spin_lock(sb_bgl_lock(sbi, group));
+ gdp->bg_free_inodes_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
+ if (S_ISDIR(mode)) {
+ gdp->bg_used_dirs_count =
+ cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
+ }
+ spin_unlock(sb_bgl_lock(sbi, group));
+ BUFFER_TRACE(bh2, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, bh2);
+ if (err) goto fail;
+
+ percpu_counter_dec(&sbi->s_freeinodes_counter);
+ if (S_ISDIR(mode))
+ percpu_counter_inc(&sbi->s_dirs_counter);
+ sb->s_dirt = 1;
+
+ inode->i_uid = current->fsuid;
+ if (test_opt (sb, GRPID))
+ inode->i_gid = dir->i_gid;
+ else if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+ if (S_ISDIR(mode))
+ mode |= S_ISGID;
+ } else
+ inode->i_gid = current->fsgid;
+ inode->i_mode = mode;
+
+ inode->i_ino = ino;
+ /* This is the optimal IO size (for stat), not the fs block size */
+ inode->i_blocks = 0;
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+
+ memset(ei->i_data, 0, sizeof(ei->i_data));
+ ei->i_dir_start_lookup = 0;
+ ei->i_disksize = 0;
+
+ ei->i_flags = EXT4_I(dir)->i_flags & ~EXT4_INDEX_FL;
+ if (S_ISLNK(mode))
+ ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL);
+ /* dirsync only applies to directories */
+ if (!S_ISDIR(mode))
+ ei->i_flags &= ~EXT4_DIRSYNC_FL;
+#ifdef EXT4_FRAGMENTS
+ ei->i_faddr = 0;
+ ei->i_frag_no = 0;
+ ei->i_frag_size = 0;
+#endif
+ ei->i_file_acl = 0;
+ ei->i_dir_acl = 0;
+ ei->i_dtime = 0;
+ ei->i_block_alloc_info = NULL;
+ ei->i_block_group = group;
+
+ ext4_set_inode_flags(inode);
+ if (IS_DIRSYNC(inode))
+ handle->h_sync = 1;
+ insert_inode_hash(inode);
+ spin_lock(&sbi->s_next_gen_lock);
+ inode->i_generation = sbi->s_next_generation++;
+ spin_unlock(&sbi->s_next_gen_lock);
+
+ ei->i_state = EXT4_STATE_NEW;
+ ei->i_extra_isize =
+ (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) ?
+ sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE : 0;
+
+ ret = inode;
+ if(DQUOT_ALLOC_INODE(inode)) {
+ err = -EDQUOT;
+ goto fail_drop;
+ }
+
+ err = ext4_init_acl(handle, inode, dir);
+ if (err)
+ goto fail_free_drop;
+
+ err = ext4_init_security(handle,inode, dir);
+ if (err)
+ goto fail_free_drop;
+
+ err = ext4_mark_inode_dirty(handle, inode);
+ if (err) {
+ ext4_std_error(sb, err);
+ goto fail_free_drop;
+ }
+ if (test_opt(sb, EXTENTS)) {
+ EXT4_I(inode)->i_flags |= EXT4_EXTENTS_FL;
+ ext4_ext_tree_init(handle, inode);
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS)) {
+ err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
+ if (err) goto fail;
+ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS);
+ BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
+ }
+ }
+
+ ext4_debug("allocating inode %lu\n", inode->i_ino);
+ goto really_out;
+fail:
+ ext4_std_error(sb, err);
+out:
+ iput(inode);
+ ret = ERR_PTR(err);
+really_out:
+ brelse(bitmap_bh);
+ return ret;
+
+fail_free_drop:
+ DQUOT_FREE_INODE(inode);
+
+fail_drop:
+ DQUOT_DROP(inode);
+ inode->i_flags |= S_NOQUOTA;
+ inode->i_nlink = 0;
+ iput(inode);
+ brelse(bitmap_bh);
+ return ERR_PTR(err);
+}
+
+/* Verify that we are loading a valid orphan from disk */
+struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino)
+{
+ unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count);
+ unsigned long block_group;
+ int bit;
+ struct buffer_head *bitmap_bh = NULL;
+ struct inode *inode = NULL;
+
+ /* Error cases - e2fsck has already cleaned up for us */
+ if (ino > max_ino) {
+ ext4_warning(sb, __FUNCTION__,
+ "bad orphan ino %lu! e2fsck was run?", ino);
+ goto out;
+ }
+
+ block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
+ bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb);
+ bitmap_bh = read_inode_bitmap(sb, block_group);
+ if (!bitmap_bh) {
+ ext4_warning(sb, __FUNCTION__,
+ "inode bitmap error for orphan %lu", ino);
+ goto out;
+ }
+
+ /* Having the inode bit set should be a 100% indicator that this
+ * is a valid orphan (no e2fsck run on fs). Orphans also include
+ * inodes that were being truncated, so we can't check i_nlink==0.
+ */
+ if (!ext4_test_bit(bit, bitmap_bh->b_data) ||
+ !(inode = iget(sb, ino)) || is_bad_inode(inode) ||
+ NEXT_ORPHAN(inode) > max_ino) {
+ ext4_warning(sb, __FUNCTION__,
+ "bad orphan inode %lu! e2fsck was run?", ino);
+ printk(KERN_NOTICE "ext4_test_bit(bit=%d, block=%llu) = %d\n",
+ bit, (unsigned long long)bitmap_bh->b_blocknr,
+ ext4_test_bit(bit, bitmap_bh->b_data));
+ printk(KERN_NOTICE "inode=%p\n", inode);
+ if (inode) {
+ printk(KERN_NOTICE "is_bad_inode(inode)=%d\n",
+ is_bad_inode(inode));
+ printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n",
+ NEXT_ORPHAN(inode));
+ printk(KERN_NOTICE "max_ino=%lu\n", max_ino);
+ }
+ /* Avoid freeing blocks if we got a bad deleted inode */
+ if (inode && inode->i_nlink == 0)
+ inode->i_blocks = 0;
+ iput(inode);
+ inode = NULL;
+ }
+out:
+ brelse(bitmap_bh);
+ return inode;
+}
+
+unsigned long ext4_count_free_inodes (struct super_block * sb)
+{
+ unsigned long desc_count;
+ struct ext4_group_desc *gdp;
+ int i;
+#ifdef EXT4FS_DEBUG
+ struct ext4_super_block *es;
+ unsigned long bitmap_count, x;
+ struct buffer_head *bitmap_bh = NULL;
+
+ es = EXT4_SB(sb)->s_es;
+ desc_count = 0;
+ bitmap_count = 0;
+ gdp = NULL;
+ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+ gdp = ext4_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
+ brelse(bitmap_bh);
+ bitmap_bh = read_inode_bitmap(sb, i);
+ if (!bitmap_bh)
+ continue;
+
+ x = ext4_count_free(bitmap_bh, EXT4_INODES_PER_GROUP(sb) / 8);
+ printk("group %d: stored = %d, counted = %lu\n",
+ i, le16_to_cpu(gdp->bg_free_inodes_count), x);
+ bitmap_count += x;
+ }
+ brelse(bitmap_bh);
+ printk("ext4_count_free_inodes: stored = %u, computed = %lu, %lu\n",
+ le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
+ return desc_count;
+#else
+ desc_count = 0;
+ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+ gdp = ext4_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
+ desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
+ cond_resched();
+ }
+ return desc_count;
+#endif
+}
+
+/* Called at mount-time, super-block is locked */
+unsigned long ext4_count_dirs (struct super_block * sb)
+{
+ unsigned long count = 0;
+ int i;
+
+ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+ struct ext4_group_desc *gdp = ext4_get_group_desc (sb, i, NULL);
+ if (!gdp)
+ continue;
+ count += le16_to_cpu(gdp->bg_used_dirs_count);
+ }
+ return count;
+}
+
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
new file mode 100644
index 000000000000..0a60ec5a16db
--- /dev/null
+++ b/fs/ext4/inode.c
@@ -0,0 +1,3233 @@
+/*
+ * linux/fs/ext4/inode.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/inode.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Goal-directed block allocation by Stephen Tweedie
+ * (sct@redhat.com), 1993, 1998
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ * 64-bit file support on 64-bit platforms by Jakub Jelinek
+ * (jj@sunsite.ms.mff.cuni.cz)
+ *
+ * Assorted race fixes, rewrite of ext4_get_block() by Al Viro, 2000
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/jbd2.h>
+#include <linux/smp_lock.h>
+#include <linux/highuid.h>
+#include <linux/pagemap.h>
+#include <linux/quotaops.h>
+#include <linux/string.h>
+#include <linux/buffer_head.h>
+#include <linux/writeback.h>
+#include <linux/mpage.h>
+#include <linux/uio.h>
+#include <linux/bio.h>
+#include "xattr.h"
+#include "acl.h"
+
+/*
+ * Test whether an inode is a fast symlink.
+ */
+static int ext4_inode_is_fast_symlink(struct inode *inode)
+{
+ int ea_blocks = EXT4_I(inode)->i_file_acl ?
+ (inode->i_sb->s_blocksize >> 9) : 0;
+
+ return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0);
+}
+
+/*
+ * The ext4 forget function must perform a revoke if we are freeing data
+ * which has been journaled. Metadata (eg. indirect blocks) must be
+ * revoked in all cases.
+ *
+ * "bh" may be NULL: a metadata block may have been freed from memory
+ * but there may still be a record of it in the journal, and that record
+ * still needs to be revoked.
+ */
+int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
+ struct buffer_head *bh, ext4_fsblk_t blocknr)
+{
+ int err;
+
+ might_sleep();
+
+ BUFFER_TRACE(bh, "enter");
+
+ jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, "
+ "data mode %lx\n",
+ bh, is_metadata, inode->i_mode,
+ test_opt(inode->i_sb, DATA_FLAGS));
+
+ /* Never use the revoke function if we are doing full data
+ * journaling: there is no need to, and a V1 superblock won't
+ * support it. Otherwise, only skip the revoke on un-journaled
+ * data blocks. */
+
+ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ||
+ (!is_metadata && !ext4_should_journal_data(inode))) {
+ if (bh) {
+ BUFFER_TRACE(bh, "call jbd2_journal_forget");
+ return ext4_journal_forget(handle, bh);
+ }
+ return 0;
+ }
+
+ /*
+ * data!=journal && (is_metadata || should_journal_data(inode))
+ */
+ BUFFER_TRACE(bh, "call ext4_journal_revoke");
+ err = ext4_journal_revoke(handle, blocknr, bh);
+ if (err)
+ ext4_abort(inode->i_sb, __FUNCTION__,
+ "error %d when attempting revoke", err);
+ BUFFER_TRACE(bh, "exit");
+ return err;
+}
+
+/*
+ * Work out how many blocks we need to proceed with the next chunk of a
+ * truncate transaction.
+ */
+static unsigned long blocks_for_truncate(struct inode *inode)
+{
+ unsigned long needed;
+
+ needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9);
+
+ /* Give ourselves just enough room to cope with inodes in which
+ * i_blocks is corrupt: we've seen disk corruptions in the past
+ * which resulted in random data in an inode which looked enough
+ * like a regular file for ext4 to try to delete it. Things
+ * will go a bit crazy if that happens, but at least we should
+ * try not to panic the whole kernel. */
+ if (needed < 2)
+ needed = 2;
+
+ /* But we need to bound the transaction so we don't overflow the
+ * journal. */
+ if (needed > EXT4_MAX_TRANS_DATA)
+ needed = EXT4_MAX_TRANS_DATA;
+
+ return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
+}
+
+/*
+ * Truncate transactions can be complex and absolutely huge. So we need to
+ * be able to restart the transaction at a conventient checkpoint to make
+ * sure we don't overflow the journal.
+ *
+ * start_transaction gets us a new handle for a truncate transaction,
+ * and extend_transaction tries to extend the existing one a bit. If
+ * extend fails, we need to propagate the failure up and restart the
+ * transaction in the top-level truncate loop. --sct
+ */
+static handle_t *start_transaction(struct inode *inode)
+{
+ handle_t *result;
+
+ result = ext4_journal_start(inode, blocks_for_truncate(inode));
+ if (!IS_ERR(result))
+ return result;
+
+ ext4_std_error(inode->i_sb, PTR_ERR(result));
+ return result;
+}
+
+/*
+ * Try to extend this transaction for the purposes of truncation.
+ *
+ * Returns 0 if we managed to create more room. If we can't create more
+ * room, and the transaction must be restarted we return 1.
+ */
+static int try_to_extend_transaction(handle_t *handle, struct inode *inode)
+{
+ if (handle->h_buffer_credits > EXT4_RESERVE_TRANS_BLOCKS)
+ return 0;
+ if (!ext4_journal_extend(handle, blocks_for_truncate(inode)))
+ return 0;
+ return 1;
+}
+
+/*
+ * Restart the transaction associated with *handle. This does a commit,
+ * so before we call here everything must be consistently dirtied against
+ * this transaction.
+ */
+static int ext4_journal_test_restart(handle_t *handle, struct inode *inode)
+{
+ jbd_debug(2, "restarting handle %p\n", handle);
+ return ext4_journal_restart(handle, blocks_for_truncate(inode));
+}
+
+/*
+ * Called at the last iput() if i_nlink is zero.
+ */
+void ext4_delete_inode (struct inode * inode)
+{
+ handle_t *handle;
+
+ truncate_inode_pages(&inode->i_data, 0);
+
+ if (is_bad_inode(inode))
+ goto no_delete;
+
+ handle = start_transaction(inode);
+ if (IS_ERR(handle)) {
+ /*
+ * If we're going to skip the normal cleanup, we still need to
+ * make sure that the in-core orphan linked list is properly
+ * cleaned up.
+ */
+ ext4_orphan_del(NULL, inode);
+ goto no_delete;
+ }
+
+ if (IS_SYNC(inode))
+ handle->h_sync = 1;
+ inode->i_size = 0;
+ if (inode->i_blocks)
+ ext4_truncate(inode);
+ /*
+ * Kill off the orphan record which ext4_truncate created.
+ * AKPM: I think this can be inside the above `if'.
+ * Note that ext4_orphan_del() has to be able to cope with the
+ * deletion of a non-existent orphan - this is because we don't
+ * know if ext4_truncate() actually created an orphan record.
+ * (Well, we could do this if we need to, but heck - it works)
+ */
+ ext4_orphan_del(handle, inode);
+ EXT4_I(inode)->i_dtime = get_seconds();
+
+ /*
+ * One subtle ordering requirement: if anything has gone wrong
+ * (transaction abort, IO errors, whatever), then we can still
+ * do these next steps (the fs will already have been marked as
+ * having errors), but we can't free the inode if the mark_dirty
+ * fails.
+ */
+ if (ext4_mark_inode_dirty(handle, inode))
+ /* If that failed, just do the required in-core inode clear. */
+ clear_inode(inode);
+ else
+ ext4_free_inode(handle, inode);
+ ext4_journal_stop(handle);
+ return;
+no_delete:
+ clear_inode(inode); /* We must guarantee clearing of inode... */
+}
+
+typedef struct {
+ __le32 *p;
+ __le32 key;
+ struct buffer_head *bh;
+} Indirect;
+
+static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v)
+{
+ p->key = *(p->p = v);
+ p->bh = bh;
+}
+
+static int verify_chain(Indirect *from, Indirect *to)
+{
+ while (from <= to && from->key == *from->p)
+ from++;
+ return (from > to);
+}
+
+/**
+ * ext4_block_to_path - parse the block number into array of offsets
+ * @inode: inode in question (we are only interested in its superblock)
+ * @i_block: block number to be parsed
+ * @offsets: array to store the offsets in
+ * @boundary: set this non-zero if the referred-to block is likely to be
+ * followed (on disk) by an indirect block.
+ *
+ * To store the locations of file's data ext4 uses a data structure common
+ * for UNIX filesystems - tree of pointers anchored in the inode, with
+ * data blocks at leaves and indirect blocks in intermediate nodes.
+ * This function translates the block number into path in that tree -
+ * return value is the path length and @offsets[n] is the offset of
+ * pointer to (n+1)th node in the nth one. If @block is out of range
+ * (negative or too large) warning is printed and zero returned.
+ *
+ * Note: function doesn't find node addresses, so no IO is needed. All
+ * we need to know is the capacity of indirect blocks (taken from the
+ * inode->i_sb).
+ */
+
+/*
+ * Portability note: the last comparison (check that we fit into triple
+ * indirect block) is spelled differently, because otherwise on an
+ * architecture with 32-bit longs and 8Kb pages we might get into trouble
+ * if our filesystem had 8Kb blocks. We might use long long, but that would
+ * kill us on x86. Oh, well, at least the sign propagation does not matter -
+ * i_block would have to be negative in the very beginning, so we would not
+ * get there at all.
+ */
+
+static int ext4_block_to_path(struct inode *inode,
+ long i_block, int offsets[4], int *boundary)
+{
+ int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb);
+ int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb);
+ const long direct_blocks = EXT4_NDIR_BLOCKS,
+ indirect_blocks = ptrs,
+ double_blocks = (1 << (ptrs_bits * 2));
+ int n = 0;
+ int final = 0;
+
+ if (i_block < 0) {
+ ext4_warning (inode->i_sb, "ext4_block_to_path", "block < 0");
+ } else if (i_block < direct_blocks) {
+ offsets[n++] = i_block;
+ final = direct_blocks;
+ } else if ( (i_block -= direct_blocks) < indirect_blocks) {
+ offsets[n++] = EXT4_IND_BLOCK;
+ offsets[n++] = i_block;
+ final = ptrs;
+ } else if ((i_block -= indirect_blocks) < double_blocks) {
+ offsets[n++] = EXT4_DIND_BLOCK;
+ offsets[n++] = i_block >> ptrs_bits;
+ offsets[n++] = i_block & (ptrs - 1);
+ final = ptrs;
+ } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
+ offsets[n++] = EXT4_TIND_BLOCK;
+ offsets[n++] = i_block >> (ptrs_bits * 2);
+ offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
+ offsets[n++] = i_block & (ptrs - 1);
+ final = ptrs;
+ } else {
+ ext4_warning(inode->i_sb, "ext4_block_to_path", "block > big");
+ }
+ if (boundary)
+ *boundary = final - 1 - (i_block & (ptrs - 1));
+ return n;
+}
+
+/**
+ * ext4_get_branch - read the chain of indirect blocks leading to data
+ * @inode: inode in question
+ * @depth: depth of the chain (1 - direct pointer, etc.)
+ * @offsets: offsets of pointers in inode/indirect blocks
+ * @chain: place to store the result
+ * @err: here we store the error value
+ *
+ * Function fills the array of triples <key, p, bh> and returns %NULL
+ * if everything went OK or the pointer to the last filled triple
+ * (incomplete one) otherwise. Upon the return chain[i].key contains
+ * the number of (i+1)-th block in the chain (as it is stored in memory,
+ * i.e. little-endian 32-bit), chain[i].p contains the address of that
+ * number (it points into struct inode for i==0 and into the bh->b_data
+ * for i>0) and chain[i].bh points to the buffer_head of i-th indirect
+ * block for i>0 and NULL for i==0. In other words, it holds the block
+ * numbers of the chain, addresses they were taken from (and where we can
+ * verify that chain did not change) and buffer_heads hosting these
+ * numbers.
+ *
+ * Function stops when it stumbles upon zero pointer (absent block)
+ * (pointer to last triple returned, *@err == 0)
+ * or when it gets an IO error reading an indirect block
+ * (ditto, *@err == -EIO)
+ * or when it notices that chain had been changed while it was reading
+ * (ditto, *@err == -EAGAIN)
+ * or when it reads all @depth-1 indirect blocks successfully and finds
+ * the whole chain, all way to the data (returns %NULL, *err == 0).
+ */
+static Indirect *ext4_get_branch(struct inode *inode, int depth, int *offsets,
+ Indirect chain[4], int *err)
+{
+ struct super_block *sb = inode->i_sb;
+ Indirect *p = chain;
+ struct buffer_head *bh;
+
+ *err = 0;
+ /* i_data is not going away, no lock needed */
+ add_chain (chain, NULL, EXT4_I(inode)->i_data + *offsets);
+ if (!p->key)
+ goto no_block;
+ while (--depth) {
+ bh = sb_bread(sb, le32_to_cpu(p->key));
+ if (!bh)
+ goto failure;
+ /* Reader: pointers */
+ if (!verify_chain(chain, p))
+ goto changed;
+ add_chain(++p, bh, (__le32*)bh->b_data + *++offsets);
+ /* Reader: end */
+ if (!p->key)
+ goto no_block;
+ }
+ return NULL;
+
+changed:
+ brelse(bh);
+ *err = -EAGAIN;
+ goto no_block;
+failure:
+ *err = -EIO;
+no_block:
+ return p;
+}
+
+/**
+ * ext4_find_near - find a place for allocation with sufficient locality
+ * @inode: owner
+ * @ind: descriptor of indirect block.
+ *
+ * This function returns the prefered place for block allocation.
+ * It is used when heuristic for sequential allocation fails.
+ * Rules are:
+ * + if there is a block to the left of our position - allocate near it.
+ * + if pointer will live in indirect block - allocate near that block.
+ * + if pointer will live in inode - allocate in the same
+ * cylinder group.
+ *
+ * In the latter case we colour the starting block by the callers PID to
+ * prevent it from clashing with concurrent allocations for a different inode
+ * in the same block group. The PID is used here so that functionally related
+ * files will be close-by on-disk.
+ *
+ * Caller must make sure that @ind is valid and will stay that way.
+ */
+static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data;
+ __le32 *p;
+ ext4_fsblk_t bg_start;
+ ext4_grpblk_t colour;
+
+ /* Try to find previous block */
+ for (p = ind->p - 1; p >= start; p--) {
+ if (*p)
+ return le32_to_cpu(*p);
+ }
+
+ /* No such thing, so let's try location of indirect block */
+ if (ind->bh)
+ return ind->bh->b_blocknr;
+
+ /*
+ * It is going to be referred to from the inode itself? OK, just put it
+ * into the same cylinder group then.
+ */
+ bg_start = ext4_group_first_block_no(inode->i_sb, ei->i_block_group);
+ colour = (current->pid % 16) *
+ (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16);
+ return bg_start + colour;
+}
+
+/**
+ * ext4_find_goal - find a prefered place for allocation.
+ * @inode: owner
+ * @block: block we want
+ * @chain: chain of indirect blocks
+ * @partial: pointer to the last triple within a chain
+ * @goal: place to store the result.
+ *
+ * Normally this function find the prefered place for block allocation,
+ * stores it in *@goal and returns zero.
+ */
+
+static ext4_fsblk_t ext4_find_goal(struct inode *inode, long block,
+ Indirect chain[4], Indirect *partial)
+{
+ struct ext4_block_alloc_info *block_i;
+
+ block_i = EXT4_I(inode)->i_block_alloc_info;
+
+ /*
+ * try the heuristic for sequential allocation,
+ * failing that at least try to get decent locality.
+ */
+ if (block_i && (block == block_i->last_alloc_logical_block + 1)
+ && (block_i->last_alloc_physical_block != 0)) {
+ return block_i->last_alloc_physical_block + 1;
+ }
+
+ return ext4_find_near(inode, partial);
+}
+
+/**
+ * ext4_blks_to_allocate: Look up the block map and count the number
+ * of direct blocks need to be allocated for the given branch.
+ *
+ * @branch: chain of indirect blocks
+ * @k: number of blocks need for indirect blocks
+ * @blks: number of data blocks to be mapped.
+ * @blocks_to_boundary: the offset in the indirect block
+ *
+ * return the total number of blocks to be allocate, including the
+ * direct and indirect blocks.
+ */
+static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned long blks,
+ int blocks_to_boundary)
+{
+ unsigned long count = 0;
+
+ /*
+ * Simple case, [t,d]Indirect block(s) has not allocated yet
+ * then it's clear blocks on that path have not allocated
+ */
+ if (k > 0) {
+ /* right now we don't handle cross boundary allocation */
+ if (blks < blocks_to_boundary + 1)
+ count += blks;
+ else
+ count += blocks_to_boundary + 1;
+ return count;
+ }
+
+ count++;
+ while (count < blks && count <= blocks_to_boundary &&
+ le32_to_cpu(*(branch[0].p + count)) == 0) {
+ count++;
+ }
+ return count;
+}
+
+/**
+ * ext4_alloc_blocks: multiple allocate blocks needed for a branch
+ * @indirect_blks: the number of blocks need to allocate for indirect
+ * blocks
+ *
+ * @new_blocks: on return it will store the new block numbers for
+ * the indirect blocks(if needed) and the first direct block,
+ * @blks: on return it will store the total number of allocated
+ * direct blocks
+ */
+static int ext4_alloc_blocks(handle_t *handle, struct inode *inode,
+ ext4_fsblk_t goal, int indirect_blks, int blks,
+ ext4_fsblk_t new_blocks[4], int *err)
+{
+ int target, i;
+ unsigned long count = 0;
+ int index = 0;
+ ext4_fsblk_t current_block = 0;
+ int ret = 0;
+
+ /*
+ * Here we try to allocate the requested multiple blocks at once,
+ * on a best-effort basis.
+ * To build a branch, we should allocate blocks for
+ * the indirect blocks(if not allocated yet), and at least
+ * the first direct block of this branch. That's the
+ * minimum number of blocks need to allocate(required)
+ */
+ target = blks + indirect_blks;
+
+ while (1) {
+ count = target;
+ /* allocating blocks for indirect blocks and direct blocks */
+ current_block = ext4_new_blocks(handle,inode,goal,&count,err);
+ if (*err)
+ goto failed_out;
+
+ target -= count;
+ /* allocate blocks for indirect blocks */
+ while (index < indirect_blks && count) {
+ new_blocks[index++] = current_block++;
+ count--;
+ }
+
+ if (count > 0)
+ break;
+ }
+
+ /* save the new block number for the first direct block */
+ new_blocks[index] = current_block;
+
+ /* total number of blocks allocated for direct blocks */
+ ret = count;
+ *err = 0;
+ return ret;
+failed_out:
+ for (i = 0; i <index; i++)
+ ext4_free_blocks(handle, inode, new_blocks[i], 1);
+ return ret;
+}
+
+/**
+ * ext4_alloc_branch - allocate and set up a chain of blocks.
+ * @inode: owner
+ * @indirect_blks: number of allocated indirect blocks
+ * @blks: number of allocated direct blocks
+ * @offsets: offsets (in the blocks) to store the pointers to next.
+ * @branch: place to store the chain in.
+ *
+ * This function allocates blocks, zeroes out all but the last one,
+ * links them into chain and (if we are synchronous) writes them to disk.
+ * In other words, it prepares a branch that can be spliced onto the
+ * inode. It stores the information about that chain in the branch[], in
+ * the same format as ext4_get_branch() would do. We are calling it after
+ * we had read the existing part of chain and partial points to the last
+ * triple of that (one with zero ->key). Upon the exit we have the same
+ * picture as after the successful ext4_get_block(), except that in one
+ * place chain is disconnected - *branch->p is still zero (we did not
+ * set the last link), but branch->key contains the number that should
+ * be placed into *branch->p to fill that gap.
+ *
+ * If allocation fails we free all blocks we've allocated (and forget
+ * their buffer_heads) and return the error value the from failed
+ * ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain
+ * as described above and return 0.
+ */
+static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
+ int indirect_blks, int *blks, ext4_fsblk_t goal,
+ int *offsets, Indirect *branch)
+{
+ int blocksize = inode->i_sb->s_blocksize;
+ int i, n = 0;
+ int err = 0;
+ struct buffer_head *bh;
+ int num;
+ ext4_fsblk_t new_blocks[4];
+ ext4_fsblk_t current_block;
+
+ num = ext4_alloc_blocks(handle, inode, goal, indirect_blks,
+ *blks, new_blocks, &err);
+ if (err)
+ return err;
+
+ branch[0].key = cpu_to_le32(new_blocks[0]);
+ /*
+ * metadata blocks and data blocks are allocated.
+ */
+ for (n = 1; n <= indirect_blks; n++) {
+ /*
+ * Get buffer_head for parent block, zero it out
+ * and set the pointer to new one, then send
+ * parent to disk.
+ */
+ bh = sb_getblk(inode->i_sb, new_blocks[n-1]);
+ branch[n].bh = bh;
+ lock_buffer(bh);
+ BUFFER_TRACE(bh, "call get_create_access");
+ err = ext4_journal_get_create_access(handle, bh);
+ if (err) {
+ unlock_buffer(bh);
+ brelse(bh);
+ goto failed;
+ }
+
+ memset(bh->b_data, 0, blocksize);
+ branch[n].p = (__le32 *) bh->b_data + offsets[n];
+ branch[n].key = cpu_to_le32(new_blocks[n]);
+ *branch[n].p = branch[n].key;
+ if ( n == indirect_blks) {
+ current_block = new_blocks[n];
+ /*
+ * End of chain, update the last new metablock of
+ * the chain to point to the new allocated
+ * data blocks numbers
+ */
+ for (i=1; i < num; i++)
+ *(branch[n].p + i) = cpu_to_le32(++current_block);
+ }
+ BUFFER_TRACE(bh, "marking uptodate");
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+
+ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, bh);
+ if (err)
+ goto failed;
+ }
+ *blks = num;
+ return err;
+failed:
+ /* Allocation failed, free what we already allocated */
+ for (i = 1; i <= n ; i++) {
+ BUFFER_TRACE(branch[i].bh, "call jbd2_journal_forget");
+ ext4_journal_forget(handle, branch[i].bh);
+ }
+ for (i = 0; i <indirect_blks; i++)
+ ext4_free_blocks(handle, inode, new_blocks[i], 1);
+
+ ext4_free_blocks(handle, inode, new_blocks[i], num);
+
+ return err;
+}
+
+/**
+ * ext4_splice_branch - splice the allocated branch onto inode.
+ * @inode: owner
+ * @block: (logical) number of block we are adding
+ * @chain: chain of indirect blocks (with a missing link - see
+ * ext4_alloc_branch)
+ * @where: location of missing link
+ * @num: number of indirect blocks we are adding
+ * @blks: number of direct blocks we are adding
+ *
+ * This function fills the missing link and does all housekeeping needed in
+ * inode (->i_blocks, etc.). In case of success we end up with the full
+ * chain to new block and return 0.
+ */
+static int ext4_splice_branch(handle_t *handle, struct inode *inode,
+ long block, Indirect *where, int num, int blks)
+{
+ int i;
+ int err = 0;
+ struct ext4_block_alloc_info *block_i;
+ ext4_fsblk_t current_block;
+
+ block_i = EXT4_I(inode)->i_block_alloc_info;
+ /*
+ * If we're splicing into a [td]indirect block (as opposed to the
+ * inode) then we need to get write access to the [td]indirect block
+ * before the splice.
+ */
+ if (where->bh) {
+ BUFFER_TRACE(where->bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, where->bh);
+ if (err)
+ goto err_out;
+ }
+ /* That's it */
+
+ *where->p = where->key;
+
+ /*
+ * Update the host buffer_head or inode to point to more just allocated
+ * direct blocks blocks
+ */
+ if (num == 0 && blks > 1) {
+ current_block = le32_to_cpu(where->key) + 1;
+ for (i = 1; i < blks; i++)
+ *(where->p + i ) = cpu_to_le32(current_block++);
+ }
+
+ /*
+ * update the most recently allocated logical & physical block
+ * in i_block_alloc_info, to assist find the proper goal block for next
+ * allocation
+ */
+ if (block_i) {
+ block_i->last_alloc_logical_block = block + blks - 1;
+ block_i->last_alloc_physical_block =
+ le32_to_cpu(where[num].key) + blks - 1;
+ }
+
+ /* We are done with atomic stuff, now do the rest of housekeeping */
+
+ inode->i_ctime = CURRENT_TIME_SEC;
+ ext4_mark_inode_dirty(handle, inode);
+
+ /* had we spliced it onto indirect block? */
+ if (where->bh) {
+ /*
+ * If we spliced it onto an indirect block, we haven't
+ * altered the inode. Note however that if it is being spliced
+ * onto an indirect block at the very end of the file (the
+ * file is growing) then we *will* alter the inode to reflect
+ * the new i_size. But that is not done here - it is done in
+ * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode.
+ */
+ jbd_debug(5, "splicing indirect only\n");
+ BUFFER_TRACE(where->bh, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, where->bh);
+ if (err)
+ goto err_out;
+ } else {
+ /*
+ * OK, we spliced it into the inode itself on a direct block.
+ * Inode was dirtied above.
+ */
+ jbd_debug(5, "splicing direct\n");
+ }
+ return err;
+
+err_out:
+ for (i = 1; i <= num; i++) {
+ BUFFER_TRACE(where[i].bh, "call jbd2_journal_forget");
+ ext4_journal_forget(handle, where[i].bh);
+ ext4_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1);
+ }
+ ext4_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks);
+
+ return err;
+}
+
+/*
+ * Allocation strategy is simple: if we have to allocate something, we will
+ * have to go the whole way to leaf. So let's do it before attaching anything
+ * to tree, set linkage between the newborn blocks, write them if sync is
+ * required, recheck the path, free and repeat if check fails, otherwise
+ * set the last missing link (that will protect us from any truncate-generated
+ * removals - all blocks on the path are immune now) and possibly force the
+ * write on the parent block.
+ * That has a nice additional property: no special recovery from the failed
+ * allocations is needed - we simply release blocks and do not touch anything
+ * reachable from inode.
+ *
+ * `handle' can be NULL if create == 0.
+ *
+ * The BKL may not be held on entry here. Be sure to take it early.
+ * return > 0, # of blocks mapped or allocated.
+ * return = 0, if plain lookup failed.
+ * return < 0, error case.
+ */
+int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
+ sector_t iblock, unsigned long maxblocks,
+ struct buffer_head *bh_result,
+ int create, int extend_disksize)
+{
+ int err = -EIO;
+ int offsets[4];
+ Indirect chain[4];
+ Indirect *partial;
+ ext4_fsblk_t goal;
+ int indirect_blks;
+ int blocks_to_boundary = 0;
+ int depth;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ int count = 0;
+ ext4_fsblk_t first_block = 0;
+
+
+ J_ASSERT(!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL));
+ J_ASSERT(handle != NULL || create == 0);
+ depth = ext4_block_to_path(inode,iblock,offsets,&blocks_to_boundary);
+
+ if (depth == 0)
+ goto out;
+
+ partial = ext4_get_branch(inode, depth, offsets, chain, &err);
+
+ /* Simplest case - block found, no allocation needed */
+ if (!partial) {
+ first_block = le32_to_cpu(chain[depth - 1].key);
+ clear_buffer_new(bh_result);
+ count++;
+ /*map more blocks*/
+ while (count < maxblocks && count <= blocks_to_boundary) {
+ ext4_fsblk_t blk;
+
+ if (!verify_chain(chain, partial)) {
+ /*
+ * Indirect block might be removed by
+ * truncate while we were reading it.
+ * Handling of that case: forget what we've
+ * got now. Flag the err as EAGAIN, so it
+ * will reread.
+ */
+ err = -EAGAIN;
+ count = 0;
+ break;
+ }
+ blk = le32_to_cpu(*(chain[depth-1].p + count));
+
+ if (blk == first_block + count)
+ count++;
+ else
+ break;
+ }
+ if (err != -EAGAIN)
+ goto got_it;
+ }
+
+ /* Next simple case - plain lookup or failed read of indirect block */
+ if (!create || err == -EIO)
+ goto cleanup;
+
+ mutex_lock(&ei->truncate_mutex);
+
+ /*
+ * If the indirect block is missing while we are reading
+ * the chain(ext4_get_branch() returns -EAGAIN err), or
+ * if the chain has been changed after we grab the semaphore,
+ * (either because another process truncated this branch, or
+ * another get_block allocated this branch) re-grab the chain to see if
+ * the request block has been allocated or not.
+ *
+ * Since we already block the truncate/other get_block
+ * at this point, we will have the current copy of the chain when we
+ * splice the branch into the tree.
+ */
+ if (err == -EAGAIN || !verify_chain(chain, partial)) {
+ while (partial > chain) {
+ brelse(partial->bh);
+ partial--;
+ }
+ partial = ext4_get_branch(inode, depth, offsets, chain, &err);
+ if (!partial) {
+ count++;
+ mutex_unlock(&ei->truncate_mutex);
+ if (err)
+ goto cleanup;
+ clear_buffer_new(bh_result);
+ goto got_it;
+ }
+ }
+
+ /*
+ * Okay, we need to do block allocation. Lazily initialize the block
+ * allocation info here if necessary
+ */
+ if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info))
+ ext4_init_block_alloc_info(inode);
+
+ goal = ext4_find_goal(inode, iblock, chain, partial);
+
+ /* the number of blocks need to allocate for [d,t]indirect blocks */
+ indirect_blks = (chain + depth) - partial - 1;
+
+ /*
+ * Next look up the indirect map to count the totoal number of
+ * direct blocks to allocate for this branch.
+ */
+ count = ext4_blks_to_allocate(partial, indirect_blks,
+ maxblocks, blocks_to_boundary);
+ /*
+ * Block out ext4_truncate while we alter the tree
+ */
+ err = ext4_alloc_branch(handle, inode, indirect_blks, &count, goal,
+ offsets + (partial - chain), partial);
+
+ /*
+ * The ext4_splice_branch call will free and forget any buffers
+ * on the new chain if there is a failure, but that risks using
+ * up transaction credits, especially for bitmaps where the
+ * credits cannot be returned. Can we handle this somehow? We
+ * may need to return -EAGAIN upwards in the worst case. --sct
+ */
+ if (!err)
+ err = ext4_splice_branch(handle, inode, iblock,
+ partial, indirect_blks, count);
+ /*
+ * i_disksize growing is protected by truncate_mutex. Don't forget to
+ * protect it if you're about to implement concurrent
+ * ext4_get_block() -bzzz
+ */
+ if (!err && extend_disksize && inode->i_size > ei->i_disksize)
+ ei->i_disksize = inode->i_size;
+ mutex_unlock(&ei->truncate_mutex);
+ if (err)
+ goto cleanup;
+
+ set_buffer_new(bh_result);
+got_it:
+ map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
+ if (count > blocks_to_boundary)
+ set_buffer_boundary(bh_result);
+ err = count;
+ /* Clean up and exit */
+ partial = chain + depth - 1; /* the whole chain */
+cleanup:
+ while (partial > chain) {
+ BUFFER_TRACE(partial->bh, "call brelse");
+ brelse(partial->bh);
+ partial--;
+ }
+ BUFFER_TRACE(bh_result, "returned");
+out:
+ return err;
+}
+
+#define DIO_CREDITS (EXT4_RESERVE_TRANS_BLOCKS + 32)
+
+static int ext4_get_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create)
+{
+ handle_t *handle = journal_current_handle();
+ int ret = 0;
+ unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
+
+ if (!create)
+ goto get_block; /* A read */
+
+ if (max_blocks == 1)
+ goto get_block; /* A single block get */
+
+ if (handle->h_transaction->t_state == T_LOCKED) {
+ /*
+ * Huge direct-io writes can hold off commits for long
+ * periods of time. Let this commit run.
+ */
+ ext4_journal_stop(handle);
+ handle = ext4_journal_start(inode, DIO_CREDITS);
+ if (IS_ERR(handle))
+ ret = PTR_ERR(handle);
+ goto get_block;
+ }
+
+ if (handle->h_buffer_credits <= EXT4_RESERVE_TRANS_BLOCKS) {
+ /*
+ * Getting low on buffer credits...
+ */
+ ret = ext4_journal_extend(handle, DIO_CREDITS);
+ if (ret > 0) {
+ /*
+ * Couldn't extend the transaction. Start a new one.
+ */
+ ret = ext4_journal_restart(handle, DIO_CREDITS);
+ }
+ }
+
+get_block:
+ if (ret == 0) {
+ ret = ext4_get_blocks_wrap(handle, inode, iblock,
+ max_blocks, bh_result, create, 0);
+ if (ret > 0) {
+ bh_result->b_size = (ret << inode->i_blkbits);
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+/*
+ * `handle' can be NULL if create is zero
+ */
+struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode,
+ long block, int create, int *errp)
+{
+ struct buffer_head dummy;
+ int fatal = 0, err;
+
+ J_ASSERT(handle != NULL || create == 0);
+
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ buffer_trace_init(&dummy.b_history);
+ err = ext4_get_blocks_wrap(handle, inode, block, 1,
+ &dummy, create, 1);
+ /*
+ * ext4_get_blocks_handle() returns number of blocks
+ * mapped. 0 in case of a HOLE.
+ */
+ if (err > 0) {
+ if (err > 1)
+ WARN_ON(1);
+ err = 0;
+ }
+ *errp = err;
+ if (!err && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = sb_getblk(inode->i_sb, dummy.b_blocknr);
+ if (!bh) {
+ *errp = -EIO;
+ goto err;
+ }
+ if (buffer_new(&dummy)) {
+ J_ASSERT(create != 0);
+ J_ASSERT(handle != 0);
+
+ /*
+ * Now that we do not always journal data, we should
+ * keep in mind whether this should always journal the
+ * new buffer as metadata. For now, regular file
+ * writes use ext4_get_block instead, so it's not a
+ * problem.
+ */
+ lock_buffer(bh);
+ BUFFER_TRACE(bh, "call get_create_access");
+ fatal = ext4_journal_get_create_access(handle, bh);
+ if (!fatal && !buffer_uptodate(bh)) {
+ memset(bh->b_data,0,inode->i_sb->s_blocksize);
+ set_buffer_uptodate(bh);
+ }
+ unlock_buffer(bh);
+ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, bh);
+ if (!fatal)
+ fatal = err;
+ } else {
+ BUFFER_TRACE(bh, "not a new buffer");
+ }
+ if (fatal) {
+ *errp = fatal;
+ brelse(bh);
+ bh = NULL;
+ }
+ return bh;
+ }
+err:
+ return NULL;
+}
+
+struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
+ int block, int create, int *err)
+{
+ struct buffer_head * bh;
+
+ bh = ext4_getblk(handle, inode, block, create, err);
+ if (!bh)
+ return bh;
+ if (buffer_uptodate(bh))
+ return bh;
+ ll_rw_block(READ_META, 1, &bh);
+ wait_on_buffer(bh);
+ if (buffer_uptodate(bh))
+ return bh;
+ put_bh(bh);
+ *err = -EIO;
+ return NULL;
+}
+
+static int walk_page_buffers( handle_t *handle,
+ struct buffer_head *head,
+ unsigned from,
+ unsigned to,
+ int *partial,
+ int (*fn)( handle_t *handle,
+ struct buffer_head *bh))
+{
+ struct buffer_head *bh;
+ unsigned block_start, block_end;
+ unsigned blocksize = head->b_size;
+ int err, ret = 0;
+ struct buffer_head *next;
+
+ for ( bh = head, block_start = 0;
+ ret == 0 && (bh != head || !block_start);
+ block_start = block_end, bh = next)
+ {
+ next = bh->b_this_page;
+ block_end = block_start + blocksize;
+ if (block_end <= from || block_start >= to) {
+ if (partial && !buffer_uptodate(bh))
+ *partial = 1;
+ continue;
+ }
+ err = (*fn)(handle, bh);
+ if (!ret)
+ ret = err;
+ }
+ return ret;
+}
+
+/*
+ * To preserve ordering, it is essential that the hole instantiation and
+ * the data write be encapsulated in a single transaction. We cannot
+ * close off a transaction and start a new one between the ext4_get_block()
+ * and the commit_write(). So doing the jbd2_journal_start at the start of
+ * prepare_write() is the right place.
+ *
+ * Also, this function can nest inside ext4_writepage() ->
+ * block_write_full_page(). In that case, we *know* that ext4_writepage()
+ * has generated enough buffer credits to do the whole page. So we won't
+ * block on the journal in that case, which is good, because the caller may
+ * be PF_MEMALLOC.
+ *
+ * By accident, ext4 can be reentered when a transaction is open via
+ * quota file writes. If we were to commit the transaction while thus
+ * reentered, there can be a deadlock - we would be holding a quota
+ * lock, and the commit would never complete if another thread had a
+ * transaction open and was blocking on the quota lock - a ranking
+ * violation.
+ *
+ * So what we do is to rely on the fact that jbd2_journal_stop/journal_start
+ * will _not_ run commit under these circumstances because handle->h_ref
+ * is elevated. We'll still have enough credits for the tiny quotafile
+ * write.
+ */
+static int do_journal_get_write_access(handle_t *handle,
+ struct buffer_head *bh)
+{
+ if (!buffer_mapped(bh) || buffer_freed(bh))
+ return 0;
+ return ext4_journal_get_write_access(handle, bh);
+}
+
+static int ext4_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ struct inode *inode = page->mapping->host;
+ int ret, needed_blocks = ext4_writepage_trans_blocks(inode);
+ handle_t *handle;
+ int retries = 0;
+
+retry:
+ handle = ext4_journal_start(inode, needed_blocks);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ goto out;
+ }
+ if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
+ ret = nobh_prepare_write(page, from, to, ext4_get_block);
+ else
+ ret = block_prepare_write(page, from, to, ext4_get_block);
+ if (ret)
+ goto prepare_write_failed;
+
+ if (ext4_should_journal_data(inode)) {
+ ret = walk_page_buffers(handle, page_buffers(page),
+ from, to, NULL, do_journal_get_write_access);
+ }
+prepare_write_failed:
+ if (ret)
+ ext4_journal_stop(handle);
+ if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+out:
+ return ret;
+}
+
+int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
+{
+ int err = jbd2_journal_dirty_data(handle, bh);
+ if (err)
+ ext4_journal_abort_handle(__FUNCTION__, __FUNCTION__,
+ bh, handle,err);
+ return err;
+}
+
+/* For commit_write() in data=journal mode */
+static int commit_write_fn(handle_t *handle, struct buffer_head *bh)
+{
+ if (!buffer_mapped(bh) || buffer_freed(bh))
+ return 0;
+ set_buffer_uptodate(bh);
+ return ext4_journal_dirty_metadata(handle, bh);
+}
+
+/*
+ * We need to pick up the new inode size which generic_commit_write gave us
+ * `file' can be NULL - eg, when called from page_symlink().
+ *
+ * ext4 never places buffers on inode->i_mapping->private_list. metadata
+ * buffers are managed internally.
+ */
+static int ext4_ordered_commit_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ handle_t *handle = ext4_journal_current_handle();
+ struct inode *inode = page->mapping->host;
+ int ret = 0, ret2;
+
+ ret = walk_page_buffers(handle, page_buffers(page),
+ from, to, NULL, ext4_journal_dirty_data);
+
+ if (ret == 0) {
+ /*
+ * generic_commit_write() will run mark_inode_dirty() if i_size
+ * changes. So let's piggyback the i_disksize mark_inode_dirty
+ * into that.
+ */
+ loff_t new_i_size;
+
+ new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+ if (new_i_size > EXT4_I(inode)->i_disksize)
+ EXT4_I(inode)->i_disksize = new_i_size;
+ ret = generic_commit_write(file, page, from, to);
+ }
+ ret2 = ext4_journal_stop(handle);
+ if (!ret)
+ ret = ret2;
+ return ret;
+}
+
+static int ext4_writeback_commit_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ handle_t *handle = ext4_journal_current_handle();
+ struct inode *inode = page->mapping->host;
+ int ret = 0, ret2;
+ loff_t new_i_size;
+
+ new_i_size = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+ if (new_i_size > EXT4_I(inode)->i_disksize)
+ EXT4_I(inode)->i_disksize = new_i_size;
+
+ if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
+ ret = nobh_commit_write(file, page, from, to);
+ else
+ ret = generic_commit_write(file, page, from, to);
+
+ ret2 = ext4_journal_stop(handle);
+ if (!ret)
+ ret = ret2;
+ return ret;
+}
+
+static int ext4_journalled_commit_write(struct file *file,
+ struct page *page, unsigned from, unsigned to)
+{
+ handle_t *handle = ext4_journal_current_handle();
+ struct inode *inode = page->mapping->host;
+ int ret = 0, ret2;
+ int partial = 0;
+ loff_t pos;
+
+ /*
+ * Here we duplicate the generic_commit_write() functionality
+ */
+ pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+
+ ret = walk_page_buffers(handle, page_buffers(page), from,
+ to, &partial, commit_write_fn);
+ if (!partial)
+ SetPageUptodate(page);
+ if (pos > inode->i_size)
+ i_size_write(inode, pos);
+ EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
+ if (inode->i_size > EXT4_I(inode)->i_disksize) {
+ EXT4_I(inode)->i_disksize = inode->i_size;
+ ret2 = ext4_mark_inode_dirty(handle, inode);
+ if (!ret)
+ ret = ret2;
+ }
+ ret2 = ext4_journal_stop(handle);
+ if (!ret)
+ ret = ret2;
+ return ret;
+}
+
+/*
+ * bmap() is special. It gets used by applications such as lilo and by
+ * the swapper to find the on-disk block of a specific piece of data.
+ *
+ * Naturally, this is dangerous if the block concerned is still in the
+ * journal. If somebody makes a swapfile on an ext4 data-journaling
+ * filesystem and enables swap, then they may get a nasty shock when the
+ * data getting swapped to that swapfile suddenly gets overwritten by
+ * the original zero's written out previously to the journal and
+ * awaiting writeback in the kernel's buffer cache.
+ *
+ * So, if we see any bmap calls here on a modified, data-journaled file,
+ * take extra steps to flush any blocks which might be in the cache.
+ */
+static sector_t ext4_bmap(struct address_space *mapping, sector_t block)
+{
+ struct inode *inode = mapping->host;
+ journal_t *journal;
+ int err;
+
+ if (EXT4_I(inode)->i_state & EXT4_STATE_JDATA) {
+ /*
+ * This is a REALLY heavyweight approach, but the use of
+ * bmap on dirty files is expected to be extremely rare:
+ * only if we run lilo or swapon on a freshly made file
+ * do we expect this to happen.
+ *
+ * (bmap requires CAP_SYS_RAWIO so this does not
+ * represent an unprivileged user DOS attack --- we'd be
+ * in trouble if mortal users could trigger this path at
+ * will.)
+ *
+ * NB. EXT4_STATE_JDATA is not set on files other than
+ * regular files. If somebody wants to bmap a directory
+ * or symlink and gets confused because the buffer
+ * hasn't yet been flushed to disk, they deserve
+ * everything they get.
+ */
+
+ EXT4_I(inode)->i_state &= ~EXT4_STATE_JDATA;
+ journal = EXT4_JOURNAL(inode);
+ jbd2_journal_lock_updates(journal);
+ err = jbd2_journal_flush(journal);
+ jbd2_journal_unlock_updates(journal);
+
+ if (err)
+ return 0;
+ }
+
+ return generic_block_bmap(mapping,block,ext4_get_block);
+}
+
+static int bget_one(handle_t *handle, struct buffer_head *bh)
+{
+ get_bh(bh);
+ return 0;
+}
+
+static int bput_one(handle_t *handle, struct buffer_head *bh)
+{
+ put_bh(bh);
+ return 0;
+}
+
+static int jbd2_journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh)
+{
+ if (buffer_mapped(bh))
+ return ext4_journal_dirty_data(handle, bh);
+ return 0;
+}
+
+/*
+ * Note that we always start a transaction even if we're not journalling
+ * data. This is to preserve ordering: any hole instantiation within
+ * __block_write_full_page -> ext4_get_block() should be journalled
+ * along with the data so we don't crash and then get metadata which
+ * refers to old data.
+ *
+ * In all journalling modes block_write_full_page() will start the I/O.
+ *
+ * Problem:
+ *
+ * ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() ->
+ * ext4_writepage()
+ *
+ * Similar for:
+ *
+ * ext4_file_write() -> generic_file_write() -> __alloc_pages() -> ...
+ *
+ * Same applies to ext4_get_block(). We will deadlock on various things like
+ * lock_journal and i_truncate_mutex.
+ *
+ * Setting PF_MEMALLOC here doesn't work - too many internal memory
+ * allocations fail.
+ *
+ * 16May01: If we're reentered then journal_current_handle() will be
+ * non-zero. We simply *return*.
+ *
+ * 1 July 2001: @@@ FIXME:
+ * In journalled data mode, a data buffer may be metadata against the
+ * current transaction. But the same file is part of a shared mapping
+ * and someone does a writepage() on it.
+ *
+ * We will move the buffer onto the async_data list, but *after* it has
+ * been dirtied. So there's a small window where we have dirty data on
+ * BJ_Metadata.
+ *
+ * Note that this only applies to the last partial page in the file. The
+ * bit which block_write_full_page() uses prepare/commit for. (That's
+ * broken code anyway: it's wrong for msync()).
+ *
+ * It's a rare case: affects the final partial page, for journalled data
+ * where the file is subject to bith write() and writepage() in the same
+ * transction. To fix it we'll need a custom block_write_full_page().
+ * We'll probably need that anyway for journalling writepage() output.
+ *
+ * We don't honour synchronous mounts for writepage(). That would be
+ * disastrous. Any write() or metadata operation will sync the fs for
+ * us.
+ *
+ * AKPM2: if all the page's buffers are mapped to disk and !data=journal,
+ * we don't need to open a transaction here.
+ */
+static int ext4_ordered_writepage(struct page *page,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = page->mapping->host;
+ struct buffer_head *page_bufs;
+ handle_t *handle = NULL;
+ int ret = 0;
+ int err;
+
+ J_ASSERT(PageLocked(page));
+
+ /*
+ * We give up here if we're reentered, because it might be for a
+ * different filesystem.
+ */
+ if (ext4_journal_current_handle())
+ goto out_fail;
+
+ handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
+
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ goto out_fail;
+ }
+
+ if (!page_has_buffers(page)) {
+ create_empty_buffers(page, inode->i_sb->s_blocksize,
+ (1 << BH_Dirty)|(1 << BH_Uptodate));
+ }
+ page_bufs = page_buffers(page);
+ walk_page_buffers(handle, page_bufs, 0,
+ PAGE_CACHE_SIZE, NULL, bget_one);
+
+ ret = block_write_full_page(page, ext4_get_block, wbc);
+
+ /*
+ * The page can become unlocked at any point now, and
+ * truncate can then come in and change things. So we
+ * can't touch *page from now on. But *page_bufs is
+ * safe due to elevated refcount.
+ */
+
+ /*
+ * And attach them to the current transaction. But only if
+ * block_write_full_page() succeeded. Otherwise they are unmapped,
+ * and generally junk.
+ */
+ if (ret == 0) {
+ err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE,
+ NULL, jbd2_journal_dirty_data_fn);
+ if (!ret)
+ ret = err;
+ }
+ walk_page_buffers(handle, page_bufs, 0,
+ PAGE_CACHE_SIZE, NULL, bput_one);
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+
+out_fail:
+ redirty_page_for_writepage(wbc, page);
+ unlock_page(page);
+ return ret;
+}
+
+static int ext4_writeback_writepage(struct page *page,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = page->mapping->host;
+ handle_t *handle = NULL;
+ int ret = 0;
+ int err;
+
+ if (ext4_journal_current_handle())
+ goto out_fail;
+
+ handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ goto out_fail;
+ }
+
+ if (test_opt(inode->i_sb, NOBH) && ext4_should_writeback_data(inode))
+ ret = nobh_writepage(page, ext4_get_block, wbc);
+ else
+ ret = block_write_full_page(page, ext4_get_block, wbc);
+
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+
+out_fail:
+ redirty_page_for_writepage(wbc, page);
+ unlock_page(page);
+ return ret;
+}
+
+static int ext4_journalled_writepage(struct page *page,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = page->mapping->host;
+ handle_t *handle = NULL;
+ int ret = 0;
+ int err;
+
+ if (ext4_journal_current_handle())
+ goto no_write;
+
+ handle = ext4_journal_start(inode, ext4_writepage_trans_blocks(inode));
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ goto no_write;
+ }
+
+ if (!page_has_buffers(page) || PageChecked(page)) {
+ /*
+ * It's mmapped pagecache. Add buffers and journal it. There
+ * doesn't seem much point in redirtying the page here.
+ */
+ ClearPageChecked(page);
+ ret = block_prepare_write(page, 0, PAGE_CACHE_SIZE,
+ ext4_get_block);
+ if (ret != 0) {
+ ext4_journal_stop(handle);
+ goto out_unlock;
+ }
+ ret = walk_page_buffers(handle, page_buffers(page), 0,
+ PAGE_CACHE_SIZE, NULL, do_journal_get_write_access);
+
+ err = walk_page_buffers(handle, page_buffers(page), 0,
+ PAGE_CACHE_SIZE, NULL, commit_write_fn);
+ if (ret == 0)
+ ret = err;
+ EXT4_I(inode)->i_state |= EXT4_STATE_JDATA;
+ unlock_page(page);
+ } else {
+ /*
+ * It may be a page full of checkpoint-mode buffers. We don't
+ * really know unless we go poke around in the buffer_heads.
+ * But block_write_full_page will do the right thing.
+ */
+ ret = block_write_full_page(page, ext4_get_block, wbc);
+ }
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+out:
+ return ret;
+
+no_write:
+ redirty_page_for_writepage(wbc, page);
+out_unlock:
+ unlock_page(page);
+ goto out;
+}
+
+static int ext4_readpage(struct file *file, struct page *page)
+{
+ return mpage_readpage(page, ext4_get_block);
+}
+
+static int
+ext4_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *pages, unsigned nr_pages)
+{
+ return mpage_readpages(mapping, pages, nr_pages, ext4_get_block);
+}
+
+static void ext4_invalidatepage(struct page *page, unsigned long offset)
+{
+ journal_t *journal = EXT4_JOURNAL(page->mapping->host);
+
+ /*
+ * If it's a full truncate we just forget about the pending dirtying
+ */
+ if (offset == 0)
+ ClearPageChecked(page);
+
+ jbd2_journal_invalidatepage(journal, page, offset);
+}
+
+static int ext4_releasepage(struct page *page, gfp_t wait)
+{
+ journal_t *journal = EXT4_JOURNAL(page->mapping->host);
+
+ WARN_ON(PageChecked(page));
+ if (!page_has_buffers(page))
+ return 0;
+ return jbd2_journal_try_to_free_buffers(journal, page, wait);
+}
+
+/*
+ * If the O_DIRECT write will extend the file then add this inode to the
+ * orphan list. So recovery will truncate it back to the original size
+ * if the machine crashes during the write.
+ *
+ * If the O_DIRECT write is intantiating holes inside i_size and the machine
+ * crashes then stale disk data _may_ be exposed inside the file.
+ */
+static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb,
+ const struct iovec *iov, loff_t offset,
+ unsigned long nr_segs)
+{
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_mapping->host;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ handle_t *handle = NULL;
+ ssize_t ret;
+ int orphan = 0;
+ size_t count = iov_length(iov, nr_segs);
+
+ if (rw == WRITE) {
+ loff_t final_size = offset + count;
+
+ handle = ext4_journal_start(inode, DIO_CREDITS);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ goto out;
+ }
+ if (final_size > inode->i_size) {
+ ret = ext4_orphan_add(handle, inode);
+ if (ret)
+ goto out_stop;
+ orphan = 1;
+ ei->i_disksize = inode->i_size;
+ }
+ }
+
+ ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ offset, nr_segs,
+ ext4_get_block, NULL);
+
+ /*
+ * Reacquire the handle: ext4_get_block() can restart the transaction
+ */
+ handle = journal_current_handle();
+
+out_stop:
+ if (handle) {
+ int err;
+
+ if (orphan && inode->i_nlink)
+ ext4_orphan_del(handle, inode);
+ if (orphan && ret > 0) {
+ loff_t end = offset + ret;
+ if (end > inode->i_size) {
+ ei->i_disksize = end;
+ i_size_write(inode, end);
+ /*
+ * We're going to return a positive `ret'
+ * here due to non-zero-length I/O, so there's
+ * no way of reporting error returns from
+ * ext4_mark_inode_dirty() to userspace. So
+ * ignore it.
+ */
+ ext4_mark_inode_dirty(handle, inode);
+ }
+ }
+ err = ext4_journal_stop(handle);
+ if (ret == 0)
+ ret = err;
+ }
+out:
+ return ret;
+}
+
+/*
+ * Pages can be marked dirty completely asynchronously from ext4's journalling
+ * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do
+ * much here because ->set_page_dirty is called under VFS locks. The page is
+ * not necessarily locked.
+ *
+ * We cannot just dirty the page and leave attached buffers clean, because the
+ * buffers' dirty state is "definitive". We cannot just set the buffers dirty
+ * or jbddirty because all the journalling code will explode.
+ *
+ * So what we do is to mark the page "pending dirty" and next time writepage
+ * is called, propagate that into the buffers appropriately.
+ */
+static int ext4_journalled_set_page_dirty(struct page *page)
+{
+ SetPageChecked(page);
+ return __set_page_dirty_nobuffers(page);
+}
+
+static const struct address_space_operations ext4_ordered_aops = {
+ .readpage = ext4_readpage,
+ .readpages = ext4_readpages,
+ .writepage = ext4_ordered_writepage,
+ .sync_page = block_sync_page,
+ .prepare_write = ext4_prepare_write,
+ .commit_write = ext4_ordered_commit_write,
+ .bmap = ext4_bmap,
+ .invalidatepage = ext4_invalidatepage,
+ .releasepage = ext4_releasepage,
+ .direct_IO = ext4_direct_IO,
+ .migratepage = buffer_migrate_page,
+};
+
+static const struct address_space_operations ext4_writeback_aops = {
+ .readpage = ext4_readpage,
+ .readpages = ext4_readpages,
+ .writepage = ext4_writeback_writepage,
+ .sync_page = block_sync_page,
+ .prepare_write = ext4_prepare_write,
+ .commit_write = ext4_writeback_commit_write,
+ .bmap = ext4_bmap,
+ .invalidatepage = ext4_invalidatepage,
+ .releasepage = ext4_releasepage,
+ .direct_IO = ext4_direct_IO,
+ .migratepage = buffer_migrate_page,
+};
+
+static const struct address_space_operations ext4_journalled_aops = {
+ .readpage = ext4_readpage,
+ .readpages = ext4_readpages,
+ .writepage = ext4_journalled_writepage,
+ .sync_page = block_sync_page,
+ .prepare_write = ext4_prepare_write,
+ .commit_write = ext4_journalled_commit_write,
+ .set_page_dirty = ext4_journalled_set_page_dirty,
+ .bmap = ext4_bmap,
+ .invalidatepage = ext4_invalidatepage,
+ .releasepage = ext4_releasepage,
+};
+
+void ext4_set_aops(struct inode *inode)
+{
+ if (ext4_should_order_data(inode))
+ inode->i_mapping->a_ops = &ext4_ordered_aops;
+ else if (ext4_should_writeback_data(inode))
+ inode->i_mapping->a_ops = &ext4_writeback_aops;
+ else
+ inode->i_mapping->a_ops = &ext4_journalled_aops;
+}
+
+/*
+ * ext4_block_truncate_page() zeroes out a mapping from file offset `from'
+ * up to the end of the block which corresponds to `from'.
+ * This required during truncate. We need to physically zero the tail end
+ * of that block so it doesn't yield old data if the file is later grown.
+ */
+int ext4_block_truncate_page(handle_t *handle, struct page *page,
+ struct address_space *mapping, loff_t from)
+{
+ ext4_fsblk_t index = from >> PAGE_CACHE_SHIFT;
+ unsigned offset = from & (PAGE_CACHE_SIZE-1);
+ unsigned blocksize, iblock, length, pos;
+ 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));
+ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+
+ /*
+ * For "nobh" option, we can only work if we don't need to
+ * read-in the page - otherwise we create buffers to do the IO.
+ */
+ if (!page_has_buffers(page) && test_opt(inode->i_sb, NOBH) &&
+ ext4_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);
+ set_page_dirty(page);
+ goto unlock;
+ }
+
+ if (!page_has_buffers(page))
+ create_empty_buffers(page, blocksize, 0);
+
+ /* Find the buffer that contains "offset" */
+ bh = page_buffers(page);
+ pos = blocksize;
+ while (offset >= pos) {
+ bh = bh->b_this_page;
+ iblock++;
+ pos += blocksize;
+ }
+
+ err = 0;
+ if (buffer_freed(bh)) {
+ BUFFER_TRACE(bh, "freed: skip");
+ goto unlock;
+ }
+
+ if (!buffer_mapped(bh)) {
+ BUFFER_TRACE(bh, "unmapped");
+ ext4_get_block(inode, iblock, bh, 0);
+ /* unmapped? It's a hole - nothing to do */
+ if (!buffer_mapped(bh)) {
+ BUFFER_TRACE(bh, "still unmapped");
+ goto unlock;
+ }
+ }
+
+ /* Ok, it's mapped. Make sure it's up-to-date */
+ if (PageUptodate(page))
+ set_buffer_uptodate(bh);
+
+ if (!buffer_uptodate(bh)) {
+ err = -EIO;
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ /* Uhhuh. Read error. Complain and punt. */
+ if (!buffer_uptodate(bh))
+ goto unlock;
+ }
+
+ if (ext4_should_journal_data(inode)) {
+ BUFFER_TRACE(bh, "get write access");
+ err = ext4_journal_get_write_access(handle, bh);
+ if (err)
+ goto unlock;
+ }
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, length);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ BUFFER_TRACE(bh, "zeroed end of block");
+
+ err = 0;
+ if (ext4_should_journal_data(inode)) {
+ err = ext4_journal_dirty_metadata(handle, bh);
+ } else {
+ if (ext4_should_order_data(inode))
+ err = ext4_journal_dirty_data(handle, bh);
+ mark_buffer_dirty(bh);
+ }
+
+unlock:
+ unlock_page(page);
+ page_cache_release(page);
+ return err;
+}
+
+/*
+ * Probably it should be a library function... search for first non-zero word
+ * or memcmp with zero_page, whatever is better for particular architecture.
+ * Linus?
+ */
+static inline int all_zeroes(__le32 *p, __le32 *q)
+{
+ while (p < q)
+ if (*p++)
+ return 0;
+ return 1;
+}
+
+/**
+ * ext4_find_shared - find the indirect blocks for partial truncation.
+ * @inode: inode in question
+ * @depth: depth of the affected branch
+ * @offsets: offsets of pointers in that branch (see ext4_block_to_path)
+ * @chain: place to store the pointers to partial indirect blocks
+ * @top: place to the (detached) top of branch
+ *
+ * This is a helper function used by ext4_truncate().
+ *
+ * When we do truncate() we may have to clean the ends of several
+ * indirect blocks but leave the blocks themselves alive. Block is
+ * partially truncated if some data below the new i_size is refered
+ * from it (and it is on the path to the first completely truncated
+ * data block, indeed). We have to free the top of that path along
+ * with everything to the right of the path. Since no allocation
+ * past the truncation point is possible until ext4_truncate()
+ * finishes, we may safely do the latter, but top of branch may
+ * require special attention - pageout below the truncation point
+ * might try to populate it.
+ *
+ * We atomically detach the top of branch from the tree, store the
+ * block number of its root in *@top, pointers to buffer_heads of
+ * partially truncated blocks - in @chain[].bh and pointers to
+ * their last elements that should not be removed - in
+ * @chain[].p. Return value is the pointer to last filled element
+ * of @chain.
+ *
+ * The work left to caller to do the actual freeing of subtrees:
+ * a) free the subtree starting from *@top
+ * b) free the subtrees whose roots are stored in
+ * (@chain[i].p+1 .. end of @chain[i].bh->b_data)
+ * c) free the subtrees growing from the inode past the @chain[0].
+ * (no partially truncated stuff there). */
+
+static Indirect *ext4_find_shared(struct inode *inode, int depth,
+ int offsets[4], Indirect chain[4], __le32 *top)
+{
+ Indirect *partial, *p;
+ int k, err;
+
+ *top = 0;
+ /* Make k index the deepest non-null offest + 1 */
+ for (k = depth; k > 1 && !offsets[k-1]; k--)
+ ;
+ partial = ext4_get_branch(inode, k, offsets, chain, &err);
+ /* Writer: pointers */
+ if (!partial)
+ partial = chain + k-1;
+ /*
+ * If the branch acquired continuation since we've looked at it -
+ * fine, it should all survive and (new) top doesn't belong to us.
+ */
+ if (!partial->key && *partial->p)
+ /* Writer: end */
+ goto no_top;
+ for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--)
+ ;
+ /*
+ * OK, we've found the last block that must survive. The rest of our
+ * branch should be detached before unlocking. However, if that rest
+ * of branch is all ours and does not grow immediately from the inode
+ * it's easier to cheat and just decrement partial->p.
+ */
+ if (p == chain + k - 1 && p > chain) {
+ p->p--;
+ } else {
+ *top = *p->p;
+ /* Nope, don't do this in ext4. Must leave the tree intact */
+#if 0
+ *p->p = 0;
+#endif
+ }
+ /* Writer: end */
+
+ while(partial > p) {
+ brelse(partial->bh);
+ partial--;
+ }
+no_top:
+ return partial;
+}
+
+/*
+ * Zero a number of block pointers in either an inode or an indirect block.
+ * If we restart the transaction we must again get write access to the
+ * indirect block for further modification.
+ *
+ * We release `count' blocks on disk, but (last - first) may be greater
+ * than `count' because there can be holes in there.
+ */
+static void ext4_clear_blocks(handle_t *handle, struct inode *inode,
+ struct buffer_head *bh, ext4_fsblk_t block_to_free,
+ unsigned long count, __le32 *first, __le32 *last)
+{
+ __le32 *p;
+ if (try_to_extend_transaction(handle, inode)) {
+ if (bh) {
+ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
+ ext4_journal_dirty_metadata(handle, bh);
+ }
+ ext4_mark_inode_dirty(handle, inode);
+ ext4_journal_test_restart(handle, inode);
+ if (bh) {
+ BUFFER_TRACE(bh, "retaking write access");
+ ext4_journal_get_write_access(handle, bh);
+ }
+ }
+
+ /*
+ * Any buffers which are on the journal will be in memory. We find
+ * them on the hash table so jbd2_journal_revoke() will run jbd2_journal_forget()
+ * on them. We've already detached each block from the file, so
+ * bforget() in jbd2_journal_forget() should be safe.
+ *
+ * AKPM: turn on bforget in jbd2_journal_forget()!!!
+ */
+ for (p = first; p < last; p++) {
+ u32 nr = le32_to_cpu(*p);
+ if (nr) {
+ struct buffer_head *bh;
+
+ *p = 0;
+ bh = sb_find_get_block(inode->i_sb, nr);
+ ext4_forget(handle, 0, inode, bh, nr);
+ }
+ }
+
+ ext4_free_blocks(handle, inode, block_to_free, count);
+}
+
+/**
+ * ext4_free_data - free a list of data blocks
+ * @handle: handle for this transaction
+ * @inode: inode we are dealing with
+ * @this_bh: indirect buffer_head which contains *@first and *@last
+ * @first: array of block numbers
+ * @last: points immediately past the end of array
+ *
+ * We are freeing all blocks refered from that array (numbers are stored as
+ * little-endian 32-bit) and updating @inode->i_blocks appropriately.
+ *
+ * We accumulate contiguous runs of blocks to free. Conveniently, if these
+ * blocks are contiguous then releasing them at one time will only affect one
+ * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't
+ * actually use a lot of journal space.
+ *
+ * @this_bh will be %NULL if @first and @last point into the inode's direct
+ * block pointers.
+ */
+static void ext4_free_data(handle_t *handle, struct inode *inode,
+ struct buffer_head *this_bh,
+ __le32 *first, __le32 *last)
+{
+ ext4_fsblk_t block_to_free = 0; /* Starting block # of a run */
+ unsigned long count = 0; /* Number of blocks in the run */
+ __le32 *block_to_free_p = NULL; /* Pointer into inode/ind
+ corresponding to
+ block_to_free */
+ ext4_fsblk_t nr; /* Current block # */
+ __le32 *p; /* Pointer into inode/ind
+ for current block */
+ int err;
+
+ if (this_bh) { /* For indirect block */
+ BUFFER_TRACE(this_bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, this_bh);
+ /* Important: if we can't update the indirect pointers
+ * to the blocks, we can't free them. */
+ if (err)
+ return;
+ }
+
+ for (p = first; p < last; p++) {
+ nr = le32_to_cpu(*p);
+ if (nr) {
+ /* accumulate blocks to free if they're contiguous */
+ if (count == 0) {
+ block_to_free = nr;
+ block_to_free_p = p;
+ count = 1;
+ } else if (nr == block_to_free + count) {
+ count++;
+ } else {
+ ext4_clear_blocks(handle, inode, this_bh,
+ block_to_free,
+ count, block_to_free_p, p);
+ block_to_free = nr;
+ block_to_free_p = p;
+ count = 1;
+ }
+ }
+ }
+
+ if (count > 0)
+ ext4_clear_blocks(handle, inode, this_bh, block_to_free,
+ count, block_to_free_p, p);
+
+ if (this_bh) {
+ BUFFER_TRACE(this_bh, "call ext4_journal_dirty_metadata");
+ ext4_journal_dirty_metadata(handle, this_bh);
+ }
+}
+
+/**
+ * ext4_free_branches - free an array of branches
+ * @handle: JBD handle for this transaction
+ * @inode: inode we are dealing with
+ * @parent_bh: the buffer_head which contains *@first and *@last
+ * @first: array of block numbers
+ * @last: pointer immediately past the end of array
+ * @depth: depth of the branches to free
+ *
+ * We are freeing all blocks refered from these branches (numbers are
+ * stored as little-endian 32-bit) and updating @inode->i_blocks
+ * appropriately.
+ */
+static void ext4_free_branches(handle_t *handle, struct inode *inode,
+ struct buffer_head *parent_bh,
+ __le32 *first, __le32 *last, int depth)
+{
+ ext4_fsblk_t nr;
+ __le32 *p;
+
+ if (is_handle_aborted(handle))
+ return;
+
+ if (depth--) {
+ struct buffer_head *bh;
+ int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
+ p = last;
+ while (--p >= first) {
+ nr = le32_to_cpu(*p);
+ if (!nr)
+ continue; /* A hole */
+
+ /* Go read the buffer for the next level down */
+ bh = sb_bread(inode->i_sb, nr);
+
+ /*
+ * A read failure? Report error and clear slot
+ * (should be rare).
+ */
+ if (!bh) {
+ ext4_error(inode->i_sb, "ext4_free_branches",
+ "Read failure, inode=%lu, block=%llu",
+ inode->i_ino, nr);
+ continue;
+ }
+
+ /* This zaps the entire block. Bottom up. */
+ BUFFER_TRACE(bh, "free child branches");
+ ext4_free_branches(handle, inode, bh,
+ (__le32*)bh->b_data,
+ (__le32*)bh->b_data + addr_per_block,
+ depth);
+
+ /*
+ * We've probably journalled the indirect block several
+ * times during the truncate. But it's no longer
+ * needed and we now drop it from the transaction via
+ * jbd2_journal_revoke().
+ *
+ * That's easy if it's exclusively part of this
+ * transaction. But if it's part of the committing
+ * transaction then jbd2_journal_forget() will simply
+ * brelse() it. That means that if the underlying
+ * block is reallocated in ext4_get_block(),
+ * unmap_underlying_metadata() will find this block
+ * and will try to get rid of it. damn, damn.
+ *
+ * If this block has already been committed to the
+ * journal, a revoke record will be written. And
+ * revoke records must be emitted *before* clearing
+ * this block's bit in the bitmaps.
+ */
+ ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
+
+ /*
+ * Everything below this this pointer has been
+ * released. Now let this top-of-subtree go.
+ *
+ * We want the freeing of this indirect block to be
+ * atomic in the journal with the updating of the
+ * bitmap block which owns it. So make some room in
+ * the journal.
+ *
+ * We zero the parent pointer *after* freeing its
+ * pointee in the bitmaps, so if extend_transaction()
+ * for some reason fails to put the bitmap changes and
+ * the release into the same transaction, recovery
+ * will merely complain about releasing a free block,
+ * rather than leaking blocks.
+ */
+ if (is_handle_aborted(handle))
+ return;
+ if (try_to_extend_transaction(handle, inode)) {
+ ext4_mark_inode_dirty(handle, inode);
+ ext4_journal_test_restart(handle, inode);
+ }
+
+ ext4_free_blocks(handle, inode, nr, 1);
+
+ if (parent_bh) {
+ /*
+ * The block which we have just freed is
+ * pointed to by an indirect block: journal it
+ */
+ BUFFER_TRACE(parent_bh, "get_write_access");
+ if (!ext4_journal_get_write_access(handle,
+ parent_bh)){
+ *p = 0;
+ BUFFER_TRACE(parent_bh,
+ "call ext4_journal_dirty_metadata");
+ ext4_journal_dirty_metadata(handle,
+ parent_bh);
+ }
+ }
+ }
+ } else {
+ /* We have reached the bottom of the tree. */
+ BUFFER_TRACE(parent_bh, "free data blocks");
+ ext4_free_data(handle, inode, parent_bh, first, last);
+ }
+}
+
+/*
+ * ext4_truncate()
+ *
+ * We block out ext4_get_block() block instantiations across the entire
+ * transaction, and VFS/VM ensures that ext4_truncate() cannot run
+ * simultaneously on behalf of the same inode.
+ *
+ * As we work through the truncate and commmit bits of it to the journal there
+ * is one core, guiding principle: the file's tree must always be consistent on
+ * disk. We must be able to restart the truncate after a crash.
+ *
+ * The file's tree may be transiently inconsistent in memory (although it
+ * probably isn't), but whenever we close off and commit a journal transaction,
+ * the contents of (the filesystem + the journal) must be consistent and
+ * restartable. It's pretty simple, really: bottom up, right to left (although
+ * left-to-right works OK too).
+ *
+ * Note that at recovery time, journal replay occurs *before* the restart of
+ * truncate against the orphan inode list.
+ *
+ * The committed inode has the new, desired i_size (which is the same as
+ * i_disksize in this case). After a crash, ext4_orphan_cleanup() will see
+ * that this inode's truncate did not complete and it will again call
+ * ext4_truncate() to have another go. So there will be instantiated blocks
+ * to the right of the truncation point in a crashed ext4 filesystem. But
+ * that's fine - as long as they are linked from the inode, the post-crash
+ * ext4_truncate() run will find them and release them.
+ */
+void ext4_truncate(struct inode *inode)
+{
+ handle_t *handle;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ __le32 *i_data = ei->i_data;
+ int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb);
+ struct address_space *mapping = inode->i_mapping;
+ int offsets[4];
+ Indirect chain[4];
+ Indirect *partial;
+ __le32 nr = 0;
+ int n;
+ long last_block;
+ unsigned blocksize = inode->i_sb->s_blocksize;
+ struct page *page;
+
+ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)))
+ return;
+ if (ext4_inode_is_fast_symlink(inode))
+ return;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ return;
+
+ /*
+ * We have to lock the EOF page here, because lock_page() nests
+ * outside jbd2_journal_start().
+ */
+ if ((inode->i_size & (blocksize - 1)) == 0) {
+ /* Block boundary? Nothing to do */
+ page = NULL;
+ } else {
+ page = grab_cache_page(mapping,
+ inode->i_size >> PAGE_CACHE_SHIFT);
+ if (!page)
+ return;
+ }
+
+ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
+ return ext4_ext_truncate(inode, page);
+
+ handle = start_transaction(inode);
+ if (IS_ERR(handle)) {
+ if (page) {
+ clear_highpage(page);
+ flush_dcache_page(page);
+ unlock_page(page);
+ page_cache_release(page);
+ }
+ return; /* AKPM: return what? */
+ }
+
+ last_block = (inode->i_size + blocksize-1)
+ >> EXT4_BLOCK_SIZE_BITS(inode->i_sb);
+
+ if (page)
+ ext4_block_truncate_page(handle, page, mapping, inode->i_size);
+
+ n = ext4_block_to_path(inode, last_block, offsets, NULL);
+ if (n == 0)
+ goto out_stop; /* error */
+
+ /*
+ * OK. This truncate is going to happen. We add the inode to the
+ * orphan list, so that if this truncate spans multiple transactions,
+ * and we crash, we will resume the truncate when the filesystem
+ * recovers. It also marks the inode dirty, to catch the new size.
+ *
+ * Implication: the file must always be in a sane, consistent
+ * truncatable state while each transaction commits.
+ */
+ if (ext4_orphan_add(handle, inode))
+ goto out_stop;
+
+ /*
+ * The orphan list entry will now protect us from any crash which
+ * occurs before the truncate completes, so it is now safe to propagate
+ * the new, shorter inode size (held for now in i_size) into the
+ * on-disk inode. We do this via i_disksize, which is the value which
+ * ext4 *really* writes onto the disk inode.
+ */
+ ei->i_disksize = inode->i_size;
+
+ /*
+ * From here we block out all ext4_get_block() callers who want to
+ * modify the block allocation tree.
+ */
+ mutex_lock(&ei->truncate_mutex);
+
+ if (n == 1) { /* direct blocks */
+ ext4_free_data(handle, inode, NULL, i_data+offsets[0],
+ i_data + EXT4_NDIR_BLOCKS);
+ goto do_indirects;
+ }
+
+ partial = ext4_find_shared(inode, n, offsets, chain, &nr);
+ /* Kill the top of shared branch (not detached) */
+ if (nr) {
+ if (partial == chain) {
+ /* Shared branch grows from the inode */
+ ext4_free_branches(handle, inode, NULL,
+ &nr, &nr+1, (chain+n-1) - partial);
+ *partial->p = 0;
+ /*
+ * We mark the inode dirty prior to restart,
+ * and prior to stop. No need for it here.
+ */
+ } else {
+ /* Shared branch grows from an indirect block */
+ BUFFER_TRACE(partial->bh, "get_write_access");
+ ext4_free_branches(handle, inode, partial->bh,
+ partial->p,
+ partial->p+1, (chain+n-1) - partial);
+ }
+ }
+ /* Clear the ends of indirect blocks on the shared branch */
+ while (partial > chain) {
+ ext4_free_branches(handle, inode, partial->bh, partial->p + 1,
+ (__le32*)partial->bh->b_data+addr_per_block,
+ (chain+n-1) - partial);
+ BUFFER_TRACE(partial->bh, "call brelse");
+ brelse (partial->bh);
+ partial--;
+ }
+do_indirects:
+ /* Kill the remaining (whole) subtrees */
+ switch (offsets[0]) {
+ default:
+ nr = i_data[EXT4_IND_BLOCK];
+ if (nr) {
+ ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1);
+ i_data[EXT4_IND_BLOCK] = 0;
+ }
+ case EXT4_IND_BLOCK:
+ nr = i_data[EXT4_DIND_BLOCK];
+ if (nr) {
+ ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2);
+ i_data[EXT4_DIND_BLOCK] = 0;
+ }
+ case EXT4_DIND_BLOCK:
+ nr = i_data[EXT4_TIND_BLOCK];
+ if (nr) {
+ ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3);
+ i_data[EXT4_TIND_BLOCK] = 0;
+ }
+ case EXT4_TIND_BLOCK:
+ ;
+ }
+
+ ext4_discard_reservation(inode);
+
+ mutex_unlock(&ei->truncate_mutex);
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
+ ext4_mark_inode_dirty(handle, inode);
+
+ /*
+ * In a multi-transaction truncate, we only make the final transaction
+ * synchronous
+ */
+ if (IS_SYNC(inode))
+ handle->h_sync = 1;
+out_stop:
+ /*
+ * If this was a simple ftruncate(), and the file will remain alive
+ * then we need to clear up the orphan record which we created above.
+ * However, if this was a real unlink then we were called by
+ * ext4_delete_inode(), and we allow that function to clean up the
+ * orphan info for us.
+ */
+ if (inode->i_nlink)
+ ext4_orphan_del(handle, inode);
+
+ ext4_journal_stop(handle);
+}
+
+static ext4_fsblk_t ext4_get_inode_block(struct super_block *sb,
+ unsigned long ino, struct ext4_iloc *iloc)
+{
+ unsigned long desc, group_desc, block_group;
+ unsigned long offset;
+ ext4_fsblk_t block;
+ struct buffer_head *bh;
+ struct ext4_group_desc * gdp;
+
+ if (!ext4_valid_inum(sb, ino)) {
+ /*
+ * This error is already checked for in namei.c unless we are
+ * looking at an NFS filehandle, in which case no error
+ * report is needed
+ */
+ return 0;
+ }
+
+ block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb);
+ if (block_group >= EXT4_SB(sb)->s_groups_count) {
+ ext4_error(sb,"ext4_get_inode_block","group >= groups count");
+ return 0;
+ }
+ smp_rmb();
+ group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
+ desc = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
+ bh = EXT4_SB(sb)->s_group_desc[group_desc];
+ if (!bh) {
+ ext4_error (sb, "ext4_get_inode_block",
+ "Descriptor not loaded");
+ return 0;
+ }
+
+ gdp = (struct ext4_group_desc *)((__u8 *)bh->b_data +
+ desc * EXT4_DESC_SIZE(sb));
+ /*
+ * Figure out the offset within the block group inode table
+ */
+ offset = ((ino - 1) % EXT4_INODES_PER_GROUP(sb)) *
+ EXT4_INODE_SIZE(sb);
+ block = ext4_inode_table(sb, gdp) +
+ (offset >> EXT4_BLOCK_SIZE_BITS(sb));
+
+ iloc->block_group = block_group;
+ iloc->offset = offset & (EXT4_BLOCK_SIZE(sb) - 1);
+ return block;
+}
+
+/*
+ * ext4_get_inode_loc returns with an extra refcount against the inode's
+ * underlying buffer_head on success. If 'in_mem' is true, we have all
+ * data in memory that is needed to recreate the on-disk version of this
+ * inode.
+ */
+static int __ext4_get_inode_loc(struct inode *inode,
+ struct ext4_iloc *iloc, int in_mem)
+{
+ ext4_fsblk_t block;
+ struct buffer_head *bh;
+
+ block = ext4_get_inode_block(inode->i_sb, inode->i_ino, iloc);
+ if (!block)
+ return -EIO;
+
+ bh = sb_getblk(inode->i_sb, block);
+ if (!bh) {
+ ext4_error (inode->i_sb, "ext4_get_inode_loc",
+ "unable to read inode block - "
+ "inode=%lu, block=%llu",
+ inode->i_ino, block);
+ return -EIO;
+ }
+ if (!buffer_uptodate(bh)) {
+ lock_buffer(bh);
+ if (buffer_uptodate(bh)) {
+ /* someone brought it uptodate while we waited */
+ unlock_buffer(bh);
+ goto has_buffer;
+ }
+
+ /*
+ * If we have all information of the inode in memory and this
+ * is the only valid inode in the block, we need not read the
+ * block.
+ */
+ if (in_mem) {
+ struct buffer_head *bitmap_bh;
+ struct ext4_group_desc *desc;
+ int inodes_per_buffer;
+ int inode_offset, i;
+ int block_group;
+ int start;
+
+ block_group = (inode->i_ino - 1) /
+ EXT4_INODES_PER_GROUP(inode->i_sb);
+ inodes_per_buffer = bh->b_size /
+ EXT4_INODE_SIZE(inode->i_sb);
+ inode_offset = ((inode->i_ino - 1) %
+ EXT4_INODES_PER_GROUP(inode->i_sb));
+ start = inode_offset & ~(inodes_per_buffer - 1);
+
+ /* Is the inode bitmap in cache? */
+ desc = ext4_get_group_desc(inode->i_sb,
+ block_group, NULL);
+ if (!desc)
+ goto make_io;
+
+ bitmap_bh = sb_getblk(inode->i_sb,
+ ext4_inode_bitmap(inode->i_sb, desc));
+ if (!bitmap_bh)
+ goto make_io;
+
+ /*
+ * If the inode bitmap isn't in cache then the
+ * optimisation may end up performing two reads instead
+ * of one, so skip it.
+ */
+ if (!buffer_uptodate(bitmap_bh)) {
+ brelse(bitmap_bh);
+ goto make_io;
+ }
+ for (i = start; i < start + inodes_per_buffer; i++) {
+ if (i == inode_offset)
+ continue;
+ if (ext4_test_bit(i, bitmap_bh->b_data))
+ break;
+ }
+ brelse(bitmap_bh);
+ if (i == start + inodes_per_buffer) {
+ /* all other inodes are free, so skip I/O */
+ memset(bh->b_data, 0, bh->b_size);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ goto has_buffer;
+ }
+ }
+
+make_io:
+ /*
+ * There are other valid inodes in the buffer, this inode
+ * has in-inode xattrs, or we don't have this inode in memory.
+ * Read the block from disk.
+ */
+ get_bh(bh);
+ bh->b_end_io = end_buffer_read_sync;
+ submit_bh(READ_META, bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ ext4_error(inode->i_sb, "ext4_get_inode_loc",
+ "unable to read inode block - "
+ "inode=%lu, block=%llu",
+ inode->i_ino, block);
+ brelse(bh);
+ return -EIO;
+ }
+ }
+has_buffer:
+ iloc->bh = bh;
+ return 0;
+}
+
+int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc)
+{
+ /* We have all inode data except xattrs in memory here. */
+ return __ext4_get_inode_loc(inode, iloc,
+ !(EXT4_I(inode)->i_state & EXT4_STATE_XATTR));
+}
+
+void ext4_set_inode_flags(struct inode *inode)
+{
+ unsigned int flags = EXT4_I(inode)->i_flags;
+
+ inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);
+ if (flags & EXT4_SYNC_FL)
+ inode->i_flags |= S_SYNC;
+ if (flags & EXT4_APPEND_FL)
+ inode->i_flags |= S_APPEND;
+ if (flags & EXT4_IMMUTABLE_FL)
+ inode->i_flags |= S_IMMUTABLE;
+ if (flags & EXT4_NOATIME_FL)
+ inode->i_flags |= S_NOATIME;
+ if (flags & EXT4_DIRSYNC_FL)
+ inode->i_flags |= S_DIRSYNC;
+}
+
+void ext4_read_inode(struct inode * inode)
+{
+ struct ext4_iloc iloc;
+ struct ext4_inode *raw_inode;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct buffer_head *bh;
+ int block;
+
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+ ei->i_acl = EXT4_ACL_NOT_CACHED;
+ ei->i_default_acl = EXT4_ACL_NOT_CACHED;
+#endif
+ ei->i_block_alloc_info = NULL;
+
+ if (__ext4_get_inode_loc(inode, &iloc, 0))
+ goto bad_inode;
+ bh = iloc.bh;
+ raw_inode = ext4_raw_inode(&iloc);
+ inode->i_mode = le16_to_cpu(raw_inode->i_mode);
+ inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
+ inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
+ if(!(test_opt (inode->i_sb, NO_UID32))) {
+ inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
+ inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
+ }
+ inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);
+ inode->i_size = le32_to_cpu(raw_inode->i_size);
+ inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime);
+ inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->i_ctime);
+ inode->i_mtime.tv_sec = le32_to_cpu(raw_inode->i_mtime);
+ inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0;
+
+ ei->i_state = 0;
+ ei->i_dir_start_lookup = 0;
+ ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
+ /* We now have enough fields to check if the inode was active or not.
+ * This is needed because nfsd might try to access dead inodes
+ * the test is that same one that e2fsck uses
+ * NeilBrown 1999oct15
+ */
+ if (inode->i_nlink == 0) {
+ if (inode->i_mode == 0 ||
+ !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) {
+ /* this inode is deleted */
+ brelse (bh);
+ goto bad_inode;
+ }
+ /* The only unlinked inodes we let through here have
+ * valid i_mode and are being read by the orphan
+ * recovery code: that's fine, we're about to complete
+ * the process of deleting those. */
+ }
+ inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
+ ei->i_flags = le32_to_cpu(raw_inode->i_flags);
+#ifdef EXT4_FRAGMENTS
+ ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
+ ei->i_frag_no = raw_inode->i_frag;
+ ei->i_frag_size = raw_inode->i_fsize;
+#endif
+ ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+ cpu_to_le32(EXT4_OS_HURD))
+ ei->i_file_acl |=
+ ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32;
+ if (!S_ISREG(inode->i_mode)) {
+ ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
+ } else {
+ inode->i_size |=
+ ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
+ }
+ ei->i_disksize = inode->i_size;
+ inode->i_generation = le32_to_cpu(raw_inode->i_generation);
+ ei->i_block_group = iloc.block_group;
+ /*
+ * NOTE! The in-memory inode i_data array is in little-endian order
+ * even on big-endian machines: we do NOT byteswap the block numbers!
+ */
+ for (block = 0; block < EXT4_N_BLOCKS; block++)
+ ei->i_data[block] = raw_inode->i_block[block];
+ INIT_LIST_HEAD(&ei->i_orphan);
+
+ if (inode->i_ino >= EXT4_FIRST_INO(inode->i_sb) + 1 &&
+ EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
+ /*
+ * When mke2fs creates big inodes it does not zero out
+ * the unused bytes above EXT4_GOOD_OLD_INODE_SIZE,
+ * so ignore those first few inodes.
+ */
+ ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize);
+ if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize >
+ EXT4_INODE_SIZE(inode->i_sb))
+ goto bad_inode;
+ if (ei->i_extra_isize == 0) {
+ /* The extra space is currently unused. Use it. */
+ ei->i_extra_isize = sizeof(struct ext4_inode) -
+ EXT4_GOOD_OLD_INODE_SIZE;
+ } else {
+ __le32 *magic = (void *)raw_inode +
+ EXT4_GOOD_OLD_INODE_SIZE +
+ ei->i_extra_isize;
+ if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC))
+ ei->i_state |= EXT4_STATE_XATTR;
+ }
+ } else
+ ei->i_extra_isize = 0;
+
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &ext4_file_inode_operations;
+ inode->i_fop = &ext4_file_operations;
+ ext4_set_aops(inode);
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &ext4_dir_inode_operations;
+ inode->i_fop = &ext4_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
+ if (ext4_inode_is_fast_symlink(inode))
+ inode->i_op = &ext4_fast_symlink_inode_operations;
+ else {
+ inode->i_op = &ext4_symlink_inode_operations;
+ ext4_set_aops(inode);
+ }
+ } else {
+ inode->i_op = &ext4_special_inode_operations;
+ if (raw_inode->i_block[0])
+ init_special_inode(inode, inode->i_mode,
+ old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));
+ else
+ init_special_inode(inode, inode->i_mode,
+ new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
+ }
+ brelse (iloc.bh);
+ ext4_set_inode_flags(inode);
+ return;
+
+bad_inode:
+ make_bad_inode(inode);
+ return;
+}
+
+/*
+ * Post the struct inode info into an on-disk inode location in the
+ * buffer-cache. This gobbles the caller's reference to the
+ * buffer_head in the inode location struct.
+ *
+ * The caller must have write access to iloc->bh.
+ */
+static int ext4_do_update_inode(handle_t *handle,
+ struct inode *inode,
+ struct ext4_iloc *iloc)
+{
+ struct ext4_inode *raw_inode = ext4_raw_inode(iloc);
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct buffer_head *bh = iloc->bh;
+ int err = 0, rc, block;
+
+ /* For fields not not tracking in the in-memory inode,
+ * initialise them to zero for new inodes. */
+ if (ei->i_state & EXT4_STATE_NEW)
+ memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
+
+ raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+ if(!(test_opt(inode->i_sb, NO_UID32))) {
+ raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid));
+ raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid));
+/*
+ * Fix up interoperability with old kernels. Otherwise, old inodes get
+ * re-used with the upper 16 bits of the uid/gid intact
+ */
+ if(!ei->i_dtime) {
+ raw_inode->i_uid_high =
+ cpu_to_le16(high_16_bits(inode->i_uid));
+ raw_inode->i_gid_high =
+ cpu_to_le16(high_16_bits(inode->i_gid));
+ } else {
+ raw_inode->i_uid_high = 0;
+ raw_inode->i_gid_high = 0;
+ }
+ } else {
+ raw_inode->i_uid_low =
+ cpu_to_le16(fs_high2lowuid(inode->i_uid));
+ raw_inode->i_gid_low =
+ cpu_to_le16(fs_high2lowgid(inode->i_gid));
+ raw_inode->i_uid_high = 0;
+ raw_inode->i_gid_high = 0;
+ }
+ raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
+ raw_inode->i_size = cpu_to_le32(ei->i_disksize);
+ raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
+ raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
+ raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);
+ raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
+ raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
+ raw_inode->i_flags = cpu_to_le32(ei->i_flags);
+#ifdef EXT4_FRAGMENTS
+ raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);
+ raw_inode->i_frag = ei->i_frag_no;
+ raw_inode->i_fsize = ei->i_frag_size;
+#endif
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+ cpu_to_le32(EXT4_OS_HURD))
+ raw_inode->i_file_acl_high =
+ cpu_to_le16(ei->i_file_acl >> 32);
+ raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);
+ if (!S_ISREG(inode->i_mode)) {
+ raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
+ } else {
+ raw_inode->i_size_high =
+ cpu_to_le32(ei->i_disksize >> 32);
+ if (ei->i_disksize > 0x7fffffffULL) {
+ struct super_block *sb = inode->i_sb;
+ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE) ||
+ EXT4_SB(sb)->s_es->s_rev_level ==
+ cpu_to_le32(EXT4_GOOD_OLD_REV)) {
+ /* If this is the first large file
+ * created, add a flag to the superblock.
+ */
+ err = ext4_journal_get_write_access(handle,
+ EXT4_SB(sb)->s_sbh);
+ if (err)
+ goto out_brelse;
+ ext4_update_dynamic_rev(sb);
+ EXT4_SET_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE);
+ sb->s_dirt = 1;
+ handle->h_sync = 1;
+ err = ext4_journal_dirty_metadata(handle,
+ EXT4_SB(sb)->s_sbh);
+ }
+ }
+ }
+ raw_inode->i_generation = cpu_to_le32(inode->i_generation);
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
+ if (old_valid_dev(inode->i_rdev)) {
+ raw_inode->i_block[0] =
+ cpu_to_le32(old_encode_dev(inode->i_rdev));
+ raw_inode->i_block[1] = 0;
+ } else {
+ raw_inode->i_block[0] = 0;
+ raw_inode->i_block[1] =
+ cpu_to_le32(new_encode_dev(inode->i_rdev));
+ raw_inode->i_block[2] = 0;
+ }
+ } else for (block = 0; block < EXT4_N_BLOCKS; block++)
+ raw_inode->i_block[block] = ei->i_data[block];
+
+ if (ei->i_extra_isize)
+ raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
+
+ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
+ rc = ext4_journal_dirty_metadata(handle, bh);
+ if (!err)
+ err = rc;
+ ei->i_state &= ~EXT4_STATE_NEW;
+
+out_brelse:
+ brelse (bh);
+ ext4_std_error(inode->i_sb, err);
+ return err;
+}
+
+/*
+ * ext4_write_inode()
+ *
+ * We are called from a few places:
+ *
+ * - Within generic_file_write() for O_SYNC files.
+ * Here, there will be no transaction running. We wait for any running
+ * trasnaction to commit.
+ *
+ * - Within sys_sync(), kupdate and such.
+ * We wait on commit, if tol to.
+ *
+ * - Within prune_icache() (PF_MEMALLOC == true)
+ * Here we simply return. We can't afford to block kswapd on the
+ * journal commit.
+ *
+ * In all cases it is actually safe for us to return without doing anything,
+ * because the inode has been copied into a raw inode buffer in
+ * ext4_mark_inode_dirty(). This is a correctness thing for O_SYNC and for
+ * knfsd.
+ *
+ * Note that we are absolutely dependent upon all inode dirtiers doing the
+ * right thing: they *must* call mark_inode_dirty() after dirtying info in
+ * which we are interested.
+ *
+ * It would be a bug for them to not do this. The code:
+ *
+ * mark_inode_dirty(inode)
+ * stuff();
+ * inode->i_size = expr;
+ *
+ * is in error because a kswapd-driven write_inode() could occur while
+ * `stuff()' is running, and the new i_size will be lost. Plus the inode
+ * will no longer be on the superblock's dirty inode list.
+ */
+int ext4_write_inode(struct inode *inode, int wait)
+{
+ if (current->flags & PF_MEMALLOC)
+ return 0;
+
+ if (ext4_journal_current_handle()) {
+ jbd_debug(0, "called recursively, non-PF_MEMALLOC!\n");
+ dump_stack();
+ return -EIO;
+ }
+
+ if (!wait)
+ return 0;
+
+ return ext4_force_commit(inode->i_sb);
+}
+
+/*
+ * ext4_setattr()
+ *
+ * Called from notify_change.
+ *
+ * We want to trap VFS attempts to truncate the file as soon as
+ * possible. In particular, we want to make sure that when the VFS
+ * shrinks i_size, we put the inode on the orphan list and modify
+ * i_disksize immediately, so that during the subsequent flushing of
+ * dirty pages and freeing of disk blocks, we can guarantee that any
+ * commit will leave the blocks being flushed in an unused state on
+ * disk. (On recovery, the inode will get truncated and the blocks will
+ * be freed, so we have a strong guarantee that no future commit will
+ * leave these blocks visible to the user.)
+ *
+ * Called with inode->sem down.
+ */
+int ext4_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error, rc = 0;
+ const unsigned int ia_valid = attr->ia_valid;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ return error;
+
+ if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+ handle_t *handle;
+
+ /* (user+group)*(old+new) structure, inode write (sb,
+ * inode block, ? - but truncate inode update has it) */
+ handle = ext4_journal_start(inode, 2*(EXT4_QUOTA_INIT_BLOCKS(inode->i_sb)+
+ EXT4_QUOTA_DEL_BLOCKS(inode->i_sb))+3);
+ if (IS_ERR(handle)) {
+ error = PTR_ERR(handle);
+ goto err_out;
+ }
+ error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+ if (error) {
+ ext4_journal_stop(handle);
+ return error;
+ }
+ /* Update corresponding info in inode so that everything is in
+ * one transaction */
+ if (attr->ia_valid & ATTR_UID)
+ inode->i_uid = attr->ia_uid;
+ if (attr->ia_valid & ATTR_GID)
+ inode->i_gid = attr->ia_gid;
+ error = ext4_mark_inode_dirty(handle, inode);
+ ext4_journal_stop(handle);
+ }
+
+ if (S_ISREG(inode->i_mode) &&
+ attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) {
+ handle_t *handle;
+
+ handle = ext4_journal_start(inode, 3);
+ if (IS_ERR(handle)) {
+ error = PTR_ERR(handle);
+ goto err_out;
+ }
+
+ error = ext4_orphan_add(handle, inode);
+ EXT4_I(inode)->i_disksize = attr->ia_size;
+ rc = ext4_mark_inode_dirty(handle, inode);
+ if (!error)
+ error = rc;
+ ext4_journal_stop(handle);
+ }
+
+ rc = inode_setattr(inode, attr);
+
+ /* If inode_setattr's call to ext4_truncate failed to get a
+ * transaction handle at all, we need to clean up the in-core
+ * orphan list manually. */
+ if (inode->i_nlink)
+ ext4_orphan_del(NULL, inode);
+
+ if (!rc && (ia_valid & ATTR_MODE))
+ rc = ext4_acl_chmod(inode);
+
+err_out:
+ ext4_std_error(inode->i_sb, error);
+ if (!error)
+ error = rc;
+ return error;
+}
+
+
+/*
+ * How many blocks doth make a writepage()?
+ *
+ * With N blocks per page, it may be:
+ * N data blocks
+ * 2 indirect block
+ * 2 dindirect
+ * 1 tindirect
+ * N+5 bitmap blocks (from the above)
+ * N+5 group descriptor summary blocks
+ * 1 inode block
+ * 1 superblock.
+ * 2 * EXT4_SINGLEDATA_TRANS_BLOCKS for the quote files
+ *
+ * 3 * (N + 5) + 2 + 2 * EXT4_SINGLEDATA_TRANS_BLOCKS
+ *
+ * With ordered or writeback data it's the same, less the N data blocks.
+ *
+ * If the inode's direct blocks can hold an integral number of pages then a
+ * page cannot straddle two indirect blocks, and we can only touch one indirect
+ * and dindirect block, and the "5" above becomes "3".
+ *
+ * This still overestimates under most circumstances. If we were to pass the
+ * start and end offsets in here as well we could do block_to_path() on each
+ * block and work out the exact number of indirects which are touched. Pah.
+ */
+
+int ext4_writepage_trans_blocks(struct inode *inode)
+{
+ int bpp = ext4_journal_blocks_per_page(inode);
+ int indirects = (EXT4_NDIR_BLOCKS % bpp) ? 5 : 3;
+ int ret;
+
+ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
+ return ext4_ext_writepage_trans_blocks(inode, bpp);
+
+ if (ext4_should_journal_data(inode))
+ ret = 3 * (bpp + indirects) + 2;
+ else
+ ret = 2 * (bpp + indirects) + 2;
+
+#ifdef CONFIG_QUOTA
+ /* We know that structure was already allocated during DQUOT_INIT so
+ * we will be updating only the data blocks + inodes */
+ ret += 2*EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
+#endif
+
+ return ret;
+}
+
+/*
+ * The caller must have previously called ext4_reserve_inode_write().
+ * Give this, we know that the caller already has write access to iloc->bh.
+ */
+int ext4_mark_iloc_dirty(handle_t *handle,
+ struct inode *inode, struct ext4_iloc *iloc)
+{
+ int err = 0;
+
+ /* the do_update_inode consumes one bh->b_count */
+ get_bh(iloc->bh);
+
+ /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */
+ err = ext4_do_update_inode(handle, inode, iloc);
+ put_bh(iloc->bh);
+ return err;
+}
+
+/*
+ * On success, We end up with an outstanding reference count against
+ * iloc->bh. This _must_ be cleaned up later.
+ */
+
+int
+ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
+ struct ext4_iloc *iloc)
+{
+ int err = 0;
+ if (handle) {
+ err = ext4_get_inode_loc(inode, iloc);
+ if (!err) {
+ BUFFER_TRACE(iloc->bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, iloc->bh);
+ if (err) {
+ brelse(iloc->bh);
+ iloc->bh = NULL;
+ }
+ }
+ }
+ ext4_std_error(inode->i_sb, err);
+ return err;
+}
+
+/*
+ * What we do here is to mark the in-core inode as clean with respect to inode
+ * dirtiness (it may still be data-dirty).
+ * This means that the in-core inode may be reaped by prune_icache
+ * without having to perform any I/O. This is a very good thing,
+ * because *any* task may call prune_icache - even ones which
+ * have a transaction open against a different journal.
+ *
+ * Is this cheating? Not really. Sure, we haven't written the
+ * inode out, but prune_icache isn't a user-visible syncing function.
+ * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync)
+ * we start and wait on commits.
+ *
+ * Is this efficient/effective? Well, we're being nice to the system
+ * by cleaning up our inodes proactively so they can be reaped
+ * without I/O. But we are potentially leaving up to five seconds'
+ * worth of inodes floating about which prune_icache wants us to
+ * write out. One way to fix that would be to get prune_icache()
+ * to do a write_super() to free up some memory. It has the desired
+ * effect.
+ */
+int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)
+{
+ struct ext4_iloc iloc;
+ int err;
+
+ might_sleep();
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (!err)
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+ return err;
+}
+
+/*
+ * ext4_dirty_inode() is called from __mark_inode_dirty()
+ *
+ * We're really interested in the case where a file is being extended.
+ * i_size has been changed by generic_commit_write() and we thus need
+ * to include the updated inode in the current transaction.
+ *
+ * Also, DQUOT_ALLOC_SPACE() will always dirty the inode when blocks
+ * are allocated to the file.
+ *
+ * If the inode is marked synchronous, we don't honour that here - doing
+ * so would cause a commit on atime updates, which we don't bother doing.
+ * We handle synchronous inodes at the highest possible level.
+ */
+void ext4_dirty_inode(struct inode *inode)
+{
+ handle_t *current_handle = ext4_journal_current_handle();
+ handle_t *handle;
+
+ handle = ext4_journal_start(inode, 2);
+ if (IS_ERR(handle))
+ goto out;
+ if (current_handle &&
+ current_handle->h_transaction != handle->h_transaction) {
+ /* This task has a transaction open against a different fs */
+ printk(KERN_EMERG "%s: transactions do not match!\n",
+ __FUNCTION__);
+ } else {
+ jbd_debug(5, "marking dirty. outer handle=%p\n",
+ current_handle);
+ ext4_mark_inode_dirty(handle, inode);
+ }
+ ext4_journal_stop(handle);
+out:
+ return;
+}
+
+#if 0
+/*
+ * Bind an inode's backing buffer_head into this transaction, to prevent
+ * it from being flushed to disk early. Unlike
+ * ext4_reserve_inode_write, this leaves behind no bh reference and
+ * returns no iloc structure, so the caller needs to repeat the iloc
+ * lookup to mark the inode dirty later.
+ */
+static int ext4_pin_inode(handle_t *handle, struct inode *inode)
+{
+ struct ext4_iloc iloc;
+
+ int err = 0;
+ if (handle) {
+ err = ext4_get_inode_loc(inode, &iloc);
+ if (!err) {
+ BUFFER_TRACE(iloc.bh, "get_write_access");
+ err = jbd2_journal_get_write_access(handle, iloc.bh);
+ if (!err)
+ err = ext4_journal_dirty_metadata(handle,
+ iloc.bh);
+ brelse(iloc.bh);
+ }
+ }
+ ext4_std_error(inode->i_sb, err);
+ return err;
+}
+#endif
+
+int ext4_change_inode_journal_flag(struct inode *inode, int val)
+{
+ journal_t *journal;
+ handle_t *handle;
+ int err;
+
+ /*
+ * We have to be very careful here: changing a data block's
+ * journaling status dynamically is dangerous. If we write a
+ * data block to the journal, change the status and then delete
+ * that block, we risk forgetting to revoke the old log record
+ * from the journal and so a subsequent replay can corrupt data.
+ * So, first we make sure that the journal is empty and that
+ * nobody is changing anything.
+ */
+
+ journal = EXT4_JOURNAL(inode);
+ if (is_journal_aborted(journal) || IS_RDONLY(inode))
+ return -EROFS;
+
+ jbd2_journal_lock_updates(journal);
+ jbd2_journal_flush(journal);
+
+ /*
+ * OK, there are no updates running now, and all cached data is
+ * synced to disk. We are now in a completely consistent state
+ * which doesn't have anything in the journal, and we know that
+ * no filesystem updates are running, so it is safe to modify
+ * the inode's in-core data-journaling state flag now.
+ */
+
+ if (val)
+ EXT4_I(inode)->i_flags |= EXT4_JOURNAL_DATA_FL;
+ else
+ EXT4_I(inode)->i_flags &= ~EXT4_JOURNAL_DATA_FL;
+ ext4_set_aops(inode);
+
+ jbd2_journal_unlock_updates(journal);
+
+ /* Finally we can mark the inode as dirty. */
+
+ handle = ext4_journal_start(inode, 1);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ err = ext4_mark_inode_dirty(handle, inode);
+ handle->h_sync = 1;
+ ext4_journal_stop(handle);
+ ext4_std_error(inode->i_sb, err);
+
+ return err;
+}
diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
new file mode 100644
index 000000000000..22a737c306c7
--- /dev/null
+++ b/fs/ext4/ioctl.c
@@ -0,0 +1,306 @@
+/*
+ * linux/fs/ext4/ioctl.c
+ *
+ * Copyright (C) 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ */
+
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/capability.h>
+#include <linux/ext4_fs.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/time.h>
+#include <linux/compat.h>
+#include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+
+int ext4_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ unsigned int flags;
+ unsigned short rsv_window_size;
+
+ ext4_debug ("cmd = %u, arg = %lu\n", cmd, arg);
+
+ switch (cmd) {
+ case EXT4_IOC_GETFLAGS:
+ flags = ei->i_flags & EXT4_FL_USER_VISIBLE;
+ return put_user(flags, (int __user *) arg);
+ case EXT4_IOC_SETFLAGS: {
+ handle_t *handle = NULL;
+ int err;
+ struct ext4_iloc iloc;
+ unsigned int oldflags;
+ unsigned int jflag;
+
+ if (IS_RDONLY(inode))
+ return -EROFS;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EACCES;
+
+ if (get_user(flags, (int __user *) arg))
+ return -EFAULT;
+
+ if (!S_ISDIR(inode->i_mode))
+ flags &= ~EXT4_DIRSYNC_FL;
+
+ mutex_lock(&inode->i_mutex);
+ oldflags = ei->i_flags;
+
+ /* The JOURNAL_DATA flag is modifiable only by root */
+ jflag = flags & EXT4_JOURNAL_DATA_FL;
+
+ /*
+ * The IMMUTABLE and APPEND_ONLY flags can only be changed by
+ * the relevant capability.
+ *
+ * This test looks nicer. Thanks to Pauline Middelink
+ */
+ if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) {
+ if (!capable(CAP_LINUX_IMMUTABLE)) {
+ mutex_unlock(&inode->i_mutex);
+ return -EPERM;
+ }
+ }
+
+ /*
+ * The JOURNAL_DATA flag can only be changed by
+ * the relevant capability.
+ */
+ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) {
+ if (!capable(CAP_SYS_RESOURCE)) {
+ mutex_unlock(&inode->i_mutex);
+ return -EPERM;
+ }
+ }
+
+
+ handle = ext4_journal_start(inode, 1);
+ if (IS_ERR(handle)) {
+ mutex_unlock(&inode->i_mutex);
+ return PTR_ERR(handle);
+ }
+ if (IS_SYNC(inode))
+ handle->h_sync = 1;
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err)
+ goto flags_err;
+
+ flags = flags & EXT4_FL_USER_MODIFIABLE;
+ flags |= oldflags & ~EXT4_FL_USER_MODIFIABLE;
+ ei->i_flags = flags;
+
+ ext4_set_inode_flags(inode);
+ inode->i_ctime = CURRENT_TIME_SEC;
+
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+flags_err:
+ ext4_journal_stop(handle);
+ if (err) {
+ mutex_unlock(&inode->i_mutex);
+ return err;
+ }
+
+ if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL))
+ err = ext4_change_inode_journal_flag(inode, jflag);
+ mutex_unlock(&inode->i_mutex);
+ return err;
+ }
+ case EXT4_IOC_GETVERSION:
+ case EXT4_IOC_GETVERSION_OLD:
+ return put_user(inode->i_generation, (int __user *) arg);
+ case EXT4_IOC_SETVERSION:
+ case EXT4_IOC_SETVERSION_OLD: {
+ handle_t *handle;
+ struct ext4_iloc iloc;
+ __u32 generation;
+ int err;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EPERM;
+ if (IS_RDONLY(inode))
+ return -EROFS;
+ if (get_user(generation, (int __user *) arg))
+ return -EFAULT;
+
+ handle = ext4_journal_start(inode, 1);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err == 0) {
+ inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_generation = generation;
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+ }
+ ext4_journal_stop(handle);
+ return err;
+ }
+#ifdef CONFIG_JBD_DEBUG
+ case EXT4_IOC_WAIT_FOR_READONLY:
+ /*
+ * This is racy - by the time we're woken up and running,
+ * the superblock could be released. And the module could
+ * have been unloaded. So sue me.
+ *
+ * Returns 1 if it slept, else zero.
+ */
+ {
+ struct super_block *sb = inode->i_sb;
+ DECLARE_WAITQUEUE(wait, current);
+ int ret = 0;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
+ if (timer_pending(&EXT4_SB(sb)->turn_ro_timer)) {
+ schedule();
+ ret = 1;
+ }
+ remove_wait_queue(&EXT4_SB(sb)->ro_wait_queue, &wait);
+ return ret;
+ }
+#endif
+ case EXT4_IOC_GETRSVSZ:
+ if (test_opt(inode->i_sb, RESERVATION)
+ && S_ISREG(inode->i_mode)
+ && ei->i_block_alloc_info) {
+ rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size;
+ return put_user(rsv_window_size, (int __user *)arg);
+ }
+ return -ENOTTY;
+ case EXT4_IOC_SETRSVSZ: {
+
+ if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode))
+ return -ENOTTY;
+
+ if (IS_RDONLY(inode))
+ return -EROFS;
+
+ if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+ return -EACCES;
+
+ if (get_user(rsv_window_size, (int __user *)arg))
+ return -EFAULT;
+
+ if (rsv_window_size > EXT4_MAX_RESERVE_BLOCKS)
+ rsv_window_size = EXT4_MAX_RESERVE_BLOCKS;
+
+ /*
+ * need to allocate reservation structure for this inode
+ * before set the window size
+ */
+ mutex_lock(&ei->truncate_mutex);
+ if (!ei->i_block_alloc_info)
+ ext4_init_block_alloc_info(inode);
+
+ if (ei->i_block_alloc_info){
+ struct ext4_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node;
+ rsv->rsv_goal_size = rsv_window_size;
+ }
+ mutex_unlock(&ei->truncate_mutex);
+ return 0;
+ }
+ case EXT4_IOC_GROUP_EXTEND: {
+ ext4_fsblk_t n_blocks_count;
+ struct super_block *sb = inode->i_sb;
+ int err;
+
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EPERM;
+
+ if (IS_RDONLY(inode))
+ return -EROFS;
+
+ if (get_user(n_blocks_count, (__u32 __user *)arg))
+ return -EFAULT;
+
+ err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count);
+ jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+ jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+ jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+
+ return err;
+ }
+ case EXT4_IOC_GROUP_ADD: {
+ struct ext4_new_group_data input;
+ struct super_block *sb = inode->i_sb;
+ int err;
+
+ if (!capable(CAP_SYS_RESOURCE))
+ return -EPERM;
+
+ if (IS_RDONLY(inode))
+ return -EROFS;
+
+ if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg,
+ sizeof(input)))
+ return -EFAULT;
+
+ err = ext4_group_add(sb, &input);
+ jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal);
+ jbd2_journal_flush(EXT4_SB(sb)->s_journal);
+ jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+
+ return err;
+ }
+
+ default:
+ return -ENOTTY;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ /* These are just misnamed, they actually get/put from/to user an int */
+ switch (cmd) {
+ case EXT4_IOC32_GETFLAGS:
+ cmd = EXT4_IOC_GETFLAGS;
+ break;
+ case EXT4_IOC32_SETFLAGS:
+ cmd = EXT4_IOC_SETFLAGS;
+ break;
+ case EXT4_IOC32_GETVERSION:
+ cmd = EXT4_IOC_GETVERSION;
+ break;
+ case EXT4_IOC32_SETVERSION:
+ cmd = EXT4_IOC_SETVERSION;
+ break;
+ case EXT4_IOC32_GROUP_EXTEND:
+ cmd = EXT4_IOC_GROUP_EXTEND;
+ break;
+ case EXT4_IOC32_GETVERSION_OLD:
+ cmd = EXT4_IOC_GETVERSION_OLD;
+ break;
+ case EXT4_IOC32_SETVERSION_OLD:
+ cmd = EXT4_IOC_SETVERSION_OLD;
+ break;
+#ifdef CONFIG_JBD_DEBUG
+ case EXT4_IOC32_WAIT_FOR_READONLY:
+ cmd = EXT4_IOC_WAIT_FOR_READONLY;
+ break;
+#endif
+ case EXT4_IOC32_GETRSVSZ:
+ cmd = EXT4_IOC_GETRSVSZ;
+ break;
+ case EXT4_IOC32_SETRSVSZ:
+ cmd = EXT4_IOC_SETRSVSZ;
+ break;
+ case EXT4_IOC_GROUP_ADD:
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ lock_kernel();
+ ret = ext4_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
+ unlock_kernel();
+ return ret;
+}
+#endif
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
new file mode 100644
index 000000000000..8b1bd03d20f5
--- /dev/null
+++ b/fs/ext4/namei.c
@@ -0,0 +1,2395 @@
+/*
+ * linux/fs/ext4/namei.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/namei.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ * Directory entry file type support and forward compatibility hooks
+ * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
+ * Hash Tree Directory indexing (c)
+ * Daniel Phillips, 2001
+ * Hash Tree Directory indexing porting
+ * Christopher Li, 2002
+ * Hash Tree Directory indexing cleanup
+ * Theodore Ts'o, 2002
+ */
+
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/jbd2.h>
+#include <linux/time.h>
+#include <linux/ext4_fs.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/quotaops.h>
+#include <linux/buffer_head.h>
+#include <linux/bio.h>
+#include <linux/smp_lock.h>
+
+#include "namei.h"
+#include "xattr.h"
+#include "acl.h"
+
+/*
+ * define how far ahead to read directories while searching them.
+ */
+#define NAMEI_RA_CHUNKS 2
+#define NAMEI_RA_BLOCKS 4
+#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b))
+
+static struct buffer_head *ext4_append(handle_t *handle,
+ struct inode *inode,
+ u32 *block, int *err)
+{
+ struct buffer_head *bh;
+
+ *block = inode->i_size >> inode->i_sb->s_blocksize_bits;
+
+ if ((bh = ext4_bread(handle, inode, *block, 1, err))) {
+ inode->i_size += inode->i_sb->s_blocksize;
+ EXT4_I(inode)->i_disksize = inode->i_size;
+ ext4_journal_get_write_access(handle,bh);
+ }
+ return bh;
+}
+
+#ifndef assert
+#define assert(test) J_ASSERT(test)
+#endif
+
+#ifndef swap
+#define swap(x, y) do { typeof(x) z = x; x = y; y = z; } while (0)
+#endif
+
+#ifdef DX_DEBUG
+#define dxtrace(command) command
+#else
+#define dxtrace(command)
+#endif
+
+struct fake_dirent
+{
+ __le32 inode;
+ __le16 rec_len;
+ u8 name_len;
+ u8 file_type;
+};
+
+struct dx_countlimit
+{
+ __le16 limit;
+ __le16 count;
+};
+
+struct dx_entry
+{
+ __le32 hash;
+ __le32 block;
+};
+
+/*
+ * dx_root_info is laid out so that if it should somehow get overlaid by a
+ * dirent the two low bits of the hash version will be zero. Therefore, the
+ * hash version mod 4 should never be 0. Sincerely, the paranoia department.
+ */
+
+struct dx_root
+{
+ struct fake_dirent dot;
+ char dot_name[4];
+ struct fake_dirent dotdot;
+ char dotdot_name[4];
+ struct dx_root_info
+ {
+ __le32 reserved_zero;
+ u8 hash_version;
+ u8 info_length; /* 8 */
+ u8 indirect_levels;
+ u8 unused_flags;
+ }
+ info;
+ struct dx_entry entries[0];
+};
+
+struct dx_node
+{
+ struct fake_dirent fake;
+ struct dx_entry entries[0];
+};
+
+
+struct dx_frame
+{
+ struct buffer_head *bh;
+ struct dx_entry *entries;
+ struct dx_entry *at;
+};
+
+struct dx_map_entry
+{
+ u32 hash;
+ u32 offs;
+};
+
+#ifdef CONFIG_EXT4_INDEX
+static inline unsigned dx_get_block (struct dx_entry *entry);
+static void dx_set_block (struct dx_entry *entry, unsigned value);
+static inline unsigned dx_get_hash (struct dx_entry *entry);
+static void dx_set_hash (struct dx_entry *entry, unsigned value);
+static unsigned dx_get_count (struct dx_entry *entries);
+static unsigned dx_get_limit (struct dx_entry *entries);
+static void dx_set_count (struct dx_entry *entries, unsigned value);
+static void dx_set_limit (struct dx_entry *entries, unsigned value);
+static unsigned dx_root_limit (struct inode *dir, unsigned infosize);
+static unsigned dx_node_limit (struct inode *dir);
+static struct dx_frame *dx_probe(struct dentry *dentry,
+ struct inode *dir,
+ struct dx_hash_info *hinfo,
+ struct dx_frame *frame,
+ int *err);
+static void dx_release (struct dx_frame *frames);
+static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
+ struct dx_hash_info *hinfo, struct dx_map_entry map[]);
+static void dx_sort_map(struct dx_map_entry *map, unsigned count);
+static struct ext4_dir_entry_2 *dx_move_dirents (char *from, char *to,
+ struct dx_map_entry *offsets, int count);
+static struct ext4_dir_entry_2* dx_pack_dirents (char *base, int size);
+static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
+static int ext4_htree_next_block(struct inode *dir, __u32 hash,
+ struct dx_frame *frame,
+ struct dx_frame *frames,
+ __u32 *start_hash);
+static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
+ struct ext4_dir_entry_2 **res_dir, int *err);
+static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
+ struct inode *inode);
+
+/*
+ * Future: use high four bits of block for coalesce-on-delete flags
+ * Mask them off for now.
+ */
+
+static inline unsigned dx_get_block (struct dx_entry *entry)
+{
+ return le32_to_cpu(entry->block) & 0x00ffffff;
+}
+
+static inline void dx_set_block (struct dx_entry *entry, unsigned value)
+{
+ entry->block = cpu_to_le32(value);
+}
+
+static inline unsigned dx_get_hash (struct dx_entry *entry)
+{
+ return le32_to_cpu(entry->hash);
+}
+
+static inline void dx_set_hash (struct dx_entry *entry, unsigned value)
+{
+ entry->hash = cpu_to_le32(value);
+}
+
+static inline unsigned dx_get_count (struct dx_entry *entries)
+{
+ return le16_to_cpu(((struct dx_countlimit *) entries)->count);
+}
+
+static inline unsigned dx_get_limit (struct dx_entry *entries)
+{
+ return le16_to_cpu(((struct dx_countlimit *) entries)->limit);
+}
+
+static inline void dx_set_count (struct dx_entry *entries, unsigned value)
+{
+ ((struct dx_countlimit *) entries)->count = cpu_to_le16(value);
+}
+
+static inline void dx_set_limit (struct dx_entry *entries, unsigned value)
+{
+ ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value);
+}
+
+static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize)
+{
+ unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) -
+ EXT4_DIR_REC_LEN(2) - infosize;
+ return 0? 20: entry_space / sizeof(struct dx_entry);
+}
+
+static inline unsigned dx_node_limit (struct inode *dir)
+{
+ unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0);
+ return 0? 22: entry_space / sizeof(struct dx_entry);
+}
+
+/*
+ * Debug
+ */
+#ifdef DX_DEBUG
+static void dx_show_index (char * label, struct dx_entry *entries)
+{
+ int i, n = dx_get_count (entries);
+ printk("%s index ", label);
+ for (i = 0; i < n; i++) {
+ printk("%x->%u ", i? dx_get_hash(entries + i) :
+ 0, dx_get_block(entries + i));
+ }
+ printk("\n");
+}
+
+struct stats
+{
+ unsigned names;
+ unsigned space;
+ unsigned bcount;
+};
+
+static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext4_dir_entry_2 *de,
+ int size, int show_names)
+{
+ unsigned names = 0, space = 0;
+ char *base = (char *) de;
+ struct dx_hash_info h = *hinfo;
+
+ printk("names: ");
+ while ((char *) de < base + size)
+ {
+ if (de->inode)
+ {
+ if (show_names)
+ {
+ int len = de->name_len;
+ char *name = de->name;
+ while (len--) printk("%c", *name++);
+ ext4fs_dirhash(de->name, de->name_len, &h);
+ printk(":%x.%u ", h.hash,
+ ((char *) de - base));
+ }
+ space += EXT4_DIR_REC_LEN(de->name_len);
+ names++;
+ }
+ de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+ printk("(%i)\n", names);
+ return (struct stats) { names, space, 1 };
+}
+
+struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir,
+ struct dx_entry *entries, int levels)
+{
+ unsigned blocksize = dir->i_sb->s_blocksize;
+ unsigned count = dx_get_count (entries), names = 0, space = 0, i;
+ unsigned bcount = 0;
+ struct buffer_head *bh;
+ int err;
+ printk("%i indexed blocks...\n", count);
+ for (i = 0; i < count; i++, entries++)
+ {
+ u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0;
+ u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash;
+ struct stats stats;
+ printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range);
+ if (!(bh = ext4_bread (NULL,dir, block, 0,&err))) continue;
+ stats = levels?
+ dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1):
+ dx_show_leaf(hinfo, (struct ext4_dir_entry_2 *) bh->b_data, blocksize, 0);
+ names += stats.names;
+ space += stats.space;
+ bcount += stats.bcount;
+ brelse (bh);
+ }
+ if (bcount)
+ printk("%snames %u, fullness %u (%u%%)\n", levels?"":" ",
+ names, space/bcount,(space/bcount)*100/blocksize);
+ return (struct stats) { names, space, bcount};
+}
+#endif /* DX_DEBUG */
+
+/*
+ * Probe for a directory leaf block to search.
+ *
+ * dx_probe can return ERR_BAD_DX_DIR, which means there was a format
+ * error in the directory index, and the caller should fall back to
+ * searching the directory normally. The callers of dx_probe **MUST**
+ * check for this error code, and make sure it never gets reflected
+ * back to userspace.
+ */
+static struct dx_frame *
+dx_probe(struct dentry *dentry, struct inode *dir,
+ struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err)
+{
+ unsigned count, indirect;
+ struct dx_entry *at, *entries, *p, *q, *m;
+ struct dx_root *root;
+ struct buffer_head *bh;
+ struct dx_frame *frame = frame_in;
+ u32 hash;
+
+ frame->bh = NULL;
+ if (dentry)
+ dir = dentry->d_parent->d_inode;
+ if (!(bh = ext4_bread (NULL,dir, 0, 0, err)))
+ goto fail;
+ root = (struct dx_root *) bh->b_data;
+ if (root->info.hash_version != DX_HASH_TEA &&
+ root->info.hash_version != DX_HASH_HALF_MD4 &&
+ root->info.hash_version != DX_HASH_LEGACY) {
+ ext4_warning(dir->i_sb, __FUNCTION__,
+ "Unrecognised inode hash code %d",
+ root->info.hash_version);
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail;
+ }
+ hinfo->hash_version = root->info.hash_version;
+ hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed;
+ if (dentry)
+ ext4fs_dirhash(dentry->d_name.name, dentry->d_name.len, hinfo);
+ hash = hinfo->hash;
+
+ if (root->info.unused_flags & 1) {
+ ext4_warning(dir->i_sb, __FUNCTION__,
+ "Unimplemented inode hash flags: %#06x",
+ root->info.unused_flags);
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail;
+ }
+
+ if ((indirect = root->info.indirect_levels) > 1) {
+ ext4_warning(dir->i_sb, __FUNCTION__,
+ "Unimplemented inode hash depth: %#06x",
+ root->info.indirect_levels);
+ brelse(bh);
+ *err = ERR_BAD_DX_DIR;
+ goto fail;
+ }
+
+ entries = (struct dx_entry *) (((char *)&root->info) +
+ root->info.info_length);
+ assert(dx_get_limit(entries) == dx_root_limit(dir,
+ root->info.info_length));
+ dxtrace (printk("Look up %x", hash));
+ while (1)
+ {
+ count = dx_get_count(entries);
+ assert (count && count <= dx_get_limit(entries));
+ p = entries + 1;
+ q = entries + count - 1;
+ while (p <= q)
+ {
+ m = p + (q - p)/2;
+ dxtrace(printk("."));
+ if (dx_get_hash(m) > hash)
+ q = m - 1;
+ else
+ p = m + 1;
+ }
+
+ if (0) // linear search cross check
+ {
+ unsigned n = count - 1;
+ at = entries;
+ while (n--)
+ {
+ dxtrace(printk(","));
+ if (dx_get_hash(++at) > hash)
+ {
+ at--;
+ break;
+ }
+ }
+ assert (at == p - 1);
+ }
+
+ at = p - 1;
+ dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at)));
+ frame->bh = bh;
+ frame->entries = entries;
+ frame->at = at;
+ if (!indirect--) return frame;
+ if (!(bh = ext4_bread (NULL,dir, dx_get_block(at), 0, err)))
+ goto fail2;
+ at = entries = ((struct dx_node *) bh->b_data)->entries;
+ assert (dx_get_limit(entries) == dx_node_limit (dir));
+ frame++;
+ }
+fail2:
+ while (frame >= frame_in) {
+ brelse(frame->bh);
+ frame--;
+ }
+fail:
+ return NULL;
+}
+
+static void dx_release (struct dx_frame *frames)
+{
+ if (frames[0].bh == NULL)
+ return;
+
+ if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels)
+ brelse(frames[1].bh);
+ brelse(frames[0].bh);
+}
+
+/*
+ * This function increments the frame pointer to search the next leaf
+ * block, and reads in the necessary intervening nodes if the search
+ * should be necessary. Whether or not the search is necessary is
+ * controlled by the hash parameter. If the hash value is even, then
+ * the search is only continued if the next block starts with that
+ * hash value. This is used if we are searching for a specific file.
+ *
+ * If the hash value is HASH_NB_ALWAYS, then always go to the next block.
+ *
+ * This function returns 1 if the caller should continue to search,
+ * or 0 if it should not. If there is an error reading one of the
+ * index blocks, it will a negative error code.
+ *
+ * If start_hash is non-null, it will be filled in with the starting
+ * hash of the next page.
+ */
+static int ext4_htree_next_block(struct inode *dir, __u32 hash,
+ struct dx_frame *frame,
+ struct dx_frame *frames,
+ __u32 *start_hash)
+{
+ struct dx_frame *p;
+ struct buffer_head *bh;
+ int err, num_frames = 0;
+ __u32 bhash;
+
+ p = frame;
+ /*
+ * Find the next leaf page by incrementing the frame pointer.
+ * If we run out of entries in the interior node, loop around and
+ * increment pointer in the parent node. When we break out of
+ * this loop, num_frames indicates the number of interior
+ * nodes need to be read.
+ */
+ while (1) {
+ if (++(p->at) < p->entries + dx_get_count(p->entries))
+ break;
+ if (p == frames)
+ return 0;
+ num_frames++;
+ p--;
+ }
+
+ /*
+ * If the hash is 1, then continue only if the next page has a
+ * continuation hash of any value. This is used for readdir
+ * handling. Otherwise, check to see if the hash matches the
+ * desired contiuation hash. If it doesn't, return since
+ * there's no point to read in the successive index pages.
+ */
+ bhash = dx_get_hash(p->at);
+ if (start_hash)
+ *start_hash = bhash;
+ if ((hash & 1) == 0) {
+ if ((bhash & ~1) != hash)
+ return 0;
+ }
+ /*
+ * If the hash is HASH_NB_ALWAYS, we always go to the next
+ * block so no check is necessary
+ */
+ while (num_frames--) {
+ if (!(bh = ext4_bread(NULL, dir, dx_get_block(p->at),
+ 0, &err)))
+ return err; /* Failure */
+ p++;
+ brelse (p->bh);
+ p->bh = bh;
+ p->at = p->entries = ((struct dx_node *) bh->b_data)->entries;
+ }
+ return 1;
+}
+
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+static inline struct ext4_dir_entry_2 *ext4_next_entry(struct ext4_dir_entry_2 *p)
+{
+ return (struct ext4_dir_entry_2 *)((char*)p + le16_to_cpu(p->rec_len));
+}
+
+/*
+ * This function fills a red-black tree with information from a
+ * directory block. It returns the number directory entries loaded
+ * into the tree. If there is an error it is returned in err.
+ */
+static int htree_dirblock_to_tree(struct file *dir_file,
+ struct inode *dir, int block,
+ struct dx_hash_info *hinfo,
+ __u32 start_hash, __u32 start_minor_hash)
+{
+ struct buffer_head *bh;
+ struct ext4_dir_entry_2 *de, *top;
+ int err, count = 0;
+
+ dxtrace(printk("In htree dirblock_to_tree: block %d\n", block));
+ if (!(bh = ext4_bread (NULL, dir, block, 0, &err)))
+ return err;
+
+ de = (struct ext4_dir_entry_2 *) bh->b_data;
+ top = (struct ext4_dir_entry_2 *) ((char *) de +
+ dir->i_sb->s_blocksize -
+ EXT4_DIR_REC_LEN(0));
+ for (; de < top; de = ext4_next_entry(de)) {
+ ext4fs_dirhash(de->name, de->name_len, hinfo);
+ if ((hinfo->hash < start_hash) ||
+ ((hinfo->hash == start_hash) &&
+ (hinfo->minor_hash < start_minor_hash)))
+ continue;
+ if (de->inode == 0)
+ continue;
+ if ((err = ext4_htree_store_dirent(dir_file,
+ hinfo->hash, hinfo->minor_hash, de)) != 0) {
+ brelse(bh);
+ return err;
+ }
+ count++;
+ }
+ brelse(bh);
+ return count;
+}
+
+
+/*
+ * This function fills a red-black tree with information from a
+ * directory. We start scanning the directory in hash order, starting
+ * at start_hash and start_minor_hash.
+ *
+ * This function returns the number of entries inserted into the tree,
+ * or a negative error code.
+ */
+int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+ __u32 start_minor_hash, __u32 *next_hash)
+{
+ struct dx_hash_info hinfo;
+ struct ext4_dir_entry_2 *de;
+ struct dx_frame frames[2], *frame;
+ struct inode *dir;
+ int block, err;
+ int count = 0;
+ int ret;
+ __u32 hashval;
+
+ dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
+ start_minor_hash));
+ dir = dir_file->f_dentry->d_inode;
+ if (!(EXT4_I(dir)->i_flags & EXT4_INDEX_FL)) {
+ hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
+ hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
+ count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo,
+ start_hash, start_minor_hash);
+ *next_hash = ~0;
+ return count;
+ }
+ hinfo.hash = start_hash;
+ hinfo.minor_hash = 0;
+ frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
+ if (!frame)
+ return err;
+
+ /* Add '.' and '..' from the htree header */
+ if (!start_hash && !start_minor_hash) {
+ de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
+ if ((err = ext4_htree_store_dirent(dir_file, 0, 0, de)) != 0)
+ goto errout;
+ count++;
+ }
+ if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) {
+ de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data;
+ de = ext4_next_entry(de);
+ if ((err = ext4_htree_store_dirent(dir_file, 2, 0, de)) != 0)
+ goto errout;
+ count++;
+ }
+
+ while (1) {
+ block = dx_get_block(frame->at);
+ ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo,
+ start_hash, start_minor_hash);
+ if (ret < 0) {
+ err = ret;
+ goto errout;
+ }
+ count += ret;
+ hashval = ~0;
+ ret = ext4_htree_next_block(dir, HASH_NB_ALWAYS,
+ frame, frames, &hashval);
+ *next_hash = hashval;
+ if (ret < 0) {
+ err = ret;
+ goto errout;
+ }
+ /*
+ * Stop if: (a) there are no more entries, or
+ * (b) we have inserted at least one entry and the
+ * next hash value is not a continuation
+ */
+ if ((ret == 0) ||
+ (count && ((hashval & 1) == 0)))
+ break;
+ }
+ dx_release(frames);
+ dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n",
+ count, *next_hash));
+ return count;
+errout:
+ dx_release(frames);
+ return (err);
+}
+
+
+/*
+ * Directory block splitting, compacting
+ */
+
+static int dx_make_map (struct ext4_dir_entry_2 *de, int size,
+ struct dx_hash_info *hinfo, struct dx_map_entry *map_tail)
+{
+ int count = 0;
+ char *base = (char *) de;
+ struct dx_hash_info h = *hinfo;
+
+ while ((char *) de < base + size)
+ {
+ if (de->name_len && de->inode) {
+ ext4fs_dirhash(de->name, de->name_len, &h);
+ map_tail--;
+ map_tail->hash = h.hash;
+ map_tail->offs = (u32) ((char *) de - base);
+ count++;
+ cond_resched();
+ }
+ /* XXX: do we need to check rec_len == 0 case? -Chris */
+ de = (struct ext4_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+ }
+ return count;
+}
+
+static void dx_sort_map (struct dx_map_entry *map, unsigned count)
+{
+ struct dx_map_entry *p, *q, *top = map + count - 1;
+ int more;
+ /* Combsort until bubble sort doesn't suck */
+ while (count > 2) {
+ count = count*10/13;
+ if (count - 9 < 2) /* 9, 10 -> 11 */
+ count = 11;
+ for (p = top, q = p - count; q >= map; p--, q--)
+ if (p->hash < q->hash)
+ swap(*p, *q);
+ }
+ /* Garden variety bubble sort */
+ do {
+ more = 0;
+ q = top;
+ while (q-- > map) {
+ if (q[1].hash >= q[0].hash)
+ continue;
+ swap(*(q+1), *q);
+ more = 1;
+ }
+ } while(more);
+}
+
+static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block)
+{
+ struct dx_entry *entries = frame->entries;
+ struct dx_entry *old = frame->at, *new = old + 1;
+ int count = dx_get_count(entries);
+
+ assert(count < dx_get_limit(entries));
+ assert(old < entries + count);
+ memmove(new + 1, new, (char *)(entries + count) - (char *)(new));
+ dx_set_hash(new, hash);
+ dx_set_block(new, block);
+ dx_set_count(entries, count + 1);
+}
+#endif
+
+
+static void ext4_update_dx_flag(struct inode *inode)
+{
+ if (!EXT4_HAS_COMPAT_FEATURE(inode->i_sb,
+ EXT4_FEATURE_COMPAT_DIR_INDEX))
+ EXT4_I(inode)->i_flags &= ~EXT4_INDEX_FL;
+}
+
+/*
+ * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure.
+ *
+ * `len <= EXT4_NAME_LEN' is guaranteed by caller.
+ * `de != NULL' is guaranteed by caller.
+ */
+static inline int ext4_match (int len, const char * const name,
+ struct ext4_dir_entry_2 * de)
+{
+ if (len != de->name_len)
+ return 0;
+ if (!de->inode)
+ return 0;
+ return !memcmp(name, de->name, len);
+}
+
+/*
+ * Returns 0 if not found, -1 on failure, and 1 on success
+ */
+static inline int search_dirblock(struct buffer_head * bh,
+ struct inode *dir,
+ struct dentry *dentry,
+ unsigned long offset,
+ struct ext4_dir_entry_2 ** res_dir)
+{
+ struct ext4_dir_entry_2 * de;
+ char * dlimit;
+ int de_len;
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len;
+
+ de = (struct ext4_dir_entry_2 *) bh->b_data;
+ dlimit = bh->b_data + dir->i_sb->s_blocksize;
+ while ((char *) de < dlimit) {
+ /* this code is executed quadratically often */
+ /* do minimal checking `by hand' */
+
+ if ((char *) de + namelen <= dlimit &&
+ ext4_match (namelen, name, de)) {
+ /* found a match - just to be sure, do a full check */
+ if (!ext4_check_dir_entry("ext4_find_entry",
+ dir, de, bh, offset))
+ return -1;
+ *res_dir = de;
+ return 1;
+ }
+ /* prevent looping on a bad block */
+ de_len = le16_to_cpu(de->rec_len);
+ if (de_len <= 0)
+ return -1;
+ offset += de_len;
+ de = (struct ext4_dir_entry_2 *) ((char *) de + de_len);
+ }
+ return 0;
+}
+
+
+/*
+ * ext4_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ *
+ * The returned buffer_head has ->b_count elevated. The caller is expected
+ * to brelse() it when appropriate.
+ */
+static struct buffer_head * ext4_find_entry (struct dentry *dentry,
+ struct ext4_dir_entry_2 ** res_dir)
+{
+ struct super_block * sb;
+ struct buffer_head * bh_use[NAMEI_RA_SIZE];
+ struct buffer_head * bh, *ret = NULL;
+ unsigned long start, block, b;
+ int ra_max = 0; /* Number of bh's in the readahead
+ buffer, bh_use[] */
+ int ra_ptr = 0; /* Current index into readahead
+ buffer */
+ int num = 0;
+ int nblocks, i, err;
+ struct inode *dir = dentry->d_parent->d_inode;
+ int namelen;
+ const u8 *name;
+ unsigned blocksize;
+
+ *res_dir = NULL;
+ sb = dir->i_sb;
+ blocksize = sb->s_blocksize;
+ namelen = dentry->d_name.len;
+ name = dentry->d_name.name;
+ if (namelen > EXT4_NAME_LEN)
+ return NULL;
+#ifdef CONFIG_EXT4_INDEX
+ if (is_dx(dir)) {
+ bh = ext4_dx_find_entry(dentry, res_dir, &err);
+ /*
+ * On success, or if the error was file not found,
+ * return. Otherwise, fall back to doing a search the
+ * old fashioned way.
+ */
+ if (bh || (err != ERR_BAD_DX_DIR))
+ return bh;
+ dxtrace(printk("ext4_find_entry: dx failed, falling back\n"));
+ }
+#endif
+ nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
+ start = EXT4_I(dir)->i_dir_start_lookup;
+ if (start >= nblocks)
+ start = 0;
+ block = start;
+restart:
+ do {
+ /*
+ * We deal with the read-ahead logic here.
+ */
+ if (ra_ptr >= ra_max) {
+ /* Refill the readahead buffer */
+ ra_ptr = 0;
+ b = block;
+ for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) {
+ /*
+ * Terminate if we reach the end of the
+ * directory and must wrap, or if our
+ * search has finished at this block.
+ */
+ if (b >= nblocks || (num && block == start)) {
+ bh_use[ra_max] = NULL;
+ break;
+ }
+ num++;
+ bh = ext4_getblk(NULL, dir, b++, 0, &err);
+ bh_use[ra_max] = bh;
+ if (bh)
+ ll_rw_block(READ_META, 1, &bh);
+ }
+ }
+ if ((bh = bh_use[ra_ptr++]) == NULL)
+ goto next;
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ /* read error, skip block & hope for the best */
+ ext4_error(sb, __FUNCTION__, "reading directory #%lu "
+ "offset %lu", dir->i_ino, block);
+ brelse(bh);
+ goto next;
+ }
+ i = search_dirblock(bh, dir, dentry,
+ block << EXT4_BLOCK_SIZE_BITS(sb), res_dir);
+ if (i == 1) {
+ EXT4_I(dir)->i_dir_start_lookup = block;
+ ret = bh;
+ goto cleanup_and_exit;
+ } else {
+ brelse(bh);
+ if (i < 0)
+ goto cleanup_and_exit;
+ }
+ next:
+ if (++block >= nblocks)
+ block = 0;
+ } while (block != start);
+
+ /*
+ * If the directory has grown while we were searching, then
+ * search the last part of the directory before giving up.
+ */
+ block = nblocks;
+ nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb);
+ if (block < nblocks) {
+ start = 0;
+ goto restart;
+ }
+
+cleanup_and_exit:
+ /* Clean up the read-ahead blocks */
+ for (; ra_ptr < ra_max; ra_ptr++)
+ brelse (bh_use[ra_ptr]);
+ return ret;
+}
+
+#ifdef CONFIG_EXT4_INDEX
+static struct buffer_head * ext4_dx_find_entry(struct dentry *dentry,
+ struct ext4_dir_entry_2 **res_dir, int *err)
+{
+ struct super_block * sb;
+ struct dx_hash_info hinfo;
+ u32 hash;
+ struct dx_frame frames[2], *frame;
+ struct ext4_dir_entry_2 *de, *top;
+ struct buffer_head *bh;
+ unsigned long block;
+ int retval;
+ int namelen = dentry->d_name.len;
+ const u8 *name = dentry->d_name.name;
+ struct inode *dir = dentry->d_parent->d_inode;
+
+ sb = dir->i_sb;
+ /* NFS may look up ".." - look at dx_root directory block */
+ if (namelen > 2 || name[0] != '.'||(name[1] != '.' && name[1] != '\0')){
+ if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err)))
+ return NULL;
+ } else {
+ frame = frames;
+ frame->bh = NULL; /* for dx_release() */
+ frame->at = (struct dx_entry *)frames; /* hack for zero entry*/
+ dx_set_block(frame->at, 0); /* dx_root block is 0 */
+ }
+ hash = hinfo.hash;
+ do {
+ block = dx_get_block(frame->at);
+ if (!(bh = ext4_bread (NULL,dir, block, 0, err)))
+ goto errout;
+ de = (struct ext4_dir_entry_2 *) bh->b_data;
+ top = (struct ext4_dir_entry_2 *) ((char *) de + sb->s_blocksize -
+ EXT4_DIR_REC_LEN(0));
+ for (; de < top; de = ext4_next_entry(de))
+ if (ext4_match (namelen, name, de)) {
+ if (!ext4_check_dir_entry("ext4_find_entry",
+ dir, de, bh,
+ (block<<EXT4_BLOCK_SIZE_BITS(sb))
+ +((char *)de - bh->b_data))) {
+ brelse (bh);
+ goto errout;
+ }
+ *res_dir = de;
+ dx_release (frames);
+ return bh;
+ }
+ brelse (bh);
+ /* Check to see if we should continue to search */
+ retval = ext4_htree_next_block(dir, hash, frame,
+ frames, NULL);
+ if (retval < 0) {
+ ext4_warning(sb, __FUNCTION__,
+ "error reading index page in directory #%lu",
+ dir->i_ino);
+ *err = retval;
+ goto errout;
+ }
+ } while (retval == 1);
+
+ *err = -ENOENT;
+errout:
+ dxtrace(printk("%s not found\n", name));
+ dx_release (frames);
+ return NULL;
+}
+#endif
+
+static struct dentry *ext4_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
+{
+ struct inode * inode;
+ struct ext4_dir_entry_2 * de;
+ struct buffer_head * bh;
+
+ if (dentry->d_name.len > EXT4_NAME_LEN)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ bh = ext4_find_entry(dentry, &de);
+ inode = NULL;
+ if (bh) {
+ unsigned long ino = le32_to_cpu(de->inode);
+ brelse (bh);
+ if (!ext4_valid_inum(dir->i_sb, ino)) {
+ ext4_error(dir->i_sb, "ext4_lookup",
+ "bad inode number: %lu", ino);
+ inode = NULL;
+ } else
+ inode = iget(dir->i_sb, ino);
+
+ if (!inode)
+ return ERR_PTR(-EACCES);
+ }
+ return d_splice_alias(inode, dentry);
+}
+
+
+struct dentry *ext4_get_parent(struct dentry *child)
+{
+ unsigned long ino;
+ struct dentry *parent;
+ struct inode *inode;
+ struct dentry dotdot;
+ struct ext4_dir_entry_2 * de;
+ struct buffer_head *bh;
+
+ dotdot.d_name.name = "..";
+ dotdot.d_name.len = 2;
+ dotdot.d_parent = child; /* confusing, isn't it! */
+
+ bh = ext4_find_entry(&dotdot, &de);
+ inode = NULL;
+ if (!bh)
+ return ERR_PTR(-ENOENT);
+ ino = le32_to_cpu(de->inode);
+ brelse(bh);
+
+ if (!ext4_valid_inum(child->d_inode->i_sb, ino)) {
+ ext4_error(child->d_inode->i_sb, "ext4_get_parent",
+ "bad inode number: %lu", ino);
+ inode = NULL;
+ } else
+ inode = iget(child->d_inode->i_sb, ino);
+
+ if (!inode)
+ return ERR_PTR(-EACCES);
+
+ parent = d_alloc_anon(inode);
+ if (!parent) {
+ iput(inode);
+ parent = ERR_PTR(-ENOMEM);
+ }
+ return parent;
+}
+
+#define S_SHIFT 12
+static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = {
+ [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
+ [S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
+ [S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
+ [S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV,
+ [S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO,
+ [S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK,
+ [S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK,
+};
+
+static inline void ext4_set_de_type(struct super_block *sb,
+ struct ext4_dir_entry_2 *de,
+ umode_t mode) {
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FILETYPE))
+ de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
+}
+
+#ifdef CONFIG_EXT4_INDEX
+static struct ext4_dir_entry_2 *
+dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count)
+{
+ unsigned rec_len = 0;
+
+ while (count--) {
+ struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) (from + map->offs);
+ rec_len = EXT4_DIR_REC_LEN(de->name_len);
+ memcpy (to, de, rec_len);
+ ((struct ext4_dir_entry_2 *) to)->rec_len =
+ cpu_to_le16(rec_len);
+ de->inode = 0;
+ map++;
+ to += rec_len;
+ }
+ return (struct ext4_dir_entry_2 *) (to - rec_len);
+}
+
+static struct ext4_dir_entry_2* dx_pack_dirents(char *base, int size)
+{
+ struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base;
+ unsigned rec_len = 0;
+
+ prev = to = de;
+ while ((char*)de < base + size) {
+ next = (struct ext4_dir_entry_2 *) ((char *) de +
+ le16_to_cpu(de->rec_len));
+ if (de->inode && de->name_len) {
+ rec_len = EXT4_DIR_REC_LEN(de->name_len);
+ if (de > to)
+ memmove(to, de, rec_len);
+ to->rec_len = cpu_to_le16(rec_len);
+ prev = to;
+ to = (struct ext4_dir_entry_2 *) (((char *) to) + rec_len);
+ }
+ de = next;
+ }
+ return prev;
+}
+
+static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
+ struct buffer_head **bh,struct dx_frame *frame,
+ struct dx_hash_info *hinfo, int *error)
+{
+ unsigned blocksize = dir->i_sb->s_blocksize;
+ unsigned count, continued;
+ struct buffer_head *bh2;
+ u32 newblock;
+ u32 hash2;
+ struct dx_map_entry *map;
+ char *data1 = (*bh)->b_data, *data2;
+ unsigned split;
+ struct ext4_dir_entry_2 *de = NULL, *de2;
+ int err;
+
+ bh2 = ext4_append (handle, dir, &newblock, error);
+ if (!(bh2)) {
+ brelse(*bh);
+ *bh = NULL;
+ goto errout;
+ }
+
+ BUFFER_TRACE(*bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, *bh);
+ if (err) {
+ journal_error:
+ brelse(*bh);
+ brelse(bh2);
+ *bh = NULL;
+ ext4_std_error(dir->i_sb, err);
+ goto errout;
+ }
+ BUFFER_TRACE(frame->bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, frame->bh);
+ if (err)
+ goto journal_error;
+
+ data2 = bh2->b_data;
+
+ /* create map in the end of data2 block */
+ map = (struct dx_map_entry *) (data2 + blocksize);
+ count = dx_make_map ((struct ext4_dir_entry_2 *) data1,
+ blocksize, hinfo, map);
+ map -= count;
+ split = count/2; // need to adjust to actual middle
+ dx_sort_map (map, count);
+ hash2 = map[split].hash;
+ continued = hash2 == map[split - 1].hash;
+ dxtrace(printk("Split block %i at %x, %i/%i\n",
+ dx_get_block(frame->at), hash2, split, count-split));
+
+ /* Fancy dance to stay within two buffers */
+ de2 = dx_move_dirents(data1, data2, map + split, count - split);
+ de = dx_pack_dirents(data1,blocksize);
+ de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
+ de2->rec_len = cpu_to_le16(data2 + blocksize - (char *) de2);
+ dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data1, blocksize, 1));
+ dxtrace(dx_show_leaf (hinfo, (struct ext4_dir_entry_2 *) data2, blocksize, 1));
+
+ /* Which block gets the new entry? */
+ if (hinfo->hash >= hash2)
+ {
+ swap(*bh, bh2);
+ de = de2;
+ }
+ dx_insert_block (frame, hash2 + continued, newblock);
+ err = ext4_journal_dirty_metadata (handle, bh2);
+ if (err)
+ goto journal_error;
+ err = ext4_journal_dirty_metadata (handle, frame->bh);
+ if (err)
+ goto journal_error;
+ brelse (bh2);
+ dxtrace(dx_show_index ("frame", frame->entries));
+errout:
+ return de;
+}
+#endif
+
+
+/*
+ * Add a new entry into a directory (leaf) block. If de is non-NULL,
+ * it points to a directory entry which is guaranteed to be large
+ * enough for new directory entry. If de is NULL, then
+ * add_dirent_to_buf will attempt search the directory block for
+ * space. It will return -ENOSPC if no space is available, and -EIO
+ * and -EEXIST if directory entry already exists.
+ *
+ * NOTE! bh is NOT released in the case where ENOSPC is returned. In
+ * all other cases bh is released.
+ */
+static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry,
+ struct inode *inode, struct ext4_dir_entry_2 *de,
+ struct buffer_head * bh)
+{
+ struct inode *dir = dentry->d_parent->d_inode;
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len;
+ unsigned long offset = 0;
+ unsigned short reclen;
+ int nlen, rlen, err;
+ char *top;
+
+ reclen = EXT4_DIR_REC_LEN(namelen);
+ if (!de) {
+ de = (struct ext4_dir_entry_2 *)bh->b_data;
+ top = bh->b_data + dir->i_sb->s_blocksize - reclen;
+ while ((char *) de <= top) {
+ if (!ext4_check_dir_entry("ext4_add_entry", dir, de,
+ bh, offset)) {
+ brelse (bh);
+ return -EIO;
+ }
+ if (ext4_match (namelen, name, de)) {
+ brelse (bh);
+ return -EEXIST;
+ }
+ nlen = EXT4_DIR_REC_LEN(de->name_len);
+ rlen = le16_to_cpu(de->rec_len);
+ if ((de->inode? rlen - nlen: rlen) >= reclen)
+ break;
+ de = (struct ext4_dir_entry_2 *)((char *)de + rlen);
+ offset += rlen;
+ }
+ if ((char *) de > top)
+ return -ENOSPC;
+ }
+ BUFFER_TRACE(bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, bh);
+ if (err) {
+ ext4_std_error(dir->i_sb, err);
+ brelse(bh);
+ return err;
+ }
+
+ /* By now the buffer is marked for journaling */
+ nlen = EXT4_DIR_REC_LEN(de->name_len);
+ rlen = le16_to_cpu(de->rec_len);
+ if (de->inode) {
+ struct ext4_dir_entry_2 *de1 = (struct ext4_dir_entry_2 *)((char *)de + nlen);
+ de1->rec_len = cpu_to_le16(rlen - nlen);
+ de->rec_len = cpu_to_le16(nlen);
+ de = de1;
+ }
+ de->file_type = EXT4_FT_UNKNOWN;
+ if (inode) {
+ de->inode = cpu_to_le32(inode->i_ino);
+ ext4_set_de_type(dir->i_sb, de, inode->i_mode);
+ } else
+ de->inode = 0;
+ de->name_len = namelen;
+ memcpy (de->name, name, namelen);
+ /*
+ * XXX shouldn't update any times until successful
+ * completion of syscall, but too many callers depend
+ * on this.
+ *
+ * XXX similarly, too many callers depend on
+ * ext4_new_inode() setting the times, but error
+ * recovery deletes the inode, so the worst that can
+ * happen is that the times are slightly out of date
+ * and/or different from the directory change time.
+ */
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ ext4_update_dx_flag(dir);
+ dir->i_version++;
+ ext4_mark_inode_dirty(handle, dir);
+ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
+ err = ext4_journal_dirty_metadata(handle, bh);
+ if (err)
+ ext4_std_error(dir->i_sb, err);
+ brelse(bh);
+ return 0;
+}
+
+#ifdef CONFIG_EXT4_INDEX
+/*
+ * This converts a one block unindexed directory to a 3 block indexed
+ * directory, and adds the dentry to the indexed directory.
+ */
+static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
+ struct inode *inode, struct buffer_head *bh)
+{
+ struct inode *dir = dentry->d_parent->d_inode;
+ const char *name = dentry->d_name.name;
+ int namelen = dentry->d_name.len;
+ struct buffer_head *bh2;
+ struct dx_root *root;
+ struct dx_frame frames[2], *frame;
+ struct dx_entry *entries;
+ struct ext4_dir_entry_2 *de, *de2;
+ char *data1, *top;
+ unsigned len;
+ int retval;
+ unsigned blocksize;
+ struct dx_hash_info hinfo;
+ u32 block;
+ struct fake_dirent *fde;
+
+ blocksize = dir->i_sb->s_blocksize;
+ dxtrace(printk("Creating index\n"));
+ retval = ext4_journal_get_write_access(handle, bh);
+ if (retval) {
+ ext4_std_error(dir->i_sb, retval);
+ brelse(bh);
+ return retval;
+ }
+ root = (struct dx_root *) bh->b_data;
+
+ bh2 = ext4_append (handle, dir, &block, &retval);
+ if (!(bh2)) {
+ brelse(bh);
+ return retval;
+ }
+ EXT4_I(dir)->i_flags |= EXT4_INDEX_FL;
+ data1 = bh2->b_data;
+
+ /* The 0th block becomes the root, move the dirents out */
+ fde = &root->dotdot;
+ de = (struct ext4_dir_entry_2 *)((char *)fde + le16_to_cpu(fde->rec_len));
+ len = ((char *) root) + blocksize - (char *) de;
+ memcpy (data1, de, len);
+ de = (struct ext4_dir_entry_2 *) data1;
+ top = data1 + len;
+ while ((char *)(de2=(void*)de+le16_to_cpu(de->rec_len)) < top)
+ de = de2;
+ de->rec_len = cpu_to_le16(data1 + blocksize - (char *) de);
+ /* Initialize the root; the dot dirents already exist */
+ de = (struct ext4_dir_entry_2 *) (&root->dotdot);
+ de->rec_len = cpu_to_le16(blocksize - EXT4_DIR_REC_LEN(2));
+ memset (&root->info, 0, sizeof(root->info));
+ root->info.info_length = sizeof(root->info);
+ root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version;
+ entries = root->entries;
+ dx_set_block (entries, 1);
+ dx_set_count (entries, 1);
+ dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info)));
+
+ /* Initialize as for dx_probe */
+ hinfo.hash_version = root->info.hash_version;
+ hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
+ ext4fs_dirhash(name, namelen, &hinfo);
+ frame = frames;
+ frame->entries = entries;
+ frame->at = entries;
+ frame->bh = bh;
+ bh = bh2;
+ de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
+ dx_release (frames);
+ if (!(de))
+ return retval;
+
+ return add_dirent_to_buf(handle, dentry, inode, de, bh);
+}
+#endif
+
+/*
+ * ext4_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as ext4_find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static int ext4_add_entry (handle_t *handle, struct dentry *dentry,
+ struct inode *inode)
+{
+ struct inode *dir = dentry->d_parent->d_inode;
+ unsigned long offset;
+ struct buffer_head * bh;
+ struct ext4_dir_entry_2 *de;
+ struct super_block * sb;
+ int retval;
+#ifdef CONFIG_EXT4_INDEX
+ int dx_fallback=0;
+#endif
+ unsigned blocksize;
+ u32 block, blocks;
+
+ sb = dir->i_sb;
+ blocksize = sb->s_blocksize;
+ if (!dentry->d_name.len)
+ return -EINVAL;
+#ifdef CONFIG_EXT4_INDEX
+ if (is_dx(dir)) {
+ retval = ext4_dx_add_entry(handle, dentry, inode);
+ if (!retval || (retval != ERR_BAD_DX_DIR))
+ return retval;
+ EXT4_I(dir)->i_flags &= ~EXT4_INDEX_FL;
+ dx_fallback++;
+ ext4_mark_inode_dirty(handle, dir);
+ }
+#endif
+ blocks = dir->i_size >> sb->s_blocksize_bits;
+ for (block = 0, offset = 0; block < blocks; block++) {
+ bh = ext4_bread(handle, dir, block, 0, &retval);
+ if(!bh)
+ return retval;
+ retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
+ if (retval != -ENOSPC)
+ return retval;
+
+#ifdef CONFIG_EXT4_INDEX
+ if (blocks == 1 && !dx_fallback &&
+ EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
+ return make_indexed_dir(handle, dentry, inode, bh);
+#endif
+ brelse(bh);
+ }
+ bh = ext4_append(handle, dir, &block, &retval);
+ if (!bh)
+ return retval;
+ de = (struct ext4_dir_entry_2 *) bh->b_data;
+ de->inode = 0;
+ de->rec_len = cpu_to_le16(blocksize);
+ return add_dirent_to_buf(handle, dentry, inode, de, bh);
+}
+
+#ifdef CONFIG_EXT4_INDEX
+/*
+ * Returns 0 for success, or a negative error value
+ */
+static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,
+ struct inode *inode)
+{
+ struct dx_frame frames[2], *frame;
+ struct dx_entry *entries, *at;
+ struct dx_hash_info hinfo;
+ struct buffer_head * bh;
+ struct inode *dir = dentry->d_parent->d_inode;
+ struct super_block * sb = dir->i_sb;
+ struct ext4_dir_entry_2 *de;
+ int err;
+
+ frame = dx_probe(dentry, NULL, &hinfo, frames, &err);
+ if (!frame)
+ return err;
+ entries = frame->entries;
+ at = frame->at;
+
+ if (!(bh = ext4_bread(handle,dir, dx_get_block(frame->at), 0, &err)))
+ goto cleanup;
+
+ BUFFER_TRACE(bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, bh);
+ if (err)
+ goto journal_error;
+
+ err = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
+ if (err != -ENOSPC) {
+ bh = NULL;
+ goto cleanup;
+ }
+
+ /* Block full, should compress but for now just split */
+ dxtrace(printk("using %u of %u node entries\n",
+ dx_get_count(entries), dx_get_limit(entries)));
+ /* Need to split index? */
+ if (dx_get_count(entries) == dx_get_limit(entries)) {
+ u32 newblock;
+ unsigned icount = dx_get_count(entries);
+ int levels = frame - frames;
+ struct dx_entry *entries2;
+ struct dx_node *node2;
+ struct buffer_head *bh2;
+
+ if (levels && (dx_get_count(frames->entries) ==
+ dx_get_limit(frames->entries))) {
+ ext4_warning(sb, __FUNCTION__,
+ "Directory index full!");
+ err = -ENOSPC;
+ goto cleanup;
+ }
+ bh2 = ext4_append (handle, dir, &newblock, &err);
+ if (!(bh2))
+ goto cleanup;
+ node2 = (struct dx_node *)(bh2->b_data);
+ entries2 = node2->entries;
+ node2->fake.rec_len = cpu_to_le16(sb->s_blocksize);
+ node2->fake.inode = 0;
+ BUFFER_TRACE(frame->bh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, frame->bh);
+ if (err)
+ goto journal_error;
+ if (levels) {
+ unsigned icount1 = icount/2, icount2 = icount - icount1;
+ unsigned hash2 = dx_get_hash(entries + icount1);
+ dxtrace(printk("Split index %i/%i\n", icount1, icount2));
+
+ BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */
+ err = ext4_journal_get_write_access(handle,
+ frames[0].bh);
+ if (err)
+ goto journal_error;
+
+ memcpy ((char *) entries2, (char *) (entries + icount1),
+ icount2 * sizeof(struct dx_entry));
+ dx_set_count (entries, icount1);
+ dx_set_count (entries2, icount2);
+ dx_set_limit (entries2, dx_node_limit(dir));
+
+ /* Which index block gets the new entry? */
+ if (at - entries >= icount1) {
+ frame->at = at = at - entries - icount1 + entries2;
+ frame->entries = entries = entries2;
+ swap(frame->bh, bh2);
+ }
+ dx_insert_block (frames + 0, hash2, newblock);
+ dxtrace(dx_show_index ("node", frames[1].entries));
+ dxtrace(dx_show_index ("node",
+ ((struct dx_node *) bh2->b_data)->entries));
+ err = ext4_journal_dirty_metadata(handle, bh2);
+ if (err)
+ goto journal_error;
+ brelse (bh2);
+ } else {
+ dxtrace(printk("Creating second level index...\n"));
+ memcpy((char *) entries2, (char *) entries,
+ icount * sizeof(struct dx_entry));
+ dx_set_limit(entries2, dx_node_limit(dir));
+
+ /* Set up root */
+ dx_set_count(entries, 1);
+ dx_set_block(entries + 0, newblock);
+ ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1;
+
+ /* Add new access path frame */
+ frame = frames + 1;
+ frame->at = at = at - entries + entries2;
+ frame->entries = entries = entries2;
+ frame->bh = bh2;
+ err = ext4_journal_get_write_access(handle,
+ frame->bh);
+ if (err)
+ goto journal_error;
+ }
+ ext4_journal_dirty_metadata(handle, frames[0].bh);
+ }
+ de = do_split(handle, dir, &bh, frame, &hinfo, &err);
+ if (!de)
+ goto cleanup;
+ err = add_dirent_to_buf(handle, dentry, inode, de, bh);
+ bh = NULL;
+ goto cleanup;
+
+journal_error:
+ ext4_std_error(dir->i_sb, err);
+cleanup:
+ if (bh)
+ brelse(bh);
+ dx_release(frames);
+ return err;
+}
+#endif
+
+/*
+ * ext4_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+static int ext4_delete_entry (handle_t *handle,
+ struct inode * dir,
+ struct ext4_dir_entry_2 * de_del,
+ struct buffer_head * bh)
+{
+ struct ext4_dir_entry_2 * de, * pde;
+ int i;
+
+ i = 0;
+ pde = NULL;
+ de = (struct ext4_dir_entry_2 *) bh->b_data;
+ while (i < bh->b_size) {
+ if (!ext4_check_dir_entry("ext4_delete_entry", dir, de, bh, i))
+ return -EIO;
+ if (de == de_del) {
+ BUFFER_TRACE(bh, "get_write_access");
+ ext4_journal_get_write_access(handle, bh);
+ if (pde)
+ pde->rec_len =
+ cpu_to_le16(le16_to_cpu(pde->rec_len) +
+ le16_to_cpu(de->rec_len));
+ else
+ de->inode = 0;
+ dir->i_version++;
+ BUFFER_TRACE(bh, "call ext4_journal_dirty_metadata");
+ ext4_journal_dirty_metadata(handle, bh);
+ return 0;
+ }
+ i += le16_to_cpu(de->rec_len);
+ pde = de;
+ de = (struct ext4_dir_entry_2 *)
+ ((char *) de + le16_to_cpu(de->rec_len));
+ }
+ return -ENOENT;
+}
+
+/*
+ * ext4_mark_inode_dirty is somewhat expensive, so unlike ext2 we
+ * do not perform it in these functions. We perform it at the call site,
+ * if it is needed.
+ */
+static inline void ext4_inc_count(handle_t *handle, struct inode *inode)
+{
+ inc_nlink(inode);
+}
+
+static inline void ext4_dec_count(handle_t *handle, struct inode *inode)
+{
+ drop_nlink(inode);
+}
+
+static int ext4_add_nondir(handle_t *handle,
+ struct dentry *dentry, struct inode *inode)
+{
+ int err = ext4_add_entry(handle, dentry, inode);
+ if (!err) {
+ ext4_mark_inode_dirty(handle, inode);
+ d_instantiate(dentry, inode);
+ return 0;
+ }
+ ext4_dec_count(handle, inode);
+ iput(inode);
+ return err;
+}
+
+/*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+ * is so far negative - it has no inode.
+ *
+ * If the create succeeds, we fill in the inode information
+ * with d_instantiate().
+ */
+static int ext4_create (struct inode * dir, struct dentry * dentry, int mode,
+ struct nameidata *nd)
+{
+ handle_t *handle;
+ struct inode * inode;
+ int err, retries = 0;
+
+retry:
+ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+ inode = ext4_new_inode (handle, dir, mode);
+ err = PTR_ERR(inode);
+ if (!IS_ERR(inode)) {
+ inode->i_op = &ext4_file_inode_operations;
+ inode->i_fop = &ext4_file_operations;
+ ext4_set_aops(inode);
+ err = ext4_add_nondir(handle, dentry, inode);
+ }
+ ext4_journal_stop(handle);
+ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+ goto retry;
+ return err;
+}
+
+static int ext4_mknod (struct inode * dir, struct dentry *dentry,
+ int mode, dev_t rdev)
+{
+ handle_t *handle;
+ struct inode *inode;
+ int err, retries = 0;
+
+ if (!new_valid_dev(rdev))
+ return -EINVAL;
+
+retry:
+ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+ inode = ext4_new_inode (handle, dir, mode);
+ err = PTR_ERR(inode);
+ if (!IS_ERR(inode)) {
+ init_special_inode(inode, inode->i_mode, rdev);
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ inode->i_op = &ext4_special_inode_operations;
+#endif
+ err = ext4_add_nondir(handle, dentry, inode);
+ }
+ ext4_journal_stop(handle);
+ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+ goto retry;
+ return err;
+}
+
+static int ext4_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+ handle_t *handle;
+ struct inode * inode;
+ struct buffer_head * dir_block;
+ struct ext4_dir_entry_2 * de;
+ int err, retries = 0;
+
+ if (dir->i_nlink >= EXT4_LINK_MAX)
+ return -EMLINK;
+
+retry:
+ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3 +
+ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+ inode = ext4_new_inode (handle, dir, S_IFDIR | mode);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
+ goto out_stop;
+
+ inode->i_op = &ext4_dir_inode_operations;
+ inode->i_fop = &ext4_dir_operations;
+ inode->i_size = EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize;
+ dir_block = ext4_bread (handle, inode, 0, 1, &err);
+ if (!dir_block) {
+ drop_nlink(inode); /* is this nlink == 0? */
+ ext4_mark_inode_dirty(handle, inode);
+ iput (inode);
+ goto out_stop;
+ }
+ BUFFER_TRACE(dir_block, "get_write_access");
+ ext4_journal_get_write_access(handle, dir_block);
+ de = (struct ext4_dir_entry_2 *) dir_block->b_data;
+ de->inode = cpu_to_le32(inode->i_ino);
+ de->name_len = 1;
+ de->rec_len = cpu_to_le16(EXT4_DIR_REC_LEN(de->name_len));
+ strcpy (de->name, ".");
+ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
+ de = (struct ext4_dir_entry_2 *)
+ ((char *) de + le16_to_cpu(de->rec_len));
+ de->inode = cpu_to_le32(dir->i_ino);
+ de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize-EXT4_DIR_REC_LEN(1));
+ de->name_len = 2;
+ strcpy (de->name, "..");
+ ext4_set_de_type(dir->i_sb, de, S_IFDIR);
+ inode->i_nlink = 2;
+ BUFFER_TRACE(dir_block, "call ext4_journal_dirty_metadata");
+ ext4_journal_dirty_metadata(handle, dir_block);
+ brelse (dir_block);
+ ext4_mark_inode_dirty(handle, inode);
+ err = ext4_add_entry (handle, dentry, inode);
+ if (err) {
+ inode->i_nlink = 0;
+ ext4_mark_inode_dirty(handle, inode);
+ iput (inode);
+ goto out_stop;
+ }
+ inc_nlink(dir);
+ ext4_update_dx_flag(dir);
+ ext4_mark_inode_dirty(handle, dir);
+ d_instantiate(dentry, inode);
+out_stop:
+ ext4_journal_stop(handle);
+ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+ goto retry;
+ return err;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int empty_dir (struct inode * inode)
+{
+ unsigned long offset;
+ struct buffer_head * bh;
+ struct ext4_dir_entry_2 * de, * de1;
+ struct super_block * sb;
+ int err = 0;
+
+ sb = inode->i_sb;
+ if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2) ||
+ !(bh = ext4_bread (NULL, inode, 0, 0, &err))) {
+ if (err)
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "error %d reading directory #%lu offset 0",
+ err, inode->i_ino);
+ else
+ ext4_warning(inode->i_sb, __FUNCTION__,
+ "bad directory (dir #%lu) - no data block",
+ inode->i_ino);
+ return 1;
+ }
+ de = (struct ext4_dir_entry_2 *) bh->b_data;
+ de1 = (struct ext4_dir_entry_2 *)
+ ((char *) de + le16_to_cpu(de->rec_len));
+ if (le32_to_cpu(de->inode) != inode->i_ino ||
+ !le32_to_cpu(de1->inode) ||
+ strcmp (".", de->name) ||
+ strcmp ("..", de1->name)) {
+ ext4_warning (inode->i_sb, "empty_dir",
+ "bad directory (dir #%lu) - no `.' or `..'",
+ inode->i_ino);
+ brelse (bh);
+ return 1;
+ }
+ offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
+ de = (struct ext4_dir_entry_2 *)
+ ((char *) de1 + le16_to_cpu(de1->rec_len));
+ while (offset < inode->i_size ) {
+ if (!bh ||
+ (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) {
+ err = 0;
+ brelse (bh);
+ bh = ext4_bread (NULL, inode,
+ offset >> EXT4_BLOCK_SIZE_BITS(sb), 0, &err);
+ if (!bh) {
+ if (err)
+ ext4_error(sb, __FUNCTION__,
+ "error %d reading directory"
+ " #%lu offset %lu",
+ err, inode->i_ino, offset);
+ offset += sb->s_blocksize;
+ continue;
+ }
+ de = (struct ext4_dir_entry_2 *) bh->b_data;
+ }
+ if (!ext4_check_dir_entry("empty_dir", inode, de, bh, offset)) {
+ de = (struct ext4_dir_entry_2 *)(bh->b_data +
+ sb->s_blocksize);
+ offset = (offset | (sb->s_blocksize - 1)) + 1;
+ continue;
+ }
+ if (le32_to_cpu(de->inode)) {
+ brelse (bh);
+ return 0;
+ }
+ offset += le16_to_cpu(de->rec_len);
+ de = (struct ext4_dir_entry_2 *)
+ ((char *) de + le16_to_cpu(de->rec_len));
+ }
+ brelse (bh);
+ return 1;
+}
+
+/* ext4_orphan_add() links an unlinked or truncated inode into a list of
+ * such inodes, starting at the superblock, in case we crash before the
+ * file is closed/deleted, or in case the inode truncate spans multiple
+ * transactions and the last transaction is not recovered after a crash.
+ *
+ * At filesystem recovery time, we walk this list deleting unlinked
+ * inodes and truncating linked inodes in ext4_orphan_cleanup().
+ */
+int ext4_orphan_add(handle_t *handle, struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ struct ext4_iloc iloc;
+ int err = 0, rc;
+
+ lock_super(sb);
+ if (!list_empty(&EXT4_I(inode)->i_orphan))
+ goto out_unlock;
+
+ /* Orphan handling is only valid for files with data blocks
+ * being truncated, or files being unlinked. */
+
+ /* @@@ FIXME: Observation from aviro:
+ * I think I can trigger J_ASSERT in ext4_orphan_add(). We block
+ * here (on lock_super()), so race with ext4_link() which might bump
+ * ->i_nlink. For, say it, character device. Not a regular file,
+ * not a directory, not a symlink and ->i_nlink > 0.
+ */
+ J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
+ S_ISLNK(inode->i_mode)) || inode->i_nlink == 0);
+
+ BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh);
+ if (err)
+ goto out_unlock;
+
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err)
+ goto out_unlock;
+
+ /* Insert this inode at the head of the on-disk orphan list... */
+ NEXT_ORPHAN(inode) = le32_to_cpu(EXT4_SB(sb)->s_es->s_last_orphan);
+ EXT4_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino);
+ err = ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
+ rc = ext4_mark_iloc_dirty(handle, inode, &iloc);
+ if (!err)
+ err = rc;
+
+ /* Only add to the head of the in-memory list if all the
+ * previous operations succeeded. If the orphan_add is going to
+ * fail (possibly taking the journal offline), we can't risk
+ * leaving the inode on the orphan list: stray orphan-list
+ * entries can cause panics at unmount time.
+ *
+ * This is safe: on error we're going to ignore the orphan list
+ * anyway on the next recovery. */
+ if (!err)
+ list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
+
+ jbd_debug(4, "superblock will point to %lu\n", inode->i_ino);
+ jbd_debug(4, "orphan inode %lu will point to %d\n",
+ inode->i_ino, NEXT_ORPHAN(inode));
+out_unlock:
+ unlock_super(sb);
+ ext4_std_error(inode->i_sb, err);
+ return err;
+}
+
+/*
+ * ext4_orphan_del() removes an unlinked or truncated inode from the list
+ * of such inodes stored on disk, because it is finally being cleaned up.
+ */
+int ext4_orphan_del(handle_t *handle, struct inode *inode)
+{
+ struct list_head *prev;
+ struct ext4_inode_info *ei = EXT4_I(inode);
+ struct ext4_sb_info *sbi;
+ unsigned long ino_next;
+ struct ext4_iloc iloc;
+ int err = 0;
+
+ lock_super(inode->i_sb);
+ if (list_empty(&ei->i_orphan)) {
+ unlock_super(inode->i_sb);
+ return 0;
+ }
+
+ ino_next = NEXT_ORPHAN(inode);
+ prev = ei->i_orphan.prev;
+ sbi = EXT4_SB(inode->i_sb);
+
+ jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino);
+
+ list_del_init(&ei->i_orphan);
+
+ /* If we're on an error path, we may not have a valid
+ * transaction handle with which to update the orphan list on
+ * disk, but we still need to remove the inode from the linked
+ * list in memory. */
+ if (!handle)
+ goto out;
+
+ err = ext4_reserve_inode_write(handle, inode, &iloc);
+ if (err)
+ goto out_err;
+
+ if (prev == &sbi->s_orphan) {
+ jbd_debug(4, "superblock will point to %lu\n", ino_next);
+ BUFFER_TRACE(sbi->s_sbh, "get_write_access");
+ err = ext4_journal_get_write_access(handle, sbi->s_sbh);
+ if (err)
+ goto out_brelse;
+ sbi->s_es->s_last_orphan = cpu_to_le32(ino_next);
+ err = ext4_journal_dirty_metadata(handle, sbi->s_sbh);
+ } else {
+ struct ext4_iloc iloc2;
+ struct inode *i_prev =
+ &list_entry(prev, struct ext4_inode_info, i_orphan)->vfs_inode;
+
+ jbd_debug(4, "orphan inode %lu will point to %lu\n",
+ i_prev->i_ino, ino_next);
+ err = ext4_reserve_inode_write(handle, i_prev, &iloc2);
+ if (err)
+ goto out_brelse;
+ NEXT_ORPHAN(i_prev) = ino_next;
+ err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2);
+ }
+ if (err)
+ goto out_brelse;
+ NEXT_ORPHAN(inode) = 0;
+ err = ext4_mark_iloc_dirty(handle, inode, &iloc);
+
+out_err:
+ ext4_std_error(inode->i_sb, err);
+out:
+ unlock_super(inode->i_sb);
+ return err;
+
+out_brelse:
+ brelse(iloc.bh);
+ goto out_err;
+}
+
+static int ext4_rmdir (struct inode * dir, struct dentry *dentry)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ext4_dir_entry_2 * de;
+ handle_t *handle;
+
+ /* Initialize quotas before so that eventual writes go in
+ * separate transaction */
+ DQUOT_INIT(dentry->d_inode);
+ handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ retval = -ENOENT;
+ bh = ext4_find_entry (dentry, &de);
+ if (!bh)
+ goto end_rmdir;
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+ inode = dentry->d_inode;
+
+ retval = -EIO;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ goto end_rmdir;
+
+ retval = -ENOTEMPTY;
+ if (!empty_dir (inode))
+ goto end_rmdir;
+
+ retval = ext4_delete_entry(handle, dir, de, bh);
+ if (retval)
+ goto end_rmdir;
+ if (inode->i_nlink != 2)
+ ext4_warning (inode->i_sb, "ext4_rmdir",
+ "empty directory has nlink!=2 (%d)",
+ inode->i_nlink);
+ inode->i_version++;
+ clear_nlink(inode);
+ /* There's no need to set i_disksize: the fact that i_nlink is
+ * zero will ensure that the right thing happens during any
+ * recovery. */
+ inode->i_size = 0;
+ ext4_orphan_add(handle, inode);
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ ext4_mark_inode_dirty(handle, inode);
+ drop_nlink(dir);
+ ext4_update_dx_flag(dir);
+ ext4_mark_inode_dirty(handle, dir);
+
+end_rmdir:
+ ext4_journal_stop(handle);
+ brelse (bh);
+ return retval;
+}
+
+static int ext4_unlink(struct inode * dir, struct dentry *dentry)
+{
+ int retval;
+ struct inode * inode;
+ struct buffer_head * bh;
+ struct ext4_dir_entry_2 * de;
+ handle_t *handle;
+
+ /* Initialize quotas before so that eventual writes go
+ * in separate transaction */
+ DQUOT_INIT(dentry->d_inode);
+ handle = ext4_journal_start(dir, EXT4_DELETE_TRANS_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+ retval = -ENOENT;
+ bh = ext4_find_entry (dentry, &de);
+ if (!bh)
+ goto end_unlink;
+
+ inode = dentry->d_inode;
+
+ retval = -EIO;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ goto end_unlink;
+
+ if (!inode->i_nlink) {
+ ext4_warning (inode->i_sb, "ext4_unlink",
+ "Deleting nonexistent file (%lu), %d",
+ inode->i_ino, inode->i_nlink);
+ inode->i_nlink = 1;
+ }
+ retval = ext4_delete_entry(handle, dir, de, bh);
+ if (retval)
+ goto end_unlink;
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ ext4_update_dx_flag(dir);
+ ext4_mark_inode_dirty(handle, dir);
+ drop_nlink(inode);
+ if (!inode->i_nlink)
+ ext4_orphan_add(handle, inode);
+ inode->i_ctime = dir->i_ctime;
+ ext4_mark_inode_dirty(handle, inode);
+ retval = 0;
+
+end_unlink:
+ ext4_journal_stop(handle);
+ brelse (bh);
+ return retval;
+}
+
+static int ext4_symlink (struct inode * dir,
+ struct dentry *dentry, const char * symname)
+{
+ handle_t *handle;
+ struct inode * inode;
+ int l, err, retries = 0;
+
+ l = strlen(symname)+1;
+ if (l > dir->i_sb->s_blocksize)
+ return -ENAMETOOLONG;
+
+retry:
+ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 5 +
+ 2*EXT4_QUOTA_INIT_BLOCKS(dir->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+ inode = ext4_new_inode (handle, dir, S_IFLNK|S_IRWXUGO);
+ err = PTR_ERR(inode);
+ if (IS_ERR(inode))
+ goto out_stop;
+
+ if (l > sizeof (EXT4_I(inode)->i_data)) {
+ inode->i_op = &ext4_symlink_inode_operations;
+ ext4_set_aops(inode);
+ /*
+ * page_symlink() calls into ext4_prepare/commit_write.
+ * We have a transaction open. All is sweetness. It also sets
+ * i_size in generic_commit_write().
+ */
+ err = __page_symlink(inode, symname, l,
+ mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS);
+ if (err) {
+ ext4_dec_count(handle, inode);
+ ext4_mark_inode_dirty(handle, inode);
+ iput (inode);
+ goto out_stop;
+ }
+ } else {
+ inode->i_op = &ext4_fast_symlink_inode_operations;
+ memcpy((char*)&EXT4_I(inode)->i_data,symname,l);
+ inode->i_size = l-1;
+ }
+ EXT4_I(inode)->i_disksize = inode->i_size;
+ err = ext4_add_nondir(handle, dentry, inode);
+out_stop:
+ ext4_journal_stop(handle);
+ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+ goto retry;
+ return err;
+}
+
+static int ext4_link (struct dentry * old_dentry,
+ struct inode * dir, struct dentry *dentry)
+{
+ handle_t *handle;
+ struct inode *inode = old_dentry->d_inode;
+ int err, retries = 0;
+
+ if (inode->i_nlink >= EXT4_LINK_MAX)
+ return -EMLINK;
+
+retry:
+ handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(dir))
+ handle->h_sync = 1;
+
+ inode->i_ctime = CURRENT_TIME_SEC;
+ ext4_inc_count(handle, inode);
+ atomic_inc(&inode->i_count);
+
+ err = ext4_add_nondir(handle, dentry, inode);
+ ext4_journal_stop(handle);
+ if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))
+ goto retry;
+ return err;
+}
+
+#define PARENT_INO(buffer) \
+ ((struct ext4_dir_entry_2 *) ((char *) buffer + \
+ le16_to_cpu(((struct ext4_dir_entry_2 *) buffer)->rec_len)))->inode
+
+/*
+ * Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+static int ext4_rename (struct inode * old_dir, struct dentry *old_dentry,
+ struct inode * new_dir,struct dentry *new_dentry)
+{
+ handle_t *handle;
+ struct inode * old_inode, * new_inode;
+ struct buffer_head * old_bh, * new_bh, * dir_bh;
+ struct ext4_dir_entry_2 * old_de, * new_de;
+ int retval;
+
+ old_bh = new_bh = dir_bh = NULL;
+
+ /* Initialize quotas before so that eventual writes go
+ * in separate transaction */
+ if (new_dentry->d_inode)
+ DQUOT_INIT(new_dentry->d_inode);
+ handle = ext4_journal_start(old_dir, 2 *
+ EXT4_DATA_TRANS_BLOCKS(old_dir->i_sb) +
+ EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
+ handle->h_sync = 1;
+
+ old_bh = ext4_find_entry (old_dentry, &old_de);
+ /*
+ * Check for inode number is _not_ due to possible IO errors.
+ * We might rmdir the source, keep it as pwd of some process
+ * and merrily kill the link to whatever was created under the
+ * same name. Goodbye sticky bit ;-<
+ */
+ old_inode = old_dentry->d_inode;
+ retval = -ENOENT;
+ if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)
+ goto end_rename;
+
+ new_inode = new_dentry->d_inode;
+ new_bh = ext4_find_entry (new_dentry, &new_de);
+ if (new_bh) {
+ if (!new_inode) {
+ brelse (new_bh);
+ new_bh = NULL;
+ }
+ }
+ if (S_ISDIR(old_inode->i_mode)) {
+ if (new_inode) {
+ retval = -ENOTEMPTY;
+ if (!empty_dir (new_inode))
+ goto end_rename;
+ }
+ retval = -EIO;
+ dir_bh = ext4_bread (handle, old_inode, 0, 0, &retval);
+ if (!dir_bh)
+ goto end_rename;
+ if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+ goto end_rename;
+ retval = -EMLINK;
+ if (!new_inode && new_dir!=old_dir &&
+ new_dir->i_nlink >= EXT4_LINK_MAX)
+ goto end_rename;
+ }
+ if (!new_bh) {
+ retval = ext4_add_entry (handle, new_dentry, old_inode);
+ if (retval)
+ goto end_rename;
+ } else {
+ BUFFER_TRACE(new_bh, "get write access");
+ ext4_journal_get_write_access(handle, new_bh);
+ new_de->inode = cpu_to_le32(old_inode->i_ino);
+ if (EXT4_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
+ EXT4_FEATURE_INCOMPAT_FILETYPE))
+ new_de->file_type = old_de->file_type;
+ new_dir->i_version++;
+ BUFFER_TRACE(new_bh, "call ext4_journal_dirty_metadata");
+ ext4_journal_dirty_metadata(handle, new_bh);
+ brelse(new_bh);
+ new_bh = NULL;
+ }
+
+ /*
+ * Like most other Unix systems, set the ctime for inodes on a
+ * rename.
+ */
+ old_inode->i_ctime = CURRENT_TIME_SEC;
+ ext4_mark_inode_dirty(handle, old_inode);
+
+ /*
+ * ok, that's it
+ */
+ if (le32_to_cpu(old_de->inode) != old_inode->i_ino ||
+ old_de->name_len != old_dentry->d_name.len ||
+ strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) ||
+ (retval = ext4_delete_entry(handle, old_dir,
+ old_de, old_bh)) == -ENOENT) {
+ /* old_de could have moved from under us during htree split, so
+ * make sure that we are deleting the right entry. We might
+ * also be pointing to a stale entry in the unused part of
+ * old_bh so just checking inum and the name isn't enough. */
+ struct buffer_head *old_bh2;
+ struct ext4_dir_entry_2 *old_de2;
+
+ old_bh2 = ext4_find_entry(old_dentry, &old_de2);
+ if (old_bh2) {
+ retval = ext4_delete_entry(handle, old_dir,
+ old_de2, old_bh2);
+ brelse(old_bh2);
+ }
+ }
+ if (retval) {
+ ext4_warning(old_dir->i_sb, "ext4_rename",
+ "Deleting old file (%lu), %d, error=%d",
+ old_dir->i_ino, old_dir->i_nlink, retval);
+ }
+
+ if (new_inode) {
+ drop_nlink(new_inode);
+ new_inode->i_ctime = CURRENT_TIME_SEC;
+ }
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
+ ext4_update_dx_flag(old_dir);
+ if (dir_bh) {
+ BUFFER_TRACE(dir_bh, "get_write_access");
+ ext4_journal_get_write_access(handle, dir_bh);
+ PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino);
+ BUFFER_TRACE(dir_bh, "call ext4_journal_dirty_metadata");
+ ext4_journal_dirty_metadata(handle, dir_bh);
+ drop_nlink(old_dir);
+ if (new_inode) {
+ drop_nlink(new_inode);
+ } else {
+ inc_nlink(new_dir);
+ ext4_update_dx_flag(new_dir);
+ ext4_mark_inode_dirty(handle, new_dir);
+ }
+ }
+ ext4_mark_inode_dirty(handle, old_dir);
+ if (new_inode) {
+ ext4_mark_inode_dirty(handle, new_inode);
+ if (!new_inode->i_nlink)
+ ext4_orphan_add(handle, new_inode);
+ }
+ retval = 0;
+
+end_rename:
+ brelse (dir_bh);
+ brelse (old_bh);
+ brelse (new_bh);
+ ext4_journal_stop(handle);
+ return retval;
+}
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations ext4_dir_inode_operations = {
+ .create = ext4_create,
+ .lookup = ext4_lookup,
+ .link = ext4_link,
+ .unlink = ext4_unlink,
+ .symlink = ext4_symlink,
+ .mkdir = ext4_mkdir,
+ .rmdir = ext4_rmdir,
+ .mknod = ext4_mknod,
+ .rename = ext4_rename,
+ .setattr = ext4_setattr,
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ext4_listxattr,
+ .removexattr = generic_removexattr,
+#endif
+ .permission = ext4_permission,
+};
+
+struct inode_operations ext4_special_inode_operations = {
+ .setattr = ext4_setattr,
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ext4_listxattr,
+ .removexattr = generic_removexattr,
+#endif
+ .permission = ext4_permission,
+};
diff --git a/fs/ext4/namei.h b/fs/ext4/namei.h
new file mode 100644
index 000000000000..5e4dfff36a00
--- /dev/null
+++ b/fs/ext4/namei.h
@@ -0,0 +1,8 @@
+/* linux/fs/ext4/namei.h
+ *
+ * Copyright (C) 2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+*/
+
+extern struct dentry *ext4_get_parent(struct dentry *child);
diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c
new file mode 100644
index 000000000000..1e9578052cd3
--- /dev/null
+++ b/fs/ext4/resize.c
@@ -0,0 +1,1045 @@
+/*
+ * linux/fs/ext4/resize.c
+ *
+ * Support for resizing an ext4 filesystem while it is mounted.
+ *
+ * Copyright (C) 2001, 2002 Andreas Dilger <adilger@clusterfs.com>
+ *
+ * This could probably be made into a module, because it is not often in use.
+ */
+
+
+#define EXT4FS_DEBUG
+
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/ext4_jbd2.h>
+
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+
+#define outside(b, first, last) ((b) < (first) || (b) >= (last))
+#define inside(b, first, last) ((b) >= (first) && (b) < (last))
+
+static int verify_group_input(struct super_block *sb,
+ struct ext4_new_group_data *input)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_super_block *es = sbi->s_es;
+ ext4_fsblk_t start = ext4_blocks_count(es);
+ ext4_fsblk_t end = start + input->blocks_count;
+ unsigned group = input->group;
+ ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;
+ unsigned overhead = ext4_bg_has_super(sb, group) ?
+ (1 + ext4_bg_num_gdb(sb, group) +
+ le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
+ ext4_fsblk_t metaend = start + overhead;
+ struct buffer_head *bh = NULL;
+ ext4_grpblk_t free_blocks_count, offset;
+ int err = -EINVAL;
+
+ input->free_blocks_count = free_blocks_count =
+ input->blocks_count - 2 - overhead - sbi->s_itb_per_group;
+
+ if (test_opt(sb, DEBUG))
+ printk(KERN_DEBUG "EXT4-fs: adding %s group %u: %u blocks "
+ "(%d free, %u reserved)\n",
+ ext4_bg_has_super(sb, input->group) ? "normal" :
+ "no-super", input->group, input->blocks_count,
+ free_blocks_count, input->reserved_blocks);
+
+ ext4_get_group_no_and_offset(sb, start, NULL, &offset);
+ if (group != sbi->s_groups_count)
+ ext4_warning(sb, __FUNCTION__,
+ "Cannot add at group %u (only %lu groups)",
+ input->group, sbi->s_groups_count);
+ else if (offset != 0)
+ ext4_warning(sb, __FUNCTION__, "Last group not full");
+ else if (input->reserved_blocks > input->blocks_count / 5)
+ ext4_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",
+ input->reserved_blocks);
+ else if (free_blocks_count < 0)
+ ext4_warning(sb, __FUNCTION__, "Bad blocks count %u",
+ input->blocks_count);
+ else if (!(bh = sb_bread(sb, end - 1)))
+ ext4_warning(sb, __FUNCTION__,
+ "Cannot read last block (%llu)",
+ end - 1);
+ else if (outside(input->block_bitmap, start, end))
+ ext4_warning(sb, __FUNCTION__,
+ "Block bitmap not in group (block %llu)",
+ input->block_bitmap);
+ else if (outside(input->inode_bitmap, start, end))
+ ext4_warning(sb, __FUNCTION__,
+ "Inode bitmap not in group (block %llu)",
+ input->inode_bitmap);
+ else if (outside(input->inode_table, start, end) ||
+ outside(itend - 1, start, end))
+ ext4_warning(sb, __FUNCTION__,
+ "Inode table not in group (blocks %llu-%llu)",
+ input->inode_table, itend - 1);
+ else if (input->inode_bitmap == input->block_bitmap)
+ ext4_warning(sb, __FUNCTION__,
+ "Block bitmap same as inode bitmap (%llu)",
+ input->block_bitmap);
+ else if (inside(input->block_bitmap, input->inode_table, itend))
+ ext4_warning(sb, __FUNCTION__,
+ "Block bitmap (%llu) in inode table (%llu-%llu)",
+ input->block_bitmap, input->inode_table, itend-1);
+ else if (inside(input->inode_bitmap, input->inode_table, itend))
+ ext4_warning(sb, __FUNCTION__,
+ "Inode bitmap (%llu) in inode table (%llu-%llu)",
+ input->inode_bitmap, input->inode_table, itend-1);
+ else if (inside(input->block_bitmap, start, metaend))
+ ext4_warning(sb, __FUNCTION__,
+ "Block bitmap (%llu) in GDT table"
+ " (%llu-%llu)",
+ input->block_bitmap, start, metaend - 1);
+ else if (inside(input->inode_bitmap, start, metaend))
+ ext4_warning(sb, __FUNCTION__,
+ "Inode bitmap (%llu) in GDT table"
+ " (%llu-%llu)",
+ input->inode_bitmap, start, metaend - 1);
+ else if (inside(input->inode_table, start, metaend) ||
+ inside(itend - 1, start, metaend))
+ ext4_warning(sb, __FUNCTION__,
+ "Inode table (%llu-%llu) overlaps"
+ "GDT table (%llu-%llu)",
+ input->inode_table, itend - 1, start, metaend - 1);
+ else
+ err = 0;
+ brelse(bh);
+
+ return err;
+}
+
+static struct buffer_head *bclean(handle_t *handle, struct super_block *sb,
+ ext4_fsblk_t blk)
+{
+ struct buffer_head *bh;
+ int err;
+
+ bh = sb_getblk(sb, blk);
+ if (!bh)
+ return ERR_PTR(-EIO);
+ if ((err = ext4_journal_get_write_access(handle, bh))) {
+ brelse(bh);
+ bh = ERR_PTR(err);
+ } else {
+ lock_buffer(bh);
+ memset(bh->b_data, 0, sb->s_blocksize);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ }
+
+ return bh;
+}
+
+/*
+ * To avoid calling the atomic setbit hundreds or thousands of times, we only
+ * need to use it within a single byte (to ensure we get endianness right).
+ * We can use memset for the rest of the bitmap as there are no other users.
+ */
+static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
+{
+ int i;
+
+ if (start_bit >= end_bit)
+ return;
+
+ ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit);
+ for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++)
+ ext4_set_bit(i, bitmap);
+ if (i < end_bit)
+ memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
+}
+
+/*
+ * Set up the block and inode bitmaps, and the inode table for the new group.
+ * This doesn't need to be part of the main transaction, since we are only
+ * changing blocks outside the actual filesystem. We still do journaling to
+ * ensure the recovery is correct in case of a failure just after resize.
+ * If any part of this fails, we simply abort the resize.
+ */
+static int setup_new_group_blocks(struct super_block *sb,
+ struct ext4_new_group_data *input)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ ext4_fsblk_t start = ext4_group_first_block_no(sb, input->group);
+ int reserved_gdb = ext4_bg_has_super(sb, input->group) ?
+ le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0;
+ unsigned long gdblocks = ext4_bg_num_gdb(sb, input->group);
+ struct buffer_head *bh;
+ handle_t *handle;
+ ext4_fsblk_t block;
+ ext4_grpblk_t bit;
+ int i;
+ int err = 0, err2;
+
+ handle = ext4_journal_start_sb(sb, reserved_gdb + gdblocks +
+ 2 + sbi->s_itb_per_group);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+
+ lock_super(sb);
+ if (input->group != sbi->s_groups_count) {
+ err = -EBUSY;
+ goto exit_journal;
+ }
+
+ if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) {
+ err = PTR_ERR(bh);
+ goto exit_journal;
+ }
+
+ if (ext4_bg_has_super(sb, input->group)) {
+ ext4_debug("mark backup superblock %#04lx (+0)\n", start);
+ ext4_set_bit(0, bh->b_data);
+ }
+
+ /* Copy all of the GDT blocks into the backup in this group */
+ for (i = 0, bit = 1, block = start + 1;
+ i < gdblocks; i++, block++, bit++) {
+ struct buffer_head *gdb;
+
+ ext4_debug("update backup group %#04lx (+%d)\n", block, bit);
+
+ gdb = sb_getblk(sb, block);
+ if (!gdb) {
+ err = -EIO;
+ goto exit_bh;
+ }
+ if ((err = ext4_journal_get_write_access(handle, gdb))) {
+ brelse(gdb);
+ goto exit_bh;
+ }
+ lock_buffer(bh);
+ memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, bh->b_size);
+ set_buffer_uptodate(gdb);
+ unlock_buffer(bh);
+ ext4_journal_dirty_metadata(handle, gdb);
+ ext4_set_bit(bit, bh->b_data);
+ brelse(gdb);
+ }
+
+ /* Zero out all of the reserved backup group descriptor table blocks */
+ for (i = 0, bit = gdblocks + 1, block = start + bit;
+ i < reserved_gdb; i++, block++, bit++) {
+ struct buffer_head *gdb;
+
+ ext4_debug("clear reserved block %#04lx (+%d)\n", block, bit);
+
+ if (IS_ERR(gdb = bclean(handle, sb, block))) {
+ err = PTR_ERR(bh);
+ goto exit_bh;
+ }
+ ext4_journal_dirty_metadata(handle, gdb);
+ ext4_set_bit(bit, bh->b_data);
+ brelse(gdb);
+ }
+ ext4_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap,
+ input->block_bitmap - start);
+ ext4_set_bit(input->block_bitmap - start, bh->b_data);
+ ext4_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap,
+ input->inode_bitmap - start);
+ ext4_set_bit(input->inode_bitmap - start, bh->b_data);
+
+ /* Zero out all of the inode table blocks */
+ for (i = 0, block = input->inode_table, bit = block - start;
+ i < sbi->s_itb_per_group; i++, bit++, block++) {
+ struct buffer_head *it;
+
+ ext4_debug("clear inode block %#04lx (+%d)\n", block, bit);
+ if (IS_ERR(it = bclean(handle, sb, block))) {
+ err = PTR_ERR(it);
+ goto exit_bh;
+ }
+ ext4_journal_dirty_metadata(handle, it);
+ brelse(it);
+ ext4_set_bit(bit, bh->b_data);
+ }
+ mark_bitmap_end(input->blocks_count, EXT4_BLOCKS_PER_GROUP(sb),
+ bh->b_data);
+ ext4_journal_dirty_metadata(handle, bh);
+ brelse(bh);
+
+ /* Mark unused entries in inode bitmap used */
+ ext4_debug("clear inode bitmap %#04x (+%ld)\n",
+ input->inode_bitmap, input->inode_bitmap - start);
+ if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) {
+ err = PTR_ERR(bh);
+ goto exit_journal;
+ }
+
+ mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), EXT4_BLOCKS_PER_GROUP(sb),
+ bh->b_data);
+ ext4_journal_dirty_metadata(handle, bh);
+exit_bh:
+ brelse(bh);
+
+exit_journal:
+ unlock_super(sb);
+ if ((err2 = ext4_journal_stop(handle)) && !err)
+ err = err2;
+
+ return err;
+}
+
+
+/*
+ * Iterate through the groups which hold BACKUP superblock/GDT copies in an
+ * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before
+ * calling this for the first time. In a sparse filesystem it will be the
+ * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
+ * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
+ */
+static unsigned ext4_list_backups(struct super_block *sb, unsigned *three,
+ unsigned *five, unsigned *seven)
+{
+ unsigned *min = three;
+ int mult = 3;
+ unsigned ret;
+
+ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+ ret = *min;
+ *min += 1;
+ return ret;
+ }
+
+ if (*five < *min) {
+ min = five;
+ mult = 5;
+ }
+ if (*seven < *min) {
+ min = seven;
+ mult = 7;
+ }
+
+ ret = *min;
+ *min *= mult;
+
+ return ret;
+}
+
+/*
+ * Check that all of the backup GDT blocks are held in the primary GDT block.
+ * It is assumed that they are stored in group order. Returns the number of
+ * groups in current filesystem that have BACKUPS, or -ve error code.
+ */
+static int verify_reserved_gdb(struct super_block *sb,
+ struct buffer_head *primary)
+{
+ const ext4_fsblk_t blk = primary->b_blocknr;
+ const unsigned long end = EXT4_SB(sb)->s_groups_count;
+ unsigned three = 1;
+ unsigned five = 5;
+ unsigned seven = 7;
+ unsigned grp;
+ __le32 *p = (__le32 *)primary->b_data;
+ int gdbackups = 0;
+
+ while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) {
+ if (le32_to_cpu(*p++) !=
+ grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){
+ ext4_warning(sb, __FUNCTION__,
+ "reserved GDT %llu"
+ " missing grp %d (%llu)",
+ blk, grp,
+ grp *
+ (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) +
+ blk);
+ return -EINVAL;
+ }
+ if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb))
+ return -EFBIG;
+ }
+
+ return gdbackups;
+}
+
+/*
+ * Called when we need to bring a reserved group descriptor table block into
+ * use from the resize inode. The primary copy of the new GDT block currently
+ * is an indirect block (under the double indirect block in the resize inode).
+ * The new backup GDT blocks will be stored as leaf blocks in this indirect
+ * block, in group order. Even though we know all the block numbers we need,
+ * we check to ensure that the resize inode has actually reserved these blocks.
+ *
+ * Don't need to update the block bitmaps because the blocks are still in use.
+ *
+ * We get all of the error cases out of the way, so that we are sure to not
+ * fail once we start modifying the data on disk, because JBD has no rollback.
+ */
+static int add_new_gdb(handle_t *handle, struct inode *inode,
+ struct ext4_new_group_data *input,
+ struct buffer_head **primary)
+{
+ struct super_block *sb = inode->i_sb;
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+ unsigned long gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb);
+ ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num;
+ struct buffer_head **o_group_desc, **n_group_desc;
+ struct buffer_head *dind;
+ int gdbackups;
+ struct ext4_iloc iloc;
+ __le32 *data;
+ int err;
+
+ if (test_opt(sb, DEBUG))
+ printk(KERN_DEBUG
+ "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n",
+ gdb_num);
+
+ /*
+ * If we are not using the primary superblock/GDT copy don't resize,
+ * because the user tools have no way of handling this. Probably a
+ * bad time to do it anyways.
+ */
+ if (EXT4_SB(sb)->s_sbh->b_blocknr !=
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) {
+ ext4_warning(sb, __FUNCTION__,
+ "won't resize using backup superblock at %llu",
+ (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr);
+ return -EPERM;
+ }
+
+ *primary = sb_bread(sb, gdblock);
+ if (!*primary)
+ return -EIO;
+
+ if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) {
+ err = gdbackups;
+ goto exit_bh;
+ }
+
+ data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK;
+ dind = sb_bread(sb, le32_to_cpu(*data));
+ if (!dind) {
+ err = -EIO;
+ goto exit_bh;
+ }
+
+ data = (__le32 *)dind->b_data;
+ if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) {
+ ext4_warning(sb, __FUNCTION__,
+ "new group %u GDT block %llu not reserved",
+ input->group, gdblock);
+ err = -EINVAL;
+ goto exit_dind;
+ }
+
+ if ((err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh)))
+ goto exit_dind;
+
+ if ((err = ext4_journal_get_write_access(handle, *primary)))
+ goto exit_sbh;
+
+ if ((err = ext4_journal_get_write_access(handle, dind)))
+ goto exit_primary;
+
+ /* ext4_reserve_inode_write() gets a reference on the iloc */
+ if ((err = ext4_reserve_inode_write(handle, inode, &iloc)))
+ goto exit_dindj;
+
+ n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *),
+ GFP_KERNEL);
+ if (!n_group_desc) {
+ err = -ENOMEM;
+ ext4_warning (sb, __FUNCTION__,
+ "not enough memory for %lu groups", gdb_num + 1);
+ goto exit_inode;
+ }
+
+ /*
+ * Finally, we have all of the possible failures behind us...
+ *
+ * Remove new GDT block from inode double-indirect block and clear out
+ * the new GDT block for use (which also "frees" the backup GDT blocks
+ * from the reserved inode). We don't need to change the bitmaps for
+ * these blocks, because they are marked as in-use from being in the
+ * reserved inode, and will become GDT blocks (primary and backup).
+ */
+ data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0;
+ ext4_journal_dirty_metadata(handle, dind);
+ brelse(dind);
+ inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9;
+ ext4_mark_iloc_dirty(handle, inode, &iloc);
+ memset((*primary)->b_data, 0, sb->s_blocksize);
+ ext4_journal_dirty_metadata(handle, *primary);
+
+ o_group_desc = EXT4_SB(sb)->s_group_desc;
+ memcpy(n_group_desc, o_group_desc,
+ EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *));
+ n_group_desc[gdb_num] = *primary;
+ EXT4_SB(sb)->s_group_desc = n_group_desc;
+ EXT4_SB(sb)->s_gdb_count++;
+ kfree(o_group_desc);
+
+ es->s_reserved_gdt_blocks =
+ cpu_to_le16(le16_to_cpu(es->s_reserved_gdt_blocks) - 1);
+ ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
+
+ return 0;
+
+exit_inode:
+ //ext4_journal_release_buffer(handle, iloc.bh);
+ brelse(iloc.bh);
+exit_dindj:
+ //ext4_journal_release_buffer(handle, dind);
+exit_primary:
+ //ext4_journal_release_buffer(handle, *primary);
+exit_sbh:
+ //ext4_journal_release_buffer(handle, *primary);
+exit_dind:
+ brelse(dind);
+exit_bh:
+ brelse(*primary);
+
+ ext4_debug("leaving with error %d\n", err);
+ return err;
+}
+
+/*
+ * Called when we are adding a new group which has a backup copy of each of
+ * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks.
+ * We need to add these reserved backup GDT blocks to the resize inode, so
+ * that they are kept for future resizing and not allocated to files.
+ *
+ * Each reserved backup GDT block will go into a different indirect block.
+ * The indirect blocks are actually the primary reserved GDT blocks,
+ * so we know in advance what their block numbers are. We only get the
+ * double-indirect block to verify it is pointing to the primary reserved
+ * GDT blocks so we don't overwrite a data block by accident. The reserved
+ * backup GDT blocks are stored in their reserved primary GDT block.
+ */
+static int reserve_backup_gdb(handle_t *handle, struct inode *inode,
+ struct ext4_new_group_data *input)
+{
+ struct super_block *sb = inode->i_sb;
+ int reserved_gdb =le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks);
+ struct buffer_head **primary;
+ struct buffer_head *dind;
+ struct ext4_iloc iloc;
+ ext4_fsblk_t blk;
+ __le32 *data, *end;
+ int gdbackups = 0;
+ int res, i;
+ int err;
+
+ primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_KERNEL);
+ if (!primary)
+ return -ENOMEM;
+
+ data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK;
+ dind = sb_bread(sb, le32_to_cpu(*data));
+ if (!dind) {
+ err = -EIO;
+ goto exit_free;
+ }
+
+ blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count;
+ data = (__le32 *)dind->b_data + EXT4_SB(sb)->s_gdb_count;
+ end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb);
+
+ /* Get each reserved primary GDT block and verify it holds backups */
+ for (res = 0; res < reserved_gdb; res++, blk++) {
+ if (le32_to_cpu(*data) != blk) {
+ ext4_warning(sb, __FUNCTION__,
+ "reserved block %llu"
+ " not at offset %ld",
+ blk,
+ (long)(data - (__le32 *)dind->b_data));
+ err = -EINVAL;
+ goto exit_bh;
+ }
+ primary[res] = sb_bread(sb, blk);
+ if (!primary[res]) {
+ err = -EIO;
+ goto exit_bh;
+ }
+ if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) {
+ brelse(primary[res]);
+ err = gdbackups;
+ goto exit_bh;
+ }
+ if (++data >= end)
+ data = (__le32 *)dind->b_data;
+ }
+
+ for (i = 0; i < reserved_gdb; i++) {
+ if ((err = ext4_journal_get_write_access(handle, primary[i]))) {
+ /*
+ int j;
+ for (j = 0; j < i; j++)
+ ext4_journal_release_buffer(handle, primary[j]);
+ */
+ goto exit_bh;
+ }
+ }
+
+ if ((err = ext4_reserve_inode_write(handle, inode, &iloc)))
+ goto exit_bh;
+
+ /*
+ * Finally we can add each of the reserved backup GDT blocks from
+ * the new group to its reserved primary GDT block.
+ */
+ blk = input->group * EXT4_BLOCKS_PER_GROUP(sb);
+ for (i = 0; i < reserved_gdb; i++) {
+ int err2;
+ data = (__le32 *)primary[i]->b_data;
+ /* printk("reserving backup %lu[%u] = %lu\n",
+ primary[i]->b_blocknr, gdbackups,
+ blk + primary[i]->b_blocknr); */
+ data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr);
+ err2 = ext4_journal_dirty_metadata(handle, primary[i]);
+ if (!err)
+ err = err2;
+ }
+ inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9;
+ ext4_mark_iloc_dirty(handle, inode, &iloc);
+
+exit_bh:
+ while (--res >= 0)
+ brelse(primary[res]);
+ brelse(dind);
+
+exit_free:
+ kfree(primary);
+
+ return err;
+}
+
+/*
+ * Update the backup copies of the ext4 metadata. These don't need to be part
+ * of the main resize transaction, because e2fsck will re-write them if there
+ * is a problem (basically only OOM will cause a problem). However, we
+ * _should_ update the backups if possible, in case the primary gets trashed
+ * for some reason and we need to run e2fsck from a backup superblock. The
+ * important part is that the new block and inode counts are in the backup
+ * superblocks, and the location of the new group metadata in the GDT backups.
+ *
+ * We do not need lock_super() for this, because these blocks are not
+ * otherwise touched by the filesystem code when it is mounted. We don't
+ * need to worry about last changing from sbi->s_groups_count, because the
+ * worst that can happen is that we do not copy the full number of backups
+ * at this time. The resize which changed s_groups_count will backup again.
+ */
+static void update_backups(struct super_block *sb,
+ int blk_off, char *data, int size)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ const unsigned long last = sbi->s_groups_count;
+ const int bpg = EXT4_BLOCKS_PER_GROUP(sb);
+ unsigned three = 1;
+ unsigned five = 5;
+ unsigned seven = 7;
+ unsigned group;
+ int rest = sb->s_blocksize - size;
+ handle_t *handle;
+ int err = 0, err2;
+
+ handle = ext4_journal_start_sb(sb, EXT4_MAX_TRANS_DATA);
+ if (IS_ERR(handle)) {
+ group = 1;
+ err = PTR_ERR(handle);
+ goto exit_err;
+ }
+
+ while ((group = ext4_list_backups(sb, &three, &five, &seven)) < last) {
+ struct buffer_head *bh;
+
+ /* Out of journal space, and can't get more - abort - so sad */
+ if (handle->h_buffer_credits == 0 &&
+ ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) &&
+ (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA)))
+ break;
+
+ bh = sb_getblk(sb, group * bpg + blk_off);
+ if (!bh) {
+ err = -EIO;
+ break;
+ }
+ ext4_debug("update metadata backup %#04lx\n",
+ (unsigned long)bh->b_blocknr);
+ if ((err = ext4_journal_get_write_access(handle, bh)))
+ break;
+ lock_buffer(bh);
+ memcpy(bh->b_data, data, size);
+ if (rest)
+ memset(bh->b_data + size, 0, rest);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ ext4_journal_dirty_metadata(handle, bh);
+ brelse(bh);
+ }
+ if ((err2 = ext4_journal_stop(handle)) && !err)
+ err = err2;
+
+ /*
+ * Ugh! Need to have e2fsck write the backup copies. It is too
+ * late to revert the resize, we shouldn't fail just because of
+ * the backup copies (they are only needed in case of corruption).
+ *
+ * However, if we got here we have a journal problem too, so we
+ * can't really start a transaction to mark the superblock.
+ * Chicken out and just set the flag on the hope it will be written
+ * to disk, and if not - we will simply wait until next fsck.
+ */
+exit_err:
+ if (err) {
+ ext4_warning(sb, __FUNCTION__,
+ "can't update backup for group %d (err %d), "
+ "forcing fsck on next reboot", group, err);
+ sbi->s_mount_state &= ~EXT4_VALID_FS;
+ sbi->s_es->s_state &= cpu_to_le16(~EXT4_VALID_FS);
+ mark_buffer_dirty(sbi->s_sbh);
+ }
+}
+
+/* Add group descriptor data to an existing or new group descriptor block.
+ * Ensure we handle all possible error conditions _before_ we start modifying
+ * the filesystem, because we cannot abort the transaction and not have it
+ * write the data to disk.
+ *
+ * If we are on a GDT block boundary, we need to get the reserved GDT block.
+ * Otherwise, we may need to add backup GDT blocks for a sparse group.
+ *
+ * We only need to hold the superblock lock while we are actually adding
+ * in the new group's counts to the superblock. Prior to that we have
+ * not really "added" the group at all. We re-check that we are still
+ * adding in the last group in case things have changed since verifying.
+ */
+int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_super_block *es = sbi->s_es;
+ int reserved_gdb = ext4_bg_has_super(sb, input->group) ?
+ le16_to_cpu(es->s_reserved_gdt_blocks) : 0;
+ struct buffer_head *primary = NULL;
+ struct ext4_group_desc *gdp;
+ struct inode *inode = NULL;
+ handle_t *handle;
+ int gdb_off, gdb_num;
+ int err, err2;
+
+ gdb_num = input->group / EXT4_DESC_PER_BLOCK(sb);
+ gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb);
+
+ if (gdb_off == 0 && !EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER)) {
+ ext4_warning(sb, __FUNCTION__,
+ "Can't resize non-sparse filesystem further");
+ return -EPERM;
+ }
+
+ if (ext4_blocks_count(es) + input->blocks_count <
+ ext4_blocks_count(es)) {
+ ext4_warning(sb, __FUNCTION__, "blocks_count overflow\n");
+ return -EINVAL;
+ }
+
+ if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) <
+ le32_to_cpu(es->s_inodes_count)) {
+ ext4_warning(sb, __FUNCTION__, "inodes_count overflow\n");
+ return -EINVAL;
+ }
+
+ if (reserved_gdb || gdb_off == 0) {
+ if (!EXT4_HAS_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_COMPAT_RESIZE_INODE)){
+ ext4_warning(sb, __FUNCTION__,
+ "No reserved GDT blocks, can't resize");
+ return -EPERM;
+ }
+ inode = iget(sb, EXT4_RESIZE_INO);
+ if (!inode || is_bad_inode(inode)) {
+ ext4_warning(sb, __FUNCTION__,
+ "Error opening resize inode");
+ iput(inode);
+ return -ENOENT;
+ }
+ }
+
+ if ((err = verify_group_input(sb, input)))
+ goto exit_put;
+
+ if ((err = setup_new_group_blocks(sb, input)))
+ goto exit_put;
+
+ /*
+ * We will always be modifying at least the superblock and a GDT
+ * block. If we are adding a group past the last current GDT block,
+ * we will also modify the inode and the dindirect block. If we
+ * are adding a group with superblock/GDT backups we will also
+ * modify each of the reserved GDT dindirect blocks.
+ */
+ handle = ext4_journal_start_sb(sb,
+ ext4_bg_has_super(sb, input->group) ?
+ 3 + reserved_gdb : 4);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ goto exit_put;
+ }
+
+ lock_super(sb);
+ if (input->group != sbi->s_groups_count) {
+ ext4_warning(sb, __FUNCTION__,
+ "multiple resizers run on filesystem!");
+ err = -EBUSY;
+ goto exit_journal;
+ }
+
+ if ((err = ext4_journal_get_write_access(handle, sbi->s_sbh)))
+ goto exit_journal;
+
+ /*
+ * We will only either add reserved group blocks to a backup group
+ * or remove reserved blocks for the first group in a new group block.
+ * Doing both would be mean more complex code, and sane people don't
+ * use non-sparse filesystems anymore. This is already checked above.
+ */
+ if (gdb_off) {
+ primary = sbi->s_group_desc[gdb_num];
+ if ((err = ext4_journal_get_write_access(handle, primary)))
+ goto exit_journal;
+
+ if (reserved_gdb && ext4_bg_num_gdb(sb, input->group) &&
+ (err = reserve_backup_gdb(handle, inode, input)))
+ goto exit_journal;
+ } else if ((err = add_new_gdb(handle, inode, input, &primary)))
+ goto exit_journal;
+
+ /*
+ * OK, now we've set up the new group. Time to make it active.
+ *
+ * Current kernels don't lock all allocations via lock_super(),
+ * so we have to be safe wrt. concurrent accesses the group
+ * data. So we need to be careful to set all of the relevant
+ * group descriptor data etc. *before* we enable the group.
+ *
+ * The key field here is sbi->s_groups_count: as long as
+ * that retains its old value, nobody is going to access the new
+ * group.
+ *
+ * So first we update all the descriptor metadata for the new
+ * group; then we update the total disk blocks count; then we
+ * update the groups count to enable the group; then finally we
+ * update the free space counts so that the system can start
+ * using the new disk blocks.
+ */
+
+ /* Update group descriptor block for new group */
+ gdp = (struct ext4_group_desc *)primary->b_data + gdb_off;
+
+ ext4_block_bitmap_set(sb, gdp, input->block_bitmap); /* LV FIXME */
+ ext4_inode_bitmap_set(sb, gdp, input->inode_bitmap); /* LV FIXME */
+ ext4_inode_table_set(sb, gdp, input->inode_table); /* LV FIXME */
+ gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count);
+ gdp->bg_free_inodes_count = cpu_to_le16(EXT4_INODES_PER_GROUP(sb));
+
+ /*
+ * Make the new blocks and inodes valid next. We do this before
+ * increasing the group count so that once the group is enabled,
+ * all of its blocks and inodes are already valid.
+ *
+ * We always allocate group-by-group, then block-by-block or
+ * inode-by-inode within a group, so enabling these
+ * blocks/inodes before the group is live won't actually let us
+ * allocate the new space yet.
+ */
+ ext4_blocks_count_set(es, ext4_blocks_count(es) +
+ input->blocks_count);
+ es->s_inodes_count = cpu_to_le32(le32_to_cpu(es->s_inodes_count) +
+ EXT4_INODES_PER_GROUP(sb));
+
+ /*
+ * We need to protect s_groups_count against other CPUs seeing
+ * inconsistent state in the superblock.
+ *
+ * The precise rules we use are:
+ *
+ * * Writers of s_groups_count *must* hold lock_super
+ * AND
+ * * Writers must perform a smp_wmb() after updating all dependent
+ * data and before modifying the groups count
+ *
+ * * Readers must hold lock_super() over the access
+ * OR
+ * * Readers must perform an smp_rmb() after reading the groups count
+ * and before reading any dependent data.
+ *
+ * NB. These rules can be relaxed when checking the group count
+ * while freeing data, as we can only allocate from a block
+ * group after serialising against the group count, and we can
+ * only then free after serialising in turn against that
+ * allocation.
+ */
+ smp_wmb();
+
+ /* Update the global fs size fields */
+ sbi->s_groups_count++;
+
+ ext4_journal_dirty_metadata(handle, primary);
+
+ /* Update the reserved block counts only once the new group is
+ * active. */
+ ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) +
+ input->reserved_blocks);
+
+ /* Update the free space counts */
+ percpu_counter_mod(&sbi->s_freeblocks_counter,
+ input->free_blocks_count);
+ percpu_counter_mod(&sbi->s_freeinodes_counter,
+ EXT4_INODES_PER_GROUP(sb));
+
+ ext4_journal_dirty_metadata(handle, sbi->s_sbh);
+ sb->s_dirt = 1;
+
+exit_journal:
+ unlock_super(sb);
+ if ((err2 = ext4_journal_stop(handle)) && !err)
+ err = err2;
+ if (!err) {
+ update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es,
+ sizeof(struct ext4_super_block));
+ update_backups(sb, primary->b_blocknr, primary->b_data,
+ primary->b_size);
+ }
+exit_put:
+ iput(inode);
+ return err;
+} /* ext4_group_add */
+
+/* Extend the filesystem to the new number of blocks specified. This entry
+ * point is only used to extend the current filesystem to the end of the last
+ * existing group. It can be accessed via ioctl, or by "remount,resize=<size>"
+ * for emergencies (because it has no dependencies on reserved blocks).
+ *
+ * If we _really_ wanted, we could use default values to call ext4_group_add()
+ * allow the "remount" trick to work for arbitrary resizing, assuming enough
+ * GDT blocks are reserved to grow to the desired size.
+ */
+int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es,
+ ext4_fsblk_t n_blocks_count)
+{
+ ext4_fsblk_t o_blocks_count;
+ unsigned long o_groups_count;
+ ext4_grpblk_t last;
+ ext4_grpblk_t add;
+ struct buffer_head * bh;
+ handle_t *handle;
+ int err;
+ unsigned long freed_blocks;
+
+ /* We don't need to worry about locking wrt other resizers just
+ * yet: we're going to revalidate es->s_blocks_count after
+ * taking lock_super() below. */
+ o_blocks_count = ext4_blocks_count(es);
+ o_groups_count = EXT4_SB(sb)->s_groups_count;
+
+ if (test_opt(sb, DEBUG))
+ printk(KERN_DEBUG "EXT4-fs: extending last group from %llu uto %llu blocks\n",
+ o_blocks_count, n_blocks_count);
+
+ if (n_blocks_count == 0 || n_blocks_count == o_blocks_count)
+ return 0;
+
+ if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+ printk(KERN_ERR "EXT4-fs: filesystem on %s:"
+ " too large to resize to %llu blocks safely\n",
+ sb->s_id, n_blocks_count);
+ if (sizeof(sector_t) < 8)
+ ext4_warning(sb, __FUNCTION__,
+ "CONFIG_LBD not enabled\n");
+ return -EINVAL;
+ }
+
+ if (n_blocks_count < o_blocks_count) {
+ ext4_warning(sb, __FUNCTION__,
+ "can't shrink FS - resize aborted");
+ return -EBUSY;
+ }
+
+ /* Handle the remaining blocks in the last group only. */
+ ext4_get_group_no_and_offset(sb, o_blocks_count, NULL, &last);
+
+ if (last == 0) {
+ ext4_warning(sb, __FUNCTION__,
+ "need to use ext2online to resize further");
+ return -EPERM;
+ }
+
+ add = EXT4_BLOCKS_PER_GROUP(sb) - last;
+
+ if (o_blocks_count + add < o_blocks_count) {
+ ext4_warning(sb, __FUNCTION__, "blocks_count overflow");
+ return -EINVAL;
+ }
+
+ if (o_blocks_count + add > n_blocks_count)
+ add = n_blocks_count - o_blocks_count;
+
+ if (o_blocks_count + add < n_blocks_count)
+ ext4_warning(sb, __FUNCTION__,
+ "will only finish group (%llu"
+ " blocks, %u new)",
+ o_blocks_count + add, add);
+
+ /* See if the device is actually as big as what was requested */
+ bh = sb_bread(sb, o_blocks_count + add -1);
+ if (!bh) {
+ ext4_warning(sb, __FUNCTION__,
+ "can't read last block, resize aborted");
+ return -ENOSPC;
+ }
+ brelse(bh);
+
+ /* We will update the superblock, one block bitmap, and
+ * one group descriptor via ext4_free_blocks().
+ */
+ handle = ext4_journal_start_sb(sb, 3);
+ if (IS_ERR(handle)) {
+ err = PTR_ERR(handle);
+ ext4_warning(sb, __FUNCTION__, "error %d on journal start",err);
+ goto exit_put;
+ }
+
+ lock_super(sb);
+ if (o_blocks_count != ext4_blocks_count(es)) {
+ ext4_warning(sb, __FUNCTION__,
+ "multiple resizers run on filesystem!");
+ unlock_super(sb);
+ err = -EBUSY;
+ goto exit_put;
+ }
+
+ if ((err = ext4_journal_get_write_access(handle,
+ EXT4_SB(sb)->s_sbh))) {
+ ext4_warning(sb, __FUNCTION__,
+ "error %d on journal write access", err);
+ unlock_super(sb);
+ ext4_journal_stop(handle);
+ goto exit_put;
+ }
+ ext4_blocks_count_set(es, o_blocks_count + add);
+ ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
+ sb->s_dirt = 1;
+ unlock_super(sb);
+ ext4_debug("freeing blocks %lu through %llu\n", o_blocks_count,
+ o_blocks_count + add);
+ ext4_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks);
+ ext4_debug("freed blocks %llu through %llu\n", o_blocks_count,
+ o_blocks_count + add);
+ if ((err = ext4_journal_stop(handle)))
+ goto exit_put;
+ if (test_opt(sb, DEBUG))
+ printk(KERN_DEBUG "EXT4-fs: extended group to %llu blocks\n",
+ ext4_blocks_count(es));
+ update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, (char *)es,
+ sizeof(struct ext4_super_block));
+exit_put:
+ return err;
+} /* ext4_group_extend */
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
new file mode 100644
index 000000000000..b4b022aa2bc2
--- /dev/null
+++ b/fs/ext4/super.c
@@ -0,0 +1,2829 @@
+/*
+ * linux/fs/ext4/super.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/inode.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * Big-endian to little-endian byte-swapping/bitmaps by
+ * David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/time.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/parser.h>
+#include <linux/smp_lock.h>
+#include <linux/buffer_head.h>
+#include <linux/vfs.h>
+#include <linux/random.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/quotaops.h>
+#include <linux/seq_file.h>
+
+#include <asm/uaccess.h>
+
+#include "xattr.h"
+#include "acl.h"
+#include "namei.h"
+
+static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
+ unsigned long journal_devnum);
+static int ext4_create_journal(struct super_block *, struct ext4_super_block *,
+ unsigned int);
+static void ext4_commit_super (struct super_block * sb,
+ struct ext4_super_block * es,
+ int sync);
+static void ext4_mark_recovery_complete(struct super_block * sb,
+ struct ext4_super_block * es);
+static void ext4_clear_journal_err(struct super_block * sb,
+ struct ext4_super_block * es);
+static int ext4_sync_fs(struct super_block *sb, int wait);
+static const char *ext4_decode_error(struct super_block * sb, int errno,
+ char nbuf[16]);
+static int ext4_remount (struct super_block * sb, int * flags, char * data);
+static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf);
+static void ext4_unlockfs(struct super_block *sb);
+static void ext4_write_super (struct super_block * sb);
+static void ext4_write_super_lockfs(struct super_block *sb);
+
+
+ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le32_to_cpu(bg->bg_block_bitmap) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
+}
+
+ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le32_to_cpu(bg->bg_inode_bitmap) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
+}
+
+ext4_fsblk_t ext4_inode_table(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le32_to_cpu(bg->bg_inode_table) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
+}
+
+void ext4_block_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk)
+{
+ bg->bg_block_bitmap = cpu_to_le32((u32)blk);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
+}
+
+void ext4_inode_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk)
+{
+ bg->bg_inode_bitmap = cpu_to_le32((u32)blk);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
+}
+
+void ext4_inode_table_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk)
+{
+ bg->bg_inode_table = cpu_to_le32((u32)blk);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
+}
+
+/*
+ * Wrappers for jbd2_journal_start/end.
+ *
+ * The only special thing we need to do here is to make sure that all
+ * journal_end calls result in the superblock being marked dirty, so
+ * that sync() will call the filesystem's write_super callback if
+ * appropriate.
+ */
+handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
+{
+ journal_t *journal;
+
+ if (sb->s_flags & MS_RDONLY)
+ return ERR_PTR(-EROFS);
+
+ /* Special case here: if the journal has aborted behind our
+ * backs (eg. EIO in the commit thread), then we still need to
+ * take the FS itself readonly cleanly. */
+ journal = EXT4_SB(sb)->s_journal;
+ if (is_journal_aborted(journal)) {
+ ext4_abort(sb, __FUNCTION__,
+ "Detected aborted journal");
+ return ERR_PTR(-EROFS);
+ }
+
+ return jbd2_journal_start(journal, nblocks);
+}
+
+/*
+ * The only special thing we need to do here is to make sure that all
+ * jbd2_journal_stop calls result in the superblock being marked dirty, so
+ * that sync() will call the filesystem's write_super callback if
+ * appropriate.
+ */
+int __ext4_journal_stop(const char *where, handle_t *handle)
+{
+ struct super_block *sb;
+ int err;
+ int rc;
+
+ sb = handle->h_transaction->t_journal->j_private;
+ err = handle->h_err;
+ rc = jbd2_journal_stop(handle);
+
+ if (!err)
+ err = rc;
+ if (err)
+ __ext4_std_error(sb, where, err);
+ return err;
+}
+
+void ext4_journal_abort_handle(const char *caller, const char *err_fn,
+ struct buffer_head *bh, handle_t *handle, int err)
+{
+ char nbuf[16];
+ const char *errstr = ext4_decode_error(NULL, err, nbuf);
+
+ if (bh)
+ BUFFER_TRACE(bh, "abort");
+
+ if (!handle->h_err)
+ handle->h_err = err;
+
+ if (is_handle_aborted(handle))
+ return;
+
+ printk(KERN_ERR "%s: aborting transaction: %s in %s\n",
+ caller, errstr, err_fn);
+
+ jbd2_journal_abort_handle(handle);
+}
+
+/* Deal with the reporting of failure conditions on a filesystem such as
+ * inconsistencies detected or read IO failures.
+ *
+ * On ext2, we can store the error state of the filesystem in the
+ * superblock. That is not possible on ext4, because we may have other
+ * write ordering constraints on the superblock which prevent us from
+ * writing it out straight away; and given that the journal is about to
+ * be aborted, we can't rely on the current, or future, transactions to
+ * write out the superblock safely.
+ *
+ * We'll just use the jbd2_journal_abort() error code to record an error in
+ * the journal instead. On recovery, the journal will compain about
+ * that error until we've noted it down and cleared it.
+ */
+
+static void ext4_handle_error(struct super_block *sb)
+{
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+
+ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+ es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
+
+ if (sb->s_flags & MS_RDONLY)
+ return;
+
+ if (!test_opt (sb, ERRORS_CONT)) {
+ journal_t *journal = EXT4_SB(sb)->s_journal;
+
+ EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT;
+ if (journal)
+ jbd2_journal_abort(journal, -EIO);
+ }
+ if (test_opt (sb, ERRORS_RO)) {
+ printk (KERN_CRIT "Remounting filesystem read-only\n");
+ sb->s_flags |= MS_RDONLY;
+ }
+ ext4_commit_super(sb, es, 1);
+ if (test_opt(sb, ERRORS_PANIC))
+ panic("EXT4-fs (device %s): panic forced after error\n",
+ sb->s_id);
+}
+
+void ext4_error (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function);
+ vprintk(fmt, args);
+ printk("\n");
+ va_end(args);
+
+ ext4_handle_error(sb);
+}
+
+static const char *ext4_decode_error(struct super_block * sb, int errno,
+ char nbuf[16])
+{
+ char *errstr = NULL;
+
+ switch (errno) {
+ case -EIO:
+ errstr = "IO failure";
+ break;
+ case -ENOMEM:
+ errstr = "Out of memory";
+ break;
+ case -EROFS:
+ if (!sb || EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT)
+ errstr = "Journal has aborted";
+ else
+ errstr = "Readonly filesystem";
+ break;
+ default:
+ /* If the caller passed in an extra buffer for unknown
+ * errors, textualise them now. Else we just return
+ * NULL. */
+ if (nbuf) {
+ /* Check for truncated error codes... */
+ if (snprintf(nbuf, 16, "error %d", -errno) >= 0)
+ errstr = nbuf;
+ }
+ break;
+ }
+
+ return errstr;
+}
+
+/* __ext4_std_error decodes expected errors from journaling functions
+ * automatically and invokes the appropriate error response. */
+
+void __ext4_std_error (struct super_block * sb, const char * function,
+ int errno)
+{
+ char nbuf[16];
+ const char *errstr;
+
+ /* Special case: if the error is EROFS, and we're not already
+ * inside a transaction, then there's really no point in logging
+ * an error. */
+ if (errno == -EROFS && journal_current_handle() == NULL &&
+ (sb->s_flags & MS_RDONLY))
+ return;
+
+ errstr = ext4_decode_error(sb, errno, nbuf);
+ printk (KERN_CRIT "EXT4-fs error (device %s) in %s: %s\n",
+ sb->s_id, function, errstr);
+
+ ext4_handle_error(sb);
+}
+
+/*
+ * ext4_abort is a much stronger failure handler than ext4_error. The
+ * abort function may be used to deal with unrecoverable failures such
+ * as journal IO errors or ENOMEM at a critical moment in log management.
+ *
+ * We unconditionally force the filesystem into an ABORT|READONLY state,
+ * unless the error response on the fs has been set to panic in which
+ * case we take the easy way out and panic immediately.
+ */
+
+void ext4_abort (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ va_list args;
+
+ printk (KERN_CRIT "ext4_abort called.\n");
+
+ va_start(args, fmt);
+ printk(KERN_CRIT "EXT4-fs error (device %s): %s: ",sb->s_id, function);
+ vprintk(fmt, args);
+ printk("\n");
+ va_end(args);
+
+ if (test_opt(sb, ERRORS_PANIC))
+ panic("EXT4-fs panic from previous error\n");
+
+ if (sb->s_flags & MS_RDONLY)
+ return;
+
+ printk(KERN_CRIT "Remounting filesystem read-only\n");
+ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+ sb->s_flags |= MS_RDONLY;
+ EXT4_SB(sb)->s_mount_opt |= EXT4_MOUNT_ABORT;
+ jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
+}
+
+void ext4_warning (struct super_block * sb, const char * function,
+ const char * fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ printk(KERN_WARNING "EXT4-fs warning (device %s): %s: ",
+ sb->s_id, function);
+ vprintk(fmt, args);
+ printk("\n");
+ va_end(args);
+}
+
+void ext4_update_dynamic_rev(struct super_block *sb)
+{
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+
+ if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV)
+ return;
+
+ ext4_warning(sb, __FUNCTION__,
+ "updating to rev %d because of new feature flag, "
+ "running e2fsck is recommended",
+ EXT4_DYNAMIC_REV);
+
+ es->s_first_ino = cpu_to_le32(EXT4_GOOD_OLD_FIRST_INO);
+ es->s_inode_size = cpu_to_le16(EXT4_GOOD_OLD_INODE_SIZE);
+ es->s_rev_level = cpu_to_le32(EXT4_DYNAMIC_REV);
+ /* leave es->s_feature_*compat flags alone */
+ /* es->s_uuid will be set by e2fsck if empty */
+
+ /*
+ * The rest of the superblock fields should be zero, and if not it
+ * means they are likely already in use, so leave them alone. We
+ * can leave it up to e2fsck to clean up any inconsistencies there.
+ */
+}
+
+/*
+ * Open the external journal device
+ */
+static struct block_device *ext4_blkdev_get(dev_t dev)
+{
+ struct block_device *bdev;
+ char b[BDEVNAME_SIZE];
+
+ bdev = open_by_devnum(dev, FMODE_READ|FMODE_WRITE);
+ if (IS_ERR(bdev))
+ goto fail;
+ return bdev;
+
+fail:
+ printk(KERN_ERR "EXT4: failed to open journal device %s: %ld\n",
+ __bdevname(dev, b), PTR_ERR(bdev));
+ return NULL;
+}
+
+/*
+ * Release the journal device
+ */
+static int ext4_blkdev_put(struct block_device *bdev)
+{
+ bd_release(bdev);
+ return blkdev_put(bdev);
+}
+
+static int ext4_blkdev_remove(struct ext4_sb_info *sbi)
+{
+ struct block_device *bdev;
+ int ret = -ENODEV;
+
+ bdev = sbi->journal_bdev;
+ if (bdev) {
+ ret = ext4_blkdev_put(bdev);
+ sbi->journal_bdev = NULL;
+ }
+ return ret;
+}
+
+static inline struct inode *orphan_list_entry(struct list_head *l)
+{
+ return &list_entry(l, struct ext4_inode_info, i_orphan)->vfs_inode;
+}
+
+static void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi)
+{
+ struct list_head *l;
+
+ printk(KERN_ERR "sb orphan head is %d\n",
+ le32_to_cpu(sbi->s_es->s_last_orphan));
+
+ printk(KERN_ERR "sb_info orphan list:\n");
+ list_for_each(l, &sbi->s_orphan) {
+ struct inode *inode = orphan_list_entry(l);
+ printk(KERN_ERR " "
+ "inode %s:%lu at %p: mode %o, nlink %d, next %d\n",
+ inode->i_sb->s_id, inode->i_ino, inode,
+ inode->i_mode, inode->i_nlink,
+ NEXT_ORPHAN(inode));
+ }
+}
+
+static void ext4_put_super (struct super_block * sb)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_super_block *es = sbi->s_es;
+ int i;
+
+ ext4_ext_release(sb);
+ ext4_xattr_put_super(sb);
+ jbd2_journal_destroy(sbi->s_journal);
+ if (!(sb->s_flags & MS_RDONLY)) {
+ EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+ es->s_state = cpu_to_le16(sbi->s_mount_state);
+ BUFFER_TRACE(sbi->s_sbh, "marking dirty");
+ mark_buffer_dirty(sbi->s_sbh);
+ ext4_commit_super(sb, es, 1);
+ }
+
+ for (i = 0; i < sbi->s_gdb_count; i++)
+ brelse(sbi->s_group_desc[i]);
+ kfree(sbi->s_group_desc);
+ percpu_counter_destroy(&sbi->s_freeblocks_counter);
+ percpu_counter_destroy(&sbi->s_freeinodes_counter);
+ percpu_counter_destroy(&sbi->s_dirs_counter);
+ brelse(sbi->s_sbh);
+#ifdef CONFIG_QUOTA
+ for (i = 0; i < MAXQUOTAS; i++)
+ kfree(sbi->s_qf_names[i]);
+#endif
+
+ /* Debugging code just in case the in-memory inode orphan list
+ * isn't empty. The on-disk one can be non-empty if we've
+ * detected an error and taken the fs readonly, but the
+ * in-memory list had better be clean by this point. */
+ if (!list_empty(&sbi->s_orphan))
+ dump_orphan_list(sb, sbi);
+ J_ASSERT(list_empty(&sbi->s_orphan));
+
+ invalidate_bdev(sb->s_bdev, 0);
+ if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) {
+ /*
+ * Invalidate the journal device's buffers. We don't want them
+ * floating about in memory - the physical journal device may
+ * hotswapped, and it breaks the `ro-after' testing code.
+ */
+ sync_blockdev(sbi->journal_bdev);
+ invalidate_bdev(sbi->journal_bdev, 0);
+ ext4_blkdev_remove(sbi);
+ }
+ sb->s_fs_info = NULL;
+ kfree(sbi);
+ return;
+}
+
+static kmem_cache_t *ext4_inode_cachep;
+
+/*
+ * Called inside transaction, so use GFP_NOFS
+ */
+static struct inode *ext4_alloc_inode(struct super_block *sb)
+{
+ struct ext4_inode_info *ei;
+
+ ei = kmem_cache_alloc(ext4_inode_cachep, SLAB_NOFS);
+ if (!ei)
+ return NULL;
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+ ei->i_acl = EXT4_ACL_NOT_CACHED;
+ ei->i_default_acl = EXT4_ACL_NOT_CACHED;
+#endif
+ ei->i_block_alloc_info = NULL;
+ ei->vfs_inode.i_version = 1;
+ memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
+ return &ei->vfs_inode;
+}
+
+static void ext4_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(ext4_inode_cachep, EXT4_I(inode));
+}
+
+static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct ext4_inode_info *ei = (struct ext4_inode_info *) foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ INIT_LIST_HEAD(&ei->i_orphan);
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ init_rwsem(&ei->xattr_sem);
+#endif
+ mutex_init(&ei->truncate_mutex);
+ inode_init_once(&ei->vfs_inode);
+ }
+}
+
+static int init_inodecache(void)
+{
+ ext4_inode_cachep = kmem_cache_create("ext4_inode_cache",
+ sizeof(struct ext4_inode_info),
+ 0, (SLAB_RECLAIM_ACCOUNT|
+ SLAB_MEM_SPREAD),
+ init_once, NULL);
+ if (ext4_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+static void destroy_inodecache(void)
+{
+ kmem_cache_destroy(ext4_inode_cachep);
+}
+
+static void ext4_clear_inode(struct inode *inode)
+{
+ struct ext4_block_alloc_info *rsv = EXT4_I(inode)->i_block_alloc_info;
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+ if (EXT4_I(inode)->i_acl &&
+ EXT4_I(inode)->i_acl != EXT4_ACL_NOT_CACHED) {
+ posix_acl_release(EXT4_I(inode)->i_acl);
+ EXT4_I(inode)->i_acl = EXT4_ACL_NOT_CACHED;
+ }
+ if (EXT4_I(inode)->i_default_acl &&
+ EXT4_I(inode)->i_default_acl != EXT4_ACL_NOT_CACHED) {
+ posix_acl_release(EXT4_I(inode)->i_default_acl);
+ EXT4_I(inode)->i_default_acl = EXT4_ACL_NOT_CACHED;
+ }
+#endif
+ ext4_discard_reservation(inode);
+ EXT4_I(inode)->i_block_alloc_info = NULL;
+ if (unlikely(rsv))
+ kfree(rsv);
+}
+
+static inline void ext4_show_quota_options(struct seq_file *seq, struct super_block *sb)
+{
+#if defined(CONFIG_QUOTA)
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (sbi->s_jquota_fmt)
+ seq_printf(seq, ",jqfmt=%s",
+ (sbi->s_jquota_fmt == QFMT_VFS_OLD) ? "vfsold": "vfsv0");
+
+ if (sbi->s_qf_names[USRQUOTA])
+ seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]);
+
+ if (sbi->s_qf_names[GRPQUOTA])
+ seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+
+ if (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA)
+ seq_puts(seq, ",usrquota");
+
+ if (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)
+ seq_puts(seq, ",grpquota");
+#endif
+}
+
+static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
+{
+ struct super_block *sb = vfs->mnt_sb;
+
+ if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+ seq_puts(seq, ",data=journal");
+ else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+ seq_puts(seq, ",data=ordered");
+ else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+ seq_puts(seq, ",data=writeback");
+
+ ext4_show_quota_options(seq, sb);
+
+ return 0;
+}
+
+
+static struct dentry *ext4_get_dentry(struct super_block *sb, void *vobjp)
+{
+ __u32 *objp = vobjp;
+ unsigned long ino = objp[0];
+ __u32 generation = objp[1];
+ struct inode *inode;
+ struct dentry *result;
+
+ if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO)
+ return ERR_PTR(-ESTALE);
+ if (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count))
+ return ERR_PTR(-ESTALE);
+
+ /* iget isn't really right if the inode is currently unallocated!!
+ *
+ * ext4_read_inode will return a bad_inode if the inode had been
+ * deleted, so we should be safe.
+ *
+ * Currently we don't know the generation for parent directory, so
+ * a generation of 0 means "accept any"
+ */
+ inode = iget(sb, ino);
+ if (inode == NULL)
+ return ERR_PTR(-ENOMEM);
+ if (is_bad_inode(inode) ||
+ (generation && inode->i_generation != generation)) {
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
+ /* now to find a dentry.
+ * If possible, get a well-connected one
+ */
+ result = d_alloc_anon(inode);
+ if (!result) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ return result;
+}
+
+#ifdef CONFIG_QUOTA
+#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group")
+#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA))
+
+static int ext4_dquot_initialize(struct inode *inode, int type);
+static int ext4_dquot_drop(struct inode *inode);
+static int ext4_write_dquot(struct dquot *dquot);
+static int ext4_acquire_dquot(struct dquot *dquot);
+static int ext4_release_dquot(struct dquot *dquot);
+static int ext4_mark_dquot_dirty(struct dquot *dquot);
+static int ext4_write_info(struct super_block *sb, int type);
+static int ext4_quota_on(struct super_block *sb, int type, int format_id, char *path);
+static int ext4_quota_on_mount(struct super_block *sb, int type);
+static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
+ size_t len, loff_t off);
+static ssize_t ext4_quota_write(struct super_block *sb, int type,
+ const char *data, size_t len, loff_t off);
+
+static struct dquot_operations ext4_quota_operations = {
+ .initialize = ext4_dquot_initialize,
+ .drop = ext4_dquot_drop,
+ .alloc_space = dquot_alloc_space,
+ .alloc_inode = dquot_alloc_inode,
+ .free_space = dquot_free_space,
+ .free_inode = dquot_free_inode,
+ .transfer = dquot_transfer,
+ .write_dquot = ext4_write_dquot,
+ .acquire_dquot = ext4_acquire_dquot,
+ .release_dquot = ext4_release_dquot,
+ .mark_dirty = ext4_mark_dquot_dirty,
+ .write_info = ext4_write_info
+};
+
+static struct quotactl_ops ext4_qctl_operations = {
+ .quota_on = ext4_quota_on,
+ .quota_off = vfs_quota_off,
+ .quota_sync = vfs_quota_sync,
+ .get_info = vfs_get_dqinfo,
+ .set_info = vfs_set_dqinfo,
+ .get_dqblk = vfs_get_dqblk,
+ .set_dqblk = vfs_set_dqblk
+};
+#endif
+
+static struct super_operations ext4_sops = {
+ .alloc_inode = ext4_alloc_inode,
+ .destroy_inode = ext4_destroy_inode,
+ .read_inode = ext4_read_inode,
+ .write_inode = ext4_write_inode,
+ .dirty_inode = ext4_dirty_inode,
+ .delete_inode = ext4_delete_inode,
+ .put_super = ext4_put_super,
+ .write_super = ext4_write_super,
+ .sync_fs = ext4_sync_fs,
+ .write_super_lockfs = ext4_write_super_lockfs,
+ .unlockfs = ext4_unlockfs,
+ .statfs = ext4_statfs,
+ .remount_fs = ext4_remount,
+ .clear_inode = ext4_clear_inode,
+ .show_options = ext4_show_options,
+#ifdef CONFIG_QUOTA
+ .quota_read = ext4_quota_read,
+ .quota_write = ext4_quota_write,
+#endif
+};
+
+static struct export_operations ext4_export_ops = {
+ .get_parent = ext4_get_parent,
+ .get_dentry = ext4_get_dentry,
+};
+
+enum {
+ Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
+ Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
+ Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
+ Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+ Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
+ Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
+ Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
+ Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
+ Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
+ Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
+ Opt_grpquota, Opt_extents,
+};
+
+static match_table_t tokens = {
+ {Opt_bsd_df, "bsddf"},
+ {Opt_minix_df, "minixdf"},
+ {Opt_grpid, "grpid"},
+ {Opt_grpid, "bsdgroups"},
+ {Opt_nogrpid, "nogrpid"},
+ {Opt_nogrpid, "sysvgroups"},
+ {Opt_resgid, "resgid=%u"},
+ {Opt_resuid, "resuid=%u"},
+ {Opt_sb, "sb=%u"},
+ {Opt_err_cont, "errors=continue"},
+ {Opt_err_panic, "errors=panic"},
+ {Opt_err_ro, "errors=remount-ro"},
+ {Opt_nouid32, "nouid32"},
+ {Opt_nocheck, "nocheck"},
+ {Opt_nocheck, "check=none"},
+ {Opt_debug, "debug"},
+ {Opt_oldalloc, "oldalloc"},
+ {Opt_orlov, "orlov"},
+ {Opt_user_xattr, "user_xattr"},
+ {Opt_nouser_xattr, "nouser_xattr"},
+ {Opt_acl, "acl"},
+ {Opt_noacl, "noacl"},
+ {Opt_reservation, "reservation"},
+ {Opt_noreservation, "noreservation"},
+ {Opt_noload, "noload"},
+ {Opt_nobh, "nobh"},
+ {Opt_bh, "bh"},
+ {Opt_commit, "commit=%u"},
+ {Opt_journal_update, "journal=update"},
+ {Opt_journal_inum, "journal=%u"},
+ {Opt_journal_dev, "journal_dev=%u"},
+ {Opt_abort, "abort"},
+ {Opt_data_journal, "data=journal"},
+ {Opt_data_ordered, "data=ordered"},
+ {Opt_data_writeback, "data=writeback"},
+ {Opt_offusrjquota, "usrjquota="},
+ {Opt_usrjquota, "usrjquota=%s"},
+ {Opt_offgrpjquota, "grpjquota="},
+ {Opt_grpjquota, "grpjquota=%s"},
+ {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
+ {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
+ {Opt_grpquota, "grpquota"},
+ {Opt_noquota, "noquota"},
+ {Opt_quota, "quota"},
+ {Opt_usrquota, "usrquota"},
+ {Opt_barrier, "barrier=%u"},
+ {Opt_extents, "extents"},
+ {Opt_err, NULL},
+ {Opt_resize, "resize"},
+};
+
+static ext4_fsblk_t get_sb_block(void **data)
+{
+ ext4_fsblk_t sb_block;
+ char *options = (char *) *data;
+
+ if (!options || strncmp(options, "sb=", 3) != 0)
+ return 1; /* Default location */
+ options += 3;
+ /*todo: use simple_strtoll with >32bit ext4 */
+ sb_block = simple_strtoul(options, &options, 0);
+ if (*options && *options != ',') {
+ printk("EXT4-fs: Invalid sb specification: %s\n",
+ (char *) *data);
+ return 1;
+ }
+ if (*options == ',')
+ options++;
+ *data = (void *) options;
+ return sb_block;
+}
+
+static int parse_options (char *options, struct super_block *sb,
+ unsigned int *inum, unsigned long *journal_devnum,
+ ext4_fsblk_t *n_blocks_count, int is_remount)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ char * p;
+ substring_t args[MAX_OPT_ARGS];
+ int data_opt = 0;
+ int option;
+#ifdef CONFIG_QUOTA
+ int qtype;
+ char *qname;
+#endif
+
+ if (!options)
+ return 1;
+
+ while ((p = strsep (&options, ",")) != NULL) {
+ int token;
+ if (!*p)
+ continue;
+
+ token = match_token(p, tokens, args);
+ switch (token) {
+ case Opt_bsd_df:
+ clear_opt (sbi->s_mount_opt, MINIX_DF);
+ break;
+ case Opt_minix_df:
+ set_opt (sbi->s_mount_opt, MINIX_DF);
+ break;
+ case Opt_grpid:
+ set_opt (sbi->s_mount_opt, GRPID);
+ break;
+ case Opt_nogrpid:
+ clear_opt (sbi->s_mount_opt, GRPID);
+ break;
+ case Opt_resuid:
+ if (match_int(&args[0], &option))
+ return 0;
+ sbi->s_resuid = option;
+ break;
+ case Opt_resgid:
+ if (match_int(&args[0], &option))
+ return 0;
+ sbi->s_resgid = option;
+ break;
+ case Opt_sb:
+ /* handled by get_sb_block() instead of here */
+ /* *sb_block = match_int(&args[0]); */
+ break;
+ case Opt_err_panic:
+ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+ clear_opt (sbi->s_mount_opt, ERRORS_RO);
+ set_opt (sbi->s_mount_opt, ERRORS_PANIC);
+ break;
+ case Opt_err_ro:
+ clear_opt (sbi->s_mount_opt, ERRORS_CONT);
+ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+ set_opt (sbi->s_mount_opt, ERRORS_RO);
+ break;
+ case Opt_err_cont:
+ clear_opt (sbi->s_mount_opt, ERRORS_RO);
+ clear_opt (sbi->s_mount_opt, ERRORS_PANIC);
+ set_opt (sbi->s_mount_opt, ERRORS_CONT);
+ break;
+ case Opt_nouid32:
+ set_opt (sbi->s_mount_opt, NO_UID32);
+ break;
+ case Opt_nocheck:
+ clear_opt (sbi->s_mount_opt, CHECK);
+ break;
+ case Opt_debug:
+ set_opt (sbi->s_mount_opt, DEBUG);
+ break;
+ case Opt_oldalloc:
+ set_opt (sbi->s_mount_opt, OLDALLOC);
+ break;
+ case Opt_orlov:
+ clear_opt (sbi->s_mount_opt, OLDALLOC);
+ break;
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ case Opt_user_xattr:
+ set_opt (sbi->s_mount_opt, XATTR_USER);
+ break;
+ case Opt_nouser_xattr:
+ clear_opt (sbi->s_mount_opt, XATTR_USER);
+ break;
+#else
+ case Opt_user_xattr:
+ case Opt_nouser_xattr:
+ printk("EXT4 (no)user_xattr options not supported\n");
+ break;
+#endif
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+ case Opt_acl:
+ set_opt(sbi->s_mount_opt, POSIX_ACL);
+ break;
+ case Opt_noacl:
+ clear_opt(sbi->s_mount_opt, POSIX_ACL);
+ break;
+#else
+ case Opt_acl:
+ case Opt_noacl:
+ printk("EXT4 (no)acl options not supported\n");
+ break;
+#endif
+ case Opt_reservation:
+ set_opt(sbi->s_mount_opt, RESERVATION);
+ break;
+ case Opt_noreservation:
+ clear_opt(sbi->s_mount_opt, RESERVATION);
+ break;
+ case Opt_journal_update:
+ /* @@@ FIXME */
+ /* Eventually we will want to be able to create
+ a journal file here. For now, only allow the
+ user to specify an existing inode to be the
+ journal file. */
+ if (is_remount) {
+ printk(KERN_ERR "EXT4-fs: cannot specify "
+ "journal on remount\n");
+ return 0;
+ }
+ set_opt (sbi->s_mount_opt, UPDATE_JOURNAL);
+ break;
+ case Opt_journal_inum:
+ if (is_remount) {
+ printk(KERN_ERR "EXT4-fs: cannot specify "
+ "journal on remount\n");
+ return 0;
+ }
+ if (match_int(&args[0], &option))
+ return 0;
+ *inum = option;
+ break;
+ case Opt_journal_dev:
+ if (is_remount) {
+ printk(KERN_ERR "EXT4-fs: cannot specify "
+ "journal on remount\n");
+ return 0;
+ }
+ if (match_int(&args[0], &option))
+ return 0;
+ *journal_devnum = option;
+ break;
+ case Opt_noload:
+ set_opt (sbi->s_mount_opt, NOLOAD);
+ break;
+ case Opt_commit:
+ if (match_int(&args[0], &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ if (option == 0)
+ option = JBD_DEFAULT_MAX_COMMIT_AGE;
+ sbi->s_commit_interval = HZ * option;
+ break;
+ case Opt_data_journal:
+ data_opt = EXT4_MOUNT_JOURNAL_DATA;
+ goto datacheck;
+ case Opt_data_ordered:
+ data_opt = EXT4_MOUNT_ORDERED_DATA;
+ goto datacheck;
+ case Opt_data_writeback:
+ data_opt = EXT4_MOUNT_WRITEBACK_DATA;
+ datacheck:
+ if (is_remount) {
+ if ((sbi->s_mount_opt & EXT4_MOUNT_DATA_FLAGS)
+ != data_opt) {
+ printk(KERN_ERR
+ "EXT4-fs: cannot change data "
+ "mode on remount\n");
+ return 0;
+ }
+ } else {
+ sbi->s_mount_opt &= ~EXT4_MOUNT_DATA_FLAGS;
+ sbi->s_mount_opt |= data_opt;
+ }
+ break;
+#ifdef CONFIG_QUOTA
+ case Opt_usrjquota:
+ qtype = USRQUOTA;
+ goto set_qf_name;
+ case Opt_grpjquota:
+ qtype = GRPQUOTA;
+set_qf_name:
+ if (sb_any_quota_enabled(sb)) {
+ printk(KERN_ERR
+ "EXT4-fs: Cannot change journalled "
+ "quota options when quota turned on.\n");
+ return 0;
+ }
+ qname = match_strdup(&args[0]);
+ if (!qname) {
+ printk(KERN_ERR
+ "EXT4-fs: not enough memory for "
+ "storing quotafile name.\n");
+ return 0;
+ }
+ if (sbi->s_qf_names[qtype] &&
+ strcmp(sbi->s_qf_names[qtype], qname)) {
+ printk(KERN_ERR
+ "EXT4-fs: %s quota file already "
+ "specified.\n", QTYPE2NAME(qtype));
+ kfree(qname);
+ return 0;
+ }
+ sbi->s_qf_names[qtype] = qname;
+ if (strchr(sbi->s_qf_names[qtype], '/')) {
+ printk(KERN_ERR
+ "EXT4-fs: quotafile must be on "
+ "filesystem root.\n");
+ kfree(sbi->s_qf_names[qtype]);
+ sbi->s_qf_names[qtype] = NULL;
+ return 0;
+ }
+ set_opt(sbi->s_mount_opt, QUOTA);
+ break;
+ case Opt_offusrjquota:
+ qtype = USRQUOTA;
+ goto clear_qf_name;
+ case Opt_offgrpjquota:
+ qtype = GRPQUOTA;
+clear_qf_name:
+ if (sb_any_quota_enabled(sb)) {
+ printk(KERN_ERR "EXT4-fs: Cannot change "
+ "journalled quota options when "
+ "quota turned on.\n");
+ return 0;
+ }
+ /*
+ * The space will be released later when all options
+ * are confirmed to be correct
+ */
+ sbi->s_qf_names[qtype] = NULL;
+ break;
+ case Opt_jqfmt_vfsold:
+ sbi->s_jquota_fmt = QFMT_VFS_OLD;
+ break;
+ case Opt_jqfmt_vfsv0:
+ sbi->s_jquota_fmt = QFMT_VFS_V0;
+ break;
+ case Opt_quota:
+ case Opt_usrquota:
+ set_opt(sbi->s_mount_opt, QUOTA);
+ set_opt(sbi->s_mount_opt, USRQUOTA);
+ break;
+ case Opt_grpquota:
+ set_opt(sbi->s_mount_opt, QUOTA);
+ set_opt(sbi->s_mount_opt, GRPQUOTA);
+ break;
+ case Opt_noquota:
+ if (sb_any_quota_enabled(sb)) {
+ printk(KERN_ERR "EXT4-fs: Cannot change quota "
+ "options when quota turned on.\n");
+ return 0;
+ }
+ clear_opt(sbi->s_mount_opt, QUOTA);
+ clear_opt(sbi->s_mount_opt, USRQUOTA);
+ clear_opt(sbi->s_mount_opt, GRPQUOTA);
+ break;
+#else
+ case Opt_quota:
+ case Opt_usrquota:
+ case Opt_grpquota:
+ case Opt_usrjquota:
+ case Opt_grpjquota:
+ case Opt_offusrjquota:
+ case Opt_offgrpjquota:
+ case Opt_jqfmt_vfsold:
+ case Opt_jqfmt_vfsv0:
+ printk(KERN_ERR
+ "EXT4-fs: journalled quota options not "
+ "supported.\n");
+ break;
+ case Opt_noquota:
+ break;
+#endif
+ case Opt_abort:
+ set_opt(sbi->s_mount_opt, ABORT);
+ break;
+ case Opt_barrier:
+ if (match_int(&args[0], &option))
+ return 0;
+ if (option)
+ set_opt(sbi->s_mount_opt, BARRIER);
+ else
+ clear_opt(sbi->s_mount_opt, BARRIER);
+ break;
+ case Opt_ignore:
+ break;
+ case Opt_resize:
+ if (!is_remount) {
+ printk("EXT4-fs: resize option only available "
+ "for remount\n");
+ return 0;
+ }
+ if (match_int(&args[0], &option) != 0)
+ return 0;
+ *n_blocks_count = option;
+ break;
+ case Opt_nobh:
+ set_opt(sbi->s_mount_opt, NOBH);
+ break;
+ case Opt_bh:
+ clear_opt(sbi->s_mount_opt, NOBH);
+ break;
+ case Opt_extents:
+ set_opt (sbi->s_mount_opt, EXTENTS);
+ break;
+ default:
+ printk (KERN_ERR
+ "EXT4-fs: Unrecognized mount option \"%s\" "
+ "or missing value\n", p);
+ return 0;
+ }
+ }
+#ifdef CONFIG_QUOTA
+ if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+ if ((sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA) &&
+ sbi->s_qf_names[USRQUOTA])
+ clear_opt(sbi->s_mount_opt, USRQUOTA);
+
+ if ((sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA) &&
+ sbi->s_qf_names[GRPQUOTA])
+ clear_opt(sbi->s_mount_opt, GRPQUOTA);
+
+ if ((sbi->s_qf_names[USRQUOTA] &&
+ (sbi->s_mount_opt & EXT4_MOUNT_GRPQUOTA)) ||
+ (sbi->s_qf_names[GRPQUOTA] &&
+ (sbi->s_mount_opt & EXT4_MOUNT_USRQUOTA))) {
+ printk(KERN_ERR "EXT4-fs: old and new quota "
+ "format mixing.\n");
+ return 0;
+ }
+
+ if (!sbi->s_jquota_fmt) {
+ printk(KERN_ERR "EXT4-fs: journalled quota format "
+ "not specified.\n");
+ return 0;
+ }
+ } else {
+ if (sbi->s_jquota_fmt) {
+ printk(KERN_ERR "EXT4-fs: journalled quota format "
+ "specified with no journalling "
+ "enabled.\n");
+ return 0;
+ }
+ }
+#endif
+ return 1;
+}
+
+static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
+ int read_only)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ int res = 0;
+
+ if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) {
+ printk (KERN_ERR "EXT4-fs warning: revision level too high, "
+ "forcing read-only mode\n");
+ res = MS_RDONLY;
+ }
+ if (read_only)
+ return res;
+ if (!(sbi->s_mount_state & EXT4_VALID_FS))
+ printk (KERN_WARNING "EXT4-fs warning: mounting unchecked fs, "
+ "running e2fsck is recommended\n");
+ else if ((sbi->s_mount_state & EXT4_ERROR_FS))
+ printk (KERN_WARNING
+ "EXT4-fs warning: mounting fs with errors, "
+ "running e2fsck is recommended\n");
+ else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+ le16_to_cpu(es->s_mnt_count) >=
+ (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
+ printk (KERN_WARNING
+ "EXT4-fs warning: maximal mount count reached, "
+ "running e2fsck is recommended\n");
+ else if (le32_to_cpu(es->s_checkinterval) &&
+ (le32_to_cpu(es->s_lastcheck) +
+ le32_to_cpu(es->s_checkinterval) <= get_seconds()))
+ printk (KERN_WARNING
+ "EXT4-fs warning: checktime reached, "
+ "running e2fsck is recommended\n");
+#if 0
+ /* @@@ We _will_ want to clear the valid bit if we find
+ * inconsistencies, to force a fsck at reboot. But for
+ * a plain journaled filesystem we can keep it set as
+ * valid forever! :)
+ */
+ es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT4_VALID_FS);
+#endif
+ if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+ es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT);
+ es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+ es->s_mtime = cpu_to_le32(get_seconds());
+ ext4_update_dynamic_rev(sb);
+ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+
+ ext4_commit_super(sb, es, 1);
+ if (test_opt(sb, DEBUG))
+ printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%lu, "
+ "bpg=%lu, ipg=%lu, mo=%04lx]\n",
+ sb->s_blocksize,
+ sbi->s_groups_count,
+ EXT4_BLOCKS_PER_GROUP(sb),
+ EXT4_INODES_PER_GROUP(sb),
+ sbi->s_mount_opt);
+
+ printk(KERN_INFO "EXT4 FS on %s, ", sb->s_id);
+ if (EXT4_SB(sb)->s_journal->j_inode == NULL) {
+ char b[BDEVNAME_SIZE];
+
+ printk("external journal on %s\n",
+ bdevname(EXT4_SB(sb)->s_journal->j_dev, b));
+ } else {
+ printk("internal journal\n");
+ }
+ return res;
+}
+
+/* Called at mount-time, super-block is locked */
+static int ext4_check_descriptors (struct super_block * sb)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
+ ext4_fsblk_t last_block;
+ ext4_fsblk_t block_bitmap;
+ ext4_fsblk_t inode_bitmap;
+ ext4_fsblk_t inode_table;
+ struct ext4_group_desc * gdp = NULL;
+ int desc_block = 0;
+ int i;
+
+ ext4_debug ("Checking group descriptors");
+
+ for (i = 0; i < sbi->s_groups_count; i++)
+ {
+ if (i == sbi->s_groups_count - 1)
+ last_block = ext4_blocks_count(sbi->s_es) - 1;
+ else
+ last_block = first_block +
+ (EXT4_BLOCKS_PER_GROUP(sb) - 1);
+
+ if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0)
+ gdp = (struct ext4_group_desc *)
+ sbi->s_group_desc[desc_block++]->b_data;
+ block_bitmap = ext4_block_bitmap(sb, gdp);
+ if (block_bitmap < first_block || block_bitmap > last_block)
+ {
+ ext4_error (sb, "ext4_check_descriptors",
+ "Block bitmap for group %d"
+ " not in group (block %llu)!",
+ i, block_bitmap);
+ return 0;
+ }
+ inode_bitmap = ext4_inode_bitmap(sb, gdp);
+ if (inode_bitmap < first_block || inode_bitmap > last_block)
+ {
+ ext4_error (sb, "ext4_check_descriptors",
+ "Inode bitmap for group %d"
+ " not in group (block %llu)!",
+ i, inode_bitmap);
+ return 0;
+ }
+ inode_table = ext4_inode_table(sb, gdp);
+ if (inode_table < first_block ||
+ inode_table + sbi->s_itb_per_group > last_block)
+ {
+ ext4_error (sb, "ext4_check_descriptors",
+ "Inode table for group %d"
+ " not in group (block %llu)!",
+ i, inode_table);
+ return 0;
+ }
+ first_block += EXT4_BLOCKS_PER_GROUP(sb);
+ gdp = (struct ext4_group_desc *)
+ ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
+ }
+
+ ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
+ sbi->s_es->s_free_inodes_count=cpu_to_le32(ext4_count_free_inodes(sb));
+ return 1;
+}
+
+
+/* ext4_orphan_cleanup() walks a singly-linked list of inodes (starting at
+ * the superblock) which were deleted from all directories, but held open by
+ * a process at the time of a crash. We walk the list and try to delete these
+ * inodes at recovery time (only with a read-write filesystem).
+ *
+ * In order to keep the orphan inode chain consistent during traversal (in
+ * case of crash during recovery), we link each inode into the superblock
+ * orphan list_head and handle it the same way as an inode deletion during
+ * normal operation (which journals the operations for us).
+ *
+ * We only do an iget() and an iput() on each inode, which is very safe if we
+ * accidentally point at an in-use or already deleted inode. The worst that
+ * can happen in this case is that we get a "bit already cleared" message from
+ * ext4_free_inode(). The only reason we would point at a wrong inode is if
+ * e2fsck was run on this filesystem, and it must have already done the orphan
+ * inode cleanup for us, so we can safely abort without any further action.
+ */
+static void ext4_orphan_cleanup (struct super_block * sb,
+ struct ext4_super_block * es)
+{
+ unsigned int s_flags = sb->s_flags;
+ int nr_orphans = 0, nr_truncates = 0;
+#ifdef CONFIG_QUOTA
+ int i;
+#endif
+ if (!es->s_last_orphan) {
+ jbd_debug(4, "no orphan inodes to clean up\n");
+ return;
+ }
+
+ if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
+ if (es->s_last_orphan)
+ jbd_debug(1, "Errors on filesystem, "
+ "clearing orphan list.\n");
+ es->s_last_orphan = 0;
+ jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
+ return;
+ }
+
+ if (s_flags & MS_RDONLY) {
+ printk(KERN_INFO "EXT4-fs: %s: orphan cleanup on readonly fs\n",
+ sb->s_id);
+ sb->s_flags &= ~MS_RDONLY;
+ }
+#ifdef CONFIG_QUOTA
+ /* Needed for iput() to work correctly and not trash data */
+ sb->s_flags |= MS_ACTIVE;
+ /* Turn on quotas so that they are updated correctly */
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (EXT4_SB(sb)->s_qf_names[i]) {
+ int ret = ext4_quota_on_mount(sb, i);
+ if (ret < 0)
+ printk(KERN_ERR
+ "EXT4-fs: Cannot turn on journalled "
+ "quota: error %d\n", ret);
+ }
+ }
+#endif
+
+ while (es->s_last_orphan) {
+ struct inode *inode;
+
+ if (!(inode =
+ ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)))) {
+ es->s_last_orphan = 0;
+ break;
+ }
+
+ list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan);
+ DQUOT_INIT(inode);
+ if (inode->i_nlink) {
+ printk(KERN_DEBUG
+ "%s: truncating inode %lu to %Ld bytes\n",
+ __FUNCTION__, inode->i_ino, inode->i_size);
+ jbd_debug(2, "truncating inode %lu to %Ld bytes\n",
+ inode->i_ino, inode->i_size);
+ ext4_truncate(inode);
+ nr_truncates++;
+ } else {
+ printk(KERN_DEBUG
+ "%s: deleting unreferenced inode %lu\n",
+ __FUNCTION__, inode->i_ino);
+ jbd_debug(2, "deleting unreferenced inode %lu\n",
+ inode->i_ino);
+ nr_orphans++;
+ }
+ iput(inode); /* The delete magic happens here! */
+ }
+
+#define PLURAL(x) (x), ((x)==1) ? "" : "s"
+
+ if (nr_orphans)
+ printk(KERN_INFO "EXT4-fs: %s: %d orphan inode%s deleted\n",
+ sb->s_id, PLURAL(nr_orphans));
+ if (nr_truncates)
+ printk(KERN_INFO "EXT4-fs: %s: %d truncate%s cleaned up\n",
+ sb->s_id, PLURAL(nr_truncates));
+#ifdef CONFIG_QUOTA
+ /* Turn quotas off */
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (sb_dqopt(sb)->files[i])
+ vfs_quota_off(sb, i);
+ }
+#endif
+ sb->s_flags = s_flags; /* Restore MS_RDONLY status */
+}
+
+#define log2(n) ffz(~(n))
+
+/*
+ * Maximal file size. There is a direct, and {,double-,triple-}indirect
+ * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks.
+ * We need to be 1 filesystem block less than the 2^32 sector limit.
+ */
+static loff_t ext4_max_size(int bits)
+{
+ loff_t res = EXT4_NDIR_BLOCKS;
+ /* This constant is calculated to be the largest file size for a
+ * dense, 4k-blocksize file such that the total number of
+ * sectors in the file, including data and all indirect blocks,
+ * does not exceed 2^32. */
+ const loff_t upper_limit = 0x1ff7fffd000LL;
+
+ res += 1LL << (bits-2);
+ res += 1LL << (2*(bits-2));
+ res += 1LL << (3*(bits-2));
+ res <<= bits;
+ if (res > upper_limit)
+ res = upper_limit;
+ return res;
+}
+
+static ext4_fsblk_t descriptor_loc(struct super_block *sb,
+ ext4_fsblk_t logical_sb_block, int nr)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ unsigned long bg, first_meta_bg;
+ int has_super = 0;
+
+ first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
+ nr < first_meta_bg)
+ return logical_sb_block + nr + 1;
+ bg = sbi->s_desc_per_block * nr;
+ if (ext4_bg_has_super(sb, bg))
+ has_super = 1;
+ return (has_super + ext4_group_first_block_no(sb, bg));
+}
+
+
+static int ext4_fill_super (struct super_block *sb, void *data, int silent)
+{
+ struct buffer_head * bh;
+ struct ext4_super_block *es = NULL;
+ struct ext4_sb_info *sbi;
+ ext4_fsblk_t block;
+ ext4_fsblk_t sb_block = get_sb_block(&data);
+ ext4_fsblk_t logical_sb_block;
+ unsigned long offset = 0;
+ unsigned int journal_inum = 0;
+ unsigned long journal_devnum = 0;
+ unsigned long def_mount_opts;
+ struct inode *root;
+ int blocksize;
+ int hblock;
+ int db_count;
+ int i;
+ int needs_recovery;
+ __le32 features;
+ __u64 blocks_count;
+
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
+ if (!sbi)
+ return -ENOMEM;
+ sb->s_fs_info = sbi;
+ sbi->s_mount_opt = 0;
+ sbi->s_resuid = EXT4_DEF_RESUID;
+ sbi->s_resgid = EXT4_DEF_RESGID;
+
+ unlock_kernel();
+
+ blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);
+ if (!blocksize) {
+ printk(KERN_ERR "EXT4-fs: unable to set blocksize\n");
+ goto out_fail;
+ }
+
+ /*
+ * The ext4 superblock will not be buffer aligned for other than 1kB
+ * block sizes. We need to calculate the offset from buffer start.
+ */
+ if (blocksize != EXT4_MIN_BLOCK_SIZE) {
+ logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
+ offset = do_div(logical_sb_block, blocksize);
+ } else {
+ logical_sb_block = sb_block;
+ }
+
+ if (!(bh = sb_bread(sb, logical_sb_block))) {
+ printk (KERN_ERR "EXT4-fs: unable to read superblock\n");
+ goto out_fail;
+ }
+ /*
+ * Note: s_es must be initialized as soon as possible because
+ * some ext4 macro-instructions depend on its value
+ */
+ es = (struct ext4_super_block *) (((char *)bh->b_data) + offset);
+ sbi->s_es = es;
+ sb->s_magic = le16_to_cpu(es->s_magic);
+ if (sb->s_magic != EXT4_SUPER_MAGIC)
+ goto cantfind_ext4;
+
+ /* Set defaults before we parse the mount options */
+ def_mount_opts = le32_to_cpu(es->s_default_mount_opts);
+ if (def_mount_opts & EXT4_DEFM_DEBUG)
+ set_opt(sbi->s_mount_opt, DEBUG);
+ if (def_mount_opts & EXT4_DEFM_BSDGROUPS)
+ set_opt(sbi->s_mount_opt, GRPID);
+ if (def_mount_opts & EXT4_DEFM_UID16)
+ set_opt(sbi->s_mount_opt, NO_UID32);
+ if (def_mount_opts & EXT4_DEFM_XATTR_USER)
+ set_opt(sbi->s_mount_opt, XATTR_USER);
+ if (def_mount_opts & EXT4_DEFM_ACL)
+ set_opt(sbi->s_mount_opt, POSIX_ACL);
+ if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
+ sbi->s_mount_opt |= EXT4_MOUNT_JOURNAL_DATA;
+ else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
+ sbi->s_mount_opt |= EXT4_MOUNT_ORDERED_DATA;
+ else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK)
+ sbi->s_mount_opt |= EXT4_MOUNT_WRITEBACK_DATA;
+
+ if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC)
+ set_opt(sbi->s_mount_opt, ERRORS_PANIC);
+ else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_RO)
+ set_opt(sbi->s_mount_opt, ERRORS_RO);
+ else
+ set_opt(sbi->s_mount_opt, ERRORS_CONT);
+
+ sbi->s_resuid = le16_to_cpu(es->s_def_resuid);
+ sbi->s_resgid = le16_to_cpu(es->s_def_resgid);
+
+ set_opt(sbi->s_mount_opt, RESERVATION);
+
+ if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
+ NULL, 0))
+ goto failed_mount;
+
+ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+ ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+
+ if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV &&
+ (EXT4_HAS_COMPAT_FEATURE(sb, ~0U) ||
+ EXT4_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
+ EXT4_HAS_INCOMPAT_FEATURE(sb, ~0U)))
+ printk(KERN_WARNING
+ "EXT4-fs warning: feature flags set on rev 0 fs, "
+ "running e2fsck is recommended\n");
+ /*
+ * Check feature flags regardless of the revision level, since we
+ * previously didn't change the revision level when setting the flags,
+ * so there is a chance incompat flags are set on a rev 0 filesystem.
+ */
+ features = EXT4_HAS_INCOMPAT_FEATURE(sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
+ if (features) {
+ printk(KERN_ERR "EXT4-fs: %s: couldn't mount because of "
+ "unsupported optional features (%x).\n",
+ sb->s_id, le32_to_cpu(features));
+ goto failed_mount;
+ }
+ features = EXT4_HAS_RO_COMPAT_FEATURE(sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
+ if (!(sb->s_flags & MS_RDONLY) && features) {
+ printk(KERN_ERR "EXT4-fs: %s: couldn't mount RDWR because of "
+ "unsupported optional features (%x).\n",
+ sb->s_id, le32_to_cpu(features));
+ goto failed_mount;
+ }
+ blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size);
+
+ if (blocksize < EXT4_MIN_BLOCK_SIZE ||
+ blocksize > EXT4_MAX_BLOCK_SIZE) {
+ printk(KERN_ERR
+ "EXT4-fs: Unsupported filesystem blocksize %d on %s.\n",
+ blocksize, sb->s_id);
+ goto failed_mount;
+ }
+
+ hblock = bdev_hardsect_size(sb->s_bdev);
+ if (sb->s_blocksize != blocksize) {
+ /*
+ * Make sure the blocksize for the filesystem is larger
+ * than the hardware sectorsize for the machine.
+ */
+ if (blocksize < hblock) {
+ printk(KERN_ERR "EXT4-fs: blocksize %d too small for "
+ "device blocksize %d.\n", blocksize, hblock);
+ goto failed_mount;
+ }
+
+ brelse (bh);
+ sb_set_blocksize(sb, blocksize);
+ logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
+ offset = do_div(logical_sb_block, blocksize);
+ bh = sb_bread(sb, logical_sb_block);
+ if (!bh) {
+ printk(KERN_ERR
+ "EXT4-fs: Can't read superblock on 2nd try.\n");
+ goto failed_mount;
+ }
+ es = (struct ext4_super_block *)(((char *)bh->b_data) + offset);
+ sbi->s_es = es;
+ if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) {
+ printk (KERN_ERR
+ "EXT4-fs: Magic mismatch, very weird !\n");
+ goto failed_mount;
+ }
+ }
+
+ sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits);
+
+ if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) {
+ sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE;
+ sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO;
+ } else {
+ sbi->s_inode_size = le16_to_cpu(es->s_inode_size);
+ sbi->s_first_ino = le32_to_cpu(es->s_first_ino);
+ if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) ||
+ (sbi->s_inode_size & (sbi->s_inode_size - 1)) ||
+ (sbi->s_inode_size > blocksize)) {
+ printk (KERN_ERR
+ "EXT4-fs: unsupported inode size: %d\n",
+ sbi->s_inode_size);
+ goto failed_mount;
+ }
+ }
+ sbi->s_frag_size = EXT4_MIN_FRAG_SIZE <<
+ le32_to_cpu(es->s_log_frag_size);
+ if (blocksize != sbi->s_frag_size) {
+ printk(KERN_ERR
+ "EXT4-fs: fragsize %lu != blocksize %u (unsupported)\n",
+ sbi->s_frag_size, blocksize);
+ goto failed_mount;
+ }
+ sbi->s_desc_size = le16_to_cpu(es->s_desc_size);
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
+ if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
+ sbi->s_desc_size > EXT4_MAX_DESC_SIZE ||
+ sbi->s_desc_size & (sbi->s_desc_size - 1)) {
+ printk(KERN_ERR
+ "EXT4-fs: unsupported descriptor size %lu\n",
+ sbi->s_desc_size);
+ goto failed_mount;
+ }
+ } else
+ sbi->s_desc_size = EXT4_MIN_DESC_SIZE;
+ sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
+ sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
+ sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
+ if (EXT4_INODE_SIZE(sb) == 0)
+ goto cantfind_ext4;
+ sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb);
+ if (sbi->s_inodes_per_block == 0)
+ goto cantfind_ext4;
+ sbi->s_itb_per_group = sbi->s_inodes_per_group /
+ sbi->s_inodes_per_block;
+ sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb);
+ sbi->s_sbh = bh;
+ sbi->s_mount_state = le16_to_cpu(es->s_state);
+ sbi->s_addr_per_block_bits = log2(EXT4_ADDR_PER_BLOCK(sb));
+ sbi->s_desc_per_block_bits = log2(EXT4_DESC_PER_BLOCK(sb));
+ for (i=0; i < 4; i++)
+ sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
+ sbi->s_def_hash_version = es->s_def_hash_version;
+
+ if (sbi->s_blocks_per_group > blocksize * 8) {
+ printk (KERN_ERR
+ "EXT4-fs: #blocks per group too big: %lu\n",
+ sbi->s_blocks_per_group);
+ goto failed_mount;
+ }
+ if (sbi->s_frags_per_group > blocksize * 8) {
+ printk (KERN_ERR
+ "EXT4-fs: #fragments per group too big: %lu\n",
+ sbi->s_frags_per_group);
+ goto failed_mount;
+ }
+ if (sbi->s_inodes_per_group > blocksize * 8) {
+ printk (KERN_ERR
+ "EXT4-fs: #inodes per group too big: %lu\n",
+ sbi->s_inodes_per_group);
+ goto failed_mount;
+ }
+
+ if (ext4_blocks_count(es) >
+ (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) {
+ printk(KERN_ERR "EXT4-fs: filesystem on %s:"
+ " too large to mount safely\n", sb->s_id);
+ if (sizeof(sector_t) < 8)
+ printk(KERN_WARNING "EXT4-fs: CONFIG_LBD not "
+ "enabled\n");
+ goto failed_mount;
+ }
+
+ if (EXT4_BLOCKS_PER_GROUP(sb) == 0)
+ goto cantfind_ext4;
+ blocks_count = (ext4_blocks_count(es) -
+ le32_to_cpu(es->s_first_data_block) +
+ EXT4_BLOCKS_PER_GROUP(sb) - 1);
+ do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb));
+ sbi->s_groups_count = blocks_count;
+ db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /
+ EXT4_DESC_PER_BLOCK(sb);
+ sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *),
+ GFP_KERNEL);
+ if (sbi->s_group_desc == NULL) {
+ printk (KERN_ERR "EXT4-fs: not enough memory\n");
+ goto failed_mount;
+ }
+
+ bgl_lock_init(&sbi->s_blockgroup_lock);
+
+ for (i = 0; i < db_count; i++) {
+ block = descriptor_loc(sb, logical_sb_block, i);
+ sbi->s_group_desc[i] = sb_bread(sb, block);
+ if (!sbi->s_group_desc[i]) {
+ printk (KERN_ERR "EXT4-fs: "
+ "can't read group descriptor %d\n", i);
+ db_count = i;
+ goto failed_mount2;
+ }
+ }
+ if (!ext4_check_descriptors (sb)) {
+ printk(KERN_ERR "EXT4-fs: group descriptors corrupted!\n");
+ goto failed_mount2;
+ }
+ sbi->s_gdb_count = db_count;
+ get_random_bytes(&sbi->s_next_generation, sizeof(u32));
+ spin_lock_init(&sbi->s_next_gen_lock);
+
+ percpu_counter_init(&sbi->s_freeblocks_counter,
+ ext4_count_free_blocks(sb));
+ percpu_counter_init(&sbi->s_freeinodes_counter,
+ ext4_count_free_inodes(sb));
+ percpu_counter_init(&sbi->s_dirs_counter,
+ ext4_count_dirs(sb));
+
+ /* per fileystem reservation list head & lock */
+ spin_lock_init(&sbi->s_rsv_window_lock);
+ sbi->s_rsv_window_root = RB_ROOT;
+ /* Add a single, static dummy reservation to the start of the
+ * reservation window list --- it gives us a placeholder for
+ * append-at-start-of-list which makes the allocation logic
+ * _much_ simpler. */
+ sbi->s_rsv_window_head.rsv_start = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
+ sbi->s_rsv_window_head.rsv_end = EXT4_RESERVE_WINDOW_NOT_ALLOCATED;
+ sbi->s_rsv_window_head.rsv_alloc_hit = 0;
+ sbi->s_rsv_window_head.rsv_goal_size = 0;
+ ext4_rsv_window_add(sb, &sbi->s_rsv_window_head);
+
+ /*
+ * set up enough so that it can read an inode
+ */
+ sb->s_op = &ext4_sops;
+ sb->s_export_op = &ext4_export_ops;
+ sb->s_xattr = ext4_xattr_handlers;
+#ifdef CONFIG_QUOTA
+ sb->s_qcop = &ext4_qctl_operations;
+ sb->dq_op = &ext4_quota_operations;
+#endif
+ INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
+
+ sb->s_root = NULL;
+
+ needs_recovery = (es->s_last_orphan != 0 ||
+ EXT4_HAS_INCOMPAT_FEATURE(sb,
+ EXT4_FEATURE_INCOMPAT_RECOVER));
+
+ /*
+ * The first inode we look at is the journal inode. Don't try
+ * root first: it may be modified in the journal!
+ */
+ if (!test_opt(sb, NOLOAD) &&
+ EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
+ if (ext4_load_journal(sb, es, journal_devnum))
+ goto failed_mount3;
+ } else if (journal_inum) {
+ if (ext4_create_journal(sb, es, journal_inum))
+ goto failed_mount3;
+ } else {
+ if (!silent)
+ printk (KERN_ERR
+ "ext4: No journal on filesystem on %s\n",
+ sb->s_id);
+ goto failed_mount3;
+ }
+
+ /* We have now updated the journal if required, so we can
+ * validate the data journaling mode. */
+ switch (test_opt(sb, DATA_FLAGS)) {
+ case 0:
+ /* No mode set, assume a default based on the journal
+ * capabilities: ORDERED_DATA if the journal can
+ * cope, else JOURNAL_DATA
+ */
+ if (jbd2_journal_check_available_features
+ (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE))
+ set_opt(sbi->s_mount_opt, ORDERED_DATA);
+ else
+ set_opt(sbi->s_mount_opt, JOURNAL_DATA);
+ break;
+
+ case EXT4_MOUNT_ORDERED_DATA:
+ case EXT4_MOUNT_WRITEBACK_DATA:
+ if (!jbd2_journal_check_available_features
+ (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) {
+ printk(KERN_ERR "EXT4-fs: Journal does not support "
+ "requested data journaling mode\n");
+ goto failed_mount4;
+ }
+ default:
+ break;
+ }
+
+ if (test_opt(sb, NOBH)) {
+ if (!(test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)) {
+ printk(KERN_WARNING "EXT4-fs: Ignoring nobh option - "
+ "its supported only with writeback mode\n");
+ clear_opt(sbi->s_mount_opt, NOBH);
+ }
+ }
+ /*
+ * The jbd2_journal_load will have done any necessary log recovery,
+ * so we can safely mount the rest of the filesystem now.
+ */
+
+ root = iget(sb, EXT4_ROOT_INO);
+ sb->s_root = d_alloc_root(root);
+ if (!sb->s_root) {
+ printk(KERN_ERR "EXT4-fs: get root inode failed\n");
+ iput(root);
+ goto failed_mount4;
+ }
+ if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
+ dput(sb->s_root);
+ sb->s_root = NULL;
+ printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n");
+ goto failed_mount4;
+ }
+
+ ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
+ /*
+ * akpm: core read_super() calls in here with the superblock locked.
+ * That deadlocks, because orphan cleanup needs to lock the superblock
+ * in numerous places. Here we just pop the lock - it's relatively
+ * harmless, because we are now ready to accept write_super() requests,
+ * and aviro says that's the only reason for hanging onto the
+ * superblock lock.
+ */
+ EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS;
+ ext4_orphan_cleanup(sb, es);
+ EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS;
+ if (needs_recovery)
+ printk (KERN_INFO "EXT4-fs: recovery complete.\n");
+ ext4_mark_recovery_complete(sb, es);
+ printk (KERN_INFO "EXT4-fs: mounted filesystem with %s data mode.\n",
+ test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA ? "journal":
+ test_opt(sb,DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA ? "ordered":
+ "writeback");
+
+ ext4_ext_init(sb);
+
+ lock_kernel();
+ return 0;
+
+cantfind_ext4:
+ if (!silent)
+ printk(KERN_ERR "VFS: Can't find ext4 filesystem on dev %s.\n",
+ sb->s_id);
+ goto failed_mount;
+
+failed_mount4:
+ jbd2_journal_destroy(sbi->s_journal);
+failed_mount3:
+ percpu_counter_destroy(&sbi->s_freeblocks_counter);
+ percpu_counter_destroy(&sbi->s_freeinodes_counter);
+ percpu_counter_destroy(&sbi->s_dirs_counter);
+failed_mount2:
+ for (i = 0; i < db_count; i++)
+ brelse(sbi->s_group_desc[i]);
+ kfree(sbi->s_group_desc);
+failed_mount:
+#ifdef CONFIG_QUOTA
+ for (i = 0; i < MAXQUOTAS; i++)
+ kfree(sbi->s_qf_names[i]);
+#endif
+ ext4_blkdev_remove(sbi);
+ brelse(bh);
+out_fail:
+ sb->s_fs_info = NULL;
+ kfree(sbi);
+ lock_kernel();
+ return -EINVAL;
+}
+
+/*
+ * Setup any per-fs journal parameters now. We'll do this both on
+ * initial mount, once the journal has been initialised but before we've
+ * done any recovery; and again on any subsequent remount.
+ */
+static void ext4_init_journal_params(struct super_block *sb, journal_t *journal)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (sbi->s_commit_interval)
+ journal->j_commit_interval = sbi->s_commit_interval;
+ /* We could also set up an ext4-specific default for the commit
+ * interval here, but for now we'll just fall back to the jbd
+ * default. */
+
+ spin_lock(&journal->j_state_lock);
+ if (test_opt(sb, BARRIER))
+ journal->j_flags |= JBD2_BARRIER;
+ else
+ journal->j_flags &= ~JBD2_BARRIER;
+ spin_unlock(&journal->j_state_lock);
+}
+
+static journal_t *ext4_get_journal(struct super_block *sb,
+ unsigned int journal_inum)
+{
+ struct inode *journal_inode;
+ journal_t *journal;
+
+ /* First, test for the existence of a valid inode on disk. Bad
+ * things happen if we iget() an unused inode, as the subsequent
+ * iput() will try to delete it. */
+
+ journal_inode = iget(sb, journal_inum);
+ if (!journal_inode) {
+ printk(KERN_ERR "EXT4-fs: no journal found.\n");
+ return NULL;
+ }
+ if (!journal_inode->i_nlink) {
+ make_bad_inode(journal_inode);
+ iput(journal_inode);
+ printk(KERN_ERR "EXT4-fs: journal inode is deleted.\n");
+ return NULL;
+ }
+
+ jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
+ journal_inode, journal_inode->i_size);
+ if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
+ printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
+ iput(journal_inode);
+ return NULL;
+ }
+
+ journal = jbd2_journal_init_inode(journal_inode);
+ if (!journal) {
+ printk(KERN_ERR "EXT4-fs: Could not load journal inode\n");
+ iput(journal_inode);
+ return NULL;
+ }
+ journal->j_private = sb;
+ ext4_init_journal_params(sb, journal);
+ return journal;
+}
+
+static journal_t *ext4_get_dev_journal(struct super_block *sb,
+ dev_t j_dev)
+{
+ struct buffer_head * bh;
+ journal_t *journal;
+ ext4_fsblk_t start;
+ ext4_fsblk_t len;
+ int hblock, blocksize;
+ ext4_fsblk_t sb_block;
+ unsigned long offset;
+ struct ext4_super_block * es;
+ struct block_device *bdev;
+
+ bdev = ext4_blkdev_get(j_dev);
+ if (bdev == NULL)
+ return NULL;
+
+ if (bd_claim(bdev, sb)) {
+ printk(KERN_ERR
+ "EXT4: failed to claim external journal device.\n");
+ blkdev_put(bdev);
+ return NULL;
+ }
+
+ blocksize = sb->s_blocksize;
+ hblock = bdev_hardsect_size(bdev);
+ if (blocksize < hblock) {
+ printk(KERN_ERR
+ "EXT4-fs: blocksize too small for journal device.\n");
+ goto out_bdev;
+ }
+
+ sb_block = EXT4_MIN_BLOCK_SIZE / blocksize;
+ offset = EXT4_MIN_BLOCK_SIZE % blocksize;
+ set_blocksize(bdev, blocksize);
+ if (!(bh = __bread(bdev, sb_block, blocksize))) {
+ printk(KERN_ERR "EXT4-fs: couldn't read superblock of "
+ "external journal\n");
+ goto out_bdev;
+ }
+
+ es = (struct ext4_super_block *) (((char *)bh->b_data) + offset);
+ if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) ||
+ !(le32_to_cpu(es->s_feature_incompat) &
+ EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+ printk(KERN_ERR "EXT4-fs: external journal has "
+ "bad superblock\n");
+ brelse(bh);
+ goto out_bdev;
+ }
+
+ if (memcmp(EXT4_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) {
+ printk(KERN_ERR "EXT4-fs: journal UUID does not match\n");
+ brelse(bh);
+ goto out_bdev;
+ }
+
+ len = ext4_blocks_count(es);
+ start = sb_block + 1;
+ brelse(bh); /* we're done with the superblock */
+
+ journal = jbd2_journal_init_dev(bdev, sb->s_bdev,
+ start, len, blocksize);
+ if (!journal) {
+ printk(KERN_ERR "EXT4-fs: failed to create device journal\n");
+ goto out_bdev;
+ }
+ journal->j_private = sb;
+ ll_rw_block(READ, 1, &journal->j_sb_buffer);
+ wait_on_buffer(journal->j_sb_buffer);
+ if (!buffer_uptodate(journal->j_sb_buffer)) {
+ printk(KERN_ERR "EXT4-fs: I/O error on journal device\n");
+ goto out_journal;
+ }
+ if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) {
+ printk(KERN_ERR "EXT4-fs: External journal has more than one "
+ "user (unsupported) - %d\n",
+ be32_to_cpu(journal->j_superblock->s_nr_users));
+ goto out_journal;
+ }
+ EXT4_SB(sb)->journal_bdev = bdev;
+ ext4_init_journal_params(sb, journal);
+ return journal;
+out_journal:
+ jbd2_journal_destroy(journal);
+out_bdev:
+ ext4_blkdev_put(bdev);
+ return NULL;
+}
+
+static int ext4_load_journal(struct super_block *sb,
+ struct ext4_super_block *es,
+ unsigned long journal_devnum)
+{
+ journal_t *journal;
+ unsigned int journal_inum = le32_to_cpu(es->s_journal_inum);
+ dev_t journal_dev;
+ int err = 0;
+ int really_read_only;
+
+ if (journal_devnum &&
+ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
+ printk(KERN_INFO "EXT4-fs: external journal device major/minor "
+ "numbers have changed\n");
+ journal_dev = new_decode_dev(journal_devnum);
+ } else
+ journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev));
+
+ really_read_only = bdev_read_only(sb->s_bdev);
+
+ /*
+ * Are we loading a blank journal or performing recovery after a
+ * crash? For recovery, we need to check in advance whether we
+ * can get read-write access to the device.
+ */
+
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER)) {
+ if (sb->s_flags & MS_RDONLY) {
+ printk(KERN_INFO "EXT4-fs: INFO: recovery "
+ "required on readonly filesystem.\n");
+ if (really_read_only) {
+ printk(KERN_ERR "EXT4-fs: write access "
+ "unavailable, cannot proceed.\n");
+ return -EROFS;
+ }
+ printk (KERN_INFO "EXT4-fs: write access will "
+ "be enabled during recovery.\n");
+ }
+ }
+
+ if (journal_inum && journal_dev) {
+ printk(KERN_ERR "EXT4-fs: filesystem has both journal "
+ "and inode journals!\n");
+ return -EINVAL;
+ }
+
+ if (journal_inum) {
+ if (!(journal = ext4_get_journal(sb, journal_inum)))
+ return -EINVAL;
+ } else {
+ if (!(journal = ext4_get_dev_journal(sb, journal_dev)))
+ return -EINVAL;
+ }
+
+ if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) {
+ err = jbd2_journal_update_format(journal);
+ if (err) {
+ printk(KERN_ERR "EXT4-fs: error updating journal.\n");
+ jbd2_journal_destroy(journal);
+ return err;
+ }
+ }
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))
+ err = jbd2_journal_wipe(journal, !really_read_only);
+ if (!err)
+ err = jbd2_journal_load(journal);
+
+ if (err) {
+ printk(KERN_ERR "EXT4-fs: error loading journal.\n");
+ jbd2_journal_destroy(journal);
+ return err;
+ }
+
+ EXT4_SB(sb)->s_journal = journal;
+ ext4_clear_journal_err(sb, es);
+
+ if (journal_devnum &&
+ journal_devnum != le32_to_cpu(es->s_journal_dev)) {
+ es->s_journal_dev = cpu_to_le32(journal_devnum);
+ sb->s_dirt = 1;
+
+ /* Make sure we flush the recovery flag to disk. */
+ ext4_commit_super(sb, es, 1);
+ }
+
+ return 0;
+}
+
+static int ext4_create_journal(struct super_block * sb,
+ struct ext4_super_block * es,
+ unsigned int journal_inum)
+{
+ journal_t *journal;
+
+ if (sb->s_flags & MS_RDONLY) {
+ printk(KERN_ERR "EXT4-fs: readonly filesystem when trying to "
+ "create journal.\n");
+ return -EROFS;
+ }
+
+ if (!(journal = ext4_get_journal(sb, journal_inum)))
+ return -EINVAL;
+
+ printk(KERN_INFO "EXT4-fs: creating new journal on inode %u\n",
+ journal_inum);
+
+ if (jbd2_journal_create(journal)) {
+ printk(KERN_ERR "EXT4-fs: error creating journal.\n");
+ jbd2_journal_destroy(journal);
+ return -EIO;
+ }
+
+ EXT4_SB(sb)->s_journal = journal;
+
+ ext4_update_dynamic_rev(sb);
+ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+ EXT4_SET_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_HAS_JOURNAL);
+
+ es->s_journal_inum = cpu_to_le32(journal_inum);
+ sb->s_dirt = 1;
+
+ /* Make sure we flush the recovery flag to disk. */
+ ext4_commit_super(sb, es, 1);
+
+ return 0;
+}
+
+static void ext4_commit_super (struct super_block * sb,
+ struct ext4_super_block * es,
+ int sync)
+{
+ struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
+
+ if (!sbh)
+ return;
+ es->s_wtime = cpu_to_le32(get_seconds());
+ ext4_free_blocks_count_set(es, ext4_count_free_blocks(sb));
+ es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
+ BUFFER_TRACE(sbh, "marking dirty");
+ mark_buffer_dirty(sbh);
+ if (sync)
+ sync_dirty_buffer(sbh);
+}
+
+
+/*
+ * Have we just finished recovery? If so, and if we are mounting (or
+ * remounting) the filesystem readonly, then we will end up with a
+ * consistent fs on disk. Record that fact.
+ */
+static void ext4_mark_recovery_complete(struct super_block * sb,
+ struct ext4_super_block * es)
+{
+ journal_t *journal = EXT4_SB(sb)->s_journal;
+
+ jbd2_journal_lock_updates(journal);
+ jbd2_journal_flush(journal);
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER) &&
+ sb->s_flags & MS_RDONLY) {
+ EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+ sb->s_dirt = 0;
+ ext4_commit_super(sb, es, 1);
+ }
+ jbd2_journal_unlock_updates(journal);
+}
+
+/*
+ * If we are mounting (or read-write remounting) a filesystem whose journal
+ * has recorded an error from a previous lifetime, move that error to the
+ * main filesystem now.
+ */
+static void ext4_clear_journal_err(struct super_block * sb,
+ struct ext4_super_block * es)
+{
+ journal_t *journal;
+ int j_errno;
+ const char *errstr;
+
+ journal = EXT4_SB(sb)->s_journal;
+
+ /*
+ * Now check for any error status which may have been recorded in the
+ * journal by a prior ext4_error() or ext4_abort()
+ */
+
+ j_errno = jbd2_journal_errno(journal);
+ if (j_errno) {
+ char nbuf[16];
+
+ errstr = ext4_decode_error(sb, j_errno, nbuf);
+ ext4_warning(sb, __FUNCTION__, "Filesystem error recorded "
+ "from previous mount: %s", errstr);
+ ext4_warning(sb, __FUNCTION__, "Marking fs in need of "
+ "filesystem check.");
+
+ EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
+ es->s_state |= cpu_to_le16(EXT4_ERROR_FS);
+ ext4_commit_super (sb, es, 1);
+
+ jbd2_journal_clear_err(journal);
+ }
+}
+
+/*
+ * Force the running and committing transactions to commit,
+ * and wait on the commit.
+ */
+int ext4_force_commit(struct super_block *sb)
+{
+ journal_t *journal;
+ int ret;
+
+ if (sb->s_flags & MS_RDONLY)
+ return 0;
+
+ journal = EXT4_SB(sb)->s_journal;
+ sb->s_dirt = 0;
+ ret = ext4_journal_force_commit(journal);
+ return ret;
+}
+
+/*
+ * Ext4 always journals updates to the superblock itself, so we don't
+ * have to propagate any other updates to the superblock on disk at this
+ * point. Just start an async writeback to get the buffers on their way
+ * to the disk.
+ *
+ * This implicitly triggers the writebehind on sync().
+ */
+
+static void ext4_write_super (struct super_block * sb)
+{
+ if (mutex_trylock(&sb->s_lock) != 0)
+ BUG();
+ sb->s_dirt = 0;
+}
+
+static int ext4_sync_fs(struct super_block *sb, int wait)
+{
+ tid_t target;
+
+ sb->s_dirt = 0;
+ if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, &target)) {
+ if (wait)
+ jbd2_log_wait_commit(EXT4_SB(sb)->s_journal, target);
+ }
+ return 0;
+}
+
+/*
+ * LVM calls this function before a (read-only) snapshot is created. This
+ * gives us a chance to flush the journal completely and mark the fs clean.
+ */
+static void ext4_write_super_lockfs(struct super_block *sb)
+{
+ sb->s_dirt = 0;
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ journal_t *journal = EXT4_SB(sb)->s_journal;
+
+ /* Now we set up the journal barrier. */
+ jbd2_journal_lock_updates(journal);
+ jbd2_journal_flush(journal);
+
+ /* Journal blocked and flushed, clear needs_recovery flag. */
+ EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+ ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
+ }
+}
+
+/*
+ * Called by LVM after the snapshot is done. We need to reset the RECOVER
+ * flag here, even though the filesystem is not technically dirty yet.
+ */
+static void ext4_unlockfs(struct super_block *sb)
+{
+ if (!(sb->s_flags & MS_RDONLY)) {
+ lock_super(sb);
+ /* Reser the needs_recovery flag before the fs is unlocked. */
+ EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
+ ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
+ unlock_super(sb);
+ jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal);
+ }
+}
+
+static int ext4_remount (struct super_block * sb, int * flags, char * data)
+{
+ struct ext4_super_block * es;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ ext4_fsblk_t n_blocks_count = 0;
+ unsigned long old_sb_flags;
+ struct ext4_mount_options old_opts;
+ int err;
+#ifdef CONFIG_QUOTA
+ int i;
+#endif
+
+ /* Store the original options */
+ old_sb_flags = sb->s_flags;
+ old_opts.s_mount_opt = sbi->s_mount_opt;
+ old_opts.s_resuid = sbi->s_resuid;
+ old_opts.s_resgid = sbi->s_resgid;
+ old_opts.s_commit_interval = sbi->s_commit_interval;
+#ifdef CONFIG_QUOTA
+ old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
+ for (i = 0; i < MAXQUOTAS; i++)
+ old_opts.s_qf_names[i] = sbi->s_qf_names[i];
+#endif
+
+ /*
+ * Allow the "check" option to be passed as a remount option.
+ */
+ if (!parse_options(data, sb, NULL, NULL, &n_blocks_count, 1)) {
+ err = -EINVAL;
+ goto restore_opts;
+ }
+
+ if (sbi->s_mount_opt & EXT4_MOUNT_ABORT)
+ ext4_abort(sb, __FUNCTION__, "Abort forced by user");
+
+ sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
+ ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
+
+ es = sbi->s_es;
+
+ ext4_init_journal_params(sb, sbi->s_journal);
+
+ if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
+ n_blocks_count > ext4_blocks_count(es)) {
+ if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) {
+ err = -EROFS;
+ goto restore_opts;
+ }
+
+ if (*flags & MS_RDONLY) {
+ /*
+ * First of all, the unconditional stuff we have to do
+ * to disable replay of the journal when we next remount
+ */
+ sb->s_flags |= MS_RDONLY;
+
+ /*
+ * OK, test if we are remounting a valid rw partition
+ * readonly, and if so set the rdonly flag and then
+ * mark the partition as valid again.
+ */
+ if (!(es->s_state & cpu_to_le16(EXT4_VALID_FS)) &&
+ (sbi->s_mount_state & EXT4_VALID_FS))
+ es->s_state = cpu_to_le16(sbi->s_mount_state);
+
+ ext4_mark_recovery_complete(sb, es);
+ } else {
+ __le32 ret;
+ if ((ret = EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ ~EXT4_FEATURE_RO_COMPAT_SUPP))) {
+ printk(KERN_WARNING "EXT4-fs: %s: couldn't "
+ "remount RDWR because of unsupported "
+ "optional features (%x).\n",
+ sb->s_id, le32_to_cpu(ret));
+ err = -EROFS;
+ goto restore_opts;
+ }
+ /*
+ * Mounting a RDONLY partition read-write, so reread
+ * and store the current valid flag. (It may have
+ * been changed by e2fsck since we originally mounted
+ * the partition.)
+ */
+ ext4_clear_journal_err(sb, es);
+ sbi->s_mount_state = le16_to_cpu(es->s_state);
+ if ((err = ext4_group_extend(sb, es, n_blocks_count)))
+ goto restore_opts;
+ if (!ext4_setup_super (sb, es, 0))
+ sb->s_flags &= ~MS_RDONLY;
+ }
+ }
+#ifdef CONFIG_QUOTA
+ /* Release old quota file names */
+ for (i = 0; i < MAXQUOTAS; i++)
+ if (old_opts.s_qf_names[i] &&
+ old_opts.s_qf_names[i] != sbi->s_qf_names[i])
+ kfree(old_opts.s_qf_names[i]);
+#endif
+ return 0;
+restore_opts:
+ sb->s_flags = old_sb_flags;
+ sbi->s_mount_opt = old_opts.s_mount_opt;
+ sbi->s_resuid = old_opts.s_resuid;
+ sbi->s_resgid = old_opts.s_resgid;
+ sbi->s_commit_interval = old_opts.s_commit_interval;
+#ifdef CONFIG_QUOTA
+ sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (sbi->s_qf_names[i] &&
+ old_opts.s_qf_names[i] != sbi->s_qf_names[i])
+ kfree(sbi->s_qf_names[i]);
+ sbi->s_qf_names[i] = old_opts.s_qf_names[i];
+ }
+#endif
+ return err;
+}
+
+static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
+{
+ struct super_block *sb = dentry->d_sb;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ struct ext4_super_block *es = sbi->s_es;
+ ext4_fsblk_t overhead;
+ int i;
+
+ if (test_opt (sb, MINIX_DF))
+ overhead = 0;
+ else {
+ unsigned long ngroups;
+ ngroups = EXT4_SB(sb)->s_groups_count;
+ smp_rmb();
+
+ /*
+ * Compute the overhead (FS structures)
+ */
+
+ /*
+ * All of the blocks before first_data_block are
+ * overhead
+ */
+ overhead = le32_to_cpu(es->s_first_data_block);
+
+ /*
+ * Add the overhead attributed to the superblock and
+ * block group descriptors. If the sparse superblocks
+ * feature is turned on, then not all groups have this.
+ */
+ for (i = 0; i < ngroups; i++) {
+ overhead += ext4_bg_has_super(sb, i) +
+ ext4_bg_num_gdb(sb, i);
+ cond_resched();
+ }
+
+ /*
+ * Every block group has an inode bitmap, a block
+ * bitmap, and an inode table.
+ */
+ overhead += (ngroups * (2 + EXT4_SB(sb)->s_itb_per_group));
+ }
+
+ buf->f_type = EXT4_SUPER_MAGIC;
+ buf->f_bsize = sb->s_blocksize;
+ buf->f_blocks = ext4_blocks_count(es) - overhead;
+ buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
+ buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
+ if (buf->f_bfree < ext4_r_blocks_count(es))
+ buf->f_bavail = 0;
+ buf->f_files = le32_to_cpu(es->s_inodes_count);
+ buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
+ buf->f_namelen = EXT4_NAME_LEN;
+ return 0;
+}
+
+/* Helper function for writing quotas on sync - we need to start transaction before quota file
+ * is locked for write. Otherwise the are possible deadlocks:
+ * Process 1 Process 2
+ * ext4_create() quota_sync()
+ * jbd2_journal_start() write_dquot()
+ * DQUOT_INIT() down(dqio_mutex)
+ * down(dqio_mutex) jbd2_journal_start()
+ *
+ */
+
+#ifdef CONFIG_QUOTA
+
+static inline struct inode *dquot_to_inode(struct dquot *dquot)
+{
+ return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
+}
+
+static int ext4_dquot_initialize(struct inode *inode, int type)
+{
+ handle_t *handle;
+ int ret, err;
+
+ /* We may create quota structure so we need to reserve enough blocks */
+ handle = ext4_journal_start(inode, 2*EXT4_QUOTA_INIT_BLOCKS(inode->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ret = dquot_initialize(inode, type);
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
+static int ext4_dquot_drop(struct inode *inode)
+{
+ handle_t *handle;
+ int ret, err;
+
+ /* We may delete quota structure so we need to reserve enough blocks */
+ handle = ext4_journal_start(inode, 2*EXT4_QUOTA_DEL_BLOCKS(inode->i_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ret = dquot_drop(inode);
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
+static int ext4_write_dquot(struct dquot *dquot)
+{
+ int ret, err;
+ handle_t *handle;
+ struct inode *inode;
+
+ inode = dquot_to_inode(dquot);
+ handle = ext4_journal_start(inode,
+ EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ret = dquot_commit(dquot);
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
+static int ext4_acquire_dquot(struct dquot *dquot)
+{
+ int ret, err;
+ handle_t *handle;
+
+ handle = ext4_journal_start(dquot_to_inode(dquot),
+ EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ret = dquot_acquire(dquot);
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
+static int ext4_release_dquot(struct dquot *dquot)
+{
+ int ret, err;
+ handle_t *handle;
+
+ handle = ext4_journal_start(dquot_to_inode(dquot),
+ EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ret = dquot_release(dquot);
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
+static int ext4_mark_dquot_dirty(struct dquot *dquot)
+{
+ /* Are we journalling quotas? */
+ if (EXT4_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] ||
+ EXT4_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) {
+ dquot_mark_dquot_dirty(dquot);
+ return ext4_write_dquot(dquot);
+ } else {
+ return dquot_mark_dquot_dirty(dquot);
+ }
+}
+
+static int ext4_write_info(struct super_block *sb, int type)
+{
+ int ret, err;
+ handle_t *handle;
+
+ /* Data block + inode block */
+ handle = ext4_journal_start(sb->s_root->d_inode, 2);
+ if (IS_ERR(handle))
+ return PTR_ERR(handle);
+ ret = dquot_commit_info(sb, type);
+ err = ext4_journal_stop(handle);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
+/*
+ * Turn on quotas during mount time - we need to find
+ * the quota file and such...
+ */
+static int ext4_quota_on_mount(struct super_block *sb, int type)
+{
+ return vfs_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type],
+ EXT4_SB(sb)->s_jquota_fmt, type);
+}
+
+/*
+ * Standard function to be called on quota_on
+ */
+static int ext4_quota_on(struct super_block *sb, int type, int format_id,
+ char *path)
+{
+ int err;
+ struct nameidata nd;
+
+ if (!test_opt(sb, QUOTA))
+ return -EINVAL;
+ /* Not journalling quota? */
+ if (!EXT4_SB(sb)->s_qf_names[USRQUOTA] &&
+ !EXT4_SB(sb)->s_qf_names[GRPQUOTA])
+ return vfs_quota_on(sb, type, format_id, path);
+ err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (err)
+ return err;
+ /* Quotafile not on the same filesystem? */
+ if (nd.mnt->mnt_sb != sb) {
+ path_release(&nd);
+ return -EXDEV;
+ }
+ /* Quotafile not of fs root? */
+ if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
+ printk(KERN_WARNING
+ "EXT4-fs: Quota file not on filesystem root. "
+ "Journalled quota will not work.\n");
+ path_release(&nd);
+ return vfs_quota_on(sb, type, format_id, path);
+}
+
+/* Read data from quotafile - avoid pagecache and such because we cannot afford
+ * acquiring the locks... As quota files are never truncated and quota code
+ * itself serializes the operations (and noone else should touch the files)
+ * we don't have to be afraid of races */
+static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
+ size_t len, loff_t off)
+{
+ struct inode *inode = sb_dqopt(sb)->files[type];
+ sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
+ int err = 0;
+ int offset = off & (sb->s_blocksize - 1);
+ int tocopy;
+ size_t toread;
+ struct buffer_head *bh;
+ loff_t i_size = i_size_read(inode);
+
+ if (off > i_size)
+ return 0;
+ if (off+len > i_size)
+ len = i_size-off;
+ toread = len;
+ while (toread > 0) {
+ tocopy = sb->s_blocksize - offset < toread ?
+ sb->s_blocksize - offset : toread;
+ bh = ext4_bread(NULL, inode, blk, 0, &err);
+ if (err)
+ return err;
+ if (!bh) /* A hole? */
+ memset(data, 0, tocopy);
+ else
+ memcpy(data, bh->b_data+offset, tocopy);
+ brelse(bh);
+ offset = 0;
+ toread -= tocopy;
+ data += tocopy;
+ blk++;
+ }
+ return len;
+}
+
+/* Write to quotafile (we know the transaction is already started and has
+ * enough credits) */
+static ssize_t ext4_quota_write(struct super_block *sb, int type,
+ const char *data, size_t len, loff_t off)
+{
+ struct inode *inode = sb_dqopt(sb)->files[type];
+ sector_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb);
+ int err = 0;
+ int offset = off & (sb->s_blocksize - 1);
+ int tocopy;
+ int journal_quota = EXT4_SB(sb)->s_qf_names[type] != NULL;
+ size_t towrite = len;
+ struct buffer_head *bh;
+ handle_t *handle = journal_current_handle();
+
+ mutex_lock_nested(&inode->i_mutex, I_MUTEX_QUOTA);
+ while (towrite > 0) {
+ tocopy = sb->s_blocksize - offset < towrite ?
+ sb->s_blocksize - offset : towrite;
+ bh = ext4_bread(handle, inode, blk, 1, &err);
+ if (!bh)
+ goto out;
+ if (journal_quota) {
+ err = ext4_journal_get_write_access(handle, bh);
+ if (err) {
+ brelse(bh);
+ goto out;
+ }
+ }
+ lock_buffer(bh);
+ memcpy(bh->b_data+offset, data, tocopy);
+ flush_dcache_page(bh->b_page);
+ unlock_buffer(bh);
+ if (journal_quota)
+ err = ext4_journal_dirty_metadata(handle, bh);
+ else {
+ /* Always do at least ordered writes for quotas */
+ err = ext4_journal_dirty_data(handle, bh);
+ mark_buffer_dirty(bh);
+ }
+ brelse(bh);
+ if (err)
+ goto out;
+ offset = 0;
+ towrite -= tocopy;
+ data += tocopy;
+ blk++;
+ }
+out:
+ if (len == towrite)
+ return err;
+ if (inode->i_size < off+len-towrite) {
+ i_size_write(inode, off+len-towrite);
+ EXT4_I(inode)->i_disksize = inode->i_size;
+ }
+ inode->i_version++;
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ ext4_mark_inode_dirty(handle, inode);
+ mutex_unlock(&inode->i_mutex);
+ return len - towrite;
+}
+
+#endif
+
+static int ext4_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ return get_sb_bdev(fs_type, flags, dev_name, data, ext4_fill_super, mnt);
+}
+
+static struct file_system_type ext4dev_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "ext4dev",
+ .get_sb = ext4_get_sb,
+ .kill_sb = kill_block_super,
+ .fs_flags = FS_REQUIRES_DEV,
+};
+
+static int __init init_ext4_fs(void)
+{
+ int err = init_ext4_xattr();
+ if (err)
+ return err;
+ err = init_inodecache();
+ if (err)
+ goto out1;
+ err = register_filesystem(&ext4dev_fs_type);
+ if (err)
+ goto out;
+ return 0;
+out:
+ destroy_inodecache();
+out1:
+ exit_ext4_xattr();
+ return err;
+}
+
+static void __exit exit_ext4_fs(void)
+{
+ unregister_filesystem(&ext4dev_fs_type);
+ destroy_inodecache();
+ exit_ext4_xattr();
+}
+
+MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");
+MODULE_DESCRIPTION("Fourth Extended Filesystem with extents");
+MODULE_LICENSE("GPL");
+module_init(init_ext4_fs)
+module_exit(exit_ext4_fs)
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
new file mode 100644
index 000000000000..fcf527286d75
--- /dev/null
+++ b/fs/ext4/symlink.c
@@ -0,0 +1,54 @@
+/*
+ * linux/fs/ext4/symlink.c
+ *
+ * Only fast symlinks left here - the rest is done by generic code. AV, 1999
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/fs/minix/symlink.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * ext4 symlink handling code
+ */
+
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/namei.h>
+#include "xattr.h"
+
+static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ struct ext4_inode_info *ei = EXT4_I(dentry->d_inode);
+ nd_set_link(nd, (char*)ei->i_data);
+ return NULL;
+}
+
+struct inode_operations ext4_symlink_inode_operations = {
+ .readlink = generic_readlink,
+ .follow_link = page_follow_link_light,
+ .put_link = page_put_link,
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ext4_listxattr,
+ .removexattr = generic_removexattr,
+#endif
+};
+
+struct inode_operations ext4_fast_symlink_inode_operations = {
+ .readlink = generic_readlink,
+ .follow_link = ext4_follow_link,
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = ext4_listxattr,
+ .removexattr = generic_removexattr,
+#endif
+};
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
new file mode 100644
index 000000000000..63233cd946a7
--- /dev/null
+++ b/fs/ext4/xattr.c
@@ -0,0 +1,1317 @@
+/*
+ * linux/fs/ext4/xattr.c
+ *
+ * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
+ *
+ * Fix by Harrison Xing <harrison@mountainviewdata.com>.
+ * Ext4 code with a lot of help from Eric Jarman <ejarman@acm.org>.
+ * Extended attributes for symlinks and special files added per
+ * suggestion of Luka Renko <luka.renko@hermes.si>.
+ * xattr consolidation Copyright (c) 2004 James Morris <jmorris@redhat.com>,
+ * Red Hat Inc.
+ * ea-in-inode support by Alex Tomas <alex@clusterfs.com> aka bzzz
+ * and Andreas Gruenbacher <agruen@suse.de>.
+ */
+
+/*
+ * Extended attributes are stored directly in inodes (on file systems with
+ * inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl
+ * field contains the block number if an inode uses an additional block. All
+ * attributes must fit in the inode and one additional block. Blocks that
+ * contain the identical set of attributes may be shared among several inodes.
+ * Identical blocks are detected by keeping a cache of blocks that have
+ * recently been accessed.
+ *
+ * The attributes in inodes and on blocks have a different header; the entries
+ * are stored in the same format:
+ *
+ * +------------------+
+ * | header |
+ * | entry 1 | |
+ * | entry 2 | | growing downwards
+ * | entry 3 | v
+ * | four null bytes |
+ * | . . . |
+ * | value 1 | ^
+ * | value 3 | | growing upwards
+ * | value 2 | |
+ * +------------------+
+ *
+ * The header is followed by multiple entry descriptors. In disk blocks, the
+ * entry descriptors are kept sorted. In inodes, they are unsorted. The
+ * attribute values are aligned to the end of the block in no specific order.
+ *
+ * Locking strategy
+ * ----------------
+ * EXT4_I(inode)->i_file_acl is protected by EXT4_I(inode)->xattr_sem.
+ * EA blocks are only changed if they are exclusive to an inode, so
+ * holding xattr_sem also means that nothing but the EA block's reference
+ * count can change. Multiple writers to the same block are synchronized
+ * by the buffer lock.
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/mbcache.h>
+#include <linux/quotaops.h>
+#include <linux/rwsem.h>
+#include "xattr.h"
+#include "acl.h"
+
+#define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data))
+#define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr))
+#define BFIRST(bh) ENTRY(BHDR(bh)+1)
+#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0)
+
+#define IHDR(inode, raw_inode) \
+ ((struct ext4_xattr_ibody_header *) \
+ ((void *)raw_inode + \
+ EXT4_GOOD_OLD_INODE_SIZE + \
+ EXT4_I(inode)->i_extra_isize))
+#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1))
+
+#ifdef EXT4_XATTR_DEBUG
+# define ea_idebug(inode, f...) do { \
+ printk(KERN_DEBUG "inode %s:%lu: ", \
+ inode->i_sb->s_id, inode->i_ino); \
+ printk(f); \
+ printk("\n"); \
+ } while (0)
+# define ea_bdebug(bh, f...) do { \
+ char b[BDEVNAME_SIZE]; \
+ printk(KERN_DEBUG "block %s:%lu: ", \
+ bdevname(bh->b_bdev, b), \
+ (unsigned long) bh->b_blocknr); \
+ printk(f); \
+ printk("\n"); \
+ } while (0)
+#else
+# define ea_idebug(f...)
+# define ea_bdebug(f...)
+#endif
+
+static void ext4_xattr_cache_insert(struct buffer_head *);
+static struct buffer_head *ext4_xattr_cache_find(struct inode *,
+ struct ext4_xattr_header *,
+ struct mb_cache_entry **);
+static void ext4_xattr_rehash(struct ext4_xattr_header *,
+ struct ext4_xattr_entry *);
+
+static struct mb_cache *ext4_xattr_cache;
+
+static struct xattr_handler *ext4_xattr_handler_map[] = {
+ [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler,
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+ [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &ext4_xattr_acl_access_handler,
+ [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler,
+#endif
+ [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler,
+#ifdef CONFIG_EXT4DEV_FS_SECURITY
+ [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler,
+#endif
+};
+
+struct xattr_handler *ext4_xattr_handlers[] = {
+ &ext4_xattr_user_handler,
+ &ext4_xattr_trusted_handler,
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+ &ext4_xattr_acl_access_handler,
+ &ext4_xattr_acl_default_handler,
+#endif
+#ifdef CONFIG_EXT4DEV_FS_SECURITY
+ &ext4_xattr_security_handler,
+#endif
+ NULL
+};
+
+static inline struct xattr_handler *
+ext4_xattr_handler(int name_index)
+{
+ struct xattr_handler *handler = NULL;
+
+ if (name_index > 0 && name_index < ARRAY_SIZE(ext4_xattr_handler_map))
+ handler = ext4_xattr_handler_map[name_index];
+ return handler;
+}
+
+/*
+ * Inode operation listxattr()
+ *
+ * dentry->d_inode->i_mutex: don't care
+ */
+ssize_t
+ext4_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+ return ext4_xattr_list(dentry->d_inode, buffer, size);
+}
+
+static int
+ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end)
+{
+ while (!IS_LAST_ENTRY(entry)) {
+ struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
+ if ((void *)next >= end)
+ return -EIO;
+ entry = next;
+ }
+ return 0;
+}
+
+static inline int
+ext4_xattr_check_block(struct buffer_head *bh)
+{
+ int error;
+
+ if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
+ BHDR(bh)->h_blocks != cpu_to_le32(1))
+ return -EIO;
+ error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size);
+ return error;
+}
+
+static inline int
+ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size)
+{
+ size_t value_size = le32_to_cpu(entry->e_value_size);
+
+ if (entry->e_value_block != 0 || value_size > size ||
+ le16_to_cpu(entry->e_value_offs) + value_size > size)
+ return -EIO;
+ return 0;
+}
+
+static int
+ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index,
+ const char *name, size_t size, int sorted)
+{
+ struct ext4_xattr_entry *entry;
+ size_t name_len;
+ int cmp = 1;
+
+ if (name == NULL)
+ return -EINVAL;
+ name_len = strlen(name);
+ entry = *pentry;
+ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+ cmp = name_index - entry->e_name_index;
+ if (!cmp)
+ cmp = name_len - entry->e_name_len;
+ if (!cmp)
+ cmp = memcmp(name, entry->e_name, name_len);
+ if (cmp <= 0 && (sorted || cmp == 0))
+ break;
+ }
+ *pentry = entry;
+ if (!cmp && ext4_xattr_check_entry(entry, size))
+ return -EIO;
+ return cmp ? -ENODATA : 0;
+}
+
+static int
+ext4_xattr_block_get(struct inode *inode, int name_index, const char *name,
+ void *buffer, size_t buffer_size)
+{
+ struct buffer_head *bh = NULL;
+ struct ext4_xattr_entry *entry;
+ size_t size;
+ int error;
+
+ ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld",
+ name_index, name, buffer, (long)buffer_size);
+
+ error = -ENODATA;
+ if (!EXT4_I(inode)->i_file_acl)
+ goto cleanup;
+ ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
+ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
+ if (!bh)
+ goto cleanup;
+ ea_bdebug(bh, "b_count=%d, refcount=%d",
+ atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
+ if (ext4_xattr_check_block(bh)) {
+bad_block: ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: bad block %llu", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+ }
+ ext4_xattr_cache_insert(bh);
+ entry = BFIRST(bh);
+ error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1);
+ if (error == -EIO)
+ goto bad_block;
+ if (error)
+ goto cleanup;
+ size = le32_to_cpu(entry->e_value_size);
+ if (buffer) {
+ error = -ERANGE;
+ if (size > buffer_size)
+ goto cleanup;
+ memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs),
+ size);
+ }
+ error = size;
+
+cleanup:
+ brelse(bh);
+ return error;
+}
+
+static int
+ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name,
+ void *buffer, size_t buffer_size)
+{
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_xattr_entry *entry;
+ struct ext4_inode *raw_inode;
+ struct ext4_iloc iloc;
+ size_t size;
+ void *end;
+ int error;
+
+ if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR))
+ return -ENODATA;
+ error = ext4_get_inode_loc(inode, &iloc);
+ if (error)
+ return error;
+ raw_inode = ext4_raw_inode(&iloc);
+ header = IHDR(inode, raw_inode);
+ entry = IFIRST(header);
+ end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
+ error = ext4_xattr_check_names(entry, end);
+ if (error)
+ goto cleanup;
+ error = ext4_xattr_find_entry(&entry, name_index, name,
+ end - (void *)entry, 0);
+ if (error)
+ goto cleanup;
+ size = le32_to_cpu(entry->e_value_size);
+ if (buffer) {
+ error = -ERANGE;
+ if (size > buffer_size)
+ goto cleanup;
+ memcpy(buffer, (void *)IFIRST(header) +
+ le16_to_cpu(entry->e_value_offs), size);
+ }
+ error = size;
+
+cleanup:
+ brelse(iloc.bh);
+ return error;
+}
+
+/*
+ * ext4_xattr_get()
+ *
+ * Copy an extended attribute into the buffer
+ * provided, or compute the buffer size required.
+ * Buffer is NULL to compute the size of the buffer required.
+ *
+ * Returns a negative error number on failure, or the number of bytes
+ * used / required on success.
+ */
+int
+ext4_xattr_get(struct inode *inode, int name_index, const char *name,
+ void *buffer, size_t buffer_size)
+{
+ int error;
+
+ down_read(&EXT4_I(inode)->xattr_sem);
+ error = ext4_xattr_ibody_get(inode, name_index, name, buffer,
+ buffer_size);
+ if (error == -ENODATA)
+ error = ext4_xattr_block_get(inode, name_index, name, buffer,
+ buffer_size);
+ up_read(&EXT4_I(inode)->xattr_sem);
+ return error;
+}
+
+static int
+ext4_xattr_list_entries(struct inode *inode, struct ext4_xattr_entry *entry,
+ char *buffer, size_t buffer_size)
+{
+ size_t rest = buffer_size;
+
+ for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+ struct xattr_handler *handler =
+ ext4_xattr_handler(entry->e_name_index);
+
+ if (handler) {
+ size_t size = handler->list(inode, buffer, rest,
+ entry->e_name,
+ entry->e_name_len);
+ if (buffer) {
+ if (size > rest)
+ return -ERANGE;
+ buffer += size;
+ }
+ rest -= size;
+ }
+ }
+ return buffer_size - rest;
+}
+
+static int
+ext4_xattr_block_list(struct inode *inode, char *buffer, size_t buffer_size)
+{
+ struct buffer_head *bh = NULL;
+ int error;
+
+ ea_idebug(inode, "buffer=%p, buffer_size=%ld",
+ buffer, (long)buffer_size);
+
+ error = 0;
+ if (!EXT4_I(inode)->i_file_acl)
+ goto cleanup;
+ ea_idebug(inode, "reading block %u", EXT4_I(inode)->i_file_acl);
+ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ if (!bh)
+ goto cleanup;
+ ea_bdebug(bh, "b_count=%d, refcount=%d",
+ atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount));
+ if (ext4_xattr_check_block(bh)) {
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: bad block %llu", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+ }
+ ext4_xattr_cache_insert(bh);
+ error = ext4_xattr_list_entries(inode, BFIRST(bh), buffer, buffer_size);
+
+cleanup:
+ brelse(bh);
+
+ return error;
+}
+
+static int
+ext4_xattr_ibody_list(struct inode *inode, char *buffer, size_t buffer_size)
+{
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_inode *raw_inode;
+ struct ext4_iloc iloc;
+ void *end;
+ int error;
+
+ if (!(EXT4_I(inode)->i_state & EXT4_STATE_XATTR))
+ return 0;
+ error = ext4_get_inode_loc(inode, &iloc);
+ if (error)
+ return error;
+ raw_inode = ext4_raw_inode(&iloc);
+ header = IHDR(inode, raw_inode);
+ end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
+ error = ext4_xattr_check_names(IFIRST(header), end);
+ if (error)
+ goto cleanup;
+ error = ext4_xattr_list_entries(inode, IFIRST(header),
+ buffer, buffer_size);
+
+cleanup:
+ brelse(iloc.bh);
+ return error;
+}
+
+/*
+ * ext4_xattr_list()
+ *
+ * Copy a list of attribute names into the buffer
+ * provided, or compute the buffer size required.
+ * Buffer is NULL to compute the size of the buffer required.
+ *
+ * Returns a negative error number on failure, or the number of bytes
+ * used / required on success.
+ */
+int
+ext4_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
+{
+ int i_error, b_error;
+
+ down_read(&EXT4_I(inode)->xattr_sem);
+ i_error = ext4_xattr_ibody_list(inode, buffer, buffer_size);
+ if (i_error < 0) {
+ b_error = 0;
+ } else {
+ if (buffer) {
+ buffer += i_error;
+ buffer_size -= i_error;
+ }
+ b_error = ext4_xattr_block_list(inode, buffer, buffer_size);
+ if (b_error < 0)
+ i_error = 0;
+ }
+ up_read(&EXT4_I(inode)->xattr_sem);
+ return i_error + b_error;
+}
+
+/*
+ * If the EXT4_FEATURE_COMPAT_EXT_ATTR feature of this file system is
+ * not set, set it.
+ */
+static void ext4_xattr_update_super_block(handle_t *handle,
+ struct super_block *sb)
+{
+ if (EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_EXT_ATTR))
+ return;
+
+ lock_super(sb);
+ if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) {
+ EXT4_SB(sb)->s_es->s_feature_compat |=
+ cpu_to_le32(EXT4_FEATURE_COMPAT_EXT_ATTR);
+ sb->s_dirt = 1;
+ ext4_journal_dirty_metadata(handle, EXT4_SB(sb)->s_sbh);
+ }
+ unlock_super(sb);
+}
+
+/*
+ * Release the xattr block BH: If the reference count is > 1, decrement
+ * it; otherwise free the block.
+ */
+static void
+ext4_xattr_release_block(handle_t *handle, struct inode *inode,
+ struct buffer_head *bh)
+{
+ struct mb_cache_entry *ce = NULL;
+
+ ce = mb_cache_entry_get(ext4_xattr_cache, bh->b_bdev, bh->b_blocknr);
+ if (BHDR(bh)->h_refcount == cpu_to_le32(1)) {
+ ea_bdebug(bh, "refcount now=0; freeing");
+ if (ce)
+ mb_cache_entry_free(ce);
+ ext4_free_blocks(handle, inode, bh->b_blocknr, 1);
+ get_bh(bh);
+ ext4_forget(handle, 1, inode, bh, bh->b_blocknr);
+ } else {
+ if (ext4_journal_get_write_access(handle, bh) == 0) {
+ lock_buffer(bh);
+ BHDR(bh)->h_refcount = cpu_to_le32(
+ le32_to_cpu(BHDR(bh)->h_refcount) - 1);
+ ext4_journal_dirty_metadata(handle, bh);
+ if (IS_SYNC(inode))
+ handle->h_sync = 1;
+ DQUOT_FREE_BLOCK(inode, 1);
+ unlock_buffer(bh);
+ ea_bdebug(bh, "refcount now=%d; releasing",
+ le32_to_cpu(BHDR(bh)->h_refcount));
+ }
+ if (ce)
+ mb_cache_entry_release(ce);
+ }
+}
+
+struct ext4_xattr_info {
+ int name_index;
+ const char *name;
+ const void *value;
+ size_t value_len;
+};
+
+struct ext4_xattr_search {
+ struct ext4_xattr_entry *first;
+ void *base;
+ void *end;
+ struct ext4_xattr_entry *here;
+ int not_found;
+};
+
+static int
+ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s)
+{
+ struct ext4_xattr_entry *last;
+ size_t free, min_offs = s->end - s->base, name_len = strlen(i->name);
+
+ /* Compute min_offs and last. */
+ last = s->first;
+ for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) {
+ if (!last->e_value_block && last->e_value_size) {
+ size_t offs = le16_to_cpu(last->e_value_offs);
+ if (offs < min_offs)
+ min_offs = offs;
+ }
+ }
+ free = min_offs - ((void *)last - s->base) - sizeof(__u32);
+ if (!s->not_found) {
+ if (!s->here->e_value_block && s->here->e_value_size) {
+ size_t size = le32_to_cpu(s->here->e_value_size);
+ free += EXT4_XATTR_SIZE(size);
+ }
+ free += EXT4_XATTR_LEN(name_len);
+ }
+ if (i->value) {
+ if (free < EXT4_XATTR_SIZE(i->value_len) ||
+ free < EXT4_XATTR_LEN(name_len) +
+ EXT4_XATTR_SIZE(i->value_len))
+ return -ENOSPC;
+ }
+
+ if (i->value && s->not_found) {
+ /* Insert the new name. */
+ size_t size = EXT4_XATTR_LEN(name_len);
+ size_t rest = (void *)last - (void *)s->here + sizeof(__u32);
+ memmove((void *)s->here + size, s->here, rest);
+ memset(s->here, 0, size);
+ s->here->e_name_index = i->name_index;
+ s->here->e_name_len = name_len;
+ memcpy(s->here->e_name, i->name, name_len);
+ } else {
+ if (!s->here->e_value_block && s->here->e_value_size) {
+ void *first_val = s->base + min_offs;
+ size_t offs = le16_to_cpu(s->here->e_value_offs);
+ void *val = s->base + offs;
+ size_t size = EXT4_XATTR_SIZE(
+ le32_to_cpu(s->here->e_value_size));
+
+ if (i->value && size == EXT4_XATTR_SIZE(i->value_len)) {
+ /* The old and the new value have the same
+ size. Just replace. */
+ s->here->e_value_size =
+ cpu_to_le32(i->value_len);
+ memset(val + size - EXT4_XATTR_PAD, 0,
+ EXT4_XATTR_PAD); /* Clear pad bytes. */
+ memcpy(val, i->value, i->value_len);
+ return 0;
+ }
+
+ /* Remove the old value. */
+ memmove(first_val + size, first_val, val - first_val);
+ memset(first_val, 0, size);
+ s->here->e_value_size = 0;
+ s->here->e_value_offs = 0;
+ min_offs += size;
+
+ /* Adjust all value offsets. */
+ last = s->first;
+ while (!IS_LAST_ENTRY(last)) {
+ size_t o = le16_to_cpu(last->e_value_offs);
+ if (!last->e_value_block &&
+ last->e_value_size && o < offs)
+ last->e_value_offs =
+ cpu_to_le16(o + size);
+ last = EXT4_XATTR_NEXT(last);
+ }
+ }
+ if (!i->value) {
+ /* Remove the old name. */
+ size_t size = EXT4_XATTR_LEN(name_len);
+ last = ENTRY((void *)last - size);
+ memmove(s->here, (void *)s->here + size,
+ (void *)last - (void *)s->here + sizeof(__u32));
+ memset(last, 0, size);
+ }
+ }
+
+ if (i->value) {
+ /* Insert the new value. */
+ s->here->e_value_size = cpu_to_le32(i->value_len);
+ if (i->value_len) {
+ size_t size = EXT4_XATTR_SIZE(i->value_len);
+ void *val = s->base + min_offs - size;
+ s->here->e_value_offs = cpu_to_le16(min_offs - size);
+ memset(val + size - EXT4_XATTR_PAD, 0,
+ EXT4_XATTR_PAD); /* Clear the pad bytes. */
+ memcpy(val, i->value, i->value_len);
+ }
+ }
+ return 0;
+}
+
+struct ext4_xattr_block_find {
+ struct ext4_xattr_search s;
+ struct buffer_head *bh;
+};
+
+static int
+ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i,
+ struct ext4_xattr_block_find *bs)
+{
+ struct super_block *sb = inode->i_sb;
+ int error;
+
+ ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
+ i->name_index, i->name, i->value, (long)i->value_len);
+
+ if (EXT4_I(inode)->i_file_acl) {
+ /* The inode already has an extended attribute block. */
+ bs->bh = sb_bread(sb, EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ if (!bs->bh)
+ goto cleanup;
+ ea_bdebug(bs->bh, "b_count=%d, refcount=%d",
+ atomic_read(&(bs->bh->b_count)),
+ le32_to_cpu(BHDR(bs->bh)->h_refcount));
+ if (ext4_xattr_check_block(bs->bh)) {
+ ext4_error(sb, __FUNCTION__,
+ "inode %lu: bad block %llu", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ error = -EIO;
+ goto cleanup;
+ }
+ /* Find the named attribute. */
+ bs->s.base = BHDR(bs->bh);
+ bs->s.first = BFIRST(bs->bh);
+ bs->s.end = bs->bh->b_data + bs->bh->b_size;
+ bs->s.here = bs->s.first;
+ error = ext4_xattr_find_entry(&bs->s.here, i->name_index,
+ i->name, bs->bh->b_size, 1);
+ if (error && error != -ENODATA)
+ goto cleanup;
+ bs->s.not_found = error;
+ }
+ error = 0;
+
+cleanup:
+ return error;
+}
+
+static int
+ext4_xattr_block_set(handle_t *handle, struct inode *inode,
+ struct ext4_xattr_info *i,
+ struct ext4_xattr_block_find *bs)
+{
+ struct super_block *sb = inode->i_sb;
+ struct buffer_head *new_bh = NULL;
+ struct ext4_xattr_search *s = &bs->s;
+ struct mb_cache_entry *ce = NULL;
+ int error;
+
+#define header(x) ((struct ext4_xattr_header *)(x))
+
+ if (i->value && i->value_len > sb->s_blocksize)
+ return -ENOSPC;
+ if (s->base) {
+ ce = mb_cache_entry_get(ext4_xattr_cache, bs->bh->b_bdev,
+ bs->bh->b_blocknr);
+ if (header(s->base)->h_refcount == cpu_to_le32(1)) {
+ if (ce) {
+ mb_cache_entry_free(ce);
+ ce = NULL;
+ }
+ ea_bdebug(bs->bh, "modifying in-place");
+ error = ext4_journal_get_write_access(handle, bs->bh);
+ if (error)
+ goto cleanup;
+ lock_buffer(bs->bh);
+ error = ext4_xattr_set_entry(i, s);
+ if (!error) {
+ if (!IS_LAST_ENTRY(s->first))
+ ext4_xattr_rehash(header(s->base),
+ s->here);
+ ext4_xattr_cache_insert(bs->bh);
+ }
+ unlock_buffer(bs->bh);
+ if (error == -EIO)
+ goto bad_block;
+ if (!error)
+ error = ext4_journal_dirty_metadata(handle,
+ bs->bh);
+ if (error)
+ goto cleanup;
+ goto inserted;
+ } else {
+ int offset = (char *)s->here - bs->bh->b_data;
+
+ if (ce) {
+ mb_cache_entry_release(ce);
+ ce = NULL;
+ }
+ ea_bdebug(bs->bh, "cloning");
+ s->base = kmalloc(bs->bh->b_size, GFP_KERNEL);
+ error = -ENOMEM;
+ if (s->base == NULL)
+ goto cleanup;
+ memcpy(s->base, BHDR(bs->bh), bs->bh->b_size);
+ s->first = ENTRY(header(s->base)+1);
+ header(s->base)->h_refcount = cpu_to_le32(1);
+ s->here = ENTRY(s->base + offset);
+ s->end = s->base + bs->bh->b_size;
+ }
+ } else {
+ /* Allocate a buffer where we construct the new block. */
+ s->base = kmalloc(sb->s_blocksize, GFP_KERNEL);
+ /* assert(header == s->base) */
+ error = -ENOMEM;
+ if (s->base == NULL)
+ goto cleanup;
+ memset(s->base, 0, sb->s_blocksize);
+ header(s->base)->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
+ header(s->base)->h_blocks = cpu_to_le32(1);
+ header(s->base)->h_refcount = cpu_to_le32(1);
+ s->first = ENTRY(header(s->base)+1);
+ s->here = ENTRY(header(s->base)+1);
+ s->end = s->base + sb->s_blocksize;
+ }
+
+ error = ext4_xattr_set_entry(i, s);
+ if (error == -EIO)
+ goto bad_block;
+ if (error)
+ goto cleanup;
+ if (!IS_LAST_ENTRY(s->first))
+ ext4_xattr_rehash(header(s->base), s->here);
+
+inserted:
+ if (!IS_LAST_ENTRY(s->first)) {
+ new_bh = ext4_xattr_cache_find(inode, header(s->base), &ce);
+ if (new_bh) {
+ /* We found an identical block in the cache. */
+ if (new_bh == bs->bh)
+ ea_bdebug(new_bh, "keeping");
+ else {
+ /* The old block is released after updating
+ the inode. */
+ error = -EDQUOT;
+ if (DQUOT_ALLOC_BLOCK(inode, 1))
+ goto cleanup;
+ error = ext4_journal_get_write_access(handle,
+ new_bh);
+ if (error)
+ goto cleanup_dquot;
+ lock_buffer(new_bh);
+ BHDR(new_bh)->h_refcount = cpu_to_le32(1 +
+ le32_to_cpu(BHDR(new_bh)->h_refcount));
+ ea_bdebug(new_bh, "reusing; refcount now=%d",
+ le32_to_cpu(BHDR(new_bh)->h_refcount));
+ unlock_buffer(new_bh);
+ error = ext4_journal_dirty_metadata(handle,
+ new_bh);
+ if (error)
+ goto cleanup_dquot;
+ }
+ mb_cache_entry_release(ce);
+ ce = NULL;
+ } else if (bs->bh && s->base == bs->bh->b_data) {
+ /* We were modifying this block in-place. */
+ ea_bdebug(bs->bh, "keeping this block");
+ new_bh = bs->bh;
+ get_bh(new_bh);
+ } else {
+ /* We need to allocate a new block */
+ ext4_fsblk_t goal = le32_to_cpu(
+ EXT4_SB(sb)->s_es->s_first_data_block) +
+ (ext4_fsblk_t)EXT4_I(inode)->i_block_group *
+ EXT4_BLOCKS_PER_GROUP(sb);
+ ext4_fsblk_t block = ext4_new_block(handle, inode,
+ goal, &error);
+ if (error)
+ goto cleanup;
+ ea_idebug(inode, "creating block %d", block);
+
+ new_bh = sb_getblk(sb, block);
+ if (!new_bh) {
+getblk_failed:
+ ext4_free_blocks(handle, inode, block, 1);
+ error = -EIO;
+ goto cleanup;
+ }
+ lock_buffer(new_bh);
+ error = ext4_journal_get_create_access(handle, new_bh);
+ if (error) {
+ unlock_buffer(new_bh);
+ goto getblk_failed;
+ }
+ memcpy(new_bh->b_data, s->base, new_bh->b_size);
+ set_buffer_uptodate(new_bh);
+ unlock_buffer(new_bh);
+ ext4_xattr_cache_insert(new_bh);
+ error = ext4_journal_dirty_metadata(handle, new_bh);
+ if (error)
+ goto cleanup;
+ }
+ }
+
+ /* Update the inode. */
+ EXT4_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0;
+
+ /* Drop the previous xattr block. */
+ if (bs->bh && bs->bh != new_bh)
+ ext4_xattr_release_block(handle, inode, bs->bh);
+ error = 0;
+
+cleanup:
+ if (ce)
+ mb_cache_entry_release(ce);
+ brelse(new_bh);
+ if (!(bs->bh && s->base == bs->bh->b_data))
+ kfree(s->base);
+
+ return error;
+
+cleanup_dquot:
+ DQUOT_FREE_BLOCK(inode, 1);
+ goto cleanup;
+
+bad_block:
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: bad block %llu", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ goto cleanup;
+
+#undef header
+}
+
+struct ext4_xattr_ibody_find {
+ struct ext4_xattr_search s;
+ struct ext4_iloc iloc;
+};
+
+static int
+ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i,
+ struct ext4_xattr_ibody_find *is)
+{
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_inode *raw_inode;
+ int error;
+
+ if (EXT4_I(inode)->i_extra_isize == 0)
+ return 0;
+ raw_inode = ext4_raw_inode(&is->iloc);
+ header = IHDR(inode, raw_inode);
+ is->s.base = is->s.first = IFIRST(header);
+ is->s.here = is->s.first;
+ is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size;
+ if (EXT4_I(inode)->i_state & EXT4_STATE_XATTR) {
+ error = ext4_xattr_check_names(IFIRST(header), is->s.end);
+ if (error)
+ return error;
+ /* Find the named attribute. */
+ error = ext4_xattr_find_entry(&is->s.here, i->name_index,
+ i->name, is->s.end -
+ (void *)is->s.base, 0);
+ if (error && error != -ENODATA)
+ return error;
+ is->s.not_found = error;
+ }
+ return 0;
+}
+
+static int
+ext4_xattr_ibody_set(handle_t *handle, struct inode *inode,
+ struct ext4_xattr_info *i,
+ struct ext4_xattr_ibody_find *is)
+{
+ struct ext4_xattr_ibody_header *header;
+ struct ext4_xattr_search *s = &is->s;
+ int error;
+
+ if (EXT4_I(inode)->i_extra_isize == 0)
+ return -ENOSPC;
+ error = ext4_xattr_set_entry(i, s);
+ if (error)
+ return error;
+ header = IHDR(inode, ext4_raw_inode(&is->iloc));
+ if (!IS_LAST_ENTRY(s->first)) {
+ header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
+ EXT4_I(inode)->i_state |= EXT4_STATE_XATTR;
+ } else {
+ header->h_magic = cpu_to_le32(0);
+ EXT4_I(inode)->i_state &= ~EXT4_STATE_XATTR;
+ }
+ return 0;
+}
+
+/*
+ * ext4_xattr_set_handle()
+ *
+ * Create, replace or remove an extended attribute for this inode. Buffer
+ * is NULL to remove an existing extended attribute, and non-NULL to
+ * either replace an existing extended attribute, or create a new extended
+ * attribute. The flags XATTR_REPLACE and XATTR_CREATE
+ * specify that an extended attribute must exist and must not exist
+ * previous to the call, respectively.
+ *
+ * Returns 0, or a negative error number on failure.
+ */
+int
+ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
+ const char *name, const void *value, size_t value_len,
+ int flags)
+{
+ struct ext4_xattr_info i = {
+ .name_index = name_index,
+ .name = name,
+ .value = value,
+ .value_len = value_len,
+
+ };
+ struct ext4_xattr_ibody_find is = {
+ .s = { .not_found = -ENODATA, },
+ };
+ struct ext4_xattr_block_find bs = {
+ .s = { .not_found = -ENODATA, },
+ };
+ int error;
+
+ if (!name)
+ return -EINVAL;
+ if (strlen(name) > 255)
+ return -ERANGE;
+ down_write(&EXT4_I(inode)->xattr_sem);
+ error = ext4_get_inode_loc(inode, &is.iloc);
+ if (error)
+ goto cleanup;
+
+ if (EXT4_I(inode)->i_state & EXT4_STATE_NEW) {
+ struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc);
+ memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size);
+ EXT4_I(inode)->i_state &= ~EXT4_STATE_NEW;
+ }
+
+ error = ext4_xattr_ibody_find(inode, &i, &is);
+ if (error)
+ goto cleanup;
+ if (is.s.not_found)
+ error = ext4_xattr_block_find(inode, &i, &bs);
+ if (error)
+ goto cleanup;
+ if (is.s.not_found && bs.s.not_found) {
+ error = -ENODATA;
+ if (flags & XATTR_REPLACE)
+ goto cleanup;
+ error = 0;
+ if (!value)
+ goto cleanup;
+ } else {
+ error = -EEXIST;
+ if (flags & XATTR_CREATE)
+ goto cleanup;
+ }
+ error = ext4_journal_get_write_access(handle, is.iloc.bh);
+ if (error)
+ goto cleanup;
+ if (!value) {
+ if (!is.s.not_found)
+ error = ext4_xattr_ibody_set(handle, inode, &i, &is);
+ else if (!bs.s.not_found)
+ error = ext4_xattr_block_set(handle, inode, &i, &bs);
+ } else {
+ error = ext4_xattr_ibody_set(handle, inode, &i, &is);
+ if (!error && !bs.s.not_found) {
+ i.value = NULL;
+ error = ext4_xattr_block_set(handle, inode, &i, &bs);
+ } else if (error == -ENOSPC) {
+ error = ext4_xattr_block_set(handle, inode, &i, &bs);
+ if (error)
+ goto cleanup;
+ if (!is.s.not_found) {
+ i.value = NULL;
+ error = ext4_xattr_ibody_set(handle, inode, &i,
+ &is);
+ }
+ }
+ }
+ if (!error) {
+ ext4_xattr_update_super_block(handle, inode->i_sb);
+ inode->i_ctime = CURRENT_TIME_SEC;
+ error = ext4_mark_iloc_dirty(handle, inode, &is.iloc);
+ /*
+ * The bh is consumed by ext4_mark_iloc_dirty, even with
+ * error != 0.
+ */
+ is.iloc.bh = NULL;
+ if (IS_SYNC(inode))
+ handle->h_sync = 1;
+ }
+
+cleanup:
+ brelse(is.iloc.bh);
+ brelse(bs.bh);
+ up_write(&EXT4_I(inode)->xattr_sem);
+ return error;
+}
+
+/*
+ * ext4_xattr_set()
+ *
+ * Like ext4_xattr_set_handle, but start from an inode. This extended
+ * attribute modification is a filesystem transaction by itself.
+ *
+ * Returns 0, or a negative error number on failure.
+ */
+int
+ext4_xattr_set(struct inode *inode, int name_index, const char *name,
+ const void *value, size_t value_len, int flags)
+{
+ handle_t *handle;
+ int error, retries = 0;
+
+retry:
+ handle = ext4_journal_start(inode, EXT4_DATA_TRANS_BLOCKS(inode->i_sb));
+ if (IS_ERR(handle)) {
+ error = PTR_ERR(handle);
+ } else {
+ int error2;
+
+ error = ext4_xattr_set_handle(handle, inode, name_index, name,
+ value, value_len, flags);
+ error2 = ext4_journal_stop(handle);
+ if (error == -ENOSPC &&
+ ext4_should_retry_alloc(inode->i_sb, &retries))
+ goto retry;
+ if (error == 0)
+ error = error2;
+ }
+
+ return error;
+}
+
+/*
+ * ext4_xattr_delete_inode()
+ *
+ * Free extended attribute resources associated with this inode. This
+ * is called immediately before an inode is freed. We have exclusive
+ * access to the inode.
+ */
+void
+ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
+{
+ struct buffer_head *bh = NULL;
+
+ if (!EXT4_I(inode)->i_file_acl)
+ goto cleanup;
+ bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl);
+ if (!bh) {
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: block %llu read error", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ goto cleanup;
+ }
+ if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) ||
+ BHDR(bh)->h_blocks != cpu_to_le32(1)) {
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: bad block %llu", inode->i_ino,
+ EXT4_I(inode)->i_file_acl);
+ goto cleanup;
+ }
+ ext4_xattr_release_block(handle, inode, bh);
+ EXT4_I(inode)->i_file_acl = 0;
+
+cleanup:
+ brelse(bh);
+}
+
+/*
+ * ext4_xattr_put_super()
+ *
+ * This is called when a file system is unmounted.
+ */
+void
+ext4_xattr_put_super(struct super_block *sb)
+{
+ mb_cache_shrink(sb->s_bdev);
+}
+
+/*
+ * ext4_xattr_cache_insert()
+ *
+ * Create a new entry in the extended attribute cache, and insert
+ * it unless such an entry is already in the cache.
+ *
+ * Returns 0, or a negative error number on failure.
+ */
+static void
+ext4_xattr_cache_insert(struct buffer_head *bh)
+{
+ __u32 hash = le32_to_cpu(BHDR(bh)->h_hash);
+ struct mb_cache_entry *ce;
+ int error;
+
+ ce = mb_cache_entry_alloc(ext4_xattr_cache);
+ if (!ce) {
+ ea_bdebug(bh, "out of memory");
+ return;
+ }
+ error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash);
+ if (error) {
+ mb_cache_entry_free(ce);
+ if (error == -EBUSY) {
+ ea_bdebug(bh, "already in cache");
+ error = 0;
+ }
+ } else {
+ ea_bdebug(bh, "inserting [%x]", (int)hash);
+ mb_cache_entry_release(ce);
+ }
+}
+
+/*
+ * ext4_xattr_cmp()
+ *
+ * Compare two extended attribute blocks for equality.
+ *
+ * Returns 0 if the blocks are equal, 1 if they differ, and
+ * a negative error number on errors.
+ */
+static int
+ext4_xattr_cmp(struct ext4_xattr_header *header1,
+ struct ext4_xattr_header *header2)
+{
+ struct ext4_xattr_entry *entry1, *entry2;
+
+ entry1 = ENTRY(header1+1);
+ entry2 = ENTRY(header2+1);
+ while (!IS_LAST_ENTRY(entry1)) {
+ if (IS_LAST_ENTRY(entry2))
+ return 1;
+ if (entry1->e_hash != entry2->e_hash ||
+ entry1->e_name_index != entry2->e_name_index ||
+ entry1->e_name_len != entry2->e_name_len ||
+ entry1->e_value_size != entry2->e_value_size ||
+ memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len))
+ return 1;
+ if (entry1->e_value_block != 0 || entry2->e_value_block != 0)
+ return -EIO;
+ if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs),
+ (char *)header2 + le16_to_cpu(entry2->e_value_offs),
+ le32_to_cpu(entry1->e_value_size)))
+ return 1;
+
+ entry1 = EXT4_XATTR_NEXT(entry1);
+ entry2 = EXT4_XATTR_NEXT(entry2);
+ }
+ if (!IS_LAST_ENTRY(entry2))
+ return 1;
+ return 0;
+}
+
+/*
+ * ext4_xattr_cache_find()
+ *
+ * Find an identical extended attribute block.
+ *
+ * Returns a pointer to the block found, or NULL if such a block was
+ * not found or an error occurred.
+ */
+static struct buffer_head *
+ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header,
+ struct mb_cache_entry **pce)
+{
+ __u32 hash = le32_to_cpu(header->h_hash);
+ struct mb_cache_entry *ce;
+
+ if (!header->h_hash)
+ return NULL; /* never share */
+ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash);
+again:
+ ce = mb_cache_entry_find_first(ext4_xattr_cache, 0,
+ inode->i_sb->s_bdev, hash);
+ while (ce) {
+ struct buffer_head *bh;
+
+ if (IS_ERR(ce)) {
+ if (PTR_ERR(ce) == -EAGAIN)
+ goto again;
+ break;
+ }
+ bh = sb_bread(inode->i_sb, ce->e_block);
+ if (!bh) {
+ ext4_error(inode->i_sb, __FUNCTION__,
+ "inode %lu: block %lu read error",
+ inode->i_ino, (unsigned long) ce->e_block);
+ } else if (le32_to_cpu(BHDR(bh)->h_refcount) >=
+ EXT4_XATTR_REFCOUNT_MAX) {
+ ea_idebug(inode, "block %lu refcount %d>=%d",
+ (unsigned long) ce->e_block,
+ le32_to_cpu(BHDR(bh)->h_refcount),
+ EXT4_XATTR_REFCOUNT_MAX);
+ } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) {
+ *pce = ce;
+ return bh;
+ }
+ brelse(bh);
+ ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash);
+ }
+ return NULL;
+}
+
+#define NAME_HASH_SHIFT 5
+#define VALUE_HASH_SHIFT 16
+
+/*
+ * ext4_xattr_hash_entry()
+ *
+ * Compute the hash of an extended attribute.
+ */
+static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
+ struct ext4_xattr_entry *entry)
+{
+ __u32 hash = 0;
+ char *name = entry->e_name;
+ int n;
+
+ for (n=0; n < entry->e_name_len; n++) {
+ hash = (hash << NAME_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
+ *name++;
+ }
+
+ if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+ __le32 *value = (__le32 *)((char *)header +
+ le16_to_cpu(entry->e_value_offs));
+ for (n = (le32_to_cpu(entry->e_value_size) +
+ EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
+ hash = (hash << VALUE_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
+ le32_to_cpu(*value++);
+ }
+ }
+ entry->e_hash = cpu_to_le32(hash);
+}
+
+#undef NAME_HASH_SHIFT
+#undef VALUE_HASH_SHIFT
+
+#define BLOCK_HASH_SHIFT 16
+
+/*
+ * ext4_xattr_rehash()
+ *
+ * Re-compute the extended attribute hash value after an entry has changed.
+ */
+static void ext4_xattr_rehash(struct ext4_xattr_header *header,
+ struct ext4_xattr_entry *entry)
+{
+ struct ext4_xattr_entry *here;
+ __u32 hash = 0;
+
+ ext4_xattr_hash_entry(header, entry);
+ here = ENTRY(header+1);
+ while (!IS_LAST_ENTRY(here)) {
+ if (!here->e_hash) {
+ /* Block is not shared if an entry's hash value == 0 */
+ hash = 0;
+ break;
+ }
+ hash = (hash << BLOCK_HASH_SHIFT) ^
+ (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^
+ le32_to_cpu(here->e_hash);
+ here = EXT4_XATTR_NEXT(here);
+ }
+ header->h_hash = cpu_to_le32(hash);
+}
+
+#undef BLOCK_HASH_SHIFT
+
+int __init
+init_ext4_xattr(void)
+{
+ ext4_xattr_cache = mb_cache_create("ext4_xattr", NULL,
+ sizeof(struct mb_cache_entry) +
+ sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6);
+ if (!ext4_xattr_cache)
+ return -ENOMEM;
+ return 0;
+}
+
+void
+exit_ext4_xattr(void)
+{
+ if (ext4_xattr_cache)
+ mb_cache_destroy(ext4_xattr_cache);
+ ext4_xattr_cache = NULL;
+}
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
new file mode 100644
index 000000000000..79432b35398f
--- /dev/null
+++ b/fs/ext4/xattr.h
@@ -0,0 +1,145 @@
+/*
+ File: fs/ext4/xattr.h
+
+ On-disk format of extended attributes for the ext4 filesystem.
+
+ (C) 2001 Andreas Gruenbacher, <a.gruenbacher@computer.org>
+*/
+
+#include <linux/xattr.h>
+
+/* Magic value in attribute blocks */
+#define EXT4_XATTR_MAGIC 0xEA020000
+
+/* Maximum number of references to one attribute block */
+#define EXT4_XATTR_REFCOUNT_MAX 1024
+
+/* Name indexes */
+#define EXT4_XATTR_INDEX_USER 1
+#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2
+#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3
+#define EXT4_XATTR_INDEX_TRUSTED 4
+#define EXT4_XATTR_INDEX_LUSTRE 5
+#define EXT4_XATTR_INDEX_SECURITY 6
+
+struct ext4_xattr_header {
+ __le32 h_magic; /* magic number for identification */
+ __le32 h_refcount; /* reference count */
+ __le32 h_blocks; /* number of disk blocks used */
+ __le32 h_hash; /* hash value of all attributes */
+ __u32 h_reserved[4]; /* zero right now */
+};
+
+struct ext4_xattr_ibody_header {
+ __le32 h_magic; /* magic number for identification */
+};
+
+struct ext4_xattr_entry {
+ __u8 e_name_len; /* length of name */
+ __u8 e_name_index; /* attribute name index */
+ __le16 e_value_offs; /* offset in disk block of value */
+ __le32 e_value_block; /* disk block attribute is stored on (n/i) */
+ __le32 e_value_size; /* size of attribute value */
+ __le32 e_hash; /* hash value of name and value */
+ char e_name[0]; /* attribute name */
+};
+
+#define EXT4_XATTR_PAD_BITS 2
+#define EXT4_XATTR_PAD (1<<EXT4_XATTR_PAD_BITS)
+#define EXT4_XATTR_ROUND (EXT4_XATTR_PAD-1)
+#define EXT4_XATTR_LEN(name_len) \
+ (((name_len) + EXT4_XATTR_ROUND + \
+ sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
+#define EXT4_XATTR_NEXT(entry) \
+ ( (struct ext4_xattr_entry *)( \
+ (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)) )
+#define EXT4_XATTR_SIZE(size) \
+ (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
+
+# ifdef CONFIG_EXT4DEV_FS_XATTR
+
+extern struct xattr_handler ext4_xattr_user_handler;
+extern struct xattr_handler ext4_xattr_trusted_handler;
+extern struct xattr_handler ext4_xattr_acl_access_handler;
+extern struct xattr_handler ext4_xattr_acl_default_handler;
+extern struct xattr_handler ext4_xattr_security_handler;
+
+extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
+
+extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t);
+extern int ext4_xattr_list(struct inode *, char *, size_t);
+extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int);
+extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int);
+
+extern void ext4_xattr_delete_inode(handle_t *, struct inode *);
+extern void ext4_xattr_put_super(struct super_block *);
+
+extern int init_ext4_xattr(void);
+extern void exit_ext4_xattr(void);
+
+extern struct xattr_handler *ext4_xattr_handlers[];
+
+# else /* CONFIG_EXT4DEV_FS_XATTR */
+
+static inline int
+ext4_xattr_get(struct inode *inode, int name_index, const char *name,
+ void *buffer, size_t size, int flags)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ext4_xattr_list(struct inode *inode, void *buffer, size_t size)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ext4_xattr_set(struct inode *inode, int name_index, const char *name,
+ const void *value, size_t size, int flags)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline int
+ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index,
+ const char *name, const void *value, size_t size, int flags)
+{
+ return -EOPNOTSUPP;
+}
+
+static inline void
+ext4_xattr_delete_inode(handle_t *handle, struct inode *inode)
+{
+}
+
+static inline void
+ext4_xattr_put_super(struct super_block *sb)
+{
+}
+
+static inline int
+init_ext4_xattr(void)
+{
+ return 0;
+}
+
+static inline void
+exit_ext4_xattr(void)
+{
+}
+
+#define ext4_xattr_handlers NULL
+
+# endif /* CONFIG_EXT4DEV_FS_XATTR */
+
+#ifdef CONFIG_EXT4DEV_FS_SECURITY
+extern int ext4_init_security(handle_t *handle, struct inode *inode,
+ struct inode *dir);
+#else
+static inline int ext4_init_security(handle_t *handle, struct inode *inode,
+ struct inode *dir)
+{
+ return 0;
+}
+#endif
diff --git a/fs/ext4/xattr_security.c b/fs/ext4/xattr_security.c
new file mode 100644
index 000000000000..b6a6861951f9
--- /dev/null
+++ b/fs/ext4/xattr_security.c
@@ -0,0 +1,77 @@
+/*
+ * linux/fs/ext4/xattr_security.c
+ * Handler for storing security labels as extended attributes.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/ext4_fs.h>
+#include <linux/security.h>
+#include "xattr.h"
+
+static size_t
+ext4_xattr_security_list(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const size_t prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
+ const size_t total_len = prefix_len + name_len + 1;
+
+
+ if (list && total_len <= list_size) {
+ memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
+ memcpy(list+prefix_len, name, name_len);
+ list[prefix_len + name_len] = '\0';
+ }
+ return total_len;
+}
+
+static int
+ext4_xattr_security_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY, name,
+ buffer, size);
+}
+
+static int
+ext4_xattr_security_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SECURITY, name,
+ value, size, flags);
+}
+
+int
+ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir)
+{
+ int err;
+ size_t len;
+ void *value;
+ char *name;
+
+ err = security_inode_init_security(inode, dir, &name, &value, &len);
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ return 0;
+ return err;
+ }
+ err = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_SECURITY,
+ name, value, len, 0);
+ kfree(name);
+ kfree(value);
+ return err;
+}
+
+struct xattr_handler ext4_xattr_security_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .list = ext4_xattr_security_list,
+ .get = ext4_xattr_security_get,
+ .set = ext4_xattr_security_set,
+};
diff --git a/fs/ext4/xattr_trusted.c b/fs/ext4/xattr_trusted.c
new file mode 100644
index 000000000000..b76f2dbc82da
--- /dev/null
+++ b/fs/ext4/xattr_trusted.c
@@ -0,0 +1,62 @@
+/*
+ * linux/fs/ext4/xattr_trusted.c
+ * Handler for trusted extended attributes.
+ *
+ * Copyright (C) 2003 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/ext4_fs.h>
+#include "xattr.h"
+
+#define XATTR_TRUSTED_PREFIX "trusted."
+
+static size_t
+ext4_xattr_trusted_list(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const size_t prefix_len = sizeof(XATTR_TRUSTED_PREFIX)-1;
+ const size_t total_len = prefix_len + name_len + 1;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return 0;
+
+ if (list && total_len <= list_size) {
+ memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len);
+ memcpy(list+prefix_len, name, name_len);
+ list[prefix_len + name_len] = '\0';
+ }
+ return total_len;
+}
+
+static int
+ext4_xattr_trusted_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ return ext4_xattr_get(inode, EXT4_XATTR_INDEX_TRUSTED, name,
+ buffer, size);
+}
+
+static int
+ext4_xattr_trusted_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ return ext4_xattr_set(inode, EXT4_XATTR_INDEX_TRUSTED, name,
+ value, size, flags);
+}
+
+struct xattr_handler ext4_xattr_trusted_handler = {
+ .prefix = XATTR_TRUSTED_PREFIX,
+ .list = ext4_xattr_trusted_list,
+ .get = ext4_xattr_trusted_get,
+ .set = ext4_xattr_trusted_set,
+};
diff --git a/fs/ext4/xattr_user.c b/fs/ext4/xattr_user.c
new file mode 100644
index 000000000000..c53cded0761a
--- /dev/null
+++ b/fs/ext4/xattr_user.c
@@ -0,0 +1,64 @@
+/*
+ * linux/fs/ext4/xattr_user.c
+ * Handler for extended user attributes.
+ *
+ * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/ext4_jbd2.h>
+#include <linux/ext4_fs.h>
+#include "xattr.h"
+
+#define XATTR_USER_PREFIX "user."
+
+static size_t
+ext4_xattr_user_list(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ const size_t prefix_len = sizeof(XATTR_USER_PREFIX)-1;
+ const size_t total_len = prefix_len + name_len + 1;
+
+ if (!test_opt(inode->i_sb, XATTR_USER))
+ return 0;
+
+ if (list && total_len <= list_size) {
+ memcpy(list, XATTR_USER_PREFIX, prefix_len);
+ memcpy(list+prefix_len, name, name_len);
+ list[prefix_len + name_len] = '\0';
+ }
+ return total_len;
+}
+
+static int
+ext4_xattr_user_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ if (!test_opt(inode->i_sb, XATTR_USER))
+ return -EOPNOTSUPP;
+ return ext4_xattr_get(inode, EXT4_XATTR_INDEX_USER, name, buffer, size);
+}
+
+static int
+ext4_xattr_user_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ if (!test_opt(inode->i_sb, XATTR_USER))
+ return -EOPNOTSUPP;
+ return ext4_xattr_set(inode, EXT4_XATTR_INDEX_USER, name,
+ value, size, flags);
+}
+
+struct xattr_handler ext4_xattr_user_handler = {
+ .prefix = XATTR_USER_PREFIX,
+ .list = ext4_xattr_user_list,
+ .get = ext4_xattr_user_get,
+ .set = ext4_xattr_user_set,
+};
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 97b967b84fc6..82cc4f59e3ba 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -58,8 +58,7 @@ int __init fat_cache_init(void)
void fat_cache_destroy(void)
{
- if (kmem_cache_destroy(fat_cache_cachep))
- printk(KERN_INFO "fat_cache: not all structures were freed\n");
+ kmem_cache_destroy(fat_cache_cachep);
}
static inline struct fat_cache *fat_cache_alloc(struct inode *inode)
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 698b85bb1dd4..69c439f44387 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -20,6 +20,7 @@
#include <linux/dirent.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
+#include <linux/compat.h>
#include <asm/uaccess.h>
static inline loff_t fat_make_i_pos(struct super_block *sb,
@@ -647,7 +648,7 @@ static int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
static int fat_ioctl_filldir(void *__buf, const char *name, int name_len,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct fat_ioctl_filldir_callback *buf = __buf;
struct dirent __user *d1 = buf->dirent;
@@ -741,10 +742,65 @@ static int fat_dir_ioctl(struct inode * inode, struct file * filp,
return ret;
}
+#ifdef CONFIG_COMPAT
+#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2])
+#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2])
+
+static long fat_compat_put_dirent32(struct dirent *d,
+ struct compat_dirent __user *d32)
+{
+ if (!access_ok(VERIFY_WRITE, d32, sizeof(struct compat_dirent)))
+ return -EFAULT;
+
+ __put_user(d->d_ino, &d32->d_ino);
+ __put_user(d->d_off, &d32->d_off);
+ __put_user(d->d_reclen, &d32->d_reclen);
+ if (__copy_to_user(d32->d_name, d->d_name, d->d_reclen))
+ return -EFAULT;
+
+ return 0;
+}
+
+static long fat_compat_dir_ioctl(struct file *file, unsigned cmd,
+ unsigned long arg)
+{
+ struct compat_dirent __user *p = compat_ptr(arg);
+ int ret;
+ mm_segment_t oldfs = get_fs();
+ struct dirent d[2];
+
+ switch (cmd) {
+ case VFAT_IOCTL_READDIR_BOTH32:
+ cmd = VFAT_IOCTL_READDIR_BOTH;
+ break;
+ case VFAT_IOCTL_READDIR_SHORT32:
+ cmd = VFAT_IOCTL_READDIR_SHORT;
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+
+ set_fs(KERNEL_DS);
+ lock_kernel();
+ ret = fat_dir_ioctl(file->f_dentry->d_inode, file,
+ cmd, (unsigned long) &d);
+ unlock_kernel();
+ set_fs(oldfs);
+ if (ret >= 0) {
+ ret |= fat_compat_put_dirent32(&d[0], p);
+ ret |= fat_compat_put_dirent32(&d[1], p + 1);
+ }
+ return ret;
+}
+#endif /* CONFIG_COMPAT */
+
const struct file_operations fat_dir_operations = {
.read = generic_read_dir,
.readdir = fat_readdir,
.ioctl = fat_dir_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = fat_compat_dir_ioctl,
+#endif
.fsync = file_fsync,
};
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 1ee25232e6af..8337451e7897 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -13,6 +13,8 @@
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
#include <linux/writeback.h>
+#include <linux/backing-dev.h>
+#include <linux/blkdev.h>
int fat_generic_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
@@ -112,15 +114,24 @@ int fat_generic_ioctl(struct inode *inode, struct file *filp,
}
}
+static int fat_file_release(struct inode *inode, struct file *filp)
+{
+ if ((filp->f_mode & FMODE_WRITE) &&
+ MSDOS_SB(inode->i_sb)->options.flush) {
+ fat_flush_inodes(inode->i_sb, inode, NULL);
+ congestion_wait(WRITE, HZ/10);
+ }
+ return 0;
+}
+
const struct file_operations fat_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
- .readv = generic_file_readv,
- .writev = generic_file_writev,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
+ .release = fat_file_release,
.ioctl = fat_generic_ioctl,
.fsync = file_fsync,
.sendfile = generic_file_sendfile,
@@ -289,6 +300,7 @@ void fat_truncate(struct inode *inode)
lock_kernel();
fat_free(inode, nr_clusters);
unlock_kernel();
+ fat_flush_inodes(inode->i_sb, inode, NULL);
}
struct inode_operations fat_file_inode_operations = {
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 31b7174176ba..78945b53b0f8 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -24,6 +24,7 @@
#include <linux/vfs.h>
#include <linux/parser.h>
#include <linux/uio.h>
+#include <linux/writeback.h>
#include <asm/unaligned.h>
#ifndef CONFIG_FAT_DEFAULT_IOCHARSET
@@ -50,14 +51,14 @@ static int fat_add_cluster(struct inode *inode)
return err;
}
-static int __fat_get_blocks(struct inode *inode, sector_t iblock,
- unsigned long *max_blocks,
- struct buffer_head *bh_result, int create)
+static inline int __fat_get_block(struct inode *inode, sector_t iblock,
+ unsigned long *max_blocks,
+ struct buffer_head *bh_result, int create)
{
struct super_block *sb = inode->i_sb;
struct msdos_sb_info *sbi = MSDOS_SB(sb);
- sector_t phys;
unsigned long mapped_blocks;
+ sector_t phys;
int err, offset;
err = fat_bmap(inode, iblock, &phys, &mapped_blocks);
@@ -73,7 +74,7 @@ static int __fat_get_blocks(struct inode *inode, sector_t iblock,
if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) {
fat_fs_panic(sb, "corrupted file size (i_pos %lld, %lld)",
- MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
+ MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private);
return -EIO;
}
@@ -93,34 +94,29 @@ static int __fat_get_blocks(struct inode *inode, sector_t iblock,
err = fat_bmap(inode, iblock, &phys, &mapped_blocks);
if (err)
return err;
+
BUG_ON(!phys);
BUG_ON(*max_blocks != mapped_blocks);
set_buffer_new(bh_result);
map_bh(bh_result, sb, phys);
+
return 0;
}
-static int fat_get_blocks(struct inode *inode, sector_t iblock,
- struct buffer_head *bh_result, int create)
+static int fat_get_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create)
{
struct super_block *sb = inode->i_sb;
- int err;
unsigned long max_blocks = bh_result->b_size >> inode->i_blkbits;
+ int err;
- err = __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create);
+ err = __fat_get_block(inode, iblock, &max_blocks, bh_result, create);
if (err)
return err;
bh_result->b_size = max_blocks << sb->s_blocksize_bits;
return 0;
}
-static int fat_get_block(struct inode *inode, sector_t iblock,
- struct buffer_head *bh_result, int create)
-{
- unsigned long max_blocks = 1;
- return __fat_get_blocks(inode, iblock, &max_blocks, bh_result, create);
-}
-
static int fat_writepage(struct page *page, struct writeback_control *wbc)
{
return block_write_full_page(page, fat_get_block, wbc);
@@ -188,7 +184,7 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb,
* condition of fat_get_block() and ->truncate().
*/
return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
- offset, nr_segs, fat_get_blocks, NULL);
+ offset, nr_segs, fat_get_block, NULL);
}
static sector_t _fat_bmap(struct address_space *mapping, sector_t block)
@@ -375,8 +371,6 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
inode->i_flags |= S_IMMUTABLE;
}
MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
- /* this is as close to the truth as we can get ... */
- inode->i_blksize = sbi->cluster_size;
inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
& ~((loff_t)sbi->cluster_size - 1)) >> 9;
inode->i_mtime.tv_sec =
@@ -390,7 +384,7 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
le16_to_cpu(de->cdate)) + secs;
inode->i_ctime.tv_nsec = csecs * 10000000;
inode->i_atime.tv_sec =
- date_dos2unix(le16_to_cpu(0), le16_to_cpu(de->adate));
+ date_dos2unix(0, le16_to_cpu(de->adate));
inode->i_atime.tv_nsec = 0;
} else
inode->i_ctime = inode->i_atime = inode->i_mtime;
@@ -528,8 +522,7 @@ static int __init fat_init_inodecache(void)
static void __exit fat_destroy_inodecache(void)
{
- if (kmem_cache_destroy(fat_inode_cachep))
- printk(KERN_INFO "fat_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(fat_inode_cachep);
}
static int fat_remount(struct super_block *sb, int *flags, char *data)
@@ -861,7 +854,7 @@ enum {
Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
- Opt_obsolate, Opt_err,
+ Opt_obsolate, Opt_flush, Opt_err,
};
static match_table_t fat_tokens = {
@@ -893,7 +886,8 @@ static match_table_t fat_tokens = {
{Opt_obsolate, "cvf_format=%20s"},
{Opt_obsolate, "cvf_options=%100s"},
{Opt_obsolate, "posix"},
- {Opt_err, NULL}
+ {Opt_flush, "flush"},
+ {Opt_err, NULL},
};
static match_table_t msdos_tokens = {
{Opt_nodots, "nodots"},
@@ -1034,6 +1028,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
return 0;
opts->codepage = option;
break;
+ case Opt_flush:
+ opts->flush = 1;
+ break;
/* msdos specific */
case Opt_dots:
@@ -1137,7 +1134,6 @@ static int fat_read_root(struct inode *inode)
MSDOS_I(inode)->i_start = 0;
inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry);
}
- inode->i_blksize = sbi->cluster_size;
inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1))
& ~((loff_t)sbi->cluster_size - 1)) >> 9;
MSDOS_I(inode)->i_logstart = 0;
@@ -1168,11 +1164,10 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
long error;
char buf[50];
- sbi = kmalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct msdos_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_fs_info = sbi;
- memset(sbi, 0, sizeof(struct msdos_sb_info));
sb->s_flags |= MS_NODIRATIME;
sb->s_magic = MSDOS_SUPER_MAGIC;
@@ -1435,6 +1430,56 @@ out_fail:
EXPORT_SYMBOL_GPL(fat_fill_super);
+/*
+ * helper function for fat_flush_inodes. This writes both the inode
+ * and the file data blocks, waiting for in flight data blocks before
+ * the start of the call. It does not wait for any io started
+ * during the call
+ */
+static int writeback_inode(struct inode *inode)
+{
+
+ int ret;
+ struct address_space *mapping = inode->i_mapping;
+ struct writeback_control wbc = {
+ .sync_mode = WB_SYNC_NONE,
+ .nr_to_write = 0,
+ };
+ /* if we used WB_SYNC_ALL, sync_inode waits for the io for the
+ * inode to finish. So WB_SYNC_NONE is sent down to sync_inode
+ * and filemap_fdatawrite is used for the data blocks
+ */
+ ret = sync_inode(inode, &wbc);
+ if (!ret)
+ ret = filemap_fdatawrite(mapping);
+ return ret;
+}
+
+/*
+ * write data and metadata corresponding to i1 and i2. The io is
+ * started but we do not wait for any of it to finish.
+ *
+ * filemap_flush is used for the block device, so if there is a dirty
+ * page for a block already in flight, we will not wait and start the
+ * io over again
+ */
+int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2)
+{
+ int ret = 0;
+ if (!MSDOS_SB(sb)->options.flush)
+ return 0;
+ if (i1)
+ ret = writeback_inode(i1);
+ if (!ret && i2)
+ ret = writeback_inode(i2);
+ if (!ret) {
+ struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping;
+ ret = filemap_flush(mapping);
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(fat_flush_inodes);
+
static int __init init_fat_fs(void)
{
int err;
diff --git a/fs/fcntl.c b/fs/fcntl.c
index d35cbc6bc112..e4f26165f12a 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -250,19 +250,22 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
return error;
}
-static void f_modown(struct file *filp, unsigned long pid,
+static void f_modown(struct file *filp, struct pid *pid, enum pid_type type,
uid_t uid, uid_t euid, int force)
{
write_lock_irq(&filp->f_owner.lock);
if (force || !filp->f_owner.pid) {
- filp->f_owner.pid = pid;
+ put_pid(filp->f_owner.pid);
+ filp->f_owner.pid = get_pid(pid);
+ filp->f_owner.pid_type = type;
filp->f_owner.uid = uid;
filp->f_owner.euid = euid;
}
write_unlock_irq(&filp->f_owner.lock);
}
-int f_setown(struct file *filp, unsigned long arg, int force)
+int __f_setown(struct file *filp, struct pid *pid, enum pid_type type,
+ int force)
{
int err;
@@ -270,15 +273,44 @@ int f_setown(struct file *filp, unsigned long arg, int force)
if (err)
return err;
- f_modown(filp, arg, current->uid, current->euid, force);
+ f_modown(filp, pid, type, current->uid, current->euid, force);
return 0;
}
+EXPORT_SYMBOL(__f_setown);
+int f_setown(struct file *filp, unsigned long arg, int force)
+{
+ enum pid_type type;
+ struct pid *pid;
+ int who = arg;
+ int result;
+ type = PIDTYPE_PID;
+ if (who < 0) {
+ type = PIDTYPE_PGID;
+ who = -who;
+ }
+ rcu_read_lock();
+ pid = find_pid(who);
+ result = __f_setown(filp, pid, type, force);
+ rcu_read_unlock();
+ return result;
+}
EXPORT_SYMBOL(f_setown);
void f_delown(struct file *filp)
{
- f_modown(filp, 0, 0, 0, 1);
+ f_modown(filp, NULL, PIDTYPE_PID, 0, 0, 1);
+}
+
+pid_t f_getown(struct file *filp)
+{
+ pid_t pid;
+ read_lock(&filp->f_owner.lock);
+ pid = pid_nr(filp->f_owner.pid);
+ if (filp->f_owner.pid_type == PIDTYPE_PGID)
+ pid = -pid;
+ read_unlock(&filp->f_owner.lock);
+ return pid;
}
static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
@@ -319,7 +351,7 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
* current syscall conventions, the only way
* to fix this will be in libc.
*/
- err = filp->f_owner.pid;
+ err = f_getown(filp);
force_successful_syscall_return();
break;
case F_SETOWN:
@@ -470,24 +502,19 @@ static void send_sigio_to_task(struct task_struct *p,
void send_sigio(struct fown_struct *fown, int fd, int band)
{
struct task_struct *p;
- int pid;
+ enum pid_type type;
+ struct pid *pid;
read_lock(&fown->lock);
+ type = fown->pid_type;
pid = fown->pid;
if (!pid)
goto out_unlock_fown;
read_lock(&tasklist_lock);
- if (pid > 0) {
- p = find_task_by_pid(pid);
- if (p) {
- send_sigio_to_task(p, fown, fd, band);
- }
- } else {
- do_each_task_pid(-pid, PIDTYPE_PGID, p) {
- send_sigio_to_task(p, fown, fd, band);
- } while_each_task_pid(-pid, PIDTYPE_PGID, p);
- }
+ do_each_pid_task(pid, type, p) {
+ send_sigio_to_task(p, fown, fd, band);
+ } while_each_pid_task(pid, type, p);
read_unlock(&tasklist_lock);
out_unlock_fown:
read_unlock(&fown->lock);
@@ -503,9 +530,12 @@ static void send_sigurg_to_task(struct task_struct *p,
int send_sigurg(struct fown_struct *fown)
{
struct task_struct *p;
- int pid, ret = 0;
+ enum pid_type type;
+ struct pid *pid;
+ int ret = 0;
read_lock(&fown->lock);
+ type = fown->pid_type;
pid = fown->pid;
if (!pid)
goto out_unlock_fown;
@@ -513,16 +543,9 @@ int send_sigurg(struct fown_struct *fown)
ret = 1;
read_lock(&tasklist_lock);
- if (pid > 0) {
- p = find_task_by_pid(pid);
- if (p) {
- send_sigurg_to_task(p, fown);
- }
- } else {
- do_each_task_pid(-pid, PIDTYPE_PGID, p) {
- send_sigurg_to_task(p, fown);
- } while_each_task_pid(-pid, PIDTYPE_PGID, p);
- }
+ do_each_pid_task(pid, type, p) {
+ send_sigurg_to_task(p, fown);
+ } while_each_pid_task(pid, type, p);
read_unlock(&tasklist_lock);
out_unlock_fown:
read_unlock(&fown->lock);
diff --git a/fs/file.c b/fs/file.c
index b3c6b82e6a9d..8e81775c5dc8 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -281,80 +281,70 @@ static struct fdtable *alloc_fdtable(int nr)
out2:
nfds = fdt->max_fdset;
out:
- if (new_openset)
- free_fdset(new_openset, nfds);
- if (new_execset)
- free_fdset(new_execset, nfds);
+ free_fdset(new_openset, nfds);
+ free_fdset(new_execset, nfds);
kfree(fdt);
return NULL;
}
/*
- * Expands the file descriptor table - it will allocate a new fdtable and
- * both fd array and fdset. It is expected to be called with the
- * files_lock held.
+ * Expand the file descriptor table.
+ * This function will allocate a new fdtable and both fd array and fdset, of
+ * the given size.
+ * Return <0 error code on error; 1 on successful completion.
+ * The files->file_lock should be held on entry, and will be held on exit.
*/
static int expand_fdtable(struct files_struct *files, int nr)
__releases(files->file_lock)
__acquires(files->file_lock)
{
- int error = 0;
- struct fdtable *fdt;
- struct fdtable *nfdt = NULL;
+ struct fdtable *new_fdt, *cur_fdt;
spin_unlock(&files->file_lock);
- nfdt = alloc_fdtable(nr);
- if (!nfdt) {
- error = -ENOMEM;
- spin_lock(&files->file_lock);
- goto out;
- }
-
+ new_fdt = alloc_fdtable(nr);
spin_lock(&files->file_lock);
- fdt = files_fdtable(files);
+ if (!new_fdt)
+ return -ENOMEM;
/*
- * Check again since another task may have expanded the
- * fd table while we dropped the lock
+ * Check again since another task may have expanded the fd table while
+ * we dropped the lock
*/
- if (nr >= fdt->max_fds || nr >= fdt->max_fdset) {
- copy_fdtable(nfdt, fdt);
+ cur_fdt = files_fdtable(files);
+ if (nr >= cur_fdt->max_fds || nr >= cur_fdt->max_fdset) {
+ /* Continue as planned */
+ copy_fdtable(new_fdt, cur_fdt);
+ rcu_assign_pointer(files->fdt, new_fdt);
+ free_fdtable(cur_fdt);
} else {
- /* Somebody expanded while we dropped file_lock */
- spin_unlock(&files->file_lock);
- __free_fdtable(nfdt);
- spin_lock(&files->file_lock);
- goto out;
+ /* Somebody else expanded, so undo our attempt */
+ __free_fdtable(new_fdt);
}
- rcu_assign_pointer(files->fdt, nfdt);
- free_fdtable(fdt);
-out:
- return error;
+ return 1;
}
/*
* Expand files.
- * Return <0 on error; 0 nothing done; 1 files expanded, we may have blocked.
- * Should be called with the files->file_lock spinlock held for write.
+ * This function will expand the file structures, if the requested size exceeds
+ * the current capacity and there is room for expansion.
+ * Return <0 error code on error; 0 when nothing done; 1 when files were
+ * expanded and execution may have blocked.
+ * The files->file_lock should be held on entry, and will be held on exit.
*/
int expand_files(struct files_struct *files, int nr)
{
- int err, expand = 0;
struct fdtable *fdt;
fdt = files_fdtable(files);
- if (nr >= fdt->max_fdset || nr >= fdt->max_fds) {
- if (fdt->max_fdset >= NR_OPEN ||
- fdt->max_fds >= NR_OPEN || nr >= NR_OPEN) {
- err = -EMFILE;
- goto out;
- }
- expand = 1;
- if ((err = expand_fdtable(files, nr)))
- goto out;
- }
- err = expand;
-out:
- return err;
+ /* Do we need to expand? */
+ if (nr < fdt->max_fdset && nr < fdt->max_fds)
+ return 0;
+ /* Can we expand? */
+ if (fdt->max_fdset >= NR_OPEN || fdt->max_fds >= NR_OPEN ||
+ nr >= NR_OPEN)
+ return -EMFILE;
+
+ /* All good, so we try */
+ return expand_fdtable(files, nr);
}
static void __devinit fdtable_defer_list_init(int cpu)
diff --git a/fs/file_table.c b/fs/file_table.c
index 0131ba06e1ee..24f25a057d9c 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -169,11 +169,12 @@ void fastcall __fput(struct file *file)
if (file->f_op && file->f_op->release)
file->f_op->release(inode, file);
security_file_free(file);
- if (unlikely(inode->i_cdev != NULL))
+ if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL))
cdev_put(inode->i_cdev);
fops_put(file->f_op);
if (file->f_mode & FMODE_WRITE)
put_write_access(inode);
+ put_pid(file->f_owner.pid);
file_kill(file);
file->f_dentry = NULL;
file->f_vfsmnt = NULL;
diff --git a/fs/filesystems.c b/fs/filesystems.c
index 9f1072836c8e..e3fa77c6ed56 100644
--- a/fs/filesystems.c
+++ b/fs/filesystems.c
@@ -69,8 +69,6 @@ int register_filesystem(struct file_system_type * fs)
int res = 0;
struct file_system_type ** p;
- if (!fs)
- return -EINVAL;
if (fs->next)
return -EBUSY;
INIT_LIST_HEAD(&fs->fs_supers);
diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
index d35979a58743..c8a92652612a 100644
--- a/fs/freevxfs/vxfs.h
+++ b/fs/freevxfs/vxfs.h
@@ -252,7 +252,7 @@ enum {
* Get filesystem private data from VFS inode.
*/
#define VXFS_INO(ip) \
- ((struct vxfs_inode_info *)(ip)->u.generic_ip)
+ ((struct vxfs_inode_info *)(ip)->i_private)
/*
* Get filesystem private data from VFS superblock.
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index ca6a39714771..4786d51ad3bd 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -239,11 +239,10 @@ vxfs_iinit(struct inode *ip, struct vxfs_inode_info *vip)
ip->i_ctime.tv_nsec = 0;
ip->i_mtime.tv_nsec = 0;
- ip->i_blksize = PAGE_SIZE;
ip->i_blocks = vip->vii_blocks;
ip->i_generation = vip->vii_gen;
- ip->u.generic_ip = (void *)vip;
+ ip->i_private = vip;
}
@@ -338,5 +337,5 @@ vxfs_read_inode(struct inode *ip)
void
vxfs_clear_inode(struct inode *ip)
{
- kmem_cache_free(vxfs_inode_cachep, ip->u.generic_ip);
+ kmem_cache_free(vxfs_inode_cachep, ip->i_private);
}
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index b74b791fc23b..ac28b0835ffc 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -260,12 +260,17 @@ static struct file_system_type vxfs_fs_type = {
static int __init
vxfs_init(void)
{
+ int rv;
+
vxfs_inode_cachep = kmem_cache_create("vxfs_inode",
sizeof(struct vxfs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL, NULL);
- if (vxfs_inode_cachep)
- return register_filesystem(&vxfs_fs_type);
- return -ENOMEM;
+ if (!vxfs_inode_cachep)
+ return -ENOMEM;
+ rv = register_filesystem(&vxfs_fs_type);
+ if (rv < 0)
+ kmem_cache_destroy(vxfs_inode_cachep);
+ return rv;
}
static void __exit
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 892643dc9af1..c403b66ec83c 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -22,8 +22,7 @@
#include <linux/blkdev.h>
#include <linux/backing-dev.h>
#include <linux/buffer_head.h>
-
-extern struct super_block *blockdev_superblock;
+#include "internal.h"
/**
* __mark_inode_dirty - internal function
@@ -320,7 +319,7 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
if (!bdi_cap_writeback_dirty(bdi)) {
list_move(&inode->i_list, &sb->s_dirty);
- if (sb == blockdev_superblock) {
+ if (sb_is_blkdev_sb(sb)) {
/*
* Dirty memory-backed blockdev: the ramdisk
* driver does this. Skip just this inode
@@ -337,14 +336,14 @@ sync_sb_inodes(struct super_block *sb, struct writeback_control *wbc)
if (wbc->nonblocking && bdi_write_congested(bdi)) {
wbc->encountered_congestion = 1;
- if (sb != blockdev_superblock)
+ if (!sb_is_blkdev_sb(sb))
break; /* Skip a congested fs */
list_move(&inode->i_list, &sb->s_dirty);
continue; /* Skip a congested blockdev */
}
if (wbc->bdi && bdi != wbc->bdi) {
- if (sb != blockdev_superblock)
+ if (!sb_is_blkdev_sb(sb))
break; /* fs has the wrong queue */
list_move(&inode->i_list, &sb->s_dirty);
continue; /* blockdev has wrong queue */
diff --git a/fs/fuse/control.c b/fs/fuse/control.c
index 46fe60b2da23..16b39c053d47 100644
--- a/fs/fuse/control.c
+++ b/fs/fuse/control.c
@@ -23,7 +23,7 @@ static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file)
{
struct fuse_conn *fc;
mutex_lock(&fuse_mutex);
- fc = file->f_dentry->d_inode->u.generic_ip;
+ fc = file->f_dentry->d_inode->i_private;
if (fc)
fc = fuse_conn_get(fc);
mutex_unlock(&fuse_mutex);
@@ -98,7 +98,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent,
inode->i_op = iop;
inode->i_fop = fop;
inode->i_nlink = nlink;
- inode->u.generic_ip = fc;
+ inode->i_private = fc;
d_add(dentry, inode);
return dentry;
}
@@ -116,7 +116,7 @@ int fuse_ctl_add_conn(struct fuse_conn *fc)
return 0;
parent = fuse_control_sb->s_root;
- parent->d_inode->i_nlink++;
+ inc_nlink(parent->d_inode);
sprintf(name, "%llu", (unsigned long long) fc->id);
parent = fuse_ctl_add_dentry(parent, fc, name, S_IFDIR | 0500, 2,
&simple_dir_inode_operations,
@@ -150,7 +150,7 @@ void fuse_ctl_remove_conn(struct fuse_conn *fc)
for (i = fc->ctl_ndents - 1; i >= 0; i--) {
struct dentry *dentry = fc->ctl_dentry[i];
- dentry->d_inode->u.generic_ip = NULL;
+ dentry->d_inode->i_private = NULL;
d_drop(dentry);
dput(dentry);
}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 1e2006caf158..66571eafbb1e 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -212,6 +212,7 @@ void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
* Called with fc->lock, unlocks it
*/
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
+ __releases(fc->lock)
{
void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
req->end = NULL;
@@ -640,6 +641,7 @@ static void request_wait(struct fuse_conn *fc)
*/
static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
const struct iovec *iov, unsigned long nr_segs)
+ __releases(fc->lock)
{
struct fuse_copy_state cs;
struct fuse_in_header ih;
@@ -678,14 +680,15 @@ static int fuse_read_interrupt(struct fuse_conn *fc, struct fuse_req *req,
* request_end(). Otherwise add it to the processing list, and set
* the 'sent' flag.
*/
-static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *off)
+static ssize_t fuse_dev_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
int err;
struct fuse_req *req;
struct fuse_in *in;
struct fuse_copy_state cs;
unsigned reqsize;
+ struct file *file = iocb->ki_filp;
struct fuse_conn *fc = fuse_get_conn(file);
if (!fc)
return -EPERM;
@@ -759,15 +762,6 @@ static ssize_t fuse_dev_readv(struct file *file, const struct iovec *iov,
return err;
}
-static ssize_t fuse_dev_read(struct file *file, char __user *buf,
- size_t nbytes, loff_t *off)
-{
- struct iovec iov;
- iov.iov_len = nbytes;
- iov.iov_base = buf;
- return fuse_dev_readv(file, &iov, 1, off);
-}
-
/* Look up request on processing list by unique ID */
static struct fuse_req *request_find(struct fuse_conn *fc, u64 unique)
{
@@ -812,15 +806,15 @@ static int copy_out_args(struct fuse_copy_state *cs, struct fuse_out *out,
* it from the list and copy the rest of the buffer to the request.
* The request is finished by calling request_end()
*/
-static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *off)
+static ssize_t fuse_dev_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
int err;
unsigned nbytes = iov_length(iov, nr_segs);
struct fuse_req *req;
struct fuse_out_header oh;
struct fuse_copy_state cs;
- struct fuse_conn *fc = fuse_get_conn(file);
+ struct fuse_conn *fc = fuse_get_conn(iocb->ki_filp);
if (!fc)
return -EPERM;
@@ -896,15 +890,6 @@ static ssize_t fuse_dev_writev(struct file *file, const struct iovec *iov,
return err;
}
-static ssize_t fuse_dev_write(struct file *file, const char __user *buf,
- size_t nbytes, loff_t *off)
-{
- struct iovec iov;
- iov.iov_len = nbytes;
- iov.iov_base = (char __user *) buf;
- return fuse_dev_writev(file, &iov, 1, off);
-}
-
static unsigned fuse_dev_poll(struct file *file, poll_table *wait)
{
unsigned mask = POLLOUT | POLLWRNORM;
@@ -1039,10 +1024,10 @@ static int fuse_dev_fasync(int fd, struct file *file, int on)
const struct file_operations fuse_dev_operations = {
.owner = THIS_MODULE,
.llseek = no_llseek,
- .read = fuse_dev_read,
- .readv = fuse_dev_readv,
- .write = fuse_dev_write,
- .writev = fuse_dev_writev,
+ .read = do_sync_read,
+ .aio_read = fuse_dev_read,
+ .write = do_sync_write,
+ .aio_write = fuse_dev_write,
.poll = fuse_dev_poll,
.release = fuse_dev_release,
.fasync = fuse_dev_fasync,
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 409ce6a7cca4..cfc8f81e60d0 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -138,6 +138,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
struct fuse_entry_out outarg;
struct fuse_conn *fc;
struct fuse_req *req;
+ struct dentry *parent;
/* Doesn't hurt to "reset" the validity timeout */
fuse_invalidate_entry_cache(entry);
@@ -151,8 +152,10 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
if (IS_ERR(req))
return 0;
- fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg);
+ parent = dget_parent(entry);
+ fuse_lookup_init(req, parent->d_inode, entry, &outarg);
request_send(fc, req);
+ dput(parent);
err = req->out.h.error;
/* Zero nodeid is same as -ENOENT */
if (!err && !outarg.nodeid)
@@ -163,7 +166,9 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
fuse_send_forget(fc, req, outarg.nodeid, 1);
return 0;
}
+ spin_lock(&fc->lock);
fi->nlookup ++;
+ spin_unlock(&fc->lock);
}
fuse_put_request(fc, req);
if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT)
@@ -175,22 +180,6 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
return 1;
}
-/*
- * Check if there's already a hashed alias of this directory inode.
- * If yes, then lookup and mkdir must not create a new alias.
- */
-static int dir_alias(struct inode *inode)
-{
- if (S_ISDIR(inode->i_mode)) {
- struct dentry *alias = d_find_alias(inode);
- if (alias) {
- dput(alias);
- return 1;
- }
- }
- return 0;
-}
-
static int invalid_nodeid(u64 nodeid)
{
return !nodeid || nodeid == FUSE_ROOT_ID;
@@ -206,6 +195,24 @@ static int valid_mode(int m)
S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m);
}
+/*
+ * Add a directory inode to a dentry, ensuring that no other dentry
+ * refers to this inode. Called with fc->inst_mutex.
+ */
+static int fuse_d_add_directory(struct dentry *entry, struct inode *inode)
+{
+ struct dentry *alias = d_find_alias(inode);
+ if (alias) {
+ /* This tries to shrink the subtree below alias */
+ fuse_invalidate_entry(alias);
+ dput(alias);
+ if (!list_empty(&inode->i_dentry))
+ return -EBUSY;
+ }
+ d_add(entry, inode);
+ return 0;
+}
+
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
struct nameidata *nd)
{
@@ -241,11 +248,17 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
if (err && err != -ENOENT)
return ERR_PTR(err);
- if (inode && dir_alias(inode)) {
- iput(inode);
- return ERR_PTR(-EIO);
- }
- d_add(entry, inode);
+ if (inode && S_ISDIR(inode->i_mode)) {
+ mutex_lock(&fc->inst_mutex);
+ err = fuse_d_add_directory(entry, inode);
+ mutex_unlock(&fc->inst_mutex);
+ if (err) {
+ iput(inode);
+ return ERR_PTR(err);
+ }
+ } else
+ d_add(entry, inode);
+
entry->d_op = &fuse_dentry_operations;
if (!err)
fuse_change_timeout(entry, &outarg);
@@ -401,12 +414,22 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req,
}
fuse_put_request(fc, req);
- if (dir_alias(inode)) {
- iput(inode);
- return -EIO;
- }
+ if (S_ISDIR(inode->i_mode)) {
+ struct dentry *alias;
+ mutex_lock(&fc->inst_mutex);
+ alias = d_find_alias(inode);
+ if (alias) {
+ /* New directory must have moved since mkdir */
+ mutex_unlock(&fc->inst_mutex);
+ dput(alias);
+ iput(inode);
+ return -EBUSY;
+ }
+ d_instantiate(entry, inode);
+ mutex_unlock(&fc->inst_mutex);
+ } else
+ d_instantiate(entry, inode);
- d_instantiate(entry, inode);
fuse_change_timeout(entry, &outarg);
fuse_invalidate_attr(dir);
return 0;
@@ -508,7 +531,7 @@ static int fuse_unlink(struct inode *dir, struct dentry *entry)
/* Set nlink to zero so the inode can be cleared, if
the inode does have more links this will be
discovered at the next lookup/getattr */
- inode->i_nlink = 0;
+ clear_nlink(inode);
fuse_invalidate_attr(inode);
fuse_invalidate_attr(dir);
fuse_invalidate_entry_cache(entry);
@@ -534,7 +557,7 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
err = req->out.h.error;
fuse_put_request(fc, req);
if (!err) {
- entry->d_inode->i_nlink = 0;
+ clear_nlink(entry->d_inode);
fuse_invalidate_attr(dir);
fuse_invalidate_entry_cache(entry);
} else if (err == -EINTR)
@@ -776,7 +799,7 @@ static int fuse_permission(struct inode *inode, int mask, struct nameidata *nd)
if ((mask & MAY_EXEC) && !S_ISDIR(mode) && !(mode & S_IXUGO))
return -EACCES;
- if (nd && (nd->flags & LOOKUP_ACCESS))
+ if (nd && (nd->flags & (LOOKUP_ACCESS | LOOKUP_CHDIR)))
return fuse_access(inode, mask);
return 0;
}
@@ -935,14 +958,30 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg)
}
}
+static void fuse_vmtruncate(struct inode *inode, loff_t offset)
+{
+ struct fuse_conn *fc = get_fuse_conn(inode);
+ int need_trunc;
+
+ spin_lock(&fc->lock);
+ need_trunc = inode->i_size > offset;
+ i_size_write(inode, offset);
+ spin_unlock(&fc->lock);
+
+ if (need_trunc) {
+ struct address_space *mapping = inode->i_mapping;
+ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1);
+ truncate_inode_pages(mapping, offset);
+ }
+}
+
/*
* Set attributes, and at the same time refresh them.
*
* Truncation is slightly complicated, because the 'truncate' request
* may fail, in which case we don't want to touch the mapping.
- * vmtruncate() doesn't allow for this case. So do the rlimit
- * checking by hand and call vmtruncate() only after the file has
- * actually been truncated.
+ * vmtruncate() doesn't allow for this case, so do the rlimit checking
+ * and the actual truncation by hand.
*/
static int fuse_setattr(struct dentry *entry, struct iattr *attr)
{
@@ -993,12 +1032,8 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr)
make_bad_inode(inode);
err = -EIO;
} else {
- if (is_truncate) {
- loff_t origsize = i_size_read(inode);
- i_size_write(inode, outarg.attr.size);
- if (origsize > outarg.attr.size)
- vmtruncate(inode, outarg.attr.size);
- }
+ if (is_truncate)
+ fuse_vmtruncate(inode, outarg.attr.size);
fuse_change_attributes(inode, &outarg.attr);
fi->i_time = time_to_jiffies(outarg.attr_valid,
outarg.attr_valid_nsec);
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 5c4fcd1dbf59..2bb5ace3882d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -481,8 +481,10 @@ static int fuse_commit_write(struct file *file, struct page *page,
err = -EIO;
if (!err) {
pos += count;
- if (pos > i_size_read(inode))
+ spin_lock(&fc->lock);
+ if (pos > inode->i_size)
i_size_write(inode, pos);
+ spin_unlock(&fc->lock);
if (offset == 0 && to == PAGE_CACHE_SIZE) {
clear_page_dirty(page);
@@ -586,8 +588,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf,
}
fuse_put_request(fc, req);
if (res > 0) {
- if (write && pos > i_size_read(inode))
- i_size_write(inode, pos);
+ if (write) {
+ spin_lock(&fc->lock);
+ if (pos > inode->i_size)
+ i_size_write(inode, pos);
+ spin_unlock(&fc->lock);
+ }
*ppos = pos;
}
fuse_invalidate_attr(inode);
@@ -753,8 +759,10 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl)
static const struct file_operations fuse_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = fuse_file_mmap,
.open = fuse_open,
.flush = fuse_flush,
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 69c7750d55b8..91edb8932d90 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -239,6 +239,9 @@ struct fuse_conn {
/** Lock protecting accessess to members of this structure */
spinlock_t lock;
+ /** Mutex protecting against directory alias creation */
+ struct mutex inst_mutex;
+
/** Refcount */
atomic_t count;
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c
index 7d25092262ae..fc4203570370 100644
--- a/fs/fuse/inode.c
+++ b/fs/fuse/inode.c
@@ -109,6 +109,7 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
{
+ struct fuse_conn *fc = get_fuse_conn(inode);
if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size)
invalidate_inode_pages(inode->i_mapping);
@@ -117,8 +118,9 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
inode->i_nlink = attr->nlink;
inode->i_uid = attr->uid;
inode->i_gid = attr->gid;
+ spin_lock(&fc->lock);
i_size_write(inode, attr->size);
- inode->i_blksize = PAGE_CACHE_SIZE;
+ spin_unlock(&fc->lock);
inode->i_blocks = attr->blocks;
inode->i_atime.tv_sec = attr->atime;
inode->i_atime.tv_nsec = attr->atimensec;
@@ -131,7 +133,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr)
static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr)
{
inode->i_mode = attr->mode & S_IFMT;
- i_size_write(inode, attr->size);
+ inode->i_size = attr->size;
if (S_ISREG(inode->i_mode)) {
fuse_init_common(inode);
fuse_init_file_inode(inode);
@@ -170,7 +172,6 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
struct inode *inode;
struct fuse_inode *fi;
struct fuse_conn *fc = get_fuse_conn_super(sb);
- int retried = 0;
retry:
inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid);
@@ -184,16 +185,16 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid,
fuse_init_inode(inode, attr);
unlock_new_inode(inode);
} else if ((inode->i_mode ^ attr->mode) & S_IFMT) {
- BUG_ON(retried);
/* Inode has changed type, any I/O on the old should fail */
make_bad_inode(inode);
iput(inode);
- retried = 1;
goto retry;
}
fi = get_fuse_inode(inode);
+ spin_lock(&fc->lock);
fi->nlookup ++;
+ spin_unlock(&fc->lock);
fuse_change_attributes(inode, attr);
return inode;
}
@@ -252,6 +253,7 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf)
memset(&outarg, 0, sizeof(outarg));
req->in.numargs = 0;
req->in.h.opcode = FUSE_STATFS;
+ req->in.h.nodeid = get_node_id(dentry->d_inode);
req->out.numargs = 1;
req->out.args[0].size =
fc->minor < 4 ? FUSE_COMPAT_STATFS_SIZE : sizeof(outarg);
@@ -377,6 +379,7 @@ static struct fuse_conn *new_conn(void)
fc = kzalloc(sizeof(*fc), GFP_KERNEL);
if (fc) {
spin_lock_init(&fc->lock);
+ mutex_init(&fc->inst_mutex);
atomic_set(&fc->count, 1);
init_waitqueue_head(&fc->waitq);
init_waitqueue_head(&fc->blocked_waitq);
@@ -396,8 +399,10 @@ static struct fuse_conn *new_conn(void)
void fuse_conn_put(struct fuse_conn *fc)
{
- if (atomic_dec_and_test(&fc->count))
+ if (atomic_dec_and_test(&fc->count)) {
+ mutex_destroy(&fc->inst_mutex);
kfree(fc);
+ }
}
struct fuse_conn *fuse_conn_get(struct fuse_conn *fc)
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
new file mode 100644
index 000000000000..9ccb78947171
--- /dev/null
+++ b/fs/generic_acl.c
@@ -0,0 +1,197 @@
+/*
+ * fs/generic_acl.c
+ *
+ * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/generic_acl.h>
+
+/**
+ * generic_acl_list - Generic xattr_handler->list() operation
+ * @ops: Filesystem specific getacl and setacl callbacks
+ */
+size_t
+generic_acl_list(struct inode *inode, struct generic_acl_operations *ops,
+ int type, char *list, size_t list_size)
+{
+ struct posix_acl *acl;
+ const char *name;
+ size_t size;
+
+ acl = ops->getacl(inode, type);
+ if (!acl)
+ return 0;
+ posix_acl_release(acl);
+
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ break;
+
+ default:
+ return 0;
+ }
+ size = strlen(name) + 1;
+ if (list && size <= list_size)
+ memcpy(list, name, size);
+ return size;
+}
+
+/**
+ * generic_acl_get - Generic xattr_handler->get() operation
+ * @ops: Filesystem specific getacl and setacl callbacks
+ */
+int
+generic_acl_get(struct inode *inode, struct generic_acl_operations *ops,
+ int type, void *buffer, size_t size)
+{
+ struct posix_acl *acl;
+ int error;
+
+ acl = ops->getacl(inode, type);
+ if (!acl)
+ return -ENODATA;
+ error = posix_acl_to_xattr(acl, buffer, size);
+ posix_acl_release(acl);
+
+ return error;
+}
+
+/**
+ * generic_acl_set - Generic xattr_handler->set() operation
+ * @ops: Filesystem specific getacl and setacl callbacks
+ */
+int
+generic_acl_set(struct inode *inode, struct generic_acl_operations *ops,
+ int type, const void *value, size_t size)
+{
+ struct posix_acl *acl = NULL;
+ int error;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+ if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER))
+ return -EPERM;
+ if (value) {
+ acl = posix_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ }
+ if (acl) {
+ mode_t mode;
+
+ error = posix_acl_valid(acl);
+ if (error)
+ goto failed;
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ mode = inode->i_mode;
+ error = posix_acl_equiv_mode(acl, &mode);
+ if (error < 0)
+ goto failed;
+ inode->i_mode = mode;
+ if (error == 0) {
+ posix_acl_release(acl);
+ acl = NULL;
+ }
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ if (!S_ISDIR(inode->i_mode)) {
+ error = -EINVAL;
+ goto failed;
+ }
+ break;
+ }
+ }
+ ops->setacl(inode, type, acl);
+ error = 0;
+failed:
+ posix_acl_release(acl);
+ return error;
+}
+
+/**
+ * generic_acl_init - Take care of acl inheritance at @inode create time
+ * @ops: Filesystem specific getacl and setacl callbacks
+ *
+ * Files created inside a directory with a default ACL inherit the
+ * directory's default ACL.
+ */
+int
+generic_acl_init(struct inode *inode, struct inode *dir,
+ struct generic_acl_operations *ops)
+{
+ struct posix_acl *acl = NULL;
+ mode_t mode = inode->i_mode;
+ int error;
+
+ inode->i_mode = mode & ~current->fs->umask;
+ if (!S_ISLNK(inode->i_mode))
+ acl = ops->getacl(dir, ACL_TYPE_DEFAULT);
+ if (acl) {
+ struct posix_acl *clone;
+
+ if (S_ISDIR(inode->i_mode)) {
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!clone)
+ goto cleanup;
+ ops->setacl(inode, ACL_TYPE_DEFAULT, clone);
+ posix_acl_release(clone);
+ }
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!clone)
+ goto cleanup;
+ error = posix_acl_create_masq(clone, &mode);
+ if (error >= 0) {
+ inode->i_mode = mode;
+ if (error > 0)
+ ops->setacl(inode, ACL_TYPE_ACCESS, clone);
+ }
+ posix_acl_release(clone);
+ }
+ error = 0;
+
+cleanup:
+ posix_acl_release(acl);
+ return error;
+}
+
+/**
+ * generic_acl_chmod - change the access acl of @inode upon chmod()
+ * @ops: FIlesystem specific getacl and setacl callbacks
+ *
+ * A chmod also changes the permissions of the owner, group/mask, and
+ * other ACL entries.
+ */
+int
+generic_acl_chmod(struct inode *inode, struct generic_acl_operations *ops)
+{
+ struct posix_acl *acl, *clone;
+ int error = 0;
+
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
+ acl = ops->getacl(inode, ACL_TYPE_ACCESS);
+ if (acl) {
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ posix_acl_release(acl);
+ if (!clone)
+ return -ENOMEM;
+ error = posix_acl_chmod_masq(clone, inode->i_mode);
+ if (!error)
+ ops->setacl(inode, ACL_TYPE_ACCESS, clone);
+ posix_acl_release(clone);
+ }
+ return error;
+}
diff --git a/fs/gfs2/Kconfig b/fs/gfs2/Kconfig
new file mode 100644
index 000000000000..8c27de8b9568
--- /dev/null
+++ b/fs/gfs2/Kconfig
@@ -0,0 +1,44 @@
+config GFS2_FS
+ tristate "GFS2 file system support"
+ depends on EXPERIMENTAL
+ select FS_POSIX_ACL
+ help
+ A cluster filesystem.
+
+ Allows a cluster of computers to simultaneously use a block device
+ that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads
+ and writes to the block device like a local filesystem, but also uses
+ a lock module to allow the computers coordinate their I/O so
+ filesystem consistency is maintained. One of the nifty features of
+ GFS is perfect consistency -- changes made to the filesystem on one
+ machine show up immediately on all other machines in the cluster.
+
+ To use the GFS2 filesystem, you will need to enable one or more of
+ the below locking modules. Documentation and utilities for GFS2 can
+ be found here: http://sources.redhat.com/cluster
+
+config GFS2_FS_LOCKING_NOLOCK
+ tristate "GFS2 \"nolock\" locking module"
+ depends on GFS2_FS
+ help
+ Single node locking module for GFS2.
+
+ Use this module if you want to use GFS2 on a single node without
+ its clustering features. You can still take advantage of the
+ large file support, and upgrade to running a full cluster later on
+ if required.
+
+ If you will only be using GFS2 in cluster mode, you do not need this
+ module.
+
+config GFS2_FS_LOCKING_DLM
+ tristate "GFS2 DLM locking module"
+ depends on GFS2_FS
+ select DLM
+ help
+ Multiple node locking module for GFS2
+
+ Most users of GFS2 will require this module. It provides the locking
+ interface between GFS2 and the DLM, which is required to use GFS2
+ in a cluster environment.
+
diff --git a/fs/gfs2/Makefile b/fs/gfs2/Makefile
new file mode 100644
index 000000000000..e3f1ada643ac
--- /dev/null
+++ b/fs/gfs2/Makefile
@@ -0,0 +1,10 @@
+obj-$(CONFIG_GFS2_FS) += gfs2.o
+gfs2-y := acl.o bmap.o daemon.o dir.o eaops.o eattr.o glock.o \
+ glops.o inode.o lm.o log.o lops.o locking.o main.o meta_io.o \
+ mount.o ondisk.o ops_address.o ops_dentry.o ops_export.o ops_file.o \
+ ops_fstype.o ops_inode.o ops_super.o ops_vm.o quota.o \
+ recovery.o rgrp.o super.o sys.o trans.o util.o
+
+obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += locking/nolock/
+obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += locking/dlm/
+
diff --git a/fs/gfs2/acl.c b/fs/gfs2/acl.c
new file mode 100644
index 000000000000..5f959b8ce406
--- /dev/null
+++ b/fs/gfs2/acl.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "trans.h"
+#include "util.h"
+
+#define ACL_ACCESS 1
+#define ACL_DEFAULT 0
+
+int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
+ struct gfs2_ea_request *er,
+ int *remove, mode_t *mode)
+{
+ struct posix_acl *acl;
+ int error;
+
+ error = gfs2_acl_validate_remove(ip, access);
+ if (error)
+ return error;
+
+ if (!er->er_data)
+ return -EINVAL;
+
+ acl = posix_acl_from_xattr(er->er_data, er->er_data_len);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (!acl) {
+ *remove = 1;
+ return 0;
+ }
+
+ error = posix_acl_valid(acl);
+ if (error)
+ goto out;
+
+ if (access) {
+ error = posix_acl_equiv_mode(acl, mode);
+ if (!error)
+ *remove = 1;
+ else if (error > 0)
+ error = 0;
+ }
+
+out:
+ posix_acl_release(acl);
+ return error;
+}
+
+int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access)
+{
+ if (!GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl)
+ return -EOPNOTSUPP;
+ if (current->fsuid != ip->i_di.di_uid && !capable(CAP_FOWNER))
+ return -EPERM;
+ if (S_ISLNK(ip->i_di.di_mode))
+ return -EOPNOTSUPP;
+ if (!access && !S_ISDIR(ip->i_di.di_mode))
+ return -EACCES;
+
+ return 0;
+}
+
+static int acl_get(struct gfs2_inode *ip, int access, struct posix_acl **acl,
+ struct gfs2_ea_location *el, char **data, unsigned int *len)
+{
+ struct gfs2_ea_request er;
+ struct gfs2_ea_location el_this;
+ int error;
+
+ if (!ip->i_di.di_eattr)
+ return 0;
+
+ memset(&er, 0, sizeof(struct gfs2_ea_request));
+ if (access) {
+ er.er_name = GFS2_POSIX_ACL_ACCESS;
+ er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
+ } else {
+ er.er_name = GFS2_POSIX_ACL_DEFAULT;
+ er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
+ }
+ er.er_type = GFS2_EATYPE_SYS;
+
+ if (!el)
+ el = &el_this;
+
+ error = gfs2_ea_find(ip, &er, el);
+ if (error)
+ return error;
+ if (!el->el_ea)
+ return 0;
+ if (!GFS2_EA_DATA_LEN(el->el_ea))
+ goto out;
+
+ er.er_data_len = GFS2_EA_DATA_LEN(el->el_ea);
+ er.er_data = kmalloc(er.er_data_len, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!er.er_data)
+ goto out;
+
+ error = gfs2_ea_get_copy(ip, el, er.er_data);
+ if (error)
+ goto out_kfree;
+
+ if (acl) {
+ *acl = posix_acl_from_xattr(er.er_data, er.er_data_len);
+ if (IS_ERR(*acl))
+ error = PTR_ERR(*acl);
+ }
+
+out_kfree:
+ if (error || !data)
+ kfree(er.er_data);
+ else {
+ *data = er.er_data;
+ *len = er.er_data_len;
+ }
+out:
+ if (error || el == &el_this)
+ brelse(el->el_bh);
+ return error;
+}
+
+/**
+ * gfs2_check_acl_locked - Check an ACL to see if we're allowed to do something
+ * @inode: the file we want to do something to
+ * @mask: what we want to do
+ *
+ * Returns: errno
+ */
+
+int gfs2_check_acl_locked(struct inode *inode, int mask)
+{
+ struct posix_acl *acl = NULL;
+ int error;
+
+ error = acl_get(GFS2_I(inode), ACL_ACCESS, &acl, NULL, NULL, NULL);
+ if (error)
+ return error;
+
+ if (acl) {
+ error = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return error;
+ }
+
+ return -EAGAIN;
+}
+
+int gfs2_check_acl(struct inode *inode, int mask)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder i_gh;
+ int error;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+ if (!error) {
+ error = gfs2_check_acl_locked(inode, mask);
+ gfs2_glock_dq_uninit(&i_gh);
+ }
+
+ return error;
+}
+
+static int munge_mode(struct gfs2_inode *ip, mode_t mode)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ if (error)
+ return error;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ gfs2_assert_withdraw(sdp,
+ (ip->i_di.di_mode & S_IFMT) == (mode & S_IFMT));
+ ip->i_di.di_mode = mode;
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(sdp);
+
+ return 0;
+}
+
+int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct posix_acl *acl = NULL, *clone;
+ struct gfs2_ea_request er;
+ mode_t mode = ip->i_di.di_mode;
+ int error;
+
+ if (!sdp->sd_args.ar_posix_acl)
+ return 0;
+ if (S_ISLNK(ip->i_di.di_mode))
+ return 0;
+
+ memset(&er, 0, sizeof(struct gfs2_ea_request));
+ er.er_type = GFS2_EATYPE_SYS;
+
+ error = acl_get(dip, ACL_DEFAULT, &acl, NULL,
+ &er.er_data, &er.er_data_len);
+ if (error)
+ return error;
+ if (!acl) {
+ mode &= ~current->fs->umask;
+ if (mode != ip->i_di.di_mode)
+ error = munge_mode(ip, mode);
+ return error;
+ }
+
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!clone)
+ goto out;
+ posix_acl_release(acl);
+ acl = clone;
+
+ if (S_ISDIR(ip->i_di.di_mode)) {
+ er.er_name = GFS2_POSIX_ACL_DEFAULT;
+ er.er_name_len = GFS2_POSIX_ACL_DEFAULT_LEN;
+ error = gfs2_system_eaops.eo_set(ip, &er);
+ if (error)
+ goto out;
+ }
+
+ error = posix_acl_create_masq(acl, &mode);
+ if (error < 0)
+ goto out;
+ if (error > 0) {
+ er.er_name = GFS2_POSIX_ACL_ACCESS;
+ er.er_name_len = GFS2_POSIX_ACL_ACCESS_LEN;
+ posix_acl_to_xattr(acl, er.er_data, er.er_data_len);
+ er.er_mode = mode;
+ er.er_flags = GFS2_ERF_MODE;
+ error = gfs2_system_eaops.eo_set(ip, &er);
+ if (error)
+ goto out;
+ } else
+ munge_mode(ip, mode);
+
+out:
+ posix_acl_release(acl);
+ kfree(er.er_data);
+ return error;
+}
+
+int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
+{
+ struct posix_acl *acl = NULL, *clone;
+ struct gfs2_ea_location el;
+ char *data;
+ unsigned int len;
+ int error;
+
+ error = acl_get(ip, ACL_ACCESS, &acl, &el, &data, &len);
+ if (error)
+ return error;
+ if (!acl)
+ return gfs2_setattr_simple(ip, attr);
+
+ clone = posix_acl_clone(acl, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!clone)
+ goto out;
+ posix_acl_release(acl);
+ acl = clone;
+
+ error = posix_acl_chmod_masq(acl, attr->ia_mode);
+ if (!error) {
+ posix_acl_to_xattr(acl, data, len);
+ error = gfs2_ea_acl_chmod(ip, &el, attr, data);
+ }
+
+out:
+ posix_acl_release(acl);
+ brelse(el.el_bh);
+ kfree(data);
+ return error;
+}
+
diff --git a/fs/gfs2/acl.h b/fs/gfs2/acl.h
new file mode 100644
index 000000000000..05c294fe0d78
--- /dev/null
+++ b/fs/gfs2/acl.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __ACL_DOT_H__
+#define __ACL_DOT_H__
+
+#include "incore.h"
+
+#define GFS2_POSIX_ACL_ACCESS "posix_acl_access"
+#define GFS2_POSIX_ACL_ACCESS_LEN 16
+#define GFS2_POSIX_ACL_DEFAULT "posix_acl_default"
+#define GFS2_POSIX_ACL_DEFAULT_LEN 17
+
+#define GFS2_ACL_IS_ACCESS(name, len) \
+ ((len) == GFS2_POSIX_ACL_ACCESS_LEN && \
+ !memcmp(GFS2_POSIX_ACL_ACCESS, (name), (len)))
+
+#define GFS2_ACL_IS_DEFAULT(name, len) \
+ ((len) == GFS2_POSIX_ACL_DEFAULT_LEN && \
+ !memcmp(GFS2_POSIX_ACL_DEFAULT, (name), (len)))
+
+struct gfs2_ea_request;
+
+int gfs2_acl_validate_set(struct gfs2_inode *ip, int access,
+ struct gfs2_ea_request *er,
+ int *remove, mode_t *mode);
+int gfs2_acl_validate_remove(struct gfs2_inode *ip, int access);
+int gfs2_check_acl_locked(struct inode *inode, int mask);
+int gfs2_check_acl(struct inode *inode, int mask);
+int gfs2_acl_create(struct gfs2_inode *dip, struct gfs2_inode *ip);
+int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
+
+#endif /* __ACL_DOT_H__ */
diff --git a/fs/gfs2/bmap.c b/fs/gfs2/bmap.c
new file mode 100644
index 000000000000..06e9a8cb45e9
--- /dev/null
+++ b/fs/gfs2/bmap.c
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "dir.h"
+#include "util.h"
+#include "ops_address.h"
+
+/* This doesn't need to be that large as max 64 bit pointers in a 4k
+ * block is 512, so __u16 is fine for that. It saves stack space to
+ * keep it small.
+ */
+struct metapath {
+ __u16 mp_list[GFS2_MAX_META_HEIGHT];
+};
+
+typedef int (*block_call_t) (struct gfs2_inode *ip, struct buffer_head *dibh,
+ struct buffer_head *bh, u64 *top,
+ u64 *bottom, unsigned int height,
+ void *data);
+
+struct strip_mine {
+ int sm_first;
+ unsigned int sm_height;
+};
+
+/**
+ * gfs2_unstuffer_page - unstuff a stuffed inode into a block cached by a page
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @block: the block number that was allocated
+ * @private: any locked page held by the caller process
+ *
+ * Returns: errno
+ */
+
+static int gfs2_unstuffer_page(struct gfs2_inode *ip, struct buffer_head *dibh,
+ u64 block, struct page *page)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct inode *inode = &ip->i_inode;
+ struct buffer_head *bh;
+ int release = 0;
+
+ if (!page || page->index) {
+ page = grab_cache_page(inode->i_mapping, 0);
+ if (!page)
+ return -ENOMEM;
+ release = 1;
+ }
+
+ if (!PageUptodate(page)) {
+ void *kaddr = kmap(page);
+
+ memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
+ ip->i_di.di_size);
+ memset(kaddr + ip->i_di.di_size, 0,
+ PAGE_CACHE_SIZE - ip->i_di.di_size);
+ kunmap(page);
+
+ SetPageUptodate(page);
+ }
+
+ if (!page_has_buffers(page))
+ create_empty_buffers(page, 1 << inode->i_blkbits,
+ (1 << BH_Uptodate));
+
+ bh = page_buffers(page);
+
+ if (!buffer_mapped(bh))
+ map_bh(bh, inode->i_sb, block);
+
+ set_buffer_uptodate(bh);
+ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+ gfs2_trans_add_bh(ip->i_gl, bh, 0);
+ mark_buffer_dirty(bh);
+
+ if (release) {
+ unlock_page(page);
+ page_cache_release(page);
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_unstuff_dinode - Unstuff a dinode when the data has grown too big
+ * @ip: The GFS2 inode to unstuff
+ * @unstuffer: the routine that handles unstuffing a non-zero length file
+ * @private: private data for the unstuffer
+ *
+ * This routine unstuffs a dinode and returns it to a "normal" state such
+ * that the height can be grown in the traditional way.
+ *
+ * Returns: errno
+ */
+
+int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page)
+{
+ struct buffer_head *bh, *dibh;
+ struct gfs2_dinode *di;
+ u64 block = 0;
+ int isdir = gfs2_is_dir(ip);
+ int error;
+
+ down_write(&ip->i_rw_mutex);
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out;
+
+ if (ip->i_di.di_size) {
+ /* Get a free block, fill it with the stuffed data,
+ and write it out to disk */
+
+ if (isdir) {
+ block = gfs2_alloc_meta(ip);
+
+ error = gfs2_dir_get_new_buffer(ip, block, &bh);
+ if (error)
+ goto out_brelse;
+ gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_meta_header),
+ dibh, sizeof(struct gfs2_dinode));
+ brelse(bh);
+ } else {
+ block = gfs2_alloc_data(ip);
+
+ error = gfs2_unstuffer_page(ip, dibh, block, page);
+ if (error)
+ goto out_brelse;
+ }
+ }
+
+ /* Set up the pointer to the new block */
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ di = (struct gfs2_dinode *)dibh->b_data;
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+
+ if (ip->i_di.di_size) {
+ *(__be64 *)(di + 1) = cpu_to_be64(block);
+ ip->i_di.di_blocks++;
+ di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
+ }
+
+ ip->i_di.di_height = 1;
+ di->di_height = cpu_to_be16(1);
+
+out_brelse:
+ brelse(dibh);
+out:
+ up_write(&ip->i_rw_mutex);
+ return error;
+}
+
+/**
+ * calc_tree_height - Calculate the height of a metadata tree
+ * @ip: The GFS2 inode
+ * @size: The proposed size of the file
+ *
+ * Work out how tall a metadata tree needs to be in order to accommodate a
+ * file of a particular size. If size is less than the current size of
+ * the inode, then the current size of the inode is used instead of the
+ * supplied one.
+ *
+ * Returns: the height the tree should be
+ */
+
+static unsigned int calc_tree_height(struct gfs2_inode *ip, u64 size)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ u64 *arr;
+ unsigned int max, height;
+
+ if (ip->i_di.di_size > size)
+ size = ip->i_di.di_size;
+
+ if (gfs2_is_dir(ip)) {
+ arr = sdp->sd_jheightsize;
+ max = sdp->sd_max_jheight;
+ } else {
+ arr = sdp->sd_heightsize;
+ max = sdp->sd_max_height;
+ }
+
+ for (height = 0; height < max; height++)
+ if (arr[height] >= size)
+ break;
+
+ return height;
+}
+
+/**
+ * build_height - Build a metadata tree of the requested height
+ * @ip: The GFS2 inode
+ * @height: The height to build to
+ *
+ *
+ * Returns: errno
+ */
+
+static int build_height(struct inode *inode, unsigned height)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ unsigned new_height = height - ip->i_di.di_height;
+ struct buffer_head *dibh;
+ struct buffer_head *blocks[GFS2_MAX_META_HEIGHT];
+ struct gfs2_dinode *di;
+ int error;
+ u64 *bp;
+ u64 bn;
+ unsigned n;
+
+ if (height <= ip->i_di.di_height)
+ return 0;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ return error;
+
+ for(n = 0; n < new_height; n++) {
+ bn = gfs2_alloc_meta(ip);
+ blocks[n] = gfs2_meta_new(ip->i_gl, bn);
+ gfs2_trans_add_bh(ip->i_gl, blocks[n], 1);
+ }
+
+ n = 0;
+ bn = blocks[0]->b_blocknr;
+ if (new_height > 1) {
+ for(; n < new_height-1; n++) {
+ gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN,
+ GFS2_FORMAT_IN);
+ gfs2_buffer_clear_tail(blocks[n],
+ sizeof(struct gfs2_meta_header));
+ bp = (u64 *)(blocks[n]->b_data +
+ sizeof(struct gfs2_meta_header));
+ *bp = cpu_to_be64(blocks[n+1]->b_blocknr);
+ brelse(blocks[n]);
+ blocks[n] = NULL;
+ }
+ }
+ gfs2_metatype_set(blocks[n], GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+ gfs2_buffer_copy_tail(blocks[n], sizeof(struct gfs2_meta_header),
+ dibh, sizeof(struct gfs2_dinode));
+ brelse(blocks[n]);
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ di = (struct gfs2_dinode *)dibh->b_data;
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+ *(__be64 *)(di + 1) = cpu_to_be64(bn);
+ ip->i_di.di_height += new_height;
+ ip->i_di.di_blocks += new_height;
+ di->di_height = cpu_to_be16(ip->i_di.di_height);
+ di->di_blocks = cpu_to_be64(ip->i_di.di_blocks);
+ brelse(dibh);
+ return error;
+}
+
+/**
+ * find_metapath - Find path through the metadata tree
+ * @ip: The inode pointer
+ * @mp: The metapath to return the result in
+ * @block: The disk block to look up
+ *
+ * This routine returns a struct metapath structure that defines a path
+ * through the metadata of inode "ip" to get to block "block".
+ *
+ * Example:
+ * Given: "ip" is a height 3 file, "offset" is 101342453, and this is a
+ * filesystem with a blocksize of 4096.
+ *
+ * find_metapath() would return a struct metapath structure set to:
+ * mp_offset = 101342453, mp_height = 3, mp_list[0] = 0, mp_list[1] = 48,
+ * and mp_list[2] = 165.
+ *
+ * That means that in order to get to the block containing the byte at
+ * offset 101342453, we would load the indirect block pointed to by pointer
+ * 0 in the dinode. We would then load the indirect block pointed to by
+ * pointer 48 in that indirect block. We would then load the data block
+ * pointed to by pointer 165 in that indirect block.
+ *
+ * ----------------------------------------
+ * | Dinode | |
+ * | | 4|
+ * | |0 1 2 3 4 5 9|
+ * | | 6|
+ * ----------------------------------------
+ * |
+ * |
+ * V
+ * ----------------------------------------
+ * | Indirect Block |
+ * | 5|
+ * | 4 4 4 4 4 5 5 1|
+ * |0 5 6 7 8 9 0 1 2|
+ * ----------------------------------------
+ * |
+ * |
+ * V
+ * ----------------------------------------
+ * | Indirect Block |
+ * | 1 1 1 1 1 5|
+ * | 6 6 6 6 6 1|
+ * |0 3 4 5 6 7 2|
+ * ----------------------------------------
+ * |
+ * |
+ * V
+ * ----------------------------------------
+ * | Data block containing offset |
+ * | 101342453 |
+ * | |
+ * | |
+ * ----------------------------------------
+ *
+ */
+
+static void find_metapath(struct gfs2_inode *ip, u64 block,
+ struct metapath *mp)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ u64 b = block;
+ unsigned int i;
+
+ for (i = ip->i_di.di_height; i--;)
+ mp->mp_list[i] = do_div(b, sdp->sd_inptrs);
+
+}
+
+/**
+ * metapointer - Return pointer to start of metadata in a buffer
+ * @bh: The buffer
+ * @height: The metadata height (0 = dinode)
+ * @mp: The metapath
+ *
+ * Return a pointer to the block number of the next height of the metadata
+ * tree given a buffer containing the pointer to the current height of the
+ * metadata tree.
+ */
+
+static inline u64 *metapointer(struct buffer_head *bh, int *boundary,
+ unsigned int height, const struct metapath *mp)
+{
+ unsigned int head_size = (height > 0) ?
+ sizeof(struct gfs2_meta_header) : sizeof(struct gfs2_dinode);
+ u64 *ptr;
+ *boundary = 0;
+ ptr = ((u64 *)(bh->b_data + head_size)) + mp->mp_list[height];
+ if (ptr + 1 == (u64 *)(bh->b_data + bh->b_size))
+ *boundary = 1;
+ return ptr;
+}
+
+/**
+ * lookup_block - Get the next metadata block in metadata tree
+ * @ip: The GFS2 inode
+ * @bh: Buffer containing the pointers to metadata blocks
+ * @height: The height of the tree (0 = dinode)
+ * @mp: The metapath
+ * @create: Non-zero if we may create a new meatdata block
+ * @new: Used to indicate if we did create a new metadata block
+ * @block: the returned disk block number
+ *
+ * Given a metatree, complete to a particular height, checks to see if the next
+ * height of the tree exists. If not the next height of the tree is created.
+ * The block number of the next height of the metadata tree is returned.
+ *
+ */
+
+static int lookup_block(struct gfs2_inode *ip, struct buffer_head *bh,
+ unsigned int height, struct metapath *mp, int create,
+ int *new, u64 *block)
+{
+ int boundary;
+ u64 *ptr = metapointer(bh, &boundary, height, mp);
+
+ if (*ptr) {
+ *block = be64_to_cpu(*ptr);
+ return boundary;
+ }
+
+ *block = 0;
+
+ if (!create)
+ return 0;
+
+ if (height == ip->i_di.di_height - 1 && !gfs2_is_dir(ip))
+ *block = gfs2_alloc_data(ip);
+ else
+ *block = gfs2_alloc_meta(ip);
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+ *ptr = cpu_to_be64(*block);
+ ip->i_di.di_blocks++;
+
+ *new = 1;
+ return 0;
+}
+
+/**
+ * gfs2_block_pointers - Map a block from an inode to a disk block
+ * @inode: The inode
+ * @lblock: The logical block number
+ * @map_bh: The bh to be mapped
+ * @mp: metapath to use
+ *
+ * Find the block number on the current device which corresponds to an
+ * inode's block. If the block had to be created, "new" will be set.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_block_pointers(struct inode *inode, u64 lblock, int create,
+ struct buffer_head *bh_map, struct metapath *mp)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct buffer_head *bh;
+ unsigned int bsize;
+ unsigned int height;
+ unsigned int end_of_metadata;
+ unsigned int x;
+ int error = 0;
+ int new = 0;
+ u64 dblock = 0;
+ int boundary;
+ unsigned int maxlen = bh_map->b_size >> inode->i_blkbits;
+
+ BUG_ON(maxlen == 0);
+
+ if (gfs2_assert_warn(sdp, !gfs2_is_stuffed(ip)))
+ return 0;
+
+ bsize = gfs2_is_dir(ip) ? sdp->sd_jbsize : sdp->sd_sb.sb_bsize;
+
+ height = calc_tree_height(ip, (lblock + 1) * bsize);
+ if (ip->i_di.di_height < height) {
+ if (!create)
+ return 0;
+
+ error = build_height(inode, height);
+ if (error)
+ return error;
+ }
+
+ find_metapath(ip, lblock, mp);
+ end_of_metadata = ip->i_di.di_height - 1;
+
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error)
+ return error;
+
+ for (x = 0; x < end_of_metadata; x++) {
+ lookup_block(ip, bh, x, mp, create, &new, &dblock);
+ brelse(bh);
+ if (!dblock)
+ return 0;
+
+ error = gfs2_meta_indirect_buffer(ip, x+1, dblock, new, &bh);
+ if (error)
+ return error;
+ }
+
+ boundary = lookup_block(ip, bh, end_of_metadata, mp, create, &new, &dblock);
+ clear_buffer_mapped(bh_map);
+ clear_buffer_new(bh_map);
+ clear_buffer_boundary(bh_map);
+
+ if (dblock) {
+ map_bh(bh_map, inode->i_sb, dblock);
+ if (boundary)
+ set_buffer_boundary(bh);
+ if (new) {
+ struct buffer_head *dibh;
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+ set_buffer_new(bh_map);
+ goto out_brelse;
+ }
+ while(--maxlen && !buffer_boundary(bh_map)) {
+ u64 eblock;
+
+ mp->mp_list[end_of_metadata]++;
+ boundary = lookup_block(ip, bh, end_of_metadata, mp, 0, &new, &eblock);
+ if (eblock != ++dblock)
+ break;
+ bh_map->b_size += (1 << inode->i_blkbits);
+ if (boundary)
+ set_buffer_boundary(bh_map);
+ }
+ }
+out_brelse:
+ brelse(bh);
+ return 0;
+}
+
+
+static inline void bmap_lock(struct inode *inode, int create)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ if (create)
+ down_write(&ip->i_rw_mutex);
+ else
+ down_read(&ip->i_rw_mutex);
+}
+
+static inline void bmap_unlock(struct inode *inode, int create)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ if (create)
+ up_write(&ip->i_rw_mutex);
+ else
+ up_read(&ip->i_rw_mutex);
+}
+
+int gfs2_block_map(struct inode *inode, u64 lblock, int create,
+ struct buffer_head *bh)
+{
+ struct metapath mp;
+ int ret;
+
+ bmap_lock(inode, create);
+ ret = gfs2_block_pointers(inode, lblock, create, bh, &mp);
+ bmap_unlock(inode, create);
+ return ret;
+}
+
+int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen)
+{
+ struct metapath mp;
+ struct buffer_head bh = { .b_state = 0, .b_blocknr = 0 };
+ int ret;
+ int create = *new;
+
+ BUG_ON(!extlen);
+ BUG_ON(!dblock);
+ BUG_ON(!new);
+
+ bh.b_size = 1 << (inode->i_blkbits + 5);
+ bmap_lock(inode, create);
+ ret = gfs2_block_pointers(inode, lblock, create, &bh, &mp);
+ bmap_unlock(inode, create);
+ *extlen = bh.b_size >> inode->i_blkbits;
+ *dblock = bh.b_blocknr;
+ if (buffer_new(&bh))
+ *new = 1;
+ else
+ *new = 0;
+ return ret;
+}
+
+/**
+ * recursive_scan - recursively scan through the end of a file
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @mp: the path through the metadata to the point to start
+ * @height: the height the recursion is at
+ * @block: the indirect block to look at
+ * @first: 1 if this is the first block
+ * @bc: the call to make for each piece of metadata
+ * @data: data opaque to this function to pass to @bc
+ *
+ * When this is first called @height and @block should be zero and
+ * @first should be 1.
+ *
+ * Returns: errno
+ */
+
+static int recursive_scan(struct gfs2_inode *ip, struct buffer_head *dibh,
+ struct metapath *mp, unsigned int height,
+ u64 block, int first, block_call_t bc,
+ void *data)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head *bh = NULL;
+ u64 *top, *bottom;
+ u64 bn;
+ int error;
+ int mh_size = sizeof(struct gfs2_meta_header);
+
+ if (!height) {
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error)
+ return error;
+ dibh = bh;
+
+ top = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + mp->mp_list[0];
+ bottom = (u64 *)(bh->b_data + sizeof(struct gfs2_dinode)) + sdp->sd_diptrs;
+ } else {
+ error = gfs2_meta_indirect_buffer(ip, height, block, 0, &bh);
+ if (error)
+ return error;
+
+ top = (u64 *)(bh->b_data + mh_size) +
+ (first ? mp->mp_list[height] : 0);
+
+ bottom = (u64 *)(bh->b_data + mh_size) + sdp->sd_inptrs;
+ }
+
+ error = bc(ip, dibh, bh, top, bottom, height, data);
+ if (error)
+ goto out;
+
+ if (height < ip->i_di.di_height - 1)
+ for (; top < bottom; top++, first = 0) {
+ if (!*top)
+ continue;
+
+ bn = be64_to_cpu(*top);
+
+ error = recursive_scan(ip, dibh, mp, height + 1, bn,
+ first, bc, data);
+ if (error)
+ break;
+ }
+
+out:
+ brelse(bh);
+ return error;
+}
+
+/**
+ * do_strip - Look for a layer a particular layer of the file and strip it off
+ * @ip: the inode
+ * @dibh: the dinode buffer
+ * @bh: A buffer of pointers
+ * @top: The first pointer in the buffer
+ * @bottom: One more than the last pointer
+ * @height: the height this buffer is at
+ * @data: a pointer to a struct strip_mine
+ *
+ * Returns: errno
+ */
+
+static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
+ struct buffer_head *bh, u64 *top, u64 *bottom,
+ unsigned int height, void *data)
+{
+ struct strip_mine *sm = data;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_rgrp_list rlist;
+ u64 bn, bstart;
+ u32 blen;
+ u64 *p;
+ unsigned int rg_blocks = 0;
+ int metadata;
+ unsigned int revokes = 0;
+ int x;
+ int error;
+
+ if (!*top)
+ sm->sm_first = 0;
+
+ if (height != sm->sm_height)
+ return 0;
+
+ if (sm->sm_first) {
+ top++;
+ sm->sm_first = 0;
+ }
+
+ metadata = (height != ip->i_di.di_height - 1);
+ if (metadata)
+ revokes = (height) ? sdp->sd_inptrs : sdp->sd_diptrs;
+
+ error = gfs2_rindex_hold(sdp, &ip->i_alloc.al_ri_gh);
+ if (error)
+ return error;
+
+ memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
+ bstart = 0;
+ blen = 0;
+
+ for (p = top; p < bottom; p++) {
+ if (!*p)
+ continue;
+
+ bn = be64_to_cpu(*p);
+
+ if (bstart + blen == bn)
+ blen++;
+ else {
+ if (bstart)
+ gfs2_rlist_add(sdp, &rlist, bstart);
+
+ bstart = bn;
+ blen = 1;
+ }
+ }
+
+ if (bstart)
+ gfs2_rlist_add(sdp, &rlist, bstart);
+ else
+ goto out; /* Nothing to do */
+
+ gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
+
+ for (x = 0; x < rlist.rl_rgrps; x++) {
+ struct gfs2_rgrpd *rgd;
+ rgd = rlist.rl_ghs[x].gh_gl->gl_object;
+ rg_blocks += rgd->rd_ri.ri_length;
+ }
+
+ error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
+ if (error)
+ goto out_rlist;
+
+ error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE +
+ RES_INDIRECT + RES_STATFS + RES_QUOTA,
+ revokes);
+ if (error)
+ goto out_rg_gunlock;
+
+ down_write(&ip->i_rw_mutex);
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+ bstart = 0;
+ blen = 0;
+
+ for (p = top; p < bottom; p++) {
+ if (!*p)
+ continue;
+
+ bn = be64_to_cpu(*p);
+
+ if (bstart + blen == bn)
+ blen++;
+ else {
+ if (bstart) {
+ if (metadata)
+ gfs2_free_meta(ip, bstart, blen);
+ else
+ gfs2_free_data(ip, bstart, blen);
+ }
+
+ bstart = bn;
+ blen = 1;
+ }
+
+ *p = 0;
+ if (!ip->i_di.di_blocks)
+ gfs2_consist_inode(ip);
+ ip->i_di.di_blocks--;
+ }
+ if (bstart) {
+ if (metadata)
+ gfs2_free_meta(ip, bstart, blen);
+ else
+ gfs2_free_data(ip, bstart, blen);
+ }
+
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+
+ up_write(&ip->i_rw_mutex);
+
+ gfs2_trans_end(sdp);
+
+out_rg_gunlock:
+ gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
+out_rlist:
+ gfs2_rlist_free(&rlist);
+out:
+ gfs2_glock_dq_uninit(&ip->i_alloc.al_ri_gh);
+ return error;
+}
+
+/**
+ * do_grow - Make a file look bigger than it is
+ * @ip: the inode
+ * @size: the size to set the file to
+ *
+ * Called with an exclusive lock on @ip.
+ *
+ * Returns: errno
+ */
+
+static int do_grow(struct gfs2_inode *ip, u64 size)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al;
+ struct buffer_head *dibh;
+ unsigned int h;
+ int error;
+
+ al = gfs2_alloc_get(ip);
+
+ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out;
+
+ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+ if (error)
+ goto out_gunlock_q;
+
+ al->al_requested = sdp->sd_max_height + RES_DATA;
+
+ error = gfs2_inplace_reserve(ip);
+ if (error)
+ goto out_gunlock_q;
+
+ error = gfs2_trans_begin(sdp,
+ sdp->sd_max_height + al->al_rgd->rd_ri.ri_length +
+ RES_JDATA + RES_DINODE + RES_STATFS + RES_QUOTA, 0);
+ if (error)
+ goto out_ipres;
+
+ if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
+ if (gfs2_is_stuffed(ip)) {
+ error = gfs2_unstuff_dinode(ip, NULL);
+ if (error)
+ goto out_end_trans;
+ }
+
+ h = calc_tree_height(ip, size);
+ if (ip->i_di.di_height < h) {
+ down_write(&ip->i_rw_mutex);
+ error = build_height(&ip->i_inode, h);
+ up_write(&ip->i_rw_mutex);
+ if (error)
+ goto out_end_trans;
+ }
+ }
+
+ ip->i_di.di_size = size;
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out_end_trans;
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+
+out_end_trans:
+ gfs2_trans_end(sdp);
+out_ipres:
+ gfs2_inplace_release(ip);
+out_gunlock_q:
+ gfs2_quota_unlock(ip);
+out:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
+
+/**
+ * gfs2_block_truncate_page - Deal with zeroing out data for truncate
+ *
+ * This is partly borrowed from ext3.
+ */
+static int gfs2_block_truncate_page(struct address_space *mapping)
+{
+ struct inode *inode = mapping->host;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ loff_t from = inode->i_size;
+ unsigned long index = from >> PAGE_CACHE_SHIFT;
+ unsigned offset = from & (PAGE_CACHE_SIZE-1);
+ unsigned blocksize, iblock, length, pos;
+ struct buffer_head *bh;
+ struct page *page;
+ void *kaddr;
+ int err;
+
+ page = grab_cache_page(mapping, index);
+ if (!page)
+ return 0;
+
+ blocksize = inode->i_sb->s_blocksize;
+ length = blocksize - (offset & (blocksize - 1));
+ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+
+ if (!page_has_buffers(page))
+ create_empty_buffers(page, blocksize, 0);
+
+ /* Find the buffer that contains "offset" */
+ bh = page_buffers(page);
+ pos = blocksize;
+ while (offset >= pos) {
+ bh = bh->b_this_page;
+ iblock++;
+ pos += blocksize;
+ }
+
+ err = 0;
+
+ if (!buffer_mapped(bh)) {
+ gfs2_get_block(inode, iblock, bh, 0);
+ /* unmapped? It's a hole - nothing to do */
+ if (!buffer_mapped(bh))
+ goto unlock;
+ }
+
+ /* Ok, it's mapped. Make sure it's up-to-date */
+ if (PageUptodate(page))
+ set_buffer_uptodate(bh);
+
+ if (!buffer_uptodate(bh)) {
+ err = -EIO;
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ /* Uhhuh. Read error. Complain and punt. */
+ if (!buffer_uptodate(bh))
+ goto unlock;
+ }
+
+ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip))
+ gfs2_trans_add_bh(ip->i_gl, bh, 0);
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, length);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+
+unlock:
+ unlock_page(page);
+ page_cache_release(page);
+ return err;
+}
+
+static int trunc_start(struct gfs2_inode *ip, u64 size)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head *dibh;
+ int journaled = gfs2_is_jdata(ip);
+ int error;
+
+ error = gfs2_trans_begin(sdp,
+ RES_DINODE + (journaled ? RES_JDATA : 0), 0);
+ if (error)
+ return error;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out;
+
+ if (gfs2_is_stuffed(ip)) {
+ ip->i_di.di_size = size;
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);
+ error = 1;
+
+ } else {
+ if (size & (u64)(sdp->sd_sb.sb_bsize - 1))
+ error = gfs2_block_truncate_page(ip->i_inode.i_mapping);
+
+ if (!error) {
+ ip->i_di.di_size = size;
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+ ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG;
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ }
+ }
+
+ brelse(dibh);
+
+out:
+ gfs2_trans_end(sdp);
+ return error;
+}
+
+static int trunc_dealloc(struct gfs2_inode *ip, u64 size)
+{
+ unsigned int height = ip->i_di.di_height;
+ u64 lblock;
+ struct metapath mp;
+ int error;
+
+ if (!size)
+ lblock = 0;
+ else
+ lblock = (size - 1) >> GFS2_SB(&ip->i_inode)->sd_sb.sb_bsize_shift;
+
+ find_metapath(ip, lblock, &mp);
+ gfs2_alloc_get(ip);
+
+ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out;
+
+ while (height--) {
+ struct strip_mine sm;
+ sm.sm_first = !!size;
+ sm.sm_height = height;
+
+ error = recursive_scan(ip, NULL, &mp, 0, 0, 1, do_strip, &sm);
+ if (error)
+ break;
+ }
+
+ gfs2_quota_unhold(ip);
+
+out:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
+static int trunc_end(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ if (error)
+ return error;
+
+ down_write(&ip->i_rw_mutex);
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out;
+
+ if (!ip->i_di.di_size) {
+ ip->i_di.di_height = 0;
+ ip->i_di.di_goal_meta =
+ ip->i_di.di_goal_data =
+ ip->i_num.no_addr;
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+ }
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+ ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG;
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+
+out:
+ up_write(&ip->i_rw_mutex);
+ gfs2_trans_end(sdp);
+ return error;
+}
+
+/**
+ * do_shrink - make a file smaller
+ * @ip: the inode
+ * @size: the size to make the file
+ * @truncator: function to truncate the last partial block
+ *
+ * Called with an exclusive lock on @ip.
+ *
+ * Returns: errno
+ */
+
+static int do_shrink(struct gfs2_inode *ip, u64 size)
+{
+ int error;
+
+ error = trunc_start(ip, size);
+ if (error < 0)
+ return error;
+ if (error > 0)
+ return 0;
+
+ error = trunc_dealloc(ip, size);
+ if (!error)
+ error = trunc_end(ip);
+
+ return error;
+}
+
+/**
+ * gfs2_truncatei - make a file a given size
+ * @ip: the inode
+ * @size: the size to make the file
+ * @truncator: function to truncate the last partial block
+ *
+ * The file size can grow, shrink, or stay the same size.
+ *
+ * Returns: errno
+ */
+
+int gfs2_truncatei(struct gfs2_inode *ip, u64 size)
+{
+ int error;
+
+ if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), S_ISREG(ip->i_di.di_mode)))
+ return -EINVAL;
+
+ if (size > ip->i_di.di_size)
+ error = do_grow(ip, size);
+ else
+ error = do_shrink(ip, size);
+
+ return error;
+}
+
+int gfs2_truncatei_resume(struct gfs2_inode *ip)
+{
+ int error;
+ error = trunc_dealloc(ip, ip->i_di.di_size);
+ if (!error)
+ error = trunc_end(ip);
+ return error;
+}
+
+int gfs2_file_dealloc(struct gfs2_inode *ip)
+{
+ return trunc_dealloc(ip, 0);
+}
+
+/**
+ * gfs2_write_calc_reserv - calculate number of blocks needed to write to a file
+ * @ip: the file
+ * @len: the number of bytes to be written to the file
+ * @data_blocks: returns the number of data blocks required
+ * @ind_blocks: returns the number of indirect blocks required
+ *
+ */
+
+void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
+ unsigned int *data_blocks, unsigned int *ind_blocks)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ unsigned int tmp;
+
+ if (gfs2_is_dir(ip)) {
+ *data_blocks = DIV_ROUND_UP(len, sdp->sd_jbsize) + 2;
+ *ind_blocks = 3 * (sdp->sd_max_jheight - 1);
+ } else {
+ *data_blocks = (len >> sdp->sd_sb.sb_bsize_shift) + 3;
+ *ind_blocks = 3 * (sdp->sd_max_height - 1);
+ }
+
+ for (tmp = *data_blocks; tmp > sdp->sd_diptrs;) {
+ tmp = DIV_ROUND_UP(tmp, sdp->sd_inptrs);
+ *ind_blocks += tmp;
+ }
+}
+
+/**
+ * gfs2_write_alloc_required - figure out if a write will require an allocation
+ * @ip: the file being written to
+ * @offset: the offset to write to
+ * @len: the number of bytes being written
+ * @alloc_required: set to 1 if an alloc is required, 0 otherwise
+ *
+ * Returns: errno
+ */
+
+int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
+ unsigned int len, int *alloc_required)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ u64 lblock, lblock_stop, dblock;
+ u32 extlen;
+ int new = 0;
+ int error = 0;
+
+ *alloc_required = 0;
+
+ if (!len)
+ return 0;
+
+ if (gfs2_is_stuffed(ip)) {
+ if (offset + len >
+ sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
+ *alloc_required = 1;
+ return 0;
+ }
+
+ if (gfs2_is_dir(ip)) {
+ unsigned int bsize = sdp->sd_jbsize;
+ lblock = offset;
+ do_div(lblock, bsize);
+ lblock_stop = offset + len + bsize - 1;
+ do_div(lblock_stop, bsize);
+ } else {
+ unsigned int shift = sdp->sd_sb.sb_bsize_shift;
+ lblock = offset >> shift;
+ lblock_stop = (offset + len + sdp->sd_sb.sb_bsize - 1) >> shift;
+ }
+
+ for (; lblock < lblock_stop; lblock += extlen) {
+ error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
+ if (error)
+ return error;
+
+ if (!dblock) {
+ *alloc_required = 1;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/fs/gfs2/bmap.h b/fs/gfs2/bmap.h
new file mode 100644
index 000000000000..ac2fd04370dc
--- /dev/null
+++ b/fs/gfs2/bmap.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __BMAP_DOT_H__
+#define __BMAP_DOT_H__
+
+struct inode;
+struct gfs2_inode;
+struct page;
+
+int gfs2_unstuff_dinode(struct gfs2_inode *ip, struct page *page);
+int gfs2_block_map(struct inode *inode, u64 lblock, int create, struct buffer_head *bh);
+int gfs2_extent_map(struct inode *inode, u64 lblock, int *new, u64 *dblock, unsigned *extlen);
+
+int gfs2_truncatei(struct gfs2_inode *ip, u64 size);
+int gfs2_truncatei_resume(struct gfs2_inode *ip);
+int gfs2_file_dealloc(struct gfs2_inode *ip);
+
+void gfs2_write_calc_reserv(struct gfs2_inode *ip, unsigned int len,
+ unsigned int *data_blocks,
+ unsigned int *ind_blocks);
+int gfs2_write_alloc_required(struct gfs2_inode *ip, u64 offset,
+ unsigned int len, int *alloc_required);
+
+#endif /* __BMAP_DOT_H__ */
diff --git a/fs/gfs2/daemon.c b/fs/gfs2/daemon.c
new file mode 100644
index 000000000000..cab1f68d4685
--- /dev/null
+++ b/fs/gfs2/daemon.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "daemon.h"
+#include "glock.h"
+#include "log.h"
+#include "quota.h"
+#include "recovery.h"
+#include "super.h"
+#include "util.h"
+
+/* This uses schedule_timeout() instead of msleep() because it's good for
+ the daemons to wake up more often than the timeout when unmounting so
+ the user's unmount doesn't sit there forever.
+
+ The kthread functions used to start these daemons block and flush signals. */
+
+/**
+ * gfs2_scand - Look for cached glocks and inodes to toss from memory
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One of these daemons runs, finding candidates to add to sd_reclaim_list.
+ * See gfs2_glockd()
+ */
+
+int gfs2_scand(void *data)
+{
+ struct gfs2_sbd *sdp = data;
+ unsigned long t;
+
+ while (!kthread_should_stop()) {
+ gfs2_scand_internal(sdp);
+ t = gfs2_tune_get(sdp, gt_scand_secs) * HZ;
+ schedule_timeout_interruptible(t);
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_glockd - Reclaim unused glock structures
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * One or more of these daemons run, reclaiming glocks on sd_reclaim_list.
+ * Number of daemons can be set by user, with num_glockd mount option.
+ */
+
+int gfs2_glockd(void *data)
+{
+ struct gfs2_sbd *sdp = data;
+
+ while (!kthread_should_stop()) {
+ while (atomic_read(&sdp->sd_reclaim_count))
+ gfs2_reclaim_glock(sdp);
+
+ wait_event_interruptible(sdp->sd_reclaim_wq,
+ (atomic_read(&sdp->sd_reclaim_count) ||
+ kthread_should_stop()));
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_recoverd - Recover dead machine's journals
+ * @sdp: Pointer to GFS2 superblock
+ *
+ */
+
+int gfs2_recoverd(void *data)
+{
+ struct gfs2_sbd *sdp = data;
+ unsigned long t;
+
+ while (!kthread_should_stop()) {
+ gfs2_check_journals(sdp);
+ t = gfs2_tune_get(sdp, gt_recoverd_secs) * HZ;
+ schedule_timeout_interruptible(t);
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_logd - Update log tail as Active Items get flushed to in-place blocks
+ * @sdp: Pointer to GFS2 superblock
+ *
+ * Also, periodically check to make sure that we're using the most recent
+ * journal index.
+ */
+
+int gfs2_logd(void *data)
+{
+ struct gfs2_sbd *sdp = data;
+ struct gfs2_holder ji_gh;
+ unsigned long t;
+
+ while (!kthread_should_stop()) {
+ /* Advance the log tail */
+
+ t = sdp->sd_log_flush_time +
+ gfs2_tune_get(sdp, gt_log_flush_secs) * HZ;
+
+ gfs2_ail1_empty(sdp, DIO_ALL);
+
+ if (time_after_eq(jiffies, t)) {
+ gfs2_log_flush(sdp, NULL);
+ sdp->sd_log_flush_time = jiffies;
+ }
+
+ /* Check for latest journal index */
+
+ t = sdp->sd_jindex_refresh_time +
+ gfs2_tune_get(sdp, gt_jindex_refresh_secs) * HZ;
+
+ if (time_after_eq(jiffies, t)) {
+ if (!gfs2_jindex_hold(sdp, &ji_gh))
+ gfs2_glock_dq_uninit(&ji_gh);
+ sdp->sd_jindex_refresh_time = jiffies;
+ }
+
+ t = gfs2_tune_get(sdp, gt_logd_secs) * HZ;
+ schedule_timeout_interruptible(t);
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_quotad - Write cached quota changes into the quota file
+ * @sdp: Pointer to GFS2 superblock
+ *
+ */
+
+int gfs2_quotad(void *data)
+{
+ struct gfs2_sbd *sdp = data;
+ unsigned long t;
+ int error;
+
+ while (!kthread_should_stop()) {
+ /* Update the master statfs file */
+
+ t = sdp->sd_statfs_sync_time +
+ gfs2_tune_get(sdp, gt_statfs_quantum) * HZ;
+
+ if (time_after_eq(jiffies, t)) {
+ error = gfs2_statfs_sync(sdp);
+ if (error &&
+ error != -EROFS &&
+ !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+ fs_err(sdp, "quotad: (1) error=%d\n", error);
+ sdp->sd_statfs_sync_time = jiffies;
+ }
+
+ /* Update quota file */
+
+ t = sdp->sd_quota_sync_time +
+ gfs2_tune_get(sdp, gt_quota_quantum) * HZ;
+
+ if (time_after_eq(jiffies, t)) {
+ error = gfs2_quota_sync(sdp);
+ if (error &&
+ error != -EROFS &&
+ !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+ fs_err(sdp, "quotad: (2) error=%d\n", error);
+ sdp->sd_quota_sync_time = jiffies;
+ }
+
+ gfs2_quota_scan(sdp);
+
+ t = gfs2_tune_get(sdp, gt_quotad_secs) * HZ;
+ schedule_timeout_interruptible(t);
+ }
+
+ return 0;
+}
+
diff --git a/fs/gfs2/daemon.h b/fs/gfs2/daemon.h
new file mode 100644
index 000000000000..801007120fb2
--- /dev/null
+++ b/fs/gfs2/daemon.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __DAEMON_DOT_H__
+#define __DAEMON_DOT_H__
+
+int gfs2_scand(void *data);
+int gfs2_glockd(void *data);
+int gfs2_recoverd(void *data);
+int gfs2_logd(void *data);
+int gfs2_quotad(void *data);
+
+#endif /* __DAEMON_DOT_H__ */
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
new file mode 100644
index 000000000000..e24af28b1a12
--- /dev/null
+++ b/fs/gfs2/dir.c
@@ -0,0 +1,1957 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+/*
+ * Implements Extendible Hashing as described in:
+ * "Extendible Hashing" by Fagin, et al in
+ * __ACM Trans. on Database Systems__, Sept 1979.
+ *
+ *
+ * Here's the layout of dirents which is essentially the same as that of ext2
+ * within a single block. The field de_name_len is the number of bytes
+ * actually required for the name (no null terminator). The field de_rec_len
+ * is the number of bytes allocated to the dirent. The offset of the next
+ * dirent in the block is (dirent + dirent->de_rec_len). When a dirent is
+ * deleted, the preceding dirent inherits its allocated space, ie
+ * prev->de_rec_len += deleted->de_rec_len. Since the next dirent is obtained
+ * by adding de_rec_len to the current dirent, this essentially causes the
+ * deleted dirent to get jumped over when iterating through all the dirents.
+ *
+ * When deleting the first dirent in a block, there is no previous dirent so
+ * the field de_ino is set to zero to designate it as deleted. When allocating
+ * a dirent, gfs2_dirent_alloc iterates through the dirents in a block. If the
+ * first dirent has (de_ino == 0) and de_rec_len is large enough, this first
+ * dirent is allocated. Otherwise it must go through all the 'used' dirents
+ * searching for one in which the amount of total space minus the amount of
+ * used space will provide enough space for the new dirent.
+ *
+ * There are two types of blocks in which dirents reside. In a stuffed dinode,
+ * the dirents begin at offset sizeof(struct gfs2_dinode) from the beginning of
+ * the block. In leaves, they begin at offset sizeof(struct gfs2_leaf) from the
+ * beginning of the leaf block. The dirents reside in leaves when
+ *
+ * dip->i_di.di_flags & GFS2_DIF_EXHASH is true
+ *
+ * Otherwise, the dirents are "linear", within a single stuffed dinode block.
+ *
+ * When the dirents are in leaves, the actual contents of the directory file are
+ * used as an array of 64-bit block pointers pointing to the leaf blocks. The
+ * dirents are NOT in the directory file itself. There can be more than one
+ * block pointer in the array that points to the same leaf. In fact, when a
+ * directory is first converted from linear to exhash, all of the pointers
+ * point to the same leaf.
+ *
+ * When a leaf is completely full, the size of the hash table can be
+ * doubled unless it is already at the maximum size which is hard coded into
+ * GFS2_DIR_MAX_DEPTH. After that, leaves are chained together in a linked list,
+ * but never before the maximum hash table size has been reached.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/buffer_head.h>
+#include <linux/sort.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/vmalloc.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "dir.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "bmap.h"
+#include "util.h"
+
+#define IS_LEAF 1 /* Hashed (leaf) directory */
+#define IS_DINODE 2 /* Linear (stuffed dinode block) directory */
+
+#define gfs2_disk_hash2offset(h) (((u64)(h)) >> 1)
+#define gfs2_dir_offset2hash(p) ((u32)(((u64)(p)) << 1))
+
+typedef int (*leaf_call_t) (struct gfs2_inode *dip, u32 index, u32 len,
+ u64 leaf_no, void *data);
+typedef int (*gfs2_dscan_t)(const struct gfs2_dirent *dent,
+ const struct qstr *name, void *opaque);
+
+
+int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
+ struct buffer_head **bhp)
+{
+ struct buffer_head *bh;
+
+ bh = gfs2_meta_new(ip->i_gl, block);
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ gfs2_metatype_set(bh, GFS2_METATYPE_JD, GFS2_FORMAT_JD);
+ gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
+ *bhp = bh;
+ return 0;
+}
+
+static int gfs2_dir_get_existing_buffer(struct gfs2_inode *ip, u64 block,
+ struct buffer_head **bhp)
+{
+ struct buffer_head *bh;
+ int error;
+
+ error = gfs2_meta_read(ip->i_gl, block, DIO_WAIT, &bh);
+ if (error)
+ return error;
+ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_JD)) {
+ brelse(bh);
+ return -EIO;
+ }
+ *bhp = bh;
+ return 0;
+}
+
+static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
+ unsigned int offset, unsigned int size)
+{
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ return error;
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
+ if (ip->i_di.di_size < offset + size)
+ ip->i_di.di_size = offset + size;
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+
+ brelse(dibh);
+
+ return size;
+}
+
+
+
+/**
+ * gfs2_dir_write_data - Write directory information to the inode
+ * @ip: The GFS2 inode
+ * @buf: The buffer containing information to be written
+ * @offset: The file offset to start writing at
+ * @size: The amount of data to write
+ *
+ * Returns: The number of bytes correctly written or error code
+ */
+static int gfs2_dir_write_data(struct gfs2_inode *ip, const char *buf,
+ u64 offset, unsigned int size)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head *dibh;
+ u64 lblock, dblock;
+ u32 extlen = 0;
+ unsigned int o;
+ int copied = 0;
+ int error = 0;
+
+ if (!size)
+ return 0;
+
+ if (gfs2_is_stuffed(ip) &&
+ offset + size <= sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode))
+ return gfs2_dir_write_stuffed(ip, buf, (unsigned int)offset,
+ size);
+
+ if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
+ return -EINVAL;
+
+ if (gfs2_is_stuffed(ip)) {
+ error = gfs2_unstuff_dinode(ip, NULL);
+ if (error)
+ return error;
+ }
+
+ lblock = offset;
+ o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
+
+ while (copied < size) {
+ unsigned int amount;
+ struct buffer_head *bh;
+ int new = 0;
+
+ amount = size - copied;
+ if (amount > sdp->sd_sb.sb_bsize - o)
+ amount = sdp->sd_sb.sb_bsize - o;
+
+ if (!extlen) {
+ new = 1;
+ error = gfs2_extent_map(&ip->i_inode, lblock, &new,
+ &dblock, &extlen);
+ if (error)
+ goto fail;
+ error = -EIO;
+ if (gfs2_assert_withdraw(sdp, dblock))
+ goto fail;
+ }
+
+ if (amount == sdp->sd_jbsize || new)
+ error = gfs2_dir_get_new_buffer(ip, dblock, &bh);
+ else
+ error = gfs2_dir_get_existing_buffer(ip, dblock, &bh);
+
+ if (error)
+ goto fail;
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ memcpy(bh->b_data + o, buf, amount);
+ brelse(bh);
+
+ buf += amount;
+ copied += amount;
+ lblock++;
+ dblock++;
+ extlen--;
+
+ o = sizeof(struct gfs2_meta_header);
+ }
+
+out:
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ return error;
+
+ if (ip->i_di.di_size < offset + copied)
+ ip->i_di.di_size = offset + copied;
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+
+ return copied;
+fail:
+ if (copied)
+ goto out;
+ return error;
+}
+
+static int gfs2_dir_read_stuffed(struct gfs2_inode *ip, char *buf,
+ u64 offset, unsigned int size)
+{
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ offset += sizeof(struct gfs2_dinode);
+ memcpy(buf, dibh->b_data + offset, size);
+ brelse(dibh);
+ }
+
+ return (error) ? error : size;
+}
+
+
+/**
+ * gfs2_dir_read_data - Read a data from a directory inode
+ * @ip: The GFS2 Inode
+ * @buf: The buffer to place result into
+ * @offset: File offset to begin jdata_readng from
+ * @size: Amount of data to transfer
+ *
+ * Returns: The amount of data actually copied or the error
+ */
+static int gfs2_dir_read_data(struct gfs2_inode *ip, char *buf, u64 offset,
+ unsigned int size, unsigned ra)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ u64 lblock, dblock;
+ u32 extlen = 0;
+ unsigned int o;
+ int copied = 0;
+ int error = 0;
+
+ if (offset >= ip->i_di.di_size)
+ return 0;
+
+ if (offset + size > ip->i_di.di_size)
+ size = ip->i_di.di_size - offset;
+
+ if (!size)
+ return 0;
+
+ if (gfs2_is_stuffed(ip))
+ return gfs2_dir_read_stuffed(ip, buf, offset, size);
+
+ if (gfs2_assert_warn(sdp, gfs2_is_jdata(ip)))
+ return -EINVAL;
+
+ lblock = offset;
+ o = do_div(lblock, sdp->sd_jbsize) + sizeof(struct gfs2_meta_header);
+
+ while (copied < size) {
+ unsigned int amount;
+ struct buffer_head *bh;
+ int new;
+
+ amount = size - copied;
+ if (amount > sdp->sd_sb.sb_bsize - o)
+ amount = sdp->sd_sb.sb_bsize - o;
+
+ if (!extlen) {
+ new = 0;
+ error = gfs2_extent_map(&ip->i_inode, lblock, &new,
+ &dblock, &extlen);
+ if (error || !dblock)
+ goto fail;
+ BUG_ON(extlen < 1);
+ if (!ra)
+ extlen = 1;
+ bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
+ } else {
+ error = gfs2_meta_read(ip->i_gl, dblock, DIO_WAIT, &bh);
+ if (error)
+ goto fail;
+ }
+ error = gfs2_metatype_check(sdp, bh, GFS2_METATYPE_JD);
+ if (error) {
+ brelse(bh);
+ goto fail;
+ }
+ dblock++;
+ extlen--;
+ memcpy(buf, bh->b_data + o, amount);
+ brelse(bh);
+ buf += amount;
+ copied += amount;
+ lblock++;
+ o = sizeof(struct gfs2_meta_header);
+ }
+
+ return copied;
+fail:
+ return (copied) ? copied : error;
+}
+
+static inline int __gfs2_dirent_find(const struct gfs2_dirent *dent,
+ const struct qstr *name, int ret)
+{
+ if (dent->de_inum.no_addr != 0 &&
+ be32_to_cpu(dent->de_hash) == name->hash &&
+ be16_to_cpu(dent->de_name_len) == name->len &&
+ memcmp(dent+1, name->name, name->len) == 0)
+ return ret;
+ return 0;
+}
+
+static int gfs2_dirent_find(const struct gfs2_dirent *dent,
+ const struct qstr *name,
+ void *opaque)
+{
+ return __gfs2_dirent_find(dent, name, 1);
+}
+
+static int gfs2_dirent_prev(const struct gfs2_dirent *dent,
+ const struct qstr *name,
+ void *opaque)
+{
+ return __gfs2_dirent_find(dent, name, 2);
+}
+
+/*
+ * name->name holds ptr to start of block.
+ * name->len holds size of block.
+ */
+static int gfs2_dirent_last(const struct gfs2_dirent *dent,
+ const struct qstr *name,
+ void *opaque)
+{
+ const char *start = name->name;
+ const char *end = (const char *)dent + be16_to_cpu(dent->de_rec_len);
+ if (name->len == (end - start))
+ return 1;
+ return 0;
+}
+
+static int gfs2_dirent_find_space(const struct gfs2_dirent *dent,
+ const struct qstr *name,
+ void *opaque)
+{
+ unsigned required = GFS2_DIRENT_SIZE(name->len);
+ unsigned actual = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
+ unsigned totlen = be16_to_cpu(dent->de_rec_len);
+
+ if (!dent->de_inum.no_addr)
+ actual = GFS2_DIRENT_SIZE(0);
+ if (totlen - actual >= required)
+ return 1;
+ return 0;
+}
+
+struct dirent_gather {
+ const struct gfs2_dirent **pdent;
+ unsigned offset;
+};
+
+static int gfs2_dirent_gather(const struct gfs2_dirent *dent,
+ const struct qstr *name,
+ void *opaque)
+{
+ struct dirent_gather *g = opaque;
+ if (dent->de_inum.no_addr) {
+ g->pdent[g->offset++] = dent;
+ }
+ return 0;
+}
+
+/*
+ * Other possible things to check:
+ * - Inode located within filesystem size (and on valid block)
+ * - Valid directory entry type
+ * Not sure how heavy-weight we want to make this... could also check
+ * hash is correct for example, but that would take a lot of extra time.
+ * For now the most important thing is to check that the various sizes
+ * are correct.
+ */
+static int gfs2_check_dirent(struct gfs2_dirent *dent, unsigned int offset,
+ unsigned int size, unsigned int len, int first)
+{
+ const char *msg = "gfs2_dirent too small";
+ if (unlikely(size < sizeof(struct gfs2_dirent)))
+ goto error;
+ msg = "gfs2_dirent misaligned";
+ if (unlikely(offset & 0x7))
+ goto error;
+ msg = "gfs2_dirent points beyond end of block";
+ if (unlikely(offset + size > len))
+ goto error;
+ msg = "zero inode number";
+ if (unlikely(!first && !dent->de_inum.no_addr))
+ goto error;
+ msg = "name length is greater than space in dirent";
+ if (dent->de_inum.no_addr &&
+ unlikely(sizeof(struct gfs2_dirent)+be16_to_cpu(dent->de_name_len) >
+ size))
+ goto error;
+ return 0;
+error:
+ printk(KERN_WARNING "gfs2_check_dirent: %s (%s)\n", msg,
+ first ? "first in block" : "not first in block");
+ return -EIO;
+}
+
+static int gfs2_dirent_offset(const void *buf)
+{
+ const struct gfs2_meta_header *h = buf;
+ int offset;
+
+ BUG_ON(buf == NULL);
+
+ switch(be32_to_cpu(h->mh_type)) {
+ case GFS2_METATYPE_LF:
+ offset = sizeof(struct gfs2_leaf);
+ break;
+ case GFS2_METATYPE_DI:
+ offset = sizeof(struct gfs2_dinode);
+ break;
+ default:
+ goto wrong_type;
+ }
+ return offset;
+wrong_type:
+ printk(KERN_WARNING "gfs2_scan_dirent: wrong block type %u\n",
+ be32_to_cpu(h->mh_type));
+ return -1;
+}
+
+static struct gfs2_dirent *gfs2_dirent_scan(struct inode *inode, void *buf,
+ unsigned int len, gfs2_dscan_t scan,
+ const struct qstr *name,
+ void *opaque)
+{
+ struct gfs2_dirent *dent, *prev;
+ unsigned offset;
+ unsigned size;
+ int ret = 0;
+
+ ret = gfs2_dirent_offset(buf);
+ if (ret < 0)
+ goto consist_inode;
+
+ offset = ret;
+ prev = NULL;
+ dent = buf + offset;
+ size = be16_to_cpu(dent->de_rec_len);
+ if (gfs2_check_dirent(dent, offset, size, len, 1))
+ goto consist_inode;
+ do {
+ ret = scan(dent, name, opaque);
+ if (ret)
+ break;
+ offset += size;
+ if (offset == len)
+ break;
+ prev = dent;
+ dent = buf + offset;
+ size = be16_to_cpu(dent->de_rec_len);
+ if (gfs2_check_dirent(dent, offset, size, len, 0))
+ goto consist_inode;
+ } while(1);
+
+ switch(ret) {
+ case 0:
+ return NULL;
+ case 1:
+ return dent;
+ case 2:
+ return prev ? prev : dent;
+ default:
+ BUG_ON(ret > 0);
+ return ERR_PTR(ret);
+ }
+
+consist_inode:
+ gfs2_consist_inode(GFS2_I(inode));
+ return ERR_PTR(-EIO);
+}
+
+
+/**
+ * dirent_first - Return the first dirent
+ * @dip: the directory
+ * @bh: The buffer
+ * @dent: Pointer to list of dirents
+ *
+ * return first dirent whether bh points to leaf or stuffed dinode
+ *
+ * Returns: IS_LEAF, IS_DINODE, or -errno
+ */
+
+static int dirent_first(struct gfs2_inode *dip, struct buffer_head *bh,
+ struct gfs2_dirent **dent)
+{
+ struct gfs2_meta_header *h = (struct gfs2_meta_header *)bh->b_data;
+
+ if (be32_to_cpu(h->mh_type) == GFS2_METATYPE_LF) {
+ if (gfs2_meta_check(GFS2_SB(&dip->i_inode), bh))
+ return -EIO;
+ *dent = (struct gfs2_dirent *)(bh->b_data +
+ sizeof(struct gfs2_leaf));
+ return IS_LEAF;
+ } else {
+ if (gfs2_metatype_check(GFS2_SB(&dip->i_inode), bh, GFS2_METATYPE_DI))
+ return -EIO;
+ *dent = (struct gfs2_dirent *)(bh->b_data +
+ sizeof(struct gfs2_dinode));
+ return IS_DINODE;
+ }
+}
+
+static int dirent_check_reclen(struct gfs2_inode *dip,
+ const struct gfs2_dirent *d, const void *end_p)
+{
+ const void *ptr = d;
+ u16 rec_len = be16_to_cpu(d->de_rec_len);
+
+ if (unlikely(rec_len < sizeof(struct gfs2_dirent)))
+ goto broken;
+ ptr += rec_len;
+ if (ptr < end_p)
+ return rec_len;
+ if (ptr == end_p)
+ return -ENOENT;
+broken:
+ gfs2_consist_inode(dip);
+ return -EIO;
+}
+
+/**
+ * dirent_next - Next dirent
+ * @dip: the directory
+ * @bh: The buffer
+ * @dent: Pointer to list of dirents
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+static int dirent_next(struct gfs2_inode *dip, struct buffer_head *bh,
+ struct gfs2_dirent **dent)
+{
+ struct gfs2_dirent *cur = *dent, *tmp;
+ char *bh_end = bh->b_data + bh->b_size;
+ int ret;
+
+ ret = dirent_check_reclen(dip, cur, bh_end);
+ if (ret < 0)
+ return ret;
+
+ tmp = (void *)cur + ret;
+ ret = dirent_check_reclen(dip, tmp, bh_end);
+ if (ret == -EIO)
+ return ret;
+
+ /* Only the first dent could ever have de_inum.no_addr == 0 */
+ if (!tmp->de_inum.no_addr) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+
+ *dent = tmp;
+ return 0;
+}
+
+/**
+ * dirent_del - Delete a dirent
+ * @dip: The GFS2 inode
+ * @bh: The buffer
+ * @prev: The previous dirent
+ * @cur: The current dirent
+ *
+ */
+
+static void dirent_del(struct gfs2_inode *dip, struct buffer_head *bh,
+ struct gfs2_dirent *prev, struct gfs2_dirent *cur)
+{
+ u16 cur_rec_len, prev_rec_len;
+
+ if (!cur->de_inum.no_addr) {
+ gfs2_consist_inode(dip);
+ return;
+ }
+
+ gfs2_trans_add_bh(dip->i_gl, bh, 1);
+
+ /* If there is no prev entry, this is the first entry in the block.
+ The de_rec_len is already as big as it needs to be. Just zero
+ out the inode number and return. */
+
+ if (!prev) {
+ cur->de_inum.no_addr = 0; /* No endianess worries */
+ return;
+ }
+
+ /* Combine this dentry with the previous one. */
+
+ prev_rec_len = be16_to_cpu(prev->de_rec_len);
+ cur_rec_len = be16_to_cpu(cur->de_rec_len);
+
+ if ((char *)prev + prev_rec_len != (char *)cur)
+ gfs2_consist_inode(dip);
+ if ((char *)cur + cur_rec_len > bh->b_data + bh->b_size)
+ gfs2_consist_inode(dip);
+
+ prev_rec_len += cur_rec_len;
+ prev->de_rec_len = cpu_to_be16(prev_rec_len);
+}
+
+/*
+ * Takes a dent from which to grab space as an argument. Returns the
+ * newly created dent.
+ */
+static struct gfs2_dirent *gfs2_init_dirent(struct inode *inode,
+ struct gfs2_dirent *dent,
+ const struct qstr *name,
+ struct buffer_head *bh)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_dirent *ndent;
+ unsigned offset = 0, totlen;
+
+ if (dent->de_inum.no_addr)
+ offset = GFS2_DIRENT_SIZE(be16_to_cpu(dent->de_name_len));
+ totlen = be16_to_cpu(dent->de_rec_len);
+ BUG_ON(offset + name->len > totlen);
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ ndent = (struct gfs2_dirent *)((char *)dent + offset);
+ dent->de_rec_len = cpu_to_be16(offset);
+ gfs2_qstr2dirent(name, totlen - offset, ndent);
+ return ndent;
+}
+
+static struct gfs2_dirent *gfs2_dirent_alloc(struct inode *inode,
+ struct buffer_head *bh,
+ const struct qstr *name)
+{
+ struct gfs2_dirent *dent;
+ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
+ gfs2_dirent_find_space, name, NULL);
+ if (!dent || IS_ERR(dent))
+ return dent;
+ return gfs2_init_dirent(inode, dent, name, bh);
+}
+
+static int get_leaf(struct gfs2_inode *dip, u64 leaf_no,
+ struct buffer_head **bhp)
+{
+ int error;
+
+ error = gfs2_meta_read(dip->i_gl, leaf_no, DIO_WAIT, bhp);
+ if (!error && gfs2_metatype_check(GFS2_SB(&dip->i_inode), *bhp, GFS2_METATYPE_LF)) {
+ /* printk(KERN_INFO "block num=%llu\n", leaf_no); */
+ error = -EIO;
+ }
+
+ return error;
+}
+
+/**
+ * get_leaf_nr - Get a leaf number associated with the index
+ * @dip: The GFS2 inode
+ * @index:
+ * @leaf_out:
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+static int get_leaf_nr(struct gfs2_inode *dip, u32 index,
+ u64 *leaf_out)
+{
+ u64 leaf_no;
+ int error;
+
+ error = gfs2_dir_read_data(dip, (char *)&leaf_no,
+ index * sizeof(u64),
+ sizeof(u64), 0);
+ if (error != sizeof(u64))
+ return (error < 0) ? error : -EIO;
+
+ *leaf_out = be64_to_cpu(leaf_no);
+
+ return 0;
+}
+
+static int get_first_leaf(struct gfs2_inode *dip, u32 index,
+ struct buffer_head **bh_out)
+{
+ u64 leaf_no;
+ int error;
+
+ error = get_leaf_nr(dip, index, &leaf_no);
+ if (!error)
+ error = get_leaf(dip, leaf_no, bh_out);
+
+ return error;
+}
+
+static struct gfs2_dirent *gfs2_dirent_search(struct inode *inode,
+ const struct qstr *name,
+ gfs2_dscan_t scan,
+ struct buffer_head **pbh)
+{
+ struct buffer_head *bh;
+ struct gfs2_dirent *dent;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ int error;
+
+ if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
+ struct gfs2_leaf *leaf;
+ unsigned hsize = 1 << ip->i_di.di_depth;
+ unsigned index;
+ u64 ln;
+ if (hsize * sizeof(u64) != ip->i_di.di_size) {
+ gfs2_consist_inode(ip);
+ return ERR_PTR(-EIO);
+ }
+
+ index = name->hash >> (32 - ip->i_di.di_depth);
+ error = get_first_leaf(ip, index, &bh);
+ if (error)
+ return ERR_PTR(error);
+ do {
+ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
+ scan, name, NULL);
+ if (dent)
+ goto got_dent;
+ leaf = (struct gfs2_leaf *)bh->b_data;
+ ln = be64_to_cpu(leaf->lf_next);
+ brelse(bh);
+ if (!ln)
+ break;
+
+ error = get_leaf(ip, ln, &bh);
+ } while(!error);
+
+ return error ? ERR_PTR(error) : NULL;
+ }
+
+
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error)
+ return ERR_PTR(error);
+ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size, scan, name, NULL);
+got_dent:
+ if (unlikely(dent == NULL || IS_ERR(dent))) {
+ brelse(bh);
+ bh = NULL;
+ }
+ *pbh = bh;
+ return dent;
+}
+
+static struct gfs2_leaf *new_leaf(struct inode *inode, struct buffer_head **pbh, u16 depth)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ u64 bn = gfs2_alloc_meta(ip);
+ struct buffer_head *bh = gfs2_meta_new(ip->i_gl, bn);
+ struct gfs2_leaf *leaf;
+ struct gfs2_dirent *dent;
+ struct qstr name = { .name = "", .len = 0, .hash = 0 };
+ if (!bh)
+ return NULL;
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ gfs2_metatype_set(bh, GFS2_METATYPE_LF, GFS2_FORMAT_LF);
+ leaf = (struct gfs2_leaf *)bh->b_data;
+ leaf->lf_depth = cpu_to_be16(depth);
+ leaf->lf_entries = 0;
+ leaf->lf_dirent_format = cpu_to_be32(GFS2_FORMAT_DE);
+ leaf->lf_next = 0;
+ memset(leaf->lf_reserved, 0, sizeof(leaf->lf_reserved));
+ dent = (struct gfs2_dirent *)(leaf+1);
+ gfs2_qstr2dirent(&name, bh->b_size - sizeof(struct gfs2_leaf), dent);
+ *pbh = bh;
+ return leaf;
+}
+
+/**
+ * dir_make_exhash - Convert a stuffed directory into an ExHash directory
+ * @dip: The GFS2 inode
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+static int dir_make_exhash(struct inode *inode)
+{
+ struct gfs2_inode *dip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct gfs2_dirent *dent;
+ struct qstr args;
+ struct buffer_head *bh, *dibh;
+ struct gfs2_leaf *leaf;
+ int y;
+ u32 x;
+ u64 *lp, bn;
+ int error;
+
+ error = gfs2_meta_inode_buffer(dip, &dibh);
+ if (error)
+ return error;
+
+ /* Turn over a new leaf */
+
+ leaf = new_leaf(inode, &bh, 0);
+ if (!leaf)
+ return -ENOSPC;
+ bn = bh->b_blocknr;
+
+ gfs2_assert(sdp, dip->i_di.di_entries < (1 << 16));
+ leaf->lf_entries = cpu_to_be16(dip->i_di.di_entries);
+
+ /* Copy dirents */
+
+ gfs2_buffer_copy_tail(bh, sizeof(struct gfs2_leaf), dibh,
+ sizeof(struct gfs2_dinode));
+
+ /* Find last entry */
+
+ x = 0;
+ args.len = bh->b_size - sizeof(struct gfs2_dinode) +
+ sizeof(struct gfs2_leaf);
+ args.name = bh->b_data;
+ dent = gfs2_dirent_scan(&dip->i_inode, bh->b_data, bh->b_size,
+ gfs2_dirent_last, &args, NULL);
+ if (!dent) {
+ brelse(bh);
+ brelse(dibh);
+ return -EIO;
+ }
+ if (IS_ERR(dent)) {
+ brelse(bh);
+ brelse(dibh);
+ return PTR_ERR(dent);
+ }
+
+ /* Adjust the last dirent's record length
+ (Remember that dent still points to the last entry.) */
+
+ dent->de_rec_len = cpu_to_be16(be16_to_cpu(dent->de_rec_len) +
+ sizeof(struct gfs2_dinode) -
+ sizeof(struct gfs2_leaf));
+
+ brelse(bh);
+
+ /* We're done with the new leaf block, now setup the new
+ hash table. */
+
+ gfs2_trans_add_bh(dip->i_gl, dibh, 1);
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+
+ lp = (u64 *)(dibh->b_data + sizeof(struct gfs2_dinode));
+
+ for (x = sdp->sd_hash_ptrs; x--; lp++)
+ *lp = cpu_to_be64(bn);
+
+ dip->i_di.di_size = sdp->sd_sb.sb_bsize / 2;
+ dip->i_di.di_blocks++;
+ dip->i_di.di_flags |= GFS2_DIF_EXHASH;
+ dip->i_di.di_payload_format = 0;
+
+ for (x = sdp->sd_hash_ptrs, y = -1; x; x >>= 1, y++) ;
+ dip->i_di.di_depth = y;
+
+ gfs2_dinode_out(&dip->i_di, dibh->b_data);
+
+ brelse(dibh);
+
+ return 0;
+}
+
+/**
+ * dir_split_leaf - Split a leaf block into two
+ * @dip: The GFS2 inode
+ * @index:
+ * @leaf_no:
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+static int dir_split_leaf(struct inode *inode, const struct qstr *name)
+{
+ struct gfs2_inode *dip = GFS2_I(inode);
+ struct buffer_head *nbh, *obh, *dibh;
+ struct gfs2_leaf *nleaf, *oleaf;
+ struct gfs2_dirent *dent = NULL, *prev = NULL, *next = NULL, *new;
+ u32 start, len, half_len, divider;
+ u64 bn, *lp, leaf_no;
+ u32 index;
+ int x, moved = 0;
+ int error;
+
+ index = name->hash >> (32 - dip->i_di.di_depth);
+ error = get_leaf_nr(dip, index, &leaf_no);
+ if (error)
+ return error;
+
+ /* Get the old leaf block */
+ error = get_leaf(dip, leaf_no, &obh);
+ if (error)
+ return error;
+
+ oleaf = (struct gfs2_leaf *)obh->b_data;
+ if (dip->i_di.di_depth == be16_to_cpu(oleaf->lf_depth)) {
+ brelse(obh);
+ return 1; /* can't split */
+ }
+
+ gfs2_trans_add_bh(dip->i_gl, obh, 1);
+
+ nleaf = new_leaf(inode, &nbh, be16_to_cpu(oleaf->lf_depth) + 1);
+ if (!nleaf) {
+ brelse(obh);
+ return -ENOSPC;
+ }
+ bn = nbh->b_blocknr;
+
+ /* Compute the start and len of leaf pointers in the hash table. */
+ len = 1 << (dip->i_di.di_depth - be16_to_cpu(oleaf->lf_depth));
+ half_len = len >> 1;
+ if (!half_len) {
+ printk(KERN_WARNING "di_depth %u lf_depth %u index %u\n", dip->i_di.di_depth, be16_to_cpu(oleaf->lf_depth), index);
+ gfs2_consist_inode(dip);
+ error = -EIO;
+ goto fail_brelse;
+ }
+
+ start = (index & ~(len - 1));
+
+ /* Change the pointers.
+ Don't bother distinguishing stuffed from non-stuffed.
+ This code is complicated enough already. */
+ lp = kmalloc(half_len * sizeof(u64), GFP_NOFS | __GFP_NOFAIL);
+ /* Change the pointers */
+ for (x = 0; x < half_len; x++)
+ lp[x] = cpu_to_be64(bn);
+
+ error = gfs2_dir_write_data(dip, (char *)lp, start * sizeof(u64),
+ half_len * sizeof(u64));
+ if (error != half_len * sizeof(u64)) {
+ if (error >= 0)
+ error = -EIO;
+ goto fail_lpfree;
+ }
+
+ kfree(lp);
+
+ /* Compute the divider */
+ divider = (start + half_len) << (32 - dip->i_di.di_depth);
+
+ /* Copy the entries */
+ dirent_first(dip, obh, &dent);
+
+ do {
+ next = dent;
+ if (dirent_next(dip, obh, &next))
+ next = NULL;
+
+ if (dent->de_inum.no_addr &&
+ be32_to_cpu(dent->de_hash) < divider) {
+ struct qstr str;
+ str.name = (char*)(dent+1);
+ str.len = be16_to_cpu(dent->de_name_len);
+ str.hash = be32_to_cpu(dent->de_hash);
+ new = gfs2_dirent_alloc(inode, nbh, &str);
+ if (IS_ERR(new)) {
+ error = PTR_ERR(new);
+ break;
+ }
+
+ new->de_inum = dent->de_inum; /* No endian worries */
+ new->de_type = dent->de_type; /* No endian worries */
+ nleaf->lf_entries = cpu_to_be16(be16_to_cpu(nleaf->lf_entries)+1);
+
+ dirent_del(dip, obh, prev, dent);
+
+ if (!oleaf->lf_entries)
+ gfs2_consist_inode(dip);
+ oleaf->lf_entries = cpu_to_be16(be16_to_cpu(oleaf->lf_entries)-1);
+
+ if (!prev)
+ prev = dent;
+
+ moved = 1;
+ } else {
+ prev = dent;
+ }
+ dent = next;
+ } while (dent);
+
+ oleaf->lf_depth = nleaf->lf_depth;
+
+ error = gfs2_meta_inode_buffer(dip, &dibh);
+ if (!gfs2_assert_withdraw(GFS2_SB(&dip->i_inode), !error)) {
+ dip->i_di.di_blocks++;
+ gfs2_dinode_out(&dip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ brelse(obh);
+ brelse(nbh);
+
+ return error;
+
+fail_lpfree:
+ kfree(lp);
+
+fail_brelse:
+ brelse(obh);
+ brelse(nbh);
+ return error;
+}
+
+/**
+ * dir_double_exhash - Double size of ExHash table
+ * @dip: The GFS2 dinode
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+static int dir_double_exhash(struct gfs2_inode *dip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct buffer_head *dibh;
+ u32 hsize;
+ u64 *buf;
+ u64 *from, *to;
+ u64 block;
+ int x;
+ int error = 0;
+
+ hsize = 1 << dip->i_di.di_depth;
+ if (hsize * sizeof(u64) != dip->i_di.di_size) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+
+ /* Allocate both the "from" and "to" buffers in one big chunk */
+
+ buf = kcalloc(3, sdp->sd_hash_bsize, GFP_KERNEL | __GFP_NOFAIL);
+
+ for (block = dip->i_di.di_size >> sdp->sd_hash_bsize_shift; block--;) {
+ error = gfs2_dir_read_data(dip, (char *)buf,
+ block * sdp->sd_hash_bsize,
+ sdp->sd_hash_bsize, 1);
+ if (error != sdp->sd_hash_bsize) {
+ if (error >= 0)
+ error = -EIO;
+ goto fail;
+ }
+
+ from = buf;
+ to = (u64 *)((char *)buf + sdp->sd_hash_bsize);
+
+ for (x = sdp->sd_hash_ptrs; x--; from++) {
+ *to++ = *from; /* No endianess worries */
+ *to++ = *from;
+ }
+
+ error = gfs2_dir_write_data(dip,
+ (char *)buf + sdp->sd_hash_bsize,
+ block * sdp->sd_sb.sb_bsize,
+ sdp->sd_sb.sb_bsize);
+ if (error != sdp->sd_sb.sb_bsize) {
+ if (error >= 0)
+ error = -EIO;
+ goto fail;
+ }
+ }
+
+ kfree(buf);
+
+ error = gfs2_meta_inode_buffer(dip, &dibh);
+ if (!gfs2_assert_withdraw(sdp, !error)) {
+ dip->i_di.di_depth++;
+ gfs2_dinode_out(&dip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ return error;
+
+fail:
+ kfree(buf);
+ return error;
+}
+
+/**
+ * compare_dents - compare directory entries by hash value
+ * @a: first dent
+ * @b: second dent
+ *
+ * When comparing the hash entries of @a to @b:
+ * gt: returns 1
+ * lt: returns -1
+ * eq: returns 0
+ */
+
+static int compare_dents(const void *a, const void *b)
+{
+ const struct gfs2_dirent *dent_a, *dent_b;
+ u32 hash_a, hash_b;
+ int ret = 0;
+
+ dent_a = *(const struct gfs2_dirent **)a;
+ hash_a = be32_to_cpu(dent_a->de_hash);
+
+ dent_b = *(const struct gfs2_dirent **)b;
+ hash_b = be32_to_cpu(dent_b->de_hash);
+
+ if (hash_a > hash_b)
+ ret = 1;
+ else if (hash_a < hash_b)
+ ret = -1;
+ else {
+ unsigned int len_a = be16_to_cpu(dent_a->de_name_len);
+ unsigned int len_b = be16_to_cpu(dent_b->de_name_len);
+
+ if (len_a > len_b)
+ ret = 1;
+ else if (len_a < len_b)
+ ret = -1;
+ else
+ ret = memcmp(dent_a + 1, dent_b + 1, len_a);
+ }
+
+ return ret;
+}
+
+/**
+ * do_filldir_main - read out directory entries
+ * @dip: The GFS2 inode
+ * @offset: The offset in the file to read from
+ * @opaque: opaque data to pass to filldir
+ * @filldir: The function to pass entries to
+ * @darr: an array of struct gfs2_dirent pointers to read
+ * @entries: the number of entries in darr
+ * @copied: pointer to int that's non-zero if a entry has been copied out
+ *
+ * Jump through some hoops to make sure that if there are hash collsions,
+ * they are read out at the beginning of a buffer. We want to minimize
+ * the possibility that they will fall into different readdir buffers or
+ * that someone will want to seek to that location.
+ *
+ * Returns: errno, >0 on exception from filldir
+ */
+
+static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
+ void *opaque, gfs2_filldir_t filldir,
+ const struct gfs2_dirent **darr, u32 entries,
+ int *copied)
+{
+ const struct gfs2_dirent *dent, *dent_next;
+ struct gfs2_inum inum;
+ u64 off, off_next;
+ unsigned int x, y;
+ int run = 0;
+ int error = 0;
+
+ sort(darr, entries, sizeof(struct gfs2_dirent *), compare_dents, NULL);
+
+ dent_next = darr[0];
+ off_next = be32_to_cpu(dent_next->de_hash);
+ off_next = gfs2_disk_hash2offset(off_next);
+
+ for (x = 0, y = 1; x < entries; x++, y++) {
+ dent = dent_next;
+ off = off_next;
+
+ if (y < entries) {
+ dent_next = darr[y];
+ off_next = be32_to_cpu(dent_next->de_hash);
+ off_next = gfs2_disk_hash2offset(off_next);
+
+ if (off < *offset)
+ continue;
+ *offset = off;
+
+ if (off_next == off) {
+ if (*copied && !run)
+ return 1;
+ run = 1;
+ } else
+ run = 0;
+ } else {
+ if (off < *offset)
+ continue;
+ *offset = off;
+ }
+
+ gfs2_inum_in(&inum, (char *)&dent->de_inum);
+
+ error = filldir(opaque, (const char *)(dent + 1),
+ be16_to_cpu(dent->de_name_len),
+ off, &inum,
+ be16_to_cpu(dent->de_type));
+ if (error)
+ return 1;
+
+ *copied = 1;
+ }
+
+ /* Increment the *offset by one, so the next time we come into the
+ do_filldir fxn, we get the next entry instead of the last one in the
+ current leaf */
+
+ (*offset)++;
+
+ return 0;
+}
+
+static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
+ gfs2_filldir_t filldir, int *copied,
+ unsigned *depth, u64 leaf_no)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct buffer_head *bh;
+ struct gfs2_leaf *lf;
+ unsigned entries = 0;
+ unsigned leaves = 0;
+ const struct gfs2_dirent **darr, *dent;
+ struct dirent_gather g;
+ struct buffer_head **larr;
+ int leaf = 0;
+ int error, i;
+ u64 lfn = leaf_no;
+
+ do {
+ error = get_leaf(ip, lfn, &bh);
+ if (error)
+ goto out;
+ lf = (struct gfs2_leaf *)bh->b_data;
+ if (leaves == 0)
+ *depth = be16_to_cpu(lf->lf_depth);
+ entries += be16_to_cpu(lf->lf_entries);
+ leaves++;
+ lfn = be64_to_cpu(lf->lf_next);
+ brelse(bh);
+ } while(lfn);
+
+ if (!entries)
+ return 0;
+
+ error = -ENOMEM;
+ larr = vmalloc((leaves + entries) * sizeof(void *));
+ if (!larr)
+ goto out;
+ darr = (const struct gfs2_dirent **)(larr + leaves);
+ g.pdent = darr;
+ g.offset = 0;
+ lfn = leaf_no;
+
+ do {
+ error = get_leaf(ip, lfn, &bh);
+ if (error)
+ goto out_kfree;
+ lf = (struct gfs2_leaf *)bh->b_data;
+ lfn = be64_to_cpu(lf->lf_next);
+ if (lf->lf_entries) {
+ dent = gfs2_dirent_scan(inode, bh->b_data, bh->b_size,
+ gfs2_dirent_gather, NULL, &g);
+ error = PTR_ERR(dent);
+ if (IS_ERR(dent)) {
+ goto out_kfree;
+ }
+ error = 0;
+ larr[leaf++] = bh;
+ } else {
+ brelse(bh);
+ }
+ } while(lfn);
+
+ error = do_filldir_main(ip, offset, opaque, filldir, darr,
+ entries, copied);
+out_kfree:
+ for(i = 0; i < leaf; i++)
+ brelse(larr[i]);
+ vfree(larr);
+out:
+ return error;
+}
+
+/**
+ * dir_e_read - Reads the entries from a directory into a filldir buffer
+ * @dip: dinode pointer
+ * @offset: the hash of the last entry read shifted to the right once
+ * @opaque: buffer for the filldir function to fill
+ * @filldir: points to the filldir function to use
+ *
+ * Returns: errno
+ */
+
+static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
+ gfs2_filldir_t filldir)
+{
+ struct gfs2_inode *dip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ u32 hsize, len = 0;
+ u32 ht_offset, lp_offset, ht_offset_cur = -1;
+ u32 hash, index;
+ u64 *lp;
+ int copied = 0;
+ int error = 0;
+ unsigned depth = 0;
+
+ hsize = 1 << dip->i_di.di_depth;
+ if (hsize * sizeof(u64) != dip->i_di.di_size) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+
+ hash = gfs2_dir_offset2hash(*offset);
+ index = hash >> (32 - dip->i_di.di_depth);
+
+ lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL);
+ if (!lp)
+ return -ENOMEM;
+
+ while (index < hsize) {
+ lp_offset = index & (sdp->sd_hash_ptrs - 1);
+ ht_offset = index - lp_offset;
+
+ if (ht_offset_cur != ht_offset) {
+ error = gfs2_dir_read_data(dip, (char *)lp,
+ ht_offset * sizeof(u64),
+ sdp->sd_hash_bsize, 1);
+ if (error != sdp->sd_hash_bsize) {
+ if (error >= 0)
+ error = -EIO;
+ goto out;
+ }
+ ht_offset_cur = ht_offset;
+ }
+
+ error = gfs2_dir_read_leaf(inode, offset, opaque, filldir,
+ &copied, &depth,
+ be64_to_cpu(lp[lp_offset]));
+ if (error)
+ break;
+
+ len = 1 << (dip->i_di.di_depth - depth);
+ index = (index & ~(len - 1)) + len;
+ }
+
+out:
+ kfree(lp);
+ if (error > 0)
+ error = 0;
+ return error;
+}
+
+int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
+ gfs2_filldir_t filldir)
+{
+ struct gfs2_inode *dip = GFS2_I(inode);
+ struct dirent_gather g;
+ const struct gfs2_dirent **darr, *dent;
+ struct buffer_head *dibh;
+ int copied = 0;
+ int error;
+
+ if (!dip->i_di.di_entries)
+ return 0;
+
+ if (dip->i_di.di_flags & GFS2_DIF_EXHASH)
+ return dir_e_read(inode, offset, opaque, filldir);
+
+ if (!gfs2_is_stuffed(dip)) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+
+ error = gfs2_meta_inode_buffer(dip, &dibh);
+ if (error)
+ return error;
+
+ error = -ENOMEM;
+ darr = kmalloc(dip->i_di.di_entries * sizeof(struct gfs2_dirent *),
+ GFP_KERNEL);
+ if (darr) {
+ g.pdent = darr;
+ g.offset = 0;
+ dent = gfs2_dirent_scan(inode, dibh->b_data, dibh->b_size,
+ gfs2_dirent_gather, NULL, &g);
+ if (IS_ERR(dent)) {
+ error = PTR_ERR(dent);
+ goto out;
+ }
+ error = do_filldir_main(dip, offset, opaque, filldir, darr,
+ dip->i_di.di_entries, &copied);
+out:
+ kfree(darr);
+ }
+
+ if (error > 0)
+ error = 0;
+
+ brelse(dibh);
+
+ return error;
+}
+
+/**
+ * gfs2_dir_search - Search a directory
+ * @dip: The GFS2 inode
+ * @filename:
+ * @inode:
+ *
+ * This routine searches a directory for a file or another directory.
+ * Assumes a glock is held on dip.
+ *
+ * Returns: errno
+ */
+
+int gfs2_dir_search(struct inode *dir, const struct qstr *name,
+ struct gfs2_inum *inum, unsigned int *type)
+{
+ struct buffer_head *bh;
+ struct gfs2_dirent *dent;
+
+ dent = gfs2_dirent_search(dir, name, gfs2_dirent_find, &bh);
+ if (dent) {
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+ if (inum)
+ gfs2_inum_in(inum, (char *)&dent->de_inum);
+ if (type)
+ *type = be16_to_cpu(dent->de_type);
+ brelse(bh);
+ return 0;
+ }
+ return -ENOENT;
+}
+
+static int dir_new_leaf(struct inode *inode, const struct qstr *name)
+{
+ struct buffer_head *bh, *obh;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_leaf *leaf, *oleaf;
+ int error;
+ u32 index;
+ u64 bn;
+
+ index = name->hash >> (32 - ip->i_di.di_depth);
+ error = get_first_leaf(ip, index, &obh);
+ if (error)
+ return error;
+ do {
+ oleaf = (struct gfs2_leaf *)obh->b_data;
+ bn = be64_to_cpu(oleaf->lf_next);
+ if (!bn)
+ break;
+ brelse(obh);
+ error = get_leaf(ip, bn, &obh);
+ if (error)
+ return error;
+ } while(1);
+
+ gfs2_trans_add_bh(ip->i_gl, obh, 1);
+
+ leaf = new_leaf(inode, &bh, be16_to_cpu(oleaf->lf_depth));
+ if (!leaf) {
+ brelse(obh);
+ return -ENOSPC;
+ }
+ oleaf->lf_next = cpu_to_be64(bh->b_blocknr);
+ brelse(bh);
+ brelse(obh);
+
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error)
+ return error;
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ ip->i_di.di_blocks++;
+ gfs2_dinode_out(&ip->i_di, bh->b_data);
+ brelse(bh);
+ return 0;
+}
+
+/**
+ * gfs2_dir_add - Add new filename into directory
+ * @dip: The GFS2 inode
+ * @filename: The new name
+ * @inode: The inode number of the entry
+ * @type: The type of the entry
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+int gfs2_dir_add(struct inode *inode, const struct qstr *name,
+ const struct gfs2_inum *inum, unsigned type)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct buffer_head *bh;
+ struct gfs2_dirent *dent;
+ struct gfs2_leaf *leaf;
+ int error;
+
+ while(1) {
+ dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space,
+ &bh);
+ if (dent) {
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+ dent = gfs2_init_dirent(inode, dent, name, bh);
+ gfs2_inum_out(inum, (char *)&dent->de_inum);
+ dent->de_type = cpu_to_be16(type);
+ if (ip->i_di.di_flags & GFS2_DIF_EXHASH) {
+ leaf = (struct gfs2_leaf *)bh->b_data;
+ leaf->lf_entries = cpu_to_be16(be16_to_cpu(leaf->lf_entries) + 1);
+ }
+ brelse(bh);
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error)
+ break;
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ ip->i_di.di_entries++;
+ ip->i_di.di_mtime = ip->i_di.di_ctime = get_seconds();
+ gfs2_dinode_out(&ip->i_di, bh->b_data);
+ brelse(bh);
+ error = 0;
+ break;
+ }
+ if (!(ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
+ error = dir_make_exhash(inode);
+ if (error)
+ break;
+ continue;
+ }
+ error = dir_split_leaf(inode, name);
+ if (error == 0)
+ continue;
+ if (error < 0)
+ break;
+ if (ip->i_di.di_depth < GFS2_DIR_MAX_DEPTH) {
+ error = dir_double_exhash(ip);
+ if (error)
+ break;
+ error = dir_split_leaf(inode, name);
+ if (error < 0)
+ break;
+ if (error == 0)
+ continue;
+ }
+ error = dir_new_leaf(inode, name);
+ if (!error)
+ continue;
+ error = -ENOSPC;
+ break;
+ }
+ return error;
+}
+
+
+/**
+ * gfs2_dir_del - Delete a directory entry
+ * @dip: The GFS2 inode
+ * @filename: The filename
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name)
+{
+ struct gfs2_dirent *dent, *prev = NULL;
+ struct buffer_head *bh;
+ int error;
+
+ /* Returns _either_ the entry (if its first in block) or the
+ previous entry otherwise */
+ dent = gfs2_dirent_search(&dip->i_inode, name, gfs2_dirent_prev, &bh);
+ if (!dent) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+ if (IS_ERR(dent)) {
+ gfs2_consist_inode(dip);
+ return PTR_ERR(dent);
+ }
+ /* If not first in block, adjust pointers accordingly */
+ if (gfs2_dirent_find(dent, name, NULL) == 0) {
+ prev = dent;
+ dent = (struct gfs2_dirent *)((char *)dent + be16_to_cpu(prev->de_rec_len));
+ }
+
+ dirent_del(dip, bh, prev, dent);
+ if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
+ struct gfs2_leaf *leaf = (struct gfs2_leaf *)bh->b_data;
+ u16 entries = be16_to_cpu(leaf->lf_entries);
+ if (!entries)
+ gfs2_consist_inode(dip);
+ leaf->lf_entries = cpu_to_be16(--entries);
+ }
+ brelse(bh);
+
+ error = gfs2_meta_inode_buffer(dip, &bh);
+ if (error)
+ return error;
+
+ if (!dip->i_di.di_entries)
+ gfs2_consist_inode(dip);
+ gfs2_trans_add_bh(dip->i_gl, bh, 1);
+ dip->i_di.di_entries--;
+ dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds();
+ gfs2_dinode_out(&dip->i_di, bh->b_data);
+ brelse(bh);
+ mark_inode_dirty(&dip->i_inode);
+
+ return error;
+}
+
+/**
+ * gfs2_dir_mvino - Change inode number of directory entry
+ * @dip: The GFS2 inode
+ * @filename:
+ * @new_inode:
+ *
+ * This routine changes the inode number of a directory entry. It's used
+ * by rename to change ".." when a directory is moved.
+ * Assumes a glock is held on dvp.
+ *
+ * Returns: errno
+ */
+
+int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
+ struct gfs2_inum *inum, unsigned int new_type)
+{
+ struct buffer_head *bh;
+ struct gfs2_dirent *dent;
+ int error;
+
+ dent = gfs2_dirent_search(&dip->i_inode, filename, gfs2_dirent_find, &bh);
+ if (!dent) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+
+ gfs2_trans_add_bh(dip->i_gl, bh, 1);
+ gfs2_inum_out(inum, (char *)&dent->de_inum);
+ dent->de_type = cpu_to_be16(new_type);
+
+ if (dip->i_di.di_flags & GFS2_DIF_EXHASH) {
+ brelse(bh);
+ error = gfs2_meta_inode_buffer(dip, &bh);
+ if (error)
+ return error;
+ gfs2_trans_add_bh(dip->i_gl, bh, 1);
+ }
+
+ dip->i_di.di_mtime = dip->i_di.di_ctime = get_seconds();
+ gfs2_dinode_out(&dip->i_di, bh->b_data);
+ brelse(bh);
+ return 0;
+}
+
+/**
+ * foreach_leaf - call a function for each leaf in a directory
+ * @dip: the directory
+ * @lc: the function to call for each each
+ * @data: private data to pass to it
+ *
+ * Returns: errno
+ */
+
+static int foreach_leaf(struct gfs2_inode *dip, leaf_call_t lc, void *data)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct buffer_head *bh;
+ struct gfs2_leaf *leaf;
+ u32 hsize, len;
+ u32 ht_offset, lp_offset, ht_offset_cur = -1;
+ u32 index = 0;
+ u64 *lp;
+ u64 leaf_no;
+ int error = 0;
+
+ hsize = 1 << dip->i_di.di_depth;
+ if (hsize * sizeof(u64) != dip->i_di.di_size) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+
+ lp = kmalloc(sdp->sd_hash_bsize, GFP_KERNEL);
+ if (!lp)
+ return -ENOMEM;
+
+ while (index < hsize) {
+ lp_offset = index & (sdp->sd_hash_ptrs - 1);
+ ht_offset = index - lp_offset;
+
+ if (ht_offset_cur != ht_offset) {
+ error = gfs2_dir_read_data(dip, (char *)lp,
+ ht_offset * sizeof(u64),
+ sdp->sd_hash_bsize, 1);
+ if (error != sdp->sd_hash_bsize) {
+ if (error >= 0)
+ error = -EIO;
+ goto out;
+ }
+ ht_offset_cur = ht_offset;
+ }
+
+ leaf_no = be64_to_cpu(lp[lp_offset]);
+ if (leaf_no) {
+ error = get_leaf(dip, leaf_no, &bh);
+ if (error)
+ goto out;
+ leaf = (struct gfs2_leaf *)bh->b_data;
+ len = 1 << (dip->i_di.di_depth - be16_to_cpu(leaf->lf_depth));
+ brelse(bh);
+
+ error = lc(dip, index, len, leaf_no, data);
+ if (error)
+ goto out;
+
+ index = (index & ~(len - 1)) + len;
+ } else
+ index++;
+ }
+
+ if (index != hsize) {
+ gfs2_consist_inode(dip);
+ error = -EIO;
+ }
+
+out:
+ kfree(lp);
+
+ return error;
+}
+
+/**
+ * leaf_dealloc - Deallocate a directory leaf
+ * @dip: the directory
+ * @index: the hash table offset in the directory
+ * @len: the number of pointers to this leaf
+ * @leaf_no: the leaf number
+ * @data: not used
+ *
+ * Returns: errno
+ */
+
+static int leaf_dealloc(struct gfs2_inode *dip, u32 index, u32 len,
+ u64 leaf_no, void *data)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct gfs2_leaf *tmp_leaf;
+ struct gfs2_rgrp_list rlist;
+ struct buffer_head *bh, *dibh;
+ u64 blk, nblk;
+ unsigned int rg_blocks = 0, l_blocks = 0;
+ char *ht;
+ unsigned int x, size = len * sizeof(u64);
+ int error;
+
+ memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
+
+ ht = kzalloc(size, GFP_KERNEL);
+ if (!ht)
+ return -ENOMEM;
+
+ gfs2_alloc_get(dip);
+
+ error = gfs2_quota_hold(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out;
+
+ error = gfs2_rindex_hold(sdp, &dip->i_alloc.al_ri_gh);
+ if (error)
+ goto out_qs;
+
+ /* Count the number of leaves */
+
+ for (blk = leaf_no; blk; blk = nblk) {
+ error = get_leaf(dip, blk, &bh);
+ if (error)
+ goto out_rlist;
+ tmp_leaf = (struct gfs2_leaf *)bh->b_data;
+ nblk = be64_to_cpu(tmp_leaf->lf_next);
+ brelse(bh);
+
+ gfs2_rlist_add(sdp, &rlist, blk);
+ l_blocks++;
+ }
+
+ gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
+
+ for (x = 0; x < rlist.rl_rgrps; x++) {
+ struct gfs2_rgrpd *rgd;
+ rgd = rlist.rl_ghs[x].gh_gl->gl_object;
+ rg_blocks += rgd->rd_ri.ri_length;
+ }
+
+ error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
+ if (error)
+ goto out_rlist;
+
+ error = gfs2_trans_begin(sdp,
+ rg_blocks + (DIV_ROUND_UP(size, sdp->sd_jbsize) + 1) +
+ RES_DINODE + RES_STATFS + RES_QUOTA, l_blocks);
+ if (error)
+ goto out_rg_gunlock;
+
+ for (blk = leaf_no; blk; blk = nblk) {
+ error = get_leaf(dip, blk, &bh);
+ if (error)
+ goto out_end_trans;
+ tmp_leaf = (struct gfs2_leaf *)bh->b_data;
+ nblk = be64_to_cpu(tmp_leaf->lf_next);
+ brelse(bh);
+
+ gfs2_free_meta(dip, blk, 1);
+
+ if (!dip->i_di.di_blocks)
+ gfs2_consist_inode(dip);
+ dip->i_di.di_blocks--;
+ }
+
+ error = gfs2_dir_write_data(dip, ht, index * sizeof(u64), size);
+ if (error != size) {
+ if (error >= 0)
+ error = -EIO;
+ goto out_end_trans;
+ }
+
+ error = gfs2_meta_inode_buffer(dip, &dibh);
+ if (error)
+ goto out_end_trans;
+
+ gfs2_trans_add_bh(dip->i_gl, dibh, 1);
+ gfs2_dinode_out(&dip->i_di, dibh->b_data);
+ brelse(dibh);
+
+out_end_trans:
+ gfs2_trans_end(sdp);
+out_rg_gunlock:
+ gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
+out_rlist:
+ gfs2_rlist_free(&rlist);
+ gfs2_glock_dq_uninit(&dip->i_alloc.al_ri_gh);
+out_qs:
+ gfs2_quota_unhold(dip);
+out:
+ gfs2_alloc_put(dip);
+ kfree(ht);
+ return error;
+}
+
+/**
+ * gfs2_dir_exhash_dealloc - free all the leaf blocks in a directory
+ * @dip: the directory
+ *
+ * Dealloc all on-disk directory leaves to FREEMETA state
+ * Change on-disk inode type to "regular file"
+ *
+ * Returns: errno
+ */
+
+int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct buffer_head *bh;
+ int error;
+
+ /* Dealloc on-disk leaves to FREEMETA state */
+ error = foreach_leaf(dip, leaf_dealloc, NULL);
+ if (error)
+ return error;
+
+ /* Make this a regular file in case we crash.
+ (We don't want to free these blocks a second time.) */
+
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ if (error)
+ return error;
+
+ error = gfs2_meta_inode_buffer(dip, &bh);
+ if (!error) {
+ gfs2_trans_add_bh(dip->i_gl, bh, 1);
+ ((struct gfs2_dinode *)bh->b_data)->di_mode =
+ cpu_to_be32(S_IFREG);
+ brelse(bh);
+ }
+
+ gfs2_trans_end(sdp);
+
+ return error;
+}
+
+/**
+ * gfs2_diradd_alloc_required - find if adding entry will require an allocation
+ * @ip: the file being written to
+ * @filname: the filename that's going to be added
+ *
+ * Returns: 1 if alloc required, 0 if not, -ve on error
+ */
+
+int gfs2_diradd_alloc_required(struct inode *inode, const struct qstr *name)
+{
+ struct gfs2_dirent *dent;
+ struct buffer_head *bh;
+
+ dent = gfs2_dirent_search(inode, name, gfs2_dirent_find_space, &bh);
+ if (!dent) {
+ return 1;
+ }
+ if (IS_ERR(dent))
+ return PTR_ERR(dent);
+ brelse(bh);
+ return 0;
+}
+
diff --git a/fs/gfs2/dir.h b/fs/gfs2/dir.h
new file mode 100644
index 000000000000..371233419b07
--- /dev/null
+++ b/fs/gfs2/dir.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __DIR_DOT_H__
+#define __DIR_DOT_H__
+
+#include <linux/dcache.h>
+
+struct inode;
+struct gfs2_inode;
+struct gfs2_inum;
+
+/**
+ * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read()
+ * @opaque: opaque data used by the function
+ * @name: the name of the directory entry
+ * @length: the length of the name
+ * @offset: the entry's offset in the directory
+ * @inum: the inode number the entry points to
+ * @type: the type of inode the entry points to
+ *
+ * Returns: 0 on success, 1 if buffer full
+ */
+
+typedef int (*gfs2_filldir_t) (void *opaque,
+ const char *name, unsigned int length,
+ u64 offset,
+ struct gfs2_inum *inum, unsigned int type);
+
+int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
+ struct gfs2_inum *inum, unsigned int *type);
+int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
+ const struct gfs2_inum *inum, unsigned int type);
+int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
+int gfs2_dir_read(struct inode *inode, u64 * offset, void *opaque,
+ gfs2_filldir_t filldir);
+int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
+ struct gfs2_inum *new_inum, unsigned int new_type);
+
+int gfs2_dir_exhash_dealloc(struct gfs2_inode *dip);
+
+int gfs2_diradd_alloc_required(struct inode *dir,
+ const struct qstr *filename);
+int gfs2_dir_get_new_buffer(struct gfs2_inode *ip, u64 block,
+ struct buffer_head **bhp);
+
+static inline u32 gfs2_disk_hash(const char *data, int len)
+{
+ return crc32_le((u32)~0, data, len) ^ (u32)~0;
+}
+
+
+static inline void gfs2_str2qstr(struct qstr *name, const char *fname)
+{
+ name->name = fname;
+ name->len = strlen(fname);
+ name->hash = gfs2_disk_hash(name->name, name->len);
+}
+
+/* N.B. This probably ought to take inum & type as args as well */
+static inline void gfs2_qstr2dirent(const struct qstr *name, u16 reclen, struct gfs2_dirent *dent)
+{
+ dent->de_inum.no_addr = cpu_to_be64(0);
+ dent->de_inum.no_formal_ino = cpu_to_be64(0);
+ dent->de_hash = cpu_to_be32(name->hash);
+ dent->de_rec_len = cpu_to_be16(reclen);
+ dent->de_name_len = cpu_to_be16(name->len);
+ dent->de_type = cpu_to_be16(0);
+ memset(dent->__pad, 0, sizeof(dent->__pad));
+ memcpy(dent + 1, name->name, name->len);
+}
+
+#endif /* __DIR_DOT_H__ */
diff --git a/fs/gfs2/eaops.c b/fs/gfs2/eaops.c
new file mode 100644
index 000000000000..92c54e9b0dc3
--- /dev/null
+++ b/fs/gfs2/eaops.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/xattr.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "util.h"
+
+/**
+ * gfs2_ea_name2type - get the type of the ea, and truncate type from the name
+ * @namep: ea name, possibly with type appended
+ *
+ * Returns: GFS2_EATYPE_XXX
+ */
+
+unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name)
+{
+ unsigned int type;
+
+ if (strncmp(name, "system.", 7) == 0) {
+ type = GFS2_EATYPE_SYS;
+ if (truncated_name)
+ *truncated_name = name + sizeof("system.") - 1;
+ } else if (strncmp(name, "user.", 5) == 0) {
+ type = GFS2_EATYPE_USR;
+ if (truncated_name)
+ *truncated_name = name + sizeof("user.") - 1;
+ } else if (strncmp(name, "security.", 9) == 0) {
+ type = GFS2_EATYPE_SECURITY;
+ if (truncated_name)
+ *truncated_name = name + sizeof("security.") - 1;
+ } else {
+ type = GFS2_EATYPE_UNUSED;
+ if (truncated_name)
+ *truncated_name = NULL;
+ }
+
+ return type;
+}
+
+static int user_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct inode *inode = &ip->i_inode;
+ int error = permission(inode, MAY_READ, NULL);
+ if (error)
+ return error;
+
+ return gfs2_ea_get_i(ip, er);
+}
+
+static int user_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct inode *inode = &ip->i_inode;
+
+ if (S_ISREG(inode->i_mode) ||
+ (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
+ int error = permission(inode, MAY_WRITE, NULL);
+ if (error)
+ return error;
+ } else
+ return -EPERM;
+
+ return gfs2_ea_set_i(ip, er);
+}
+
+static int user_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct inode *inode = &ip->i_inode;
+
+ if (S_ISREG(inode->i_mode) ||
+ (S_ISDIR(inode->i_mode) && !(inode->i_mode & S_ISVTX))) {
+ int error = permission(inode, MAY_WRITE, NULL);
+ if (error)
+ return error;
+ } else
+ return -EPERM;
+
+ return gfs2_ea_remove_i(ip, er);
+}
+
+static int system_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ if (!GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) &&
+ !GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len) &&
+ !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (GFS2_SB(&ip->i_inode)->sd_args.ar_posix_acl == 0 &&
+ (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len) ||
+ GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)))
+ return -EOPNOTSUPP;
+
+
+
+ return gfs2_ea_get_i(ip, er);
+}
+
+static int system_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ int remove = 0;
+ int error;
+
+ if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
+ if (!(er->er_flags & GFS2_ERF_MODE)) {
+ er->er_mode = ip->i_di.di_mode;
+ er->er_flags |= GFS2_ERF_MODE;
+ }
+ error = gfs2_acl_validate_set(ip, 1, er,
+ &remove, &er->er_mode);
+ if (error)
+ return error;
+ error = gfs2_ea_set_i(ip, er);
+ if (error)
+ return error;
+ if (remove)
+ gfs2_ea_remove_i(ip, er);
+ return 0;
+
+ } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
+ error = gfs2_acl_validate_set(ip, 0, er,
+ &remove, NULL);
+ if (error)
+ return error;
+ if (!remove)
+ error = gfs2_ea_set_i(ip, er);
+ else {
+ error = gfs2_ea_remove_i(ip, er);
+ if (error == -ENODATA)
+ error = 0;
+ }
+ return error;
+ }
+
+ return -EPERM;
+}
+
+static int system_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ if (GFS2_ACL_IS_ACCESS(er->er_name, er->er_name_len)) {
+ int error = gfs2_acl_validate_remove(ip, 1);
+ if (error)
+ return error;
+
+ } else if (GFS2_ACL_IS_DEFAULT(er->er_name, er->er_name_len)) {
+ int error = gfs2_acl_validate_remove(ip, 0);
+ if (error)
+ return error;
+
+ } else
+ return -EPERM;
+
+ return gfs2_ea_remove_i(ip, er);
+}
+
+static int security_eo_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct inode *inode = &ip->i_inode;
+ int error = permission(inode, MAY_READ, NULL);
+ if (error)
+ return error;
+
+ return gfs2_ea_get_i(ip, er);
+}
+
+static int security_eo_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct inode *inode = &ip->i_inode;
+ int error = permission(inode, MAY_WRITE, NULL);
+ if (error)
+ return error;
+
+ return gfs2_ea_set_i(ip, er);
+}
+
+static int security_eo_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct inode *inode = &ip->i_inode;
+ int error = permission(inode, MAY_WRITE, NULL);
+ if (error)
+ return error;
+
+ return gfs2_ea_remove_i(ip, er);
+}
+
+static struct gfs2_eattr_operations gfs2_user_eaops = {
+ .eo_get = user_eo_get,
+ .eo_set = user_eo_set,
+ .eo_remove = user_eo_remove,
+ .eo_name = "user",
+};
+
+struct gfs2_eattr_operations gfs2_system_eaops = {
+ .eo_get = system_eo_get,
+ .eo_set = system_eo_set,
+ .eo_remove = system_eo_remove,
+ .eo_name = "system",
+};
+
+static struct gfs2_eattr_operations gfs2_security_eaops = {
+ .eo_get = security_eo_get,
+ .eo_set = security_eo_set,
+ .eo_remove = security_eo_remove,
+ .eo_name = "security",
+};
+
+struct gfs2_eattr_operations *gfs2_ea_ops[] = {
+ NULL,
+ &gfs2_user_eaops,
+ &gfs2_system_eaops,
+ &gfs2_security_eaops,
+};
+
diff --git a/fs/gfs2/eaops.h b/fs/gfs2/eaops.h
new file mode 100644
index 000000000000..508b4f7a2449
--- /dev/null
+++ b/fs/gfs2/eaops.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __EAOPS_DOT_H__
+#define __EAOPS_DOT_H__
+
+struct gfs2_ea_request;
+struct gfs2_inode;
+
+struct gfs2_eattr_operations {
+ int (*eo_get) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
+ int (*eo_set) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
+ int (*eo_remove) (struct gfs2_inode *ip, struct gfs2_ea_request *er);
+ char *eo_name;
+};
+
+unsigned int gfs2_ea_name2type(const char *name, const char **truncated_name);
+
+extern struct gfs2_eattr_operations gfs2_system_eaops;
+
+extern struct gfs2_eattr_operations *gfs2_ea_ops[];
+
+#endif /* __EAOPS_DOT_H__ */
+
diff --git a/fs/gfs2/eattr.c b/fs/gfs2/eattr.c
new file mode 100644
index 000000000000..a65a4ccfd4dd
--- /dev/null
+++ b/fs/gfs2/eattr.c
@@ -0,0 +1,1501 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/xattr.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+/**
+ * ea_calc_size - returns the acutal number of bytes the request will take up
+ * (not counting any unstuffed data blocks)
+ * @sdp:
+ * @er:
+ * @size:
+ *
+ * Returns: 1 if the EA should be stuffed
+ */
+
+static int ea_calc_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er,
+ unsigned int *size)
+{
+ *size = GFS2_EAREQ_SIZE_STUFFED(er);
+ if (*size <= sdp->sd_jbsize)
+ return 1;
+
+ *size = GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er);
+
+ return 0;
+}
+
+static int ea_check_size(struct gfs2_sbd *sdp, struct gfs2_ea_request *er)
+{
+ unsigned int size;
+
+ if (er->er_data_len > GFS2_EA_MAX_DATA_LEN)
+ return -ERANGE;
+
+ ea_calc_size(sdp, er, &size);
+
+ /* This can only happen with 512 byte blocks */
+ if (size > sdp->sd_jbsize)
+ return -ERANGE;
+
+ return 0;
+}
+
+typedef int (*ea_call_t) (struct gfs2_inode *ip, struct buffer_head *bh,
+ struct gfs2_ea_header *ea,
+ struct gfs2_ea_header *prev, void *private);
+
+static int ea_foreach_i(struct gfs2_inode *ip, struct buffer_head *bh,
+ ea_call_t ea_call, void *data)
+{
+ struct gfs2_ea_header *ea, *prev = NULL;
+ int error = 0;
+
+ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_EA))
+ return -EIO;
+
+ for (ea = GFS2_EA_BH2FIRST(bh);; prev = ea, ea = GFS2_EA2NEXT(ea)) {
+ if (!GFS2_EA_REC_LEN(ea))
+ goto fail;
+ if (!(bh->b_data <= (char *)ea && (char *)GFS2_EA2NEXT(ea) <=
+ bh->b_data + bh->b_size))
+ goto fail;
+ if (!GFS2_EATYPE_VALID(ea->ea_type))
+ goto fail;
+
+ error = ea_call(ip, bh, ea, prev, data);
+ if (error)
+ return error;
+
+ if (GFS2_EA_IS_LAST(ea)) {
+ if ((char *)GFS2_EA2NEXT(ea) !=
+ bh->b_data + bh->b_size)
+ goto fail;
+ break;
+ }
+ }
+
+ return error;
+
+fail:
+ gfs2_consist_inode(ip);
+ return -EIO;
+}
+
+static int ea_foreach(struct gfs2_inode *ip, ea_call_t ea_call, void *data)
+{
+ struct buffer_head *bh, *eabh;
+ u64 *eablk, *end;
+ int error;
+
+ error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &bh);
+ if (error)
+ return error;
+
+ if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT)) {
+ error = ea_foreach_i(ip, bh, ea_call, data);
+ goto out;
+ }
+
+ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), bh, GFS2_METATYPE_IN)) {
+ error = -EIO;
+ goto out;
+ }
+
+ eablk = (u64 *)(bh->b_data + sizeof(struct gfs2_meta_header));
+ end = eablk + GFS2_SB(&ip->i_inode)->sd_inptrs;
+
+ for (; eablk < end; eablk++) {
+ u64 bn;
+
+ if (!*eablk)
+ break;
+ bn = be64_to_cpu(*eablk);
+
+ error = gfs2_meta_read(ip->i_gl, bn, DIO_WAIT, &eabh);
+ if (error)
+ break;
+ error = ea_foreach_i(ip, eabh, ea_call, data);
+ brelse(eabh);
+ if (error)
+ break;
+ }
+out:
+ brelse(bh);
+ return error;
+}
+
+struct ea_find {
+ struct gfs2_ea_request *ef_er;
+ struct gfs2_ea_location *ef_el;
+};
+
+static int ea_find_i(struct gfs2_inode *ip, struct buffer_head *bh,
+ struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
+ void *private)
+{
+ struct ea_find *ef = private;
+ struct gfs2_ea_request *er = ef->ef_er;
+
+ if (ea->ea_type == GFS2_EATYPE_UNUSED)
+ return 0;
+
+ if (ea->ea_type == er->er_type) {
+ if (ea->ea_name_len == er->er_name_len &&
+ !memcmp(GFS2_EA2NAME(ea), er->er_name, ea->ea_name_len)) {
+ struct gfs2_ea_location *el = ef->ef_el;
+ get_bh(bh);
+ el->el_bh = bh;
+ el->el_ea = ea;
+ el->el_prev = prev;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int gfs2_ea_find(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+ struct gfs2_ea_location *el)
+{
+ struct ea_find ef;
+ int error;
+
+ ef.ef_er = er;
+ ef.ef_el = el;
+
+ memset(el, 0, sizeof(struct gfs2_ea_location));
+
+ error = ea_foreach(ip, ea_find_i, &ef);
+ if (error > 0)
+ return 0;
+
+ return error;
+}
+
+/**
+ * ea_dealloc_unstuffed -
+ * @ip:
+ * @bh:
+ * @ea:
+ * @prev:
+ * @private:
+ *
+ * Take advantage of the fact that all unstuffed blocks are
+ * allocated from the same RG. But watch, this may not always
+ * be true.
+ *
+ * Returns: errno
+ */
+
+static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
+ struct gfs2_ea_header *ea,
+ struct gfs2_ea_header *prev, void *private)
+{
+ int *leave = private;
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_holder rg_gh;
+ struct buffer_head *dibh;
+ u64 *dataptrs, bn = 0;
+ u64 bstart = 0;
+ unsigned int blen = 0;
+ unsigned int blks = 0;
+ unsigned int x;
+ int error;
+
+ if (GFS2_EA_IS_STUFFED(ea))
+ return 0;
+
+ dataptrs = GFS2_EA2DATAPTRS(ea);
+ for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
+ if (*dataptrs) {
+ blks++;
+ bn = be64_to_cpu(*dataptrs);
+ }
+ }
+ if (!blks)
+ return 0;
+
+ rgd = gfs2_blk2rgrpd(sdp, bn);
+ if (!rgd) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
+ if (error)
+ return error;
+
+ error = gfs2_trans_begin(sdp, rgd->rd_ri.ri_length + RES_DINODE +
+ RES_EATTR + RES_STATFS + RES_QUOTA, blks);
+ if (error)
+ goto out_gunlock;
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+ dataptrs = GFS2_EA2DATAPTRS(ea);
+ for (x = 0; x < ea->ea_num_ptrs; x++, dataptrs++) {
+ if (!*dataptrs)
+ break;
+ bn = be64_to_cpu(*dataptrs);
+
+ if (bstart + blen == bn)
+ blen++;
+ else {
+ if (bstart)
+ gfs2_free_meta(ip, bstart, blen);
+ bstart = bn;
+ blen = 1;
+ }
+
+ *dataptrs = 0;
+ if (!ip->i_di.di_blocks)
+ gfs2_consist_inode(ip);
+ ip->i_di.di_blocks--;
+ }
+ if (bstart)
+ gfs2_free_meta(ip, bstart, blen);
+
+ if (prev && !leave) {
+ u32 len;
+
+ len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
+ prev->ea_rec_len = cpu_to_be32(len);
+
+ if (GFS2_EA_IS_LAST(ea))
+ prev->ea_flags |= GFS2_EAFLAG_LAST;
+ } else {
+ ea->ea_type = GFS2_EATYPE_UNUSED;
+ ea->ea_num_ptrs = 0;
+ }
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ ip->i_di.di_ctime = get_seconds();
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(sdp);
+
+out_gunlock:
+ gfs2_glock_dq_uninit(&rg_gh);
+ return error;
+}
+
+static int ea_remove_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
+ struct gfs2_ea_header *ea,
+ struct gfs2_ea_header *prev, int leave)
+{
+ struct gfs2_alloc *al;
+ int error;
+
+ al = gfs2_alloc_get(ip);
+
+ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out_alloc;
+
+ error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
+ if (error)
+ goto out_quota;
+
+ error = ea_dealloc_unstuffed(ip, bh, ea, prev, (leave) ? &error : NULL);
+
+ gfs2_glock_dq_uninit(&al->al_ri_gh);
+
+out_quota:
+ gfs2_quota_unhold(ip);
+out_alloc:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
+struct ea_list {
+ struct gfs2_ea_request *ei_er;
+ unsigned int ei_size;
+};
+
+static int ea_list_i(struct gfs2_inode *ip, struct buffer_head *bh,
+ struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
+ void *private)
+{
+ struct ea_list *ei = private;
+ struct gfs2_ea_request *er = ei->ei_er;
+ unsigned int ea_size = gfs2_ea_strlen(ea);
+
+ if (ea->ea_type == GFS2_EATYPE_UNUSED)
+ return 0;
+
+ if (er->er_data_len) {
+ char *prefix = NULL;
+ unsigned int l = 0;
+ char c = 0;
+
+ if (ei->ei_size + ea_size > er->er_data_len)
+ return -ERANGE;
+
+ switch (ea->ea_type) {
+ case GFS2_EATYPE_USR:
+ prefix = "user.";
+ l = 5;
+ break;
+ case GFS2_EATYPE_SYS:
+ prefix = "system.";
+ l = 7;
+ break;
+ case GFS2_EATYPE_SECURITY:
+ prefix = "security.";
+ l = 9;
+ break;
+ }
+
+ BUG_ON(l == 0);
+
+ memcpy(er->er_data + ei->ei_size, prefix, l);
+ memcpy(er->er_data + ei->ei_size + l, GFS2_EA2NAME(ea),
+ ea->ea_name_len);
+ memcpy(er->er_data + ei->ei_size + ea_size - 1, &c, 1);
+ }
+
+ ei->ei_size += ea_size;
+
+ return 0;
+}
+
+/**
+ * gfs2_ea_list -
+ * @ip:
+ * @er:
+ *
+ * Returns: actual size of data on success, -errno on error
+ */
+
+int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct gfs2_holder i_gh;
+ int error;
+
+ if (!er->er_data || !er->er_data_len) {
+ er->er_data = NULL;
+ er->er_data_len = 0;
+ }
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+ if (error)
+ return error;
+
+ if (ip->i_di.di_eattr) {
+ struct ea_list ei = { .ei_er = er, .ei_size = 0 };
+
+ error = ea_foreach(ip, ea_list_i, &ei);
+ if (!error)
+ error = ei.ei_size;
+ }
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+ return error;
+}
+
+/**
+ * ea_get_unstuffed - actually copies the unstuffed data into the
+ * request buffer
+ * @ip: The GFS2 inode
+ * @ea: The extended attribute header structure
+ * @data: The data to be copied
+ *
+ * Returns: errno
+ */
+
+static int ea_get_unstuffed(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
+ char *data)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head **bh;
+ unsigned int amount = GFS2_EA_DATA_LEN(ea);
+ unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
+ u64 *dataptrs = GFS2_EA2DATAPTRS(ea);
+ unsigned int x;
+ int error = 0;
+
+ bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL);
+ if (!bh)
+ return -ENOMEM;
+
+ for (x = 0; x < nptrs; x++) {
+ error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
+ bh + x);
+ if (error) {
+ while (x--)
+ brelse(bh[x]);
+ goto out;
+ }
+ dataptrs++;
+ }
+
+ for (x = 0; x < nptrs; x++) {
+ error = gfs2_meta_wait(sdp, bh[x]);
+ if (error) {
+ for (; x < nptrs; x++)
+ brelse(bh[x]);
+ goto out;
+ }
+ if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
+ for (; x < nptrs; x++)
+ brelse(bh[x]);
+ error = -EIO;
+ goto out;
+ }
+
+ memcpy(data, bh[x]->b_data + sizeof(struct gfs2_meta_header),
+ (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
+
+ amount -= sdp->sd_jbsize;
+ data += sdp->sd_jbsize;
+
+ brelse(bh[x]);
+ }
+
+out:
+ kfree(bh);
+ return error;
+}
+
+int gfs2_ea_get_copy(struct gfs2_inode *ip, struct gfs2_ea_location *el,
+ char *data)
+{
+ if (GFS2_EA_IS_STUFFED(el->el_ea)) {
+ memcpy(data, GFS2_EA2DATA(el->el_ea), GFS2_EA_DATA_LEN(el->el_ea));
+ return 0;
+ } else
+ return ea_get_unstuffed(ip, el->el_ea, data);
+}
+
+/**
+ * gfs2_ea_get_i -
+ * @ip: The GFS2 inode
+ * @er: The request structure
+ *
+ * Returns: actual size of data on success, -errno on error
+ */
+
+int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct gfs2_ea_location el;
+ int error;
+
+ if (!ip->i_di.di_eattr)
+ return -ENODATA;
+
+ error = gfs2_ea_find(ip, er, &el);
+ if (error)
+ return error;
+ if (!el.el_ea)
+ return -ENODATA;
+
+ if (er->er_data_len) {
+ if (GFS2_EA_DATA_LEN(el.el_ea) > er->er_data_len)
+ error = -ERANGE;
+ else
+ error = gfs2_ea_get_copy(ip, &el, er->er_data);
+ }
+ if (!error)
+ error = GFS2_EA_DATA_LEN(el.el_ea);
+
+ brelse(el.el_bh);
+
+ return error;
+}
+
+/**
+ * gfs2_ea_get -
+ * @ip: The GFS2 inode
+ * @er: The request structure
+ *
+ * Returns: actual size of data on success, -errno on error
+ */
+
+int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct gfs2_holder i_gh;
+ int error;
+
+ if (!er->er_name_len ||
+ er->er_name_len > GFS2_EA_MAX_NAME_LEN)
+ return -EINVAL;
+ if (!er->er_data || !er->er_data_len) {
+ er->er_data = NULL;
+ er->er_data_len = 0;
+ }
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+ if (error)
+ return error;
+
+ error = gfs2_ea_ops[er->er_type]->eo_get(ip, er);
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+ return error;
+}
+
+/**
+ * ea_alloc_blk - allocates a new block for extended attributes.
+ * @ip: A pointer to the inode that's getting extended attributes
+ * @bhp: Pointer to pointer to a struct buffer_head
+ *
+ * Returns: errno
+ */
+
+static int ea_alloc_blk(struct gfs2_inode *ip, struct buffer_head **bhp)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_ea_header *ea;
+ u64 block;
+
+ block = gfs2_alloc_meta(ip);
+
+ *bhp = gfs2_meta_new(ip->i_gl, block);
+ gfs2_trans_add_bh(ip->i_gl, *bhp, 1);
+ gfs2_metatype_set(*bhp, GFS2_METATYPE_EA, GFS2_FORMAT_EA);
+ gfs2_buffer_clear_tail(*bhp, sizeof(struct gfs2_meta_header));
+
+ ea = GFS2_EA_BH2FIRST(*bhp);
+ ea->ea_rec_len = cpu_to_be32(sdp->sd_jbsize);
+ ea->ea_type = GFS2_EATYPE_UNUSED;
+ ea->ea_flags = GFS2_EAFLAG_LAST;
+ ea->ea_num_ptrs = 0;
+
+ ip->i_di.di_blocks++;
+
+ return 0;
+}
+
+/**
+ * ea_write - writes the request info to an ea, creating new blocks if
+ * necessary
+ * @ip: inode that is being modified
+ * @ea: the location of the new ea in a block
+ * @er: the write request
+ *
+ * Note: does not update ea_rec_len or the GFS2_EAFLAG_LAST bin of ea_flags
+ *
+ * returns : errno
+ */
+
+static int ea_write(struct gfs2_inode *ip, struct gfs2_ea_header *ea,
+ struct gfs2_ea_request *er)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+
+ ea->ea_data_len = cpu_to_be32(er->er_data_len);
+ ea->ea_name_len = er->er_name_len;
+ ea->ea_type = er->er_type;
+ ea->__pad = 0;
+
+ memcpy(GFS2_EA2NAME(ea), er->er_name, er->er_name_len);
+
+ if (GFS2_EAREQ_SIZE_STUFFED(er) <= sdp->sd_jbsize) {
+ ea->ea_num_ptrs = 0;
+ memcpy(GFS2_EA2DATA(ea), er->er_data, er->er_data_len);
+ } else {
+ u64 *dataptr = GFS2_EA2DATAPTRS(ea);
+ const char *data = er->er_data;
+ unsigned int data_len = er->er_data_len;
+ unsigned int copy;
+ unsigned int x;
+
+ ea->ea_num_ptrs = DIV_ROUND_UP(er->er_data_len, sdp->sd_jbsize);
+ for (x = 0; x < ea->ea_num_ptrs; x++) {
+ struct buffer_head *bh;
+ u64 block;
+ int mh_size = sizeof(struct gfs2_meta_header);
+
+ block = gfs2_alloc_meta(ip);
+
+ bh = gfs2_meta_new(ip->i_gl, block);
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ gfs2_metatype_set(bh, GFS2_METATYPE_ED, GFS2_FORMAT_ED);
+
+ ip->i_di.di_blocks++;
+
+ copy = data_len > sdp->sd_jbsize ? sdp->sd_jbsize :
+ data_len;
+ memcpy(bh->b_data + mh_size, data, copy);
+ if (copy < sdp->sd_jbsize)
+ memset(bh->b_data + mh_size + copy, 0,
+ sdp->sd_jbsize - copy);
+
+ *dataptr++ = cpu_to_be64(bh->b_blocknr);
+ data += copy;
+ data_len -= copy;
+
+ brelse(bh);
+ }
+
+ gfs2_assert_withdraw(sdp, !data_len);
+ }
+
+ return 0;
+}
+
+typedef int (*ea_skeleton_call_t) (struct gfs2_inode *ip,
+ struct gfs2_ea_request *er, void *private);
+
+static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+ unsigned int blks,
+ ea_skeleton_call_t skeleton_call, void *private)
+{
+ struct gfs2_alloc *al;
+ struct buffer_head *dibh;
+ int error;
+
+ al = gfs2_alloc_get(ip);
+
+ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out;
+
+ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+ if (error)
+ goto out_gunlock_q;
+
+ al->al_requested = blks;
+
+ error = gfs2_inplace_reserve(ip);
+ if (error)
+ goto out_gunlock_q;
+
+ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode),
+ blks + al->al_rgd->rd_ri.ri_length +
+ RES_DINODE + RES_STATFS + RES_QUOTA, 0);
+ if (error)
+ goto out_ipres;
+
+ error = skeleton_call(ip, er, private);
+ if (error)
+ goto out_end_trans;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ if (er->er_flags & GFS2_ERF_MODE) {
+ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
+ (ip->i_di.di_mode & S_IFMT) ==
+ (er->er_mode & S_IFMT));
+ ip->i_di.di_mode = er->er_mode;
+ }
+ ip->i_di.di_ctime = get_seconds();
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+out_end_trans:
+ gfs2_trans_end(GFS2_SB(&ip->i_inode));
+out_ipres:
+ gfs2_inplace_release(ip);
+out_gunlock_q:
+ gfs2_quota_unlock(ip);
+out:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
+static int ea_init_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+ void *private)
+{
+ struct buffer_head *bh;
+ int error;
+
+ error = ea_alloc_blk(ip, &bh);
+ if (error)
+ return error;
+
+ ip->i_di.di_eattr = bh->b_blocknr;
+ error = ea_write(ip, GFS2_EA_BH2FIRST(bh), er);
+
+ brelse(bh);
+
+ return error;
+}
+
+/**
+ * ea_init - initializes a new eattr block
+ * @ip:
+ * @er:
+ *
+ * Returns: errno
+ */
+
+static int ea_init(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ unsigned int jbsize = GFS2_SB(&ip->i_inode)->sd_jbsize;
+ unsigned int blks = 1;
+
+ if (GFS2_EAREQ_SIZE_STUFFED(er) > jbsize)
+ blks += DIV_ROUND_UP(er->er_data_len, jbsize);
+
+ return ea_alloc_skeleton(ip, er, blks, ea_init_i, NULL);
+}
+
+static struct gfs2_ea_header *ea_split_ea(struct gfs2_ea_header *ea)
+{
+ u32 ea_size = GFS2_EA_SIZE(ea);
+ struct gfs2_ea_header *new = (struct gfs2_ea_header *)((char *)ea +
+ ea_size);
+ u32 new_size = GFS2_EA_REC_LEN(ea) - ea_size;
+ int last = ea->ea_flags & GFS2_EAFLAG_LAST;
+
+ ea->ea_rec_len = cpu_to_be32(ea_size);
+ ea->ea_flags ^= last;
+
+ new->ea_rec_len = cpu_to_be32(new_size);
+ new->ea_flags = last;
+
+ return new;
+}
+
+static void ea_set_remove_stuffed(struct gfs2_inode *ip,
+ struct gfs2_ea_location *el)
+{
+ struct gfs2_ea_header *ea = el->el_ea;
+ struct gfs2_ea_header *prev = el->el_prev;
+ u32 len;
+
+ gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
+
+ if (!prev || !GFS2_EA_IS_STUFFED(ea)) {
+ ea->ea_type = GFS2_EATYPE_UNUSED;
+ return;
+ } else if (GFS2_EA2NEXT(prev) != ea) {
+ prev = GFS2_EA2NEXT(prev);
+ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), GFS2_EA2NEXT(prev) == ea);
+ }
+
+ len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
+ prev->ea_rec_len = cpu_to_be32(len);
+
+ if (GFS2_EA_IS_LAST(ea))
+ prev->ea_flags |= GFS2_EAFLAG_LAST;
+}
+
+struct ea_set {
+ int ea_split;
+
+ struct gfs2_ea_request *es_er;
+ struct gfs2_ea_location *es_el;
+
+ struct buffer_head *es_bh;
+ struct gfs2_ea_header *es_ea;
+};
+
+static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
+ struct gfs2_ea_header *ea, struct ea_set *es)
+{
+ struct gfs2_ea_request *er = es->es_er;
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + 2 * RES_EATTR, 0);
+ if (error)
+ return error;
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+
+ if (es->ea_split)
+ ea = ea_split_ea(ea);
+
+ ea_write(ip, ea, er);
+
+ if (es->es_el)
+ ea_set_remove_stuffed(ip, es->es_el);
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out;
+
+ if (er->er_flags & GFS2_ERF_MODE) {
+ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
+ (ip->i_di.di_mode & S_IFMT) == (er->er_mode & S_IFMT));
+ ip->i_di.di_mode = er->er_mode;
+ }
+ ip->i_di.di_ctime = get_seconds();
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+out:
+ gfs2_trans_end(GFS2_SB(&ip->i_inode));
+ return error;
+}
+
+static int ea_set_simple_alloc(struct gfs2_inode *ip,
+ struct gfs2_ea_request *er, void *private)
+{
+ struct ea_set *es = private;
+ struct gfs2_ea_header *ea = es->es_ea;
+ int error;
+
+ gfs2_trans_add_bh(ip->i_gl, es->es_bh, 1);
+
+ if (es->ea_split)
+ ea = ea_split_ea(ea);
+
+ error = ea_write(ip, ea, er);
+ if (error)
+ return error;
+
+ if (es->es_el)
+ ea_set_remove_stuffed(ip, es->es_el);
+
+ return 0;
+}
+
+static int ea_set_simple(struct gfs2_inode *ip, struct buffer_head *bh,
+ struct gfs2_ea_header *ea, struct gfs2_ea_header *prev,
+ void *private)
+{
+ struct ea_set *es = private;
+ unsigned int size;
+ int stuffed;
+ int error;
+
+ stuffed = ea_calc_size(GFS2_SB(&ip->i_inode), es->es_er, &size);
+
+ if (ea->ea_type == GFS2_EATYPE_UNUSED) {
+ if (GFS2_EA_REC_LEN(ea) < size)
+ return 0;
+ if (!GFS2_EA_IS_STUFFED(ea)) {
+ error = ea_remove_unstuffed(ip, bh, ea, prev, 1);
+ if (error)
+ return error;
+ }
+ es->ea_split = 0;
+ } else if (GFS2_EA_REC_LEN(ea) - GFS2_EA_SIZE(ea) >= size)
+ es->ea_split = 1;
+ else
+ return 0;
+
+ if (stuffed) {
+ error = ea_set_simple_noalloc(ip, bh, ea, es);
+ if (error)
+ return error;
+ } else {
+ unsigned int blks;
+
+ es->es_bh = bh;
+ es->es_ea = ea;
+ blks = 2 + DIV_ROUND_UP(es->es_er->er_data_len,
+ GFS2_SB(&ip->i_inode)->sd_jbsize);
+
+ error = ea_alloc_skeleton(ip, es->es_er, blks,
+ ea_set_simple_alloc, es);
+ if (error)
+ return error;
+ }
+
+ return 1;
+}
+
+static int ea_set_block(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+ void *private)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head *indbh, *newbh;
+ u64 *eablk;
+ int error;
+ int mh_size = sizeof(struct gfs2_meta_header);
+
+ if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) {
+ u64 *end;
+
+ error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT,
+ &indbh);
+ if (error)
+ return error;
+
+ if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) {
+ error = -EIO;
+ goto out;
+ }
+
+ eablk = (u64 *)(indbh->b_data + mh_size);
+ end = eablk + sdp->sd_inptrs;
+
+ for (; eablk < end; eablk++)
+ if (!*eablk)
+ break;
+
+ if (eablk == end) {
+ error = -ENOSPC;
+ goto out;
+ }
+
+ gfs2_trans_add_bh(ip->i_gl, indbh, 1);
+ } else {
+ u64 blk;
+
+ blk = gfs2_alloc_meta(ip);
+
+ indbh = gfs2_meta_new(ip->i_gl, blk);
+ gfs2_trans_add_bh(ip->i_gl, indbh, 1);
+ gfs2_metatype_set(indbh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+ gfs2_buffer_clear_tail(indbh, mh_size);
+
+ eablk = (u64 *)(indbh->b_data + mh_size);
+ *eablk = cpu_to_be64(ip->i_di.di_eattr);
+ ip->i_di.di_eattr = blk;
+ ip->i_di.di_flags |= GFS2_DIF_EA_INDIRECT;
+ ip->i_di.di_blocks++;
+
+ eablk++;
+ }
+
+ error = ea_alloc_blk(ip, &newbh);
+ if (error)
+ goto out;
+
+ *eablk = cpu_to_be64((u64)newbh->b_blocknr);
+ error = ea_write(ip, GFS2_EA_BH2FIRST(newbh), er);
+ brelse(newbh);
+ if (error)
+ goto out;
+
+ if (private)
+ ea_set_remove_stuffed(ip, private);
+
+out:
+ brelse(indbh);
+ return error;
+}
+
+static int ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er,
+ struct gfs2_ea_location *el)
+{
+ struct ea_set es;
+ unsigned int blks = 2;
+ int error;
+
+ memset(&es, 0, sizeof(struct ea_set));
+ es.es_er = er;
+ es.es_el = el;
+
+ error = ea_foreach(ip, ea_set_simple, &es);
+ if (error > 0)
+ return 0;
+ if (error)
+ return error;
+
+ if (!(ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT))
+ blks++;
+ if (GFS2_EAREQ_SIZE_STUFFED(er) > GFS2_SB(&ip->i_inode)->sd_jbsize)
+ blks += DIV_ROUND_UP(er->er_data_len, GFS2_SB(&ip->i_inode)->sd_jbsize);
+
+ return ea_alloc_skeleton(ip, er, blks, ea_set_block, el);
+}
+
+static int ea_set_remove_unstuffed(struct gfs2_inode *ip,
+ struct gfs2_ea_location *el)
+{
+ if (el->el_prev && GFS2_EA2NEXT(el->el_prev) != el->el_ea) {
+ el->el_prev = GFS2_EA2NEXT(el->el_prev);
+ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode),
+ GFS2_EA2NEXT(el->el_prev) == el->el_ea);
+ }
+
+ return ea_remove_unstuffed(ip, el->el_bh, el->el_ea, el->el_prev,0);
+}
+
+int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct gfs2_ea_location el;
+ int error;
+
+ if (!ip->i_di.di_eattr) {
+ if (er->er_flags & XATTR_REPLACE)
+ return -ENODATA;
+ return ea_init(ip, er);
+ }
+
+ error = gfs2_ea_find(ip, er, &el);
+ if (error)
+ return error;
+
+ if (el.el_ea) {
+ if (ip->i_di.di_flags & GFS2_DIF_APPENDONLY) {
+ brelse(el.el_bh);
+ return -EPERM;
+ }
+
+ error = -EEXIST;
+ if (!(er->er_flags & XATTR_CREATE)) {
+ int unstuffed = !GFS2_EA_IS_STUFFED(el.el_ea);
+ error = ea_set_i(ip, er, &el);
+ if (!error && unstuffed)
+ ea_set_remove_unstuffed(ip, &el);
+ }
+
+ brelse(el.el_bh);
+ } else {
+ error = -ENODATA;
+ if (!(er->er_flags & XATTR_REPLACE))
+ error = ea_set_i(ip, er, NULL);
+ }
+
+ return error;
+}
+
+int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct gfs2_holder i_gh;
+ int error;
+
+ if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
+ return -EINVAL;
+ if (!er->er_data || !er->er_data_len) {
+ er->er_data = NULL;
+ er->er_data_len = 0;
+ }
+ error = ea_check_size(GFS2_SB(&ip->i_inode), er);
+ if (error)
+ return error;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+ if (error)
+ return error;
+
+ if (IS_IMMUTABLE(&ip->i_inode))
+ error = -EPERM;
+ else
+ error = gfs2_ea_ops[er->er_type]->eo_set(ip, er);
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+ return error;
+}
+
+static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
+{
+ struct gfs2_ea_header *ea = el->el_ea;
+ struct gfs2_ea_header *prev = el->el_prev;
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
+ if (error)
+ return error;
+
+ gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
+
+ if (prev) {
+ u32 len;
+
+ len = GFS2_EA_REC_LEN(prev) + GFS2_EA_REC_LEN(ea);
+ prev->ea_rec_len = cpu_to_be32(len);
+
+ if (GFS2_EA_IS_LAST(ea))
+ prev->ea_flags |= GFS2_EAFLAG_LAST;
+ } else
+ ea->ea_type = GFS2_EATYPE_UNUSED;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ ip->i_di.di_ctime = get_seconds();
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(GFS2_SB(&ip->i_inode));
+
+ return error;
+}
+
+int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct gfs2_ea_location el;
+ int error;
+
+ if (!ip->i_di.di_eattr)
+ return -ENODATA;
+
+ error = gfs2_ea_find(ip, er, &el);
+ if (error)
+ return error;
+ if (!el.el_ea)
+ return -ENODATA;
+
+ if (GFS2_EA_IS_STUFFED(el.el_ea))
+ error = ea_remove_stuffed(ip, &el);
+ else
+ error = ea_remove_unstuffed(ip, el.el_bh, el.el_ea, el.el_prev,
+ 0);
+
+ brelse(el.el_bh);
+
+ return error;
+}
+
+/**
+ * gfs2_ea_remove - sets (or creates or replaces) an extended attribute
+ * @ip: pointer to the inode of the target file
+ * @er: request information
+ *
+ * Returns: errno
+ */
+
+int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er)
+{
+ struct gfs2_holder i_gh;
+ int error;
+
+ if (!er->er_name_len || er->er_name_len > GFS2_EA_MAX_NAME_LEN)
+ return -EINVAL;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+ if (error)
+ return error;
+
+ if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
+ error = -EPERM;
+ else
+ error = gfs2_ea_ops[er->er_type]->eo_remove(ip, er);
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+ return error;
+}
+
+static int ea_acl_chmod_unstuffed(struct gfs2_inode *ip,
+ struct gfs2_ea_header *ea, char *data)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct buffer_head **bh;
+ unsigned int amount = GFS2_EA_DATA_LEN(ea);
+ unsigned int nptrs = DIV_ROUND_UP(amount, sdp->sd_jbsize);
+ u64 *dataptrs = GFS2_EA2DATAPTRS(ea);
+ unsigned int x;
+ int error;
+
+ bh = kcalloc(nptrs, sizeof(struct buffer_head *), GFP_KERNEL);
+ if (!bh)
+ return -ENOMEM;
+
+ error = gfs2_trans_begin(sdp, nptrs + RES_DINODE, 0);
+ if (error)
+ goto out;
+
+ for (x = 0; x < nptrs; x++) {
+ error = gfs2_meta_read(ip->i_gl, be64_to_cpu(*dataptrs), 0,
+ bh + x);
+ if (error) {
+ while (x--)
+ brelse(bh[x]);
+ goto fail;
+ }
+ dataptrs++;
+ }
+
+ for (x = 0; x < nptrs; x++) {
+ error = gfs2_meta_wait(sdp, bh[x]);
+ if (error) {
+ for (; x < nptrs; x++)
+ brelse(bh[x]);
+ goto fail;
+ }
+ if (gfs2_metatype_check(sdp, bh[x], GFS2_METATYPE_ED)) {
+ for (; x < nptrs; x++)
+ brelse(bh[x]);
+ error = -EIO;
+ goto fail;
+ }
+
+ gfs2_trans_add_bh(ip->i_gl, bh[x], 1);
+
+ memcpy(bh[x]->b_data + sizeof(struct gfs2_meta_header), data,
+ (sdp->sd_jbsize > amount) ? amount : sdp->sd_jbsize);
+
+ amount -= sdp->sd_jbsize;
+ data += sdp->sd_jbsize;
+
+ brelse(bh[x]);
+ }
+
+out:
+ kfree(bh);
+ return error;
+
+fail:
+ gfs2_trans_end(sdp);
+ kfree(bh);
+ return error;
+}
+
+int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
+ struct iattr *attr, char *data)
+{
+ struct buffer_head *dibh;
+ int error;
+
+ if (GFS2_EA_IS_STUFFED(el->el_ea)) {
+ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE + RES_EATTR, 0);
+ if (error)
+ return error;
+
+ gfs2_trans_add_bh(ip->i_gl, el->el_bh, 1);
+ memcpy(GFS2_EA2DATA(el->el_ea), data,
+ GFS2_EA_DATA_LEN(el->el_ea));
+ } else
+ error = ea_acl_chmod_unstuffed(ip, el->el_ea, data);
+
+ if (error)
+ return error;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ error = inode_setattr(&ip->i_inode, attr);
+ gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
+ gfs2_inode_attr_out(ip);
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(GFS2_SB(&ip->i_inode));
+
+ return error;
+}
+
+static int ea_dealloc_indirect(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_rgrp_list rlist;
+ struct buffer_head *indbh, *dibh;
+ u64 *eablk, *end;
+ unsigned int rg_blocks = 0;
+ u64 bstart = 0;
+ unsigned int blen = 0;
+ unsigned int blks = 0;
+ unsigned int x;
+ int error;
+
+ memset(&rlist, 0, sizeof(struct gfs2_rgrp_list));
+
+ error = gfs2_meta_read(ip->i_gl, ip->i_di.di_eattr, DIO_WAIT, &indbh);
+ if (error)
+ return error;
+
+ if (gfs2_metatype_check(sdp, indbh, GFS2_METATYPE_IN)) {
+ error = -EIO;
+ goto out;
+ }
+
+ eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header));
+ end = eablk + sdp->sd_inptrs;
+
+ for (; eablk < end; eablk++) {
+ u64 bn;
+
+ if (!*eablk)
+ break;
+ bn = be64_to_cpu(*eablk);
+
+ if (bstart + blen == bn)
+ blen++;
+ else {
+ if (bstart)
+ gfs2_rlist_add(sdp, &rlist, bstart);
+ bstart = bn;
+ blen = 1;
+ }
+ blks++;
+ }
+ if (bstart)
+ gfs2_rlist_add(sdp, &rlist, bstart);
+ else
+ goto out;
+
+ gfs2_rlist_alloc(&rlist, LM_ST_EXCLUSIVE, 0);
+
+ for (x = 0; x < rlist.rl_rgrps; x++) {
+ struct gfs2_rgrpd *rgd;
+ rgd = rlist.rl_ghs[x].gh_gl->gl_object;
+ rg_blocks += rgd->rd_ri.ri_length;
+ }
+
+ error = gfs2_glock_nq_m(rlist.rl_rgrps, rlist.rl_ghs);
+ if (error)
+ goto out_rlist_free;
+
+ error = gfs2_trans_begin(sdp, rg_blocks + RES_DINODE + RES_INDIRECT +
+ RES_STATFS + RES_QUOTA, blks);
+ if (error)
+ goto out_gunlock;
+
+ gfs2_trans_add_bh(ip->i_gl, indbh, 1);
+
+ eablk = (u64 *)(indbh->b_data + sizeof(struct gfs2_meta_header));
+ bstart = 0;
+ blen = 0;
+
+ for (; eablk < end; eablk++) {
+ u64 bn;
+
+ if (!*eablk)
+ break;
+ bn = be64_to_cpu(*eablk);
+
+ if (bstart + blen == bn)
+ blen++;
+ else {
+ if (bstart)
+ gfs2_free_meta(ip, bstart, blen);
+ bstart = bn;
+ blen = 1;
+ }
+
+ *eablk = 0;
+ if (!ip->i_di.di_blocks)
+ gfs2_consist_inode(ip);
+ ip->i_di.di_blocks--;
+ }
+ if (bstart)
+ gfs2_free_meta(ip, bstart, blen);
+
+ ip->i_di.di_flags &= ~GFS2_DIF_EA_INDIRECT;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(sdp);
+
+out_gunlock:
+ gfs2_glock_dq_m(rlist.rl_rgrps, rlist.rl_ghs);
+out_rlist_free:
+ gfs2_rlist_free(&rlist);
+out:
+ brelse(indbh);
+ return error;
+}
+
+static int ea_dealloc_block(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_rgrpd *rgd;
+ struct buffer_head *dibh;
+ int error;
+
+ rgd = gfs2_blk2rgrpd(sdp, ip->i_di.di_eattr);
+ if (!rgd) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
+ &al->al_rgd_gh);
+ if (error)
+ return error;
+
+ error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_DINODE + RES_STATFS +
+ RES_QUOTA, 1);
+ if (error)
+ goto out_gunlock;
+
+ gfs2_free_meta(ip, ip->i_di.di_eattr, 1);
+
+ ip->i_di.di_eattr = 0;
+ if (!ip->i_di.di_blocks)
+ gfs2_consist_inode(ip);
+ ip->i_di.di_blocks--;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(sdp);
+
+out_gunlock:
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ return error;
+}
+
+/**
+ * gfs2_ea_dealloc - deallocate the extended attribute fork
+ * @ip: the inode
+ *
+ * Returns: errno
+ */
+
+int gfs2_ea_dealloc(struct gfs2_inode *ip)
+{
+ struct gfs2_alloc *al;
+ int error;
+
+ al = gfs2_alloc_get(ip);
+
+ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out_alloc;
+
+ error = gfs2_rindex_hold(GFS2_SB(&ip->i_inode), &al->al_ri_gh);
+ if (error)
+ goto out_quota;
+
+ error = ea_foreach(ip, ea_dealloc_unstuffed, NULL);
+ if (error)
+ goto out_rindex;
+
+ if (ip->i_di.di_flags & GFS2_DIF_EA_INDIRECT) {
+ error = ea_dealloc_indirect(ip);
+ if (error)
+ goto out_rindex;
+ }
+
+ error = ea_dealloc_block(ip);
+
+out_rindex:
+ gfs2_glock_dq_uninit(&al->al_ri_gh);
+out_quota:
+ gfs2_quota_unhold(ip);
+out_alloc:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
diff --git a/fs/gfs2/eattr.h b/fs/gfs2/eattr.h
new file mode 100644
index 000000000000..ffa65947d686
--- /dev/null
+++ b/fs/gfs2/eattr.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __EATTR_DOT_H__
+#define __EATTR_DOT_H__
+
+struct gfs2_inode;
+struct iattr;
+
+#define GFS2_EA_REC_LEN(ea) be32_to_cpu((ea)->ea_rec_len)
+#define GFS2_EA_DATA_LEN(ea) be32_to_cpu((ea)->ea_data_len)
+
+#define GFS2_EA_SIZE(ea) \
+ALIGN(sizeof(struct gfs2_ea_header) + (ea)->ea_name_len + \
+ ((GFS2_EA_IS_STUFFED(ea)) ? GFS2_EA_DATA_LEN(ea) : \
+ (sizeof(u64) * (ea)->ea_num_ptrs)), 8)
+
+#define GFS2_EA_IS_STUFFED(ea) (!(ea)->ea_num_ptrs)
+#define GFS2_EA_IS_LAST(ea) ((ea)->ea_flags & GFS2_EAFLAG_LAST)
+
+#define GFS2_EAREQ_SIZE_STUFFED(er) \
+ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + (er)->er_data_len, 8)
+
+#define GFS2_EAREQ_SIZE_UNSTUFFED(sdp, er) \
+ALIGN(sizeof(struct gfs2_ea_header) + (er)->er_name_len + \
+ sizeof(u64) * DIV_ROUND_UP((er)->er_data_len, (sdp)->sd_jbsize), 8)
+
+#define GFS2_EA2NAME(ea) ((char *)((struct gfs2_ea_header *)(ea) + 1))
+#define GFS2_EA2DATA(ea) (GFS2_EA2NAME(ea) + (ea)->ea_name_len)
+
+#define GFS2_EA2DATAPTRS(ea) \
+((u64 *)(GFS2_EA2NAME(ea) + ALIGN((ea)->ea_name_len, 8)))
+
+#define GFS2_EA2NEXT(ea) \
+((struct gfs2_ea_header *)((char *)(ea) + GFS2_EA_REC_LEN(ea)))
+
+#define GFS2_EA_BH2FIRST(bh) \
+((struct gfs2_ea_header *)((bh)->b_data + sizeof(struct gfs2_meta_header)))
+
+#define GFS2_ERF_MODE 0x80000000
+
+struct gfs2_ea_request {
+ const char *er_name;
+ char *er_data;
+ unsigned int er_name_len;
+ unsigned int er_data_len;
+ unsigned int er_type; /* GFS2_EATYPE_... */
+ int er_flags;
+ mode_t er_mode;
+};
+
+struct gfs2_ea_location {
+ struct buffer_head *el_bh;
+ struct gfs2_ea_header *el_ea;
+ struct gfs2_ea_header *el_prev;
+};
+
+int gfs2_ea_get_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_set_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_remove_i(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+
+int gfs2_ea_list(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_get(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_set(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+int gfs2_ea_remove(struct gfs2_inode *ip, struct gfs2_ea_request *er);
+
+int gfs2_ea_dealloc(struct gfs2_inode *ip);
+
+/* Exported to acl.c */
+
+int gfs2_ea_find(struct gfs2_inode *ip,
+ struct gfs2_ea_request *er,
+ struct gfs2_ea_location *el);
+int gfs2_ea_get_copy(struct gfs2_inode *ip,
+ struct gfs2_ea_location *el,
+ char *data);
+int gfs2_ea_acl_chmod(struct gfs2_inode *ip, struct gfs2_ea_location *el,
+ struct iattr *attr, char *data);
+
+static inline unsigned int gfs2_ea_strlen(struct gfs2_ea_header *ea)
+{
+ switch (ea->ea_type) {
+ case GFS2_EATYPE_USR:
+ return 5 + ea->ea_name_len + 1;
+ case GFS2_EATYPE_SYS:
+ return 7 + ea->ea_name_len + 1;
+ case GFS2_EATYPE_SECURITY:
+ return 9 + ea->ea_name_len + 1;
+ default:
+ return 0;
+ }
+}
+
+#endif /* __EATTR_DOT_H__ */
diff --git a/fs/gfs2/gfs2.h b/fs/gfs2/gfs2.h
new file mode 100644
index 000000000000..3bb11c0f8b56
--- /dev/null
+++ b/fs/gfs2/gfs2.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __GFS2_DOT_H__
+#define __GFS2_DOT_H__
+
+enum {
+ NO_CREATE = 0,
+ CREATE = 1,
+};
+
+enum {
+ NO_WAIT = 0,
+ WAIT = 1,
+};
+
+enum {
+ NO_FORCE = 0,
+ FORCE = 1,
+};
+
+#define GFS2_FAST_NAME_SIZE 8
+
+#endif /* __GFS2_DOT_H__ */
+
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
new file mode 100644
index 000000000000..78fe0fae23ff
--- /dev/null
+++ b/fs/gfs2/glock.c
@@ -0,0 +1,2231 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/delay.h>
+#include <linux/sort.h>
+#include <linux/jhash.h>
+#include <linux/kallsyms.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/list.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "lm.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "super.h"
+#include "util.h"
+
+struct greedy {
+ struct gfs2_holder gr_gh;
+ struct work_struct gr_work;
+};
+
+struct gfs2_gl_hash_bucket {
+ struct hlist_head hb_list;
+};
+
+typedef void (*glock_examiner) (struct gfs2_glock * gl);
+
+static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
+static int dump_glock(struct gfs2_glock *gl);
+static int dump_inode(struct gfs2_inode *ip);
+
+#define GFS2_GL_HASH_SHIFT 15
+#define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT)
+#define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1)
+
+static struct gfs2_gl_hash_bucket gl_hash_table[GFS2_GL_HASH_SIZE];
+
+/*
+ * Despite what you might think, the numbers below are not arbitrary :-)
+ * They are taken from the ipv4 routing hash code, which is well tested
+ * and thus should be nearly optimal. Later on we might tweek the numbers
+ * but for now this should be fine.
+ *
+ * The reason for putting the locks in a separate array from the list heads
+ * is that we can have fewer locks than list heads and save memory. We use
+ * the same hash function for both, but with a different hash mask.
+ */
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \
+ defined(CONFIG_PROVE_LOCKING)
+
+#ifdef CONFIG_LOCKDEP
+# define GL_HASH_LOCK_SZ 256
+#else
+# if NR_CPUS >= 32
+# define GL_HASH_LOCK_SZ 4096
+# elif NR_CPUS >= 16
+# define GL_HASH_LOCK_SZ 2048
+# elif NR_CPUS >= 8
+# define GL_HASH_LOCK_SZ 1024
+# elif NR_CPUS >= 4
+# define GL_HASH_LOCK_SZ 512
+# else
+# define GL_HASH_LOCK_SZ 256
+# endif
+#endif
+
+/* We never want more locks than chains */
+#if GFS2_GL_HASH_SIZE < GL_HASH_LOCK_SZ
+# undef GL_HASH_LOCK_SZ
+# define GL_HASH_LOCK_SZ GFS2_GL_HASH_SIZE
+#endif
+
+static rwlock_t gl_hash_locks[GL_HASH_LOCK_SZ];
+
+static inline rwlock_t *gl_lock_addr(unsigned int x)
+{
+ return &gl_hash_locks[x & (GL_HASH_LOCK_SZ-1)];
+}
+#else /* not SMP, so no spinlocks required */
+static inline rwlock_t *gl_lock_addr(x)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * relaxed_state_ok - is a requested lock compatible with the current lock mode?
+ * @actual: the current state of the lock
+ * @requested: the lock state that was requested by the caller
+ * @flags: the modifier flags passed in by the caller
+ *
+ * Returns: 1 if the locks are compatible, 0 otherwise
+ */
+
+static inline int relaxed_state_ok(unsigned int actual, unsigned requested,
+ int flags)
+{
+ if (actual == requested)
+ return 1;
+
+ if (flags & GL_EXACT)
+ return 0;
+
+ if (actual == LM_ST_EXCLUSIVE && requested == LM_ST_SHARED)
+ return 1;
+
+ if (actual != LM_ST_UNLOCKED && (flags & LM_FLAG_ANY))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * gl_hash() - Turn glock number into hash bucket number
+ * @lock: The glock number
+ *
+ * Returns: The number of the corresponding hash bucket
+ */
+
+static unsigned int gl_hash(const struct gfs2_sbd *sdp,
+ const struct lm_lockname *name)
+{
+ unsigned int h;
+
+ h = jhash(&name->ln_number, sizeof(u64), 0);
+ h = jhash(&name->ln_type, sizeof(unsigned int), h);
+ h = jhash(&sdp, sizeof(struct gfs2_sbd *), h);
+ h &= GFS2_GL_HASH_MASK;
+
+ return h;
+}
+
+/**
+ * glock_free() - Perform a few checks and then release struct gfs2_glock
+ * @gl: The glock to release
+ *
+ * Also calls lock module to release its internal structure for this glock.
+ *
+ */
+
+static void glock_free(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct inode *aspace = gl->gl_aspace;
+
+ gfs2_lm_put_lock(sdp, gl->gl_lock);
+
+ if (aspace)
+ gfs2_aspace_put(aspace);
+
+ kmem_cache_free(gfs2_glock_cachep, gl);
+}
+
+/**
+ * gfs2_glock_hold() - increment reference count on glock
+ * @gl: The glock to hold
+ *
+ */
+
+void gfs2_glock_hold(struct gfs2_glock *gl)
+{
+ atomic_inc(&gl->gl_ref);
+}
+
+/**
+ * gfs2_glock_put() - Decrement reference count on glock
+ * @gl: The glock to put
+ *
+ */
+
+int gfs2_glock_put(struct gfs2_glock *gl)
+{
+ int rv = 0;
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+
+ write_lock(gl_lock_addr(gl->gl_hash));
+ if (atomic_dec_and_test(&gl->gl_ref)) {
+ hlist_del(&gl->gl_list);
+ write_unlock(gl_lock_addr(gl->gl_hash));
+ BUG_ON(spin_is_locked(&gl->gl_spin));
+ gfs2_assert(sdp, gl->gl_state == LM_ST_UNLOCKED);
+ gfs2_assert(sdp, list_empty(&gl->gl_reclaim));
+ gfs2_assert(sdp, list_empty(&gl->gl_holders));
+ gfs2_assert(sdp, list_empty(&gl->gl_waiters1));
+ gfs2_assert(sdp, list_empty(&gl->gl_waiters2));
+ gfs2_assert(sdp, list_empty(&gl->gl_waiters3));
+ glock_free(gl);
+ rv = 1;
+ goto out;
+ }
+ write_unlock(gl_lock_addr(gl->gl_hash));
+out:
+ return rv;
+}
+
+/**
+ * queue_empty - check to see if a glock's queue is empty
+ * @gl: the glock
+ * @head: the head of the queue to check
+ *
+ * This function protects the list in the event that a process already
+ * has a holder on the list and is adding a second holder for itself.
+ * The glmutex lock is what generally prevents processes from working
+ * on the same glock at once, but the special case of adding a second
+ * holder for yourself ("recursive" locking) doesn't involve locking
+ * glmutex, making the spin lock necessary.
+ *
+ * Returns: 1 if the queue is empty
+ */
+
+static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head)
+{
+ int empty;
+ spin_lock(&gl->gl_spin);
+ empty = list_empty(head);
+ spin_unlock(&gl->gl_spin);
+ return empty;
+}
+
+/**
+ * search_bucket() - Find struct gfs2_glock by lock number
+ * @bucket: the bucket to search
+ * @name: The lock name
+ *
+ * Returns: NULL, or the struct gfs2_glock with the requested number
+ */
+
+static struct gfs2_glock *search_bucket(unsigned int hash,
+ const struct gfs2_sbd *sdp,
+ const struct lm_lockname *name)
+{
+ struct gfs2_glock *gl;
+ struct hlist_node *h;
+
+ hlist_for_each_entry(gl, h, &gl_hash_table[hash].hb_list, gl_list) {
+ if (!lm_name_equal(&gl->gl_name, name))
+ continue;
+ if (gl->gl_sbd != sdp)
+ continue;
+
+ atomic_inc(&gl->gl_ref);
+
+ return gl;
+ }
+
+ return NULL;
+}
+
+/**
+ * gfs2_glock_find() - Find glock by lock number
+ * @sdp: The GFS2 superblock
+ * @name: The lock name
+ *
+ * Returns: NULL, or the struct gfs2_glock with the requested number
+ */
+
+static struct gfs2_glock *gfs2_glock_find(const struct gfs2_sbd *sdp,
+ const struct lm_lockname *name)
+{
+ unsigned int hash = gl_hash(sdp, name);
+ struct gfs2_glock *gl;
+
+ read_lock(gl_lock_addr(hash));
+ gl = search_bucket(hash, sdp, name);
+ read_unlock(gl_lock_addr(hash));
+
+ return gl;
+}
+
+/**
+ * gfs2_glock_get() - Get a glock, or create one if one doesn't exist
+ * @sdp: The GFS2 superblock
+ * @number: the lock number
+ * @glops: The glock_operations to use
+ * @create: If 0, don't create the glock if it doesn't exist
+ * @glp: the glock is returned here
+ *
+ * This does not lock a glock, just finds/creates structures for one.
+ *
+ * Returns: errno
+ */
+
+int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number,
+ const struct gfs2_glock_operations *glops, int create,
+ struct gfs2_glock **glp)
+{
+ struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type };
+ struct gfs2_glock *gl, *tmp;
+ unsigned int hash = gl_hash(sdp, &name);
+ int error;
+
+ read_lock(gl_lock_addr(hash));
+ gl = search_bucket(hash, sdp, &name);
+ read_unlock(gl_lock_addr(hash));
+
+ if (gl || !create) {
+ *glp = gl;
+ return 0;
+ }
+
+ gl = kmem_cache_alloc(gfs2_glock_cachep, GFP_KERNEL);
+ if (!gl)
+ return -ENOMEM;
+
+ gl->gl_flags = 0;
+ gl->gl_name = name;
+ atomic_set(&gl->gl_ref, 1);
+ gl->gl_state = LM_ST_UNLOCKED;
+ gl->gl_hash = hash;
+ gl->gl_owner = NULL;
+ gl->gl_ip = 0;
+ gl->gl_ops = glops;
+ gl->gl_req_gh = NULL;
+ gl->gl_req_bh = NULL;
+ gl->gl_vn = 0;
+ gl->gl_stamp = jiffies;
+ gl->gl_object = NULL;
+ gl->gl_sbd = sdp;
+ gl->gl_aspace = NULL;
+ lops_init_le(&gl->gl_le, &gfs2_glock_lops);
+
+ /* If this glock protects actual on-disk data or metadata blocks,
+ create a VFS inode to manage the pages/buffers holding them. */
+ if (glops == &gfs2_inode_glops || glops == &gfs2_rgrp_glops) {
+ gl->gl_aspace = gfs2_aspace_get(sdp);
+ if (!gl->gl_aspace) {
+ error = -ENOMEM;
+ goto fail;
+ }
+ }
+
+ error = gfs2_lm_get_lock(sdp, &name, &gl->gl_lock);
+ if (error)
+ goto fail_aspace;
+
+ write_lock(gl_lock_addr(hash));
+ tmp = search_bucket(hash, sdp, &name);
+ if (tmp) {
+ write_unlock(gl_lock_addr(hash));
+ glock_free(gl);
+ gl = tmp;
+ } else {
+ hlist_add_head(&gl->gl_list, &gl_hash_table[hash].hb_list);
+ write_unlock(gl_lock_addr(hash));
+ }
+
+ *glp = gl;
+
+ return 0;
+
+fail_aspace:
+ if (gl->gl_aspace)
+ gfs2_aspace_put(gl->gl_aspace);
+fail:
+ kmem_cache_free(gfs2_glock_cachep, gl);
+ return error;
+}
+
+/**
+ * gfs2_holder_init - initialize a struct gfs2_holder in the default way
+ * @gl: the glock
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gh: the holder structure
+ *
+ */
+
+void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
+ struct gfs2_holder *gh)
+{
+ INIT_LIST_HEAD(&gh->gh_list);
+ gh->gh_gl = gl;
+ gh->gh_ip = (unsigned long)__builtin_return_address(0);
+ gh->gh_owner = current;
+ gh->gh_state = state;
+ gh->gh_flags = flags;
+ gh->gh_error = 0;
+ gh->gh_iflags = 0;
+ init_completion(&gh->gh_wait);
+
+ if (gh->gh_state == LM_ST_EXCLUSIVE)
+ gh->gh_flags |= GL_LOCAL_EXCL;
+
+ gfs2_glock_hold(gl);
+}
+
+/**
+ * gfs2_holder_reinit - reinitialize a struct gfs2_holder so we can requeue it
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gh: the holder structure
+ *
+ * Don't mess with the glock.
+ *
+ */
+
+void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *gh)
+{
+ gh->gh_state = state;
+ gh->gh_flags = flags;
+ if (gh->gh_state == LM_ST_EXCLUSIVE)
+ gh->gh_flags |= GL_LOCAL_EXCL;
+
+ gh->gh_iflags &= 1 << HIF_ALLOCED;
+ gh->gh_ip = (unsigned long)__builtin_return_address(0);
+}
+
+/**
+ * gfs2_holder_uninit - uninitialize a holder structure (drop glock reference)
+ * @gh: the holder structure
+ *
+ */
+
+void gfs2_holder_uninit(struct gfs2_holder *gh)
+{
+ gfs2_glock_put(gh->gh_gl);
+ gh->gh_gl = NULL;
+ gh->gh_ip = 0;
+}
+
+/**
+ * gfs2_holder_get - get a struct gfs2_holder structure
+ * @gl: the glock
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gfp_flags:
+ *
+ * Figure out how big an impact this function has. Either:
+ * 1) Replace it with a cache of structures hanging off the struct gfs2_sbd
+ * 2) Leave it like it is
+ *
+ * Returns: the holder structure, NULL on ENOMEM
+ */
+
+static struct gfs2_holder *gfs2_holder_get(struct gfs2_glock *gl,
+ unsigned int state,
+ int flags, gfp_t gfp_flags)
+{
+ struct gfs2_holder *gh;
+
+ gh = kmalloc(sizeof(struct gfs2_holder), gfp_flags);
+ if (!gh)
+ return NULL;
+
+ gfs2_holder_init(gl, state, flags, gh);
+ set_bit(HIF_ALLOCED, &gh->gh_iflags);
+ gh->gh_ip = (unsigned long)__builtin_return_address(0);
+ return gh;
+}
+
+/**
+ * gfs2_holder_put - get rid of a struct gfs2_holder structure
+ * @gh: the holder structure
+ *
+ */
+
+static void gfs2_holder_put(struct gfs2_holder *gh)
+{
+ gfs2_holder_uninit(gh);
+ kfree(gh);
+}
+
+/**
+ * rq_mutex - process a mutex request in the queue
+ * @gh: the glock holder
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_mutex(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+
+ list_del_init(&gh->gh_list);
+ /* gh->gh_error never examined. */
+ set_bit(GLF_LOCK, &gl->gl_flags);
+ complete(&gh->gh_wait);
+
+ return 1;
+}
+
+/**
+ * rq_promote - process a promote request in the queue
+ * @gh: the glock holder
+ *
+ * Acquire a new inter-node lock, or change a lock state to more restrictive.
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_promote(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+ if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
+ if (list_empty(&gl->gl_holders)) {
+ gl->gl_req_gh = gh;
+ set_bit(GLF_LOCK, &gl->gl_flags);
+ spin_unlock(&gl->gl_spin);
+
+ if (atomic_read(&sdp->sd_reclaim_count) >
+ gfs2_tune_get(sdp, gt_reclaim_limit) &&
+ !(gh->gh_flags & LM_FLAG_PRIORITY)) {
+ gfs2_reclaim_glock(sdp);
+ gfs2_reclaim_glock(sdp);
+ }
+
+ glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+ spin_lock(&gl->gl_spin);
+ }
+ return 1;
+ }
+
+ if (list_empty(&gl->gl_holders)) {
+ set_bit(HIF_FIRST, &gh->gh_iflags);
+ set_bit(GLF_LOCK, &gl->gl_flags);
+ } else {
+ struct gfs2_holder *next_gh;
+ if (gh->gh_flags & GL_LOCAL_EXCL)
+ return 1;
+ next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder,
+ gh_list);
+ if (next_gh->gh_flags & GL_LOCAL_EXCL)
+ return 1;
+ }
+
+ list_move_tail(&gh->gh_list, &gl->gl_holders);
+ gh->gh_error = 0;
+ set_bit(HIF_HOLDER, &gh->gh_iflags);
+
+ complete(&gh->gh_wait);
+
+ return 0;
+}
+
+/**
+ * rq_demote - process a demote request in the queue
+ * @gh: the glock holder
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_demote(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+ if (!list_empty(&gl->gl_holders))
+ return 1;
+
+ if (gl->gl_state == gh->gh_state || gl->gl_state == LM_ST_UNLOCKED) {
+ list_del_init(&gh->gh_list);
+ gh->gh_error = 0;
+ spin_unlock(&gl->gl_spin);
+ if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
+ gfs2_holder_put(gh);
+ else
+ complete(&gh->gh_wait);
+ spin_lock(&gl->gl_spin);
+ } else {
+ gl->gl_req_gh = gh;
+ set_bit(GLF_LOCK, &gl->gl_flags);
+ spin_unlock(&gl->gl_spin);
+
+ if (gh->gh_state == LM_ST_UNLOCKED ||
+ gl->gl_state != LM_ST_EXCLUSIVE)
+ glops->go_drop_th(gl);
+ else
+ glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+
+ spin_lock(&gl->gl_spin);
+ }
+
+ return 0;
+}
+
+/**
+ * rq_greedy - process a queued request to drop greedy status
+ * @gh: the glock holder
+ *
+ * Returns: 1 if the queue is blocked
+ */
+
+static int rq_greedy(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+
+ list_del_init(&gh->gh_list);
+ /* gh->gh_error never examined. */
+ clear_bit(GLF_GREEDY, &gl->gl_flags);
+ spin_unlock(&gl->gl_spin);
+
+ gfs2_holder_uninit(gh);
+ kfree(container_of(gh, struct greedy, gr_gh));
+
+ spin_lock(&gl->gl_spin);
+
+ return 0;
+}
+
+/**
+ * run_queue - process holder structures on a glock
+ * @gl: the glock
+ *
+ */
+static void run_queue(struct gfs2_glock *gl)
+{
+ struct gfs2_holder *gh;
+ int blocked = 1;
+
+ for (;;) {
+ if (test_bit(GLF_LOCK, &gl->gl_flags))
+ break;
+
+ if (!list_empty(&gl->gl_waiters1)) {
+ gh = list_entry(gl->gl_waiters1.next,
+ struct gfs2_holder, gh_list);
+
+ if (test_bit(HIF_MUTEX, &gh->gh_iflags))
+ blocked = rq_mutex(gh);
+ else
+ gfs2_assert_warn(gl->gl_sbd, 0);
+
+ } else if (!list_empty(&gl->gl_waiters2) &&
+ !test_bit(GLF_SKIP_WAITERS2, &gl->gl_flags)) {
+ gh = list_entry(gl->gl_waiters2.next,
+ struct gfs2_holder, gh_list);
+
+ if (test_bit(HIF_DEMOTE, &gh->gh_iflags))
+ blocked = rq_demote(gh);
+ else if (test_bit(HIF_GREEDY, &gh->gh_iflags))
+ blocked = rq_greedy(gh);
+ else
+ gfs2_assert_warn(gl->gl_sbd, 0);
+
+ } else if (!list_empty(&gl->gl_waiters3)) {
+ gh = list_entry(gl->gl_waiters3.next,
+ struct gfs2_holder, gh_list);
+
+ if (test_bit(HIF_PROMOTE, &gh->gh_iflags))
+ blocked = rq_promote(gh);
+ else
+ gfs2_assert_warn(gl->gl_sbd, 0);
+
+ } else
+ break;
+
+ if (blocked)
+ break;
+ }
+}
+
+/**
+ * gfs2_glmutex_lock - acquire a local lock on a glock
+ * @gl: the glock
+ *
+ * Gives caller exclusive access to manipulate a glock structure.
+ */
+
+static void gfs2_glmutex_lock(struct gfs2_glock *gl)
+{
+ struct gfs2_holder gh;
+
+ gfs2_holder_init(gl, 0, 0, &gh);
+ set_bit(HIF_MUTEX, &gh.gh_iflags);
+
+ spin_lock(&gl->gl_spin);
+ if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
+ list_add_tail(&gh.gh_list, &gl->gl_waiters1);
+ } else {
+ gl->gl_owner = current;
+ gl->gl_ip = (unsigned long)__builtin_return_address(0);
+ complete(&gh.gh_wait);
+ }
+ spin_unlock(&gl->gl_spin);
+
+ wait_for_completion(&gh.gh_wait);
+ gfs2_holder_uninit(&gh);
+}
+
+/**
+ * gfs2_glmutex_trylock - try to acquire a local lock on a glock
+ * @gl: the glock
+ *
+ * Returns: 1 if the glock is acquired
+ */
+
+static int gfs2_glmutex_trylock(struct gfs2_glock *gl)
+{
+ int acquired = 1;
+
+ spin_lock(&gl->gl_spin);
+ if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
+ acquired = 0;
+ } else {
+ gl->gl_owner = current;
+ gl->gl_ip = (unsigned long)__builtin_return_address(0);
+ }
+ spin_unlock(&gl->gl_spin);
+
+ return acquired;
+}
+
+/**
+ * gfs2_glmutex_unlock - release a local lock on a glock
+ * @gl: the glock
+ *
+ */
+
+static void gfs2_glmutex_unlock(struct gfs2_glock *gl)
+{
+ spin_lock(&gl->gl_spin);
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+ gl->gl_owner = NULL;
+ gl->gl_ip = 0;
+ run_queue(gl);
+ BUG_ON(!spin_is_locked(&gl->gl_spin));
+ spin_unlock(&gl->gl_spin);
+}
+
+/**
+ * handle_callback - add a demote request to a lock's queue
+ * @gl: the glock
+ * @state: the state the caller wants us to change to
+ *
+ * Note: This may fail sliently if we are out of memory.
+ */
+
+static void handle_callback(struct gfs2_glock *gl, unsigned int state)
+{
+ struct gfs2_holder *gh, *new_gh = NULL;
+
+restart:
+ spin_lock(&gl->gl_spin);
+
+ list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
+ if (test_bit(HIF_DEMOTE, &gh->gh_iflags) &&
+ gl->gl_req_gh != gh) {
+ if (gh->gh_state != state)
+ gh->gh_state = LM_ST_UNLOCKED;
+ goto out;
+ }
+ }
+
+ if (new_gh) {
+ list_add_tail(&new_gh->gh_list, &gl->gl_waiters2);
+ new_gh = NULL;
+ } else {
+ spin_unlock(&gl->gl_spin);
+
+ new_gh = gfs2_holder_get(gl, state, LM_FLAG_TRY, GFP_KERNEL);
+ if (!new_gh)
+ return;
+ set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
+ set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
+
+ goto restart;
+ }
+
+out:
+ spin_unlock(&gl->gl_spin);
+
+ if (new_gh)
+ gfs2_holder_put(new_gh);
+}
+
+void gfs2_glock_inode_squish(struct inode *inode)
+{
+ struct gfs2_holder gh;
+ struct gfs2_glock *gl = GFS2_I(inode)->i_gl;
+ gfs2_holder_init(gl, LM_ST_UNLOCKED, 0, &gh);
+ set_bit(HIF_DEMOTE, &gh.gh_iflags);
+ spin_lock(&gl->gl_spin);
+ gfs2_assert(inode->i_sb->s_fs_info, list_empty(&gl->gl_holders));
+ list_add_tail(&gh.gh_list, &gl->gl_waiters2);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+ wait_for_completion(&gh.gh_wait);
+ gfs2_holder_uninit(&gh);
+}
+
+/**
+ * state_change - record that the glock is now in a different state
+ * @gl: the glock
+ * @new_state the new state
+ *
+ */
+
+static void state_change(struct gfs2_glock *gl, unsigned int new_state)
+{
+ int held1, held2;
+
+ held1 = (gl->gl_state != LM_ST_UNLOCKED);
+ held2 = (new_state != LM_ST_UNLOCKED);
+
+ if (held1 != held2) {
+ if (held2)
+ gfs2_glock_hold(gl);
+ else
+ gfs2_glock_put(gl);
+ }
+
+ gl->gl_state = new_state;
+}
+
+/**
+ * xmote_bh - Called after the lock module is done acquiring a lock
+ * @gl: The glock in question
+ * @ret: the int returned from the lock module
+ *
+ */
+
+static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+ struct gfs2_holder *gh = gl->gl_req_gh;
+ int prev_state = gl->gl_state;
+ int op_done = 1;
+
+ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+ gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC));
+
+ state_change(gl, ret & LM_OUT_ST_MASK);
+
+ if (prev_state != LM_ST_UNLOCKED && !(ret & LM_OUT_CACHEABLE)) {
+ if (glops->go_inval)
+ glops->go_inval(gl, DIO_METADATA | DIO_DATA);
+ } else if (gl->gl_state == LM_ST_DEFERRED) {
+ /* We might not want to do this here.
+ Look at moving to the inode glops. */
+ if (glops->go_inval)
+ glops->go_inval(gl, DIO_DATA);
+ }
+
+ /* Deal with each possible exit condition */
+
+ if (!gh)
+ gl->gl_stamp = jiffies;
+ else if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+ spin_lock(&gl->gl_spin);
+ list_del_init(&gh->gh_list);
+ gh->gh_error = -EIO;
+ spin_unlock(&gl->gl_spin);
+ } else if (test_bit(HIF_DEMOTE, &gh->gh_iflags)) {
+ spin_lock(&gl->gl_spin);
+ list_del_init(&gh->gh_list);
+ if (gl->gl_state == gh->gh_state ||
+ gl->gl_state == LM_ST_UNLOCKED) {
+ gh->gh_error = 0;
+ } else {
+ if (gfs2_assert_warn(sdp, gh->gh_flags &
+ (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) == -1)
+ fs_warn(sdp, "ret = 0x%.8X\n", ret);
+ gh->gh_error = GLR_TRYFAILED;
+ }
+ spin_unlock(&gl->gl_spin);
+
+ if (ret & LM_OUT_CANCELED)
+ handle_callback(gl, LM_ST_UNLOCKED);
+
+ } else if (ret & LM_OUT_CANCELED) {
+ spin_lock(&gl->gl_spin);
+ list_del_init(&gh->gh_list);
+ gh->gh_error = GLR_CANCELED;
+ spin_unlock(&gl->gl_spin);
+
+ } else if (relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
+ spin_lock(&gl->gl_spin);
+ list_move_tail(&gh->gh_list, &gl->gl_holders);
+ gh->gh_error = 0;
+ set_bit(HIF_HOLDER, &gh->gh_iflags);
+ spin_unlock(&gl->gl_spin);
+
+ set_bit(HIF_FIRST, &gh->gh_iflags);
+
+ op_done = 0;
+
+ } else if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
+ spin_lock(&gl->gl_spin);
+ list_del_init(&gh->gh_list);
+ gh->gh_error = GLR_TRYFAILED;
+ spin_unlock(&gl->gl_spin);
+
+ } else {
+ if (gfs2_assert_withdraw(sdp, 0) == -1)
+ fs_err(sdp, "ret = 0x%.8X\n", ret);
+ }
+
+ if (glops->go_xmote_bh)
+ glops->go_xmote_bh(gl);
+
+ if (op_done) {
+ spin_lock(&gl->gl_spin);
+ gl->gl_req_gh = NULL;
+ gl->gl_req_bh = NULL;
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+ }
+
+ gfs2_glock_put(gl);
+
+ if (gh) {
+ if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
+ gfs2_holder_put(gh);
+ else
+ complete(&gh->gh_wait);
+ }
+}
+
+/**
+ * gfs2_glock_xmote_th - Call into the lock module to acquire or change a glock
+ * @gl: The glock in question
+ * @state: the requested state
+ * @flags: modifier flags to the lock call
+ *
+ */
+
+void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+ int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB |
+ LM_FLAG_NOEXP | LM_FLAG_ANY |
+ LM_FLAG_PRIORITY);
+ unsigned int lck_ret;
+
+ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+ gfs2_assert_warn(sdp, state != LM_ST_UNLOCKED);
+ gfs2_assert_warn(sdp, state != gl->gl_state);
+
+ if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
+ glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE);
+
+ gfs2_glock_hold(gl);
+ gl->gl_req_bh = xmote_bh;
+
+ lck_ret = gfs2_lm_lock(sdp, gl->gl_lock, gl->gl_state, state, lck_flags);
+
+ if (gfs2_assert_withdraw(sdp, !(lck_ret & LM_OUT_ERROR)))
+ return;
+
+ if (lck_ret & LM_OUT_ASYNC)
+ gfs2_assert_warn(sdp, lck_ret == LM_OUT_ASYNC);
+ else
+ xmote_bh(gl, lck_ret);
+}
+
+/**
+ * drop_bh - Called after a lock module unlock completes
+ * @gl: the glock
+ * @ret: the return status
+ *
+ * Doesn't wake up the process waiting on the struct gfs2_holder (if any)
+ * Doesn't drop the reference on the glock the top half took out
+ *
+ */
+
+static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+ struct gfs2_holder *gh = gl->gl_req_gh;
+
+ clear_bit(GLF_PREFETCH, &gl->gl_flags);
+
+ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+ gfs2_assert_warn(sdp, !ret);
+
+ state_change(gl, LM_ST_UNLOCKED);
+
+ if (glops->go_inval)
+ glops->go_inval(gl, DIO_METADATA | DIO_DATA);
+
+ if (gh) {
+ spin_lock(&gl->gl_spin);
+ list_del_init(&gh->gh_list);
+ gh->gh_error = 0;
+ spin_unlock(&gl->gl_spin);
+ }
+
+ if (glops->go_drop_bh)
+ glops->go_drop_bh(gl);
+
+ spin_lock(&gl->gl_spin);
+ gl->gl_req_gh = NULL;
+ gl->gl_req_bh = NULL;
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+
+ gfs2_glock_put(gl);
+
+ if (gh) {
+ if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
+ gfs2_holder_put(gh);
+ else
+ complete(&gh->gh_wait);
+ }
+}
+
+/**
+ * gfs2_glock_drop_th - call into the lock module to unlock a lock
+ * @gl: the glock
+ *
+ */
+
+void gfs2_glock_drop_th(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+ unsigned int ret;
+
+ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+ gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+ gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED);
+
+ if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
+ glops->go_sync(gl, DIO_METADATA | DIO_DATA | DIO_RELEASE);
+
+ gfs2_glock_hold(gl);
+ gl->gl_req_bh = drop_bh;
+
+ ret = gfs2_lm_unlock(sdp, gl->gl_lock, gl->gl_state);
+
+ if (gfs2_assert_withdraw(sdp, !(ret & LM_OUT_ERROR)))
+ return;
+
+ if (!ret)
+ drop_bh(gl, ret);
+ else
+ gfs2_assert_warn(sdp, ret == LM_OUT_ASYNC);
+}
+
+/**
+ * do_cancels - cancel requests for locks stuck waiting on an expire flag
+ * @gh: the LM_FLAG_PRIORITY holder waiting to acquire the lock
+ *
+ * Don't cancel GL_NOCANCEL requests.
+ */
+
+static void do_cancels(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+
+ spin_lock(&gl->gl_spin);
+
+ while (gl->gl_req_gh != gh &&
+ !test_bit(HIF_HOLDER, &gh->gh_iflags) &&
+ !list_empty(&gh->gh_list)) {
+ if (gl->gl_req_bh && !(gl->gl_req_gh &&
+ (gl->gl_req_gh->gh_flags & GL_NOCANCEL))) {
+ spin_unlock(&gl->gl_spin);
+ gfs2_lm_cancel(gl->gl_sbd, gl->gl_lock);
+ msleep(100);
+ spin_lock(&gl->gl_spin);
+ } else {
+ spin_unlock(&gl->gl_spin);
+ msleep(100);
+ spin_lock(&gl->gl_spin);
+ }
+ }
+
+ spin_unlock(&gl->gl_spin);
+}
+
+/**
+ * glock_wait_internal - wait on a glock acquisition
+ * @gh: the glock holder
+ *
+ * Returns: 0 on success
+ */
+
+static int glock_wait_internal(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+ if (test_bit(HIF_ABORTED, &gh->gh_iflags))
+ return -EIO;
+
+ if (gh->gh_flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB)) {
+ spin_lock(&gl->gl_spin);
+ if (gl->gl_req_gh != gh &&
+ !test_bit(HIF_HOLDER, &gh->gh_iflags) &&
+ !list_empty(&gh->gh_list)) {
+ list_del_init(&gh->gh_list);
+ gh->gh_error = GLR_TRYFAILED;
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+ return gh->gh_error;
+ }
+ spin_unlock(&gl->gl_spin);
+ }
+
+ if (gh->gh_flags & LM_FLAG_PRIORITY)
+ do_cancels(gh);
+
+ wait_for_completion(&gh->gh_wait);
+
+ if (gh->gh_error)
+ return gh->gh_error;
+
+ gfs2_assert_withdraw(sdp, test_bit(HIF_HOLDER, &gh->gh_iflags));
+ gfs2_assert_withdraw(sdp, relaxed_state_ok(gl->gl_state, gh->gh_state,
+ gh->gh_flags));
+
+ if (test_bit(HIF_FIRST, &gh->gh_iflags)) {
+ gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
+
+ if (glops->go_lock) {
+ gh->gh_error = glops->go_lock(gh);
+ if (gh->gh_error) {
+ spin_lock(&gl->gl_spin);
+ list_del_init(&gh->gh_list);
+ spin_unlock(&gl->gl_spin);
+ }
+ }
+
+ spin_lock(&gl->gl_spin);
+ gl->gl_req_gh = NULL;
+ gl->gl_req_bh = NULL;
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+ }
+
+ return gh->gh_error;
+}
+
+static inline struct gfs2_holder *
+find_holder_by_owner(struct list_head *head, struct task_struct *owner)
+{
+ struct gfs2_holder *gh;
+
+ list_for_each_entry(gh, head, gh_list) {
+ if (gh->gh_owner == owner)
+ return gh;
+ }
+
+ return NULL;
+}
+
+/**
+ * add_to_queue - Add a holder to the wait queue (but look for recursion)
+ * @gh: the holder structure to add
+ *
+ */
+
+static void add_to_queue(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_holder *existing;
+
+ BUG_ON(!gh->gh_owner);
+
+ existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
+ if (existing) {
+ print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
+ printk(KERN_INFO "pid : %d\n", existing->gh_owner->pid);
+ printk(KERN_INFO "lock type : %d lock state : %d\n",
+ existing->gh_gl->gl_name.ln_type, existing->gh_gl->gl_state);
+ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+ printk(KERN_INFO "pid : %d\n", gh->gh_owner->pid);
+ printk(KERN_INFO "lock type : %d lock state : %d\n",
+ gl->gl_name.ln_type, gl->gl_state);
+ BUG();
+ }
+
+ existing = find_holder_by_owner(&gl->gl_waiters3, gh->gh_owner);
+ if (existing) {
+ print_symbol(KERN_WARNING "original: %s\n", existing->gh_ip);
+ print_symbol(KERN_WARNING "new: %s\n", gh->gh_ip);
+ BUG();
+ }
+
+ if (gh->gh_flags & LM_FLAG_PRIORITY)
+ list_add(&gh->gh_list, &gl->gl_waiters3);
+ else
+ list_add_tail(&gh->gh_list, &gl->gl_waiters3);
+}
+
+/**
+ * gfs2_glock_nq - enqueue a struct gfs2_holder onto a glock (acquire a glock)
+ * @gh: the holder structure
+ *
+ * if (gh->gh_flags & GL_ASYNC), this never returns an error
+ *
+ * Returns: 0, GLR_TRYFAILED, or errno on failure
+ */
+
+int gfs2_glock_nq(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ int error = 0;
+
+restart:
+ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) {
+ set_bit(HIF_ABORTED, &gh->gh_iflags);
+ return -EIO;
+ }
+
+ set_bit(HIF_PROMOTE, &gh->gh_iflags);
+
+ spin_lock(&gl->gl_spin);
+ add_to_queue(gh);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+
+ if (!(gh->gh_flags & GL_ASYNC)) {
+ error = glock_wait_internal(gh);
+ if (error == GLR_CANCELED) {
+ msleep(100);
+ goto restart;
+ }
+ }
+
+ clear_bit(GLF_PREFETCH, &gl->gl_flags);
+
+ if (error == GLR_TRYFAILED && (gh->gh_flags & GL_DUMP))
+ dump_glock(gl);
+
+ return error;
+}
+
+/**
+ * gfs2_glock_poll - poll to see if an async request has been completed
+ * @gh: the holder
+ *
+ * Returns: 1 if the request is ready to be gfs2_glock_wait()ed on
+ */
+
+int gfs2_glock_poll(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ int ready = 0;
+
+ spin_lock(&gl->gl_spin);
+
+ if (test_bit(HIF_HOLDER, &gh->gh_iflags))
+ ready = 1;
+ else if (list_empty(&gh->gh_list)) {
+ if (gh->gh_error == GLR_CANCELED) {
+ spin_unlock(&gl->gl_spin);
+ msleep(100);
+ if (gfs2_glock_nq(gh))
+ return 1;
+ return 0;
+ } else
+ ready = 1;
+ }
+
+ spin_unlock(&gl->gl_spin);
+
+ return ready;
+}
+
+/**
+ * gfs2_glock_wait - wait for a lock acquisition that ended in a GLR_ASYNC
+ * @gh: the holder structure
+ *
+ * Returns: 0, GLR_TRYFAILED, or errno on failure
+ */
+
+int gfs2_glock_wait(struct gfs2_holder *gh)
+{
+ int error;
+
+ error = glock_wait_internal(gh);
+ if (error == GLR_CANCELED) {
+ msleep(100);
+ gh->gh_flags &= ~GL_ASYNC;
+ error = gfs2_glock_nq(gh);
+ }
+
+ return error;
+}
+
+/**
+ * gfs2_glock_dq - dequeue a struct gfs2_holder from a glock (release a glock)
+ * @gh: the glock holder
+ *
+ */
+
+void gfs2_glock_dq(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+ if (gh->gh_flags & GL_NOCACHE)
+ handle_callback(gl, LM_ST_UNLOCKED);
+
+ gfs2_glmutex_lock(gl);
+
+ spin_lock(&gl->gl_spin);
+ list_del_init(&gh->gh_list);
+
+ if (list_empty(&gl->gl_holders)) {
+ spin_unlock(&gl->gl_spin);
+
+ if (glops->go_unlock)
+ glops->go_unlock(gh);
+
+ gl->gl_stamp = jiffies;
+
+ spin_lock(&gl->gl_spin);
+ }
+
+ clear_bit(GLF_LOCK, &gl->gl_flags);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+}
+
+/**
+ * gfs2_glock_prefetch - Try to prefetch a glock
+ * @gl: the glock
+ * @state: the state to prefetch in
+ * @flags: flags passed to go_xmote_th()
+ *
+ */
+
+static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state,
+ int flags)
+{
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+ spin_lock(&gl->gl_spin);
+
+ if (test_bit(GLF_LOCK, &gl->gl_flags) || !list_empty(&gl->gl_holders) ||
+ !list_empty(&gl->gl_waiters1) || !list_empty(&gl->gl_waiters2) ||
+ !list_empty(&gl->gl_waiters3) ||
+ relaxed_state_ok(gl->gl_state, state, flags)) {
+ spin_unlock(&gl->gl_spin);
+ return;
+ }
+
+ set_bit(GLF_PREFETCH, &gl->gl_flags);
+ set_bit(GLF_LOCK, &gl->gl_flags);
+ spin_unlock(&gl->gl_spin);
+
+ glops->go_xmote_th(gl, state, flags);
+}
+
+static void greedy_work(void *data)
+{
+ struct greedy *gr = data;
+ struct gfs2_holder *gh = &gr->gr_gh;
+ struct gfs2_glock *gl = gh->gh_gl;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+
+ clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
+
+ if (glops->go_greedy)
+ glops->go_greedy(gl);
+
+ spin_lock(&gl->gl_spin);
+
+ if (list_empty(&gl->gl_waiters2)) {
+ clear_bit(GLF_GREEDY, &gl->gl_flags);
+ spin_unlock(&gl->gl_spin);
+ gfs2_holder_uninit(gh);
+ kfree(gr);
+ } else {
+ gfs2_glock_hold(gl);
+ list_add_tail(&gh->gh_list, &gl->gl_waiters2);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+ gfs2_glock_put(gl);
+ }
+}
+
+/**
+ * gfs2_glock_be_greedy -
+ * @gl:
+ * @time:
+ *
+ * Returns: 0 if go_greedy will be called, 1 otherwise
+ */
+
+int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time)
+{
+ struct greedy *gr;
+ struct gfs2_holder *gh;
+
+ if (!time || gl->gl_sbd->sd_args.ar_localcaching ||
+ test_and_set_bit(GLF_GREEDY, &gl->gl_flags))
+ return 1;
+
+ gr = kmalloc(sizeof(struct greedy), GFP_KERNEL);
+ if (!gr) {
+ clear_bit(GLF_GREEDY, &gl->gl_flags);
+ return 1;
+ }
+ gh = &gr->gr_gh;
+
+ gfs2_holder_init(gl, 0, 0, gh);
+ set_bit(HIF_GREEDY, &gh->gh_iflags);
+ INIT_WORK(&gr->gr_work, greedy_work, gr);
+
+ set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
+ schedule_delayed_work(&gr->gr_work, time);
+
+ return 0;
+}
+
+/**
+ * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it
+ * @gh: the holder structure
+ *
+ */
+
+void gfs2_glock_dq_uninit(struct gfs2_holder *gh)
+{
+ gfs2_glock_dq(gh);
+ gfs2_holder_uninit(gh);
+}
+
+/**
+ * gfs2_glock_nq_num - acquire a glock based on lock number
+ * @sdp: the filesystem
+ * @number: the lock number
+ * @glops: the glock operations for the type of glock
+ * @state: the state to acquire the glock in
+ * @flags: modifier flags for the aquisition
+ * @gh: the struct gfs2_holder
+ *
+ * Returns: errno
+ */
+
+int gfs2_glock_nq_num(struct gfs2_sbd *sdp, u64 number,
+ const struct gfs2_glock_operations *glops,
+ unsigned int state, int flags, struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl;
+ int error;
+
+ error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
+ if (!error) {
+ error = gfs2_glock_nq_init(gl, state, flags, gh);
+ gfs2_glock_put(gl);
+ }
+
+ return error;
+}
+
+/**
+ * glock_compare - Compare two struct gfs2_glock structures for sorting
+ * @arg_a: the first structure
+ * @arg_b: the second structure
+ *
+ */
+
+static int glock_compare(const void *arg_a, const void *arg_b)
+{
+ const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a;
+ const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b;
+ const struct lm_lockname *a = &gh_a->gh_gl->gl_name;
+ const struct lm_lockname *b = &gh_b->gh_gl->gl_name;
+
+ if (a->ln_number > b->ln_number)
+ return 1;
+ if (a->ln_number < b->ln_number)
+ return -1;
+ if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
+ return 1;
+ if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && (gh_b->gh_flags & GL_LOCAL_EXCL))
+ return 1;
+ return 0;
+}
+
+/**
+ * nq_m_sync - synchonously acquire more than one glock in deadlock free order
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ * Returns: 0 on success (all glocks acquired),
+ * errno on failure (no glocks acquired)
+ */
+
+static int nq_m_sync(unsigned int num_gh, struct gfs2_holder *ghs,
+ struct gfs2_holder **p)
+{
+ unsigned int x;
+ int error = 0;
+
+ for (x = 0; x < num_gh; x++)
+ p[x] = &ghs[x];
+
+ sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare, NULL);
+
+ for (x = 0; x < num_gh; x++) {
+ p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+
+ error = gfs2_glock_nq(p[x]);
+ if (error) {
+ while (x--)
+ gfs2_glock_dq(p[x]);
+ break;
+ }
+ }
+
+ return error;
+}
+
+/**
+ * gfs2_glock_nq_m - acquire multiple glocks
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ * Figure out how big an impact this function has. Either:
+ * 1) Replace this code with code that calls gfs2_glock_prefetch()
+ * 2) Forget async stuff and just call nq_m_sync()
+ * 3) Leave it like it is
+ *
+ * Returns: 0 on success (all glocks acquired),
+ * errno on failure (no glocks acquired)
+ */
+
+int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+ int *e;
+ unsigned int x;
+ int borked = 0, serious = 0;
+ int error = 0;
+
+ if (!num_gh)
+ return 0;
+
+ if (num_gh == 1) {
+ ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+ return gfs2_glock_nq(ghs);
+ }
+
+ e = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
+ if (!e)
+ return -ENOMEM;
+
+ for (x = 0; x < num_gh; x++) {
+ ghs[x].gh_flags |= LM_FLAG_TRY | GL_ASYNC;
+ error = gfs2_glock_nq(&ghs[x]);
+ if (error) {
+ borked = 1;
+ serious = error;
+ num_gh = x;
+ break;
+ }
+ }
+
+ for (x = 0; x < num_gh; x++) {
+ error = e[x] = glock_wait_internal(&ghs[x]);
+ if (error) {
+ borked = 1;
+ if (error != GLR_TRYFAILED && error != GLR_CANCELED)
+ serious = error;
+ }
+ }
+
+ if (!borked) {
+ kfree(e);
+ return 0;
+ }
+
+ for (x = 0; x < num_gh; x++)
+ if (!e[x])
+ gfs2_glock_dq(&ghs[x]);
+
+ if (serious)
+ error = serious;
+ else {
+ for (x = 0; x < num_gh; x++)
+ gfs2_holder_reinit(ghs[x].gh_state, ghs[x].gh_flags,
+ &ghs[x]);
+ error = nq_m_sync(num_gh, ghs, (struct gfs2_holder **)e);
+ }
+
+ kfree(e);
+
+ return error;
+}
+
+/**
+ * gfs2_glock_dq_m - release multiple glocks
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ */
+
+void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+ unsigned int x;
+
+ for (x = 0; x < num_gh; x++)
+ gfs2_glock_dq(&ghs[x]);
+}
+
+/**
+ * gfs2_glock_dq_uninit_m - release multiple glocks
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ */
+
+void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+ unsigned int x;
+
+ for (x = 0; x < num_gh; x++)
+ gfs2_glock_dq_uninit(&ghs[x]);
+}
+
+/**
+ * gfs2_glock_prefetch_num - prefetch a glock based on lock number
+ * @sdp: the filesystem
+ * @number: the lock number
+ * @glops: the glock operations for the type of glock
+ * @state: the state to acquire the glock in
+ * @flags: modifier flags for the aquisition
+ *
+ * Returns: errno
+ */
+
+void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
+ const struct gfs2_glock_operations *glops,
+ unsigned int state, int flags)
+{
+ struct gfs2_glock *gl;
+ int error;
+
+ if (atomic_read(&sdp->sd_reclaim_count) <
+ gfs2_tune_get(sdp, gt_reclaim_limit)) {
+ error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
+ if (!error) {
+ gfs2_glock_prefetch(gl, state, flags);
+ gfs2_glock_put(gl);
+ }
+ }
+}
+
+/**
+ * gfs2_lvb_hold - attach a LVB from a glock
+ * @gl: The glock in question
+ *
+ */
+
+int gfs2_lvb_hold(struct gfs2_glock *gl)
+{
+ int error;
+
+ gfs2_glmutex_lock(gl);
+
+ if (!atomic_read(&gl->gl_lvb_count)) {
+ error = gfs2_lm_hold_lvb(gl->gl_sbd, gl->gl_lock, &gl->gl_lvb);
+ if (error) {
+ gfs2_glmutex_unlock(gl);
+ return error;
+ }
+ gfs2_glock_hold(gl);
+ }
+ atomic_inc(&gl->gl_lvb_count);
+
+ gfs2_glmutex_unlock(gl);
+
+ return 0;
+}
+
+/**
+ * gfs2_lvb_unhold - detach a LVB from a glock
+ * @gl: The glock in question
+ *
+ */
+
+void gfs2_lvb_unhold(struct gfs2_glock *gl)
+{
+ gfs2_glock_hold(gl);
+ gfs2_glmutex_lock(gl);
+
+ gfs2_assert(gl->gl_sbd, atomic_read(&gl->gl_lvb_count) > 0);
+ if (atomic_dec_and_test(&gl->gl_lvb_count)) {
+ gfs2_lm_unhold_lvb(gl->gl_sbd, gl->gl_lock, gl->gl_lvb);
+ gl->gl_lvb = NULL;
+ gfs2_glock_put(gl);
+ }
+
+ gfs2_glmutex_unlock(gl);
+ gfs2_glock_put(gl);
+}
+
+static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ unsigned int state)
+{
+ struct gfs2_glock *gl;
+
+ gl = gfs2_glock_find(sdp, name);
+ if (!gl)
+ return;
+
+ if (gl->gl_ops->go_callback)
+ gl->gl_ops->go_callback(gl, state);
+ handle_callback(gl, state);
+
+ spin_lock(&gl->gl_spin);
+ run_queue(gl);
+ spin_unlock(&gl->gl_spin);
+
+ gfs2_glock_put(gl);
+}
+
+/**
+ * gfs2_glock_cb - Callback used by locking module
+ * @sdp: Pointer to the superblock
+ * @type: Type of callback
+ * @data: Type dependent data pointer
+ *
+ * Called by the locking module when it wants to tell us something.
+ * Either we need to drop a lock, one of our ASYNC requests completed, or
+ * a journal from another client needs to be recovered.
+ */
+
+void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
+{
+ struct gfs2_sbd *sdp = cb_data;
+
+ switch (type) {
+ case LM_CB_NEED_E:
+ blocking_cb(sdp, data, LM_ST_UNLOCKED);
+ return;
+
+ case LM_CB_NEED_D:
+ blocking_cb(sdp, data, LM_ST_DEFERRED);
+ return;
+
+ case LM_CB_NEED_S:
+ blocking_cb(sdp, data, LM_ST_SHARED);
+ return;
+
+ case LM_CB_ASYNC: {
+ struct lm_async_cb *async = data;
+ struct gfs2_glock *gl;
+
+ gl = gfs2_glock_find(sdp, &async->lc_name);
+ if (gfs2_assert_warn(sdp, gl))
+ return;
+ if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
+ gl->gl_req_bh(gl, async->lc_ret);
+ gfs2_glock_put(gl);
+ return;
+ }
+
+ case LM_CB_NEED_RECOVERY:
+ gfs2_jdesc_make_dirty(sdp, *(unsigned int *)data);
+ if (sdp->sd_recoverd_process)
+ wake_up_process(sdp->sd_recoverd_process);
+ return;
+
+ case LM_CB_DROPLOCKS:
+ gfs2_gl_hash_clear(sdp, NO_WAIT);
+ gfs2_quota_scan(sdp);
+ return;
+
+ default:
+ gfs2_assert_warn(sdp, 0);
+ return;
+ }
+}
+
+/**
+ * demote_ok - Check to see if it's ok to unlock a glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int demote_ok(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ const struct gfs2_glock_operations *glops = gl->gl_ops;
+ int demote = 1;
+
+ if (test_bit(GLF_STICKY, &gl->gl_flags))
+ demote = 0;
+ else if (test_bit(GLF_PREFETCH, &gl->gl_flags))
+ demote = time_after_eq(jiffies, gl->gl_stamp +
+ gfs2_tune_get(sdp, gt_prefetch_secs) * HZ);
+ else if (glops->go_demote_ok)
+ demote = glops->go_demote_ok(gl);
+
+ return demote;
+}
+
+/**
+ * gfs2_glock_schedule_for_reclaim - Add a glock to the reclaim list
+ * @gl: the glock
+ *
+ */
+
+void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+
+ spin_lock(&sdp->sd_reclaim_lock);
+ if (list_empty(&gl->gl_reclaim)) {
+ gfs2_glock_hold(gl);
+ list_add(&gl->gl_reclaim, &sdp->sd_reclaim_list);
+ atomic_inc(&sdp->sd_reclaim_count);
+ }
+ spin_unlock(&sdp->sd_reclaim_lock);
+
+ wake_up(&sdp->sd_reclaim_wq);
+}
+
+/**
+ * gfs2_reclaim_glock - process the next glock on the filesystem's reclaim list
+ * @sdp: the filesystem
+ *
+ * Called from gfs2_glockd() glock reclaim daemon, or when promoting a
+ * different glock and we notice that there are a lot of glocks in the
+ * reclaim list.
+ *
+ */
+
+void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
+{
+ struct gfs2_glock *gl;
+
+ spin_lock(&sdp->sd_reclaim_lock);
+ if (list_empty(&sdp->sd_reclaim_list)) {
+ spin_unlock(&sdp->sd_reclaim_lock);
+ return;
+ }
+ gl = list_entry(sdp->sd_reclaim_list.next,
+ struct gfs2_glock, gl_reclaim);
+ list_del_init(&gl->gl_reclaim);
+ spin_unlock(&sdp->sd_reclaim_lock);
+
+ atomic_dec(&sdp->sd_reclaim_count);
+ atomic_inc(&sdp->sd_reclaimed);
+
+ if (gfs2_glmutex_trylock(gl)) {
+ if (queue_empty(gl, &gl->gl_holders) &&
+ gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
+ handle_callback(gl, LM_ST_UNLOCKED);
+ gfs2_glmutex_unlock(gl);
+ }
+
+ gfs2_glock_put(gl);
+}
+
+/**
+ * examine_bucket - Call a function for glock in a hash bucket
+ * @examiner: the function
+ * @sdp: the filesystem
+ * @bucket: the bucket
+ *
+ * Returns: 1 if the bucket has entries
+ */
+
+static int examine_bucket(glock_examiner examiner, struct gfs2_sbd *sdp,
+ unsigned int hash)
+{
+ struct gfs2_glock *gl, *prev = NULL;
+ int has_entries = 0;
+ struct hlist_head *head = &gl_hash_table[hash].hb_list;
+
+ read_lock(gl_lock_addr(hash));
+ /* Can't use hlist_for_each_entry - don't want prefetch here */
+ if (hlist_empty(head))
+ goto out;
+ gl = list_entry(head->first, struct gfs2_glock, gl_list);
+ while(1) {
+ if (gl->gl_sbd == sdp) {
+ gfs2_glock_hold(gl);
+ read_unlock(gl_lock_addr(hash));
+ if (prev)
+ gfs2_glock_put(prev);
+ prev = gl;
+ examiner(gl);
+ has_entries = 1;
+ read_lock(gl_lock_addr(hash));
+ }
+ if (gl->gl_list.next == NULL)
+ break;
+ gl = list_entry(gl->gl_list.next, struct gfs2_glock, gl_list);
+ }
+out:
+ read_unlock(gl_lock_addr(hash));
+ if (prev)
+ gfs2_glock_put(prev);
+ return has_entries;
+}
+
+/**
+ * scan_glock - look at a glock and see if we can reclaim it
+ * @gl: the glock to look at
+ *
+ */
+
+static void scan_glock(struct gfs2_glock *gl)
+{
+ if (gl->gl_ops == &gfs2_inode_glops)
+ return;
+
+ if (gfs2_glmutex_trylock(gl)) {
+ if (queue_empty(gl, &gl->gl_holders) &&
+ gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
+ goto out_schedule;
+ gfs2_glmutex_unlock(gl);
+ }
+ return;
+
+out_schedule:
+ gfs2_glmutex_unlock(gl);
+ gfs2_glock_schedule_for_reclaim(gl);
+}
+
+/**
+ * gfs2_scand_internal - Look for glocks and inodes to toss from memory
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_scand_internal(struct gfs2_sbd *sdp)
+{
+ unsigned int x;
+
+ for (x = 0; x < GFS2_GL_HASH_SIZE; x++)
+ examine_bucket(scan_glock, sdp, x);
+}
+
+/**
+ * clear_glock - look at a glock and see if we can free it from glock cache
+ * @gl: the glock to look at
+ *
+ */
+
+static void clear_glock(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ int released;
+
+ spin_lock(&sdp->sd_reclaim_lock);
+ if (!list_empty(&gl->gl_reclaim)) {
+ list_del_init(&gl->gl_reclaim);
+ atomic_dec(&sdp->sd_reclaim_count);
+ spin_unlock(&sdp->sd_reclaim_lock);
+ released = gfs2_glock_put(gl);
+ gfs2_assert(sdp, !released);
+ } else {
+ spin_unlock(&sdp->sd_reclaim_lock);
+ }
+
+ if (gfs2_glmutex_trylock(gl)) {
+ if (queue_empty(gl, &gl->gl_holders) &&
+ gl->gl_state != LM_ST_UNLOCKED)
+ handle_callback(gl, LM_ST_UNLOCKED);
+ gfs2_glmutex_unlock(gl);
+ }
+}
+
+/**
+ * gfs2_gl_hash_clear - Empty out the glock hash table
+ * @sdp: the filesystem
+ * @wait: wait until it's all gone
+ *
+ * Called when unmounting the filesystem, or when inter-node lock manager
+ * requests DROPLOCKS because it is running out of capacity.
+ */
+
+void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
+{
+ unsigned long t;
+ unsigned int x;
+ int cont;
+
+ t = jiffies;
+
+ for (;;) {
+ cont = 0;
+ for (x = 0; x < GFS2_GL_HASH_SIZE; x++) {
+ if (examine_bucket(clear_glock, sdp, x))
+ cont = 1;
+ }
+
+ if (!wait || !cont)
+ break;
+
+ if (time_after_eq(jiffies,
+ t + gfs2_tune_get(sdp, gt_stall_secs) * HZ)) {
+ fs_warn(sdp, "Unmount seems to be stalled. "
+ "Dumping lock state...\n");
+ gfs2_dump_lockstate(sdp);
+ t = jiffies;
+ }
+
+ invalidate_inodes(sdp->sd_vfs);
+ msleep(10);
+ }
+}
+
+/*
+ * Diagnostic routines to help debug distributed deadlock
+ */
+
+/**
+ * dump_holder - print information about a glock holder
+ * @str: a string naming the type of holder
+ * @gh: the glock holder
+ *
+ * Returns: 0 on success, -ENOBUFS when we run out of space
+ */
+
+static int dump_holder(char *str, struct gfs2_holder *gh)
+{
+ unsigned int x;
+ int error = -ENOBUFS;
+
+ printk(KERN_INFO " %s\n", str);
+ printk(KERN_INFO " owner = %ld\n",
+ (gh->gh_owner) ? (long)gh->gh_owner->pid : -1);
+ printk(KERN_INFO " gh_state = %u\n", gh->gh_state);
+ printk(KERN_INFO " gh_flags =");
+ for (x = 0; x < 32; x++)
+ if (gh->gh_flags & (1 << x))
+ printk(" %u", x);
+ printk(" \n");
+ printk(KERN_INFO " error = %d\n", gh->gh_error);
+ printk(KERN_INFO " gh_iflags =");
+ for (x = 0; x < 32; x++)
+ if (test_bit(x, &gh->gh_iflags))
+ printk(" %u", x);
+ printk(" \n");
+ print_symbol(KERN_INFO " initialized at: %s\n", gh->gh_ip);
+
+ error = 0;
+
+ return error;
+}
+
+/**
+ * dump_inode - print information about an inode
+ * @ip: the inode
+ *
+ * Returns: 0 on success, -ENOBUFS when we run out of space
+ */
+
+static int dump_inode(struct gfs2_inode *ip)
+{
+ unsigned int x;
+ int error = -ENOBUFS;
+
+ printk(KERN_INFO " Inode:\n");
+ printk(KERN_INFO " num = %llu %llu\n",
+ (unsigned long long)ip->i_num.no_formal_ino,
+ (unsigned long long)ip->i_num.no_addr);
+ printk(KERN_INFO " type = %u\n", IF2DT(ip->i_di.di_mode));
+ printk(KERN_INFO " i_flags =");
+ for (x = 0; x < 32; x++)
+ if (test_bit(x, &ip->i_flags))
+ printk(" %u", x);
+ printk(" \n");
+
+ error = 0;
+
+ return error;
+}
+
+/**
+ * dump_glock - print information about a glock
+ * @gl: the glock
+ * @count: where we are in the buffer
+ *
+ * Returns: 0 on success, -ENOBUFS when we run out of space
+ */
+
+static int dump_glock(struct gfs2_glock *gl)
+{
+ struct gfs2_holder *gh;
+ unsigned int x;
+ int error = -ENOBUFS;
+
+ spin_lock(&gl->gl_spin);
+
+ printk(KERN_INFO "Glock 0x%p (%u, %llu)\n", gl, gl->gl_name.ln_type,
+ (unsigned long long)gl->gl_name.ln_number);
+ printk(KERN_INFO " gl_flags =");
+ for (x = 0; x < 32; x++) {
+ if (test_bit(x, &gl->gl_flags))
+ printk(" %u", x);
+ }
+ printk(" \n");
+ printk(KERN_INFO " gl_ref = %d\n", atomic_read(&gl->gl_ref));
+ printk(KERN_INFO " gl_state = %u\n", gl->gl_state);
+ printk(KERN_INFO " gl_owner = %s\n", gl->gl_owner->comm);
+ print_symbol(KERN_INFO " gl_ip = %s\n", gl->gl_ip);
+ printk(KERN_INFO " req_gh = %s\n", (gl->gl_req_gh) ? "yes" : "no");
+ printk(KERN_INFO " req_bh = %s\n", (gl->gl_req_bh) ? "yes" : "no");
+ printk(KERN_INFO " lvb_count = %d\n", atomic_read(&gl->gl_lvb_count));
+ printk(KERN_INFO " object = %s\n", (gl->gl_object) ? "yes" : "no");
+ printk(KERN_INFO " le = %s\n",
+ (list_empty(&gl->gl_le.le_list)) ? "no" : "yes");
+ printk(KERN_INFO " reclaim = %s\n",
+ (list_empty(&gl->gl_reclaim)) ? "no" : "yes");
+ if (gl->gl_aspace)
+ printk(KERN_INFO " aspace = 0x%p nrpages = %lu\n", gl->gl_aspace,
+ gl->gl_aspace->i_mapping->nrpages);
+ else
+ printk(KERN_INFO " aspace = no\n");
+ printk(KERN_INFO " ail = %d\n", atomic_read(&gl->gl_ail_count));
+ if (gl->gl_req_gh) {
+ error = dump_holder("Request", gl->gl_req_gh);
+ if (error)
+ goto out;
+ }
+ list_for_each_entry(gh, &gl->gl_holders, gh_list) {
+ error = dump_holder("Holder", gh);
+ if (error)
+ goto out;
+ }
+ list_for_each_entry(gh, &gl->gl_waiters1, gh_list) {
+ error = dump_holder("Waiter1", gh);
+ if (error)
+ goto out;
+ }
+ list_for_each_entry(gh, &gl->gl_waiters2, gh_list) {
+ error = dump_holder("Waiter2", gh);
+ if (error)
+ goto out;
+ }
+ list_for_each_entry(gh, &gl->gl_waiters3, gh_list) {
+ error = dump_holder("Waiter3", gh);
+ if (error)
+ goto out;
+ }
+ if (gl->gl_ops == &gfs2_inode_glops && gl->gl_object) {
+ if (!test_bit(GLF_LOCK, &gl->gl_flags) &&
+ list_empty(&gl->gl_holders)) {
+ error = dump_inode(gl->gl_object);
+ if (error)
+ goto out;
+ } else {
+ error = -ENOBUFS;
+ printk(KERN_INFO " Inode: busy\n");
+ }
+ }
+
+ error = 0;
+
+out:
+ spin_unlock(&gl->gl_spin);
+ return error;
+}
+
+/**
+ * gfs2_dump_lockstate - print out the current lockstate
+ * @sdp: the filesystem
+ * @ub: the buffer to copy the information into
+ *
+ * If @ub is NULL, dump the lockstate to the console.
+ *
+ */
+
+static int gfs2_dump_lockstate(struct gfs2_sbd *sdp)
+{
+ struct gfs2_glock *gl;
+ struct hlist_node *h;
+ unsigned int x;
+ int error = 0;
+
+ for (x = 0; x < GFS2_GL_HASH_SIZE; x++) {
+
+ read_lock(gl_lock_addr(x));
+
+ hlist_for_each_entry(gl, h, &gl_hash_table[x].hb_list, gl_list) {
+ if (gl->gl_sbd != sdp)
+ continue;
+
+ error = dump_glock(gl);
+ if (error)
+ break;
+ }
+
+ read_unlock(gl_lock_addr(x));
+
+ if (error)
+ break;
+ }
+
+
+ return error;
+}
+
+int __init gfs2_glock_init(void)
+{
+ unsigned i;
+ for(i = 0; i < GFS2_GL_HASH_SIZE; i++) {
+ INIT_HLIST_HEAD(&gl_hash_table[i].hb_list);
+ }
+#ifdef GL_HASH_LOCK_SZ
+ for(i = 0; i < GL_HASH_LOCK_SZ; i++) {
+ rwlock_init(&gl_hash_locks[i]);
+ }
+#endif
+ return 0;
+}
+
diff --git a/fs/gfs2/glock.h b/fs/gfs2/glock.h
new file mode 100644
index 000000000000..2b2a889ee2cc
--- /dev/null
+++ b/fs/gfs2/glock.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __GLOCK_DOT_H__
+#define __GLOCK_DOT_H__
+
+#include "incore.h"
+
+/* Flags for lock requests; used in gfs2_holder gh_flag field.
+ From lm_interface.h:
+#define LM_FLAG_TRY 0x00000001
+#define LM_FLAG_TRY_1CB 0x00000002
+#define LM_FLAG_NOEXP 0x00000004
+#define LM_FLAG_ANY 0x00000008
+#define LM_FLAG_PRIORITY 0x00000010 */
+
+#define GL_LOCAL_EXCL 0x00000020
+#define GL_ASYNC 0x00000040
+#define GL_EXACT 0x00000080
+#define GL_SKIP 0x00000100
+#define GL_ATIME 0x00000200
+#define GL_NOCACHE 0x00000400
+#define GL_NOCANCEL 0x00001000
+#define GL_AOP 0x00004000
+#define GL_DUMP 0x00008000
+
+#define GLR_TRYFAILED 13
+#define GLR_CANCELED 14
+
+static inline int gfs2_glock_is_locked_by_me(struct gfs2_glock *gl)
+{
+ struct gfs2_holder *gh;
+ int locked = 0;
+
+ /* Look in glock's list of holders for one with current task as owner */
+ spin_lock(&gl->gl_spin);
+ list_for_each_entry(gh, &gl->gl_holders, gh_list) {
+ if (gh->gh_owner == current) {
+ locked = 1;
+ break;
+ }
+ }
+ spin_unlock(&gl->gl_spin);
+
+ return locked;
+}
+
+static inline int gfs2_glock_is_held_excl(struct gfs2_glock *gl)
+{
+ return gl->gl_state == LM_ST_EXCLUSIVE;
+}
+
+static inline int gfs2_glock_is_held_dfrd(struct gfs2_glock *gl)
+{
+ return gl->gl_state == LM_ST_DEFERRED;
+}
+
+static inline int gfs2_glock_is_held_shrd(struct gfs2_glock *gl)
+{
+ return gl->gl_state == LM_ST_SHARED;
+}
+
+static inline int gfs2_glock_is_blocking(struct gfs2_glock *gl)
+{
+ int ret;
+ spin_lock(&gl->gl_spin);
+ ret = !list_empty(&gl->gl_waiters2) || !list_empty(&gl->gl_waiters3);
+ spin_unlock(&gl->gl_spin);
+ return ret;
+}
+
+int gfs2_glock_get(struct gfs2_sbd *sdp,
+ u64 number, const struct gfs2_glock_operations *glops,
+ int create, struct gfs2_glock **glp);
+void gfs2_glock_hold(struct gfs2_glock *gl);
+int gfs2_glock_put(struct gfs2_glock *gl);
+void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
+ struct gfs2_holder *gh);
+void gfs2_holder_reinit(unsigned int state, unsigned flags,
+ struct gfs2_holder *gh);
+void gfs2_holder_uninit(struct gfs2_holder *gh);
+
+void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags);
+void gfs2_glock_drop_th(struct gfs2_glock *gl);
+
+int gfs2_glock_nq(struct gfs2_holder *gh);
+int gfs2_glock_poll(struct gfs2_holder *gh);
+int gfs2_glock_wait(struct gfs2_holder *gh);
+void gfs2_glock_dq(struct gfs2_holder *gh);
+
+int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time);
+
+void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
+int gfs2_glock_nq_num(struct gfs2_sbd *sdp,
+ u64 number, const struct gfs2_glock_operations *glops,
+ unsigned int state, int flags, struct gfs2_holder *gh);
+
+int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
+void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
+void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
+
+void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
+ const struct gfs2_glock_operations *glops,
+ unsigned int state, int flags);
+void gfs2_glock_inode_squish(struct inode *inode);
+
+/**
+ * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock
+ * @gl: the glock
+ * @state: the state we're requesting
+ * @flags: the modifier flags
+ * @gh: the holder structure
+ *
+ * Returns: 0, GLR_*, or errno
+ */
+
+static inline int gfs2_glock_nq_init(struct gfs2_glock *gl,
+ unsigned int state, int flags,
+ struct gfs2_holder *gh)
+{
+ int error;
+
+ gfs2_holder_init(gl, state, flags, gh);
+
+ error = gfs2_glock_nq(gh);
+ if (error)
+ gfs2_holder_uninit(gh);
+
+ return error;
+}
+
+/* Lock Value Block functions */
+
+int gfs2_lvb_hold(struct gfs2_glock *gl);
+void gfs2_lvb_unhold(struct gfs2_glock *gl);
+
+void gfs2_glock_cb(void *cb_data, unsigned int type, void *data);
+
+void gfs2_glock_schedule_for_reclaim(struct gfs2_glock *gl);
+void gfs2_reclaim_glock(struct gfs2_sbd *sdp);
+
+void gfs2_scand_internal(struct gfs2_sbd *sdp);
+void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait);
+
+int __init gfs2_glock_init(void);
+
+#endif /* __GLOCK_DOT_H__ */
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
new file mode 100644
index 000000000000..41a6b6818a50
--- /dev/null
+++ b/fs/gfs2/glops.c
@@ -0,0 +1,615 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "util.h"
+#include "trans.h"
+
+/**
+ * ail_empty_gl - remove all buffers for a given lock from the AIL
+ * @gl: the glock
+ *
+ * None of the buffers should be dirty, locked, or pinned.
+ */
+
+static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ unsigned int blocks;
+ struct list_head *head = &gl->gl_ail_list;
+ struct gfs2_bufdata *bd;
+ struct buffer_head *bh;
+ u64 blkno;
+ int error;
+
+ blocks = atomic_read(&gl->gl_ail_count);
+ if (!blocks)
+ return;
+
+ error = gfs2_trans_begin(sdp, 0, blocks);
+ if (gfs2_assert_withdraw(sdp, !error))
+ return;
+
+ gfs2_log_lock(sdp);
+ while (!list_empty(head)) {
+ bd = list_entry(head->next, struct gfs2_bufdata,
+ bd_ail_gl_list);
+ bh = bd->bd_bh;
+ blkno = bh->b_blocknr;
+ gfs2_assert_withdraw(sdp, !buffer_busy(bh));
+
+ bd->bd_ail = NULL;
+ list_del(&bd->bd_ail_st_list);
+ list_del(&bd->bd_ail_gl_list);
+ atomic_dec(&gl->gl_ail_count);
+ brelse(bh);
+ gfs2_log_unlock(sdp);
+
+ gfs2_trans_add_revoke(sdp, blkno);
+
+ gfs2_log_lock(sdp);
+ }
+ gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
+ gfs2_log_unlock(sdp);
+
+ gfs2_trans_end(sdp);
+ gfs2_log_flush(sdp, NULL);
+}
+
+/**
+ * gfs2_pte_inval - Sync and invalidate all PTEs associated with a glock
+ * @gl: the glock
+ *
+ */
+
+static void gfs2_pte_inval(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip;
+ struct inode *inode;
+
+ ip = gl->gl_object;
+ inode = &ip->i_inode;
+ if (!ip || !S_ISREG(ip->i_di.di_mode))
+ return;
+
+ if (!test_bit(GIF_PAGED, &ip->i_flags))
+ return;
+
+ unmap_shared_mapping_range(inode->i_mapping, 0, 0);
+
+ if (test_bit(GIF_SW_PAGED, &ip->i_flags))
+ set_bit(GLF_DIRTY, &gl->gl_flags);
+
+ clear_bit(GIF_SW_PAGED, &ip->i_flags);
+}
+
+/**
+ * gfs2_page_inval - Invalidate all pages associated with a glock
+ * @gl: the glock
+ *
+ */
+
+static void gfs2_page_inval(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip;
+ struct inode *inode;
+
+ ip = gl->gl_object;
+ inode = &ip->i_inode;
+ if (!ip || !S_ISREG(ip->i_di.di_mode))
+ return;
+
+ truncate_inode_pages(inode->i_mapping, 0);
+ gfs2_assert_withdraw(GFS2_SB(&ip->i_inode), !inode->i_mapping->nrpages);
+ clear_bit(GIF_PAGED, &ip->i_flags);
+}
+
+/**
+ * gfs2_page_wait - Wait for writeback of data
+ * @gl: the glock
+ *
+ * Syncs data (not metadata) for a regular file.
+ * No-op for all other types.
+ */
+
+static void gfs2_page_wait(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip = gl->gl_object;
+ struct inode *inode = &ip->i_inode;
+ struct address_space *mapping = inode->i_mapping;
+ int error;
+
+ if (!S_ISREG(ip->i_di.di_mode))
+ return;
+
+ error = filemap_fdatawait(mapping);
+
+ /* Put back any errors cleared by filemap_fdatawait()
+ so they can be caught by someone who can pass them
+ up to user space. */
+
+ if (error == -ENOSPC)
+ set_bit(AS_ENOSPC, &mapping->flags);
+ else if (error)
+ set_bit(AS_EIO, &mapping->flags);
+
+}
+
+static void gfs2_page_writeback(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip = gl->gl_object;
+ struct inode *inode = &ip->i_inode;
+ struct address_space *mapping = inode->i_mapping;
+
+ if (!S_ISREG(ip->i_di.di_mode))
+ return;
+
+ filemap_fdatawrite(mapping);
+}
+
+/**
+ * meta_go_sync - sync out the metadata for this glock
+ * @gl: the glock
+ * @flags: DIO_*
+ *
+ * Called when demoting or unlocking an EX glock. We must flush
+ * to disk all dirty buffers/pages relating to this glock, and must not
+ * not return to caller to demote/unlock the glock until I/O is complete.
+ */
+
+static void meta_go_sync(struct gfs2_glock *gl, int flags)
+{
+ if (!(flags & DIO_METADATA))
+ return;
+
+ if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
+ gfs2_log_flush(gl->gl_sbd, gl);
+ gfs2_meta_sync(gl);
+ if (flags & DIO_RELEASE)
+ gfs2_ail_empty_gl(gl);
+ }
+
+}
+
+/**
+ * meta_go_inval - invalidate the metadata for this glock
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void meta_go_inval(struct gfs2_glock *gl, int flags)
+{
+ if (!(flags & DIO_METADATA))
+ return;
+
+ gfs2_meta_inval(gl);
+ gl->gl_vn++;
+}
+
+/**
+ * inode_go_xmote_th - promote/demote a glock
+ * @gl: the glock
+ * @state: the requested state
+ * @flags:
+ *
+ */
+
+static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
+ int flags)
+{
+ if (gl->gl_state != LM_ST_UNLOCKED)
+ gfs2_pte_inval(gl);
+ gfs2_glock_xmote_th(gl, state, flags);
+}
+
+/**
+ * inode_go_xmote_bh - After promoting/demoting a glock
+ * @gl: the glock
+ *
+ */
+
+static void inode_go_xmote_bh(struct gfs2_glock *gl)
+{
+ struct gfs2_holder *gh = gl->gl_req_gh;
+ struct buffer_head *bh;
+ int error;
+
+ if (gl->gl_state != LM_ST_UNLOCKED &&
+ (!gh || !(gh->gh_flags & GL_SKIP))) {
+ error = gfs2_meta_read(gl, gl->gl_name.ln_number, 0, &bh);
+ if (!error)
+ brelse(bh);
+ }
+}
+
+/**
+ * inode_go_drop_th - unlock a glock
+ * @gl: the glock
+ *
+ * Invoked from rq_demote().
+ * Another node needs the lock in EXCLUSIVE mode, or lock (unused for too long)
+ * is being purged from our node's glock cache; we're dropping lock.
+ */
+
+static void inode_go_drop_th(struct gfs2_glock *gl)
+{
+ gfs2_pte_inval(gl);
+ gfs2_glock_drop_th(gl);
+}
+
+/**
+ * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
+ * @gl: the glock protecting the inode
+ * @flags:
+ *
+ */
+
+static void inode_go_sync(struct gfs2_glock *gl, int flags)
+{
+ int meta = (flags & DIO_METADATA);
+ int data = (flags & DIO_DATA);
+
+ if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
+ if (meta && data) {
+ gfs2_page_writeback(gl);
+ gfs2_log_flush(gl->gl_sbd, gl);
+ gfs2_meta_sync(gl);
+ gfs2_page_wait(gl);
+ clear_bit(GLF_DIRTY, &gl->gl_flags);
+ } else if (meta) {
+ gfs2_log_flush(gl->gl_sbd, gl);
+ gfs2_meta_sync(gl);
+ } else if (data) {
+ gfs2_page_writeback(gl);
+ gfs2_page_wait(gl);
+ }
+ if (flags & DIO_RELEASE)
+ gfs2_ail_empty_gl(gl);
+ }
+}
+
+/**
+ * inode_go_inval - prepare a inode glock to be released
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void inode_go_inval(struct gfs2_glock *gl, int flags)
+{
+ int meta = (flags & DIO_METADATA);
+ int data = (flags & DIO_DATA);
+
+ if (meta) {
+ gfs2_meta_inval(gl);
+ gl->gl_vn++;
+ }
+ if (data)
+ gfs2_page_inval(gl);
+}
+
+/**
+ * inode_go_demote_ok - Check to see if it's ok to unlock an inode glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int inode_go_demote_ok(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ int demote = 0;
+
+ if (!gl->gl_object && !gl->gl_aspace->i_mapping->nrpages)
+ demote = 1;
+ else if (!sdp->sd_args.ar_localcaching &&
+ time_after_eq(jiffies, gl->gl_stamp +
+ gfs2_tune_get(sdp, gt_demote_secs) * HZ))
+ demote = 1;
+
+ return demote;
+}
+
+/**
+ * inode_go_lock - operation done after an inode lock is locked by a process
+ * @gl: the glock
+ * @flags:
+ *
+ * Returns: errno
+ */
+
+static int inode_go_lock(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_inode *ip = gl->gl_object;
+ int error = 0;
+
+ if (!ip)
+ return 0;
+
+ if (ip->i_vn != gl->gl_vn) {
+ error = gfs2_inode_refresh(ip);
+ if (error)
+ return error;
+ gfs2_inode_attr_in(ip);
+ }
+
+ if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) &&
+ (gl->gl_state == LM_ST_EXCLUSIVE) &&
+ (gh->gh_flags & GL_LOCAL_EXCL))
+ error = gfs2_truncatei_resume(ip);
+
+ return error;
+}
+
+/**
+ * inode_go_unlock - operation done before an inode lock is unlocked by a
+ * process
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void inode_go_unlock(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_inode *ip = gl->gl_object;
+
+ if (ip == NULL)
+ return;
+ if (test_bit(GLF_DIRTY, &gl->gl_flags))
+ gfs2_inode_attr_in(ip);
+ gfs2_meta_cache_flush(ip);
+}
+
+/**
+ * inode_greedy -
+ * @gl: the glock
+ *
+ */
+
+static void inode_greedy(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct gfs2_inode *ip = gl->gl_object;
+ unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum);
+ unsigned int max = gfs2_tune_get(sdp, gt_greedy_max);
+ unsigned int new_time;
+
+ spin_lock(&ip->i_spin);
+
+ if (time_after(ip->i_last_pfault + quantum, jiffies)) {
+ new_time = ip->i_greedy + quantum;
+ if (new_time > max)
+ new_time = max;
+ } else {
+ new_time = ip->i_greedy - quantum;
+ if (!new_time || new_time > max)
+ new_time = 1;
+ }
+
+ ip->i_greedy = new_time;
+
+ spin_unlock(&ip->i_spin);
+
+ iput(&ip->i_inode);
+}
+
+/**
+ * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int rgrp_go_demote_ok(struct gfs2_glock *gl)
+{
+ return !gl->gl_aspace->i_mapping->nrpages;
+}
+
+/**
+ * rgrp_go_lock - operation done after an rgrp lock is locked by
+ * a first holder on this node.
+ * @gl: the glock
+ * @flags:
+ *
+ * Returns: errno
+ */
+
+static int rgrp_go_lock(struct gfs2_holder *gh)
+{
+ return gfs2_rgrp_bh_get(gh->gh_gl->gl_object);
+}
+
+/**
+ * rgrp_go_unlock - operation done before an rgrp lock is unlocked by
+ * a last holder on this node.
+ * @gl: the glock
+ * @flags:
+ *
+ */
+
+static void rgrp_go_unlock(struct gfs2_holder *gh)
+{
+ gfs2_rgrp_bh_put(gh->gh_gl->gl_object);
+}
+
+/**
+ * trans_go_xmote_th - promote/demote the transaction glock
+ * @gl: the glock
+ * @state: the requested state
+ * @flags:
+ *
+ */
+
+static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
+ int flags)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+
+ if (gl->gl_state != LM_ST_UNLOCKED &&
+ test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+ gfs2_meta_syncfs(sdp);
+ gfs2_log_shutdown(sdp);
+ }
+
+ gfs2_glock_xmote_th(gl, state, flags);
+}
+
+/**
+ * trans_go_xmote_bh - After promoting/demoting the transaction glock
+ * @gl: the glock
+ *
+ */
+
+static void trans_go_xmote_bh(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
+ struct gfs2_glock *j_gl = ip->i_gl;
+ struct gfs2_log_header head;
+ int error;
+
+ if (gl->gl_state != LM_ST_UNLOCKED &&
+ test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+ gfs2_meta_cache_flush(GFS2_I(sdp->sd_jdesc->jd_inode));
+ j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
+
+ error = gfs2_find_jhead(sdp->sd_jdesc, &head);
+ if (error)
+ gfs2_consist(sdp);
+ if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT))
+ gfs2_consist(sdp);
+
+ /* Initialize some head of the log stuff */
+ if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
+ sdp->sd_log_sequence = head.lh_sequence + 1;
+ gfs2_log_pointers_init(sdp, head.lh_blkno);
+ }
+ }
+}
+
+/**
+ * trans_go_drop_th - unlock the transaction glock
+ * @gl: the glock
+ *
+ * We want to sync the device even with localcaching. Remember
+ * that localcaching journal replay only marks buffers dirty.
+ */
+
+static void trans_go_drop_th(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+
+ if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+ gfs2_meta_syncfs(sdp);
+ gfs2_log_shutdown(sdp);
+ }
+
+ gfs2_glock_drop_th(gl);
+}
+
+/**
+ * quota_go_demote_ok - Check to see if it's ok to unlock a quota glock
+ * @gl: the glock
+ *
+ * Returns: 1 if it's ok
+ */
+
+static int quota_go_demote_ok(struct gfs2_glock *gl)
+{
+ return !atomic_read(&gl->gl_lvb_count);
+}
+
+const struct gfs2_glock_operations gfs2_meta_glops = {
+ .go_xmote_th = gfs2_glock_xmote_th,
+ .go_drop_th = gfs2_glock_drop_th,
+ .go_type = LM_TYPE_META,
+};
+
+const struct gfs2_glock_operations gfs2_inode_glops = {
+ .go_xmote_th = inode_go_xmote_th,
+ .go_xmote_bh = inode_go_xmote_bh,
+ .go_drop_th = inode_go_drop_th,
+ .go_sync = inode_go_sync,
+ .go_inval = inode_go_inval,
+ .go_demote_ok = inode_go_demote_ok,
+ .go_lock = inode_go_lock,
+ .go_unlock = inode_go_unlock,
+ .go_greedy = inode_greedy,
+ .go_type = LM_TYPE_INODE,
+};
+
+const struct gfs2_glock_operations gfs2_rgrp_glops = {
+ .go_xmote_th = gfs2_glock_xmote_th,
+ .go_drop_th = gfs2_glock_drop_th,
+ .go_sync = meta_go_sync,
+ .go_inval = meta_go_inval,
+ .go_demote_ok = rgrp_go_demote_ok,
+ .go_lock = rgrp_go_lock,
+ .go_unlock = rgrp_go_unlock,
+ .go_type = LM_TYPE_RGRP,
+};
+
+const struct gfs2_glock_operations gfs2_trans_glops = {
+ .go_xmote_th = trans_go_xmote_th,
+ .go_xmote_bh = trans_go_xmote_bh,
+ .go_drop_th = trans_go_drop_th,
+ .go_type = LM_TYPE_NONDISK,
+};
+
+const struct gfs2_glock_operations gfs2_iopen_glops = {
+ .go_xmote_th = gfs2_glock_xmote_th,
+ .go_drop_th = gfs2_glock_drop_th,
+ .go_type = LM_TYPE_IOPEN,
+};
+
+const struct gfs2_glock_operations gfs2_flock_glops = {
+ .go_xmote_th = gfs2_glock_xmote_th,
+ .go_drop_th = gfs2_glock_drop_th,
+ .go_type = LM_TYPE_FLOCK,
+};
+
+const struct gfs2_glock_operations gfs2_nondisk_glops = {
+ .go_xmote_th = gfs2_glock_xmote_th,
+ .go_drop_th = gfs2_glock_drop_th,
+ .go_type = LM_TYPE_NONDISK,
+};
+
+const struct gfs2_glock_operations gfs2_quota_glops = {
+ .go_xmote_th = gfs2_glock_xmote_th,
+ .go_drop_th = gfs2_glock_drop_th,
+ .go_demote_ok = quota_go_demote_ok,
+ .go_type = LM_TYPE_QUOTA,
+};
+
+const struct gfs2_glock_operations gfs2_journal_glops = {
+ .go_xmote_th = gfs2_glock_xmote_th,
+ .go_drop_th = gfs2_glock_drop_th,
+ .go_type = LM_TYPE_JOURNAL,
+};
+
diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h
new file mode 100644
index 000000000000..a1d9b5b024e6
--- /dev/null
+++ b/fs/gfs2/glops.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __GLOPS_DOT_H__
+#define __GLOPS_DOT_H__
+
+#include "incore.h"
+
+extern const struct gfs2_glock_operations gfs2_meta_glops;
+extern const struct gfs2_glock_operations gfs2_inode_glops;
+extern const struct gfs2_glock_operations gfs2_rgrp_glops;
+extern const struct gfs2_glock_operations gfs2_trans_glops;
+extern const struct gfs2_glock_operations gfs2_iopen_glops;
+extern const struct gfs2_glock_operations gfs2_flock_glops;
+extern const struct gfs2_glock_operations gfs2_nondisk_glops;
+extern const struct gfs2_glock_operations gfs2_quota_glops;
+extern const struct gfs2_glock_operations gfs2_journal_glops;
+
+#endif /* __GLOPS_DOT_H__ */
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
new file mode 100644
index 000000000000..118dc693d111
--- /dev/null
+++ b/fs/gfs2/incore.h
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __INCORE_DOT_H__
+#define __INCORE_DOT_H__
+
+#include <linux/fs.h>
+
+#define DIO_WAIT 0x00000010
+#define DIO_METADATA 0x00000020
+#define DIO_DATA 0x00000040
+#define DIO_RELEASE 0x00000080
+#define DIO_ALL 0x00000100
+
+struct gfs2_log_operations;
+struct gfs2_log_element;
+struct gfs2_holder;
+struct gfs2_glock;
+struct gfs2_quota_data;
+struct gfs2_trans;
+struct gfs2_ail;
+struct gfs2_jdesc;
+struct gfs2_sbd;
+
+typedef void (*gfs2_glop_bh_t) (struct gfs2_glock *gl, unsigned int ret);
+
+/*
+ * Structure of operations that are associated with each
+ * type of element in the log.
+ */
+
+struct gfs2_log_operations {
+ void (*lo_add) (struct gfs2_sbd *sdp, struct gfs2_log_element *le);
+ void (*lo_incore_commit) (struct gfs2_sbd *sdp, struct gfs2_trans *tr);
+ void (*lo_before_commit) (struct gfs2_sbd *sdp);
+ void (*lo_after_commit) (struct gfs2_sbd *sdp, struct gfs2_ail *ai);
+ void (*lo_before_scan) (struct gfs2_jdesc *jd,
+ struct gfs2_log_header *head, int pass);
+ int (*lo_scan_elements) (struct gfs2_jdesc *jd, unsigned int start,
+ struct gfs2_log_descriptor *ld, __be64 *ptr,
+ int pass);
+ void (*lo_after_scan) (struct gfs2_jdesc *jd, int error, int pass);
+ const char *lo_name;
+};
+
+struct gfs2_log_element {
+ struct list_head le_list;
+ const struct gfs2_log_operations *le_ops;
+};
+
+struct gfs2_bitmap {
+ struct buffer_head *bi_bh;
+ char *bi_clone;
+ u32 bi_offset;
+ u32 bi_start;
+ u32 bi_len;
+};
+
+struct gfs2_rgrpd {
+ struct list_head rd_list; /* Link with superblock */
+ struct list_head rd_list_mru;
+ struct list_head rd_recent; /* Recently used rgrps */
+ struct gfs2_glock *rd_gl; /* Glock for this rgrp */
+ struct gfs2_rindex rd_ri;
+ struct gfs2_rgrp rd_rg;
+ u64 rd_rg_vn;
+ struct gfs2_bitmap *rd_bits;
+ unsigned int rd_bh_count;
+ struct mutex rd_mutex;
+ u32 rd_free_clone;
+ struct gfs2_log_element rd_le;
+ u32 rd_last_alloc_data;
+ u32 rd_last_alloc_meta;
+ struct gfs2_sbd *rd_sbd;
+};
+
+enum gfs2_state_bits {
+ BH_Pinned = BH_PrivateStart,
+ BH_Escaped = BH_PrivateStart + 1,
+};
+
+BUFFER_FNS(Pinned, pinned)
+TAS_BUFFER_FNS(Pinned, pinned)
+BUFFER_FNS(Escaped, escaped)
+TAS_BUFFER_FNS(Escaped, escaped)
+
+struct gfs2_bufdata {
+ struct buffer_head *bd_bh;
+ struct gfs2_glock *bd_gl;
+
+ struct list_head bd_list_tr;
+ struct gfs2_log_element bd_le;
+
+ struct gfs2_ail *bd_ail;
+ struct list_head bd_ail_st_list;
+ struct list_head bd_ail_gl_list;
+};
+
+struct gfs2_glock_operations {
+ void (*go_xmote_th) (struct gfs2_glock * gl, unsigned int state,
+ int flags);
+ void (*go_xmote_bh) (struct gfs2_glock * gl);
+ void (*go_drop_th) (struct gfs2_glock * gl);
+ void (*go_drop_bh) (struct gfs2_glock * gl);
+ void (*go_sync) (struct gfs2_glock * gl, int flags);
+ void (*go_inval) (struct gfs2_glock * gl, int flags);
+ int (*go_demote_ok) (struct gfs2_glock * gl);
+ int (*go_lock) (struct gfs2_holder * gh);
+ void (*go_unlock) (struct gfs2_holder * gh);
+ void (*go_callback) (struct gfs2_glock * gl, unsigned int state);
+ void (*go_greedy) (struct gfs2_glock * gl);
+ const int go_type;
+};
+
+enum {
+ /* Actions */
+ HIF_MUTEX = 0,
+ HIF_PROMOTE = 1,
+ HIF_DEMOTE = 2,
+ HIF_GREEDY = 3,
+
+ /* States */
+ HIF_ALLOCED = 4,
+ HIF_DEALLOC = 5,
+ HIF_HOLDER = 6,
+ HIF_FIRST = 7,
+ HIF_ABORTED = 9,
+};
+
+struct gfs2_holder {
+ struct list_head gh_list;
+
+ struct gfs2_glock *gh_gl;
+ struct task_struct *gh_owner;
+ unsigned int gh_state;
+ unsigned gh_flags;
+
+ int gh_error;
+ unsigned long gh_iflags;
+ struct completion gh_wait;
+ unsigned long gh_ip;
+};
+
+enum {
+ GLF_LOCK = 1,
+ GLF_STICKY = 2,
+ GLF_PREFETCH = 3,
+ GLF_DIRTY = 5,
+ GLF_SKIP_WAITERS2 = 6,
+ GLF_GREEDY = 7,
+};
+
+struct gfs2_glock {
+ struct hlist_node gl_list;
+ unsigned long gl_flags; /* GLF_... */
+ struct lm_lockname gl_name;
+ atomic_t gl_ref;
+
+ spinlock_t gl_spin;
+
+ unsigned int gl_state;
+ unsigned int gl_hash;
+ struct task_struct *gl_owner;
+ unsigned long gl_ip;
+ struct list_head gl_holders;
+ struct list_head gl_waiters1; /* HIF_MUTEX */
+ struct list_head gl_waiters2; /* HIF_DEMOTE, HIF_GREEDY */
+ struct list_head gl_waiters3; /* HIF_PROMOTE */
+
+ const struct gfs2_glock_operations *gl_ops;
+
+ struct gfs2_holder *gl_req_gh;
+ gfs2_glop_bh_t gl_req_bh;
+
+ void *gl_lock;
+ char *gl_lvb;
+ atomic_t gl_lvb_count;
+
+ u64 gl_vn;
+ unsigned long gl_stamp;
+ void *gl_object;
+
+ struct list_head gl_reclaim;
+
+ struct gfs2_sbd *gl_sbd;
+
+ struct inode *gl_aspace;
+ struct gfs2_log_element gl_le;
+ struct list_head gl_ail_list;
+ atomic_t gl_ail_count;
+};
+
+struct gfs2_alloc {
+ /* Quota stuff */
+
+ struct gfs2_quota_data *al_qd[2*MAXQUOTAS];
+ struct gfs2_holder al_qd_ghs[2*MAXQUOTAS];
+ unsigned int al_qd_num;
+
+ u32 al_requested; /* Filled in by caller of gfs2_inplace_reserve() */
+ u32 al_alloced; /* Filled in by gfs2_alloc_*() */
+
+ /* Filled in by gfs2_inplace_reserve() */
+
+ unsigned int al_line;
+ char *al_file;
+ struct gfs2_holder al_ri_gh;
+ struct gfs2_holder al_rgd_gh;
+ struct gfs2_rgrpd *al_rgd;
+
+};
+
+enum {
+ GIF_QD_LOCKED = 1,
+ GIF_PAGED = 2,
+ GIF_SW_PAGED = 3,
+};
+
+struct gfs2_inode {
+ struct inode i_inode;
+ struct gfs2_inum i_num;
+
+ unsigned long i_flags; /* GIF_... */
+
+ u64 i_vn;
+ struct gfs2_dinode i_di; /* To be replaced by ref to block */
+
+ struct gfs2_glock *i_gl; /* Move into i_gh? */
+ struct gfs2_holder i_iopen_gh;
+ struct gfs2_holder i_gh; /* for prepare/commit_write only */
+ struct gfs2_alloc i_alloc;
+ u64 i_last_rg_alloc;
+
+ spinlock_t i_spin;
+ struct rw_semaphore i_rw_mutex;
+ unsigned int i_greedy;
+ unsigned long i_last_pfault;
+
+ struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
+};
+
+/*
+ * Since i_inode is the first element of struct gfs2_inode,
+ * this is effectively a cast.
+ */
+static inline struct gfs2_inode *GFS2_I(struct inode *inode)
+{
+ return container_of(inode, struct gfs2_inode, i_inode);
+}
+
+/* To be removed? */
+static inline struct gfs2_sbd *GFS2_SB(struct inode *inode)
+{
+ return inode->i_sb->s_fs_info;
+}
+
+enum {
+ GFF_DID_DIRECT_ALLOC = 0,
+ GFF_EXLOCK = 1,
+};
+
+struct gfs2_file {
+ unsigned long f_flags; /* GFF_... */
+ struct mutex f_fl_mutex;
+ struct gfs2_holder f_fl_gh;
+};
+
+struct gfs2_revoke {
+ struct gfs2_log_element rv_le;
+ u64 rv_blkno;
+};
+
+struct gfs2_revoke_replay {
+ struct list_head rr_list;
+ u64 rr_blkno;
+ unsigned int rr_where;
+};
+
+enum {
+ QDF_USER = 0,
+ QDF_CHANGE = 1,
+ QDF_LOCKED = 2,
+};
+
+struct gfs2_quota_lvb {
+ __be32 qb_magic;
+ u32 __pad;
+ __be64 qb_limit; /* Hard limit of # blocks to alloc */
+ __be64 qb_warn; /* Warn user when alloc is above this # */
+ __be64 qb_value; /* Current # blocks allocated */
+};
+
+struct gfs2_quota_data {
+ struct list_head qd_list;
+ unsigned int qd_count;
+
+ u32 qd_id;
+ unsigned long qd_flags; /* QDF_... */
+
+ s64 qd_change;
+ s64 qd_change_sync;
+
+ unsigned int qd_slot;
+ unsigned int qd_slot_count;
+
+ struct buffer_head *qd_bh;
+ struct gfs2_quota_change *qd_bh_qc;
+ unsigned int qd_bh_count;
+
+ struct gfs2_glock *qd_gl;
+ struct gfs2_quota_lvb qd_qb;
+
+ u64 qd_sync_gen;
+ unsigned long qd_last_warn;
+ unsigned long qd_last_touched;
+};
+
+struct gfs2_log_buf {
+ struct list_head lb_list;
+ struct buffer_head *lb_bh;
+ struct buffer_head *lb_real;
+};
+
+struct gfs2_trans {
+ unsigned long tr_ip;
+
+ unsigned int tr_blocks;
+ unsigned int tr_revokes;
+ unsigned int tr_reserved;
+
+ struct gfs2_holder tr_t_gh;
+
+ int tr_touched;
+
+ unsigned int tr_num_buf;
+ unsigned int tr_num_buf_new;
+ unsigned int tr_num_buf_rm;
+ struct list_head tr_list_buf;
+
+ unsigned int tr_num_revoke;
+ unsigned int tr_num_revoke_rm;
+};
+
+struct gfs2_ail {
+ struct list_head ai_list;
+
+ unsigned int ai_first;
+ struct list_head ai_ail1_list;
+ struct list_head ai_ail2_list;
+
+ u64 ai_sync_gen;
+};
+
+struct gfs2_jdesc {
+ struct list_head jd_list;
+
+ struct inode *jd_inode;
+ unsigned int jd_jid;
+ int jd_dirty;
+
+ unsigned int jd_blocks;
+};
+
+#define GFS2_GLOCKD_DEFAULT 1
+#define GFS2_GLOCKD_MAX 16
+
+#define GFS2_QUOTA_DEFAULT GFS2_QUOTA_OFF
+#define GFS2_QUOTA_OFF 0
+#define GFS2_QUOTA_ACCOUNT 1
+#define GFS2_QUOTA_ON 2
+
+#define GFS2_DATA_DEFAULT GFS2_DATA_ORDERED
+#define GFS2_DATA_WRITEBACK 1
+#define GFS2_DATA_ORDERED 2
+
+struct gfs2_args {
+ char ar_lockproto[GFS2_LOCKNAME_LEN]; /* Name of the Lock Protocol */
+ char ar_locktable[GFS2_LOCKNAME_LEN]; /* Name of the Lock Table */
+ char ar_hostdata[GFS2_LOCKNAME_LEN]; /* Host specific data */
+ int ar_spectator; /* Don't get a journal because we're always RO */
+ int ar_ignore_local_fs; /* Don't optimize even if local_fs is 1 */
+ int ar_localflocks; /* Let the VFS do flock|fcntl locks for us */
+ int ar_localcaching; /* Local-style caching (dangerous on multihost) */
+ int ar_debug; /* Oops on errors instead of trying to be graceful */
+ int ar_upgrade; /* Upgrade ondisk/multihost format */
+ unsigned int ar_num_glockd; /* Number of glockd threads */
+ int ar_posix_acl; /* Enable posix acls */
+ int ar_quota; /* off/account/on */
+ int ar_suiddir; /* suiddir support */
+ int ar_data; /* ordered/writeback */
+};
+
+struct gfs2_tune {
+ spinlock_t gt_spin;
+
+ unsigned int gt_ilimit;
+ unsigned int gt_ilimit_tries;
+ unsigned int gt_ilimit_min;
+ unsigned int gt_demote_secs; /* Cache retention for unheld glock */
+ unsigned int gt_incore_log_blocks;
+ unsigned int gt_log_flush_secs;
+ unsigned int gt_jindex_refresh_secs; /* Check for new journal index */
+
+ unsigned int gt_scand_secs;
+ unsigned int gt_recoverd_secs;
+ unsigned int gt_logd_secs;
+ unsigned int gt_quotad_secs;
+
+ unsigned int gt_quota_simul_sync; /* Max quotavals to sync at once */
+ unsigned int gt_quota_warn_period; /* Secs between quota warn msgs */
+ unsigned int gt_quota_scale_num; /* Numerator */
+ unsigned int gt_quota_scale_den; /* Denominator */
+ unsigned int gt_quota_cache_secs;
+ unsigned int gt_quota_quantum; /* Secs between syncs to quota file */
+ unsigned int gt_atime_quantum; /* Min secs between atime updates */
+ unsigned int gt_new_files_jdata;
+ unsigned int gt_new_files_directio;
+ unsigned int gt_max_atomic_write; /* Split big writes into this size */
+ unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
+ unsigned int gt_lockdump_size;
+ unsigned int gt_stall_secs; /* Detects trouble! */
+ unsigned int gt_complain_secs;
+ unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
+ unsigned int gt_entries_per_readdir;
+ unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */
+ unsigned int gt_greedy_default;
+ unsigned int gt_greedy_quantum;
+ unsigned int gt_greedy_max;
+ unsigned int gt_statfs_quantum;
+ unsigned int gt_statfs_slow;
+};
+
+enum {
+ SDF_JOURNAL_CHECKED = 0,
+ SDF_JOURNAL_LIVE = 1,
+ SDF_SHUTDOWN = 2,
+ SDF_NOATIME = 3,
+};
+
+#define GFS2_FSNAME_LEN 256
+
+struct gfs2_sbd {
+ struct super_block *sd_vfs;
+ struct super_block *sd_vfs_meta;
+ struct kobject sd_kobj;
+ unsigned long sd_flags; /* SDF_... */
+ struct gfs2_sb sd_sb;
+
+ /* Constants computed on mount */
+
+ u32 sd_fsb2bb;
+ u32 sd_fsb2bb_shift;
+ u32 sd_diptrs; /* Number of pointers in a dinode */
+ u32 sd_inptrs; /* Number of pointers in a indirect block */
+ u32 sd_jbsize; /* Size of a journaled data block */
+ u32 sd_hash_bsize; /* sizeof(exhash block) */
+ u32 sd_hash_bsize_shift;
+ u32 sd_hash_ptrs; /* Number of pointers in a hash block */
+ u32 sd_qc_per_block;
+ u32 sd_max_dirres; /* Max blocks needed to add a directory entry */
+ u32 sd_max_height; /* Max height of a file's metadata tree */
+ u64 sd_heightsize[GFS2_MAX_META_HEIGHT];
+ u32 sd_max_jheight; /* Max height of journaled file's meta tree */
+ u64 sd_jheightsize[GFS2_MAX_META_HEIGHT];
+
+ struct gfs2_args sd_args; /* Mount arguments */
+ struct gfs2_tune sd_tune; /* Filesystem tuning structure */
+
+ /* Lock Stuff */
+
+ struct lm_lockstruct sd_lockstruct;
+ struct list_head sd_reclaim_list;
+ spinlock_t sd_reclaim_lock;
+ wait_queue_head_t sd_reclaim_wq;
+ atomic_t sd_reclaim_count;
+ struct gfs2_holder sd_live_gh;
+ struct gfs2_glock *sd_rename_gl;
+ struct gfs2_glock *sd_trans_gl;
+
+ /* Inode Stuff */
+
+ struct inode *sd_master_dir;
+ struct inode *sd_jindex;
+ struct inode *sd_inum_inode;
+ struct inode *sd_statfs_inode;
+ struct inode *sd_ir_inode;
+ struct inode *sd_sc_inode;
+ struct inode *sd_qc_inode;
+ struct inode *sd_rindex;
+ struct inode *sd_quota_inode;
+
+ /* Inum stuff */
+
+ struct mutex sd_inum_mutex;
+
+ /* StatFS stuff */
+
+ spinlock_t sd_statfs_spin;
+ struct mutex sd_statfs_mutex;
+ struct gfs2_statfs_change sd_statfs_master;
+ struct gfs2_statfs_change sd_statfs_local;
+ unsigned long sd_statfs_sync_time;
+
+ /* Resource group stuff */
+
+ u64 sd_rindex_vn;
+ spinlock_t sd_rindex_spin;
+ struct mutex sd_rindex_mutex;
+ struct list_head sd_rindex_list;
+ struct list_head sd_rindex_mru_list;
+ struct list_head sd_rindex_recent_list;
+ struct gfs2_rgrpd *sd_rindex_forward;
+ unsigned int sd_rgrps;
+
+ /* Journal index stuff */
+
+ struct list_head sd_jindex_list;
+ spinlock_t sd_jindex_spin;
+ struct mutex sd_jindex_mutex;
+ unsigned int sd_journals;
+ unsigned long sd_jindex_refresh_time;
+
+ struct gfs2_jdesc *sd_jdesc;
+ struct gfs2_holder sd_journal_gh;
+ struct gfs2_holder sd_jinode_gh;
+
+ struct gfs2_holder sd_ir_gh;
+ struct gfs2_holder sd_sc_gh;
+ struct gfs2_holder sd_qc_gh;
+
+ /* Daemon stuff */
+
+ struct task_struct *sd_scand_process;
+ struct task_struct *sd_recoverd_process;
+ struct task_struct *sd_logd_process;
+ struct task_struct *sd_quotad_process;
+ struct task_struct *sd_glockd_process[GFS2_GLOCKD_MAX];
+ unsigned int sd_glockd_num;
+
+ /* Quota stuff */
+
+ struct list_head sd_quota_list;
+ atomic_t sd_quota_count;
+ spinlock_t sd_quota_spin;
+ struct mutex sd_quota_mutex;
+
+ unsigned int sd_quota_slots;
+ unsigned int sd_quota_chunks;
+ unsigned char **sd_quota_bitmap;
+
+ u64 sd_quota_sync_gen;
+ unsigned long sd_quota_sync_time;
+
+ /* Log stuff */
+
+ spinlock_t sd_log_lock;
+
+ unsigned int sd_log_blks_reserved;
+ unsigned int sd_log_commited_buf;
+ unsigned int sd_log_commited_revoke;
+
+ unsigned int sd_log_num_gl;
+ unsigned int sd_log_num_buf;
+ unsigned int sd_log_num_revoke;
+ unsigned int sd_log_num_rg;
+ unsigned int sd_log_num_databuf;
+ unsigned int sd_log_num_jdata;
+ unsigned int sd_log_num_hdrs;
+
+ struct list_head sd_log_le_gl;
+ struct list_head sd_log_le_buf;
+ struct list_head sd_log_le_revoke;
+ struct list_head sd_log_le_rg;
+ struct list_head sd_log_le_databuf;
+
+ unsigned int sd_log_blks_free;
+ struct mutex sd_log_reserve_mutex;
+
+ u64 sd_log_sequence;
+ unsigned int sd_log_head;
+ unsigned int sd_log_tail;
+ int sd_log_idle;
+
+ unsigned long sd_log_flush_time;
+ struct rw_semaphore sd_log_flush_lock;
+ struct list_head sd_log_flush_list;
+
+ unsigned int sd_log_flush_head;
+ u64 sd_log_flush_wrapped;
+
+ struct list_head sd_ail1_list;
+ struct list_head sd_ail2_list;
+ u64 sd_ail_sync_gen;
+
+ /* Replay stuff */
+
+ struct list_head sd_revoke_list;
+ unsigned int sd_replay_tail;
+
+ unsigned int sd_found_blocks;
+ unsigned int sd_found_revokes;
+ unsigned int sd_replayed_blocks;
+
+ /* For quiescing the filesystem */
+
+ struct gfs2_holder sd_freeze_gh;
+ struct mutex sd_freeze_lock;
+ unsigned int sd_freeze_count;
+
+ /* Counters */
+
+ atomic_t sd_glock_count;
+ atomic_t sd_glock_held_count;
+ atomic_t sd_inode_count;
+ atomic_t sd_reclaimed;
+
+ char sd_fsname[GFS2_FSNAME_LEN];
+ char sd_table_name[GFS2_FSNAME_LEN];
+ char sd_proto_name[GFS2_FSNAME_LEN];
+
+ /* Debugging crud */
+
+ unsigned long sd_last_warning;
+ struct vfsmount *sd_gfs2mnt;
+};
+
+#endif /* __INCORE_DOT_H__ */
+
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
new file mode 100644
index 000000000000..57c43ac47925
--- /dev/null
+++ b/fs/gfs2/inode.c
@@ -0,0 +1,1379 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/posix_acl.h>
+#include <linux/sort.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+#include <linux/security.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "bmap.h"
+#include "dir.h"
+#include "eattr.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "ops_address.h"
+#include "ops_file.h"
+#include "ops_inode.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+/**
+ * gfs2_inode_attr_in - Copy attributes from the dinode into the VFS inode
+ * @ip: The GFS2 inode (with embedded disk inode data)
+ * @inode: The Linux VFS inode
+ *
+ */
+
+void gfs2_inode_attr_in(struct gfs2_inode *ip)
+{
+ struct inode *inode = &ip->i_inode;
+ struct gfs2_dinode *di = &ip->i_di;
+
+ inode->i_ino = ip->i_num.no_addr;
+
+ switch (di->di_mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+ inode->i_rdev = MKDEV(di->di_major, di->di_minor);
+ break;
+ default:
+ inode->i_rdev = 0;
+ break;
+ };
+
+ inode->i_mode = di->di_mode;
+ inode->i_nlink = di->di_nlink;
+ inode->i_uid = di->di_uid;
+ inode->i_gid = di->di_gid;
+ i_size_write(inode, di->di_size);
+ inode->i_atime.tv_sec = di->di_atime;
+ inode->i_mtime.tv_sec = di->di_mtime;
+ inode->i_ctime.tv_sec = di->di_ctime;
+ inode->i_atime.tv_nsec = 0;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_blocks = di->di_blocks <<
+ (GFS2_SB(inode)->sd_sb.sb_bsize_shift - GFS2_BASIC_BLOCK_SHIFT);
+
+ if (di->di_flags & GFS2_DIF_IMMUTABLE)
+ inode->i_flags |= S_IMMUTABLE;
+ else
+ inode->i_flags &= ~S_IMMUTABLE;
+
+ if (di->di_flags & GFS2_DIF_APPENDONLY)
+ inode->i_flags |= S_APPEND;
+ else
+ inode->i_flags &= ~S_APPEND;
+}
+
+/**
+ * gfs2_inode_attr_out - Copy attributes from VFS inode into the dinode
+ * @ip: The GFS2 inode
+ *
+ * Only copy out the attributes that we want the VFS layer
+ * to be able to modify.
+ */
+
+void gfs2_inode_attr_out(struct gfs2_inode *ip)
+{
+ struct inode *inode = &ip->i_inode;
+ struct gfs2_dinode *di = &ip->i_di;
+ gfs2_assert_withdraw(GFS2_SB(inode),
+ (di->di_mode & S_IFMT) == (inode->i_mode & S_IFMT));
+ di->di_mode = inode->i_mode;
+ di->di_uid = inode->i_uid;
+ di->di_gid = inode->i_gid;
+ di->di_atime = inode->i_atime.tv_sec;
+ di->di_mtime = inode->i_mtime.tv_sec;
+ di->di_ctime = inode->i_ctime.tv_sec;
+}
+
+static int iget_test(struct inode *inode, void *opaque)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_inum *inum = opaque;
+
+ if (ip && ip->i_num.no_addr == inum->no_addr)
+ return 1;
+
+ return 0;
+}
+
+static int iget_set(struct inode *inode, void *opaque)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_inum *inum = opaque;
+
+ ip->i_num = *inum;
+ return 0;
+}
+
+struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum)
+{
+ return ilookup5(sb, (unsigned long)inum->no_formal_ino,
+ iget_test, inum);
+}
+
+static struct inode *gfs2_iget(struct super_block *sb, struct gfs2_inum *inum)
+{
+ return iget5_locked(sb, (unsigned long)inum->no_formal_ino,
+ iget_test, iget_set, inum);
+}
+
+/**
+ * gfs2_inode_lookup - Lookup an inode
+ * @sb: The super block
+ * @inum: The inode number
+ * @type: The type of the inode
+ *
+ * Returns: A VFS inode, or an error
+ */
+
+struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned int type)
+{
+ struct inode *inode = gfs2_iget(sb, inum);
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_glock *io_gl;
+ int error;
+
+ if (inode->i_state & I_NEW) {
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ umode_t mode = DT2IF(type);
+ inode->i_private = ip;
+ inode->i_mode = mode;
+
+ if (S_ISREG(mode)) {
+ inode->i_op = &gfs2_file_iops;
+ inode->i_fop = &gfs2_file_fops;
+ inode->i_mapping->a_ops = &gfs2_file_aops;
+ } else if (S_ISDIR(mode)) {
+ inode->i_op = &gfs2_dir_iops;
+ inode->i_fop = &gfs2_dir_fops;
+ } else if (S_ISLNK(mode)) {
+ inode->i_op = &gfs2_symlink_iops;
+ } else {
+ inode->i_op = &gfs2_dev_iops;
+ }
+
+ error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_inode_glops, CREATE, &ip->i_gl);
+ if (unlikely(error))
+ goto fail;
+ ip->i_gl->gl_object = ip;
+
+ error = gfs2_glock_get(sdp, inum->no_addr, &gfs2_iopen_glops, CREATE, &io_gl);
+ if (unlikely(error))
+ goto fail_put;
+
+ ip->i_vn = ip->i_gl->gl_vn - 1;
+ error = gfs2_glock_nq_init(io_gl, LM_ST_SHARED, GL_EXACT, &ip->i_iopen_gh);
+ if (unlikely(error))
+ goto fail_iopen;
+
+ gfs2_glock_put(io_gl);
+ unlock_new_inode(inode);
+ }
+
+ return inode;
+fail_iopen:
+ gfs2_glock_put(io_gl);
+fail_put:
+ ip->i_gl->gl_object = NULL;
+ gfs2_glock_put(ip->i_gl);
+fail:
+ iput(inode);
+ return ERR_PTR(error);
+}
+
+/**
+ * gfs2_inode_refresh - Refresh the incore copy of the dinode
+ * @ip: The GFS2 inode
+ *
+ * Returns: errno
+ */
+
+int gfs2_inode_refresh(struct gfs2_inode *ip)
+{
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ return error;
+
+ if (gfs2_metatype_check(GFS2_SB(&ip->i_inode), dibh, GFS2_METATYPE_DI)) {
+ brelse(dibh);
+ return -EIO;
+ }
+
+ gfs2_dinode_in(&ip->i_di, dibh->b_data);
+
+ brelse(dibh);
+
+ if (ip->i_num.no_addr != ip->i_di.di_num.no_addr) {
+ if (gfs2_consist_inode(ip))
+ gfs2_dinode_print(&ip->i_di);
+ return -EIO;
+ }
+ if (ip->i_num.no_formal_ino != ip->i_di.di_num.no_formal_ino)
+ return -ESTALE;
+
+ ip->i_vn = ip->i_gl->gl_vn;
+
+ return 0;
+}
+
+int gfs2_dinode_dealloc(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al;
+ struct gfs2_rgrpd *rgd;
+ int error;
+
+ if (ip->i_di.di_blocks != 1) {
+ if (gfs2_consist_inode(ip))
+ gfs2_dinode_print(&ip->i_di);
+ return -EIO;
+ }
+
+ al = gfs2_alloc_get(ip);
+
+ error = gfs2_quota_hold(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out;
+
+ error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
+ if (error)
+ goto out_qs;
+
+ rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+ if (!rgd) {
+ gfs2_consist_inode(ip);
+ error = -EIO;
+ goto out_rindex_relse;
+ }
+
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0,
+ &al->al_rgd_gh);
+ if (error)
+ goto out_rindex_relse;
+
+ error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS + RES_QUOTA, 1);
+ if (error)
+ goto out_rg_gunlock;
+
+ gfs2_trans_add_gl(ip->i_gl);
+
+ gfs2_free_di(rgd, ip);
+
+ gfs2_trans_end(sdp);
+ clear_bit(GLF_STICKY, &ip->i_gl->gl_flags);
+
+out_rg_gunlock:
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
+out_rindex_relse:
+ gfs2_glock_dq_uninit(&al->al_ri_gh);
+out_qs:
+ gfs2_quota_unhold(ip);
+out:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
+/**
+ * gfs2_change_nlink - Change nlink count on inode
+ * @ip: The GFS2 inode
+ * @diff: The change in the nlink count required
+ *
+ * Returns: errno
+ */
+
+int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
+{
+ struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
+ struct buffer_head *dibh;
+ u32 nlink;
+ int error;
+
+ BUG_ON(ip->i_di.di_nlink != ip->i_inode.i_nlink);
+ nlink = ip->i_di.di_nlink + diff;
+
+ /* If we are reducing the nlink count, but the new value ends up being
+ bigger than the old one, we must have underflowed. */
+ if (diff < 0 && nlink > ip->i_di.di_nlink) {
+ if (gfs2_consist_inode(ip))
+ gfs2_dinode_print(&ip->i_di);
+ return -EIO;
+ }
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ return error;
+
+ ip->i_di.di_nlink = nlink;
+ ip->i_di.di_ctime = get_seconds();
+ ip->i_inode.i_nlink = nlink;
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ mark_inode_dirty(&ip->i_inode);
+
+ if (ip->i_di.di_nlink == 0) {
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_holder ri_gh, rg_gh;
+
+ error = gfs2_rindex_hold(sdp, &ri_gh);
+ if (error)
+ goto out;
+ error = -EIO;
+ rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+ if (!rgd)
+ goto out_norgrp;
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
+ if (error)
+ goto out_norgrp;
+
+ clear_nlink(&ip->i_inode);
+ gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
+ gfs2_glock_dq_uninit(&rg_gh);
+out_norgrp:
+ gfs2_glock_dq_uninit(&ri_gh);
+ }
+out:
+ return error;
+}
+
+struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
+{
+ struct qstr qstr;
+ gfs2_str2qstr(&qstr, name);
+ return gfs2_lookupi(dip, &qstr, 1, NULL);
+}
+
+
+/**
+ * gfs2_lookupi - Look up a filename in a directory and return its inode
+ * @d_gh: An initialized holder for the directory glock
+ * @name: The name of the inode to look for
+ * @is_root: If 1, ignore the caller's permissions
+ * @i_gh: An uninitialized holder for the new inode glock
+ *
+ * There will always be a vnode (Linux VFS inode) for the d_gh inode unless
+ * @is_root is true.
+ *
+ * Returns: errno
+ */
+
+struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
+ int is_root, struct nameidata *nd)
+{
+ struct super_block *sb = dir->i_sb;
+ struct gfs2_inode *dip = GFS2_I(dir);
+ struct gfs2_holder d_gh;
+ struct gfs2_inum inum;
+ unsigned int type;
+ int error = 0;
+ struct inode *inode = NULL;
+
+ if (!name->len || name->len > GFS2_FNAMESIZE)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ if ((name->len == 1 && memcmp(name->name, ".", 1) == 0) ||
+ (name->len == 2 && memcmp(name->name, "..", 2) == 0 &&
+ dir == sb->s_root->d_inode)) {
+ igrab(dir);
+ return dir;
+ }
+
+ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+ if (error)
+ return ERR_PTR(error);
+
+ if (!is_root) {
+ error = permission(dir, MAY_EXEC, NULL);
+ if (error)
+ goto out;
+ }
+
+ error = gfs2_dir_search(dir, name, &inum, &type);
+ if (error)
+ goto out;
+
+ inode = gfs2_inode_lookup(sb, &inum, type);
+
+out:
+ gfs2_glock_dq_uninit(&d_gh);
+ if (error == -ENOENT)
+ return NULL;
+ return inode;
+}
+
+static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
+{
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
+ struct buffer_head *bh;
+ struct gfs2_inum_range ir;
+ int error;
+
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ if (error)
+ return error;
+ mutex_lock(&sdp->sd_inum_mutex);
+
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error) {
+ mutex_unlock(&sdp->sd_inum_mutex);
+ gfs2_trans_end(sdp);
+ return error;
+ }
+
+ gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
+
+ if (ir.ir_length) {
+ *formal_ino = ir.ir_start++;
+ ir.ir_length--;
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ gfs2_inum_range_out(&ir,
+ bh->b_data + sizeof(struct gfs2_dinode));
+ brelse(bh);
+ mutex_unlock(&sdp->sd_inum_mutex);
+ gfs2_trans_end(sdp);
+ return 0;
+ }
+
+ brelse(bh);
+
+ mutex_unlock(&sdp->sd_inum_mutex);
+ gfs2_trans_end(sdp);
+
+ return 1;
+}
+
+static int pick_formal_ino_2(struct gfs2_sbd *sdp, u64 *formal_ino)
+{
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_ir_inode);
+ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_inum_inode);
+ struct gfs2_holder gh;
+ struct buffer_head *bh;
+ struct gfs2_inum_range ir;
+ int error;
+
+ error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+ if (error)
+ return error;
+
+ error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
+ if (error)
+ goto out;
+ mutex_lock(&sdp->sd_inum_mutex);
+
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error)
+ goto out_end_trans;
+
+ gfs2_inum_range_in(&ir, bh->b_data + sizeof(struct gfs2_dinode));
+
+ if (!ir.ir_length) {
+ struct buffer_head *m_bh;
+ u64 x, y;
+
+ error = gfs2_meta_inode_buffer(m_ip, &m_bh);
+ if (error)
+ goto out_brelse;
+
+ x = *(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode));
+ x = y = be64_to_cpu(x);
+ ir.ir_start = x;
+ ir.ir_length = GFS2_INUM_QUANTUM;
+ x += GFS2_INUM_QUANTUM;
+ if (x < y)
+ gfs2_consist_inode(m_ip);
+ x = cpu_to_be64(x);
+ gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
+ *(u64 *)(m_bh->b_data + sizeof(struct gfs2_dinode)) = x;
+
+ brelse(m_bh);
+ }
+
+ *formal_ino = ir.ir_start++;
+ ir.ir_length--;
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ gfs2_inum_range_out(&ir, bh->b_data + sizeof(struct gfs2_dinode));
+
+out_brelse:
+ brelse(bh);
+out_end_trans:
+ mutex_unlock(&sdp->sd_inum_mutex);
+ gfs2_trans_end(sdp);
+out:
+ gfs2_glock_dq_uninit(&gh);
+ return error;
+}
+
+static int pick_formal_ino(struct gfs2_sbd *sdp, u64 *inum)
+{
+ int error;
+
+ error = pick_formal_ino_1(sdp, inum);
+ if (error <= 0)
+ return error;
+
+ error = pick_formal_ino_2(sdp, inum);
+
+ return error;
+}
+
+/**
+ * create_ok - OK to create a new on-disk inode here?
+ * @dip: Directory in which dinode is to be created
+ * @name: Name of new dinode
+ * @mode:
+ *
+ * Returns: errno
+ */
+
+static int create_ok(struct gfs2_inode *dip, const struct qstr *name,
+ unsigned int mode)
+{
+ int error;
+
+ error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+ if (error)
+ return error;
+
+ /* Don't create entries in an unlinked directory */
+ if (!dip->i_di.di_nlink)
+ return -EPERM;
+
+ error = gfs2_dir_search(&dip->i_inode, name, NULL, NULL);
+ switch (error) {
+ case -ENOENT:
+ error = 0;
+ break;
+ case 0:
+ return -EEXIST;
+ default:
+ return error;
+ }
+
+ if (dip->i_di.di_entries == (u32)-1)
+ return -EFBIG;
+ if (S_ISDIR(mode) && dip->i_di.di_nlink == (u32)-1)
+ return -EMLINK;
+
+ return 0;
+}
+
+static void munge_mode_uid_gid(struct gfs2_inode *dip, unsigned int *mode,
+ unsigned int *uid, unsigned int *gid)
+{
+ if (GFS2_SB(&dip->i_inode)->sd_args.ar_suiddir &&
+ (dip->i_di.di_mode & S_ISUID) && dip->i_di.di_uid) {
+ if (S_ISDIR(*mode))
+ *mode |= S_ISUID;
+ else if (dip->i_di.di_uid != current->fsuid)
+ *mode &= ~07111;
+ *uid = dip->i_di.di_uid;
+ } else
+ *uid = current->fsuid;
+
+ if (dip->i_di.di_mode & S_ISGID) {
+ if (S_ISDIR(*mode))
+ *mode |= S_ISGID;
+ *gid = dip->i_di.di_gid;
+ } else
+ *gid = current->fsgid;
+}
+
+static int alloc_dinode(struct gfs2_inode *dip, struct gfs2_inum *inum,
+ u64 *generation)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ int error;
+
+ gfs2_alloc_get(dip);
+
+ dip->i_alloc.al_requested = RES_DINODE;
+ error = gfs2_inplace_reserve(dip);
+ if (error)
+ goto out;
+
+ error = gfs2_trans_begin(sdp, RES_RG_BIT + RES_STATFS, 0);
+ if (error)
+ goto out_ipreserv;
+
+ inum->no_addr = gfs2_alloc_di(dip, generation);
+
+ gfs2_trans_end(sdp);
+
+out_ipreserv:
+ gfs2_inplace_release(dip);
+out:
+ gfs2_alloc_put(dip);
+ return error;
+}
+
+/**
+ * init_dinode - Fill in a new dinode structure
+ * @dip: the directory this inode is being created in
+ * @gl: The glock covering the new inode
+ * @inum: the inode number
+ * @mode: the file permissions
+ * @uid:
+ * @gid:
+ *
+ */
+
+static void init_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
+ const struct gfs2_inum *inum, unsigned int mode,
+ unsigned int uid, unsigned int gid,
+ const u64 *generation)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct gfs2_dinode *di;
+ struct buffer_head *dibh;
+
+ dibh = gfs2_meta_new(gl, inum->no_addr);
+ gfs2_trans_add_bh(gl, dibh, 1);
+ gfs2_metatype_set(dibh, GFS2_METATYPE_DI, GFS2_FORMAT_DI);
+ gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
+ di = (struct gfs2_dinode *)dibh->b_data;
+
+ di->di_num.no_formal_ino = cpu_to_be64(inum->no_formal_ino);
+ di->di_num.no_addr = cpu_to_be64(inum->no_addr);
+ di->di_mode = cpu_to_be32(mode);
+ di->di_uid = cpu_to_be32(uid);
+ di->di_gid = cpu_to_be32(gid);
+ di->di_nlink = cpu_to_be32(0);
+ di->di_size = cpu_to_be64(0);
+ di->di_blocks = cpu_to_be64(1);
+ di->di_atime = di->di_mtime = di->di_ctime = cpu_to_be64(get_seconds());
+ di->di_major = di->di_minor = cpu_to_be32(0);
+ di->di_goal_meta = di->di_goal_data = cpu_to_be64(inum->no_addr);
+ di->di_generation = cpu_to_be64(*generation);
+ di->di_flags = cpu_to_be32(0);
+
+ if (S_ISREG(mode)) {
+ if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_JDATA) ||
+ gfs2_tune_get(sdp, gt_new_files_jdata))
+ di->di_flags |= cpu_to_be32(GFS2_DIF_JDATA);
+ if ((dip->i_di.di_flags & GFS2_DIF_INHERIT_DIRECTIO) ||
+ gfs2_tune_get(sdp, gt_new_files_directio))
+ di->di_flags |= cpu_to_be32(GFS2_DIF_DIRECTIO);
+ } else if (S_ISDIR(mode)) {
+ di->di_flags |= cpu_to_be32(dip->i_di.di_flags &
+ GFS2_DIF_INHERIT_DIRECTIO);
+ di->di_flags |= cpu_to_be32(dip->i_di.di_flags &
+ GFS2_DIF_INHERIT_JDATA);
+ }
+
+ di->__pad1 = 0;
+ di->di_payload_format = cpu_to_be32(0);
+ di->di_height = cpu_to_be32(0);
+ di->__pad2 = 0;
+ di->__pad3 = 0;
+ di->di_depth = cpu_to_be16(0);
+ di->di_entries = cpu_to_be32(0);
+ memset(&di->__pad4, 0, sizeof(di->__pad4));
+ di->di_eattr = cpu_to_be64(0);
+ memset(&di->di_reserved, 0, sizeof(di->di_reserved));
+
+ brelse(dibh);
+}
+
+static int make_dinode(struct gfs2_inode *dip, struct gfs2_glock *gl,
+ unsigned int mode, const struct gfs2_inum *inum,
+ const u64 *generation)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ unsigned int uid, gid;
+ int error;
+
+ munge_mode_uid_gid(dip, &mode, &uid, &gid);
+ gfs2_alloc_get(dip);
+
+ error = gfs2_quota_lock(dip, uid, gid);
+ if (error)
+ goto out;
+
+ error = gfs2_quota_check(dip, uid, gid);
+ if (error)
+ goto out_quota;
+
+ error = gfs2_trans_begin(sdp, RES_DINODE + RES_QUOTA, 0);
+ if (error)
+ goto out_quota;
+
+ init_dinode(dip, gl, inum, mode, uid, gid, generation);
+ gfs2_quota_change(dip, +1, uid, gid);
+ gfs2_trans_end(sdp);
+
+out_quota:
+ gfs2_quota_unlock(dip);
+out:
+ gfs2_alloc_put(dip);
+ return error;
+}
+
+static int link_dinode(struct gfs2_inode *dip, const struct qstr *name,
+ struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct gfs2_alloc *al;
+ int alloc_required;
+ struct buffer_head *dibh;
+ int error;
+
+ al = gfs2_alloc_get(dip);
+
+ error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto fail;
+
+ error = alloc_required = gfs2_diradd_alloc_required(&dip->i_inode, name);
+ if (alloc_required < 0)
+ goto fail;
+ if (alloc_required) {
+ error = gfs2_quota_check(dip, dip->i_di.di_uid,
+ dip->i_di.di_gid);
+ if (error)
+ goto fail_quota_locks;
+
+ al->al_requested = sdp->sd_max_dirres;
+
+ error = gfs2_inplace_reserve(dip);
+ if (error)
+ goto fail_quota_locks;
+
+ error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
+ al->al_rgd->rd_ri.ri_length +
+ 2 * RES_DINODE +
+ RES_STATFS + RES_QUOTA, 0);
+ if (error)
+ goto fail_ipreserv;
+ } else {
+ error = gfs2_trans_begin(sdp, RES_LEAF + 2 * RES_DINODE, 0);
+ if (error)
+ goto fail_quota_locks;
+ }
+
+ error = gfs2_dir_add(&dip->i_inode, name, &ip->i_num, IF2DT(ip->i_di.di_mode));
+ if (error)
+ goto fail_end_trans;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto fail_end_trans;
+ ip->i_di.di_nlink = 1;
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ return 0;
+
+fail_end_trans:
+ gfs2_trans_end(sdp);
+
+fail_ipreserv:
+ if (dip->i_alloc.al_rgd)
+ gfs2_inplace_release(dip);
+
+fail_quota_locks:
+ gfs2_quota_unlock(dip);
+
+fail:
+ gfs2_alloc_put(dip);
+ return error;
+}
+
+static int gfs2_security_init(struct gfs2_inode *dip, struct gfs2_inode *ip)
+{
+ int err;
+ size_t len;
+ void *value;
+ char *name;
+ struct gfs2_ea_request er;
+
+ err = security_inode_init_security(&ip->i_inode, &dip->i_inode,
+ &name, &value, &len);
+
+ if (err) {
+ if (err == -EOPNOTSUPP)
+ return 0;
+ return err;
+ }
+
+ memset(&er, 0, sizeof(struct gfs2_ea_request));
+
+ er.er_type = GFS2_EATYPE_SECURITY;
+ er.er_name = name;
+ er.er_data = value;
+ er.er_name_len = strlen(name);
+ er.er_data_len = len;
+
+ err = gfs2_ea_set_i(ip, &er);
+
+ kfree(value);
+ kfree(name);
+
+ return err;
+}
+
+/**
+ * gfs2_createi - Create a new inode
+ * @ghs: An array of two holders
+ * @name: The name of the new file
+ * @mode: the permissions on the new inode
+ *
+ * @ghs[0] is an initialized holder for the directory
+ * @ghs[1] is the holder for the inode lock
+ *
+ * If the return value is not NULL, the glocks on both the directory and the new
+ * file are held. A transaction has been started and an inplace reservation
+ * is held, as well.
+ *
+ * Returns: An inode
+ */
+
+struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
+ unsigned int mode)
+{
+ struct inode *inode;
+ struct gfs2_inode *dip = ghs->gh_gl->gl_object;
+ struct inode *dir = &dip->i_inode;
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct gfs2_inum inum;
+ int error;
+ u64 generation;
+
+ if (!name->len || name->len > GFS2_FNAMESIZE)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
+ error = gfs2_glock_nq(ghs);
+ if (error)
+ goto fail;
+
+ error = create_ok(dip, name, mode);
+ if (error)
+ goto fail_gunlock;
+
+ error = pick_formal_ino(sdp, &inum.no_formal_ino);
+ if (error)
+ goto fail_gunlock;
+
+ error = alloc_dinode(dip, &inum, &generation);
+ if (error)
+ goto fail_gunlock;
+
+ if (inum.no_addr < dip->i_num.no_addr) {
+ gfs2_glock_dq(ghs);
+
+ error = gfs2_glock_nq_num(sdp, inum.no_addr,
+ &gfs2_inode_glops, LM_ST_EXCLUSIVE,
+ GL_SKIP, ghs + 1);
+ if (error) {
+ return ERR_PTR(error);
+ }
+
+ gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, ghs);
+ error = gfs2_glock_nq(ghs);
+ if (error) {
+ gfs2_glock_dq_uninit(ghs + 1);
+ return ERR_PTR(error);
+ }
+
+ error = create_ok(dip, name, mode);
+ if (error)
+ goto fail_gunlock2;
+ } else {
+ error = gfs2_glock_nq_num(sdp, inum.no_addr,
+ &gfs2_inode_glops, LM_ST_EXCLUSIVE,
+ GL_SKIP, ghs + 1);
+ if (error)
+ goto fail_gunlock;
+ }
+
+ error = make_dinode(dip, ghs[1].gh_gl, mode, &inum, &generation);
+ if (error)
+ goto fail_gunlock2;
+
+ inode = gfs2_inode_lookup(dir->i_sb, &inum, IF2DT(mode));
+ if (IS_ERR(inode))
+ goto fail_gunlock2;
+
+ error = gfs2_inode_refresh(GFS2_I(inode));
+ if (error)
+ goto fail_iput;
+
+ error = gfs2_acl_create(dip, GFS2_I(inode));
+ if (error)
+ goto fail_iput;
+
+ error = gfs2_security_init(dip, GFS2_I(inode));
+ if (error)
+ goto fail_iput;
+
+ error = link_dinode(dip, name, GFS2_I(inode));
+ if (error)
+ goto fail_iput;
+
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ return inode;
+
+fail_iput:
+ iput(inode);
+fail_gunlock2:
+ gfs2_glock_dq_uninit(ghs + 1);
+fail_gunlock:
+ gfs2_glock_dq(ghs);
+fail:
+ return ERR_PTR(error);
+}
+
+/**
+ * gfs2_rmdiri - Remove a directory
+ * @dip: The parent directory of the directory to be removed
+ * @name: The name of the directory to be removed
+ * @ip: The GFS2 inode of the directory to be removed
+ *
+ * Assumes Glocks on dip and ip are held
+ *
+ * Returns: errno
+ */
+
+int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
+ struct gfs2_inode *ip)
+{
+ struct qstr dotname;
+ int error;
+
+ if (ip->i_di.di_entries != 2) {
+ if (gfs2_consist_inode(ip))
+ gfs2_dinode_print(&ip->i_di);
+ return -EIO;
+ }
+
+ error = gfs2_dir_del(dip, name);
+ if (error)
+ return error;
+
+ error = gfs2_change_nlink(dip, -1);
+ if (error)
+ return error;
+
+ gfs2_str2qstr(&dotname, ".");
+ error = gfs2_dir_del(ip, &dotname);
+ if (error)
+ return error;
+
+ gfs2_str2qstr(&dotname, "..");
+ error = gfs2_dir_del(ip, &dotname);
+ if (error)
+ return error;
+
+ error = gfs2_change_nlink(ip, -2);
+ if (error)
+ return error;
+
+ return error;
+}
+
+/*
+ * gfs2_unlink_ok - check to see that a inode is still in a directory
+ * @dip: the directory
+ * @name: the name of the file
+ * @ip: the inode
+ *
+ * Assumes that the lock on (at least) @dip is held.
+ *
+ * Returns: 0 if the parent/child relationship is correct, errno if it isn't
+ */
+
+int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
+ struct gfs2_inode *ip)
+{
+ struct gfs2_inum inum;
+ unsigned int type;
+ int error;
+
+ if (IS_IMMUTABLE(&ip->i_inode) || IS_APPEND(&ip->i_inode))
+ return -EPERM;
+
+ if ((dip->i_di.di_mode & S_ISVTX) &&
+ dip->i_di.di_uid != current->fsuid &&
+ ip->i_di.di_uid != current->fsuid && !capable(CAP_FOWNER))
+ return -EPERM;
+
+ if (IS_APPEND(&dip->i_inode))
+ return -EPERM;
+
+ error = permission(&dip->i_inode, MAY_WRITE | MAY_EXEC, NULL);
+ if (error)
+ return error;
+
+ error = gfs2_dir_search(&dip->i_inode, name, &inum, &type);
+ if (error)
+ return error;
+
+ if (!gfs2_inum_equal(&inum, &ip->i_num))
+ return -ENOENT;
+
+ if (IF2DT(ip->i_di.di_mode) != type) {
+ gfs2_consist_inode(dip);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/*
+ * gfs2_ok_to_move - check if it's ok to move a directory to another directory
+ * @this: move this
+ * @to: to here
+ *
+ * Follow @to back to the root and make sure we don't encounter @this
+ * Assumes we already hold the rename lock.
+ *
+ * Returns: errno
+ */
+
+int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to)
+{
+ struct inode *dir = &to->i_inode;
+ struct super_block *sb = dir->i_sb;
+ struct inode *tmp;
+ struct qstr dotdot;
+ int error = 0;
+
+ gfs2_str2qstr(&dotdot, "..");
+
+ igrab(dir);
+
+ for (;;) {
+ if (dir == &this->i_inode) {
+ error = -EINVAL;
+ break;
+ }
+ if (dir == sb->s_root->d_inode) {
+ error = 0;
+ break;
+ }
+
+ tmp = gfs2_lookupi(dir, &dotdot, 1, NULL);
+ if (IS_ERR(tmp)) {
+ error = PTR_ERR(tmp);
+ break;
+ }
+
+ iput(dir);
+ dir = tmp;
+ }
+
+ iput(dir);
+
+ return error;
+}
+
+/**
+ * gfs2_readlinki - return the contents of a symlink
+ * @ip: the symlink's inode
+ * @buf: a pointer to the buffer to be filled
+ * @len: a pointer to the length of @buf
+ *
+ * If @buf is too small, a piece of memory is kmalloc()ed and needs
+ * to be freed by the caller.
+ *
+ * Returns: errno
+ */
+
+int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
+{
+ struct gfs2_holder i_gh;
+ struct buffer_head *dibh;
+ unsigned int x;
+ int error;
+
+ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh);
+ error = gfs2_glock_nq_atime(&i_gh);
+ if (error) {
+ gfs2_holder_uninit(&i_gh);
+ return error;
+ }
+
+ if (!ip->i_di.di_size) {
+ gfs2_consist_inode(ip);
+ error = -EIO;
+ goto out;
+ }
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out;
+
+ x = ip->i_di.di_size + 1;
+ if (x > *len) {
+ *buf = kmalloc(x, GFP_KERNEL);
+ if (!*buf) {
+ error = -ENOMEM;
+ goto out_brelse;
+ }
+ }
+
+ memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
+ *len = x;
+
+out_brelse:
+ brelse(dibh);
+out:
+ gfs2_glock_dq_uninit(&i_gh);
+ return error;
+}
+
+/**
+ * gfs2_glock_nq_atime - Acquire a hold on an inode's glock, and
+ * conditionally update the inode's atime
+ * @gh: the holder to acquire
+ *
+ * Tests atime (access time) for gfs2_read, gfs2_readdir and gfs2_mmap
+ * Update if the difference between the current time and the inode's current
+ * atime is greater than an interval specified at mount.
+ *
+ * Returns: errno
+ */
+
+int gfs2_glock_nq_atime(struct gfs2_holder *gh)
+{
+ struct gfs2_glock *gl = gh->gh_gl;
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct gfs2_inode *ip = gl->gl_object;
+ s64 curtime, quantum = gfs2_tune_get(sdp, gt_atime_quantum);
+ unsigned int state;
+ int flags;
+ int error;
+
+ if (gfs2_assert_warn(sdp, gh->gh_flags & GL_ATIME) ||
+ gfs2_assert_warn(sdp, !(gh->gh_flags & GL_ASYNC)) ||
+ gfs2_assert_warn(sdp, gl->gl_ops == &gfs2_inode_glops))
+ return -EINVAL;
+
+ state = gh->gh_state;
+ flags = gh->gh_flags;
+
+ error = gfs2_glock_nq(gh);
+ if (error)
+ return error;
+
+ if (test_bit(SDF_NOATIME, &sdp->sd_flags) ||
+ (sdp->sd_vfs->s_flags & MS_RDONLY))
+ return 0;
+
+ curtime = get_seconds();
+ if (curtime - ip->i_di.di_atime >= quantum) {
+ gfs2_glock_dq(gh);
+ gfs2_holder_reinit(LM_ST_EXCLUSIVE, gh->gh_flags & ~LM_FLAG_ANY,
+ gh);
+ error = gfs2_glock_nq(gh);
+ if (error)
+ return error;
+
+ /* Verify that atime hasn't been updated while we were
+ trying to get exclusive lock. */
+
+ curtime = get_seconds();
+ if (curtime - ip->i_di.di_atime >= quantum) {
+ struct buffer_head *dibh;
+ struct gfs2_dinode *di;
+
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ if (error == -EROFS)
+ return 0;
+ if (error)
+ goto fail;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto fail_end_trans;
+
+ ip->i_di.di_atime = curtime;
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ di = (struct gfs2_dinode *)dibh->b_data;
+ di->di_atime = cpu_to_be64(ip->i_di.di_atime);
+ brelse(dibh);
+
+ gfs2_trans_end(sdp);
+ }
+
+ /* If someone else has asked for the glock,
+ unlock and let them have it. Then reacquire
+ in the original state. */
+ if (gfs2_glock_is_blocking(gl)) {
+ gfs2_glock_dq(gh);
+ gfs2_holder_reinit(state, flags, gh);
+ return gfs2_glock_nq(gh);
+ }
+ }
+
+ return 0;
+
+fail_end_trans:
+ gfs2_trans_end(sdp);
+fail:
+ gfs2_glock_dq(gh);
+ return error;
+}
+
+/**
+ * glock_compare_atime - Compare two struct gfs2_glock structures for sort
+ * @arg_a: the first structure
+ * @arg_b: the second structure
+ *
+ * Returns: 1 if A > B
+ * -1 if A < B
+ * 0 if A == B
+ */
+
+static int glock_compare_atime(const void *arg_a, const void *arg_b)
+{
+ const struct gfs2_holder *gh_a = *(const struct gfs2_holder **)arg_a;
+ const struct gfs2_holder *gh_b = *(const struct gfs2_holder **)arg_b;
+ const struct lm_lockname *a = &gh_a->gh_gl->gl_name;
+ const struct lm_lockname *b = &gh_b->gh_gl->gl_name;
+
+ if (a->ln_number > b->ln_number)
+ return 1;
+ if (a->ln_number < b->ln_number)
+ return -1;
+ if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
+ return 1;
+ if (gh_a->gh_state == LM_ST_SHARED && (gh_b->gh_flags & GL_ATIME))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * gfs2_glock_nq_m_atime - acquire multiple glocks where one may need an
+ * atime update
+ * @num_gh: the number of structures
+ * @ghs: an array of struct gfs2_holder structures
+ *
+ * Returns: 0 on success (all glocks acquired),
+ * errno on failure (no glocks acquired)
+ */
+
+int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs)
+{
+ struct gfs2_holder **p;
+ unsigned int x;
+ int error = 0;
+
+ if (!num_gh)
+ return 0;
+
+ if (num_gh == 1) {
+ ghs->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+ if (ghs->gh_flags & GL_ATIME)
+ error = gfs2_glock_nq_atime(ghs);
+ else
+ error = gfs2_glock_nq(ghs);
+ return error;
+ }
+
+ p = kcalloc(num_gh, sizeof(struct gfs2_holder *), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+
+ for (x = 0; x < num_gh; x++)
+ p[x] = &ghs[x];
+
+ sort(p, num_gh, sizeof(struct gfs2_holder *), glock_compare_atime,NULL);
+
+ for (x = 0; x < num_gh; x++) {
+ p[x]->gh_flags &= ~(LM_FLAG_TRY | GL_ASYNC);
+
+ if (p[x]->gh_flags & GL_ATIME)
+ error = gfs2_glock_nq_atime(p[x]);
+ else
+ error = gfs2_glock_nq(p[x]);
+
+ if (error) {
+ while (x--)
+ gfs2_glock_dq(p[x]);
+ break;
+ }
+ }
+
+ kfree(p);
+ return error;
+}
+
+
+static int
+__gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+{
+ struct buffer_head *dibh;
+ int error;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (!error) {
+ error = inode_setattr(&ip->i_inode, attr);
+ gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
+ gfs2_inode_attr_out(ip);
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+ return error;
+}
+
+/**
+ * gfs2_setattr_simple -
+ * @ip:
+ * @attr:
+ *
+ * Called with a reference on the vnode.
+ *
+ * Returns: errno
+ */
+
+int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr)
+{
+ int error;
+
+ if (current->journal_info)
+ return __gfs2_setattr_simple(ip, attr);
+
+ error = gfs2_trans_begin(GFS2_SB(&ip->i_inode), RES_DINODE, 0);
+ if (error)
+ return error;
+
+ error = __gfs2_setattr_simple(ip, attr);
+ gfs2_trans_end(GFS2_SB(&ip->i_inode));
+ return error;
+}
+
diff --git a/fs/gfs2/inode.h b/fs/gfs2/inode.h
new file mode 100644
index 000000000000..f5d861760579
--- /dev/null
+++ b/fs/gfs2/inode.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __INODE_DOT_H__
+#define __INODE_DOT_H__
+
+static inline int gfs2_is_stuffed(struct gfs2_inode *ip)
+{
+ return !ip->i_di.di_height;
+}
+
+static inline int gfs2_is_jdata(struct gfs2_inode *ip)
+{
+ return ip->i_di.di_flags & GFS2_DIF_JDATA;
+}
+
+static inline int gfs2_is_dir(struct gfs2_inode *ip)
+{
+ return S_ISDIR(ip->i_di.di_mode);
+}
+
+void gfs2_inode_attr_in(struct gfs2_inode *ip);
+void gfs2_inode_attr_out(struct gfs2_inode *ip);
+struct inode *gfs2_inode_lookup(struct super_block *sb, struct gfs2_inum *inum, unsigned type);
+struct inode *gfs2_ilookup(struct super_block *sb, struct gfs2_inum *inum);
+
+int gfs2_inode_refresh(struct gfs2_inode *ip);
+
+int gfs2_dinode_dealloc(struct gfs2_inode *inode);
+int gfs2_change_nlink(struct gfs2_inode *ip, int diff);
+struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
+ int is_root, struct nameidata *nd);
+struct inode *gfs2_createi(struct gfs2_holder *ghs, const struct qstr *name,
+ unsigned int mode);
+int gfs2_rmdiri(struct gfs2_inode *dip, const struct qstr *name,
+ struct gfs2_inode *ip);
+int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
+ struct gfs2_inode *ip);
+int gfs2_ok_to_move(struct gfs2_inode *this, struct gfs2_inode *to);
+int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len);
+
+int gfs2_glock_nq_atime(struct gfs2_holder *gh);
+int gfs2_glock_nq_m_atime(unsigned int num_gh, struct gfs2_holder *ghs);
+
+int gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr);
+
+struct inode *gfs2_lookup_simple(struct inode *dip, const char *name);
+
+#endif /* __INODE_DOT_H__ */
+
diff --git a/fs/gfs2/lm.c b/fs/gfs2/lm.c
new file mode 100644
index 000000000000..effe4a337c1d
--- /dev/null
+++ b/fs/gfs2/lm.c
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/delay.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "lm.h"
+#include "super.h"
+#include "util.h"
+
+/**
+ * gfs2_lm_mount - mount a locking protocol
+ * @sdp: the filesystem
+ * @args: mount arguements
+ * @silent: if 1, don't complain if the FS isn't a GFS2 fs
+ *
+ * Returns: errno
+ */
+
+int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent)
+{
+ char *proto = sdp->sd_proto_name;
+ char *table = sdp->sd_table_name;
+ int flags = 0;
+ int error;
+
+ if (sdp->sd_args.ar_spectator)
+ flags |= LM_MFLAG_SPECTATOR;
+
+ fs_info(sdp, "Trying to join cluster \"%s\", \"%s\"\n", proto, table);
+
+ error = gfs2_mount_lockproto(proto, table, sdp->sd_args.ar_hostdata,
+ gfs2_glock_cb, sdp,
+ GFS2_MIN_LVB_SIZE, flags,
+ &sdp->sd_lockstruct, &sdp->sd_kobj);
+ if (error) {
+ fs_info(sdp, "can't mount proto=%s, table=%s, hostdata=%s\n",
+ proto, table, sdp->sd_args.ar_hostdata);
+ goto out;
+ }
+
+ if (gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lockspace) ||
+ gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_ops) ||
+ gfs2_assert_warn(sdp, sdp->sd_lockstruct.ls_lvb_size >=
+ GFS2_MIN_LVB_SIZE)) {
+ gfs2_unmount_lockproto(&sdp->sd_lockstruct);
+ goto out;
+ }
+
+ if (sdp->sd_args.ar_spectator)
+ snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.s", table);
+ else
+ snprintf(sdp->sd_fsname, GFS2_FSNAME_LEN, "%s.%u", table,
+ sdp->sd_lockstruct.ls_jid);
+
+ fs_info(sdp, "Joined cluster. Now mounting FS...\n");
+
+ if ((sdp->sd_lockstruct.ls_flags & LM_LSFLAG_LOCAL) &&
+ !sdp->sd_args.ar_ignore_local_fs) {
+ sdp->sd_args.ar_localflocks = 1;
+ sdp->sd_args.ar_localcaching = 1;
+ }
+
+out:
+ return error;
+}
+
+void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp)
+{
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ sdp->sd_lockstruct.ls_ops->lm_others_may_mount(
+ sdp->sd_lockstruct.ls_lockspace);
+}
+
+void gfs2_lm_unmount(struct gfs2_sbd *sdp)
+{
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ gfs2_unmount_lockproto(&sdp->sd_lockstruct);
+}
+
+int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
+{
+ va_list args;
+
+ if (test_and_set_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+ return 0;
+
+ va_start(args, fmt);
+ vprintk(fmt, args);
+ va_end(args);
+
+ fs_err(sdp, "about to withdraw from the cluster\n");
+ BUG_ON(sdp->sd_args.ar_debug);
+
+
+ fs_err(sdp, "waiting for outstanding I/O\n");
+
+ /* FIXME: suspend dm device so oustanding bio's complete
+ and all further io requests fail */
+
+ fs_err(sdp, "telling LM to withdraw\n");
+ gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
+ fs_err(sdp, "withdrawn\n");
+ dump_stack();
+
+ return -1;
+}
+
+int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ void **lockp)
+{
+ int error = -EIO;
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ error = sdp->sd_lockstruct.ls_ops->lm_get_lock(
+ sdp->sd_lockstruct.ls_lockspace, name, lockp);
+ return error;
+}
+
+void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock)
+{
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ sdp->sd_lockstruct.ls_ops->lm_put_lock(lock);
+}
+
+unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
+ unsigned int cur_state, unsigned int req_state,
+ unsigned int flags)
+{
+ int ret = 0;
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ ret = sdp->sd_lockstruct.ls_ops->lm_lock(lock, cur_state,
+ req_state, flags);
+ return ret;
+}
+
+unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
+ unsigned int cur_state)
+{
+ int ret = 0;
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ ret = sdp->sd_lockstruct.ls_ops->lm_unlock(lock, cur_state);
+ return ret;
+}
+
+void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock)
+{
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ sdp->sd_lockstruct.ls_ops->lm_cancel(lock);
+}
+
+int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp)
+{
+ int error = -EIO;
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ error = sdp->sd_lockstruct.ls_ops->lm_hold_lvb(lock, lvbp);
+ return error;
+}
+
+void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb)
+{
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ sdp->sd_lockstruct.ls_ops->lm_unhold_lvb(lock, lvb);
+}
+
+int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl)
+{
+ int error = -EIO;
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ error = sdp->sd_lockstruct.ls_ops->lm_plock_get(
+ sdp->sd_lockstruct.ls_lockspace, name, file, fl);
+ return error;
+}
+
+int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ struct file *file, int cmd, struct file_lock *fl)
+{
+ int error = -EIO;
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ error = sdp->sd_lockstruct.ls_ops->lm_plock(
+ sdp->sd_lockstruct.ls_lockspace, name, file, cmd, fl);
+ return error;
+}
+
+int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl)
+{
+ int error = -EIO;
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ error = sdp->sd_lockstruct.ls_ops->lm_punlock(
+ sdp->sd_lockstruct.ls_lockspace, name, file, fl);
+ return error;
+}
+
+void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
+ unsigned int message)
+{
+ if (likely(!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ sdp->sd_lockstruct.ls_ops->lm_recovery_done(
+ sdp->sd_lockstruct.ls_lockspace, jid, message);
+}
+
diff --git a/fs/gfs2/lm.h b/fs/gfs2/lm.h
new file mode 100644
index 000000000000..21cdc30ee08c
--- /dev/null
+++ b/fs/gfs2/lm.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LM_DOT_H__
+#define __LM_DOT_H__
+
+struct gfs2_sbd;
+
+#define GFS2_MIN_LVB_SIZE 32
+
+int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent);
+void gfs2_lm_others_may_mount(struct gfs2_sbd *sdp);
+void gfs2_lm_unmount(struct gfs2_sbd *sdp);
+int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
+ __attribute__ ((format(printf, 2, 3)));
+int gfs2_lm_get_lock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ void **lockp);
+void gfs2_lm_put_lock(struct gfs2_sbd *sdp, void *lock);
+unsigned int gfs2_lm_lock(struct gfs2_sbd *sdp, void *lock,
+ unsigned int cur_state, unsigned int req_state,
+ unsigned int flags);
+unsigned int gfs2_lm_unlock(struct gfs2_sbd *sdp, void *lock,
+ unsigned int cur_state);
+void gfs2_lm_cancel(struct gfs2_sbd *sdp, void *lock);
+int gfs2_lm_hold_lvb(struct gfs2_sbd *sdp, void *lock, char **lvbp);
+void gfs2_lm_unhold_lvb(struct gfs2_sbd *sdp, void *lock, char *lvb);
+int gfs2_lm_plock_get(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl);
+int gfs2_lm_plock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ struct file *file, int cmd, struct file_lock *fl);
+int gfs2_lm_punlock(struct gfs2_sbd *sdp, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl);
+void gfs2_lm_recovery_done(struct gfs2_sbd *sdp, unsigned int jid,
+ unsigned int message);
+
+#endif /* __LM_DOT_H__ */
diff --git a/fs/gfs2/locking.c b/fs/gfs2/locking.c
new file mode 100644
index 000000000000..663fee728783
--- /dev/null
+++ b/fs/gfs2/locking.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/lm_interface.h>
+
+struct lmh_wrapper {
+ struct list_head lw_list;
+ const struct lm_lockops *lw_ops;
+};
+
+/* List of registered low-level locking protocols. A file system selects one
+ of them by name at mount time, e.g. lock_nolock, lock_dlm. */
+
+static LIST_HEAD(lmh_list);
+static DEFINE_MUTEX(lmh_lock);
+
+/**
+ * gfs2_register_lockproto - Register a low-level locking protocol
+ * @proto: the protocol definition
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+int gfs2_register_lockproto(const struct lm_lockops *proto)
+{
+ struct lmh_wrapper *lw;
+
+ mutex_lock(&lmh_lock);
+
+ list_for_each_entry(lw, &lmh_list, lw_list) {
+ if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
+ mutex_unlock(&lmh_lock);
+ printk(KERN_INFO "GFS2: protocol %s already exists\n",
+ proto->lm_proto_name);
+ return -EEXIST;
+ }
+ }
+
+ lw = kzalloc(sizeof(struct lmh_wrapper), GFP_KERNEL);
+ if (!lw) {
+ mutex_unlock(&lmh_lock);
+ return -ENOMEM;
+ }
+
+ lw->lw_ops = proto;
+ list_add(&lw->lw_list, &lmh_list);
+
+ mutex_unlock(&lmh_lock);
+
+ return 0;
+}
+
+/**
+ * gfs2_unregister_lockproto - Unregister a low-level locking protocol
+ * @proto: the protocol definition
+ *
+ */
+
+void gfs2_unregister_lockproto(const struct lm_lockops *proto)
+{
+ struct lmh_wrapper *lw;
+
+ mutex_lock(&lmh_lock);
+
+ list_for_each_entry(lw, &lmh_list, lw_list) {
+ if (!strcmp(lw->lw_ops->lm_proto_name, proto->lm_proto_name)) {
+ list_del(&lw->lw_list);
+ mutex_unlock(&lmh_lock);
+ kfree(lw);
+ return;
+ }
+ }
+
+ mutex_unlock(&lmh_lock);
+
+ printk(KERN_WARNING "GFS2: can't unregister lock protocol %s\n",
+ proto->lm_proto_name);
+}
+
+/**
+ * gfs2_mount_lockproto - Mount a lock protocol
+ * @proto_name - the name of the protocol
+ * @table_name - the name of the lock space
+ * @host_data - data specific to this host
+ * @cb - the callback to the code using the lock module
+ * @sdp - The GFS2 superblock
+ * @min_lvb_size - the mininum LVB size that the caller can deal with
+ * @flags - LM_MFLAG_*
+ * @lockstruct - a structure returned describing the mount
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
+ lm_callback_t cb, void *cb_data,
+ unsigned int min_lvb_size, int flags,
+ struct lm_lockstruct *lockstruct,
+ struct kobject *fskobj)
+{
+ struct lmh_wrapper *lw = NULL;
+ int try = 0;
+ int error, found;
+
+retry:
+ mutex_lock(&lmh_lock);
+
+ found = 0;
+ list_for_each_entry(lw, &lmh_list, lw_list) {
+ if (!strcmp(lw->lw_ops->lm_proto_name, proto_name)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ if (!try && capable(CAP_SYS_MODULE)) {
+ try = 1;
+ mutex_unlock(&lmh_lock);
+ request_module(proto_name);
+ goto retry;
+ }
+ printk(KERN_INFO "GFS2: can't find protocol %s\n", proto_name);
+ error = -ENOENT;
+ goto out;
+ }
+
+ if (!try_module_get(lw->lw_ops->lm_owner)) {
+ try = 0;
+ mutex_unlock(&lmh_lock);
+ msleep(1000);
+ goto retry;
+ }
+
+ error = lw->lw_ops->lm_mount(table_name, host_data, cb, cb_data,
+ min_lvb_size, flags, lockstruct, fskobj);
+ if (error)
+ module_put(lw->lw_ops->lm_owner);
+out:
+ mutex_unlock(&lmh_lock);
+ return error;
+}
+
+void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct)
+{
+ mutex_lock(&lmh_lock);
+ lockstruct->ls_ops->lm_unmount(lockstruct->ls_lockspace);
+ if (lockstruct->ls_ops->lm_owner)
+ module_put(lockstruct->ls_ops->lm_owner);
+ mutex_unlock(&lmh_lock);
+}
+
+/**
+ * gfs2_withdraw_lockproto - abnormally unmount a lock module
+ * @lockstruct: the lockstruct passed into mount
+ *
+ */
+
+void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct)
+{
+ mutex_lock(&lmh_lock);
+ lockstruct->ls_ops->lm_withdraw(lockstruct->ls_lockspace);
+ if (lockstruct->ls_ops->lm_owner)
+ module_put(lockstruct->ls_ops->lm_owner);
+ mutex_unlock(&lmh_lock);
+}
+
+EXPORT_SYMBOL_GPL(gfs2_register_lockproto);
+EXPORT_SYMBOL_GPL(gfs2_unregister_lockproto);
+
diff --git a/fs/gfs2/locking/dlm/Makefile b/fs/gfs2/locking/dlm/Makefile
new file mode 100644
index 000000000000..89b93b6b45cf
--- /dev/null
+++ b/fs/gfs2/locking/dlm/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_GFS2_FS_LOCKING_DLM) += lock_dlm.o
+lock_dlm-y := lock.o main.o mount.o sysfs.o thread.o plock.o
+
diff --git a/fs/gfs2/locking/dlm/lock.c b/fs/gfs2/locking/dlm/lock.c
new file mode 100644
index 000000000000..b167addf9fd1
--- /dev/null
+++ b/fs/gfs2/locking/dlm/lock.c
@@ -0,0 +1,524 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include "lock_dlm.h"
+
+static char junk_lvb[GDLM_LVB_SIZE];
+
+static void queue_complete(struct gdlm_lock *lp)
+{
+ struct gdlm_ls *ls = lp->ls;
+
+ clear_bit(LFL_ACTIVE, &lp->flags);
+
+ spin_lock(&ls->async_lock);
+ list_add_tail(&lp->clist, &ls->complete);
+ spin_unlock(&ls->async_lock);
+ wake_up(&ls->thread_wait);
+}
+
+static inline void gdlm_ast(void *astarg)
+{
+ queue_complete(astarg);
+}
+
+static inline void gdlm_bast(void *astarg, int mode)
+{
+ struct gdlm_lock *lp = astarg;
+ struct gdlm_ls *ls = lp->ls;
+
+ if (!mode) {
+ printk(KERN_INFO "lock_dlm: bast mode zero %x,%llx\n",
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number);
+ return;
+ }
+
+ spin_lock(&ls->async_lock);
+ if (!lp->bast_mode) {
+ list_add_tail(&lp->blist, &ls->blocking);
+ lp->bast_mode = mode;
+ } else if (lp->bast_mode < mode)
+ lp->bast_mode = mode;
+ spin_unlock(&ls->async_lock);
+ wake_up(&ls->thread_wait);
+}
+
+void gdlm_queue_delayed(struct gdlm_lock *lp)
+{
+ struct gdlm_ls *ls = lp->ls;
+
+ spin_lock(&ls->async_lock);
+ list_add_tail(&lp->delay_list, &ls->delayed);
+ spin_unlock(&ls->async_lock);
+}
+
+/* convert gfs lock-state to dlm lock-mode */
+
+static s16 make_mode(s16 lmstate)
+{
+ switch (lmstate) {
+ case LM_ST_UNLOCKED:
+ return DLM_LOCK_NL;
+ case LM_ST_EXCLUSIVE:
+ return DLM_LOCK_EX;
+ case LM_ST_DEFERRED:
+ return DLM_LOCK_CW;
+ case LM_ST_SHARED:
+ return DLM_LOCK_PR;
+ }
+ gdlm_assert(0, "unknown LM state %d", lmstate);
+ return -1;
+}
+
+/* convert dlm lock-mode to gfs lock-state */
+
+s16 gdlm_make_lmstate(s16 dlmmode)
+{
+ switch (dlmmode) {
+ case DLM_LOCK_IV:
+ case DLM_LOCK_NL:
+ return LM_ST_UNLOCKED;
+ case DLM_LOCK_EX:
+ return LM_ST_EXCLUSIVE;
+ case DLM_LOCK_CW:
+ return LM_ST_DEFERRED;
+ case DLM_LOCK_PR:
+ return LM_ST_SHARED;
+ }
+ gdlm_assert(0, "unknown DLM mode %d", dlmmode);
+ return -1;
+}
+
+/* verify agreement with GFS on the current lock state, NB: DLM_LOCK_NL and
+ DLM_LOCK_IV are both considered LM_ST_UNLOCKED by GFS. */
+
+static void check_cur_state(struct gdlm_lock *lp, unsigned int cur_state)
+{
+ s16 cur = make_mode(cur_state);
+ if (lp->cur != DLM_LOCK_IV)
+ gdlm_assert(lp->cur == cur, "%d, %d", lp->cur, cur);
+}
+
+static inline unsigned int make_flags(struct gdlm_lock *lp,
+ unsigned int gfs_flags,
+ s16 cur, s16 req)
+{
+ unsigned int lkf = 0;
+
+ if (gfs_flags & LM_FLAG_TRY)
+ lkf |= DLM_LKF_NOQUEUE;
+
+ if (gfs_flags & LM_FLAG_TRY_1CB) {
+ lkf |= DLM_LKF_NOQUEUE;
+ lkf |= DLM_LKF_NOQUEUEBAST;
+ }
+
+ if (gfs_flags & LM_FLAG_PRIORITY) {
+ lkf |= DLM_LKF_NOORDER;
+ lkf |= DLM_LKF_HEADQUE;
+ }
+
+ if (gfs_flags & LM_FLAG_ANY) {
+ if (req == DLM_LOCK_PR)
+ lkf |= DLM_LKF_ALTCW;
+ else if (req == DLM_LOCK_CW)
+ lkf |= DLM_LKF_ALTPR;
+ }
+
+ if (lp->lksb.sb_lkid != 0) {
+ lkf |= DLM_LKF_CONVERT;
+
+ /* Conversion deadlock avoidance by DLM */
+
+ if (!test_bit(LFL_FORCE_PROMOTE, &lp->flags) &&
+ !(lkf & DLM_LKF_NOQUEUE) &&
+ cur > DLM_LOCK_NL && req > DLM_LOCK_NL && cur != req)
+ lkf |= DLM_LKF_CONVDEADLK;
+ }
+
+ if (lp->lvb)
+ lkf |= DLM_LKF_VALBLK;
+
+ return lkf;
+}
+
+/* make_strname - convert GFS lock numbers to a string */
+
+static inline void make_strname(struct lm_lockname *lockname,
+ struct gdlm_strname *str)
+{
+ sprintf(str->name, "%8x%16llx", lockname->ln_type,
+ (unsigned long long)lockname->ln_number);
+ str->namelen = GDLM_STRNAME_BYTES;
+}
+
+static int gdlm_create_lp(struct gdlm_ls *ls, struct lm_lockname *name,
+ struct gdlm_lock **lpp)
+{
+ struct gdlm_lock *lp;
+
+ lp = kzalloc(sizeof(struct gdlm_lock), GFP_KERNEL);
+ if (!lp)
+ return -ENOMEM;
+
+ lp->lockname = *name;
+ lp->ls = ls;
+ lp->cur = DLM_LOCK_IV;
+ lp->lvb = NULL;
+ lp->hold_null = NULL;
+ init_completion(&lp->ast_wait);
+ INIT_LIST_HEAD(&lp->clist);
+ INIT_LIST_HEAD(&lp->blist);
+ INIT_LIST_HEAD(&lp->delay_list);
+
+ spin_lock(&ls->async_lock);
+ list_add(&lp->all_list, &ls->all_locks);
+ ls->all_locks_count++;
+ spin_unlock(&ls->async_lock);
+
+ *lpp = lp;
+ return 0;
+}
+
+void gdlm_delete_lp(struct gdlm_lock *lp)
+{
+ struct gdlm_ls *ls = lp->ls;
+
+ spin_lock(&ls->async_lock);
+ if (!list_empty(&lp->clist))
+ list_del_init(&lp->clist);
+ if (!list_empty(&lp->blist))
+ list_del_init(&lp->blist);
+ if (!list_empty(&lp->delay_list))
+ list_del_init(&lp->delay_list);
+ gdlm_assert(!list_empty(&lp->all_list), "%x,%llx", lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number);
+ list_del_init(&lp->all_list);
+ ls->all_locks_count--;
+ spin_unlock(&ls->async_lock);
+
+ kfree(lp);
+}
+
+int gdlm_get_lock(void *lockspace, struct lm_lockname *name,
+ void **lockp)
+{
+ struct gdlm_lock *lp;
+ int error;
+
+ error = gdlm_create_lp(lockspace, name, &lp);
+
+ *lockp = lp;
+ return error;
+}
+
+void gdlm_put_lock(void *lock)
+{
+ gdlm_delete_lp(lock);
+}
+
+unsigned int gdlm_do_lock(struct gdlm_lock *lp)
+{
+ struct gdlm_ls *ls = lp->ls;
+ struct gdlm_strname str;
+ int error, bast = 1;
+
+ /*
+ * When recovery is in progress, delay lock requests for submission
+ * once recovery is done. Requests for recovery (NOEXP) and unlocks
+ * can pass.
+ */
+
+ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
+ !test_bit(LFL_NOBLOCK, &lp->flags) && lp->req != DLM_LOCK_NL) {
+ gdlm_queue_delayed(lp);
+ return LM_OUT_ASYNC;
+ }
+
+ /*
+ * Submit the actual lock request.
+ */
+
+ if (test_bit(LFL_NOBAST, &lp->flags))
+ bast = 0;
+
+ make_strname(&lp->lockname, &str);
+
+ set_bit(LFL_ACTIVE, &lp->flags);
+
+ log_debug("lk %x,%llx id %x %d,%d %x", lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number, lp->lksb.sb_lkid,
+ lp->cur, lp->req, lp->lkf);
+
+ error = dlm_lock(ls->dlm_lockspace, lp->req, &lp->lksb, lp->lkf,
+ str.name, str.namelen, 0, gdlm_ast, lp,
+ bast ? gdlm_bast : NULL);
+
+ if ((error == -EAGAIN) && (lp->lkf & DLM_LKF_NOQUEUE)) {
+ lp->lksb.sb_status = -EAGAIN;
+ queue_complete(lp);
+ error = 0;
+ }
+
+ if (error) {
+ log_debug("%s: gdlm_lock %x,%llx err=%d cur=%d req=%d lkf=%x "
+ "flags=%lx", ls->fsname, lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number, error,
+ lp->cur, lp->req, lp->lkf, lp->flags);
+ return LM_OUT_ERROR;
+ }
+ return LM_OUT_ASYNC;
+}
+
+static unsigned int gdlm_do_unlock(struct gdlm_lock *lp)
+{
+ struct gdlm_ls *ls = lp->ls;
+ unsigned int lkf = 0;
+ int error;
+
+ set_bit(LFL_DLM_UNLOCK, &lp->flags);
+ set_bit(LFL_ACTIVE, &lp->flags);
+
+ if (lp->lvb)
+ lkf = DLM_LKF_VALBLK;
+
+ log_debug("un %x,%llx %x %d %x", lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number,
+ lp->lksb.sb_lkid, lp->cur, lkf);
+
+ error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, lkf, NULL, lp);
+
+ if (error) {
+ log_debug("%s: gdlm_unlock %x,%llx err=%d cur=%d req=%d lkf=%x "
+ "flags=%lx", ls->fsname, lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number, error,
+ lp->cur, lp->req, lp->lkf, lp->flags);
+ return LM_OUT_ERROR;
+ }
+ return LM_OUT_ASYNC;
+}
+
+unsigned int gdlm_lock(void *lock, unsigned int cur_state,
+ unsigned int req_state, unsigned int flags)
+{
+ struct gdlm_lock *lp = lock;
+
+ clear_bit(LFL_DLM_CANCEL, &lp->flags);
+ if (flags & LM_FLAG_NOEXP)
+ set_bit(LFL_NOBLOCK, &lp->flags);
+
+ check_cur_state(lp, cur_state);
+ lp->req = make_mode(req_state);
+ lp->lkf = make_flags(lp, flags, lp->cur, lp->req);
+
+ return gdlm_do_lock(lp);
+}
+
+unsigned int gdlm_unlock(void *lock, unsigned int cur_state)
+{
+ struct gdlm_lock *lp = lock;
+
+ clear_bit(LFL_DLM_CANCEL, &lp->flags);
+ if (lp->cur == DLM_LOCK_IV)
+ return 0;
+ return gdlm_do_unlock(lp);
+}
+
+void gdlm_cancel(void *lock)
+{
+ struct gdlm_lock *lp = lock;
+ struct gdlm_ls *ls = lp->ls;
+ int error, delay_list = 0;
+
+ if (test_bit(LFL_DLM_CANCEL, &lp->flags))
+ return;
+
+ log_info("gdlm_cancel %x,%llx flags %lx", lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number, lp->flags);
+
+ spin_lock(&ls->async_lock);
+ if (!list_empty(&lp->delay_list)) {
+ list_del_init(&lp->delay_list);
+ delay_list = 1;
+ }
+ spin_unlock(&ls->async_lock);
+
+ if (delay_list) {
+ set_bit(LFL_CANCEL, &lp->flags);
+ set_bit(LFL_ACTIVE, &lp->flags);
+ queue_complete(lp);
+ return;
+ }
+
+ if (!test_bit(LFL_ACTIVE, &lp->flags) ||
+ test_bit(LFL_DLM_UNLOCK, &lp->flags)) {
+ log_info("gdlm_cancel skip %x,%llx flags %lx",
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number, lp->flags);
+ return;
+ }
+
+ /* the lock is blocked in the dlm */
+
+ set_bit(LFL_DLM_CANCEL, &lp->flags);
+ set_bit(LFL_ACTIVE, &lp->flags);
+
+ error = dlm_unlock(ls->dlm_lockspace, lp->lksb.sb_lkid, DLM_LKF_CANCEL,
+ NULL, lp);
+
+ log_info("gdlm_cancel rv %d %x,%llx flags %lx", error,
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number, lp->flags);
+
+ if (error == -EBUSY)
+ clear_bit(LFL_DLM_CANCEL, &lp->flags);
+}
+
+static int gdlm_add_lvb(struct gdlm_lock *lp)
+{
+ char *lvb;
+
+ lvb = kzalloc(GDLM_LVB_SIZE, GFP_KERNEL);
+ if (!lvb)
+ return -ENOMEM;
+
+ lp->lksb.sb_lvbptr = lvb;
+ lp->lvb = lvb;
+ return 0;
+}
+
+static void gdlm_del_lvb(struct gdlm_lock *lp)
+{
+ kfree(lp->lvb);
+ lp->lvb = NULL;
+ lp->lksb.sb_lvbptr = NULL;
+}
+
+/* This can do a synchronous dlm request (requiring a lock_dlm thread to get
+ the completion) because gfs won't call hold_lvb() during a callback (from
+ the context of a lock_dlm thread). */
+
+static int hold_null_lock(struct gdlm_lock *lp)
+{
+ struct gdlm_lock *lpn = NULL;
+ int error;
+
+ if (lp->hold_null) {
+ printk(KERN_INFO "lock_dlm: lvb already held\n");
+ return 0;
+ }
+
+ error = gdlm_create_lp(lp->ls, &lp->lockname, &lpn);
+ if (error)
+ goto out;
+
+ lpn->lksb.sb_lvbptr = junk_lvb;
+ lpn->lvb = junk_lvb;
+
+ lpn->req = DLM_LOCK_NL;
+ lpn->lkf = DLM_LKF_VALBLK | DLM_LKF_EXPEDITE;
+ set_bit(LFL_NOBAST, &lpn->flags);
+ set_bit(LFL_INLOCK, &lpn->flags);
+
+ init_completion(&lpn->ast_wait);
+ gdlm_do_lock(lpn);
+ wait_for_completion(&lpn->ast_wait);
+ error = lpn->lksb.sb_status;
+ if (error) {
+ printk(KERN_INFO "lock_dlm: hold_null_lock dlm error %d\n",
+ error);
+ gdlm_delete_lp(lpn);
+ lpn = NULL;
+ }
+out:
+ lp->hold_null = lpn;
+ return error;
+}
+
+/* This cannot do a synchronous dlm request (requiring a lock_dlm thread to get
+ the completion) because gfs may call unhold_lvb() during a callback (from
+ the context of a lock_dlm thread) which could cause a deadlock since the
+ other lock_dlm thread could be engaged in recovery. */
+
+static void unhold_null_lock(struct gdlm_lock *lp)
+{
+ struct gdlm_lock *lpn = lp->hold_null;
+
+ gdlm_assert(lpn, "%x,%llx", lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number);
+ lpn->lksb.sb_lvbptr = NULL;
+ lpn->lvb = NULL;
+ set_bit(LFL_UNLOCK_DELETE, &lpn->flags);
+ gdlm_do_unlock(lpn);
+ lp->hold_null = NULL;
+}
+
+/* Acquire a NL lock because gfs requires the value block to remain
+ intact on the resource while the lvb is "held" even if it's holding no locks
+ on the resource. */
+
+int gdlm_hold_lvb(void *lock, char **lvbp)
+{
+ struct gdlm_lock *lp = lock;
+ int error;
+
+ error = gdlm_add_lvb(lp);
+ if (error)
+ return error;
+
+ *lvbp = lp->lvb;
+
+ error = hold_null_lock(lp);
+ if (error)
+ gdlm_del_lvb(lp);
+
+ return error;
+}
+
+void gdlm_unhold_lvb(void *lock, char *lvb)
+{
+ struct gdlm_lock *lp = lock;
+
+ unhold_null_lock(lp);
+ gdlm_del_lvb(lp);
+}
+
+void gdlm_submit_delayed(struct gdlm_ls *ls)
+{
+ struct gdlm_lock *lp, *safe;
+
+ spin_lock(&ls->async_lock);
+ list_for_each_entry_safe(lp, safe, &ls->delayed, delay_list) {
+ list_del_init(&lp->delay_list);
+ list_add_tail(&lp->delay_list, &ls->submit);
+ }
+ spin_unlock(&ls->async_lock);
+ wake_up(&ls->thread_wait);
+}
+
+int gdlm_release_all_locks(struct gdlm_ls *ls)
+{
+ struct gdlm_lock *lp, *safe;
+ int count = 0;
+
+ spin_lock(&ls->async_lock);
+ list_for_each_entry_safe(lp, safe, &ls->all_locks, all_list) {
+ list_del_init(&lp->all_list);
+
+ if (lp->lvb && lp->lvb != junk_lvb)
+ kfree(lp->lvb);
+ kfree(lp);
+ count++;
+ }
+ spin_unlock(&ls->async_lock);
+
+ return count;
+}
+
diff --git a/fs/gfs2/locking/dlm/lock_dlm.h b/fs/gfs2/locking/dlm/lock_dlm.h
new file mode 100644
index 000000000000..33af707a4d3f
--- /dev/null
+++ b/fs/gfs2/locking/dlm/lock_dlm.h
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef LOCK_DLM_DOT_H
+#define LOCK_DLM_DOT_H
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/socket.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/kobject.h>
+#include <linux/fcntl.h>
+#include <linux/wait.h>
+#include <net/sock.h>
+
+#include <linux/dlm.h>
+#include <linux/lm_interface.h>
+
+/*
+ * Internally, we prefix things with gdlm_ and GDLM_ (for gfs-dlm) since a
+ * prefix of lock_dlm_ gets awkward. Externally, GFS refers to this module
+ * as "lock_dlm".
+ */
+
+#define GDLM_STRNAME_BYTES 24
+#define GDLM_LVB_SIZE 32
+#define GDLM_DROP_COUNT 50000
+#define GDLM_DROP_PERIOD 60
+#define GDLM_NAME_LEN 128
+
+/* GFS uses 12 bytes to identify a resource (32 bit type + 64 bit number).
+ We sprintf these numbers into a 24 byte string of hex values to make them
+ human-readable (to make debugging simpler.) */
+
+struct gdlm_strname {
+ unsigned char name[GDLM_STRNAME_BYTES];
+ unsigned short namelen;
+};
+
+enum {
+ DFL_BLOCK_LOCKS = 0,
+ DFL_SPECTATOR = 1,
+ DFL_WITHDRAW = 2,
+};
+
+struct gdlm_ls {
+ u32 id;
+ int jid;
+ int first;
+ int first_done;
+ unsigned long flags;
+ struct kobject kobj;
+ char clustername[GDLM_NAME_LEN];
+ char fsname[GDLM_NAME_LEN];
+ int fsflags;
+ dlm_lockspace_t *dlm_lockspace;
+ lm_callback_t fscb;
+ struct gfs2_sbd *sdp;
+ int recover_jid;
+ int recover_jid_done;
+ int recover_jid_status;
+ spinlock_t async_lock;
+ struct list_head complete;
+ struct list_head blocking;
+ struct list_head delayed;
+ struct list_head submit;
+ struct list_head all_locks;
+ u32 all_locks_count;
+ wait_queue_head_t wait_control;
+ struct task_struct *thread1;
+ struct task_struct *thread2;
+ wait_queue_head_t thread_wait;
+ unsigned long drop_time;
+ int drop_locks_count;
+ int drop_locks_period;
+};
+
+enum {
+ LFL_NOBLOCK = 0,
+ LFL_NOCACHE = 1,
+ LFL_DLM_UNLOCK = 2,
+ LFL_DLM_CANCEL = 3,
+ LFL_SYNC_LVB = 4,
+ LFL_FORCE_PROMOTE = 5,
+ LFL_REREQUEST = 6,
+ LFL_ACTIVE = 7,
+ LFL_INLOCK = 8,
+ LFL_CANCEL = 9,
+ LFL_NOBAST = 10,
+ LFL_HEADQUE = 11,
+ LFL_UNLOCK_DELETE = 12,
+};
+
+struct gdlm_lock {
+ struct gdlm_ls *ls;
+ struct lm_lockname lockname;
+ char *lvb;
+ struct dlm_lksb lksb;
+
+ s16 cur;
+ s16 req;
+ s16 prev_req;
+ u32 lkf; /* dlm flags DLM_LKF_ */
+ unsigned long flags; /* lock_dlm flags LFL_ */
+
+ int bast_mode; /* protected by async_lock */
+ struct completion ast_wait;
+
+ struct list_head clist; /* complete */
+ struct list_head blist; /* blocking */
+ struct list_head delay_list; /* delayed */
+ struct list_head all_list; /* all locks for the fs */
+ struct gdlm_lock *hold_null; /* NL lock for hold_lvb */
+};
+
+#define gdlm_assert(assertion, fmt, args...) \
+do { \
+ if (unlikely(!(assertion))) { \
+ printk(KERN_EMERG "lock_dlm: fatal assertion failed \"%s\"\n" \
+ "lock_dlm: " fmt "\n", \
+ #assertion, ##args); \
+ BUG(); \
+ } \
+} while (0)
+
+#define log_print(lev, fmt, arg...) printk(lev "lock_dlm: " fmt "\n" , ## arg)
+#define log_info(fmt, arg...) log_print(KERN_INFO , fmt , ## arg)
+#define log_error(fmt, arg...) log_print(KERN_ERR , fmt , ## arg)
+#ifdef LOCK_DLM_LOG_DEBUG
+#define log_debug(fmt, arg...) log_print(KERN_DEBUG , fmt , ## arg)
+#else
+#define log_debug(fmt, arg...)
+#endif
+
+/* sysfs.c */
+
+int gdlm_sysfs_init(void);
+void gdlm_sysfs_exit(void);
+int gdlm_kobject_setup(struct gdlm_ls *, struct kobject *);
+void gdlm_kobject_release(struct gdlm_ls *);
+
+/* thread.c */
+
+int gdlm_init_threads(struct gdlm_ls *);
+void gdlm_release_threads(struct gdlm_ls *);
+
+/* lock.c */
+
+s16 gdlm_make_lmstate(s16);
+void gdlm_queue_delayed(struct gdlm_lock *);
+void gdlm_submit_delayed(struct gdlm_ls *);
+int gdlm_release_all_locks(struct gdlm_ls *);
+void gdlm_delete_lp(struct gdlm_lock *);
+unsigned int gdlm_do_lock(struct gdlm_lock *);
+
+int gdlm_get_lock(void *, struct lm_lockname *, void **);
+void gdlm_put_lock(void *);
+unsigned int gdlm_lock(void *, unsigned int, unsigned int, unsigned int);
+unsigned int gdlm_unlock(void *, unsigned int);
+void gdlm_cancel(void *);
+int gdlm_hold_lvb(void *, char **);
+void gdlm_unhold_lvb(void *, char *);
+
+/* plock.c */
+
+int gdlm_plock_init(void);
+void gdlm_plock_exit(void);
+int gdlm_plock(void *, struct lm_lockname *, struct file *, int,
+ struct file_lock *);
+int gdlm_plock_get(void *, struct lm_lockname *, struct file *,
+ struct file_lock *);
+int gdlm_punlock(void *, struct lm_lockname *, struct file *,
+ struct file_lock *);
+#endif
+
diff --git a/fs/gfs2/locking/dlm/main.c b/fs/gfs2/locking/dlm/main.c
new file mode 100644
index 000000000000..2194b1d5b5ec
--- /dev/null
+++ b/fs/gfs2/locking/dlm/main.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/init.h>
+
+#include "lock_dlm.h"
+
+extern int gdlm_drop_count;
+extern int gdlm_drop_period;
+
+extern struct lm_lockops gdlm_ops;
+
+static int __init init_lock_dlm(void)
+{
+ int error;
+
+ error = gfs2_register_lockproto(&gdlm_ops);
+ if (error) {
+ printk(KERN_WARNING "lock_dlm: can't register protocol: %d\n",
+ error);
+ return error;
+ }
+
+ error = gdlm_sysfs_init();
+ if (error) {
+ gfs2_unregister_lockproto(&gdlm_ops);
+ return error;
+ }
+
+ error = gdlm_plock_init();
+ if (error) {
+ gdlm_sysfs_exit();
+ gfs2_unregister_lockproto(&gdlm_ops);
+ return error;
+ }
+
+ gdlm_drop_count = GDLM_DROP_COUNT;
+ gdlm_drop_period = GDLM_DROP_PERIOD;
+
+ printk(KERN_INFO
+ "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__);
+ return 0;
+}
+
+static void __exit exit_lock_dlm(void)
+{
+ gdlm_plock_exit();
+ gdlm_sysfs_exit();
+ gfs2_unregister_lockproto(&gdlm_ops);
+}
+
+module_init(init_lock_dlm);
+module_exit(exit_lock_dlm);
+
+MODULE_DESCRIPTION("GFS DLM Locking Module");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/fs/gfs2/locking/dlm/mount.c b/fs/gfs2/locking/dlm/mount.c
new file mode 100644
index 000000000000..cdd1694e889b
--- /dev/null
+++ b/fs/gfs2/locking/dlm/mount.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include "lock_dlm.h"
+
+int gdlm_drop_count;
+int gdlm_drop_period;
+const struct lm_lockops gdlm_ops;
+
+
+static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
+ int flags, char *table_name)
+{
+ struct gdlm_ls *ls;
+ char buf[256], *p;
+
+ ls = kzalloc(sizeof(struct gdlm_ls), GFP_KERNEL);
+ if (!ls)
+ return NULL;
+
+ ls->drop_locks_count = gdlm_drop_count;
+ ls->drop_locks_period = gdlm_drop_period;
+ ls->fscb = cb;
+ ls->sdp = sdp;
+ ls->fsflags = flags;
+ spin_lock_init(&ls->async_lock);
+ INIT_LIST_HEAD(&ls->complete);
+ INIT_LIST_HEAD(&ls->blocking);
+ INIT_LIST_HEAD(&ls->delayed);
+ INIT_LIST_HEAD(&ls->submit);
+ INIT_LIST_HEAD(&ls->all_locks);
+ init_waitqueue_head(&ls->thread_wait);
+ init_waitqueue_head(&ls->wait_control);
+ ls->thread1 = NULL;
+ ls->thread2 = NULL;
+ ls->drop_time = jiffies;
+ ls->jid = -1;
+
+ strncpy(buf, table_name, 256);
+ buf[255] = '\0';
+
+ p = strchr(buf, ':');
+ if (!p) {
+ log_info("invalid table_name \"%s\"", table_name);
+ kfree(ls);
+ return NULL;
+ }
+ *p = '\0';
+ p++;
+
+ strncpy(ls->clustername, buf, GDLM_NAME_LEN);
+ strncpy(ls->fsname, p, GDLM_NAME_LEN);
+
+ return ls;
+}
+
+static int make_args(struct gdlm_ls *ls, char *data_arg, int *nodir)
+{
+ char data[256];
+ char *options, *x, *y;
+ int error = 0;
+
+ memset(data, 0, 256);
+ strncpy(data, data_arg, 255);
+
+ for (options = data; (x = strsep(&options, ":")); ) {
+ if (!*x)
+ continue;
+
+ y = strchr(x, '=');
+ if (y)
+ *y++ = 0;
+
+ if (!strcmp(x, "jid")) {
+ if (!y) {
+ log_error("need argument to jid");
+ error = -EINVAL;
+ break;
+ }
+ sscanf(y, "%u", &ls->jid);
+
+ } else if (!strcmp(x, "first")) {
+ if (!y) {
+ log_error("need argument to first");
+ error = -EINVAL;
+ break;
+ }
+ sscanf(y, "%u", &ls->first);
+
+ } else if (!strcmp(x, "id")) {
+ if (!y) {
+ log_error("need argument to id");
+ error = -EINVAL;
+ break;
+ }
+ sscanf(y, "%u", &ls->id);
+
+ } else if (!strcmp(x, "nodir")) {
+ if (!y) {
+ log_error("need argument to nodir");
+ error = -EINVAL;
+ break;
+ }
+ sscanf(y, "%u", nodir);
+
+ } else {
+ log_error("unkonwn option: %s", x);
+ error = -EINVAL;
+ break;
+ }
+ }
+
+ return error;
+}
+
+static int gdlm_mount(char *table_name, char *host_data,
+ lm_callback_t cb, void *cb_data,
+ unsigned int min_lvb_size, int flags,
+ struct lm_lockstruct *lockstruct,
+ struct kobject *fskobj)
+{
+ struct gdlm_ls *ls;
+ int error = -ENOMEM, nodir = 0;
+
+ if (min_lvb_size > GDLM_LVB_SIZE)
+ goto out;
+
+ ls = init_gdlm(cb, cb_data, flags, table_name);
+ if (!ls)
+ goto out;
+
+ error = make_args(ls, host_data, &nodir);
+ if (error)
+ goto out;
+
+ error = gdlm_init_threads(ls);
+ if (error)
+ goto out_free;
+
+ error = gdlm_kobject_setup(ls, fskobj);
+ if (error)
+ goto out_thread;
+
+ error = dlm_new_lockspace(ls->fsname, strlen(ls->fsname),
+ &ls->dlm_lockspace,
+ nodir ? DLM_LSFL_NODIR : 0,
+ GDLM_LVB_SIZE);
+ if (error) {
+ log_error("dlm_new_lockspace error %d", error);
+ goto out_kobj;
+ }
+
+ lockstruct->ls_jid = ls->jid;
+ lockstruct->ls_first = ls->first;
+ lockstruct->ls_lockspace = ls;
+ lockstruct->ls_ops = &gdlm_ops;
+ lockstruct->ls_flags = 0;
+ lockstruct->ls_lvb_size = GDLM_LVB_SIZE;
+ return 0;
+
+out_kobj:
+ gdlm_kobject_release(ls);
+out_thread:
+ gdlm_release_threads(ls);
+out_free:
+ kfree(ls);
+out:
+ return error;
+}
+
+static void gdlm_unmount(void *lockspace)
+{
+ struct gdlm_ls *ls = lockspace;
+ int rv;
+
+ log_debug("unmount flags %lx", ls->flags);
+
+ /* FIXME: serialize unmount and withdraw in case they
+ happen at once. Also, if unmount follows withdraw,
+ wait for withdraw to finish. */
+
+ if (test_bit(DFL_WITHDRAW, &ls->flags))
+ goto out;
+
+ gdlm_kobject_release(ls);
+ dlm_release_lockspace(ls->dlm_lockspace, 2);
+ gdlm_release_threads(ls);
+ rv = gdlm_release_all_locks(ls);
+ if (rv)
+ log_info("gdlm_unmount: %d stray locks freed", rv);
+out:
+ kfree(ls);
+}
+
+static void gdlm_recovery_done(void *lockspace, unsigned int jid,
+ unsigned int message)
+{
+ struct gdlm_ls *ls = lockspace;
+ ls->recover_jid_done = jid;
+ ls->recover_jid_status = message;
+ kobject_uevent(&ls->kobj, KOBJ_CHANGE);
+}
+
+static void gdlm_others_may_mount(void *lockspace)
+{
+ struct gdlm_ls *ls = lockspace;
+ ls->first_done = 1;
+ kobject_uevent(&ls->kobj, KOBJ_CHANGE);
+}
+
+/* Userspace gets the offline uevent, blocks new gfs locks on
+ other mounters, and lets us know (sets WITHDRAW flag). Then,
+ userspace leaves the mount group while we leave the lockspace. */
+
+static void gdlm_withdraw(void *lockspace)
+{
+ struct gdlm_ls *ls = lockspace;
+
+ kobject_uevent(&ls->kobj, KOBJ_OFFLINE);
+
+ wait_event_interruptible(ls->wait_control,
+ test_bit(DFL_WITHDRAW, &ls->flags));
+
+ dlm_release_lockspace(ls->dlm_lockspace, 2);
+ gdlm_release_threads(ls);
+ gdlm_release_all_locks(ls);
+ gdlm_kobject_release(ls);
+}
+
+const struct lm_lockops gdlm_ops = {
+ .lm_proto_name = "lock_dlm",
+ .lm_mount = gdlm_mount,
+ .lm_others_may_mount = gdlm_others_may_mount,
+ .lm_unmount = gdlm_unmount,
+ .lm_withdraw = gdlm_withdraw,
+ .lm_get_lock = gdlm_get_lock,
+ .lm_put_lock = gdlm_put_lock,
+ .lm_lock = gdlm_lock,
+ .lm_unlock = gdlm_unlock,
+ .lm_plock = gdlm_plock,
+ .lm_punlock = gdlm_punlock,
+ .lm_plock_get = gdlm_plock_get,
+ .lm_cancel = gdlm_cancel,
+ .lm_hold_lvb = gdlm_hold_lvb,
+ .lm_unhold_lvb = gdlm_unhold_lvb,
+ .lm_recovery_done = gdlm_recovery_done,
+ .lm_owner = THIS_MODULE,
+};
+
diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c
new file mode 100644
index 000000000000..7365aec9511b
--- /dev/null
+++ b/fs/gfs2/locking/dlm/plock.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/miscdevice.h>
+#include <linux/lock_dlm_plock.h>
+
+#include "lock_dlm.h"
+
+
+static spinlock_t ops_lock;
+static struct list_head send_list;
+static struct list_head recv_list;
+static wait_queue_head_t send_wq;
+static wait_queue_head_t recv_wq;
+
+struct plock_op {
+ struct list_head list;
+ int done;
+ struct gdlm_plock_info info;
+};
+
+static inline void set_version(struct gdlm_plock_info *info)
+{
+ info->version[0] = GDLM_PLOCK_VERSION_MAJOR;
+ info->version[1] = GDLM_PLOCK_VERSION_MINOR;
+ info->version[2] = GDLM_PLOCK_VERSION_PATCH;
+}
+
+static int check_version(struct gdlm_plock_info *info)
+{
+ if ((GDLM_PLOCK_VERSION_MAJOR != info->version[0]) ||
+ (GDLM_PLOCK_VERSION_MINOR < info->version[1])) {
+ log_error("plock device version mismatch: "
+ "kernel (%u.%u.%u), user (%u.%u.%u)",
+ GDLM_PLOCK_VERSION_MAJOR,
+ GDLM_PLOCK_VERSION_MINOR,
+ GDLM_PLOCK_VERSION_PATCH,
+ info->version[0],
+ info->version[1],
+ info->version[2]);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void send_op(struct plock_op *op)
+{
+ set_version(&op->info);
+ INIT_LIST_HEAD(&op->list);
+ spin_lock(&ops_lock);
+ list_add_tail(&op->list, &send_list);
+ spin_unlock(&ops_lock);
+ wake_up(&send_wq);
+}
+
+int gdlm_plock(void *lockspace, struct lm_lockname *name,
+ struct file *file, int cmd, struct file_lock *fl)
+{
+ struct gdlm_ls *ls = lockspace;
+ struct plock_op *op;
+ int rv;
+
+ op = kzalloc(sizeof(*op), GFP_KERNEL);
+ if (!op)
+ return -ENOMEM;
+
+ op->info.optype = GDLM_PLOCK_OP_LOCK;
+ op->info.pid = fl->fl_pid;
+ op->info.ex = (fl->fl_type == F_WRLCK);
+ op->info.wait = IS_SETLKW(cmd);
+ op->info.fsid = ls->id;
+ op->info.number = name->ln_number;
+ op->info.start = fl->fl_start;
+ op->info.end = fl->fl_end;
+ op->info.owner = (__u64)(long) fl->fl_owner;
+
+ send_op(op);
+ wait_event(recv_wq, (op->done != 0));
+
+ spin_lock(&ops_lock);
+ if (!list_empty(&op->list)) {
+ printk(KERN_INFO "plock op on list\n");
+ list_del(&op->list);
+ }
+ spin_unlock(&ops_lock);
+
+ rv = op->info.rv;
+
+ if (!rv) {
+ if (posix_lock_file_wait(file, fl) < 0)
+ log_error("gdlm_plock: vfs lock error %x,%llx",
+ name->ln_type,
+ (unsigned long long)name->ln_number);
+ }
+
+ kfree(op);
+ return rv;
+}
+
+int gdlm_punlock(void *lockspace, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl)
+{
+ struct gdlm_ls *ls = lockspace;
+ struct plock_op *op;
+ int rv;
+
+ op = kzalloc(sizeof(*op), GFP_KERNEL);
+ if (!op)
+ return -ENOMEM;
+
+ if (posix_lock_file_wait(file, fl) < 0)
+ log_error("gdlm_punlock: vfs unlock error %x,%llx",
+ name->ln_type, (unsigned long long)name->ln_number);
+
+ op->info.optype = GDLM_PLOCK_OP_UNLOCK;
+ op->info.pid = fl->fl_pid;
+ op->info.fsid = ls->id;
+ op->info.number = name->ln_number;
+ op->info.start = fl->fl_start;
+ op->info.end = fl->fl_end;
+ op->info.owner = (__u64)(long) fl->fl_owner;
+
+ send_op(op);
+ wait_event(recv_wq, (op->done != 0));
+
+ spin_lock(&ops_lock);
+ if (!list_empty(&op->list)) {
+ printk(KERN_INFO "punlock op on list\n");
+ list_del(&op->list);
+ }
+ spin_unlock(&ops_lock);
+
+ rv = op->info.rv;
+
+ kfree(op);
+ return rv;
+}
+
+int gdlm_plock_get(void *lockspace, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl)
+{
+ struct gdlm_ls *ls = lockspace;
+ struct plock_op *op;
+ int rv;
+
+ op = kzalloc(sizeof(*op), GFP_KERNEL);
+ if (!op)
+ return -ENOMEM;
+
+ op->info.optype = GDLM_PLOCK_OP_GET;
+ op->info.pid = fl->fl_pid;
+ op->info.ex = (fl->fl_type == F_WRLCK);
+ op->info.fsid = ls->id;
+ op->info.number = name->ln_number;
+ op->info.start = fl->fl_start;
+ op->info.end = fl->fl_end;
+
+ send_op(op);
+ wait_event(recv_wq, (op->done != 0));
+
+ spin_lock(&ops_lock);
+ if (!list_empty(&op->list)) {
+ printk(KERN_INFO "plock_get op on list\n");
+ list_del(&op->list);
+ }
+ spin_unlock(&ops_lock);
+
+ rv = op->info.rv;
+
+ if (rv == 0)
+ fl->fl_type = F_UNLCK;
+ else if (rv > 0) {
+ fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
+ fl->fl_pid = op->info.pid;
+ fl->fl_start = op->info.start;
+ fl->fl_end = op->info.end;
+ }
+
+ kfree(op);
+ return rv;
+}
+
+/* a read copies out one plock request from the send list */
+static ssize_t dev_read(struct file *file, char __user *u, size_t count,
+ loff_t *ppos)
+{
+ struct gdlm_plock_info info;
+ struct plock_op *op = NULL;
+
+ if (count < sizeof(info))
+ return -EINVAL;
+
+ spin_lock(&ops_lock);
+ if (!list_empty(&send_list)) {
+ op = list_entry(send_list.next, struct plock_op, list);
+ list_move(&op->list, &recv_list);
+ memcpy(&info, &op->info, sizeof(info));
+ }
+ spin_unlock(&ops_lock);
+
+ if (!op)
+ return -EAGAIN;
+
+ if (copy_to_user(u, &info, sizeof(info)))
+ return -EFAULT;
+ return sizeof(info);
+}
+
+/* a write copies in one plock result that should match a plock_op
+ on the recv list */
+static ssize_t dev_write(struct file *file, const char __user *u, size_t count,
+ loff_t *ppos)
+{
+ struct gdlm_plock_info info;
+ struct plock_op *op;
+ int found = 0;
+
+ if (count != sizeof(info))
+ return -EINVAL;
+
+ if (copy_from_user(&info, u, sizeof(info)))
+ return -EFAULT;
+
+ if (check_version(&info))
+ return -EINVAL;
+
+ spin_lock(&ops_lock);
+ list_for_each_entry(op, &recv_list, list) {
+ if (op->info.fsid == info.fsid && op->info.number == info.number &&
+ op->info.owner == info.owner) {
+ list_del_init(&op->list);
+ found = 1;
+ op->done = 1;
+ memcpy(&op->info, &info, sizeof(info));
+ break;
+ }
+ }
+ spin_unlock(&ops_lock);
+
+ if (found)
+ wake_up(&recv_wq);
+ else
+ printk(KERN_INFO "gdlm dev_write no op %x %llx\n", info.fsid,
+ (unsigned long long)info.number);
+ return count;
+}
+
+static unsigned int dev_poll(struct file *file, poll_table *wait)
+{
+ poll_wait(file, &send_wq, wait);
+
+ spin_lock(&ops_lock);
+ if (!list_empty(&send_list)) {
+ spin_unlock(&ops_lock);
+ return POLLIN | POLLRDNORM;
+ }
+ spin_unlock(&ops_lock);
+ return 0;
+}
+
+static struct file_operations dev_fops = {
+ .read = dev_read,
+ .write = dev_write,
+ .poll = dev_poll,
+ .owner = THIS_MODULE
+};
+
+static struct miscdevice plock_dev_misc = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = GDLM_PLOCK_MISC_NAME,
+ .fops = &dev_fops
+};
+
+int gdlm_plock_init(void)
+{
+ int rv;
+
+ spin_lock_init(&ops_lock);
+ INIT_LIST_HEAD(&send_list);
+ INIT_LIST_HEAD(&recv_list);
+ init_waitqueue_head(&send_wq);
+ init_waitqueue_head(&recv_wq);
+
+ rv = misc_register(&plock_dev_misc);
+ if (rv)
+ printk(KERN_INFO "gdlm_plock_init: misc_register failed %d",
+ rv);
+ return rv;
+}
+
+void gdlm_plock_exit(void)
+{
+ if (misc_deregister(&plock_dev_misc) < 0)
+ printk(KERN_INFO "gdlm_plock_exit: misc_deregister failed");
+}
+
diff --git a/fs/gfs2/locking/dlm/sysfs.c b/fs/gfs2/locking/dlm/sysfs.c
new file mode 100644
index 000000000000..29ae06f94944
--- /dev/null
+++ b/fs/gfs2/locking/dlm/sysfs.c
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/ctype.h>
+#include <linux/stat.h>
+
+#include "lock_dlm.h"
+
+extern struct lm_lockops gdlm_ops;
+
+static ssize_t proto_name_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%s\n", gdlm_ops.lm_proto_name);
+}
+
+static ssize_t block_show(struct gdlm_ls *ls, char *buf)
+{
+ ssize_t ret;
+ int val = 0;
+
+ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags))
+ val = 1;
+ ret = sprintf(buf, "%d\n", val);
+ return ret;
+}
+
+static ssize_t block_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+ ssize_t ret = len;
+ int val;
+
+ val = simple_strtol(buf, NULL, 0);
+
+ if (val == 1)
+ set_bit(DFL_BLOCK_LOCKS, &ls->flags);
+ else if (val == 0) {
+ clear_bit(DFL_BLOCK_LOCKS, &ls->flags);
+ gdlm_submit_delayed(ls);
+ } else {
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static ssize_t withdraw_show(struct gdlm_ls *ls, char *buf)
+{
+ ssize_t ret;
+ int val = 0;
+
+ if (test_bit(DFL_WITHDRAW, &ls->flags))
+ val = 1;
+ ret = sprintf(buf, "%d\n", val);
+ return ret;
+}
+
+static ssize_t withdraw_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+ ssize_t ret = len;
+ int val;
+
+ val = simple_strtol(buf, NULL, 0);
+
+ if (val == 1)
+ set_bit(DFL_WITHDRAW, &ls->flags);
+ else
+ ret = -EINVAL;
+ wake_up(&ls->wait_control);
+ return ret;
+}
+
+static ssize_t id_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%u\n", ls->id);
+}
+
+static ssize_t jid_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%d\n", ls->jid);
+}
+
+static ssize_t first_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%d\n", ls->first);
+}
+
+static ssize_t first_done_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%d\n", ls->first_done);
+}
+
+static ssize_t recover_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%d\n", ls->recover_jid);
+}
+
+static ssize_t recover_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+ ls->recover_jid = simple_strtol(buf, NULL, 0);
+ ls->fscb(ls->sdp, LM_CB_NEED_RECOVERY, &ls->recover_jid);
+ return len;
+}
+
+static ssize_t recover_done_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%d\n", ls->recover_jid_done);
+}
+
+static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf)
+{
+ return sprintf(buf, "%d\n", ls->recover_jid_status);
+}
+
+struct gdlm_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct gdlm_ls *, char *);
+ ssize_t (*store)(struct gdlm_ls *, const char *, size_t);
+};
+
+#define GDLM_ATTR(_name,_mode,_show,_store) \
+static struct gdlm_attr gdlm_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+GDLM_ATTR(proto_name, 0444, proto_name_show, NULL);
+GDLM_ATTR(block, 0644, block_show, block_store);
+GDLM_ATTR(withdraw, 0644, withdraw_show, withdraw_store);
+GDLM_ATTR(id, 0444, id_show, NULL);
+GDLM_ATTR(jid, 0444, jid_show, NULL);
+GDLM_ATTR(first, 0444, first_show, NULL);
+GDLM_ATTR(first_done, 0444, first_done_show, NULL);
+GDLM_ATTR(recover, 0644, recover_show, recover_store);
+GDLM_ATTR(recover_done, 0444, recover_done_show, NULL);
+GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
+
+static struct attribute *gdlm_attrs[] = {
+ &gdlm_attr_proto_name.attr,
+ &gdlm_attr_block.attr,
+ &gdlm_attr_withdraw.attr,
+ &gdlm_attr_id.attr,
+ &gdlm_attr_jid.attr,
+ &gdlm_attr_first.attr,
+ &gdlm_attr_first_done.attr,
+ &gdlm_attr_recover.attr,
+ &gdlm_attr_recover_done.attr,
+ &gdlm_attr_recover_status.attr,
+ NULL,
+};
+
+static ssize_t gdlm_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
+ struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
+ return a->show ? a->show(ls, buf) : 0;
+}
+
+static ssize_t gdlm_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct gdlm_ls *ls = container_of(kobj, struct gdlm_ls, kobj);
+ struct gdlm_attr *a = container_of(attr, struct gdlm_attr, attr);
+ return a->store ? a->store(ls, buf, len) : len;
+}
+
+static struct sysfs_ops gdlm_attr_ops = {
+ .show = gdlm_attr_show,
+ .store = gdlm_attr_store,
+};
+
+static struct kobj_type gdlm_ktype = {
+ .default_attrs = gdlm_attrs,
+ .sysfs_ops = &gdlm_attr_ops,
+};
+
+static struct kset gdlm_kset = {
+ .subsys = &kernel_subsys,
+ .kobj = {.name = "lock_dlm",},
+ .ktype = &gdlm_ktype,
+};
+
+int gdlm_kobject_setup(struct gdlm_ls *ls, struct kobject *fskobj)
+{
+ int error;
+
+ error = kobject_set_name(&ls->kobj, "%s", "lock_module");
+ if (error) {
+ log_error("can't set kobj name %d", error);
+ return error;
+ }
+
+ ls->kobj.kset = &gdlm_kset;
+ ls->kobj.ktype = &gdlm_ktype;
+ ls->kobj.parent = fskobj;
+
+ error = kobject_register(&ls->kobj);
+ if (error)
+ log_error("can't register kobj %d", error);
+
+ return error;
+}
+
+void gdlm_kobject_release(struct gdlm_ls *ls)
+{
+ kobject_unregister(&ls->kobj);
+}
+
+int gdlm_sysfs_init(void)
+{
+ int error;
+
+ error = kset_register(&gdlm_kset);
+ if (error)
+ printk("lock_dlm: cannot register kset %d\n", error);
+
+ return error;
+}
+
+void gdlm_sysfs_exit(void)
+{
+ kset_unregister(&gdlm_kset);
+}
+
diff --git a/fs/gfs2/locking/dlm/thread.c b/fs/gfs2/locking/dlm/thread.c
new file mode 100644
index 000000000000..9cf1f168eaf8
--- /dev/null
+++ b/fs/gfs2/locking/dlm/thread.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include "lock_dlm.h"
+
+/* A lock placed on this queue is re-submitted to DLM as soon as the lock_dlm
+ thread gets to it. */
+
+static void queue_submit(struct gdlm_lock *lp)
+{
+ struct gdlm_ls *ls = lp->ls;
+
+ spin_lock(&ls->async_lock);
+ list_add_tail(&lp->delay_list, &ls->submit);
+ spin_unlock(&ls->async_lock);
+ wake_up(&ls->thread_wait);
+}
+
+static void process_blocking(struct gdlm_lock *lp, int bast_mode)
+{
+ struct gdlm_ls *ls = lp->ls;
+ unsigned int cb = 0;
+
+ switch (gdlm_make_lmstate(bast_mode)) {
+ case LM_ST_EXCLUSIVE:
+ cb = LM_CB_NEED_E;
+ break;
+ case LM_ST_DEFERRED:
+ cb = LM_CB_NEED_D;
+ break;
+ case LM_ST_SHARED:
+ cb = LM_CB_NEED_S;
+ break;
+ default:
+ gdlm_assert(0, "unknown bast mode %u", lp->bast_mode);
+ }
+
+ ls->fscb(ls->sdp, cb, &lp->lockname);
+}
+
+static void process_complete(struct gdlm_lock *lp)
+{
+ struct gdlm_ls *ls = lp->ls;
+ struct lm_async_cb acb;
+ s16 prev_mode = lp->cur;
+
+ memset(&acb, 0, sizeof(acb));
+
+ if (lp->lksb.sb_status == -DLM_ECANCEL) {
+ log_info("complete dlm cancel %x,%llx flags %lx",
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number,
+ lp->flags);
+
+ lp->req = lp->cur;
+ acb.lc_ret |= LM_OUT_CANCELED;
+ if (lp->cur == DLM_LOCK_IV)
+ lp->lksb.sb_lkid = 0;
+ goto out;
+ }
+
+ if (test_and_clear_bit(LFL_DLM_UNLOCK, &lp->flags)) {
+ if (lp->lksb.sb_status != -DLM_EUNLOCK) {
+ log_info("unlock sb_status %d %x,%llx flags %lx",
+ lp->lksb.sb_status, lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number,
+ lp->flags);
+ return;
+ }
+
+ lp->cur = DLM_LOCK_IV;
+ lp->req = DLM_LOCK_IV;
+ lp->lksb.sb_lkid = 0;
+
+ if (test_and_clear_bit(LFL_UNLOCK_DELETE, &lp->flags)) {
+ gdlm_delete_lp(lp);
+ return;
+ }
+ goto out;
+ }
+
+ if (lp->lksb.sb_flags & DLM_SBF_VALNOTVALID)
+ memset(lp->lksb.sb_lvbptr, 0, GDLM_LVB_SIZE);
+
+ if (lp->lksb.sb_flags & DLM_SBF_ALTMODE) {
+ if (lp->req == DLM_LOCK_PR)
+ lp->req = DLM_LOCK_CW;
+ else if (lp->req == DLM_LOCK_CW)
+ lp->req = DLM_LOCK_PR;
+ }
+
+ /*
+ * A canceled lock request. The lock was just taken off the delayed
+ * list and was never even submitted to dlm.
+ */
+
+ if (test_and_clear_bit(LFL_CANCEL, &lp->flags)) {
+ log_info("complete internal cancel %x,%llx",
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number);
+ lp->req = lp->cur;
+ acb.lc_ret |= LM_OUT_CANCELED;
+ goto out;
+ }
+
+ /*
+ * An error occured.
+ */
+
+ if (lp->lksb.sb_status) {
+ /* a "normal" error */
+ if ((lp->lksb.sb_status == -EAGAIN) &&
+ (lp->lkf & DLM_LKF_NOQUEUE)) {
+ lp->req = lp->cur;
+ if (lp->cur == DLM_LOCK_IV)
+ lp->lksb.sb_lkid = 0;
+ goto out;
+ }
+
+ /* this could only happen with cancels I think */
+ log_info("ast sb_status %d %x,%llx flags %lx",
+ lp->lksb.sb_status, lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number,
+ lp->flags);
+ return;
+ }
+
+ /*
+ * This is an AST for an EX->EX conversion for sync_lvb from GFS.
+ */
+
+ if (test_and_clear_bit(LFL_SYNC_LVB, &lp->flags)) {
+ complete(&lp->ast_wait);
+ return;
+ }
+
+ /*
+ * A lock has been demoted to NL because it initially completed during
+ * BLOCK_LOCKS. Now it must be requested in the originally requested
+ * mode.
+ */
+
+ if (test_and_clear_bit(LFL_REREQUEST, &lp->flags)) {
+ gdlm_assert(lp->req == DLM_LOCK_NL, "%x,%llx",
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number);
+ gdlm_assert(lp->prev_req > DLM_LOCK_NL, "%x,%llx",
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number);
+
+ lp->cur = DLM_LOCK_NL;
+ lp->req = lp->prev_req;
+ lp->prev_req = DLM_LOCK_IV;
+ lp->lkf &= ~DLM_LKF_CONVDEADLK;
+
+ set_bit(LFL_NOCACHE, &lp->flags);
+
+ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
+ !test_bit(LFL_NOBLOCK, &lp->flags))
+ gdlm_queue_delayed(lp);
+ else
+ queue_submit(lp);
+ return;
+ }
+
+ /*
+ * A request is granted during dlm recovery. It may be granted
+ * because the locks of a failed node were cleared. In that case,
+ * there may be inconsistent data beneath this lock and we must wait
+ * for recovery to complete to use it. When gfs recovery is done this
+ * granted lock will be converted to NL and then reacquired in this
+ * granted state.
+ */
+
+ if (test_bit(DFL_BLOCK_LOCKS, &ls->flags) &&
+ !test_bit(LFL_NOBLOCK, &lp->flags) &&
+ lp->req != DLM_LOCK_NL) {
+
+ lp->cur = lp->req;
+ lp->prev_req = lp->req;
+ lp->req = DLM_LOCK_NL;
+ lp->lkf |= DLM_LKF_CONVERT;
+ lp->lkf &= ~DLM_LKF_CONVDEADLK;
+
+ log_debug("rereq %x,%llx id %x %d,%d",
+ lp->lockname.ln_type,
+ (unsigned long long)lp->lockname.ln_number,
+ lp->lksb.sb_lkid, lp->cur, lp->req);
+
+ set_bit(LFL_REREQUEST, &lp->flags);
+ queue_submit(lp);
+ return;
+ }
+
+ /*
+ * DLM demoted the lock to NL before it was granted so GFS must be
+ * told it cannot cache data for this lock.
+ */
+
+ if (lp->lksb.sb_flags & DLM_SBF_DEMOTED)
+ set_bit(LFL_NOCACHE, &lp->flags);
+
+out:
+ /*
+ * This is an internal lock_dlm lock
+ */
+
+ if (test_bit(LFL_INLOCK, &lp->flags)) {
+ clear_bit(LFL_NOBLOCK, &lp->flags);
+ lp->cur = lp->req;
+ complete(&lp->ast_wait);
+ return;
+ }
+
+ /*
+ * Normal completion of a lock request. Tell GFS it now has the lock.
+ */
+
+ clear_bit(LFL_NOBLOCK, &lp->flags);
+ lp->cur = lp->req;
+
+ acb.lc_name = lp->lockname;
+ acb.lc_ret |= gdlm_make_lmstate(lp->cur);
+
+ if (!test_and_clear_bit(LFL_NOCACHE, &lp->flags) &&
+ (lp->cur > DLM_LOCK_NL) && (prev_mode > DLM_LOCK_NL))
+ acb.lc_ret |= LM_OUT_CACHEABLE;
+
+ ls->fscb(ls->sdp, LM_CB_ASYNC, &acb);
+}
+
+static inline int no_work(struct gdlm_ls *ls, int blocking)
+{
+ int ret;
+
+ spin_lock(&ls->async_lock);
+ ret = list_empty(&ls->complete) && list_empty(&ls->submit);
+ if (ret && blocking)
+ ret = list_empty(&ls->blocking);
+ spin_unlock(&ls->async_lock);
+
+ return ret;
+}
+
+static inline int check_drop(struct gdlm_ls *ls)
+{
+ if (!ls->drop_locks_count)
+ return 0;
+
+ if (time_after(jiffies, ls->drop_time + ls->drop_locks_period * HZ)) {
+ ls->drop_time = jiffies;
+ if (ls->all_locks_count >= ls->drop_locks_count)
+ return 1;
+ }
+ return 0;
+}
+
+static int gdlm_thread(void *data)
+{
+ struct gdlm_ls *ls = (struct gdlm_ls *) data;
+ struct gdlm_lock *lp = NULL;
+ int blist = 0;
+ uint8_t complete, blocking, submit, drop;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /* Only thread1 is allowed to do blocking callbacks since gfs
+ may wait for a completion callback within a blocking cb. */
+
+ if (current == ls->thread1)
+ blist = 1;
+
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&ls->thread_wait, &wait);
+ if (no_work(ls, blist))
+ schedule();
+ remove_wait_queue(&ls->thread_wait, &wait);
+ set_current_state(TASK_RUNNING);
+
+ complete = blocking = submit = drop = 0;
+
+ spin_lock(&ls->async_lock);
+
+ if (blist && !list_empty(&ls->blocking)) {
+ lp = list_entry(ls->blocking.next, struct gdlm_lock,
+ blist);
+ list_del_init(&lp->blist);
+ blocking = lp->bast_mode;
+ lp->bast_mode = 0;
+ } else if (!list_empty(&ls->complete)) {
+ lp = list_entry(ls->complete.next, struct gdlm_lock,
+ clist);
+ list_del_init(&lp->clist);
+ complete = 1;
+ } else if (!list_empty(&ls->submit)) {
+ lp = list_entry(ls->submit.next, struct gdlm_lock,
+ delay_list);
+ list_del_init(&lp->delay_list);
+ submit = 1;
+ }
+
+ drop = check_drop(ls);
+ spin_unlock(&ls->async_lock);
+
+ if (complete)
+ process_complete(lp);
+
+ else if (blocking)
+ process_blocking(lp, blocking);
+
+ else if (submit)
+ gdlm_do_lock(lp);
+
+ if (drop)
+ ls->fscb(ls->sdp, LM_CB_DROPLOCKS, NULL);
+
+ schedule();
+ }
+
+ return 0;
+}
+
+int gdlm_init_threads(struct gdlm_ls *ls)
+{
+ struct task_struct *p;
+ int error;
+
+ p = kthread_run(gdlm_thread, ls, "lock_dlm1");
+ error = IS_ERR(p);
+ if (error) {
+ log_error("can't start lock_dlm1 thread %d", error);
+ return error;
+ }
+ ls->thread1 = p;
+
+ p = kthread_run(gdlm_thread, ls, "lock_dlm2");
+ error = IS_ERR(p);
+ if (error) {
+ log_error("can't start lock_dlm2 thread %d", error);
+ kthread_stop(ls->thread1);
+ return error;
+ }
+ ls->thread2 = p;
+
+ return 0;
+}
+
+void gdlm_release_threads(struct gdlm_ls *ls)
+{
+ kthread_stop(ls->thread1);
+ kthread_stop(ls->thread2);
+}
+
diff --git a/fs/gfs2/locking/nolock/Makefile b/fs/gfs2/locking/nolock/Makefile
new file mode 100644
index 000000000000..35e9730bc3a8
--- /dev/null
+++ b/fs/gfs2/locking/nolock/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_GFS2_FS_LOCKING_NOLOCK) += lock_nolock.o
+lock_nolock-y := main.o
+
diff --git a/fs/gfs2/locking/nolock/main.c b/fs/gfs2/locking/nolock/main.c
new file mode 100644
index 000000000000..acfbc941f319
--- /dev/null
+++ b/fs/gfs2/locking/nolock/main.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/lm_interface.h>
+
+struct nolock_lockspace {
+ unsigned int nl_lvb_size;
+};
+
+static const struct lm_lockops nolock_ops;
+
+static int nolock_mount(char *table_name, char *host_data,
+ lm_callback_t cb, void *cb_data,
+ unsigned int min_lvb_size, int flags,
+ struct lm_lockstruct *lockstruct,
+ struct kobject *fskobj)
+{
+ char *c;
+ unsigned int jid;
+ struct nolock_lockspace *nl;
+
+ c = strstr(host_data, "jid=");
+ if (!c)
+ jid = 0;
+ else {
+ c += 4;
+ sscanf(c, "%u", &jid);
+ }
+
+ nl = kzalloc(sizeof(struct nolock_lockspace), GFP_KERNEL);
+ if (!nl)
+ return -ENOMEM;
+
+ nl->nl_lvb_size = min_lvb_size;
+
+ lockstruct->ls_jid = jid;
+ lockstruct->ls_first = 1;
+ lockstruct->ls_lvb_size = min_lvb_size;
+ lockstruct->ls_lockspace = nl;
+ lockstruct->ls_ops = &nolock_ops;
+ lockstruct->ls_flags = LM_LSFLAG_LOCAL;
+
+ return 0;
+}
+
+static void nolock_others_may_mount(void *lockspace)
+{
+}
+
+static void nolock_unmount(void *lockspace)
+{
+ struct nolock_lockspace *nl = lockspace;
+ kfree(nl);
+}
+
+static void nolock_withdraw(void *lockspace)
+{
+}
+
+/**
+ * nolock_get_lock - get a lm_lock_t given a descripton of the lock
+ * @lockspace: the lockspace the lock lives in
+ * @name: the name of the lock
+ * @lockp: return the lm_lock_t here
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+static int nolock_get_lock(void *lockspace, struct lm_lockname *name,
+ void **lockp)
+{
+ *lockp = lockspace;
+ return 0;
+}
+
+/**
+ * nolock_put_lock - get rid of a lock structure
+ * @lock: the lock to throw away
+ *
+ */
+
+static void nolock_put_lock(void *lock)
+{
+}
+
+/**
+ * nolock_lock - acquire a lock
+ * @lock: the lock to manipulate
+ * @cur_state: the current state
+ * @req_state: the requested state
+ * @flags: modifier flags
+ *
+ * Returns: A bitmap of LM_OUT_*
+ */
+
+static unsigned int nolock_lock(void *lock, unsigned int cur_state,
+ unsigned int req_state, unsigned int flags)
+{
+ return req_state | LM_OUT_CACHEABLE;
+}
+
+/**
+ * nolock_unlock - unlock a lock
+ * @lock: the lock to manipulate
+ * @cur_state: the current state
+ *
+ * Returns: 0
+ */
+
+static unsigned int nolock_unlock(void *lock, unsigned int cur_state)
+{
+ return 0;
+}
+
+static void nolock_cancel(void *lock)
+{
+}
+
+/**
+ * nolock_hold_lvb - hold on to a lock value block
+ * @lock: the lock the LVB is associated with
+ * @lvbp: return the lm_lvb_t here
+ *
+ * Returns: 0 on success, -EXXX on failure
+ */
+
+static int nolock_hold_lvb(void *lock, char **lvbp)
+{
+ struct nolock_lockspace *nl = lock;
+ int error = 0;
+
+ *lvbp = kzalloc(nl->nl_lvb_size, GFP_KERNEL);
+ if (!*lvbp)
+ error = -ENOMEM;
+
+ return error;
+}
+
+/**
+ * nolock_unhold_lvb - release a LVB
+ * @lock: the lock the LVB is associated with
+ * @lvb: the lock value block
+ *
+ */
+
+static void nolock_unhold_lvb(void *lock, char *lvb)
+{
+ kfree(lvb);
+}
+
+static int nolock_plock_get(void *lockspace, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl)
+{
+ struct file_lock tmp;
+ int ret;
+
+ ret = posix_test_lock(file, fl, &tmp);
+ fl->fl_type = F_UNLCK;
+ if (ret)
+ memcpy(fl, &tmp, sizeof(struct file_lock));
+
+ return 0;
+}
+
+static int nolock_plock(void *lockspace, struct lm_lockname *name,
+ struct file *file, int cmd, struct file_lock *fl)
+{
+ int error;
+ error = posix_lock_file_wait(file, fl);
+ return error;
+}
+
+static int nolock_punlock(void *lockspace, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl)
+{
+ int error;
+ error = posix_lock_file_wait(file, fl);
+ return error;
+}
+
+static void nolock_recovery_done(void *lockspace, unsigned int jid,
+ unsigned int message)
+{
+}
+
+static const struct lm_lockops nolock_ops = {
+ .lm_proto_name = "lock_nolock",
+ .lm_mount = nolock_mount,
+ .lm_others_may_mount = nolock_others_may_mount,
+ .lm_unmount = nolock_unmount,
+ .lm_withdraw = nolock_withdraw,
+ .lm_get_lock = nolock_get_lock,
+ .lm_put_lock = nolock_put_lock,
+ .lm_lock = nolock_lock,
+ .lm_unlock = nolock_unlock,
+ .lm_cancel = nolock_cancel,
+ .lm_hold_lvb = nolock_hold_lvb,
+ .lm_unhold_lvb = nolock_unhold_lvb,
+ .lm_plock_get = nolock_plock_get,
+ .lm_plock = nolock_plock,
+ .lm_punlock = nolock_punlock,
+ .lm_recovery_done = nolock_recovery_done,
+ .lm_owner = THIS_MODULE,
+};
+
+static int __init init_nolock(void)
+{
+ int error;
+
+ error = gfs2_register_lockproto(&nolock_ops);
+ if (error) {
+ printk(KERN_WARNING
+ "lock_nolock: can't register protocol: %d\n", error);
+ return error;
+ }
+
+ printk(KERN_INFO
+ "Lock_Nolock (built %s %s) installed\n", __DATE__, __TIME__);
+ return 0;
+}
+
+static void __exit exit_nolock(void)
+{
+ gfs2_unregister_lockproto(&nolock_ops);
+}
+
+module_init(init_nolock);
+module_exit(exit_nolock);
+
+MODULE_DESCRIPTION("GFS Nolock Locking Module");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
new file mode 100644
index 000000000000..0cace3da9dbb
--- /dev/null
+++ b/fs/gfs2/log.c
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "util.h"
+#include "dir.h"
+
+#define PULL 1
+
+/**
+ * gfs2_struct2blk - compute stuff
+ * @sdp: the filesystem
+ * @nstruct: the number of structures
+ * @ssize: the size of the structures
+ *
+ * Compute the number of log descriptor blocks needed to hold a certain number
+ * of structures of a certain size.
+ *
+ * Returns: the number of blocks needed (minimum is always 1)
+ */
+
+unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
+ unsigned int ssize)
+{
+ unsigned int blks;
+ unsigned int first, second;
+
+ blks = 1;
+ first = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / ssize;
+
+ if (nstruct > first) {
+ second = (sdp->sd_sb.sb_bsize -
+ sizeof(struct gfs2_meta_header)) / ssize;
+ blks += DIV_ROUND_UP(nstruct - first, second);
+ }
+
+ return blks;
+}
+
+/**
+ * gfs2_ail1_start_one - Start I/O on a part of the AIL
+ * @sdp: the filesystem
+ * @tr: the part of the AIL
+ *
+ */
+
+static void gfs2_ail1_start_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+ struct gfs2_bufdata *bd, *s;
+ struct buffer_head *bh;
+ int retry;
+
+ BUG_ON(!spin_is_locked(&sdp->sd_log_lock));
+
+ do {
+ retry = 0;
+
+ list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,
+ bd_ail_st_list) {
+ bh = bd->bd_bh;
+
+ gfs2_assert(sdp, bd->bd_ail == ai);
+
+ if (!buffer_busy(bh)) {
+ if (!buffer_uptodate(bh)) {
+ gfs2_log_unlock(sdp);
+ gfs2_io_error_bh(sdp, bh);
+ gfs2_log_lock(sdp);
+ }
+ list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
+ continue;
+ }
+
+ if (!buffer_dirty(bh))
+ continue;
+
+ list_move(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+
+ gfs2_log_unlock(sdp);
+ wait_on_buffer(bh);
+ ll_rw_block(WRITE, 1, &bh);
+ gfs2_log_lock(sdp);
+
+ retry = 1;
+ break;
+ }
+ } while (retry);
+}
+
+/**
+ * gfs2_ail1_empty_one - Check whether or not a trans in the AIL has been synced
+ * @sdp: the filesystem
+ * @ai: the AIL entry
+ *
+ */
+
+static int gfs2_ail1_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai, int flags)
+{
+ struct gfs2_bufdata *bd, *s;
+ struct buffer_head *bh;
+
+ list_for_each_entry_safe_reverse(bd, s, &ai->ai_ail1_list,
+ bd_ail_st_list) {
+ bh = bd->bd_bh;
+
+ gfs2_assert(sdp, bd->bd_ail == ai);
+
+ if (buffer_busy(bh)) {
+ if (flags & DIO_ALL)
+ continue;
+ else
+ break;
+ }
+
+ if (!buffer_uptodate(bh))
+ gfs2_io_error_bh(sdp, bh);
+
+ list_move(&bd->bd_ail_st_list, &ai->ai_ail2_list);
+ }
+
+ return list_empty(&ai->ai_ail1_list);
+}
+
+void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags)
+{
+ struct list_head *head = &sdp->sd_ail1_list;
+ u64 sync_gen;
+ struct list_head *first;
+ struct gfs2_ail *first_ai, *ai, *tmp;
+ int done = 0;
+
+ gfs2_log_lock(sdp);
+ if (list_empty(head)) {
+ gfs2_log_unlock(sdp);
+ return;
+ }
+ sync_gen = sdp->sd_ail_sync_gen++;
+
+ first = head->prev;
+ first_ai = list_entry(first, struct gfs2_ail, ai_list);
+ first_ai->ai_sync_gen = sync_gen;
+ gfs2_ail1_start_one(sdp, first_ai); /* This may drop log lock */
+
+ if (flags & DIO_ALL)
+ first = NULL;
+
+ while(!done) {
+ if (first && (head->prev != first ||
+ gfs2_ail1_empty_one(sdp, first_ai, 0)))
+ break;
+
+ done = 1;
+ list_for_each_entry_safe_reverse(ai, tmp, head, ai_list) {
+ if (ai->ai_sync_gen >= sync_gen)
+ continue;
+ ai->ai_sync_gen = sync_gen;
+ gfs2_ail1_start_one(sdp, ai); /* This may drop log lock */
+ done = 0;
+ break;
+ }
+ }
+
+ gfs2_log_unlock(sdp);
+}
+
+int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags)
+{
+ struct gfs2_ail *ai, *s;
+ int ret;
+
+ gfs2_log_lock(sdp);
+
+ list_for_each_entry_safe_reverse(ai, s, &sdp->sd_ail1_list, ai_list) {
+ if (gfs2_ail1_empty_one(sdp, ai, flags))
+ list_move(&ai->ai_list, &sdp->sd_ail2_list);
+ else if (!(flags & DIO_ALL))
+ break;
+ }
+
+ ret = list_empty(&sdp->sd_ail1_list);
+
+ gfs2_log_unlock(sdp);
+
+ return ret;
+}
+
+
+/**
+ * gfs2_ail2_empty_one - Check whether or not a trans in the AIL has been synced
+ * @sdp: the filesystem
+ * @ai: the AIL entry
+ *
+ */
+
+static void gfs2_ail2_empty_one(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+ struct list_head *head = &ai->ai_ail2_list;
+ struct gfs2_bufdata *bd;
+
+ while (!list_empty(head)) {
+ bd = list_entry(head->prev, struct gfs2_bufdata,
+ bd_ail_st_list);
+ gfs2_assert(sdp, bd->bd_ail == ai);
+ bd->bd_ail = NULL;
+ list_del(&bd->bd_ail_st_list);
+ list_del(&bd->bd_ail_gl_list);
+ atomic_dec(&bd->bd_gl->gl_ail_count);
+ brelse(bd->bd_bh);
+ }
+}
+
+static void ail2_empty(struct gfs2_sbd *sdp, unsigned int new_tail)
+{
+ struct gfs2_ail *ai, *safe;
+ unsigned int old_tail = sdp->sd_log_tail;
+ int wrap = (new_tail < old_tail);
+ int a, b, rm;
+
+ gfs2_log_lock(sdp);
+
+ list_for_each_entry_safe(ai, safe, &sdp->sd_ail2_list, ai_list) {
+ a = (old_tail <= ai->ai_first);
+ b = (ai->ai_first < new_tail);
+ rm = (wrap) ? (a || b) : (a && b);
+ if (!rm)
+ continue;
+
+ gfs2_ail2_empty_one(sdp, ai);
+ list_del(&ai->ai_list);
+ gfs2_assert_warn(sdp, list_empty(&ai->ai_ail1_list));
+ gfs2_assert_warn(sdp, list_empty(&ai->ai_ail2_list));
+ kfree(ai);
+ }
+
+ gfs2_log_unlock(sdp);
+}
+
+/**
+ * gfs2_log_reserve - Make a log reservation
+ * @sdp: The GFS2 superblock
+ * @blks: The number of blocks to reserve
+ *
+ * Returns: errno
+ */
+
+int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
+{
+ unsigned int try = 0;
+
+ if (gfs2_assert_warn(sdp, blks) ||
+ gfs2_assert_warn(sdp, blks <= sdp->sd_jdesc->jd_blocks))
+ return -EINVAL;
+
+ mutex_lock(&sdp->sd_log_reserve_mutex);
+ gfs2_log_lock(sdp);
+ while(sdp->sd_log_blks_free <= blks) {
+ gfs2_log_unlock(sdp);
+ gfs2_ail1_empty(sdp, 0);
+ gfs2_log_flush(sdp, NULL);
+
+ if (try++)
+ gfs2_ail1_start(sdp, 0);
+ gfs2_log_lock(sdp);
+ }
+ sdp->sd_log_blks_free -= blks;
+ gfs2_log_unlock(sdp);
+ mutex_unlock(&sdp->sd_log_reserve_mutex);
+
+ down_read(&sdp->sd_log_flush_lock);
+
+ return 0;
+}
+
+/**
+ * gfs2_log_release - Release a given number of log blocks
+ * @sdp: The GFS2 superblock
+ * @blks: The number of blocks
+ *
+ */
+
+void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
+{
+
+ gfs2_log_lock(sdp);
+ sdp->sd_log_blks_free += blks;
+ gfs2_assert_withdraw(sdp,
+ sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
+ gfs2_log_unlock(sdp);
+ up_read(&sdp->sd_log_flush_lock);
+}
+
+static u64 log_bmap(struct gfs2_sbd *sdp, unsigned int lbn)
+{
+ struct inode *inode = sdp->sd_jdesc->jd_inode;
+ int error;
+ struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
+
+ bh_map.b_size = 1 << inode->i_blkbits;
+ error = gfs2_block_map(inode, lbn, 0, &bh_map);
+ if (error || !bh_map.b_blocknr)
+ printk(KERN_INFO "error=%d, dbn=%llu lbn=%u", error, bh_map.b_blocknr, lbn);
+ gfs2_assert_withdraw(sdp, !error && bh_map.b_blocknr);
+
+ return bh_map.b_blocknr;
+}
+
+/**
+ * log_distance - Compute distance between two journal blocks
+ * @sdp: The GFS2 superblock
+ * @newer: The most recent journal block of the pair
+ * @older: The older journal block of the pair
+ *
+ * Compute the distance (in the journal direction) between two
+ * blocks in the journal
+ *
+ * Returns: the distance in blocks
+ */
+
+static inline unsigned int log_distance(struct gfs2_sbd *sdp, unsigned int newer,
+ unsigned int older)
+{
+ int dist;
+
+ dist = newer - older;
+ if (dist < 0)
+ dist += sdp->sd_jdesc->jd_blocks;
+
+ return dist;
+}
+
+static unsigned int current_tail(struct gfs2_sbd *sdp)
+{
+ struct gfs2_ail *ai;
+ unsigned int tail;
+
+ gfs2_log_lock(sdp);
+
+ if (list_empty(&sdp->sd_ail1_list)) {
+ tail = sdp->sd_log_head;
+ } else {
+ ai = list_entry(sdp->sd_ail1_list.prev, struct gfs2_ail, ai_list);
+ tail = ai->ai_first;
+ }
+
+ gfs2_log_unlock(sdp);
+
+ return tail;
+}
+
+static inline void log_incr_head(struct gfs2_sbd *sdp)
+{
+ if (sdp->sd_log_flush_head == sdp->sd_log_tail)
+ gfs2_assert_withdraw(sdp, sdp->sd_log_flush_head == sdp->sd_log_head);
+
+ if (++sdp->sd_log_flush_head == sdp->sd_jdesc->jd_blocks) {
+ sdp->sd_log_flush_head = 0;
+ sdp->sd_log_flush_wrapped = 1;
+ }
+}
+
+/**
+ * gfs2_log_get_buf - Get and initialize a buffer to use for log control data
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: the buffer_head
+ */
+
+struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp)
+{
+ u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
+ struct gfs2_log_buf *lb;
+ struct buffer_head *bh;
+
+ lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
+ list_add(&lb->lb_list, &sdp->sd_log_flush_list);
+
+ bh = lb->lb_bh = sb_getblk(sdp->sd_vfs, blkno);
+ lock_buffer(bh);
+ memset(bh->b_data, 0, bh->b_size);
+ set_buffer_uptodate(bh);
+ clear_buffer_dirty(bh);
+ unlock_buffer(bh);
+
+ log_incr_head(sdp);
+
+ return bh;
+}
+
+/**
+ * gfs2_log_fake_buf - Build a fake buffer head to write metadata buffer to log
+ * @sdp: the filesystem
+ * @data: the data the buffer_head should point to
+ *
+ * Returns: the log buffer descriptor
+ */
+
+struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+ struct buffer_head *real)
+{
+ u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
+ struct gfs2_log_buf *lb;
+ struct buffer_head *bh;
+
+ lb = kzalloc(sizeof(struct gfs2_log_buf), GFP_NOFS | __GFP_NOFAIL);
+ list_add(&lb->lb_list, &sdp->sd_log_flush_list);
+ lb->lb_real = real;
+
+ bh = lb->lb_bh = alloc_buffer_head(GFP_NOFS | __GFP_NOFAIL);
+ atomic_set(&bh->b_count, 1);
+ bh->b_state = (1 << BH_Mapped) | (1 << BH_Uptodate);
+ set_bh_page(bh, real->b_page, bh_offset(real));
+ bh->b_blocknr = blkno;
+ bh->b_size = sdp->sd_sb.sb_bsize;
+ bh->b_bdev = sdp->sd_vfs->s_bdev;
+
+ log_incr_head(sdp);
+
+ return bh;
+}
+
+static void log_pull_tail(struct gfs2_sbd *sdp, unsigned int new_tail, int pull)
+{
+ unsigned int dist = log_distance(sdp, new_tail, sdp->sd_log_tail);
+
+ ail2_empty(sdp, new_tail);
+
+ gfs2_log_lock(sdp);
+ sdp->sd_log_blks_free += dist - (pull ? 1 : 0);
+ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks);
+ gfs2_log_unlock(sdp);
+
+ sdp->sd_log_tail = new_tail;
+}
+
+/**
+ * log_write_header - Get and initialize a journal header buffer
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: the initialized log buffer descriptor
+ */
+
+static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull)
+{
+ u64 blkno = log_bmap(sdp, sdp->sd_log_flush_head);
+ struct buffer_head *bh;
+ struct gfs2_log_header *lh;
+ unsigned int tail;
+ u32 hash;
+
+ bh = sb_getblk(sdp->sd_vfs, blkno);
+ lock_buffer(bh);
+ memset(bh->b_data, 0, bh->b_size);
+ set_buffer_uptodate(bh);
+ clear_buffer_dirty(bh);
+ unlock_buffer(bh);
+
+ gfs2_ail1_empty(sdp, 0);
+ tail = current_tail(sdp);
+
+ lh = (struct gfs2_log_header *)bh->b_data;
+ memset(lh, 0, sizeof(struct gfs2_log_header));
+ lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+ lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
+ lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
+ lh->lh_sequence = cpu_to_be64(sdp->sd_log_sequence++);
+ lh->lh_flags = cpu_to_be32(flags);
+ lh->lh_tail = cpu_to_be32(tail);
+ lh->lh_blkno = cpu_to_be32(sdp->sd_log_flush_head);
+ hash = gfs2_disk_hash(bh->b_data, sizeof(struct gfs2_log_header));
+ lh->lh_hash = cpu_to_be32(hash);
+
+ set_buffer_dirty(bh);
+ if (sync_dirty_buffer(bh))
+ gfs2_io_error_bh(sdp, bh);
+ brelse(bh);
+
+ if (sdp->sd_log_tail != tail)
+ log_pull_tail(sdp, tail, pull);
+ else
+ gfs2_assert_withdraw(sdp, !pull);
+
+ sdp->sd_log_idle = (tail == sdp->sd_log_flush_head);
+ log_incr_head(sdp);
+}
+
+static void log_flush_commit(struct gfs2_sbd *sdp)
+{
+ struct list_head *head = &sdp->sd_log_flush_list;
+ struct gfs2_log_buf *lb;
+ struct buffer_head *bh;
+
+ while (!list_empty(head)) {
+ lb = list_entry(head->next, struct gfs2_log_buf, lb_list);
+ list_del(&lb->lb_list);
+ bh = lb->lb_bh;
+
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+ gfs2_io_error_bh(sdp, bh);
+ if (lb->lb_real) {
+ while (atomic_read(&bh->b_count) != 1) /* Grrrr... */
+ schedule();
+ free_buffer_head(bh);
+ } else
+ brelse(bh);
+ kfree(lb);
+ }
+
+ log_write_header(sdp, 0, 0);
+}
+
+/**
+ * gfs2_log_flush - flush incore transaction(s)
+ * @sdp: the filesystem
+ * @gl: The glock structure to flush. If NULL, flush the whole incore log
+ *
+ */
+
+void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl)
+{
+ struct gfs2_ail *ai;
+
+ down_write(&sdp->sd_log_flush_lock);
+
+ if (gl) {
+ gfs2_log_lock(sdp);
+ if (list_empty(&gl->gl_le.le_list)) {
+ gfs2_log_unlock(sdp);
+ up_write(&sdp->sd_log_flush_lock);
+ return;
+ }
+ gfs2_log_unlock(sdp);
+ }
+
+ ai = kzalloc(sizeof(struct gfs2_ail), GFP_NOFS | __GFP_NOFAIL);
+ INIT_LIST_HEAD(&ai->ai_ail1_list);
+ INIT_LIST_HEAD(&ai->ai_ail2_list);
+
+ gfs2_assert_withdraw(sdp, sdp->sd_log_num_buf == sdp->sd_log_commited_buf);
+ gfs2_assert_withdraw(sdp,
+ sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
+
+ sdp->sd_log_flush_head = sdp->sd_log_head;
+ sdp->sd_log_flush_wrapped = 0;
+ ai->ai_first = sdp->sd_log_flush_head;
+
+ lops_before_commit(sdp);
+ if (!list_empty(&sdp->sd_log_flush_list))
+ log_flush_commit(sdp);
+ else if (sdp->sd_log_tail != current_tail(sdp) && !sdp->sd_log_idle)
+ log_write_header(sdp, 0, PULL);
+ lops_after_commit(sdp, ai);
+
+ gfs2_log_lock(sdp);
+ sdp->sd_log_head = sdp->sd_log_flush_head;
+ sdp->sd_log_blks_free -= sdp->sd_log_num_hdrs;
+ sdp->sd_log_blks_reserved = 0;
+ sdp->sd_log_commited_buf = 0;
+ sdp->sd_log_num_hdrs = 0;
+ sdp->sd_log_commited_revoke = 0;
+
+ if (!list_empty(&ai->ai_ail1_list)) {
+ list_add(&ai->ai_list, &sdp->sd_ail1_list);
+ ai = NULL;
+ }
+ gfs2_log_unlock(sdp);
+
+ sdp->sd_vfs->s_dirt = 0;
+ up_write(&sdp->sd_log_flush_lock);
+
+ kfree(ai);
+}
+
+static void log_refund(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+{
+ unsigned int reserved = 0;
+ unsigned int old;
+
+ gfs2_log_lock(sdp);
+
+ sdp->sd_log_commited_buf += tr->tr_num_buf_new - tr->tr_num_buf_rm;
+ gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_buf) >= 0);
+ sdp->sd_log_commited_revoke += tr->tr_num_revoke - tr->tr_num_revoke_rm;
+ gfs2_assert_withdraw(sdp, ((int)sdp->sd_log_commited_revoke) >= 0);
+
+ if (sdp->sd_log_commited_buf)
+ reserved += sdp->sd_log_commited_buf;
+ if (sdp->sd_log_commited_revoke)
+ reserved += gfs2_struct2blk(sdp, sdp->sd_log_commited_revoke,
+ sizeof(u64));
+ if (reserved)
+ reserved++;
+
+ old = sdp->sd_log_blks_free;
+ sdp->sd_log_blks_free += tr->tr_reserved -
+ (reserved - sdp->sd_log_blks_reserved);
+
+ gfs2_assert_withdraw(sdp, sdp->sd_log_blks_free >= old);
+ gfs2_assert_withdraw(sdp,
+ sdp->sd_log_blks_free <= sdp->sd_jdesc->jd_blocks +
+ sdp->sd_log_num_hdrs);
+
+ sdp->sd_log_blks_reserved = reserved;
+
+ gfs2_log_unlock(sdp);
+}
+
+/**
+ * gfs2_log_commit - Commit a transaction to the log
+ * @sdp: the filesystem
+ * @tr: the transaction
+ *
+ * Returns: errno
+ */
+
+void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+{
+ log_refund(sdp, tr);
+ lops_incore_commit(sdp, tr);
+
+ sdp->sd_vfs->s_dirt = 1;
+ up_read(&sdp->sd_log_flush_lock);
+
+ gfs2_log_lock(sdp);
+ if (sdp->sd_log_num_buf > gfs2_tune_get(sdp, gt_incore_log_blocks)) {
+ gfs2_log_unlock(sdp);
+ gfs2_log_flush(sdp, NULL);
+ } else {
+ gfs2_log_unlock(sdp);
+ }
+}
+
+/**
+ * gfs2_log_shutdown - write a shutdown header into a journal
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_log_shutdown(struct gfs2_sbd *sdp)
+{
+ down_write(&sdp->sd_log_flush_lock);
+
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_blks_reserved);
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_gl);
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_buf);
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_jdata);
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_rg);
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_databuf);
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_hdrs);
+ gfs2_assert_withdraw(sdp, list_empty(&sdp->sd_ail1_list));
+
+ sdp->sd_log_flush_head = sdp->sd_log_head;
+ sdp->sd_log_flush_wrapped = 0;
+
+ log_write_header(sdp, GFS2_LOG_HEAD_UNMOUNT, 0);
+
+ gfs2_assert_warn(sdp, sdp->sd_log_blks_free == sdp->sd_jdesc->jd_blocks);
+ gfs2_assert_warn(sdp, sdp->sd_log_head == sdp->sd_log_tail);
+ gfs2_assert_warn(sdp, list_empty(&sdp->sd_ail2_list));
+
+ sdp->sd_log_head = sdp->sd_log_flush_head;
+ sdp->sd_log_tail = sdp->sd_log_head;
+
+ up_write(&sdp->sd_log_flush_lock);
+}
+
diff --git a/fs/gfs2/log.h b/fs/gfs2/log.h
new file mode 100644
index 000000000000..7f5737d55612
--- /dev/null
+++ b/fs/gfs2/log.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LOG_DOT_H__
+#define __LOG_DOT_H__
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include "incore.h"
+
+/**
+ * gfs2_log_lock - acquire the right to mess with the log manager
+ * @sdp: the filesystem
+ *
+ */
+
+static inline void gfs2_log_lock(struct gfs2_sbd *sdp)
+{
+ spin_lock(&sdp->sd_log_lock);
+}
+
+/**
+ * gfs2_log_unlock - release the right to mess with the log manager
+ * @sdp: the filesystem
+ *
+ */
+
+static inline void gfs2_log_unlock(struct gfs2_sbd *sdp)
+{
+ spin_unlock(&sdp->sd_log_lock);
+}
+
+static inline void gfs2_log_pointers_init(struct gfs2_sbd *sdp,
+ unsigned int value)
+{
+ if (++value == sdp->sd_jdesc->jd_blocks) {
+ value = 0;
+ }
+ sdp->sd_log_head = sdp->sd_log_tail = value;
+}
+
+unsigned int gfs2_struct2blk(struct gfs2_sbd *sdp, unsigned int nstruct,
+ unsigned int ssize);
+
+void gfs2_ail1_start(struct gfs2_sbd *sdp, int flags);
+int gfs2_ail1_empty(struct gfs2_sbd *sdp, int flags);
+
+int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks);
+void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks);
+
+struct buffer_head *gfs2_log_get_buf(struct gfs2_sbd *sdp);
+struct buffer_head *gfs2_log_fake_buf(struct gfs2_sbd *sdp,
+ struct buffer_head *real);
+void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl);
+void gfs2_log_commit(struct gfs2_sbd *sdp, struct gfs2_trans *trans);
+
+void gfs2_log_shutdown(struct gfs2_sbd *sdp);
+
+#endif /* __LOG_DOT_H__ */
diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c
new file mode 100644
index 000000000000..ab6d1115f95d
--- /dev/null
+++ b/fs/gfs2/lops.c
@@ -0,0 +1,809 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+static void glock_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+ struct gfs2_glock *gl;
+ struct gfs2_trans *tr = current->journal_info;
+
+ tr->tr_touched = 1;
+
+ if (!list_empty(&le->le_list))
+ return;
+
+ gl = container_of(le, struct gfs2_glock, gl_le);
+ if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl)))
+ return;
+ gfs2_glock_hold(gl);
+ set_bit(GLF_DIRTY, &gl->gl_flags);
+
+ gfs2_log_lock(sdp);
+ sdp->sd_log_num_gl++;
+ list_add(&le->le_list, &sdp->sd_log_le_gl);
+ gfs2_log_unlock(sdp);
+}
+
+static void glock_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+ struct list_head *head = &sdp->sd_log_le_gl;
+ struct gfs2_glock *gl;
+
+ while (!list_empty(head)) {
+ gl = list_entry(head->next, struct gfs2_glock, gl_le.le_list);
+ list_del_init(&gl->gl_le.le_list);
+ sdp->sd_log_num_gl--;
+
+ gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(gl));
+ gfs2_glock_put(gl);
+ }
+ gfs2_assert_warn(sdp, !sdp->sd_log_num_gl);
+}
+
+static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+ struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
+ struct gfs2_trans *tr;
+
+ if (!list_empty(&bd->bd_list_tr))
+ return;
+
+ tr = current->journal_info;
+ tr->tr_touched = 1;
+ tr->tr_num_buf++;
+ list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+
+ if (!list_empty(&le->le_list))
+ return;
+
+ gfs2_trans_add_gl(bd->bd_gl);
+
+ gfs2_meta_check(sdp, bd->bd_bh);
+ gfs2_pin(sdp, bd->bd_bh);
+
+ gfs2_log_lock(sdp);
+ sdp->sd_log_num_buf++;
+ list_add(&le->le_list, &sdp->sd_log_le_buf);
+ gfs2_log_unlock(sdp);
+
+ tr->tr_num_buf_new++;
+}
+
+static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
+{
+ struct list_head *head = &tr->tr_list_buf;
+ struct gfs2_bufdata *bd;
+
+ while (!list_empty(head)) {
+ bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
+ list_del_init(&bd->bd_list_tr);
+ tr->tr_num_buf--;
+ }
+ gfs2_assert_warn(sdp, !tr->tr_num_buf);
+}
+
+static void buf_lo_before_commit(struct gfs2_sbd *sdp)
+{
+ struct buffer_head *bh;
+ struct gfs2_log_descriptor *ld;
+ struct gfs2_bufdata *bd1 = NULL, *bd2;
+ unsigned int total = sdp->sd_log_num_buf;
+ unsigned int offset = sizeof(struct gfs2_log_descriptor);
+ unsigned int limit;
+ unsigned int num;
+ unsigned n;
+ __be64 *ptr;
+
+ offset += sizeof(__be64) - 1;
+ offset &= ~(sizeof(__be64) - 1);
+ limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64);
+ /* for 4k blocks, limit = 503 */
+
+ bd1 = bd2 = list_prepare_entry(bd1, &sdp->sd_log_le_buf, bd_le.le_list);
+ while(total) {
+ num = total;
+ if (total > limit)
+ num = limit;
+ bh = gfs2_log_get_buf(sdp);
+ sdp->sd_log_num_hdrs++;
+ ld = (struct gfs2_log_descriptor *)bh->b_data;
+ ptr = (__be64 *)(bh->b_data + offset);
+ ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+ ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
+ ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
+ ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_METADATA);
+ ld->ld_length = cpu_to_be32(num + 1);
+ ld->ld_data1 = cpu_to_be32(num);
+ ld->ld_data2 = cpu_to_be32(0);
+ memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+
+ n = 0;
+ list_for_each_entry_continue(bd1, &sdp->sd_log_le_buf,
+ bd_le.le_list) {
+ *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr);
+ if (++n >= num)
+ break;
+ }
+
+ set_buffer_dirty(bh);
+ ll_rw_block(WRITE, 1, &bh);
+
+ n = 0;
+ list_for_each_entry_continue(bd2, &sdp->sd_log_le_buf,
+ bd_le.le_list) {
+ bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
+ set_buffer_dirty(bh);
+ ll_rw_block(WRITE, 1, &bh);
+ if (++n >= num)
+ break;
+ }
+
+ total -= num;
+ }
+}
+
+static void buf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+ struct list_head *head = &sdp->sd_log_le_buf;
+ struct gfs2_bufdata *bd;
+
+ while (!list_empty(head)) {
+ bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
+ list_del_init(&bd->bd_le.le_list);
+ sdp->sd_log_num_buf--;
+
+ gfs2_unpin(sdp, bd->bd_bh, ai);
+ }
+ gfs2_assert_warn(sdp, !sdp->sd_log_num_buf);
+}
+
+static void buf_lo_before_scan(struct gfs2_jdesc *jd,
+ struct gfs2_log_header *head, int pass)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+ if (pass != 0)
+ return;
+
+ sdp->sd_found_blocks = 0;
+ sdp->sd_replayed_blocks = 0;
+}
+
+static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+ struct gfs2_log_descriptor *ld, __be64 *ptr,
+ int pass)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ struct gfs2_glock *gl = ip->i_gl;
+ unsigned int blks = be32_to_cpu(ld->ld_data1);
+ struct buffer_head *bh_log, *bh_ip;
+ u64 blkno;
+ int error = 0;
+
+ if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_METADATA)
+ return 0;
+
+ gfs2_replay_incr_blk(sdp, &start);
+
+ for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
+ blkno = be64_to_cpu(*ptr++);
+
+ sdp->sd_found_blocks++;
+
+ if (gfs2_revoke_check(sdp, blkno, start))
+ continue;
+
+ error = gfs2_replay_read_block(jd, start, &bh_log);
+ if (error)
+ return error;
+
+ bh_ip = gfs2_meta_new(gl, blkno);
+ memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
+
+ if (gfs2_meta_check(sdp, bh_ip))
+ error = -EIO;
+ else
+ mark_buffer_dirty(bh_ip);
+
+ brelse(bh_log);
+ brelse(bh_ip);
+
+ if (error)
+ break;
+
+ sdp->sd_replayed_blocks++;
+ }
+
+ return error;
+}
+
+static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+ if (error) {
+ gfs2_meta_sync(ip->i_gl);
+ return;
+ }
+ if (pass != 1)
+ return;
+
+ gfs2_meta_sync(ip->i_gl);
+
+ fs_info(sdp, "jid=%u: Replayed %u of %u blocks\n",
+ jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
+}
+
+static void revoke_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+ struct gfs2_trans *tr;
+
+ tr = current->journal_info;
+ tr->tr_touched = 1;
+ tr->tr_num_revoke++;
+
+ gfs2_log_lock(sdp);
+ sdp->sd_log_num_revoke++;
+ list_add(&le->le_list, &sdp->sd_log_le_revoke);
+ gfs2_log_unlock(sdp);
+}
+
+static void revoke_lo_before_commit(struct gfs2_sbd *sdp)
+{
+ struct gfs2_log_descriptor *ld;
+ struct gfs2_meta_header *mh;
+ struct buffer_head *bh;
+ unsigned int offset;
+ struct list_head *head = &sdp->sd_log_le_revoke;
+ struct gfs2_revoke *rv;
+
+ if (!sdp->sd_log_num_revoke)
+ return;
+
+ bh = gfs2_log_get_buf(sdp);
+ ld = (struct gfs2_log_descriptor *)bh->b_data;
+ ld->ld_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+ ld->ld_header.mh_type = cpu_to_be32(GFS2_METATYPE_LD);
+ ld->ld_header.mh_format = cpu_to_be32(GFS2_FORMAT_LD);
+ ld->ld_type = cpu_to_be32(GFS2_LOG_DESC_REVOKE);
+ ld->ld_length = cpu_to_be32(gfs2_struct2blk(sdp, sdp->sd_log_num_revoke,
+ sizeof(u64)));
+ ld->ld_data1 = cpu_to_be32(sdp->sd_log_num_revoke);
+ ld->ld_data2 = cpu_to_be32(0);
+ memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+ offset = sizeof(struct gfs2_log_descriptor);
+
+ while (!list_empty(head)) {
+ rv = list_entry(head->next, struct gfs2_revoke, rv_le.le_list);
+ list_del_init(&rv->rv_le.le_list);
+ sdp->sd_log_num_revoke--;
+
+ if (offset + sizeof(u64) > sdp->sd_sb.sb_bsize) {
+ set_buffer_dirty(bh);
+ ll_rw_block(WRITE, 1, &bh);
+
+ bh = gfs2_log_get_buf(sdp);
+ mh = (struct gfs2_meta_header *)bh->b_data;
+ mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
+ mh->mh_type = cpu_to_be32(GFS2_METATYPE_LB);
+ mh->mh_format = cpu_to_be32(GFS2_FORMAT_LB);
+ offset = sizeof(struct gfs2_meta_header);
+ }
+
+ *(__be64 *)(bh->b_data + offset) = cpu_to_be64(rv->rv_blkno);
+ kfree(rv);
+
+ offset += sizeof(u64);
+ }
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
+
+ set_buffer_dirty(bh);
+ ll_rw_block(WRITE, 1, &bh);
+}
+
+static void revoke_lo_before_scan(struct gfs2_jdesc *jd,
+ struct gfs2_log_header *head, int pass)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+ if (pass != 0)
+ return;
+
+ sdp->sd_found_revokes = 0;
+ sdp->sd_replay_tail = head->lh_tail;
+}
+
+static int revoke_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+ struct gfs2_log_descriptor *ld, __be64 *ptr,
+ int pass)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ unsigned int blks = be32_to_cpu(ld->ld_length);
+ unsigned int revokes = be32_to_cpu(ld->ld_data1);
+ struct buffer_head *bh;
+ unsigned int offset;
+ u64 blkno;
+ int first = 1;
+ int error;
+
+ if (pass != 0 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_REVOKE)
+ return 0;
+
+ offset = sizeof(struct gfs2_log_descriptor);
+
+ for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
+ error = gfs2_replay_read_block(jd, start, &bh);
+ if (error)
+ return error;
+
+ if (!first)
+ gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LB);
+
+ while (offset + sizeof(u64) <= sdp->sd_sb.sb_bsize) {
+ blkno = be64_to_cpu(*(__be64 *)(bh->b_data + offset));
+
+ error = gfs2_revoke_add(sdp, blkno, start);
+ if (error < 0)
+ return error;
+ else if (error)
+ sdp->sd_found_revokes++;
+
+ if (!--revokes)
+ break;
+ offset += sizeof(u64);
+ }
+
+ brelse(bh);
+ offset = sizeof(struct gfs2_meta_header);
+ first = 0;
+ }
+
+ return 0;
+}
+
+static void revoke_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+ if (error) {
+ gfs2_revoke_clean(sdp);
+ return;
+ }
+ if (pass != 1)
+ return;
+
+ fs_info(sdp, "jid=%u: Found %u revoke tags\n",
+ jd->jd_jid, sdp->sd_found_revokes);
+
+ gfs2_revoke_clean(sdp);
+}
+
+static void rg_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_trans *tr = current->journal_info;
+
+ tr->tr_touched = 1;
+
+ if (!list_empty(&le->le_list))
+ return;
+
+ rgd = container_of(le, struct gfs2_rgrpd, rd_le);
+ gfs2_rgrp_bh_hold(rgd);
+
+ gfs2_log_lock(sdp);
+ sdp->sd_log_num_rg++;
+ list_add(&le->le_list, &sdp->sd_log_le_rg);
+ gfs2_log_unlock(sdp);
+}
+
+static void rg_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+ struct list_head *head = &sdp->sd_log_le_rg;
+ struct gfs2_rgrpd *rgd;
+
+ while (!list_empty(head)) {
+ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_le.le_list);
+ list_del_init(&rgd->rd_le.le_list);
+ sdp->sd_log_num_rg--;
+
+ gfs2_rgrp_repolish_clones(rgd);
+ gfs2_rgrp_bh_put(rgd);
+ }
+ gfs2_assert_warn(sdp, !sdp->sd_log_num_rg);
+}
+
+/**
+ * databuf_lo_add - Add a databuf to the transaction.
+ *
+ * This is used in two distinct cases:
+ * i) In ordered write mode
+ * We put the data buffer on a list so that we can ensure that its
+ * synced to disk at the right time
+ * ii) In journaled data mode
+ * We need to journal the data block in the same way as metadata in
+ * the functions above. The difference is that here we have a tag
+ * which is two __be64's being the block number (as per meta data)
+ * and a flag which says whether the data block needs escaping or
+ * not. This means we need a new log entry for each 251 or so data
+ * blocks, which isn't an enormous overhead but twice as much as
+ * for normal metadata blocks.
+ */
+static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+ struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
+ struct gfs2_trans *tr = current->journal_info;
+ struct address_space *mapping = bd->bd_bh->b_page->mapping;
+ struct gfs2_inode *ip = GFS2_I(mapping->host);
+
+ tr->tr_touched = 1;
+ if (list_empty(&bd->bd_list_tr) &&
+ (ip->i_di.di_flags & GFS2_DIF_JDATA)) {
+ tr->tr_num_buf++;
+ list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+ gfs2_pin(sdp, bd->bd_bh);
+ tr->tr_num_buf_new++;
+ }
+ gfs2_trans_add_gl(bd->bd_gl);
+ gfs2_log_lock(sdp);
+ if (list_empty(&le->le_list)) {
+ if (ip->i_di.di_flags & GFS2_DIF_JDATA)
+ sdp->sd_log_num_jdata++;
+ sdp->sd_log_num_databuf++;
+ list_add(&le->le_list, &sdp->sd_log_le_databuf);
+ }
+ gfs2_log_unlock(sdp);
+}
+
+static int gfs2_check_magic(struct buffer_head *bh)
+{
+ struct page *page = bh->b_page;
+ void *kaddr;
+ __be32 *ptr;
+ int rv = 0;
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ ptr = kaddr + bh_offset(bh);
+ if (*ptr == cpu_to_be32(GFS2_MAGIC))
+ rv = 1;
+ kunmap_atomic(kaddr, KM_USER0);
+
+ return rv;
+}
+
+/**
+ * databuf_lo_before_commit - Scan the data buffers, writing as we go
+ *
+ * Here we scan through the lists of buffers and make the assumption
+ * that any buffer thats been pinned is being journaled, and that
+ * any unpinned buffer is an ordered write data buffer and therefore
+ * will be written back rather than journaled.
+ */
+static void databuf_lo_before_commit(struct gfs2_sbd *sdp)
+{
+ LIST_HEAD(started);
+ struct gfs2_bufdata *bd1 = NULL, *bd2, *bdt;
+ struct buffer_head *bh = NULL;
+ unsigned int offset = sizeof(struct gfs2_log_descriptor);
+ struct gfs2_log_descriptor *ld;
+ unsigned int limit;
+ unsigned int total_dbuf = sdp->sd_log_num_databuf;
+ unsigned int total_jdata = sdp->sd_log_num_jdata;
+ unsigned int num, n;
+ __be64 *ptr = NULL;
+
+ offset += 2*sizeof(__be64) - 1;
+ offset &= ~(2*sizeof(__be64) - 1);
+ limit = (sdp->sd_sb.sb_bsize - offset)/sizeof(__be64);
+
+ /*
+ * Start writing ordered buffers, write journaled buffers
+ * into the log along with a header
+ */
+ gfs2_log_lock(sdp);
+ bd2 = bd1 = list_prepare_entry(bd1, &sdp->sd_log_le_databuf,
+ bd_le.le_list);
+ while(total_dbuf) {
+ num = total_jdata;
+ if (num > limit)
+ num = limit;
+ n = 0;
+ list_for_each_entry_safe_continue(bd1, bdt,
+ &sdp->sd_log_le_databuf,
+ bd_le.le_list) {
+ /* An ordered write buffer */
+ if (bd1->bd_bh && !buffer_pinned(bd1->bd_bh)) {
+ list_move(&bd1->bd_le.le_list, &started);
+ if (bd1 == bd2) {
+ bd2 = NULL;
+ bd2 = list_prepare_entry(bd2,
+ &sdp->sd_log_le_databuf,
+ bd_le.le_list);
+ }
+ total_dbuf--;
+ if (bd1->bd_bh) {
+ get_bh(bd1->bd_bh);
+ if (buffer_dirty(bd1->bd_bh)) {
+ gfs2_log_unlock(sdp);
+ wait_on_buffer(bd1->bd_bh);
+ ll_rw_block(WRITE, 1,
+ &bd1->bd_bh);
+ gfs2_log_lock(sdp);
+ }
+ brelse(bd1->bd_bh);
+ continue;
+ }
+ continue;
+ } else if (bd1->bd_bh) { /* A journaled buffer */
+ int magic;
+ gfs2_log_unlock(sdp);
+ if (!bh) {
+ bh = gfs2_log_get_buf(sdp);
+ sdp->sd_log_num_hdrs++;
+ ld = (struct gfs2_log_descriptor *)
+ bh->b_data;
+ ptr = (__be64 *)(bh->b_data + offset);
+ ld->ld_header.mh_magic =
+ cpu_to_be32(GFS2_MAGIC);
+ ld->ld_header.mh_type =
+ cpu_to_be32(GFS2_METATYPE_LD);
+ ld->ld_header.mh_format =
+ cpu_to_be32(GFS2_FORMAT_LD);
+ ld->ld_type =
+ cpu_to_be32(GFS2_LOG_DESC_JDATA);
+ ld->ld_length = cpu_to_be32(num + 1);
+ ld->ld_data1 = cpu_to_be32(num);
+ ld->ld_data2 = cpu_to_be32(0);
+ memset(ld->ld_reserved, 0, sizeof(ld->ld_reserved));
+ }
+ magic = gfs2_check_magic(bd1->bd_bh);
+ *ptr++ = cpu_to_be64(bd1->bd_bh->b_blocknr);
+ *ptr++ = cpu_to_be64((__u64)magic);
+ clear_buffer_escaped(bd1->bd_bh);
+ if (unlikely(magic != 0))
+ set_buffer_escaped(bd1->bd_bh);
+ gfs2_log_lock(sdp);
+ if (n++ > num)
+ break;
+ } else if (!bd1->bd_bh) {
+ total_dbuf--;
+ sdp->sd_log_num_databuf--;
+ list_del_init(&bd1->bd_le.le_list);
+ if (bd1 == bd2) {
+ bd2 = NULL;
+ bd2 = list_prepare_entry(bd2,
+ &sdp->sd_log_le_databuf,
+ bd_le.le_list);
+ }
+ kmem_cache_free(gfs2_bufdata_cachep, bd1);
+ }
+ }
+ gfs2_log_unlock(sdp);
+ if (bh) {
+ set_buffer_dirty(bh);
+ ll_rw_block(WRITE, 1, &bh);
+ bh = NULL;
+ }
+ n = 0;
+ gfs2_log_lock(sdp);
+ list_for_each_entry_continue(bd2, &sdp->sd_log_le_databuf,
+ bd_le.le_list) {
+ if (!bd2->bd_bh)
+ continue;
+ /* copy buffer if it needs escaping */
+ gfs2_log_unlock(sdp);
+ if (unlikely(buffer_escaped(bd2->bd_bh))) {
+ void *kaddr;
+ struct page *page = bd2->bd_bh->b_page;
+ bh = gfs2_log_get_buf(sdp);
+ kaddr = kmap_atomic(page, KM_USER0);
+ memcpy(bh->b_data,
+ kaddr + bh_offset(bd2->bd_bh),
+ sdp->sd_sb.sb_bsize);
+ kunmap_atomic(kaddr, KM_USER0);
+ *(__be32 *)bh->b_data = 0;
+ } else {
+ bh = gfs2_log_fake_buf(sdp, bd2->bd_bh);
+ }
+ set_buffer_dirty(bh);
+ ll_rw_block(WRITE, 1, &bh);
+ gfs2_log_lock(sdp);
+ if (++n >= num)
+ break;
+ }
+ bh = NULL;
+ total_dbuf -= num;
+ total_jdata -= num;
+ }
+ gfs2_log_unlock(sdp);
+
+ /* Wait on all ordered buffers */
+ while (!list_empty(&started)) {
+ gfs2_log_lock(sdp);
+ bd1 = list_entry(started.next, struct gfs2_bufdata,
+ bd_le.le_list);
+ list_del_init(&bd1->bd_le.le_list);
+ sdp->sd_log_num_databuf--;
+ bh = bd1->bd_bh;
+ if (bh) {
+ bh->b_private = NULL;
+ get_bh(bh);
+ gfs2_log_unlock(sdp);
+ wait_on_buffer(bh);
+ brelse(bh);
+ } else
+ gfs2_log_unlock(sdp);
+
+ kmem_cache_free(gfs2_bufdata_cachep, bd1);
+ }
+
+ /* We've removed all the ordered write bufs here, so only jdata left */
+ gfs2_assert_warn(sdp, sdp->sd_log_num_databuf == sdp->sd_log_num_jdata);
+}
+
+static int databuf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+ struct gfs2_log_descriptor *ld,
+ __be64 *ptr, int pass)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ struct gfs2_glock *gl = ip->i_gl;
+ unsigned int blks = be32_to_cpu(ld->ld_data1);
+ struct buffer_head *bh_log, *bh_ip;
+ u64 blkno;
+ u64 esc;
+ int error = 0;
+
+ if (pass != 1 || be32_to_cpu(ld->ld_type) != GFS2_LOG_DESC_JDATA)
+ return 0;
+
+ gfs2_replay_incr_blk(sdp, &start);
+ for (; blks; gfs2_replay_incr_blk(sdp, &start), blks--) {
+ blkno = be64_to_cpu(*ptr++);
+ esc = be64_to_cpu(*ptr++);
+
+ sdp->sd_found_blocks++;
+
+ if (gfs2_revoke_check(sdp, blkno, start))
+ continue;
+
+ error = gfs2_replay_read_block(jd, start, &bh_log);
+ if (error)
+ return error;
+
+ bh_ip = gfs2_meta_new(gl, blkno);
+ memcpy(bh_ip->b_data, bh_log->b_data, bh_log->b_size);
+
+ /* Unescape */
+ if (esc) {
+ __be32 *eptr = (__be32 *)bh_ip->b_data;
+ *eptr = cpu_to_be32(GFS2_MAGIC);
+ }
+ mark_buffer_dirty(bh_ip);
+
+ brelse(bh_log);
+ brelse(bh_ip);
+ if (error)
+ break;
+
+ sdp->sd_replayed_blocks++;
+ }
+
+ return error;
+}
+
+/* FIXME: sort out accounting for log blocks etc. */
+
+static void databuf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+
+ if (error) {
+ gfs2_meta_sync(ip->i_gl);
+ return;
+ }
+ if (pass != 1)
+ return;
+
+ /* data sync? */
+ gfs2_meta_sync(ip->i_gl);
+
+ fs_info(sdp, "jid=%u: Replayed %u of %u data blocks\n",
+ jd->jd_jid, sdp->sd_replayed_blocks, sdp->sd_found_blocks);
+}
+
+static void databuf_lo_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+ struct list_head *head = &sdp->sd_log_le_databuf;
+ struct gfs2_bufdata *bd;
+
+ while (!list_empty(head)) {
+ bd = list_entry(head->next, struct gfs2_bufdata, bd_le.le_list);
+ list_del_init(&bd->bd_le.le_list);
+ sdp->sd_log_num_databuf--;
+ sdp->sd_log_num_jdata--;
+ gfs2_unpin(sdp, bd->bd_bh, ai);
+ }
+ gfs2_assert_warn(sdp, !sdp->sd_log_num_databuf);
+ gfs2_assert_warn(sdp, !sdp->sd_log_num_jdata);
+}
+
+
+const struct gfs2_log_operations gfs2_glock_lops = {
+ .lo_add = glock_lo_add,
+ .lo_after_commit = glock_lo_after_commit,
+ .lo_name = "glock",
+};
+
+const struct gfs2_log_operations gfs2_buf_lops = {
+ .lo_add = buf_lo_add,
+ .lo_incore_commit = buf_lo_incore_commit,
+ .lo_before_commit = buf_lo_before_commit,
+ .lo_after_commit = buf_lo_after_commit,
+ .lo_before_scan = buf_lo_before_scan,
+ .lo_scan_elements = buf_lo_scan_elements,
+ .lo_after_scan = buf_lo_after_scan,
+ .lo_name = "buf",
+};
+
+const struct gfs2_log_operations gfs2_revoke_lops = {
+ .lo_add = revoke_lo_add,
+ .lo_before_commit = revoke_lo_before_commit,
+ .lo_before_scan = revoke_lo_before_scan,
+ .lo_scan_elements = revoke_lo_scan_elements,
+ .lo_after_scan = revoke_lo_after_scan,
+ .lo_name = "revoke",
+};
+
+const struct gfs2_log_operations gfs2_rg_lops = {
+ .lo_add = rg_lo_add,
+ .lo_after_commit = rg_lo_after_commit,
+ .lo_name = "rg",
+};
+
+const struct gfs2_log_operations gfs2_databuf_lops = {
+ .lo_add = databuf_lo_add,
+ .lo_incore_commit = buf_lo_incore_commit,
+ .lo_before_commit = databuf_lo_before_commit,
+ .lo_after_commit = databuf_lo_after_commit,
+ .lo_scan_elements = databuf_lo_scan_elements,
+ .lo_after_scan = databuf_lo_after_scan,
+ .lo_name = "databuf",
+};
+
+const struct gfs2_log_operations *gfs2_log_ops[] = {
+ &gfs2_glock_lops,
+ &gfs2_buf_lops,
+ &gfs2_revoke_lops,
+ &gfs2_rg_lops,
+ &gfs2_databuf_lops,
+ NULL,
+};
+
diff --git a/fs/gfs2/lops.h b/fs/gfs2/lops.h
new file mode 100644
index 000000000000..5839c05ae6be
--- /dev/null
+++ b/fs/gfs2/lops.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LOPS_DOT_H__
+#define __LOPS_DOT_H__
+
+#include <linux/list.h>
+#include "incore.h"
+
+extern const struct gfs2_log_operations gfs2_glock_lops;
+extern const struct gfs2_log_operations gfs2_buf_lops;
+extern const struct gfs2_log_operations gfs2_revoke_lops;
+extern const struct gfs2_log_operations gfs2_rg_lops;
+extern const struct gfs2_log_operations gfs2_databuf_lops;
+
+extern const struct gfs2_log_operations *gfs2_log_ops[];
+
+static inline void lops_init_le(struct gfs2_log_element *le,
+ const struct gfs2_log_operations *lops)
+{
+ INIT_LIST_HEAD(&le->le_list);
+ le->le_ops = lops;
+}
+
+static inline void lops_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
+{
+ if (le->le_ops->lo_add)
+ le->le_ops->lo_add(sdp, le);
+}
+
+static inline void lops_incore_commit(struct gfs2_sbd *sdp,
+ struct gfs2_trans *tr)
+{
+ int x;
+ for (x = 0; gfs2_log_ops[x]; x++)
+ if (gfs2_log_ops[x]->lo_incore_commit)
+ gfs2_log_ops[x]->lo_incore_commit(sdp, tr);
+}
+
+static inline void lops_before_commit(struct gfs2_sbd *sdp)
+{
+ int x;
+ for (x = 0; gfs2_log_ops[x]; x++)
+ if (gfs2_log_ops[x]->lo_before_commit)
+ gfs2_log_ops[x]->lo_before_commit(sdp);
+}
+
+static inline void lops_after_commit(struct gfs2_sbd *sdp, struct gfs2_ail *ai)
+{
+ int x;
+ for (x = 0; gfs2_log_ops[x]; x++)
+ if (gfs2_log_ops[x]->lo_after_commit)
+ gfs2_log_ops[x]->lo_after_commit(sdp, ai);
+}
+
+static inline void lops_before_scan(struct gfs2_jdesc *jd,
+ struct gfs2_log_header *head,
+ unsigned int pass)
+{
+ int x;
+ for (x = 0; gfs2_log_ops[x]; x++)
+ if (gfs2_log_ops[x]->lo_before_scan)
+ gfs2_log_ops[x]->lo_before_scan(jd, head, pass);
+}
+
+static inline int lops_scan_elements(struct gfs2_jdesc *jd, unsigned int start,
+ struct gfs2_log_descriptor *ld,
+ __be64 *ptr,
+ unsigned int pass)
+{
+ int x, error;
+ for (x = 0; gfs2_log_ops[x]; x++)
+ if (gfs2_log_ops[x]->lo_scan_elements) {
+ error = gfs2_log_ops[x]->lo_scan_elements(jd, start,
+ ld, ptr, pass);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
+static inline void lops_after_scan(struct gfs2_jdesc *jd, int error,
+ unsigned int pass)
+{
+ int x;
+ for (x = 0; gfs2_log_ops[x]; x++)
+ if (gfs2_log_ops[x]->lo_before_scan)
+ gfs2_log_ops[x]->lo_after_scan(jd, error, pass);
+}
+
+#endif /* __LOPS_DOT_H__ */
+
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
new file mode 100644
index 000000000000..21508a13bb78
--- /dev/null
+++ b/fs/gfs2/main.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/atomic.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "ops_fstype.h"
+#include "sys.h"
+#include "util.h"
+#include "glock.h"
+
+static void gfs2_init_inode_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+ struct gfs2_inode *ip = foo;
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ inode_init_once(&ip->i_inode);
+ spin_lock_init(&ip->i_spin);
+ init_rwsem(&ip->i_rw_mutex);
+ memset(ip->i_cache, 0, sizeof(ip->i_cache));
+ }
+}
+
+static void gfs2_init_glock_once(void *foo, kmem_cache_t *cachep, unsigned long flags)
+{
+ struct gfs2_glock *gl = foo;
+ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR) {
+ INIT_HLIST_NODE(&gl->gl_list);
+ spin_lock_init(&gl->gl_spin);
+ INIT_LIST_HEAD(&gl->gl_holders);
+ INIT_LIST_HEAD(&gl->gl_waiters1);
+ INIT_LIST_HEAD(&gl->gl_waiters2);
+ INIT_LIST_HEAD(&gl->gl_waiters3);
+ gl->gl_lvb = NULL;
+ atomic_set(&gl->gl_lvb_count, 0);
+ INIT_LIST_HEAD(&gl->gl_reclaim);
+ INIT_LIST_HEAD(&gl->gl_ail_list);
+ atomic_set(&gl->gl_ail_count, 0);
+ }
+}
+
+/**
+ * init_gfs2_fs - Register GFS2 as a filesystem
+ *
+ * Returns: 0 on success, error code on failure
+ */
+
+static int __init init_gfs2_fs(void)
+{
+ int error;
+
+ error = gfs2_sys_init();
+ if (error)
+ return error;
+
+ error = gfs2_glock_init();
+ if (error)
+ goto fail;
+
+ error = -ENOMEM;
+ gfs2_glock_cachep = kmem_cache_create("gfs2_glock",
+ sizeof(struct gfs2_glock),
+ 0, 0,
+ gfs2_init_glock_once, NULL);
+ if (!gfs2_glock_cachep)
+ goto fail;
+
+ gfs2_inode_cachep = kmem_cache_create("gfs2_inode",
+ sizeof(struct gfs2_inode),
+ 0, (SLAB_RECLAIM_ACCOUNT|
+ SLAB_PANIC|SLAB_MEM_SPREAD),
+ gfs2_init_inode_once, NULL);
+ if (!gfs2_inode_cachep)
+ goto fail;
+
+ gfs2_bufdata_cachep = kmem_cache_create("gfs2_bufdata",
+ sizeof(struct gfs2_bufdata),
+ 0, 0, NULL, NULL);
+ if (!gfs2_bufdata_cachep)
+ goto fail;
+
+ error = register_filesystem(&gfs2_fs_type);
+ if (error)
+ goto fail;
+
+ error = register_filesystem(&gfs2meta_fs_type);
+ if (error)
+ goto fail_unregister;
+
+ printk("GFS2 (built %s %s) installed\n", __DATE__, __TIME__);
+
+ return 0;
+
+fail_unregister:
+ unregister_filesystem(&gfs2_fs_type);
+fail:
+ if (gfs2_bufdata_cachep)
+ kmem_cache_destroy(gfs2_bufdata_cachep);
+
+ if (gfs2_inode_cachep)
+ kmem_cache_destroy(gfs2_inode_cachep);
+
+ if (gfs2_glock_cachep)
+ kmem_cache_destroy(gfs2_glock_cachep);
+
+ gfs2_sys_uninit();
+ return error;
+}
+
+/**
+ * exit_gfs2_fs - Unregister the file system
+ *
+ */
+
+static void __exit exit_gfs2_fs(void)
+{
+ unregister_filesystem(&gfs2_fs_type);
+ unregister_filesystem(&gfs2meta_fs_type);
+
+ kmem_cache_destroy(gfs2_bufdata_cachep);
+ kmem_cache_destroy(gfs2_inode_cachep);
+ kmem_cache_destroy(gfs2_glock_cachep);
+
+ gfs2_sys_uninit();
+}
+
+MODULE_DESCRIPTION("Global File System");
+MODULE_AUTHOR("Red Hat, Inc.");
+MODULE_LICENSE("GPL");
+
+module_init(init_gfs2_fs);
+module_exit(exit_gfs2_fs);
+
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c
new file mode 100644
index 000000000000..3912d6a4b1e6
--- /dev/null
+++ b/fs/gfs2/meta_io.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/writeback.h>
+#include <linux/swap.h>
+#include <linux/delay.h>
+#include <linux/bio.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+#include "ops_address.h"
+
+static int aspace_get_block(struct inode *inode, sector_t lblock,
+ struct buffer_head *bh_result, int create)
+{
+ gfs2_assert_warn(inode->i_sb->s_fs_info, 0);
+ return -EOPNOTSUPP;
+}
+
+static int gfs2_aspace_writepage(struct page *page,
+ struct writeback_control *wbc)
+{
+ return block_write_full_page(page, aspace_get_block, wbc);
+}
+
+static const struct address_space_operations aspace_aops = {
+ .writepage = gfs2_aspace_writepage,
+ .releasepage = gfs2_releasepage,
+};
+
+/**
+ * gfs2_aspace_get - Create and initialize a struct inode structure
+ * @sdp: the filesystem the aspace is in
+ *
+ * Right now a struct inode is just a struct inode. Maybe Linux
+ * will supply a more lightweight address space construct (that works)
+ * in the future.
+ *
+ * Make sure pages/buffers in this aspace aren't in high memory.
+ *
+ * Returns: the aspace
+ */
+
+struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp)
+{
+ struct inode *aspace;
+
+ aspace = new_inode(sdp->sd_vfs);
+ if (aspace) {
+ mapping_set_gfp_mask(aspace->i_mapping, GFP_NOFS);
+ aspace->i_mapping->a_ops = &aspace_aops;
+ aspace->i_size = ~0ULL;
+ aspace->i_private = NULL;
+ insert_inode_hash(aspace);
+ }
+ return aspace;
+}
+
+void gfs2_aspace_put(struct inode *aspace)
+{
+ remove_inode_hash(aspace);
+ iput(aspace);
+}
+
+/**
+ * gfs2_meta_inval - Invalidate all buffers associated with a glock
+ * @gl: the glock
+ *
+ */
+
+void gfs2_meta_inval(struct gfs2_glock *gl)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct inode *aspace = gl->gl_aspace;
+ struct address_space *mapping = gl->gl_aspace->i_mapping;
+
+ gfs2_assert_withdraw(sdp, !atomic_read(&gl->gl_ail_count));
+
+ atomic_inc(&aspace->i_writecount);
+ truncate_inode_pages(mapping, 0);
+ atomic_dec(&aspace->i_writecount);
+
+ gfs2_assert_withdraw(sdp, !mapping->nrpages);
+}
+
+/**
+ * gfs2_meta_sync - Sync all buffers associated with a glock
+ * @gl: The glock
+ *
+ */
+
+void gfs2_meta_sync(struct gfs2_glock *gl)
+{
+ struct address_space *mapping = gl->gl_aspace->i_mapping;
+ int error;
+
+ filemap_fdatawrite(mapping);
+ error = filemap_fdatawait(mapping);
+
+ if (error)
+ gfs2_io_error(gl->gl_sbd);
+}
+
+/**
+ * getbuf - Get a buffer with a given address space
+ * @sdp: the filesystem
+ * @aspace: the address space
+ * @blkno: the block number (filesystem scope)
+ * @create: 1 if the buffer should be created
+ *
+ * Returns: the buffer
+ */
+
+static struct buffer_head *getbuf(struct gfs2_sbd *sdp, struct inode *aspace,
+ u64 blkno, int create)
+{
+ struct page *page;
+ struct buffer_head *bh;
+ unsigned int shift;
+ unsigned long index;
+ unsigned int bufnum;
+
+ shift = PAGE_CACHE_SHIFT - sdp->sd_sb.sb_bsize_shift;
+ index = blkno >> shift; /* convert block to page */
+ bufnum = blkno - (index << shift); /* block buf index within page */
+
+ if (create) {
+ for (;;) {
+ page = grab_cache_page(aspace->i_mapping, index);
+ if (page)
+ break;
+ yield();
+ }
+ } else {
+ page = find_lock_page(aspace->i_mapping, index);
+ if (!page)
+ return NULL;
+ }
+
+ if (!page_has_buffers(page))
+ create_empty_buffers(page, sdp->sd_sb.sb_bsize, 0);
+
+ /* Locate header for our buffer within our page */
+ for (bh = page_buffers(page); bufnum--; bh = bh->b_this_page)
+ /* Do nothing */;
+ get_bh(bh);
+
+ if (!buffer_mapped(bh))
+ map_bh(bh, sdp->sd_vfs, blkno);
+
+ unlock_page(page);
+ mark_page_accessed(page);
+ page_cache_release(page);
+
+ return bh;
+}
+
+static void meta_prep_new(struct buffer_head *bh)
+{
+ struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
+
+ lock_buffer(bh);
+ clear_buffer_dirty(bh);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+
+ mh->mh_magic = cpu_to_be32(GFS2_MAGIC);
+}
+
+/**
+ * gfs2_meta_new - Get a block
+ * @gl: The glock associated with this block
+ * @blkno: The block number
+ *
+ * Returns: The buffer
+ */
+
+struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno)
+{
+ struct buffer_head *bh;
+ bh = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE);
+ meta_prep_new(bh);
+ return bh;
+}
+
+/**
+ * gfs2_meta_read - Read a block from disk
+ * @gl: The glock covering the block
+ * @blkno: The block number
+ * @flags: flags
+ * @bhp: the place where the buffer is returned (NULL on failure)
+ *
+ * Returns: errno
+ */
+
+int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags,
+ struct buffer_head **bhp)
+{
+ *bhp = getbuf(gl->gl_sbd, gl->gl_aspace, blkno, CREATE);
+ if (!buffer_uptodate(*bhp))
+ ll_rw_block(READ_META, 1, bhp);
+ if (flags & DIO_WAIT) {
+ int error = gfs2_meta_wait(gl->gl_sbd, *bhp);
+ if (error) {
+ brelse(*bhp);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_meta_wait - Reread a block from disk
+ * @sdp: the filesystem
+ * @bh: The block to wait for
+ *
+ * Returns: errno
+ */
+
+int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ return -EIO;
+
+ wait_on_buffer(bh);
+
+ if (!buffer_uptodate(bh)) {
+ struct gfs2_trans *tr = current->journal_info;
+ if (tr && tr->tr_touched)
+ gfs2_io_error_bh(sdp, bh);
+ return -EIO;
+ }
+ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * gfs2_attach_bufdata - attach a struct gfs2_bufdata structure to a buffer
+ * @gl: the glock the buffer belongs to
+ * @bh: The buffer to be attached to
+ * @meta: Flag to indicate whether its metadata or not
+ */
+
+void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
+ int meta)
+{
+ struct gfs2_bufdata *bd;
+
+ if (meta)
+ lock_page(bh->b_page);
+
+ if (bh->b_private) {
+ if (meta)
+ unlock_page(bh->b_page);
+ return;
+ }
+
+ bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL),
+ memset(bd, 0, sizeof(struct gfs2_bufdata));
+ bd->bd_bh = bh;
+ bd->bd_gl = gl;
+
+ INIT_LIST_HEAD(&bd->bd_list_tr);
+ if (meta)
+ lops_init_le(&bd->bd_le, &gfs2_buf_lops);
+ else
+ lops_init_le(&bd->bd_le, &gfs2_databuf_lops);
+ bh->b_private = bd;
+
+ if (meta)
+ unlock_page(bh->b_page);
+}
+
+/**
+ * gfs2_pin - Pin a buffer in memory
+ * @sdp: the filesystem the buffer belongs to
+ * @bh: The buffer to be pinned
+ *
+ */
+
+void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+ struct gfs2_bufdata *bd = bh->b_private;
+
+ gfs2_assert_withdraw(sdp, test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags));
+
+ if (test_set_buffer_pinned(bh))
+ gfs2_assert_withdraw(sdp, 0);
+
+ wait_on_buffer(bh);
+
+ /* If this buffer is in the AIL and it has already been written
+ to in-place disk block, remove it from the AIL. */
+
+ gfs2_log_lock(sdp);
+ if (bd->bd_ail && !buffer_in_io(bh))
+ list_move(&bd->bd_ail_st_list, &bd->bd_ail->ai_ail2_list);
+ gfs2_log_unlock(sdp);
+
+ clear_buffer_dirty(bh);
+ wait_on_buffer(bh);
+
+ if (!buffer_uptodate(bh))
+ gfs2_io_error_bh(sdp, bh);
+
+ get_bh(bh);
+}
+
+/**
+ * gfs2_unpin - Unpin a buffer
+ * @sdp: the filesystem the buffer belongs to
+ * @bh: The buffer to unpin
+ * @ai:
+ *
+ */
+
+void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ struct gfs2_ail *ai)
+{
+ struct gfs2_bufdata *bd = bh->b_private;
+
+ gfs2_assert_withdraw(sdp, buffer_uptodate(bh));
+
+ if (!buffer_pinned(bh))
+ gfs2_assert_withdraw(sdp, 0);
+
+ mark_buffer_dirty(bh);
+ clear_buffer_pinned(bh);
+
+ gfs2_log_lock(sdp);
+ if (bd->bd_ail) {
+ list_del(&bd->bd_ail_st_list);
+ brelse(bh);
+ } else {
+ struct gfs2_glock *gl = bd->bd_gl;
+ list_add(&bd->bd_ail_gl_list, &gl->gl_ail_list);
+ atomic_inc(&gl->gl_ail_count);
+ }
+ bd->bd_ail = ai;
+ list_add(&bd->bd_ail_st_list, &ai->ai_ail1_list);
+ gfs2_log_unlock(sdp);
+}
+
+/**
+ * gfs2_meta_wipe - make inode's buffers so they aren't dirty/pinned anymore
+ * @ip: the inode who owns the buffers
+ * @bstart: the first buffer in the run
+ * @blen: the number of buffers in the run
+ *
+ */
+
+void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct inode *aspace = ip->i_gl->gl_aspace;
+ struct buffer_head *bh;
+
+ while (blen) {
+ bh = getbuf(sdp, aspace, bstart, NO_CREATE);
+ if (bh) {
+ struct gfs2_bufdata *bd = bh->b_private;
+
+ if (test_clear_buffer_pinned(bh)) {
+ struct gfs2_trans *tr = current->journal_info;
+ gfs2_log_lock(sdp);
+ list_del_init(&bd->bd_le.le_list);
+ gfs2_assert_warn(sdp, sdp->sd_log_num_buf);
+ sdp->sd_log_num_buf--;
+ gfs2_log_unlock(sdp);
+ tr->tr_num_buf_rm++;
+ brelse(bh);
+ }
+ if (bd) {
+ gfs2_log_lock(sdp);
+ if (bd->bd_ail) {
+ u64 blkno = bh->b_blocknr;
+ bd->bd_ail = NULL;
+ list_del(&bd->bd_ail_st_list);
+ list_del(&bd->bd_ail_gl_list);
+ atomic_dec(&bd->bd_gl->gl_ail_count);
+ brelse(bh);
+ gfs2_log_unlock(sdp);
+ gfs2_trans_add_revoke(sdp, blkno);
+ } else
+ gfs2_log_unlock(sdp);
+ }
+
+ lock_buffer(bh);
+ clear_buffer_dirty(bh);
+ clear_buffer_uptodate(bh);
+ unlock_buffer(bh);
+
+ brelse(bh);
+ }
+
+ bstart++;
+ blen--;
+ }
+}
+
+/**
+ * gfs2_meta_cache_flush - get rid of any references on buffers for this inode
+ * @ip: The GFS2 inode
+ *
+ * This releases buffers that are in the most-recently-used array of
+ * blocks used for indirect block addressing for this inode.
+ */
+
+void gfs2_meta_cache_flush(struct gfs2_inode *ip)
+{
+ struct buffer_head **bh_slot;
+ unsigned int x;
+
+ spin_lock(&ip->i_spin);
+
+ for (x = 0; x < GFS2_MAX_META_HEIGHT; x++) {
+ bh_slot = &ip->i_cache[x];
+ if (!*bh_slot)
+ break;
+ brelse(*bh_slot);
+ *bh_slot = NULL;
+ }
+
+ spin_unlock(&ip->i_spin);
+}
+
+/**
+ * gfs2_meta_indirect_buffer - Get a metadata buffer
+ * @ip: The GFS2 inode
+ * @height: The level of this buf in the metadata (indir addr) tree (if any)
+ * @num: The block number (device relative) of the buffer
+ * @new: Non-zero if we may create a new buffer
+ * @bhp: the buffer is returned here
+ *
+ * Try to use the gfs2_inode's MRU metadata tree cache.
+ *
+ * Returns: errno
+ */
+
+int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
+ int new, struct buffer_head **bhp)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_glock *gl = ip->i_gl;
+ struct buffer_head *bh = NULL, **bh_slot = ip->i_cache + height;
+ int in_cache = 0;
+
+ spin_lock(&ip->i_spin);
+ if (*bh_slot && (*bh_slot)->b_blocknr == num) {
+ bh = *bh_slot;
+ get_bh(bh);
+ in_cache = 1;
+ }
+ spin_unlock(&ip->i_spin);
+
+ if (!bh)
+ bh = getbuf(gl->gl_sbd, gl->gl_aspace, num, CREATE);
+
+ if (!bh)
+ return -ENOBUFS;
+
+ if (new) {
+ if (gfs2_assert_warn(sdp, height))
+ goto err;
+ meta_prep_new(bh);
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ gfs2_metatype_set(bh, GFS2_METATYPE_IN, GFS2_FORMAT_IN);
+ gfs2_buffer_clear_tail(bh, sizeof(struct gfs2_meta_header));
+ } else {
+ u32 mtype = height ? GFS2_METATYPE_IN : GFS2_METATYPE_DI;
+ if (!buffer_uptodate(bh)) {
+ ll_rw_block(READ_META, 1, &bh);
+ if (gfs2_meta_wait(sdp, bh))
+ goto err;
+ }
+ if (gfs2_metatype_check(sdp, bh, mtype))
+ goto err;
+ }
+
+ if (!in_cache) {
+ spin_lock(&ip->i_spin);
+ if (*bh_slot)
+ brelse(*bh_slot);
+ *bh_slot = bh;
+ get_bh(bh);
+ spin_unlock(&ip->i_spin);
+ }
+
+ *bhp = bh;
+ return 0;
+err:
+ brelse(bh);
+ return -EIO;
+}
+
+/**
+ * gfs2_meta_ra - start readahead on an extent of a file
+ * @gl: the glock the blocks belong to
+ * @dblock: the starting disk block
+ * @extlen: the number of blocks in the extent
+ *
+ * returns: the first buffer in the extent
+ */
+
+struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct inode *aspace = gl->gl_aspace;
+ struct buffer_head *first_bh, *bh;
+ u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >>
+ sdp->sd_sb.sb_bsize_shift;
+
+ BUG_ON(!extlen);
+
+ if (max_ra < 1)
+ max_ra = 1;
+ if (extlen > max_ra)
+ extlen = max_ra;
+
+ first_bh = getbuf(sdp, aspace, dblock, CREATE);
+
+ if (buffer_uptodate(first_bh))
+ goto out;
+ if (!buffer_locked(first_bh))
+ ll_rw_block(READ_META, 1, &first_bh);
+
+ dblock++;
+ extlen--;
+
+ while (extlen) {
+ bh = getbuf(sdp, aspace, dblock, CREATE);
+
+ if (!buffer_uptodate(bh) && !buffer_locked(bh))
+ ll_rw_block(READA, 1, &bh);
+ brelse(bh);
+ dblock++;
+ extlen--;
+ if (!buffer_locked(first_bh) && buffer_uptodate(first_bh))
+ goto out;
+ }
+
+ wait_on_buffer(first_bh);
+out:
+ return first_bh;
+}
+
+/**
+ * gfs2_meta_syncfs - sync all the buffers in a filesystem
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_meta_syncfs(struct gfs2_sbd *sdp)
+{
+ gfs2_log_flush(sdp, NULL);
+ for (;;) {
+ gfs2_ail1_start(sdp, DIO_ALL);
+ if (gfs2_ail1_empty(sdp, DIO_ALL))
+ break;
+ msleep(10);
+ }
+}
+
diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h
new file mode 100644
index 000000000000..3ec939e20dff
--- /dev/null
+++ b/fs/gfs2/meta_io.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __DIO_DOT_H__
+#define __DIO_DOT_H__
+
+#include <linux/buffer_head.h>
+#include <linux/string.h>
+#include "incore.h"
+
+static inline void gfs2_buffer_clear(struct buffer_head *bh)
+{
+ memset(bh->b_data, 0, bh->b_size);
+}
+
+static inline void gfs2_buffer_clear_tail(struct buffer_head *bh, int head)
+{
+ BUG_ON(head > bh->b_size);
+ memset(bh->b_data + head, 0, bh->b_size - head);
+}
+
+static inline void gfs2_buffer_copy_tail(struct buffer_head *to_bh,
+ int to_head,
+ struct buffer_head *from_bh,
+ int from_head)
+{
+ BUG_ON(from_head < to_head);
+ memcpy(to_bh->b_data + to_head, from_bh->b_data + from_head,
+ from_bh->b_size - from_head);
+ memset(to_bh->b_data + to_bh->b_size + to_head - from_head,
+ 0, from_head - to_head);
+}
+
+struct inode *gfs2_aspace_get(struct gfs2_sbd *sdp);
+void gfs2_aspace_put(struct inode *aspace);
+
+void gfs2_meta_inval(struct gfs2_glock *gl);
+void gfs2_meta_sync(struct gfs2_glock *gl);
+
+struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno);
+int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno,
+ int flags, struct buffer_head **bhp);
+int gfs2_meta_wait(struct gfs2_sbd *sdp, struct buffer_head *bh);
+
+void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh,
+ int meta);
+void gfs2_pin(struct gfs2_sbd *sdp, struct buffer_head *bh);
+void gfs2_unpin(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ struct gfs2_ail *ai);
+
+void gfs2_meta_wipe(struct gfs2_inode *ip, u64 bstart, u32 blen);
+
+void gfs2_meta_cache_flush(struct gfs2_inode *ip);
+int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num,
+ int new, struct buffer_head **bhp);
+
+static inline int gfs2_meta_inode_buffer(struct gfs2_inode *ip,
+ struct buffer_head **bhp)
+{
+ return gfs2_meta_indirect_buffer(ip, 0, ip->i_num.no_addr, 0, bhp);
+}
+
+struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen);
+void gfs2_meta_syncfs(struct gfs2_sbd *sdp);
+
+#define buffer_busy(bh) \
+((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock) | (1ul << BH_Pinned)))
+#define buffer_in_io(bh) \
+((bh)->b_state & ((1ul << BH_Dirty) | (1ul << BH_Lock)))
+
+#endif /* __DIO_DOT_H__ */
+
diff --git a/fs/gfs2/mount.c b/fs/gfs2/mount.c
new file mode 100644
index 000000000000..ef3092e29607
--- /dev/null
+++ b/fs/gfs2/mount.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "mount.h"
+#include "sys.h"
+#include "util.h"
+
+/**
+ * gfs2_mount_args - Parse mount options
+ * @sdp:
+ * @data:
+ *
+ * Return: errno
+ */
+
+int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
+{
+ struct gfs2_args *args = &sdp->sd_args;
+ char *data = data_arg;
+ char *options, *o, *v;
+ int error = 0;
+
+ if (!remount) {
+ /* If someone preloaded options, use those instead */
+ spin_lock(&gfs2_sys_margs_lock);
+ if (gfs2_sys_margs) {
+ data = gfs2_sys_margs;
+ gfs2_sys_margs = NULL;
+ }
+ spin_unlock(&gfs2_sys_margs_lock);
+
+ /* Set some defaults */
+ args->ar_num_glockd = GFS2_GLOCKD_DEFAULT;
+ args->ar_quota = GFS2_QUOTA_DEFAULT;
+ args->ar_data = GFS2_DATA_DEFAULT;
+ }
+
+ /* Split the options into tokens with the "," character and
+ process them */
+
+ for (options = data; (o = strsep(&options, ",")); ) {
+ if (!*o)
+ continue;
+
+ v = strchr(o, '=');
+ if (v)
+ *v++ = 0;
+
+ if (!strcmp(o, "lockproto")) {
+ if (!v)
+ goto need_value;
+ if (remount && strcmp(v, args->ar_lockproto))
+ goto cant_remount;
+ strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
+ args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
+ }
+
+ else if (!strcmp(o, "locktable")) {
+ if (!v)
+ goto need_value;
+ if (remount && strcmp(v, args->ar_locktable))
+ goto cant_remount;
+ strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
+ args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
+ }
+
+ else if (!strcmp(o, "hostdata")) {
+ if (!v)
+ goto need_value;
+ if (remount && strcmp(v, args->ar_hostdata))
+ goto cant_remount;
+ strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
+ args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
+ }
+
+ else if (!strcmp(o, "spectator")) {
+ if (remount && !args->ar_spectator)
+ goto cant_remount;
+ args->ar_spectator = 1;
+ sdp->sd_vfs->s_flags |= MS_RDONLY;
+ }
+
+ else if (!strcmp(o, "ignore_local_fs")) {
+ if (remount && !args->ar_ignore_local_fs)
+ goto cant_remount;
+ args->ar_ignore_local_fs = 1;
+ }
+
+ else if (!strcmp(o, "localflocks")) {
+ if (remount && !args->ar_localflocks)
+ goto cant_remount;
+ args->ar_localflocks = 1;
+ }
+
+ else if (!strcmp(o, "localcaching")) {
+ if (remount && !args->ar_localcaching)
+ goto cant_remount;
+ args->ar_localcaching = 1;
+ }
+
+ else if (!strcmp(o, "debug"))
+ args->ar_debug = 1;
+
+ else if (!strcmp(o, "nodebug"))
+ args->ar_debug = 0;
+
+ else if (!strcmp(o, "upgrade")) {
+ if (remount && !args->ar_upgrade)
+ goto cant_remount;
+ args->ar_upgrade = 1;
+ }
+
+ else if (!strcmp(o, "num_glockd")) {
+ unsigned int x;
+ if (!v)
+ goto need_value;
+ sscanf(v, "%u", &x);
+ if (remount && x != args->ar_num_glockd)
+ goto cant_remount;
+ if (!x || x > GFS2_GLOCKD_MAX) {
+ fs_info(sdp, "0 < num_glockd <= %u (not %u)\n",
+ GFS2_GLOCKD_MAX, x);
+ error = -EINVAL;
+ break;
+ }
+ args->ar_num_glockd = x;
+ }
+
+ else if (!strcmp(o, "acl")) {
+ args->ar_posix_acl = 1;
+ sdp->sd_vfs->s_flags |= MS_POSIXACL;
+ }
+
+ else if (!strcmp(o, "noacl")) {
+ args->ar_posix_acl = 0;
+ sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
+ }
+
+ else if (!strcmp(o, "quota")) {
+ if (!v)
+ goto need_value;
+ if (!strcmp(v, "off"))
+ args->ar_quota = GFS2_QUOTA_OFF;
+ else if (!strcmp(v, "account"))
+ args->ar_quota = GFS2_QUOTA_ACCOUNT;
+ else if (!strcmp(v, "on"))
+ args->ar_quota = GFS2_QUOTA_ON;
+ else {
+ fs_info(sdp, "invalid value for quota\n");
+ error = -EINVAL;
+ break;
+ }
+ }
+
+ else if (!strcmp(o, "suiddir"))
+ args->ar_suiddir = 1;
+
+ else if (!strcmp(o, "nosuiddir"))
+ args->ar_suiddir = 0;
+
+ else if (!strcmp(o, "data")) {
+ if (!v)
+ goto need_value;
+ if (!strcmp(v, "writeback"))
+ args->ar_data = GFS2_DATA_WRITEBACK;
+ else if (!strcmp(v, "ordered"))
+ args->ar_data = GFS2_DATA_ORDERED;
+ else {
+ fs_info(sdp, "invalid value for data\n");
+ error = -EINVAL;
+ break;
+ }
+ }
+
+ else {
+ fs_info(sdp, "unknown option: %s\n", o);
+ error = -EINVAL;
+ break;
+ }
+ }
+
+ if (error)
+ fs_info(sdp, "invalid mount option(s)\n");
+
+ if (data != data_arg)
+ kfree(data);
+
+ return error;
+
+need_value:
+ fs_info(sdp, "need value for option %s\n", o);
+ return -EINVAL;
+
+cant_remount:
+ fs_info(sdp, "can't remount with option %s\n", o);
+ return -EINVAL;
+}
+
diff --git a/fs/gfs2/mount.h b/fs/gfs2/mount.h
new file mode 100644
index 000000000000..401288acfdf3
--- /dev/null
+++ b/fs/gfs2/mount.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __MOUNT_DOT_H__
+#define __MOUNT_DOT_H__
+
+struct gfs2_sbd;
+
+int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount);
+
+#endif /* __MOUNT_DOT_H__ */
diff --git a/fs/gfs2/ondisk.c b/fs/gfs2/ondisk.c
new file mode 100644
index 000000000000..1025960b0e6e
--- /dev/null
+++ b/fs/gfs2/ondisk.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+
+#include "gfs2.h"
+#include <linux/gfs2_ondisk.h>
+
+#define pv(struct, member, fmt) printk(KERN_INFO " "#member" = "fmt"\n", \
+ struct->member);
+
+/*
+ * gfs2_xxx_in - read in an xxx struct
+ * first arg: the cpu-order structure
+ * buf: the disk-order buffer
+ *
+ * gfs2_xxx_out - write out an xxx struct
+ * first arg: the cpu-order structure
+ * buf: the disk-order buffer
+ *
+ * gfs2_xxx_print - print out an xxx struct
+ * first arg: the cpu-order structure
+ */
+
+void gfs2_inum_in(struct gfs2_inum *no, const void *buf)
+{
+ const struct gfs2_inum *str = buf;
+
+ no->no_formal_ino = be64_to_cpu(str->no_formal_ino);
+ no->no_addr = be64_to_cpu(str->no_addr);
+}
+
+void gfs2_inum_out(const struct gfs2_inum *no, void *buf)
+{
+ struct gfs2_inum *str = buf;
+
+ str->no_formal_ino = cpu_to_be64(no->no_formal_ino);
+ str->no_addr = cpu_to_be64(no->no_addr);
+}
+
+static void gfs2_inum_print(const struct gfs2_inum *no)
+{
+ printk(KERN_INFO " no_formal_ino = %llu\n", (unsigned long long)no->no_formal_ino);
+ printk(KERN_INFO " no_addr = %llu\n", (unsigned long long)no->no_addr);
+}
+
+static void gfs2_meta_header_in(struct gfs2_meta_header *mh, const void *buf)
+{
+ const struct gfs2_meta_header *str = buf;
+
+ mh->mh_magic = be32_to_cpu(str->mh_magic);
+ mh->mh_type = be32_to_cpu(str->mh_type);
+ mh->mh_format = be32_to_cpu(str->mh_format);
+}
+
+static void gfs2_meta_header_out(const struct gfs2_meta_header *mh, void *buf)
+{
+ struct gfs2_meta_header *str = buf;
+
+ str->mh_magic = cpu_to_be32(mh->mh_magic);
+ str->mh_type = cpu_to_be32(mh->mh_type);
+ str->mh_format = cpu_to_be32(mh->mh_format);
+}
+
+static void gfs2_meta_header_print(const struct gfs2_meta_header *mh)
+{
+ pv(mh, mh_magic, "0x%.8X");
+ pv(mh, mh_type, "%u");
+ pv(mh, mh_format, "%u");
+}
+
+void gfs2_sb_in(struct gfs2_sb *sb, const void *buf)
+{
+ const struct gfs2_sb *str = buf;
+
+ gfs2_meta_header_in(&sb->sb_header, buf);
+
+ sb->sb_fs_format = be32_to_cpu(str->sb_fs_format);
+ sb->sb_multihost_format = be32_to_cpu(str->sb_multihost_format);
+ sb->sb_bsize = be32_to_cpu(str->sb_bsize);
+ sb->sb_bsize_shift = be32_to_cpu(str->sb_bsize_shift);
+
+ gfs2_inum_in(&sb->sb_master_dir, (char *)&str->sb_master_dir);
+ gfs2_inum_in(&sb->sb_root_dir, (char *)&str->sb_root_dir);
+
+ memcpy(sb->sb_lockproto, str->sb_lockproto, GFS2_LOCKNAME_LEN);
+ memcpy(sb->sb_locktable, str->sb_locktable, GFS2_LOCKNAME_LEN);
+}
+
+void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf)
+{
+ const struct gfs2_rindex *str = buf;
+
+ ri->ri_addr = be64_to_cpu(str->ri_addr);
+ ri->ri_length = be32_to_cpu(str->ri_length);
+ ri->ri_data0 = be64_to_cpu(str->ri_data0);
+ ri->ri_data = be32_to_cpu(str->ri_data);
+ ri->ri_bitbytes = be32_to_cpu(str->ri_bitbytes);
+
+}
+
+void gfs2_rindex_print(const struct gfs2_rindex *ri)
+{
+ printk(KERN_INFO " ri_addr = %llu\n", (unsigned long long)ri->ri_addr);
+ pv(ri, ri_length, "%u");
+
+ printk(KERN_INFO " ri_data0 = %llu\n", (unsigned long long)ri->ri_data0);
+ pv(ri, ri_data, "%u");
+
+ pv(ri, ri_bitbytes, "%u");
+}
+
+void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf)
+{
+ const struct gfs2_rgrp *str = buf;
+
+ gfs2_meta_header_in(&rg->rg_header, buf);
+ rg->rg_flags = be32_to_cpu(str->rg_flags);
+ rg->rg_free = be32_to_cpu(str->rg_free);
+ rg->rg_dinodes = be32_to_cpu(str->rg_dinodes);
+ rg->rg_igeneration = be64_to_cpu(str->rg_igeneration);
+}
+
+void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf)
+{
+ struct gfs2_rgrp *str = buf;
+
+ gfs2_meta_header_out(&rg->rg_header, buf);
+ str->rg_flags = cpu_to_be32(rg->rg_flags);
+ str->rg_free = cpu_to_be32(rg->rg_free);
+ str->rg_dinodes = cpu_to_be32(rg->rg_dinodes);
+ str->__pad = cpu_to_be32(0);
+ str->rg_igeneration = cpu_to_be64(rg->rg_igeneration);
+ memset(&str->rg_reserved, 0, sizeof(str->rg_reserved));
+}
+
+void gfs2_quota_in(struct gfs2_quota *qu, const void *buf)
+{
+ const struct gfs2_quota *str = buf;
+
+ qu->qu_limit = be64_to_cpu(str->qu_limit);
+ qu->qu_warn = be64_to_cpu(str->qu_warn);
+ qu->qu_value = be64_to_cpu(str->qu_value);
+}
+
+void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf)
+{
+ const struct gfs2_dinode *str = buf;
+
+ gfs2_meta_header_in(&di->di_header, buf);
+ gfs2_inum_in(&di->di_num, &str->di_num);
+
+ di->di_mode = be32_to_cpu(str->di_mode);
+ di->di_uid = be32_to_cpu(str->di_uid);
+ di->di_gid = be32_to_cpu(str->di_gid);
+ di->di_nlink = be32_to_cpu(str->di_nlink);
+ di->di_size = be64_to_cpu(str->di_size);
+ di->di_blocks = be64_to_cpu(str->di_blocks);
+ di->di_atime = be64_to_cpu(str->di_atime);
+ di->di_mtime = be64_to_cpu(str->di_mtime);
+ di->di_ctime = be64_to_cpu(str->di_ctime);
+ di->di_major = be32_to_cpu(str->di_major);
+ di->di_minor = be32_to_cpu(str->di_minor);
+
+ di->di_goal_meta = be64_to_cpu(str->di_goal_meta);
+ di->di_goal_data = be64_to_cpu(str->di_goal_data);
+ di->di_generation = be64_to_cpu(str->di_generation);
+
+ di->di_flags = be32_to_cpu(str->di_flags);
+ di->di_payload_format = be32_to_cpu(str->di_payload_format);
+ di->di_height = be16_to_cpu(str->di_height);
+
+ di->di_depth = be16_to_cpu(str->di_depth);
+ di->di_entries = be32_to_cpu(str->di_entries);
+
+ di->di_eattr = be64_to_cpu(str->di_eattr);
+
+}
+
+void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf)
+{
+ struct gfs2_dinode *str = buf;
+
+ gfs2_meta_header_out(&di->di_header, buf);
+ gfs2_inum_out(&di->di_num, (char *)&str->di_num);
+
+ str->di_mode = cpu_to_be32(di->di_mode);
+ str->di_uid = cpu_to_be32(di->di_uid);
+ str->di_gid = cpu_to_be32(di->di_gid);
+ str->di_nlink = cpu_to_be32(di->di_nlink);
+ str->di_size = cpu_to_be64(di->di_size);
+ str->di_blocks = cpu_to_be64(di->di_blocks);
+ str->di_atime = cpu_to_be64(di->di_atime);
+ str->di_mtime = cpu_to_be64(di->di_mtime);
+ str->di_ctime = cpu_to_be64(di->di_ctime);
+ str->di_major = cpu_to_be32(di->di_major);
+ str->di_minor = cpu_to_be32(di->di_minor);
+
+ str->di_goal_meta = cpu_to_be64(di->di_goal_meta);
+ str->di_goal_data = cpu_to_be64(di->di_goal_data);
+ str->di_generation = cpu_to_be64(di->di_generation);
+
+ str->di_flags = cpu_to_be32(di->di_flags);
+ str->di_payload_format = cpu_to_be32(di->di_payload_format);
+ str->di_height = cpu_to_be16(di->di_height);
+
+ str->di_depth = cpu_to_be16(di->di_depth);
+ str->di_entries = cpu_to_be32(di->di_entries);
+
+ str->di_eattr = cpu_to_be64(di->di_eattr);
+
+}
+
+void gfs2_dinode_print(const struct gfs2_dinode *di)
+{
+ gfs2_meta_header_print(&di->di_header);
+ gfs2_inum_print(&di->di_num);
+
+ pv(di, di_mode, "0%o");
+ pv(di, di_uid, "%u");
+ pv(di, di_gid, "%u");
+ pv(di, di_nlink, "%u");
+ printk(KERN_INFO " di_size = %llu\n", (unsigned long long)di->di_size);
+ printk(KERN_INFO " di_blocks = %llu\n", (unsigned long long)di->di_blocks);
+ printk(KERN_INFO " di_atime = %lld\n", (long long)di->di_atime);
+ printk(KERN_INFO " di_mtime = %lld\n", (long long)di->di_mtime);
+ printk(KERN_INFO " di_ctime = %lld\n", (long long)di->di_ctime);
+ pv(di, di_major, "%u");
+ pv(di, di_minor, "%u");
+
+ printk(KERN_INFO " di_goal_meta = %llu\n", (unsigned long long)di->di_goal_meta);
+ printk(KERN_INFO " di_goal_data = %llu\n", (unsigned long long)di->di_goal_data);
+
+ pv(di, di_flags, "0x%.8X");
+ pv(di, di_payload_format, "%u");
+ pv(di, di_height, "%u");
+
+ pv(di, di_depth, "%u");
+ pv(di, di_entries, "%u");
+
+ printk(KERN_INFO " di_eattr = %llu\n", (unsigned long long)di->di_eattr);
+}
+
+void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf)
+{
+ const struct gfs2_log_header *str = buf;
+
+ gfs2_meta_header_in(&lh->lh_header, buf);
+ lh->lh_sequence = be64_to_cpu(str->lh_sequence);
+ lh->lh_flags = be32_to_cpu(str->lh_flags);
+ lh->lh_tail = be32_to_cpu(str->lh_tail);
+ lh->lh_blkno = be32_to_cpu(str->lh_blkno);
+ lh->lh_hash = be32_to_cpu(str->lh_hash);
+}
+
+void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf)
+{
+ const struct gfs2_inum_range *str = buf;
+
+ ir->ir_start = be64_to_cpu(str->ir_start);
+ ir->ir_length = be64_to_cpu(str->ir_length);
+}
+
+void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf)
+{
+ struct gfs2_inum_range *str = buf;
+
+ str->ir_start = cpu_to_be64(ir->ir_start);
+ str->ir_length = cpu_to_be64(ir->ir_length);
+}
+
+void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf)
+{
+ const struct gfs2_statfs_change *str = buf;
+
+ sc->sc_total = be64_to_cpu(str->sc_total);
+ sc->sc_free = be64_to_cpu(str->sc_free);
+ sc->sc_dinodes = be64_to_cpu(str->sc_dinodes);
+}
+
+void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf)
+{
+ struct gfs2_statfs_change *str = buf;
+
+ str->sc_total = cpu_to_be64(sc->sc_total);
+ str->sc_free = cpu_to_be64(sc->sc_free);
+ str->sc_dinodes = cpu_to_be64(sc->sc_dinodes);
+}
+
+void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf)
+{
+ const struct gfs2_quota_change *str = buf;
+
+ qc->qc_change = be64_to_cpu(str->qc_change);
+ qc->qc_flags = be32_to_cpu(str->qc_flags);
+ qc->qc_id = be32_to_cpu(str->qc_id);
+}
+
diff --git a/fs/gfs2/ops_address.c b/fs/gfs2/ops_address.c
new file mode 100644
index 000000000000..8d5963c7e123
--- /dev/null
+++ b/fs/gfs2/ops_address.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/pagemap.h>
+#include <linux/pagevec.h>
+#include <linux/mpage.h>
+#include <linux/fs.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "ops_address.h"
+#include "quota.h"
+#include "trans.h"
+#include "rgrp.h"
+#include "ops_file.h"
+#include "util.h"
+#include "glops.h"
+
+
+static void gfs2_page_add_databufs(struct gfs2_inode *ip, struct page *page,
+ unsigned int from, unsigned int to)
+{
+ struct buffer_head *head = page_buffers(page);
+ unsigned int bsize = head->b_size;
+ struct buffer_head *bh;
+ unsigned int start, end;
+
+ for (bh = head, start = 0; bh != head || !start;
+ bh = bh->b_this_page, start = end) {
+ end = start + bsize;
+ if (end <= from || start >= to)
+ continue;
+ gfs2_trans_add_bh(ip->i_gl, bh, 0);
+ }
+}
+
+/**
+ * gfs2_get_block - Fills in a buffer head with details about a block
+ * @inode: The inode
+ * @lblock: The block number to look up
+ * @bh_result: The buffer head to return the result in
+ * @create: Non-zero if we may add block to the file
+ *
+ * Returns: errno
+ */
+
+int gfs2_get_block(struct inode *inode, sector_t lblock,
+ struct buffer_head *bh_result, int create)
+{
+ return gfs2_block_map(inode, lblock, create, bh_result);
+}
+
+/**
+ * gfs2_get_block_noalloc - Fills in a buffer head with details about a block
+ * @inode: The inode
+ * @lblock: The block number to look up
+ * @bh_result: The buffer head to return the result in
+ * @create: Non-zero if we may add block to the file
+ *
+ * Returns: errno
+ */
+
+static int gfs2_get_block_noalloc(struct inode *inode, sector_t lblock,
+ struct buffer_head *bh_result, int create)
+{
+ int error;
+
+ error = gfs2_block_map(inode, lblock, 0, bh_result);
+ if (error)
+ return error;
+ if (bh_result->b_blocknr == 0)
+ return -EIO;
+ return 0;
+}
+
+static int gfs2_get_block_direct(struct inode *inode, sector_t lblock,
+ struct buffer_head *bh_result, int create)
+{
+ return gfs2_block_map(inode, lblock, 0, bh_result);
+}
+
+/**
+ * gfs2_writepage - Write complete page
+ * @page: Page to write
+ *
+ * Returns: errno
+ *
+ * Some of this is copied from block_write_full_page() although we still
+ * call it to do most of the work.
+ */
+
+static int gfs2_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct inode *inode = page->mapping->host;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ loff_t i_size = i_size_read(inode);
+ pgoff_t end_index = i_size >> PAGE_CACHE_SHIFT;
+ unsigned offset;
+ int error;
+ int done_trans = 0;
+
+ if (gfs2_assert_withdraw(sdp, gfs2_glock_is_held_excl(ip->i_gl))) {
+ unlock_page(page);
+ return -EIO;
+ }
+ if (current->journal_info)
+ goto out_ignore;
+
+ /* Is the page fully outside i_size? (truncate in progress) */
+ offset = i_size & (PAGE_CACHE_SIZE-1);
+ if (page->index > end_index || (page->index == end_index && !offset)) {
+ page->mapping->a_ops->invalidatepage(page, 0);
+ unlock_page(page);
+ return 0; /* don't care */
+ }
+
+ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED || gfs2_is_jdata(ip)) {
+ error = gfs2_trans_begin(sdp, RES_DINODE + 1, 0);
+ if (error)
+ goto out_ignore;
+ if (!page_has_buffers(page)) {
+ create_empty_buffers(page, inode->i_sb->s_blocksize,
+ (1 << BH_Dirty)|(1 << BH_Uptodate));
+ }
+ gfs2_page_add_databufs(ip, page, 0, sdp->sd_vfs->s_blocksize-1);
+ done_trans = 1;
+ }
+ error = block_write_full_page(page, gfs2_get_block_noalloc, wbc);
+ if (done_trans)
+ gfs2_trans_end(sdp);
+ gfs2_meta_cache_flush(ip);
+ return error;
+
+out_ignore:
+ redirty_page_for_writepage(wbc, page);
+ unlock_page(page);
+ return 0;
+}
+
+static int zero_readpage(struct page *page)
+{
+ void *kaddr;
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr, 0, PAGE_CACHE_SIZE);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ SetPageUptodate(page);
+
+ return 0;
+}
+
+/**
+ * stuffed_readpage - Fill in a Linux page with stuffed file data
+ * @ip: the inode
+ * @page: the page
+ *
+ * Returns: errno
+ */
+
+static int stuffed_readpage(struct gfs2_inode *ip, struct page *page)
+{
+ struct buffer_head *dibh;
+ void *kaddr;
+ int error;
+
+ /* Only the first page of a stuffed file might contain data */
+ if (unlikely(page->index))
+ return zero_readpage(page);
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ return error;
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ memcpy(kaddr, dibh->b_data + sizeof(struct gfs2_dinode),
+ ip->i_di.di_size);
+ memset(kaddr + ip->i_di.di_size, 0, PAGE_CACHE_SIZE - ip->i_di.di_size);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ brelse(dibh);
+
+ SetPageUptodate(page);
+
+ return 0;
+}
+
+
+/**
+ * gfs2_readpage - readpage with locking
+ * @file: The file to read a page for. N.B. This may be NULL if we are
+ * reading an internal file.
+ * @page: The page to read
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readpage(struct file *file, struct page *page)
+{
+ struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+ struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+ struct gfs2_file *gf = NULL;
+ struct gfs2_holder gh;
+ int error;
+ int do_unlock = 0;
+
+ if (likely(file != &gfs2_internal_file_sentinel)) {
+ if (file) {
+ gf = file->private_data;
+ if (test_bit(GFF_EXLOCK, &gf->f_flags))
+ /* gfs2_sharewrite_nopage has grabbed the ip->i_gl already */
+ goto skip_lock;
+ }
+ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME|GL_AOP, &gh);
+ do_unlock = 1;
+ error = gfs2_glock_nq_m_atime(1, &gh);
+ if (unlikely(error))
+ goto out_unlock;
+ }
+
+skip_lock:
+ if (gfs2_is_stuffed(ip)) {
+ error = stuffed_readpage(ip, page);
+ unlock_page(page);
+ } else
+ error = mpage_readpage(page, gfs2_get_block);
+
+ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ error = -EIO;
+
+ if (do_unlock) {
+ gfs2_glock_dq_m(1, &gh);
+ gfs2_holder_uninit(&gh);
+ }
+out:
+ return error;
+out_unlock:
+ unlock_page(page);
+ if (do_unlock)
+ gfs2_holder_uninit(&gh);
+ goto out;
+}
+
+/**
+ * gfs2_readpages - Read a bunch of pages at once
+ *
+ * Some notes:
+ * 1. This is only for readahead, so we can simply ignore any things
+ * which are slightly inconvenient (such as locking conflicts between
+ * the page lock and the glock) and return having done no I/O. Its
+ * obviously not something we'd want to do on too regular a basis.
+ * Any I/O we ignore at this time will be done via readpage later.
+ * 2. We have to handle stuffed files here too.
+ * 3. mpage_readpages() does most of the heavy lifting in the common case.
+ * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
+ * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
+ * well as read-ahead.
+ */
+static int gfs2_readpages(struct file *file, struct address_space *mapping,
+ struct list_head *pages, unsigned nr_pages)
+{
+ struct inode *inode = mapping->host;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct gfs2_holder gh;
+ unsigned page_idx;
+ int ret;
+ int do_unlock = 0;
+
+ if (likely(file != &gfs2_internal_file_sentinel)) {
+ if (file) {
+ struct gfs2_file *gf = file->private_data;
+ if (test_bit(GFF_EXLOCK, &gf->f_flags))
+ goto skip_lock;
+ }
+ gfs2_holder_init(ip->i_gl, LM_ST_SHARED,
+ LM_FLAG_TRY_1CB|GL_ATIME|GL_AOP, &gh);
+ do_unlock = 1;
+ ret = gfs2_glock_nq_m_atime(1, &gh);
+ if (ret == GLR_TRYFAILED)
+ goto out_noerror;
+ if (unlikely(ret))
+ goto out_unlock;
+ }
+skip_lock:
+ if (gfs2_is_stuffed(ip)) {
+ struct pagevec lru_pvec;
+ pagevec_init(&lru_pvec, 0);
+ for (page_idx = 0; page_idx < nr_pages; page_idx++) {
+ struct page *page = list_entry(pages->prev, struct page, lru);
+ prefetchw(&page->flags);
+ list_del(&page->lru);
+ if (!add_to_page_cache(page, mapping,
+ page->index, GFP_KERNEL)) {
+ ret = stuffed_readpage(ip, page);
+ unlock_page(page);
+ if (!pagevec_add(&lru_pvec, page))
+ __pagevec_lru_add(&lru_pvec);
+ } else {
+ page_cache_release(page);
+ }
+ }
+ pagevec_lru_add(&lru_pvec);
+ ret = 0;
+ } else {
+ /* What we really want to do .... */
+ ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
+ }
+
+ if (do_unlock) {
+ gfs2_glock_dq_m(1, &gh);
+ gfs2_holder_uninit(&gh);
+ }
+out:
+ if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags)))
+ ret = -EIO;
+ return ret;
+out_noerror:
+ ret = 0;
+out_unlock:
+ /* unlock all pages, we can't do any I/O right now */
+ for (page_idx = 0; page_idx < nr_pages; page_idx++) {
+ struct page *page = list_entry(pages->prev, struct page, lru);
+ list_del(&page->lru);
+ unlock_page(page);
+ page_cache_release(page);
+ }
+ if (do_unlock)
+ gfs2_holder_uninit(&gh);
+ goto out;
+}
+
+/**
+ * gfs2_prepare_write - Prepare to write a page to a file
+ * @file: The file to write to
+ * @page: The page which is to be prepared for writing
+ * @from: From (byte range within page)
+ * @to: To (byte range within page)
+ *
+ * Returns: errno
+ */
+
+static int gfs2_prepare_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ struct gfs2_inode *ip = GFS2_I(page->mapping->host);
+ struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+ unsigned int data_blocks, ind_blocks, rblocks;
+ int alloc_required;
+ int error = 0;
+ loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + from;
+ loff_t end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
+ struct gfs2_alloc *al;
+ unsigned int write_len = to - from;
+
+
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|GL_AOP, &ip->i_gh);
+ error = gfs2_glock_nq_m_atime(1, &ip->i_gh);
+ if (error)
+ goto out_uninit;
+
+ gfs2_write_calc_reserv(ip, write_len, &data_blocks, &ind_blocks);
+
+ error = gfs2_write_alloc_required(ip, pos, write_len, &alloc_required);
+ if (error)
+ goto out_unlock;
+
+
+ ip->i_alloc.al_requested = 0;
+ if (alloc_required) {
+ al = gfs2_alloc_get(ip);
+
+ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out_alloc_put;
+
+ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+ if (error)
+ goto out_qunlock;
+
+ al->al_requested = data_blocks + ind_blocks;
+ error = gfs2_inplace_reserve(ip);
+ if (error)
+ goto out_qunlock;
+ }
+
+ rblocks = RES_DINODE + ind_blocks;
+ if (gfs2_is_jdata(ip))
+ rblocks += data_blocks ? data_blocks : 1;
+ if (ind_blocks || data_blocks)
+ rblocks += RES_STATFS + RES_QUOTA;
+
+ error = gfs2_trans_begin(sdp, rblocks, 0);
+ if (error)
+ goto out;
+
+ if (gfs2_is_stuffed(ip)) {
+ if (end > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode)) {
+ error = gfs2_unstuff_dinode(ip, page);
+ if (error == 0)
+ goto prepare_write;
+ } else if (!PageUptodate(page))
+ error = stuffed_readpage(ip, page);
+ goto out;
+ }
+
+prepare_write:
+ error = block_prepare_write(page, from, to, gfs2_get_block);
+
+out:
+ if (error) {
+ gfs2_trans_end(sdp);
+ if (alloc_required) {
+ gfs2_inplace_release(ip);
+out_qunlock:
+ gfs2_quota_unlock(ip);
+out_alloc_put:
+ gfs2_alloc_put(ip);
+ }
+out_unlock:
+ gfs2_glock_dq_m(1, &ip->i_gh);
+out_uninit:
+ gfs2_holder_uninit(&ip->i_gh);
+ }
+
+ return error;
+}
+
+/**
+ * gfs2_commit_write - Commit write to a file
+ * @file: The file to write to
+ * @page: The page containing the data
+ * @from: From (byte range within page)
+ * @to: To (byte range within page)
+ *
+ * Returns: errno
+ */
+
+static int gfs2_commit_write(struct file *file, struct page *page,
+ unsigned from, unsigned to)
+{
+ struct inode *inode = page->mapping->host;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ int error = -EOPNOTSUPP;
+ struct buffer_head *dibh;
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_dinode *di;
+
+ if (gfs2_assert_withdraw(sdp, gfs2_glock_is_locked_by_me(ip->i_gl)))
+ goto fail_nounlock;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto fail_endtrans;
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ di = (struct gfs2_dinode *)dibh->b_data;
+
+ if (gfs2_is_stuffed(ip)) {
+ u64 file_size;
+ void *kaddr;
+
+ file_size = ((u64)page->index << PAGE_CACHE_SHIFT) + to;
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ memcpy(dibh->b_data + sizeof(struct gfs2_dinode) + from,
+ kaddr + from, to - from);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ SetPageUptodate(page);
+
+ if (inode->i_size < file_size)
+ i_size_write(inode, file_size);
+ } else {
+ if (sdp->sd_args.ar_data == GFS2_DATA_ORDERED ||
+ gfs2_is_jdata(ip))
+ gfs2_page_add_databufs(ip, page, from, to);
+ error = generic_commit_write(file, page, from, to);
+ if (error)
+ goto fail;
+ }
+
+ if (ip->i_di.di_size < inode->i_size) {
+ ip->i_di.di_size = inode->i_size;
+ di->di_size = cpu_to_be64(inode->i_size);
+ }
+
+ di->di_mode = cpu_to_be32(inode->i_mode);
+ di->di_atime = cpu_to_be64(inode->i_atime.tv_sec);
+ di->di_mtime = cpu_to_be64(inode->i_mtime.tv_sec);
+ di->di_ctime = cpu_to_be64(inode->i_ctime.tv_sec);
+
+ brelse(dibh);
+ gfs2_trans_end(sdp);
+ if (al->al_requested) {
+ gfs2_inplace_release(ip);
+ gfs2_quota_unlock(ip);
+ gfs2_alloc_put(ip);
+ }
+ gfs2_glock_dq_m(1, &ip->i_gh);
+ gfs2_holder_uninit(&ip->i_gh);
+ return 0;
+
+fail:
+ brelse(dibh);
+fail_endtrans:
+ gfs2_trans_end(sdp);
+ if (al->al_requested) {
+ gfs2_inplace_release(ip);
+ gfs2_quota_unlock(ip);
+ gfs2_alloc_put(ip);
+ }
+ gfs2_glock_dq_m(1, &ip->i_gh);
+ gfs2_holder_uninit(&ip->i_gh);
+fail_nounlock:
+ ClearPageUptodate(page);
+ return error;
+}
+
+/**
+ * gfs2_bmap - Block map function
+ * @mapping: Address space info
+ * @lblock: The block to map
+ *
+ * Returns: The disk address for the block or 0 on hole or error
+ */
+
+static sector_t gfs2_bmap(struct address_space *mapping, sector_t lblock)
+{
+ struct gfs2_inode *ip = GFS2_I(mapping->host);
+ struct gfs2_holder i_gh;
+ sector_t dblock = 0;
+ int error;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+ if (error)
+ return 0;
+
+ if (!gfs2_is_stuffed(ip))
+ dblock = generic_block_bmap(mapping, lblock, gfs2_get_block);
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+ return dblock;
+}
+
+static void discard_buffer(struct gfs2_sbd *sdp, struct buffer_head *bh)
+{
+ struct gfs2_bufdata *bd;
+
+ gfs2_log_lock(sdp);
+ bd = bh->b_private;
+ if (bd) {
+ bd->bd_bh = NULL;
+ bh->b_private = NULL;
+ }
+ gfs2_log_unlock(sdp);
+
+ lock_buffer(bh);
+ clear_buffer_dirty(bh);
+ bh->b_bdev = NULL;
+ clear_buffer_mapped(bh);
+ clear_buffer_req(bh);
+ clear_buffer_new(bh);
+ clear_buffer_delay(bh);
+ unlock_buffer(bh);
+}
+
+static void gfs2_invalidatepage(struct page *page, unsigned long offset)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(page->mapping->host);
+ struct buffer_head *head, *bh, *next;
+ unsigned int curr_off = 0;
+
+ BUG_ON(!PageLocked(page));
+ if (!page_has_buffers(page))
+ return;
+
+ bh = head = page_buffers(page);
+ do {
+ unsigned int next_off = curr_off + bh->b_size;
+ next = bh->b_this_page;
+
+ if (offset <= curr_off)
+ discard_buffer(sdp, bh);
+
+ curr_off = next_off;
+ bh = next;
+ } while (bh != head);
+
+ if (!offset)
+ try_to_release_page(page, 0);
+
+ return;
+}
+
+static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
+ const struct iovec *iov, loff_t offset,
+ unsigned long nr_segs)
+{
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_mapping->host;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder gh;
+ int rv;
+
+ if (rw == READ)
+ mutex_lock(&inode->i_mutex);
+ /*
+ * Shared lock, even if its a write, since we do no allocation
+ * on this path. All we need change is atime.
+ */
+ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+ rv = gfs2_glock_nq_m_atime(1, &gh);
+ if (rv)
+ goto out;
+
+ if (offset > i_size_read(inode))
+ goto out;
+
+ /*
+ * Should we return an error here? I can't see that O_DIRECT for
+ * a journaled file makes any sense. For now we'll silently fall
+ * back to buffered I/O, likewise we do the same for stuffed
+ * files since they are (a) small and (b) unaligned.
+ */
+ if (gfs2_is_jdata(ip))
+ goto out;
+
+ if (gfs2_is_stuffed(ip))
+ goto out;
+
+ rv = blockdev_direct_IO_own_locking(rw, iocb, inode,
+ inode->i_sb->s_bdev,
+ iov, offset, nr_segs,
+ gfs2_get_block_direct, NULL);
+out:
+ gfs2_glock_dq_m(1, &gh);
+ gfs2_holder_uninit(&gh);
+ if (rw == READ)
+ mutex_unlock(&inode->i_mutex);
+
+ return rv;
+}
+
+/**
+ * stuck_releasepage - We're stuck in gfs2_releasepage(). Print stuff out.
+ * @bh: the buffer we're stuck on
+ *
+ */
+
+static void stuck_releasepage(struct buffer_head *bh)
+{
+ struct inode *inode = bh->b_page->mapping->host;
+ struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+ struct gfs2_bufdata *bd = bh->b_private;
+ struct gfs2_glock *gl;
+static unsigned limit = 0;
+
+ if (limit > 3)
+ return;
+ limit++;
+
+ fs_warn(sdp, "stuck in gfs2_releasepage() %p\n", inode);
+ fs_warn(sdp, "blkno = %llu, bh->b_count = %d\n",
+ (unsigned long long)bh->b_blocknr, atomic_read(&bh->b_count));
+ fs_warn(sdp, "pinned = %u\n", buffer_pinned(bh));
+ fs_warn(sdp, "bh->b_private = %s\n", (bd) ? "!NULL" : "NULL");
+
+ if (!bd)
+ return;
+
+ gl = bd->bd_gl;
+
+ fs_warn(sdp, "gl = (%u, %llu)\n",
+ gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number);
+
+ fs_warn(sdp, "bd_list_tr = %s, bd_le.le_list = %s\n",
+ (list_empty(&bd->bd_list_tr)) ? "no" : "yes",
+ (list_empty(&bd->bd_le.le_list)) ? "no" : "yes");
+
+ if (gl->gl_ops == &gfs2_inode_glops) {
+ struct gfs2_inode *ip = gl->gl_object;
+ unsigned int x;
+
+ if (!ip)
+ return;
+
+ fs_warn(sdp, "ip = %llu %llu\n",
+ (unsigned long long)ip->i_num.no_formal_ino,
+ (unsigned long long)ip->i_num.no_addr);
+
+ for (x = 0; x < GFS2_MAX_META_HEIGHT; x++)
+ fs_warn(sdp, "ip->i_cache[%u] = %s\n",
+ x, (ip->i_cache[x]) ? "!NULL" : "NULL");
+ }
+}
+
+/**
+ * gfs2_releasepage - free the metadata associated with a page
+ * @page: the page that's being released
+ * @gfp_mask: passed from Linux VFS, ignored by us
+ *
+ * Call try_to_free_buffers() if the buffers in this page can be
+ * released.
+ *
+ * Returns: 0
+ */
+
+int gfs2_releasepage(struct page *page, gfp_t gfp_mask)
+{
+ struct inode *aspace = page->mapping->host;
+ struct gfs2_sbd *sdp = aspace->i_sb->s_fs_info;
+ struct buffer_head *bh, *head;
+ struct gfs2_bufdata *bd;
+ unsigned long t = jiffies + gfs2_tune_get(sdp, gt_stall_secs) * HZ;
+
+ if (!page_has_buffers(page))
+ goto out;
+
+ head = bh = page_buffers(page);
+ do {
+ while (atomic_read(&bh->b_count)) {
+ if (!atomic_read(&aspace->i_writecount))
+ return 0;
+
+ if (time_after_eq(jiffies, t)) {
+ stuck_releasepage(bh);
+ /* should we withdraw here? */
+ return 0;
+ }
+
+ yield();
+ }
+
+ gfs2_assert_warn(sdp, !buffer_pinned(bh));
+ gfs2_assert_warn(sdp, !buffer_dirty(bh));
+
+ gfs2_log_lock(sdp);
+ bd = bh->b_private;
+ if (bd) {
+ gfs2_assert_warn(sdp, bd->bd_bh == bh);
+ gfs2_assert_warn(sdp, list_empty(&bd->bd_list_tr));
+ gfs2_assert_warn(sdp, !bd->bd_ail);
+ bd->bd_bh = NULL;
+ if (!list_empty(&bd->bd_le.le_list))
+ bd = NULL;
+ bh->b_private = NULL;
+ }
+ gfs2_log_unlock(sdp);
+ if (bd)
+ kmem_cache_free(gfs2_bufdata_cachep, bd);
+
+ bh = bh->b_this_page;
+ } while (bh != head);
+
+out:
+ return try_to_free_buffers(page);
+}
+
+const struct address_space_operations gfs2_file_aops = {
+ .writepage = gfs2_writepage,
+ .readpage = gfs2_readpage,
+ .readpages = gfs2_readpages,
+ .sync_page = block_sync_page,
+ .prepare_write = gfs2_prepare_write,
+ .commit_write = gfs2_commit_write,
+ .bmap = gfs2_bmap,
+ .invalidatepage = gfs2_invalidatepage,
+ .releasepage = gfs2_releasepage,
+ .direct_IO = gfs2_direct_IO,
+};
+
diff --git a/fs/gfs2/ops_address.h b/fs/gfs2/ops_address.h
new file mode 100644
index 000000000000..35aaee4aa7e1
--- /dev/null
+++ b/fs/gfs2/ops_address.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_ADDRESS_DOT_H__
+#define __OPS_ADDRESS_DOT_H__
+
+#include <linux/fs.h>
+#include <linux/buffer_head.h>
+#include <linux/mm.h>
+
+extern const struct address_space_operations gfs2_file_aops;
+extern int gfs2_get_block(struct inode *inode, sector_t lblock,
+ struct buffer_head *bh_result, int create);
+extern int gfs2_releasepage(struct page *page, gfp_t gfp_mask);
+
+#endif /* __OPS_ADDRESS_DOT_H__ */
diff --git a/fs/gfs2/ops_dentry.c b/fs/gfs2/ops_dentry.c
new file mode 100644
index 000000000000..00041b1b8025
--- /dev/null
+++ b/fs/gfs2/ops_dentry.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/smp_lock.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "dir.h"
+#include "glock.h"
+#include "ops_dentry.h"
+#include "util.h"
+
+/**
+ * gfs2_drevalidate - Check directory lookup consistency
+ * @dentry: the mapping to check
+ * @nd:
+ *
+ * Check to make sure the lookup necessary to arrive at this inode from its
+ * parent is still good.
+ *
+ * Returns: 1 if the dentry is ok, 0 if it isn't
+ */
+
+static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ struct dentry *parent = dget_parent(dentry);
+ struct gfs2_sbd *sdp = GFS2_SB(parent->d_inode);
+ struct gfs2_inode *dip = GFS2_I(parent->d_inode);
+ struct inode *inode = dentry->d_inode;
+ struct gfs2_holder d_gh;
+ struct gfs2_inode *ip;
+ struct gfs2_inum inum;
+ unsigned int type;
+ int error;
+
+ if (inode && is_bad_inode(inode))
+ goto invalid;
+
+ if (sdp->sd_args.ar_localcaching)
+ goto valid;
+
+ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+ if (error)
+ goto fail;
+
+ error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type);
+ switch (error) {
+ case 0:
+ if (!inode)
+ goto invalid_gunlock;
+ break;
+ case -ENOENT:
+ if (!inode)
+ goto valid_gunlock;
+ goto invalid_gunlock;
+ default:
+ goto fail_gunlock;
+ }
+
+ ip = GFS2_I(inode);
+
+ if (!gfs2_inum_equal(&ip->i_num, &inum))
+ goto invalid_gunlock;
+
+ if (IF2DT(ip->i_di.di_mode) != type) {
+ gfs2_consist_inode(dip);
+ goto fail_gunlock;
+ }
+
+valid_gunlock:
+ gfs2_glock_dq_uninit(&d_gh);
+valid:
+ dput(parent);
+ return 1;
+
+invalid_gunlock:
+ gfs2_glock_dq_uninit(&d_gh);
+invalid:
+ if (inode && S_ISDIR(inode->i_mode)) {
+ if (have_submounts(dentry))
+ goto valid;
+ shrink_dcache_parent(dentry);
+ }
+ d_drop(dentry);
+ dput(parent);
+ return 0;
+
+fail_gunlock:
+ gfs2_glock_dq_uninit(&d_gh);
+fail:
+ dput(parent);
+ return 0;
+}
+
+static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
+{
+ str->hash = gfs2_disk_hash(str->name, str->len);
+ return 0;
+}
+
+struct dentry_operations gfs2_dops = {
+ .d_revalidate = gfs2_drevalidate,
+ .d_hash = gfs2_dhash,
+};
+
diff --git a/fs/gfs2/ops_dentry.h b/fs/gfs2/ops_dentry.h
new file mode 100644
index 000000000000..5caa3db4d3f5
--- /dev/null
+++ b/fs/gfs2/ops_dentry.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_DENTRY_DOT_H__
+#define __OPS_DENTRY_DOT_H__
+
+#include <linux/dcache.h>
+
+extern struct dentry_operations gfs2_dops;
+
+#endif /* __OPS_DENTRY_DOT_H__ */
diff --git a/fs/gfs2/ops_export.c b/fs/gfs2/ops_export.c
new file mode 100644
index 000000000000..86127d93bd35
--- /dev/null
+++ b/fs/gfs2/ops_export.c
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "dir.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "ops_export.h"
+#include "rgrp.h"
+#include "util.h"
+
+static struct dentry *gfs2_decode_fh(struct super_block *sb,
+ __u32 *fh,
+ int fh_len,
+ int fh_type,
+ int (*acceptable)(void *context,
+ struct dentry *dentry),
+ void *context)
+{
+ struct gfs2_fh_obj fh_obj;
+ struct gfs2_inum *this, parent;
+
+ if (fh_type != fh_len)
+ return NULL;
+
+ this = &fh_obj.this;
+ fh_obj.imode = DT_UNKNOWN;
+ memset(&parent, 0, sizeof(struct gfs2_inum));
+
+ switch (fh_type) {
+ case GFS2_LARGE_FH_SIZE:
+ parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
+ parent.no_formal_ino |= be32_to_cpu(fh[5]);
+ parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
+ parent.no_addr |= be32_to_cpu(fh[7]);
+ fh_obj.imode = be32_to_cpu(fh[8]);
+ case GFS2_SMALL_FH_SIZE:
+ this->no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
+ this->no_formal_ino |= be32_to_cpu(fh[1]);
+ this->no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
+ this->no_addr |= be32_to_cpu(fh[3]);
+ break;
+ default:
+ return NULL;
+ }
+
+ return gfs2_export_ops.find_exported_dentry(sb, &fh_obj, &parent,
+ acceptable, context);
+}
+
+static int gfs2_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
+ int connectable)
+{
+ struct inode *inode = dentry->d_inode;
+ struct super_block *sb = inode->i_sb;
+ struct gfs2_inode *ip = GFS2_I(inode);
+
+ if (*len < GFS2_SMALL_FH_SIZE ||
+ (connectable && *len < GFS2_LARGE_FH_SIZE))
+ return 255;
+
+ fh[0] = ip->i_num.no_formal_ino >> 32;
+ fh[0] = cpu_to_be32(fh[0]);
+ fh[1] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
+ fh[1] = cpu_to_be32(fh[1]);
+ fh[2] = ip->i_num.no_addr >> 32;
+ fh[2] = cpu_to_be32(fh[2]);
+ fh[3] = ip->i_num.no_addr & 0xFFFFFFFF;
+ fh[3] = cpu_to_be32(fh[3]);
+ *len = GFS2_SMALL_FH_SIZE;
+
+ if (!connectable || inode == sb->s_root->d_inode)
+ return *len;
+
+ spin_lock(&dentry->d_lock);
+ inode = dentry->d_parent->d_inode;
+ ip = GFS2_I(inode);
+ igrab(inode);
+ spin_unlock(&dentry->d_lock);
+
+ fh[4] = ip->i_num.no_formal_ino >> 32;
+ fh[4] = cpu_to_be32(fh[4]);
+ fh[5] = ip->i_num.no_formal_ino & 0xFFFFFFFF;
+ fh[5] = cpu_to_be32(fh[5]);
+ fh[6] = ip->i_num.no_addr >> 32;
+ fh[6] = cpu_to_be32(fh[6]);
+ fh[7] = ip->i_num.no_addr & 0xFFFFFFFF;
+ fh[7] = cpu_to_be32(fh[7]);
+
+ fh[8] = cpu_to_be32(inode->i_mode);
+ fh[9] = 0; /* pad to double word */
+ *len = GFS2_LARGE_FH_SIZE;
+
+ iput(inode);
+
+ return *len;
+}
+
+struct get_name_filldir {
+ struct gfs2_inum inum;
+ char *name;
+};
+
+static int get_name_filldir(void *opaque, const char *name, unsigned int length,
+ u64 offset, struct gfs2_inum *inum,
+ unsigned int type)
+{
+ struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;
+
+ if (!gfs2_inum_equal(inum, &gnfd->inum))
+ return 0;
+
+ memcpy(gnfd->name, name, length);
+ gnfd->name[length] = 0;
+
+ return 1;
+}
+
+static int gfs2_get_name(struct dentry *parent, char *name,
+ struct dentry *child)
+{
+ struct inode *dir = parent->d_inode;
+ struct inode *inode = child->d_inode;
+ struct gfs2_inode *dip, *ip;
+ struct get_name_filldir gnfd;
+ struct gfs2_holder gh;
+ u64 offset = 0;
+ int error;
+
+ if (!dir)
+ return -EINVAL;
+
+ if (!S_ISDIR(dir->i_mode) || !inode)
+ return -EINVAL;
+
+ dip = GFS2_I(dir);
+ ip = GFS2_I(inode);
+
+ *name = 0;
+ gnfd.inum = ip->i_num;
+ gnfd.name = name;
+
+ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
+ if (error)
+ return error;
+
+ error = gfs2_dir_read(dir, &offset, &gnfd, get_name_filldir);
+
+ gfs2_glock_dq_uninit(&gh);
+
+ if (!error && !*name)
+ error = -ENOENT;
+
+ return error;
+}
+
+static struct dentry *gfs2_get_parent(struct dentry *child)
+{
+ struct qstr dotdot;
+ struct inode *inode;
+ struct dentry *dentry;
+
+ gfs2_str2qstr(&dotdot, "..");
+ inode = gfs2_lookupi(child->d_inode, &dotdot, 1, NULL);
+
+ if (!inode)
+ return ERR_PTR(-ENOENT);
+ /*
+ * In case of an error, @inode carries the error value, and we
+ * have to return that as a(n invalid) pointer to dentry.
+ */
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(inode));
+
+ dentry = d_alloc_anon(inode);
+ if (!dentry) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return dentry;
+}
+
+static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct gfs2_fh_obj *fh_obj = (struct gfs2_fh_obj *)inum_obj;
+ struct gfs2_inum *inum = &fh_obj->this;
+ struct gfs2_holder i_gh, ri_gh, rgd_gh;
+ struct gfs2_rgrpd *rgd;
+ struct inode *inode;
+ struct dentry *dentry;
+ int error;
+
+ /* System files? */
+
+ inode = gfs2_ilookup(sb, inum);
+ if (inode) {
+ if (GFS2_I(inode)->i_num.no_formal_ino != inum->no_formal_ino) {
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
+ goto out_inode;
+ }
+
+ error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
+ LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
+ &i_gh);
+ if (error)
+ return ERR_PTR(error);
+
+ error = gfs2_rindex_hold(sdp, &ri_gh);
+ if (error)
+ goto fail;
+
+ error = -EINVAL;
+ rgd = gfs2_blk2rgrpd(sdp, inum->no_addr);
+ if (!rgd)
+ goto fail_rindex;
+
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_SHARED, 0, &rgd_gh);
+ if (error)
+ goto fail_rindex;
+
+ error = -ESTALE;
+ if (gfs2_get_block_type(rgd, inum->no_addr) != GFS2_BLKST_DINODE)
+ goto fail_rgd;
+
+ gfs2_glock_dq_uninit(&rgd_gh);
+ gfs2_glock_dq_uninit(&ri_gh);
+
+ inode = gfs2_inode_lookup(sb, inum, fh_obj->imode);
+ if (!inode)
+ goto fail;
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ goto fail;
+ }
+
+ error = gfs2_inode_refresh(GFS2_I(inode));
+ if (error) {
+ iput(inode);
+ goto fail;
+ }
+
+ error = -EIO;
+ if (GFS2_I(inode)->i_di.di_flags & GFS2_DIF_SYSTEM) {
+ iput(inode);
+ goto fail;
+ }
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+out_inode:
+ dentry = d_alloc_anon(inode);
+ if (!dentry) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return dentry;
+
+fail_rgd:
+ gfs2_glock_dq_uninit(&rgd_gh);
+
+fail_rindex:
+ gfs2_glock_dq_uninit(&ri_gh);
+
+fail:
+ gfs2_glock_dq_uninit(&i_gh);
+ return ERR_PTR(error);
+}
+
+struct export_operations gfs2_export_ops = {
+ .decode_fh = gfs2_decode_fh,
+ .encode_fh = gfs2_encode_fh,
+ .get_name = gfs2_get_name,
+ .get_parent = gfs2_get_parent,
+ .get_dentry = gfs2_get_dentry,
+};
+
diff --git a/fs/gfs2/ops_export.h b/fs/gfs2/ops_export.h
new file mode 100644
index 000000000000..09aca5046fb1
--- /dev/null
+++ b/fs/gfs2/ops_export.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_EXPORT_DOT_H__
+#define __OPS_EXPORT_DOT_H__
+
+#define GFS2_SMALL_FH_SIZE 4
+#define GFS2_LARGE_FH_SIZE 10
+
+extern struct export_operations gfs2_export_ops;
+struct gfs2_fh_obj {
+ struct gfs2_inum this;
+ __u32 imode;
+};
+
+#endif /* __OPS_EXPORT_DOT_H__ */
diff --git a/fs/gfs2/ops_file.c b/fs/gfs2/ops_file.c
new file mode 100644
index 000000000000..3064f133bf3c
--- /dev/null
+++ b/fs/gfs2/ops_file.c
@@ -0,0 +1,661 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/pagemap.h>
+#include <linux/uio.h>
+#include <linux/blkdev.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/fs.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/ext2_fs.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "dir.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "lm.h"
+#include "log.h"
+#include "meta_io.h"
+#include "ops_file.h"
+#include "ops_vm.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+#include "eaops.h"
+
+/* For regular, non-NFS */
+struct filldir_reg {
+ struct gfs2_sbd *fdr_sbd;
+ int fdr_prefetch;
+
+ filldir_t fdr_filldir;
+ void *fdr_opaque;
+};
+
+/*
+ * Most fields left uninitialised to catch anybody who tries to
+ * use them. f_flags set to prevent file_accessed() from touching
+ * any other part of this. Its use is purely as a flag so that we
+ * know (in readpage()) whether or not do to locking.
+ */
+struct file gfs2_internal_file_sentinel = {
+ .f_flags = O_NOATIME|O_RDONLY,
+};
+
+static int gfs2_read_actor(read_descriptor_t *desc, struct page *page,
+ unsigned long offset, unsigned long size)
+{
+ char *kaddr;
+ unsigned long count = desc->count;
+
+ if (size > count)
+ size = count;
+
+ kaddr = kmap(page);
+ memcpy(desc->arg.buf, kaddr + offset, size);
+ kunmap(page);
+
+ desc->count = count - size;
+ desc->written += size;
+ desc->arg.buf += size;
+ return size;
+}
+
+int gfs2_internal_read(struct gfs2_inode *ip, struct file_ra_state *ra_state,
+ char *buf, loff_t *pos, unsigned size)
+{
+ struct inode *inode = &ip->i_inode;
+ read_descriptor_t desc;
+ desc.written = 0;
+ desc.arg.buf = buf;
+ desc.count = size;
+ desc.error = 0;
+ do_generic_mapping_read(inode->i_mapping, ra_state,
+ &gfs2_internal_file_sentinel, pos, &desc,
+ gfs2_read_actor);
+ return desc.written ? desc.written : desc.error;
+}
+
+/**
+ * gfs2_llseek - seek to a location in a file
+ * @file: the file
+ * @offset: the offset
+ * @origin: Where to seek from (SEEK_SET, SEEK_CUR, or SEEK_END)
+ *
+ * SEEK_END requires the glock for the file because it references the
+ * file's size.
+ *
+ * Returns: The new offset, or errno
+ */
+
+static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
+{
+ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+ struct gfs2_holder i_gh;
+ loff_t error;
+
+ if (origin == 2) {
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
+ &i_gh);
+ if (!error) {
+ error = remote_llseek(file, offset, origin);
+ gfs2_glock_dq_uninit(&i_gh);
+ }
+ } else
+ error = remote_llseek(file, offset, origin);
+
+ return error;
+}
+
+/**
+ * filldir_func - Report a directory entry to the caller of gfs2_dir_read()
+ * @opaque: opaque data used by the function
+ * @name: the name of the directory entry
+ * @length: the length of the name
+ * @offset: the entry's offset in the directory
+ * @inum: the inode number the entry points to
+ * @type: the type of inode the entry points to
+ *
+ * Returns: 0 on success, 1 if buffer full
+ */
+
+static int filldir_func(void *opaque, const char *name, unsigned int length,
+ u64 offset, struct gfs2_inum *inum,
+ unsigned int type)
+{
+ struct filldir_reg *fdr = (struct filldir_reg *)opaque;
+ struct gfs2_sbd *sdp = fdr->fdr_sbd;
+ int error;
+
+ error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset,
+ inum->no_addr, type);
+ if (error)
+ return 1;
+
+ if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) {
+ gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops,
+ LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY);
+ gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops,
+ LM_ST_SHARED, LM_FLAG_TRY);
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_readdir - Read directory entries from a directory
+ * @file: The directory to read from
+ * @dirent: Buffer for dirents
+ * @filldir: Function used to do the copying
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
+{
+ struct inode *dir = file->f_mapping->host;
+ struct gfs2_inode *dip = GFS2_I(dir);
+ struct filldir_reg fdr;
+ struct gfs2_holder d_gh;
+ u64 offset = file->f_pos;
+ int error;
+
+ fdr.fdr_sbd = GFS2_SB(dir);
+ fdr.fdr_prefetch = 1;
+ fdr.fdr_filldir = filldir;
+ fdr.fdr_opaque = dirent;
+
+ gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh);
+ error = gfs2_glock_nq_atime(&d_gh);
+ if (error) {
+ gfs2_holder_uninit(&d_gh);
+ return error;
+ }
+
+ error = gfs2_dir_read(dir, &offset, &fdr, filldir_func);
+
+ gfs2_glock_dq_uninit(&d_gh);
+
+ file->f_pos = offset;
+
+ return error;
+}
+
+/**
+ * fsflags_cvt
+ * @table: A table of 32 u32 flags
+ * @val: a 32 bit value to convert
+ *
+ * This function can be used to convert between fsflags values and
+ * GFS2's own flags values.
+ *
+ * Returns: the converted flags
+ */
+static u32 fsflags_cvt(const u32 *table, u32 val)
+{
+ u32 res = 0;
+ while(val) {
+ if (val & 1)
+ res |= *table;
+ table++;
+ val >>= 1;
+ }
+ return res;
+}
+
+static const u32 fsflags_to_gfs2[32] = {
+ [3] = GFS2_DIF_SYNC,
+ [4] = GFS2_DIF_IMMUTABLE,
+ [5] = GFS2_DIF_APPENDONLY,
+ [7] = GFS2_DIF_NOATIME,
+ [12] = GFS2_DIF_EXHASH,
+ [14] = GFS2_DIF_JDATA,
+ [20] = GFS2_DIF_DIRECTIO,
+};
+
+static const u32 gfs2_to_fsflags[32] = {
+ [gfs2fl_Sync] = FS_SYNC_FL,
+ [gfs2fl_Immutable] = FS_IMMUTABLE_FL,
+ [gfs2fl_AppendOnly] = FS_APPEND_FL,
+ [gfs2fl_NoAtime] = FS_NOATIME_FL,
+ [gfs2fl_ExHash] = FS_INDEX_FL,
+ [gfs2fl_Jdata] = FS_JOURNAL_DATA_FL,
+ [gfs2fl_Directio] = FS_DIRECTIO_FL,
+ [gfs2fl_InheritDirectio] = FS_DIRECTIO_FL,
+ [gfs2fl_InheritJdata] = FS_JOURNAL_DATA_FL,
+};
+
+static int gfs2_get_flags(struct file *filp, u32 __user *ptr)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder gh;
+ int error;
+ u32 fsflags;
+
+ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+ error = gfs2_glock_nq_m_atime(1, &gh);
+ if (error)
+ return error;
+
+ fsflags = fsflags_cvt(gfs2_to_fsflags, ip->i_di.di_flags);
+ if (put_user(fsflags, ptr))
+ error = -EFAULT;
+
+ gfs2_glock_dq_m(1, &gh);
+ gfs2_holder_uninit(&gh);
+ return error;
+}
+
+/* Flags that can be set by user space */
+#define GFS2_FLAGS_USER_SET (GFS2_DIF_JDATA| \
+ GFS2_DIF_DIRECTIO| \
+ GFS2_DIF_IMMUTABLE| \
+ GFS2_DIF_APPENDONLY| \
+ GFS2_DIF_NOATIME| \
+ GFS2_DIF_SYNC| \
+ GFS2_DIF_SYSTEM| \
+ GFS2_DIF_INHERIT_DIRECTIO| \
+ GFS2_DIF_INHERIT_JDATA)
+
+/**
+ * gfs2_set_flags - set flags on an inode
+ * @inode: The inode
+ * @flags: The flags to set
+ * @mask: Indicates which flags are valid
+ *
+ */
+static int do_gfs2_set_flags(struct file *filp, u32 reqflags, u32 mask)
+{
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct buffer_head *bh;
+ struct gfs2_holder gh;
+ int error;
+ u32 new_flags, flags;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+ if (error)
+ return error;
+
+ flags = ip->i_di.di_flags;
+ new_flags = (flags & ~mask) | (reqflags & mask);
+ if ((new_flags ^ flags) == 0)
+ goto out;
+
+ if (S_ISDIR(inode->i_mode)) {
+ if ((new_flags ^ flags) & GFS2_DIF_JDATA)
+ new_flags ^= (GFS2_DIF_JDATA|GFS2_DIF_INHERIT_JDATA);
+ if ((new_flags ^ flags) & GFS2_DIF_DIRECTIO)
+ new_flags ^= (GFS2_DIF_DIRECTIO|GFS2_DIF_INHERIT_DIRECTIO);
+ }
+
+ error = -EINVAL;
+ if ((new_flags ^ flags) & ~GFS2_FLAGS_USER_SET)
+ goto out;
+
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) && (new_flags & GFS2_DIF_IMMUTABLE))
+ goto out;
+ if (IS_APPEND(inode) && (new_flags & GFS2_DIF_APPENDONLY))
+ goto out;
+ if (((new_flags ^ flags) & GFS2_DIF_IMMUTABLE) &&
+ !capable(CAP_LINUX_IMMUTABLE))
+ goto out;
+ if (!IS_IMMUTABLE(inode)) {
+ error = permission(inode, MAY_WRITE, NULL);
+ if (error)
+ goto out;
+ }
+
+ error = gfs2_trans_begin(sdp, RES_DINODE, 0);
+ if (error)
+ goto out;
+ error = gfs2_meta_inode_buffer(ip, &bh);
+ if (error)
+ goto out_trans_end;
+ gfs2_trans_add_bh(ip->i_gl, bh, 1);
+ ip->i_di.di_flags = new_flags;
+ gfs2_dinode_out(&ip->i_di, bh->b_data);
+ brelse(bh);
+out_trans_end:
+ gfs2_trans_end(sdp);
+out:
+ gfs2_glock_dq_uninit(&gh);
+ return error;
+}
+
+static int gfs2_set_flags(struct file *filp, u32 __user *ptr)
+{
+ u32 fsflags, gfsflags;
+ if (get_user(fsflags, ptr))
+ return -EFAULT;
+ gfsflags = fsflags_cvt(fsflags_to_gfs2, fsflags);
+ return do_gfs2_set_flags(filp, gfsflags, ~0);
+}
+
+static long gfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ switch(cmd) {
+ case FS_IOC_GETFLAGS:
+ return gfs2_get_flags(filp, (u32 __user *)arg);
+ case FS_IOC_SETFLAGS:
+ return gfs2_set_flags(filp, (u32 __user *)arg);
+ }
+ return -ENOTTY;
+}
+
+
+/**
+ * gfs2_mmap -
+ * @file: The file to map
+ * @vma: The VMA which described the mapping
+ *
+ * Returns: 0 or error code
+ */
+
+static int gfs2_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+ struct gfs2_holder i_gh;
+ int error;
+
+ gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &i_gh);
+ error = gfs2_glock_nq_atime(&i_gh);
+ if (error) {
+ gfs2_holder_uninit(&i_gh);
+ return error;
+ }
+
+ /* This is VM_MAYWRITE instead of VM_WRITE because a call
+ to mprotect() can turn on VM_WRITE later. */
+
+ if ((vma->vm_flags & (VM_MAYSHARE | VM_MAYWRITE)) ==
+ (VM_MAYSHARE | VM_MAYWRITE))
+ vma->vm_ops = &gfs2_vm_ops_sharewrite;
+ else
+ vma->vm_ops = &gfs2_vm_ops_private;
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+ return error;
+}
+
+/**
+ * gfs2_open - open a file
+ * @inode: the inode to open
+ * @file: the struct file for this opening
+ *
+ * Returns: errno
+ */
+
+static int gfs2_open(struct inode *inode, struct file *file)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder i_gh;
+ struct gfs2_file *fp;
+ int error;
+
+ fp = kzalloc(sizeof(struct gfs2_file), GFP_KERNEL);
+ if (!fp)
+ return -ENOMEM;
+
+ mutex_init(&fp->f_fl_mutex);
+
+ gfs2_assert_warn(GFS2_SB(inode), !file->private_data);
+ file->private_data = fp;
+
+ if (S_ISREG(ip->i_di.di_mode)) {
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY,
+ &i_gh);
+ if (error)
+ goto fail;
+
+ if (!(file->f_flags & O_LARGEFILE) &&
+ ip->i_di.di_size > MAX_NON_LFS) {
+ error = -EFBIG;
+ goto fail_gunlock;
+ }
+
+ /* Listen to the Direct I/O flag */
+
+ if (ip->i_di.di_flags & GFS2_DIF_DIRECTIO)
+ file->f_flags |= O_DIRECT;
+
+ gfs2_glock_dq_uninit(&i_gh);
+ }
+
+ return 0;
+
+fail_gunlock:
+ gfs2_glock_dq_uninit(&i_gh);
+fail:
+ file->private_data = NULL;
+ kfree(fp);
+ return error;
+}
+
+/**
+ * gfs2_close - called to close a struct file
+ * @inode: the inode the struct file belongs to
+ * @file: the struct file being closed
+ *
+ * Returns: errno
+ */
+
+static int gfs2_close(struct inode *inode, struct file *file)
+{
+ struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+ struct gfs2_file *fp;
+
+ fp = file->private_data;
+ file->private_data = NULL;
+
+ if (gfs2_assert_warn(sdp, fp))
+ return -EIO;
+
+ kfree(fp);
+
+ return 0;
+}
+
+/**
+ * gfs2_fsync - sync the dirty data for a file (across the cluster)
+ * @file: the file that points to the dentry (we ignore this)
+ * @dentry: the dentry that points to the inode to sync
+ *
+ * Returns: errno
+ */
+
+static int gfs2_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+
+ gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
+
+ return 0;
+}
+
+/**
+ * gfs2_lock - acquire/release a posix lock on a file
+ * @file: the file pointer
+ * @cmd: either modify or retrieve lock state, possibly wait
+ * @fl: type and range of lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_lock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+ struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
+ struct lm_lockname name =
+ { .ln_number = ip->i_num.no_addr,
+ .ln_type = LM_TYPE_PLOCK };
+
+ if (!(fl->fl_flags & FL_POSIX))
+ return -ENOLCK;
+ if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ return -ENOLCK;
+
+ if (sdp->sd_args.ar_localflocks) {
+ if (IS_GETLK(cmd)) {
+ struct file_lock tmp;
+ int ret;
+ ret = posix_test_lock(file, fl, &tmp);
+ fl->fl_type = F_UNLCK;
+ if (ret)
+ memcpy(fl, &tmp, sizeof(struct file_lock));
+ return 0;
+ } else {
+ return posix_lock_file_wait(file, fl);
+ }
+ }
+
+ if (IS_GETLK(cmd))
+ return gfs2_lm_plock_get(sdp, &name, file, fl);
+ else if (fl->fl_type == F_UNLCK)
+ return gfs2_lm_punlock(sdp, &name, file, fl);
+ else
+ return gfs2_lm_plock(sdp, &name, file, cmd, fl);
+}
+
+static int do_flock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct gfs2_file *fp = file->private_data;
+ struct gfs2_holder *fl_gh = &fp->f_fl_gh;
+ struct gfs2_inode *ip = GFS2_I(file->f_dentry->d_inode);
+ struct gfs2_glock *gl;
+ unsigned int state;
+ int flags;
+ int error = 0;
+
+ state = (fl->fl_type == F_WRLCK) ? LM_ST_EXCLUSIVE : LM_ST_SHARED;
+ flags = (IS_SETLKW(cmd) ? 0 : LM_FLAG_TRY) | GL_EXACT | GL_NOCACHE;
+
+ mutex_lock(&fp->f_fl_mutex);
+
+ gl = fl_gh->gh_gl;
+ if (gl) {
+ if (fl_gh->gh_state == state)
+ goto out;
+ gfs2_glock_hold(gl);
+ flock_lock_file_wait(file,
+ &(struct file_lock){.fl_type = F_UNLCK});
+ gfs2_glock_dq_uninit(fl_gh);
+ } else {
+ error = gfs2_glock_get(GFS2_SB(&ip->i_inode),
+ ip->i_num.no_addr, &gfs2_flock_glops,
+ CREATE, &gl);
+ if (error)
+ goto out;
+ }
+
+ gfs2_holder_init(gl, state, flags, fl_gh);
+ gfs2_glock_put(gl);
+
+ error = gfs2_glock_nq(fl_gh);
+ if (error) {
+ gfs2_holder_uninit(fl_gh);
+ if (error == GLR_TRYFAILED)
+ error = -EAGAIN;
+ } else {
+ error = flock_lock_file_wait(file, fl);
+ gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error);
+ }
+
+out:
+ mutex_unlock(&fp->f_fl_mutex);
+ return error;
+}
+
+static void do_unflock(struct file *file, struct file_lock *fl)
+{
+ struct gfs2_file *fp = file->private_data;
+ struct gfs2_holder *fl_gh = &fp->f_fl_gh;
+
+ mutex_lock(&fp->f_fl_mutex);
+ flock_lock_file_wait(file, fl);
+ if (fl_gh->gh_gl)
+ gfs2_glock_dq_uninit(fl_gh);
+ mutex_unlock(&fp->f_fl_mutex);
+}
+
+/**
+ * gfs2_flock - acquire/release a flock lock on a file
+ * @file: the file pointer
+ * @cmd: either modify or retrieve lock state, possibly wait
+ * @fl: type and range of lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_flock(struct file *file, int cmd, struct file_lock *fl)
+{
+ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+ struct gfs2_sbd *sdp = GFS2_SB(file->f_mapping->host);
+
+ if (!(fl->fl_flags & FL_FLOCK))
+ return -ENOLCK;
+ if ((ip->i_di.di_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+ return -ENOLCK;
+
+ if (sdp->sd_args.ar_localflocks)
+ return flock_lock_file_wait(file, fl);
+
+ if (fl->fl_type == F_UNLCK) {
+ do_unflock(file, fl);
+ return 0;
+ } else {
+ return do_flock(file, cmd, fl);
+ }
+}
+
+const struct file_operations gfs2_file_fops = {
+ .llseek = gfs2_llseek,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
+ .unlocked_ioctl = gfs2_ioctl,
+ .mmap = gfs2_mmap,
+ .open = gfs2_open,
+ .release = gfs2_close,
+ .fsync = gfs2_fsync,
+ .lock = gfs2_lock,
+ .sendfile = generic_file_sendfile,
+ .flock = gfs2_flock,
+ .splice_read = generic_file_splice_read,
+ .splice_write = generic_file_splice_write,
+};
+
+const struct file_operations gfs2_dir_fops = {
+ .readdir = gfs2_readdir,
+ .unlocked_ioctl = gfs2_ioctl,
+ .open = gfs2_open,
+ .release = gfs2_close,
+ .fsync = gfs2_fsync,
+ .lock = gfs2_lock,
+ .flock = gfs2_flock,
+};
+
diff --git a/fs/gfs2/ops_file.h b/fs/gfs2/ops_file.h
new file mode 100644
index 000000000000..ce319f89ec8e
--- /dev/null
+++ b/fs/gfs2/ops_file.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_FILE_DOT_H__
+#define __OPS_FILE_DOT_H__
+
+#include <linux/fs.h>
+struct gfs2_inode;
+
+extern struct file gfs2_internal_file_sentinel;
+extern int gfs2_internal_read(struct gfs2_inode *ip,
+ struct file_ra_state *ra_state,
+ char *buf, loff_t *pos, unsigned size);
+
+extern const struct file_operations gfs2_file_fops;
+extern const struct file_operations gfs2_dir_fops;
+
+#endif /* __OPS_FILE_DOT_H__ */
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
new file mode 100644
index 000000000000..882873a6bd69
--- /dev/null
+++ b/fs/gfs2/ops_fstype.c
@@ -0,0 +1,925 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/blkdev.h>
+#include <linux/kthread.h>
+#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "daemon.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "lm.h"
+#include "mount.h"
+#include "ops_export.h"
+#include "ops_fstype.h"
+#include "ops_super.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "super.h"
+#include "sys.h"
+#include "util.h"
+
+#define DO 0
+#define UNDO 1
+
+extern struct dentry_operations gfs2_dops;
+
+static struct gfs2_sbd *init_sbd(struct super_block *sb)
+{
+ struct gfs2_sbd *sdp;
+
+ sdp = kzalloc(sizeof(struct gfs2_sbd), GFP_KERNEL);
+ if (!sdp)
+ return NULL;
+
+ sb->s_fs_info = sdp;
+ sdp->sd_vfs = sb;
+
+ gfs2_tune_init(&sdp->sd_tune);
+
+ INIT_LIST_HEAD(&sdp->sd_reclaim_list);
+ spin_lock_init(&sdp->sd_reclaim_lock);
+ init_waitqueue_head(&sdp->sd_reclaim_wq);
+
+ mutex_init(&sdp->sd_inum_mutex);
+ spin_lock_init(&sdp->sd_statfs_spin);
+ mutex_init(&sdp->sd_statfs_mutex);
+
+ spin_lock_init(&sdp->sd_rindex_spin);
+ mutex_init(&sdp->sd_rindex_mutex);
+ INIT_LIST_HEAD(&sdp->sd_rindex_list);
+ INIT_LIST_HEAD(&sdp->sd_rindex_mru_list);
+ INIT_LIST_HEAD(&sdp->sd_rindex_recent_list);
+
+ INIT_LIST_HEAD(&sdp->sd_jindex_list);
+ spin_lock_init(&sdp->sd_jindex_spin);
+ mutex_init(&sdp->sd_jindex_mutex);
+
+ INIT_LIST_HEAD(&sdp->sd_quota_list);
+ spin_lock_init(&sdp->sd_quota_spin);
+ mutex_init(&sdp->sd_quota_mutex);
+
+ spin_lock_init(&sdp->sd_log_lock);
+
+ INIT_LIST_HEAD(&sdp->sd_log_le_gl);
+ INIT_LIST_HEAD(&sdp->sd_log_le_buf);
+ INIT_LIST_HEAD(&sdp->sd_log_le_revoke);
+ INIT_LIST_HEAD(&sdp->sd_log_le_rg);
+ INIT_LIST_HEAD(&sdp->sd_log_le_databuf);
+
+ mutex_init(&sdp->sd_log_reserve_mutex);
+ INIT_LIST_HEAD(&sdp->sd_ail1_list);
+ INIT_LIST_HEAD(&sdp->sd_ail2_list);
+
+ init_rwsem(&sdp->sd_log_flush_lock);
+ INIT_LIST_HEAD(&sdp->sd_log_flush_list);
+
+ INIT_LIST_HEAD(&sdp->sd_revoke_list);
+
+ mutex_init(&sdp->sd_freeze_lock);
+
+ return sdp;
+}
+
+static void init_vfs(struct super_block *sb, unsigned noatime)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+
+ sb->s_magic = GFS2_MAGIC;
+ sb->s_op = &gfs2_super_ops;
+ sb->s_export_op = &gfs2_export_ops;
+ sb->s_maxbytes = MAX_LFS_FILESIZE;
+
+ if (sb->s_flags & (MS_NOATIME | MS_NODIRATIME))
+ set_bit(noatime, &sdp->sd_flags);
+
+ /* Don't let the VFS update atimes. GFS2 handles this itself. */
+ sb->s_flags |= MS_NOATIME | MS_NODIRATIME;
+}
+
+static int init_names(struct gfs2_sbd *sdp, int silent)
+{
+ struct page *page;
+ char *proto, *table;
+ int error = 0;
+
+ proto = sdp->sd_args.ar_lockproto;
+ table = sdp->sd_args.ar_locktable;
+
+ /* Try to autodetect */
+
+ if (!proto[0] || !table[0]) {
+ struct gfs2_sb *sb;
+ page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
+ if (!page)
+ return -ENOBUFS;
+ sb = kmap(page);
+ gfs2_sb_in(&sdp->sd_sb, sb);
+ kunmap(page);
+ __free_page(page);
+
+ error = gfs2_check_sb(sdp, &sdp->sd_sb, silent);
+ if (error)
+ goto out;
+
+ if (!proto[0])
+ proto = sdp->sd_sb.sb_lockproto;
+ if (!table[0])
+ table = sdp->sd_sb.sb_locktable;
+ }
+
+ if (!table[0])
+ table = sdp->sd_vfs->s_id;
+
+ snprintf(sdp->sd_proto_name, GFS2_FSNAME_LEN, "%s", proto);
+ snprintf(sdp->sd_table_name, GFS2_FSNAME_LEN, "%s", table);
+
+out:
+ return error;
+}
+
+static int init_locking(struct gfs2_sbd *sdp, struct gfs2_holder *mount_gh,
+ int undo)
+{
+ struct task_struct *p;
+ int error = 0;
+
+ if (undo)
+ goto fail_trans;
+
+ p = kthread_run(gfs2_scand, sdp, "gfs2_scand");
+ error = IS_ERR(p);
+ if (error) {
+ fs_err(sdp, "can't start scand thread: %d\n", error);
+ return error;
+ }
+ sdp->sd_scand_process = p;
+
+ for (sdp->sd_glockd_num = 0;
+ sdp->sd_glockd_num < sdp->sd_args.ar_num_glockd;
+ sdp->sd_glockd_num++) {
+ p = kthread_run(gfs2_glockd, sdp, "gfs2_glockd");
+ error = IS_ERR(p);
+ if (error) {
+ fs_err(sdp, "can't start glockd thread: %d\n", error);
+ goto fail;
+ }
+ sdp->sd_glockd_process[sdp->sd_glockd_num] = p;
+ }
+
+ error = gfs2_glock_nq_num(sdp,
+ GFS2_MOUNT_LOCK, &gfs2_nondisk_glops,
+ LM_ST_EXCLUSIVE, LM_FLAG_NOEXP | GL_NOCACHE,
+ mount_gh);
+ if (error) {
+ fs_err(sdp, "can't acquire mount glock: %d\n", error);
+ goto fail;
+ }
+
+ error = gfs2_glock_nq_num(sdp,
+ GFS2_LIVE_LOCK, &gfs2_nondisk_glops,
+ LM_ST_SHARED,
+ LM_FLAG_NOEXP | GL_EXACT,
+ &sdp->sd_live_gh);
+ if (error) {
+ fs_err(sdp, "can't acquire live glock: %d\n", error);
+ goto fail_mount;
+ }
+
+ error = gfs2_glock_get(sdp, GFS2_RENAME_LOCK, &gfs2_nondisk_glops,
+ CREATE, &sdp->sd_rename_gl);
+ if (error) {
+ fs_err(sdp, "can't create rename glock: %d\n", error);
+ goto fail_live;
+ }
+
+ error = gfs2_glock_get(sdp, GFS2_TRANS_LOCK, &gfs2_trans_glops,
+ CREATE, &sdp->sd_trans_gl);
+ if (error) {
+ fs_err(sdp, "can't create transaction glock: %d\n", error);
+ goto fail_rename;
+ }
+ set_bit(GLF_STICKY, &sdp->sd_trans_gl->gl_flags);
+
+ return 0;
+
+fail_trans:
+ gfs2_glock_put(sdp->sd_trans_gl);
+fail_rename:
+ gfs2_glock_put(sdp->sd_rename_gl);
+fail_live:
+ gfs2_glock_dq_uninit(&sdp->sd_live_gh);
+fail_mount:
+ gfs2_glock_dq_uninit(mount_gh);
+fail:
+ while (sdp->sd_glockd_num--)
+ kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
+
+ kthread_stop(sdp->sd_scand_process);
+ return error;
+}
+
+static struct inode *gfs2_lookup_root(struct super_block *sb,
+ struct gfs2_inum *inum)
+{
+ return gfs2_inode_lookup(sb, inum, DT_DIR);
+}
+
+static int init_sb(struct gfs2_sbd *sdp, int silent, int undo)
+{
+ struct super_block *sb = sdp->sd_vfs;
+ struct gfs2_holder sb_gh;
+ struct gfs2_inum *inum;
+ struct inode *inode;
+ int error = 0;
+
+ if (undo) {
+ if (sb->s_root) {
+ dput(sb->s_root);
+ sb->s_root = NULL;
+ }
+ return 0;
+ }
+
+ error = gfs2_glock_nq_num(sdp, GFS2_SB_LOCK, &gfs2_meta_glops,
+ LM_ST_SHARED, 0, &sb_gh);
+ if (error) {
+ fs_err(sdp, "can't acquire superblock glock: %d\n", error);
+ return error;
+ }
+
+ error = gfs2_read_sb(sdp, sb_gh.gh_gl, silent);
+ if (error) {
+ fs_err(sdp, "can't read superblock: %d\n", error);
+ goto out;
+ }
+
+ /* Set up the buffer cache and SB for real */
+ if (sdp->sd_sb.sb_bsize < bdev_hardsect_size(sb->s_bdev)) {
+ error = -EINVAL;
+ fs_err(sdp, "FS block size (%u) is too small for device "
+ "block size (%u)\n",
+ sdp->sd_sb.sb_bsize, bdev_hardsect_size(sb->s_bdev));
+ goto out;
+ }
+ if (sdp->sd_sb.sb_bsize > PAGE_SIZE) {
+ error = -EINVAL;
+ fs_err(sdp, "FS block size (%u) is too big for machine "
+ "page size (%u)\n",
+ sdp->sd_sb.sb_bsize, (unsigned int)PAGE_SIZE);
+ goto out;
+ }
+ sb_set_blocksize(sb, sdp->sd_sb.sb_bsize);
+
+ /* Get the root inode */
+ inum = &sdp->sd_sb.sb_root_dir;
+ if (sb->s_type == &gfs2meta_fs_type)
+ inum = &sdp->sd_sb.sb_master_dir;
+ inode = gfs2_lookup_root(sb, inum);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ fs_err(sdp, "can't read in root inode: %d\n", error);
+ goto out;
+ }
+
+ sb->s_root = d_alloc_root(inode);
+ if (!sb->s_root) {
+ fs_err(sdp, "can't get root dentry\n");
+ error = -ENOMEM;
+ iput(inode);
+ }
+ sb->s_root->d_op = &gfs2_dops;
+out:
+ gfs2_glock_dq_uninit(&sb_gh);
+ return error;
+}
+
+static int init_journal(struct gfs2_sbd *sdp, int undo)
+{
+ struct gfs2_holder ji_gh;
+ struct task_struct *p;
+ struct gfs2_inode *ip;
+ int jindex = 1;
+ int error = 0;
+
+ if (undo) {
+ jindex = 0;
+ goto fail_recoverd;
+ }
+
+ sdp->sd_jindex = gfs2_lookup_simple(sdp->sd_master_dir, "jindex");
+ if (IS_ERR(sdp->sd_jindex)) {
+ fs_err(sdp, "can't lookup journal index: %d\n", error);
+ return PTR_ERR(sdp->sd_jindex);
+ }
+ ip = GFS2_I(sdp->sd_jindex);
+ set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
+
+ /* Load in the journal index special file */
+
+ error = gfs2_jindex_hold(sdp, &ji_gh);
+ if (error) {
+ fs_err(sdp, "can't read journal index: %d\n", error);
+ goto fail;
+ }
+
+ error = -EINVAL;
+ if (!gfs2_jindex_size(sdp)) {
+ fs_err(sdp, "no journals!\n");
+ goto fail_jindex;
+ }
+
+ if (sdp->sd_args.ar_spectator) {
+ sdp->sd_jdesc = gfs2_jdesc_find(sdp, 0);
+ sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
+ } else {
+ if (sdp->sd_lockstruct.ls_jid >= gfs2_jindex_size(sdp)) {
+ fs_err(sdp, "can't mount journal #%u\n",
+ sdp->sd_lockstruct.ls_jid);
+ fs_err(sdp, "there are only %u journals (0 - %u)\n",
+ gfs2_jindex_size(sdp),
+ gfs2_jindex_size(sdp) - 1);
+ goto fail_jindex;
+ }
+ sdp->sd_jdesc = gfs2_jdesc_find(sdp, sdp->sd_lockstruct.ls_jid);
+
+ error = gfs2_glock_nq_num(sdp, sdp->sd_lockstruct.ls_jid,
+ &gfs2_journal_glops,
+ LM_ST_EXCLUSIVE, LM_FLAG_NOEXP,
+ &sdp->sd_journal_gh);
+ if (error) {
+ fs_err(sdp, "can't acquire journal glock: %d\n", error);
+ goto fail_jindex;
+ }
+
+ ip = GFS2_I(sdp->sd_jdesc->jd_inode);
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
+ LM_FLAG_NOEXP | GL_EXACT,
+ &sdp->sd_jinode_gh);
+ if (error) {
+ fs_err(sdp, "can't acquire journal inode glock: %d\n",
+ error);
+ goto fail_journal_gh;
+ }
+
+ error = gfs2_jdesc_check(sdp->sd_jdesc);
+ if (error) {
+ fs_err(sdp, "my journal (%u) is bad: %d\n",
+ sdp->sd_jdesc->jd_jid, error);
+ goto fail_jinode_gh;
+ }
+ sdp->sd_log_blks_free = sdp->sd_jdesc->jd_blocks;
+ }
+
+ if (sdp->sd_lockstruct.ls_first) {
+ unsigned int x;
+ for (x = 0; x < sdp->sd_journals; x++) {
+ error = gfs2_recover_journal(gfs2_jdesc_find(sdp, x));
+ if (error) {
+ fs_err(sdp, "error recovering journal %u: %d\n",
+ x, error);
+ goto fail_jinode_gh;
+ }
+ }
+
+ gfs2_lm_others_may_mount(sdp);
+ } else if (!sdp->sd_args.ar_spectator) {
+ error = gfs2_recover_journal(sdp->sd_jdesc);
+ if (error) {
+ fs_err(sdp, "error recovering my journal: %d\n", error);
+ goto fail_jinode_gh;
+ }
+ }
+
+ set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
+ gfs2_glock_dq_uninit(&ji_gh);
+ jindex = 0;
+
+ p = kthread_run(gfs2_recoverd, sdp, "gfs2_recoverd");
+ error = IS_ERR(p);
+ if (error) {
+ fs_err(sdp, "can't start recoverd thread: %d\n", error);
+ goto fail_jinode_gh;
+ }
+ sdp->sd_recoverd_process = p;
+
+ return 0;
+
+fail_recoverd:
+ kthread_stop(sdp->sd_recoverd_process);
+fail_jinode_gh:
+ if (!sdp->sd_args.ar_spectator)
+ gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
+fail_journal_gh:
+ if (!sdp->sd_args.ar_spectator)
+ gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
+fail_jindex:
+ gfs2_jindex_free(sdp);
+ if (jindex)
+ gfs2_glock_dq_uninit(&ji_gh);
+fail:
+ iput(sdp->sd_jindex);
+ return error;
+}
+
+
+static int init_inodes(struct gfs2_sbd *sdp, int undo)
+{
+ int error = 0;
+ struct gfs2_inode *ip;
+ struct inode *inode;
+
+ if (undo)
+ goto fail_qinode;
+
+ inode = gfs2_lookup_root(sdp->sd_vfs, &sdp->sd_sb.sb_master_dir);
+ if (IS_ERR(inode)) {
+ error = PTR_ERR(inode);
+ fs_err(sdp, "can't read in master directory: %d\n", error);
+ goto fail;
+ }
+ sdp->sd_master_dir = inode;
+
+ error = init_journal(sdp, undo);
+ if (error)
+ goto fail_master;
+
+ /* Read in the master inode number inode */
+ sdp->sd_inum_inode = gfs2_lookup_simple(sdp->sd_master_dir, "inum");
+ if (IS_ERR(sdp->sd_inum_inode)) {
+ error = PTR_ERR(sdp->sd_inum_inode);
+ fs_err(sdp, "can't read in inum inode: %d\n", error);
+ goto fail_journal;
+ }
+
+
+ /* Read in the master statfs inode */
+ sdp->sd_statfs_inode = gfs2_lookup_simple(sdp->sd_master_dir, "statfs");
+ if (IS_ERR(sdp->sd_statfs_inode)) {
+ error = PTR_ERR(sdp->sd_statfs_inode);
+ fs_err(sdp, "can't read in statfs inode: %d\n", error);
+ goto fail_inum;
+ }
+
+ /* Read in the resource index inode */
+ sdp->sd_rindex = gfs2_lookup_simple(sdp->sd_master_dir, "rindex");
+ if (IS_ERR(sdp->sd_rindex)) {
+ error = PTR_ERR(sdp->sd_rindex);
+ fs_err(sdp, "can't get resource index inode: %d\n", error);
+ goto fail_statfs;
+ }
+ ip = GFS2_I(sdp->sd_rindex);
+ set_bit(GLF_STICKY, &ip->i_gl->gl_flags);
+ sdp->sd_rindex_vn = ip->i_gl->gl_vn - 1;
+
+ /* Read in the quota inode */
+ sdp->sd_quota_inode = gfs2_lookup_simple(sdp->sd_master_dir, "quota");
+ if (IS_ERR(sdp->sd_quota_inode)) {
+ error = PTR_ERR(sdp->sd_quota_inode);
+ fs_err(sdp, "can't get quota file inode: %d\n", error);
+ goto fail_rindex;
+ }
+ return 0;
+
+fail_qinode:
+ iput(sdp->sd_quota_inode);
+fail_rindex:
+ gfs2_clear_rgrpd(sdp);
+ iput(sdp->sd_rindex);
+fail_statfs:
+ iput(sdp->sd_statfs_inode);
+fail_inum:
+ iput(sdp->sd_inum_inode);
+fail_journal:
+ init_journal(sdp, UNDO);
+fail_master:
+ iput(sdp->sd_master_dir);
+fail:
+ return error;
+}
+
+static int init_per_node(struct gfs2_sbd *sdp, int undo)
+{
+ struct inode *pn = NULL;
+ char buf[30];
+ int error = 0;
+ struct gfs2_inode *ip;
+
+ if (sdp->sd_args.ar_spectator)
+ return 0;
+
+ if (undo)
+ goto fail_qc_gh;
+
+ pn = gfs2_lookup_simple(sdp->sd_master_dir, "per_node");
+ if (IS_ERR(pn)) {
+ error = PTR_ERR(pn);
+ fs_err(sdp, "can't find per_node directory: %d\n", error);
+ return error;
+ }
+
+ sprintf(buf, "inum_range%u", sdp->sd_jdesc->jd_jid);
+ sdp->sd_ir_inode = gfs2_lookup_simple(pn, buf);
+ if (IS_ERR(sdp->sd_ir_inode)) {
+ error = PTR_ERR(sdp->sd_ir_inode);
+ fs_err(sdp, "can't find local \"ir\" file: %d\n", error);
+ goto fail;
+ }
+
+ sprintf(buf, "statfs_change%u", sdp->sd_jdesc->jd_jid);
+ sdp->sd_sc_inode = gfs2_lookup_simple(pn, buf);
+ if (IS_ERR(sdp->sd_sc_inode)) {
+ error = PTR_ERR(sdp->sd_sc_inode);
+ fs_err(sdp, "can't find local \"sc\" file: %d\n", error);
+ goto fail_ir_i;
+ }
+
+ sprintf(buf, "quota_change%u", sdp->sd_jdesc->jd_jid);
+ sdp->sd_qc_inode = gfs2_lookup_simple(pn, buf);
+ if (IS_ERR(sdp->sd_qc_inode)) {
+ error = PTR_ERR(sdp->sd_qc_inode);
+ fs_err(sdp, "can't find local \"qc\" file: %d\n", error);
+ goto fail_ut_i;
+ }
+
+ iput(pn);
+ pn = NULL;
+
+ ip = GFS2_I(sdp->sd_ir_inode);
+ error = gfs2_glock_nq_init(ip->i_gl,
+ LM_ST_EXCLUSIVE, 0,
+ &sdp->sd_ir_gh);
+ if (error) {
+ fs_err(sdp, "can't lock local \"ir\" file: %d\n", error);
+ goto fail_qc_i;
+ }
+
+ ip = GFS2_I(sdp->sd_sc_inode);
+ error = gfs2_glock_nq_init(ip->i_gl,
+ LM_ST_EXCLUSIVE, 0,
+ &sdp->sd_sc_gh);
+ if (error) {
+ fs_err(sdp, "can't lock local \"sc\" file: %d\n", error);
+ goto fail_ir_gh;
+ }
+
+ ip = GFS2_I(sdp->sd_qc_inode);
+ error = gfs2_glock_nq_init(ip->i_gl,
+ LM_ST_EXCLUSIVE, 0,
+ &sdp->sd_qc_gh);
+ if (error) {
+ fs_err(sdp, "can't lock local \"qc\" file: %d\n", error);
+ goto fail_ut_gh;
+ }
+
+ return 0;
+
+fail_qc_gh:
+ gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
+fail_ut_gh:
+ gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
+fail_ir_gh:
+ gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
+fail_qc_i:
+ iput(sdp->sd_qc_inode);
+fail_ut_i:
+ iput(sdp->sd_sc_inode);
+fail_ir_i:
+ iput(sdp->sd_ir_inode);
+fail:
+ if (pn)
+ iput(pn);
+ return error;
+}
+
+static int init_threads(struct gfs2_sbd *sdp, int undo)
+{
+ struct task_struct *p;
+ int error = 0;
+
+ if (undo)
+ goto fail_quotad;
+
+ sdp->sd_log_flush_time = jiffies;
+ sdp->sd_jindex_refresh_time = jiffies;
+
+ p = kthread_run(gfs2_logd, sdp, "gfs2_logd");
+ error = IS_ERR(p);
+ if (error) {
+ fs_err(sdp, "can't start logd thread: %d\n", error);
+ return error;
+ }
+ sdp->sd_logd_process = p;
+
+ sdp->sd_statfs_sync_time = jiffies;
+ sdp->sd_quota_sync_time = jiffies;
+
+ p = kthread_run(gfs2_quotad, sdp, "gfs2_quotad");
+ error = IS_ERR(p);
+ if (error) {
+ fs_err(sdp, "can't start quotad thread: %d\n", error);
+ goto fail;
+ }
+ sdp->sd_quotad_process = p;
+
+ return 0;
+
+
+fail_quotad:
+ kthread_stop(sdp->sd_quotad_process);
+fail:
+ kthread_stop(sdp->sd_logd_process);
+ return error;
+}
+
+/**
+ * fill_super - Read in superblock
+ * @sb: The VFS superblock
+ * @data: Mount options
+ * @silent: Don't complain if it's not a GFS2 filesystem
+ *
+ * Returns: errno
+ */
+
+static int fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct gfs2_sbd *sdp;
+ struct gfs2_holder mount_gh;
+ int error;
+
+ sdp = init_sbd(sb);
+ if (!sdp) {
+ printk(KERN_WARNING "GFS2: can't alloc struct gfs2_sbd\n");
+ return -ENOMEM;
+ }
+
+ error = gfs2_mount_args(sdp, (char *)data, 0);
+ if (error) {
+ printk(KERN_WARNING "GFS2: can't parse mount arguments\n");
+ goto fail;
+ }
+
+ init_vfs(sb, SDF_NOATIME);
+
+ /* Set up the buffer cache and fill in some fake block size values
+ to allow us to read-in the on-disk superblock. */
+ sdp->sd_sb.sb_bsize = sb_min_blocksize(sb, GFS2_BASIC_BLOCK);
+ sdp->sd_sb.sb_bsize_shift = sb->s_blocksize_bits;
+ sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
+ GFS2_BASIC_BLOCK_SHIFT;
+ sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
+
+ error = init_names(sdp, silent);
+ if (error)
+ goto fail;
+
+ error = gfs2_sys_fs_add(sdp);
+ if (error)
+ goto fail;
+
+ error = gfs2_lm_mount(sdp, silent);
+ if (error)
+ goto fail_sys;
+
+ error = init_locking(sdp, &mount_gh, DO);
+ if (error)
+ goto fail_lm;
+
+ error = init_sb(sdp, silent, DO);
+ if (error)
+ goto fail_locking;
+
+ error = init_inodes(sdp, DO);
+ if (error)
+ goto fail_sb;
+
+ error = init_per_node(sdp, DO);
+ if (error)
+ goto fail_inodes;
+
+ error = gfs2_statfs_init(sdp);
+ if (error) {
+ fs_err(sdp, "can't initialize statfs subsystem: %d\n", error);
+ goto fail_per_node;
+ }
+
+ error = init_threads(sdp, DO);
+ if (error)
+ goto fail_per_node;
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ error = gfs2_make_fs_rw(sdp);
+ if (error) {
+ fs_err(sdp, "can't make FS RW: %d\n", error);
+ goto fail_threads;
+ }
+ }
+
+ gfs2_glock_dq_uninit(&mount_gh);
+
+ return 0;
+
+fail_threads:
+ init_threads(sdp, UNDO);
+fail_per_node:
+ init_per_node(sdp, UNDO);
+fail_inodes:
+ init_inodes(sdp, UNDO);
+fail_sb:
+ init_sb(sdp, 0, UNDO);
+fail_locking:
+ init_locking(sdp, &mount_gh, UNDO);
+fail_lm:
+ gfs2_gl_hash_clear(sdp, WAIT);
+ gfs2_lm_unmount(sdp);
+ while (invalidate_inodes(sb))
+ yield();
+fail_sys:
+ gfs2_sys_fs_del(sdp);
+fail:
+ kfree(sdp);
+ sb->s_fs_info = NULL;
+ return error;
+}
+
+static int gfs2_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ struct super_block *sb;
+ struct gfs2_sbd *sdp;
+ int error = get_sb_bdev(fs_type, flags, dev_name, data, fill_super, mnt);
+ if (error)
+ goto out;
+ sb = mnt->mnt_sb;
+ sdp = sb->s_fs_info;
+ sdp->sd_gfs2mnt = mnt;
+out:
+ return error;
+}
+
+static int fill_super_meta(struct super_block *sb, struct super_block *new,
+ void *data, int silent)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct inode *inode;
+ int error = 0;
+
+ new->s_fs_info = sdp;
+ sdp->sd_vfs_meta = sb;
+
+ init_vfs(new, SDF_NOATIME);
+
+ /* Get the master inode */
+ inode = igrab(sdp->sd_master_dir);
+
+ new->s_root = d_alloc_root(inode);
+ if (!new->s_root) {
+ fs_err(sdp, "can't get root dentry\n");
+ error = -ENOMEM;
+ iput(inode);
+ } else
+ new->s_root->d_op = &gfs2_dops;
+
+ return error;
+}
+
+static int set_bdev_super(struct super_block *s, void *data)
+{
+ s->s_bdev = data;
+ s->s_dev = s->s_bdev->bd_dev;
+ return 0;
+}
+
+static int test_bdev_super(struct super_block *s, void *data)
+{
+ return s->s_bdev == data;
+}
+
+static struct super_block* get_gfs2_sb(const char *dev_name)
+{
+ struct kstat stat;
+ struct nameidata nd;
+ struct file_system_type *fstype;
+ struct super_block *sb = NULL, *s;
+ struct list_head *l;
+ int error;
+
+ error = path_lookup(dev_name, LOOKUP_FOLLOW, &nd);
+ if (error) {
+ printk(KERN_WARNING "GFS2: path_lookup on %s returned error\n",
+ dev_name);
+ goto out;
+ }
+ error = vfs_getattr(nd.mnt, nd.dentry, &stat);
+
+ fstype = get_fs_type("gfs2");
+ list_for_each(l, &fstype->fs_supers) {
+ s = list_entry(l, struct super_block, s_instances);
+ if ((S_ISBLK(stat.mode) && s->s_dev == stat.rdev) ||
+ (S_ISDIR(stat.mode) && s == nd.dentry->d_inode->i_sb)) {
+ sb = s;
+ goto free_nd;
+ }
+ }
+
+ printk(KERN_WARNING "GFS2: Unrecognized block device or "
+ "mount point %s", dev_name);
+
+free_nd:
+ path_release(&nd);
+out:
+ return sb;
+}
+
+static int gfs2_get_sb_meta(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data, struct vfsmount *mnt)
+{
+ int error = 0;
+ struct super_block *sb = NULL, *new;
+ struct gfs2_sbd *sdp;
+
+ sb = get_gfs2_sb(dev_name);
+ if (!sb) {
+ printk(KERN_WARNING "GFS2: gfs2 mount does not exist\n");
+ error = -ENOENT;
+ goto error;
+ }
+ sdp = (struct gfs2_sbd*) sb->s_fs_info;
+ if (sdp->sd_vfs_meta) {
+ printk(KERN_WARNING "GFS2: gfs2meta mount already exists\n");
+ error = -EBUSY;
+ goto error;
+ }
+ mutex_lock(&sb->s_bdev->bd_mount_mutex);
+ new = sget(fs_type, test_bdev_super, set_bdev_super, sb->s_bdev);
+ mutex_unlock(&sb->s_bdev->bd_mount_mutex);
+ if (IS_ERR(new)) {
+ error = PTR_ERR(new);
+ goto error;
+ }
+ module_put(fs_type->owner);
+ new->s_flags = flags;
+ strlcpy(new->s_id, sb->s_id, sizeof(new->s_id));
+ sb_set_blocksize(new, sb->s_blocksize);
+ error = fill_super_meta(sb, new, data, flags & MS_SILENT ? 1 : 0);
+ if (error) {
+ up_write(&new->s_umount);
+ deactivate_super(new);
+ goto error;
+ }
+
+ new->s_flags |= MS_ACTIVE;
+
+ /* Grab a reference to the gfs2 mount point */
+ atomic_inc(&sdp->sd_gfs2mnt->mnt_count);
+ return simple_set_mnt(mnt, new);
+error:
+ return error;
+}
+
+static void gfs2_kill_sb(struct super_block *sb)
+{
+ kill_block_super(sb);
+}
+
+static void gfs2_kill_sb_meta(struct super_block *sb)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ generic_shutdown_super(sb);
+ sdp->sd_vfs_meta = NULL;
+ atomic_dec(&sdp->sd_gfs2mnt->mnt_count);
+}
+
+struct file_system_type gfs2_fs_type = {
+ .name = "gfs2",
+ .fs_flags = FS_REQUIRES_DEV,
+ .get_sb = gfs2_get_sb,
+ .kill_sb = gfs2_kill_sb,
+ .owner = THIS_MODULE,
+};
+
+struct file_system_type gfs2meta_fs_type = {
+ .name = "gfs2meta",
+ .fs_flags = FS_REQUIRES_DEV,
+ .get_sb = gfs2_get_sb_meta,
+ .kill_sb = gfs2_kill_sb_meta,
+ .owner = THIS_MODULE,
+};
+
diff --git a/fs/gfs2/ops_fstype.h b/fs/gfs2/ops_fstype.h
new file mode 100644
index 000000000000..7cc2c296271b
--- /dev/null
+++ b/fs/gfs2/ops_fstype.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_FSTYPE_DOT_H__
+#define __OPS_FSTYPE_DOT_H__
+
+#include <linux/fs.h>
+
+extern struct file_system_type gfs2_fs_type;
+extern struct file_system_type gfs2meta_fs_type;
+
+#endif /* __OPS_FSTYPE_DOT_H__ */
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
new file mode 100644
index 000000000000..ef6e5ed70e94
--- /dev/null
+++ b/fs/gfs2/ops_inode.c
@@ -0,0 +1,1151 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/namei.h>
+#include <linux/utsname.h>
+#include <linux/mm.h>
+#include <linux/xattr.h>
+#include <linux/posix_acl.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "acl.h"
+#include "bmap.h"
+#include "dir.h"
+#include "eaops.h"
+#include "eattr.h"
+#include "glock.h"
+#include "inode.h"
+#include "meta_io.h"
+#include "ops_dentry.h"
+#include "ops_inode.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+/**
+ * gfs2_create - Create a file
+ * @dir: The directory in which to create the file
+ * @dentry: The dentry of the new file
+ * @mode: The mode of the new file
+ *
+ * Returns: errno
+ */
+
+static int gfs2_create(struct inode *dir, struct dentry *dentry,
+ int mode, struct nameidata *nd)
+{
+ struct gfs2_inode *dip = GFS2_I(dir);
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ struct gfs2_holder ghs[2];
+ struct inode *inode;
+
+ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+ for (;;) {
+ inode = gfs2_createi(ghs, &dentry->d_name, S_IFREG | mode);
+ if (!IS_ERR(inode)) {
+ gfs2_trans_end(sdp);
+ if (dip->i_alloc.al_rgd)
+ gfs2_inplace_release(dip);
+ gfs2_quota_unlock(dip);
+ gfs2_alloc_put(dip);
+ gfs2_glock_dq_uninit_m(2, ghs);
+ mark_inode_dirty(inode);
+ break;
+ } else if (PTR_ERR(inode) != -EEXIST ||
+ (nd->intent.open.flags & O_EXCL)) {
+ gfs2_holder_uninit(ghs);
+ return PTR_ERR(inode);
+ }
+
+ inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
+ if (inode) {
+ if (!IS_ERR(inode)) {
+ gfs2_holder_uninit(ghs);
+ break;
+ } else {
+ gfs2_holder_uninit(ghs);
+ return PTR_ERR(inode);
+ }
+ }
+ }
+
+ d_instantiate(dentry, inode);
+
+ return 0;
+}
+
+/**
+ * gfs2_lookup - Look up a filename in a directory and return its inode
+ * @dir: The directory inode
+ * @dentry: The dentry of the new inode
+ * @nd: passed from Linux VFS, ignored by us
+ *
+ * Called by the VFS layer. Lock dir and call gfs2_lookupi()
+ *
+ * Returns: errno
+ */
+
+static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
+{
+ struct inode *inode = NULL;
+
+ dentry->d_op = &gfs2_dops;
+
+ inode = gfs2_lookupi(dir, &dentry->d_name, 0, nd);
+ if (inode && IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(inode));
+
+ if (inode)
+ return d_splice_alias(inode, dentry);
+ d_add(dentry, inode);
+
+ return NULL;
+}
+
+/**
+ * gfs2_link - Link to a file
+ * @old_dentry: The inode to link
+ * @dir: Add link to this directory
+ * @dentry: The name of the link
+ *
+ * Link the inode in "old_dentry" into the directory "dir" with the
+ * name in "dentry".
+ *
+ * Returns: errno
+ */
+
+static int gfs2_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ struct gfs2_inode *dip = GFS2_I(dir);
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ struct inode *inode = old_dentry->d_inode;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder ghs[2];
+ int alloc_required;
+ int error;
+
+ if (S_ISDIR(ip->i_di.di_mode))
+ return -EPERM;
+
+ gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+
+ error = gfs2_glock_nq_m(2, ghs);
+ if (error)
+ goto out;
+
+ error = permission(dir, MAY_WRITE | MAY_EXEC, NULL);
+ if (error)
+ goto out_gunlock;
+
+ error = gfs2_dir_search(dir, &dentry->d_name, NULL, NULL);
+ switch (error) {
+ case -ENOENT:
+ break;
+ case 0:
+ error = -EEXIST;
+ default:
+ goto out_gunlock;
+ }
+
+ error = -EINVAL;
+ if (!dip->i_di.di_nlink)
+ goto out_gunlock;
+ error = -EFBIG;
+ if (dip->i_di.di_entries == (u32)-1)
+ goto out_gunlock;
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto out_gunlock;
+ error = -EINVAL;
+ if (!ip->i_di.di_nlink)
+ goto out_gunlock;
+ error = -EMLINK;
+ if (ip->i_di.di_nlink == (u32)-1)
+ goto out_gunlock;
+
+ alloc_required = error = gfs2_diradd_alloc_required(dir, &dentry->d_name);
+ if (error < 0)
+ goto out_gunlock;
+ error = 0;
+
+ if (alloc_required) {
+ struct gfs2_alloc *al = gfs2_alloc_get(dip);
+
+ error = gfs2_quota_lock(dip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out_alloc;
+
+ error = gfs2_quota_check(dip, dip->i_di.di_uid,
+ dip->i_di.di_gid);
+ if (error)
+ goto out_gunlock_q;
+
+ al->al_requested = sdp->sd_max_dirres;
+
+ error = gfs2_inplace_reserve(dip);
+ if (error)
+ goto out_gunlock_q;
+
+ error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
+ al->al_rgd->rd_ri.ri_length +
+ 2 * RES_DINODE + RES_STATFS +
+ RES_QUOTA, 0);
+ if (error)
+ goto out_ipres;
+ } else {
+ error = gfs2_trans_begin(sdp, 2 * RES_DINODE + RES_LEAF, 0);
+ if (error)
+ goto out_ipres;
+ }
+
+ error = gfs2_dir_add(dir, &dentry->d_name, &ip->i_num,
+ IF2DT(ip->i_di.di_mode));
+ if (error)
+ goto out_end_trans;
+
+ error = gfs2_change_nlink(ip, +1);
+
+out_end_trans:
+ gfs2_trans_end(sdp);
+out_ipres:
+ if (alloc_required)
+ gfs2_inplace_release(dip);
+out_gunlock_q:
+ if (alloc_required)
+ gfs2_quota_unlock(dip);
+out_alloc:
+ if (alloc_required)
+ gfs2_alloc_put(dip);
+out_gunlock:
+ gfs2_glock_dq_m(2, ghs);
+out:
+ gfs2_holder_uninit(ghs);
+ gfs2_holder_uninit(ghs + 1);
+ if (!error) {
+ atomic_inc(&inode->i_count);
+ d_instantiate(dentry, inode);
+ mark_inode_dirty(inode);
+ }
+ return error;
+}
+
+/**
+ * gfs2_unlink - Unlink a file
+ * @dir: The inode of the directory containing the file to unlink
+ * @dentry: The file itself
+ *
+ * Unlink a file. Call gfs2_unlinki()
+ *
+ * Returns: errno
+ */
+
+static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
+{
+ struct gfs2_inode *dip = GFS2_I(dir);
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+ struct gfs2_holder ghs[2];
+ int error;
+
+ gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+
+ error = gfs2_glock_nq_m(2, ghs);
+ if (error)
+ goto out;
+
+ error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
+ if (error)
+ goto out_gunlock;
+
+ error = gfs2_trans_begin(sdp, 2*RES_DINODE + RES_LEAF + RES_RG_BIT, 0);
+ if (error)
+ goto out_gunlock;
+
+ error = gfs2_dir_del(dip, &dentry->d_name);
+ if (error)
+ goto out_end_trans;
+
+ error = gfs2_change_nlink(ip, -1);
+
+out_end_trans:
+ gfs2_trans_end(sdp);
+out_gunlock:
+ gfs2_glock_dq_m(2, ghs);
+out:
+ gfs2_holder_uninit(ghs);
+ gfs2_holder_uninit(ghs + 1);
+ return error;
+}
+
+/**
+ * gfs2_symlink - Create a symlink
+ * @dir: The directory to create the symlink in
+ * @dentry: The dentry to put the symlink in
+ * @symname: The thing which the link points to
+ *
+ * Returns: errno
+ */
+
+static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
+ const char *symname)
+{
+ struct gfs2_inode *dip = GFS2_I(dir), *ip;
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ struct gfs2_holder ghs[2];
+ struct inode *inode;
+ struct buffer_head *dibh;
+ int size;
+ int error;
+
+ /* Must be stuffed with a null terminator for gfs2_follow_link() */
+ size = strlen(symname);
+ if (size > sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode) - 1)
+ return -ENAMETOOLONG;
+
+ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+ inode = gfs2_createi(ghs, &dentry->d_name, S_IFLNK | S_IRWXUGO);
+ if (IS_ERR(inode)) {
+ gfs2_holder_uninit(ghs);
+ return PTR_ERR(inode);
+ }
+
+ ip = ghs[1].gh_gl->gl_object;
+
+ ip->i_di.di_size = size;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+
+ if (!gfs2_assert_withdraw(sdp, !error)) {
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ memcpy(dibh->b_data + sizeof(struct gfs2_dinode), symname,
+ size);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(sdp);
+ if (dip->i_alloc.al_rgd)
+ gfs2_inplace_release(dip);
+ gfs2_quota_unlock(dip);
+ gfs2_alloc_put(dip);
+
+ gfs2_glock_dq_uninit_m(2, ghs);
+
+ d_instantiate(dentry, inode);
+ mark_inode_dirty(inode);
+
+ return 0;
+}
+
+/**
+ * gfs2_mkdir - Make a directory
+ * @dir: The parent directory of the new one
+ * @dentry: The dentry of the new directory
+ * @mode: The mode of the new directory
+ *
+ * Returns: errno
+ */
+
+static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ struct gfs2_inode *dip = GFS2_I(dir), *ip;
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ struct gfs2_holder ghs[2];
+ struct inode *inode;
+ struct buffer_head *dibh;
+ int error;
+
+ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+ inode = gfs2_createi(ghs, &dentry->d_name, S_IFDIR | mode);
+ if (IS_ERR(inode)) {
+ gfs2_holder_uninit(ghs);
+ return PTR_ERR(inode);
+ }
+
+ ip = ghs[1].gh_gl->gl_object;
+
+ ip->i_di.di_nlink = 2;
+ ip->i_di.di_size = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_dinode);
+ ip->i_di.di_flags |= GFS2_DIF_JDATA;
+ ip->i_di.di_payload_format = GFS2_FORMAT_DE;
+ ip->i_di.di_entries = 2;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+
+ if (!gfs2_assert_withdraw(sdp, !error)) {
+ struct gfs2_dinode *di = (struct gfs2_dinode *)dibh->b_data;
+ struct gfs2_dirent *dent = (struct gfs2_dirent *)(di+1);
+ struct qstr str;
+
+ gfs2_str2qstr(&str, ".");
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_qstr2dirent(&str, GFS2_DIRENT_SIZE(str.len), dent);
+ dent->de_inum = di->di_num; /* already GFS2 endian */
+ dent->de_type = cpu_to_be16(DT_DIR);
+ di->di_entries = cpu_to_be32(1);
+
+ gfs2_str2qstr(&str, "..");
+ dent = (struct gfs2_dirent *)((char*)dent + GFS2_DIRENT_SIZE(1));
+ gfs2_qstr2dirent(&str, dibh->b_size - GFS2_DIRENT_SIZE(1) - sizeof(struct gfs2_dinode), dent);
+
+ gfs2_inum_out(&dip->i_num, &dent->de_inum);
+ dent->de_type = cpu_to_be16(DT_DIR);
+
+ gfs2_dinode_out(&ip->i_di, di);
+
+ brelse(dibh);
+ }
+
+ error = gfs2_change_nlink(dip, +1);
+ gfs2_assert_withdraw(sdp, !error); /* dip already pinned */
+
+ gfs2_trans_end(sdp);
+ if (dip->i_alloc.al_rgd)
+ gfs2_inplace_release(dip);
+ gfs2_quota_unlock(dip);
+ gfs2_alloc_put(dip);
+
+ gfs2_glock_dq_uninit_m(2, ghs);
+
+ d_instantiate(dentry, inode);
+ mark_inode_dirty(inode);
+
+ return 0;
+}
+
+/**
+ * gfs2_rmdir - Remove a directory
+ * @dir: The parent directory of the directory to be removed
+ * @dentry: The dentry of the directory to remove
+ *
+ * Remove a directory. Call gfs2_rmdiri()
+ *
+ * Returns: errno
+ */
+
+static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct gfs2_inode *dip = GFS2_I(dir);
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+ struct gfs2_holder ghs[2];
+ int error;
+
+ gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+
+ error = gfs2_glock_nq_m(2, ghs);
+ if (error)
+ goto out;
+
+ error = gfs2_unlink_ok(dip, &dentry->d_name, ip);
+ if (error)
+ goto out_gunlock;
+
+ if (ip->i_di.di_entries < 2) {
+ if (gfs2_consist_inode(ip))
+ gfs2_dinode_print(&ip->i_di);
+ error = -EIO;
+ goto out_gunlock;
+ }
+ if (ip->i_di.di_entries > 2) {
+ error = -ENOTEMPTY;
+ goto out_gunlock;
+ }
+
+ error = gfs2_trans_begin(sdp, 2 * RES_DINODE + 3 * RES_LEAF + RES_RG_BIT, 0);
+ if (error)
+ goto out_gunlock;
+
+ error = gfs2_rmdiri(dip, &dentry->d_name, ip);
+
+ gfs2_trans_end(sdp);
+
+out_gunlock:
+ gfs2_glock_dq_m(2, ghs);
+out:
+ gfs2_holder_uninit(ghs);
+ gfs2_holder_uninit(ghs + 1);
+ return error;
+}
+
+/**
+ * gfs2_mknod - Make a special file
+ * @dir: The directory in which the special file will reside
+ * @dentry: The dentry of the special file
+ * @mode: The mode of the special file
+ * @rdev: The device specification of the special file
+ *
+ */
+
+static int gfs2_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t dev)
+{
+ struct gfs2_inode *dip = GFS2_I(dir), *ip;
+ struct gfs2_sbd *sdp = GFS2_SB(dir);
+ struct gfs2_holder ghs[2];
+ struct inode *inode;
+ struct buffer_head *dibh;
+ u32 major = 0, minor = 0;
+ int error;
+
+ switch (mode & S_IFMT) {
+ case S_IFBLK:
+ case S_IFCHR:
+ major = MAJOR(dev);
+ minor = MINOR(dev);
+ break;
+ case S_IFIFO:
+ case S_IFSOCK:
+ break;
+ default:
+ return -EOPNOTSUPP;
+ };
+
+ gfs2_holder_init(dip->i_gl, 0, 0, ghs);
+
+ inode = gfs2_createi(ghs, &dentry->d_name, mode);
+ if (IS_ERR(inode)) {
+ gfs2_holder_uninit(ghs);
+ return PTR_ERR(inode);
+ }
+
+ ip = ghs[1].gh_gl->gl_object;
+
+ ip->i_di.di_major = major;
+ ip->i_di.di_minor = minor;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+
+ if (!gfs2_assert_withdraw(sdp, !error)) {
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ gfs2_trans_end(sdp);
+ if (dip->i_alloc.al_rgd)
+ gfs2_inplace_release(dip);
+ gfs2_quota_unlock(dip);
+ gfs2_alloc_put(dip);
+
+ gfs2_glock_dq_uninit_m(2, ghs);
+
+ d_instantiate(dentry, inode);
+ mark_inode_dirty(inode);
+
+ return 0;
+}
+
+/**
+ * gfs2_rename - Rename a file
+ * @odir: Parent directory of old file name
+ * @odentry: The old dentry of the file
+ * @ndir: Parent directory of new file name
+ * @ndentry: The new dentry of the file
+ *
+ * Returns: errno
+ */
+
+static int gfs2_rename(struct inode *odir, struct dentry *odentry,
+ struct inode *ndir, struct dentry *ndentry)
+{
+ struct gfs2_inode *odip = GFS2_I(odir);
+ struct gfs2_inode *ndip = GFS2_I(ndir);
+ struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
+ struct gfs2_inode *nip = NULL;
+ struct gfs2_sbd *sdp = GFS2_SB(odir);
+ struct gfs2_holder ghs[4], r_gh;
+ unsigned int num_gh;
+ int dir_rename = 0;
+ int alloc_required;
+ unsigned int x;
+ int error;
+
+ if (ndentry->d_inode) {
+ nip = GFS2_I(ndentry->d_inode);
+ if (ip == nip)
+ return 0;
+ }
+
+ /* Make sure we aren't trying to move a dirctory into it's subdir */
+
+ if (S_ISDIR(ip->i_di.di_mode) && odip != ndip) {
+ dir_rename = 1;
+
+ error = gfs2_glock_nq_init(sdp->sd_rename_gl,
+ LM_ST_EXCLUSIVE, 0,
+ &r_gh);
+ if (error)
+ goto out;
+
+ error = gfs2_ok_to_move(ip, ndip);
+ if (error)
+ goto out_gunlock_r;
+ }
+
+ num_gh = 1;
+ gfs2_holder_init(odip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
+ if (odip != ndip) {
+ gfs2_holder_init(ndip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+ num_gh++;
+ }
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+ num_gh++;
+
+ if (nip) {
+ gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
+ num_gh++;
+ }
+
+ error = gfs2_glock_nq_m(num_gh, ghs);
+ if (error)
+ goto out_uninit;
+
+ /* Check out the old directory */
+
+ error = gfs2_unlink_ok(odip, &odentry->d_name, ip);
+ if (error)
+ goto out_gunlock;
+
+ /* Check out the new directory */
+
+ if (nip) {
+ error = gfs2_unlink_ok(ndip, &ndentry->d_name, nip);
+ if (error)
+ goto out_gunlock;
+
+ if (S_ISDIR(nip->i_di.di_mode)) {
+ if (nip->i_di.di_entries < 2) {
+ if (gfs2_consist_inode(nip))
+ gfs2_dinode_print(&nip->i_di);
+ error = -EIO;
+ goto out_gunlock;
+ }
+ if (nip->i_di.di_entries > 2) {
+ error = -ENOTEMPTY;
+ goto out_gunlock;
+ }
+ }
+ } else {
+ error = permission(ndir, MAY_WRITE | MAY_EXEC, NULL);
+ if (error)
+ goto out_gunlock;
+
+ error = gfs2_dir_search(ndir, &ndentry->d_name, NULL, NULL);
+ switch (error) {
+ case -ENOENT:
+ error = 0;
+ break;
+ case 0:
+ error = -EEXIST;
+ default:
+ goto out_gunlock;
+ };
+
+ if (odip != ndip) {
+ if (!ndip->i_di.di_nlink) {
+ error = -EINVAL;
+ goto out_gunlock;
+ }
+ if (ndip->i_di.di_entries == (u32)-1) {
+ error = -EFBIG;
+ goto out_gunlock;
+ }
+ if (S_ISDIR(ip->i_di.di_mode) &&
+ ndip->i_di.di_nlink == (u32)-1) {
+ error = -EMLINK;
+ goto out_gunlock;
+ }
+ }
+ }
+
+ /* Check out the dir to be renamed */
+
+ if (dir_rename) {
+ error = permission(odentry->d_inode, MAY_WRITE, NULL);
+ if (error)
+ goto out_gunlock;
+ }
+
+ alloc_required = error = gfs2_diradd_alloc_required(ndir, &ndentry->d_name);
+ if (error < 0)
+ goto out_gunlock;
+ error = 0;
+
+ if (alloc_required) {
+ struct gfs2_alloc *al = gfs2_alloc_get(ndip);
+
+ error = gfs2_quota_lock(ndip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out_alloc;
+
+ error = gfs2_quota_check(ndip, ndip->i_di.di_uid,
+ ndip->i_di.di_gid);
+ if (error)
+ goto out_gunlock_q;
+
+ al->al_requested = sdp->sd_max_dirres;
+
+ error = gfs2_inplace_reserve(ndip);
+ if (error)
+ goto out_gunlock_q;
+
+ error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
+ al->al_rgd->rd_ri.ri_length +
+ 4 * RES_DINODE + 4 * RES_LEAF +
+ RES_STATFS + RES_QUOTA, 0);
+ if (error)
+ goto out_ipreserv;
+ } else {
+ error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
+ 5 * RES_LEAF, 0);
+ if (error)
+ goto out_gunlock;
+ }
+
+ /* Remove the target file, if it exists */
+
+ if (nip) {
+ if (S_ISDIR(nip->i_di.di_mode))
+ error = gfs2_rmdiri(ndip, &ndentry->d_name, nip);
+ else {
+ error = gfs2_dir_del(ndip, &ndentry->d_name);
+ if (error)
+ goto out_end_trans;
+ error = gfs2_change_nlink(nip, -1);
+ }
+ if (error)
+ goto out_end_trans;
+ }
+
+ if (dir_rename) {
+ struct qstr name;
+ gfs2_str2qstr(&name, "..");
+
+ error = gfs2_change_nlink(ndip, +1);
+ if (error)
+ goto out_end_trans;
+ error = gfs2_change_nlink(odip, -1);
+ if (error)
+ goto out_end_trans;
+
+ error = gfs2_dir_mvino(ip, &name, &ndip->i_num, DT_DIR);
+ if (error)
+ goto out_end_trans;
+ } else {
+ struct buffer_head *dibh;
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out_end_trans;
+ ip->i_di.di_ctime = get_seconds();
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+ }
+
+ error = gfs2_dir_del(odip, &odentry->d_name);
+ if (error)
+ goto out_end_trans;
+
+ error = gfs2_dir_add(ndir, &ndentry->d_name, &ip->i_num,
+ IF2DT(ip->i_di.di_mode));
+ if (error)
+ goto out_end_trans;
+
+out_end_trans:
+ gfs2_trans_end(sdp);
+out_ipreserv:
+ if (alloc_required)
+ gfs2_inplace_release(ndip);
+out_gunlock_q:
+ if (alloc_required)
+ gfs2_quota_unlock(ndip);
+out_alloc:
+ if (alloc_required)
+ gfs2_alloc_put(ndip);
+out_gunlock:
+ gfs2_glock_dq_m(num_gh, ghs);
+out_uninit:
+ for (x = 0; x < num_gh; x++)
+ gfs2_holder_uninit(ghs + x);
+out_gunlock_r:
+ if (dir_rename)
+ gfs2_glock_dq_uninit(&r_gh);
+out:
+ return error;
+}
+
+/**
+ * gfs2_readlink - Read the value of a symlink
+ * @dentry: the symlink
+ * @buf: the buffer to read the symlink data into
+ * @size: the size of the buffer
+ *
+ * Returns: errno
+ */
+
+static int gfs2_readlink(struct dentry *dentry, char __user *user_buf,
+ int user_size)
+{
+ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+ char array[GFS2_FAST_NAME_SIZE], *buf = array;
+ unsigned int len = GFS2_FAST_NAME_SIZE;
+ int error;
+
+ error = gfs2_readlinki(ip, &buf, &len);
+ if (error)
+ return error;
+
+ if (user_size > len - 1)
+ user_size = len - 1;
+
+ if (copy_to_user(user_buf, buf, user_size))
+ error = -EFAULT;
+ else
+ error = user_size;
+
+ if (buf != array)
+ kfree(buf);
+
+ return error;
+}
+
+/**
+ * gfs2_follow_link - Follow a symbolic link
+ * @dentry: The dentry of the link
+ * @nd: Data that we pass to vfs_follow_link()
+ *
+ * This can handle symlinks of any size. It is optimised for symlinks
+ * under GFS2_FAST_NAME_SIZE.
+ *
+ * Returns: 0 on success or error code
+ */
+
+static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
+{
+ struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
+ char array[GFS2_FAST_NAME_SIZE], *buf = array;
+ unsigned int len = GFS2_FAST_NAME_SIZE;
+ int error;
+
+ error = gfs2_readlinki(ip, &buf, &len);
+ if (!error) {
+ error = vfs_follow_link(nd, buf);
+ if (buf != array)
+ kfree(buf);
+ }
+
+ return ERR_PTR(error);
+}
+
+/**
+ * gfs2_permission -
+ * @inode:
+ * @mask:
+ * @nd: passed from Linux VFS, ignored by us
+ *
+ * Returns: errno
+ */
+
+static int gfs2_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder i_gh;
+ int error;
+
+ if (ip->i_vn == ip->i_gl->gl_vn)
+ return generic_permission(inode, mask, gfs2_check_acl);
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+ if (!error) {
+ error = generic_permission(inode, mask, gfs2_check_acl_locked);
+ gfs2_glock_dq_uninit(&i_gh);
+ }
+
+ return error;
+}
+
+static int setattr_size(struct inode *inode, struct iattr *attr)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ int error;
+
+ if (attr->ia_size != ip->i_di.di_size) {
+ error = vmtruncate(inode, attr->ia_size);
+ if (error)
+ return error;
+ }
+
+ error = gfs2_truncatei(ip, attr->ia_size);
+ if (error)
+ return error;
+
+ return error;
+}
+
+static int setattr_chown(struct inode *inode, struct iattr *attr)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct buffer_head *dibh;
+ u32 ouid, ogid, nuid, ngid;
+ int error;
+
+ ouid = ip->i_di.di_uid;
+ ogid = ip->i_di.di_gid;
+ nuid = attr->ia_uid;
+ ngid = attr->ia_gid;
+
+ if (!(attr->ia_valid & ATTR_UID) || ouid == nuid)
+ ouid = nuid = NO_QUOTA_CHANGE;
+ if (!(attr->ia_valid & ATTR_GID) || ogid == ngid)
+ ogid = ngid = NO_QUOTA_CHANGE;
+
+ gfs2_alloc_get(ip);
+
+ error = gfs2_quota_lock(ip, nuid, ngid);
+ if (error)
+ goto out_alloc;
+
+ if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
+ error = gfs2_quota_check(ip, nuid, ngid);
+ if (error)
+ goto out_gunlock_q;
+ }
+
+ error = gfs2_trans_begin(sdp, RES_DINODE + 2 * RES_QUOTA, 0);
+ if (error)
+ goto out_gunlock_q;
+
+ error = gfs2_meta_inode_buffer(ip, &dibh);
+ if (error)
+ goto out_end_trans;
+
+ error = inode_setattr(inode, attr);
+ gfs2_assert_warn(sdp, !error);
+ gfs2_inode_attr_out(ip);
+
+ gfs2_trans_add_bh(ip->i_gl, dibh, 1);
+ gfs2_dinode_out(&ip->i_di, dibh->b_data);
+ brelse(dibh);
+
+ if (ouid != NO_QUOTA_CHANGE || ogid != NO_QUOTA_CHANGE) {
+ gfs2_quota_change(ip, -ip->i_di.di_blocks, ouid, ogid);
+ gfs2_quota_change(ip, ip->i_di.di_blocks, nuid, ngid);
+ }
+
+out_end_trans:
+ gfs2_trans_end(sdp);
+out_gunlock_q:
+ gfs2_quota_unlock(ip);
+out_alloc:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
+/**
+ * gfs2_setattr - Change attributes on an inode
+ * @dentry: The dentry which is changing
+ * @attr: The structure describing the change
+ *
+ * The VFS layer wants to change one or more of an inodes attributes. Write
+ * that change out to disk.
+ *
+ * Returns: errno
+ */
+
+static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder i_gh;
+ int error;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+ if (error)
+ return error;
+
+ error = -EPERM;
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ goto out;
+
+ error = inode_change_ok(inode, attr);
+ if (error)
+ goto out;
+
+ if (attr->ia_valid & ATTR_SIZE)
+ error = setattr_size(inode, attr);
+ else if (attr->ia_valid & (ATTR_UID | ATTR_GID))
+ error = setattr_chown(inode, attr);
+ else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
+ error = gfs2_acl_chmod(ip, attr);
+ else
+ error = gfs2_setattr_simple(ip, attr);
+
+out:
+ gfs2_glock_dq_uninit(&i_gh);
+ if (!error)
+ mark_inode_dirty(inode);
+ return error;
+}
+
+/**
+ * gfs2_getattr - Read out an inode's attributes
+ * @mnt: The vfsmount the inode is being accessed from
+ * @dentry: The dentry to stat
+ * @stat: The inode's stats
+ *
+ * Returns: errno
+ */
+
+static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
+ struct kstat *stat)
+{
+ struct inode *inode = dentry->d_inode;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder gh;
+ int error;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
+ if (!error) {
+ generic_fillattr(inode, stat);
+ gfs2_glock_dq_uninit(&gh);
+ }
+
+ return error;
+}
+
+static int gfs2_setxattr(struct dentry *dentry, const char *name,
+ const void *data, size_t size, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+ struct gfs2_ea_request er;
+
+ memset(&er, 0, sizeof(struct gfs2_ea_request));
+ er.er_type = gfs2_ea_name2type(name, &er.er_name);
+ if (er.er_type == GFS2_EATYPE_UNUSED)
+ return -EOPNOTSUPP;
+ er.er_data = (char *)data;
+ er.er_name_len = strlen(er.er_name);
+ er.er_data_len = size;
+ er.er_flags = flags;
+
+ gfs2_assert_warn(GFS2_SB(inode), !(er.er_flags & GFS2_ERF_MODE));
+
+ return gfs2_ea_set(GFS2_I(inode), &er);
+}
+
+static ssize_t gfs2_getxattr(struct dentry *dentry, const char *name,
+ void *data, size_t size)
+{
+ struct gfs2_ea_request er;
+
+ memset(&er, 0, sizeof(struct gfs2_ea_request));
+ er.er_type = gfs2_ea_name2type(name, &er.er_name);
+ if (er.er_type == GFS2_EATYPE_UNUSED)
+ return -EOPNOTSUPP;
+ er.er_data = data;
+ er.er_name_len = strlen(er.er_name);
+ er.er_data_len = size;
+
+ return gfs2_ea_get(GFS2_I(dentry->d_inode), &er);
+}
+
+static ssize_t gfs2_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+ struct gfs2_ea_request er;
+
+ memset(&er, 0, sizeof(struct gfs2_ea_request));
+ er.er_data = (size) ? buffer : NULL;
+ er.er_data_len = size;
+
+ return gfs2_ea_list(GFS2_I(dentry->d_inode), &er);
+}
+
+static int gfs2_removexattr(struct dentry *dentry, const char *name)
+{
+ struct gfs2_ea_request er;
+
+ memset(&er, 0, sizeof(struct gfs2_ea_request));
+ er.er_type = gfs2_ea_name2type(name, &er.er_name);
+ if (er.er_type == GFS2_EATYPE_UNUSED)
+ return -EOPNOTSUPP;
+ er.er_name_len = strlen(er.er_name);
+
+ return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er);
+}
+
+struct inode_operations gfs2_file_iops = {
+ .permission = gfs2_permission,
+ .setattr = gfs2_setattr,
+ .getattr = gfs2_getattr,
+ .setxattr = gfs2_setxattr,
+ .getxattr = gfs2_getxattr,
+ .listxattr = gfs2_listxattr,
+ .removexattr = gfs2_removexattr,
+};
+
+struct inode_operations gfs2_dev_iops = {
+ .permission = gfs2_permission,
+ .setattr = gfs2_setattr,
+ .getattr = gfs2_getattr,
+ .setxattr = gfs2_setxattr,
+ .getxattr = gfs2_getxattr,
+ .listxattr = gfs2_listxattr,
+ .removexattr = gfs2_removexattr,
+};
+
+struct inode_operations gfs2_dir_iops = {
+ .create = gfs2_create,
+ .lookup = gfs2_lookup,
+ .link = gfs2_link,
+ .unlink = gfs2_unlink,
+ .symlink = gfs2_symlink,
+ .mkdir = gfs2_mkdir,
+ .rmdir = gfs2_rmdir,
+ .mknod = gfs2_mknod,
+ .rename = gfs2_rename,
+ .permission = gfs2_permission,
+ .setattr = gfs2_setattr,
+ .getattr = gfs2_getattr,
+ .setxattr = gfs2_setxattr,
+ .getxattr = gfs2_getxattr,
+ .listxattr = gfs2_listxattr,
+ .removexattr = gfs2_removexattr,
+};
+
+struct inode_operations gfs2_symlink_iops = {
+ .readlink = gfs2_readlink,
+ .follow_link = gfs2_follow_link,
+ .permission = gfs2_permission,
+ .setattr = gfs2_setattr,
+ .getattr = gfs2_getattr,
+ .setxattr = gfs2_setxattr,
+ .getxattr = gfs2_getxattr,
+ .listxattr = gfs2_listxattr,
+ .removexattr = gfs2_removexattr,
+};
+
diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h
new file mode 100644
index 000000000000..b15acb4fd34c
--- /dev/null
+++ b/fs/gfs2/ops_inode.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_INODE_DOT_H__
+#define __OPS_INODE_DOT_H__
+
+#include <linux/fs.h>
+
+extern struct inode_operations gfs2_file_iops;
+extern struct inode_operations gfs2_dir_iops;
+extern struct inode_operations gfs2_symlink_iops;
+extern struct inode_operations gfs2_dev_iops;
+
+#endif /* __OPS_INODE_DOT_H__ */
diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c
new file mode 100644
index 000000000000..06f06f7773d0
--- /dev/null
+++ b/fs/gfs2/ops_super.c
@@ -0,0 +1,468 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/statfs.h>
+#include <linux/seq_file.h>
+#include <linux/mount.h>
+#include <linux/kthread.h>
+#include <linux/delay.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "inode.h"
+#include "lm.h"
+#include "log.h"
+#include "mount.h"
+#include "ops_super.h"
+#include "quota.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "super.h"
+#include "sys.h"
+#include "util.h"
+#include "trans.h"
+#include "dir.h"
+#include "eattr.h"
+#include "bmap.h"
+
+/**
+ * gfs2_write_inode - Make sure the inode is stable on the disk
+ * @inode: The inode
+ * @sync: synchronous write flag
+ *
+ * Returns: errno
+ */
+
+static int gfs2_write_inode(struct inode *inode, int sync)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+
+ /* Check this is a "normal" inode */
+ if (inode->i_private) {
+ if (current->flags & PF_MEMALLOC)
+ return 0;
+ if (sync)
+ gfs2_log_flush(GFS2_SB(inode), ip->i_gl);
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_put_super - Unmount the filesystem
+ * @sb: The VFS superblock
+ *
+ */
+
+static void gfs2_put_super(struct super_block *sb)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ int error;
+
+ if (!sdp)
+ return;
+
+ if (!strncmp(sb->s_type->name, "gfs2meta", 8))
+ return; /* Nothing to do */
+
+ /* Unfreeze the filesystem, if we need to */
+
+ mutex_lock(&sdp->sd_freeze_lock);
+ if (sdp->sd_freeze_count)
+ gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
+ mutex_unlock(&sdp->sd_freeze_lock);
+
+ kthread_stop(sdp->sd_quotad_process);
+ kthread_stop(sdp->sd_logd_process);
+ kthread_stop(sdp->sd_recoverd_process);
+ while (sdp->sd_glockd_num--)
+ kthread_stop(sdp->sd_glockd_process[sdp->sd_glockd_num]);
+ kthread_stop(sdp->sd_scand_process);
+
+ if (!(sb->s_flags & MS_RDONLY)) {
+ error = gfs2_make_fs_ro(sdp);
+ if (error)
+ gfs2_io_error(sdp);
+ }
+ /* At this point, we're through modifying the disk */
+
+ /* Release stuff */
+
+ iput(sdp->sd_master_dir);
+ iput(sdp->sd_jindex);
+ iput(sdp->sd_inum_inode);
+ iput(sdp->sd_statfs_inode);
+ iput(sdp->sd_rindex);
+ iput(sdp->sd_quota_inode);
+
+ gfs2_glock_put(sdp->sd_rename_gl);
+ gfs2_glock_put(sdp->sd_trans_gl);
+
+ if (!sdp->sd_args.ar_spectator) {
+ gfs2_glock_dq_uninit(&sdp->sd_journal_gh);
+ gfs2_glock_dq_uninit(&sdp->sd_jinode_gh);
+ gfs2_glock_dq_uninit(&sdp->sd_ir_gh);
+ gfs2_glock_dq_uninit(&sdp->sd_sc_gh);
+ gfs2_glock_dq_uninit(&sdp->sd_qc_gh);
+ iput(sdp->sd_ir_inode);
+ iput(sdp->sd_sc_inode);
+ iput(sdp->sd_qc_inode);
+ }
+
+ gfs2_glock_dq_uninit(&sdp->sd_live_gh);
+ gfs2_clear_rgrpd(sdp);
+ gfs2_jindex_free(sdp);
+ /* Take apart glock structures and buffer lists */
+ gfs2_gl_hash_clear(sdp, WAIT);
+ /* Unmount the locking protocol */
+ gfs2_lm_unmount(sdp);
+
+ /* At this point, we're through participating in the lockspace */
+ gfs2_sys_fs_del(sdp);
+ kfree(sdp);
+}
+
+/**
+ * gfs2_write_super - disk commit all incore transactions
+ * @sb: the filesystem
+ *
+ * This function is called every time sync(2) is called.
+ * After this exits, all dirty buffers are synced.
+ */
+
+static void gfs2_write_super(struct super_block *sb)
+{
+ gfs2_log_flush(sb->s_fs_info, NULL);
+}
+
+/**
+ * gfs2_write_super_lockfs - prevent further writes to the filesystem
+ * @sb: the VFS structure for the filesystem
+ *
+ */
+
+static void gfs2_write_super_lockfs(struct super_block *sb)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ int error;
+
+ for (;;) {
+ error = gfs2_freeze_fs(sdp);
+ if (!error)
+ break;
+
+ switch (error) {
+ case -EBUSY:
+ fs_err(sdp, "waiting for recovery before freeze\n");
+ break;
+
+ default:
+ fs_err(sdp, "error freezing FS: %d\n", error);
+ break;
+ }
+
+ fs_err(sdp, "retrying...\n");
+ msleep(1000);
+ }
+}
+
+/**
+ * gfs2_unlockfs - reallow writes to the filesystem
+ * @sb: the VFS structure for the filesystem
+ *
+ */
+
+static void gfs2_unlockfs(struct super_block *sb)
+{
+ gfs2_unfreeze_fs(sb->s_fs_info);
+}
+
+/**
+ * gfs2_statfs - Gather and return stats about the filesystem
+ * @sb: The superblock
+ * @statfsbuf: The buffer
+ *
+ * Returns: 0 on success or error code
+ */
+
+static int gfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+ struct super_block *sb = dentry->d_inode->i_sb;
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct gfs2_statfs_change sc;
+ int error;
+
+ if (gfs2_tune_get(sdp, gt_statfs_slow))
+ error = gfs2_statfs_slow(sdp, &sc);
+ else
+ error = gfs2_statfs_i(sdp, &sc);
+
+ if (error)
+ return error;
+
+ buf->f_type = GFS2_MAGIC;
+ buf->f_bsize = sdp->sd_sb.sb_bsize;
+ buf->f_blocks = sc.sc_total;
+ buf->f_bfree = sc.sc_free;
+ buf->f_bavail = sc.sc_free;
+ buf->f_files = sc.sc_dinodes + sc.sc_free;
+ buf->f_ffree = sc.sc_free;
+ buf->f_namelen = GFS2_FNAMESIZE;
+
+ return 0;
+}
+
+/**
+ * gfs2_remount_fs - called when the FS is remounted
+ * @sb: the filesystem
+ * @flags: the remount flags
+ * @data: extra data passed in (not used right now)
+ *
+ * Returns: errno
+ */
+
+static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ int error;
+
+ error = gfs2_mount_args(sdp, data, 1);
+ if (error)
+ return error;
+
+ if (sdp->sd_args.ar_spectator)
+ *flags |= MS_RDONLY;
+ else {
+ if (*flags & MS_RDONLY) {
+ if (!(sb->s_flags & MS_RDONLY))
+ error = gfs2_make_fs_ro(sdp);
+ } else if (!(*flags & MS_RDONLY) &&
+ (sb->s_flags & MS_RDONLY)) {
+ error = gfs2_make_fs_rw(sdp);
+ }
+ }
+
+ if (*flags & (MS_NOATIME | MS_NODIRATIME))
+ set_bit(SDF_NOATIME, &sdp->sd_flags);
+ else
+ clear_bit(SDF_NOATIME, &sdp->sd_flags);
+
+ /* Don't let the VFS update atimes. GFS2 handles this itself. */
+ *flags |= MS_NOATIME | MS_NODIRATIME;
+
+ return error;
+}
+
+/**
+ * gfs2_clear_inode - Deallocate an inode when VFS is done with it
+ * @inode: The VFS inode
+ *
+ */
+
+static void gfs2_clear_inode(struct inode *inode)
+{
+ /* This tells us its a "real" inode and not one which only
+ * serves to contain an address space (see rgrp.c, meta_io.c)
+ * which therefore doesn't have its own glocks.
+ */
+ if (inode->i_private) {
+ struct gfs2_inode *ip = GFS2_I(inode);
+ gfs2_glock_inode_squish(inode);
+ gfs2_assert(inode->i_sb->s_fs_info, ip->i_gl->gl_state == LM_ST_UNLOCKED);
+ ip->i_gl->gl_object = NULL;
+ gfs2_glock_schedule_for_reclaim(ip->i_gl);
+ gfs2_glock_put(ip->i_gl);
+ ip->i_gl = NULL;
+ if (ip->i_iopen_gh.gh_gl)
+ gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+ }
+}
+
+/**
+ * gfs2_show_options - Show mount options for /proc/mounts
+ * @s: seq_file structure
+ * @mnt: vfsmount
+ *
+ * Returns: 0 on success or error code
+ */
+
+static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt)
+{
+ struct gfs2_sbd *sdp = mnt->mnt_sb->s_fs_info;
+ struct gfs2_args *args = &sdp->sd_args;
+
+ if (args->ar_lockproto[0])
+ seq_printf(s, ",lockproto=%s", args->ar_lockproto);
+ if (args->ar_locktable[0])
+ seq_printf(s, ",locktable=%s", args->ar_locktable);
+ if (args->ar_hostdata[0])
+ seq_printf(s, ",hostdata=%s", args->ar_hostdata);
+ if (args->ar_spectator)
+ seq_printf(s, ",spectator");
+ if (args->ar_ignore_local_fs)
+ seq_printf(s, ",ignore_local_fs");
+ if (args->ar_localflocks)
+ seq_printf(s, ",localflocks");
+ if (args->ar_localcaching)
+ seq_printf(s, ",localcaching");
+ if (args->ar_debug)
+ seq_printf(s, ",debug");
+ if (args->ar_upgrade)
+ seq_printf(s, ",upgrade");
+ if (args->ar_num_glockd != GFS2_GLOCKD_DEFAULT)
+ seq_printf(s, ",num_glockd=%u", args->ar_num_glockd);
+ if (args->ar_posix_acl)
+ seq_printf(s, ",acl");
+ if (args->ar_quota != GFS2_QUOTA_DEFAULT) {
+ char *state;
+ switch (args->ar_quota) {
+ case GFS2_QUOTA_OFF:
+ state = "off";
+ break;
+ case GFS2_QUOTA_ACCOUNT:
+ state = "account";
+ break;
+ case GFS2_QUOTA_ON:
+ state = "on";
+ break;
+ default:
+ state = "unknown";
+ break;
+ }
+ seq_printf(s, ",quota=%s", state);
+ }
+ if (args->ar_suiddir)
+ seq_printf(s, ",suiddir");
+ if (args->ar_data != GFS2_DATA_DEFAULT) {
+ char *state;
+ switch (args->ar_data) {
+ case GFS2_DATA_WRITEBACK:
+ state = "writeback";
+ break;
+ case GFS2_DATA_ORDERED:
+ state = "ordered";
+ break;
+ default:
+ state = "unknown";
+ break;
+ }
+ seq_printf(s, ",data=%s", state);
+ }
+
+ return 0;
+}
+
+/*
+ * We have to (at the moment) hold the inodes main lock to cover
+ * the gap between unlocking the shared lock on the iopen lock and
+ * taking the exclusive lock. I'd rather do a shared -> exclusive
+ * conversion on the iopen lock, but we can change that later. This
+ * is safe, just less efficient.
+ */
+static void gfs2_delete_inode(struct inode *inode)
+{
+ struct gfs2_sbd *sdp = inode->i_sb->s_fs_info;
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder gh;
+ int error;
+
+ if (!inode->i_private)
+ goto out;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &gh);
+ if (unlikely(error)) {
+ gfs2_glock_dq_uninit(&ip->i_iopen_gh);
+ goto out;
+ }
+
+ gfs2_glock_dq(&ip->i_iopen_gh);
+ gfs2_holder_reinit(LM_ST_EXCLUSIVE, LM_FLAG_TRY_1CB | GL_NOCACHE, &ip->i_iopen_gh);
+ error = gfs2_glock_nq(&ip->i_iopen_gh);
+ if (error)
+ goto out_uninit;
+
+ if (S_ISDIR(ip->i_di.di_mode) &&
+ (ip->i_di.di_flags & GFS2_DIF_EXHASH)) {
+ error = gfs2_dir_exhash_dealloc(ip);
+ if (error)
+ goto out_unlock;
+ }
+
+ if (ip->i_di.di_eattr) {
+ error = gfs2_ea_dealloc(ip);
+ if (error)
+ goto out_unlock;
+ }
+
+ if (!gfs2_is_stuffed(ip)) {
+ error = gfs2_file_dealloc(ip);
+ if (error)
+ goto out_unlock;
+ }
+
+ error = gfs2_dinode_dealloc(ip);
+
+out_unlock:
+ gfs2_glock_dq(&ip->i_iopen_gh);
+out_uninit:
+ gfs2_holder_uninit(&ip->i_iopen_gh);
+ gfs2_glock_dq_uninit(&gh);
+ if (error)
+ fs_warn(sdp, "gfs2_delete_inode: %d\n", error);
+out:
+ truncate_inode_pages(&inode->i_data, 0);
+ clear_inode(inode);
+}
+
+
+
+static struct inode *gfs2_alloc_inode(struct super_block *sb)
+{
+ struct gfs2_sbd *sdp = sb->s_fs_info;
+ struct gfs2_inode *ip;
+
+ ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL);
+ if (ip) {
+ ip->i_flags = 0;
+ ip->i_gl = NULL;
+ ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default);
+ ip->i_last_pfault = jiffies;
+ }
+ return &ip->i_inode;
+}
+
+static void gfs2_destroy_inode(struct inode *inode)
+{
+ kmem_cache_free(gfs2_inode_cachep, inode);
+}
+
+struct super_operations gfs2_super_ops = {
+ .alloc_inode = gfs2_alloc_inode,
+ .destroy_inode = gfs2_destroy_inode,
+ .write_inode = gfs2_write_inode,
+ .delete_inode = gfs2_delete_inode,
+ .put_super = gfs2_put_super,
+ .write_super = gfs2_write_super,
+ .write_super_lockfs = gfs2_write_super_lockfs,
+ .unlockfs = gfs2_unlockfs,
+ .statfs = gfs2_statfs,
+ .remount_fs = gfs2_remount_fs,
+ .clear_inode = gfs2_clear_inode,
+ .show_options = gfs2_show_options,
+};
+
diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h
new file mode 100644
index 000000000000..9de73f042f78
--- /dev/null
+++ b/fs/gfs2/ops_super.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_SUPER_DOT_H__
+#define __OPS_SUPER_DOT_H__
+
+#include <linux/fs.h>
+
+extern struct super_operations gfs2_super_ops;
+
+#endif /* __OPS_SUPER_DOT_H__ */
diff --git a/fs/gfs2/ops_vm.c b/fs/gfs2/ops_vm.c
new file mode 100644
index 000000000000..5453d2947ab3
--- /dev/null
+++ b/fs/gfs2/ops_vm.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "inode.h"
+#include "ops_vm.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "trans.h"
+#include "util.h"
+
+static void pfault_be_greedy(struct gfs2_inode *ip)
+{
+ unsigned int time;
+
+ spin_lock(&ip->i_spin);
+ time = ip->i_greedy;
+ ip->i_last_pfault = jiffies;
+ spin_unlock(&ip->i_spin);
+
+ igrab(&ip->i_inode);
+ if (gfs2_glock_be_greedy(ip->i_gl, time))
+ iput(&ip->i_inode);
+}
+
+static struct page *gfs2_private_nopage(struct vm_area_struct *area,
+ unsigned long address, int *type)
+{
+ struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
+ struct page *result;
+
+ set_bit(GIF_PAGED, &ip->i_flags);
+
+ result = filemap_nopage(area, address, type);
+
+ if (result && result != NOPAGE_OOM)
+ pfault_be_greedy(ip);
+
+ return result;
+}
+
+static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ unsigned long index = page->index;
+ u64 lblock = index << (PAGE_CACHE_SHIFT -
+ sdp->sd_sb.sb_bsize_shift);
+ unsigned int blocks = PAGE_CACHE_SIZE >> sdp->sd_sb.sb_bsize_shift;
+ struct gfs2_alloc *al;
+ unsigned int data_blocks, ind_blocks;
+ unsigned int x;
+ int error;
+
+ al = gfs2_alloc_get(ip);
+
+ error = gfs2_quota_lock(ip, NO_QUOTA_CHANGE, NO_QUOTA_CHANGE);
+ if (error)
+ goto out;
+
+ error = gfs2_quota_check(ip, ip->i_di.di_uid, ip->i_di.di_gid);
+ if (error)
+ goto out_gunlock_q;
+
+ gfs2_write_calc_reserv(ip, PAGE_CACHE_SIZE, &data_blocks, &ind_blocks);
+
+ al->al_requested = data_blocks + ind_blocks;
+
+ error = gfs2_inplace_reserve(ip);
+ if (error)
+ goto out_gunlock_q;
+
+ error = gfs2_trans_begin(sdp, al->al_rgd->rd_ri.ri_length +
+ ind_blocks + RES_DINODE +
+ RES_STATFS + RES_QUOTA, 0);
+ if (error)
+ goto out_ipres;
+
+ if (gfs2_is_stuffed(ip)) {
+ error = gfs2_unstuff_dinode(ip, NULL);
+ if (error)
+ goto out_trans;
+ }
+
+ for (x = 0; x < blocks; ) {
+ u64 dblock;
+ unsigned int extlen;
+ int new = 1;
+
+ error = gfs2_extent_map(&ip->i_inode, lblock, &new, &dblock, &extlen);
+ if (error)
+ goto out_trans;
+
+ lblock += extlen;
+ x += extlen;
+ }
+
+ gfs2_assert_warn(sdp, al->al_alloced);
+
+out_trans:
+ gfs2_trans_end(sdp);
+out_ipres:
+ gfs2_inplace_release(ip);
+out_gunlock_q:
+ gfs2_quota_unlock(ip);
+out:
+ gfs2_alloc_put(ip);
+ return error;
+}
+
+static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
+ unsigned long address, int *type)
+{
+ struct file *file = area->vm_file;
+ struct gfs2_file *gf = file->private_data;
+ struct gfs2_inode *ip = GFS2_I(file->f_mapping->host);
+ struct gfs2_holder i_gh;
+ struct page *result = NULL;
+ unsigned long index = ((address - area->vm_start) >> PAGE_CACHE_SHIFT) +
+ area->vm_pgoff;
+ int alloc_required;
+ int error;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+ if (error)
+ return NULL;
+
+ set_bit(GIF_PAGED, &ip->i_flags);
+ set_bit(GIF_SW_PAGED, &ip->i_flags);
+
+ error = gfs2_write_alloc_required(ip, (u64)index << PAGE_CACHE_SHIFT,
+ PAGE_CACHE_SIZE, &alloc_required);
+ if (error)
+ goto out;
+
+ set_bit(GFF_EXLOCK, &gf->f_flags);
+ result = filemap_nopage(area, address, type);
+ clear_bit(GFF_EXLOCK, &gf->f_flags);
+ if (!result || result == NOPAGE_OOM)
+ goto out;
+
+ if (alloc_required) {
+ error = alloc_page_backing(ip, result);
+ if (error) {
+ page_cache_release(result);
+ result = NULL;
+ goto out;
+ }
+ set_page_dirty(result);
+ }
+
+ pfault_be_greedy(ip);
+out:
+ gfs2_glock_dq_uninit(&i_gh);
+
+ return result;
+}
+
+struct vm_operations_struct gfs2_vm_ops_private = {
+ .nopage = gfs2_private_nopage,
+};
+
+struct vm_operations_struct gfs2_vm_ops_sharewrite = {
+ .nopage = gfs2_sharewrite_nopage,
+};
+
diff --git a/fs/gfs2/ops_vm.h b/fs/gfs2/ops_vm.h
new file mode 100644
index 000000000000..4ae8f43ed5e3
--- /dev/null
+++ b/fs/gfs2/ops_vm.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __OPS_VM_DOT_H__
+#define __OPS_VM_DOT_H__
+
+#include <linux/mm.h>
+
+extern struct vm_operations_struct gfs2_vm_ops_private;
+extern struct vm_operations_struct gfs2_vm_ops_sharewrite;
+
+#endif /* __OPS_VM_DOT_H__ */
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
new file mode 100644
index 000000000000..a3deae7416c9
--- /dev/null
+++ b/fs/gfs2/quota.c
@@ -0,0 +1,1228 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+/*
+ * Quota change tags are associated with each transaction that allocates or
+ * deallocates space. Those changes are accumulated locally to each node (in a
+ * per-node file) and then are periodically synced to the quota file. This
+ * avoids the bottleneck of constantly touching the quota file, but introduces
+ * fuzziness in the current usage value of IDs that are being used on different
+ * nodes in the cluster simultaneously. So, it is possible for a user on
+ * multiple nodes to overrun their quota, but that overrun is controlable.
+ * Since quota tags are part of transactions, there is no need to a quota check
+ * program to be run on node crashes or anything like that.
+ *
+ * There are couple of knobs that let the administrator manage the quota
+ * fuzziness. "quota_quantum" sets the maximum time a quota change can be
+ * sitting on one node before being synced to the quota file. (The default is
+ * 60 seconds.) Another knob, "quota_scale" controls how quickly the frequency
+ * of quota file syncs increases as the user moves closer to their limit. The
+ * more frequent the syncs, the more accurate the quota enforcement, but that
+ * means that there is more contention between the nodes for the quota file.
+ * The default value is one. This sets the maximum theoretical quota overrun
+ * (with infinite node with infinite bandwidth) to twice the user's limit. (In
+ * practice, the maximum overrun you see should be much less.) A "quota_scale"
+ * number greater than one makes quota syncs more frequent and reduces the
+ * maximum overrun. Numbers less than one (but greater than zero) make quota
+ * syncs less frequent.
+ *
+ * GFS quotas also use per-ID Lock Value Blocks (LVBs) to cache the contents of
+ * the quota file, so it is not being constantly read.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/sort.h>
+#include <linux/fs.h>
+#include <linux/bio.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "glops.h"
+#include "log.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "super.h"
+#include "trans.h"
+#include "inode.h"
+#include "ops_file.h"
+#include "ops_address.h"
+#include "util.h"
+
+#define QUOTA_USER 1
+#define QUOTA_GROUP 0
+
+static u64 qd2offset(struct gfs2_quota_data *qd)
+{
+ u64 offset;
+
+ offset = 2 * (u64)qd->qd_id + !test_bit(QDF_USER, &qd->qd_flags);
+ offset *= sizeof(struct gfs2_quota);
+
+ return offset;
+}
+
+static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id,
+ struct gfs2_quota_data **qdp)
+{
+ struct gfs2_quota_data *qd;
+ int error;
+
+ qd = kzalloc(sizeof(struct gfs2_quota_data), GFP_KERNEL);
+ if (!qd)
+ return -ENOMEM;
+
+ qd->qd_count = 1;
+ qd->qd_id = id;
+ if (user)
+ set_bit(QDF_USER, &qd->qd_flags);
+ qd->qd_slot = -1;
+
+ error = gfs2_glock_get(sdp, 2 * (u64)id + !user,
+ &gfs2_quota_glops, CREATE, &qd->qd_gl);
+ if (error)
+ goto fail;
+
+ error = gfs2_lvb_hold(qd->qd_gl);
+ gfs2_glock_put(qd->qd_gl);
+ if (error)
+ goto fail;
+
+ *qdp = qd;
+
+ return 0;
+
+fail:
+ kfree(qd);
+ return error;
+}
+
+static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
+ struct gfs2_quota_data **qdp)
+{
+ struct gfs2_quota_data *qd = NULL, *new_qd = NULL;
+ int error, found;
+
+ *qdp = NULL;
+
+ for (;;) {
+ found = 0;
+ spin_lock(&sdp->sd_quota_spin);
+ list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
+ if (qd->qd_id == id &&
+ !test_bit(QDF_USER, &qd->qd_flags) == !user) {
+ qd->qd_count++;
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ qd = NULL;
+
+ if (!qd && new_qd) {
+ qd = new_qd;
+ list_add(&qd->qd_list, &sdp->sd_quota_list);
+ atomic_inc(&sdp->sd_quota_count);
+ new_qd = NULL;
+ }
+
+ spin_unlock(&sdp->sd_quota_spin);
+
+ if (qd || !create) {
+ if (new_qd) {
+ gfs2_lvb_unhold(new_qd->qd_gl);
+ kfree(new_qd);
+ }
+ *qdp = qd;
+ return 0;
+ }
+
+ error = qd_alloc(sdp, user, id, &new_qd);
+ if (error)
+ return error;
+ }
+}
+
+static void qd_hold(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+ spin_lock(&sdp->sd_quota_spin);
+ gfs2_assert(sdp, qd->qd_count);
+ qd->qd_count++;
+ spin_unlock(&sdp->sd_quota_spin);
+}
+
+static void qd_put(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+ spin_lock(&sdp->sd_quota_spin);
+ gfs2_assert(sdp, qd->qd_count);
+ if (!--qd->qd_count)
+ qd->qd_last_touched = jiffies;
+ spin_unlock(&sdp->sd_quota_spin);
+}
+
+static int slot_get(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+ unsigned int c, o = 0, b;
+ unsigned char byte = 0;
+
+ spin_lock(&sdp->sd_quota_spin);
+
+ if (qd->qd_slot_count++) {
+ spin_unlock(&sdp->sd_quota_spin);
+ return 0;
+ }
+
+ for (c = 0; c < sdp->sd_quota_chunks; c++)
+ for (o = 0; o < PAGE_SIZE; o++) {
+ byte = sdp->sd_quota_bitmap[c][o];
+ if (byte != 0xFF)
+ goto found;
+ }
+
+ goto fail;
+
+found:
+ for (b = 0; b < 8; b++)
+ if (!(byte & (1 << b)))
+ break;
+ qd->qd_slot = c * (8 * PAGE_SIZE) + o * 8 + b;
+
+ if (qd->qd_slot >= sdp->sd_quota_slots)
+ goto fail;
+
+ sdp->sd_quota_bitmap[c][o] |= 1 << b;
+
+ spin_unlock(&sdp->sd_quota_spin);
+
+ return 0;
+
+fail:
+ qd->qd_slot_count--;
+ spin_unlock(&sdp->sd_quota_spin);
+ return -ENOSPC;
+}
+
+static void slot_hold(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+ spin_lock(&sdp->sd_quota_spin);
+ gfs2_assert(sdp, qd->qd_slot_count);
+ qd->qd_slot_count++;
+ spin_unlock(&sdp->sd_quota_spin);
+}
+
+static void slot_put(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+ spin_lock(&sdp->sd_quota_spin);
+ gfs2_assert(sdp, qd->qd_slot_count);
+ if (!--qd->qd_slot_count) {
+ gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, qd->qd_slot, 0);
+ qd->qd_slot = -1;
+ }
+ spin_unlock(&sdp->sd_quota_spin);
+}
+
+static int bh_get(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
+ unsigned int block, offset;
+ struct buffer_head *bh;
+ int error;
+ struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
+
+ mutex_lock(&sdp->sd_quota_mutex);
+
+ if (qd->qd_bh_count++) {
+ mutex_unlock(&sdp->sd_quota_mutex);
+ return 0;
+ }
+
+ block = qd->qd_slot / sdp->sd_qc_per_block;
+ offset = qd->qd_slot % sdp->sd_qc_per_block;;
+
+ bh_map.b_size = 1 << ip->i_inode.i_blkbits;
+ error = gfs2_block_map(&ip->i_inode, block, 0, &bh_map);
+ if (error)
+ goto fail;
+ error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh);
+ if (error)
+ goto fail;
+ error = -EIO;
+ if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC))
+ goto fail_brelse;
+
+ qd->qd_bh = bh;
+ qd->qd_bh_qc = (struct gfs2_quota_change *)
+ (bh->b_data + sizeof(struct gfs2_meta_header) +
+ offset * sizeof(struct gfs2_quota_change));
+
+ mutex_lock(&sdp->sd_quota_mutex);
+
+ return 0;
+
+fail_brelse:
+ brelse(bh);
+fail:
+ qd->qd_bh_count--;
+ mutex_unlock(&sdp->sd_quota_mutex);
+ return error;
+}
+
+static void bh_put(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+ mutex_lock(&sdp->sd_quota_mutex);
+ gfs2_assert(sdp, qd->qd_bh_count);
+ if (!--qd->qd_bh_count) {
+ brelse(qd->qd_bh);
+ qd->qd_bh = NULL;
+ qd->qd_bh_qc = NULL;
+ }
+ mutex_unlock(&sdp->sd_quota_mutex);
+}
+
+static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp)
+{
+ struct gfs2_quota_data *qd = NULL;
+ int error;
+ int found = 0;
+
+ *qdp = NULL;
+
+ if (sdp->sd_vfs->s_flags & MS_RDONLY)
+ return 0;
+
+ spin_lock(&sdp->sd_quota_spin);
+
+ list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) {
+ if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
+ !test_bit(QDF_CHANGE, &qd->qd_flags) ||
+ qd->qd_sync_gen >= sdp->sd_quota_sync_gen)
+ continue;
+
+ list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
+
+ set_bit(QDF_LOCKED, &qd->qd_flags);
+ gfs2_assert_warn(sdp, qd->qd_count);
+ qd->qd_count++;
+ qd->qd_change_sync = qd->qd_change;
+ gfs2_assert_warn(sdp, qd->qd_slot_count);
+ qd->qd_slot_count++;
+ found = 1;
+
+ break;
+ }
+
+ if (!found)
+ qd = NULL;
+
+ spin_unlock(&sdp->sd_quota_spin);
+
+ if (qd) {
+ gfs2_assert_warn(sdp, qd->qd_change_sync);
+ error = bh_get(qd);
+ if (error) {
+ clear_bit(QDF_LOCKED, &qd->qd_flags);
+ slot_put(qd);
+ qd_put(qd);
+ return error;
+ }
+ }
+
+ *qdp = qd;
+
+ return 0;
+}
+
+static int qd_trylock(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+ if (sdp->sd_vfs->s_flags & MS_RDONLY)
+ return 0;
+
+ spin_lock(&sdp->sd_quota_spin);
+
+ if (test_bit(QDF_LOCKED, &qd->qd_flags) ||
+ !test_bit(QDF_CHANGE, &qd->qd_flags)) {
+ spin_unlock(&sdp->sd_quota_spin);
+ return 0;
+ }
+
+ list_move_tail(&qd->qd_list, &sdp->sd_quota_list);
+
+ set_bit(QDF_LOCKED, &qd->qd_flags);
+ gfs2_assert_warn(sdp, qd->qd_count);
+ qd->qd_count++;
+ qd->qd_change_sync = qd->qd_change;
+ gfs2_assert_warn(sdp, qd->qd_slot_count);
+ qd->qd_slot_count++;
+
+ spin_unlock(&sdp->sd_quota_spin);
+
+ gfs2_assert_warn(sdp, qd->qd_change_sync);
+ if (bh_get(qd)) {
+ clear_bit(QDF_LOCKED, &qd->qd_flags);
+ slot_put(qd);
+ qd_put(qd);
+ return 0;
+ }
+
+ return 1;
+}
+
+static void qd_unlock(struct gfs2_quota_data *qd)
+{
+ gfs2_assert_warn(qd->qd_gl->gl_sbd,
+ test_bit(QDF_LOCKED, &qd->qd_flags));
+ clear_bit(QDF_LOCKED, &qd->qd_flags);
+ bh_put(qd);
+ slot_put(qd);
+ qd_put(qd);
+}
+
+static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, int create,
+ struct gfs2_quota_data **qdp)
+{
+ int error;
+
+ error = qd_get(sdp, user, id, create, qdp);
+ if (error)
+ return error;
+
+ error = slot_get(*qdp);
+ if (error)
+ goto fail;
+
+ error = bh_get(*qdp);
+ if (error)
+ goto fail_slot;
+
+ return 0;
+
+fail_slot:
+ slot_put(*qdp);
+fail:
+ qd_put(*qdp);
+ return error;
+}
+
+static void qdsb_put(struct gfs2_quota_data *qd)
+{
+ bh_put(qd);
+ slot_put(qd);
+ qd_put(qd);
+}
+
+int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_quota_data **qd = al->al_qd;
+ int error;
+
+ if (gfs2_assert_warn(sdp, !al->al_qd_num) ||
+ gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)))
+ return -EIO;
+
+ if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF)
+ return 0;
+
+ error = qdsb_get(sdp, QUOTA_USER, ip->i_di.di_uid, CREATE, qd);
+ if (error)
+ goto out;
+ al->al_qd_num++;
+ qd++;
+
+ error = qdsb_get(sdp, QUOTA_GROUP, ip->i_di.di_gid, CREATE, qd);
+ if (error)
+ goto out;
+ al->al_qd_num++;
+ qd++;
+
+ if (uid != NO_QUOTA_CHANGE && uid != ip->i_di.di_uid) {
+ error = qdsb_get(sdp, QUOTA_USER, uid, CREATE, qd);
+ if (error)
+ goto out;
+ al->al_qd_num++;
+ qd++;
+ }
+
+ if (gid != NO_QUOTA_CHANGE && gid != ip->i_di.di_gid) {
+ error = qdsb_get(sdp, QUOTA_GROUP, gid, CREATE, qd);
+ if (error)
+ goto out;
+ al->al_qd_num++;
+ qd++;
+ }
+
+out:
+ if (error)
+ gfs2_quota_unhold(ip);
+ return error;
+}
+
+void gfs2_quota_unhold(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ unsigned int x;
+
+ gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags));
+
+ for (x = 0; x < al->al_qd_num; x++) {
+ qdsb_put(al->al_qd[x]);
+ al->al_qd[x] = NULL;
+ }
+ al->al_qd_num = 0;
+}
+
+static int sort_qd(const void *a, const void *b)
+{
+ const struct gfs2_quota_data *qd_a = *(const struct gfs2_quota_data **)a;
+ const struct gfs2_quota_data *qd_b = *(const struct gfs2_quota_data **)b;
+
+ if (!test_bit(QDF_USER, &qd_a->qd_flags) !=
+ !test_bit(QDF_USER, &qd_b->qd_flags)) {
+ if (test_bit(QDF_USER, &qd_a->qd_flags))
+ return -1;
+ else
+ return 1;
+ }
+ if (qd_a->qd_id < qd_b->qd_id)
+ return -1;
+ if (qd_a->qd_id > qd_b->qd_id)
+ return 1;
+
+ return 0;
+}
+
+static void do_qc(struct gfs2_quota_data *qd, s64 change)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
+ struct gfs2_quota_change *qc = qd->qd_bh_qc;
+ s64 x;
+
+ mutex_lock(&sdp->sd_quota_mutex);
+ gfs2_trans_add_bh(ip->i_gl, qd->qd_bh, 1);
+
+ if (!test_bit(QDF_CHANGE, &qd->qd_flags)) {
+ qc->qc_change = 0;
+ qc->qc_flags = 0;
+ if (test_bit(QDF_USER, &qd->qd_flags))
+ qc->qc_flags = cpu_to_be32(GFS2_QCF_USER);
+ qc->qc_id = cpu_to_be32(qd->qd_id);
+ }
+
+ x = qc->qc_change;
+ x = be64_to_cpu(x) + change;
+ qc->qc_change = cpu_to_be64(x);
+
+ spin_lock(&sdp->sd_quota_spin);
+ qd->qd_change = x;
+ spin_unlock(&sdp->sd_quota_spin);
+
+ if (!x) {
+ gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags));
+ clear_bit(QDF_CHANGE, &qd->qd_flags);
+ qc->qc_flags = 0;
+ qc->qc_id = 0;
+ slot_put(qd);
+ qd_put(qd);
+ } else if (!test_and_set_bit(QDF_CHANGE, &qd->qd_flags)) {
+ qd_hold(qd);
+ slot_hold(qd);
+ }
+
+ mutex_unlock(&sdp->sd_quota_mutex);
+}
+
+/**
+ * gfs2_adjust_quota
+ *
+ * This function was mostly borrowed from gfs2_block_truncate_page which was
+ * in turn mostly borrowed from ext3
+ */
+static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc,
+ s64 change, struct gfs2_quota_data *qd)
+{
+ struct inode *inode = &ip->i_inode;
+ struct address_space *mapping = inode->i_mapping;
+ unsigned long index = loc >> PAGE_CACHE_SHIFT;
+ unsigned offset = loc & (PAGE_CACHE_SHIFT - 1);
+ unsigned blocksize, iblock, pos;
+ struct buffer_head *bh;
+ struct page *page;
+ void *kaddr;
+ __be64 *ptr;
+ s64 value;
+ int err = -EIO;
+
+ page = grab_cache_page(mapping, index);
+ if (!page)
+ return -ENOMEM;
+
+ blocksize = inode->i_sb->s_blocksize;
+ iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+
+ if (!page_has_buffers(page))
+ create_empty_buffers(page, blocksize, 0);
+
+ bh = page_buffers(page);
+ pos = blocksize;
+ while (offset >= pos) {
+ bh = bh->b_this_page;
+ iblock++;
+ pos += blocksize;
+ }
+
+ if (!buffer_mapped(bh)) {
+ gfs2_get_block(inode, iblock, bh, 1);
+ if (!buffer_mapped(bh))
+ goto unlock;
+ }
+
+ if (PageUptodate(page))
+ set_buffer_uptodate(bh);
+
+ if (!buffer_uptodate(bh)) {
+ ll_rw_block(READ_META, 1, &bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh))
+ goto unlock;
+ }
+
+ gfs2_trans_add_bh(ip->i_gl, bh, 0);
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ ptr = kaddr + offset;
+ value = (s64)be64_to_cpu(*ptr) + change;
+ *ptr = cpu_to_be64(value);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ err = 0;
+ qd->qd_qb.qb_magic = cpu_to_be32(GFS2_MAGIC);
+ qd->qd_qb.qb_value = cpu_to_be64(value);
+unlock:
+ unlock_page(page);
+ page_cache_release(page);
+ return err;
+}
+
+static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda)
+{
+ struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+ unsigned int data_blocks, ind_blocks;
+ struct gfs2_holder *ghs, i_gh;
+ unsigned int qx, x;
+ struct gfs2_quota_data *qd;
+ loff_t offset;
+ unsigned int nalloc = 0;
+ struct gfs2_alloc *al = NULL;
+ int error;
+
+ gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota),
+ &data_blocks, &ind_blocks);
+
+ ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_KERNEL);
+ if (!ghs)
+ return -ENOMEM;
+
+ sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL);
+ for (qx = 0; qx < num_qd; qx++) {
+ error = gfs2_glock_nq_init(qda[qx]->qd_gl,
+ LM_ST_EXCLUSIVE,
+ GL_NOCACHE, &ghs[qx]);
+ if (error)
+ goto out;
+ }
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh);
+ if (error)
+ goto out;
+
+ for (x = 0; x < num_qd; x++) {
+ int alloc_required;
+
+ offset = qd2offset(qda[x]);
+ error = gfs2_write_alloc_required(ip, offset,
+ sizeof(struct gfs2_quota),
+ &alloc_required);
+ if (error)
+ goto out_gunlock;
+ if (alloc_required)
+ nalloc++;
+ }
+
+ if (nalloc) {
+ al = gfs2_alloc_get(ip);
+
+ al->al_requested = nalloc * (data_blocks + ind_blocks);
+
+ error = gfs2_inplace_reserve(ip);
+ if (error)
+ goto out_alloc;
+
+ error = gfs2_trans_begin(sdp,
+ al->al_rgd->rd_ri.ri_length +
+ num_qd * data_blocks +
+ nalloc * ind_blocks +
+ RES_DINODE + num_qd +
+ RES_STATFS, 0);
+ if (error)
+ goto out_ipres;
+ } else {
+ error = gfs2_trans_begin(sdp,
+ num_qd * data_blocks +
+ RES_DINODE + num_qd, 0);
+ if (error)
+ goto out_gunlock;
+ }
+
+ for (x = 0; x < num_qd; x++) {
+ qd = qda[x];
+ offset = qd2offset(qd);
+ error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync,
+ (struct gfs2_quota_data *)
+ qd->qd_gl->gl_lvb);
+ if (error)
+ goto out_end_trans;
+
+ do_qc(qd, -qd->qd_change_sync);
+ }
+
+ error = 0;
+
+out_end_trans:
+ gfs2_trans_end(sdp);
+out_ipres:
+ if (nalloc)
+ gfs2_inplace_release(ip);
+out_alloc:
+ if (nalloc)
+ gfs2_alloc_put(ip);
+out_gunlock:
+ gfs2_glock_dq_uninit(&i_gh);
+out:
+ while (qx--)
+ gfs2_glock_dq_uninit(&ghs[qx]);
+ kfree(ghs);
+ gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl);
+ return error;
+}
+
+static int do_glock(struct gfs2_quota_data *qd, int force_refresh,
+ struct gfs2_holder *q_gh)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode);
+ struct gfs2_holder i_gh;
+ struct gfs2_quota q;
+ char buf[sizeof(struct gfs2_quota)];
+ struct file_ra_state ra_state;
+ int error;
+ struct gfs2_quota_lvb *qlvb;
+
+ file_ra_state_init(&ra_state, sdp->sd_quota_inode->i_mapping);
+restart:
+ error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh);
+ if (error)
+ return error;
+
+ qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
+
+ if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) {
+ loff_t pos;
+ gfs2_glock_dq_uninit(q_gh);
+ error = gfs2_glock_nq_init(qd->qd_gl,
+ LM_ST_EXCLUSIVE, GL_NOCACHE,
+ q_gh);
+ if (error)
+ return error;
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
+ if (error)
+ goto fail;
+
+ memset(buf, 0, sizeof(struct gfs2_quota));
+ pos = qd2offset(qd);
+ error = gfs2_internal_read(ip, &ra_state, buf,
+ &pos, sizeof(struct gfs2_quota));
+ if (error < 0)
+ goto fail_gunlock;
+
+ gfs2_glock_dq_uninit(&i_gh);
+
+
+ gfs2_quota_in(&q, buf);
+ qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb;
+ qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC);
+ qlvb->__pad = 0;
+ qlvb->qb_limit = cpu_to_be64(q.qu_limit);
+ qlvb->qb_warn = cpu_to_be64(q.qu_warn);
+ qlvb->qb_value = cpu_to_be64(q.qu_value);
+ qd->qd_qb = *qlvb;
+
+ if (gfs2_glock_is_blocking(qd->qd_gl)) {
+ gfs2_glock_dq_uninit(q_gh);
+ force_refresh = 0;
+ goto restart;
+ }
+ }
+
+ return 0;
+
+fail_gunlock:
+ gfs2_glock_dq_uninit(&i_gh);
+fail:
+ gfs2_glock_dq_uninit(q_gh);
+ return error;
+}
+
+int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ unsigned int x;
+ int error = 0;
+
+ gfs2_quota_hold(ip, uid, gid);
+
+ if (capable(CAP_SYS_RESOURCE) ||
+ sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
+ return 0;
+
+ sort(al->al_qd, al->al_qd_num, sizeof(struct gfs2_quota_data *),
+ sort_qd, NULL);
+
+ for (x = 0; x < al->al_qd_num; x++) {
+ error = do_glock(al->al_qd[x], NO_FORCE, &al->al_qd_ghs[x]);
+ if (error)
+ break;
+ }
+
+ if (!error)
+ set_bit(GIF_QD_LOCKED, &ip->i_flags);
+ else {
+ while (x--)
+ gfs2_glock_dq_uninit(&al->al_qd_ghs[x]);
+ gfs2_quota_unhold(ip);
+ }
+
+ return error;
+}
+
+static int need_sync(struct gfs2_quota_data *qd)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+ struct gfs2_tune *gt = &sdp->sd_tune;
+ s64 value;
+ unsigned int num, den;
+ int do_sync = 1;
+
+ if (!qd->qd_qb.qb_limit)
+ return 0;
+
+ spin_lock(&sdp->sd_quota_spin);
+ value = qd->qd_change;
+ spin_unlock(&sdp->sd_quota_spin);
+
+ spin_lock(&gt->gt_spin);
+ num = gt->gt_quota_scale_num;
+ den = gt->gt_quota_scale_den;
+ spin_unlock(&gt->gt_spin);
+
+ if (value < 0)
+ do_sync = 0;
+ else if ((s64)be64_to_cpu(qd->qd_qb.qb_value) >=
+ (s64)be64_to_cpu(qd->qd_qb.qb_limit))
+ do_sync = 0;
+ else {
+ value *= gfs2_jindex_size(sdp) * num;
+ do_div(value, den);
+ value += (s64)be64_to_cpu(qd->qd_qb.qb_value);
+ if (value < (s64)be64_to_cpu(qd->qd_qb.qb_limit))
+ do_sync = 0;
+ }
+
+ return do_sync;
+}
+
+void gfs2_quota_unlock(struct gfs2_inode *ip)
+{
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_quota_data *qda[4];
+ unsigned int count = 0;
+ unsigned int x;
+
+ if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags))
+ goto out;
+
+ for (x = 0; x < al->al_qd_num; x++) {
+ struct gfs2_quota_data *qd;
+ int sync;
+
+ qd = al->al_qd[x];
+ sync = need_sync(qd);
+
+ gfs2_glock_dq_uninit(&al->al_qd_ghs[x]);
+
+ if (sync && qd_trylock(qd))
+ qda[count++] = qd;
+ }
+
+ if (count) {
+ do_sync(count, qda);
+ for (x = 0; x < count; x++)
+ qd_unlock(qda[x]);
+ }
+
+out:
+ gfs2_quota_unhold(ip);
+}
+
+#define MAX_LINE 256
+
+static int print_message(struct gfs2_quota_data *qd, char *type)
+{
+ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd;
+
+ printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u\r\n",
+ sdp->sd_fsname, type,
+ (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group",
+ qd->qd_id);
+
+ return 0;
+}
+
+int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_quota_data *qd;
+ s64 value;
+ unsigned int x;
+ int error = 0;
+
+ if (!test_bit(GIF_QD_LOCKED, &ip->i_flags))
+ return 0;
+
+ if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON)
+ return 0;
+
+ for (x = 0; x < al->al_qd_num; x++) {
+ qd = al->al_qd[x];
+
+ if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
+ (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))))
+ continue;
+
+ value = (s64)be64_to_cpu(qd->qd_qb.qb_value);
+ spin_lock(&sdp->sd_quota_spin);
+ value += qd->qd_change;
+ spin_unlock(&sdp->sd_quota_spin);
+
+ if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) {
+ print_message(qd, "exceeded");
+ error = -EDQUOT;
+ break;
+ } else if (be64_to_cpu(qd->qd_qb.qb_warn) &&
+ (s64)be64_to_cpu(qd->qd_qb.qb_warn) < value &&
+ time_after_eq(jiffies, qd->qd_last_warn +
+ gfs2_tune_get(sdp,
+ gt_quota_warn_period) * HZ)) {
+ error = print_message(qd, "warning");
+ qd->qd_last_warn = jiffies;
+ }
+ }
+
+ return error;
+}
+
+void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
+ u32 uid, u32 gid)
+{
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_quota_data *qd;
+ unsigned int x;
+ unsigned int found = 0;
+
+ if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change))
+ return;
+ if (ip->i_di.di_flags & GFS2_DIF_SYSTEM)
+ return;
+
+ for (x = 0; x < al->al_qd_num; x++) {
+ qd = al->al_qd[x];
+
+ if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) ||
+ (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) {
+ do_qc(qd, change);
+ found++;
+ }
+ }
+}
+
+int gfs2_quota_sync(struct gfs2_sbd *sdp)
+{
+ struct gfs2_quota_data **qda;
+ unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync);
+ unsigned int num_qd;
+ unsigned int x;
+ int error = 0;
+
+ sdp->sd_quota_sync_gen++;
+
+ qda = kcalloc(max_qd, sizeof(struct gfs2_quota_data *), GFP_KERNEL);
+ if (!qda)
+ return -ENOMEM;
+
+ do {
+ num_qd = 0;
+
+ for (;;) {
+ error = qd_fish(sdp, qda + num_qd);
+ if (error || !qda[num_qd])
+ break;
+ if (++num_qd == max_qd)
+ break;
+ }
+
+ if (num_qd) {
+ if (!error)
+ error = do_sync(num_qd, qda);
+ if (!error)
+ for (x = 0; x < num_qd; x++)
+ qda[x]->qd_sync_gen =
+ sdp->sd_quota_sync_gen;
+
+ for (x = 0; x < num_qd; x++)
+ qd_unlock(qda[x]);
+ }
+ } while (!error && num_qd == max_qd);
+
+ kfree(qda);
+
+ return error;
+}
+
+int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
+{
+ struct gfs2_quota_data *qd;
+ struct gfs2_holder q_gh;
+ int error;
+
+ error = qd_get(sdp, user, id, CREATE, &qd);
+ if (error)
+ return error;
+
+ error = do_glock(qd, FORCE, &q_gh);
+ if (!error)
+ gfs2_glock_dq_uninit(&q_gh);
+
+ qd_put(qd);
+
+ return error;
+}
+
+int gfs2_quota_init(struct gfs2_sbd *sdp)
+{
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode);
+ unsigned int blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift;
+ unsigned int x, slot = 0;
+ unsigned int found = 0;
+ u64 dblock;
+ u32 extlen = 0;
+ int error;
+
+ if (!ip->i_di.di_size || ip->i_di.di_size > (64 << 20) ||
+ ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1)) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+ sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block;
+ sdp->sd_quota_chunks = DIV_ROUND_UP(sdp->sd_quota_slots, 8 * PAGE_SIZE);
+
+ error = -ENOMEM;
+
+ sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks,
+ sizeof(unsigned char *), GFP_KERNEL);
+ if (!sdp->sd_quota_bitmap)
+ return error;
+
+ for (x = 0; x < sdp->sd_quota_chunks; x++) {
+ sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!sdp->sd_quota_bitmap[x])
+ goto fail;
+ }
+
+ for (x = 0; x < blocks; x++) {
+ struct buffer_head *bh;
+ unsigned int y;
+
+ if (!extlen) {
+ int new = 0;
+ error = gfs2_extent_map(&ip->i_inode, x, &new, &dblock, &extlen);
+ if (error)
+ goto fail;
+ }
+ error = -EIO;
+ bh = gfs2_meta_ra(ip->i_gl, dblock, extlen);
+ if (!bh)
+ goto fail;
+ if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) {
+ brelse(bh);
+ goto fail;
+ }
+
+ for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots;
+ y++, slot++) {
+ struct gfs2_quota_change qc;
+ struct gfs2_quota_data *qd;
+
+ gfs2_quota_change_in(&qc, bh->b_data +
+ sizeof(struct gfs2_meta_header) +
+ y * sizeof(struct gfs2_quota_change));
+ if (!qc.qc_change)
+ continue;
+
+ error = qd_alloc(sdp, (qc.qc_flags & GFS2_QCF_USER),
+ qc.qc_id, &qd);
+ if (error) {
+ brelse(bh);
+ goto fail;
+ }
+
+ set_bit(QDF_CHANGE, &qd->qd_flags);
+ qd->qd_change = qc.qc_change;
+ qd->qd_slot = slot;
+ qd->qd_slot_count = 1;
+ qd->qd_last_touched = jiffies;
+
+ spin_lock(&sdp->sd_quota_spin);
+ gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, slot, 1);
+ list_add(&qd->qd_list, &sdp->sd_quota_list);
+ atomic_inc(&sdp->sd_quota_count);
+ spin_unlock(&sdp->sd_quota_spin);
+
+ found++;
+ }
+
+ brelse(bh);
+ dblock++;
+ extlen--;
+ }
+
+ if (found)
+ fs_info(sdp, "found %u quota changes\n", found);
+
+ return 0;
+
+fail:
+ gfs2_quota_cleanup(sdp);
+ return error;
+}
+
+void gfs2_quota_scan(struct gfs2_sbd *sdp)
+{
+ struct gfs2_quota_data *qd, *safe;
+ LIST_HEAD(dead);
+
+ spin_lock(&sdp->sd_quota_spin);
+ list_for_each_entry_safe(qd, safe, &sdp->sd_quota_list, qd_list) {
+ if (!qd->qd_count &&
+ time_after_eq(jiffies, qd->qd_last_touched +
+ gfs2_tune_get(sdp, gt_quota_cache_secs) * HZ)) {
+ list_move(&qd->qd_list, &dead);
+ gfs2_assert_warn(sdp,
+ atomic_read(&sdp->sd_quota_count) > 0);
+ atomic_dec(&sdp->sd_quota_count);
+ }
+ }
+ spin_unlock(&sdp->sd_quota_spin);
+
+ while (!list_empty(&dead)) {
+ qd = list_entry(dead.next, struct gfs2_quota_data, qd_list);
+ list_del(&qd->qd_list);
+
+ gfs2_assert_warn(sdp, !qd->qd_change);
+ gfs2_assert_warn(sdp, !qd->qd_slot_count);
+ gfs2_assert_warn(sdp, !qd->qd_bh_count);
+
+ gfs2_lvb_unhold(qd->qd_gl);
+ kfree(qd);
+ }
+}
+
+void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
+{
+ struct list_head *head = &sdp->sd_quota_list;
+ struct gfs2_quota_data *qd;
+ unsigned int x;
+
+ spin_lock(&sdp->sd_quota_spin);
+ while (!list_empty(head)) {
+ qd = list_entry(head->prev, struct gfs2_quota_data, qd_list);
+
+ if (qd->qd_count > 1 ||
+ (qd->qd_count && !test_bit(QDF_CHANGE, &qd->qd_flags))) {
+ list_move(&qd->qd_list, head);
+ spin_unlock(&sdp->sd_quota_spin);
+ schedule();
+ spin_lock(&sdp->sd_quota_spin);
+ continue;
+ }
+
+ list_del(&qd->qd_list);
+ atomic_dec(&sdp->sd_quota_count);
+ spin_unlock(&sdp->sd_quota_spin);
+
+ if (!qd->qd_count) {
+ gfs2_assert_warn(sdp, !qd->qd_change);
+ gfs2_assert_warn(sdp, !qd->qd_slot_count);
+ } else
+ gfs2_assert_warn(sdp, qd->qd_slot_count == 1);
+ gfs2_assert_warn(sdp, !qd->qd_bh_count);
+
+ gfs2_lvb_unhold(qd->qd_gl);
+ kfree(qd);
+
+ spin_lock(&sdp->sd_quota_spin);
+ }
+ spin_unlock(&sdp->sd_quota_spin);
+
+ gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count));
+
+ if (sdp->sd_quota_bitmap) {
+ for (x = 0; x < sdp->sd_quota_chunks; x++)
+ kfree(sdp->sd_quota_bitmap[x]);
+ kfree(sdp->sd_quota_bitmap);
+ }
+}
+
diff --git a/fs/gfs2/quota.h b/fs/gfs2/quota.h
new file mode 100644
index 000000000000..a8be1417051f
--- /dev/null
+++ b/fs/gfs2/quota.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __QUOTA_DOT_H__
+#define __QUOTA_DOT_H__
+
+struct gfs2_inode;
+struct gfs2_sbd;
+
+#define NO_QUOTA_CHANGE ((u32)-1)
+
+int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid);
+void gfs2_quota_unhold(struct gfs2_inode *ip);
+
+int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid);
+void gfs2_quota_unlock(struct gfs2_inode *ip);
+
+int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid);
+void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
+ u32 uid, u32 gid);
+
+int gfs2_quota_sync(struct gfs2_sbd *sdp);
+int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id);
+
+int gfs2_quota_init(struct gfs2_sbd *sdp);
+void gfs2_quota_scan(struct gfs2_sbd *sdp);
+void gfs2_quota_cleanup(struct gfs2_sbd *sdp);
+
+#endif /* __QUOTA_DOT_H__ */
diff --git a/fs/gfs2/recovery.c b/fs/gfs2/recovery.c
new file mode 100644
index 000000000000..62cd223819b7
--- /dev/null
+++ b/fs/gfs2/recovery.c
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/crc32.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "glock.h"
+#include "glops.h"
+#include "lm.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "recovery.h"
+#include "super.h"
+#include "util.h"
+#include "dir.h"
+
+int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
+ struct buffer_head **bh)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_glock *gl = ip->i_gl;
+ int new = 0;
+ u64 dblock;
+ u32 extlen;
+ int error;
+
+ error = gfs2_extent_map(&ip->i_inode, blk, &new, &dblock, &extlen);
+ if (error)
+ return error;
+ if (!dblock) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+
+ *bh = gfs2_meta_ra(gl, dblock, extlen);
+
+ return error;
+}
+
+int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where)
+{
+ struct list_head *head = &sdp->sd_revoke_list;
+ struct gfs2_revoke_replay *rr;
+ int found = 0;
+
+ list_for_each_entry(rr, head, rr_list) {
+ if (rr->rr_blkno == blkno) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (found) {
+ rr->rr_where = where;
+ return 0;
+ }
+
+ rr = kmalloc(sizeof(struct gfs2_revoke_replay), GFP_KERNEL);
+ if (!rr)
+ return -ENOMEM;
+
+ rr->rr_blkno = blkno;
+ rr->rr_where = where;
+ list_add(&rr->rr_list, head);
+
+ return 1;
+}
+
+int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where)
+{
+ struct gfs2_revoke_replay *rr;
+ int wrap, a, b, revoke;
+ int found = 0;
+
+ list_for_each_entry(rr, &sdp->sd_revoke_list, rr_list) {
+ if (rr->rr_blkno == blkno) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return 0;
+
+ wrap = (rr->rr_where < sdp->sd_replay_tail);
+ a = (sdp->sd_replay_tail < where);
+ b = (where < rr->rr_where);
+ revoke = (wrap) ? (a || b) : (a && b);
+
+ return revoke;
+}
+
+void gfs2_revoke_clean(struct gfs2_sbd *sdp)
+{
+ struct list_head *head = &sdp->sd_revoke_list;
+ struct gfs2_revoke_replay *rr;
+
+ while (!list_empty(head)) {
+ rr = list_entry(head->next, struct gfs2_revoke_replay, rr_list);
+ list_del(&rr->rr_list);
+ kfree(rr);
+ }
+}
+
+/**
+ * get_log_header - read the log header for a given segment
+ * @jd: the journal
+ * @blk: the block to look at
+ * @lh: the log header to return
+ *
+ * Read the log header for a given segement in a given journal. Do a few
+ * sanity checks on it.
+ *
+ * Returns: 0 on success,
+ * 1 if the header was invalid or incomplete,
+ * errno on error
+ */
+
+static int get_log_header(struct gfs2_jdesc *jd, unsigned int blk,
+ struct gfs2_log_header *head)
+{
+ struct buffer_head *bh;
+ struct gfs2_log_header lh;
+ u32 hash;
+ int error;
+
+ error = gfs2_replay_read_block(jd, blk, &bh);
+ if (error)
+ return error;
+
+ memcpy(&lh, bh->b_data, sizeof(struct gfs2_log_header));
+ lh.lh_hash = 0;
+ hash = gfs2_disk_hash((char *)&lh, sizeof(struct gfs2_log_header));
+ gfs2_log_header_in(&lh, bh->b_data);
+
+ brelse(bh);
+
+ if (lh.lh_header.mh_magic != GFS2_MAGIC ||
+ lh.lh_header.mh_type != GFS2_METATYPE_LH ||
+ lh.lh_blkno != blk || lh.lh_hash != hash)
+ return 1;
+
+ *head = lh;
+
+ return 0;
+}
+
+/**
+ * find_good_lh - find a good log header
+ * @jd: the journal
+ * @blk: the segment to start searching from
+ * @lh: the log header to fill in
+ * @forward: if true search forward in the log, else search backward
+ *
+ * Call get_log_header() to get a log header for a segment, but if the
+ * segment is bad, either scan forward or backward until we find a good one.
+ *
+ * Returns: errno
+ */
+
+static int find_good_lh(struct gfs2_jdesc *jd, unsigned int *blk,
+ struct gfs2_log_header *head)
+{
+ unsigned int orig_blk = *blk;
+ int error;
+
+ for (;;) {
+ error = get_log_header(jd, *blk, head);
+ if (error <= 0)
+ return error;
+
+ if (++*blk == jd->jd_blocks)
+ *blk = 0;
+
+ if (*blk == orig_blk) {
+ gfs2_consist_inode(GFS2_I(jd->jd_inode));
+ return -EIO;
+ }
+ }
+}
+
+/**
+ * jhead_scan - make sure we've found the head of the log
+ * @jd: the journal
+ * @head: this is filled in with the log descriptor of the head
+ *
+ * At this point, seg and lh should be either the head of the log or just
+ * before. Scan forward until we find the head.
+ *
+ * Returns: errno
+ */
+
+static int jhead_scan(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
+{
+ unsigned int blk = head->lh_blkno;
+ struct gfs2_log_header lh;
+ int error;
+
+ for (;;) {
+ if (++blk == jd->jd_blocks)
+ blk = 0;
+
+ error = get_log_header(jd, blk, &lh);
+ if (error < 0)
+ return error;
+ if (error == 1)
+ continue;
+
+ if (lh.lh_sequence == head->lh_sequence) {
+ gfs2_consist_inode(GFS2_I(jd->jd_inode));
+ return -EIO;
+ }
+ if (lh.lh_sequence < head->lh_sequence)
+ break;
+
+ *head = lh;
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_find_jhead - find the head of a log
+ * @jd: the journal
+ * @head: the log descriptor for the head of the log is returned here
+ *
+ * Do a binary search of a journal and find the valid log entry with the
+ * highest sequence number. (i.e. the log head)
+ *
+ * Returns: errno
+ */
+
+int gfs2_find_jhead(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
+{
+ struct gfs2_log_header lh_1, lh_m;
+ u32 blk_1, blk_2, blk_m;
+ int error;
+
+ blk_1 = 0;
+ blk_2 = jd->jd_blocks - 1;
+
+ for (;;) {
+ blk_m = (blk_1 + blk_2) / 2;
+
+ error = find_good_lh(jd, &blk_1, &lh_1);
+ if (error)
+ return error;
+
+ error = find_good_lh(jd, &blk_m, &lh_m);
+ if (error)
+ return error;
+
+ if (blk_1 == blk_m || blk_m == blk_2)
+ break;
+
+ if (lh_1.lh_sequence <= lh_m.lh_sequence)
+ blk_1 = blk_m;
+ else
+ blk_2 = blk_m;
+ }
+
+ error = jhead_scan(jd, &lh_1);
+ if (error)
+ return error;
+
+ *head = lh_1;
+
+ return error;
+}
+
+/**
+ * foreach_descriptor - go through the active part of the log
+ * @jd: the journal
+ * @start: the first log header in the active region
+ * @end: the last log header (don't process the contents of this entry))
+ *
+ * Call a given function once for every log descriptor in the active
+ * portion of the log.
+ *
+ * Returns: errno
+ */
+
+static int foreach_descriptor(struct gfs2_jdesc *jd, unsigned int start,
+ unsigned int end, int pass)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ struct buffer_head *bh;
+ struct gfs2_log_descriptor *ld;
+ int error = 0;
+ u32 length;
+ __be64 *ptr;
+ unsigned int offset = sizeof(struct gfs2_log_descriptor);
+ offset += sizeof(__be64) - 1;
+ offset &= ~(sizeof(__be64) - 1);
+
+ while (start != end) {
+ error = gfs2_replay_read_block(jd, start, &bh);
+ if (error)
+ return error;
+ if (gfs2_meta_check(sdp, bh)) {
+ brelse(bh);
+ return -EIO;
+ }
+ ld = (struct gfs2_log_descriptor *)bh->b_data;
+ length = be32_to_cpu(ld->ld_length);
+
+ if (be32_to_cpu(ld->ld_header.mh_type) == GFS2_METATYPE_LH) {
+ struct gfs2_log_header lh;
+ error = get_log_header(jd, start, &lh);
+ if (!error) {
+ gfs2_replay_incr_blk(sdp, &start);
+ brelse(bh);
+ continue;
+ }
+ if (error == 1) {
+ gfs2_consist_inode(GFS2_I(jd->jd_inode));
+ error = -EIO;
+ }
+ brelse(bh);
+ return error;
+ } else if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_LD)) {
+ brelse(bh);
+ return -EIO;
+ }
+ ptr = (__be64 *)(bh->b_data + offset);
+ error = lops_scan_elements(jd, start, ld, ptr, pass);
+ if (error) {
+ brelse(bh);
+ return error;
+ }
+
+ while (length--)
+ gfs2_replay_incr_blk(sdp, &start);
+
+ brelse(bh);
+ }
+
+ return 0;
+}
+
+/**
+ * clean_journal - mark a dirty journal as being clean
+ * @sdp: the filesystem
+ * @jd: the journal
+ * @gl: the journal's glock
+ * @head: the head journal to start from
+ *
+ * Returns: errno
+ */
+
+static int clean_journal(struct gfs2_jdesc *jd, struct gfs2_log_header *head)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ unsigned int lblock;
+ struct gfs2_log_header *lh;
+ u32 hash;
+ struct buffer_head *bh;
+ int error;
+ struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 };
+
+ lblock = head->lh_blkno;
+ gfs2_replay_incr_blk(sdp, &lblock);
+ bh_map.b_size = 1 << ip->i_inode.i_blkbits;
+ error = gfs2_block_map(&ip->i_inode, lblock, 0, &bh_map);
+ if (error)
+ return error;
+ if (!bh_map.b_blocknr) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+
+ bh = sb_getblk(sdp->sd_vfs, bh_map.b_blocknr);
+ lock_buffer(bh);
+ memset(bh->b_data, 0, bh->b_size);
+ set_buffer_uptodate(bh);
+ clear_buffer_dirty(bh);
+ unlock_buffer(bh);
+
+ lh = (struct gfs2_log_header *)bh->b_data;
+ memset(lh, 0, sizeof(struct gfs2_log_header));
+ lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
+ lh->lh_header.mh_type = cpu_to_be32(GFS2_METATYPE_LH);
+ lh->lh_header.mh_format = cpu_to_be32(GFS2_FORMAT_LH);
+ lh->lh_sequence = cpu_to_be64(head->lh_sequence + 1);
+ lh->lh_flags = cpu_to_be32(GFS2_LOG_HEAD_UNMOUNT);
+ lh->lh_blkno = cpu_to_be32(lblock);
+ hash = gfs2_disk_hash((const char *)lh, sizeof(struct gfs2_log_header));
+ lh->lh_hash = cpu_to_be32(hash);
+
+ set_buffer_dirty(bh);
+ if (sync_dirty_buffer(bh))
+ gfs2_io_error_bh(sdp, bh);
+ brelse(bh);
+
+ return error;
+}
+
+/**
+ * gfs2_recover_journal - recovery a given journal
+ * @jd: the struct gfs2_jdesc describing the journal
+ *
+ * Acquire the journal's lock, check to see if the journal is clean, and
+ * do recovery if necessary.
+ *
+ * Returns: errno
+ */
+
+int gfs2_recover_journal(struct gfs2_jdesc *jd)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ struct gfs2_log_header head;
+ struct gfs2_holder j_gh, ji_gh, t_gh;
+ unsigned long t;
+ int ro = 0;
+ unsigned int pass;
+ int error;
+
+ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
+ fs_info(sdp, "jid=%u: Trying to acquire journal lock...\n",
+ jd->jd_jid);
+
+ /* Aquire the journal lock so we can do recovery */
+
+ error = gfs2_glock_nq_num(sdp, jd->jd_jid, &gfs2_journal_glops,
+ LM_ST_EXCLUSIVE,
+ LM_FLAG_NOEXP | LM_FLAG_TRY | GL_NOCACHE,
+ &j_gh);
+ switch (error) {
+ case 0:
+ break;
+
+ case GLR_TRYFAILED:
+ fs_info(sdp, "jid=%u: Busy\n", jd->jd_jid);
+ error = 0;
+
+ default:
+ goto fail;
+ };
+
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED,
+ LM_FLAG_NOEXP, &ji_gh);
+ if (error)
+ goto fail_gunlock_j;
+ } else {
+ fs_info(sdp, "jid=%u, already locked for use\n", jd->jd_jid);
+ }
+
+ fs_info(sdp, "jid=%u: Looking at journal...\n", jd->jd_jid);
+
+ error = gfs2_jdesc_check(jd);
+ if (error)
+ goto fail_gunlock_ji;
+
+ error = gfs2_find_jhead(jd, &head);
+ if (error)
+ goto fail_gunlock_ji;
+
+ if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
+ fs_info(sdp, "jid=%u: Acquiring the transaction lock...\n",
+ jd->jd_jid);
+
+ t = jiffies;
+
+ /* Acquire a shared hold on the transaction lock */
+
+ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
+ LM_FLAG_NOEXP | LM_FLAG_PRIORITY |
+ GL_NOCANCEL | GL_NOCACHE, &t_gh);
+ if (error)
+ goto fail_gunlock_ji;
+
+ if (test_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags)) {
+ if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+ ro = 1;
+ } else {
+ if (sdp->sd_vfs->s_flags & MS_RDONLY)
+ ro = 1;
+ }
+
+ if (ro) {
+ fs_warn(sdp, "jid=%u: Can't replay: read-only FS\n",
+ jd->jd_jid);
+ error = -EROFS;
+ goto fail_gunlock_tr;
+ }
+
+ fs_info(sdp, "jid=%u: Replaying journal...\n", jd->jd_jid);
+
+ for (pass = 0; pass < 2; pass++) {
+ lops_before_scan(jd, &head, pass);
+ error = foreach_descriptor(jd, head.lh_tail,
+ head.lh_blkno, pass);
+ lops_after_scan(jd, error, pass);
+ if (error)
+ goto fail_gunlock_tr;
+ }
+
+ error = clean_journal(jd, &head);
+ if (error)
+ goto fail_gunlock_tr;
+
+ gfs2_glock_dq_uninit(&t_gh);
+ t = DIV_ROUND_UP(jiffies - t, HZ);
+ fs_info(sdp, "jid=%u: Journal replayed in %lus\n",
+ jd->jd_jid, t);
+ }
+
+ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
+ gfs2_glock_dq_uninit(&ji_gh);
+
+ gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_SUCCESS);
+
+ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid)
+ gfs2_glock_dq_uninit(&j_gh);
+
+ fs_info(sdp, "jid=%u: Done\n", jd->jd_jid);
+ return 0;
+
+fail_gunlock_tr:
+ gfs2_glock_dq_uninit(&t_gh);
+fail_gunlock_ji:
+ if (jd->jd_jid != sdp->sd_lockstruct.ls_jid) {
+ gfs2_glock_dq_uninit(&ji_gh);
+fail_gunlock_j:
+ gfs2_glock_dq_uninit(&j_gh);
+ }
+
+ fs_info(sdp, "jid=%u: %s\n", jd->jd_jid, (error) ? "Failed" : "Done");
+
+fail:
+ gfs2_lm_recovery_done(sdp, jd->jd_jid, LM_RD_GAVEUP);
+ return error;
+}
+
+/**
+ * gfs2_check_journals - Recover any dirty journals
+ * @sdp: the filesystem
+ *
+ */
+
+void gfs2_check_journals(struct gfs2_sbd *sdp)
+{
+ struct gfs2_jdesc *jd;
+
+ for (;;) {
+ jd = gfs2_jdesc_find_dirty(sdp);
+ if (!jd)
+ break;
+
+ if (jd != sdp->sd_jdesc)
+ gfs2_recover_journal(jd);
+ }
+}
+
diff --git a/fs/gfs2/recovery.h b/fs/gfs2/recovery.h
new file mode 100644
index 000000000000..961feedf4d8b
--- /dev/null
+++ b/fs/gfs2/recovery.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __RECOVERY_DOT_H__
+#define __RECOVERY_DOT_H__
+
+#include "incore.h"
+
+static inline void gfs2_replay_incr_blk(struct gfs2_sbd *sdp, unsigned int *blk)
+{
+ if (++*blk == sdp->sd_jdesc->jd_blocks)
+ *blk = 0;
+}
+
+int gfs2_replay_read_block(struct gfs2_jdesc *jd, unsigned int blk,
+ struct buffer_head **bh);
+
+int gfs2_revoke_add(struct gfs2_sbd *sdp, u64 blkno, unsigned int where);
+int gfs2_revoke_check(struct gfs2_sbd *sdp, u64 blkno, unsigned int where);
+void gfs2_revoke_clean(struct gfs2_sbd *sdp);
+
+int gfs2_find_jhead(struct gfs2_jdesc *jd,
+ struct gfs2_log_header *head);
+int gfs2_recover_journal(struct gfs2_jdesc *gfs2_jd);
+void gfs2_check_journals(struct gfs2_sbd *sdp);
+
+#endif /* __RECOVERY_DOT_H__ */
+
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
new file mode 100644
index 000000000000..b261385c0065
--- /dev/null
+++ b/fs/gfs2/rgrp.c
@@ -0,0 +1,1513 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/fs.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "glops.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "rgrp.h"
+#include "super.h"
+#include "trans.h"
+#include "ops_file.h"
+#include "util.h"
+
+#define BFITNOENT ((u32)~0)
+
+/*
+ * These routines are used by the resource group routines (rgrp.c)
+ * to keep track of block allocation. Each block is represented by two
+ * bits. So, each byte represents GFS2_NBBY (i.e. 4) blocks.
+ *
+ * 0 = Free
+ * 1 = Used (not metadata)
+ * 2 = Unlinked (still in use) inode
+ * 3 = Used (metadata)
+ */
+
+static const char valid_change[16] = {
+ /* current */
+ /* n */ 0, 1, 1, 1,
+ /* e */ 1, 0, 0, 0,
+ /* w */ 0, 0, 0, 1,
+ 1, 0, 0, 0
+};
+
+/**
+ * gfs2_setbit - Set a bit in the bitmaps
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @block: the block to set
+ * @new_state: the new state of the block
+ *
+ */
+
+static void gfs2_setbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+ unsigned int buflen, u32 block,
+ unsigned char new_state)
+{
+ unsigned char *byte, *end, cur_state;
+ unsigned int bit;
+
+ byte = buffer + (block / GFS2_NBBY);
+ bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
+ end = buffer + buflen;
+
+ gfs2_assert(rgd->rd_sbd, byte < end);
+
+ cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+
+ if (valid_change[new_state * 4 + cur_state]) {
+ *byte ^= cur_state << bit;
+ *byte |= new_state << bit;
+ } else
+ gfs2_consist_rgrpd(rgd);
+}
+
+/**
+ * gfs2_testbit - test a bit in the bitmaps
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @block: the block to read
+ *
+ */
+
+static unsigned char gfs2_testbit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+ unsigned int buflen, u32 block)
+{
+ unsigned char *byte, *end, cur_state;
+ unsigned int bit;
+
+ byte = buffer + (block / GFS2_NBBY);
+ bit = (block % GFS2_NBBY) * GFS2_BIT_SIZE;
+ end = buffer + buflen;
+
+ gfs2_assert(rgd->rd_sbd, byte < end);
+
+ cur_state = (*byte >> bit) & GFS2_BIT_MASK;
+
+ return cur_state;
+}
+
+/**
+ * gfs2_bitfit - Search an rgrp's bitmap buffer to find a bit-pair representing
+ * a block in a given allocation state.
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @goal: start search at this block's bit-pair (within @buffer)
+ * @old_state: GFS2_BLKST_XXX the state of the block we're looking for;
+ * bit 0 = alloc(1)/free(0), bit 1 = meta(1)/data(0)
+ *
+ * Scope of @goal and returned block number is only within this bitmap buffer,
+ * not entire rgrp or filesystem. @buffer will be offset from the actual
+ * beginning of a bitmap block buffer, skipping any header structures.
+ *
+ * Return: the block number (bitmap buffer scope) that was found
+ */
+
+static u32 gfs2_bitfit(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+ unsigned int buflen, u32 goal,
+ unsigned char old_state)
+{
+ unsigned char *byte, *end, alloc;
+ u32 blk = goal;
+ unsigned int bit;
+
+ byte = buffer + (goal / GFS2_NBBY);
+ bit = (goal % GFS2_NBBY) * GFS2_BIT_SIZE;
+ end = buffer + buflen;
+ alloc = (old_state & 1) ? 0 : 0x55;
+
+ while (byte < end) {
+ if ((*byte & 0x55) == alloc) {
+ blk += (8 - bit) >> 1;
+
+ bit = 0;
+ byte++;
+
+ continue;
+ }
+
+ if (((*byte >> bit) & GFS2_BIT_MASK) == old_state)
+ return blk;
+
+ bit += GFS2_BIT_SIZE;
+ if (bit >= 8) {
+ bit = 0;
+ byte++;
+ }
+
+ blk++;
+ }
+
+ return BFITNOENT;
+}
+
+/**
+ * gfs2_bitcount - count the number of bits in a certain state
+ * @buffer: the buffer that holds the bitmaps
+ * @buflen: the length (in bytes) of the buffer
+ * @state: the state of the block we're looking for
+ *
+ * Returns: The number of bits
+ */
+
+static u32 gfs2_bitcount(struct gfs2_rgrpd *rgd, unsigned char *buffer,
+ unsigned int buflen, unsigned char state)
+{
+ unsigned char *byte = buffer;
+ unsigned char *end = buffer + buflen;
+ unsigned char state1 = state << 2;
+ unsigned char state2 = state << 4;
+ unsigned char state3 = state << 6;
+ u32 count = 0;
+
+ for (; byte < end; byte++) {
+ if (((*byte) & 0x03) == state)
+ count++;
+ if (((*byte) & 0x0C) == state1)
+ count++;
+ if (((*byte) & 0x30) == state2)
+ count++;
+ if (((*byte) & 0xC0) == state3)
+ count++;
+ }
+
+ return count;
+}
+
+/**
+ * gfs2_rgrp_verify - Verify that a resource group is consistent
+ * @sdp: the filesystem
+ * @rgd: the rgrp
+ *
+ */
+
+void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ struct gfs2_bitmap *bi = NULL;
+ u32 length = rgd->rd_ri.ri_length;
+ u32 count[4], tmp;
+ int buf, x;
+
+ memset(count, 0, 4 * sizeof(u32));
+
+ /* Count # blocks in each of 4 possible allocation states */
+ for (buf = 0; buf < length; buf++) {
+ bi = rgd->rd_bits + buf;
+ for (x = 0; x < 4; x++)
+ count[x] += gfs2_bitcount(rgd,
+ bi->bi_bh->b_data +
+ bi->bi_offset,
+ bi->bi_len, x);
+ }
+
+ if (count[0] != rgd->rd_rg.rg_free) {
+ if (gfs2_consist_rgrpd(rgd))
+ fs_err(sdp, "free data mismatch: %u != %u\n",
+ count[0], rgd->rd_rg.rg_free);
+ return;
+ }
+
+ tmp = rgd->rd_ri.ri_data -
+ rgd->rd_rg.rg_free -
+ rgd->rd_rg.rg_dinodes;
+ if (count[1] + count[2] != tmp) {
+ if (gfs2_consist_rgrpd(rgd))
+ fs_err(sdp, "used data mismatch: %u != %u\n",
+ count[1], tmp);
+ return;
+ }
+
+ if (count[3] != rgd->rd_rg.rg_dinodes) {
+ if (gfs2_consist_rgrpd(rgd))
+ fs_err(sdp, "used metadata mismatch: %u != %u\n",
+ count[3], rgd->rd_rg.rg_dinodes);
+ return;
+ }
+
+ if (count[2] > count[3]) {
+ if (gfs2_consist_rgrpd(rgd))
+ fs_err(sdp, "unlinked inodes > inodes: %u\n",
+ count[2]);
+ return;
+ }
+
+}
+
+static inline int rgrp_contains_block(struct gfs2_rindex *ri, u64 block)
+{
+ u64 first = ri->ri_data0;
+ u64 last = first + ri->ri_data;
+ return first <= block && block < last;
+}
+
+/**
+ * gfs2_blk2rgrpd - Find resource group for a given data/meta block number
+ * @sdp: The GFS2 superblock
+ * @n: The data block number
+ *
+ * Returns: The resource group, or NULL if not found
+ */
+
+struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk)
+{
+ struct gfs2_rgrpd *rgd;
+
+ spin_lock(&sdp->sd_rindex_spin);
+
+ list_for_each_entry(rgd, &sdp->sd_rindex_mru_list, rd_list_mru) {
+ if (rgrp_contains_block(&rgd->rd_ri, blk)) {
+ list_move(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
+ spin_unlock(&sdp->sd_rindex_spin);
+ return rgd;
+ }
+ }
+
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ return NULL;
+}
+
+/**
+ * gfs2_rgrpd_get_first - get the first Resource Group in the filesystem
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: The first rgrp in the filesystem
+ */
+
+struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp)
+{
+ gfs2_assert(sdp, !list_empty(&sdp->sd_rindex_list));
+ return list_entry(sdp->sd_rindex_list.next, struct gfs2_rgrpd, rd_list);
+}
+
+/**
+ * gfs2_rgrpd_get_next - get the next RG
+ * @rgd: A RG
+ *
+ * Returns: The next rgrp
+ */
+
+struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd)
+{
+ if (rgd->rd_list.next == &rgd->rd_sbd->sd_rindex_list)
+ return NULL;
+ return list_entry(rgd->rd_list.next, struct gfs2_rgrpd, rd_list);
+}
+
+static void clear_rgrpdi(struct gfs2_sbd *sdp)
+{
+ struct list_head *head;
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_glock *gl;
+
+ spin_lock(&sdp->sd_rindex_spin);
+ sdp->sd_rindex_forward = NULL;
+ head = &sdp->sd_rindex_recent_list;
+ while (!list_empty(head)) {
+ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);
+ list_del(&rgd->rd_recent);
+ }
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ head = &sdp->sd_rindex_list;
+ while (!list_empty(head)) {
+ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_list);
+ gl = rgd->rd_gl;
+
+ list_del(&rgd->rd_list);
+ list_del(&rgd->rd_list_mru);
+
+ if (gl) {
+ gl->gl_object = NULL;
+ gfs2_glock_put(gl);
+ }
+
+ kfree(rgd->rd_bits);
+ kfree(rgd);
+ }
+}
+
+void gfs2_clear_rgrpd(struct gfs2_sbd *sdp)
+{
+ mutex_lock(&sdp->sd_rindex_mutex);
+ clear_rgrpdi(sdp);
+ mutex_unlock(&sdp->sd_rindex_mutex);
+}
+
+/**
+ * gfs2_compute_bitstructs - Compute the bitmap sizes
+ * @rgd: The resource group descriptor
+ *
+ * Calculates bitmap descriptors, one for each block that contains bitmap data
+ *
+ * Returns: errno
+ */
+
+static int compute_bitstructs(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ struct gfs2_bitmap *bi;
+ u32 length = rgd->rd_ri.ri_length; /* # blocks in hdr & bitmap */
+ u32 bytes_left, bytes;
+ int x;
+
+ if (!length)
+ return -EINVAL;
+
+ rgd->rd_bits = kcalloc(length, sizeof(struct gfs2_bitmap), GFP_NOFS);
+ if (!rgd->rd_bits)
+ return -ENOMEM;
+
+ bytes_left = rgd->rd_ri.ri_bitbytes;
+
+ for (x = 0; x < length; x++) {
+ bi = rgd->rd_bits + x;
+
+ /* small rgrp; bitmap stored completely in header block */
+ if (length == 1) {
+ bytes = bytes_left;
+ bi->bi_offset = sizeof(struct gfs2_rgrp);
+ bi->bi_start = 0;
+ bi->bi_len = bytes;
+ /* header block */
+ } else if (x == 0) {
+ bytes = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_rgrp);
+ bi->bi_offset = sizeof(struct gfs2_rgrp);
+ bi->bi_start = 0;
+ bi->bi_len = bytes;
+ /* last block */
+ } else if (x + 1 == length) {
+ bytes = bytes_left;
+ bi->bi_offset = sizeof(struct gfs2_meta_header);
+ bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left;
+ bi->bi_len = bytes;
+ /* other blocks */
+ } else {
+ bytes = sdp->sd_sb.sb_bsize -
+ sizeof(struct gfs2_meta_header);
+ bi->bi_offset = sizeof(struct gfs2_meta_header);
+ bi->bi_start = rgd->rd_ri.ri_bitbytes - bytes_left;
+ bi->bi_len = bytes;
+ }
+
+ bytes_left -= bytes;
+ }
+
+ if (bytes_left) {
+ gfs2_consist_rgrpd(rgd);
+ return -EIO;
+ }
+ bi = rgd->rd_bits + (length - 1);
+ if ((bi->bi_start + bi->bi_len) * GFS2_NBBY != rgd->rd_ri.ri_data) {
+ if (gfs2_consist_rgrpd(rgd)) {
+ gfs2_rindex_print(&rgd->rd_ri);
+ fs_err(sdp, "start=%u len=%u offset=%u\n",
+ bi->bi_start, bi->bi_len, bi->bi_offset);
+ }
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_ri_update - Pull in a new resource index from the disk
+ * @gl: The glock covering the rindex inode
+ *
+ * Returns: 0 on successful update, error code otherwise
+ */
+
+static int gfs2_ri_update(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct inode *inode = &ip->i_inode;
+ struct gfs2_rgrpd *rgd;
+ char buf[sizeof(struct gfs2_rindex)];
+ struct file_ra_state ra_state;
+ u64 junk = ip->i_di.di_size;
+ int error;
+
+ if (do_div(junk, sizeof(struct gfs2_rindex))) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+
+ clear_rgrpdi(sdp);
+
+ file_ra_state_init(&ra_state, inode->i_mapping);
+ for (sdp->sd_rgrps = 0;; sdp->sd_rgrps++) {
+ loff_t pos = sdp->sd_rgrps * sizeof(struct gfs2_rindex);
+ error = gfs2_internal_read(ip, &ra_state, buf, &pos,
+ sizeof(struct gfs2_rindex));
+ if (!error)
+ break;
+ if (error != sizeof(struct gfs2_rindex)) {
+ if (error > 0)
+ error = -EIO;
+ goto fail;
+ }
+
+ rgd = kzalloc(sizeof(struct gfs2_rgrpd), GFP_NOFS);
+ error = -ENOMEM;
+ if (!rgd)
+ goto fail;
+
+ mutex_init(&rgd->rd_mutex);
+ lops_init_le(&rgd->rd_le, &gfs2_rg_lops);
+ rgd->rd_sbd = sdp;
+
+ list_add_tail(&rgd->rd_list, &sdp->sd_rindex_list);
+ list_add_tail(&rgd->rd_list_mru, &sdp->sd_rindex_mru_list);
+
+ gfs2_rindex_in(&rgd->rd_ri, buf);
+ error = compute_bitstructs(rgd);
+ if (error)
+ goto fail;
+
+ error = gfs2_glock_get(sdp, rgd->rd_ri.ri_addr,
+ &gfs2_rgrp_glops, CREATE, &rgd->rd_gl);
+ if (error)
+ goto fail;
+
+ rgd->rd_gl->gl_object = rgd;
+ rgd->rd_rg_vn = rgd->rd_gl->gl_vn - 1;
+ }
+
+ sdp->sd_rindex_vn = ip->i_gl->gl_vn;
+ return 0;
+
+fail:
+ clear_rgrpdi(sdp);
+ return error;
+}
+
+/**
+ * gfs2_rindex_hold - Grab a lock on the rindex
+ * @sdp: The GFS2 superblock
+ * @ri_gh: the glock holder
+ *
+ * We grab a lock on the rindex inode to make sure that it doesn't
+ * change whilst we are performing an operation. We keep this lock
+ * for quite long periods of time compared to other locks. This
+ * doesn't matter, since it is shared and it is very, very rarely
+ * accessed in the exclusive mode (i.e. only when expanding the filesystem).
+ *
+ * This makes sure that we're using the latest copy of the resource index
+ * special file, which might have been updated if someone expanded the
+ * filesystem (via gfs2_grow utility), which adds new resource groups.
+ *
+ * Returns: 0 on success, error code otherwise
+ */
+
+int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh)
+{
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_rindex);
+ struct gfs2_glock *gl = ip->i_gl;
+ int error;
+
+ error = gfs2_glock_nq_init(gl, LM_ST_SHARED, 0, ri_gh);
+ if (error)
+ return error;
+
+ /* Read new copy from disk if we don't have the latest */
+ if (sdp->sd_rindex_vn != gl->gl_vn) {
+ mutex_lock(&sdp->sd_rindex_mutex);
+ if (sdp->sd_rindex_vn != gl->gl_vn) {
+ error = gfs2_ri_update(ip);
+ if (error)
+ gfs2_glock_dq_uninit(ri_gh);
+ }
+ mutex_unlock(&sdp->sd_rindex_mutex);
+ }
+
+ return error;
+}
+
+/**
+ * gfs2_rgrp_bh_get - Read in a RG's header and bitmaps
+ * @rgd: the struct gfs2_rgrpd describing the RG to read in
+ *
+ * Read in all of a Resource Group's header and bitmap blocks.
+ * Caller must eventually call gfs2_rgrp_relse() to free the bitmaps.
+ *
+ * Returns: errno
+ */
+
+int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ struct gfs2_glock *gl = rgd->rd_gl;
+ unsigned int length = rgd->rd_ri.ri_length;
+ struct gfs2_bitmap *bi;
+ unsigned int x, y;
+ int error;
+
+ mutex_lock(&rgd->rd_mutex);
+
+ spin_lock(&sdp->sd_rindex_spin);
+ if (rgd->rd_bh_count) {
+ rgd->rd_bh_count++;
+ spin_unlock(&sdp->sd_rindex_spin);
+ mutex_unlock(&rgd->rd_mutex);
+ return 0;
+ }
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ for (x = 0; x < length; x++) {
+ bi = rgd->rd_bits + x;
+ error = gfs2_meta_read(gl, rgd->rd_ri.ri_addr + x, 0, &bi->bi_bh);
+ if (error)
+ goto fail;
+ }
+
+ for (y = length; y--;) {
+ bi = rgd->rd_bits + y;
+ error = gfs2_meta_wait(sdp, bi->bi_bh);
+ if (error)
+ goto fail;
+ if (gfs2_metatype_check(sdp, bi->bi_bh, y ? GFS2_METATYPE_RB :
+ GFS2_METATYPE_RG)) {
+ error = -EIO;
+ goto fail;
+ }
+ }
+
+ if (rgd->rd_rg_vn != gl->gl_vn) {
+ gfs2_rgrp_in(&rgd->rd_rg, (rgd->rd_bits[0].bi_bh)->b_data);
+ rgd->rd_rg_vn = gl->gl_vn;
+ }
+
+ spin_lock(&sdp->sd_rindex_spin);
+ rgd->rd_free_clone = rgd->rd_rg.rg_free;
+ rgd->rd_bh_count++;
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ mutex_unlock(&rgd->rd_mutex);
+
+ return 0;
+
+fail:
+ while (x--) {
+ bi = rgd->rd_bits + x;
+ brelse(bi->bi_bh);
+ bi->bi_bh = NULL;
+ gfs2_assert_warn(sdp, !bi->bi_clone);
+ }
+ mutex_unlock(&rgd->rd_mutex);
+
+ return error;
+}
+
+void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+
+ spin_lock(&sdp->sd_rindex_spin);
+ gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
+ rgd->rd_bh_count++;
+ spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * gfs2_rgrp_bh_put - Release RG bitmaps read in with gfs2_rgrp_bh_get()
+ * @rgd: the struct gfs2_rgrpd describing the RG to read in
+ *
+ */
+
+void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ int x, length = rgd->rd_ri.ri_length;
+
+ spin_lock(&sdp->sd_rindex_spin);
+ gfs2_assert_warn(rgd->rd_sbd, rgd->rd_bh_count);
+ if (--rgd->rd_bh_count) {
+ spin_unlock(&sdp->sd_rindex_spin);
+ return;
+ }
+
+ for (x = 0; x < length; x++) {
+ struct gfs2_bitmap *bi = rgd->rd_bits + x;
+ kfree(bi->bi_clone);
+ bi->bi_clone = NULL;
+ brelse(bi->bi_bh);
+ bi->bi_bh = NULL;
+ }
+
+ spin_unlock(&sdp->sd_rindex_spin);
+}
+
+void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ unsigned int length = rgd->rd_ri.ri_length;
+ unsigned int x;
+
+ for (x = 0; x < length; x++) {
+ struct gfs2_bitmap *bi = rgd->rd_bits + x;
+ if (!bi->bi_clone)
+ continue;
+ memcpy(bi->bi_clone + bi->bi_offset,
+ bi->bi_bh->b_data + bi->bi_offset, bi->bi_len);
+ }
+
+ spin_lock(&sdp->sd_rindex_spin);
+ rgd->rd_free_clone = rgd->rd_rg.rg_free;
+ spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * gfs2_alloc_get - get the struct gfs2_alloc structure for an inode
+ * @ip: the incore GFS2 inode structure
+ *
+ * Returns: the struct gfs2_alloc
+ */
+
+struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip)
+{
+ struct gfs2_alloc *al = &ip->i_alloc;
+
+ /* FIXME: Should assert that the correct locks are held here... */
+ memset(al, 0, sizeof(*al));
+ return al;
+}
+
+/**
+ * try_rgrp_fit - See if a given reservation will fit in a given RG
+ * @rgd: the RG data
+ * @al: the struct gfs2_alloc structure describing the reservation
+ *
+ * If there's room for the requested blocks to be allocated from the RG:
+ * Sets the $al_reserved_data field in @al.
+ * Sets the $al_reserved_meta field in @al.
+ * Sets the $al_rgd field in @al.
+ *
+ * Returns: 1 on success (it fits), 0 on failure (it doesn't fit)
+ */
+
+static int try_rgrp_fit(struct gfs2_rgrpd *rgd, struct gfs2_alloc *al)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ int ret = 0;
+
+ spin_lock(&sdp->sd_rindex_spin);
+ if (rgd->rd_free_clone >= al->al_requested) {
+ al->al_rgd = rgd;
+ ret = 1;
+ }
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ return ret;
+}
+
+/**
+ * recent_rgrp_first - get first RG from "recent" list
+ * @sdp: The GFS2 superblock
+ * @rglast: address of the rgrp used last
+ *
+ * Returns: The first rgrp in the recent list
+ */
+
+static struct gfs2_rgrpd *recent_rgrp_first(struct gfs2_sbd *sdp,
+ u64 rglast)
+{
+ struct gfs2_rgrpd *rgd = NULL;
+
+ spin_lock(&sdp->sd_rindex_spin);
+
+ if (list_empty(&sdp->sd_rindex_recent_list))
+ goto out;
+
+ if (!rglast)
+ goto first;
+
+ list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
+ if (rgd->rd_ri.ri_addr == rglast)
+ goto out;
+ }
+
+first:
+ rgd = list_entry(sdp->sd_rindex_recent_list.next, struct gfs2_rgrpd,
+ rd_recent);
+out:
+ spin_unlock(&sdp->sd_rindex_spin);
+ return rgd;
+}
+
+/**
+ * recent_rgrp_next - get next RG from "recent" list
+ * @cur_rgd: current rgrp
+ * @remove:
+ *
+ * Returns: The next rgrp in the recent list
+ */
+
+static struct gfs2_rgrpd *recent_rgrp_next(struct gfs2_rgrpd *cur_rgd,
+ int remove)
+{
+ struct gfs2_sbd *sdp = cur_rgd->rd_sbd;
+ struct list_head *head;
+ struct gfs2_rgrpd *rgd;
+
+ spin_lock(&sdp->sd_rindex_spin);
+
+ head = &sdp->sd_rindex_recent_list;
+
+ list_for_each_entry(rgd, head, rd_recent) {
+ if (rgd == cur_rgd) {
+ if (cur_rgd->rd_recent.next != head)
+ rgd = list_entry(cur_rgd->rd_recent.next,
+ struct gfs2_rgrpd, rd_recent);
+ else
+ rgd = NULL;
+
+ if (remove)
+ list_del(&cur_rgd->rd_recent);
+
+ goto out;
+ }
+ }
+
+ rgd = NULL;
+ if (!list_empty(head))
+ rgd = list_entry(head->next, struct gfs2_rgrpd, rd_recent);
+
+out:
+ spin_unlock(&sdp->sd_rindex_spin);
+ return rgd;
+}
+
+/**
+ * recent_rgrp_add - add an RG to tail of "recent" list
+ * @new_rgd: The rgrp to add
+ *
+ */
+
+static void recent_rgrp_add(struct gfs2_rgrpd *new_rgd)
+{
+ struct gfs2_sbd *sdp = new_rgd->rd_sbd;
+ struct gfs2_rgrpd *rgd;
+ unsigned int count = 0;
+ unsigned int max = sdp->sd_rgrps / gfs2_jindex_size(sdp);
+
+ spin_lock(&sdp->sd_rindex_spin);
+
+ list_for_each_entry(rgd, &sdp->sd_rindex_recent_list, rd_recent) {
+ if (rgd == new_rgd)
+ goto out;
+
+ if (++count >= max)
+ goto out;
+ }
+ list_add_tail(&new_rgd->rd_recent, &sdp->sd_rindex_recent_list);
+
+out:
+ spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * forward_rgrp_get - get an rgrp to try next from full list
+ * @sdp: The GFS2 superblock
+ *
+ * Returns: The rgrp to try next
+ */
+
+static struct gfs2_rgrpd *forward_rgrp_get(struct gfs2_sbd *sdp)
+{
+ struct gfs2_rgrpd *rgd;
+ unsigned int journals = gfs2_jindex_size(sdp);
+ unsigned int rg = 0, x;
+
+ spin_lock(&sdp->sd_rindex_spin);
+
+ rgd = sdp->sd_rindex_forward;
+ if (!rgd) {
+ if (sdp->sd_rgrps >= journals)
+ rg = sdp->sd_rgrps * sdp->sd_jdesc->jd_jid / journals;
+
+ for (x = 0, rgd = gfs2_rgrpd_get_first(sdp); x < rg;
+ x++, rgd = gfs2_rgrpd_get_next(rgd))
+ /* Do Nothing */;
+
+ sdp->sd_rindex_forward = rgd;
+ }
+
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ return rgd;
+}
+
+/**
+ * forward_rgrp_set - set the forward rgrp pointer
+ * @sdp: the filesystem
+ * @rgd: The new forward rgrp
+ *
+ */
+
+static void forward_rgrp_set(struct gfs2_sbd *sdp, struct gfs2_rgrpd *rgd)
+{
+ spin_lock(&sdp->sd_rindex_spin);
+ sdp->sd_rindex_forward = rgd;
+ spin_unlock(&sdp->sd_rindex_spin);
+}
+
+/**
+ * get_local_rgrp - Choose and lock a rgrp for allocation
+ * @ip: the inode to reserve space for
+ * @rgp: the chosen and locked rgrp
+ *
+ * Try to acquire rgrp in way which avoids contending with others.
+ *
+ * Returns: errno
+ */
+
+static int get_local_rgrp(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_rgrpd *rgd, *begin = NULL;
+ struct gfs2_alloc *al = &ip->i_alloc;
+ int flags = LM_FLAG_TRY;
+ int skipped = 0;
+ int loops = 0;
+ int error;
+
+ /* Try recently successful rgrps */
+
+ rgd = recent_rgrp_first(sdp, ip->i_last_rg_alloc);
+
+ while (rgd) {
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE,
+ LM_FLAG_TRY, &al->al_rgd_gh);
+ switch (error) {
+ case 0:
+ if (try_rgrp_fit(rgd, al))
+ goto out;
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ rgd = recent_rgrp_next(rgd, 1);
+ break;
+
+ case GLR_TRYFAILED:
+ rgd = recent_rgrp_next(rgd, 0);
+ break;
+
+ default:
+ return error;
+ }
+ }
+
+ /* Go through full list of rgrps */
+
+ begin = rgd = forward_rgrp_get(sdp);
+
+ for (;;) {
+ error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, flags,
+ &al->al_rgd_gh);
+ switch (error) {
+ case 0:
+ if (try_rgrp_fit(rgd, al))
+ goto out;
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ break;
+
+ case GLR_TRYFAILED:
+ skipped++;
+ break;
+
+ default:
+ return error;
+ }
+
+ rgd = gfs2_rgrpd_get_next(rgd);
+ if (!rgd)
+ rgd = gfs2_rgrpd_get_first(sdp);
+
+ if (rgd == begin) {
+ if (++loops >= 2 || !skipped)
+ return -ENOSPC;
+ flags = 0;
+ }
+ }
+
+out:
+ ip->i_last_rg_alloc = rgd->rd_ri.ri_addr;
+
+ if (begin) {
+ recent_rgrp_add(rgd);
+ rgd = gfs2_rgrpd_get_next(rgd);
+ if (!rgd)
+ rgd = gfs2_rgrpd_get_first(sdp);
+ forward_rgrp_set(sdp, rgd);
+ }
+
+ return 0;
+}
+
+/**
+ * gfs2_inplace_reserve_i - Reserve space in the filesystem
+ * @ip: the inode to reserve space for
+ *
+ * Returns: errno
+ */
+
+int gfs2_inplace_reserve_i(struct gfs2_inode *ip, char *file, unsigned int line)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ int error;
+
+ if (gfs2_assert_warn(sdp, al->al_requested))
+ return -EINVAL;
+
+ error = gfs2_rindex_hold(sdp, &al->al_ri_gh);
+ if (error)
+ return error;
+
+ error = get_local_rgrp(ip);
+ if (error) {
+ gfs2_glock_dq_uninit(&al->al_ri_gh);
+ return error;
+ }
+
+ al->al_file = file;
+ al->al_line = line;
+
+ return 0;
+}
+
+/**
+ * gfs2_inplace_release - release an inplace reservation
+ * @ip: the inode the reservation was taken out on
+ *
+ * Release a reservation made by gfs2_inplace_reserve().
+ */
+
+void gfs2_inplace_release(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+
+ if (gfs2_assert_warn(sdp, al->al_alloced <= al->al_requested) == -1)
+ fs_warn(sdp, "al_alloced = %u, al_requested = %u "
+ "al_file = %s, al_line = %u\n",
+ al->al_alloced, al->al_requested, al->al_file,
+ al->al_line);
+
+ al->al_rgd = NULL;
+ gfs2_glock_dq_uninit(&al->al_rgd_gh);
+ gfs2_glock_dq_uninit(&al->al_ri_gh);
+}
+
+/**
+ * gfs2_get_block_type - Check a block in a RG is of given type
+ * @rgd: the resource group holding the block
+ * @block: the block number
+ *
+ * Returns: The block type (GFS2_BLKST_*)
+ */
+
+unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block)
+{
+ struct gfs2_bitmap *bi = NULL;
+ u32 length, rgrp_block, buf_block;
+ unsigned int buf;
+ unsigned char type;
+
+ length = rgd->rd_ri.ri_length;
+ rgrp_block = block - rgd->rd_ri.ri_data0;
+
+ for (buf = 0; buf < length; buf++) {
+ bi = rgd->rd_bits + buf;
+ if (rgrp_block < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
+ break;
+ }
+
+ gfs2_assert(rgd->rd_sbd, buf < length);
+ buf_block = rgrp_block - bi->bi_start * GFS2_NBBY;
+
+ type = gfs2_testbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+ bi->bi_len, buf_block);
+
+ return type;
+}
+
+/**
+ * rgblk_search - find a block in @old_state, change allocation
+ * state to @new_state
+ * @rgd: the resource group descriptor
+ * @goal: the goal block within the RG (start here to search for avail block)
+ * @old_state: GFS2_BLKST_XXX the before-allocation state to find
+ * @new_state: GFS2_BLKST_XXX the after-allocation block state
+ *
+ * Walk rgrp's bitmap to find bits that represent a block in @old_state.
+ * Add the found bitmap buffer to the transaction.
+ * Set the found bits to @new_state to change block's allocation state.
+ *
+ * This function never fails, because we wouldn't call it unless we
+ * know (from reservation results, etc.) that a block is available.
+ *
+ * Scope of @goal and returned block is just within rgrp, not the whole
+ * filesystem.
+ *
+ * Returns: the block number allocated
+ */
+
+static u32 rgblk_search(struct gfs2_rgrpd *rgd, u32 goal,
+ unsigned char old_state, unsigned char new_state)
+{
+ struct gfs2_bitmap *bi = NULL;
+ u32 length = rgd->rd_ri.ri_length;
+ u32 blk = 0;
+ unsigned int buf, x;
+
+ /* Find bitmap block that contains bits for goal block */
+ for (buf = 0; buf < length; buf++) {
+ bi = rgd->rd_bits + buf;
+ if (goal < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
+ break;
+ }
+
+ gfs2_assert(rgd->rd_sbd, buf < length);
+
+ /* Convert scope of "goal" from rgrp-wide to within found bit block */
+ goal -= bi->bi_start * GFS2_NBBY;
+
+ /* Search (up to entire) bitmap in this rgrp for allocatable block.
+ "x <= length", instead of "x < length", because we typically start
+ the search in the middle of a bit block, but if we can't find an
+ allocatable block anywhere else, we want to be able wrap around and
+ search in the first part of our first-searched bit block. */
+ for (x = 0; x <= length; x++) {
+ if (bi->bi_clone)
+ blk = gfs2_bitfit(rgd, bi->bi_clone + bi->bi_offset,
+ bi->bi_len, goal, old_state);
+ else
+ blk = gfs2_bitfit(rgd,
+ bi->bi_bh->b_data + bi->bi_offset,
+ bi->bi_len, goal, old_state);
+ if (blk != BFITNOENT)
+ break;
+
+ /* Try next bitmap block (wrap back to rgrp header if at end) */
+ buf = (buf + 1) % length;
+ bi = rgd->rd_bits + buf;
+ goal = 0;
+ }
+
+ if (gfs2_assert_withdraw(rgd->rd_sbd, x <= length))
+ blk = 0;
+
+ gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
+ gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+ bi->bi_len, blk, new_state);
+ if (bi->bi_clone)
+ gfs2_setbit(rgd, bi->bi_clone + bi->bi_offset,
+ bi->bi_len, blk, new_state);
+
+ return bi->bi_start * GFS2_NBBY + blk;
+}
+
+/**
+ * rgblk_free - Change alloc state of given block(s)
+ * @sdp: the filesystem
+ * @bstart: the start of a run of blocks to free
+ * @blen: the length of the block run (all must lie within ONE RG!)
+ * @new_state: GFS2_BLKST_XXX the after-allocation block state
+ *
+ * Returns: Resource group containing the block(s)
+ */
+
+static struct gfs2_rgrpd *rgblk_free(struct gfs2_sbd *sdp, u64 bstart,
+ u32 blen, unsigned char new_state)
+{
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_bitmap *bi = NULL;
+ u32 length, rgrp_blk, buf_blk;
+ unsigned int buf;
+
+ rgd = gfs2_blk2rgrpd(sdp, bstart);
+ if (!rgd) {
+ if (gfs2_consist(sdp))
+ fs_err(sdp, "block = %llu\n", (unsigned long long)bstart);
+ return NULL;
+ }
+
+ length = rgd->rd_ri.ri_length;
+
+ rgrp_blk = bstart - rgd->rd_ri.ri_data0;
+
+ while (blen--) {
+ for (buf = 0; buf < length; buf++) {
+ bi = rgd->rd_bits + buf;
+ if (rgrp_blk < (bi->bi_start + bi->bi_len) * GFS2_NBBY)
+ break;
+ }
+
+ gfs2_assert(rgd->rd_sbd, buf < length);
+
+ buf_blk = rgrp_blk - bi->bi_start * GFS2_NBBY;
+ rgrp_blk++;
+
+ if (!bi->bi_clone) {
+ bi->bi_clone = kmalloc(bi->bi_bh->b_size,
+ GFP_NOFS | __GFP_NOFAIL);
+ memcpy(bi->bi_clone + bi->bi_offset,
+ bi->bi_bh->b_data + bi->bi_offset,
+ bi->bi_len);
+ }
+ gfs2_trans_add_bh(rgd->rd_gl, bi->bi_bh, 1);
+ gfs2_setbit(rgd, bi->bi_bh->b_data + bi->bi_offset,
+ bi->bi_len, buf_blk, new_state);
+ }
+
+ return rgd;
+}
+
+/**
+ * gfs2_alloc_data - Allocate a data block
+ * @ip: the inode to allocate the data block for
+ *
+ * Returns: the allocated block
+ */
+
+u64 gfs2_alloc_data(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_rgrpd *rgd = al->al_rgd;
+ u32 goal, blk;
+ u64 block;
+
+ if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_data))
+ goal = ip->i_di.di_goal_data - rgd->rd_ri.ri_data0;
+ else
+ goal = rgd->rd_last_alloc_data;
+
+ blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
+ rgd->rd_last_alloc_data = blk;
+
+ block = rgd->rd_ri.ri_data0 + blk;
+ ip->i_di.di_goal_data = block;
+
+ gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
+ rgd->rd_rg.rg_free--;
+
+ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+ al->al_alloced++;
+
+ gfs2_statfs_change(sdp, 0, -1, 0);
+ gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid);
+
+ spin_lock(&sdp->sd_rindex_spin);
+ rgd->rd_free_clone--;
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ return block;
+}
+
+/**
+ * gfs2_alloc_meta - Allocate a metadata block
+ * @ip: the inode to allocate the metadata block for
+ *
+ * Returns: the allocated block
+ */
+
+u64 gfs2_alloc_meta(struct gfs2_inode *ip)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_alloc *al = &ip->i_alloc;
+ struct gfs2_rgrpd *rgd = al->al_rgd;
+ u32 goal, blk;
+ u64 block;
+
+ if (rgrp_contains_block(&rgd->rd_ri, ip->i_di.di_goal_meta))
+ goal = ip->i_di.di_goal_meta - rgd->rd_ri.ri_data0;
+ else
+ goal = rgd->rd_last_alloc_meta;
+
+ blk = rgblk_search(rgd, goal, GFS2_BLKST_FREE, GFS2_BLKST_USED);
+ rgd->rd_last_alloc_meta = blk;
+
+ block = rgd->rd_ri.ri_data0 + blk;
+ ip->i_di.di_goal_meta = block;
+
+ gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
+ rgd->rd_rg.rg_free--;
+
+ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+ al->al_alloced++;
+
+ gfs2_statfs_change(sdp, 0, -1, 0);
+ gfs2_quota_change(ip, +1, ip->i_di.di_uid, ip->i_di.di_gid);
+ gfs2_trans_add_unrevoke(sdp, block);
+
+ spin_lock(&sdp->sd_rindex_spin);
+ rgd->rd_free_clone--;
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ return block;
+}
+
+/**
+ * gfs2_alloc_di - Allocate a dinode
+ * @dip: the directory that the inode is going in
+ *
+ * Returns: the block allocated
+ */
+
+u64 gfs2_alloc_di(struct gfs2_inode *dip, u64 *generation)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
+ struct gfs2_alloc *al = &dip->i_alloc;
+ struct gfs2_rgrpd *rgd = al->al_rgd;
+ u32 blk;
+ u64 block;
+
+ blk = rgblk_search(rgd, rgd->rd_last_alloc_meta,
+ GFS2_BLKST_FREE, GFS2_BLKST_DINODE);
+
+ rgd->rd_last_alloc_meta = blk;
+
+ block = rgd->rd_ri.ri_data0 + blk;
+
+ gfs2_assert_withdraw(sdp, rgd->rd_rg.rg_free);
+ rgd->rd_rg.rg_free--;
+ rgd->rd_rg.rg_dinodes++;
+ *generation = rgd->rd_rg.rg_igeneration++;
+ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+ al->al_alloced++;
+
+ gfs2_statfs_change(sdp, 0, -1, +1);
+ gfs2_trans_add_unrevoke(sdp, block);
+
+ spin_lock(&sdp->sd_rindex_spin);
+ rgd->rd_free_clone--;
+ spin_unlock(&sdp->sd_rindex_spin);
+
+ return block;
+}
+
+/**
+ * gfs2_free_data - free a contiguous run of data block(s)
+ * @ip: the inode these blocks are being freed from
+ * @bstart: first block of a run of contiguous blocks
+ * @blen: the length of the block run
+ *
+ */
+
+void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_rgrpd *rgd;
+
+ rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
+ if (!rgd)
+ return;
+
+ rgd->rd_rg.rg_free += blen;
+
+ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+ gfs2_trans_add_rg(rgd);
+
+ gfs2_statfs_change(sdp, 0, +blen, 0);
+ gfs2_quota_change(ip, -(s64)blen,
+ ip->i_di.di_uid, ip->i_di.di_gid);
+}
+
+/**
+ * gfs2_free_meta - free a contiguous run of data block(s)
+ * @ip: the inode these blocks are being freed from
+ * @bstart: first block of a run of contiguous blocks
+ * @blen: the length of the block run
+ *
+ */
+
+void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ struct gfs2_rgrpd *rgd;
+
+ rgd = rgblk_free(sdp, bstart, blen, GFS2_BLKST_FREE);
+ if (!rgd)
+ return;
+
+ rgd->rd_rg.rg_free += blen;
+
+ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+ gfs2_trans_add_rg(rgd);
+
+ gfs2_statfs_change(sdp, 0, +blen, 0);
+ gfs2_quota_change(ip, -(s64)blen, ip->i_di.di_uid, ip->i_di.di_gid);
+ gfs2_meta_wipe(ip, bstart, blen);
+}
+
+void gfs2_unlink_di(struct inode *inode)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_sbd *sdp = GFS2_SB(inode);
+ struct gfs2_rgrpd *rgd;
+ u64 blkno = ip->i_num.no_addr;
+
+ rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_UNLINKED);
+ if (!rgd)
+ return;
+ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+ gfs2_trans_add_rg(rgd);
+}
+
+static void gfs2_free_uninit_di(struct gfs2_rgrpd *rgd, u64 blkno)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ struct gfs2_rgrpd *tmp_rgd;
+
+ tmp_rgd = rgblk_free(sdp, blkno, 1, GFS2_BLKST_FREE);
+ if (!tmp_rgd)
+ return;
+ gfs2_assert_withdraw(sdp, rgd == tmp_rgd);
+
+ if (!rgd->rd_rg.rg_dinodes)
+ gfs2_consist_rgrpd(rgd);
+ rgd->rd_rg.rg_dinodes--;
+ rgd->rd_rg.rg_free++;
+
+ gfs2_trans_add_bh(rgd->rd_gl, rgd->rd_bits[0].bi_bh, 1);
+ gfs2_rgrp_out(&rgd->rd_rg, rgd->rd_bits[0].bi_bh->b_data);
+
+ gfs2_statfs_change(sdp, 0, +1, -1);
+ gfs2_trans_add_rg(rgd);
+}
+
+
+void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip)
+{
+ gfs2_free_uninit_di(rgd, ip->i_num.no_addr);
+ gfs2_quota_change(ip, -1, ip->i_di.di_uid, ip->i_di.di_gid);
+ gfs2_meta_wipe(ip, ip->i_num.no_addr, 1);
+}
+
+/**
+ * gfs2_rlist_add - add a RG to a list of RGs
+ * @sdp: the filesystem
+ * @rlist: the list of resource groups
+ * @block: the block
+ *
+ * Figure out what RG a block belongs to and add that RG to the list
+ *
+ * FIXME: Don't use NOFAIL
+ *
+ */
+
+void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
+ u64 block)
+{
+ struct gfs2_rgrpd *rgd;
+ struct gfs2_rgrpd **tmp;
+ unsigned int new_space;
+ unsigned int x;
+
+ if (gfs2_assert_warn(sdp, !rlist->rl_ghs))
+ return;
+
+ rgd = gfs2_blk2rgrpd(sdp, block);
+ if (!rgd) {
+ if (gfs2_consist(sdp))
+ fs_err(sdp, "block = %llu\n", (unsigned long long)block);
+ return;
+ }
+
+ for (x = 0; x < rlist->rl_rgrps; x++)
+ if (rlist->rl_rgd[x] == rgd)
+ return;
+
+ if (rlist->rl_rgrps == rlist->rl_space) {
+ new_space = rlist->rl_space + 10;
+
+ tmp = kcalloc(new_space, sizeof(struct gfs2_rgrpd *),
+ GFP_NOFS | __GFP_NOFAIL);
+
+ if (rlist->rl_rgd) {
+ memcpy(tmp, rlist->rl_rgd,
+ rlist->rl_space * sizeof(struct gfs2_rgrpd *));
+ kfree(rlist->rl_rgd);
+ }
+
+ rlist->rl_space = new_space;
+ rlist->rl_rgd = tmp;
+ }
+
+ rlist->rl_rgd[rlist->rl_rgrps++] = rgd;
+}
+
+/**
+ * gfs2_rlist_alloc - all RGs have been added to the rlist, now allocate
+ * and initialize an array of glock holders for them
+ * @rlist: the list of resource groups
+ * @state: the lock state to acquire the RG lock in
+ * @flags: the modifier flags for the holder structures
+ *
+ * FIXME: Don't use NOFAIL
+ *
+ */
+
+void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state,
+ int flags)
+{
+ unsigned int x;
+
+ rlist->rl_ghs = kcalloc(rlist->rl_rgrps, sizeof(struct gfs2_holder),
+ GFP_NOFS | __GFP_NOFAIL);
+ for (x = 0; x < rlist->rl_rgrps; x++)
+ gfs2_holder_init(rlist->rl_rgd[x]->rd_gl,
+ state, flags,
+ &rlist->rl_ghs[x]);
+}
+
+/**
+ * gfs2_rlist_free - free a resource group list
+ * @list: the list of resource groups
+ *
+ */
+
+void gfs2_rlist_free(struct gfs2_rgrp_list *rlist)
+{
+ unsigned int x;
+
+ kfree(rlist->rl_rgd);
+
+ if (rlist->rl_ghs) {
+ for (x = 0; x < rlist->rl_rgrps; x++)
+ gfs2_holder_uninit(&rlist->rl_ghs[x]);
+ kfree(rlist->rl_ghs);
+ }
+}
+
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
new file mode 100644
index 000000000000..b01e0cfc99b5
--- /dev/null
+++ b/fs/gfs2/rgrp.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __RGRP_DOT_H__
+#define __RGRP_DOT_H__
+
+struct gfs2_rgrpd;
+struct gfs2_sbd;
+struct gfs2_holder;
+
+void gfs2_rgrp_verify(struct gfs2_rgrpd *rgd);
+
+struct gfs2_rgrpd *gfs2_blk2rgrpd(struct gfs2_sbd *sdp, u64 blk);
+struct gfs2_rgrpd *gfs2_rgrpd_get_first(struct gfs2_sbd *sdp);
+struct gfs2_rgrpd *gfs2_rgrpd_get_next(struct gfs2_rgrpd *rgd);
+
+void gfs2_clear_rgrpd(struct gfs2_sbd *sdp);
+int gfs2_rindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ri_gh);
+
+int gfs2_rgrp_bh_get(struct gfs2_rgrpd *rgd);
+void gfs2_rgrp_bh_hold(struct gfs2_rgrpd *rgd);
+void gfs2_rgrp_bh_put(struct gfs2_rgrpd *rgd);
+
+void gfs2_rgrp_repolish_clones(struct gfs2_rgrpd *rgd);
+
+struct gfs2_alloc *gfs2_alloc_get(struct gfs2_inode *ip);
+static inline void gfs2_alloc_put(struct gfs2_inode *ip)
+{
+ return; /* So we can see where ip->i_alloc is used */
+}
+
+int gfs2_inplace_reserve_i(struct gfs2_inode *ip,
+ char *file, unsigned int line);
+#define gfs2_inplace_reserve(ip) \
+gfs2_inplace_reserve_i((ip), __FILE__, __LINE__)
+
+void gfs2_inplace_release(struct gfs2_inode *ip);
+
+unsigned char gfs2_get_block_type(struct gfs2_rgrpd *rgd, u64 block);
+
+u64 gfs2_alloc_data(struct gfs2_inode *ip);
+u64 gfs2_alloc_meta(struct gfs2_inode *ip);
+u64 gfs2_alloc_di(struct gfs2_inode *ip, u64 *generation);
+
+void gfs2_free_data(struct gfs2_inode *ip, u64 bstart, u32 blen);
+void gfs2_free_meta(struct gfs2_inode *ip, u64 bstart, u32 blen);
+void gfs2_free_di(struct gfs2_rgrpd *rgd, struct gfs2_inode *ip);
+void gfs2_unlink_di(struct inode *inode);
+
+struct gfs2_rgrp_list {
+ unsigned int rl_rgrps;
+ unsigned int rl_space;
+ struct gfs2_rgrpd **rl_rgd;
+ struct gfs2_holder *rl_ghs;
+};
+
+void gfs2_rlist_add(struct gfs2_sbd *sdp, struct gfs2_rgrp_list *rlist,
+ u64 block);
+void gfs2_rlist_alloc(struct gfs2_rgrp_list *rlist, unsigned int state,
+ int flags);
+void gfs2_rlist_free(struct gfs2_rgrp_list *rlist);
+
+#endif /* __RGRP_DOT_H__ */
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
new file mode 100644
index 000000000000..6a78b1b32e25
--- /dev/null
+++ b/fs/gfs2/super.c
@@ -0,0 +1,976 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/crc32.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/bio.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "bmap.h"
+#include "dir.h"
+#include "glock.h"
+#include "glops.h"
+#include "inode.h"
+#include "log.h"
+#include "meta_io.h"
+#include "quota.h"
+#include "recovery.h"
+#include "rgrp.h"
+#include "super.h"
+#include "trans.h"
+#include "util.h"
+
+static const u32 gfs2_old_fs_formats[] = {
+ 0
+};
+
+static const u32 gfs2_old_multihost_formats[] = {
+ 0
+};
+
+/**
+ * gfs2_tune_init - Fill a gfs2_tune structure with default values
+ * @gt: tune
+ *
+ */
+
+void gfs2_tune_init(struct gfs2_tune *gt)
+{
+ spin_lock_init(&gt->gt_spin);
+
+ gt->gt_ilimit = 100;
+ gt->gt_ilimit_tries = 3;
+ gt->gt_ilimit_min = 1;
+ gt->gt_demote_secs = 300;
+ gt->gt_incore_log_blocks = 1024;
+ gt->gt_log_flush_secs = 60;
+ gt->gt_jindex_refresh_secs = 60;
+ gt->gt_scand_secs = 15;
+ gt->gt_recoverd_secs = 60;
+ gt->gt_logd_secs = 1;
+ gt->gt_quotad_secs = 5;
+ gt->gt_quota_simul_sync = 64;
+ gt->gt_quota_warn_period = 10;
+ gt->gt_quota_scale_num = 1;
+ gt->gt_quota_scale_den = 1;
+ gt->gt_quota_cache_secs = 300;
+ gt->gt_quota_quantum = 60;
+ gt->gt_atime_quantum = 3600;
+ gt->gt_new_files_jdata = 0;
+ gt->gt_new_files_directio = 0;
+ gt->gt_max_atomic_write = 4 << 20;
+ gt->gt_max_readahead = 1 << 18;
+ gt->gt_lockdump_size = 131072;
+ gt->gt_stall_secs = 600;
+ gt->gt_complain_secs = 10;
+ gt->gt_reclaim_limit = 5000;
+ gt->gt_entries_per_readdir = 32;
+ gt->gt_prefetch_secs = 10;
+ gt->gt_greedy_default = HZ / 10;
+ gt->gt_greedy_quantum = HZ / 40;
+ gt->gt_greedy_max = HZ / 4;
+ gt->gt_statfs_quantum = 30;
+ gt->gt_statfs_slow = 0;
+}
+
+/**
+ * gfs2_check_sb - Check superblock
+ * @sdp: the filesystem
+ * @sb: The superblock
+ * @silent: Don't print a message if the check fails
+ *
+ * Checks the version code of the FS is one that we understand how to
+ * read and that the sizes of the various on-disk structures have not
+ * changed.
+ */
+
+int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent)
+{
+ unsigned int x;
+
+ if (sb->sb_header.mh_magic != GFS2_MAGIC ||
+ sb->sb_header.mh_type != GFS2_METATYPE_SB) {
+ if (!silent)
+ printk(KERN_WARNING "GFS2: not a GFS2 filesystem\n");
+ return -EINVAL;
+ }
+
+ /* If format numbers match exactly, we're done. */
+
+ if (sb->sb_fs_format == GFS2_FORMAT_FS &&
+ sb->sb_multihost_format == GFS2_FORMAT_MULTI)
+ return 0;
+
+ if (sb->sb_fs_format != GFS2_FORMAT_FS) {
+ for (x = 0; gfs2_old_fs_formats[x]; x++)
+ if (gfs2_old_fs_formats[x] == sb->sb_fs_format)
+ break;
+
+ if (!gfs2_old_fs_formats[x]) {
+ printk(KERN_WARNING
+ "GFS2: code version (%u, %u) is incompatible "
+ "with ondisk format (%u, %u)\n",
+ GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
+ sb->sb_fs_format, sb->sb_multihost_format);
+ printk(KERN_WARNING
+ "GFS2: I don't know how to upgrade this FS\n");
+ return -EINVAL;
+ }
+ }
+
+ if (sb->sb_multihost_format != GFS2_FORMAT_MULTI) {
+ for (x = 0; gfs2_old_multihost_formats[x]; x++)
+ if (gfs2_old_multihost_formats[x] ==
+ sb->sb_multihost_format)
+ break;
+
+ if (!gfs2_old_multihost_formats[x]) {
+ printk(KERN_WARNING
+ "GFS2: code version (%u, %u) is incompatible "
+ "with ondisk format (%u, %u)\n",
+ GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
+ sb->sb_fs_format, sb->sb_multihost_format);
+ printk(KERN_WARNING
+ "GFS2: I don't know how to upgrade this FS\n");
+ return -EINVAL;
+ }
+ }
+
+ if (!sdp->sd_args.ar_upgrade) {
+ printk(KERN_WARNING
+ "GFS2: code version (%u, %u) is incompatible "
+ "with ondisk format (%u, %u)\n",
+ GFS2_FORMAT_FS, GFS2_FORMAT_MULTI,
+ sb->sb_fs_format, sb->sb_multihost_format);
+ printk(KERN_INFO
+ "GFS2: Use the \"upgrade\" mount option to upgrade "
+ "the FS\n");
+ printk(KERN_INFO "GFS2: See the manual for more details\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int end_bio_io_page(struct bio *bio, unsigned int bytes_done, int error)
+{
+ struct page *page = bio->bi_private;
+ if (bio->bi_size)
+ return 1;
+
+ if (!error)
+ SetPageUptodate(page);
+ else
+ printk(KERN_WARNING "gfs2: error %d reading superblock\n", error);
+ unlock_page(page);
+ return 0;
+}
+
+struct page *gfs2_read_super(struct super_block *sb, sector_t sector)
+{
+ struct page *page;
+ struct bio *bio;
+
+ page = alloc_page(GFP_KERNEL);
+ if (unlikely(!page))
+ return NULL;
+
+ ClearPageUptodate(page);
+ ClearPageDirty(page);
+ lock_page(page);
+
+ bio = bio_alloc(GFP_KERNEL, 1);
+ if (unlikely(!bio)) {
+ __free_page(page);
+ return NULL;
+ }
+
+ bio->bi_sector = sector;
+ bio->bi_bdev = sb->s_bdev;
+ bio_add_page(bio, page, PAGE_SIZE, 0);
+
+ bio->bi_end_io = end_bio_io_page;
+ bio->bi_private = page;
+ submit_bio(READ_SYNC | (1 << BIO_RW_META), bio);
+ wait_on_page_locked(page);
+ bio_put(bio);
+ if (!PageUptodate(page)) {
+ __free_page(page);
+ return NULL;
+ }
+ return page;
+}
+
+/**
+ * gfs2_read_sb - Read super block
+ * @sdp: The GFS2 superblock
+ * @gl: the glock for the superblock (assumed to be held)
+ * @silent: Don't print message if mount fails
+ *
+ */
+
+int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent)
+{
+ u32 hash_blocks, ind_blocks, leaf_blocks;
+ u32 tmp_blocks;
+ unsigned int x;
+ int error;
+ struct page *page;
+ char *sb;
+
+ page = gfs2_read_super(sdp->sd_vfs, GFS2_SB_ADDR >> sdp->sd_fsb2bb_shift);
+ if (!page) {
+ if (!silent)
+ fs_err(sdp, "can't read superblock\n");
+ return -EIO;
+ }
+ sb = kmap(page);
+ gfs2_sb_in(&sdp->sd_sb, sb);
+ kunmap(page);
+ __free_page(page);
+
+ error = gfs2_check_sb(sdp, &sdp->sd_sb, silent);
+ if (error)
+ return error;
+
+ sdp->sd_fsb2bb_shift = sdp->sd_sb.sb_bsize_shift -
+ GFS2_BASIC_BLOCK_SHIFT;
+ sdp->sd_fsb2bb = 1 << sdp->sd_fsb2bb_shift;
+ sdp->sd_diptrs = (sdp->sd_sb.sb_bsize -
+ sizeof(struct gfs2_dinode)) / sizeof(u64);
+ sdp->sd_inptrs = (sdp->sd_sb.sb_bsize -
+ sizeof(struct gfs2_meta_header)) / sizeof(u64);
+ sdp->sd_jbsize = sdp->sd_sb.sb_bsize - sizeof(struct gfs2_meta_header);
+ sdp->sd_hash_bsize = sdp->sd_sb.sb_bsize / 2;
+ sdp->sd_hash_bsize_shift = sdp->sd_sb.sb_bsize_shift - 1;
+ sdp->sd_hash_ptrs = sdp->sd_hash_bsize / sizeof(u64);
+ sdp->sd_qc_per_block = (sdp->sd_sb.sb_bsize -
+ sizeof(struct gfs2_meta_header)) /
+ sizeof(struct gfs2_quota_change);
+
+ /* Compute maximum reservation required to add a entry to a directory */
+
+ hash_blocks = DIV_ROUND_UP(sizeof(u64) * (1 << GFS2_DIR_MAX_DEPTH),
+ sdp->sd_jbsize);
+
+ ind_blocks = 0;
+ for (tmp_blocks = hash_blocks; tmp_blocks > sdp->sd_diptrs;) {
+ tmp_blocks = DIV_ROUND_UP(tmp_blocks, sdp->sd_inptrs);
+ ind_blocks += tmp_blocks;
+ }
+
+ leaf_blocks = 2 + GFS2_DIR_MAX_DEPTH;
+
+ sdp->sd_max_dirres = hash_blocks + ind_blocks + leaf_blocks;
+
+ sdp->sd_heightsize[0] = sdp->sd_sb.sb_bsize -
+ sizeof(struct gfs2_dinode);
+ sdp->sd_heightsize[1] = sdp->sd_sb.sb_bsize * sdp->sd_diptrs;
+ for (x = 2;; x++) {
+ u64 space, d;
+ u32 m;
+
+ space = sdp->sd_heightsize[x - 1] * sdp->sd_inptrs;
+ d = space;
+ m = do_div(d, sdp->sd_inptrs);
+
+ if (d != sdp->sd_heightsize[x - 1] || m)
+ break;
+ sdp->sd_heightsize[x] = space;
+ }
+ sdp->sd_max_height = x;
+ gfs2_assert(sdp, sdp->sd_max_height <= GFS2_MAX_META_HEIGHT);
+
+ sdp->sd_jheightsize[0] = sdp->sd_sb.sb_bsize -
+ sizeof(struct gfs2_dinode);
+ sdp->sd_jheightsize[1] = sdp->sd_jbsize * sdp->sd_diptrs;
+ for (x = 2;; x++) {
+ u64 space, d;
+ u32 m;
+
+ space = sdp->sd_jheightsize[x - 1] * sdp->sd_inptrs;
+ d = space;
+ m = do_div(d, sdp->sd_inptrs);
+
+ if (d != sdp->sd_jheightsize[x - 1] || m)
+ break;
+ sdp->sd_jheightsize[x] = space;
+ }
+ sdp->sd_max_jheight = x;
+ gfs2_assert(sdp, sdp->sd_max_jheight <= GFS2_MAX_META_HEIGHT);
+
+ return 0;
+}
+
+/**
+ * gfs2_jindex_hold - Grab a lock on the jindex
+ * @sdp: The GFS2 superblock
+ * @ji_gh: the holder for the jindex glock
+ *
+ * This is very similar to the gfs2_rindex_hold() function, except that
+ * in general we hold the jindex lock for longer periods of time and
+ * we grab it far less frequently (in general) then the rgrp lock.
+ *
+ * Returns: errno
+ */
+
+int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
+{
+ struct gfs2_inode *dip = GFS2_I(sdp->sd_jindex);
+ struct qstr name;
+ char buf[20];
+ struct gfs2_jdesc *jd;
+ int error;
+
+ name.name = buf;
+
+ mutex_lock(&sdp->sd_jindex_mutex);
+
+ for (;;) {
+ error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
+ GL_LOCAL_EXCL, ji_gh);
+ if (error)
+ break;
+
+ name.len = sprintf(buf, "journal%u", sdp->sd_journals);
+ name.hash = gfs2_disk_hash(name.name, name.len);
+
+ error = gfs2_dir_search(sdp->sd_jindex, &name, NULL, NULL);
+ if (error == -ENOENT) {
+ error = 0;
+ break;
+ }
+
+ gfs2_glock_dq_uninit(ji_gh);
+
+ if (error)
+ break;
+
+ error = -ENOMEM;
+ jd = kzalloc(sizeof(struct gfs2_jdesc), GFP_KERNEL);
+ if (!jd)
+ break;
+
+ jd->jd_inode = gfs2_lookupi(sdp->sd_jindex, &name, 1, NULL);
+ if (!jd->jd_inode || IS_ERR(jd->jd_inode)) {
+ if (!jd->jd_inode)
+ error = -ENOENT;
+ else
+ error = PTR_ERR(jd->jd_inode);
+ kfree(jd);
+ break;
+ }
+
+ spin_lock(&sdp->sd_jindex_spin);
+ jd->jd_jid = sdp->sd_journals++;
+ list_add_tail(&jd->jd_list, &sdp->sd_jindex_list);
+ spin_unlock(&sdp->sd_jindex_spin);
+ }
+
+ mutex_unlock(&sdp->sd_jindex_mutex);
+
+ return error;
+}
+
+/**
+ * gfs2_jindex_free - Clear all the journal index information
+ * @sdp: The GFS2 superblock
+ *
+ */
+
+void gfs2_jindex_free(struct gfs2_sbd *sdp)
+{
+ struct list_head list;
+ struct gfs2_jdesc *jd;
+
+ spin_lock(&sdp->sd_jindex_spin);
+ list_add(&list, &sdp->sd_jindex_list);
+ list_del_init(&sdp->sd_jindex_list);
+ sdp->sd_journals = 0;
+ spin_unlock(&sdp->sd_jindex_spin);
+
+ while (!list_empty(&list)) {
+ jd = list_entry(list.next, struct gfs2_jdesc, jd_list);
+ list_del(&jd->jd_list);
+ iput(jd->jd_inode);
+ kfree(jd);
+ }
+}
+
+static struct gfs2_jdesc *jdesc_find_i(struct list_head *head, unsigned int jid)
+{
+ struct gfs2_jdesc *jd;
+ int found = 0;
+
+ list_for_each_entry(jd, head, jd_list) {
+ if (jd->jd_jid == jid) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ jd = NULL;
+
+ return jd;
+}
+
+struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid)
+{
+ struct gfs2_jdesc *jd;
+
+ spin_lock(&sdp->sd_jindex_spin);
+ jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
+ spin_unlock(&sdp->sd_jindex_spin);
+
+ return jd;
+}
+
+void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid)
+{
+ struct gfs2_jdesc *jd;
+
+ spin_lock(&sdp->sd_jindex_spin);
+ jd = jdesc_find_i(&sdp->sd_jindex_list, jid);
+ if (jd)
+ jd->jd_dirty = 1;
+ spin_unlock(&sdp->sd_jindex_spin);
+}
+
+struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp)
+{
+ struct gfs2_jdesc *jd;
+ int found = 0;
+
+ spin_lock(&sdp->sd_jindex_spin);
+
+ list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+ if (jd->jd_dirty) {
+ jd->jd_dirty = 0;
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock(&sdp->sd_jindex_spin);
+
+ if (!found)
+ jd = NULL;
+
+ return jd;
+}
+
+int gfs2_jdesc_check(struct gfs2_jdesc *jd)
+{
+ struct gfs2_inode *ip = GFS2_I(jd->jd_inode);
+ struct gfs2_sbd *sdp = GFS2_SB(jd->jd_inode);
+ int ar;
+ int error;
+
+ if (ip->i_di.di_size < (8 << 20) || ip->i_di.di_size > (1 << 30) ||
+ (ip->i_di.di_size & (sdp->sd_sb.sb_bsize - 1))) {
+ gfs2_consist_inode(ip);
+ return -EIO;
+ }
+ jd->jd_blocks = ip->i_di.di_size >> sdp->sd_sb.sb_bsize_shift;
+
+ error = gfs2_write_alloc_required(ip, 0, ip->i_di.di_size, &ar);
+ if (!error && ar) {
+ gfs2_consist_inode(ip);
+ error = -EIO;
+ }
+
+ return error;
+}
+
+/**
+ * gfs2_make_fs_rw - Turn a Read-Only FS into a Read-Write one
+ * @sdp: the filesystem
+ *
+ * Returns: errno
+ */
+
+int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
+{
+ struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
+ struct gfs2_glock *j_gl = ip->i_gl;
+ struct gfs2_holder t_gh;
+ struct gfs2_log_header head;
+ int error;
+
+ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
+ GL_LOCAL_EXCL, &t_gh);
+ if (error)
+ return error;
+
+ gfs2_meta_cache_flush(ip);
+ j_gl->gl_ops->go_inval(j_gl, DIO_METADATA | DIO_DATA);
+
+ error = gfs2_find_jhead(sdp->sd_jdesc, &head);
+ if (error)
+ goto fail;
+
+ if (!(head.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
+ gfs2_consist(sdp);
+ error = -EIO;
+ goto fail;
+ }
+
+ /* Initialize some head of the log stuff */
+ sdp->sd_log_sequence = head.lh_sequence + 1;
+ gfs2_log_pointers_init(sdp, head.lh_blkno);
+
+ error = gfs2_quota_init(sdp);
+ if (error)
+ goto fail;
+
+ set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+
+ gfs2_glock_dq_uninit(&t_gh);
+
+ return 0;
+
+fail:
+ t_gh.gh_flags |= GL_NOCACHE;
+ gfs2_glock_dq_uninit(&t_gh);
+
+ return error;
+}
+
+/**
+ * gfs2_make_fs_ro - Turn a Read-Write FS into a Read-Only one
+ * @sdp: the filesystem
+ *
+ * Returns: errno
+ */
+
+int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
+{
+ struct gfs2_holder t_gh;
+ int error;
+
+ gfs2_quota_sync(sdp);
+ gfs2_statfs_sync(sdp);
+
+ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
+ GL_LOCAL_EXCL | GL_NOCACHE,
+ &t_gh);
+ if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+ return error;
+
+ gfs2_meta_syncfs(sdp);
+ gfs2_log_shutdown(sdp);
+
+ clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+
+ if (t_gh.gh_gl)
+ gfs2_glock_dq_uninit(&t_gh);
+
+ gfs2_quota_cleanup(sdp);
+
+ return error;
+}
+
+int gfs2_statfs_init(struct gfs2_sbd *sdp)
+{
+ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
+ struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
+ struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
+ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+ struct buffer_head *m_bh, *l_bh;
+ struct gfs2_holder gh;
+ int error;
+
+ error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
+ &gh);
+ if (error)
+ return error;
+
+ error = gfs2_meta_inode_buffer(m_ip, &m_bh);
+ if (error)
+ goto out;
+
+ if (sdp->sd_args.ar_spectator) {
+ spin_lock(&sdp->sd_statfs_spin);
+ gfs2_statfs_change_in(m_sc, m_bh->b_data +
+ sizeof(struct gfs2_dinode));
+ spin_unlock(&sdp->sd_statfs_spin);
+ } else {
+ error = gfs2_meta_inode_buffer(l_ip, &l_bh);
+ if (error)
+ goto out_m_bh;
+
+ spin_lock(&sdp->sd_statfs_spin);
+ gfs2_statfs_change_in(m_sc, m_bh->b_data +
+ sizeof(struct gfs2_dinode));
+ gfs2_statfs_change_in(l_sc, l_bh->b_data +
+ sizeof(struct gfs2_dinode));
+ spin_unlock(&sdp->sd_statfs_spin);
+
+ brelse(l_bh);
+ }
+
+out_m_bh:
+ brelse(m_bh);
+out:
+ gfs2_glock_dq_uninit(&gh);
+ return 0;
+}
+
+void gfs2_statfs_change(struct gfs2_sbd *sdp, s64 total, s64 free,
+ s64 dinodes)
+{
+ struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
+ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+ struct buffer_head *l_bh;
+ int error;
+
+ error = gfs2_meta_inode_buffer(l_ip, &l_bh);
+ if (error)
+ return;
+
+ mutex_lock(&sdp->sd_statfs_mutex);
+ gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+ mutex_unlock(&sdp->sd_statfs_mutex);
+
+ spin_lock(&sdp->sd_statfs_spin);
+ l_sc->sc_total += total;
+ l_sc->sc_free += free;
+ l_sc->sc_dinodes += dinodes;
+ gfs2_statfs_change_out(l_sc, l_bh->b_data + sizeof(struct gfs2_dinode));
+ spin_unlock(&sdp->sd_statfs_spin);
+
+ brelse(l_bh);
+}
+
+int gfs2_statfs_sync(struct gfs2_sbd *sdp)
+{
+ struct gfs2_inode *m_ip = GFS2_I(sdp->sd_statfs_inode);
+ struct gfs2_inode *l_ip = GFS2_I(sdp->sd_sc_inode);
+ struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
+ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+ struct gfs2_holder gh;
+ struct buffer_head *m_bh, *l_bh;
+ int error;
+
+ error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
+ &gh);
+ if (error)
+ return error;
+
+ error = gfs2_meta_inode_buffer(m_ip, &m_bh);
+ if (error)
+ goto out;
+
+ spin_lock(&sdp->sd_statfs_spin);
+ gfs2_statfs_change_in(m_sc, m_bh->b_data +
+ sizeof(struct gfs2_dinode));
+ if (!l_sc->sc_total && !l_sc->sc_free && !l_sc->sc_dinodes) {
+ spin_unlock(&sdp->sd_statfs_spin);
+ goto out_bh;
+ }
+ spin_unlock(&sdp->sd_statfs_spin);
+
+ error = gfs2_meta_inode_buffer(l_ip, &l_bh);
+ if (error)
+ goto out_bh;
+
+ error = gfs2_trans_begin(sdp, 2 * RES_DINODE, 0);
+ if (error)
+ goto out_bh2;
+
+ mutex_lock(&sdp->sd_statfs_mutex);
+ gfs2_trans_add_bh(l_ip->i_gl, l_bh, 1);
+ mutex_unlock(&sdp->sd_statfs_mutex);
+
+ spin_lock(&sdp->sd_statfs_spin);
+ m_sc->sc_total += l_sc->sc_total;
+ m_sc->sc_free += l_sc->sc_free;
+ m_sc->sc_dinodes += l_sc->sc_dinodes;
+ memset(l_sc, 0, sizeof(struct gfs2_statfs_change));
+ memset(l_bh->b_data + sizeof(struct gfs2_dinode),
+ 0, sizeof(struct gfs2_statfs_change));
+ spin_unlock(&sdp->sd_statfs_spin);
+
+ gfs2_trans_add_bh(m_ip->i_gl, m_bh, 1);
+ gfs2_statfs_change_out(m_sc, m_bh->b_data + sizeof(struct gfs2_dinode));
+
+ gfs2_trans_end(sdp);
+
+out_bh2:
+ brelse(l_bh);
+out_bh:
+ brelse(m_bh);
+out:
+ gfs2_glock_dq_uninit(&gh);
+ return error;
+}
+
+/**
+ * gfs2_statfs_i - Do a statfs
+ * @sdp: the filesystem
+ * @sg: the sg structure
+ *
+ * Returns: errno
+ */
+
+int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
+{
+ struct gfs2_statfs_change *m_sc = &sdp->sd_statfs_master;
+ struct gfs2_statfs_change *l_sc = &sdp->sd_statfs_local;
+
+ spin_lock(&sdp->sd_statfs_spin);
+
+ *sc = *m_sc;
+ sc->sc_total += l_sc->sc_total;
+ sc->sc_free += l_sc->sc_free;
+ sc->sc_dinodes += l_sc->sc_dinodes;
+
+ spin_unlock(&sdp->sd_statfs_spin);
+
+ if (sc->sc_free < 0)
+ sc->sc_free = 0;
+ if (sc->sc_free > sc->sc_total)
+ sc->sc_free = sc->sc_total;
+ if (sc->sc_dinodes < 0)
+ sc->sc_dinodes = 0;
+
+ return 0;
+}
+
+/**
+ * statfs_fill - fill in the sg for a given RG
+ * @rgd: the RG
+ * @sc: the sc structure
+ *
+ * Returns: 0 on success, -ESTALE if the LVB is invalid
+ */
+
+static int statfs_slow_fill(struct gfs2_rgrpd *rgd,
+ struct gfs2_statfs_change *sc)
+{
+ gfs2_rgrp_verify(rgd);
+ sc->sc_total += rgd->rd_ri.ri_data;
+ sc->sc_free += rgd->rd_rg.rg_free;
+ sc->sc_dinodes += rgd->rd_rg.rg_dinodes;
+ return 0;
+}
+
+/**
+ * gfs2_statfs_slow - Stat a filesystem using asynchronous locking
+ * @sdp: the filesystem
+ * @sc: the sc info that will be returned
+ *
+ * Any error (other than a signal) will cause this routine to fall back
+ * to the synchronous version.
+ *
+ * FIXME: This really shouldn't busy wait like this.
+ *
+ * Returns: errno
+ */
+
+int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc)
+{
+ struct gfs2_holder ri_gh;
+ struct gfs2_rgrpd *rgd_next;
+ struct gfs2_holder *gha, *gh;
+ unsigned int slots = 64;
+ unsigned int x;
+ int done;
+ int error = 0, err;
+
+ memset(sc, 0, sizeof(struct gfs2_statfs_change));
+ gha = kcalloc(slots, sizeof(struct gfs2_holder), GFP_KERNEL);
+ if (!gha)
+ return -ENOMEM;
+
+ error = gfs2_rindex_hold(sdp, &ri_gh);
+ if (error)
+ goto out;
+
+ rgd_next = gfs2_rgrpd_get_first(sdp);
+
+ for (;;) {
+ done = 1;
+
+ for (x = 0; x < slots; x++) {
+ gh = gha + x;
+
+ if (gh->gh_gl && gfs2_glock_poll(gh)) {
+ err = gfs2_glock_wait(gh);
+ if (err) {
+ gfs2_holder_uninit(gh);
+ error = err;
+ } else {
+ if (!error)
+ error = statfs_slow_fill(
+ gh->gh_gl->gl_object, sc);
+ gfs2_glock_dq_uninit(gh);
+ }
+ }
+
+ if (gh->gh_gl)
+ done = 0;
+ else if (rgd_next && !error) {
+ error = gfs2_glock_nq_init(rgd_next->rd_gl,
+ LM_ST_SHARED,
+ GL_ASYNC,
+ gh);
+ rgd_next = gfs2_rgrpd_get_next(rgd_next);
+ done = 0;
+ }
+
+ if (signal_pending(current))
+ error = -ERESTARTSYS;
+ }
+
+ if (done)
+ break;
+
+ yield();
+ }
+
+ gfs2_glock_dq_uninit(&ri_gh);
+
+out:
+ kfree(gha);
+ return error;
+}
+
+struct lfcc {
+ struct list_head list;
+ struct gfs2_holder gh;
+};
+
+/**
+ * gfs2_lock_fs_check_clean - Stop all writes to the FS and check that all
+ * journals are clean
+ * @sdp: the file system
+ * @state: the state to put the transaction lock into
+ * @t_gh: the hold on the transaction lock
+ *
+ * Returns: errno
+ */
+
+static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
+ struct gfs2_holder *t_gh)
+{
+ struct gfs2_inode *ip;
+ struct gfs2_holder ji_gh;
+ struct gfs2_jdesc *jd;
+ struct lfcc *lfcc;
+ LIST_HEAD(list);
+ struct gfs2_log_header lh;
+ int error;
+
+ error = gfs2_jindex_hold(sdp, &ji_gh);
+ if (error)
+ return error;
+
+ list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+ lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
+ if (!lfcc) {
+ error = -ENOMEM;
+ goto out;
+ }
+ ip = GFS2_I(jd->jd_inode);
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &lfcc->gh);
+ if (error) {
+ kfree(lfcc);
+ goto out;
+ }
+ list_add(&lfcc->list, &list);
+ }
+
+ error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_DEFERRED,
+ LM_FLAG_PRIORITY | GL_NOCACHE,
+ t_gh);
+
+ list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
+ error = gfs2_jdesc_check(jd);
+ if (error)
+ break;
+ error = gfs2_find_jhead(jd, &lh);
+ if (error)
+ break;
+ if (!(lh.lh_flags & GFS2_LOG_HEAD_UNMOUNT)) {
+ error = -EBUSY;
+ break;
+ }
+ }
+
+ if (error)
+ gfs2_glock_dq_uninit(t_gh);
+
+out:
+ while (!list_empty(&list)) {
+ lfcc = list_entry(list.next, struct lfcc, list);
+ list_del(&lfcc->list);
+ gfs2_glock_dq_uninit(&lfcc->gh);
+ kfree(lfcc);
+ }
+ gfs2_glock_dq_uninit(&ji_gh);
+ return error;
+}
+
+/**
+ * gfs2_freeze_fs - freezes the file system
+ * @sdp: the file system
+ *
+ * This function flushes data and meta data for all machines by
+ * aquiring the transaction log exclusively. All journals are
+ * ensured to be in a clean state as well.
+ *
+ * Returns: errno
+ */
+
+int gfs2_freeze_fs(struct gfs2_sbd *sdp)
+{
+ int error = 0;
+
+ mutex_lock(&sdp->sd_freeze_lock);
+
+ if (!sdp->sd_freeze_count++) {
+ error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
+ if (error)
+ sdp->sd_freeze_count--;
+ }
+
+ mutex_unlock(&sdp->sd_freeze_lock);
+
+ return error;
+}
+
+/**
+ * gfs2_unfreeze_fs - unfreezes the file system
+ * @sdp: the file system
+ *
+ * This function allows the file system to proceed by unlocking
+ * the exclusively held transaction lock. Other GFS2 nodes are
+ * now free to acquire the lock shared and go on with their lives.
+ *
+ */
+
+void gfs2_unfreeze_fs(struct gfs2_sbd *sdp)
+{
+ mutex_lock(&sdp->sd_freeze_lock);
+
+ if (sdp->sd_freeze_count && !--sdp->sd_freeze_count)
+ gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
+
+ mutex_unlock(&sdp->sd_freeze_lock);
+}
+
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
new file mode 100644
index 000000000000..5bb443ae0f59
--- /dev/null
+++ b/fs/gfs2/super.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __SUPER_DOT_H__
+#define __SUPER_DOT_H__
+
+#include "incore.h"
+
+void gfs2_tune_init(struct gfs2_tune *gt);
+
+int gfs2_check_sb(struct gfs2_sbd *sdp, struct gfs2_sb *sb, int silent);
+int gfs2_read_sb(struct gfs2_sbd *sdp, struct gfs2_glock *gl, int silent);
+struct page *gfs2_read_super(struct super_block *sb, sector_t sector);
+
+static inline unsigned int gfs2_jindex_size(struct gfs2_sbd *sdp)
+{
+ unsigned int x;
+ spin_lock(&sdp->sd_jindex_spin);
+ x = sdp->sd_journals;
+ spin_unlock(&sdp->sd_jindex_spin);
+ return x;
+}
+
+int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh);
+void gfs2_jindex_free(struct gfs2_sbd *sdp);
+
+struct gfs2_jdesc *gfs2_jdesc_find(struct gfs2_sbd *sdp, unsigned int jid);
+void gfs2_jdesc_make_dirty(struct gfs2_sbd *sdp, unsigned int jid);
+struct gfs2_jdesc *gfs2_jdesc_find_dirty(struct gfs2_sbd *sdp);
+int gfs2_jdesc_check(struct gfs2_jdesc *jd);
+
+int gfs2_lookup_in_master_dir(struct gfs2_sbd *sdp, char *filename,
+ struct gfs2_inode **ipp);
+
+int gfs2_make_fs_rw(struct gfs2_sbd *sdp);
+int gfs2_make_fs_ro(struct gfs2_sbd *sdp);
+
+int gfs2_statfs_init(struct gfs2_sbd *sdp);
+void gfs2_statfs_change(struct gfs2_sbd *sdp,
+ s64 total, s64 free, s64 dinodes);
+int gfs2_statfs_sync(struct gfs2_sbd *sdp);
+int gfs2_statfs_i(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc);
+int gfs2_statfs_slow(struct gfs2_sbd *sdp, struct gfs2_statfs_change *sc);
+
+int gfs2_freeze_fs(struct gfs2_sbd *sdp);
+void gfs2_unfreeze_fs(struct gfs2_sbd *sdp);
+
+#endif /* __SUPER_DOT_H__ */
+
diff --git a/fs/gfs2/sys.c b/fs/gfs2/sys.c
new file mode 100644
index 000000000000..0e0ec988f731
--- /dev/null
+++ b/fs/gfs2/sys.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/module.h>
+#include <linux/kobject.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "lm.h"
+#include "sys.h"
+#include "super.h"
+#include "glock.h"
+#include "quota.h"
+#include "util.h"
+
+char *gfs2_sys_margs;
+spinlock_t gfs2_sys_margs_lock;
+
+static ssize_t id_show(struct gfs2_sbd *sdp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_vfs->s_id);
+}
+
+static ssize_t fsname_show(struct gfs2_sbd *sdp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%s\n", sdp->sd_fsname);
+}
+
+static ssize_t freeze_show(struct gfs2_sbd *sdp, char *buf)
+{
+ unsigned int count;
+
+ mutex_lock(&sdp->sd_freeze_lock);
+ count = sdp->sd_freeze_count;
+ mutex_unlock(&sdp->sd_freeze_lock);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n", count);
+}
+
+static ssize_t freeze_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+ ssize_t ret = len;
+ int error = 0;
+ int n = simple_strtol(buf, NULL, 0);
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ switch (n) {
+ case 0:
+ gfs2_unfreeze_fs(sdp);
+ break;
+ case 1:
+ error = gfs2_freeze_fs(sdp);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ if (error)
+ fs_warn(sdp, "freeze %d error %d", n, error);
+
+ return ret;
+}
+
+static ssize_t withdraw_show(struct gfs2_sbd *sdp, char *buf)
+{
+ unsigned int b = test_bit(SDF_SHUTDOWN, &sdp->sd_flags);
+ return snprintf(buf, PAGE_SIZE, "%u\n", b);
+}
+
+static ssize_t withdraw_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (simple_strtol(buf, NULL, 0) != 1)
+ return -EINVAL;
+
+ gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: withdrawing from cluster at user's request\n",
+ sdp->sd_fsname);
+ return len;
+}
+
+static ssize_t statfs_sync_store(struct gfs2_sbd *sdp, const char *buf,
+ size_t len)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (simple_strtol(buf, NULL, 0) != 1)
+ return -EINVAL;
+
+ gfs2_statfs_sync(sdp);
+ return len;
+}
+
+static ssize_t shrink_store(struct gfs2_sbd *sdp, const char *buf, size_t len)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (simple_strtol(buf, NULL, 0) != 1)
+ return -EINVAL;
+
+ gfs2_gl_hash_clear(sdp, NO_WAIT);
+ return len;
+}
+
+static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
+ size_t len)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (simple_strtol(buf, NULL, 0) != 1)
+ return -EINVAL;
+
+ gfs2_quota_sync(sdp);
+ return len;
+}
+
+static ssize_t quota_refresh_user_store(struct gfs2_sbd *sdp, const char *buf,
+ size_t len)
+{
+ u32 id;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ id = simple_strtoul(buf, NULL, 0);
+
+ gfs2_quota_refresh(sdp, 1, id);
+ return len;
+}
+
+static ssize_t quota_refresh_group_store(struct gfs2_sbd *sdp, const char *buf,
+ size_t len)
+{
+ u32 id;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ id = simple_strtoul(buf, NULL, 0);
+
+ gfs2_quota_refresh(sdp, 0, id);
+ return len;
+}
+
+struct gfs2_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct gfs2_sbd *, char *);
+ ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
+};
+
+#define GFS2_ATTR(name, mode, show, store) \
+static struct gfs2_attr gfs2_attr_##name = __ATTR(name, mode, show, store)
+
+GFS2_ATTR(id, 0444, id_show, NULL);
+GFS2_ATTR(fsname, 0444, fsname_show, NULL);
+GFS2_ATTR(freeze, 0644, freeze_show, freeze_store);
+GFS2_ATTR(shrink, 0200, NULL, shrink_store);
+GFS2_ATTR(withdraw, 0644, withdraw_show, withdraw_store);
+GFS2_ATTR(statfs_sync, 0200, NULL, statfs_sync_store);
+GFS2_ATTR(quota_sync, 0200, NULL, quota_sync_store);
+GFS2_ATTR(quota_refresh_user, 0200, NULL, quota_refresh_user_store);
+GFS2_ATTR(quota_refresh_group, 0200, NULL, quota_refresh_group_store);
+
+static struct attribute *gfs2_attrs[] = {
+ &gfs2_attr_id.attr,
+ &gfs2_attr_fsname.attr,
+ &gfs2_attr_freeze.attr,
+ &gfs2_attr_shrink.attr,
+ &gfs2_attr_withdraw.attr,
+ &gfs2_attr_statfs_sync.attr,
+ &gfs2_attr_quota_sync.attr,
+ &gfs2_attr_quota_refresh_user.attr,
+ &gfs2_attr_quota_refresh_group.attr,
+ NULL,
+};
+
+static ssize_t gfs2_attr_show(struct kobject *kobj, struct attribute *attr,
+ char *buf)
+{
+ struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+ struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
+ return a->show ? a->show(sdp, buf) : 0;
+}
+
+static ssize_t gfs2_attr_store(struct kobject *kobj, struct attribute *attr,
+ const char *buf, size_t len)
+{
+ struct gfs2_sbd *sdp = container_of(kobj, struct gfs2_sbd, sd_kobj);
+ struct gfs2_attr *a = container_of(attr, struct gfs2_attr, attr);
+ return a->store ? a->store(sdp, buf, len) : len;
+}
+
+static struct sysfs_ops gfs2_attr_ops = {
+ .show = gfs2_attr_show,
+ .store = gfs2_attr_store,
+};
+
+static struct kobj_type gfs2_ktype = {
+ .default_attrs = gfs2_attrs,
+ .sysfs_ops = &gfs2_attr_ops,
+};
+
+static struct kset gfs2_kset = {
+ .subsys = &fs_subsys,
+ .kobj = {.name = "gfs2"},
+ .ktype = &gfs2_ktype,
+};
+
+/*
+ * display struct lm_lockstruct fields
+ */
+
+struct lockstruct_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct gfs2_sbd *, char *);
+};
+
+#define LOCKSTRUCT_ATTR(name, fmt) \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
+{ \
+ return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_lockstruct.ls_##name); \
+} \
+static struct lockstruct_attr lockstruct_attr_##name = __ATTR_RO(name)
+
+LOCKSTRUCT_ATTR(jid, "%u\n");
+LOCKSTRUCT_ATTR(first, "%u\n");
+LOCKSTRUCT_ATTR(lvb_size, "%u\n");
+LOCKSTRUCT_ATTR(flags, "%d\n");
+
+static struct attribute *lockstruct_attrs[] = {
+ &lockstruct_attr_jid.attr,
+ &lockstruct_attr_first.attr,
+ &lockstruct_attr_lvb_size.attr,
+ &lockstruct_attr_flags.attr,
+ NULL,
+};
+
+/*
+ * display struct gfs2_args fields
+ */
+
+struct args_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct gfs2_sbd *, char *);
+};
+
+#define ARGS_ATTR(name, fmt) \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
+{ \
+ return snprintf(buf, PAGE_SIZE, fmt, sdp->sd_args.ar_##name); \
+} \
+static struct args_attr args_attr_##name = __ATTR_RO(name)
+
+ARGS_ATTR(lockproto, "%s\n");
+ARGS_ATTR(locktable, "%s\n");
+ARGS_ATTR(hostdata, "%s\n");
+ARGS_ATTR(spectator, "%d\n");
+ARGS_ATTR(ignore_local_fs, "%d\n");
+ARGS_ATTR(localcaching, "%d\n");
+ARGS_ATTR(localflocks, "%d\n");
+ARGS_ATTR(debug, "%d\n");
+ARGS_ATTR(upgrade, "%d\n");
+ARGS_ATTR(num_glockd, "%u\n");
+ARGS_ATTR(posix_acl, "%d\n");
+ARGS_ATTR(quota, "%u\n");
+ARGS_ATTR(suiddir, "%d\n");
+ARGS_ATTR(data, "%d\n");
+
+/* one oddball doesn't fit the macro mold */
+static ssize_t noatime_show(struct gfs2_sbd *sdp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ !!test_bit(SDF_NOATIME, &sdp->sd_flags));
+}
+static struct args_attr args_attr_noatime = __ATTR_RO(noatime);
+
+static struct attribute *args_attrs[] = {
+ &args_attr_lockproto.attr,
+ &args_attr_locktable.attr,
+ &args_attr_hostdata.attr,
+ &args_attr_spectator.attr,
+ &args_attr_ignore_local_fs.attr,
+ &args_attr_localcaching.attr,
+ &args_attr_localflocks.attr,
+ &args_attr_debug.attr,
+ &args_attr_upgrade.attr,
+ &args_attr_num_glockd.attr,
+ &args_attr_posix_acl.attr,
+ &args_attr_quota.attr,
+ &args_attr_suiddir.attr,
+ &args_attr_data.attr,
+ &args_attr_noatime.attr,
+ NULL,
+};
+
+/*
+ * display counters from superblock
+ */
+
+struct counters_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct gfs2_sbd *, char *);
+};
+
+#define COUNTERS_ATTR(name, fmt) \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
+{ \
+ return snprintf(buf, PAGE_SIZE, fmt, \
+ (unsigned int)atomic_read(&sdp->sd_##name)); \
+} \
+static struct counters_attr counters_attr_##name = __ATTR_RO(name)
+
+COUNTERS_ATTR(glock_count, "%u\n");
+COUNTERS_ATTR(glock_held_count, "%u\n");
+COUNTERS_ATTR(inode_count, "%u\n");
+COUNTERS_ATTR(reclaimed, "%u\n");
+
+static struct attribute *counters_attrs[] = {
+ &counters_attr_glock_count.attr,
+ &counters_attr_glock_held_count.attr,
+ &counters_attr_inode_count.attr,
+ &counters_attr_reclaimed.attr,
+ NULL,
+};
+
+/*
+ * get and set struct gfs2_tune fields
+ */
+
+static ssize_t quota_scale_show(struct gfs2_sbd *sdp, char *buf)
+{
+ return snprintf(buf, PAGE_SIZE, "%u %u\n",
+ sdp->sd_tune.gt_quota_scale_num,
+ sdp->sd_tune.gt_quota_scale_den);
+}
+
+static ssize_t quota_scale_store(struct gfs2_sbd *sdp, const char *buf,
+ size_t len)
+{
+ struct gfs2_tune *gt = &sdp->sd_tune;
+ unsigned int x, y;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ if (sscanf(buf, "%u %u", &x, &y) != 2 || !y)
+ return -EINVAL;
+
+ spin_lock(&gt->gt_spin);
+ gt->gt_quota_scale_num = x;
+ gt->gt_quota_scale_den = y;
+ spin_unlock(&gt->gt_spin);
+ return len;
+}
+
+static ssize_t tune_set(struct gfs2_sbd *sdp, unsigned int *field,
+ int check_zero, const char *buf, size_t len)
+{
+ struct gfs2_tune *gt = &sdp->sd_tune;
+ unsigned int x;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+
+ x = simple_strtoul(buf, NULL, 0);
+
+ if (check_zero && !x)
+ return -EINVAL;
+
+ spin_lock(&gt->gt_spin);
+ *field = x;
+ spin_unlock(&gt->gt_spin);
+ return len;
+}
+
+struct tune_attr {
+ struct attribute attr;
+ ssize_t (*show)(struct gfs2_sbd *, char *);
+ ssize_t (*store)(struct gfs2_sbd *, const char *, size_t);
+};
+
+#define TUNE_ATTR_3(name, show, store) \
+static struct tune_attr tune_attr_##name = __ATTR(name, 0644, show, store)
+
+#define TUNE_ATTR_2(name, store) \
+static ssize_t name##_show(struct gfs2_sbd *sdp, char *buf) \
+{ \
+ return snprintf(buf, PAGE_SIZE, "%u\n", sdp->sd_tune.gt_##name); \
+} \
+TUNE_ATTR_3(name, name##_show, store)
+
+#define TUNE_ATTR(name, check_zero) \
+static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
+{ \
+ return tune_set(sdp, &sdp->sd_tune.gt_##name, check_zero, buf, len); \
+} \
+TUNE_ATTR_2(name, name##_store)
+
+#define TUNE_ATTR_DAEMON(name, process) \
+static ssize_t name##_store(struct gfs2_sbd *sdp, const char *buf, size_t len)\
+{ \
+ ssize_t r = tune_set(sdp, &sdp->sd_tune.gt_##name, 1, buf, len); \
+ wake_up_process(sdp->sd_##process); \
+ return r; \
+} \
+TUNE_ATTR_2(name, name##_store)
+
+TUNE_ATTR(ilimit, 0);
+TUNE_ATTR(ilimit_tries, 0);
+TUNE_ATTR(ilimit_min, 0);
+TUNE_ATTR(demote_secs, 0);
+TUNE_ATTR(incore_log_blocks, 0);
+TUNE_ATTR(log_flush_secs, 0);
+TUNE_ATTR(jindex_refresh_secs, 0);
+TUNE_ATTR(quota_warn_period, 0);
+TUNE_ATTR(quota_quantum, 0);
+TUNE_ATTR(atime_quantum, 0);
+TUNE_ATTR(max_readahead, 0);
+TUNE_ATTR(complain_secs, 0);
+TUNE_ATTR(reclaim_limit, 0);
+TUNE_ATTR(prefetch_secs, 0);
+TUNE_ATTR(statfs_slow, 0);
+TUNE_ATTR(new_files_jdata, 0);
+TUNE_ATTR(new_files_directio, 0);
+TUNE_ATTR(quota_simul_sync, 1);
+TUNE_ATTR(quota_cache_secs, 1);
+TUNE_ATTR(max_atomic_write, 1);
+TUNE_ATTR(stall_secs, 1);
+TUNE_ATTR(entries_per_readdir, 1);
+TUNE_ATTR(greedy_default, 1);
+TUNE_ATTR(greedy_quantum, 1);
+TUNE_ATTR(greedy_max, 1);
+TUNE_ATTR(statfs_quantum, 1);
+TUNE_ATTR_DAEMON(scand_secs, scand_process);
+TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
+TUNE_ATTR_DAEMON(logd_secs, logd_process);
+TUNE_ATTR_DAEMON(quotad_secs, quotad_process);
+TUNE_ATTR_3(quota_scale, quota_scale_show, quota_scale_store);
+
+static struct attribute *tune_attrs[] = {
+ &tune_attr_ilimit.attr,
+ &tune_attr_ilimit_tries.attr,
+ &tune_attr_ilimit_min.attr,
+ &tune_attr_demote_secs.attr,
+ &tune_attr_incore_log_blocks.attr,
+ &tune_attr_log_flush_secs.attr,
+ &tune_attr_jindex_refresh_secs.attr,
+ &tune_attr_quota_warn_period.attr,
+ &tune_attr_quota_quantum.attr,
+ &tune_attr_atime_quantum.attr,
+ &tune_attr_max_readahead.attr,
+ &tune_attr_complain_secs.attr,
+ &tune_attr_reclaim_limit.attr,
+ &tune_attr_prefetch_secs.attr,
+ &tune_attr_statfs_slow.attr,
+ &tune_attr_quota_simul_sync.attr,
+ &tune_attr_quota_cache_secs.attr,
+ &tune_attr_max_atomic_write.attr,
+ &tune_attr_stall_secs.attr,
+ &tune_attr_entries_per_readdir.attr,
+ &tune_attr_greedy_default.attr,
+ &tune_attr_greedy_quantum.attr,
+ &tune_attr_greedy_max.attr,
+ &tune_attr_statfs_quantum.attr,
+ &tune_attr_scand_secs.attr,
+ &tune_attr_recoverd_secs.attr,
+ &tune_attr_logd_secs.attr,
+ &tune_attr_quotad_secs.attr,
+ &tune_attr_quota_scale.attr,
+ &tune_attr_new_files_jdata.attr,
+ &tune_attr_new_files_directio.attr,
+ NULL,
+};
+
+static struct attribute_group lockstruct_group = {
+ .name = "lockstruct",
+ .attrs = lockstruct_attrs,
+};
+
+static struct attribute_group counters_group = {
+ .name = "counters",
+ .attrs = counters_attrs,
+};
+
+static struct attribute_group args_group = {
+ .name = "args",
+ .attrs = args_attrs,
+};
+
+static struct attribute_group tune_group = {
+ .name = "tune",
+ .attrs = tune_attrs,
+};
+
+int gfs2_sys_fs_add(struct gfs2_sbd *sdp)
+{
+ int error;
+
+ sdp->sd_kobj.kset = &gfs2_kset;
+ sdp->sd_kobj.ktype = &gfs2_ktype;
+
+ error = kobject_set_name(&sdp->sd_kobj, "%s", sdp->sd_table_name);
+ if (error)
+ goto fail;
+
+ error = kobject_register(&sdp->sd_kobj);
+ if (error)
+ goto fail;
+
+ error = sysfs_create_group(&sdp->sd_kobj, &lockstruct_group);
+ if (error)
+ goto fail_reg;
+
+ error = sysfs_create_group(&sdp->sd_kobj, &counters_group);
+ if (error)
+ goto fail_lockstruct;
+
+ error = sysfs_create_group(&sdp->sd_kobj, &args_group);
+ if (error)
+ goto fail_counters;
+
+ error = sysfs_create_group(&sdp->sd_kobj, &tune_group);
+ if (error)
+ goto fail_args;
+
+ return 0;
+
+fail_args:
+ sysfs_remove_group(&sdp->sd_kobj, &args_group);
+fail_counters:
+ sysfs_remove_group(&sdp->sd_kobj, &counters_group);
+fail_lockstruct:
+ sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
+fail_reg:
+ kobject_unregister(&sdp->sd_kobj);
+fail:
+ fs_err(sdp, "error %d adding sysfs files", error);
+ return error;
+}
+
+void gfs2_sys_fs_del(struct gfs2_sbd *sdp)
+{
+ sysfs_remove_group(&sdp->sd_kobj, &tune_group);
+ sysfs_remove_group(&sdp->sd_kobj, &args_group);
+ sysfs_remove_group(&sdp->sd_kobj, &counters_group);
+ sysfs_remove_group(&sdp->sd_kobj, &lockstruct_group);
+ kobject_unregister(&sdp->sd_kobj);
+}
+
+int gfs2_sys_init(void)
+{
+ gfs2_sys_margs = NULL;
+ spin_lock_init(&gfs2_sys_margs_lock);
+ return kset_register(&gfs2_kset);
+}
+
+void gfs2_sys_uninit(void)
+{
+ kfree(gfs2_sys_margs);
+ kset_unregister(&gfs2_kset);
+}
+
diff --git a/fs/gfs2/sys.h b/fs/gfs2/sys.h
new file mode 100644
index 000000000000..1ca8cdac5304
--- /dev/null
+++ b/fs/gfs2/sys.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __SYS_DOT_H__
+#define __SYS_DOT_H__
+
+#include <linux/spinlock.h>
+struct gfs2_sbd;
+
+/* Allow args to be passed to GFS2 when using an initial ram disk */
+extern char *gfs2_sys_margs;
+extern spinlock_t gfs2_sys_margs_lock;
+
+int gfs2_sys_fs_add(struct gfs2_sbd *sdp);
+void gfs2_sys_fs_del(struct gfs2_sbd *sdp);
+
+int gfs2_sys_init(void);
+void gfs2_sys_uninit(void);
+
+#endif /* __SYS_DOT_H__ */
+
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
new file mode 100644
index 000000000000..f8dabf8446bb
--- /dev/null
+++ b/fs/gfs2/trans.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/kallsyms.h>
+#include <linux/lm_interface.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "log.h"
+#include "lops.h"
+#include "meta_io.h"
+#include "trans.h"
+#include "util.h"
+
+int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
+ unsigned int revokes)
+{
+ struct gfs2_trans *tr;
+ int error;
+
+ BUG_ON(current->journal_info);
+ BUG_ON(blocks == 0 && revokes == 0);
+
+ tr = kzalloc(sizeof(struct gfs2_trans), GFP_NOFS);
+ if (!tr)
+ return -ENOMEM;
+
+ tr->tr_ip = (unsigned long)__builtin_return_address(0);
+ tr->tr_blocks = blocks;
+ tr->tr_revokes = revokes;
+ tr->tr_reserved = 1;
+ if (blocks)
+ tr->tr_reserved += 6 + blocks;
+ if (revokes)
+ tr->tr_reserved += gfs2_struct2blk(sdp, revokes,
+ sizeof(u64));
+ INIT_LIST_HEAD(&tr->tr_list_buf);
+
+ gfs2_holder_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &tr->tr_t_gh);
+
+ error = gfs2_glock_nq(&tr->tr_t_gh);
+ if (error)
+ goto fail_holder_uninit;
+
+ if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
+ tr->tr_t_gh.gh_flags |= GL_NOCACHE;
+ error = -EROFS;
+ goto fail_gunlock;
+ }
+
+ error = gfs2_log_reserve(sdp, tr->tr_reserved);
+ if (error)
+ goto fail_gunlock;
+
+ current->journal_info = tr;
+
+ return 0;
+
+fail_gunlock:
+ gfs2_glock_dq(&tr->tr_t_gh);
+
+fail_holder_uninit:
+ gfs2_holder_uninit(&tr->tr_t_gh);
+ kfree(tr);
+
+ return error;
+}
+
+void gfs2_trans_end(struct gfs2_sbd *sdp)
+{
+ struct gfs2_trans *tr = current->journal_info;
+
+ BUG_ON(!tr);
+ current->journal_info = NULL;
+
+ if (!tr->tr_touched) {
+ gfs2_log_release(sdp, tr->tr_reserved);
+ gfs2_glock_dq(&tr->tr_t_gh);
+ gfs2_holder_uninit(&tr->tr_t_gh);
+ kfree(tr);
+ return;
+ }
+
+ if (gfs2_assert_withdraw(sdp, tr->tr_num_buf <= tr->tr_blocks)) {
+ fs_err(sdp, "tr_num_buf = %u, tr_blocks = %u ",
+ tr->tr_num_buf, tr->tr_blocks);
+ print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
+ }
+ if (gfs2_assert_withdraw(sdp, tr->tr_num_revoke <= tr->tr_revokes)) {
+ fs_err(sdp, "tr_num_revoke = %u, tr_revokes = %u ",
+ tr->tr_num_revoke, tr->tr_revokes);
+ print_symbol(KERN_WARNING "GFS2: Transaction created at: %s\n", tr->tr_ip);
+ }
+
+ gfs2_log_commit(sdp, tr);
+ gfs2_glock_dq(&tr->tr_t_gh);
+ gfs2_holder_uninit(&tr->tr_t_gh);
+ kfree(tr);
+
+ if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
+ gfs2_log_flush(sdp, NULL);
+}
+
+void gfs2_trans_add_gl(struct gfs2_glock *gl)
+{
+ lops_add(gl->gl_sbd, &gl->gl_le);
+}
+
+/**
+ * gfs2_trans_add_bh - Add a to-be-modified buffer to the current transaction
+ * @gl: the glock the buffer belongs to
+ * @bh: The buffer to add
+ * @meta: True in the case of adding metadata
+ *
+ */
+
+void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta)
+{
+ struct gfs2_sbd *sdp = gl->gl_sbd;
+ struct gfs2_bufdata *bd;
+
+ bd = bh->b_private;
+ if (bd)
+ gfs2_assert(sdp, bd->bd_gl == gl);
+ else {
+ gfs2_attach_bufdata(gl, bh, meta);
+ bd = bh->b_private;
+ }
+ lops_add(sdp, &bd->bd_le);
+}
+
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno)
+{
+ struct gfs2_revoke *rv = kmalloc(sizeof(struct gfs2_revoke),
+ GFP_NOFS | __GFP_NOFAIL);
+ lops_init_le(&rv->rv_le, &gfs2_revoke_lops);
+ rv->rv_blkno = blkno;
+ lops_add(sdp, &rv->rv_le);
+}
+
+void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno)
+{
+ struct gfs2_revoke *rv;
+ int found = 0;
+
+ gfs2_log_lock(sdp);
+
+ list_for_each_entry(rv, &sdp->sd_log_le_revoke, rv_le.le_list) {
+ if (rv->rv_blkno == blkno) {
+ list_del(&rv->rv_le.le_list);
+ gfs2_assert_withdraw(sdp, sdp->sd_log_num_revoke);
+ sdp->sd_log_num_revoke--;
+ found = 1;
+ break;
+ }
+ }
+
+ gfs2_log_unlock(sdp);
+
+ if (found) {
+ struct gfs2_trans *tr = current->journal_info;
+ kfree(rv);
+ tr->tr_num_revoke_rm++;
+ }
+}
+
+void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd)
+{
+ lops_add(rgd->rd_sbd, &rgd->rd_le);
+}
+
diff --git a/fs/gfs2/trans.h b/fs/gfs2/trans.h
new file mode 100644
index 000000000000..23d4cbe1de5b
--- /dev/null
+++ b/fs/gfs2/trans.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __TRANS_DOT_H__
+#define __TRANS_DOT_H__
+
+#include <linux/buffer_head.h>
+struct gfs2_sbd;
+struct gfs2_rgrpd;
+struct gfs2_glock;
+
+#define RES_DINODE 1
+#define RES_INDIRECT 1
+#define RES_JDATA 1
+#define RES_DATA 1
+#define RES_LEAF 1
+#define RES_RG_BIT 2
+#define RES_EATTR 1
+#define RES_STATFS 1
+#define RES_QUOTA 2
+
+int gfs2_trans_begin(struct gfs2_sbd *sdp, unsigned int blocks,
+ unsigned int revokes);
+
+void gfs2_trans_end(struct gfs2_sbd *sdp);
+
+void gfs2_trans_add_gl(struct gfs2_glock *gl);
+void gfs2_trans_add_bh(struct gfs2_glock *gl, struct buffer_head *bh, int meta);
+void gfs2_trans_add_revoke(struct gfs2_sbd *sdp, u64 blkno);
+void gfs2_trans_add_unrevoke(struct gfs2_sbd *sdp, u64 blkno);
+void gfs2_trans_add_rg(struct gfs2_rgrpd *rgd);
+
+#endif /* __TRANS_DOT_H__ */
diff --git a/fs/gfs2/util.c b/fs/gfs2/util.c
new file mode 100644
index 000000000000..196c604faadc
--- /dev/null
+++ b/fs/gfs2/util.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/buffer_head.h>
+#include <linux/crc32.h>
+#include <linux/gfs2_ondisk.h>
+#include <linux/lm_interface.h>
+#include <asm/uaccess.h>
+
+#include "gfs2.h"
+#include "incore.h"
+#include "glock.h"
+#include "lm.h"
+#include "util.h"
+
+kmem_cache_t *gfs2_glock_cachep __read_mostly;
+kmem_cache_t *gfs2_inode_cachep __read_mostly;
+kmem_cache_t *gfs2_bufdata_cachep __read_mostly;
+
+void gfs2_assert_i(struct gfs2_sbd *sdp)
+{
+ printk(KERN_EMERG "GFS2: fsid=%s: fatal assertion failed\n",
+ sdp->sd_fsname);
+}
+
+/**
+ * gfs2_assert_withdraw_i - Cause the machine to withdraw if @assertion is false
+ * Returns: -1 if this call withdrew the machine,
+ * -2 if it was already withdrawn
+ */
+
+int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
+ const char *function, char *file, unsigned int line)
+{
+ int me;
+ me = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: assertion \"%s\" failed\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname, assertion,
+ sdp->sd_fsname, function, file, line);
+ dump_stack();
+ return (me) ? -1 : -2;
+}
+
+/**
+ * gfs2_assert_warn_i - Print a message to the console if @assertion is false
+ * Returns: -1 if we printed something
+ * -2 if we didn't
+ */
+
+int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
+ const char *function, char *file, unsigned int line)
+{
+ if (time_before(jiffies,
+ sdp->sd_last_warning +
+ gfs2_tune_get(sdp, gt_complain_secs) * HZ))
+ return -2;
+
+ printk(KERN_WARNING
+ "GFS2: fsid=%s: warning: assertion \"%s\" failed\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname, assertion,
+ sdp->sd_fsname, function, file, line);
+
+ if (sdp->sd_args.ar_debug)
+ BUG();
+ else
+ dump_stack();
+
+ sdp->sd_last_warning = jiffies;
+
+ return -1;
+}
+
+/**
+ * gfs2_consist_i - Flag a filesystem consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ * 0 if it was already withdrawn
+ */
+
+int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide, const char *function,
+ char *file, unsigned int line)
+{
+ int rv;
+ rv = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: filesystem consistency error\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname,
+ sdp->sd_fsname, function, file, line);
+ return rv;
+}
+
+/**
+ * gfs2_consist_inode_i - Flag an inode consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ * 0 if it was already withdrawn
+ */
+
+int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide,
+ const char *function, char *file, unsigned int line)
+{
+ struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode);
+ int rv;
+ rv = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: filesystem consistency error\n"
+ "GFS2: fsid=%s: inode = %llu %llu\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname,
+ sdp->sd_fsname, (unsigned long long)ip->i_num.no_formal_ino,
+ (unsigned long long)ip->i_num.no_addr,
+ sdp->sd_fsname, function, file, line);
+ return rv;
+}
+
+/**
+ * gfs2_consist_rgrpd_i - Flag a RG consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ * 0 if it was already withdrawn
+ */
+
+int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide,
+ const char *function, char *file, unsigned int line)
+{
+ struct gfs2_sbd *sdp = rgd->rd_sbd;
+ int rv;
+ rv = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: filesystem consistency error\n"
+ "GFS2: fsid=%s: RG = %llu\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname,
+ sdp->sd_fsname, (unsigned long long)rgd->rd_ri.ri_addr,
+ sdp->sd_fsname, function, file, line);
+ return rv;
+}
+
+/**
+ * gfs2_meta_check_ii - Flag a magic number consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ * -2 if it was already withdrawn
+ */
+
+int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ const char *type, const char *function, char *file,
+ unsigned int line)
+{
+ int me;
+ me = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: invalid metadata block\n"
+ "GFS2: fsid=%s: bh = %llu (%s)\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname,
+ sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type,
+ sdp->sd_fsname, function, file, line);
+ return (me) ? -1 : -2;
+}
+
+/**
+ * gfs2_metatype_check_ii - Flag a metadata type consistency error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ * -2 if it was already withdrawn
+ */
+
+int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ u16 type, u16 t, const char *function,
+ char *file, unsigned int line)
+{
+ int me;
+ me = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: invalid metadata block\n"
+ "GFS2: fsid=%s: bh = %llu (type: exp=%u, found=%u)\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname,
+ sdp->sd_fsname, (unsigned long long)bh->b_blocknr, type, t,
+ sdp->sd_fsname, function, file, line);
+ return (me) ? -1 : -2;
+}
+
+/**
+ * gfs2_io_error_i - Flag an I/O error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ * 0 if it was already withdrawn
+ */
+
+int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function, char *file,
+ unsigned int line)
+{
+ int rv;
+ rv = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: I/O error\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname,
+ sdp->sd_fsname, function, file, line);
+ return rv;
+}
+
+/**
+ * gfs2_io_error_bh_i - Flag a buffer I/O error and withdraw
+ * Returns: -1 if this call withdrew the machine,
+ * 0 if it was already withdrawn
+ */
+
+int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ const char *function, char *file, unsigned int line)
+{
+ int rv;
+ rv = gfs2_lm_withdraw(sdp,
+ "GFS2: fsid=%s: fatal: I/O error\n"
+ "GFS2: fsid=%s: block = %llu\n"
+ "GFS2: fsid=%s: function = %s, file = %s, line = %u\n",
+ sdp->sd_fsname,
+ sdp->sd_fsname, (unsigned long long)bh->b_blocknr,
+ sdp->sd_fsname, function, file, line);
+ return rv;
+}
+
+void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
+ unsigned int bit, int new_value)
+{
+ unsigned int c, o, b = bit;
+ int old_value;
+
+ c = b / (8 * PAGE_SIZE);
+ b %= 8 * PAGE_SIZE;
+ o = b / 8;
+ b %= 8;
+
+ old_value = (bitmap[c][o] & (1 << b));
+ gfs2_assert_withdraw(sdp, !old_value != !new_value);
+
+ if (new_value)
+ bitmap[c][o] |= 1 << b;
+ else
+ bitmap[c][o] &= ~(1 << b);
+}
+
diff --git a/fs/gfs2/util.h b/fs/gfs2/util.h
new file mode 100644
index 000000000000..76a50899fe9e
--- /dev/null
+++ b/fs/gfs2/util.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __UTIL_DOT_H__
+#define __UTIL_DOT_H__
+
+#include "incore.h"
+
+#define fs_printk(level, fs, fmt, arg...) \
+ printk(level "GFS2: fsid=%s: " fmt , (fs)->sd_fsname , ## arg)
+
+#define fs_info(fs, fmt, arg...) \
+ fs_printk(KERN_INFO , fs , fmt , ## arg)
+
+#define fs_warn(fs, fmt, arg...) \
+ fs_printk(KERN_WARNING , fs , fmt , ## arg)
+
+#define fs_err(fs, fmt, arg...) \
+ fs_printk(KERN_ERR, fs , fmt , ## arg)
+
+
+void gfs2_assert_i(struct gfs2_sbd *sdp);
+
+#define gfs2_assert(sdp, assertion) \
+do { \
+ if (unlikely(!(assertion))) { \
+ gfs2_assert_i(sdp); \
+ BUG(); \
+ } \
+} while (0)
+
+
+int gfs2_assert_withdraw_i(struct gfs2_sbd *sdp, char *assertion,
+ const char *function, char *file, unsigned int line);
+
+#define gfs2_assert_withdraw(sdp, assertion) \
+((likely(assertion)) ? 0 : gfs2_assert_withdraw_i((sdp), #assertion, \
+ __FUNCTION__, __FILE__, __LINE__))
+
+
+int gfs2_assert_warn_i(struct gfs2_sbd *sdp, char *assertion,
+ const char *function, char *file, unsigned int line);
+
+#define gfs2_assert_warn(sdp, assertion) \
+((likely(assertion)) ? 0 : gfs2_assert_warn_i((sdp), #assertion, \
+ __FUNCTION__, __FILE__, __LINE__))
+
+
+int gfs2_consist_i(struct gfs2_sbd *sdp, int cluster_wide,
+ const char *function, char *file, unsigned int line);
+
+#define gfs2_consist(sdp) \
+gfs2_consist_i((sdp), 0, __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_consist_inode_i(struct gfs2_inode *ip, int cluster_wide,
+ const char *function, char *file, unsigned int line);
+
+#define gfs2_consist_inode(ip) \
+gfs2_consist_inode_i((ip), 0, __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_consist_rgrpd_i(struct gfs2_rgrpd *rgd, int cluster_wide,
+ const char *function, char *file, unsigned int line);
+
+#define gfs2_consist_rgrpd(rgd) \
+gfs2_consist_rgrpd_i((rgd), 0, __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_meta_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ const char *type, const char *function,
+ char *file, unsigned int line);
+
+static inline int gfs2_meta_check_i(struct gfs2_sbd *sdp,
+ struct buffer_head *bh,
+ const char *function,
+ char *file, unsigned int line)
+{
+ struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
+ u32 magic = mh->mh_magic;
+ magic = be32_to_cpu(magic);
+ if (unlikely(magic != GFS2_MAGIC))
+ return gfs2_meta_check_ii(sdp, bh, "magic number", function,
+ file, line);
+ return 0;
+}
+
+#define gfs2_meta_check(sdp, bh) \
+gfs2_meta_check_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__)
+
+
+int gfs2_metatype_check_ii(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ u16 type, u16 t,
+ const char *function,
+ char *file, unsigned int line);
+
+static inline int gfs2_metatype_check_i(struct gfs2_sbd *sdp,
+ struct buffer_head *bh,
+ u16 type,
+ const char *function,
+ char *file, unsigned int line)
+{
+ struct gfs2_meta_header *mh = (struct gfs2_meta_header *)bh->b_data;
+ u32 magic = mh->mh_magic;
+ u16 t = be32_to_cpu(mh->mh_type);
+ magic = be32_to_cpu(magic);
+ if (unlikely(magic != GFS2_MAGIC))
+ return gfs2_meta_check_ii(sdp, bh, "magic number", function,
+ file, line);
+ if (unlikely(t != type))
+ return gfs2_metatype_check_ii(sdp, bh, type, t, function,
+ file, line);
+ return 0;
+}
+
+#define gfs2_metatype_check(sdp, bh, type) \
+gfs2_metatype_check_i((sdp), (bh), (type), __FUNCTION__, __FILE__, __LINE__)
+
+static inline void gfs2_metatype_set(struct buffer_head *bh, u16 type,
+ u16 format)
+{
+ struct gfs2_meta_header *mh;
+ mh = (struct gfs2_meta_header *)bh->b_data;
+ mh->mh_type = cpu_to_be32(type);
+ mh->mh_format = cpu_to_be32(format);
+}
+
+
+int gfs2_io_error_i(struct gfs2_sbd *sdp, const char *function,
+ char *file, unsigned int line);
+
+#define gfs2_io_error(sdp) \
+gfs2_io_error_i((sdp), __FUNCTION__, __FILE__, __LINE__);
+
+
+int gfs2_io_error_bh_i(struct gfs2_sbd *sdp, struct buffer_head *bh,
+ const char *function, char *file, unsigned int line);
+
+#define gfs2_io_error_bh(sdp, bh) \
+gfs2_io_error_bh_i((sdp), (bh), __FUNCTION__, __FILE__, __LINE__);
+
+
+extern kmem_cache_t *gfs2_glock_cachep;
+extern kmem_cache_t *gfs2_inode_cachep;
+extern kmem_cache_t *gfs2_bufdata_cachep;
+
+static inline unsigned int gfs2_tune_get_i(struct gfs2_tune *gt,
+ unsigned int *p)
+{
+ unsigned int x;
+ spin_lock(&gt->gt_spin);
+ x = *p;
+ spin_unlock(&gt->gt_spin);
+ return x;
+}
+
+#define gfs2_tune_get(sdp, field) \
+gfs2_tune_get_i(&(sdp)->sd_tune, &(sdp)->sd_tune.field)
+
+void gfs2_icbit_munge(struct gfs2_sbd *sdp, unsigned char **bitmap,
+ unsigned int bit, int new_value);
+
+#endif /* __UTIL_DOT_H__ */
+
diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c
index 13231dd5ce66..0d200068d0af 100644
--- a/fs/hfs/bnode.c
+++ b/fs/hfs/bnode.c
@@ -249,10 +249,9 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
sb = tree->inode->i_sb;
size = sizeof(struct hfs_bnode) + tree->pages_per_bnode *
sizeof(struct page *);
- node = kmalloc(size, GFP_KERNEL);
+ node = kzalloc(size, GFP_KERNEL);
if (!node)
return NULL;
- memset(node, 0, size);
node->tree = tree;
node->this = cnid;
set_bit(HFS_BNODE_NEW, &node->flags);
diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c
index 400357994319..5fd0ed71f923 100644
--- a/fs/hfs/btree.c
+++ b/fs/hfs/btree.c
@@ -21,10 +21,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id, btree_keycmp ke
struct page *page;
unsigned int size;
- tree = kmalloc(sizeof(*tree), GFP_KERNEL);
+ tree = kzalloc(sizeof(*tree), GFP_KERNEL);
if (!tree)
return NULL;
- memset(tree, 0, sizeof(*tree));
init_MUTEX(&tree->tree_lock);
spin_lock_init(&tree->hash_lock);
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 7cd8cc03aea7..37d681b4f216 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -246,7 +246,7 @@ static int hfs_unlink(struct inode *dir, struct dentry *dentry)
if (res)
return res;
- inode->i_nlink--;
+ drop_nlink(inode);
hfs_delete_inode(inode);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
@@ -273,7 +273,7 @@ static int hfs_rmdir(struct inode *dir, struct dentry *dentry)
res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
if (res)
return res;
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC;
hfs_delete_inode(inode);
mark_inode_dirty(inode);
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 315cf44a90b2..02f5573e0349 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -154,7 +154,6 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, int mode)
inode->i_gid = current->fsgid;
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- inode->i_blksize = HFS_SB(sb)->alloc_blksz;
HFS_I(inode)->flags = 0;
HFS_I(inode)->rsrc_inode = NULL;
HFS_I(inode)->fs_blocks = 0;
@@ -284,7 +283,6 @@ static int hfs_read_inode(struct inode *inode, void *data)
inode->i_uid = hsb->s_uid;
inode->i_gid = hsb->s_gid;
inode->i_nlink = 1;
- inode->i_blksize = HFS_SB(inode->i_sb)->alloc_blksz;
if (idata->key)
HFS_I(inode)->cat_key = *idata->key;
@@ -603,8 +601,10 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr)
static const struct file_operations hfs_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.sendfile = generic_file_sendfile,
.fsync = file_fsync,
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 34937ee83ab1..d43b4fcc8ad3 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -356,11 +356,10 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
struct inode *root_inode;
int res;
- sbi = kmalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct hfs_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
sb->s_fs_info = sbi;
- memset(sbi, 0, sizeof(struct hfs_sb_info));
INIT_HLIST_HEAD(&sbi->rsrc_inodes);
res = -EINVAL;
@@ -455,8 +454,7 @@ static int __init init_hfs_fs(void)
static void __exit exit_hfs_fs(void)
{
unregister_filesystem(&hfs_fs_type);
- if (kmem_cache_destroy(hfs_inode_cachep))
- printk(KERN_ERR "hfs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(hfs_inode_cachep);
}
module_init(init_hfs_fs)
diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c
index 77bf434da679..29da6574ba77 100644
--- a/fs/hfsplus/bnode.c
+++ b/fs/hfsplus/bnode.c
@@ -409,10 +409,9 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
sb = tree->inode->i_sb;
size = sizeof(struct hfs_bnode) + tree->pages_per_bnode *
sizeof(struct page *);
- node = kmalloc(size, GFP_KERNEL);
+ node = kzalloc(size, GFP_KERNEL);
if (!node)
return NULL;
- memset(node, 0, size);
node->tree = tree;
node->this = cnid;
set_bit(HFS_BNODE_NEW, &node->flags);
diff --git a/fs/hfsplus/btree.c b/fs/hfsplus/btree.c
index cfc852fdd1b5..a9b9e872e29a 100644
--- a/fs/hfsplus/btree.c
+++ b/fs/hfsplus/btree.c
@@ -24,10 +24,9 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
struct page *page;
unsigned int size;
- tree = kmalloc(sizeof(*tree), GFP_KERNEL);
+ tree = kzalloc(sizeof(*tree), GFP_KERNEL);
if (!tree)
return NULL;
- memset(tree, 0, sizeof(*tree));
init_MUTEX(&tree->tree_lock);
spin_lock_init(&tree->hash_lock);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 1f9ece0de326..7e309751645f 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -298,7 +298,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
if (res)
return res;
- inode->i_nlink++;
+ inc_nlink(inode);
hfsplus_instantiate(dst_dentry, inode, cnid);
atomic_inc(&inode->i_count);
inode->i_ctime = CURRENT_TIME_SEC;
@@ -338,7 +338,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
return res;
if (inode->i_nlink > 0)
- inode->i_nlink--;
+ drop_nlink(inode);
hfsplus_delete_inode(inode);
if (inode->i_ino != cnid && !inode->i_nlink) {
if (!atomic_read(&HFSPLUS_I(inode).opencnt)) {
@@ -348,7 +348,7 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
} else
inode->i_flags |= S_DEAD;
} else
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
@@ -387,7 +387,7 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
res = hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name);
if (res)
return res;
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC;
hfsplus_delete_inode(inode);
mark_inode_dirty(inode);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index 8a1ca5ef7ada..3915635b4470 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -246,12 +246,8 @@ struct hfsplus_readdir_data {
/* ext2 ioctls (EXT2_IOC_GETFLAGS and EXT2_IOC_SETFLAGS) to support
* chattr/lsattr */
-#define HFSPLUS_IOC_EXT2_GETFLAGS _IOR('f', 1, long)
-#define HFSPLUS_IOC_EXT2_SETFLAGS _IOW('f', 2, long)
-
-#define EXT2_FLAG_IMMUTABLE 0x00000010 /* Immutable file */
-#define EXT2_FLAG_APPEND 0x00000020 /* writes to file may only append */
-#define EXT2_FLAG_NODUMP 0x00000040 /* do not dump file */
+#define HFSPLUS_IOC_EXT2_GETFLAGS FS_IOC_GETFLAGS
+#define HFSPLUS_IOC_EXT2_SETFLAGS FS_IOC_SETFLAGS
/*
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 924ecdef8091..9e3675249633 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -282,8 +282,10 @@ static struct inode_operations hfsplus_file_inode_operations = {
static const struct file_operations hfsplus_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.sendfile = generic_file_sendfile,
.fsync = file_fsync,
@@ -304,7 +306,6 @@ struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
inode->i_gid = current->fsgid;
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- inode->i_blksize = HFSPLUS_SB(sb).alloc_blksz;
INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
init_MUTEX(&HFSPLUS_I(inode).extents_lock);
atomic_set(&HFSPLUS_I(inode).opencnt, 0);
@@ -407,7 +408,6 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
HFSPLUS_I(inode).dev = 0;
- inode->i_blksize = HFSPLUS_SB(inode->i_sb).alloc_blksz;
if (type == HFSPLUS_FOLDER) {
struct hfsplus_cat_folder *folder = &entry.folder;
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c
index 13cf848ac833..79fd10402ea3 100644
--- a/fs/hfsplus/ioctl.c
+++ b/fs/hfsplus/ioctl.c
@@ -28,11 +28,11 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
case HFSPLUS_IOC_EXT2_GETFLAGS:
flags = 0;
if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE)
- flags |= EXT2_FLAG_IMMUTABLE; /* EXT2_IMMUTABLE_FL */
+ flags |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */
if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND)
- flags |= EXT2_FLAG_APPEND; /* EXT2_APPEND_FL */
+ flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */
if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP)
- flags |= EXT2_FLAG_NODUMP; /* EXT2_NODUMP_FL */
+ flags |= FS_NODUMP_FL; /* EXT2_NODUMP_FL */
return put_user(flags, (int __user *)arg);
case HFSPLUS_IOC_EXT2_SETFLAGS: {
if (IS_RDONLY(inode))
@@ -44,32 +44,31 @@ int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
if (get_user(flags, (int __user *)arg))
return -EFAULT;
- if (flags & (EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND) ||
+ if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) {
if (!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
}
/* don't silently ignore unsupported ext2 flags */
- if (flags & ~(EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND|
- EXT2_FLAG_NODUMP))
+ if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL))
return -EOPNOTSUPP;
- if (flags & EXT2_FLAG_IMMUTABLE) { /* EXT2_IMMUTABLE_FL */
+ if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */
inode->i_flags |= S_IMMUTABLE;
HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE;
} else {
inode->i_flags &= ~S_IMMUTABLE;
HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
}
- if (flags & EXT2_FLAG_APPEND) { /* EXT2_APPEND_FL */
+ if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */
inode->i_flags |= S_APPEND;
HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND;
} else {
inode->i_flags &= ~S_APPEND;
HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND;
}
- if (flags & EXT2_FLAG_NODUMP) /* EXT2_NODUMP_FL */
+ if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */
HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP;
else
HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP;
diff --git a/fs/hfsplus/part_tbl.c b/fs/hfsplus/part_tbl.c
index ae783066fc3a..1528a6fd0299 100644
--- a/fs/hfsplus/part_tbl.c
+++ b/fs/hfsplus/part_tbl.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/hfs/part_tbl.c
+ * linux/fs/hfsplus/part_tbl.c
*
* Copyright (C) 1996-1997 Paul H. Hargrove
* This file may be distributed under the terms of the GNU General Public License.
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c
index d279d5924f28..194eede52fa4 100644
--- a/fs/hfsplus/super.c
+++ b/fs/hfsplus/super.c
@@ -493,8 +493,7 @@ static int __init init_hfsplus_fs(void)
static void __exit exit_hfsplus_fs(void)
{
unregister_filesystem(&hfsplus_fs_type);
- if (kmem_cache_destroy(hfsplus_inode_cachep))
- printk(KERN_ERR "hfsplus_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(hfsplus_inode_cachep);
}
module_init(init_hfsplus_fs)
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index b82e3d9c8790..b6bd33ca3731 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -156,7 +156,6 @@ static int read_name(struct inode *ino, char *name)
ino->i_mode = i_mode;
ino->i_nlink = i_nlink;
ino->i_size = i_size;
- ino->i_blksize = i_blksize;
ino->i_blocks = i_blocks;
return(0);
}
@@ -386,13 +385,11 @@ int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync)
static const struct file_operations hostfs_file_fops = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
+ .read = do_sync_read,
.sendfile = generic_file_sendfile,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
- .readv = generic_file_readv,
- .writev = generic_file_writev,
- .write = generic_file_write,
+ .write = do_sync_write,
.mmap = generic_file_mmap,
.open = hostfs_file_open,
.release = NULL,
diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c
index 2807aa833e62..b52b7381d10f 100644
--- a/fs/hpfs/buffer.c
+++ b/fs/hpfs/buffer.c
@@ -76,7 +76,7 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
return NULL;
}
- qbh->data = data = (char *)kmalloc(2048, GFP_NOFS);
+ qbh->data = data = kmalloc(2048, GFP_NOFS);
if (!data) {
printk("HPFS: hpfs_map_4sectors: out of memory\n");
goto bail;
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c
index d9eb19b7b8ae..8b94d24855f0 100644
--- a/fs/hpfs/file.c
+++ b/fs/hpfs/file.c
@@ -113,7 +113,7 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf,
{
ssize_t retval;
- retval = generic_file_write(file, buf, count, ppos);
+ retval = do_sync_write(file, buf, count, ppos);
if (retval > 0)
hpfs_i(file->f_dentry->d_inode)->i_dirty = 1;
return retval;
@@ -122,8 +122,10 @@ static ssize_t hpfs_file_write(struct file *file, const char __user *buf,
const struct file_operations hpfs_file_ops =
{
.llseek = generic_file_llseek,
- .read = generic_file_read,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
.write = hpfs_file_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.release = hpfs_file_release,
.fsync = hpfs_file_fsync,
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c
index 56f2c338c4d9..7faef8544f32 100644
--- a/fs/hpfs/inode.c
+++ b/fs/hpfs/inode.c
@@ -17,7 +17,6 @@ void hpfs_init_inode(struct inode *i)
i->i_gid = hpfs_sb(sb)->sb_gid;
i->i_mode = hpfs_sb(sb)->sb_mode;
hpfs_inode->i_conv = hpfs_sb(sb)->sb_conv;
- i->i_blksize = 512;
i->i_size = -1;
i->i_blocks = -1;
@@ -61,14 +60,14 @@ void hpfs_read_inode(struct inode *i)
if (hpfs_sb(i->i_sb)->sb_eas) {
if ((ea = hpfs_get_ea(i->i_sb, fnode, "UID", &ea_size))) {
if (ea_size == 2) {
- i->i_uid = le16_to_cpu(*(u16*)ea);
+ i->i_uid = le16_to_cpu(*(__le16*)ea);
hpfs_inode->i_ea_uid = 1;
}
kfree(ea);
}
if ((ea = hpfs_get_ea(i->i_sb, fnode, "GID", &ea_size))) {
if (ea_size == 2) {
- i->i_gid = le16_to_cpu(*(u16*)ea);
+ i->i_gid = le16_to_cpu(*(__le16*)ea);
hpfs_inode->i_ea_gid = 1;
}
kfree(ea);
@@ -88,7 +87,7 @@ void hpfs_read_inode(struct inode *i)
int rdev = 0;
umode_t mode = hpfs_sb(sb)->sb_mode;
if (ea_size == 2) {
- mode = le16_to_cpu(*(u16*)ea);
+ mode = le16_to_cpu(*(__le16*)ea);
hpfs_inode->i_ea_mode = 1;
}
kfree(ea);
@@ -96,7 +95,7 @@ void hpfs_read_inode(struct inode *i)
if (S_ISBLK(mode) || S_ISCHR(mode)) {
if ((ea = hpfs_get_ea(i->i_sb, fnode, "DEV", &ea_size))) {
if (ea_size == 4)
- rdev = le32_to_cpu(*(u32*)ea);
+ rdev = le32_to_cpu(*(__le32*)ea);
kfree(ea);
}
}
@@ -149,7 +148,7 @@ static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
we'd better not overwrite them
hpfs_error(i->i_sb, "fnode %08x has some unknown HPFS386 stuctures", i->i_ino);
} else*/ if (hpfs_sb(i->i_sb)->sb_eas >= 2) {
- u32 ea;
+ __le32 ea;
if ((i->i_uid != hpfs_sb(i->i_sb)->sb_uid) || hpfs_inode->i_ea_uid) {
ea = cpu_to_le32(i->i_uid);
hpfs_set_ea(i, fnode, "UID", (char*)&ea, 2);
@@ -166,6 +165,7 @@ static void hpfs_write_inode_ea(struct inode *i, struct fnode *fnode)
&& i->i_mode != ((hpfs_sb(i->i_sb)->sb_mode & ~(S_ISDIR(i->i_mode) ? 0222 : 0333))
| (S_ISDIR(i->i_mode) ? S_IFDIR : S_IFREG))) || hpfs_inode->i_ea_mode) {
ea = cpu_to_le32(i->i_mode);
+ /* sick, but legal */
hpfs_set_ea(i, fnode, "MODE", (char *)&ea, 2);
hpfs_inode->i_ea_mode = 1;
}
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 59e7dc182a0c..2507e7393f3c 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -89,7 +89,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
brelse(bh);
hpfs_mark_4buffers_dirty(&qbh0);
hpfs_brelse4(&qbh0);
- dir->i_nlink++;
+ inc_nlink(dir);
insert_inode_hash(result);
if (result->i_uid != current->fsuid ||
@@ -434,7 +434,7 @@ again:
unlock_kernel();
return -ENOSPC;
default:
- inode->i_nlink--;
+ drop_nlink(inode);
err = 0;
}
goto out;
@@ -494,8 +494,8 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
err = -ENOSPC;
break;
default:
- dir->i_nlink--;
- inode->i_nlink = 0;
+ drop_nlink(dir);
+ clear_nlink(inode);
err = 0;
}
goto out;
@@ -590,7 +590,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
int r;
if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) {
- new_inode->i_nlink = 0;
+ clear_nlink(new_inode);
copy_de(nde, &de);
memcpy(nde->name, new_name, new_len);
hpfs_mark_4buffers_dirty(&qbh1);
@@ -635,8 +635,8 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
end:
hpfs_i(i)->i_parent_dir = new_dir->i_ino;
if (S_ISDIR(i->i_mode)) {
- new_dir->i_nlink++;
- old_dir->i_nlink--;
+ inc_nlink(new_dir);
+ drop_nlink(old_dir);
}
if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
fnode->up = new_dir->i_ino;
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c
index 8fe51c343786..450b5e0b4785 100644
--- a/fs/hpfs/super.c
+++ b/fs/hpfs/super.c
@@ -203,8 +203,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(hpfs_inode_cachep))
- printk(KERN_INFO "hpfs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(hpfs_inode_cachep);
}
/*
@@ -462,11 +461,10 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
int o;
- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
s->s_fs_info = sbi;
- memset(sbi, 0, sizeof(*sbi));
sbi->sb_bmp_dir = NULL;
sbi->sb_cp_table = NULL;
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index 3a9bdf58166f..642675fc394a 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -152,7 +152,6 @@ static void hppfs_read_inode(struct inode *ino)
ino->i_mode = proc_ino->i_mode;
ino->i_nlink = proc_ino->i_nlink;
ino->i_size = proc_ino->i_size;
- ino->i_blksize = proc_ino->i_blksize;
ino->i_blocks = proc_ino->i_blocks;
}
@@ -573,7 +572,7 @@ struct hppfs_dirent {
};
static int hppfs_filldir(void *d, const char *name, int size,
- loff_t offset, ino_t inode, unsigned int type)
+ loff_t offset, u64 inode, unsigned int type)
{
struct hppfs_dirent *dirent = d;
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index c3920c96dadf..4ee3f006b861 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -229,7 +229,7 @@ static void hugetlbfs_delete_inode(struct inode *inode)
clear_inode(inode);
}
-static void hugetlbfs_forget_inode(struct inode *inode)
+static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock)
{
struct super_block *sb = inode->i_sb;
@@ -293,7 +293,7 @@ hugetlb_vmtruncate_list(struct prio_tree_root *root, unsigned long h_pgoff)
if (h_vm_pgoff >= h_pgoff)
v_offset = 0;
- unmap_hugepage_range(vma,
+ __unmap_hugepage_range(vma,
vma->vm_start + v_offset, vma->vm_end);
}
}
@@ -357,7 +357,6 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
inode->i_mode = mode;
inode->i_uid = uid;
inode->i_gid = gid;
- inode->i_blksize = HPAGE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->a_ops = &hugetlbfs_aops;
inode->i_mapping->backing_dev_info =&hugetlbfs_backing_dev_info;
@@ -378,7 +377,7 @@ static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid,
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
@@ -419,7 +418,7 @@ static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0);
if (!retval)
- dir->i_nlink++;
+ inc_nlink(dir);
return retval;
}
diff --git a/fs/inode.c b/fs/inode.c
index 0bf9f0444a96..26cdb115ce67 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -133,7 +133,6 @@ static struct inode *alloc_inode(struct super_block *sb)
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
- inode->i_security = NULL;
inode->dirtied_when = 0;
if (security_inode_alloc(inode)) {
if (inode->i_sb->s_op->destroy_inode)
@@ -163,7 +162,7 @@ static struct inode *alloc_inode(struct super_block *sb)
bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
mapping->backing_dev_info = bdi;
}
- memset(&inode->u, 0, sizeof(inode->u));
+ inode->i_private = NULL;
inode->i_mapping = mapping;
}
return inode;
@@ -254,9 +253,9 @@ void clear_inode(struct inode *inode)
DQUOT_DROP(inode);
if (inode->i_sb && inode->i_sb->s_op->clear_inode)
inode->i_sb->s_op->clear_inode(inode);
- if (inode->i_bdev)
+ if (S_ISBLK(inode->i_mode) && inode->i_bdev)
bd_forget(inode);
- if (inode->i_cdev)
+ if (S_ISCHR(inode->i_mode) && inode->i_cdev)
cd_forget(inode);
inode->i_state = I_CLEAR;
}
@@ -363,27 +362,6 @@ int invalidate_inodes(struct super_block * sb)
}
EXPORT_SYMBOL(invalidate_inodes);
-
-int __invalidate_device(struct block_device *bdev)
-{
- struct super_block *sb = get_super(bdev);
- int res = 0;
-
- if (sb) {
- /*
- * no need to lock the super, get_super holds the
- * read mutex so the filesystem cannot go away
- * under us (->put_super runs with the write lock
- * hold).
- */
- shrink_dcache_sb(sb);
- res = invalidate_inodes(sb);
- drop_super(sb);
- }
- invalidate_bdev(bdev, 0);
- return res;
-}
-EXPORT_SYMBOL(__invalidate_device);
static int can_unuse(struct inode *inode)
{
@@ -679,7 +657,7 @@ static struct inode * get_new_inode_fast(struct super_block *sb, struct hlist_he
return inode;
}
-static inline unsigned long hash(struct super_block *sb, unsigned long hashval)
+static unsigned long hash(struct super_block *sb, unsigned long hashval)
{
unsigned long tmp;
@@ -1025,7 +1003,7 @@ void generic_delete_inode(struct inode *inode)
list_del_init(&inode->i_list);
list_del_init(&inode->i_sb_list);
- inode->i_state|=I_FREEING;
+ inode->i_state |= I_FREEING;
inodes_stat.nr_inodes--;
spin_unlock(&inode_lock);
@@ -1232,13 +1210,15 @@ void file_update_time(struct file *file)
return;
now = current_fs_time(inode->i_sb);
- if (!timespec_equal(&inode->i_mtime, &now))
+ if (!timespec_equal(&inode->i_mtime, &now)) {
+ inode->i_mtime = now;
sync_it = 1;
- inode->i_mtime = now;
+ }
- if (!timespec_equal(&inode->i_ctime, &now))
+ if (!timespec_equal(&inode->i_ctime, &now)) {
+ inode->i_ctime = now;
sync_it = 1;
- inode->i_ctime = now;
+ }
if (sync_it)
mark_inode_dirty_sync(inode);
@@ -1326,6 +1306,42 @@ void wake_up_inode(struct inode *inode)
wake_up_bit(&inode->i_state, __I_LOCK);
}
+/*
+ * We rarely want to lock two inodes that do not have a parent/child
+ * relationship (such as directory, child inode) simultaneously. The
+ * vast majority of file systems should be able to get along fine
+ * without this. Do not use these functions except as a last resort.
+ */
+void inode_double_lock(struct inode *inode1, struct inode *inode2)
+{
+ if (inode1 == NULL || inode2 == NULL || inode1 == inode2) {
+ if (inode1)
+ mutex_lock(&inode1->i_mutex);
+ else if (inode2)
+ mutex_lock(&inode2->i_mutex);
+ return;
+ }
+
+ if (inode1 < inode2) {
+ mutex_lock_nested(&inode1->i_mutex, I_MUTEX_PARENT);
+ mutex_lock_nested(&inode2->i_mutex, I_MUTEX_CHILD);
+ } else {
+ mutex_lock_nested(&inode2->i_mutex, I_MUTEX_PARENT);
+ mutex_lock_nested(&inode1->i_mutex, I_MUTEX_CHILD);
+ }
+}
+EXPORT_SYMBOL(inode_double_lock);
+
+void inode_double_unlock(struct inode *inode1, struct inode *inode2)
+{
+ if (inode1)
+ mutex_unlock(&inode1->i_mutex);
+
+ if (inode2 && inode2 != inode1)
+ mutex_unlock(&inode2->i_mutex);
+}
+EXPORT_SYMBOL(inode_double_unlock);
+
static __initdata unsigned long ihash_entries;
static int __init set_ihash_entries(char *str)
{
diff --git a/fs/internal.h b/fs/internal.h
new file mode 100644
index 000000000000..ea00126c9a59
--- /dev/null
+++ b/fs/internal.h
@@ -0,0 +1,55 @@
+/* fs/ internal definitions
+ *
+ * Copyright (C) 2006 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/ioctl32.h>
+
+struct super_block;
+
+/*
+ * block_dev.c
+ */
+#ifdef CONFIG_BLOCK
+extern struct super_block *blockdev_superblock;
+extern void __init bdev_cache_init(void);
+
+static inline int sb_is_blkdev_sb(struct super_block *sb)
+{
+ return sb == blockdev_superblock;
+}
+
+#else
+static inline void bdev_cache_init(void)
+{
+}
+
+static inline int sb_is_blkdev_sb(struct super_block *sb)
+{
+ return 0;
+}
+#endif
+
+/*
+ * char_dev.c
+ */
+extern void __init chrdev_init(void);
+
+/*
+ * compat_ioctl.c
+ */
+#ifdef CONFIG_COMPAT
+extern struct ioctl_trans ioctl_start[];
+extern int ioctl_table_size;
+#endif
+
+/*
+ * namespace.c
+ */
+extern int copy_mount_options(const void __user *, unsigned long *);
diff --git a/fs/ioprio.c b/fs/ioprio.c
index 78b1deae3fa2..89e8da112a75 100644
--- a/fs/ioprio.c
+++ b/fs/ioprio.c
@@ -1,7 +1,7 @@
/*
* fs/ioprio.c
*
- * Copyright (C) 2004 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2004 Jens Axboe <axboe@kernel.dk>
*
* Helper functions for setting/querying io priorities of processes. The
* system calls closely mimmick getpriority/setpriority, see the man page for
@@ -47,8 +47,8 @@ static int set_task_ioprio(struct task_struct *task, int ioprio)
/* see wmb() in current_io_context() */
smp_read_barrier_depends();
- if (ioc && ioc->set_ioprio)
- ioc->set_ioprio(ioc, ioprio);
+ if (ioc)
+ ioc->ioprio_changed = 1;
task_unlock(task);
return 0;
@@ -81,7 +81,12 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
}
ret = -ESRCH;
- read_lock_irq(&tasklist_lock);
+ /*
+ * We want IOPRIO_WHO_PGRP/IOPRIO_WHO_USER to be "atomic",
+ * so we can't use rcu_read_lock(). See re-copy of ->ioprio
+ * in copy_process().
+ */
+ read_lock(&tasklist_lock);
switch (which) {
case IOPRIO_WHO_PROCESS:
if (!who)
@@ -124,7 +129,7 @@ free_uid:
ret = -EINVAL;
}
- read_unlock_irq(&tasklist_lock);
+ read_unlock(&tasklist_lock);
return ret;
}
@@ -145,11 +150,6 @@ int ioprio_best(unsigned short aprio, unsigned short bprio)
unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
- if (!ioprio_valid(aprio))
- return bprio;
- if (!ioprio_valid(bprio))
- return aprio;
-
if (aclass == IOPRIO_CLASS_NONE)
aclass = IOPRIO_CLASS_BE;
if (bclass == IOPRIO_CLASS_NONE)
@@ -170,7 +170,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
int ret = -ESRCH;
int tmpio;
- read_lock_irq(&tasklist_lock);
+ read_lock(&tasklist_lock);
switch (which) {
case IOPRIO_WHO_PROCESS:
if (!who)
@@ -221,7 +221,7 @@ asmlinkage long sys_ioprio_get(int which, int who)
ret = -EINVAL;
}
- read_unlock_irq(&tasklist_lock);
+ read_unlock(&tasklist_lock);
return ret;
}
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 14391361c886..c34b862cdbf2 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -96,9 +96,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(isofs_inode_cachep))
- printk(KERN_INFO "iso_inode_cache: not all structures were "
- "freed\n");
+ kmem_cache_destroy(isofs_inode_cachep);
}
static int isofs_remount(struct super_block *sb, int *flags, char *data)
@@ -557,11 +555,10 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent)
struct iso9660_options opt;
struct isofs_sb_info * sbi;
- sbi = kmalloc(sizeof(*sbi), GFP_KERNEL);
+ sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
s->s_fs_info = sbi;
- memset(sbi, 0, sizeof(*sbi));
if (!parse_options((char *)data, &opt))
goto out_freesbi;
@@ -963,30 +960,30 @@ int isofs_get_blocks(struct inode *inode, sector_t iblock_s,
goto abort;
}
- if (nextblk) {
- while (b_off >= (offset + sect_size)) {
- struct inode *ninode;
-
- offset += sect_size;
- if (nextblk == 0)
- goto abort;
- ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
- if (!ninode)
- goto abort;
- firstext = ISOFS_I(ninode)->i_first_extent;
- sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
- nextblk = ISOFS_I(ninode)->i_next_section_block;
- nextoff = ISOFS_I(ninode)->i_next_section_offset;
- iput(ninode);
-
- if (++section > 100) {
- printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
- printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
- "nextblk=%lu nextoff=%lu\n",
- iblock, firstext, (unsigned) sect_size,
- nextblk, nextoff);
- goto abort;
- }
+ /* On the last section, nextblk == 0, section size is likely to
+ * exceed sect_size by a partial block, and access beyond the
+ * end of the file will reach beyond the section size, too.
+ */
+ while (nextblk && (b_off >= (offset + sect_size))) {
+ struct inode *ninode;
+
+ offset += sect_size;
+ ninode = isofs_iget(inode->i_sb, nextblk, nextoff);
+ if (!ninode)
+ goto abort;
+ firstext = ISOFS_I(ninode)->i_first_extent;
+ sect_size = ISOFS_I(ninode)->i_section_size >> ISOFS_BUFFER_BITS(ninode);
+ nextblk = ISOFS_I(ninode)->i_next_section_block;
+ nextoff = ISOFS_I(ninode)->i_next_section_offset;
+ iput(ninode);
+
+ if (++section > 100) {
+ printk("isofs_get_blocks: More than 100 file sections ?!?, aborting...\n");
+ printk("isofs_get_blocks: block=%ld firstext=%u sect_size=%u "
+ "nextblk=%lu nextoff=%lu\n",
+ iblock, firstext, (unsigned) sect_size,
+ nextblk, nextoff);
+ goto abort;
}
}
@@ -1238,7 +1235,7 @@ static void isofs_read_inode(struct inode *inode)
}
inode->i_uid = sbi->s_uid;
inode->i_gid = sbi->s_gid;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
ei->i_format_parm[0] = 0;
ei->i_format_parm[1] = 0;
@@ -1294,7 +1291,6 @@ static void isofs_read_inode(struct inode *inode)
isonum_711 (de->ext_attr_length));
/* Set the number of blocks for stat() - should be done before RR */
- inode->i_blksize = PAGE_CACHE_SIZE; /* For stat() only */
inode->i_blocks = (inode->i_size + 511) >> 9;
/*
diff --git a/fs/isofs/joliet.c b/fs/isofs/joliet.c
index 81a90e170ac3..fb8fe7a9ddc6 100644
--- a/fs/isofs/joliet.c
+++ b/fs/isofs/joliet.c
@@ -14,9 +14,9 @@
* Convert Unicode 16 to UTF-8 or ASCII.
*/
static int
-uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls)
+uni16_to_x8(unsigned char *ascii, __be16 *uni, int len, struct nls_table *nls)
{
- wchar_t *ip, ch;
+ __be16 *ip, ch;
unsigned char *op;
ip = uni;
@@ -24,8 +24,8 @@ uni16_to_x8(unsigned char *ascii, u16 *uni, int len, struct nls_table *nls)
while ((ch = get_unaligned(ip)) && len) {
int llen;
- ch = be16_to_cpu(ch);
- if ((llen = nls->uni2char(ch, op, NLS_MAX_CHARSET_SIZE)) > 0)
+ llen = nls->uni2char(be16_to_cpu(ch), op, NLS_MAX_CHARSET_SIZE);
+ if (llen > 0)
op += llen;
else
*op++ = '?';
@@ -82,7 +82,7 @@ get_joliet_filename(struct iso_directory_record * de, unsigned char *outname, st
len = wcsntombs_be(outname, de->name,
de->name_len[0] >> 1, PAGE_SIZE);
} else {
- len = uni16_to_x8(outname, (u16 *) de->name,
+ len = uni16_to_x8(outname, (__be16 *) de->name,
de->name_len[0] >> 1, nls);
}
if ((len > 2) && (outname[len-2] == ';') && (outname[len-1] == '1')) {
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index e7ba0c30e071..c04b3a14a3e9 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -6,7 +6,6 @@
* (C) 1991 Linus Torvalds - minix filesystem
*/
-#include <linux/config.h> /* Joliet? */
#include <linux/smp_lock.h>
#include "isofs.h"
diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c
index 47678a26c13b..0208cc7ac5d0 100644
--- a/fs/jbd/checkpoint.c
+++ b/fs/jbd/checkpoint.c
@@ -1,6 +1,6 @@
/*
* linux/fs/checkpoint.c
- *
+ *
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
*
* Copyright 1999 Red Hat Software --- All Rights Reserved
@@ -9,8 +9,8 @@
* the terms of the GNU General Public License, version 2, or at your
* option, any later version, incorporated herein by reference.
*
- * Checkpoint routines for the generic filesystem journaling code.
- * Part of the ext2fs journaling system.
+ * Checkpoint routines for the generic filesystem journaling code.
+ * Part of the ext2fs journaling system.
*
* Checkpointing is the process of ensuring that a section of the log is
* committed fully to disk, so that that portion of the log can be
@@ -145,6 +145,7 @@ void __log_wait_for_space(journal_t *journal)
* jbd_unlock_bh_state().
*/
static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
+ __releases(journal->j_list_lock)
{
get_bh(bh);
spin_unlock(&journal->j_list_lock);
@@ -225,7 +226,7 @@ __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
* Try to flush one buffer from the checkpoint list to disk.
*
* Return 1 if something happened which requires us to abort the current
- * scan of the checkpoint list.
+ * scan of the checkpoint list.
*
* Called with j_list_lock held and drops it if 1 is returned
* Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
@@ -269,7 +270,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
* possibly block, while still holding the journal lock.
* We cannot afford to let the transaction logic start
* messing around with this buffer before we write it to
- * disk, as that would break recoverability.
+ * disk, as that would break recoverability.
*/
BUFFER_TRACE(bh, "queue");
get_bh(bh);
@@ -292,7 +293,7 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
* Perform an actual checkpoint. We take the first transaction on the
* list of transactions to be checkpointed and send all its buffers
* to disk. We submit larger chunks of data at once.
- *
+ *
* The journal should be locked before calling this function.
*/
int log_do_checkpoint(journal_t *journal)
@@ -303,10 +304,10 @@ int log_do_checkpoint(journal_t *journal)
jbd_debug(1, "Start checkpoint\n");
- /*
+ /*
* First thing: if there are any transactions in the log which
* don't need checkpointing, just eliminate them from the
- * journal straight away.
+ * journal straight away.
*/
result = cleanup_journal_tail(journal);
jbd_debug(1, "cleanup_journal_tail returned %d\n", result);
@@ -384,9 +385,9 @@ out:
* we have already got rid of any since the last update of the log tail
* in the journal superblock. If so, we can instantly roll the
* superblock forward to remove those transactions from the log.
- *
+ *
* Return <0 on error, 0 on success, 1 if there was nothing to clean up.
- *
+ *
* Called with the journal lock held.
*
* This is the only part of the journaling code which really needs to be
@@ -403,8 +404,8 @@ int cleanup_journal_tail(journal_t *journal)
unsigned long blocknr, freed;
/* OK, work out the oldest transaction remaining in the log, and
- * the log block it starts at.
- *
+ * the log block it starts at.
+ *
* If the log is now empty, we need to work out which is the
* next transaction ID we will write, and where it will
* start. */
@@ -479,7 +480,7 @@ static int journal_clean_one_cp_list(struct journal_head *jh, int *released)
if (!jh)
return 0;
- last_jh = jh->b_cpprev;
+ last_jh = jh->b_cpprev;
do {
jh = next_jh;
next_jh = jh->b_cpnext;
@@ -557,7 +558,7 @@ out:
return ret;
}
-/*
+/*
* journal_remove_checkpoint: called after a buffer has been committed
* to disk (either by being write-back flushed to disk, or being
* committed to the log).
@@ -635,7 +636,7 @@ out:
* Called with the journal locked.
* Called with j_list_lock held.
*/
-void __journal_insert_checkpoint(struct journal_head *jh,
+void __journal_insert_checkpoint(struct journal_head *jh,
transaction_t *transaction)
{
JBUFFER_TRACE(jh, "entry");
@@ -657,7 +658,7 @@ void __journal_insert_checkpoint(struct journal_head *jh,
/*
* We've finished with this transaction structure: adios...
- *
+ *
* The transaction must have no links except for the checkpoint by this
* point.
*
diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c
index 32a8caf0c41e..10be51290a27 100644
--- a/fs/jbd/commit.c
+++ b/fs/jbd/commit.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/commit.c
+ * linux/fs/jbd/commit.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1998
*
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index f66724ce443a..b85c686b60db 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/journal.c
+ * linux/fs/jbd/journal.c
*
* Written by Stephen C. Tweedie <sct@redhat.com>, 1998
*
@@ -181,7 +181,7 @@ loop:
transaction->t_expires))
should_sleep = 0;
if (journal->j_flags & JFS_UNMOUNT)
- should_sleep = 0;
+ should_sleep = 0;
if (should_sleep) {
spin_unlock(&journal->j_state_lock);
schedule();
@@ -271,7 +271,7 @@ static void journal_kill_thread(journal_t *journal)
int journal_write_metadata_buffer(transaction_t *transaction,
struct journal_head *jh_in,
struct journal_head **jh_out,
- int blocknr)
+ unsigned long blocknr)
{
int need_copy_out = 0;
int done_copy_out = 0;
@@ -578,7 +578,7 @@ int journal_next_log_block(journal_t *journal, unsigned long *retp)
* this is a no-op. If needed, we can use j_blk_offset - everything is
* ready.
*/
-int journal_bmap(journal_t *journal, unsigned long blocknr,
+int journal_bmap(journal_t *journal, unsigned long blocknr,
unsigned long *retp)
{
int err = 0;
@@ -696,13 +696,13 @@ fail:
* @bdev: Block device on which to create the journal
* @fs_dev: Device which hold journalled filesystem for this journal.
* @start: Block nr Start of journal.
- * @len: Lenght of the journal in blocks.
+ * @len: Length of the journal in blocks.
* @blocksize: blocksize of journalling device
* @returns: a newly created journal_t *
- *
+ *
* journal_init_dev creates a journal which maps a fixed contiguous
* range of blocks on an arbitrary block device.
- *
+ *
*/
journal_t * journal_init_dev(struct block_device *bdev,
struct block_device *fs_dev,
@@ -715,18 +715,8 @@ journal_t * journal_init_dev(struct block_device *bdev,
if (!journal)
return NULL;
- journal->j_dev = bdev;
- journal->j_fs_dev = fs_dev;
- journal->j_blk_offset = start;
- journal->j_maxlen = len;
- journal->j_blocksize = blocksize;
-
- bh = __getblk(journal->j_dev, start, journal->j_blocksize);
- J_ASSERT(bh != NULL);
- journal->j_sb_buffer = bh;
- journal->j_superblock = (journal_superblock_t *)bh->b_data;
-
/* journal descriptor can store up to n blocks -bzzz */
+ journal->j_blocksize = blocksize;
n = journal->j_blocksize / sizeof(journal_block_tag_t);
journal->j_wbufsize = n;
journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
@@ -735,15 +725,25 @@ journal_t * journal_init_dev(struct block_device *bdev,
__FUNCTION__);
kfree(journal);
journal = NULL;
+ goto out;
}
+ journal->j_dev = bdev;
+ journal->j_fs_dev = fs_dev;
+ journal->j_blk_offset = start;
+ journal->j_maxlen = len;
+ bh = __getblk(journal->j_dev, start, journal->j_blocksize);
+ J_ASSERT(bh != NULL);
+ journal->j_sb_buffer = bh;
+ journal->j_superblock = (journal_superblock_t *)bh->b_data;
+out:
return journal;
}
-
-/**
+
+/**
* journal_t * journal_init_inode () - creates a journal which maps to a inode.
* @inode: An inode to create the journal in
- *
+ *
* journal_init_inode creates a journal which maps an on-disk inode as
* the journal. The inode must exist already, must support bmap() and
* must have all data blocks preallocated.
@@ -763,7 +763,7 @@ journal_t * journal_init_inode (struct inode *inode)
journal->j_inode = inode;
jbd_debug(1,
"journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
- journal, inode->i_sb->s_id, inode->i_ino,
+ journal, inode->i_sb->s_id, inode->i_ino,
(long long) inode->i_size,
inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
@@ -798,10 +798,10 @@ journal_t * journal_init_inode (struct inode *inode)
return journal;
}
-/*
+/*
* If the journal init or create aborts, we need to mark the journal
* superblock as being NULL to prevent the journal destroy from writing
- * back a bogus superblock.
+ * back a bogus superblock.
*/
static void journal_fail_superblock (journal_t *journal)
{
@@ -820,7 +820,7 @@ static void journal_fail_superblock (journal_t *journal)
static int journal_reset(journal_t *journal)
{
journal_superblock_t *sb = journal->j_superblock;
- unsigned int first, last;
+ unsigned long first, last;
first = be32_to_cpu(sb->s_first);
last = be32_to_cpu(sb->s_maxlen);
@@ -844,13 +844,13 @@ static int journal_reset(journal_t *journal)
return 0;
}
-/**
+/**
* int journal_create() - Initialise the new journal file
* @journal: Journal to create. This structure must have been initialised
- *
+ *
* Given a journal_t structure which tells us which disk blocks we can
* use, create a new journal superblock and initialise all of the
- * journal fields from scratch.
+ * journal fields from scratch.
**/
int journal_create(journal_t *journal)
{
@@ -915,7 +915,7 @@ int journal_create(journal_t *journal)
return journal_reset(journal);
}
-/**
+/**
* void journal_update_superblock() - Update journal sb on disk.
* @journal: The journal to update.
* @wait: Set to '0' if you don't want to wait for IO completion.
@@ -939,7 +939,7 @@ void journal_update_superblock(journal_t *journal, int wait)
journal->j_transaction_sequence) {
jbd_debug(1,"JBD: Skipping superblock update on recovered sb "
"(start %ld, seq %d, errno %d)\n",
- journal->j_tail, journal->j_tail_sequence,
+ journal->j_tail, journal->j_tail_sequence,
journal->j_errno);
goto out;
}
@@ -1062,7 +1062,7 @@ static int load_superblock(journal_t *journal)
/**
* int journal_load() - Read journal from disk.
* @journal: Journal to act on.
- *
+ *
* Given a journal_t structure which tells us which disk blocks contain
* a journal, read the journal from disk to initialise the in-memory
* structures.
@@ -1094,7 +1094,7 @@ int journal_load(journal_t *journal)
/*
* Create a slab for this blocksize
*/
- err = journal_create_jbd_slab(cpu_to_be32(sb->s_blocksize));
+ err = journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize));
if (err)
return err;
@@ -1172,9 +1172,9 @@ void journal_destroy(journal_t *journal)
* @compat: bitmask of compatible features
* @ro: bitmask of features that force read-only mount
* @incompat: bitmask of incompatible features
- *
+ *
* Check whether the journal uses all of a given set of
- * features. Return true (non-zero) if it does.
+ * features. Return true (non-zero) if it does.
**/
int journal_check_used_features (journal_t *journal, unsigned long compat,
@@ -1203,7 +1203,7 @@ int journal_check_used_features (journal_t *journal, unsigned long compat,
* @compat: bitmask of compatible features
* @ro: bitmask of features that force read-only mount
* @incompat: bitmask of incompatible features
- *
+ *
* Check whether the journaling code supports the use of
* all of a given set of features on this journal. Return true
* (non-zero) if it can. */
@@ -1241,7 +1241,7 @@ int journal_check_available_features (journal_t *journal, unsigned long compat,
* @incompat: bitmask of incompatible features
*
* Mark a given journal feature as present on the
- * superblock. Returns true if the requested features could be set.
+ * superblock. Returns true if the requested features could be set.
*
*/
@@ -1327,7 +1327,7 @@ static int journal_convert_superblock_v1(journal_t *journal,
/**
* int journal_flush () - Flush journal
* @journal: Journal to act on.
- *
+ *
* Flush all data for a given journal to disk and empty the journal.
* Filesystems can use this when remounting readonly to ensure that
* recovery does not need to happen on remount.
@@ -1394,7 +1394,7 @@ int journal_flush(journal_t *journal)
* int journal_wipe() - Wipe journal contents
* @journal: Journal to act on.
* @write: flag (see below)
- *
+ *
* Wipe out all of the contents of a journal, safely. This will produce
* a warning if the journal contains any valid recovery information.
* Must be called between journal_init_*() and journal_load().
@@ -1449,7 +1449,7 @@ static const char *journal_dev_name(journal_t *journal, char *buffer)
/*
* Journal abort has very specific semantics, which we describe
- * for journal abort.
+ * for journal abort.
*
* Two internal function, which provide abort to te jbd layer
* itself are here.
@@ -1504,7 +1504,7 @@ static void __journal_abort_soft (journal_t *journal, int errno)
* Perform a complete, immediate shutdown of the ENTIRE
* journal (not of a single transaction). This operation cannot be
* undone without closing and reopening the journal.
- *
+ *
* The journal_abort function is intended to support higher level error
* recovery mechanisms such as the ext2/ext3 remount-readonly error
* mode.
@@ -1538,7 +1538,7 @@ static void __journal_abort_soft (journal_t *journal, int errno)
* supply an errno; a null errno implies that absolutely no further
* writes are done to the journal (unless there are any already in
* progress).
- *
+ *
*/
void journal_abort(journal_t *journal, int errno)
@@ -1546,7 +1546,7 @@ void journal_abort(journal_t *journal, int errno)
__journal_abort_soft(journal, errno);
}
-/**
+/**
* int journal_errno () - returns the journal's error state.
* @journal: journal to examine.
*
@@ -1570,7 +1570,7 @@ int journal_errno(journal_t *journal)
return err;
}
-/**
+/**
* int journal_clear_err () - clears the journal's error state
* @journal: journal to act on.
*
@@ -1590,7 +1590,7 @@ int journal_clear_err(journal_t *journal)
return err;
}
-/**
+/**
* void journal_ack_err() - Ack journal err.
* @journal: journal to act on.
*
@@ -1612,7 +1612,7 @@ int journal_blocks_per_page(struct inode *inode)
/*
* Simple support for retrying memory allocations. Introduced to help to
- * debug different VM deadlock avoidance strategies.
+ * debug different VM deadlock avoidance strategies.
*/
void * __jbd_kmalloc (const char *where, size_t size, gfp_t flags, int retry)
{
@@ -2047,13 +2047,7 @@ static int __init journal_init(void)
{
int ret;
-/* Static check for data structure consistency. There's no code
- * invoked --- we'll just get a linker failure if things aren't right.
- */
- extern void journal_bad_superblock_size(void);
- if (sizeof(struct journal_superblock_s) != 1024)
- journal_bad_superblock_size();
-
+ BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024);
ret = journal_init_caches();
if (ret != 0)
diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c
index de5bafb4e853..11563fe2a52b 100644
--- a/fs/jbd/recovery.c
+++ b/fs/jbd/recovery.c
@@ -1,6 +1,6 @@
/*
* linux/fs/recovery.c
- *
+ *
* Written by Stephen C. Tweedie <sct@redhat.com>, 1999
*
* Copyright 1999-2000 Red Hat Software --- All Rights Reserved
@@ -10,7 +10,7 @@
* option, any later version, incorporated herein by reference.
*
* Journal recovery routines for the generic filesystem journaling code;
- * part of the ext2fs journaling system.
+ * part of the ext2fs journaling system.
*/
#ifndef __KERNEL__
@@ -25,9 +25,9 @@
/*
* Maintain information about the progress of the recovery job, so that
- * the different passes can carry information between them.
+ * the different passes can carry information between them.
*/
-struct recovery_info
+struct recovery_info
{
tid_t start_transaction;
tid_t end_transaction;
@@ -46,7 +46,7 @@ static int scan_revoke_records(journal_t *, struct buffer_head *,
#ifdef __KERNEL__
/* Release readahead buffers after use */
-void journal_brelse_array(struct buffer_head *b[], int n)
+static void journal_brelse_array(struct buffer_head *b[], int n)
{
while (--n >= 0)
brelse (b[n]);
@@ -116,7 +116,7 @@ static int do_readahead(journal_t *journal, unsigned int start)
err = 0;
failed:
- if (nbufs)
+ if (nbufs)
journal_brelse_array(bufs, nbufs);
return err;
}
@@ -128,7 +128,7 @@ failed:
* Read a block from the journal
*/
-static int jread(struct buffer_head **bhp, journal_t *journal,
+static int jread(struct buffer_head **bhp, journal_t *journal,
unsigned int offset)
{
int err;
@@ -212,14 +212,14 @@ do { \
/**
* journal_recover - recovers a on-disk journal
* @journal: the journal to recover
- *
+ *
* The primary function for recovering the log contents when mounting a
- * journaled device.
+ * journaled device.
*
* Recovery is done in three passes. In the first pass, we look for the
* end of the log. In the second, we assemble the list of revoke
* blocks. In the third and final pass, we replay any un-revoked blocks
- * in the log.
+ * in the log.
*/
int journal_recover(journal_t *journal)
{
@@ -231,10 +231,10 @@ int journal_recover(journal_t *journal)
memset(&info, 0, sizeof(info));
sb = journal->j_superblock;
- /*
+ /*
* The journal superblock's s_start field (the current log head)
* is always zero if, and only if, the journal was cleanly
- * unmounted.
+ * unmounted.
*/
if (!sb->s_start) {
@@ -253,7 +253,7 @@ int journal_recover(journal_t *journal)
jbd_debug(0, "JBD: recovery, exit status %d, "
"recovered transactions %u to %u\n",
err, info.start_transaction, info.end_transaction);
- jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
+ jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
/* Restart the log at the next transaction ID, thus invalidating
@@ -268,15 +268,15 @@ int journal_recover(journal_t *journal)
/**
* journal_skip_recovery - Start journal and wipe exiting records
* @journal: journal to startup
- *
+ *
* Locate any valid recovery information from the journal and set up the
* journal structures in memory to ignore it (presumably because the
- * caller has evidence that it is out of date).
+ * caller has evidence that it is out of date).
* This function does'nt appear to be exorted..
*
* We perform one pass over the journal to allow us to tell the user how
* much recovery information is being erased, and to let us initialise
- * the journal transaction sequence numbers to the next unused ID.
+ * the journal transaction sequence numbers to the next unused ID.
*/
int journal_skip_recovery(journal_t *journal)
{
@@ -297,7 +297,7 @@ int journal_skip_recovery(journal_t *journal)
#ifdef CONFIG_JBD_DEBUG
int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
#endif
- jbd_debug(0,
+ jbd_debug(0,
"JBD: ignoring %d transaction%s from the journal.\n",
dropped, (dropped == 1) ? "" : "s");
journal->j_transaction_sequence = ++info.end_transaction;
@@ -314,7 +314,7 @@ static int do_one_pass(journal_t *journal,
unsigned long next_log_block;
int err, success = 0;
journal_superblock_t * sb;
- journal_header_t * tmp;
+ journal_header_t * tmp;
struct buffer_head * bh;
unsigned int sequence;
int blocktype;
@@ -324,10 +324,10 @@ static int do_one_pass(journal_t *journal,
MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
/ sizeof(journal_block_tag_t));
- /*
+ /*
* First thing is to establish what we expect to find in the log
* (in terms of transaction IDs), and where (in terms of log
- * block offsets): query the superblock.
+ * block offsets): query the superblock.
*/
sb = journal->j_superblock;
@@ -344,7 +344,7 @@ static int do_one_pass(journal_t *journal,
* Now we walk through the log, transaction by transaction,
* making sure that each transaction has a commit block in the
* expected place. Each complete transaction gets replayed back
- * into the main filesystem.
+ * into the main filesystem.
*/
while (1) {
@@ -379,8 +379,8 @@ static int do_one_pass(journal_t *journal,
next_log_block++;
wrap(journal, next_log_block);
- /* What kind of buffer is it?
- *
+ /* What kind of buffer is it?
+ *
* If it is a descriptor block, check that it has the
* expected sequence number. Otherwise, we're all done
* here. */
@@ -394,7 +394,7 @@ static int do_one_pass(journal_t *journal,
blocktype = be32_to_cpu(tmp->h_blocktype);
sequence = be32_to_cpu(tmp->h_sequence);
- jbd_debug(3, "Found magic %d, sequence %d\n",
+ jbd_debug(3, "Found magic %d, sequence %d\n",
blocktype, sequence);
if (sequence != next_commit_ID) {
@@ -438,7 +438,7 @@ static int do_one_pass(journal_t *journal,
/* Recover what we can, but
* report failure at the end. */
success = err;
- printk (KERN_ERR
+ printk (KERN_ERR
"JBD: IO error %d recovering "
"block %ld in log\n",
err, io_block);
@@ -452,7 +452,7 @@ static int do_one_pass(journal_t *journal,
* revoked, then we're all done
* here. */
if (journal_test_revoke
- (journal, blocknr,
+ (journal, blocknr,
next_commit_ID)) {
brelse(obh);
++info->nr_revoke_hits;
@@ -465,7 +465,7 @@ static int do_one_pass(journal_t *journal,
blocknr,
journal->j_blocksize);
if (nbh == NULL) {
- printk(KERN_ERR
+ printk(KERN_ERR
"JBD: Out of memory "
"during recovery.\n");
err = -ENOMEM;
@@ -537,7 +537,7 @@ static int do_one_pass(journal_t *journal,
}
done:
- /*
+ /*
* We broke out of the log scan loop: either we came to the
* known end of the log or we found an unexpected block in the
* log. If the latter happened, then we know that the "current"
@@ -567,7 +567,7 @@ static int do_one_pass(journal_t *journal,
/* Scan a revoke record, marking all blocks mentioned as revoked. */
-static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
+static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
tid_t sequence, struct recovery_info *info)
{
journal_revoke_header_t *header;
diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c
index a56144183462..c532429d8d9b 100644
--- a/fs/jbd/revoke.c
+++ b/fs/jbd/revoke.c
@@ -1,6 +1,6 @@
/*
* linux/fs/revoke.c
- *
+ *
* Written by Stephen C. Tweedie <sct@redhat.com>, 2000
*
* Copyright 2000 Red Hat corp --- All Rights Reserved
@@ -15,10 +15,10 @@
* Revoke is the mechanism used to prevent old log records for deleted
* metadata from being replayed on top of newer data using the same
* blocks. The revoke mechanism is used in two separate places:
- *
+ *
* + Commit: during commit we write the entire list of the current
* transaction's revoked blocks to the journal
- *
+ *
* + Recovery: during recovery we record the transaction ID of all
* revoked blocks. If there are multiple revoke records in the log
* for a single block, only the last one counts, and if there is a log
@@ -29,7 +29,7 @@
* single transaction:
*
* Block is revoked and then journaled:
- * The desired end result is the journaling of the new block, so we
+ * The desired end result is the journaling of the new block, so we
* cancel the revoke before the transaction commits.
*
* Block is journaled and then revoked:
@@ -41,7 +41,7 @@
* transaction must have happened after the block was journaled and so
* the revoke must take precedence.
*
- * Block is revoked and then written as data:
+ * Block is revoked and then written as data:
* The data write is allowed to succeed, but the revoke is _not_
* cancelled. We still need to prevent old log records from
* overwriting the new data. We don't even need to clear the revoke
@@ -54,7 +54,7 @@
* buffer has not been revoked, and cancel_revoke
* need do nothing.
* RevokeValid set, Revoked set:
- * buffer has been revoked.
+ * buffer has been revoked.
*/
#ifndef __KERNEL__
@@ -77,7 +77,7 @@ static kmem_cache_t *revoke_table_cache;
journal replay, this involves recording the transaction ID of the
last transaction to revoke this block. */
-struct jbd_revoke_record_s
+struct jbd_revoke_record_s
{
struct list_head hash;
tid_t sequence; /* Used for recovery only */
@@ -90,8 +90,8 @@ struct jbd_revoke_table_s
{
/* It is conceivable that we might want a larger hash table
* for recovery. Must be a power of two. */
- int hash_size;
- int hash_shift;
+ int hash_size;
+ int hash_shift;
struct list_head *hash_table;
};
@@ -301,22 +301,22 @@ void journal_destroy_revoke(journal_t *journal)
#ifdef __KERNEL__
-/*
+/*
* journal_revoke: revoke a given buffer_head from the journal. This
* prevents the block from being replayed during recovery if we take a
* crash after this current transaction commits. Any subsequent
* metadata writes of the buffer in this transaction cancel the
- * revoke.
+ * revoke.
*
* Note that this call may block --- it is up to the caller to make
* sure that there are no further calls to journal_write_metadata
* before the revoke is complete. In ext3, this implies calling the
* revoke before clearing the block bitmap when we are deleting
- * metadata.
+ * metadata.
*
* Revoke performs a journal_forget on any buffer_head passed in as a
* parameter, but does _not_ forget the buffer_head if the bh was only
- * found implicitly.
+ * found implicitly.
*
* bh_in may not be a journalled buffer - it may have come off
* the hash tables without an attached journal_head.
@@ -325,7 +325,7 @@ void journal_destroy_revoke(journal_t *journal)
* by one.
*/
-int journal_revoke(handle_t *handle, unsigned long blocknr,
+int journal_revoke(handle_t *handle, unsigned long blocknr,
struct buffer_head *bh_in)
{
struct buffer_head *bh = NULL;
@@ -487,7 +487,7 @@ void journal_switch_revoke_table(journal_t *journal)
else
journal->j_revoke = journal->j_revoke_table[0];
- for (i = 0; i < journal->j_revoke->hash_size; i++)
+ for (i = 0; i < journal->j_revoke->hash_size; i++)
INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
}
@@ -498,7 +498,7 @@ void journal_switch_revoke_table(journal_t *journal)
* Called with the journal lock held.
*/
-void journal_write_revoke_records(journal_t *journal,
+void journal_write_revoke_records(journal_t *journal,
transaction_t *transaction)
{
struct journal_head *descriptor;
@@ -507,7 +507,7 @@ void journal_write_revoke_records(journal_t *journal,
struct list_head *hash_list;
int i, offset, count;
- descriptor = NULL;
+ descriptor = NULL;
offset = 0;
count = 0;
@@ -519,10 +519,10 @@ void journal_write_revoke_records(journal_t *journal,
hash_list = &revoke->hash_table[i];
while (!list_empty(hash_list)) {
- record = (struct jbd_revoke_record_s *)
+ record = (struct jbd_revoke_record_s *)
hash_list->next;
write_one_revoke_record(journal, transaction,
- &descriptor, &offset,
+ &descriptor, &offset,
record);
count++;
list_del(&record->hash);
@@ -534,14 +534,14 @@ void journal_write_revoke_records(journal_t *journal,
jbd_debug(1, "Wrote %d revoke records\n", count);
}
-/*
+/*
* Write out one revoke record. We need to create a new descriptor
- * block if the old one is full or if we have not already created one.
+ * block if the old one is full or if we have not already created one.
*/
-static void write_one_revoke_record(journal_t *journal,
+static void write_one_revoke_record(journal_t *journal,
transaction_t *transaction,
- struct journal_head **descriptorp,
+ struct journal_head **descriptorp,
int *offsetp,
struct jbd_revoke_record_s *record)
{
@@ -584,21 +584,21 @@ static void write_one_revoke_record(journal_t *journal,
*descriptorp = descriptor;
}
- * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
+ * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
cpu_to_be32(record->blocknr);
offset += 4;
*offsetp = offset;
}
-/*
+/*
* Flush a revoke descriptor out to the journal. If we are aborting,
* this is a noop; otherwise we are generating a buffer which needs to
* be waited for during commit, so it has to go onto the appropriate
* journal buffer list.
*/
-static void flush_descriptor(journal_t *journal,
- struct journal_head *descriptor,
+static void flush_descriptor(journal_t *journal,
+ struct journal_head *descriptor,
int offset)
{
journal_revoke_header_t *header;
@@ -618,7 +618,7 @@ static void flush_descriptor(journal_t *journal,
}
#endif
-/*
+/*
* Revoke support for recovery.
*
* Recovery needs to be able to:
@@ -629,7 +629,7 @@ static void flush_descriptor(journal_t *journal,
* check whether a given block in a given transaction should be replayed
* (ie. has not been revoked by a revoke record in that or a subsequent
* transaction)
- *
+ *
* empty the revoke table after recovery.
*/
@@ -637,11 +637,11 @@ static void flush_descriptor(journal_t *journal,
* First, setting revoke records. We create a new revoke record for
* every block ever revoked in the log as we scan it for recovery, and
* we update the existing records if we find multiple revokes for a
- * single block.
+ * single block.
*/
-int journal_set_revoke(journal_t *journal,
- unsigned long blocknr,
+int journal_set_revoke(journal_t *journal,
+ unsigned long blocknr,
tid_t sequence)
{
struct jbd_revoke_record_s *record;
@@ -653,18 +653,18 @@ int journal_set_revoke(journal_t *journal,
if (tid_gt(sequence, record->sequence))
record->sequence = sequence;
return 0;
- }
+ }
return insert_revoke_hash(journal, blocknr, sequence);
}
-/*
+/*
* Test revoke records. For a given block referenced in the log, has
* that block been revoked? A revoke record with a given transaction
* sequence number revokes all blocks in that transaction and earlier
* ones, but later transactions still need replayed.
*/
-int journal_test_revoke(journal_t *journal,
+int journal_test_revoke(journal_t *journal,
unsigned long blocknr,
tid_t sequence)
{
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index f5169a96260e..d5c63047a8b3 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1,6 +1,6 @@
/*
* linux/fs/transaction.c
- *
+ *
* Written by Stephen C. Tweedie <sct@redhat.com>, 1998
*
* Copyright 1998 Red Hat corp --- All Rights Reserved
@@ -10,7 +10,7 @@
* option, any later version, incorporated herein by reference.
*
* Generic filesystem transaction handling code; part of the ext2fs
- * journaling system.
+ * journaling system.
*
* This file manages transactions (compound commits managed by the
* journaling code) and handles (individual atomic operations by the
@@ -74,7 +74,7 @@ get_transaction(journal_t *journal, transaction_t *transaction)
* start_this_handle: Given a handle, deal with any locking or stalling
* needed to make sure that there is enough journal space for the handle
* to begin. Attach the handle to a transaction and set up the
- * transaction's buffer credits.
+ * transaction's buffer credits.
*/
static int start_this_handle(journal_t *journal, handle_t *handle)
@@ -117,7 +117,7 @@ repeat_locked:
if (is_journal_aborted(journal) ||
(journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) {
spin_unlock(&journal->j_state_lock);
- ret = -EROFS;
+ ret = -EROFS;
goto out;
}
@@ -182,7 +182,7 @@ repeat_locked:
goto repeat;
}
- /*
+ /*
* The commit code assumes that it can get enough log space
* without forcing a checkpoint. This is *critical* for
* correctness: a checkpoint of a buffer which is also
@@ -191,7 +191,7 @@ repeat_locked:
*
* We must therefore ensure the necessary space in the journal
* *before* starting to dirty potentially checkpointed buffers
- * in the new transaction.
+ * in the new transaction.
*
* The worst part is, any transaction currently committing can
* reduce the free space arbitrarily. Be careful to account for
@@ -246,13 +246,13 @@ static handle_t *new_handle(int nblocks)
}
/**
- * handle_t *journal_start() - Obtain a new handle.
+ * handle_t *journal_start() - Obtain a new handle.
* @journal: Journal to start transaction on.
* @nblocks: number of block buffer we might modify
*
* We make sure that the transaction can guarantee at least nblocks of
* modified buffers in the log. We block until the log can guarantee
- * that much space.
+ * that much space.
*
* This function is visible to journal users (like ext3fs), so is not
* called with the journal already locked.
@@ -292,11 +292,11 @@ handle_t *journal_start(journal_t *journal, int nblocks)
* int journal_extend() - extend buffer credits.
* @handle: handle to 'extend'
* @nblocks: nr blocks to try to extend by.
- *
+ *
* Some transactions, such as large extends and truncates, can be done
* atomically all at once or in several stages. The operation requests
* a credit for a number of buffer modications in advance, but can
- * extend its credit if it needs more.
+ * extend its credit if it needs more.
*
* journal_extend tries to give the running handle more buffer credits.
* It does not guarantee that allocation - this is a best-effort only.
@@ -363,7 +363,7 @@ out:
* int journal_restart() - restart a handle .
* @handle: handle to restart
* @nblocks: nr credits requested
- *
+ *
* Restart a handle for a multi-transaction filesystem
* operation.
*
@@ -462,7 +462,7 @@ void journal_lock_updates(journal_t *journal)
/**
* void journal_unlock_updates (journal_t* journal) - release barrier
* @journal: Journal to release the barrier on.
- *
+ *
* Release a transaction barrier obtained with journal_lock_updates().
*
* Should be called without the journal lock held.
@@ -547,8 +547,8 @@ repeat:
jbd_lock_bh_state(bh);
/* We now hold the buffer lock so it is safe to query the buffer
- * state. Is the buffer dirty?
- *
+ * state. Is the buffer dirty?
+ *
* If so, there are two possibilities. The buffer may be
* non-journaled, and undergoing a quite legitimate writeback.
* Otherwise, it is journaled, and we don't expect dirty buffers
@@ -566,7 +566,7 @@ repeat:
*/
if (jh->b_transaction) {
J_ASSERT_JH(jh,
- jh->b_transaction == transaction ||
+ jh->b_transaction == transaction ||
jh->b_transaction ==
journal->j_committing_transaction);
if (jh->b_next_transaction)
@@ -580,7 +580,7 @@ repeat:
*/
JBUFFER_TRACE(jh, "Unexpected dirty buffer");
jbd_unexpected_dirty_buffer(jh);
- }
+ }
unlock_buffer(bh);
@@ -653,7 +653,7 @@ repeat:
* buffer had better remain locked during the kmalloc,
* but that should be true --- we hold the journal lock
* still and the buffer is already on the BUF_JOURNAL
- * list so won't be flushed.
+ * list so won't be flushed.
*
* Subtle point, though: if this is a get_undo_access,
* then we will be relying on the frozen_data to contain
@@ -765,8 +765,8 @@ int journal_get_write_access(handle_t *handle, struct buffer_head *bh)
* manually rather than reading off disk), then we need to keep the
* buffer_head locked until it has been completely filled with new
* data. In this case, we should be able to make the assertion that
- * the bh is not already part of an existing transaction.
- *
+ * the bh is not already part of an existing transaction.
+ *
* The buffer should already be locked by the caller by this point.
* There is no lock ranking violation: it was a newly created,
* unlocked buffer beforehand. */
@@ -778,7 +778,7 @@ int journal_get_write_access(handle_t *handle, struct buffer_head *bh)
*
* Call this if you create a new bh.
*/
-int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
+int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
{
transaction_t *transaction = handle->h_transaction;
journal_t *journal = transaction->t_journal;
@@ -847,13 +847,13 @@ out:
* do not reuse freed space until the deallocation has been committed,
* since if we overwrote that space we would make the delete
* un-rewindable in case of a crash.
- *
+ *
* To deal with that, journal_get_undo_access requests write access to a
* buffer for parts of non-rewindable operations such as delete
* operations on the bitmaps. The journaling code must keep a copy of
* the buffer's contents prior to the undo_access call until such time
* as we know that the buffer has definitely been committed to disk.
- *
+ *
* We never need to know which transaction the committed data is part
* of, buffers touched here are guaranteed to be dirtied later and so
* will be committed to a new transaction in due course, at which point
@@ -911,13 +911,13 @@ out:
return err;
}
-/**
+/**
* int journal_dirty_data() - mark a buffer as containing dirty data which
* needs to be flushed before we can commit the
- * current transaction.
+ * current transaction.
* @handle: transaction
* @bh: bufferhead to mark
- *
+ *
* The buffer is placed on the transaction's data list and is marked as
* belonging to the transaction.
*
@@ -946,15 +946,15 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
/*
* What if the buffer is already part of a running transaction?
- *
+ *
* There are two cases:
* 1) It is part of the current running transaction. Refile it,
* just in case we have allocated it as metadata, deallocated
- * it, then reallocated it as data.
+ * it, then reallocated it as data.
* 2) It is part of the previous, still-committing transaction.
* If all we want to do is to guarantee that the buffer will be
* written to disk before this new transaction commits, then
- * being sure that the *previous* transaction has this same
+ * being sure that the *previous* transaction has this same
* property is sufficient for us! Just leave it on its old
* transaction.
*
@@ -1076,18 +1076,18 @@ no_journal:
return 0;
}
-/**
+/**
* int journal_dirty_metadata() - mark a buffer as containing dirty metadata
* @handle: transaction to add buffer to.
- * @bh: buffer to mark
- *
+ * @bh: buffer to mark
+ *
* mark dirty metadata which needs to be journaled as part of the current
* transaction.
*
* The buffer is placed on the transaction's metadata list and is marked
- * as belonging to the transaction.
+ * as belonging to the transaction.
*
- * Returns error number or 0 on success.
+ * Returns error number or 0 on success.
*
* Special care needs to be taken if the buffer already belongs to the
* current committing transaction (in which case we should have frozen
@@ -1135,11 +1135,11 @@ int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
set_buffer_jbddirty(bh);
- /*
+ /*
* Metadata already on the current transaction list doesn't
* need to be filed. Metadata on another transaction's list must
* be committing, and will be refiled once the commit completes:
- * leave it alone for now.
+ * leave it alone for now.
*/
if (jh->b_transaction != transaction) {
JBUFFER_TRACE(jh, "already on other transaction");
@@ -1165,7 +1165,7 @@ out:
return 0;
}
-/*
+/*
* journal_release_buffer: undo a get_write_access without any buffer
* updates, if the update decided in the end that it didn't need access.
*
@@ -1176,20 +1176,20 @@ journal_release_buffer(handle_t *handle, struct buffer_head *bh)
BUFFER_TRACE(bh, "entry");
}
-/**
+/**
* void journal_forget() - bforget() for potentially-journaled buffers.
* @handle: transaction handle
* @bh: bh to 'forget'
*
* We can only do the bforget if there are no commits pending against the
* buffer. If the buffer is dirty in the current running transaction we
- * can safely unlink it.
+ * can safely unlink it.
*
* bh may not be a journalled buffer at all - it may be a non-JBD
* buffer which came off the hashtable. Check for this.
*
* Decrements bh->b_count by one.
- *
+ *
* Allow this call even if the handle has aborted --- it may be part of
* the caller's cleanup after an abort.
*/
@@ -1237,7 +1237,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
drop_reserve = 1;
- /*
+ /*
* We are no longer going to journal this buffer.
* However, the commit of this transaction is still
* important to the buffer: the delete that we are now
@@ -1246,7 +1246,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
*
* So, if we have a checkpoint on the buffer, we should
* now refile the buffer on our BJ_Forget list so that
- * we know to remove the checkpoint after we commit.
+ * we know to remove the checkpoint after we commit.
*/
if (jh->b_cp_transaction) {
@@ -1264,7 +1264,7 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
}
}
} else if (jh->b_transaction) {
- J_ASSERT_JH(jh, (jh->b_transaction ==
+ J_ASSERT_JH(jh, (jh->b_transaction ==
journal->j_committing_transaction));
/* However, if the buffer is still owned by a prior
* (committing) transaction, we can't drop it yet... */
@@ -1294,7 +1294,7 @@ drop:
/**
* int journal_stop() - complete a transaction
* @handle: tranaction to complete.
- *
+ *
* All done for a particular handle.
*
* There is not much action needed here. We just return any remaining
@@ -1303,7 +1303,7 @@ drop:
* filesystem is marked for synchronous update.
*
* journal_stop itself will not usually return an error, but it may
- * do so in unusual circumstances. In particular, expect it to
+ * do so in unusual circumstances. In particular, expect it to
* return -EIO if a journal_abort has been executed since the
* transaction began.
*/
@@ -1314,13 +1314,14 @@ int journal_stop(handle_t *handle)
int old_handle_count, err;
pid_t pid;
- J_ASSERT(transaction->t_updates > 0);
J_ASSERT(journal_current_handle() == handle);
if (is_handle_aborted(handle))
err = -EIO;
- else
+ else {
+ J_ASSERT(transaction->t_updates > 0);
err = 0;
+ }
if (--handle->h_ref > 0) {
jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
@@ -1373,7 +1374,7 @@ int journal_stop(handle_t *handle)
if (handle->h_sync ||
transaction->t_outstanding_credits >
journal->j_max_transaction_buffers ||
- time_after_eq(jiffies, transaction->t_expires)) {
+ time_after_eq(jiffies, transaction->t_expires)) {
/* Do this even for aborted journals: an abort still
* completes the commit thread, it just doesn't write
* anything to disk. */
@@ -1388,7 +1389,7 @@ int journal_stop(handle_t *handle)
/*
* Special case: JFS_SYNC synchronous updates require us
- * to wait for the commit to complete.
+ * to wait for the commit to complete.
*/
if (handle->h_sync && !(current->flags & PF_MEMALLOC))
err = log_wait_commit(journal, tid);
@@ -1439,7 +1440,7 @@ int journal_force_commit(journal_t *journal)
* jbd_lock_bh_state(jh2bh(jh)) is held.
*/
-static inline void
+static inline void
__blist_add_buffer(struct journal_head **list, struct journal_head *jh)
{
if (!*list) {
@@ -1454,7 +1455,7 @@ __blist_add_buffer(struct journal_head **list, struct journal_head *jh)
}
}
-/*
+/*
* Remove a buffer from a transaction list, given the transaction's list
* head pointer.
*
@@ -1475,7 +1476,7 @@ __blist_del_buffer(struct journal_head **list, struct journal_head *jh)
jh->b_tnext->b_tprev = jh->b_tprev;
}
-/*
+/*
* Remove a buffer from the appropriate transaction list.
*
* Note that this function can *change* the value of
@@ -1595,17 +1596,17 @@ out:
}
-/**
+/**
* int journal_try_to_free_buffers() - try to free page buffers.
* @journal: journal for operation
* @page: to try and free
* @unused_gfp_mask: unused
*
- *
+ *
* For all the buffers on this page,
* if they are fully written out ordered data, move them onto BUF_CLEAN
* so try_to_free_buffers() can reap them.
- *
+ *
* This function returns non-zero if we wish try_to_free_buffers()
* to be called. We do this if the page is releasable by try_to_free_buffers().
* We also do it if the page has locked or dirty buffers and the caller wants
@@ -1629,7 +1630,7 @@ out:
* cannot happen because we never reallocate freed data as metadata
* while the data is part of a transaction. Yes?
*/
-int journal_try_to_free_buffers(journal_t *journal,
+int journal_try_to_free_buffers(journal_t *journal,
struct page *page, gfp_t unused_gfp_mask)
{
struct buffer_head *head;
@@ -1697,7 +1698,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
}
/*
- * journal_invalidatepage
+ * journal_invalidatepage
*
* This code is tricky. It has a number of cases to deal with.
*
@@ -1705,15 +1706,15 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
*
* i_size must be updated on disk before we start calling invalidatepage on the
* data.
- *
+ *
* This is done in ext3 by defining an ext3_setattr method which
* updates i_size before truncate gets going. By maintaining this
* invariant, we can be sure that it is safe to throw away any buffers
* attached to the current transaction: once the transaction commits,
* we know that the data will not be needed.
- *
+ *
* Note however that we can *not* throw away data belonging to the
- * previous, committing transaction!
+ * previous, committing transaction!
*
* Any disk blocks which *are* part of the previous, committing
* transaction (and which therefore cannot be discarded immediately) are
@@ -1732,7 +1733,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
* don't make guarantees about the order in which data hits disk --- in
* particular we don't guarantee that new dirty data is flushed before
* transaction commit --- so it is always safe just to discard data
- * immediately in that mode. --sct
+ * immediately in that mode. --sct
*/
/*
@@ -1876,9 +1877,9 @@ zap_buffer_unlocked:
return may_free;
}
-/**
+/**
* void journal_invalidatepage()
- * @journal: journal to use for flush...
+ * @journal: journal to use for flush...
* @page: page to flush
* @offset: length of page to invalidate.
*
@@ -1886,7 +1887,7 @@ zap_buffer_unlocked:
*
*/
void journal_invalidatepage(journal_t *journal,
- struct page *page,
+ struct page *page,
unsigned long offset)
{
struct buffer_head *head, *bh, *next;
@@ -1908,7 +1909,7 @@ void journal_invalidatepage(journal_t *journal,
next = bh->b_this_page;
if (offset <= curr_off) {
- /* This block is wholly outside the truncation point */
+ /* This block is wholly outside the truncation point */
lock_buffer(bh);
may_free &= journal_unmap_buffer(journal, bh);
unlock_buffer(bh);
@@ -1924,8 +1925,8 @@ void journal_invalidatepage(journal_t *journal,
}
}
-/*
- * File a buffer on the given transaction list.
+/*
+ * File a buffer on the given transaction list.
*/
void __journal_file_buffer(struct journal_head *jh,
transaction_t *transaction, int jlist)
@@ -1948,7 +1949,7 @@ void __journal_file_buffer(struct journal_head *jh,
* with __jbd_unexpected_dirty_buffer()'s handling of dirty
* state. */
- if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
+ if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
jlist == BJ_Shadow || jlist == BJ_Forget) {
if (test_clear_buffer_dirty(bh) ||
test_clear_buffer_jbddirty(bh))
@@ -2008,7 +2009,7 @@ void journal_file_buffer(struct journal_head *jh,
jbd_unlock_bh_state(jh2bh(jh));
}
-/*
+/*
* Remove a buffer from its current buffer list in preparation for
* dropping it from its current transaction entirely. If the buffer has
* already started to be used by a subsequent transaction, refile the
@@ -2060,7 +2061,7 @@ void __journal_refile_buffer(struct journal_head *jh)
* to the caller to remove the journal_head if necessary. For the
* unlocked journal_refile_buffer call, the caller isn't going to be
* doing anything else to the buffer so we need to do the cleanup
- * ourselves to avoid a jh leak.
+ * ourselves to avoid a jh leak.
*
* *** The journal_head may be freed by this call! ***
*/
diff --git a/fs/jbd2/Makefile b/fs/jbd2/Makefile
new file mode 100644
index 000000000000..802a3413872a
--- /dev/null
+++ b/fs/jbd2/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the linux journaling routines.
+#
+
+obj-$(CONFIG_JBD2) += jbd2.o
+
+jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o
diff --git a/fs/jbd2/checkpoint.c b/fs/jbd2/checkpoint.c
new file mode 100644
index 000000000000..68039fa9a566
--- /dev/null
+++ b/fs/jbd2/checkpoint.c
@@ -0,0 +1,697 @@
+/*
+ * linux/fs/checkpoint.c
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1999 Red Hat Software --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Checkpoint routines for the generic filesystem journaling code.
+ * Part of the ext2fs journaling system.
+ *
+ * Checkpointing is the process of ensuring that a section of the log is
+ * committed fully to disk, so that that portion of the log can be
+ * reused.
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+
+/*
+ * Unlink a buffer from a transaction checkpoint list.
+ *
+ * Called with j_list_lock held.
+ */
+static inline void __buffer_unlink_first(struct journal_head *jh)
+{
+ transaction_t *transaction = jh->b_cp_transaction;
+
+ jh->b_cpnext->b_cpprev = jh->b_cpprev;
+ jh->b_cpprev->b_cpnext = jh->b_cpnext;
+ if (transaction->t_checkpoint_list == jh) {
+ transaction->t_checkpoint_list = jh->b_cpnext;
+ if (transaction->t_checkpoint_list == jh)
+ transaction->t_checkpoint_list = NULL;
+ }
+}
+
+/*
+ * Unlink a buffer from a transaction checkpoint(io) list.
+ *
+ * Called with j_list_lock held.
+ */
+static inline void __buffer_unlink(struct journal_head *jh)
+{
+ transaction_t *transaction = jh->b_cp_transaction;
+
+ __buffer_unlink_first(jh);
+ if (transaction->t_checkpoint_io_list == jh) {
+ transaction->t_checkpoint_io_list = jh->b_cpnext;
+ if (transaction->t_checkpoint_io_list == jh)
+ transaction->t_checkpoint_io_list = NULL;
+ }
+}
+
+/*
+ * Move a buffer from the checkpoint list to the checkpoint io list
+ *
+ * Called with j_list_lock held
+ */
+static inline void __buffer_relink_io(struct journal_head *jh)
+{
+ transaction_t *transaction = jh->b_cp_transaction;
+
+ __buffer_unlink_first(jh);
+
+ if (!transaction->t_checkpoint_io_list) {
+ jh->b_cpnext = jh->b_cpprev = jh;
+ } else {
+ jh->b_cpnext = transaction->t_checkpoint_io_list;
+ jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev;
+ jh->b_cpprev->b_cpnext = jh;
+ jh->b_cpnext->b_cpprev = jh;
+ }
+ transaction->t_checkpoint_io_list = jh;
+}
+
+/*
+ * Try to release a checkpointed buffer from its transaction.
+ * Returns 1 if we released it and 2 if we also released the
+ * whole transaction.
+ *
+ * Requires j_list_lock
+ * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
+ */
+static int __try_to_free_cp_buf(struct journal_head *jh)
+{
+ int ret = 0;
+ struct buffer_head *bh = jh2bh(jh);
+
+ if (jh->b_jlist == BJ_None && !buffer_locked(bh) && !buffer_dirty(bh)) {
+ JBUFFER_TRACE(jh, "remove from checkpoint list");
+ ret = __jbd2_journal_remove_checkpoint(jh) + 1;
+ jbd_unlock_bh_state(bh);
+ jbd2_journal_remove_journal_head(bh);
+ BUFFER_TRACE(bh, "release");
+ __brelse(bh);
+ } else {
+ jbd_unlock_bh_state(bh);
+ }
+ return ret;
+}
+
+/*
+ * __jbd2_log_wait_for_space: wait until there is space in the journal.
+ *
+ * Called under j-state_lock *only*. It will be unlocked if we have to wait
+ * for a checkpoint to free up some space in the log.
+ */
+void __jbd2_log_wait_for_space(journal_t *journal)
+{
+ int nblocks;
+ assert_spin_locked(&journal->j_state_lock);
+
+ nblocks = jbd_space_needed(journal);
+ while (__jbd2_log_space_left(journal) < nblocks) {
+ if (journal->j_flags & JBD2_ABORT)
+ return;
+ spin_unlock(&journal->j_state_lock);
+ mutex_lock(&journal->j_checkpoint_mutex);
+
+ /*
+ * Test again, another process may have checkpointed while we
+ * were waiting for the checkpoint lock
+ */
+ spin_lock(&journal->j_state_lock);
+ nblocks = jbd_space_needed(journal);
+ if (__jbd2_log_space_left(journal) < nblocks) {
+ spin_unlock(&journal->j_state_lock);
+ jbd2_log_do_checkpoint(journal);
+ spin_lock(&journal->j_state_lock);
+ }
+ mutex_unlock(&journal->j_checkpoint_mutex);
+ }
+}
+
+/*
+ * We were unable to perform jbd_trylock_bh_state() inside j_list_lock.
+ * The caller must restart a list walk. Wait for someone else to run
+ * jbd_unlock_bh_state().
+ */
+static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh)
+ __releases(journal->j_list_lock)
+{
+ get_bh(bh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_lock_bh_state(bh);
+ jbd_unlock_bh_state(bh);
+ put_bh(bh);
+}
+
+/*
+ * Clean up transaction's list of buffers submitted for io.
+ * We wait for any pending IO to complete and remove any clean
+ * buffers. Note that we take the buffers in the opposite ordering
+ * from the one in which they were submitted for IO.
+ *
+ * Called with j_list_lock held.
+ */
+static void __wait_cp_io(journal_t *journal, transaction_t *transaction)
+{
+ struct journal_head *jh;
+ struct buffer_head *bh;
+ tid_t this_tid;
+ int released = 0;
+
+ this_tid = transaction->t_tid;
+restart:
+ /* Did somebody clean up the transaction in the meanwhile? */
+ if (journal->j_checkpoint_transactions != transaction ||
+ transaction->t_tid != this_tid)
+ return;
+ while (!released && transaction->t_checkpoint_io_list) {
+ jh = transaction->t_checkpoint_io_list;
+ bh = jh2bh(jh);
+ if (!jbd_trylock_bh_state(bh)) {
+ jbd_sync_bh(journal, bh);
+ spin_lock(&journal->j_list_lock);
+ goto restart;
+ }
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ wait_on_buffer(bh);
+ /* the journal_head may have gone by now */
+ BUFFER_TRACE(bh, "brelse");
+ __brelse(bh);
+ spin_lock(&journal->j_list_lock);
+ goto restart;
+ }
+ /*
+ * Now in whatever state the buffer currently is, we know that
+ * it has been written out and so we can drop it from the list
+ */
+ released = __jbd2_journal_remove_checkpoint(jh);
+ jbd_unlock_bh_state(bh);
+ jbd2_journal_remove_journal_head(bh);
+ __brelse(bh);
+ }
+}
+
+#define NR_BATCH 64
+
+static void
+__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
+{
+ int i;
+
+ ll_rw_block(SWRITE, *batch_count, bhs);
+ for (i = 0; i < *batch_count; i++) {
+ struct buffer_head *bh = bhs[i];
+ clear_buffer_jwrite(bh);
+ BUFFER_TRACE(bh, "brelse");
+ __brelse(bh);
+ }
+ *batch_count = 0;
+}
+
+/*
+ * Try to flush one buffer from the checkpoint list to disk.
+ *
+ * Return 1 if something happened which requires us to abort the current
+ * scan of the checkpoint list.
+ *
+ * Called with j_list_lock held and drops it if 1 is returned
+ * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it
+ */
+static int __process_buffer(journal_t *journal, struct journal_head *jh,
+ struct buffer_head **bhs, int *batch_count)
+{
+ struct buffer_head *bh = jh2bh(jh);
+ int ret = 0;
+
+ if (buffer_locked(bh)) {
+ atomic_inc(&bh->b_count);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ wait_on_buffer(bh);
+ /* the journal_head may have gone by now */
+ BUFFER_TRACE(bh, "brelse");
+ __brelse(bh);
+ ret = 1;
+ } else if (jh->b_transaction != NULL) {
+ transaction_t *t = jh->b_transaction;
+ tid_t tid = t->t_tid;
+
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ jbd2_log_start_commit(journal, tid);
+ jbd2_log_wait_commit(journal, tid);
+ ret = 1;
+ } else if (!buffer_dirty(bh)) {
+ J_ASSERT_JH(jh, !buffer_jbddirty(bh));
+ BUFFER_TRACE(bh, "remove from checkpoint");
+ __jbd2_journal_remove_checkpoint(jh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ jbd2_journal_remove_journal_head(bh);
+ __brelse(bh);
+ ret = 1;
+ } else {
+ /*
+ * Important: we are about to write the buffer, and
+ * possibly block, while still holding the journal lock.
+ * We cannot afford to let the transaction logic start
+ * messing around with this buffer before we write it to
+ * disk, as that would break recoverability.
+ */
+ BUFFER_TRACE(bh, "queue");
+ get_bh(bh);
+ J_ASSERT_BH(bh, !buffer_jwrite(bh));
+ set_buffer_jwrite(bh);
+ bhs[*batch_count] = bh;
+ __buffer_relink_io(jh);
+ jbd_unlock_bh_state(bh);
+ (*batch_count)++;
+ if (*batch_count == NR_BATCH) {
+ spin_unlock(&journal->j_list_lock);
+ __flush_batch(journal, bhs, batch_count);
+ ret = 1;
+ }
+ }
+ return ret;
+}
+
+/*
+ * Perform an actual checkpoint. We take the first transaction on the
+ * list of transactions to be checkpointed and send all its buffers
+ * to disk. We submit larger chunks of data at once.
+ *
+ * The journal should be locked before calling this function.
+ */
+int jbd2_log_do_checkpoint(journal_t *journal)
+{
+ transaction_t *transaction;
+ tid_t this_tid;
+ int result;
+
+ jbd_debug(1, "Start checkpoint\n");
+
+ /*
+ * First thing: if there are any transactions in the log which
+ * don't need checkpointing, just eliminate them from the
+ * journal straight away.
+ */
+ result = jbd2_cleanup_journal_tail(journal);
+ jbd_debug(1, "cleanup_journal_tail returned %d\n", result);
+ if (result <= 0)
+ return result;
+
+ /*
+ * OK, we need to start writing disk blocks. Take one transaction
+ * and write it.
+ */
+ spin_lock(&journal->j_list_lock);
+ if (!journal->j_checkpoint_transactions)
+ goto out;
+ transaction = journal->j_checkpoint_transactions;
+ this_tid = transaction->t_tid;
+restart:
+ /*
+ * If someone cleaned up this transaction while we slept, we're
+ * done (maybe it's a new transaction, but it fell at the same
+ * address).
+ */
+ if (journal->j_checkpoint_transactions == transaction &&
+ transaction->t_tid == this_tid) {
+ int batch_count = 0;
+ struct buffer_head *bhs[NR_BATCH];
+ struct journal_head *jh;
+ int retry = 0;
+
+ while (!retry && transaction->t_checkpoint_list) {
+ struct buffer_head *bh;
+
+ jh = transaction->t_checkpoint_list;
+ bh = jh2bh(jh);
+ if (!jbd_trylock_bh_state(bh)) {
+ jbd_sync_bh(journal, bh);
+ retry = 1;
+ break;
+ }
+ retry = __process_buffer(journal, jh, bhs,&batch_count);
+ if (!retry && lock_need_resched(&journal->j_list_lock)){
+ spin_unlock(&journal->j_list_lock);
+ retry = 1;
+ break;
+ }
+ }
+
+ if (batch_count) {
+ if (!retry) {
+ spin_unlock(&journal->j_list_lock);
+ retry = 1;
+ }
+ __flush_batch(journal, bhs, &batch_count);
+ }
+
+ if (retry) {
+ spin_lock(&journal->j_list_lock);
+ goto restart;
+ }
+ /*
+ * Now we have cleaned up the first transaction's checkpoint
+ * list. Let's clean up the second one
+ */
+ __wait_cp_io(journal, transaction);
+ }
+out:
+ spin_unlock(&journal->j_list_lock);
+ result = jbd2_cleanup_journal_tail(journal);
+ if (result < 0)
+ return result;
+ return 0;
+}
+
+/*
+ * Check the list of checkpoint transactions for the journal to see if
+ * we have already got rid of any since the last update of the log tail
+ * in the journal superblock. If so, we can instantly roll the
+ * superblock forward to remove those transactions from the log.
+ *
+ * Return <0 on error, 0 on success, 1 if there was nothing to clean up.
+ *
+ * Called with the journal lock held.
+ *
+ * This is the only part of the journaling code which really needs to be
+ * aware of transaction aborts. Checkpointing involves writing to the
+ * main filesystem area rather than to the journal, so it can proceed
+ * even in abort state, but we must not update the journal superblock if
+ * we have an abort error outstanding.
+ */
+
+int jbd2_cleanup_journal_tail(journal_t *journal)
+{
+ transaction_t * transaction;
+ tid_t first_tid;
+ unsigned long blocknr, freed;
+
+ /* OK, work out the oldest transaction remaining in the log, and
+ * the log block it starts at.
+ *
+ * If the log is now empty, we need to work out which is the
+ * next transaction ID we will write, and where it will
+ * start. */
+
+ spin_lock(&journal->j_state_lock);
+ spin_lock(&journal->j_list_lock);
+ transaction = journal->j_checkpoint_transactions;
+ if (transaction) {
+ first_tid = transaction->t_tid;
+ blocknr = transaction->t_log_start;
+ } else if ((transaction = journal->j_committing_transaction) != NULL) {
+ first_tid = transaction->t_tid;
+ blocknr = transaction->t_log_start;
+ } else if ((transaction = journal->j_running_transaction) != NULL) {
+ first_tid = transaction->t_tid;
+ blocknr = journal->j_head;
+ } else {
+ first_tid = journal->j_transaction_sequence;
+ blocknr = journal->j_head;
+ }
+ spin_unlock(&journal->j_list_lock);
+ J_ASSERT(blocknr != 0);
+
+ /* If the oldest pinned transaction is at the tail of the log
+ already then there's not much we can do right now. */
+ if (journal->j_tail_sequence == first_tid) {
+ spin_unlock(&journal->j_state_lock);
+ return 1;
+ }
+
+ /* OK, update the superblock to recover the freed space.
+ * Physical blocks come first: have we wrapped beyond the end of
+ * the log? */
+ freed = blocknr - journal->j_tail;
+ if (blocknr < journal->j_tail)
+ freed = freed + journal->j_last - journal->j_first;
+
+ jbd_debug(1,
+ "Cleaning journal tail from %d to %d (offset %lu), "
+ "freeing %lu\n",
+ journal->j_tail_sequence, first_tid, blocknr, freed);
+
+ journal->j_free += freed;
+ journal->j_tail_sequence = first_tid;
+ journal->j_tail = blocknr;
+ spin_unlock(&journal->j_state_lock);
+ if (!(journal->j_flags & JBD2_ABORT))
+ jbd2_journal_update_superblock(journal, 1);
+ return 0;
+}
+
+
+/* Checkpoint list management */
+
+/*
+ * journal_clean_one_cp_list
+ *
+ * Find all the written-back checkpoint buffers in the given list and release them.
+ *
+ * Called with the journal locked.
+ * Called with j_list_lock held.
+ * Returns number of bufers reaped (for debug)
+ */
+
+static int journal_clean_one_cp_list(struct journal_head *jh, int *released)
+{
+ struct journal_head *last_jh;
+ struct journal_head *next_jh = jh;
+ int ret, freed = 0;
+
+ *released = 0;
+ if (!jh)
+ return 0;
+
+ last_jh = jh->b_cpprev;
+ do {
+ jh = next_jh;
+ next_jh = jh->b_cpnext;
+ /* Use trylock because of the ranking */
+ if (jbd_trylock_bh_state(jh2bh(jh))) {
+ ret = __try_to_free_cp_buf(jh);
+ if (ret) {
+ freed++;
+ if (ret == 2) {
+ *released = 1;
+ return freed;
+ }
+ }
+ }
+ /*
+ * This function only frees up some memory
+ * if possible so we dont have an obligation
+ * to finish processing. Bail out if preemption
+ * requested:
+ */
+ if (need_resched())
+ return freed;
+ } while (jh != last_jh);
+
+ return freed;
+}
+
+/*
+ * journal_clean_checkpoint_list
+ *
+ * Find all the written-back checkpoint buffers in the journal and release them.
+ *
+ * Called with the journal locked.
+ * Called with j_list_lock held.
+ * Returns number of buffers reaped (for debug)
+ */
+
+int __jbd2_journal_clean_checkpoint_list(journal_t *journal)
+{
+ transaction_t *transaction, *last_transaction, *next_transaction;
+ int ret = 0;
+ int released;
+
+ transaction = journal->j_checkpoint_transactions;
+ if (!transaction)
+ goto out;
+
+ last_transaction = transaction->t_cpprev;
+ next_transaction = transaction;
+ do {
+ transaction = next_transaction;
+ next_transaction = transaction->t_cpnext;
+ ret += journal_clean_one_cp_list(transaction->
+ t_checkpoint_list, &released);
+ /*
+ * This function only frees up some memory if possible so we
+ * dont have an obligation to finish processing. Bail out if
+ * preemption requested:
+ */
+ if (need_resched())
+ goto out;
+ if (released)
+ continue;
+ /*
+ * It is essential that we are as careful as in the case of
+ * t_checkpoint_list with removing the buffer from the list as
+ * we can possibly see not yet submitted buffers on io_list
+ */
+ ret += journal_clean_one_cp_list(transaction->
+ t_checkpoint_io_list, &released);
+ if (need_resched())
+ goto out;
+ } while (transaction != last_transaction);
+out:
+ return ret;
+}
+
+/*
+ * journal_remove_checkpoint: called after a buffer has been committed
+ * to disk (either by being write-back flushed to disk, or being
+ * committed to the log).
+ *
+ * We cannot safely clean a transaction out of the log until all of the
+ * buffer updates committed in that transaction have safely been stored
+ * elsewhere on disk. To achieve this, all of the buffers in a
+ * transaction need to be maintained on the transaction's checkpoint
+ * lists until they have been rewritten, at which point this function is
+ * called to remove the buffer from the existing transaction's
+ * checkpoint lists.
+ *
+ * The function returns 1 if it frees the transaction, 0 otherwise.
+ *
+ * This function is called with the journal locked.
+ * This function is called with j_list_lock held.
+ * This function is called with jbd_lock_bh_state(jh2bh(jh))
+ */
+
+int __jbd2_journal_remove_checkpoint(struct journal_head *jh)
+{
+ transaction_t *transaction;
+ journal_t *journal;
+ int ret = 0;
+
+ JBUFFER_TRACE(jh, "entry");
+
+ if ((transaction = jh->b_cp_transaction) == NULL) {
+ JBUFFER_TRACE(jh, "not on transaction");
+ goto out;
+ }
+ journal = transaction->t_journal;
+
+ __buffer_unlink(jh);
+ jh->b_cp_transaction = NULL;
+
+ if (transaction->t_checkpoint_list != NULL ||
+ transaction->t_checkpoint_io_list != NULL)
+ goto out;
+ JBUFFER_TRACE(jh, "transaction has no more buffers");
+
+ /*
+ * There is one special case to worry about: if we have just pulled the
+ * buffer off a committing transaction's forget list, then even if the
+ * checkpoint list is empty, the transaction obviously cannot be
+ * dropped!
+ *
+ * The locking here around j_committing_transaction is a bit sleazy.
+ * See the comment at the end of jbd2_journal_commit_transaction().
+ */
+ if (transaction == journal->j_committing_transaction) {
+ JBUFFER_TRACE(jh, "belongs to committing transaction");
+ goto out;
+ }
+
+ /* OK, that was the last buffer for the transaction: we can now
+ safely remove this transaction from the log */
+
+ __jbd2_journal_drop_transaction(journal, transaction);
+
+ /* Just in case anybody was waiting for more transactions to be
+ checkpointed... */
+ wake_up(&journal->j_wait_logspace);
+ ret = 1;
+out:
+ JBUFFER_TRACE(jh, "exit");
+ return ret;
+}
+
+/*
+ * journal_insert_checkpoint: put a committed buffer onto a checkpoint
+ * list so that we know when it is safe to clean the transaction out of
+ * the log.
+ *
+ * Called with the journal locked.
+ * Called with j_list_lock held.
+ */
+void __jbd2_journal_insert_checkpoint(struct journal_head *jh,
+ transaction_t *transaction)
+{
+ JBUFFER_TRACE(jh, "entry");
+ J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh)));
+ J_ASSERT_JH(jh, jh->b_cp_transaction == NULL);
+
+ jh->b_cp_transaction = transaction;
+
+ if (!transaction->t_checkpoint_list) {
+ jh->b_cpnext = jh->b_cpprev = jh;
+ } else {
+ jh->b_cpnext = transaction->t_checkpoint_list;
+ jh->b_cpprev = transaction->t_checkpoint_list->b_cpprev;
+ jh->b_cpprev->b_cpnext = jh;
+ jh->b_cpnext->b_cpprev = jh;
+ }
+ transaction->t_checkpoint_list = jh;
+}
+
+/*
+ * We've finished with this transaction structure: adios...
+ *
+ * The transaction must have no links except for the checkpoint by this
+ * point.
+ *
+ * Called with the journal locked.
+ * Called with j_list_lock held.
+ */
+
+void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transaction)
+{
+ assert_spin_locked(&journal->j_list_lock);
+ if (transaction->t_cpnext) {
+ transaction->t_cpnext->t_cpprev = transaction->t_cpprev;
+ transaction->t_cpprev->t_cpnext = transaction->t_cpnext;
+ if (journal->j_checkpoint_transactions == transaction)
+ journal->j_checkpoint_transactions =
+ transaction->t_cpnext;
+ if (journal->j_checkpoint_transactions == transaction)
+ journal->j_checkpoint_transactions = NULL;
+ }
+
+ J_ASSERT(transaction->t_state == T_FINISHED);
+ J_ASSERT(transaction->t_buffers == NULL);
+ J_ASSERT(transaction->t_sync_datalist == NULL);
+ J_ASSERT(transaction->t_forget == NULL);
+ J_ASSERT(transaction->t_iobuf_list == NULL);
+ J_ASSERT(transaction->t_shadow_list == NULL);
+ J_ASSERT(transaction->t_log_list == NULL);
+ J_ASSERT(transaction->t_checkpoint_list == NULL);
+ J_ASSERT(transaction->t_checkpoint_io_list == NULL);
+ J_ASSERT(transaction->t_updates == 0);
+ J_ASSERT(journal->j_committing_transaction != transaction);
+ J_ASSERT(journal->j_running_transaction != transaction);
+
+ jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
+ kfree(transaction);
+}
diff --git a/fs/jbd2/commit.c b/fs/jbd2/commit.c
new file mode 100644
index 000000000000..70b2ae1ef281
--- /dev/null
+++ b/fs/jbd2/commit.c
@@ -0,0 +1,920 @@
+/*
+ * linux/fs/jbd2/commit.c
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Journal commit routines for the generic filesystem journaling code;
+ * part of the ext2fs journaling system.
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/smp_lock.h>
+
+/*
+ * Default IO end handler for temporary BJ_IO buffer_heads.
+ */
+static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+{
+ BUFFER_TRACE(bh, "");
+ if (uptodate)
+ set_buffer_uptodate(bh);
+ else
+ clear_buffer_uptodate(bh);
+ unlock_buffer(bh);
+}
+
+/*
+ * When an ext3-ordered file is truncated, it is possible that many pages are
+ * not sucessfully freed, because they are attached to a committing transaction.
+ * After the transaction commits, these pages are left on the LRU, with no
+ * ->mapping, and with attached buffers. These pages are trivially reclaimable
+ * by the VM, but their apparent absence upsets the VM accounting, and it makes
+ * the numbers in /proc/meminfo look odd.
+ *
+ * So here, we have a buffer which has just come off the forget list. Look to
+ * see if we can strip all buffers from the backing page.
+ *
+ * Called under lock_journal(), and possibly under journal_datalist_lock. The
+ * caller provided us with a ref against the buffer, and we drop that here.
+ */
+static void release_buffer_page(struct buffer_head *bh)
+{
+ struct page *page;
+
+ if (buffer_dirty(bh))
+ goto nope;
+ if (atomic_read(&bh->b_count) != 1)
+ goto nope;
+ page = bh->b_page;
+ if (!page)
+ goto nope;
+ if (page->mapping)
+ goto nope;
+
+ /* OK, it's a truncated page */
+ if (TestSetPageLocked(page))
+ goto nope;
+
+ page_cache_get(page);
+ __brelse(bh);
+ try_to_free_buffers(page);
+ unlock_page(page);
+ page_cache_release(page);
+ return;
+
+nope:
+ __brelse(bh);
+}
+
+/*
+ * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is
+ * held. For ranking reasons we must trylock. If we lose, schedule away and
+ * return 0. j_list_lock is dropped in this case.
+ */
+static int inverted_lock(journal_t *journal, struct buffer_head *bh)
+{
+ if (!jbd_trylock_bh_state(bh)) {
+ spin_unlock(&journal->j_list_lock);
+ schedule();
+ return 0;
+ }
+ return 1;
+}
+
+/* Done it all: now write the commit record. We should have
+ * cleaned up our previous buffers by now, so if we are in abort
+ * mode we can now just skip the rest of the journal write
+ * entirely.
+ *
+ * Returns 1 if the journal needs to be aborted or 0 on success
+ */
+static int journal_write_commit_record(journal_t *journal,
+ transaction_t *commit_transaction)
+{
+ struct journal_head *descriptor;
+ struct buffer_head *bh;
+ int i, ret;
+ int barrier_done = 0;
+
+ if (is_journal_aborted(journal))
+ return 0;
+
+ descriptor = jbd2_journal_get_descriptor_buffer(journal);
+ if (!descriptor)
+ return 1;
+
+ bh = jh2bh(descriptor);
+
+ /* AKPM: buglet - add `i' to tmp! */
+ for (i = 0; i < bh->b_size; i += 512) {
+ journal_header_t *tmp = (journal_header_t*)bh->b_data;
+ tmp->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
+ tmp->h_blocktype = cpu_to_be32(JBD2_COMMIT_BLOCK);
+ tmp->h_sequence = cpu_to_be32(commit_transaction->t_tid);
+ }
+
+ JBUFFER_TRACE(descriptor, "write commit block");
+ set_buffer_dirty(bh);
+ if (journal->j_flags & JBD2_BARRIER) {
+ set_buffer_ordered(bh);
+ barrier_done = 1;
+ }
+ ret = sync_dirty_buffer(bh);
+ /* is it possible for another commit to fail at roughly
+ * the same time as this one? If so, we don't want to
+ * trust the barrier flag in the super, but instead want
+ * to remember if we sent a barrier request
+ */
+ if (ret == -EOPNOTSUPP && barrier_done) {
+ char b[BDEVNAME_SIZE];
+
+ printk(KERN_WARNING
+ "JBD: barrier-based sync failed on %s - "
+ "disabling barriers\n",
+ bdevname(journal->j_dev, b));
+ spin_lock(&journal->j_state_lock);
+ journal->j_flags &= ~JBD2_BARRIER;
+ spin_unlock(&journal->j_state_lock);
+
+ /* And try again, without the barrier */
+ clear_buffer_ordered(bh);
+ set_buffer_uptodate(bh);
+ set_buffer_dirty(bh);
+ ret = sync_dirty_buffer(bh);
+ }
+ put_bh(bh); /* One for getblk() */
+ jbd2_journal_put_journal_head(descriptor);
+
+ return (ret == -EIO);
+}
+
+static void journal_do_submit_data(struct buffer_head **wbuf, int bufs)
+{
+ int i;
+
+ for (i = 0; i < bufs; i++) {
+ wbuf[i]->b_end_io = end_buffer_write_sync;
+ /* We use-up our safety reference in submit_bh() */
+ submit_bh(WRITE, wbuf[i]);
+ }
+}
+
+/*
+ * Submit all the data buffers to disk
+ */
+static void journal_submit_data_buffers(journal_t *journal,
+ transaction_t *commit_transaction)
+{
+ struct journal_head *jh;
+ struct buffer_head *bh;
+ int locked;
+ int bufs = 0;
+ struct buffer_head **wbuf = journal->j_wbuf;
+
+ /*
+ * Whenever we unlock the journal and sleep, things can get added
+ * onto ->t_sync_datalist, so we have to keep looping back to
+ * write_out_data until we *know* that the list is empty.
+ *
+ * Cleanup any flushed data buffers from the data list. Even in
+ * abort mode, we want to flush this out as soon as possible.
+ */
+write_out_data:
+ cond_resched();
+ spin_lock(&journal->j_list_lock);
+
+ while (commit_transaction->t_sync_datalist) {
+ jh = commit_transaction->t_sync_datalist;
+ bh = jh2bh(jh);
+ locked = 0;
+
+ /* Get reference just to make sure buffer does not disappear
+ * when we are forced to drop various locks */
+ get_bh(bh);
+ /* If the buffer is dirty, we need to submit IO and hence
+ * we need the buffer lock. We try to lock the buffer without
+ * blocking. If we fail, we need to drop j_list_lock and do
+ * blocking lock_buffer().
+ */
+ if (buffer_dirty(bh)) {
+ if (test_set_buffer_locked(bh)) {
+ BUFFER_TRACE(bh, "needs blocking lock");
+ spin_unlock(&journal->j_list_lock);
+ /* Write out all data to prevent deadlocks */
+ journal_do_submit_data(wbuf, bufs);
+ bufs = 0;
+ lock_buffer(bh);
+ spin_lock(&journal->j_list_lock);
+ }
+ locked = 1;
+ }
+ /* We have to get bh_state lock. Again out of order, sigh. */
+ if (!inverted_lock(journal, bh)) {
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
+ }
+ /* Someone already cleaned up the buffer? */
+ if (!buffer_jbd(bh)
+ || jh->b_transaction != commit_transaction
+ || jh->b_jlist != BJ_SyncData) {
+ jbd_unlock_bh_state(bh);
+ if (locked)
+ unlock_buffer(bh);
+ BUFFER_TRACE(bh, "already cleaned up");
+ put_bh(bh);
+ continue;
+ }
+ if (locked && test_clear_buffer_dirty(bh)) {
+ BUFFER_TRACE(bh, "needs writeout, adding to array");
+ wbuf[bufs++] = bh;
+ __jbd2_journal_file_buffer(jh, commit_transaction,
+ BJ_Locked);
+ jbd_unlock_bh_state(bh);
+ if (bufs == journal->j_wbufsize) {
+ spin_unlock(&journal->j_list_lock);
+ journal_do_submit_data(wbuf, bufs);
+ bufs = 0;
+ goto write_out_data;
+ }
+ }
+ else {
+ BUFFER_TRACE(bh, "writeout complete: unfile");
+ __jbd2_journal_unfile_buffer(jh);
+ jbd_unlock_bh_state(bh);
+ if (locked)
+ unlock_buffer(bh);
+ jbd2_journal_remove_journal_head(bh);
+ /* Once for our safety reference, once for
+ * jbd2_journal_remove_journal_head() */
+ put_bh(bh);
+ put_bh(bh);
+ }
+
+ if (lock_need_resched(&journal->j_list_lock)) {
+ spin_unlock(&journal->j_list_lock);
+ goto write_out_data;
+ }
+ }
+ spin_unlock(&journal->j_list_lock);
+ journal_do_submit_data(wbuf, bufs);
+}
+
+static inline void write_tag_block(int tag_bytes, journal_block_tag_t *tag,
+ unsigned long long block)
+{
+ tag->t_blocknr = cpu_to_be32(block & (u32)~0);
+ if (tag_bytes > JBD_TAG_SIZE32)
+ tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1);
+}
+
+/*
+ * jbd2_journal_commit_transaction
+ *
+ * The primary function for committing a transaction to the log. This
+ * function is called by the journal thread to begin a complete commit.
+ */
+void jbd2_journal_commit_transaction(journal_t *journal)
+{
+ transaction_t *commit_transaction;
+ struct journal_head *jh, *new_jh, *descriptor;
+ struct buffer_head **wbuf = journal->j_wbuf;
+ int bufs;
+ int flags;
+ int err;
+ unsigned long long blocknr;
+ char *tagp = NULL;
+ journal_header_t *header;
+ journal_block_tag_t *tag = NULL;
+ int space_left = 0;
+ int first_tag = 0;
+ int tag_flag;
+ int i;
+ int tag_bytes = journal_tag_bytes(journal);
+
+ /*
+ * First job: lock down the current transaction and wait for
+ * all outstanding updates to complete.
+ */
+
+#ifdef COMMIT_STATS
+ spin_lock(&journal->j_list_lock);
+ summarise_journal_usage(journal);
+ spin_unlock(&journal->j_list_lock);
+#endif
+
+ /* Do we need to erase the effects of a prior jbd2_journal_flush? */
+ if (journal->j_flags & JBD2_FLUSHED) {
+ jbd_debug(3, "super block updated\n");
+ jbd2_journal_update_superblock(journal, 1);
+ } else {
+ jbd_debug(3, "superblock not updated\n");
+ }
+
+ J_ASSERT(journal->j_running_transaction != NULL);
+ J_ASSERT(journal->j_committing_transaction == NULL);
+
+ commit_transaction = journal->j_running_transaction;
+ J_ASSERT(commit_transaction->t_state == T_RUNNING);
+
+ jbd_debug(1, "JBD: starting commit of transaction %d\n",
+ commit_transaction->t_tid);
+
+ spin_lock(&journal->j_state_lock);
+ commit_transaction->t_state = T_LOCKED;
+
+ spin_lock(&commit_transaction->t_handle_lock);
+ while (commit_transaction->t_updates) {
+ DEFINE_WAIT(wait);
+
+ prepare_to_wait(&journal->j_wait_updates, &wait,
+ TASK_UNINTERRUPTIBLE);
+ if (commit_transaction->t_updates) {
+ spin_unlock(&commit_transaction->t_handle_lock);
+ spin_unlock(&journal->j_state_lock);
+ schedule();
+ spin_lock(&journal->j_state_lock);
+ spin_lock(&commit_transaction->t_handle_lock);
+ }
+ finish_wait(&journal->j_wait_updates, &wait);
+ }
+ spin_unlock(&commit_transaction->t_handle_lock);
+
+ J_ASSERT (commit_transaction->t_outstanding_credits <=
+ journal->j_max_transaction_buffers);
+
+ /*
+ * First thing we are allowed to do is to discard any remaining
+ * BJ_Reserved buffers. Note, it is _not_ permissible to assume
+ * that there are no such buffers: if a large filesystem
+ * operation like a truncate needs to split itself over multiple
+ * transactions, then it may try to do a jbd2_journal_restart() while
+ * there are still BJ_Reserved buffers outstanding. These must
+ * be released cleanly from the current transaction.
+ *
+ * In this case, the filesystem must still reserve write access
+ * again before modifying the buffer in the new transaction, but
+ * we do not require it to remember exactly which old buffers it
+ * has reserved. This is consistent with the existing behaviour
+ * that multiple jbd2_journal_get_write_access() calls to the same
+ * buffer are perfectly permissable.
+ */
+ while (commit_transaction->t_reserved_list) {
+ jh = commit_transaction->t_reserved_list;
+ JBUFFER_TRACE(jh, "reserved, unused: refile");
+ /*
+ * A jbd2_journal_get_undo_access()+jbd2_journal_release_buffer() may
+ * leave undo-committed data.
+ */
+ if (jh->b_committed_data) {
+ struct buffer_head *bh = jh2bh(jh);
+
+ jbd_lock_bh_state(bh);
+ jbd2_slab_free(jh->b_committed_data, bh->b_size);
+ jh->b_committed_data = NULL;
+ jbd_unlock_bh_state(bh);
+ }
+ jbd2_journal_refile_buffer(journal, jh);
+ }
+
+ /*
+ * Now try to drop any written-back buffers from the journal's
+ * checkpoint lists. We do this *before* commit because it potentially
+ * frees some memory
+ */
+ spin_lock(&journal->j_list_lock);
+ __jbd2_journal_clean_checkpoint_list(journal);
+ spin_unlock(&journal->j_list_lock);
+
+ jbd_debug (3, "JBD: commit phase 1\n");
+
+ /*
+ * Switch to a new revoke table.
+ */
+ jbd2_journal_switch_revoke_table(journal);
+
+ commit_transaction->t_state = T_FLUSH;
+ journal->j_committing_transaction = commit_transaction;
+ journal->j_running_transaction = NULL;
+ commit_transaction->t_log_start = journal->j_head;
+ wake_up(&journal->j_wait_transaction_locked);
+ spin_unlock(&journal->j_state_lock);
+
+ jbd_debug (3, "JBD: commit phase 2\n");
+
+ /*
+ * First, drop modified flag: all accesses to the buffers
+ * will be tracked for a new trasaction only -bzzz
+ */
+ spin_lock(&journal->j_list_lock);
+ if (commit_transaction->t_buffers) {
+ new_jh = jh = commit_transaction->t_buffers->b_tnext;
+ do {
+ J_ASSERT_JH(new_jh, new_jh->b_modified == 1 ||
+ new_jh->b_modified == 0);
+ new_jh->b_modified = 0;
+ new_jh = new_jh->b_tnext;
+ } while (new_jh != jh);
+ }
+ spin_unlock(&journal->j_list_lock);
+
+ /*
+ * Now start flushing things to disk, in the order they appear
+ * on the transaction lists. Data blocks go first.
+ */
+ err = 0;
+ journal_submit_data_buffers(journal, commit_transaction);
+
+ /*
+ * Wait for all previously submitted IO to complete.
+ */
+ spin_lock(&journal->j_list_lock);
+ while (commit_transaction->t_locked_list) {
+ struct buffer_head *bh;
+
+ jh = commit_transaction->t_locked_list->b_tprev;
+ bh = jh2bh(jh);
+ get_bh(bh);
+ if (buffer_locked(bh)) {
+ spin_unlock(&journal->j_list_lock);
+ wait_on_buffer(bh);
+ if (unlikely(!buffer_uptodate(bh)))
+ err = -EIO;
+ spin_lock(&journal->j_list_lock);
+ }
+ if (!inverted_lock(journal, bh)) {
+ put_bh(bh);
+ spin_lock(&journal->j_list_lock);
+ continue;
+ }
+ if (buffer_jbd(bh) && jh->b_jlist == BJ_Locked) {
+ __jbd2_journal_unfile_buffer(jh);
+ jbd_unlock_bh_state(bh);
+ jbd2_journal_remove_journal_head(bh);
+ put_bh(bh);
+ } else {
+ jbd_unlock_bh_state(bh);
+ }
+ put_bh(bh);
+ cond_resched_lock(&journal->j_list_lock);
+ }
+ spin_unlock(&journal->j_list_lock);
+
+ if (err)
+ __jbd2_journal_abort_hard(journal);
+
+ jbd2_journal_write_revoke_records(journal, commit_transaction);
+
+ jbd_debug(3, "JBD: commit phase 2\n");
+
+ /*
+ * If we found any dirty or locked buffers, then we should have
+ * looped back up to the write_out_data label. If there weren't
+ * any then journal_clean_data_list should have wiped the list
+ * clean by now, so check that it is in fact empty.
+ */
+ J_ASSERT (commit_transaction->t_sync_datalist == NULL);
+
+ jbd_debug (3, "JBD: commit phase 3\n");
+
+ /*
+ * Way to go: we have now written out all of the data for a
+ * transaction! Now comes the tricky part: we need to write out
+ * metadata. Loop over the transaction's entire buffer list:
+ */
+ commit_transaction->t_state = T_COMMIT;
+
+ descriptor = NULL;
+ bufs = 0;
+ while (commit_transaction->t_buffers) {
+
+ /* Find the next buffer to be journaled... */
+
+ jh = commit_transaction->t_buffers;
+
+ /* If we're in abort mode, we just un-journal the buffer and
+ release it for background writing. */
+
+ if (is_journal_aborted(journal)) {
+ JBUFFER_TRACE(jh, "journal is aborting: refile");
+ jbd2_journal_refile_buffer(journal, jh);
+ /* If that was the last one, we need to clean up
+ * any descriptor buffers which may have been
+ * already allocated, even if we are now
+ * aborting. */
+ if (!commit_transaction->t_buffers)
+ goto start_journal_io;
+ continue;
+ }
+
+ /* Make sure we have a descriptor block in which to
+ record the metadata buffer. */
+
+ if (!descriptor) {
+ struct buffer_head *bh;
+
+ J_ASSERT (bufs == 0);
+
+ jbd_debug(4, "JBD: get descriptor\n");
+
+ descriptor = jbd2_journal_get_descriptor_buffer(journal);
+ if (!descriptor) {
+ __jbd2_journal_abort_hard(journal);
+ continue;
+ }
+
+ bh = jh2bh(descriptor);
+ jbd_debug(4, "JBD: got buffer %llu (%p)\n",
+ (unsigned long long)bh->b_blocknr, bh->b_data);
+ header = (journal_header_t *)&bh->b_data[0];
+ header->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
+ header->h_blocktype = cpu_to_be32(JBD2_DESCRIPTOR_BLOCK);
+ header->h_sequence = cpu_to_be32(commit_transaction->t_tid);
+
+ tagp = &bh->b_data[sizeof(journal_header_t)];
+ space_left = bh->b_size - sizeof(journal_header_t);
+ first_tag = 1;
+ set_buffer_jwrite(bh);
+ set_buffer_dirty(bh);
+ wbuf[bufs++] = bh;
+
+ /* Record it so that we can wait for IO
+ completion later */
+ BUFFER_TRACE(bh, "ph3: file as descriptor");
+ jbd2_journal_file_buffer(descriptor, commit_transaction,
+ BJ_LogCtl);
+ }
+
+ /* Where is the buffer to be written? */
+
+ err = jbd2_journal_next_log_block(journal, &blocknr);
+ /* If the block mapping failed, just abandon the buffer
+ and repeat this loop: we'll fall into the
+ refile-on-abort condition above. */
+ if (err) {
+ __jbd2_journal_abort_hard(journal);
+ continue;
+ }
+
+ /*
+ * start_this_handle() uses t_outstanding_credits to determine
+ * the free space in the log, but this counter is changed
+ * by jbd2_journal_next_log_block() also.
+ */
+ commit_transaction->t_outstanding_credits--;
+
+ /* Bump b_count to prevent truncate from stumbling over
+ the shadowed buffer! @@@ This can go if we ever get
+ rid of the BJ_IO/BJ_Shadow pairing of buffers. */
+ atomic_inc(&jh2bh(jh)->b_count);
+
+ /* Make a temporary IO buffer with which to write it out
+ (this will requeue both the metadata buffer and the
+ temporary IO buffer). new_bh goes on BJ_IO*/
+
+ set_bit(BH_JWrite, &jh2bh(jh)->b_state);
+ /*
+ * akpm: jbd2_journal_write_metadata_buffer() sets
+ * new_bh->b_transaction to commit_transaction.
+ * We need to clean this up before we release new_bh
+ * (which is of type BJ_IO)
+ */
+ JBUFFER_TRACE(jh, "ph3: write metadata");
+ flags = jbd2_journal_write_metadata_buffer(commit_transaction,
+ jh, &new_jh, blocknr);
+ set_bit(BH_JWrite, &jh2bh(new_jh)->b_state);
+ wbuf[bufs++] = jh2bh(new_jh);
+
+ /* Record the new block's tag in the current descriptor
+ buffer */
+
+ tag_flag = 0;
+ if (flags & 1)
+ tag_flag |= JBD2_FLAG_ESCAPE;
+ if (!first_tag)
+ tag_flag |= JBD2_FLAG_SAME_UUID;
+
+ tag = (journal_block_tag_t *) tagp;
+ write_tag_block(tag_bytes, tag, jh2bh(jh)->b_blocknr);
+ tag->t_flags = cpu_to_be32(tag_flag);
+ tagp += tag_bytes;
+ space_left -= tag_bytes;
+
+ if (first_tag) {
+ memcpy (tagp, journal->j_uuid, 16);
+ tagp += 16;
+ space_left -= 16;
+ first_tag = 0;
+ }
+
+ /* If there's no more to do, or if the descriptor is full,
+ let the IO rip! */
+
+ if (bufs == journal->j_wbufsize ||
+ commit_transaction->t_buffers == NULL ||
+ space_left < tag_bytes + 16) {
+
+ jbd_debug(4, "JBD: Submit %d IOs\n", bufs);
+
+ /* Write an end-of-descriptor marker before
+ submitting the IOs. "tag" still points to
+ the last tag we set up. */
+
+ tag->t_flags |= cpu_to_be32(JBD2_FLAG_LAST_TAG);
+
+start_journal_io:
+ for (i = 0; i < bufs; i++) {
+ struct buffer_head *bh = wbuf[i];
+ lock_buffer(bh);
+ clear_buffer_dirty(bh);
+ set_buffer_uptodate(bh);
+ bh->b_end_io = journal_end_buffer_io_sync;
+ submit_bh(WRITE, bh);
+ }
+ cond_resched();
+
+ /* Force a new descriptor to be generated next
+ time round the loop. */
+ descriptor = NULL;
+ bufs = 0;
+ }
+ }
+
+ /* Lo and behold: we have just managed to send a transaction to
+ the log. Before we can commit it, wait for the IO so far to
+ complete. Control buffers being written are on the
+ transaction's t_log_list queue, and metadata buffers are on
+ the t_iobuf_list queue.
+
+ Wait for the buffers in reverse order. That way we are
+ less likely to be woken up until all IOs have completed, and
+ so we incur less scheduling load.
+ */
+
+ jbd_debug(3, "JBD: commit phase 4\n");
+
+ /*
+ * akpm: these are BJ_IO, and j_list_lock is not needed.
+ * See __journal_try_to_free_buffer.
+ */
+wait_for_iobuf:
+ while (commit_transaction->t_iobuf_list != NULL) {
+ struct buffer_head *bh;
+
+ jh = commit_transaction->t_iobuf_list->b_tprev;
+ bh = jh2bh(jh);
+ if (buffer_locked(bh)) {
+ wait_on_buffer(bh);
+ goto wait_for_iobuf;
+ }
+ if (cond_resched())
+ goto wait_for_iobuf;
+
+ if (unlikely(!buffer_uptodate(bh)))
+ err = -EIO;
+
+ clear_buffer_jwrite(bh);
+
+ JBUFFER_TRACE(jh, "ph4: unfile after journal write");
+ jbd2_journal_unfile_buffer(journal, jh);
+
+ /*
+ * ->t_iobuf_list should contain only dummy buffer_heads
+ * which were created by jbd2_journal_write_metadata_buffer().
+ */
+ BUFFER_TRACE(bh, "dumping temporary bh");
+ jbd2_journal_put_journal_head(jh);
+ __brelse(bh);
+ J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0);
+ free_buffer_head(bh);
+
+ /* We also have to unlock and free the corresponding
+ shadowed buffer */
+ jh = commit_transaction->t_shadow_list->b_tprev;
+ bh = jh2bh(jh);
+ clear_bit(BH_JWrite, &bh->b_state);
+ J_ASSERT_BH(bh, buffer_jbddirty(bh));
+
+ /* The metadata is now released for reuse, but we need
+ to remember it against this transaction so that when
+ we finally commit, we can do any checkpointing
+ required. */
+ JBUFFER_TRACE(jh, "file as BJ_Forget");
+ jbd2_journal_file_buffer(jh, commit_transaction, BJ_Forget);
+ /* Wake up any transactions which were waiting for this
+ IO to complete */
+ wake_up_bit(&bh->b_state, BH_Unshadow);
+ JBUFFER_TRACE(jh, "brelse shadowed buffer");
+ __brelse(bh);
+ }
+
+ J_ASSERT (commit_transaction->t_shadow_list == NULL);
+
+ jbd_debug(3, "JBD: commit phase 5\n");
+
+ /* Here we wait for the revoke record and descriptor record buffers */
+ wait_for_ctlbuf:
+ while (commit_transaction->t_log_list != NULL) {
+ struct buffer_head *bh;
+
+ jh = commit_transaction->t_log_list->b_tprev;
+ bh = jh2bh(jh);
+ if (buffer_locked(bh)) {
+ wait_on_buffer(bh);
+ goto wait_for_ctlbuf;
+ }
+ if (cond_resched())
+ goto wait_for_ctlbuf;
+
+ if (unlikely(!buffer_uptodate(bh)))
+ err = -EIO;
+
+ BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile");
+ clear_buffer_jwrite(bh);
+ jbd2_journal_unfile_buffer(journal, jh);
+ jbd2_journal_put_journal_head(jh);
+ __brelse(bh); /* One for getblk */
+ /* AKPM: bforget here */
+ }
+
+ jbd_debug(3, "JBD: commit phase 6\n");
+
+ if (journal_write_commit_record(journal, commit_transaction))
+ err = -EIO;
+
+ if (err)
+ __jbd2_journal_abort_hard(journal);
+
+ /* End of a transaction! Finally, we can do checkpoint
+ processing: any buffers committed as a result of this
+ transaction can be removed from any checkpoint list it was on
+ before. */
+
+ jbd_debug(3, "JBD: commit phase 7\n");
+
+ J_ASSERT(commit_transaction->t_sync_datalist == NULL);
+ J_ASSERT(commit_transaction->t_buffers == NULL);
+ J_ASSERT(commit_transaction->t_checkpoint_list == NULL);
+ J_ASSERT(commit_transaction->t_iobuf_list == NULL);
+ J_ASSERT(commit_transaction->t_shadow_list == NULL);
+ J_ASSERT(commit_transaction->t_log_list == NULL);
+
+restart_loop:
+ /*
+ * As there are other places (journal_unmap_buffer()) adding buffers
+ * to this list we have to be careful and hold the j_list_lock.
+ */
+ spin_lock(&journal->j_list_lock);
+ while (commit_transaction->t_forget) {
+ transaction_t *cp_transaction;
+ struct buffer_head *bh;
+
+ jh = commit_transaction->t_forget;
+ spin_unlock(&journal->j_list_lock);
+ bh = jh2bh(jh);
+ jbd_lock_bh_state(bh);
+ J_ASSERT_JH(jh, jh->b_transaction == commit_transaction ||
+ jh->b_transaction == journal->j_running_transaction);
+
+ /*
+ * If there is undo-protected committed data against
+ * this buffer, then we can remove it now. If it is a
+ * buffer needing such protection, the old frozen_data
+ * field now points to a committed version of the
+ * buffer, so rotate that field to the new committed
+ * data.
+ *
+ * Otherwise, we can just throw away the frozen data now.
+ */
+ if (jh->b_committed_data) {
+ jbd2_slab_free(jh->b_committed_data, bh->b_size);
+ jh->b_committed_data = NULL;
+ if (jh->b_frozen_data) {
+ jh->b_committed_data = jh->b_frozen_data;
+ jh->b_frozen_data = NULL;
+ }
+ } else if (jh->b_frozen_data) {
+ jbd2_slab_free(jh->b_frozen_data, bh->b_size);
+ jh->b_frozen_data = NULL;
+ }
+
+ spin_lock(&journal->j_list_lock);
+ cp_transaction = jh->b_cp_transaction;
+ if (cp_transaction) {
+ JBUFFER_TRACE(jh, "remove from old cp transaction");
+ __jbd2_journal_remove_checkpoint(jh);
+ }
+
+ /* Only re-checkpoint the buffer_head if it is marked
+ * dirty. If the buffer was added to the BJ_Forget list
+ * by jbd2_journal_forget, it may no longer be dirty and
+ * there's no point in keeping a checkpoint record for
+ * it. */
+
+ /* A buffer which has been freed while still being
+ * journaled by a previous transaction may end up still
+ * being dirty here, but we want to avoid writing back
+ * that buffer in the future now that the last use has
+ * been committed. That's not only a performance gain,
+ * it also stops aliasing problems if the buffer is left
+ * behind for writeback and gets reallocated for another
+ * use in a different page. */
+ if (buffer_freed(bh)) {
+ clear_buffer_freed(bh);
+ clear_buffer_jbddirty(bh);
+ }
+
+ if (buffer_jbddirty(bh)) {
+ JBUFFER_TRACE(jh, "add to new checkpointing trans");
+ __jbd2_journal_insert_checkpoint(jh, commit_transaction);
+ JBUFFER_TRACE(jh, "refile for checkpoint writeback");
+ __jbd2_journal_refile_buffer(jh);
+ jbd_unlock_bh_state(bh);
+ } else {
+ J_ASSERT_BH(bh, !buffer_dirty(bh));
+ /* The buffer on BJ_Forget list and not jbddirty means
+ * it has been freed by this transaction and hence it
+ * could not have been reallocated until this
+ * transaction has committed. *BUT* it could be
+ * reallocated once we have written all the data to
+ * disk and before we process the buffer on BJ_Forget
+ * list. */
+ JBUFFER_TRACE(jh, "refile or unfile freed buffer");
+ __jbd2_journal_refile_buffer(jh);
+ if (!jh->b_transaction) {
+ jbd_unlock_bh_state(bh);
+ /* needs a brelse */
+ jbd2_journal_remove_journal_head(bh);
+ release_buffer_page(bh);
+ } else
+ jbd_unlock_bh_state(bh);
+ }
+ cond_resched_lock(&journal->j_list_lock);
+ }
+ spin_unlock(&journal->j_list_lock);
+ /*
+ * This is a bit sleazy. We borrow j_list_lock to protect
+ * journal->j_committing_transaction in __jbd2_journal_remove_checkpoint.
+ * Really, __jbd2_journal_remove_checkpoint should be using j_state_lock but
+ * it's a bit hassle to hold that across __jbd2_journal_remove_checkpoint
+ */
+ spin_lock(&journal->j_state_lock);
+ spin_lock(&journal->j_list_lock);
+ /*
+ * Now recheck if some buffers did not get attached to the transaction
+ * while the lock was dropped...
+ */
+ if (commit_transaction->t_forget) {
+ spin_unlock(&journal->j_list_lock);
+ spin_unlock(&journal->j_state_lock);
+ goto restart_loop;
+ }
+
+ /* Done with this transaction! */
+
+ jbd_debug(3, "JBD: commit phase 8\n");
+
+ J_ASSERT(commit_transaction->t_state == T_COMMIT);
+
+ commit_transaction->t_state = T_FINISHED;
+ J_ASSERT(commit_transaction == journal->j_committing_transaction);
+ journal->j_commit_sequence = commit_transaction->t_tid;
+ journal->j_committing_transaction = NULL;
+ spin_unlock(&journal->j_state_lock);
+
+ if (commit_transaction->t_checkpoint_list == NULL) {
+ __jbd2_journal_drop_transaction(journal, commit_transaction);
+ } else {
+ if (journal->j_checkpoint_transactions == NULL) {
+ journal->j_checkpoint_transactions = commit_transaction;
+ commit_transaction->t_cpnext = commit_transaction;
+ commit_transaction->t_cpprev = commit_transaction;
+ } else {
+ commit_transaction->t_cpnext =
+ journal->j_checkpoint_transactions;
+ commit_transaction->t_cpprev =
+ commit_transaction->t_cpnext->t_cpprev;
+ commit_transaction->t_cpnext->t_cpprev =
+ commit_transaction;
+ commit_transaction->t_cpprev->t_cpnext =
+ commit_transaction;
+ }
+ }
+ spin_unlock(&journal->j_list_lock);
+
+ jbd_debug(1, "JBD: commit %d complete, head %d\n",
+ journal->j_commit_sequence, journal->j_tail_sequence);
+
+ wake_up(&journal->j_wait_done_commit);
+}
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
new file mode 100644
index 000000000000..c60f378b0f76
--- /dev/null
+++ b/fs/jbd2/journal.c
@@ -0,0 +1,2084 @@
+/*
+ * linux/fs/jbd2/journal.c
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Generic filesystem journal-writing code; part of the ext2fs
+ * journaling system.
+ *
+ * This file manages journals: areas of disk reserved for logging
+ * transactional updates. This includes the kernel journaling thread
+ * which is responsible for scheduling updates to the log.
+ *
+ * We do not actually manage the physical storage of the journal in this
+ * file: that is left to a per-journal policy function, which allows us
+ * to store the journal within a filesystem-specified area for ext2
+ * journaling (ext2 can use a reserved inode for storing the log).
+ */
+
+#include <linux/module.h>
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/suspend.h>
+#include <linux/pagemap.h>
+#include <linux/kthread.h>
+#include <linux/poison.h>
+#include <linux/proc_fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/page.h>
+
+EXPORT_SYMBOL(jbd2_journal_start);
+EXPORT_SYMBOL(jbd2_journal_restart);
+EXPORT_SYMBOL(jbd2_journal_extend);
+EXPORT_SYMBOL(jbd2_journal_stop);
+EXPORT_SYMBOL(jbd2_journal_lock_updates);
+EXPORT_SYMBOL(jbd2_journal_unlock_updates);
+EXPORT_SYMBOL(jbd2_journal_get_write_access);
+EXPORT_SYMBOL(jbd2_journal_get_create_access);
+EXPORT_SYMBOL(jbd2_journal_get_undo_access);
+EXPORT_SYMBOL(jbd2_journal_dirty_data);
+EXPORT_SYMBOL(jbd2_journal_dirty_metadata);
+EXPORT_SYMBOL(jbd2_journal_release_buffer);
+EXPORT_SYMBOL(jbd2_journal_forget);
+#if 0
+EXPORT_SYMBOL(journal_sync_buffer);
+#endif
+EXPORT_SYMBOL(jbd2_journal_flush);
+EXPORT_SYMBOL(jbd2_journal_revoke);
+
+EXPORT_SYMBOL(jbd2_journal_init_dev);
+EXPORT_SYMBOL(jbd2_journal_init_inode);
+EXPORT_SYMBOL(jbd2_journal_update_format);
+EXPORT_SYMBOL(jbd2_journal_check_used_features);
+EXPORT_SYMBOL(jbd2_journal_check_available_features);
+EXPORT_SYMBOL(jbd2_journal_set_features);
+EXPORT_SYMBOL(jbd2_journal_create);
+EXPORT_SYMBOL(jbd2_journal_load);
+EXPORT_SYMBOL(jbd2_journal_destroy);
+EXPORT_SYMBOL(jbd2_journal_update_superblock);
+EXPORT_SYMBOL(jbd2_journal_abort);
+EXPORT_SYMBOL(jbd2_journal_errno);
+EXPORT_SYMBOL(jbd2_journal_ack_err);
+EXPORT_SYMBOL(jbd2_journal_clear_err);
+EXPORT_SYMBOL(jbd2_log_wait_commit);
+EXPORT_SYMBOL(jbd2_journal_start_commit);
+EXPORT_SYMBOL(jbd2_journal_force_commit_nested);
+EXPORT_SYMBOL(jbd2_journal_wipe);
+EXPORT_SYMBOL(jbd2_journal_blocks_per_page);
+EXPORT_SYMBOL(jbd2_journal_invalidatepage);
+EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers);
+EXPORT_SYMBOL(jbd2_journal_force_commit);
+
+static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *);
+static void __journal_abort_soft (journal_t *journal, int errno);
+static int jbd2_journal_create_jbd_slab(size_t slab_size);
+
+/*
+ * Helper function used to manage commit timeouts
+ */
+
+static void commit_timeout(unsigned long __data)
+{
+ struct task_struct * p = (struct task_struct *) __data;
+
+ wake_up_process(p);
+}
+
+/*
+ * kjournald2: The main thread function used to manage a logging device
+ * journal.
+ *
+ * This kernel thread is responsible for two things:
+ *
+ * 1) COMMIT: Every so often we need to commit the current state of the
+ * filesystem to disk. The journal thread is responsible for writing
+ * all of the metadata buffers to disk.
+ *
+ * 2) CHECKPOINT: We cannot reuse a used section of the log file until all
+ * of the data in that part of the log has been rewritten elsewhere on
+ * the disk. Flushing these old buffers to reclaim space in the log is
+ * known as checkpointing, and this thread is responsible for that job.
+ */
+
+static int kjournald2(void *arg)
+{
+ journal_t *journal = arg;
+ transaction_t *transaction;
+
+ /*
+ * Set up an interval timer which can be used to trigger a commit wakeup
+ * after the commit interval expires
+ */
+ setup_timer(&journal->j_commit_timer, commit_timeout,
+ (unsigned long)current);
+
+ /* Record that the journal thread is running */
+ journal->j_task = current;
+ wake_up(&journal->j_wait_done_commit);
+
+ printk(KERN_INFO "kjournald2 starting. Commit interval %ld seconds\n",
+ journal->j_commit_interval / HZ);
+
+ /*
+ * And now, wait forever for commit wakeup events.
+ */
+ spin_lock(&journal->j_state_lock);
+
+loop:
+ if (journal->j_flags & JBD2_UNMOUNT)
+ goto end_loop;
+
+ jbd_debug(1, "commit_sequence=%d, commit_request=%d\n",
+ journal->j_commit_sequence, journal->j_commit_request);
+
+ if (journal->j_commit_sequence != journal->j_commit_request) {
+ jbd_debug(1, "OK, requests differ\n");
+ spin_unlock(&journal->j_state_lock);
+ del_timer_sync(&journal->j_commit_timer);
+ jbd2_journal_commit_transaction(journal);
+ spin_lock(&journal->j_state_lock);
+ goto loop;
+ }
+
+ wake_up(&journal->j_wait_done_commit);
+ if (freezing(current)) {
+ /*
+ * The simpler the better. Flushing journal isn't a
+ * good idea, because that depends on threads that may
+ * be already stopped.
+ */
+ jbd_debug(1, "Now suspending kjournald2\n");
+ spin_unlock(&journal->j_state_lock);
+ refrigerator();
+ spin_lock(&journal->j_state_lock);
+ } else {
+ /*
+ * We assume on resume that commits are already there,
+ * so we don't sleep
+ */
+ DEFINE_WAIT(wait);
+ int should_sleep = 1;
+
+ prepare_to_wait(&journal->j_wait_commit, &wait,
+ TASK_INTERRUPTIBLE);
+ if (journal->j_commit_sequence != journal->j_commit_request)
+ should_sleep = 0;
+ transaction = journal->j_running_transaction;
+ if (transaction && time_after_eq(jiffies,
+ transaction->t_expires))
+ should_sleep = 0;
+ if (journal->j_flags & JBD2_UNMOUNT)
+ should_sleep = 0;
+ if (should_sleep) {
+ spin_unlock(&journal->j_state_lock);
+ schedule();
+ spin_lock(&journal->j_state_lock);
+ }
+ finish_wait(&journal->j_wait_commit, &wait);
+ }
+
+ jbd_debug(1, "kjournald2 wakes\n");
+
+ /*
+ * Were we woken up by a commit wakeup event?
+ */
+ transaction = journal->j_running_transaction;
+ if (transaction && time_after_eq(jiffies, transaction->t_expires)) {
+ journal->j_commit_request = transaction->t_tid;
+ jbd_debug(1, "woke because of timeout\n");
+ }
+ goto loop;
+
+end_loop:
+ spin_unlock(&journal->j_state_lock);
+ del_timer_sync(&journal->j_commit_timer);
+ journal->j_task = NULL;
+ wake_up(&journal->j_wait_done_commit);
+ jbd_debug(1, "Journal thread exiting.\n");
+ return 0;
+}
+
+static void jbd2_journal_start_thread(journal_t *journal)
+{
+ kthread_run(kjournald2, journal, "kjournald2");
+ wait_event(journal->j_wait_done_commit, journal->j_task != 0);
+}
+
+static void journal_kill_thread(journal_t *journal)
+{
+ spin_lock(&journal->j_state_lock);
+ journal->j_flags |= JBD2_UNMOUNT;
+
+ while (journal->j_task) {
+ wake_up(&journal->j_wait_commit);
+ spin_unlock(&journal->j_state_lock);
+ wait_event(journal->j_wait_done_commit, journal->j_task == 0);
+ spin_lock(&journal->j_state_lock);
+ }
+ spin_unlock(&journal->j_state_lock);
+}
+
+/*
+ * jbd2_journal_write_metadata_buffer: write a metadata buffer to the journal.
+ *
+ * Writes a metadata buffer to a given disk block. The actual IO is not
+ * performed but a new buffer_head is constructed which labels the data
+ * to be written with the correct destination disk block.
+ *
+ * Any magic-number escaping which needs to be done will cause a
+ * copy-out here. If the buffer happens to start with the
+ * JBD2_MAGIC_NUMBER, then we can't write it to the log directly: the
+ * magic number is only written to the log for descripter blocks. In
+ * this case, we copy the data and replace the first word with 0, and we
+ * return a result code which indicates that this buffer needs to be
+ * marked as an escaped buffer in the corresponding log descriptor
+ * block. The missing word can then be restored when the block is read
+ * during recovery.
+ *
+ * If the source buffer has already been modified by a new transaction
+ * since we took the last commit snapshot, we use the frozen copy of
+ * that data for IO. If we end up using the existing buffer_head's data
+ * for the write, then we *have* to lock the buffer to prevent anyone
+ * else from using and possibly modifying it while the IO is in
+ * progress.
+ *
+ * The function returns a pointer to the buffer_heads to be used for IO.
+ *
+ * We assume that the journal has already been locked in this function.
+ *
+ * Return value:
+ * <0: Error
+ * >=0: Finished OK
+ *
+ * On success:
+ * Bit 0 set == escape performed on the data
+ * Bit 1 set == buffer copy-out performed (kfree the data after IO)
+ */
+
+int jbd2_journal_write_metadata_buffer(transaction_t *transaction,
+ struct journal_head *jh_in,
+ struct journal_head **jh_out,
+ unsigned long long blocknr)
+{
+ int need_copy_out = 0;
+ int done_copy_out = 0;
+ int do_escape = 0;
+ char *mapped_data;
+ struct buffer_head *new_bh;
+ struct journal_head *new_jh;
+ struct page *new_page;
+ unsigned int new_offset;
+ struct buffer_head *bh_in = jh2bh(jh_in);
+
+ /*
+ * The buffer really shouldn't be locked: only the current committing
+ * transaction is allowed to write it, so nobody else is allowed
+ * to do any IO.
+ *
+ * akpm: except if we're journalling data, and write() output is
+ * also part of a shared mapping, and another thread has
+ * decided to launch a writepage() against this buffer.
+ */
+ J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in));
+
+ new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL);
+
+ /*
+ * If a new transaction has already done a buffer copy-out, then
+ * we use that version of the data for the commit.
+ */
+ jbd_lock_bh_state(bh_in);
+repeat:
+ if (jh_in->b_frozen_data) {
+ done_copy_out = 1;
+ new_page = virt_to_page(jh_in->b_frozen_data);
+ new_offset = offset_in_page(jh_in->b_frozen_data);
+ } else {
+ new_page = jh2bh(jh_in)->b_page;
+ new_offset = offset_in_page(jh2bh(jh_in)->b_data);
+ }
+
+ mapped_data = kmap_atomic(new_page, KM_USER0);
+ /*
+ * Check for escaping
+ */
+ if (*((__be32 *)(mapped_data + new_offset)) ==
+ cpu_to_be32(JBD2_MAGIC_NUMBER)) {
+ need_copy_out = 1;
+ do_escape = 1;
+ }
+ kunmap_atomic(mapped_data, KM_USER0);
+
+ /*
+ * Do we need to do a data copy?
+ */
+ if (need_copy_out && !done_copy_out) {
+ char *tmp;
+
+ jbd_unlock_bh_state(bh_in);
+ tmp = jbd2_slab_alloc(bh_in->b_size, GFP_NOFS);
+ jbd_lock_bh_state(bh_in);
+ if (jh_in->b_frozen_data) {
+ jbd2_slab_free(tmp, bh_in->b_size);
+ goto repeat;
+ }
+
+ jh_in->b_frozen_data = tmp;
+ mapped_data = kmap_atomic(new_page, KM_USER0);
+ memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size);
+ kunmap_atomic(mapped_data, KM_USER0);
+
+ new_page = virt_to_page(tmp);
+ new_offset = offset_in_page(tmp);
+ done_copy_out = 1;
+ }
+
+ /*
+ * Did we need to do an escaping? Now we've done all the
+ * copying, we can finally do so.
+ */
+ if (do_escape) {
+ mapped_data = kmap_atomic(new_page, KM_USER0);
+ *((unsigned int *)(mapped_data + new_offset)) = 0;
+ kunmap_atomic(mapped_data, KM_USER0);
+ }
+
+ /* keep subsequent assertions sane */
+ new_bh->b_state = 0;
+ init_buffer(new_bh, NULL, NULL);
+ atomic_set(&new_bh->b_count, 1);
+ jbd_unlock_bh_state(bh_in);
+
+ new_jh = jbd2_journal_add_journal_head(new_bh); /* This sleeps */
+
+ set_bh_page(new_bh, new_page, new_offset);
+ new_jh->b_transaction = NULL;
+ new_bh->b_size = jh2bh(jh_in)->b_size;
+ new_bh->b_bdev = transaction->t_journal->j_dev;
+ new_bh->b_blocknr = blocknr;
+ set_buffer_mapped(new_bh);
+ set_buffer_dirty(new_bh);
+
+ *jh_out = new_jh;
+
+ /*
+ * The to-be-written buffer needs to get moved to the io queue,
+ * and the original buffer whose contents we are shadowing or
+ * copying is moved to the transaction's shadow queue.
+ */
+ JBUFFER_TRACE(jh_in, "file as BJ_Shadow");
+ jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow);
+ JBUFFER_TRACE(new_jh, "file as BJ_IO");
+ jbd2_journal_file_buffer(new_jh, transaction, BJ_IO);
+
+ return do_escape | (done_copy_out << 1);
+}
+
+/*
+ * Allocation code for the journal file. Manage the space left in the
+ * journal, so that we can begin checkpointing when appropriate.
+ */
+
+/*
+ * __jbd2_log_space_left: Return the number of free blocks left in the journal.
+ *
+ * Called with the journal already locked.
+ *
+ * Called under j_state_lock
+ */
+
+int __jbd2_log_space_left(journal_t *journal)
+{
+ int left = journal->j_free;
+
+ assert_spin_locked(&journal->j_state_lock);
+
+ /*
+ * Be pessimistic here about the number of those free blocks which
+ * might be required for log descriptor control blocks.
+ */
+
+#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */
+
+ left -= MIN_LOG_RESERVED_BLOCKS;
+
+ if (left <= 0)
+ return 0;
+ left -= (left >> 3);
+ return left;
+}
+
+/*
+ * Called under j_state_lock. Returns true if a transaction was started.
+ */
+int __jbd2_log_start_commit(journal_t *journal, tid_t target)
+{
+ /*
+ * Are we already doing a recent enough commit?
+ */
+ if (!tid_geq(journal->j_commit_request, target)) {
+ /*
+ * We want a new commit: OK, mark the request and wakup the
+ * commit thread. We do _not_ do the commit ourselves.
+ */
+
+ journal->j_commit_request = target;
+ jbd_debug(1, "JBD: requesting commit %d/%d\n",
+ journal->j_commit_request,
+ journal->j_commit_sequence);
+ wake_up(&journal->j_wait_commit);
+ return 1;
+ }
+ return 0;
+}
+
+int jbd2_log_start_commit(journal_t *journal, tid_t tid)
+{
+ int ret;
+
+ spin_lock(&journal->j_state_lock);
+ ret = __jbd2_log_start_commit(journal, tid);
+ spin_unlock(&journal->j_state_lock);
+ return ret;
+}
+
+/*
+ * Force and wait upon a commit if the calling process is not within
+ * transaction. This is used for forcing out undo-protected data which contains
+ * bitmaps, when the fs is running out of space.
+ *
+ * We can only force the running transaction if we don't have an active handle;
+ * otherwise, we will deadlock.
+ *
+ * Returns true if a transaction was started.
+ */
+int jbd2_journal_force_commit_nested(journal_t *journal)
+{
+ transaction_t *transaction = NULL;
+ tid_t tid;
+
+ spin_lock(&journal->j_state_lock);
+ if (journal->j_running_transaction && !current->journal_info) {
+ transaction = journal->j_running_transaction;
+ __jbd2_log_start_commit(journal, transaction->t_tid);
+ } else if (journal->j_committing_transaction)
+ transaction = journal->j_committing_transaction;
+
+ if (!transaction) {
+ spin_unlock(&journal->j_state_lock);
+ return 0; /* Nothing to retry */
+ }
+
+ tid = transaction->t_tid;
+ spin_unlock(&journal->j_state_lock);
+ jbd2_log_wait_commit(journal, tid);
+ return 1;
+}
+
+/*
+ * Start a commit of the current running transaction (if any). Returns true
+ * if a transaction was started, and fills its tid in at *ptid
+ */
+int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
+{
+ int ret = 0;
+
+ spin_lock(&journal->j_state_lock);
+ if (journal->j_running_transaction) {
+ tid_t tid = journal->j_running_transaction->t_tid;
+
+ ret = __jbd2_log_start_commit(journal, tid);
+ if (ret && ptid)
+ *ptid = tid;
+ } else if (journal->j_committing_transaction && ptid) {
+ /*
+ * If ext3_write_super() recently started a commit, then we
+ * have to wait for completion of that transaction
+ */
+ *ptid = journal->j_committing_transaction->t_tid;
+ ret = 1;
+ }
+ spin_unlock(&journal->j_state_lock);
+ return ret;
+}
+
+/*
+ * Wait for a specified commit to complete.
+ * The caller may not hold the journal lock.
+ */
+int jbd2_log_wait_commit(journal_t *journal, tid_t tid)
+{
+ int err = 0;
+
+#ifdef CONFIG_JBD_DEBUG
+ spin_lock(&journal->j_state_lock);
+ if (!tid_geq(journal->j_commit_request, tid)) {
+ printk(KERN_EMERG
+ "%s: error: j_commit_request=%d, tid=%d\n",
+ __FUNCTION__, journal->j_commit_request, tid);
+ }
+ spin_unlock(&journal->j_state_lock);
+#endif
+ spin_lock(&journal->j_state_lock);
+ while (tid_gt(tid, journal->j_commit_sequence)) {
+ jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n",
+ tid, journal->j_commit_sequence);
+ wake_up(&journal->j_wait_commit);
+ spin_unlock(&journal->j_state_lock);
+ wait_event(journal->j_wait_done_commit,
+ !tid_gt(tid, journal->j_commit_sequence));
+ spin_lock(&journal->j_state_lock);
+ }
+ spin_unlock(&journal->j_state_lock);
+
+ if (unlikely(is_journal_aborted(journal))) {
+ printk(KERN_EMERG "journal commit I/O error\n");
+ err = -EIO;
+ }
+ return err;
+}
+
+/*
+ * Log buffer allocation routines:
+ */
+
+int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp)
+{
+ unsigned long blocknr;
+
+ spin_lock(&journal->j_state_lock);
+ J_ASSERT(journal->j_free > 1);
+
+ blocknr = journal->j_head;
+ journal->j_head++;
+ journal->j_free--;
+ if (journal->j_head == journal->j_last)
+ journal->j_head = journal->j_first;
+ spin_unlock(&journal->j_state_lock);
+ return jbd2_journal_bmap(journal, blocknr, retp);
+}
+
+/*
+ * Conversion of logical to physical block numbers for the journal
+ *
+ * On external journals the journal blocks are identity-mapped, so
+ * this is a no-op. If needed, we can use j_blk_offset - everything is
+ * ready.
+ */
+int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr,
+ unsigned long long *retp)
+{
+ int err = 0;
+ unsigned long long ret;
+
+ if (journal->j_inode) {
+ ret = bmap(journal->j_inode, blocknr);
+ if (ret)
+ *retp = ret;
+ else {
+ char b[BDEVNAME_SIZE];
+
+ printk(KERN_ALERT "%s: journal block not found "
+ "at offset %lu on %s\n",
+ __FUNCTION__,
+ blocknr,
+ bdevname(journal->j_dev, b));
+ err = -EIO;
+ __journal_abort_soft(journal, err);
+ }
+ } else {
+ *retp = blocknr; /* +journal->j_blk_offset */
+ }
+ return err;
+}
+
+/*
+ * We play buffer_head aliasing tricks to write data/metadata blocks to
+ * the journal without copying their contents, but for journal
+ * descriptor blocks we do need to generate bona fide buffers.
+ *
+ * After the caller of jbd2_journal_get_descriptor_buffer() has finished modifying
+ * the buffer's contents they really should run flush_dcache_page(bh->b_page).
+ * But we don't bother doing that, so there will be coherency problems with
+ * mmaps of blockdevs which hold live JBD-controlled filesystems.
+ */
+struct journal_head *jbd2_journal_get_descriptor_buffer(journal_t *journal)
+{
+ struct buffer_head *bh;
+ unsigned long long blocknr;
+ int err;
+
+ err = jbd2_journal_next_log_block(journal, &blocknr);
+
+ if (err)
+ return NULL;
+
+ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ lock_buffer(bh);
+ memset(bh->b_data, 0, journal->j_blocksize);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ BUFFER_TRACE(bh, "return this buffer");
+ return jbd2_journal_add_journal_head(bh);
+}
+
+/*
+ * Management for journal control blocks: functions to create and
+ * destroy journal_t structures, and to initialise and read existing
+ * journal blocks from disk. */
+
+/* First: create and setup a journal_t object in memory. We initialise
+ * very few fields yet: that has to wait until we have created the
+ * journal structures from from scratch, or loaded them from disk. */
+
+static journal_t * journal_init_common (void)
+{
+ journal_t *journal;
+ int err;
+
+ journal = jbd_kmalloc(sizeof(*journal), GFP_KERNEL);
+ if (!journal)
+ goto fail;
+ memset(journal, 0, sizeof(*journal));
+
+ init_waitqueue_head(&journal->j_wait_transaction_locked);
+ init_waitqueue_head(&journal->j_wait_logspace);
+ init_waitqueue_head(&journal->j_wait_done_commit);
+ init_waitqueue_head(&journal->j_wait_checkpoint);
+ init_waitqueue_head(&journal->j_wait_commit);
+ init_waitqueue_head(&journal->j_wait_updates);
+ mutex_init(&journal->j_barrier);
+ mutex_init(&journal->j_checkpoint_mutex);
+ spin_lock_init(&journal->j_revoke_lock);
+ spin_lock_init(&journal->j_list_lock);
+ spin_lock_init(&journal->j_state_lock);
+
+ journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE);
+
+ /* The journal is marked for error until we succeed with recovery! */
+ journal->j_flags = JBD2_ABORT;
+
+ /* Set up a default-sized revoke table for the new mount. */
+ err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH);
+ if (err) {
+ kfree(journal);
+ goto fail;
+ }
+ return journal;
+fail:
+ return NULL;
+}
+
+/* jbd2_journal_init_dev and jbd2_journal_init_inode:
+ *
+ * Create a journal structure assigned some fixed set of disk blocks to
+ * the journal. We don't actually touch those disk blocks yet, but we
+ * need to set up all of the mapping information to tell the journaling
+ * system where the journal blocks are.
+ *
+ */
+
+/**
+ * journal_t * jbd2_journal_init_dev() - creates an initialises a journal structure
+ * @bdev: Block device on which to create the journal
+ * @fs_dev: Device which hold journalled filesystem for this journal.
+ * @start: Block nr Start of journal.
+ * @len: Length of the journal in blocks.
+ * @blocksize: blocksize of journalling device
+ * @returns: a newly created journal_t *
+ *
+ * jbd2_journal_init_dev creates a journal which maps a fixed contiguous
+ * range of blocks on an arbitrary block device.
+ *
+ */
+journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+ struct block_device *fs_dev,
+ unsigned long long start, int len, int blocksize)
+{
+ journal_t *journal = journal_init_common();
+ struct buffer_head *bh;
+ int n;
+
+ if (!journal)
+ return NULL;
+
+ /* journal descriptor can store up to n blocks -bzzz */
+ journal->j_blocksize = blocksize;
+ n = journal->j_blocksize / sizeof(journal_block_tag_t);
+ journal->j_wbufsize = n;
+ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
+ if (!journal->j_wbuf) {
+ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+ __FUNCTION__);
+ kfree(journal);
+ journal = NULL;
+ goto out;
+ }
+ journal->j_dev = bdev;
+ journal->j_fs_dev = fs_dev;
+ journal->j_blk_offset = start;
+ journal->j_maxlen = len;
+
+ bh = __getblk(journal->j_dev, start, journal->j_blocksize);
+ J_ASSERT(bh != NULL);
+ journal->j_sb_buffer = bh;
+ journal->j_superblock = (journal_superblock_t *)bh->b_data;
+out:
+ return journal;
+}
+
+/**
+ * journal_t * jbd2_journal_init_inode () - creates a journal which maps to a inode.
+ * @inode: An inode to create the journal in
+ *
+ * jbd2_journal_init_inode creates a journal which maps an on-disk inode as
+ * the journal. The inode must exist already, must support bmap() and
+ * must have all data blocks preallocated.
+ */
+journal_t * jbd2_journal_init_inode (struct inode *inode)
+{
+ struct buffer_head *bh;
+ journal_t *journal = journal_init_common();
+ int err;
+ int n;
+ unsigned long long blocknr;
+
+ if (!journal)
+ return NULL;
+
+ journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev;
+ journal->j_inode = inode;
+ jbd_debug(1,
+ "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n",
+ journal, inode->i_sb->s_id, inode->i_ino,
+ (long long) inode->i_size,
+ inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
+
+ journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
+ journal->j_blocksize = inode->i_sb->s_blocksize;
+
+ /* journal descriptor can store up to n blocks -bzzz */
+ n = journal->j_blocksize / sizeof(journal_block_tag_t);
+ journal->j_wbufsize = n;
+ journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL);
+ if (!journal->j_wbuf) {
+ printk(KERN_ERR "%s: Cant allocate bhs for commit thread\n",
+ __FUNCTION__);
+ kfree(journal);
+ return NULL;
+ }
+
+ err = jbd2_journal_bmap(journal, 0, &blocknr);
+ /* If that failed, give up */
+ if (err) {
+ printk(KERN_ERR "%s: Cannnot locate journal superblock\n",
+ __FUNCTION__);
+ kfree(journal);
+ return NULL;
+ }
+
+ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ J_ASSERT(bh != NULL);
+ journal->j_sb_buffer = bh;
+ journal->j_superblock = (journal_superblock_t *)bh->b_data;
+
+ return journal;
+}
+
+/*
+ * If the journal init or create aborts, we need to mark the journal
+ * superblock as being NULL to prevent the journal destroy from writing
+ * back a bogus superblock.
+ */
+static void journal_fail_superblock (journal_t *journal)
+{
+ struct buffer_head *bh = journal->j_sb_buffer;
+ brelse(bh);
+ journal->j_sb_buffer = NULL;
+}
+
+/*
+ * Given a journal_t structure, initialise the various fields for
+ * startup of a new journaling session. We use this both when creating
+ * a journal, and after recovering an old journal to reset it for
+ * subsequent use.
+ */
+
+static int journal_reset(journal_t *journal)
+{
+ journal_superblock_t *sb = journal->j_superblock;
+ unsigned long long first, last;
+
+ first = be32_to_cpu(sb->s_first);
+ last = be32_to_cpu(sb->s_maxlen);
+
+ journal->j_first = first;
+ journal->j_last = last;
+
+ journal->j_head = first;
+ journal->j_tail = first;
+ journal->j_free = last - first;
+
+ journal->j_tail_sequence = journal->j_transaction_sequence;
+ journal->j_commit_sequence = journal->j_transaction_sequence - 1;
+ journal->j_commit_request = journal->j_commit_sequence;
+
+ journal->j_max_transaction_buffers = journal->j_maxlen / 4;
+
+ /* Add the dynamic fields and write it to disk. */
+ jbd2_journal_update_superblock(journal, 1);
+ jbd2_journal_start_thread(journal);
+ return 0;
+}
+
+/**
+ * int jbd2_journal_create() - Initialise the new journal file
+ * @journal: Journal to create. This structure must have been initialised
+ *
+ * Given a journal_t structure which tells us which disk blocks we can
+ * use, create a new journal superblock and initialise all of the
+ * journal fields from scratch.
+ **/
+int jbd2_journal_create(journal_t *journal)
+{
+ unsigned long long blocknr;
+ struct buffer_head *bh;
+ journal_superblock_t *sb;
+ int i, err;
+
+ if (journal->j_maxlen < JBD2_MIN_JOURNAL_BLOCKS) {
+ printk (KERN_ERR "Journal length (%d blocks) too short.\n",
+ journal->j_maxlen);
+ journal_fail_superblock(journal);
+ return -EINVAL;
+ }
+
+ if (journal->j_inode == NULL) {
+ /*
+ * We don't know what block to start at!
+ */
+ printk(KERN_EMERG
+ "%s: creation of journal on external device!\n",
+ __FUNCTION__);
+ BUG();
+ }
+
+ /* Zero out the entire journal on disk. We cannot afford to
+ have any blocks on disk beginning with JBD2_MAGIC_NUMBER. */
+ jbd_debug(1, "JBD: Zeroing out journal blocks...\n");
+ for (i = 0; i < journal->j_maxlen; i++) {
+ err = jbd2_journal_bmap(journal, i, &blocknr);
+ if (err)
+ return err;
+ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ lock_buffer(bh);
+ memset (bh->b_data, 0, journal->j_blocksize);
+ BUFFER_TRACE(bh, "marking dirty");
+ mark_buffer_dirty(bh);
+ BUFFER_TRACE(bh, "marking uptodate");
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ __brelse(bh);
+ }
+
+ sync_blockdev(journal->j_dev);
+ jbd_debug(1, "JBD: journal cleared.\n");
+
+ /* OK, fill in the initial static fields in the new superblock */
+ sb = journal->j_superblock;
+
+ sb->s_header.h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
+ sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2);
+
+ sb->s_blocksize = cpu_to_be32(journal->j_blocksize);
+ sb->s_maxlen = cpu_to_be32(journal->j_maxlen);
+ sb->s_first = cpu_to_be32(1);
+
+ journal->j_transaction_sequence = 1;
+
+ journal->j_flags &= ~JBD2_ABORT;
+ journal->j_format_version = 2;
+
+ return journal_reset(journal);
+}
+
+/**
+ * void jbd2_journal_update_superblock() - Update journal sb on disk.
+ * @journal: The journal to update.
+ * @wait: Set to '0' if you don't want to wait for IO completion.
+ *
+ * Update a journal's dynamic superblock fields and write it to disk,
+ * optionally waiting for the IO to complete.
+ */
+void jbd2_journal_update_superblock(journal_t *journal, int wait)
+{
+ journal_superblock_t *sb = journal->j_superblock;
+ struct buffer_head *bh = journal->j_sb_buffer;
+
+ /*
+ * As a special case, if the on-disk copy is already marked as needing
+ * no recovery (s_start == 0) and there are no outstanding transactions
+ * in the filesystem, then we can safely defer the superblock update
+ * until the next commit by setting JBD2_FLUSHED. This avoids
+ * attempting a write to a potential-readonly device.
+ */
+ if (sb->s_start == 0 && journal->j_tail_sequence ==
+ journal->j_transaction_sequence) {
+ jbd_debug(1,"JBD: Skipping superblock update on recovered sb "
+ "(start %ld, seq %d, errno %d)\n",
+ journal->j_tail, journal->j_tail_sequence,
+ journal->j_errno);
+ goto out;
+ }
+
+ spin_lock(&journal->j_state_lock);
+ jbd_debug(1,"JBD: updating superblock (start %ld, seq %d, errno %d)\n",
+ journal->j_tail, journal->j_tail_sequence, journal->j_errno);
+
+ sb->s_sequence = cpu_to_be32(journal->j_tail_sequence);
+ sb->s_start = cpu_to_be32(journal->j_tail);
+ sb->s_errno = cpu_to_be32(journal->j_errno);
+ spin_unlock(&journal->j_state_lock);
+
+ BUFFER_TRACE(bh, "marking dirty");
+ mark_buffer_dirty(bh);
+ if (wait)
+ sync_dirty_buffer(bh);
+ else
+ ll_rw_block(SWRITE, 1, &bh);
+
+out:
+ /* If we have just flushed the log (by marking s_start==0), then
+ * any future commit will have to be careful to update the
+ * superblock again to re-record the true start of the log. */
+
+ spin_lock(&journal->j_state_lock);
+ if (sb->s_start)
+ journal->j_flags &= ~JBD2_FLUSHED;
+ else
+ journal->j_flags |= JBD2_FLUSHED;
+ spin_unlock(&journal->j_state_lock);
+}
+
+/*
+ * Read the superblock for a given journal, performing initial
+ * validation of the format.
+ */
+
+static int journal_get_superblock(journal_t *journal)
+{
+ struct buffer_head *bh;
+ journal_superblock_t *sb;
+ int err = -EIO;
+
+ bh = journal->j_sb_buffer;
+
+ J_ASSERT(bh != NULL);
+ if (!buffer_uptodate(bh)) {
+ ll_rw_block(READ, 1, &bh);
+ wait_on_buffer(bh);
+ if (!buffer_uptodate(bh)) {
+ printk (KERN_ERR
+ "JBD: IO error reading journal superblock\n");
+ goto out;
+ }
+ }
+
+ sb = journal->j_superblock;
+
+ err = -EINVAL;
+
+ if (sb->s_header.h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER) ||
+ sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) {
+ printk(KERN_WARNING "JBD: no valid journal superblock found\n");
+ goto out;
+ }
+
+ switch(be32_to_cpu(sb->s_header.h_blocktype)) {
+ case JBD2_SUPERBLOCK_V1:
+ journal->j_format_version = 1;
+ break;
+ case JBD2_SUPERBLOCK_V2:
+ journal->j_format_version = 2;
+ break;
+ default:
+ printk(KERN_WARNING "JBD: unrecognised superblock format ID\n");
+ goto out;
+ }
+
+ if (be32_to_cpu(sb->s_maxlen) < journal->j_maxlen)
+ journal->j_maxlen = be32_to_cpu(sb->s_maxlen);
+ else if (be32_to_cpu(sb->s_maxlen) > journal->j_maxlen) {
+ printk (KERN_WARNING "JBD: journal file too short\n");
+ goto out;
+ }
+
+ return 0;
+
+out:
+ journal_fail_superblock(journal);
+ return err;
+}
+
+/*
+ * Load the on-disk journal superblock and read the key fields into the
+ * journal_t.
+ */
+
+static int load_superblock(journal_t *journal)
+{
+ int err;
+ journal_superblock_t *sb;
+
+ err = journal_get_superblock(journal);
+ if (err)
+ return err;
+
+ sb = journal->j_superblock;
+
+ journal->j_tail_sequence = be32_to_cpu(sb->s_sequence);
+ journal->j_tail = be32_to_cpu(sb->s_start);
+ journal->j_first = be32_to_cpu(sb->s_first);
+ journal->j_last = be32_to_cpu(sb->s_maxlen);
+ journal->j_errno = be32_to_cpu(sb->s_errno);
+
+ return 0;
+}
+
+
+/**
+ * int jbd2_journal_load() - Read journal from disk.
+ * @journal: Journal to act on.
+ *
+ * Given a journal_t structure which tells us which disk blocks contain
+ * a journal, read the journal from disk to initialise the in-memory
+ * structures.
+ */
+int jbd2_journal_load(journal_t *journal)
+{
+ int err;
+ journal_superblock_t *sb;
+
+ err = load_superblock(journal);
+ if (err)
+ return err;
+
+ sb = journal->j_superblock;
+ /* If this is a V2 superblock, then we have to check the
+ * features flags on it. */
+
+ if (journal->j_format_version >= 2) {
+ if ((sb->s_feature_ro_compat &
+ ~cpu_to_be32(JBD2_KNOWN_ROCOMPAT_FEATURES)) ||
+ (sb->s_feature_incompat &
+ ~cpu_to_be32(JBD2_KNOWN_INCOMPAT_FEATURES))) {
+ printk (KERN_WARNING
+ "JBD: Unrecognised features on journal\n");
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * Create a slab for this blocksize
+ */
+ err = jbd2_journal_create_jbd_slab(be32_to_cpu(sb->s_blocksize));
+ if (err)
+ return err;
+
+ /* Let the recovery code check whether it needs to recover any
+ * data from the journal. */
+ if (jbd2_journal_recover(journal))
+ goto recovery_error;
+
+ /* OK, we've finished with the dynamic journal bits:
+ * reinitialise the dynamic contents of the superblock in memory
+ * and reset them on disk. */
+ if (journal_reset(journal))
+ goto recovery_error;
+
+ journal->j_flags &= ~JBD2_ABORT;
+ journal->j_flags |= JBD2_LOADED;
+ return 0;
+
+recovery_error:
+ printk (KERN_WARNING "JBD: recovery failed\n");
+ return -EIO;
+}
+
+/**
+ * void jbd2_journal_destroy() - Release a journal_t structure.
+ * @journal: Journal to act on.
+ *
+ * Release a journal_t structure once it is no longer in use by the
+ * journaled object.
+ */
+void jbd2_journal_destroy(journal_t *journal)
+{
+ /* Wait for the commit thread to wake up and die. */
+ journal_kill_thread(journal);
+
+ /* Force a final log commit */
+ if (journal->j_running_transaction)
+ jbd2_journal_commit_transaction(journal);
+
+ /* Force any old transactions to disk */
+
+ /* Totally anal locking here... */
+ spin_lock(&journal->j_list_lock);
+ while (journal->j_checkpoint_transactions != NULL) {
+ spin_unlock(&journal->j_list_lock);
+ jbd2_log_do_checkpoint(journal);
+ spin_lock(&journal->j_list_lock);
+ }
+
+ J_ASSERT(journal->j_running_transaction == NULL);
+ J_ASSERT(journal->j_committing_transaction == NULL);
+ J_ASSERT(journal->j_checkpoint_transactions == NULL);
+ spin_unlock(&journal->j_list_lock);
+
+ /* We can now mark the journal as empty. */
+ journal->j_tail = 0;
+ journal->j_tail_sequence = ++journal->j_transaction_sequence;
+ if (journal->j_sb_buffer) {
+ jbd2_journal_update_superblock(journal, 1);
+ brelse(journal->j_sb_buffer);
+ }
+
+ if (journal->j_inode)
+ iput(journal->j_inode);
+ if (journal->j_revoke)
+ jbd2_journal_destroy_revoke(journal);
+ kfree(journal->j_wbuf);
+ kfree(journal);
+}
+
+
+/**
+ *int jbd2_journal_check_used_features () - Check if features specified are used.
+ * @journal: Journal to check.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
+ *
+ * Check whether the journal uses all of a given set of
+ * features. Return true (non-zero) if it does.
+ **/
+
+int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat,
+ unsigned long ro, unsigned long incompat)
+{
+ journal_superblock_t *sb;
+
+ if (!compat && !ro && !incompat)
+ return 1;
+ if (journal->j_format_version == 1)
+ return 0;
+
+ sb = journal->j_superblock;
+
+ if (((be32_to_cpu(sb->s_feature_compat) & compat) == compat) &&
+ ((be32_to_cpu(sb->s_feature_ro_compat) & ro) == ro) &&
+ ((be32_to_cpu(sb->s_feature_incompat) & incompat) == incompat))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * int jbd2_journal_check_available_features() - Check feature set in journalling layer
+ * @journal: Journal to check.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
+ *
+ * Check whether the journaling code supports the use of
+ * all of a given set of features on this journal. Return true
+ * (non-zero) if it can. */
+
+int jbd2_journal_check_available_features (journal_t *journal, unsigned long compat,
+ unsigned long ro, unsigned long incompat)
+{
+ journal_superblock_t *sb;
+
+ if (!compat && !ro && !incompat)
+ return 1;
+
+ sb = journal->j_superblock;
+
+ /* We can support any known requested features iff the
+ * superblock is in version 2. Otherwise we fail to support any
+ * extended sb features. */
+
+ if (journal->j_format_version != 2)
+ return 0;
+
+ if ((compat & JBD2_KNOWN_COMPAT_FEATURES) == compat &&
+ (ro & JBD2_KNOWN_ROCOMPAT_FEATURES) == ro &&
+ (incompat & JBD2_KNOWN_INCOMPAT_FEATURES) == incompat)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * int jbd2_journal_set_features () - Mark a given journal feature in the superblock
+ * @journal: Journal to act on.
+ * @compat: bitmask of compatible features
+ * @ro: bitmask of features that force read-only mount
+ * @incompat: bitmask of incompatible features
+ *
+ * Mark a given journal feature as present on the
+ * superblock. Returns true if the requested features could be set.
+ *
+ */
+
+int jbd2_journal_set_features (journal_t *journal, unsigned long compat,
+ unsigned long ro, unsigned long incompat)
+{
+ journal_superblock_t *sb;
+
+ if (jbd2_journal_check_used_features(journal, compat, ro, incompat))
+ return 1;
+
+ if (!jbd2_journal_check_available_features(journal, compat, ro, incompat))
+ return 0;
+
+ jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n",
+ compat, ro, incompat);
+
+ sb = journal->j_superblock;
+
+ sb->s_feature_compat |= cpu_to_be32(compat);
+ sb->s_feature_ro_compat |= cpu_to_be32(ro);
+ sb->s_feature_incompat |= cpu_to_be32(incompat);
+
+ return 1;
+}
+
+
+/**
+ * int jbd2_journal_update_format () - Update on-disk journal structure.
+ * @journal: Journal to act on.
+ *
+ * Given an initialised but unloaded journal struct, poke about in the
+ * on-disk structure to update it to the most recent supported version.
+ */
+int jbd2_journal_update_format (journal_t *journal)
+{
+ journal_superblock_t *sb;
+ int err;
+
+ err = journal_get_superblock(journal);
+ if (err)
+ return err;
+
+ sb = journal->j_superblock;
+
+ switch (be32_to_cpu(sb->s_header.h_blocktype)) {
+ case JBD2_SUPERBLOCK_V2:
+ return 0;
+ case JBD2_SUPERBLOCK_V1:
+ return journal_convert_superblock_v1(journal, sb);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int journal_convert_superblock_v1(journal_t *journal,
+ journal_superblock_t *sb)
+{
+ int offset, blocksize;
+ struct buffer_head *bh;
+
+ printk(KERN_WARNING
+ "JBD: Converting superblock from version 1 to 2.\n");
+
+ /* Pre-initialise new fields to zero */
+ offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb);
+ blocksize = be32_to_cpu(sb->s_blocksize);
+ memset(&sb->s_feature_compat, 0, blocksize-offset);
+
+ sb->s_nr_users = cpu_to_be32(1);
+ sb->s_header.h_blocktype = cpu_to_be32(JBD2_SUPERBLOCK_V2);
+ journal->j_format_version = 2;
+
+ bh = journal->j_sb_buffer;
+ BUFFER_TRACE(bh, "marking dirty");
+ mark_buffer_dirty(bh);
+ sync_dirty_buffer(bh);
+ return 0;
+}
+
+
+/**
+ * int jbd2_journal_flush () - Flush journal
+ * @journal: Journal to act on.
+ *
+ * Flush all data for a given journal to disk and empty the journal.
+ * Filesystems can use this when remounting readonly to ensure that
+ * recovery does not need to happen on remount.
+ */
+
+int jbd2_journal_flush(journal_t *journal)
+{
+ int err = 0;
+ transaction_t *transaction = NULL;
+ unsigned long old_tail;
+
+ spin_lock(&journal->j_state_lock);
+
+ /* Force everything buffered to the log... */
+ if (journal->j_running_transaction) {
+ transaction = journal->j_running_transaction;
+ __jbd2_log_start_commit(journal, transaction->t_tid);
+ } else if (journal->j_committing_transaction)
+ transaction = journal->j_committing_transaction;
+
+ /* Wait for the log commit to complete... */
+ if (transaction) {
+ tid_t tid = transaction->t_tid;
+
+ spin_unlock(&journal->j_state_lock);
+ jbd2_log_wait_commit(journal, tid);
+ } else {
+ spin_unlock(&journal->j_state_lock);
+ }
+
+ /* ...and flush everything in the log out to disk. */
+ spin_lock(&journal->j_list_lock);
+ while (!err && journal->j_checkpoint_transactions != NULL) {
+ spin_unlock(&journal->j_list_lock);
+ err = jbd2_log_do_checkpoint(journal);
+ spin_lock(&journal->j_list_lock);
+ }
+ spin_unlock(&journal->j_list_lock);
+ jbd2_cleanup_journal_tail(journal);
+
+ /* Finally, mark the journal as really needing no recovery.
+ * This sets s_start==0 in the underlying superblock, which is
+ * the magic code for a fully-recovered superblock. Any future
+ * commits of data to the journal will restore the current
+ * s_start value. */
+ spin_lock(&journal->j_state_lock);
+ old_tail = journal->j_tail;
+ journal->j_tail = 0;
+ spin_unlock(&journal->j_state_lock);
+ jbd2_journal_update_superblock(journal, 1);
+ spin_lock(&journal->j_state_lock);
+ journal->j_tail = old_tail;
+
+ J_ASSERT(!journal->j_running_transaction);
+ J_ASSERT(!journal->j_committing_transaction);
+ J_ASSERT(!journal->j_checkpoint_transactions);
+ J_ASSERT(journal->j_head == journal->j_tail);
+ J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence);
+ spin_unlock(&journal->j_state_lock);
+ return err;
+}
+
+/**
+ * int jbd2_journal_wipe() - Wipe journal contents
+ * @journal: Journal to act on.
+ * @write: flag (see below)
+ *
+ * Wipe out all of the contents of a journal, safely. This will produce
+ * a warning if the journal contains any valid recovery information.
+ * Must be called between journal_init_*() and jbd2_journal_load().
+ *
+ * If 'write' is non-zero, then we wipe out the journal on disk; otherwise
+ * we merely suppress recovery.
+ */
+
+int jbd2_journal_wipe(journal_t *journal, int write)
+{
+ journal_superblock_t *sb;
+ int err = 0;
+
+ J_ASSERT (!(journal->j_flags & JBD2_LOADED));
+
+ err = load_superblock(journal);
+ if (err)
+ return err;
+
+ sb = journal->j_superblock;
+
+ if (!journal->j_tail)
+ goto no_recovery;
+
+ printk (KERN_WARNING "JBD: %s recovery information on journal\n",
+ write ? "Clearing" : "Ignoring");
+
+ err = jbd2_journal_skip_recovery(journal);
+ if (write)
+ jbd2_journal_update_superblock(journal, 1);
+
+ no_recovery:
+ return err;
+}
+
+/*
+ * journal_dev_name: format a character string to describe on what
+ * device this journal is present.
+ */
+
+static const char *journal_dev_name(journal_t *journal, char *buffer)
+{
+ struct block_device *bdev;
+
+ if (journal->j_inode)
+ bdev = journal->j_inode->i_sb->s_bdev;
+ else
+ bdev = journal->j_dev;
+
+ return bdevname(bdev, buffer);
+}
+
+/*
+ * Journal abort has very specific semantics, which we describe
+ * for journal abort.
+ *
+ * Two internal function, which provide abort to te jbd layer
+ * itself are here.
+ */
+
+/*
+ * Quick version for internal journal use (doesn't lock the journal).
+ * Aborts hard --- we mark the abort as occurred, but do _nothing_ else,
+ * and don't attempt to make any other journal updates.
+ */
+void __jbd2_journal_abort_hard(journal_t *journal)
+{
+ transaction_t *transaction;
+ char b[BDEVNAME_SIZE];
+
+ if (journal->j_flags & JBD2_ABORT)
+ return;
+
+ printk(KERN_ERR "Aborting journal on device %s.\n",
+ journal_dev_name(journal, b));
+
+ spin_lock(&journal->j_state_lock);
+ journal->j_flags |= JBD2_ABORT;
+ transaction = journal->j_running_transaction;
+ if (transaction)
+ __jbd2_log_start_commit(journal, transaction->t_tid);
+ spin_unlock(&journal->j_state_lock);
+}
+
+/* Soft abort: record the abort error status in the journal superblock,
+ * but don't do any other IO. */
+static void __journal_abort_soft (journal_t *journal, int errno)
+{
+ if (journal->j_flags & JBD2_ABORT)
+ return;
+
+ if (!journal->j_errno)
+ journal->j_errno = errno;
+
+ __jbd2_journal_abort_hard(journal);
+
+ if (errno)
+ jbd2_journal_update_superblock(journal, 1);
+}
+
+/**
+ * void jbd2_journal_abort () - Shutdown the journal immediately.
+ * @journal: the journal to shutdown.
+ * @errno: an error number to record in the journal indicating
+ * the reason for the shutdown.
+ *
+ * Perform a complete, immediate shutdown of the ENTIRE
+ * journal (not of a single transaction). This operation cannot be
+ * undone without closing and reopening the journal.
+ *
+ * The jbd2_journal_abort function is intended to support higher level error
+ * recovery mechanisms such as the ext2/ext3 remount-readonly error
+ * mode.
+ *
+ * Journal abort has very specific semantics. Any existing dirty,
+ * unjournaled buffers in the main filesystem will still be written to
+ * disk by bdflush, but the journaling mechanism will be suspended
+ * immediately and no further transaction commits will be honoured.
+ *
+ * Any dirty, journaled buffers will be written back to disk without
+ * hitting the journal. Atomicity cannot be guaranteed on an aborted
+ * filesystem, but we _do_ attempt to leave as much data as possible
+ * behind for fsck to use for cleanup.
+ *
+ * Any attempt to get a new transaction handle on a journal which is in
+ * ABORT state will just result in an -EROFS error return. A
+ * jbd2_journal_stop on an existing handle will return -EIO if we have
+ * entered abort state during the update.
+ *
+ * Recursive transactions are not disturbed by journal abort until the
+ * final jbd2_journal_stop, which will receive the -EIO error.
+ *
+ * Finally, the jbd2_journal_abort call allows the caller to supply an errno
+ * which will be recorded (if possible) in the journal superblock. This
+ * allows a client to record failure conditions in the middle of a
+ * transaction without having to complete the transaction to record the
+ * failure to disk. ext3_error, for example, now uses this
+ * functionality.
+ *
+ * Errors which originate from within the journaling layer will NOT
+ * supply an errno; a null errno implies that absolutely no further
+ * writes are done to the journal (unless there are any already in
+ * progress).
+ *
+ */
+
+void jbd2_journal_abort(journal_t *journal, int errno)
+{
+ __journal_abort_soft(journal, errno);
+}
+
+/**
+ * int jbd2_journal_errno () - returns the journal's error state.
+ * @journal: journal to examine.
+ *
+ * This is the errno numbet set with jbd2_journal_abort(), the last
+ * time the journal was mounted - if the journal was stopped
+ * without calling abort this will be 0.
+ *
+ * If the journal has been aborted on this mount time -EROFS will
+ * be returned.
+ */
+int jbd2_journal_errno(journal_t *journal)
+{
+ int err;
+
+ spin_lock(&journal->j_state_lock);
+ if (journal->j_flags & JBD2_ABORT)
+ err = -EROFS;
+ else
+ err = journal->j_errno;
+ spin_unlock(&journal->j_state_lock);
+ return err;
+}
+
+/**
+ * int jbd2_journal_clear_err () - clears the journal's error state
+ * @journal: journal to act on.
+ *
+ * An error must be cleared or Acked to take a FS out of readonly
+ * mode.
+ */
+int jbd2_journal_clear_err(journal_t *journal)
+{
+ int err = 0;
+
+ spin_lock(&journal->j_state_lock);
+ if (journal->j_flags & JBD2_ABORT)
+ err = -EROFS;
+ else
+ journal->j_errno = 0;
+ spin_unlock(&journal->j_state_lock);
+ return err;
+}
+
+/**
+ * void jbd2_journal_ack_err() - Ack journal err.
+ * @journal: journal to act on.
+ *
+ * An error must be cleared or Acked to take a FS out of readonly
+ * mode.
+ */
+void jbd2_journal_ack_err(journal_t *journal)
+{
+ spin_lock(&journal->j_state_lock);
+ if (journal->j_errno)
+ journal->j_flags |= JBD2_ACK_ERR;
+ spin_unlock(&journal->j_state_lock);
+}
+
+int jbd2_journal_blocks_per_page(struct inode *inode)
+{
+ return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits);
+}
+
+/*
+ * helper functions to deal with 32 or 64bit block numbers.
+ */
+size_t journal_tag_bytes(journal_t *journal)
+{
+ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+ return JBD_TAG_SIZE64;
+ else
+ return JBD_TAG_SIZE32;
+}
+
+/*
+ * Simple support for retrying memory allocations. Introduced to help to
+ * debug different VM deadlock avoidance strategies.
+ */
+void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry)
+{
+ return kmalloc(size, flags | (retry ? __GFP_NOFAIL : 0));
+}
+
+/*
+ * jbd slab management: create 1k, 2k, 4k, 8k slabs as needed
+ * and allocate frozen and commit buffers from these slabs.
+ *
+ * Reason for doing this is to avoid, SLAB_DEBUG - since it could
+ * cause bh to cross page boundary.
+ */
+
+#define JBD_MAX_SLABS 5
+#define JBD_SLAB_INDEX(size) (size >> 11)
+
+static kmem_cache_t *jbd_slab[JBD_MAX_SLABS];
+static const char *jbd_slab_names[JBD_MAX_SLABS] = {
+ "jbd2_1k", "jbd2_2k", "jbd2_4k", NULL, "jbd2_8k"
+};
+
+static void jbd2_journal_destroy_jbd_slabs(void)
+{
+ int i;
+
+ for (i = 0; i < JBD_MAX_SLABS; i++) {
+ if (jbd_slab[i])
+ kmem_cache_destroy(jbd_slab[i]);
+ jbd_slab[i] = NULL;
+ }
+}
+
+static int jbd2_journal_create_jbd_slab(size_t slab_size)
+{
+ int i = JBD_SLAB_INDEX(slab_size);
+
+ BUG_ON(i >= JBD_MAX_SLABS);
+
+ /*
+ * Check if we already have a slab created for this size
+ */
+ if (jbd_slab[i])
+ return 0;
+
+ /*
+ * Create a slab and force alignment to be same as slabsize -
+ * this will make sure that allocations won't cross the page
+ * boundary.
+ */
+ jbd_slab[i] = kmem_cache_create(jbd_slab_names[i],
+ slab_size, slab_size, 0, NULL, NULL);
+ if (!jbd_slab[i]) {
+ printk(KERN_EMERG "JBD: no memory for jbd_slab cache\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void * jbd2_slab_alloc(size_t size, gfp_t flags)
+{
+ int idx;
+
+ idx = JBD_SLAB_INDEX(size);
+ BUG_ON(jbd_slab[idx] == NULL);
+ return kmem_cache_alloc(jbd_slab[idx], flags | __GFP_NOFAIL);
+}
+
+void jbd2_slab_free(void *ptr, size_t size)
+{
+ int idx;
+
+ idx = JBD_SLAB_INDEX(size);
+ BUG_ON(jbd_slab[idx] == NULL);
+ kmem_cache_free(jbd_slab[idx], ptr);
+}
+
+/*
+ * Journal_head storage management
+ */
+static kmem_cache_t *jbd2_journal_head_cache;
+#ifdef CONFIG_JBD_DEBUG
+static atomic_t nr_journal_heads = ATOMIC_INIT(0);
+#endif
+
+static int journal_init_jbd2_journal_head_cache(void)
+{
+ int retval;
+
+ J_ASSERT(jbd2_journal_head_cache == 0);
+ jbd2_journal_head_cache = kmem_cache_create("jbd2_journal_head",
+ sizeof(struct journal_head),
+ 0, /* offset */
+ 0, /* flags */
+ NULL, /* ctor */
+ NULL); /* dtor */
+ retval = 0;
+ if (jbd2_journal_head_cache == 0) {
+ retval = -ENOMEM;
+ printk(KERN_EMERG "JBD: no memory for journal_head cache\n");
+ }
+ return retval;
+}
+
+static void jbd2_journal_destroy_jbd2_journal_head_cache(void)
+{
+ J_ASSERT(jbd2_journal_head_cache != NULL);
+ kmem_cache_destroy(jbd2_journal_head_cache);
+ jbd2_journal_head_cache = NULL;
+}
+
+/*
+ * journal_head splicing and dicing
+ */
+static struct journal_head *journal_alloc_journal_head(void)
+{
+ struct journal_head *ret;
+ static unsigned long last_warning;
+
+#ifdef CONFIG_JBD_DEBUG
+ atomic_inc(&nr_journal_heads);
+#endif
+ ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
+ if (ret == 0) {
+ jbd_debug(1, "out of memory for journal_head\n");
+ if (time_after(jiffies, last_warning + 5*HZ)) {
+ printk(KERN_NOTICE "ENOMEM in %s, retrying.\n",
+ __FUNCTION__);
+ last_warning = jiffies;
+ }
+ while (ret == 0) {
+ yield();
+ ret = kmem_cache_alloc(jbd2_journal_head_cache, GFP_NOFS);
+ }
+ }
+ return ret;
+}
+
+static void journal_free_journal_head(struct journal_head *jh)
+{
+#ifdef CONFIG_JBD_DEBUG
+ atomic_dec(&nr_journal_heads);
+ memset(jh, JBD_POISON_FREE, sizeof(*jh));
+#endif
+ kmem_cache_free(jbd2_journal_head_cache, jh);
+}
+
+/*
+ * A journal_head is attached to a buffer_head whenever JBD has an
+ * interest in the buffer.
+ *
+ * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit
+ * is set. This bit is tested in core kernel code where we need to take
+ * JBD-specific actions. Testing the zeroness of ->b_private is not reliable
+ * there.
+ *
+ * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one.
+ *
+ * When a buffer has its BH_JBD bit set it is immune from being released by
+ * core kernel code, mainly via ->b_count.
+ *
+ * A journal_head may be detached from its buffer_head when the journal_head's
+ * b_transaction, b_cp_transaction and b_next_transaction pointers are NULL.
+ * Various places in JBD call jbd2_journal_remove_journal_head() to indicate that the
+ * journal_head can be dropped if needed.
+ *
+ * Various places in the kernel want to attach a journal_head to a buffer_head
+ * _before_ attaching the journal_head to a transaction. To protect the
+ * journal_head in this situation, jbd2_journal_add_journal_head elevates the
+ * journal_head's b_jcount refcount by one. The caller must call
+ * jbd2_journal_put_journal_head() to undo this.
+ *
+ * So the typical usage would be:
+ *
+ * (Attach a journal_head if needed. Increments b_jcount)
+ * struct journal_head *jh = jbd2_journal_add_journal_head(bh);
+ * ...
+ * jh->b_transaction = xxx;
+ * jbd2_journal_put_journal_head(jh);
+ *
+ * Now, the journal_head's b_jcount is zero, but it is safe from being released
+ * because it has a non-zero b_transaction.
+ */
+
+/*
+ * Give a buffer_head a journal_head.
+ *
+ * Doesn't need the journal lock.
+ * May sleep.
+ */
+struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh)
+{
+ struct journal_head *jh;
+ struct journal_head *new_jh = NULL;
+
+repeat:
+ if (!buffer_jbd(bh)) {
+ new_jh = journal_alloc_journal_head();
+ memset(new_jh, 0, sizeof(*new_jh));
+ }
+
+ jbd_lock_bh_journal_head(bh);
+ if (buffer_jbd(bh)) {
+ jh = bh2jh(bh);
+ } else {
+ J_ASSERT_BH(bh,
+ (atomic_read(&bh->b_count) > 0) ||
+ (bh->b_page && bh->b_page->mapping));
+
+ if (!new_jh) {
+ jbd_unlock_bh_journal_head(bh);
+ goto repeat;
+ }
+
+ jh = new_jh;
+ new_jh = NULL; /* We consumed it */
+ set_buffer_jbd(bh);
+ bh->b_private = jh;
+ jh->b_bh = bh;
+ get_bh(bh);
+ BUFFER_TRACE(bh, "added journal_head");
+ }
+ jh->b_jcount++;
+ jbd_unlock_bh_journal_head(bh);
+ if (new_jh)
+ journal_free_journal_head(new_jh);
+ return bh->b_private;
+}
+
+/*
+ * Grab a ref against this buffer_head's journal_head. If it ended up not
+ * having a journal_head, return NULL
+ */
+struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh)
+{
+ struct journal_head *jh = NULL;
+
+ jbd_lock_bh_journal_head(bh);
+ if (buffer_jbd(bh)) {
+ jh = bh2jh(bh);
+ jh->b_jcount++;
+ }
+ jbd_unlock_bh_journal_head(bh);
+ return jh;
+}
+
+static void __journal_remove_journal_head(struct buffer_head *bh)
+{
+ struct journal_head *jh = bh2jh(bh);
+
+ J_ASSERT_JH(jh, jh->b_jcount >= 0);
+
+ get_bh(bh);
+ if (jh->b_jcount == 0) {
+ if (jh->b_transaction == NULL &&
+ jh->b_next_transaction == NULL &&
+ jh->b_cp_transaction == NULL) {
+ J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
+ J_ASSERT_BH(bh, buffer_jbd(bh));
+ J_ASSERT_BH(bh, jh2bh(jh) == bh);
+ BUFFER_TRACE(bh, "remove journal_head");
+ if (jh->b_frozen_data) {
+ printk(KERN_WARNING "%s: freeing "
+ "b_frozen_data\n",
+ __FUNCTION__);
+ jbd2_slab_free(jh->b_frozen_data, bh->b_size);
+ }
+ if (jh->b_committed_data) {
+ printk(KERN_WARNING "%s: freeing "
+ "b_committed_data\n",
+ __FUNCTION__);
+ jbd2_slab_free(jh->b_committed_data, bh->b_size);
+ }
+ bh->b_private = NULL;
+ jh->b_bh = NULL; /* debug, really */
+ clear_buffer_jbd(bh);
+ __brelse(bh);
+ journal_free_journal_head(jh);
+ } else {
+ BUFFER_TRACE(bh, "journal_head was locked");
+ }
+ }
+}
+
+/*
+ * jbd2_journal_remove_journal_head(): if the buffer isn't attached to a transaction
+ * and has a zero b_jcount then remove and release its journal_head. If we did
+ * see that the buffer is not used by any transaction we also "logically"
+ * decrement ->b_count.
+ *
+ * We in fact take an additional increment on ->b_count as a convenience,
+ * because the caller usually wants to do additional things with the bh
+ * after calling here.
+ * The caller of jbd2_journal_remove_journal_head() *must* run __brelse(bh) at some
+ * time. Once the caller has run __brelse(), the buffer is eligible for
+ * reaping by try_to_free_buffers().
+ */
+void jbd2_journal_remove_journal_head(struct buffer_head *bh)
+{
+ jbd_lock_bh_journal_head(bh);
+ __journal_remove_journal_head(bh);
+ jbd_unlock_bh_journal_head(bh);
+}
+
+/*
+ * Drop a reference on the passed journal_head. If it fell to zero then try to
+ * release the journal_head from the buffer_head.
+ */
+void jbd2_journal_put_journal_head(struct journal_head *jh)
+{
+ struct buffer_head *bh = jh2bh(jh);
+
+ jbd_lock_bh_journal_head(bh);
+ J_ASSERT_JH(jh, jh->b_jcount > 0);
+ --jh->b_jcount;
+ if (!jh->b_jcount && !jh->b_transaction) {
+ __journal_remove_journal_head(bh);
+ __brelse(bh);
+ }
+ jbd_unlock_bh_journal_head(bh);
+}
+
+/*
+ * /proc tunables
+ */
+#if defined(CONFIG_JBD_DEBUG)
+int jbd2_journal_enable_debug;
+EXPORT_SYMBOL(jbd2_journal_enable_debug);
+#endif
+
+#if defined(CONFIG_JBD_DEBUG) && defined(CONFIG_PROC_FS)
+
+static struct proc_dir_entry *proc_jbd_debug;
+
+static int read_jbd_debug(char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int ret;
+
+ ret = sprintf(page + off, "%d\n", jbd2_journal_enable_debug);
+ *eof = 1;
+ return ret;
+}
+
+static int write_jbd_debug(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ char buf[32];
+
+ if (count > ARRAY_SIZE(buf) - 1)
+ count = ARRAY_SIZE(buf) - 1;
+ if (copy_from_user(buf, buffer, count))
+ return -EFAULT;
+ buf[ARRAY_SIZE(buf) - 1] = '\0';
+ jbd2_journal_enable_debug = simple_strtoul(buf, NULL, 10);
+ return count;
+}
+
+#define JBD_PROC_NAME "sys/fs/jbd2-debug"
+
+static void __init create_jbd_proc_entry(void)
+{
+ proc_jbd_debug = create_proc_entry(JBD_PROC_NAME, 0644, NULL);
+ if (proc_jbd_debug) {
+ /* Why is this so hard? */
+ proc_jbd_debug->read_proc = read_jbd_debug;
+ proc_jbd_debug->write_proc = write_jbd_debug;
+ }
+}
+
+static void __exit jbd2_remove_jbd_proc_entry(void)
+{
+ if (proc_jbd_debug)
+ remove_proc_entry(JBD_PROC_NAME, NULL);
+}
+
+#else
+
+#define create_jbd_proc_entry() do {} while (0)
+#define jbd2_remove_jbd_proc_entry() do {} while (0)
+
+#endif
+
+kmem_cache_t *jbd2_handle_cache;
+
+static int __init journal_init_handle_cache(void)
+{
+ jbd2_handle_cache = kmem_cache_create("jbd2_journal_handle",
+ sizeof(handle_t),
+ 0, /* offset */
+ 0, /* flags */
+ NULL, /* ctor */
+ NULL); /* dtor */
+ if (jbd2_handle_cache == NULL) {
+ printk(KERN_EMERG "JBD: failed to create handle cache\n");
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static void jbd2_journal_destroy_handle_cache(void)
+{
+ if (jbd2_handle_cache)
+ kmem_cache_destroy(jbd2_handle_cache);
+}
+
+/*
+ * Module startup and shutdown
+ */
+
+static int __init journal_init_caches(void)
+{
+ int ret;
+
+ ret = jbd2_journal_init_revoke_caches();
+ if (ret == 0)
+ ret = journal_init_jbd2_journal_head_cache();
+ if (ret == 0)
+ ret = journal_init_handle_cache();
+ return ret;
+}
+
+static void jbd2_journal_destroy_caches(void)
+{
+ jbd2_journal_destroy_revoke_caches();
+ jbd2_journal_destroy_jbd2_journal_head_cache();
+ jbd2_journal_destroy_handle_cache();
+ jbd2_journal_destroy_jbd_slabs();
+}
+
+static int __init journal_init(void)
+{
+ int ret;
+
+ BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024);
+
+ ret = journal_init_caches();
+ if (ret != 0)
+ jbd2_journal_destroy_caches();
+ create_jbd_proc_entry();
+ return ret;
+}
+
+static void __exit journal_exit(void)
+{
+#ifdef CONFIG_JBD_DEBUG
+ int n = atomic_read(&nr_journal_heads);
+ if (n)
+ printk(KERN_EMERG "JBD: leaked %d journal_heads!\n", n);
+#endif
+ jbd2_remove_jbd_proc_entry();
+ jbd2_journal_destroy_caches();
+}
+
+MODULE_LICENSE("GPL");
+module_init(journal_init);
+module_exit(journal_exit);
+
diff --git a/fs/jbd2/recovery.c b/fs/jbd2/recovery.c
new file mode 100644
index 000000000000..9f10acafaf70
--- /dev/null
+++ b/fs/jbd2/recovery.c
@@ -0,0 +1,609 @@
+/*
+ * linux/fs/recovery.c
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1999-2000 Red Hat Software --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Journal recovery routines for the generic filesystem journaling code;
+ * part of the ext2fs journaling system.
+ */
+
+#ifndef __KERNEL__
+#include "jfs_user.h"
+#else
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#endif
+
+/*
+ * Maintain information about the progress of the recovery job, so that
+ * the different passes can carry information between them.
+ */
+struct recovery_info
+{
+ tid_t start_transaction;
+ tid_t end_transaction;
+
+ int nr_replays;
+ int nr_revokes;
+ int nr_revoke_hits;
+};
+
+enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
+static int do_one_pass(journal_t *journal,
+ struct recovery_info *info, enum passtype pass);
+static int scan_revoke_records(journal_t *, struct buffer_head *,
+ tid_t, struct recovery_info *);
+
+#ifdef __KERNEL__
+
+/* Release readahead buffers after use */
+static void journal_brelse_array(struct buffer_head *b[], int n)
+{
+ while (--n >= 0)
+ brelse (b[n]);
+}
+
+
+/*
+ * When reading from the journal, we are going through the block device
+ * layer directly and so there is no readahead being done for us. We
+ * need to implement any readahead ourselves if we want it to happen at
+ * all. Recovery is basically one long sequential read, so make sure we
+ * do the IO in reasonably large chunks.
+ *
+ * This is not so critical that we need to be enormously clever about
+ * the readahead size, though. 128K is a purely arbitrary, good-enough
+ * fixed value.
+ */
+
+#define MAXBUF 8
+static int do_readahead(journal_t *journal, unsigned int start)
+{
+ int err;
+ unsigned int max, nbufs, next;
+ unsigned long long blocknr;
+ struct buffer_head *bh;
+
+ struct buffer_head * bufs[MAXBUF];
+
+ /* Do up to 128K of readahead */
+ max = start + (128 * 1024 / journal->j_blocksize);
+ if (max > journal->j_maxlen)
+ max = journal->j_maxlen;
+
+ /* Do the readahead itself. We'll submit MAXBUF buffer_heads at
+ * a time to the block device IO layer. */
+
+ nbufs = 0;
+
+ for (next = start; next < max; next++) {
+ err = jbd2_journal_bmap(journal, next, &blocknr);
+
+ if (err) {
+ printk (KERN_ERR "JBD: bad block at offset %u\n",
+ next);
+ goto failed;
+ }
+
+ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ if (!bh) {
+ err = -ENOMEM;
+ goto failed;
+ }
+
+ if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
+ bufs[nbufs++] = bh;
+ if (nbufs == MAXBUF) {
+ ll_rw_block(READ, nbufs, bufs);
+ journal_brelse_array(bufs, nbufs);
+ nbufs = 0;
+ }
+ } else
+ brelse(bh);
+ }
+
+ if (nbufs)
+ ll_rw_block(READ, nbufs, bufs);
+ err = 0;
+
+failed:
+ if (nbufs)
+ journal_brelse_array(bufs, nbufs);
+ return err;
+}
+
+#endif /* __KERNEL__ */
+
+
+/*
+ * Read a block from the journal
+ */
+
+static int jread(struct buffer_head **bhp, journal_t *journal,
+ unsigned int offset)
+{
+ int err;
+ unsigned long long blocknr;
+ struct buffer_head *bh;
+
+ *bhp = NULL;
+
+ if (offset >= journal->j_maxlen) {
+ printk(KERN_ERR "JBD: corrupted journal superblock\n");
+ return -EIO;
+ }
+
+ err = jbd2_journal_bmap(journal, offset, &blocknr);
+
+ if (err) {
+ printk (KERN_ERR "JBD: bad block at offset %u\n",
+ offset);
+ return err;
+ }
+
+ bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize);
+ if (!bh)
+ return -ENOMEM;
+
+ if (!buffer_uptodate(bh)) {
+ /* If this is a brand new buffer, start readahead.
+ Otherwise, we assume we are already reading it. */
+ if (!buffer_req(bh))
+ do_readahead(journal, offset);
+ wait_on_buffer(bh);
+ }
+
+ if (!buffer_uptodate(bh)) {
+ printk (KERN_ERR "JBD: Failed to read block at offset %u\n",
+ offset);
+ brelse(bh);
+ return -EIO;
+ }
+
+ *bhp = bh;
+ return 0;
+}
+
+
+/*
+ * Count the number of in-use tags in a journal descriptor block.
+ */
+
+static int count_tags(journal_t *journal, struct buffer_head *bh)
+{
+ char * tagp;
+ journal_block_tag_t * tag;
+ int nr = 0, size = journal->j_blocksize;
+ int tag_bytes = journal_tag_bytes(journal);
+
+ tagp = &bh->b_data[sizeof(journal_header_t)];
+
+ while ((tagp - bh->b_data + tag_bytes) <= size) {
+ tag = (journal_block_tag_t *) tagp;
+
+ nr++;
+ tagp += tag_bytes;
+ if (!(tag->t_flags & cpu_to_be32(JBD2_FLAG_SAME_UUID)))
+ tagp += 16;
+
+ if (tag->t_flags & cpu_to_be32(JBD2_FLAG_LAST_TAG))
+ break;
+ }
+
+ return nr;
+}
+
+
+/* Make sure we wrap around the log correctly! */
+#define wrap(journal, var) \
+do { \
+ if (var >= (journal)->j_last) \
+ var -= ((journal)->j_last - (journal)->j_first); \
+} while (0)
+
+/**
+ * jbd2_journal_recover - recovers a on-disk journal
+ * @journal: the journal to recover
+ *
+ * The primary function for recovering the log contents when mounting a
+ * journaled device.
+ *
+ * Recovery is done in three passes. In the first pass, we look for the
+ * end of the log. In the second, we assemble the list of revoke
+ * blocks. In the third and final pass, we replay any un-revoked blocks
+ * in the log.
+ */
+int jbd2_journal_recover(journal_t *journal)
+{
+ int err;
+ journal_superblock_t * sb;
+
+ struct recovery_info info;
+
+ memset(&info, 0, sizeof(info));
+ sb = journal->j_superblock;
+
+ /*
+ * The journal superblock's s_start field (the current log head)
+ * is always zero if, and only if, the journal was cleanly
+ * unmounted.
+ */
+
+ if (!sb->s_start) {
+ jbd_debug(1, "No recovery required, last transaction %d\n",
+ be32_to_cpu(sb->s_sequence));
+ journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1;
+ return 0;
+ }
+
+ err = do_one_pass(journal, &info, PASS_SCAN);
+ if (!err)
+ err = do_one_pass(journal, &info, PASS_REVOKE);
+ if (!err)
+ err = do_one_pass(journal, &info, PASS_REPLAY);
+
+ jbd_debug(0, "JBD: recovery, exit status %d, "
+ "recovered transactions %u to %u\n",
+ err, info.start_transaction, info.end_transaction);
+ jbd_debug(0, "JBD: Replayed %d and revoked %d/%d blocks\n",
+ info.nr_replays, info.nr_revoke_hits, info.nr_revokes);
+
+ /* Restart the log at the next transaction ID, thus invalidating
+ * any existing commit records in the log. */
+ journal->j_transaction_sequence = ++info.end_transaction;
+
+ jbd2_journal_clear_revoke(journal);
+ sync_blockdev(journal->j_fs_dev);
+ return err;
+}
+
+/**
+ * jbd2_journal_skip_recovery - Start journal and wipe exiting records
+ * @journal: journal to startup
+ *
+ * Locate any valid recovery information from the journal and set up the
+ * journal structures in memory to ignore it (presumably because the
+ * caller has evidence that it is out of date).
+ * This function does'nt appear to be exorted..
+ *
+ * We perform one pass over the journal to allow us to tell the user how
+ * much recovery information is being erased, and to let us initialise
+ * the journal transaction sequence numbers to the next unused ID.
+ */
+int jbd2_journal_skip_recovery(journal_t *journal)
+{
+ int err;
+ journal_superblock_t * sb;
+
+ struct recovery_info info;
+
+ memset (&info, 0, sizeof(info));
+ sb = journal->j_superblock;
+
+ err = do_one_pass(journal, &info, PASS_SCAN);
+
+ if (err) {
+ printk(KERN_ERR "JBD: error %d scanning journal\n", err);
+ ++journal->j_transaction_sequence;
+ } else {
+#ifdef CONFIG_JBD_DEBUG
+ int dropped = info.end_transaction - be32_to_cpu(sb->s_sequence);
+#endif
+ jbd_debug(0,
+ "JBD: ignoring %d transaction%s from the journal.\n",
+ dropped, (dropped == 1) ? "" : "s");
+ journal->j_transaction_sequence = ++info.end_transaction;
+ }
+
+ journal->j_tail = 0;
+ return err;
+}
+
+static inline unsigned long long read_tag_block(int tag_bytes, journal_block_tag_t *tag)
+{
+ unsigned long long block = be32_to_cpu(tag->t_blocknr);
+ if (tag_bytes > JBD_TAG_SIZE32)
+ block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32;
+ return block;
+}
+
+static int do_one_pass(journal_t *journal,
+ struct recovery_info *info, enum passtype pass)
+{
+ unsigned int first_commit_ID, next_commit_ID;
+ unsigned long next_log_block;
+ int err, success = 0;
+ journal_superblock_t * sb;
+ journal_header_t * tmp;
+ struct buffer_head * bh;
+ unsigned int sequence;
+ int blocktype;
+ int tag_bytes = journal_tag_bytes(journal);
+
+ /* Precompute the maximum metadata descriptors in a descriptor block */
+ int MAX_BLOCKS_PER_DESC;
+ MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
+ / tag_bytes);
+
+ /*
+ * First thing is to establish what we expect to find in the log
+ * (in terms of transaction IDs), and where (in terms of log
+ * block offsets): query the superblock.
+ */
+
+ sb = journal->j_superblock;
+ next_commit_ID = be32_to_cpu(sb->s_sequence);
+ next_log_block = be32_to_cpu(sb->s_start);
+
+ first_commit_ID = next_commit_ID;
+ if (pass == PASS_SCAN)
+ info->start_transaction = first_commit_ID;
+
+ jbd_debug(1, "Starting recovery pass %d\n", pass);
+
+ /*
+ * Now we walk through the log, transaction by transaction,
+ * making sure that each transaction has a commit block in the
+ * expected place. Each complete transaction gets replayed back
+ * into the main filesystem.
+ */
+
+ while (1) {
+ int flags;
+ char * tagp;
+ journal_block_tag_t * tag;
+ struct buffer_head * obh;
+ struct buffer_head * nbh;
+
+ cond_resched(); /* We're under lock_kernel() */
+
+ /* If we already know where to stop the log traversal,
+ * check right now that we haven't gone past the end of
+ * the log. */
+
+ if (pass != PASS_SCAN)
+ if (tid_geq(next_commit_ID, info->end_transaction))
+ break;
+
+ jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
+ next_commit_ID, next_log_block, journal->j_last);
+
+ /* Skip over each chunk of the transaction looking
+ * either the next descriptor block or the final commit
+ * record. */
+
+ jbd_debug(3, "JBD: checking block %ld\n", next_log_block);
+ err = jread(&bh, journal, next_log_block);
+ if (err)
+ goto failed;
+
+ next_log_block++;
+ wrap(journal, next_log_block);
+
+ /* What kind of buffer is it?
+ *
+ * If it is a descriptor block, check that it has the
+ * expected sequence number. Otherwise, we're all done
+ * here. */
+
+ tmp = (journal_header_t *)bh->b_data;
+
+ if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) {
+ brelse(bh);
+ break;
+ }
+
+ blocktype = be32_to_cpu(tmp->h_blocktype);
+ sequence = be32_to_cpu(tmp->h_sequence);
+ jbd_debug(3, "Found magic %d, sequence %d\n",
+ blocktype, sequence);
+
+ if (sequence != next_commit_ID) {
+ brelse(bh);
+ break;
+ }
+
+ /* OK, we have a valid descriptor block which matches
+ * all of the sequence number checks. What are we going
+ * to do with it? That depends on the pass... */
+
+ switch(blocktype) {
+ case JBD2_DESCRIPTOR_BLOCK:
+ /* If it is a valid descriptor block, replay it
+ * in pass REPLAY; otherwise, just skip over the
+ * blocks it describes. */
+ if (pass != PASS_REPLAY) {
+ next_log_block += count_tags(journal, bh);
+ wrap(journal, next_log_block);
+ brelse(bh);
+ continue;
+ }
+
+ /* A descriptor block: we can now write all of
+ * the data blocks. Yay, useful work is finally
+ * getting done here! */
+
+ tagp = &bh->b_data[sizeof(journal_header_t)];
+ while ((tagp - bh->b_data + tag_bytes)
+ <= journal->j_blocksize) {
+ unsigned long io_block;
+
+ tag = (journal_block_tag_t *) tagp;
+ flags = be32_to_cpu(tag->t_flags);
+
+ io_block = next_log_block++;
+ wrap(journal, next_log_block);
+ err = jread(&obh, journal, io_block);
+ if (err) {
+ /* Recover what we can, but
+ * report failure at the end. */
+ success = err;
+ printk (KERN_ERR
+ "JBD: IO error %d recovering "
+ "block %ld in log\n",
+ err, io_block);
+ } else {
+ unsigned long long blocknr;
+
+ J_ASSERT(obh != NULL);
+ blocknr = read_tag_block(tag_bytes,
+ tag);
+
+ /* If the block has been
+ * revoked, then we're all done
+ * here. */
+ if (jbd2_journal_test_revoke
+ (journal, blocknr,
+ next_commit_ID)) {
+ brelse(obh);
+ ++info->nr_revoke_hits;
+ goto skip_write;
+ }
+
+ /* Find a buffer for the new
+ * data being restored */
+ nbh = __getblk(journal->j_fs_dev,
+ blocknr,
+ journal->j_blocksize);
+ if (nbh == NULL) {
+ printk(KERN_ERR
+ "JBD: Out of memory "
+ "during recovery.\n");
+ err = -ENOMEM;
+ brelse(bh);
+ brelse(obh);
+ goto failed;
+ }
+
+ lock_buffer(nbh);
+ memcpy(nbh->b_data, obh->b_data,
+ journal->j_blocksize);
+ if (flags & JBD2_FLAG_ESCAPE) {
+ *((__be32 *)bh->b_data) =
+ cpu_to_be32(JBD2_MAGIC_NUMBER);
+ }
+
+ BUFFER_TRACE(nbh, "marking dirty");
+ set_buffer_uptodate(nbh);
+ mark_buffer_dirty(nbh);
+ BUFFER_TRACE(nbh, "marking uptodate");
+ ++info->nr_replays;
+ /* ll_rw_block(WRITE, 1, &nbh); */
+ unlock_buffer(nbh);
+ brelse(obh);
+ brelse(nbh);
+ }
+
+ skip_write:
+ tagp += tag_bytes;
+ if (!(flags & JBD2_FLAG_SAME_UUID))
+ tagp += 16;
+
+ if (flags & JBD2_FLAG_LAST_TAG)
+ break;
+ }
+
+ brelse(bh);
+ continue;
+
+ case JBD2_COMMIT_BLOCK:
+ /* Found an expected commit block: not much to
+ * do other than move on to the next sequence
+ * number. */
+ brelse(bh);
+ next_commit_ID++;
+ continue;
+
+ case JBD2_REVOKE_BLOCK:
+ /* If we aren't in the REVOKE pass, then we can
+ * just skip over this block. */
+ if (pass != PASS_REVOKE) {
+ brelse(bh);
+ continue;
+ }
+
+ err = scan_revoke_records(journal, bh,
+ next_commit_ID, info);
+ brelse(bh);
+ if (err)
+ goto failed;
+ continue;
+
+ default:
+ jbd_debug(3, "Unrecognised magic %d, end of scan.\n",
+ blocktype);
+ brelse(bh);
+ goto done;
+ }
+ }
+
+ done:
+ /*
+ * We broke out of the log scan loop: either we came to the
+ * known end of the log or we found an unexpected block in the
+ * log. If the latter happened, then we know that the "current"
+ * transaction marks the end of the valid log.
+ */
+
+ if (pass == PASS_SCAN)
+ info->end_transaction = next_commit_ID;
+ else {
+ /* It's really bad news if different passes end up at
+ * different places (but possible due to IO errors). */
+ if (info->end_transaction != next_commit_ID) {
+ printk (KERN_ERR "JBD: recovery pass %d ended at "
+ "transaction %u, expected %u\n",
+ pass, next_commit_ID, info->end_transaction);
+ if (!success)
+ success = -EIO;
+ }
+ }
+
+ return success;
+
+ failed:
+ return err;
+}
+
+
+/* Scan a revoke record, marking all blocks mentioned as revoked. */
+
+static int scan_revoke_records(journal_t *journal, struct buffer_head *bh,
+ tid_t sequence, struct recovery_info *info)
+{
+ jbd2_journal_revoke_header_t *header;
+ int offset, max;
+ int record_len = 4;
+
+ header = (jbd2_journal_revoke_header_t *) bh->b_data;
+ offset = sizeof(jbd2_journal_revoke_header_t);
+ max = be32_to_cpu(header->r_count);
+
+ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT))
+ record_len = 8;
+
+ while (offset + record_len <= max) {
+ unsigned long long blocknr;
+ int err;
+
+ if (record_len == 4)
+ blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset)));
+ else
+ blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset)));
+ offset += record_len;
+ err = jbd2_journal_set_revoke(journal, blocknr, sequence);
+ if (err)
+ return err;
+ ++info->nr_revokes;
+ }
+ return 0;
+}
diff --git a/fs/jbd2/revoke.c b/fs/jbd2/revoke.c
new file mode 100644
index 000000000000..380d19917f37
--- /dev/null
+++ b/fs/jbd2/revoke.c
@@ -0,0 +1,712 @@
+/*
+ * linux/fs/revoke.c
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 2000
+ *
+ * Copyright 2000 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Journal revoke routines for the generic filesystem journaling code;
+ * part of the ext2fs journaling system.
+ *
+ * Revoke is the mechanism used to prevent old log records for deleted
+ * metadata from being replayed on top of newer data using the same
+ * blocks. The revoke mechanism is used in two separate places:
+ *
+ * + Commit: during commit we write the entire list of the current
+ * transaction's revoked blocks to the journal
+ *
+ * + Recovery: during recovery we record the transaction ID of all
+ * revoked blocks. If there are multiple revoke records in the log
+ * for a single block, only the last one counts, and if there is a log
+ * entry for a block beyond the last revoke, then that log entry still
+ * gets replayed.
+ *
+ * We can get interactions between revokes and new log data within a
+ * single transaction:
+ *
+ * Block is revoked and then journaled:
+ * The desired end result is the journaling of the new block, so we
+ * cancel the revoke before the transaction commits.
+ *
+ * Block is journaled and then revoked:
+ * The revoke must take precedence over the write of the block, so we
+ * need either to cancel the journal entry or to write the revoke
+ * later in the log than the log block. In this case, we choose the
+ * latter: journaling a block cancels any revoke record for that block
+ * in the current transaction, so any revoke for that block in the
+ * transaction must have happened after the block was journaled and so
+ * the revoke must take precedence.
+ *
+ * Block is revoked and then written as data:
+ * The data write is allowed to succeed, but the revoke is _not_
+ * cancelled. We still need to prevent old log records from
+ * overwriting the new data. We don't even need to clear the revoke
+ * bit here.
+ *
+ * Revoke information on buffers is a tri-state value:
+ *
+ * RevokeValid clear: no cached revoke status, need to look it up
+ * RevokeValid set, Revoked clear:
+ * buffer has not been revoked, and cancel_revoke
+ * need do nothing.
+ * RevokeValid set, Revoked set:
+ * buffer has been revoked.
+ */
+
+#ifndef __KERNEL__
+#include "jfs_user.h"
+#else
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/smp_lock.h>
+#include <linux/init.h>
+#endif
+
+static kmem_cache_t *jbd2_revoke_record_cache;
+static kmem_cache_t *jbd2_revoke_table_cache;
+
+/* Each revoke record represents one single revoked block. During
+ journal replay, this involves recording the transaction ID of the
+ last transaction to revoke this block. */
+
+struct jbd2_revoke_record_s
+{
+ struct list_head hash;
+ tid_t sequence; /* Used for recovery only */
+ unsigned long long blocknr;
+};
+
+
+/* The revoke table is just a simple hash table of revoke records. */
+struct jbd2_revoke_table_s
+{
+ /* It is conceivable that we might want a larger hash table
+ * for recovery. Must be a power of two. */
+ int hash_size;
+ int hash_shift;
+ struct list_head *hash_table;
+};
+
+
+#ifdef __KERNEL__
+static void write_one_revoke_record(journal_t *, transaction_t *,
+ struct journal_head **, int *,
+ struct jbd2_revoke_record_s *);
+static void flush_descriptor(journal_t *, struct journal_head *, int);
+#endif
+
+/* Utility functions to maintain the revoke table */
+
+/* Borrowed from buffer.c: this is a tried and tested block hash function */
+static inline int hash(journal_t *journal, unsigned long long block)
+{
+ struct jbd2_revoke_table_s *table = journal->j_revoke;
+ int hash_shift = table->hash_shift;
+ int hash = (int)block ^ (int)((block >> 31) >> 1);
+
+ return ((hash << (hash_shift - 6)) ^
+ (hash >> 13) ^
+ (hash << (hash_shift - 12))) & (table->hash_size - 1);
+}
+
+static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr,
+ tid_t seq)
+{
+ struct list_head *hash_list;
+ struct jbd2_revoke_record_s *record;
+
+repeat:
+ record = kmem_cache_alloc(jbd2_revoke_record_cache, GFP_NOFS);
+ if (!record)
+ goto oom;
+
+ record->sequence = seq;
+ record->blocknr = blocknr;
+ hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
+ spin_lock(&journal->j_revoke_lock);
+ list_add(&record->hash, hash_list);
+ spin_unlock(&journal->j_revoke_lock);
+ return 0;
+
+oom:
+ if (!journal_oom_retry)
+ return -ENOMEM;
+ jbd_debug(1, "ENOMEM in %s, retrying\n", __FUNCTION__);
+ yield();
+ goto repeat;
+}
+
+/* Find a revoke record in the journal's hash table. */
+
+static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal,
+ unsigned long long blocknr)
+{
+ struct list_head *hash_list;
+ struct jbd2_revoke_record_s *record;
+
+ hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)];
+
+ spin_lock(&journal->j_revoke_lock);
+ record = (struct jbd2_revoke_record_s *) hash_list->next;
+ while (&(record->hash) != hash_list) {
+ if (record->blocknr == blocknr) {
+ spin_unlock(&journal->j_revoke_lock);
+ return record;
+ }
+ record = (struct jbd2_revoke_record_s *) record->hash.next;
+ }
+ spin_unlock(&journal->j_revoke_lock);
+ return NULL;
+}
+
+int __init jbd2_journal_init_revoke_caches(void)
+{
+ jbd2_revoke_record_cache = kmem_cache_create("jbd2_revoke_record",
+ sizeof(struct jbd2_revoke_record_s),
+ 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+ if (jbd2_revoke_record_cache == 0)
+ return -ENOMEM;
+
+ jbd2_revoke_table_cache = kmem_cache_create("jbd2_revoke_table",
+ sizeof(struct jbd2_revoke_table_s),
+ 0, 0, NULL, NULL);
+ if (jbd2_revoke_table_cache == 0) {
+ kmem_cache_destroy(jbd2_revoke_record_cache);
+ jbd2_revoke_record_cache = NULL;
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+void jbd2_journal_destroy_revoke_caches(void)
+{
+ kmem_cache_destroy(jbd2_revoke_record_cache);
+ jbd2_revoke_record_cache = NULL;
+ kmem_cache_destroy(jbd2_revoke_table_cache);
+ jbd2_revoke_table_cache = NULL;
+}
+
+/* Initialise the revoke table for a given journal to a given size. */
+
+int jbd2_journal_init_revoke(journal_t *journal, int hash_size)
+{
+ int shift, tmp;
+
+ J_ASSERT (journal->j_revoke_table[0] == NULL);
+
+ shift = 0;
+ tmp = hash_size;
+ while((tmp >>= 1UL) != 0UL)
+ shift++;
+
+ journal->j_revoke_table[0] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
+ if (!journal->j_revoke_table[0])
+ return -ENOMEM;
+ journal->j_revoke = journal->j_revoke_table[0];
+
+ /* Check that the hash_size is a power of two */
+ J_ASSERT ((hash_size & (hash_size-1)) == 0);
+
+ journal->j_revoke->hash_size = hash_size;
+
+ journal->j_revoke->hash_shift = shift;
+
+ journal->j_revoke->hash_table =
+ kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
+ if (!journal->j_revoke->hash_table) {
+ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
+ journal->j_revoke = NULL;
+ return -ENOMEM;
+ }
+
+ for (tmp = 0; tmp < hash_size; tmp++)
+ INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
+
+ journal->j_revoke_table[1] = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL);
+ if (!journal->j_revoke_table[1]) {
+ kfree(journal->j_revoke_table[0]->hash_table);
+ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
+ return -ENOMEM;
+ }
+
+ journal->j_revoke = journal->j_revoke_table[1];
+
+ /* Check that the hash_size is a power of two */
+ J_ASSERT ((hash_size & (hash_size-1)) == 0);
+
+ journal->j_revoke->hash_size = hash_size;
+
+ journal->j_revoke->hash_shift = shift;
+
+ journal->j_revoke->hash_table =
+ kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL);
+ if (!journal->j_revoke->hash_table) {
+ kfree(journal->j_revoke_table[0]->hash_table);
+ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[0]);
+ kmem_cache_free(jbd2_revoke_table_cache, journal->j_revoke_table[1]);
+ journal->j_revoke = NULL;
+ return -ENOMEM;
+ }
+
+ for (tmp = 0; tmp < hash_size; tmp++)
+ INIT_LIST_HEAD(&journal->j_revoke->hash_table[tmp]);
+
+ spin_lock_init(&journal->j_revoke_lock);
+
+ return 0;
+}
+
+/* Destoy a journal's revoke table. The table must already be empty! */
+
+void jbd2_journal_destroy_revoke(journal_t *journal)
+{
+ struct jbd2_revoke_table_s *table;
+ struct list_head *hash_list;
+ int i;
+
+ table = journal->j_revoke_table[0];
+ if (!table)
+ return;
+
+ for (i=0; i<table->hash_size; i++) {
+ hash_list = &table->hash_table[i];
+ J_ASSERT (list_empty(hash_list));
+ }
+
+ kfree(table->hash_table);
+ kmem_cache_free(jbd2_revoke_table_cache, table);
+ journal->j_revoke = NULL;
+
+ table = journal->j_revoke_table[1];
+ if (!table)
+ return;
+
+ for (i=0; i<table->hash_size; i++) {
+ hash_list = &table->hash_table[i];
+ J_ASSERT (list_empty(hash_list));
+ }
+
+ kfree(table->hash_table);
+ kmem_cache_free(jbd2_revoke_table_cache, table);
+ journal->j_revoke = NULL;
+}
+
+
+#ifdef __KERNEL__
+
+/*
+ * jbd2_journal_revoke: revoke a given buffer_head from the journal. This
+ * prevents the block from being replayed during recovery if we take a
+ * crash after this current transaction commits. Any subsequent
+ * metadata writes of the buffer in this transaction cancel the
+ * revoke.
+ *
+ * Note that this call may block --- it is up to the caller to make
+ * sure that there are no further calls to journal_write_metadata
+ * before the revoke is complete. In ext3, this implies calling the
+ * revoke before clearing the block bitmap when we are deleting
+ * metadata.
+ *
+ * Revoke performs a jbd2_journal_forget on any buffer_head passed in as a
+ * parameter, but does _not_ forget the buffer_head if the bh was only
+ * found implicitly.
+ *
+ * bh_in may not be a journalled buffer - it may have come off
+ * the hash tables without an attached journal_head.
+ *
+ * If bh_in is non-zero, jbd2_journal_revoke() will decrement its b_count
+ * by one.
+ */
+
+int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr,
+ struct buffer_head *bh_in)
+{
+ struct buffer_head *bh = NULL;
+ journal_t *journal;
+ struct block_device *bdev;
+ int err;
+
+ might_sleep();
+ if (bh_in)
+ BUFFER_TRACE(bh_in, "enter");
+
+ journal = handle->h_transaction->t_journal;
+ if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){
+ J_ASSERT (!"Cannot set revoke feature!");
+ return -EINVAL;
+ }
+
+ bdev = journal->j_fs_dev;
+ bh = bh_in;
+
+ if (!bh) {
+ bh = __find_get_block(bdev, blocknr, journal->j_blocksize);
+ if (bh)
+ BUFFER_TRACE(bh, "found on hash");
+ }
+#ifdef JBD_EXPENSIVE_CHECKING
+ else {
+ struct buffer_head *bh2;
+
+ /* If there is a different buffer_head lying around in
+ * memory anywhere... */
+ bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize);
+ if (bh2) {
+ /* ... and it has RevokeValid status... */
+ if (bh2 != bh && buffer_revokevalid(bh2))
+ /* ...then it better be revoked too,
+ * since it's illegal to create a revoke
+ * record against a buffer_head which is
+ * not marked revoked --- that would
+ * risk missing a subsequent revoke
+ * cancel. */
+ J_ASSERT_BH(bh2, buffer_revoked(bh2));
+ put_bh(bh2);
+ }
+ }
+#endif
+
+ /* We really ought not ever to revoke twice in a row without
+ first having the revoke cancelled: it's illegal to free a
+ block twice without allocating it in between! */
+ if (bh) {
+ if (!J_EXPECT_BH(bh, !buffer_revoked(bh),
+ "inconsistent data on disk")) {
+ if (!bh_in)
+ brelse(bh);
+ return -EIO;
+ }
+ set_buffer_revoked(bh);
+ set_buffer_revokevalid(bh);
+ if (bh_in) {
+ BUFFER_TRACE(bh_in, "call jbd2_journal_forget");
+ jbd2_journal_forget(handle, bh_in);
+ } else {
+ BUFFER_TRACE(bh, "call brelse");
+ __brelse(bh);
+ }
+ }
+
+ jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in);
+ err = insert_revoke_hash(journal, blocknr,
+ handle->h_transaction->t_tid);
+ BUFFER_TRACE(bh_in, "exit");
+ return err;
+}
+
+/*
+ * Cancel an outstanding revoke. For use only internally by the
+ * journaling code (called from jbd2_journal_get_write_access).
+ *
+ * We trust buffer_revoked() on the buffer if the buffer is already
+ * being journaled: if there is no revoke pending on the buffer, then we
+ * don't do anything here.
+ *
+ * This would break if it were possible for a buffer to be revoked and
+ * discarded, and then reallocated within the same transaction. In such
+ * a case we would have lost the revoked bit, but when we arrived here
+ * the second time we would still have a pending revoke to cancel. So,
+ * do not trust the Revoked bit on buffers unless RevokeValid is also
+ * set.
+ *
+ * The caller must have the journal locked.
+ */
+int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh)
+{
+ struct jbd2_revoke_record_s *record;
+ journal_t *journal = handle->h_transaction->t_journal;
+ int need_cancel;
+ int did_revoke = 0; /* akpm: debug */
+ struct buffer_head *bh = jh2bh(jh);
+
+ jbd_debug(4, "journal_head %p, cancelling revoke\n", jh);
+
+ /* Is the existing Revoke bit valid? If so, we trust it, and
+ * only perform the full cancel if the revoke bit is set. If
+ * not, we can't trust the revoke bit, and we need to do the
+ * full search for a revoke record. */
+ if (test_set_buffer_revokevalid(bh)) {
+ need_cancel = test_clear_buffer_revoked(bh);
+ } else {
+ need_cancel = 1;
+ clear_buffer_revoked(bh);
+ }
+
+ if (need_cancel) {
+ record = find_revoke_record(journal, bh->b_blocknr);
+ if (record) {
+ jbd_debug(4, "cancelled existing revoke on "
+ "blocknr %llu\n", (unsigned long long)bh->b_blocknr);
+ spin_lock(&journal->j_revoke_lock);
+ list_del(&record->hash);
+ spin_unlock(&journal->j_revoke_lock);
+ kmem_cache_free(jbd2_revoke_record_cache, record);
+ did_revoke = 1;
+ }
+ }
+
+#ifdef JBD_EXPENSIVE_CHECKING
+ /* There better not be one left behind by now! */
+ record = find_revoke_record(journal, bh->b_blocknr);
+ J_ASSERT_JH(jh, record == NULL);
+#endif
+
+ /* Finally, have we just cleared revoke on an unhashed
+ * buffer_head? If so, we'd better make sure we clear the
+ * revoked status on any hashed alias too, otherwise the revoke
+ * state machine will get very upset later on. */
+ if (need_cancel) {
+ struct buffer_head *bh2;
+ bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size);
+ if (bh2) {
+ if (bh2 != bh)
+ clear_buffer_revoked(bh2);
+ __brelse(bh2);
+ }
+ }
+ return did_revoke;
+}
+
+/* journal_switch_revoke table select j_revoke for next transaction
+ * we do not want to suspend any processing until all revokes are
+ * written -bzzz
+ */
+void jbd2_journal_switch_revoke_table(journal_t *journal)
+{
+ int i;
+
+ if (journal->j_revoke == journal->j_revoke_table[0])
+ journal->j_revoke = journal->j_revoke_table[1];
+ else
+ journal->j_revoke = journal->j_revoke_table[0];
+
+ for (i = 0; i < journal->j_revoke->hash_size; i++)
+ INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]);
+}
+
+/*
+ * Write revoke records to the journal for all entries in the current
+ * revoke hash, deleting the entries as we go.
+ *
+ * Called with the journal lock held.
+ */
+
+void jbd2_journal_write_revoke_records(journal_t *journal,
+ transaction_t *transaction)
+{
+ struct journal_head *descriptor;
+ struct jbd2_revoke_record_s *record;
+ struct jbd2_revoke_table_s *revoke;
+ struct list_head *hash_list;
+ int i, offset, count;
+
+ descriptor = NULL;
+ offset = 0;
+ count = 0;
+
+ /* select revoke table for committing transaction */
+ revoke = journal->j_revoke == journal->j_revoke_table[0] ?
+ journal->j_revoke_table[1] : journal->j_revoke_table[0];
+
+ for (i = 0; i < revoke->hash_size; i++) {
+ hash_list = &revoke->hash_table[i];
+
+ while (!list_empty(hash_list)) {
+ record = (struct jbd2_revoke_record_s *)
+ hash_list->next;
+ write_one_revoke_record(journal, transaction,
+ &descriptor, &offset,
+ record);
+ count++;
+ list_del(&record->hash);
+ kmem_cache_free(jbd2_revoke_record_cache, record);
+ }
+ }
+ if (descriptor)
+ flush_descriptor(journal, descriptor, offset);
+ jbd_debug(1, "Wrote %d revoke records\n", count);
+}
+
+/*
+ * Write out one revoke record. We need to create a new descriptor
+ * block if the old one is full or if we have not already created one.
+ */
+
+static void write_one_revoke_record(journal_t *journal,
+ transaction_t *transaction,
+ struct journal_head **descriptorp,
+ int *offsetp,
+ struct jbd2_revoke_record_s *record)
+{
+ struct journal_head *descriptor;
+ int offset;
+ journal_header_t *header;
+
+ /* If we are already aborting, this all becomes a noop. We
+ still need to go round the loop in
+ jbd2_journal_write_revoke_records in order to free all of the
+ revoke records: only the IO to the journal is omitted. */
+ if (is_journal_aborted(journal))
+ return;
+
+ descriptor = *descriptorp;
+ offset = *offsetp;
+
+ /* Make sure we have a descriptor with space left for the record */
+ if (descriptor) {
+ if (offset == journal->j_blocksize) {
+ flush_descriptor(journal, descriptor, offset);
+ descriptor = NULL;
+ }
+ }
+
+ if (!descriptor) {
+ descriptor = jbd2_journal_get_descriptor_buffer(journal);
+ if (!descriptor)
+ return;
+ header = (journal_header_t *) &jh2bh(descriptor)->b_data[0];
+ header->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER);
+ header->h_blocktype = cpu_to_be32(JBD2_REVOKE_BLOCK);
+ header->h_sequence = cpu_to_be32(transaction->t_tid);
+
+ /* Record it so that we can wait for IO completion later */
+ JBUFFER_TRACE(descriptor, "file as BJ_LogCtl");
+ jbd2_journal_file_buffer(descriptor, transaction, BJ_LogCtl);
+
+ offset = sizeof(jbd2_journal_revoke_header_t);
+ *descriptorp = descriptor;
+ }
+
+ if (JBD2_HAS_INCOMPAT_FEATURE(journal, JBD2_FEATURE_INCOMPAT_64BIT)) {
+ * ((__be64 *)(&jh2bh(descriptor)->b_data[offset])) =
+ cpu_to_be64(record->blocknr);
+ offset += 8;
+
+ } else {
+ * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) =
+ cpu_to_be32(record->blocknr);
+ offset += 4;
+ }
+
+ *offsetp = offset;
+}
+
+/*
+ * Flush a revoke descriptor out to the journal. If we are aborting,
+ * this is a noop; otherwise we are generating a buffer which needs to
+ * be waited for during commit, so it has to go onto the appropriate
+ * journal buffer list.
+ */
+
+static void flush_descriptor(journal_t *journal,
+ struct journal_head *descriptor,
+ int offset)
+{
+ jbd2_journal_revoke_header_t *header;
+ struct buffer_head *bh = jh2bh(descriptor);
+
+ if (is_journal_aborted(journal)) {
+ put_bh(bh);
+ return;
+ }
+
+ header = (jbd2_journal_revoke_header_t *) jh2bh(descriptor)->b_data;
+ header->r_count = cpu_to_be32(offset);
+ set_buffer_jwrite(bh);
+ BUFFER_TRACE(bh, "write");
+ set_buffer_dirty(bh);
+ ll_rw_block(SWRITE, 1, &bh);
+}
+#endif
+
+/*
+ * Revoke support for recovery.
+ *
+ * Recovery needs to be able to:
+ *
+ * record all revoke records, including the tid of the latest instance
+ * of each revoke in the journal
+ *
+ * check whether a given block in a given transaction should be replayed
+ * (ie. has not been revoked by a revoke record in that or a subsequent
+ * transaction)
+ *
+ * empty the revoke table after recovery.
+ */
+
+/*
+ * First, setting revoke records. We create a new revoke record for
+ * every block ever revoked in the log as we scan it for recovery, and
+ * we update the existing records if we find multiple revokes for a
+ * single block.
+ */
+
+int jbd2_journal_set_revoke(journal_t *journal,
+ unsigned long long blocknr,
+ tid_t sequence)
+{
+ struct jbd2_revoke_record_s *record;
+
+ record = find_revoke_record(journal, blocknr);
+ if (record) {
+ /* If we have multiple occurrences, only record the
+ * latest sequence number in the hashed record */
+ if (tid_gt(sequence, record->sequence))
+ record->sequence = sequence;
+ return 0;
+ }
+ return insert_revoke_hash(journal, blocknr, sequence);
+}
+
+/*
+ * Test revoke records. For a given block referenced in the log, has
+ * that block been revoked? A revoke record with a given transaction
+ * sequence number revokes all blocks in that transaction and earlier
+ * ones, but later transactions still need replayed.
+ */
+
+int jbd2_journal_test_revoke(journal_t *journal,
+ unsigned long long blocknr,
+ tid_t sequence)
+{
+ struct jbd2_revoke_record_s *record;
+
+ record = find_revoke_record(journal, blocknr);
+ if (!record)
+ return 0;
+ if (tid_gt(sequence, record->sequence))
+ return 0;
+ return 1;
+}
+
+/*
+ * Finally, once recovery is over, we need to clear the revoke table so
+ * that it can be reused by the running filesystem.
+ */
+
+void jbd2_journal_clear_revoke(journal_t *journal)
+{
+ int i;
+ struct list_head *hash_list;
+ struct jbd2_revoke_record_s *record;
+ struct jbd2_revoke_table_s *revoke;
+
+ revoke = journal->j_revoke;
+
+ for (i = 0; i < revoke->hash_size; i++) {
+ hash_list = &revoke->hash_table[i];
+ while (!list_empty(hash_list)) {
+ record = (struct jbd2_revoke_record_s*) hash_list->next;
+ list_del(&record->hash);
+ kmem_cache_free(jbd2_revoke_record_cache, record);
+ }
+ }
+}
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c
new file mode 100644
index 000000000000..b6cf2be845a1
--- /dev/null
+++ b/fs/jbd2/transaction.c
@@ -0,0 +1,2081 @@
+/*
+ * linux/fs/transaction.c
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Generic filesystem transaction handling code; part of the ext2fs
+ * journaling system.
+ *
+ * This file manages transactions (compound commits managed by the
+ * journaling code) and handles (individual atomic operations by the
+ * filesystem).
+ */
+
+#include <linux/time.h>
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/smp_lock.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+
+/*
+ * jbd2_get_transaction: obtain a new transaction_t object.
+ *
+ * Simply allocate and initialise a new transaction. Create it in
+ * RUNNING state and add it to the current journal (which should not
+ * have an existing running transaction: we only make a new transaction
+ * once we have started to commit the old one).
+ *
+ * Preconditions:
+ * The journal MUST be locked. We don't perform atomic mallocs on the
+ * new transaction and we can't block without protecting against other
+ * processes trying to touch the journal while it is in transition.
+ *
+ * Called under j_state_lock
+ */
+
+static transaction_t *
+jbd2_get_transaction(journal_t *journal, transaction_t *transaction)
+{
+ transaction->t_journal = journal;
+ transaction->t_state = T_RUNNING;
+ transaction->t_tid = journal->j_transaction_sequence++;
+ transaction->t_expires = jiffies + journal->j_commit_interval;
+ spin_lock_init(&transaction->t_handle_lock);
+
+ /* Set up the commit timer for the new transaction. */
+ journal->j_commit_timer.expires = transaction->t_expires;
+ add_timer(&journal->j_commit_timer);
+
+ J_ASSERT(journal->j_running_transaction == NULL);
+ journal->j_running_transaction = transaction;
+
+ return transaction;
+}
+
+/*
+ * Handle management.
+ *
+ * A handle_t is an object which represents a single atomic update to a
+ * filesystem, and which tracks all of the modifications which form part
+ * of that one update.
+ */
+
+/*
+ * start_this_handle: Given a handle, deal with any locking or stalling
+ * needed to make sure that there is enough journal space for the handle
+ * to begin. Attach the handle to a transaction and set up the
+ * transaction's buffer credits.
+ */
+
+static int start_this_handle(journal_t *journal, handle_t *handle)
+{
+ transaction_t *transaction;
+ int needed;
+ int nblocks = handle->h_buffer_credits;
+ transaction_t *new_transaction = NULL;
+ int ret = 0;
+
+ if (nblocks > journal->j_max_transaction_buffers) {
+ printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n",
+ current->comm, nblocks,
+ journal->j_max_transaction_buffers);
+ ret = -ENOSPC;
+ goto out;
+ }
+
+alloc_transaction:
+ if (!journal->j_running_transaction) {
+ new_transaction = jbd_kmalloc(sizeof(*new_transaction),
+ GFP_NOFS);
+ if (!new_transaction) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ memset(new_transaction, 0, sizeof(*new_transaction));
+ }
+
+ jbd_debug(3, "New handle %p going live.\n", handle);
+
+repeat:
+
+ /*
+ * We need to hold j_state_lock until t_updates has been incremented,
+ * for proper journal barrier handling
+ */
+ spin_lock(&journal->j_state_lock);
+repeat_locked:
+ if (is_journal_aborted(journal) ||
+ (journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) {
+ spin_unlock(&journal->j_state_lock);
+ ret = -EROFS;
+ goto out;
+ }
+
+ /* Wait on the journal's transaction barrier if necessary */
+ if (journal->j_barrier_count) {
+ spin_unlock(&journal->j_state_lock);
+ wait_event(journal->j_wait_transaction_locked,
+ journal->j_barrier_count == 0);
+ goto repeat;
+ }
+
+ if (!journal->j_running_transaction) {
+ if (!new_transaction) {
+ spin_unlock(&journal->j_state_lock);
+ goto alloc_transaction;
+ }
+ jbd2_get_transaction(journal, new_transaction);
+ new_transaction = NULL;
+ }
+
+ transaction = journal->j_running_transaction;
+
+ /*
+ * If the current transaction is locked down for commit, wait for the
+ * lock to be released.
+ */
+ if (transaction->t_state == T_LOCKED) {
+ DEFINE_WAIT(wait);
+
+ prepare_to_wait(&journal->j_wait_transaction_locked,
+ &wait, TASK_UNINTERRUPTIBLE);
+ spin_unlock(&journal->j_state_lock);
+ schedule();
+ finish_wait(&journal->j_wait_transaction_locked, &wait);
+ goto repeat;
+ }
+
+ /*
+ * If there is not enough space left in the log to write all potential
+ * buffers requested by this operation, we need to stall pending a log
+ * checkpoint to free some more log space.
+ */
+ spin_lock(&transaction->t_handle_lock);
+ needed = transaction->t_outstanding_credits + nblocks;
+
+ if (needed > journal->j_max_transaction_buffers) {
+ /*
+ * If the current transaction is already too large, then start
+ * to commit it: we can then go back and attach this handle to
+ * a new transaction.
+ */
+ DEFINE_WAIT(wait);
+
+ jbd_debug(2, "Handle %p starting new commit...\n", handle);
+ spin_unlock(&transaction->t_handle_lock);
+ prepare_to_wait(&journal->j_wait_transaction_locked, &wait,
+ TASK_UNINTERRUPTIBLE);
+ __jbd2_log_start_commit(journal, transaction->t_tid);
+ spin_unlock(&journal->j_state_lock);
+ schedule();
+ finish_wait(&journal->j_wait_transaction_locked, &wait);
+ goto repeat;
+ }
+
+ /*
+ * The commit code assumes that it can get enough log space
+ * without forcing a checkpoint. This is *critical* for
+ * correctness: a checkpoint of a buffer which is also
+ * associated with a committing transaction creates a deadlock,
+ * so commit simply cannot force through checkpoints.
+ *
+ * We must therefore ensure the necessary space in the journal
+ * *before* starting to dirty potentially checkpointed buffers
+ * in the new transaction.
+ *
+ * The worst part is, any transaction currently committing can
+ * reduce the free space arbitrarily. Be careful to account for
+ * those buffers when checkpointing.
+ */
+
+ /*
+ * @@@ AKPM: This seems rather over-defensive. We're giving commit
+ * a _lot_ of headroom: 1/4 of the journal plus the size of
+ * the committing transaction. Really, we only need to give it
+ * committing_transaction->t_outstanding_credits plus "enough" for
+ * the log control blocks.
+ * Also, this test is inconsitent with the matching one in
+ * jbd2_journal_extend().
+ */
+ if (__jbd2_log_space_left(journal) < jbd_space_needed(journal)) {
+ jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle);
+ spin_unlock(&transaction->t_handle_lock);
+ __jbd2_log_wait_for_space(journal);
+ goto repeat_locked;
+ }
+
+ /* OK, account for the buffers that this operation expects to
+ * use and add the handle to the running transaction. */
+
+ handle->h_transaction = transaction;
+ transaction->t_outstanding_credits += nblocks;
+ transaction->t_updates++;
+ transaction->t_handle_count++;
+ jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
+ handle, nblocks, transaction->t_outstanding_credits,
+ __jbd2_log_space_left(journal));
+ spin_unlock(&transaction->t_handle_lock);
+ spin_unlock(&journal->j_state_lock);
+out:
+ if (unlikely(new_transaction)) /* It's usually NULL */
+ kfree(new_transaction);
+ return ret;
+}
+
+/* Allocate a new handle. This should probably be in a slab... */
+static handle_t *new_handle(int nblocks)
+{
+ handle_t *handle = jbd_alloc_handle(GFP_NOFS);
+ if (!handle)
+ return NULL;
+ memset(handle, 0, sizeof(*handle));
+ handle->h_buffer_credits = nblocks;
+ handle->h_ref = 1;
+
+ return handle;
+}
+
+/**
+ * handle_t *jbd2_journal_start() - Obtain a new handle.
+ * @journal: Journal to start transaction on.
+ * @nblocks: number of block buffer we might modify
+ *
+ * We make sure that the transaction can guarantee at least nblocks of
+ * modified buffers in the log. We block until the log can guarantee
+ * that much space.
+ *
+ * This function is visible to journal users (like ext3fs), so is not
+ * called with the journal already locked.
+ *
+ * Return a pointer to a newly allocated handle, or NULL on failure
+ */
+handle_t *jbd2_journal_start(journal_t *journal, int nblocks)
+{
+ handle_t *handle = journal_current_handle();
+ int err;
+
+ if (!journal)
+ return ERR_PTR(-EROFS);
+
+ if (handle) {
+ J_ASSERT(handle->h_transaction->t_journal == journal);
+ handle->h_ref++;
+ return handle;
+ }
+
+ handle = new_handle(nblocks);
+ if (!handle)
+ return ERR_PTR(-ENOMEM);
+
+ current->journal_info = handle;
+
+ err = start_this_handle(journal, handle);
+ if (err < 0) {
+ jbd_free_handle(handle);
+ current->journal_info = NULL;
+ handle = ERR_PTR(err);
+ }
+ return handle;
+}
+
+/**
+ * int jbd2_journal_extend() - extend buffer credits.
+ * @handle: handle to 'extend'
+ * @nblocks: nr blocks to try to extend by.
+ *
+ * Some transactions, such as large extends and truncates, can be done
+ * atomically all at once or in several stages. The operation requests
+ * a credit for a number of buffer modications in advance, but can
+ * extend its credit if it needs more.
+ *
+ * jbd2_journal_extend tries to give the running handle more buffer credits.
+ * It does not guarantee that allocation - this is a best-effort only.
+ * The calling process MUST be able to deal cleanly with a failure to
+ * extend here.
+ *
+ * Return 0 on success, non-zero on failure.
+ *
+ * return code < 0 implies an error
+ * return code > 0 implies normal transaction-full status.
+ */
+int jbd2_journal_extend(handle_t *handle, int nblocks)
+{
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+ int result;
+ int wanted;
+
+ result = -EIO;
+ if (is_handle_aborted(handle))
+ goto out;
+
+ result = 1;
+
+ spin_lock(&journal->j_state_lock);
+
+ /* Don't extend a locked-down transaction! */
+ if (handle->h_transaction->t_state != T_RUNNING) {
+ jbd_debug(3, "denied handle %p %d blocks: "
+ "transaction not running\n", handle, nblocks);
+ goto error_out;
+ }
+
+ spin_lock(&transaction->t_handle_lock);
+ wanted = transaction->t_outstanding_credits + nblocks;
+
+ if (wanted > journal->j_max_transaction_buffers) {
+ jbd_debug(3, "denied handle %p %d blocks: "
+ "transaction too large\n", handle, nblocks);
+ goto unlock;
+ }
+
+ if (wanted > __jbd2_log_space_left(journal)) {
+ jbd_debug(3, "denied handle %p %d blocks: "
+ "insufficient log space\n", handle, nblocks);
+ goto unlock;
+ }
+
+ handle->h_buffer_credits += nblocks;
+ transaction->t_outstanding_credits += nblocks;
+ result = 0;
+
+ jbd_debug(3, "extended handle %p by %d\n", handle, nblocks);
+unlock:
+ spin_unlock(&transaction->t_handle_lock);
+error_out:
+ spin_unlock(&journal->j_state_lock);
+out:
+ return result;
+}
+
+
+/**
+ * int jbd2_journal_restart() - restart a handle .
+ * @handle: handle to restart
+ * @nblocks: nr credits requested
+ *
+ * Restart a handle for a multi-transaction filesystem
+ * operation.
+ *
+ * If the jbd2_journal_extend() call above fails to grant new buffer credits
+ * to a running handle, a call to jbd2_journal_restart will commit the
+ * handle's transaction so far and reattach the handle to a new
+ * transaction capabable of guaranteeing the requested number of
+ * credits.
+ */
+
+int jbd2_journal_restart(handle_t *handle, int nblocks)
+{
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+ int ret;
+
+ /* If we've had an abort of any type, don't even think about
+ * actually doing the restart! */
+ if (is_handle_aborted(handle))
+ return 0;
+
+ /*
+ * First unlink the handle from its current transaction, and start the
+ * commit on that.
+ */
+ J_ASSERT(transaction->t_updates > 0);
+ J_ASSERT(journal_current_handle() == handle);
+
+ spin_lock(&journal->j_state_lock);
+ spin_lock(&transaction->t_handle_lock);
+ transaction->t_outstanding_credits -= handle->h_buffer_credits;
+ transaction->t_updates--;
+
+ if (!transaction->t_updates)
+ wake_up(&journal->j_wait_updates);
+ spin_unlock(&transaction->t_handle_lock);
+
+ jbd_debug(2, "restarting handle %p\n", handle);
+ __jbd2_log_start_commit(journal, transaction->t_tid);
+ spin_unlock(&journal->j_state_lock);
+
+ handle->h_buffer_credits = nblocks;
+ ret = start_this_handle(journal, handle);
+ return ret;
+}
+
+
+/**
+ * void jbd2_journal_lock_updates () - establish a transaction barrier.
+ * @journal: Journal to establish a barrier on.
+ *
+ * This locks out any further updates from being started, and blocks
+ * until all existing updates have completed, returning only once the
+ * journal is in a quiescent state with no updates running.
+ *
+ * The journal lock should not be held on entry.
+ */
+void jbd2_journal_lock_updates(journal_t *journal)
+{
+ DEFINE_WAIT(wait);
+
+ spin_lock(&journal->j_state_lock);
+ ++journal->j_barrier_count;
+
+ /* Wait until there are no running updates */
+ while (1) {
+ transaction_t *transaction = journal->j_running_transaction;
+
+ if (!transaction)
+ break;
+
+ spin_lock(&transaction->t_handle_lock);
+ if (!transaction->t_updates) {
+ spin_unlock(&transaction->t_handle_lock);
+ break;
+ }
+ prepare_to_wait(&journal->j_wait_updates, &wait,
+ TASK_UNINTERRUPTIBLE);
+ spin_unlock(&transaction->t_handle_lock);
+ spin_unlock(&journal->j_state_lock);
+ schedule();
+ finish_wait(&journal->j_wait_updates, &wait);
+ spin_lock(&journal->j_state_lock);
+ }
+ spin_unlock(&journal->j_state_lock);
+
+ /*
+ * We have now established a barrier against other normal updates, but
+ * we also need to barrier against other jbd2_journal_lock_updates() calls
+ * to make sure that we serialise special journal-locked operations
+ * too.
+ */
+ mutex_lock(&journal->j_barrier);
+}
+
+/**
+ * void jbd2_journal_unlock_updates (journal_t* journal) - release barrier
+ * @journal: Journal to release the barrier on.
+ *
+ * Release a transaction barrier obtained with jbd2_journal_lock_updates().
+ *
+ * Should be called without the journal lock held.
+ */
+void jbd2_journal_unlock_updates (journal_t *journal)
+{
+ J_ASSERT(journal->j_barrier_count != 0);
+
+ mutex_unlock(&journal->j_barrier);
+ spin_lock(&journal->j_state_lock);
+ --journal->j_barrier_count;
+ spin_unlock(&journal->j_state_lock);
+ wake_up(&journal->j_wait_transaction_locked);
+}
+
+/*
+ * Report any unexpected dirty buffers which turn up. Normally those
+ * indicate an error, but they can occur if the user is running (say)
+ * tune2fs to modify the live filesystem, so we need the option of
+ * continuing as gracefully as possible. #
+ *
+ * The caller should already hold the journal lock and
+ * j_list_lock spinlock: most callers will need those anyway
+ * in order to probe the buffer's journaling state safely.
+ */
+static void jbd_unexpected_dirty_buffer(struct journal_head *jh)
+{
+ int jlist;
+
+ /* If this buffer is one which might reasonably be dirty
+ * --- ie. data, or not part of this journal --- then
+ * we're OK to leave it alone, but otherwise we need to
+ * move the dirty bit to the journal's own internal
+ * JBDDirty bit. */
+ jlist = jh->b_jlist;
+
+ if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
+ jlist == BJ_Shadow || jlist == BJ_Forget) {
+ struct buffer_head *bh = jh2bh(jh);
+
+ if (test_clear_buffer_dirty(bh))
+ set_buffer_jbddirty(bh);
+ }
+}
+
+/*
+ * If the buffer is already part of the current transaction, then there
+ * is nothing we need to do. If it is already part of a prior
+ * transaction which we are still committing to disk, then we need to
+ * make sure that we do not overwrite the old copy: we do copy-out to
+ * preserve the copy going to disk. We also account the buffer against
+ * the handle's metadata buffer credits (unless the buffer is already
+ * part of the transaction, that is).
+ *
+ */
+static int
+do_get_write_access(handle_t *handle, struct journal_head *jh,
+ int force_copy)
+{
+ struct buffer_head *bh;
+ transaction_t *transaction;
+ journal_t *journal;
+ int error;
+ char *frozen_buffer = NULL;
+ int need_copy = 0;
+
+ if (is_handle_aborted(handle))
+ return -EROFS;
+
+ transaction = handle->h_transaction;
+ journal = transaction->t_journal;
+
+ jbd_debug(5, "buffer_head %p, force_copy %d\n", jh, force_copy);
+
+ JBUFFER_TRACE(jh, "entry");
+repeat:
+ bh = jh2bh(jh);
+
+ /* @@@ Need to check for errors here at some point. */
+
+ lock_buffer(bh);
+ jbd_lock_bh_state(bh);
+
+ /* We now hold the buffer lock so it is safe to query the buffer
+ * state. Is the buffer dirty?
+ *
+ * If so, there are two possibilities. The buffer may be
+ * non-journaled, and undergoing a quite legitimate writeback.
+ * Otherwise, it is journaled, and we don't expect dirty buffers
+ * in that state (the buffers should be marked JBD_Dirty
+ * instead.) So either the IO is being done under our own
+ * control and this is a bug, or it's a third party IO such as
+ * dump(8) (which may leave the buffer scheduled for read ---
+ * ie. locked but not dirty) or tune2fs (which may actually have
+ * the buffer dirtied, ugh.) */
+
+ if (buffer_dirty(bh)) {
+ /*
+ * First question: is this buffer already part of the current
+ * transaction or the existing committing transaction?
+ */
+ if (jh->b_transaction) {
+ J_ASSERT_JH(jh,
+ jh->b_transaction == transaction ||
+ jh->b_transaction ==
+ journal->j_committing_transaction);
+ if (jh->b_next_transaction)
+ J_ASSERT_JH(jh, jh->b_next_transaction ==
+ transaction);
+ }
+ /*
+ * In any case we need to clean the dirty flag and we must
+ * do it under the buffer lock to be sure we don't race
+ * with running write-out.
+ */
+ JBUFFER_TRACE(jh, "Unexpected dirty buffer");
+ jbd_unexpected_dirty_buffer(jh);
+ }
+
+ unlock_buffer(bh);
+
+ error = -EROFS;
+ if (is_handle_aborted(handle)) {
+ jbd_unlock_bh_state(bh);
+ goto out;
+ }
+ error = 0;
+
+ /*
+ * The buffer is already part of this transaction if b_transaction or
+ * b_next_transaction points to it
+ */
+ if (jh->b_transaction == transaction ||
+ jh->b_next_transaction == transaction)
+ goto done;
+
+ /*
+ * If there is already a copy-out version of this buffer, then we don't
+ * need to make another one
+ */
+ if (jh->b_frozen_data) {
+ JBUFFER_TRACE(jh, "has frozen data");
+ J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+ jh->b_next_transaction = transaction;
+ goto done;
+ }
+
+ /* Is there data here we need to preserve? */
+
+ if (jh->b_transaction && jh->b_transaction != transaction) {
+ JBUFFER_TRACE(jh, "owned by older transaction");
+ J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+ J_ASSERT_JH(jh, jh->b_transaction ==
+ journal->j_committing_transaction);
+
+ /* There is one case we have to be very careful about.
+ * If the committing transaction is currently writing
+ * this buffer out to disk and has NOT made a copy-out,
+ * then we cannot modify the buffer contents at all
+ * right now. The essence of copy-out is that it is the
+ * extra copy, not the primary copy, which gets
+ * journaled. If the primary copy is already going to
+ * disk then we cannot do copy-out here. */
+
+ if (jh->b_jlist == BJ_Shadow) {
+ DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Unshadow);
+ wait_queue_head_t *wqh;
+
+ wqh = bit_waitqueue(&bh->b_state, BH_Unshadow);
+
+ JBUFFER_TRACE(jh, "on shadow: sleep");
+ jbd_unlock_bh_state(bh);
+ /* commit wakes up all shadow buffers after IO */
+ for ( ; ; ) {
+ prepare_to_wait(wqh, &wait.wait,
+ TASK_UNINTERRUPTIBLE);
+ if (jh->b_jlist != BJ_Shadow)
+ break;
+ schedule();
+ }
+ finish_wait(wqh, &wait.wait);
+ goto repeat;
+ }
+
+ /* Only do the copy if the currently-owning transaction
+ * still needs it. If it is on the Forget list, the
+ * committing transaction is past that stage. The
+ * buffer had better remain locked during the kmalloc,
+ * but that should be true --- we hold the journal lock
+ * still and the buffer is already on the BUF_JOURNAL
+ * list so won't be flushed.
+ *
+ * Subtle point, though: if this is a get_undo_access,
+ * then we will be relying on the frozen_data to contain
+ * the new value of the committed_data record after the
+ * transaction, so we HAVE to force the frozen_data copy
+ * in that case. */
+
+ if (jh->b_jlist != BJ_Forget || force_copy) {
+ JBUFFER_TRACE(jh, "generate frozen data");
+ if (!frozen_buffer) {
+ JBUFFER_TRACE(jh, "allocate memory for buffer");
+ jbd_unlock_bh_state(bh);
+ frozen_buffer =
+ jbd2_slab_alloc(jh2bh(jh)->b_size,
+ GFP_NOFS);
+ if (!frozen_buffer) {
+ printk(KERN_EMERG
+ "%s: OOM for frozen_buffer\n",
+ __FUNCTION__);
+ JBUFFER_TRACE(jh, "oom!");
+ error = -ENOMEM;
+ jbd_lock_bh_state(bh);
+ goto done;
+ }
+ goto repeat;
+ }
+ jh->b_frozen_data = frozen_buffer;
+ frozen_buffer = NULL;
+ need_copy = 1;
+ }
+ jh->b_next_transaction = transaction;
+ }
+
+
+ /*
+ * Finally, if the buffer is not journaled right now, we need to make
+ * sure it doesn't get written to disk before the caller actually
+ * commits the new data
+ */
+ if (!jh->b_transaction) {
+ JBUFFER_TRACE(jh, "no transaction");
+ J_ASSERT_JH(jh, !jh->b_next_transaction);
+ jh->b_transaction = transaction;
+ JBUFFER_TRACE(jh, "file as BJ_Reserved");
+ spin_lock(&journal->j_list_lock);
+ __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
+ spin_unlock(&journal->j_list_lock);
+ }
+
+done:
+ if (need_copy) {
+ struct page *page;
+ int offset;
+ char *source;
+
+ J_EXPECT_JH(jh, buffer_uptodate(jh2bh(jh)),
+ "Possible IO failure.\n");
+ page = jh2bh(jh)->b_page;
+ offset = ((unsigned long) jh2bh(jh)->b_data) & ~PAGE_MASK;
+ source = kmap_atomic(page, KM_USER0);
+ memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size);
+ kunmap_atomic(source, KM_USER0);
+ }
+ jbd_unlock_bh_state(bh);
+
+ /*
+ * If we are about to journal a buffer, then any revoke pending on it is
+ * no longer valid
+ */
+ jbd2_journal_cancel_revoke(handle, jh);
+
+out:
+ if (unlikely(frozen_buffer)) /* It's usually NULL */
+ jbd2_slab_free(frozen_buffer, bh->b_size);
+
+ JBUFFER_TRACE(jh, "exit");
+ return error;
+}
+
+/**
+ * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update.
+ * @handle: transaction to add buffer modifications to
+ * @bh: bh to be used for metadata writes
+ * @credits: variable that will receive credits for the buffer
+ *
+ * Returns an error code or 0 on success.
+ *
+ * In full data journalling mode the buffer may be of type BJ_AsyncData,
+ * because we're write()ing a buffer which is also part of a shared mapping.
+ */
+
+int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh)
+{
+ struct journal_head *jh = jbd2_journal_add_journal_head(bh);
+ int rc;
+
+ /* We do not want to get caught playing with fields which the
+ * log thread also manipulates. Make sure that the buffer
+ * completes any outstanding IO before proceeding. */
+ rc = do_get_write_access(handle, jh, 0);
+ jbd2_journal_put_journal_head(jh);
+ return rc;
+}
+
+
+/*
+ * When the user wants to journal a newly created buffer_head
+ * (ie. getblk() returned a new buffer and we are going to populate it
+ * manually rather than reading off disk), then we need to keep the
+ * buffer_head locked until it has been completely filled with new
+ * data. In this case, we should be able to make the assertion that
+ * the bh is not already part of an existing transaction.
+ *
+ * The buffer should already be locked by the caller by this point.
+ * There is no lock ranking violation: it was a newly created,
+ * unlocked buffer beforehand. */
+
+/**
+ * int jbd2_journal_get_create_access () - notify intent to use newly created bh
+ * @handle: transaction to new buffer to
+ * @bh: new buffer.
+ *
+ * Call this if you create a new bh.
+ */
+int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh)
+{
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+ struct journal_head *jh = jbd2_journal_add_journal_head(bh);
+ int err;
+
+ jbd_debug(5, "journal_head %p\n", jh);
+ err = -EROFS;
+ if (is_handle_aborted(handle))
+ goto out;
+ err = 0;
+
+ JBUFFER_TRACE(jh, "entry");
+ /*
+ * The buffer may already belong to this transaction due to pre-zeroing
+ * in the filesystem's new_block code. It may also be on the previous,
+ * committing transaction's lists, but it HAS to be in Forget state in
+ * that case: the transaction must have deleted the buffer for it to be
+ * reused here.
+ */
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
+ J_ASSERT_JH(jh, (jh->b_transaction == transaction ||
+ jh->b_transaction == NULL ||
+ (jh->b_transaction == journal->j_committing_transaction &&
+ jh->b_jlist == BJ_Forget)));
+
+ J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+ J_ASSERT_JH(jh, buffer_locked(jh2bh(jh)));
+
+ if (jh->b_transaction == NULL) {
+ jh->b_transaction = transaction;
+ JBUFFER_TRACE(jh, "file as BJ_Reserved");
+ __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved);
+ } else if (jh->b_transaction == journal->j_committing_transaction) {
+ JBUFFER_TRACE(jh, "set next transaction");
+ jh->b_next_transaction = transaction;
+ }
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+
+ /*
+ * akpm: I added this. ext3_alloc_branch can pick up new indirect
+ * blocks which contain freed but then revoked metadata. We need
+ * to cancel the revoke in case we end up freeing it yet again
+ * and the reallocating as data - this would cause a second revoke,
+ * which hits an assertion error.
+ */
+ JBUFFER_TRACE(jh, "cancelling revoke");
+ jbd2_journal_cancel_revoke(handle, jh);
+ jbd2_journal_put_journal_head(jh);
+out:
+ return err;
+}
+
+/**
+ * int jbd2_journal_get_undo_access() - Notify intent to modify metadata with
+ * non-rewindable consequences
+ * @handle: transaction
+ * @bh: buffer to undo
+ * @credits: store the number of taken credits here (if not NULL)
+ *
+ * Sometimes there is a need to distinguish between metadata which has
+ * been committed to disk and that which has not. The ext3fs code uses
+ * this for freeing and allocating space, we have to make sure that we
+ * do not reuse freed space until the deallocation has been committed,
+ * since if we overwrote that space we would make the delete
+ * un-rewindable in case of a crash.
+ *
+ * To deal with that, jbd2_journal_get_undo_access requests write access to a
+ * buffer for parts of non-rewindable operations such as delete
+ * operations on the bitmaps. The journaling code must keep a copy of
+ * the buffer's contents prior to the undo_access call until such time
+ * as we know that the buffer has definitely been committed to disk.
+ *
+ * We never need to know which transaction the committed data is part
+ * of, buffers touched here are guaranteed to be dirtied later and so
+ * will be committed to a new transaction in due course, at which point
+ * we can discard the old committed data pointer.
+ *
+ * Returns error number or 0 on success.
+ */
+int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh)
+{
+ int err;
+ struct journal_head *jh = jbd2_journal_add_journal_head(bh);
+ char *committed_data = NULL;
+
+ JBUFFER_TRACE(jh, "entry");
+
+ /*
+ * Do this first --- it can drop the journal lock, so we want to
+ * make sure that obtaining the committed_data is done
+ * atomically wrt. completion of any outstanding commits.
+ */
+ err = do_get_write_access(handle, jh, 1);
+ if (err)
+ goto out;
+
+repeat:
+ if (!jh->b_committed_data) {
+ committed_data = jbd2_slab_alloc(jh2bh(jh)->b_size, GFP_NOFS);
+ if (!committed_data) {
+ printk(KERN_EMERG "%s: No memory for committed data\n",
+ __FUNCTION__);
+ err = -ENOMEM;
+ goto out;
+ }
+ }
+
+ jbd_lock_bh_state(bh);
+ if (!jh->b_committed_data) {
+ /* Copy out the current buffer contents into the
+ * preserved, committed copy. */
+ JBUFFER_TRACE(jh, "generate b_committed data");
+ if (!committed_data) {
+ jbd_unlock_bh_state(bh);
+ goto repeat;
+ }
+
+ jh->b_committed_data = committed_data;
+ committed_data = NULL;
+ memcpy(jh->b_committed_data, bh->b_data, bh->b_size);
+ }
+ jbd_unlock_bh_state(bh);
+out:
+ jbd2_journal_put_journal_head(jh);
+ if (unlikely(committed_data))
+ jbd2_slab_free(committed_data, bh->b_size);
+ return err;
+}
+
+/**
+ * int jbd2_journal_dirty_data() - mark a buffer as containing dirty data which
+ * needs to be flushed before we can commit the
+ * current transaction.
+ * @handle: transaction
+ * @bh: bufferhead to mark
+ *
+ * The buffer is placed on the transaction's data list and is marked as
+ * belonging to the transaction.
+ *
+ * Returns error number or 0 on success.
+ *
+ * jbd2_journal_dirty_data() can be called via page_launder->ext3_writepage
+ * by kswapd.
+ */
+int jbd2_journal_dirty_data(handle_t *handle, struct buffer_head *bh)
+{
+ journal_t *journal = handle->h_transaction->t_journal;
+ int need_brelse = 0;
+ struct journal_head *jh;
+
+ if (is_handle_aborted(handle))
+ return 0;
+
+ jh = jbd2_journal_add_journal_head(bh);
+ JBUFFER_TRACE(jh, "entry");
+
+ /*
+ * The buffer could *already* be dirty. Writeout can start
+ * at any time.
+ */
+ jbd_debug(4, "jh: %p, tid:%d\n", jh, handle->h_transaction->t_tid);
+
+ /*
+ * What if the buffer is already part of a running transaction?
+ *
+ * There are two cases:
+ * 1) It is part of the current running transaction. Refile it,
+ * just in case we have allocated it as metadata, deallocated
+ * it, then reallocated it as data.
+ * 2) It is part of the previous, still-committing transaction.
+ * If all we want to do is to guarantee that the buffer will be
+ * written to disk before this new transaction commits, then
+ * being sure that the *previous* transaction has this same
+ * property is sufficient for us! Just leave it on its old
+ * transaction.
+ *
+ * In case (2), the buffer must not already exist as metadata
+ * --- that would violate write ordering (a transaction is free
+ * to write its data at any point, even before the previous
+ * committing transaction has committed). The caller must
+ * never, ever allow this to happen: there's nothing we can do
+ * about it in this layer.
+ */
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
+ if (jh->b_transaction) {
+ JBUFFER_TRACE(jh, "has transaction");
+ if (jh->b_transaction != handle->h_transaction) {
+ JBUFFER_TRACE(jh, "belongs to older transaction");
+ J_ASSERT_JH(jh, jh->b_transaction ==
+ journal->j_committing_transaction);
+
+ /* @@@ IS THIS TRUE ? */
+ /*
+ * Not any more. Scenario: someone does a write()
+ * in data=journal mode. The buffer's transaction has
+ * moved into commit. Then someone does another
+ * write() to the file. We do the frozen data copyout
+ * and set b_next_transaction to point to j_running_t.
+ * And while we're in that state, someone does a
+ * writepage() in an attempt to pageout the same area
+ * of the file via a shared mapping. At present that
+ * calls jbd2_journal_dirty_data(), and we get right here.
+ * It may be too late to journal the data. Simply
+ * falling through to the next test will suffice: the
+ * data will be dirty and wil be checkpointed. The
+ * ordering comments in the next comment block still
+ * apply.
+ */
+ //J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
+
+ /*
+ * If we're journalling data, and this buffer was
+ * subject to a write(), it could be metadata, forget
+ * or shadow against the committing transaction. Now,
+ * someone has dirtied the same darn page via a mapping
+ * and it is being writepage()'d.
+ * We *could* just steal the page from commit, with some
+ * fancy locking there. Instead, we just skip it -
+ * don't tie the page's buffers to the new transaction
+ * at all.
+ * Implication: if we crash before the writepage() data
+ * is written into the filesystem, recovery will replay
+ * the write() data.
+ */
+ if (jh->b_jlist != BJ_None &&
+ jh->b_jlist != BJ_SyncData &&
+ jh->b_jlist != BJ_Locked) {
+ JBUFFER_TRACE(jh, "Not stealing");
+ goto no_journal;
+ }
+
+ /*
+ * This buffer may be undergoing writeout in commit. We
+ * can't return from here and let the caller dirty it
+ * again because that can cause the write-out loop in
+ * commit to never terminate.
+ */
+ if (buffer_dirty(bh)) {
+ get_bh(bh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ need_brelse = 1;
+ sync_dirty_buffer(bh);
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
+ /* The buffer may become locked again at any
+ time if it is redirtied */
+ }
+
+ /* journal_clean_data_list() may have got there first */
+ if (jh->b_transaction != NULL) {
+ JBUFFER_TRACE(jh, "unfile from commit");
+ __jbd2_journal_temp_unlink_buffer(jh);
+ /* It still points to the committing
+ * transaction; move it to this one so
+ * that the refile assert checks are
+ * happy. */
+ jh->b_transaction = handle->h_transaction;
+ }
+ /* The buffer will be refiled below */
+
+ }
+ /*
+ * Special case --- the buffer might actually have been
+ * allocated and then immediately deallocated in the previous,
+ * committing transaction, so might still be left on that
+ * transaction's metadata lists.
+ */
+ if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) {
+ JBUFFER_TRACE(jh, "not on correct data list: unfile");
+ J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow);
+ __jbd2_journal_temp_unlink_buffer(jh);
+ jh->b_transaction = handle->h_transaction;
+ JBUFFER_TRACE(jh, "file as data");
+ __jbd2_journal_file_buffer(jh, handle->h_transaction,
+ BJ_SyncData);
+ }
+ } else {
+ JBUFFER_TRACE(jh, "not on a transaction");
+ __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_SyncData);
+ }
+no_journal:
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ if (need_brelse) {
+ BUFFER_TRACE(bh, "brelse");
+ __brelse(bh);
+ }
+ JBUFFER_TRACE(jh, "exit");
+ jbd2_journal_put_journal_head(jh);
+ return 0;
+}
+
+/**
+ * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata
+ * @handle: transaction to add buffer to.
+ * @bh: buffer to mark
+ *
+ * mark dirty metadata which needs to be journaled as part of the current
+ * transaction.
+ *
+ * The buffer is placed on the transaction's metadata list and is marked
+ * as belonging to the transaction.
+ *
+ * Returns error number or 0 on success.
+ *
+ * Special care needs to be taken if the buffer already belongs to the
+ * current committing transaction (in which case we should have frozen
+ * data present for that commit). In that case, we don't relink the
+ * buffer: that only gets done when the old transaction finally
+ * completes its commit.
+ */
+int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh)
+{
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+ struct journal_head *jh = bh2jh(bh);
+
+ jbd_debug(5, "journal_head %p\n", jh);
+ JBUFFER_TRACE(jh, "entry");
+ if (is_handle_aborted(handle))
+ goto out;
+
+ jbd_lock_bh_state(bh);
+
+ if (jh->b_modified == 0) {
+ /*
+ * This buffer's got modified and becoming part
+ * of the transaction. This needs to be done
+ * once a transaction -bzzz
+ */
+ jh->b_modified = 1;
+ J_ASSERT_JH(jh, handle->h_buffer_credits > 0);
+ handle->h_buffer_credits--;
+ }
+
+ /*
+ * fastpath, to avoid expensive locking. If this buffer is already
+ * on the running transaction's metadata list there is nothing to do.
+ * Nobody can take it off again because there is a handle open.
+ * I _think_ we're OK here with SMP barriers - a mistaken decision will
+ * result in this test being false, so we go in and take the locks.
+ */
+ if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) {
+ JBUFFER_TRACE(jh, "fastpath");
+ J_ASSERT_JH(jh, jh->b_transaction ==
+ journal->j_running_transaction);
+ goto out_unlock_bh;
+ }
+
+ set_buffer_jbddirty(bh);
+
+ /*
+ * Metadata already on the current transaction list doesn't
+ * need to be filed. Metadata on another transaction's list must
+ * be committing, and will be refiled once the commit completes:
+ * leave it alone for now.
+ */
+ if (jh->b_transaction != transaction) {
+ JBUFFER_TRACE(jh, "already on other transaction");
+ J_ASSERT_JH(jh, jh->b_transaction ==
+ journal->j_committing_transaction);
+ J_ASSERT_JH(jh, jh->b_next_transaction == transaction);
+ /* And this case is illegal: we can't reuse another
+ * transaction's data buffer, ever. */
+ goto out_unlock_bh;
+ }
+
+ /* That test should have eliminated the following case: */
+ J_ASSERT_JH(jh, jh->b_frozen_data == 0);
+
+ JBUFFER_TRACE(jh, "file as BJ_Metadata");
+ spin_lock(&journal->j_list_lock);
+ __jbd2_journal_file_buffer(jh, handle->h_transaction, BJ_Metadata);
+ spin_unlock(&journal->j_list_lock);
+out_unlock_bh:
+ jbd_unlock_bh_state(bh);
+out:
+ JBUFFER_TRACE(jh, "exit");
+ return 0;
+}
+
+/*
+ * jbd2_journal_release_buffer: undo a get_write_access without any buffer
+ * updates, if the update decided in the end that it didn't need access.
+ *
+ */
+void
+jbd2_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
+{
+ BUFFER_TRACE(bh, "entry");
+}
+
+/**
+ * void jbd2_journal_forget() - bforget() for potentially-journaled buffers.
+ * @handle: transaction handle
+ * @bh: bh to 'forget'
+ *
+ * We can only do the bforget if there are no commits pending against the
+ * buffer. If the buffer is dirty in the current running transaction we
+ * can safely unlink it.
+ *
+ * bh may not be a journalled buffer at all - it may be a non-JBD
+ * buffer which came off the hashtable. Check for this.
+ *
+ * Decrements bh->b_count by one.
+ *
+ * Allow this call even if the handle has aborted --- it may be part of
+ * the caller's cleanup after an abort.
+ */
+int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh)
+{
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+ struct journal_head *jh;
+ int drop_reserve = 0;
+ int err = 0;
+
+ BUFFER_TRACE(bh, "entry");
+
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
+
+ if (!buffer_jbd(bh))
+ goto not_jbd;
+ jh = bh2jh(bh);
+
+ /* Critical error: attempting to delete a bitmap buffer, maybe?
+ * Don't do any jbd operations, and return an error. */
+ if (!J_EXPECT_JH(jh, !jh->b_committed_data,
+ "inconsistent data on disk")) {
+ err = -EIO;
+ goto not_jbd;
+ }
+
+ /*
+ * The buffer's going from the transaction, we must drop
+ * all references -bzzz
+ */
+ jh->b_modified = 0;
+
+ if (jh->b_transaction == handle->h_transaction) {
+ J_ASSERT_JH(jh, !jh->b_frozen_data);
+
+ /* If we are forgetting a buffer which is already part
+ * of this transaction, then we can just drop it from
+ * the transaction immediately. */
+ clear_buffer_dirty(bh);
+ clear_buffer_jbddirty(bh);
+
+ JBUFFER_TRACE(jh, "belongs to current transaction: unfile");
+
+ drop_reserve = 1;
+
+ /*
+ * We are no longer going to journal this buffer.
+ * However, the commit of this transaction is still
+ * important to the buffer: the delete that we are now
+ * processing might obsolete an old log entry, so by
+ * committing, we can satisfy the buffer's checkpoint.
+ *
+ * So, if we have a checkpoint on the buffer, we should
+ * now refile the buffer on our BJ_Forget list so that
+ * we know to remove the checkpoint after we commit.
+ */
+
+ if (jh->b_cp_transaction) {
+ __jbd2_journal_temp_unlink_buffer(jh);
+ __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
+ } else {
+ __jbd2_journal_unfile_buffer(jh);
+ jbd2_journal_remove_journal_head(bh);
+ __brelse(bh);
+ if (!buffer_jbd(bh)) {
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ __bforget(bh);
+ goto drop;
+ }
+ }
+ } else if (jh->b_transaction) {
+ J_ASSERT_JH(jh, (jh->b_transaction ==
+ journal->j_committing_transaction));
+ /* However, if the buffer is still owned by a prior
+ * (committing) transaction, we can't drop it yet... */
+ JBUFFER_TRACE(jh, "belongs to older transaction");
+ /* ... but we CAN drop it from the new transaction if we
+ * have also modified it since the original commit. */
+
+ if (jh->b_next_transaction) {
+ J_ASSERT(jh->b_next_transaction == transaction);
+ jh->b_next_transaction = NULL;
+ drop_reserve = 1;
+ }
+ }
+
+not_jbd:
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ __brelse(bh);
+drop:
+ if (drop_reserve) {
+ /* no need to reserve log space for this block -bzzz */
+ handle->h_buffer_credits++;
+ }
+ return err;
+}
+
+/**
+ * int jbd2_journal_stop() - complete a transaction
+ * @handle: tranaction to complete.
+ *
+ * All done for a particular handle.
+ *
+ * There is not much action needed here. We just return any remaining
+ * buffer credits to the transaction and remove the handle. The only
+ * complication is that we need to start a commit operation if the
+ * filesystem is marked for synchronous update.
+ *
+ * jbd2_journal_stop itself will not usually return an error, but it may
+ * do so in unusual circumstances. In particular, expect it to
+ * return -EIO if a jbd2_journal_abort has been executed since the
+ * transaction began.
+ */
+int jbd2_journal_stop(handle_t *handle)
+{
+ transaction_t *transaction = handle->h_transaction;
+ journal_t *journal = transaction->t_journal;
+ int old_handle_count, err;
+ pid_t pid;
+
+ J_ASSERT(journal_current_handle() == handle);
+
+ if (is_handle_aborted(handle))
+ err = -EIO;
+ else {
+ J_ASSERT(transaction->t_updates > 0);
+ err = 0;
+ }
+
+ if (--handle->h_ref > 0) {
+ jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1,
+ handle->h_ref);
+ return err;
+ }
+
+ jbd_debug(4, "Handle %p going down\n", handle);
+
+ /*
+ * Implement synchronous transaction batching. If the handle
+ * was synchronous, don't force a commit immediately. Let's
+ * yield and let another thread piggyback onto this transaction.
+ * Keep doing that while new threads continue to arrive.
+ * It doesn't cost much - we're about to run a commit and sleep
+ * on IO anyway. Speeds up many-threaded, many-dir operations
+ * by 30x or more...
+ *
+ * But don't do this if this process was the most recent one to
+ * perform a synchronous write. We do this to detect the case where a
+ * single process is doing a stream of sync writes. No point in waiting
+ * for joiners in that case.
+ */
+ pid = current->pid;
+ if (handle->h_sync && journal->j_last_sync_writer != pid) {
+ journal->j_last_sync_writer = pid;
+ do {
+ old_handle_count = transaction->t_handle_count;
+ schedule_timeout_uninterruptible(1);
+ } while (old_handle_count != transaction->t_handle_count);
+ }
+
+ current->journal_info = NULL;
+ spin_lock(&journal->j_state_lock);
+ spin_lock(&transaction->t_handle_lock);
+ transaction->t_outstanding_credits -= handle->h_buffer_credits;
+ transaction->t_updates--;
+ if (!transaction->t_updates) {
+ wake_up(&journal->j_wait_updates);
+ if (journal->j_barrier_count)
+ wake_up(&journal->j_wait_transaction_locked);
+ }
+
+ /*
+ * If the handle is marked SYNC, we need to set another commit
+ * going! We also want to force a commit if the current
+ * transaction is occupying too much of the log, or if the
+ * transaction is too old now.
+ */
+ if (handle->h_sync ||
+ transaction->t_outstanding_credits >
+ journal->j_max_transaction_buffers ||
+ time_after_eq(jiffies, transaction->t_expires)) {
+ /* Do this even for aborted journals: an abort still
+ * completes the commit thread, it just doesn't write
+ * anything to disk. */
+ tid_t tid = transaction->t_tid;
+
+ spin_unlock(&transaction->t_handle_lock);
+ jbd_debug(2, "transaction too old, requesting commit for "
+ "handle %p\n", handle);
+ /* This is non-blocking */
+ __jbd2_log_start_commit(journal, transaction->t_tid);
+ spin_unlock(&journal->j_state_lock);
+
+ /*
+ * Special case: JBD2_SYNC synchronous updates require us
+ * to wait for the commit to complete.
+ */
+ if (handle->h_sync && !(current->flags & PF_MEMALLOC))
+ err = jbd2_log_wait_commit(journal, tid);
+ } else {
+ spin_unlock(&transaction->t_handle_lock);
+ spin_unlock(&journal->j_state_lock);
+ }
+
+ jbd_free_handle(handle);
+ return err;
+}
+
+/**int jbd2_journal_force_commit() - force any uncommitted transactions
+ * @journal: journal to force
+ *
+ * For synchronous operations: force any uncommitted transactions
+ * to disk. May seem kludgy, but it reuses all the handle batching
+ * code in a very simple manner.
+ */
+int jbd2_journal_force_commit(journal_t *journal)
+{
+ handle_t *handle;
+ int ret;
+
+ handle = jbd2_journal_start(journal, 1);
+ if (IS_ERR(handle)) {
+ ret = PTR_ERR(handle);
+ } else {
+ handle->h_sync = 1;
+ ret = jbd2_journal_stop(handle);
+ }
+ return ret;
+}
+
+/*
+ *
+ * List management code snippets: various functions for manipulating the
+ * transaction buffer lists.
+ *
+ */
+
+/*
+ * Append a buffer to a transaction list, given the transaction's list head
+ * pointer.
+ *
+ * j_list_lock is held.
+ *
+ * jbd_lock_bh_state(jh2bh(jh)) is held.
+ */
+
+static inline void
+__blist_add_buffer(struct journal_head **list, struct journal_head *jh)
+{
+ if (!*list) {
+ jh->b_tnext = jh->b_tprev = jh;
+ *list = jh;
+ } else {
+ /* Insert at the tail of the list to preserve order */
+ struct journal_head *first = *list, *last = first->b_tprev;
+ jh->b_tprev = last;
+ jh->b_tnext = first;
+ last->b_tnext = first->b_tprev = jh;
+ }
+}
+
+/*
+ * Remove a buffer from a transaction list, given the transaction's list
+ * head pointer.
+ *
+ * Called with j_list_lock held, and the journal may not be locked.
+ *
+ * jbd_lock_bh_state(jh2bh(jh)) is held.
+ */
+
+static inline void
+__blist_del_buffer(struct journal_head **list, struct journal_head *jh)
+{
+ if (*list == jh) {
+ *list = jh->b_tnext;
+ if (*list == jh)
+ *list = NULL;
+ }
+ jh->b_tprev->b_tnext = jh->b_tnext;
+ jh->b_tnext->b_tprev = jh->b_tprev;
+}
+
+/*
+ * Remove a buffer from the appropriate transaction list.
+ *
+ * Note that this function can *change* the value of
+ * bh->b_transaction->t_sync_datalist, t_buffers, t_forget,
+ * t_iobuf_list, t_shadow_list, t_log_list or t_reserved_list. If the caller
+ * is holding onto a copy of one of thee pointers, it could go bad.
+ * Generally the caller needs to re-read the pointer from the transaction_t.
+ *
+ * Called under j_list_lock. The journal may not be locked.
+ */
+void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh)
+{
+ struct journal_head **list = NULL;
+ transaction_t *transaction;
+ struct buffer_head *bh = jh2bh(jh);
+
+ J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
+ transaction = jh->b_transaction;
+ if (transaction)
+ assert_spin_locked(&transaction->t_journal->j_list_lock);
+
+ J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
+ if (jh->b_jlist != BJ_None)
+ J_ASSERT_JH(jh, transaction != 0);
+
+ switch (jh->b_jlist) {
+ case BJ_None:
+ return;
+ case BJ_SyncData:
+ list = &transaction->t_sync_datalist;
+ break;
+ case BJ_Metadata:
+ transaction->t_nr_buffers--;
+ J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0);
+ list = &transaction->t_buffers;
+ break;
+ case BJ_Forget:
+ list = &transaction->t_forget;
+ break;
+ case BJ_IO:
+ list = &transaction->t_iobuf_list;
+ break;
+ case BJ_Shadow:
+ list = &transaction->t_shadow_list;
+ break;
+ case BJ_LogCtl:
+ list = &transaction->t_log_list;
+ break;
+ case BJ_Reserved:
+ list = &transaction->t_reserved_list;
+ break;
+ case BJ_Locked:
+ list = &transaction->t_locked_list;
+ break;
+ }
+
+ __blist_del_buffer(list, jh);
+ jh->b_jlist = BJ_None;
+ if (test_clear_buffer_jbddirty(bh))
+ mark_buffer_dirty(bh); /* Expose it to the VM */
+}
+
+void __jbd2_journal_unfile_buffer(struct journal_head *jh)
+{
+ __jbd2_journal_temp_unlink_buffer(jh);
+ jh->b_transaction = NULL;
+}
+
+void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
+{
+ jbd_lock_bh_state(jh2bh(jh));
+ spin_lock(&journal->j_list_lock);
+ __jbd2_journal_unfile_buffer(jh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(jh2bh(jh));
+}
+
+/*
+ * Called from jbd2_journal_try_to_free_buffers().
+ *
+ * Called under jbd_lock_bh_state(bh)
+ */
+static void
+__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
+{
+ struct journal_head *jh;
+
+ jh = bh2jh(bh);
+
+ if (buffer_locked(bh) || buffer_dirty(bh))
+ goto out;
+
+ if (jh->b_next_transaction != 0)
+ goto out;
+
+ spin_lock(&journal->j_list_lock);
+ if (jh->b_transaction != 0 && jh->b_cp_transaction == 0) {
+ if (jh->b_jlist == BJ_SyncData || jh->b_jlist == BJ_Locked) {
+ /* A written-back ordered data buffer */
+ JBUFFER_TRACE(jh, "release data");
+ __jbd2_journal_unfile_buffer(jh);
+ jbd2_journal_remove_journal_head(bh);
+ __brelse(bh);
+ }
+ } else if (jh->b_cp_transaction != 0 && jh->b_transaction == 0) {
+ /* written-back checkpointed metadata buffer */
+ if (jh->b_jlist == BJ_None) {
+ JBUFFER_TRACE(jh, "remove from checkpoint list");
+ __jbd2_journal_remove_checkpoint(jh);
+ jbd2_journal_remove_journal_head(bh);
+ __brelse(bh);
+ }
+ }
+ spin_unlock(&journal->j_list_lock);
+out:
+ return;
+}
+
+
+/**
+ * int jbd2_journal_try_to_free_buffers() - try to free page buffers.
+ * @journal: journal for operation
+ * @page: to try and free
+ * @unused_gfp_mask: unused
+ *
+ *
+ * For all the buffers on this page,
+ * if they are fully written out ordered data, move them onto BUF_CLEAN
+ * so try_to_free_buffers() can reap them.
+ *
+ * This function returns non-zero if we wish try_to_free_buffers()
+ * to be called. We do this if the page is releasable by try_to_free_buffers().
+ * We also do it if the page has locked or dirty buffers and the caller wants
+ * us to perform sync or async writeout.
+ *
+ * This complicates JBD locking somewhat. We aren't protected by the
+ * BKL here. We wish to remove the buffer from its committing or
+ * running transaction's ->t_datalist via __jbd2_journal_unfile_buffer.
+ *
+ * This may *change* the value of transaction_t->t_datalist, so anyone
+ * who looks at t_datalist needs to lock against this function.
+ *
+ * Even worse, someone may be doing a jbd2_journal_dirty_data on this
+ * buffer. So we need to lock against that. jbd2_journal_dirty_data()
+ * will come out of the lock with the buffer dirty, which makes it
+ * ineligible for release here.
+ *
+ * Who else is affected by this? hmm... Really the only contender
+ * is do_get_write_access() - it could be looking at the buffer while
+ * journal_try_to_free_buffer() is changing its state. But that
+ * cannot happen because we never reallocate freed data as metadata
+ * while the data is part of a transaction. Yes?
+ */
+int jbd2_journal_try_to_free_buffers(journal_t *journal,
+ struct page *page, gfp_t unused_gfp_mask)
+{
+ struct buffer_head *head;
+ struct buffer_head *bh;
+ int ret = 0;
+
+ J_ASSERT(PageLocked(page));
+
+ head = page_buffers(page);
+ bh = head;
+ do {
+ struct journal_head *jh;
+
+ /*
+ * We take our own ref against the journal_head here to avoid
+ * having to add tons of locking around each instance of
+ * jbd2_journal_remove_journal_head() and jbd2_journal_put_journal_head().
+ */
+ jh = jbd2_journal_grab_journal_head(bh);
+ if (!jh)
+ continue;
+
+ jbd_lock_bh_state(bh);
+ __journal_try_to_free_buffer(journal, bh);
+ jbd2_journal_put_journal_head(jh);
+ jbd_unlock_bh_state(bh);
+ if (buffer_jbd(bh))
+ goto busy;
+ } while ((bh = bh->b_this_page) != head);
+ ret = try_to_free_buffers(page);
+busy:
+ return ret;
+}
+
+/*
+ * This buffer is no longer needed. If it is on an older transaction's
+ * checkpoint list we need to record it on this transaction's forget list
+ * to pin this buffer (and hence its checkpointing transaction) down until
+ * this transaction commits. If the buffer isn't on a checkpoint list, we
+ * release it.
+ * Returns non-zero if JBD no longer has an interest in the buffer.
+ *
+ * Called under j_list_lock.
+ *
+ * Called under jbd_lock_bh_state(bh).
+ */
+static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
+{
+ int may_free = 1;
+ struct buffer_head *bh = jh2bh(jh);
+
+ __jbd2_journal_unfile_buffer(jh);
+
+ if (jh->b_cp_transaction) {
+ JBUFFER_TRACE(jh, "on running+cp transaction");
+ __jbd2_journal_file_buffer(jh, transaction, BJ_Forget);
+ clear_buffer_jbddirty(bh);
+ may_free = 0;
+ } else {
+ JBUFFER_TRACE(jh, "on running transaction");
+ jbd2_journal_remove_journal_head(bh);
+ __brelse(bh);
+ }
+ return may_free;
+}
+
+/*
+ * jbd2_journal_invalidatepage
+ *
+ * This code is tricky. It has a number of cases to deal with.
+ *
+ * There are two invariants which this code relies on:
+ *
+ * i_size must be updated on disk before we start calling invalidatepage on the
+ * data.
+ *
+ * This is done in ext3 by defining an ext3_setattr method which
+ * updates i_size before truncate gets going. By maintaining this
+ * invariant, we can be sure that it is safe to throw away any buffers
+ * attached to the current transaction: once the transaction commits,
+ * we know that the data will not be needed.
+ *
+ * Note however that we can *not* throw away data belonging to the
+ * previous, committing transaction!
+ *
+ * Any disk blocks which *are* part of the previous, committing
+ * transaction (and which therefore cannot be discarded immediately) are
+ * not going to be reused in the new running transaction
+ *
+ * The bitmap committed_data images guarantee this: any block which is
+ * allocated in one transaction and removed in the next will be marked
+ * as in-use in the committed_data bitmap, so cannot be reused until
+ * the next transaction to delete the block commits. This means that
+ * leaving committing buffers dirty is quite safe: the disk blocks
+ * cannot be reallocated to a different file and so buffer aliasing is
+ * not possible.
+ *
+ *
+ * The above applies mainly to ordered data mode. In writeback mode we
+ * don't make guarantees about the order in which data hits disk --- in
+ * particular we don't guarantee that new dirty data is flushed before
+ * transaction commit --- so it is always safe just to discard data
+ * immediately in that mode. --sct
+ */
+
+/*
+ * The journal_unmap_buffer helper function returns zero if the buffer
+ * concerned remains pinned as an anonymous buffer belonging to an older
+ * transaction.
+ *
+ * We're outside-transaction here. Either or both of j_running_transaction
+ * and j_committing_transaction may be NULL.
+ */
+static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh)
+{
+ transaction_t *transaction;
+ struct journal_head *jh;
+ int may_free = 1;
+ int ret;
+
+ BUFFER_TRACE(bh, "entry");
+
+ /*
+ * It is safe to proceed here without the j_list_lock because the
+ * buffers cannot be stolen by try_to_free_buffers as long as we are
+ * holding the page lock. --sct
+ */
+
+ if (!buffer_jbd(bh))
+ goto zap_buffer_unlocked;
+
+ spin_lock(&journal->j_state_lock);
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
+
+ jh = jbd2_journal_grab_journal_head(bh);
+ if (!jh)
+ goto zap_buffer_no_jh;
+
+ transaction = jh->b_transaction;
+ if (transaction == NULL) {
+ /* First case: not on any transaction. If it
+ * has no checkpoint link, then we can zap it:
+ * it's a writeback-mode buffer so we don't care
+ * if it hits disk safely. */
+ if (!jh->b_cp_transaction) {
+ JBUFFER_TRACE(jh, "not on any transaction: zap");
+ goto zap_buffer;
+ }
+
+ if (!buffer_dirty(bh)) {
+ /* bdflush has written it. We can drop it now */
+ goto zap_buffer;
+ }
+
+ /* OK, it must be in the journal but still not
+ * written fully to disk: it's metadata or
+ * journaled data... */
+
+ if (journal->j_running_transaction) {
+ /* ... and once the current transaction has
+ * committed, the buffer won't be needed any
+ * longer. */
+ JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget");
+ ret = __dispose_buffer(jh,
+ journal->j_running_transaction);
+ jbd2_journal_put_journal_head(jh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ spin_unlock(&journal->j_state_lock);
+ return ret;
+ } else {
+ /* There is no currently-running transaction. So the
+ * orphan record which we wrote for this file must have
+ * passed into commit. We must attach this buffer to
+ * the committing transaction, if it exists. */
+ if (journal->j_committing_transaction) {
+ JBUFFER_TRACE(jh, "give to committing trans");
+ ret = __dispose_buffer(jh,
+ journal->j_committing_transaction);
+ jbd2_journal_put_journal_head(jh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ spin_unlock(&journal->j_state_lock);
+ return ret;
+ } else {
+ /* The orphan record's transaction has
+ * committed. We can cleanse this buffer */
+ clear_buffer_jbddirty(bh);
+ goto zap_buffer;
+ }
+ }
+ } else if (transaction == journal->j_committing_transaction) {
+ if (jh->b_jlist == BJ_Locked) {
+ /*
+ * The buffer is on the committing transaction's locked
+ * list. We have the buffer locked, so I/O has
+ * completed. So we can nail the buffer now.
+ */
+ may_free = __dispose_buffer(jh, transaction);
+ goto zap_buffer;
+ }
+ /*
+ * If it is committing, we simply cannot touch it. We
+ * can remove it's next_transaction pointer from the
+ * running transaction if that is set, but nothing
+ * else. */
+ JBUFFER_TRACE(jh, "on committing transaction");
+ set_buffer_freed(bh);
+ if (jh->b_next_transaction) {
+ J_ASSERT(jh->b_next_transaction ==
+ journal->j_running_transaction);
+ jh->b_next_transaction = NULL;
+ }
+ jbd2_journal_put_journal_head(jh);
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ spin_unlock(&journal->j_state_lock);
+ return 0;
+ } else {
+ /* Good, the buffer belongs to the running transaction.
+ * We are writing our own transaction's data, not any
+ * previous one's, so it is safe to throw it away
+ * (remember that we expect the filesystem to have set
+ * i_size already for this truncate so recovery will not
+ * expose the disk blocks we are discarding here.) */
+ J_ASSERT_JH(jh, transaction == journal->j_running_transaction);
+ may_free = __dispose_buffer(jh, transaction);
+ }
+
+zap_buffer:
+ jbd2_journal_put_journal_head(jh);
+zap_buffer_no_jh:
+ spin_unlock(&journal->j_list_lock);
+ jbd_unlock_bh_state(bh);
+ spin_unlock(&journal->j_state_lock);
+zap_buffer_unlocked:
+ clear_buffer_dirty(bh);
+ J_ASSERT_BH(bh, !buffer_jbddirty(bh));
+ clear_buffer_mapped(bh);
+ clear_buffer_req(bh);
+ clear_buffer_new(bh);
+ bh->b_bdev = NULL;
+ return may_free;
+}
+
+/**
+ * void jbd2_journal_invalidatepage()
+ * @journal: journal to use for flush...
+ * @page: page to flush
+ * @offset: length of page to invalidate.
+ *
+ * Reap page buffers containing data after offset in page.
+ *
+ */
+void jbd2_journal_invalidatepage(journal_t *journal,
+ struct page *page,
+ unsigned long offset)
+{
+ struct buffer_head *head, *bh, *next;
+ unsigned int curr_off = 0;
+ int may_free = 1;
+
+ if (!PageLocked(page))
+ BUG();
+ if (!page_has_buffers(page))
+ return;
+
+ /* We will potentially be playing with lists other than just the
+ * data lists (especially for journaled data mode), so be
+ * cautious in our locking. */
+
+ head = bh = page_buffers(page);
+ do {
+ unsigned int next_off = curr_off + bh->b_size;
+ next = bh->b_this_page;
+
+ if (offset <= curr_off) {
+ /* This block is wholly outside the truncation point */
+ lock_buffer(bh);
+ may_free &= journal_unmap_buffer(journal, bh);
+ unlock_buffer(bh);
+ }
+ curr_off = next_off;
+ bh = next;
+
+ } while (bh != head);
+
+ if (!offset) {
+ if (may_free && try_to_free_buffers(page))
+ J_ASSERT(!page_has_buffers(page));
+ }
+}
+
+/*
+ * File a buffer on the given transaction list.
+ */
+void __jbd2_journal_file_buffer(struct journal_head *jh,
+ transaction_t *transaction, int jlist)
+{
+ struct journal_head **list = NULL;
+ int was_dirty = 0;
+ struct buffer_head *bh = jh2bh(jh);
+
+ J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
+ assert_spin_locked(&transaction->t_journal->j_list_lock);
+
+ J_ASSERT_JH(jh, jh->b_jlist < BJ_Types);
+ J_ASSERT_JH(jh, jh->b_transaction == transaction ||
+ jh->b_transaction == 0);
+
+ if (jh->b_transaction && jh->b_jlist == jlist)
+ return;
+
+ /* The following list of buffer states needs to be consistent
+ * with __jbd_unexpected_dirty_buffer()'s handling of dirty
+ * state. */
+
+ if (jlist == BJ_Metadata || jlist == BJ_Reserved ||
+ jlist == BJ_Shadow || jlist == BJ_Forget) {
+ if (test_clear_buffer_dirty(bh) ||
+ test_clear_buffer_jbddirty(bh))
+ was_dirty = 1;
+ }
+
+ if (jh->b_transaction)
+ __jbd2_journal_temp_unlink_buffer(jh);
+ jh->b_transaction = transaction;
+
+ switch (jlist) {
+ case BJ_None:
+ J_ASSERT_JH(jh, !jh->b_committed_data);
+ J_ASSERT_JH(jh, !jh->b_frozen_data);
+ return;
+ case BJ_SyncData:
+ list = &transaction->t_sync_datalist;
+ break;
+ case BJ_Metadata:
+ transaction->t_nr_buffers++;
+ list = &transaction->t_buffers;
+ break;
+ case BJ_Forget:
+ list = &transaction->t_forget;
+ break;
+ case BJ_IO:
+ list = &transaction->t_iobuf_list;
+ break;
+ case BJ_Shadow:
+ list = &transaction->t_shadow_list;
+ break;
+ case BJ_LogCtl:
+ list = &transaction->t_log_list;
+ break;
+ case BJ_Reserved:
+ list = &transaction->t_reserved_list;
+ break;
+ case BJ_Locked:
+ list = &transaction->t_locked_list;
+ break;
+ }
+
+ __blist_add_buffer(list, jh);
+ jh->b_jlist = jlist;
+
+ if (was_dirty)
+ set_buffer_jbddirty(bh);
+}
+
+void jbd2_journal_file_buffer(struct journal_head *jh,
+ transaction_t *transaction, int jlist)
+{
+ jbd_lock_bh_state(jh2bh(jh));
+ spin_lock(&transaction->t_journal->j_list_lock);
+ __jbd2_journal_file_buffer(jh, transaction, jlist);
+ spin_unlock(&transaction->t_journal->j_list_lock);
+ jbd_unlock_bh_state(jh2bh(jh));
+}
+
+/*
+ * Remove a buffer from its current buffer list in preparation for
+ * dropping it from its current transaction entirely. If the buffer has
+ * already started to be used by a subsequent transaction, refile the
+ * buffer on that transaction's metadata list.
+ *
+ * Called under journal->j_list_lock
+ *
+ * Called under jbd_lock_bh_state(jh2bh(jh))
+ */
+void __jbd2_journal_refile_buffer(struct journal_head *jh)
+{
+ int was_dirty;
+ struct buffer_head *bh = jh2bh(jh);
+
+ J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh));
+ if (jh->b_transaction)
+ assert_spin_locked(&jh->b_transaction->t_journal->j_list_lock);
+
+ /* If the buffer is now unused, just drop it. */
+ if (jh->b_next_transaction == NULL) {
+ __jbd2_journal_unfile_buffer(jh);
+ return;
+ }
+
+ /*
+ * It has been modified by a later transaction: add it to the new
+ * transaction's metadata list.
+ */
+
+ was_dirty = test_clear_buffer_jbddirty(bh);
+ __jbd2_journal_temp_unlink_buffer(jh);
+ jh->b_transaction = jh->b_next_transaction;
+ jh->b_next_transaction = NULL;
+ __jbd2_journal_file_buffer(jh, jh->b_transaction,
+ was_dirty ? BJ_Metadata : BJ_Reserved);
+ J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING);
+
+ if (was_dirty)
+ set_buffer_jbddirty(bh);
+}
+
+/*
+ * For the unlocked version of this call, also make sure that any
+ * hanging journal_head is cleaned up if necessary.
+ *
+ * __jbd2_journal_refile_buffer is usually called as part of a single locked
+ * operation on a buffer_head, in which the caller is probably going to
+ * be hooking the journal_head onto other lists. In that case it is up
+ * to the caller to remove the journal_head if necessary. For the
+ * unlocked jbd2_journal_refile_buffer call, the caller isn't going to be
+ * doing anything else to the buffer so we need to do the cleanup
+ * ourselves to avoid a jh leak.
+ *
+ * *** The journal_head may be freed by this call! ***
+ */
+void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh)
+{
+ struct buffer_head *bh = jh2bh(jh);
+
+ jbd_lock_bh_state(bh);
+ spin_lock(&journal->j_list_lock);
+
+ __jbd2_journal_refile_buffer(jh);
+ jbd_unlock_bh_state(bh);
+ jbd2_journal_remove_journal_head(bh);
+
+ spin_unlock(&journal->j_list_lock);
+ __brelse(bh);
+}
diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
index 93068697a9bf..3f7899ea4cba 100644
--- a/fs/jffs/inode-v23.c
+++ b/fs/jffs/inode-v23.c
@@ -364,12 +364,11 @@ jffs_new_inode(const struct inode * dir, struct jffs_raw_inode *raw_inode,
inode->i_ctime.tv_nsec = 0;
inode->i_mtime.tv_nsec = 0;
inode->i_atime.tv_nsec = 0;
- inode->i_blksize = PAGE_SIZE;
inode->i_blocks = (inode->i_size + 511) >> 9;
f = jffs_find_file(c, raw_inode->ino);
- inode->u.generic_ip = (void *)f;
+ inode->i_private = (void *)f;
insert_inode_hash(inode);
return inode;
@@ -442,7 +441,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
});
result = -ENOTDIR;
- if (!(old_dir_f = (struct jffs_file *)old_dir->u.generic_ip)) {
+ if (!(old_dir_f = old_dir->i_private)) {
D(printk("jffs_rename(): Old dir invalid.\n"));
goto jffs_rename_end;
}
@@ -456,7 +455,7 @@ jffs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* Find the new directory. */
result = -ENOTDIR;
- if (!(new_dir_f = (struct jffs_file *)new_dir->u.generic_ip)) {
+ if (!(new_dir_f = new_dir->i_private)) {
D(printk("jffs_rename(): New dir invalid.\n"));
goto jffs_rename_end;
}
@@ -593,7 +592,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
else {
ddino = ((struct jffs_file *)
- inode->u.generic_ip)->pino;
+ inode->i_private)->pino;
}
D3(printk("jffs_readdir(): \"..\" %u\n", ddino));
if (filldir(dirent, "..", 2, filp->f_pos, ddino, DT_DIR) < 0) {
@@ -604,7 +603,7 @@ jffs_readdir(struct file *filp, void *dirent, filldir_t filldir)
}
filp->f_pos++;
}
- f = ((struct jffs_file *)inode->u.generic_ip)->children;
+ f = ((struct jffs_file *)inode->i_private)->children;
j = 2;
while(f && (f->deleted || j++ < filp->f_pos )) {
@@ -652,7 +651,7 @@ jffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
lock_kernel();
D3({
- char *s = (char *)kmalloc(len + 1, GFP_KERNEL);
+ char *s = kmalloc(len + 1, GFP_KERNEL);
memcpy(s, name, len);
s[len] = '\0';
printk("jffs_lookup(): dir: 0x%p, name: \"%s\"\n", dir, s);
@@ -668,7 +667,7 @@ jffs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
}
r = -EACCES;
- if (!(d = (struct jffs_file *)dir->u.generic_ip)) {
+ if (!(d = (struct jffs_file *)dir->i_private)) {
D(printk("jffs_lookup(): No such inode! (%lu)\n",
dir->i_ino));
goto jffs_lookup_end;
@@ -739,7 +738,7 @@ jffs_do_readpage_nolock(struct file *file, struct page *page)
unsigned long read_len;
int result;
struct inode *inode = (struct inode*)page->mapping->host;
- struct jffs_file *f = (struct jffs_file *)inode->u.generic_ip;
+ struct jffs_file *f = (struct jffs_file *)inode->i_private;
struct jffs_control *c = (struct jffs_control *)inode->i_sb->s_fs_info;
int r;
loff_t offset;
@@ -828,7 +827,7 @@ jffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
});
lock_kernel();
- dir_f = (struct jffs_file *)dir->u.generic_ip;
+ dir_f = dir->i_private;
ASSERT(if (!dir_f) {
printk(KERN_ERR "jffs_mkdir(): No reference to a "
@@ -972,7 +971,7 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
kfree(_name);
});
- dir_f = (struct jffs_file *) dir->u.generic_ip;
+ dir_f = dir->i_private;
c = dir_f->c;
result = -ENOENT;
@@ -1053,9 +1052,8 @@ jffs_remove(struct inode *dir, struct dentry *dentry, int type)
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
- inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
- mark_inode_dirty(inode);
+ inode_dec_link_count(inode);
d_delete(dentry); /* This also frees the inode */
@@ -1082,7 +1080,7 @@ jffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
if (!old_valid_dev(rdev))
return -EINVAL;
lock_kernel();
- dir_f = (struct jffs_file *)dir->u.generic_ip;
+ dir_f = dir->i_private;
c = dir_f->c;
D3(printk (KERN_NOTICE "mknod(): down biglock\n"));
@@ -1173,8 +1171,8 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
lock_kernel();
D1({
int len = dentry->d_name.len;
- char *_name = (char *)kmalloc(len + 1, GFP_KERNEL);
- char *_symname = (char *)kmalloc(symname_len + 1, GFP_KERNEL);
+ char *_name = kmalloc(len + 1, GFP_KERNEL);
+ char *_symname = kmalloc(symname_len + 1, GFP_KERNEL);
memcpy(_name, dentry->d_name.name, len);
_name[len] = '\0';
memcpy(_symname, symname, symname_len);
@@ -1186,7 +1184,7 @@ jffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
kfree(_symname);
});
- dir_f = (struct jffs_file *)dir->u.generic_ip;
+ dir_f = dir->i_private;
ASSERT(if (!dir_f) {
printk(KERN_ERR "jffs_symlink(): No reference to a "
"jffs_file struct in inode.\n");
@@ -1282,14 +1280,14 @@ jffs_create(struct inode *dir, struct dentry *dentry, int mode,
lock_kernel();
D1({
int len = dentry->d_name.len;
- char *s = (char *)kmalloc(len + 1, GFP_KERNEL);
+ char *s = kmalloc(len + 1, GFP_KERNEL);
memcpy(s, dentry->d_name.name, len);
s[len] = '\0';
printk("jffs_create(): dir: 0x%p, name: \"%s\"\n", dir, s);
kfree(s);
});
- dir_f = (struct jffs_file *)dir->u.generic_ip;
+ dir_f = dir->i_private;
ASSERT(if (!dir_f) {
printk(KERN_ERR "jffs_create(): No reference to a "
"jffs_file struct in inode.\n");
@@ -1403,9 +1401,9 @@ jffs_file_write(struct file *filp, const char *buf, size_t count,
goto out_isem;
}
- if (!(f = (struct jffs_file *)inode->u.generic_ip)) {
- D(printk("jffs_file_write(): inode->u.generic_ip = 0x%p\n",
- inode->u.generic_ip));
+ if (!(f = inode->i_private)) {
+ D(printk("jffs_file_write(): inode->i_private = 0x%p\n",
+ inode->i_private));
goto out_isem;
}
@@ -1633,8 +1631,10 @@ static const struct file_operations jffs_file_operations =
{
.open = generic_file_open,
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.ioctl = jffs_ioctl,
.mmap = generic_file_readonly_mmap,
.fsync = jffs_fsync,
@@ -1693,7 +1693,7 @@ jffs_read_inode(struct inode *inode)
mutex_unlock(&c->fmc->biglock);
return;
}
- inode->u.generic_ip = (void *)f;
+ inode->i_private = f;
inode->i_mode = f->mode;
inode->i_nlink = f->nlink;
inode->i_uid = f->uid;
@@ -1706,7 +1706,6 @@ jffs_read_inode(struct inode *inode)
inode->i_mtime.tv_nsec =
inode->i_ctime.tv_nsec = 0;
- inode->i_blksize = PAGE_SIZE;
inode->i_blocks = (inode->i_size + 511) >> 9;
if (S_ISREG(inode->i_mode)) {
inode->i_op = &jffs_file_inode_operations;
@@ -1748,7 +1747,7 @@ jffs_delete_inode(struct inode *inode)
lock_kernel();
inode->i_size = 0;
inode->i_blocks = 0;
- inode->u.generic_ip = NULL;
+ inode->i_private = NULL;
clear_inode(inode);
if (inode->i_nlink == 0) {
c = (struct jffs_control *) inode->i_sb->s_fs_info;
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index 9000f1effedf..4a543e114970 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -488,13 +488,11 @@ jffs_create_file(struct jffs_control *c,
{
struct jffs_file *f;
- if (!(f = (struct jffs_file *)kmalloc(sizeof(struct jffs_file),
- GFP_KERNEL))) {
+ if (!(f = kzalloc(sizeof(*f), GFP_KERNEL))) {
D(printk("jffs_create_file(): Failed!\n"));
return NULL;
}
no_jffs_file++;
- memset(f, 0, sizeof(struct jffs_file));
f->ino = raw_inode->ino;
f->pino = raw_inode->pino;
f->nlink = raw_inode->nlink;
@@ -516,7 +514,7 @@ jffs_create_control(struct super_block *sb)
D2(printk("jffs_create_control()\n"));
- if (!(c = (struct jffs_control *)kmalloc(s, GFP_KERNEL))) {
+ if (!(c = kmalloc(s, GFP_KERNEL))) {
goto fail_control;
}
DJM(no_jffs_control++);
@@ -524,7 +522,7 @@ jffs_create_control(struct super_block *sb)
c->gc_task = NULL;
c->hash_len = JFFS_HASH_SIZE;
s = sizeof(struct list_head) * c->hash_len;
- if (!(c->hash = (struct list_head *)kmalloc(s, GFP_KERNEL))) {
+ if (!(c->hash = kmalloc(s, GFP_KERNEL))) {
goto fail_hash;
}
DJM(no_hash++);
@@ -593,8 +591,7 @@ jffs_add_virtual_root(struct jffs_control *c)
D2(printk("jffs_add_virtual_root(): "
"Creating a virtual root directory.\n"));
- if (!(root = (struct jffs_file *)kmalloc(sizeof(struct jffs_file),
- GFP_KERNEL))) {
+ if (!(root = kmalloc(sizeof(struct jffs_file), GFP_KERNEL))) {
return -ENOMEM;
}
no_jffs_file++;
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c
index 7d8ca1aeace2..29b68d939bd9 100644
--- a/fs/jffs/jffs_fm.c
+++ b/fs/jffs/jffs_fm.c
@@ -94,8 +94,7 @@ jffs_build_begin(struct jffs_control *c, int unit)
struct mtd_info *mtd;
D3(printk("jffs_build_begin()\n"));
- fmc = (struct jffs_fmcontrol *)kmalloc(sizeof(struct jffs_fmcontrol),
- GFP_KERNEL);
+ fmc = kmalloc(sizeof(*fmc), GFP_KERNEL);
if (!fmc) {
D(printk("jffs_build_begin(): Allocation of "
"struct jffs_fmcontrol failed!\n"));
@@ -486,8 +485,7 @@ jffs_add_node(struct jffs_node *node)
D3(printk("jffs_add_node(): ino = %u\n", node->ino));
- ref = (struct jffs_node_ref *)kmalloc(sizeof(struct jffs_node_ref),
- GFP_KERNEL);
+ ref = kmalloc(sizeof(*ref), GFP_KERNEL);
if (!ref)
return -ENOMEM;
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index edd8371fc6a5..9def6adf4a5d 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -588,7 +588,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode)
}
dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime));
- dir_i->i_nlink++;
+ inc_nlink(dir_i);
jffs2_free_raw_dirent(rd);
@@ -615,7 +615,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
}
ret = jffs2_unlink(dir_i, dentry);
if (!ret)
- dir_i->i_nlink--;
+ drop_nlink(dir_i);
return ret;
}
@@ -823,7 +823,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
if (victim_f) {
/* There was a victim. Kill it off nicely */
- new_dentry->d_inode->i_nlink--;
+ drop_nlink(new_dentry->d_inode);
/* Don't oops if the victim was a dirent pointing to an
inode which didn't exist. */
if (victim_f->inocache) {
@@ -836,7 +836,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
/* If it was a directory we moved, and there was no victim,
increase i_nlink on its new parent */
if (S_ISDIR(old_dentry->d_inode->i_mode) && !victim_f)
- new_dir_i->i_nlink++;
+ inc_nlink(new_dir_i);
/* Unlink the original */
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
@@ -848,7 +848,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
/* Oh shit. We really ought to make a single node which can do both atomically */
struct jffs2_inode_info *f = JFFS2_INODE_INFO(old_dentry->d_inode);
down(&f->sem);
- old_dentry->d_inode->i_nlink++;
+ inc_nlink(old_dentry->d_inode);
if (f->inocache)
f->inocache->nlink++;
up(&f->sem);
@@ -862,7 +862,7 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
}
if (S_ISDIR(old_dentry->d_inode->i_mode))
- old_dir_i->i_nlink--;
+ drop_nlink(old_dir_i);
new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 3ed6e3e120b6..242875f77cb3 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -42,8 +42,10 @@ const struct file_operations jffs2_file_operations =
{
.llseek = generic_file_llseek,
.open = generic_file_open,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.ioctl = jffs2_ioctl,
.mmap = generic_file_readonly_mmap,
.fsync = jffs2_fsync,
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 4780f82825d6..7bc1a4201c0c 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -263,7 +263,6 @@ void jffs2_read_inode (struct inode *inode)
inode->i_nlink = f->inocache->nlink;
- inode->i_blksize = PAGE_SIZE;
inode->i_blocks = (inode->i_size + 511) >> 9;
switch (inode->i_mode & S_IFMT) {
@@ -278,13 +277,13 @@ void jffs2_read_inode (struct inode *inode)
for (fd=f->dents; fd; fd = fd->next) {
if (fd->type == DT_DIR && fd->ino)
- inode->i_nlink++;
+ inc_nlink(inode);
}
/* and '..' */
- inode->i_nlink++;
+ inc_nlink(inode);
/* Root dir gets i_nlink 3 for some reason */
if (inode->i_ino == 1)
- inode->i_nlink++;
+ inc_nlink(inode);
inode->i_op = &jffs2_dir_inode_operations;
inode->i_fop = &jffs2_dir_operations;
@@ -449,7 +448,6 @@ struct inode *jffs2_new_inode (struct inode *dir_i, int mode, struct jffs2_raw_i
inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime));
- inode->i_blksize = PAGE_SIZE;
inode->i_blocks = 0;
inode->i_size = 0;
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 68e3953419b4..bc4b8106a490 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -119,10 +119,9 @@ static int jffs2_get_sb_mtd(struct file_system_type *fs_type,
struct jffs2_sb_info *c;
int ret;
- c = kmalloc(sizeof(*c), GFP_KERNEL);
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return -ENOMEM;
- memset(c, 0, sizeof(*c));
c->mtd = mtd;
sb = sget(fs_type, jffs2_sb_compare, jffs2_sb_set, c);
@@ -335,10 +334,10 @@ static int __init init_jffs2_fs(void)
which means just 'no padding', without the alignment
thing. But GCC doesn't have that -- we have to just
hope the structs are the right sizes, instead. */
- BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
- BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
- BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
- BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
+ BUILD_BUG_ON(sizeof(struct jffs2_unknown_node) != 12);
+ BUILD_BUG_ON(sizeof(struct jffs2_raw_dirent) != 40);
+ BUILD_BUG_ON(sizeof(struct jffs2_raw_inode) != 68);
+ BUILD_BUG_ON(sizeof(struct jffs2_raw_summary) != 32);
printk(KERN_INFO "JFFS2 version 2.2."
#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
diff --git a/fs/jfs/acl.c b/fs/jfs/acl.c
index e2281300979c..4d84bdc88299 100644
--- a/fs/jfs/acl.c
+++ b/fs/jfs/acl.c
@@ -5,16 +5,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -183,7 +183,7 @@ cleanup:
posix_acl_release(acl);
} else
inode->i_mode &= ~current->fs->umask;
-
+
JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
inode->i_mode;
diff --git a/fs/jfs/endian24.h b/fs/jfs/endian24.h
index ab7cd0567c95..79494c4f2b10 100644
--- a/fs/jfs/endian24.h
+++ b/fs/jfs/endian24.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) International Business Machines Corp., 2001
+ * Copyright (C) International Business Machines Corp., 2001
*
* 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/fs/jfs/file.c b/fs/jfs/file.c
index 1c9745be5ada..34181b8f5a0a 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -103,14 +103,12 @@ struct inode_operations jfs_file_inode_operations = {
const struct file_operations jfs_file_operations = {
.open = jfs_open,
.llseek = generic_file_llseek,
- .write = generic_file_write,
- .read = generic_file_read,
+ .write = do_sync_write,
+ .read = do_sync_read,
.aio_read = generic_file_aio_read,
.aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
- .readv = generic_file_readv,
- .writev = generic_file_writev,
- .sendfile = generic_file_sendfile,
+ .sendfile = generic_file_sendfile,
.fsync = jfs_fsync,
.release = jfs_release,
.ioctl = jfs_ioctl,
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c
index a223cf4faa9b..f5719117edfe 100644
--- a/fs/jfs/inode.c
+++ b/fs/jfs/inode.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -33,7 +33,7 @@
void jfs_read_inode(struct inode *inode)
{
- if (diRead(inode)) {
+ if (diRead(inode)) {
make_bad_inode(inode);
return;
}
@@ -227,7 +227,7 @@ int jfs_get_block(struct inode *ip, sector_t lblock,
#ifdef _JFS_4K
if ((rc = extHint(ip, lblock64 << ip->i_sb->s_blocksize_bits, &xad)))
goto unlock;
- rc = extAlloc(ip, xlen, lblock64, &xad, FALSE);
+ rc = extAlloc(ip, xlen, lblock64, &xad, false);
if (rc)
goto unlock;
diff --git a/fs/jfs/ioctl.c b/fs/jfs/ioctl.c
index 67b3774820eb..37db52488262 100644
--- a/fs/jfs/ioctl.c
+++ b/fs/jfs/ioctl.c
@@ -6,7 +6,6 @@
*/
#include <linux/fs.h>
-#include <linux/ext2_fs.h>
#include <linux/ctype.h>
#include <linux/capability.h>
#include <linux/time.h>
@@ -22,13 +21,13 @@ static struct {
long jfs_flag;
long ext2_flag;
} jfs_map[] = {
- {JFS_NOATIME_FL, EXT2_NOATIME_FL},
- {JFS_DIRSYNC_FL, EXT2_DIRSYNC_FL},
- {JFS_SYNC_FL, EXT2_SYNC_FL},
- {JFS_SECRM_FL, EXT2_SECRM_FL},
- {JFS_UNRM_FL, EXT2_UNRM_FL},
- {JFS_APPEND_FL, EXT2_APPEND_FL},
- {JFS_IMMUTABLE_FL, EXT2_IMMUTABLE_FL},
+ {JFS_NOATIME_FL, FS_NOATIME_FL},
+ {JFS_DIRSYNC_FL, FS_DIRSYNC_FL},
+ {JFS_SYNC_FL, FS_SYNC_FL},
+ {JFS_SECRM_FL, FS_SECRM_FL},
+ {JFS_UNRM_FL, FS_UNRM_FL},
+ {JFS_APPEND_FL, FS_APPEND_FL},
+ {JFS_IMMUTABLE_FL, FS_IMMUTABLE_FL},
{0, 0},
};
diff --git a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
index a76293767c73..455fa4292045 100644
--- a/fs/jfs/jfs_acl.h
+++ b/fs/jfs/jfs_acl.h
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2002
+ * Copyright (C) International Business Machines Corp., 2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_ACL
diff --git a/fs/jfs/jfs_btree.h b/fs/jfs/jfs_btree.h
index 7f3e9ac454ff..79c61805bd33 100644
--- a/fs/jfs/jfs_btree.h
+++ b/fs/jfs/jfs_btree.h
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_BTREE
diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c
index 81f0e514c490..9c5d59632aac 100644
--- a/fs/jfs/jfs_debug.c
+++ b/fs/jfs/jfs_debug.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/fs/jfs/jfs_dinode.h b/fs/jfs/jfs_dinode.h
index 9f2572aea561..40b20111383c 100644
--- a/fs/jfs/jfs_dinode.h
+++ b/fs/jfs/jfs_dinode.h
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2001
+ * Copyright (C) International Business Machines Corp., 2000-2001
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_DINODE
diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c
index c161c98954e0..23546c8fd48b 100644
--- a/fs/jfs/jfs_dmap.c
+++ b/fs/jfs/jfs_dmap.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -30,28 +30,28 @@
*
* the working state of the block allocation map is accessed in
* two directions:
- *
+ *
* 1) allocation and free requests that start at the dmap
* level and move up through the dmap control pages (i.e.
* the vast majority of requests).
- *
- * 2) allocation requests that start at dmap control page
+ *
+ * 2) allocation requests that start at dmap control page
* level and work down towards the dmaps.
- *
- * the serialization scheme used here is as follows.
*
- * requests which start at the bottom are serialized against each
- * other through buffers and each requests holds onto its buffers
- * as it works it way up from a single dmap to the required level
+ * the serialization scheme used here is as follows.
+ *
+ * requests which start at the bottom are serialized against each
+ * other through buffers and each requests holds onto its buffers
+ * as it works it way up from a single dmap to the required level
* of dmap control page.
* requests that start at the top are serialized against each other
* and request that start from the bottom by the multiple read/single
* write inode lock of the bmap inode. requests starting at the top
* take this lock in write mode while request starting at the bottom
* take the lock in read mode. a single top-down request may proceed
- * exclusively while multiple bottoms-up requests may proceed
- * simultaneously (under the protection of busy buffers).
- *
+ * exclusively while multiple bottoms-up requests may proceed
+ * simultaneously (under the protection of busy buffers).
+ *
* in addition to information found in dmaps and dmap control pages,
* the working state of the block allocation map also includes read/
* write information maintained in the bmap descriptor (i.e. total
@@ -59,7 +59,7 @@
* a single exclusive lock (BMAP_LOCK) is used to guard this information
* in the face of multiple-bottoms up requests.
* (lock ordering: IREAD_LOCK, BMAP_LOCK);
- *
+ *
* accesses to the persistent state of the block allocation map (limited
* to the persistent bitmaps in dmaps) is guarded by (busy) buffers.
*/
@@ -120,7 +120,7 @@ static int dbGetL2AGSize(s64 nblocks);
/*
* buddy table
*
- * table used for determining buddy sizes within characters of
+ * table used for determining buddy sizes within characters of
* dmap bitmap words. the characters themselves serve as indexes
* into the table, with the table elements yielding the maximum
* binary buddy of free bits within the character.
@@ -146,7 +146,7 @@ static const s8 budtab[256] = {
/*
- * NAME: dbMount()
+ * NAME: dbMount()
*
* FUNCTION: initializate the block allocation map.
*
@@ -223,12 +223,12 @@ int dbMount(struct inode *ipbmap)
/*
- * NAME: dbUnmount()
+ * NAME: dbUnmount()
*
* FUNCTION: terminate the block allocation map in preparation for
* file system unmount.
*
- * the in-core bmap descriptor is written to disk and
+ * the in-core bmap descriptor is written to disk and
* the memory for this descriptor is freed.
*
* PARAMETERS:
@@ -311,7 +311,7 @@ int dbSync(struct inode *ipbmap)
/*
- * NAME: dbFree()
+ * NAME: dbFree()
*
* FUNCTION: free the specified block range from the working block
* allocation map.
@@ -397,14 +397,14 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
*
* FUNCTION: update the allocation state (free or allocate) of the
* specified block range in the persistent block allocation map.
- *
+ *
* the blocks will be updated in the persistent map one
* dmap at a time.
*
* PARAMETERS:
* ipbmap - pointer to in-core inode for the block map.
- * free - TRUE if block range is to be freed from the persistent
- * map; FALSE if it is to be allocated.
+ * free - 'true' if block range is to be freed from the persistent
+ * map; 'false' if it is to be allocated.
* blkno - starting block number of the range.
* nblocks - number of contiguous blocks in the range.
* tblk - transaction block;
@@ -475,7 +475,7 @@ dbUpdatePMap(struct inode *ipbmap,
/* update the bits of the dmap words. the first and last
* words may only have a subset of their bits updated. if
* this is the case, we'll work against that word (i.e.
- * partial first and/or last) only in a single pass. a
+ * partial first and/or last) only in a single pass. a
* single pass will also be used to update all words that
* are to have all their bits updated.
*/
@@ -662,11 +662,11 @@ unlock:
* the block allocation policy uses hints and a multi-step
* approach.
*
- * for allocation requests smaller than the number of blocks
+ * for allocation requests smaller than the number of blocks
* per dmap, we first try to allocate the new blocks
* immediately following the hint. if these blocks are not
* available, we try to allocate blocks near the hint. if
- * no blocks near the hint are available, we next try to
+ * no blocks near the hint are available, we next try to
* allocate within the same dmap as contains the hint.
*
* if no blocks are available in the dmap or the allocation
@@ -713,7 +713,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
#endif /* _STILL_TO_PORT */
/* get the log2 number of blocks to be allocated.
- * if the number of blocks is not a log2 multiple,
+ * if the number of blocks is not a log2 multiple,
* it will be rounded up to the next log2 multiple.
*/
l2nb = BLKSTOL2(nblocks);
@@ -906,7 +906,7 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
* validate extent request:
*
* note: defragfs policy:
- * max 64 blocks will be moved.
+ * max 64 blocks will be moved.
* allocation request size must be satisfied from a single dmap.
*/
if (nblocks <= 0 || nblocks > BPERDMAP || blkno >= bmp->db_mapsize) {
@@ -1333,7 +1333,7 @@ dbAllocNear(struct bmap * bmp,
* or two sub-trees, depending on the allocation group size.
* we search the top nodes of these subtrees left to right for
* sufficient free space. if sufficient free space is found,
- * the subtree is searched to find the leftmost leaf that
+ * the subtree is searched to find the leftmost leaf that
* has free space. once we have made it to the leaf, we
* move the search to the next lower level dmap control page
* corresponding to this leaf. we continue down the dmap control
@@ -1398,7 +1398,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
* that fully describes the allocation group since the allocation
* group is already fully described by a dmap. in this case, we
* just call dbAllocCtl() to search the dmap tree and allocate the
- * required space if available.
+ * required space if available.
*
* if the allocation group is completely free, dbAllocCtl() is
* also called to allocate the required space. this is done for
@@ -1450,7 +1450,7 @@ dbAllocAG(struct bmap * bmp, int agno, s64 nblocks, int l2nb, s64 * results)
(1 << (L2LPERCTL - (bmp->db_agheigth << 1))) / bmp->db_agwidth;
ti = bmp->db_agstart + bmp->db_agwidth * (agno & (agperlev - 1));
- /* dmap control page trees fan-out by 4 and a single allocation
+ /* dmap control page trees fan-out by 4 and a single allocation
* group may be described by 1 or 2 subtrees within the ag level
* dmap control page, depending upon the ag size. examine the ag's
* subtrees for sufficient free space, starting with the leftmost
@@ -1633,7 +1633,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
/* starting at the specified dmap control page level and block
* number, search down the dmap control levels for the starting
- * block number of a dmap page that contains or starts off
+ * block number of a dmap page that contains or starts off
* sufficient free blocks.
*/
for (lev = level, b = *blkno; lev >= 0; lev--) {
@@ -1677,7 +1677,7 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
}
/* adjust the block number to reflect the location within
- * the dmap control page (i.e. the leaf) at which free
+ * the dmap control page (i.e. the leaf) at which free
* space was found.
*/
b += (((s64) leafidx) << budmin);
@@ -1700,12 +1700,12 @@ static int dbFindCtl(struct bmap * bmp, int l2nb, int level, s64 * blkno)
* NAME: dbAllocCtl()
*
* FUNCTION: attempt to allocate a specified number of contiguous
- * blocks starting within a specific dmap.
- *
+ * blocks starting within a specific dmap.
+ *
* this routine is called by higher level routines that search
* the dmap control pages above the actual dmaps for contiguous
* free space. the result of successful searches by these
- * routines are the starting block numbers within dmaps, with
+ * routines are the starting block numbers within dmaps, with
* the dmaps themselves containing the desired contiguous free
* space or starting a contiguous free space of desired size
* that is made up of the blocks of one or more dmaps. these
@@ -1872,14 +1872,14 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
*
* FUNCTION: attempt to allocate a specified number of contiguous blocks
* from a specified dmap.
- *
+ *
* this routine checks if the contiguous blocks are available.
* if so, nblocks of blocks are allocated; otherwise, ENOSPC is
* returned.
*
* PARAMETERS:
* mp - pointer to bmap descriptor
- * dp - pointer to dmap to attempt to allocate blocks from.
+ * dp - pointer to dmap to attempt to allocate blocks from.
* l2nb - log2 number of contiguous block desired.
* nblocks - actual number of contiguous block desired.
* results - on successful return, set to the starting block number
@@ -1890,7 +1890,7 @@ dbAllocCtl(struct bmap * bmp, s64 nblocks, int l2nb, s64 blkno, s64 * results)
* -ENOSPC - insufficient disk resources
* -EIO - i/o error
*
- * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or
+ * serialization: IREAD_LOCK(ipbmap), e.g., from dbAlloc(), or
* IWRITE_LOCK(ipbmap), e.g., dbAllocCtl(), held on entry/exit;
*/
static int
@@ -2032,7 +2032,7 @@ static int dbFreeDmap(struct bmap * bmp, struct dmap * dp, s64 blkno,
/* root changed. bubble the change up to the dmap control pages.
* if the adjustment of the upper level control pages fails,
- * backout the deallocation.
+ * backout the deallocation.
*/
if ((rc = dbAdjCtl(bmp, blkno, dp->tree.stree[ROOT], 0, 0))) {
word = (blkno & (BPERDMAP - 1)) >> L2DBWORD;
@@ -2245,7 +2245,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
* words (i.e. partial first and/or last) on an individual basis
* (a single pass), freeing the bits of interest by hand and updating
* the leaf corresponding to the dmap word. a single pass will be used
- * for all dmap words fully contained within the specified range.
+ * for all dmap words fully contained within the specified range.
* within this pass, the bits of all fully contained dmap words will
* be marked as free in a single shot and the leaves will be updated. a
* single leaf may describe the free space of multiple dmap words,
@@ -2267,7 +2267,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
*/
if (nb < DBWORD) {
/* free (zero) the appropriate bits within this
- * dmap word.
+ * dmap word.
*/
dp->wmap[word] &=
cpu_to_le32(~(ONES << (DBWORD - nb)
@@ -2327,7 +2327,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
BMAP_LOCK(bmp);
- /* update the free count for the allocation group and
+ /* update the free count for the allocation group and
* map.
*/
agno = blkno >> bmp->db_agl2size;
@@ -2378,7 +2378,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
* or deallocation resulted in the root change. this range
* is respresented by a single leaf of the current dmapctl
* and the leaf will be updated with this value, possibly
- * causing a binary buddy system within the leaves to be
+ * causing a binary buddy system within the leaves to be
* split or joined. the update may also cause the dmapctl's
* dmtree to be updated.
*
@@ -2394,7 +2394,7 @@ static int dbFreeBits(struct bmap * bmp, struct dmap * dp, s64 blkno,
* requires the dmap control page to be adjusted.
* newval - the new value of the lower level dmap or dmap control
* page root.
- * alloc - TRUE if adjustment is due to an allocation.
+ * alloc - 'true' if adjustment is due to an allocation.
* level - current level of dmap control page (i.e. L0, L1, L2) to
* be adjusted.
*
@@ -2590,7 +2590,7 @@ static void dbSplit(dmtree_t * tp, int leafno, int splitsz, int newval)
}
}
- /* adjust the dmap tree to reflect the specified leaf's new
+ /* adjust the dmap tree to reflect the specified leaf's new
* value.
*/
dbAdjTree(tp, leafno, newval);
@@ -2638,7 +2638,7 @@ static int dbBackSplit(dmtree_t * tp, int leafno)
/* the back split is accomplished by iteratively finding the leaf
* that starts the buddy system that contains the specified leaf and
* splitting that system in two. this iteration continues until
- * the specified leaf becomes the start of a buddy system.
+ * the specified leaf becomes the start of a buddy system.
*
* determine maximum possible l2 size for the specified leaf.
*/
@@ -2853,7 +2853,7 @@ static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
* NAME: dbFindLeaf()
*
* FUNCTION: search a dmtree_t for sufficient free blocks, returning
- * the index of a leaf describing the free blocks if
+ * the index of a leaf describing the free blocks if
* sufficient free blocks are found.
*
* the search starts at the top of the dmtree_t tree and
@@ -2869,7 +2869,7 @@ static void dbAdjTree(dmtree_t * tp, int leafno, int newval)
*
* RETURN VALUES:
* 0 - success
- * -ENOSPC - insufficient free blocks.
+ * -ENOSPC - insufficient free blocks.
*/
static int dbFindLeaf(dmtree_t * tp, int l2nb, int *leafidx)
{
@@ -3090,7 +3090,7 @@ static int blkstol2(s64 nb)
/*
- * NAME: dbAllocBottomUp()
+ * NAME: dbAllocBottomUp()
*
* FUNCTION: alloc the specified block range from the working block
* allocation map.
@@ -3241,7 +3241,7 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
BMAP_LOCK(bmp);
/* if this allocation group is completely free,
- * update the highest active allocation group number
+ * update the highest active allocation group number
* if this allocation group is the new max.
*/
agno = blkno >> bmp->db_agl2size;
@@ -3273,7 +3273,7 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
* NAME: dbExtendFS()
*
* FUNCTION: extend bmap from blkno for nblocks;
- * dbExtendFS() updates bmap ready for dbAllocBottomUp();
+ * dbExtendFS() updates bmap ready for dbAllocBottomUp();
*
* L2
* |
@@ -3284,13 +3284,13 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno,
* d0,...,dn d0,...,dn d0,...,dn d0,...,dn d0,...,dn d0,.,dm;
* L2L1L0d0,...,dnL0d0,...,dnL0d0,...,dnL1L0d0,...,dnL0d0,...,dnL0d0,..dm
*
- * <---old---><----------------------------extend----------------------->
+ * <---old---><----------------------------extend----------------------->
*/
int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
{
struct jfs_sb_info *sbi = JFS_SBI(ipbmap->i_sb);
int nbperpage = sbi->nbperpage;
- int i, i0 = TRUE, j, j0 = TRUE, k, n;
+ int i, i0 = true, j, j0 = true, k, n;
s64 newsize;
s64 p;
struct metapage *mp, *l2mp, *l1mp = NULL, *l0mp = NULL;
@@ -3330,7 +3330,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
bmp->db_numag += ((u32) newsize % (u32) bmp->db_agsize) ? 1 : 0;
/*
- * reconfigure db_agfree[]
+ * reconfigure db_agfree[]
* from old AG configuration to new AG configuration;
*
* coalesce contiguous k (newAGSize/oldAGSize) AGs;
@@ -3398,7 +3398,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
j = (blkno & (MAXL1SIZE - 1)) >> L2MAXL0SIZE;
l1leaf = l1dcp->stree + CTLLEAFIND + j;
p = BLKTOL0(blkno, sbi->l2nbperpage);
- j0 = FALSE;
+ j0 = false;
} else {
/* assign/init L1 page */
l1mp = get_metapage(ipbmap, p, PSIZE, 0);
@@ -3432,7 +3432,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
l0leaf = l0dcp->stree + CTLLEAFIND + i;
p = BLKTODMAP(blkno,
sbi->l2nbperpage);
- i0 = FALSE;
+ i0 = false;
} else {
/* assign/init L0 page */
l0mp = get_metapage(ipbmap, p, PSIZE, 0);
@@ -3491,7 +3491,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
} /* for each dmap in a L0 */
/*
- * build current L0 page from its leaves, and
+ * build current L0 page from its leaves, and
* initialize corresponding parent L1 leaf
*/
*l1leaf = dbInitDmapCtl(l0dcp, 0, ++i);
@@ -3515,7 +3515,7 @@ int dbExtendFS(struct inode *ipbmap, s64 blkno, s64 nblocks)
} /* for each L0 in a L1 */
/*
- * build current L1 page from its leaves, and
+ * build current L1 page from its leaves, and
* initialize corresponding parent L2 leaf
*/
*l2leaf = dbInitDmapCtl(l1dcp, 1, ++j);
@@ -3570,7 +3570,7 @@ void dbFinalizeBmap(struct inode *ipbmap)
* finalize bmap control page
*/
//finalize:
- /*
+ /*
* compute db_agpref: preferred ag to allocate from
* (the leftmost ag with average free space in it);
*/
@@ -3614,9 +3614,9 @@ void dbFinalizeBmap(struct inode *ipbmap)
/*
* compute db_aglevel, db_agheigth, db_width, db_agstart:
- * an ag is covered in aglevel dmapctl summary tree,
- * at agheight level height (from leaf) with agwidth number of nodes
- * each, which starts at agstart index node of the smmary tree node
+ * an ag is covered in aglevel dmapctl summary tree,
+ * at agheight level height (from leaf) with agwidth number of nodes
+ * each, which starts at agstart index node of the smmary tree node
* array;
*/
bmp->db_aglevel = BMAPSZTOLEV(bmp->db_agsize);
@@ -3635,13 +3635,13 @@ void dbFinalizeBmap(struct inode *ipbmap)
/*
* NAME: dbInitDmap()/ujfs_idmap_page()
- *
+ *
* FUNCTION: initialize working/persistent bitmap of the dmap page
* for the specified number of blocks:
- *
+ *
* at entry, the bitmaps had been initialized as free (ZEROS);
- * The number of blocks will only account for the actually
- * existing blocks. Blocks which don't actually exist in
+ * The number of blocks will only account for the actually
+ * existing blocks. Blocks which don't actually exist in
* the aggregate will be marked as allocated (ONES);
*
* PARAMETERS:
@@ -3677,7 +3677,7 @@ static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks)
/*
* free the bits corresponding to the block range (ZEROS):
- * note: not all bits of the first and last words may be contained
+ * note: not all bits of the first and last words may be contained
* within the block range.
*/
for (r = nblocks; r > 0; r -= nb, blkno += nb) {
@@ -3709,7 +3709,7 @@ static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks)
}
/*
- * mark bits following the range to be freed (non-existing
+ * mark bits following the range to be freed (non-existing
* blocks) as allocated (ONES)
*/
@@ -3741,11 +3741,11 @@ static int dbInitDmap(struct dmap * dp, s64 Blkno, int nblocks)
/*
* NAME: dbInitDmapTree()/ujfs_complete_dmap()
- *
+ *
* FUNCTION: initialize summary tree of the specified dmap:
*
* at entry, bitmap of the dmap has been initialized;
- *
+ *
* PARAMETERS:
* dp - dmap to complete
* blkno - starting block number for this dmap
@@ -3769,7 +3769,7 @@ static int dbInitDmapTree(struct dmap * dp)
/* init each leaf from corresponding wmap word:
* note: leaf is set to NOFREE(-1) if all blocks of corresponding
- * bitmap word are allocated.
+ * bitmap word are allocated.
*/
cp = tp->stree + le32_to_cpu(tp->leafidx);
for (i = 0; i < LPERDMAP; i++)
@@ -3782,10 +3782,10 @@ static int dbInitDmapTree(struct dmap * dp)
/*
* NAME: dbInitTree()/ujfs_adjtree()
- *
+ *
* FUNCTION: initialize binary buddy summary tree of a dmap or dmapctl.
*
- * at entry, the leaves of the tree has been initialized
+ * at entry, the leaves of the tree has been initialized
* from corresponding bitmap word or root of summary tree
* of the child control page;
* configure binary buddy system at the leaf level, then
@@ -3813,15 +3813,15 @@ static int dbInitTree(struct dmaptree * dtp)
/*
* configure the leaf levevl into binary buddy system
*
- * Try to combine buddies starting with a buddy size of 1
- * (i.e. two leaves). At a buddy size of 1 two buddy leaves
- * can be combined if both buddies have a maximum free of l2min;
- * the combination will result in the left-most buddy leaf having
- * a maximum free of l2min+1.
- * After processing all buddies for a given size, process buddies
- * at the next higher buddy size (i.e. current size * 2) and
- * the next maximum free (current free + 1).
- * This continues until the maximum possible buddy combination
+ * Try to combine buddies starting with a buddy size of 1
+ * (i.e. two leaves). At a buddy size of 1 two buddy leaves
+ * can be combined if both buddies have a maximum free of l2min;
+ * the combination will result in the left-most buddy leaf having
+ * a maximum free of l2min+1.
+ * After processing all buddies for a given size, process buddies
+ * at the next higher buddy size (i.e. current size * 2) and
+ * the next maximum free (current free + 1).
+ * This continues until the maximum possible buddy combination
* yields maximum free.
*/
for (l2free = dtp->budmin, bsize = 1; l2free < l2max;
@@ -3845,10 +3845,10 @@ static int dbInitTree(struct dmaptree * dtp)
* bubble summary information of leaves up the tree.
*
* Starting at the leaf node level, the four nodes described by
- * the higher level parent node are compared for a maximum free and
- * this maximum becomes the value of the parent node.
- * when all lower level nodes are processed in this fashion then
- * move up to the next level (parent becomes a lower level node) and
+ * the higher level parent node are compared for a maximum free and
+ * this maximum becomes the value of the parent node.
+ * when all lower level nodes are processed in this fashion then
+ * move up to the next level (parent becomes a lower level node) and
* continue the process for that level.
*/
for (child = le32_to_cpu(dtp->leafidx),
@@ -3857,7 +3857,7 @@ static int dbInitTree(struct dmaptree * dtp)
/* get index of 1st node of parent level */
parent = (child - 1) >> 2;
- /* set the value of the parent node as the maximum
+ /* set the value of the parent node as the maximum
* of the four nodes of the current level.
*/
for (i = 0, cp = tp + child, cp1 = tp + parent;
@@ -3885,8 +3885,8 @@ static int dbInitDmapCtl(struct dmapctl * dcp, int level, int i)
dcp->budmin = L2BPERDMAP + L2LPERCTL * level;
/*
- * initialize the leaves of current level that were not covered
- * by the specified input block range (i.e. the leaves have no
+ * initialize the leaves of current level that were not covered
+ * by the specified input block range (i.e. the leaves have no
* low level dmapctl or dmap).
*/
cp = &dcp->stree[CTLLEAFIND + i];
@@ -3900,9 +3900,9 @@ static int dbInitDmapCtl(struct dmapctl * dcp, int level, int i)
/*
* NAME: dbGetL2AGSize()/ujfs_getagl2size()
- *
+ *
* FUNCTION: Determine log2(allocation group size) from aggregate size
- *
+ *
* PARAMETERS:
* nblocks - Number of blocks in aggregate
*
@@ -3935,8 +3935,8 @@ static int dbGetL2AGSize(s64 nblocks)
/*
* NAME: dbMapFileSizeToMapSize()
- *
- * FUNCTION: compute number of blocks the block allocation map file
+ *
+ * FUNCTION: compute number of blocks the block allocation map file
* can cover from the map file size;
*
* RETURNS: Number of blocks which can be covered by this block map file;
@@ -3968,7 +3968,7 @@ s64 dbMapFileSizeToMapSize(struct inode * ipbmap)
npages = nblocks >> JFS_SBI(sb)->l2nbperpage;
level = BMAPPGTOLEV(npages);
- /* At each level, accumulate the number of dmap pages covered by
+ /* At each level, accumulate the number of dmap pages covered by
* the number of full child levels below it;
* repeat for the last incomplete child level.
*/
@@ -3990,7 +3990,7 @@ s64 dbMapFileSizeToMapSize(struct inode * ipbmap)
npages--;
}
- /* convert the number of dmaps into the number of blocks
+ /* convert the number of dmaps into the number of blocks
* which can be covered by the dmaps;
*/
nblocks = ndmaps << L2BPERDMAP;
diff --git a/fs/jfs/jfs_dmap.h b/fs/jfs/jfs_dmap.h
index 8b14cc8e0228..45ea454c74bd 100644
--- a/fs/jfs/jfs_dmap.h
+++ b/fs/jfs/jfs_dmap.h
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2002
+ * Copyright (C) International Business Machines Corp., 2000-2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_DMAP
@@ -27,7 +27,7 @@
#define L2LPERDMAP 8 /* l2 number of leaves per dmap tree */
#define DBWORD 32 /* # of blks covered by a map word */
#define L2DBWORD 5 /* l2 # of blks covered by a mword */
-#define BUDMIN L2DBWORD /* max free string in a map word */
+#define BUDMIN L2DBWORD /* max free string in a map word */
#define BPERDMAP (LPERDMAP * DBWORD) /* num of blks per dmap */
#define L2BPERDMAP 13 /* l2 num of blks per dmap */
#define CTLTREESIZE (1024+256+64+16+4+1) /* size of a dmapctl tree */
@@ -57,7 +57,7 @@
#define MAXMAPSIZE MAXL2SIZE /* maximum aggregate map size */
-/*
+/*
* determine the maximum free string for four (lower level) nodes
* of the tree.
*/
@@ -122,7 +122,7 @@ static __inline signed char TREEMAX(signed char *cp)
#define BLKTOCTL(b,s,l) \
(((l) == 2) ? 1 : ((l) == 1) ? BLKTOL1((b),(s)) : BLKTOL0((b),(s)))
-/*
+/*
* convert aggregate map size to the zero origin dmapctl level of the
* top dmapctl.
*/
@@ -192,13 +192,13 @@ typedef union dmtree {
/* macros for accessing fields within dmtree */
#define dmt_nleafs t1.nleafs
-#define dmt_l2nleafs t1.l2nleafs
-#define dmt_leafidx t1.leafidx
-#define dmt_height t1.height
-#define dmt_budmin t1.budmin
-#define dmt_stree t1.stree
+#define dmt_l2nleafs t1.l2nleafs
+#define dmt_leafidx t1.leafidx
+#define dmt_height t1.height
+#define dmt_budmin t1.budmin
+#define dmt_stree t1.stree
-/*
+/*
* on-disk aggregate disk allocation map descriptor.
*/
struct dbmap_disk {
@@ -237,7 +237,7 @@ struct dbmap {
s64 dn_agsize; /* num of blks per alloc group */
signed char dn_maxfreebud; /* max free buddy system */
}; /* - 4096 - */
-/*
+/*
* in-memory aggregate disk allocation map descriptor.
*/
struct bmap {
diff --git a/fs/jfs/jfs_dtree.c b/fs/jfs/jfs_dtree.c
index 6c3f08319846..ecb2216d881c 100644
--- a/fs/jfs/jfs_dtree.c
+++ b/fs/jfs/jfs_dtree.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -78,7 +78,7 @@
*
* case-insensitive search:
*
- * fold search key;
+ * fold search key;
*
* case-insensitive search of B-tree:
* for internal entry, router key is already folded;
@@ -93,7 +93,7 @@
* else
* return no match;
*
- * serialization:
+ * serialization:
* target directory inode lock is being held on entry/exit
* of all main directory service routines.
*
@@ -925,7 +925,7 @@ int dtInsert(tid_t tid, struct inode *ip,
*
* return: 0 - success;
* errno - failure;
- * leaf page unpinned;
+ * leaf page unpinned;
*/
static int dtSplitUp(tid_t tid,
struct inode *ip, struct dtsplit * split, struct btstack * btstack)
@@ -3767,7 +3767,7 @@ static int ciCompare(struct component_name * key, /* search key */
* across page boundary
*
* return: non-zero on error
- *
+ *
*/
static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
int ri, struct component_name * key, int flag)
@@ -3780,13 +3780,13 @@ static int ciGetLeafPrefixKey(dtpage_t * lp, int li, dtpage_t * rp,
lkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
GFP_KERNEL);
if (lkey.name == NULL)
- return -ENOSPC;
+ return -ENOMEM;
rkey.name = (wchar_t *) kmalloc((JFS_NAME_MAX + 1) * sizeof(wchar_t),
GFP_KERNEL);
if (rkey.name == NULL) {
kfree(lkey.name);
- return -ENOSPC;
+ return -ENOMEM;
}
/* get left and right key */
diff --git a/fs/jfs/jfs_dtree.h b/fs/jfs/jfs_dtree.h
index 13e4fdf07724..af8513f78648 100644
--- a/fs/jfs/jfs_dtree.h
+++ b/fs/jfs/jfs_dtree.h
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2002
+ * Copyright (C) International Business Machines Corp., 2000-2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_DTREE
@@ -80,7 +80,7 @@ struct idtentry {
/*
* leaf node entry head/only segment
*
- * For legacy filesystems, name contains 13 wchars -- no index field
+ * For legacy filesystems, name contains 13 wchars -- no index field
*/
struct ldtentry {
__le32 inumber; /* 4: 4-byte aligned */
diff --git a/fs/jfs/jfs_extent.c b/fs/jfs/jfs_extent.c
index 4d52593a5fc6..a35bdca6a805 100644
--- a/fs/jfs/jfs_extent.c
+++ b/fs/jfs/jfs_extent.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -74,7 +74,7 @@ static s64 extRoundDown(s64 nb);
* extent that is used as an allocation hint if the
* xaddr of the xad is non-zero. on successful exit,
* the xad describes the newly allocated extent.
- * abnr - boolean_t indicating whether the newly allocated extent
+ * abnr - bool indicating whether the newly allocated extent
* should be marked as allocated but not recorded.
*
* RETURN VALUES:
@@ -83,7 +83,7 @@ static s64 extRoundDown(s64 nb);
* -ENOSPC - insufficient disk resources.
*/
int
-extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
+extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
{
struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
@@ -117,7 +117,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
* following the hint extent.
*/
if (offsetXAD(xp) + nxlen == xoff &&
- abnr == ((xp->flag & XAD_NOTRECORDED) ? TRUE : FALSE))
+ abnr == ((xp->flag & XAD_NOTRECORDED) ? true : false))
xaddr = hint + nxlen;
/* adjust the hint to the last block of the extent */
@@ -125,7 +125,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
}
/* allocate the disk blocks for the extent. initially, extBalloc()
- * will try to allocate disk blocks for the requested size (xlen).
+ * will try to allocate disk blocks for the requested size (xlen).
* if this fails (xlen contiguous free blocks not avaliable), it'll
* try to allocate a smaller number of blocks (producing a smaller
* extent), with this smaller number of blocks consisting of the
@@ -148,9 +148,9 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
}
/* determine the value of the extent flag */
- xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0;
+ xflag = abnr ? XAD_NOTRECORDED : 0;
- /* if we can extend the hint extent to cover the current request,
+ /* if we can extend the hint extent to cover the current request,
* extend it. otherwise, insert a new extent to
* cover the current request.
*/
@@ -159,7 +159,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
else
rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
- /* if the extend or insert failed,
+ /* if the extend or insert failed,
* free the newly allocated blocks and return the error.
*/
if (rc) {
@@ -203,7 +203,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
* xlen - request size of the resulting extent.
* xp - pointer to an xad. on successful exit, the xad
* describes the newly allocated extent.
- * abnr - boolean_t indicating whether the newly allocated extent
+ * abnr - bool indicating whether the newly allocated extent
* should be marked as allocated but not recorded.
*
* RETURN VALUES:
@@ -211,7 +211,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, boolean_t abnr)
* -EIO - i/o error.
* -ENOSPC - insufficient disk resources.
*/
-int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
+int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
{
struct super_block *sb = ip->i_sb;
s64 xaddr, xlen, nxaddr, delta, xoff;
@@ -235,7 +235,7 @@ int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, boolean_t abnr)
xoff = offsetXAD(xp);
/* if the extend page is abnr and if the request is for
- * the extent to be allocated and recorded,
+ * the extent to be allocated and recorded,
* make the page allocated and recorded.
*/
if ((xp->flag & XAD_NOTRECORDED) && !abnr) {
@@ -397,7 +397,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
if ((rc = xtLookupList(ip, &lxdl, &xadl, 0)))
return (rc);
- /* check if not extent exists for the previous page.
+ /* check if not extent exists for the previous page.
* this is possible for sparse files.
*/
if (xadl.nxad == 0) {
@@ -410,7 +410,7 @@ int extHint(struct inode *ip, s64 offset, xad_t * xp)
*/
xp->flag &= XAD_NOTRECORDED;
- if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
+ if(xadl.nxad != 1 || lengthXAD(xp) != nbperpage) {
jfs_error(ip->i_sb, "extHint: corrupt xtree");
return -EIO;
}
@@ -468,7 +468,7 @@ int extRecord(struct inode *ip, xad_t * xp)
int extFill(struct inode *ip, xad_t * xp)
{
int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
- s64 blkno = offsetXAD(xp) >> ip->i_blksize;
+ s64 blkno = offsetXAD(xp) >> ip->i_blkbits;
// assert(ISSPARSE(ip));
@@ -476,7 +476,7 @@ int extFill(struct inode *ip, xad_t * xp)
XADaddress(xp, 0);
/* allocate an extent to fill the hole */
- if ((rc = extAlloc(ip, nbperpage, blkno, xp, FALSE)))
+ if ((rc = extAlloc(ip, nbperpage, blkno, xp, false)))
return (rc);
assert(lengthPXD(xp) == nbperpage);
@@ -492,7 +492,7 @@ int extFill(struct inode *ip, xad_t * xp)
* FUNCTION: allocate disk blocks to form an extent.
*
* initially, we will try to allocate disk blocks for the
- * requested size (nblocks). if this fails (nblocks
+ * requested size (nblocks). if this fails (nblocks
* contiguous free blocks not avaliable), we'll try to allocate
* a smaller number of blocks (producing a smaller extent), with
* this smaller number of blocks consisting of the requested
@@ -500,7 +500,7 @@ int extFill(struct inode *ip, xad_t * xp)
* number (i.e. 16 -> 8). we'll continue to round down and
* retry the allocation until the number of blocks to allocate
* is smaller than the number of blocks per page.
- *
+ *
* PARAMETERS:
* ip - the inode of the file.
* hint - disk block number to be used as an allocation hint.
@@ -509,7 +509,7 @@ int extFill(struct inode *ip, xad_t * xp)
* exit, this value is set to the number of blocks actually
* allocated.
* blkno - pointer to a block address that is filled in on successful
- * return with the starting block number of the newly
+ * return with the starting block number of the newly
* allocated block range.
*
* RETURN VALUES:
@@ -530,7 +530,7 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
/* get the number of blocks to initially attempt to allocate.
* we'll first try the number of blocks requested unless this
* number is greater than the maximum number of contiguous free
- * blocks in the map. in that case, we'll start off with the
+ * blocks in the map. in that case, we'll start off with the
* maximum free.
*/
max = (s64) 1 << bmp->db_maxfreebud;
@@ -582,19 +582,19 @@ extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
*
* FUNCTION: attempt to extend an extent's allocation.
*
- * initially, we will try to extend the extent's allocation
- * in place. if this fails, we'll try to move the extent
- * to a new set of blocks. if moving the extent, we initially
+ * Initially, we will try to extend the extent's allocation
+ * in place. If this fails, we'll try to move the extent
+ * to a new set of blocks. If moving the extent, we initially
* will try to allocate disk blocks for the requested size
- * (nnew). if this fails (new contiguous free blocks not
- * avaliable), we'll try to allocate a smaller number of
+ * (newnblks). if this fails (new contiguous free blocks not
+ * avaliable), we'll try to allocate a smaller number of
* blocks (producing a smaller extent), with this smaller
* number of blocks consisting of the requested number of
* blocks rounded down to the next smaller power of 2
- * number (i.e. 16 -> 8). we'll continue to round down and
+ * number (i.e. 16 -> 8). We'll continue to round down and
* retry the allocation until the number of blocks to allocate
* is smaller than the number of blocks per page.
- *
+ *
* PARAMETERS:
* ip - the inode of the file.
* blkno - starting block number of the extents current allocation.
@@ -625,7 +625,7 @@ extBrealloc(struct inode *ip,
return (rc);
}
- /* in place extension not possible.
+ /* in place extension not possible.
* try to move the extent to a new set of blocks.
*/
return (extBalloc(ip, blkno, newnblks, newblkno));
diff --git a/fs/jfs/jfs_extent.h b/fs/jfs/jfs_extent.h
index e80fc7ced87d..b567e12c52d3 100644
--- a/fs/jfs/jfs_extent.h
+++ b/fs/jfs/jfs_extent.h
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2001
+ * Copyright (C) International Business Machines Corp., 2000-2001
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_EXTENT
@@ -22,10 +22,10 @@
#define INOHINT(ip) \
(addressPXD(&(JFS_IP(ip)->ixpxd)) + lengthPXD(&(JFS_IP(ip)->ixpxd)) - 1)
-extern int extAlloc(struct inode *, s64, s64, xad_t *, boolean_t);
+extern int extAlloc(struct inode *, s64, s64, xad_t *, bool);
extern int extFill(struct inode *, xad_t *);
extern int extHint(struct inode *, s64, xad_t *);
-extern int extRealloc(struct inode *, s64, xad_t *, boolean_t);
+extern int extRealloc(struct inode *, s64, xad_t *, bool);
extern int extRecord(struct inode *, xad_t *);
#endif /* _H_JFS_EXTENT */
diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h
index 72a5588faeca..9901928668cf 100644
--- a/fs/jfs/jfs_filsys.h
+++ b/fs/jfs/jfs_filsys.h
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_FILSYS
@@ -21,9 +21,9 @@
/*
* jfs_filsys.h
*
- * file system (implementation-dependent) constants
+ * file system (implementation-dependent) constants
*
- * refer to <limits.h> for system wide implementation-dependent constants
+ * refer to <limits.h> for system wide implementation-dependent constants
*/
/*
@@ -49,7 +49,7 @@
#define JFS_DFS 0x20000000 /* DCE DFS LFS support */
-#define JFS_LINUX 0x10000000 /* Linux support */
+#define JFS_LINUX 0x10000000 /* Linux support */
/* case-sensitive name/directory support */
/* directory option */
@@ -59,7 +59,7 @@
#define JFS_COMMIT 0x00000f00 /* commit option mask */
#define JFS_GROUPCOMMIT 0x00000100 /* group (of 1) commit */
#define JFS_LAZYCOMMIT 0x00000200 /* lazy commit */
-#define JFS_TMPFS 0x00000400 /* temporary file system -
+#define JFS_TMPFS 0x00000400 /* temporary file system -
* do not log/commit:
*/
@@ -196,7 +196,7 @@
* followed by 1st extent of map
*/
#define AITBL_OFF (AIMAP_OFF + (SIZE_OF_MAP_PAGE << 1))
- /*
+ /*
* 1st extent of aggregate inode table
*/
#define SUPER2_OFF (AITBL_OFF + INODE_EXTENT_SIZE)
@@ -270,13 +270,13 @@
*/
#define FM_CLEAN 0x00000000 /* file system is unmounted and clean */
#define FM_MOUNT 0x00000001 /* file system is mounted cleanly */
-#define FM_DIRTY 0x00000002 /* file system was not unmounted and clean
- * when mounted or
+#define FM_DIRTY 0x00000002 /* file system was not unmounted and clean
+ * when mounted or
* commit failure occurred while being mounted:
- * fsck() must be run to repair
+ * fsck() must be run to repair
*/
#define FM_LOGREDO 0x00000004 /* log based recovery (logredo()) failed:
- * fsck() must be run to repair
+ * fsck() must be run to repair
*/
#define FM_EXTENDFS 0x00000008 /* file system extendfs() in progress */
diff --git a/fs/jfs/jfs_imap.c b/fs/jfs/jfs_imap.c
index ccbe60aff83d..489a3d63002d 100644
--- a/fs/jfs/jfs_imap.c
+++ b/fs/jfs/jfs_imap.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -78,8 +78,8 @@ static HLIST_HEAD(aggregate_hash);
/*
* forward references
*/
-static int diAllocAG(struct inomap *, int, boolean_t, struct inode *);
-static int diAllocAny(struct inomap *, int, boolean_t, struct inode *);
+static int diAllocAG(struct inomap *, int, bool, struct inode *);
+static int diAllocAny(struct inomap *, int, bool, struct inode *);
static int diAllocBit(struct inomap *, struct iag *, int);
static int diAllocExt(struct inomap *, int, struct inode *);
static int diAllocIno(struct inomap *, int, struct inode *);
@@ -98,7 +98,7 @@ static void copy_to_dinode(struct dinode *, struct inode *);
* FUNCTION: initialize the incore inode map control structures for
* a fileset or aggregate init time.
*
- * the inode map's control structure (dinomap) is
+ * the inode map's control structure (dinomap) is
* brought in from disk and placed in virtual memory.
*
* PARAMETERS:
@@ -107,7 +107,7 @@ static void copy_to_dinode(struct dinode *, struct inode *);
* RETURN VALUES:
* 0 - success
* -ENOMEM - insufficient free virtual memory.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
int diMount(struct inode *ipimap)
{
@@ -191,7 +191,7 @@ int diMount(struct inode *ipimap)
* RETURN VALUES:
* 0 - success
* -ENOMEM - insufficient free virtual memory.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
int diUnmount(struct inode *ipimap, int mounterror)
{
@@ -281,7 +281,7 @@ int diSync(struct inode *ipimap)
* on entry, the specifed incore inode should itself
* specify the disk inode number corresponding to the
* incore inode (i.e. i_number should be initialized).
- *
+ *
* this routine handles incore inode initialization for
* both "special" and "regular" inodes. special inodes
* are those required early in the mount process and
@@ -289,7 +289,7 @@ int diSync(struct inode *ipimap)
* is not yet initialized. these "special" inodes are
* identified by a NULL inode map inode pointer and are
* actually initialized by a call to diReadSpecial().
- *
+ *
* for regular inodes, the iag describing the disk inode
* is read from disk to determine the inode extent address
* for the disk inode. with the inode extent address in
@@ -302,9 +302,9 @@ int diSync(struct inode *ipimap)
*
* RETURN VALUES:
* 0 - success
- * -EIO - i/o error.
+ * -EIO - i/o error.
* -ENOMEM - insufficient memory
- *
+ *
*/
int diRead(struct inode *ip)
{
@@ -586,14 +586,14 @@ void diFreeSpecial(struct inode *ip)
* page of the extent that contains the disk inode is
* read and the disk inode portion of the incore inode
* is copied to the disk inode.
- *
+ *
* PARAMETERS:
* tid - transacation id
* ip - pointer to incore inode to be written to the inode extent.
*
* RETURN VALUES:
* 0 - success
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
int diWrite(tid_t tid, struct inode *ip)
{
@@ -676,11 +676,11 @@ int diWrite(tid_t tid, struct inode *ip)
* copy btree root from in-memory inode to on-disk inode
*
* (tlock is taken from inline B+-tree root in in-memory
- * inode when the B+-tree root is updated, which is pointed
+ * inode when the B+-tree root is updated, which is pointed
* by jfs_ip->blid as well as being on tx tlock list)
*
- * further processing of btree root is based on the copy
- * in in-memory inode, where txLog() will log from, and,
+ * further processing of btree root is based on the copy
+ * in in-memory inode, where txLog() will log from, and,
* for xtree root, txUpdateMap() will update map and reset
* XAD_NEW bit;
*/
@@ -824,7 +824,7 @@ int diWrite(tid_t tid, struct inode *ip)
memcpy(&dp->di_DASD, &ip->i_DASD, sizeof(struct dasd));
#endif /* _JFS_FASTDASD */
- /* release the buffer holding the updated on-disk inode.
+ /* release the buffer holding the updated on-disk inode.
* the buffer will be later written by commit processing.
*/
write_metapage(mp);
@@ -842,7 +842,7 @@ int diWrite(tid_t tid, struct inode *ip)
* if the inode to be freed represents the first (only)
* free inode within the iag, the iag will be placed on
* the ag free inode list.
- *
+ *
* freeing the inode will cause the inode extent to be
* freed if the inode is the only allocated inode within
* the extent. in this case all the disk resource backing
@@ -865,11 +865,11 @@ int diWrite(tid_t tid, struct inode *ip)
* any updates and are held until all updates are complete.
*
* PARAMETERS:
- * ip - inode to be freed.
+ * ip - inode to be freed.
*
* RETURN VALUES:
* 0 - success
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
int diFree(struct inode *ip)
{
@@ -898,7 +898,7 @@ int diFree(struct inode *ip)
*/
iagno = INOTOIAG(inum);
- /* make sure that the iag is contained within
+ /* make sure that the iag is contained within
* the map.
*/
if (iagno >= imap->im_nextiag) {
@@ -1013,7 +1013,7 @@ int diFree(struct inode *ip)
/* update the free inode summary map for the extent if
* freeing the inode means the extent will now have free
- * inodes (i.e., the inode being freed is the first free
+ * inodes (i.e., the inode being freed is the first free
* inode of extent),
*/
if (iagp->wmap[extno] == cpu_to_le32(ONES)) {
@@ -1204,9 +1204,9 @@ int diFree(struct inode *ip)
iagp->inofreefwd = iagp->inofreeback = cpu_to_le32(-1);
}
- /* update the inode extent address and working map
+ /* update the inode extent address and working map
* to reflect the free extent.
- * the permanent map should have been updated already
+ * the permanent map should have been updated already
* for the inode being freed.
*/
if (iagp->pmap[extno] != 0) {
@@ -1218,7 +1218,7 @@ int diFree(struct inode *ip)
/* update the free extent and free inode summary maps
* to reflect the freed extent.
- * the inode summary map is marked to indicate no inodes
+ * the inode summary map is marked to indicate no inodes
* available for the freed extent.
*/
sword = extno >> L2EXTSPERSUM;
@@ -1255,17 +1255,17 @@ int diFree(struct inode *ip)
* start transaction to update block allocation map
* for the inode extent freed;
*
- * N.B. AG_LOCK is released and iag will be released below, and
+ * N.B. AG_LOCK is released and iag will be released below, and
* other thread may allocate inode from/reusing the ixad freed
- * BUT with new/different backing inode extent from the extent
- * to be freed by the transaction;
+ * BUT with new/different backing inode extent from the extent
+ * to be freed by the transaction;
*/
tid = txBegin(ipimap->i_sb, COMMIT_FORCE);
mutex_lock(&JFS_IP(ipimap)->commit_mutex);
- /* acquire tlock of the iag page of the freed ixad
+ /* acquire tlock of the iag page of the freed ixad
* to force the page NOHOMEOK (even though no data is
- * logged from the iag page) until NOREDOPAGE|FREEXTENT log
+ * logged from the iag page) until NOREDOPAGE|FREEXTENT log
* for the free of the extent is committed;
* write FREEXTENT|NOREDOPAGE log record
* N.B. linelock is overlaid as freed extent descriptor;
@@ -1284,8 +1284,8 @@ int diFree(struct inode *ip)
* logredo needs the IAG number and IAG extent index in order
* to ensure that the IMap is consistent. The least disruptive
* way to pass these values through to the transaction manager
- * is in the iplist array.
- *
+ * is in the iplist array.
+ *
* It's not pretty, but it works.
*/
iplist[1] = (struct inode *) (size_t)iagno;
@@ -1340,20 +1340,20 @@ diInitInode(struct inode *ip, int iagno, int ino, int extno, struct iag * iagp)
/*
* NAME: diAlloc(pip,dir,ip)
*
- * FUNCTION: allocate a disk inode from the inode working map
+ * FUNCTION: allocate a disk inode from the inode working map
* for a fileset or aggregate.
*
* PARAMETERS:
- * pip - pointer to incore inode for the parent inode.
- * dir - TRUE if the new disk inode is for a directory.
- * ip - pointer to a new inode
+ * pip - pointer to incore inode for the parent inode.
+ * dir - 'true' if the new disk inode is for a directory.
+ * ip - pointer to a new inode
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
-int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
+int diAlloc(struct inode *pip, bool dir, struct inode *ip)
{
int rc, ino, iagno, addext, extno, bitno, sword;
int nwords, rem, i, agno;
@@ -1372,10 +1372,10 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
JFS_IP(ip)->ipimap = ipimap;
JFS_IP(ip)->fileset = FILESYSTEM_I;
- /* for a directory, the allocation policy is to start
+ /* for a directory, the allocation policy is to start
* at the ag level using the preferred ag.
*/
- if (dir == TRUE) {
+ if (dir) {
agno = dbNextAG(JFS_SBI(pip->i_sb)->ipbmap);
AG_LOCK(imap, agno);
goto tryag;
@@ -1435,7 +1435,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
/*
* try to allocate from the IAG
*/
- /* check if the inode may be allocated from the iag
+ /* check if the inode may be allocated from the iag
* (i.e. the inode has free inodes or new extent can be added).
*/
if (iagp->nfreeinos || addext) {
@@ -1490,7 +1490,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
* hint or, if appropriate (i.e. addext is true), allocate
* an extent of free inodes at or following the extent
* containing the hint.
- *
+ *
* the free inode and free extent summary maps are used
* here, so determine the starting summary map position
* and the number of words we'll have to examine. again,
@@ -1641,7 +1641,7 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
* inodes should be added for the allocation group, with
* the current request satisfied from this extent. if this
* is the case, an attempt will be made to do just that. if
- * this attempt fails or it has been determined that a new
+ * this attempt fails or it has been determined that a new
* extent should not be added, an attempt is made to satisfy
* the request by allocating an existing (backed) free inode
* from the allocation group.
@@ -1649,24 +1649,24 @@ int diAlloc(struct inode *pip, boolean_t dir, struct inode *ip)
* PRE CONDITION: Already have the AG lock for this AG.
*
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * agno - allocation group to allocate from.
- * dir - TRUE if the new disk inode is for a directory.
- * ip - pointer to the new inode to be filled in on successful return
+ * imap - pointer to inode map control structure.
+ * agno - allocation group to allocate from.
+ * dir - 'true' if the new disk inode is for a directory.
+ * ip - pointer to the new inode to be filled in on successful return
* with the disk inode number allocated, its extent address
* and the start of the ag.
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
static int
-diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
+diAllocAG(struct inomap * imap, int agno, bool dir, struct inode *ip)
{
int rc, addext, numfree, numinos;
- /* get the number of free and the number of backed disk
+ /* get the number of free and the number of backed disk
* inodes currently within the ag.
*/
numfree = imap->im_agctl[agno].numfree;
@@ -1682,7 +1682,7 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
* if there are a small number of free inodes or number of free
* inodes is a small percentage of the number of backed inodes.
*/
- if (dir == TRUE)
+ if (dir)
addext = (numfree < 64 ||
(numfree < 256
&& ((numfree * 100) / numinos) <= 20));
@@ -1719,26 +1719,26 @@ diAllocAG(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
* specified primary group.
*
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * agno - primary allocation group (to avoid).
- * dir - TRUE if the new disk inode is for a directory.
- * ip - pointer to a new inode to be filled in on successful return
+ * imap - pointer to inode map control structure.
+ * agno - primary allocation group (to avoid).
+ * dir - 'true' if the new disk inode is for a directory.
+ * ip - pointer to a new inode to be filled in on successful return
* with the disk inode number allocated, its extent address
* and the start of the ag.
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
static int
-diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
+diAllocAny(struct inomap * imap, int agno, bool dir, struct inode *ip)
{
int ag, rc;
int maxag = JFS_SBI(imap->im_ipimap->i_sb)->bmap->db_maxag;
- /* try to allocate from the ags following agno up to
+ /* try to allocate from the ags following agno up to
* the maximum ag number.
*/
for (ag = agno + 1; ag <= maxag; ag++) {
@@ -1780,21 +1780,21 @@ diAllocAny(struct inomap * imap, int agno, boolean_t dir, struct inode *ip)
*
* allocation occurs from the first iag on the list using
* the iag's free inode summary map to find the leftmost
- * free inode in the iag.
- *
+ * free inode in the iag.
+ *
* PRE CONDITION: Already have AG lock for this AG.
- *
+ *
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * agno - allocation group.
- * ip - pointer to new inode to be filled in on successful return
+ * imap - pointer to inode map control structure.
+ * agno - allocation group.
+ * ip - pointer to new inode to be filled in on successful return
* with the disk inode number allocated, its extent address
* and the start of the ag.
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
{
@@ -1867,7 +1867,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
return -EIO;
}
- /* compute the inode number within the iag.
+ /* compute the inode number within the iag.
*/
ino = (extno << L2INOSPEREXT) + rem;
@@ -1892,17 +1892,17 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
/*
* NAME: diAllocExt(imap,agno,ip)
*
- * FUNCTION: add a new extent of free inodes to an iag, allocating
- * an inode from this extent to satisfy the current allocation
- * request.
- *
+ * FUNCTION: add a new extent of free inodes to an iag, allocating
+ * an inode from this extent to satisfy the current allocation
+ * request.
+ *
* this routine first tries to find an existing iag with free
* extents through the ag free extent list. if list is not
* empty, the head of the list will be selected as the home
* of the new extent of free inodes. otherwise (the list is
* empty), a new iag will be allocated for the ag to contain
* the extent.
- *
+ *
* once an iag has been selected, the free extent summary map
* is used to locate a free extent within the iag and diNewExt()
* is called to initialize the extent, with initialization
@@ -1910,16 +1910,16 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
* for the purpose of satisfying this request.
*
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * agno - allocation group number.
- * ip - pointer to new inode to be filled in on successful return
+ * imap - pointer to inode map control structure.
+ * agno - allocation group number.
+ * ip - pointer to new inode to be filled in on successful return
* with the disk inode number allocated, its extent address
* and the start of the ag.
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
{
@@ -2012,7 +2012,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
/*
* NAME: diAllocBit(imap,iagp,ino)
*
- * FUNCTION: allocate a backed inode from an iag.
+ * FUNCTION: allocate a backed inode from an iag.
*
* this routine performs the mechanics of allocating a
* specified inode from a backed extent.
@@ -2025,19 +2025,19 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
* in the face of updates to multiple buffers. under this
* approach, all required buffers are obtained before making
* any updates and are held all are updates are complete.
- *
+ *
* PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on
* this AG. Must have read lock on imap inode.
*
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * iagp - pointer to iag.
- * ino - inode number to be allocated within the iag.
+ * imap - pointer to inode map control structure.
+ * iagp - pointer to iag.
+ * ino - inode number to be allocated within the iag.
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
{
@@ -2172,19 +2172,19 @@ static int diAllocBit(struct inomap * imap, struct iag * iagp, int ino)
* buffers. under this approach, all required buffers are
* obtained before making any updates and are held until all
* updates are complete.
- *
+ *
* PRE CONDITION: Already have buffer lock on iagp. Already have AG lock on
* this AG. Must have read lock on imap inode.
*
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * iagp - pointer to iag.
- * extno - extent number.
+ * imap - pointer to inode map control structure.
+ * iagp - pointer to iag.
+ * extno - extent number.
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
{
@@ -2432,34 +2432,34 @@ static int diNewExt(struct inomap * imap, struct iag * iagp, int extno)
/*
* NAME: diNewIAG(imap,iagnop,agno)
*
- * FUNCTION: allocate a new iag for an allocation group.
- *
- * first tries to allocate the iag from the inode map
- * iagfree list:
- * if the list has free iags, the head of the list is removed
+ * FUNCTION: allocate a new iag for an allocation group.
+ *
+ * first tries to allocate the iag from the inode map
+ * iagfree list:
+ * if the list has free iags, the head of the list is removed
* and returned to satisfy the request.
* if the inode map's iag free list is empty, the inode map
* is extended to hold a new iag. this new iag is initialized
* and returned to satisfy the request.
*
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * iagnop - pointer to an iag number set with the number of the
+ * imap - pointer to inode map control structure.
+ * iagnop - pointer to an iag number set with the number of the
* newly allocated iag upon successful return.
- * agno - allocation group number.
+ * agno - allocation group number.
* bpp - Buffer pointer to be filled in with new IAG's buffer
*
* RETURN VALUES:
* 0 - success.
* -ENOSPC - insufficient disk resources.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*
- * serialization:
+ * serialization:
* AG lock held on entry/exit;
* write lock on the map is held inside;
* read lock on the map is held on successful completion;
*
- * note: new iag transaction:
+ * note: new iag transaction:
* . synchronously write iag;
* . write log of xtree and inode of imap;
* . commit;
@@ -2494,7 +2494,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
/* acquire the free iag lock */
IAGFREE_LOCK(imap);
- /* if there are any iags on the inode map free iag list,
+ /* if there are any iags on the inode map free iag list,
* allocate the iag from the head of the list.
*/
if (imap->im_freeiag >= 0) {
@@ -2618,8 +2618,8 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
flush_metapage(mp);
/*
- * txCommit(COMMIT_FORCE) will synchronously write address
- * index pages and inode after commit in careful update order
+ * txCommit(COMMIT_FORCE) will synchronously write address
+ * index pages and inode after commit in careful update order
* of address index pages (right to left, bottom up);
*/
iplist[0] = ipimap;
@@ -2678,11 +2678,11 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
*
* FUNCTION: get the buffer for the specified iag within a fileset
* or aggregate inode map.
- *
+ *
* PARAMETERS:
- * imap - pointer to inode map control structure.
- * iagno - iag number.
- * bpp - point to buffer pointer to be filled in on successful
+ * imap - pointer to inode map control structure.
+ * iagno - iag number.
+ * bpp - point to buffer pointer to be filled in on successful
* exit.
*
* SERIALIZATION:
@@ -2692,7 +2692,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
*
* RETURN VALUES:
* 0 - success.
- * -EIO - i/o error.
+ * -EIO - i/o error.
*/
static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
{
@@ -2718,8 +2718,8 @@ static int diIAGRead(struct inomap * imap, int iagno, struct metapage ** mpp)
* the specified bit position.
*
* PARAMETERS:
- * word - word to be examined.
- * start - starting bit position.
+ * word - word to be examined.
+ * start - starting bit position.
*
* RETURN VALUES:
* bit position of first free bit in the word or 32 if
@@ -2740,24 +2740,24 @@ static int diFindFree(u32 word, int start)
/*
* NAME: diUpdatePMap()
- *
- * FUNCTION: Update the persistent map in an IAG for the allocation or
+ *
+ * FUNCTION: Update the persistent map in an IAG for the allocation or
* freeing of the specified inode.
- *
+ *
* PRE CONDITIONS: Working map has already been updated for allocate.
*
* PARAMETERS:
* ipimap - Incore inode map inode
* inum - Number of inode to mark in permanent map
- * is_free - If TRUE indicates inode should be marked freed, otherwise
+ * is_free - If 'true' indicates inode should be marked freed, otherwise
* indicates inode should be marked allocated.
*
- * RETURN VALUES:
+ * RETURN VALUES:
* 0 for success
*/
int
diUpdatePMap(struct inode *ipimap,
- unsigned long inum, boolean_t is_free, struct tblock * tblk)
+ unsigned long inum, bool is_free, struct tblock * tblk)
{
int rc;
struct iag *iagp;
@@ -2793,17 +2793,17 @@ diUpdatePMap(struct inode *ipimap,
extno = ino >> L2INOSPEREXT;
bitno = ino & (INOSPEREXT - 1);
mask = HIGHORDER >> bitno;
- /*
+ /*
* mark the inode free in persistent map:
*/
- if (is_free == TRUE) {
+ if (is_free) {
/* The inode should have been allocated both in working
* map and in persistent map;
* the inode will be freed from working map at the release
* of last reference release;
*/
if (!(le32_to_cpu(iagp->wmap[extno]) & mask)) {
- jfs_error(ipimap->i_sb,
+ jfs_error(ipimap->i_sb,
"diUpdatePMap: inode %ld not marked as "
"allocated in wmap!", inum);
}
@@ -2877,8 +2877,8 @@ diUpdatePMap(struct inode *ipimap,
* diExtendFS()
*
* function: update imap for extendfs();
- *
- * note: AG size has been increased s.t. each k old contiguous AGs are
+ *
+ * note: AG size has been increased s.t. each k old contiguous AGs are
* coalesced into a new AG;
*/
int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
@@ -2897,7 +2897,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
atomic_read(&imap->im_numfree));
/*
- * reconstruct imap
+ * reconstruct imap
*
* coalesce contiguous k (newAGSize/oldAGSize) AGs;
* i.e., (AGi, ..., AGj) where i = k*n and j = k*(n+1) - 1 to AGn;
@@ -2931,7 +2931,7 @@ int diExtendFS(struct inode *ipimap, struct inode *ipbmap)
}
/* leave free iag in the free iag list */
- if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
+ if (iagp->nfreeexts == cpu_to_le32(EXTSPERIAG)) {
release_metapage(bp);
continue;
}
@@ -3115,7 +3115,6 @@ static int copy_from_dinode(struct dinode * dip, struct inode *ip)
ip->i_mtime.tv_nsec = le32_to_cpu(dip->di_mtime.tv_nsec);
ip->i_ctime.tv_sec = le32_to_cpu(dip->di_ctime.tv_sec);
ip->i_ctime.tv_nsec = le32_to_cpu(dip->di_ctime.tv_nsec);
- ip->i_blksize = ip->i_sb->s_blocksize;
ip->i_blocks = LBLK2PBLK(ip->i_sb, le64_to_cpu(dip->di_nblocks));
ip->i_generation = le32_to_cpu(dip->di_gen);
diff --git a/fs/jfs/jfs_imap.h b/fs/jfs/jfs_imap.h
index 6e24465f0f98..4f9c346ed498 100644
--- a/fs/jfs/jfs_imap.h
+++ b/fs/jfs/jfs_imap.h
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2002
+ * Copyright (C) International Business Machines Corp., 2000-2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_IMAP
@@ -45,13 +45,13 @@
/* get the starting block number of the 4K page of an inode extent
* that contains ino.
*/
-#define INOPBLK(pxd,ino,l2nbperpg) (addressPXD((pxd)) + \
+#define INOPBLK(pxd,ino,l2nbperpg) (addressPXD((pxd)) + \
((((ino) & (INOSPEREXT-1)) >> L2INOSPERPAGE) << (l2nbperpg)))
/*
* inode allocation map:
- *
- * inode allocation map consists of
+ *
+ * inode allocation map consists of
* . the inode map control page and
* . inode allocation group pages (per 4096 inodes)
* which are addressed by standard JFS xtree.
@@ -159,11 +159,11 @@ struct inomap {
#define im_maxag im_imap.in_maxag
extern int diFree(struct inode *);
-extern int diAlloc(struct inode *, boolean_t, struct inode *);
+extern int diAlloc(struct inode *, bool, struct inode *);
extern int diSync(struct inode *);
/* external references */
extern int diUpdatePMap(struct inode *ipimap, unsigned long inum,
- boolean_t is_free, struct tblock * tblk);
+ bool is_free, struct tblock * tblk);
extern int diExtendFS(struct inode *ipimap, struct inode *ipbmap);
extern int diMount(struct inode *);
extern int diUnmount(struct inode *, int);
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index 54d73716ca8c..94005584445a 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -4,18 +4,18 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
+ */
#ifndef _H_JFS_INCORE
#define _H_JFS_INCORE
diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c
index 495df402916d..4c67ed97682b 100644
--- a/fs/jfs/jfs_inode.c
+++ b/fs/jfs/jfs_inode.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -61,7 +61,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
inode = new_inode(sb);
if (!inode) {
jfs_warn("ialloc: new_inode returned NULL!");
- return inode;
+ return ERR_PTR(-ENOMEM);
}
jfs_inode = JFS_IP(inode);
@@ -69,9 +69,10 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
rc = diAlloc(parent, S_ISDIR(mode), inode);
if (rc) {
jfs_warn("ialloc: diAlloc returned %d!", rc);
- make_bad_inode(inode);
+ if (rc == -EIO)
+ make_bad_inode(inode);
iput(inode);
- return NULL;
+ return ERR_PTR(rc);
}
inode->i_uid = current->fsuid;
@@ -97,7 +98,7 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
- return NULL;
+ return ERR_PTR(-EDQUOT);
}
inode->i_mode = mode;
@@ -115,7 +116,6 @@ struct inode *ialloc(struct inode *parent, umode_t mode)
}
jfs_inode->mode2 |= mode;
- inode->i_blksize = sb->s_blocksize;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
jfs_inode->otime = inode->i_ctime.tv_sec;
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h
index 1fc48df670c8..0d06ccfaff0e 100644
--- a/fs/jfs/jfs_inode.h
+++ b/fs/jfs/jfs_inode.h
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_INODE
diff --git a/fs/jfs/jfs_lock.h b/fs/jfs/jfs_lock.h
index 70ac9f7d1e00..7d78e83d7c40 100644
--- a/fs/jfs/jfs_lock.h
+++ b/fs/jfs/jfs_lock.h
@@ -1,19 +1,19 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2001
- * Portions Copyright (c) Christoph Hellwig, 2001-2002
+ * Copyright (C) International Business Machines Corp., 2000-2001
+ * Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_LOCK
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 3315f0b1fbc0..b89c9aba0466 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -337,7 +337,7 @@ int lmLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* PARAMETER: cd - commit descriptor
*
* RETURN: end-of-log address
- *
+ *
* serialization: LOG_LOCK() held on entry/exit
*/
static int
@@ -554,7 +554,7 @@ lmWriteRecord(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* PARAMETER: log
*
* RETURN: 0
- *
+ *
* serialization: LOG_LOCK() held on entry/exit
*/
static int lmNextPage(struct jfs_log * log)
@@ -656,7 +656,7 @@ static int lmNextPage(struct jfs_log * log)
* page number - redrive pageout of the page at the head of
* pageout queue until full page has been written.
*
- * RETURN:
+ * RETURN:
*
* NOTE:
* LOGGC_LOCK serializes log group commit queue, and
@@ -920,10 +920,10 @@ static void lmPostGC(struct lbuf * bp)
* this code is called again.
*
* PARAMETERS: log - log structure
- * hard_sync - 1 to force all metadata to be written
+ * hard_sync - 1 to force all metadata to be written
*
* RETURN: 0
- *
+ *
* serialization: LOG_LOCK() held on entry/exit
*/
static int lmLogSync(struct jfs_log * log, int hard_sync)
@@ -1052,7 +1052,7 @@ static int lmLogSync(struct jfs_log * log, int hard_sync)
* FUNCTION: write log SYNCPT record for specified log
*
* PARAMETERS: log - log structure
- * hard_sync - set to 1 to force metadata to be written
+ * hard_sync - set to 1 to force metadata to be written
*/
void jfs_syncpt(struct jfs_log *log, int hard_sync)
{ LOG_LOCK(log);
@@ -1067,7 +1067,7 @@ void jfs_syncpt(struct jfs_log *log, int hard_sync)
* insert filesystem in the active list of the log.
*
* PARAMETER: ipmnt - file system mount inode
- * iplog - log inode (out)
+ * iplog - log inode (out)
*
* RETURN:
*
@@ -1082,7 +1082,7 @@ int lmLogOpen(struct super_block *sb)
if (sbi->flag & JFS_NOINTEGRITY)
return open_dummy_log(sb);
-
+
if (sbi->mntflag & JFS_INLINELOG)
return open_inline_log(sb);
@@ -1131,7 +1131,7 @@ int lmLogOpen(struct super_block *sb)
log->bdev = bdev;
memcpy(log->uuid, sbi->loguuid, sizeof(log->uuid));
-
+
/*
* initialize log:
*/
@@ -1253,13 +1253,13 @@ static int open_dummy_log(struct super_block *sb)
* initialize the log from log superblock.
* set the log state in the superblock to LOGMOUNT and
* write SYNCPT log record.
- *
+ *
* PARAMETER: log - log structure
*
* RETURN: 0 - if ok
* -EINVAL - bad log magic number or superblock dirty
* error returned from logwait()
- *
+ *
* serialization: single first open thread
*/
int lmLogInit(struct jfs_log * log)
@@ -1297,7 +1297,7 @@ int lmLogInit(struct jfs_log * log)
if (!test_bit(log_INLINELOG, &log->flag))
log->l2bsize = L2LOGPSIZE;
-
+
/* check for disabled journaling to disk */
if (log->no_integrity) {
/*
@@ -1651,7 +1651,7 @@ void jfs_flush_journal(struct jfs_log *log, int wait)
* PARAMETER: log - log inode
*
* RETURN: 0 - success
- *
+ *
* serialization: single last close thread
*/
int lmLogShutdown(struct jfs_log * log)
@@ -1677,7 +1677,7 @@ int lmLogShutdown(struct jfs_log * log)
lrd.type = cpu_to_le16(LOG_SYNCPT);
lrd.length = 0;
lrd.log.syncpt.sync = 0;
-
+
lsn = lmWriteRecord(log, NULL, &lrd, NULL);
bp = log->bp;
lp = (struct logpage *) bp->l_ldata;
@@ -1703,7 +1703,7 @@ int lmLogShutdown(struct jfs_log * log)
jfs_info("lmLogShutdown: lsn:0x%x page:%d eor:%d",
lsn, log->page, log->eor);
- out:
+ out:
/*
* shutdown per log i/o
*/
@@ -1769,7 +1769,7 @@ static int lmLogFileSystem(struct jfs_log * log, struct jfs_sb_info *sbi,
lbmFree(bpsuper);
return -EIO;
}
-
+
}
/*
diff --git a/fs/jfs/jfs_logmgr.h b/fs/jfs/jfs_logmgr.h
index 8c6909b80014..a53fb17ea219 100644
--- a/fs/jfs/jfs_logmgr.h
+++ b/fs/jfs/jfs_logmgr.h
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_LOGMGR
@@ -35,19 +35,19 @@
/*
* log logical volume
*
- * a log is used to make the commit operation on journalled
+ * a log is used to make the commit operation on journalled
* files within the same logical volume group atomic.
* a log is implemented with a logical volume.
- * there is one log per logical volume group.
+ * there is one log per logical volume group.
*
* block 0 of the log logical volume is not used (ipl etc).
* block 1 contains a log "superblock" and is used by logFormat(),
- * lmLogInit(), lmLogShutdown(), and logRedo() to record status
- * of the log but is not otherwise used during normal processing.
+ * lmLogInit(), lmLogShutdown(), and logRedo() to record status
+ * of the log but is not otherwise used during normal processing.
* blocks 2 - (N-1) are used to contain log records.
*
- * when a volume group is varied-on-line, logRedo() must have
- * been executed before the file systems (logical volumes) in
+ * when a volume group is varied-on-line, logRedo() must have
+ * been executed before the file systems (logical volumes) in
* the volume group can be mounted.
*/
/*
@@ -97,26 +97,26 @@ struct logsuper {
* log logical page
*
* (this comment should be rewritten !)
- * the header and trailer structures (h,t) will normally have
+ * the header and trailer structures (h,t) will normally have
* the same page and eor value.
- * An exception to this occurs when a complete page write is not
+ * An exception to this occurs when a complete page write is not
* accomplished on a power failure. Since the hardware may "split write"
- * sectors in the page, any out of order sequence may occur during powerfail
+ * sectors in the page, any out of order sequence may occur during powerfail
* and needs to be recognized during log replay. The xor value is
* an "exclusive or" of all log words in the page up to eor. This
* 32 bit eor is stored with the top 16 bits in the header and the
* bottom 16 bits in the trailer. logredo can easily recognize pages
- * that were not completed by reconstructing this eor and checking
+ * that were not completed by reconstructing this eor and checking
* the log page.
*
- * Previous versions of the operating system did not allow split
- * writes and detected partially written records in logredo by
- * ordering the updates to the header, trailer, and the move of data
- * into the logdata area. The order: (1) data is moved (2) header
- * is updated (3) trailer is updated. In logredo, when the header
- * differed from the trailer, the header and trailer were reconciled
- * as follows: if h.page != t.page they were set to the smaller of
- * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only)
+ * Previous versions of the operating system did not allow split
+ * writes and detected partially written records in logredo by
+ * ordering the updates to the header, trailer, and the move of data
+ * into the logdata area. The order: (1) data is moved (2) header
+ * is updated (3) trailer is updated. In logredo, when the header
+ * differed from the trailer, the header and trailer were reconciled
+ * as follows: if h.page != t.page they were set to the smaller of
+ * the two and h.eor and t.eor set to 8 (i.e. empty page). if (only)
* h.eor != t.eor they were set to the smaller of their two values.
*/
struct logpage {
@@ -147,20 +147,20 @@ struct logpage {
* in a page, pages are written to temporary paging space if
* if they must be written to disk before commit, and i/o is
* scheduled for modified pages to their home location after
- * the log records containing the after values and the commit
+ * the log records containing the after values and the commit
* record is written to the log on disk, undo discards the copy
* in main-memory.)
*
- * a log record consists of a data area of variable length followed by
+ * a log record consists of a data area of variable length followed by
* a descriptor of fixed size LOGRDSIZE bytes.
- * the data area is rounded up to an integral number of 4-bytes and
+ * the data area is rounded up to an integral number of 4-bytes and
* must be no longer than LOGPSIZE.
- * the descriptor is of size of multiple of 4-bytes and aligned on a
- * 4-byte boundary.
+ * the descriptor is of size of multiple of 4-bytes and aligned on a
+ * 4-byte boundary.
* records are packed one after the other in the data area of log pages.
- * (sometimes a DUMMY record is inserted so that at least one record ends
+ * (sometimes a DUMMY record is inserted so that at least one record ends
* on every page or the longest record is placed on at most two pages).
- * the field eor in page header/trailer points to the byte following
+ * the field eor in page header/trailer points to the byte following
* the last record on a page.
*/
@@ -270,11 +270,11 @@ struct lrd {
/*
* NOREDOINOEXT: the inode extent is freed
*
- * do not apply after-image records which precede this
- * record in the log with the any of the 4 page block
- * numbers in this inode extent.
- *
- * NOTE: The fileset and pxd fields MUST remain in
+ * do not apply after-image records which precede this
+ * record in the log with the any of the 4 page block
+ * numbers in this inode extent.
+ *
+ * NOTE: The fileset and pxd fields MUST remain in
* the same fields in the REDOPAGE record format.
*
*/
@@ -319,12 +319,10 @@ struct lrd {
* do not apply records which precede this record in the log
* with the same inode number.
*
- * NOREDILE must be the first to be written at commit
+ * NOREDOFILE must be the first to be written at commit
* (last to be read in logredo()) - it prevents
* replay of preceding updates of all preceding generations
- * of the inumber esp. the on-disk inode itself,
- * but does NOT prevent
- * replay of the
+ * of the inumber esp. the on-disk inode itself.
*/
struct {
__le32 fileset; /* 4: fileset number */
@@ -332,7 +330,7 @@ struct lrd {
} noredofile;
/*
- * ? NEWPAGE:
+ * ? NEWPAGE:
*
* metadata type dependent
*/
@@ -464,7 +462,7 @@ struct lbuf {
s64 l_blkno; /* 8: log page block number */
caddr_t l_ldata; /* 4: data page */
struct page *l_page; /* The page itself */
- uint l_offset; /* Offset of l_ldata within the page */
+ uint l_offset; /* Offset of l_ldata within the page */
wait_queue_head_t l_ioevent; /* 4: i/o done event */
};
diff --git a/fs/jfs/jfs_metapage.c b/fs/jfs/jfs_metapage.c
index e1e0a6e6ebdf..0cccd1c39d75 100644
--- a/fs/jfs/jfs_metapage.c
+++ b/fs/jfs/jfs_metapage.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -257,7 +257,7 @@ static sector_t metapage_get_blocks(struct inode *inode, sector_t lblock,
int rc = 0;
int xflag;
s64 xaddr;
- sector_t file_blocks = (inode->i_size + inode->i_blksize - 1) >>
+ sector_t file_blocks = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
inode->i_blkbits;
if (lblock >= file_blocks)
@@ -461,7 +461,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
goto add_failed;
if (!bio->bi_size)
goto dump_bio;
-
+
submit_bio(WRITE, bio);
}
if (redirty)
@@ -648,7 +648,7 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
jfs_err("logical_size = %d, size = %d",
mp->logical_size, size);
dump_stack();
- goto unlock;
+ goto unlock;
}
mp->count++;
lock_metapage(mp);
@@ -658,7 +658,7 @@ struct metapage *__get_metapage(struct inode *inode, unsigned long lblock,
"__get_metapage: using a "
"discarded metapage");
discard_metapage(mp);
- goto unlock;
+ goto unlock;
}
clear_bit(META_discard, &mp->flag);
}
diff --git a/fs/jfs/jfs_metapage.h b/fs/jfs/jfs_metapage.h
index d17a3290f5aa..d94f8d9e87d7 100644
--- a/fs/jfs/jfs_metapage.h
+++ b/fs/jfs/jfs_metapage.h
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_METAPAGE
@@ -33,7 +33,7 @@ struct metapage {
unsigned long flag; /* See Below */
unsigned long count; /* Reference count */
void *data; /* Data pointer */
- sector_t index; /* block address of page */
+ sector_t index; /* block address of page */
wait_queue_head_t wait;
/* implementation */
@@ -65,10 +65,10 @@ extern struct metapage *__get_metapage(struct inode *inode,
int absolute, unsigned long new);
#define read_metapage(inode, lblock, size, absolute)\
- __get_metapage(inode, lblock, size, absolute, FALSE)
+ __get_metapage(inode, lblock, size, absolute, false)
#define get_metapage(inode, lblock, size, absolute)\
- __get_metapage(inode, lblock, size, absolute, TRUE)
+ __get_metapage(inode, lblock, size, absolute, true)
extern void release_metapage(struct metapage *);
extern void grab_metapage(struct metapage *);
diff --git a/fs/jfs/jfs_mount.c b/fs/jfs/jfs_mount.c
index 032d111bc330..4dd479834897 100644
--- a/fs/jfs/jfs_mount.c
+++ b/fs/jfs/jfs_mount.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -21,18 +21,18 @@
*
* note: file system in transition to aggregate/fileset:
*
- * file system mount is interpreted as the mount of aggregate,
- * if not already mounted, and mount of the single/only fileset in
+ * file system mount is interpreted as the mount of aggregate,
+ * if not already mounted, and mount of the single/only fileset in
* the aggregate;
*
* a file system/aggregate is represented by an internal inode
* (aka mount inode) initialized with aggregate superblock;
- * each vfs represents a fileset, and points to its "fileset inode
+ * each vfs represents a fileset, and points to its "fileset inode
* allocation map inode" (aka fileset inode):
- * (an aggregate itself is structured recursively as a filset:
- * an internal vfs is constructed and points to its "fileset inode
- * allocation map inode" (aka aggregate inode) where each inode
- * represents a fileset inode) so that inode number is mapped to
+ * (an aggregate itself is structured recursively as a filset:
+ * an internal vfs is constructed and points to its "fileset inode
+ * allocation map inode" (aka aggregate inode) where each inode
+ * represents a fileset inode) so that inode number is mapped to
* on-disk inode in uniform way at both aggregate and fileset level;
*
* each vnode/inode of a fileset is linked to its vfs (to facilitate
@@ -41,7 +41,7 @@
* per aggregate information, e.g., block size, etc.) as well as
* its file set inode.
*
- * aggregate
+ * aggregate
* ipmnt
* mntvfs -> fileset ipimap+ -> aggregate ipbmap -> aggregate ipaimap;
* fileset vfs -> vp(1) <-> ... <-> vp(n) <->vproot;
@@ -88,7 +88,7 @@ int jfs_mount(struct super_block *sb)
struct inode *ipbmap = NULL;
/*
- * read/validate superblock
+ * read/validate superblock
* (initialize mount inode from the superblock)
*/
if ((rc = chkSuper(sb))) {
@@ -238,7 +238,7 @@ int jfs_mount(struct super_block *sb)
*/
int jfs_mount_rw(struct super_block *sb, int remount)
{
- struct jfs_sb_info *sbi = JFS_SBI(sb);
+ struct jfs_sb_info *sbi = JFS_SBI(sb);
int rc;
/*
@@ -291,7 +291,7 @@ int jfs_mount_rw(struct super_block *sb, int remount)
/*
* chkSuper()
*
- * validate the superblock of the file system to be mounted and
+ * validate the superblock of the file system to be mounted and
* get the file system parameters.
*
* returns
@@ -426,7 +426,7 @@ int updateSuper(struct super_block *sb, uint state)
jfs_err("updateSuper: bad state");
} else if (sbi->state == FM_DIRTY)
return 0;
-
+
if ((rc = readSuper(sb, &bh)))
return rc;
@@ -486,9 +486,9 @@ int readSuper(struct super_block *sb, struct buffer_head **bpp)
* for this file system past this point in log.
* it is harmless if mount fails.
*
- * note: MOUNT record is at aggregate level, not at fileset level,
+ * note: MOUNT record is at aggregate level, not at fileset level,
* since log records of previous mounts of a fileset
- * (e.g., AFTER record of extent allocation) have to be processed
+ * (e.g., AFTER record of extent allocation) have to be processed
* to update block allocation map at aggregate level.
*/
static int logMOUNT(struct super_block *sb)
diff --git a/fs/jfs/jfs_superblock.h b/fs/jfs/jfs_superblock.h
index 682cf1a68a18..884fc21ab8ee 100644
--- a/fs/jfs/jfs_superblock.h
+++ b/fs/jfs/jfs_superblock.h
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_SUPERBLOCK
@@ -21,14 +21,14 @@
/*
* make the magic number something a human could read
*/
-#define JFS_MAGIC "JFS1" /* Magic word */
+#define JFS_MAGIC "JFS1" /* Magic word */
#define JFS_VERSION 2 /* Version number: Version 2 */
#define LV_NAME_SIZE 11 /* MUST BE 11 for OS/2 boot sector */
-/*
- * aggregate superblock
+/*
+ * aggregate superblock
*
* The name superblock is too close to super_block, so the name has been
* changed to jfs_superblock. The utilities are still using the old name.
@@ -40,7 +40,7 @@ struct jfs_superblock {
__le64 s_size; /* 8: aggregate size in hardware/LVM blocks;
* VFS: number of blocks
*/
- __le32 s_bsize; /* 4: aggregate block size in bytes;
+ __le32 s_bsize; /* 4: aggregate block size in bytes;
* VFS: fragment size
*/
__le16 s_l2bsize; /* 2: log2 of s_bsize */
@@ -54,7 +54,7 @@ struct jfs_superblock {
__le32 s_flag; /* 4: aggregate attributes:
* see jfs_filsys.h
*/
- __le32 s_state; /* 4: mount/unmount/recovery state:
+ __le32 s_state; /* 4: mount/unmount/recovery state:
* see jfs_filsys.h
*/
__le32 s_compress; /* 4: > 0 if data compression */
@@ -75,11 +75,11 @@ struct jfs_superblock {
struct timestruc_t s_time; /* 8: time last updated */
__le32 s_fsckloglen; /* 4: Number of filesystem blocks reserved for
- * the fsck service log.
+ * the fsck service log.
* N.B. These blocks are divided among the
* versions kept. This is not a per
* version size.
- * N.B. These blocks are included in the
+ * N.B. These blocks are included in the
* length field of s_fsckpxd.
*/
s8 s_fscklog; /* 1: which fsck service log is most recent
@@ -87,7 +87,7 @@ struct jfs_superblock {
* 1 => the first one
* 2 => the 2nd one
*/
- char s_fpack[11]; /* 11: file system volume name
+ char s_fpack[11]; /* 11: file system volume name
* N.B. This must be 11 bytes to
* conform with the OS/2 BootSector
* requirements
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index efbb586bed4b..81f6f04af192 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -282,7 +282,7 @@ int txInit(void)
TxLockVHWM = (nTxLock * 8) / 10;
size = sizeof(struct tblock) * nTxBlock;
- TxBlock = (struct tblock *) vmalloc(size);
+ TxBlock = vmalloc(size);
if (TxBlock == NULL)
return -ENOMEM;
@@ -307,7 +307,7 @@ int txInit(void)
* tlock id = 0 is reserved.
*/
size = sizeof(struct tlock) * nTxLock;
- TxLock = (struct tlock *) vmalloc(size);
+ TxLock = vmalloc(size);
if (TxLock == NULL) {
vfree(TxBlock);
return -ENOMEM;
@@ -2026,8 +2026,6 @@ static void xtLog(struct jfs_log * log, struct tblock * tblk, struct lrd * lrd,
* truncate entry XAD[twm == next - 1]:
*/
if (twm == next - 1) {
- struct pxd_lock *pxdlock;
-
/* format a maplock for txUpdateMap() to update bmap
* to free truncated delta extent of the truncated
* entry XAD[next - 1];
@@ -2393,7 +2391,7 @@ static void txUpdateMap(struct tblock * tblk)
* unlock mapper/write lock
*/
if (tblk->xflag & COMMIT_CREATE) {
- diUpdatePMap(ipimap, tblk->ino, FALSE, tblk);
+ diUpdatePMap(ipimap, tblk->ino, false, tblk);
/* update persistent block allocation map
* for the allocation of inode extent;
*/
@@ -2403,7 +2401,7 @@ static void txUpdateMap(struct tblock * tblk)
txAllocPMap(ipimap, (struct maplock *) & pxdlock, tblk);
} else if (tblk->xflag & COMMIT_DELETE) {
ip = tblk->u.ip;
- diUpdatePMap(ipimap, ip->i_ino, TRUE, tblk);
+ diUpdatePMap(ipimap, ip->i_ino, true, tblk);
iput(ip);
}
}
@@ -2451,7 +2449,7 @@ static void txAllocPMap(struct inode *ip, struct maplock * maplock,
if (xad->flag & (XAD_NEW | XAD_EXTENDED)) {
xaddr = addressXAD(xad);
xlen = lengthXAD(xad);
- dbUpdatePMap(ipbmap, FALSE, xaddr,
+ dbUpdatePMap(ipbmap, false, xaddr,
(s64) xlen, tblk);
xad->flag &= ~(XAD_NEW | XAD_EXTENDED);
jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
@@ -2462,7 +2460,7 @@ static void txAllocPMap(struct inode *ip, struct maplock * maplock,
pxdlock = (struct pxd_lock *) maplock;
xaddr = addressPXD(&pxdlock->pxd);
xlen = lengthPXD(&pxdlock->pxd);
- dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen, tblk);
+ dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen, tblk);
jfs_info("allocPMap: xaddr:0x%lx xlen:%d", (ulong) xaddr, xlen);
} else { /* (maplock->flag & mlckALLOCPXDLIST) */
@@ -2471,7 +2469,7 @@ static void txAllocPMap(struct inode *ip, struct maplock * maplock,
for (n = 0; n < pxdlistlock->count; n++, pxd++) {
xaddr = addressPXD(pxd);
xlen = lengthPXD(pxd);
- dbUpdatePMap(ipbmap, FALSE, xaddr, (s64) xlen,
+ dbUpdatePMap(ipbmap, false, xaddr, (s64) xlen,
tblk);
jfs_info("allocPMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
@@ -2513,7 +2511,7 @@ void txFreeMap(struct inode *ip,
if (!(xad->flag & XAD_NEW)) {
xaddr = addressXAD(xad);
xlen = lengthXAD(xad);
- dbUpdatePMap(ipbmap, TRUE, xaddr,
+ dbUpdatePMap(ipbmap, true, xaddr,
(s64) xlen, tblk);
jfs_info("freePMap: xaddr:0x%lx "
"xlen:%d",
@@ -2524,7 +2522,7 @@ void txFreeMap(struct inode *ip,
pxdlock = (struct pxd_lock *) maplock;
xaddr = addressPXD(&pxdlock->pxd);
xlen = lengthPXD(&pxdlock->pxd);
- dbUpdatePMap(ipbmap, TRUE, xaddr, (s64) xlen,
+ dbUpdatePMap(ipbmap, true, xaddr, (s64) xlen,
tblk);
jfs_info("freePMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
@@ -2535,7 +2533,7 @@ void txFreeMap(struct inode *ip,
for (n = 0; n < pxdlistlock->count; n++, pxd++) {
xaddr = addressPXD(pxd);
xlen = lengthPXD(pxd);
- dbUpdatePMap(ipbmap, TRUE, xaddr,
+ dbUpdatePMap(ipbmap, true, xaddr,
(s64) xlen, tblk);
jfs_info("freePMap: xaddr:0x%lx xlen:%d",
(ulong) xaddr, xlen);
diff --git a/fs/jfs/jfs_txnmgr.h b/fs/jfs/jfs_txnmgr.h
index 0e4dc4514c47..7863cf21afca 100644
--- a/fs/jfs/jfs_txnmgr.h
+++ b/fs/jfs/jfs_txnmgr.h
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_TXNMGR
@@ -179,7 +179,7 @@ struct linelock {
/* (8) */
struct lv lv[20]; /* 40: */
-}; /* (48) */
+}; /* (48) */
#define dt_lock linelock
@@ -211,8 +211,8 @@ struct xtlock {
* at tlock.lock/linelock: watch for alignment;
* N.B. next field may be set by linelock, and should not
* be modified by maplock;
- * N.B. index of the first pxdlock specifies index of next
- * free maplock (i.e., number of maplock) in the tlock;
+ * N.B. index of the first pxdlock specifies index of next
+ * free maplock (i.e., number of maplock) in the tlock;
*/
struct maplock {
lid_t next; /* 2: */
diff --git a/fs/jfs/jfs_types.h b/fs/jfs/jfs_types.h
index 5bfad39a2078..09b252958687 100644
--- a/fs/jfs/jfs_types.h
+++ b/fs/jfs/jfs_types.h
@@ -57,10 +57,6 @@ struct timestruc_t {
#define HIGHORDER 0x80000000u /* high order bit on */
#define ONES 0xffffffffu /* all bit on */
-typedef int boolean_t;
-#define TRUE 1
-#define FALSE 0
-
/*
* logical xd (lxd)
*/
diff --git a/fs/jfs/jfs_umount.c b/fs/jfs/jfs_umount.c
index 21eaf7ac0fcb..a386f48c73fc 100644
--- a/fs/jfs/jfs_umount.c
+++ b/fs/jfs/jfs_umount.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -22,8 +22,8 @@
* note: file system in transition to aggregate/fileset:
* (ref. jfs_mount.c)
*
- * file system unmount is interpreted as mount of the single/only
- * fileset in the aggregate and, if unmount of the last fileset,
+ * file system unmount is interpreted as mount of the single/only
+ * fileset in the aggregate and, if unmount of the last fileset,
* as unmount of the aggerate;
*/
@@ -60,13 +60,13 @@ int jfs_umount(struct super_block *sb)
jfs_info("UnMount JFS: sb:0x%p", sb);
/*
- * update superblock and close log
+ * update superblock and close log
*
* if mounted read-write and log based recovery was enabled
*/
if ((log = sbi->log))
/*
- * Wait for outstanding transactions to be written to log:
+ * Wait for outstanding transactions to be written to log:
*/
jfs_flush_journal(log, 2);
@@ -112,17 +112,17 @@ int jfs_umount(struct super_block *sb)
/*
* ensure all file system file pages are propagated to their
- * home blocks on disk (and their in-memory buffer pages are
+ * home blocks on disk (and their in-memory buffer pages are
* invalidated) BEFORE updating file system superblock state
- * (to signify file system is unmounted cleanly, and thus in
- * consistent state) and log superblock active file system
+ * (to signify file system is unmounted cleanly, and thus in
+ * consistent state) and log superblock active file system
* list (to signify skip logredo()).
*/
if (log) { /* log = NULL if read-only mount */
updateSuper(sb, FM_CLEAN);
/*
- * close log:
+ * close log:
*
* remove file system from log active file system list.
*/
@@ -142,7 +142,7 @@ int jfs_umount_rw(struct super_block *sb)
return 0;
/*
- * close log:
+ * close log:
*
* remove file system from log active file system list.
*/
diff --git a/fs/jfs/jfs_unicode.c b/fs/jfs/jfs_unicode.c
index f327decfb155..c7de6f5bbefc 100644
--- a/fs/jfs/jfs_unicode.c
+++ b/fs/jfs/jfs_unicode.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -57,8 +57,8 @@ int jfs_strfromUCS_le(char *to, const __le16 * from,
warn--;
warn_again--;
printk(KERN_ERR
- "non-latin1 character 0x%x found in JFS file name\n",
- le16_to_cpu(from[i]));
+ "non-latin1 character 0x%x found in JFS file name\n",
+ le16_to_cpu(from[i]));
printk(KERN_ERR
"mount with iocharset=utf8 to access\n");
}
@@ -124,7 +124,7 @@ int get_UCSname(struct component_name * uniName, struct dentry *dentry)
kmalloc((length + 1) * sizeof(wchar_t), GFP_NOFS);
if (uniName->name == NULL)
- return -ENOSPC;
+ return -ENOMEM;
uniName->namlen = jfs_strtoUCS(uniName->name, dentry->d_name.name,
length, nls_tab);
diff --git a/fs/jfs/jfs_unicode.h b/fs/jfs/jfs_unicode.h
index 69e25ebe87ac..3fbb3a225590 100644
--- a/fs/jfs/jfs_unicode.h
+++ b/fs/jfs/jfs_unicode.h
@@ -1,19 +1,19 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2002
- * Portions Copyright (c) Christoph Hellwig, 2001-2002
+ * Copyright (C) International Business Machines Corp., 2000-2002
+ * Portions Copyright (C) Christoph Hellwig, 2001-2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_UNICODE
diff --git a/fs/jfs/jfs_uniupr.c b/fs/jfs/jfs_uniupr.c
index 4ab185d26308..cfe50666d312 100644
--- a/fs/jfs/jfs_uniupr.c
+++ b/fs/jfs/jfs_uniupr.c
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2002
+ * Copyright (C) International Business Machines Corp., 2000-2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/fs/jfs/jfs_xattr.h b/fs/jfs/jfs_xattr.h
index 25e9990bccd1..88b6cc535bf2 100644
--- a/fs/jfs/jfs_xattr.h
+++ b/fs/jfs/jfs_xattr.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2002
+ * Copyright (C) International Business Machines Corp., 2000-2002
*
* 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/fs/jfs/jfs_xtree.c b/fs/jfs/jfs_xtree.c
index e72f4ebb6e9c..e98eb03e5310 100644
--- a/fs/jfs/jfs_xtree.c
+++ b/fs/jfs/jfs_xtree.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
@@ -2428,7 +2428,7 @@ printf("xtUpdate.updateLeft.split p:0x%p\n", p);
* return:
*/
int xtAppend(tid_t tid, /* transaction id */
- struct inode *ip, int xflag, s64 xoff, s32 maxblocks,
+ struct inode *ip, int xflag, s64 xoff, s32 maxblocks,
s32 * xlenp, /* (in/out) */
s64 * xaddrp, /* (in/out) */
int flag)
@@ -2499,7 +2499,7 @@ int xtAppend(tid_t tid, /* transaction id */
pxdlist.maxnpxd = pxdlist.npxd = 0;
pxd = &pxdlist.pxd[0];
nblocks = JFS_SBI(ip->i_sb)->nbperpage;
- for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) {
+ for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) {
if ((rc = dbAllocBottomUp(ip, xaddr, (s64) nblocks)) == 0) {
PXDaddress(pxd, xaddr);
PXDlength(pxd, nblocks);
@@ -2514,7 +2514,7 @@ int xtAppend(tid_t tid, /* transaction id */
goto out;
}
- xlen = min(xlen, maxblocks);
+ xlen = min(xlen, maxblocks);
/*
* allocate data extent requested
@@ -2964,7 +2964,7 @@ xtRelocate(tid_t tid, struct inode * ip, xad_t * oxad, /* old XAD */
cmSetXD(ip, cp, pno, dxaddr, nblks);
/* release the cbuf, mark it as modified */
- cmPut(cp, TRUE);
+ cmPut(cp, true);
dxaddr += nblks;
sxaddr += nblks;
diff --git a/fs/jfs/jfs_xtree.h b/fs/jfs/jfs_xtree.h
index af668a80b40f..164f6f2b1019 100644
--- a/fs/jfs/jfs_xtree.h
+++ b/fs/jfs/jfs_xtree.h
@@ -1,18 +1,18 @@
/*
- * Copyright (c) International Business Machines Corp., 2000-2002
+ * Copyright (C) International Business Machines Corp., 2000-2002
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_JFS_XTREE
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 295268ad231b..a6a8c16c872c 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -41,7 +41,7 @@ static s64 commitZeroLink(tid_t, struct inode *);
/*
* NAME: free_ea_wmap(inode)
*
- * FUNCTION: free uncommitted extended attributes from working map
+ * FUNCTION: free uncommitted extended attributes from working map
*
*/
static inline void free_ea_wmap(struct inode *inode)
@@ -62,7 +62,7 @@ static inline void free_ea_wmap(struct inode *inode)
* FUNCTION: create a regular file in the parent directory <dip>
* with name = <from dentry> and mode = <mode>
*
- * PARAMETER: dip - parent directory vnode
+ * PARAMETER: dip - parent directory vnode
* dentry - dentry of new file
* mode - create mode (rwxrwxrwx).
* nd- nd struct
@@ -97,8 +97,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
* begin the transaction before we search the directory.
*/
ip = ialloc(dip, mode);
- if (ip == NULL) {
- rc = -ENOSPC;
+ if (IS_ERR(ip)) {
+ rc = PTR_ERR(ip);
goto out2;
}
@@ -190,7 +190,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
* FUNCTION: create a child directory in the parent directory <dip>
* with name = <from dentry> and mode = <mode>
*
- * PARAMETER: dip - parent directory vnode
+ * PARAMETER: dip - parent directory vnode
* dentry - dentry of child directory
* mode - create mode (rwxrwxrwx).
*
@@ -231,8 +231,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
* begin the transaction before we search the directory.
*/
ip = ialloc(dip, S_IFDIR | mode);
- if (ip == NULL) {
- rc = -ENOSPC;
+ if (IS_ERR(ip)) {
+ rc = PTR_ERR(ip);
goto out2;
}
@@ -292,7 +292,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
mark_inode_dirty(ip);
/* update parent directory inode */
- dip->i_nlink++; /* for '..' from child directory */
+ inc_nlink(dip); /* for '..' from child directory */
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
mark_inode_dirty(dip);
@@ -324,7 +324,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
*
* FUNCTION: remove a link to child directory
*
- * PARAMETER: dip - parent inode
+ * PARAMETER: dip - parent inode
* dentry - child directory dentry
*
* RETURN: -EINVAL - if name is . or ..
@@ -332,10 +332,10 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
* errors from subroutines
*
* note:
- * if other threads have the directory open when the last link
- * is removed, the "." and ".." entries, if present, are removed before
- * rmdir() returns and no new entries may be created in the directory,
- * but the directory is not removed until the last reference to
+ * if other threads have the directory open when the last link
+ * is removed, the "." and ".." entries, if present, are removed before
+ * rmdir() returns and no new entries may be created in the directory,
+ * but the directory is not removed until the last reference to
* the directory is released (cf.unlink() of regular file).
*/
static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
@@ -393,9 +393,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
/* update parent directory's link count corresponding
* to ".." entry of the target directory deleted
*/
- dip->i_nlink--;
dip->i_ctime = dip->i_mtime = CURRENT_TIME;
- mark_inode_dirty(dip);
+ inode_dec_link_count(dip);
/*
* OS/2 could have created EA and/or ACL
@@ -415,7 +414,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
JFS_IP(ip)->acl.flag = 0;
/* mark the target directory as deleted */
- ip->i_nlink = 0;
+ clear_nlink(ip);
mark_inode_dirty(ip);
rc = txCommit(tid, 2, &iplist[0], 0);
@@ -447,11 +446,11 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
/*
* NAME: jfs_unlink(dip, dentry)
*
- * FUNCTION: remove a link to object <vp> named by <name>
+ * FUNCTION: remove a link to object <vp> named by <name>
* from parent directory <dvp>
*
- * PARAMETER: dip - inode of parent directory
- * dentry - dentry of object to be removed
+ * PARAMETER: dip - inode of parent directory
+ * dentry - dentry of object to be removed
*
* RETURN: errors from subroutines
*
@@ -515,8 +514,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
mark_inode_dirty(dip);
/* update target's inode */
- ip->i_nlink--;
- mark_inode_dirty(ip);
+ inode_dec_link_count(ip);
/*
* commit zero link count object
@@ -600,7 +598,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
*
* FUNCTION: for non-directory, called by jfs_remove(),
* truncate a regular file, directory or symbolic
- * link to zero length. return 0 if type is not
+ * link to zero length. return 0 if type is not
* one of these.
*
* if the file is currently associated with a VM segment
@@ -610,7 +608,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
* map by ctrunc1.
* if there is no VM segment on entry, the resources are
* freed in both work and permanent map.
- * (? for temporary file - memory object is cached even
+ * (? for temporary file - memory object is cached even
* after no reference:
* reference count > 0 - )
*
@@ -664,7 +662,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip)
/*
* free xtree/data (truncate to zero length):
- * free xtree/data pages from cache if COMMIT_PWMAP,
+ * free xtree/data pages from cache if COMMIT_PWMAP,
* free xtree/data blocks from persistent block map, and
* free xtree/data blocks from working block map if COMMIT_PWMAP;
*/
@@ -679,7 +677,7 @@ static s64 commitZeroLink(tid_t tid, struct inode *ip)
* NAME: jfs_free_zero_link()
*
* FUNCTION: for non-directory, called by iClose(),
- * free resources of a file from cache and WORKING map
+ * free resources of a file from cache and WORKING map
* for a file previously committed with zero link count
* while associated with a pager object,
*
@@ -764,7 +762,7 @@ void jfs_free_zero_link(struct inode *ip)
* FUNCTION: create a link to <vp> by the name = <name>
* in the parent directory <dvp>
*
- * PARAMETER: vp - target object
+ * PARAMETER: vp - target object
* dvp - parent directory of new link
* name - name of new link to target object
* crp - credential
@@ -824,7 +822,7 @@ static int jfs_link(struct dentry *old_dentry,
goto free_dname;
/* update object inode */
- ip->i_nlink++; /* for new link */
+ inc_nlink(ip); /* for new link */
ip->i_ctime = CURRENT_TIME;
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
mark_inode_dirty(dir);
@@ -835,7 +833,7 @@ static int jfs_link(struct dentry *old_dentry,
rc = txCommit(tid, 2, &iplist[0], 0);
if (rc) {
- ip->i_nlink--;
+ ip->i_nlink--; /* never instantiated */
iput(ip);
} else
d_instantiate(dentry, ip);
@@ -860,8 +858,8 @@ static int jfs_link(struct dentry *old_dentry,
* in directory <dip>
*
* PARAMETER: dip - parent directory vnode
- * dentry - dentry of symbolic link
- * name - the path name of the existing object
+ * dentry - dentry of symbolic link
+ * name - the path name of the existing object
* that will be the source of the link
*
* RETURN: errors from subroutines
@@ -908,8 +906,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
* (iAlloc() returns new, locked inode)
*/
ip = ialloc(dip, S_IFLNK | 0777);
- if (ip == NULL) {
- rc = -ENOSPC;
+ if (IS_ERR(ip)) {
+ rc = PTR_ERR(ip);
goto out2;
}
@@ -928,7 +926,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
tblk->u.ixpxd = JFS_IP(ip)->ixpxd;
/* fix symlink access permission
- * (dir_create() ANDs in the u.u_cmask,
+ * (dir_create() ANDs in the u.u_cmask,
* but symlinks really need to be 777 access)
*/
ip->i_mode |= 0777;
@@ -969,7 +967,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
ip->i_mapping->a_ops = &jfs_aops;
/*
- * even though the data of symlink object (source
+ * even though the data of symlink object (source
* path name) is treated as non-journaled user data,
* it is read/written thru buffer cache for performance.
*/
@@ -980,7 +978,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
xlen = xsize >> JFS_SBI(sb)->l2bsize;
if ((rc = xtInsert(tid, ip, 0, 0, xlen, &xaddr, 0))) {
txAbort(tid, 0);
- rc = -ENOSPC;
goto out3;
}
extent = xaddr;
@@ -1155,9 +1152,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
old_ip->i_ino, JFS_RENAME);
if (rc)
goto out4;
- new_ip->i_nlink--;
+ drop_nlink(new_ip);
if (S_ISDIR(new_ip->i_mode)) {
- new_ip->i_nlink--;
+ drop_nlink(new_ip);
if (new_ip->i_nlink) {
mutex_unlock(&JFS_IP(new_ip)->commit_mutex);
if (old_dir != new_dir)
@@ -1178,7 +1175,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* free block resources */
if ((new_size = commitZeroLink(tid, new_ip)) < 0) {
txAbort(tid, 1); /* Marks FS Dirty */
- rc = new_size;
+ rc = new_size;
goto out4;
}
tblk = tid_to_tblock(tid);
@@ -1208,7 +1205,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out4;
}
if (S_ISDIR(old_ip->i_mode))
- new_dir->i_nlink++;
+ inc_nlink(new_dir);
}
/*
* Remove old directory entry
@@ -1223,7 +1220,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out4;
}
if (S_ISDIR(old_ip->i_mode)) {
- old_dir->i_nlink--;
+ drop_nlink(old_dir);
if (old_dir != new_dir) {
/*
* Change inode number of parent for moved directory
@@ -1294,7 +1291,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
new_size = xtTruncate_pmap(tid, new_ip, new_size);
if (new_size < 0) {
txAbort(tid, 1);
- rc = new_size;
+ rc = new_size;
} else
rc = txCommit(tid, 1, &new_ip, COMMIT_SYNC);
txEnd(tid);
@@ -1352,8 +1349,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
goto out;
ip = ialloc(dir, mode);
- if (ip == NULL) {
- rc = -ENOSPC;
+ if (IS_ERR(ip)) {
+ rc = PTR_ERR(ip);
goto out1;
}
jfs_ip = JFS_IP(ip);
diff --git a/fs/jfs/resize.c b/fs/jfs/resize.c
index 45180361871c..79d625f3f733 100644
--- a/fs/jfs/resize.c
+++ b/fs/jfs/resize.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 143bcd1d5eaa..9c1c6e0e633d 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -82,7 +82,7 @@ static void jfs_handle_error(struct super_block *sb)
"as read-only\n",
sb->s_id);
sb->s_flags |= MS_RDONLY;
- }
+ }
/* nothing is done for continue beyond marking the superblock dirty */
}
@@ -422,7 +422,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
sbi = kzalloc(sizeof (struct jfs_sb_info), GFP_KERNEL);
if (!sbi)
- return -ENOSPC;
+ return -ENOMEM;
sb->s_fs_info = sbi;
sbi->sb = sb;
sbi->uid = sbi->gid = sbi->umask = -1;
@@ -775,7 +775,7 @@ static int __init init_jfs_fs(void)
int rc;
jfs_inode_cachep =
- kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
+ kmem_cache_create("jfs_ip", sizeof(struct jfs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
init_once, NULL);
if (jfs_inode_cachep == NULL)
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
index 16477b3835e1..cee43f36f51d 100644
--- a/fs/jfs/symlink.c
+++ b/fs/jfs/symlink.c
@@ -3,16 +3,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c
index 9bc5b7c055ce..4c7985ebca92 100644
--- a/fs/jfs/xattr.c
+++ b/fs/jfs/xattr.c
@@ -4,16 +4,16 @@
*
* 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
+ * 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
+ * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
@@ -57,7 +57,7 @@
*
* 0 4 4 + EA_SIZE(ea1)
* +------------+-------------------+--------------------+-----
- * | Overall EA | First FEA Element | Second FEA Element | .....
+ * | Overall EA | First FEA Element | Second FEA Element | .....
* | List Size | | |
* +------------+-------------------+--------------------+-----
*
@@ -97,26 +97,26 @@ static inline int is_os2_xattr(struct jfs_ea *ea)
*/
if ((ea->namelen >= XATTR_SYSTEM_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
- return FALSE;
+ return false;
/*
* Check for "user."
*/
if ((ea->namelen >= XATTR_USER_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
- return FALSE;
+ return false;
/*
* Check for "security."
*/
if ((ea->namelen >= XATTR_SECURITY_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_SECURITY_PREFIX,
XATTR_SECURITY_PREFIX_LEN))
- return FALSE;
+ return false;
/*
* Check for "trusted."
*/
if ((ea->namelen >= XATTR_TRUSTED_PREFIX_LEN) &&
!strncmp(ea->name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN))
- return FALSE;
+ return false;
/*
* Add any other valid namespace prefixes here
*/
@@ -124,7 +124,7 @@ static inline int is_os2_xattr(struct jfs_ea *ea)
/*
* We assume it's OS/2's flat namespace
*/
- return TRUE;
+ return true;
}
static inline int name_size(struct jfs_ea *ea)
@@ -155,9 +155,9 @@ static void ea_release(struct inode *inode, struct ea_buffer *ea_buf);
/*
* NAME: ea_write_inline
- *
+ *
* FUNCTION: Attempt to write an EA inline if area is available
- *
+ *
* PRE CONDITIONS:
* Already verified that the specified EA is small enough to fit inline
*
@@ -216,10 +216,10 @@ static int ea_write_inline(struct inode *ip, struct jfs_ea_list *ealist,
/*
* NAME: ea_write
- *
+ *
* FUNCTION: Write an EA for an inode
- *
- * PRE CONDITIONS: EA has been verified
+ *
+ * PRE CONDITIONS: EA has been verified
*
* PARAMETERS:
* ip - Inode pointer
@@ -340,9 +340,9 @@ static int ea_write(struct inode *ip, struct jfs_ea_list *ealist, int size,
/*
* NAME: ea_read_inline
- *
+ *
* FUNCTION: Read an inlined EA into user's buffer
- *
+ *
* PARAMETERS:
* ip - Inode pointer
* ealist - Pointer to buffer to fill in with EA
@@ -372,9 +372,9 @@ static int ea_read_inline(struct inode *ip, struct jfs_ea_list *ealist)
/*
* NAME: ea_read
- *
+ *
* FUNCTION: copy EA data into user's buffer
- *
+ *
* PARAMETERS:
* ip - Inode pointer
* ealist - Pointer to buffer to fill in with EA
@@ -406,7 +406,7 @@ static int ea_read(struct inode *ip, struct jfs_ea_list *ealist)
return -EIO;
}
- /*
+ /*
* Figure out how many blocks were allocated when this EA list was
* originally written to disk.
*/
@@ -443,14 +443,14 @@ static int ea_read(struct inode *ip, struct jfs_ea_list *ealist)
/*
* NAME: ea_get
- *
+ *
* FUNCTION: Returns buffer containing existing extended attributes.
* The size of the buffer will be the larger of the existing
* attributes size, or min_size.
*
* The buffer, which may be inlined in the inode or in the
- * page cache must be release by calling ea_release or ea_put
- *
+ * page cache must be release by calling ea_release or ea_put
+ *
* PARAMETERS:
* inode - Inode pointer
* ea_buf - Structure to be populated with ealist and its metadata
@@ -1054,7 +1054,7 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
/* compute required size of list */
for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) {
- if (can_list(ea))
+ if (can_list(ea))
size += name_size(ea) + 1;
}
@@ -1069,7 +1069,7 @@ ssize_t jfs_listxattr(struct dentry * dentry, char *data, size_t buf_size)
/* Copy attribute names to buffer */
buffer = data;
for (ea = FIRST_EA(ealist); ea < END_EALIST(ealist); ea = NEXT_EA(ea)) {
- if (can_list(ea)) {
+ if (can_list(ea)) {
int namelen = copy_name(buffer, ea);
buffer += namelen + 1;
}
diff --git a/fs/libfs.c b/fs/libfs.c
index ac02ea602c3d..bd08e0e64a8c 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -243,7 +243,7 @@ int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *den
struct inode *inode = old_dentry->d_inode;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- inode->i_nlink++;
+ inc_nlink(inode);
atomic_inc(&inode->i_count);
dget(dentry);
d_instantiate(dentry, inode);
@@ -275,7 +275,7 @@ int simple_unlink(struct inode *dir, struct dentry *dentry)
struct inode *inode = dentry->d_inode;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- inode->i_nlink--;
+ drop_nlink(inode);
dput(dentry);
return 0;
}
@@ -285,9 +285,9 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
if (!simple_empty(dentry))
return -ENOTEMPTY;
- dentry->d_inode->i_nlink--;
+ drop_nlink(dentry->d_inode);
simple_unlink(dir, dentry);
- dir->i_nlink--;
+ drop_nlink(dir);
return 0;
}
@@ -303,10 +303,10 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_dentry->d_inode) {
simple_unlink(new_dir, new_dentry);
if (they_are_dirs)
- old_dir->i_nlink--;
+ drop_nlink(old_dir);
} else if (they_are_dirs) {
- old_dir->i_nlink--;
- new_dir->i_nlink++;
+ drop_nlink(old_dir);
+ inc_nlink(new_dir);
}
old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime =
@@ -317,17 +317,9 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
int simple_readpage(struct file *file, struct page *page)
{
- void *kaddr;
-
- if (PageUptodate(page))
- goto out;
-
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr, 0, PAGE_CACHE_SIZE);
- kunmap_atomic(kaddr, KM_USER0);
+ clear_highpage(page);
flush_dcache_page(page);
SetPageUptodate(page);
-out:
unlock_page(page);
return 0;
}
@@ -383,7 +375,6 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
return -ENOMEM;
inode->i_mode = S_IFDIR | 0755;
inode->i_uid = inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &simple_dir_inode_operations;
@@ -405,7 +396,6 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
goto out;
inode->i_mode = S_IFREG | files->mode;
inode->i_uid = inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_fop = files->ops;
@@ -547,7 +537,7 @@ int simple_attr_open(struct inode *inode, struct file *file,
attr->get = get;
attr->set = set;
- attr->data = inode->u.generic_ip;
+ attr->data = inode->i_private;
attr->fmt = fmt;
mutex_init(&attr->mutex);
diff --git a/fs/lockd/clntlock.c b/fs/lockd/clntlock.c
index 52774feab93f..b85a0ad2cfb6 100644
--- a/fs/lockd/clntlock.c
+++ b/fs/lockd/clntlock.c
@@ -100,12 +100,12 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
/*
* The server lockd has called us back to tell us the lock was granted
*/
-u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
+__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
{
const struct file_lock *fl = &lock->fl;
const struct nfs_fh *fh = &lock->fh;
struct nlm_wait *block;
- u32 res = nlm_lck_denied;
+ __be32 res = nlm_lck_denied;
/*
* Look up blocked request based on arguments.
@@ -144,42 +144,12 @@ u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *lock)
*/
/*
- * Someone has sent us an SM_NOTIFY. Ensure we bind to the new port number,
- * that we mark locks for reclaiming, and that we bump the pseudo NSM state.
- */
-static void nlmclnt_prepare_reclaim(struct nlm_host *host)
-{
- down_write(&host->h_rwsem);
- host->h_monitored = 0;
- host->h_state++;
- host->h_nextrebind = 0;
- nlm_rebind_host(host);
-
- /*
- * Mark the locks for reclaiming.
- */
- list_splice_init(&host->h_granted, &host->h_reclaim);
-
- dprintk("NLM: reclaiming locks for host %s", host->h_name);
-}
-
-static void nlmclnt_finish_reclaim(struct nlm_host *host)
-{
- host->h_reclaiming = 0;
- up_write(&host->h_rwsem);
- dprintk("NLM: done reclaiming locks for host %s", host->h_name);
-}
-
-/*
* Reclaim all locks on server host. We do this by spawning a separate
* reclaimer thread.
*/
void
-nlmclnt_recovery(struct nlm_host *host, u32 newstate)
+nlmclnt_recovery(struct nlm_host *host)
{
- if (host->h_nsmstate == newstate)
- return;
- host->h_nsmstate = newstate;
if (!host->h_reclaiming++) {
nlm_get_host(host);
__module_get(THIS_MODULE);
@@ -199,18 +169,30 @@ reclaimer(void *ptr)
daemonize("%s-reclaim", host->h_name);
allow_signal(SIGKILL);
+ down_write(&host->h_rwsem);
+
/* This one ensures that our parent doesn't terminate while the
* reclaim is in progress */
lock_kernel();
- lockd_up();
+ lockd_up(0); /* note: this cannot fail as lockd is already running */
+
+ dprintk("lockd: reclaiming locks for host %s", host->h_name);
- nlmclnt_prepare_reclaim(host);
- /* First, reclaim all locks that have been marked. */
restart:
nsmstate = host->h_nsmstate;
+
+ /* Force a portmap getport - the peer's lockd will
+ * most likely end up on a different port.
+ */
+ host->h_nextrebind = jiffies;
+ nlm_rebind_host(host);
+
+ /* First, reclaim all locks that have been granted. */
+ list_splice_init(&host->h_granted, &host->h_reclaim);
list_for_each_entry_safe(fl, next, &host->h_reclaim, fl_u.nfs_fl.list) {
list_del_init(&fl->fl_u.nfs_fl.list);
+ /* Why are we leaking memory here? --okir */
if (signalled())
continue;
if (nlmclnt_reclaim(host, fl) != 0)
@@ -218,11 +200,13 @@ restart:
list_add_tail(&fl->fl_u.nfs_fl.list, &host->h_granted);
if (host->h_nsmstate != nsmstate) {
/* Argh! The server rebooted again! */
- list_splice_init(&host->h_granted, &host->h_reclaim);
goto restart;
}
}
- nlmclnt_finish_reclaim(host);
+
+ host->h_reclaiming = 0;
+ up_write(&host->h_rwsem);
+ dprintk("NLM: done reclaiming locks for host %s", host->h_name);
/* Now, wake up all processes that sleep on a blocked lock */
list_for_each_entry(block, &nlm_blocked, b_list) {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 50dbb67ae0c4..3d84f600b633 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -36,14 +36,14 @@ static const struct rpc_call_ops nlmclnt_cancel_ops;
/*
* Cookie counter for NLM requests
*/
-static u32 nlm_cookie = 0x1234;
+static atomic_t nlm_cookie = ATOMIC_INIT(0x1234);
-static inline void nlmclnt_next_cookie(struct nlm_cookie *c)
+void nlmclnt_next_cookie(struct nlm_cookie *c)
{
- memcpy(c->data, &nlm_cookie, 4);
- memset(c->data+4, 0, 4);
+ u32 cookie = atomic_inc_return(&nlm_cookie);
+
+ memcpy(c->data, &cookie, 4);
c->len=4;
- nlm_cookie++;
}
static struct nlm_lockowner *nlm_get_lockowner(struct nlm_lockowner *lockowner)
@@ -100,7 +100,7 @@ static struct nlm_lockowner *nlm_find_lockowner(struct nlm_host *host, fl_owner_
res = __nlm_find_lockowner(host, owner);
if (res == NULL) {
spin_unlock(&host->h_lock);
- new = (struct nlm_lockowner *)kmalloc(sizeof(*new), GFP_KERNEL);
+ new = kmalloc(sizeof(*new), GFP_KERNEL);
spin_lock(&host->h_lock);
res = __nlm_find_lockowner(host, owner);
if (res == NULL && new != NULL) {
@@ -129,11 +129,11 @@ static void nlmclnt_setlockargs(struct nlm_rqst *req, struct file_lock *fl)
nlmclnt_next_cookie(&argp->cookie);
argp->state = nsm_local_state;
memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh));
- lock->caller = system_utsname.nodename;
+ lock->caller = utsname()->nodename;
lock->oh.data = req->a_owner;
lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s",
(unsigned int)fl->fl_u.nfs_fl.owner->pid,
- system_utsname.nodename);
+ utsname()->nodename);
lock->svid = fl->fl_u.nfs_fl.owner->pid;
lock->fl.fl_start = fl->fl_start;
lock->fl.fl_end = fl->fl_end;
@@ -153,6 +153,7 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
{
struct rpc_clnt *client = NFS_CLIENT(inode);
struct sockaddr_in addr;
+ struct nfs_server *nfssrv = NFS_SERVER(inode);
struct nlm_host *host;
struct nlm_rqst *call;
sigset_t oldset;
@@ -166,7 +167,9 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
}
rpc_peeraddr(client, (struct sockaddr *) &addr, sizeof(addr));
- host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers);
+ host = nlmclnt_lookup_host(&addr, client->cl_xprt->prot, vers,
+ nfssrv->nfs_client->cl_hostname,
+ strlen(nfssrv->nfs_client->cl_hostname));
if (host == NULL)
return -ENOLCK;
@@ -499,7 +502,7 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
unsigned char fl_flags = fl->fl_flags;
int status = -ENOLCK;
- if (!host->h_monitored && nsm_monitor(host) < 0) {
+ if (nsm_monitor(host) < 0) {
printk(KERN_NOTICE "lockd: failed to monitor %s\n",
host->h_name);
goto out;
diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 703fb038c813..fb24a9730345 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -27,46 +27,60 @@
#define NLM_HOST_EXPIRE ((nrhosts > NLM_HOST_MAX)? 300 * HZ : 120 * HZ)
#define NLM_HOST_COLLECT ((nrhosts > NLM_HOST_MAX)? 120 * HZ : 60 * HZ)
-static struct nlm_host * nlm_hosts[NLM_HOST_NRHASH];
+static struct hlist_head nlm_hosts[NLM_HOST_NRHASH];
static unsigned long next_gc;
static int nrhosts;
static DEFINE_MUTEX(nlm_host_mutex);
static void nlm_gc_hosts(void);
+static struct nsm_handle * __nsm_find(const struct sockaddr_in *,
+ const char *, int, int);
/*
* Find an NLM server handle in the cache. If there is none, create it.
*/
struct nlm_host *
-nlmclnt_lookup_host(struct sockaddr_in *sin, int proto, int version)
+nlmclnt_lookup_host(const struct sockaddr_in *sin, int proto, int version,
+ const char *hostname, int hostname_len)
{
- return nlm_lookup_host(0, sin, proto, version);
+ return nlm_lookup_host(0, sin, proto, version,
+ hostname, hostname_len);
}
/*
* Find an NLM client handle in the cache. If there is none, create it.
*/
struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp)
+nlmsvc_lookup_host(struct svc_rqst *rqstp,
+ const char *hostname, int hostname_len)
{
return nlm_lookup_host(1, &rqstp->rq_addr,
- rqstp->rq_prot, rqstp->rq_vers);
+ rqstp->rq_prot, rqstp->rq_vers,
+ hostname, hostname_len);
}
/*
* Common host lookup routine for server & client
*/
struct nlm_host *
-nlm_lookup_host(int server, struct sockaddr_in *sin,
- int proto, int version)
+nlm_lookup_host(int server, const struct sockaddr_in *sin,
+ int proto, int version,
+ const char *hostname,
+ int hostname_len)
{
- struct nlm_host *host, **hp;
- u32 addr;
+ struct hlist_head *chain;
+ struct hlist_node *pos;
+ struct nlm_host *host;
+ struct nsm_handle *nsm = NULL;
int hash;
- dprintk("lockd: nlm_lookup_host(%08x, p=%d, v=%d)\n",
- (unsigned)(sin? ntohl(sin->sin_addr.s_addr) : 0), proto, version);
+ dprintk("lockd: nlm_lookup_host(%u.%u.%u.%u, p=%d, v=%d, my role=%s, name=%.*s)\n",
+ NIPQUAD(sin->sin_addr.s_addr), proto, version,
+ server? "server" : "client",
+ hostname_len,
+ hostname? hostname : "<none>");
+
hash = NLM_ADDRHASH(sin->sin_addr.s_addr);
@@ -76,7 +90,22 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
if (time_after_eq(jiffies, next_gc))
nlm_gc_hosts();
- for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
+ /* We may keep several nlm_host objects for a peer, because each
+ * nlm_host is identified by
+ * (address, protocol, version, server/client)
+ * We could probably simplify this a little by putting all those
+ * different NLM rpc_clients into one single nlm_host object.
+ * This would allow us to have one nlm_host per address.
+ */
+ chain = &nlm_hosts[hash];
+ hlist_for_each_entry(host, pos, chain, h_hash) {
+ if (!nlm_cmp_addr(&host->h_addr, sin))
+ continue;
+
+ /* See if we have an NSM handle for this client */
+ if (!nsm)
+ nsm = host->h_nsmhandle;
+
if (host->h_proto != proto)
continue;
if (host->h_version != version)
@@ -84,28 +113,30 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
if (host->h_server != server)
continue;
- if (nlm_cmp_addr(&host->h_addr, sin)) {
- if (hp != nlm_hosts + hash) {
- *hp = host->h_next;
- host->h_next = nlm_hosts[hash];
- nlm_hosts[hash] = host;
- }
- nlm_get_host(host);
- mutex_unlock(&nlm_host_mutex);
- return host;
- }
- }
+ /* Move to head of hash chain. */
+ hlist_del(&host->h_hash);
+ hlist_add_head(&host->h_hash, chain);
- /* Ooops, no host found, create it */
- dprintk("lockd: creating host entry\n");
+ nlm_get_host(host);
+ goto out;
+ }
+ if (nsm)
+ atomic_inc(&nsm->sm_count);
- if (!(host = (struct nlm_host *) kmalloc(sizeof(*host), GFP_KERNEL)))
- goto nohost;
- memset(host, 0, sizeof(*host));
+ host = NULL;
- addr = sin->sin_addr.s_addr;
- sprintf(host->h_name, "%u.%u.%u.%u", NIPQUAD(addr));
+ /* Sadly, the host isn't in our hash table yet. See if
+ * we have an NSM handle for it. If not, create one.
+ */
+ if (!nsm && !(nsm = nsm_find(sin, hostname, hostname_len)))
+ goto out;
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
+ if (!host) {
+ nsm_release(nsm);
+ goto out;
+ }
+ host->h_name = nsm->sm_name;
host->h_addr = *sin;
host->h_addr.sin_port = 0; /* ouch! */
host->h_version = version;
@@ -119,9 +150,9 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
init_rwsem(&host->h_rwsem);
host->h_state = 0; /* pseudo NSM state */
host->h_nsmstate = 0; /* real NSM state */
+ host->h_nsmhandle = nsm;
host->h_server = server;
- host->h_next = nlm_hosts[hash];
- nlm_hosts[hash] = host;
+ hlist_add_head(&host->h_hash, chain);
INIT_LIST_HEAD(&host->h_lockowners);
spin_lock_init(&host->h_lock);
INIT_LIST_HEAD(&host->h_granted);
@@ -130,35 +161,39 @@ nlm_lookup_host(int server, struct sockaddr_in *sin,
if (++nrhosts > NLM_HOST_MAX)
next_gc = 0;
-nohost:
+out:
mutex_unlock(&nlm_host_mutex);
return host;
}
-struct nlm_host *
-nlm_find_client(void)
+/*
+ * Destroy a host
+ */
+static void
+nlm_destroy_host(struct nlm_host *host)
{
- /* find a nlm_host for a client for which h_killed == 0.
- * and return it
+ struct rpc_clnt *clnt;
+
+ BUG_ON(!list_empty(&host->h_lockowners));
+ BUG_ON(atomic_read(&host->h_count));
+
+ /*
+ * Release NSM handle and unmonitor host.
*/
- int hash;
- mutex_lock(&nlm_host_mutex);
- for (hash = 0 ; hash < NLM_HOST_NRHASH; hash++) {
- struct nlm_host *host, **hp;
- for (hp = &nlm_hosts[hash]; (host = *hp) != 0; hp = &host->h_next) {
- if (host->h_server &&
- host->h_killed == 0) {
- nlm_get_host(host);
- mutex_unlock(&nlm_host_mutex);
- return host;
- }
+ nsm_unmonitor(host);
+
+ if ((clnt = host->h_rpcclnt) != NULL) {
+ if (atomic_read(&clnt->cl_users)) {
+ printk(KERN_WARNING
+ "lockd: active RPC handle\n");
+ clnt->cl_dead = 1;
+ } else {
+ rpc_destroy_client(host->h_rpcclnt);
}
}
- mutex_unlock(&nlm_host_mutex);
- return NULL;
+ kfree(host);
}
-
/*
* Create the NLM RPC client for an NLM peer
*/
@@ -260,22 +295,82 @@ void nlm_release_host(struct nlm_host *host)
}
/*
+ * We were notified that the host indicated by address &sin
+ * has rebooted.
+ * Release all resources held by that peer.
+ */
+void nlm_host_rebooted(const struct sockaddr_in *sin,
+ const char *hostname, int hostname_len,
+ u32 new_state)
+{
+ struct hlist_head *chain;
+ struct hlist_node *pos;
+ struct nsm_handle *nsm;
+ struct nlm_host *host;
+
+ dprintk("lockd: nlm_host_rebooted(%s, %u.%u.%u.%u)\n",
+ hostname, NIPQUAD(sin->sin_addr));
+
+ /* Find the NSM handle for this peer */
+ if (!(nsm = __nsm_find(sin, hostname, hostname_len, 0)))
+ return;
+
+ /* When reclaiming locks on this peer, make sure that
+ * we set up a new notification */
+ nsm->sm_monitored = 0;
+
+ /* Mark all hosts tied to this NSM state as having rebooted.
+ * We run the loop repeatedly, because we drop the host table
+ * lock for this.
+ * To avoid processing a host several times, we match the nsmstate.
+ */
+again: mutex_lock(&nlm_host_mutex);
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash) {
+ if (host->h_nsmhandle == nsm
+ && host->h_nsmstate != new_state) {
+ host->h_nsmstate = new_state;
+ host->h_state++;
+
+ nlm_get_host(host);
+ mutex_unlock(&nlm_host_mutex);
+
+ if (host->h_server) {
+ /* We're server for this guy, just ditch
+ * all the locks he held. */
+ nlmsvc_free_host_resources(host);
+ } else {
+ /* He's the server, initiate lock recovery. */
+ nlmclnt_recovery(host);
+ }
+
+ nlm_release_host(host);
+ goto again;
+ }
+ }
+ }
+
+ mutex_unlock(&nlm_host_mutex);
+}
+
+/*
* Shut down the hosts module.
* Note that this routine is called only at server shutdown time.
*/
void
nlm_shutdown_hosts(void)
{
+ struct hlist_head *chain;
+ struct hlist_node *pos;
struct nlm_host *host;
- int i;
dprintk("lockd: shutting down host module\n");
mutex_lock(&nlm_host_mutex);
/* First, make all hosts eligible for gc */
dprintk("lockd: nuking all hosts...\n");
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- for (host = nlm_hosts[i]; host; host = host->h_next)
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash)
host->h_expires = jiffies - 1;
}
@@ -287,8 +382,8 @@ nlm_shutdown_hosts(void)
if (nrhosts) {
printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
dprintk("lockd: %d hosts left:\n", nrhosts);
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- for (host = nlm_hosts[i]; host; host = host->h_next) {
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash) {
dprintk(" %s (cnt %d use %d exp %ld)\n",
host->h_name, atomic_read(&host->h_count),
host->h_inuse, host->h_expires);
@@ -305,45 +400,32 @@ nlm_shutdown_hosts(void)
static void
nlm_gc_hosts(void)
{
- struct nlm_host **q, *host;
- struct rpc_clnt *clnt;
- int i;
+ struct hlist_head *chain;
+ struct hlist_node *pos, *next;
+ struct nlm_host *host;
dprintk("lockd: host garbage collection\n");
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- for (host = nlm_hosts[i]; host; host = host->h_next)
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry(host, pos, chain, h_hash)
host->h_inuse = 0;
}
/* Mark all hosts that hold locks, blocks or shares */
nlmsvc_mark_resources();
- for (i = 0; i < NLM_HOST_NRHASH; i++) {
- q = &nlm_hosts[i];
- while ((host = *q) != NULL) {
+ for (chain = nlm_hosts; chain < nlm_hosts + NLM_HOST_NRHASH; ++chain) {
+ hlist_for_each_entry_safe(host, pos, next, chain, h_hash) {
if (atomic_read(&host->h_count) || host->h_inuse
|| time_before(jiffies, host->h_expires)) {
dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n",
host->h_name, atomic_read(&host->h_count),
host->h_inuse, host->h_expires);
- q = &host->h_next;
continue;
}
dprintk("lockd: delete host %s\n", host->h_name);
- *q = host->h_next;
- /* Don't unmonitor hosts that have been invalidated */
- if (host->h_monitored && !host->h_killed)
- nsm_unmonitor(host);
- if ((clnt = host->h_rpcclnt) != NULL) {
- if (atomic_read(&clnt->cl_users)) {
- printk(KERN_WARNING
- "lockd: active RPC handle\n");
- clnt->cl_dead = 1;
- } else {
- rpc_destroy_client(host->h_rpcclnt);
- }
- }
- kfree(host);
+ hlist_del_init(&host->h_hash);
+
+ nlm_destroy_host(host);
nrhosts--;
}
}
@@ -351,3 +433,88 @@ nlm_gc_hosts(void)
next_gc = jiffies + NLM_HOST_COLLECT;
}
+
+/*
+ * Manage NSM handles
+ */
+static LIST_HEAD(nsm_handles);
+static DEFINE_MUTEX(nsm_mutex);
+
+static struct nsm_handle *
+__nsm_find(const struct sockaddr_in *sin,
+ const char *hostname, int hostname_len,
+ int create)
+{
+ struct nsm_handle *nsm = NULL;
+ struct list_head *pos;
+
+ if (!sin)
+ return NULL;
+
+ if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
+ if (printk_ratelimit()) {
+ printk(KERN_WARNING "Invalid hostname \"%.*s\" "
+ "in NFS lock request\n",
+ hostname_len, hostname);
+ }
+ return NULL;
+ }
+
+ mutex_lock(&nsm_mutex);
+ list_for_each(pos, &nsm_handles) {
+ nsm = list_entry(pos, struct nsm_handle, sm_link);
+
+ if (hostname && nsm_use_hostnames) {
+ if (strlen(nsm->sm_name) != hostname_len
+ || memcmp(nsm->sm_name, hostname, hostname_len))
+ continue;
+ } else if (!nlm_cmp_addr(&nsm->sm_addr, sin))
+ continue;
+ atomic_inc(&nsm->sm_count);
+ goto out;
+ }
+
+ if (!create) {
+ nsm = NULL;
+ goto out;
+ }
+
+ nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
+ if (nsm != NULL) {
+ nsm->sm_addr = *sin;
+ nsm->sm_name = (char *) (nsm + 1);
+ memcpy(nsm->sm_name, hostname, hostname_len);
+ nsm->sm_name[hostname_len] = '\0';
+ atomic_set(&nsm->sm_count, 1);
+
+ list_add(&nsm->sm_link, &nsm_handles);
+ }
+
+out:
+ mutex_unlock(&nsm_mutex);
+ return nsm;
+}
+
+struct nsm_handle *
+nsm_find(const struct sockaddr_in *sin, const char *hostname, int hostname_len)
+{
+ return __nsm_find(sin, hostname, hostname_len, 1);
+}
+
+/*
+ * Release an NSM handle
+ */
+void
+nsm_release(struct nsm_handle *nsm)
+{
+ if (!nsm)
+ return;
+ if (atomic_dec_and_test(&nsm->sm_count)) {
+ mutex_lock(&nsm_mutex);
+ if (atomic_read(&nsm->sm_count) == 0) {
+ list_del(&nsm->sm_link);
+ kfree(nsm);
+ }
+ mutex_unlock(&nsm_mutex);
+ }
+}
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 5954dcb497e4..eb243edf8932 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -24,13 +24,13 @@ static struct rpc_program nsm_program;
/*
* Local NSM state
*/
-u32 nsm_local_state;
+int nsm_local_state;
/*
* Common procedure for SM_MON/SM_UNMON calls
*/
static int
-nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
+nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
{
struct rpc_clnt *clnt;
int status;
@@ -46,10 +46,11 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
goto out;
}
- args.addr = host->h_addr.sin_addr.s_addr;
- args.proto= (host->h_proto<<1) | host->h_server;
+ memset(&args, 0, sizeof(args));
+ args.mon_name = nsm->sm_name;
+ args.addr = nsm->sm_addr.sin_addr.s_addr;
args.prog = NLM_PROGRAM;
- args.vers = host->h_version;
+ args.vers = 3;
args.proc = NLMPROC_NSM_NOTIFY;
memset(res, 0, sizeof(*res));
@@ -70,17 +71,22 @@ nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
int
nsm_monitor(struct nlm_host *host)
{
+ struct nsm_handle *nsm = host->h_nsmhandle;
struct nsm_res res;
int status;
dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
+ BUG_ON(nsm == NULL);
- status = nsm_mon_unmon(host, SM_MON, &res);
+ if (nsm->sm_monitored)
+ return 0;
+
+ status = nsm_mon_unmon(nsm, SM_MON, &res);
if (status < 0 || res.status != 0)
printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
else
- host->h_monitored = 1;
+ nsm->sm_monitored = 1;
return status;
}
@@ -90,16 +96,26 @@ nsm_monitor(struct nlm_host *host)
int
nsm_unmonitor(struct nlm_host *host)
{
+ struct nsm_handle *nsm = host->h_nsmhandle;
struct nsm_res res;
- int status;
-
- dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
-
- status = nsm_mon_unmon(host, SM_UNMON, &res);
- if (status < 0)
- printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
- else
- host->h_monitored = 0;
+ int status = 0;
+
+ if (nsm == NULL)
+ return 0;
+ host->h_nsmhandle = NULL;
+
+ if (atomic_read(&nsm->sm_count) == 1
+ && nsm->sm_monitored && !nsm->sm_sticky) {
+ dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
+
+ status = nsm_mon_unmon(nsm, SM_UNMON, &res);
+ if (status < 0)
+ printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
+ host->h_name);
+ else
+ nsm->sm_monitored = 0;
+ }
+ nsm_release(nsm);
return status;
}
@@ -132,10 +148,10 @@ nsm_create(void)
* XDR functions for NSM.
*/
-static u32 *
-xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
+static __be32 *
+xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
{
- char buffer[20];
+ char buffer[20], *name;
/*
* Use the dotted-quad IP address of the remote host as
@@ -143,9 +159,14 @@ xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
* hostname first for whatever remote hostname it receives,
* so this works alright.
*/
- sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
- if (!(p = xdr_encode_string(p, buffer))
- || !(p = xdr_encode_string(p, system_utsname.nodename)))
+ if (nsm_use_hostnames) {
+ name = argp->mon_name;
+ } else {
+ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
+ name = buffer;
+ }
+ if (!(p = xdr_encode_string(p, name))
+ || !(p = xdr_encode_string(p, utsname()->nodename)))
return ERR_PTR(-EIO);
*p++ = htonl(argp->prog);
*p++ = htonl(argp->vers);
@@ -155,21 +176,23 @@ xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
}
static int
-xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
+xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
{
p = xdr_encode_common(rqstp, p, argp);
if (IS_ERR(p))
return PTR_ERR(p);
+
+ /* Surprise - there may even be room for an IPv6 address now */
*p++ = argp->addr;
- *p++ = argp->vers;
- *p++ = argp->proto;
+ *p++ = 0;
+ *p++ = 0;
*p++ = 0;
rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
return 0;
}
static int
-xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
+xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
{
p = xdr_encode_common(rqstp, p, argp);
if (IS_ERR(p))
@@ -179,7 +202,7 @@ xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
}
static int
-xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
+xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
{
resp->status = ntohl(*p++);
resp->state = ntohl(*p++);
@@ -189,7 +212,7 @@ xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
}
static int
-xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
+xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
{
resp->state = ntohl(*p++);
return 0;
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 9a991b52c647..634139232aaf 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -31,7 +31,9 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/sunrpc/svcsock.h>
+#include <net/ip.h>
#include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
#include <linux/nfs.h>
#define NLMDBG_FACILITY NLMDBG_SVC
@@ -46,6 +48,7 @@ EXPORT_SYMBOL(nlmsvc_ops);
static DEFINE_MUTEX(nlmsvc_mutex);
static unsigned int nlmsvc_users;
static pid_t nlmsvc_pid;
+static struct svc_serv *nlmsvc_serv;
int nlmsvc_grace_period;
unsigned long nlmsvc_timeout;
@@ -59,6 +62,7 @@ static DECLARE_WAIT_QUEUE_HEAD(lockd_exit);
static unsigned long nlm_grace_period;
static unsigned long nlm_timeout = LOCKD_DFLT_TIMEO;
static int nlm_udpport, nlm_tcpport;
+int nsm_use_hostnames = 0;
/*
* Constants needed for the sysctl interface.
@@ -96,7 +100,6 @@ static inline void clear_grace_period(void)
static void
lockd(struct svc_rqst *rqstp)
{
- struct svc_serv *serv = rqstp->rq_server;
int err = 0;
unsigned long grace_period_expire;
@@ -112,6 +115,7 @@ lockd(struct svc_rqst *rqstp)
* Let our maker know we're running.
*/
nlmsvc_pid = current->pid;
+ nlmsvc_serv = rqstp->rq_server;
complete(&lockd_start_done);
daemonize("lockd");
@@ -161,7 +165,7 @@ lockd(struct svc_rqst *rqstp)
* Find a socket with data available and call its
* recvfrom routine.
*/
- err = svc_recv(serv, rqstp, timeout);
+ err = svc_recv(rqstp, timeout);
if (err == -EAGAIN || err == -EINTR)
continue;
if (err < 0) {
@@ -174,7 +178,7 @@ lockd(struct svc_rqst *rqstp)
dprintk("lockd: request from %08x\n",
(unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr));
- svc_process(serv, rqstp);
+ svc_process(rqstp);
}
@@ -189,6 +193,7 @@ lockd(struct svc_rqst *rqstp)
nlmsvc_invalidate_all();
nlm_shutdown_hosts();
nlmsvc_pid = 0;
+ nlmsvc_serv = NULL;
} else
printk(KERN_DEBUG
"lockd: new process, skipping host shutdown\n");
@@ -205,54 +210,77 @@ lockd(struct svc_rqst *rqstp)
module_put_and_exit(0);
}
+
+static int find_socket(struct svc_serv *serv, int proto)
+{
+ struct svc_sock *svsk;
+ int found = 0;
+ list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
+ if (svsk->sk_sk->sk_protocol == proto) {
+ found = 1;
+ break;
+ }
+ return found;
+}
+
+static int make_socks(struct svc_serv *serv, int proto)
+{
+ /* Make any sockets that are needed but not present.
+ * If nlm_udpport or nlm_tcpport were set as module
+ * options, make those sockets unconditionally
+ */
+ static int warned;
+ int err = 0;
+ if (proto == IPPROTO_UDP || nlm_udpport)
+ if (!find_socket(serv, IPPROTO_UDP))
+ err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport);
+ if (err == 0 && (proto == IPPROTO_TCP || nlm_tcpport))
+ if (!find_socket(serv, IPPROTO_TCP))
+ err= svc_makesock(serv, IPPROTO_TCP, nlm_tcpport);
+ if (!err)
+ warned = 0;
+ else if (warned++ == 0)
+ printk(KERN_WARNING
+ "lockd_up: makesock failed, error=%d\n", err);
+ return err;
+}
+
/*
* Bring up the lockd process if it's not already up.
*/
int
-lockd_up(void)
+lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
{
- static int warned;
struct svc_serv * serv;
int error = 0;
mutex_lock(&nlmsvc_mutex);
/*
- * Unconditionally increment the user count ... this is
- * the number of clients who _want_ a lockd process.
- */
- nlmsvc_users++;
- /*
* Check whether we're already up and running.
*/
- if (nlmsvc_pid)
+ if (nlmsvc_pid) {
+ if (proto)
+ error = make_socks(nlmsvc_serv, proto);
goto out;
+ }
/*
* Sanity check: if there's no pid,
* we should be the first user ...
*/
- if (nlmsvc_users > 1)
+ if (nlmsvc_users)
printk(KERN_WARNING
"lockd_up: no pid, %d users??\n", nlmsvc_users);
error = -ENOMEM;
- serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE);
+ serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n");
goto out;
}
- if ((error = svc_makesock(serv, IPPROTO_UDP, nlm_udpport)) < 0
-#ifdef CONFIG_NFSD_TCP
- || (error = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport)) < 0
-#endif
- ) {
- if (warned++ == 0)
- printk(KERN_WARNING
- "lockd_up: makesock failed, error=%d\n", error);
+ if ((error = make_socks(serv, proto)) < 0)
goto destroy_and_out;
- }
- warned = 0;
/*
* Create the kernel thread and wait for it to start.
@@ -272,6 +300,8 @@ lockd_up(void)
destroy_and_out:
svc_destroy(serv);
out:
+ if (!error)
+ nlmsvc_users++;
mutex_unlock(&nlmsvc_mutex);
return error;
}
@@ -367,6 +397,22 @@ static ctl_table nlm_sysctls[] = {
.extra1 = (int *) &nlm_port_min,
.extra2 = (int *) &nlm_port_max,
},
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nsm_use_hostnames",
+ .data = &nsm_use_hostnames,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "nsm_local_state",
+ .data = &nsm_local_state,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec,
+ },
{ .ctl_name = 0 }
};
@@ -455,6 +501,7 @@ module_param_call(nlm_udpport, param_set_port, param_get_int,
&nlm_udpport, 0644);
module_param_call(nlm_tcpport, param_set_port, param_get_int,
&nlm_tcpport, 0644);
+module_param(nsm_use_hostnames, bool, 0644);
/*
* Initialising and terminating the module.
diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c
index a2dd9ccb9b32..0ce5c81ff507 100644
--- a/fs/lockd/svc4proc.c
+++ b/fs/lockd/svc4proc.c
@@ -24,22 +24,22 @@
/*
* Obtain client and file from arguments
*/
-static u32
+static __be32
nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_host **hostp, struct nlm_file **filp)
{
struct nlm_host *host = NULL;
struct nlm_file *file = NULL;
struct nlm_lock *lock = &argp->lock;
- u32 error = 0;
+ __be32 error = 0;
/* nfsd callbacks must have been installed for this procedure */
if (!nlmsvc_ops)
return nlm_lck_denied_nolocks;
/* Obtain host handle */
- if (!(host = nlmsvc_lookup_host(rqstp))
- || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+ if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
+ || (argp->monitor && nsm_monitor(host) < 0))
goto no_locks;
*hostp = host;
@@ -68,7 +68,7 @@ no_locks:
/*
* NULL: Test for presence of service
*/
-static int
+static __be32
nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
dprintk("lockd: NULL called\n");
@@ -78,7 +78,7 @@ nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
/*
* TEST: Check for conflicting lock
*/
-static int
+static __be32
nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -96,7 +96,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now check for conflicting locks */
resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
@@ -107,7 +107,7 @@ nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
}
-static int
+static __be32
nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -126,7 +126,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
#if 0
/* If supplied state doesn't match current state, we assume it's
@@ -150,7 +150,7 @@ nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
}
-static int
+static __be32
nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -169,7 +169,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Try to cancel request. */
resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
@@ -183,7 +183,7 @@ nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* UNLOCK: release a lock
*/
-static int
+static __be32
nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -202,7 +202,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to remove the lock */
resp->status = nlmsvc_unlock(file, &argp->lock);
@@ -217,7 +217,7 @@ nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
* GRANTED: A server calls us to tell that a process' lock request
* was granted
*/
-static int
+static __be32
nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -253,14 +253,16 @@ static const struct rpc_call_ops nlm4svc_callback_ops = {
* because we send the callback before the reply proper. I hope this
* doesn't break any clients.
*/
-static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
- int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
+static __be32 nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
+ __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
{
struct nlm_host *host;
struct nlm_rqst *call;
- int stat;
+ __be32 stat;
- host = nlmsvc_lookup_host(rqstp);
+ host = nlmsvc_lookup_host(rqstp,
+ argp->lock.caller,
+ argp->lock.len);
if (host == NULL)
return rpc_system_err;
@@ -280,35 +282,35 @@ static int nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *a
return rpc_success;
}
-static int nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: TEST_MSG called\n");
return nlm4svc_callback(rqstp, NLMPROC_TEST_RES, argp, nlm4svc_proc_test);
}
-static int nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: LOCK_MSG called\n");
return nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlm4svc_proc_lock);
}
-static int nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: CANCEL_MSG called\n");
return nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlm4svc_proc_cancel);
}
-static int nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: UNLOCK_MSG called\n");
return nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlm4svc_proc_unlock);
}
-static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: GRANTED_MSG called\n");
@@ -318,7 +320,7 @@ static int nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *arg
/*
* SHARE: create a DOS share or alter existing share.
*/
-static int
+static __be32
nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -337,7 +339,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to create the share */
resp->status = nlmsvc_share_file(host, file, argp);
@@ -351,7 +353,7 @@ nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* UNSHARE: Release a DOS share.
*/
-static int
+static __be32
nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -370,7 +372,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to lock the file */
resp->status = nlmsvc_unshare_file(host, file, argp);
@@ -384,7 +386,7 @@ nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* NM_LOCK: Create an unmonitored lock
*/
-static int
+static __be32
nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -397,7 +399,7 @@ nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* FREE_ALL: Release all locks and shares held by client
*/
-static int
+static __be32
nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
@@ -415,15 +417,11 @@ nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* SM_NOTIFY: private callback from statd (not part of official NLM proto)
*/
-static int
+static __be32
nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
void *resp)
{
struct sockaddr_in saddr = rqstp->rq_addr;
- int vers = argp->vers;
- int prot = argp->proto >> 1;
-
- struct nlm_host *host;
dprintk("lockd: SM_NOTIFY called\n");
if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
@@ -438,28 +436,17 @@ nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
/* Obtain the host pointer for this NFS server and try to
* reclaim all locks we hold on this server.
*/
+ memset(&saddr, 0, sizeof(saddr));
saddr.sin_addr.s_addr = argp->addr;
+ nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
- if ((argp->proto & 1)==0) {
- if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
- nlmclnt_recovery(host, argp->state);
- nlm_release_host(host);
- }
- } else {
- /* If we run on an NFS server, delete all locks held by the client */
-
- if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
- nlmsvc_free_host_resources(host);
- nlm_release_host(host);
- }
- }
return rpc_success;
}
/*
* client sent a GRANTED_RES, let's remove the associated block
*/
-static int
+static __be32
nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
void *resp)
{
@@ -468,7 +455,7 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
dprintk("lockd: GRANTED_RES called\n");
- nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+ nlmsvc_grant_reply(&argp->cookie, argp->status);
return rpc_success;
}
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index c9d419703cf3..7e219b938552 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -40,7 +40,7 @@
static void nlmsvc_release_block(struct nlm_block *block);
static void nlmsvc_insert_block(struct nlm_block *block, unsigned long);
-static int nlmsvc_remove_block(struct nlm_block *block);
+static void nlmsvc_remove_block(struct nlm_block *block);
static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock);
static void nlmsvc_freegrantargs(struct nlm_rqst *call);
@@ -49,7 +49,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops;
/*
* The list of blocked locks to retry
*/
-static struct nlm_block * nlm_blocked;
+static LIST_HEAD(nlm_blocked);
/*
* Insert a blocked lock into the global list
@@ -57,48 +57,44 @@ static struct nlm_block * nlm_blocked;
static void
nlmsvc_insert_block(struct nlm_block *block, unsigned long when)
{
- struct nlm_block **bp, *b;
+ struct nlm_block *b;
+ struct list_head *pos;
dprintk("lockd: nlmsvc_insert_block(%p, %ld)\n", block, when);
- kref_get(&block->b_count);
- if (block->b_queued)
- nlmsvc_remove_block(block);
- bp = &nlm_blocked;
+ if (list_empty(&block->b_list)) {
+ kref_get(&block->b_count);
+ } else {
+ list_del_init(&block->b_list);
+ }
+
+ pos = &nlm_blocked;
if (when != NLM_NEVER) {
if ((when += jiffies) == NLM_NEVER)
when ++;
- while ((b = *bp) && time_before_eq(b->b_when,when) && b->b_when != NLM_NEVER)
- bp = &b->b_next;
- } else
- while ((b = *bp) != 0)
- bp = &b->b_next;
+ list_for_each(pos, &nlm_blocked) {
+ b = list_entry(pos, struct nlm_block, b_list);
+ if (time_after(b->b_when,when) || b->b_when == NLM_NEVER)
+ break;
+ }
+ /* On normal exit from the loop, pos == &nlm_blocked,
+ * so we will be adding to the end of the list - good
+ */
+ }
- block->b_queued = 1;
+ list_add_tail(&block->b_list, pos);
block->b_when = when;
- block->b_next = b;
- *bp = block;
}
/*
* Remove a block from the global list
*/
-static int
+static inline void
nlmsvc_remove_block(struct nlm_block *block)
{
- struct nlm_block **bp, *b;
-
- if (!block->b_queued)
- return 1;
- for (bp = &nlm_blocked; (b = *bp) != 0; bp = &b->b_next) {
- if (b == block) {
- *bp = block->b_next;
- block->b_queued = 0;
- nlmsvc_release_block(block);
- return 1;
- }
+ if (!list_empty(&block->b_list)) {
+ list_del_init(&block->b_list);
+ nlmsvc_release_block(block);
}
-
- return 0;
}
/*
@@ -107,14 +103,14 @@ nlmsvc_remove_block(struct nlm_block *block)
static struct nlm_block *
nlmsvc_lookup_block(struct nlm_file *file, struct nlm_lock *lock)
{
- struct nlm_block **head, *block;
+ struct nlm_block *block;
struct file_lock *fl;
dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %Ld-%Ld ty=%d\n",
file, lock->fl.fl_pid,
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end, lock->fl.fl_type);
- for (head = &nlm_blocked; (block = *head) != 0; head = &block->b_next) {
+ list_for_each_entry(block, &nlm_blocked, b_list) {
fl = &block->b_call->a_args.lock.fl;
dprintk("lockd: check f=%p pd=%d %Ld-%Ld ty=%d cookie=%s\n",
block->b_file, fl->fl_pid,
@@ -143,20 +139,20 @@ static inline int nlm_cookie_match(struct nlm_cookie *a, struct nlm_cookie *b)
* Find a block with a given NLM cookie.
*/
static inline struct nlm_block *
-nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
+nlmsvc_find_block(struct nlm_cookie *cookie)
{
struct nlm_block *block;
- for (block = nlm_blocked; block; block = block->b_next) {
- dprintk("cookie: head of blocked queue %p, block %p\n",
- nlm_blocked, block);
- if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie)
- && nlm_cmp_addr(sin, &block->b_host->h_addr))
- break;
+ list_for_each_entry(block, &nlm_blocked, b_list) {
+ if (nlm_cookie_match(&block->b_call->a_args.cookie,cookie))
+ goto found;
}
- if (block != NULL)
- kref_get(&block->b_count);
+ return NULL;
+
+found:
+ dprintk("nlmsvc_find_block(%s): block=%p\n", nlmdbg_cookie2a(cookie), block);
+ kref_get(&block->b_count);
return block;
}
@@ -169,6 +165,11 @@ nlmsvc_find_block(struct nlm_cookie *cookie, struct sockaddr_in *sin)
* request, but (as I found out later) that's because some implementations
* do just this. Never mind the standards comittees, they support our
* logging industries.
+ *
+ * 10 years later: I hope we can safely ignore these old and broken
+ * clients by now. Let's fix this so we can uniquely identify an incoming
+ * GRANTED_RES message by cookie, without having to rely on the client's IP
+ * address. --okir
*/
static inline struct nlm_block *
nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
@@ -179,7 +180,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_rqst *call = NULL;
/* Create host handle for callback */
- host = nlmsvc_lookup_host(rqstp);
+ host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len);
if (host == NULL)
return NULL;
@@ -192,6 +193,8 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
if (block == NULL)
goto failed;
kref_init(&block->b_count);
+ INIT_LIST_HEAD(&block->b_list);
+ INIT_LIST_HEAD(&block->b_flist);
if (!nlmsvc_setgrantargs(call, lock))
goto failed_free;
@@ -199,7 +202,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
/* Set notifier function for VFS, and init args */
call->a_args.lock.fl.fl_flags |= FL_SLEEP;
call->a_args.lock.fl.fl_lmops = &nlmsvc_lock_operations;
- call->a_args.cookie = *cookie; /* see above */
+ nlmclnt_next_cookie(&call->a_args.cookie);
dprintk("lockd: created block %p...\n", block);
@@ -210,8 +213,7 @@ nlmsvc_create_block(struct svc_rqst *rqstp, struct nlm_file *file,
file->f_count++;
/* Add to file's list of blocks */
- block->b_fnext = file->f_blocks;
- file->f_blocks = block;
+ list_add(&block->b_flist, &file->f_blocks);
/* Set up RPC arguments for callback */
block->b_call = call;
@@ -248,19 +250,13 @@ static void nlmsvc_free_block(struct kref *kref)
{
struct nlm_block *block = container_of(kref, struct nlm_block, b_count);
struct nlm_file *file = block->b_file;
- struct nlm_block **bp;
dprintk("lockd: freeing block %p...\n", block);
- down(&file->f_sema);
/* Remove block from file's list of blocks */
- for (bp = &file->f_blocks; *bp; bp = &(*bp)->b_fnext) {
- if (*bp == block) {
- *bp = block->b_fnext;
- break;
- }
- }
- up(&file->f_sema);
+ mutex_lock(&file->f_mutex);
+ list_del_init(&block->b_flist);
+ mutex_unlock(&file->f_mutex);
nlmsvc_freegrantargs(block->b_call);
nlm_release_call(block->b_call);
@@ -274,47 +270,32 @@ static void nlmsvc_release_block(struct nlm_block *block)
kref_put(&block->b_count, nlmsvc_free_block);
}
-static void nlmsvc_act_mark(struct nlm_host *host, struct nlm_file *file)
-{
- struct nlm_block *block;
-
- down(&file->f_sema);
- for (block = file->f_blocks; block != NULL; block = block->b_fnext)
- block->b_host->h_inuse = 1;
- up(&file->f_sema);
-}
-
-static void nlmsvc_act_unlock(struct nlm_host *host, struct nlm_file *file)
+/*
+ * Loop over all blocks and delete blocks held by
+ * a matching host.
+ */
+void nlmsvc_traverse_blocks(struct nlm_host *host,
+ struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
- struct nlm_block *block;
+ struct nlm_block *block, *next;
restart:
- down(&file->f_sema);
- for (block = file->f_blocks; block != NULL; block = block->b_fnext) {
- if (host != NULL && host != block->b_host)
+ mutex_lock(&file->f_mutex);
+ list_for_each_entry_safe(block, next, &file->f_blocks, b_flist) {
+ if (!match(block->b_host, host))
continue;
- if (!block->b_queued)
+ /* Do not destroy blocks that are not on
+ * the global retry list - why? */
+ if (list_empty(&block->b_list))
continue;
kref_get(&block->b_count);
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
goto restart;
}
- up(&file->f_sema);
-}
-
-/*
- * Loop over all blocks and perform the action specified.
- * (NLM_ACT_CHECK handled by nlmsvc_inspect_file).
- */
-void
-nlmsvc_traverse_blocks(struct nlm_host *host, struct nlm_file *file, int action)
-{
- if (action == NLM_ACT_MARK)
- nlmsvc_act_mark(host, file);
- else
- nlmsvc_act_unlock(host, file);
+ mutex_unlock(&file->f_mutex);
}
/*
@@ -325,7 +306,7 @@ static int nlmsvc_setgrantargs(struct nlm_rqst *call, struct nlm_lock *lock)
{
locks_copy_lock(&call->a_args.lock.fl, &lock->fl);
memcpy(&call->a_args.lock.fh, &lock->fh, sizeof(call->a_args.lock.fh));
- call->a_args.lock.caller = system_utsname.nodename;
+ call->a_args.lock.caller = utsname()->nodename;
call->a_args.lock.oh.len = lock->oh.len;
/* set default data area */
@@ -353,13 +334,13 @@ static void nlmsvc_freegrantargs(struct nlm_rqst *call)
* Attempt to establish a lock, and if it can't be granted, block it
* if required.
*/
-u32
+__be32
nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
struct nlm_lock *lock, int wait, struct nlm_cookie *cookie)
{
struct nlm_block *block, *newblock = NULL;
int error;
- u32 ret;
+ __be32 ret;
dprintk("lockd: nlmsvc_lock(%s/%ld, ty=%d, pi=%d, %Ld-%Ld, bl=%d)\n",
file->f_file->f_dentry->d_inode->i_sb->s_id,
@@ -373,7 +354,7 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
lock->fl.fl_flags &= ~FL_SLEEP;
again:
/* Lock file against concurrent access */
- down(&file->f_sema);
+ mutex_lock(&file->f_mutex);
/* Get existing block (in case client is busy-waiting) */
block = nlmsvc_lookup_block(file, lock);
if (block == NULL) {
@@ -411,10 +392,10 @@ again:
/* If we don't have a block, create and initialize it. Then
* retry because we may have slept in kmalloc. */
- /* We have to release f_sema as nlmsvc_create_block may try to
+ /* We have to release f_mutex as nlmsvc_create_block may try to
* to claim it while doing host garbage collection */
if (newblock == NULL) {
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
dprintk("lockd: blocking on this lock (allocating).\n");
if (!(newblock = nlmsvc_create_block(rqstp, file, lock, cookie)))
return nlm_lck_denied_nolocks;
@@ -424,7 +405,7 @@ again:
/* Append to list of blocked */
nlmsvc_insert_block(newblock, NLM_NEVER);
out:
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
nlmsvc_release_block(newblock);
nlmsvc_release_block(block);
dprintk("lockd: nlmsvc_lock returned %u\n", ret);
@@ -434,7 +415,7 @@ out:
/*
* Test for presence of a conflicting lock.
*/
-u32
+__be32
nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
struct nlm_lock *conflock)
{
@@ -451,6 +432,7 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
(long long)conflock->fl.fl_start,
(long long)conflock->fl.fl_end);
conflock->caller = "somehost"; /* FIXME */
+ conflock->len = strlen(conflock->caller);
conflock->oh.len = 0; /* don't return OH info */
conflock->svid = conflock->fl.fl_pid;
return nlm_lck_denied;
@@ -466,7 +448,7 @@ nlmsvc_testlock(struct nlm_file *file, struct nlm_lock *lock,
* afterwards. In this case the block will still be there, and hence
* must be removed.
*/
-u32
+__be32
nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
{
int error;
@@ -494,7 +476,7 @@ nlmsvc_unlock(struct nlm_file *file, struct nlm_lock *lock)
* be in progress.
* The calling procedure must check whether the file can be closed.
*/
-u32
+__be32
nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
{
struct nlm_block *block;
@@ -507,9 +489,9 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
(long long)lock->fl.fl_start,
(long long)lock->fl.fl_end);
- down(&file->f_sema);
+ mutex_lock(&file->f_mutex);
block = nlmsvc_lookup_block(file, lock);
- up(&file->f_sema);
+ mutex_unlock(&file->f_mutex);
if (block != NULL) {
status = nlmsvc_unlink_block(block);
nlmsvc_release_block(block);
@@ -527,10 +509,10 @@ nlmsvc_cancel_blocked(struct nlm_file *file, struct nlm_lock *lock)
static void
nlmsvc_notify_blocked(struct file_lock *fl)
{
- struct nlm_block **bp, *block;
+ struct nlm_block *block;
dprintk("lockd: VFS unblock notification for block %p\n", fl);
- for (bp = &nlm_blocked; (block = *bp) != 0; bp = &block->b_next) {
+ list_for_each_entry(block, &nlm_blocked, b_list) {
if (nlm_compare_locks(&block->b_call->a_args.lock.fl, fl)) {
nlmsvc_insert_block(block, 0);
svc_wake_up(block->b_daemon);
@@ -663,17 +645,14 @@ static const struct rpc_call_ops nlmsvc_grant_ops = {
* block.
*/
void
-nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status)
+nlmsvc_grant_reply(struct nlm_cookie *cookie, u32 status)
{
struct nlm_block *block;
- struct nlm_file *file;
- dprintk("grant_reply: looking for cookie %x, host (%08x), s=%d \n",
- *(unsigned int *)(cookie->data),
- ntohl(rqstp->rq_addr.sin_addr.s_addr), status);
- if (!(block = nlmsvc_find_block(cookie, &rqstp->rq_addr)))
+ dprintk("grant_reply: looking for cookie %x, s=%d \n",
+ *(unsigned int *)(cookie->data), status);
+ if (!(block = nlmsvc_find_block(cookie)))
return;
- file = block->b_file;
if (block) {
if (status == NLM_LCK_DENIED_GRACE_PERIOD) {
@@ -696,16 +675,19 @@ nlmsvc_grant_reply(struct svc_rqst *rqstp, struct nlm_cookie *cookie, u32 status
unsigned long
nlmsvc_retry_blocked(void)
{
- struct nlm_block *block;
+ unsigned long timeout = MAX_SCHEDULE_TIMEOUT;
+ struct nlm_block *block;
+
+ while (!list_empty(&nlm_blocked)) {
+ block = list_entry(nlm_blocked.next, struct nlm_block, b_list);
- dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
- nlm_blocked,
- nlm_blocked? nlm_blocked->b_when : 0);
- while ((block = nlm_blocked) != 0) {
if (block->b_when == NLM_NEVER)
break;
- if (time_after(block->b_when,jiffies))
+ if (time_after(block->b_when,jiffies)) {
+ timeout = block->b_when - jiffies;
break;
+ }
+
dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
block, block->b_when);
kref_get(&block->b_count);
@@ -713,8 +695,5 @@ nlmsvc_retry_blocked(void)
nlmsvc_release_block(block);
}
- if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
- return (block->b_when - jiffies);
-
- return MAX_SCHEDULE_TIMEOUT;
+ return timeout;
}
diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c
index dbb66a3b5cd9..32e99a6e8dca 100644
--- a/fs/lockd/svcproc.c
+++ b/fs/lockd/svcproc.c
@@ -22,8 +22,8 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT
#ifdef CONFIG_LOCKD_V4
-static u32
-cast_to_nlm(u32 status, u32 vers)
+static __be32
+cast_to_nlm(__be32 status, u32 vers)
{
/* Note: status is assumed to be in network byte order !!! */
if (vers != 4){
@@ -52,22 +52,22 @@ cast_to_nlm(u32 status, u32 vers)
/*
* Obtain client and file from arguments
*/
-static u32
+static __be32
nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_host **hostp, struct nlm_file **filp)
{
struct nlm_host *host = NULL;
struct nlm_file *file = NULL;
struct nlm_lock *lock = &argp->lock;
- u32 error;
+ __be32 error = 0;
/* nfsd callbacks must have been installed for this procedure */
if (!nlmsvc_ops)
return nlm_lck_denied_nolocks;
/* Obtain host handle */
- if (!(host = nlmsvc_lookup_host(rqstp))
- || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+ if (!(host = nlmsvc_lookup_host(rqstp, lock->caller, lock->len))
+ || (argp->monitor && nsm_monitor(host) < 0))
goto no_locks;
*hostp = host;
@@ -88,13 +88,15 @@ nlmsvc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
no_locks:
if (host)
nlm_release_host(host);
+ if (error)
+ return error;
return nlm_lck_denied_nolocks;
}
/*
* NULL: Test for presence of service
*/
-static int
+static __be32
nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
dprintk("lockd: NULL called\n");
@@ -104,7 +106,7 @@ nlmsvc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
/*
* TEST: Check for conflicting lock
*/
-static int
+static __be32
nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -122,7 +124,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now check for conflicting locks */
resp->status = cast_status(nlmsvc_testlock(file, &argp->lock, &resp->lock));
@@ -134,7 +136,7 @@ nlmsvc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
}
-static int
+static __be32
nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -153,7 +155,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
#if 0
/* If supplied state doesn't match current state, we assume it's
@@ -177,7 +179,7 @@ nlmsvc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
return rpc_success;
}
-static int
+static __be32
nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -196,7 +198,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Try to cancel request. */
resp->status = cast_status(nlmsvc_cancel_blocked(file, &argp->lock));
@@ -210,7 +212,7 @@ nlmsvc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* UNLOCK: release a lock
*/
-static int
+static __be32
nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -229,7 +231,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to remove the lock */
resp->status = cast_status(nlmsvc_unlock(file, &argp->lock));
@@ -244,7 +246,7 @@ nlmsvc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
* GRANTED: A server calls us to tell that a process' lock request
* was granted
*/
-static int
+static __be32
nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -280,14 +282,16 @@ static const struct rpc_call_ops nlmsvc_callback_ops = {
* because we send the callback before the reply proper. I hope this
* doesn't break any clients.
*/
-static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
- int (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
+static __be32 nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *argp,
+ __be32 (*func)(struct svc_rqst *, struct nlm_args *, struct nlm_res *))
{
struct nlm_host *host;
struct nlm_rqst *call;
- int stat;
+ __be32 stat;
- host = nlmsvc_lookup_host(rqstp);
+ host = nlmsvc_lookup_host(rqstp,
+ argp->lock.caller,
+ argp->lock.len);
if (host == NULL)
return rpc_system_err;
@@ -307,28 +311,28 @@ static int nlmsvc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_args *ar
return rpc_success;
}
-static int nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlmsvc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: TEST_MSG called\n");
return nlmsvc_callback(rqstp, NLMPROC_TEST_RES, argp, nlmsvc_proc_test);
}
-static int nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlmsvc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: LOCK_MSG called\n");
return nlmsvc_callback(rqstp, NLMPROC_LOCK_RES, argp, nlmsvc_proc_lock);
}
-static int nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+static __be32 nlmsvc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
dprintk("lockd: CANCEL_MSG called\n");
return nlmsvc_callback(rqstp, NLMPROC_CANCEL_RES, argp, nlmsvc_proc_cancel);
}
-static int
+static __be32
nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
@@ -336,7 +340,7 @@ nlmsvc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
return nlmsvc_callback(rqstp, NLMPROC_UNLOCK_RES, argp, nlmsvc_proc_unlock);
}
-static int
+static __be32
nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
@@ -347,7 +351,7 @@ nlmsvc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* SHARE: create a DOS share or alter existing share.
*/
-static int
+static __be32
nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -366,7 +370,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to create the share */
resp->status = cast_status(nlmsvc_share_file(host, file, argp));
@@ -380,7 +384,7 @@ nlmsvc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* UNSHARE: Release a DOS share.
*/
-static int
+static __be32
nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -399,7 +403,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
/* Obtain client and file */
if ((resp->status = nlmsvc_retrieve_args(rqstp, argp, &host, &file)))
- return rpc_success;
+ return resp->status == nlm_drop_reply ? rpc_drop_reply :rpc_success;
/* Now try to unshare the file */
resp->status = cast_status(nlmsvc_unshare_file(host, file, argp));
@@ -413,7 +417,7 @@ nlmsvc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* NM_LOCK: Create an unmonitored lock
*/
-static int
+static __be32
nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
struct nlm_res *resp)
{
@@ -426,7 +430,7 @@ nlmsvc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* FREE_ALL: Release all locks and shares held by client
*/
-static int
+static __be32
nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
void *resp)
{
@@ -444,14 +448,11 @@ nlmsvc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
/*
* SM_NOTIFY: private callback from statd (not part of official NLM proto)
*/
-static int
+static __be32
nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
void *resp)
{
struct sockaddr_in saddr = rqstp->rq_addr;
- int vers = argp->vers;
- int prot = argp->proto >> 1;
- struct nlm_host *host;
dprintk("lockd: SM_NOTIFY called\n");
if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
@@ -466,19 +467,9 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
/* Obtain the host pointer for this NFS server and try to
* reclaim all locks we hold on this server.
*/
+ memset(&saddr, 0, sizeof(saddr));
saddr.sin_addr.s_addr = argp->addr;
- if ((argp->proto & 1)==0) {
- if ((host = nlmclnt_lookup_host(&saddr, prot, vers)) != NULL) {
- nlmclnt_recovery(host, argp->state);
- nlm_release_host(host);
- }
- } else {
- /* If we run on an NFS server, delete all locks held by the client */
- if ((host = nlm_lookup_host(1, &saddr, prot, vers)) != NULL) {
- nlmsvc_free_host_resources(host);
- nlm_release_host(host);
- }
- }
+ nlm_host_rebooted(&saddr, argp->mon, argp->len, argp->state);
return rpc_success;
}
@@ -486,7 +477,7 @@ nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
/*
* client sent a GRANTED_RES, let's remove the associated block
*/
-static int
+static __be32
nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
void *resp)
{
@@ -495,7 +486,7 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp, struct nlm_res *argp,
dprintk("lockd: GRANTED_RES called\n");
- nlmsvc_grant_reply(rqstp, &argp->cookie, argp->status);
+ nlmsvc_grant_reply(&argp->cookie, argp->status);
return rpc_success;
}
diff --git a/fs/lockd/svcshare.c b/fs/lockd/svcshare.c
index 27288c83da96..6220dc2a3f2c 100644
--- a/fs/lockd/svcshare.c
+++ b/fs/lockd/svcshare.c
@@ -23,7 +23,7 @@ nlm_cmp_owner(struct nlm_share *share, struct xdr_netobj *oh)
&& !memcmp(share->s_owner.data, oh->data, oh->len);
}
-u32
+__be32
nlmsvc_share_file(struct nlm_host *host, struct nlm_file *file,
struct nlm_args *argp)
{
@@ -64,7 +64,7 @@ update:
/*
* Delete a share.
*/
-u32
+__be32
nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
struct nlm_args *argp)
{
@@ -85,24 +85,20 @@ nlmsvc_unshare_file(struct nlm_host *host, struct nlm_file *file,
}
/*
- * Traverse all shares for a given file (and host).
- * NLM_ACT_CHECK is handled by nlmsvc_inspect_file.
+ * Traverse all shares for a given file, and delete
+ * those owned by the given (type of) host
*/
-void
-nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file, int action)
+void nlmsvc_traverse_shares(struct nlm_host *host, struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
struct nlm_share *share, **shpp;
shpp = &file->f_shares;
while ((share = *shpp) != NULL) {
- if (action == NLM_ACT_MARK)
- share->s_host->h_inuse = 1;
- else if (action == NLM_ACT_UNLOCK) {
- if (host == NULL || host == share->s_host) {
- *shpp = share->s_next;
- kfree(share);
- continue;
- }
+ if (match(share->s_host, host)) {
+ *shpp = share->s_next;
+ kfree(share);
+ continue;
}
shpp = &share->s_next;
}
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index 01b4db9e5466..e83024e16042 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -25,9 +25,9 @@
/*
* Global file hash table
*/
-#define FILE_HASH_BITS 5
+#define FILE_HASH_BITS 7
#define FILE_NRHASH (1<<FILE_HASH_BITS)
-static struct nlm_file * nlm_files[FILE_NRHASH];
+static struct hlist_head nlm_files[FILE_NRHASH];
static DEFINE_MUTEX(nlm_file_mutex);
#ifdef NFSD_DEBUG
@@ -78,13 +78,14 @@ static inline unsigned int file_hash(struct nfs_fh *f)
* This is not quite right, but for now, we assume the client performs
* the proper R/W checking.
*/
-u32
+__be32
nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
struct nfs_fh *f)
{
+ struct hlist_node *pos;
struct nlm_file *file;
unsigned int hash;
- u32 nfserr;
+ __be32 nfserr;
nlm_debug_print_fh("nlm_file_lookup", f);
@@ -93,21 +94,21 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
/* Lock file table */
mutex_lock(&nlm_file_mutex);
- for (file = nlm_files[hash]; file; file = file->f_next)
+ hlist_for_each_entry(file, pos, &nlm_files[hash], f_list)
if (!nfs_compare_fh(&file->f_handle, f))
goto found;
nlm_debug_print_fh("creating file for", f);
nfserr = nlm_lck_denied_nolocks;
- file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL);
+ file = kzalloc(sizeof(*file), GFP_KERNEL);
if (!file)
goto out_unlock;
- memset(file, 0, sizeof(*file));
memcpy(&file->f_handle, f, sizeof(struct nfs_fh));
- file->f_hash = hash;
- init_MUTEX(&file->f_sema);
+ mutex_init(&file->f_mutex);
+ INIT_HLIST_NODE(&file->f_list);
+ INIT_LIST_HEAD(&file->f_blocks);
/* Open the file. Note that this must not sleep for too long, else
* we would lock up lockd:-) So no NFS re-exports, folks.
@@ -116,12 +117,11 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
* the file.
*/
if ((nfserr = nlmsvc_ops->fopen(rqstp, f, &file->f_file)) != 0) {
- dprintk("lockd: open failed (nfserr %d)\n", ntohl(nfserr));
+ dprintk("lockd: open failed (error %d)\n", nfserr);
goto out_free;
}
- file->f_next = nlm_files[hash];
- nlm_files[hash] = file;
+ hlist_add_head(&file->f_list, &nlm_files[hash]);
found:
dprintk("lockd: found file %p (count %d)\n", file, file->f_count);
@@ -135,12 +135,6 @@ out_unlock:
out_free:
kfree(file);
-#ifdef CONFIG_LOCKD_V4
- if (nfserr == 1)
- nfserr = nlm4_stale_fh;
- else
-#endif
- nfserr = nlm_lck_denied;
goto out_unlock;
}
@@ -150,22 +144,14 @@ out_free:
static inline void
nlm_delete_file(struct nlm_file *file)
{
- struct nlm_file **fp, *f;
-
nlm_debug_print_file("closing file", file);
-
- fp = nlm_files + file->f_hash;
- while ((f = *fp) != NULL) {
- if (f == file) {
- *fp = file->f_next;
- nlmsvc_ops->fclose(file->f_file);
- kfree(file);
- return;
- }
- fp = &f->f_next;
+ if (!hlist_unhashed(&file->f_list)) {
+ hlist_del(&file->f_list);
+ nlmsvc_ops->fclose(file->f_file);
+ kfree(file);
+ } else {
+ printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
}
-
- printk(KERN_WARNING "lockd: attempt to release unknown file!\n");
}
/*
@@ -173,7 +159,8 @@ nlm_delete_file(struct nlm_file *file)
* action.
*/
static int
-nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_traverse_locks(struct nlm_host *host, struct nlm_file *file,
+ nlm_host_match_fn_t match)
{
struct inode *inode = nlmsvc_file_inode(file);
struct file_lock *fl;
@@ -187,17 +174,11 @@ again:
/* update current lock count */
file->f_locks++;
+
lockhost = (struct nlm_host *) fl->fl_owner;
- if (action == NLM_ACT_MARK)
- lockhost->h_inuse = 1;
- else if (action == NLM_ACT_CHECK)
- return 1;
- else if (action == NLM_ACT_UNLOCK) {
+ if (match(lockhost, host)) {
struct file_lock lock = *fl;
- if (host && lockhost != host)
- continue;
-
lock.fl_type = F_UNLCK;
lock.fl_start = 0;
lock.fl_end = OFFSET_MAX;
@@ -214,53 +195,66 @@ again:
}
/*
- * Operate on a single file
+ * Inspect a single file
+ */
+static inline int
+nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, nlm_host_match_fn_t match)
+{
+ nlmsvc_traverse_blocks(host, file, match);
+ nlmsvc_traverse_shares(host, file, match);
+ return nlm_traverse_locks(host, file, match);
+}
+
+/*
+ * Quick check whether there are still any locks, blocks or
+ * shares on a given file.
*/
static inline int
-nlm_inspect_file(struct nlm_host *host, struct nlm_file *file, int action)
+nlm_file_inuse(struct nlm_file *file)
{
- if (action == NLM_ACT_CHECK) {
- /* Fast path for mark and sweep garbage collection */
- if (file->f_count || file->f_blocks || file->f_shares)
+ struct inode *inode = nlmsvc_file_inode(file);
+ struct file_lock *fl;
+
+ if (file->f_count || !list_empty(&file->f_blocks) || file->f_shares)
+ return 1;
+
+ for (fl = inode->i_flock; fl; fl = fl->fl_next) {
+ if (fl->fl_lmops == &nlmsvc_lock_operations)
return 1;
- } else {
- nlmsvc_traverse_blocks(host, file, action);
- nlmsvc_traverse_shares(host, file, action);
}
- return nlm_traverse_locks(host, file, action);
+ file->f_locks = 0;
+ return 0;
}
/*
* Loop over all files in the file table.
*/
static int
-nlm_traverse_files(struct nlm_host *host, int action)
+nlm_traverse_files(struct nlm_host *host, nlm_host_match_fn_t match)
{
- struct nlm_file *file, **fp;
+ struct hlist_node *pos, *next;
+ struct nlm_file *file;
int i, ret = 0;
mutex_lock(&nlm_file_mutex);
for (i = 0; i < FILE_NRHASH; i++) {
- fp = nlm_files + i;
- while ((file = *fp) != NULL) {
+ hlist_for_each_entry_safe(file, pos, next, &nlm_files[i], f_list) {
file->f_count++;
mutex_unlock(&nlm_file_mutex);
/* Traverse locks, blocks and shares of this file
* and update file->f_locks count */
- if (nlm_inspect_file(host, file, action))
+ if (nlm_inspect_file(host, file, match))
ret = 1;
mutex_lock(&nlm_file_mutex);
file->f_count--;
/* No more references to this file. Let go of it. */
- if (!file->f_blocks && !file->f_locks
+ if (list_empty(&file->f_blocks) && !file->f_locks
&& !file->f_shares && !file->f_count) {
- *fp = file->f_next;
+ hlist_del(&file->f_list);
nlmsvc_ops->fclose(file->f_file);
kfree(file);
- } else {
- fp = &file->f_next;
}
}
}
@@ -287,23 +281,63 @@ nlm_release_file(struct nlm_file *file)
mutex_lock(&nlm_file_mutex);
/* If there are no more locks etc, delete the file */
- if(--file->f_count == 0) {
- if(!nlm_inspect_file(NULL, file, NLM_ACT_CHECK))
- nlm_delete_file(file);
- }
+ if (--file->f_count == 0 && !nlm_file_inuse(file))
+ nlm_delete_file(file);
mutex_unlock(&nlm_file_mutex);
}
/*
+ * Helpers function for resource traversal
+ *
+ * nlmsvc_mark_host:
+ * used by the garbage collector; simply sets h_inuse.
+ * Always returns 0.
+ *
+ * nlmsvc_same_host:
+ * returns 1 iff the two hosts match. Used to release
+ * all resources bound to a specific host.
+ *
+ * nlmsvc_is_client:
+ * returns 1 iff the host is a client.
+ * Used by nlmsvc_invalidate_all
+ */
+static int
+nlmsvc_mark_host(struct nlm_host *host, struct nlm_host *dummy)
+{
+ host->h_inuse = 1;
+ return 0;
+}
+
+static int
+nlmsvc_same_host(struct nlm_host *host, struct nlm_host *other)
+{
+ return host == other;
+}
+
+static int
+nlmsvc_is_client(struct nlm_host *host, struct nlm_host *dummy)
+{
+ if (host->h_server) {
+ /* we are destroying locks even though the client
+ * hasn't asked us too, so don't unmonitor the
+ * client
+ */
+ if (host->h_nsmhandle)
+ host->h_nsmhandle->sm_sticky = 1;
+ return 1;
+ } else
+ return 0;
+}
+
+/*
* Mark all hosts that still hold resources
*/
void
nlmsvc_mark_resources(void)
{
dprintk("lockd: nlmsvc_mark_resources\n");
-
- nlm_traverse_files(NULL, NLM_ACT_MARK);
+ nlm_traverse_files(NULL, nlmsvc_mark_host);
}
/*
@@ -314,23 +348,25 @@ nlmsvc_free_host_resources(struct nlm_host *host)
{
dprintk("lockd: nlmsvc_free_host_resources\n");
- if (nlm_traverse_files(host, NLM_ACT_UNLOCK))
+ if (nlm_traverse_files(host, nlmsvc_same_host)) {
printk(KERN_WARNING
- "lockd: couldn't remove all locks held by %s",
+ "lockd: couldn't remove all locks held by %s\n",
host->h_name);
+ BUG();
+ }
}
/*
- * delete all hosts structs for clients
+ * Remove all locks held for clients
*/
void
nlmsvc_invalidate_all(void)
{
- struct nlm_host *host;
- while ((host = nlm_find_client()) != NULL) {
- nlmsvc_free_host_resources(host);
- host->h_expires = 0;
- host->h_killed = 1;
- nlm_release_host(host);
- }
+ /* Release all locks held by NFS clients.
+ * Previously, the code would call
+ * nlmsvc_free_host_resources for each client in
+ * turn, which is about as inefficient as it gets.
+ * Now we just do it once in nlm_traverse_files.
+ */
+ nlm_traverse_files(NULL, nlmsvc_is_client);
}
diff --git a/fs/lockd/xdr.c b/fs/lockd/xdr.c
index 033ea4ac2c30..b7c949256e5a 100644
--- a/fs/lockd/xdr.c
+++ b/fs/lockd/xdr.c
@@ -43,7 +43,7 @@ loff_t_to_s32(loff_t offset)
/*
* XDR functions for basic NLM types
*/
-static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
+static __be32 *nlm_decode_cookie(__be32 *p, struct nlm_cookie *c)
{
unsigned int len;
@@ -69,8 +69,8 @@ static u32 *nlm_decode_cookie(u32 *p, struct nlm_cookie *c)
return p;
}
-static inline u32 *
-nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
+static inline __be32 *
+nlm_encode_cookie(__be32 *p, struct nlm_cookie *c)
{
*p++ = htonl(c->len);
memcpy(p, c->data, c->len);
@@ -78,8 +78,8 @@ nlm_encode_cookie(u32 *p, struct nlm_cookie *c)
return p;
}
-static u32 *
-nlm_decode_fh(u32 *p, struct nfs_fh *f)
+static __be32 *
+nlm_decode_fh(__be32 *p, struct nfs_fh *f)
{
unsigned int len;
@@ -95,8 +95,8 @@ nlm_decode_fh(u32 *p, struct nfs_fh *f)
return p + XDR_QUADLEN(NFS2_FHSIZE);
}
-static inline u32 *
-nlm_encode_fh(u32 *p, struct nfs_fh *f)
+static inline __be32 *
+nlm_encode_fh(__be32 *p, struct nfs_fh *f)
{
*p++ = htonl(NFS2_FHSIZE);
memcpy(p, f->data, NFS2_FHSIZE);
@@ -106,20 +106,20 @@ nlm_encode_fh(u32 *p, struct nfs_fh *f)
/*
* Encode and decode owner handle
*/
-static inline u32 *
-nlm_decode_oh(u32 *p, struct xdr_netobj *oh)
+static inline __be32 *
+nlm_decode_oh(__be32 *p, struct xdr_netobj *oh)
{
return xdr_decode_netobj(p, oh);
}
-static inline u32 *
-nlm_encode_oh(u32 *p, struct xdr_netobj *oh)
+static inline __be32 *
+nlm_encode_oh(__be32 *p, struct xdr_netobj *oh)
{
return xdr_encode_netobj(p, oh);
}
-static u32 *
-nlm_decode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm_decode_lock(__be32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
s32 start, len, end;
@@ -153,8 +153,8 @@ nlm_decode_lock(u32 *p, struct nlm_lock *lock)
/*
* Encode a lock as part of an NLM call
*/
-static u32 *
-nlm_encode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm_encode_lock(__be32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
__s32 start, len;
@@ -184,8 +184,8 @@ nlm_encode_lock(u32 *p, struct nlm_lock *lock)
/*
* Encode result of a TEST/TEST_MSG call
*/
-static u32 *
-nlm_encode_testres(u32 *p, struct nlm_res *resp)
+static __be32 *
+nlm_encode_testres(__be32 *p, struct nlm_res *resp)
{
s32 start, len;
@@ -221,7 +221,7 @@ nlm_encode_testres(u32 *p, struct nlm_res *resp)
* First, the server side XDR functions
*/
int
-nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
u32 exclusive;
@@ -238,7 +238,7 @@ nlmsvc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_encode_testres(p, resp)))
return 0;
@@ -246,7 +246,7 @@ nlmsvc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
u32 exclusive;
@@ -266,7 +266,7 @@ nlmsvc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
u32 exclusive;
@@ -282,7 +282,7 @@ nlmsvc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
if (!(p = nlm_decode_cookie(p, &argp->cookie))
|| !(p = nlm_decode_lock(p, &argp->lock)))
@@ -292,7 +292,7 @@ nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -313,7 +313,7 @@ nlmsvc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return 0;
@@ -323,7 +323,7 @@ nlmsvc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return 0;
@@ -332,7 +332,7 @@ nlmsvc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
+nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -344,7 +344,7 @@ nlmsvc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
}
int
-nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
+nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
{
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
return 0;
@@ -357,7 +357,7 @@ nlmsvc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
}
int
-nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_decode_cookie(p, &resp->cookie)))
return 0;
@@ -366,13 +366,13 @@ nlmsvc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlmsvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_argsize_check(rqstp, p);
}
int
-nlmsvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_ressize_check(rqstp, p);
}
@@ -389,7 +389,7 @@ nlmclt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
#endif
static int
-nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -403,7 +403,7 @@ nlmclt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_decode_cookie(p, &resp->cookie)))
return -EIO;
@@ -438,7 +438,7 @@ nlmclt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
static int
-nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -455,7 +455,7 @@ nlmclt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -470,7 +470,7 @@ nlmclt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlmclt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -483,7 +483,7 @@ nlmclt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_encode_cookie(p, &resp->cookie)))
return -EIO;
@@ -493,7 +493,7 @@ nlmclt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
}
static int
-nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_encode_testres(p, resp)))
return -EIO;
@@ -502,7 +502,7 @@ nlmclt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
}
static int
-nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlmclt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm_decode_cookie(p, &resp->cookie)))
return -EIO;
@@ -515,7 +515,7 @@ nlmclt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
*/
#define NLM_void_sz 0
#define NLM_cookie_sz 1+XDR_QUADLEN(NLM_MAXCOOKIELEN)
-#define NLM_caller_sz 1+XDR_QUADLEN(sizeof(system_utsname.nodename))
+#define NLM_caller_sz 1+XDR_QUADLEN(sizeof(utsname()->nodename))
#define NLM_netobj_sz 1+XDR_QUADLEN(XDR_MAX_NETOBJ)
/* #define NLM_owner_sz 1+XDR_QUADLEN(NLM_MAXOWNER) */
#define NLM_fhandle_sz 1+XDR_QUADLEN(NFS2_FHSIZE)
diff --git a/fs/lockd/xdr4.c b/fs/lockd/xdr4.c
index 36eb175ec335..f4c0b2b9f75a 100644
--- a/fs/lockd/xdr4.c
+++ b/fs/lockd/xdr4.c
@@ -44,8 +44,8 @@ loff_t_to_s64(loff_t offset)
/*
* XDR functions for basic NLM types
*/
-static u32 *
-nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
+static __be32 *
+nlm4_decode_cookie(__be32 *p, struct nlm_cookie *c)
{
unsigned int len;
@@ -71,8 +71,8 @@ nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
return p;
}
-static u32 *
-nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
+static __be32 *
+nlm4_encode_cookie(__be32 *p, struct nlm_cookie *c)
{
*p++ = htonl(c->len);
memcpy(p, c->data, c->len);
@@ -80,8 +80,8 @@ nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
return p;
}
-static u32 *
-nlm4_decode_fh(u32 *p, struct nfs_fh *f)
+static __be32 *
+nlm4_decode_fh(__be32 *p, struct nfs_fh *f)
{
memset(f->data, 0, sizeof(f->data));
f->size = ntohl(*p++);
@@ -95,8 +95,8 @@ nlm4_decode_fh(u32 *p, struct nfs_fh *f)
return p + XDR_QUADLEN(f->size);
}
-static u32 *
-nlm4_encode_fh(u32 *p, struct nfs_fh *f)
+static __be32 *
+nlm4_encode_fh(__be32 *p, struct nfs_fh *f)
{
*p++ = htonl(f->size);
if (f->size) p[XDR_QUADLEN(f->size)-1] = 0; /* don't leak anything */
@@ -107,20 +107,20 @@ nlm4_encode_fh(u32 *p, struct nfs_fh *f)
/*
* Encode and decode owner handle
*/
-static u32 *
-nlm4_decode_oh(u32 *p, struct xdr_netobj *oh)
+static __be32 *
+nlm4_decode_oh(__be32 *p, struct xdr_netobj *oh)
{
return xdr_decode_netobj(p, oh);
}
-static u32 *
-nlm4_encode_oh(u32 *p, struct xdr_netobj *oh)
+static __be32 *
+nlm4_encode_oh(__be32 *p, struct xdr_netobj *oh)
{
return xdr_encode_netobj(p, oh);
}
-static u32 *
-nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm4_decode_lock(__be32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
__s64 len, start, end;
@@ -153,8 +153,8 @@ nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
/*
* Encode a lock as part of an NLM call
*/
-static u32 *
-nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
+static __be32 *
+nlm4_encode_lock(__be32 *p, struct nlm_lock *lock)
{
struct file_lock *fl = &lock->fl;
__s64 start, len;
@@ -185,8 +185,8 @@ nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
/*
* Encode result of a TEST/TEST_MSG call
*/
-static u32 *
-nlm4_encode_testres(u32 *p, struct nlm_res *resp)
+static __be32 *
+nlm4_encode_testres(__be32 *p, struct nlm_res *resp)
{
s64 start, len;
@@ -227,7 +227,7 @@ nlm4_encode_testres(u32 *p, struct nlm_res *resp)
* First, the server side XDR functions
*/
int
-nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_testargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
u32 exclusive;
@@ -244,7 +244,7 @@ nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_encode_testres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_encode_testres(p, resp)))
return 0;
@@ -252,7 +252,7 @@ nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
u32 exclusive;
@@ -272,7 +272,7 @@ nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
u32 exclusive;
@@ -288,7 +288,7 @@ nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
if (!(p = nlm4_decode_cookie(p, &argp->cookie))
|| !(p = nlm4_decode_lock(p, &argp->lock)))
@@ -298,7 +298,7 @@ nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+nlm4svc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -319,7 +319,7 @@ nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
}
int
-nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_encode_shareres(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
return 0;
@@ -329,7 +329,7 @@ nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_encode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
return 0;
@@ -338,7 +338,7 @@ nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
+nlm4svc_decode_notify(struct svc_rqst *rqstp, __be32 *p, struct nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -350,7 +350,7 @@ nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
}
int
-nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
+nlm4svc_decode_reboot(struct svc_rqst *rqstp, __be32 *p, struct nlm_reboot *argp)
{
if (!(p = xdr_decode_string_inplace(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
return 0;
@@ -363,7 +363,7 @@ nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
}
int
-nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+nlm4svc_decode_res(struct svc_rqst *rqstp, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
return 0;
@@ -372,13 +372,13 @@ nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
}
int
-nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlm4svc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_argsize_check(rqstp, p);
}
int
-nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nlm4svc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_ressize_check(rqstp, p);
}
@@ -388,14 +388,14 @@ nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
*/
#ifdef NLMCLNT_SUPPORT_SHARES
static int
-nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+nlm4clt_decode_void(struct rpc_rqst *req, __be32 *p, void *ptr)
{
return 0;
}
#endif
static int
-nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_testargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -409,7 +409,7 @@ nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_decode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
return -EIO;
@@ -444,7 +444,7 @@ nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
static int
-nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_lockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -461,7 +461,7 @@ nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_cancargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -476,7 +476,7 @@ nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+nlm4clt_encode_unlockargs(struct rpc_rqst *req, __be32 *p, nlm_args *argp)
{
struct nlm_lock *lock = &argp->lock;
@@ -489,7 +489,7 @@ nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
}
static int
-nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_encode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
return -EIO;
@@ -499,7 +499,7 @@ nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
}
static int
-nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_encode_testres(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_encode_testres(p, resp)))
return -EIO;
@@ -508,7 +508,7 @@ nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
}
static int
-nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+nlm4clt_decode_res(struct rpc_rqst *req, __be32 *p, struct nlm_res *resp)
{
if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
return -EIO;
diff --git a/fs/locks.c b/fs/locks.c
index d7c53392cac1..e0b6a80649a0 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -314,13 +314,13 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
off_t start, end;
switch (l->l_whence) {
- case 0: /*SEEK_SET*/
+ case SEEK_SET:
start = 0;
break;
- case 1: /*SEEK_CUR*/
+ case SEEK_CUR:
start = filp->f_pos;
break;
- case 2: /*SEEK_END*/
+ case SEEK_END:
start = i_size_read(filp->f_dentry->d_inode);
break;
default:
@@ -364,13 +364,13 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
loff_t start;
switch (l->l_whence) {
- case 0: /*SEEK_SET*/
+ case SEEK_SET:
start = 0;
break;
- case 1: /*SEEK_CUR*/
+ case SEEK_CUR:
start = filp->f_pos;
break;
- case 2: /*SEEK_END*/
+ case SEEK_END:
start = i_size_read(filp->f_dentry->d_inode);
break;
default:
@@ -1514,7 +1514,7 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
goto out_unlock;
}
- error = f_setown(filp, current->pid, 0);
+ error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
out_unlock:
unlock_kernel();
return error;
diff --git a/fs/mbcache.c b/fs/mbcache.c
index e4fde1ab22cd..0ff71256e65b 100644
--- a/fs/mbcache.c
+++ b/fs/mbcache.c
@@ -160,6 +160,7 @@ __mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask)
static void
__mb_cache_entry_release_unlock(struct mb_cache_entry *ce)
+ __releases(mb_cache_spinlock)
{
/* Wake up all processes queuing for this cache entry. */
if (ce->e_queued)
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c
index 4a6abc49418e..df6b1075b549 100644
--- a/fs/minix/bitmap.c
+++ b/fs/minix/bitmap.c
@@ -254,7 +254,7 @@ struct inode * minix_new_inode(const struct inode * dir, int * error)
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
inode->i_ino = j;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
memset(&minix_i(inode)->u, 0, sizeof(minix_i(inode)->u));
insert_inode_hash(inode);
mark_inode_dirty(inode);
diff --git a/fs/minix/file.c b/fs/minix/file.c
index 420b32882a10..40eac2e60d25 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -17,8 +17,10 @@ int minix_sync_file(struct file *, struct dentry *, int);
const struct file_operations minix_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.fsync = minix_sync_file,
.sendfile = generic_file_sendfile,
diff --git a/fs/minix/inode.c b/fs/minix/inode.c
index 330ff9fc7cf0..1e36bae4d0eb 100644
--- a/fs/minix/inode.c
+++ b/fs/minix/inode.c
@@ -90,8 +90,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(minix_inode_cachep))
- printk(KERN_INFO "minix_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(minix_inode_cachep);
}
static struct super_operations minix_sops = {
@@ -145,18 +144,13 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
struct inode *root_inode;
struct minix_sb_info *sbi;
- sbi = kmalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct minix_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
s->s_fs_info = sbi;
- memset(sbi, 0, sizeof(struct minix_sb_info));
- /* N.B. These should be compile-time tests.
- Unfortunately that is impossible. */
- if (32 != sizeof (struct minix_inode))
- panic("bad V1 i-node size");
- if (64 != sizeof(struct minix2_inode))
- panic("bad V2 i-node size");
+ BUILD_BUG_ON(32 != sizeof (struct minix_inode));
+ BUILD_BUG_ON(64 != sizeof(struct minix2_inode));
if (!sb_set_blocksize(s, BLOCK_SIZE))
goto out_bad_hblock;
@@ -207,10 +201,9 @@ static int minix_fill_super(struct super_block *s, void *data, int silent)
if (sbi->s_imap_blocks == 0 || sbi->s_zmap_blocks == 0)
goto out_illegal_sb;
i = (sbi->s_imap_blocks + sbi->s_zmap_blocks) * sizeof(bh);
- map = kmalloc(i, GFP_KERNEL);
+ map = kzalloc(i, GFP_KERNEL);
if (!map)
goto out_no_map;
- memset(map, 0, i);
sbi->s_imap = &map[0];
sbi->s_zmap = &map[sbi->s_imap_blocks];
@@ -399,7 +392,7 @@ static void V1_minix_read_inode(struct inode * inode)
inode->i_mtime.tv_nsec = 0;
inode->i_atime.tv_nsec = 0;
inode->i_ctime.tv_nsec = 0;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
for (i = 0; i < 9; i++)
minix_inode->u.i1_data[i] = raw_inode->i_zone[i];
minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
@@ -432,7 +425,7 @@ static void V2_minix_read_inode(struct inode * inode)
inode->i_mtime.tv_nsec = 0;
inode->i_atime.tv_nsec = 0;
inode->i_ctime.tv_nsec = 0;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
for (i = 0; i < 10; i++)
minix_inode->u.i2_data[i] = raw_inode->i_zone[i];
minix_set_inode(inode, old_decode_dev(raw_inode->i_zone[0]));
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 5b6a4540a05b..299bb66e3bde 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -249,7 +249,7 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
minix_set_link(new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
inode_dec_link_count(new_inode);
} else {
if (dir_de) {
diff --git a/fs/mpage.c b/fs/mpage.c
index 1e4598247d0b..692a3e578fc8 100644
--- a/fs/mpage.c
+++ b/fs/mpage.c
@@ -693,6 +693,8 @@ 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,
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c
index 9e44158a7540..b0f01b3b0536 100644
--- a/fs/msdos/namei.c
+++ b/fs/msdos/namei.c
@@ -280,7 +280,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
struct nameidata *nd)
{
struct super_block *sb = dir->i_sb;
- struct inode *inode;
+ struct inode *inode = NULL;
struct fat_slot_info sinfo;
struct timespec ts;
unsigned char msdos_name[MSDOS_NAME];
@@ -316,6 +316,8 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, int mode,
d_instantiate(dentry, inode);
out:
unlock_kernel();
+ if (!err)
+ err = fat_flush_inodes(sb, dir, inode);
return err;
}
@@ -341,13 +343,15 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
- dir->i_nlink--;
+ drop_nlink(dir);
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC;
fat_detach(inode);
out:
unlock_kernel();
+ if (!err)
+ err = fat_flush_inodes(inode->i_sb, dir, inode);
return err;
}
@@ -385,7 +389,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
err = msdos_add_entry(dir, msdos_name, 1, is_hid, cluster, &ts, &sinfo);
if (err)
goto out_free;
- dir->i_nlink++;
+ inc_nlink(dir);
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
@@ -401,6 +405,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, int mode)
d_instantiate(dentry, inode);
unlock_kernel();
+ fat_flush_inodes(sb, dir, inode);
return 0;
out_free:
@@ -425,11 +430,13 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_ctime = CURRENT_TIME_SEC;
fat_detach(inode);
out:
unlock_kernel();
+ if (!err)
+ err = fat_flush_inodes(inode->i_sb, dir, inode);
return err;
}
@@ -542,9 +549,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
if (err)
goto error_dotdot;
}
- old_dir->i_nlink--;
+ drop_nlink(old_dir);
if (!new_inode)
- new_dir->i_nlink++;
+ inc_nlink(new_dir);
}
err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
@@ -559,10 +566,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
mark_inode_dirty(old_dir);
if (new_inode) {
+ drop_nlink(new_inode);
if (is_dir)
- new_inode->i_nlink -= 2;
- else
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
new_inode->i_ctime = ts;
}
out:
@@ -635,6 +641,8 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,
new_dir, new_msdos_name, new_dentry, is_hid);
out:
unlock_kernel();
+ if (!err)
+ err = fat_flush_inodes(old_dir->i_sb, old_dir, new_dir);
return err;
}
diff --git a/fs/namei.c b/fs/namei.c
index 6b591c01b09f..28d49b301d55 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -372,6 +372,30 @@ void release_open_intent(struct nameidata *nd)
fput(nd->intent.open.file);
}
+static inline struct dentry *
+do_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ int status = dentry->d_op->d_revalidate(dentry, nd);
+ if (unlikely(status <= 0)) {
+ /*
+ * The dentry failed validation.
+ * If d_revalidate returned 0 attempt to invalidate
+ * the dentry otherwise d_revalidate is asking us
+ * to return a fail status.
+ */
+ if (!status) {
+ if (!d_invalidate(dentry)) {
+ dput(dentry);
+ dentry = NULL;
+ }
+ } else {
+ dput(dentry);
+ dentry = ERR_PTR(status);
+ }
+ }
+ return dentry;
+}
+
/*
* Internal lookup() using the new generic dcache.
* SMP-safe
@@ -386,12 +410,9 @@ static struct dentry * cached_lookup(struct dentry * parent, struct qstr * name,
if (!dentry)
dentry = d_lookup(parent, name);
- if (dentry && dentry->d_op && dentry->d_op->d_revalidate) {
- if (!dentry->d_op->d_revalidate(dentry, nd) && !d_invalidate(dentry)) {
- dput(dentry);
- dentry = NULL;
- }
- }
+ if (dentry && dentry->d_op && dentry->d_op->d_revalidate)
+ dentry = do_revalidate(dentry, nd);
+
return dentry;
}
@@ -484,10 +505,9 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name, s
*/
mutex_unlock(&dir->i_mutex);
if (result->d_op && result->d_op->d_revalidate) {
- if (!result->d_op->d_revalidate(result, nd) && !d_invalidate(result)) {
- dput(result);
+ result = do_revalidate(result, nd);
+ if (!result)
result = ERR_PTR(-ENOENT);
- }
}
return result;
}
@@ -498,18 +518,20 @@ static int __emul_lookup_dentry(const char *, struct nameidata *);
static __always_inline int
walk_init_root(const char *name, struct nameidata *nd)
{
- read_lock(&current->fs->lock);
- if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
- nd->mnt = mntget(current->fs->altrootmnt);
- nd->dentry = dget(current->fs->altroot);
- read_unlock(&current->fs->lock);
+ struct fs_struct *fs = current->fs;
+
+ read_lock(&fs->lock);
+ if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+ nd->mnt = mntget(fs->altrootmnt);
+ nd->dentry = dget(fs->altroot);
+ read_unlock(&fs->lock);
if (__emul_lookup_dentry(name,nd))
return 0;
- read_lock(&current->fs->lock);
+ read_lock(&fs->lock);
}
- nd->mnt = mntget(current->fs->rootmnt);
- nd->dentry = dget(current->fs->root);
- read_unlock(&current->fs->lock);
+ nd->mnt = mntget(fs->rootmnt);
+ nd->dentry = dget(fs->root);
+ read_unlock(&fs->lock);
return 1;
}
@@ -704,17 +726,19 @@ int follow_down(struct vfsmount **mnt, struct dentry **dentry)
static __always_inline void follow_dotdot(struct nameidata *nd)
{
+ struct fs_struct *fs = current->fs;
+
while(1) {
struct vfsmount *parent;
struct dentry *old = nd->dentry;
- read_lock(&current->fs->lock);
- if (nd->dentry == current->fs->root &&
- nd->mnt == current->fs->rootmnt) {
- read_unlock(&current->fs->lock);
+ read_lock(&fs->lock);
+ if (nd->dentry == fs->root &&
+ nd->mnt == fs->rootmnt) {
+ read_unlock(&fs->lock);
break;
}
- read_unlock(&current->fs->lock);
+ read_unlock(&fs->lock);
spin_lock(&dcache_lock);
if (nd->dentry != nd->mnt->mnt_root) {
nd->dentry = dget(nd->dentry->d_parent);
@@ -767,12 +791,12 @@ need_lookup:
goto done;
need_revalidate:
- if (dentry->d_op->d_revalidate(dentry, nd))
- goto done;
- if (d_invalidate(dentry))
- goto done;
- dput(dentry);
- goto need_lookup;
+ dentry = do_revalidate(dentry, nd);
+ if (!dentry)
+ goto need_lookup;
+ if (IS_ERR(dentry))
+ goto fail;
+ goto done;
fail:
return PTR_ERR(dentry);
@@ -1022,15 +1046,17 @@ static int __emul_lookup_dentry(const char *name, struct nameidata *nd)
struct vfsmount *old_mnt = nd->mnt;
struct qstr last = nd->last;
int last_type = nd->last_type;
+ struct fs_struct *fs = current->fs;
+
/*
- * NAME was not found in alternate root or it's a directory. Try to find
- * it in the normal root:
+ * NAME was not found in alternate root or it's a directory.
+ * Try to find it in the normal root:
*/
nd->last_type = LAST_ROOT;
- read_lock(&current->fs->lock);
- nd->mnt = mntget(current->fs->rootmnt);
- nd->dentry = dget(current->fs->root);
- read_unlock(&current->fs->lock);
+ read_lock(&fs->lock);
+ nd->mnt = mntget(fs->rootmnt);
+ nd->dentry = dget(fs->root);
+ read_unlock(&fs->lock);
if (path_walk(name, nd) == 0) {
if (nd->dentry->d_inode) {
dput(old_dentry);
@@ -1054,6 +1080,7 @@ void set_fs_altroot(void)
struct vfsmount *mnt = NULL, *oldmnt;
struct dentry *dentry = NULL, *olddentry;
int err;
+ struct fs_struct *fs = current->fs;
if (!emul)
goto set_it;
@@ -1063,12 +1090,12 @@ void set_fs_altroot(void)
dentry = nd.dentry;
}
set_it:
- write_lock(&current->fs->lock);
- oldmnt = current->fs->altrootmnt;
- olddentry = current->fs->altroot;
- current->fs->altrootmnt = mnt;
- current->fs->altroot = dentry;
- write_unlock(&current->fs->lock);
+ write_lock(&fs->lock);
+ oldmnt = fs->altrootmnt;
+ olddentry = fs->altroot;
+ fs->altrootmnt = mnt;
+ fs->altroot = dentry;
+ write_unlock(&fs->lock);
if (olddentry) {
dput(olddentry);
mntput(oldmnt);
@@ -1082,29 +1109,30 @@ static int fastcall do_path_lookup(int dfd, const char *name,
int retval = 0;
int fput_needed;
struct file *file;
+ struct fs_struct *fs = current->fs;
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
nd->depth = 0;
if (*name=='/') {
- read_lock(&current->fs->lock);
- if (current->fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
- nd->mnt = mntget(current->fs->altrootmnt);
- nd->dentry = dget(current->fs->altroot);
- read_unlock(&current->fs->lock);
+ read_lock(&fs->lock);
+ if (fs->altroot && !(nd->flags & LOOKUP_NOALT)) {
+ nd->mnt = mntget(fs->altrootmnt);
+ nd->dentry = dget(fs->altroot);
+ read_unlock(&fs->lock);
if (__emul_lookup_dentry(name,nd))
goto out; /* found in altroot */
- read_lock(&current->fs->lock);
+ read_lock(&fs->lock);
}
- nd->mnt = mntget(current->fs->rootmnt);
- nd->dentry = dget(current->fs->root);
- read_unlock(&current->fs->lock);
+ nd->mnt = mntget(fs->rootmnt);
+ nd->dentry = dget(fs->root);
+ read_unlock(&fs->lock);
} else if (dfd == AT_FDCWD) {
- read_lock(&current->fs->lock);
- nd->mnt = mntget(current->fs->pwdmnt);
- nd->dentry = dget(current->fs->pwd);
- read_unlock(&current->fs->lock);
+ read_lock(&fs->lock);
+ nd->mnt = mntget(fs->pwdmnt);
+ nd->dentry = dget(fs->pwd);
+ read_unlock(&fs->lock);
} else {
struct dentry *dentry;
@@ -1567,6 +1595,24 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
return 0;
}
+static int open_namei_create(struct nameidata *nd, struct path *path,
+ int flag, int mode)
+{
+ int error;
+ struct dentry *dir = nd->dentry;
+
+ if (!IS_POSIXACL(dir->d_inode))
+ mode &= ~current->fs->umask;
+ error = vfs_create(dir->d_inode, path->dentry, mode, nd);
+ mutex_unlock(&dir->d_inode->i_mutex);
+ dput(nd->dentry);
+ nd->dentry = path->dentry;
+ if (error)
+ return error;
+ /* Don't check for write permission, don't truncate */
+ return may_open(nd, 0, flag & ~O_TRUNC);
+}
+
/*
* open_namei()
*
@@ -1648,18 +1694,10 @@ do_last:
/* Negative dentry, just create the file */
if (!path.dentry->d_inode) {
- if (!IS_POSIXACL(dir->d_inode))
- mode &= ~current->fs->umask;
- error = vfs_create(dir->d_inode, path.dentry, mode, nd);
- mutex_unlock(&dir->d_inode->i_mutex);
- dput(nd->dentry);
- nd->dentry = path.dentry;
+ error = open_namei_create(nd, &path, flag, mode);
if (error)
goto exit;
- /* Don't check for write permission, don't truncate */
- acc_mode = 0;
- flag &= ~O_TRUNC;
- goto ok;
+ return 0;
}
/*
@@ -1906,30 +1944,32 @@ asmlinkage long sys_mkdirat(int dfd, const char __user *pathname, int mode)
{
int error = 0;
char * tmp;
+ struct dentry *dentry;
+ struct nameidata nd;
tmp = getname(pathname);
error = PTR_ERR(tmp);
- if (!IS_ERR(tmp)) {
- struct dentry *dentry;
- struct nameidata nd;
+ if (IS_ERR(tmp))
+ goto out_err;
- error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
- if (error)
- goto out;
- dentry = lookup_create(&nd, 1);
- error = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
- if (!IS_POSIXACL(nd.dentry->d_inode))
- mode &= ~current->fs->umask;
- error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
- dput(dentry);
- }
- mutex_unlock(&nd.dentry->d_inode->i_mutex);
- path_release(&nd);
-out:
- putname(tmp);
- }
+ error = do_path_lookup(dfd, tmp, LOOKUP_PARENT, &nd);
+ if (error)
+ goto out;
+ dentry = lookup_create(&nd, 1);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out_unlock;
+ if (!IS_POSIXACL(nd.dentry->d_inode))
+ mode &= ~current->fs->umask;
+ error = vfs_mkdir(nd.dentry->d_inode, dentry, mode);
+ dput(dentry);
+out_unlock:
+ mutex_unlock(&nd.dentry->d_inode->i_mutex);
+ path_release(&nd);
+out:
+ putname(tmp);
+out_err:
return error;
}
@@ -2028,10 +2068,11 @@ static long do_rmdir(int dfd, const char __user *pathname)
mutex_lock_nested(&nd.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
dentry = lookup_hash(&nd);
error = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
- error = vfs_rmdir(nd.dentry->d_inode, dentry);
- dput(dentry);
- }
+ if (IS_ERR(dentry))
+ goto exit2;
+ error = vfs_rmdir(nd.dentry->d_inode, dentry);
+ dput(dentry);
+exit2:
mutex_unlock(&nd.dentry->d_inode->i_mutex);
exit1:
path_release(&nd);
@@ -2171,30 +2212,33 @@ asmlinkage long sys_symlinkat(const char __user *oldname,
int error = 0;
char * from;
char * to;
+ struct dentry *dentry;
+ struct nameidata nd;
from = getname(oldname);
if(IS_ERR(from))
return PTR_ERR(from);
to = getname(newname);
error = PTR_ERR(to);
- if (!IS_ERR(to)) {
- struct dentry *dentry;
- struct nameidata nd;
+ if (IS_ERR(to))
+ goto out_putname;
- error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
- if (error)
- goto out;
- dentry = lookup_create(&nd, 0);
- error = PTR_ERR(dentry);
- if (!IS_ERR(dentry)) {
- error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
- dput(dentry);
- }
- mutex_unlock(&nd.dentry->d_inode->i_mutex);
- path_release(&nd);
+ error = do_path_lookup(newdfd, to, LOOKUP_PARENT, &nd);
+ if (error)
+ goto out;
+ dentry = lookup_create(&nd, 0);
+ error = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto out_unlock;
+
+ error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO);
+ dput(dentry);
+out_unlock:
+ mutex_unlock(&nd.dentry->d_inode->i_mutex);
+ path_release(&nd);
out:
- putname(to);
- }
+ putname(to);
+out_putname:
putname(from);
return error;
}
@@ -2280,10 +2324,11 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
goto out_release;
new_dentry = lookup_create(&nd, 0);
error = PTR_ERR(new_dentry);
- if (!IS_ERR(new_dentry)) {
- error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
- dput(new_dentry);
- }
+ if (IS_ERR(new_dentry))
+ goto out_unlock;
+ error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+ dput(new_dentry);
+out_unlock:
mutex_unlock(&nd.dentry->d_inode->i_mutex);
out_release:
path_release(&nd);
diff --git a/fs/namespace.c b/fs/namespace.c
index 36d180858136..55442a6cf221 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -13,6 +13,7 @@
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
+#include <linux/kernel.h>
#include <linux/quotaops.h>
#include <linux/acct.h>
#include <linux/capability.h>
@@ -23,12 +24,11 @@
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/mount.h>
+#include <linux/ramfs.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include "pnode.h"
-extern int __init init_rootfs(void);
-
/* spinlock for vfsmount related operations, inplace of dcache_lock */
__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
@@ -133,7 +133,7 @@ struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
static inline int check_mnt(struct vfsmount *mnt)
{
- return mnt->mnt_namespace == current->namespace;
+ return mnt->mnt_namespace == current->nsproxy->namespace;
}
static void touch_namespace(struct namespace *ns)
@@ -830,7 +830,7 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
if (parent_nd) {
detach_mnt(source_mnt, parent_nd);
attach_mnt(source_mnt, nd);
- touch_namespace(current->namespace);
+ touch_namespace(current->nsproxy->namespace);
} else {
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
commit_tree(source_mnt);
@@ -1441,7 +1441,7 @@ dput_out:
*/
struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
{
- struct namespace *namespace = tsk->namespace;
+ struct namespace *namespace = tsk->nsproxy->namespace;
struct namespace *new_ns;
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
struct vfsmount *p, *q;
@@ -1508,7 +1508,7 @@ struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
int copy_namespace(int flags, struct task_struct *tsk)
{
- struct namespace *namespace = tsk->namespace;
+ struct namespace *namespace = tsk->nsproxy->namespace;
struct namespace *new_ns;
int err = 0;
@@ -1531,7 +1531,7 @@ int copy_namespace(int flags, struct task_struct *tsk)
goto out;
}
- tsk->namespace = new_ns;
+ tsk->nsproxy->namespace = new_ns;
out:
put_namespace(namespace);
@@ -1754,7 +1754,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
detach_mnt(user_nd.mnt, &root_parent);
attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */
attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
- touch_namespace(current->namespace);
+ touch_namespace(current->nsproxy->namespace);
spin_unlock(&vfsmount_lock);
chroot_fs_refs(&user_nd, &new_nd);
security_sb_post_pivotroot(&user_nd, &new_nd);
@@ -1780,7 +1780,6 @@ static void __init init_mount_tree(void)
{
struct vfsmount *mnt;
struct namespace *namespace;
- struct task_struct *g, *p;
mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
if (IS_ERR(mnt))
@@ -1796,13 +1795,8 @@ static void __init init_mount_tree(void)
namespace->root = mnt;
mnt->mnt_namespace = namespace;
- init_task.namespace = namespace;
- read_lock(&tasklist_lock);
- do_each_thread(g, p) {
- get_namespace(namespace);
- p->namespace = namespace;
- } while_each_thread(g, p);
- read_unlock(&tasklist_lock);
+ init_task.nsproxy->namespace = namespace;
+ get_namespace(namespace);
set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
@@ -1813,6 +1807,7 @@ void __init mnt_init(unsigned long mempages)
struct list_head *d;
unsigned int nr_hash;
int i;
+ int err;
init_rwsem(&namespace_sem);
@@ -1853,8 +1848,14 @@ void __init mnt_init(unsigned long mempages)
d++;
i--;
} while (i);
- sysfs_init();
- subsystem_register(&fs_subsys);
+ err = sysfs_init();
+ if (err)
+ printk(KERN_WARNING "%s: sysfs_init error: %d\n",
+ __FUNCTION__, err);
+ err = subsystem_register(&fs_subsys);
+ if (err)
+ printk(KERN_WARNING "%s: subsystem_register error: %d\n",
+ __FUNCTION__, err);
init_rootfs();
init_mount_tree();
}
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index b4ee89250e95..458b3b785194 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -53,6 +53,9 @@ const struct file_operations ncp_dir_operations =
.read = generic_read_dir,
.readdir = ncp_readdir,
.ioctl = ncp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ncp_compat_ioctl,
+#endif
};
struct inode_operations ncp_dir_inode_operations =
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index e6b7c67cf057..df37524b85db 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -289,6 +289,9 @@ const struct file_operations ncp_file_operations =
.read = ncp_file_read,
.write = ncp_file_write,
.ioctl = ncp_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ncp_compat_ioctl,
+#endif
.mmap = ncp_mmap,
.release = ncp_release,
.fsync = ncp_fsync,
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
index 1ddf77b0b825..42e3bef270c9 100644
--- a/fs/ncpfs/inode.c
+++ b/fs/ncpfs/inode.c
@@ -81,8 +81,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(ncp_inode_cachep))
- printk(KERN_INFO "ncp_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(ncp_inode_cachep);
}
static int ncp_remount(struct super_block *sb, int *flags, char* data)
@@ -224,7 +223,6 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
inode->i_nlink = 1;
inode->i_uid = server->m.uid;
inode->i_gid = server->m.gid;
- inode->i_blksize = NCP_BLOCK_SIZE;
ncp_update_dates(inode, &nwinfo->i);
ncp_update_inode(inode, nwinfo);
@@ -411,11 +409,10 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
#endif
struct ncp_entry_info finfo;
- server = kmalloc(sizeof(struct ncp_server), GFP_KERNEL);
+ server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
if (!server)
return -ENOMEM;
sb->s_fs_info = server;
- memset(server, 0, sizeof(struct ncp_server));
error = -EFAULT;
if (raw_data == NULL)
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index 42039fe0653c..589d1eac55c1 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -7,19 +7,21 @@
*
*/
-
-#include <asm/uaccess.h>
#include <linux/capability.h>
+#include <linux/compat.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ioctl.h>
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/highuid.h>
+#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/ncp_fs.h>
+#include <asm/uaccess.h>
+
#include "ncplib_kernel.h"
/* maximum limit for ncp_objectname_ioctl */
@@ -89,6 +91,82 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct file *file,
return 0;
}
+#ifdef CONFIG_COMPAT
+struct compat_ncp_objectname_ioctl
+{
+ s32 auth_type;
+ u32 object_name_len;
+ compat_caddr_t object_name; /* an userspace data, in most cases user name */
+};
+
+struct compat_ncp_fs_info_v2 {
+ s32 version;
+ u32 mounted_uid;
+ u32 connection;
+ u32 buffer_size;
+
+ u32 volume_number;
+ u32 directory_id;
+
+ u32 dummy1;
+ u32 dummy2;
+ u32 dummy3;
+};
+
+struct compat_ncp_ioctl_request {
+ u32 function;
+ u32 size;
+ compat_caddr_t data;
+};
+
+struct compat_ncp_privatedata_ioctl
+{
+ u32 len;
+ compat_caddr_t data; /* ~1000 for NDS */
+};
+
+#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2)
+#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request)
+#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl)
+#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl)
+#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl)
+#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl)
+
+static int
+ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file,
+ struct compat_ncp_fs_info_v2 __user * arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct compat_ncp_fs_info_v2 info2;
+
+ if ((file_permission(file, MAY_WRITE) != 0)
+ && (current->uid != server->m.mounted_uid)) {
+ return -EACCES;
+ }
+ if (copy_from_user(&info2, arg, sizeof(info2)))
+ return -EFAULT;
+
+ if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
+ DPRINTK("info.version invalid: %d\n", info2.version);
+ return -EINVAL;
+ }
+ info2.mounted_uid = server->m.mounted_uid;
+ info2.connection = server->connection;
+ info2.buffer_size = server->buffer_size;
+ info2.volume_number = NCP_FINFO(inode)->volNumber;
+ info2.directory_id = NCP_FINFO(inode)->DosDirNum;
+ info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
+
+ if (copy_to_user(arg, &info2, sizeof(info2)))
+ return -EFAULT;
+ return 0;
+}
+#endif
+
+#define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16)
+#define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32)
+#define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64)
+
#ifdef CONFIG_NCPFS_NLS
/* Here we are select the iocharset and the codepage for NLS.
* Thanks Petr Vandrovec for idea and many hints.
@@ -192,12 +270,24 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
void __user *argp = (void __user *)arg;
switch (cmd) {
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_NCPREQUEST_32:
+#endif
case NCP_IOC_NCPREQUEST:
-
if ((file_permission(filp, MAY_WRITE) != 0)
&& (current->uid != server->m.mounted_uid)) {
return -EACCES;
}
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_NCPREQUEST_32) {
+ struct compat_ncp_ioctl_request request32;
+ if (copy_from_user(&request32, argp, sizeof(request32)))
+ return -EFAULT;
+ request.function = request32.function;
+ request.size = request32.size;
+ request.data = compat_ptr(request32.data);
+ } else
+#endif
if (copy_from_user(&request, argp, sizeof(request)))
return -EFAULT;
@@ -254,19 +344,35 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
case NCP_IOC_GET_FS_INFO_V2:
return ncp_get_fs_info_v2(server, filp, argp);
- case NCP_IOC_GETMOUNTUID2:
- {
- unsigned long tmp = server->m.mounted_uid;
-
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid))
- {
- return -EACCES;
- }
- if (put_user(tmp, (unsigned long __user *)argp))
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_GET_FS_INFO_V2_32:
+ return ncp_get_compat_fs_info_v2(server, filp, argp);
+#endif
+ /* we have too many combinations of CONFIG_COMPAT,
+ * CONFIG_64BIT and CONFIG_UID16, so just handle
+ * any of the possible ioctls */
+ case NCP_IOC_GETMOUNTUID16:
+ case NCP_IOC_GETMOUNTUID32:
+ case NCP_IOC_GETMOUNTUID64:
+ if ((file_permission(filp, MAY_READ) != 0)
+ && (current->uid != server->m.mounted_uid)) {
+ return -EACCES;
+ }
+ if (cmd == NCP_IOC_GETMOUNTUID16) {
+ u16 uid;
+ SET_UID(uid, server->m.mounted_uid);
+ if (put_user(uid, (u16 __user *)argp))
+ return -EFAULT;
+ } else if (cmd == NCP_IOC_GETMOUNTUID32) {
+ if (put_user(server->m.mounted_uid,
+ (u32 __user *)argp))
+ return -EFAULT;
+ } else {
+ if (put_user(server->m.mounted_uid,
+ (u64 __user *)argp))
return -EFAULT;
- return 0;
}
+ return 0;
case NCP_IOC_GETROOT:
{
@@ -476,6 +582,32 @@ outrel:
}
#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_GETOBJECTNAME_32:
+ if (current->uid != server->m.mounted_uid) {
+ return -EACCES;
+ }
+ {
+ struct compat_ncp_objectname_ioctl user;
+ size_t outl;
+
+ if (copy_from_user(&user, argp, sizeof(user)))
+ return -EFAULT;
+ user.auth_type = server->auth.auth_type;
+ outl = user.object_name_len;
+ user.object_name_len = server->auth.object_name_len;
+ if (outl > user.object_name_len)
+ outl = user.object_name_len;
+ if (outl) {
+ if (copy_to_user(compat_ptr(user.object_name),
+ server->auth.object_name,
+ outl)) return -EFAULT;
+ }
+ if (copy_to_user(argp, &user, sizeof(user)))
+ return -EFAULT;
+ return 0;
+ }
+#endif
case NCP_IOC_GETOBJECTNAME:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -500,6 +632,9 @@ outrel:
return -EFAULT;
return 0;
}
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_SETOBJECTNAME_32:
+#endif
case NCP_IOC_SETOBJECTNAME:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -512,8 +647,19 @@ outrel:
void* oldprivate;
size_t oldprivatelen;
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_SETOBJECTNAME_32) {
+ struct compat_ncp_objectname_ioctl user32;
+ if (copy_from_user(&user32, argp, sizeof(user32)))
+ return -EFAULT;
+ user.auth_type = user32.auth_type;
+ user.object_name_len = user32.object_name_len;
+ user.object_name = compat_ptr(user32.object_name);
+ } else
+#endif
if (copy_from_user(&user, argp, sizeof(user)))
return -EFAULT;
+
if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
return -ENOMEM;
if (user.object_name_len) {
@@ -544,6 +690,9 @@ outrel:
kfree(oldname);
return 0;
}
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_GETPRIVATEDATA_32:
+#endif
case NCP_IOC_GETPRIVATEDATA:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -552,8 +701,18 @@ outrel:
struct ncp_privatedata_ioctl user;
size_t outl;
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
+ struct compat_ncp_privatedata_ioctl user32;
+ if (copy_from_user(&user32, argp, sizeof(user32)))
+ return -EFAULT;
+ user.len = user32.len;
+ user.data = compat_ptr(user32.data);
+ } else
+#endif
if (copy_from_user(&user, argp, sizeof(user)))
return -EFAULT;
+
outl = user.len;
user.len = server->priv.len;
if (outl > user.len) outl = user.len;
@@ -562,10 +721,23 @@ outrel:
server->priv.data,
outl)) return -EFAULT;
}
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
+ struct compat_ncp_privatedata_ioctl user32;
+ user32.len = user.len;
+ user32.data = (unsigned long) user.data;
+ if (copy_to_user(argp, &user32, sizeof(user32)))
+ return -EFAULT;
+ } else
+#endif
if (copy_to_user(argp, &user, sizeof(user)))
return -EFAULT;
+
return 0;
}
+#ifdef CONFIG_COMPAT
+ case NCP_IOC_SETPRIVATEDATA_32:
+#endif
case NCP_IOC_SETPRIVATEDATA:
if (current->uid != server->m.mounted_uid) {
return -EACCES;
@@ -576,8 +748,18 @@ outrel:
void* old;
size_t oldlen;
+#ifdef CONFIG_COMPAT
+ if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
+ struct compat_ncp_privatedata_ioctl user32;
+ if (copy_from_user(&user32, argp, sizeof(user32)))
+ return -EFAULT;
+ user.len = user32.len;
+ user.data = compat_ptr(user32.data);
+ } else
+#endif
if (copy_from_user(&user, argp, sizeof(user)))
return -EFAULT;
+
if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
return -ENOMEM;
if (user.len) {
@@ -636,20 +818,19 @@ outrel:
}
}
-/* #ifdef CONFIG_UID16 */
- /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2,
- so we have this out of switch */
- if (cmd == NCP_IOC_GETMOUNTUID) {
- __kernel_uid_t uid = 0;
- if ((file_permission(filp, MAY_READ) != 0)
- && (current->uid != server->m.mounted_uid)) {
- return -EACCES;
- }
- SET_UID(uid, server->m.mounted_uid);
- if (put_user(uid, (__kernel_uid_t __user *)argp))
- return -EFAULT;
- return 0;
- }
-/* #endif */
return -EINVAL;
}
+
+#ifdef CONFIG_COMPAT
+long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ lock_kernel();
+ arg = (unsigned long) compat_ptr(arg);
+ ret = ncp_ioctl(inode, file, cmd, arg);
+ unlock_kernel();
+ return ret;
+}
+#endif
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
index ca92c2406635..e3d26c1bd105 100644
--- a/fs/ncpfs/symlink.c
+++ b/fs/ncpfs/symlink.c
@@ -48,7 +48,7 @@ static int ncp_symlink_readpage(struct file *file, struct page *page)
char *buf = kmap(page);
error = -ENOMEM;
- rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
+ rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
if (!rawlink)
goto fail;
@@ -126,7 +126,7 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
/* EPERM is returned by VFS if symlink procedure does not exist */
return -EPERM;
- rawlink=(char *)kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
+ rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
if (!rawlink)
return -ENOMEM;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index a3ee11364db0..7933e2e99dbc 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -58,7 +58,6 @@ module_param_call(callback_tcpport, param_set_port, param_get_int,
*/
static void nfs_callback_svc(struct svc_rqst *rqstp)
{
- struct svc_serv *serv = rqstp->rq_server;
int err;
__module_get(THIS_MODULE);
@@ -80,7 +79,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
/*
* Listen for a request on the socket
*/
- err = svc_recv(serv, rqstp, MAX_SCHEDULE_TIMEOUT);
+ err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT);
if (err == -EAGAIN || err == -EINTR)
continue;
if (err < 0) {
@@ -91,7 +90,7 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
}
dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__,
NIPQUAD(rqstp->rq_addr.sin_addr.s_addr));
- svc_process(serv, rqstp);
+ svc_process(rqstp);
}
svc_exit_thread(rqstp);
@@ -116,7 +115,7 @@ int nfs_callback_up(void)
goto out;
init_completion(&nfs_callback_info.started);
init_completion(&nfs_callback_info.stopped);
- serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE);
+ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
ret = -ENOMEM;
if (!serv)
goto out_err;
diff --git a/fs/nfs/callback.h b/fs/nfs/callback.h
index 5676163d26e8..db3d7919c601 100644
--- a/fs/nfs/callback.h
+++ b/fs/nfs/callback.h
@@ -31,10 +31,10 @@ struct cb_compound_hdr_arg {
};
struct cb_compound_hdr_res {
- uint32_t *status;
+ __be32 *status;
int taglen;
const char *tag;
- uint32_t *nops;
+ __be32 *nops;
};
struct cb_getattrargs {
@@ -44,7 +44,7 @@ struct cb_getattrargs {
};
struct cb_getattrres {
- uint32_t status;
+ __be32 status;
uint32_t bitmap[2];
uint64_t size;
uint64_t change_attr;
@@ -59,8 +59,8 @@ struct cb_recallargs {
uint32_t truncate;
};
-extern unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
-extern unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
+extern __be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res);
+extern __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy);
#ifdef CONFIG_NFS_V4
extern int nfs_callback_up(void);
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 97cf8f71451f..72e55d83756d 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -14,7 +14,7 @@
#define NFSDBG_FACILITY NFSDBG_CALLBACK
-unsigned nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
+__be32 nfs4_callback_getattr(struct cb_getattrargs *args, struct cb_getattrres *res)
{
struct nfs_client *clp;
struct nfs_delegation *delegation;
@@ -55,11 +55,11 @@ out:
return res->status;
}
-unsigned nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
+__be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy)
{
struct nfs_client *clp;
struct inode *inode;
- unsigned res;
+ __be32 res;
res = htonl(NFS4ERR_BADHANDLE);
clp = nfs_find_client(args->addr, 4);
diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 29f932192054..f8ea1f51f590 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -22,9 +22,9 @@
#define NFSDBG_FACILITY NFSDBG_CALLBACK
-typedef unsigned (*callback_process_op_t)(void *, void *);
-typedef unsigned (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
-typedef unsigned (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
+typedef __be32 (*callback_process_op_t)(void *, void *);
+typedef __be32 (*callback_decode_arg_t)(struct svc_rqst *, struct xdr_stream *, void *);
+typedef __be32 (*callback_encode_res_t)(struct svc_rqst *, struct xdr_stream *, void *);
struct callback_op {
@@ -36,24 +36,24 @@ struct callback_op {
static struct callback_op callback_ops[];
-static int nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
+static __be32 nfs4_callback_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
return htonl(NFS4_OK);
}
-static int nfs4_decode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_argsize_check(rqstp, p);
}
-static int nfs4_encode_void(struct svc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_ressize_check(rqstp, p);
}
-static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes)
+static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)
{
- uint32_t *p;
+ __be32 *p;
p = xdr_inline_decode(xdr, nbytes);
if (unlikely(p == NULL))
@@ -61,9 +61,9 @@ static uint32_t *read_buf(struct xdr_stream *xdr, int nbytes)
return p;
}
-static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
+static __be32 decode_string(struct xdr_stream *xdr, unsigned int *len, const char **str)
{
- uint32_t *p;
+ __be32 *p;
p = read_buf(xdr, 4);
if (unlikely(p == NULL))
@@ -81,9 +81,9 @@ static unsigned decode_string(struct xdr_stream *xdr, unsigned int *len, const c
return 0;
}
-static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
+static __be32 decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
- uint32_t *p;
+ __be32 *p;
p = read_buf(xdr, 4);
if (unlikely(p == NULL))
@@ -99,9 +99,9 @@ static unsigned decode_fh(struct xdr_stream *xdr, struct nfs_fh *fh)
return 0;
}
-static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
+static __be32 decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
{
- uint32_t *p;
+ __be32 *p;
unsigned int attrlen;
p = read_buf(xdr, 4);
@@ -118,9 +118,9 @@ static unsigned decode_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
return 0;
}
-static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
+static __be32 decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
{
- uint32_t *p;
+ __be32 *p;
p = read_buf(xdr, 16);
if (unlikely(p == NULL))
@@ -129,11 +129,11 @@ static unsigned decode_stateid(struct xdr_stream *xdr, nfs4_stateid *stateid)
return 0;
}
-static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
+static __be32 decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compound_hdr_arg *hdr)
{
- uint32_t *p;
+ __be32 *p;
unsigned int minor_version;
- unsigned status;
+ __be32 status;
status = decode_string(xdr, &hdr->taglen, &hdr->tag);
if (unlikely(status != 0))
@@ -159,9 +159,9 @@ static unsigned decode_compound_hdr_arg(struct xdr_stream *xdr, struct cb_compou
return 0;
}
-static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
+static __be32 decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
{
- uint32_t *p;
+ __be32 *p;
p = read_buf(xdr, 4);
if (unlikely(p == NULL))
return htonl(NFS4ERR_RESOURCE);
@@ -169,9 +169,9 @@ static unsigned decode_op_hdr(struct xdr_stream *xdr, unsigned int *op)
return 0;
}
-static unsigned decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
+static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_getattrargs *args)
{
- unsigned status;
+ __be32 status;
status = decode_fh(xdr, &args->fh);
if (unlikely(status != 0))
@@ -183,10 +183,10 @@ out:
return status;
}
-static unsigned decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
+static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, struct cb_recallargs *args)
{
- uint32_t *p;
- unsigned status;
+ __be32 *p;
+ __be32 status;
args->addr = &rqstp->rq_addr;
status = decode_stateid(xdr, &args->stateid);
@@ -204,9 +204,9 @@ out:
return status;
}
-static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
+static __be32 encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
- uint32_t *p;
+ __be32 *p;
p = xdr_reserve_space(xdr, 4 + len);
if (unlikely(p == NULL))
@@ -217,10 +217,10 @@ static unsigned encode_string(struct xdr_stream *xdr, unsigned int len, const ch
#define CB_SUPPORTED_ATTR0 (FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE)
#define CB_SUPPORTED_ATTR1 (FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY)
-static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, uint32_t **savep)
+static __be32 encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitmap, __be32 **savep)
{
- uint32_t bm[2];
- uint32_t *p;
+ __be32 bm[2];
+ __be32 *p;
bm[0] = htonl(bitmap[0] & CB_SUPPORTED_ATTR0);
bm[1] = htonl(bitmap[1] & CB_SUPPORTED_ATTR1);
@@ -247,9 +247,9 @@ static unsigned encode_attr_bitmap(struct xdr_stream *xdr, const uint32_t *bitma
return 0;
}
-static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
+static __be32 encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t change)
{
- uint32_t *p;
+ __be32 *p;
if (!(bitmap[0] & FATTR4_WORD0_CHANGE))
return 0;
@@ -260,9 +260,9 @@ static unsigned encode_attr_change(struct xdr_stream *xdr, const uint32_t *bitma
return 0;
}
-static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
+static __be32 encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap, uint64_t size)
{
- uint32_t *p;
+ __be32 *p;
if (!(bitmap[0] & FATTR4_WORD0_SIZE))
return 0;
@@ -273,9 +273,9 @@ static unsigned encode_attr_size(struct xdr_stream *xdr, const uint32_t *bitmap,
return 0;
}
-static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
+static __be32 encode_attr_time(struct xdr_stream *xdr, const struct timespec *time)
{
- uint32_t *p;
+ __be32 *p;
p = xdr_reserve_space(xdr, 12);
if (unlikely(p == 0))
@@ -285,23 +285,23 @@ static unsigned encode_attr_time(struct xdr_stream *xdr, const struct timespec *
return 0;
}
-static unsigned encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+static __be32 encode_attr_ctime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
{
if (!(bitmap[1] & FATTR4_WORD1_TIME_METADATA))
return 0;
return encode_attr_time(xdr,time);
}
-static unsigned encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
+static __be32 encode_attr_mtime(struct xdr_stream *xdr, const uint32_t *bitmap, const struct timespec *time)
{
if (!(bitmap[1] & FATTR4_WORD1_TIME_MODIFY))
return 0;
return encode_attr_time(xdr,time);
}
-static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
+static __be32 encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compound_hdr_res *hdr)
{
- unsigned status;
+ __be32 status;
hdr->status = xdr_reserve_space(xdr, 4);
if (unlikely(hdr->status == NULL))
@@ -315,9 +315,9 @@ static unsigned encode_compound_hdr_res(struct xdr_stream *xdr, struct cb_compou
return 0;
}
-static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res)
+static __be32 encode_op_hdr(struct xdr_stream *xdr, uint32_t op, __be32 res)
{
- uint32_t *p;
+ __be32 *p;
p = xdr_reserve_space(xdr, 8);
if (unlikely(p == NULL))
@@ -327,10 +327,10 @@ static unsigned encode_op_hdr(struct xdr_stream *xdr, uint32_t op, uint32_t res)
return 0;
}
-static unsigned encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
+static __be32 encode_getattr_res(struct svc_rqst *rqstp, struct xdr_stream *xdr, const struct cb_getattrres *res)
{
- uint32_t *savep = NULL;
- unsigned status = res->status;
+ __be32 *savep = NULL;
+ __be32 status = res->status;
if (unlikely(status != 0))
goto out;
@@ -353,15 +353,15 @@ out:
return status;
}
-static unsigned process_op(struct svc_rqst *rqstp,
+static __be32 process_op(struct svc_rqst *rqstp,
struct xdr_stream *xdr_in, void *argp,
struct xdr_stream *xdr_out, void *resp)
{
struct callback_op *op = &callback_ops[0];
unsigned int op_nr = OP_CB_ILLEGAL;
- unsigned int status = 0;
+ __be32 status = 0;
long maxlen;
- unsigned res;
+ __be32 res;
dprintk("%s: start\n", __FUNCTION__);
status = decode_op_hdr(xdr_in, &op_nr);
@@ -399,20 +399,20 @@ static unsigned process_op(struct svc_rqst *rqstp,
/*
* Decode, process and encode a COMPOUND
*/
-static int nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
+static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *resp)
{
struct cb_compound_hdr_arg hdr_arg;
struct cb_compound_hdr_res hdr_res;
struct xdr_stream xdr_in, xdr_out;
- uint32_t *p;
- unsigned int status;
+ __be32 *p;
+ __be32 status;
unsigned int nops = 1;
dprintk("%s: start\n", __FUNCTION__);
xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);
- p = (uint32_t*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
+ p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
decode_compound_hdr_arg(&xdr_in, &hdr_arg);
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index ec1938d4b814..5fea638743e4 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -10,7 +10,6 @@
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -233,11 +232,15 @@ void nfs_put_client(struct nfs_client *clp)
* Find a client by address
* - caller must hold nfs_client_lock
*/
-static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion)
+static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int nfsversion, int match_port)
{
struct nfs_client *clp;
list_for_each_entry(clp, &nfs_client_list, cl_share_link) {
+ /* Don't match clients that failed to initialise properly */
+ if (clp->cl_cons_state < 0)
+ continue;
+
/* Different NFS versions cannot share the same nfs_client */
if (clp->cl_nfsversion != nfsversion)
continue;
@@ -246,7 +249,7 @@ static struct nfs_client *__nfs_find_client(const struct sockaddr_in *addr, int
sizeof(clp->cl_addr.sin_addr)) != 0)
continue;
- if (clp->cl_addr.sin_port == addr->sin_port)
+ if (!match_port || clp->cl_addr.sin_port == addr->sin_port)
goto found;
}
@@ -266,11 +269,12 @@ struct nfs_client *nfs_find_client(const struct sockaddr_in *addr, int nfsversio
struct nfs_client *clp;
spin_lock(&nfs_client_lock);
- clp = __nfs_find_client(addr, nfsversion);
+ clp = __nfs_find_client(addr, nfsversion, 0);
spin_unlock(&nfs_client_lock);
-
- BUG_ON(clp && clp->cl_cons_state == 0);
-
+ if (clp != NULL && clp->cl_cons_state != NFS_CS_READY) {
+ nfs_put_client(clp);
+ clp = NULL;
+ }
return clp;
}
@@ -293,7 +297,7 @@ static struct nfs_client *nfs_get_client(const char *hostname,
do {
spin_lock(&nfs_client_lock);
- clp = __nfs_find_client(addr, nfsversion);
+ clp = __nfs_find_client(addr, nfsversion, 1);
if (clp)
goto found_client;
if (new)
@@ -323,25 +327,11 @@ found_client:
if (new)
nfs_free_client(new);
- if (clp->cl_cons_state == NFS_CS_INITING) {
- DECLARE_WAITQUEUE(myself, current);
-
- add_wait_queue(&nfs_client_active_wq, &myself);
-
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current) ||
- clp->cl_cons_state > NFS_CS_READY)
- break;
- schedule();
- }
-
- remove_wait_queue(&nfs_client_active_wq, &myself);
-
- if (signal_pending(current)) {
- nfs_put_client(clp);
- return ERR_PTR(-ERESTARTSYS);
- }
+ error = wait_event_interruptible(nfs_client_active_wq,
+ clp->cl_cons_state != NFS_CS_INITING);
+ if (error < 0) {
+ nfs_put_client(clp);
+ return ERR_PTR(-ERESTARTSYS);
}
if (clp->cl_cons_state < NFS_CS_READY) {
@@ -460,7 +450,8 @@ static int nfs_start_lockd(struct nfs_server *server)
goto out;
if (server->flags & NFS_MOUNT_NONLM)
goto out;
- error = lockd_up();
+ error = lockd_up((server->flags & NFS_MOUNT_TCP) ?
+ IPPROTO_TCP : IPPROTO_UDP);
if (error < 0)
server->flags |= NFS_MOUNT_NONLM;
else
@@ -863,6 +854,7 @@ error:
*/
static int nfs4_init_client(struct nfs_client *clp,
int proto, int timeo, int retrans,
+ const char *ip_addr,
rpc_authflavor_t authflavour)
{
int error;
@@ -879,6 +871,7 @@ static int nfs4_init_client(struct nfs_client *clp,
error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour);
if (error < 0)
goto error;
+ memcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));
error = nfs_idmap_new(clp);
if (error < 0) {
@@ -902,6 +895,7 @@ error:
*/
static int nfs4_set_client(struct nfs_server *server,
const char *hostname, const struct sockaddr_in *addr,
+ const char *ip_addr,
rpc_authflavor_t authflavour,
int proto, int timeo, int retrans)
{
@@ -916,7 +910,7 @@ static int nfs4_set_client(struct nfs_server *server,
error = PTR_ERR(clp);
goto error;
}
- error = nfs4_init_client(clp, proto, timeo, retrans, authflavour);
+ error = nfs4_init_client(clp, proto, timeo, retrans, ip_addr, authflavour);
if (error < 0)
goto error_put;
@@ -985,7 +979,7 @@ struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
return ERR_PTR(-ENOMEM);
/* Get a client record */
- error = nfs4_set_client(server, hostname, addr, authflavour,
+ error = nfs4_set_client(server, hostname, addr, ip_addr, authflavour,
data->proto, data->timeo, data->retrans);
if (error < 0)
goto error;
@@ -1055,6 +1049,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
/* Get a client representation.
* Note: NFSv4 always uses TCP, */
error = nfs4_set_client(server, data->hostname, data->addr,
+ parent_client->cl_ipaddr,
data->authflavor,
parent_server->client->cl_xprt->prot,
parent_client->retrans_timeo,
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 57133678db16..841c99a9b11c 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -20,11 +20,6 @@
#include "delegation.h"
#include "internal.h"
-static struct nfs_delegation *nfs_alloc_delegation(void)
-{
- return (struct nfs_delegation *)kmalloc(sizeof(struct nfs_delegation), GFP_KERNEL);
-}
-
static void nfs_free_delegation(struct nfs_delegation *delegation)
{
if (delegation->cred)
@@ -124,7 +119,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct
if ((nfsi->cache_validity & (NFS_INO_REVAL_PAGECACHE|NFS_INO_INVALID_ATTR)))
__nfs_revalidate_inode(NFS_SERVER(inode), inode);
- delegation = nfs_alloc_delegation();
+ delegation = kmalloc(sizeof(*delegation), GFP_KERNEL);
if (delegation == NULL)
return -ENOMEM;
memcpy(delegation->stateid.data, res->delegation.data,
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 7432f1a43f3d..b34cd16f472f 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -142,12 +142,12 @@ nfs_opendir(struct inode *inode, struct file *filp)
return res;
}
-typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
+typedef __be32 * (*decode_dirent_t)(__be32 *, struct nfs_entry *, int);
typedef struct {
struct file *file;
struct page *page;
unsigned long page_index;
- u32 *ptr;
+ __be32 *ptr;
u64 *dir_cookie;
loff_t current_index;
struct nfs_entry *entry;
@@ -203,8 +203,10 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
* Note: assumes we have exclusive access to this mapping either
* through inode->i_mutex or some other mechanism.
*/
- if (page->index == 0)
- invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1);
+ if (page->index == 0 && invalidate_inode_pages2_range(inode->i_mapping, PAGE_CACHE_SIZE, -1) < 0) {
+ /* Should never happen */
+ nfs_zap_mapping(inode, inode->i_mapping);
+ }
unlock_page(page);
return 0;
error:
@@ -218,7 +220,7 @@ int nfs_readdir_filler(nfs_readdir_descriptor_t *desc, struct page *page)
static inline
int dir_decode(nfs_readdir_descriptor_t *desc)
{
- u32 *p = desc->ptr;
+ __be32 *p = desc->ptr;
p = desc->decode(p, desc->entry, desc->plus);
if (IS_ERR(p))
return PTR_ERR(p);
@@ -843,7 +845,7 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode)
nfs_inode_return_delegation(inode);
if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
lock_kernel();
- inode->i_nlink--;
+ drop_nlink(inode);
nfs_complete_unlink(dentry);
unlock_kernel();
}
@@ -933,8 +935,17 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru
no_entry:
res = d_materialise_unique(dentry, inode);
- if (res != NULL)
+ if (res != NULL) {
+ struct dentry *parent;
+ if (IS_ERR(res))
+ goto out_unlock;
+ /* Was a directory renamed! */
+ parent = dget_parent(res);
+ if (!IS_ROOT(parent))
+ nfs_mark_for_revalidate(parent->d_inode);
+ dput(parent);
dentry = res;
+ }
nfs_renew_times(dentry);
nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
out_unlock:
@@ -1130,6 +1141,8 @@ static struct dentry *nfs_readdir_lookup(nfs_readdir_descriptor_t *desc)
alias = d_materialise_unique(dentry, inode);
if (alias != NULL) {
dput(dentry);
+ if (IS_ERR(alias))
+ return NULL;
dentry = alias;
}
@@ -1286,7 +1299,7 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
/* Ensure the VFS deletes this inode */
if (error == 0 && dentry->d_inode != NULL)
- dentry->d_inode->i_nlink = 0;
+ clear_nlink(dentry->d_inode);
nfs_end_data_update(dir);
unlock_kernel();
@@ -1401,7 +1414,7 @@ static int nfs_safe_remove(struct dentry *dentry)
error = NFS_PROTO(dir)->remove(dir, &dentry->d_name);
/* The VFS may want to delete this inode */
if (error == 0)
- inode->i_nlink--;
+ drop_nlink(inode);
nfs_mark_for_revalidate(inode);
nfs_end_data_update(inode);
} else
@@ -1517,8 +1530,8 @@ static int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *sym
pagevec_init(&lru_pvec, 0);
if (!add_to_page_cache(page, dentry->d_inode->i_mapping, 0,
GFP_KERNEL)) {
- if (!pagevec_add(&lru_pvec, page))
- __pagevec_lru_add(&lru_pvec);
+ pagevec_add(&lru_pvec, page);
+ pagevec_lru_add(&lru_pvec);
SetPageUptodate(page);
unlock_page(page);
} else
@@ -1639,7 +1652,7 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out;
}
} else
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
go_ahead:
/*
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 76ca1cbc38f9..bdfabf854a51 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -497,6 +497,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
if (dreq->commit_data != NULL)
nfs_commit_free(dreq->commit_data);
nfs_direct_free_writedata(dreq);
+ nfs_zap_mapping(inode, inode->i_mapping);
nfs_direct_complete(dreq);
}
}
@@ -517,6 +518,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode
{
nfs_end_data_update(inode);
nfs_direct_free_writedata(dreq);
+ nfs_zap_mapping(inode, inode->i_mapping);
nfs_direct_complete(dreq);
}
#endif
@@ -532,10 +534,12 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
spin_lock(&dreq->lock);
- if (likely(status >= 0))
- dreq->count += data->res.count;
- else
- dreq->error = task->tk_status;
+ if (unlikely(status < 0)) {
+ dreq->error = status;
+ goto out_unlock;
+ }
+
+ dreq->count += data->res.count;
if (data->res.verf->committed != NFS_FILE_SYNC) {
switch (dreq->flags) {
@@ -550,7 +554,7 @@ static void nfs_direct_write_result(struct rpc_task *task, void *calldata)
}
}
}
-
+out_unlock:
spin_unlock(&dreq->lock);
}
@@ -707,8 +711,8 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
/**
* nfs_file_direct_read - file direct read operation for NFS files
* @iocb: target I/O control block
- * @buf: user's buffer into which to read data
- * @count: number of bytes to read
+ * @iov: vector of user buffers into which to read data
+ * @nr_segs: size of iov vector
* @pos: byte offset in file where reading starts
*
* We use this function for direct reads instead of calling
@@ -725,17 +729,24 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, unsigned long user_addr, siz
* client must read the updated atime from the server back into its
* cache.
*/
-ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
+ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
ssize_t retval = -EINVAL;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
+ /* XXX: temporary */
+ const char __user *buf = iov[0].iov_base;
+ size_t count = iov[0].iov_len;
dprintk("nfs: direct read(%s/%s, %lu@%Ld)\n",
file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name,
(unsigned long) count, (long long) pos);
+ if (nr_segs != 1)
+ return -EINVAL;
+
if (count < 0)
goto out;
retval = -EFAULT;
@@ -760,8 +771,8 @@ out:
/**
* nfs_file_direct_write - file direct write operation for NFS files
* @iocb: target I/O control block
- * @buf: user's buffer from which to write data
- * @count: number of bytes to write
+ * @iov: vector of user buffers from which to write data
+ * @nr_segs: size of iov vector
* @pos: byte offset in file where writing starts
*
* We use this function for direct writes instead of calling
@@ -782,17 +793,24 @@ out:
* Note that O_APPEND is not supported for NFS direct writes, as there
* is no atomic O_APPEND write facility in the NFS protocol.
*/
-ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
+ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
ssize_t retval;
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
+ /* XXX: temporary */
+ const char __user *buf = iov[0].iov_base;
+ size_t count = iov[0].iov_len;
dfprintk(VFS, "nfs: direct write(%s/%s, %lu@%Ld)\n",
file->f_dentry->d_parent->d_name.name,
file->f_dentry->d_name.name,
(unsigned long) count, (long long) pos);
+ if (nr_segs != 1)
+ return -EINVAL;
+
retval = generic_write_checks(file, &pos, &count, 0);
if (retval)
goto out;
@@ -814,17 +832,6 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t
retval = nfs_direct_write(iocb, (unsigned long) buf, count, pos);
- /*
- * XXX: nfs_end_data_update() already ensures this file's
- * cached data is subsequently invalidated. Do we really
- * need to call invalidate_inode_pages2() again here?
- *
- * For aio writes, this invalidation will almost certainly
- * occur before the writes complete. Kind of racey.
- */
- if (mapping->nrpages)
- invalidate_inode_pages2(mapping);
-
if (retval > 0)
iocb->ki_pos = pos + retval;
@@ -855,6 +862,5 @@ int __init nfs_init_directcache(void)
*/
void nfs_destroy_directcache(void)
{
- if (kmem_cache_destroy(nfs_direct_cachep))
- printk(KERN_INFO "nfs_direct_cache: not all structures were freed\n");
+ kmem_cache_destroy(nfs_direct_cachep);
}
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index be997d649127..cc93865cea93 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -41,8 +41,10 @@ static int nfs_file_release(struct inode *, struct file *);
static loff_t nfs_file_llseek(struct file *file, loff_t offset, int origin);
static int nfs_file_mmap(struct file *, struct vm_area_struct *);
static ssize_t nfs_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
-static ssize_t nfs_file_read(struct kiocb *, char __user *, size_t, loff_t);
-static ssize_t nfs_file_write(struct kiocb *, const char __user *, size_t, loff_t);
+static ssize_t nfs_file_read(struct kiocb *, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
+static ssize_t nfs_file_write(struct kiocb *, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
static int nfs_file_flush(struct file *, fl_owner_t id);
static int nfs_fsync(struct file *, struct dentry *dentry, int datasync);
static int nfs_check_flags(int flags);
@@ -53,8 +55,8 @@ const struct file_operations nfs_file_operations = {
.llseek = nfs_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
- .aio_read = nfs_file_read,
- .aio_write = nfs_file_write,
+ .aio_read = nfs_file_read,
+ .aio_write = nfs_file_write,
.mmap = nfs_file_mmap,
.open = nfs_file_open,
.flush = nfs_file_flush,
@@ -196,15 +198,17 @@ nfs_file_flush(struct file *file, fl_owner_t id)
}
static ssize_t
-nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
+nfs_file_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct dentry * dentry = iocb->ki_filp->f_dentry;
struct inode * inode = dentry->d_inode;
ssize_t result;
+ size_t count = iov_length(iov, nr_segs);
#ifdef CONFIG_NFS_DIRECTIO
if (iocb->ki_filp->f_flags & O_DIRECT)
- return nfs_file_direct_read(iocb, buf, count, pos);
+ return nfs_file_direct_read(iocb, iov, nr_segs, pos);
#endif
dfprintk(VFS, "nfs: read(%s/%s, %lu@%lu)\n",
@@ -214,7 +218,7 @@ nfs_file_read(struct kiocb *iocb, char __user * buf, size_t count, loff_t pos)
result = nfs_revalidate_mapping(inode, iocb->ki_filp->f_mapping);
nfs_add_stats(inode, NFSIOS_NORMALREADBYTES, count);
if (!result)
- result = generic_file_aio_read(iocb, buf, count, pos);
+ result = generic_file_aio_read(iocb, iov, nr_segs, pos);
return result;
}
@@ -336,24 +340,22 @@ const struct address_space_operations nfs_file_aops = {
#endif
};
-/*
- * Write to a file (through the page cache).
- */
-static ssize_t
-nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t pos)
+static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct dentry * dentry = iocb->ki_filp->f_dentry;
struct inode * inode = dentry->d_inode;
ssize_t result;
+ size_t count = iov_length(iov, nr_segs);
#ifdef CONFIG_NFS_DIRECTIO
if (iocb->ki_filp->f_flags & O_DIRECT)
- return nfs_file_direct_write(iocb, buf, count, pos);
+ return nfs_file_direct_write(iocb, iov, nr_segs, pos);
#endif
- dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%lu)\n",
+ dfprintk(VFS, "nfs: write(%s/%s(%ld), %lu@%Ld)\n",
dentry->d_parent->d_name.name, dentry->d_name.name,
- inode->i_ino, (unsigned long) count, (unsigned long) pos);
+ inode->i_ino, (unsigned long) count, (long long) pos);
result = -EBUSY;
if (IS_SWAPFILE(inode))
@@ -372,7 +374,7 @@ nfs_file_write(struct kiocb *iocb, const char __user *buf, size_t count, loff_t
goto out;
nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count);
- result = generic_file_aio_write(iocb, buf, count, pos);
+ result = generic_file_aio_write(iocb, iov, nr_segs, pos);
out:
return result;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 76b08ae9ed82..20c6f39ea38a 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -9,7 +9,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index e8c143d182c4..08cc4c5919ab 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -131,6 +131,15 @@ void nfs_zap_caches(struct inode *inode)
spin_unlock(&inode->i_lock);
}
+void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
+{
+ if (mapping->nrpages != 0) {
+ spin_lock(&inode->i_lock);
+ NFS_I(inode)->cache_validity |= NFS_INO_INVALID_DATA;
+ spin_unlock(&inode->i_lock);
+ }
+}
+
static void nfs_zap_acl_cache(struct inode *inode)
{
void (*clear_acl_cache)(struct inode *);
@@ -277,10 +286,8 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr)
* report the blocks in 512byte units
*/
inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
- inode->i_blksize = inode->i_sb->s_blocksize;
} else {
inode->i_blocks = fattr->du.nfs2.blocks;
- inode->i_blksize = fattr->du.nfs2.blocksize;
}
nfsi->attrtimeo = NFS_MINATTRTIMEO(inode);
nfsi->attrtimeo_timestamp = jiffies;
@@ -443,7 +450,7 @@ static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, str
{
struct nfs_open_context *ctx;
- ctx = (struct nfs_open_context *)kmalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) {
atomic_set(&ctx->count, 1);
ctx->dentry = dget(dentry);
@@ -576,7 +583,7 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
nfs_inc_stats(inode, NFSIOS_INODEREVALIDATE);
lock_kernel();
- if (!inode || is_bad_inode(inode))
+ if (is_bad_inode(inode))
goto out_nowait;
if (NFS_STALE(inode))
goto out_nowait;
@@ -673,13 +680,20 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
|| nfs_attribute_timeout(inode))
ret = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
+ if (ret < 0)
+ goto out;
if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
- nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
- if (S_ISREG(inode->i_mode))
- nfs_sync_mapping(mapping);
- invalidate_inode_pages2(mapping);
-
+ if (mapping->nrpages != 0) {
+ if (S_ISREG(inode->i_mode)) {
+ ret = nfs_sync_mapping(mapping);
+ if (ret < 0)
+ goto out;
+ }
+ ret = invalidate_inode_pages2(mapping);
+ if (ret < 0)
+ goto out;
+ }
spin_lock(&inode->i_lock);
nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
if (S_ISDIR(inode->i_mode)) {
@@ -689,10 +703,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
}
spin_unlock(&inode->i_lock);
+ nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
inode->i_sb->s_id,
(long long)NFS_FILEID(inode));
}
+out:
return ret;
}
@@ -969,10 +985,8 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
* report the blocks in 512byte units
*/
inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
- inode->i_blksize = inode->i_sb->s_blocksize;
} else {
inode->i_blocks = fattr->du.nfs2.blocks;
- inode->i_blksize = fattr->du.nfs2.blocksize;
}
if ((fattr->valid & NFS_ATTR_FATTR_V4) != 0 &&
@@ -1134,8 +1148,7 @@ static int __init nfs_init_inodecache(void)
static void nfs_destroy_inodecache(void)
{
- if (kmem_cache_destroy(nfs_inode_cachep))
- printk(KERN_INFO "nfs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(nfs_inode_cachep);
}
/*
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index bea0b016bd70..d205466233f6 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -93,15 +93,15 @@ extern void nfs_destroy_directcache(void);
/* nfs2xdr.c */
extern int nfs_stat_to_errno(int);
extern struct rpc_procinfo nfs_procedures[];
-extern u32 * nfs_decode_dirent(u32 *, struct nfs_entry *, int);
+extern __be32 * nfs_decode_dirent(__be32 *, struct nfs_entry *, int);
/* nfs3xdr.c */
extern struct rpc_procinfo nfs3_procedures[];
-extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
+extern __be32 *nfs3_decode_dirent(__be32 *, struct nfs_entry *, int);
/* nfs4xdr.c */
#ifdef CONFIG_NFS_V4
-extern u32 *nfs4_decode_dirent(u32 *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
#endif
/* nfs4proc.c */
diff --git a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
index d507b021207f..f75fe72b4160 100644
--- a/fs/nfs/mount_clnt.c
+++ b/fs/nfs/mount_clnt.c
@@ -95,7 +95,7 @@ mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
* XDR encode/decode functions for MOUNT
*/
static int
-xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
+xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, const char *path)
{
p = xdr_encode_string(p, path);
@@ -104,7 +104,7 @@ xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
}
static int
-xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
{
struct nfs_fh *fh = res->fh;
@@ -116,7 +116,7 @@ xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
}
static int
-xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, struct mnt_fhstatus *res)
{
struct nfs_fh *fh = res->fh;
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 77b00684894d..ec1114b33d89 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -7,8 +7,6 @@
* NFS namespace
*/
-#include <linux/config.h>
-
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/namei.h>
@@ -26,6 +24,11 @@ LIST_HEAD(nfs_automount_list);
static DECLARE_WORK(nfs_automount_task, nfs_expire_automounts, &nfs_automount_list);
int nfs_mountpoint_expiry_timeout = 500 * HZ;
+static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+ const struct dentry *dentry,
+ struct nfs_fh *fh,
+ struct nfs_fattr *fattr);
+
/*
* nfs_path - reconstruct the path given an arbitrary dentry
* @base - arbitrary string to prepend to the path
@@ -209,9 +212,10 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server,
* @fattr - attributes for new root inode
*
*/
-struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
- const struct dentry *dentry, struct nfs_fh *fh,
- struct nfs_fattr *fattr)
+static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
+ const struct dentry *dentry,
+ struct nfs_fh *fh,
+ struct nfs_fattr *fattr)
{
struct nfs_clone_mount mountdata = {
.sb = mnt_parent->mnt_sb,
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index b49501fc0a79..3be4e72a0227 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -66,15 +66,15 @@
/*
* Common NFS XDR functions as inlines
*/
-static inline u32 *
-xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
+static inline __be32 *
+xdr_encode_fhandle(__be32 *p, struct nfs_fh *fhandle)
{
memcpy(p, fhandle->data, NFS2_FHSIZE);
return p + XDR_QUADLEN(NFS2_FHSIZE);
}
-static inline u32 *
-xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
+static inline __be32 *
+xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
{
/* NFSv2 handles have a fixed length */
fhandle->size = NFS2_FHSIZE;
@@ -82,8 +82,8 @@ xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
return p + XDR_QUADLEN(NFS2_FHSIZE);
}
-static inline u32*
-xdr_encode_time(u32 *p, struct timespec *timep)
+static inline __be32*
+xdr_encode_time(__be32 *p, struct timespec *timep)
{
*p++ = htonl(timep->tv_sec);
/* Convert nanoseconds into microseconds */
@@ -91,8 +91,8 @@ xdr_encode_time(u32 *p, struct timespec *timep)
return p;
}
-static inline u32*
-xdr_encode_current_server_time(u32 *p, struct timespec *timep)
+static inline __be32*
+xdr_encode_current_server_time(__be32 *p, struct timespec *timep)
{
/*
* Passing the invalid value useconds=1000000 is a
@@ -108,8 +108,8 @@ xdr_encode_current_server_time(u32 *p, struct timespec *timep)
return p;
}
-static inline u32*
-xdr_decode_time(u32 *p, struct timespec *timep)
+static inline __be32*
+xdr_decode_time(__be32 *p, struct timespec *timep)
{
timep->tv_sec = ntohl(*p++);
/* Convert microseconds into nanoseconds */
@@ -117,8 +117,8 @@ xdr_decode_time(u32 *p, struct timespec *timep)
return p;
}
-static u32 *
-xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
+static __be32 *
+xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
{
u32 rdev;
fattr->type = (enum nfs_ftype) ntohl(*p++);
@@ -146,10 +146,10 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
return p;
}
-static inline u32 *
-xdr_encode_sattr(u32 *p, struct iattr *attr)
+static inline __be32 *
+xdr_encode_sattr(__be32 *p, struct iattr *attr)
{
- const u32 not_set = __constant_htonl(0xFFFFFFFF);
+ const __be32 not_set = __constant_htonl(0xFFFFFFFF);
*p++ = (attr->ia_valid & ATTR_MODE) ? htonl(attr->ia_mode) : not_set;
*p++ = (attr->ia_valid & ATTR_UID) ? htonl(attr->ia_uid) : not_set;
@@ -184,7 +184,7 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
* GETATTR, READLINK, STATFS
*/
static int
-nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
+nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
{
p = xdr_encode_fhandle(p, fh);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -195,7 +195,7 @@ nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
* Encode SETATTR arguments
*/
static int
-nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
+nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_sattr(p, args->sattr);
@@ -208,7 +208,7 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
* LOOKUP, REMOVE, RMDIR
*/
static int
-nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
+nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name, args->len);
@@ -222,7 +222,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
* exactly to the page we want to fetch.
*/
static int
-nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
+nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int replen;
@@ -246,7 +246,7 @@ nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
* Decode READ reply
*/
static int
-nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
+nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
{
struct kvec *iov = req->rq_rcv_buf.head;
int status, count, recvd, hdrlen;
@@ -286,7 +286,7 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
* Write arguments. Splice the buffer to be written into the iovec.
*/
static int
-nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
{
struct xdr_buf *sndbuf = &req->rq_snd_buf;
u32 offset = (u32)args->offset;
@@ -309,7 +309,7 @@ nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
* CREATE, MKDIR
*/
static int
-nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
+nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name, args->len);
@@ -322,7 +322,7 @@ nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
* Encode RENAME arguments
*/
static int
-nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
+nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_array(p, args->fromname, args->fromlen);
@@ -336,7 +336,7 @@ nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
* Encode LINK arguments
*/
static int
-nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
+nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_fhandle(p, args->tofh);
@@ -349,7 +349,7 @@ nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
* Encode SYMLINK arguments
*/
static int
-nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
+nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *args)
{
struct xdr_buf *sndbuf = &req->rq_snd_buf;
size_t pad;
@@ -378,7 +378,7 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
* Encode arguments to readdir call
*/
static int
-nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
+nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *args)
{
struct rpc_task *task = req->rq_task;
struct rpc_auth *auth = task->tk_auth;
@@ -404,7 +404,7 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
* from nfs_readdir for each entry.
*/
static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
@@ -412,7 +412,7 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
int hdrlen, recvd;
int status, nr;
unsigned int len, pglen;
- u32 *end, *entry, *kaddr;
+ __be32 *end, *entry, *kaddr;
if ((status = ntohl(*p++)))
return -nfs_stat_to_errno(status);
@@ -432,8 +432,8 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, void *dummy)
if (pglen > recvd)
pglen = recvd;
page = rcvbuf->pages;
- kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
- end = (u32 *)((char *)p + pglen);
+ kaddr = p = kmap_atomic(*page, KM_USER0);
+ end = (__be32 *)((char *)p + pglen);
entry = p;
for (nr = 0; *p++; nr++) {
if (p + 2 > end)
@@ -468,8 +468,8 @@ err_unmap:
goto out;
}
-u32 *
-nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+__be32 *
+nfs_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
{
if (!*p++) {
if (!*p)
@@ -496,7 +496,7 @@ nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
* Decode simple status reply
*/
static int
-nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
{
int status;
@@ -510,7 +510,7 @@ nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
* GETATTR, SETATTR, WRITE
*/
static int
-nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
{
int status;
@@ -525,7 +525,7 @@ nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
* LOOKUP, CREATE, MKDIR
*/
static int
-nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
+nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
{
int status;
@@ -540,7 +540,7 @@ nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
* Encode READLINK args
*/
static int
-nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
+nfs_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_readlinkargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int replen;
@@ -558,7 +558,7 @@ nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args
* Decode READLINK reply
*/
static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
@@ -601,7 +601,7 @@ nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, void *dummy)
* Decode WRITE reply
*/
static int
-nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
{
res->verf->committed = NFS_FILE_SYNC;
return nfs_xdr_attrstat(req, p, res->fattr);
@@ -611,7 +611,7 @@ nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
* Decode STATFS reply
*/
static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs2_fsstat *res)
+nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
{
int status;
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index f8688eaa0001..e5f128ffc32d 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -449,7 +449,7 @@ nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr
struct nfs_fattr res;
} *ptr;
- ptr = (struct unlinkxdr *)kmalloc(sizeof(*ptr), GFP_KERNEL);
+ ptr = kmalloc(sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ptr->arg.fh = NFS_FH(dir->d_inode);
@@ -668,7 +668,7 @@ nfs3_proc_readdir(struct dentry *dentry, struct rpc_cred *cred,
{
struct inode *dir = dentry->d_inode;
struct nfs_fattr dir_attr;
- u32 *verf = NFS_COOKIEVERF(dir);
+ __be32 *verf = NFS_COOKIEVERF(dir);
struct nfs3_readdirargs arg = {
.fh = NFS_FH(dir),
.cookie = cookie,
diff --git a/fs/nfs/nfs3xdr.c b/fs/nfs/nfs3xdr.c
index 16556fa4effb..0ace092d126f 100644
--- a/fs/nfs/nfs3xdr.c
+++ b/fs/nfs/nfs3xdr.c
@@ -105,14 +105,14 @@ static struct {
/*
* Common NFS XDR functions as inlines
*/
-static inline u32 *
-xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
+static inline __be32 *
+xdr_encode_fhandle(__be32 *p, struct nfs_fh *fh)
{
return xdr_encode_array(p, fh->data, fh->size);
}
-static inline u32 *
-xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
+static inline __be32 *
+xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
{
if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
memcpy(fh->data, p, fh->size);
@@ -124,24 +124,24 @@ xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
/*
* Encode/decode time.
*/
-static inline u32 *
-xdr_encode_time3(u32 *p, struct timespec *timep)
+static inline __be32 *
+xdr_encode_time3(__be32 *p, struct timespec *timep)
{
*p++ = htonl(timep->tv_sec);
*p++ = htonl(timep->tv_nsec);
return p;
}
-static inline u32 *
-xdr_decode_time3(u32 *p, struct timespec *timep)
+static inline __be32 *
+xdr_decode_time3(__be32 *p, struct timespec *timep)
{
timep->tv_sec = ntohl(*p++);
timep->tv_nsec = ntohl(*p++);
return p;
}
-static u32 *
-xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
+static __be32 *
+xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
{
unsigned int type, major, minor;
int fmode;
@@ -177,8 +177,8 @@ xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
return p;
}
-static inline u32 *
-xdr_encode_sattr(u32 *p, struct iattr *attr)
+static inline __be32 *
+xdr_encode_sattr(__be32 *p, struct iattr *attr)
{
if (attr->ia_valid & ATTR_MODE) {
*p++ = xdr_one;
@@ -223,8 +223,8 @@ xdr_encode_sattr(u32 *p, struct iattr *attr)
return p;
}
-static inline u32 *
-xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
{
p = xdr_decode_hyper(p, &fattr->pre_size);
p = xdr_decode_time3(p, &fattr->pre_mtime);
@@ -233,16 +233,16 @@ xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
return p;
}
-static inline u32 *
-xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
{
if (*p++)
p = xdr_decode_fattr(p, fattr);
return p;
}
-static inline u32 *
-xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
{
if (*p++)
return xdr_decode_wcc_attr(p, fattr);
@@ -250,8 +250,8 @@ xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
}
-static inline u32 *
-xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
+static inline __be32 *
+xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
{
p = xdr_decode_pre_op_attr(p, fattr);
return xdr_decode_post_op_attr(p, fattr);
@@ -265,7 +265,7 @@ xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
* Encode file handle argument
*/
static int
-nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
+nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
{
p = xdr_encode_fhandle(p, fh);
req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -276,7 +276,7 @@ nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
* Encode SETATTR arguments
*/
static int
-nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
+nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_sattr(p, args->sattr);
@@ -291,7 +291,7 @@ nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
* Encode directory ops argument
*/
static int
-nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
+nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name, args->len);
@@ -303,7 +303,7 @@ nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
* Encode access() argument
*/
static int
-nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
+nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
*p++ = htonl(args->access);
@@ -317,7 +317,7 @@ nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
* exactly to the page we want to fetch.
*/
static int
-nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
+nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int replen;
@@ -339,7 +339,7 @@ nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
* Write arguments. Splice the buffer to be written into the iovec.
*/
static int
-nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
{
struct xdr_buf *sndbuf = &req->rq_snd_buf;
u32 count = args->count;
@@ -360,7 +360,7 @@ nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
* Encode CREATE arguments
*/
static int
-nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
+nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name, args->len);
@@ -380,7 +380,7 @@ nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
* Encode MKDIR arguments
*/
static int
-nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
+nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name, args->len);
@@ -393,7 +393,7 @@ nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
* Encode SYMLINK arguments
*/
static int
-nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
+nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_array(p, args->fromname, args->fromlen);
@@ -410,7 +410,7 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args
* Encode MKNOD arguments
*/
static int
-nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
+nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_array(p, args->name, args->len);
@@ -429,7 +429,7 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
* Encode RENAME arguments
*/
static int
-nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
+nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_array(p, args->fromname, args->fromlen);
@@ -443,7 +443,7 @@ nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
* Encode LINK arguments
*/
static int
-nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
+nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
{
p = xdr_encode_fhandle(p, args->fromfh);
p = xdr_encode_fhandle(p, args->tofh);
@@ -456,7 +456,7 @@ nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
* Encode arguments to readdir call
*/
static int
-nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
+nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int replen;
@@ -485,7 +485,7 @@ nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args
* We just check for syntactical correctness.
*/
static int
-nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
+nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
@@ -493,7 +493,7 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
int hdrlen, recvd;
int status, nr;
unsigned int len, pglen;
- u32 *entry, *end, *kaddr;
+ __be32 *entry, *end, *kaddr;
status = ntohl(*p++);
/* Decode post_op_attrs */
@@ -523,8 +523,8 @@ nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
if (pglen > recvd)
pglen = recvd;
page = rcvbuf->pages;
- kaddr = p = (u32 *)kmap_atomic(*page, KM_USER0);
- end = (u32 *)((char *)p + pglen);
+ kaddr = p = kmap_atomic(*page, KM_USER0);
+ end = (__be32 *)((char *)p + pglen);
entry = p;
for (nr = 0; *p++; nr++) {
if (p + 3 > end)
@@ -583,8 +583,8 @@ err_unmap:
goto out;
}
-u32 *
-nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+__be32 *
+nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
{
struct nfs_entry old = *entry;
@@ -626,7 +626,7 @@ nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
* Encode COMMIT arguments
*/
static int
-nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
{
p = xdr_encode_fhandle(p, args->fh);
p = xdr_encode_hyper(p, args->offset);
@@ -640,7 +640,7 @@ nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
* Encode GETACL arguments
*/
static int
-nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
+nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
struct nfs3_getaclargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
@@ -664,7 +664,7 @@ nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
* Encode SETACL arguments
*/
static int
-nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
+nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
struct nfs3_setaclargs *args)
{
struct xdr_buf *buf = &req->rq_snd_buf;
@@ -711,7 +711,7 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
* Decode attrstat reply.
*/
static int
-nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
{
int status;
@@ -726,7 +726,7 @@ nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
* SATTR, REMOVE, RMDIR
*/
static int
-nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
{
int status;
@@ -740,7 +740,7 @@ nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
* Decode LOOKUP reply
*/
static int
-nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
+nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
{
int status;
@@ -759,7 +759,7 @@ nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
* Decode ACCESS reply
*/
static int
-nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
+nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
{
int status = ntohl(*p++);
@@ -771,7 +771,7 @@ nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
}
static int
-nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
+nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int replen;
@@ -789,7 +789,7 @@ nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *ar
* Decode READLINK reply
*/
static int
-nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
{
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
@@ -837,7 +837,7 @@ nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
* Decode READ reply
*/
static int
-nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
+nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
{
struct kvec *iov = req->rq_rcv_buf.head;
int status, count, ocount, recvd, hdrlen;
@@ -888,7 +888,7 @@ nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
* Decode WRITE response
*/
static int
-nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
{
int status;
@@ -910,7 +910,7 @@ nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
* Decode a CREATE response
*/
static int
-nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
+nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
{
int status;
@@ -937,7 +937,7 @@ nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
* Decode RENAME reply
*/
static int
-nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
+nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
{
int status;
@@ -952,7 +952,7 @@ nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
* Decode LINK reply
*/
static int
-nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
+nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
{
int status;
@@ -967,7 +967,7 @@ nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
* Decode FSSTAT reply
*/
static int
-nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
+nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
{
int status;
@@ -992,7 +992,7 @@ nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsstat *res)
* Decode FSINFO reply
*/
static int
-nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
{
int status;
@@ -1020,7 +1020,7 @@ nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
* Decode PATHCONF reply
*/
static int
-nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
+nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
{
int status;
@@ -1040,7 +1040,7 @@ nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_pathconf *res)
* Decode COMMIT reply
*/
static int
-nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
{
int status;
@@ -1059,7 +1059,7 @@ nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
* Decode GETACL reply
*/
static int
-nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
+nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
struct nfs3_getaclres *res)
{
struct xdr_buf *buf = &req->rq_rcv_buf;
@@ -1091,7 +1091,7 @@ nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
* Decode setacl reply.
*/
static int
-nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
{
int status = ntohl(*p++);
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 61095fe4b5ca..6f346677332d 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -212,7 +212,7 @@ extern void nfs_free_seqid(struct nfs_seqid *seqid);
extern const nfs4_stateid zero_stateid;
/* nfs4xdr.c */
-extern uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus);
+extern __be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus);
extern struct rpc_procinfo nfs4_procedures[];
struct nfs4_mount_data;
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 24e47f3bbd17..b872779d7cd5 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -7,8 +7,6 @@
* NFSv4 namespace
*/
-#include <linux/config.h>
-
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/namei.h>
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 47c7e6e3910d..8118036cc449 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -138,10 +138,10 @@ const u32 nfs4_fs_locations_bitmap[2] = {
| FATTR4_WORD1_MOUNTED_ON_FILEID
};
-static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
+static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dentry,
struct nfs4_readdir_arg *readdir)
{
- u32 *start, *p;
+ __be32 *start, *p;
BUG_ON(readdir->count < 80);
if (cookie > 2) {
@@ -162,7 +162,7 @@ static void nfs4_setup_readdir(u64 cookie, u32 *verifier, struct dentry *dentry,
* when talking to the server, we always send cookie 0
* instead of 1 or 2.
*/
- start = p = (u32 *)kmap_atomic(*readdir->pages, KM_USER0);
+ start = p = kmap_atomic(*readdir->pages, KM_USER0);
if (cookie == 0) {
*p++ = xdr_one; /* next */
@@ -1314,11 +1314,9 @@ nfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags, st
case -EROFS:
lookup_instantiate_filp(nd, (struct dentry *)state, NULL);
return 1;
- case -ENOENT:
- if (dentry->d_inode == NULL)
- return 1;
+ default:
+ goto out_drop;
}
- goto out_drop;
}
if (state->inode == dentry->d_inode) {
nfs4_intent_set_file(nd, dentry, state);
@@ -2917,11 +2915,11 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, unsigned short po
.rpc_resp = clp,
.rpc_cred = cred,
};
- u32 *p;
+ __be32 *p;
int loop = 0;
int status;
- p = (u32*)sc_verifier.data;
+ p = (__be32*)sc_verifier.data;
*p++ = htonl((u32)clp->cl_boot_time.tv_sec);
*p = htonl((u32)clp->cl_boot_time.tv_nsec);
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 3dd413f52da1..0cf3fa312a33 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -471,7 +471,7 @@ struct compound_hdr {
static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *str)
{
- uint32_t *p;
+ __be32 *p;
p = xdr_reserve_space(xdr, 4 + len);
BUG_ON(p == NULL);
@@ -480,7 +480,7 @@ static void encode_string(struct xdr_stream *xdr, unsigned int len, const char *
static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
- uint32_t *p;
+ __be32 *p;
dprintk("encode_compound: tag=%.*s\n", (int)hdr->taglen, hdr->tag);
BUG_ON(hdr->taglen > NFS4_MAXTAGLEN);
@@ -494,7 +494,7 @@ static int encode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *verf)
{
- uint32_t *p;
+ __be32 *p;
p = xdr_reserve_space(xdr, NFS4_VERIFIER_SIZE);
BUG_ON(p == NULL);
@@ -507,8 +507,8 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
char owner_group[IDMAP_NAMESZ];
int owner_namelen = 0;
int owner_grouplen = 0;
- uint32_t *p;
- uint32_t *q;
+ __be32 *p;
+ __be32 *q;
int len;
uint32_t bmval0 = 0;
uint32_t bmval1 = 0;
@@ -630,7 +630,7 @@ static int encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const s
static int encode_access(struct xdr_stream *xdr, u32 access)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8);
WRITE32(OP_ACCESS);
@@ -641,7 +641,7 @@ static int encode_access(struct xdr_stream *xdr, u32 access)
static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8+sizeof(arg->stateid->data));
WRITE32(OP_CLOSE);
@@ -653,7 +653,7 @@ static int encode_close(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *args)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(16);
WRITE32(OP_COMMIT);
@@ -665,7 +665,7 @@ static int encode_commit(struct xdr_stream *xdr, const struct nfs_writeargs *arg
static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *create)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8);
WRITE32(OP_CREATE);
@@ -697,7 +697,7 @@ static int encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg *c
static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(12);
WRITE32(OP_GETATTR);
@@ -708,7 +708,7 @@ static int encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap)
static int encode_getattr_two(struct xdr_stream *xdr, uint32_t bm0, uint32_t bm1)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(16);
WRITE32(OP_GETATTR);
@@ -740,7 +740,7 @@ static int encode_fs_locations(struct xdr_stream *xdr, const u32* bitmask)
static int encode_getfh(struct xdr_stream *xdr)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_GETFH);
@@ -750,7 +750,7 @@ static int encode_getfh(struct xdr_stream *xdr)
static int encode_link(struct xdr_stream *xdr, const struct qstr *name)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8 + name->len);
WRITE32(OP_LINK);
@@ -780,7 +780,7 @@ static inline uint64_t nfs4_lock_length(struct file_lock *fl)
*/
static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(32);
WRITE32(OP_LOCK);
@@ -809,7 +809,7 @@ static int encode_lock(struct xdr_stream *xdr, const struct nfs_lock_args *args)
static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *args)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(40);
WRITE32(OP_LOCKT);
@@ -825,7 +825,7 @@ static int encode_lockt(struct xdr_stream *xdr, const struct nfs_lockt_args *arg
static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *args)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(44);
WRITE32(OP_LOCKU);
@@ -841,7 +841,7 @@ static int encode_locku(struct xdr_stream *xdr, const struct nfs_locku_args *arg
static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
{
int len = name->len;
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8 + len);
WRITE32(OP_LOOKUP);
@@ -853,7 +853,7 @@ static int encode_lookup(struct xdr_stream *xdr, const struct qstr *name)
static void encode_share_access(struct xdr_stream *xdr, int open_flags)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8);
switch (open_flags & (FMODE_READ|FMODE_WRITE)) {
@@ -874,7 +874,7 @@ static void encode_share_access(struct xdr_stream *xdr, int open_flags)
static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
- uint32_t *p;
+ __be32 *p;
/*
* opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
* owner 4 = 32
@@ -891,7 +891,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
switch(arg->open_flags & O_EXCL) {
@@ -907,7 +907,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op
static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *arg)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
switch (arg->open_flags & O_CREAT) {
@@ -923,7 +923,7 @@ static void encode_opentype(struct xdr_stream *xdr, const struct nfs_openargs *a
static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation_type)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
switch (delegation_type) {
@@ -943,7 +943,7 @@ static inline void encode_delegation_type(struct xdr_stream *xdr, int delegation
static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *name)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(NFS4_OPEN_CLAIM_NULL);
@@ -952,7 +952,7 @@ static inline void encode_claim_null(struct xdr_stream *xdr, const struct qstr *
static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
@@ -961,7 +961,7 @@ static inline void encode_claim_previous(struct xdr_stream *xdr, int type)
static inline void encode_claim_delegate_cur(struct xdr_stream *xdr, const struct qstr *name, const nfs4_stateid *stateid)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4+sizeof(stateid->data));
WRITE32(NFS4_OPEN_CLAIM_DELEGATE_CUR);
@@ -991,7 +991,7 @@ static int encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg)
static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_confirmargs *arg)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8+sizeof(arg->stateid->data));
WRITE32(OP_OPEN_CONFIRM);
@@ -1003,7 +1003,7 @@ static int encode_open_confirm(struct xdr_stream *xdr, const struct nfs_open_con
static int encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_closeargs *arg)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8+sizeof(arg->stateid->data));
WRITE32(OP_OPEN_DOWNGRADE);
@@ -1017,7 +1017,7 @@ static int
encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
{
int len = fh->size;
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8 + len);
WRITE32(OP_PUTFH);
@@ -1029,7 +1029,7 @@ encode_putfh(struct xdr_stream *xdr, const struct nfs_fh *fh)
static int encode_putrootfh(struct xdr_stream *xdr)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_PUTROOTFH);
@@ -1040,7 +1040,7 @@ static int encode_putrootfh(struct xdr_stream *xdr)
static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx)
{
nfs4_stateid stateid;
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(16);
if (ctx->state != NULL) {
@@ -1052,7 +1052,7 @@ static void encode_stateid(struct xdr_stream *xdr, const struct nfs_open_context
static int encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_READ);
@@ -1074,7 +1074,7 @@ static int encode_readdir(struct xdr_stream *xdr, const struct nfs4_readdir_arg
FATTR4_WORD1_MOUNTED_ON_FILEID,
};
int replen;
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(32+sizeof(nfs4_verifier));
WRITE32(OP_READDIR);
@@ -1116,7 +1116,7 @@ static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *r
{
struct rpc_auth *auth = req->rq_task->tk_auth;
unsigned int replen;
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_READLINK);
@@ -1134,7 +1134,7 @@ static int encode_readlink(struct xdr_stream *xdr, const struct nfs4_readlink *r
static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8 + name->len);
WRITE32(OP_REMOVE);
@@ -1146,7 +1146,7 @@ static int encode_remove(struct xdr_stream *xdr, const struct qstr *name)
static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, const struct qstr *newname)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(8 + oldname->len);
WRITE32(OP_RENAME);
@@ -1162,7 +1162,7 @@ static int encode_rename(struct xdr_stream *xdr, const struct qstr *oldname, con
static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_stateid)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(12);
WRITE32(OP_RENEW);
@@ -1174,7 +1174,7 @@ static int encode_renew(struct xdr_stream *xdr, const struct nfs_client *client_
static int
encode_restorefh(struct xdr_stream *xdr)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_RESTOREFH);
@@ -1185,7 +1185,7 @@ encode_restorefh(struct xdr_stream *xdr)
static int
encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4+sizeof(zero_stateid.data));
WRITE32(OP_SETATTR);
@@ -1204,7 +1204,7 @@ encode_setacl(struct xdr_stream *xdr, struct nfs_setaclargs *arg)
static int
encode_savefh(struct xdr_stream *xdr)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_SAVEFH);
@@ -1215,7 +1215,7 @@ encode_savefh(struct xdr_stream *xdr)
static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *arg, const struct nfs_server *server)
{
int status;
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4+sizeof(arg->stateid.data));
WRITE32(OP_SETATTR);
@@ -1229,7 +1229,7 @@ static int encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs *
static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4 + sizeof(setclientid->sc_verifier->data));
WRITE32(OP_SETCLIENTID);
@@ -1248,7 +1248,7 @@ static int encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclien
static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_client *client_state)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(12 + sizeof(client_state->cl_confirm.data));
WRITE32(OP_SETCLIENTID_CONFIRM);
@@ -1260,7 +1260,7 @@ static int encode_setclientid_confirm(struct xdr_stream *xdr, const struct nfs_c
static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(4);
WRITE32(OP_WRITE);
@@ -1279,7 +1279,7 @@ static int encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *args
static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *stateid)
{
- uint32_t *p;
+ __be32 *p;
RESERVE_SPACE(20);
@@ -1295,7 +1295,7 @@ static int encode_delegreturn(struct xdr_stream *xdr, const nfs4_stateid *statei
/*
* Encode an ACCESS request
*/
-static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct nfs4_accessargs *args)
+static int nfs4_xdr_enc_access(struct rpc_rqst *req, __be32 *p, const struct nfs4_accessargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1313,7 +1313,7 @@ static int nfs4_xdr_enc_access(struct rpc_rqst *req, uint32_t *p, const struct n
/*
* Encode LOOKUP request
*/
-static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_arg *args)
+static int nfs4_xdr_enc_lookup(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1337,7 +1337,7 @@ out:
/*
* Encode LOOKUP_ROOT request
*/
-static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, uint32_t *p, const struct nfs4_lookup_root_arg *args)
+static int nfs4_xdr_enc_lookup_root(struct rpc_rqst *req, __be32 *p, const struct nfs4_lookup_root_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1358,7 +1358,7 @@ out:
/*
* Encode REMOVE request
*/
-static int nfs4_xdr_enc_remove(struct rpc_rqst *req, uint32_t *p, const struct nfs4_remove_arg *args)
+static int nfs4_xdr_enc_remove(struct rpc_rqst *req, __be32 *p, const struct nfs4_remove_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1380,7 +1380,7 @@ out:
/*
* Encode RENAME request
*/
-static int nfs4_xdr_enc_rename(struct rpc_rqst *req, uint32_t *p, const struct nfs4_rename_arg *args)
+static int nfs4_xdr_enc_rename(struct rpc_rqst *req, __be32 *p, const struct nfs4_rename_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1410,7 +1410,7 @@ out:
/*
* Encode LINK request
*/
-static int nfs4_xdr_enc_link(struct rpc_rqst *req, uint32_t *p, const struct nfs4_link_arg *args)
+static int nfs4_xdr_enc_link(struct rpc_rqst *req, __be32 *p, const struct nfs4_link_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1440,7 +1440,7 @@ out:
/*
* Encode CREATE request
*/
-static int nfs4_xdr_enc_create(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+static int nfs4_xdr_enc_create(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1470,7 +1470,7 @@ out:
/*
* Encode SYMLINK request
*/
-static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_create_arg *args)
+static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_create_arg *args)
{
return nfs4_xdr_enc_create(req, p, args);
}
@@ -1478,7 +1478,7 @@ static int nfs4_xdr_enc_symlink(struct rpc_rqst *req, uint32_t *p, const struct
/*
* Encode GETATTR request
*/
-static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct nfs4_getattr_arg *args)
+static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, __be32 *p, const struct nfs4_getattr_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1496,7 +1496,7 @@ static int nfs4_xdr_enc_getattr(struct rpc_rqst *req, uint32_t *p, const struct
/*
* Encode a CLOSE request
*/
-static int nfs4_xdr_enc_close(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_close(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1520,7 +1520,7 @@ out:
/*
* Encode an OPEN request
*/
-static int nfs4_xdr_enc_open(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
+static int nfs4_xdr_enc_open(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1556,7 +1556,7 @@ out:
/*
* Encode an OPEN_CONFIRM request
*/
-static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_open_confirmargs *args)
+static int nfs4_xdr_enc_open_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_open_confirmargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1577,7 +1577,7 @@ out:
/*
* Encode an OPEN request with no attributes.
*/
-static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, uint32_t *p, struct nfs_openargs *args)
+static int nfs4_xdr_enc_open_noattr(struct rpc_rqst *req, __be32 *p, struct nfs_openargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1601,7 +1601,7 @@ out:
/*
* Encode an OPEN_DOWNGRADE request
*/
-static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, uint32_t *p, struct nfs_closeargs *args)
+static int nfs4_xdr_enc_open_downgrade(struct rpc_rqst *req, __be32 *p, struct nfs_closeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1625,7 +1625,7 @@ out:
/*
* Encode a LOCK request
*/
-static int nfs4_xdr_enc_lock(struct rpc_rqst *req, uint32_t *p, struct nfs_lock_args *args)
+static int nfs4_xdr_enc_lock(struct rpc_rqst *req, __be32 *p, struct nfs_lock_args *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1646,7 +1646,7 @@ out:
/*
* Encode a LOCKT request
*/
-static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, uint32_t *p, struct nfs_lockt_args *args)
+static int nfs4_xdr_enc_lockt(struct rpc_rqst *req, __be32 *p, struct nfs_lockt_args *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1667,7 +1667,7 @@ out:
/*
* Encode a LOCKU request
*/
-static int nfs4_xdr_enc_locku(struct rpc_rqst *req, uint32_t *p, struct nfs_locku_args *args)
+static int nfs4_xdr_enc_locku(struct rpc_rqst *req, __be32 *p, struct nfs_locku_args *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1688,7 +1688,7 @@ out:
/*
* Encode a READLINK request
*/
-static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readlink *args)
+static int nfs4_xdr_enc_readlink(struct rpc_rqst *req, __be32 *p, const struct nfs4_readlink *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1709,7 +1709,7 @@ out:
/*
* Encode a READDIR request
*/
-static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, uint32_t *p, const struct nfs4_readdir_arg *args)
+static int nfs4_xdr_enc_readdir(struct rpc_rqst *req, __be32 *p, const struct nfs4_readdir_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1730,7 +1730,7 @@ out:
/*
* Encode a READ request
*/
-static int nfs4_xdr_enc_read(struct rpc_rqst *req, uint32_t *p, struct nfs_readargs *args)
+static int nfs4_xdr_enc_read(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
{
struct rpc_auth *auth = req->rq_task->tk_auth;
struct xdr_stream xdr;
@@ -1762,7 +1762,7 @@ out:
/*
* Encode an SETATTR request
*/
-static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, uint32_t *p, struct nfs_setattrargs *args)
+static int nfs4_xdr_enc_setattr(struct rpc_rqst *req, __be32 *p, struct nfs_setattrargs *args)
{
struct xdr_stream xdr;
@@ -1788,7 +1788,7 @@ out:
* Encode a GETACL request
*/
static int
-nfs4_xdr_enc_getacl(struct rpc_rqst *req, uint32_t *p,
+nfs4_xdr_enc_getacl(struct rpc_rqst *req, __be32 *p,
struct nfs_getaclargs *args)
{
struct xdr_stream xdr;
@@ -1815,7 +1815,7 @@ out:
/*
* Encode a WRITE request
*/
-static int nfs4_xdr_enc_write(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_write(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1839,7 +1839,7 @@ out:
/*
* a COMMIT request
*/
-static int nfs4_xdr_enc_commit(struct rpc_rqst *req, uint32_t *p, struct nfs_writeargs *args)
+static int nfs4_xdr_enc_commit(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1863,7 +1863,7 @@ out:
/*
* FSINFO request
*/
-static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fsinfo_arg *args)
+static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs4_fsinfo_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1882,7 +1882,7 @@ static int nfs4_xdr_enc_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs
/*
* a PATHCONF request
*/
-static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct nfs4_pathconf_arg *args)
+static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, __be32 *p, const struct nfs4_pathconf_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1902,7 +1902,7 @@ static int nfs4_xdr_enc_pathconf(struct rpc_rqst *req, uint32_t *p, const struct
/*
* a STATFS request
*/
-static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct nfs4_statfs_arg *args)
+static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, __be32 *p, const struct nfs4_statfs_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1923,7 +1923,7 @@ static int nfs4_xdr_enc_statfs(struct rpc_rqst *req, uint32_t *p, const struct n
/*
* GETATTR_BITMAP request
*/
-static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const struct nfs_fh *fhandle)
+static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, __be32 *p, const struct nfs_fh *fhandle)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1945,7 +1945,7 @@ static int nfs4_xdr_enc_server_caps(struct rpc_rqst *req, uint32_t *p, const str
/*
* a RENEW request
*/
-static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
+static int nfs4_xdr_enc_renew(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1960,7 +1960,7 @@ static int nfs4_xdr_enc_renew(struct rpc_rqst *req, uint32_t *p, struct nfs_clie
/*
* a SETCLIENTID request
*/
-static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nfs4_setclientid *sc)
+static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, __be32 *p, struct nfs4_setclientid *sc)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1975,7 +1975,7 @@ static int nfs4_xdr_enc_setclientid(struct rpc_rqst *req, uint32_t *p, struct nf
/*
* a SETCLIENTID_CONFIRM request
*/
-static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_client *clp)
+static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_client *clp)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -1997,7 +1997,7 @@ static int nfs4_xdr_enc_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
/*
* DELEGRETURN request
*/
-static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, uint32_t *p, const struct nfs4_delegreturnargs *args)
+static int nfs4_xdr_enc_delegreturn(struct rpc_rqst *req, __be32 *p, const struct nfs4_delegreturnargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -2021,7 +2021,7 @@ out:
/*
* Encode FS_LOCATIONS request
*/
-static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations_arg *args)
+static int nfs4_xdr_enc_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations_arg *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -2086,7 +2086,7 @@ out:
static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char **string)
{
- uint32_t *p;
+ __be32 *p;
READ_BUF(4);
READ32(*len);
@@ -2097,7 +2097,7 @@ static int decode_opaque_inline(struct xdr_stream *xdr, unsigned int *len, char
static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
{
- uint32_t *p;
+ __be32 *p;
READ_BUF(8);
READ32(hdr->status);
@@ -2112,7 +2112,7 @@ static int decode_compound_hdr(struct xdr_stream *xdr, struct compound_hdr *hdr)
static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
- uint32_t *p;
+ __be32 *p;
uint32_t opnum;
int32_t nfserr;
@@ -2134,7 +2134,7 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
/* Dummy routine */
static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
{
- uint32_t *p;
+ __be32 *p;
unsigned int strlen;
char *str;
@@ -2144,7 +2144,8 @@ static int decode_ace(struct xdr_stream *xdr, void *ace, struct nfs_client *clp)
static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
{
- uint32_t bmlen, *p;
+ uint32_t bmlen;
+ __be32 *p;
READ_BUF(4);
READ32(bmlen);
@@ -2159,9 +2160,9 @@ static int decode_attr_bitmap(struct xdr_stream *xdr, uint32_t *bitmap)
return 0;
}
-static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, uint32_t **savep)
+static inline int decode_attr_length(struct xdr_stream *xdr, uint32_t *attrlen, __be32 **savep)
{
- uint32_t *p;
+ __be32 *p;
READ_BUF(4);
READ32(*attrlen);
@@ -2182,7 +2183,7 @@ static int decode_attr_supported(struct xdr_stream *xdr, uint32_t *bitmap, uint3
static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *type)
{
- uint32_t *p;
+ __be32 *p;
*type = 0;
if (unlikely(bitmap[0] & (FATTR4_WORD0_TYPE - 1U)))
@@ -2202,7 +2203,7 @@ static int decode_attr_type(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *change)
{
- uint32_t *p;
+ __be32 *p;
*change = 0;
if (unlikely(bitmap[0] & (FATTR4_WORD0_CHANGE - 1U)))
@@ -2219,7 +2220,7 @@ static int decode_attr_change(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *size)
{
- uint32_t *p;
+ __be32 *p;
*size = 0;
if (unlikely(bitmap[0] & (FATTR4_WORD0_SIZE - 1U)))
@@ -2235,7 +2236,7 @@ static int decode_attr_size(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *
static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
- uint32_t *p;
+ __be32 *p;
*res = 0;
if (unlikely(bitmap[0] & (FATTR4_WORD0_LINK_SUPPORT - 1U)))
@@ -2251,7 +2252,7 @@ static int decode_attr_link_support(struct xdr_stream *xdr, uint32_t *bitmap, ui
static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
- uint32_t *p;
+ __be32 *p;
*res = 0;
if (unlikely(bitmap[0] & (FATTR4_WORD0_SYMLINK_SUPPORT - 1U)))
@@ -2267,7 +2268,7 @@ static int decode_attr_symlink_support(struct xdr_stream *xdr, uint32_t *bitmap,
static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fsid *fsid)
{
- uint32_t *p;
+ __be32 *p;
fsid->major = 0;
fsid->minor = 0;
@@ -2287,7 +2288,7 @@ static int decode_attr_fsid(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs
static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
- uint32_t *p;
+ __be32 *p;
*res = 60;
if (unlikely(bitmap[0] & (FATTR4_WORD0_LEASE_TIME - 1U)))
@@ -2303,7 +2304,7 @@ static int decode_attr_lease_time(struct xdr_stream *xdr, uint32_t *bitmap, uint
static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
- uint32_t *p;
+ __be32 *p;
*res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
@@ -2319,7 +2320,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
- uint32_t *p;
+ __be32 *p;
*fileid = 0;
if (unlikely(bitmap[0] & (FATTR4_WORD0_FILEID - 1U)))
@@ -2335,7 +2336,7 @@ static int decode_attr_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t
static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *fileid)
{
- uint32_t *p;
+ __be32 *p;
*fileid = 0;
if (unlikely(bitmap[1] & (FATTR4_WORD1_MOUNTED_ON_FILEID - 1U)))
@@ -2351,7 +2352,7 @@ static int decode_attr_mounted_on_fileid(struct xdr_stream *xdr, uint32_t *bitma
static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 0;
@@ -2368,7 +2369,7 @@ static int decode_attr_files_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin
static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 0;
@@ -2385,7 +2386,7 @@ static int decode_attr_files_free(struct xdr_stream *xdr, uint32_t *bitmap, uint
static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 0;
@@ -2403,7 +2404,7 @@ static int decode_attr_files_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
static int decode_pathname(struct xdr_stream *xdr, struct nfs4_pathname *path)
{
int n;
- uint32_t *p;
+ __be32 *p;
int status = 0;
READ_BUF(4);
@@ -2448,7 +2449,7 @@ out_eio:
static int decode_attr_fs_locations(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs4_fs_locations *res)
{
int n;
- uint32_t *p;
+ __be32 *p;
int status = -EIO;
if (unlikely(bitmap[0] & (FATTR4_WORD0_FS_LOCATIONS -1U)))
@@ -2512,7 +2513,7 @@ out_eio:
static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 0;
@@ -2529,7 +2530,7 @@ static int decode_attr_maxfilesize(struct xdr_stream *xdr, uint32_t *bitmap, uin
static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxlink)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*maxlink = 1;
@@ -2546,7 +2547,7 @@ static int decode_attr_maxlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_
static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *maxname)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*maxname = 1024;
@@ -2563,7 +2564,7 @@ static int decode_attr_maxname(struct xdr_stream *xdr, uint32_t *bitmap, uint32_
static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 1024;
@@ -2584,7 +2585,7 @@ static int decode_attr_maxread(struct xdr_stream *xdr, uint32_t *bitmap, uint32_
static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 1024;
@@ -2605,7 +2606,7 @@ static int decode_attr_maxwrite(struct xdr_stream *xdr, uint32_t *bitmap, uint32
static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *mode)
{
- uint32_t *p;
+ __be32 *p;
*mode = 0;
if (unlikely(bitmap[1] & (FATTR4_WORD1_MODE - 1U)))
@@ -2622,7 +2623,7 @@ static int decode_attr_mode(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *
static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t *nlink)
{
- uint32_t *p;
+ __be32 *p;
*nlink = 1;
if (unlikely(bitmap[1] & (FATTR4_WORD1_NUMLINKS - 1U)))
@@ -2638,7 +2639,8 @@ static int decode_attr_nlink(struct xdr_stream *xdr, uint32_t *bitmap, uint32_t
static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *uid)
{
- uint32_t len, *p;
+ uint32_t len;
+ __be32 *p;
*uid = -2;
if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER - 1U)))
@@ -2662,7 +2664,8 @@ static int decode_attr_owner(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_client *clp, int32_t *gid)
{
- uint32_t len, *p;
+ uint32_t len;
+ __be32 *p;
*gid = -2;
if (unlikely(bitmap[1] & (FATTR4_WORD1_OWNER_GROUP - 1U)))
@@ -2686,7 +2689,8 @@ static int decode_attr_group(struct xdr_stream *xdr, uint32_t *bitmap, struct nf
static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rdev)
{
- uint32_t major = 0, minor = 0, *p;
+ uint32_t major = 0, minor = 0;
+ __be32 *p;
*rdev = MKDEV(0,0);
if (unlikely(bitmap[1] & (FATTR4_WORD1_RAWDEV - 1U)))
@@ -2708,7 +2712,7 @@ static int decode_attr_rdev(struct xdr_stream *xdr, uint32_t *bitmap, dev_t *rde
static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 0;
@@ -2725,7 +2729,7 @@ static int decode_attr_space_avail(struct xdr_stream *xdr, uint32_t *bitmap, uin
static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 0;
@@ -2742,7 +2746,7 @@ static int decode_attr_space_free(struct xdr_stream *xdr, uint32_t *bitmap, uint
static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *res)
{
- uint32_t *p;
+ __be32 *p;
int status = 0;
*res = 0;
@@ -2759,7 +2763,7 @@ static int decode_attr_space_total(struct xdr_stream *xdr, uint32_t *bitmap, uin
static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint64_t *used)
{
- uint32_t *p;
+ __be32 *p;
*used = 0;
if (unlikely(bitmap[1] & (FATTR4_WORD1_SPACE_USED - 1U)))
@@ -2776,7 +2780,7 @@ static int decode_attr_space_used(struct xdr_stream *xdr, uint32_t *bitmap, uint
static int decode_attr_time(struct xdr_stream *xdr, struct timespec *time)
{
- uint32_t *p;
+ __be32 *p;
uint64_t sec;
uint32_t nsec;
@@ -2836,7 +2840,7 @@ static int decode_attr_time_modify(struct xdr_stream *xdr, uint32_t *bitmap, str
return status;
}
-static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t attrlen)
+static int verify_attr_len(struct xdr_stream *xdr, __be32 *savep, uint32_t attrlen)
{
unsigned int attrwords = XDR_QUADLEN(attrlen);
unsigned int nwords = xdr->p - savep;
@@ -2854,7 +2858,7 @@ static int verify_attr_len(struct xdr_stream *xdr, uint32_t *savep, uint32_t att
static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
- uint32_t *p;
+ __be32 *p;
READ_BUF(20);
READ32(cinfo->atomic);
@@ -2865,7 +2869,7 @@ static int decode_change_info(struct xdr_stream *xdr, struct nfs4_change_info *c
static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
{
- uint32_t *p;
+ __be32 *p;
uint32_t supp, acc;
int status;
@@ -2882,7 +2886,7 @@ static int decode_access(struct xdr_stream *xdr, struct nfs4_accessres *access)
static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
{
- uint32_t *p;
+ __be32 *p;
int status;
status = decode_op_hdr(xdr, OP_CLOSE);
@@ -2895,7 +2899,7 @@ static int decode_close(struct xdr_stream *xdr, struct nfs_closeres *res)
static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
{
- uint32_t *p;
+ __be32 *p;
int status;
status = decode_op_hdr(xdr, OP_COMMIT);
@@ -2908,7 +2912,7 @@ static int decode_commit(struct xdr_stream *xdr, struct nfs_writeres *res)
static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
{
- uint32_t *p;
+ __be32 *p;
uint32_t bmlen;
int status;
@@ -2925,7 +2929,7 @@ static int decode_create(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_res *res)
{
- uint32_t *savep;
+ __be32 *savep;
uint32_t attrlen,
bitmap[2] = {0};
int status;
@@ -2952,7 +2956,7 @@ xdr_error:
static int decode_statfs(struct xdr_stream *xdr, struct nfs_fsstat *fsstat)
{
- uint32_t *savep;
+ __be32 *savep;
uint32_t attrlen,
bitmap[2] = {0};
int status;
@@ -2985,7 +2989,7 @@ xdr_error:
static int decode_pathconf(struct xdr_stream *xdr, struct nfs_pathconf *pathconf)
{
- uint32_t *savep;
+ __be32 *savep;
uint32_t attrlen,
bitmap[2] = {0};
int status;
@@ -3010,7 +3014,7 @@ xdr_error:
static int decode_getfattr(struct xdr_stream *xdr, struct nfs_fattr *fattr, const struct nfs_server *server)
{
- uint32_t *savep;
+ __be32 *savep;
uint32_t attrlen,
bitmap[2] = {0},
type;
@@ -3079,7 +3083,7 @@ xdr_error:
static int decode_fsinfo(struct xdr_stream *xdr, struct nfs_fsinfo *fsinfo)
{
- uint32_t *savep;
+ __be32 *savep;
uint32_t attrlen, bitmap[2];
int status;
@@ -3111,7 +3115,7 @@ xdr_error:
static int decode_getfh(struct xdr_stream *xdr, struct nfs_fh *fh)
{
- uint32_t *p;
+ __be32 *p;
uint32_t len;
int status;
@@ -3147,7 +3151,7 @@ static int decode_link(struct xdr_stream *xdr, struct nfs4_change_info *cinfo)
static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
{
uint64_t offset, length, clientid;
- uint32_t *p;
+ __be32 *p;
uint32_t namelen, type;
READ_BUF(32);
@@ -3172,7 +3176,7 @@ static int decode_lock_denied (struct xdr_stream *xdr, struct file_lock *fl)
static int decode_lock(struct xdr_stream *xdr, struct nfs_lock_res *res)
{
- uint32_t *p;
+ __be32 *p;
int status;
status = decode_op_hdr(xdr, OP_LOCK);
@@ -3195,7 +3199,7 @@ static int decode_lockt(struct xdr_stream *xdr, struct nfs_lockt_res *res)
static int decode_locku(struct xdr_stream *xdr, struct nfs_locku_res *res)
{
- uint32_t *p;
+ __be32 *p;
int status;
status = decode_op_hdr(xdr, OP_LOCKU);
@@ -3214,7 +3218,7 @@ static int decode_lookup(struct xdr_stream *xdr)
/* This is too sick! */
static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
{
- uint32_t *p;
+ __be32 *p;
uint32_t limit_type, nblocks, blocksize;
READ_BUF(12);
@@ -3233,7 +3237,7 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
{
- uint32_t *p;
+ __be32 *p;
uint32_t delegation_type;
READ_BUF(4);
@@ -3259,7 +3263,7 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
{
- uint32_t *p;
+ __be32 *p;
uint32_t bmlen;
int status;
@@ -3287,7 +3291,7 @@ xdr_error:
static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmres *res)
{
- uint32_t *p;
+ __be32 *p;
int status;
status = decode_op_hdr(xdr, OP_OPEN_CONFIRM);
@@ -3300,7 +3304,7 @@ static int decode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmre
static int decode_open_downgrade(struct xdr_stream *xdr, struct nfs_closeres *res)
{
- uint32_t *p;
+ __be32 *p;
int status;
status = decode_op_hdr(xdr, OP_OPEN_DOWNGRADE);
@@ -3324,7 +3328,7 @@ static int decode_putrootfh(struct xdr_stream *xdr)
static int decode_read(struct xdr_stream *xdr, struct rpc_rqst *req, struct nfs_readres *res)
{
struct kvec *iov = req->rq_rcv_buf.head;
- uint32_t *p;
+ __be32 *p;
uint32_t count, eof, recvd, hdrlen;
int status;
@@ -3354,7 +3358,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
struct page *page = *rcvbuf->pages;
struct kvec *iov = rcvbuf->head;
unsigned int nr, pglen = rcvbuf->page_len;
- uint32_t *end, *entry, *p, *kaddr;
+ __be32 *end, *entry, *p, *kaddr;
uint32_t len, attrlen, xlen;
int hdrlen, recvd, status;
@@ -3376,7 +3380,7 @@ static int decode_readdir(struct xdr_stream *xdr, struct rpc_rqst *req, struct n
xdr_read_pages(xdr, pglen);
BUG_ON(pglen + readdir->pgbase > PAGE_CACHE_SIZE);
- kaddr = p = (uint32_t *) kmap_atomic(page, KM_USER0);
+ kaddr = p = kmap_atomic(page, KM_USER0);
end = p + ((pglen + readdir->pgbase) >> 2);
entry = p;
for (nr = 0; *p++; nr++) {
@@ -3428,7 +3432,7 @@ static int decode_readlink(struct xdr_stream *xdr, struct rpc_rqst *req)
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
struct kvec *iov = rcvbuf->head;
int hdrlen, len, recvd;
- uint32_t *p;
+ __be32 *p;
char *kaddr;
int status;
@@ -3505,7 +3509,7 @@ decode_restorefh(struct xdr_stream *xdr)
static int decode_getacl(struct xdr_stream *xdr, struct rpc_rqst *req,
size_t *acl_len)
{
- uint32_t *savep;
+ __be32 *savep;
uint32_t attrlen,
bitmap[2] = {0};
struct kvec *iov = req->rq_rcv_buf.head;
@@ -3551,7 +3555,7 @@ decode_savefh(struct xdr_stream *xdr)
static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
{
- uint32_t *p;
+ __be32 *p;
uint32_t bmlen;
int status;
@@ -3567,7 +3571,7 @@ static int decode_setattr(struct xdr_stream *xdr, struct nfs_setattrres *res)
static int decode_setclientid(struct xdr_stream *xdr, struct nfs_client *clp)
{
- uint32_t *p;
+ __be32 *p;
uint32_t opnum;
int32_t nfserr;
@@ -3610,7 +3614,7 @@ static int decode_setclientid_confirm(struct xdr_stream *xdr)
static int decode_write(struct xdr_stream *xdr, struct nfs_writeres *res)
{
- uint32_t *p;
+ __be32 *p;
int status;
status = decode_op_hdr(xdr, OP_WRITE);
@@ -3632,7 +3636,7 @@ static int decode_delegreturn(struct xdr_stream *xdr)
/*
* Decode OPEN_DOWNGRADE response
*/
-static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_open_downgrade(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3660,7 +3664,7 @@ out:
/*
* Decode ACCESS response
*/
-static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_accessres *res)
+static int nfs4_xdr_dec_access(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_accessres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3678,7 +3682,7 @@ out:
/*
* Decode LOOKUP response
*/
-static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+static int nfs4_xdr_dec_lookup(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3701,7 +3705,7 @@ out:
/*
* Decode LOOKUP_ROOT response
*/
-static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_lookup_res *res)
+static int nfs4_xdr_dec_lookup_root(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_lookup_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3721,7 +3725,7 @@ out:
/*
* Decode REMOVE response
*/
-static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_remove_res *res)
+static int nfs4_xdr_dec_remove(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_remove_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3742,7 +3746,7 @@ out:
/*
* Decode RENAME response
*/
-static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_rename_res *res)
+static int nfs4_xdr_dec_rename(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_rename_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3772,7 +3776,7 @@ out:
/*
* Decode LINK response
*/
-static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_link_res *res)
+static int nfs4_xdr_dec_link(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_link_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3805,7 +3809,7 @@ out:
/*
* Decode CREATE response
*/
-static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+static int nfs4_xdr_dec_create(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3834,7 +3838,7 @@ out:
/*
* Decode SYMLINK response
*/
-static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_create_res *res)
+static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_create_res *res)
{
return nfs4_xdr_dec_create(rqstp, p, res);
}
@@ -3842,7 +3846,7 @@ static int nfs4_xdr_dec_symlink(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4
/*
* Decode GETATTR response
*/
-static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_getattr_res *res)
+static int nfs4_xdr_dec_getattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_getattr_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3865,7 +3869,7 @@ out:
* Encode an SETACL request
*/
static int
-nfs4_xdr_enc_setacl(struct rpc_rqst *req, uint32_t *p, struct nfs_setaclargs *args)
+nfs4_xdr_enc_setacl(struct rpc_rqst *req, __be32 *p, struct nfs_setaclargs *args)
{
struct xdr_stream xdr;
struct compound_hdr hdr = {
@@ -3886,7 +3890,7 @@ out:
* Decode SETACL response
*/
static int
-nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, uint32_t *p, void *res)
+nfs4_xdr_dec_setacl(struct rpc_rqst *rqstp, __be32 *p, void *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3908,7 +3912,7 @@ out:
* Decode GETACL response
*/
static int
-nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, uint32_t *p, size_t *acl_len)
+nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, __be32 *p, size_t *acl_len)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3930,7 +3934,7 @@ out:
/*
* Decode CLOSE response
*/
-static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_closeres *res)
+static int nfs4_xdr_dec_close(struct rpc_rqst *rqstp, __be32 *p, struct nfs_closeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3960,7 +3964,7 @@ out:
/*
* Decode OPEN response
*/
-static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -3994,7 +3998,7 @@ out:
/*
* Decode OPEN_CONFIRM response
*/
-static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_open_confirmres *res)
+static int nfs4_xdr_dec_open_confirm(struct rpc_rqst *rqstp, __be32 *p, struct nfs_open_confirmres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4015,7 +4019,7 @@ out:
/*
* Decode OPEN response
*/
-static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+static int nfs4_xdr_dec_open_noattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_openres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4039,7 +4043,7 @@ out:
/*
* Decode SETATTR response
*/
-static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_setattrres *res)
+static int nfs4_xdr_dec_setattr(struct rpc_rqst *rqstp, __be32 *p, struct nfs_setattrres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4065,7 +4069,7 @@ out:
/*
* Decode LOCK response
*/
-static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lock_res *res)
+static int nfs4_xdr_dec_lock(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lock_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4086,7 +4090,7 @@ out:
/*
* Decode LOCKT response
*/
-static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_lockt_res *res)
+static int nfs4_xdr_dec_lockt(struct rpc_rqst *rqstp, __be32 *p, struct nfs_lockt_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4107,7 +4111,7 @@ out:
/*
* Decode LOCKU response
*/
-static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_locku_res *res)
+static int nfs4_xdr_dec_locku(struct rpc_rqst *rqstp, __be32 *p, struct nfs_locku_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4128,7 +4132,7 @@ out:
/*
* Decode READLINK response
*/
-static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, uint32_t *p, void *res)
+static int nfs4_xdr_dec_readlink(struct rpc_rqst *rqstp, __be32 *p, void *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4149,7 +4153,7 @@ out:
/*
* Decode READDIR response
*/
-static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_readdir_res *res)
+static int nfs4_xdr_dec_readdir(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_readdir_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4170,7 +4174,7 @@ out:
/*
* Decode Read response
*/
-static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_readres *res)
+static int nfs4_xdr_dec_read(struct rpc_rqst *rqstp, __be32 *p, struct nfs_readres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4193,7 +4197,7 @@ out:
/*
* Decode WRITE response
*/
-static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_write(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4219,7 +4223,7 @@ out:
/*
* Decode COMMIT response
*/
-static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_writeres *res)
+static int nfs4_xdr_dec_commit(struct rpc_rqst *rqstp, __be32 *p, struct nfs_writeres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4243,7 +4247,7 @@ out:
/*
* FSINFO request
*/
-static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4263,7 +4267,7 @@ static int nfs4_xdr_dec_fsinfo(struct rpc_rqst *req, uint32_t *p, struct nfs_fsi
/*
* PATHCONF request
*/
-static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_pathconf *pathconf)
+static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *pathconf)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4281,7 +4285,7 @@ static int nfs4_xdr_dec_pathconf(struct rpc_rqst *req, uint32_t *p, struct nfs_p
/*
* STATFS request
*/
-static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fsstat *fsstat)
+static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *fsstat)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4299,7 +4303,7 @@ static int nfs4_xdr_dec_statfs(struct rpc_rqst *req, uint32_t *p, struct nfs_fss
/*
* GETATTR_BITMAP request
*/
-static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, uint32_t *p, struct nfs4_server_caps_res *res)
+static int nfs4_xdr_dec_server_caps(struct rpc_rqst *req, __be32 *p, struct nfs4_server_caps_res *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4318,7 +4322,7 @@ out:
/*
* Decode RENEW response
*/
-static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
+static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, __be32 *p, void *dummy)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4334,7 +4338,7 @@ static int nfs4_xdr_dec_renew(struct rpc_rqst *rqstp, uint32_t *p, void *dummy)
/*
* a SETCLIENTID request
*/
-static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
+static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, __be32 *p,
struct nfs_client *clp)
{
struct xdr_stream xdr;
@@ -4353,7 +4357,7 @@ static int nfs4_xdr_dec_setclientid(struct rpc_rqst *req, uint32_t *p,
/*
* a SETCLIENTID_CONFIRM request
*/
-static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, struct nfs_fsinfo *fsinfo)
+static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *fsinfo)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4375,7 +4379,7 @@ static int nfs4_xdr_dec_setclientid_confirm(struct rpc_rqst *req, uint32_t *p, s
/*
* DELEGRETURN request
*/
-static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, uint32_t *p, struct nfs4_delegreturnres *res)
+static int nfs4_xdr_dec_delegreturn(struct rpc_rqst *rqstp, __be32 *p, struct nfs4_delegreturnres *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4397,7 +4401,7 @@ out:
/*
* FS_LOCATIONS request
*/
-static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, uint32_t *p, struct nfs4_fs_locations *res)
+static int nfs4_xdr_dec_fs_locations(struct rpc_rqst *req, __be32 *p, struct nfs4_fs_locations *res)
{
struct xdr_stream xdr;
struct compound_hdr hdr;
@@ -4417,7 +4421,7 @@ out:
return status;
}
-uint32_t *nfs4_decode_dirent(uint32_t *p, struct nfs_entry *entry, int plus)
+__be32 *nfs4_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
{
uint32_t bitmap[2] = {0};
uint32_t len;
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
index c0a754ecdee6..8dfefe41a8da 100644
--- a/fs/nfs/nfsroot.c
+++ b/fs/nfs/nfsroot.c
@@ -69,7 +69,6 @@
* Fabian Frederick: Option parser rebuilt (using parser lib)
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/kernel.h>
@@ -312,7 +311,7 @@ static int __init root_nfs_name(char *name)
/* Override them by options set on kernel command-line */
root_nfs_parse(name, buf);
- cp = system_utsname.nodename;
+ cp = utsname()->nodename;
if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
return -1;
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 36e902a88ca1..829af323f288 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -392,7 +392,6 @@ int __init nfs_init_nfspagecache(void)
void nfs_destroy_nfspagecache(void)
{
- if (kmem_cache_destroy(nfs_page_cachep))
- printk(KERN_INFO "nfs_page: not all structures were freed\n");
+ kmem_cache_destroy(nfs_page_cachep);
}
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 630e50647bbb..4529cc4f3f8f 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -352,7 +352,7 @@ nfs_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *
{
struct nfs_diropargs *arg;
- arg = (struct nfs_diropargs *)kmalloc(sizeof(*arg), GFP_KERNEL);
+ arg = kmalloc(sizeof(*arg), GFP_KERNEL);
if (!arg)
return -ENOMEM;
arg->fh = NFS_FH(dir->d_inode);
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 69f1549da2b9..c2e49c397a27 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -737,6 +737,5 @@ int __init nfs_init_readpagecache(void)
void nfs_destroy_readpagecache(void)
{
mempool_destroy(nfs_rdata_mempool);
- if (kmem_cache_destroy(nfs_rdata_cachep))
- printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
+ kmem_cache_destroy(nfs_rdata_cachep);
}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index e8d40030cab4..28108c82b887 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -20,7 +20,6 @@
* of another (see nfs_lookup())
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
@@ -835,7 +834,7 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
}
/* RFC3530: The default port for NFS is 2049 */
if (addr.sin_port == 0)
- addr.sin_port = NFS_PORT;
+ addr.sin_port = htons(NFS_PORT);
/* Grab the authentication type */
authflavour = RPC_AUTH_UNIX;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index c12effb46fe5..883dd4a1c157 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -51,13 +51,14 @@
#include <linux/mm.h>
#include <linux/pagemap.h>
#include <linux/file.h>
-#include <linux/mpage.h>
#include <linux/writeback.h>
#include <linux/sunrpc/clnt.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs_page.h>
+#include <linux/backing-dev.h>
+
#include <asm/uaccess.h>
#include <linux/smp_lock.h>
@@ -396,7 +397,7 @@ int nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
out:
clear_bit(BDI_write_congested, &bdi->state);
wake_up_all(&nfs_write_congestion);
- writeback_congestion_end();
+ congestion_end(WRITE);
return err;
}
@@ -589,10 +590,10 @@ static void nfs_cancel_commit_list(struct list_head *head)
while(!list_empty(head)) {
req = nfs_list_entry(head->next);
+ dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
nfs_list_remove_request(req);
nfs_inode_remove_request(req);
- dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
- nfs_clear_page_writeback(req);
+ nfs_unlock_request(req);
}
}
@@ -1565,7 +1566,6 @@ void nfs_destroy_writepagecache(void)
{
mempool_destroy(nfs_commit_mempool);
mempool_destroy(nfs_wdata_mempool);
- if (kmem_cache_destroy(nfs_wdata_cachep))
- printk(KERN_INFO "nfs_write_data: not all structures were freed\n");
+ kmem_cache_destroy(nfs_wdata_cachep);
}
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
index 0c2be8c0307d..c11f5375d7c1 100644
--- a/fs/nfs_common/nfsacl.c
+++ b/fs/nfs_common/nfsacl.c
@@ -46,7 +46,7 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
{
struct nfsacl_encode_desc *nfsacl_desc =
(struct nfsacl_encode_desc *) desc;
- u32 *p = (u32 *) elem;
+ __be32 *p = elem;
struct posix_acl_entry *entry =
&nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
@@ -127,7 +127,7 @@ xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)
{
struct nfsacl_decode_desc *nfsacl_desc =
(struct nfsacl_decode_desc *) desc;
- u32 *p = (u32 *) elem;
+ __be32 *p = elem;
struct posix_acl_entry *entry;
if (!nfsacl_desc->acl) {
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 01bc68c628ad..f37df46d2eaa 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -319,12 +319,25 @@ svc_expkey_update(struct svc_expkey *new, struct svc_expkey *old)
static struct cache_head *export_table[EXPORT_HASHMAX];
+static void nfsd4_fslocs_free(struct nfsd4_fs_locations *fsloc)
+{
+ int i;
+
+ for (i = 0; i < fsloc->locations_count; i++) {
+ kfree(fsloc->locations[i].path);
+ kfree(fsloc->locations[i].hosts);
+ }
+ kfree(fsloc->locations);
+}
+
static void svc_export_put(struct kref *ref)
{
struct svc_export *exp = container_of(ref, struct svc_export, h.ref);
dput(exp->ex_dentry);
mntput(exp->ex_mnt);
auth_domain_put(exp->ex_client);
+ kfree(exp->ex_path);
+ nfsd4_fslocs_free(&exp->ex_fslocs);
kfree(exp);
}
@@ -370,7 +383,7 @@ static int check_export(struct inode *inode, int flags)
*/
if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) &&
!(flags & NFSEXP_FSID)) {
- dprintk("exp_export: export of non-dev fs without fsid");
+ dprintk("exp_export: export of non-dev fs without fsid\n");
return -EINVAL;
}
if (!inode->i_sb->s_export_op) {
@@ -386,6 +399,69 @@ static int check_export(struct inode *inode, int flags)
}
+#ifdef CONFIG_NFSD_V4
+
+static int
+fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc)
+{
+ int len;
+ int migrated, i, err;
+
+ len = qword_get(mesg, buf, PAGE_SIZE);
+ if (len != 5 || memcmp(buf, "fsloc", 5))
+ return 0;
+
+ /* listsize */
+ err = get_int(mesg, &fsloc->locations_count);
+ if (err)
+ return err;
+ if (fsloc->locations_count > MAX_FS_LOCATIONS)
+ return -EINVAL;
+ if (fsloc->locations_count == 0)
+ return 0;
+
+ fsloc->locations = kzalloc(fsloc->locations_count
+ * sizeof(struct nfsd4_fs_location), GFP_KERNEL);
+ if (!fsloc->locations)
+ return -ENOMEM;
+ for (i=0; i < fsloc->locations_count; i++) {
+ /* colon separated host list */
+ err = -EINVAL;
+ len = qword_get(mesg, buf, PAGE_SIZE);
+ if (len <= 0)
+ goto out_free_all;
+ err = -ENOMEM;
+ fsloc->locations[i].hosts = kstrdup(buf, GFP_KERNEL);
+ if (!fsloc->locations[i].hosts)
+ goto out_free_all;
+ err = -EINVAL;
+ /* slash separated path component list */
+ len = qword_get(mesg, buf, PAGE_SIZE);
+ if (len <= 0)
+ goto out_free_all;
+ err = -ENOMEM;
+ fsloc->locations[i].path = kstrdup(buf, GFP_KERNEL);
+ if (!fsloc->locations[i].path)
+ goto out_free_all;
+ }
+ /* migrated */
+ err = get_int(mesg, &migrated);
+ if (err)
+ goto out_free_all;
+ err = -EINVAL;
+ if (migrated < 0 || migrated > 1)
+ goto out_free_all;
+ fsloc->migrated = migrated;
+ return 0;
+out_free_all:
+ nfsd4_fslocs_free(fsloc);
+ return err;
+}
+
+#else /* CONFIG_NFSD_V4 */
+static inline int fsloc_parse(char **mesg, char *buf, struct nfsd4_fs_locations *fsloc) { return 0; }
+#endif
+
static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
{
/* client path expiry [flags anonuid anongid fsid] */
@@ -398,6 +474,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
int an_int;
nd.dentry = NULL;
+ exp.ex_path = NULL;
if (mesg[mlen-1] != '\n')
return -EINVAL;
@@ -428,6 +505,10 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
exp.ex_client = dom;
exp.ex_mnt = nd.mnt;
exp.ex_dentry = nd.dentry;
+ exp.ex_path = kstrdup(buf, GFP_KERNEL);
+ err = -ENOMEM;
+ if (!exp.ex_path)
+ goto out;
/* expiry */
err = -EINVAL;
@@ -435,6 +516,11 @@ 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;
+
/* flags */
err = get_int(&mesg, &an_int);
if (err == -ENOENT)
@@ -460,6 +546,10 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
err = check_export(nd.dentry->d_inode, exp.ex_flags);
if (err) goto out;
+
+ err = fsloc_parse(&mesg, buf, &exp.ex_fslocs);
+ if (err)
+ goto out;
}
expp = svc_export_lookup(&exp);
@@ -473,6 +563,7 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
else
exp_put(expp);
out:
+ kfree(exp.ex_path);
if (nd.dentry)
path_release(&nd);
out_no_path:
@@ -482,7 +573,8 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
return err;
}
-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong);
+static void exp_flags(struct seq_file *m, int flag, int fsid,
+ uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fslocs);
static int svc_export_show(struct seq_file *m,
struct cache_detail *cd,
@@ -501,8 +593,8 @@ static int svc_export_show(struct seq_file *m,
seq_putc(m, '(');
if (test_bit(CACHE_VALID, &h->flags) &&
!test_bit(CACHE_NEGATIVE, &h->flags))
- exp_flags(m, exp->ex_flags, exp->ex_fsid,
- exp->ex_anon_uid, exp->ex_anon_gid);
+ exp_flags(m, exp->ex_flags, exp->ex_fsid,
+ exp->ex_anon_uid, exp->ex_anon_gid, &exp->ex_fslocs);
seq_puts(m, ")\n");
return 0;
}
@@ -524,6 +616,10 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
new->ex_client = item->ex_client;
new->ex_dentry = dget(item->ex_dentry);
new->ex_mnt = mntget(item->ex_mnt);
+ new->ex_path = NULL;
+ new->ex_fslocs.locations = NULL;
+ new->ex_fslocs.locations_count = 0;
+ new->ex_fslocs.migrated = 0;
}
static void export_update(struct cache_head *cnew, struct cache_head *citem)
@@ -535,6 +631,14 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
new->ex_anon_uid = item->ex_anon_uid;
new->ex_anon_gid = item->ex_anon_gid;
new->ex_fsid = item->ex_fsid;
+ new->ex_path = item->ex_path;
+ item->ex_path = NULL;
+ new->ex_fslocs.locations = item->ex_fslocs.locations;
+ item->ex_fslocs.locations = NULL;
+ new->ex_fslocs.locations_count = item->ex_fslocs.locations_count;
+ item->ex_fslocs.locations_count = 0;
+ new->ex_fslocs.migrated = item->ex_fslocs.migrated;
+ item->ex_fslocs.migrated = 0;
}
static struct cache_head *svc_export_alloc(void)
@@ -1044,40 +1148,32 @@ exp_find(struct auth_domain *clp, int fsid_type, u32 *fsidv,
* for a given NFSv4 client. The root is defined to be the
* export point with fsid==0
*/
-int
+__be32
exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
struct cache_req *creq)
{
- struct svc_expkey *fsid_key;
struct svc_export *exp;
- int rv;
+ __be32 rv;
u32 fsidv[2];
mk_fsid_v1(fsidv, 0);
- fsid_key = exp_find_key(clp, 1, fsidv, creq);
- if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN)
+ exp = exp_find(clp, 1, fsidv, creq);
+ if (IS_ERR(exp) && PTR_ERR(exp) == -EAGAIN)
return nfserr_dropit;
- if (!fsid_key || IS_ERR(fsid_key))
- return nfserr_perm;
-
- exp = exp_get_by_name(clp, fsid_key->ek_mnt, fsid_key->ek_dentry, creq);
if (exp == NULL)
- rv = nfserr_perm;
+ return nfserr_perm;
else if (IS_ERR(exp))
- rv = nfserrno(PTR_ERR(exp));
- else {
- rv = fh_compose(fhp, exp,
- fsid_key->ek_dentry, NULL);
- exp_put(exp);
- }
- cache_put(&fsid_key->h, &svc_expkey_cache);
+ return nfserrno(PTR_ERR(exp));
+ rv = fh_compose(fhp, exp, exp->ex_dentry, NULL);
+ exp_put(exp);
return rv;
}
/* Iterator */
static void *e_start(struct seq_file *m, loff_t *pos)
+ __acquires(svc_export_cache.hash_lock)
{
loff_t n = *pos;
unsigned hash, export;
@@ -1086,7 +1182,7 @@ static void *e_start(struct seq_file *m, loff_t *pos)
exp_readlock();
read_lock(&svc_export_cache.hash_lock);
if (!n--)
- return (void *)1;
+ return SEQ_START_TOKEN;
hash = n >> 32;
export = n & ((1LL<<32) - 1);
@@ -1110,7 +1206,7 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
struct cache_head *ch = p;
int hash = (*pos >> 32);
- if (p == (void *)1)
+ if (p == SEQ_START_TOKEN)
hash = 0;
else if (ch->next == NULL) {
hash++;
@@ -1131,6 +1227,7 @@ static void *e_next(struct seq_file *m, void *p, loff_t *pos)
}
static void e_stop(struct seq_file *m, void *p)
+ __releases(svc_export_cache.hash_lock)
{
read_unlock(&svc_export_cache.hash_lock);
exp_readunlock();
@@ -1156,7 +1253,8 @@ static struct flags {
{ 0, {"", ""}}
};
-static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t anong)
+static void exp_flags(struct seq_file *m, int flag, int fsid,
+ uid_t anonu, uid_t anong, struct nfsd4_fs_locations *fsloc)
{
int first = 0;
struct flags *flg;
@@ -1172,21 +1270,34 @@ static void exp_flags(struct seq_file *m, int flag, int fsid, uid_t anonu, uid_t
seq_printf(m, "%sanonuid=%d", first++?",":"", anonu);
if (anong != (gid_t)-2 && anong != (0x10000-2))
seq_printf(m, "%sanongid=%d", first++?",":"", anong);
+ if (fsloc && fsloc->locations_count > 0) {
+ char *loctype = (fsloc->migrated) ? "refer" : "replicas";
+ int i;
+
+ seq_printf(m, "%s%s=", first++?",":"", loctype);
+ seq_escape(m, fsloc->locations[0].path, ",;@ \t\n\\");
+ seq_putc(m, '@');
+ seq_escape(m, fsloc->locations[0].hosts, ",;@ \t\n\\");
+ for (i = 1; i < fsloc->locations_count; i++) {
+ seq_putc(m, ';');
+ seq_escape(m, fsloc->locations[i].path, ",;@ \t\n\\");
+ seq_putc(m, '@');
+ seq_escape(m, fsloc->locations[i].hosts, ",;@ \t\n\\");
+ }
+ }
}
static int e_show(struct seq_file *m, void *p)
{
struct cache_head *cp = p;
struct svc_export *exp = container_of(cp, struct svc_export, h);
- svc_client *clp;
- if (p == (void *)1) {
+ if (p == SEQ_START_TOKEN) {
seq_puts(m, "# Version 1.1\n");
seq_puts(m, "# Path Client(Flags) # IPs\n");
return 0;
}
- clp = exp->ex_client;
cache_get(&exp->h);
if (cache_check(&svc_export_cache, &exp->h, NULL))
return 0;
diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c
index 7b889ff15ae6..11fdaf7721b4 100644
--- a/fs/nfsd/lockd.c
+++ b/fs/nfsd/lockd.c
@@ -25,7 +25,7 @@
static u32
nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
{
- u32 nfserr;
+ __be32 nfserr;
struct svc_fh fh;
/* must initialize before using! but maxsize doesn't matter */
@@ -39,18 +39,20 @@ nlm_fopen(struct svc_rqst *rqstp, struct nfs_fh *f, struct file **filp)
fh_put(&fh);
rqstp->rq_client = NULL;
exp_readunlock();
- /* nlm and nfsd don't share error codes.
- * we invent: 0 = no error
- * 1 = stale file handle
- * 2 = other error
+ /* We return nlm error codes as nlm doesn't know
+ * about nfsd, but nfsd does know about nlm..
*/
switch (nfserr) {
case nfs_ok:
return 0;
+ case nfserr_dropit:
+ return nlm_drop_reply;
+#ifdef CONFIG_LOCKD_V4
case nfserr_stale:
- return 1;
+ return nlm4_stale_fh;
+#endif
default:
- return 2;
+ return nlm_lck_denied;
}
}
diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c
index fc95c4df6693..e3eca0816986 100644
--- a/fs/nfsd/nfs2acl.c
+++ b/fs/nfsd/nfs2acl.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nfsd/nfsacl.c
+ * linux/fs/nfsd/nfs2acl.c
*
* Process version 2 NFSACL requests.
*
@@ -21,7 +21,7 @@
/*
* NULL call.
*/
-static int
+static __be32
nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
return nfs_ok;
@@ -30,12 +30,12 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
/*
* Get the Access and/or Default ACL of a file.
*/
-static int nfsacld_proc_getacl(struct svc_rqst * rqstp,
+static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
{
svc_fh *fh;
struct posix_acl *acl;
- int nfserr = 0;
+ __be32 nfserr = 0;
dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
@@ -97,12 +97,12 @@ fail:
/*
* Set the Access and/or Default ACL of a file.
*/
-static int nfsacld_proc_setacl(struct svc_rqst * rqstp,
+static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
struct nfsd3_setaclargs *argp,
struct nfsd_attrstat *resp)
{
svc_fh *fh;
- int nfserr = 0;
+ __be32 nfserr = 0;
dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
@@ -128,7 +128,7 @@ static int nfsacld_proc_setacl(struct svc_rqst * rqstp,
/*
* Check file attributes
*/
-static int nfsacld_proc_getattr(struct svc_rqst * rqstp,
+static __be32 nfsacld_proc_getattr(struct svc_rqst * rqstp,
struct nfsd_fhandle *argp, struct nfsd_attrstat *resp)
{
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
@@ -140,10 +140,10 @@ static int nfsacld_proc_getattr(struct svc_rqst * rqstp,
/*
* Check file access
*/
-static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
+static __be32 nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
struct nfsd3_accessres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
SVCFH_fmt(&argp->fh),
@@ -158,7 +158,7 @@ static int nfsacld_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *
/*
* XDR decode functions
*/
-static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclargs *argp)
{
if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
@@ -169,7 +169,7 @@ static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
}
-static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_setaclargs *argp)
{
struct kvec *head = rqstp->rq_arg.head;
@@ -194,7 +194,7 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
return (n > 0);
}
-static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_fhandle *argp)
{
if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
@@ -202,7 +202,7 @@ static int nfsaclsvc_decode_fhandleargs(struct svc_rqst *rqstp, u32 *p,
return xdr_argsize_check(rqstp, p);
}
-static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_accessargs *argp)
{
if (!(p = nfs2svc_decode_fh(p, &argp->fh)))
@@ -217,7 +217,7 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
*/
/* GETACL */
-static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclres *resp)
{
struct dentry *dentry = resp->fh.fh_dentry;
@@ -241,7 +241,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = w;
while (w > 0) {
- if (!svc_take_res_page(rqstp))
+ if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
w -= PAGE_SIZE;
}
@@ -259,7 +259,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
return 1;
}
-static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_attrstat *resp)
{
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
@@ -267,7 +267,7 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, u32 *p,
}
/* ACCESS */
-static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_accessres *resp)
{
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh);
@@ -278,7 +278,7 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
/*
* XDR release functions
*/
-static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclres *resp)
{
fh_put(&resp->fh);
@@ -287,7 +287,7 @@ static int nfsaclsvc_release_getacl(struct svc_rqst *rqstp, u32 *p,
return 1;
}
-static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
+static int nfsaclsvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_fhandle *resp)
{
fh_put(&resp->fh);
@@ -333,4 +333,5 @@ struct svc_version nfsd_acl_version2 = {
.vs_proc = nfsd_acl_procedures2,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
+ .vs_hidden = 1,
};
diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c
index 16e10c170aed..fcad2895ddb0 100644
--- a/fs/nfsd/nfs3acl.c
+++ b/fs/nfsd/nfs3acl.c
@@ -19,7 +19,7 @@
/*
* NULL call.
*/
-static int
+static __be32
nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
return nfs_ok;
@@ -28,12 +28,12 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
/*
* Get the Access and/or Default ACL of a file.
*/
-static int nfsd3_proc_getacl(struct svc_rqst * rqstp,
+static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
{
svc_fh *fh;
struct posix_acl *acl;
- int nfserr = 0;
+ __be32 nfserr = 0;
fh = fh_copy(&resp->fh, &argp->fh);
if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
@@ -93,12 +93,12 @@ fail:
/*
* Set the Access and/or Default ACL of a file.
*/
-static int nfsd3_proc_setacl(struct svc_rqst * rqstp,
+static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
struct nfsd3_setaclargs *argp,
struct nfsd3_attrstat *resp)
{
svc_fh *fh;
- int nfserr = 0;
+ __be32 nfserr = 0;
fh = fh_copy(&resp->fh, &argp->fh);
nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_SATTR);
@@ -122,7 +122,7 @@ static int nfsd3_proc_setacl(struct svc_rqst * rqstp,
/*
* XDR decode functions
*/
-static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclargs *args)
{
if (!(p = nfs3svc_decode_fh(p, &args->fh)))
@@ -133,7 +133,7 @@ static int nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
}
-static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_setaclargs *args)
{
struct kvec *head = rqstp->rq_arg.head;
@@ -163,7 +163,7 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
*/
/* GETACL */
-static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclres *resp)
{
struct dentry *dentry = resp->fh.fh_dentry;
@@ -185,7 +185,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = w;
while (w > 0) {
- if (!svc_take_res_page(rqstp))
+ if (!rqstp->rq_respages[rqstp->rq_resused++])
return 0;
w -= PAGE_SIZE;
}
@@ -208,7 +208,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
}
/* SETACL */
-static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_attrstat *resp)
{
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
@@ -219,7 +219,7 @@ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
/*
* XDR release functions
*/
-static int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+static int nfs3svc_release_getacl(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_getaclres *resp)
{
fh_put(&resp->fh);
@@ -263,5 +263,6 @@ struct svc_version nfsd_acl_version3 = {
.vs_proc = nfsd_acl_procedures3,
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
+ .vs_hidden = 1,
};
diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
index f61142afea44..64db601c2bd2 100644
--- a/fs/nfsd/nfs3proc.c
+++ b/fs/nfsd/nfs3proc.c
@@ -43,7 +43,7 @@ static int nfs3_ftypes[] = {
/*
* NULL call.
*/
-static int
+static __be32
nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
return nfs_ok;
@@ -52,11 +52,12 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
/*
* Get a file's attributes
*/
-static int
+static __be32
nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
struct nfsd3_attrstat *resp)
{
- int err, nfserr;
+ int err;
+ __be32 nfserr;
dprintk("nfsd: GETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
@@ -76,11 +77,11 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
/*
* Set a file's attributes
*/
-static int
+static __be32
nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
struct nfsd3_attrstat *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: SETATTR(3) %s\n",
SVCFH_fmt(&argp->fh));
@@ -94,11 +95,11 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
/*
* Look up a path name component
*/
-static int
+static __be32
nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
struct nfsd3_diropres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: LOOKUP(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
@@ -118,11 +119,11 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
/*
* Check file access
*/
-static int
+static __be32
nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
struct nfsd3_accessres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: ACCESS(3) %s 0x%x\n",
SVCFH_fmt(&argp->fh),
@@ -137,11 +138,11 @@ nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
/*
* Read a symlink.
*/
-static int
+static __be32
nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
struct nfsd3_readlinkres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
@@ -155,11 +156,12 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
/*
* Read a portion of a file.
*/
-static int
+static __be32
nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
struct nfsd3_readres *resp)
{
- int nfserr;
+ __be32 nfserr;
+ u32 max_blocksize = svc_max_payload(rqstp);
dprintk("nfsd: READ(3) %s %lu bytes at %lu\n",
SVCFH_fmt(&argp->fh),
@@ -172,15 +174,15 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
*/
resp->count = argp->count;
- if (NFSSVC_MAXBLKSIZE < resp->count)
- resp->count = NFSSVC_MAXBLKSIZE;
+ if (max_blocksize < resp->count)
+ resp->count = max_blocksize;
svc_reserve(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,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
&resp->count);
if (nfserr == 0) {
struct inode *inode = resp->fh.fh_dentry->d_inode;
@@ -194,11 +196,11 @@ nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
/*
* Write data to a file
*/
-static int
+static __be32
nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
struct nfsd3_writeres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: WRITE(3) %s %d bytes at %ld%s\n",
SVCFH_fmt(&argp->fh),
@@ -210,7 +212,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
resp->committed = argp->stable;
nfserr = nfsd_write(rqstp, &resp->fh, NULL,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
argp->len,
&resp->committed);
resp->count = argp->count;
@@ -222,13 +224,13 @@ nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
* At least in theory; we'll see how it fares in practice when the
* first reports about SunOS compatibility problems start to pour in...
*/
-static int
+static __be32
nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
struct nfsd3_diropres *resp)
{
svc_fh *dirfhp, *newfhp = NULL;
struct iattr *attr;
- u32 nfserr;
+ __be32 nfserr;
dprintk("nfsd: CREATE(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
@@ -264,11 +266,11 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
/*
* Make directory. This operation is not idempotent.
*/
-static int
+static __be32
nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
struct nfsd3_diropres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: MKDIR(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
@@ -284,11 +286,11 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
RETURN_STATUS(nfserr);
}
-static int
+static __be32
nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
struct nfsd3_diropres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
SVCFH_fmt(&argp->ffh),
@@ -306,11 +308,12 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
/*
* Make socket/fifo/device.
*/
-static int
+static __be32
nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
struct nfsd3_diropres *resp)
{
- int nfserr, type;
+ __be32 nfserr;
+ int type;
dev_t rdev = 0;
dprintk("nfsd: MKNOD(3) %s %.*s\n",
@@ -342,11 +345,11 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
/*
* Remove file/fifo/socket etc.
*/
-static int
+static __be32
nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
struct nfsd3_attrstat *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: REMOVE(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
@@ -362,11 +365,11 @@ nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
/*
* Remove a directory
*/
-static int
+static __be32
nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
struct nfsd3_attrstat *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: RMDIR(3) %s %.*s\n",
SVCFH_fmt(&argp->fh),
@@ -378,11 +381,11 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
RETURN_STATUS(nfserr);
}
-static int
+static __be32
nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
struct nfsd3_renameres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: RENAME(3) %s %.*s ->\n",
SVCFH_fmt(&argp->ffh),
@@ -400,11 +403,11 @@ nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
RETURN_STATUS(nfserr);
}
-static int
+static __be32
nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
struct nfsd3_linkres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: LINK(3) %s ->\n",
SVCFH_fmt(&argp->ffh));
@@ -423,11 +426,12 @@ nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
/*
* Read a portion of a directory.
*/
-static int
+static __be32
nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
struct nfsd3_readdirres *resp)
{
- int nfserr, count;
+ __be32 nfserr;
+ int count;
dprintk("nfsd: READDIR(3) %s %d bytes at %d\n",
SVCFH_fmt(&argp->fh),
@@ -458,11 +462,12 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
* Read a portion of a directory, including file handles and attrs.
* For now, we choose to ignore the dircount parameter.
*/
-static int
+static __be32
nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
struct nfsd3_readdirres *resp)
{
- int nfserr, count = 0;
+ __be32 nfserr;
+ int count = 0;
loff_t offset;
int i;
caddr_t page_addr = NULL;
@@ -516,11 +521,11 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
/*
* Get file system stats
*/
-static int
+static __be32
nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
struct nfsd3_fsstatres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: FSSTAT(3) %s\n",
SVCFH_fmt(&argp->fh));
@@ -533,20 +538,21 @@ nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
/*
* Get file system info
*/
-static int
+static __be32
nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
struct nfsd3_fsinfores *resp)
{
- int nfserr;
+ __be32 nfserr;
+ u32 max_blocksize = svc_max_payload(rqstp);
dprintk("nfsd: FSINFO(3) %s\n",
SVCFH_fmt(&argp->fh));
- resp->f_rtmax = NFSSVC_MAXBLKSIZE;
- resp->f_rtpref = NFSSVC_MAXBLKSIZE;
+ resp->f_rtmax = max_blocksize;
+ resp->f_rtpref = max_blocksize;
resp->f_rtmult = PAGE_SIZE;
- resp->f_wtmax = NFSSVC_MAXBLKSIZE;
- resp->f_wtpref = NFSSVC_MAXBLKSIZE;
+ resp->f_wtmax = max_blocksize;
+ resp->f_wtpref = max_blocksize;
resp->f_wtmult = PAGE_SIZE;
resp->f_dtpref = PAGE_SIZE;
resp->f_maxfilesize = ~(u32) 0;
@@ -574,11 +580,11 @@ nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
/*
* Get pathconf info for the specified file
*/
-static int
+static __be32
nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
struct nfsd3_pathconfres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: PATHCONF(3) %s\n",
SVCFH_fmt(&argp->fh));
@@ -617,11 +623,11 @@ nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
/*
* Commit a file (range) to stable storage.
*/
-static int
+static __be32
nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
struct nfsd3_commitres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
SVCFH_fmt(&argp->fh),
diff --git a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
index 243d94b9653a..b4baca3053c3 100644
--- a/fs/nfsd/nfs3xdr.c
+++ b/fs/nfsd/nfs3xdr.c
@@ -42,23 +42,23 @@ static u32 nfs3_ftypes[] = {
/*
* XDR functions for basic NFS types
*/
-static inline u32 *
-encode_time3(u32 *p, struct timespec *time)
+static inline __be32 *
+encode_time3(__be32 *p, struct timespec *time)
{
*p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
return p;
}
-static inline u32 *
-decode_time3(u32 *p, struct timespec *time)
+static inline __be32 *
+decode_time3(__be32 *p, struct timespec *time)
{
time->tv_sec = ntohl(*p++);
time->tv_nsec = ntohl(*p++);
return p;
}
-static inline u32 *
-decode_fh(u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+decode_fh(__be32 *p, struct svc_fh *fhp)
{
unsigned int size;
fh_init(fhp, NFS3_FHSIZE);
@@ -72,13 +72,13 @@ decode_fh(u32 *p, struct svc_fh *fhp)
}
/* Helper function for NFSv3 ACL code */
-u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp)
+__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp)
{
return decode_fh(p, fhp);
}
-static inline u32 *
-encode_fh(u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+encode_fh(__be32 *p, struct svc_fh *fhp)
{
unsigned int size = fhp->fh_handle.fh_size;
*p++ = htonl(size);
@@ -91,8 +91,8 @@ encode_fh(u32 *p, struct svc_fh *fhp)
* Decode a file name and make sure that the path contains
* no slashes or null bytes.
*/
-static inline u32 *
-decode_filename(u32 *p, char **namp, int *lenp)
+static inline __be32 *
+decode_filename(__be32 *p, char **namp, int *lenp)
{
char *name;
int i;
@@ -107,8 +107,8 @@ decode_filename(u32 *p, char **namp, int *lenp)
return p;
}
-static inline u32 *
-decode_sattr3(u32 *p, struct iattr *iap)
+static inline __be32 *
+decode_sattr3(__be32 *p, struct iattr *iap)
{
u32 tmp;
@@ -153,8 +153,8 @@ decode_sattr3(u32 *p, struct iattr *iap)
return p;
}
-static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
+static inline __be32 *
+encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat)
{
struct dentry *dentry = fhp->fh_dentry;
@@ -186,8 +186,8 @@ encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
return p;
}
-static inline u32 *
-encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
struct inode *inode = fhp->fh_dentry->d_inode;
@@ -224,8 +224,8 @@ encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
* The inode may be NULL if the call failed because of a stale file
* handle. In this case, no attributes are returned.
*/
-static u32 *
-encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+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) {
@@ -243,8 +243,8 @@ encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
}
/* Helper for NFSv3 ACLs */
-u32 *
-nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+__be32 *
+nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
return encode_post_op_attr(rqstp, p, fhp);
}
@@ -252,8 +252,8 @@ nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
/*
* Enocde weak cache consistency data
*/
-static u32 *
-encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+static __be32 *
+encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
struct dentry *dentry = fhp->fh_dentry;
@@ -278,7 +278,7 @@ encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
* XDR decode functions
*/
int
-nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
+nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
@@ -286,7 +286,7 @@ nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args
}
int
-nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_sattrargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -303,7 +303,7 @@ nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_diropargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -314,7 +314,7 @@ nfs3svc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_accessargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
@@ -325,11 +325,12 @@ nfs3svc_decode_accessargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_readargs *args)
{
unsigned int len;
int v,pn;
+ u32 max_blocksize = svc_max_payload(rqstp);
if (!(p = decode_fh(p, &args->fh))
|| !(p = xdr_decode_hyper(p, &args->offset)))
@@ -337,17 +338,16 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
len = args->count = ntohl(*p++);
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > max_blocksize)
+ len = max_blocksize;
/* set up the kvec */
v=0;
while (len > 0) {
- pn = rqstp->rq_resused;
- svc_take_page(rqstp);
- args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
- args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
- len -= args->vec[v].iov_len;
+ pn = rqstp->rq_resused++;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+ rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
+ len -= rqstp->rq_vec[v].iov_len;
v++;
}
args->vlen = v;
@@ -355,10 +355,11 @@ nfs3svc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_writeargs *args)
{
unsigned int len, v, hdr;
+ u32 max_blocksize = svc_max_payload(rqstp);
if (!(p = decode_fh(p, &args->fh))
|| !(p = xdr_decode_hyper(p, &args->offset)))
@@ -373,26 +374,26 @@ nfs3svc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_arg.len - hdr < len)
return 0;
- args->vec[0].iov_base = (void*)p;
- args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
+ rqstp->rq_vec[0].iov_base = (void*)p;
+ rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > max_blocksize)
+ len = max_blocksize;
v= 0;
- while (len > args->vec[v].iov_len) {
- len -= args->vec[v].iov_len;
+ while (len > rqstp->rq_vec[v].iov_len) {
+ len -= rqstp->rq_vec[v].iov_len;
v++;
- args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
- args->vec[v].iov_len = PAGE_SIZE;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
+ rqstp->rq_vec[v].iov_len = PAGE_SIZE;
}
- args->vec[v].iov_len = len;
+ rqstp->rq_vec[v].iov_len = len;
args->vlen = v+1;
- return args->count == args->len && args->vec[0].iov_len > 0;
+ return args->count == args->len && rqstp->rq_vec[0].iov_len > 0;
}
int
-nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_createargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -416,7 +417,7 @@ nfs3svc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
return xdr_argsize_check(rqstp, p);
}
int
-nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_createargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -428,7 +429,7 @@ nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_symlinkargs *args)
{
unsigned int len;
@@ -446,11 +447,11 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
* This page appears in the rq_res.pages list, but as pages_len is always
* 0, it won't get in the way
*/
- svc_take_page(rqstp);
len = ntohl(*p++);
if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
return 0;
- args->tname = new = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->tname = new =
+ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
args->tlen = len;
/* first copy and check from the first page */
old = (char*)p;
@@ -480,7 +481,7 @@ nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_mknodargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -504,7 +505,7 @@ nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_renameargs *args)
{
if (!(p = decode_fh(p, &args->ffh))
@@ -517,19 +518,19 @@ nfs3svc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_readlinkargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer =
+ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
int
-nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_linkargs *args)
{
if (!(p = decode_fh(p, &args->ffh))
@@ -541,7 +542,7 @@ nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_readdirargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
@@ -554,17 +555,18 @@ nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
if (args->count > PAGE_SIZE)
args->count = PAGE_SIZE;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer =
+ page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
int
-nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_readdirargs *args)
{
int len, pn;
+ u32 max_blocksize = svc_max_payload(rqstp);
if (!(p = decode_fh(p, &args->fh)))
return 0;
@@ -573,13 +575,12 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
args->dircount = ntohl(*p++);
args->count = ntohl(*p++);
- len = (args->count > NFSSVC_MAXBLKSIZE) ? NFSSVC_MAXBLKSIZE :
+ len = (args->count > max_blocksize) ? max_blocksize :
args->count;
args->count = len;
while (len > 0) {
- pn = rqstp->rq_resused;
- svc_take_page(rqstp);
+ pn = rqstp->rq_resused++;
if (!args->buffer)
args->buffer = page_address(rqstp->rq_respages[pn]);
len -= PAGE_SIZE;
@@ -589,7 +590,7 @@ nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_commitargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
@@ -608,14 +609,14 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
* will work properly.
*/
int
-nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_ressize_check(rqstp, p);
}
/* GETATTR */
int
-nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_attrstat *resp)
{
if (resp->status == 0)
@@ -625,7 +626,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
/* SETATTR, REMOVE, RMDIR */
int
-nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_attrstat *resp)
{
p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -634,7 +635,7 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, u32 *p,
/* LOOKUP */
int
-nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_diropres *resp)
{
if (resp->status == 0) {
@@ -647,7 +648,7 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
/* ACCESS */
int
-nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_accessres *resp)
{
p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -658,7 +659,7 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
/* READLINK */
int
-nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_readlinkres *resp)
{
p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -668,7 +669,6 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -680,7 +680,7 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
/* READ */
int
-nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_readres *resp)
{
p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -693,7 +693,6 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->count;
if (resp->count & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
@@ -705,7 +704,7 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
/* WRITE */
int
-nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_writeres *resp)
{
p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -720,7 +719,7 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, u32 *p,
/* CREATE, MKDIR, SYMLINK, MKNOD */
int
-nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_diropres *resp)
{
if (resp->status == 0) {
@@ -734,7 +733,7 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
/* RENAME */
int
-nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_renameres *resp)
{
p = encode_wcc_data(rqstp, p, &resp->ffh);
@@ -744,7 +743,7 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, u32 *p,
/* LINK */
int
-nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_linkres *resp)
{
p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -754,7 +753,7 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
/* READDIR */
int
-nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_readdirres *resp)
{
p = encode_post_op_attr(rqstp, p, &resp->fh);
@@ -768,7 +767,6 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = (resp->count) << 2;
/* add the 'tail' to the end of the 'head' page - page 0. */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p++ = 0; /* no more entries */
*p++ = htonl(resp->common.err == nfserr_eof);
@@ -778,8 +776,8 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
return xdr_ressize_check(rqstp, p);
}
-static inline u32 *
-encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name,
+static inline __be32 *
+encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
int namlen, ino_t ino)
{
*p++ = xdr_one; /* mark entry present */
@@ -792,8 +790,8 @@ encode_entry_baggage(struct nfsd3_readdirres *cd, u32 *p, const char *name,
return p;
}
-static inline u32 *
-encode_entryplus_baggage(struct nfsd3_readdirres *cd, u32 *p,
+static inline __be32 *
+encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p,
struct svc_fh *fhp)
{
p = encode_post_op_attr(cd->rqstp, p, fhp);
@@ -855,7 +853,7 @@ encode_entry(struct readdir_cd *ccd, const char *name,
{
struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
common);
- u32 *p = cd->buffer;
+ __be32 *p = cd->buffer;
caddr_t curr_page_addr = NULL;
int pn; /* current page number */
int slen; /* string (name) length */
@@ -921,7 +919,7 @@ encode_entry(struct readdir_cd *ccd, const char *name,
} else if (cd->rqstp->rq_respages[pn+1] != NULL) {
/* temporarily encode entry into next page, then move back to
* current and next page in rq_respages[] */
- u32 *p1, *tmp;
+ __be32 *p1, *tmp;
int len1, len2;
/* grab next page for temporary storage of entry */
@@ -1011,7 +1009,7 @@ nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
/* FSSTAT */
int
-nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_fsstatres *resp)
{
struct kstatfs *s = &resp->stats;
@@ -1033,7 +1031,7 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
/* FSINFO */
int
-nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_fsinfores *resp)
{
*p++ = xdr_zero; /* no post_op_attr */
@@ -1057,7 +1055,7 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, u32 *p,
/* PATHCONF */
int
-nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_pathconfres *resp)
{
*p++ = xdr_zero; /* no post_op_attr */
@@ -1076,7 +1074,7 @@ nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, u32 *p,
/* COMMIT */
int
-nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_commitres *resp)
{
p = encode_wcc_data(rqstp, p, &resp->fh);
@@ -1092,7 +1090,7 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, u32 *p,
* XDR release functions
*/
int
-nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_attrstat *resp)
{
fh_put(&resp->fh);
@@ -1100,7 +1098,7 @@ nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
}
int
-nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
+nfs3svc_release_fhandle2(struct svc_rqst *rqstp, __be32 *p,
struct nfsd3_fhandle_pair *resp)
{
fh_put(&resp->fh1);
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index edb107e61b91..5d94555cdc83 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -63,6 +63,8 @@
#define NFS4_INHERITANCE_FLAGS (NFS4_ACE_FILE_INHERIT_ACE \
| NFS4_ACE_DIRECTORY_INHERIT_ACE | NFS4_ACE_INHERIT_ONLY_ACE)
+#define NFS4_SUPPORTED_FLAGS (NFS4_INHERITANCE_FLAGS | NFS4_ACE_IDENTIFIER_GROUP)
+
#define MASK_EQUAL(mask1, mask2) \
( ((mask1) & NFS4_ACE_MASK_ALL) == ((mask2) & NFS4_ACE_MASK_ALL) )
@@ -96,24 +98,26 @@ deny_mask(u32 allow_mask, unsigned int flags)
/* XXX: modify functions to return NFS errors; they're only ever
* used by nfs code, after all.... */
-static int
-mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
+/* We only map from NFSv4 to POSIX ACLs when setting ACLs, when we err on the
+ * side of being more restrictive, so the mode bit mapping below is
+ * pessimistic. An optimistic version would be needed to handle DENY's,
+ * but we espect to coalesce all ALLOWs and DENYs before mapping to mode
+ * bits. */
+
+static void
+low_mode_from_nfs4(u32 perm, unsigned short *mode, unsigned int flags)
{
- u32 ignore = 0;
+ u32 write_mode = NFS4_WRITE_MODE;
- if (!(flags & NFS4_ACL_DIR))
- ignore |= NFS4_ACE_DELETE_CHILD; /* ignore it */
- perm |= ignore;
+ if (flags & NFS4_ACL_DIR)
+ write_mode |= NFS4_ACE_DELETE_CHILD;
*mode = 0;
if ((perm & NFS4_READ_MODE) == NFS4_READ_MODE)
*mode |= ACL_READ;
- if ((perm & NFS4_WRITE_MODE) == NFS4_WRITE_MODE)
+ if ((perm & write_mode) == write_mode)
*mode |= ACL_WRITE;
if ((perm & NFS4_EXECUTE_MODE) == NFS4_EXECUTE_MODE)
*mode |= ACL_EXECUTE;
- if (!MASK_EQUAL(perm, ignore|mask_from_posix(*mode, flags)))
- return -EINVAL;
- return 0;
}
struct ace_container {
@@ -338,38 +342,6 @@ sort_pacl(struct posix_acl *pacl)
return;
}
-static int
-write_pace(struct nfs4_ace *ace, struct posix_acl *pacl,
- struct posix_acl_entry **pace, short tag, unsigned int flags)
-{
- struct posix_acl_entry *this = *pace;
-
- if (*pace == pacl->a_entries + pacl->a_count)
- return -EINVAL; /* fell off the end */
- (*pace)++;
- this->e_tag = tag;
- if (tag == ACL_USER_OBJ)
- flags |= NFS4_ACL_OWNER;
- if (mode_from_nfs4(ace->access_mask, &this->e_perm, flags))
- return -EINVAL;
- this->e_id = (tag == ACL_USER || tag == ACL_GROUP ?
- ace->who : ACL_UNDEFINED_ID);
- return 0;
-}
-
-static struct nfs4_ace *
-get_next_v4_ace(struct list_head **p, struct list_head *head)
-{
- struct nfs4_ace *ace;
-
- *p = (*p)->next;
- if (*p == head)
- return NULL;
- ace = list_entry(*p, struct nfs4_ace, l_ace);
-
- return ace;
-}
-
int
nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
struct posix_acl **dpacl, unsigned int flags)
@@ -385,42 +357,23 @@ nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
goto out;
error = nfs4_acl_split(acl, dacl);
- if (error < 0)
+ if (error)
goto out_acl;
- if (pacl != NULL) {
- if (acl->naces == 0) {
- error = -ENODATA;
- goto try_dpacl;
- }
-
- *pacl = _nfsv4_to_posix_one(acl, flags);
- if (IS_ERR(*pacl)) {
- error = PTR_ERR(*pacl);
- *pacl = NULL;
- goto out_acl;
- }
+ *pacl = _nfsv4_to_posix_one(acl, flags);
+ if (IS_ERR(*pacl)) {
+ error = PTR_ERR(*pacl);
+ *pacl = NULL;
+ goto out_acl;
}
-try_dpacl:
- if (dpacl != NULL) {
- if (dacl->naces == 0) {
- if (pacl == NULL || *pacl == NULL)
- error = -ENODATA;
- goto out_acl;
- }
-
- error = 0;
- *dpacl = _nfsv4_to_posix_one(dacl, flags);
- if (IS_ERR(*dpacl)) {
- error = PTR_ERR(*dpacl);
- *dpacl = NULL;
- goto out_acl;
- }
+ *dpacl = _nfsv4_to_posix_one(dacl, flags);
+ if (IS_ERR(*dpacl)) {
+ error = PTR_ERR(*dpacl);
+ *dpacl = NULL;
}
-
out_acl:
- if (error && pacl) {
+ if (error) {
posix_acl_release(*pacl);
*pacl = NULL;
}
@@ -429,349 +382,311 @@ out:
return error;
}
+/*
+ * While processing the NFSv4 ACE, this maintains bitmasks representing
+ * which permission bits have been allowed and which denied to a given
+ * entity: */
+struct posix_ace_state {
+ u32 allow;
+ u32 deny;
+};
+
+struct posix_user_ace_state {
+ uid_t uid;
+ struct posix_ace_state perms;
+};
+
+struct posix_ace_state_array {
+ int n;
+ struct posix_user_ace_state aces[];
+};
+
+/*
+ * While processing the NFSv4 ACE, this maintains the partial permissions
+ * calculated so far: */
+
+struct posix_acl_state {
+ struct posix_ace_state owner;
+ struct posix_ace_state group;
+ struct posix_ace_state other;
+ struct posix_ace_state everyone;
+ struct posix_ace_state mask; /* Deny unused in this case */
+ struct posix_ace_state_array *users;
+ struct posix_ace_state_array *groups;
+};
+
static int
-same_who(struct nfs4_ace *a, struct nfs4_ace *b)
+init_state(struct posix_acl_state *state, int cnt)
{
- return a->whotype == b->whotype &&
- (a->whotype != NFS4_ACL_WHO_NAMED || a->who == b->who);
+ int alloc;
+
+ memset(state, 0, sizeof(struct posix_acl_state));
+ /*
+ * In the worst case, each individual acl could be for a distinct
+ * named user or group, but we don't no which, so we allocate
+ * enough space for either:
+ */
+ alloc = sizeof(struct posix_ace_state_array)
+ + cnt*sizeof(struct posix_ace_state);
+ state->users = kzalloc(alloc, GFP_KERNEL);
+ if (!state->users)
+ return -ENOMEM;
+ state->groups = kzalloc(alloc, GFP_KERNEL);
+ if (!state->groups) {
+ kfree(state->users);
+ return -ENOMEM;
+ }
+ return 0;
}
-static int
-complementary_ace_pair(struct nfs4_ace *allow, struct nfs4_ace *deny,
- unsigned int flags)
-{
- int ignore = 0;
- if (!(flags & NFS4_ACL_DIR))
- ignore |= NFS4_ACE_DELETE_CHILD;
- return MASK_EQUAL(ignore|deny_mask(allow->access_mask, flags),
- ignore|deny->access_mask) &&
- allow->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
- deny->type == NFS4_ACE_ACCESS_DENIED_ACE_TYPE &&
- allow->flag == deny->flag &&
- same_who(allow, deny);
+static void
+free_state(struct posix_acl_state *state) {
+ kfree(state->users);
+ kfree(state->groups);
}
-static inline int
-user_obj_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+static inline void add_to_mask(struct posix_acl_state *state, struct posix_ace_state *astate)
{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
-
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace2type(ace) != ACL_USER_OBJ)
- goto out;
- error = write_pace(ace, pacl, pace, ACL_USER_OBJ, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace2 == NULL)
- goto out;
- if (!complementary_ace_pair(ace, ace2, flags))
- goto out;
- error = 0;
-out:
- return error;
+ state->mask.allow |= astate->allow;
}
-static inline int
-users_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct nfs4_ace **mask_ace,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
-{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
+/*
+ * Certain bits (SYNCHRONIZE, DELETE, WRITE_OWNER, READ/WRITE_NAMED_ATTRS,
+ * READ_ATTRIBUTES, READ_ACL) are currently unenforceable and don't translate
+ * to traditional read/write/execute permissions.
+ *
+ * It's problematic to reject acls that use certain mode bits, because it
+ * places the burden on users to learn the rules about which bits one
+ * particular server sets, without giving the user a lot of help--we return an
+ * error that could mean any number of different things. To make matters
+ * worse, the problematic bits might be introduced by some application that's
+ * automatically mapping from some other acl model.
+ *
+ * So wherever possible we accept anything, possibly erring on the side of
+ * denying more permissions than necessary.
+ *
+ * However we do reject *explicit* DENY's of a few bits representing
+ * permissions we could never deny:
+ */
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- while (ace2type(ace) == ACL_USER) {
- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
- goto out;
- if (*mask_ace &&
- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
- goto out;
- *mask_ace = ace;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
- goto out;
- error = write_pace(ace, pacl, pace, ACL_USER, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace2 == NULL)
- goto out;
- if (!complementary_ace_pair(ace, ace2, flags))
- goto out;
- if ((*mask_ace)->flag != ace2->flag ||
- !same_who(*mask_ace, ace2))
- goto out;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- }
- error = 0;
-out:
- return error;
+static inline int check_deny(u32 mask, int isowner)
+{
+ if (mask & (NFS4_ACE_READ_ATTRIBUTES | NFS4_ACE_READ_ACL))
+ return -EINVAL;
+ if (!isowner)
+ return 0;
+ if (mask & (NFS4_ACE_WRITE_ATTRIBUTES | NFS4_ACE_WRITE_ACL))
+ return -EINVAL;
+ return 0;
}
-static inline int
-group_obj_and_groups_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct nfs4_ace **mask_ace,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+static struct posix_acl *
+posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
- struct ace_container *ac;
- struct list_head group_l;
-
- INIT_LIST_HEAD(&group_l);
- ace = list_entry(*p, struct nfs4_ace, l_ace);
-
- /* group owner (mask and allow aces) */
+ struct posix_acl_entry *pace;
+ struct posix_acl *pacl;
+ int nace;
+ int i, error = 0;
- if (pacl->a_count != 3) {
- /* then the group owner should be preceded by mask */
- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
- goto out;
- if (*mask_ace &&
- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
- goto out;
- *mask_ace = ace;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
+ nace = 4 + state->users->n + state->groups->n;
+ pacl = posix_acl_alloc(nace, GFP_KERNEL);
+ if (!pacl)
+ return ERR_PTR(-ENOMEM);
- if ((*mask_ace)->flag != ace->flag || !same_who(*mask_ace, ace))
- goto out;
+ pace = pacl->a_entries;
+ pace->e_tag = ACL_USER_OBJ;
+ error = check_deny(state->owner.deny, 1);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->owner.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
+
+ for (i=0; i < state->users->n; i++) {
+ pace++;
+ pace->e_tag = ACL_USER;
+ error = check_deny(state->users->aces[i].perms.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->users->aces[i].perms.allow,
+ &pace->e_perm, flags);
+ pace->e_id = state->users->aces[i].uid;
+ add_to_mask(state, &state->users->aces[i].perms);
}
- if (ace2type(ace) != ACL_GROUP_OBJ)
- goto out;
-
- ac = kmalloc(sizeof(*ac), GFP_KERNEL);
- error = -ENOMEM;
- if (ac == NULL)
- goto out;
- ac->ace = ace;
- list_add_tail(&ac->ace_l, &group_l);
-
- error = -EINVAL;
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
- goto out;
-
- error = write_pace(ace, pacl, pace, ACL_GROUP_OBJ, flags);
- if (error < 0)
- goto out;
-
- error = -EINVAL;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
-
- /* groups (mask and allow aces) */
-
- while (ace2type(ace) == ACL_GROUP) {
- if (*mask_ace == NULL)
- goto out;
-
- if (ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE ||
- !MASK_EQUAL(ace->access_mask, (*mask_ace)->access_mask))
- goto out;
- *mask_ace = ace;
+ pace++;
+ pace->e_tag = ACL_GROUP_OBJ;
+ error = check_deny(state->group.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->group.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
+ add_to_mask(state, &state->group);
+
+ for (i=0; i < state->groups->n; i++) {
+ pace++;
+ pace->e_tag = ACL_GROUP;
+ error = check_deny(state->groups->aces[i].perms.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->groups->aces[i].perms.allow,
+ &pace->e_perm, flags);
+ pace->e_id = state->groups->aces[i].uid;
+ add_to_mask(state, &state->groups->aces[i].perms);
+ }
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- ac = kmalloc(sizeof(*ac), GFP_KERNEL);
- error = -ENOMEM;
- if (ac == NULL)
- goto out;
- error = -EINVAL;
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE ||
- !same_who(ace, *mask_ace))
- goto out;
+ pace++;
+ pace->e_tag = ACL_MASK;
+ low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
- ac->ace = ace;
- list_add_tail(&ac->ace_l, &group_l);
+ pace++;
+ pace->e_tag = ACL_OTHER;
+ error = check_deny(state->other.deny, 0);
+ if (error)
+ goto out_err;
+ low_mode_from_nfs4(state->other.allow, &pace->e_perm, flags);
+ pace->e_id = ACL_UNDEFINED_ID;
- error = write_pace(ace, pacl, pace, ACL_GROUP, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- }
+ return pacl;
+out_err:
+ posix_acl_release(pacl);
+ return ERR_PTR(error);
+}
- /* group owner (deny ace) */
+static inline void allow_bits(struct posix_ace_state *astate, u32 mask)
+{
+ /* Allow all bits in the mask not already denied: */
+ astate->allow |= mask & ~astate->deny;
+}
- if (ace2type(ace) != ACL_GROUP_OBJ)
- goto out;
- ac = list_entry(group_l.next, struct ace_container, ace_l);
- ace2 = ac->ace;
- if (!complementary_ace_pair(ace2, ace, flags))
- goto out;
- list_del(group_l.next);
- kfree(ac);
+static inline void deny_bits(struct posix_ace_state *astate, u32 mask)
+{
+ /* Deny all bits in the mask not already allowed: */
+ astate->deny |= mask & ~astate->allow;
+}
- /* groups (deny aces) */
+static int find_uid(struct posix_acl_state *state, struct posix_ace_state_array *a, uid_t uid)
+{
+ int i;
- while (!list_empty(&group_l)) {
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace2type(ace) != ACL_GROUP)
- goto out;
- ac = list_entry(group_l.next, struct ace_container, ace_l);
- ace2 = ac->ace;
- if (!complementary_ace_pair(ace2, ace, flags))
- goto out;
- list_del(group_l.next);
- kfree(ac);
- }
+ for (i = 0; i < a->n; i++)
+ if (a->aces[i].uid == uid)
+ return i;
+ /* Not found: */
+ a->n++;
+ a->aces[i].uid = uid;
+ a->aces[i].perms.allow = state->everyone.allow;
+ a->aces[i].perms.deny = state->everyone.deny;
- ace = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace == NULL)
- goto out;
- if (ace2type(ace) != ACL_OTHER)
- goto out;
- error = 0;
-out:
- while (!list_empty(&group_l)) {
- ac = list_entry(group_l.next, struct ace_container, ace_l);
- list_del(group_l.next);
- kfree(ac);
- }
- return error;
+ return i;
}
-static inline int
-mask_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct nfs4_ace **mask_ace,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+static void deny_bits_array(struct posix_ace_state_array *a, u32 mask)
{
- int error = -EINVAL;
- struct nfs4_ace *ace;
+ int i;
- ace = list_entry(*p, struct nfs4_ace, l_ace);
- if (pacl->a_count != 3) {
- if (*mask_ace == NULL)
- goto out;
- (*mask_ace)->access_mask = deny_mask((*mask_ace)->access_mask, flags);
- write_pace(*mask_ace, pacl, pace, ACL_MASK, flags);
- }
- error = 0;
-out:
- return error;
+ for (i=0; i < a->n; i++)
+ deny_bits(&a->aces[i].perms, mask);
}
-static inline int
-other_from_v4(struct nfs4_acl *n4acl, struct list_head **p,
- struct posix_acl *pacl, struct posix_acl_entry **pace,
- unsigned int flags)
+static void allow_bits_array(struct posix_ace_state_array *a, u32 mask)
{
- int error = -EINVAL;
- struct nfs4_ace *ace, *ace2;
+ int i;
- ace = list_entry(*p, struct nfs4_ace, l_ace);
- if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE)
- goto out;
- error = write_pace(ace, pacl, pace, ACL_OTHER, flags);
- if (error < 0)
- goto out;
- error = -EINVAL;
- ace2 = get_next_v4_ace(p, &n4acl->ace_head);
- if (ace2 == NULL)
- goto out;
- if (!complementary_ace_pair(ace, ace2, flags))
- goto out;
- error = 0;
-out:
- return error;
+ for (i=0; i < a->n; i++)
+ allow_bits(&a->aces[i].perms, mask);
}
-static int
-calculate_posix_ace_count(struct nfs4_acl *n4acl)
+static void process_one_v4_ace(struct posix_acl_state *state,
+ struct nfs4_ace *ace)
{
- if (n4acl->naces == 6) /* owner, owner group, and other only */
- return 3;
- else { /* Otherwise there must be a mask entry. */
- /* Also, the remaining entries are for named users and
- * groups, and come in threes (mask, allow, deny): */
- if (n4acl->naces < 7)
- return -EINVAL;
- if ((n4acl->naces - 7) % 3)
- return -EINVAL;
- return 4 + (n4acl->naces - 7)/3;
+ u32 mask = ace->access_mask;
+ int i;
+
+ switch (ace2type(ace)) {
+ case ACL_USER_OBJ:
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->owner, mask);
+ } else {
+ deny_bits(&state->owner, mask);
+ }
+ break;
+ case ACL_USER:
+ i = find_uid(state, state->users, ace->who);
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->users->aces[i].perms, mask);
+ } else {
+ deny_bits(&state->users->aces[i].perms, mask);
+ mask = state->users->aces[i].perms.deny;
+ deny_bits(&state->owner, mask);
+ }
+ break;
+ case ACL_GROUP_OBJ:
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->group, mask);
+ } else {
+ deny_bits(&state->group, mask);
+ mask = state->group.deny;
+ deny_bits(&state->owner, mask);
+ deny_bits(&state->everyone, mask);
+ deny_bits_array(state->users, mask);
+ deny_bits_array(state->groups, mask);
+ }
+ break;
+ case ACL_GROUP:
+ i = find_uid(state, state->groups, ace->who);
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->groups->aces[i].perms, mask);
+ } else {
+ deny_bits(&state->groups->aces[i].perms, mask);
+ mask = state->groups->aces[i].perms.deny;
+ deny_bits(&state->owner, mask);
+ deny_bits(&state->group, mask);
+ deny_bits(&state->everyone, mask);
+ deny_bits_array(state->users, mask);
+ deny_bits_array(state->groups, mask);
+ }
+ break;
+ case ACL_OTHER:
+ if (ace->type == NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE) {
+ allow_bits(&state->owner, mask);
+ allow_bits(&state->group, mask);
+ allow_bits(&state->other, mask);
+ allow_bits(&state->everyone, mask);
+ allow_bits_array(state->users, mask);
+ allow_bits_array(state->groups, mask);
+ } else {
+ deny_bits(&state->owner, mask);
+ deny_bits(&state->group, mask);
+ deny_bits(&state->other, mask);
+ deny_bits(&state->everyone, mask);
+ deny_bits_array(state->users, mask);
+ deny_bits_array(state->groups, mask);
+ }
}
}
-
static struct posix_acl *
_nfsv4_to_posix_one(struct nfs4_acl *n4acl, unsigned int flags)
{
+ struct posix_acl_state state;
struct posix_acl *pacl;
- int error = -EINVAL, nace = 0;
- struct list_head *p;
- struct nfs4_ace *mask_ace = NULL;
- struct posix_acl_entry *pace;
-
- nace = calculate_posix_ace_count(n4acl);
- if (nace < 0)
- goto out_err;
-
- pacl = posix_acl_alloc(nace, GFP_KERNEL);
- error = -ENOMEM;
- if (pacl == NULL)
- goto out_err;
-
- pace = &pacl->a_entries[0];
- p = &n4acl->ace_head;
-
- error = user_obj_from_v4(n4acl, &p, pacl, &pace, flags);
- if (error)
- goto out_acl;
-
- error = users_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
- if (error)
- goto out_acl;
+ struct nfs4_ace *ace;
+ int ret;
- error = group_obj_and_groups_from_v4(n4acl, &p, &mask_ace, pacl, &pace,
- flags);
- if (error)
- goto out_acl;
+ ret = init_state(&state, n4acl->naces);
+ if (ret)
+ return ERR_PTR(ret);
- error = mask_from_v4(n4acl, &p, &mask_ace, pacl, &pace, flags);
- if (error)
- goto out_acl;
- error = other_from_v4(n4acl, &p, pacl, &pace, flags);
- if (error)
- goto out_acl;
+ list_for_each_entry(ace, &n4acl->ace_head, l_ace)
+ process_one_v4_ace(&state, ace);
- error = -EINVAL;
- if (p->next != &n4acl->ace_head)
- goto out_acl;
- if (pace != pacl->a_entries + pacl->a_count)
- goto out_acl;
+ pacl = posix_state_to_acl(&state, flags);
- sort_pacl(pacl);
+ free_state(&state);
- return pacl;
-out_acl:
- posix_acl_release(pacl);
-out_err:
- pacl = ERR_PTR(error);
+ if (!IS_ERR(pacl))
+ sort_pacl(pacl);
return pacl;
}
@@ -785,22 +700,41 @@ nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
list_for_each_safe(h, n, &acl->ace_head) {
ace = list_entry(h, struct nfs4_ace, l_ace);
- if ((ace->flag & NFS4_INHERITANCE_FLAGS)
- != NFS4_INHERITANCE_FLAGS)
- continue;
+ if (ace->type != NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE &&
+ ace->type != NFS4_ACE_ACCESS_DENIED_ACE_TYPE)
+ return -EINVAL;
- error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
- ace->access_mask, ace->whotype, ace->who);
- if (error < 0)
- goto out;
+ if (ace->flag & ~NFS4_SUPPORTED_FLAGS)
+ return -EINVAL;
- list_del(h);
- kfree(ace);
- acl->naces--;
+ switch (ace->flag & NFS4_INHERITANCE_FLAGS) {
+ case 0:
+ /* Leave this ace in the effective acl: */
+ continue;
+ case NFS4_INHERITANCE_FLAGS:
+ /* Add this ace to the default acl and remove it
+ * from the effective acl: */
+ error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+ ace->access_mask, ace->whotype, ace->who);
+ if (error)
+ return error;
+ list_del(h);
+ kfree(ace);
+ acl->naces--;
+ break;
+ case NFS4_INHERITANCE_FLAGS & ~NFS4_ACE_INHERIT_ONLY_ACE:
+ /* Add this ace to the default, but leave it in
+ * the effective acl as well: */
+ error = nfs4_acl_add_ace(dacl, ace->type, ace->flag,
+ ace->access_mask, ace->whotype, ace->who);
+ if (error)
+ return error;
+ break;
+ default:
+ return -EINVAL;
+ }
}
-
-out:
- return error;
+ return 0;
}
static short
@@ -930,23 +864,6 @@ nfs4_acl_write_who(int who, char *p)
return -1;
}
-static inline int
-match_who(struct nfs4_ace *ace, uid_t owner, gid_t group, uid_t who)
-{
- switch (ace->whotype) {
- case NFS4_ACL_WHO_NAMED:
- return who == ace->who;
- case NFS4_ACL_WHO_OWNER:
- return who == owner;
- case NFS4_ACL_WHO_GROUP:
- return who == group;
- case NFS4_ACL_WHO_EVERYONE:
- return 1;
- default:
- return 0;
- }
-}
-
EXPORT_SYMBOL(nfs4_acl_new);
EXPORT_SYMBOL(nfs4_acl_free);
EXPORT_SYMBOL(nfs4_acl_add_ace);
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 8583d99ee740..f57655a7a2b6 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -85,8 +85,8 @@ enum nfs_cb_opnum4 {
/*
* Generic encode routines from fs/nfs/nfs4xdr.c
*/
-static inline u32 *
-xdr_writemem(u32 *p, const void *ptr, int nbytes)
+static inline __be32 *
+xdr_writemem(__be32 *p, const void *ptr, int nbytes)
{
int tmp = XDR_QUADLEN(nbytes);
if (!tmp)
@@ -131,7 +131,7 @@ xdr_error: \
#define READ_BUF(nbytes) do { \
p = xdr_inline_decode(xdr, nbytes); \
if (!p) { \
- dprintk("NFSD: %s: reply buffer overflowed in line %d.", \
+ dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \
__FUNCTION__, __LINE__); \
return -EIO; \
} \
@@ -205,7 +205,7 @@ nfs_cb_stat_to_errno(int stat)
static int
encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
{
- u32 * p;
+ __be32 * p;
RESERVE_SPACE(16);
WRITE32(0); /* tag length is always 0 */
@@ -218,7 +218,7 @@ encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
static int
encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
{
- u32 *p;
+ __be32 *p;
int len = cb_rec->cbr_fhlen;
RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len);
@@ -231,7 +231,7 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec)
}
static int
-nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p)
+nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p)
{
struct xdr_stream xdrs, *xdr = &xdrs;
@@ -241,7 +241,7 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p)
}
static int
-nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args)
+nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args)
{
struct xdr_stream xdr;
struct nfs4_cb_compound_hdr hdr = {
@@ -257,7 +257,7 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args
static int
decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
- u32 *p;
+ __be32 *p;
READ_BUF(8);
READ32(hdr->status);
@@ -272,7 +272,7 @@ decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
static int
decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
{
- u32 *p;
+ __be32 *p;
u32 op;
int32_t nfserr;
@@ -291,13 +291,13 @@ decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
}
static int
-nfs4_xdr_dec_cb_null(struct rpc_rqst *req, u32 *p)
+nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
{
return 0;
}
static int
-nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p)
+nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p)
{
struct xdr_stream xdr;
struct nfs4_cb_compound_hdr hdr;
@@ -421,7 +421,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
/* Create RPC client */
cb->cb_client = rpc_create(&args);
- if (!cb->cb_client) {
+ if (IS_ERR(cb->cb_client)) {
dprintk("NFSD: couldn't create callback client\n");
goto out_err;
}
@@ -448,10 +448,10 @@ nfsd4_probe_callback(struct nfs4_client *clp)
out_rpciod:
atomic_dec(&clp->cl_count);
rpciod_down();
- cb->cb_client = NULL;
out_clnt:
rpc_shutdown_client(cb->cb_client);
out_err:
+ cb->cb_client = NULL;
dprintk("NFSD: warning: no callback path to client %.*s\n",
(int)clp->cl_name.len, clp->cl_name.data);
}
@@ -461,7 +461,7 @@ nfs4_cb_null(struct rpc_task *task, void *dummy)
{
struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp;
struct nfs4_callback *cb = &clp->cl_callback;
- u32 addr = htonl(cb->cb_addr);
+ __be32 addr = htonl(cb->cb_addr);
dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status);
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index bea6b9478114..b1902ebaab41 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -573,10 +573,9 @@ idmap_lookup(struct svc_rqst *rqstp,
struct idmap_defer_req *mdr;
int ret;
- mdr = kmalloc(sizeof(*mdr), GFP_KERNEL);
+ mdr = kzalloc(sizeof(*mdr), GFP_KERNEL);
if (!mdr)
return -ENOMEM;
- memset(mdr, 0, sizeof(*mdr));
atomic_set(&mdr->count, 1);
init_waitqueue_head(&mdr->waitq);
mdr->req.defer = idmap_defer;
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index ee4eff27aedc..0a7bbdc4a10a 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -67,32 +67,32 @@ fh_dup2(struct svc_fh *dst, struct svc_fh *src)
*dst = *src;
}
-static int
-do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+static __be32
+do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
{
- int accmode, status;
+ __be32 status;
if (open->op_truncate &&
!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
return nfserr_inval;
- accmode = MAY_NOP;
if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
- accmode = MAY_READ;
- if (open->op_share_deny & NFS4_SHARE_ACCESS_WRITE)
+ accmode |= MAY_READ;
+ if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
accmode |= (MAY_WRITE | MAY_TRUNC);
- accmode |= MAY_OWNER_OVERRIDE;
+ if (open->op_share_deny & NFS4_SHARE_DENY_WRITE)
+ accmode |= MAY_WRITE;
status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
return status;
}
-static int
+static __be32
do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct svc_fh resfh;
- int status;
+ __be32 status;
fh_init(&resfh, NFS4_FHSIZE);
open->op_truncate = 0;
@@ -124,17 +124,17 @@ do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_o
&resfh.fh_handle.fh_base,
resfh.fh_handle.fh_size);
- status = do_open_permission(rqstp, current_fh, open);
+ status = do_open_permission(rqstp, current_fh, open, MAY_NOP);
}
fh_put(&resfh);
return status;
}
-static int
+static __be32
do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
- int status;
+ __be32 status;
/* Only reclaims from previously confirmed clients are valid */
if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
@@ -155,16 +155,16 @@ do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_
open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
(open->op_iattr.ia_size == 0);
- status = do_open_permission(rqstp, current_fh, open);
+ status = do_open_permission(rqstp, current_fh, open, MAY_OWNER_OVERRIDE);
return status;
}
-static inline int
+static inline __be32
nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, struct nfs4_stateowner **replay_owner)
{
- int status;
+ __be32 status;
dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
(int)open->op_fname.len, open->op_fname.data,
open->op_stateowner);
@@ -177,7 +177,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
/* check seqid for replay. set nfs4_owner */
status = nfsd4_process_open1(open);
- if (status == NFSERR_REPLAY_ME) {
+ if (status == nfserr_replay_me) {
struct nfs4_replay *rp = &open->op_stateowner->so_replay;
fh_put(current_fh);
current_fh->fh_handle.fh_size = rp->rp_openfh_len;
@@ -188,7 +188,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
dprintk("nfsd4_open: replay failed"
" restoring previous filehandle\n");
else
- status = NFSERR_REPLAY_ME;
+ status = nfserr_replay_me;
}
if (status)
goto out;
@@ -261,7 +261,7 @@ out:
/*
* filehandle-manipulating ops.
*/
-static inline int
+static inline __be32
nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh)
{
if (!current_fh->fh_dentry)
@@ -271,7 +271,7 @@ nfsd4_getfh(struct svc_fh *current_fh, struct svc_fh **getfh)
return nfs_ok;
}
-static inline int
+static inline __be32
nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putfh *putfh)
{
fh_put(current_fh);
@@ -280,10 +280,10 @@ nfsd4_putfh(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_putf
return fh_verify(rqstp, current_fh, 0, MAY_NOP);
}
-static inline int
+static inline __be32
nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
{
- int status;
+ __be32 status;
fh_put(current_fh);
status = exp_pseudoroot(rqstp->rq_client, current_fh,
@@ -291,7 +291,7 @@ nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
return status;
}
-static inline int
+static inline __be32
nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
{
if (!save_fh->fh_dentry)
@@ -301,7 +301,7 @@ nfsd4_restorefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
return nfs_ok;
}
-static inline int
+static inline __be32
nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
{
if (!current_fh->fh_dentry)
@@ -314,7 +314,7 @@ nfsd4_savefh(struct svc_fh *current_fh, struct svc_fh *save_fh)
/*
* misc nfsv4 ops
*/
-static inline int
+static inline __be32
nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_access *access)
{
if (access->ac_req_access & ~NFS3_ACCESS_FULL)
@@ -324,10 +324,10 @@ nfsd4_access(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_acc
return nfsd_access(rqstp, current_fh, &access->ac_resp_access, &access->ac_supported);
}
-static inline int
+static inline __be32
nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_commit *commit)
{
- int status;
+ __be32 status;
u32 *p = (u32 *)commit->co_verf.data;
*p++ = nfssvc_boot.tv_sec;
@@ -339,11 +339,11 @@ nfsd4_commit(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_com
return status;
}
-static int
+static __be32
nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_create *create)
{
struct svc_fh resfh;
- int status;
+ __be32 status;
dev_t rdev;
fh_init(&resfh, NFS4_FHSIZE);
@@ -423,10 +423,10 @@ nfsd4_create(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_cre
return status;
}
-static inline int
+static inline __be32
nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_getattr *getattr)
{
- int status;
+ __be32 status;
status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
if (status)
@@ -442,11 +442,11 @@ nfsd4_getattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_ge
return nfs_ok;
}
-static inline int
+static inline __be32
nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct svc_fh *save_fh, struct nfsd4_link *link)
{
- int status = nfserr_nofilehandle;
+ __be32 status = nfserr_nofilehandle;
if (!save_fh->fh_dentry)
return status;
@@ -456,11 +456,11 @@ nfsd4_link(struct svc_rqst *rqstp, struct svc_fh *current_fh,
return status;
}
-static int
+static __be32
nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
{
struct svc_fh tmp_fh;
- int ret;
+ __be32 ret;
fh_init(&tmp_fh, NFS4_FHSIZE);
if((ret = exp_pseudoroot(rqstp->rq_client, &tmp_fh,
@@ -474,16 +474,16 @@ nfsd4_lookupp(struct svc_rqst *rqstp, struct svc_fh *current_fh)
return nfsd_lookup(rqstp, current_fh, "..", 2, current_fh);
}
-static inline int
+static inline __be32
nfsd4_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lookup *lookup)
{
return nfsd_lookup(rqstp, current_fh, lookup->lo_name, lookup->lo_len, current_fh);
}
-static inline int
+static inline __be32
nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
{
- int status;
+ __be32 status;
/* no need to check permission - this will be done in nfsd_read() */
@@ -508,7 +508,7 @@ out:
return status;
}
-static inline int
+static inline __be32
nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readdir *readdir)
{
u64 cookie = readdir->rd_cookie;
@@ -531,7 +531,7 @@ nfsd4_readdir(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_re
return nfs_ok;
}
-static inline int
+static inline __be32
nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_readlink *readlink)
{
readlink->rl_rqstp = rqstp;
@@ -539,10 +539,10 @@ nfsd4_readlink(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_r
return nfs_ok;
}
-static inline int
+static inline __be32
nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_remove *remove)
{
- int status;
+ __be32 status;
if (nfs4_in_grace())
return nfserr_grace;
@@ -556,11 +556,11 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem
return status;
}
-static inline int
+static inline __be32
nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct svc_fh *save_fh, struct nfsd4_rename *rename)
{
- int status = nfserr_nofilehandle;
+ __be32 status = nfserr_nofilehandle;
if (!save_fh->fh_dentry)
return status;
@@ -589,10 +589,10 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
return status;
}
-static inline int
+static inline __be32
nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_setattr *setattr)
{
- int status = nfs_ok;
+ __be32 status = nfs_ok;
if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
nfs4_lock_state();
@@ -600,7 +600,7 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se
&setattr->sa_stateid, CHECK_FH | WR_STATE, NULL);
nfs4_unlock_state();
if (status) {
- dprintk("NFSD: nfsd4_setattr: couldn't process stateid!");
+ dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
return status;
}
}
@@ -614,13 +614,13 @@ nfsd4_setattr(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_se
return status;
}
-static inline int
+static inline __be32
nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_write *write)
{
stateid_t *stateid = &write->wr_stateid;
struct file *filp = NULL;
u32 *p;
- int status = nfs_ok;
+ __be32 status = nfs_ok;
/* no need to check permission - this will be done in nfsd_write() */
@@ -646,7 +646,7 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
*p++ = nfssvc_boot.tv_usec;
status = nfsd_write(rqstp, current_fh, filp, write->wr_offset,
- write->wr_vec, write->wr_vlen, write->wr_buflen,
+ rqstp->rq_vec, write->wr_vlen, write->wr_buflen,
&write->wr_how_written);
if (filp)
fput(filp);
@@ -661,12 +661,12 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
* attributes matched. VERIFY is implemented by mapping NFSERR_SAME
* to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
*/
-static int
+static __be32
nfsd4_verify(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_verify *verify)
{
- u32 *buf, *p;
+ __be32 *buf, *p;
int count;
- int status;
+ __be32 status;
status = fh_verify(rqstp, current_fh, 0, MAY_NOP);
if (status)
@@ -715,7 +715,7 @@ out_kfree:
/*
* NULL call.
*/
-static int
+static __be32
nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
return nfs_ok;
@@ -731,7 +731,7 @@ static inline void nfsd4_increment_op_stats(u32 opnum)
/*
* COMPOUND call.
*/
-static int
+static __be32
nfsd4_proc_compound(struct svc_rqst *rqstp,
struct nfsd4_compoundargs *args,
struct nfsd4_compoundres *resp)
@@ -741,7 +741,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
struct svc_fh *save_fh = NULL;
struct nfs4_stateowner *replay_owner = NULL;
int slack_space; /* in words, not bytes! */
- int status;
+ __be32 status;
status = nfserr_resource;
current_fh = kmalloc(sizeof(*current_fh), GFP_KERNEL);
@@ -802,13 +802,29 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
* SETCLIENTID_CONFIRM, PUTFH and PUTROOTFH
* require a valid current filehandle
*/
- if ((!current_fh->fh_dentry) &&
- !((op->opnum == OP_PUTFH) || (op->opnum == OP_PUTROOTFH) ||
- (op->opnum == OP_SETCLIENTID) ||
- (op->opnum == OP_SETCLIENTID_CONFIRM) ||
- (op->opnum == OP_RENEW) || (op->opnum == OP_RESTOREFH) ||
- (op->opnum == OP_RELEASE_LOCKOWNER))) {
- op->status = nfserr_nofilehandle;
+ if (!current_fh->fh_dentry) {
+ if (!((op->opnum == OP_PUTFH) ||
+ (op->opnum == OP_PUTROOTFH) ||
+ (op->opnum == OP_SETCLIENTID) ||
+ (op->opnum == OP_SETCLIENTID_CONFIRM) ||
+ (op->opnum == OP_RENEW) ||
+ (op->opnum == OP_RESTOREFH) ||
+ (op->opnum == OP_RELEASE_LOCKOWNER))) {
+ op->status = nfserr_nofilehandle;
+ goto encode_op;
+ }
+ }
+ /* Check must be done at start of each operation, except
+ * for GETATTR and ops not listed as returning NFS4ERR_MOVED
+ */
+ else if (current_fh->fh_export->ex_fslocs.migrated &&
+ !((op->opnum == OP_GETATTR) ||
+ (op->opnum == OP_PUTROOTFH) ||
+ (op->opnum == OP_PUTPUBFH) ||
+ (op->opnum == OP_RENEW) ||
+ (op->opnum == OP_SETCLIENTID) ||
+ (op->opnum == OP_RELEASE_LOCKOWNER))) {
+ op->status = nfserr_moved;
goto encode_op;
}
switch (op->opnum) {
@@ -921,7 +937,7 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
}
encode_op:
- if (op->status == NFSERR_REPLAY_ME) {
+ if (op->status == nfserr_replay_me) {
op->replay = &replay_owner->so_replay;
nfsd4_encode_replay(resp, op);
status = op->status = op->replay->rp_status;
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index e35d7e52fdeb..e9d07704680e 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -83,13 +83,13 @@ md5_to_hex(char *out, char *md5)
*out = '\0';
}
-int
+__be32
nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
{
struct xdr_netobj cksum;
struct hash_desc desc;
struct scatterlist sg[1];
- int status = nfserr_resource;
+ __be32 status = nfserr_resource;
dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
clname->len, clname->data);
@@ -184,7 +184,7 @@ struct dentry_list_arg {
static int
nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct dentry_list_arg *dla = arg;
struct list_head *dentries = &dla->dentries;
@@ -193,7 +193,7 @@ nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
struct dentry_list *child;
if (name && isdotent(name, namlen))
- return nfs_ok;
+ return 0;
dentry = lookup_one_len(name, parent, namlen);
if (IS_ERR(dentry))
return PTR_ERR(dentry);
@@ -333,14 +333,14 @@ purge_old(struct dentry *parent, struct dentry *child)
int status;
if (nfs4_has_reclaimed_state(child->d_name.name))
- return nfs_ok;
+ return 0;
status = nfsd4_clear_clid_dir(parent, child);
if (status)
printk("failed to remove client recovery directory %s\n",
child->d_name.name);
/* Keep trying, success or failure: */
- return nfs_ok;
+ return 0;
}
void
@@ -365,10 +365,10 @@ load_recdir(struct dentry *parent, struct dentry *child)
printk("nfsd4: illegal name %s in recovery directory\n",
child->d_name.name);
/* Keep trying; maybe the others are OK: */
- return nfs_ok;
+ return 0;
}
nfs4_client_to_reclaim(child->d_name.name);
- return nfs_ok;
+ return 0;
}
int
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 9daa0b9feb8d..293b6495829f 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -339,8 +339,7 @@ alloc_client(struct xdr_netobj name)
{
struct nfs4_client *clp;
- if ((clp = kmalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
- memset(clp, 0, sizeof(*clp));
+ if ((clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL))!= NULL) {
if ((clp->cl_name.data = kmalloc(name.len, GFP_KERNEL)) != NULL) {
memcpy(clp->cl_name.data, name.data, name.len);
clp->cl_name.len = name.len;
@@ -711,10 +710,10 @@ out_err:
* as described above.
*
*/
-int
+__be32
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
{
- u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+ __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
struct xdr_netobj clname = {
.len = setclid->se_namelen,
.data = setclid->se_name,
@@ -722,7 +721,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
nfs4_verifier clverifier = setclid->se_verf;
unsigned int strhashval;
struct nfs4_client *conf, *unconf, *new;
- int status;
+ __be32 status;
char dname[HEXDIR_LEN];
if (!check_name(clname))
@@ -876,14 +875,14 @@ out:
*
* NOTE: callback information will be processed here in a future patch
*/
-int
+__be32
nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
{
- u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
+ __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
struct nfs4_client *conf, *unconf;
nfs4_verifier confirm = setclientid_confirm->sc_confirm;
clientid_t * clid = &setclientid_confirm->sc_clientid;
- int status;
+ __be32 status;
if (STALE_CLIENTID(clid))
return nfserr_stale_clientid;
@@ -1006,13 +1005,10 @@ alloc_init_file(struct inode *ino)
static void
nfsd4_free_slab(kmem_cache_t **slab)
{
- int status;
-
if (*slab == NULL)
return;
- status = kmem_cache_destroy(*slab);
+ kmem_cache_destroy(*slab);
*slab = NULL;
- WARN_ON(status);
}
static void
@@ -1284,13 +1280,13 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
* Called to check deny when READ with all zero stateid or
* WRITE with all zero or all one stateid
*/
-static int
+static __be32
nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_file *fp;
struct nfs4_stateid *stp;
- int ret;
+ __be32 ret;
dprintk("NFSD: nfs4_share_conflict\n");
@@ -1448,7 +1444,7 @@ static struct lock_manager_operations nfsd_lease_mng_ops = {
};
-int
+__be32
nfsd4_process_open1(struct nfsd4_open *open)
{
clientid_t *clientid = &open->op_clientid;
@@ -1481,7 +1477,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
}
if (open->op_seqid == sop->so_seqid - 1) {
if (sop->so_replay.rp_buflen)
- return NFSERR_REPLAY_ME;
+ return nfserr_replay_me;
/* The original OPEN failed so spectacularly
* that we don't even have replay data saved!
* Therefore, we have no choice but to continue
@@ -1505,7 +1501,7 @@ renew:
return nfs_ok;
}
-static inline int
+static inline __be32
nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
{
if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
@@ -1526,12 +1522,12 @@ find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
return NULL;
}
-static int
+static __be32
nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
struct nfs4_delegation **dp)
{
int flags;
- int status = nfserr_bad_stateid;
+ __be32 status = nfserr_bad_stateid;
*dp = find_delegation_file(fp, &open->op_delegate_stateid);
if (*dp == NULL)
@@ -1550,11 +1546,11 @@ out:
return nfs_ok;
}
-static int
+static __be32
nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
{
struct nfs4_stateid *local;
- int status = nfserr_share_denied;
+ __be32 status = nfserr_share_denied;
struct nfs4_stateowner *sop = open->op_stateowner;
list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
@@ -1579,7 +1575,7 @@ nfs4_alloc_stateid(void)
return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
}
-static int
+static __be32
nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
struct nfs4_delegation *dp,
struct svc_fh *cur_fh, int flags)
@@ -1594,7 +1590,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
get_file(dp->dl_vfs_file);
stp->st_vfs_file = dp->dl_vfs_file;
} else {
- int status;
+ __be32 status;
status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
&stp->st_vfs_file);
if (status) {
@@ -1608,7 +1604,7 @@ nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
return 0;
}
-static inline int
+static inline __be32
nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
struct nfsd4_open *open)
{
@@ -1623,22 +1619,22 @@ nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
}
-static int
+static __be32
nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_stateid *stp, struct nfsd4_open *open)
{
struct file *filp = stp->st_vfs_file;
struct inode *inode = filp->f_dentry->d_inode;
unsigned int share_access, new_writer;
- int status;
+ __be32 status;
set_access(&share_access, stp->st_access_bmap);
new_writer = (~share_access) & open->op_share_access
& NFS4_SHARE_ACCESS_WRITE;
if (new_writer) {
- status = get_write_access(inode);
- if (status)
- return nfserrno(status);
+ int err = get_write_access(inode);
+ if (err)
+ return nfserrno(err);
}
status = nfsd4_truncate(rqstp, cur_fh, open);
if (status) {
@@ -1742,14 +1738,14 @@ out:
/*
* called with nfs4_lock_state() held.
*/
-int
+__be32
nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
struct nfs4_file *fp = NULL;
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
- int status;
+ __be32 status;
status = nfserr_inval;
if (!access_valid(open->op_share_access)
@@ -1837,11 +1833,11 @@ static struct work_struct laundromat_work;
static void laundromat_main(void *);
static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
-int
+__be32
nfsd4_renew(clientid_t *clid)
{
struct nfs4_client *clp;
- int status;
+ __be32 status;
nfs4_lock_state();
dprintk("process_renew(%08x/%08x): starting\n",
@@ -2000,9 +1996,9 @@ access_permit_write(unsigned long access_bmap)
}
static
-int nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
+__be32 nfs4_check_openmode(struct nfs4_stateid *stp, int flags)
{
- int status = nfserr_openmode;
+ __be32 status = nfserr_openmode;
if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
goto out;
@@ -2013,7 +2009,7 @@ out:
return status;
}
-static inline int
+static inline __be32
check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
{
/* Trying to call delegreturn with a special stateid? Yuch: */
@@ -2047,14 +2043,14 @@ io_during_grace_disallowed(struct inode *inode, int flags)
/*
* Checks for stateid operations
*/
-int
+__be32
nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int flags, struct file **filpp)
{
struct nfs4_stateid *stp = NULL;
struct nfs4_delegation *dp = NULL;
stateid_t *stidp;
struct inode *ino = current_fh->fh_dentry->d_inode;
- int status;
+ __be32 status;
dprintk("NFSD: preprocess_stateid_op: stateid = (%08x/%08x/%08x/%08x)\n",
stateid->si_boot, stateid->si_stateownerid,
@@ -2129,7 +2125,7 @@ setlkflg (int type)
/*
* Checks for sequence id mutating operations.
*/
-static int
+static __be32
nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
{
struct nfs4_stateid *stp;
@@ -2173,7 +2169,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
clientid_t *lockclid = &lock->v.new.clientid;
struct nfs4_client *clp = sop->so_client;
int lkflg = 0;
- int status;
+ __be32 status;
lkflg = setlkflg(lock->lk_type);
@@ -2237,7 +2233,7 @@ check_replay:
if (seqid == sop->so_seqid - 1) {
dprintk("NFSD: preprocess_seqid_op: retransmission?\n");
/* indicate replay to calling function */
- return NFSERR_REPLAY_ME;
+ return nfserr_replay_me;
}
printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
sop->so_seqid, seqid);
@@ -2245,10 +2241,10 @@ check_replay:
return nfserr_bad_seqid;
}
-int
+__be32
nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_confirm *oc, struct nfs4_stateowner **replay_owner)
{
- int status;
+ __be32 status;
struct nfs4_stateowner *sop;
struct nfs4_stateid *stp;
@@ -2314,10 +2310,10 @@ reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
}
}
-int
+__be32
nfsd4_open_downgrade(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open_downgrade *od, struct nfs4_stateowner **replay_owner)
{
- int status;
+ __be32 status;
struct nfs4_stateid *stp;
unsigned int share_access;
@@ -2369,10 +2365,10 @@ out:
/*
* nfs4_unlock_state() called after encode
*/
-int
+__be32
nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_close *close, struct nfs4_stateowner **replay_owner)
{
- int status;
+ __be32 status;
struct nfs4_stateid *stp;
dprintk("NFSD: nfsd4_close on file %.*s\n",
@@ -2408,10 +2404,10 @@ out:
return status;
}
-int
+__be32
nfsd4_delegreturn(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_delegreturn *dr)
{
- int status;
+ __be32 status;
if ((status = fh_verify(rqstp, current_fh, S_IFREG, 0)))
goto out;
@@ -2639,7 +2635,7 @@ check_lock_length(u64 offset, u64 length)
/*
* LOCK operation
*/
-int
+__be32
nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock, struct nfs4_stateowner **replay_owner)
{
struct nfs4_stateowner *open_sop = NULL;
@@ -2648,8 +2644,9 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
struct file *filp;
struct file_lock file_lock;
struct file_lock conflock;
- int status = 0;
+ __be32 status = 0;
unsigned int strhashval;
+ int err;
dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
(long long) lock->lk_offset,
@@ -2762,13 +2759,14 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
* locks_copy_lock: */
conflock.fl_ops = NULL;
conflock.fl_lmops = NULL;
- status = posix_lock_file_conf(filp, &file_lock, &conflock);
+ err = posix_lock_file_conf(filp, &file_lock, &conflock);
dprintk("NFSD: nfsd4_lock: posix_lock_file_conf status %d\n",status);
- switch (-status) {
+ switch (-err) {
case 0: /* success! */
update_stateid(&lock_stp->st_stateid);
memcpy(&lock->lk_resp_stateid, &lock_stp->st_stateid,
sizeof(stateid_t));
+ status = 0;
break;
case (EAGAIN): /* conflock holds conflicting lock */
status = nfserr_denied;
@@ -2779,7 +2777,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
status = nfserr_deadlock;
break;
default:
- dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",status);
+ dprintk("NFSD: nfsd4_lock: posix_lock_file_conf() failed! status %d\n",err);
status = nfserr_resource;
break;
}
@@ -2797,14 +2795,14 @@ out:
/*
* LOCKT operation
*/
-int
+__be32
nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lockt *lockt)
{
struct inode *inode;
struct file file;
struct file_lock file_lock;
struct file_lock conflock;
- int status;
+ __be32 status;
if (nfs4_in_grace())
return nfserr_grace;
@@ -2877,13 +2875,14 @@ out:
return status;
}
-int
+__be32
nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_locku *locku, struct nfs4_stateowner **replay_owner)
{
struct nfs4_stateid *stp;
struct file *filp = NULL;
struct file_lock file_lock;
- int status;
+ __be32 status;
+ int err;
dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
(long long) locku->lu_offset,
@@ -2921,8 +2920,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
/*
* Try to unlock the file in the VFS.
*/
- status = posix_lock_file(filp, &file_lock);
- if (status) {
+ err = posix_lock_file(filp, &file_lock);
+ if (err) {
dprintk("NFSD: nfs4_locku: posix_lock_file failed!\n");
goto out_nfserr;
}
@@ -2941,7 +2940,7 @@ out:
return status;
out_nfserr:
- status = nfserrno(status);
+ status = nfserrno(err);
goto out;
}
@@ -2969,7 +2968,7 @@ out:
return status;
}
-int
+__be32
nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
{
clientid_t *clid = &rlockowner->rl_clientid;
@@ -2978,7 +2977,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
struct xdr_netobj *owner = &rlockowner->rl_owner;
struct list_head matches;
int i;
- int status;
+ __be32 status;
dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
clid->cl_boot, clid->cl_id);
@@ -3115,7 +3114,7 @@ nfs4_find_reclaim_client(clientid_t *clid)
/*
* Called from OPEN. Look for clientid in reclaim list.
*/
-int
+__be32
nfs4_check_open_reclaim(clientid_t *clid)
{
return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 5446a0861d1d..f3f239db04bb 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -60,8 +60,16 @@
#define NFSDDBG_FACILITY NFSDDBG_XDR
-static int
-check_filename(char *str, int len, int err)
+/*
+ * As per referral draft, the fsid for a referral MUST be different from the fsid of the containing
+ * directory in order to indicate to the client that a filesystem boundary is present
+ * We use a fixed fsid for a referral
+ */
+#define NFS4_REFERRAL_FSID_MAJOR 0x8000000ULL
+#define NFS4_REFERRAL_FSID_MINOR 0x8000000ULL
+
+static __be32
+check_filename(char *str, int len, __be32 err)
{
int i;
@@ -86,8 +94,8 @@ check_filename(char *str, int len, int err)
* consistent with the style used in NFSv2/v3...
*/
#define DECODE_HEAD \
- u32 *p; \
- int status
+ __be32 *p; \
+ __be32 status
#define DECODE_TAIL \
status = 0; \
out: \
@@ -136,13 +144,13 @@ xdr_error: \
} \
} while (0)
-static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
+static __be32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
{
/* We want more bytes than seem to be available.
* Maybe we need a new page, maybe we have just run out
*/
int avail = (char*)argp->end - (char*)argp->p;
- u32 *p;
+ __be32 *p;
if (avail + argp->pagelen < nbytes)
return NULL;
if (avail + PAGE_SIZE < nbytes) /* need more than a page !! */
@@ -189,7 +197,7 @@ defer_free(struct nfsd4_compoundargs *argp,
return 0;
}
-static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
+static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
{
void *new = NULL;
if (p == argp->tmp) {
@@ -198,8 +206,7 @@ static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
p = new;
memcpy(p, argp->tmp, nbytes);
} else {
- if (p != argp->tmpp)
- BUG();
+ BUG_ON(p != argp->tmpp);
argp->tmpp = NULL;
}
if (defer_free(argp, kfree, p)) {
@@ -210,7 +217,7 @@ static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
}
-static int
+static __be32
nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
{
u32 bmlen;
@@ -233,13 +240,14 @@ nfsd4_decode_bitmap(struct nfsd4_compoundargs *argp, u32 *bmval)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *iattr,
struct nfs4_acl **acl)
{
int expected_len, len = 0;
u32 dummy32;
char *buf;
+ int host_err;
DECODE_HEAD;
iattr->ia_valid = 0;
@@ -273,7 +281,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
*acl = nfs4_acl_new();
if (*acl == NULL) {
- status = -ENOMEM;
+ host_err = -ENOMEM;
goto out_nfserr;
}
defer_free(argp, (void (*)(const void *))nfs4_acl_free, *acl);
@@ -288,20 +296,20 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
len += XDR_QUADLEN(dummy32) << 2;
READMEM(buf, dummy32);
ace.whotype = nfs4_acl_get_whotype(buf, dummy32);
- status = 0;
+ host_err = 0;
if (ace.whotype != NFS4_ACL_WHO_NAMED)
ace.who = 0;
else if (ace.flag & NFS4_ACE_IDENTIFIER_GROUP)
- status = nfsd_map_name_to_gid(argp->rqstp,
+ host_err = nfsd_map_name_to_gid(argp->rqstp,
buf, dummy32, &ace.who);
else
- status = nfsd_map_name_to_uid(argp->rqstp,
+ host_err = nfsd_map_name_to_uid(argp->rqstp,
buf, dummy32, &ace.who);
- if (status)
+ if (host_err)
goto out_nfserr;
- status = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
+ host_err = nfs4_acl_add_ace(*acl, ace.type, ace.flag,
ace.access_mask, ace.whotype, ace.who);
- if (status)
+ if (host_err)
goto out_nfserr;
}
} else
@@ -320,7 +328,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
READ_BUF(dummy32);
len += (XDR_QUADLEN(dummy32) << 2);
READMEM(buf, dummy32);
- if ((status = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
+ if ((host_err = nfsd_map_name_to_uid(argp->rqstp, buf, dummy32, &iattr->ia_uid)))
goto out_nfserr;
iattr->ia_valid |= ATTR_UID;
}
@@ -331,7 +339,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
READ_BUF(dummy32);
len += (XDR_QUADLEN(dummy32) << 2);
READMEM(buf, dummy32);
- if ((status = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
+ if ((host_err = nfsd_map_name_to_gid(argp->rqstp, buf, dummy32, &iattr->ia_gid)))
goto out_nfserr;
iattr->ia_valid |= ATTR_GID;
}
@@ -407,11 +415,11 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, struct iattr *ia
DECODE_TAIL;
out_nfserr:
- status = nfserrno(status);
+ status = nfserrno(host_err);
goto out;
}
-static int
+static __be32
nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access)
{
DECODE_HEAD;
@@ -422,7 +430,7 @@ nfsd4_decode_access(struct nfsd4_compoundargs *argp, struct nfsd4_access *access
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
{
DECODE_HEAD;
@@ -437,7 +445,7 @@ nfsd4_decode_close(struct nfsd4_compoundargs *argp, struct nfsd4_close *close)
}
-static int
+static __be32
nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit)
{
DECODE_HEAD;
@@ -449,7 +457,7 @@ nfsd4_decode_commit(struct nfsd4_compoundargs *argp, struct nfsd4_commit *commit
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create)
{
DECODE_HEAD;
@@ -489,7 +497,7 @@ nfsd4_decode_create(struct nfsd4_compoundargs *argp, struct nfsd4_create *create
DECODE_TAIL;
}
-static inline int
+static inline __be32
nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegreturn *dr)
{
DECODE_HEAD;
@@ -501,13 +509,13 @@ nfsd4_decode_delegreturn(struct nfsd4_compoundargs *argp, struct nfsd4_delegretu
DECODE_TAIL;
}
-static inline int
+static inline __be32
nfsd4_decode_getattr(struct nfsd4_compoundargs *argp, struct nfsd4_getattr *getattr)
{
return nfsd4_decode_bitmap(argp, getattr->ga_bmval);
}
-static int
+static __be32
nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
{
DECODE_HEAD;
@@ -522,7 +530,7 @@ nfsd4_decode_link(struct nfsd4_compoundargs *argp, struct nfsd4_link *link)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
{
DECODE_HEAD;
@@ -561,7 +569,7 @@ nfsd4_decode_lock(struct nfsd4_compoundargs *argp, struct nfsd4_lock *lock)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
{
DECODE_HEAD;
@@ -580,7 +588,7 @@ nfsd4_decode_lockt(struct nfsd4_compoundargs *argp, struct nfsd4_lockt *lockt)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
{
DECODE_HEAD;
@@ -599,7 +607,7 @@ nfsd4_decode_locku(struct nfsd4_compoundargs *argp, struct nfsd4_locku *locku)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup)
{
DECODE_HEAD;
@@ -614,7 +622,7 @@ nfsd4_decode_lookup(struct nfsd4_compoundargs *argp, struct nfsd4_lookup *lookup
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
{
DECODE_HEAD;
@@ -692,7 +700,7 @@ nfsd4_decode_open(struct nfsd4_compoundargs *argp, struct nfsd4_open *open)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf)
{
DECODE_HEAD;
@@ -706,7 +714,7 @@ nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_con
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_downgrade *open_down)
{
DECODE_HEAD;
@@ -722,7 +730,7 @@ nfsd4_decode_open_downgrade(struct nfsd4_compoundargs *argp, struct nfsd4_open_d
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
{
DECODE_HEAD;
@@ -737,7 +745,7 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
{
DECODE_HEAD;
@@ -751,7 +759,7 @@ nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *readdir)
{
DECODE_HEAD;
@@ -767,7 +775,7 @@ nfsd4_decode_readdir(struct nfsd4_compoundargs *argp, struct nfsd4_readdir *read
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove)
{
DECODE_HEAD;
@@ -782,7 +790,7 @@ nfsd4_decode_remove(struct nfsd4_compoundargs *argp, struct nfsd4_remove *remove
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename)
{
DECODE_HEAD;
@@ -802,7 +810,7 @@ nfsd4_decode_rename(struct nfsd4_compoundargs *argp, struct nfsd4_rename *rename
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
{
DECODE_HEAD;
@@ -813,7 +821,7 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid)
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *setattr)
{
DECODE_HEAD;
@@ -827,7 +835,7 @@ nfsd4_decode_setattr(struct nfsd4_compoundargs *argp, struct nfsd4_setattr *seta
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid *setclientid)
{
DECODE_HEAD;
@@ -852,7 +860,7 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_setclientid_confirm *scd_c)
{
DECODE_HEAD;
@@ -865,7 +873,7 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s
}
/* Also used for NVERIFY */
-static int
+static __be32
nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify)
{
#if 0
@@ -901,7 +909,7 @@ nfsd4_decode_verify(struct nfsd4_compoundargs *argp, struct nfsd4_verify *verify
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
{
int avail;
@@ -927,32 +935,32 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
printk(KERN_NOTICE "xdr error! (%s:%d)\n", __FILE__, __LINE__);
goto xdr_error;
}
- write->wr_vec[0].iov_base = p;
- write->wr_vec[0].iov_len = avail;
+ argp->rqstp->rq_vec[0].iov_base = p;
+ argp->rqstp->rq_vec[0].iov_len = avail;
v = 0;
len = write->wr_buflen;
- while (len > write->wr_vec[v].iov_len) {
- len -= write->wr_vec[v].iov_len;
+ while (len > argp->rqstp->rq_vec[v].iov_len) {
+ len -= argp->rqstp->rq_vec[v].iov_len;
v++;
- write->wr_vec[v].iov_base = page_address(argp->pagelist[0]);
+ argp->rqstp->rq_vec[v].iov_base = page_address(argp->pagelist[0]);
argp->pagelist++;
if (argp->pagelen >= PAGE_SIZE) {
- write->wr_vec[v].iov_len = PAGE_SIZE;
+ argp->rqstp->rq_vec[v].iov_len = PAGE_SIZE;
argp->pagelen -= PAGE_SIZE;
} else {
- write->wr_vec[v].iov_len = argp->pagelen;
+ argp->rqstp->rq_vec[v].iov_len = argp->pagelen;
argp->pagelen -= len;
}
}
- argp->end = (u32*) (write->wr_vec[v].iov_base + write->wr_vec[v].iov_len);
- argp->p = (u32*) (write->wr_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
- write->wr_vec[v].iov_len = len;
+ argp->end = (__be32*) (argp->rqstp->rq_vec[v].iov_base + argp->rqstp->rq_vec[v].iov_len);
+ argp->p = (__be32*) (argp->rqstp->rq_vec[v].iov_base + (XDR_QUADLEN(len) << 2));
+ argp->rqstp->rq_vec[v].iov_len = len;
write->wr_vlen = v+1;
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_release_lockowner *rlockowner)
{
DECODE_HEAD;
@@ -966,7 +974,7 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel
DECODE_TAIL;
}
-static int
+static __be32
nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
{
DECODE_HEAD;
@@ -1172,7 +1180,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
* task to translate them into Linux-specific versions which are more
* consistent with the style used in NFSv2/v3...
*/
-#define ENCODE_HEAD u32 *p
+#define ENCODE_HEAD __be32 *p
#define WRITE32(n) *p++ = htonl(n)
#define WRITE64(n) do { \
@@ -1202,8 +1210,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
* Header routine to setup seqid operation replay cache
*/
#define ENCODE_SEQID_OP_HEAD \
- u32 *p; \
- u32 *save; \
+ __be32 *p; \
+ __be32 *save; \
\
save = resp->p;
@@ -1224,6 +1232,120 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
stateowner->so_replay.rp_buflen); \
} } while (0);
+/* Encode as an array of strings the string given with components
+ * seperated @sep.
+ */
+static __be32 nfsd4_encode_components(char sep, char *components,
+ __be32 **pp, int *buflen)
+{
+ __be32 *p = *pp;
+ __be32 *countp = p;
+ int strlen, count=0;
+ char *str, *end;
+
+ dprintk("nfsd4_encode_components(%s)\n", components);
+ if ((*buflen -= 4) < 0)
+ return nfserr_resource;
+ WRITE32(0); /* We will fill this in with @count later */
+ end = str = components;
+ while (*end) {
+ for (; *end && (*end != sep); end++)
+ ; /* Point to end of component */
+ strlen = end - str;
+ if (strlen) {
+ if ((*buflen -= ((XDR_QUADLEN(strlen) << 2) + 4)) < 0)
+ return nfserr_resource;
+ WRITE32(strlen);
+ WRITEMEM(str, strlen);
+ count++;
+ }
+ else
+ end++;
+ str = end;
+ }
+ *pp = p;
+ p = countp;
+ WRITE32(count);
+ return 0;
+}
+
+/*
+ * encode a location element of a fs_locations structure
+ */
+static __be32 nfsd4_encode_fs_location4(struct nfsd4_fs_location *location,
+ __be32 **pp, int *buflen)
+{
+ __be32 status;
+ __be32 *p = *pp;
+
+ status = nfsd4_encode_components(':', location->hosts, &p, buflen);
+ if (status)
+ return status;
+ status = nfsd4_encode_components('/', location->path, &p, buflen);
+ if (status)
+ return status;
+ *pp = p;
+ return 0;
+}
+
+/*
+ * Return the path to an export point in the pseudo filesystem namespace
+ * Returned string is safe to use as long as the caller holds a reference
+ * to @exp.
+ */
+static char *nfsd4_path(struct svc_rqst *rqstp, struct svc_export *exp, __be32 *stat)
+{
+ struct svc_fh tmp_fh;
+ char *path, *rootpath;
+
+ fh_init(&tmp_fh, NFS4_FHSIZE);
+ *stat = exp_pseudoroot(rqstp->rq_client, &tmp_fh, &rqstp->rq_chandle);
+ if (*stat)
+ return NULL;
+ rootpath = tmp_fh.fh_export->ex_path;
+
+ path = exp->ex_path;
+
+ if (strncmp(path, rootpath, strlen(rootpath))) {
+ printk("nfsd: fs_locations failed;"
+ "%s is not contained in %s\n", path, rootpath);
+ *stat = nfserr_notsupp;
+ return NULL;
+ }
+
+ return path + strlen(rootpath);
+}
+
+/*
+ * encode a fs_locations structure
+ */
+static __be32 nfsd4_encode_fs_locations(struct svc_rqst *rqstp,
+ struct svc_export *exp,
+ __be32 **pp, int *buflen)
+{
+ __be32 status;
+ int i;
+ __be32 *p = *pp;
+ struct nfsd4_fs_locations *fslocs = &exp->ex_fslocs;
+ char *root = nfsd4_path(rqstp, exp, &status);
+
+ if (status)
+ return status;
+ status = nfsd4_encode_components('/', root, &p, buflen);
+ if (status)
+ return status;
+ if ((*buflen -= 4) < 0)
+ return nfserr_resource;
+ WRITE32(fslocs->locations_count);
+ for (i=0; i<fslocs->locations_count; i++) {
+ status = nfsd4_encode_fs_location4(&fslocs->locations[i],
+ &p, buflen);
+ if (status)
+ return status;
+ }
+ *pp = p;
+ return 0;
+}
static u32 nfs4_ftypes[16] = {
NF4BAD, NF4FIFO, NF4CHR, NF4BAD,
@@ -1232,9 +1354,9 @@ static u32 nfs4_ftypes[16] = {
NF4SOCK, NF4BAD, NF4LNK, NF4BAD,
};
-static int
+static __be32
nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
- u32 **p, int *buflen)
+ __be32 **p, int *buflen)
{
int status;
@@ -1254,25 +1376,44 @@ nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
return 0;
}
-static inline int
-nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, u32 **p, int *buflen)
+static inline __be32
+nfsd4_encode_user(struct svc_rqst *rqstp, uid_t uid, __be32 **p, int *buflen)
{
return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, uid, 0, p, buflen);
}
-static inline int
-nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, u32 **p, int *buflen)
+static inline __be32
+nfsd4_encode_group(struct svc_rqst *rqstp, uid_t gid, __be32 **p, int *buflen)
{
return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, gid, 1, p, buflen);
}
-static inline int
+static inline __be32
nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
- u32 **p, int *buflen)
+ __be32 **p, int *buflen)
{
return nfsd4_encode_name(rqstp, whotype, id, group, p, buflen);
}
+#define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
+ FATTR4_WORD0_RDATTR_ERROR)
+#define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID
+
+static __be32 fattr_handle_absent_fs(u32 *bmval0, u32 *bmval1, u32 *rdattr_err)
+{
+ /* As per referral draft: */
+ if (*bmval0 & ~WORD0_ABSENT_FS_ATTRS ||
+ *bmval1 & ~WORD1_ABSENT_FS_ATTRS) {
+ if (*bmval0 & FATTR4_WORD0_RDATTR_ERROR ||
+ *bmval0 & FATTR4_WORD0_FS_LOCATIONS)
+ *rdattr_err = NFSERR_MOVED;
+ else
+ return nfserr_moved;
+ }
+ *bmval0 &= WORD0_ABSENT_FS_ATTRS;
+ *bmval1 &= WORD1_ABSENT_FS_ATTRS;
+ return 0;
+}
/*
* Note: @fhp can be NULL; in this case, we might have to compose the filehandle
@@ -1281,9 +1422,9 @@ nfsd4_encode_aclname(struct svc_rqst *rqstp, int whotype, uid_t id, int group,
* @countp is the buffer size in _words_; upon successful return this becomes
* replaced with the number of words written.
*/
-int
+__be32
nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval,
+ struct dentry *dentry, __be32 *buffer, int *countp, u32 *bmval,
struct svc_rqst *rqstp)
{
u32 bmval0 = bmval[0];
@@ -1292,11 +1433,13 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
struct svc_fh tempfh;
struct kstatfs statfs;
int buflen = *countp << 2;
- u32 *attrlenp;
+ __be32 *attrlenp;
u32 dummy;
u64 dummy64;
- u32 *p = buffer;
- int status;
+ u32 rdattr_err = 0;
+ __be32 *p = buffer;
+ __be32 status;
+ int err;
int aclsupport = 0;
struct nfs4_acl *acl = NULL;
@@ -1304,14 +1447,20 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
BUG_ON(bmval0 & ~NFSD_SUPPORTED_ATTRS_WORD0);
BUG_ON(bmval1 & ~NFSD_SUPPORTED_ATTRS_WORD1);
- status = vfs_getattr(exp->ex_mnt, dentry, &stat);
- if (status)
+ if (exp->ex_fslocs.migrated) {
+ status = fattr_handle_absent_fs(&bmval0, &bmval1, &rdattr_err);
+ if (status)
+ goto out;
+ }
+
+ err = vfs_getattr(exp->ex_mnt, dentry, &stat);
+ if (err)
goto out_nfserr;
if ((bmval0 & (FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL)) ||
(bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE |
FATTR4_WORD1_SPACE_TOTAL))) {
- status = vfs_statfs(dentry, &statfs);
- if (status)
+ err = vfs_statfs(dentry, &statfs);
+ if (err)
goto out_nfserr;
}
if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
@@ -1323,18 +1472,23 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
}
if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
| FATTR4_WORD0_SUPPORTED_ATTRS)) {
- status = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
- aclsupport = (status == 0);
+ err = nfsd4_get_nfs4_acl(rqstp, dentry, &acl);
+ aclsupport = (err == 0);
if (bmval0 & FATTR4_WORD0_ACL) {
- if (status == -EOPNOTSUPP)
+ if (err == -EOPNOTSUPP)
bmval0 &= ~FATTR4_WORD0_ACL;
- else if (status == -EINVAL) {
+ else if (err == -EINVAL) {
status = nfserr_attrnotsupp;
goto out;
- } else if (status != 0)
+ } else if (err != 0)
goto out_nfserr;
}
}
+ if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
+ if (exp->ex_fslocs.locations == NULL) {
+ bmval0 &= ~FATTR4_WORD0_FS_LOCATIONS;
+ }
+ }
if ((buflen -= 16) < 0)
goto out_resource;
@@ -1344,12 +1498,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
attrlenp = p++; /* to be backfilled later */
if (bmval0 & FATTR4_WORD0_SUPPORTED_ATTRS) {
+ u32 word0 = NFSD_SUPPORTED_ATTRS_WORD0;
if ((buflen -= 12) < 0)
goto out_resource;
+ if (!aclsupport)
+ word0 &= ~FATTR4_WORD0_ACL;
+ if (!exp->ex_fslocs.locations)
+ word0 &= ~FATTR4_WORD0_FS_LOCATIONS;
WRITE32(2);
- WRITE32(aclsupport ?
- NFSD_SUPPORTED_ATTRS_WORD0 :
- NFSD_SUPPORTED_ATTRS_WORD0 & ~FATTR4_WORD0_ACL);
+ WRITE32(word0);
WRITE32(NFSD_SUPPORTED_ATTRS_WORD1);
}
if (bmval0 & FATTR4_WORD0_TYPE) {
@@ -1403,7 +1560,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (bmval0 & FATTR4_WORD0_FSID) {
if ((buflen -= 16) < 0)
goto out_resource;
- if (is_fsid(fhp, rqstp->rq_reffh)) {
+ if (exp->ex_fslocs.migrated) {
+ WRITE64(NFS4_REFERRAL_FSID_MAJOR);
+ WRITE64(NFS4_REFERRAL_FSID_MINOR);
+ } else if (is_fsid(fhp, rqstp->rq_reffh)) {
WRITE64((u64)exp->ex_fsid);
WRITE64((u64)0);
} else {
@@ -1426,7 +1586,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (bmval0 & FATTR4_WORD0_RDATTR_ERROR) {
if ((buflen -= 4) < 0)
goto out_resource;
- WRITE32(0);
+ WRITE32(rdattr_err);
}
if (bmval0 & FATTR4_WORD0_ACL) {
struct nfs4_ace *ace;
@@ -1514,6 +1674,13 @@ out_acl:
goto out_resource;
WRITE64((u64) statfs.f_files);
}
+ if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
+ status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
+ if (status == nfserr_resource)
+ goto out_resource;
+ if (status)
+ goto out;
+ }
if (bmval0 & FATTR4_WORD0_HOMOGENEOUS) {
if ((buflen -= 4) < 0)
goto out_resource;
@@ -1537,12 +1704,12 @@ out_acl:
if (bmval0 & FATTR4_WORD0_MAXREAD) {
if ((buflen -= 8) < 0)
goto out_resource;
- WRITE64((u64) NFSSVC_MAXBLKSIZE);
+ WRITE64((u64) svc_max_payload(rqstp));
}
if (bmval0 & FATTR4_WORD0_MAXWRITE) {
if ((buflen -= 8) < 0)
goto out_resource;
- WRITE64((u64) NFSSVC_MAXBLKSIZE);
+ WRITE64((u64) svc_max_payload(rqstp));
}
if (bmval1 & FATTR4_WORD1_MODE) {
if ((buflen -= 4) < 0)
@@ -1653,7 +1820,7 @@ out:
fh_put(&tempfh);
return status;
out_nfserr:
- status = nfserrno(status);
+ status = nfserrno(err);
goto out;
out_resource:
*countp = 0;
@@ -1664,13 +1831,13 @@ out_serverfault:
goto out;
}
-static int
+static __be32
nfsd4_encode_dirent_fattr(struct nfsd4_readdir *cd,
- const char *name, int namlen, u32 *p, int *buflen)
+ const char *name, int namlen, __be32 *p, int *buflen)
{
struct svc_export *exp = cd->rd_fhp->fh_export;
struct dentry *dentry;
- int nfserr;
+ __be32 nfserr;
dentry = lookup_one_len(name, cd->rd_fhp->fh_dentry, namlen);
if (IS_ERR(dentry))
@@ -1699,10 +1866,10 @@ out_put:
return nfserr;
}
-static u32 *
-nfsd4_encode_rdattr_error(u32 *p, int buflen, int nfserr)
+static __be32 *
+nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
{
- u32 *attrlenp;
+ __be32 *attrlenp;
if (buflen < 6)
return NULL;
@@ -1722,8 +1889,8 @@ nfsd4_encode_dirent(struct readdir_cd *ccd, const char *name, int namlen,
{
struct nfsd4_readdir *cd = container_of(ccd, struct nfsd4_readdir, common);
int buflen;
- u32 *p = cd->buffer;
- int nfserr = nfserr_toosmall;
+ __be32 *p = cd->buffer;
+ __be32 nfserr = nfserr_toosmall;
/* In nfsv4, "." and ".." never make it onto the wire.. */
if (name && isdotent(name, namlen)) {
@@ -1779,7 +1946,7 @@ fail:
}
static void
-nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_access *access)
+nfsd4_encode_access(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_access *access)
{
ENCODE_HEAD;
@@ -1792,7 +1959,7 @@ nfsd4_encode_access(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_acc
}
static void
-nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_close *close)
+nfsd4_encode_close(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_close *close)
{
ENCODE_SEQID_OP_HEAD;
@@ -1807,7 +1974,7 @@ nfsd4_encode_close(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_clos
static void
-nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_commit *commit)
+nfsd4_encode_commit(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_commit *commit)
{
ENCODE_HEAD;
@@ -1819,7 +1986,7 @@ nfsd4_encode_commit(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_com
}
static void
-nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_create *create)
+nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_create *create)
{
ENCODE_HEAD;
@@ -1833,8 +2000,8 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_cre
}
}
-static int
-nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_getattr *getattr)
+static __be32
+nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_getattr *getattr)
{
struct svc_fh *fhp = getattr->ga_fhp;
int buflen;
@@ -1846,14 +2013,13 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ge
nfserr = nfsd4_encode_fattr(fhp, fhp->fh_export, fhp->fh_dentry,
resp->p, &buflen, getattr->ga_bmval,
resp->rqstp);
-
if (!nfserr)
resp->p += buflen;
return nfserr;
}
static void
-nfsd4_encode_getfh(struct nfsd4_compoundres *resp, int nfserr, struct svc_fh *fhp)
+nfsd4_encode_getfh(struct nfsd4_compoundres *resp, __be32 nfserr, struct svc_fh *fhp)
{
unsigned int len;
ENCODE_HEAD;
@@ -1893,7 +2059,7 @@ nfsd4_encode_lock_denied(struct nfsd4_compoundres *resp, struct nfsd4_lock_denie
}
static void
-nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock *lock)
+nfsd4_encode_lock(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lock *lock)
{
ENCODE_SEQID_OP_HEAD;
@@ -1909,14 +2075,14 @@ nfsd4_encode_lock(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock
}
static void
-nfsd4_encode_lockt(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lockt *lockt)
+nfsd4_encode_lockt(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_lockt *lockt)
{
if (nfserr == nfserr_denied)
nfsd4_encode_lock_denied(resp, &lockt->lt_denied);
}
static void
-nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_locku *locku)
+nfsd4_encode_locku(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_locku *locku)
{
ENCODE_SEQID_OP_HEAD;
@@ -1932,7 +2098,7 @@ nfsd4_encode_locku(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_lock
static void
-nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link *link)
+nfsd4_encode_link(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_link *link)
{
ENCODE_HEAD;
@@ -1945,7 +2111,7 @@ nfsd4_encode_link(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_link
static void
-nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open *open)
+nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open *open)
{
ENCODE_SEQID_OP_HEAD;
@@ -2010,7 +2176,7 @@ out:
}
static void
-nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_confirm *oc)
+nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_confirm *oc)
{
ENCODE_SEQID_OP_HEAD;
@@ -2025,7 +2191,7 @@ nfsd4_encode_open_confirm(struct nfsd4_compoundres *resp, int nfserr, struct nfs
}
static void
-nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open_downgrade *od)
+nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_open_downgrade *od)
{
ENCODE_SEQID_OP_HEAD;
@@ -2039,8 +2205,9 @@ nfsd4_encode_open_downgrade(struct nfsd4_compoundres *resp, int nfserr, struct n
ENCODE_SEQID_OP_TAIL(od->od_stateowner);
}
-static int
-nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read *read)
+static __be32
+nfsd4_encode_read(struct nfsd4_compoundres *resp, __be32 nfserr,
+ struct nfsd4_read *read)
{
u32 eof;
int v, pn;
@@ -2055,31 +2222,33 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
RESERVE_SPACE(8); /* eof flag and byte count */
- maxcount = NFSSVC_MAXBLKSIZE;
+ maxcount = svc_max_payload(resp->rqstp);
if (maxcount > read->rd_length)
maxcount = read->rd_length;
len = maxcount;
v = 0;
while (len > 0) {
- pn = resp->rqstp->rq_resused;
- svc_take_page(resp->rqstp);
- read->rd_iov[v].iov_base = page_address(resp->rqstp->rq_respages[pn]);
- read->rd_iov[v].iov_len = len < PAGE_SIZE ? len : PAGE_SIZE;
+ pn = resp->rqstp->rq_resused++;
+ resp->rqstp->rq_vec[v].iov_base =
+ page_address(resp->rqstp->rq_respages[pn]);
+ resp->rqstp->rq_vec[v].iov_len =
+ len < PAGE_SIZE ? len : PAGE_SIZE;
v++;
len -= PAGE_SIZE;
}
read->rd_vlen = v;
nfserr = nfsd_read(read->rd_rqstp, read->rd_fhp, read->rd_filp,
- read->rd_offset, read->rd_iov, read->rd_vlen,
+ read->rd_offset, resp->rqstp->rq_vec, read->rd_vlen,
&maxcount);
if (nfserr == nfserr_symlink)
nfserr = nfserr_inval;
if (nfserr)
return nfserr;
- eof = (read->rd_offset + maxcount >= read->rd_fhp->fh_dentry->d_inode->i_size);
+ eof = (read->rd_offset + maxcount >=
+ read->rd_fhp->fh_dentry->d_inode->i_size);
WRITE32(eof);
WRITE32(maxcount);
@@ -2089,7 +2258,6 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
resp->xbuf->page_len = maxcount;
/* Use rest of head for padding and remaining ops: */
- resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
if (maxcount&3) {
@@ -2102,8 +2270,8 @@ nfsd4_encode_read(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_read
return 0;
}
-static int
-nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readlink *readlink)
+static __be32
+nfsd4_encode_readlink(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readlink *readlink)
{
int maxcount;
char *page;
@@ -2114,8 +2282,7 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
if (resp->xbuf->page_len)
return nfserr_resource;
- svc_take_page(resp->rqstp);
- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+ page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
maxcount = PAGE_SIZE;
RESERVE_SPACE(4);
@@ -2139,7 +2306,6 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
resp->xbuf->page_len = maxcount;
/* Use rest of head for padding and remaining ops: */
- resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = p;
resp->xbuf->tail[0].iov_len = 0;
if (maxcount&3) {
@@ -2152,12 +2318,12 @@ nfsd4_encode_readlink(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_r
return 0;
}
-static int
-nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_readdir *readdir)
+static __be32
+nfsd4_encode_readdir(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_readdir *readdir)
{
int maxcount;
loff_t offset;
- u32 *page, *savep, *tailbase;
+ __be32 *page, *savep, *tailbase;
ENCODE_HEAD;
if (nfserr)
@@ -2190,8 +2356,7 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
goto err_no_verf;
}
- svc_take_page(resp->rqstp);
- page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+ page = page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused++]);
readdir->common.err = 0;
readdir->buflen = maxcount;
readdir->buffer = page;
@@ -2216,10 +2381,10 @@ nfsd4_encode_readdir(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_re
p = readdir->buffer;
*p++ = 0; /* no more entries */
*p++ = htonl(readdir->common.err == nfserr_eof);
- resp->xbuf->page_len = ((char*)p) - (char*)page_address(resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
+ resp->xbuf->page_len = ((char*)p) - (char*)page_address(
+ resp->rqstp->rq_respages[resp->rqstp->rq_resused-1]);
/* Use rest of head for padding and remaining ops: */
- resp->rqstp->rq_restailpage = 0;
resp->xbuf->tail[0].iov_base = tailbase;
resp->xbuf->tail[0].iov_len = 0;
resp->p = resp->xbuf->tail[0].iov_base;
@@ -2233,7 +2398,7 @@ err_no_verf:
}
static void
-nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_remove *remove)
+nfsd4_encode_remove(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_remove *remove)
{
ENCODE_HEAD;
@@ -2245,7 +2410,7 @@ nfsd4_encode_remove(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rem
}
static void
-nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_rename *rename)
+nfsd4_encode_rename(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_rename *rename)
{
ENCODE_HEAD;
@@ -2262,7 +2427,7 @@ nfsd4_encode_rename(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_ren
* regardless of the error status.
*/
static void
-nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setattr *setattr)
+nfsd4_encode_setattr(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setattr *setattr)
{
ENCODE_HEAD;
@@ -2281,7 +2446,7 @@ nfsd4_encode_setattr(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_se
}
static void
-nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_setclientid *scd)
+nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_setclientid *scd)
{
ENCODE_HEAD;
@@ -2300,7 +2465,7 @@ nfsd4_encode_setclientid(struct nfsd4_compoundres *resp, int nfserr, struct nfsd
}
static void
-nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_write *write)
+nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_write *write)
{
ENCODE_HEAD;
@@ -2316,7 +2481,7 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_writ
void
nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
{
- u32 *statp;
+ __be32 *statp;
ENCODE_HEAD;
RESERVE_SPACE(8);
@@ -2454,7 +2619,7 @@ nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
*/
int
-nfs4svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfs4svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_ressize_check(rqstp, p);
}
@@ -2476,9 +2641,9 @@ void nfsd4_release_compoundargs(struct nfsd4_compoundargs *args)
}
int
-nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundargs *args)
+nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
{
- int status;
+ __be32 status;
args->p = p;
args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
@@ -2497,7 +2662,7 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoun
}
int
-nfs4svc_encode_compoundres(struct svc_rqst *rqstp, u32 *p, struct nfsd4_compoundres *resp)
+nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundres *resp)
{
/*
* All that remains is to write the tag and operation count...
diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c
index fdf7cf3dfadc..6100bbe27432 100644
--- a/fs/nfsd/nfscache.c
+++ b/fs/nfsd/nfscache.c
@@ -29,7 +29,7 @@
*/
#define CACHESIZE 1024
#define HASHSIZE 64
-#define REQHASH(xid) ((((xid) >> 24) ^ (xid)) & (HASHSIZE-1))
+#define REQHASH(xid) (((((__force __u32)xid) >> 24) ^ ((__force __u32)xid)) & (HASHSIZE-1))
static struct hlist_head * hash_list;
static struct list_head lru_head;
@@ -127,8 +127,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type)
struct hlist_node *hn;
struct hlist_head *rh;
struct svc_cacherep *rp;
- u32 xid = rqstp->rq_xid,
- proto = rqstp->rq_prot,
+ __be32 xid = rqstp->rq_xid;
+ u32 proto = rqstp->rq_prot,
vers = rqstp->rq_vers,
proc = rqstp->rq_proc;
unsigned long age;
@@ -258,7 +258,7 @@ found_entry:
* In this case, nfsd_cache_update is called with statp == NULL.
*/
void
-nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, u32 *statp)
+nfsd_cache_update(struct svc_rqst *rqstp, int cachetype, __be32 *statp)
{
struct svc_cacherep *rp;
struct kvec *resv = &rqstp->rq_res.head[0], *cachv;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 7046ac9cf97f..39aed901514b 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -23,10 +23,14 @@
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/ctype.h>
#include <linux/nfs.h>
#include <linux/nfsd_idmap.h>
+#include <linux/lockd/bind.h>
#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/svcsock.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr.h>
@@ -35,8 +39,6 @@
#include <asm/uaccess.h>
-unsigned int nfsd_versbits = ~0;
-
/*
* We have a single directory with 9 nodes in it.
*/
@@ -52,7 +54,10 @@ enum {
NFSD_List,
NFSD_Fh,
NFSD_Threads,
+ NFSD_Pool_Threads,
NFSD_Versions,
+ NFSD_Ports,
+ NFSD_MaxBlkSize,
/*
* The below MUST come last. Otherwise we leave a hole in nfsd_files[]
* with !CONFIG_NFSD_V4 and simple_fill_super() goes oops
@@ -75,7 +80,10 @@ static ssize_t write_getfd(struct file *file, char *buf, size_t size);
static ssize_t write_getfs(struct file *file, char *buf, size_t size);
static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
static ssize_t write_threads(struct file *file, char *buf, size_t size);
+static ssize_t write_pool_threads(struct file *file, char *buf, size_t size);
static ssize_t write_versions(struct file *file, char *buf, size_t size);
+static ssize_t write_ports(struct file *file, char *buf, size_t size);
+static ssize_t write_maxblksize(struct file *file, char *buf, size_t size);
#ifdef CONFIG_NFSD_V4
static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
@@ -91,7 +99,10 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Getfs] = write_getfs,
[NFSD_Fh] = write_filehandle,
[NFSD_Threads] = write_threads,
+ [NFSD_Pool_Threads] = write_pool_threads,
[NFSD_Versions] = write_versions,
+ [NFSD_Ports] = write_ports,
+ [NFSD_MaxBlkSize] = write_maxblksize,
#ifdef CONFIG_NFSD_V4
[NFSD_Leasetime] = write_leasetime,
[NFSD_RecoveryDir] = write_recoverydir,
@@ -358,6 +369,72 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
return strlen(buf);
}
+extern int nfsd_nrpools(void);
+extern int nfsd_get_nrthreads(int n, int *);
+extern int nfsd_set_nrthreads(int n, int *);
+
+static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
+{
+ /* if size > 0, look for an array of number of threads per node
+ * and apply them then write out number of threads per node as reply
+ */
+ char *mesg = buf;
+ int i;
+ int rv;
+ int len;
+ int npools = nfsd_nrpools();
+ int *nthreads;
+
+ if (npools == 0) {
+ /*
+ * NFS is shut down. The admin can start it by
+ * writing to the threads file but NOT the pool_threads
+ * file, sorry. Report zero threads.
+ */
+ strcpy(buf, "0\n");
+ return strlen(buf);
+ }
+
+ nthreads = kcalloc(npools, sizeof(int), GFP_KERNEL);
+ if (nthreads == NULL)
+ return -ENOMEM;
+
+ if (size > 0) {
+ for (i = 0; i < npools; i++) {
+ rv = get_int(&mesg, &nthreads[i]);
+ if (rv == -ENOENT)
+ break; /* fewer numbers than pools */
+ if (rv)
+ goto out_free; /* syntax error */
+ rv = -EINVAL;
+ if (nthreads[i] < 0)
+ goto out_free;
+ }
+ rv = nfsd_set_nrthreads(i, nthreads);
+ if (rv)
+ goto out_free;
+ }
+
+ rv = nfsd_get_nrthreads(npools, nthreads);
+ if (rv)
+ goto out_free;
+
+ mesg = buf;
+ size = SIMPLE_TRANSACTION_LIMIT;
+ for (i = 0; i < npools && size > 0; i++) {
+ snprintf(mesg, size, "%d%c", nthreads[i], (i == npools-1 ? '\n' : ' '));
+ len = strlen(mesg);
+ size -= len;
+ mesg += len;
+ }
+
+ return (mesg-buf);
+
+out_free:
+ kfree(nthreads);
+ return rv;
+}
+
static ssize_t write_versions(struct file *file, char *buf, size_t size)
{
/*
@@ -372,6 +449,10 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
if (size>0) {
if (nfsd_serv)
+ /* Cannot change versions without updating
+ * nfsd_serv->sv_xdrsize, and reallocing
+ * rq_argp and rq_resp
+ */
return -EBUSY;
if (buf[size-1] != '\n')
return -EINVAL;
@@ -390,10 +471,7 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
case 2:
case 3:
case 4:
- if (sign != '-')
- NFSCTL_VERSET(nfsd_versbits, num);
- else
- NFSCTL_VERUNSET(nfsd_versbits, num);
+ nfsd_vers(num, sign == '-' ? NFSD_CLEAR : NFSD_SET);
break;
default:
return -EINVAL;
@@ -404,16 +482,15 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
/* If all get turned off, turn them back on, as
* having no versions is BAD
*/
- if ((nfsd_versbits & NFSCTL_VERALL)==0)
- nfsd_versbits = NFSCTL_VERALL;
+ nfsd_reset_versions();
}
/* Now write current state into reply buffer */
len = 0;
sep = "";
for (num=2 ; num <= 4 ; num++)
- if (NFSCTL_VERISSET(NFSCTL_VERALL, num)) {
+ if (nfsd_vers(num, NFSD_AVAIL)) {
len += sprintf(buf+len, "%s%c%d", sep,
- NFSCTL_VERISSET(nfsd_versbits, num)?'+':'-',
+ nfsd_vers(num, NFSD_TEST)?'+':'-',
num);
sep = " ";
}
@@ -421,6 +498,95 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
return len;
}
+static ssize_t write_ports(struct file *file, char *buf, size_t size)
+{
+ if (size == 0) {
+ int len = 0;
+ lock_kernel();
+ if (nfsd_serv)
+ len = svc_sock_names(buf, nfsd_serv, NULL);
+ unlock_kernel();
+ return len;
+ }
+ /* Either a single 'fd' number is written, in which
+ * case it must be for a socket of a supported family/protocol,
+ * and we use it as an nfsd socket, or
+ * A '-' followed by the 'name' of a socket in which case
+ * we close the socket.
+ */
+ if (isdigit(buf[0])) {
+ char *mesg = buf;
+ int fd;
+ int err;
+ err = get_int(&mesg, &fd);
+ if (err)
+ return -EINVAL;
+ if (fd < 0)
+ return -EINVAL;
+ err = nfsd_create_serv();
+ if (!err) {
+ int proto = 0;
+ err = svc_addsock(nfsd_serv, fd, buf, &proto);
+ if (err >= 0) {
+ err = lockd_up(proto);
+ if (err < 0)
+ svc_sock_names(buf+strlen(buf)+1, nfsd_serv, buf);
+ }
+ /* Decrease the count, but don't shutdown the
+ * the service
+ */
+ lock_kernel();
+ nfsd_serv->sv_nrthreads--;
+ unlock_kernel();
+ }
+ return err < 0 ? err : 0;
+ }
+ if (buf[0] == '-') {
+ char *toclose = kstrdup(buf+1, GFP_KERNEL);
+ int len = 0;
+ if (!toclose)
+ return -ENOMEM;
+ lock_kernel();
+ if (nfsd_serv)
+ len = svc_sock_names(buf, nfsd_serv, toclose);
+ unlock_kernel();
+ if (len >= 0)
+ lockd_down();
+ kfree(toclose);
+ return len;
+ }
+ return -EINVAL;
+}
+
+int nfsd_max_blksize;
+
+static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
+{
+ char *mesg = buf;
+ if (size > 0) {
+ int bsize;
+ int rv = get_int(&mesg, &bsize);
+ if (rv)
+ return rv;
+ /* force bsize into allowed range and
+ * required alignment.
+ */
+ if (bsize < 1024)
+ bsize = 1024;
+ if (bsize > NFSSVC_MAXBLKSIZE)
+ bsize = NFSSVC_MAXBLKSIZE;
+ bsize &= ~(1024-1);
+ lock_kernel();
+ if (nfsd_serv && nfsd_serv->sv_nrthreads) {
+ unlock_kernel();
+ return -EBUSY;
+ }
+ nfsd_max_blksize = bsize;
+ unlock_kernel();
+ }
+ return sprintf(buf, "%d\n", nfsd_max_blksize);
+}
+
#ifdef CONFIG_NFSD_V4
extern time_t nfs4_leasetime(void);
@@ -483,7 +649,10 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
[NFSD_List] = {"exports", &exports_operations, S_IRUGO},
[NFSD_Fh] = {"filehandle", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
+ [NFSD_Pool_Threads] = {"pool_threads", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_Versions] = {"versions", &transaction_ops, S_IWUSR|S_IRUSR},
+ [NFSD_Ports] = {"portlist", &transaction_ops, S_IWUSR|S_IRUGO},
+ [NFSD_MaxBlkSize] = {"max_block_size", &transaction_ops, S_IWUSR|S_IRUGO},
#ifdef CONFIG_NFSD_V4
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
[NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index 501d83884530..727ab3bd450d 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -76,7 +76,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
* comment in the NFSv3 spec says this is incorrect (implementation notes for
* the write call).
*/
-static inline int
+static inline __be32
nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
{
/* Type can be negative when creating hardlinks - not to a dir */
@@ -110,13 +110,13 @@ nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, int type)
* This is only called at the start of an nfsproc call, so fhp points to
* a svc_fh which is all 0 except for the over-the-wire file handle.
*/
-u32
+__be32
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
{
struct knfsd_fh *fh = &fhp->fh_handle;
struct svc_export *exp = NULL;
struct dentry *dentry;
- u32 error = 0;
+ __be32 error = 0;
dprintk("nfsd: fh_verify(%s)\n", SVCFH_fmt(fhp));
@@ -315,7 +315,7 @@ static inline void _fh_update_old(struct dentry *dentry,
fh->ofh_dirino = 0;
}
-int
+__be32
fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, struct svc_fh *ref_fh)
{
/* ref_fh is a reference file handle.
@@ -451,7 +451,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, st
* Update file handle information after changing a dentry.
* This is only called by nfsd_create, nfsd_create_v3 and nfsd_proc_create
*/
-int
+__be32
fh_update(struct svc_fh *fhp)
{
struct dentry *dentry;
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
index 06cd0db0f32b..ec983b777680 100644
--- a/fs/nfsd/nfsproc.c
+++ b/fs/nfsd/nfsproc.c
@@ -30,22 +30,22 @@ typedef struct svc_buf svc_buf;
#define NFSDDBG_FACILITY NFSDDBG_PROC
-static int
+static __be32
nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
return nfs_ok;
}
-static int
-nfsd_return_attrs(int err, struct nfsd_attrstat *resp)
+static __be32
+nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
{
if (err) return err;
return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
resp->fh.fh_dentry,
&resp->stat));
}
-static int
-nfsd_return_dirop(int err, struct nfsd_diropres *resp)
+static __be32
+nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
{
if (err) return err;
return nfserrno(vfs_getattr(resp->fh.fh_export->ex_mnt,
@@ -56,11 +56,11 @@ nfsd_return_dirop(int err, struct nfsd_diropres *resp)
* Get a file's attributes
* N.B. After this call resp->fh needs an fh_put
*/
-static int
+static __be32
nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
struct nfsd_attrstat *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
fh_copy(&resp->fh, &argp->fh);
@@ -72,11 +72,11 @@ nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle *argp,
* Set a file's attributes
* N.B. After this call resp->fh needs an fh_put
*/
-static int
+static __be32
nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
struct nfsd_attrstat *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
SVCFH_fmt(&argp->fh),
argp->attrs.ia_valid, (long) argp->attrs.ia_size);
@@ -92,11 +92,11 @@ nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
* doesn't exist yet.
* N.B. After this call resp->fh needs an fh_put
*/
-static int
+static __be32
nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
struct nfsd_diropres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: LOOKUP %s %.*s\n",
SVCFH_fmt(&argp->fh), argp->len, argp->name);
@@ -112,11 +112,11 @@ nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
/*
* Read a symlink.
*/
-static int
+static __be32
nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
struct nfsd_readlinkres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
@@ -132,11 +132,11 @@ nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
* Read a portion of a file.
* N.B. After this call resp->fh needs an fh_put
*/
-static int
+static __be32
nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
struct nfsd_readres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: READ %s %d bytes at %d\n",
SVCFH_fmt(&argp->fh),
@@ -146,20 +146,20 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
* status, 17 words for fattr, and 1 word for the byte count.
*/
- if (NFSSVC_MAXBLKSIZE < argp->count) {
+ if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
printk(KERN_NOTICE
"oversized read request from %u.%u.%u.%u:%d (%d bytes)\n",
NIPQUAD(rqstp->rq_addr.sin_addr.s_addr),
ntohs(rqstp->rq_addr.sin_port),
argp->count);
- argp->count = NFSSVC_MAXBLKSIZE;
+ argp->count = NFSSVC_MAXBLKSIZE_V2;
}
svc_reserve(rqstp, (19<<2) + argp->count + 4);
resp->count = argp->count;
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
&resp->count);
if (nfserr) return nfserr;
@@ -172,11 +172,11 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
* Write data to a file
* N.B. After this call resp->fh needs an fh_put
*/
-static int
+static __be32
nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
struct nfsd_attrstat *resp)
{
- int nfserr;
+ __be32 nfserr;
int stable = 1;
dprintk("nfsd: WRITE %s %d bytes at %d\n",
@@ -185,7 +185,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), NULL,
argp->offset,
- argp->vec, argp->vlen,
+ rqstp->rq_vec, argp->vlen,
argp->len,
&stable);
return nfsd_return_attrs(nfserr, resp);
@@ -197,7 +197,7 @@ nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
* and the actual create() call in compliance with VFS protocols.
* N.B. After this call _both_ argp->fh and resp->fh need an fh_put
*/
-static int
+static __be32
nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
struct nfsd_diropres *resp)
{
@@ -206,7 +206,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
struct iattr *attr = &argp->attrs;
struct inode *inode;
struct dentry *dchild;
- int nfserr, type, mode;
+ int type, mode;
+ __be32 nfserr;
dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
dprintk("nfsd: CREATE %s %.*s\n",
@@ -225,7 +226,7 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
nfserr = nfserr_exist;
if (isdotent(argp->name, argp->len))
goto done;
- fh_lock(dirfhp);
+ fh_lock_nested(dirfhp, I_MUTEX_PARENT);
dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
if (IS_ERR(dchild)) {
nfserr = nfserrno(PTR_ERR(dchild));
@@ -348,11 +349,11 @@ done:
return nfsd_return_dirop(nfserr, resp);
}
-static int
+static __be32
nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
void *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh),
argp->len, argp->name);
@@ -363,11 +364,11 @@ nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
return nfserr;
}
-static int
+static __be32
nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
void *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: RENAME %s %.*s -> \n",
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
@@ -381,11 +382,11 @@ nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
return nfserr;
}
-static int
+static __be32
nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
void *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: LINK %s ->\n",
SVCFH_fmt(&argp->ffh));
@@ -401,12 +402,12 @@ nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
return nfserr;
}
-static int
+static __be32
nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
void *resp)
{
struct svc_fh newfh;
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
@@ -430,11 +431,11 @@ nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
* Make directory. This operation is not idempotent.
* N.B. After this call resp->fh needs an fh_put
*/
-static int
+static __be32
nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
struct nfsd_diropres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
@@ -454,11 +455,11 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
/*
* Remove a directory
*/
-static int
+static __be32
nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
void *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
@@ -470,11 +471,12 @@ nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
/*
* Read a portion of a directory.
*/
-static int
+static __be32
nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
struct nfsd_readdirres *resp)
{
- int nfserr, count;
+ int count;
+ __be32 nfserr;
loff_t offset;
dprintk("nfsd: READDIR %s %d bytes at %d\n",
@@ -509,11 +511,11 @@ nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
/*
* Get file system info
*/
-static int
+static __be32
nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle *argp,
struct nfsd_statfsres *resp)
{
- int nfserr;
+ __be32 nfserr;
dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
@@ -553,7 +555,7 @@ static struct svc_procedure nfsd_procedures2[18] = {
PROC(none, void, void, none, RC_NOCACHE, ST),
PROC(lookup, diropargs, diropres, fhandle, RC_NOCACHE, ST+FH+AT),
PROC(readlink, readlinkargs, readlinkres, none, RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
- PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE/4),
+ PROC(read, readargs, readres, fhandle, RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4),
PROC(none, void, void, none, RC_NOCACHE, ST),
PROC(write, writeargs, attrstat, fhandle, RC_REPLBUFF, ST+AT),
PROC(create, createargs, diropres, fhandle, RC_REPLBUFF, ST+FH+AT),
@@ -579,11 +581,11 @@ struct svc_version nfsd_version2 = {
/*
* Map errnos to NFS errnos.
*/
-int
+__be32
nfserrno (int errno)
{
static struct {
- int nfserr;
+ __be32 nfserr;
int syserr;
} nfs_errtbl[] = {
{ nfs_ok, 0 },
@@ -615,11 +617,10 @@ nfserrno (int errno)
{ nfserr_badname, -ESRCH },
{ nfserr_io, -ETXTBSY },
{ nfserr_notsupp, -EOPNOTSUPP },
- { -1, -EIO }
};
int i;
- for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
+ for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
if (nfs_errtbl[i].syserr == errno)
return nfs_errtbl[i].nfserr;
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index ec1decf29bab..0aaccb03bf76 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -57,12 +57,6 @@ static atomic_t nfsd_busy;
static unsigned long nfsd_last_call;
static DEFINE_SPINLOCK(nfsd_call_lock);
-struct nfsd_list {
- struct list_head list;
- struct task_struct *task;
-};
-static struct list_head nfsd_list = LIST_HEAD_INIT(nfsd_list);
-
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
static struct svc_stat nfsd_acl_svcstats;
static struct svc_version * nfsd_acl_version[] = {
@@ -117,6 +111,32 @@ struct svc_program nfsd_program = {
};
+int nfsd_vers(int vers, enum vers_op change)
+{
+ if (vers < NFSD_MINVERS || vers >= NFSD_NRVERS)
+ return -1;
+ switch(change) {
+ case NFSD_SET:
+ nfsd_versions[vers] = nfsd_version[vers];
+ break;
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+ if (vers < NFSD_ACL_NRVERS)
+ nfsd_acl_version[vers] = nfsd_acl_version[vers];
+#endif
+ case NFSD_CLEAR:
+ nfsd_versions[vers] = NULL;
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+ if (vers < NFSD_ACL_NRVERS)
+ nfsd_acl_version[vers] = NULL;
+#endif
+ break;
+ case NFSD_TEST:
+ return nfsd_versions[vers] != NULL;
+ case NFSD_AVAIL:
+ return nfsd_version[vers] != NULL;
+ }
+ return 0;
+}
/*
* Maximum number of nfsd processes
*/
@@ -130,16 +150,192 @@ int nfsd_nrthreads(void)
return nfsd_serv->sv_nrthreads;
}
+static int killsig; /* signal that was used to kill last nfsd */
+static void nfsd_last_thread(struct svc_serv *serv)
+{
+ /* When last nfsd thread exits we need to do some clean-up */
+ struct svc_sock *svsk;
+ list_for_each_entry(svsk, &serv->sv_permsocks, sk_list)
+ lockd_down();
+ nfsd_serv = NULL;
+ nfsd_racache_shutdown();
+ nfs4_state_shutdown();
+
+ printk(KERN_WARNING "nfsd: last server has exited\n");
+ if (killsig != SIG_NOCLEAN) {
+ printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
+ nfsd_export_flush();
+ }
+}
+
+void nfsd_reset_versions(void)
+{
+ int found_one = 0;
+ int i;
+
+ for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
+ if (nfsd_program.pg_vers[i])
+ found_one = 1;
+ }
+
+ if (!found_one) {
+ for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
+ nfsd_program.pg_vers[i] = nfsd_version[i];
+#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
+ for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
+ nfsd_acl_program.pg_vers[i] =
+ nfsd_acl_version[i];
+#endif
+ }
+}
+
+int nfsd_create_serv(void)
+{
+ int err = 0;
+ lock_kernel();
+ if (nfsd_serv) {
+ svc_get(nfsd_serv);
+ unlock_kernel();
+ return 0;
+ }
+ if (nfsd_max_blksize == 0) {
+ /* choose a suitable default */
+ struct sysinfo i;
+ si_meminfo(&i);
+ /* Aim for 1/4096 of memory per thread
+ * This gives 1MB on 4Gig machines
+ * But only uses 32K on 128M machines.
+ * Bottom out at 8K on 32M and smaller.
+ * Of course, this is only a default.
+ */
+ nfsd_max_blksize = NFSSVC_MAXBLKSIZE;
+ i.totalram <<= PAGE_SHIFT - 12;
+ while (nfsd_max_blksize > i.totalram &&
+ nfsd_max_blksize >= 8*1024*2)
+ nfsd_max_blksize /= 2;
+ }
+
+ atomic_set(&nfsd_busy, 0);
+ nfsd_serv = svc_create_pooled(&nfsd_program,
+ nfsd_max_blksize,
+ nfsd_last_thread,
+ nfsd, SIG_NOCLEAN, THIS_MODULE);
+ if (nfsd_serv == NULL)
+ err = -ENOMEM;
+ unlock_kernel();
+ do_gettimeofday(&nfssvc_boot); /* record boot time */
+ return err;
+}
+
+static int nfsd_init_socks(int port)
+{
+ int error;
+ if (!list_empty(&nfsd_serv->sv_permsocks))
+ return 0;
+
+ error = lockd_up(IPPROTO_UDP);
+ if (error >= 0) {
+ error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
+ if (error < 0)
+ lockd_down();
+ }
+ if (error < 0)
+ return error;
+
+#ifdef CONFIG_NFSD_TCP
+ error = lockd_up(IPPROTO_TCP);
+ if (error >= 0) {
+ error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
+ if (error < 0)
+ lockd_down();
+ }
+ if (error < 0)
+ return error;
+#endif
+ return 0;
+}
+
+int nfsd_nrpools(void)
+{
+ if (nfsd_serv == NULL)
+ return 0;
+ else
+ return nfsd_serv->sv_nrpools;
+}
+
+int nfsd_get_nrthreads(int n, int *nthreads)
+{
+ int i = 0;
+
+ if (nfsd_serv != NULL) {
+ for (i = 0; i < nfsd_serv->sv_nrpools && i < n; i++)
+ nthreads[i] = nfsd_serv->sv_pools[i].sp_nrthreads;
+ }
+
+ return 0;
+}
+
+int nfsd_set_nrthreads(int n, int *nthreads)
+{
+ int i = 0;
+ int tot = 0;
+ int err = 0;
+
+ if (nfsd_serv == NULL || n <= 0)
+ return 0;
+
+ if (n > nfsd_serv->sv_nrpools)
+ n = nfsd_serv->sv_nrpools;
+
+ /* enforce a global maximum number of threads */
+ tot = 0;
+ for (i = 0; i < n; i++) {
+ if (nthreads[i] > NFSD_MAXSERVS)
+ nthreads[i] = NFSD_MAXSERVS;
+ tot += nthreads[i];
+ }
+ if (tot > NFSD_MAXSERVS) {
+ /* total too large: scale down requested numbers */
+ for (i = 0; i < n && tot > 0; i++) {
+ int new = nthreads[i] * NFSD_MAXSERVS / tot;
+ tot -= (nthreads[i] - new);
+ nthreads[i] = new;
+ }
+ for (i = 0; i < n && tot > 0; i++) {
+ nthreads[i]--;
+ tot--;
+ }
+ }
+
+ /*
+ * There must always be a thread in pool 0; the admin
+ * can't shut down NFS completely using pool_threads.
+ */
+ if (nthreads[0] == 0)
+ nthreads[0] = 1;
+
+ /* apply the new numbers */
+ lock_kernel();
+ svc_get(nfsd_serv);
+ for (i = 0; i < n; i++) {
+ err = svc_set_num_threads(nfsd_serv, &nfsd_serv->sv_pools[i],
+ nthreads[i]);
+ if (err)
+ break;
+ }
+ svc_destroy(nfsd_serv);
+ unlock_kernel();
+
+ return err;
+}
+
int
nfsd_svc(unsigned short port, int nrservs)
{
int error;
- int none_left, found_one, i;
- struct list_head *victim;
lock_kernel();
- dprintk("nfsd: creating service: vers 0x%x\n",
- nfsd_versbits);
+ dprintk("nfsd: creating service\n");
error = -EINVAL;
if (nrservs <= 0)
nrservs = 0;
@@ -153,91 +349,20 @@ nfsd_svc(unsigned short port, int nrservs)
error = nfs4_state_start();
if (error<0)
goto out;
- if (!nfsd_serv) {
- /*
- * Use the nfsd_ctlbits to define which
- * versions that will be advertised.
- * If nfsd_ctlbits doesn't list any version,
- * export them all.
- */
- found_one = 0;
-
- for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++) {
- if (NFSCTL_VERISSET(nfsd_versbits, i)) {
- nfsd_program.pg_vers[i] = nfsd_version[i];
- found_one = 1;
- } else
- nfsd_program.pg_vers[i] = NULL;
- }
- if (!found_one) {
- for (i = NFSD_MINVERS; i < NFSD_NRVERS; i++)
- nfsd_program.pg_vers[i] = nfsd_version[i];
- }
+ nfsd_reset_versions();
+ error = nfsd_create_serv();
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
- found_one = 0;
-
- for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++) {
- if (NFSCTL_VERISSET(nfsd_versbits, i)) {
- nfsd_acl_program.pg_vers[i] =
- nfsd_acl_version[i];
- found_one = 1;
- } else
- nfsd_acl_program.pg_vers[i] = NULL;
- }
-
- if (!found_one) {
- for (i = NFSD_ACL_MINVERS; i < NFSD_ACL_NRVERS; i++)
- nfsd_acl_program.pg_vers[i] =
- nfsd_acl_version[i];
- }
-#endif
-
- atomic_set(&nfsd_busy, 0);
- error = -ENOMEM;
- nfsd_serv = svc_create(&nfsd_program, NFSD_BUFSIZE);
- if (nfsd_serv == NULL)
- goto out;
- error = svc_makesock(nfsd_serv, IPPROTO_UDP, port);
- if (error < 0)
- goto failure;
+ if (error)
+ goto out;
+ error = nfsd_init_socks(port);
+ if (error)
+ goto failure;
-#ifdef CONFIG_NFSD_TCP
- error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
- if (error < 0)
- goto failure;
-#endif
- do_gettimeofday(&nfssvc_boot); /* record boot time */
- } else
- nfsd_serv->sv_nrthreads++;
- nrservs -= (nfsd_serv->sv_nrthreads-1);
- while (nrservs > 0) {
- nrservs--;
- __module_get(THIS_MODULE);
- error = svc_create_thread(nfsd, nfsd_serv);
- if (error < 0) {
- module_put(THIS_MODULE);
- break;
- }
- }
- victim = nfsd_list.next;
- while (nrservs < 0 && victim != &nfsd_list) {
- struct nfsd_list *nl =
- list_entry(victim,struct nfsd_list, list);
- victim = victim->next;
- send_sig(SIG_NOCLEAN, nl->task, 1);
- nrservs++;
- }
+ error = svc_set_num_threads(nfsd_serv, NULL, nrservs);
failure:
- none_left = (nfsd_serv->sv_nrthreads == 1);
svc_destroy(nfsd_serv); /* Release server */
- if (none_left) {
- nfsd_serv = NULL;
- nfsd_racache_shutdown();
- nfs4_state_shutdown();
- }
out:
unlock_kernel();
return error;
@@ -270,10 +395,8 @@ update_thread_usage(int busy_threads)
static void
nfsd(struct svc_rqst *rqstp)
{
- struct svc_serv *serv = rqstp->rq_server;
struct fs_struct *fsp;
int err;
- struct nfsd_list me;
sigset_t shutdown_mask, allowed_mask;
/* Lock module and set up kernel thread */
@@ -297,10 +420,7 @@ nfsd(struct svc_rqst *rqstp)
nfsdstats.th_cnt++;
- lockd_up(); /* start lockd */
-
- me.task = current;
- list_add(&me.list, &nfsd_list);
+ rqstp->rq_task = current;
unlock_kernel();
@@ -322,8 +442,7 @@ nfsd(struct svc_rqst *rqstp)
* Find a socket with data available and call its
* recvfrom routine.
*/
- while ((err = svc_recv(serv, rqstp,
- 60*60*HZ)) == -EAGAIN)
+ while ((err = svc_recv(rqstp, 60*60*HZ)) == -EAGAIN)
;
if (err < 0)
break;
@@ -336,7 +455,7 @@ nfsd(struct svc_rqst *rqstp)
/* Process request with signals blocked. */
sigprocmask(SIG_SETMASK, &allowed_mask, NULL);
- svc_process(serv, rqstp);
+ svc_process(rqstp);
/* Unlock export hash tables */
exp_readunlock();
@@ -353,29 +472,13 @@ nfsd(struct svc_rqst *rqstp)
if (sigismember(&current->pending.signal, signo) &&
!sigismember(&current->blocked, signo))
break;
- err = signo;
+ killsig = signo;
}
- /* Clear signals before calling lockd_down() and svc_exit_thread() */
+ /* Clear signals before calling svc_exit_thread() */
flush_signals(current);
lock_kernel();
- /* Release lockd */
- lockd_down();
-
- /* Check if this is last thread */
- if (serv->sv_nrthreads==1) {
-
- printk(KERN_WARNING "nfsd: last server has exited\n");
- if (err != SIG_NOCLEAN) {
- printk(KERN_WARNING "nfsd: unexporting all filesystems\n");
- nfsd_export_flush();
- }
- nfsd_serv = NULL;
- nfsd_racache_shutdown(); /* release read-ahead cache */
- nfs4_state_shutdown();
- }
- list_del(&me.list);
nfsdstats.th_cnt --;
out:
@@ -388,12 +491,12 @@ out:
}
int
-nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
+nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
{
struct svc_procedure *proc;
kxdrproc_t xdr;
- u32 nfserr;
- u32 *nfserrp;
+ __be32 nfserr;
+ __be32 *nfserrp;
dprintk("nfsd_dispatch: vers %d proc %d\n",
rqstp->rq_vers, rqstp->rq_proc);
@@ -412,7 +515,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
/* Decode arguments */
xdr = proc->pc_decode;
- if (xdr && !xdr(rqstp, (u32*)rqstp->rq_arg.head[0].iov_base,
+ if (xdr && !xdr(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base,
rqstp->rq_argp)) {
dprintk("nfsd: failed to decode arguments!\n");
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
@@ -425,7 +528,7 @@ nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp)
*/
nfserrp = rqstp->rq_res.head[0].iov_base
+ rqstp->rq_res.head[0].iov_len;
- rqstp->rq_res.head[0].iov_len += sizeof(u32);
+ rqstp->rq_res.head[0].iov_len += sizeof(__be32);
/* Now call the procedure handler, and encode NFS status. */
nfserr = proc->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
diff --git a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
index e3a0797dd56b..56ebb1443e0e 100644
--- a/fs/nfsd/nfsxdr.c
+++ b/fs/nfsd/nfsxdr.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nfsd/xdr.c
+ * linux/fs/nfsd/nfsxdr.c
*
* XDR support for nfsd
*
@@ -37,8 +37,8 @@ static u32 nfs_ftypes[] = {
/*
* XDR functions for basic NFS types
*/
-static u32 *
-decode_fh(u32 *p, struct svc_fh *fhp)
+static __be32 *
+decode_fh(__be32 *p, struct svc_fh *fhp)
{
fh_init(fhp, NFS_FHSIZE);
memcpy(&fhp->fh_handle.fh_base, p, NFS_FHSIZE);
@@ -50,13 +50,13 @@ decode_fh(u32 *p, struct svc_fh *fhp)
}
/* Helper function for NFSv2 ACL code */
-u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp)
+__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp)
{
return decode_fh(p, fhp);
}
-static inline u32 *
-encode_fh(u32 *p, struct svc_fh *fhp)
+static inline __be32 *
+encode_fh(__be32 *p, struct svc_fh *fhp)
{
memcpy(p, &fhp->fh_handle.fh_base, NFS_FHSIZE);
return p + (NFS_FHSIZE>> 2);
@@ -66,8 +66,8 @@ encode_fh(u32 *p, struct svc_fh *fhp)
* Decode a file name and make sure that the path contains
* no slashes or null bytes.
*/
-static inline u32 *
-decode_filename(u32 *p, char **namp, int *lenp)
+static inline __be32 *
+decode_filename(__be32 *p, char **namp, int *lenp)
{
char *name;
int i;
@@ -82,8 +82,8 @@ decode_filename(u32 *p, char **namp, int *lenp)
return p;
}
-static inline u32 *
-decode_pathname(u32 *p, char **namp, int *lenp)
+static inline __be32 *
+decode_pathname(__be32 *p, char **namp, int *lenp)
{
char *name;
int i;
@@ -98,8 +98,8 @@ decode_pathname(u32 *p, char **namp, int *lenp)
return p;
}
-static inline u32 *
-decode_sattr(u32 *p, struct iattr *iap)
+static inline __be32 *
+decode_sattr(__be32 *p, struct iattr *iap)
{
u32 tmp, tmp1;
@@ -151,8 +151,8 @@ decode_sattr(u32 *p, struct iattr *iap)
return p;
}
-static u32 *
-encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
+static __be32 *
+encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
struct kstat *stat)
{
struct dentry *dentry = fhp->fh_dentry;
@@ -195,7 +195,7 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp,
}
/* Helper function for NFSv2 ACL code */
-u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
{
struct kstat stat;
vfs_getattr(fhp->fh_export->ex_mnt, fhp->fh_dentry, &stat);
@@ -206,13 +206,13 @@ u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
* XDR decode functions
*/
int
-nfssvc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfssvc_decode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_argsize_check(rqstp, p);
}
int
-nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
+nfssvc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
@@ -220,7 +220,7 @@ nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
}
int
-nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_sattrargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_sattrargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -231,7 +231,7 @@ nfssvc_decode_sattrargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_diropargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -242,7 +242,7 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_readargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_readargs *args)
{
unsigned int len;
@@ -254,19 +254,18 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
len = args->count = ntohl(*p++);
p++; /* totalcount - unused */
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > NFSSVC_MAXBLKSIZE_V2)
+ len = NFSSVC_MAXBLKSIZE_V2;
/* set up somewhere to store response.
* We take pages, put them on reslist and include in iovec
*/
v=0;
while (len > 0) {
- pn=rqstp->rq_resused;
- svc_take_page(rqstp);
- args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
- args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
- len -= args->vec[v].iov_len;
+ pn = rqstp->rq_resused++;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
+ rqstp->rq_vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
+ len -= rqstp->rq_vec[v].iov_len;
v++;
}
args->vlen = v;
@@ -274,7 +273,7 @@ nfssvc_decode_readargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_writeargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_writeargs *args)
{
unsigned int len;
@@ -286,25 +285,25 @@ nfssvc_decode_writeargs(struct svc_rqst *rqstp, u32 *p,
args->offset = ntohl(*p++); /* offset */
p++; /* totalcount */
len = args->len = ntohl(*p++);
- args->vec[0].iov_base = (void*)p;
- args->vec[0].iov_len = rqstp->rq_arg.head[0].iov_len -
+ 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);
- if (len > NFSSVC_MAXBLKSIZE)
- len = NFSSVC_MAXBLKSIZE;
+ if (len > NFSSVC_MAXBLKSIZE_V2)
+ len = NFSSVC_MAXBLKSIZE_V2;
v = 0;
- while (len > args->vec[v].iov_len) {
- len -= args->vec[v].iov_len;
+ while (len > rqstp->rq_vec[v].iov_len) {
+ len -= rqstp->rq_vec[v].iov_len;
v++;
- args->vec[v].iov_base = page_address(rqstp->rq_argpages[v]);
- args->vec[v].iov_len = PAGE_SIZE;
+ rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
+ rqstp->rq_vec[v].iov_len = PAGE_SIZE;
}
- args->vec[v].iov_len = len;
+ rqstp->rq_vec[v].iov_len = len;
args->vlen = v+1;
- return args->vec[0].iov_len > 0;
+ return rqstp->rq_vec[0].iov_len > 0;
}
int
-nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_createargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_createargs *args)
{
if (!(p = decode_fh(p, &args->fh))
@@ -316,7 +315,7 @@ nfssvc_decode_createargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_renameargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_renameargs *args)
{
if (!(p = decode_fh(p, &args->ffh))
@@ -329,18 +328,17 @@ nfssvc_decode_renameargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinkargs *args)
+nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd_readlinkargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
return 0;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
int
-nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_linkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_linkargs *args)
{
if (!(p = decode_fh(p, &args->ffh))
@@ -352,7 +350,7 @@ nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_symlinkargs *args)
{
if (!(p = decode_fh(p, &args->ffh))
@@ -365,7 +363,7 @@ nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
+nfssvc_decode_readdirargs(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_readdirargs *args)
{
if (!(p = decode_fh(p, &args->fh)))
@@ -375,8 +373,7 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
if (args->count > PAGE_SIZE)
args->count = PAGE_SIZE;
- svc_take_page(rqstp);
- args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+ args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused++]);
return xdr_argsize_check(rqstp, p);
}
@@ -385,13 +382,13 @@ nfssvc_decode_readdirargs(struct svc_rqst *rqstp, u32 *p,
* XDR encode functions
*/
int
-nfssvc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p, void *dummy)
{
return xdr_ressize_check(rqstp, p);
}
int
-nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_attrstat *resp)
{
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
@@ -399,7 +396,7 @@ nfssvc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_diropres *resp)
{
p = encode_fh(p, &resp->fh);
@@ -408,7 +405,7 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_readlinkres *resp)
{
*p++ = htonl(resp->len);
@@ -416,7 +413,6 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->len;
if (resp->len & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
@@ -425,7 +421,7 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_readres *resp)
{
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
@@ -436,7 +432,6 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
rqstp->rq_res.page_len = resp->count;
if (resp->count & 3) {
/* need to pad the tail */
- rqstp->rq_restailpage = 0;
rqstp->rq_res.tail[0].iov_base = p;
*p = 0;
rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
@@ -445,7 +440,7 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_readdirres *resp)
{
xdr_ressize_check(rqstp, p);
@@ -458,12 +453,12 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
}
int
-nfssvc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
+nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_statfsres *resp)
{
struct kstatfs *stat = &resp->stats;
- *p++ = htonl(NFSSVC_MAXBLKSIZE); /* max transfer size */
+ *p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */
*p++ = htonl(stat->f_bsize);
*p++ = htonl(stat->f_blocks);
*p++ = htonl(stat->f_bfree);
@@ -476,7 +471,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name,
int namlen, loff_t offset, ino_t ino, unsigned int d_type)
{
struct nfsd_readdirres *cd = container_of(ccd, struct nfsd_readdirres, common);
- u32 *p = cd->buffer;
+ __be32 *p = cd->buffer;
int buflen, slen;
/*
@@ -502,7 +497,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name,
*p++ = htonl((u32) ino); /* file id */
p = xdr_encode_array(p, name, namlen);/* name length & name */
cd->offset = p; /* remember pointer */
- *p++ = ~(u32) 0; /* offset of next entry */
+ *p++ = htonl(~0U); /* offset of next entry */
cd->buflen = buflen;
cd->buffer = p;
@@ -514,7 +509,7 @@ nfssvc_encode_entry(struct readdir_cd *ccd, const char *name,
* XDR release functions
*/
int
-nfssvc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
+nfssvc_release_fhandle(struct svc_rqst *rqstp, __be32 *p,
struct nfsd_fhandle *resp)
{
fh_put(&resp->fh);
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index c9e3b5a8fe07..f21e917bb8ed 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -54,6 +54,7 @@
#include <linux/nfsd_idmap.h>
#include <linux/security.h>
#endif /* CONFIG_NFSD_V4 */
+#include <linux/jhash.h>
#include <asm/uaccess.h>
@@ -81,10 +82,19 @@ struct raparms {
dev_t p_dev;
int p_set;
struct file_ra_state p_ra;
+ unsigned int p_hindex;
};
+struct raparm_hbucket {
+ struct raparms *pb_head;
+ spinlock_t pb_lock;
+} ____cacheline_aligned_in_smp;
+
static struct raparms * raparml;
-static struct raparms * raparm_cache;
+#define RAPARM_HASH_BITS 4
+#define RAPARM_HASH_SIZE (1<<RAPARM_HASH_BITS)
+#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
+static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
/*
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
@@ -100,7 +110,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct dentry *dentry = *dpp;
struct vfsmount *mnt = mntget(exp->ex_mnt);
struct dentry *mounts = dget(dentry);
- int err = nfs_ok;
+ int err = 0;
while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts));
@@ -138,14 +148,15 @@ out:
* clients and is explicitly disallowed for NFSv3
* NeilBrown <neilb@cse.unsw.edu.au>
*/
-int
+__be32
nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
int len, struct svc_fh *resfh)
{
struct svc_export *exp;
struct dentry *dparent;
struct dentry *dentry;
- int err;
+ __be32 err;
+ int host_err;
dprintk("nfsd: nfsd_lookup(fh %s, %.*s)\n", SVCFH_fmt(fhp), len,name);
@@ -183,7 +194,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
exp2 = exp_parent(exp->ex_client, mnt, dentry,
&rqstp->rq_chandle);
if (IS_ERR(exp2)) {
- err = PTR_ERR(exp2);
+ host_err = PTR_ERR(exp2);
dput(dentry);
mntput(mnt);
goto out_nfserr;
@@ -200,14 +211,14 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
} else {
fh_lock(fhp);
dentry = lookup_one_len(name, dparent, len);
- err = PTR_ERR(dentry);
+ host_err = PTR_ERR(dentry);
if (IS_ERR(dentry))
goto out_nfserr;
/*
* check if we have crossed a mount point ...
*/
if (d_mountpoint(dentry)) {
- if ((err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
+ if ((host_err = nfsd_cross_mnt(rqstp, &dentry, &exp))) {
dput(dentry);
goto out_nfserr;
}
@@ -226,7 +237,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
goto out;
}
@@ -234,7 +245,7 @@ out_nfserr:
* Set various file attributes.
* N.B. After this call fhp needs an fh_put
*/
-int
+__be32
nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
int check_guard, time_t guardtime)
{
@@ -243,7 +254,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
int accmode = MAY_SATTR;
int ftype = 0;
int imode;
- int err;
+ __be32 err;
+ int host_err;
int size_change = 0;
if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
@@ -309,19 +321,19 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
* If we are changing the size of the file, then
* we need to break all leases.
*/
- err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
- if (err == -EWOULDBLOCK)
- err = -ETIMEDOUT;
- if (err) /* ENOMEM or EWOULDBLOCK */
+ host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK);
+ if (host_err == -EWOULDBLOCK)
+ host_err = -ETIMEDOUT;
+ if (host_err) /* ENOMEM or EWOULDBLOCK */
goto out_nfserr;
- err = get_write_access(inode);
- if (err)
+ host_err = get_write_access(inode);
+ if (host_err)
goto out_nfserr;
size_change = 1;
- err = locks_verify_truncate(inode, NULL, iap->ia_size);
- if (err) {
+ host_err = locks_verify_truncate(inode, NULL, iap->ia_size);
+ if (host_err) {
put_write_access(inode);
goto out_nfserr;
}
@@ -347,8 +359,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
err = nfserr_notsync;
if (!check_guard || guardtime == inode->i_ctime.tv_sec) {
fh_lock(fhp);
- err = notify_change(dentry, iap);
- err = nfserrno(err);
+ host_err = notify_change(dentry, iap);
+ err = nfserrno(host_err);
fh_unlock(fhp);
}
if (size_change)
@@ -360,7 +372,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
goto out;
}
@@ -410,11 +422,12 @@ out:
return error;
}
-int
+__be32
nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct nfs4_acl *acl)
{
- int error;
+ __be32 error;
+ int host_error;
struct dentry *dentry;
struct inode *inode;
struct posix_acl *pacl = NULL, *dpacl = NULL;
@@ -430,22 +443,20 @@ nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (S_ISDIR(inode->i_mode))
flags = NFS4_ACL_DIR;
- error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
- if (error == -EINVAL) {
+ host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+ if (host_error == -EINVAL) {
error = nfserr_attrnotsupp;
goto out;
- } else if (error < 0)
+ } else if (host_error < 0)
goto out_nfserr;
- if (pacl) {
- error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
- if (error < 0)
- goto out_nfserr;
- }
+ host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+ if (host_error < 0)
+ goto out_nfserr;
- if (dpacl) {
- error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
- if (error < 0)
+ if (S_ISDIR(inode->i_mode)) {
+ host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
+ if (host_error < 0)
goto out_nfserr;
}
@@ -456,7 +467,7 @@ out:
posix_acl_release(dpacl);
return (error);
out_nfserr:
- error = nfserrno(error);
+ error = nfserrno(host_error);
goto out;
}
@@ -563,14 +574,14 @@ static struct accessmap nfs3_anyaccess[] = {
{ 0, 0 }
};
-int
+__be32
nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *supported)
{
struct accessmap *map;
struct svc_export *export;
struct dentry *dentry;
u32 query, result = 0, sresult = 0;
- unsigned int error;
+ __be32 error;
error = fh_verify(rqstp, fhp, 0, MAY_NOP);
if (error)
@@ -590,7 +601,7 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
query = *access;
for (; map->access; map++) {
if (map->access & query) {
- unsigned int err2;
+ __be32 err2;
sresult |= map->access;
@@ -629,13 +640,15 @@ nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access, u32 *suppor
* The access argument indicates the type of open (read/write/lock)
* N.B. After this call fhp needs an fh_put
*/
-int
+__be32
nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
int access, struct file **filp)
{
struct dentry *dentry;
struct inode *inode;
- int flags = O_RDONLY|O_LARGEFILE, err;
+ int flags = O_RDONLY|O_LARGEFILE;
+ __be32 err;
+ int host_err;
/*
* If we get here, then the client has already done an "open",
@@ -665,10 +678,10 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
* Check to see if there are any leases on this file.
* This may block while leases are broken.
*/
- err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));
- if (err == -EWOULDBLOCK)
- err = -ETIMEDOUT;
- if (err) /* NOMEM or WOULDBLOCK */
+ host_err = break_lease(inode, O_NONBLOCK | ((access & MAY_WRITE) ? FMODE_WRITE : 0));
+ if (host_err == -EWOULDBLOCK)
+ host_err = -ETIMEDOUT;
+ if (host_err) /* NOMEM or WOULDBLOCK */
goto out_nfserr;
if (access & MAY_WRITE) {
@@ -681,10 +694,9 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
}
*filp = dentry_open(dget(dentry), mntget(fhp->fh_export->ex_mnt), flags);
if (IS_ERR(*filp))
- err = PTR_ERR(*filp);
+ host_err = PTR_ERR(*filp);
out_nfserr:
- if (err)
- err = nfserrno(err);
+ err = nfserrno(host_err);
out:
return err;
}
@@ -743,16 +755,20 @@ nfsd_sync_dir(struct dentry *dp)
* Obtain the readahead parameters for the file
* specified by (dev, ino).
*/
-static DEFINE_SPINLOCK(ra_lock);
static inline struct raparms *
nfsd_get_raparms(dev_t dev, ino_t ino)
{
struct raparms *ra, **rap, **frap = NULL;
int depth = 0;
+ unsigned int hash;
+ struct raparm_hbucket *rab;
+
+ hash = jhash_2words(dev, ino, 0xfeedbeef) & RAPARM_HASH_MASK;
+ rab = &raparm_hash[hash];
- spin_lock(&ra_lock);
- for (rap = &raparm_cache; (ra = *rap); rap = &ra->p_next) {
+ spin_lock(&rab->pb_lock);
+ for (rap = &rab->pb_head; (ra = *rap); rap = &ra->p_next) {
if (ra->p_ino == ino && ra->p_dev == dev)
goto found;
depth++;
@@ -761,7 +777,7 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
}
depth = nfsdstats.ra_size*11/10;
if (!frap) {
- spin_unlock(&ra_lock);
+ spin_unlock(&rab->pb_lock);
return NULL;
}
rap = frap;
@@ -769,15 +785,16 @@ nfsd_get_raparms(dev_t dev, ino_t ino)
ra->p_dev = dev;
ra->p_ino = ino;
ra->p_set = 0;
+ ra->p_hindex = hash;
found:
- if (rap != &raparm_cache) {
+ if (rap != &rab->pb_head) {
*rap = ra->p_next;
- ra->p_next = raparm_cache;
- raparm_cache = ra;
+ ra->p_next = rab->pb_head;
+ rab->pb_head = ra;
}
ra->p_count++;
nfsdstats.ra_depth[depth*10/nfsdstats.ra_size]++;
- spin_unlock(&ra_lock);
+ spin_unlock(&rab->pb_lock);
return ra;
}
@@ -791,36 +808,41 @@ nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset
{
unsigned long count = desc->count;
struct svc_rqst *rqstp = desc->arg.data;
+ struct page **pp = rqstp->rq_respages + rqstp->rq_resused;
if (size > count)
size = count;
if (rqstp->rq_res.page_len == 0) {
get_page(page);
- rqstp->rq_respages[rqstp->rq_resused++] = page;
+ put_page(*pp);
+ *pp = page;
+ rqstp->rq_resused++;
rqstp->rq_res.page_base = offset;
rqstp->rq_res.page_len = size;
- } else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) {
+ } else if (page != pp[-1]) {
get_page(page);
- rqstp->rq_respages[rqstp->rq_resused++] = page;
+ put_page(*pp);
+ *pp = page;
+ rqstp->rq_resused++;
rqstp->rq_res.page_len += size;
- } else {
+ } else
rqstp->rq_res.page_len += size;
- }
desc->count = count - size;
desc->written += size;
return size;
}
-static int
+static __be32
nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, unsigned long *count)
{
struct inode *inode;
struct raparms *ra;
mm_segment_t oldfs;
- int err;
+ __be32 err;
+ int host_err;
err = nfserr_perm;
inode = file->f_dentry->d_inode;
@@ -837,32 +859,33 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
file->f_ra = ra->p_ra;
if (file->f_op->sendfile && rqstp->rq_sendfile_ok) {
- svc_pushback_unused_pages(rqstp);
- err = file->f_op->sendfile(file, &offset, *count,
+ rqstp->rq_resused = 1;
+ host_err = file->f_op->sendfile(file, &offset, *count,
nfsd_read_actor, rqstp);
} else {
oldfs = get_fs();
set_fs(KERNEL_DS);
- err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
+ host_err = vfs_readv(file, (struct iovec __user *)vec, vlen, &offset);
set_fs(oldfs);
}
/* Write back readahead params */
if (ra) {
- spin_lock(&ra_lock);
+ struct raparm_hbucket *rab = &raparm_hash[ra->p_hindex];
+ spin_lock(&rab->pb_lock);
ra->p_ra = file->f_ra;
ra->p_set = 1;
ra->p_count--;
- spin_unlock(&ra_lock);
+ spin_unlock(&rab->pb_lock);
}
- if (err >= 0) {
- nfsdstats.io_read += err;
- *count = err;
+ if (host_err >= 0) {
+ nfsdstats.io_read += host_err;
+ *count = host_err;
err = 0;
fsnotify_access(file->f_dentry);
} else
- err = nfserrno(err);
+ err = nfserrno(host_err);
out:
return err;
}
@@ -877,7 +900,7 @@ static void kill_suid(struct dentry *dentry)
mutex_unlock(&dentry->d_inode->i_mutex);
}
-static int
+static __be32
nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen,
unsigned long cnt, int *stablep)
@@ -886,7 +909,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
struct dentry *dentry;
struct inode *inode;
mm_segment_t oldfs;
- int err = 0;
+ __be32 err = 0;
+ int host_err;
int stable = *stablep;
#ifdef MSNFS
@@ -922,18 +946,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
/* Write the data. */
oldfs = get_fs(); set_fs(KERNEL_DS);
- err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
+ host_err = vfs_writev(file, (struct iovec __user *)vec, vlen, &offset);
set_fs(oldfs);
- if (err >= 0) {
+ if (host_err >= 0) {
nfsdstats.io_write += cnt;
fsnotify_modify(file->f_dentry);
}
/* clear setuid/setgid flag after write */
- if (err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
+ if (host_err >= 0 && (inode->i_mode & (S_ISUID | S_ISGID)))
kill_suid(dentry);
- if (err >= 0 && stable) {
+ if (host_err >= 0 && stable) {
static ino_t last_ino;
static dev_t last_dev;
@@ -959,7 +983,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
if (inode->i_state & I_DIRTY) {
dprintk("nfsd: write sync %d\n", current->pid);
- err=nfsd_sync(file);
+ host_err=nfsd_sync(file);
}
#if 0
wake_up(&inode->i_wait);
@@ -969,11 +993,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
last_dev = inode->i_sb->s_dev;
}
- dprintk("nfsd: write complete err=%d\n", err);
- if (err >= 0)
+ dprintk("nfsd: write complete host_err=%d\n", host_err);
+ if (host_err >= 0)
err = 0;
else
- err = nfserrno(err);
+ err = nfserrno(host_err);
out:
return err;
}
@@ -983,12 +1007,12 @@ out:
* on entry. On return, *count contains the number of bytes actually read.
* N.B. After this call fhp needs an fh_put
*/
-int
+__be32
nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen,
unsigned long *count)
{
- int err;
+ __be32 err;
if (file) {
err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
@@ -1012,12 +1036,12 @@ out:
* The stable flag requests synchronous writes.
* N.B. After this call fhp needs an fh_put
*/
-int
+__be32
nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
loff_t offset, struct kvec *vec, int vlen, unsigned long cnt,
int *stablep)
{
- int err = 0;
+ __be32 err = 0;
if (file) {
err = nfsd_permission(fhp->fh_export, fhp->fh_dentry,
@@ -1049,12 +1073,12 @@ out:
* Unfortunately we cannot lock the file to make sure we return full WCC
* data to the client, as locking happens lower down in the filesystem.
*/
-int
+__be32
nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
loff_t offset, unsigned long count)
{
struct file *file;
- int err;
+ __be32 err;
if ((u64)count > ~(u64)offset)
return nfserr_inval;
@@ -1082,14 +1106,15 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
*
* N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
*/
-int
+__be32
nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
char *fname, int flen, struct iattr *iap,
int type, dev_t rdev, struct svc_fh *resfhp)
{
struct dentry *dentry, *dchild = NULL;
struct inode *dirp;
- int err;
+ __be32 err;
+ int host_err;
err = nfserr_perm;
if (!flen)
@@ -1114,9 +1139,9 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
*/
if (!resfhp->fh_dentry) {
/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
- fh_lock(fhp);
+ fh_lock_nested(fhp, I_MUTEX_PARENT);
dchild = lookup_one_len(fname, dentry, flen);
- err = PTR_ERR(dchild);
+ host_err = PTR_ERR(dchild);
if (IS_ERR(dchild))
goto out_nfserr;
err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
@@ -1155,22 +1180,22 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = nfserr_perm;
switch (type) {
case S_IFREG:
- err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+ host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
break;
case S_IFDIR:
- err = vfs_mkdir(dirp, dchild, iap->ia_mode);
+ host_err = vfs_mkdir(dirp, dchild, iap->ia_mode);
break;
case S_IFCHR:
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
- err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
+ host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
break;
default:
printk("nfsd: bad file type %o in nfsd_create\n", type);
- err = -EINVAL;
+ host_err = -EINVAL;
}
- if (err < 0)
+ if (host_err < 0)
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
@@ -1185,7 +1210,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
* directories via NFS.
*/
if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0) {
- int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
if (err2)
err = err2;
}
@@ -1200,7 +1225,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
goto out;
}
@@ -1208,7 +1233,7 @@ out_nfserr:
/*
* NFSv3 version of nfsd_create
*/
-int
+__be32
nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
char *fname, int flen, struct iattr *iap,
struct svc_fh *resfhp, int createmode, u32 *verifier,
@@ -1216,7 +1241,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
{
struct dentry *dentry, *dchild = NULL;
struct inode *dirp;
- int err;
+ __be32 err;
+ int host_err;
__u32 v_mtime=0, v_atime=0;
int v_mode=0;
@@ -1240,13 +1266,13 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
err = nfserr_notdir;
if(!dirp->i_op || !dirp->i_op->lookup)
goto out;
- fh_lock(fhp);
+ fh_lock_nested(fhp, I_MUTEX_PARENT);
/*
* Compose the response file handle.
*/
dchild = lookup_one_len(fname, dentry, flen);
- err = PTR_ERR(dchild);
+ host_err = PTR_ERR(dchild);
if (IS_ERR(dchild))
goto out_nfserr;
@@ -1302,8 +1328,8 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
goto out;
}
- err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
- if (err < 0)
+ host_err = vfs_create(dirp, dchild, iap->ia_mode, NULL);
+ if (host_err < 0)
goto out_nfserr;
if (EX_ISSYNC(fhp->fh_export)) {
@@ -1332,7 +1358,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
*/
set_attr:
if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID)) != 0) {
- int err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
+ __be32 err2 = nfsd_setattr(rqstp, resfhp, iap, 0, (time_t)0);
if (err2)
err = err2;
}
@@ -1350,7 +1376,7 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
return err;
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
goto out;
}
#endif /* CONFIG_NFSD_V3 */
@@ -1360,13 +1386,14 @@ nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
* fits into the buffer. On return, it contains the true length.
* N.B. After this call fhp needs an fh_put
*/
-int
+__be32
nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
{
struct dentry *dentry;
struct inode *inode;
mm_segment_t oldfs;
- int err;
+ __be32 err;
+ int host_err;
err = fh_verify(rqstp, fhp, S_IFLNK, MAY_NOP);
if (err)
@@ -1385,18 +1412,18 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)
*/
oldfs = get_fs(); set_fs(KERNEL_DS);
- err = inode->i_op->readlink(dentry, buf, *lenp);
+ host_err = inode->i_op->readlink(dentry, buf, *lenp);
set_fs(oldfs);
- if (err < 0)
+ if (host_err < 0)
goto out_nfserr;
- *lenp = err;
+ *lenp = host_err;
err = 0;
out:
return err;
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
goto out;
}
@@ -1404,7 +1431,7 @@ out_nfserr:
* Create a symlink and look up its inode
* N.B. After this call _both_ fhp and resfhp need an fh_put
*/
-int
+__be32
nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
char *fname, int flen,
char *path, int plen,
@@ -1412,7 +1439,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct iattr *iap)
{
struct dentry *dentry, *dnew;
- int err, cerr;
+ __be32 err, cerr;
+ int host_err;
umode_t mode;
err = nfserr_noent;
@@ -1428,7 +1456,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
fh_lock(fhp);
dentry = fhp->fh_dentry;
dnew = lookup_one_len(fname, dentry, flen);
- err = PTR_ERR(dnew);
+ host_err = PTR_ERR(dnew);
if (IS_ERR(dnew))
goto out_nfserr;
@@ -1440,21 +1468,21 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
if (unlikely(path[plen] != 0)) {
char *path_alloced = kmalloc(plen+1, GFP_KERNEL);
if (path_alloced == NULL)
- err = -ENOMEM;
+ host_err = -ENOMEM;
else {
strncpy(path_alloced, path, plen);
path_alloced[plen] = 0;
- err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
+ host_err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode);
kfree(path_alloced);
}
} else
- err = vfs_symlink(dentry->d_inode, dnew, path, mode);
+ host_err = vfs_symlink(dentry->d_inode, dnew, path, mode);
- if (!err)
+ if (!host_err) {
if (EX_ISSYNC(fhp->fh_export))
- err = nfsd_sync_dir(dentry);
- if (err)
- err = nfserrno(err);
+ host_err = nfsd_sync_dir(dentry);
+ }
+ err = nfserrno(host_err);
fh_unlock(fhp);
cerr = fh_compose(resfhp, fhp->fh_export, dnew, fhp);
@@ -1464,7 +1492,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
goto out;
}
@@ -1472,13 +1500,14 @@ out_nfserr:
* Create a hardlink
* N.B. After this call _both_ ffhp and tfhp need an fh_put
*/
-int
+__be32
nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
char *name, int len, struct svc_fh *tfhp)
{
struct dentry *ddir, *dnew, *dold;
struct inode *dirp, *dest;
- int err;
+ __be32 err;
+ int host_err;
err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);
if (err)
@@ -1494,29 +1523,30 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
if (isdotent(name, len))
goto out;
- fh_lock(ffhp);
+ fh_lock_nested(ffhp, I_MUTEX_PARENT);
ddir = ffhp->fh_dentry;
dirp = ddir->d_inode;
dnew = lookup_one_len(name, ddir, len);
- err = PTR_ERR(dnew);
+ host_err = PTR_ERR(dnew);
if (IS_ERR(dnew))
goto out_nfserr;
dold = tfhp->fh_dentry;
dest = dold->d_inode;
- err = vfs_link(dold, dirp, dnew);
- if (!err) {
+ host_err = vfs_link(dold, dirp, dnew);
+ if (!host_err) {
if (EX_ISSYNC(ffhp->fh_export)) {
err = nfserrno(nfsd_sync_dir(ddir));
write_inode_now(dest, 1);
}
+ err = 0;
} else {
- if (err == -EXDEV && rqstp->rq_vers == 2)
+ if (host_err == -EXDEV && rqstp->rq_vers == 2)
err = nfserr_acces;
else
- err = nfserrno(err);
+ err = nfserrno(host_err);
}
dput(dnew);
@@ -1526,7 +1556,7 @@ out:
return err;
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
goto out_unlock;
}
@@ -1534,13 +1564,14 @@ out_nfserr:
* Rename a file
* N.B. After this call _both_ ffhp and tfhp need an fh_put
*/
-int
+__be32
nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
struct svc_fh *tfhp, char *tname, int tlen)
{
struct dentry *fdentry, *tdentry, *odentry, *ndentry, *trap;
struct inode *fdir, *tdir;
- int err;
+ __be32 err;
+ int host_err;
err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE);
if (err)
@@ -1571,22 +1602,22 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
fill_pre_wcc(tfhp);
odentry = lookup_one_len(fname, fdentry, flen);
- err = PTR_ERR(odentry);
+ host_err = PTR_ERR(odentry);
if (IS_ERR(odentry))
goto out_nfserr;
- err = -ENOENT;
+ host_err = -ENOENT;
if (!odentry->d_inode)
goto out_dput_old;
- err = -EINVAL;
+ host_err = -EINVAL;
if (odentry == trap)
goto out_dput_old;
ndentry = lookup_one_len(tname, tdentry, tlen);
- err = PTR_ERR(ndentry);
+ host_err = PTR_ERR(ndentry);
if (IS_ERR(ndentry))
goto out_dput_old;
- err = -ENOTEMPTY;
+ host_err = -ENOTEMPTY;
if (ndentry == trap)
goto out_dput_new;
@@ -1594,14 +1625,14 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if ((ffhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
((atomic_read(&odentry->d_count) > 1)
|| (atomic_read(&ndentry->d_count) > 1))) {
- err = -EPERM;
+ host_err = -EPERM;
} else
#endif
- err = vfs_rename(fdir, odentry, tdir, ndentry);
- if (!err && EX_ISSYNC(tfhp->fh_export)) {
- err = nfsd_sync_dir(tdentry);
- if (!err)
- err = nfsd_sync_dir(fdentry);
+ host_err = vfs_rename(fdir, odentry, tdir, ndentry);
+ if (!host_err && EX_ISSYNC(tfhp->fh_export)) {
+ host_err = nfsd_sync_dir(tdentry);
+ if (!host_err)
+ host_err = nfsd_sync_dir(fdentry);
}
out_dput_new:
@@ -1609,8 +1640,7 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
out_dput_old:
dput(odentry);
out_nfserr:
- if (err)
- err = nfserrno(err);
+ err = nfserrno(host_err);
/* we cannot reply on fh_unlock on the two filehandles,
* as that would do the wrong thing if the two directories
@@ -1629,13 +1659,14 @@ out:
* Unlink a file or directory
* N.B. After this call fhp needs an fh_put
*/
-int
+__be32
nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
char *fname, int flen)
{
struct dentry *dentry, *rdentry;
struct inode *dirp;
- int err;
+ __be32 err;
+ int host_err;
err = nfserr_acces;
if (!flen || isdotent(fname, flen))
@@ -1644,12 +1675,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (err)
goto out;
- fh_lock(fhp);
+ fh_lock_nested(fhp, I_MUTEX_PARENT);
dentry = fhp->fh_dentry;
dirp = dentry->d_inode;
rdentry = lookup_one_len(fname, dentry, flen);
- err = PTR_ERR(rdentry);
+ host_err = PTR_ERR(rdentry);
if (IS_ERR(rdentry))
goto out_nfserr;
@@ -1666,22 +1697,23 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
#ifdef MSNFS
if ((fhp->fh_export->ex_flags & NFSEXP_MSNFS) &&
(atomic_read(&rdentry->d_count) > 1)) {
- err = -EPERM;
+ host_err = -EPERM;
} else
#endif
- err = vfs_unlink(dirp, rdentry);
+ host_err = vfs_unlink(dirp, rdentry);
} else { /* It's RMDIR */
- err = vfs_rmdir(dirp, rdentry);
+ host_err = vfs_rmdir(dirp, rdentry);
}
dput(rdentry);
- if (err == 0 &&
- EX_ISSYNC(fhp->fh_export))
- err = nfsd_sync_dir(dentry);
+ if (host_err)
+ goto out_nfserr;
+ if (EX_ISSYNC(fhp->fh_export))
+ host_err = nfsd_sync_dir(dentry);
out_nfserr:
- err = nfserrno(err);
+ err = nfserrno(host_err);
out:
return err;
}
@@ -1690,11 +1722,12 @@ out:
* Read entries from a directory.
* The NFSv3/4 verifier we ignore for now.
*/
-int
+__be32
nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
struct readdir_cd *cdp, encode_dent_fn func)
{
- int err;
+ __be32 err;
+ int host_err;
struct file *file;
loff_t offset = *offsetp;
@@ -1716,10 +1749,10 @@ nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
do {
cdp->err = nfserr_eof; /* will be cleared on successful read */
- err = vfs_readdir(file, (filldir_t) func, cdp);
- } while (err >=0 && cdp->err == nfs_ok);
- if (err)
- err = nfserrno(err);
+ host_err = vfs_readdir(file, (filldir_t) func, cdp);
+ } while (host_err >=0 && cdp->err == nfs_ok);
+ if (host_err)
+ err = nfserrno(host_err);
else
err = cdp->err;
*offsetp = vfs_llseek(file, 0, 1);
@@ -1736,10 +1769,10 @@ out:
* Get file system stats
* N.B. After this call fhp needs an fh_put
*/
-int
+__be32
nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
{
- int err = fh_verify(rqstp, fhp, 0, MAY_NOP);
+ __be32 err = fh_verify(rqstp, fhp, 0, MAY_NOP);
if (!err && vfs_statfs(fhp->fh_dentry,stat))
err = nfserr_io;
return err;
@@ -1748,7 +1781,7 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat)
/*
* Check for a user's access permissions to this inode.
*/
-int
+__be32
nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
{
struct inode *inode = dentry->d_inode;
@@ -1829,11 +1862,11 @@ nfsd_permission(struct svc_export *exp, struct dentry *dentry, int acc)
void
nfsd_racache_shutdown(void)
{
- if (!raparm_cache)
+ if (!raparml)
return;
dprintk("nfsd: freeing readahead buffers.\n");
kfree(raparml);
- raparm_cache = raparml = NULL;
+ raparml = NULL;
}
/*
* Initialize readahead param cache
@@ -1842,19 +1875,31 @@ int
nfsd_racache_init(int cache_size)
{
int i;
+ int j = 0;
+ int nperbucket;
+
- if (raparm_cache)
+ if (raparml)
return 0;
+ if (cache_size < 2*RAPARM_HASH_SIZE)
+ cache_size = 2*RAPARM_HASH_SIZE;
raparml = kmalloc(sizeof(struct raparms) * cache_size, GFP_KERNEL);
if (raparml != NULL) {
dprintk("nfsd: allocating %d readahead buffers.\n",
cache_size);
+ for (i = 0 ; i < RAPARM_HASH_SIZE ; i++) {
+ raparm_hash[i].pb_head = NULL;
+ spin_lock_init(&raparm_hash[i].pb_lock);
+ }
+ nperbucket = cache_size >> RAPARM_HASH_BITS;
memset(raparml, 0, sizeof(struct raparms) * cache_size);
for (i = 0; i < cache_size - 1; i++) {
- raparml[i].p_next = raparml + i + 1;
+ if (i % nperbucket == 0)
+ raparm_hash[j++].pb_head = raparml + i;
+ if (i % nperbucket < nperbucket-1)
+ raparml[i].p_next = raparml + i + 1;
}
- raparm_cache = raparml;
} else {
printk(KERN_WARNING
"nfsd: Could not allocate memory read-ahead cache.\n");
diff --git a/fs/nls/nls_ascii.c b/fs/nls/nls_ascii.c
index b83381c07ad6..6993faea28ac 100644
--- a/fs/nls/nls_ascii.c
+++ b/fs/nls/nls_ascii.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_ascii.c
+ * linux/fs/nls/nls_ascii.c
*
* Charset ascii translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 9de6b495f112..7dfdab98729b 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_base.c
+ * linux/fs/nls/nls_base.c
*
* Native language support--charsets and unicode translations.
* By Gordon Chaffee 1996, 1997
@@ -163,8 +163,6 @@ int register_nls(struct nls_table * nls)
{
struct nls_table ** tmp = &tables;
- if (!nls)
- return -EINVAL;
if (nls->next)
return -EBUSY;
diff --git a/fs/nls/nls_cp1250.c b/fs/nls/nls_cp1250.c
index 32e78cf95180..570aa69846a0 100644
--- a/fs/nls/nls_cp1250.c
+++ b/fs/nls/nls_cp1250.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp1250.c
+ * linux/fs/nls/nls_cp1250.c
*
* Charset cp1250 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp1251.c b/fs/nls/nls_cp1251.c
index cb41c8ae4486..f114afa069db 100644
--- a/fs/nls/nls_cp1251.c
+++ b/fs/nls/nls_cp1251.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp1251.c
+ * linux/fs/nls/nls_cp1251.c
*
* Charset cp1251 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp1255.c b/fs/nls/nls_cp1255.c
index efdeefee5346..e57f2cbf5bc0 100644
--- a/fs/nls/nls_cp1255.c
+++ b/fs/nls/nls_cp1255.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp1255.c
+ * linux/fs/nls/nls_cp1255.c
*
* Charset cp1255 translation tables.
* The Unicode to charset table has only exact mappings.
diff --git a/fs/nls/nls_cp437.c b/fs/nls/nls_cp437.c
index 5c4a1cd685dd..d41930ce4a44 100644
--- a/fs/nls/nls_cp437.c
+++ b/fs/nls/nls_cp437.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp437.c
+ * linux/fs/nls/nls_cp437.c
*
* Charset cp437 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp737.c b/fs/nls/nls_cp737.c
index e8b3ca8462e7..d21f8790aa19 100644
--- a/fs/nls/nls_cp737.c
+++ b/fs/nls/nls_cp737.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp737.c
+ * linux/fs/nls/nls_cp737.c
*
* Charset cp737 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp775.c b/fs/nls/nls_cp775.c
index bdb290ea523a..c97714c38a90 100644
--- a/fs/nls/nls_cp775.c
+++ b/fs/nls/nls_cp775.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp775.c
+ * linux/fs/nls/nls_cp775.c
*
* Charset cp775 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp850.c b/fs/nls/nls_cp850.c
index 25deaa4c8648..843b7d975ba2 100644
--- a/fs/nls/nls_cp850.c
+++ b/fs/nls/nls_cp850.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp850.c
+ * linux/fs/nls/nls_cp850.c
*
* Charset cp850 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp852.c b/fs/nls/nls_cp852.c
index b822a7b6b970..83cfd844d5ca 100644
--- a/fs/nls/nls_cp852.c
+++ b/fs/nls/nls_cp852.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp852.c
+ * linux/fs/nls/nls_cp852.c
*
* Charset cp852 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp855.c b/fs/nls/nls_cp855.c
index e8641b7a8b27..9190b7b574ff 100644
--- a/fs/nls/nls_cp855.c
+++ b/fs/nls/nls_cp855.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp855.c
+ * linux/fs/nls/nls_cp855.c
*
* Charset cp855 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp857.c b/fs/nls/nls_cp857.c
index 7ba589ef8cc0..ef3d36db8082 100644
--- a/fs/nls/nls_cp857.c
+++ b/fs/nls/nls_cp857.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp857.c
+ * linux/fs/nls/nls_cp857.c
*
* Charset cp857 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp860.c b/fs/nls/nls_cp860.c
index 3b9e49ce8c80..7e2fb6645893 100644
--- a/fs/nls/nls_cp860.c
+++ b/fs/nls/nls_cp860.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp860.c
+ * linux/fs/nls/nls_cp860.c
*
* Charset cp860 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp861.c b/fs/nls/nls_cp861.c
index 959ff64ee971..66d8d808ccf1 100644
--- a/fs/nls/nls_cp861.c
+++ b/fs/nls/nls_cp861.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp861.c
+ * linux/fs/nls/nls_cp861.c
*
* Charset cp861 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp862.c b/fs/nls/nls_cp862.c
index b96928f5a023..360ba388485f 100644
--- a/fs/nls/nls_cp862.c
+++ b/fs/nls/nls_cp862.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp862.c
+ * linux/fs/nls/nls_cp862.c
*
* Charset cp862 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp863.c b/fs/nls/nls_cp863.c
index baa6e0eab1d6..656a93113e37 100644
--- a/fs/nls/nls_cp863.c
+++ b/fs/nls/nls_cp863.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp863.c
+ * linux/fs/nls/nls_cp863.c
*
* Charset cp863 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp864.c b/fs/nls/nls_cp864.c
index f4dabb037dfe..01ca7309753e 100644
--- a/fs/nls/nls_cp864.c
+++ b/fs/nls/nls_cp864.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp864.c
+ * linux/fs/nls/nls_cp864.c
*
* Charset cp864 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp865.c b/fs/nls/nls_cp865.c
index 4caeafae32c2..5ba6ee13e109 100644
--- a/fs/nls/nls_cp865.c
+++ b/fs/nls/nls_cp865.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp865.c
+ * linux/fs/nls/nls_cp865.c
*
* Charset cp865 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp866.c b/fs/nls/nls_cp866.c
index f2b4a9a293fb..c5f82221c9fe 100644
--- a/fs/nls/nls_cp866.c
+++ b/fs/nls/nls_cp866.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp866.c
+ * linux/fs/nls/nls_cp866.c
*
* Charset cp866 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp869.c b/fs/nls/nls_cp869.c
index 12b436f4eca1..8d4015124d11 100644
--- a/fs/nls/nls_cp869.c
+++ b/fs/nls/nls_cp869.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp869.c
+ * linux/fs/nls/nls_cp869.c
*
* Charset cp869 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp874.c b/fs/nls/nls_cp874.c
index b5766a01703a..df042052c2db 100644
--- a/fs/nls/nls_cp874.c
+++ b/fs/nls/nls_cp874.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp874.c
+ * linux/fs/nls/nls_cp874.c
*
* Charset cp874 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_cp932.c b/fs/nls/nls_cp932.c
index 2c1a17cdcd24..2a9ccf3bc7ef 100644
--- a/fs/nls/nls_cp932.c
+++ b/fs/nls/nls_cp932.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp932.c
+ * linux/fs/nls/nls_cp932.c
*
* Charset cp932 translation tables.
* This translation table was generated automatically, the
diff --git a/fs/nls/nls_cp936.c b/fs/nls/nls_cp936.c
index ef4cef464aba..046fde8170ea 100644
--- a/fs/nls/nls_cp936.c
+++ b/fs/nls/nls_cp936.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp936.c
+ * linux/fs/nls/nls_cp936.c
*
* Charset cp936 translation tables.
* This translation table was generated automatically, the
diff --git a/fs/nls/nls_cp949.c b/fs/nls/nls_cp949.c
index 4351ae21d897..92ae19372f0f 100644
--- a/fs/nls/nls_cp949.c
+++ b/fs/nls/nls_cp949.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp949.c
+ * linux/fs/nls/nls_cp949.c
*
* Charset cp949 translation tables.
* This translation table was generated automatically, the
diff --git a/fs/nls/nls_cp950.c b/fs/nls/nls_cp950.c
index 8167a2858879..5665945fb88c 100644
--- a/fs/nls/nls_cp950.c
+++ b/fs/nls/nls_cp950.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_cp950.c
+ * linux/fs/nls/nls_cp950.c
*
* Charset cp950 translation tables.
* This translation table was generated automatically, the
diff --git a/fs/nls/nls_euc-jp.c b/fs/nls/nls_euc-jp.c
index 06640c3e4021..73293511578b 100644
--- a/fs/nls/nls_euc-jp.c
+++ b/fs/nls/nls_euc-jp.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_euc-jp.c
+ * linux/fs/nls/nls_euc-jp.c
*
* Added `OSF/JVC Recommended Code Set Conversion Specification
* between Japanese EUC and Shift-JIS' support: <hirofumi@mail.parknet.co.jp>
diff --git a/fs/nls/nls_iso8859-1.c b/fs/nls/nls_iso8859-1.c
index 70a2c1956723..2483c3c6c1c1 100644
--- a/fs/nls/nls_iso8859-1.c
+++ b/fs/nls/nls_iso8859-1.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-1.c
+ * linux/fs/nls/nls_iso8859-1.c
*
* Charset iso8859-1 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_iso8859-13.c b/fs/nls/nls_iso8859-13.c
index 4547035f21a3..7b8721d74368 100644
--- a/fs/nls/nls_iso8859-13.c
+++ b/fs/nls/nls_iso8859-13.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-13.c
+ * linux/fs/nls/nls_iso8859-13.c
*
* Charset iso8859-13 translation tables.
* The Unicode to charset table has only exact mappings.
diff --git a/fs/nls/nls_iso8859-14.c b/fs/nls/nls_iso8859-14.c
index 13628d0dd3a9..2e895e638dba 100644
--- a/fs/nls/nls_iso8859-14.c
+++ b/fs/nls/nls_iso8859-14.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-14.c
+ * linux/fs/nls/nls_iso8859-14.c
*
* Charset iso8859-14 translation tables.
*
diff --git a/fs/nls/nls_iso8859-15.c b/fs/nls/nls_iso8859-15.c
index 88b924bf7e18..5c91592779fe 100644
--- a/fs/nls/nls_iso8859-15.c
+++ b/fs/nls/nls_iso8859-15.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-15.c
+ * linux/fs/nls/nls_iso8859-15.c
*
* Charset iso8859-15 translation tables.
* The Unicode to charset table has only exact mappings.
diff --git a/fs/nls/nls_iso8859-2.c b/fs/nls/nls_iso8859-2.c
index 372528a6c40c..892d38fe9530 100644
--- a/fs/nls/nls_iso8859-2.c
+++ b/fs/nls/nls_iso8859-2.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-2.c
+ * linux/fs/nls/nls_iso8859-2.c
*
* Charset iso8859-2 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_iso8859-3.c b/fs/nls/nls_iso8859-3.c
index 81b45a234369..49317bcdb4be 100644
--- a/fs/nls/nls_iso8859-3.c
+++ b/fs/nls/nls_iso8859-3.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-3.c
+ * linux/fs/nls/nls_iso8859-3.c
*
* Charset iso8859-3 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_iso8859-4.c b/fs/nls/nls_iso8859-4.c
index 101b87f5a49b..9f3b9368c2cf 100644
--- a/fs/nls/nls_iso8859-4.c
+++ b/fs/nls/nls_iso8859-4.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-4.c
+ * linux/fs/nls/nls_iso8859-4.c
*
* Charset iso8859-4 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_iso8859-5.c b/fs/nls/nls_iso8859-5.c
index 83b0084de5eb..001a2bb132ce 100644
--- a/fs/nls/nls_iso8859-5.c
+++ b/fs/nls/nls_iso8859-5.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-5.c
+ * linux/fs/nls/nls_iso8859-5.c
*
* Charset iso8859-5 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_iso8859-6.c b/fs/nls/nls_iso8859-6.c
index 0c519d65f55b..8cec03d66088 100644
--- a/fs/nls/nls_iso8859-6.c
+++ b/fs/nls/nls_iso8859-6.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-6.c
+ * linux/fs/nls/nls_iso8859-6.c
*
* Charset iso8859-6 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_iso8859-7.c b/fs/nls/nls_iso8859-7.c
index bd0854625acf..1be707d5ac31 100644
--- a/fs/nls/nls_iso8859-7.c
+++ b/fs/nls/nls_iso8859-7.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-7.c
+ * linux/fs/nls/nls_iso8859-7.c
*
* Charset iso8859-7 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_iso8859-9.c b/fs/nls/nls_iso8859-9.c
index 988eff791c06..8c0146f73834 100644
--- a/fs/nls/nls_iso8859-9.c
+++ b/fs/nls/nls_iso8859-9.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_iso8859-9.c
+ * linux/fs/nls/nls_iso8859-9.c
*
* Charset iso8859-9 translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_koi8-r.c b/fs/nls/nls_koi8-r.c
index 0ad22c249796..fefbe0807265 100644
--- a/fs/nls/nls_koi8-r.c
+++ b/fs/nls/nls_koi8-r.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_koi8-r.c
+ * linux/fs/nls/nls_koi8-r.c
*
* Charset koi8-r translation tables.
* Generated automatically from the Unicode and charset
diff --git a/fs/nls/nls_koi8-ru.c b/fs/nls/nls_koi8-ru.c
index 5db83efe27c6..e7bc1d75c78c 100644
--- a/fs/nls/nls_koi8-ru.c
+++ b/fs/nls/nls_koi8-ru.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_koi8-ru.c
+ * linux/fs/nls/nls_koi8-ru.c
*
* Charset koi8-ru translation based on charset koi8-u.
* The Unicode to charset table has only exact mappings.
diff --git a/fs/nls/nls_koi8-u.c b/fs/nls/nls_koi8-u.c
index 9d30fd61cf46..015070211f22 100644
--- a/fs/nls/nls_koi8-u.c
+++ b/fs/nls/nls_koi8-u.c
@@ -1,5 +1,5 @@
/*
- * linux/fs/nls_koi8-u.c
+ * linux/fs/nls/nls_koi8-u.c
*
* Charset koi8-u translation tables.
* The Unicode to charset table has only exact mappings.
diff --git a/fs/no-block.c b/fs/no-block.c
new file mode 100644
index 000000000000..d269a93d3467
--- /dev/null
+++ b/fs/no-block.c
@@ -0,0 +1,22 @@
+/* no-block.c: implementation of routines required for non-BLOCK configuration
+ *
+ * Copyright (C) 2006 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/kernel.h>
+#include <linux/fs.h>
+
+static int no_blkdev_open(struct inode * inode, struct file * filp)
+{
+ return -ENODEV;
+}
+
+const struct file_operations def_blk_fops = {
+ .open = no_blkdev_open,
+};
diff --git a/fs/ntfs/aops.c b/fs/ntfs/aops.c
index bc579bfdfbd8..7b2c8f4f6a6f 100644
--- a/fs/ntfs/aops.c
+++ b/fs/ntfs/aops.c
@@ -254,7 +254,7 @@ static int ntfs_read_block(struct page *page)
bh->b_bdev = vol->sb->s_bdev;
/* Is the block within the allowed limits? */
if (iblock < lblock) {
- BOOL is_retry = FALSE;
+ bool is_retry = false;
/* Convert iblock into corresponding vcn and offset. */
vcn = (VCN)iblock << blocksize_bits >>
@@ -292,7 +292,7 @@ lock_retry_remap:
goto handle_hole;
/* If first try and runlist unmapped, map and retry. */
if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
- is_retry = TRUE;
+ is_retry = true;
/*
* Attempt to map runlist, dropping lock for
* the duration.
@@ -558,7 +558,7 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc)
unsigned long flags;
unsigned int blocksize, vcn_ofs;
int err;
- BOOL need_end_writeback;
+ bool need_end_writeback;
unsigned char blocksize_bits;
vi = page->mapping->host;
@@ -626,7 +626,7 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc)
rl = NULL;
err = 0;
do {
- BOOL is_retry = FALSE;
+ bool is_retry = false;
if (unlikely(block >= dblock)) {
/*
@@ -768,7 +768,7 @@ lock_retry_remap:
}
/* If first try and runlist unmapped, map and retry. */
if (!is_retry && lcn == LCN_RL_NOT_MAPPED) {
- is_retry = TRUE;
+ is_retry = true;
/*
* Attempt to map runlist, dropping lock for
* the duration.
@@ -874,12 +874,12 @@ lock_retry_remap:
set_page_writeback(page); /* Keeps try_to_free_buffers() away. */
/* Submit the prepared buffers for i/o. */
- need_end_writeback = TRUE;
+ need_end_writeback = true;
do {
struct buffer_head *next = bh->b_this_page;
if (buffer_async_write(bh)) {
submit_bh(WRITE, bh);
- need_end_writeback = FALSE;
+ need_end_writeback = false;
}
bh = next;
} while (bh != head);
@@ -932,7 +932,7 @@ static int ntfs_write_mst_block(struct page *page,
runlist_element *rl;
int i, nr_locked_nis, nr_recs, nr_bhs, max_bhs, bhs_per_rec, err, err2;
unsigned bh_size, rec_size_bits;
- BOOL sync, is_mft, page_is_dirty, rec_is_dirty;
+ bool sync, is_mft, page_is_dirty, rec_is_dirty;
unsigned char bh_size_bits;
ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
@@ -975,10 +975,10 @@ static int ntfs_write_mst_block(struct page *page,
rl = NULL;
err = err2 = nr_bhs = nr_recs = nr_locked_nis = 0;
- page_is_dirty = rec_is_dirty = FALSE;
+ page_is_dirty = rec_is_dirty = false;
rec_start_bh = NULL;
do {
- BOOL is_retry = FALSE;
+ bool is_retry = false;
if (likely(block < rec_block)) {
if (unlikely(block >= dblock)) {
@@ -1009,10 +1009,10 @@ static int ntfs_write_mst_block(struct page *page,
}
if (!buffer_dirty(bh)) {
/* Clean records are not written out. */
- rec_is_dirty = FALSE;
+ rec_is_dirty = false;
continue;
}
- rec_is_dirty = TRUE;
+ rec_is_dirty = true;
rec_start_bh = bh;
}
/* Need to map the buffer if it is not mapped already. */
@@ -1053,7 +1053,7 @@ lock_retry_remap:
*/
if (!is_mft && !is_retry &&
lcn == LCN_RL_NOT_MAPPED) {
- is_retry = TRUE;
+ is_retry = true;
/*
* Attempt to map runlist, dropping
* lock for the duration.
@@ -1063,7 +1063,7 @@ lock_retry_remap:
if (likely(!err2))
goto lock_retry_remap;
if (err2 == -ENOMEM)
- page_is_dirty = TRUE;
+ page_is_dirty = true;
lcn = err2;
} else {
err2 = -EIO;
@@ -1145,7 +1145,7 @@ lock_retry_remap:
* means we need to redirty the page before
* returning.
*/
- page_is_dirty = TRUE;
+ page_is_dirty = true;
/*
* Remove the buffers in this mft record from
* the list of buffers to write.
diff --git a/fs/ntfs/aops.h b/fs/ntfs/aops.h
index 325ce261a107..9393f4b1e298 100644
--- a/fs/ntfs/aops.h
+++ b/fs/ntfs/aops.h
@@ -80,7 +80,7 @@ static inline void ntfs_unmap_page(struct page *page)
*
* The unlocked and uptodate page is returned on success or an encoded error
* on failure. Caller has to test for error using the IS_ERR() macro on the
- * return value. If that evaluates to TRUE, the negative error code can be
+ * return value. If that evaluates to 'true', the negative error code can be
* obtained using PTR_ERR() on the return value of ntfs_map_page().
*/
static inline struct page *ntfs_map_page(struct address_space *mapping,
diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c
index 6708e1d68a9e..9f08e851cfb6 100644
--- a/fs/ntfs/attrib.c
+++ b/fs/ntfs/attrib.c
@@ -67,7 +67,7 @@
* the attribute has zero allocated size, i.e. there simply is no runlist.
*
* WARNING: If @ctx is supplied, regardless of whether success or failure is
- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
+ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
* is no longer valid, i.e. you need to either call
* ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
* In that case PTR_ERR(@ctx->mrec) will give you the error code for
@@ -90,7 +90,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
runlist_element *rl;
struct page *put_this_page = NULL;
int err = 0;
- BOOL ctx_is_temporary, ctx_needs_reset;
+ bool ctx_is_temporary, ctx_needs_reset;
ntfs_attr_search_ctx old_ctx = { NULL, };
ntfs_debug("Mapping runlist part containing vcn 0x%llx.",
@@ -100,7 +100,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
else
base_ni = ni->ext.base_ntfs_ino;
if (!ctx) {
- ctx_is_temporary = ctx_needs_reset = TRUE;
+ ctx_is_temporary = ctx_needs_reset = true;
m = map_mft_record(base_ni);
if (IS_ERR(m))
return PTR_ERR(m);
@@ -115,7 +115,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
BUG_ON(IS_ERR(ctx->mrec));
a = ctx->attr;
BUG_ON(!a->non_resident);
- ctx_is_temporary = FALSE;
+ ctx_is_temporary = false;
end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn);
read_lock_irqsave(&ni->size_lock, flags);
allocated_size_vcn = ni->allocated_size >>
@@ -136,7 +136,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
ni->name, ni->name_len) &&
sle64_to_cpu(a->data.non_resident.lowest_vcn)
<= vcn && end_vcn >= vcn))
- ctx_needs_reset = FALSE;
+ ctx_needs_reset = false;
else {
/* Save the old search context. */
old_ctx = *ctx;
@@ -158,7 +158,7 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx)
* needed attribute extent.
*/
ntfs_attr_reinit_search_ctx(ctx);
- ctx_needs_reset = TRUE;
+ ctx_needs_reset = true;
}
}
if (ctx_needs_reset) {
@@ -336,16 +336,16 @@ int ntfs_map_runlist(ntfs_inode *ni, VCN vcn)
* LCN_EIO Critical error (runlist/file is corrupt, i/o error, etc).
*
* Locking: - The runlist must be locked on entry and is left locked on return.
- * - If @write_locked is FALSE, i.e. the runlist is locked for reading,
+ * - If @write_locked is 'false', i.e. the runlist is locked for reading,
* the lock may be dropped inside the function so you cannot rely on
* the runlist still being the same when this function returns.
*/
LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
- const BOOL write_locked)
+ const bool write_locked)
{
LCN lcn;
unsigned long flags;
- BOOL is_retry = FALSE;
+ bool is_retry = false;
ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.",
ni->mft_no, (unsigned long long)vcn,
@@ -390,7 +390,7 @@ retry_remap:
down_read(&ni->runlist.lock);
}
if (likely(!err)) {
- is_retry = TRUE;
+ is_retry = true;
goto retry_remap;
}
if (err == -ENOENT)
@@ -449,7 +449,7 @@ retry_remap:
* -EIO - Critical error (runlist/file is corrupt, i/o error, etc).
*
* WARNING: If @ctx is supplied, regardless of whether success or failure is
- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
+ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
* is no longer valid, i.e. you need to either call
* ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
* In that case PTR_ERR(@ctx->mrec) will give you the error code for
@@ -469,7 +469,7 @@ runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn,
unsigned long flags;
runlist_element *rl;
int err = 0;
- BOOL is_retry = FALSE;
+ bool is_retry = false;
ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.",
ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out");
@@ -518,7 +518,7 @@ retry_remap:
*/
err = ntfs_map_runlist_nolock(ni, vcn, ctx);
if (likely(!err)) {
- is_retry = TRUE;
+ is_retry = true;
goto retry_remap;
}
}
@@ -558,8 +558,8 @@ retry_remap:
* On actual error, ntfs_attr_find() returns -EIO. In this case @ctx->attr is
* undefined and in particular do not rely on it not changing.
*
- * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it
- * is FALSE, the search begins after @ctx->attr.
+ * If @ctx->is_first is 'true', the search begins with @ctx->attr itself. If it
+ * is 'false', the search begins after @ctx->attr.
*
* If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and
* @ctx->ntfs_ino must be set to the ntfs inode to which the mft record
@@ -599,11 +599,11 @@ static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name,
/*
* Iterate over attributes in mft record starting at @ctx->attr, or the
- * attribute following that, if @ctx->is_first is TRUE.
+ * attribute following that, if @ctx->is_first is 'true'.
*/
if (ctx->is_first) {
a = ctx->attr;
- ctx->is_first = FALSE;
+ ctx->is_first = false;
} else
a = (ATTR_RECORD*)((u8*)ctx->attr +
le32_to_cpu(ctx->attr->length));
@@ -890,11 +890,11 @@ static int ntfs_external_attr_find(const ATTR_TYPE type,
ctx->al_entry = (ATTR_LIST_ENTRY*)al_start;
/*
* Iterate over entries in attribute list starting at @ctx->al_entry,
- * or the entry following that, if @ctx->is_first is TRUE.
+ * or the entry following that, if @ctx->is_first is 'true'.
*/
if (ctx->is_first) {
al_entry = ctx->al_entry;
- ctx->is_first = FALSE;
+ ctx->is_first = false;
} else
al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry +
le16_to_cpu(ctx->al_entry->length));
@@ -1127,7 +1127,7 @@ not_found:
ctx->mrec = ctx->base_mrec;
ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
le16_to_cpu(ctx->mrec->attrs_offset));
- ctx->is_first = TRUE;
+ ctx->is_first = true;
ctx->ntfs_ino = base_ni;
ctx->base_ntfs_ino = NULL;
ctx->base_mrec = NULL;
@@ -1224,7 +1224,7 @@ static inline void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
/* Sanity checks are performed elsewhere. */
.attr = (ATTR_RECORD*)((u8*)mrec +
le16_to_cpu(mrec->attrs_offset)),
- .is_first = TRUE,
+ .is_first = true,
.ntfs_ino = ni,
};
}
@@ -1243,7 +1243,7 @@ void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx)
{
if (likely(!ctx->base_ntfs_ino)) {
/* No attribute list. */
- ctx->is_first = TRUE;
+ ctx->is_first = true;
/* Sanity checks are performed elsewhere. */
ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec +
le16_to_cpu(ctx->mrec->attrs_offset));
@@ -1585,7 +1585,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size)
return -ENOMEM;
/* Start by allocating clusters to hold the attribute value. */
rl = ntfs_cluster_alloc(vol, 0, new_size >>
- vol->cluster_size_bits, -1, DATA_ZONE, TRUE);
+ vol->cluster_size_bits, -1, DATA_ZONE, true);
if (IS_ERR(rl)) {
err = PTR_ERR(rl);
ntfs_debug("Failed to allocate cluster%s, error code "
@@ -1919,7 +1919,7 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size,
unsigned long flags;
int err, mp_size;
u32 attr_len = 0; /* Silence stupid gcc warning. */
- BOOL mp_rebuilt;
+ bool mp_rebuilt;
#ifdef NTFS_DEBUG
read_lock_irqsave(&ni->size_lock, flags);
@@ -2222,7 +2222,7 @@ first_alloc:
rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits,
(new_alloc_size - allocated_size) >>
vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ?
- rl->lcn + rl->length : -1, DATA_ZONE, TRUE);
+ rl->lcn + rl->length : -1, DATA_ZONE, true);
if (IS_ERR(rl2)) {
err = PTR_ERR(rl2);
if (start < 0 || start >= allocated_size)
@@ -2265,7 +2265,7 @@ first_alloc:
BUG_ON(!rl2);
BUG_ON(!rl2->length);
BUG_ON(rl2->lcn < LCN_HOLE);
- mp_rebuilt = FALSE;
+ mp_rebuilt = false;
/* Get the size for the new mapping pairs array for this extent. */
mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1);
if (unlikely(mp_size <= 0)) {
@@ -2300,7 +2300,7 @@ first_alloc:
err = -EOPNOTSUPP;
goto undo_alloc;
}
- mp_rebuilt = TRUE;
+ mp_rebuilt = true;
/* Generate the mapping pairs array directly into the attr record. */
err = ntfs_mapping_pairs_build(vol, (u8*)a +
le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
diff --git a/fs/ntfs/attrib.h b/fs/ntfs/attrib.h
index 9074886b44ba..3c8b74c99b80 100644
--- a/fs/ntfs/attrib.h
+++ b/fs/ntfs/attrib.h
@@ -40,10 +40,10 @@
* Structure must be initialized to zero before the first call to one of the
* attribute search functions. Initialize @mrec to point to the mft record to
* search, and @attr to point to the first attribute within @mrec (not necessary
- * if calling the _first() functions), and set @is_first to TRUE (not necessary
+ * if calling the _first() functions), and set @is_first to 'true' (not necessary
* if calling the _first() functions).
*
- * If @is_first is TRUE, the search begins with @attr. If @is_first is FALSE,
+ * If @is_first is 'true', the search begins with @attr. If @is_first is 'false',
* the search begins after @attr. This is so that, after the first call to one
* of the search attribute functions, we can call the function again, without
* any modification of the search context, to automagically get the next
@@ -52,7 +52,7 @@
typedef struct {
MFT_RECORD *mrec;
ATTR_RECORD *attr;
- BOOL is_first;
+ bool is_first;
ntfs_inode *ntfs_ino;
ATTR_LIST_ENTRY *al_entry;
ntfs_inode *base_ntfs_ino;
@@ -65,7 +65,7 @@ extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn,
extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn);
extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
- const BOOL write_locked);
+ const bool write_locked);
extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
const VCN vcn, ntfs_attr_search_ctx *ctx);
diff --git a/fs/ntfs/bitmap.c b/fs/ntfs/bitmap.c
index 7a190cdc60e2..0809cf876098 100644
--- a/fs/ntfs/bitmap.c
+++ b/fs/ntfs/bitmap.c
@@ -34,18 +34,18 @@
* @start_bit: first bit to set
* @count: number of bits to set
* @value: value to set the bits to (i.e. 0 or 1)
- * @is_rollback: if TRUE this is a rollback operation
+ * @is_rollback: if 'true' this is a rollback operation
*
* Set @count bits starting at bit @start_bit in the bitmap described by the
* vfs inode @vi to @value, where @value is either 0 or 1.
*
- * @is_rollback should always be FALSE, it is for internal use to rollback
+ * @is_rollback should always be 'false', it is for internal use to rollback
* errors. You probably want to use ntfs_bitmap_set_bits_in_run() instead.
*
* Return 0 on success and -errno on error.
*/
int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
- const s64 count, const u8 value, const BOOL is_rollback)
+ const s64 count, const u8 value, const bool is_rollback)
{
s64 cnt = count;
pgoff_t index, end_index;
@@ -172,7 +172,7 @@ rollback:
return PTR_ERR(page);
if (count != cnt)
pos = __ntfs_bitmap_set_bits_in_run(vi, start_bit, count - cnt,
- value ? 0 : 1, TRUE);
+ value ? 0 : 1, true);
else
pos = 0;
if (!pos) {
diff --git a/fs/ntfs/bitmap.h b/fs/ntfs/bitmap.h
index bb50d6bc9212..72c9ad8be70d 100644
--- a/fs/ntfs/bitmap.h
+++ b/fs/ntfs/bitmap.h
@@ -30,7 +30,7 @@
#include "types.h"
extern int __ntfs_bitmap_set_bits_in_run(struct inode *vi, const s64 start_bit,
- const s64 count, const u8 value, const BOOL is_rollback);
+ const s64 count, const u8 value, const bool is_rollback);
/**
* ntfs_bitmap_set_bits_in_run - set a run of bits in a bitmap to a value
@@ -48,7 +48,7 @@ static inline int ntfs_bitmap_set_bits_in_run(struct inode *vi,
const s64 start_bit, const s64 count, const u8 value)
{
return __ntfs_bitmap_set_bits_in_run(vi, start_bit, count, value,
- FALSE);
+ false);
}
/**
diff --git a/fs/ntfs/collate.h b/fs/ntfs/collate.h
index e027f36fcc2f..aba83347e5fe 100644
--- a/fs/ntfs/collate.h
+++ b/fs/ntfs/collate.h
@@ -26,7 +26,7 @@
#include "types.h"
#include "volume.h"
-static inline BOOL ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
+static inline bool ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
int i;
/*
@@ -35,12 +35,12 @@ static inline BOOL ntfs_is_collation_rule_supported(COLLATION_RULE cr) {
* now.
*/
if (unlikely(cr != COLLATION_BINARY && cr != COLLATION_NTOFS_ULONG))
- return FALSE;
+ return false;
i = le32_to_cpu(cr);
if (likely(((i >= 0) && (i <= 0x02)) ||
((i >= 0x10) && (i <= 0x13))))
- return TRUE;
- return FALSE;
+ return true;
+ return false;
}
extern int ntfs_collate(ntfs_volume *vol, COLLATION_RULE cr,
diff --git a/fs/ntfs/compress.c b/fs/ntfs/compress.c
index 68a607ff9fd3..d98daf59e0b6 100644
--- a/fs/ntfs/compress.c
+++ b/fs/ntfs/compress.c
@@ -600,7 +600,7 @@ do_next_cb:
rl = NULL;
for (vcn = start_vcn, start_vcn += cb_clusters; vcn < start_vcn;
vcn++) {
- BOOL is_retry = FALSE;
+ bool is_retry = false;
if (!rl) {
lock_retry_remap:
@@ -626,7 +626,7 @@ lock_retry_remap:
break;
if (is_retry || lcn != LCN_RL_NOT_MAPPED)
goto rl_err;
- is_retry = TRUE;
+ is_retry = true;
/*
* Attempt to map runlist, dropping lock for the
* duration.
diff --git a/fs/ntfs/dir.c b/fs/ntfs/dir.c
index d1e2c6f9f05e..85c36b8ca452 100644
--- a/fs/ntfs/dir.c
+++ b/fs/ntfs/dir.c
@@ -1149,8 +1149,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
* Allocate a buffer to store the current name being processed
* converted to format determined by current NLS.
*/
- name = (u8*)kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1,
- GFP_NOFS);
+ name = kmalloc(NTFS_MAX_NAME_LEN * NLS_MAX_CHARSET_SIZE + 1, GFP_NOFS);
if (unlikely(!name)) {
err = -ENOMEM;
goto err_out;
@@ -1191,7 +1190,7 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
* map the mft record without deadlocking.
*/
rc = le32_to_cpu(ctx->attr->data.resident.value_length);
- ir = (INDEX_ROOT*)kmalloc(rc, GFP_NOFS);
+ ir = kmalloc(rc, GFP_NOFS);
if (unlikely(!ir)) {
err = -ENOMEM;
goto err_out;
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 2e42c2dcae12..ae2fe0016d2c 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -509,7 +509,7 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
u32 attr_rec_len = 0;
unsigned blocksize, u;
int err, mp_size;
- BOOL rl_write_locked, was_hole, is_retry;
+ bool rl_write_locked, was_hole, is_retry;
unsigned char blocksize_bits;
struct {
u8 runlist_merged:1;
@@ -543,13 +543,13 @@ static int ntfs_prepare_pages_for_non_resident_write(struct page **pages,
return -ENOMEM;
}
} while (++u < nr_pages);
- rl_write_locked = FALSE;
+ rl_write_locked = false;
rl = NULL;
err = 0;
vcn = lcn = -1;
vcn_len = 0;
lcn_block = -1;
- was_hole = FALSE;
+ was_hole = false;
cpos = pos >> vol->cluster_size_bits;
end = pos + bytes;
cend = (end + vol->cluster_size - 1) >> vol->cluster_size_bits;
@@ -760,7 +760,7 @@ map_buffer_cached:
}
continue;
}
- is_retry = FALSE;
+ is_retry = false;
if (!rl) {
down_read(&ni->runlist.lock);
retry_remap:
@@ -776,7 +776,7 @@ retry_remap:
* Successful remap, setup the map cache and
* use that to deal with the buffer.
*/
- was_hole = FALSE;
+ was_hole = false;
vcn = bh_cpos;
vcn_len = rl[1].vcn - vcn;
lcn_block = lcn << (vol->cluster_size_bits -
@@ -792,7 +792,7 @@ retry_remap:
if (likely(vcn + vcn_len >= cend)) {
if (rl_write_locked) {
up_write(&ni->runlist.lock);
- rl_write_locked = FALSE;
+ rl_write_locked = false;
} else
up_read(&ni->runlist.lock);
rl = NULL;
@@ -818,13 +818,13 @@ retry_remap:
*/
up_read(&ni->runlist.lock);
down_write(&ni->runlist.lock);
- rl_write_locked = TRUE;
+ rl_write_locked = true;
goto retry_remap;
}
err = ntfs_map_runlist_nolock(ni, bh_cpos,
NULL);
if (likely(!err)) {
- is_retry = TRUE;
+ is_retry = true;
goto retry_remap;
}
/*
@@ -903,7 +903,7 @@ rl_not_mapped_enoent:
if (!rl_write_locked) {
up_read(&ni->runlist.lock);
down_write(&ni->runlist.lock);
- rl_write_locked = TRUE;
+ rl_write_locked = true;
goto retry_remap;
}
/* Find the previous last allocated cluster. */
@@ -917,7 +917,7 @@ rl_not_mapped_enoent:
}
}
rl2 = ntfs_cluster_alloc(vol, bh_cpos, 1, lcn, DATA_ZONE,
- FALSE);
+ false);
if (IS_ERR(rl2)) {
err = PTR_ERR(rl2);
ntfs_debug("Failed to allocate cluster, error code %i.",
@@ -1093,7 +1093,7 @@ rl_not_mapped_enoent:
status.mft_attr_mapped = 0;
status.mp_rebuilt = 0;
/* Setup the map cache and use that to deal with the buffer. */
- was_hole = TRUE;
+ was_hole = true;
vcn = bh_cpos;
vcn_len = 1;
lcn_block = lcn << (vol->cluster_size_bits - blocksize_bits);
@@ -1105,7 +1105,7 @@ rl_not_mapped_enoent:
*/
if (likely(vcn + vcn_len >= cend)) {
up_write(&ni->runlist.lock);
- rl_write_locked = FALSE;
+ rl_write_locked = false;
rl = NULL;
}
goto map_buffer_cached;
@@ -1117,7 +1117,7 @@ rl_not_mapped_enoent:
if (likely(!err)) {
if (unlikely(rl_write_locked)) {
up_write(&ni->runlist.lock);
- rl_write_locked = FALSE;
+ rl_write_locked = false;
} else if (unlikely(rl))
up_read(&ni->runlist.lock);
rl = NULL;
@@ -1528,19 +1528,19 @@ static inline int ntfs_commit_pages_after_non_resident_write(
do {
s64 bh_pos;
struct page *page;
- BOOL partial;
+ bool partial;
page = pages[u];
bh_pos = (s64)page->index << PAGE_CACHE_SHIFT;
bh = head = page_buffers(page);
- partial = FALSE;
+ partial = false;
do {
s64 bh_end;
bh_end = bh_pos + blocksize;
if (bh_end <= pos || bh_pos >= end) {
if (!buffer_uptodate(bh))
- partial = TRUE;
+ partial = true;
} else {
set_buffer_uptodate(bh);
mark_buffer_dirty(bh);
@@ -1997,7 +1997,7 @@ static ssize_t ntfs_file_buffered_write(struct kiocb *iocb,
*/
down_read(&ni->runlist.lock);
lcn = ntfs_attr_vcn_to_lcn_nolock(ni, pos >>
- vol->cluster_size_bits, FALSE);
+ vol->cluster_size_bits, false);
up_read(&ni->runlist.lock);
if (unlikely(lcn < LCN_HOLE)) {
status = -EIO;
@@ -2176,20 +2176,18 @@ out:
/**
* ntfs_file_aio_write -
*/
-static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
+static ssize_t ntfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
ssize_t ret;
- struct iovec local_iov = { .iov_base = (void __user *)buf,
- .iov_len = count };
BUG_ON(iocb->ki_pos != pos);
mutex_lock(&inode->i_mutex);
- ret = ntfs_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+ ret = ntfs_file_aio_write_nolock(iocb, iov, nr_segs, &iocb->ki_pos);
mutex_unlock(&inode->i_mutex);
if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
int err = sync_page_range(inode, mapping, pos, ret);
@@ -2298,13 +2296,11 @@ static int ntfs_file_fsync(struct file *filp, struct dentry *dentry,
const struct file_operations ntfs_file_ops = {
.llseek = generic_file_llseek, /* Seek inside file. */
- .read = generic_file_read, /* Read from file. */
+ .read = do_sync_read, /* Read from file. */
.aio_read = generic_file_aio_read, /* Async read from file. */
- .readv = generic_file_readv, /* Read from file. */
#ifdef NTFS_RW
.write = ntfs_file_write, /* Write to file. */
.aio_write = ntfs_file_aio_write, /* Async write to file. */
- .writev = ntfs_file_writev, /* Write to file. */
/*.release = ,*/ /* Last file is closed. See
fs/ext2/file.c::
ext2_release_file() for
diff --git a/fs/ntfs/index.c b/fs/ntfs/index.c
index 9f5427c2d105..e32cde486362 100644
--- a/fs/ntfs/index.c
+++ b/fs/ntfs/index.c
@@ -204,7 +204,7 @@ int ntfs_index_lookup(const void *key, const int key_len,
if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
&ie->key, key_len)) {
ir_done:
- ictx->is_in_root = TRUE;
+ ictx->is_in_root = true;
ictx->ir = ir;
ictx->actx = actx;
ictx->base_ni = base_ni;
@@ -374,7 +374,7 @@ fast_descend_into_child_node:
if ((key_len == le16_to_cpu(ie->key_length)) && !memcmp(key,
&ie->key, key_len)) {
ia_done:
- ictx->is_in_root = FALSE;
+ ictx->is_in_root = false;
ictx->actx = NULL;
ictx->base_ni = NULL;
ictx->ia = ia;
diff --git a/fs/ntfs/index.h b/fs/ntfs/index.h
index 846a489e8692..8745469c3989 100644
--- a/fs/ntfs/index.h
+++ b/fs/ntfs/index.h
@@ -37,12 +37,12 @@
* @entry: index entry (points into @ir or @ia)
* @data: index entry data (points into @entry)
* @data_len: length in bytes of @data
- * @is_in_root: TRUE if @entry is in @ir and FALSE if it is in @ia
+ * @is_in_root: 'true' if @entry is in @ir and 'false' if it is in @ia
* @ir: index root if @is_in_root and NULL otherwise
* @actx: attribute search context if @is_in_root and NULL otherwise
* @base_ni: base inode if @is_in_root and NULL otherwise
- * @ia: index block if @is_in_root is FALSE and NULL otherwise
- * @page: page if @is_in_root is FALSE and NULL otherwise
+ * @ia: index block if @is_in_root is 'false' and NULL otherwise
+ * @page: page if @is_in_root is 'false' and NULL otherwise
*
* @idx_ni is the index inode this context belongs to.
*
@@ -50,11 +50,11 @@
* are the index entry data and its length in bytes, respectively. @data
* simply points into @entry. This is probably what the user is interested in.
*
- * If @is_in_root is TRUE, @entry is in the index root attribute @ir described
+ * If @is_in_root is 'true', @entry is in the index root attribute @ir described
* by the attribute search context @actx and the base inode @base_ni. @ia and
* @page are NULL in this case.
*
- * If @is_in_root is FALSE, @entry is in the index allocation attribute and @ia
+ * If @is_in_root is 'false', @entry is in the index allocation attribute and @ia
* and @page point to the index allocation block and the mapped, locked page it
* is in, respectively. @ir, @actx and @base_ni are NULL in this case.
*
@@ -77,7 +77,7 @@ typedef struct {
INDEX_ENTRY *entry;
void *data;
u16 data_len;
- BOOL is_in_root;
+ bool is_in_root;
INDEX_ROOT *ir;
ntfs_attr_search_ctx *actx;
ntfs_inode *base_ni;
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index d313f356e66a..2d3de9c89818 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -137,7 +137,7 @@ static int ntfs_init_locked_inode(struct inode *vi, ntfs_attr *na)
BUG_ON(!na->name);
i = na->name_len * sizeof(ntfschar);
- ni->name = (ntfschar*)kmalloc(i + sizeof(ntfschar), GFP_ATOMIC);
+ ni->name = kmalloc(i + sizeof(ntfschar), GFP_ATOMIC);
if (!ni->name)
return -ENOMEM;
memcpy(ni->name, na->name, i);
@@ -556,8 +556,6 @@ static int ntfs_read_locked_inode(struct inode *vi)
/* Setup the generic vfs inode parts now. */
- /* This is the optimal IO size (for stat), not the fs block size. */
- vi->i_blksize = PAGE_CACHE_SIZE;
/*
* This is for checking whether an inode has changed w.r.t. a file so
* that the file can be updated if necessary (compare with f_version).
@@ -1234,7 +1232,6 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
base_ni = NTFS_I(base_vi);
/* Just mirror the values from the base inode. */
- vi->i_blksize = base_vi->i_blksize;
vi->i_version = base_vi->i_version;
vi->i_uid = base_vi->i_uid;
vi->i_gid = base_vi->i_gid;
@@ -1504,7 +1501,6 @@ static int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi)
ni = NTFS_I(vi);
base_ni = NTFS_I(base_vi);
/* Just mirror the values from the base inode. */
- vi->i_blksize = base_vi->i_blksize;
vi->i_version = base_vi->i_version;
vi->i_uid = base_vi->i_uid;
vi->i_gid = base_vi->i_gid;
@@ -2305,7 +2301,7 @@ void ntfs_clear_big_inode(struct inode *vi)
}
#ifdef NTFS_RW
if (NInoDirty(ni)) {
- BOOL was_bad = (is_bad_inode(vi));
+ bool was_bad = (is_bad_inode(vi));
/* Committing the inode also commits all extent inodes. */
ntfs_commit_inode(vi);
@@ -3019,7 +3015,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
MFT_RECORD *m;
STANDARD_INFORMATION *si;
int err = 0;
- BOOL modified = FALSE;
+ bool modified = false;
ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "",
vi->i_ino);
@@ -3061,7 +3057,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
sle64_to_cpu(si->last_data_change_time),
(long long)sle64_to_cpu(nt));
si->last_data_change_time = nt;
- modified = TRUE;
+ modified = true;
}
nt = utc2ntfs(vi->i_ctime);
if (si->last_mft_change_time != nt) {
@@ -3070,7 +3066,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
sle64_to_cpu(si->last_mft_change_time),
(long long)sle64_to_cpu(nt));
si->last_mft_change_time = nt;
- modified = TRUE;
+ modified = true;
}
nt = utc2ntfs(vi->i_atime);
if (si->last_access_time != nt) {
@@ -3079,7 +3075,7 @@ int ntfs_write_inode(struct inode *vi, int sync)
(long long)sle64_to_cpu(si->last_access_time),
(long long)sle64_to_cpu(nt));
si->last_access_time = nt;
- modified = TRUE;
+ modified = true;
}
/*
* If we just modified the standard information attribute we need to
diff --git a/fs/ntfs/layout.h b/fs/ntfs/layout.h
index d34b93cb8b48..1e383328eceb 100644
--- a/fs/ntfs/layout.h
+++ b/fs/ntfs/layout.h
@@ -142,13 +142,13 @@ typedef le32 NTFS_RECORD_TYPE;
* operator! (-8
*/
-static inline BOOL __ntfs_is_magic(le32 x, NTFS_RECORD_TYPE r)
+static inline bool __ntfs_is_magic(le32 x, NTFS_RECORD_TYPE r)
{
return (x == r);
}
#define ntfs_is_magic(x, m) __ntfs_is_magic(x, magic_##m)
-static inline BOOL __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
+static inline bool __ntfs_is_magicp(le32 *p, NTFS_RECORD_TYPE r)
{
return (*p == r);
}
@@ -323,7 +323,7 @@ typedef le64 leMFT_REF;
#define MREF_LE(x) ((unsigned long)(le64_to_cpu(x) & MFT_REF_MASK_CPU))
#define MSEQNO_LE(x) ((u16)((le64_to_cpu(x) >> 48) & 0xffff))
-#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? 1 : 0)
+#define IS_ERR_MREF(x) (((x) & 0x0000800000000000ULL) ? true : false)
#define ERR_MREF(x) ((u64)((s64)(x)))
#define MREF_ERR(x) ((int)((s64)(x)))
diff --git a/fs/ntfs/lcnalloc.c b/fs/ntfs/lcnalloc.c
index 29cabf93d2d2..1711b710b641 100644
--- a/fs/ntfs/lcnalloc.c
+++ b/fs/ntfs/lcnalloc.c
@@ -76,7 +76,7 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
* @count: number of clusters to allocate
* @start_lcn: starting lcn at which to allocate the clusters (or -1 if none)
* @zone: zone from which to allocate the clusters
- * @is_extension: if TRUE, this is an attribute extension
+ * @is_extension: if 'true', this is an attribute extension
*
* Allocate @count clusters preferably starting at cluster @start_lcn or at the
* current allocator position if @start_lcn is -1, on the mounted ntfs volume
@@ -87,11 +87,11 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
* @start_vcn specifies the vcn of the first allocated cluster. This makes
* merging the resulting runlist with the old runlist easier.
*
- * If @is_extension is TRUE, the caller is allocating clusters to extend an
- * attribute and if it is FALSE, the caller is allocating clusters to fill a
+ * If @is_extension is 'true', the caller is allocating clusters to extend an
+ * attribute and if it is 'false', the caller is allocating clusters to fill a
* hole in an attribute. Practically the difference is that if @is_extension
- * is TRUE the returned runlist will be terminated with LCN_ENOENT and if
- * @is_extension is FALSE the runlist will be terminated with
+ * is 'true' the returned runlist will be terminated with LCN_ENOENT and if
+ * @is_extension is 'false' the runlist will be terminated with
* LCN_RL_NOT_MAPPED.
*
* You need to check the return value with IS_ERR(). If this is false, the
@@ -146,7 +146,7 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
const s64 count, const LCN start_lcn,
const NTFS_CLUSTER_ALLOCATION_ZONES zone,
- const BOOL is_extension)
+ const bool is_extension)
{
LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
@@ -818,7 +818,7 @@ out:
* Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that
* you cache ctx->mrec in a variable @m of type MFT_RECORD *.
*
- * @is_rollback should always be FALSE, it is for internal use to rollback
+ * @is_rollback should always be 'false', it is for internal use to rollback
* errors. You probably want to use ntfs_cluster_free() instead.
*
* Note, __ntfs_cluster_free() does not modify the runlist, so you have to
@@ -828,7 +828,7 @@ out:
* success and -errno on error.
*
* WARNING: If @ctx is supplied, regardless of whether success or failure is
- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
+ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
* is no longer valid, i.e. you need to either call
* ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
* In that case PTR_ERR(@ctx->mrec) will give you the error code for
@@ -847,7 +847,7 @@ out:
* and it will be left mapped on return.
*/
s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn, s64 count,
- ntfs_attr_search_ctx *ctx, const BOOL is_rollback)
+ ntfs_attr_search_ctx *ctx, const bool is_rollback)
{
s64 delta, to_free, total_freed, real_freed;
ntfs_volume *vol;
@@ -999,7 +999,7 @@ err_out:
* If rollback fails, set the volume errors flag, emit an error
* message, and return the error code.
*/
- delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, TRUE);
+ delta = __ntfs_cluster_free(ni, start_vcn, total_freed, ctx, true);
if (delta < 0) {
ntfs_error(vol->sb, "Failed to rollback (error %i). Leaving "
"inconsistent metadata! Unmount and run "
diff --git a/fs/ntfs/lcnalloc.h b/fs/ntfs/lcnalloc.h
index 72cbca7003b2..2adb04316941 100644
--- a/fs/ntfs/lcnalloc.h
+++ b/fs/ntfs/lcnalloc.h
@@ -43,10 +43,10 @@ typedef enum {
extern runlist_element *ntfs_cluster_alloc(ntfs_volume *vol,
const VCN start_vcn, const s64 count, const LCN start_lcn,
const NTFS_CLUSTER_ALLOCATION_ZONES zone,
- const BOOL is_extension);
+ const bool is_extension);
extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
- s64 count, ntfs_attr_search_ctx *ctx, const BOOL is_rollback);
+ s64 count, ntfs_attr_search_ctx *ctx, const bool is_rollback);
/**
* ntfs_cluster_free - free clusters on an ntfs volume
@@ -86,7 +86,7 @@ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
* success and -errno on error.
*
* WARNING: If @ctx is supplied, regardless of whether success or failure is
- * returned, you need to check IS_ERR(@ctx->mrec) and if TRUE the @ctx
+ * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx
* is no longer valid, i.e. you need to either call
* ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it.
* In that case PTR_ERR(@ctx->mrec) will give you the error code for
@@ -107,7 +107,7 @@ extern s64 __ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
static inline s64 ntfs_cluster_free(ntfs_inode *ni, const VCN start_vcn,
s64 count, ntfs_attr_search_ctx *ctx)
{
- return __ntfs_cluster_free(ni, start_vcn, count, ctx, FALSE);
+ return __ntfs_cluster_free(ni, start_vcn, count, ctx, false);
}
extern int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
diff --git a/fs/ntfs/logfile.c b/fs/ntfs/logfile.c
index 4af2ad1193ec..acfed325f4ec 100644
--- a/fs/ntfs/logfile.c
+++ b/fs/ntfs/logfile.c
@@ -41,18 +41,18 @@
* @rp: restart page header to check
* @pos: position in @vi at which the restart page header resides
*
- * Check the restart page header @rp for consistency and return TRUE if it is
- * consistent and FALSE otherwise.
+ * Check the restart page header @rp for consistency and return 'true' if it is
+ * consistent and 'false' otherwise.
*
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
* require the full restart page.
*/
-static BOOL ntfs_check_restart_page_header(struct inode *vi,
+static bool ntfs_check_restart_page_header(struct inode *vi,
RESTART_PAGE_HEADER *rp, s64 pos)
{
u32 logfile_system_page_size, logfile_log_page_size;
u16 ra_ofs, usa_count, usa_ofs, usa_end = 0;
- BOOL have_usa = TRUE;
+ bool have_usa = true;
ntfs_debug("Entering.");
/*
@@ -67,7 +67,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
(logfile_system_page_size - 1) ||
logfile_log_page_size & (logfile_log_page_size - 1)) {
ntfs_error(vi->i_sb, "$LogFile uses unsupported page size.");
- return FALSE;
+ return false;
}
/*
* We must be either at !pos (1st restart page) or at pos = system page
@@ -76,7 +76,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
if (pos && pos != logfile_system_page_size) {
ntfs_error(vi->i_sb, "Found restart area in incorrect "
"position in $LogFile.");
- return FALSE;
+ return false;
}
/* We only know how to handle version 1.1. */
if (sle16_to_cpu(rp->major_ver) != 1 ||
@@ -85,14 +85,14 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
"supported. (This driver supports version "
"1.1 only.)", (int)sle16_to_cpu(rp->major_ver),
(int)sle16_to_cpu(rp->minor_ver));
- return FALSE;
+ return false;
}
/*
* If chkdsk has been run the restart page may not be protected by an
* update sequence array.
*/
if (ntfs_is_chkd_record(rp->magic) && !le16_to_cpu(rp->usa_count)) {
- have_usa = FALSE;
+ have_usa = false;
goto skip_usa_checks;
}
/* Verify the size of the update sequence array. */
@@ -100,7 +100,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
if (usa_count != le16_to_cpu(rp->usa_count)) {
ntfs_error(vi->i_sb, "$LogFile restart page specifies "
"inconsistent update sequence array count.");
- return FALSE;
+ return false;
}
/* Verify the position of the update sequence array. */
usa_ofs = le16_to_cpu(rp->usa_ofs);
@@ -109,7 +109,7 @@ static BOOL ntfs_check_restart_page_header(struct inode *vi,
usa_end > NTFS_BLOCK_SIZE - sizeof(u16)) {
ntfs_error(vi->i_sb, "$LogFile restart page specifies "
"inconsistent update sequence array offset.");
- return FALSE;
+ return false;
}
skip_usa_checks:
/*
@@ -124,7 +124,7 @@ skip_usa_checks:
ra_ofs > logfile_system_page_size) {
ntfs_error(vi->i_sb, "$LogFile restart page specifies "
"inconsistent restart area offset.");
- return FALSE;
+ return false;
}
/*
* Only restart pages modified by chkdsk are allowed to have chkdsk_lsn
@@ -133,10 +133,10 @@ skip_usa_checks:
if (!ntfs_is_chkd_record(rp->magic) && sle64_to_cpu(rp->chkdsk_lsn)) {
ntfs_error(vi->i_sb, "$LogFile restart page is not modified "
"by chkdsk but a chkdsk LSN is specified.");
- return FALSE;
+ return false;
}
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
/**
@@ -145,7 +145,7 @@ skip_usa_checks:
* @rp: restart page whose restart area to check
*
* Check the restart area of the restart page @rp for consistency and return
- * TRUE if it is consistent and FALSE otherwise.
+ * 'true' if it is consistent and 'false' otherwise.
*
* This function assumes that the restart page header has already been
* consistency checked.
@@ -153,7 +153,7 @@ skip_usa_checks:
* This function only needs NTFS_BLOCK_SIZE bytes in @rp, i.e. it does not
* require the full restart page.
*/
-static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
+static bool ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
{
u64 file_size;
RESTART_AREA *ra;
@@ -172,7 +172,7 @@ static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
NTFS_BLOCK_SIZE - sizeof(u16)) {
ntfs_error(vi->i_sb, "$LogFile restart area specifies "
"inconsistent file offset.");
- return FALSE;
+ return false;
}
/*
* Now that we can access ra->client_array_offset, make sure everything
@@ -186,7 +186,7 @@ static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
ra_ofs + ca_ofs > NTFS_BLOCK_SIZE - sizeof(u16)) {
ntfs_error(vi->i_sb, "$LogFile restart area specifies "
"inconsistent client array offset.");
- return FALSE;
+ return false;
}
/*
* The restart area must end within the system page size both when
@@ -203,7 +203,7 @@ static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
"of the system page size specified by the "
"restart page header and/or the specified "
"restart area length is inconsistent.");
- return FALSE;
+ return false;
}
/*
* The ra->client_free_list and ra->client_in_use_list must be either
@@ -218,7 +218,7 @@ static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
le16_to_cpu(ra->log_clients))) {
ntfs_error(vi->i_sb, "$LogFile restart area specifies "
"overflowing client free and/or in use lists.");
- return FALSE;
+ return false;
}
/*
* Check ra->seq_number_bits against ra->file_size for consistency.
@@ -233,24 +233,24 @@ static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
if (le32_to_cpu(ra->seq_number_bits) != 67 - fs_bits) {
ntfs_error(vi->i_sb, "$LogFile restart area specifies "
"inconsistent sequence number bits.");
- return FALSE;
+ return false;
}
/* The log record header length must be a multiple of 8. */
if (((le16_to_cpu(ra->log_record_header_length) + 7) & ~7) !=
le16_to_cpu(ra->log_record_header_length)) {
ntfs_error(vi->i_sb, "$LogFile restart area specifies "
"inconsistent log record header length.");
- return FALSE;
+ return false;
}
/* Dito for the log page data offset. */
if (((le16_to_cpu(ra->log_page_data_offset) + 7) & ~7) !=
le16_to_cpu(ra->log_page_data_offset)) {
ntfs_error(vi->i_sb, "$LogFile restart area specifies "
"inconsistent log page data offset.");
- return FALSE;
+ return false;
}
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
/**
@@ -259,7 +259,7 @@ static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
* @rp: restart page whose log client array to check
*
* Check the log client array of the restart page @rp for consistency and
- * return TRUE if it is consistent and FALSE otherwise.
+ * return 'true' if it is consistent and 'false' otherwise.
*
* This function assumes that the restart page header and the restart area have
* already been consistency checked.
@@ -268,13 +268,13 @@ static BOOL ntfs_check_restart_area(struct inode *vi, RESTART_PAGE_HEADER *rp)
* function needs @rp->system_page_size bytes in @rp, i.e. it requires the full
* restart page and the page must be multi sector transfer deprotected.
*/
-static BOOL ntfs_check_log_client_array(struct inode *vi,
+static bool ntfs_check_log_client_array(struct inode *vi,
RESTART_PAGE_HEADER *rp)
{
RESTART_AREA *ra;
LOG_CLIENT_RECORD *ca, *cr;
u16 nr_clients, idx;
- BOOL in_free_list, idx_is_first;
+ bool in_free_list, idx_is_first;
ntfs_debug("Entering.");
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
@@ -290,9 +290,9 @@ static BOOL ntfs_check_log_client_array(struct inode *vi,
*/
nr_clients = le16_to_cpu(ra->log_clients);
idx = le16_to_cpu(ra->client_free_list);
- in_free_list = TRUE;
+ in_free_list = true;
check_list:
- for (idx_is_first = TRUE; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
+ for (idx_is_first = true; idx != LOGFILE_NO_CLIENT_CPU; nr_clients--,
idx = le16_to_cpu(cr->next_client)) {
if (!nr_clients || idx >= le16_to_cpu(ra->log_clients))
goto err_out;
@@ -302,20 +302,20 @@ check_list:
if (idx_is_first) {
if (cr->prev_client != LOGFILE_NO_CLIENT)
goto err_out;
- idx_is_first = FALSE;
+ idx_is_first = false;
}
}
/* Switch to and check the in use list if we just did the free list. */
if (in_free_list) {
- in_free_list = FALSE;
+ in_free_list = false;
idx = le16_to_cpu(ra->client_in_use_list);
goto check_list;
}
ntfs_debug("Done.");
- return TRUE;
+ return true;
err_out:
ntfs_error(vi->i_sb, "$LogFile log client array is corrupt.");
- return FALSE;
+ return false;
}
/**
@@ -468,8 +468,8 @@ err_out:
* @log_vi: struct inode of loaded journal $LogFile to check
* @rp: [OUT] on success this is a copy of the current restart page
*
- * Check the $LogFile journal for consistency and return TRUE if it is
- * consistent and FALSE if not. On success, the current restart page is
+ * Check the $LogFile journal for consistency and return 'true' if it is
+ * consistent and 'false' if not. On success, the current restart page is
* returned in *@rp. Caller must call ntfs_free(*@rp) when finished with it.
*
* At present we only check the two restart pages and ignore the log record
@@ -480,7 +480,7 @@ err_out:
* if the $LogFile was created on a system with a different page size to ours
* yet and mst deprotection would fail if our page size is smaller.
*/
-BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
+bool ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
{
s64 size, pos;
LSN rstr1_lsn, rstr2_lsn;
@@ -491,7 +491,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
RESTART_PAGE_HEADER *rstr1_ph = NULL;
RESTART_PAGE_HEADER *rstr2_ph = NULL;
int log_page_size, log_page_mask, err;
- BOOL logfile_is_empty = TRUE;
+ bool logfile_is_empty = true;
u8 log_page_bits;
ntfs_debug("Entering.");
@@ -527,7 +527,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
if (size < log_page_size * 2 || (size - log_page_size * 2) >>
log_page_bits < MinLogRecordPages) {
ntfs_error(vol->sb, "$LogFile is too small.");
- return FALSE;
+ return false;
}
/*
* Read through the file looking for a restart page. Since the restart
@@ -556,7 +556,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
* means we are done.
*/
if (!ntfs_is_empty_recordp((le32*)kaddr))
- logfile_is_empty = FALSE;
+ logfile_is_empty = false;
else if (!logfile_is_empty)
break;
/*
@@ -615,13 +615,13 @@ BOOL ntfs_check_logfile(struct inode *log_vi, RESTART_PAGE_HEADER **rp)
NVolSetLogFileEmpty(vol);
is_empty:
ntfs_debug("Done. ($LogFile is empty.)");
- return TRUE;
+ return true;
}
if (!rstr1_ph) {
BUG_ON(rstr2_ph);
ntfs_error(vol->sb, "Did not find any restart pages in "
"$LogFile and it was not empty.");
- return FALSE;
+ return false;
}
/* If both restart pages were found, use the more recent one. */
if (rstr2_ph) {
@@ -648,11 +648,11 @@ is_empty:
else
ntfs_free(rstr1_ph);
ntfs_debug("Done.");
- return TRUE;
+ return true;
err_out:
if (rstr1_ph)
ntfs_free(rstr1_ph);
- return FALSE;
+ return false;
}
/**
@@ -660,8 +660,8 @@ err_out:
* @log_vi: struct inode of loaded journal $LogFile to check
* @rp: copy of the current restart page
*
- * Analyze the $LogFile journal and return TRUE if it indicates the volume was
- * shutdown cleanly and FALSE if not.
+ * Analyze the $LogFile journal and return 'true' if it indicates the volume was
+ * shutdown cleanly and 'false' if not.
*
* At present we only look at the two restart pages and ignore the log record
* pages. This is a little bit crude in that there will be a very small number
@@ -675,7 +675,7 @@ err_out:
* is empty this function requires that NVolLogFileEmpty() is true otherwise an
* empty volume will be reported as dirty.
*/
-BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
+bool ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
{
ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
RESTART_AREA *ra;
@@ -684,7 +684,7 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
/* An empty $LogFile must have been clean before it got emptied. */
if (NVolLogFileEmpty(vol)) {
ntfs_debug("Done. ($LogFile is empty.)");
- return TRUE;
+ return true;
}
BUG_ON(!rp);
if (!ntfs_is_rstr_record(rp->magic) &&
@@ -693,7 +693,7 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
"probably a bug in that the $LogFile should "
"have been consistency checked before calling "
"this function.");
- return FALSE;
+ return false;
}
ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset));
/*
@@ -704,25 +704,25 @@ BOOL ntfs_is_logfile_clean(struct inode *log_vi, const RESTART_PAGE_HEADER *rp)
if (ra->client_in_use_list != LOGFILE_NO_CLIENT &&
!(ra->flags & RESTART_VOLUME_IS_CLEAN)) {
ntfs_debug("Done. $LogFile indicates a dirty shutdown.");
- return FALSE;
+ return false;
}
/* $LogFile indicates a clean shutdown. */
ntfs_debug("Done. $LogFile indicates a clean shutdown.");
- return TRUE;
+ return true;
}
/**
* ntfs_empty_logfile - empty the contents of the $LogFile journal
* @log_vi: struct inode of loaded journal $LogFile to empty
*
- * Empty the contents of the $LogFile journal @log_vi and return TRUE on
- * success and FALSE on error.
+ * Empty the contents of the $LogFile journal @log_vi and return 'true' on
+ * success and 'false' on error.
*
* This function assumes that the $LogFile journal has already been consistency
* checked by a call to ntfs_check_logfile() and that ntfs_is_logfile_clean()
* has been used to ensure that the $LogFile is clean.
*/
-BOOL ntfs_empty_logfile(struct inode *log_vi)
+bool ntfs_empty_logfile(struct inode *log_vi)
{
ntfs_volume *vol = NTFS_SB(log_vi->i_sb);
@@ -735,13 +735,13 @@ BOOL ntfs_empty_logfile(struct inode *log_vi)
if (unlikely(err)) {
ntfs_error(vol->sb, "Failed to fill $LogFile with "
"0xff bytes (error code %i).", err);
- return FALSE;
+ return false;
}
/* Set the flag so we do not have to do it again on remount. */
NVolSetLogFileEmpty(vol);
}
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
#endif /* NTFS_RW */
diff --git a/fs/ntfs/logfile.h b/fs/ntfs/logfile.h
index a51f3dd0e9eb..9468e1c45ae3 100644
--- a/fs/ntfs/logfile.h
+++ b/fs/ntfs/logfile.h
@@ -296,13 +296,13 @@ typedef struct {
/* sizeof() = 160 (0xa0) bytes */
} __attribute__ ((__packed__)) LOG_CLIENT_RECORD;
-extern BOOL ntfs_check_logfile(struct inode *log_vi,
+extern bool ntfs_check_logfile(struct inode *log_vi,
RESTART_PAGE_HEADER **rp);
-extern BOOL ntfs_is_logfile_clean(struct inode *log_vi,
+extern bool ntfs_is_logfile_clean(struct inode *log_vi,
const RESTART_PAGE_HEADER *rp);
-extern BOOL ntfs_empty_logfile(struct inode *log_vi);
+extern bool ntfs_empty_logfile(struct inode *log_vi);
#endif /* NTFS_RW */
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 2438c00ec0ce..2ad5c8b104b9 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -251,7 +251,7 @@ MFT_RECORD *map_extent_mft_record(ntfs_inode *base_ni, MFT_REF mref,
int i;
unsigned long mft_no = MREF(mref);
u16 seq_no = MSEQNO(mref);
- BOOL destroy_ni = FALSE;
+ bool destroy_ni = false;
ntfs_debug("Mapping extent mft record 0x%lx (base mft record 0x%lx).",
mft_no, base_ni->mft_no);
@@ -322,7 +322,7 @@ map_err_out:
if (seq_no && (le16_to_cpu(m->sequence_number) != seq_no)) {
ntfs_error(base_ni->vol->sb, "Found stale extent mft "
"reference! Corrupt filesystem. Run chkdsk.");
- destroy_ni = TRUE;
+ destroy_ni = true;
m = ERR_PTR(-EIO);
goto unm_err_out;
}
@@ -331,11 +331,11 @@ map_err_out:
ntfs_inode **tmp;
int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode *);
- tmp = (ntfs_inode **)kmalloc(new_size, GFP_NOFS);
+ tmp = kmalloc(new_size, GFP_NOFS);
if (unlikely(!tmp)) {
ntfs_error(base_ni->vol->sb, "Failed to allocate "
"internal buffer.");
- destroy_ni = TRUE;
+ destroy_ni = true;
m = ERR_PTR(-ENOMEM);
goto unm_err_out;
}
@@ -857,7 +857,7 @@ err_out:
* caller is responsible for unlocking the ntfs inode and unpinning the base
* vfs inode.
*
- * Return TRUE if the mft record may be written out and FALSE if not.
+ * Return 'true' if the mft record may be written out and 'false' if not.
*
* The caller has locked the page and cleared the uptodate flag on it which
* means that we can safely write out any dirty mft records that do not have
@@ -868,7 +868,7 @@ err_out:
* Here is a description of the tests we perform:
*
* If the inode is found in icache we know the mft record must be a base mft
- * record. If it is dirty, we do not write it and return FALSE as the vfs
+ * record. If it is dirty, we do not write it and return 'false' as the vfs
* inode write paths will result in the access times being updated which would
* cause the base mft record to be redirtied and written out again. (We know
* the access time update will modify the base mft record because Windows
@@ -877,11 +877,11 @@ err_out:
*
* If the inode is in icache and not dirty, we attempt to lock the mft record
* and if we find the lock was already taken, it is not safe to write the mft
- * record and we return FALSE.
+ * record and we return 'false'.
*
* If we manage to obtain the lock we have exclusive access to the mft record,
* which also allows us safe writeout of the mft record. We then set
- * @locked_ni to the locked ntfs inode and return TRUE.
+ * @locked_ni to the locked ntfs inode and return 'true'.
*
* Note we cannot just lock the mft record and sleep while waiting for the lock
* because this would deadlock due to lock reversal (normally the mft record is
@@ -891,24 +891,24 @@ err_out:
* If the inode is not in icache we need to perform further checks.
*
* If the mft record is not a FILE record or it is a base mft record, we can
- * safely write it and return TRUE.
+ * safely write it and return 'true'.
*
* We now know the mft record is an extent mft record. We check if the inode
* corresponding to its base mft record is in icache and obtain a reference to
- * it if it is. If it is not, we can safely write it and return TRUE.
+ * it if it is. If it is not, we can safely write it and return 'true'.
*
* We now have the base inode for the extent mft record. We check if it has an
* ntfs inode for the extent mft record attached and if not it is safe to write
- * the extent mft record and we return TRUE.
+ * the extent mft record and we return 'true'.
*
* The ntfs inode for the extent mft record is attached to the base inode so we
* attempt to lock the extent mft record and if we find the lock was already
- * taken, it is not safe to write the extent mft record and we return FALSE.
+ * taken, it is not safe to write the extent mft record and we return 'false'.
*
* If we manage to obtain the lock we have exclusive access to the extent mft
* record, which also allows us safe writeout of the extent mft record. We
* set the ntfs inode of the extent mft record clean and then set @locked_ni to
- * the now locked ntfs inode and return TRUE.
+ * the now locked ntfs inode and return 'true'.
*
* Note, the reason for actually writing dirty mft records here and not just
* relying on the vfs inode dirty code paths is that we can have mft records
@@ -922,7 +922,7 @@ err_out:
* appear if the mft record is reused for a new inode before it got written
* out.
*/
-BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
+bool ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
const MFT_RECORD *m, ntfs_inode **locked_ni)
{
struct super_block *sb = vol->sb;
@@ -977,7 +977,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
mft_no);
atomic_dec(&ni->count);
iput(vi);
- return FALSE;
+ return false;
}
ntfs_debug("Inode 0x%lx is not dirty.", mft_no);
/* The inode is not dirty, try to take the mft record lock. */
@@ -986,7 +986,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
"not write it.", mft_no);
atomic_dec(&ni->count);
iput(vi);
- return FALSE;
+ return false;
}
ntfs_debug("Managed to lock mft record 0x%lx, write it.",
mft_no);
@@ -995,7 +995,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
* return the locked ntfs inode.
*/
*locked_ni = ni;
- return TRUE;
+ return true;
}
ntfs_debug("Inode 0x%lx is not in icache.", mft_no);
/* The inode is not in icache. */
@@ -1003,13 +1003,13 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
if (!ntfs_is_mft_record(m->magic)) {
ntfs_debug("Mft record 0x%lx is not a FILE record, write it.",
mft_no);
- return TRUE;
+ return true;
}
/* Write the mft record if it is a base inode. */
if (!m->base_mft_record) {
ntfs_debug("Mft record 0x%lx is a base record, write it.",
mft_no);
- return TRUE;
+ return true;
}
/*
* This is an extent mft record. Check if the inode corresponding to
@@ -1033,7 +1033,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
*/
ntfs_debug("Base inode 0x%lx is not in icache, write the "
"extent record.", na.mft_no);
- return TRUE;
+ return true;
}
ntfs_debug("Base inode 0x%lx is in icache.", na.mft_no);
/*
@@ -1051,7 +1051,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
iput(vi);
ntfs_debug("Base inode 0x%lx has no attached extent inodes, "
"write the extent record.", na.mft_no);
- return TRUE;
+ return true;
}
/* Iterate over the attached extent inodes. */
extent_nis = ni->ext.extent_ntfs_inos;
@@ -1075,7 +1075,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
ntfs_debug("Extent inode 0x%lx is not attached to its base "
"inode 0x%lx, write the extent record.",
mft_no, na.mft_no);
- return TRUE;
+ return true;
}
ntfs_debug("Extent inode 0x%lx is attached to its base inode 0x%lx.",
mft_no, na.mft_no);
@@ -1091,7 +1091,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
iput(vi);
ntfs_debug("Extent mft record 0x%lx is already locked, do "
"not write it.", mft_no);
- return FALSE;
+ return false;
}
ntfs_debug("Managed to lock extent mft record 0x%lx, write it.",
mft_no);
@@ -1103,7 +1103,7 @@ BOOL ntfs_may_write_mft_record(ntfs_volume *vol, const unsigned long mft_no,
* the locked extent ntfs inode.
*/
*locked_ni = eni;
- return TRUE;
+ return true;
}
static const char *es = " Leaving inconsistent metadata. Unmount and run "
@@ -1354,7 +1354,7 @@ static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol)
ntfs_unmap_page(page);
/* Allocate a cluster from the DATA_ZONE. */
rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE,
- TRUE);
+ true);
if (IS_ERR(rl2)) {
up_write(&mftbmp_ni->runlist.lock);
ntfs_error(vol->sb, "Failed to allocate a cluster for "
@@ -1724,7 +1724,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol)
ATTR_RECORD *a = NULL;
int ret, mp_size;
u32 old_alen = 0;
- BOOL mp_rebuilt = FALSE;
+ bool mp_rebuilt = false;
ntfs_debug("Extending mft data allocation.");
mft_ni = NTFS_I(vol->mft_ino);
@@ -1780,7 +1780,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol)
old_last_vcn = rl[1].vcn;
do {
rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE,
- TRUE);
+ true);
if (likely(!IS_ERR(rl2)))
break;
if (PTR_ERR(rl2) != -ENOSPC || nr == min_nr) {
@@ -1884,7 +1884,7 @@ static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol)
ret = -EOPNOTSUPP;
goto undo_alloc;
}
- mp_rebuilt = TRUE;
+ mp_rebuilt = true;
/* Generate the mapping pairs array directly into the attr record. */
ret = ntfs_mapping_pairs_build(vol, (u8*)a +
le16_to_cpu(a->data.non_resident.mapping_pairs_offset),
@@ -2255,7 +2255,7 @@ ntfs_inode *ntfs_mft_record_alloc(ntfs_volume *vol, const int mode,
unsigned int ofs;
int err;
le16 seq_no, usn;
- BOOL record_formatted = FALSE;
+ bool record_formatted = false;
if (base_ni) {
ntfs_debug("Entering (allocating an extent mft record for "
@@ -2454,7 +2454,7 @@ have_alloc_rec:
mft_ni->initialized_size = new_initialized_size;
}
write_unlock_irqrestore(&mft_ni->size_lock, flags);
- record_formatted = TRUE;
+ record_formatted = true;
/* Update the mft data attribute record to reflect the new sizes. */
m = map_mft_record(mft_ni);
if (IS_ERR(m)) {
@@ -2638,11 +2638,6 @@ mft_rec_already_initialized:
}
vi->i_ino = bit;
/*
- * This is the optimal IO size (for stat), not the fs block
- * size.
- */
- vi->i_blksize = PAGE_CACHE_SIZE;
- /*
* This is for checking whether an inode has changed w.r.t. a
* file so that the file can be updated if necessary (compare
* with f_version).
@@ -2893,7 +2888,7 @@ rollback:
if (!(base_ni->nr_extents & 3)) {
int new_size = (base_ni->nr_extents + 4) * sizeof(ntfs_inode*);
- extent_nis = (ntfs_inode**)kmalloc(new_size, GFP_NOFS);
+ extent_nis = kmalloc(new_size, GFP_NOFS);
if (unlikely(!extent_nis)) {
ntfs_error(vol->sb, "Failed to allocate internal "
"buffer during rollback.%s", es);
diff --git a/fs/ntfs/mft.h b/fs/ntfs/mft.h
index 639cd1bab08b..b52bf87b99de 100644
--- a/fs/ntfs/mft.h
+++ b/fs/ntfs/mft.h
@@ -111,7 +111,7 @@ static inline int write_mft_record(ntfs_inode *ni, MFT_RECORD *m, int sync)
return err;
}
-extern BOOL ntfs_may_write_mft_record(ntfs_volume *vol,
+extern bool ntfs_may_write_mft_record(ntfs_volume *vol,
const unsigned long mft_no, const MFT_RECORD *m,
ntfs_inode **locked_ni);
diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h
index ddd3d503097c..a12847ae467d 100644
--- a/fs/ntfs/ntfs.h
+++ b/fs/ntfs/ntfs.h
@@ -105,7 +105,7 @@ extern int pre_write_mst_fixup(NTFS_RECORD *b, const u32 size);
extern void post_write_mst_fixup(NTFS_RECORD *b);
/* From fs/ntfs/unistr.c */
-extern BOOL ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
+extern bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
const ntfschar *s2, size_t s2_len,
const IGNORE_CASE_BOOL ic,
const ntfschar *upcase, const u32 upcase_size);
diff --git a/fs/ntfs/quota.c b/fs/ntfs/quota.c
index d0ef4182147b..d80e3315cab0 100644
--- a/fs/ntfs/quota.c
+++ b/fs/ntfs/quota.c
@@ -31,10 +31,10 @@
* ntfs_mark_quotas_out_of_date - mark the quotas out of date on an ntfs volume
* @vol: ntfs volume on which to mark the quotas out of date
*
- * Mark the quotas out of date on the ntfs volume @vol and return TRUE on
- * success and FALSE on error.
+ * Mark the quotas out of date on the ntfs volume @vol and return 'true' on
+ * success and 'false' on error.
*/
-BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
+bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
{
ntfs_index_context *ictx;
QUOTA_CONTROL_ENTRY *qce;
@@ -46,7 +46,7 @@ BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol)
goto done;
if (!vol->quota_ino || !vol->quota_q_ino) {
ntfs_error(vol->sb, "Quota inodes are not open.");
- return FALSE;
+ return false;
}
mutex_lock(&vol->quota_q_ino->i_mutex);
ictx = ntfs_index_ctx_get(NTFS_I(vol->quota_q_ino));
@@ -106,12 +106,12 @@ set_done:
NVolSetQuotaOutOfDate(vol);
done:
ntfs_debug("Done.");
- return TRUE;
+ return true;
err_out:
if (ictx)
ntfs_index_ctx_put(ictx);
mutex_unlock(&vol->quota_q_ino->i_mutex);
- return FALSE;
+ return false;
}
#endif /* NTFS_RW */
diff --git a/fs/ntfs/quota.h b/fs/ntfs/quota.h
index 40e4763aa222..4cbe5594c0b0 100644
--- a/fs/ntfs/quota.h
+++ b/fs/ntfs/quota.h
@@ -28,7 +28,7 @@
#include "types.h"
#include "volume.h"
-extern BOOL ntfs_mark_quotas_out_of_date(ntfs_volume *vol);
+extern bool ntfs_mark_quotas_out_of_date(ntfs_volume *vol);
#endif /* NTFS_RW */
diff --git a/fs/ntfs/runlist.c b/fs/ntfs/runlist.c
index eb52b801512b..9afd72c7ad0d 100644
--- a/fs/ntfs/runlist.c
+++ b/fs/ntfs/runlist.c
@@ -149,10 +149,10 @@ static inline runlist_element *ntfs_rl_realloc_nofail(runlist_element *rl,
*
* It is up to the caller to serialize access to the runlists @dst and @src.
*
- * Return: TRUE Success, the runlists can be merged.
- * FALSE Failure, the runlists cannot be merged.
+ * Return: true Success, the runlists can be merged.
+ * false Failure, the runlists cannot be merged.
*/
-static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst,
+static inline bool ntfs_are_rl_mergeable(runlist_element *dst,
runlist_element *src)
{
BUG_ON(!dst);
@@ -160,19 +160,19 @@ static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst,
/* We can merge unmapped regions even if they are misaligned. */
if ((dst->lcn == LCN_RL_NOT_MAPPED) && (src->lcn == LCN_RL_NOT_MAPPED))
- return TRUE;
+ return true;
/* If the runs are misaligned, we cannot merge them. */
if ((dst->vcn + dst->length) != src->vcn)
- return FALSE;
+ return false;
/* If both runs are non-sparse and contiguous, we can merge them. */
if ((dst->lcn >= 0) && (src->lcn >= 0) &&
((dst->lcn + dst->length) == src->lcn))
- return TRUE;
+ return true;
/* If we are merging two holes, we can merge them. */
if ((dst->lcn == LCN_HOLE) && (src->lcn == LCN_HOLE))
- return TRUE;
+ return true;
/* Cannot merge. */
- return FALSE;
+ return false;
}
/**
@@ -218,7 +218,7 @@ static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src)
static inline runlist_element *ntfs_rl_append(runlist_element *dst,
int dsize, runlist_element *src, int ssize, int loc)
{
- BOOL right = FALSE; /* Right end of @src needs merging. */
+ bool right = false; /* Right end of @src needs merging. */
int marker; /* End of the inserted runs. */
BUG_ON(!dst);
@@ -285,8 +285,8 @@ static inline runlist_element *ntfs_rl_append(runlist_element *dst,
static inline runlist_element *ntfs_rl_insert(runlist_element *dst,
int dsize, runlist_element *src, int ssize, int loc)
{
- BOOL left = FALSE; /* Left end of @src needs merging. */
- BOOL disc = FALSE; /* Discontinuity between @dst and @src. */
+ bool left = false; /* Left end of @src needs merging. */
+ bool disc = false; /* Discontinuity between @dst and @src. */
int marker; /* End of the inserted runs. */
BUG_ON(!dst);
@@ -382,8 +382,8 @@ static inline runlist_element *ntfs_rl_replace(runlist_element *dst,
int dsize, runlist_element *src, int ssize, int loc)
{
signed delta;
- BOOL left = FALSE; /* Left end of @src needs merging. */
- BOOL right = FALSE; /* Right end of @src needs merging. */
+ bool left = false; /* Left end of @src needs merging. */
+ bool right = false; /* Right end of @src needs merging. */
int tail; /* Start of tail of @dst. */
int marker; /* End of the inserted runs. */
@@ -620,8 +620,8 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl,
;
{
- BOOL start;
- BOOL finish;
+ bool start;
+ bool finish;
int ds = dend + 1; /* Number of elements in drl & srl */
int ss = sfinal - sstart + 1;
@@ -635,7 +635,7 @@ runlist_element *ntfs_runlists_merge(runlist_element *drl,
if (finish && !drl[dins].length)
ss++;
if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn))
- finish = FALSE;
+ finish = false;
#if 0
ntfs_debug("dfinal = %i, dend = %i", dfinal, dend);
ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send);
@@ -1134,7 +1134,7 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
{
LCN prev_lcn;
int rls;
- BOOL the_end = FALSE;
+ bool the_end = false;
BUG_ON(first_vcn < 0);
BUG_ON(last_vcn < -1);
@@ -1168,7 +1168,7 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
s64 s1 = last_vcn + 1;
if (unlikely(rl[1].vcn > s1))
length = s1 - rl->vcn;
- the_end = TRUE;
+ the_end = true;
}
delta = first_vcn - rl->vcn;
/* Header byte + length. */
@@ -1204,7 +1204,7 @@ int ntfs_get_size_for_mapping_pairs(const ntfs_volume *vol,
s64 s1 = last_vcn + 1;
if (unlikely(rl[1].vcn > s1))
length = s1 - rl->vcn;
- the_end = TRUE;
+ the_end = true;
}
/* Header byte + length. */
rls += 1 + ntfs_get_nr_significant_bytes(length);
@@ -1327,7 +1327,7 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
LCN prev_lcn;
s8 *dst_max, *dst_next;
int err = -ENOSPC;
- BOOL the_end = FALSE;
+ bool the_end = false;
s8 len_len, lcn_len;
BUG_ON(first_vcn < 0);
@@ -1370,7 +1370,7 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
s64 s1 = last_vcn + 1;
if (unlikely(rl[1].vcn > s1))
length = s1 - rl->vcn;
- the_end = TRUE;
+ the_end = true;
}
delta = first_vcn - rl->vcn;
/* Write length. */
@@ -1422,7 +1422,7 @@ int ntfs_mapping_pairs_build(const ntfs_volume *vol, s8 *dst,
s64 s1 = last_vcn + 1;
if (unlikely(rl[1].vcn > s1))
length = s1 - rl->vcn;
- the_end = TRUE;
+ the_end = true;
}
/* Write length. */
len_len = ntfs_write_significant_bytes(dst + 1, dst_max,
@@ -1541,7 +1541,7 @@ int ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist,
*/
if (rl->length) {
runlist_element *trl;
- BOOL is_end;
+ bool is_end;
ntfs_debug("Shrinking runlist.");
/* Determine the runlist size. */
@@ -1555,11 +1555,11 @@ int ntfs_rl_truncate_nolock(const ntfs_volume *vol, runlist *const runlist,
* If a run was partially truncated, make the following runlist
* element a terminator.
*/
- is_end = FALSE;
+ is_end = false;
if (rl->length) {
rl++;
if (!rl->length)
- is_end = TRUE;
+ is_end = true;
rl->vcn = new_length;
rl->length = 0;
}
@@ -1648,7 +1648,7 @@ int ntfs_rl_punch_nolock(const ntfs_volume *vol, runlist *const runlist,
s64 delta;
runlist_element *rl, *rl_end, *rl_real_end, *trl;
int old_size;
- BOOL lcn_fixup = FALSE;
+ bool lcn_fixup = false;
ntfs_debug("Entering for start 0x%llx, length 0x%llx.",
(long long)start, (long long)length);
@@ -1862,7 +1862,7 @@ split_end:
if (rl->lcn >= 0) {
rl->lcn -= delta;
/* Need this in case the lcn just became negative. */
- lcn_fixup = TRUE;
+ lcn_fixup = true;
}
rl->length += delta;
goto split_end;
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 74e0ee8fce72..03a391ac7145 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -74,18 +74,18 @@ const option_t on_errors_arr[] = {
*
* Copied from old ntfs driver (which copied from vfat driver).
*/
-static int simple_getbool(char *s, BOOL *setval)
+static int simple_getbool(char *s, bool *setval)
{
if (s) {
if (!strcmp(s, "1") || !strcmp(s, "yes") || !strcmp(s, "true"))
- *setval = TRUE;
+ *setval = true;
else if (!strcmp(s, "0") || !strcmp(s, "no") ||
!strcmp(s, "false"))
- *setval = FALSE;
+ *setval = false;
else
return 0;
} else
- *setval = TRUE;
+ *setval = true;
return 1;
}
@@ -96,7 +96,7 @@ static int simple_getbool(char *s, BOOL *setval)
*
* Parse the recognized options in @opt for the ntfs volume described by @vol.
*/
-static BOOL parse_options(ntfs_volume *vol, char *opt)
+static bool parse_options(ntfs_volume *vol, char *opt)
{
char *p, *v, *ov;
static char *utf8 = "utf8";
@@ -137,7 +137,7 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
}
#define NTFS_GETOPT_BOOL(option, variable) \
if (!strcmp(p, option)) { \
- BOOL val; \
+ bool val; \
if (!simple_getbool(v, &val)) \
goto needs_bool; \
variable = val; \
@@ -170,7 +170,7 @@ static BOOL parse_options(ntfs_volume *vol, char *opt)
else NTFS_GETOPT_OCTAL("fmask", fmask)
else NTFS_GETOPT_OCTAL("dmask", dmask)
else NTFS_GETOPT("mft_zone_multiplier", mft_zone_multiplier)
- else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, TRUE)
+ else NTFS_GETOPT_WITH_DEFAULT("sloppy", sloppy, true)
else NTFS_GETOPT_BOOL("show_sys_files", show_sys_files)
else NTFS_GETOPT_BOOL("case_sensitive", case_sensitive)
else NTFS_GETOPT_BOOL("disable_sparse", disable_sparse)
@@ -194,7 +194,7 @@ use_utf8:
if (!old_nls) {
ntfs_error(vol->sb, "NLS character set "
"%s not found.", v);
- return FALSE;
+ return false;
}
ntfs_error(vol->sb, "NLS character set %s not "
"found. Using previous one %s.",
@@ -205,14 +205,14 @@ use_utf8:
unload_nls(old_nls);
}
} else if (!strcmp(p, "utf8")) {
- BOOL val = FALSE;
+ bool val = false;
ntfs_warning(vol->sb, "Option utf8 is no longer "
"supported, using option nls=utf8. Please "
"use option nls=utf8 in the future and "
"make sure utf8 is compiled either as a "
"module or into the kernel.");
if (!v || !*v)
- val = TRUE;
+ val = true;
else if (!simple_getbool(v, &val))
goto needs_bool;
if (val) {
@@ -231,7 +231,7 @@ use_utf8:
}
no_mount_options:
if (errors && !sloppy)
- return FALSE;
+ return false;
if (sloppy)
ntfs_warning(vol->sb, "Sloppy option given. Ignoring "
"unrecognized mount option(s) and continuing.");
@@ -240,14 +240,14 @@ no_mount_options:
if (!on_errors) {
ntfs_error(vol->sb, "Invalid errors option argument "
"or bug in options parser.");
- return FALSE;
+ return false;
}
}
if (nls_map) {
if (vol->nls_map && vol->nls_map != nls_map) {
ntfs_error(vol->sb, "Cannot change NLS character set "
"on remount.");
- return FALSE;
+ return false;
} /* else (!vol->nls_map) */
ntfs_debug("Using NLS character set %s.", nls_map->charset);
vol->nls_map = nls_map;
@@ -257,7 +257,7 @@ no_mount_options:
if (!vol->nls_map) {
ntfs_error(vol->sb, "Failed to load default "
"NLS character set.");
- return FALSE;
+ return false;
}
ntfs_debug("Using default NLS character set (%s).",
vol->nls_map->charset);
@@ -268,7 +268,7 @@ no_mount_options:
mft_zone_multiplier) {
ntfs_error(vol->sb, "Cannot change mft_zone_multiplier "
"on remount.");
- return FALSE;
+ return false;
}
if (mft_zone_multiplier < 1 || mft_zone_multiplier > 4) {
ntfs_error(vol->sb, "Invalid mft_zone_multiplier. "
@@ -318,16 +318,16 @@ no_mount_options:
NVolSetSparseEnabled(vol);
}
}
- return TRUE;
+ return true;
needs_arg:
ntfs_error(vol->sb, "The %s option requires an argument.", p);
- return FALSE;
+ return false;
needs_bool:
ntfs_error(vol->sb, "The %s option requires a boolean argument.", p);
- return FALSE;
+ return false;
needs_val:
ntfs_error(vol->sb, "Invalid %s option argument: %s", p, ov);
- return FALSE;
+ return false;
}
#ifdef NTFS_RW
@@ -543,16 +543,16 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
* is_boot_sector_ntfs - check whether a boot sector is a valid NTFS boot sector
* @sb: Super block of the device to which @b belongs.
* @b: Boot sector of device @sb to check.
- * @silent: If TRUE, all output will be silenced.
+ * @silent: If 'true', all output will be silenced.
*
* is_boot_sector_ntfs() checks whether the boot sector @b is a valid NTFS boot
- * sector. Returns TRUE if it is valid and FALSE if not.
+ * sector. Returns 'true' if it is valid and 'false' if not.
*
* @sb is only needed for warning/error output, i.e. it can be NULL when silent
- * is TRUE.
+ * is 'true'.
*/
-static BOOL is_boot_sector_ntfs(const struct super_block *sb,
- const NTFS_BOOT_SECTOR *b, const BOOL silent)
+static bool is_boot_sector_ntfs(const struct super_block *sb,
+ const NTFS_BOOT_SECTOR *b, const bool silent)
{
/*
* Check that checksum == sum of u32 values from b to the checksum
@@ -620,9 +620,9 @@ static BOOL is_boot_sector_ntfs(const struct super_block *sb,
*/
if (!silent && b->end_of_sector_marker != const_cpu_to_le16(0xaa55))
ntfs_warning(sb, "Invalid end of sector marker.");
- return TRUE;
+ return true;
not_ntfs:
- return FALSE;
+ return false;
}
/**
@@ -732,9 +732,9 @@ hotfix_primary_boot_sector:
* @b: boot sector to parse
*
* Parse the ntfs boot sector @b and store all imporant information therein in
- * the ntfs super block @vol. Return TRUE on success and FALSE on error.
+ * the ntfs super block @vol. Return 'true' on success and 'false' on error.
*/
-static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
+static bool parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
{
unsigned int sectors_per_cluster_bits, nr_hidden_sects;
int clusters_per_mft_record, clusters_per_index_record;
@@ -751,7 +751,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
"device block size (%lu). This is not "
"supported. Sorry.", vol->sector_size,
vol->sb->s_blocksize);
- return FALSE;
+ return false;
}
ntfs_debug("sectors_per_cluster = 0x%x", b->bpb.sectors_per_cluster);
sectors_per_cluster_bits = ffs(b->bpb.sectors_per_cluster) - 1;
@@ -770,7 +770,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
ntfs_error(vol->sb, "Cluster size (%i) is smaller than the "
"sector size (%i). This is not supported. "
"Sorry.", vol->cluster_size, vol->sector_size);
- return FALSE;
+ return false;
}
clusters_per_mft_record = b->clusters_per_mft_record;
ntfs_debug("clusters_per_mft_record = %i (0x%x)",
@@ -802,7 +802,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
"PAGE_CACHE_SIZE on your system (%lu). "
"This is not supported. Sorry.",
vol->mft_record_size, PAGE_CACHE_SIZE);
- return FALSE;
+ return false;
}
/* We cannot support mft record sizes below the sector size. */
if (vol->mft_record_size < vol->sector_size) {
@@ -810,7 +810,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
"sector size (%i). This is not supported. "
"Sorry.", vol->mft_record_size,
vol->sector_size);
- return FALSE;
+ return false;
}
clusters_per_index_record = b->clusters_per_index_record;
ntfs_debug("clusters_per_index_record = %i (0x%x)",
@@ -841,7 +841,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
"the sector size (%i). This is not "
"supported. Sorry.", vol->index_record_size,
vol->sector_size);
- return FALSE;
+ return false;
}
/*
* Get the size of the volume in clusters and check for 64-bit-ness.
@@ -851,7 +851,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
ll = sle64_to_cpu(b->number_of_sectors) >> sectors_per_cluster_bits;
if ((u64)ll >= 1ULL << 32) {
ntfs_error(vol->sb, "Cannot handle 64-bit clusters. Sorry.");
- return FALSE;
+ return false;
}
vol->nr_clusters = ll;
ntfs_debug("vol->nr_clusters = 0x%llx", (long long)vol->nr_clusters);
@@ -867,7 +867,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
"Maximum supported is 2TiB. Sorry.",
(unsigned long long)ll >> (40 -
vol->cluster_size_bits));
- return FALSE;
+ return false;
}
}
ll = sle64_to_cpu(b->mft_lcn);
@@ -875,7 +875,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
ntfs_error(vol->sb, "MFT LCN (%lli, 0x%llx) is beyond end of "
"volume. Weird.", (unsigned long long)ll,
(unsigned long long)ll);
- return FALSE;
+ return false;
}
vol->mft_lcn = ll;
ntfs_debug("vol->mft_lcn = 0x%llx", (long long)vol->mft_lcn);
@@ -884,7 +884,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
ntfs_error(vol->sb, "MFTMirr LCN (%lli, 0x%llx) is beyond end "
"of volume. Weird.", (unsigned long long)ll,
(unsigned long long)ll);
- return FALSE;
+ return false;
}
vol->mftmirr_lcn = ll;
ntfs_debug("vol->mftmirr_lcn = 0x%llx", (long long)vol->mftmirr_lcn);
@@ -907,7 +907,7 @@ static BOOL parse_ntfs_boot_sector(ntfs_volume *vol, const NTFS_BOOT_SECTOR *b)
vol->serial_no = le64_to_cpu(b->volume_serial_number);
ntfs_debug("vol->serial_no = 0x%llx",
(unsigned long long)vol->serial_no);
- return TRUE;
+ return true;
}
/**
@@ -1000,9 +1000,9 @@ static void ntfs_setup_allocators(ntfs_volume *vol)
* load_and_init_mft_mirror - load and setup the mft mirror inode for a volume
* @vol: ntfs super block describing device whose mft mirror to load
*
- * Return TRUE on success or FALSE on error.
+ * Return 'true' on success or 'false' on error.
*/
-static BOOL load_and_init_mft_mirror(ntfs_volume *vol)
+static bool load_and_init_mft_mirror(ntfs_volume *vol)
{
struct inode *tmp_ino;
ntfs_inode *tmp_ni;
@@ -1014,7 +1014,7 @@ static BOOL load_and_init_mft_mirror(ntfs_volume *vol)
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
/* Caller will display error message. */
- return FALSE;
+ return false;
}
/*
* Re-initialize some specifics about $MFTMirr's inode as
@@ -1041,20 +1041,20 @@ static BOOL load_and_init_mft_mirror(ntfs_volume *vol)
tmp_ni->itype.index.block_size_bits = vol->mft_record_size_bits;
vol->mftmirr_ino = tmp_ino;
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
/**
* check_mft_mirror - compare contents of the mft mirror with the mft
* @vol: ntfs super block describing device whose mft mirror to check
*
- * Return TRUE on success or FALSE on error.
+ * Return 'true' on success or 'false' on error.
*
* Note, this function also results in the mft mirror runlist being completely
* mapped into memory. The mft mirror write code requires this and will BUG()
* should it find an unmapped runlist element.
*/
-static BOOL check_mft_mirror(ntfs_volume *vol)
+static bool check_mft_mirror(ntfs_volume *vol)
{
struct super_block *sb = vol->sb;
ntfs_inode *mirr_ni;
@@ -1086,7 +1086,7 @@ static BOOL check_mft_mirror(ntfs_volume *vol)
index);
if (IS_ERR(mft_page)) {
ntfs_error(sb, "Failed to read $MFT.");
- return FALSE;
+ return false;
}
kmft = page_address(mft_page);
/* Get the $MFTMirr page. */
@@ -1110,7 +1110,7 @@ mm_unmap_out:
ntfs_unmap_page(mirr_page);
mft_unmap_out:
ntfs_unmap_page(mft_page);
- return FALSE;
+ return false;
}
}
/* Do not check the mirror record if it is not in use. */
@@ -1169,21 +1169,21 @@ mft_unmap_out:
ntfs_error(sb, "$MFTMirr location mismatch. "
"Run chkdsk.");
up_read(&mirr_ni->runlist.lock);
- return FALSE;
+ return false;
}
} while (rl2[i++].length);
up_read(&mirr_ni->runlist.lock);
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
/**
* load_and_check_logfile - load and check the logfile inode for a volume
* @vol: ntfs super block describing device whose logfile to load
*
- * Return TRUE on success or FALSE on error.
+ * Return 'true' on success or 'false' on error.
*/
-static BOOL load_and_check_logfile(ntfs_volume *vol,
+static bool load_and_check_logfile(ntfs_volume *vol,
RESTART_PAGE_HEADER **rp)
{
struct inode *tmp_ino;
@@ -1194,17 +1194,17 @@ static BOOL load_and_check_logfile(ntfs_volume *vol,
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
/* Caller will display error message. */
- return FALSE;
+ return false;
}
if (!ntfs_check_logfile(tmp_ino, rp)) {
iput(tmp_ino);
/* ntfs_check_logfile() will have displayed error output. */
- return FALSE;
+ return false;
}
NInoSetSparseDisabled(NTFS_I(tmp_ino));
vol->logfile_ino = tmp_ino;
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
#define NTFS_HIBERFIL_HEADER_SIZE 4096
@@ -1329,10 +1329,10 @@ iput_out:
* load_and_init_quota - load and setup the quota file for a volume if present
* @vol: ntfs super block describing device whose quota file to load
*
- * Return TRUE on success or FALSE on error. If $Quota is not present, we
+ * Return 'true' on success or 'false' on error. If $Quota is not present, we
* leave vol->quota_ino as NULL and return success.
*/
-static BOOL load_and_init_quota(ntfs_volume *vol)
+static bool load_and_init_quota(ntfs_volume *vol)
{
MFT_REF mref;
struct inode *tmp_ino;
@@ -1366,11 +1366,11 @@ static BOOL load_and_init_quota(ntfs_volume *vol)
* not enabled.
*/
NVolSetQuotaOutOfDate(vol);
- return TRUE;
+ return true;
}
/* A real error occured. */
ntfs_error(vol->sb, "Failed to find inode number for $Quota.");
- return FALSE;
+ return false;
}
/* We do not care for the type of match that was found. */
kfree(name);
@@ -1380,25 +1380,25 @@ static BOOL load_and_init_quota(ntfs_volume *vol)
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(vol->sb, "Failed to load $Quota.");
- return FALSE;
+ return false;
}
vol->quota_ino = tmp_ino;
/* Get the $Q index allocation attribute. */
tmp_ino = ntfs_index_iget(vol->quota_ino, Q, 2);
if (IS_ERR(tmp_ino)) {
ntfs_error(vol->sb, "Failed to load $Quota/$Q index.");
- return FALSE;
+ return false;
}
vol->quota_q_ino = tmp_ino;
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
/**
* load_and_init_usnjrnl - load and setup the transaction log if present
* @vol: ntfs super block describing device whose usnjrnl file to load
*
- * Return TRUE on success or FALSE on error.
+ * Return 'true' on success or 'false' on error.
*
* If $UsnJrnl is not present or in the process of being disabled, we set
* NVolUsnJrnlStamped() and return success.
@@ -1408,7 +1408,7 @@ static BOOL load_and_init_quota(ntfs_volume *vol)
* stamped and nothing has been logged since, we also set NVolUsnJrnlStamped()
* and return success.
*/
-static BOOL load_and_init_usnjrnl(ntfs_volume *vol)
+static bool load_and_init_usnjrnl(ntfs_volume *vol)
{
MFT_REF mref;
struct inode *tmp_ino;
@@ -1450,12 +1450,12 @@ not_enabled:
* transaction logging is not enabled.
*/
NVolSetUsnJrnlStamped(vol);
- return TRUE;
+ return true;
}
/* A real error occured. */
ntfs_error(vol->sb, "Failed to find inode number for "
"$UsnJrnl.");
- return FALSE;
+ return false;
}
/* We do not care for the type of match that was found. */
kfree(name);
@@ -1465,7 +1465,7 @@ not_enabled:
if (!IS_ERR(tmp_ino))
iput(tmp_ino);
ntfs_error(vol->sb, "Failed to load $UsnJrnl.");
- return FALSE;
+ return false;
}
vol->usnjrnl_ino = tmp_ino;
/*
@@ -1483,7 +1483,7 @@ not_enabled:
if (IS_ERR(tmp_ino)) {
ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$Max "
"attribute.");
- return FALSE;
+ return false;
}
vol->usnjrnl_max_ino = tmp_ino;
if (unlikely(i_size_read(tmp_ino) < sizeof(USN_HEADER))) {
@@ -1491,14 +1491,14 @@ not_enabled:
"attribute (size is 0x%llx but should be at "
"least 0x%zx bytes).", i_size_read(tmp_ino),
sizeof(USN_HEADER));
- return FALSE;
+ return false;
}
/* Get the $DATA/$J attribute. */
tmp_ino = ntfs_attr_iget(vol->usnjrnl_ino, AT_DATA, J, 2);
if (IS_ERR(tmp_ino)) {
ntfs_error(vol->sb, "Failed to load $UsnJrnl/$DATA/$J "
"attribute.");
- return FALSE;
+ return false;
}
vol->usnjrnl_j_ino = tmp_ino;
/* Verify $J is non-resident and sparse. */
@@ -1506,14 +1506,14 @@ not_enabled:
if (unlikely(!NInoNonResident(tmp_ni) || !NInoSparse(tmp_ni))) {
ntfs_error(vol->sb, "$UsnJrnl/$DATA/$J attribute is resident "
"and/or not sparse.");
- return FALSE;
+ return false;
}
/* Read the USN_HEADER from $DATA/$Max. */
page = ntfs_map_page(vol->usnjrnl_max_ino->i_mapping, 0);
if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read from $UsnJrnl/$DATA/$Max "
"attribute.");
- return FALSE;
+ return false;
}
uh = (USN_HEADER*)page_address(page);
/* Sanity check the $Max. */
@@ -1524,7 +1524,7 @@ not_enabled:
(long long)sle64_to_cpu(uh->allocation_delta),
(long long)sle64_to_cpu(uh->maximum_size));
ntfs_unmap_page(page);
- return FALSE;
+ return false;
}
/*
* If the transaction log has been stamped and nothing has been written
@@ -1548,20 +1548,20 @@ not_enabled:
(long long)sle64_to_cpu(uh->lowest_valid_usn),
i_size_read(vol->usnjrnl_j_ino));
ntfs_unmap_page(page);
- return FALSE;
+ return false;
}
ntfs_unmap_page(page);
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
/**
* load_and_init_attrdef - load the attribute definitions table for a volume
* @vol: ntfs super block describing device whose attrdef to load
*
- * Return TRUE on success or FALSE on error.
+ * Return 'true' on success or 'false' on error.
*/
-static BOOL load_and_init_attrdef(ntfs_volume *vol)
+static bool load_and_init_attrdef(ntfs_volume *vol)
{
loff_t i_size;
struct super_block *sb = vol->sb;
@@ -1607,7 +1607,7 @@ read_partial_attrdef_page:
vol->attrdef_size = i_size;
ntfs_debug("Read %llu bytes from $AttrDef.", i_size);
iput(ino);
- return TRUE;
+ return true;
free_iput_failed:
ntfs_free(vol->attrdef);
vol->attrdef = NULL;
@@ -1615,7 +1615,7 @@ iput_failed:
iput(ino);
failed:
ntfs_error(sb, "Failed to initialize attribute definition table.");
- return FALSE;
+ return false;
}
#endif /* NTFS_RW */
@@ -1624,9 +1624,9 @@ failed:
* load_and_init_upcase - load the upcase table for an ntfs volume
* @vol: ntfs super block describing device whose upcase to load
*
- * Return TRUE on success or FALSE on error.
+ * Return 'true' on success or 'false' on error.
*/
-static BOOL load_and_init_upcase(ntfs_volume *vol)
+static bool load_and_init_upcase(ntfs_volume *vol)
{
loff_t i_size;
struct super_block *sb = vol->sb;
@@ -1682,7 +1682,7 @@ read_partial_upcase_page:
ntfs_debug("Using volume specified $UpCase since default is "
"not present.");
mutex_unlock(&ntfs_lock);
- return TRUE;
+ return true;
}
max = default_upcase_len;
if (max > vol->upcase_len)
@@ -1698,12 +1698,12 @@ read_partial_upcase_page:
mutex_unlock(&ntfs_lock);
ntfs_debug("Volume specified $UpCase matches default. Using "
"default.");
- return TRUE;
+ return true;
}
mutex_unlock(&ntfs_lock);
ntfs_debug("Using volume specified $UpCase since it does not match "
"the default.");
- return TRUE;
+ return true;
iput_upcase_failed:
iput(ino);
ntfs_free(vol->upcase);
@@ -1717,11 +1717,11 @@ upcase_failed:
mutex_unlock(&ntfs_lock);
ntfs_error(sb, "Failed to load $UpCase from the volume. Using "
"default.");
- return TRUE;
+ return true;
}
mutex_unlock(&ntfs_lock);
ntfs_error(sb, "Failed to initialize upcase table.");
- return FALSE;
+ return false;
}
/*
@@ -1739,9 +1739,9 @@ static struct lock_class_key
* Open the system files with normal access functions and complete setting up
* the ntfs super block @vol.
*
- * Return TRUE on success or FALSE on error.
+ * Return 'true' on success or 'false' on error.
*/
-static BOOL load_system_files(ntfs_volume *vol)
+static bool load_system_files(ntfs_volume *vol)
{
struct super_block *sb = vol->sb;
MFT_RECORD *m;
@@ -2067,7 +2067,7 @@ get_ctx_vol_failed:
#endif /* NTFS_RW */
/* If on NTFS versions before 3.0, we are done. */
if (unlikely(vol->major_ver < 3))
- return TRUE;
+ return true;
/* NTFS 3.0+ specific initialization. */
/* Get the security descriptors inode. */
vol->secure_ino = ntfs_iget(sb, FILE_Secure);
@@ -2173,7 +2173,7 @@ get_ctx_vol_failed:
NVolSetErrors(vol);
}
#endif /* NTFS_RW */
- return TRUE;
+ return true;
#ifdef NTFS_RW
iput_usnjrnl_err_out:
if (vol->usnjrnl_j_ino)
@@ -2229,7 +2229,7 @@ iput_mirr_err_out:
if (vol->mftmirr_ino)
iput(vol->mftmirr_ino);
#endif /* NTFS_RW */
- return FALSE;
+ return false;
}
/**
@@ -3248,32 +3248,14 @@ ictx_err_out:
static void __exit exit_ntfs_fs(void)
{
- int err = 0;
-
ntfs_debug("Unregistering NTFS driver.");
unregister_filesystem(&ntfs_fs_type);
-
- if (kmem_cache_destroy(ntfs_big_inode_cache) && (err = 1))
- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
- ntfs_big_inode_cache_name);
- if (kmem_cache_destroy(ntfs_inode_cache) && (err = 1))
- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
- ntfs_inode_cache_name);
- if (kmem_cache_destroy(ntfs_name_cache) && (err = 1))
- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
- ntfs_name_cache_name);
- if (kmem_cache_destroy(ntfs_attr_ctx_cache) && (err = 1))
- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
- ntfs_attr_ctx_cache_name);
- if (kmem_cache_destroy(ntfs_index_ctx_cache) && (err = 1))
- printk(KERN_CRIT "NTFS: Failed to destory %s.\n",
- ntfs_index_ctx_cache_name);
- if (err)
- printk(KERN_CRIT "NTFS: This causes memory to leak! There is "
- "probably a BUG in the driver! Please report "
- "you saw this message to "
- "linux-ntfs-dev@lists.sourceforge.net\n");
+ kmem_cache_destroy(ntfs_big_inode_cache);
+ kmem_cache_destroy(ntfs_inode_cache);
+ kmem_cache_destroy(ntfs_name_cache);
+ kmem_cache_destroy(ntfs_attr_ctx_cache);
+ kmem_cache_destroy(ntfs_index_ctx_cache);
/* Unregister the ntfs sysctls. */
ntfs_sysctl(0);
}
diff --git a/fs/ntfs/types.h b/fs/ntfs/types.h
index 6e4a7e3343f2..8c8053b66984 100644
--- a/fs/ntfs/types.h
+++ b/fs/ntfs/types.h
@@ -62,11 +62,6 @@ typedef s64 USN;
typedef sle64 leUSN;
typedef enum {
- FALSE = 0,
- TRUE = 1
-} BOOL;
-
-typedef enum {
CASE_SENSITIVE = 0,
IGNORE_CASE = 1,
} IGNORE_CASE_BOOL;
diff --git a/fs/ntfs/unistr.c b/fs/ntfs/unistr.c
index b123c0fa6bf6..6a495f7369f9 100644
--- a/fs/ntfs/unistr.c
+++ b/fs/ntfs/unistr.c
@@ -61,16 +61,16 @@ static const u8 legal_ansi_char_array[0x40] = {
* @upcase: upcase table (only if @ic == IGNORE_CASE)
* @upcase_size: length in Unicode characters of @upcase (if present)
*
- * Compare the names @s1 and @s2 and return TRUE (1) if the names are
- * identical, or FALSE (0) if they are not identical. If @ic is IGNORE_CASE,
+ * Compare the names @s1 and @s2 and return 'true' (1) if the names are
+ * identical, or 'false' (0) if they are not identical. If @ic is IGNORE_CASE,
* the @upcase table is used to performa a case insensitive comparison.
*/
-BOOL ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
+bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
const ntfschar *upcase, const u32 upcase_size)
{
if (s1_len != s2_len)
- return FALSE;
+ return false;
if (ic == CASE_SENSITIVE)
return !ntfs_ucsncmp(s1, s2, s1_len);
return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size);
@@ -350,7 +350,7 @@ int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
}
if (!ns) {
ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
- ns = (unsigned char*)kmalloc(ns_len + 1, GFP_NOFS);
+ ns = kmalloc(ns_len + 1, GFP_NOFS);
if (!ns)
goto mem_err_out;
}
@@ -365,7 +365,7 @@ retry: wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
else if (wc == -ENAMETOOLONG && ns != *outs) {
unsigned char *tc;
/* Grow in multiples of 64 bytes. */
- tc = (unsigned char*)kmalloc((ns_len + 64) &
+ tc = kmalloc((ns_len + 64) &
~63, GFP_NOFS);
if (tc) {
memcpy(tc, ns, ns_len);
diff --git a/fs/ntfs/usnjrnl.c b/fs/ntfs/usnjrnl.c
index 77773240d139..b2bc0d55b036 100644
--- a/fs/ntfs/usnjrnl.c
+++ b/fs/ntfs/usnjrnl.c
@@ -39,12 +39,12 @@
* @vol: ntfs volume on which to stamp the transaction log
*
* Stamp the transaction log ($UsnJrnl) on the ntfs volume @vol and return
- * TRUE on success and FALSE on error.
+ * 'true' on success and 'false' on error.
*
* This function assumes that the transaction log has already been loaded and
* consistency checked by a call to fs/ntfs/super.c::load_and_init_usnjrnl().
*/
-BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol)
+bool ntfs_stamp_usnjrnl(ntfs_volume *vol)
{
ntfs_debug("Entering.");
if (likely(!NVolUsnJrnlStamped(vol))) {
@@ -56,7 +56,7 @@ BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol)
if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read from "
"$UsnJrnl/$DATA/$Max attribute.");
- return FALSE;
+ return false;
}
uh = (USN_HEADER*)page_address(page);
stamp = get_current_ntfs_time();
@@ -78,7 +78,7 @@ BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol)
NVolSetUsnJrnlStamped(vol);
}
ntfs_debug("Done.");
- return TRUE;
+ return true;
}
#endif /* NTFS_RW */
diff --git a/fs/ntfs/usnjrnl.h b/fs/ntfs/usnjrnl.h
index ff988b0deb45..3a8af75351e8 100644
--- a/fs/ntfs/usnjrnl.h
+++ b/fs/ntfs/usnjrnl.h
@@ -198,7 +198,7 @@ typedef struct {
/* sizeof() = 60 (0x3c) bytes */
} __attribute__ ((__packed__)) USN_RECORD;
-extern BOOL ntfs_stamp_usnjrnl(ntfs_volume *vol);
+extern bool ntfs_stamp_usnjrnl(ntfs_volume *vol);
#endif /* NTFS_RW */
diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c
index e1fceb8aa32d..d11753c50bc1 100644
--- a/fs/ocfs2/cluster/nodemanager.c
+++ b/fs/ocfs2/cluster/nodemanager.c
@@ -152,14 +152,16 @@ static struct o2nm_node *o2nm_node_ip_tree_lookup(struct o2nm_cluster *cluster,
struct o2nm_node *node, *ret = NULL;
while (*p) {
+ int cmp;
+
parent = *p;
node = rb_entry(parent, struct o2nm_node, nd_ip_node);
- if (memcmp(&ip_needle, &node->nd_ipv4_address,
- sizeof(ip_needle)) < 0)
+ cmp = memcmp(&ip_needle, &node->nd_ipv4_address,
+ sizeof(ip_needle));
+ if (cmp < 0)
p = &(*p)->rb_left;
- else if (memcmp(&ip_needle, &node->nd_ipv4_address,
- sizeof(ip_needle)) > 0)
+ else if (cmp > 0)
p = &(*p)->rb_right;
else {
ret = node;
diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c
index 033ad1701232..16b8d1ba7066 100644
--- a/fs/ocfs2/dlm/dlmfs.c
+++ b/fs/ocfs2/dlm/dlmfs.c
@@ -335,11 +335,10 @@ static struct inode *dlmfs_get_root_inode(struct super_block *sb)
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_nlink++;
+ inc_nlink(inode);
inode->i_fop = &simple_dir_operations;
inode->i_op = &dlmfs_root_inode_operations;
@@ -362,7 +361,6 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
@@ -397,7 +395,7 @@ static struct inode *dlmfs_get_inode(struct inode *parent,
/* directory inodes start off with i_nlink ==
* 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
break;
}
@@ -451,7 +449,7 @@ static int dlmfs_mkdir(struct inode * dir,
}
ip->ip_dlm = dlm;
- dir->i_nlink++;
+ inc_nlink(dir);
d_instantiate(dentry, inode);
dget(dentry); /* Extra count - pin the dentry in core */
@@ -629,9 +627,7 @@ static void __exit exit_dlmfs_fs(void)
flush_workqueue(user_dlm_worker);
destroy_workqueue(user_dlm_worker);
- if (kmem_cache_destroy(dlmfs_inode_cache))
- printk(KERN_INFO "dlmfs_inode_cache: not all structures "
- "were freed\n");
+ kmem_cache_destroy(dlmfs_inode_cache);
}
MODULE_AUTHOR("Oracle");
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index de887063dcfc..8801e41afe80 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -2052,7 +2052,7 @@ static int ocfs2_dlm_debug_open(struct inode *inode, struct file *file)
mlog_errno(ret);
goto out;
}
- osb = (struct ocfs2_super *) inode->u.generic_ip;
+ osb = inode->i_private;
ocfs2_get_dlm_debug(osb->osb_dlm_debug);
priv->p_dlm_debug = osb->osb_dlm_debug;
INIT_LIST_HEAD(&priv->p_iter_res.l_debug_list);
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 2bbfa17090cf..1be74c4e7814 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -30,6 +30,7 @@
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/uio.h>
+#include <linux/sched.h>
#define MLOG_MASK_PREFIX ML_INODE
#include <cluster/masklog.h>
@@ -691,6 +692,12 @@ static int ocfs2_zero_extend(struct inode *inode,
}
start_off += sb->s_blocksize;
+
+ /*
+ * Very large extends have the potential to lock up
+ * the cpu for extended periods of time.
+ */
+ cond_resched();
}
out:
@@ -728,31 +735,36 @@ static int ocfs2_extend_file(struct inode *inode,
clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) -
OCFS2_I(inode)->ip_clusters;
- if (clusters_to_add) {
- /*
- * protect the pages that ocfs2_zero_extend is going to
- * be pulling into the page cache.. we do this before the
- * metadata extend so that we don't get into the situation
- * where we've extended the metadata but can't get the data
- * lock to zero.
- */
- ret = ocfs2_data_lock(inode, 1);
- if (ret < 0) {
- mlog_errno(ret);
- goto out;
- }
+ /*
+ * protect the pages that ocfs2_zero_extend is going to be
+ * pulling into the page cache.. we do this before the
+ * metadata extend so that we don't get into the situation
+ * where we've extended the metadata but can't get the data
+ * lock to zero.
+ */
+ ret = ocfs2_data_lock(inode, 1);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out;
+ }
+ if (clusters_to_add) {
ret = ocfs2_extend_allocation(inode, clusters_to_add);
if (ret < 0) {
mlog_errno(ret);
goto out_unlock;
}
+ }
- ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
- if (ret < 0) {
- mlog_errno(ret);
- goto out_unlock;
- }
+ /*
+ * Call this even if we don't add any clusters to the tree. We
+ * still need to zero the area between the old i_size and the
+ * new i_size.
+ */
+ ret = ocfs2_zero_extend(inode, (u64)new_i_size - tail_to_skip);
+ if (ret < 0) {
+ mlog_errno(ret);
+ goto out_unlock;
}
if (!tail_to_skip) {
@@ -764,8 +776,7 @@ static int ocfs2_extend_file(struct inode *inode,
}
out_unlock:
- if (clusters_to_add) /* this is the only case in which we lock */
- ocfs2_data_unlock(inode, 1);
+ ocfs2_data_unlock(inode, 1);
out:
return ret;
@@ -961,25 +972,23 @@ static inline int ocfs2_write_should_remove_suid(struct inode *inode)
}
static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
- const char __user *buf,
- size_t count,
+ const struct iovec *iov,
+ unsigned long nr_segs,
loff_t pos)
{
- struct iovec local_iov = { .iov_base = (void __user *)buf,
- .iov_len = count };
int ret, rw_level = -1, meta_level = -1, have_alloc_sem = 0;
u32 clusters;
struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
loff_t newsize, saved_pos;
- mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
- (unsigned int)count,
+ mlog_entry("(0x%p, %u, '%.*s')\n", filp,
+ (unsigned int)nr_segs,
filp->f_dentry->d_name.len,
filp->f_dentry->d_name.name);
/* happy write of zero bytes */
- if (count == 0)
+ if (iocb->ki_left == 0)
return 0;
if (!inode) {
@@ -1048,7 +1057,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
} else {
saved_pos = iocb->ki_pos;
}
- newsize = count + saved_pos;
+ newsize = iocb->ki_left + saved_pos;
mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
(long long) saved_pos, (long long) newsize,
@@ -1081,7 +1090,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
if (!clusters)
break;
- ret = ocfs2_extend_file(inode, NULL, newsize, count);
+ ret = ocfs2_extend_file(inode, NULL, newsize, iocb->ki_left);
if (ret < 0) {
if (ret != -ENOSPC)
mlog_errno(ret);
@@ -1098,7 +1107,7 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
/* communicate with ocfs2_dio_end_io */
ocfs2_iocb_set_rw_locked(iocb);
- ret = generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
+ ret = generic_file_aio_write_nolock(iocb, iov, nr_segs, iocb->ki_pos);
/* buffered aio wouldn't have proper lock coverage today */
BUG_ON(ret == -EIOCBQUEUED && !(filp->f_flags & O_DIRECT));
@@ -1132,16 +1141,16 @@ out:
}
static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
- char __user *buf,
- size_t count,
+ const struct iovec *iov,
+ unsigned long nr_segs,
loff_t pos)
{
int ret = 0, rw_level = -1, have_alloc_sem = 0;
struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
- mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", filp, buf,
- (unsigned int)count,
+ mlog_entry("(0x%p, %u, '%.*s')\n", filp,
+ (unsigned int)nr_segs,
filp->f_dentry->d_name.len,
filp->f_dentry->d_name.name);
@@ -1185,7 +1194,7 @@ static ssize_t ocfs2_file_aio_read(struct kiocb *iocb,
}
ocfs2_meta_unlock(inode, 0);
- ret = generic_file_aio_read(iocb, buf, count, iocb->ki_pos);
+ ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos);
if (ret == -EINVAL)
mlog(ML_ERROR, "generic_file_aio_read returned -EINVAL\n");
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 69d3db569166..16e8e74dc966 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -269,7 +269,6 @@ int ocfs2_populate_inode(struct inode *inode, struct ocfs2_dinode *fe,
inode->i_mode = le16_to_cpu(fe->i_mode);
inode->i_uid = le32_to_cpu(fe->i_uid);
inode->i_gid = le32_to_cpu(fe->i_gid);
- inode->i_blksize = (u32)osb->s_clustersize;
/* Fast symlinks will have i_size but no allocated clusters. */
if (S_ISLNK(inode->i_mode) && !fe->i_clusters)
@@ -1258,8 +1257,6 @@ leave:
void ocfs2_refresh_inode(struct inode *inode,
struct ocfs2_dinode *fe)
{
- struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-
spin_lock(&OCFS2_I(inode)->ip_lock);
OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters);
@@ -1270,7 +1267,6 @@ void ocfs2_refresh_inode(struct inode *inode,
inode->i_uid = le32_to_cpu(fe->i_uid);
inode->i_gid = le32_to_cpu(fe->i_gid);
inode->i_mode = le16_to_cpu(fe->i_mode);
- inode->i_blksize = (u32) osb->s_clustersize;
if (S_ISLNK(inode->i_mode) && le32_to_cpu(fe->i_clusters) == 0)
inode->i_blocks = 0;
else
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 849c3b4bb94a..a57b751d4f40 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -429,7 +429,7 @@ static int ocfs2_mknod(struct inode *dir,
mlog_errno(status);
goto leave;
}
- dir->i_nlink++;
+ inc_nlink(dir);
}
status = ocfs2_add_entry(handle, dentry, inode,
@@ -730,7 +730,7 @@ static int ocfs2_link(struct dentry *old_dentry,
goto bail;
}
- inode->i_nlink++;
+ inc_nlink(inode);
inode->i_ctime = CURRENT_TIME;
fe->i_links_count = cpu_to_le16(inode->i_nlink);
fe->i_ctime = cpu_to_le64(inode->i_ctime.tv_sec);
@@ -739,7 +739,7 @@ static int ocfs2_link(struct dentry *old_dentry,
err = ocfs2_journal_dirty(handle, fe_bh);
if (err < 0) {
le16_add_cpu(&fe->i_links_count, -1);
- inode->i_nlink--;
+ drop_nlink(inode);
mlog_errno(err);
goto bail;
}
@@ -749,7 +749,7 @@ static int ocfs2_link(struct dentry *old_dentry,
parent_fe_bh, de_bh);
if (err) {
le16_add_cpu(&fe->i_links_count, -1);
- inode->i_nlink--;
+ drop_nlink(inode);
mlog_errno(err);
goto bail;
}
@@ -795,11 +795,23 @@ static int ocfs2_remote_dentry_delete(struct dentry *dentry)
return ret;
}
+static inline int inode_is_unlinkable(struct inode *inode)
+{
+ if (S_ISDIR(inode->i_mode)) {
+ if (inode->i_nlink == 2)
+ return 1;
+ return 0;
+ }
+
+ if (inode->i_nlink == 1)
+ return 1;
+ return 0;
+}
+
static int ocfs2_unlink(struct inode *dir,
struct dentry *dentry)
{
int status;
- unsigned int saved_nlink = 0;
struct inode *inode = dentry->d_inode;
struct ocfs2_super *osb = OCFS2_SB(dir->i_sb);
u64 blkno;
@@ -874,16 +886,6 @@ static int ocfs2_unlink(struct inode *dir,
}
}
- /* There are still a few steps left until we can consider the
- * unlink to have succeeded. Save off nlink here before
- * modification so we can set it back in case we hit an issue
- * before commit. */
- saved_nlink = inode->i_nlink;
- if (S_ISDIR(inode->i_mode))
- inode->i_nlink = 0;
- else
- inode->i_nlink--;
-
status = ocfs2_remote_dentry_delete(dentry);
if (status < 0) {
/* This vote should succeed under all normal
@@ -892,7 +894,7 @@ static int ocfs2_unlink(struct inode *dir,
goto leave;
}
- if (!inode->i_nlink) {
+ if (inode_is_unlinkable(inode)) {
status = ocfs2_prepare_orphan_dir(osb, handle, inode,
orphan_name,
&orphan_entry_bh);
@@ -919,7 +921,7 @@ static int ocfs2_unlink(struct inode *dir,
fe = (struct ocfs2_dinode *) fe_bh->b_data;
- if (!inode->i_nlink) {
+ if (inode_is_unlinkable(inode)) {
status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name,
orphan_entry_bh);
if (status < 0) {
@@ -935,10 +937,10 @@ static int ocfs2_unlink(struct inode *dir,
goto leave;
}
- /* We can set nlink on the dinode now. clear the saved version
- * so that it doesn't get set later. */
+ if (S_ISDIR(inode->i_mode))
+ drop_nlink(inode);
+ drop_nlink(inode);
fe->i_links_count = cpu_to_le16(inode->i_nlink);
- saved_nlink = 0;
status = ocfs2_journal_dirty(handle, fe_bh);
if (status < 0) {
@@ -947,19 +949,16 @@ static int ocfs2_unlink(struct inode *dir,
}
if (S_ISDIR(inode->i_mode)) {
- dir->i_nlink--;
+ drop_nlink(dir);
status = ocfs2_mark_inode_dirty(handle, dir,
parent_node_bh);
if (status < 0) {
mlog_errno(status);
- dir->i_nlink++;
+ inc_nlink(dir);
}
}
leave:
- if (status < 0 && saved_nlink)
- inode->i_nlink = saved_nlink;
-
if (handle)
ocfs2_commit_trans(handle);
@@ -1086,14 +1085,6 @@ static int ocfs2_rename(struct inode *old_dir,
BUG();
}
- if (atomic_read(&old_dentry->d_count) > 2) {
- shrink_dcache_parent(old_dentry);
- if (atomic_read(&old_dentry->d_count) > 2) {
- status = -EBUSY;
- goto bail;
- }
- }
-
/* Assume a directory heirarchy thusly:
* a/b/c
* a/d
@@ -1382,7 +1373,7 @@ static int ocfs2_rename(struct inode *old_dir,
if (new_inode) {
new_inode->i_nlink--;
} else {
- new_dir->i_nlink++;
+ inc_nlink(new_dir);
mark_inode_dirty(new_dir);
}
}
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 4c29cd7cc8e6..76b46ebbb10c 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -339,7 +339,7 @@ static unsigned long long ocfs2_max_file_offset(unsigned int blockshift)
#if BITS_PER_LONG == 32
# if defined(CONFIG_LBD)
- BUG_ON(sizeof(sector_t) != 8);
+ BUILD_BUG_ON(sizeof(sector_t) != 8);
pagefactor = PAGE_CACHE_SIZE;
bitshift = BITS_PER_LONG;
# else
diff --git a/fs/open.c b/fs/open.c
index 303f06d2a7b9..89e0c237a636 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -6,7 +6,6 @@
#include <linux/string.h>
#include <linux/mm.h>
-#include <linux/utime.h>
#include <linux/file.h>
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
@@ -29,8 +28,6 @@
#include <linux/rcupdate.h>
#include <linux/audit.h>
-#include <asm/unistd.h>
-
int vfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int retval = -ENODEV;
@@ -353,137 +350,6 @@ asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
}
#endif
-#ifdef __ARCH_WANT_SYS_UTIME
-
-/*
- * sys_utime() can be implemented in user-level using sys_utimes().
- * Is this for backwards compatibility? If so, why not move it
- * into the appropriate arch directory (for those architectures that
- * need it).
- */
-
-/* If times==NULL, set access and modification to current time,
- * must be owner or have write permission.
- * Else, update from *times, must be owner or super user.
- */
-asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
-{
- int error;
- struct nameidata nd;
- struct inode * inode;
- struct iattr newattrs;
-
- error = user_path_walk(filename, &nd);
- if (error)
- goto out;
- inode = nd.dentry->d_inode;
-
- error = -EROFS;
- if (IS_RDONLY(inode))
- goto dput_and_out;
-
- /* Don't worry, the checks are done in inode_change_ok() */
- newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
- if (times) {
- error = -EPERM;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
- newattrs.ia_atime.tv_nsec = 0;
- if (!error)
- error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
- newattrs.ia_mtime.tv_nsec = 0;
- if (error)
- goto dput_and_out;
-
- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
- } else {
- error = -EACCES;
- if (IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- if (current->fsuid != inode->i_uid &&
- (error = vfs_permission(&nd, MAY_WRITE)) != 0)
- goto dput_and_out;
- }
- mutex_lock(&inode->i_mutex);
- error = notify_change(nd.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-dput_and_out:
- path_release(&nd);
-out:
- return error;
-}
-
-#endif
-
-/* If times==NULL, set access and modification to current time,
- * must be owner or have write permission.
- * Else, update from *times, must be owner or super user.
- */
-long do_utimes(int dfd, char __user *filename, struct timeval *times)
-{
- int error;
- struct nameidata nd;
- struct inode * inode;
- struct iattr newattrs;
-
- error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
-
- if (error)
- goto out;
- inode = nd.dentry->d_inode;
-
- error = -EROFS;
- if (IS_RDONLY(inode))
- goto dput_and_out;
-
- /* Don't worry, the checks are done in inode_change_ok() */
- newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
- if (times) {
- error = -EPERM;
- if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- newattrs.ia_atime.tv_sec = times[0].tv_sec;
- newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
- newattrs.ia_mtime.tv_sec = times[1].tv_sec;
- newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
- newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
- } else {
- error = -EACCES;
- if (IS_IMMUTABLE(inode))
- goto dput_and_out;
-
- if (current->fsuid != inode->i_uid &&
- (error = vfs_permission(&nd, MAY_WRITE)) != 0)
- goto dput_and_out;
- }
- mutex_lock(&inode->i_mutex);
- error = notify_change(nd.dentry, &newattrs);
- mutex_unlock(&inode->i_mutex);
-dput_and_out:
- path_release(&nd);
-out:
- return error;
-}
-
-asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
-{
- struct timeval times[2];
-
- if (utimes && copy_from_user(&times, utimes, sizeof(times)))
- return -EFAULT;
- return do_utimes(dfd, filename, utimes ? times : NULL);
-}
-
-asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
-{
- return sys_futimesat(AT_FDCWD, filename, utimes);
-}
-
-
/*
* access() needs to use the real uid/gid, not the effective uid/gid.
* We do this by temporarily clearing all FS-related capabilities and
@@ -520,15 +386,21 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
current->cap_effective = current->cap_permitted;
res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
- if (!res) {
- res = vfs_permission(&nd, mode);
- /* SuS v2 requires we report a read only fs too */
- if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode)
- && !special_file(nd.dentry->d_inode->i_mode))
- res = -EROFS;
- path_release(&nd);
- }
+ if (res)
+ goto out;
+
+ res = vfs_permission(&nd, mode);
+ /* SuS v2 requires we report a read only fs too */
+ if(res || !(mode & S_IWOTH) ||
+ special_file(nd.dentry->d_inode->i_mode))
+ goto out_path_release;
+
+ if(IS_RDONLY(nd.dentry->d_inode))
+ res = -EROFS;
+out_path_release:
+ path_release(&nd);
+out:
current->fsuid = old_fsuid;
current->fsgid = old_fsgid;
current->cap_effective = old_cap;
@@ -546,7 +418,8 @@ asmlinkage long sys_chdir(const char __user * filename)
struct nameidata nd;
int error;
- error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
+ error = __user_walk(filename,
+ LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
if (error)
goto out;
@@ -736,10 +609,11 @@ asmlinkage long sys_chown(const char __user * filename, uid_t user, gid_t group)
int error;
error = user_path_walk(filename, &nd);
- if (!error) {
- error = chown_common(nd.dentry, user, group);
- path_release(&nd);
- }
+ if (error)
+ goto out;
+ error = chown_common(nd.dentry, user, group);
+ path_release(&nd);
+out:
return error;
}
@@ -755,10 +629,10 @@ asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
error = __user_walk_fd(dfd, filename, follow, &nd);
- if (!error) {
- error = chown_common(nd.dentry, user, group);
- path_release(&nd);
- }
+ if (error)
+ goto out;
+ error = chown_common(nd.dentry, user, group);
+ path_release(&nd);
out:
return error;
}
@@ -769,10 +643,11 @@ asmlinkage long sys_lchown(const char __user * filename, uid_t user, gid_t group
int error;
error = user_path_walk_link(filename, &nd);
- if (!error) {
- error = chown_common(nd.dentry, user, group);
- path_release(&nd);
- }
+ if (error)
+ goto out;
+ error = chown_common(nd.dentry, user, group);
+ path_release(&nd);
+out:
return error;
}
@@ -781,15 +656,17 @@ asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
{
struct file * file;
int error = -EBADF;
+ struct dentry * dentry;
file = fget(fd);
- if (file) {
- struct dentry * dentry;
- dentry = file->f_dentry;
- audit_inode(NULL, dentry->d_inode);
- error = chown_common(dentry, user, group);
- fput(file);
- }
+ if (!file)
+ goto out;
+
+ dentry = file->f_dentry;
+ audit_inode(NULL, dentry->d_inode);
+ error = chown_common(dentry, user, group);
+ fput(file);
+out:
return error;
}
@@ -1172,6 +1049,7 @@ asmlinkage long sys_close(unsigned int fd)
struct file * filp;
struct files_struct *files = current->files;
struct fdtable *fdt;
+ int retval;
spin_lock(&files->file_lock);
fdt = files_fdtable(files);
@@ -1184,7 +1062,16 @@ asmlinkage long sys_close(unsigned int fd)
FD_CLR(fd, fdt->close_on_exec);
__put_unused_fd(files, fd);
spin_unlock(&files->file_lock);
- return filp_close(filp, files);
+ retval = filp_close(filp, files);
+
+ /* can't restart close syscall because file table entry was cleared */
+ if (unlikely(retval == -ERESTARTSYS ||
+ retval == -ERESTARTNOINTR ||
+ retval == -ERESTARTNOHAND ||
+ retval == -ERESTART_RESTARTBLOCK))
+ retval = -EINTR;
+
+ return retval;
out_unlock:
spin_unlock(&files->file_lock);
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index d713ce6b3e12..67e665fdb7fc 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -2,7 +2,7 @@
# Makefile for the linux kernel.
#
-obj-y := check.o
+obj-$(CONFIG_BLOCK) := check.o
obj-$(CONFIG_ACORN_PARTITION) += acorn.o
obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 51c6a748df49..6fb4b6150d77 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -376,18 +376,48 @@ static char *make_block_name(struct gendisk *disk)
return name;
}
-static void disk_sysfs_symlinks(struct gendisk *disk)
+static int disk_sysfs_symlinks(struct gendisk *disk)
{
struct device *target = get_device(disk->driverfs_dev);
+ int err;
+ char *disk_name = NULL;
+
if (target) {
- char *disk_name = make_block_name(disk);
- sysfs_create_link(&disk->kobj,&target->kobj,"device");
- if (disk_name) {
- sysfs_create_link(&target->kobj,&disk->kobj,disk_name);
- kfree(disk_name);
+ disk_name = make_block_name(disk);
+ if (!disk_name) {
+ err = -ENOMEM;
+ goto err_out;
}
+
+ err = sysfs_create_link(&disk->kobj, &target->kobj, "device");
+ if (err)
+ goto err_out_disk_name;
+
+ err = sysfs_create_link(&target->kobj, &disk->kobj, disk_name);
+ if (err)
+ goto err_out_dev_link;
}
- sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj, "subsystem");
+
+ err = sysfs_create_link(&disk->kobj, &block_subsys.kset.kobj,
+ "subsystem");
+ if (err)
+ goto err_out_disk_name_lnk;
+
+ kfree(disk_name);
+
+ return 0;
+
+err_out_disk_name_lnk:
+ if (target) {
+ sysfs_remove_link(&target->kobj, disk_name);
+err_out_dev_link:
+ sysfs_remove_link(&disk->kobj, "device");
+err_out_disk_name:
+ kfree(disk_name);
+err_out:
+ put_device(target);
+ }
+ return err;
}
/* Not exported, helper to add_disk(). */
@@ -406,7 +436,11 @@ void register_disk(struct gendisk *disk)
*s = '!';
if ((err = kobject_add(&disk->kobj)))
return;
- disk_sysfs_symlinks(disk);
+ err = disk_sysfs_symlinks(disk);
+ if (err) {
+ kobject_del(&disk->kobj);
+ return;
+ }
disk_sysfs_add_subdirs(disk);
/* No minors to use for partitions */
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c
index 63730282ad81..1bea610078b3 100644
--- a/fs/partitions/efi.c
+++ b/fs/partitions/efi.c
@@ -238,10 +238,9 @@ alloc_read_gpt_entries(struct block_device *bdev, gpt_header *gpt)
le32_to_cpu(gpt->sizeof_partition_entry);
if (!count)
return NULL;
- pte = kmalloc(count, GFP_KERNEL);
+ pte = kzalloc(count, GFP_KERNEL);
if (!pte)
return NULL;
- memset(pte, 0, count);
if (read_lba(bdev, le64_to_cpu(gpt->partition_entry_lba),
(u8 *) pte,
@@ -269,10 +268,9 @@ alloc_read_gpt_header(struct block_device *bdev, u64 lba)
if (!bdev)
return NULL;
- gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL);
+ gpt = kzalloc(sizeof (gpt_header), GFP_KERNEL);
if (!gpt)
return NULL;
- memset(gpt, 0, sizeof (gpt_header));
if (read_lba(bdev, lba, (u8 *) gpt,
sizeof (gpt_header)) < sizeof (gpt_header)) {
@@ -526,9 +524,8 @@ find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes)
lastlba = last_lba(bdev);
if (!force_gpt) {
/* This will be added to the EFI Spec. per Intel after v1.02. */
- legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL);
+ legacymbr = kzalloc(sizeof (*legacymbr), GFP_KERNEL);
if (legacymbr) {
- memset(legacymbr, 0, sizeof (*legacymbr));
read_lba(bdev, 0, (u8 *) legacymbr,
sizeof (*legacymbr));
good_pmbr = is_pmbr_valid(legacymbr, lastlba);
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c
index 7ab1c11dca4e..1a60926a4ccd 100644
--- a/fs/partitions/ldm.c
+++ b/fs/partitions/ldm.c
@@ -30,11 +30,6 @@
#include "check.h"
#include "msdos.h"
-typedef enum {
- FALSE = 0,
- TRUE = 1
-} BOOL;
-
/**
* ldm_debug/info/error/crit - Output an error message
* @f: A printf format string containing the message
@@ -103,24 +98,24 @@ static int ldm_parse_hexbyte (const u8 *src)
*
* N.B. The GUID need not be NULL terminated.
*
- * Return: TRUE @dest contains binary GUID
- * FALSE @dest contents are undefined
+ * Return: 'true' @dest contains binary GUID
+ * 'false' @dest contents are undefined
*/
-static BOOL ldm_parse_guid (const u8 *src, u8 *dest)
+static bool ldm_parse_guid (const u8 *src, u8 *dest)
{
static const int size[] = { 4, 2, 2, 2, 6 };
int i, j, v;
if (src[8] != '-' || src[13] != '-' ||
src[18] != '-' || src[23] != '-')
- return FALSE;
+ return false;
for (j = 0; j < 5; j++, src++)
for (i = 0; i < size[j]; i++, src+=2, *dest++ = v)
if ((v = ldm_parse_hexbyte (src)) < 0)
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
@@ -132,17 +127,17 @@ static BOOL ldm_parse_guid (const u8 *src, u8 *dest)
* This parses the LDM database PRIVHEAD structure supplied in @data and
* sets up the in-memory privhead structure @ph with the obtained information.
*
- * Return: TRUE @ph contains the PRIVHEAD data
- * FALSE @ph contents are undefined
+ * Return: 'true' @ph contains the PRIVHEAD data
+ * 'false' @ph contents are undefined
*/
-static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
+static bool ldm_parse_privhead (const u8 *data, struct privhead *ph)
{
BUG_ON (!data || !ph);
if (MAGIC_PRIVHEAD != BE64 (data)) {
ldm_error ("Cannot find PRIVHEAD structure. LDM database is"
" corrupt. Aborting.");
- return FALSE;
+ return false;
}
ph->ver_major = BE16 (data + 0x000C);
@@ -155,7 +150,7 @@ static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
ldm_error ("Expected PRIVHEAD version %d.%d, got %d.%d."
" Aborting.", 2, 11, ph->ver_major, ph->ver_minor);
- return FALSE;
+ return false;
}
if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
/* Warn the user and continue, carefully */
@@ -166,16 +161,16 @@ static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
if ((ph->logical_disk_size == 0) ||
(ph->logical_disk_start + ph->logical_disk_size > ph->config_start)) {
ldm_error ("PRIVHEAD disk size doesn't match real disk size");
- return FALSE;
+ return false;
}
if (!ldm_parse_guid (data + 0x0030, ph->disk_id)) {
ldm_error ("PRIVHEAD contains an invalid GUID.");
- return FALSE;
+ return false;
}
ldm_debug ("Parsed PRIVHEAD successfully.");
- return TRUE;
+ return true;
}
/**
@@ -189,16 +184,16 @@ static BOOL ldm_parse_privhead (const u8 *data, struct privhead *ph)
*
* N.B. The *_start and *_size values returned in @toc are not range-checked.
*
- * Return: TRUE @toc contains the TOCBLOCK data
- * FALSE @toc contents are undefined
+ * Return: 'true' @toc contains the TOCBLOCK data
+ * 'false' @toc contents are undefined
*/
-static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
+static bool ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
{
BUG_ON (!data || !toc);
if (MAGIC_TOCBLOCK != BE64 (data)) {
ldm_crit ("Cannot find TOCBLOCK, database may be corrupt.");
- return FALSE;
+ return false;
}
strncpy (toc->bitmap1_name, data + 0x24, sizeof (toc->bitmap1_name));
toc->bitmap1_name[sizeof (toc->bitmap1_name) - 1] = 0;
@@ -209,7 +204,7 @@ static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
sizeof (toc->bitmap1_name)) != 0) {
ldm_crit ("TOCBLOCK's first bitmap is '%s', should be '%s'.",
TOC_BITMAP1, toc->bitmap1_name);
- return FALSE;
+ return false;
}
strncpy (toc->bitmap2_name, data + 0x46, sizeof (toc->bitmap2_name));
toc->bitmap2_name[sizeof (toc->bitmap2_name) - 1] = 0;
@@ -219,10 +214,10 @@ static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
sizeof (toc->bitmap2_name)) != 0) {
ldm_crit ("TOCBLOCK's second bitmap is '%s', should be '%s'.",
TOC_BITMAP2, toc->bitmap2_name);
- return FALSE;
+ return false;
}
ldm_debug ("Parsed TOCBLOCK successfully.");
- return TRUE;
+ return true;
}
/**
@@ -235,16 +230,16 @@ static BOOL ldm_parse_tocblock (const u8 *data, struct tocblock *toc)
*
* N.B. The *_start, *_size and *_seq values will be range-checked later.
*
- * Return: TRUE @vm contains VMDB info
- * FALSE @vm contents are undefined
+ * Return: 'true' @vm contains VMDB info
+ * 'false' @vm contents are undefined
*/
-static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
+static bool ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
{
BUG_ON (!data || !vm);
if (MAGIC_VMDB != BE32 (data)) {
ldm_crit ("Cannot find the VMDB, database may be corrupt.");
- return FALSE;
+ return false;
}
vm->ver_major = BE16 (data + 0x12);
@@ -252,7 +247,7 @@ static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
ldm_error ("Expected VMDB version %d.%d, got %d.%d. "
"Aborting.", 4, 10, vm->ver_major, vm->ver_minor);
- return FALSE;
+ return false;
}
vm->vblk_size = BE32 (data + 0x08);
@@ -260,7 +255,7 @@ static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
vm->last_vblk_seq = BE32 (data + 0x04);
ldm_debug ("Parsed VMDB successfully.");
- return TRUE;
+ return true;
}
/**
@@ -270,10 +265,10 @@ static BOOL ldm_parse_vmdb (const u8 *data, struct vmdb *vm)
*
* This compares the two privhead structures @ph1 and @ph2.
*
- * Return: TRUE Identical
- * FALSE Different
+ * Return: 'true' Identical
+ * 'false' Different
*/
-static BOOL ldm_compare_privheads (const struct privhead *ph1,
+static bool ldm_compare_privheads (const struct privhead *ph1,
const struct privhead *ph2)
{
BUG_ON (!ph1 || !ph2);
@@ -294,10 +289,10 @@ static BOOL ldm_compare_privheads (const struct privhead *ph1,
*
* This compares the two tocblock structures @toc1 and @toc2.
*
- * Return: TRUE Identical
- * FALSE Different
+ * Return: 'true' Identical
+ * 'false' Different
*/
-static BOOL ldm_compare_tocblocks (const struct tocblock *toc1,
+static bool ldm_compare_tocblocks (const struct tocblock *toc1,
const struct tocblock *toc2)
{
BUG_ON (!toc1 || !toc2);
@@ -323,17 +318,17 @@ static BOOL ldm_compare_tocblocks (const struct tocblock *toc1,
* the configuration area (the database). The values are range-checked against
* @hd, which contains the real size of the disk.
*
- * Return: TRUE Success
- * FALSE Error
+ * Return: 'true' Success
+ * 'false' Error
*/
-static BOOL ldm_validate_privheads (struct block_device *bdev,
+static bool ldm_validate_privheads (struct block_device *bdev,
struct privhead *ph1)
{
static const int off[3] = { OFF_PRIV1, OFF_PRIV2, OFF_PRIV3 };
struct privhead *ph[3] = { ph1 };
Sector sect;
u8 *data;
- BOOL result = FALSE;
+ bool result = false;
long num_sects;
int i;
@@ -393,7 +388,7 @@ static BOOL ldm_validate_privheads (struct block_device *bdev,
goto out;
}*/
ldm_debug ("Validated PRIVHEADs successfully.");
- result = TRUE;
+ result = true;
out:
kfree (ph[1]);
kfree (ph[2]);
@@ -411,10 +406,10 @@ out:
*
* The offsets and sizes of the configs are range-checked against a privhead.
*
- * Return: TRUE @toc1 contains validated TOCBLOCK info
- * FALSE @toc1 contents are undefined
+ * Return: 'true' @toc1 contains validated TOCBLOCK info
+ * 'false' @toc1 contents are undefined
*/
-static BOOL ldm_validate_tocblocks (struct block_device *bdev,
+static bool ldm_validate_tocblocks (struct block_device *bdev,
unsigned long base, struct ldmdb *ldb)
{
static const int off[4] = { OFF_TOCB1, OFF_TOCB2, OFF_TOCB3, OFF_TOCB4};
@@ -422,7 +417,7 @@ static BOOL ldm_validate_tocblocks (struct block_device *bdev,
struct privhead *ph;
Sector sect;
u8 *data;
- BOOL result = FALSE;
+ bool result = false;
int i;
BUG_ON (!bdev || !ldb);
@@ -465,7 +460,7 @@ static BOOL ldm_validate_tocblocks (struct block_device *bdev,
}
ldm_debug ("Validated TOCBLOCKs successfully.");
- result = TRUE;
+ result = true;
out:
kfree (tb[1]);
kfree (tb[2]);
@@ -482,15 +477,15 @@ out:
* Find the vmdb of the LDM Database stored on @bdev and return the parsed
* information in @ldb.
*
- * Return: TRUE @ldb contains validated VBDB info
- * FALSE @ldb contents are undefined
+ * Return: 'true' @ldb contains validated VBDB info
+ * 'false' @ldb contents are undefined
*/
-static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
+static bool ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
struct ldmdb *ldb)
{
Sector sect;
u8 *data;
- BOOL result = FALSE;
+ bool result = false;
struct vmdb *vm;
struct tocblock *toc;
@@ -502,7 +497,7 @@ static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
data = read_dev_sector (bdev, base + OFF_VMDB, &sect);
if (!data) {
ldm_crit ("Disk read failed.");
- return FALSE;
+ return false;
}
if (!ldm_parse_vmdb (data, vm))
@@ -527,7 +522,7 @@ static BOOL ldm_validate_vmdb (struct block_device *bdev, unsigned long base,
goto out;
}
- result = TRUE;
+ result = true;
out:
put_dev_sector (sect);
return result;
@@ -547,23 +542,23 @@ out:
* only likely to happen if the underlying device is strange. If that IS
* the case we should return zero to let someone else try.
*
- * Return: TRUE @bdev is a dynamic disk
- * FALSE @bdev is not a dynamic disk, or an error occurred
+ * Return: 'true' @bdev is a dynamic disk
+ * 'false' @bdev is not a dynamic disk, or an error occurred
*/
-static BOOL ldm_validate_partition_table (struct block_device *bdev)
+static bool ldm_validate_partition_table (struct block_device *bdev)
{
Sector sect;
u8 *data;
struct partition *p;
int i;
- BOOL result = FALSE;
+ bool result = false;
BUG_ON (!bdev);
data = read_dev_sector (bdev, 0, &sect);
if (!data) {
ldm_crit ("Disk read failed.");
- return FALSE;
+ return false;
}
if (*(__le16*) (data + 0x01FE) != cpu_to_le16 (MSDOS_LABEL_MAGIC))
@@ -572,7 +567,7 @@ static BOOL ldm_validate_partition_table (struct block_device *bdev)
p = (struct partition*)(data + 0x01BE);
for (i = 0; i < 4; i++, p++)
if (SYS_IND (p) == WIN2K_DYNAMIC_PARTITION) {
- result = TRUE;
+ result = true;
break;
}
@@ -625,10 +620,10 @@ static struct vblk * ldm_get_disk_objid (const struct ldmdb *ldb)
* N.B. This function creates the partitions in the order it finds partition
* objects in the linked list.
*
- * Return: TRUE Partition created
- * FALSE Error, probably a range checking problem
+ * Return: 'true' Partition created
+ * 'false' Error, probably a range checking problem
*/
-static BOOL ldm_create_data_partitions (struct parsed_partitions *pp,
+static bool ldm_create_data_partitions (struct parsed_partitions *pp,
const struct ldmdb *ldb)
{
struct list_head *item;
@@ -642,7 +637,7 @@ static BOOL ldm_create_data_partitions (struct parsed_partitions *pp,
disk = ldm_get_disk_objid (ldb);
if (!disk) {
ldm_crit ("Can't find the ID of this disk in the database.");
- return FALSE;
+ return false;
}
printk (" [LDM]");
@@ -661,7 +656,7 @@ static BOOL ldm_create_data_partitions (struct parsed_partitions *pp,
}
printk ("\n");
- return TRUE;
+ return true;
}
@@ -766,10 +761,10 @@ static int ldm_get_vstr (const u8 *block, u8 *buffer, int buflen)
*
* Read a raw VBLK Component object (version 3) into a vblk structure.
*
- * Return: TRUE @vb contains a Component VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a Component VBLK
+ * 'false' @vb contents are not defined
*/
-static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
+static bool ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
{
int r_objid, r_name, r_vstate, r_child, r_parent, r_stripe, r_cols, len;
struct vblk_comp *comp;
@@ -792,11 +787,11 @@ static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
len = r_parent;
}
if (len < 0)
- return FALSE;
+ return false;
len += VBLK_SIZE_CMP3;
if (len != BE32 (buffer + 0x14))
- return FALSE;
+ return false;
comp = &vb->vblk.comp;
ldm_get_vstr (buffer + 0x18 + r_name, comp->state,
@@ -806,7 +801,7 @@ static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
comp->parent_id = ldm_get_vnum (buffer + 0x2D + r_child);
comp->chunksize = r_stripe ? ldm_get_vnum (buffer+r_parent+0x2E) : 0;
- return TRUE;
+ return true;
}
/**
@@ -817,8 +812,8 @@ static BOOL ldm_parse_cmp3 (const u8 *buffer, int buflen, struct vblk *vb)
*
* Read a raw VBLK Disk Group object (version 3) into a vblk structure.
*
- * Return: TRUE @vb contains a Disk Group VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a Disk Group VBLK
+ * 'false' @vb contents are not defined
*/
static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
{
@@ -841,16 +836,16 @@ static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
len = r_diskid;
}
if (len < 0)
- return FALSE;
+ return false;
len += VBLK_SIZE_DGR3;
if (len != BE32 (buffer + 0x14))
- return FALSE;
+ return false;
dgrp = &vb->vblk.dgrp;
ldm_get_vstr (buffer + 0x18 + r_name, dgrp->disk_id,
sizeof (dgrp->disk_id));
- return TRUE;
+ return true;
}
/**
@@ -861,10 +856,10 @@ static int ldm_parse_dgr3 (const u8 *buffer, int buflen, struct vblk *vb)
*
* Read a raw VBLK Disk Group object (version 4) into a vblk structure.
*
- * Return: TRUE @vb contains a Disk Group VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a Disk Group VBLK
+ * 'false' @vb contents are not defined
*/
-static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
+static bool ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
{
char buf[64];
int r_objid, r_name, r_id1, r_id2, len;
@@ -885,16 +880,16 @@ static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
len = r_name;
}
if (len < 0)
- return FALSE;
+ return false;
len += VBLK_SIZE_DGR4;
if (len != BE32 (buffer + 0x14))
- return FALSE;
+ return false;
dgrp = &vb->vblk.dgrp;
ldm_get_vstr (buffer + 0x18 + r_objid, buf, sizeof (buf));
- return TRUE;
+ return true;
}
/**
@@ -905,10 +900,10 @@ static BOOL ldm_parse_dgr4 (const u8 *buffer, int buflen, struct vblk *vb)
*
* Read a raw VBLK Disk object (version 3) into a vblk structure.
*
- * Return: TRUE @vb contains a Disk VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a Disk VBLK
+ * 'false' @vb contents are not defined
*/
-static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
+static bool ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
{
int r_objid, r_name, r_diskid, r_altname, len;
struct vblk_disk *disk;
@@ -921,19 +916,19 @@ static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
r_altname = ldm_relative (buffer, buflen, 0x18, r_diskid);
len = r_altname;
if (len < 0)
- return FALSE;
+ return false;
len += VBLK_SIZE_DSK3;
if (len != BE32 (buffer + 0x14))
- return FALSE;
+ return false;
disk = &vb->vblk.disk;
ldm_get_vstr (buffer + 0x18 + r_diskid, disk->alt_name,
sizeof (disk->alt_name));
if (!ldm_parse_guid (buffer + 0x19 + r_name, disk->disk_id))
- return FALSE;
+ return false;
- return TRUE;
+ return true;
}
/**
@@ -944,10 +939,10 @@ static BOOL ldm_parse_dsk3 (const u8 *buffer, int buflen, struct vblk *vb)
*
* Read a raw VBLK Disk object (version 4) into a vblk structure.
*
- * Return: TRUE @vb contains a Disk VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a Disk VBLK
+ * 'false' @vb contents are not defined
*/
-static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
+static bool ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
{
int r_objid, r_name, len;
struct vblk_disk *disk;
@@ -958,15 +953,15 @@ static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
r_name = ldm_relative (buffer, buflen, 0x18, r_objid);
len = r_name;
if (len < 0)
- return FALSE;
+ return false;
len += VBLK_SIZE_DSK4;
if (len != BE32 (buffer + 0x14))
- return FALSE;
+ return false;
disk = &vb->vblk.disk;
memcpy (disk->disk_id, buffer + 0x18 + r_name, GUID_SIZE);
- return TRUE;
+ return true;
}
/**
@@ -977,10 +972,10 @@ static BOOL ldm_parse_dsk4 (const u8 *buffer, int buflen, struct vblk *vb)
*
* Read a raw VBLK Partition object (version 3) into a vblk structure.
*
- * Return: TRUE @vb contains a Partition VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a Partition VBLK
+ * 'false' @vb contents are not defined
*/
-static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
+static bool ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
{
int r_objid, r_name, r_size, r_parent, r_diskid, r_index, len;
struct vblk_part *part;
@@ -1001,11 +996,11 @@ static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
len = r_diskid;
}
if (len < 0)
- return FALSE;
+ return false;
len += VBLK_SIZE_PRT3;
if (len != BE32 (buffer + 0x14))
- return FALSE;
+ return false;
part = &vb->vblk.part;
part->start = BE64 (buffer + 0x24 + r_name);
@@ -1018,7 +1013,7 @@ static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
else
part->partnum = 0;
- return TRUE;
+ return true;
}
/**
@@ -1029,10 +1024,10 @@ static BOOL ldm_parse_prt3 (const u8 *buffer, int buflen, struct vblk *vb)
*
* Read a raw VBLK Volume object (version 5) into a vblk structure.
*
- * Return: TRUE @vb contains a Volume VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a Volume VBLK
+ * 'false' @vb contents are not defined
*/
-static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
+static bool ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
{
int r_objid, r_name, r_vtype, r_child, r_size, r_id1, r_id2, r_size2;
int r_drive, len;
@@ -1068,11 +1063,11 @@ static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
len = r_drive;
if (len < 0)
- return FALSE;
+ return false;
len += VBLK_SIZE_VOL5;
if (len != BE32 (buffer + 0x14))
- return FALSE;
+ return false;
volu = &vb->vblk.volu;
@@ -1087,7 +1082,7 @@ static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
ldm_get_vstr (buffer + 0x53 + r_size, volu->drive_hint,
sizeof (volu->drive_hint));
}
- return TRUE;
+ return true;
}
/**
@@ -1100,12 +1095,12 @@ static BOOL ldm_parse_vol5 (const u8 *buffer, int buflen, struct vblk *vb)
* information common to all VBLK types, then delegates the rest of the work to
* helper functions: ldm_parse_*.
*
- * Return: TRUE @vb contains a VBLK
- * FALSE @vb contents are not defined
+ * Return: 'true' @vb contains a VBLK
+ * 'false' @vb contents are not defined
*/
-static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
+static bool ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
{
- BOOL result = FALSE;
+ bool result = false;
int r_objid;
BUG_ON (!buf || !vb);
@@ -1113,7 +1108,7 @@ static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
r_objid = ldm_relative (buf, len, 0x18, 0);
if (r_objid < 0) {
ldm_error ("VBLK header is corrupt.");
- return FALSE;
+ return false;
}
vb->flags = buf[0x12];
@@ -1152,10 +1147,10 @@ static BOOL ldm_parse_vblk (const u8 *buf, int len, struct vblk *vb)
*
* N.B. This function does not check the validity of the VBLKs.
*
- * Return: TRUE The VBLK was added
- * FALSE An error occurred
+ * Return: 'true' The VBLK was added
+ * 'false' An error occurred
*/
-static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
+static bool ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
{
struct vblk *vb;
struct list_head *item;
@@ -1165,12 +1160,12 @@ static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
vb = kmalloc (sizeof (*vb), GFP_KERNEL);
if (!vb) {
ldm_crit ("Out of memory.");
- return FALSE;
+ return false;
}
if (!ldm_parse_vblk (data, len, vb)) {
kfree(vb);
- return FALSE; /* Already logged */
+ return false; /* Already logged */
}
/* Put vblk into the correct list. */
@@ -1196,13 +1191,13 @@ static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
if ((v->vblk.part.disk_id == vb->vblk.part.disk_id) &&
(v->vblk.part.start > vb->vblk.part.start)) {
list_add_tail (&vb->list, &v->list);
- return TRUE;
+ return true;
}
}
list_add_tail (&vb->list, &ldb->v_part);
break;
}
- return TRUE;
+ return true;
}
/**
@@ -1214,10 +1209,10 @@ static BOOL ldm_ldmdb_add (u8 *data, int len, struct ldmdb *ldb)
* Fragmented VBLKs may not be consecutive in the database, so they are placed
* in a list so they can be pieced together later.
*
- * Return: TRUE Success, the VBLK was added to the list
- * FALSE Error, a problem occurred
+ * Return: 'true' Success, the VBLK was added to the list
+ * 'false' Error, a problem occurred
*/
-static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags)
+static bool ldm_frag_add (const u8 *data, int size, struct list_head *frags)
{
struct frag *f;
struct list_head *item;
@@ -1230,7 +1225,7 @@ static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags)
num = BE16 (data + 0x0E);
if ((num < 1) || (num > 4)) {
ldm_error ("A VBLK claims to have %d parts.", num);
- return FALSE;
+ return false;
}
list_for_each (item, frags) {
@@ -1242,7 +1237,7 @@ static BOOL ldm_frag_add (const u8 *data, int size, struct list_head *frags)
f = kmalloc (sizeof (*f) + size*num, GFP_KERNEL);
if (!f) {
ldm_crit ("Out of memory.");
- return FALSE;
+ return false;
}
f->group = group;
@@ -1255,7 +1250,7 @@ found:
if (f->map & (1 << rec)) {
ldm_error ("Duplicate VBLK, part %d.", rec);
f->map &= 0x7F; /* Mark the group as broken */
- return FALSE;
+ return false;
}
f->map |= (1 << rec);
@@ -1266,7 +1261,7 @@ found:
}
memcpy (f->data+rec*(size-VBLK_SIZE_HEAD)+VBLK_SIZE_HEAD, data, size);
- return TRUE;
+ return true;
}
/**
@@ -1295,10 +1290,10 @@ static void ldm_frag_free (struct list_head *list)
* Now that all the fragmented VBLKs have been collected, they must be added to
* the database for later use.
*
- * Return: TRUE All the fragments we added successfully
- * FALSE One or more of the fragments we invalid
+ * Return: 'true' All the fragments we added successfully
+ * 'false' One or more of the fragments we invalid
*/
-static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
+static bool ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
{
struct frag *f;
struct list_head *item;
@@ -1311,13 +1306,13 @@ static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
if (f->map != 0xFF) {
ldm_error ("VBLK group %d is incomplete (0x%02x).",
f->group, f->map);
- return FALSE;
+ return false;
}
if (!ldm_ldmdb_add (f->data, f->num*ldb->vm.vblk_size, ldb))
- return FALSE; /* Already logged */
+ return false; /* Already logged */
}
- return TRUE;
+ return true;
}
/**
@@ -1329,16 +1324,16 @@ static BOOL ldm_frag_commit (struct list_head *frags, struct ldmdb *ldb)
* To use the information from the VBLKs, they need to be read from the disk,
* unpacked and validated. We cache them in @ldb according to their type.
*
- * Return: TRUE All the VBLKs were read successfully
- * FALSE An error occurred
+ * Return: 'true' All the VBLKs were read successfully
+ * 'false' An error occurred
*/
-static BOOL ldm_get_vblks (struct block_device *bdev, unsigned long base,
+static bool ldm_get_vblks (struct block_device *bdev, unsigned long base,
struct ldmdb *ldb)
{
int size, perbuf, skip, finish, s, v, recs;
u8 *data = NULL;
Sector sect;
- BOOL result = FALSE;
+ bool result = false;
LIST_HEAD (frags);
BUG_ON (!bdev || !ldb);
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index 8f12587c3129..8c7af1777819 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -32,13 +32,11 @@
#include <asm/unaligned.h>
#define SYS_IND(p) (get_unaligned(&p->sys_ind))
-#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \
- get_unaligned(&p->nr_sects); \
+#define NR_SECTS(p) ({ __le32 __a = get_unaligned(&p->nr_sects); \
le32_to_cpu(__a); \
})
-#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \
- get_unaligned(&p->start_sect); \
+#define START_SECT(p) ({ __le32 __a = get_unaligned(&p->start_sect); \
le32_to_cpu(__a); \
})
@@ -58,6 +56,31 @@ msdos_magic_present(unsigned char *p)
return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
}
+/* Value is EBCDIC 'IBMA' */
+#define AIX_LABEL_MAGIC1 0xC9
+#define AIX_LABEL_MAGIC2 0xC2
+#define AIX_LABEL_MAGIC3 0xD4
+#define AIX_LABEL_MAGIC4 0xC1
+static int aix_magic_present(unsigned char *p, struct block_device *bdev)
+{
+ Sector sect;
+ unsigned char *d;
+ int ret = 0;
+
+ if (p[0] != AIX_LABEL_MAGIC1 &&
+ p[1] != AIX_LABEL_MAGIC2 &&
+ p[2] != AIX_LABEL_MAGIC3 &&
+ p[3] != AIX_LABEL_MAGIC4)
+ return 0;
+ d = read_dev_sector(bdev, 7, &sect);
+ if (d) {
+ if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
+ ret = 1;
+ put_dev_sector(sect);
+ };
+ return ret;
+}
+
/*
* Create devices for each logical partition in an extended partition.
* The logical partitions form a linked list, with each entry being
@@ -393,6 +416,12 @@ int msdos_partition(struct parsed_partitions *state, struct block_device *bdev)
return 0;
}
+ if (aix_magic_present(data, bdev)) {
+ put_dev_sector(sect);
+ printk( " [AIX]");
+ return 0;
+ }
+
/*
* Now that the 55aa signature is present, this is probably
* either the boot sector of a FAT filesystem or a DOS-type
diff --git a/fs/pipe.c b/fs/pipe.c
index 20352573e025..b1626f269a34 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -218,9 +218,10 @@ static struct pipe_buf_operations anon_pipe_buf_ops = {
};
static ssize_t
-pipe_readv(struct file *filp, const struct iovec *_iov,
- unsigned long nr_segs, loff_t *ppos)
+pipe_read(struct kiocb *iocb, const struct iovec *_iov,
+ unsigned long nr_segs, loff_t pos)
{
+ struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
struct pipe_inode_info *pipe;
int do_wakeup;
@@ -330,17 +331,10 @@ redo:
}
static ssize_t
-pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
-{
- struct iovec iov = { .iov_base = buf, .iov_len = count };
-
- return pipe_readv(filp, &iov, 1, ppos);
-}
-
-static ssize_t
-pipe_writev(struct file *filp, const struct iovec *_iov,
- unsigned long nr_segs, loff_t *ppos)
+pipe_write(struct kiocb *iocb, const struct iovec *_iov,
+ unsigned long nr_segs, loff_t ppos)
{
+ struct file *filp = iocb->ki_filp;
struct inode *inode = filp->f_dentry->d_inode;
struct pipe_inode_info *pipe;
ssize_t ret;
@@ -510,15 +504,6 @@ out:
}
static ssize_t
-pipe_write(struct file *filp, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = count };
-
- return pipe_writev(filp, &iov, 1, ppos);
-}
-
-static ssize_t
bad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
return -EBADF;
@@ -736,8 +721,8 @@ pipe_rdwr_open(struct inode *inode, struct file *filp)
*/
const struct file_operations read_fifo_fops = {
.llseek = no_llseek,
- .read = pipe_read,
- .readv = pipe_readv,
+ .read = do_sync_read,
+ .aio_read = pipe_read,
.write = bad_pipe_w,
.poll = pipe_poll,
.ioctl = pipe_ioctl,
@@ -749,8 +734,8 @@ const struct file_operations read_fifo_fops = {
const struct file_operations write_fifo_fops = {
.llseek = no_llseek,
.read = bad_pipe_r,
- .write = pipe_write,
- .writev = pipe_writev,
+ .write = do_sync_write,
+ .aio_write = pipe_write,
.poll = pipe_poll,
.ioctl = pipe_ioctl,
.open = pipe_write_open,
@@ -760,10 +745,10 @@ const struct file_operations write_fifo_fops = {
const struct file_operations rdwr_fifo_fops = {
.llseek = no_llseek,
- .read = pipe_read,
- .readv = pipe_readv,
- .write = pipe_write,
- .writev = pipe_writev,
+ .read = do_sync_read,
+ .aio_read = pipe_read,
+ .write = do_sync_write,
+ .aio_write = pipe_write,
.poll = pipe_poll,
.ioctl = pipe_ioctl,
.open = pipe_rdwr_open,
@@ -773,8 +758,8 @@ const struct file_operations rdwr_fifo_fops = {
static struct file_operations read_pipe_fops = {
.llseek = no_llseek,
- .read = pipe_read,
- .readv = pipe_readv,
+ .read = do_sync_read,
+ .aio_read = pipe_read,
.write = bad_pipe_w,
.poll = pipe_poll,
.ioctl = pipe_ioctl,
@@ -786,8 +771,8 @@ static struct file_operations read_pipe_fops = {
static struct file_operations write_pipe_fops = {
.llseek = no_llseek,
.read = bad_pipe_r,
- .write = pipe_write,
- .writev = pipe_writev,
+ .write = do_sync_write,
+ .aio_write = pipe_write,
.poll = pipe_poll,
.ioctl = pipe_ioctl,
.open = pipe_write_open,
@@ -797,10 +782,10 @@ static struct file_operations write_pipe_fops = {
static struct file_operations rdwr_pipe_fops = {
.llseek = no_llseek,
- .read = pipe_read,
- .readv = pipe_readv,
- .write = pipe_write,
- .writev = pipe_writev,
+ .read = do_sync_read,
+ .aio_read = pipe_read,
+ .write = do_sync_write,
+ .aio_write = pipe_write,
.poll = pipe_poll,
.ioctl = pipe_ioctl,
.open = pipe_rdwr_open,
@@ -879,7 +864,6 @@ static struct inode * get_pipe_inode(void)
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- inode->i_blksize = PAGE_SIZE;
return inode;
@@ -890,87 +874,118 @@ fail_inode:
return NULL;
}
-int do_pipe(int *fd)
+struct file *create_write_pipe(void)
{
- struct qstr this;
- char name[32];
+ int err;
+ struct inode *inode;
+ struct file *f;
struct dentry *dentry;
- struct inode * inode;
- struct file *f1, *f2;
- int error;
- int i, j;
-
- error = -ENFILE;
- f1 = get_empty_filp();
- if (!f1)
- goto no_files;
-
- f2 = get_empty_filp();
- if (!f2)
- goto close_f1;
+ char name[32];
+ struct qstr this;
+ f = get_empty_filp();
+ if (!f)
+ return ERR_PTR(-ENFILE);
+ err = -ENFILE;
inode = get_pipe_inode();
if (!inode)
- goto close_f12;
-
- error = get_unused_fd();
- if (error < 0)
- goto close_f12_inode;
- i = error;
-
- error = get_unused_fd();
- if (error < 0)
- goto close_f12_inode_i;
- j = error;
+ goto err_file;
- error = -ENOMEM;
sprintf(name, "[%lu]", inode->i_ino);
this.name = name;
this.len = strlen(name);
this.hash = inode->i_ino; /* will go */
+ err = -ENOMEM;
dentry = d_alloc(pipe_mnt->mnt_sb->s_root, &this);
if (!dentry)
- goto close_f12_inode_i_j;
+ goto err_inode;
dentry->d_op = &pipefs_dentry_operations;
d_add(dentry, inode);
- f1->f_vfsmnt = f2->f_vfsmnt = mntget(mntget(pipe_mnt));
- f1->f_dentry = f2->f_dentry = dget(dentry);
- f1->f_mapping = f2->f_mapping = inode->i_mapping;
-
- /* read file */
- f1->f_pos = f2->f_pos = 0;
- f1->f_flags = O_RDONLY;
- f1->f_op = &read_pipe_fops;
- f1->f_mode = FMODE_READ;
- f1->f_version = 0;
-
- /* write file */
- f2->f_flags = O_WRONLY;
- f2->f_op = &write_pipe_fops;
- f2->f_mode = FMODE_WRITE;
- f2->f_version = 0;
-
- fd_install(i, f1);
- fd_install(j, f2);
- fd[0] = i;
- fd[1] = j;
+ f->f_vfsmnt = mntget(pipe_mnt);
+ f->f_dentry = dentry;
+ f->f_mapping = inode->i_mapping;
- return 0;
+ f->f_flags = O_WRONLY;
+ f->f_op = &write_pipe_fops;
+ f->f_mode = FMODE_WRITE;
+ f->f_version = 0;
+
+ return f;
-close_f12_inode_i_j:
- put_unused_fd(j);
-close_f12_inode_i:
- put_unused_fd(i);
-close_f12_inode:
+ err_inode:
free_pipe_info(inode);
iput(inode);
-close_f12:
- put_filp(f2);
-close_f1:
- put_filp(f1);
-no_files:
- return error;
+ err_file:
+ put_filp(f);
+ return ERR_PTR(err);
+}
+
+void free_write_pipe(struct file *f)
+{
+ mntput(f->f_vfsmnt);
+ dput(f->f_dentry);
+ put_filp(f);
+}
+
+struct file *create_read_pipe(struct file *wrf)
+{
+ struct file *f = get_empty_filp();
+ if (!f)
+ return ERR_PTR(-ENFILE);
+
+ /* Grab pipe from the writer */
+ f->f_vfsmnt = mntget(wrf->f_vfsmnt);
+ f->f_dentry = dget(wrf->f_dentry);
+ f->f_mapping = wrf->f_dentry->d_inode->i_mapping;
+
+ f->f_pos = 0;
+ f->f_flags = O_RDONLY;
+ f->f_op = &read_pipe_fops;
+ f->f_mode = FMODE_READ;
+ f->f_version = 0;
+
+ return f;
+}
+
+int do_pipe(int *fd)
+{
+ struct file *fw, *fr;
+ int error;
+ int fdw, fdr;
+
+ fw = create_write_pipe();
+ if (IS_ERR(fw))
+ return PTR_ERR(fw);
+ fr = create_read_pipe(fw);
+ error = PTR_ERR(fr);
+ if (IS_ERR(fr))
+ goto err_write_pipe;
+
+ error = get_unused_fd();
+ if (error < 0)
+ goto err_read_pipe;
+ fdr = error;
+
+ error = get_unused_fd();
+ if (error < 0)
+ goto err_fdr;
+ fdw = error;
+
+ fd_install(fdr, fr);
+ fd_install(fdw, fw);
+ fd[0] = fdr;
+ fd[1] = fdw;
+
+ return 0;
+
+ err_fdr:
+ put_unused_fd(fdr);
+ err_read_pipe:
+ put_filp(fr);
+ err_write_pipe:
+ free_write_pipe(fw);
+ return error;
}
/*
diff --git a/fs/posix_acl.c b/fs/posix_acl.c
index 6c8dcf7613fd..aec931e09973 100644
--- a/fs/posix_acl.c
+++ b/fs/posix_acl.c
@@ -58,11 +58,9 @@ posix_acl_clone(const struct posix_acl *acl, gfp_t flags)
if (acl) {
int size = sizeof(struct posix_acl) + acl->a_count *
sizeof(struct posix_acl_entry);
- clone = kmalloc(size, flags);
- if (clone) {
- memcpy(clone, acl, size);
+ clone = kmemdup(acl, size, flags);
+ if (clone)
atomic_set(&clone->a_refcount, 1);
- }
}
return clone;
}
diff --git a/fs/proc/array.c b/fs/proc/array.c
index 0b615d62a159..25e917fb4739 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -162,7 +162,7 @@ static inline char * task_state(struct task_struct *p, char *buffer)
int g;
struct fdtable *fdt = NULL;
- read_lock(&tasklist_lock);
+ rcu_read_lock();
buffer += sprintf(buffer,
"State:\t%s\n"
"SleepAVG:\t%lu%%\n"
@@ -174,14 +174,13 @@ static inline char * task_state(struct task_struct *p, char *buffer)
"Gid:\t%d\t%d\t%d\t%d\n",
get_task_state(p),
(p->sleep_avg/1024)*100/(1020000000/1024),
- p->tgid,
- p->pid, pid_alive(p) ? p->group_leader->real_parent->tgid : 0,
- pid_alive(p) && p->ptrace ? p->parent->pid : 0,
+ p->tgid, p->pid,
+ pid_alive(p) ? rcu_dereference(p->real_parent)->tgid : 0,
+ pid_alive(p) && p->ptrace ? rcu_dereference(p->parent)->pid : 0,
p->uid, p->euid, p->suid, p->fsuid,
p->gid, p->egid, p->sgid, p->fsgid);
- read_unlock(&tasklist_lock);
+
task_lock(p);
- rcu_read_lock();
if (p->files)
fdt = files_fdtable(p->files);
buffer += sprintf(buffer,
@@ -244,6 +243,7 @@ static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign,
static inline char * task_sig(struct task_struct *p, char *buffer)
{
+ unsigned long flags;
sigset_t pending, shpending, blocked, ignored, caught;
int num_threads = 0;
unsigned long qsize = 0;
@@ -255,10 +255,8 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
sigemptyset(&ignored);
sigemptyset(&caught);
- /* Gather all the data with the appropriate locks held */
- read_lock(&tasklist_lock);
- if (p->sighand) {
- spin_lock_irq(&p->sighand->siglock);
+ rcu_read_lock();
+ if (lock_task_sighand(p, &flags)) {
pending = p->pending.signal;
shpending = p->signal->shared_pending.signal;
blocked = p->blocked;
@@ -266,9 +264,9 @@ static inline char * task_sig(struct task_struct *p, char *buffer)
num_threads = atomic_read(&p->signal->count);
qsize = atomic_read(&p->user->sigpending);
qlim = p->signal->rlim[RLIMIT_SIGPENDING].rlim_cur;
- spin_unlock_irq(&p->sighand->siglock);
+ unlock_task_sighand(p, &flags);
}
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
buffer += sprintf(buffer, "Threads:\t%d\n", num_threads);
buffer += sprintf(buffer, "SigQ:\t%lu/%lu\n", qsize, qlim);
@@ -322,7 +320,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
sigset_t sigign, sigcatch;
char state;
int res;
- pid_t ppid, pgid = -1, sid = -1;
+ pid_t ppid = 0, pgid = -1, sid = -1;
int num_threads = 0;
struct mm_struct *mm;
unsigned long long start_time;
@@ -330,8 +328,8 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
unsigned long min_flt = 0, maj_flt = 0;
cputime_t cutime, cstime, utime, stime;
unsigned long rsslim = 0;
- struct task_struct *t;
char tcomm[sizeof(task->comm)];
+ unsigned long flags;
state = *get_task_state(task);
vsize = eip = esp = 0;
@@ -347,15 +345,35 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
sigemptyset(&sigign);
sigemptyset(&sigcatch);
cutime = cstime = utime = stime = cputime_zero;
- read_lock(&tasklist_lock);
- if (task->sighand) {
- spin_lock_irq(&task->sighand->siglock);
- num_threads = atomic_read(&task->signal->count);
+
+ mutex_lock(&tty_mutex);
+ rcu_read_lock();
+ if (lock_task_sighand(task, &flags)) {
+ struct signal_struct *sig = task->signal;
+ struct tty_struct *tty = sig->tty;
+
+ if (tty) {
+ /*
+ * sig->tty is not stable, but tty_mutex
+ * protects us from release_dev(tty)
+ */
+ barrier();
+ tty_pgrp = tty->pgrp;
+ tty_nr = new_encode_dev(tty_devnum(tty));
+ }
+
+ num_threads = atomic_read(&sig->count);
collect_sigign_sigcatch(task, &sigign, &sigcatch);
+ cmin_flt = sig->cmin_flt;
+ cmaj_flt = sig->cmaj_flt;
+ cutime = sig->cutime;
+ cstime = sig->cstime;
+ rsslim = sig->rlim[RLIMIT_RSS].rlim_cur;
+
/* add up live thread stats at the group level */
if (whole) {
- t = task;
+ struct task_struct *t = task;
do {
min_flt += t->min_flt;
maj_flt += t->maj_flt;
@@ -363,31 +381,21 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole)
stime = cputime_add(stime, t->stime);
t = next_thread(t);
} while (t != task);
- }
- spin_unlock_irq(&task->sighand->siglock);
- }
- if (task->signal) {
- if (task->signal->tty) {
- tty_pgrp = task->signal->tty->pgrp;
- tty_nr = new_encode_dev(tty_devnum(task->signal->tty));
+ min_flt += sig->min_flt;
+ maj_flt += sig->maj_flt;
+ utime = cputime_add(utime, sig->utime);
+ stime = cputime_add(stime, sig->stime);
}
+
+ sid = sig->session;
pgid = process_group(task);
- sid = task->signal->session;
- cmin_flt = task->signal->cmin_flt;
- cmaj_flt = task->signal->cmaj_flt;
- cutime = task->signal->cutime;
- cstime = task->signal->cstime;
- rsslim = task->signal->rlim[RLIMIT_RSS].rlim_cur;
- if (whole) {
- min_flt += task->signal->min_flt;
- maj_flt += task->signal->maj_flt;
- utime = cputime_add(utime, task->signal->utime);
- stime = cputime_add(stime, task->signal->stime);
- }
+ ppid = rcu_dereference(task->real_parent)->tgid;
+
+ unlock_task_sighand(task, &flags);
}
- ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0;
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
+ mutex_unlock(&tty_mutex);
if (!whole || num_threads<2)
wchan = get_wchan(task);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index fe8d55fb17cc..8df27401d292 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -71,6 +71,8 @@
#include <linux/cpuset.h>
#include <linux/audit.h>
#include <linux/poll.h>
+#include <linux/nsproxy.h>
+#include <linux/oom.h>
#include "internal.h"
/* NOTE:
@@ -83,262 +85,44 @@
* in /proc for a task before it execs a suid executable.
*/
-/*
- * For hysterical raisins we keep the same inumbers as in the old procfs.
- * Feel free to change the macro below - just keep the range distinct from
- * inumbers of the rest of procfs (currently those are in 0x0000--0xffff).
- * As soon as we'll get a separate superblock we will be able to forget
- * about magical ranges too.
- */
-
-#define fake_ino(pid,ino) (((pid)<<16)|(ino))
-
-enum pid_directory_inos {
- PROC_TGID_INO = 2,
- PROC_TGID_TASK,
- PROC_TGID_STATUS,
- PROC_TGID_MEM,
-#ifdef CONFIG_SECCOMP
- PROC_TGID_SECCOMP,
-#endif
- PROC_TGID_CWD,
- PROC_TGID_ROOT,
- PROC_TGID_EXE,
- PROC_TGID_FD,
- PROC_TGID_ENVIRON,
- PROC_TGID_AUXV,
- PROC_TGID_CMDLINE,
- PROC_TGID_STAT,
- PROC_TGID_STATM,
- PROC_TGID_MAPS,
- PROC_TGID_NUMA_MAPS,
- PROC_TGID_MOUNTS,
- PROC_TGID_MOUNTSTATS,
- PROC_TGID_WCHAN,
-#ifdef CONFIG_MMU
- PROC_TGID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
- PROC_TGID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
- PROC_TGID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
- PROC_TGID_ATTR,
- PROC_TGID_ATTR_CURRENT,
- PROC_TGID_ATTR_PREV,
- PROC_TGID_ATTR_EXEC,
- PROC_TGID_ATTR_FSCREATE,
- PROC_TGID_ATTR_KEYCREATE,
- PROC_TGID_ATTR_SOCKCREATE,
-#endif
-#ifdef CONFIG_AUDITSYSCALL
- PROC_TGID_LOGINUID,
-#endif
- PROC_TGID_OOM_SCORE,
- PROC_TGID_OOM_ADJUST,
- PROC_TID_INO,
- PROC_TID_STATUS,
- PROC_TID_MEM,
-#ifdef CONFIG_SECCOMP
- PROC_TID_SECCOMP,
-#endif
- PROC_TID_CWD,
- PROC_TID_ROOT,
- PROC_TID_EXE,
- PROC_TID_FD,
- PROC_TID_ENVIRON,
- PROC_TID_AUXV,
- PROC_TID_CMDLINE,
- PROC_TID_STAT,
- PROC_TID_STATM,
- PROC_TID_MAPS,
- PROC_TID_NUMA_MAPS,
- PROC_TID_MOUNTS,
- PROC_TID_MOUNTSTATS,
- PROC_TID_WCHAN,
-#ifdef CONFIG_MMU
- PROC_TID_SMAPS,
-#endif
-#ifdef CONFIG_SCHEDSTATS
- PROC_TID_SCHEDSTAT,
-#endif
-#ifdef CONFIG_CPUSETS
- PROC_TID_CPUSET,
-#endif
-#ifdef CONFIG_SECURITY
- PROC_TID_ATTR,
- PROC_TID_ATTR_CURRENT,
- PROC_TID_ATTR_PREV,
- PROC_TID_ATTR_EXEC,
- PROC_TID_ATTR_FSCREATE,
- PROC_TID_ATTR_KEYCREATE,
- PROC_TID_ATTR_SOCKCREATE,
-#endif
-#ifdef CONFIG_AUDITSYSCALL
- PROC_TID_LOGINUID,
-#endif
- PROC_TID_OOM_SCORE,
- PROC_TID_OOM_ADJUST,
-
- /* Add new entries before this */
- PROC_TID_FD_DIR = 0x8000, /* 0x8000-0xffff */
-};
/* Worst case buffer size needed for holding an integer. */
-#define PROC_NUMBUF 10
+#define PROC_NUMBUF 13
struct pid_entry {
- int type;
int len;
char *name;
mode_t mode;
+ struct inode_operations *iop;
+ struct file_operations *fop;
+ union proc_op op;
};
-#define E(type,name,mode) {(type),sizeof(name)-1,(name),(mode)}
-
-static struct pid_entry tgid_base_stuff[] = {
- E(PROC_TGID_TASK, "task", S_IFDIR|S_IRUGO|S_IXUGO),
- E(PROC_TGID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR),
- E(PROC_TGID_ENVIRON, "environ", S_IFREG|S_IRUSR),
- E(PROC_TGID_AUXV, "auxv", S_IFREG|S_IRUSR),
- E(PROC_TGID_STATUS, "status", S_IFREG|S_IRUGO),
- E(PROC_TGID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
- E(PROC_TGID_STAT, "stat", S_IFREG|S_IRUGO),
- E(PROC_TGID_STATM, "statm", S_IFREG|S_IRUGO),
- E(PROC_TGID_MAPS, "maps", S_IFREG|S_IRUGO),
-#ifdef CONFIG_NUMA
- E(PROC_TGID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
-#endif
- E(PROC_TGID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
-#ifdef CONFIG_SECCOMP
- E(PROC_TGID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
-#endif
- E(PROC_TGID_CWD, "cwd", S_IFLNK|S_IRWXUGO),
- E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO),
- E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO),
- E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
- E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR),
-#ifdef CONFIG_MMU
- E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_SECURITY
- E(PROC_TGID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
-#endif
-#ifdef CONFIG_KALLSYMS
- E(PROC_TGID_WCHAN, "wchan", S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_SCHEDSTATS
- E(PROC_TGID_SCHEDSTAT, "schedstat", S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_CPUSETS
- E(PROC_TGID_CPUSET, "cpuset", S_IFREG|S_IRUGO),
-#endif
- E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO),
- E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
-#ifdef CONFIG_AUDITSYSCALL
- E(PROC_TGID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
-#endif
- {0,0,NULL,0}
-};
-static struct pid_entry tid_base_stuff[] = {
- E(PROC_TID_FD, "fd", S_IFDIR|S_IRUSR|S_IXUSR),
- E(PROC_TID_ENVIRON, "environ", S_IFREG|S_IRUSR),
- E(PROC_TID_AUXV, "auxv", S_IFREG|S_IRUSR),
- E(PROC_TID_STATUS, "status", S_IFREG|S_IRUGO),
- E(PROC_TID_CMDLINE, "cmdline", S_IFREG|S_IRUGO),
- E(PROC_TID_STAT, "stat", S_IFREG|S_IRUGO),
- E(PROC_TID_STATM, "statm", S_IFREG|S_IRUGO),
- E(PROC_TID_MAPS, "maps", S_IFREG|S_IRUGO),
-#ifdef CONFIG_NUMA
- E(PROC_TID_NUMA_MAPS, "numa_maps", S_IFREG|S_IRUGO),
-#endif
- E(PROC_TID_MEM, "mem", S_IFREG|S_IRUSR|S_IWUSR),
-#ifdef CONFIG_SECCOMP
- E(PROC_TID_SECCOMP, "seccomp", S_IFREG|S_IRUSR|S_IWUSR),
-#endif
- E(PROC_TID_CWD, "cwd", S_IFLNK|S_IRWXUGO),
- E(PROC_TID_ROOT, "root", S_IFLNK|S_IRWXUGO),
- E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO),
- E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO),
-#ifdef CONFIG_MMU
- E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_SECURITY
- E(PROC_TID_ATTR, "attr", S_IFDIR|S_IRUGO|S_IXUGO),
-#endif
-#ifdef CONFIG_KALLSYMS
- E(PROC_TID_WCHAN, "wchan", S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_SCHEDSTATS
- E(PROC_TID_SCHEDSTAT, "schedstat",S_IFREG|S_IRUGO),
-#endif
-#ifdef CONFIG_CPUSETS
- E(PROC_TID_CPUSET, "cpuset", S_IFREG|S_IRUGO),
-#endif
- E(PROC_TID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO),
- E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR),
-#ifdef CONFIG_AUDITSYSCALL
- E(PROC_TID_LOGINUID, "loginuid", S_IFREG|S_IWUSR|S_IRUGO),
-#endif
- {0,0,NULL,0}
-};
-
-#ifdef CONFIG_SECURITY
-static struct pid_entry tgid_attr_stuff[] = {
- E(PROC_TGID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TGID_ATTR_PREV, "prev", S_IFREG|S_IRUGO),
- E(PROC_TGID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TGID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TGID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TGID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
- {0,0,NULL,0}
-};
-static struct pid_entry tid_attr_stuff[] = {
- E(PROC_TID_ATTR_CURRENT, "current", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TID_ATTR_PREV, "prev", S_IFREG|S_IRUGO),
- E(PROC_TID_ATTR_EXEC, "exec", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TID_ATTR_FSCREATE, "fscreate", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TID_ATTR_KEYCREATE, "keycreate", S_IFREG|S_IRUGO|S_IWUGO),
- E(PROC_TID_ATTR_SOCKCREATE, "sockcreate", S_IFREG|S_IRUGO|S_IWUGO),
- {0,0,NULL,0}
-};
-#endif
-
-#undef E
-
-static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
-{
- struct task_struct *task = get_proc_task(inode);
- struct files_struct *files = NULL;
- struct file *file;
- int fd = proc_fd(inode);
-
- if (task) {
- files = get_files_struct(task);
- put_task_struct(task);
- }
- if (files) {
- /*
- * We are not taking a ref to the file structure, so we must
- * hold ->file_lock.
- */
- spin_lock(&files->file_lock);
- file = fcheck_files(files, fd);
- if (file) {
- *mnt = mntget(file->f_vfsmnt);
- *dentry = dget(file->f_dentry);
- spin_unlock(&files->file_lock);
- put_files_struct(files);
- return 0;
- }
- spin_unlock(&files->file_lock);
- put_files_struct(files);
- }
- return -ENOENT;
+#define NOD(NAME, MODE, IOP, FOP, OP) { \
+ .len = sizeof(NAME) - 1, \
+ .name = (NAME), \
+ .mode = MODE, \
+ .iop = IOP, \
+ .fop = FOP, \
+ .op = OP, \
}
+#define DIR(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFDIR|(MODE)), \
+ &proc_##OTYPE##_inode_operations, &proc_##OTYPE##_operations, \
+ {} )
+#define LNK(NAME, OTYPE) \
+ NOD(NAME, (S_IFLNK|S_IRWXUGO), \
+ &proc_pid_link_inode_operations, NULL, \
+ { .proc_get_link = &proc_##OTYPE##_link } )
+#define REG(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), NULL, \
+ &proc_##OTYPE##_operations, {})
+#define INF(NAME, MODE, OTYPE) \
+ NOD(NAME, (S_IFREG|(MODE)), \
+ NULL, &proc_info_file_operations, \
+ { .proc_read = &proc_##OTYPE } )
+
static struct fs_struct *get_fs_struct(struct task_struct *task)
{
struct fs_struct *fs;
@@ -587,7 +371,7 @@ static int mounts_open(struct inode *inode, struct file *file)
if (task) {
task_lock(task);
- namespace = task->namespace;
+ namespace = task->nsproxy->namespace;
if (namespace)
get_namespace(namespace);
task_unlock(task);
@@ -658,7 +442,7 @@ static int mountstats_open(struct inode *inode, struct file *file)
if (task) {
task_lock(task);
- namespace = task->namespace;
+ namespace = task->nsproxy->namespace;
if (namespace)
get_namespace(namespace);
task_unlock(task);
@@ -797,7 +581,7 @@ out_no_task:
static ssize_t mem_write(struct file * file, const char * buf,
size_t count, loff_t *ppos)
{
- int copied = 0;
+ int copied;
char *page;
struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
unsigned long dst = *ppos;
@@ -814,6 +598,7 @@ static ssize_t mem_write(struct file * file, const char * buf,
if (!page)
goto out;
+ copied = 0;
while (count > 0) {
int this_len, retval;
@@ -905,7 +690,8 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf,
if (copy_from_user(buffer, buf, count))
return -EFAULT;
oom_adjust = simple_strtol(buffer, &end, 0);
- if ((oom_adjust < -16 || oom_adjust > 15) && oom_adjust != OOM_DISABLE)
+ if ((oom_adjust < OOM_ADJUST_MIN || oom_adjust > OOM_ADJUST_MAX) &&
+ oom_adjust != OOM_DISABLE)
return -EINVAL;
if (*end == '\n')
end++;
@@ -1136,143 +922,6 @@ static struct inode_operations proc_pid_link_inode_operations = {
.setattr = proc_setattr,
};
-static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
-{
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct task_struct *p = get_proc_task(inode);
- unsigned int fd, tid, ino;
- int retval;
- char buf[PROC_NUMBUF];
- struct files_struct * files;
- struct fdtable *fdt;
-
- retval = -ENOENT;
- if (!p)
- goto out_no_task;
- retval = 0;
- tid = p->pid;
-
- fd = filp->f_pos;
- switch (fd) {
- case 0:
- if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
- goto out;
- filp->f_pos++;
- case 1:
- ino = parent_ino(dentry);
- if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
- goto out;
- filp->f_pos++;
- default:
- files = get_files_struct(p);
- if (!files)
- goto out;
- rcu_read_lock();
- fdt = files_fdtable(files);
- for (fd = filp->f_pos-2;
- fd < fdt->max_fds;
- fd++, filp->f_pos++) {
- unsigned int i,j;
-
- if (!fcheck_files(files, fd))
- continue;
- rcu_read_unlock();
-
- j = PROC_NUMBUF;
- i = fd;
- do {
- j--;
- buf[j] = '0' + (i % 10);
- i /= 10;
- } while (i);
-
- ino = fake_ino(tid, PROC_TID_FD_DIR + fd);
- if (filldir(dirent, buf+j, PROC_NUMBUF-j, fd+2, ino, DT_LNK) < 0) {
- rcu_read_lock();
- break;
- }
- rcu_read_lock();
- }
- rcu_read_unlock();
- put_files_struct(files);
- }
-out:
- put_task_struct(p);
-out_no_task:
- return retval;
-}
-
-static int proc_pident_readdir(struct file *filp,
- void *dirent, filldir_t filldir,
- struct pid_entry *ents, unsigned int nents)
-{
- int i;
- int pid;
- struct dentry *dentry = filp->f_dentry;
- struct inode *inode = dentry->d_inode;
- struct task_struct *task = get_proc_task(inode);
- struct pid_entry *p;
- ino_t ino;
- int ret;
-
- ret = -ENOENT;
- if (!task)
- goto out;
-
- ret = 0;
- pid = task->pid;
- put_task_struct(task);
- i = filp->f_pos;
- switch (i) {
- case 0:
- ino = inode->i_ino;
- if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
- goto out;
- i++;
- filp->f_pos++;
- /* fall through */
- case 1:
- ino = parent_ino(dentry);
- if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
- goto out;
- i++;
- filp->f_pos++;
- /* fall through */
- default:
- i -= 2;
- if (i >= nents) {
- ret = 1;
- goto out;
- }
- p = ents + i;
- while (p->name) {
- if (filldir(dirent, p->name, p->len, filp->f_pos,
- fake_ino(pid, p->type), p->mode >> 12) < 0)
- goto out;
- filp->f_pos++;
- p++;
- }
- }
-
- ret = 1;
-out:
- return ret;
-}
-
-static int proc_tgid_base_readdir(struct file * filp,
- void * dirent, filldir_t filldir)
-{
- return proc_pident_readdir(filp,dirent,filldir,
- tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
-}
-
-static int proc_tid_base_readdir(struct file * filp,
- void * dirent, filldir_t filldir)
-{
- return proc_pident_readdir(filp,dirent,filldir,
- tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
-}
/* building an inode */
@@ -1292,13 +941,13 @@ static int task_dumpable(struct task_struct *task)
}
-static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino)
+static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task)
{
struct inode * inode;
struct proc_inode *ei;
/* We need a new inode */
-
+
inode = new_inode(sb);
if (!inode)
goto out;
@@ -1306,13 +955,12 @@ static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_st
/* Common stuff */
ei = PROC_I(inode);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_ino = fake_ino(task->pid, ino);
inode->i_op = &proc_def_inode_operations;
/*
* grab the reference to task.
*/
- ei->pid = get_pid(task->pids[PIDTYPE_PID].pid);
+ ei->pid = get_task_pid(task, PIDTYPE_PID);
if (!ei->pid)
goto out_unlock;
@@ -1332,6 +980,27 @@ out_unlock:
return NULL;
}
+static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+{
+ struct inode *inode = dentry->d_inode;
+ struct task_struct *task;
+ generic_fillattr(inode, stat);
+
+ rcu_read_lock();
+ stat->uid = 0;
+ stat->gid = 0;
+ task = pid_task(proc_pid(inode), PIDTYPE_PID);
+ if (task) {
+ if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
+ task_dumpable(task)) {
+ stat->uid = task->euid;
+ stat->gid = task->egid;
+ }
+ }
+ rcu_read_unlock();
+ return 0;
+}
+
/* dentry stuff */
/*
@@ -1371,25 +1040,130 @@ static int pid_revalidate(struct dentry *dentry, struct nameidata *nd)
return 0;
}
-static int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
+static int pid_delete_dentry(struct dentry * dentry)
{
- struct inode *inode = dentry->d_inode;
- struct task_struct *task;
- generic_fillattr(inode, stat);
+ /* Is the task we represent dead?
+ * If so, then don't put the dentry on the lru list,
+ * kill it immediately.
+ */
+ return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
+}
+
+static struct dentry_operations pid_dentry_operations =
+{
+ .d_revalidate = pid_revalidate,
+ .d_delete = pid_delete_dentry,
+};
+
+/* Lookups */
+
+typedef struct dentry *instantiate_t(struct inode *, struct dentry *, struct task_struct *, void *);
+
+/*
+ * Fill a directory entry.
+ *
+ * If possible create the dcache entry and derive our inode number and
+ * file type from dcache entry.
+ *
+ * Since all of the proc inode numbers are dynamically generated, the inode
+ * numbers do not exist until the inode is cache. This means creating the
+ * the dcache entry in readdir is necessary to keep the inode numbers
+ * reported by readdir in sync with the inode numbers reported
+ * by stat.
+ */
+static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ char *name, int len,
+ instantiate_t instantiate, struct task_struct *task, void *ptr)
+{
+ struct dentry *child, *dir = filp->f_dentry;
+ struct inode *inode;
+ struct qstr qname;
+ ino_t ino = 0;
+ unsigned type = DT_UNKNOWN;
+
+ qname.name = name;
+ qname.len = len;
+ qname.hash = full_name_hash(name, len);
+
+ child = d_lookup(dir, &qname);
+ if (!child) {
+ struct dentry *new;
+ new = d_alloc(dir, &qname);
+ if (new) {
+ child = instantiate(dir->d_inode, new, task, ptr);
+ if (child)
+ dput(new);
+ else
+ child = new;
+ }
+ }
+ if (!child || IS_ERR(child) || !child->d_inode)
+ goto end_instantiate;
+ inode = child->d_inode;
+ if (inode) {
+ ino = inode->i_ino;
+ type = inode->i_mode >> 12;
+ }
+ dput(child);
+end_instantiate:
+ if (!ino)
+ ino = find_inode_number(dir, &qname);
+ if (!ino)
+ ino = 1;
+ return filldir(dirent, name, len, filp->f_pos, ino, type);
+}
+
+static unsigned name_to_int(struct dentry *dentry)
+{
+ const char *name = dentry->d_name.name;
+ int len = dentry->d_name.len;
+ unsigned n = 0;
+
+ if (len > 1 && *name == '0')
+ goto out;
+ while (len-- > 0) {
+ unsigned c = *name++ - '0';
+ if (c > 9)
+ goto out;
+ if (n >= (~0U-9)/10)
+ goto out;
+ n *= 10;
+ n += c;
+ }
+ return n;
+out:
+ return ~0U;
+}
+
+static int proc_fd_link(struct inode *inode, struct dentry **dentry, struct vfsmount **mnt)
+{
+ struct task_struct *task = get_proc_task(inode);
+ struct files_struct *files = NULL;
+ struct file *file;
+ int fd = proc_fd(inode);
- rcu_read_lock();
- stat->uid = 0;
- stat->gid = 0;
- task = pid_task(proc_pid(inode), PIDTYPE_PID);
if (task) {
- if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) ||
- task_dumpable(task)) {
- stat->uid = task->euid;
- stat->gid = task->egid;
+ files = get_files_struct(task);
+ put_task_struct(task);
+ }
+ if (files) {
+ /*
+ * We are not taking a ref to the file structure, so we must
+ * hold ->file_lock.
+ */
+ spin_lock(&files->file_lock);
+ file = fcheck_files(files, fd);
+ if (file) {
+ *mnt = mntget(file->f_vfsmnt);
+ *dentry = dget(file->f_dentry);
+ spin_unlock(&files->file_lock);
+ put_files_struct(files);
+ return 0;
}
+ spin_unlock(&files->file_lock);
+ put_files_struct(files);
}
- rcu_read_unlock();
- return 0;
+ return -ENOENT;
}
static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
@@ -1427,75 +1201,30 @@ static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd)
return 0;
}
-static int pid_delete_dentry(struct dentry * dentry)
-{
- /* Is the task we represent dead?
- * If so, then don't put the dentry on the lru list,
- * kill it immediately.
- */
- return !proc_pid(dentry->d_inode)->tasks[PIDTYPE_PID].first;
-}
-
static struct dentry_operations tid_fd_dentry_operations =
{
.d_revalidate = tid_fd_revalidate,
.d_delete = pid_delete_dentry,
};
-static struct dentry_operations pid_dentry_operations =
-{
- .d_revalidate = pid_revalidate,
- .d_delete = pid_delete_dentry,
-};
-
-/* Lookups */
-
-static unsigned name_to_int(struct dentry *dentry)
-{
- const char *name = dentry->d_name.name;
- int len = dentry->d_name.len;
- unsigned n = 0;
-
- if (len > 1 && *name == '0')
- goto out;
- while (len-- > 0) {
- unsigned c = *name++ - '0';
- if (c > 9)
- goto out;
- if (n >= (~0U-9)/10)
- goto out;
- n *= 10;
- n += c;
- }
- return n;
-out:
- return ~0U;
-}
-
-/* SMP-safe */
-static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *proc_fd_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
{
- struct task_struct *task = get_proc_task(dir);
- unsigned fd = name_to_int(dentry);
- struct dentry *result = ERR_PTR(-ENOENT);
- struct file * file;
- struct files_struct * files;
- struct inode *inode;
- struct proc_inode *ei;
-
- if (!task)
- goto out_no_task;
- if (fd == ~0U)
- goto out;
+ unsigned fd = *(unsigned *)ptr;
+ struct file *file;
+ struct files_struct *files;
+ struct inode *inode;
+ struct proc_inode *ei;
+ struct dentry *error = ERR_PTR(-ENOENT);
- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd);
+ inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
goto out;
ei = PROC_I(inode);
ei->fd = fd;
files = get_files_struct(task);
if (!files)
- goto out_unlock;
+ goto out_iput;
inode->i_mode = S_IFLNK;
/*
@@ -1505,13 +1234,14 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
spin_lock(&files->file_lock);
file = fcheck_files(files, fd);
if (!file)
- goto out_unlock2;
+ goto out_unlock;
if (file->f_mode & 1)
inode->i_mode |= S_IRUSR | S_IXUSR;
if (file->f_mode & 2)
inode->i_mode |= S_IWUSR | S_IXUSR;
spin_unlock(&files->file_lock);
put_files_struct(files);
+
inode->i_op = &proc_pid_link_inode_operations;
inode->i_size = 64;
ei->op.proc_get_link = proc_fd_link;
@@ -1519,34 +1249,106 @@ static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry,
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (tid_fd_revalidate(dentry, NULL))
- result = NULL;
-out:
- put_task_struct(task);
-out_no_task:
- return result;
+ error = NULL;
-out_unlock2:
+ out:
+ return error;
+out_unlock:
spin_unlock(&files->file_lock);
put_files_struct(files);
-out_unlock:
+out_iput:
iput(inode);
goto out;
}
-static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir);
-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd);
-static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+{
+ struct task_struct *task = get_proc_task(dir);
+ unsigned fd = name_to_int(dentry);
+ struct dentry *result = ERR_PTR(-ENOENT);
+
+ if (!task)
+ goto out_no_task;
+ if (fd == ~0U)
+ goto out;
+
+ result = proc_fd_instantiate(dir, dentry, task, &fd);
+out:
+ put_task_struct(task);
+out_no_task:
+ return result;
+}
+
+static int proc_fd_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, int fd)
+{
+ char name[PROC_NUMBUF];
+ int len = snprintf(name, sizeof(name), "%d", fd);
+ return proc_fill_cache(filp, dirent, filldir, name, len,
+ proc_fd_instantiate, task, &fd);
+}
+
+static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir)
+{
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct task_struct *p = get_proc_task(inode);
+ unsigned int fd, tid, ino;
+ int retval;
+ struct files_struct * files;
+ struct fdtable *fdt;
+
+ retval = -ENOENT;
+ if (!p)
+ goto out_no_task;
+ retval = 0;
+ tid = p->pid;
+
+ fd = filp->f_pos;
+ switch (fd) {
+ case 0:
+ if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0)
+ goto out;
+ filp->f_pos++;
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0)
+ goto out;
+ filp->f_pos++;
+ default:
+ files = get_files_struct(p);
+ if (!files)
+ goto out;
+ rcu_read_lock();
+ fdt = files_fdtable(files);
+ for (fd = filp->f_pos-2;
+ fd < fdt->max_fds;
+ fd++, filp->f_pos++) {
+
+ if (!fcheck_files(files, fd))
+ continue;
+ rcu_read_unlock();
+
+ if (proc_fd_fill_cache(filp, dirent, filldir, p, fd) < 0) {
+ rcu_read_lock();
+ break;
+ }
+ rcu_read_lock();
+ }
+ rcu_read_unlock();
+ put_files_struct(files);
+ }
+out:
+ put_task_struct(p);
+out_no_task:
+ return retval;
+}
static struct file_operations proc_fd_operations = {
.read = generic_read_dir,
.readdir = proc_readfd,
};
-static struct file_operations proc_task_operations = {
- .read = generic_read_dir,
- .readdir = proc_task_readdir,
-};
-
/*
* proc directories can do almost nothing..
*/
@@ -1555,11 +1357,137 @@ static struct inode_operations proc_fd_inode_operations = {
.setattr = proc_setattr,
};
-static struct inode_operations proc_task_inode_operations = {
- .lookup = proc_task_lookup,
- .getattr = proc_task_getattr,
- .setattr = proc_setattr,
-};
+static struct dentry *proc_pident_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+ struct pid_entry *p = ptr;
+ struct inode *inode;
+ struct proc_inode *ei;
+ struct dentry *error = ERR_PTR(-EINVAL);
+
+ inode = proc_pid_make_inode(dir->i_sb, task);
+ if (!inode)
+ goto out;
+
+ ei = PROC_I(inode);
+ inode->i_mode = p->mode;
+ if (S_ISDIR(inode->i_mode))
+ inode->i_nlink = 2; /* Use getattr to fix if necessary */
+ if (p->iop)
+ inode->i_op = p->iop;
+ if (p->fop)
+ inode->i_fop = p->fop;
+ ei->op = p->op;
+ dentry->d_op = &pid_dentry_operations;
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (pid_revalidate(dentry, NULL))
+ error = NULL;
+out:
+ return error;
+}
+
+static struct dentry *proc_pident_lookup(struct inode *dir,
+ struct dentry *dentry,
+ struct pid_entry *ents,
+ unsigned int nents)
+{
+ struct inode *inode;
+ struct dentry *error;
+ struct task_struct *task = get_proc_task(dir);
+ struct pid_entry *p, *last;
+
+ error = ERR_PTR(-ENOENT);
+ inode = NULL;
+
+ if (!task)
+ goto out_no_task;
+
+ /*
+ * Yes, it does not scale. And it should not. Don't add
+ * new entries into /proc/<tgid>/ without very good reasons.
+ */
+ last = &ents[nents - 1];
+ for (p = ents; p <= last; p++) {
+ if (p->len != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, p->name, p->len))
+ break;
+ }
+ if (p > last)
+ goto out;
+
+ error = proc_pident_instantiate(dir, dentry, task, p);
+out:
+ put_task_struct(task);
+out_no_task:
+ return error;
+}
+
+static int proc_pident_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, struct pid_entry *p)
+{
+ return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ proc_pident_instantiate, task, p);
+}
+
+static int proc_pident_readdir(struct file *filp,
+ void *dirent, filldir_t filldir,
+ struct pid_entry *ents, unsigned int nents)
+{
+ int i;
+ int pid;
+ struct dentry *dentry = filp->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ struct task_struct *task = get_proc_task(inode);
+ struct pid_entry *p, *last;
+ ino_t ino;
+ int ret;
+
+ ret = -ENOENT;
+ if (!task)
+ goto out_no_task;
+
+ ret = 0;
+ pid = task->pid;
+ i = filp->f_pos;
+ switch (i) {
+ case 0:
+ ino = inode->i_ino;
+ if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
+ goto out;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ case 1:
+ ino = parent_ino(dentry);
+ if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
+ goto out;
+ i++;
+ filp->f_pos++;
+ /* fall through */
+ default:
+ i -= 2;
+ if (i >= nents) {
+ ret = 1;
+ goto out;
+ }
+ p = ents + i;
+ last = &ents[nents - 1];
+ while (p <= last) {
+ if (proc_pident_fill_cache(filp, dirent, filldir, task, p) < 0)
+ goto out;
+ filp->f_pos++;
+ p++;
+ }
+ }
+
+ ret = 1;
+out:
+ put_task_struct(task);
+out_no_task:
+ return ret;
+}
#ifdef CONFIG_SECURITY
static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
@@ -1580,8 +1508,8 @@ static ssize_t proc_pid_attr_read(struct file * file, char __user * buf,
if (!(page = __get_free_page(GFP_KERNEL)))
goto out;
- length = security_getprocattr(task,
- (char*)file->f_dentry->d_name.name,
+ length = security_getprocattr(task,
+ (char*)file->f_dentry->d_name.name,
(void*)page, count);
if (length >= 0)
length = simple_read_from_buffer(buf, count, ppos, (char *)page, length);
@@ -1594,17 +1522,17 @@ out_no_task:
static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
-{
+{
struct inode * inode = file->f_dentry->d_inode;
- char *page;
- ssize_t length;
+ char *page;
+ ssize_t length;
struct task_struct *task = get_proc_task(inode);
length = -ESRCH;
if (!task)
goto out_no_task;
- if (count > PAGE_SIZE)
- count = PAGE_SIZE;
+ if (count > PAGE_SIZE)
+ count = PAGE_SIZE;
/* No partial writes. */
length = -EINVAL;
@@ -1612,16 +1540,16 @@ static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf,
goto out;
length = -ENOMEM;
- page = (char*)__get_free_page(GFP_USER);
- if (!page)
+ page = (char*)__get_free_page(GFP_USER);
+ if (!page)
goto out;
- length = -EFAULT;
- if (copy_from_user(page, buf, count))
+ length = -EFAULT;
+ if (copy_from_user(page, buf, count))
goto out_free;
- length = security_setprocattr(task,
- (char*)file->f_dentry->d_name.name,
+ length = security_setprocattr(task,
+ (char*)file->f_dentry->d_name.name,
(void*)page, count);
out_free:
free_page((unsigned long) page);
@@ -1629,330 +1557,263 @@ out:
put_task_struct(task);
out_no_task:
return length;
-}
+}
static struct file_operations proc_pid_attr_operations = {
.read = proc_pid_attr_read,
.write = proc_pid_attr_write,
};
-static struct file_operations proc_tid_attr_operations;
-static struct inode_operations proc_tid_attr_inode_operations;
-static struct file_operations proc_tgid_attr_operations;
-static struct inode_operations proc_tgid_attr_inode_operations;
+static struct pid_entry attr_dir_stuff[] = {
+ REG("current", S_IRUGO|S_IWUGO, pid_attr),
+ REG("prev", S_IRUGO, pid_attr),
+ REG("exec", S_IRUGO|S_IWUGO, pid_attr),
+ REG("fscreate", S_IRUGO|S_IWUGO, pid_attr),
+ REG("keycreate", S_IRUGO|S_IWUGO, pid_attr),
+ REG("sockcreate", S_IRUGO|S_IWUGO, pid_attr),
+};
+
+static int proc_attr_dir_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ return proc_pident_readdir(filp,dirent,filldir,
+ attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff));
+}
+
+static struct file_operations proc_attr_dir_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_attr_dir_readdir,
+};
+
+static struct dentry *proc_attr_dir_lookup(struct inode *dir,
+ struct dentry *dentry, struct nameidata *nd)
+{
+ return proc_pident_lookup(dir, dentry,
+ attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff));
+}
+
+static struct inode_operations proc_attr_dir_inode_operations = {
+ .lookup = proc_attr_dir_lookup,
+ .getattr = pid_getattr,
+ .setattr = proc_setattr,
+};
+
#endif
-/* SMP-safe */
-static struct dentry *proc_pident_lookup(struct inode *dir,
- struct dentry *dentry,
- struct pid_entry *ents)
+/*
+ * /proc/self:
+ */
+static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
+ int buflen)
+{
+ char tmp[PROC_NUMBUF];
+ sprintf(tmp, "%d", current->tgid);
+ return vfs_readlink(dentry,buffer,buflen,tmp);
+}
+
+static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
{
+ char tmp[PROC_NUMBUF];
+ sprintf(tmp, "%d", current->tgid);
+ return ERR_PTR(vfs_follow_link(nd,tmp));
+}
+
+static struct inode_operations proc_self_inode_operations = {
+ .readlink = proc_self_readlink,
+ .follow_link = proc_self_follow_link,
+};
+
+/*
+ * proc base
+ *
+ * These are the directory entries in the root directory of /proc
+ * that properly belong to the /proc filesystem, as they describe
+ * describe something that is process related.
+ */
+static struct pid_entry proc_base_stuff[] = {
+ NOD("self", S_IFLNK|S_IRWXUGO,
+ &proc_self_inode_operations, NULL, {}),
+};
+
+/*
+ * Exceptional case: normally we are not allowed to unhash a busy
+ * directory. In this case, however, we can do it - no aliasing problems
+ * due to the way we treat inodes.
+ */
+static int proc_base_revalidate(struct dentry *dentry, struct nameidata *nd)
+{
+ struct inode *inode = dentry->d_inode;
+ struct task_struct *task = get_proc_task(inode);
+ if (task) {
+ put_task_struct(task);
+ return 1;
+ }
+ d_drop(dentry);
+ return 0;
+}
+
+static struct dentry_operations proc_base_dentry_operations =
+{
+ .d_revalidate = proc_base_revalidate,
+ .d_delete = pid_delete_dentry,
+};
+
+static struct dentry *proc_base_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+ struct pid_entry *p = ptr;
struct inode *inode;
+ struct proc_inode *ei;
+ struct dentry *error = ERR_PTR(-EINVAL);
+
+ /* Allocate the inode */
+ error = ERR_PTR(-ENOMEM);
+ inode = new_inode(dir->i_sb);
+ if (!inode)
+ goto out;
+
+ /* Initialize the inode */
+ ei = PROC_I(inode);
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+
+ /*
+ * grab the reference to the task.
+ */
+ ei->pid = get_task_pid(task, PIDTYPE_PID);
+ if (!ei->pid)
+ goto out_iput;
+
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_mode = p->mode;
+ if (S_ISDIR(inode->i_mode))
+ inode->i_nlink = 2;
+ if (S_ISLNK(inode->i_mode))
+ inode->i_size = 64;
+ if (p->iop)
+ inode->i_op = p->iop;
+ if (p->fop)
+ inode->i_fop = p->fop;
+ ei->op = p->op;
+ dentry->d_op = &proc_base_dentry_operations;
+ d_add(dentry, inode);
+ error = NULL;
+out:
+ return error;
+out_iput:
+ iput(inode);
+ goto out;
+}
+
+static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry)
+{
struct dentry *error;
struct task_struct *task = get_proc_task(dir);
- struct pid_entry *p;
- struct proc_inode *ei;
+ struct pid_entry *p, *last;
error = ERR_PTR(-ENOENT);
- inode = NULL;
if (!task)
goto out_no_task;
- for (p = ents; p->name; p++) {
+ /* Lookup the directory entry */
+ last = &proc_base_stuff[ARRAY_SIZE(proc_base_stuff) - 1];
+ for (p = proc_base_stuff; p <= last; p++) {
if (p->len != dentry->d_name.len)
continue;
if (!memcmp(dentry->d_name.name, p->name, p->len))
break;
}
- if (!p->name)
+ if (p > last)
goto out;
- error = ERR_PTR(-EINVAL);
- inode = proc_pid_make_inode(dir->i_sb, task, p->type);
- if (!inode)
- goto out;
+ error = proc_base_instantiate(dir, dentry, task, p);
- ei = PROC_I(inode);
- inode->i_mode = p->mode;
- /*
- * Yes, it does not scale. And it should not. Don't add
- * new entries into /proc/<tgid>/ without very good reasons.
- */
- switch(p->type) {
- case PROC_TGID_TASK:
- inode->i_nlink = 2;
- inode->i_op = &proc_task_inode_operations;
- inode->i_fop = &proc_task_operations;
- break;
- case PROC_TID_FD:
- case PROC_TGID_FD:
- inode->i_nlink = 2;
- inode->i_op = &proc_fd_inode_operations;
- inode->i_fop = &proc_fd_operations;
- break;
- case PROC_TID_EXE:
- case PROC_TGID_EXE:
- inode->i_op = &proc_pid_link_inode_operations;
- ei->op.proc_get_link = proc_exe_link;
- break;
- case PROC_TID_CWD:
- case PROC_TGID_CWD:
- inode->i_op = &proc_pid_link_inode_operations;
- ei->op.proc_get_link = proc_cwd_link;
- break;
- case PROC_TID_ROOT:
- case PROC_TGID_ROOT:
- inode->i_op = &proc_pid_link_inode_operations;
- ei->op.proc_get_link = proc_root_link;
- break;
- case PROC_TID_ENVIRON:
- case PROC_TGID_ENVIRON:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_pid_environ;
- break;
- case PROC_TID_AUXV:
- case PROC_TGID_AUXV:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_pid_auxv;
- break;
- case PROC_TID_STATUS:
- case PROC_TGID_STATUS:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_pid_status;
- break;
- case PROC_TID_STAT:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_tid_stat;
- break;
- case PROC_TGID_STAT:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_tgid_stat;
- break;
- case PROC_TID_CMDLINE:
- case PROC_TGID_CMDLINE:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_pid_cmdline;
- break;
- case PROC_TID_STATM:
- case PROC_TGID_STATM:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_pid_statm;
- break;
- case PROC_TID_MAPS:
- case PROC_TGID_MAPS:
- inode->i_fop = &proc_maps_operations;
- break;
+out:
+ put_task_struct(task);
+out_no_task:
+ return error;
+}
+
+static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, struct pid_entry *p)
+{
+ return proc_fill_cache(filp, dirent, filldir, p->name, p->len,
+ proc_base_instantiate, task, p);
+}
+
+/*
+ * Thread groups
+ */
+static struct file_operations proc_task_operations;
+static struct inode_operations proc_task_inode_operations;
+
+static struct pid_entry tgid_base_stuff[] = {
+ DIR("task", S_IRUGO|S_IXUGO, task),
+ DIR("fd", S_IRUSR|S_IXUSR, fd),
+ INF("environ", S_IRUSR, pid_environ),
+ INF("auxv", S_IRUSR, pid_auxv),
+ INF("status", S_IRUGO, pid_status),
+ INF("cmdline", S_IRUGO, pid_cmdline),
+ INF("stat", S_IRUGO, tgid_stat),
+ INF("statm", S_IRUGO, pid_statm),
+ REG("maps", S_IRUGO, maps),
#ifdef CONFIG_NUMA
- case PROC_TID_NUMA_MAPS:
- case PROC_TGID_NUMA_MAPS:
- inode->i_fop = &proc_numa_maps_operations;
- break;
+ REG("numa_maps", S_IRUGO, numa_maps),
#endif
- case PROC_TID_MEM:
- case PROC_TGID_MEM:
- inode->i_fop = &proc_mem_operations;
- break;
+ REG("mem", S_IRUSR|S_IWUSR, mem),
#ifdef CONFIG_SECCOMP
- case PROC_TID_SECCOMP:
- case PROC_TGID_SECCOMP:
- inode->i_fop = &proc_seccomp_operations;
- break;
-#endif /* CONFIG_SECCOMP */
- case PROC_TID_MOUNTS:
- case PROC_TGID_MOUNTS:
- inode->i_fop = &proc_mounts_operations;
- break;
+ REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
+#endif
+ LNK("cwd", cwd),
+ LNK("root", root),
+ LNK("exe", exe),
+ REG("mounts", S_IRUGO, mounts),
+ REG("mountstats", S_IRUSR, mountstats),
#ifdef CONFIG_MMU
- case PROC_TID_SMAPS:
- case PROC_TGID_SMAPS:
- inode->i_fop = &proc_smaps_operations;
- break;
+ REG("smaps", S_IRUGO, smaps),
#endif
- case PROC_TID_MOUNTSTATS:
- case PROC_TGID_MOUNTSTATS:
- inode->i_fop = &proc_mountstats_operations;
- break;
#ifdef CONFIG_SECURITY
- case PROC_TID_ATTR:
- inode->i_nlink = 2;
- inode->i_op = &proc_tid_attr_inode_operations;
- inode->i_fop = &proc_tid_attr_operations;
- break;
- case PROC_TGID_ATTR:
- inode->i_nlink = 2;
- inode->i_op = &proc_tgid_attr_inode_operations;
- inode->i_fop = &proc_tgid_attr_operations;
- break;
- case PROC_TID_ATTR_CURRENT:
- case PROC_TGID_ATTR_CURRENT:
- case PROC_TID_ATTR_PREV:
- case PROC_TGID_ATTR_PREV:
- case PROC_TID_ATTR_EXEC:
- case PROC_TGID_ATTR_EXEC:
- case PROC_TID_ATTR_FSCREATE:
- case PROC_TGID_ATTR_FSCREATE:
- case PROC_TID_ATTR_KEYCREATE:
- case PROC_TGID_ATTR_KEYCREATE:
- case PROC_TID_ATTR_SOCKCREATE:
- case PROC_TGID_ATTR_SOCKCREATE:
- inode->i_fop = &proc_pid_attr_operations;
- break;
+ DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
#endif
#ifdef CONFIG_KALLSYMS
- case PROC_TID_WCHAN:
- case PROC_TGID_WCHAN:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_pid_wchan;
- break;
+ INF("wchan", S_IRUGO, pid_wchan),
#endif
#ifdef CONFIG_SCHEDSTATS
- case PROC_TID_SCHEDSTAT:
- case PROC_TGID_SCHEDSTAT:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_pid_schedstat;
- break;
+ INF("schedstat", S_IRUGO, pid_schedstat),
#endif
#ifdef CONFIG_CPUSETS
- case PROC_TID_CPUSET:
- case PROC_TGID_CPUSET:
- inode->i_fop = &proc_cpuset_operations;
- break;
+ REG("cpuset", S_IRUGO, cpuset),
#endif
- case PROC_TID_OOM_SCORE:
- case PROC_TGID_OOM_SCORE:
- inode->i_fop = &proc_info_file_operations;
- ei->op.proc_read = proc_oom_score;
- break;
- case PROC_TID_OOM_ADJUST:
- case PROC_TGID_OOM_ADJUST:
- inode->i_fop = &proc_oom_adjust_operations;
- break;
+ INF("oom_score", S_IRUGO, oom_score),
+ REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
#ifdef CONFIG_AUDITSYSCALL
- case PROC_TID_LOGINUID:
- case PROC_TGID_LOGINUID:
- inode->i_fop = &proc_loginuid_operations;
- break;
+ REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
#endif
- default:
- printk("procfs: impossible type (%d)",p->type);
- iput(inode);
- error = ERR_PTR(-EINVAL);
- goto out;
- }
- dentry->d_op = &pid_dentry_operations;
- d_add(dentry, inode);
- /* Close the race of the process dying before we return the dentry */
- if (pid_revalidate(dentry, NULL))
- error = NULL;
-out:
- put_task_struct(task);
-out_no_task:
- return error;
-}
-
-static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
- return proc_pident_lookup(dir, dentry, tgid_base_stuff);
-}
-
-static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
- return proc_pident_lookup(dir, dentry, tid_base_stuff);
-}
-
-static struct file_operations proc_tgid_base_operations = {
- .read = generic_read_dir,
- .readdir = proc_tgid_base_readdir,
};
-static struct file_operations proc_tid_base_operations = {
- .read = generic_read_dir,
- .readdir = proc_tid_base_readdir,
-};
-
-static struct inode_operations proc_tgid_base_inode_operations = {
- .lookup = proc_tgid_base_lookup,
- .getattr = pid_getattr,
- .setattr = proc_setattr,
-};
-
-static struct inode_operations proc_tid_base_inode_operations = {
- .lookup = proc_tid_base_lookup,
- .getattr = pid_getattr,
- .setattr = proc_setattr,
-};
-
-#ifdef CONFIG_SECURITY
-static int proc_tgid_attr_readdir(struct file * filp,
- void * dirent, filldir_t filldir)
-{
- return proc_pident_readdir(filp,dirent,filldir,
- tgid_attr_stuff,ARRAY_SIZE(tgid_attr_stuff));
-}
-
-static int proc_tid_attr_readdir(struct file * filp,
+static int proc_tgid_base_readdir(struct file * filp,
void * dirent, filldir_t filldir)
{
return proc_pident_readdir(filp,dirent,filldir,
- tid_attr_stuff,ARRAY_SIZE(tid_attr_stuff));
+ tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));
}
-static struct file_operations proc_tgid_attr_operations = {
- .read = generic_read_dir,
- .readdir = proc_tgid_attr_readdir,
-};
-
-static struct file_operations proc_tid_attr_operations = {
+static struct file_operations proc_tgid_base_operations = {
.read = generic_read_dir,
- .readdir = proc_tid_attr_readdir,
+ .readdir = proc_tgid_base_readdir,
};
-static struct dentry *proc_tgid_attr_lookup(struct inode *dir,
- struct dentry *dentry, struct nameidata *nd)
-{
- return proc_pident_lookup(dir, dentry, tgid_attr_stuff);
-}
-
-static struct dentry *proc_tid_attr_lookup(struct inode *dir,
- struct dentry *dentry, struct nameidata *nd)
-{
- return proc_pident_lookup(dir, dentry, tid_attr_stuff);
+static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+ return proc_pident_lookup(dir, dentry,
+ tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff));
}
-static struct inode_operations proc_tgid_attr_inode_operations = {
- .lookup = proc_tgid_attr_lookup,
- .getattr = pid_getattr,
- .setattr = proc_setattr,
-};
-
-static struct inode_operations proc_tid_attr_inode_operations = {
- .lookup = proc_tid_attr_lookup,
+static struct inode_operations proc_tgid_base_inode_operations = {
+ .lookup = proc_tgid_base_lookup,
.getattr = pid_getattr,
.setattr = proc_setattr,
};
-#endif
-
-/*
- * /proc/self:
- */
-static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
- int buflen)
-{
- char tmp[PROC_NUMBUF];
- sprintf(tmp, "%d", current->tgid);
- return vfs_readlink(dentry,buffer,buflen,tmp);
-}
-
-static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
-{
- char tmp[PROC_NUMBUF];
- sprintf(tmp, "%d", current->tgid);
- return ERR_PTR(vfs_follow_link(nd,tmp));
-}
-
-static struct inode_operations proc_self_inode_operations = {
- .readlink = proc_self_readlink,
- .follow_link = proc_self_follow_link,
-};
/**
* proc_flush_task - Remove dcache entries for @task from the /proc dcache.
@@ -2021,54 +1882,23 @@ out:
return;
}
-/* SMP-safe */
-struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *proc_pid_instantiate(struct inode *dir,
+ struct dentry * dentry, struct task_struct *task, void *ptr)
{
- struct dentry *result = ERR_PTR(-ENOENT);
- struct task_struct *task;
+ struct dentry *error = ERR_PTR(-ENOENT);
struct inode *inode;
- struct proc_inode *ei;
- unsigned tgid;
-
- if (dentry->d_name.len == 4 && !memcmp(dentry->d_name.name,"self",4)) {
- inode = new_inode(dir->i_sb);
- if (!inode)
- return ERR_PTR(-ENOMEM);
- ei = PROC_I(inode);
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_ino = fake_ino(0, PROC_TGID_INO);
- ei->pde = NULL;
- inode->i_mode = S_IFLNK|S_IRWXUGO;
- inode->i_uid = inode->i_gid = 0;
- inode->i_size = 64;
- inode->i_op = &proc_self_inode_operations;
- d_add(dentry, inode);
- return NULL;
- }
- tgid = name_to_int(dentry);
- if (tgid == ~0U)
- goto out;
- rcu_read_lock();
- task = find_task_by_pid(tgid);
- if (task)
- get_task_struct(task);
- rcu_read_unlock();
- if (!task)
- goto out;
-
- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO);
+ inode = proc_pid_make_inode(dir->i_sb, task);
if (!inode)
- goto out_put_task;
+ goto out;
inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
inode->i_op = &proc_tgid_base_inode_operations;
inode->i_fop = &proc_tgid_base_operations;
inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
- inode->i_nlink = 5;
-#else
inode->i_nlink = 4;
+#ifdef CONFIG_SECURITY
+ inode->i_nlink += 1;
#endif
dentry->d_op = &pid_dentry_operations;
@@ -2076,179 +1906,251 @@ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct
d_add(dentry, inode);
/* Close the race of the process dying before we return the dentry */
if (pid_revalidate(dentry, NULL))
- result = NULL;
-
-out_put_task:
- put_task_struct(task);
+ error = NULL;
out:
- return result;
+ return error;
}
-/* SMP-safe */
-static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
{
struct dentry *result = ERR_PTR(-ENOENT);
struct task_struct *task;
- struct task_struct *leader = get_proc_task(dir);
- struct inode *inode;
- unsigned tid;
+ unsigned tgid;
- if (!leader)
- goto out_no_task;
+ result = proc_base_lookup(dir, dentry);
+ if (!IS_ERR(result) || PTR_ERR(result) != -ENOENT)
+ goto out;
- tid = name_to_int(dentry);
- if (tid == ~0U)
+ tgid = name_to_int(dentry);
+ if (tgid == ~0U)
goto out;
rcu_read_lock();
- task = find_task_by_pid(tid);
+ task = find_task_by_pid(tgid);
if (task)
get_task_struct(task);
rcu_read_unlock();
if (!task)
goto out;
- if (leader->tgid != task->tgid)
- goto out_drop_task;
-
- inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO);
-
-
- if (!inode)
- goto out_drop_task;
- inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
- inode->i_op = &proc_tid_base_inode_operations;
- inode->i_fop = &proc_tid_base_operations;
- inode->i_flags|=S_IMMUTABLE;
-#ifdef CONFIG_SECURITY
- inode->i_nlink = 4;
-#else
- inode->i_nlink = 3;
-#endif
-
- dentry->d_op = &pid_dentry_operations;
-
- d_add(dentry, inode);
- /* Close the race of the process dying before we return the dentry */
- if (pid_revalidate(dentry, NULL))
- result = NULL;
-out_drop_task:
+ result = proc_pid_instantiate(dir, dentry, task, NULL);
put_task_struct(task);
out:
- put_task_struct(leader);
-out_no_task:
return result;
}
/*
- * Find the first tgid to return to user space.
- *
- * Usually this is just whatever follows &init_task, but if the users
- * buffer was too small to hold the full list or there was a seek into
- * the middle of the directory we have more work to do.
- *
- * In the case of a short read we start with find_task_by_pid.
+ * Find the first task with tgid >= tgid
*
- * In the case of a seek we start with &init_task and walk nr
- * threads past it.
*/
-static struct task_struct *first_tgid(int tgid, unsigned int nr)
+static struct task_struct *next_tgid(unsigned int tgid)
{
- struct task_struct *pos;
- rcu_read_lock();
- if (tgid && nr) {
- pos = find_task_by_pid(tgid);
- if (pos && thread_group_leader(pos))
- goto found;
- }
- /* If nr exceeds the number of processes get out quickly */
- pos = NULL;
- if (nr && nr >= nr_processes())
- goto done;
+ struct task_struct *task;
+ struct pid *pid;
- /* If we haven't found our starting place yet start with
- * the init_task and walk nr tasks forward.
- */
- for (pos = next_task(&init_task); nr > 0; --nr) {
- pos = next_task(pos);
- if (pos == &init_task) {
- pos = NULL;
- goto done;
- }
+ rcu_read_lock();
+retry:
+ task = NULL;
+ pid = find_ge_pid(tgid);
+ if (pid) {
+ tgid = pid->nr + 1;
+ task = pid_task(pid, PIDTYPE_PID);
+ /* What we to know is if the pid we have find is the
+ * pid of a thread_group_leader. Testing for task
+ * being a thread_group_leader is the obvious thing
+ * todo but there is a window when it fails, due to
+ * the pid transfer logic in de_thread.
+ *
+ * So we perform the straight forward test of seeing
+ * if the pid we have found is the pid of a thread
+ * group leader, and don't worry if the task we have
+ * found doesn't happen to be a thread group leader.
+ * As we don't care in the case of readdir.
+ */
+ if (!task || !has_group_leader_pid(task))
+ goto retry;
+ get_task_struct(task);
}
-found:
- get_task_struct(pos);
-done:
rcu_read_unlock();
- return pos;
+ return task;
}
-/*
- * Find the next task in the task list.
- * Return NULL if we loop or there is any error.
- *
- * The reference to the input task_struct is released.
- */
-static struct task_struct *next_tgid(struct task_struct *start)
+#define TGID_OFFSET (FIRST_PROCESS_ENTRY + ARRAY_SIZE(proc_base_stuff))
+
+static int proc_pid_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, int tgid)
{
- struct task_struct *pos;
- rcu_read_lock();
- pos = start;
- if (pid_alive(start))
- pos = next_task(start);
- if (pid_alive(pos) && (pos != &init_task)) {
- get_task_struct(pos);
- goto done;
- }
- pos = NULL;
-done:
- rcu_read_unlock();
- put_task_struct(start);
- return pos;
+ char name[PROC_NUMBUF];
+ int len = snprintf(name, sizeof(name), "%d", tgid);
+ return proc_fill_cache(filp, dirent, filldir, name, len,
+ proc_pid_instantiate, task, NULL);
}
/* for the /proc/ directory itself, after non-process stuff has been done */
int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- char buf[PROC_NUMBUF];
unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY;
+ struct task_struct *reaper = get_proc_task(filp->f_dentry->d_inode);
struct task_struct *task;
int tgid;
- if (!nr) {
- ino_t ino = fake_ino(0,PROC_TGID_INO);
- if (filldir(dirent, "self", 4, filp->f_pos, ino, DT_LNK) < 0)
- return 0;
- filp->f_pos++;
- nr++;
+ if (!reaper)
+ goto out_no_task;
+
+ for (; nr < ARRAY_SIZE(proc_base_stuff); filp->f_pos++, nr++) {
+ struct pid_entry *p = &proc_base_stuff[nr];
+ if (proc_base_fill_cache(filp, dirent, filldir, reaper, p) < 0)
+ goto out;
}
- nr -= 1;
- /* f_version caches the tgid value that the last readdir call couldn't
- * return. lseek aka telldir automagically resets f_version to 0.
- */
- tgid = filp->f_version;
- filp->f_version = 0;
- for (task = first_tgid(tgid, nr);
+ tgid = filp->f_pos - TGID_OFFSET;
+ for (task = next_tgid(tgid);
task;
- task = next_tgid(task), filp->f_pos++) {
- int len;
- ino_t ino;
+ put_task_struct(task), task = next_tgid(tgid + 1)) {
tgid = task->pid;
- len = snprintf(buf, sizeof(buf), "%d", tgid);
- ino = fake_ino(tgid, PROC_TGID_INO);
- if (filldir(dirent, buf, len, filp->f_pos, ino, DT_DIR) < 0) {
- /* returning this tgid failed, save it as the first
- * pid for the next readir call */
- filp->f_version = tgid;
+ filp->f_pos = tgid + TGID_OFFSET;
+ if (proc_pid_fill_cache(filp, dirent, filldir, task, tgid) < 0) {
put_task_struct(task);
- break;
+ goto out;
}
}
+ filp->f_pos = PID_MAX_LIMIT + TGID_OFFSET;
+out:
+ put_task_struct(reaper);
+out_no_task:
return 0;
}
/*
+ * Tasks
+ */
+static struct pid_entry tid_base_stuff[] = {
+ DIR("fd", S_IRUSR|S_IXUSR, fd),
+ INF("environ", S_IRUSR, pid_environ),
+ INF("auxv", S_IRUSR, pid_auxv),
+ INF("status", S_IRUGO, pid_status),
+ INF("cmdline", S_IRUGO, pid_cmdline),
+ INF("stat", S_IRUGO, tid_stat),
+ INF("statm", S_IRUGO, pid_statm),
+ REG("maps", S_IRUGO, maps),
+#ifdef CONFIG_NUMA
+ REG("numa_maps", S_IRUGO, numa_maps),
+#endif
+ REG("mem", S_IRUSR|S_IWUSR, mem),
+#ifdef CONFIG_SECCOMP
+ REG("seccomp", S_IRUSR|S_IWUSR, seccomp),
+#endif
+ LNK("cwd", cwd),
+ LNK("root", root),
+ LNK("exe", exe),
+ REG("mounts", S_IRUGO, mounts),
+#ifdef CONFIG_MMU
+ REG("smaps", S_IRUGO, smaps),
+#endif
+#ifdef CONFIG_SECURITY
+ DIR("attr", S_IRUGO|S_IXUGO, attr_dir),
+#endif
+#ifdef CONFIG_KALLSYMS
+ INF("wchan", S_IRUGO, pid_wchan),
+#endif
+#ifdef CONFIG_SCHEDSTATS
+ INF("schedstat", S_IRUGO, pid_schedstat),
+#endif
+#ifdef CONFIG_CPUSETS
+ REG("cpuset", S_IRUGO, cpuset),
+#endif
+ INF("oom_score", S_IRUGO, oom_score),
+ REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust),
+#ifdef CONFIG_AUDITSYSCALL
+ REG("loginuid", S_IWUSR|S_IRUGO, loginuid),
+#endif
+};
+
+static int proc_tid_base_readdir(struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ return proc_pident_readdir(filp,dirent,filldir,
+ tid_base_stuff,ARRAY_SIZE(tid_base_stuff));
+}
+
+static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd){
+ return proc_pident_lookup(dir, dentry,
+ tid_base_stuff, ARRAY_SIZE(tid_base_stuff));
+}
+
+static struct file_operations proc_tid_base_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_tid_base_readdir,
+};
+
+static struct inode_operations proc_tid_base_inode_operations = {
+ .lookup = proc_tid_base_lookup,
+ .getattr = pid_getattr,
+ .setattr = proc_setattr,
+};
+
+static struct dentry *proc_task_instantiate(struct inode *dir,
+ struct dentry *dentry, struct task_struct *task, void *ptr)
+{
+ struct dentry *error = ERR_PTR(-ENOENT);
+ struct inode *inode;
+ inode = proc_pid_make_inode(dir->i_sb, task);
+
+ if (!inode)
+ goto out;
+ inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO;
+ inode->i_op = &proc_tid_base_inode_operations;
+ inode->i_fop = &proc_tid_base_operations;
+ inode->i_flags|=S_IMMUTABLE;
+ inode->i_nlink = 3;
+#ifdef CONFIG_SECURITY
+ inode->i_nlink += 1;
+#endif
+
+ dentry->d_op = &pid_dentry_operations;
+
+ d_add(dentry, inode);
+ /* Close the race of the process dying before we return the dentry */
+ if (pid_revalidate(dentry, NULL))
+ error = NULL;
+out:
+ return error;
+}
+
+static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd)
+{
+ struct dentry *result = ERR_PTR(-ENOENT);
+ struct task_struct *task;
+ struct task_struct *leader = get_proc_task(dir);
+ unsigned tid;
+
+ if (!leader)
+ goto out_no_task;
+
+ tid = name_to_int(dentry);
+ if (tid == ~0U)
+ goto out;
+
+ rcu_read_lock();
+ task = find_task_by_pid(tid);
+ if (task)
+ get_task_struct(task);
+ rcu_read_unlock();
+ if (!task)
+ goto out;
+ if (leader->tgid != task->tgid)
+ goto out_drop_task;
+
+ result = proc_task_instantiate(dir, dentry, task, NULL);
+out_drop_task:
+ put_task_struct(task);
+out:
+ put_task_struct(leader);
+out_no_task:
+ return result;
+}
+
+/*
* Find the first tid of a thread group to return to user space.
*
* Usually this is just the thread group leader, but if the users
@@ -2317,10 +2219,18 @@ static struct task_struct *next_tid(struct task_struct *start)
return pos;
}
+static int proc_task_fill_cache(struct file *filp, void *dirent, filldir_t filldir,
+ struct task_struct *task, int tid)
+{
+ char name[PROC_NUMBUF];
+ int len = snprintf(name, sizeof(name), "%d", tid);
+ return proc_fill_cache(filp, dirent, filldir, name, len,
+ proc_task_instantiate, task, NULL);
+}
+
/* for the /proc/TGID/task/ directories */
static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir)
{
- char buf[PROC_NUMBUF];
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
struct task_struct *leader = get_proc_task(inode);
@@ -2357,11 +2267,8 @@ static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldi
for (task = first_tid(leader, tid, pos - 2);
task;
task = next_tid(task), pos++) {
- int len;
tid = task->pid;
- len = snprintf(buf, sizeof(buf), "%d", tid);
- ino = fake_ino(tid, PROC_TID_INO);
- if (filldir(dirent, buf, len, pos, ino, DT_DIR < 0)) {
+ if (proc_task_fill_cache(filp, dirent, filldir, task, tid) < 0) {
/* returning this tgid failed, save it as the first
* pid for the next readir call */
filp->f_version = tid;
@@ -2391,3 +2298,14 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct
return 0;
}
+
+static struct inode_operations proc_task_inode_operations = {
+ .lookup = proc_task_lookup,
+ .getattr = proc_task_getattr,
+ .setattr = proc_setattr,
+};
+
+static struct file_operations proc_task_operations = {
+ .read = generic_read_dir,
+ .readdir = proc_task_readdir,
+};
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index 146a434ba944..987c773dbb20 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -28,6 +28,7 @@ do { \
(vmi)->largest_chunk = 0; \
} while(0)
+extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
#endif
extern void create_seq_entry(char *name, mode_t mode, const struct file_operations *f);
diff --git a/fs/proc/kcore.c b/fs/proc/kcore.c
index 6a984f64edd7..1294eda4acae 100644
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@ -100,7 +100,7 @@ static int notesize(struct memelfnote *en)
int sz;
sz = sizeof(struct elf_note);
- sz += roundup(strlen(en->name), 4);
+ sz += roundup((strlen(en->name) + 1), 4);
sz += roundup(en->datasz, 4);
return sz;
@@ -116,7 +116,7 @@ static char *storenote(struct memelfnote *men, char *bufp)
#define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
- en.n_namesz = strlen(men->name);
+ en.n_namesz = strlen(men->name) + 1;
en.n_descsz = men->datasz;
en.n_type = men->type;
@@ -279,12 +279,11 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
tsz = elf_buflen - *fpos;
if (buflen < tsz)
tsz = buflen;
- elf_buf = kmalloc(elf_buflen, GFP_ATOMIC);
+ elf_buf = kzalloc(elf_buflen, GFP_ATOMIC);
if (!elf_buf) {
read_unlock(&kclist_lock);
return -ENOMEM;
}
- memset(elf_buf, 0, elf_buflen);
elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
read_unlock(&kclist_lock);
if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
@@ -330,10 +329,9 @@ read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
unsigned long curstart = start;
unsigned long cursize = tsz;
- elf_buf = kmalloc(tsz, GFP_KERNEL);
+ elf_buf = kzalloc(tsz, GFP_KERNEL);
if (!elf_buf)
return -ENOMEM;
- memset(elf_buf, 0, tsz);
read_lock(&vmlist_lock);
for (m=vmlist; m && cursize; m=m->next) {
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index cff10ab1af63..d7dbdf9e0f49 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -33,19 +33,15 @@
#include "internal.h"
/*
- * display a list of all the VMAs the kernel knows about
- * - nommu kernals have a single flat list
+ * display a single VMA to a sequenced file
*/
-static int nommu_vma_list_show(struct seq_file *m, void *v)
+int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma)
{
- struct vm_area_struct *vma;
unsigned long ino = 0;
struct file *file;
dev_t dev = 0;
int flags, len;
- vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb);
-
flags = vma->vm_flags;
file = vma->vm_file;
@@ -78,6 +74,18 @@ static int nommu_vma_list_show(struct seq_file *m, void *v)
return 0;
}
+/*
+ * display a list of all the VMAs the kernel knows about
+ * - nommu kernals have a single flat list
+ */
+static int nommu_vma_list_show(struct seq_file *m, void *v)
+{
+ struct vm_area_struct *vma;
+
+ vma = rb_entry((struct rb_node *) v, struct vm_area_struct, vm_rb);
+ return nommu_vma_show(m, vma);
+}
+
static void *nommu_vma_list_start(struct seq_file *m, loff_t *_pos)
{
struct rb_node *_rb;
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 5bbd60896050..93c43b676e59 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -45,6 +45,7 @@
#include <linux/sysrq.h>
#include <linux/vmalloc.h>
#include <linux/crash_dump.h>
+#include <linux/pspace.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
@@ -91,7 +92,7 @@ static int loadavg_read_proc(char *page, char **start, off_t off,
LOAD_INT(a), LOAD_FRAC(a),
LOAD_INT(b), LOAD_FRAC(b),
LOAD_INT(c), LOAD_FRAC(c),
- nr_running(), nr_threads, last_pid);
+ nr_running(), nr_threads, init_pspace.last_pid);
return proc_calc_metrics(page, start, off, count, eof, len);
}
@@ -277,12 +278,15 @@ static int devinfo_show(struct seq_file *f, void *v)
if (i == 0)
seq_printf(f, "Character devices:\n");
chrdev_show(f, i);
- } else {
+ }
+#ifdef CONFIG_BLOCK
+ else {
i -= CHRDEV_MAJOR_HASH_SIZE;
if (i == 0)
seq_printf(f, "\nBlock devices:\n");
blkdev_show(f, i);
}
+#endif
return 0;
}
@@ -355,6 +359,7 @@ static int stram_read_proc(char *page, char **start, off_t off,
}
#endif
+#ifdef CONFIG_BLOCK
extern struct seq_operations partitions_op;
static int partitions_open(struct inode *inode, struct file *file)
{
@@ -378,6 +383,7 @@ static struct file_operations proc_diskstats_operations = {
.llseek = seq_lseek,
.release = seq_release,
};
+#endif
#ifdef CONFIG_MODULES
extern struct seq_operations modules_op;
@@ -641,7 +647,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
if (get_user(c, buf))
return -EFAULT;
- __handle_sysrq(c, NULL, NULL, 0);
+ __handle_sysrq(c, NULL, 0);
}
return count;
}
@@ -695,7 +701,9 @@ void __init proc_misc_init(void)
entry->proc_fops = &proc_kmsg_operations;
create_seq_entry("devices", 0, &proc_devinfo_operations);
create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+#ifdef CONFIG_BLOCK
create_seq_entry("partitions", 0, &proc_partitions_operations);
+#endif
create_seq_entry("stat", 0, &proc_stat_operations);
create_seq_entry("interrupts", 0, &proc_interrupts_operations);
#ifdef CONFIG_SLAB
@@ -707,7 +715,9 @@ void __init proc_misc_init(void)
create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);
+#ifdef CONFIG_BLOCK
create_seq_entry("diskstats", 0, &proc_diskstats_operations);
+#endif
#ifdef CONFIG_MODULES
create_seq_entry("modules", 0, &proc_modules_operations);
#endif
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 8901c65caca8..ffe66c38488b 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -16,6 +16,7 @@
#include <linux/module.h>
#include <linux/bitops.h>
#include <linux/smp_lock.h>
+#include <linux/mount.h>
#include "internal.h"
@@ -28,6 +29,17 @@ struct proc_dir_entry *proc_sys_root;
static int proc_get_sb(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
{
+ if (proc_mnt) {
+ /* Seed the root directory with a pid so it doesn't need
+ * to be special in base.c. I would do this earlier but
+ * the only task alive when /proc is mounted the first time
+ * is the init_task and it doesn't have any pids.
+ */
+ struct proc_inode *ei;
+ ei = PROC_I(proc_mnt->mnt_sb->s_root->d_inode);
+ if (!ei->pid)
+ ei->pid = find_get_pid(1);
+ }
return get_sb_single(fs_type, flags, data, proc_fill_super, mnt);
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 0a163a4f7764..6b769afac55a 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -122,11 +122,6 @@ struct mem_size_stats
unsigned long private_dirty;
};
-__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
-{
- return NULL;
-}
-
static int show_map_internal(struct seq_file *m, void *v, struct mem_size_stats *mss)
{
struct proc_maps_private *priv = m->private;
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 4616ed50ffcd..091aa8e48e02 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -138,25 +138,63 @@ out:
}
/*
- * Albert D. Cahalan suggested to fake entries for the traditional
- * sections here. This might be worth investigating.
+ * display mapping lines for a particular process's /proc/pid/maps
*/
-static int show_map(struct seq_file *m, void *v)
+static int show_map(struct seq_file *m, void *_vml)
{
- return 0;
+ struct vm_list_struct *vml = _vml;
+ return nommu_vma_show(m, vml->vma);
}
+
static void *m_start(struct seq_file *m, loff_t *pos)
{
+ struct proc_maps_private *priv = m->private;
+ struct vm_list_struct *vml;
+ struct mm_struct *mm;
+ loff_t n = *pos;
+
+ /* pin the task and mm whilst we play with them */
+ priv->task = get_pid_task(priv->pid, PIDTYPE_PID);
+ if (!priv->task)
+ return NULL;
+
+ mm = get_task_mm(priv->task);
+ if (!mm) {
+ put_task_struct(priv->task);
+ priv->task = NULL;
+ return NULL;
+ }
+
+ down_read(&mm->mmap_sem);
+
+ /* start from the Nth VMA */
+ for (vml = mm->context.vmlist; vml; vml = vml->next)
+ if (n-- == 0)
+ return vml;
return NULL;
}
-static void m_stop(struct seq_file *m, void *v)
+
+static void m_stop(struct seq_file *m, void *_vml)
{
+ struct proc_maps_private *priv = m->private;
+
+ if (priv->task) {
+ struct mm_struct *mm = priv->task->mm;
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ put_task_struct(priv->task);
+ }
}
-static void *m_next(struct seq_file *m, void *v, loff_t *pos)
+
+static void *m_next(struct seq_file *m, void *_vml, loff_t *pos)
{
- return NULL;
+ struct vm_list_struct *vml = _vml;
+
+ (*pos)++;
+ return vml ? vml->next : NULL;
}
-static struct seq_operations proc_pid_maps_op = {
+
+static struct seq_operations proc_pid_maps_ops = {
.start = m_start,
.next = m_next,
.stop = m_stop,
@@ -165,11 +203,19 @@ static struct seq_operations proc_pid_maps_op = {
static int maps_open(struct inode *inode, struct file *file)
{
- int ret;
- ret = seq_open(file, &proc_pid_maps_op);
- if (!ret) {
- struct seq_file *m = file->private_data;
- m->private = NULL;
+ struct proc_maps_private *priv;
+ int ret = -ENOMEM;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv) {
+ priv->pid = proc_pid(inode);
+ ret = seq_open(file, &proc_pid_maps_ops);
+ if (!ret) {
+ struct seq_file *m = file->private_data;
+ m->private = priv;
+ } else {
+ kfree(priv);
+ }
}
return ret;
}
@@ -178,6 +224,6 @@ struct file_operations proc_maps_operations = {
.open = maps_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = seq_release,
+ .release = seq_release_private,
};
diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c
index 62af4b1348bd..467e5ac7280e 100644
--- a/fs/qnx4/file.c
+++ b/fs/qnx4/file.c
@@ -22,11 +22,13 @@
const struct file_operations qnx4_file_operations =
{
.llseek = generic_file_llseek,
- .read = generic_file_read,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
.mmap = generic_file_mmap,
.sendfile = generic_file_sendfile,
#ifdef CONFIG_QNX4FS_RW
- .write = generic_file_write,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.fsync = qnx4_sync_file,
#endif
};
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index 5a903491e697..5a41db2a218d 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -358,11 +358,10 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
const char *errmsg;
struct qnx4_sb_info *qs;
- qs = kmalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
+ qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
if (!qs)
return -ENOMEM;
s->s_fs_info = qs;
- memset(qs, 0, sizeof(struct qnx4_sb_info));
sb_set_blocksize(s, QNX4_BLOCK_SIZE);
@@ -497,7 +496,6 @@ static void qnx4_read_inode(struct inode *inode)
inode->i_ctime.tv_sec = le32_to_cpu(raw_inode->di_ctime);
inode->i_ctime.tv_nsec = 0;
inode->i_blocks = le32_to_cpu(raw_inode->di_first_xtnt.xtnt_size);
- inode->i_blksize = QNX4_DIR_ENTRY_SIZE;
memcpy(qnx4_inode, raw_inode, QNX4_DIR_ENTRY_SIZE);
if (S_ISREG(inode->i_mode)) {
@@ -557,9 +555,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(qnx4_inode_cachep))
- printk(KERN_INFO
- "qnx4_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(qnx4_inode_cachep);
}
static int qnx4_get_sb(struct file_system_type *fs_type,
diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c
index c3d83f67154a..733cdf01d645 100644
--- a/fs/qnx4/namei.c
+++ b/fs/qnx4/namei.c
@@ -186,11 +186,10 @@ int qnx4_rmdir(struct inode *dir, struct dentry *dentry)
memset(de->di_fname, 0, sizeof de->di_fname);
de->di_mode = 0;
mark_buffer_dirty(bh);
- inode->i_nlink = 0;
+ clear_nlink(inode);
mark_inode_dirty(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
- dir->i_nlink--;
- mark_inode_dirty(dir);
+ inode_dec_link_count(dir);
retval = 0;
end_rmdir:
@@ -234,9 +233,8 @@ int qnx4_unlink(struct inode *dir, struct dentry *dentry)
mark_buffer_dirty(bh);
dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
mark_inode_dirty(dir);
- inode->i_nlink--;
inode->i_ctime = dir->i_ctime;
- mark_inode_dirty(inode);
+ inode_dec_link_count(inode);
retval = 0;
end_unlink:
diff --git a/fs/quota.c b/fs/quota.c
index d6a2be826e29..b9dae76a0b6e 100644
--- a/fs/quota.c
+++ b/fs/quota.c
@@ -338,6 +338,34 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void
}
/*
+ * look up a superblock on which quota ops will be performed
+ * - use the name of a block device to find the superblock thereon
+ */
+static inline struct super_block *quotactl_block(const char __user *special)
+{
+#ifdef CONFIG_BLOCK
+ struct block_device *bdev;
+ struct super_block *sb;
+ char *tmp = getname(special);
+
+ if (IS_ERR(tmp))
+ return ERR_PTR(PTR_ERR(tmp));
+ bdev = lookup_bdev(tmp);
+ putname(tmp);
+ if (IS_ERR(bdev))
+ return ERR_PTR(PTR_ERR(bdev));
+ sb = get_super(bdev);
+ bdput(bdev);
+ if (!sb)
+ return ERR_PTR(-ENODEV);
+
+ return sb;
+#else
+ return ERR_PTR(-ENODEV);
+#endif
+}
+
+/*
* This is the system call interface. This communicates with
* the user-level programs. Currently this only supports diskquota
* calls. Maybe we need to add the process quotas etc. in the future,
@@ -347,25 +375,15 @@ asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t
{
uint cmds, type;
struct super_block *sb = NULL;
- struct block_device *bdev;
- char *tmp;
int ret;
cmds = cmd >> SUBCMDSHIFT;
type = cmd & SUBCMDMASK;
if (cmds != Q_SYNC || special) {
- tmp = getname(special);
- if (IS_ERR(tmp))
- return PTR_ERR(tmp);
- bdev = lookup_bdev(tmp);
- putname(tmp);
- if (IS_ERR(bdev))
- return PTR_ERR(bdev);
- sb = get_super(bdev);
- bdput(bdev);
- if (!sb)
- return -ENODEV;
+ sb = quotactl_block(special);
+ if (IS_ERR(sb))
+ return PTR_ERR(sb);
}
ret = check_quotactl_valid(sb, type, cmds, id);
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index 86f14cacf641..0947fb57dcf3 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -33,8 +33,10 @@ const struct address_space_operations ramfs_aops = {
};
const struct file_operations ramfs_file_operations = {
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.fsync = simple_sync_file,
.sendfile = generic_file_sendfile,
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c
index 677139b48e00..bfe5dbf1002e 100644
--- a/fs/ramfs/file-nommu.c
+++ b/fs/ramfs/file-nommu.c
@@ -36,8 +36,10 @@ const struct address_space_operations ramfs_aops = {
const struct file_operations ramfs_file_operations = {
.mmap = ramfs_nommu_mmap,
.get_unmapped_area = ramfs_nommu_get_unmapped_area,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.fsync = simple_sync_file,
.sendfile = generic_file_sendfile,
.llseek = generic_file_llseek,
diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c
index b9677335cc8d..2faf4cdf61b0 100644
--- a/fs/ramfs/inode.c
+++ b/fs/ramfs/inode.c
@@ -58,7 +58,6 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->a_ops = &ramfs_aops;
inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;
@@ -76,7 +75,7 @@ struct inode *ramfs_get_inode(struct super_block *sb, int mode, dev_t dev)
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
break;
case S_IFLNK:
inode->i_op = &page_symlink_inode_operations;
@@ -114,7 +113,7 @@ static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
{
int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0);
if (!retval)
- dir->i_nlink++;
+ inc_nlink(dir);
return retval;
}
diff --git a/fs/read_write.c b/fs/read_write.c
index d4cb3183c99c..f792000a28e6 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -15,13 +15,15 @@
#include <linux/module.h>
#include <linux/syscalls.h>
#include <linux/pagemap.h>
+#include "read_write.h"
#include <asm/uaccess.h>
#include <asm/unistd.h>
const struct file_operations generic_ro_fops = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
.mmap = generic_file_readonly_mmap,
.sendfile = generic_file_sendfile,
};
@@ -227,14 +229,20 @@ static void wait_on_retry_sync_kiocb(struct kiocb *iocb)
ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
{
+ struct iovec iov = { .iov_base = buf, .iov_len = len };
struct kiocb kiocb;
ssize_t ret;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = *ppos;
- while (-EIOCBRETRY ==
- (ret = filp->f_op->aio_read(&kiocb, buf, len, kiocb.ki_pos)))
+ kiocb.ki_left = len;
+
+ for (;;) {
+ ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);
+ if (ret != -EIOCBRETRY)
+ break;
wait_on_retry_sync_kiocb(&kiocb);
+ }
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&kiocb);
@@ -279,14 +287,20 @@ EXPORT_SYMBOL(vfs_read);
ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos)
{
+ struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len };
struct kiocb kiocb;
ssize_t ret;
init_sync_kiocb(&kiocb, filp);
kiocb.ki_pos = *ppos;
- while (-EIOCBRETRY ==
- (ret = filp->f_op->aio_write(&kiocb, buf, len, kiocb.ki_pos)))
+ kiocb.ki_left = len;
+
+ for (;;) {
+ ret = filp->f_op->aio_write(&kiocb, &iov, 1, kiocb.ki_pos);
+ if (ret != -EIOCBRETRY)
+ break;
wait_on_retry_sync_kiocb(&kiocb);
+ }
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&kiocb);
@@ -438,78 +452,155 @@ unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to)
EXPORT_UNUSED_SYMBOL(iov_shorten); /* June 2006 */
+ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
+ unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn)
+{
+ struct kiocb kiocb;
+ ssize_t ret;
+
+ init_sync_kiocb(&kiocb, filp);
+ kiocb.ki_pos = *ppos;
+ kiocb.ki_left = len;
+ kiocb.ki_nbytes = len;
+
+ for (;;) {
+ ret = fn(&kiocb, iov, nr_segs, kiocb.ki_pos);
+ if (ret != -EIOCBRETRY)
+ break;
+ wait_on_retry_sync_kiocb(&kiocb);
+ }
+
+ if (ret == -EIOCBQUEUED)
+ ret = wait_on_sync_kiocb(&kiocb);
+ *ppos = kiocb.ki_pos;
+ return ret;
+}
+
+/* Do it by hand, with file-ops */
+ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
+ unsigned long nr_segs, loff_t *ppos, io_fn_t fn)
+{
+ struct iovec *vector = iov;
+ ssize_t ret = 0;
+
+ while (nr_segs > 0) {
+ void __user *base;
+ size_t len;
+ ssize_t nr;
+
+ base = vector->iov_base;
+ len = vector->iov_len;
+ vector++;
+ nr_segs--;
+
+ nr = fn(filp, base, len, ppos);
+
+ if (nr < 0) {
+ if (!ret)
+ ret = nr;
+ break;
+ }
+ ret += nr;
+ if (nr != len)
+ break;
+ }
+
+ return ret;
+}
+
/* A write operation does a read from user space and vice versa */
#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ)
+ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
+ unsigned long nr_segs, unsigned long fast_segs,
+ struct iovec *fast_pointer,
+ struct iovec **ret_pointer)
+ {
+ unsigned long seg;
+ ssize_t ret;
+ struct iovec *iov = fast_pointer;
+
+ /*
+ * SuS says "The readv() function *may* fail if the iovcnt argument
+ * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
+ * traditionally returned zero for zero segments, so...
+ */
+ if (nr_segs == 0) {
+ ret = 0;
+ goto out;
+ }
+
+ /*
+ * First get the "struct iovec" from user memory and
+ * verify all the pointers
+ */
+ if (nr_segs > UIO_MAXIOV) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (nr_segs > fast_segs) {
+ iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
+ if (iov == NULL) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+ if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ /*
+ * According to the Single Unix Specification we should return EINVAL
+ * if an element length is < 0 when cast to ssize_t or if the
+ * total length would overflow the ssize_t return value of the
+ * system call.
+ */
+ ret = 0;
+ for (seg = 0; seg < nr_segs; seg++) {
+ void __user *buf = iov[seg].iov_base;
+ ssize_t len = (ssize_t)iov[seg].iov_len;
+
+ /* see if we we're about to use an invalid len or if
+ * it's about to overflow ssize_t */
+ if (len < 0 || (ret + len < ret)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ if (unlikely(!access_ok(vrfy_dir(type), buf, len))) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ ret += len;
+ }
+out:
+ *ret_pointer = iov;
+ return ret;
+}
+
static ssize_t do_readv_writev(int type, struct file *file,
const struct iovec __user * uvector,
unsigned long nr_segs, loff_t *pos)
{
- typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
- typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
-
size_t tot_len;
struct iovec iovstack[UIO_FASTIOV];
- struct iovec *iov=iovstack, *vector;
+ struct iovec *iov = iovstack;
ssize_t ret;
- int seg;
io_fn_t fn;
iov_fn_t fnv;
- /*
- * SuS says "The readv() function *may* fail if the iovcnt argument
- * was less than or equal to 0, or greater than {IOV_MAX}. Linux has
- * traditionally returned zero for zero segments, so...
- */
- ret = 0;
- if (nr_segs == 0)
+ if (!file->f_op) {
+ ret = -EINVAL;
goto out;
+ }
- /*
- * First get the "struct iovec" from user memory and
- * verify all the pointers
- */
- ret = -EINVAL;
- if (nr_segs > UIO_MAXIOV)
- goto out;
- if (!file->f_op)
- goto out;
- if (nr_segs > UIO_FASTIOV) {
- ret = -ENOMEM;
- iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);
- if (!iov)
- goto out;
- }
- ret = -EFAULT;
- if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector)))
+ ret = rw_copy_check_uvector(type, uvector, nr_segs,
+ ARRAY_SIZE(iovstack), iovstack, &iov);
+ if (ret <= 0)
goto out;
- /*
- * Single unix specification:
- * We should -EINVAL if an element length is not >= 0 and fitting an
- * ssize_t. The total length is fitting an ssize_t
- *
- * Be careful here because iov_len is a size_t not an ssize_t
- */
- tot_len = 0;
- ret = -EINVAL;
- for (seg = 0; seg < nr_segs; seg++) {
- void __user *buf = iov[seg].iov_base;
- ssize_t len = (ssize_t)iov[seg].iov_len;
-
- if (len < 0) /* size_t not fitting an ssize_t .. */
- goto out;
- if (unlikely(!access_ok(vrfy_dir(type), buf, len)))
- goto Efault;
- tot_len += len;
- if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */
- goto out;
- }
- if (tot_len == 0) {
- ret = 0;
- goto out;
- }
-
+ tot_len = ret;
ret = rw_verify_area(type, file, pos, tot_len);
if (ret < 0)
goto out;
@@ -520,39 +611,18 @@ static ssize_t do_readv_writev(int type, struct file *file,
fnv = NULL;
if (type == READ) {
fn = file->f_op->read;
- fnv = file->f_op->readv;
+ fnv = file->f_op->aio_read;
} else {
fn = (io_fn_t)file->f_op->write;
- fnv = file->f_op->writev;
+ fnv = file->f_op->aio_write;
}
- if (fnv) {
- ret = fnv(file, iov, nr_segs, pos);
- goto out;
- }
-
- /* Do it by hand, with file-ops */
- ret = 0;
- vector = iov;
- while (nr_segs > 0) {
- void __user * base;
- size_t len;
- ssize_t nr;
- base = vector->iov_base;
- len = vector->iov_len;
- vector++;
- nr_segs--;
-
- nr = fn(file, base, len, pos);
+ if (fnv)
+ ret = do_sync_readv_writev(file, iov, nr_segs, tot_len,
+ pos, fnv);
+ else
+ ret = do_loop_readv_writev(file, iov, nr_segs, pos, fn);
- if (nr < 0) {
- if (!ret) ret = nr;
- break;
- }
- ret += nr;
- if (nr != len)
- break;
- }
out:
if (iov != iovstack)
kfree(iov);
@@ -563,9 +633,6 @@ out:
fsnotify_modify(file->f_dentry);
}
return ret;
-Efault:
- ret = -EFAULT;
- goto out;
}
ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
@@ -573,7 +640,7 @@ ssize_t vfs_readv(struct file *file, const struct iovec __user *vec,
{
if (!(file->f_mode & FMODE_READ))
return -EBADF;
- if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
+ if (!file->f_op || (!file->f_op->aio_read && !file->f_op->read))
return -EINVAL;
return do_readv_writev(READ, file, vec, vlen, pos);
@@ -586,7 +653,7 @@ ssize_t vfs_writev(struct file *file, const struct iovec __user *vec,
{
if (!(file->f_mode & FMODE_WRITE))
return -EBADF;
- if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
+ if (!file->f_op || (!file->f_op->aio_write && !file->f_op->write))
return -EINVAL;
return do_readv_writev(WRITE, file, vec, vlen, pos);
diff --git a/fs/read_write.h b/fs/read_write.h
new file mode 100644
index 000000000000..d07b954c6e0c
--- /dev/null
+++ b/fs/read_write.h
@@ -0,0 +1,14 @@
+/*
+ * This file is only for sharing some helpers from read_write.c with compat.c.
+ * Don't use anywhere else.
+ */
+
+
+typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);
+typedef ssize_t (*iov_fn_t)(struct kiocb *, const struct iovec *,
+ unsigned long, loff_t);
+
+ssize_t do_sync_readv_writev(struct file *filp, const struct iovec *iov,
+ unsigned long nr_segs, size_t len, loff_t *ppos, iov_fn_t fn);
+ssize_t do_loop_readv_writev(struct file *filp, struct iovec *iov,
+ unsigned long nr_segs, loff_t *ppos, io_fn_t fn);
diff --git a/fs/readdir.c b/fs/readdir.c
index b6109329b607..bff3ee58e2f8 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -69,20 +69,24 @@ struct readdir_callback {
};
static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
- ino_t ino, unsigned int d_type)
+ u64 ino, unsigned int d_type)
{
struct readdir_callback * buf = (struct readdir_callback *) __buf;
struct old_linux_dirent __user * dirent;
+ unsigned long d_ino;
if (buf->result)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
buf->result++;
dirent = buf->dirent;
if (!access_ok(VERIFY_WRITE, dirent,
(unsigned long)(dirent->d_name + namlen + 1) -
(unsigned long)dirent))
goto efault;
- if ( __put_user(ino, &dirent->d_ino) ||
+ if ( __put_user(d_ino, &dirent->d_ino) ||
__put_user(offset, &dirent->d_offset) ||
__put_user(namlen, &dirent->d_namlen) ||
__copy_to_user(dirent->d_name, name, namlen) ||
@@ -138,22 +142,26 @@ struct getdents_callback {
};
static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
- ino_t ino, unsigned int d_type)
+ u64 ino, unsigned int d_type)
{
struct linux_dirent __user * dirent;
struct getdents_callback * buf = (struct getdents_callback *) __buf;
+ unsigned long d_ino;
int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 2);
buf->error = -EINVAL; /* only used if we fail.. */
if (reclen > buf->count)
return -EINVAL;
+ d_ino = ino;
+ if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+ return -EOVERFLOW;
dirent = buf->previous;
if (dirent) {
if (__put_user(offset, &dirent->d_off))
goto efault;
}
dirent = buf->current_dir;
- if (__put_user(ino, &dirent->d_ino))
+ if (__put_user(d_ino, &dirent->d_ino))
goto efault;
if (__put_user(reclen, &dirent->d_reclen))
goto efault;
@@ -222,7 +230,7 @@ struct getdents_callback64 {
};
static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
- ino_t ino, unsigned int d_type)
+ u64 ino, unsigned int d_type)
{
struct linux_dirent64 __user *dirent;
struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
diff --git a/fs/reiserfs/Makefile b/fs/reiserfs/Makefile
index 3a59309f3ca9..0eb7ac080484 100644
--- a/fs/reiserfs/Makefile
+++ b/fs/reiserfs/Makefile
@@ -28,7 +28,7 @@ endif
# will work around it. If any other architecture displays this behavior,
# add it here.
ifeq ($(CONFIG_PPC32),y)
-EXTRA_CFLAGS := -O1
+EXTRA_CFLAGS := $(call cc-ifversion, -lt, 0400, -O1)
endif
TAGS:
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index 4a7dbdee1b6d..e3d466a228d4 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -9,6 +9,7 @@
#include <linux/buffer_head.h>
#include <linux/kernel.h>
#include <linux/pagemap.h>
+#include <linux/vmalloc.h>
#include <linux/reiserfs_fs_sb.h>
#include <linux/reiserfs_fs_i.h>
#include <linux/quotaops.h>
@@ -50,16 +51,15 @@ static inline void get_bit_address(struct super_block *s,
{
/* It is in the bitmap block number equal to the block
* number divided by the number of bits in a block. */
- *bmap_nr = block / (s->s_blocksize << 3);
+ *bmap_nr = block >> (s->s_blocksize_bits + 3);
/* Within that bitmap block it is located at bit offset *offset. */
*offset = block & ((s->s_blocksize << 3) - 1);
- return;
}
#ifdef CONFIG_REISERFS_CHECK
int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
{
- int i, j;
+ int bmap, offset;
if (block == 0 || block >= SB_BLOCK_COUNT(s)) {
reiserfs_warning(s,
@@ -68,36 +68,32 @@ int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
return 0;
}
- /* it can't be one of the bitmap blocks */
- for (i = 0; i < SB_BMAP_NR(s); i++)
- if (block == SB_AP_BITMAP(s)[i].bh->b_blocknr) {
+ get_bit_address(s, block, &bmap, &offset);
+
+ /* Old format filesystem? Unlikely, but the bitmaps are all up front so
+ * we need to account for it. */
+ if (unlikely(test_bit(REISERFS_OLD_FORMAT,
+ &(REISERFS_SB(s)->s_properties)))) {
+ b_blocknr_t bmap1 = REISERFS_SB(s)->s_sbh->b_blocknr + 1;
+ if (block >= bmap1 && block <= bmap1 + SB_BMAP_NR(s)) {
+ reiserfs_warning(s, "vs: 4019: is_reusable: "
+ "bitmap block %lu(%u) can't be freed or reused",
+ block, SB_BMAP_NR(s));
+ return 0;
+ }
+ } else {
+ if (offset == 0) {
reiserfs_warning(s, "vs: 4020: is_reusable: "
"bitmap block %lu(%u) can't be freed or reused",
block, SB_BMAP_NR(s));
return 0;
}
-
- get_bit_address(s, block, &i, &j);
-
- if (i >= SB_BMAP_NR(s)) {
- reiserfs_warning(s,
- "vs-4030: is_reusable: there is no so many bitmap blocks: "
- "block=%lu, bitmap_nr=%d", block, i);
- return 0;
}
- if ((bit_value == 0 &&
- reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) ||
- (bit_value == 1 &&
- reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data) == 0)) {
+ if (bmap >= SB_BMAP_NR(s)) {
reiserfs_warning(s,
- "vs-4040: is_reusable: corresponding bit of block %lu does not "
- "match required value (i==%d, j==%d) test_bit==%d",
- block, i, j, reiserfs_test_le_bit(j,
- SB_AP_BITMAP
- (s)[i].bh->
- b_data));
-
+ "vs-4030: is_reusable: there is no so many bitmap blocks: "
+ "block=%lu, bitmap_nr=%d", block, bmap);
return 0;
}
@@ -141,6 +137,7 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
{
struct super_block *s = th->t_super;
struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n];
+ struct buffer_head *bh;
int end, next;
int org = *beg;
@@ -159,22 +156,25 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
bmap_n);
return 0;
}
- if (buffer_locked(bi->bh)) {
- PROC_INFO_INC(s, scan_bitmap.wait);
- __wait_on_buffer(bi->bh);
- }
+
+ bh = reiserfs_read_bitmap_block(s, bmap_n);
+ if (bh == NULL)
+ return 0;
while (1) {
cont:
- if (bi->free_count < min)
+ if (bi->free_count < min) {
+ brelse(bh);
return 0; // No free blocks in this bitmap
+ }
/* search for a first zero bit -- beggining of a window */
*beg = reiserfs_find_next_zero_le_bit
- ((unsigned long *)(bi->bh->b_data), boundary, *beg);
+ ((unsigned long *)(bh->b_data), boundary, *beg);
if (*beg + min > boundary) { /* search for a zero bit fails or the rest of bitmap block
* cannot contain a zero window of minimum size */
+ brelse(bh);
return 0;
}
@@ -183,7 +183,7 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
/* first zero bit found; we check next bits */
for (end = *beg + 1;; end++) {
if (end >= *beg + max || end >= boundary
- || reiserfs_test_le_bit(end, bi->bh->b_data)) {
+ || reiserfs_test_le_bit(end, bh->b_data)) {
next = end;
break;
}
@@ -197,12 +197,12 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
* (end) points to one bit after the window end */
if (end - *beg >= min) { /* it seems we have found window of proper size */
int i;
- reiserfs_prepare_for_journal(s, bi->bh, 1);
+ reiserfs_prepare_for_journal(s, bh, 1);
/* try to set all blocks used checking are they still free */
for (i = *beg; i < end; i++) {
/* It seems that we should not check in journal again. */
if (reiserfs_test_and_set_le_bit
- (i, bi->bh->b_data)) {
+ (i, bh->b_data)) {
/* bit was set by another process
* while we slept in prepare_for_journal() */
PROC_INFO_INC(s, scan_bitmap.stolen);
@@ -214,17 +214,16 @@ static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
/* otherwise we clear all bit were set ... */
while (--i >= *beg)
reiserfs_test_and_clear_le_bit
- (i, bi->bh->b_data);
- reiserfs_restore_prepared_buffer(s,
- bi->
- bh);
+ (i, bh->b_data);
+ reiserfs_restore_prepared_buffer(s, bh);
*beg = org;
/* ... and search again in current block from beginning */
goto cont;
}
}
bi->free_count -= (end - *beg);
- journal_mark_dirty(th, s, bi->bh);
+ journal_mark_dirty(th, s, bh);
+ brelse(bh);
/* free block count calculation */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
@@ -266,9 +265,20 @@ static int bmap_hash_id(struct super_block *s, u32 id)
*/
static inline int block_group_used(struct super_block *s, u32 id)
{
- int bm;
- bm = bmap_hash_id(s, id);
- if (SB_AP_BITMAP(s)[bm].free_count > ((s->s_blocksize << 3) * 60 / 100)) {
+ int bm = bmap_hash_id(s, id);
+ struct reiserfs_bitmap_info *info = &SB_AP_BITMAP(s)[bm];
+
+ /* If we don't have cached information on this bitmap block, we're
+ * going to have to load it later anyway. Loading it here allows us
+ * to make a better decision. This favors long-term performace gain
+ * with a better on-disk layout vs. a short term gain of skipping the
+ * read and potentially having a bad placement. */
+ if (info->first_zero_hint == 0) {
+ struct buffer_head *bh = reiserfs_read_bitmap_block(s, bm);
+ brelse(bh);
+ }
+
+ if (info->free_count > ((s->s_blocksize << 3) * 60 / 100)) {
return 0;
}
return 1;
@@ -373,7 +383,7 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th,
{
struct super_block *s = th->t_super;
struct reiserfs_super_block *rs;
- struct buffer_head *sbh;
+ struct buffer_head *sbh, *bmbh;
struct reiserfs_bitmap_info *apbi;
int nr, offset;
@@ -394,16 +404,21 @@ static void _reiserfs_free_block(struct reiserfs_transaction_handle *th,
return;
}
- reiserfs_prepare_for_journal(s, apbi[nr].bh, 1);
+ bmbh = reiserfs_read_bitmap_block(s, nr);
+ if (!bmbh)
+ return;
+
+ reiserfs_prepare_for_journal(s, bmbh, 1);
/* clear bit for the given block in bit map */
- if (!reiserfs_test_and_clear_le_bit(offset, apbi[nr].bh->b_data)) {
+ if (!reiserfs_test_and_clear_le_bit(offset, bmbh->b_data)) {
reiserfs_warning(s, "vs-4080: reiserfs_free_block: "
"free_block (%s:%lu)[dev:blocknr]: bit already cleared",
reiserfs_bdevname(s), block);
}
apbi[nr].free_count++;
- journal_mark_dirty(th, s, apbi[nr].bh);
+ journal_mark_dirty(th, s, bmbh);
+ brelse(bmbh);
reiserfs_prepare_for_journal(s, sbh, 1);
/* update super block */
@@ -1019,7 +1034,6 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start
b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
int passno = 0;
int nr_allocated = 0;
- int bigalloc = 0;
determine_prealloc_size(hint);
if (!hint->formatted_node) {
@@ -1046,28 +1060,9 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start
hint->preallocate = hint->prealloc_size = 0;
}
/* for unformatted nodes, force large allocations */
- bigalloc = amount_needed;
}
do {
- /* in bigalloc mode, nr_allocated should stay zero until
- * the entire allocation is filled
- */
- if (unlikely(bigalloc && nr_allocated)) {
- reiserfs_warning(s, "bigalloc is %d, nr_allocated %d\n",
- bigalloc, nr_allocated);
- /* reset things to a sane value */
- bigalloc = amount_needed - nr_allocated;
- }
- /*
- * try pass 0 and pass 1 looking for a nice big
- * contiguous allocation. Then reset and look
- * for anything you can find.
- */
- if (passno == 2 && bigalloc) {
- passno = 0;
- bigalloc = 0;
- }
switch (passno++) {
case 0: /* Search from hint->search_start to end of disk */
start = hint->search_start;
@@ -1105,8 +1100,7 @@ static inline int blocknrs_and_prealloc_arrays_from_search_start
new_blocknrs +
nr_allocated,
start, finish,
- bigalloc ?
- bigalloc : 1,
+ 1,
amount_needed -
nr_allocated,
hint->
@@ -1263,3 +1257,89 @@ int reiserfs_can_fit_pages(struct super_block *sb /* superblock of filesystem
return space > 0 ? space : 0;
}
+
+void reiserfs_cache_bitmap_metadata(struct super_block *sb,
+ struct buffer_head *bh,
+ struct reiserfs_bitmap_info *info)
+{
+ unsigned long *cur = (unsigned long *)(bh->b_data + bh->b_size);
+
+ info->first_zero_hint = 1 << (sb->s_blocksize_bits + 3);
+
+ while (--cur >= (unsigned long *)bh->b_data) {
+ int base = ((char *)cur - bh->b_data) << 3;
+
+ /* 0 and ~0 are special, we can optimize for them */
+ if (*cur == 0) {
+ info->first_zero_hint = base;
+ info->free_count += BITS_PER_LONG;
+ } else if (*cur != ~0L) { /* A mix, investigate */
+ int b;
+ for (b = BITS_PER_LONG - 1; b >= 0; b--) {
+ if (!reiserfs_test_le_bit(b, cur)) {
+ info->first_zero_hint = base + b;
+ info->free_count++;
+ }
+ }
+ }
+ }
+ /* The first bit must ALWAYS be 1 */
+ BUG_ON(info->first_zero_hint == 0);
+}
+
+struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb,
+ unsigned int bitmap)
+{
+ b_blocknr_t block = (sb->s_blocksize << 3) * bitmap;
+ struct reiserfs_bitmap_info *info = SB_AP_BITMAP(sb) + bitmap;
+ struct buffer_head *bh;
+
+ /* Way old format filesystems had the bitmaps packed up front.
+ * I doubt there are any of these left, but just in case... */
+ if (unlikely(test_bit(REISERFS_OLD_FORMAT,
+ &(REISERFS_SB(sb)->s_properties))))
+ block = REISERFS_SB(sb)->s_sbh->b_blocknr + 1 + bitmap;
+ else if (bitmap == 0)
+ block = (REISERFS_DISK_OFFSET_IN_BYTES >> sb->s_blocksize_bits) + 1;
+
+ bh = sb_bread(sb, block);
+ if (bh == NULL)
+ reiserfs_warning(sb, "sh-2029: %s: bitmap block (#%u) "
+ "reading failed", __FUNCTION__, block);
+ else {
+ if (buffer_locked(bh)) {
+ PROC_INFO_INC(sb, scan_bitmap.wait);
+ __wait_on_buffer(bh);
+ }
+ BUG_ON(!buffer_uptodate(bh));
+ BUG_ON(atomic_read(&bh->b_count) == 0);
+
+ if (info->first_zero_hint == 0)
+ reiserfs_cache_bitmap_metadata(sb, bh, info);
+ }
+
+ return bh;
+}
+
+int reiserfs_init_bitmap_cache(struct super_block *sb)
+{
+ struct reiserfs_bitmap_info *bitmap;
+
+ bitmap = vmalloc(sizeof (*bitmap) * SB_BMAP_NR(sb));
+ if (bitmap == NULL)
+ return -ENOMEM;
+
+ memset(bitmap, 0, sizeof (*bitmap) * SB_BMAP_NR(sb));
+
+ SB_AP_BITMAP(sb) = bitmap;
+
+ return 0;
+}
+
+void reiserfs_free_bitmap_cache(struct super_block *sb)
+{
+ if (SB_AP_BITMAP(sb)) {
+ vfree(SB_AP_BITMAP(sb));
+ SB_AP_BITMAP(sb) = NULL;
+ }
+}
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index 9aabcc0ccd2d..657050ad7430 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -22,6 +22,9 @@ const struct file_operations reiserfs_dir_operations = {
.readdir = reiserfs_readdir,
.fsync = reiserfs_dir_fsync,
.ioctl = reiserfs_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = reiserfs_compat_ioctl,
+#endif
};
static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 1627edd50810..b67ce9354048 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -37,8 +37,7 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp)
int err;
int jbegin_failure = 0;
- if (!S_ISREG(inode->i_mode))
- BUG();
+ BUG_ON(!S_ISREG(inode->i_mode));
/* fast out for when nothing needs to be done */
if ((atomic_read(&inode->i_count) > 1 ||
@@ -124,13 +123,12 @@ static int reiserfs_sync_file(struct file *p_s_filp,
int n_err;
int barrier_done;
- if (!S_ISREG(p_s_inode->i_mode))
- BUG();
+ BUG_ON(!S_ISREG(p_s_inode->i_mode));
n_err = sync_mapping_buffers(p_s_inode->i_mapping);
reiserfs_write_lock(p_s_inode->i_sb);
barrier_done = reiserfs_commit_for_inode(p_s_inode);
reiserfs_write_unlock(p_s_inode->i_sb);
- if (barrier_done != 1)
+ if (barrier_done != 1 && reiserfs_barrier_flush(p_s_inode->i_sb))
blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
if (barrier_done < 0)
return barrier_done;
@@ -1333,7 +1331,7 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
if (err)
return err;
}
- result = generic_file_write(file, buf, count, ppos);
+ result = do_sync_write(file, buf, count, ppos);
if (after_file_end) { /* Now update i_size and remove the savelink */
struct reiserfs_transaction_handle th;
@@ -1565,10 +1563,14 @@ static ssize_t reiserfs_file_write(struct file *file, /* the file we are going t
}
const struct file_operations reiserfs_file_operations = {
- .read = generic_file_read,
+ .read = do_sync_read,
.write = reiserfs_file_write,
.ioctl = reiserfs_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = reiserfs_compat_ioctl,
+#endif
.mmap = generic_file_mmap,
+ .open = generic_file_open,
.release = reiserfs_file_release,
.fsync = reiserfs_sync_file,
.sendfile = generic_file_sendfile,
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 52f1e2136546..9c69bcacad22 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -17,8 +17,6 @@
#include <linux/writeback.h>
#include <linux/quotaops.h>
-extern int reiserfs_default_io_size; /* default io size devuned in super.c */
-
static int reiserfs_commit_write(struct file *f, struct page *page,
unsigned from, unsigned to);
static int reiserfs_prepare_write(struct file *f, struct page *page,
@@ -1122,7 +1120,6 @@ static void init_inode(struct inode *inode, struct path *path)
ih = PATH_PITEM_HEAD(path);
copy_key(INODE_PKEY(inode), &(ih->ih_key));
- inode->i_blksize = reiserfs_default_io_size;
INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list));
REISERFS_I(inode)->i_flags = 0;
@@ -1130,9 +1127,9 @@ static void init_inode(struct inode *inode, struct path *path)
REISERFS_I(inode)->i_prealloc_count = 0;
REISERFS_I(inode)->i_trans_id = 0;
REISERFS_I(inode)->i_jl = NULL;
- REISERFS_I(inode)->i_acl_access = NULL;
- REISERFS_I(inode)->i_acl_default = NULL;
- init_rwsem(&REISERFS_I(inode)->xattr_sem);
+ reiserfs_init_acl_access(inode);
+ reiserfs_init_acl_default(inode);
+ reiserfs_init_xattr_rwsem(inode);
if (stat_data_v1(ih)) {
struct stat_data_v1 *sd =
@@ -1783,7 +1780,7 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
err = -EDQUOT;
goto out_end_trans;
}
- if (!dir || !dir->i_nlink) {
+ if (!dir->i_nlink) {
err = -EPERM;
goto out_bad_inode;
}
@@ -1837,9 +1834,9 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
REISERFS_I(inode)->i_attrs =
REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode);
- REISERFS_I(inode)->i_acl_access = NULL;
- REISERFS_I(inode)->i_acl_default = NULL;
- init_rwsem(&REISERFS_I(inode)->xattr_sem);
+ reiserfs_init_acl_access(inode);
+ reiserfs_init_acl_default(inode);
+ reiserfs_init_xattr_rwsem(inode);
if (old_format_only(sb))
make_le_item_head(&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET,
@@ -1877,7 +1874,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
}
// these do not go to on-disk stat data
inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
- inode->i_blksize = reiserfs_default_io_size;
// store in in-core inode the key of stat data and version all
// object items will have (directory items will have old offset
@@ -1978,11 +1974,13 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
* iput doesn't deadlock in reiserfs_delete_xattrs. The locking
* code really needs to be reworked, but this will take care of it
* for now. -jeffm */
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
if (REISERFS_I(dir)->i_acl_default && !IS_ERR(REISERFS_I(dir)->i_acl_default)) {
reiserfs_write_unlock_xattrs(dir->i_sb);
iput(inode);
reiserfs_write_lock_xattrs(dir->i_sb);
} else
+#endif
iput(inode);
return err;
}
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index a986b5e1e288..9c57578cb831 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -9,6 +9,7 @@
#include <asm/uaccess.h>
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
+#include <linux/compat.h>
static int reiserfs_unpack(struct inode *inode, struct file *filp);
@@ -94,6 +95,40 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
}
}
+#ifdef CONFIG_COMPAT
+long reiserfs_compat_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ int ret;
+
+ /* These are just misnamed, they actually get/put from/to user an int */
+ switch (cmd) {
+ case REISERFS_IOC32_UNPACK:
+ cmd = REISERFS_IOC_UNPACK;
+ break;
+ case REISERFS_IOC32_GETFLAGS:
+ cmd = REISERFS_IOC_GETFLAGS;
+ break;
+ case REISERFS_IOC32_SETFLAGS:
+ cmd = REISERFS_IOC_SETFLAGS;
+ break;
+ case REISERFS_IOC32_GETVERSION:
+ cmd = REISERFS_IOC_GETVERSION;
+ break;
+ case REISERFS_IOC32_SETVERSION:
+ cmd = REISERFS_IOC_SETVERSION;
+ break;
+ default:
+ return -ENOIOCTLCMD;
+ }
+ lock_kernel();
+ ret = reiserfs_ioctl(inode, file, cmd, (unsigned long) compat_ptr(arg));
+ unlock_kernel();
+ return ret;
+}
+#endif
+
/*
** reiserfs_unpack
** Function try to convert tail from direct item into indirect.
diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c
index 7a88adbceef6..b9b423b22a8b 100644
--- a/fs/reiserfs/item_ops.c
+++ b/fs/reiserfs/item_ops.c
@@ -75,8 +75,7 @@ static int sd_create_vi(struct virtual_node *vn,
static int sd_check_left(struct virtual_item *vi, int free,
int start_skip, int end_skip)
{
- if (start_skip || end_skip)
- BUG();
+ BUG_ON(start_skip || end_skip);
return -1;
}
@@ -87,8 +86,7 @@ static int sd_check_right(struct virtual_item *vi, int free)
static int sd_part_size(struct virtual_item *vi, int first, int count)
{
- if (count)
- BUG();
+ BUG_ON(count);
return 0;
}
@@ -476,8 +474,7 @@ static int direntry_create_vi(struct virtual_node *vn,
vi->vi_index = TYPE_DIRENTRY;
- if (!(vi->vi_ih) || !vi->vi_item)
- BUG();
+ BUG_ON(!(vi->vi_ih) || !vi->vi_item);
dir_u->flags = 0;
if (le_ih_k_offset(vi->vi_ih) == DOT_OFFSET)
@@ -575,8 +572,7 @@ static int direntry_check_right(struct virtual_item *vi, int free)
free -= dir_u->entry_sizes[i];
entries++;
}
- if (entries == dir_u->entry_count)
- BUG();
+ BUG_ON(entries == dir_u->entry_count);
/* "." and ".." can not be separated from each other */
if ((dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 9b3672d69367..85ce23268302 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -53,6 +53,7 @@
#include <linux/workqueue.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
/* gets a struct reiserfs_journal_list * from a list head */
#define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \
@@ -718,8 +719,7 @@ static int add_to_chunk(struct buffer_chunk *chunk, struct buffer_head *bh,
spinlock_t * lock, void (fn) (struct buffer_chunk *))
{
int ret = 0;
- if (chunk->nr >= CHUNK_SIZE)
- BUG();
+ BUG_ON(chunk->nr >= CHUNK_SIZE);
chunk->bh[chunk->nr++] = bh;
if (chunk->nr >= CHUNK_SIZE) {
ret = 1;
@@ -788,8 +788,7 @@ static inline int __add_jh(struct reiserfs_journal *j, struct buffer_head *bh,
/* buffer must be locked for __add_jh, should be able to have
* two adds at the same time
*/
- if (bh->b_private)
- BUG();
+ BUG_ON(bh->b_private);
jh->bh = bh;
bh->b_private = jh;
}
@@ -972,7 +971,7 @@ int reiserfs_async_progress_wait(struct super_block *s)
DEFINE_WAIT(wait);
struct reiserfs_journal *j = SB_JOURNAL(s);
if (atomic_read(&j->j_async_throttle))
- blk_congestion_wait(WRITE, HZ / 10);
+ congestion_wait(WRITE, HZ / 10);
return 0;
}
@@ -1186,6 +1185,21 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct
return NULL;
}
+static int newer_jl_done(struct reiserfs_journal_cnode *cn)
+{
+ struct super_block *sb = cn->sb;
+ b_blocknr_t blocknr = cn->blocknr;
+
+ cn = cn->hprev;
+ while (cn) {
+ if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist &&
+ atomic_read(&cn->jlist->j_commit_left) != 0)
+ return 0;
+ cn = cn->hprev;
+ }
+ return 1;
+}
+
static void remove_journal_hash(struct super_block *,
struct reiserfs_journal_cnode **,
struct reiserfs_journal_list *, unsigned long,
@@ -1604,6 +1618,31 @@ static int flush_journal_list(struct super_block *s,
return err;
}
+static int test_transaction(struct super_block *s,
+ struct reiserfs_journal_list *jl)
+{
+ struct reiserfs_journal_cnode *cn;
+
+ if (jl->j_len == 0 || atomic_read(&jl->j_nonzerolen) == 0)
+ return 1;
+
+ cn = jl->j_realblock;
+ while (cn) {
+ /* if the blocknr == 0, this has been cleared from the hash,
+ ** skip it
+ */
+ if (cn->blocknr == 0) {
+ goto next;
+ }
+ if (cn->bh && !newer_jl_done(cn))
+ return 0;
+ next:
+ cn = cn->next;
+ cond_resched();
+ }
+ return 0;
+}
+
static int write_one_transaction(struct super_block *s,
struct reiserfs_journal_list *jl,
struct buffer_chunk *chunk)
@@ -2927,8 +2966,7 @@ static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
int retval;
reiserfs_check_lock_depth(p_s_sb, "journal_begin");
- if (nblocks > journal->j_trans_max)
- BUG();
+ BUG_ON(nblocks > journal->j_trans_max);
PROC_INFO_INC(p_s_sb, journal.journal_being);
/* set here for journal_join */
@@ -3044,9 +3082,8 @@ struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
if (reiserfs_transaction_running(s)) {
th = current->journal_info;
th->t_refcount++;
- if (th->t_refcount < 2) {
- BUG();
- }
+ BUG_ON(th->t_refcount < 2);
+
return th;
}
th = kmalloc(sizeof(struct reiserfs_transaction_handle), GFP_NOFS);
@@ -3086,9 +3123,7 @@ static int journal_join(struct reiserfs_transaction_handle *th,
** pointer
*/
th->t_handle_save = cur_th;
- if (cur_th && cur_th->t_refcount > 1) {
- BUG();
- }
+ BUG_ON(cur_th && cur_th->t_refcount > 1);
return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN);
}
@@ -3101,9 +3136,7 @@ int journal_join_abort(struct reiserfs_transaction_handle *th,
** pointer
*/
th->t_handle_save = cur_th;
- if (cur_th && cur_th->t_refcount > 1) {
- BUG();
- }
+ BUG_ON(cur_th && cur_th->t_refcount > 1);
return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT);
}
@@ -3138,8 +3171,7 @@ int journal_begin(struct reiserfs_transaction_handle *th,
current->journal_info = th;
}
ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG);
- if (current->journal_info != th)
- BUG();
+ BUG_ON(current->journal_info != th);
/* I guess this boils down to being the reciprocal of clm-2100 above.
* If do_journal_begin_r fails, we need to put it back, since journal_end
@@ -3284,8 +3316,7 @@ int journal_end(struct reiserfs_transaction_handle *th,
/* we aren't allowed to close a nested transaction on a different
** filesystem from the one in the task struct
*/
- if (cur_th->t_super != th->t_super)
- BUG();
+ BUG_ON(cur_th->t_super != th->t_super);
if (th != cur_th) {
memcpy(current->journal_info, th, sizeof(*th));
@@ -3404,9 +3435,7 @@ int journal_end_sync(struct reiserfs_transaction_handle *th,
BUG_ON(!th->t_trans_id);
/* you can sync while nested, very, very bad */
- if (th->t_refcount > 1) {
- BUG();
- }
+ BUG_ON(th->t_refcount > 1);
if (journal->j_len == 0) {
reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb),
1);
@@ -3433,16 +3462,6 @@ static void flush_async_commits(void *p)
flush_commit_list(p_s_sb, jl, 1);
}
unlock_kernel();
- /*
- * this is a little racey, but there's no harm in missing
- * the filemap_fdata_write
- */
- if (!atomic_read(&journal->j_async_throttle)
- && !reiserfs_is_journal_aborted(journal)) {
- atomic_inc(&journal->j_async_throttle);
- filemap_fdatawrite(p_s_sb->s_bdev->bd_inode->i_mapping);
- atomic_dec(&journal->j_async_throttle);
- }
}
/*
@@ -3526,9 +3545,8 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
** will be dealt with by next transaction that actually writes something, but should be taken
** care of in this trans
*/
- if (journal->j_len == 0) {
- BUG();
- }
+ BUG_ON(journal->j_len == 0);
+
/* if wcount > 0, and we are called to with flush or commit_now,
** we wait on j_join_wait. We will wake up when the last writer has
** finished the transaction, and started it on its way to the disk.
@@ -3562,9 +3580,8 @@ static int check_journal_end(struct reiserfs_transaction_handle *th,
unlock_journal(p_s_sb);
}
}
- if (journal->j_trans_id == trans_id) {
- BUG();
- }
+ BUG_ON(journal->j_trans_id == trans_id);
+
if (commit_now
&& journal_list_still_alive(p_s_sb, trans_id)
&& wait_on_commit) {
@@ -3844,7 +3861,9 @@ static void flush_old_journal_lists(struct super_block *s)
entry = journal->j_journal_list.next;
jl = JOURNAL_LIST_ENTRY(entry);
/* this check should always be run, to send old lists to disk */
- if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4))) {
+ if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4)) &&
+ atomic_read(&jl->j_commit_left) == 0 &&
+ test_transaction(s, jl)) {
flush_used_journal_lists(s, jl);
} else {
break;
@@ -4042,9 +4061,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
set_commit_trans_len(commit, journal->j_len);
/* special check in case all buffers in the journal were marked for not logging */
- if (journal->j_len == 0) {
- BUG();
- }
+ BUG_ON(journal->j_len == 0);
/* we're about to dirty all the log blocks, mark the description block
* dirty now too. Don't mark the commit block dirty until all the
@@ -4141,8 +4158,7 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
journal, jl, &jl->j_tail_bh_list);
lock_kernel();
}
- if (!list_empty(&jl->j_tail_bh_list))
- BUG();
+ BUG_ON(!list_empty(&jl->j_tail_bh_list));
up(&jl->j_commit_lock);
/* honor the flush wishes from the caller, simple commits can
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index c61710e49c62..abde1edc2235 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -19,8 +19,8 @@
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
-#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { i->i_nlink++; if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
-#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) i->i_nlink--;
+#define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; }
+#define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i);
// directory item contains array of entry headers. This performs
// binary search through that array
@@ -67,8 +67,7 @@ inline void set_de_name_and_namelen(struct reiserfs_dir_entry *de)
{
struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
- if (de->de_entry_num >= ih_entry_count(de->de_ih))
- BUG();
+ BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));
de->de_entrylen = entry_length(de->de_bh, de->de_ih, de->de_entry_num);
de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0);
@@ -80,8 +79,7 @@ inline void set_de_name_and_namelen(struct reiserfs_dir_entry *de)
// what entry points to
static inline void set_de_object_key(struct reiserfs_dir_entry *de)
{
- if (de->de_entry_num >= ih_entry_count(de->de_ih))
- BUG();
+ BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));
de->de_dir_id = deh_dir_id(&(de->de_deh[de->de_entry_num]));
de->de_objectid = deh_objectid(&(de->de_deh[de->de_entry_num]));
}
@@ -90,8 +88,7 @@ static inline void store_de_entry_key(struct reiserfs_dir_entry *de)
{
struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
- if (de->de_entry_num >= ih_entry_count(de->de_ih))
- BUG();
+ BUG_ON(de->de_entry_num >= ih_entry_count(de->de_ih));
/* store key of the found entry */
de->de_entry_key.version = KEY_FORMAT_3_5;
@@ -913,7 +910,7 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
reiserfs_warning(inode->i_sb, "%s: empty directory has nlink "
"!= 2 (%d)", __FUNCTION__, inode->i_nlink);
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
reiserfs_update_sd(&th, inode);
@@ -994,7 +991,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
inode->i_nlink = 1;
}
- inode->i_nlink--;
+ drop_nlink(inode);
/*
* we schedule before doing the add_save_link call, save the link
@@ -1006,7 +1003,7 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
reiserfs_cut_from_item(&th, &path, &(de.de_entry_key), dir, NULL,
0);
if (retval < 0) {
- inode->i_nlink++;
+ inc_nlink(inode);
goto end_unlink;
}
inode->i_ctime = CURRENT_TIME_SEC;
@@ -1143,7 +1140,7 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
}
/* inc before scheduling so reiserfs_unlink knows we are here */
- inode->i_nlink++;
+ inc_nlink(inode);
retval = journal_begin(&th, dir->i_sb, jbegin_count);
if (retval) {
@@ -1473,9 +1470,9 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_dentry_inode) {
// adjust link number of the victim
if (S_ISDIR(new_dentry_inode->i_mode)) {
- new_dentry_inode->i_nlink = 0;
+ clear_nlink(new_dentry_inode);
} else {
- new_dentry_inode->i_nlink--;
+ drop_nlink(new_dentry_inode);
}
new_dentry_inode->i_ctime = ctime;
savelink = new_dentry_inode->i_nlink;
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index 39cc7f47f5dc..315684793d1d 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -22,6 +22,7 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
int err = 0;
struct reiserfs_super_block *sb;
struct reiserfs_bitmap_info *bitmap;
+ struct reiserfs_bitmap_info *info;
struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
struct buffer_head *bh;
struct reiserfs_transaction_handle th;
@@ -127,16 +128,20 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
* transaction begins, and the new bitmaps don't matter if the
* transaction fails. */
for (i = bmap_nr; i < bmap_nr_new; i++) {
- bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
- memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
- reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
-
- set_buffer_uptodate(bitmap[i].bh);
- mark_buffer_dirty(bitmap[i].bh);
- sync_dirty_buffer(bitmap[i].bh);
+ /* don't use read_bitmap_block since it will cache
+ * the uninitialized bitmap */
+ bh = sb_bread(s, i * s->s_blocksize * 8);
+ memset(bh->b_data, 0, sb_blocksize(sb));
+ reiserfs_test_and_set_le_bit(0, bh->b_data);
+ reiserfs_cache_bitmap_metadata(s, bh, bitmap + i);
+
+ set_buffer_uptodate(bh);
+ mark_buffer_dirty(bh);
+ sync_dirty_buffer(bh);
// update bitmap_info stuff
bitmap[i].first_zero_hint = 1;
bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
+ brelse(bh);
}
/* free old bitmap blocks array */
SB_AP_BITMAP(s) = bitmap;
@@ -150,30 +155,46 @@ int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
if (err)
return err;
- /* correct last bitmap blocks in old and new disk layout */
- reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
+ /* Extend old last bitmap block - new blocks have been made available */
+ info = SB_AP_BITMAP(s) + bmap_nr - 1;
+ bh = reiserfs_read_bitmap_block(s, bmap_nr - 1);
+ if (!bh) {
+ int jerr = journal_end(&th, s, 10);
+ if (jerr)
+ return jerr;
+ return -EIO;
+ }
+
+ reiserfs_prepare_for_journal(s, bh, 1);
for (i = block_r; i < s->s_blocksize * 8; i++)
- reiserfs_test_and_clear_le_bit(i,
- SB_AP_BITMAP(s)[bmap_nr -
- 1].bh->b_data);
- SB_AP_BITMAP(s)[bmap_nr - 1].free_count += s->s_blocksize * 8 - block_r;
- if (!SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
- SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;
+ reiserfs_test_and_clear_le_bit(i, bh->b_data);
+ info->free_count += s->s_blocksize * 8 - block_r;
+ if (!info->first_zero_hint)
+ info->first_zero_hint = block_r;
- journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);
+ journal_mark_dirty(&th, s, bh);
+ brelse(bh);
+
+ /* Correct new last bitmap block - It may not be full */
+ info = SB_AP_BITMAP(s) + bmap_nr_new - 1;
+ bh = reiserfs_read_bitmap_block(s, bmap_nr_new - 1);
+ if (!bh) {
+ int jerr = journal_end(&th, s, 10);
+ if (jerr)
+ return jerr;
+ return -EIO;
+ }
- reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
+ reiserfs_prepare_for_journal(s, bh, 1);
for (i = block_r_new; i < s->s_blocksize * 8; i++)
- reiserfs_test_and_set_le_bit(i,
- SB_AP_BITMAP(s)[bmap_nr_new -
- 1].bh->b_data);
- journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
+ reiserfs_test_and_set_le_bit(i, bh->b_data);
+ journal_mark_dirty(&th, s, bh);
+ brelse(bh);
- SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -=
- s->s_blocksize * 8 - block_r_new;
+ info->free_count -= s->s_blocksize * 8 - block_r_new;
/* Extreme case where last bitmap is the only valid block in itself. */
- if (!SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count)
- SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0;
+ if (!info->free_count)
+ info->first_zero_hint = 0;
/* update super */
reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
free_blocks = SB_FREE_BLOCKS(s);
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index 8b9b13127136..5240abe1a709 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -1476,9 +1476,7 @@ static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th,
int n_block_size = p_s_sb->s_blocksize;
int cut_bytes;
BUG_ON(!th->t_trans_id);
-
- if (n_new_file_size != p_s_inode->i_size)
- BUG();
+ BUG_ON(n_new_file_size != p_s_inode->i_size);
/* the page being sent in could be NULL if there was an i/o error
** reading in the last block. The user will hit problems trying to
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 5567328f1041..9041802df832 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -430,21 +430,29 @@ int remove_save_link(struct inode *inode, int truncate)
return journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
}
-static void reiserfs_put_super(struct super_block *s)
+static void reiserfs_kill_sb(struct super_block *s)
{
- int i;
- struct reiserfs_transaction_handle th;
- th.t_trans_id = 0;
+ if (REISERFS_SB(s)) {
+ if (REISERFS_SB(s)->xattr_root) {
+ d_invalidate(REISERFS_SB(s)->xattr_root);
+ dput(REISERFS_SB(s)->xattr_root);
+ REISERFS_SB(s)->xattr_root = NULL;
+ }
- if (REISERFS_SB(s)->xattr_root) {
- d_invalidate(REISERFS_SB(s)->xattr_root);
- dput(REISERFS_SB(s)->xattr_root);
+ if (REISERFS_SB(s)->priv_root) {
+ d_invalidate(REISERFS_SB(s)->priv_root);
+ dput(REISERFS_SB(s)->priv_root);
+ REISERFS_SB(s)->priv_root = NULL;
+ }
}
- if (REISERFS_SB(s)->priv_root) {
- d_invalidate(REISERFS_SB(s)->priv_root);
- dput(REISERFS_SB(s)->priv_root);
- }
+ kill_block_super(s);
+}
+
+static void reiserfs_put_super(struct super_block *s)
+{
+ struct reiserfs_transaction_handle th;
+ th.t_trans_id = 0;
/* change file system state to current state if it was mounted with read-write permissions */
if (!(s->s_flags & MS_RDONLY)) {
@@ -462,10 +470,7 @@ static void reiserfs_put_super(struct super_block *s)
*/
journal_release(&th, s);
- for (i = 0; i < SB_BMAP_NR(s); i++)
- brelse(SB_AP_BITMAP(s)[i].bh);
-
- vfree(SB_AP_BITMAP(s));
+ reiserfs_free_bitmap_cache(s);
brelse(SB_BUFFER_WITH_SB(s));
@@ -510,8 +515,10 @@ static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
SLAB_CTOR_CONSTRUCTOR) {
INIT_LIST_HEAD(&ei->i_prealloc_list);
inode_init_once(&ei->vfs_inode);
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
ei->i_acl_access = NULL;
ei->i_acl_default = NULL;
+#endif
}
}
@@ -530,9 +537,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(reiserfs_inode_cachep))
- reiserfs_warning(NULL,
- "reiserfs_inode_cache: not all structures were freed");
+ kmem_cache_destroy(reiserfs_inode_cachep);
}
/* we don't mark inodes dirty, we just log them */
@@ -562,6 +567,7 @@ static void reiserfs_dirty_inode(struct inode *inode)
reiserfs_write_unlock(inode->i_sb);
}
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
static void reiserfs_clear_inode(struct inode *inode)
{
struct posix_acl *acl;
@@ -576,6 +582,9 @@ static void reiserfs_clear_inode(struct inode *inode)
posix_acl_release(acl);
REISERFS_I(inode)->i_acl_default = NULL;
}
+#else
+#define reiserfs_clear_inode NULL
+#endif
#ifdef CONFIG_QUOTA
static ssize_t reiserfs_quota_write(struct super_block *, int, const char *,
@@ -725,12 +734,6 @@ static const arg_desc_t error_actions[] = {
{NULL, 0, 0},
};
-int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
- There might be broken applications that are
- confused by this. Use nolargeio mount option
- to get usual i/o size = PAGE_SIZE.
- */
-
/* proceed only one option from a list *cur - string containing of mount options
opts - array of options which are accepted
opt_arg - if option is found and requires an argument and if it is specifed
@@ -959,19 +962,8 @@ static int reiserfs_parse_options(struct super_block *s, char *options, /* strin
}
if (c == 'w') {
- char *p = NULL;
- int val = simple_strtoul(arg, &p, 0);
-
- if (*p != '\0') {
- reiserfs_warning(s,
- "reiserfs_parse_options: non-numeric value %s for nolargeio option",
- arg);
- return 0;
- }
- if (val)
- reiserfs_default_io_size = PAGE_SIZE;
- else
- reiserfs_default_io_size = 128 * 1024;
+ reiserfs_warning(s, "reiserfs: nolargeio option is no longer supported");
+ return 0;
}
if (c == 'j') {
@@ -1256,118 +1248,6 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
return 0;
}
-/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk.
- * @sb - superblock for this filesystem
- * @bi - the bitmap info to be loaded. Requires that bi->bh is valid.
- *
- * This routine counts how many free bits there are, finding the first zero
- * as a side effect. Could also be implemented as a loop of test_bit() calls, or
- * a loop of find_first_zero_bit() calls. This implementation is similar to
- * find_first_zero_bit(), but doesn't return after it finds the first bit.
- * Should only be called on fs mount, but should be fairly efficient anyways.
- *
- * bi->first_zero_hint is considered unset if it == 0, since the bitmap itself
- * will * invariably occupt block 0 represented in the bitmap. The only
- * exception to this is when free_count also == 0, since there will be no
- * free blocks at all.
- */
-
-static void load_bitmap_info_data(struct super_block *sb,
- struct reiserfs_bitmap_info *bi)
-{
- unsigned long *cur = (unsigned long *)bi->bh->b_data;
-
- while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) {
-
- /* No need to scan if all 0's or all 1's.
- * Since we're only counting 0's, we can simply ignore all 1's */
- if (*cur == 0) {
- if (bi->first_zero_hint == 0) {
- bi->first_zero_hint =
- ((char *)cur - bi->bh->b_data) << 3;
- }
- bi->free_count += sizeof(unsigned long) * 8;
- } else if (*cur != ~0L) {
- int b;
- for (b = 0; b < sizeof(unsigned long) * 8; b++) {
- if (!reiserfs_test_le_bit(b, cur)) {
- bi->free_count++;
- if (bi->first_zero_hint == 0)
- bi->first_zero_hint =
- (((char *)cur -
- bi->bh->b_data) << 3) + b;
- }
- }
- }
- cur++;
- }
-
-#ifdef CONFIG_REISERFS_CHECK
-// This outputs a lot of unneded info on big FSes
-// reiserfs_warning ("bitmap loaded from block %d: %d free blocks",
-// bi->bh->b_blocknr, bi->free_count);
-#endif
-}
-
-static int read_bitmaps(struct super_block *s)
-{
- int i, bmap_nr;
-
- SB_AP_BITMAP(s) =
- vmalloc(sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
- if (SB_AP_BITMAP(s) == 0)
- return 1;
- memset(SB_AP_BITMAP(s), 0,
- sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
- for (i = 0, bmap_nr =
- REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
- i < SB_BMAP_NR(s); i++, bmap_nr = s->s_blocksize * 8 * i) {
- SB_AP_BITMAP(s)[i].bh = sb_getblk(s, bmap_nr);
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
- ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);
- }
- for (i = 0; i < SB_BMAP_NR(s); i++) {
- wait_on_buffer(SB_AP_BITMAP(s)[i].bh);
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
- reiserfs_warning(s, "sh-2029: reiserfs read_bitmaps: "
- "bitmap block (#%lu) reading failed",
- SB_AP_BITMAP(s)[i].bh->b_blocknr);
- for (i = 0; i < SB_BMAP_NR(s); i++)
- brelse(SB_AP_BITMAP(s)[i].bh);
- vfree(SB_AP_BITMAP(s));
- SB_AP_BITMAP(s) = NULL;
- return 1;
- }
- load_bitmap_info_data(s, SB_AP_BITMAP(s) + i);
- }
- return 0;
-}
-
-static int read_old_bitmaps(struct super_block *s)
-{
- int i;
- struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
- int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */
-
- /* read true bitmap */
- SB_AP_BITMAP(s) =
- vmalloc(sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
- if (SB_AP_BITMAP(s) == 0)
- return 1;
-
- memset(SB_AP_BITMAP(s), 0,
- sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
-
- for (i = 0; i < sb_bmap_nr(rs); i++) {
- SB_AP_BITMAP(s)[i].bh = sb_bread(s, bmp1 + i);
- if (!SB_AP_BITMAP(s)[i].bh)
- return 1;
- load_bitmap_info_data(s, SB_AP_BITMAP(s) + i);
- }
-
- return 0;
-}
-
static int read_super_block(struct super_block *s, int offset)
{
struct buffer_head *bh;
@@ -1469,7 +1349,6 @@ static int read_super_block(struct super_block *s, int offset)
/* after journal replay, reread all bitmap and super blocks */
static int reread_meta_blocks(struct super_block *s)
{
- int i;
ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s)));
wait_on_buffer(SB_BUFFER_WITH_SB(s));
if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
@@ -1478,20 +1357,7 @@ static int reread_meta_blocks(struct super_block *s)
return 1;
}
- for (i = 0; i < SB_BMAP_NR(s); i++) {
- ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh));
- wait_on_buffer(SB_AP_BITMAP(s)[i].bh);
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
- reiserfs_warning(s,
- "reread_meta_blocks, error reading bitmap block number %d at %llu",
- i,
- (unsigned long long)SB_AP_BITMAP(s)[i].
- bh->b_blocknr);
- return 1;
- }
- }
return 0;
-
}
/////////////////////////////////////////////////////
@@ -1672,7 +1538,6 @@ static int function2code(hashf_t func)
static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
{
struct inode *root_inode;
- int j;
struct reiserfs_transaction_handle th;
int old_format = 0;
unsigned long blocks;
@@ -1749,7 +1614,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
sbi->s_mount_state = SB_REISERFS_STATE(s);
sbi->s_mount_state = REISERFS_VALID_FS;
- if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) {
+ if ((errval = reiserfs_init_bitmap_cache(s))) {
SWARN(silent, s,
"jmacd-8: reiserfs_fill_super: unable to read bitmap");
goto error;
@@ -1831,6 +1696,8 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
if (is_reiserfs_3_5(rs)
|| (is_reiserfs_jr(rs) && SB_VERSION(s) == REISERFS_VERSION_1))
set_bit(REISERFS_3_5, &(sbi->s_properties));
+ else if (old_format)
+ set_bit(REISERFS_OLD_FORMAT, &(sbi->s_properties));
else
set_bit(REISERFS_3_6, &(sbi->s_properties));
@@ -1916,19 +1783,17 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
if (jinit_done) { /* kill the commit thread, free journal ram */
journal_release_error(NULL, s);
}
- if (SB_DISK_SUPER_BLOCK(s)) {
- for (j = 0; j < SB_BMAP_NR(s); j++) {
- if (SB_AP_BITMAP(s))
- brelse(SB_AP_BITMAP(s)[j].bh);
- }
- vfree(SB_AP_BITMAP(s));
- }
+
+ reiserfs_free_bitmap_cache(s);
if (SB_BUFFER_WITH_SB(s))
brelse(SB_BUFFER_WITH_SB(s));
#ifdef CONFIG_QUOTA
- for (j = 0; j < MAXQUOTAS; j++) {
- kfree(sbi->s_qf_names[j]);
- sbi->s_qf_names[j] = NULL;
+ {
+ int j;
+ for (j = 0; j < MAXQUOTAS; j++) {
+ kfree(sbi->s_qf_names[j]);
+ sbi->s_qf_names[j] = NULL;
+ }
}
#endif
kfree(sbi);
@@ -2300,7 +2165,7 @@ struct file_system_type reiserfs_fs_type = {
.owner = THIS_MODULE,
.name = "reiserfs",
.get_sb = get_super_block,
- .kill_sb = kill_block_super,
+ .kill_sb = reiserfs_kill_sb,
.fs_flags = FS_REQUIRES_DEV,
};
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index d935fb9394e3..7bdb0ed443e1 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -773,7 +773,7 @@ int reiserfs_xattr_del(struct inode *inode, const char *name)
static int
reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct dentry *xadir = (struct dentry *)buf;
@@ -851,7 +851,7 @@ struct reiserfs_chown_buf {
/* XXX: If there is a better way to do this, I'd love to hear about it */
static int
reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
struct dentry *xafile, *xadir = chown_buf->xadir;
@@ -1036,7 +1036,7 @@ struct reiserfs_listxattr_buf {
static int
reiserfs_listxattr_filler(void *buf, const char *name, int namelen,
- loff_t offset, ino_t ino, unsigned int d_type)
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
int len = 0;
diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c
index 22eed61ebf69..ddcd9e1ef282 100644
--- a/fs/romfs/inode.c
+++ b/fs/romfs/inode.c
@@ -589,8 +589,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(romfs_inode_cachep))
- printk(KERN_INFO "romfs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(romfs_inode_cachep);
}
static int romfs_remount(struct super_block *sb, int *flags, char *data)
diff --git a/fs/select.c b/fs/select.c
index 33b72ba0f86f..dcbc1112b7ec 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -658,8 +658,6 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
unsigned int i;
struct poll_list *head;
struct poll_list *walk;
- struct fdtable *fdt;
- int max_fdset;
/* Allocate small arguments on the stack to save memory and be
faster - use long to make sure the buffer is aligned properly
on 64 bit archs to avoid unaligned access */
@@ -667,11 +665,7 @@ int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, s64 *timeout)
struct poll_list *stack_pp = NULL;
/* Do a sanity check on nfds ... */
- rcu_read_lock();
- fdt = files_fdtable(current->files);
- max_fdset = fdt->max_fdset;
- rcu_read_unlock();
- if (nfds > max_fdset && nfds > OPEN_MAX)
+ if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur)
return -EINVAL;
poll_initwait(&table);
diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c
index dae67048baba..50784d13c87b 100644
--- a/fs/smbfs/file.c
+++ b/fs/smbfs/file.c
@@ -214,13 +214,15 @@ smb_updatepage(struct file *file, struct page *page, unsigned long offset,
}
static ssize_t
-smb_file_read(struct file * file, char __user * buf, size_t count, loff_t *ppos)
+smb_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
+ struct file * file = iocb->ki_filp;
struct dentry * dentry = file->f_dentry;
ssize_t status;
VERBOSE("file %s/%s, count=%lu@%lu\n", DENTRY_PATH(dentry),
- (unsigned long) count, (unsigned long) *ppos);
+ (unsigned long) iocb->ki_left, (unsigned long) pos);
status = smb_revalidate_inode(dentry);
if (status) {
@@ -233,7 +235,7 @@ smb_file_read(struct file * file, char __user * buf, size_t count, loff_t *ppos)
(long)dentry->d_inode->i_size,
dentry->d_inode->i_flags, dentry->d_inode->i_atime);
- status = generic_file_read(file, buf, count, ppos);
+ status = generic_file_aio_read(iocb, iov, nr_segs, pos);
out:
return status;
}
@@ -317,14 +319,16 @@ const struct address_space_operations smb_file_aops = {
* Write to a file (through the page cache).
*/
static ssize_t
-smb_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+smb_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
+ struct file * file = iocb->ki_filp;
struct dentry * dentry = file->f_dentry;
ssize_t result;
VERBOSE("file %s/%s, count=%lu@%lu\n",
DENTRY_PATH(dentry),
- (unsigned long) count, (unsigned long) *ppos);
+ (unsigned long) iocb->ki_left, (unsigned long) pos);
result = smb_revalidate_inode(dentry);
if (result) {
@@ -337,8 +341,8 @@ smb_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
if (result)
goto out;
- if (count > 0) {
- result = generic_file_write(file, buf, count, ppos);
+ if (iocb->ki_left > 0) {
+ result = generic_file_aio_write(iocb, iov, nr_segs, pos);
VERBOSE("pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
(long) file->f_pos, (long) dentry->d_inode->i_size,
dentry->d_inode->i_mtime, dentry->d_inode->i_atime);
@@ -402,8 +406,10 @@ smb_file_permission(struct inode *inode, int mask, struct nameidata *nd)
const struct file_operations smb_file_operations =
{
.llseek = remote_llseek,
- .read = smb_file_read,
- .write = smb_file_write,
+ .read = do_sync_read,
+ .aio_read = smb_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = smb_file_aio_write,
.ioctl = smb_ioctl,
.mmap = smb_file_mmap,
.open = smb_file_open,
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c
index a1ed657c3c84..2c122ee83adb 100644
--- a/fs/smbfs/inode.c
+++ b/fs/smbfs/inode.c
@@ -89,8 +89,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(smb_inode_cachep))
- printk(KERN_INFO "smb_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(smb_inode_cachep);
}
static int smb_remount(struct super_block *sb, int *flags, char *data)
@@ -167,7 +166,6 @@ smb_get_inode_attr(struct inode *inode, struct smb_fattr *fattr)
fattr->f_mtime = inode->i_mtime;
fattr->f_ctime = inode->i_ctime;
fattr->f_atime = inode->i_atime;
- fattr->f_blksize= inode->i_blksize;
fattr->f_blocks = inode->i_blocks;
fattr->attr = SMB_I(inode)->attr;
@@ -201,7 +199,6 @@ smb_set_inode_attr(struct inode *inode, struct smb_fattr *fattr)
inode->i_uid = fattr->f_uid;
inode->i_gid = fattr->f_gid;
inode->i_ctime = fattr->f_ctime;
- inode->i_blksize= fattr->f_blksize;
inode->i_blocks = fattr->f_blocks;
inode->i_size = fattr->f_size;
inode->i_mtime = fattr->f_mtime;
diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c
index c3495059889d..40e174db9872 100644
--- a/fs/smbfs/proc.c
+++ b/fs/smbfs/proc.c
@@ -1826,7 +1826,6 @@ smb_init_dirent(struct smb_sb_info *server, struct smb_fattr *fattr)
fattr->f_nlink = 1;
fattr->f_uid = server->mnt->uid;
fattr->f_gid = server->mnt->gid;
- fattr->f_blksize = SMB_ST_BLKSIZE;
fattr->f_unix = 0;
}
diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c
index c8e96195b96e..0fb74697abc4 100644
--- a/fs/smbfs/request.c
+++ b/fs/smbfs/request.c
@@ -49,8 +49,7 @@ int smb_init_request_cache(void)
void smb_destroy_request_cache(void)
{
- if (kmem_cache_destroy(req_cachep))
- printk(KERN_INFO "smb_destroy_request_cache: not all structures were freed\n");
+ kmem_cache_destroy(req_cachep);
}
/*
diff --git a/fs/splice.c b/fs/splice.c
index 684bca3d3a10..49fb9f129938 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -12,7 +12,7 @@
* Jens to support splicing to files, network, direct splicing, etc and
* fixing lots of bugs.
*
- * Copyright (C) 2005-2006 Jens Axboe <axboe@suse.de>
+ * Copyright (C) 2005-2006 Jens Axboe <axboe@kernel.dk>
* Copyright (C) 2005-2006 Linus Torvalds <torvalds@osdl.org>
* Copyright (C) 2006 Ingo Molnar <mingo@elte.hu>
*
@@ -607,7 +607,7 @@ find_page:
ret = -ENOMEM;
page = page_cache_alloc_cold(mapping);
if (unlikely(!page))
- goto out_nomem;
+ goto out_ret;
/*
* This will also lock the page
@@ -666,7 +666,7 @@ find_page:
if (sd->pos + this_len > isize)
vmtruncate(mapping->host, isize);
- goto out;
+ goto out_ret;
}
if (buf->page != page) {
@@ -698,7 +698,7 @@ find_page:
out:
page_cache_release(page);
unlock_page(page);
-out_nomem:
+out_ret:
return ret;
}
@@ -707,9 +707,9 @@ out_nomem:
* key here is the 'actor' worker passed in that actually moves the data
* to the wanted destination. See pipe_to_file/pipe_to_sendpage above.
*/
-ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
- loff_t *ppos, size_t len, unsigned int flags,
- splice_actor *actor)
+static ssize_t __splice_from_pipe(struct pipe_inode_info *pipe,
+ struct file *out, loff_t *ppos, size_t len,
+ unsigned int flags, splice_actor *actor)
{
int ret, do_wakeup, err;
struct splice_desc sd;
@@ -722,9 +722,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
sd.file = out;
sd.pos = *ppos;
- if (pipe->inode)
- mutex_lock(&pipe->inode->i_mutex);
-
for (;;) {
if (pipe->nrbufs) {
struct pipe_buffer *buf = pipe->bufs + pipe->curbuf;
@@ -797,9 +794,6 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
pipe_wait(pipe);
}
- if (pipe->inode)
- mutex_unlock(&pipe->inode->i_mutex);
-
if (do_wakeup) {
smp_mb();
if (waitqueue_active(&pipe->wait))
@@ -810,6 +804,73 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
return ret;
}
+ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out,
+ loff_t *ppos, size_t len, unsigned int flags,
+ splice_actor *actor)
+{
+ ssize_t ret;
+ struct inode *inode = out->f_mapping->host;
+
+ /*
+ * The actor worker might be calling ->prepare_write and
+ * ->commit_write. Most of the time, these expect i_mutex to
+ * be held. Since this may result in an ABBA deadlock with
+ * pipe->inode, we have to order lock acquiry here.
+ */
+ inode_double_lock(inode, pipe->inode);
+ ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor);
+ inode_double_unlock(inode, pipe->inode);
+
+ return ret;
+}
+
+/**
+ * generic_file_splice_write_nolock - generic_file_splice_write without mutexes
+ * @pipe: pipe info
+ * @out: file to write to
+ * @len: number of bytes to splice
+ * @flags: splice modifier flags
+ *
+ * Will either move or copy pages (determined by @flags options) from
+ * the given pipe inode to the given file. The caller is responsible
+ * for acquiring i_mutex on both inodes.
+ *
+ */
+ssize_t
+generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out,
+ loff_t *ppos, size_t len, unsigned int flags)
+{
+ struct address_space *mapping = out->f_mapping;
+ struct inode *inode = mapping->host;
+ ssize_t ret;
+ int err;
+
+ err = remove_suid(out->f_dentry);
+ if (unlikely(err))
+ return err;
+
+ ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
+ if (ret > 0) {
+ *ppos += ret;
+
+ /*
+ * If file or inode is SYNC and we actually wrote some data,
+ * sync it.
+ */
+ if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
+ err = generic_osync_inode(inode, mapping,
+ OSYNC_METADATA|OSYNC_DATA);
+
+ if (err)
+ ret = err;
+ }
+ }
+
+ return ret;
+}
+
+EXPORT_SYMBOL(generic_file_splice_write_nolock);
+
/**
* generic_file_splice_write - splice data from a pipe to a file
* @pipe: pipe info
@@ -826,12 +887,21 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
loff_t *ppos, size_t len, unsigned int flags)
{
struct address_space *mapping = out->f_mapping;
+ struct inode *inode = mapping->host;
ssize_t ret;
+ int err;
+
+ err = should_remove_suid(out->f_dentry);
+ if (unlikely(err)) {
+ mutex_lock(&inode->i_mutex);
+ err = __remove_suid(out->f_dentry, err);
+ mutex_unlock(&inode->i_mutex);
+ if (err)
+ return err;
+ }
ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
if (ret > 0) {
- struct inode *inode = mapping->host;
-
*ppos += ret;
/*
@@ -839,8 +909,6 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
* sync it.
*/
if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
- int err;
-
mutex_lock(&inode->i_mutex);
err = generic_osync_inode(inode, mapping,
OSYNC_METADATA|OSYNC_DATA);
@@ -1400,13 +1468,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
* grabbing by inode address. Otherwise two different processes
* could deadlock (one doing tee from A -> B, the other from B -> A).
*/
- if (ipipe->inode < opipe->inode) {
- mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_PARENT);
- mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_CHILD);
- } else {
- mutex_lock_nested(&opipe->inode->i_mutex, I_MUTEX_PARENT);
- mutex_lock_nested(&ipipe->inode->i_mutex, I_MUTEX_CHILD);
- }
+ inode_double_lock(ipipe->inode, opipe->inode);
do {
if (!opipe->readers) {
@@ -1450,8 +1512,7 @@ static int link_pipe(struct pipe_inode_info *ipipe,
i++;
} while (len);
- mutex_unlock(&ipipe->inode->i_mutex);
- mutex_unlock(&opipe->inode->i_mutex);
+ inode_double_unlock(ipipe->inode, opipe->inode);
/*
* If we put data in the output pipe, wakeup any potential readers.
diff --git a/fs/stat.c b/fs/stat.c
index 3a44dcf97da2..bca07eb2003c 100644
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -14,6 +14,7 @@
#include <linux/namei.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include <linux/pagemap.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -32,7 +33,7 @@ void generic_fillattr(struct inode *inode, struct kstat *stat)
stat->ctime = inode->i_ctime;
stat->size = i_size_read(inode);
stat->blocks = inode->i_blocks;
- stat->blksize = inode->i_blksize;
+ stat->blksize = (1 << inode->i_blkbits);
}
EXPORT_SYMBOL(generic_fillattr);
@@ -139,6 +140,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
memset(&tmp, 0, sizeof(struct __old_kernel_stat));
tmp.st_dev = old_encode_dev(stat->dev);
tmp.st_ino = stat->ino;
+ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
+ return -EOVERFLOW;
tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
if (tmp.st_nlink != stat->nlink)
@@ -209,6 +212,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
tmp.st_dev = new_encode_dev(stat->dev);
#endif
tmp.st_ino = stat->ino;
+ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
+ return -EOVERFLOW;
tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
if (tmp.st_nlink != stat->nlink)
@@ -346,6 +351,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf)
tmp.st_rdev = huge_encode_dev(stat->rdev);
#endif
tmp.st_ino = stat->ino;
+ if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
+ return -EOVERFLOW;
#ifdef STAT64_HAS_BROKEN_ST_INO
tmp.__st_ino = stat->ino;
#endif
diff --git a/fs/super.c b/fs/super.c
index 5c4c94d5495e..47e554c12e76 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -199,7 +199,7 @@ EXPORT_SYMBOL(deactivate_super);
* success, 0 if we had failed (superblock contents was already dead or
* dying when grab_super() had been called).
*/
-static int grab_super(struct super_block *s)
+static int grab_super(struct super_block *s) __releases(sb_lock)
{
s->s_count++;
spin_unlock(&sb_lock);
@@ -220,6 +220,37 @@ static int grab_super(struct super_block *s)
return 0;
}
+/*
+ * Write out and wait upon all dirty data associated with this
+ * superblock. Filesystem data as well as the underlying block
+ * device. Takes the superblock lock. Requires a second blkdev
+ * flush by the caller to complete the operation.
+ */
+void __fsync_super(struct super_block *sb)
+{
+ sync_inodes_sb(sb, 0);
+ DQUOT_SYNC(sb);
+ lock_super(sb);
+ if (sb->s_dirt && sb->s_op->write_super)
+ sb->s_op->write_super(sb);
+ unlock_super(sb);
+ if (sb->s_op->sync_fs)
+ sb->s_op->sync_fs(sb, 1);
+ sync_blockdev(sb->s_bdev);
+ sync_inodes_sb(sb, 1);
+}
+
+/*
+ * Write out and wait upon all dirty data associated with this
+ * superblock. Filesystem data as well as the underlying block
+ * device. Takes the superblock lock.
+ */
+int fsync_super(struct super_block *sb)
+{
+ __fsync_super(sb);
+ return sync_blockdev(sb->s_bdev);
+}
+
/**
* generic_shutdown_super - common helper for ->kill_sb()
* @sb: superblock to kill
@@ -229,17 +260,17 @@ static int grab_super(struct super_block *s)
* that need destruction out of superblock, call generic_shutdown_super()
* and release aforementioned objects. Note: dentries and inodes _are_
* taken care of and do not need specific handling.
+ *
+ * Upon calling this function, the filesystem may no longer alter or
+ * rearrange the set of dentries belonging to this super_block, nor may it
+ * change the attachments of dentries to inodes.
*/
void generic_shutdown_super(struct super_block *sb)
{
- struct dentry *root = sb->s_root;
struct super_operations *sop = sb->s_op;
- if (root) {
- sb->s_root = NULL;
- shrink_dcache_parent(root);
- shrink_dcache_sb(sb);
- dput(root);
+ if (sb->s_root) {
+ shrink_dcache_for_umount(sb);
fsync_super(sb);
lock_super(sb);
sb->s_flags &= ~MS_ACTIVE;
@@ -540,8 +571,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
{
int retval;
+#ifdef CONFIG_BLOCK
if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
return -EACCES;
+#endif
if (flags & MS_RDONLY)
acct_auto_close(sb);
shrink_dcache_sb(sb);
@@ -661,6 +694,7 @@ void kill_litter_super(struct super_block *sb)
EXPORT_SYMBOL(kill_litter_super);
+#ifdef CONFIG_BLOCK
static int set_bdev_super(struct super_block *s, void *data)
{
s->s_bdev = data;
@@ -756,6 +790,7 @@ void kill_block_super(struct super_block *sb)
}
EXPORT_SYMBOL(kill_block_super);
+#endif
int get_sb_nodev(struct file_system_type *fs_type,
int flags, void *data,
diff --git a/fs/sync.c b/fs/sync.c
index 955aef04da28..1de747b5ddb9 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -10,11 +10,124 @@
#include <linux/syscalls.h>
#include <linux/linkage.h>
#include <linux/pagemap.h>
+#include <linux/quotaops.h>
+#include <linux/buffer_head.h>
#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \
SYNC_FILE_RANGE_WAIT_AFTER)
/*
+ * sync everything. Start out by waking pdflush, because that writes back
+ * all queues in parallel.
+ */
+static void do_sync(unsigned long wait)
+{
+ wakeup_pdflush(0);
+ sync_inodes(0); /* All mappings, inodes and their blockdevs */
+ DQUOT_SYNC(NULL);
+ sync_supers(); /* Write the superblocks */
+ sync_filesystems(0); /* Start syncing the filesystems */
+ sync_filesystems(wait); /* Waitingly sync the filesystems */
+ sync_inodes(wait); /* Mappings, inodes and blockdevs, again. */
+ if (!wait)
+ printk("Emergency Sync complete\n");
+ if (unlikely(laptop_mode))
+ laptop_sync_completion();
+}
+
+asmlinkage long sys_sync(void)
+{
+ do_sync(1);
+ return 0;
+}
+
+void emergency_sync(void)
+{
+ pdflush_operation(do_sync, 0);
+}
+
+/*
+ * Generic function to fsync a file.
+ *
+ * filp may be NULL if called via the msync of a vma.
+ */
+int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
+{
+ struct inode * inode = dentry->d_inode;
+ struct super_block * sb;
+ int ret, err;
+
+ /* sync the inode to buffers */
+ ret = write_inode_now(inode, 0);
+
+ /* sync the superblock to buffers */
+ sb = inode->i_sb;
+ lock_super(sb);
+ if (sb->s_op->write_super)
+ sb->s_op->write_super(sb);
+ unlock_super(sb);
+
+ /* .. finally sync the buffers to disk */
+ err = sync_blockdev(sb->s_bdev);
+ if (!ret)
+ ret = err;
+ return ret;
+}
+
+long do_fsync(struct file *file, int datasync)
+{
+ int ret;
+ int err;
+ struct address_space *mapping = file->f_mapping;
+
+ if (!file->f_op || !file->f_op->fsync) {
+ /* Why? We can still call filemap_fdatawrite */
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = filemap_fdatawrite(mapping);
+
+ /*
+ * We need to protect against concurrent writers, which could cause
+ * livelocks in fsync_buffers_list().
+ */
+ mutex_lock(&mapping->host->i_mutex);
+ err = file->f_op->fsync(file, file->f_dentry, datasync);
+ if (!ret)
+ ret = err;
+ mutex_unlock(&mapping->host->i_mutex);
+ err = filemap_fdatawait(mapping);
+ if (!ret)
+ ret = err;
+out:
+ return ret;
+}
+
+static long __do_fsync(unsigned int fd, int datasync)
+{
+ struct file *file;
+ int ret = -EBADF;
+
+ file = fget(fd);
+ if (file) {
+ ret = do_fsync(file, datasync);
+ fput(file);
+ }
+ return ret;
+}
+
+asmlinkage long sys_fsync(unsigned int fd)
+{
+ return __do_fsync(fd, 0);
+}
+
+asmlinkage long sys_fdatasync(unsigned int fd)
+{
+ return __do_fsync(fd, 1);
+}
+
+/*
* sys_sync_file_range() permits finely controlled syncing over a segment of
* a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is
* zero then sys_sync_file_range() will operate from offset out to EOF.
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 5f3d725d1125..3aa3434621ca 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -103,7 +103,7 @@ static int init_dir(struct inode * inode)
inode->i_fop = &sysfs_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
return 0;
}
@@ -137,7 +137,7 @@ static int create_dir(struct kobject * k, struct dentry * p,
if (!error) {
error = sysfs_create(*d, mode, init_dir);
if (!error) {
- p->d_inode->i_nlink++;
+ inc_nlink(p->d_inode);
(*d)->d_op = &sysfs_dentry_ops;
d_rehash(*d);
}
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index cf3786625bfa..298303b5a716 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -157,8 +157,8 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
if ((retval = fill_read_buffer(file->f_dentry,buffer)))
goto out;
}
- pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
- __FUNCTION__,count,*ppos,buffer->page);
+ pr_debug("%s: count = %zd, ppos = %lld, buf = %s\n",
+ __FUNCTION__, count, *ppos, buffer->page);
retval = flush_read_buffer(buffer,buf,count,ppos);
out:
up(&buffer->sem);
@@ -483,17 +483,12 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
(victim->d_parent->d_inode == dir->d_inode)) {
victim->d_inode->i_mtime = CURRENT_TIME;
fsnotify_modify(victim);
-
- /**
- * Drop reference from initial sysfs_get_dentry().
- */
- dput(victim);
res = 0;
} else
d_drop(victim);
/**
- * Drop the reference acquired from sysfs_get_dentry() above.
+ * Drop the reference acquired from lookup_one_len() above.
*/
dput(victim);
}
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index fd7cd5f843d2..e79e38d52c00 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -125,7 +125,6 @@ struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent * sd)
{
struct inode * inode = new_inode(sysfs_sb);
if (inode) {
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->a_ops = &sysfs_aops;
inode->i_mapping->backing_dev_info = &sysfs_backing_dev_info;
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 40190c489271..20551a1b8a56 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -49,7 +49,7 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
inode->i_op = &sysfs_dir_inode_operations;
inode->i_fop = &sysfs_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
} else {
pr_debug("sysfs: could not get root inode\n");
return -ENOMEM;
diff --git a/fs/sysv/file.c b/fs/sysv/file.c
index a59e303135fa..47a4b728f15b 100644
--- a/fs/sysv/file.c
+++ b/fs/sysv/file.c
@@ -21,8 +21,10 @@
*/
const struct file_operations sysv_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.fsync = sysv_sync_file,
.sendfile = generic_file_sendfile,
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c
index 9b585d1081c0..115ab0d6f4bc 100644
--- a/fs/sysv/ialloc.c
+++ b/fs/sysv/ialloc.c
@@ -170,7 +170,7 @@ struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
inode->i_uid = current->fsuid;
inode->i_ino = fs16_to_cpu(sbi, ino);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
memset(SYSV_I(inode)->i_data, 0, sizeof(SYSV_I(inode)->i_data));
SYSV_I(inode)->i_dir_start_lookup = 0;
insert_inode_hash(inode);
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c
index 58b2d22142ba..d63c5e48b050 100644
--- a/fs/sysv/inode.c
+++ b/fs/sysv/inode.c
@@ -201,7 +201,7 @@ static void sysv_read_inode(struct inode *inode)
inode->i_ctime.tv_nsec = 0;
inode->i_atime.tv_nsec = 0;
inode->i_mtime.tv_nsec = 0;
- inode->i_blocks = inode->i_blksize = 0;
+ inode->i_blocks = 0;
si = SYSV_I(inode);
for (block = 0; block < 10+1+1+1; block++)
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index b8a73f716fbe..f7c08db8e34c 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -250,7 +250,7 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
sysv_set_link(new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
inode_dec_link_count(new_inode);
} else {
if (dir_de) {
diff --git a/fs/sysv/super.c b/fs/sysv/super.c
index 876639b93321..dc9e7dc07fb7 100644
--- a/fs/sysv/super.c
+++ b/fs/sysv/super.c
@@ -358,21 +358,15 @@ static int sysv_fill_super(struct super_block *sb, void *data, int silent)
unsigned long blocknr;
int size = 0, i;
- if (1024 != sizeof (struct xenix_super_block))
- panic("Xenix FS: bad superblock size");
- if (512 != sizeof (struct sysv4_super_block))
- panic("SystemV FS: bad superblock size");
- if (512 != sizeof (struct sysv2_super_block))
- panic("SystemV FS: bad superblock size");
- if (500 != sizeof (struct coh_super_block))
- panic("Coherent FS: bad superblock size");
- if (64 != sizeof (struct sysv_inode))
- panic("sysv fs: bad inode size");
+ BUILD_BUG_ON(1024 != sizeof (struct xenix_super_block));
+ BUILD_BUG_ON(512 != sizeof (struct sysv4_super_block));
+ BUILD_BUG_ON(512 != sizeof (struct sysv2_super_block));
+ BUILD_BUG_ON(500 != sizeof (struct coh_super_block));
+ BUILD_BUG_ON(64 != sizeof (struct sysv_inode));
- sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
- memset(sbi, 0, sizeof(struct sysv_sb_info));
sbi->s_sb = sb;
sbi->s_block_base = 0;
@@ -453,10 +447,9 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent)
if (64 != sizeof (struct sysv_inode))
panic("sysv fs: bad i-node size");
- sbi = kmalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct sysv_sb_info), GFP_KERNEL);
if (!sbi)
return -ENOMEM;
- memset(sbi, 0, sizeof(struct sysv_sb_info));
sbi->s_sb = sb;
sbi->s_block_base = 0;
diff --git a/fs/udf/file.c b/fs/udf/file.c
index a59e5f33daf6..7aedd552cba1 100644
--- a/fs/udf/file.c
+++ b/fs/udf/file.c
@@ -103,19 +103,21 @@ const struct address_space_operations udf_adinicb_aops = {
.commit_write = udf_adinicb_commit_write,
};
-static ssize_t udf_file_write(struct file * file, const char __user * buf,
- size_t count, loff_t *ppos)
+static ssize_t udf_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t ppos)
{
ssize_t retval;
+ struct file *file = iocb->ki_filp;
struct inode *inode = file->f_dentry->d_inode;
int err, pos;
+ size_t count = iocb->ki_left;
if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB)
{
if (file->f_flags & O_APPEND)
pos = inode->i_size;
else
- pos = *ppos;
+ pos = ppos;
if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) +
pos + count))
@@ -136,7 +138,7 @@ static ssize_t udf_file_write(struct file * file, const char __user * buf,
}
}
- retval = generic_file_write(file, buf, count, ppos);
+ retval = generic_file_aio_write(iocb, iov, nr_segs, ppos);
if (retval > 0)
mark_inode_dirty(inode);
@@ -249,11 +251,13 @@ static int udf_release_file(struct inode * inode, struct file * filp)
}
const struct file_operations udf_file_operations = {
- .read = generic_file_read,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
.ioctl = udf_ioctl,
.open = generic_file_open,
.mmap = generic_file_mmap,
- .write = udf_file_write,
+ .write = do_sync_write,
+ .aio_write = udf_file_aio_write,
.release = udf_release_file,
.fsync = udf_fsync_file,
.sendfile = generic_file_sendfile,
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 33323473e3c4..8206983f2ebf 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -121,7 +121,6 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
UDF_I_LOCATION(inode).logicalBlockNum = block;
UDF_I_LOCATION(inode).partitionReferenceNum = UDF_I_LOCATION(dir).partitionReferenceNum;
inode->i_ino = udf_get_lb_pblock(sb, UDF_I_LOCATION(inode), 0);
- inode->i_blksize = PAGE_SIZE;
inode->i_blocks = 0;
UDF_I_LENEATTR(inode) = 0;
UDF_I_LENALLOC(inode) = 0;
@@ -130,14 +129,12 @@ struct inode * udf_new_inode (struct inode *dir, int mode, int * err)
{
UDF_I_EFE(inode) = 1;
UDF_UPDATE_UDFREV(inode->i_sb, UDF_VERS_USE_EXTENDED_FE);
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
- memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry));
+ UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct extendedFileEntry), GFP_KERNEL);
}
else
{
UDF_I_EFE(inode) = 0;
- UDF_I_DATA(inode) = kmalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
- memset(UDF_I_DATA(inode), 0x00, inode->i_sb->s_blocksize - sizeof(struct fileEntry));
+ UDF_I_DATA(inode) = kzalloc(inode->i_sb->s_blocksize - sizeof(struct fileEntry), GFP_KERNEL);
}
if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_AD_IN_ICB))
UDF_I_ALLOCTYPE(inode) = ICBTAG_FLAG_AD_IN_ICB;
diff --git a/fs/udf/inode.c b/fs/udf/inode.c
index 605f5111b6d8..ae21a0e59e95 100644
--- a/fs/udf/inode.c
+++ b/fs/udf/inode.c
@@ -916,8 +916,6 @@ __udf_read_inode(struct inode *inode)
* i_nlink = 1
* i_op = NULL;
*/
- inode->i_blksize = PAGE_SIZE;
-
bh = udf_read_ptagged(inode->i_sb, UDF_I_LOCATION(inode), 0, &ident);
if (!bh)
@@ -1167,7 +1165,7 @@ static void udf_fill_inode(struct inode *inode, struct buffer_head *bh)
inode->i_op = &udf_dir_inode_operations;
inode->i_fop = &udf_dir_operations;
inode->i_mode |= S_IFDIR;
- inode->i_nlink ++;
+ inc_nlink(inode);
break;
}
case ICBTAG_FILE_TYPE_REALTIME:
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index ab9a7629d23e..73163325e5ec 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -762,7 +762,7 @@ static int udf_mkdir(struct inode * dir, struct dentry * dentry, int mode)
cpu_to_le32(UDF_I_UNIQUE(inode) & 0x00000000FFFFFFFFUL);
cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
- dir->i_nlink++;
+ inc_nlink(dir);
mark_inode_dirty(dir);
d_instantiate(dentry, inode);
if (fibh.sbh != fibh.ebh)
@@ -876,10 +876,9 @@ static int udf_rmdir(struct inode * dir, struct dentry * dentry)
udf_warning(inode->i_sb, "udf_rmdir",
"empty directory has nlink != 2 (%d)",
inode->i_nlink);
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_size = 0;
- mark_inode_dirty(inode);
- dir->i_nlink --;
+ inode_dec_link_count(inode);
inode->i_ctime = dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
mark_inode_dirty(dir);
@@ -923,8 +922,7 @@ static int udf_unlink(struct inode * dir, struct dentry * dentry)
goto end_unlink;
dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
mark_inode_dirty(dir);
- inode->i_nlink--;
- mark_inode_dirty(inode);
+ inode_dec_link_count(inode);
inode->i_ctime = dir->i_ctime;
retval = 0;
@@ -1101,8 +1099,7 @@ out:
return err;
out_no_entry:
- inode->i_nlink--;
- mark_inode_dirty(inode);
+ inode_dec_link_count(inode);
iput(inode);
goto out;
}
@@ -1150,7 +1147,7 @@ static int udf_link(struct dentry * old_dentry, struct inode * dir,
if (fibh.sbh != fibh.ebh)
udf_release_data(fibh.ebh);
udf_release_data(fibh.sbh);
- inode->i_nlink ++;
+ inc_nlink(inode);
inode->i_ctime = current_fs_time(inode->i_sb);
mark_inode_dirty(inode);
atomic_inc(&inode->i_count);
@@ -1261,9 +1258,8 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
if (new_inode)
{
- new_inode->i_nlink--;
new_inode->i_ctime = current_fs_time(new_inode->i_sb);
- mark_inode_dirty(new_inode);
+ inode_dec_link_count(new_inode);
}
old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
mark_inode_dirty(old_dir);
@@ -1279,16 +1275,14 @@ static int udf_rename (struct inode * old_dir, struct dentry * old_dentry,
}
else
mark_buffer_dirty_inode(dir_bh, old_inode);
- old_dir->i_nlink --;
- mark_inode_dirty(old_dir);
+ inode_dec_link_count(old_dir);
if (new_inode)
{
- new_inode->i_nlink --;
- mark_inode_dirty(new_inode);
+ inode_dec_link_count(new_inode);
}
else
{
- new_dir->i_nlink ++;
+ inc_nlink(new_dir);
mark_inode_dirty(new_dir);
}
}
diff --git a/fs/udf/super.c b/fs/udf/super.c
index fcce1a21a51b..1aea6a4f9a4a 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -156,8 +156,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(udf_inode_cachep))
- printk(KERN_INFO "udf_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(udf_inode_cachep);
}
/* Superblock operations */
@@ -1622,6 +1621,11 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
goto error_out;
}
+ if (UDF_SB_PARTFLAGS(sb, UDF_SB_PARTITION(sb)) & UDF_PART_FLAG_READ_ONLY) {
+ printk("UDF-fs: Partition marked readonly; forcing readonly mount\n");
+ sb->s_flags |= MS_RDONLY;
+ }
+
if ( udf_find_fileset(sb, &fileset, &rootdir) )
{
printk("UDF-fs: No fileset found\n");
diff --git a/fs/ufs/file.c b/fs/ufs/file.c
index a9c6e5f04fae..1e096323bad4 100644
--- a/fs/ufs/file.c
+++ b/fs/ufs/file.c
@@ -53,8 +53,10 @@ static int ufs_sync_file(struct file *file, struct dentry *dentry, int datasync)
const struct file_operations ufs_file_operations = {
.llseek = generic_file_llseek,
- .read = generic_file_read,
- .write = generic_file_write,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .write = do_sync_write,
+ .aio_write = generic_file_aio_write,
.mmap = generic_file_mmap,
.open = generic_file_open,
.fsync = ufs_sync_file,
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c
index 9501dcd3b213..2ad1259c6eca 100644
--- a/fs/ufs/ialloc.c
+++ b/fs/ufs/ialloc.c
@@ -255,7 +255,6 @@ cg_found:
inode->i_gid = current->fsgid;
inode->i_ino = cg * uspi->s_ipg + bit;
- inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
ufsi->i_flags = UFS_I(dir)->i_flags;
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index 30c6e8a9446c..ee1eaa6f4ec2 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -741,7 +741,6 @@ void ufs_read_inode(struct inode * inode)
ufs1_read_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino));
}
- inode->i_blksize = PAGE_SIZE;/*This is the optimal IO size (for stat)*/
inode->i_version++;
ufsi->i_lastfrag =
(inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index d344b411e261..e84c0ecf0730 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -308,7 +308,7 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
ufs_set_link(new_dir, new_de, new_page, old_inode);
new_inode->i_ctime = CURRENT_TIME_SEC;
if (dir_de)
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
inode_dec_link_count(new_inode);
} else {
if (dir_de) {
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index 992ee0b87cc3..ec79e3091d1b 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -611,11 +611,10 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)
UFSD("ENTER\n");
- sbi = kmalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
+ sbi = kzalloc(sizeof(struct ufs_sb_info), GFP_KERNEL);
if (!sbi)
goto failed_nomem;
sb->s_fs_info = sbi;
- memset(sbi, 0, sizeof(struct ufs_sb_info));
UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY));
@@ -1245,8 +1244,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(ufs_inode_cachep))
- printk(KERN_INFO "ufs_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(ufs_inode_cachep);
}
#ifdef CONFIG_QUOTA
diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index 22f820a9b15c..17437574f79c 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -184,14 +184,13 @@ void _ubh_memcpyubh_(struct ufs_sb_private_info * uspi,
dev_t
ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi)
{
- __fs32 fs32;
+ __u32 fs32;
dev_t dev;
if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
- fs32 = ufsi->i_u1.i_data[1];
+ fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[1]);
else
- fs32 = ufsi->i_u1.i_data[0];
- fs32 = fs32_to_cpu(sb, fs32);
+ fs32 = fs32_to_cpu(sb, ufsi->i_u1.i_data[0]);
switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
case UFS_ST_SUNx86:
case UFS_ST_SUN:
@@ -212,7 +211,7 @@ ufs_get_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi)
void
ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev)
{
- __fs32 fs32;
+ __u32 fs32;
switch (UFS_SB(sb)->s_flags & UFS_ST_MASK) {
case UFS_ST_SUNx86:
@@ -227,11 +226,10 @@ ufs_set_inode_dev(struct super_block *sb, struct ufs_inode_info *ufsi, dev_t dev
fs32 = old_encode_dev(dev);
break;
}
- fs32 = cpu_to_fs32(sb, fs32);
if ((UFS_SB(sb)->s_flags & UFS_ST_MASK) == UFS_ST_SUNx86)
- ufsi->i_u1.i_data[1] = fs32;
+ ufsi->i_u1.i_data[1] = cpu_to_fs32(sb, fs32);
else
- ufsi->i_u1.i_data[0] = fs32;
+ ufsi->i_u1.i_data[0] = cpu_to_fs32(sb, fs32);
}
/**
diff --git a/fs/utimes.c b/fs/utimes.c
new file mode 100644
index 000000000000..1bcd852fc4a9
--- /dev/null
+++ b/fs/utimes.c
@@ -0,0 +1,137 @@
+#include <linux/compiler.h>
+#include <linux/fs.h>
+#include <linux/linkage.h>
+#include <linux/namei.h>
+#include <linux/utime.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+
+#ifdef __ARCH_WANT_SYS_UTIME
+
+/*
+ * sys_utime() can be implemented in user-level using sys_utimes().
+ * Is this for backwards compatibility? If so, why not move it
+ * into the appropriate arch directory (for those architectures that
+ * need it).
+ */
+
+/* If times==NULL, set access and modification to current time,
+ * must be owner or have write permission.
+ * Else, update from *times, must be owner or super user.
+ */
+asmlinkage long sys_utime(char __user * filename, struct utimbuf __user * times)
+{
+ int error;
+ struct nameidata nd;
+ struct inode * inode;
+ struct iattr newattrs;
+
+ error = user_path_walk(filename, &nd);
+ if (error)
+ goto out;
+ inode = nd.dentry->d_inode;
+
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto dput_and_out;
+
+ /* Don't worry, the checks are done in inode_change_ok() */
+ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
+ if (times) {
+ error = -EPERM;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ goto dput_and_out;
+
+ error = get_user(newattrs.ia_atime.tv_sec, &times->actime);
+ newattrs.ia_atime.tv_nsec = 0;
+ if (!error)
+ error = get_user(newattrs.ia_mtime.tv_sec, &times->modtime);
+ newattrs.ia_mtime.tv_nsec = 0;
+ if (error)
+ goto dput_and_out;
+
+ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+ } else {
+ error = -EACCES;
+ if (IS_IMMUTABLE(inode))
+ goto dput_and_out;
+
+ if (current->fsuid != inode->i_uid &&
+ (error = vfs_permission(&nd, MAY_WRITE)) != 0)
+ goto dput_and_out;
+ }
+ mutex_lock(&inode->i_mutex);
+ error = notify_change(nd.dentry, &newattrs);
+ mutex_unlock(&inode->i_mutex);
+dput_and_out:
+ path_release(&nd);
+out:
+ return error;
+}
+
+#endif
+
+/* If times==NULL, set access and modification to current time,
+ * must be owner or have write permission.
+ * Else, update from *times, must be owner or super user.
+ */
+long do_utimes(int dfd, char __user *filename, struct timeval *times)
+{
+ int error;
+ struct nameidata nd;
+ struct inode * inode;
+ struct iattr newattrs;
+
+ error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
+
+ if (error)
+ goto out;
+ inode = nd.dentry->d_inode;
+
+ error = -EROFS;
+ if (IS_RDONLY(inode))
+ goto dput_and_out;
+
+ /* Don't worry, the checks are done in inode_change_ok() */
+ newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
+ if (times) {
+ error = -EPERM;
+ if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
+ goto dput_and_out;
+
+ newattrs.ia_atime.tv_sec = times[0].tv_sec;
+ newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
+ newattrs.ia_mtime.tv_sec = times[1].tv_sec;
+ newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
+ newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
+ } else {
+ error = -EACCES;
+ if (IS_IMMUTABLE(inode))
+ goto dput_and_out;
+
+ if (current->fsuid != inode->i_uid &&
+ (error = vfs_permission(&nd, MAY_WRITE)) != 0)
+ goto dput_and_out;
+ }
+ mutex_lock(&inode->i_mutex);
+ error = notify_change(nd.dentry, &newattrs);
+ mutex_unlock(&inode->i_mutex);
+dput_and_out:
+ path_release(&nd);
+out:
+ return error;
+}
+
+asmlinkage long sys_futimesat(int dfd, char __user *filename, struct timeval __user *utimes)
+{
+ struct timeval times[2];
+
+ if (utimes && copy_from_user(&times, utimes, sizeof(times)))
+ return -EFAULT;
+ return do_utimes(dfd, filename, utimes ? times : NULL);
+}
+
+asmlinkage long sys_utimes(char __user *filename, struct timeval __user *utimes)
+{
+ return sys_futimesat(AT_FDCWD, filename, utimes);
+}
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c
index 9a8f48bae956..edb711ff7b05 100644
--- a/fs/vfat/namei.c
+++ b/fs/vfat/namei.c
@@ -782,9 +782,9 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
- dir->i_nlink--;
+ drop_nlink(dir);
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
out:
@@ -808,7 +808,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)
err = fat_remove_entries(dir, &sinfo); /* and releases bh */
if (err)
goto out;
- inode->i_nlink = 0;
+ clear_nlink(inode);
inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
fat_detach(inode);
out:
@@ -837,7 +837,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (err)
goto out_free;
dir->i_version++;
- dir->i_nlink++;
+ inc_nlink(dir);
inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos);
brelse(sinfo.bh);
@@ -930,9 +930,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
if (err)
goto error_dotdot;
}
- old_dir->i_nlink--;
+ drop_nlink(old_dir);
if (!new_inode)
- new_dir->i_nlink++;
+ inc_nlink(new_dir);
}
err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */
@@ -947,10 +947,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
mark_inode_dirty(old_dir);
if (new_inode) {
+ drop_nlink(new_inode);
if (is_dir)
- new_inode->i_nlink -= 2;
- else
- new_inode->i_nlink--;
+ drop_nlink(new_inode);
new_inode->i_ctime = ts;
}
out:
diff --git a/fs/xattr.c b/fs/xattr.c
index c32f15b5f60f..395635100f77 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -135,6 +135,26 @@ vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
}
EXPORT_SYMBOL_GPL(vfs_getxattr);
+ssize_t
+vfs_listxattr(struct dentry *d, char *list, size_t size)
+{
+ ssize_t error;
+
+ error = security_inode_listxattr(d);
+ if (error)
+ return error;
+ error = -EOPNOTSUPP;
+ if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
+ error = d->d_inode->i_op->listxattr(d, list, size);
+ } else {
+ error = security_inode_listsecurity(d->d_inode, list, size);
+ if (size && error > size)
+ error = -ERANGE;
+ }
+ return error;
+}
+EXPORT_SYMBOL_GPL(vfs_listxattr);
+
int
vfs_removexattr(struct dentry *dentry, char *name)
{
@@ -346,17 +366,7 @@ listxattr(struct dentry *d, char __user *list, size_t size)
return -ENOMEM;
}
- error = security_inode_listxattr(d);
- if (error)
- goto out;
- error = -EOPNOTSUPP;
- if (d->d_inode->i_op && d->d_inode->i_op->listxattr) {
- error = d->d_inode->i_op->listxattr(d, klist, size);
- } else {
- error = security_inode_listsecurity(d->d_inode, klist, size);
- if (size && error > size)
- error = -ERANGE;
- }
+ error = vfs_listxattr(d, klist, size);
if (error > 0) {
if (size && copy_to_user(list, klist, error))
error = -EFAULT;
@@ -365,7 +375,6 @@ listxattr(struct dentry *d, char __user *list, size_t size)
than XATTR_LIST_MAX bytes. Not possible. */
error = -E2BIG;
}
-out:
kfree(klist);
return error;
}
diff --git a/fs/xfs/Kconfig b/fs/xfs/Kconfig
index 26b364c9d62c..35115bca036e 100644
--- a/fs/xfs/Kconfig
+++ b/fs/xfs/Kconfig
@@ -1,5 +1,6 @@
config XFS_FS
tristate "XFS filesystem support"
+ depends on BLOCK
help
XFS is a high performance journaling filesystem which originated
on the SGI IRIX platform. It is completely multi-threaded, can
diff --git a/fs/xfs/Makefile-linux-2.6 b/fs/xfs/Makefile-linux-2.6
index 9e7f85986d0d..291948d5085a 100644
--- a/fs/xfs/Makefile-linux-2.6
+++ b/fs/xfs/Makefile-linux-2.6
@@ -30,7 +30,6 @@ ifeq ($(CONFIG_XFS_TRACE),y)
EXTRA_CFLAGS += -DXFS_BLI_TRACE
EXTRA_CFLAGS += -DXFS_BMAP_TRACE
EXTRA_CFLAGS += -DXFS_BMBT_TRACE
- EXTRA_CFLAGS += -DXFS_DIR_TRACE
EXTRA_CFLAGS += -DXFS_DIR2_TRACE
EXTRA_CFLAGS += -DXFS_DQUOT_TRACE
EXTRA_CFLAGS += -DXFS_ILOCK_TRACE
diff --git a/fs/xfs/linux-2.6/kmem.c b/fs/xfs/linux-2.6/kmem.c
index aba7fcf881a2..004baf600611 100644
--- a/fs/xfs/linux-2.6/kmem.c
+++ b/fs/xfs/linux-2.6/kmem.c
@@ -21,6 +21,7 @@
#include <linux/highmem.h>
#include <linux/swap.h>
#include <linux/blkdev.h>
+#include <linux/backing-dev.h>
#include "time.h"
#include "kmem.h"
@@ -34,6 +35,14 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
gfp_t lflags = kmem_flags_convert(flags);
void *ptr;
+#ifdef DEBUG
+ if (unlikely(!(flags & KM_LARGE) && (size > PAGE_SIZE))) {
+ printk(KERN_WARNING "Large %s attempt, size=%ld\n",
+ __FUNCTION__, (long)size);
+ dump_stack();
+ }
+#endif
+
do {
if (size < MAX_SLAB_SIZE || retries > MAX_VMALLOCS)
ptr = kmalloc(size, lflags);
@@ -45,7 +54,7 @@ kmem_alloc(size_t size, unsigned int __nocast flags)
printk(KERN_ERR "XFS: possible memory allocation "
"deadlock in %s (mode:0x%x)\n",
__FUNCTION__, lflags);
- blk_congestion_wait(WRITE, HZ/50);
+ congestion_wait(WRITE, HZ/50);
} while (1);
}
@@ -60,6 +69,27 @@ kmem_zalloc(size_t size, unsigned int __nocast flags)
return ptr;
}
+void *
+kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize,
+ unsigned int __nocast flags)
+{
+ void *ptr;
+ size_t kmsize = maxsize;
+ unsigned int kmflags = (flags & ~KM_SLEEP) | KM_NOSLEEP;
+
+ while (!(ptr = kmem_zalloc(kmsize, kmflags))) {
+ if ((kmsize <= minsize) && (flags & KM_NOSLEEP))
+ break;
+ if ((kmsize >>= 1) <= minsize) {
+ kmsize = minsize;
+ kmflags = flags;
+ }
+ }
+ if (ptr)
+ *size = kmsize;
+ return ptr;
+}
+
void
kmem_free(void *ptr, size_t size)
{
@@ -102,7 +132,7 @@ kmem_zone_alloc(kmem_zone_t *zone, unsigned int __nocast flags)
printk(KERN_ERR "XFS: possible memory allocation "
"deadlock in %s (mode:0x%x)\n",
__FUNCTION__, lflags);
- blk_congestion_wait(WRITE, HZ/50);
+ congestion_wait(WRITE, HZ/50);
} while (1);
}
diff --git a/fs/xfs/linux-2.6/kmem.h b/fs/xfs/linux-2.6/kmem.h
index 939bd84bc7ee..9ebabdf7829c 100644
--- a/fs/xfs/linux-2.6/kmem.h
+++ b/fs/xfs/linux-2.6/kmem.h
@@ -30,6 +30,7 @@
#define KM_NOSLEEP 0x0002u
#define KM_NOFS 0x0004u
#define KM_MAYFAIL 0x0008u
+#define KM_LARGE 0x0010u
/*
* We use a special process flag to avoid recursive callbacks into
@@ -41,7 +42,7 @@ kmem_flags_convert(unsigned int __nocast flags)
{
gfp_t lflags;
- BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL));
+ BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL|KM_LARGE));
if (flags & KM_NOSLEEP) {
lflags = GFP_ATOMIC | __GFP_NOWARN;
@@ -54,8 +55,9 @@ kmem_flags_convert(unsigned int __nocast flags)
}
extern void *kmem_alloc(size_t, unsigned int __nocast);
-extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast);
extern void *kmem_zalloc(size_t, unsigned int __nocast);
+extern void *kmem_zalloc_greedy(size_t *, size_t, size_t, unsigned int __nocast);
+extern void *kmem_realloc(void *, size_t, size_t, unsigned int __nocast);
extern void kmem_free(void *, size_t);
/*
@@ -91,8 +93,8 @@ kmem_zone_free(kmem_zone_t *zone, void *ptr)
static inline void
kmem_zone_destroy(kmem_zone_t *zone)
{
- if (zone && kmem_cache_destroy(zone))
- BUG();
+ if (zone)
+ kmem_cache_destroy(zone);
}
extern void *kmem_zone_alloc(kmem_zone_t *, unsigned int __nocast);
diff --git a/fs/xfs/linux-2.6/sema.h b/fs/xfs/linux-2.6/sema.h
index b25090094cca..2009e6d922ce 100644
--- a/fs/xfs/linux-2.6/sema.h
+++ b/fs/xfs/linux-2.6/sema.h
@@ -29,8 +29,6 @@
typedef struct semaphore sema_t;
-#define init_sema(sp, val, c, d) sema_init(sp, val)
-#define initsema(sp, val) sema_init(sp, val)
#define initnsema(sp, val, name) sema_init(sp, val)
#define psema(sp, b) down(sp)
#define vsema(sp) up(sp)
diff --git a/fs/xfs/linux-2.6/sv.h b/fs/xfs/linux-2.6/sv.h
index 9a8ad481b008..351a8f454bd1 100644
--- a/fs/xfs/linux-2.6/sv.h
+++ b/fs/xfs/linux-2.6/sv.h
@@ -53,8 +53,6 @@ static inline void _sv_wait(sv_t *sv, spinlock_t *lock, int state,
remove_wait_queue(&sv->waiters, &wait);
}
-#define init_sv(sv,type,name,flag) \
- init_waitqueue_head(&(sv)->waiters)
#define sv_init(sv,flag,name) \
init_waitqueue_head(&(sv)->waiters)
#define sv_destroy(sv) \
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 34dcb43a7837..09360cf1e1f2 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -71,7 +71,7 @@ xfs_page_trace(
int tag,
struct inode *inode,
struct page *page,
- int mask)
+ unsigned long pgoff)
{
xfs_inode_t *ip;
bhv_vnode_t *vp = vn_from_inode(inode);
@@ -91,7 +91,7 @@ xfs_page_trace(
(void *)ip,
(void *)inode,
(void *)page,
- (void *)((unsigned long)mask),
+ (void *)pgoff,
(void *)((unsigned long)((ip->i_d.di_size >> 32) & 0xffffffff)),
(void *)((unsigned long)(ip->i_d.di_size & 0xffffffff)),
(void *)((unsigned long)((isize >> 32) & 0xffffffff)),
@@ -105,7 +105,7 @@ xfs_page_trace(
(void *)NULL);
}
#else
-#define xfs_page_trace(tag, inode, page, mask)
+#define xfs_page_trace(tag, inode, page, pgoff)
#endif
/*
@@ -1197,7 +1197,7 @@ xfs_vm_releasepage(
.nr_to_write = 1,
};
- xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, gfp_mask);
+ xfs_page_trace(XFS_RELEASEPAGE_ENTER, inode, page, 0);
if (!page_has_buffers(page))
return 0;
@@ -1356,7 +1356,6 @@ xfs_end_io_direct(
ioend->io_size = size;
xfs_finish_ioend(ioend);
} else {
- ASSERT(size >= 0);
xfs_destroy_ioend(ioend);
}
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index 2af528dcfb04..db5f5a3608ca 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000-2005 Silicon Graphics, Inc.
+ * Copyright (c) 2000-2006 Silicon Graphics, Inc.
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -30,6 +30,7 @@
#include <linux/hash.h>
#include <linux/kthread.h>
#include <linux/migrate.h>
+#include <linux/backing-dev.h>
#include "xfs_linux.h"
STATIC kmem_zone_t *xfs_buf_zone;
@@ -318,8 +319,12 @@ xfs_buf_free(
if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1))
free_address(bp->b_addr - bp->b_offset);
- for (i = 0; i < bp->b_page_count; i++)
- page_cache_release(bp->b_pages[i]);
+ for (i = 0; i < bp->b_page_count; i++) {
+ struct page *page = bp->b_pages[i];
+
+ ASSERT(!PagePrivate(page));
+ page_cache_release(page);
+ }
_xfs_buf_free_pages(bp);
} else if (bp->b_flags & _XBF_KMEM_ALLOC) {
/*
@@ -391,7 +396,7 @@ _xfs_buf_lookup_pages(
XFS_STATS_INC(xb_page_retries);
xfsbufd_wakeup(0, gfp_mask);
- blk_congestion_wait(WRITE, HZ/50);
+ congestion_wait(WRITE, HZ/50);
goto retry;
}
@@ -400,6 +405,7 @@ _xfs_buf_lookup_pages(
nbytes = min_t(size_t, size, PAGE_CACHE_SIZE - offset);
size -= nbytes;
+ ASSERT(!PagePrivate(page));
if (!PageUptodate(page)) {
page_count--;
if (blocksize >= PAGE_CACHE_SIZE) {
@@ -768,7 +774,7 @@ xfs_buf_get_noaddr(
_xfs_buf_initialize(bp, target, 0, len, 0);
try_again:
- data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL);
+ data = kmem_alloc(malloc_len, KM_SLEEP | KM_MAYFAIL | KM_LARGE);
if (unlikely(data == NULL))
goto fail_free_buf;
@@ -1117,10 +1123,10 @@ xfs_buf_bio_end_io(
do {
struct page *page = bvec->bv_page;
+ ASSERT(!PagePrivate(page));
if (unlikely(bp->b_error)) {
if (bp->b_flags & XBF_READ)
ClearPageUptodate(page);
- SetPageError(page);
} else if (blocksize >= PAGE_CACHE_SIZE) {
SetPageUptodate(page);
} else if (!PagePrivate(page) &&
@@ -1156,16 +1162,16 @@ _xfs_buf_ioapply(
total_nr_pages = bp->b_page_count;
map_i = 0;
- if (bp->b_flags & _XBF_RUN_QUEUES) {
- bp->b_flags &= ~_XBF_RUN_QUEUES;
- rw = (bp->b_flags & XBF_READ) ? READ_SYNC : WRITE_SYNC;
- } else {
- rw = (bp->b_flags & XBF_READ) ? READ : WRITE;
- }
-
if (bp->b_flags & XBF_ORDERED) {
ASSERT(!(bp->b_flags & XBF_READ));
rw = WRITE_BARRIER;
+ } else if (bp->b_flags & _XBF_RUN_QUEUES) {
+ ASSERT(!(bp->b_flags & XBF_READ_AHEAD));
+ bp->b_flags &= ~_XBF_RUN_QUEUES;
+ rw = (bp->b_flags & XBF_WRITE) ? WRITE_SYNC : READ_SYNC;
+ } else {
+ rw = (bp->b_flags & XBF_WRITE) ? WRITE :
+ (bp->b_flags & XBF_READ_AHEAD) ? READA : READ;
}
/* Special code path for reading a sub page size buffer in --
@@ -1681,6 +1687,7 @@ xfsbufd(
xfs_buf_t *bp, *n;
struct list_head *dwq = &target->bt_delwrite_queue;
spinlock_t *dwlk = &target->bt_delwrite_lock;
+ int count;
current->flags |= PF_MEMALLOC;
@@ -1696,6 +1703,7 @@ xfsbufd(
schedule_timeout_interruptible(
xfs_buf_timer_centisecs * msecs_to_jiffies(10));
+ count = 0;
age = xfs_buf_age_centisecs * msecs_to_jiffies(10);
spin_lock(dwlk);
list_for_each_entry_safe(bp, n, dwq, b_list) {
@@ -1711,9 +1719,11 @@ xfsbufd(
break;
}
- bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q);
+ bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q|
+ _XBF_RUN_QUEUES);
bp->b_flags |= XBF_WRITE;
- list_move(&bp->b_list, &tmp);
+ list_move_tail(&bp->b_list, &tmp);
+ count++;
}
}
spin_unlock(dwlk);
@@ -1724,12 +1734,12 @@ xfsbufd(
list_del_init(&bp->b_list);
xfs_buf_iostrategy(bp);
-
- blk_run_address_space(target->bt_mapping);
}
if (as_list_len > 0)
purge_addresses();
+ if (count)
+ blk_run_address_space(target->bt_mapping);
clear_bit(XBT_FORCE_FLUSH, &target->bt_flags);
} while (!kthread_should_stop());
@@ -1767,7 +1777,7 @@ xfs_flush_buftarg(
continue;
}
- list_move(&bp->b_list, &tmp);
+ list_move_tail(&bp->b_list, &tmp);
}
spin_unlock(dwlk);
@@ -1776,7 +1786,7 @@ xfs_flush_buftarg(
*/
list_for_each_entry_safe(bp, n, &tmp, b_list) {
xfs_buf_lock(bp);
- bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q);
+ bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q|_XBF_RUN_QUEUES);
bp->b_flags |= XBF_WRITE;
if (wait)
bp->b_flags &= ~XBF_ASYNC;
@@ -1786,6 +1796,9 @@ xfs_flush_buftarg(
xfs_buf_iostrategy(bp);
}
+ if (wait)
+ blk_run_address_space(target->bt_mapping);
+
/*
* Remaining list items must be flushed before returning
*/
@@ -1797,9 +1810,6 @@ xfs_flush_buftarg(
xfs_buf_relse(bp);
}
- if (wait)
- blk_run_address_space(target->bt_mapping);
-
return pincount;
}
diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h
index 7858703ed84c..9dd235cb0107 100644
--- a/fs/xfs/linux-2.6/xfs_buf.h
+++ b/fs/xfs/linux-2.6/xfs_buf.h
@@ -298,11 +298,6 @@ extern void xfs_buf_trace(xfs_buf_t *, char *, void *, void *);
#define XFS_BUF_UNWRITE(bp) ((bp)->b_flags &= ~XBF_WRITE)
#define XFS_BUF_ISWRITE(bp) ((bp)->b_flags & XBF_WRITE)
-#define XFS_BUF_ISUNINITIAL(bp) (0)
-#define XFS_BUF_UNUNINITIAL(bp) (0)
-
-#define XFS_BUF_BP_ISMAPPED(bp) (1)
-
#define XFS_BUF_IODONE_FUNC(bp) ((bp)->b_iodone)
#define XFS_BUF_SET_IODONE_FUNC(bp, func) ((bp)->b_iodone = (func))
#define XFS_BUF_CLR_IODONE_FUNC(bp) ((bp)->b_iodone = NULL)
@@ -393,8 +388,6 @@ static inline int XFS_bwrite(xfs_buf_t *bp)
return error;
}
-#define XFS_bdwrite(bp) xfs_buf_iostart(bp, XBF_DELWRI | XBF_ASYNC)
-
static inline int xfs_bdwrite(void *mp, xfs_buf_t *bp)
{
bp->b_strat = xfs_bdstrat_cb;
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c
index 3d4f6dff2113..d93d8dd1958d 100644
--- a/fs/xfs/linux-2.6/xfs_file.c
+++ b/fs/xfs/linux-2.6/xfs_file.c
@@ -49,50 +49,49 @@ static struct vm_operations_struct xfs_dmapi_file_vm_ops;
STATIC inline ssize_t
__xfs_file_read(
struct kiocb *iocb,
- char __user *buf,
+ const struct iovec *iov,
+ unsigned long nr_segs,
int ioflags,
- size_t count,
loff_t pos)
{
- struct iovec iov = {buf, count};
struct file *file = iocb->ki_filp;
bhv_vnode_t *vp = vn_from_inode(file->f_dentry->d_inode);
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
- return bhv_vop_read(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
+ return bhv_vop_read(vp, iocb, iov, nr_segs, &iocb->ki_pos,
+ ioflags, NULL);
}
STATIC ssize_t
xfs_file_aio_read(
struct kiocb *iocb,
- char __user *buf,
- size_t count,
+ const struct iovec *iov,
+ unsigned long nr_segs,
loff_t pos)
{
- return __xfs_file_read(iocb, buf, IO_ISAIO, count, pos);
+ return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO, pos);
}
STATIC ssize_t
xfs_file_aio_read_invis(
struct kiocb *iocb,
- char __user *buf,
- size_t count,
+ const struct iovec *iov,
+ unsigned long nr_segs,
loff_t pos)
{
- return __xfs_file_read(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
+ return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
}
STATIC inline ssize_t
__xfs_file_write(
- struct kiocb *iocb,
- const char __user *buf,
- int ioflags,
- size_t count,
- loff_t pos)
+ struct kiocb *iocb,
+ const struct iovec *iov,
+ unsigned long nr_segs,
+ int ioflags,
+ loff_t pos)
{
- struct iovec iov = {(void __user *)buf, count};
struct file *file = iocb->ki_filp;
struct inode *inode = file->f_mapping->host;
bhv_vnode_t *vp = vn_from_inode(inode);
@@ -100,117 +99,28 @@ __xfs_file_write(
BUG_ON(iocb->ki_pos != pos);
if (unlikely(file->f_flags & O_DIRECT))
ioflags |= IO_ISDIRECT;
- return bhv_vop_write(vp, iocb, &iov, 1, &iocb->ki_pos, ioflags, NULL);
+ return bhv_vop_write(vp, iocb, iov, nr_segs, &iocb->ki_pos,
+ ioflags, NULL);
}
STATIC ssize_t
xfs_file_aio_write(
struct kiocb *iocb,
- const char __user *buf,
- size_t count,
+ const struct iovec *iov,
+ unsigned long nr_segs,
loff_t pos)
{
- return __xfs_file_write(iocb, buf, IO_ISAIO, count, pos);
+ return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO, pos);
}
STATIC ssize_t
xfs_file_aio_write_invis(
struct kiocb *iocb,
- const char __user *buf,
- size_t count,
- loff_t pos)
-{
- return __xfs_file_write(iocb, buf, IO_ISAIO|IO_INVIS, count, pos);
-}
-
-STATIC inline ssize_t
-__xfs_file_readv(
- struct file *file,
- const struct iovec *iov,
- int ioflags,
- unsigned long nr_segs,
- loff_t *ppos)
-{
- struct inode *inode = file->f_mapping->host;
- bhv_vnode_t *vp = vn_from_inode(inode);
- struct kiocb kiocb;
- ssize_t rval;
-
- init_sync_kiocb(&kiocb, file);
- kiocb.ki_pos = *ppos;
-
- if (unlikely(file->f_flags & O_DIRECT))
- ioflags |= IO_ISDIRECT;
- rval = bhv_vop_read(vp, &kiocb, iov, nr_segs,
- &kiocb.ki_pos, ioflags, NULL);
-
- *ppos = kiocb.ki_pos;
- return rval;
-}
-
-STATIC ssize_t
-xfs_file_readv(
- struct file *file,
- const struct iovec *iov,
- unsigned long nr_segs,
- loff_t *ppos)
-{
- return __xfs_file_readv(file, iov, 0, nr_segs, ppos);
-}
-
-STATIC ssize_t
-xfs_file_readv_invis(
- struct file *file,
- const struct iovec *iov,
- unsigned long nr_segs,
- loff_t *ppos)
-{
- return __xfs_file_readv(file, iov, IO_INVIS, nr_segs, ppos);
-}
-
-STATIC inline ssize_t
-__xfs_file_writev(
- struct file *file,
- const struct iovec *iov,
- int ioflags,
- unsigned long nr_segs,
- loff_t *ppos)
-{
- struct inode *inode = file->f_mapping->host;
- bhv_vnode_t *vp = vn_from_inode(inode);
- struct kiocb kiocb;
- ssize_t rval;
-
- init_sync_kiocb(&kiocb, file);
- kiocb.ki_pos = *ppos;
- if (unlikely(file->f_flags & O_DIRECT))
- ioflags |= IO_ISDIRECT;
-
- rval = bhv_vop_write(vp, &kiocb, iov, nr_segs,
- &kiocb.ki_pos, ioflags, NULL);
-
- *ppos = kiocb.ki_pos;
- return rval;
-}
-
-STATIC ssize_t
-xfs_file_writev(
- struct file *file,
- const struct iovec *iov,
+ const struct iovec *iov,
unsigned long nr_segs,
- loff_t *ppos)
-{
- return __xfs_file_writev(file, iov, 0, nr_segs, ppos);
-}
-
-STATIC ssize_t
-xfs_file_writev_invis(
- struct file *file,
- const struct iovec *iov,
- unsigned long nr_segs,
- loff_t *ppos)
+ loff_t pos)
{
- return __xfs_file_writev(file, iov, IO_INVIS, nr_segs, ppos);
+ return __xfs_file_write(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos);
}
STATIC ssize_t
@@ -370,7 +280,7 @@ xfs_file_readdir(
/* Try fairly hard to get memory */
do {
- if ((read_buf = (caddr_t)kmalloc(rlen, GFP_KERNEL)))
+ if ((read_buf = kmalloc(rlen, GFP_KERNEL)))
break;
rlen >>= 1;
} while (rlen >= 1024);
@@ -540,8 +450,6 @@ const struct file_operations xfs_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
- .readv = xfs_file_readv,
- .writev = xfs_file_writev,
.aio_read = xfs_file_aio_read,
.aio_write = xfs_file_aio_write,
.sendfile = xfs_file_sendfile,
@@ -565,8 +473,6 @@ const struct file_operations xfs_invis_file_operations = {
.llseek = generic_file_llseek,
.read = do_sync_read,
.write = do_sync_write,
- .readv = xfs_file_readv_invis,
- .writev = xfs_file_writev_invis,
.aio_read = xfs_file_aio_read_invis,
.aio_write = xfs_file_aio_write_invis,
.sendfile = xfs_file_sendfile_invis,
diff --git a/fs/xfs/linux-2.6/xfs_globals.c b/fs/xfs/linux-2.6/xfs_globals.c
index 6c162c3dde7e..ed3a5e1b4b67 100644
--- a/fs/xfs/linux-2.6/xfs_globals.c
+++ b/fs/xfs/linux-2.6/xfs_globals.c
@@ -34,7 +34,7 @@ xfs_param_t xfs_params = {
.restrict_chown = { 0, 1, 1 },
.sgid_inherit = { 0, 0, 1 },
.symlink_mode = { 0, 0, 1 },
- .panic_mask = { 0, 0, 127 },
+ .panic_mask = { 0, 0, 255 },
.error_level = { 0, 3, 11 },
.syncd_timer = { 1*100, 30*100, 7200*100},
.stats_clear = { 0, 0, 1 },
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index 6e52a5dd38d8..a74f854d91e6 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -653,7 +653,7 @@ xfs_attrmulti_by_handle(
STATIC int
xfs_ioc_space(
bhv_desc_t *bdp,
- bhv_vnode_t *vp,
+ struct inode *inode,
struct file *filp,
int flags,
unsigned int cmd,
@@ -735,7 +735,7 @@ xfs_ioctl(
!capable(CAP_SYS_ADMIN))
return -EPERM;
- return xfs_ioc_space(bdp, vp, filp, ioflags, cmd, arg);
+ return xfs_ioc_space(bdp, inode, filp, ioflags, cmd, arg);
case XFS_IOC_DIOINFO: {
struct dioattr da;
@@ -763,6 +763,8 @@ xfs_ioctl(
return xfs_ioc_fsgeometry(mp, arg);
case XFS_IOC_GETVERSION:
+ return put_user(inode->i_generation, (int __user *)arg);
+
case XFS_IOC_GETXFLAGS:
case XFS_IOC_SETXFLAGS:
case XFS_IOC_FSGETXATTR:
@@ -957,7 +959,7 @@ xfs_ioctl(
STATIC int
xfs_ioc_space(
bhv_desc_t *bdp,
- bhv_vnode_t *vp,
+ struct inode *inode,
struct file *filp,
int ioflags,
unsigned int cmd,
@@ -967,13 +969,13 @@ xfs_ioc_space(
int attr_flags = 0;
int error;
- if (vp->v_inode.i_flags & (S_IMMUTABLE|S_APPEND))
+ if (inode->i_flags & (S_IMMUTABLE|S_APPEND))
return -XFS_ERROR(EPERM);
if (!(filp->f_mode & FMODE_WRITE))
return -XFS_ERROR(EBADF);
- if (!VN_ISREG(vp))
+ if (!S_ISREG(inode->i_mode))
return -XFS_ERROR(EINVAL);
if (copy_from_user(&bf, arg, sizeof(bf)))
@@ -1264,13 +1266,6 @@ xfs_ioc_xattr(
break;
}
- case XFS_IOC_GETVERSION: {
- flags = vn_to_inode(vp)->i_generation;
- if (copy_to_user(arg, &flags, sizeof(flags)))
- error = -EFAULT;
- break;
- }
-
default:
error = -ENOTTY;
break;
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c
index d9180020de63..3ba814ae3bba 100644
--- a/fs/xfs/linux-2.6/xfs_iops.c
+++ b/fs/xfs/linux-2.6/xfs_iops.c
@@ -553,13 +553,13 @@ xfs_vn_follow_link(
ASSERT(dentry);
ASSERT(nd);
- link = (char *)kmalloc(MAXPATHLEN+1, GFP_KERNEL);
+ link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
if (!link) {
nd_set_link(nd, ERR_PTR(-ENOMEM));
return NULL;
}
- uio = (uio_t *)kmalloc(sizeof(uio_t), GFP_KERNEL);
+ uio = kmalloc(sizeof(uio_t), GFP_KERNEL);
if (!uio) {
kfree(link);
nd_set_link(nd, ERR_PTR(-ENOMEM));
@@ -623,12 +623,27 @@ xfs_vn_getattr(
{
struct inode *inode = dentry->d_inode;
bhv_vnode_t *vp = vn_from_inode(inode);
- int error = 0;
+ bhv_vattr_t vattr = { .va_mask = XFS_AT_STAT };
+ int error;
- if (unlikely(vp->v_flag & VMODIFIED))
- error = vn_revalidate(vp);
- if (!error)
- generic_fillattr(inode, stat);
+ error = bhv_vop_getattr(vp, &vattr, ATTR_LAZY, NULL);
+ if (likely(!error)) {
+ stat->size = i_size_read(inode);
+ stat->dev = inode->i_sb->s_dev;
+ stat->rdev = (vattr.va_rdev == 0) ? 0 :
+ MKDEV(sysv_major(vattr.va_rdev) & 0x1ff,
+ sysv_minor(vattr.va_rdev));
+ stat->mode = vattr.va_mode;
+ stat->nlink = vattr.va_nlink;
+ stat->uid = vattr.va_uid;
+ stat->gid = vattr.va_gid;
+ stat->ino = vattr.va_nodeid;
+ stat->atime = vattr.va_atime;
+ stat->mtime = vattr.va_mtime;
+ stat->ctime = vattr.va_ctime;
+ stat->blocks = vattr.va_nblocks;
+ stat->blksize = vattr.va_blocksize;
+ }
return -error;
}
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h
index a13f75c1a936..2b0e0018738a 100644
--- a/fs/xfs/linux-2.6/xfs_linux.h
+++ b/fs/xfs/linux-2.6/xfs_linux.h
@@ -148,11 +148,7 @@ BUFFER_FNS(PrivateStart, unwritten);
(current->flags = ((current->flags & ~(f)) | (*(sp) & (f))))
#define NBPP PAGE_SIZE
-#define DPPSHFT (PAGE_SHIFT - 9)
#define NDPP (1 << (PAGE_SHIFT - 9))
-#define dtop(DD) (((DD) + NDPP - 1) >> DPPSHFT)
-#define dtopt(DD) ((DD) >> DPPSHFT)
-#define dpoff(DD) ((DD) & (NDPP-1))
#define NBBY 8 /* number of bits per byte */
#define NBPC PAGE_SIZE /* Number of bytes per click */
@@ -172,8 +168,6 @@ BUFFER_FNS(PrivateStart, unwritten);
#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT)
#define btoc64(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT)
#define btoct64(x) ((__uint64_t)(x)>>BPCSHIFT)
-#define io_btoc(x) (((__psunsigned_t)(x)+(IO_NBPC-1))>>IO_BPCSHIFT)
-#define io_btoct(x) ((__psunsigned_t)(x)>>IO_BPCSHIFT)
/* off_t bytes to clicks */
#define offtoc(x) (((__uint64_t)(x)+(NBPC-1))>>BPCSHIFT)
@@ -186,7 +180,6 @@ BUFFER_FNS(PrivateStart, unwritten);
#define ctob(x) ((__psunsigned_t)(x)<<BPCSHIFT)
#define btoct(x) ((__psunsigned_t)(x)>>BPCSHIFT)
#define ctob64(x) ((__uint64_t)(x)<<BPCSHIFT)
-#define io_ctob(x) ((__psunsigned_t)(x)<<IO_BPCSHIFT)
/* bytes to clicks */
#define btoc(x) (((__psunsigned_t)(x)+(NBPC-1))>>BPCSHIFT)
@@ -339,4 +332,11 @@ static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y)
return(x * y);
}
+static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y)
+{
+ x += y - 1;
+ do_div(x, y);
+ return x;
+}
+
#endif /* __XFS_LINUX__ */
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index ee788b1cb364..fa842f1c9fa2 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -270,16 +270,18 @@ xfs_read(
}
}
- if (unlikely((ioflags & IO_ISDIRECT) && VN_CACHED(vp)))
- bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
- -1, FI_REMAPF_LOCKED);
-
- if (unlikely(ioflags & IO_ISDIRECT))
+ if (unlikely(ioflags & IO_ISDIRECT)) {
+ if (VN_CACHED(vp))
+ bhv_vop_flushinval_pages(vp, ctooff(offtoct(*offset)),
+ -1, FI_REMAPF_LOCKED);
mutex_unlock(&inode->i_mutex);
+ }
xfs_rw_enter_trace(XFS_READ_ENTER, &ip->i_iocore,
(void *)iovp, segs, *offset, ioflags);
- ret = __generic_file_aio_read(iocb, iovp, segs, offset);
+
+ iocb->ki_pos = *offset;
+ ret = generic_file_aio_read(iocb, iovp, segs, *offset);
if (ret == -EIOCBQUEUED && !(ioflags & IO_ISAIO))
ret = wait_on_sync_kiocb(iocb);
if (ret > 0)
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 4754f342a5d3..38c4d128a8c0 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -171,7 +171,6 @@ xfs_revalidate_inode(
break;
}
- inode->i_blksize = xfs_preferred_iosize(mp);
inode->i_generation = ip->i_d.di_gen;
i_size_write(inode, ip->i_d.di_size);
inode->i_blocks =
@@ -228,7 +227,9 @@ xfs_initialize_vnode(
xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
xfs_set_inodeops(inode);
+ spin_lock(&ip->i_flags_lock);
ip->i_flags &= ~XFS_INEW;
+ spin_unlock(&ip->i_flags_lock);
barrier();
unlock_new_inode(inode);
diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h
index 91fc2c4b3353..da255bdf5260 100644
--- a/fs/xfs/linux-2.6/xfs_vfs.h
+++ b/fs/xfs/linux-2.6/xfs_vfs.h
@@ -79,7 +79,7 @@ typedef enum {
#define VFS_RDONLY 0x0001 /* read-only vfs */
#define VFS_GRPID 0x0002 /* group-ID assigned from directory */
#define VFS_DMI 0x0004 /* filesystem has the DMI enabled */
-#define VFS_UMOUNT 0x0008 /* unmount in progress */
+/* ---- VFS_UMOUNT ---- 0x0008 -- unneeded, fixed via kthread APIs */
#define VFS_32BITINODES 0x0010 /* do not use inums above 32 bits */
#define VFS_END 0x0010 /* max flag */
diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c
index 6628d96b6fd6..553fa731ade5 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.c
+++ b/fs/xfs/linux-2.6/xfs_vnode.c
@@ -122,7 +122,6 @@ vn_revalidate_core(
inode->i_blocks = vap->va_nblocks;
inode->i_mtime = vap->va_mtime;
inode->i_ctime = vap->va_ctime;
- inode->i_blksize = vap->va_blocksize;
if (vap->va_xflags & XFS_XFLAG_IMMUTABLE)
inode->i_flags |= S_IMMUTABLE;
else
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h
index c42b3221b20c..515f5fdea57a 100644
--- a/fs/xfs/linux-2.6/xfs_vnode.h
+++ b/fs/xfs/linux-2.6/xfs_vnode.h
@@ -85,8 +85,6 @@ typedef enum {
#define VN_BHV_HEAD(vp) ((bhv_head_t *)(&((vp)->v_bh)))
#define vn_bhv_head_init(bhp,name) bhv_head_init(bhp,name)
#define vn_bhv_remove(bhp,bdp) bhv_remove(bhp,bdp)
-#define vn_bhv_lookup(bhp,ops) bhv_lookup(bhp,ops)
-#define vn_bhv_lookup_unlocked(bhp,ops) bhv_lookup_unlocked(bhp,ops)
/*
* Vnode to Linux inode mapping.
diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c
index 5b2dcc58b244..33ad5af386e0 100644
--- a/fs/xfs/quota/xfs_dquot_item.c
+++ b/fs/xfs/quota/xfs_dquot_item.c
@@ -382,18 +382,6 @@ xfs_qm_dquot_logitem_unlock(
/*
- * The transaction with the dquot locked has aborted. The dquot
- * must not be dirty within the transaction. We simply unlock just
- * as if the transaction had been cancelled.
- */
-STATIC void
-xfs_qm_dquot_logitem_abort(
- xfs_dq_logitem_t *ql)
-{
- xfs_qm_dquot_logitem_unlock(ql);
-}
-
-/*
* this needs to stamp an lsn into the dquot, I think.
* rpc's that look at user dquot's would then have to
* push on the dependency recorded in the dquot
@@ -426,7 +414,6 @@ STATIC struct xfs_item_ops xfs_dquot_item_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_qm_dquot_logitem_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_push,
- .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_abort,
.iop_pushbuf = (void(*)(xfs_log_item_t*))
xfs_qm_dquot_logitem_pushbuf,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
@@ -559,17 +546,6 @@ xfs_qm_qoff_logitem_committed(xfs_qoff_logitem_t *qf, xfs_lsn_t lsn)
}
/*
- * The transaction of which this QUOTAOFF is a part has been aborted.
- * Just clean up after ourselves.
- * Shouldn't this never happen in the case of qoffend logitems? XXX
- */
-STATIC void
-xfs_qm_qoff_logitem_abort(xfs_qoff_logitem_t *qf)
-{
- kmem_free(qf, sizeof(xfs_qoff_logitem_t));
-}
-
-/*
* There isn't much you can do to push on an quotaoff item. It is simply
* stuck waiting for the log to be flushed to disk.
*/
@@ -644,7 +620,6 @@ STATIC struct xfs_item_ops xfs_qm_qoffend_logitem_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_qm_qoffend_logitem_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
- .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
.iop_pushbuf = NULL,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_qm_qoffend_logitem_committing
@@ -667,7 +642,6 @@ STATIC struct xfs_item_ops xfs_qm_qoff_logitem_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_qm_qoff_logitem_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_push,
- .iop_abort = (void(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_abort,
.iop_pushbuf = NULL,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_qm_qoff_logitem_committing
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index e23e45535c48..7c6a3a50379e 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -112,17 +112,17 @@ xfs_Gqm_init(void)
{
xfs_dqhash_t *udqhash, *gdqhash;
xfs_qm_t *xqm;
- uint i, hsize, flags = KM_SLEEP | KM_MAYFAIL;
+ size_t hsize;
+ uint i;
/*
* Initialize the dquot hash tables.
*/
- hsize = XFS_QM_HASHSIZE_HIGH;
- while (!(udqhash = kmem_zalloc(hsize * sizeof(xfs_dqhash_t), flags))) {
- if ((hsize >>= 1) <= XFS_QM_HASHSIZE_LOW)
- flags = KM_SLEEP;
- }
- gdqhash = kmem_zalloc(hsize * sizeof(xfs_dqhash_t), KM_SLEEP);
+ udqhash = kmem_zalloc_greedy(&hsize,
+ XFS_QM_HASHSIZE_LOW, XFS_QM_HASHSIZE_HIGH,
+ KM_SLEEP | KM_MAYFAIL | KM_LARGE);
+ gdqhash = kmem_zalloc(hsize, KM_SLEEP | KM_LARGE);
+ hsize /= sizeof(xfs_dqhash_t);
ndquot = hsize << 8;
xqm = kmem_zalloc(sizeof(xfs_qm_t), KM_SLEEP);
diff --git a/fs/xfs/quota/xfs_qm.h b/fs/xfs/quota/xfs_qm.h
index 4568deb6da86..689407de0a20 100644
--- a/fs/xfs/quota/xfs_qm.h
+++ b/fs/xfs/quota/xfs_qm.h
@@ -56,12 +56,6 @@ extern kmem_zone_t *qm_dqtrxzone;
#define XFS_QM_HASHSIZE_HIGH ((NBPP * 4) / sizeof(xfs_dqhash_t))
/*
- * We output a cmn_err when quotachecking a quota file with more than
- * this many fsbs.
- */
-#define XFS_QM_BIG_QCHECK_NBLKS 500
-
-/*
* This defines the unit of allocation of dquots.
* Currently, it is just one file system block, and a 4K blk contains 30
* (136 * 30 = 4080) dquots. It's probably not worth trying to make
diff --git a/fs/xfs/quota/xfs_quota_priv.h b/fs/xfs/quota/xfs_quota_priv.h
index b7ddd04aae32..a8b85e2be9d5 100644
--- a/fs/xfs/quota/xfs_quota_priv.h
+++ b/fs/xfs/quota/xfs_quota_priv.h
@@ -75,7 +75,6 @@ static inline int XQMISLCKD(struct xfs_dqhash *h)
#define xfs_qm_freelist_lock(qm) XQMLCK(&((qm)->qm_dqfreelist))
#define xfs_qm_freelist_unlock(qm) XQMUNLCK(&((qm)->qm_dqfreelist))
-#define XFS_QM_IS_FREELIST_LOCKED(qm) XQMISLCKD(&((qm)->qm_dqfreelist))
/*
* Hash into a bucket in the dquot hash table, based on <mp, id>.
@@ -170,6 +169,5 @@ for ((dqp) = (qlist)->qh_next; (dqp) != (xfs_dquot_t *)(qlist); \
#define DQFLAGTO_TYPESTR(d) (((d)->dq_flags & XFS_DQ_USER) ? "USR" : \
(((d)->dq_flags & XFS_DQ_GROUP) ? "GRP" : \
(((d)->dq_flags & XFS_DQ_PROJ) ? "PRJ":"???")))
-#define DQFLAGTO_DIRTYSTR(d) (XFS_DQ_IS_DIRTY(d) ? "DIRTY" : "NOTDIRTY")
#endif /* __XFS_QUOTA_PRIV_H__ */
diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c
index 36fbeccdc722..c75f68361e33 100644
--- a/fs/xfs/support/debug.c
+++ b/fs/xfs/support/debug.c
@@ -53,8 +53,7 @@ cmn_err(register int level, char *fmt, ...)
va_end(ap);
spin_unlock_irqrestore(&xfs_err_lock,flags);
- if (level == CE_PANIC)
- BUG();
+ BUG_ON(level == CE_PANIC);
}
void
@@ -72,8 +71,7 @@ icmn_err(register int level, char *fmt, va_list ap)
strcat(message, "\n");
spin_unlock_irqrestore(&xfs_err_lock,flags);
printk("%s%s", err_level[level], message);
- if (level == CE_PANIC)
- BUG();
+ BUG_ON(level == CE_PANIC);
}
void
diff --git a/fs/xfs/support/ktrace.c b/fs/xfs/support/ktrace.c
index addf5a7ea06c..5cf2e86caa71 100644
--- a/fs/xfs/support/ktrace.c
+++ b/fs/xfs/support/ktrace.c
@@ -75,7 +75,7 @@ ktrace_alloc(int nentries, unsigned int __nocast sleep)
sleep);
} else {
ktep = (ktrace_entry_t*)kmem_zalloc((nentries * sizeof(*ktep)),
- sleep);
+ sleep | KM_LARGE);
}
if (ktep == NULL) {
diff --git a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
index dc2361dd740a..9ece7f87ec5b 100644
--- a/fs/xfs/xfs_ag.h
+++ b/fs/xfs/xfs_ag.h
@@ -150,7 +150,7 @@ typedef struct xfs_agi {
#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)XFS_BUF_PTR(bp))
typedef struct xfs_agfl {
- xfs_agblock_t agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
+ __be32 agfl_bno[1]; /* actually XFS_AGFL_SIZE(mp) */
} xfs_agfl_t;
/*
diff --git a/fs/xfs/xfs_alloc.c b/fs/xfs/xfs_alloc.c
index d2bbcd882a69..e80dda3437d1 100644
--- a/fs/xfs/xfs_alloc.c
+++ b/fs/xfs/xfs_alloc.c
@@ -1477,8 +1477,10 @@ xfs_alloc_ag_vextent_small(
/*
* Can't allocate from the freelist for some reason.
*/
- else
+ else {
+ fbno = NULLAGBLOCK;
flen = 0;
+ }
/*
* Can't do the allocation, give up.
*/
@@ -2021,7 +2023,7 @@ xfs_alloc_get_freelist(
/*
* Get the block number and update the data structures.
*/
- bno = INT_GET(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)], ARCH_CONVERT);
+ bno = be32_to_cpu(agfl->agfl_bno[be32_to_cpu(agf->agf_flfirst)]);
be32_add(&agf->agf_flfirst, 1);
xfs_trans_brelse(tp, agflbp);
if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp))
@@ -2108,7 +2110,7 @@ xfs_alloc_put_freelist(
{
xfs_agf_t *agf; /* a.g. freespace structure */
xfs_agfl_t *agfl; /* a.g. free block array */
- xfs_agblock_t *blockp;/* pointer to array entry */
+ __be32 *blockp;/* pointer to array entry */
int error;
#ifdef XFS_ALLOC_TRACE
static char fname[] = "xfs_alloc_put_freelist";
@@ -2132,7 +2134,7 @@ xfs_alloc_put_freelist(
pag->pagf_flcount++;
ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp));
blockp = &agfl->agfl_bno[be32_to_cpu(agf->agf_fllast)];
- INT_SET(*blockp, ARCH_CONVERT, bno);
+ *blockp = cpu_to_be32(bno);
TRACE_MODAGF(NULL, agf, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
xfs_alloc_log_agf(tp, agbp, XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
xfs_trans_log_buf(tp, agflbp,
diff --git a/fs/xfs/xfs_alloc_btree.c b/fs/xfs/xfs_alloc_btree.c
index 7446556e8021..74cadf95d4e8 100644
--- a/fs/xfs/xfs_alloc_btree.c
+++ b/fs/xfs/xfs_alloc_btree.c
@@ -92,6 +92,7 @@ xfs_alloc_delrec(
xfs_alloc_key_t *rkp; /* right block key pointer */
xfs_alloc_ptr_t *rpp; /* right block address pointer */
int rrecs=0; /* number of records in right block */
+ int numrecs;
xfs_alloc_rec_t *rrp; /* right block record pointer */
xfs_btree_cur_t *tcur; /* temporary btree cursor */
@@ -115,7 +116,8 @@ xfs_alloc_delrec(
/*
* Fail if we're off the end of the block.
*/
- if (ptr > be16_to_cpu(block->bb_numrecs)) {
+ numrecs = be16_to_cpu(block->bb_numrecs);
+ if (ptr > numrecs) {
*stat = 0;
return 0;
}
@@ -129,18 +131,18 @@ xfs_alloc_delrec(
lkp = XFS_ALLOC_KEY_ADDR(block, 1, cur);
lpp = XFS_ALLOC_PTR_ADDR(block, 1, cur);
#ifdef DEBUG
- for (i = ptr; i < be16_to_cpu(block->bb_numrecs); i++) {
+ for (i = ptr; i < numrecs; i++) {
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(lpp[i]), level)))
return error;
}
#endif
- if (ptr < be16_to_cpu(block->bb_numrecs)) {
+ if (ptr < numrecs) {
memmove(&lkp[ptr - 1], &lkp[ptr],
- (be16_to_cpu(block->bb_numrecs) - ptr) * sizeof(*lkp));
+ (numrecs - ptr) * sizeof(*lkp));
memmove(&lpp[ptr - 1], &lpp[ptr],
- (be16_to_cpu(block->bb_numrecs) - ptr) * sizeof(*lpp));
- xfs_alloc_log_ptrs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs) - 1);
- xfs_alloc_log_keys(cur, bp, ptr, be16_to_cpu(block->bb_numrecs) - 1);
+ (numrecs - ptr) * sizeof(*lpp));
+ xfs_alloc_log_ptrs(cur, bp, ptr, numrecs - 1);
+ xfs_alloc_log_keys(cur, bp, ptr, numrecs - 1);
}
}
/*
@@ -149,10 +151,10 @@ xfs_alloc_delrec(
*/
else {
lrp = XFS_ALLOC_REC_ADDR(block, 1, cur);
- if (ptr < be16_to_cpu(block->bb_numrecs)) {
+ if (ptr < numrecs) {
memmove(&lrp[ptr - 1], &lrp[ptr],
- (be16_to_cpu(block->bb_numrecs) - ptr) * sizeof(*lrp));
- xfs_alloc_log_recs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs) - 1);
+ (numrecs - ptr) * sizeof(*lrp));
+ xfs_alloc_log_recs(cur, bp, ptr, numrecs - 1);
}
/*
* If it's the first record in the block, we'll need a key
@@ -167,7 +169,8 @@ xfs_alloc_delrec(
/*
* Decrement and log the number of entries in the block.
*/
- be16_add(&block->bb_numrecs, -1);
+ numrecs--;
+ block->bb_numrecs = cpu_to_be16(numrecs);
xfs_alloc_log_block(cur->bc_tp, bp, XFS_BB_NUMRECS);
/*
* See if the longest free extent in the allocation group was
@@ -181,14 +184,14 @@ xfs_alloc_delrec(
if (level == 0 &&
cur->bc_btnum == XFS_BTNUM_CNT &&
be32_to_cpu(block->bb_rightsib) == NULLAGBLOCK &&
- ptr > be16_to_cpu(block->bb_numrecs)) {
- ASSERT(ptr == be16_to_cpu(block->bb_numrecs) + 1);
+ ptr > numrecs) {
+ ASSERT(ptr == numrecs + 1);
/*
* There are still records in the block. Grab the size
* from the last one.
*/
- if (be16_to_cpu(block->bb_numrecs)) {
- rrp = XFS_ALLOC_REC_ADDR(block, be16_to_cpu(block->bb_numrecs), cur);
+ if (numrecs) {
+ rrp = XFS_ALLOC_REC_ADDR(block, numrecs, cur);
agf->agf_longest = rrp->ar_blockcount;
}
/*
@@ -211,7 +214,7 @@ xfs_alloc_delrec(
* and it's NOT the leaf level,
* then we can get rid of this level.
*/
- if (be16_to_cpu(block->bb_numrecs) == 1 && level > 0) {
+ if (numrecs == 1 && level > 0) {
/*
* lpp is still set to the first pointer in the block.
* Make it the new root of the btree.
@@ -267,7 +270,7 @@ xfs_alloc_delrec(
* If the number of records remaining in the block is at least
* the minimum, we're done.
*/
- if (be16_to_cpu(block->bb_numrecs) >= XFS_ALLOC_BLOCK_MINRECS(level, cur)) {
+ if (numrecs >= XFS_ALLOC_BLOCK_MINRECS(level, cur)) {
if (level > 0 && (error = xfs_alloc_decrement(cur, level, &i)))
return error;
*stat = 1;
@@ -419,19 +422,21 @@ xfs_alloc_delrec(
* See if we can join with the left neighbor block.
*/
if (lbno != NULLAGBLOCK &&
- lrecs + be16_to_cpu(block->bb_numrecs) <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
+ lrecs + numrecs <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
/*
* Set "right" to be the starting block,
* "left" to be the left neighbor.
*/
rbno = bno;
right = block;
+ rrecs = be16_to_cpu(right->bb_numrecs);
rbp = bp;
if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
cur->bc_private.a.agno, lbno, 0, &lbp,
XFS_ALLOC_BTREE_REF)))
return error;
left = XFS_BUF_TO_ALLOC_BLOCK(lbp);
+ lrecs = be16_to_cpu(left->bb_numrecs);
if ((error = xfs_btree_check_sblock(cur, left, level, lbp)))
return error;
}
@@ -439,20 +444,21 @@ xfs_alloc_delrec(
* If that won't work, see if we can join with the right neighbor block.
*/
else if (rbno != NULLAGBLOCK &&
- rrecs + be16_to_cpu(block->bb_numrecs) <=
- XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
+ rrecs + numrecs <= XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
/*
* Set "left" to be the starting block,
* "right" to be the right neighbor.
*/
lbno = bno;
left = block;
+ lrecs = be16_to_cpu(left->bb_numrecs);
lbp = bp;
if ((error = xfs_btree_read_bufs(mp, cur->bc_tp,
cur->bc_private.a.agno, rbno, 0, &rbp,
XFS_ALLOC_BTREE_REF)))
return error;
right = XFS_BUF_TO_ALLOC_BLOCK(rbp);
+ rrecs = be16_to_cpu(right->bb_numrecs);
if ((error = xfs_btree_check_sblock(cur, right, level, rbp)))
return error;
}
@@ -474,34 +480,28 @@ xfs_alloc_delrec(
/*
* It's a non-leaf. Move keys and pointers.
*/
- lkp = XFS_ALLOC_KEY_ADDR(left, be16_to_cpu(left->bb_numrecs) + 1, cur);
- lpp = XFS_ALLOC_PTR_ADDR(left, be16_to_cpu(left->bb_numrecs) + 1, cur);
+ lkp = XFS_ALLOC_KEY_ADDR(left, lrecs + 1, cur);
+ lpp = XFS_ALLOC_PTR_ADDR(left, lrecs + 1, cur);
rkp = XFS_ALLOC_KEY_ADDR(right, 1, cur);
rpp = XFS_ALLOC_PTR_ADDR(right, 1, cur);
#ifdef DEBUG
- for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) {
+ for (i = 0; i < rrecs; i++) {
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(rpp[i]), level)))
return error;
}
#endif
- memcpy(lkp, rkp, be16_to_cpu(right->bb_numrecs) * sizeof(*lkp));
- memcpy(lpp, rpp, be16_to_cpu(right->bb_numrecs) * sizeof(*lpp));
- xfs_alloc_log_keys(cur, lbp, be16_to_cpu(left->bb_numrecs) + 1,
- be16_to_cpu(left->bb_numrecs) +
- be16_to_cpu(right->bb_numrecs));
- xfs_alloc_log_ptrs(cur, lbp, be16_to_cpu(left->bb_numrecs) + 1,
- be16_to_cpu(left->bb_numrecs) +
- be16_to_cpu(right->bb_numrecs));
+ memcpy(lkp, rkp, rrecs * sizeof(*lkp));
+ memcpy(lpp, rpp, rrecs * sizeof(*lpp));
+ xfs_alloc_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs);
+ xfs_alloc_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs);
} else {
/*
* It's a leaf. Move records.
*/
- lrp = XFS_ALLOC_REC_ADDR(left, be16_to_cpu(left->bb_numrecs) + 1, cur);
+ lrp = XFS_ALLOC_REC_ADDR(left, lrecs + 1, cur);
rrp = XFS_ALLOC_REC_ADDR(right, 1, cur);
- memcpy(lrp, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*lrp));
- xfs_alloc_log_recs(cur, lbp, be16_to_cpu(left->bb_numrecs) + 1,
- be16_to_cpu(left->bb_numrecs) +
- be16_to_cpu(right->bb_numrecs));
+ memcpy(lrp, rrp, rrecs * sizeof(*lrp));
+ xfs_alloc_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs);
}
/*
* If we joined with the left neighbor, set the buffer in the
@@ -509,7 +509,7 @@ xfs_alloc_delrec(
*/
if (bp != lbp) {
xfs_btree_setbuf(cur, level, lbp);
- cur->bc_ptrs[level] += be16_to_cpu(left->bb_numrecs);
+ cur->bc_ptrs[level] += lrecs;
}
/*
* If we joined with the right neighbor and there's a level above
@@ -521,7 +521,8 @@ xfs_alloc_delrec(
/*
* Fix up the number of records in the surviving block.
*/
- be16_add(&left->bb_numrecs, be16_to_cpu(right->bb_numrecs));
+ lrecs += rrecs;
+ left->bb_numrecs = cpu_to_be16(lrecs);
/*
* Fix up the right block pointer in the surviving block, and log it.
*/
@@ -608,6 +609,7 @@ xfs_alloc_insrec(
xfs_btree_cur_t *ncur; /* new cursor to be used at next lvl */
xfs_alloc_key_t nkey; /* new key value, from split */
xfs_alloc_rec_t nrec; /* new record value, for caller */
+ int numrecs;
int optr; /* old ptr value */
xfs_alloc_ptr_t *pp; /* pointer to btree addresses */
int ptr; /* index in btree block for this rec */
@@ -653,13 +655,14 @@ xfs_alloc_insrec(
*/
bp = cur->bc_bufs[level];
block = XFS_BUF_TO_ALLOC_BLOCK(bp);
+ numrecs = be16_to_cpu(block->bb_numrecs);
#ifdef DEBUG
if ((error = xfs_btree_check_sblock(cur, block, level, bp)))
return error;
/*
* Check that the new entry is being inserted in the right place.
*/
- if (ptr <= be16_to_cpu(block->bb_numrecs)) {
+ if (ptr <= numrecs) {
if (level == 0) {
rp = XFS_ALLOC_REC_ADDR(block, ptr, cur);
xfs_btree_check_rec(cur->bc_btnum, recp, rp);
@@ -670,12 +673,12 @@ xfs_alloc_insrec(
}
#endif
nbno = NULLAGBLOCK;
- ncur = (xfs_btree_cur_t *)0;
+ ncur = NULL;
/*
* If the block is full, we can't insert the new entry until we
* make the block un-full.
*/
- if (be16_to_cpu(block->bb_numrecs) == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
+ if (numrecs == XFS_ALLOC_BLOCK_MAXRECS(level, cur)) {
/*
* First, try shifting an entry to the right neighbor.
*/
@@ -729,6 +732,7 @@ xfs_alloc_insrec(
* At this point we know there's room for our new entry in the block
* we're pointing at.
*/
+ numrecs = be16_to_cpu(block->bb_numrecs);
if (level > 0) {
/*
* It's a non-leaf entry. Make a hole for the new data
@@ -737,15 +741,15 @@ xfs_alloc_insrec(
kp = XFS_ALLOC_KEY_ADDR(block, 1, cur);
pp = XFS_ALLOC_PTR_ADDR(block, 1, cur);
#ifdef DEBUG
- for (i = be16_to_cpu(block->bb_numrecs); i >= ptr; i--) {
+ for (i = numrecs; i >= ptr; i--) {
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(pp[i - 1]), level)))
return error;
}
#endif
memmove(&kp[ptr], &kp[ptr - 1],
- (be16_to_cpu(block->bb_numrecs) - ptr + 1) * sizeof(*kp));
+ (numrecs - ptr + 1) * sizeof(*kp));
memmove(&pp[ptr], &pp[ptr - 1],
- (be16_to_cpu(block->bb_numrecs) - ptr + 1) * sizeof(*pp));
+ (numrecs - ptr + 1) * sizeof(*pp));
#ifdef DEBUG
if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
return error;
@@ -755,11 +759,12 @@ xfs_alloc_insrec(
*/
kp[ptr - 1] = key;
pp[ptr - 1] = cpu_to_be32(*bnop);
- be16_add(&block->bb_numrecs, 1);
- xfs_alloc_log_keys(cur, bp, ptr, be16_to_cpu(block->bb_numrecs));
- xfs_alloc_log_ptrs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs));
+ numrecs++;
+ block->bb_numrecs = cpu_to_be16(numrecs);
+ xfs_alloc_log_keys(cur, bp, ptr, numrecs);
+ xfs_alloc_log_ptrs(cur, bp, ptr, numrecs);
#ifdef DEBUG
- if (ptr < be16_to_cpu(block->bb_numrecs))
+ if (ptr < numrecs)
xfs_btree_check_key(cur->bc_btnum, kp + ptr - 1,
kp + ptr);
#endif
@@ -769,16 +774,17 @@ xfs_alloc_insrec(
*/
rp = XFS_ALLOC_REC_ADDR(block, 1, cur);
memmove(&rp[ptr], &rp[ptr - 1],
- (be16_to_cpu(block->bb_numrecs) - ptr + 1) * sizeof(*rp));
+ (numrecs - ptr + 1) * sizeof(*rp));
/*
* Now stuff the new record in, bump numrecs
* and log the new data.
*/
- rp[ptr - 1] = *recp; /* INT_: struct copy */
- be16_add(&block->bb_numrecs, 1);
- xfs_alloc_log_recs(cur, bp, ptr, be16_to_cpu(block->bb_numrecs));
+ rp[ptr - 1] = *recp;
+ numrecs++;
+ block->bb_numrecs = cpu_to_be16(numrecs);
+ xfs_alloc_log_recs(cur, bp, ptr, numrecs);
#ifdef DEBUG
- if (ptr < be16_to_cpu(block->bb_numrecs))
+ if (ptr < numrecs)
xfs_btree_check_rec(cur->bc_btnum, rp + ptr - 1,
rp + ptr);
#endif
@@ -819,8 +825,8 @@ xfs_alloc_insrec(
*/
*bnop = nbno;
if (nbno != NULLAGBLOCK) {
- *recp = nrec; /* INT_: struct copy */
- *curp = ncur; /* INT_: struct copy */
+ *recp = nrec;
+ *curp = ncur;
}
*stat = 1;
return 0;
@@ -981,7 +987,7 @@ xfs_alloc_lookup(
*/
bp = cur->bc_bufs[level];
if (bp && XFS_BUF_ADDR(bp) != d)
- bp = (xfs_buf_t *)0;
+ bp = NULL;
if (!bp) {
/*
* Need to get a new buffer. Read it, then
@@ -1229,7 +1235,7 @@ xfs_alloc_lshift(
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*rpp), level)))
return error;
#endif
- *lpp = *rpp; /* INT_: copy */
+ *lpp = *rpp;
xfs_alloc_log_ptrs(cur, lbp, nrec, nrec);
xfs_btree_check_key(cur->bc_btnum, lkp - 1, lkp);
}
@@ -1406,8 +1412,8 @@ xfs_alloc_newroot(
kp = XFS_ALLOC_KEY_ADDR(new, 1, cur);
if (be16_to_cpu(left->bb_level) > 0) {
- kp[0] = *XFS_ALLOC_KEY_ADDR(left, 1, cur); /* INT_: structure copy */
- kp[1] = *XFS_ALLOC_KEY_ADDR(right, 1, cur);/* INT_: structure copy */
+ kp[0] = *XFS_ALLOC_KEY_ADDR(left, 1, cur);
+ kp[1] = *XFS_ALLOC_KEY_ADDR(right, 1, cur);
} else {
xfs_alloc_rec_t *rp; /* btree record pointer */
@@ -1527,8 +1533,8 @@ xfs_alloc_rshift(
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*lpp), level)))
return error;
#endif
- *rkp = *lkp; /* INT_: copy */
- *rpp = *lpp; /* INT_: copy */
+ *rkp = *lkp;
+ *rpp = *lpp;
xfs_alloc_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
xfs_alloc_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
xfs_btree_check_key(cur->bc_btnum, rkp, rkp + 1);
@@ -2044,7 +2050,7 @@ xfs_alloc_insert(
nbno = NULLAGBLOCK;
nrec.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock);
nrec.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount);
- ncur = (xfs_btree_cur_t *)0;
+ ncur = NULL;
pcur = cur;
/*
* Loop going up the tree, starting at the leaf level.
@@ -2076,7 +2082,7 @@ xfs_alloc_insert(
*/
if (ncur) {
pcur = ncur;
- ncur = (xfs_btree_cur_t *)0;
+ ncur = NULL;
}
} while (nbno != NULLAGBLOCK);
*stat = i;
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index 1a2101043275..9ada7bdbae52 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -91,7 +91,6 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
/*
* Routines to manipulate out-of-line attribute values.
*/
-STATIC int xfs_attr_rmtval_get(xfs_da_args_t *args);
STATIC int xfs_attr_rmtval_set(xfs_da_args_t *args);
STATIC int xfs_attr_rmtval_remove(xfs_da_args_t *args);
@@ -180,7 +179,7 @@ xfs_attr_get(bhv_desc_t *bdp, const char *name, char *value, int *valuelenp,
return(error);
}
-STATIC int
+int
xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen,
char *value, int valuelen, int flags)
{
@@ -440,7 +439,7 @@ xfs_attr_set(bhv_desc_t *bdp, const char *name, char *value, int valuelen, int f
* Generic handler routine to remove a name from an attribute list.
* Transitions attribute list from Btree to shortform as necessary.
*/
-STATIC int
+int
xfs_attr_remove_int(xfs_inode_t *dp, const char *name, int namelen, int flags)
{
xfs_da_args_t args;
@@ -591,6 +590,110 @@ xfs_attr_remove(bhv_desc_t *bdp, const char *name, int flags, struct cred *cred)
return xfs_attr_remove_int(dp, name, namelen, flags);
}
+int /* error */
+xfs_attr_list_int(xfs_attr_list_context_t *context)
+{
+ int error;
+ xfs_inode_t *dp = context->dp;
+
+ /*
+ * Decide on what work routines to call based on the inode size.
+ */
+ if (XFS_IFORK_Q(dp) == 0 ||
+ (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
+ dp->i_d.di_anextents == 0)) {
+ error = 0;
+ } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+ error = xfs_attr_shortform_list(context);
+ } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+ error = xfs_attr_leaf_list(context);
+ } else {
+ error = xfs_attr_node_list(context);
+ }
+ return error;
+}
+
+#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \
+ (((struct attrlist_ent *) 0)->a_name - (char *) 0)
+#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \
+ ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
+ & ~(sizeof(u_int32_t)-1))
+
+/*
+ * Format an attribute and copy it out to the user's buffer.
+ * Take care to check values and protect against them changing later,
+ * we may be reading them directly out of a user buffer.
+ */
+/*ARGSUSED*/
+STATIC int
+xfs_attr_put_listent(xfs_attr_list_context_t *context, attrnames_t *namesp,
+ char *name, int namelen,
+ int valuelen, char *value)
+{
+ attrlist_ent_t *aep;
+ int arraytop;
+
+ ASSERT(!(context->flags & ATTR_KERNOVAL));
+ ASSERT(context->count >= 0);
+ ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
+ ASSERT(context->firstu >= sizeof(*context->alist));
+ ASSERT(context->firstu <= context->bufsize);
+
+ arraytop = sizeof(*context->alist) +
+ context->count * sizeof(context->alist->al_offset[0]);
+ context->firstu -= ATTR_ENTSIZE(namelen);
+ if (context->firstu < arraytop) {
+ xfs_attr_trace_l_c("buffer full", context);
+ context->alist->al_more = 1;
+ context->seen_enough = 1;
+ return 1;
+ }
+
+ aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
+ aep->a_valuelen = valuelen;
+ memcpy(aep->a_name, name, namelen);
+ aep->a_name[ namelen ] = 0;
+ context->alist->al_offset[ context->count++ ] = context->firstu;
+ context->alist->al_count = context->count;
+ xfs_attr_trace_l_c("add", context);
+ return 0;
+}
+
+STATIC int
+xfs_attr_kern_list(xfs_attr_list_context_t *context, attrnames_t *namesp,
+ char *name, int namelen,
+ int valuelen, char *value)
+{
+ char *offset;
+ int arraytop;
+
+ ASSERT(context->count >= 0);
+
+ arraytop = context->count + namesp->attr_namelen + namelen + 1;
+ if (arraytop > context->firstu) {
+ context->count = -1; /* insufficient space */
+ return 1;
+ }
+ offset = (char *)context->alist + context->count;
+ strncpy(offset, namesp->attr_name, namesp->attr_namelen);
+ offset += namesp->attr_namelen;
+ strncpy(offset, name, namelen); /* real name */
+ offset += namelen;
+ *offset = '\0';
+ context->count += namesp->attr_namelen + namelen + 1;
+ return 0;
+}
+
+/*ARGSUSED*/
+STATIC int
+xfs_attr_kern_list_sizes(xfs_attr_list_context_t *context, attrnames_t *namesp,
+ char *name, int namelen,
+ int valuelen, char *value)
+{
+ context->count += namesp->attr_namelen + namelen + 1;
+ return 0;
+}
+
/*
* Generate a list of extended attribute names and optionally
* also value lengths. Positive return value follows the XFS
@@ -615,13 +718,13 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
return(XFS_ERROR(EINVAL));
if ((cursor->initted == 0) &&
(cursor->hashval || cursor->blkno || cursor->offset))
- return(XFS_ERROR(EINVAL));
+ return XFS_ERROR(EINVAL);
/*
* Check for a properly aligned buffer.
*/
if (((long)buffer) & (sizeof(int)-1))
- return(XFS_ERROR(EFAULT));
+ return XFS_ERROR(EFAULT);
if (flags & ATTR_KERNOVAL)
bufsize = 0;
@@ -634,53 +737,47 @@ xfs_attr_list(bhv_desc_t *bdp, char *buffer, int bufsize, int flags,
context.dupcnt = 0;
context.resynch = 1;
context.flags = flags;
- if (!(flags & ATTR_KERNAMELS)) {
+ context.seen_enough = 0;
+ context.alist = (attrlist_t *)buffer;
+ context.put_value = 0;
+
+ if (flags & ATTR_KERNAMELS) {
+ context.bufsize = bufsize;
+ context.firstu = context.bufsize;
+ if (flags & ATTR_KERNOVAL)
+ context.put_listent = xfs_attr_kern_list_sizes;
+ else
+ context.put_listent = xfs_attr_kern_list;
+ } else {
context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
context.firstu = context.bufsize;
- context.alist = (attrlist_t *)buffer;
context.alist->al_count = 0;
context.alist->al_more = 0;
context.alist->al_offset[0] = context.bufsize;
- }
- else {
- context.bufsize = bufsize;
- context.firstu = context.bufsize;
- context.alist = (attrlist_t *)buffer;
+ context.put_listent = xfs_attr_put_listent;
}
if (XFS_FORCED_SHUTDOWN(dp->i_mount))
- return (EIO);
+ return EIO;
xfs_ilock(dp, XFS_ILOCK_SHARED);
- /*
- * Decide on what work routines to call based on the inode size.
- */
xfs_attr_trace_l_c("syscall start", &context);
- if (XFS_IFORK_Q(dp) == 0 ||
- (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
- dp->i_d.di_anextents == 0)) {
- error = 0;
- } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
- error = xfs_attr_shortform_list(&context);
- } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
- error = xfs_attr_leaf_list(&context);
- } else {
- error = xfs_attr_node_list(&context);
- }
+
+ error = xfs_attr_list_int(&context);
+
xfs_iunlock(dp, XFS_ILOCK_SHARED);
xfs_attr_trace_l_c("syscall end", &context);
- if (!(context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS))) {
- ASSERT(error >= 0);
- }
- else { /* must return negated buffer size or the error */
+ if (context.flags & (ATTR_KERNOVAL|ATTR_KERNAMELS)) {
+ /* must return negated buffer size or the error */
if (context.count < 0)
error = XFS_ERROR(ERANGE);
else
error = -context.count;
- }
+ } else
+ ASSERT(error >= 0);
- return(error);
+ return error;
}
int /* error */
@@ -1122,19 +1219,19 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
context->cursor->blkno = 0;
error = xfs_da_read_buf(NULL, context->dp, 0, -1, &bp, XFS_ATTR_FORK);
if (error)
- return(error);
+ return XFS_ERROR(error);
ASSERT(bp != NULL);
leaf = bp->data;
if (unlikely(be16_to_cpu(leaf->hdr.info.magic) != XFS_ATTR_LEAF_MAGIC)) {
XFS_CORRUPTION_ERROR("xfs_attr_leaf_list", XFS_ERRLEVEL_LOW,
context->dp->i_mount, leaf);
xfs_da_brelse(NULL, bp);
- return(XFS_ERROR(EFSCORRUPTED));
+ return XFS_ERROR(EFSCORRUPTED);
}
- (void)xfs_attr_leaf_list_int(bp, context);
+ error = xfs_attr_leaf_list_int(bp, context);
xfs_da_brelse(NULL, bp);
- return(0);
+ return XFS_ERROR(error);
}
@@ -1858,8 +1955,12 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
return(XFS_ERROR(EFSCORRUPTED));
}
error = xfs_attr_leaf_list_int(bp, context);
- if (error || !leaf->hdr.info.forw)
- break; /* not really an error, buffer full or EOF */
+ if (error) {
+ xfs_da_brelse(NULL, bp);
+ return error;
+ }
+ if (context->seen_enough || leaf->hdr.info.forw == 0)
+ break;
cursor->blkno = be32_to_cpu(leaf->hdr.info.forw);
xfs_da_brelse(NULL, bp);
error = xfs_da_read_buf(NULL, context->dp, cursor->blkno, -1,
@@ -1886,7 +1987,7 @@ xfs_attr_node_list(xfs_attr_list_context_t *context)
* Read the value associated with an attribute from the out-of-line buffer
* that we stored it in.
*/
-STATIC int
+int
xfs_attr_rmtval_get(xfs_da_args_t *args)
{
xfs_bmbt_irec_t map[ATTR_RMTVALUE_MAPSIZE];
diff --git a/fs/xfs/xfs_attr.h b/fs/xfs/xfs_attr.h
index 981633f6c077..783977d3ea71 100644
--- a/fs/xfs/xfs_attr.h
+++ b/fs/xfs/xfs_attr.h
@@ -37,6 +37,7 @@
struct cred;
struct bhv_vnode;
+struct xfs_attr_list_context;
typedef int (*attrset_t)(struct bhv_vnode *, char *, void *, size_t, int);
typedef int (*attrget_t)(struct bhv_vnode *, char *, void *, size_t, int);
@@ -160,13 +161,16 @@ struct xfs_da_args;
*/
int xfs_attr_get(bhv_desc_t *, const char *, char *, int *, int, struct cred *);
int xfs_attr_set(bhv_desc_t *, const char *, char *, int, int, struct cred *);
+int xfs_attr_set_int(struct xfs_inode *, const char *, int, char *, int, int);
int xfs_attr_remove(bhv_desc_t *, const char *, int, struct cred *);
-int xfs_attr_list(bhv_desc_t *, char *, int, int,
- struct attrlist_cursor_kern *, struct cred *);
+int xfs_attr_remove_int(struct xfs_inode *, const char *, int, int);
+int xfs_attr_list(bhv_desc_t *, char *, int, int, struct attrlist_cursor_kern *, struct cred *);
+int xfs_attr_list_int(struct xfs_attr_list_context *);
int xfs_attr_inactive(struct xfs_inode *dp);
int xfs_attr_shortform_getvalue(struct xfs_da_args *);
int xfs_attr_fetch(struct xfs_inode *, const char *, int,
char *, int *, int, struct cred *);
+int xfs_attr_rmtval_get(struct xfs_da_args *args);
#endif /* __XFS_ATTR_H__ */
diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c
index 9455051f0120..9719bbef122c 100644
--- a/fs/xfs/xfs_attr_leaf.c
+++ b/fs/xfs/xfs_attr_leaf.c
@@ -89,9 +89,46 @@ STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf,
int dst_start, int move_count,
xfs_mount_t *mp);
STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
-STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context,
- attrnames_t *, char *name, int namelen,
- int valuelen);
+
+/*========================================================================
+ * Namespace helper routines
+ *========================================================================*/
+
+STATIC inline attrnames_t *
+xfs_attr_flags_namesp(int flags)
+{
+ return ((flags & XFS_ATTR_SECURE) ? &attr_secure:
+ ((flags & XFS_ATTR_ROOT) ? &attr_trusted : &attr_user));
+}
+
+/*
+ * If namespace bits don't match return 0.
+ * If all match then return 1.
+ */
+STATIC inline int
+xfs_attr_namesp_match(int arg_flags, int ondisk_flags)
+{
+ return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags);
+}
+
+/*
+ * If namespace bits don't match and we don't have an override for it
+ * then return 0.
+ * If all match or are overridable then return 1.
+ */
+STATIC inline int
+xfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags)
+{
+ if (((arg_flags & ATTR_SECURE) == 0) !=
+ ((ondisk_flags & XFS_ATTR_SECURE) == 0) &&
+ !(arg_flags & ATTR_KERNORMALS))
+ return 0;
+ if (((arg_flags & ATTR_ROOT) == 0) !=
+ ((ondisk_flags & XFS_ATTR_ROOT) == 0) &&
+ !(arg_flags & ATTR_KERNROOTLS))
+ return 0;
+ return 1;
+}
/*========================================================================
@@ -228,11 +265,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
continue;
if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue;
- if (((args->flags & ATTR_SECURE) != 0) !=
- ((sfe->flags & XFS_ATTR_SECURE) != 0))
- continue;
- if (((args->flags & ATTR_ROOT) != 0) !=
- ((sfe->flags & XFS_ATTR_ROOT) != 0))
+ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
continue;
ASSERT(0);
#endif
@@ -246,8 +279,7 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
sfe->namelen = args->namelen;
sfe->valuelen = args->valuelen;
- sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
- ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
+ sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
memcpy(sfe->nameval, args->name, args->namelen);
memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
sf->hdr.count++;
@@ -282,11 +314,7 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
continue;
if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
continue;
- if (((args->flags & ATTR_SECURE) != 0) !=
- ((sfe->flags & XFS_ATTR_SECURE) != 0))
- continue;
- if (((args->flags & ATTR_ROOT) != 0) !=
- ((sfe->flags & XFS_ATTR_ROOT) != 0))
+ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
continue;
break;
}
@@ -363,11 +391,7 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
continue;
if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue;
- if (((args->flags & ATTR_SECURE) != 0) !=
- ((sfe->flags & XFS_ATTR_SECURE) != 0))
- continue;
- if (((args->flags & ATTR_ROOT) != 0) !=
- ((sfe->flags & XFS_ATTR_ROOT) != 0))
+ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
continue;
return(XFS_ERROR(EEXIST));
}
@@ -394,11 +418,7 @@ xfs_attr_shortform_getvalue(xfs_da_args_t *args)
continue;
if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
continue;
- if (((args->flags & ATTR_SECURE) != 0) !=
- ((sfe->flags & XFS_ATTR_SECURE) != 0))
- continue;
- if (((args->flags & ATTR_ROOT) != 0) !=
- ((sfe->flags & XFS_ATTR_ROOT) != 0))
+ if (!xfs_attr_namesp_match(args->flags, sfe->flags))
continue;
if (args->flags & ATTR_KERNOVAL) {
args->valuelen = sfe->valuelen;
@@ -485,8 +505,7 @@ xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
nargs.valuelen = sfe->valuelen;
nargs.hashval = xfs_da_hashname((char *)sfe->nameval,
sfe->namelen);
- nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
- ((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
+ nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
ASSERT(error == ENOATTR);
error = xfs_attr_leaf_add(bp, &nargs);
@@ -520,6 +539,10 @@ xfs_attr_shortform_compare(const void *a, const void *b)
}
}
+
+#define XFS_ISRESET_CURSOR(cursor) \
+ (!((cursor)->initted) && !((cursor)->hashval) && \
+ !((cursor)->blkno) && !((cursor)->offset))
/*
* Copy out entries of shortform attribute lists for attr_list().
* Shortform attribute lists are not stored in hashval sorted order.
@@ -537,6 +560,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
xfs_attr_sf_entry_t *sfe;
xfs_inode_t *dp;
int sbsize, nsbuf, count, i;
+ int error;
ASSERT(context != NULL);
dp = context->dp;
@@ -552,46 +576,51 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
xfs_attr_trace_l_c("sf start", context);
/*
- * If the buffer is large enough, do not bother with sorting.
+ * If the buffer is large enough and the cursor is at the start,
+ * do not bother with sorting since we will return everything in
+ * one buffer and another call using the cursor won't need to be
+ * made.
* Note the generous fudge factor of 16 overhead bytes per entry.
+ * If bufsize is zero then put_listent must be a search function
+ * and can just scan through what we have.
*/
- if ((dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize) {
+ if (context->bufsize == 0 ||
+ (XFS_ISRESET_CURSOR(cursor) &&
+ (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
attrnames_t *namesp;
- if (((context->flags & ATTR_SECURE) != 0) !=
- ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
- !(context->flags & ATTR_KERNORMALS)) {
- sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
- continue;
- }
- if (((context->flags & ATTR_ROOT) != 0) !=
- ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
- !(context->flags & ATTR_KERNROOTLS)) {
+ if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue;
}
- namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure:
- ((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :
- &attr_user);
- if (context->flags & ATTR_KERNOVAL) {
- ASSERT(context->flags & ATTR_KERNAMELS);
- context->count += namesp->attr_namelen +
- sfe->namelen + 1;
- }
- else {
- if (xfs_attr_put_listent(context, namesp,
- (char *)sfe->nameval,
- (int)sfe->namelen,
- (int)sfe->valuelen))
- break;
- }
+ namesp = xfs_attr_flags_namesp(sfe->flags);
+ error = context->put_listent(context,
+ namesp,
+ (char *)sfe->nameval,
+ (int)sfe->namelen,
+ (int)sfe->valuelen,
+ (char*)&sfe->nameval[sfe->namelen]);
+
+ /*
+ * Either search callback finished early or
+ * didn't fit it all in the buffer after all.
+ */
+ if (context->seen_enough)
+ break;
+
+ if (error)
+ return error;
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
}
xfs_attr_trace_l_c("sf big-gulp", context);
return(0);
}
+ /* do no more for a search callback */
+ if (context->bufsize == 0)
+ return 0;
+
/*
* It didn't all fit, so we have to sort everything on hashval.
*/
@@ -614,15 +643,7 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
kmem_free(sbuf, sbsize);
return XFS_ERROR(EFSCORRUPTED);
}
- if (((context->flags & ATTR_SECURE) != 0) !=
- ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
- !(context->flags & ATTR_KERNORMALS)) {
- sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
- continue;
- }
- if (((context->flags & ATTR_ROOT) != 0) !=
- ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
- !(context->flags & ATTR_KERNROOTLS)) {
+ if (!xfs_attr_namesp_match_overrides(context->flags, sfe->flags)) {
sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
continue;
}
@@ -671,24 +692,22 @@ xfs_attr_shortform_list(xfs_attr_list_context_t *context)
for ( ; i < nsbuf; i++, sbp++) {
attrnames_t *namesp;
- namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure :
- ((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :
- &attr_user);
+ namesp = xfs_attr_flags_namesp(sbp->flags);
if (cursor->hashval != sbp->hash) {
cursor->hashval = sbp->hash;
cursor->offset = 0;
}
- if (context->flags & ATTR_KERNOVAL) {
- ASSERT(context->flags & ATTR_KERNAMELS);
- context->count += namesp->attr_namelen +
- sbp->namelen + 1;
- } else {
- if (xfs_attr_put_listent(context, namesp,
- sbp->name, sbp->namelen,
- sbp->valuelen))
- break;
- }
+ error = context->put_listent(context,
+ namesp,
+ sbp->name,
+ sbp->namelen,
+ sbp->valuelen,
+ &sbp->name[sbp->namelen]);
+ if (error)
+ return error;
+ if (context->seen_enough)
+ break;
cursor->offset++;
}
@@ -810,8 +829,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
nargs.value = (char *)&name_loc->nameval[nargs.namelen];
nargs.valuelen = be16_to_cpu(name_loc->valuelen);
nargs.hashval = be32_to_cpu(entry->hashval);
- nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
- ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
+ nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
xfs_attr_shortform_add(&nargs, forkoff);
}
error = 0;
@@ -1098,8 +1116,7 @@ xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
be16_to_cpu(map->size));
entry->hashval = cpu_to_be32(args->hashval);
entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
- entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
- ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
+ entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
if (args->rename) {
entry->flags |= XFS_ATTR_INCOMPLETE;
if ((args->blkno2 == args->blkno) &&
@@ -1926,7 +1943,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
else
break;
}
- ASSERT((probe >= 0) &&
+ ASSERT((probe >= 0) &&
(!leaf->hdr.count
|| (probe < be16_to_cpu(leaf->hdr.count))));
ASSERT((span <= 4) || (be32_to_cpu(entry->hashval) == hashval));
@@ -1971,14 +1988,9 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
if (name_loc->namelen != args->namelen)
continue;
- if (memcmp(args->name, (char *)name_loc->nameval,
- args->namelen) != 0)
+ if (memcmp(args->name, (char *)name_loc->nameval, args->namelen) != 0)
continue;
- if (((args->flags & ATTR_SECURE) != 0) !=
- ((entry->flags & XFS_ATTR_SECURE) != 0))
- continue;
- if (((args->flags & ATTR_ROOT) != 0) !=
- ((entry->flags & XFS_ATTR_ROOT) != 0))
+ if (!xfs_attr_namesp_match(args->flags, entry->flags))
continue;
args->index = probe;
return(XFS_ERROR(EEXIST));
@@ -1989,11 +2001,7 @@ xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
if (memcmp(args->name, (char *)name_rmt->name,
args->namelen) != 0)
continue;
- if (((args->flags & ATTR_SECURE) != 0) !=
- ((entry->flags & XFS_ATTR_SECURE) != 0))
- continue;
- if (((args->flags & ATTR_ROOT) != 0) !=
- ((entry->flags & XFS_ATTR_ROOT) != 0))
+ if (!xfs_attr_namesp_match(args->flags, entry->flags))
continue;
args->index = probe;
args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
@@ -2312,8 +2320,6 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
attrlist_cursor_kern_t *cursor;
xfs_attr_leafblock_t *leaf;
xfs_attr_leaf_entry_t *entry;
- xfs_attr_leaf_name_local_t *name_loc;
- xfs_attr_leaf_name_remote_t *name_rmt;
int retval, i;
ASSERT(bp != NULL);
@@ -2355,9 +2361,8 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
* We have found our place, start copying out the new attributes.
*/
retval = 0;
- for ( ; (i < be16_to_cpu(leaf->hdr.count))
- && (retval == 0); entry++, i++) {
- attrnames_t *namesp;
+ for ( ; (i < be16_to_cpu(leaf->hdr.count)); entry++, i++) {
+ attrnames_t *namesp;
if (be32_to_cpu(entry->hashval) != cursor->hashval) {
cursor->hashval = be32_to_cpu(entry->hashval);
@@ -2366,115 +2371,69 @@ xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
if (entry->flags & XFS_ATTR_INCOMPLETE)
continue; /* skip incomplete entries */
- if (((context->flags & ATTR_SECURE) != 0) !=
- ((entry->flags & XFS_ATTR_SECURE) != 0) &&
- !(context->flags & ATTR_KERNORMALS))
- continue; /* skip non-matching entries */
- if (((context->flags & ATTR_ROOT) != 0) !=
- ((entry->flags & XFS_ATTR_ROOT) != 0) &&
- !(context->flags & ATTR_KERNROOTLS))
- continue; /* skip non-matching entries */
-
- namesp = (entry->flags & XFS_ATTR_SECURE) ? &attr_secure :
- ((entry->flags & XFS_ATTR_ROOT) ? &attr_trusted :
- &attr_user);
+ if (!xfs_attr_namesp_match_overrides(context->flags, entry->flags))
+ continue;
+
+ namesp = xfs_attr_flags_namesp(entry->flags);
if (entry->flags & XFS_ATTR_LOCAL) {
- name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
- if (context->flags & ATTR_KERNOVAL) {
- ASSERT(context->flags & ATTR_KERNAMELS);
- context->count += namesp->attr_namelen +
- (int)name_loc->namelen + 1;
- } else {
- retval = xfs_attr_put_listent(context, namesp,
- (char *)name_loc->nameval,
- (int)name_loc->namelen,
- be16_to_cpu(name_loc->valuelen));
- }
+ xfs_attr_leaf_name_local_t *name_loc =
+ XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
+
+ retval = context->put_listent(context,
+ namesp,
+ (char *)name_loc->nameval,
+ (int)name_loc->namelen,
+ be16_to_cpu(name_loc->valuelen),
+ (char *)&name_loc->nameval[name_loc->namelen]);
+ if (retval)
+ return retval;
} else {
- name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
- if (context->flags & ATTR_KERNOVAL) {
- ASSERT(context->flags & ATTR_KERNAMELS);
- context->count += namesp->attr_namelen +
- (int)name_rmt->namelen + 1;
- } else {
- retval = xfs_attr_put_listent(context, namesp,
- (char *)name_rmt->name,
- (int)name_rmt->namelen,
- be32_to_cpu(name_rmt->valuelen));
+ xfs_attr_leaf_name_remote_t *name_rmt =
+ XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
+
+ int valuelen = be32_to_cpu(name_rmt->valuelen);
+
+ if (context->put_value) {
+ xfs_da_args_t args;
+
+ memset((char *)&args, 0, sizeof(args));
+ args.dp = context->dp;
+ args.whichfork = XFS_ATTR_FORK;
+ args.valuelen = valuelen;
+ args.value = kmem_alloc(valuelen, KM_SLEEP);
+ args.rmtblkno = be32_to_cpu(name_rmt->valueblk);
+ args.rmtblkcnt = XFS_B_TO_FSB(args.dp->i_mount, valuelen);
+ retval = xfs_attr_rmtval_get(&args);
+ if (retval)
+ return retval;
+ retval = context->put_listent(context,
+ namesp,
+ (char *)name_rmt->name,
+ (int)name_rmt->namelen,
+ valuelen,
+ (char*)args.value);
+ kmem_free(args.value, valuelen);
}
+ else {
+ retval = context->put_listent(context,
+ namesp,
+ (char *)name_rmt->name,
+ (int)name_rmt->namelen,
+ valuelen,
+ NULL);
+ }
+ if (retval)
+ return retval;
}
- if (retval == 0) {
- cursor->offset++;
- }
+ if (context->seen_enough)
+ break;
+ cursor->offset++;
}
xfs_attr_trace_l_cl("blk end", context, leaf);
return(retval);
}
-#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \
- (((struct attrlist_ent *) 0)->a_name - (char *) 0)
-#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \
- ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
- & ~(sizeof(u_int32_t)-1))
-
-/*
- * Format an attribute and copy it out to the user's buffer.
- * Take care to check values and protect against them changing later,
- * we may be reading them directly out of a user buffer.
- */
-/*ARGSUSED*/
-STATIC int
-xfs_attr_put_listent(xfs_attr_list_context_t *context,
- attrnames_t *namesp, char *name, int namelen, int valuelen)
-{
- attrlist_ent_t *aep;
- int arraytop;
-
- ASSERT(!(context->flags & ATTR_KERNOVAL));
- if (context->flags & ATTR_KERNAMELS) {
- char *offset;
-
- ASSERT(context->count >= 0);
-
- arraytop = context->count + namesp->attr_namelen + namelen + 1;
- if (arraytop > context->firstu) {
- context->count = -1; /* insufficient space */
- return(1);
- }
- offset = (char *)context->alist + context->count;
- strncpy(offset, namesp->attr_name, namesp->attr_namelen);
- offset += namesp->attr_namelen;
- strncpy(offset, name, namelen); /* real name */
- offset += namelen;
- *offset = '\0';
- context->count += namesp->attr_namelen + namelen + 1;
- return(0);
- }
-
- ASSERT(context->count >= 0);
- ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
- ASSERT(context->firstu >= sizeof(*context->alist));
- ASSERT(context->firstu <= context->bufsize);
-
- arraytop = sizeof(*context->alist) +
- context->count * sizeof(context->alist->al_offset[0]);
- context->firstu -= ATTR_ENTSIZE(namelen);
- if (context->firstu < arraytop) {
- xfs_attr_trace_l_c("buffer full", context);
- context->alist->al_more = 1;
- return(1);
- }
-
- aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
- aep->a_valuelen = valuelen;
- memcpy(aep->a_name, name, namelen);
- aep->a_name[ namelen ] = 0;
- context->alist->al_offset[ context->count++ ] = context->firstu;
- context->alist->al_count = context->count;
- xfs_attr_trace_l_c("add", context);
- return(0);
-}
/*========================================================================
* Manage the INCOMPLETE flag in a leaf entry
diff --git a/fs/xfs/xfs_attr_leaf.h b/fs/xfs/xfs_attr_leaf.h
index 51c3ee156b2f..040f732ce1e2 100644
--- a/fs/xfs/xfs_attr_leaf.h
+++ b/fs/xfs/xfs_attr_leaf.h
@@ -130,6 +130,19 @@ typedef struct xfs_attr_leafblock {
#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT)
/*
+ * Conversion macros for converting namespace bits from argument flags
+ * to ondisk flags.
+ */
+#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE)
+#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE)
+#define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK)
+#define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK)
+#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\
+ ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0))
+#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\
+ ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0))
+
+/*
* Alignment for namelist and valuelist entries (since they are mixed
* there can be only one alignment value)
*/
@@ -196,16 +209,26 @@ static inline int xfs_attr_leaf_entsize_local_max(int bsize)
* Structure used to pass context around among the routines.
*========================================================================*/
+
+struct xfs_attr_list_context;
+
+typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, struct attrnames *,
+ char *, int, int, char *);
+
typedef struct xfs_attr_list_context {
- struct xfs_inode *dp; /* inode */
- struct attrlist_cursor_kern *cursor;/* position in list */
- struct attrlist *alist; /* output buffer */
- int count; /* num used entries */
- int dupcnt; /* count dup hashvals seen */
- int bufsize;/* total buffer size */
- int firstu; /* first used byte in buffer */
- int flags; /* from VOP call */
- int resynch;/* T/F: resynch with cursor */
+ struct xfs_inode *dp; /* inode */
+ struct attrlist_cursor_kern *cursor; /* position in list */
+ struct attrlist *alist; /* output buffer */
+ int seen_enough; /* T/F: seen enough of list? */
+ int count; /* num used entries */
+ int dupcnt; /* count dup hashvals seen */
+ int bufsize; /* total buffer size */
+ int firstu; /* first used byte in buffer */
+ int flags; /* from VOP call */
+ int resynch; /* T/F: resynch with cursor */
+ int put_value; /* T/F: need value for listent */
+ put_listent_func_t put_listent; /* list output fmt function */
+ int index; /* index into output buffer */
} xfs_attr_list_context_t;
/*
diff --git a/fs/xfs/xfs_behavior.c b/fs/xfs/xfs_behavior.c
index f4fe3715a803..0dc17219d412 100644
--- a/fs/xfs/xfs_behavior.c
+++ b/fs/xfs/xfs_behavior.c
@@ -110,26 +110,6 @@ bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp)
}
/*
- * Look for a specific ops vector on the specified behavior chain.
- * Return the associated behavior descriptor. Or NULL, if not found.
- */
-bhv_desc_t *
-bhv_lookup(bhv_head_t *bhp, void *ops)
-{
- bhv_desc_t *curdesc;
-
- for (curdesc = bhp->bh_first;
- curdesc != NULL;
- curdesc = curdesc->bd_next) {
-
- if (curdesc->bd_ops == ops)
- return curdesc;
- }
-
- return NULL;
-}
-
-/*
* Looks for the first behavior within a specified range of positions.
* Return the associated behavior descriptor. Or NULL, if none found.
*/
diff --git a/fs/xfs/xfs_behavior.h b/fs/xfs/xfs_behavior.h
index 6e6e56fb352d..e7ca1fed955a 100644
--- a/fs/xfs/xfs_behavior.h
+++ b/fs/xfs/xfs_behavior.h
@@ -176,12 +176,10 @@ extern void bhv_insert_initial(bhv_head_t *, bhv_desc_t *);
* Behavior module prototypes.
*/
extern void bhv_remove_not_first(bhv_head_t *bhp, bhv_desc_t *bdp);
-extern bhv_desc_t * bhv_lookup(bhv_head_t *bhp, void *ops);
extern bhv_desc_t * bhv_lookup_range(bhv_head_t *bhp, int low, int high);
extern bhv_desc_t * bhv_base(bhv_head_t *bhp);
/* No bhv locking on Linux */
-#define bhv_lookup_unlocked bhv_lookup
#define bhv_base_unlocked bhv_base
#endif /* __XFS_BEHAVIOR_H__ */
diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c
index bf46fae303af..5b050c06795f 100644
--- a/fs/xfs/xfs_bmap.c
+++ b/fs/xfs/xfs_bmap.c
@@ -2999,7 +2999,7 @@ xfs_bmap_btree_to_extents(
int error; /* error return value */
xfs_ifork_t *ifp; /* inode fork data */
xfs_mount_t *mp; /* mount point structure */
- xfs_bmbt_ptr_t *pp; /* ptr to block address */
+ __be64 *pp; /* ptr to block address */
xfs_bmbt_block_t *rblock;/* root btree block */
ifp = XFS_IFORK_PTR(ip, whichfork);
@@ -3011,12 +3011,12 @@ xfs_bmap_btree_to_extents(
ASSERT(XFS_BMAP_BROOT_MAXRECS(ifp->if_broot_bytes) == 1);
mp = ip->i_mount;
pp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, ifp->if_broot_bytes);
+ cbno = be64_to_cpu(*pp);
*logflagsp = 0;
#ifdef DEBUG
- if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), 1)))
+ if ((error = xfs_btree_check_lptr(cur, cbno, 1)))
return error;
#endif
- cbno = INT_GET(*pp, ARCH_CONVERT);
if ((error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp,
XFS_BMAP_BTREE_REF)))
return error;
@@ -3512,9 +3512,9 @@ xfs_bmap_extents_to_btree(
*/
kp = XFS_BMAP_KEY_IADDR(block, 1, cur);
arp = XFS_BMAP_REC_IADDR(ablock, 1, cur);
- INT_SET(kp->br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(arp));
+ kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp));
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
- INT_SET(*pp, ARCH_CONVERT, args.fsbno);
+ *pp = cpu_to_be64(args.fsbno);
/*
* Do all this logging at the end so that
* the root is at the right level.
@@ -3705,7 +3705,7 @@ STATIC xfs_bmbt_rec_t * /* pointer to found extent entry */
xfs_bmap_search_extents(
xfs_inode_t *ip, /* incore inode pointer */
xfs_fileoff_t bno, /* block number searched for */
- int whichfork, /* data or attr fork */
+ int fork, /* data or attr fork */
int *eofp, /* out: end of file found */
xfs_extnum_t *lastxp, /* out: last extent index */
xfs_bmbt_irec_t *gotp, /* out: extent entry found */
@@ -3713,25 +3713,28 @@ xfs_bmap_search_extents(
{
xfs_ifork_t *ifp; /* inode fork pointer */
xfs_bmbt_rec_t *ep; /* extent record pointer */
- int rt; /* realtime flag */
XFS_STATS_INC(xs_look_exlist);
- ifp = XFS_IFORK_PTR(ip, whichfork);
+ ifp = XFS_IFORK_PTR(ip, fork);
ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp);
- rt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
- if (unlikely(!rt && !gotp->br_startblock && (*lastxp != NULLEXTNUM))) {
- cmn_err(CE_PANIC,"Access to block zero: fs: <%s> inode: %lld "
- "start_block : %llx start_off : %llx blkcnt : %llx "
- "extent-state : %x \n",
- (ip->i_mount)->m_fsname, (long long)ip->i_ino,
+ if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) &&
+ !(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) {
+ xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount,
+ "Access to block zero in inode %llu "
+ "start_block: %llx start_off: %llx "
+ "blkcnt: %llx extent-state: %x lastx: %x\n",
+ (unsigned long long)ip->i_ino,
(unsigned long long)gotp->br_startblock,
(unsigned long long)gotp->br_startoff,
(unsigned long long)gotp->br_blockcount,
- gotp->br_state);
- }
- return ep;
+ gotp->br_state, *lastxp);
+ *lastxp = NULLEXTNUM;
+ *eofp = 1;
+ return NULL;
+ }
+ return ep;
}
@@ -4494,7 +4497,7 @@ xfs_bmap_read_extents(
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
xfs_mount_t *mp; /* file system mount structure */
- xfs_bmbt_ptr_t *pp; /* pointer to block address */
+ __be64 *pp; /* pointer to block address */
/* REFERENCED */
xfs_extnum_t room; /* number of entries there's room for */
@@ -4510,10 +4513,10 @@ xfs_bmap_read_extents(
level = be16_to_cpu(block->bb_level);
ASSERT(level > 0);
pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
- ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
- ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
- ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
- bno = INT_GET(*pp, ARCH_CONVERT);
+ bno = be64_to_cpu(*pp);
+ ASSERT(bno != NULLDFSBNO);
+ ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
+ ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
/*
* Go down the tree until leaf level is reached, following the first
* pointer (leftmost) at each level.
@@ -4530,10 +4533,8 @@ xfs_bmap_read_extents(
break;
pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
1, mp->m_bmap_dmxr[1]);
- XFS_WANT_CORRUPTED_GOTO(
- XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)),
- error0);
- bno = INT_GET(*pp, ARCH_CONVERT);
+ bno = be64_to_cpu(*pp);
+ XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0);
xfs_trans_brelse(tp, bp);
}
/*
@@ -6141,7 +6142,7 @@ xfs_check_block(
short sz)
{
int i, j, dmxr;
- xfs_bmbt_ptr_t *pp, *thispa; /* pointer to block address */
+ __be64 *pp, *thispa; /* pointer to block address */
xfs_bmbt_key_t *prevp, *keyp;
ASSERT(be16_to_cpu(block->bb_level) > 0);
@@ -6179,11 +6180,10 @@ xfs_check_block(
thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
xfs_bmbt, block, j, dmxr);
}
- if (INT_GET(*thispa, ARCH_CONVERT) ==
- INT_GET(*pp, ARCH_CONVERT)) {
+ if (*thispa == *pp) {
cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld",
__FUNCTION__, j, i,
- INT_GET(*thispa, ARCH_CONVERT));
+ (unsigned long long)be64_to_cpu(*thispa));
panic("%s: ptrs are equal in node\n",
__FUNCTION__);
}
@@ -6210,7 +6210,7 @@ xfs_bmap_check_leaf_extents(
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
xfs_mount_t *mp; /* file system mount structure */
- xfs_bmbt_ptr_t *pp; /* pointer to block address */
+ __be64 *pp; /* pointer to block address */
xfs_bmbt_rec_t *ep; /* pointer to current extent */
xfs_bmbt_rec_t *lastp; /* pointer to previous extent */
xfs_bmbt_rec_t *nextp; /* pointer to next extent */
@@ -6231,10 +6231,12 @@ xfs_bmap_check_leaf_extents(
ASSERT(level > 0);
xfs_check_block(block, mp, 1, ifp->if_broot_bytes);
pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
- ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
- ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
- ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
- bno = INT_GET(*pp, ARCH_CONVERT);
+ bno = be64_to_cpu(*pp);
+
+ ASSERT(bno != NULLDFSBNO);
+ ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
+ ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
+
/*
* Go down the tree until leaf level is reached, following the first
* pointer (leftmost) at each level.
@@ -6265,8 +6267,8 @@ xfs_bmap_check_leaf_extents(
xfs_check_block(block, mp, 0, 0);
pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block,
1, mp->m_bmap_dmxr[1]);
- XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, INT_GET(*pp, ARCH_CONVERT)), error0);
- bno = INT_GET(*pp, ARCH_CONVERT);
+ bno = be64_to_cpu(*pp);
+ XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0);
if (bp_release) {
bp_release = 0;
xfs_trans_brelse(NULL, bp);
@@ -6372,7 +6374,7 @@ xfs_bmap_count_blocks(
xfs_ifork_t *ifp; /* fork structure */
int level; /* btree level, for checking */
xfs_mount_t *mp; /* file system mount structure */
- xfs_bmbt_ptr_t *pp; /* pointer to block address */
+ __be64 *pp; /* pointer to block address */
bno = NULLFSBLOCK;
mp = ip->i_mount;
@@ -6395,10 +6397,10 @@ xfs_bmap_count_blocks(
level = be16_to_cpu(block->bb_level);
ASSERT(level > 0);
pp = XFS_BMAP_BROOT_PTR_ADDR(block, 1, ifp->if_broot_bytes);
- ASSERT(INT_GET(*pp, ARCH_CONVERT) != NULLDFSBNO);
- ASSERT(XFS_FSB_TO_AGNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agcount);
- ASSERT(XFS_FSB_TO_AGBNO(mp, INT_GET(*pp, ARCH_CONVERT)) < mp->m_sb.sb_agblocks);
- bno = INT_GET(*pp, ARCH_CONVERT);
+ bno = be64_to_cpu(*pp);
+ ASSERT(bno != NULLDFSBNO);
+ ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount);
+ ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks);
if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) {
XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW,
@@ -6425,7 +6427,7 @@ xfs_bmap_count_tree(
int error;
xfs_buf_t *bp, *nbp;
int level = levelin;
- xfs_bmbt_ptr_t *pp;
+ __be64 *pp;
xfs_fsblock_t bno = blockno;
xfs_fsblock_t nextbno;
xfs_bmbt_block_t *block, *nextblock;
@@ -6452,7 +6454,7 @@ xfs_bmap_count_tree(
/* Dive to the next level */
pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize,
xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]);
- bno = INT_GET(*pp, ARCH_CONVERT);
+ bno = be64_to_cpu(*pp);
if (unlikely((error =
xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) {
xfs_trans_brelse(tp, bp);
diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
index 18fb7385d719..a7b835bf870a 100644
--- a/fs/xfs/xfs_bmap_btree.c
+++ b/fs/xfs/xfs_bmap_btree.c
@@ -58,7 +58,7 @@ STATIC void xfs_bmbt_log_ptrs(xfs_btree_cur_t *, xfs_buf_t *, int, int);
STATIC int xfs_bmbt_lshift(xfs_btree_cur_t *, int, int *);
STATIC int xfs_bmbt_rshift(xfs_btree_cur_t *, int, int *);
STATIC int xfs_bmbt_split(xfs_btree_cur_t *, int, xfs_fsblock_t *,
- xfs_bmbt_key_t *, xfs_btree_cur_t **, int *);
+ __uint64_t *, xfs_btree_cur_t **, int *);
STATIC int xfs_bmbt_updkey(xfs_btree_cur_t *, xfs_bmbt_key_t *, int);
@@ -192,16 +192,11 @@ xfs_bmbt_trace_argifk(
xfs_btree_cur_t *cur,
int i,
xfs_fsblock_t f,
- xfs_bmbt_key_t *k,
+ xfs_dfiloff_t o,
int line)
{
- xfs_dfsbno_t d;
- xfs_dfiloff_t o;
-
- d = (xfs_dfsbno_t)f;
- o = INT_GET(k->br_startoff, ARCH_CONVERT);
xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line,
- i, d >> 32, (int)d, o >> 32,
+ i, (xfs_dfsbno_t)f >> 32, (int)f, o >> 32,
(int)o, 0, 0, 0,
0, 0, 0);
}
@@ -248,7 +243,7 @@ xfs_bmbt_trace_argik(
{
xfs_dfiloff_t o;
- o = INT_GET(k->br_startoff, ARCH_CONVERT);
+ o = be64_to_cpu(k->br_startoff);
xfs_bmbt_trace_enter(func, cur, ARGS, XFS_BMBT_KTRACE_ARGIFK, line,
i, o >> 32, (int)o, 0,
0, 0, 0, 0,
@@ -286,8 +281,8 @@ xfs_bmbt_trace_cursor(
xfs_bmbt_trace_argfffi(fname, c, o, b, i, j, __LINE__)
#define XFS_BMBT_TRACE_ARGI(c,i) \
xfs_bmbt_trace_argi(fname, c, i, __LINE__)
-#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k) \
- xfs_bmbt_trace_argifk(fname, c, i, f, k, __LINE__)
+#define XFS_BMBT_TRACE_ARGIFK(c,i,f,s) \
+ xfs_bmbt_trace_argifk(fname, c, i, f, s, __LINE__)
#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r) \
xfs_bmbt_trace_argifr(fname, c, i, f, r, __LINE__)
#define XFS_BMBT_TRACE_ARGIK(c,i,k) \
@@ -299,7 +294,7 @@ xfs_bmbt_trace_cursor(
#define XFS_BMBT_TRACE_ARGBII(c,b,i,j)
#define XFS_BMBT_TRACE_ARGFFFI(c,o,b,i,j)
#define XFS_BMBT_TRACE_ARGI(c,i)
-#define XFS_BMBT_TRACE_ARGIFK(c,i,f,k)
+#define XFS_BMBT_TRACE_ARGIFK(c,i,f,s)
#define XFS_BMBT_TRACE_ARGIFR(c,i,f,r)
#define XFS_BMBT_TRACE_ARGIK(c,i,k)
#define XFS_BMBT_TRACE_CURSOR(c,s)
@@ -357,7 +352,7 @@ xfs_bmbt_delrec(
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
XFS_BMBT_TRACE_ARGI(cur, level);
ptr = cur->bc_ptrs[level];
- tcur = (xfs_btree_cur_t *)0;
+ tcur = NULL;
if (ptr == 0) {
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
*stat = 0;
@@ -382,7 +377,7 @@ xfs_bmbt_delrec(
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
#ifdef DEBUG
for (i = ptr; i < numrecs; i++) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, pp[i], level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
goto error0;
}
@@ -404,7 +399,8 @@ xfs_bmbt_delrec(
xfs_bmbt_log_recs(cur, bp, ptr, numrecs - 1);
}
if (ptr == 1) {
- INT_SET(key.br_startoff, ARCH_CONVERT, xfs_bmbt_disk_get_startoff(rp));
+ key.br_startoff =
+ cpu_to_be64(xfs_bmbt_disk_get_startoff(rp));
kp = &key;
}
}
@@ -621,7 +617,7 @@ xfs_bmbt_delrec(
rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
#ifdef DEBUG
for (i = 0; i < numrrecs; i++) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, rpp[i], level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
goto error0;
}
@@ -748,7 +744,7 @@ xfs_bmbt_insrec(
int logflags; /* inode logging flags */
xfs_fsblock_t nbno; /* new block number */
struct xfs_btree_cur *ncur; /* new btree cursor */
- xfs_bmbt_key_t nkey; /* new btree key value */
+ __uint64_t startoff; /* new btree key value */
xfs_bmbt_rec_t nrec; /* new record count */
int optr; /* old key/record index */
xfs_bmbt_ptr_t *pp; /* pointer to bmap block addr */
@@ -759,9 +755,8 @@ xfs_bmbt_insrec(
ASSERT(level < cur->bc_nlevels);
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
XFS_BMBT_TRACE_ARGIFR(cur, level, *bnop, recp);
- ncur = (xfs_btree_cur_t *)0;
- INT_SET(key.br_startoff, ARCH_CONVERT,
- xfs_bmbt_disk_get_startoff(recp));
+ ncur = NULL;
+ key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(recp));
optr = ptr = cur->bc_ptrs[level];
if (ptr == 0) {
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
@@ -820,7 +815,7 @@ xfs_bmbt_insrec(
optr = ptr = cur->bc_ptrs[level];
} else {
if ((error = xfs_bmbt_split(cur, level,
- &nbno, &nkey, &ncur,
+ &nbno, &startoff, &ncur,
&i))) {
XFS_BMBT_TRACE_CURSOR(cur,
ERROR);
@@ -840,7 +835,7 @@ xfs_bmbt_insrec(
#endif
ptr = cur->bc_ptrs[level];
xfs_bmbt_disk_set_allf(&nrec,
- nkey.br_startoff, 0, 0,
+ startoff, 0, 0,
XFS_EXT_NORM);
} else {
XFS_BMBT_TRACE_CURSOR(cur,
@@ -858,7 +853,7 @@ xfs_bmbt_insrec(
pp = XFS_BMAP_PTR_IADDR(block, 1, cur);
#ifdef DEBUG
for (i = numrecs; i >= ptr; i--) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i - 1], ARCH_CONVERT),
+ if ((error = xfs_btree_check_lptr_disk(cur, pp[i - 1],
level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
@@ -870,14 +865,13 @@ xfs_bmbt_insrec(
memmove(&pp[ptr], &pp[ptr - 1], /* INT_: direct copy */
(numrecs - ptr + 1) * sizeof(*pp));
#ifdef DEBUG
- if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)*bnop,
- level))) {
+ if ((error = xfs_btree_check_lptr(cur, *bnop, level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
#endif
kp[ptr - 1] = key;
- INT_SET(pp[ptr - 1], ARCH_CONVERT, *bnop);
+ pp[ptr - 1] = cpu_to_be64(*bnop);
numrecs++;
block->bb_numrecs = cpu_to_be16(numrecs);
xfs_bmbt_log_keys(cur, bp, ptr, numrecs);
@@ -988,7 +982,7 @@ xfs_bmbt_killroot(
cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
#ifdef DEBUG
for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(cpp[i], ARCH_CONVERT), level - 1))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, cpp[i], level - 1))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
@@ -1132,7 +1126,7 @@ xfs_bmbt_lookup(
d = XFS_FSB_TO_DADDR(mp, fsbno);
bp = cur->bc_bufs[level];
if (bp && XFS_BUF_ADDR(bp) != d)
- bp = (xfs_buf_t *)0;
+ bp = NULL;
if (!bp) {
if ((error = xfs_btree_read_bufl(mp, tp, fsbno,
0, &bp, XFS_BMAP_BTREE_REF))) {
@@ -1170,7 +1164,7 @@ xfs_bmbt_lookup(
keyno = (low + high) >> 1;
if (level > 0) {
kkp = kkbase + keyno - 1;
- startoff = INT_GET(kkp->br_startoff, ARCH_CONVERT);
+ startoff = be64_to_cpu(kkp->br_startoff);
} else {
krp = krbase + keyno - 1;
startoff = xfs_bmbt_disk_get_startoff(krp);
@@ -1189,13 +1183,13 @@ xfs_bmbt_lookup(
if (diff > 0 && --keyno < 1)
keyno = 1;
pp = XFS_BMAP_PTR_IADDR(block, keyno, cur);
+ fsbno = be64_to_cpu(*pp);
#ifdef DEBUG
- if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr(cur, fsbno, level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
#endif
- fsbno = INT_GET(*pp, ARCH_CONVERT);
cur->bc_ptrs[level] = keyno;
}
}
@@ -1313,7 +1307,7 @@ xfs_bmbt_lshift(
lpp = XFS_BMAP_PTR_IADDR(left, lrecs, cur);
rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
#ifdef DEBUG
- if ((error = xfs_btree_check_lptr(cur, INT_GET(*rpp, ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, *rpp, level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
@@ -1340,7 +1334,7 @@ xfs_bmbt_lshift(
if (level > 0) {
#ifdef DEBUG
for (i = 0; i < rrecs; i++) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i + 1], ARCH_CONVERT),
+ if ((error = xfs_btree_check_lptr_disk(cur, rpp[i + 1],
level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
@@ -1354,8 +1348,7 @@ xfs_bmbt_lshift(
} else {
memmove(rrp, rrp + 1, rrecs * sizeof(*rrp));
xfs_bmbt_log_recs(cur, rbp, 1, rrecs);
- INT_SET(key.br_startoff, ARCH_CONVERT,
- xfs_bmbt_disk_get_startoff(rrp));
+ key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(rrp));
rkp = &key;
}
if ((error = xfs_bmbt_updkey(cur, rkp, level + 1))) {
@@ -1445,7 +1438,7 @@ xfs_bmbt_rshift(
rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
#ifdef DEBUG
for (i = be16_to_cpu(right->bb_numrecs) - 1; i >= 0; i--) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(rpp[i], ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, rpp[i], level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
@@ -1454,7 +1447,7 @@ xfs_bmbt_rshift(
memmove(rkp + 1, rkp, be16_to_cpu(right->bb_numrecs) * sizeof(*rkp));
memmove(rpp + 1, rpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));
#ifdef DEBUG
- if ((error = xfs_btree_check_lptr(cur, INT_GET(*lpp, ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, *lpp, level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
@@ -1469,8 +1462,7 @@ xfs_bmbt_rshift(
memmove(rrp + 1, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
*rrp = *lrp;
xfs_bmbt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
- INT_SET(key.br_startoff, ARCH_CONVERT,
- xfs_bmbt_disk_get_startoff(rrp));
+ key.br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(rrp));
rkp = &key;
}
be16_add(&left->bb_numrecs, -1);
@@ -1535,7 +1527,7 @@ xfs_bmbt_split(
xfs_btree_cur_t *cur,
int level,
xfs_fsblock_t *bnop,
- xfs_bmbt_key_t *keyp,
+ __uint64_t *startoff,
xfs_btree_cur_t **curp,
int *stat) /* success/failure */
{
@@ -1560,7 +1552,7 @@ xfs_bmbt_split(
xfs_bmbt_rec_t *rrp; /* right record pointer */
XFS_BMBT_TRACE_CURSOR(cur, ENTRY);
- XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, keyp);
+ XFS_BMBT_TRACE_ARGIFK(cur, level, *bnop, *startoff);
args.tp = cur->bc_tp;
args.mp = cur->bc_mp;
lbp = cur->bc_bufs[level];
@@ -1619,7 +1611,7 @@ xfs_bmbt_split(
rpp = XFS_BMAP_PTR_IADDR(right, 1, cur);
#ifdef DEBUG
for (i = 0; i < be16_to_cpu(right->bb_numrecs); i++) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(lpp[i], ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, lpp[i], level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
@@ -1629,13 +1621,13 @@ xfs_bmbt_split(
memcpy(rpp, lpp, be16_to_cpu(right->bb_numrecs) * sizeof(*rpp));
xfs_bmbt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
xfs_bmbt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
- keyp->br_startoff = INT_GET(rkp->br_startoff, ARCH_CONVERT);
+ *startoff = be64_to_cpu(rkp->br_startoff);
} else {
lrp = XFS_BMAP_REC_IADDR(left, i, cur);
rrp = XFS_BMAP_REC_IADDR(right, 1, cur);
memcpy(rrp, lrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
xfs_bmbt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
- keyp->br_startoff = xfs_bmbt_disk_get_startoff(rrp);
+ *startoff = xfs_bmbt_disk_get_startoff(rrp);
}
be16_add(&left->bb_numrecs, -(be16_to_cpu(right->bb_numrecs)));
right->bb_rightsib = left->bb_rightsib;
@@ -1728,9 +1720,9 @@ xfs_bmdr_to_bmbt(
{
int dmxr;
xfs_bmbt_key_t *fkp;
- xfs_bmbt_ptr_t *fpp;
+ __be64 *fpp;
xfs_bmbt_key_t *tkp;
- xfs_bmbt_ptr_t *tpp;
+ __be64 *tpp;
rblock->bb_magic = cpu_to_be32(XFS_BMAP_MAGIC);
rblock->bb_level = dblock->bb_level;
@@ -1745,7 +1737,7 @@ xfs_bmdr_to_bmbt(
tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen);
dmxr = be16_to_cpu(dblock->bb_numrecs);
memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
- memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
+ memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
}
/*
@@ -1805,7 +1797,7 @@ xfs_bmbt_decrement(
tp = cur->bc_tp;
mp = cur->bc_mp;
for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) {
- fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT);
+ fsbno = be64_to_cpu(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur));
if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp,
XFS_BMAP_BTREE_REF))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
@@ -2135,7 +2127,7 @@ xfs_bmbt_increment(
tp = cur->bc_tp;
mp = cur->bc_mp;
for (block = xfs_bmbt_get_block(cur, lev, &bp); lev > level; ) {
- fsbno = INT_GET(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur), ARCH_CONVERT);
+ fsbno = be64_to_cpu(*XFS_BMAP_PTR_IADDR(block, cur->bc_ptrs[lev], cur));
if ((error = xfs_btree_read_bufl(mp, tp, fsbno, 0, &bp,
XFS_BMAP_BTREE_REF))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
@@ -2178,7 +2170,7 @@ xfs_bmbt_insert(
level = 0;
nbno = NULLFSBLOCK;
xfs_bmbt_disk_set_all(&nrec, &cur->bc_rec.b);
- ncur = (xfs_btree_cur_t *)0;
+ ncur = NULL;
pcur = cur;
do {
if ((error = xfs_bmbt_insrec(pcur, level++, &nbno, &nrec, &ncur,
@@ -2205,7 +2197,7 @@ xfs_bmbt_insert(
}
if (ncur) {
pcur = ncur;
- ncur = (xfs_btree_cur_t *)0;
+ ncur = NULL;
}
} while (nbno != NULLFSBLOCK);
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
@@ -2356,12 +2348,12 @@ xfs_bmbt_newroot(
args.firstblock = args.fsbno;
if (args.fsbno == NULLFSBLOCK) {
#ifdef DEBUG
- if ((error = xfs_btree_check_lptr(cur, INT_GET(*pp, ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, *pp, level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
#endif
- args.fsbno = INT_GET(*pp, ARCH_CONVERT);
+ args.fsbno = be64_to_cpu(*pp);
args.type = XFS_ALLOCTYPE_START_BNO;
} else
args.type = XFS_ALLOCTYPE_NEAR_BNO;
@@ -2393,7 +2385,7 @@ xfs_bmbt_newroot(
cpp = XFS_BMAP_PTR_IADDR(cblock, 1, cur);
#ifdef DEBUG
for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) {
- if ((error = xfs_btree_check_lptr(cur, INT_GET(pp[i], ARCH_CONVERT), level))) {
+ if ((error = xfs_btree_check_lptr_disk(cur, pp[i], level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
@@ -2401,13 +2393,12 @@ xfs_bmbt_newroot(
#endif
memcpy(cpp, pp, be16_to_cpu(cblock->bb_numrecs) * sizeof(*pp));
#ifdef DEBUG
- if ((error = xfs_btree_check_lptr(cur, (xfs_bmbt_ptr_t)args.fsbno,
- level))) {
+ if ((error = xfs_btree_check_lptr(cur, args.fsbno, level))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
}
#endif
- INT_SET(*pp, ARCH_CONVERT, args.fsbno);
+ *pp = cpu_to_be64(args.fsbno);
xfs_iroot_realloc(cur->bc_private.b.ip, 1 - be16_to_cpu(cblock->bb_numrecs),
cur->bc_private.b.whichfork);
xfs_btree_setbuf(cur, level, bp);
@@ -2681,9 +2672,9 @@ xfs_bmbt_to_bmdr(
{
int dmxr;
xfs_bmbt_key_t *fkp;
- xfs_bmbt_ptr_t *fpp;
+ __be64 *fpp;
xfs_bmbt_key_t *tkp;
- xfs_bmbt_ptr_t *tpp;
+ __be64 *tpp;
ASSERT(be32_to_cpu(rblock->bb_magic) == XFS_BMAP_MAGIC);
ASSERT(be64_to_cpu(rblock->bb_leftsib) == NULLDFSBNO);
@@ -2698,7 +2689,7 @@ xfs_bmbt_to_bmdr(
tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr);
dmxr = be16_to_cpu(dblock->bb_numrecs);
memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
- memcpy(tpp, fpp, sizeof(*fpp) * dmxr); /* INT_: direct copy */
+ memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
}
/*
@@ -2740,7 +2731,7 @@ xfs_bmbt_update(
XFS_BMBT_TRACE_CURSOR(cur, EXIT);
return 0;
}
- INT_SET(key.br_startoff, ARCH_CONVERT, off);
+ key.br_startoff = cpu_to_be64(off);
if ((error = xfs_bmbt_updkey(cur, &key, 1))) {
XFS_BMBT_TRACE_CURSOR(cur, ERROR);
return error;
diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h
index 6478cfa0e539..49539de9525b 100644
--- a/fs/xfs/xfs_bmap_btree.h
+++ b/fs/xfs/xfs_bmap_btree.h
@@ -163,13 +163,14 @@ typedef struct xfs_bmbt_irec
/*
* Key structure for non-leaf levels of the tree.
*/
-typedef struct xfs_bmbt_key
-{
- xfs_dfiloff_t br_startoff; /* starting file offset */
+typedef struct xfs_bmbt_key {
+ __be64 br_startoff; /* starting file offset */
} xfs_bmbt_key_t, xfs_bmdr_key_t;
-typedef xfs_dfsbno_t xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; /* btree pointer type */
- /* btree block header type */
+/* btree pointer type */
+typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t;
+
+/* btree block header type */
typedef struct xfs_btree_lblock xfs_bmbt_block_t;
#define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)XFS_BUF_PTR(bp))
diff --git a/fs/xfs/xfs_btree.c b/fs/xfs/xfs_btree.c
index ee2255bd6562..aeb87ca69fcc 100644
--- a/fs/xfs/xfs_btree.c
+++ b/fs/xfs/xfs_btree.c
@@ -161,7 +161,7 @@ xfs_btree_check_key(
k1 = ak1;
k2 = ak2;
- ASSERT(INT_GET(k1->br_startoff, ARCH_CONVERT) < INT_GET(k2->br_startoff, ARCH_CONVERT));
+ ASSERT(be64_to_cpu(k1->br_startoff) < be64_to_cpu(k2->br_startoff));
break;
}
case XFS_BTNUM_INO: {
@@ -170,7 +170,7 @@ xfs_btree_check_key(
k1 = ak1;
k2 = ak2;
- ASSERT(INT_GET(k1->ir_startino, ARCH_CONVERT) < INT_GET(k2->ir_startino, ARCH_CONVERT));
+ ASSERT(be32_to_cpu(k1->ir_startino) < be32_to_cpu(k2->ir_startino));
break;
}
default:
@@ -285,8 +285,8 @@ xfs_btree_check_rec(
r1 = ar1;
r2 = ar2;
- ASSERT(INT_GET(r1->ir_startino, ARCH_CONVERT) + XFS_INODES_PER_CHUNK <=
- INT_GET(r2->ir_startino, ARCH_CONVERT));
+ ASSERT(be32_to_cpu(r1->ir_startino) + XFS_INODES_PER_CHUNK <=
+ be32_to_cpu(r2->ir_startino));
break;
}
default:
diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h
index 44f1bd98064a..892b06c54263 100644
--- a/fs/xfs/xfs_btree.h
+++ b/fs/xfs/xfs_btree.h
@@ -145,7 +145,7 @@ typedef struct xfs_btree_cur
union {
xfs_alloc_rec_incore_t a;
xfs_bmbt_irec_t b;
- xfs_inobt_rec_t i;
+ xfs_inobt_rec_incore_t i;
} bc_rec; /* current insert/search record value */
struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */
int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */
@@ -243,6 +243,9 @@ xfs_btree_check_lptr(
xfs_dfsbno_t ptr, /* btree block disk address */
int level); /* btree block level */
+#define xfs_btree_check_lptr_disk(cur, ptr, level) \
+ xfs_btree_check_lptr(cur, be64_to_cpu(ptr), level)
+
/*
* Checking routine: check that short form block header is ok.
*/
diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
index a4aa53974f76..7a55c248ea70 100644
--- a/fs/xfs/xfs_buf_item.c
+++ b/fs/xfs/xfs_buf_item.c
@@ -234,7 +234,6 @@ xfs_buf_item_format(
ASSERT((bip->bli_flags & XFS_BLI_LOGGED) ||
(bip->bli_flags & XFS_BLI_STALE));
bp = bip->bli_buf;
- ASSERT(XFS_BUF_BP_ISMAPPED(bp));
vecp = log_vector;
/*
@@ -628,25 +627,6 @@ xfs_buf_item_committed(
}
/*
- * This is called when the transaction holding the buffer is aborted.
- * Just behave as if the transaction had been cancelled. If we're shutting down
- * and have aborted this transaction, we'll trap this buffer when it tries to
- * get written out.
- */
-STATIC void
-xfs_buf_item_abort(
- xfs_buf_log_item_t *bip)
-{
- xfs_buf_t *bp;
-
- bp = bip->bli_buf;
- xfs_buftrace("XFS_ABORT", bp);
- XFS_BUF_SUPER_STALE(bp);
- xfs_buf_item_unlock(bip);
- return;
-}
-
-/*
* This is called to asynchronously write the buffer associated with this
* buf log item out to disk. The buffer will already have been locked by
* a successful call to xfs_buf_item_trylock(). If the buffer still has
@@ -693,7 +673,6 @@ STATIC struct xfs_item_ops xfs_buf_item_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_buf_item_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push,
- .iop_abort = (void(*)(xfs_log_item_t*))xfs_buf_item_abort,
.iop_pushbuf = NULL,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_buf_item_committing
@@ -901,7 +880,6 @@ xfs_buf_item_relse(
XFS_BUF_SET_FSPRIVATE(bp, bip->bli_item.li_bio_list);
if ((XFS_BUF_FSPRIVATE(bp, void *) == NULL) &&
(XFS_BUF_IODONE_FUNC(bp) != NULL)) {
- ASSERT((XFS_BUF_ISUNINITIAL(bp)) == 0);
XFS_BUF_CLR_IODONE_FUNC(bp);
}
diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
index 32ab61d17ace..a68bc1f1a313 100644
--- a/fs/xfs/xfs_da_btree.c
+++ b/fs/xfs/xfs_da_btree.c
@@ -1054,7 +1054,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
xfs_da_node_entry_t *btree;
xfs_dablk_t blkno;
int probe, span, max, error, retval;
- xfs_dahash_t hashval;
+ xfs_dahash_t hashval, btreehashval;
xfs_da_args_t *args;
args = state->args;
@@ -1079,30 +1079,32 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
return(error);
}
curr = blk->bp->data;
- ASSERT(be16_to_cpu(curr->magic) == XFS_DA_NODE_MAGIC ||
- be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC ||
- be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC);
+ blk->magic = be16_to_cpu(curr->magic);
+ ASSERT(blk->magic == XFS_DA_NODE_MAGIC ||
+ blk->magic == XFS_DIR2_LEAFN_MAGIC ||
+ blk->magic == XFS_ATTR_LEAF_MAGIC);
/*
* Search an intermediate node for a match.
*/
- blk->magic = be16_to_cpu(curr->magic);
if (blk->magic == XFS_DA_NODE_MAGIC) {
node = blk->bp->data;
- blk->hashval = be32_to_cpu(node->btree[be16_to_cpu(node->hdr.count)-1].hashval);
+ max = be16_to_cpu(node->hdr.count);
+ btreehashval = node->btree[max-1].hashval;
+ blk->hashval = be32_to_cpu(btreehashval);
/*
* Binary search. (note: small blocks will skip loop)
*/
- max = be16_to_cpu(node->hdr.count);
probe = span = max / 2;
hashval = args->hashval;
for (btree = &node->btree[probe]; span > 4;
btree = &node->btree[probe]) {
span /= 2;
- if (be32_to_cpu(btree->hashval) < hashval)
+ btreehashval = be32_to_cpu(btree->hashval);
+ if (btreehashval < hashval)
probe += span;
- else if (be32_to_cpu(btree->hashval) > hashval)
+ else if (btreehashval > hashval)
probe -= span;
else
break;
@@ -1133,10 +1135,10 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
blk->index = probe;
blkno = be32_to_cpu(btree->before);
}
- } else if (be16_to_cpu(curr->magic) == XFS_ATTR_LEAF_MAGIC) {
+ } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL);
break;
- } else if (be16_to_cpu(curr->magic) == XFS_DIR2_LEAFN_MAGIC) {
+ } else if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
blk->hashval = xfs_dir2_leafn_lasthash(blk->bp, NULL);
break;
}
@@ -1152,11 +1154,13 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
if (blk->magic == XFS_DIR2_LEAFN_MAGIC) {
retval = xfs_dir2_leafn_lookup_int(blk->bp, args,
&blk->index, state);
- }
- else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
+ } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
retval = xfs_attr_leaf_lookup_int(blk->bp, args);
blk->index = args->index;
args->blkno = blk->blkno;
+ } else {
+ ASSERT(0);
+ return XFS_ERROR(EFSCORRUPTED);
}
if (((retval == ENOENT) || (retval == ENOATTR)) &&
(blk->hashval == args->hashval)) {
@@ -1166,8 +1170,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result)
return(error);
if (retval == 0) {
continue;
- }
- else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
+ } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) {
/* path_shift() gives ENOENT */
retval = XFS_ERROR(ENOATTR);
}
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
index bc43163456ef..0893e16b7d83 100644
--- a/fs/xfs/xfs_error.h
+++ b/fs/xfs/xfs_error.h
@@ -18,14 +18,6 @@
#ifndef __XFS_ERROR_H__
#define __XFS_ERROR_H__
-#define XFS_ERECOVER 1 /* Failure to recover log */
-#define XFS_ELOGSTAT 2 /* Failure to stat log in user space */
-#define XFS_ENOLOGSPACE 3 /* Reservation too large */
-#define XFS_ENOTSUP 4 /* Operation not supported */
-#define XFS_ENOLSN 5 /* Can't find the lsn you asked for */
-#define XFS_ENOTFOUND 6
-#define XFS_ENOTXFS 7 /* Not XFS filesystem */
-
#ifdef DEBUG
#define XFS_ERROR_NTRAP 10
extern int xfs_etrap[XFS_ERROR_NTRAP];
@@ -175,6 +167,7 @@ extern int xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud);
#define XFS_PTAG_SHUTDOWN_CORRUPT 0x00000010
#define XFS_PTAG_SHUTDOWN_IOERROR 0x00000020
#define XFS_PTAG_SHUTDOWN_LOGERROR 0x00000040
+#define XFS_PTAG_FSBLOCK_ZERO 0x00000080
struct xfs_mount;
/* PRINTFLIKE4 */
diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c
index 6cf6d8769b97..6dba78199faf 100644
--- a/fs/xfs/xfs_extfree_item.c
+++ b/fs/xfs/xfs_extfree_item.c
@@ -33,9 +33,6 @@ kmem_zone_t *xfs_efi_zone;
kmem_zone_t *xfs_efd_zone;
STATIC void xfs_efi_item_unlock(xfs_efi_log_item_t *);
-STATIC void xfs_efi_item_abort(xfs_efi_log_item_t *);
-STATIC void xfs_efd_item_abort(xfs_efd_log_item_t *);
-
void
xfs_efi_item_free(xfs_efi_log_item_t *efip)
@@ -184,7 +181,7 @@ STATIC void
xfs_efi_item_unlock(xfs_efi_log_item_t *efip)
{
if (efip->efi_item.li_flags & XFS_LI_ABORTED)
- xfs_efi_item_abort(efip);
+ xfs_efi_item_free(efip);
return;
}
@@ -202,18 +199,6 @@ xfs_efi_item_committed(xfs_efi_log_item_t *efip, xfs_lsn_t lsn)
}
/*
- * This is called when the transaction logging the EFI is aborted.
- * Free up the EFI and return. No need to clean up the slot for
- * the item in the transaction. That was done by the unpin code
- * which is called prior to this routine in the abort/fs-shutdown path.
- */
-STATIC void
-xfs_efi_item_abort(xfs_efi_log_item_t *efip)
-{
- xfs_efi_item_free(efip);
-}
-
-/*
* There isn't much you can do to push on an efi item. It is simply
* stuck waiting for all of its corresponding efd items to be
* committed to disk.
@@ -255,7 +240,6 @@ STATIC struct xfs_item_ops xfs_efi_item_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_efi_item_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_efi_item_push,
- .iop_abort = (void(*)(xfs_log_item_t*))xfs_efi_item_abort,
.iop_pushbuf = NULL,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_efi_item_committing
@@ -386,33 +370,6 @@ xfs_efi_release(xfs_efi_log_item_t *efip,
}
}
-/*
- * This is called when the transaction that should be committing the
- * EFD corresponding to the given EFI is aborted. The committed and
- * canceled flags are used to coordinate the freeing of the EFI and
- * the references by the transaction that committed it.
- */
-STATIC void
-xfs_efi_cancel(
- xfs_efi_log_item_t *efip)
-{
- xfs_mount_t *mp;
- SPLDECL(s);
-
- mp = efip->efi_item.li_mountp;
- AIL_LOCK(mp, s);
- if (efip->efi_flags & XFS_EFI_COMMITTED) {
- /*
- * xfs_trans_delete_ail() drops the AIL lock.
- */
- xfs_trans_delete_ail(mp, (xfs_log_item_t *)efip, s);
- xfs_efi_item_free(efip);
- } else {
- efip->efi_flags |= XFS_EFI_CANCELED;
- AIL_UNLOCK(mp, s);
- }
-}
-
STATIC void
xfs_efd_item_free(xfs_efd_log_item_t *efdp)
{
@@ -514,7 +471,7 @@ STATIC void
xfs_efd_item_unlock(xfs_efd_log_item_t *efdp)
{
if (efdp->efd_item.li_flags & XFS_LI_ABORTED)
- xfs_efd_item_abort(efdp);
+ xfs_efd_item_free(efdp);
return;
}
@@ -541,27 +498,6 @@ xfs_efd_item_committed(xfs_efd_log_item_t *efdp, xfs_lsn_t lsn)
}
/*
- * The transaction of which this EFD is a part has been aborted.
- * Inform its companion EFI of this fact and then clean up after
- * ourselves. No need to clean up the slot for the item in the
- * transaction. That was done by the unpin code which is called
- * prior to this routine in the abort/fs-shutdown path.
- */
-STATIC void
-xfs_efd_item_abort(xfs_efd_log_item_t *efdp)
-{
- /*
- * If we got a log I/O error, it's always the case that the LR with the
- * EFI got unpinned and freed before the EFD got aborted. So don't
- * reference the EFI at all in that case.
- */
- if ((efdp->efd_item.li_flags & XFS_LI_ABORTED) == 0)
- xfs_efi_cancel(efdp->efd_efip);
-
- xfs_efd_item_free(efdp);
-}
-
-/*
* There isn't much you can do to push on an efd item. It is simply
* stuck waiting for the log to be flushed to disk.
*/
@@ -602,7 +538,6 @@ STATIC struct xfs_item_ops xfs_efd_item_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_efd_item_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_efd_item_push,
- .iop_abort = (void(*)(xfs_log_item_t*))xfs_efd_item_abort,
.iop_pushbuf = NULL,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_efd_item_committing
diff --git a/fs/xfs/xfs_extfree_item.h b/fs/xfs/xfs_extfree_item.h
index 0ea45edaab03..2f049f63e85f 100644
--- a/fs/xfs/xfs_extfree_item.h
+++ b/fs/xfs/xfs_extfree_item.h
@@ -33,14 +33,16 @@ typedef struct xfs_extent {
* conversion routine.
*/
+#ifndef HAVE_FORMAT32
typedef struct xfs_extent_32 {
- xfs_dfsbno_t ext_start;
- xfs_extlen_t ext_len;
+ __uint64_t ext_start;
+ __uint32_t ext_len;
} __attribute__((packed)) xfs_extent_32_t;
+#endif
typedef struct xfs_extent_64 {
- xfs_dfsbno_t ext_start;
- xfs_extlen_t ext_len;
+ __uint64_t ext_start;
+ __uint32_t ext_len;
__uint32_t ext_pad;
} xfs_extent_64_t;
@@ -50,25 +52,27 @@ typedef struct xfs_extent_64 {
* size is given by efi_nextents.
*/
typedef struct xfs_efi_log_format {
- unsigned short efi_type; /* efi log item type */
- unsigned short efi_size; /* size of this item */
- uint efi_nextents; /* # extents to free */
+ __uint16_t efi_type; /* efi log item type */
+ __uint16_t efi_size; /* size of this item */
+ __uint32_t efi_nextents; /* # extents to free */
__uint64_t efi_id; /* efi identifier */
xfs_extent_t efi_extents[1]; /* array of extents to free */
} xfs_efi_log_format_t;
+#ifndef HAVE_FORMAT32
typedef struct xfs_efi_log_format_32 {
- unsigned short efi_type; /* efi log item type */
- unsigned short efi_size; /* size of this item */
- uint efi_nextents; /* # extents to free */
+ __uint16_t efi_type; /* efi log item type */
+ __uint16_t efi_size; /* size of this item */
+ __uint32_t efi_nextents; /* # extents to free */
__uint64_t efi_id; /* efi identifier */
xfs_extent_32_t efi_extents[1]; /* array of extents to free */
} __attribute__((packed)) xfs_efi_log_format_32_t;
+#endif
typedef struct xfs_efi_log_format_64 {
- unsigned short efi_type; /* efi log item type */
- unsigned short efi_size; /* size of this item */
- uint efi_nextents; /* # extents to free */
+ __uint16_t efi_type; /* efi log item type */
+ __uint16_t efi_size; /* size of this item */
+ __uint32_t efi_nextents; /* # extents to free */
__uint64_t efi_id; /* efi identifier */
xfs_extent_64_t efi_extents[1]; /* array of extents to free */
} xfs_efi_log_format_64_t;
@@ -79,25 +83,27 @@ typedef struct xfs_efi_log_format_64 {
* size is given by efd_nextents;
*/
typedef struct xfs_efd_log_format {
- unsigned short efd_type; /* efd log item type */
- unsigned short efd_size; /* size of this item */
- uint efd_nextents; /* # of extents freed */
+ __uint16_t efd_type; /* efd log item type */
+ __uint16_t efd_size; /* size of this item */
+ __uint32_t efd_nextents; /* # of extents freed */
__uint64_t efd_efi_id; /* id of corresponding efi */
xfs_extent_t efd_extents[1]; /* array of extents freed */
} xfs_efd_log_format_t;
+#ifndef HAVE_FORMAT32
typedef struct xfs_efd_log_format_32 {
- unsigned short efd_type; /* efd log item type */
- unsigned short efd_size; /* size of this item */
- uint efd_nextents; /* # of extents freed */
+ __uint16_t efd_type; /* efd log item type */
+ __uint16_t efd_size; /* size of this item */
+ __uint32_t efd_nextents; /* # of extents freed */
__uint64_t efd_efi_id; /* id of corresponding efi */
xfs_extent_32_t efd_extents[1]; /* array of extents freed */
} __attribute__((packed)) xfs_efd_log_format_32_t;
+#endif
typedef struct xfs_efd_log_format_64 {
- unsigned short efd_type; /* efd log item type */
- unsigned short efd_size; /* size of this item */
- uint efd_nextents; /* # of extents freed */
+ __uint16_t efd_type; /* efd log item type */
+ __uint16_t efd_size; /* size of this item */
+ __uint32_t efd_nextents; /* # of extents freed */
__uint64_t efd_efi_id; /* id of corresponding efi */
xfs_extent_64_t efd_extents[1]; /* array of extents freed */
} xfs_efd_log_format_64_t;
diff --git a/fs/xfs/xfs_fs.h b/fs/xfs/xfs_fs.h
index 0f0ad1535951..1335449841cd 100644
--- a/fs/xfs/xfs_fs.h
+++ b/fs/xfs/xfs_fs.h
@@ -22,8 +22,6 @@
* SGI's XFS filesystem's major stuff (constants, structures)
*/
-#define XFS_NAME "xfs"
-
/*
* Direct I/O attribute record used with XFS_IOC_DIOINFO
* d_miniosz is the min xfer size, xfer size multiple and file seek offset
@@ -426,11 +424,7 @@ typedef struct xfs_handle {
- (char *) &(handle)) \
+ (handle).ha_fid.xfs_fid_len)
-#define XFS_HANDLE_CMP(h1, h2) memcmp(h1, h2, sizeof(xfs_handle_t))
-
-#define FSHSIZE sizeof(fsid_t)
-
-/*
+/*
* Flags for going down operation
*/
#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index 33164a85aa9d..a446e5a115c6 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -458,7 +458,7 @@ nextag:
*/
if (XFS_FORCED_SHUTDOWN(mp)) {
up_read(&mp->m_peraglock);
- return (xfs_buf_t *)0;
+ return NULL;
}
agno++;
if (agno >= agcount)
@@ -466,7 +466,7 @@ nextag:
if (agno == pagno) {
if (flags == 0) {
up_read(&mp->m_peraglock);
- return (xfs_buf_t *)0;
+ return NULL;
}
flags = 0;
}
@@ -529,10 +529,10 @@ xfs_dialloc(
int offset; /* index of inode in chunk */
xfs_agino_t pagino; /* parent's a.g. relative inode # */
xfs_agnumber_t pagno; /* parent's allocation group number */
- xfs_inobt_rec_t rec; /* inode allocation record */
+ xfs_inobt_rec_incore_t rec; /* inode allocation record */
xfs_agnumber_t tagno; /* testing allocation group number */
xfs_btree_cur_t *tcur; /* temp cursor */
- xfs_inobt_rec_t trec; /* temp inode allocation record */
+ xfs_inobt_rec_incore_t trec; /* temp inode allocation record */
if (*IO_agbp == NULL) {
@@ -945,7 +945,7 @@ xfs_difree(
int ilen; /* inodes in an inode cluster */
xfs_mount_t *mp; /* mount structure for filesystem */
int off; /* offset of inode in inode chunk */
- xfs_inobt_rec_t rec; /* btree record */
+ xfs_inobt_rec_incore_t rec; /* btree record */
mp = tp->t_mountp;
@@ -1195,6 +1195,7 @@ xfs_dilocate(
"(0x%llx)",
ino, XFS_AGINO_TO_INO(mp, agno, agino));
}
+ xfs_stack_trace();
#endif /* DEBUG */
return XFS_ERROR(EINVAL);
}
diff --git a/fs/xfs/xfs_ialloc_btree.c b/fs/xfs/xfs_ialloc_btree.c
index 616eeeb6953e..8cdeeaf8632b 100644
--- a/fs/xfs/xfs_ialloc_btree.c
+++ b/fs/xfs/xfs_ialloc_btree.c
@@ -568,7 +568,7 @@ xfs_inobt_insrec(
/*
* Make a key out of the record data to be inserted, and save it.
*/
- key.ir_startino = recp->ir_startino; /* INT_: direct copy */
+ key.ir_startino = recp->ir_startino;
optr = ptr = cur->bc_ptrs[level];
/*
* If we're off the left edge, return failure.
@@ -600,7 +600,7 @@ xfs_inobt_insrec(
}
#endif
nbno = NULLAGBLOCK;
- ncur = (xfs_btree_cur_t *)0;
+ ncur = NULL;
/*
* If the block is full, we can't insert the new entry until we
* make the block un-full.
@@ -641,7 +641,7 @@ xfs_inobt_insrec(
return error;
#endif
ptr = cur->bc_ptrs[level];
- nrec.ir_startino = nkey.ir_startino; /* INT_: direct copy */
+ nrec.ir_startino = nkey.ir_startino;
} else {
/*
* Otherwise the insert fails.
@@ -681,7 +681,7 @@ xfs_inobt_insrec(
if ((error = xfs_btree_check_sptr(cur, *bnop, level)))
return error;
#endif
- kp[ptr - 1] = key; /* INT_: struct copy */
+ kp[ptr - 1] = key;
pp[ptr - 1] = cpu_to_be32(*bnop);
numrecs++;
block->bb_numrecs = cpu_to_be16(numrecs);
@@ -698,7 +698,7 @@ xfs_inobt_insrec(
* Now stuff the new record in, bump numrecs
* and log the new data.
*/
- rp[ptr - 1] = *recp; /* INT_: struct copy */
+ rp[ptr - 1] = *recp;
numrecs++;
block->bb_numrecs = cpu_to_be16(numrecs);
xfs_inobt_log_recs(cur, bp, ptr, numrecs);
@@ -731,7 +731,7 @@ xfs_inobt_insrec(
*/
*bnop = nbno;
if (nbno != NULLAGBLOCK) {
- *recp = nrec; /* INT_: struct copy */
+ *recp = nrec;
*curp = ncur;
}
*stat = 1;
@@ -878,7 +878,7 @@ xfs_inobt_lookup(
*/
bp = cur->bc_bufs[level];
if (bp && XFS_BUF_ADDR(bp) != d)
- bp = (xfs_buf_t *)0;
+ bp = NULL;
if (!bp) {
/*
* Need to get a new buffer. Read it, then
@@ -950,12 +950,12 @@ xfs_inobt_lookup(
xfs_inobt_key_t *kkp;
kkp = kkbase + keyno - 1;
- startino = INT_GET(kkp->ir_startino, ARCH_CONVERT);
+ startino = be32_to_cpu(kkp->ir_startino);
} else {
xfs_inobt_rec_t *krp;
krp = krbase + keyno - 1;
- startino = INT_GET(krp->ir_startino, ARCH_CONVERT);
+ startino = be32_to_cpu(krp->ir_startino);
}
/*
* Compute difference to get next direction.
@@ -1117,7 +1117,7 @@ xfs_inobt_lshift(
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*rpp), level)))
return error;
#endif
- *lpp = *rpp; /* INT_: no-change copy */
+ *lpp = *rpp;
xfs_inobt_log_ptrs(cur, lbp, nrec, nrec);
}
/*
@@ -1160,7 +1160,7 @@ xfs_inobt_lshift(
} else {
memmove(rrp, rrp + 1, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
- key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
+ key.ir_startino = rrp->ir_startino;
rkp = &key;
}
/*
@@ -1297,13 +1297,13 @@ xfs_inobt_newroot(
*/
kp = XFS_INOBT_KEY_ADDR(new, 1, cur);
if (be16_to_cpu(left->bb_level) > 0) {
- kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur); /* INT_: struct copy */
- kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur); /* INT_: struct copy */
+ kp[0] = *XFS_INOBT_KEY_ADDR(left, 1, cur);
+ kp[1] = *XFS_INOBT_KEY_ADDR(right, 1, cur);
} else {
rp = XFS_INOBT_REC_ADDR(left, 1, cur);
- INT_COPY(kp[0].ir_startino, rp->ir_startino, ARCH_CONVERT);
+ kp[0].ir_startino = rp->ir_startino;
rp = XFS_INOBT_REC_ADDR(right, 1, cur);
- INT_COPY(kp[1].ir_startino, rp->ir_startino, ARCH_CONVERT);
+ kp[1].ir_startino = rp->ir_startino;
}
xfs_inobt_log_keys(cur, nbp, 1, 2);
/*
@@ -1410,8 +1410,8 @@ xfs_inobt_rshift(
if ((error = xfs_btree_check_sptr(cur, be32_to_cpu(*lpp), level)))
return error;
#endif
- *rkp = *lkp; /* INT_: no change copy */
- *rpp = *lpp; /* INT_: no change copy */
+ *rkp = *lkp;
+ *rpp = *lpp;
xfs_inobt_log_keys(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
xfs_inobt_log_ptrs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
} else {
@@ -1420,7 +1420,7 @@ xfs_inobt_rshift(
memmove(rrp + 1, rrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
*rrp = *lrp;
xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs) + 1);
- key.ir_startino = rrp->ir_startino; /* INT_: direct copy */
+ key.ir_startino = rrp->ir_startino;
rkp = &key;
}
/*
@@ -1559,7 +1559,7 @@ xfs_inobt_split(
rrp = XFS_INOBT_REC_ADDR(right, 1, cur);
memcpy(rrp, lrp, be16_to_cpu(right->bb_numrecs) * sizeof(*rrp));
xfs_inobt_log_recs(cur, rbp, 1, be16_to_cpu(right->bb_numrecs));
- keyp->ir_startino = rrp->ir_startino; /* INT_: direct copy */
+ keyp->ir_startino = rrp->ir_startino;
}
/*
* Find the left block number by looking in the buffer.
@@ -1813,9 +1813,9 @@ xfs_inobt_get_rec(
* Point to the record and extract its data.
*/
rec = XFS_INOBT_REC_ADDR(block, ptr, cur);
- *ino = INT_GET(rec->ir_startino, ARCH_CONVERT);
- *fcnt = INT_GET(rec->ir_freecount, ARCH_CONVERT);
- *free = INT_GET(rec->ir_free, ARCH_CONVERT);
+ *ino = be32_to_cpu(rec->ir_startino);
+ *fcnt = be32_to_cpu(rec->ir_freecount);
+ *free = be64_to_cpu(rec->ir_free);
*stat = 1;
return 0;
}
@@ -1930,10 +1930,10 @@ xfs_inobt_insert(
level = 0;
nbno = NULLAGBLOCK;
- INT_SET(nrec.ir_startino, ARCH_CONVERT, cur->bc_rec.i.ir_startino);
- INT_SET(nrec.ir_freecount, ARCH_CONVERT, cur->bc_rec.i.ir_freecount);
- INT_SET(nrec.ir_free, ARCH_CONVERT, cur->bc_rec.i.ir_free);
- ncur = (xfs_btree_cur_t *)0;
+ nrec.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino);
+ nrec.ir_freecount = cpu_to_be32(cur->bc_rec.i.ir_freecount);
+ nrec.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free);
+ ncur = NULL;
pcur = cur;
/*
* Loop going up the tree, starting at the leaf level.
@@ -1965,7 +1965,7 @@ xfs_inobt_insert(
*/
if (ncur) {
pcur = ncur;
- ncur = (xfs_btree_cur_t *)0;
+ ncur = NULL;
}
} while (nbno != NULLAGBLOCK);
*stat = i;
@@ -2060,9 +2060,9 @@ xfs_inobt_update(
/*
* Fill in the new contents and log them.
*/
- INT_SET(rp->ir_startino, ARCH_CONVERT, ino);
- INT_SET(rp->ir_freecount, ARCH_CONVERT, fcnt);
- INT_SET(rp->ir_free, ARCH_CONVERT, free);
+ rp->ir_startino = cpu_to_be32(ino);
+ rp->ir_freecount = cpu_to_be32(fcnt);
+ rp->ir_free = cpu_to_be64(free);
xfs_inobt_log_recs(cur, bp, ptr, ptr);
/*
* Updating first record in leaf. Pass new key value up to our parent.
@@ -2070,7 +2070,7 @@ xfs_inobt_update(
if (ptr == 1) {
xfs_inobt_key_t key; /* key containing [ino] */
- INT_SET(key.ir_startino, ARCH_CONVERT, ino);
+ key.ir_startino = cpu_to_be32(ino);
if ((error = xfs_inobt_updkey(cur, &key, 1)))
return error;
}
diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h
index ae3904cb1ee8..2c0e49893ff7 100644
--- a/fs/xfs/xfs_ialloc_btree.h
+++ b/fs/xfs/xfs_ialloc_btree.h
@@ -47,19 +47,24 @@ static inline xfs_inofree_t xfs_inobt_maskn(int i, int n)
/*
* Data record structure
*/
-typedef struct xfs_inobt_rec
-{
+typedef struct xfs_inobt_rec {
+ __be32 ir_startino; /* starting inode number */
+ __be32 ir_freecount; /* count of free inodes (set bits) */
+ __be64 ir_free; /* free inode mask */
+} xfs_inobt_rec_t;
+
+typedef struct xfs_inobt_rec_incore {
xfs_agino_t ir_startino; /* starting inode number */
__int32_t ir_freecount; /* count of free inodes (set bits) */
xfs_inofree_t ir_free; /* free inode mask */
-} xfs_inobt_rec_t;
+} xfs_inobt_rec_incore_t;
+
/*
* Key structure
*/
-typedef struct xfs_inobt_key
-{
- xfs_agino_t ir_startino; /* starting inode number */
+typedef struct xfs_inobt_key {
+ __be32 ir_startino; /* starting inode number */
} xfs_inobt_key_t;
/* btree pointer type */
@@ -77,7 +82,7 @@ typedef struct xfs_btree_sblock xfs_inobt_block_t;
#define XFS_INOBT_IS_FREE(rp,i) \
(((rp)->ir_free & XFS_INOBT_MASK(i)) != 0)
#define XFS_INOBT_IS_FREE_DISK(rp,i) \
- ((INT_GET((rp)->ir_free,ARCH_CONVERT) & XFS_INOBT_MASK(i)) != 0)
+ ((be64_to_cpu((rp)->ir_free) & XFS_INOBT_MASK(i)) != 0)
#define XFS_INOBT_SET_FREE(rp,i) ((rp)->ir_free |= XFS_INOBT_MASK(i))
#define XFS_INOBT_CLR_FREE(rp,i) ((rp)->ir_free &= ~XFS_INOBT_MASK(i))
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 0724df7fabb7..b73d216ecaf9 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -50,7 +50,7 @@ void
xfs_ihash_init(xfs_mount_t *mp)
{
__uint64_t icount;
- uint i, flags = KM_SLEEP | KM_MAYFAIL;
+ uint i;
if (!mp->m_ihsize) {
icount = mp->m_maxicount ? mp->m_maxicount :
@@ -61,14 +61,13 @@ xfs_ihash_init(xfs_mount_t *mp)
(64 * NBPP) / sizeof(xfs_ihash_t));
}
- while (!(mp->m_ihash = (xfs_ihash_t *)kmem_zalloc(mp->m_ihsize *
- sizeof(xfs_ihash_t), flags))) {
- if ((mp->m_ihsize >>= 1) <= NBPP)
- flags = KM_SLEEP;
- }
- for (i = 0; i < mp->m_ihsize; i++) {
+ mp->m_ihash = kmem_zalloc_greedy(&mp->m_ihsize,
+ NBPC * sizeof(xfs_ihash_t),
+ mp->m_ihsize * sizeof(xfs_ihash_t),
+ KM_SLEEP | KM_MAYFAIL | KM_LARGE);
+ mp->m_ihsize /= sizeof(xfs_ihash_t);
+ for (i = 0; i < mp->m_ihsize; i++)
rwlock_init(&(mp->m_ihash[i].ih_lock));
- }
}
/*
@@ -77,7 +76,7 @@ xfs_ihash_init(xfs_mount_t *mp)
void
xfs_ihash_free(xfs_mount_t *mp)
{
- kmem_free(mp->m_ihash, mp->m_ihsize*sizeof(xfs_ihash_t));
+ kmem_free(mp->m_ihash, mp->m_ihsize * sizeof(xfs_ihash_t));
mp->m_ihash = NULL;
}
@@ -95,7 +94,7 @@ xfs_chash_init(xfs_mount_t *mp)
mp->m_chsize = min_t(uint, mp->m_chsize, mp->m_ihsize);
mp->m_chash = (xfs_chash_t *)kmem_zalloc(mp->m_chsize
* sizeof(xfs_chash_t),
- KM_SLEEP);
+ KM_SLEEP | KM_LARGE);
for (i = 0; i < mp->m_chsize; i++) {
spinlock_init(&mp->m_chash[i].ch_lock,"xfshash");
}
@@ -244,7 +243,9 @@ again:
XFS_STATS_INC(xs_ig_found);
+ spin_lock(&ip->i_flags_lock);
ip->i_flags &= ~XFS_IRECLAIMABLE;
+ spin_unlock(&ip->i_flags_lock);
version = ih->ih_version;
read_unlock(&ih->ih_lock);
xfs_ihash_promote(ih, ip, version);
@@ -290,15 +291,17 @@ again:
finish_inode:
if (ip->i_d.di_mode == 0) {
- if (!(flags & IGET_CREATE))
+ if (!(flags & XFS_IGET_CREATE))
return ENOENT;
xfs_iocore_inode_reinit(ip);
}
-
+
if (lock_flags != 0)
xfs_ilock(ip, lock_flags);
+ spin_lock(&ip->i_flags_lock);
ip->i_flags &= ~XFS_ISTALE;
+ spin_unlock(&ip->i_flags_lock);
vn_trace_exit(vp, "xfs_iget.found",
(inst_t *)__return_address);
@@ -320,21 +323,20 @@ finish_inode:
* Read the disk inode attributes into a new inode structure and get
* a new vnode for it. This should also initialize i_ino and i_mount.
*/
- error = xfs_iread(mp, tp, ino, &ip, bno);
- if (error) {
+ error = xfs_iread(mp, tp, ino, &ip, bno,
+ (flags & XFS_IGET_BULKSTAT) ? XFS_IMAP_BULKSTAT : 0);
+ if (error)
return error;
- }
vn_trace_exit(vp, "xfs_iget.alloc", (inst_t *)__return_address);
xfs_inode_lock_init(ip, vp);
xfs_iocore_inode_init(ip);
- if (lock_flags != 0) {
+ if (lock_flags)
xfs_ilock(ip, lock_flags);
- }
-
- if ((ip->i_d.di_mode == 0) && !(flags & IGET_CREATE)) {
+
+ if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {
xfs_idestroy(ip);
return ENOENT;
}
@@ -369,7 +371,9 @@ finish_inode:
ih->ih_next = ip;
ip->i_udquot = ip->i_gdquot = NULL;
ih->ih_version++;
+ spin_lock(&ip->i_flags_lock);
ip->i_flags |= XFS_INEW;
+ spin_unlock(&ip->i_flags_lock);
write_unlock(&ih->ih_lock);
@@ -548,7 +552,7 @@ xfs_inode_lock_init(
mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", vp->v_number);
init_waitqueue_head(&ip->i_ipin_wait);
atomic_set(&ip->i_pincount, 0);
- init_sema(&ip->i_flock, 1, "xfsfino", vp->v_number);
+ initnsema(&ip->i_flock, 1, "xfsfino");
}
/*
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 1f8ecff8553a..c27d7d495aa0 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -854,7 +854,8 @@ xfs_iread(
xfs_trans_t *tp,
xfs_ino_t ino,
xfs_inode_t **ipp,
- xfs_daddr_t bno)
+ xfs_daddr_t bno,
+ uint imap_flags)
{
xfs_buf_t *bp;
xfs_dinode_t *dip;
@@ -866,6 +867,7 @@ xfs_iread(
ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP);
ip->i_ino = ino;
ip->i_mount = mp;
+ spin_lock_init(&ip->i_flags_lock);
/*
* Get pointer's to the on-disk inode and the buffer containing it.
@@ -874,7 +876,7 @@ xfs_iread(
* return NULL as well. Set i_blkno to 0 so that xfs_itobp() will
* know that this is a new incore inode.
*/
- error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, 0);
+ error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, imap_flags);
if (error) {
kmem_zone_free(xfs_inode_zone, ip);
return error;
@@ -1113,7 +1115,7 @@ xfs_ialloc(
* to prevent others from looking at until we're done.
*/
error = xfs_trans_iget(tp->t_mountp, tp, ino,
- IGET_CREATE, XFS_ILOCK_EXCL, &ip);
+ XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip);
if (error != 0) {
return error;
}
@@ -2213,7 +2215,9 @@ xfs_ifree_cluster(
if (ip == free_ip) {
if (xfs_iflock_nowait(ip)) {
+ spin_lock(&ip->i_flags_lock);
ip->i_flags |= XFS_ISTALE;
+ spin_unlock(&ip->i_flags_lock);
if (xfs_inode_clean(ip)) {
xfs_ifunlock(ip);
@@ -2227,7 +2231,9 @@ xfs_ifree_cluster(
if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
if (xfs_iflock_nowait(ip)) {
+ spin_lock(&ip->i_flags_lock);
ip->i_flags |= XFS_ISTALE;
+ spin_unlock(&ip->i_flags_lock);
if (xfs_inode_clean(ip)) {
xfs_ifunlock(ip);
@@ -2257,7 +2263,9 @@ xfs_ifree_cluster(
AIL_LOCK(mp,s);
iip->ili_flush_lsn = iip->ili_item.li_lsn;
AIL_UNLOCK(mp, s);
+ spin_lock(&iip->ili_inode->i_flags_lock);
iip->ili_inode->i_flags |= XFS_ISTALE;
+ spin_unlock(&iip->ili_inode->i_flags_lock);
pre_flushed++;
}
lip = lip->li_bio_list;
@@ -2753,19 +2761,29 @@ xfs_iunpin(
* call as the inode reclaim may be blocked waiting for
* the inode to become unpinned.
*/
+ struct inode *inode = NULL;
+
+ spin_lock(&ip->i_flags_lock);
if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) {
bhv_vnode_t *vp = XFS_ITOV_NULL(ip);
/* make sync come back and flush this inode */
if (vp) {
- struct inode *inode = vn_to_inode(vp);
+ inode = vn_to_inode(vp);
if (!(inode->i_state &
- (I_NEW|I_FREEING|I_CLEAR)))
- mark_inode_dirty_sync(inode);
+ (I_NEW|I_FREEING|I_CLEAR))) {
+ inode = igrab(inode);
+ if (inode)
+ mark_inode_dirty_sync(inode);
+ } else
+ inode = NULL;
}
}
+ spin_unlock(&ip->i_flags_lock);
wake_up(&ip->i_ipin_wait);
+ if (inode)
+ iput(inode);
}
}
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index d10b76ed1e5b..e96eb0835fe6 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -267,6 +267,7 @@ typedef struct xfs_inode {
sema_t i_flock; /* inode flush lock */
atomic_t i_pincount; /* inode pin count */
wait_queue_head_t i_ipin_wait; /* inode pinning wait queue */
+ spinlock_t i_flags_lock; /* inode i_flags lock */
#ifdef HAVE_REFCACHE
struct xfs_inode **i_refcache; /* ptr to entry in ref cache */
struct xfs_inode *i_release; /* inode to unref */
@@ -389,11 +390,14 @@ typedef struct xfs_inode {
(((vfsp)->vfs_flag & VFS_GRPID) || ((pip)->i_d.di_mode & S_ISGID))
/*
- * xfs_iget.c prototypes.
+ * Flags for xfs_iget()
*/
+#define XFS_IGET_CREATE 0x1
+#define XFS_IGET_BULKSTAT 0x2
-#define IGET_CREATE 1
-
+/*
+ * xfs_iget.c prototypes.
+ */
void xfs_ihash_init(struct xfs_mount *);
void xfs_ihash_free(struct xfs_mount *);
void xfs_chash_init(struct xfs_mount *);
@@ -425,7 +429,7 @@ int xfs_itobp(struct xfs_mount *, struct xfs_trans *,
xfs_inode_t *, xfs_dinode_t **, struct xfs_buf **,
xfs_daddr_t, uint);
int xfs_iread(struct xfs_mount *, struct xfs_trans *, xfs_ino_t,
- xfs_inode_t **, xfs_daddr_t);
+ xfs_inode_t **, xfs_daddr_t, uint);
int xfs_iread_extents(struct xfs_trans *, xfs_inode_t *, int);
int xfs_ialloc(struct xfs_trans *, xfs_inode_t *, mode_t,
xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t,
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index f8e80d8e7237..a7a92251eb56 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -743,21 +743,6 @@ xfs_inode_item_committed(
}
/*
- * The transaction with the inode locked has aborted. The inode
- * must not be dirty within the transaction (unless we're forcibly
- * shutting down). We simply unlock just as if the transaction
- * had been cancelled.
- */
-STATIC void
-xfs_inode_item_abort(
- xfs_inode_log_item_t *iip)
-{
- xfs_inode_item_unlock(iip);
- return;
-}
-
-
-/*
* This gets called by xfs_trans_push_ail(), when IOP_TRYLOCK
* failed to get the inode flush lock but did get the inode locked SHARED.
* Here we're trying to see if the inode buffer is incore, and if so whether it's
@@ -915,7 +900,6 @@ STATIC struct xfs_item_ops xfs_inode_item_ops = {
.iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_inode_item_committed,
.iop_push = (void(*)(xfs_log_item_t*))xfs_inode_item_push,
- .iop_abort = (void(*)(xfs_log_item_t*))xfs_inode_item_abort,
.iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_inode_item_pushbuf,
.iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t))
xfs_inode_item_committing
diff --git a/fs/xfs/xfs_inode_item.h b/fs/xfs/xfs_inode_item.h
index 5db6cd1b4cf3..bfe92ea17952 100644
--- a/fs/xfs/xfs_inode_item.h
+++ b/fs/xfs/xfs_inode_item.h
@@ -25,52 +25,54 @@
* must be added on to the end.
*/
typedef struct xfs_inode_log_format {
- unsigned short ilf_type; /* inode log item type */
- unsigned short ilf_size; /* size of this item */
- uint ilf_fields; /* flags for fields logged */
- ushort ilf_asize; /* size of attr d/ext/root */
- ushort ilf_dsize; /* size of data/ext/root */
- xfs_ino_t ilf_ino; /* inode number */
+ __uint16_t ilf_type; /* inode log item type */
+ __uint16_t ilf_size; /* size of this item */
+ __uint32_t ilf_fields; /* flags for fields logged */
+ __uint16_t ilf_asize; /* size of attr d/ext/root */
+ __uint16_t ilf_dsize; /* size of data/ext/root */
+ __uint64_t ilf_ino; /* inode number */
union {
- xfs_dev_t ilfu_rdev; /* rdev value for dev inode*/
+ __uint32_t ilfu_rdev; /* rdev value for dev inode*/
uuid_t ilfu_uuid; /* mount point value */
} ilf_u;
__int64_t ilf_blkno; /* blkno of inode buffer */
- int ilf_len; /* len of inode buffer */
- int ilf_boffset; /* off of inode in buffer */
+ __int32_t ilf_len; /* len of inode buffer */
+ __int32_t ilf_boffset; /* off of inode in buffer */
} xfs_inode_log_format_t;
+#ifndef HAVE_FORMAT32
typedef struct xfs_inode_log_format_32 {
- unsigned short ilf_type; /* 16: inode log item type */
- unsigned short ilf_size; /* 16: size of this item */
- uint ilf_fields; /* 32: flags for fields logged */
- ushort ilf_asize; /* 32: size of attr d/ext/root */
- ushort ilf_dsize; /* 32: size of data/ext/root */
- xfs_ino_t ilf_ino; /* 64: inode number */
+ __uint16_t ilf_type; /* inode log item type */
+ __uint16_t ilf_size; /* size of this item */
+ __uint32_t ilf_fields; /* flags for fields logged */
+ __uint16_t ilf_asize; /* size of attr d/ext/root */
+ __uint16_t ilf_dsize; /* size of data/ext/root */
+ __uint64_t ilf_ino; /* inode number */
union {
- xfs_dev_t ilfu_rdev; /* 32: rdev value for dev inode*/
- uuid_t ilfu_uuid; /* 128: mount point value */
+ __uint32_t ilfu_rdev; /* rdev value for dev inode*/
+ uuid_t ilfu_uuid; /* mount point value */
} ilf_u;
- __int64_t ilf_blkno; /* 64: blkno of inode buffer */
- int ilf_len; /* 32: len of inode buffer */
- int ilf_boffset; /* 32: off of inode in buffer */
+ __int64_t ilf_blkno; /* blkno of inode buffer */
+ __int32_t ilf_len; /* len of inode buffer */
+ __int32_t ilf_boffset; /* off of inode in buffer */
} __attribute__((packed)) xfs_inode_log_format_32_t;
+#endif
typedef struct xfs_inode_log_format_64 {
- unsigned short ilf_type; /* 16: inode log item type */
- unsigned short ilf_size; /* 16: size of this item */
- uint ilf_fields; /* 32: flags for fields logged */
- ushort ilf_asize; /* 32: size of attr d/ext/root */
- ushort ilf_dsize; /* 32: size of data/ext/root */
- __uint32_t ilf_pad; /* 32: pad for 64 bit boundary */
- xfs_ino_t ilf_ino; /* 64: inode number */
+ __uint16_t ilf_type; /* inode log item type */
+ __uint16_t ilf_size; /* size of this item */
+ __uint32_t ilf_fields; /* flags for fields logged */
+ __uint16_t ilf_asize; /* size of attr d/ext/root */
+ __uint16_t ilf_dsize; /* size of data/ext/root */
+ __uint32_t ilf_pad; /* pad for 64 bit boundary */
+ __uint64_t ilf_ino; /* inode number */
union {
- xfs_dev_t ilfu_rdev; /* 32: rdev value for dev inode*/
- uuid_t ilfu_uuid; /* 128: mount point value */
+ __uint32_t ilfu_rdev; /* rdev value for dev inode*/
+ uuid_t ilfu_uuid; /* mount point value */
} ilf_u;
- __int64_t ilf_blkno; /* 64: blkno of inode buffer */
- int ilf_len; /* 32: len of inode buffer */
- int ilf_boffset; /* 32: off of inode in buffer */
+ __int64_t ilf_blkno; /* blkno of inode buffer */
+ __int32_t ilf_len; /* len of inode buffer */
+ __int32_t ilf_boffset; /* off of inode in buffer */
} xfs_inode_log_format_64_t;
/*
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index f1949c16df15..19655124da78 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -398,6 +398,23 @@ xfs_flush_space(
return 1;
}
+STATIC int
+xfs_cmn_err_fsblock_zero(
+ xfs_inode_t *ip,
+ xfs_bmbt_irec_t *imap)
+{
+ xfs_cmn_err(XFS_PTAG_FSBLOCK_ZERO, CE_ALERT, ip->i_mount,
+ "Access to block zero in inode %llu "
+ "start_block: %llx start_off: %llx "
+ "blkcnt: %llx extent-state: %x\n",
+ (unsigned long long)ip->i_ino,
+ (unsigned long long)imap->br_startblock,
+ (unsigned long long)imap->br_startoff,
+ (unsigned long long)imap->br_blockcount,
+ imap->br_state);
+ return EFSCORRUPTED;
+}
+
int
xfs_iomap_write_direct(
xfs_inode_t *ip,
@@ -536,23 +553,17 @@ xfs_iomap_write_direct(
* Copy any maps to caller's array and return any error.
*/
if (nimaps == 0) {
- error = (ENOSPC);
+ error = ENOSPC;
+ goto error_out;
+ }
+
+ if (unlikely(!imap.br_startblock && !(io->io_flags & XFS_IOCORE_RT))) {
+ error = xfs_cmn_err_fsblock_zero(ip, &imap);
goto error_out;
}
*ret_imap = imap;
*nmaps = 1;
- if ( !(io->io_flags & XFS_IOCORE_RT) && !ret_imap->br_startblock) {
- cmn_err(CE_PANIC,"Access to block zero: fs <%s> inode: %lld "
- "start_block : %llx start_off : %llx blkcnt : %llx "
- "extent-state : %x \n",
- (ip->i_mount)->m_fsname,
- (long long)ip->i_ino,
- (unsigned long long)ret_imap->br_startblock,
- (unsigned long long)ret_imap->br_startoff,
- (unsigned long long)ret_imap->br_blockcount,
- ret_imap->br_state);
- }
return 0;
error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */
@@ -715,17 +726,8 @@ retry:
goto retry;
}
- if (!(io->io_flags & XFS_IOCORE_RT) && !ret_imap->br_startblock) {
- cmn_err(CE_PANIC,"Access to block zero: fs <%s> inode: %lld "
- "start_block : %llx start_off : %llx blkcnt : %llx "
- "extent-state : %x \n",
- (ip->i_mount)->m_fsname,
- (long long)ip->i_ino,
- (unsigned long long)ret_imap->br_startblock,
- (unsigned long long)ret_imap->br_startoff,
- (unsigned long long)ret_imap->br_blockcount,
- ret_imap->br_state);
- }
+ if (unlikely(!imap[0].br_startblock && !(io->io_flags & XFS_IOCORE_RT)))
+ return xfs_cmn_err_fsblock_zero(ip, &imap[0]);
*ret_imap = imap[0];
*nmaps = 1;
@@ -853,24 +855,10 @@ xfs_iomap_write_allocate(
* See if we were able to allocate an extent that
* covers at least part of the callers request
*/
-
for (i = 0; i < nimaps; i++) {
- if (!(io->io_flags & XFS_IOCORE_RT) &&
- !imap[i].br_startblock) {
- cmn_err(CE_PANIC,"Access to block zero: "
- "fs <%s> inode: %lld "
- "start_block : %llx start_off : %llx "
- "blkcnt : %llx extent-state : %x \n",
- (ip->i_mount)->m_fsname,
- (long long)ip->i_ino,
- (unsigned long long)
- imap[i].br_startblock,
- (unsigned long long)
- imap[i].br_startoff,
- (unsigned long long)
- imap[i].br_blockcount,
- imap[i].br_state);
- }
+ if (unlikely(!imap[i].br_startblock &&
+ !(io->io_flags & XFS_IOCORE_RT)))
+ return xfs_cmn_err_fsblock_zero(ip, &imap[i]);
if ((offset_fsb >= imap[i].br_startoff) &&
(offset_fsb < (imap[i].br_startoff +
imap[i].br_blockcount))) {
@@ -941,7 +929,7 @@ xfs_iomap_write_unwritten(
XFS_WRITE_LOG_COUNT);
if (error) {
xfs_trans_cancel(tp, 0);
- goto error0;
+ return XFS_ERROR(error);
}
xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -967,19 +955,11 @@ xfs_iomap_write_unwritten(
error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
xfs_iunlock(ip, XFS_ILOCK_EXCL);
if (error)
- goto error0;
-
- if ( !(io->io_flags & XFS_IOCORE_RT) && !imap.br_startblock) {
- cmn_err(CE_PANIC,"Access to block zero: fs <%s> "
- "inode: %lld start_block : %llx start_off : "
- "%llx blkcnt : %llx extent-state : %x \n",
- (ip->i_mount)->m_fsname,
- (long long)ip->i_ino,
- (unsigned long long)imap.br_startblock,
- (unsigned long long)imap.br_startoff,
- (unsigned long long)imap.br_blockcount,
- imap.br_state);
- }
+ return XFS_ERROR(error);
+
+ if (unlikely(!imap.br_startblock &&
+ !(io->io_flags & XFS_IOCORE_RT)))
+ return xfs_cmn_err_fsblock_zero(ip, &imap);
if ((numblks_fsb = imap.br_blockcount) == 0) {
/*
@@ -999,6 +979,5 @@ error_on_bmapi_transaction:
xfs_bmap_cancel(&free_list);
xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT));
xfs_iunlock(ip, XFS_ILOCK_EXCL);
-error0:
return XFS_ERROR(error);
}
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 46249e4d1fea..7775ddc0b3c6 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -39,6 +39,16 @@
#include "xfs_error.h"
#include "xfs_btree.h"
+int
+xfs_internal_inum(
+ xfs_mount_t *mp,
+ xfs_ino_t ino)
+{
+ return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
+ (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
+ (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino)));
+}
+
STATIC int
xfs_bulkstat_one_iget(
xfs_mount_t *mp, /* mount point for filesystem */
@@ -52,7 +62,8 @@ xfs_bulkstat_one_iget(
bhv_vnode_t *vp;
int error;
- error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno);
+ error = xfs_iget(mp, NULL, ino,
+ XFS_IGET_BULKSTAT, XFS_ILOCK_SHARED, &ip, bno);
if (error) {
*stat = BULKSTAT_RV_NOTHING;
return error;
@@ -212,17 +223,12 @@ xfs_bulkstat_one(
xfs_dinode_t *dip; /* dinode inode pointer */
dip = (xfs_dinode_t *)dibuff;
+ *stat = BULKSTAT_RV_NOTHING;
- if (!buffer || ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
- (XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
- (ino == mp->m_sb.sb_uquotino || ino == mp->m_sb.sb_gquotino))) {
- *stat = BULKSTAT_RV_NOTHING;
+ if (!buffer || xfs_internal_inum(mp, ino))
return XFS_ERROR(EINVAL);
- }
- if (ubsize < sizeof(*buf)) {
- *stat = BULKSTAT_RV_NOTHING;
+ if (ubsize < sizeof(*buf))
return XFS_ERROR(ENOMEM);
- }
buf = kmem_alloc(sizeof(*buf), KM_SLEEP);
@@ -238,8 +244,7 @@ xfs_bulkstat_one(
}
if (copy_to_user(buffer, buf, sizeof(*buf))) {
- *stat = BULKSTAT_RV_NOTHING;
- error = EFAULT;
+ error = EFAULT;
goto out_free;
}
@@ -253,6 +258,46 @@ xfs_bulkstat_one(
}
/*
+ * Test to see whether we can use the ondisk inode directly, based
+ * on the given bulkstat flags, filling in dipp accordingly.
+ * Returns zero if the inode is dodgey.
+ */
+STATIC int
+xfs_bulkstat_use_dinode(
+ xfs_mount_t *mp,
+ int flags,
+ xfs_buf_t *bp,
+ int clustidx,
+ xfs_dinode_t **dipp)
+{
+ xfs_dinode_t *dip;
+ unsigned int aformat;
+
+ *dipp = NULL;
+ if (!bp || (flags & BULKSTAT_FG_IGET))
+ return 1;
+ dip = (xfs_dinode_t *)
+ xfs_buf_offset(bp, clustidx << mp->m_sb.sb_inodelog);
+ if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT) != XFS_DINODE_MAGIC ||
+ !XFS_DINODE_GOOD_VERSION(
+ INT_GET(dip->di_core.di_version, ARCH_CONVERT)))
+ return 0;
+ if (flags & BULKSTAT_FG_QUICK) {
+ *dipp = dip;
+ return 1;
+ }
+ /* BULKSTAT_FG_INLINE: if attr fork is local, or not there, use it */
+ aformat = INT_GET(dip->di_core.di_aformat, ARCH_CONVERT);
+ if ((XFS_CFORK_Q(&dip->di_core) == 0) ||
+ (aformat == XFS_DINODE_FMT_LOCAL) ||
+ (aformat == XFS_DINODE_FMT_EXTENTS && !dip->di_core.di_anextents)) {
+ *dipp = dip;
+ return 1;
+ }
+ return 1;
+}
+
+/*
* Return stat information in bulk (by-inode) for the filesystem.
*/
int /* error status */
@@ -284,10 +329,11 @@ xfs_bulkstat(
xfs_agino_t gino; /* current btree rec's start inode */
int i; /* loop index */
int icount; /* count of inodes good in irbuf */
+ size_t irbsize; /* size of irec buffer in bytes */
xfs_ino_t ino; /* inode number (filesystem) */
- xfs_inobt_rec_t *irbp; /* current irec buffer pointer */
- xfs_inobt_rec_t *irbuf; /* start of irec buffer */
- xfs_inobt_rec_t *irbufend; /* end of good irec buffer entries */
+ xfs_inobt_rec_incore_t *irbp; /* current irec buffer pointer */
+ xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */
+ xfs_inobt_rec_incore_t *irbufend; /* end of good irec buffer entries */
xfs_ino_t lastino=0; /* last inode number returned */
int nbcluster; /* # of blocks in a cluster */
int nicluster; /* # of inodes in a cluster */
@@ -328,13 +374,10 @@ xfs_bulkstat(
(XFS_INODE_CLUSTER_SIZE(mp) >> mp->m_sb.sb_inodelog);
nimask = ~(nicluster - 1);
nbcluster = nicluster >> mp->m_sb.sb_inopblog;
- /*
- * Allocate a page-sized buffer for inode btree records.
- * We could try allocating something smaller, but for normal
- * calls we'll always (potentially) need the whole page.
- */
- irbuf = kmem_alloc(NBPC, KM_SLEEP);
- nirbuf = NBPC / sizeof(*irbuf);
+ irbuf = kmem_zalloc_greedy(&irbsize, NBPC, NBPC * 4,
+ KM_SLEEP | KM_MAYFAIL | KM_LARGE);
+ nirbuf = irbsize / sizeof(*irbuf);
+
/*
* Loop over the allocation groups, starting from the last
* inode returned; 0 means start of the allocation group.
@@ -358,7 +401,7 @@ xfs_bulkstat(
* Allocate and initialize a btree cursor for ialloc btree.
*/
cur = xfs_btree_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_INO,
- (xfs_inode_t *)0, 0);
+ (xfs_inode_t *)0, 0);
irbp = irbuf;
irbufend = irbuf + nirbuf;
end_of_ag = 0;
@@ -395,9 +438,9 @@ xfs_bulkstat(
gcnt++;
}
gfree |= XFS_INOBT_MASKN(0, chunkidx);
- INT_SET(irbp->ir_startino, ARCH_CONVERT, gino);
- INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt);
- INT_SET(irbp->ir_free, ARCH_CONVERT, gfree);
+ irbp->ir_startino = gino;
+ irbp->ir_freecount = gcnt;
+ irbp->ir_free = gfree;
irbp++;
agino = gino + XFS_INODES_PER_CHUNK;
icount = XFS_INODES_PER_CHUNK - gcnt;
@@ -451,11 +494,27 @@ xfs_bulkstat(
}
/*
* If this chunk has any allocated inodes, save it.
+ * Also start read-ahead now for this chunk.
*/
if (gcnt < XFS_INODES_PER_CHUNK) {
- INT_SET(irbp->ir_startino, ARCH_CONVERT, gino);
- INT_SET(irbp->ir_freecount, ARCH_CONVERT, gcnt);
- INT_SET(irbp->ir_free, ARCH_CONVERT, gfree);
+ /*
+ * Loop over all clusters in the next chunk.
+ * Do a readahead if there are any allocated
+ * inodes in that cluster.
+ */
+ for (agbno = XFS_AGINO_TO_AGBNO(mp, gino),
+ chunkidx = 0;
+ chunkidx < XFS_INODES_PER_CHUNK;
+ chunkidx += nicluster,
+ agbno += nbcluster) {
+ if (XFS_INOBT_MASKN(chunkidx,
+ nicluster) & ~gfree)
+ xfs_btree_reada_bufs(mp, agno,
+ agbno, nbcluster);
+ }
+ irbp->ir_startino = gino;
+ irbp->ir_freecount = gcnt;
+ irbp->ir_free = gfree;
irbp++;
icount += XFS_INODES_PER_CHUNK - gcnt;
}
@@ -479,33 +538,11 @@ xfs_bulkstat(
for (irbp = irbuf;
irbp < irbufend && ubleft >= statstruct_size; irbp++) {
/*
- * Read-ahead the next chunk's worth of inodes.
- */
- if (&irbp[1] < irbufend) {
- /*
- * Loop over all clusters in the next chunk.
- * Do a readahead if there are any allocated
- * inodes in that cluster.
- */
- for (agbno = XFS_AGINO_TO_AGBNO(mp,
- INT_GET(irbp[1].ir_startino, ARCH_CONVERT)),
- chunkidx = 0;
- chunkidx < XFS_INODES_PER_CHUNK;
- chunkidx += nicluster,
- agbno += nbcluster) {
- if (XFS_INOBT_MASKN(chunkidx,
- nicluster) &
- ~(INT_GET(irbp[1].ir_free, ARCH_CONVERT)))
- xfs_btree_reada_bufs(mp, agno,
- agbno, nbcluster);
- }
- }
- /*
* Now process this chunk of inodes.
*/
- for (agino = INT_GET(irbp->ir_startino, ARCH_CONVERT), chunkidx = 0, clustidx = 0;
+ for (agino = irbp->ir_startino, chunkidx = clustidx = 0;
ubleft > 0 &&
- INT_GET(irbp->ir_freecount, ARCH_CONVERT) < XFS_INODES_PER_CHUNK;
+ irbp->ir_freecount < XFS_INODES_PER_CHUNK;
chunkidx++, clustidx++, agino++) {
ASSERT(chunkidx < XFS_INODES_PER_CHUNK);
/*
@@ -525,11 +562,12 @@ xfs_bulkstat(
*/
if ((chunkidx & (nicluster - 1)) == 0) {
agbno = XFS_AGINO_TO_AGBNO(mp,
- INT_GET(irbp->ir_startino, ARCH_CONVERT)) +
+ irbp->ir_startino) +
((chunkidx & nimask) >>
mp->m_sb.sb_inopblog);
- if (flags & BULKSTAT_FG_QUICK) {
+ if (flags & (BULKSTAT_FG_QUICK |
+ BULKSTAT_FG_INLINE)) {
ino = XFS_AGINO_TO_INO(mp, agno,
agino);
bno = XFS_AGB_TO_DADDR(mp, agno,
@@ -543,6 +581,7 @@ xfs_bulkstat(
KM_SLEEP);
ip->i_ino = ino;
ip->i_mount = mp;
+ spin_lock_init(&ip->i_flags_lock);
if (bp)
xfs_buf_relse(bp);
error = xfs_itobp(mp, NULL, ip,
@@ -564,30 +603,34 @@ xfs_bulkstat(
/*
* Skip if this inode is free.
*/
- if (XFS_INOBT_MASK(chunkidx) & INT_GET(irbp->ir_free, ARCH_CONVERT))
+ if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free)
continue;
/*
* Count used inodes as free so we can tell
* when the chunk is used up.
*/
- INT_MOD(irbp->ir_freecount, ARCH_CONVERT, +1);
+ irbp->ir_freecount++;
ino = XFS_AGINO_TO_INO(mp, agno, agino);
bno = XFS_AGB_TO_DADDR(mp, agno, agbno);
- if (flags & BULKSTAT_FG_QUICK) {
- dip = (xfs_dinode_t *)xfs_buf_offset(bp,
- (clustidx << mp->m_sb.sb_inodelog));
-
- if (INT_GET(dip->di_core.di_magic, ARCH_CONVERT)
- != XFS_DINODE_MAGIC
- || !XFS_DINODE_GOOD_VERSION(
- INT_GET(dip->di_core.di_version, ARCH_CONVERT)))
- continue;
+ if (!xfs_bulkstat_use_dinode(mp, flags, bp,
+ clustidx, &dip))
+ continue;
+ /*
+ * If we need to do an iget, cannot hold bp.
+ * Drop it, until starting the next cluster.
+ */
+ if ((flags & BULKSTAT_FG_INLINE) && !dip) {
+ if (bp)
+ xfs_buf_relse(bp);
+ bp = NULL;
}
/*
* Get the inode and fill in a single buffer.
* BULKSTAT_FG_QUICK uses dip to fill it in.
* BULKSTAT_FG_IGET uses igets.
+ * BULKSTAT_FG_INLINE uses dip if we have an
+ * inline attr fork, else igets.
* See: xfs_bulkstat_one & xfs_dm_bulkstat_one.
* This is also used to count inodes/blks, etc
* in xfs_qm_quotacheck.
@@ -597,8 +640,15 @@ xfs_bulkstat(
ubleft, private_data,
bno, &ubused, dip, &fmterror);
if (fmterror == BULKSTAT_RV_NOTHING) {
- if (error == ENOMEM)
+ if (error == EFAULT) {
+ ubleft = 0;
+ rval = error;
+ break;
+ }
+ else if (error == ENOMEM)
ubleft = 0;
+ else
+ lastino = ino;
continue;
}
if (fmterror == BULKSTAT_RV_GIVEUP) {
@@ -633,7 +683,7 @@ xfs_bulkstat(
/*
* Done, we're either out of filesystem or space to put the data.
*/
- kmem_free(irbuf, NBPC);
+ kmem_free(irbuf, irbsize);
*ubcountp = ubelem;
if (agno >= mp->m_sb.sb_agcount) {
/*
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index be5f12e07d22..f25a28862a17 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -36,15 +36,16 @@ typedef int (*bulkstat_one_pf)(struct xfs_mount *mp,
/*
* Values for stat return value.
*/
-#define BULKSTAT_RV_NOTHING 0
-#define BULKSTAT_RV_DIDONE 1
-#define BULKSTAT_RV_GIVEUP 2
+#define BULKSTAT_RV_NOTHING 0
+#define BULKSTAT_RV_DIDONE 1
+#define BULKSTAT_RV_GIVEUP 2
/*
* Values for bulkstat flag argument.
*/
-#define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */
-#define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */
+#define BULKSTAT_FG_IGET 0x1 /* Go through the buffer cache */
+#define BULKSTAT_FG_QUICK 0x2 /* No iget, walk the dinode cluster */
+#define BULKSTAT_FG_INLINE 0x4 /* No iget if inline attrs */
/*
* Return stat information in bulk (by-inode) for the filesystem.
@@ -80,6 +81,11 @@ xfs_bulkstat_one(
void *dibuff,
int *stat);
+int
+xfs_internal_inum(
+ xfs_mount_t *mp,
+ xfs_ino_t ino);
+
int /* error status */
xfs_inumbers(
xfs_mount_t *mp, /* mount point for filesystem */
diff --git a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
index 21ac1a67e3e0..c48bf61f17bd 100644
--- a/fs/xfs/xfs_log.c
+++ b/fs/xfs/xfs_log.c
@@ -617,7 +617,8 @@ xfs_log_unmount_write(xfs_mount_t *mp)
reg[0].i_len = sizeof(magic);
XLOG_VEC_SET_TYPE(&reg[0], XLOG_REG_TYPE_UNMOUNT);
- error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0, 0);
+ error = xfs_log_reserve(mp, 600, 1, &tic,
+ XFS_LOG, 0, XLOG_UNMOUNT_REC_TYPE);
if (!error) {
/* remove inited flag */
((xlog_ticket_t *)tic)->t_flags = 0;
@@ -655,8 +656,11 @@ xfs_log_unmount_write(xfs_mount_t *mp)
} else {
LOG_UNLOCK(log, s);
}
- if (tic)
+ if (tic) {
+ xlog_trace_loggrant(log, tic, "unmount rec");
+ xlog_ungrant_log_space(log, tic);
xlog_state_put_ticket(log, tic);
+ }
} else {
/*
* We're already in forced_shutdown mode, couldn't
@@ -1196,7 +1200,7 @@ xlog_alloc_log(xfs_mount_t *mp,
kmem_zalloc(sizeof(xlog_in_core_t), KM_SLEEP);
iclog = *iclogp;
iclog->hic_data = (xlog_in_core_2_t *)
- kmem_zalloc(iclogsize, KM_SLEEP);
+ kmem_zalloc(iclogsize, KM_SLEEP | KM_LARGE);
iclog->ic_prev = prev_iclog;
prev_iclog = iclog;
@@ -2212,9 +2216,13 @@ xlog_state_do_callback(
iclog = iclog->ic_next;
} while (first_iclog != iclog);
- if (repeats && (repeats % 10) == 0) {
+
+ if (repeats > 5000) {
+ flushcnt += repeats;
+ repeats = 0;
xfs_fs_cmn_err(CE_WARN, log->l_mp,
- "xlog_state_do_callback: looping %d", repeats);
+ "%s: possible infinite loop (%d iterations)",
+ __FUNCTION__, flushcnt);
}
} while (!ioerrors && loopdidcallbacks);
@@ -2246,6 +2254,7 @@ xlog_state_do_callback(
}
#endif
+ flushcnt = 0;
if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) {
flushcnt = log->l_flushcnt;
log->l_flushcnt = 0;
diff --git a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
index eacb3d4987f2..ebbe93f4f97b 100644
--- a/fs/xfs/xfs_log.h
+++ b/fs/xfs/xfs_log.h
@@ -48,16 +48,10 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
*/
/*
- * Flags to xfs_log_mount
- */
-#define XFS_LOG_RECOVER 0x1
-
-/*
* Flags to xfs_log_done()
*/
#define XFS_LOG_REL_PERM_RESERV 0x1
-
/*
* Flags to xfs_log_reserve()
*
@@ -70,8 +64,6 @@ static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2)
#define XFS_LOG_SLEEP 0x0
#define XFS_LOG_NOSLEEP 0x1
#define XFS_LOG_PERM_RESERV 0x2
-#define XFS_LOG_RESV_ALL (XFS_LOG_NOSLEEP|XFS_LOG_PERM_RESERV)
-
/*
* Flags to xfs_log_force()
diff --git a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
index 34bcbf50789c..9bd3cdf11a87 100644
--- a/fs/xfs/xfs_log_priv.h
+++ b/fs/xfs/xfs_log_priv.h
@@ -32,7 +32,6 @@ struct xfs_mount;
#define XLOG_MIN_ICLOGS 2
#define XLOG_MED_ICLOGS 4
#define XLOG_MAX_ICLOGS 8
-#define XLOG_CALLBACK_SIZE 10
#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Invalid cycle number */
#define XLOG_VERSION_1 1
#define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */
@@ -149,9 +148,6 @@ struct xfs_mount;
#define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */
#define XLOG_END_TRANS 0x10 /* End a continued transaction */
#define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */
-#define XLOG_SKIP_TRANS (XLOG_COMMIT_TRANS | XLOG_CONTINUE_TRANS | \
- XLOG_WAS_CONT_TRANS | XLOG_END_TRANS | \
- XLOG_UNMOUNT_TRANS)
#ifdef __KERNEL__
/*
@@ -506,6 +502,12 @@ extern int xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
#define XLOG_TRACE_SLEEP_FLUSH 3
#define XLOG_TRACE_WAKE_FLUSH 4
+/*
+ * Unmount record type is used as a pseudo transaction type for the ticket.
+ * It's value must be outside the range of XFS_TRANS_* values.
+ */
+#define XLOG_UNMOUNT_REC_TYPE (-1U)
+
#endif /* __KERNEL__ */
#endif /* __XFS_LOG_PRIV_H__ */
diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
index b2bd4be4200a..e5f396ff9a3d 100644
--- a/fs/xfs/xfs_mount.h
+++ b/fs/xfs/xfs_mount.h
@@ -331,7 +331,7 @@ typedef struct xfs_mount {
xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */
lock_t m_agirotor_lock;/* .. and lock protecting it */
xfs_agnumber_t m_maxagi; /* highest inode alloc group */
- uint m_ihsize; /* size of next field */
+ size_t m_ihsize; /* size of next field */
struct xfs_ihash *m_ihash; /* fs private inode hash table*/
struct xfs_inode *m_inodes; /* active inode list */
struct list_head m_del_inodes; /* inodes to reclaim */
@@ -541,7 +541,8 @@ static inline xfs_mount_t *xfs_bhvtom(bhv_desc_t *bdp)
#define XFS_VFSTOM(vfs) xfs_vfstom(vfs)
static inline xfs_mount_t *xfs_vfstom(bhv_vfs_t *vfs)
{
- return XFS_BHVTOM(bhv_lookup(VFS_BHVHEAD(vfs), &xfs_vfsops));
+ return XFS_BHVTOM(bhv_lookup_range(VFS_BHVHEAD(vfs),
+ VFS_POSITION_XFS, VFS_POSITION_XFS));
}
#define XFS_DADDR_TO_AGNO(mp,d) xfs_daddr_to_agno(mp,d)
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index acb853b33ebb..9dcb32aa4e2e 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -281,8 +281,6 @@ typedef struct xfs_qoff_logformat {
XFS_UQUOTA_CHKD|XFS_PQUOTA_ACCT|\
XFS_OQUOTA_ENFD|XFS_OQUOTA_CHKD|\
XFS_GQUOTA_ACCT)
-#define XFS_MOUNT_QUOTA_MASK (XFS_MOUNT_QUOTA_ALL | XFS_UQUOTA_ACTIVE | \
- XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE)
/*
diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
index 5a0b678956e0..880c73271c05 100644
--- a/fs/xfs/xfs_rtalloc.c
+++ b/fs/xfs/xfs_rtalloc.c
@@ -1948,7 +1948,7 @@ xfs_growfs_rt(
*/
nrextents = nrblocks;
do_div(nrextents, in->extsize);
- nrbmblocks = roundup_64(nrextents, NBBY * sbp->sb_blocksize);
+ nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
nrextslog = xfs_highbit32(nrextents);
nrsumlevels = nrextslog + 1;
nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
@@ -1976,7 +1976,10 @@ xfs_growfs_rt(
if ((error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks,
mp->m_sb.sb_rsumino)))
return error;
- nmp = NULL;
+ /*
+ * Allocate a new (fake) mount/sb.
+ */
+ nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP);
/*
* Loop over the bitmap blocks.
* We will do everything one bitmap block at a time.
@@ -1987,10 +1990,6 @@ xfs_growfs_rt(
((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
bmbno < nrbmblocks;
bmbno++) {
- /*
- * Allocate a new (fake) mount/sb.
- */
- nmp = kmem_alloc(sizeof(*nmp), KM_SLEEP);
*nmp = *mp;
nsbp = &nmp->m_sb;
/*
@@ -2018,13 +2017,13 @@ xfs_growfs_rt(
cancelflags = 0;
if ((error = xfs_trans_reserve(tp, 0,
XFS_GROWRTFREE_LOG_RES(nmp), 0, 0, 0)))
- goto error_exit;
+ break;
/*
* Lock out other callers by grabbing the bitmap inode lock.
*/
if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0,
XFS_ILOCK_EXCL, &ip)))
- goto error_exit;
+ break;
ASSERT(ip == mp->m_rbmip);
/*
* Update the bitmap inode's size.
@@ -2038,7 +2037,7 @@ xfs_growfs_rt(
*/
if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, 0,
XFS_ILOCK_EXCL, &ip)))
- goto error_exit;
+ break;
ASSERT(ip == mp->m_rsumip);
/*
* Update the summary inode's size.
@@ -2053,7 +2052,7 @@ xfs_growfs_rt(
mp->m_rsumlevels != nmp->m_rsumlevels) {
error = xfs_rtcopy_summary(mp, nmp, tp);
if (error)
- goto error_exit;
+ break;
}
/*
* Update superblock fields.
@@ -2080,18 +2079,13 @@ xfs_growfs_rt(
error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
if (error)
- goto error_exit;
+ break;
/*
* Mark more blocks free in the superblock.
*/
xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,
nsbp->sb_rextents - sbp->sb_rextents);
/*
- * Free the fake mp structure.
- */
- kmem_free(nmp, sizeof(*nmp));
- nmp = NULL;
- /*
* Update mp values into the real mp structure.
*/
mp->m_rsumlevels = nrsumlevels;
@@ -2101,15 +2095,15 @@ xfs_growfs_rt(
*/
xfs_trans_commit(tp, 0, NULL);
}
- return 0;
+
+ if (error)
+ xfs_trans_cancel(tp, cancelflags);
/*
- * Error paths come here.
+ * Free the fake mp structure.
*/
-error_exit:
- if (nmp)
- kmem_free(nmp, sizeof(*nmp));
- xfs_trans_cancel(tp, cancelflags);
+ kmem_free(nmp, sizeof(*nmp));
+
return error;
}
diff --git a/fs/xfs/xfs_sb.h b/fs/xfs/xfs_sb.h
index bf168a91ddb8..467854b45c8f 100644
--- a/fs/xfs/xfs_sb.h
+++ b/fs/xfs/xfs_sb.h
@@ -60,10 +60,6 @@ struct xfs_mount;
XFS_SB_VERSION_LOGV2BIT | \
XFS_SB_VERSION_SECTORBIT | \
XFS_SB_VERSION_MOREBITSBIT)
-#define XFS_SB_VERSION_OKSASHBITS \
- (XFS_SB_VERSION_NUMBITS | \
- XFS_SB_VERSION_REALFBITS | \
- XFS_SB_VERSION_OKSASHFBITS)
#define XFS_SB_VERSION_OKREALBITS \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_OKREALFBITS | \
@@ -81,9 +77,6 @@ struct xfs_mount;
#define XFS_SB_VERSION2_RESERVED2BIT 0x00000002
#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004
#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */
-#define XFS_SB_VERSION2_SASHFBITS 0xff000000 /* Mask: features that
- require changing
- PROM and SASH */
#define XFS_SB_VERSION2_OKREALFBITS \
(XFS_SB_VERSION2_ATTR2BIT)
@@ -238,12 +231,6 @@ static inline int xfs_sb_good_version(xfs_sb_t *sbp)
}
#endif /* __KERNEL__ */
-#define XFS_SB_GOOD_SASH_VERSION(sbp) \
- ((((sbp)->sb_versionnum >= XFS_SB_VERSION_1) && \
- ((sbp)->sb_versionnum <= XFS_SB_VERSION_3)) || \
- ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
- !((sbp)->sb_versionnum & ~XFS_SB_VERSION_OKSASHBITS)))
-
#define XFS_SB_VERSION_TONEW(v) xfs_sb_version_tonew(v)
static inline unsigned xfs_sb_version_tonew(unsigned v)
{
@@ -461,15 +448,6 @@ static inline void xfs_sb_version_addattr2(xfs_sb_t *sbp)
* File system sector to basic block conversions.
*/
#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log)
-#define XFS_BB_TO_FSS(mp,bb) \
- (((bb) + (XFS_FSS_TO_BB(mp,1) - 1)) >> (mp)->m_sectbb_log)
-#define XFS_BB_TO_FSST(mp,bb) ((bb) >> (mp)->m_sectbb_log)
-
-/*
- * File system sector to byte conversions.
- */
-#define XFS_FSS_TO_B(mp,sectno) ((xfs_fsize_t)(sectno) << (mp)->m_sb.sb_sectlog)
-#define XFS_B_TO_FSST(mp,b) (((__uint64_t)(b)) >> (mp)->m_sb.sb_sectlog)
/*
* File system block to basic block conversions.
diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h
index 9dc88b380608..c68e00105d23 100644
--- a/fs/xfs/xfs_trans.h
+++ b/fs/xfs/xfs_trans.h
@@ -149,7 +149,6 @@ typedef struct xfs_item_ops {
void (*iop_unlock)(xfs_log_item_t *);
xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t);
void (*iop_push)(xfs_log_item_t *);
- void (*iop_abort)(xfs_log_item_t *);
void (*iop_pushbuf)(xfs_log_item_t *);
void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t);
} xfs_item_ops_t;
@@ -163,7 +162,6 @@ typedef struct xfs_item_ops {
#define IOP_UNLOCK(ip) (*(ip)->li_ops->iop_unlock)(ip)
#define IOP_COMMITTED(ip, lsn) (*(ip)->li_ops->iop_committed)(ip, lsn)
#define IOP_PUSH(ip) (*(ip)->li_ops->iop_push)(ip)
-#define IOP_ABORT(ip) (*(ip)->li_ops->iop_abort)(ip)
#define IOP_PUSHBUF(ip) (*(ip)->li_ops->iop_pushbuf)(ip)
#define IOP_COMMITTING(ip, lsn) (*(ip)->li_ops->iop_committing)(ip, lsn)
diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c
index 558c87ff0c41..fc39b166d403 100644
--- a/fs/xfs/xfs_trans_ail.c
+++ b/fs/xfs/xfs_trans_ail.c
@@ -276,7 +276,7 @@ xfs_trans_update_ail(
xfs_mount_t *mp,
xfs_log_item_t *lip,
xfs_lsn_t lsn,
- unsigned long s)
+ unsigned long s) __releases(mp->m_ail_lock)
{
xfs_ail_entry_t *ailp;
xfs_log_item_t *dlip=NULL;
@@ -328,7 +328,7 @@ void
xfs_trans_delete_ail(
xfs_mount_t *mp,
xfs_log_item_t *lip,
- unsigned long s)
+ unsigned long s) __releases(mp->m_ail_lock)
{
xfs_ail_entry_t *ailp;
xfs_log_item_t *dlip;
diff --git a/fs/xfs/xfs_trans_priv.h b/fs/xfs/xfs_trans_priv.h
index 13edab8a9e94..447ac4308c91 100644
--- a/fs/xfs/xfs_trans_priv.h
+++ b/fs/xfs/xfs_trans_priv.h
@@ -46,11 +46,13 @@ xfs_log_busy_slot_t *xfs_trans_add_busy(xfs_trans_t *tp,
/*
* From xfs_trans_ail.c
*/
-void xfs_trans_update_ail(struct xfs_mount *,
- struct xfs_log_item *, xfs_lsn_t,
- unsigned long);
-void xfs_trans_delete_ail(struct xfs_mount *,
- struct xfs_log_item *, unsigned long);
+void xfs_trans_update_ail(struct xfs_mount *mp,
+ struct xfs_log_item *lip, xfs_lsn_t lsn,
+ unsigned long s)
+ __releases(mp->m_ail_lock);
+void xfs_trans_delete_ail(struct xfs_mount *mp,
+ struct xfs_log_item *lip, unsigned long s)
+ __releases(mp->m_ail_lock);
struct xfs_log_item *xfs_trans_first_ail(struct xfs_mount *, int *);
struct xfs_log_item *xfs_trans_next_ail(struct xfs_mount *,
struct xfs_log_item *, int *, int *);
diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
index a34796e57afb..62336a4cc5a4 100644
--- a/fs/xfs/xfs_vfsops.c
+++ b/fs/xfs/xfs_vfsops.c
@@ -1922,7 +1922,7 @@ xfs_showargs(
}
if (mp->m_flags & XFS_MOUNT_IHASHSIZE)
- seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", mp->m_ihsize);
+ seq_printf(m, "," MNTOPT_IHASHSIZE "=%d", (int)mp->m_ihsize);
if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)
seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk",
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index 23cfa5837728..061e2ffdd1de 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -2366,10 +2366,15 @@ xfs_remove(
namelen = VNAMELEN(dentry);
+ if (!xfs_get_dir_entry(dentry, &ip)) {
+ dm_di_mode = ip->i_d.di_mode;
+ IRELE(ip);
+ }
+
if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dir_vp,
DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
- name, NULL, 0, 0, 0);
+ name, NULL, dm_di_mode, 0, 0);
if (error)
return error;
}
@@ -2995,7 +3000,7 @@ xfs_rmdir(
int cancel_flags;
int committed;
bhv_vnode_t *dir_vp;
- int dm_di_mode = 0;
+ int dm_di_mode = S_IFDIR;
int last_cdp_link;
int namelen;
uint resblks;
@@ -3010,11 +3015,16 @@ xfs_rmdir(
return XFS_ERROR(EIO);
namelen = VNAMELEN(dentry);
+ if (!xfs_get_dir_entry(dentry, &cdp)) {
+ dm_di_mode = cdp->i_d.di_mode;
+ IRELE(cdp);
+ }
+
if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
dir_vp, DM_RIGHT_NULL,
NULL, DM_RIGHT_NULL,
- name, NULL, 0, 0, 0);
+ name, NULL, dm_di_mode, 0, 0);
if (error)
return XFS_ERROR(error);
}
@@ -3834,7 +3844,9 @@ xfs_reclaim(
XFS_MOUNT_ILOCK(mp);
vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
+ spin_lock(&ip->i_flags_lock);
ip->i_flags |= XFS_IRECLAIMABLE;
+ spin_unlock(&ip->i_flags_lock);
XFS_MOUNT_IUNLOCK(mp);
}
return 0;
@@ -3859,8 +3871,10 @@ xfs_finish_reclaim(
* us.
*/
write_lock(&ih->ih_lock);
+ spin_lock(&ip->i_flags_lock);
if ((ip->i_flags & XFS_IRECLAIM) ||
(!(ip->i_flags & XFS_IRECLAIMABLE) && vp == NULL)) {
+ spin_unlock(&ip->i_flags_lock);
write_unlock(&ih->ih_lock);
if (locked) {
xfs_ifunlock(ip);
@@ -3869,6 +3883,7 @@ xfs_finish_reclaim(
return 1;
}
ip->i_flags |= XFS_IRECLAIM;
+ spin_unlock(&ip->i_flags_lock);
write_unlock(&ih->ih_lock);
/*
@@ -4272,7 +4287,7 @@ xfs_free_file_space(
xfs_mount_t *mp;
int nimap;
uint resblks;
- int rounding;
+ uint rounding;
int rt;
xfs_fileoff_t startoffset_fsb;
xfs_trans_t *tp;
@@ -4313,8 +4328,7 @@ xfs_free_file_space(
vn_iowait(vp); /* wait for the completion of any pending DIOs */
}
- rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog),
- (__uint8_t)NBPP);
+ rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP);
ilen = len + (offset & (rounding - 1));
ioffset = offset & ~(rounding - 1);
if (ilen & (rounding - 1))
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index a4d0e73d5aca..063c4b54290f 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -708,7 +708,7 @@ struct acpi_bit_register_info {
* must be preserved.
*/
#define ACPI_PM1_STATUS_PRESERVED_BITS 0x0800 /* Bit 11 */
-#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0201 /* Bit 9, Bit 0 (SCI_EN) */
+#define ACPI_PM1_CONTROL_PRESERVED_BITS 0x0200 /* Bit 9 (whatever) */
/*
* Register IDs
diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h
index c5472be6f3a2..e72bfdd887f9 100644
--- a/include/acpi/pdc_intel.h
+++ b/include/acpi/pdc_intel.h
@@ -13,6 +13,7 @@
#define ACPI_PDC_SMP_C_SWCOORD (0x0040)
#define ACPI_PDC_SMP_T_SWCOORD (0x0080)
#define ACPI_PDC_C_C1_FFH (0x0100)
+#define ACPI_PDC_C_C2C3_FFH (0x0200)
#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
ACPI_PDC_C_C1_HALT | \
@@ -23,8 +24,10 @@
ACPI_PDC_SMP_P_SWCOORD | \
ACPI_PDC_P_FFH)
-#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
- ACPI_PDC_SMP_C1PT | \
- ACPI_PDC_C_C1_HALT)
+#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
+ ACPI_PDC_SMP_C1PT | \
+ ACPI_PDC_C_C1_HALT | \
+ ACPI_PDC_C_C1_FFH | \
+ ACPI_PDC_C_C2C3_FFH)
#endif /* __PDC_INTEL_H__ */
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 9dd5b75961f8..7798d2a9f793 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -29,6 +29,9 @@
#define DOMAIN_COORD_TYPE_SW_ANY 0xfd
#define DOMAIN_COORD_TYPE_HW_ALL 0xfe
+#define ACPI_CSTATE_SYSTEMIO (0)
+#define ACPI_CSTATE_FFH (1)
+
/* Power Management */
struct acpi_processor_cx;
@@ -58,6 +61,8 @@ struct acpi_processor_cx {
u8 valid;
u8 type;
u32 address;
+ u8 space_id;
+ u8 index;
u32 latency;
u32 latency_ticks;
u32 power;
@@ -206,6 +211,9 @@ void arch_acpi_processor_init_pdc(struct acpi_processor *pr);
#ifdef ARCH_HAS_POWER_INIT
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);
+void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx *cstate);
#else
static inline void acpi_processor_power_init_bm_check(struct
acpi_processor_flags
@@ -214,6 +222,16 @@ static inline void acpi_processor_power_init_bm_check(struct
flags->bm_check = 1;
return;
}
+static inline int acpi_processor_ffh_cstate_probe(unsigned int cpu,
+ 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)
+{
+ return;
+}
#endif
/* in processor_perflib.c */
diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h
index f5ae98c25d1f..5d15af24573b 100644
--- a/include/asm-alpha/io.h
+++ b/include/asm-alpha/io.h
@@ -533,19 +533,6 @@ extern void outsl (unsigned long port, const void *src, unsigned long count);
#define eth_io_copy_and_sum(skb,src,len,unused) \
memcpy_fromio((skb)->data,src,len)
-static inline int
-check_signature(const volatile void __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- do {
- if (readb(io_addr) != *signature)
- return 0;
- io_addr++;
- signature++;
- } while (--length);
- return 1;
-}
-
/*
* The Alpha Jensen hardware for some rather strange reason puts
* the RTC clock at 0x170 instead of 0x70. Probably due to some
diff --git a/include/asm-alpha/irq_regs.h b/include/asm-alpha/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-alpha/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-alpha/machvec.h b/include/asm-alpha/machvec.h
index aced22f91752..a86c083cdf7f 100644
--- a/include/asm-alpha/machvec.h
+++ b/include/asm-alpha/machvec.h
@@ -15,7 +15,6 @@
struct task_struct;
struct mm_struct;
-struct pt_regs;
struct vm_area_struct;
struct linux_hose_info;
struct pci_dev;
@@ -79,8 +78,8 @@ struct alpha_machine_vector
void (*update_irq_hw)(unsigned long, unsigned long, int);
void (*ack_irq)(unsigned long);
- void (*device_interrupt)(unsigned long vector, struct pt_regs *regs);
- void (*machine_check)(u64 vector, u64 la, struct pt_regs *regs);
+ void (*device_interrupt)(unsigned long vector);
+ void (*machine_check)(u64 vector, u64 la);
void (*smp_callin)(void);
void (*init_arch)(void);
diff --git a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
index 0c294c9b0c55..aeeb125f6851 100644
--- a/include/asm-alpha/spinlock.h
+++ b/include/asm-alpha/spinlock.h
@@ -166,4 +166,8 @@ static inline void __raw_write_unlock(raw_rwlock_t * lock)
lock->lock = 0;
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* _ALPHA_SPINLOCK_H */
diff --git a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h
index bc6e6a9259dc..2cabbd465c0c 100644
--- a/include/asm-alpha/unistd.h
+++ b/include/asm-alpha/unistd.h
@@ -580,75 +580,6 @@ type name (type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5, type6 arg6)\
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_SIGPENDING
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/signal.h>
-#include <linux/syscalls.h>
-#include <asm/ptrace.h>
-
-static inline long open(const char * name, int mode, int flags)
-{
- return sys_open(name, mode, flags);
-}
-
-static inline long dup(int fd)
-{
- return sys_dup(fd);
-}
-
-static inline long close(int fd)
-{
- return sys_close(fd);
-}
-
-static inline off_t lseek(int fd, off_t off, int whence)
-{
- return sys_lseek(fd, off, whence);
-}
-
-static inline void _exit(int value)
-{
- sys_exit(value);
-}
-
-#define exit(x) _exit(x)
-
-static inline long write(int fd, const char * buf, size_t nr)
-{
- return sys_write(fd, buf, nr);
-}
-
-static inline long read(int fd, char * buf, size_t nr)
-{
- return sys_read(fd, buf, nr);
-}
-
-extern int execve(char *, char **, char **);
-
-static inline long setsid(void)
-{
- return sys_setsid();
-}
-
-static inline pid_t waitpid(int pid, int * wait_stat, int flags)
-{
- return sys_wait4(pid, wait_stat, flags, NULL);
-}
-
-asmlinkage int sys_execve(char *ufilename, char **argv, char **envp,
- unsigned long a3, unsigned long a4, unsigned long a5,
- struct pt_regs regs);
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize,
- void *restorer);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/* "Conditional" syscalls. What we want is
__attribute__((weak,alias("sys_ni_syscall")))
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200.h b/include/asm-arm/arch-at91rm9200/at91rm9200.h
index 58f40931a5c1..a5a86b1ff886 100644
--- a/include/asm-arm/arch-at91rm9200/at91rm9200.h
+++ b/include/asm-arm/arch-at91rm9200/at91rm9200.h
@@ -19,67 +19,80 @@
/*
* Peripheral identifiers/interrupts.
*/
-#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
-#define AT91_ID_SYS 1 /* System Peripheral */
-#define AT91_ID_PIOA 2 /* Parallel IO Controller A */
-#define AT91_ID_PIOB 3 /* Parallel IO Controller B */
-#define AT91_ID_PIOC 4 /* Parallel IO Controller C */
-#define AT91_ID_PIOD 5 /* Parallel IO Controller D */
-#define AT91_ID_US0 6 /* USART 0 */
-#define AT91_ID_US1 7 /* USART 1 */
-#define AT91_ID_US2 8 /* USART 2 */
-#define AT91_ID_US3 9 /* USART 3 */
-#define AT91_ID_MCI 10 /* Multimedia Card Interface */
-#define AT91_ID_UDP 11 /* USB Device Port */
-#define AT91_ID_TWI 12 /* Two-Wire Interface */
-#define AT91_ID_SPI 13 /* Serial Peripheral Interface */
-#define AT91_ID_SSC0 14 /* Serial Synchronous Controller 0 */
-#define AT91_ID_SSC1 15 /* Serial Synchronous Controller 1 */
-#define AT91_ID_SSC2 16 /* Serial Synchronous Controller 2 */
-#define AT91_ID_TC0 17 /* Timer Counter 0 */
-#define AT91_ID_TC1 18 /* Timer Counter 1 */
-#define AT91_ID_TC2 19 /* Timer Counter 2 */
-#define AT91_ID_TC3 20 /* Timer Counter 3 */
-#define AT91_ID_TC4 21 /* Timer Counter 4 */
-#define AT91_ID_TC5 22 /* Timer Counter 5 */
-#define AT91_ID_UHP 23 /* USB Host port */
-#define AT91_ID_EMAC 24 /* Ethernet MAC */
-#define AT91_ID_IRQ0 25 /* Advanced Interrupt Controller (IRQ0) */
-#define AT91_ID_IRQ1 26 /* Advanced Interrupt Controller (IRQ1) */
-#define AT91_ID_IRQ2 27 /* Advanced Interrupt Controller (IRQ2) */
-#define AT91_ID_IRQ3 28 /* Advanced Interrupt Controller (IRQ3) */
-#define AT91_ID_IRQ4 29 /* Advanced Interrupt Controller (IRQ4) */
-#define AT91_ID_IRQ5 30 /* Advanced Interrupt Controller (IRQ5) */
-#define AT91_ID_IRQ6 31 /* Advanced Interrupt Controller (IRQ6) */
+#define AT91_ID_FIQ 0 /* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS 1 /* System Peripheral */
+#define AT91RM9200_ID_PIOA 2 /* Parallel IO Controller A */
+#define AT91RM9200_ID_PIOB 3 /* Parallel IO Controller B */
+#define AT91RM9200_ID_PIOC 4 /* Parallel IO Controller C */
+#define AT91RM9200_ID_PIOD 5 /* Parallel IO Controller D */
+#define AT91RM9200_ID_US0 6 /* USART 0 */
+#define AT91RM9200_ID_US1 7 /* USART 1 */
+#define AT91RM9200_ID_US2 8 /* USART 2 */
+#define AT91RM9200_ID_US3 9 /* USART 3 */
+#define AT91RM9200_ID_MCI 10 /* Multimedia Card Interface */
+#define AT91RM9200_ID_UDP 11 /* USB Device Port */
+#define AT91RM9200_ID_TWI 12 /* Two-Wire Interface */
+#define AT91RM9200_ID_SPI 13 /* Serial Peripheral Interface */
+#define AT91RM9200_ID_SSC0 14 /* Serial Synchronous Controller 0 */
+#define AT91RM9200_ID_SSC1 15 /* Serial Synchronous Controller 1 */
+#define AT91RM9200_ID_SSC2 16 /* Serial Synchronous Controller 2 */
+#define AT91RM9200_ID_TC0 17 /* Timer Counter 0 */
+#define AT91RM9200_ID_TC1 18 /* Timer Counter 1 */
+#define AT91RM9200_ID_TC2 19 /* Timer Counter 2 */
+#define AT91RM9200_ID_TC3 20 /* Timer Counter 3 */
+#define AT91RM9200_ID_TC4 21 /* Timer Counter 4 */
+#define AT91RM9200_ID_TC5 22 /* Timer Counter 5 */
+#define AT91RM9200_ID_UHP 23 /* USB Host port */
+#define AT91RM9200_ID_EMAC 24 /* Ethernet MAC */
+#define AT91RM9200_ID_IRQ0 25 /* Advanced Interrupt Controller (IRQ0) */
+#define AT91RM9200_ID_IRQ1 26 /* Advanced Interrupt Controller (IRQ1) */
+#define AT91RM9200_ID_IRQ2 27 /* Advanced Interrupt Controller (IRQ2) */
+#define AT91RM9200_ID_IRQ3 28 /* Advanced Interrupt Controller (IRQ3) */
+#define AT91RM9200_ID_IRQ4 29 /* Advanced Interrupt Controller (IRQ4) */
+#define AT91RM9200_ID_IRQ5 30 /* Advanced Interrupt Controller (IRQ5) */
+#define AT91RM9200_ID_IRQ6 31 /* Advanced Interrupt Controller (IRQ6) */
/*
* Peripheral physical base addresses.
*/
-#define AT91_BASE_TCB0 0xfffa0000
-#define AT91_BASE_TC0 0xfffa0000
-#define AT91_BASE_TC1 0xfffa0040
-#define AT91_BASE_TC2 0xfffa0080
-#define AT91_BASE_TCB1 0xfffa4000
-#define AT91_BASE_TC3 0xfffa4000
-#define AT91_BASE_TC4 0xfffa4040
-#define AT91_BASE_TC5 0xfffa4080
-#define AT91_BASE_UDP 0xfffb0000
-#define AT91_BASE_MCI 0xfffb4000
-#define AT91_BASE_TWI 0xfffb8000
-#define AT91_BASE_EMAC 0xfffbc000
-#define AT91_BASE_US0 0xfffc0000
-#define AT91_BASE_US1 0xfffc4000
-#define AT91_BASE_US2 0xfffc8000
-#define AT91_BASE_US3 0xfffcc000
-#define AT91_BASE_SSC0 0xfffd0000
-#define AT91_BASE_SSC1 0xfffd4000
-#define AT91_BASE_SSC2 0xfffd8000
-#define AT91_BASE_SPI 0xfffe0000
+#define AT91RM9200_BASE_TCB0 0xfffa0000
+#define AT91RM9200_BASE_TC0 0xfffa0000
+#define AT91RM9200_BASE_TC1 0xfffa0040
+#define AT91RM9200_BASE_TC2 0xfffa0080
+#define AT91RM9200_BASE_TCB1 0xfffa4000
+#define AT91RM9200_BASE_TC3 0xfffa4000
+#define AT91RM9200_BASE_TC4 0xfffa4040
+#define AT91RM9200_BASE_TC5 0xfffa4080
+#define AT91RM9200_BASE_UDP 0xfffb0000
+#define AT91RM9200_BASE_MCI 0xfffb4000
+#define AT91RM9200_BASE_TWI 0xfffb8000
+#define AT91RM9200_BASE_EMAC 0xfffbc000
+#define AT91RM9200_BASE_US0 0xfffc0000
+#define AT91RM9200_BASE_US1 0xfffc4000
+#define AT91RM9200_BASE_US2 0xfffc8000
+#define AT91RM9200_BASE_US3 0xfffcc000
+#define AT91RM9200_BASE_SSC0 0xfffd0000
+#define AT91RM9200_BASE_SSC1 0xfffd4000
+#define AT91RM9200_BASE_SSC2 0xfffd8000
+#define AT91RM9200_BASE_SPI 0xfffe0000
#define AT91_BASE_SYS 0xfffff000
/*
+ * Internal Memory.
+ */
+#define AT91RM9200_ROM_BASE 0x00100000 /* Internal ROM base address */
+#define AT91RM9200_ROM_SIZE SZ_128K /* Internal ROM size (128Kb) */
+
+#define AT91RM9200_SRAM_BASE 0x00200000 /* Internal SRAM base address */
+#define AT91RM9200_SRAM_SIZE SZ_16K /* Internal SRAM size (16Kb) */
+
+#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 */
@@ -257,5 +270,6 @@
#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
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h
index 0f4c12d5f0cd..73693fea76a2 100644
--- a/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h
+++ b/include/asm-arm/arch-at91rm9200/at91rm9200_sys.h
@@ -80,6 +80,9 @@
#define AT91_CIDR_NVPTYP (7 << 28) /* Nonvolatile Program Memory Type */
#define AT91_CIDR_EXT (1 << 31) /* Extension Flag */
+#define AT91_AIC_FFER (AT91_AIC + 0x140) /* Fast Forcing Enable Register [SAM9 only] */
+#define AT91_AIC_FFDR (AT91_AIC + 0x144) /* Fast Forcing Disable Register [SAM9 only] */
+#define AT91_AIC_FFSR (AT91_AIC + 0x148) /* Fast Forcing Status Register [SAM9 only] */
/*
* PIO Controllers.
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_twi.h b/include/asm-arm/arch-at91rm9200/at91rm9200_twi.h
new file mode 100644
index 000000000000..93547d7482bd
--- /dev/null
+++ b/include/asm-arm/arch-at91rm9200/at91rm9200_twi.h
@@ -0,0 +1,57 @@
+/*
+ * include/asm-arm/arch-at91rm9200/at91rm9200_twi.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Two-wire Interface (TWI) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * 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.
+ */
+
+#ifndef AT91RM9200_TWI_H
+#define AT91RM9200_TWI_H
+
+#define AT91_TWI_CR 0x00 /* Control Register */
+#define AT91_TWI_START (1 << 0) /* Send a Start Condition */
+#define AT91_TWI_STOP (1 << 1) /* Send a Stop Condition */
+#define AT91_TWI_MSEN (1 << 2) /* Master Transfer Enable */
+#define AT91_TWI_MSDIS (1 << 3) /* Master Transfer Disable */
+#define AT91_TWI_SWRST (1 << 7) /* Software Reset */
+
+#define AT91_TWI_MMR 0x04 /* Master Mode Register */
+#define AT91_TWI_IADRSZ (3 << 8) /* Internal Device Address Size */
+#define AT91_TWI_IADRSZ_NO (0 << 8)
+#define AT91_TWI_IADRSZ_1 (1 << 8)
+#define AT91_TWI_IADRSZ_2 (2 << 8)
+#define AT91_TWI_IADRSZ_3 (3 << 8)
+#define AT91_TWI_MREAD (1 << 12) /* Master Read Direction */
+#define AT91_TWI_DADR (0x7f << 16) /* Device Address */
+
+#define AT91_TWI_IADR 0x0c /* Internal Address Register */
+
+#define AT91_TWI_CWGR 0x10 /* Clock Waveform Generator Register */
+#define AT91_TWI_CLDIV (0xff << 0) /* Clock Low Divisor */
+#define AT91_TWI_CHDIV (0xff << 8) /* Clock High Divisor */
+#define AT91_TWI_CKDIV (7 << 16) /* Clock Divider */
+
+#define AT91_TWI_SR 0x20 /* Status Register */
+#define AT91_TWI_TXCOMP (1 << 0) /* Transmission Complete */
+#define AT91_TWI_RXRDY (1 << 1) /* Receive Holding Register Ready */
+#define AT91_TWI_TXRDY (1 << 2) /* Transmit Holding Register Ready */
+#define AT91_TWI_OVRE (1 << 6) /* Overrun Error */
+#define AT91_TWI_UNRE (1 << 7) /* Underrun Error */
+#define AT91_TWI_NACK (1 << 8) /* Not Acknowledged */
+
+#define AT91_TWI_IER 0x24 /* Interrupt Enable Register */
+#define AT91_TWI_IDR 0x28 /* Interrupt Disable Register */
+#define AT91_TWI_IMR 0x2c /* Interrupt Mask Register */
+#define AT91_TWI_RHR 0x30 /* Receive Holding Register */
+#define AT91_TWI_THR 0x34 /* Transmit Holding Register */
+
+#endif
+
diff --git a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h b/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
deleted file mode 100644
index 79f851e31b9c..000000000000
--- a/include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * USART registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * 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.
- */
-
-#ifndef AT91RM9200_USART_H
-#define AT91RM9200_USART_H
-
-#define AT91_US_CR 0x00 /* Control Register */
-#define AT91_US_RSTRX (1 << 2) /* Reset Receiver */
-#define AT91_US_RSTTX (1 << 3) /* Reset Transmitter */
-#define AT91_US_RXEN (1 << 4) /* Receiver Enable */
-#define AT91_US_RXDIS (1 << 5) /* Receiver Disable */
-#define AT91_US_TXEN (1 << 6) /* Transmitter Enable */
-#define AT91_US_TXDIS (1 << 7) /* Transmitter Disable */
-#define AT91_US_RSTSTA (1 << 8) /* Reset Status Bits */
-#define AT91_US_STTBRK (1 << 9) /* Start Break */
-#define AT91_US_STPBRK (1 << 10) /* Stop Break */
-#define AT91_US_STTTO (1 << 11) /* Start Time-out */
-#define AT91_US_SENDA (1 << 12) /* Send Address */
-#define AT91_US_RSTIT (1 << 13) /* Reset Iterations */
-#define AT91_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */
-#define AT91_US_RETTO (1 << 15) /* Rearm Time-out */
-#define AT91_US_DTREN (1 << 16) /* Data Terminal Ready Enable */
-#define AT91_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */
-#define AT91_US_RTSEN (1 << 18) /* Request To Send Enable */
-#define AT91_US_RTSDIS (1 << 19) /* Request To Send Disable */
-
-#define AT91_US_MR 0x04 /* Mode Register */
-#define AT91_US_USMODE (0xf << 0) /* Mode of the USART */
-#define AT91_US_USMODE_NORMAL 0
-#define AT91_US_USMODE_RS485 1
-#define AT91_US_USMODE_HWHS 2
-#define AT91_US_USMODE_MODEM 3
-#define AT91_US_USMODE_ISO7816_T0 4
-#define AT91_US_USMODE_ISO7816_T1 6
-#define AT91_US_USMODE_IRDA 8
-#define AT91_US_USCLKS (3 << 4) /* Clock Selection */
-#define AT91_US_CHRL (3 << 6) /* Character Length */
-#define AT91_US_CHRL_5 (0 << 6)
-#define AT91_US_CHRL_6 (1 << 6)
-#define AT91_US_CHRL_7 (2 << 6)
-#define AT91_US_CHRL_8 (3 << 6)
-#define AT91_US_SYNC (1 << 8) /* Synchronous Mode Select */
-#define AT91_US_PAR (7 << 9) /* Parity Type */
-#define AT91_US_PAR_EVEN (0 << 9)
-#define AT91_US_PAR_ODD (1 << 9)
-#define AT91_US_PAR_SPACE (2 << 9)
-#define AT91_US_PAR_MARK (3 << 9)
-#define AT91_US_PAR_NONE (4 << 9)
-#define AT91_US_PAR_MULTI_DROP (6 << 9)
-#define AT91_US_NBSTOP (3 << 12) /* Number of Stop Bits */
-#define AT91_US_NBSTOP_1 (0 << 12)
-#define AT91_US_NBSTOP_1_5 (1 << 12)
-#define AT91_US_NBSTOP_2 (2 << 12)
-#define AT91_US_CHMODE (3 << 14) /* Channel Mode */
-#define AT91_US_CHMODE_NORMAL (0 << 14)
-#define AT91_US_CHMODE_ECHO (1 << 14)
-#define AT91_US_CHMODE_LOC_LOOP (2 << 14)
-#define AT91_US_CHMODE_REM_LOOP (3 << 14)
-#define AT91_US_MSBF (1 << 16) /* Bit Order */
-#define AT91_US_MODE9 (1 << 17) /* 9-bit Character Length */
-#define AT91_US_CLKO (1 << 18) /* Clock Output Select */
-#define AT91_US_OVER (1 << 19) /* Oversampling Mode */
-#define AT91_US_INACK (1 << 20) /* Inhibit Non Acknowledge */
-#define AT91_US_DSNACK (1 << 21) /* Disable Successive NACK */
-#define AT91_US_MAX_ITER (7 << 24) /* Max Iterations */
-#define AT91_US_FILTER (1 << 28) /* Infrared Receive Line Filter */
-
-#define AT91_US_IER 0x08 /* Interrupt Enable Register */
-#define AT91_US_RXRDY (1 << 0) /* Receiver Ready */
-#define AT91_US_TXRDY (1 << 1) /* Transmitter Ready */
-#define AT91_US_RXBRK (1 << 2) /* Break Received / End of Break */
-#define AT91_US_ENDRX (1 << 3) /* End of Receiver Transfer */
-#define AT91_US_ENDTX (1 << 4) /* End of Transmitter Transfer */
-#define AT91_US_OVRE (1 << 5) /* Overrun Error */
-#define AT91_US_FRAME (1 << 6) /* Framing Error */
-#define AT91_US_PARE (1 << 7) /* Parity Error */
-#define AT91_US_TIMEOUT (1 << 8) /* Receiver Time-out */
-#define AT91_US_TXEMPTY (1 << 9) /* Transmitter Empty */
-#define AT91_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */
-#define AT91_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */
-#define AT91_US_RXBUFF (1 << 12) /* Reception Buffer Full */
-#define AT91_US_NACK (1 << 13) /* Non Acknowledge */
-#define AT91_US_RIIC (1 << 16) /* Ring Indicator Input Change */
-#define AT91_US_DSRIC (1 << 17) /* Data Set Ready Input Change */
-#define AT91_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */
-#define AT91_US_CTSIC (1 << 19) /* Clear to Send Input Change */
-#define AT91_US_RI (1 << 20) /* RI */
-#define AT91_US_DSR (1 << 21) /* DSR */
-#define AT91_US_DCD (1 << 22) /* DCD */
-#define AT91_US_CTS (1 << 23) /* CTS */
-
-#define AT91_US_IDR 0x0c /* Interrupt Disable Register */
-#define AT91_US_IMR 0x10 /* Interrupt Mask Register */
-#define AT91_US_CSR 0x14 /* Channel Status Register */
-#define AT91_US_RHR 0x18 /* Receiver Holding Register */
-#define AT91_US_THR 0x1c /* Transmitter Holding Register */
-
-#define AT91_US_BRGR 0x20 /* Baud Rate Generator Register */
-#define AT91_US_CD (0xffff << 0) /* Clock Divider */
-
-#define AT91_US_RTOR 0x24 /* Receiver Time-out Register */
-#define AT91_US_TO (0xffff << 0) /* Time-out Value */
-
-#define AT91_US_TTGR 0x28 /* Transmitter Timeguard Register */
-#define AT91_US_TG (0xff << 0) /* Timeguard Value */
-
-#define AT91_US_FIDI 0x40 /* FI DI Ratio Register */
-#define AT91_US_NER 0x44 /* Number of Errors Register */
-#define AT91_US_IF 0x4c /* IrDA Filter Register */
-
-#endif
diff --git a/include/asm-arm/arch-at91rm9200/board.h b/include/asm-arm/arch-at91rm9200/board.h
index c1ca9a4658ec..3cc9aec80f9d 100644
--- a/include/asm-arm/arch-at91rm9200/board.h
+++ b/include/asm-arm/arch-at91rm9200/board.h
@@ -97,12 +97,13 @@ struct at91_uart_config {
unsigned short nr_tty; /* number of serial tty's */
short tty_map[]; /* map UART to tty number */
};
-extern struct platform_device *at91_default_console_device;
+extern struct platform_device *atmel_default_console_device;
extern void __init at91_init_serial(struct at91_uart_config *config);
-struct at91_uart_data {
+struct atmel_uart_data {
short use_dma_tx; /* use transmit DMA? */
short use_dma_rx; /* use receive DMA? */
+ void __iomem *regs; /* virtual base address, if any */
};
extern void __init at91_add_device_serial(void);
diff --git a/include/asm-arm/arch-at91rm9200/gpio.h b/include/asm-arm/arch-at91rm9200/gpio.h
index dbde1baaf251..a011d27876a2 100644
--- a/include/asm-arm/arch-at91rm9200/gpio.h
+++ b/include/asm-arm/arch-at91rm9200/gpio.h
@@ -17,10 +17,9 @@
#define PIN_BASE NR_AIC_IRQS
-#define PQFP_GPIO_BANKS 3 /* PQFP package has 3 banks */
-#define BGA_GPIO_BANKS 4 /* BGA package has 4 banks */
+#define MAX_GPIO_BANKS 4
-/* these pin numbers double as IRQ numbers, like AT91_ID_* values */
+/* these pin numbers double as IRQ numbers, like AT91xxx_ID_* values */
#define AT91_PIN_PA0 (PIN_BASE + 0x00 + 0)
#define AT91_PIN_PA1 (PIN_BASE + 0x00 + 1)
@@ -180,17 +179,18 @@
#ifndef __ASSEMBLY__
/* setup setup routines, called from board init or driver probe() */
-extern int at91_set_A_periph(unsigned pin, int use_pullup);
-extern int at91_set_B_periph(unsigned pin, int use_pullup);
-extern int at91_set_gpio_input(unsigned pin, int use_pullup);
-extern int at91_set_gpio_output(unsigned pin, int value);
-extern int at91_set_deglitch(unsigned pin, int is_on);
-extern int at91_set_multi_drive(unsigned pin, int is_on);
+extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
+extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
+extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
+extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
/* callable at any time */
extern int at91_set_gpio_value(unsigned pin, int value);
extern int at91_get_gpio_value(unsigned pin);
+/* callable only from core power-management code */
extern void at91_gpio_suspend(void);
extern void at91_gpio_resume(void);
#endif
diff --git a/include/asm-arm/arch-at91rm9200/hardware.h b/include/asm-arm/arch-at91rm9200/hardware.h
index 235d39d91107..9ca4cc9c0b2e 100644
--- a/include/asm-arm/arch-at91rm9200/hardware.h
+++ b/include/asm-arm/arch-at91rm9200/hardware.h
@@ -34,30 +34,17 @@
* Virtual to Physical Address mapping for IO devices.
*/
#define AT91_VA_BASE_SYS AT91_IO_P2V(AT91_BASE_SYS)
-#define AT91_VA_BASE_SPI AT91_IO_P2V(AT91_BASE_SPI)
-#define AT91_VA_BASE_SSC2 AT91_IO_P2V(AT91_BASE_SSC2)
-#define AT91_VA_BASE_SSC1 AT91_IO_P2V(AT91_BASE_SSC1)
-#define AT91_VA_BASE_SSC0 AT91_IO_P2V(AT91_BASE_SSC0)
-#define AT91_VA_BASE_US3 AT91_IO_P2V(AT91_BASE_US3)
-#define AT91_VA_BASE_US2 AT91_IO_P2V(AT91_BASE_US2)
-#define AT91_VA_BASE_US1 AT91_IO_P2V(AT91_BASE_US1)
-#define AT91_VA_BASE_US0 AT91_IO_P2V(AT91_BASE_US0)
-#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91_BASE_EMAC)
-#define AT91_VA_BASE_TWI AT91_IO_P2V(AT91_BASE_TWI)
-#define AT91_VA_BASE_MCI AT91_IO_P2V(AT91_BASE_MCI)
-#define AT91_VA_BASE_UDP AT91_IO_P2V(AT91_BASE_UDP)
-#define AT91_VA_BASE_TCB1 AT91_IO_P2V(AT91_BASE_TCB1)
-#define AT91_VA_BASE_TCB0 AT91_IO_P2V(AT91_BASE_TCB0)
-
-/* Internal SRAM */
-#define AT91_SRAM_BASE 0x00200000 /* Internal SRAM base address */
-#define AT91_SRAM_SIZE 0x00004000 /* Internal SRAM SIZE (16Kb) */
+#define AT91_VA_BASE_SPI AT91_IO_P2V(AT91RM9200_BASE_SPI)
+#define AT91_VA_BASE_EMAC AT91_IO_P2V(AT91RM9200_BASE_EMAC)
+#define AT91_VA_BASE_TWI AT91_IO_P2V(AT91RM9200_BASE_TWI)
+#define AT91_VA_BASE_MCI AT91_IO_P2V(AT91RM9200_BASE_MCI)
+#define AT91_VA_BASE_UDP AT91_IO_P2V(AT91RM9200_BASE_UDP)
/* Internal SRAM is mapped below the IO devices */
-#define AT91_SRAM_VIRT_BASE (AT91_IO_VIRT_BASE - AT91_SRAM_SIZE)
+#define AT91_SRAM_VIRT_BASE (AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE)
/* Serial ports */
-#define AT91_NR_UART 5 /* 4 USART3's and one DBGU port */
+#define ATMEL_MAX_UART 5 /* 4 USART3's and one DBGU port */
/* FLASH */
#define AT91_FLASH_BASE 0x10000000 /* NCS0: Flash physical base address */
@@ -71,9 +58,6 @@
/* Compact Flash */
#define AT91_CF_BASE 0x50000000 /* NCS4-NCS6: Compact Flash physical base address */
-/* Multi-Master Memory controller */
-#define AT91_UHP_BASE 0x00300000 /* USB Host controller */
-
/* Clocks */
#define AT91_SLOW_CLOCK 32768 /* slow clock */
diff --git a/include/asm-arm/arch-at91rm9200/irqs.h b/include/asm-arm/arch-at91rm9200/irqs.h
index f63842c2c093..763cb96c418b 100644
--- a/include/asm-arm/arch-at91rm9200/irqs.h
+++ b/include/asm-arm/arch-at91rm9200/irqs.h
@@ -32,7 +32,7 @@
/*
- * IRQ interrupt symbols are the AT91_ID_* symbols in at91rm9200.h
+ * IRQ interrupt symbols are the AT91xxx_ID_* symbols
* for IRQs handled directly through the AIC, or else the AT91_PIN_*
* symbols in gpio.h for ones handled indirectly as GPIOs.
* We make provision for 4 banks of GPIO.
diff --git a/include/asm-arm/arch-clps711x/entry-macro.S b/include/asm-arm/arch-clps711x/entry-macro.S
index 21f6ee485819..de4481dd8ba0 100644
--- a/include/asm-arm/arch-clps711x/entry-macro.S
+++ b/include/asm-arm/arch-clps711x/entry-macro.S
@@ -1,5 +1,5 @@
/*
- * include/asm-arm/arch-CLPS711x/entry-macro.S
+ * include/asm-arm/arch-clps711x/entry-macro.S
*
* Low-level IRQ helper macros for CLPS711X-based platforms
*
diff --git a/include/asm-arm/arch-clps711x/time.h b/include/asm-arm/arch-clps711x/time.h
index 9cb27cd4e6ae..5edaae1c61d3 100644
--- a/include/asm-arm/arch-clps711x/time.h
+++ b/include/asm-arm/arch-clps711x/time.h
@@ -26,10 +26,11 @@ extern void clps711x_setup_timer(void);
* IRQ handler for the timer
*/
static irqreturn_t
-p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+p720t_timer_interrupt(int irq, void *dev_id)
{
+ struct pt_regs *regs = get_irq_regs();
do_leds();
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
diff --git a/include/asm-arm/arch-ebsa285/entry-macro.S b/include/asm-arm/arch-ebsa285/entry-macro.S
index cf10ac96fdde..ce812d4f4a33 100644
--- a/include/asm-arm/arch-ebsa285/entry-macro.S
+++ b/include/asm-arm/arch-ebsa285/entry-macro.S
@@ -1,5 +1,5 @@
/*
- * include/asm-arm/arch-footbridge/entry-macro.S
+ * include/asm-arm/arch-ebsa285/entry-macro.S
*
* Low-level IRQ helper macros for footbridge-based platforms
*
diff --git a/include/asm-arm/arch-h720x/system.h b/include/asm-arm/arch-h720x/system.h
index 09eda84592ff..8dc1460b2305 100644
--- a/include/asm-arm/arch-h720x/system.h
+++ b/include/asm-arm/arch-h720x/system.h
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-h720x/system.h
+ * linux/include/asm-arm/arch-h720x/system.h
*
* Copyright (C) 2001-2002 Jungjun Kim, Hynix Semiconductor Inc.
*
diff --git a/include/asm-arm/arch-imx/imx-dma.h b/include/asm-arm/arch-imx/imx-dma.h
index 599f03e5a9ef..5b1066da4e1f 100644
--- a/include/asm-arm/arch-imx/imx-dma.h
+++ b/include/asm-arm/arch-imx/imx-dma.h
@@ -45,8 +45,8 @@
struct imx_dma_channel {
const char *name;
- void (*irq_handler) (int, void *, struct pt_regs *);
- void (*err_handler) (int, void *, struct pt_regs *, int errcode);
+ void (*irq_handler) (int, void *);
+ void (*err_handler) (int, void *, int errcode);
void *data;
dmamode_t dma_mode;
struct scatterlist *sg;
@@ -77,8 +77,8 @@ imx_dma_setup_sg(imx_dmach_t dma_ch,
int
imx_dma_setup_handlers(imx_dmach_t dma_ch,
- void (*irq_handler) (int, void *, struct pt_regs *),
- void (*err_handler) (int, void *, struct pt_regs *, int), void *data);
+ void (*irq_handler) (int, void *),
+ void (*err_handler) (int, void *, int), void *data);
void imx_dma_enable(imx_dmach_t dma_ch);
diff --git a/include/asm-arm/arch-iop32x/debug-macro.S b/include/asm-arm/arch-iop32x/debug-macro.S
new file mode 100644
index 000000000000..9022b6849e23
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/debug-macro.S
@@ -0,0 +1,20 @@
+/*
+ * include/asm-arm/arch-iop32x/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ * Copyright (C) 1994-1999 Russell King
+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * 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.
+ */
+
+ .macro addruart, rx
+ mov \rx, #0xfe000000 @ physical as well as virtual
+ orr \rx, \rx, #0x00800000 @ location of the UART
+ .endm
+
+#define UART_SHIFT 0
+#include <asm/hardware/debug-8250.S>
diff --git a/include/asm-arm/arch-iop3xx/dma.h b/include/asm-arm/arch-iop32x/dma.h
index 1e808db8af2a..e977a9ef3160 100644
--- a/include/asm-arm/arch-iop3xx/dma.h
+++ b/include/asm-arm/arch-iop32x/dma.h
@@ -1,7 +1,7 @@
/*
- * linux/include/asm-arm/arch-iop3xx/dma.h
+ * include/asm-arm/arch-iop32x/dma.h
*
- * Copyright (C) 2004 Intel Corp.
+ * Copyright (C) 2004 Intel Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/include/asm-arm/arch-iop32x/entry-macro.S b/include/asm-arm/arch-iop32x/entry-macro.S
new file mode 100644
index 000000000000..1500cbbd2295
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/entry-macro.S
@@ -0,0 +1,21 @@
+/*
+ * include/asm-arm/arch-iop32x/entry-macro.S
+ *
+ * Low-level IRQ helper macros for IOP32x-based platforms
+ *
+ * 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 <asm/arch/iop32x.h>
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \base, =IOP3XX_REG_ADDR(0x07D8)
+ ldr \irqstat, [\base] @ Read IINTSRC
+ cmp \irqstat, #0
+ clzne \irqnr, \irqstat
+ rsbne \irqnr, \irqnr, #31
+ .endm
diff --git a/include/asm-arm/arch-iop32x/glantank.h b/include/asm-arm/arch-iop32x/glantank.h
new file mode 100644
index 000000000000..3b065618dd00
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/glantank.h
@@ -0,0 +1,13 @@
+/*
+ * include/asm/arch-iop32x/glantank.h
+ *
+ * IO-Data GLAN Tank board registers
+ */
+
+#ifndef __GLANTANK_H
+#define __GLANTANK_H
+
+#define GLANTANK_UART 0xfe800000 /* UART */
+
+
+#endif
diff --git a/include/asm-arm/arch-iop32x/hardware.h b/include/asm-arm/arch-iop32x/hardware.h
new file mode 100644
index 000000000000..6556ed5eee31
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/hardware.h
@@ -0,0 +1,44 @@
+/*
+ * include/asm-arm/arch-iop32x/hardware.h
+ */
+
+#ifndef __HARDWARE_H
+#define __HARDWARE_H
+
+#include <asm/types.h>
+
+/*
+ * Note about PCI IO space mappings
+ *
+ * To make IO space accesses efficient, we store virtual addresses in
+ * the IO resources.
+ *
+ * The PCI IO space is located at virtual 0xfe000000 from physical
+ * 0x90000000. The PCI BARs must be programmed with physical addresses,
+ * but when we read them, we convert them to virtual addresses. See
+ * arch/arm/plat-iop/pci.c.
+ */
+#define pcibios_assign_all_busses() 1
+#define PCIBIOS_MIN_IO 0x00000000
+#define PCIBIOS_MIN_MEM 0x00000000
+
+#ifndef __ASSEMBLY__
+void iop32x_init_irq(void);
+#endif
+
+
+/*
+ * Generic chipset bits
+ */
+#include "iop32x.h"
+
+/*
+ * Board specific bits
+ */
+#include "glantank.h"
+#include "iq80321.h"
+#include "iq31244.h"
+#include "n2100.h"
+
+
+#endif
diff --git a/include/asm-arm/arch-iop3xx/io.h b/include/asm-arm/arch-iop32x/io.h
index 36adbdf5055a..12d9ee02cde3 100644
--- a/include/asm-arm/arch-iop3xx/io.h
+++ b/include/asm-arm/arch-iop32x/io.h
@@ -1,21 +1,22 @@
/*
- * linux/include/asm-arm/arch-iop3xx/io.h
+ * include/asm-arm/arch-iop32x/io.h
*
- * Copyright (C) 2001 MontaVista Software, Inc.
+ * Copyright (C) 2001 MontaVista Software, Inc.
*
* 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_ARM_ARCH_IO_H
-#define __ASM_ARM_ARCH_IO_H
+#ifndef __IO_H
+#define __IO_H
#include <asm/hardware.h>
-#define IO_SPACE_LIMIT 0xffffffff
+#define IO_SPACE_LIMIT 0xffffffff
#define __io(p) ((void __iomem *)(p))
#define __mem_pci(a) (a)
+
#endif
diff --git a/include/asm-arm/arch-iop32x/iop32x.h b/include/asm-arm/arch-iop32x/iop32x.h
new file mode 100644
index 000000000000..4bbd85f3ed2a
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/iop32x.h
@@ -0,0 +1,28 @@
+/*
+ * include/asm-arm/arch-iop32x/iop32x.h
+ *
+ * Intel IOP32X Chip definitions
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ * Copyright (C) 2004 Intel Corp.
+ *
+ * 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 __IOP32X_H
+#define __IOP32X_H
+
+/*
+ * Peripherals that are shared between the iop32x and iop33x but
+ * located at different addresses.
+ */
+#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07c0 + (reg))
+#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07e0 + (reg))
+
+#include <asm/hardware/iop3xx.h>
+
+
+#endif
diff --git a/include/asm-arm/arch-iop3xx/iq31244.h b/include/asm-arm/arch-iop32x/iq31244.h
index 4177cfa8100f..fff4eafa1f6b 100644
--- a/include/asm-arm/arch-iop3xx/iq31244.h
+++ b/include/asm-arm/arch-iop32x/iq31244.h
@@ -1,15 +1,11 @@
/*
- * linux/include/asm/arch-iop3xx/iq31244.h
+ * include/asm-arm/arch-iop32x/iq31244.h
*
* Intel IQ31244 evaluation board registers
*/
-#ifndef _IQ31244_H_
-#define _IQ31244_H_
-
-#define IQ31244_FLASHBASE 0xf0000000 /* Flash */
-#define IQ31244_FLASHSIZE 0x00800000
-#define IQ31244_FLASHWIDTH 2
+#ifndef __IQ31244_H
+#define __IQ31244_H
#define IQ31244_UART 0xfe800000 /* UART #1 */
#define IQ31244_7SEG_1 0xfe840000 /* 7-Segment MSB */
@@ -17,8 +13,5 @@
#define IQ31244_ROTARY_SW 0xfe8d0000 /* Rotary Switch */
#define IQ31244_BATT_STAT 0xfe8f0000 /* Battery Status */
-#ifndef __ASSEMBLY__
-extern void iq31244_map_io(void);
-#endif
-#endif // _IQ31244_H_
+#endif
diff --git a/include/asm-arm/arch-iop3xx/iq80321.h b/include/asm-arm/arch-iop32x/iq80321.h
index cb8725979ffa..eb69db9b9a06 100644
--- a/include/asm-arm/arch-iop3xx/iq80321.h
+++ b/include/asm-arm/arch-iop32x/iq80321.h
@@ -1,15 +1,11 @@
/*
- * linux/include/asm/arch-iop3xx/iq80321.h
+ * include/asm-arm/arch-iop32x/iq80321.h
*
* Intel IQ80321 evaluation board registers
*/
-#ifndef _IQ80321_H_
-#define _IQ80321_H_
-
-#define IQ80321_FLASHBASE 0xf0000000 /* Flash */
-#define IQ80321_FLASHSIZE 0x00800000
-#define IQ80321_FLASHWIDTH 1
+#ifndef __IQ80321_H
+#define __IQ80321_H
#define IQ80321_UART 0xfe800000 /* UART #1 */
#define IQ80321_7SEG_1 0xfe840000 /* 7-Segment MSB */
@@ -17,8 +13,5 @@
#define IQ80321_ROTARY_SW 0xfe8d0000 /* Rotary Switch */
#define IQ80321_BATT_STAT 0xfe8f0000 /* Battery Status */
-#ifndef __ASSEMBLY__
-extern void iq80321_map_io(void);
-#endif
-#endif // _IQ80321_H_
+#endif
diff --git a/include/asm-arm/arch-iop32x/irqs.h b/include/asm-arm/arch-iop32x/irqs.h
new file mode 100644
index 000000000000..bbaef873afce
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/irqs.h
@@ -0,0 +1,50 @@
+/*
+ * include/asm-arm/arch-iop32x/irqs.h
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright: (C) 2002 Rory Bolt
+ *
+ * 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 __IRQS_H
+#define __IRQS_H
+
+/*
+ * IOP80321 chipset interrupts
+ */
+#define IRQ_IOP32X_DMA0_EOT 0
+#define IRQ_IOP32X_DMA0_EOC 1
+#define IRQ_IOP32X_DMA1_EOT 2
+#define IRQ_IOP32X_DMA1_EOC 3
+#define IRQ_IOP32X_AA_EOT 6
+#define IRQ_IOP32X_AA_EOC 7
+#define IRQ_IOP32X_CORE_PMON 8
+#define IRQ_IOP32X_TIMER0 9
+#define IRQ_IOP32X_TIMER1 10
+#define IRQ_IOP32X_I2C_0 11
+#define IRQ_IOP32X_I2C_1 12
+#define IRQ_IOP32X_MESSAGING 13
+#define IRQ_IOP32X_ATU_BIST 14
+#define IRQ_IOP32X_PERFMON 15
+#define IRQ_IOP32X_CORE_PMU 16
+#define IRQ_IOP32X_BIU_ERR 17
+#define IRQ_IOP32X_ATU_ERR 18
+#define IRQ_IOP32X_MCU_ERR 19
+#define IRQ_IOP32X_DMA0_ERR 20
+#define IRQ_IOP32X_DMA1_ERR 21
+#define IRQ_IOP32X_AA_ERR 23
+#define IRQ_IOP32X_MSG_ERR 24
+#define IRQ_IOP32X_SSP 25
+#define IRQ_IOP32X_XINT0 27
+#define IRQ_IOP32X_XINT1 28
+#define IRQ_IOP32X_XINT2 29
+#define IRQ_IOP32X_XINT3 30
+#define IRQ_IOP32X_HPI 31
+
+#define NR_IRQS 32
+
+
+#endif
diff --git a/include/asm-arm/arch-iop32x/memory.h b/include/asm-arm/arch-iop32x/memory.h
new file mode 100644
index 000000000000..764cd3f0d416
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/memory.h
@@ -0,0 +1,26 @@
+/*
+ * include/asm-arm/arch-iop32x/memory.h
+ */
+
+#ifndef __MEMORY_H
+#define __MEMORY_H
+
+#include <asm/hardware.h>
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET UL(0xa0000000)
+
+/*
+ * Virtual view <-> PCI DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ * address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ * to an address that the kernel can use.
+ */
+#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0))
+#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2)))
+
+
+#endif
diff --git a/include/asm-arm/arch-iop32x/n2100.h b/include/asm-arm/arch-iop32x/n2100.h
new file mode 100644
index 000000000000..fed31a648425
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/n2100.h
@@ -0,0 +1,19 @@
+/*
+ * include/asm/arch-iop32x/n2100.h
+ *
+ * Thecus N2100 board registers
+ */
+
+#ifndef __N2100_H
+#define __N2100_H
+
+#define N2100_UART 0xfe800000 /* UART */
+
+#define N2100_COPY_BUTTON IOP3XX_GPIO_LINE(0)
+#define N2100_PCA9532_RESET IOP3XX_GPIO_LINE(2)
+#define N2100_RESET_BUTTON IOP3XX_GPIO_LINE(3)
+#define N2100_HARDWARE_RESET IOP3XX_GPIO_LINE(4)
+#define N2100_POWER_BUTTON IOP3XX_GPIO_LINE(5)
+
+
+#endif
diff --git a/include/asm-arm/arch-iop32x/system.h b/include/asm-arm/arch-iop32x/system.h
new file mode 100644
index 000000000000..17b7eb7e9c0d
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/system.h
@@ -0,0 +1,33 @@
+/*
+ * include/asm-arm/arch-iop32x/system.h
+ *
+ * Copyright (C) 2001 MontaVista Software, Inc.
+ *
+ * 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 <asm/mach-types.h>
+
+static inline void arch_idle(void)
+{
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode)
+{
+ local_irq_disable();
+
+ if (machine_is_n2100()) {
+ gpio_line_set(N2100_HARDWARE_RESET, GPIO_LOW);
+ gpio_line_config(N2100_HARDWARE_RESET, GPIO_OUT);
+ while (1)
+ ;
+ }
+
+ *IOP3XX_PCSR = 0x30;
+
+ /* Jump into ROM at address 0 */
+ cpu_reset(0);
+}
diff --git a/include/asm-arm/arch-iop32x/timex.h b/include/asm-arm/arch-iop32x/timex.h
new file mode 100644
index 000000000000..9934b087311b
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/timex.h
@@ -0,0 +1,9 @@
+/*
+ * include/asm-arm/arch-iop32x/timex.h
+ *
+ * IOP32x architecture timex specifications
+ */
+
+#include <asm/hardware.h>
+
+#define CLOCK_TICK_RATE (100 * HZ)
diff --git a/include/asm-arm/arch-iop32x/uncompress.h b/include/asm-arm/arch-iop32x/uncompress.h
new file mode 100644
index 000000000000..e64f52bf2bce
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/uncompress.h
@@ -0,0 +1,39 @@
+/*
+ * include/asm-arm/arch-iop32x/uncompress.h
+ */
+
+#include <asm/types.h>
+#include <asm/mach-types.h>
+#include <linux/serial_reg.h>
+#include <asm/hardware.h>
+
+static volatile u8 *uart_base;
+
+#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
+
+static inline void putc(char c)
+{
+ while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE)
+ barrier();
+ uart_base[UART_TX] = c;
+}
+
+static inline void flush(void)
+{
+}
+
+static __inline__ void __arch_decomp_setup(unsigned long arch_id)
+{
+ if (machine_is_iq80321())
+ uart_base = (volatile u8 *)IQ80321_UART;
+ else if (machine_is_iq31244())
+ uart_base = (volatile u8 *)IQ31244_UART;
+ else
+ uart_base = (volatile u8 *)0xfe800000;
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup() __arch_decomp_setup(arch_id)
+#define arch_decomp_wdog()
diff --git a/include/asm-arm/arch-iop32x/vmalloc.h b/include/asm-arm/arch-iop32x/vmalloc.h
new file mode 100644
index 000000000000..0a70baa19517
--- /dev/null
+++ b/include/asm-arm/arch-iop32x/vmalloc.h
@@ -0,0 +1,5 @@
+/*
+ * include/asm-arm/arch-iop32x/vmalloc.h
+ */
+
+#define VMALLOC_END 0xfe000000
diff --git a/include/asm-arm/arch-iop33x/debug-macro.S b/include/asm-arm/arch-iop33x/debug-macro.S
new file mode 100644
index 000000000000..9e7132ebe6a7
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/debug-macro.S
@@ -0,0 +1,24 @@
+/*
+ * include/asm-arm/arch-iop33x/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ * Copyright (C) 1994-1999 Russell King
+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * 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.
+ */
+
+ .macro addruart, rx
+ mrc p15, 0, \rx, c1, c0
+ tst \rx, #1 @ mmu enabled?
+ moveq \rx, #0xff000000 @ physical
+ movne \rx, #0xfe000000 @ virtual
+ orr \rx, \rx, #0x00ff0000
+ orr \rx, \rx, #0x0000f700
+ .endm
+
+#define UART_SHIFT 2
+#include <asm/hardware/debug-8250.S>
diff --git a/include/asm-arm/arch-iop33x/dma.h b/include/asm-arm/arch-iop33x/dma.h
new file mode 100644
index 000000000000..b7775fdc5ad3
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/dma.h
@@ -0,0 +1,9 @@
+/*
+ * include/asm-arm/arch-iop33x/dma.h
+ *
+ * Copyright (C) 2004 Intel Corp.
+ *
+ * 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.
+ */
diff --git a/include/asm-arm/arch-iop33x/entry-macro.S b/include/asm-arm/arch-iop33x/entry-macro.S
new file mode 100644
index 000000000000..92b791702e34
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/entry-macro.S
@@ -0,0 +1,22 @@
+/*
+ * include/asm-arm/arch-iop33x/entry-macro.S
+ *
+ * Low-level IRQ helper macros for IOP33x-based platforms
+ *
+ * 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 <asm/arch/iop33x.h>
+
+ .macro disable_fiq
+ .endm
+
+ .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
+ ldr \base, =IOP3XX_REG_ADDR(0x07C8)
+ ldr \irqstat, [\base] @ Read IINTVEC
+ cmp \irqstat, #0
+ ldreq \irqstat, [\base] @ erratum 63 workaround
+ adds \irqnr, \irqstat, #1
+ movne \irqnr, \irqstat, lsr #2
+ .endm
diff --git a/include/asm-arm/arch-iop33x/hardware.h b/include/asm-arm/arch-iop33x/hardware.h
new file mode 100644
index 000000000000..0659cf94d040
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/hardware.h
@@ -0,0 +1,46 @@
+/*
+ * include/asm-arm/arch-iop33x/hardware.h
+ */
+
+#ifndef __HARDWARE_H
+#define __HARDWARE_H
+
+#include <asm/types.h>
+
+/*
+ * Note about PCI IO space mappings
+ *
+ * To make IO space accesses efficient, we store virtual addresses in
+ * the IO resources.
+ *
+ * The PCI IO space is located at virtual 0xfe000000 from physical
+ * 0x90000000. The PCI BARs must be programmed with physical addresses,
+ * but when we read them, we convert them to virtual addresses. See
+ * arch/arm/mach-iop3xx/iop3xx-pci.c
+ */
+#define pcibios_assign_all_busses() 1
+#define PCIBIOS_MIN_IO 0x00000000
+#define PCIBIOS_MIN_MEM 0x00000000
+
+#ifndef __ASSEMBLY__
+void iop33x_init_irq(void);
+
+extern struct platform_device iop33x_uart0_device;
+extern struct platform_device iop33x_uart1_device;
+#endif
+
+
+/*
+ * Generic chipset bits
+ *
+ */
+#include "iop33x.h"
+
+/*
+ * Board specific bits
+ */
+#include "iq80331.h"
+#include "iq80332.h"
+
+
+#endif
diff --git a/include/asm-arm/arch-iop33x/io.h b/include/asm-arm/arch-iop33x/io.h
new file mode 100644
index 000000000000..c017402bab96
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/io.h
@@ -0,0 +1,21 @@
+/*
+ * include/asm-arm/arch-iop33x/io.h
+ *
+ * Copyright (C) 2001 MontaVista Software, Inc.
+ *
+ * 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 __IO_H
+#define __IO_H
+
+#include <asm/hardware.h>
+
+#define IO_SPACE_LIMIT 0xffffffff
+#define __io(p) ((void __iomem *)(p))
+#define __mem_pci(a) (a)
+
+
+#endif
diff --git a/include/asm-arm/arch-iop33x/iop33x.h b/include/asm-arm/arch-iop33x/iop33x.h
new file mode 100644
index 000000000000..7ac6e93db5ff
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/iop33x.h
@@ -0,0 +1,33 @@
+/*
+ * include/asm-arm/arch-iop33x/iop33x.h
+ *
+ * Intel IOP33X Chip definitions
+ *
+ * Author: Dave Jiang (dave.jiang@intel.com)
+ * Copyright (C) 2003, 2004 Intel Corp.
+ *
+ * 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 __IOP33X_H
+#define __IOP33X_H
+
+/*
+ * Peripherals that are shared between the iop32x and iop33x but
+ * located at different addresses.
+ */
+#define IOP3XX_GPIO_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1780 + (reg))
+#define IOP3XX_TIMER_REG(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + 0x07d0 + (reg))
+
+#include <asm/hardware/iop3xx.h>
+
+/* UARTs */
+#define IOP33X_UART0_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1700)
+#define IOP33X_UART0_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1700)
+#define IOP33X_UART1_PHYS (IOP3XX_PERIPHERAL_PHYS_BASE + 0x1740)
+#define IOP33X_UART1_VIRT (IOP3XX_PERIPHERAL_VIRT_BASE + 0x1740)
+
+
+#endif
diff --git a/include/asm-arm/arch-iop3xx/iq80331.h b/include/asm-arm/arch-iop33x/iq80331.h
index 0668e78d483e..79b9302017ea 100644
--- a/include/asm-arm/arch-iop3xx/iq80331.h
+++ b/include/asm-arm/arch-iop33x/iq80331.h
@@ -1,23 +1,16 @@
/*
- * linux/include/asm/arch-iop3xx/iq80331.h
+ * include/asm-arm/arch-iop33x/iq80331.h
*
* Intel IQ80331 evaluation board registers
*/
-#ifndef _IQ80331_H_
-#define _IQ80331_H_
-
-#define IQ80331_FLASHBASE 0xc0000000 /* Flash */
-#define IQ80331_FLASHSIZE 0x00800000
-#define IQ80331_FLASHWIDTH 1
+#ifndef __IQ80331_H
+#define __IQ80331_H
#define IQ80331_7SEG_1 0xce840000 /* 7-Segment MSB */
#define IQ80331_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */
#define IQ80331_ROTARY_SW 0xce8d0000 /* Rotary Switch */
#define IQ80331_BATT_STAT 0xce8f0000 /* Battery Status */
-#ifndef __ASSEMBLY__
-extern void iq80331_map_io(void);
-#endif
-#endif // _IQ80331_H_
+#endif
diff --git a/include/asm-arm/arch-iop3xx/iq80332.h b/include/asm-arm/arch-iop33x/iq80332.h
index e5fff1775d1a..053165629492 100644
--- a/include/asm-arm/arch-iop3xx/iq80332.h
+++ b/include/asm-arm/arch-iop33x/iq80332.h
@@ -1,23 +1,16 @@
/*
- * linux/include/asm/arch-iop3xx/iq80332.h
+ * include/asm-arm/arch-iop33x/iq80332.h
*
* Intel IQ80332 evaluation board registers
*/
-#ifndef _IQ80332_H_
-#define _IQ80332_H_
-
-#define IQ80332_FLASHBASE 0xc0000000 /* Flash */
-#define IQ80332_FLASHSIZE 0x00800000
-#define IQ80332_FLASHWIDTH 1
+#ifndef __IQ80332_H
+#define __IQ80332_H
#define IQ80332_7SEG_1 0xce840000 /* 7-Segment MSB */
#define IQ80332_7SEG_0 0xce850000 /* 7-Segment LSB (WO) */
#define IQ80332_ROTARY_SW 0xce8d0000 /* Rotary Switch */
#define IQ80332_BATT_STAT 0xce8f0000 /* Battery Status */
-#ifndef __ASSEMBLY__
-extern void iq80332_map_io(void);
-#endif
-#endif // _IQ80332_H_
+#endif
diff --git a/include/asm-arm/arch-iop33x/irqs.h b/include/asm-arm/arch-iop33x/irqs.h
new file mode 100644
index 000000000000..d045f8403396
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/irqs.h
@@ -0,0 +1,60 @@
+/*
+ * include/asm-arm/arch-iop33x/irqs.h
+ *
+ * Author: Dave Jiang (dave.jiang@intel.com)
+ * Copyright: (C) 2003 Intel Corp.
+ *
+ * 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 __IRQS_H
+#define __IRQS_H
+
+/*
+ * IOP80331 chipset interrupts
+ */
+#define IRQ_IOP33X_DMA0_EOT 0
+#define IRQ_IOP33X_DMA0_EOC 1
+#define IRQ_IOP33X_DMA1_EOT 2
+#define IRQ_IOP33X_DMA1_EOC 3
+#define IRQ_IOP33X_AA_EOT 6
+#define IRQ_IOP33X_AA_EOC 7
+#define IRQ_IOP33X_TIMER0 8
+#define IRQ_IOP33X_TIMER1 9
+#define IRQ_IOP33X_I2C_0 10
+#define IRQ_IOP33X_I2C_1 11
+#define IRQ_IOP33X_MSG 12
+#define IRQ_IOP33X_MSGIBQ 13
+#define IRQ_IOP33X_ATU_BIST 14
+#define IRQ_IOP33X_PERFMON 15
+#define IRQ_IOP33X_CORE_PMU 16
+#define IRQ_IOP33X_XINT0 24
+#define IRQ_IOP33X_XINT1 25
+#define IRQ_IOP33X_XINT2 26
+#define IRQ_IOP33X_XINT3 27
+#define IRQ_IOP33X_XINT8 32
+#define IRQ_IOP33X_XINT9 33
+#define IRQ_IOP33X_XINT10 34
+#define IRQ_IOP33X_XINT11 35
+#define IRQ_IOP33X_XINT12 36
+#define IRQ_IOP33X_XINT13 37
+#define IRQ_IOP33X_XINT14 38
+#define IRQ_IOP33X_XINT15 39
+#define IRQ_IOP33X_UART0 51
+#define IRQ_IOP33X_UART1 52
+#define IRQ_IOP33X_PBIE 53
+#define IRQ_IOP33X_ATU_CRW 54
+#define IRQ_IOP33X_ATU_ERR 55
+#define IRQ_IOP33X_MCU_ERR 56
+#define IRQ_IOP33X_DMA0_ERR 57
+#define IRQ_IOP33X_DMA1_ERR 58
+#define IRQ_IOP33X_AA_ERR 60
+#define IRQ_IOP33X_MSG_ERR 62
+#define IRQ_IOP33X_HPI 63
+
+#define NR_IRQS 64
+
+
+#endif
diff --git a/include/asm-arm/arch-iop33x/memory.h b/include/asm-arm/arch-iop33x/memory.h
new file mode 100644
index 000000000000..0d39139b241e
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/memory.h
@@ -0,0 +1,26 @@
+/*
+ * include/asm-arm/arch-iop33x/memory.h
+ */
+
+#ifndef __MEMORY_H
+#define __MEMORY_H
+
+#include <asm/hardware.h>
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET UL(0x00000000)
+
+/*
+ * Virtual view <-> PCI DMA view memory address translations
+ * virt_to_bus: Used to translate the virtual address to an
+ * address suitable to be passed to set_dma_addr
+ * bus_to_virt: Used to convert an address for DMA operations
+ * to an address that the kernel can use.
+ */
+#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP3XX_IATVR2)) | ((*IOP3XX_IABAR2) & 0xfffffff0))
+#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP3XX_IALR2)) | ( *IOP3XX_IATVR2)))
+
+
+#endif
diff --git a/include/asm-arm/arch-iop33x/system.h b/include/asm-arm/arch-iop33x/system.h
new file mode 100644
index 000000000000..00dd07ece262
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/system.h
@@ -0,0 +1,22 @@
+/*
+ * include/asm-arm/arch-iop33x/system.h
+ *
+ * Copyright (C) 2001 MontaVista Software, Inc.
+ *
+ * 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.
+ */
+
+static inline void arch_idle(void)
+{
+ cpu_do_idle();
+}
+
+static inline void arch_reset(char mode)
+{
+ *IOP3XX_PCSR = 0x30;
+
+ /* Jump into ROM at address 0 */
+ cpu_reset(0);
+}
diff --git a/include/asm-arm/arch-iop33x/timex.h b/include/asm-arm/arch-iop33x/timex.h
new file mode 100644
index 000000000000..fe3e1e369ff9
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/timex.h
@@ -0,0 +1,9 @@
+/*
+ * include/asm-arm/arch-iop33x/timex.h
+ *
+ * IOP3xx architecture timex specifications
+ */
+
+#include <asm/hardware.h>
+
+#define CLOCK_TICK_RATE (100 * HZ)
diff --git a/include/asm-arm/arch-iop33x/uncompress.h b/include/asm-arm/arch-iop33x/uncompress.h
new file mode 100644
index 000000000000..e17fbc05877b
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/uncompress.h
@@ -0,0 +1,37 @@
+/*
+ * include/asm-arm/arch-iop33x/uncompress.h
+ */
+
+#include <asm/types.h>
+#include <asm/mach-types.h>
+#include <linux/serial_reg.h>
+#include <asm/hardware.h>
+
+static volatile u32 *uart_base;
+
+#define TX_DONE (UART_LSR_TEMT | UART_LSR_THRE)
+
+static inline void putc(char c)
+{
+ while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE)
+ barrier();
+ uart_base[UART_TX] = c;
+}
+
+static inline void flush(void)
+{
+}
+
+static __inline__ void __arch_decomp_setup(unsigned long arch_id)
+{
+ if (machine_is_iq80331() || machine_is_iq80332())
+ uart_base = (volatile u32 *)IOP33X_UART0_PHYS;
+ else
+ uart_base = (volatile u32 *)0xfe800000;
+}
+
+/*
+ * nothing to do
+ */
+#define arch_decomp_setup() __arch_decomp_setup(arch_id)
+#define arch_decomp_wdog()
diff --git a/include/asm-arm/arch-iop33x/vmalloc.h b/include/asm-arm/arch-iop33x/vmalloc.h
new file mode 100644
index 000000000000..66f545a7f4fc
--- /dev/null
+++ b/include/asm-arm/arch-iop33x/vmalloc.h
@@ -0,0 +1,5 @@
+/*
+ * include/asm-arm/arch-iop33x/vmalloc.h
+ */
+
+#define VMALLOC_END 0xfe000000
diff --git a/include/asm-arm/arch-iop3xx/debug-macro.S b/include/asm-arm/arch-iop3xx/debug-macro.S
deleted file mode 100644
index ce007e531994..000000000000
--- a/include/asm-arm/arch-iop3xx/debug-macro.S
+++ /dev/null
@@ -1,35 +0,0 @@
-/* linux/include/asm-arm/arch-iop3xx/debug-macro.S
- *
- * Debugging macro include header
- *
- * Copyright (C) 1994-1999 Russell King
- * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
- *
- * 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.
- *
-*/
-
- .macro addruart,rx
- mov \rx, #0xfe000000 @ physical
-#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244)
- orr \rx, \rx, #0x00800000 @ location of the UART
-#elif defined(CONFIG_ARCH_IOP331)
- mrc p15, 0, \rx, c1, c0
- tst \rx, #1 @ MMU enabled?
- moveq \rx, #0x000fe000 @ Physical Base
- movne \rx, #0
- orr \rx, \rx, #0xfe000000
- orr \rx, \rx, #0x00f00000 @ Virtual Base
- orr \rx, \rx, #0x00001700 @ location of the UART
-#else
-#error Unknown IOP3XX implementation
-#endif
- .endm
-
-#if !defined(CONFIG_ARCH_IQ80321) || !defined(CONFIG_ARCH_IQ31244) || !defined(CONFIG_ARCH_IQ80331)
-#define FLOW_CONTROL
-#endif
-#define UART_SHIFT 0
-#include <asm/hardware/debug-8250.S>
diff --git a/include/asm-arm/arch-iop3xx/entry-macro.S b/include/asm-arm/arch-iop3xx/entry-macro.S
deleted file mode 100644
index 926668c098a5..000000000000
--- a/include/asm-arm/arch-iop3xx/entry-macro.S
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * include/asm-arm/arch-iop3xx/entry-macro.S
- *
- * Low-level IRQ helper macros for IOP3xx-based platforms
- *
- * 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 <asm/arch/irqs.h>
-
-#if defined(CONFIG_ARCH_IOP321)
- .macro disable_fiq
- .endm
-
- /*
- * Note: only deal with normal interrupts, not FIQ
- */
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- mov \irqnr, #0
- mrc p6, 0, \irqstat, c8, c0, 0 @ Read IINTSRC
- cmp \irqstat, #0
- beq 1001f
- clz \irqnr, \irqstat
- mov \base, #31
- subs \irqnr,\base,\irqnr
- add \irqnr,\irqnr,#IRQ_IOP321_DMA0_EOT
-1001:
- .endm
-
-#elif defined(CONFIG_ARCH_IOP331)
- .macro disable_fiq
- .endm
-
- /*
- * Note: only deal with normal interrupts, not FIQ
- */
- .macro get_irqnr_and_base, irqnr, irqstat, base, tmp
- mov \irqnr, #0
- mrc p6, 0, \irqstat, c4, c0, 0 @ Read IINTSRC0
- cmp \irqstat, #0
- bne 1002f
- mrc p6, 0, \irqstat, c5, c0, 0 @ Read IINTSRC1
- cmp \irqstat, #0
- beq 1001f
- clz \irqnr, \irqstat
- rsbs \irqnr,\irqnr,#31 @ recommend by RMK
- add \irqnr,\irqnr,#IRQ_IOP331_XINT8
- b 1001f
-1002: clz \irqnr, \irqstat
- rsbs \irqnr,\irqnr,#31 @ recommend by RMK
- add \irqnr,\irqnr,#IRQ_IOP331_DMA0_EOT
-1001:
- .endm
-
-#endif
-
diff --git a/include/asm-arm/arch-iop3xx/hardware.h b/include/asm-arm/arch-iop3xx/hardware.h
deleted file mode 100644
index 3b138171d086..000000000000
--- a/include/asm-arm/arch-iop3xx/hardware.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/hardware.h
- */
-#ifndef __ASM_ARCH_HARDWARE_H
-#define __ASM_ARCH_HARDWARE_H
-
-#include <asm/types.h>
-
-/*
- * Note about PCI IO space mappings
- *
- * To make IO space accesses efficient, we store virtual addresses in
- * the IO resources.
- *
- * The PCI IO space is located at virtual 0xfe000000 from physical
- * 0x90000000. The PCI BARs must be programmed with physical addresses,
- * but when we read them, we convert them to virtual addresses. See
- * arch/arm/mach-iop3xx/iop3xx-pci.c
- */
-
-#define pcibios_assign_all_busses() 1
-
-
-/*
- * The min PCI I/O and MEM space are dependent on what specific
- * chipset/platform we are running on, so instead of hardcoding with
- * #ifdefs, we just fill these in the platform level PCI init code.
- */
-#ifndef __ASSEMBLY__
-extern unsigned long iop3xx_pcibios_min_io;
-extern unsigned long iop3xx_pcibios_min_mem;
-
-extern unsigned int processor_id;
-#endif
-
-/*
- * We just set these to zero since they are really bogus anyways
- */
-#define PCIBIOS_MIN_IO (iop3xx_pcibios_min_io)
-#define PCIBIOS_MIN_MEM (iop3xx_pcibios_min_mem)
-
-/*
- * Generic chipset bits
- *
- */
-#include "iop321.h"
-#include "iop331.h"
-
-/*
- * Board specific bits
- */
-#include "iq80321.h"
-#include "iq31244.h"
-#include "iq80331.h"
-#include "iq80332.h"
-
-#endif /* _ASM_ARCH_HARDWARE_H */
diff --git a/include/asm-arm/arch-iop3xx/iop321-irqs.h b/include/asm-arm/arch-iop3xx/iop321-irqs.h
deleted file mode 100644
index 2fcc1654cb9d..000000000000
--- a/include/asm-arm/arch-iop3xx/iop321-irqs.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/irqs.h
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright: (C) 2002 Rory Bolt
- *
- * 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 _IOP321_IRQS_H_
-#define _IOP321_IRQS_H_
-
-/*
- * IOP80321 chipset interrupts
- */
-#define IOP321_IRQ_OFS 0
-#define IOP321_IRQ(x) (IOP321_IRQ_OFS + (x))
-
-/*
- * On IRQ or FIQ register
- */
-#define IRQ_IOP321_DMA0_EOT IOP321_IRQ(0)
-#define IRQ_IOP321_DMA0_EOC IOP321_IRQ(1)
-#define IRQ_IOP321_DMA1_EOT IOP321_IRQ(2)
-#define IRQ_IOP321_DMA1_EOC IOP321_IRQ(3)
-#define IRQ_IOP321_RSVD_4 IOP321_IRQ(4)
-#define IRQ_IOP321_RSVD_5 IOP321_IRQ(5)
-#define IRQ_IOP321_AA_EOT IOP321_IRQ(6)
-#define IRQ_IOP321_AA_EOC IOP321_IRQ(7)
-#define IRQ_IOP321_CORE_PMON IOP321_IRQ(8)
-#define IRQ_IOP321_TIMER0 IOP321_IRQ(9)
-#define IRQ_IOP321_TIMER1 IOP321_IRQ(10)
-#define IRQ_IOP321_I2C_0 IOP321_IRQ(11)
-#define IRQ_IOP321_I2C_1 IOP321_IRQ(12)
-#define IRQ_IOP321_MESSAGING IOP321_IRQ(13)
-#define IRQ_IOP321_ATU_BIST IOP321_IRQ(14)
-#define IRQ_IOP321_PERFMON IOP321_IRQ(15)
-#define IRQ_IOP321_CORE_PMU IOP321_IRQ(16)
-#define IRQ_IOP321_BIU_ERR IOP321_IRQ(17)
-#define IRQ_IOP321_ATU_ERR IOP321_IRQ(18)
-#define IRQ_IOP321_MCU_ERR IOP321_IRQ(19)
-#define IRQ_IOP321_DMA0_ERR IOP321_IRQ(20)
-#define IRQ_IOP321_DMA1_ERR IOP321_IRQ(21)
-#define IRQ_IOP321_RSVD_22 IOP321_IRQ(22)
-#define IRQ_IOP321_AA_ERR IOP321_IRQ(23)
-#define IRQ_IOP321_MSG_ERR IOP321_IRQ(24)
-#define IRQ_IOP321_SSP IOP321_IRQ(25)
-#define IRQ_IOP321_RSVD_26 IOP321_IRQ(26)
-#define IRQ_IOP321_XINT0 IOP321_IRQ(27)
-#define IRQ_IOP321_XINT1 IOP321_IRQ(28)
-#define IRQ_IOP321_XINT2 IOP321_IRQ(29)
-#define IRQ_IOP321_XINT3 IOP321_IRQ(30)
-#define IRQ_IOP321_HPI IOP321_IRQ(31)
-
-#define NR_IOP321_IRQS (IOP321_IRQ(31) + 1)
-
-#define NR_IRQS NR_IOP321_IRQS
-
-
-/*
- * Interrupts available on the IQ80321 board
- */
-
-/*
- * On board devices
- */
-#define IRQ_IQ80321_I82544 IRQ_IOP321_XINT0
-#define IRQ_IQ80321_UART IRQ_IOP321_XINT1
-
-/*
- * PCI interrupts
- */
-#define IRQ_IQ80321_INTA IRQ_IOP321_XINT0
-#define IRQ_IQ80321_INTB IRQ_IOP321_XINT1
-#define IRQ_IQ80321_INTC IRQ_IOP321_XINT2
-#define IRQ_IQ80321_INTD IRQ_IOP321_XINT3
-
-/*
- * Interrupts on the IQ31244 board
- */
-
-/*
- * On board devices
- */
-#define IRQ_IQ31244_UART IRQ_IOP321_XINT1
-#define IRQ_IQ31244_I82546 IRQ_IOP321_XINT0
-#define IRQ_IQ31244_SATA IRQ_IOP321_XINT2
-#define IRQ_IQ31244_PCIX_SLOT IRQ_IOP321_XINT3
-
-/*
- * PCI interrupts
- */
-#define IRQ_IQ31244_INTA IRQ_IOP321_XINT0
-#define IRQ_IQ31244_INTB IRQ_IOP321_XINT1
-#define IRQ_IQ31244_INTC IRQ_IOP321_XINT2
-#define IRQ_IQ31244_INTD IRQ_IOP321_XINT3
-
-#endif // _IOP321_IRQ_H_
diff --git a/include/asm-arm/arch-iop3xx/iop321.h b/include/asm-arm/arch-iop3xx/iop321.h
deleted file mode 100644
index f8df778a356f..000000000000
--- a/include/asm-arm/arch-iop3xx/iop321.h
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * linux/include/asm/arch-iop3xx/iop321.h
- *
- * Intel IOP321 Chip definitions
- *
- * Author: Rory Bolt <rorybolt@pacbell.net>
- * Copyright (C) 2002 Rory Bolt
- * Copyright (C) 2004 Intel Corp.
- *
- * 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 _IOP321_HW_H_
-#define _IOP321_HW_H_
-
-
-/*
- * This is needed for mixed drivers that need to work on all
- * IOP3xx variants but behave slightly differently on each.
- */
-#ifndef __ASSEMBLY__
-#ifdef CONFIG_ARCH_IOP321
-#define iop_is_321() (((processor_id & 0xfffff5e0) == 0x69052420))
-#else
-#define iop_is_321() 0
-#endif
-#endif
-
-/*
- * IOP321 I/O and Mem space regions for PCI autoconfiguration
- */
-#define IOP321_PCI_IO_WINDOW_SIZE 0x00010000
-#define IOP321_PCI_LOWER_IO_PA 0x90000000
-#define IOP321_PCI_LOWER_IO_VA 0xfe000000
-#define IOP321_PCI_LOWER_IO_BA (*IOP321_OIOWTVR)
-#define IOP321_PCI_UPPER_IO_PA (IOP321_PCI_LOWER_IO_PA + IOP321_PCI_IO_WINDOW_SIZE - 1)
-#define IOP321_PCI_UPPER_IO_VA (IOP321_PCI_LOWER_IO_VA + IOP321_PCI_IO_WINDOW_SIZE - 1)
-#define IOP321_PCI_UPPER_IO_BA (IOP321_PCI_LOWER_IO_BA + IOP321_PCI_IO_WINDOW_SIZE - 1)
-#define IOP321_PCI_IO_OFFSET (IOP321_PCI_LOWER_IO_VA - IOP321_PCI_LOWER_IO_BA)
-
-/* #define IOP321_PCI_MEM_WINDOW_SIZE (~*IOP321_IALR1 + 1) */
-#define IOP321_PCI_MEM_WINDOW_SIZE 0x04000000 /* 64M outbound window */
-#define IOP321_PCI_LOWER_MEM_PA 0x80000000
-#define IOP321_PCI_LOWER_MEM_BA (*IOP321_OMWTVR0)
-#define IOP321_PCI_UPPER_MEM_PA (IOP321_PCI_LOWER_MEM_PA + IOP321_PCI_MEM_WINDOW_SIZE - 1)
-#define IOP321_PCI_UPPER_MEM_BA (IOP321_PCI_LOWER_MEM_BA + IOP321_PCI_MEM_WINDOW_SIZE - 1)
-#define IOP321_PCI_MEM_OFFSET (IOP321_PCI_LOWER_MEM_PA - IOP321_PCI_LOWER_MEM_BA)
-
-
-/*
- * IOP321 chipset registers
- */
-#define IOP321_VIRT_MEM_BASE 0xfeffe000 /* chip virtual mem address*/
-#define IOP321_PHYS_MEM_BASE 0xffffe000 /* chip physical memory address */
-#define IOP321_REG_ADDR(reg) (IOP321_VIRT_MEM_BASE | (reg))
-
-/* Reserved 0x00000000 through 0x000000FF */
-
-/* Address Translation Unit 0x00000100 through 0x000001FF */
-#define IOP321_ATUVID (volatile u16 *)IOP321_REG_ADDR(0x00000100)
-#define IOP321_ATUDID (volatile u16 *)IOP321_REG_ADDR(0x00000102)
-#define IOP321_ATUCMD (volatile u16 *)IOP321_REG_ADDR(0x00000104)
-#define IOP321_ATUSR (volatile u16 *)IOP321_REG_ADDR(0x00000106)
-#define IOP321_ATURID (volatile u8 *)IOP321_REG_ADDR(0x00000108)
-#define IOP321_ATUCCR (volatile u32 *)IOP321_REG_ADDR(0x00000109)
-#define IOP321_ATUCLSR (volatile u8 *)IOP321_REG_ADDR(0x0000010C)
-#define IOP321_ATULT (volatile u8 *)IOP321_REG_ADDR(0x0000010D)
-#define IOP321_ATUHTR (volatile u8 *)IOP321_REG_ADDR(0x0000010E)
-#define IOP321_ATUBIST (volatile u8 *)IOP321_REG_ADDR(0x0000010F)
-#define IOP321_IABAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000110)
-#define IOP321_IAUBAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000114)
-#define IOP321_IABAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000118)
-#define IOP321_IAUBAR1 (volatile u32 *)IOP321_REG_ADDR(0x0000011C)
-#define IOP321_IABAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000120)
-#define IOP321_IAUBAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000124)
-#define IOP321_ASVIR (volatile u16 *)IOP321_REG_ADDR(0x0000012C)
-#define IOP321_ASIR (volatile u16 *)IOP321_REG_ADDR(0x0000012E)
-#define IOP321_ERBAR (volatile u32 *)IOP321_REG_ADDR(0x00000130)
-/* Reserved 0x00000134 through 0x0000013B */
-#define IOP321_ATUILR (volatile u8 *)IOP321_REG_ADDR(0x0000013C)
-#define IOP321_ATUIPR (volatile u8 *)IOP321_REG_ADDR(0x0000013D)
-#define IOP321_ATUMGNT (volatile u8 *)IOP321_REG_ADDR(0x0000013E)
-#define IOP321_ATUMLAT (volatile u8 *)IOP321_REG_ADDR(0x0000013F)
-#define IOP321_IALR0 (volatile u32 *)IOP321_REG_ADDR(0x00000140)
-#define IOP321_IATVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000144)
-#define IOP321_ERLR (volatile u32 *)IOP321_REG_ADDR(0x00000148)
-#define IOP321_ERTVR (volatile u32 *)IOP321_REG_ADDR(0x0000014C)
-#define IOP321_IALR1 (volatile u32 *)IOP321_REG_ADDR(0x00000150)
-#define IOP321_IALR2 (volatile u32 *)IOP321_REG_ADDR(0x00000154)
-#define IOP321_IATVR2 (volatile u32 *)IOP321_REG_ADDR(0x00000158)
-#define IOP321_OIOWTVR (volatile u32 *)IOP321_REG_ADDR(0x0000015C)
-#define IOP321_OMWTVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000160)
-#define IOP321_OUMWTVR0 (volatile u32 *)IOP321_REG_ADDR(0x00000164)
-#define IOP321_OMWTVR1 (volatile u32 *)IOP321_REG_ADDR(0x00000168)
-#define IOP321_OUMWTVR1 (volatile u32 *)IOP321_REG_ADDR(0x0000016C)
-/* Reserved 0x00000170 through 0x00000177*/
-#define IOP321_OUDWTVR (volatile u32 *)IOP321_REG_ADDR(0x00000178)
-/* Reserved 0x0000017C through 0x0000017F*/
-#define IOP321_ATUCR (volatile u32 *)IOP321_REG_ADDR(0x00000180)
-#define IOP321_PCSR (volatile u32 *)IOP321_REG_ADDR(0x00000184)
-#define IOP321_ATUISR (volatile u32 *)IOP321_REG_ADDR(0x00000188)
-#define IOP321_ATUIMR (volatile u32 *)IOP321_REG_ADDR(0x0000018C)
-#define IOP321_IABAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000190)
-#define IOP321_IAUBAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000194)
-#define IOP321_IALR3 (volatile u32 *)IOP321_REG_ADDR(0x00000198)
-#define IOP321_IATVR3 (volatile u32 *)IOP321_REG_ADDR(0x0000019C)
-/* Reserved 0x000001A0 through 0x000001A3*/
-#define IOP321_OCCAR (volatile u32 *)IOP321_REG_ADDR(0x000001A4)
-/* Reserved 0x000001A8 through 0x000001AB*/
-#define IOP321_OCCDR (volatile u32 *)IOP321_REG_ADDR(0x000001AC)
-/* Reserved 0x000001B0 through 0x000001BB*/
-#define IOP321_PDSCR (volatile u32 *)IOP321_REG_ADDR(0x000001BC)
-#define IOP321_PMCAPID (volatile u8 *)IOP321_REG_ADDR(0x000001C0)
-#define IOP321_PMNEXT (volatile u8 *)IOP321_REG_ADDR(0x000001C1)
-#define IOP321_APMCR (volatile u16 *)IOP321_REG_ADDR(0x000001C2)
-#define IOP321_APMCSR (volatile u16 *)IOP321_REG_ADDR(0x000001C4)
-/* Reserved 0x000001C6 through 0x000001DF */
-#define IOP321_PCIXCAPID (volatile u8 *)IOP321_REG_ADDR(0x000001E0)
-#define IOP321_PCIXNEXT (volatile u8 *)IOP321_REG_ADDR(0x000001E1)
-#define IOP321_PCIXCMD (volatile u16 *)IOP321_REG_ADDR(0x000001E2)
-#define IOP321_PCIXSR (volatile u32 *)IOP321_REG_ADDR(0x000001E4)
-#define IOP321_PCIIRSR (volatile u32 *)IOP321_REG_ADDR(0x000001EC)
-
-/* Messaging Unit 0x00000300 through 0x000003FF */
-
-/* Reserved 0x00000300 through 0x0000030c */
-#define IOP321_IMR0 (volatile u32 *)IOP321_REG_ADDR(0x00000310)
-#define IOP321_IMR1 (volatile u32 *)IOP321_REG_ADDR(0x00000314)
-#define IOP321_OMR0 (volatile u32 *)IOP321_REG_ADDR(0x00000318)
-#define IOP321_OMR1 (volatile u32 *)IOP321_REG_ADDR(0x0000031C)
-#define IOP321_IDR (volatile u32 *)IOP321_REG_ADDR(0x00000320)
-#define IOP321_IISR (volatile u32 *)IOP321_REG_ADDR(0x00000324)
-#define IOP321_IIMR (volatile u32 *)IOP321_REG_ADDR(0x00000328)
-#define IOP321_ODR (volatile u32 *)IOP321_REG_ADDR(0x0000032C)
-#define IOP321_OISR (volatile u32 *)IOP321_REG_ADDR(0x00000330)
-#define IOP321_OIMR (volatile u32 *)IOP321_REG_ADDR(0x00000334)
-/* Reserved 0x00000338 through 0x0000034F */
-#define IOP321_MUCR (volatile u32 *)IOP321_REG_ADDR(0x00000350)
-#define IOP321_QBAR (volatile u32 *)IOP321_REG_ADDR(0x00000354)
-/* Reserved 0x00000358 through 0x0000035C */
-#define IOP321_IFHPR (volatile u32 *)IOP321_REG_ADDR(0x00000360)
-#define IOP321_IFTPR (volatile u32 *)IOP321_REG_ADDR(0x00000364)
-#define IOP321_IPHPR (volatile u32 *)IOP321_REG_ADDR(0x00000368)
-#define IOP321_IPTPR (volatile u32 *)IOP321_REG_ADDR(0x0000036C)
-#define IOP321_OFHPR (volatile u32 *)IOP321_REG_ADDR(0x00000370)
-#define IOP321_OFTPR (volatile u32 *)IOP321_REG_ADDR(0x00000374)
-#define IOP321_OPHPR (volatile u32 *)IOP321_REG_ADDR(0x00000378)
-#define IOP321_OPTPR (volatile u32 *)IOP321_REG_ADDR(0x0000037C)
-#define IOP321_IAR (volatile u32 *)IOP321_REG_ADDR(0x00000380)
-
-#define IOP321_IIxR_MASK 0x7f /* masks all */
-#define IOP321_IIxR_IRI 0x40 /* RC Index Register Interrupt */
-#define IOP321_IIxR_OFQF 0x20 /* RC Output Free Q Full (ERROR) */
-#define IOP321_IIxR_ipq 0x10 /* RC Inbound Post Q (post) */
-#define IOP321_IIxR_ERRDI 0x08 /* RO Error Doorbell Interrupt */
-#define IOP321_IIxR_IDI 0x04 /* RO Inbound Doorbell Interrupt */
-#define IOP321_IIxR_IM1 0x02 /* RC Inbound Message 1 Interrupt */
-#define IOP321_IIxR_IM0 0x01 /* RC Inbound Message 0 Interrupt */
-
-/* Reserved 0x00000384 through 0x000003FF */
-
-/* DMA Controller 0x00000400 through 0x000004FF */
-#define IOP321_DMA0_CCR (volatile u32 *)IOP321_REG_ADDR(0x00000400)
-#define IOP321_DMA0_CSR (volatile u32 *)IOP321_REG_ADDR(0x00000404)
-#define IOP321_DMA0_DAR (volatile u32 *)IOP321_REG_ADDR(0x0000040C)
-#define IOP321_DMA0_NDAR (volatile u32 *)IOP321_REG_ADDR(0x00000410)
-#define IOP321_DMA0_PADR (volatile u32 *)IOP321_REG_ADDR(0x00000414)
-#define IOP321_DMA0_PUADR (volatile u32 *)IOP321_REG_ADDR(0x00000418)
-#define IOP321_DMA0_LADR (volatile u32 *)IOP321_REG_ADDR(0X0000041C)
-#define IOP321_DMA0_BCR (volatile u32 *)IOP321_REG_ADDR(0x00000420)
-#define IOP321_DMA0_DCR (volatile u32 *)IOP321_REG_ADDR(0x00000424)
-/* Reserved 0x00000428 through 0x0000043C */
-#define IOP321_DMA1_CCR (volatile u32 *)IOP321_REG_ADDR(0x00000440)
-#define IOP321_DMA1_CSR (volatile u32 *)IOP321_REG_ADDR(0x00000444)
-#define IOP321_DMA1_DAR (volatile u32 *)IOP321_REG_ADDR(0x0000044C)
-#define IOP321_DMA1_NDAR (volatile u32 *)IOP321_REG_ADDR(0x00000450)
-#define IOP321_DMA1_PADR (volatile u32 *)IOP321_REG_ADDR(0x00000454)
-#define IOP321_DMA1_PUADR (volatile u32 *)IOP321_REG_ADDR(0x00000458)
-#define IOP321_DMA1_LADR (volatile u32 *)IOP321_REG_ADDR(0x0000045C)
-#define IOP321_DMA1_BCR (volatile u32 *)IOP321_REG_ADDR(0x00000460)
-#define IOP321_DMA1_DCR (volatile u32 *)IOP321_REG_ADDR(0x00000464)
-/* Reserved 0x00000468 through 0x000004FF */
-
-/* Memory controller 0x00000500 through 0x0005FF */
-
-/* Peripheral bus interface unit 0x00000680 through 0x0006FF */
-#define IOP321_PBCR (volatile u32 *)IOP321_REG_ADDR(0x00000680)
-#define IOP321_PBISR (volatile u32 *)IOP321_REG_ADDR(0x00000684)
-#define IOP321_PBBAR0 (volatile u32 *)IOP321_REG_ADDR(0x00000688)
-#define IOP321_PBLR0 (volatile u32 *)IOP321_REG_ADDR(0x0000068C)
-#define IOP321_PBBAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000690)
-#define IOP321_PBLR1 (volatile u32 *)IOP321_REG_ADDR(0x00000694)
-#define IOP321_PBBAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000698)
-#define IOP321_PBLR2 (volatile u32 *)IOP321_REG_ADDR(0x0000069C)
-#define IOP321_PBBAR3 (volatile u32 *)IOP321_REG_ADDR(0x000006A0)
-#define IOP321_PBLR3 (volatile u32 *)IOP321_REG_ADDR(0x000006A4)
-#define IOP321_PBBAR4 (volatile u32 *)IOP321_REG_ADDR(0x000006A8)
-#define IOP321_PBLR4 (volatile u32 *)IOP321_REG_ADDR(0x000006AC)
-#define IOP321_PBBAR5 (volatile u32 *)IOP321_REG_ADDR(0x000006B0)
-#define IOP321_PBLR5 (volatile u32 *)IOP321_REG_ADDR(0x000006B4)
-#define IOP321_PBDSCR (volatile u32 *)IOP321_REG_ADDR(0x000006B8)
-/* Reserved 0x000006BC */
-#define IOP321_PMBR0 (volatile u32 *)IOP321_REG_ADDR(0x000006C0)
-/* Reserved 0x000006C4 through 0x000006DC */
-#define IOP321_PMBR1 (volatile u32 *)IOP321_REG_ADDR(0x000006E0)
-#define IOP321_PMBR2 (volatile u32 *)IOP321_REG_ADDR(0x000006E4)
-
-#define IOP321_PBCR_EN 0x1
-
-#define IOP321_PBISR_BOOR_ERR 0x1
-
-/* Peripheral performance monitoring unit 0x00000700 through 0x00077F */
-#define IOP321_GTMR (volatile u32 *)IOP321_REG_ADDR(0x00000700)
-#define IOP321_ESR (volatile u32 *)IOP321_REG_ADDR(0x00000704)
-#define IOP321_EMISR (volatile u32 *)IOP321_REG_ADDR(0x00000708)
-/* reserved 0x00000070c */
-#define IOP321_GTSR (volatile u32 *)IOP321_REG_ADDR(0x00000710)
-/* PERC0 DOESN'T EXIST - index from 1! */
-#define IOP321_PERCR0 (volatile u32 *)IOP321_REG_ADDR(0x00000710)
-
-#define IOP321_GTMR_NGCE 0x04 /* (Not) Global Counter Enable */
-
-/* Internal arbitration unit 0x00000780 through 0x0007BF */
-#define IOP321_IACR (volatile u32 *)IOP321_REG_ADDR(0x00000780)
-#define IOP321_MTTR1 (volatile u32 *)IOP321_REG_ADDR(0x00000784)
-#define IOP321_MTTR2 (volatile u32 *)IOP321_REG_ADDR(0x00000788)
-
-/* General Purpose I/O Registers */
-#define IOP321_GPOE (volatile u32 *)IOP321_REG_ADDR(0x000007C4)
-#define IOP321_GPID (volatile u32 *)IOP321_REG_ADDR(0x000007C8)
-#define IOP321_GPOD (volatile u32 *)IOP321_REG_ADDR(0x000007CC)
-
-/* Interrupt Controller */
-#define IOP321_INTCTL (volatile u32 *)IOP321_REG_ADDR(0x000007D0)
-#define IOP321_INTSTR (volatile u32 *)IOP321_REG_ADDR(0x000007D4)
-#define IOP321_IINTSRC (volatile u32 *)IOP321_REG_ADDR(0x000007D8)
-#define IOP321_FINTSRC (volatile u32 *)IOP321_REG_ADDR(0x000007DC)
-
-/* Timers */
-
-#define IOP321_TU_TMR0 (volatile u32 *)IOP321_REG_ADDR(0x000007E0)
-#define IOP321_TU_TMR1 (volatile u32 *)IOP321_REG_ADDR(0x000007E4)
-
-#ifdef CONFIG_ARCH_IQ80321
-#define IOP321_TICK_RATE 200000000 /* 200 MHz clock */
-#elif defined(CONFIG_ARCH_IQ31244)
-#define IOP321_TICK_RATE 198000000 /* 33.000 MHz crystal */
-#endif
-
-#ifdef CONFIG_ARCH_EP80219
-#undef IOP321_TICK_RATE
-#define IOP321_TICK_RATE 200000000 /* 33.333333 Mhz crystal */
-#endif
-
-#define IOP321_TMR_TC 0x01
-#define IOP321_TMR_EN 0x02
-#define IOP321_TMR_RELOAD 0x04
-#define IOP321_TMR_PRIVILEGED 0x09
-
-#define IOP321_TMR_RATIO_1_1 0x00
-#define IOP321_TMR_RATIO_4_1 0x10
-#define IOP321_TMR_RATIO_8_1 0x20
-#define IOP321_TMR_RATIO_16_1 0x30
-
-#define IOP321_TU_TCR0 (volatile u32 *)IOP321_REG_ADDR(0x000007E8)
-#define IOP321_TU_TCR1 (volatile u32 *)IOP321_REG_ADDR(0x000007EC)
-#define IOP321_TU_TRR0 (volatile u32 *)IOP321_REG_ADDR(0x000007F0)
-#define IOP321_TU_TRR1 (volatile u32 *)IOP321_REG_ADDR(0x000007F4)
-#define IOP321_TU_TISR (volatile u32 *)IOP321_REG_ADDR(0x000007F8)
-#define IOP321_TU_WDTCR (volatile u32 *)IOP321_REG_ADDR(0x000007FC)
-
-/* Application accelerator unit 0x00000800 - 0x000008FF */
-#define IOP321_AAU_ACR (volatile u32 *)IOP321_REG_ADDR(0x00000800)
-#define IOP321_AAU_ASR (volatile u32 *)IOP321_REG_ADDR(0x00000804)
-#define IOP321_AAU_ADAR (volatile u32 *)IOP321_REG_ADDR(0x00000808)
-#define IOP321_AAU_ANDAR (volatile u32 *)IOP321_REG_ADDR(0x0000080C)
-#define IOP321_AAU_SAR1 (volatile u32 *)IOP321_REG_ADDR(0x00000810)
-#define IOP321_AAU_SAR2 (volatile u32 *)IOP321_REG_ADDR(0x00000814)
-#define IOP321_AAU_SAR3 (volatile u32 *)IOP321_REG_ADDR(0x00000818)
-#define IOP321_AAU_SAR4 (volatile u32 *)IOP321_REG_ADDR(0x0000081C)
-#define IOP321_AAU_SAR5 (volatile u32 *)IOP321_REG_ADDR(0x0000082C)
-#define IOP321_AAU_SAR6 (volatile u32 *)IOP321_REG_ADDR(0x00000830)
-#define IOP321_AAU_SAR7 (volatile u32 *)IOP321_REG_ADDR(0x00000834)
-#define IOP321_AAU_SAR8 (volatile u32 *)IOP321_REG_ADDR(0x00000838)
-#define IOP321_AAU_SAR9 (volatile u32 *)IOP321_REG_ADDR(0x00000840)
-#define IOP321_AAU_SAR10 (volatile u32 *)IOP321_REG_ADDR(0x00000844)
-#define IOP321_AAU_SAR11 (volatile u32 *)IOP321_REG_ADDR(0x00000848)
-#define IOP321_AAU_SAR12 (volatile u32 *)IOP321_REG_ADDR(0x0000084C)
-#define IOP321_AAU_SAR13 (volatile u32 *)IOP321_REG_ADDR(0x00000850)
-#define IOP321_AAU_SAR14 (volatile u32 *)IOP321_REG_ADDR(0x00000854)
-#define IOP321_AAU_SAR15 (volatile u32 *)IOP321_REG_ADDR(0x00000858)
-#define IOP321_AAU_SAR16 (volatile u32 *)IOP321_REG_ADDR(0x0000085C)
-#define IOP321_AAU_SAR17 (volatile u32 *)IOP321_REG_ADDR(0x00000864)
-#define IOP321_AAU_SAR18 (volatile u32 *)IOP321_REG_ADDR(0x00000868)
-#define IOP321_AAU_SAR19 (volatile u32 *)IOP321_REG_ADDR(0x0000086C)
-#define IOP321_AAU_SAR20 (volatile u32 *)IOP321_REG_ADDR(0x00000870)
-#define IOP321_AAU_SAR21 (volatile u32 *)IOP321_REG_ADDR(0x00000874)
-#define IOP321_AAU_SAR22 (volatile u32 *)IOP321_REG_ADDR(0x00000878)
-#define IOP321_AAU_SAR23 (volatile u32 *)IOP321_REG_ADDR(0x0000087C)
-#define IOP321_AAU_SAR24 (volatile u32 *)IOP321_REG_ADDR(0x00000880)
-#define IOP321_AAU_SAR25 (volatile u32 *)IOP321_REG_ADDR(0x00000888)
-#define IOP321_AAU_SAR26 (volatile u32 *)IOP321_REG_ADDR(0x0000088C)
-#define IOP321_AAU_SAR27 (volatile u32 *)IOP321_REG_ADDR(0x00000890)
-#define IOP321_AAU_SAR28 (volatile u32 *)IOP321_REG_ADDR(0x00000894)
-#define IOP321_AAU_SAR29 (volatile u32 *)IOP321_REG_ADDR(0x00000898)
-#define IOP321_AAU_SAR30 (volatile u32 *)IOP321_REG_ADDR(0x0000089C)
-#define IOP321_AAU_SAR31 (volatile u32 *)IOP321_REG_ADDR(0x000008A0)
-#define IOP321_AAU_SAR32 (volatile u32 *)IOP321_REG_ADDR(0x000008A4)
-#define IOP321_AAU_DAR (volatile u32 *)IOP321_REG_ADDR(0x00000820)
-#define IOP321_AAU_ABCR (volatile u32 *)IOP321_REG_ADDR(0x00000824)
-#define IOP321_AAU_ADCR (volatile u32 *)IOP321_REG_ADDR(0x00000828)
-#define IOP321_AAU_EDCR0 (volatile u32 *)IOP321_REG_ADDR(0x0000083c)
-#define IOP321_AAU_EDCR1 (volatile u32 *)IOP321_REG_ADDR(0x00000860)
-#define IOP321_AAU_EDCR2 (volatile u32 *)IOP321_REG_ADDR(0x00000884)
-
-
-/* SSP serial port unit 0x00001600 - 0x0000167F */
-/* I2C bus interface unit 0x00001680 - 0x000016FF */
-#define IOP321_ICR0 (volatile u32 *)IOP321_REG_ADDR(0x00001680)
-#define IOP321_ISR0 (volatile u32 *)IOP321_REG_ADDR(0x00001684)
-#define IOP321_ISAR0 (volatile u32 *)IOP321_REG_ADDR(0x00001688)
-#define IOP321_IDBR0 (volatile u32 *)IOP321_REG_ADDR(0x0000168C)
-/* Reserved 0x00001690 */
-#define IOP321_IBMR0 (volatile u32 *)IOP321_REG_ADDR(0x00001694)
-/* Reserved 0x00001698 */
-/* Reserved 0x0000169C */
-#define IOP321_ICR1 (volatile u32 *)IOP321_REG_ADDR(0x000016A0)
-#define IOP321_ISR1 (volatile u32 *)IOP321_REG_ADDR(0x000016A4)
-#define IOP321_ISAR1 (volatile u32 *)IOP321_REG_ADDR(0x000016A8)
-#define IOP321_IDBR1 (volatile u32 *)IOP321_REG_ADDR(0x000016AC)
-#define IOP321_IBMR1 (volatile u32 *)IOP321_REG_ADDR(0x000016B4)
-/* Reserved 0x000016B8 through 0x000016FC */
-
-/* for I2C bit defs see drivers/i2c/i2c-iop3xx.h */
-
-
-#ifndef __ASSEMBLY__
-extern void iop321_map_io(void);
-extern void iop321_init_irq(void);
-extern void iop321_time_init(void);
-#endif
-
-#endif // _IOP321_HW_H_
diff --git a/include/asm-arm/arch-iop3xx/iop331-irqs.h b/include/asm-arm/arch-iop3xx/iop331-irqs.h
deleted file mode 100644
index 7135ad7e335e..000000000000
--- a/include/asm-arm/arch-iop3xx/iop331-irqs.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/irqs.h
- *
- * Author: Dave Jiang (dave.jiang@intel.com)
- * Copyright: (C) 2003 Intel Corp.
- *
- * 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 _IOP331_IRQS_H_
-#define _IOP331_IRQS_H_
-
-/*
- * IOP80331 chipset interrupts
- */
-#define IOP331_IRQ_OFS 0
-#define IOP331_IRQ(x) (IOP331_IRQ_OFS + (x))
-
-/*
- * On IRQ or FIQ register
- */
-#define IRQ_IOP331_DMA0_EOT IOP331_IRQ(0)
-#define IRQ_IOP331_DMA0_EOC IOP331_IRQ(1)
-#define IRQ_IOP331_DMA1_EOT IOP331_IRQ(2)
-#define IRQ_IOP331_DMA1_EOC IOP331_IRQ(3)
-#define IRQ_IOP331_RSVD_4 IOP331_IRQ(4)
-#define IRQ_IOP331_RSVD_5 IOP331_IRQ(5)
-#define IRQ_IOP331_AA_EOT IOP331_IRQ(6)
-#define IRQ_IOP331_AA_EOC IOP331_IRQ(7)
-#define IRQ_IOP331_TIMER0 IOP331_IRQ(8)
-#define IRQ_IOP331_TIMER1 IOP331_IRQ(9)
-#define IRQ_IOP331_I2C_0 IOP331_IRQ(10)
-#define IRQ_IOP331_I2C_1 IOP331_IRQ(11)
-#define IRQ_IOP331_MSG IOP331_IRQ(12)
-#define IRQ_IOP331_MSGIBQ IOP331_IRQ(13)
-#define IRQ_IOP331_ATU_BIST IOP331_IRQ(14)
-#define IRQ_IOP331_PERFMON IOP331_IRQ(15)
-#define IRQ_IOP331_CORE_PMU IOP331_IRQ(16)
-#define IRQ_IOP331_RSVD_17 IOP331_IRQ(17)
-#define IRQ_IOP331_RSVD_18 IOP331_IRQ(18)
-#define IRQ_IOP331_RSVD_19 IOP331_IRQ(19)
-#define IRQ_IOP331_RSVD_20 IOP331_IRQ(20)
-#define IRQ_IOP331_RSVD_21 IOP331_IRQ(21)
-#define IRQ_IOP331_RSVD_22 IOP331_IRQ(22)
-#define IRQ_IOP331_RSVD_23 IOP331_IRQ(23)
-#define IRQ_IOP331_XINT0 IOP331_IRQ(24)
-#define IRQ_IOP331_XINT1 IOP331_IRQ(25)
-#define IRQ_IOP331_XINT2 IOP331_IRQ(26)
-#define IRQ_IOP331_XINT3 IOP331_IRQ(27)
-#define IRQ_IOP331_RSVD_28 IOP331_IRQ(28)
-#define IRQ_IOP331_RSVD_29 IOP331_IRQ(29)
-#define IRQ_IOP331_RSVD_30 IOP331_IRQ(30)
-#define IRQ_IOP331_RSVD_31 IOP331_IRQ(31)
-#define IRQ_IOP331_XINT8 IOP331_IRQ(32) // 0
-#define IRQ_IOP331_XINT9 IOP331_IRQ(33) // 1
-#define IRQ_IOP331_XINT10 IOP331_IRQ(34) // 2
-#define IRQ_IOP331_XINT11 IOP331_IRQ(35) // 3
-#define IRQ_IOP331_XINT12 IOP331_IRQ(36) // 4
-#define IRQ_IOP331_XINT13 IOP331_IRQ(37) // 5
-#define IRQ_IOP331_XINT14 IOP331_IRQ(38) // 6
-#define IRQ_IOP331_XINT15 IOP331_IRQ(39) // 7
-#define IRQ_IOP331_RSVD_40 IOP331_IRQ(40) // 8
-#define IRQ_IOP331_RSVD_41 IOP331_IRQ(41) // 9
-#define IRQ_IOP331_RSVD_42 IOP331_IRQ(42) // 10
-#define IRQ_IOP331_RSVD_43 IOP331_IRQ(43) // 11
-#define IRQ_IOP331_RSVD_44 IOP331_IRQ(44) // 12
-#define IRQ_IOP331_RSVD_45 IOP331_IRQ(45) // 13
-#define IRQ_IOP331_RSVD_46 IOP331_IRQ(46) // 14
-#define IRQ_IOP331_RSVD_47 IOP331_IRQ(47) // 15
-#define IRQ_IOP331_RSVD_48 IOP331_IRQ(48) // 16
-#define IRQ_IOP331_RSVD_49 IOP331_IRQ(49) // 17
-#define IRQ_IOP331_RSVD_50 IOP331_IRQ(50) // 18
-#define IRQ_IOP331_UART0 IOP331_IRQ(51) // 19
-#define IRQ_IOP331_UART1 IOP331_IRQ(52) // 20
-#define IRQ_IOP331_PBIE IOP331_IRQ(53) // 21
-#define IRQ_IOP331_ATU_CRW IOP331_IRQ(54) // 22
-#define IRQ_IOP331_ATU_ERR IOP331_IRQ(55) // 23
-#define IRQ_IOP331_MCU_ERR IOP331_IRQ(56) // 24
-#define IRQ_IOP331_DMA0_ERR IOP331_IRQ(57) // 25
-#define IRQ_IOP331_DMA1_ERR IOP331_IRQ(58) // 26
-#define IRQ_IOP331_RSVD_59 IOP331_IRQ(59) // 27
-#define IRQ_IOP331_AA_ERR IOP331_IRQ(60) // 28
-#define IRQ_IOP331_RSVD_61 IOP331_IRQ(61) // 29
-#define IRQ_IOP331_MSG_ERR IOP331_IRQ(62) // 30
-#define IRQ_IOP331_HPI IOP331_IRQ(63) // 31
-
-#define NR_IOP331_IRQS (IOP331_IRQ(63) + 1)
-
-#define NR_IRQS NR_IOP331_IRQS
-
-
-/*
- * Interrupts available on the IQ80331 board
- */
-
-/*
- * On board devices
- */
-#define IRQ_IQ80331_I82544 IRQ_IOP331_XINT0
-#define IRQ_IQ80331_UART0 IRQ_IOP331_UART0
-#define IRQ_IQ80331_UART1 IRQ_IOP331_UART1
-
-/*
- * PCI interrupts
- */
-#define IRQ_IQ80331_INTA IRQ_IOP331_XINT0
-#define IRQ_IQ80331_INTB IRQ_IOP331_XINT1
-#define IRQ_IQ80331_INTC IRQ_IOP331_XINT2
-#define IRQ_IQ80331_INTD IRQ_IOP331_XINT3
-
-/*
- * Interrupts available on the IQ80332 board
- */
-
-/*
- * On board devices
- */
-#define IRQ_IQ80332_I82544 IRQ_IOP331_XINT0
-#define IRQ_IQ80332_UART0 IRQ_IOP331_UART0
-#define IRQ_IQ80332_UART1 IRQ_IOP331_UART1
-
-/*
- * PCI interrupts
- */
-#define IRQ_IQ80332_INTA IRQ_IOP331_XINT0
-#define IRQ_IQ80332_INTB IRQ_IOP331_XINT1
-#define IRQ_IQ80332_INTC IRQ_IOP331_XINT2
-#define IRQ_IQ80332_INTD IRQ_IOP331_XINT3
-
-#endif // _IOP331_IRQ_H_
diff --git a/include/asm-arm/arch-iop3xx/iop331.h b/include/asm-arm/arch-iop3xx/iop331.h
deleted file mode 100644
index fbf0cc11bdd9..000000000000
--- a/include/asm-arm/arch-iop3xx/iop331.h
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * linux/include/asm/arch-iop3xx/iop331.h
- *
- * Intel IOP331 Chip definitions
- *
- * Author: Dave Jiang (dave.jiang@intel.com)
- * Copyright (C) 2003, 2004 Intel Corp.
- *
- * 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 _IOP331_HW_H_
-#define _IOP331_HW_H_
-
-
-/*
- * This is needed for mixed drivers that need to work on all
- * IOP3xx variants but behave slightly differently on each.
- */
-#ifndef __ASSEMBLY__
-#ifdef CONFIG_ARCH_IOP331
-/*#define iop_is_331() ((processor_id & 0xffffffb0) == 0x69054090) */
-#define iop_is_331() ((processor_id & 0xffffff30) == 0x69054010)
-#else
-#define iop_is_331() 0
-#endif
-#endif
-
-/*
- * IOP331 I/O and Mem space regions for PCI autoconfiguration
- */
-#define IOP331_PCI_IO_WINDOW_SIZE 0x00010000
-#define IOP331_PCI_LOWER_IO_PA 0x90000000
-#define IOP331_PCI_LOWER_IO_VA 0xfe000000
-#define IOP331_PCI_LOWER_IO_BA (*IOP331_OIOWTVR)
-#define IOP331_PCI_UPPER_IO_PA (IOP331_PCI_LOWER_IO_PA + IOP331_PCI_IO_WINDOW_SIZE - 1)
-#define IOP331_PCI_UPPER_IO_VA (IOP331_PCI_LOWER_IO_VA + IOP331_PCI_IO_WINDOW_SIZE - 1)
-#define IOP331_PCI_UPPER_IO_BA (IOP331_PCI_LOWER_IO_BA + IOP331_PCI_IO_WINDOW_SIZE - 1)
-#define IOP331_PCI_IO_OFFSET (IOP331_PCI_LOWER_IO_VA - IOP331_PCI_LOWER_IO_BA)
-
-/* this can be 128M if OMWTVR1 is set */
-#define IOP331_PCI_MEM_WINDOW_SIZE 0x04000000 /* 64M outbound window */
-/* #define IOP331_PCI_MEM_WINDOW_SIZE (~*IOP331_IALR1 + 1) */
-#define IOP331_PCI_LOWER_MEM_PA 0x80000000
-#define IOP331_PCI_LOWER_MEM_BA (*IOP331_OMWTVR0)
-#define IOP331_PCI_UPPER_MEM_PA (IOP331_PCI_LOWER_MEM_PA + IOP331_PCI_MEM_WINDOW_SIZE - 1)
-#define IOP331_PCI_UPPER_MEM_BA (IOP331_PCI_LOWER_MEM_BA + IOP331_PCI_MEM_WINDOW_SIZE - 1)
-#define IOP331_PCI_MEM_OFFSET (IOP331_PCI_LOWER_MEM_PA - IOP331_PCI_LOWER_MEM_BA)
-
-/*
- * IOP331 chipset registers
- */
-#define IOP331_VIRT_MEM_BASE 0xfeffe000 /* chip virtual mem address*/
-#define IOP331_PHYS_MEM_BASE 0xffffe000 /* chip physical memory address */
-#define IOP331_REG_ADDR(reg) (IOP331_VIRT_MEM_BASE | (reg))
-
-/* Reserved 0x00000000 through 0x000000FF */
-
-/* Address Translation Unit 0x00000100 through 0x000001FF */
-#define IOP331_ATUVID (volatile u16 *)IOP331_REG_ADDR(0x00000100)
-#define IOP331_ATUDID (volatile u16 *)IOP331_REG_ADDR(0x00000102)
-#define IOP331_ATUCMD (volatile u16 *)IOP331_REG_ADDR(0x00000104)
-#define IOP331_ATUSR (volatile u16 *)IOP331_REG_ADDR(0x00000106)
-#define IOP331_ATURID (volatile u8 *)IOP331_REG_ADDR(0x00000108)
-#define IOP331_ATUCCR (volatile u32 *)IOP331_REG_ADDR(0x00000109)
-#define IOP331_ATUCLSR (volatile u8 *)IOP331_REG_ADDR(0x0000010C)
-#define IOP331_ATULT (volatile u8 *)IOP331_REG_ADDR(0x0000010D)
-#define IOP331_ATUHTR (volatile u8 *)IOP331_REG_ADDR(0x0000010E)
-#define IOP331_ATUBIST (volatile u8 *)IOP331_REG_ADDR(0x0000010F)
-#define IOP331_IABAR0 (volatile u32 *)IOP331_REG_ADDR(0x00000110)
-#define IOP331_IAUBAR0 (volatile u32 *)IOP331_REG_ADDR(0x00000114)
-#define IOP331_IABAR1 (volatile u32 *)IOP331_REG_ADDR(0x00000118)
-#define IOP331_IAUBAR1 (volatile u32 *)IOP331_REG_ADDR(0x0000011C)
-#define IOP331_IABAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000120)
-#define IOP331_IAUBAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000124)
-#define IOP331_ASVIR (volatile u16 *)IOP331_REG_ADDR(0x0000012C)
-#define IOP331_ASIR (volatile u16 *)IOP331_REG_ADDR(0x0000012E)
-#define IOP331_ERBAR (volatile u32 *)IOP331_REG_ADDR(0x00000130)
-#define IOP331_ATU_CAPPTR (volatile u32 *)IOP331_REG_ADDR(0x00000134)
-/* Reserved 0x00000138 through 0x0000013B */
-#define IOP331_ATUILR (volatile u8 *)IOP331_REG_ADDR(0x0000013C)
-#define IOP331_ATUIPR (volatile u8 *)IOP331_REG_ADDR(0x0000013D)
-#define IOP331_ATUMGNT (volatile u8 *)IOP331_REG_ADDR(0x0000013E)
-#define IOP331_ATUMLAT (volatile u8 *)IOP331_REG_ADDR(0x0000013F)
-#define IOP331_IALR0 (volatile u32 *)IOP331_REG_ADDR(0x00000140)
-#define IOP331_IATVR0 (volatile u32 *)IOP331_REG_ADDR(0x00000144)
-#define IOP331_ERLR (volatile u32 *)IOP331_REG_ADDR(0x00000148)
-#define IOP331_ERTVR (volatile u32 *)IOP331_REG_ADDR(0x0000014C)
-#define IOP331_IALR1 (volatile u32 *)IOP331_REG_ADDR(0x00000150)
-#define IOP331_IALR2 (volatile u32 *)IOP331_REG_ADDR(0x00000154)
-#define IOP331_IATVR2 (volatile u32 *)IOP331_REG_ADDR(0x00000158)
-#define IOP331_OIOWTVR (volatile u32 *)IOP331_REG_ADDR(0x0000015C)
-#define IOP331_OMWTVR0 (volatile u32 *)IOP331_REG_ADDR(0x00000160)
-#define IOP331_OUMWTVR0 (volatile u32 *)IOP331_REG_ADDR(0x00000164)
-#define IOP331_OMWTVR1 (volatile u32 *)IOP331_REG_ADDR(0x00000168)
-#define IOP331_OUMWTVR1 (volatile u32 *)IOP331_REG_ADDR(0x0000016C)
-/* Reserved 0x00000170 through 0x00000177*/
-#define IOP331_OUDWTVR (volatile u32 *)IOP331_REG_ADDR(0x00000178)
-/* Reserved 0x0000017C through 0x0000017F*/
-#define IOP331_ATUCR (volatile u32 *)IOP331_REG_ADDR(0x00000180)
-#define IOP331_PCSR (volatile u32 *)IOP331_REG_ADDR(0x00000184)
-#define IOP331_ATUISR (volatile u32 *)IOP331_REG_ADDR(0x00000188)
-#define IOP331_ATUIMR (volatile u32 *)IOP331_REG_ADDR(0x0000018C)
-#define IOP331_IABAR3 (volatile u32 *)IOP331_REG_ADDR(0x00000190)
-#define IOP331_IAUBAR3 (volatile u32 *)IOP331_REG_ADDR(0x00000194)
-#define IOP331_IALR3 (volatile u32 *)IOP331_REG_ADDR(0x00000198)
-#define IOP331_IATVR3 (volatile u32 *)IOP331_REG_ADDR(0x0000019C)
-/* Reserved 0x000001A0 through 0x000001A3*/
-#define IOP331_OCCAR (volatile u32 *)IOP331_REG_ADDR(0x000001A4)
-/* Reserved 0x000001A8 through 0x000001AB*/
-#define IOP331_OCCDR (volatile u32 *)IOP331_REG_ADDR(0x000001AC)
-/* Reserved 0x000001B0 through 0x000001BB*/
-#define IOP331_VPDCAPID (volatile u8 *)IOP331_REG_ADDR(0x000001B8)
-#define IOP331_VPDNXTP (volatile u8 *)IOP331_REG_ADDR(0x000001B9)
-#define IOP331_VPDAR (volatile u16 *)IOP331_REG_ADDR(0x000001BA)
-#define IOP331_VPDDR (volatile u32 *)IOP331_REG_ADDR(0x000001BC)
-#define IOP331_PMCAPID (volatile u8 *)IOP331_REG_ADDR(0x000001C0)
-#define IOP331_PMNEXT (volatile u8 *)IOP331_REG_ADDR(0x000001C1)
-#define IOP331_APMCR (volatile u16 *)IOP331_REG_ADDR(0x000001C2)
-#define IOP331_APMCSR (volatile u16 *)IOP331_REG_ADDR(0x000001C4)
-/* Reserved 0x000001C6 through 0x000001CF */
-#define IOP331_MSICAPID (volatile u8 *)IOP331_REG_ADDR(0x000001D0)
-#define IOP331_MSINXTP (volatile u8 *)IOP331_REG_ADDR(0x000001D1)
-#define IOP331_MSIMCR (volatile u16 *)IOP331_REG_ADDR(0x000001D2)
-#define IOP331_MSIMAR (volatile u32 *)IOP331_REG_ADDR(0x000001D4)
-#define IOP331_MSIMUAR (volatile u32 *)IOP331_REG_ADDR(0x000001D8)
-#define IOP331_MSIMDR (volatile u32 *)IOP331_REG_ADDR(0x000001DC)
-#define IOP331_PCIXCAPID (volatile u8 *)IOP331_REG_ADDR(0x000001E0)
-#define IOP331_PCIXNEXT (volatile u8 *)IOP331_REG_ADDR(0x000001E1)
-#define IOP331_PCIXCMD (volatile u16 *)IOP331_REG_ADDR(0x000001E2)
-#define IOP331_PCIXSR (volatile u32 *)IOP331_REG_ADDR(0x000001E4)
-#define IOP331_PCIIRSR (volatile u32 *)IOP331_REG_ADDR(0x000001EC)
-
-/* Messaging Unit 0x00000300 through 0x000003FF */
-
-/* Reserved 0x00000300 through 0x0000030c */
-#define IOP331_IMR0 (volatile u32 *)IOP331_REG_ADDR(0x00000310)
-#define IOP331_IMR1 (volatile u32 *)IOP331_REG_ADDR(0x00000314)
-#define IOP331_OMR0 (volatile u32 *)IOP331_REG_ADDR(0x00000318)
-#define IOP331_OMR1 (volatile u32 *)IOP331_REG_ADDR(0x0000031C)
-#define IOP331_IDR (volatile u32 *)IOP331_REG_ADDR(0x00000320)
-#define IOP331_IISR (volatile u32 *)IOP331_REG_ADDR(0x00000324)
-#define IOP331_IIMR (volatile u32 *)IOP331_REG_ADDR(0x00000328)
-#define IOP331_ODR (volatile u32 *)IOP331_REG_ADDR(0x0000032C)
-#define IOP331_OISR (volatile u32 *)IOP331_REG_ADDR(0x00000330)
-#define IOP331_OIMR (volatile u32 *)IOP331_REG_ADDR(0x00000334)
-/* Reserved 0x00000338 through 0x0000034F */
-#define IOP331_MUCR (volatile u32 *)IOP331_REG_ADDR(0x00000350)
-#define IOP331_QBAR (volatile u32 *)IOP331_REG_ADDR(0x00000354)
-/* Reserved 0x00000358 through 0x0000035C */
-#define IOP331_IFHPR (volatile u32 *)IOP331_REG_ADDR(0x00000360)
-#define IOP331_IFTPR (volatile u32 *)IOP331_REG_ADDR(0x00000364)
-#define IOP331_IPHPR (volatile u32 *)IOP331_REG_ADDR(0x00000368)
-#define IOP331_IPTPR (volatile u32 *)IOP331_REG_ADDR(0x0000036C)
-#define IOP331_OFHPR (volatile u32 *)IOP331_REG_ADDR(0x00000370)
-#define IOP331_OFTPR (volatile u32 *)IOP331_REG_ADDR(0x00000374)
-#define IOP331_OPHPR (volatile u32 *)IOP331_REG_ADDR(0x00000378)
-#define IOP331_OPTPR (volatile u32 *)IOP331_REG_ADDR(0x0000037C)
-#define IOP331_IAR (volatile u32 *)IOP331_REG_ADDR(0x00000380)
-/* Reserved 0x00000384 through 0x000003FF */
-
-/* DMA Controller 0x00000400 through 0x000004FF */
-#define IOP331_DMA0_CCR (volatile u32 *)IOP331_REG_ADDR(0x00000400)
-#define IOP331_DMA0_CSR (volatile u32 *)IOP331_REG_ADDR(0x00000404)
-#define IOP331_DMA0_DAR (volatile u32 *)IOP331_REG_ADDR(0x0000040C)
-#define IOP331_DMA0_NDAR (volatile u32 *)IOP331_REG_ADDR(0x00000410)
-#define IOP331_DMA0_PADR (volatile u32 *)IOP331_REG_ADDR(0x00000414)
-#define IOP331_DMA0_PUADR (volatile u32 *)IOP331_REG_ADDR(0x00000418)
-#define IOP331_DMA0_LADR (volatile u32 *)IOP331_REG_ADDR(0X0000041C)
-#define IOP331_DMA0_BCR (volatile u32 *)IOP331_REG_ADDR(0x00000420)
-#define IOP331_DMA0_DCR (volatile u32 *)IOP331_REG_ADDR(0x00000424)
-/* Reserved 0x00000428 through 0x0000043C */
-#define IOP331_DMA1_CCR (volatile u32 *)IOP331_REG_ADDR(0x00000440)
-#define IOP331_DMA1_CSR (volatile u32 *)IOP331_REG_ADDR(0x00000444)
-#define IOP331_DMA1_DAR (volatile u32 *)IOP331_REG_ADDR(0x0000044C)
-#define IOP331_DMA1_NDAR (volatile u32 *)IOP331_REG_ADDR(0x00000450)
-#define IOP331_DMA1_PADR (volatile u32 *)IOP331_REG_ADDR(0x00000454)
-#define IOP331_DMA1_PUADR (volatile u32 *)IOP331_REG_ADDR(0x00000458)
-#define IOP331_DMA1_LADR (volatile u32 *)IOP331_REG_ADDR(0x0000045C)
-#define IOP331_DMA1_BCR (volatile u32 *)IOP331_REG_ADDR(0x00000460)
-#define IOP331_DMA1_DCR (volatile u32 *)IOP331_REG_ADDR(0x00000464)
-/* Reserved 0x00000468 through 0x000004FF */
-
-/* Memory controller 0x00000500 through 0x0005FF */
-
-/* Peripheral bus interface unit 0x00000680 through 0x0006FF */
-#define IOP331_PBCR (volatile u32 *)IOP331_REG_ADDR(0x00000680)
-#define IOP331_PBISR (volatile u32 *)IOP331_REG_ADDR(0x00000684)
-#define IOP331_PBBAR0 (volatile u32 *)IOP331_REG_ADDR(0x00000688)
-#define IOP331_PBLR0 (volatile u32 *)IOP331_REG_ADDR(0x0000068C)
-#define IOP331_PBBAR1 (volatile u32 *)IOP331_REG_ADDR(0x00000690)
-#define IOP331_PBLR1 (volatile u32 *)IOP331_REG_ADDR(0x00000694)
-#define IOP331_PBBAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000698)
-#define IOP331_PBLR2 (volatile u32 *)IOP331_REG_ADDR(0x0000069C)
-#define IOP331_PBBAR3 (volatile u32 *)IOP331_REG_ADDR(0x000006A0)
-#define IOP331_PBLR3 (volatile u32 *)IOP331_REG_ADDR(0x000006A4)
-#define IOP331_PBBAR4 (volatile u32 *)IOP331_REG_ADDR(0x000006A8)
-#define IOP331_PBLR4 (volatile u32 *)IOP331_REG_ADDR(0x000006AC)
-#define IOP331_PBBAR5 (volatile u32 *)IOP331_REG_ADDR(0x000006B0)
-#define IOP331_PBLR5 (volatile u32 *)IOP331_REG_ADDR(0x000006B4)
-#define IOP331_PBDSCR (volatile u32 *)IOP331_REG_ADDR(0x000006B8)
-/* Reserved 0x000006BC */
-#define IOP331_PMBR0 (volatile u32 *)IOP331_REG_ADDR(0x000006C0)
-/* Reserved 0x000006C4 through 0x000006DC */
-#define IOP331_PMBR1 (volatile u32 *)IOP331_REG_ADDR(0x000006E0)
-#define IOP331_PMBR2 (volatile u32 *)IOP331_REG_ADDR(0x000006E4)
-
-#define IOP331_PBCR_EN 0x1
-
-#define IOP331_PBISR_BOOR_ERR 0x1
-
-
-
-/* Peripheral performance monitoring unit 0x00000700 through 0x00077F */
-/* Internal arbitration unit 0x00000780 through 0x0007BF */
-
-/* Interrupt Controller */
-#define IOP331_INTCTL0 (volatile u32 *)IOP331_REG_ADDR(0x00000790)
-#define IOP331_INTCTL1 (volatile u32 *)IOP331_REG_ADDR(0x00000794)
-#define IOP331_INTSTR0 (volatile u32 *)IOP331_REG_ADDR(0x00000798)
-#define IOP331_INTSTR1 (volatile u32 *)IOP331_REG_ADDR(0x0000079C)
-#define IOP331_IINTSRC0 (volatile u32 *)IOP331_REG_ADDR(0x000007A0)
-#define IOP331_IINTSRC1 (volatile u32 *)IOP331_REG_ADDR(0x000007A4)
-#define IOP331_FINTSRC0 (volatile u32 *)IOP331_REG_ADDR(0x000007A8)
-#define IOP331_FINTSRC1 (volatile u32 *)IOP331_REG_ADDR(0x000007AC)
-#define IOP331_IPR0 (volatile u32 *)IOP331_REG_ADDR(0x000007B0)
-#define IOP331_IPR1 (volatile u32 *)IOP331_REG_ADDR(0x000007B4)
-#define IOP331_IPR2 (volatile u32 *)IOP331_REG_ADDR(0x000007B8)
-#define IOP331_IPR3 (volatile u32 *)IOP331_REG_ADDR(0x000007BC)
-#define IOP331_INTBASE (volatile u32 *)IOP331_REG_ADDR(0x000007C0)
-#define IOP331_INTSIZE (volatile u32 *)IOP331_REG_ADDR(0x000007C4)
-#define IOP331_IINTVEC (volatile u32 *)IOP331_REG_ADDR(0x000007C8)
-#define IOP331_FINTVEC (volatile u32 *)IOP331_REG_ADDR(0x000007CC)
-
-
-/* Timers */
-
-#define IOP331_TU_TMR0 (volatile u32 *)IOP331_REG_ADDR(0x000007D0)
-#define IOP331_TU_TMR1 (volatile u32 *)IOP331_REG_ADDR(0x000007D4)
-
-#define IOP331_TMR_TC 0x01
-#define IOP331_TMR_EN 0x02
-#define IOP331_TMR_RELOAD 0x04
-#define IOP331_TMR_PRIVILEGED 0x09
-
-#define IOP331_TMR_RATIO_1_1 0x00
-#define IOP331_TMR_RATIO_4_1 0x10
-#define IOP331_TMR_RATIO_8_1 0x20
-#define IOP331_TMR_RATIO_16_1 0x30
-
-#define IOP331_TU_TCR0 (volatile u32 *)IOP331_REG_ADDR(0x000007D8)
-#define IOP331_TU_TCR1 (volatile u32 *)IOP331_REG_ADDR(0x000007DC)
-#define IOP331_TU_TRR0 (volatile u32 *)IOP331_REG_ADDR(0x000007E0)
-#define IOP331_TU_TRR1 (volatile u32 *)IOP331_REG_ADDR(0x000007E4)
-#define IOP331_TU_TISR (volatile u32 *)IOP331_REG_ADDR(0x000007E8)
-#define IOP331_TU_WDTCR (volatile u32 *)IOP331_REG_ADDR(0x000007EC)
-
-#if defined(CONFIG_ARCH_IOP331)
-#define IOP331_TICK_RATE 266000000 /* 266 MHz IB clock */
-#endif
-
-#if defined(CONFIG_IOP331_STEPD) || defined(CONFIG_ARCH_IQ80333)
-#undef IOP331_TICK_RATE
-#define IOP331_TICK_RATE 333000000 /* 333 Mhz IB clock */
-#endif
-
-/* Application accelerator unit 0x00000800 - 0x000008FF */
-#define IOP331_AAU_ACR (volatile u32 *)IOP331_REG_ADDR(0x00000800)
-#define IOP331_AAU_ASR (volatile u32 *)IOP331_REG_ADDR(0x00000804)
-#define IOP331_AAU_ADAR (volatile u32 *)IOP331_REG_ADDR(0x00000808)
-#define IOP331_AAU_ANDAR (volatile u32 *)IOP331_REG_ADDR(0x0000080C)
-#define IOP331_AAU_SAR1 (volatile u32 *)IOP331_REG_ADDR(0x00000810)
-#define IOP331_AAU_SAR2 (volatile u32 *)IOP331_REG_ADDR(0x00000814)
-#define IOP331_AAU_SAR3 (volatile u32 *)IOP331_REG_ADDR(0x00000818)
-#define IOP331_AAU_SAR4 (volatile u32 *)IOP331_REG_ADDR(0x0000081C)
-#define IOP331_AAU_SAR5 (volatile u32 *)IOP331_REG_ADDR(0x0000082C)
-#define IOP331_AAU_SAR6 (volatile u32 *)IOP331_REG_ADDR(0x00000830)
-#define IOP331_AAU_SAR7 (volatile u32 *)IOP331_REG_ADDR(0x00000834)
-#define IOP331_AAU_SAR8 (volatile u32 *)IOP331_REG_ADDR(0x00000838)
-#define IOP331_AAU_SAR9 (volatile u32 *)IOP331_REG_ADDR(0x00000840)
-#define IOP331_AAU_SAR10 (volatile u32 *)IOP331_REG_ADDR(0x00000844)
-#define IOP331_AAU_SAR11 (volatile u32 *)IOP331_REG_ADDR(0x00000848)
-#define IOP331_AAU_SAR12 (volatile u32 *)IOP331_REG_ADDR(0x0000084C)
-#define IOP331_AAU_SAR13 (volatile u32 *)IOP331_REG_ADDR(0x00000850)
-#define IOP331_AAU_SAR14 (volatile u32 *)IOP331_REG_ADDR(0x00000854)
-#define IOP331_AAU_SAR15 (volatile u32 *)IOP331_REG_ADDR(0x00000858)
-#define IOP331_AAU_SAR16 (volatile u32 *)IOP331_REG_ADDR(0x0000085C)
-#define IOP331_AAU_SAR17 (volatile u32 *)IOP331_REG_ADDR(0x00000864)
-#define IOP331_AAU_SAR18 (volatile u32 *)IOP331_REG_ADDR(0x00000868)
-#define IOP331_AAU_SAR19 (volatile u32 *)IOP331_REG_ADDR(0x0000086C)
-#define IOP331_AAU_SAR20 (volatile u32 *)IOP331_REG_ADDR(0x00000870)
-#define IOP331_AAU_SAR21 (volatile u32 *)IOP331_REG_ADDR(0x00000874)
-#define IOP331_AAU_SAR22 (volatile u32 *)IOP331_REG_ADDR(0x00000878)
-#define IOP331_AAU_SAR23 (volatile u32 *)IOP331_REG_ADDR(0x0000087C)
-#define IOP331_AAU_SAR24 (volatile u32 *)IOP331_REG_ADDR(0x00000880)
-#define IOP331_AAU_SAR25 (volatile u32 *)IOP331_REG_ADDR(0x00000888)
-#define IOP331_AAU_SAR26 (volatile u32 *)IOP331_REG_ADDR(0x0000088C)
-#define IOP331_AAU_SAR27 (volatile u32 *)IOP331_REG_ADDR(0x00000890)
-#define IOP331_AAU_SAR28 (volatile u32 *)IOP331_REG_ADDR(0x00000894)
-#define IOP331_AAU_SAR29 (volatile u32 *)IOP331_REG_ADDR(0x00000898)
-#define IOP331_AAU_SAR30 (volatile u32 *)IOP331_REG_ADDR(0x0000089C)
-#define IOP331_AAU_SAR31 (volatile u32 *)IOP331_REG_ADDR(0x000008A0)
-#define IOP331_AAU_SAR32 (volatile u32 *)IOP331_REG_ADDR(0x000008A4)
-#define IOP331_AAU_DAR (volatile u32 *)IOP331_REG_ADDR(0x00000820)
-#define IOP331_AAU_ABCR (volatile u32 *)IOP331_REG_ADDR(0x00000824)
-#define IOP331_AAU_ADCR (volatile u32 *)IOP331_REG_ADDR(0x00000828)
-#define IOP331_AAU_EDCR0 (volatile u32 *)IOP331_REG_ADDR(0x0000083c)
-#define IOP331_AAU_EDCR1 (volatile u32 *)IOP331_REG_ADDR(0x00000860)
-#define IOP331_AAU_EDCR2 (volatile u32 *)IOP331_REG_ADDR(0x00000884)
-
-
-#define IOP331_SPDSCR (volatile u32 *)IOP331_REG_ADDR(0x000015C0)
-#define IOP331_PPDSCR (volatile u32 *)IOP331_REG_ADDR(0x000015C8)
-/* SSP serial port unit 0x00001600 - 0x0000167F */
-
-/* I2C bus interface unit 0x00001680 - 0x000016FF */
-/* for I2C bit defs see drivers/i2c/i2c-iop3xx.h */
-
-#define IOP331_ICR0 (volatile u32 *)IOP331_REG_ADDR(0x00001680)
-#define IOP331_ISR0 (volatile u32 *)IOP331_REG_ADDR(0x00001684)
-#define IOP331_ISAR0 (volatile u32 *)IOP331_REG_ADDR(0x00001688)
-#define IOP331_IDBR0 (volatile u32 *)IOP331_REG_ADDR(0x0000168C)
-/* Reserved 0x00001690 */
-#define IOP331_IBMR0 (volatile u32 *)IOP331_REG_ADDR(0x00001694)
-/* Reserved 0x00001698 */
-/* Reserved 0x0000169C */
-#define IOP331_ICR1 (volatile u32 *)IOP331_REG_ADDR(0x000016A0)
-#define IOP331_ISR1 (volatile u32 *)IOP331_REG_ADDR(0x000016A4)
-#define IOP331_ISAR1 (volatile u32 *)IOP331_REG_ADDR(0x000016A8)
-#define IOP331_IDBR1 (volatile u32 *)IOP331_REG_ADDR(0x000016AC)
-#define IOP331_IBMR1 (volatile u32 *)IOP331_REG_ADDR(0x000016B4)
-/* Reserved 0x000016B8 through 0x000016FF */
-
-/* 0x00001700 through 0x0000172C UART 0 */
-
-/* Reserved 0x00001730 through 0x0000173F */
-
-/* 0x00001740 through 0x0000176C UART 1 */
-
-#define IOP331_UART0_PHYS (IOP331_PHYS_MEM_BASE | 0x00001700) /* UART #1 physical */
-#define IOP331_UART1_PHYS (IOP331_PHYS_MEM_BASE | 0x00001740) /* UART #2 physical */
-#define IOP331_UART0_VIRT (IOP331_VIRT_MEM_BASE | 0x00001700) /* UART #1 virtual addr */
-#define IOP331_UART1_VIRT (IOP331_VIRT_MEM_BASE | 0x00001740) /* UART #2 virtual addr */
-
-/* Reserved 0x00001770 through 0x0000177F */
-
-/* General Purpose I/O Registers */
-#define IOP331_GPOE (volatile u32 *)IOP331_REG_ADDR(0x00001780)
-#define IOP331_GPID (volatile u32 *)IOP331_REG_ADDR(0x00001784)
-#define IOP331_GPOD (volatile u32 *)IOP331_REG_ADDR(0x00001788)
-
-/* Reserved 0x0000178c through 0x000019ff */
-
-
-#ifndef __ASSEMBLY__
-extern void iop331_map_io(void);
-extern void iop331_init_irq(void);
-extern void iop331_time_init(void);
-#endif
-
-#endif // _IOP331_HW_H_
diff --git a/include/asm-arm/arch-iop3xx/irqs.h b/include/asm-arm/arch-iop3xx/irqs.h
deleted file mode 100644
index b2c03f4c269c..000000000000
--- a/include/asm-arm/arch-iop3xx/irqs.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/irqs.h
- *
- * Copyright: (C) 2001-2003 MontaVista Software Inc.
- *
- * 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.
- *
- */
-
-/*
- * Chipset-specific bits
- */
-#ifdef CONFIG_ARCH_IOP321
-#include "iop321-irqs.h"
-#endif
-
-#ifdef CONFIG_ARCH_IOP331
-#include "iop331-irqs.h"
-#endif
diff --git a/include/asm-arm/arch-iop3xx/memory.h b/include/asm-arm/arch-iop3xx/memory.h
deleted file mode 100644
index e43ebd984745..000000000000
--- a/include/asm-arm/arch-iop3xx/memory.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/memory.h
- */
-
-#ifndef __ASM_ARCH_MEMORY_H
-#define __ASM_ARCH_MEMORY_H
-
-#include <asm/hardware.h>
-
-/*
- * Physical DRAM offset.
- */
-#ifndef CONFIG_ARCH_IOP331
-#define PHYS_OFFSET UL(0xa0000000)
-#else
-#define PHYS_OFFSET UL(0x00000000)
-#endif
-
-/*
- * Virtual view <-> PCI DMA view memory address translations
- * virt_to_bus: Used to translate the virtual address to an
- * address suitable to be passed to set_dma_addr
- * bus_to_virt: Used to convert an address for DMA operations
- * to an address that the kernel can use.
- */
-#if defined(CONFIG_ARCH_IOP321)
-
-#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP321_IATVR2)) | ((*IOP321_IABAR2) & 0xfffffff0))
-#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP321_IALR2)) | ( *IOP321_IATVR2)))
-
-#elif defined(CONFIG_ARCH_IOP331)
-
-#define __virt_to_bus(x) (((__virt_to_phys(x)) & ~(*IOP331_IATVR2)) | ((*IOP331_IABAR2) & 0xfffffff0))
-#define __bus_to_virt(x) (__phys_to_virt(((x) & ~(*IOP331_IALR2)) | ( *IOP331_IATVR2)))
-
-#endif
-
-#endif
diff --git a/include/asm-arm/arch-iop3xx/system.h b/include/asm-arm/arch-iop3xx/system.h
deleted file mode 100644
index af6ae8cd36c9..000000000000
--- a/include/asm-arm/arch-iop3xx/system.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/system.h
- *
- * Copyright (C) 2001 MontaVista Software, Inc.
- *
- * 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.
- */
-
-static inline void arch_idle(void)
-{
- cpu_do_idle();
-}
-
-
-static inline void arch_reset(char mode)
-{
-#ifdef CONFIG_ARCH_IOP321
- *IOP321_PCSR = 0x30;
-#endif
-
-#ifdef CONFIG_ARCH_IOP331
- *IOP331_PCSR = 0x30;
-#endif
-
- if ( 1 && mode == 's') {
- /* Jump into ROM at address 0 */
- cpu_reset(0);
- } else {
- /* No on-chip reset capability */
- cpu_reset(0);
- }
-}
-
diff --git a/include/asm-arm/arch-iop3xx/timex.h b/include/asm-arm/arch-iop3xx/timex.h
deleted file mode 100644
index 14ca8d0f7b29..000000000000
--- a/include/asm-arm/arch-iop3xx/timex.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/timex.h
- *
- * IOP3xx architecture timex specifications
- */
-#include <asm/hardware.h>
-
-#if defined(CONFIG_ARCH_IQ80321) || defined(CONFIG_ARCH_IQ31244)
-
-#define CLOCK_TICK_RATE IOP321_TICK_RATE
-
-#elif defined(CONFIG_ARCH_IQ80331) || defined(CONFIG_MACH_IQ80332)
-
-#define CLOCK_TICK_RATE IOP331_TICK_RATE
-
-#else
-
-#error "No IOP3xx timex information for this architecture"
-
-#endif
diff --git a/include/asm-arm/arch-iop3xx/uncompress.h b/include/asm-arm/arch-iop3xx/uncompress.h
deleted file mode 100644
index fbdd5af644fe..000000000000
--- a/include/asm-arm/arch-iop3xx/uncompress.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/uncompress.h
- */
-#include <asm/types.h>
-#include <asm/mach-types.h>
-#include <linux/serial_reg.h>
-#include <asm/hardware.h>
-
-#ifdef CONFIG_ARCH_IOP321
-#define UTYPE unsigned char *
-#elif defined(CONFIG_ARCH_IOP331)
-#define UTYPE u32 *
-#else
-#error "Missing IOP3xx arch type def"
-#endif
-
-static volatile UTYPE uart_base;
-
-#define TX_DONE (UART_LSR_TEMT|UART_LSR_THRE)
-
-static inline void putc(char c)
-{
- while ((uart_base[UART_LSR] & TX_DONE) != TX_DONE)
- barrier();
- *uart_base = c;
-}
-
-static inline void flush(void)
-{
-}
-
-static __inline__ void __arch_decomp_setup(unsigned long arch_id)
-{
- if(machine_is_iq80321())
- uart_base = (volatile UTYPE)IQ80321_UART;
- else if(machine_is_iq31244())
- uart_base = (volatile UTYPE)IQ31244_UART;
- else if(machine_is_iq80331() || machine_is_iq80332())
- uart_base = (volatile UTYPE)IOP331_UART0_PHYS;
- else
- uart_base = (volatile UTYPE)0xfe800000;
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup() __arch_decomp_setup(arch_id)
-#define arch_decomp_wdog()
diff --git a/include/asm-arm/arch-iop3xx/vmalloc.h b/include/asm-arm/arch-iop3xx/vmalloc.h
deleted file mode 100644
index 0f2f6847f93c..000000000000
--- a/include/asm-arm/arch-iop3xx/vmalloc.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * linux/include/asm-arm/arch-iop3xx/vmalloc.h
- */
-
-/*
- * Just any arbitrary offset to the start of the vmalloc VM area: the
- * current 8MB value just means that there will be a 8MB "hole" after the
- * physical memory until the kernel virtual memory starts. That means that
- * any out-of-bounds memory accesses will hopefully be caught.
- * The vmalloc() routines leaves a hole of 4kB between each vmalloced
- * area for the same reason. ;)
- */
-//#define VMALLOC_END (0xe8000000)
-/* increase usable physical RAM to ~992M per RMK */
-#define VMALLOC_END (0xfe000000)
-
diff --git a/include/asm-arm/arch-ixp4xx/platform.h b/include/asm-arm/arch-ixp4xx/platform.h
index 13aee17b0475..8d10a9187693 100644
--- a/include/asm-arm/arch-ixp4xx/platform.h
+++ b/include/asm-arm/arch-ixp4xx/platform.h
@@ -90,6 +90,11 @@ struct ixp4xx_i2c_pins {
struct sys_timer;
/*
+ * Frequency of clock used for primary clocksource
+ */
+extern unsigned long ixp4xx_timer_freq;
+
+/*
* Functions used by platform-level setup code
*/
extern void ixp4xx_map_io(void);
diff --git a/include/asm-arm/arch-ixp4xx/system.h b/include/asm-arm/arch-ixp4xx/system.h
index 73589aad8dd6..8e1db423b1cc 100644
--- a/include/asm-arm/arch-ixp4xx/system.h
+++ b/include/asm-arm/arch-ixp4xx/system.h
@@ -1,5 +1,5 @@
/*
- * include/asm-arm/arch-ixp4x//system.h
+ * include/asm-arm/arch-ixp4xx/system.h
*
* Copyright (C) 2002 Intel Corporation.
*
diff --git a/include/asm-arm/arch-l7200/io.h b/include/asm-arm/arch-l7200/io.h
index cd080d8384d9..d744d97c18a5 100644
--- a/include/asm-arm/arch-l7200/io.h
+++ b/include/asm-arm/arch-l7200/io.h
@@ -31,9 +31,9 @@
static inline unsigned int __arch_getw(unsigned long a)
{
unsigned int value;
- __asm__ __volatile__("ldr%?h %0, [%1, #0] @ getw"
+ __asm__ __volatile__("ldrh %0, [%1, #0] @ getw"
: "=&r" (value)
- : "r" (a));
+ : "r" (a) : "cc");
return value;
}
@@ -42,8 +42,8 @@ static inline unsigned int __arch_getw(unsigned long a)
static inline void __arch_putw(unsigned int value, unsigned long a)
{
- __asm__ __volatile__("str%?h %0, [%1, #0] @ putw"
- : : "r" (value), "r" (a));
+ __asm__ __volatile__("strh %0, [%1, #0] @ putw"
+ : : "r" (value), "r" (a) : "cc");
}
/*
diff --git a/include/asm-arm/arch-l7200/time.h b/include/asm-arm/arch-l7200/time.h
index 7b98b533e63a..ea22f7fff9cd 100644
--- a/include/asm-arm/arch-l7200/time.h
+++ b/include/asm-arm/arch-l7200/time.h
@@ -43,9 +43,10 @@
* Handler for RTC timer interrupt
*/
static irqreturn_t
-timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+timer_interrupt(int irq, void *dev_id)
{
- do_timer(regs);
+ struct pt_regs *regs = get_irq_regs();
+ do_timer(1);
#ifndef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
diff --git a/include/asm-arm/arch-lh7a40x/clocks.h b/include/asm-arm/arch-lh7a40x/clocks.h
index bee02fd8dab1..7d0ba18ad578 100644
--- a/include/asm-arm/arch-lh7a40x/clocks.h
+++ b/include/asm-arm/arch-lh7a40x/clocks.h
@@ -8,8 +8,6 @@
*
*/
-#include <linux/config.h>
-
#ifndef __ASM_ARCH_CLOCKS_H
#define __ASM_ARCH_CLOCKS_H
diff --git a/include/asm-arm/arch-omap/board-ams-delta.h b/include/asm-arm/arch-omap/board-ams-delta.h
index 0070f6d3b75c..9aee15d97145 100644
--- a/include/asm-arm/arch-omap/board-ams-delta.h
+++ b/include/asm-arm/arch-omap/board-ams-delta.h
@@ -50,9 +50,20 @@
#define AMS_DELTA_LATCH2_NAND_NWE 0x0020
#define AMS_DELTA_LATCH2_NAND_ALE 0x0040
#define AMS_DELTA_LATCH2_NAND_CLE 0x0080
+#define AMD_DELTA_LATCH2_KEYBRD_PWR 0x0100
+#define AMD_DELTA_LATCH2_KEYBRD_DATA 0x0200
+#define AMD_DELTA_LATCH2_SCARD_RSTIN 0x0400
+#define AMD_DELTA_LATCH2_SCARD_CMDVCC 0x0800
#define AMS_DELTA_LATCH2_MODEM_NRESET 0x1000
#define AMS_DELTA_LATCH2_MODEM_CODEC 0x2000
+#define AMS_DELTA_GPIO_PIN_KEYBRD_DATA 0
+#define AMS_DELTA_GPIO_PIN_KEYBRD_CLK 1
+#define AMS_DELTA_GPIO_PIN_MODEM_IRQ 2
+#define AMS_DELTA_GPIO_PIN_HOOK_SWITCH 4
+#define AMS_DELTA_GPIO_PIN_SCARD_NOFF 6
+#define AMS_DELTA_GPIO_PIN_SCARD_IO 7
+#define AMS_DELTA_GPIO_PIN_CONFIG 11
#define AMS_DELTA_GPIO_PIN_NAND_RB 12
#ifndef __ASSEMBLY__
diff --git a/include/asm-arm/arch-omap/clock.h b/include/asm-arm/arch-omap/clock.h
index f83003f5287b..fa6881049903 100644
--- a/include/asm-arm/arch-omap/clock.h
+++ b/include/asm-arm/arch-omap/clock.h
@@ -45,6 +45,7 @@ struct clk_functions {
struct clk * (*clk_get_parent)(struct clk *clk);
void (*clk_allow_idle)(struct clk *clk);
void (*clk_deny_idle)(struct clk *clk);
+ void (*clk_disable_unused)(struct clk *clk);
};
extern unsigned int mpurate;
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index 1b1b02307e77..d591d0585bba 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -331,6 +331,12 @@ enum omap_dma_color_mode {
OMAP_DMA_TRANSPARENT_COPY
};
+enum omap_dma_write_mode {
+ OMAP_DMA_WRITE_NON_POSTED = 0,
+ OMAP_DMA_WRITE_POSTED,
+ OMAP_DMA_WRITE_LAST_NON_POSTED
+};
+
struct omap_dma_channel_params {
int data_type; /* data type 8,16,32 */
int elem_count; /* number of elements in a frame */
@@ -338,13 +344,13 @@ struct omap_dma_channel_params {
int src_port; /* Only on OMAP1 REVISIT: Is this needed? */
int src_amode; /* constant , post increment, indexed , double indexed */
- int src_start; /* source address : physical */
+ unsigned long src_start; /* source address : physical */
int src_ei; /* source element index */
int src_fi; /* source frame index */
int dst_port; /* Only on OMAP1 REVISIT: Is this needed? */
int dst_amode; /* constant , post increment, indexed , double indexed */
- int dst_start; /* source address : physical */
+ unsigned long dst_start; /* source address : physical */
int dst_ei; /* source element index */
int dst_fi; /* source frame index */
@@ -356,7 +362,7 @@ struct omap_dma_channel_params {
};
-extern void omap_set_dma_priority(int dst_port, int priority);
+extern void omap_set_dma_priority(int lch, int dst_port, int priority);
extern int omap_request_dma(int dev_id, const char *dev_name,
void (* callback)(int lch, u16 ch_status, void *data),
void *data, int *dma_ch);
@@ -371,6 +377,7 @@ extern void omap_set_dma_transfer_params(int lch, int data_type,
int dma_trigger, int src_or_dst_synch);
extern void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode,
u32 color);
+extern void omap_set_dma_write_mode(int lch, enum omap_dma_write_mode mode);
extern void omap_set_dma_src_params(int lch, int src_port, int src_amode,
unsigned long src_start,
@@ -394,6 +401,9 @@ extern void omap_set_dma_params(int lch,
extern void omap_dma_link_lch (int lch_head, int lch_queue);
extern void omap_dma_unlink_lch (int lch_head, int lch_queue);
+extern int omap_set_dma_callback(int lch,
+ void (* callback)(int lch, u16 ch_status, void *data),
+ void *data);
extern dma_addr_t omap_get_dma_src_pos(int lch);
extern dma_addr_t omap_get_dma_dst_pos(int lch);
extern int omap_get_dma_src_addr_counter(int lch);
diff --git a/include/asm-arm/arch-omap/dmtimer.h b/include/asm-arm/arch-omap/dmtimer.h
index 7a289ff07404..fefb276ed402 100644
--- a/include/asm-arm/arch-omap/dmtimer.h
+++ b/include/asm-arm/arch-omap/dmtimer.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/arm/arch-omap/dmtimer.h
+ * linux/include/asm-arm/arch-omap/dmtimer.h
*
* OMAP Dual-Mode Timers
*
@@ -52,6 +52,8 @@ int omap_dm_timer_init(void);
struct omap_dm_timer *omap_dm_timer_request(void);
struct omap_dm_timer *omap_dm_timer_request_specific(int timer_id);
void omap_dm_timer_free(struct omap_dm_timer *timer);
+void omap_dm_timer_enable(struct omap_dm_timer *timer);
+void omap_dm_timer_disable(struct omap_dm_timer *timer);
int omap_dm_timer_get_irq(struct omap_dm_timer *timer);
diff --git a/include/asm-arm/arch-omap/gpmc.h b/include/asm-arm/arch-omap/gpmc.h
index 1a0a5207822d..7c03ef6c14c4 100644
--- a/include/asm-arm/arch-omap/gpmc.h
+++ b/include/asm-arm/arch-omap/gpmc.h
@@ -85,7 +85,7 @@ extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
extern u32 gpmc_cs_read_reg(int cs, int idx);
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 unsigned long gpmc_cs_get_base_addr(int cs);
-
+extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
+extern void gpmc_cs_free(int cs);
#endif
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 2542495d8a43..c5bb05a69b81 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -237,6 +237,7 @@
#define INT_24XX_SDMA_IRQ1 13
#define INT_24XX_SDMA_IRQ2 14
#define INT_24XX_SDMA_IRQ3 15
+#define INT_24XX_CAM_IRQ 24
#define INT_24XX_DSS_IRQ 25
#define INT_24XX_GPIO_BANK1 29
#define INT_24XX_GPIO_BANK2 30
@@ -261,6 +262,7 @@
#define INT_24XX_UART1_IRQ 72
#define INT_24XX_UART2_IRQ 73
#define INT_24XX_UART3_IRQ 74
+#define INT_24XX_MMC_IRQ 83
/* Max. 128 level 2 IRQs (OMAP1610), 192 GPIOs (OMAP730) and
* 16 MPUIO lines */
diff --git a/include/asm-arm/arch-omap/keypad.h b/include/asm-arm/arch-omap/keypad.h
index 8a023a984acb..b7f83075436e 100644
--- a/include/asm-arm/arch-omap/keypad.h
+++ b/include/asm-arm/arch-omap/keypad.h
@@ -14,7 +14,10 @@ struct omap_kp_platform_data {
int rows;
int cols;
int *keymap;
+ unsigned int keymapsize;
unsigned int rep:1;
+ unsigned long delay;
+ unsigned int dbounce:1;
/* specific to OMAP242x*/
unsigned int *row_gpios;
unsigned int *col_gpios;
diff --git a/include/asm-arm/arch-omap/mcbsp.h b/include/asm-arm/arch-omap/mcbsp.h
index ed0dde4f7219..c7a0cc1c4e93 100644
--- a/include/asm-arm/arch-omap/mcbsp.h
+++ b/include/asm-arm/arch-omap/mcbsp.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/arch-omap/gpio.h
+ * linux/include/asm-arm/arch-omap/mcbsp.h
*
* Defines for Multi-Channel Buffered Serial Port
*
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
index 679869c5e68f..828cc5c114e1 100644
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -320,6 +320,17 @@ enum omap1xxx_index {
P15_1610_UWIRE_CS3,
N15_1610_UWIRE_CS1,
+ /* OMAP-1610 SPI */
+ U19_1610_SPIF_SCK,
+ U18_1610_SPIF_DIN,
+ P20_1610_SPIF_DIN,
+ W21_1610_SPIF_DOUT,
+ R18_1610_SPIF_DOUT,
+ N14_1610_SPIF_CS0,
+ N15_1610_SPIF_CS1,
+ T19_1610_SPIF_CS2,
+ P15_1610_SPIF_CS3,
+
/* OMAP-1610 Flash */
L3_1610_FLASH_CS2B_OE,
M8_1610_FLASH_CS2B_WE,
@@ -461,6 +472,20 @@ enum omap24xx_index {
K15_24XX_UART3_TX,
K14_24XX_UART3_RX,
+ /* MMC/SDIO */
+ G19_24XX_MMC_CLKO,
+ H18_24XX_MMC_CMD,
+ F20_24XX_MMC_DAT0,
+ H14_24XX_MMC_DAT1,
+ E19_24XX_MMC_DAT2,
+ D19_24XX_MMC_DAT3,
+ F19_24XX_MMC_DAT_DIR0,
+ E20_24XX_MMC_DAT_DIR1,
+ F18_24XX_MMC_DAT_DIR2,
+ E18_24XX_MMC_DAT_DIR3,
+ G18_24XX_MMC_CMD_DIR,
+ H15_24XX_MMC_CLKI,
+
/* Keypad GPIO*/
T19_24XX_KBR0,
R19_24XX_KBR1,
diff --git a/include/asm-arm/arch-omap/pm.h b/include/asm-arm/arch-omap/pm.h
index e46623c61a72..14588059981f 100644
--- a/include/asm-arm/arch-omap/pm.h
+++ b/include/asm-arm/arch-omap/pm.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm/arch-omap/pm.h
+ * linux/include/asm-arm/arch-omap/pm.h
*
* Header file for OMAP Power Management Routines
*
diff --git a/include/asm-arm/arch-pnx4008/clock.h b/include/asm-arm/arch-pnx4008/clock.h
index 91ae0030fdf2..ce155e161269 100644
--- a/include/asm-arm/arch-pnx4008/clock.h
+++ b/include/asm-arm/arch-pnx4008/clock.h
@@ -32,6 +32,7 @@ struct clk;
#define KEYCLKCTRL_REG (PWRMAN_VA_BASE + 0xb0)
#define TSCLKCTRL_REG (PWRMAN_VA_BASE + 0xb4)
#define PWMCLKCTRL_REG (PWRMAN_VA_BASE + 0xb8)
+#define TIMCLKCTRL_REG (PWRMAN_VA_BASE + 0xbc)
#define SPICTRL_REG (PWRMAN_VA_BASE + 0xc4)
#define FLASHCLKCTRL_REG (PWRMAN_VA_BASE + 0xc8)
#define UART3CLK_REG (PWRMAN_VA_BASE + 0xd0)
diff --git a/include/asm-arm/arch-pnx4008/dma.h b/include/asm-arm/arch-pnx4008/dma.h
index 3aee1204795b..418f15283ff1 100644
--- a/include/asm-arm/arch-pnx4008/dma.h
+++ b/include/asm-arm/arch-pnx4008/dma.h
@@ -137,7 +137,7 @@ extern void pnx4008_free_ll_entry(struct pnx4008_dma_ll *, dma_addr_t);
extern void pnx4008_free_ll(u32 ll_dma, struct pnx4008_dma_ll *);
extern int pnx4008_request_channel(char *, int,
- void (*)(int, int, void *, struct pt_regs *),
+ void (*)(int, int, void *),
void *);
extern void pnx4008_free_channel(int);
extern int pnx4008_config_dma(int, int, int);
diff --git a/include/asm-arm/arch-pnx4008/platform.h b/include/asm-arm/arch-pnx4008/platform.h
index 485a3651b4d7..2613c7c669b1 100644
--- a/include/asm-arm/arch-pnx4008/platform.h
+++ b/include/asm-arm/arch-pnx4008/platform.h
@@ -1,5 +1,5 @@
/*
- * include/asm-arm/arch-pnx4008/platfrom.h
+ * include/asm-arm/arch-pnx4008/platform.h
*
* PNX4008 Base addresses - header file
*
diff --git a/include/asm-arm/arch-pxa/dma.h b/include/asm-arm/arch-pxa/dma.h
index a008150abc59..bed042d71d68 100644
--- a/include/asm-arm/arch-pxa/dma.h
+++ b/include/asm-arm/arch-pxa/dma.h
@@ -56,7 +56,7 @@ for ( \
int pxa_request_dma (char *name,
pxa_dma_prio prio,
- void (*irq_handler)(int, void *, struct pt_regs *),
+ void (*irq_handler)(int, void *),
void *data);
void pxa_free_dma (int dma_ch);
diff --git a/include/asm-arm/arch-pxa/mmc.h b/include/asm-arm/arch-pxa/mmc.h
index 88c17dd02ed2..a38a28c4bbd8 100644
--- a/include/asm-arm/arch-pxa/mmc.h
+++ b/include/asm-arm/arch-pxa/mmc.h
@@ -10,7 +10,7 @@ struct mmc_host;
struct pxamci_platform_data {
unsigned int ocr_mask; /* available voltages */
unsigned long detect_delay; /* delay in jiffies before detecting cards after interrupt */
- int (*init)(struct device *, irqreturn_t (*)(int, void *, struct pt_regs *), void *);
+ int (*init)(struct device *, irq_handler_t , void *);
int (*get_ro)(struct device *);
void (*setpower)(struct device *, unsigned int);
void (*exit)(struct device *, void *);
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index f5cc65dd7d0d..68731e0923a4 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1681,6 +1681,7 @@
#define SSSR_TINT (1 << 19) /* Receiver Time-out Interrupt */
#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
+#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
#define SSPSP_DMYSTOP(x) (x << 23) /* Dummy Stop */
#define SSPSP_SFRMWDTH(x) (x << 16) /* Serial Frame Width */
#define SSPSP_SFRMDLY(x) (x << 9) /* Serial Frame Delay */
diff --git a/include/asm-arm/arch-pxa/pxafb.h b/include/asm-arm/arch-pxa/pxafb.h
index aba9b30f4249..81c3928d608c 100644
--- a/include/asm-arm/arch-pxa/pxafb.h
+++ b/include/asm-arm/arch-pxa/pxafb.h
@@ -12,12 +12,14 @@
* published by the Free Software Foundation.
*/
+#include <linux/fb.h>
+
/*
* This structure describes the machine which we are running on.
* It is set in linux/arch/arm/mach-pxa/machine_name.c and used in the probe routine
* of linux/drivers/video/pxafb.c
*/
-struct pxafb_mach_info {
+struct pxafb_mode_info {
u_long pixclock;
u_short xres;
@@ -34,6 +36,14 @@ struct pxafb_mach_info {
u_char sync;
u_int cmap_greyscale:1,
+ unused:31;
+};
+
+struct pxafb_mach_info {
+ struct pxafb_mode_info *modes;
+ unsigned int num_modes;
+
+ u_int fixed_modes:1,
cmap_inverse:1,
cmap_static:1,
unused:29;
@@ -62,7 +72,7 @@ struct pxafb_mach_info {
u_int lccr3;
void (*pxafb_backlight_power)(int);
- void (*pxafb_lcd_power)(int);
+ void (*pxafb_lcd_power)(int, struct fb_var_screeninfo *);
};
void set_pxa_fb_info(struct pxafb_mach_info *hard_pxa_fb_info);
diff --git a/include/asm-arm/arch-pxa/spitz.h b/include/asm-arm/arch-pxa/spitz.h
index 62e1fe4d025f..4953dd324d4d 100644
--- a/include/asm-arm/arch-pxa/spitz.h
+++ b/include/asm-arm/arch-pxa/spitz.h
@@ -15,6 +15,8 @@
#define __ASM_ARCH_SPITZ_H 1
#endif
+#include <linux/fb.h>
+
/* Spitz/Akita GPIOs */
#define SPITZ_GPIO_KEY_INT (0) /* Key Interrupt */
@@ -155,4 +157,4 @@ extern struct platform_device spitzscoop2_device;
extern struct platform_device spitzssp_device;
extern struct sharpsl_charger_machinfo spitz_pm_machinfo;
-extern void spitz_lcd_power(int on);
+extern void spitz_lcd_power(int on, struct fb_var_screeninfo *var);
diff --git a/include/asm-arm/arch-pxa/udc.h b/include/asm-arm/arch-pxa/udc.h
index 30548a30c773..121cd241115d 100644
--- a/include/asm-arm/arch-pxa/udc.h
+++ b/include/asm-arm/arch-pxa/udc.h
@@ -12,6 +12,14 @@ struct pxa2xx_udc_mach_info {
void (*udc_command)(int cmd);
#define PXA2XX_UDC_CMD_CONNECT 0 /* let host see us */
#define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */
+
+ /* Boards following the design guidelines in the developer's manual,
+ * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
+ * VBUS IRQ and omit the methods above. Store the GPIO number
+ * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
+ */
+ u16 gpio_vbus; /* high == vbus present */
+ u16 gpio_pullup; /* high == pullup activated */
};
extern void pxa_set_udc_info(struct pxa2xx_udc_mach_info *info);
diff --git a/include/asm-arm/arch-s3c2410/dma.h b/include/asm-arm/arch-s3c2410/dma.h
index 3661e465b0a5..7ac224836971 100644
--- a/include/asm-arm/arch-s3c2410/dma.h
+++ b/include/asm-arm/arch-s3c2410/dma.h
@@ -23,6 +23,39 @@
#define MAX_DMA_ADDRESS 0x40000000
#define MAX_DMA_TRANSFER_SIZE 0x100000 /* Data Unit is half word */
+/* We use `virtual` dma channels to hide the fact we have only a limited
+ * number of DMA channels, and not of all of them (dependant on the device)
+ * can be attached to any DMA source. We therefore let the DMA core handle
+ * the allocation of hardware channels to clients.
+*/
+
+enum dma_ch {
+ DMACH_XD0,
+ DMACH_XD1,
+ DMACH_SDI,
+ DMACH_SPI0,
+ DMACH_SPI1,
+ DMACH_UART0,
+ DMACH_UART1,
+ DMACH_UART2,
+ DMACH_TIMER,
+ DMACH_I2S_IN,
+ DMACH_I2S_OUT,
+ DMACH_PCM_IN,
+ DMACH_PCM_OUT,
+ DMACH_MIC_IN,
+ DMACH_USB_EP1,
+ DMACH_USB_EP2,
+ DMACH_USB_EP3,
+ DMACH_USB_EP4,
+ DMACH_UART0_SRC2, /* s3c2412 second uart sources */
+ DMACH_UART1_SRC2,
+ DMACH_UART2_SRC2,
+ DMACH_MAX, /* the end entry */
+};
+
+#define DMACH_LOW_LEVEL (1<<28) /* use this to specifiy hardware ch no */
+
/* we have 4 dma channels */
#define S3C2410_DMA_CHANNELS (4)
@@ -149,6 +182,8 @@ struct s3c2410_dma_stats {
unsigned long timeout_failed;
};
+struct s3c2410_dma_map;
+
/* struct s3c2410_dma_chan
*
* full state information for each DMA channel
@@ -174,6 +209,8 @@ struct s3c2410_dma_chan {
unsigned long load_timeout;
unsigned int flags; /* channel flags */
+ struct s3c24xx_dma_map *map; /* channel hw maps */
+
/* channel's hardware position and configuration */
void __iomem *regs; /* channels registers */
void __iomem *addr_reg; /* data address register */
@@ -283,6 +320,7 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn);
#define S3C2410_DMA_DCSRC (0x18)
#define S3C2410_DMA_DCDST (0x1C)
#define S3C2410_DMA_DMASKTRIG (0x20)
+#define S3C2412_DMA_DMAREQSEL (0x24)
#define S3C2410_DISRCC_INC (1<<0)
#define S3C2410_DISRCC_APB (1<<1)
@@ -349,4 +387,32 @@ extern int s3c2410_dma_set_buffdone_fn(dmach_t, s3c2410_dma_cbfn_t rtn);
#define S3C2440_DCON_CH3_PCMOUT (6<<24)
#endif
+#ifdef CONFIG_CPU_S3C2412
+
+#define S3C2412_DMAREQSEL_SRC(x) ((x)<<1)
+
+#define S3C2412_DMAREQSEL_HW (1)
+
+#define S3C2412_DMAREQSEL_SPI0TX S3C2412_DMAREQSEL_SRC(0)
+#define S3C2412_DMAREQSEL_SPI0RX S3C2412_DMAREQSEL_SRC(1)
+#define S3C2412_DMAREQSEL_SPI1TX S3C2412_DMAREQSEL_SRC(2)
+#define S3C2412_DMAREQSEL_SPI1RX S3C2412_DMAREQSEL_SRC(3)
+#define S3C2412_DMAREQSEL_I2STX S3C2412_DMAREQSEL_SRC(4)
+#define S3C2412_DMAREQSEL_I2SRX S3C2412_DMAREQSEL_SRC(5)
+#define S3C2412_DMAREQSEL_TIMER S3C2412_DMAREQSEL_SRC(9)
+#define S3C2412_DMAREQSEL_SDI S3C2412_DMAREQSEL_SRC(10)
+#define S3C2412_DMAREQSEL_USBEP1 S3C2412_DMAREQSEL_SRC(13)
+#define S3C2412_DMAREQSEL_USBEP2 S3C2412_DMAREQSEL_SRC(14)
+#define S3C2412_DMAREQSEL_USBEP3 S3C2412_DMAREQSEL_SRC(15)
+#define S3C2412_DMAREQSEL_USBEP4 S3C2412_DMAREQSEL_SRC(16)
+#define S3C2412_DMAREQSEL_XDREQ0 S3C2412_DMAREQSEL_SRC(17)
+#define S3C2412_DMAREQSEL_XDREQ1 S3C2412_DMAREQSEL_SRC(18)
+#define S3C2412_DMAREQSEL_UART0_0 S3C2412_DMAREQSEL_SRC(19)
+#define S3C2412_DMAREQSEL_UART0_1 S3C2412_DMAREQSEL_SRC(20)
+#define S3C2412_DMAREQSEL_UART1_0 S3C2412_DMAREQSEL_SRC(21)
+#define S3C2412_DMAREQSEL_UART1_1 S3C2412_DMAREQSEL_SRC(22)
+#define S3C2412_DMAREQSEL_UART2_0 S3C2412_DMAREQSEL_SRC(23)
+#define S3C2412_DMAREQSEL_UART2_1 S3C2412_DMAREQSEL_SRC(24)
+
+#endif
#endif /* __ASM_ARCH_DMA_H */
diff --git a/include/asm-arm/arch-s3c2410/fb.h b/include/asm-arm/arch-s3c2410/fb.h
index 71161797bc89..90894214cace 100644
--- a/include/asm-arm/arch-s3c2410/fb.h
+++ b/include/asm-arm/arch-s3c2410/fb.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/fb.h
+/* linux/include/asm-arm/arch-s3c2410/fb.h
*
* Copyright (c) 2004 Arnaud Patard <arnaud.patard@rtp-net.org>
*
diff --git a/include/asm-arm/arch-s3c2410/map.h b/include/asm-arm/arch-s3c2410/map.h
index 27ba0ac3fdd5..7895042d176b 100644
--- a/include/asm-arm/arch-s3c2410/map.h
+++ b/include/asm-arm/arch-s3c2410/map.h
@@ -160,6 +160,11 @@
#define S3C2440_PA_CAMIF (0x4F000000)
#define S3C2440_SZ_CAMIF SZ_1M
+/* AC97 */
+
+#define S3C2440_PA_AC97 (0x5B000000)
+#define S3C2440_SZ_AC97 SZ_1M
+
/* ISA style IO, for each machine to sort out mappings for, if it
* implements it. We reserve two 16M regions for ISA.
*/
diff --git a/include/asm-arm/arch-s3c2410/osiris-map.h b/include/asm-arm/arch-s3c2410/osiris-map.h
index e2d406218ae5..a14164dfa525 100644
--- a/include/asm-arm/arch-s3c2410/osiris-map.h
+++ b/include/asm-arm/arch-s3c2410/osiris-map.h
@@ -18,22 +18,22 @@
/* start peripherals off after the S3C2410 */
-#define OSIRIS_IOADDR(x) (S3C2410_ADDR((x) + 0x05000000))
+#define OSIRIS_IOADDR(x) (S3C2410_ADDR((x) + 0x04000000))
-#define OSIRIS_PA_CPLD (S3C2410_CS1 | (3<<25))
+#define OSIRIS_PA_CPLD (S3C2410_CS1 | (1<<26))
/* we put the CPLD registers next, to get them out of the way */
-#define OSIRIS_VA_CTRL1 OSIRIS_IOADDR(0x00000000) /* 0x01300000 */
+#define OSIRIS_VA_CTRL1 OSIRIS_IOADDR(0x00000000)
#define OSIRIS_PA_CTRL1 (OSIRIS_PA_CPLD)
-#define OSIRIS_VA_CTRL2 OSIRIS_IOADDR(0x00100000) /* 0x01400000 */
-#define OSIRIS_PA_CTRL2 (OSIRIS_PA_CPLD + (1<<24))
+#define OSIRIS_VA_CTRL2 OSIRIS_IOADDR(0x00100000)
+#define OSIRIS_PA_CTRL2 (OSIRIS_PA_CPLD + (1<<23))
-#define OSIRIS_VA_CTRL3 OSIRIS_IOADDR(0x00200000) /* 0x01500000 */
-#define OSIRIS_PA_CTRL3 (OSIRIS_PA_CPLD + (2<<24))
+#define OSIRIS_VA_CTRL3 OSIRIS_IOADDR(0x00200000)
+#define OSIRIS_PA_CTRL3 (OSIRIS_PA_CPLD + (2<<23))
-#define OSIRIS_VA_CTRL4 OSIRIS_IOADDR(0x00300000) /* 0x01600000 */
-#define OSIRIS_PA_CTRL4 (OSIRIS_PA_CPLD + (3<<24))
+#define OSIRIS_VA_CTRL4 OSIRIS_IOADDR(0x00300000)
+#define OSIRIS_PA_CTRL4 (OSIRIS_PA_CPLD + (3<<23))
#endif /* __ASM_ARCH_OSIRISMAP_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-ac97.h b/include/asm-arm/arch-s3c2410/regs-ac97.h
new file mode 100644
index 000000000000..bdd6a4f93d7f
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/regs-ac97.h
@@ -0,0 +1,23 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-ac97.h
+ *
+ * Copyright (c) 2006 Simtec Electronics <linux@simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * 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.
+ *
+ * S3C2440 AC97 Controller
+*/
+
+#ifndef __ASM_ARCH_REGS_AC97_H
+#define __ASM_ARCH_REGS_AC97_H __FILE__
+
+#define S3C_AC97_GLBCTRL (0x00)
+#define S3C_AC97_GLBSTAT (0x04)
+#define S3C_AC97_CODEC_CMD (0x08)
+#define S3C_AC97_PCM_ADDR (0x10)
+#define S3C_AC97_PCM_DATA (0x18)
+#define S3C_AC97_MIC_DATA (0x1C)
+
+#endif /* __ASM_ARCH_REGS_AC97_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-adc.h b/include/asm-arm/arch-s3c2410/regs-adc.h
index c7b90b3ecc9e..3196a2849e8a 100644
--- a/include/asm-arm/arch-s3c2410/regs-adc.h
+++ b/include/asm-arm/arch-s3c2410/regs-adc.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-adc.h
+/* linux/include/asm-arm/arch-s3c2410/regs-adc.h
*
* Copyright (c) 2004 Shannon Holland <holland@loser.net>
*
diff --git a/include/asm-arm/arch-s3c2410/regs-clock.h b/include/asm-arm/arch-s3c2410/regs-clock.h
index b2f4690c0791..e39656b7a086 100644
--- a/include/asm-arm/arch-s3c2410/regs-clock.h
+++ b/include/asm-arm/arch-s3c2410/regs-clock.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-clock.h
+/* linux/include/asm-arm/arch-s3c2410/regs-clock.h
*
* Copyright (c) 2003,2004,2005,2006 Simtec Electronics <linux@simtec.co.uk>
* http://armlinux.simtec.co.uk/
diff --git a/include/asm-arm/arch-s3c2410/regs-dsc.h b/include/asm-arm/arch-s3c2410/regs-dsc.h
index a0a124875164..c0748511edbc 100644
--- a/include/asm-arm/arch-s3c2410/regs-dsc.h
+++ b/include/asm-arm/arch-s3c2410/regs-dsc.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/hardware/s3c2410/regs-dsc.h
+/* linux/include/asm-arm/arch-s3c2410/regs-dsc.h
*
* Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
index 93c49432db95..b2893e32a236 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/hardware/s3c2410/regs-gpio.h
+/* linux/include/asm-arm/arch-s3c2410/regs-gpio.h
*
* Copyright (c) 2003,2004 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-gpioj.h b/include/asm-arm/arch-s3c2410/regs-gpioj.h
index 91cefa260497..02131a5a1d3a 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpioj.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpioj.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/hardware/s3c2410/regs-gpioj.h
+/* linux/include/asm-arm/arch-s3c2410/regs-gpioj.h
*
* Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-iis.h b/include/asm-arm/arch-s3c2410/regs-iis.h
index 72cd2509822e..eaf77916a602 100644
--- a/include/asm-arm/arch-s3c2410/regs-iis.h
+++ b/include/asm-arm/arch-s3c2410/regs-iis.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-iis.h
+/* linux/include/asm-arm/arch-s3c2410/regs-iis.h
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-irq.h b/include/asm-arm/arch-s3c2410/regs-irq.h
index 29fb8ef670f0..498184cb8adc 100644
--- a/include/asm-arm/arch-s3c2410/regs-irq.h
+++ b/include/asm-arm/arch-s3c2410/regs-irq.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-irq.h
+/* linux/include/asm-arm/arch-s3c2410/regs-irq.h
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-lcd.h b/include/asm-arm/arch-s3c2410/regs-lcd.h
index b306d6e3135d..b7faeb04c0ff 100644
--- a/include/asm-arm/arch-s3c2410/regs-lcd.h
+++ b/include/asm-arm/arch-s3c2410/regs-lcd.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-lcd.h
+/* linux/include/asm-arm/arch-s3c2410/regs-lcd.h
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
@@ -63,6 +63,8 @@
#define S3C2410_LCDCON3_GET_HBPD(x) ( ((x) >> 19) & 0x7F)
#define S3C2410_LCDCON3_GET_HFPD(x) ( ((x) >> 0) & 0xFF)
+/* LDCCON4 changes for STN mode on the S3C2412 */
+
#define S3C2410_LCDCON4_MVAL(x) ((x) << 8)
#define S3C2410_LCDCON4_HSPW(x) ((x) << 0)
#define S3C2410_LCDCON4_WLH(x) ((x) << 0)
@@ -113,10 +115,38 @@
#define S3C2410_LCDINT_FRSYNC (1<<1)
#define S3C2410_LCDINT_FICNT (1<<0)
+/* s3c2442 extra stn registers */
+
+#define S3C2442_REDLUT S3C2410_LCDREG(0x20)
+#define S3C2442_GREENLUT S3C2410_LCDREG(0x24)
+#define S3C2442_BLUELUT S3C2410_LCDREG(0x28)
+#define S3C2442_DITHMODE S3C2410_LCDREG(0x20)
+
#define S3C2410_LPCSEL S3C2410_LCDREG(0x60)
#define S3C2410_TFTPAL(x) S3C2410_LCDREG((0x400 + (x)*4))
+/* S3C2412 registers */
+
+#define S3C2412_TPAL S3C2410_LCDREG(0x20)
+
+#define S3C2412_LCDINTPND S3C2410_LCDREG(0x24)
+#define S3C2412_LCDSRCPND S3C2410_LCDREG(0x28)
+#define S3C2412_LCDINTMSK S3C2410_LCDREG(0x2C)
+
+#define S3C2412_TCONSEL S3C2410_LCDREG(0x30)
+
+#define S3C2412_LCDCON6 S3C2410_LCDREG(0x34)
+#define S3C2412_LCDCON7 S3C2410_LCDREG(0x38)
+#define S3C2412_LCDCON8 S3C2410_LCDREG(0x3C)
+#define S3C2412_LCDCON9 S3C2410_LCDREG(0x40)
+
+#define S3C2412_REDLUT(x) S3C2410_LCDREG(0x44 + ((x)*4))
+#define S3C2412_GREENLUT(x) S3C2410_LCDREG(0x60 + ((x)*4))
+#define S3C2412_BLUELUT(x) S3C2410_LCDREG(0x98 + ((x)*4))
+
+#define S3C2412_FRCPAT(x) S3C2410_LCDREG(0xB4 + ((x)*4))
+
#endif /* ___ASM_ARCH_REGS_LCD_H */
diff --git a/include/asm-arm/arch-s3c2410/regs-rtc.h b/include/asm-arm/arch-s3c2410/regs-rtc.h
index cd88fd634d12..93b03c49710a 100644
--- a/include/asm-arm/arch-s3c2410/regs-rtc.h
+++ b/include/asm-arm/arch-s3c2410/regs-rtc.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-rtc.h
+/* linux/include/asm-arm/arch-s3c2410/regs-rtc.h
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-sdi.h b/include/asm-arm/arch-s3c2410/regs-sdi.h
index 06e716e5b46d..bb9d30b72952 100644
--- a/include/asm-arm/arch-s3c2410/regs-sdi.h
+++ b/include/asm-arm/arch-s3c2410/regs-sdi.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-sdi.h
+/* linux/include/asm-arm/arch-s3c2410/regs-sdi.h
*
* Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-timer.h b/include/asm-arm/arch-s3c2410/regs-timer.h
index 731918e77831..6f8fe432fe3a 100644
--- a/include/asm-arm/arch-s3c2410/regs-timer.h
+++ b/include/asm-arm/arch-s3c2410/regs-timer.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-timer.h
+/* linux/include/asm-arm/arch-s3c2410/regs-timer.h
*
* Copyright (c) 2003 Simtec Electronics <linux@simtec.co.uk>
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/asm-arm/arch-s3c2410/regs-udc.h b/include/asm-arm/arch-s3c2410/regs-udc.h
index 3aa31a27da1a..487861d5b49a 100644
--- a/include/asm-arm/arch-s3c2410/regs-udc.h
+++ b/include/asm-arm/arch-s3c2410/regs-udc.h
@@ -1,4 +1,4 @@
-/* linux/include/asm/arch-s3c2410/regs-udc.h
+/* linux/include/asm-arm/arch-s3c2410/regs-udc.h
*
* Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at>
*
diff --git a/include/asm-arm/arch-s3c2410/spi-gpio.h b/include/asm-arm/arch-s3c2410/spi-gpio.h
index 258c00bca270..c1e4db7c9710 100644
--- a/include/asm-arm/arch-s3c2410/spi-gpio.h
+++ b/include/asm-arm/arch-s3c2410/spi-gpio.h
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-s3c2410/spi.h
+/* linux/include/asm-arm/arch-s3c2410/spi-gpio.h
*
* Copyright (c) 2006 Simtec Electronics
* Ben Dooks <ben@simtec.co.uk>
diff --git a/include/asm-arm/arch-sa1100/jornada720.h b/include/asm-arm/arch-sa1100/jornada720.h
index 1b8e8a304800..3f37ca07806d 100644
--- a/include/asm-arm/arch-sa1100/jornada720.h
+++ b/include/asm-arm/arch-sa1100/jornada720.h
@@ -19,6 +19,20 @@
#define GPIO_JORNADA720_KEYBOARD_IRQ IRQ_GPIO0
#define GPIO_JORNADA720_MOUSE_IRQ IRQ_GPIO9
+/* MCU COMMANDS */
+#define MCU_GetBatteryData 0xc0
+#define MCU_GetScanKeyCode 0x90
+#define MCU_GetTouchSamples 0xa0
+#define MCU_GetContrast 0xD0
+#define MCU_SetContrast 0xD1
+#define MCU_GetBrightness 0xD2
+#define MCU_SetBrightness 0xD3
+#define MCU_ContrastOff 0xD8
+#define MCU_BrightnessOff 0xD9
+#define MCU_PWMOFF 0xDF
+#define MCU_TxDummy 0x11
+#define MCU_ErrorCode 0x00
+
#ifndef __ASSEMBLY__
void jornada720_mcu_init(void);
diff --git a/include/asm-arm/arch-sa1100/neponset.h b/include/asm-arm/arch-sa1100/neponset.h
index 8051fd73a80b..09ec9e2bd182 100644
--- a/include/asm-arm/arch-sa1100/neponset.h
+++ b/include/asm-arm/arch-sa1100/neponset.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/arch-sa1100/assabet.h
+ * linux/include/asm-arm/arch-sa1100/neponset.h
*
* Created 2000/06/05 by Nicolas Pitre <nico@cam.org>
*
diff --git a/include/asm-arm/arch-sa1100/uncompress.h b/include/asm-arm/arch-sa1100/uncompress.h
index 2601a77a6dda..17e64d232e7d 100644
--- a/include/asm-arm/arch-sa1100/uncompress.h
+++ b/include/asm-arm/arch-sa1100/uncompress.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/arch-brutus/uncompress.h
+ * linux/include/asm-arm/arch-sa1100/uncompress.h
*
* (C) 1999 Nicolas Pitre <nico@cam.org>
*
diff --git a/include/asm-arm/arch-shark/vmalloc.h b/include/asm-arm/arch-shark/vmalloc.h
index 10db5d188231..fac37c636b38 100644
--- a/include/asm-arm/arch-shark/vmalloc.h
+++ b/include/asm-arm/arch-shark/vmalloc.h
@@ -1,4 +1,4 @@
/*
- * linux/include/asm-arm/arch-rpc/vmalloc.h
+ * linux/include/asm-arm/arch-shark/vmalloc.h
*/
#define VMALLOC_END (PAGE_OFFSET + 0x10000000)
diff --git a/include/asm-arm/arch-versatile/hardware.h b/include/asm-arm/arch-versatile/hardware.h
index 41c1bee342ad..edc06598d187 100644
--- a/include/asm-arm/arch-versatile/hardware.h
+++ b/include/asm-arm/arch-versatile/hardware.h
@@ -28,8 +28,8 @@
/*
* PCI space virtual addresses
*/
-#define VERSATILE_PCI_VIRT_BASE 0xe8000000
-#define VERSATILE_PCI_CFG_VIRT_BASE 0xe9000000
+#define VERSATILE_PCI_VIRT_BASE (void __iomem *)0xe8000000ul
+#define VERSATILE_PCI_CFG_VIRT_BASE (void __iomem *)0xe9000000ul
#if 0
#define VERSATILE_PCI_VIRT_MEM_BASE0 0xf4000000
diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h
index 4b0ce3e7de9a..ea88aa6bfc78 100644
--- a/include/asm-arm/atomic.h
+++ b/include/asm-arm/atomic.h
@@ -128,10 +128,10 @@ static inline int atomic_add_return(int i, atomic_t *v)
unsigned long flags;
int val;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
val = v->counter;
v->counter = val += i;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
return val;
}
@@ -141,10 +141,10 @@ static inline int atomic_sub_return(int i, atomic_t *v)
unsigned long flags;
int val;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
val = v->counter;
v->counter = val -= i;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
return val;
}
@@ -154,11 +154,11 @@ static inline int atomic_cmpxchg(atomic_t *v, int old, int new)
int ret;
unsigned long flags;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
ret = v->counter;
if (likely(ret == old))
v->counter = new;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
return ret;
}
@@ -167,9 +167,9 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
{
unsigned long flags;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
*addr &= ~mask;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
}
#endif /* __LINUX_ARM_ARCH__ */
diff --git a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h
index 0ac54b1a8bad..b41831b6432f 100644
--- a/include/asm-arm/bitops.h
+++ b/include/asm-arm/bitops.h
@@ -37,9 +37,9 @@ static inline void ____atomic_set_bit(unsigned int bit, volatile unsigned long *
p += bit >> 5;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
*p |= mask;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
}
static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long *p)
@@ -49,9 +49,9 @@ static inline void ____atomic_clear_bit(unsigned int bit, volatile unsigned long
p += bit >> 5;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
*p &= ~mask;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
}
static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned long *p)
@@ -61,9 +61,9 @@ static inline void ____atomic_change_bit(unsigned int bit, volatile unsigned lon
p += bit >> 5;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
*p ^= mask;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
}
static inline int
@@ -75,10 +75,10 @@ ____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p)
p += bit >> 5;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
res = *p;
*p = res | mask;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
return res & mask;
}
@@ -92,10 +92,10 @@ ____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p)
p += bit >> 5;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
res = *p;
*p = res & ~mask;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
return res & mask;
}
@@ -109,10 +109,10 @@ ____atomic_test_and_change_bit(unsigned int bit, volatile unsigned long *p)
p += bit >> 5;
- local_irq_save(flags);
+ raw_local_irq_save(flags);
res = *p;
*p = res ^ mask;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
return res & mask;
}
diff --git a/include/asm-arm/cacheflush.h b/include/asm-arm/cacheflush.h
index e4a2569c636c..f0845646aacb 100644
--- a/include/asm-arm/cacheflush.h
+++ b/include/asm-arm/cacheflush.h
@@ -25,7 +25,7 @@
#undef _CACHE
#undef MULTI_CACHE
-#if defined(CONFIG_CPU_ARM610) || defined(CONFIG_CPU_ARM710)
+#if defined(CONFIG_CPU_CACHE_V3)
# ifdef _CACHE
# define MULTI_CACHE 1
# else
@@ -33,7 +33,7 @@
# endif
#endif
-#if defined(CONFIG_CPU_ARM720T)
+#if defined(CONFIG_CPU_CACHE_V4)
# ifdef _CACHE
# define MULTI_CACHE 1
# else
@@ -54,7 +54,23 @@
# endif
#endif
-#if defined(CONFIG_CPU_SA110) || defined(CONFIG_CPU_SA1100)
+#if defined(CONFIG_CPU_ARM940T)
+# ifdef _CACHE
+# define MULTI_CACHE 1
+# else
+# define _CACHE arm940
+# endif
+#endif
+
+#if defined(CONFIG_CPU_ARM946E)
+# ifdef _CACHE
+# define MULTI_CACHE 1
+# else
+# define _CACHE arm946
+# endif
+#endif
+
+#if defined(CONFIG_CPU_CACHE_V4WB)
# ifdef _CACHE
# define MULTI_CACHE 1
# else
diff --git a/include/asm-arm/flat.h b/include/asm-arm/flat.h
new file mode 100644
index 000000000000..966946478589
--- /dev/null
+++ b/include/asm-arm/flat.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-arm/flat.h -- uClinux flat-format executables
+ */
+
+#ifndef __ARM_FLAT_H__
+#define __ARM_FLAT_H__
+
+#define flat_stack_align(sp) /* nothing needed */
+#define flat_argvp_envp_on_stack() 1
+#define flat_old_ram_flag(flags) (flags)
+#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
+#define flat_get_addr_from_rp(rp, relval, flags) get_unaligned(rp)
+#define flat_put_addr_at_rp(rp, val, relval) put_unaligned(val,rp)
+#define flat_get_relocate_addr(rel) (rel)
+
+#endif /* __ARM_FLAT_H__ */
diff --git a/include/asm-arm/hardware/debug-8250.S b/include/asm-arm/hardware/debug-8250.S
index 4594fea91ec1..07c97fb233fc 100644
--- a/include/asm-arm/hardware/debug-8250.S
+++ b/include/asm-arm/hardware/debug-8250.S
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/hardware/debug-8250.h
+ * linux/include/asm-arm/hardware/debug-8250.S
*
* Copyright (C) 1994-1999 Russell King
*
diff --git a/include/asm-arm/hardware/debug-pl01x.S b/include/asm-arm/hardware/debug-pl01x.S
index db0d0f7de5e9..23c541a9e89a 100644
--- a/include/asm-arm/hardware/debug-pl01x.S
+++ b/include/asm-arm/hardware/debug-pl01x.S
@@ -1,4 +1,4 @@
-/* linux/include/asm-arm/arch-integrator/debug-macro.S
+/* linux/include/asm-arm/hardware/debug-pl01x.S
*
* Debugging macro include header
*
diff --git a/include/asm-arm/hardware/entry-macro-iomd.S b/include/asm-arm/hardware/entry-macro-iomd.S
index 30c7b92c2416..fbed08f298d0 100644
--- a/include/asm-arm/hardware/entry-macro-iomd.S
+++ b/include/asm-arm/hardware/entry-macro-iomd.S
@@ -1,5 +1,5 @@
/*
- * arch/arm/commond/entry-macro-iomd.S
+ * include/asm-arm/hardware/entry-macro-iomd.S
*
* Low-level IRQ helper macros for IOC/IOMD based platforms
*
diff --git a/include/asm-arm/hardware/iop3xx.h b/include/asm-arm/hardware/iop3xx.h
new file mode 100644
index 000000000000..1018a7486ab7
--- /dev/null
+++ b/include/asm-arm/hardware/iop3xx.h
@@ -0,0 +1,301 @@
+/*
+ * include/asm-arm/hardware/iop3xx.h
+ *
+ * Intel IOP32X and IOP33X register definitions
+ *
+ * Author: Rory Bolt <rorybolt@pacbell.net>
+ * Copyright (C) 2002 Rory Bolt
+ * Copyright (C) 2004 Intel Corp.
+ *
+ * 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 __IOP3XX_H
+#define __IOP3XX_H
+
+/*
+ * IOP3XX GPIO handling
+ */
+#define GPIO_IN 0
+#define GPIO_OUT 1
+#define GPIO_LOW 0
+#define GPIO_HIGH 1
+#define IOP3XX_GPIO_LINE(x) (x)
+
+#ifndef __ASSEMBLY__
+extern void gpio_line_config(int line, int direction);
+extern int gpio_line_get(int line);
+extern void gpio_line_set(int line, int value);
+#endif
+
+
+/*
+ * IOP3XX processor registers
+ */
+#define IOP3XX_PERIPHERAL_PHYS_BASE 0xffffe000
+#define IOP3XX_PERIPHERAL_VIRT_BASE 0xfeffe000
+#define IOP3XX_PERIPHERAL_SIZE 0x00002000
+#define IOP3XX_REG_ADDR(reg) (IOP3XX_PERIPHERAL_VIRT_BASE + (reg))
+
+/* Address Translation Unit */
+#define IOP3XX_ATUVID (volatile u16 *)IOP3XX_REG_ADDR(0x0100)
+#define IOP3XX_ATUDID (volatile u16 *)IOP3XX_REG_ADDR(0x0102)
+#define IOP3XX_ATUCMD (volatile u16 *)IOP3XX_REG_ADDR(0x0104)
+#define IOP3XX_ATUSR (volatile u16 *)IOP3XX_REG_ADDR(0x0106)
+#define IOP3XX_ATURID (volatile u8 *)IOP3XX_REG_ADDR(0x0108)
+#define IOP3XX_ATUCCR (volatile u32 *)IOP3XX_REG_ADDR(0x0109)
+#define IOP3XX_ATUCLSR (volatile u8 *)IOP3XX_REG_ADDR(0x010c)
+#define IOP3XX_ATULT (volatile u8 *)IOP3XX_REG_ADDR(0x010d)
+#define IOP3XX_ATUHTR (volatile u8 *)IOP3XX_REG_ADDR(0x010e)
+#define IOP3XX_ATUBIST (volatile u8 *)IOP3XX_REG_ADDR(0x010f)
+#define IOP3XX_IABAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0110)
+#define IOP3XX_IAUBAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0114)
+#define IOP3XX_IABAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0118)
+#define IOP3XX_IAUBAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x011c)
+#define IOP3XX_IABAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0120)
+#define IOP3XX_IAUBAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0124)
+#define IOP3XX_ASVIR (volatile u16 *)IOP3XX_REG_ADDR(0x012c)
+#define IOP3XX_ASIR (volatile u16 *)IOP3XX_REG_ADDR(0x012e)
+#define IOP3XX_ERBAR (volatile u32 *)IOP3XX_REG_ADDR(0x0130)
+#define IOP3XX_ATUILR (volatile u8 *)IOP3XX_REG_ADDR(0x013c)
+#define IOP3XX_ATUIPR (volatile u8 *)IOP3XX_REG_ADDR(0x013d)
+#define IOP3XX_ATUMGNT (volatile u8 *)IOP3XX_REG_ADDR(0x013e)
+#define IOP3XX_ATUMLAT (volatile u8 *)IOP3XX_REG_ADDR(0x013f)
+#define IOP3XX_IALR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0140)
+#define IOP3XX_IATVR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0144)
+#define IOP3XX_ERLR (volatile u32 *)IOP3XX_REG_ADDR(0x0148)
+#define IOP3XX_ERTVR (volatile u32 *)IOP3XX_REG_ADDR(0x014c)
+#define IOP3XX_IALR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0150)
+#define IOP3XX_IALR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0154)
+#define IOP3XX_IATVR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0158)
+#define IOP3XX_OIOWTVR (volatile u32 *)IOP3XX_REG_ADDR(0x015c)
+#define IOP3XX_OMWTVR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0160)
+#define IOP3XX_OUMWTVR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0164)
+#define IOP3XX_OMWTVR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0168)
+#define IOP3XX_OUMWTVR1 (volatile u32 *)IOP3XX_REG_ADDR(0x016c)
+#define IOP3XX_OUDWTVR (volatile u32 *)IOP3XX_REG_ADDR(0x0178)
+#define IOP3XX_ATUCR (volatile u32 *)IOP3XX_REG_ADDR(0x0180)
+#define IOP3XX_PCSR (volatile u32 *)IOP3XX_REG_ADDR(0x0184)
+#define IOP3XX_ATUISR (volatile u32 *)IOP3XX_REG_ADDR(0x0188)
+#define IOP3XX_ATUIMR (volatile u32 *)IOP3XX_REG_ADDR(0x018c)
+#define IOP3XX_IABAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0190)
+#define IOP3XX_IAUBAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0194)
+#define IOP3XX_IALR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0198)
+#define IOP3XX_IATVR3 (volatile u32 *)IOP3XX_REG_ADDR(0x019c)
+#define IOP3XX_OCCAR (volatile u32 *)IOP3XX_REG_ADDR(0x01a4)
+#define IOP3XX_OCCDR (volatile u32 *)IOP3XX_REG_ADDR(0x01ac)
+#define IOP3XX_PDSCR (volatile u32 *)IOP3XX_REG_ADDR(0x01bc)
+#define IOP3XX_PMCAPID (volatile u8 *)IOP3XX_REG_ADDR(0x01c0)
+#define IOP3XX_PMNEXT (volatile u8 *)IOP3XX_REG_ADDR(0x01c1)
+#define IOP3XX_APMCR (volatile u16 *)IOP3XX_REG_ADDR(0x01c2)
+#define IOP3XX_APMCSR (volatile u16 *)IOP3XX_REG_ADDR(0x01c4)
+#define IOP3XX_PCIXCAPID (volatile u8 *)IOP3XX_REG_ADDR(0x01e0)
+#define IOP3XX_PCIXNEXT (volatile u8 *)IOP3XX_REG_ADDR(0x01e1)
+#define IOP3XX_PCIXCMD (volatile u16 *)IOP3XX_REG_ADDR(0x01e2)
+#define IOP3XX_PCIXSR (volatile u32 *)IOP3XX_REG_ADDR(0x01e4)
+#define IOP3XX_PCIIRSR (volatile u32 *)IOP3XX_REG_ADDR(0x01ec)
+
+/* Messaging Unit */
+#define IOP3XX_IMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0310)
+#define IOP3XX_IMR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0314)
+#define IOP3XX_OMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0318)
+#define IOP3XX_OMR1 (volatile u32 *)IOP3XX_REG_ADDR(0x031c)
+#define IOP3XX_IDR (volatile u32 *)IOP3XX_REG_ADDR(0x0320)
+#define IOP3XX_IISR (volatile u32 *)IOP3XX_REG_ADDR(0x0324)
+#define IOP3XX_IIMR (volatile u32 *)IOP3XX_REG_ADDR(0x0328)
+#define IOP3XX_ODR (volatile u32 *)IOP3XX_REG_ADDR(0x032c)
+#define IOP3XX_OISR (volatile u32 *)IOP3XX_REG_ADDR(0x0330)
+#define IOP3XX_OIMR (volatile u32 *)IOP3XX_REG_ADDR(0x0334)
+#define IOP3XX_MUCR (volatile u32 *)IOP3XX_REG_ADDR(0x0350)
+#define IOP3XX_QBAR (volatile u32 *)IOP3XX_REG_ADDR(0x0354)
+#define IOP3XX_IFHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0360)
+#define IOP3XX_IFTPR (volatile u32 *)IOP3XX_REG_ADDR(0x0364)
+#define IOP3XX_IPHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0368)
+#define IOP3XX_IPTPR (volatile u32 *)IOP3XX_REG_ADDR(0x036c)
+#define IOP3XX_OFHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0370)
+#define IOP3XX_OFTPR (volatile u32 *)IOP3XX_REG_ADDR(0x0374)
+#define IOP3XX_OPHPR (volatile u32 *)IOP3XX_REG_ADDR(0x0378)
+#define IOP3XX_OPTPR (volatile u32 *)IOP3XX_REG_ADDR(0x037c)
+#define IOP3XX_IAR (volatile u32 *)IOP3XX_REG_ADDR(0x0380)
+
+/* DMA Controller */
+#define IOP3XX_DMA0_CCR (volatile u32 *)IOP3XX_REG_ADDR(0x0400)
+#define IOP3XX_DMA0_CSR (volatile u32 *)IOP3XX_REG_ADDR(0x0404)
+#define IOP3XX_DMA0_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x040c)
+#define IOP3XX_DMA0_NDAR (volatile u32 *)IOP3XX_REG_ADDR(0x0410)
+#define IOP3XX_DMA0_PADR (volatile u32 *)IOP3XX_REG_ADDR(0x0414)
+#define IOP3XX_DMA0_PUADR (volatile u32 *)IOP3XX_REG_ADDR(0x0418)
+#define IOP3XX_DMA0_LADR (volatile u32 *)IOP3XX_REG_ADDR(0x041c)
+#define IOP3XX_DMA0_BCR (volatile u32 *)IOP3XX_REG_ADDR(0x0420)
+#define IOP3XX_DMA0_DCR (volatile u32 *)IOP3XX_REG_ADDR(0x0424)
+#define IOP3XX_DMA1_CCR (volatile u32 *)IOP3XX_REG_ADDR(0x0440)
+#define IOP3XX_DMA1_CSR (volatile u32 *)IOP3XX_REG_ADDR(0x0444)
+#define IOP3XX_DMA1_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x044c)
+#define IOP3XX_DMA1_NDAR (volatile u32 *)IOP3XX_REG_ADDR(0x0450)
+#define IOP3XX_DMA1_PADR (volatile u32 *)IOP3XX_REG_ADDR(0x0454)
+#define IOP3XX_DMA1_PUADR (volatile u32 *)IOP3XX_REG_ADDR(0x0458)
+#define IOP3XX_DMA1_LADR (volatile u32 *)IOP3XX_REG_ADDR(0x045c)
+#define IOP3XX_DMA1_BCR (volatile u32 *)IOP3XX_REG_ADDR(0x0460)
+#define IOP3XX_DMA1_DCR (volatile u32 *)IOP3XX_REG_ADDR(0x0464)
+
+/* Peripheral bus interface */
+#define IOP3XX_PBCR (volatile u32 *)IOP3XX_REG_ADDR(0x0680)
+#define IOP3XX_PBISR (volatile u32 *)IOP3XX_REG_ADDR(0x0684)
+#define IOP3XX_PBBAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0688)
+#define IOP3XX_PBLR0 (volatile u32 *)IOP3XX_REG_ADDR(0x068c)
+#define IOP3XX_PBBAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0690)
+#define IOP3XX_PBLR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0694)
+#define IOP3XX_PBBAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0698)
+#define IOP3XX_PBLR2 (volatile u32 *)IOP3XX_REG_ADDR(0x069c)
+#define IOP3XX_PBBAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x06a0)
+#define IOP3XX_PBLR3 (volatile u32 *)IOP3XX_REG_ADDR(0x06a4)
+#define IOP3XX_PBBAR4 (volatile u32 *)IOP3XX_REG_ADDR(0x06a8)
+#define IOP3XX_PBLR4 (volatile u32 *)IOP3XX_REG_ADDR(0x06ac)
+#define IOP3XX_PBBAR5 (volatile u32 *)IOP3XX_REG_ADDR(0x06b0)
+#define IOP3XX_PBLR5 (volatile u32 *)IOP3XX_REG_ADDR(0x06b4)
+#define IOP3XX_PMBR0 (volatile u32 *)IOP3XX_REG_ADDR(0x06c0)
+#define IOP3XX_PMBR1 (volatile u32 *)IOP3XX_REG_ADDR(0x06e0)
+#define IOP3XX_PMBR2 (volatile u32 *)IOP3XX_REG_ADDR(0x06e4)
+
+/* Peripheral performance monitoring unit */
+#define IOP3XX_GTMR (volatile u32 *)IOP3XX_REG_ADDR(0x0700)
+#define IOP3XX_ESR (volatile u32 *)IOP3XX_REG_ADDR(0x0704)
+#define IOP3XX_EMISR (volatile u32 *)IOP3XX_REG_ADDR(0x0708)
+#define IOP3XX_GTSR (volatile u32 *)IOP3XX_REG_ADDR(0x0710)
+/* PERCR0 DOESN'T EXIST - index from 1! */
+#define IOP3XX_PERCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x0710)
+
+/* General Purpose I/O */
+#define IOP3XX_GPOE (volatile u32 *)IOP3XX_GPIO_REG(0x0004)
+#define IOP3XX_GPID (volatile u32 *)IOP3XX_GPIO_REG(0x0008)
+#define IOP3XX_GPOD (volatile u32 *)IOP3XX_GPIO_REG(0x000c)
+
+/* Timers */
+#define IOP3XX_TU_TMR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0000)
+#define IOP3XX_TU_TMR1 (volatile u32 *)IOP3XX_TIMER_REG(0x0004)
+#define IOP3XX_TU_TCR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0008)
+#define IOP3XX_TU_TCR1 (volatile u32 *)IOP3XX_TIMER_REG(0x000c)
+#define IOP3XX_TU_TRR0 (volatile u32 *)IOP3XX_TIMER_REG(0x0010)
+#define IOP3XX_TU_TRR1 (volatile u32 *)IOP3XX_TIMER_REG(0x0014)
+#define IOP3XX_TU_TISR (volatile u32 *)IOP3XX_TIMER_REG(0x0018)
+#define IOP3XX_TU_WDTCR (volatile u32 *)IOP3XX_TIMER_REG(0x001c)
+#define IOP3XX_TMR_TC 0x01
+#define IOP3XX_TMR_EN 0x02
+#define IOP3XX_TMR_RELOAD 0x04
+#define IOP3XX_TMR_PRIVILEGED 0x09
+#define IOP3XX_TMR_RATIO_1_1 0x00
+#define IOP3XX_TMR_RATIO_4_1 0x10
+#define IOP3XX_TMR_RATIO_8_1 0x20
+#define IOP3XX_TMR_RATIO_16_1 0x30
+
+/* Application accelerator unit */
+#define IOP3XX_AAU_ACR (volatile u32 *)IOP3XX_REG_ADDR(0x0800)
+#define IOP3XX_AAU_ASR (volatile u32 *)IOP3XX_REG_ADDR(0x0804)
+#define IOP3XX_AAU_ADAR (volatile u32 *)IOP3XX_REG_ADDR(0x0808)
+#define IOP3XX_AAU_ANDAR (volatile u32 *)IOP3XX_REG_ADDR(0x080c)
+#define IOP3XX_AAU_SAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0810)
+#define IOP3XX_AAU_SAR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0814)
+#define IOP3XX_AAU_SAR3 (volatile u32 *)IOP3XX_REG_ADDR(0x0818)
+#define IOP3XX_AAU_SAR4 (volatile u32 *)IOP3XX_REG_ADDR(0x081c)
+#define IOP3XX_AAU_DAR (volatile u32 *)IOP3XX_REG_ADDR(0x0820)
+#define IOP3XX_AAU_ABCR (volatile u32 *)IOP3XX_REG_ADDR(0x0824)
+#define IOP3XX_AAU_ADCR (volatile u32 *)IOP3XX_REG_ADDR(0x0828)
+#define IOP3XX_AAU_SAR5 (volatile u32 *)IOP3XX_REG_ADDR(0x082c)
+#define IOP3XX_AAU_SAR6 (volatile u32 *)IOP3XX_REG_ADDR(0x0830)
+#define IOP3XX_AAU_SAR7 (volatile u32 *)IOP3XX_REG_ADDR(0x0834)
+#define IOP3XX_AAU_SAR8 (volatile u32 *)IOP3XX_REG_ADDR(0x0838)
+#define IOP3XX_AAU_EDCR0 (volatile u32 *)IOP3XX_REG_ADDR(0x083c)
+#define IOP3XX_AAU_SAR9 (volatile u32 *)IOP3XX_REG_ADDR(0x0840)
+#define IOP3XX_AAU_SAR10 (volatile u32 *)IOP3XX_REG_ADDR(0x0844)
+#define IOP3XX_AAU_SAR11 (volatile u32 *)IOP3XX_REG_ADDR(0x0848)
+#define IOP3XX_AAU_SAR12 (volatile u32 *)IOP3XX_REG_ADDR(0x084c)
+#define IOP3XX_AAU_SAR13 (volatile u32 *)IOP3XX_REG_ADDR(0x0850)
+#define IOP3XX_AAU_SAR14 (volatile u32 *)IOP3XX_REG_ADDR(0x0854)
+#define IOP3XX_AAU_SAR15 (volatile u32 *)IOP3XX_REG_ADDR(0x0858)
+#define IOP3XX_AAU_SAR16 (volatile u32 *)IOP3XX_REG_ADDR(0x085c)
+#define IOP3XX_AAU_EDCR1 (volatile u32 *)IOP3XX_REG_ADDR(0x0860)
+#define IOP3XX_AAU_SAR17 (volatile u32 *)IOP3XX_REG_ADDR(0x0864)
+#define IOP3XX_AAU_SAR18 (volatile u32 *)IOP3XX_REG_ADDR(0x0868)
+#define IOP3XX_AAU_SAR19 (volatile u32 *)IOP3XX_REG_ADDR(0x086c)
+#define IOP3XX_AAU_SAR20 (volatile u32 *)IOP3XX_REG_ADDR(0x0870)
+#define IOP3XX_AAU_SAR21 (volatile u32 *)IOP3XX_REG_ADDR(0x0874)
+#define IOP3XX_AAU_SAR22 (volatile u32 *)IOP3XX_REG_ADDR(0x0878)
+#define IOP3XX_AAU_SAR23 (volatile u32 *)IOP3XX_REG_ADDR(0x087c)
+#define IOP3XX_AAU_SAR24 (volatile u32 *)IOP3XX_REG_ADDR(0x0880)
+#define IOP3XX_AAU_EDCR2 (volatile u32 *)IOP3XX_REG_ADDR(0x0884)
+#define IOP3XX_AAU_SAR25 (volatile u32 *)IOP3XX_REG_ADDR(0x0888)
+#define IOP3XX_AAU_SAR26 (volatile u32 *)IOP3XX_REG_ADDR(0x088c)
+#define IOP3XX_AAU_SAR27 (volatile u32 *)IOP3XX_REG_ADDR(0x0890)
+#define IOP3XX_AAU_SAR28 (volatile u32 *)IOP3XX_REG_ADDR(0x0894)
+#define IOP3XX_AAU_SAR29 (volatile u32 *)IOP3XX_REG_ADDR(0x0898)
+#define IOP3XX_AAU_SAR30 (volatile u32 *)IOP3XX_REG_ADDR(0x089c)
+#define IOP3XX_AAU_SAR31 (volatile u32 *)IOP3XX_REG_ADDR(0x08a0)
+#define IOP3XX_AAU_SAR32 (volatile u32 *)IOP3XX_REG_ADDR(0x08a4)
+
+/* I2C bus interface unit */
+#define IOP3XX_ICR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1680)
+#define IOP3XX_ISR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1684)
+#define IOP3XX_ISAR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1688)
+#define IOP3XX_IDBR0 (volatile u32 *)IOP3XX_REG_ADDR(0x168c)
+#define IOP3XX_IBMR0 (volatile u32 *)IOP3XX_REG_ADDR(0x1694)
+#define IOP3XX_ICR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16a0)
+#define IOP3XX_ISR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16a4)
+#define IOP3XX_ISAR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16a8)
+#define IOP3XX_IDBR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16ac)
+#define IOP3XX_IBMR1 (volatile u32 *)IOP3XX_REG_ADDR(0x16b4)
+
+
+/*
+ * IOP3XX I/O and Mem space regions for PCI autoconfiguration
+ */
+#define IOP3XX_PCI_MEM_WINDOW_SIZE 0x04000000
+#define IOP3XX_PCI_LOWER_MEM_PA 0x80000000
+#define IOP3XX_PCI_LOWER_MEM_BA (*IOP3XX_OMWTVR0)
+
+#define IOP3XX_PCI_IO_WINDOW_SIZE 0x00010000
+#define IOP3XX_PCI_LOWER_IO_PA 0x90000000
+#define IOP3XX_PCI_LOWER_IO_VA 0xfe000000
+#define IOP3XX_PCI_LOWER_IO_BA (*IOP3XX_OIOWTVR)
+
+
+#ifndef __ASSEMBLY__
+void iop3xx_map_io(void);
+void iop3xx_init_time(unsigned long);
+unsigned long iop3xx_gettimeoffset(void);
+
+extern struct platform_device iop3xx_i2c0_device;
+extern struct platform_device iop3xx_i2c1_device;
+
+extern inline void iop3xx_cp6_enable(void)
+{
+ u32 temp;
+
+ asm volatile (
+ "mrc p15, 0, %0, c15, c1, 0\n\t"
+ "orr %0, %0, #(1 << 6)\n\t"
+ "mcr p15, 0, %0, c15, c1, 0\n\t"
+ "mrc p15, 0, %0, c15, c1, 0\n\t"
+ "mov %0, %0\n\t"
+ "sub pc, pc, #4\n\t"
+ : "=r" (temp) );
+}
+
+extern inline void iop3xx_cp6_disable(void)
+{
+ u32 temp;
+
+ asm volatile (
+ "mrc p15, 0, %0, c15, c1, 0\n\t"
+ "bic %0, %0, #(1 << 6)\n\t"
+ "mcr p15, 0, %0, c15, c1, 0\n\t"
+ "mrc p15, 0, %0, c15, c1, 0\n\t"
+ "mov %0, %0\n\t"
+ "sub pc, pc, #4\n\t"
+ : "=r" (temp) );
+}
+#endif
+
+
+#endif
diff --git a/include/asm-arm/hardware/locomo.h b/include/asm-arm/hardware/locomo.h
index 22dfb1737768..adab77780ed3 100644
--- a/include/asm-arm/hardware/locomo.h
+++ b/include/asm-arm/hardware/locomo.h
@@ -54,17 +54,18 @@
#define LOCOMO_DAC_SDAOEB 0x01 /* SDA pin output data */
/* SPI interface */
-#define LOCOMO_SPIMD 0x60 /* SPI mode setting */
-#define LOCOMO_SPICT 0x64 /* SPI mode control */
-#define LOCOMO_SPIST 0x68 /* SPI status */
-#define LOCOMO_SPIIS 0x70 /* SPI interrupt status */
-#define LOCOMO_SPIWE 0x74 /* SPI interrupt status write enable */
-#define LOCOMO_SPIIE 0x78 /* SPI interrupt enable */
-#define LOCOMO_SPIIR 0x7c /* SPI interrupt request */
-#define LOCOMO_SPITD 0x80 /* SPI transfer data write */
-#define LOCOMO_SPIRD 0x84 /* SPI receive data read */
-#define LOCOMO_SPITS 0x88 /* SPI transfer data shift */
-#define LOCOMO_SPIRS 0x8C /* SPI receive data shift */
+#define LOCOMO_SPI 0x60
+#define LOCOMO_SPIMD 0x00 /* SPI mode setting */
+#define LOCOMO_SPICT 0x04 /* SPI mode control */
+#define LOCOMO_SPIST 0x08 /* SPI status */
+#define LOCOMO_SPIIS 0x10 /* SPI interrupt status */
+#define LOCOMO_SPIWE 0x14 /* SPI interrupt status write enable */
+#define LOCOMO_SPIIE 0x18 /* SPI interrupt enable */
+#define LOCOMO_SPIIR 0x1c /* SPI interrupt request */
+#define LOCOMO_SPITD 0x20 /* SPI transfer data write */
+#define LOCOMO_SPIRD 0x24 /* SPI receive data read */
+#define LOCOMO_SPITS 0x28 /* SPI transfer data shift */
+#define LOCOMO_SPIRS 0x2C /* SPI receive data shift */
#define LOCOMO_SPI_TEND (1 << 3) /* Transfer end bit */
#define LOCOMO_SPI_OVRN (1 << 2) /* Over Run bit */
#define LOCOMO_SPI_RFW (1 << 1) /* write buffer bit */
@@ -161,6 +162,7 @@ extern struct bus_type locomo_bus_type;
#define LOCOMO_DEVID_AUDIO 3
#define LOCOMO_DEVID_LED 4
#define LOCOMO_DEVID_UART 5
+#define LOCOMO_DEVID_SPI 6
struct locomo_dev {
struct device dev;
@@ -197,10 +199,11 @@ int locomo_driver_register(struct locomo_driver *);
void locomo_driver_unregister(struct locomo_driver *);
/* GPIO control functions */
-void locomo_gpio_set_dir(struct locomo_dev *ldev, unsigned int bits, unsigned int dir);
-unsigned int locomo_gpio_read_level(struct locomo_dev *ldev, unsigned int bits);
-unsigned int locomo_gpio_read_output(struct locomo_dev *ldev, unsigned int bits);
-void locomo_gpio_write(struct locomo_dev *ldev, unsigned int bits, unsigned int set);
+void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir);
+int locomo_gpio_read_level(struct device *dev, unsigned int bits);
+int locomo_gpio_read_output(struct device *dev, unsigned int bits);
+void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set);
+
/* M62332 control function */
void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel);
diff --git a/include/asm-arm/hardware/sa1111.h b/include/asm-arm/hardware/sa1111.h
index 319aea064c36..6aa0a5b75b69 100644
--- a/include/asm-arm/hardware/sa1111.h
+++ b/include/asm-arm/hardware/sa1111.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/hardware/SA-1111.h
+ * linux/include/asm-arm/hardware/sa1111.h
*
* Copyright (C) 2000 John G Dorsey <john+@cs.cmu.edu>
*
diff --git a/include/asm-arm/hardware/sharpsl_pm.h b/include/asm-arm/hardware/sharpsl_pm.h
index ecf15b83956f..2d00db22b981 100644
--- a/include/asm-arm/hardware/sharpsl_pm.h
+++ b/include/asm-arm/hardware/sharpsl_pm.h
@@ -25,6 +25,7 @@ struct sharpsl_charger_machinfo {
void (*measure_temp)(int);
void (*presuspend)(void);
void (*postsuspend)(void);
+ void (*earlyresume)(void);
unsigned long (*read_devdata)(int);
#define SHARPSL_BATT_VOLT 1
#define SHARPSL_BATT_TEMP 2
@@ -99,7 +100,7 @@ extern struct sharpsl_pm_status sharpsl_pm;
void sharpsl_battery_kick(void);
void sharpsl_pm_led(int val);
-irqreturn_t sharpsl_ac_isr(int irq, void *dev_id, struct pt_regs *fp);
-irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id, struct pt_regs *fp);
-irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id, struct pt_regs *fp);
+irqreturn_t sharpsl_ac_isr(int irq, void *dev_id);
+irqreturn_t sharpsl_chrg_full_isr(int irq, void *dev_id);
+irqreturn_t sharpsl_fatal_isr(int irq, void *dev_id);
diff --git a/include/asm-arm/hw_irq.h b/include/asm-arm/hw_irq.h
index ea856971989a..98d594a973d6 100644
--- a/include/asm-arm/hw_irq.h
+++ b/include/asm-arm/hw_irq.h
@@ -12,7 +12,7 @@
if (!(action->flags & IRQF_TIMER) && system_timer->dyn_tick) { \
write_seqlock(&xtime_lock); \
if (system_timer->dyn_tick->state & DYN_TICK_ENABLED) \
- system_timer->dyn_tick->handler(irq, 0, regs); \
+ system_timer->dyn_tick->handler(irq, NULL); \
write_sequnlock(&xtime_lock); \
}
#endif
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index bf7b9dea30f1..ae999fd5dc67 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -63,7 +63,7 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
*/
extern void __iomem * __ioremap_pfn(unsigned long, unsigned long, size_t, unsigned long);
extern void __iomem * __ioremap(unsigned long, size_t, unsigned long);
-extern void __iounmap(void __iomem *addr);
+extern void __iounmap(volatile void __iomem *addr);
/*
* Bad read/write accesses...
@@ -193,23 +193,6 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define eth_io_copy_and_sum(s,c,l,b) \
eth_copy_and_sum((s),__mem_pci(c),(l),(b))
-static inline int
-check_signature(void __iomem *io_addr, const unsigned char *signature,
- int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
#elif !defined(readb)
#define readb(c) (__readwrite_bug("readb"),0)
@@ -280,6 +263,10 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
#define BIOVEC_MERGEABLE(vec1, vec2) \
((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2)))
+#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
+extern int valid_phys_addr_range(unsigned long addr, size_t size);
+extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
* access
diff --git a/include/asm-arm/irq_regs.h b/include/asm-arm/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-arm/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-arm/irqflags.h b/include/asm-arm/irqflags.h
new file mode 100644
index 000000000000..6d09974e6646
--- /dev/null
+++ b/include/asm-arm/irqflags.h
@@ -0,0 +1,132 @@
+#ifndef __ASM_ARM_IRQFLAGS_H
+#define __ASM_ARM_IRQFLAGS_H
+
+#ifdef __KERNEL__
+
+#include <asm/ptrace.h>
+
+/*
+ * CPU interrupt mask handling.
+ */
+#if __LINUX_ARM_ARCH__ >= 6
+
+#define raw_local_irq_save(x) \
+ ({ \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_save\n" \
+ "cpsid i" \
+ : "=r" (x) : : "memory", "cc"); \
+ })
+
+#define raw_local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc")
+#define raw_local_irq_disable() __asm__("cpsid i @ __cli" : : : "memory", "cc")
+#define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc")
+#define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc")
+
+#else
+
+/*
+ * Save the current interrupt enable state & disable IRQs
+ */
+#define raw_local_irq_save(x) \
+ ({ \
+ unsigned long temp; \
+ (void) (&temp == &x); \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_save\n" \
+" orr %1, %0, #128\n" \
+" msr cpsr_c, %1" \
+ : "=r" (x), "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Enable IRQs
+ */
+#define raw_local_irq_enable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_enable\n" \
+" bic %0, %0, #128\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Disable IRQs
+ */
+#define raw_local_irq_disable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_irq_disable\n" \
+" orr %0, %0, #128\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Enable FIQs
+ */
+#define local_fiq_enable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ stf\n" \
+" bic %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+/*
+ * Disable FIQs
+ */
+#define local_fiq_disable() \
+ ({ \
+ unsigned long temp; \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ clf\n" \
+" orr %0, %0, #64\n" \
+" msr cpsr_c, %0" \
+ : "=r" (temp) \
+ : \
+ : "memory", "cc"); \
+ })
+
+#endif
+
+/*
+ * Save the current interrupt enable state.
+ */
+#define raw_local_save_flags(x) \
+ ({ \
+ __asm__ __volatile__( \
+ "mrs %0, cpsr @ local_save_flags" \
+ : "=r" (x) : : "memory", "cc"); \
+ })
+
+/*
+ * restore saved IRQ & FIQ state
+ */
+#define raw_local_irq_restore(x) \
+ __asm__ __volatile__( \
+ "msr cpsr_c, %0 @ local_irq_restore\n" \
+ : \
+ : "r" (x) \
+ : "memory", "cc")
+
+#define raw_irqs_disabled_flags(flags) \
+({ \
+ (int)((flags) & PSR_I_BIT); \
+})
+
+#endif
+#endif
diff --git a/include/asm-arm/mach/irq.h b/include/asm-arm/mach/irq.h
index 131f33733d25..0e017ecf2096 100644
--- a/include/asm-arm/mach/irq.h
+++ b/include/asm-arm/mach/irq.h
@@ -30,10 +30,9 @@ extern int show_fiq_list(struct seq_file *, void *);
/*
* Obsolete inline function for calling irq descriptor handlers.
*/
-static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc)
{
- desc->handle_irq(irq, desc, regs);
+ desc->handle_irq(irq, desc);
}
void set_irq_flags(unsigned int irq, unsigned int flags);
@@ -51,10 +50,10 @@ void set_irq_flags(unsigned int irq, unsigned int flags);
#define irqdesc irq_desc
#define irqchip irq_chip
-#define do_bad_IRQ(irq,desc,regs) \
+#define do_bad_IRQ(irq,desc) \
do { \
spin_lock(&desc->lock); \
- handle_bad_irq(irq, desc, regs); \
+ handle_bad_irq(irq, desc); \
spin_unlock(&desc->lock); \
} while(0)
diff --git a/include/asm-arm/mach/pci.h b/include/asm-arm/mach/pci.h
index 923e0ca66200..24621c49a0c7 100644
--- a/include/asm-arm/mach/pci.h
+++ b/include/asm-arm/mach/pci.h
@@ -52,13 +52,9 @@ void pci_common_init(struct hw_pci *);
/*
* PCI controllers
*/
-extern int iop321_setup(int nr, struct pci_sys_data *);
-extern struct pci_bus *iop321_scan_bus(int nr, struct pci_sys_data *);
-extern void iop321_init(void);
-
-extern int iop331_setup(int nr, struct pci_sys_data *);
-extern struct pci_bus *iop331_scan_bus(int nr, struct pci_sys_data *);
-extern void iop331_init(void);
+extern int iop3xx_pci_setup(int nr, struct pci_sys_data *);
+extern struct pci_bus *iop3xx_pci_scan_bus(int nr, struct pci_sys_data *);
+extern void iop3xx_pci_preinit(void);
extern int dc21285_setup(int nr, struct pci_sys_data *);
extern struct pci_bus *dc21285_scan_bus(int nr, struct pci_sys_data *);
diff --git a/include/asm-arm/mach/serial_at91.h b/include/asm-arm/mach/serial_at91.h
index 1290bb32802d..55b317a89061 100644
--- a/include/asm-arm/mach/serial_at91.h
+++ b/include/asm-arm/mach/serial_at91.h
@@ -14,7 +14,7 @@ struct uart_port;
* This is a temporary structure for registering these
* functions; it is intended to be discarded after boot.
*/
-struct at91_port_fns {
+struct atmel_port_fns {
void (*set_mctrl)(struct uart_port *, u_int);
u_int (*get_mctrl)(struct uart_port *);
void (*enable_ms)(struct uart_port *);
@@ -24,10 +24,10 @@ struct at91_port_fns {
void (*close)(struct uart_port *);
};
-#if defined(CONFIG_SERIAL_AT91)
-void at91_register_uart_fns(struct at91_port_fns *fns);
+#if defined(CONFIG_SERIAL_ATMEL)
+void atmel_register_uart_fns(struct atmel_port_fns *fns);
#else
-#define at91_register_uart_fns(fns) do { } while (0)
+#define atmel_register_uart_fns(fns) do { } while (0)
#endif
diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h
index dee0bc336fe8..5dc357013b79 100644
--- a/include/asm-arm/mach/time.h
+++ b/include/asm-arm/mach/time.h
@@ -38,7 +38,9 @@ struct sys_timer {
void (*init)(void);
void (*suspend)(void);
void (*resume)(void);
+#ifndef CONFIG_GENERIC_TIME
unsigned long (*offset)(void);
+#endif
#ifdef CONFIG_NO_IDLE_HZ
struct dyn_tick_timer *dyn_tick;
@@ -55,7 +57,7 @@ struct dyn_tick_timer {
int (*enable)(void); /* Enables dynamic tick */
int (*disable)(void); /* Disables dynamic tick */
void (*reprogram)(unsigned long); /* Reprograms the timer */
- int (*handler)(int, void *, struct pt_regs *);
+ int (*handler)(int, void *);
};
void timer_dyn_reprogram(void);
@@ -64,7 +66,7 @@ void timer_dyn_reprogram(void);
#endif
extern struct sys_timer *system_timer;
-extern void timer_tick(struct pt_regs *);
+extern void timer_tick(void);
/*
* Kernel time keeping support.
diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h
index 02bd3ee935b0..7e85db77d99b 100644
--- a/include/asm-arm/page.h
+++ b/include/asm-arm/page.h
@@ -174,9 +174,6 @@ typedef unsigned long pgprot_t;
#endif /* STRICT_MM_TYPECHECKS */
-/* the upper-most page table pointer */
-extern pmd_t *top_pmd;
-
#endif /* CONFIG_MMU */
#include <asm/memory.h>
diff --git a/include/asm-arm/pgtable-nommu.h b/include/asm-arm/pgtable-nommu.h
index b13322dccf41..c1b264dff287 100644
--- a/include/asm-arm/pgtable-nommu.h
+++ b/include/asm-arm/pgtable-nommu.h
@@ -13,7 +13,6 @@
#ifndef __ASSEMBLY__
-#include <linux/config.h>
#include <linux/slab.h>
#include <asm/processor.h>
#include <asm/page.h>
diff --git a/include/asm-arm/pgtable.h b/include/asm-arm/pgtable.h
index 4d10d319fa34..ed8cb5963e99 100644
--- a/include/asm-arm/pgtable.h
+++ b/include/asm-arm/pgtable.h
@@ -136,6 +136,13 @@ extern void __pgd_error(const char *file, int line, unsigned long val);
#define USER_PTRS_PER_PGD ((TASK_SIZE/PGDIR_SIZE) - FIRST_USER_PGD_NR)
/*
+ * section address mask and size definitions.
+ */
+#define SECTION_SHIFT 20
+#define SECTION_SIZE (1UL << SECTION_SHIFT)
+#define SECTION_MASK (~(SECTION_SIZE-1))
+
+/*
* ARMv6 supersection address mask and size definitions.
*/
#define SUPERSECTION_SHIFT 24
diff --git a/include/asm-arm/proc-fns.h b/include/asm-arm/proc-fns.h
index 1bde92cdaebd..ea7e54c319be 100644
--- a/include/asm-arm/proc-fns.h
+++ b/include/asm-arm/proc-fns.h
@@ -33,6 +33,14 @@
# define CPU_NAME cpu_arm6
# endif
# endif
+# ifdef CONFIG_CPU_ARM7TDMI
+# ifdef CPU_NAME
+# undef MULTI_CPU
+# define MULTI_CPU
+# else
+# define CPU_NAME cpu_arm7tdmi
+# endif
+# endif
# ifdef CONFIG_CPU_ARM710
# ifdef CPU_NAME
# undef MULTI_CPU
@@ -49,6 +57,22 @@
# define CPU_NAME cpu_arm720
# endif
# endif
+# ifdef CONFIG_CPU_ARM740T
+# ifdef CPU_NAME
+# undef MULTI_CPU
+# define MULTI_CPU
+# else
+# define CPU_NAME cpu_arm740
+# endif
+# endif
+# ifdef CONFIG_CPU_ARM9TDMI
+# ifdef CPU_NAME
+# undef MULTI_CPU
+# define MULTI_CPU
+# else
+# define CPU_NAME cpu_arm9tdmi
+# endif
+# endif
# ifdef CONFIG_CPU_ARM920T
# ifdef CPU_NAME
# undef MULTI_CPU
@@ -81,6 +105,22 @@
# define CPU_NAME cpu_arm926
# endif
# endif
+# ifdef CONFIG_CPU_ARM940T
+# ifdef CPU_NAME
+# undef MULTI_CPU
+# define MULTI_CPU
+# else
+# define CPU_NAME cpu_arm940
+# endif
+# endif
+# ifdef CONFIG_CPU_ARM946E
+# ifdef CPU_NAME
+# undef MULTI_CPU
+# define MULTI_CPU
+# else
+# define CPU_NAME cpu_arm946
+# endif
+# endif
# ifdef CONFIG_CPU_SA110
# ifdef CPU_NAME
# undef MULTI_CPU
diff --git a/include/asm-arm/setup.h b/include/asm-arm/setup.h
index ea3ed2465233..aa4b5782f0c9 100644
--- a/include/asm-arm/setup.h
+++ b/include/asm-arm/setup.h
@@ -194,13 +194,15 @@ static struct tagtable __tagtable_##fn __tag = { tag, fn }
# define NR_BANKS 8
#endif
+struct membank {
+ unsigned long start;
+ unsigned long size;
+ int node;
+};
+
struct meminfo {
int nr_banks;
- struct {
- unsigned long start;
- unsigned long size;
- int node;
- } bank[NR_BANKS];
+ struct membank bank[NR_BANKS];
};
/*
diff --git a/include/asm-arm/spinlock.h b/include/asm-arm/spinlock.h
index 01b7c26a3038..861092fbaa53 100644
--- a/include/asm-arm/spinlock.h
+++ b/include/asm-arm/spinlock.h
@@ -218,4 +218,8 @@ static inline int __raw_read_trylock(raw_rwlock_t *rw)
/* read_can_lock - would read_trylock() succeed? */
#define __raw_read_can_lock(x) ((x)->lock < 0x80000000)
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 0947cbf9b69a..f05fbe31576c 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -46,6 +46,7 @@
#define CPUID_TCM 2
#define CPUID_TLBTYPE 3
+#ifdef CONFIG_CPU_CP15
#define read_cpuid(reg) \
({ \
unsigned int __val; \
@@ -55,6 +56,9 @@
: "cc"); \
__val; \
})
+#else
+#define read_cpuid(reg) (processor_id)
+#endif
/*
* This is used to ensure the compiler did actually allocate the register we
@@ -207,130 +211,7 @@ static inline void sched_cacheflush(void)
{
}
-/*
- * CPU interrupt mask handling.
- */
-#if __LINUX_ARM_ARCH__ >= 6
-
-#define local_irq_save(x) \
- ({ \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ local_irq_save\n" \
- "cpsid i" \
- : "=r" (x) : : "memory", "cc"); \
- })
-
-#define local_irq_enable() __asm__("cpsie i @ __sti" : : : "memory", "cc")
-#define local_irq_disable() __asm__("cpsid i @ __cli" : : : "memory", "cc")
-#define local_fiq_enable() __asm__("cpsie f @ __stf" : : : "memory", "cc")
-#define local_fiq_disable() __asm__("cpsid f @ __clf" : : : "memory", "cc")
-
-#else
-
-/*
- * Save the current interrupt enable state & disable IRQs
- */
-#define local_irq_save(x) \
- ({ \
- unsigned long temp; \
- (void) (&temp == &x); \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ local_irq_save\n" \
-" orr %1, %0, #128\n" \
-" msr cpsr_c, %1" \
- : "=r" (x), "=r" (temp) \
- : \
- : "memory", "cc"); \
- })
-
-/*
- * Enable IRQs
- */
-#define local_irq_enable() \
- ({ \
- unsigned long temp; \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ local_irq_enable\n" \
-" bic %0, %0, #128\n" \
-" msr cpsr_c, %0" \
- : "=r" (temp) \
- : \
- : "memory", "cc"); \
- })
-
-/*
- * Disable IRQs
- */
-#define local_irq_disable() \
- ({ \
- unsigned long temp; \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ local_irq_disable\n" \
-" orr %0, %0, #128\n" \
-" msr cpsr_c, %0" \
- : "=r" (temp) \
- : \
- : "memory", "cc"); \
- })
-
-/*
- * Enable FIQs
- */
-#define local_fiq_enable() \
- ({ \
- unsigned long temp; \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ stf\n" \
-" bic %0, %0, #64\n" \
-" msr cpsr_c, %0" \
- : "=r" (temp) \
- : \
- : "memory", "cc"); \
- })
-
-/*
- * Disable FIQs
- */
-#define local_fiq_disable() \
- ({ \
- unsigned long temp; \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ clf\n" \
-" orr %0, %0, #64\n" \
-" msr cpsr_c, %0" \
- : "=r" (temp) \
- : \
- : "memory", "cc"); \
- })
-
-#endif
-
-/*
- * Save the current interrupt enable state.
- */
-#define local_save_flags(x) \
- ({ \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ local_save_flags" \
- : "=r" (x) : : "memory", "cc"); \
- })
-
-/*
- * restore saved IRQ & FIQ state
- */
-#define local_irq_restore(x) \
- __asm__ __volatile__( \
- "msr cpsr_c, %0 @ local_irq_restore\n" \
- : \
- : "r" (x) \
- : "memory", "cc")
-
-#define irqs_disabled() \
-({ \
- unsigned long flags; \
- local_save_flags(flags); \
- (int)(flags & PSR_I_BIT); \
-})
+#include <linux/irqflags.h>
#ifdef CONFIG_SMP
@@ -405,17 +286,17 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
#error SMP is not supported on this platform
#endif
case 1:
- local_irq_save(flags);
+ raw_local_irq_save(flags);
ret = *(volatile unsigned char *)ptr;
*(volatile unsigned char *)ptr = x;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
break;
case 4:
- local_irq_save(flags);
+ raw_local_irq_save(flags);
ret = *(volatile unsigned long *)ptr;
*(volatile unsigned long *)ptr = x;
- local_irq_restore(flags);
+ raw_local_irq_restore(flags);
break;
#else
case 1:
diff --git a/include/asm-arm/tlbflush.h b/include/asm-arm/tlbflush.h
index d97fc76189a5..cd10a0b5f8ae 100644
--- a/include/asm-arm/tlbflush.h
+++ b/include/asm-arm/tlbflush.h
@@ -247,16 +247,16 @@ static inline void local_flush_tlb_all(void)
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_WB))
- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V3_FULL))
- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_U_FULL | TLB_V6_U_FULL))
- asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_D_FULL | TLB_V6_D_FULL))
- asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_I_FULL | TLB_V6_I_FULL))
- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
}
static inline void local_flush_tlb_mm(struct mm_struct *mm)
@@ -266,25 +266,25 @@ static inline void local_flush_tlb_mm(struct mm_struct *mm)
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_WB))
- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
if (cpu_isset(smp_processor_id(), mm->cpu_vm_mask)) {
if (tlb_flag(TLB_V3_FULL))
- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_U_FULL))
- asm("mcr%? p15, 0, %0, c8, c7, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c7, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_D_FULL))
- asm("mcr%? p15, 0, %0, c8, c6, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c6, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V4_I_FULL))
- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
}
if (tlb_flag(TLB_V6_U_ASID))
- asm("mcr%? p15, 0, %0, c8, c7, 2" : : "r" (asid));
+ asm("mcr p15, 0, %0, c8, c7, 2" : : "r" (asid) : "cc");
if (tlb_flag(TLB_V6_D_ASID))
- asm("mcr%? p15, 0, %0, c8, c6, 2" : : "r" (asid));
+ asm("mcr p15, 0, %0, c8, c6, 2" : : "r" (asid) : "cc");
if (tlb_flag(TLB_V6_I_ASID))
- asm("mcr%? p15, 0, %0, c8, c5, 2" : : "r" (asid));
+ asm("mcr p15, 0, %0, c8, c5, 2" : : "r" (asid) : "cc");
}
static inline void
@@ -296,27 +296,27 @@ local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
uaddr = (uaddr & PAGE_MASK) | ASID(vma->vm_mm);
if (tlb_flag(TLB_WB))
- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero));
if (cpu_isset(smp_processor_id(), vma->vm_mm->cpu_vm_mask)) {
if (tlb_flag(TLB_V3_PAGE))
- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (uaddr));
+ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V4_U_PAGE))
- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (uaddr));
+ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V4_D_PAGE))
- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (uaddr));
+ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V4_I_PAGE))
- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
+ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
}
if (tlb_flag(TLB_V6_U_PAGE))
- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (uaddr));
+ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V6_D_PAGE))
- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (uaddr));
+ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (uaddr) : "cc");
if (tlb_flag(TLB_V6_I_PAGE))
- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
+ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (uaddr) : "cc");
}
static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
@@ -327,31 +327,31 @@ static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
kaddr &= PAGE_MASK;
if (tlb_flag(TLB_WB))
- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V3_PAGE))
- asm("mcr%? p15, 0, %0, c6, c0, 0" : : "r" (kaddr));
+ asm("mcr p15, 0, %0, c6, c0, 0" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V4_U_PAGE))
- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (kaddr));
+ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V4_D_PAGE))
- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (kaddr));
+ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V4_I_PAGE))
- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (kaddr));
+ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
if (!tlb_flag(TLB_V4_I_PAGE) && tlb_flag(TLB_V4_I_FULL))
- asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
+ asm("mcr p15, 0, %0, c8, c5, 0" : : "r" (zero) : "cc");
if (tlb_flag(TLB_V6_U_PAGE))
- asm("mcr%? p15, 0, %0, c8, c7, 1" : : "r" (kaddr));
+ asm("mcr p15, 0, %0, c8, c7, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V6_D_PAGE))
- asm("mcr%? p15, 0, %0, c8, c6, 1" : : "r" (kaddr));
+ asm("mcr p15, 0, %0, c8, c6, 1" : : "r" (kaddr) : "cc");
if (tlb_flag(TLB_V6_I_PAGE))
- asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (kaddr));
+ asm("mcr p15, 0, %0, c8, c5, 1" : : "r" (kaddr) : "cc");
/* The ARM ARM states that the completion of a TLB maintenance
* operation is only guaranteed by a DSB instruction
*/
if (tlb_flag(TLB_V6_U_PAGE | TLB_V6_D_PAGE | TLB_V6_I_PAGE))
- asm("mcr%? p15, 0, %0, c7, c10, 4" : : "r" (zero));
+ asm("mcr p15, 0, %0, c7, c10, 4" : : "r" (zero) : "cc");
}
/*
@@ -373,11 +373,11 @@ static inline void flush_pmd_entry(pmd_t *pmd)
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
- asm("mcr%? p15, 0, %0, c7, c10, 1 @ flush_pmd"
- : : "r" (pmd));
+ asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
+ : : "r" (pmd) : "cc");
if (tlb_flag(TLB_WB))
- asm("mcr%? p15, 0, %0, c7, c10, 4 @ flush_pmd"
- : : "r" (zero));
+ asm("mcr p15, 0, %0, c7, c10, 4 @ flush_pmd"
+ : : "r" (zero) : "cc");
}
static inline void clean_pmd_entry(pmd_t *pmd)
@@ -385,8 +385,8 @@ static inline void clean_pmd_entry(pmd_t *pmd)
const unsigned int __tlb_flag = __cpu_tlb_flags;
if (tlb_flag(TLB_DCLEAN))
- asm("mcr%? p15, 0, %0, c7, c10, 1 @ flush_pmd"
- : : "r" (pmd));
+ asm("mcr p15, 0, %0, c7, c10, 1 @ flush_pmd"
+ : : "r" (pmd) : "cc");
}
#undef tlb_flag
diff --git a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h
index 87aba57a66c4..09ad0cab9014 100644
--- a/include/asm-arm/uaccess.h
+++ b/include/asm-arm/uaccess.h
@@ -110,7 +110,7 @@ extern int __get_user_4(void *);
#define get_user(x,p) \
({ \
const register typeof(*(p)) __user *__p asm("r0") = (p);\
- register unsigned int __r2 asm("r2"); \
+ register unsigned long __r2 asm("r2"); \
register int __e asm("r0"); \
switch (sizeof(*(__p))) { \
case 1: \
diff --git a/include/asm-arm/unaligned.h b/include/asm-arm/unaligned.h
index 1b39c2f322c9..795b9e5b9e6a 100644
--- a/include/asm-arm/unaligned.h
+++ b/include/asm-arm/unaligned.h
@@ -3,7 +3,7 @@
#include <asm/types.h>
-extern int __bug_unaligned_x(void *ptr);
+extern int __bug_unaligned_x(const void *ptr);
/*
* What is the most efficient way of loading/storing an unaligned value?
@@ -51,44 +51,32 @@ extern int __bug_unaligned_x(void *ptr);
#define __get_unaligned_4_be(__p) \
(__p[0] << 24 | __p[1] << 16 | __p[2] << 8 | __p[3])
-#define __get_unaligned_le(ptr) \
- ({ \
- __typeof__(*(ptr)) __v; \
- __u8 *__p = (__u8 *)(ptr); \
- switch (sizeof(*(ptr))) { \
- case 1: __v = *(ptr); break; \
- case 2: __v = __get_unaligned_2_le(__p); break; \
- case 4: __v = __get_unaligned_4_le(__p); break; \
- case 8: { \
- unsigned int __v1, __v2; \
- __v2 = __get_unaligned_4_le((__p+4)); \
- __v1 = __get_unaligned_4_le(__p); \
- __v = ((unsigned long long)__v2 << 32 | __v1); \
- } \
- break; \
- default: __v = __bug_unaligned_x(__p); break; \
- } \
- __v; \
+#define __get_unaligned_8_le(__p) \
+ ((unsigned long long)__get_unaligned_4_le((__p+4)) << 32 | \
+ __get_unaligned_4_le(__p))
+
+#define __get_unaligned_8_be(__p) \
+ ((unsigned long long)__get_unaligned_4_be(__p) << 32 | \
+ __get_unaligned_4_be((__p+4)))
+
+#define __get_unaligned_le(ptr) \
+ ({ \
+ const __u8 *__p = (const __u8 *)(ptr); \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *__p, \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, __get_unaligned_2_le(__p), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, __get_unaligned_4_le(__p), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, __get_unaligned_8_le(__p), \
+ (void)__bug_unaligned_x(__p))))); \
})
-#define __get_unaligned_be(ptr) \
- ({ \
- __typeof__(*(ptr)) __v; \
- __u8 *__p = (__u8 *)(ptr); \
- switch (sizeof(*(ptr))) { \
- case 1: __v = *(ptr); break; \
- case 2: __v = __get_unaligned_2_be(__p); break; \
- case 4: __v = __get_unaligned_4_be(__p); break; \
- case 8: { \
- unsigned int __v1, __v2; \
- __v2 = __get_unaligned_4_be(__p); \
- __v1 = __get_unaligned_4_be((__p+4)); \
- __v = ((unsigned long long)__v2 << 32 | __v1); \
- } \
- break; \
- default: __v = __bug_unaligned_x(__p); break; \
- } \
- __v; \
+#define __get_unaligned_be(ptr) \
+ ({ \
+ const __u8 *__p = (const __u8 *)(ptr); \
+ __builtin_choose_expr(sizeof(*(ptr)) == 1, *__p, \
+ __builtin_choose_expr(sizeof(*(ptr)) == 2, __get_unaligned_2_be(__p), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 4, __get_unaligned_4_be(__p), \
+ __builtin_choose_expr(sizeof(*(ptr)) == 8, __get_unaligned_8_be(__p), \
+ (void)__bug_unaligned_x(__p))))); \
})
diff --git a/include/asm-arm/unistd.h b/include/asm-arm/unistd.h
index 1e891f860ef3..14a87eec5a2d 100644
--- a/include/asm-arm/unistd.h
+++ b/include/asm-arm/unistd.h
@@ -377,6 +377,7 @@
#endif
#ifdef __KERNEL__
+#include <linux/err.h>
#include <linux/linkage.h>
#define __sys2(x) #x
@@ -396,7 +397,7 @@
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-129)) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
errno = -(res); \
res = -1; \
} \
@@ -548,30 +549,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6
#define __ARCH_WANT_SYS_SOCKETCALL
#endif
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/syscalls.h>
-
-extern long execve(const char *file, char **argv, char **envp);
-
-struct pt_regs;
-asmlinkage int sys_execve(char *filenamei, char **argv, char **envp,
- struct pt_regs *regs);
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
- struct pt_regs *regs);
-asmlinkage int sys_fork(struct pt_regs *regs);
-asmlinkage int sys_vfork(struct pt_regs *regs);
-asmlinkage int sys_pipe(unsigned long *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-arm26/assembler.h b/include/asm-arm26/assembler.h
index 83f9aec55e4f..bb507a9a4a55 100644
--- a/include/asm-arm26/assembler.h
+++ b/include/asm-arm26/assembler.h
@@ -1,5 +1,5 @@
/*
- * linux/asm/assembler.h
+ * linux/include/asm-arm26/assembler.h
*
* This file contains arm architecture specific defines
* for the different processors.
diff --git a/include/asm-arm26/namei.h b/include/asm-arm26/namei.h
index a402d3b9d0f7..3f5d340110eb 100644
--- a/include/asm-arm26/namei.h
+++ b/include/asm-arm26/namei.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/namei.h
+ * linux/include/asm-arm26/namei.h
*
* Routines to handle famous /usr/gnemul
* Derived from the Sparc version of this file
diff --git a/include/asm-arm26/semaphore.h b/include/asm-arm26/semaphore.h
index ccf15e704109..1fda54375ed8 100644
--- a/include/asm-arm26/semaphore.h
+++ b/include/asm-arm26/semaphore.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-arm/semaphore.h
+ * linux/include/asm-arm26/semaphore.h
*/
#ifndef __ASM_ARM_SEMAPHORE_H
#define __ASM_ARM_SEMAPHORE_H
diff --git a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h
index 70eb6d91cfd0..25a5eead85be 100644
--- a/include/asm-arm26/unistd.h
+++ b/include/asm-arm26/unistd.h
@@ -311,6 +311,7 @@
#define __ARM_NR_usr26 (__ARM_NR_BASE+3)
#ifdef __KERNEL__
+#include <linux/err.h>
#include <linux/linkage.h>
#define __sys2(x) #x
@@ -322,7 +323,7 @@
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+ if ((unsigned long)(res) >= (unsigned long)-MAX_ERRNO) { \
errno = -(res); \
res = -1; \
} \
@@ -463,30 +464,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/syscalls.h>
-
-extern long execve(const char *file, char **argv, char **envp);
-
-struct pt_regs;
-asmlinkage int sys_execve(char *filenamei, char **argv, char **envp,
- struct pt_regs *regs);
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
- struct pt_regs *regs);
-asmlinkage int sys_fork(struct pt_regs *regs);
-asmlinkage int sys_vfork(struct pt_regs *regs);
-asmlinkage int sys_pipe(unsigned long *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-avr32/arch-at32ap/at91rm9200_usart.h b/include/asm-avr32/arch-at32ap/at91rm9200_usart.h
deleted file mode 100644
index 79f851e31b9c..000000000000
--- a/include/asm-avr32/arch-at32ap/at91rm9200_usart.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * include/asm-arm/arch-at91rm9200/at91rm9200_usart.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * USART registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * 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.
- */
-
-#ifndef AT91RM9200_USART_H
-#define AT91RM9200_USART_H
-
-#define AT91_US_CR 0x00 /* Control Register */
-#define AT91_US_RSTRX (1 << 2) /* Reset Receiver */
-#define AT91_US_RSTTX (1 << 3) /* Reset Transmitter */
-#define AT91_US_RXEN (1 << 4) /* Receiver Enable */
-#define AT91_US_RXDIS (1 << 5) /* Receiver Disable */
-#define AT91_US_TXEN (1 << 6) /* Transmitter Enable */
-#define AT91_US_TXDIS (1 << 7) /* Transmitter Disable */
-#define AT91_US_RSTSTA (1 << 8) /* Reset Status Bits */
-#define AT91_US_STTBRK (1 << 9) /* Start Break */
-#define AT91_US_STPBRK (1 << 10) /* Stop Break */
-#define AT91_US_STTTO (1 << 11) /* Start Time-out */
-#define AT91_US_SENDA (1 << 12) /* Send Address */
-#define AT91_US_RSTIT (1 << 13) /* Reset Iterations */
-#define AT91_US_RSTNACK (1 << 14) /* Reset Non Acknowledge */
-#define AT91_US_RETTO (1 << 15) /* Rearm Time-out */
-#define AT91_US_DTREN (1 << 16) /* Data Terminal Ready Enable */
-#define AT91_US_DTRDIS (1 << 17) /* Data Terminal Ready Disable */
-#define AT91_US_RTSEN (1 << 18) /* Request To Send Enable */
-#define AT91_US_RTSDIS (1 << 19) /* Request To Send Disable */
-
-#define AT91_US_MR 0x04 /* Mode Register */
-#define AT91_US_USMODE (0xf << 0) /* Mode of the USART */
-#define AT91_US_USMODE_NORMAL 0
-#define AT91_US_USMODE_RS485 1
-#define AT91_US_USMODE_HWHS 2
-#define AT91_US_USMODE_MODEM 3
-#define AT91_US_USMODE_ISO7816_T0 4
-#define AT91_US_USMODE_ISO7816_T1 6
-#define AT91_US_USMODE_IRDA 8
-#define AT91_US_USCLKS (3 << 4) /* Clock Selection */
-#define AT91_US_CHRL (3 << 6) /* Character Length */
-#define AT91_US_CHRL_5 (0 << 6)
-#define AT91_US_CHRL_6 (1 << 6)
-#define AT91_US_CHRL_7 (2 << 6)
-#define AT91_US_CHRL_8 (3 << 6)
-#define AT91_US_SYNC (1 << 8) /* Synchronous Mode Select */
-#define AT91_US_PAR (7 << 9) /* Parity Type */
-#define AT91_US_PAR_EVEN (0 << 9)
-#define AT91_US_PAR_ODD (1 << 9)
-#define AT91_US_PAR_SPACE (2 << 9)
-#define AT91_US_PAR_MARK (3 << 9)
-#define AT91_US_PAR_NONE (4 << 9)
-#define AT91_US_PAR_MULTI_DROP (6 << 9)
-#define AT91_US_NBSTOP (3 << 12) /* Number of Stop Bits */
-#define AT91_US_NBSTOP_1 (0 << 12)
-#define AT91_US_NBSTOP_1_5 (1 << 12)
-#define AT91_US_NBSTOP_2 (2 << 12)
-#define AT91_US_CHMODE (3 << 14) /* Channel Mode */
-#define AT91_US_CHMODE_NORMAL (0 << 14)
-#define AT91_US_CHMODE_ECHO (1 << 14)
-#define AT91_US_CHMODE_LOC_LOOP (2 << 14)
-#define AT91_US_CHMODE_REM_LOOP (3 << 14)
-#define AT91_US_MSBF (1 << 16) /* Bit Order */
-#define AT91_US_MODE9 (1 << 17) /* 9-bit Character Length */
-#define AT91_US_CLKO (1 << 18) /* Clock Output Select */
-#define AT91_US_OVER (1 << 19) /* Oversampling Mode */
-#define AT91_US_INACK (1 << 20) /* Inhibit Non Acknowledge */
-#define AT91_US_DSNACK (1 << 21) /* Disable Successive NACK */
-#define AT91_US_MAX_ITER (7 << 24) /* Max Iterations */
-#define AT91_US_FILTER (1 << 28) /* Infrared Receive Line Filter */
-
-#define AT91_US_IER 0x08 /* Interrupt Enable Register */
-#define AT91_US_RXRDY (1 << 0) /* Receiver Ready */
-#define AT91_US_TXRDY (1 << 1) /* Transmitter Ready */
-#define AT91_US_RXBRK (1 << 2) /* Break Received / End of Break */
-#define AT91_US_ENDRX (1 << 3) /* End of Receiver Transfer */
-#define AT91_US_ENDTX (1 << 4) /* End of Transmitter Transfer */
-#define AT91_US_OVRE (1 << 5) /* Overrun Error */
-#define AT91_US_FRAME (1 << 6) /* Framing Error */
-#define AT91_US_PARE (1 << 7) /* Parity Error */
-#define AT91_US_TIMEOUT (1 << 8) /* Receiver Time-out */
-#define AT91_US_TXEMPTY (1 << 9) /* Transmitter Empty */
-#define AT91_US_ITERATION (1 << 10) /* Max number of Repetitions Reached */
-#define AT91_US_TXBUFE (1 << 11) /* Transmission Buffer Empty */
-#define AT91_US_RXBUFF (1 << 12) /* Reception Buffer Full */
-#define AT91_US_NACK (1 << 13) /* Non Acknowledge */
-#define AT91_US_RIIC (1 << 16) /* Ring Indicator Input Change */
-#define AT91_US_DSRIC (1 << 17) /* Data Set Ready Input Change */
-#define AT91_US_DCDIC (1 << 18) /* Data Carrier Detect Input Change */
-#define AT91_US_CTSIC (1 << 19) /* Clear to Send Input Change */
-#define AT91_US_RI (1 << 20) /* RI */
-#define AT91_US_DSR (1 << 21) /* DSR */
-#define AT91_US_DCD (1 << 22) /* DCD */
-#define AT91_US_CTS (1 << 23) /* CTS */
-
-#define AT91_US_IDR 0x0c /* Interrupt Disable Register */
-#define AT91_US_IMR 0x10 /* Interrupt Mask Register */
-#define AT91_US_CSR 0x14 /* Channel Status Register */
-#define AT91_US_RHR 0x18 /* Receiver Holding Register */
-#define AT91_US_THR 0x1c /* Transmitter Holding Register */
-
-#define AT91_US_BRGR 0x20 /* Baud Rate Generator Register */
-#define AT91_US_CD (0xffff << 0) /* Clock Divider */
-
-#define AT91_US_RTOR 0x24 /* Receiver Time-out Register */
-#define AT91_US_TO (0xffff << 0) /* Time-out Value */
-
-#define AT91_US_TTGR 0x28 /* Transmitter Timeguard Register */
-#define AT91_US_TG (0xff << 0) /* Timeguard Value */
-
-#define AT91_US_FIDI 0x40 /* FI DI Ratio Register */
-#define AT91_US_NER 0x44 /* Number of Errors Register */
-#define AT91_US_IF 0x4c /* IrDA Filter Register */
-
-#endif
diff --git a/include/asm-avr32/arch-at32ap/board.h b/include/asm-avr32/arch-at32ap/board.h
index 39368e18ab20..a39b3e999f18 100644
--- a/include/asm-avr32/arch-at32ap/board.h
+++ b/include/asm-avr32/arch-at32ap/board.h
@@ -9,9 +9,15 @@
/* Add basic devices: system manager, interrupt controller, portmuxes, etc. */
void at32_add_system_devices(void);
-#define AT91_NR_UART 4
-extern struct platform_device *at91_default_console_device;
+#define ATMEL_MAX_UART 4
+extern struct platform_device *atmel_default_console_device;
+struct atmel_uart_data {
+ short use_dma_tx; /* use transmit DMA? */
+ short use_dma_rx; /* use receive DMA? */
+ void __iomem *regs; /* virtual base address, if any */
+};
+void at32_map_usart(unsigned int hw_id, unsigned int line);
struct platform_device *at32_add_device_usart(unsigned int id);
struct eth_platform_data {
diff --git a/include/asm-avr32/arch-at32ap/init.h b/include/asm-avr32/arch-at32ap/init.h
index 43722634e069..5e75d850d707 100644
--- a/include/asm-avr32/arch-at32ap/init.h
+++ b/include/asm-avr32/arch-at32ap/init.h
@@ -11,6 +11,7 @@
#define __ASM_AVR32_AT32AP_INIT_H__
void setup_platform(void);
+void setup_board(void);
/* Called by setup_platform */
void at32_clock_init(void);
diff --git a/include/asm-avr32/irq_regs.h b/include/asm-avr32/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-avr32/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-avr32/mach/serial_at91.h b/include/asm-avr32/mach/serial_at91.h
index 1290bb32802d..55b317a89061 100644
--- a/include/asm-avr32/mach/serial_at91.h
+++ b/include/asm-avr32/mach/serial_at91.h
@@ -14,7 +14,7 @@ struct uart_port;
* This is a temporary structure for registering these
* functions; it is intended to be discarded after boot.
*/
-struct at91_port_fns {
+struct atmel_port_fns {
void (*set_mctrl)(struct uart_port *, u_int);
u_int (*get_mctrl)(struct uart_port *);
void (*enable_ms)(struct uart_port *);
@@ -24,10 +24,10 @@ struct at91_port_fns {
void (*close)(struct uart_port *);
};
-#if defined(CONFIG_SERIAL_AT91)
-void at91_register_uart_fns(struct at91_port_fns *fns);
+#if defined(CONFIG_SERIAL_ATMEL)
+void atmel_register_uart_fns(struct atmel_port_fns *fns);
#else
-#define at91_register_uart_fns(fns) do { } while (0)
+#define atmel_register_uart_fns(fns) do { } while (0)
#endif
diff --git a/include/asm-avr32/unistd.h b/include/asm-avr32/unistd.h
index 1f528f92690d..a50e5004550c 100644
--- a/include/asm-avr32/unistd.h
+++ b/include/asm-avr32/unistd.h
@@ -281,30 +281,10 @@
#define __NR_tee 263
#define __NR_vmsplice 264
+#ifdef __KERNEL__
#define NR_syscalls 265
-/*
- * AVR32 calling convention for system calls:
- * - System call number in r8
- * - Parameters in r12 and downwards to r9 as well as r6 and r5.
- * - Return value in r12
- */
-
-/*
- * user-visible error numbers are in the range -1 - -124: see
- * <asm-generic/errno.h>
- */
-
-#define __syscall_return(type, res) do { \
- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
- errno = -(res); \
- res = -1; \
- } \
- return (type) (res); \
- } while (0)
-
-#ifdef __KERNEL__
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_STAT64
#define __ARCH_WANT_SYS_ALARM
@@ -319,62 +299,6 @@
#define __ARCH_WANT_SYS_GETPGRP
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#endif
-
-#if defined(__KERNEL_SYSCALLS__) || defined(__CHECKER__)
-
-#include <linux/types.h>
-#include <linux/linkage.h>
-#include <asm/signal.h>
-
-struct pt_regs;
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-static inline int execve(const char *file, char **argv, char **envp)
-{
- register long scno asm("r8") = __NR_execve;
- register long sc1 asm("r12") = (long)file;
- register long sc2 asm("r11") = (long)argv;
- register long sc3 asm("r10") = (long)envp;
- int res;
-
- asm volatile("scall"
- : "=r"(sc1)
- : "r"(scno), "0"(sc1), "r"(sc2), "r"(sc3)
- : "lr", "memory");
- res = sc1;
- __syscall_return(int, res);
-}
-
-asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize);
-asmlinkage int sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
- struct pt_regs *regs);
-asmlinkage int sys_rt_sigreturn(struct pt_regs *regs);
-asmlinkage int sys_pipe(unsigned long __user *filedes);
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, off_t offset);
-asmlinkage int sys_cacheflush(int operation, void __user *addr, size_t len);
-asmlinkage int sys_fork(struct pt_regs *regs);
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
- unsigned long parent_tidptr,
- unsigned long child_tidptr, struct pt_regs *regs);
-asmlinkage int sys_vfork(struct pt_regs *regs);
-asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv,
- char __user *__user *uenvp, struct pt_regs *regs);
-
-#endif
/*
* "Conditional" syscalls
@@ -384,4 +308,6 @@ asmlinkage int sys_execve(char __user *ufilename, char __user *__user *uargv,
*/
#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#endif /* __KERNEL__ */
+
#endif /* __ASM_AVR32_UNISTD_H */
diff --git a/include/asm-cris/arch-v32/spinlock.h b/include/asm-cris/arch-v32/spinlock.h
index 52df72a62232..5f43df0a5fb4 100644
--- a/include/asm-cris/arch-v32/spinlock.h
+++ b/include/asm-cris/arch-v32/spinlock.h
@@ -160,4 +160,8 @@ static __inline__ int is_write_locked(rwlock_t *rw)
return rw->counter < 0;
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_ARCH_SPINLOCK_H */
diff --git a/include/asm-cris/unistd.h b/include/asm-cris/unistd.h
index 7372efae0516..7c90fa970c38 100644
--- a/include/asm-cris/unistd.h
+++ b/include/asm-cris/unistd.h
@@ -322,67 +322,6 @@
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/linkage.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-
-struct pt_regs;
-asmlinkage long sys_mmap2(
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(const char *fname, char **argv, char **envp,
- long r13, long mof, long srp, struct pt_regs *regs);
-asmlinkage int sys_clone(unsigned long newusp, unsigned long flags,
- int* parent_tid, int* child_tid, long mof, long srp,
- struct pt_regs *regs);
-asmlinkage int sys_fork(long r10, long r11, long r12, long r13,
- long mof, long srp, struct pt_regs *regs);
-asmlinkage int sys_vfork(long r10, long r11, long r12, long r13,
- long mof, long srp, struct pt_regs *regs);
-asmlinkage int sys_pipe(unsigned long __user *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-/*
- * Since we define it "external", it collides with the built-in
- * definition, which has the "noreturn" attribute and will cause
- * complaints. We don't want to use -fno-builtin, so just use a
- * different name when in the kernel.
- */
-#define _exit kernel_syscall_exit
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-#endif /* __KERNEL_SYSCALLS__ */
-
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-frv/dma.h b/include/asm-frv/dma.h
index 18d6bb8f84fc..683c47d48a5b 100644
--- a/include/asm-frv/dma.h
+++ b/include/asm-frv/dma.h
@@ -24,10 +24,7 @@
/*
* FRV DMA controller management
*/
-struct pt_regs;
-
-typedef irqreturn_t (*dma_irq_handler_t)(int dmachan, unsigned long cstr, void *data,
- struct pt_regs *regs);
+typedef irqreturn_t (*dma_irq_handler_t)(int dmachan, unsigned long cstr, void *data);
extern void frv_dma_init(void);
diff --git a/include/asm-frv/highmem.h b/include/asm-frv/highmem.h
index e2247c22a638..0f390f41f816 100644
--- a/include/asm-frv/highmem.h
+++ b/include/asm-frv/highmem.h
@@ -82,11 +82,11 @@ extern struct page *kmap_atomic_to_page(void *ptr);
dampr = paddr | xAMPRx_L | xAMPRx_M | xAMPRx_S | xAMPRx_SS_16Kb | xAMPRx_V; \
\
if (type != __KM_CACHE) \
- asm volatile("movgs %0,dampr"#ampr :: "r"(dampr)); \
+ asm volatile("movgs %0,dampr"#ampr :: "r"(dampr) : "memory"); \
else \
asm volatile("movgs %0,iampr"#ampr"\n" \
"movgs %0,dampr"#ampr"\n" \
- :: "r"(dampr) \
+ :: "r"(dampr) : "memory" \
); \
\
asm("movsg damlr"#ampr",%0" : "=r"(damlr)); \
@@ -104,7 +104,7 @@ extern struct page *kmap_atomic_to_page(void *ptr);
asm volatile("movgs %0,tplr \n" \
"movgs %1,tppr \n" \
"tlbpr %0,gr0,#2,#1" \
- : : "r"(damlr), "r"(dampr)); \
+ : : "r"(damlr), "r"(dampr) : "memory"); \
\
/*printk("TLB: SECN sl=%d L=%08lx P=%08lx\n", slot, damlr, dampr);*/ \
\
@@ -115,7 +115,7 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
{
unsigned long paddr;
- preempt_disable();
+ inc_preempt_count();
paddr = page_to_phys(page);
switch (type) {
@@ -138,16 +138,16 @@ static inline void *kmap_atomic(struct page *page, enum km_type type)
}
}
-#define __kunmap_atomic_primary(type, ampr) \
-do { \
- asm volatile("movgs gr0,dampr"#ampr"\n"); \
- if (type == __KM_CACHE) \
- asm volatile("movgs gr0,iampr"#ampr"\n"); \
+#define __kunmap_atomic_primary(type, ampr) \
+do { \
+ asm volatile("movgs gr0,dampr"#ampr"\n" ::: "memory"); \
+ if (type == __KM_CACHE) \
+ asm volatile("movgs gr0,iampr"#ampr"\n" ::: "memory"); \
} while(0)
-#define __kunmap_atomic_secondary(slot, vaddr) \
-do { \
- asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr)); \
+#define __kunmap_atomic_secondary(slot, vaddr) \
+do { \
+ asm volatile("tlbpr %0,gr0,#4,#1" : : "r"(vaddr) : "memory"); \
} while(0)
static inline void kunmap_atomic(void *kvaddr, enum km_type type)
@@ -170,7 +170,8 @@ static inline void kunmap_atomic(void *kvaddr, enum km_type type)
default:
BUG();
}
- preempt_enable();
+ dec_preempt_count();
+ preempt_check_resched();
}
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-frv/io.h b/include/asm-frv/io.h
index 7765f5528894..20e44fe00abf 100644
--- a/include/asm-frv/io.h
+++ b/include/asm-frv/io.h
@@ -385,27 +385,6 @@ static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
*/
#define xlate_dev_kmem_ptr(p) p
-/*
- * Check BIOS signature
- */
-static inline int check_signature(volatile void __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
-
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
-
- retval = 1;
-out:
- return retval;
-}
-
#endif /* __KERNEL__ */
#endif /* _ASM_IO_H */
diff --git a/include/asm-frv/irq_regs.h b/include/asm-frv/irq_regs.h
new file mode 100644
index 000000000000..d22e83289ad1
--- /dev/null
+++ b/include/asm-frv/irq_regs.h
@@ -0,0 +1,27 @@
+/* FRV per-CPU frame pointer holder
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef _ASM_IRQ_REGS_H
+#define _ASM_IRQ_REGS_H
+
+/*
+ * Per-cpu current frame pointer - the location of the last exception frame on
+ * the stack
+ * - on FRV, GR28 is dedicated to keeping a pointer to the current exception
+ * frame
+ */
+#define ARCH_HAS_OWN_IRQ_REGS
+
+#ifndef __ASSEMBLY__
+#define get_irq_regs() (__frame)
+#endif
+
+#endif /* _ASM_IRQ_REGS_H */
diff --git a/include/asm-frv/namei.h b/include/asm-frv/namei.h
index 84ddd6445f23..4ea57171d951 100644
--- a/include/asm-frv/namei.h
+++ b/include/asm-frv/namei.h
@@ -1,5 +1,5 @@
/*
- * asm/namei.h
+ * include/asm-frv/namei.h
*
* Included from linux/fs/namei.c
*/
diff --git a/include/asm-frv/pgtable.h b/include/asm-frv/pgtable.h
index 2fb3c6f05e03..ba1b37df69d5 100644
--- a/include/asm-frv/pgtable.h
+++ b/include/asm-frv/pgtable.h
@@ -176,8 +176,6 @@ do { \
} while(0)
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-#define set_pte_atomic(pteptr, pteval) set_pte((pteptr), (pteval))
-
/*
* pgd_offset() returns a (pgd_t *)
* pgd_index() is used get the offset into the pgd page's array of pgd_t's;
diff --git a/include/asm-frv/ptrace.h b/include/asm-frv/ptrace.h
index 7ff525162a72..9a2241b8eb1e 100644
--- a/include/asm-frv/ptrace.h
+++ b/include/asm-frv/ptrace.h
@@ -12,6 +12,7 @@
#define _ASM_PTRACE_H
#include <asm/registers.h>
+#include <asm/irq_regs.h>
#define in_syscall(regs) (((regs)->tbr & TBR_TT) == TBR_TT_TRAP0)
diff --git a/include/asm-frv/timex.h b/include/asm-frv/timex.h
index 2aa562fa067b..a89bddefdacf 100644
--- a/include/asm-frv/timex.h
+++ b/include/asm-frv/timex.h
@@ -6,11 +6,6 @@
#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
-#define FINETUNE \
-((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
- (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
- << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
-
typedef unsigned long cycles_t;
static inline cycles_t get_cycles(void)
diff --git a/include/asm-frv/unistd.h b/include/asm-frv/unistd.h
index b80dbd839475..725e854928cf 100644
--- a/include/asm-frv/unistd.h
+++ b/include/asm-frv/unistd.h
@@ -320,6 +320,7 @@
#ifdef __KERNEL__
#define NR_syscalls 310
+#include <linux/err.h>
/*
* process the return value of a syscall, consigning it to one of two possible fates
@@ -329,7 +330,7 @@
#define __syscall_return(type, res) \
do { \
unsigned long __sr2 = (res); \
- if (__builtin_expect(__sr2 >= (unsigned long)(-4095), 0)) { \
+ if (__builtin_expect(__sr2 >= (unsigned long)(-MAX_ERRNO), 0)) { \
errno = (-__sr2); \
__sr2 = ~0UL; \
} \
@@ -439,31 +440,6 @@ type name (type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg
__syscall_return(type, __sc0); \
}
-
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-
-#endif /* __KERNEL_SYSCALLS__ */
-
#define __ARCH_WANT_IPC_PARSE_VERSION
/* #define __ARCH_WANT_OLD_READDIR */
#define __ARCH_WANT_OLD_STAT
diff --git a/include/asm-generic/bitops/sched.h b/include/asm-generic/bitops/sched.h
index 5ef93a4d009f..815bb0148060 100644
--- a/include/asm-generic/bitops/sched.h
+++ b/include/asm-generic/bitops/sched.h
@@ -15,7 +15,7 @@ static inline int sched_find_first_bit(const unsigned long *b)
#if BITS_PER_LONG == 64
if (unlikely(b[0]))
return __ffs(b[0]);
- if (unlikely(b[1]))
+ if (likely(b[1]))
return __ffs(b[1]) + 64;
return __ffs(b[2]) + 128;
#elif BITS_PER_LONG == 32
diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
index 8ceab7bcd8b4..c92ae0f166ff 100644
--- a/include/asm-generic/bug.h
+++ b/include/asm-generic/bug.h
@@ -16,12 +16,15 @@
#endif
#ifndef HAVE_ARCH_WARN_ON
-#define WARN_ON(condition) do { \
- if (unlikely((condition)!=0)) { \
- printk("BUG: warning at %s:%d/%s()\n", __FILE__, __LINE__, __FUNCTION__); \
- dump_stack(); \
- } \
-} while (0)
+#define WARN_ON(condition) ({ \
+ typeof(condition) __ret_warn_on = (condition); \
+ if (unlikely(__ret_warn_on)) { \
+ printk("BUG: warning at %s:%d/%s()\n", __FILE__, \
+ __LINE__, __FUNCTION__); \
+ dump_stack(); \
+ } \
+ unlikely(__ret_warn_on); \
+})
#endif
#else /* !CONFIG_BUG */
@@ -34,21 +37,21 @@
#endif
#ifndef HAVE_ARCH_WARN_ON
-#define WARN_ON(condition) do { if (condition) ; } while(0)
+#define WARN_ON(condition) ({ \
+ typeof(condition) __ret_warn_on = (condition); \
+ unlikely(__ret_warn_on); \
+})
#endif
#endif
-#define WARN_ON_ONCE(condition) \
-({ \
- static int __warn_once = 1; \
- int __ret = 0; \
- \
- if (unlikely((condition) && __warn_once)) { \
- __warn_once = 0; \
- WARN_ON(1); \
- __ret = 1; \
- } \
- __ret; \
+#define WARN_ON_ONCE(condition) ({ \
+ static int __warned; \
+ typeof(condition) __ret_warn_once = (condition); \
+ \
+ if (unlikely(__ret_warn_once)) \
+ if (WARN_ON(!__warned)) \
+ __warned = 1; \
+ unlikely(__ret_warn_once); \
})
#ifdef CONFIG_SMP
diff --git a/include/asm-generic/irq_regs.h b/include/asm-generic/irq_regs.h
new file mode 100644
index 000000000000..5ae1d07d4a12
--- /dev/null
+++ b/include/asm-generic/irq_regs.h
@@ -0,0 +1,37 @@
+/* Fallback per-CPU frame pointer holder
+ *
+ * Copyright (C) 2006 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.
+ */
+
+#ifndef _ASM_GENERIC_IRQ_REGS_H
+#define _ASM_GENERIC_IRQ_REGS_H
+
+#include <linux/percpu.h>
+
+/*
+ * Per-cpu current frame pointer - the location of the last exception frame on
+ * the stack
+ */
+DECLARE_PER_CPU(struct pt_regs *, __irq_regs);
+
+static inline struct pt_regs *get_irq_regs(void)
+{
+ return __get_cpu_var(__irq_regs);
+}
+
+static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs)
+{
+ struct pt_regs *old_regs, **pp_regs = &__get_cpu_var(__irq_regs);
+
+ old_regs = *pp_regs;
+ *pp_regs = new_regs;
+ return old_regs;
+}
+
+#endif /* _ASM_GENERIC_IRQ_REGS_H */
diff --git a/include/asm-generic/mutex-dec.h b/include/asm-generic/mutex-dec.h
index 29c6ac34e236..0134151656af 100644
--- a/include/asm-generic/mutex-dec.h
+++ b/include/asm-generic/mutex-dec.h
@@ -1,5 +1,5 @@
/*
- * asm-generic/mutex-dec.h
+ * include/asm-generic/mutex-dec.h
*
* Generic implementation of the mutex fastpath, based on atomic
* decrement/increment.
diff --git a/include/asm-generic/mutex-null.h b/include/asm-generic/mutex-null.h
index 254a126ede5c..e1bbbc72b6a2 100644
--- a/include/asm-generic/mutex-null.h
+++ b/include/asm-generic/mutex-null.h
@@ -1,5 +1,5 @@
/*
- * asm-generic/mutex-null.h
+ * include/asm-generic/mutex-null.h
*
* Generic implementation of the mutex fastpath, based on NOP :-)
*
diff --git a/include/asm-generic/mutex-xchg.h b/include/asm-generic/mutex-xchg.h
index 32a2100c1aeb..6a7e8c141b53 100644
--- a/include/asm-generic/mutex-xchg.h
+++ b/include/asm-generic/mutex-xchg.h
@@ -1,5 +1,5 @@
/*
- * asm-generic/mutex-xchg.h
+ * include/asm-generic/mutex-xchg.h
*
* Generic implementation of the mutex fastpath, based on xchg().
*
diff --git a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h
index 6d45ee5472af..196376262240 100644
--- a/include/asm-generic/percpu.h
+++ b/include/asm-generic/percpu.h
@@ -15,7 +15,7 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*({ \
- extern int simple_indentifier_##var(void); \
+ extern int simple_identifier_##var(void); \
RELOC_HIDE(&per_cpu__##var, __per_cpu_offset[cpu]); }))
#define __get_cpu_var(var) per_cpu(var, smp_processor_id())
#define __raw_get_cpu_var(var) per_cpu(var, raw_smp_processor_id())
diff --git a/include/asm-generic/pgtable.h b/include/asm-generic/pgtable.h
index 349260cd86ed..9d774d07d95b 100644
--- a/include/asm-generic/pgtable.h
+++ b/include/asm-generic/pgtable.h
@@ -15,19 +15,11 @@
* Note: the old pte is known to not be writable, so we don't need to
* worry about dirty bits etc getting lost.
*/
-#ifndef __HAVE_ARCH_SET_PTE_ATOMIC
#define ptep_establish(__vma, __address, __ptep, __entry) \
do { \
set_pte_at((__vma)->vm_mm, (__address), __ptep, __entry); \
flush_tlb_page(__vma, __address); \
} while (0)
-#else /* __HAVE_ARCH_SET_PTE_ATOMIC */
-#define ptep_establish(__vma, __address, __ptep, __entry) \
-do { \
- set_pte_atomic(__ptep, __entry); \
- flush_tlb_page(__vma, __address); \
-} while (0)
-#endif /* __HAVE_ARCH_SET_PTE_ATOMIC */
#endif
#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
@@ -112,8 +104,13 @@ do { \
})
#endif
-#ifndef __HAVE_ARCH_PTE_CLEAR_FULL
-#define pte_clear_full(__mm, __address, __ptep, __full) \
+/*
+ * Some architectures may be able to avoid expensive synchronization
+ * primitives when modifications are made to PTE's which are already
+ * not present, or in the process of an address space destruction.
+ */
+#ifndef __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL
+#define pte_clear_not_present_full(__mm, __address, __ptep, __full) \
do { \
pte_clear((__mm), (__address), (__ptep)); \
} while (0)
@@ -166,6 +163,26 @@ static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addres
#endif
/*
+ * A facility to provide lazy MMU batching. This allows PTE updates and
+ * page invalidations to be delayed until a call to leave lazy MMU mode
+ * is issued. Some architectures may benefit from doing this, and it is
+ * beneficial for both shadow and direct mode hypervisors, which may batch
+ * the PTE updates which happen during this window. Note that using this
+ * interface requires that read hazards be removed from the code. A read
+ * hazard could result in the direct mode hypervisor case, since the actual
+ * write to the page tables may not yet have taken place, so reads though
+ * a raw PTE pointer after it has been modified are not guaranteed to be
+ * up to date. This mode can only be entered and left under the protection of
+ * the page table locks for all page tables which may be modified. In the UP
+ * case, this is required so that preemption is disabled, and in the SMP case,
+ * it must synchronize the delayed page table writes properly on other CPUs.
+ */
+#ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE
+#define arch_enter_lazy_mmu_mode() do {} while (0)
+#define arch_leave_lazy_mmu_mode() do {} while (0)
+#endif
+
+/*
* When walking page tables, get the address of the next boundary,
* or the end address of the range if that comes earlier. Although no
* vma end wraps to 0, rounded up __boundary may wrap to 0 throughout.
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h
index 4087037a4225..d3238f1f70a6 100644
--- a/include/asm-generic/rtc.h
+++ b/include/asm-generic/rtc.h
@@ -1,5 +1,5 @@
/*
- * inclue/asm-generic/rtc.h
+ * include/asm-generic/rtc.h
*
* Author: Tom Rini <trini@mvista.com>
*
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 867d9008fafa..f490e43a90b9 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -1,4 +1,4 @@
-/* asm-generic/tlb.h
+/* include/asm-generic/tlb.h
*
* Generic TLB shootdown code
*
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 253ae1328271..9d0d11c180d9 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -118,15 +118,19 @@
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
*(__ksymtab_strings) \
} \
- __end_rodata = .; \
- . = ALIGN(4096); \
\
/* Built-in module parameters. */ \
__param : AT(ADDR(__param) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__start___param) = .; \
*(__param) \
VMLINUX_SYMBOL(__stop___param) = .; \
- }
+ } \
+ \
+ /* Unwind data binary search table */ \
+ EH_FRAME_HDR \
+ \
+ __end_rodata = .; \
+ . = ALIGN(4096);
#define SECURITY_INIT \
.security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
@@ -157,6 +161,18 @@
*(.kprobes.text) \
VMLINUX_SYMBOL(__kprobes_text_end) = .;
+#ifdef CONFIG_STACK_UNWIND
+ /* Unwind data binary search table */
+#define EH_FRAME_HDR \
+ .eh_frame_hdr : AT(ADDR(.eh_frame_hdr) - LOAD_OFFSET) { \
+ VMLINUX_SYMBOL(__start_unwind_hdr) = .; \
+ *(.eh_frame_hdr) \
+ VMLINUX_SYMBOL(__end_unwind_hdr) = .; \
+ }
+#else
+#define EH_FRAME_HDR
+#endif
+
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to
the beginning of the section so we begin them at 0. */
diff --git a/include/asm-h8300/keyboard.h b/include/asm-h8300/keyboard.h
index fbad65e8a5c0..90efbd655390 100644
--- a/include/asm-h8300/keyboard.h
+++ b/include/asm-h8300/keyboard.h
@@ -18,14 +18,6 @@
#define kbd_enable_irq(x...) do {;} while (0)
#define kbd_disable_irq(x...) do {;} while (0)
-
-/* needed if MAGIC_SYSRQ is enabled for serial console */
-#ifndef SYSRQ_KEY
-#define SYSRQ_KEY ((unsigned char)(-1))
-#define kbd_sysrq_xlate ((unsigned char *)NULL)
-#endif
-
-
#endif /* _H8300_KEYBOARD_H */
diff --git a/include/asm-h8300/unistd.h b/include/asm-h8300/unistd.h
index 226dd596c2da..747788d629ae 100644
--- a/include/asm-h8300/unistd.h
+++ b/include/asm-h8300/unistd.h
@@ -295,14 +295,14 @@
#ifdef __KERNEL__
#define NR_syscalls 289
+#include <linux/err.h>
-
-/* user-visible error numbers are in the range -1 - -122: see
+/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
<asm-m68k/errno.h> */
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
/* avoid using res which is declared to be in register d0; \
errno might expand to a function call and clobber it. */ \
int __err = -(res); \
@@ -485,57 +485,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e, ftype f) \
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall0(int,pause)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall1(int,delete_module,const char *,name)
-
-static inline pid_t wait(int * wait_stat)
-{
- return waitpid(-1,wait_stat,0);
-}
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(char *name, char **argv, char **envp,
- int dummy, ...);
-asmlinkage int sys_pipe(unsigned long *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*/
diff --git a/include/asm-i386/alternative-asm.i b/include/asm-i386/alternative-asm.i
index 6c47e3b9484b..f0510209ccbe 100644
--- a/include/asm-i386/alternative-asm.i
+++ b/include/asm-i386/alternative-asm.i
@@ -1,5 +1,3 @@
-#include <linux/config.h>
-
#ifdef CONFIG_SMP
.macro LOCK_PREFIX
1: lock
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index 3a42b7d6fc92..b9529578fc37 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -98,7 +98,7 @@ extern void sync_Arb_IDs (void);
extern void init_bsp_APIC (void);
extern void setup_local_APIC (void);
extern void init_apic_mappings (void);
-extern void smp_local_timer_interrupt (struct pt_regs * regs);
+extern void smp_local_timer_interrupt (void);
extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void);
extern int APIC_init_uniprocessor (void);
@@ -107,7 +107,7 @@ extern void enable_APIC_timer(void);
extern void enable_NMI_through_LVT0 (void * dummy);
-void smp_send_timer_broadcast_ipi(struct pt_regs *regs);
+void smp_send_timer_broadcast_ipi(void);
void switch_APIC_timer_to_ipi(void *cpumask);
void switch_ipi_to_APIC_timer(void *cpumask);
#define ARCH_APICTIMER_STOPS_ON_C3 1
diff --git a/include/asm-i386/arch_hooks.h b/include/asm-i386/arch_hooks.h
index 238cf4275b96..a8c1fca9726d 100644
--- a/include/asm-i386/arch_hooks.h
+++ b/include/asm-i386/arch_hooks.h
@@ -14,7 +14,7 @@
extern void init_ISA_irqs(void);
extern void apic_intr_init(void);
extern void smp_intr_init(void);
-extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t timer_interrupt(int irq, void *dev_id);
/* these are the defined hooks */
extern void intr_init_hook(void);
diff --git a/include/asm-i386/bugs.h b/include/asm-i386/bugs.h
index 2a9e4ee5904d..592ffeeda45e 100644
--- a/include/asm-i386/bugs.h
+++ b/include/asm-i386/bugs.h
@@ -189,6 +189,6 @@ static void __init check_bugs(void)
check_fpu();
check_hlt();
check_popad();
- system_utsname.machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
+ init_utsname()->machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86);
alternative_instructions();
}
diff --git a/include/asm-i386/dma-mapping.h b/include/asm-i386/dma-mapping.h
index 576ae01d71c8..81999a3ebe7c 100644
--- a/include/asm-i386/dma-mapping.h
+++ b/include/asm-i386/dma-mapping.h
@@ -21,7 +21,7 @@ static inline dma_addr_t
dma_map_single(struct device *dev, void *ptr, size_t size,
enum dma_data_direction direction)
{
- BUG_ON(direction == DMA_NONE);
+ BUG_ON(!valid_dma_direction(direction));
WARN_ON(size == 0);
flush_write_buffers();
return virt_to_phys(ptr);
@@ -31,7 +31,7 @@ static inline void
dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
enum dma_data_direction direction)
{
- BUG_ON(direction == DMA_NONE);
+ BUG_ON(!valid_dma_direction(direction));
}
static inline int
@@ -40,7 +40,7 @@ dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
{
int i;
- BUG_ON(direction == DMA_NONE);
+ BUG_ON(!valid_dma_direction(direction));
WARN_ON(nents == 0 || sg[0].length == 0);
for (i = 0; i < nents; i++ ) {
@@ -57,7 +57,7 @@ static inline dma_addr_t
dma_map_page(struct device *dev, struct page *page, unsigned long offset,
size_t size, enum dma_data_direction direction)
{
- BUG_ON(direction == DMA_NONE);
+ BUG_ON(!valid_dma_direction(direction));
return page_to_phys(page) + offset;
}
@@ -65,7 +65,7 @@ static inline void
dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
enum dma_data_direction direction)
{
- BUG_ON(direction == DMA_NONE);
+ BUG_ON(!valid_dma_direction(direction));
}
@@ -73,7 +73,7 @@ static inline void
dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
enum dma_data_direction direction)
{
- BUG_ON(direction == DMA_NONE);
+ BUG_ON(!valid_dma_direction(direction));
}
static inline void
diff --git a/include/asm-i386/elf.h b/include/asm-i386/elf.h
index db4344d9f73f..3a05436f31c0 100644
--- a/include/asm-i386/elf.h
+++ b/include/asm-i386/elf.h
@@ -112,7 +112,7 @@ typedef struct user_fxsr_struct elf_fpxregset_t;
For the moment, we have only optimizations for the Intel generations,
but that could change... */
-#define ELF_PLATFORM (system_utsname.machine)
+#define ELF_PLATFORM (utsname()->machine)
#define SET_PERSONALITY(ex, ibcs2) do { } while (0)
diff --git a/include/asm-i386/floppy.h b/include/asm-i386/floppy.h
index 359ead60b718..44ef2f55a8e9 100644
--- a/include/asm-i386/floppy.h
+++ b/include/asm-i386/floppy.h
@@ -51,7 +51,7 @@ static char *virtual_dma_addr;
static int virtual_dma_mode;
static int doing_pdma;
-static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t floppy_hardint(int irq, void *dev_id)
{
register unsigned char st;
@@ -63,7 +63,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
static int dma_wait=0;
#endif
if (!doing_pdma)
- return floppy_interrupt(irq, dev_id, regs);
+ return floppy_interrupt(irq, dev_id);
#ifdef TRACE_FLPY_INT
if(!calls)
@@ -106,7 +106,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
dma_wait=0;
#endif
doing_pdma = 0;
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
#ifdef TRACE_FLPY_INT
diff --git a/include/asm-i386/frame.i b/include/asm-i386/frame.i
index 4d68ddce18b6..03620251ae17 100644
--- a/include/asm-i386/frame.i
+++ b/include/asm-i386/frame.i
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <asm/dwarf2.h>
/* The annotation hides the frame from the unwinder and makes it look
diff --git a/include/asm-i386/hpet.h b/include/asm-i386/hpet.h
index af5d435519d1..e47be9a56cc2 100644
--- a/include/asm-i386/hpet.h
+++ b/include/asm-i386/hpet.h
@@ -108,7 +108,7 @@ extern int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned ch
extern int hpet_set_periodic_freq(unsigned long freq);
extern int hpet_rtc_dropped_irq(void);
extern int hpet_rtc_timer_init(void);
-extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id);
#endif /* CONFIG_HPET_EMULATE_RTC */
#endif /* CONFIG_HPET_TIMER */
#endif /* _I386_HPET_H */
diff --git a/include/asm-i386/hw_irq.h b/include/asm-i386/hw_irq.h
index 87e5a351d881..0bedbdf5e907 100644
--- a/include/asm-i386/hw_irq.h
+++ b/include/asm-i386/hw_irq.h
@@ -17,8 +17,6 @@
#include <asm/irq.h>
#include <asm/sections.h>
-struct hw_interrupt_type;
-
#define NMI_VECTOR 0x02
/*
@@ -28,10 +26,6 @@ struct hw_interrupt_type;
* Interrupt entry/exit code at both C and assembly level
*/
-extern u8 irq_vector[NR_IRQ_VECTORS];
-#define IO_APIC_VECTOR(irq) (irq_vector[irq])
-#define AUTO_ASSIGN -1
-
extern void (*interrupt[NR_IRQS])(void);
#ifdef CONFIG_SMP
@@ -44,7 +38,7 @@ fastcall void call_function_interrupt(void);
fastcall void apic_timer_interrupt(void);
fastcall void error_interrupt(void);
fastcall void spurious_interrupt(void);
-fastcall void thermal_interrupt(struct pt_regs *);
+fastcall void thermal_interrupt(void);
#define platform_legacy_irq(irq) ((irq) < 16)
#endif
diff --git a/include/asm-i386/hypertransport.h b/include/asm-i386/hypertransport.h
new file mode 100644
index 000000000000..c16c6ff4bdd7
--- /dev/null
+++ b/include/asm-i386/hypertransport.h
@@ -0,0 +1,42 @@
+#ifndef ASM_HYPERTRANSPORT_H
+#define ASM_HYPERTRANSPORT_H
+
+/*
+ * Constants for x86 Hypertransport Interrupts.
+ */
+
+#define HT_IRQ_LOW_BASE 0xf8000000
+
+#define HT_IRQ_LOW_VECTOR_SHIFT 16
+#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000
+#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
+
+#define HT_IRQ_LOW_DEST_ID_SHIFT 8
+#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00
+#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
+
+#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000
+#define HT_IRQ_LOW_DM_LOGICAL 0x0000040
+
+#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000
+#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020
+
+
+#define HT_IRQ_LOW_MT_FIXED 0x0000000
+#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004
+#define HT_IRQ_LOW_MT_SMI 0x0000008
+#define HT_IRQ_LOW_MT_NMI 0x000000c
+#define HT_IRQ_LOW_MT_INIT 0x0000010
+#define HT_IRQ_LOW_MT_STARTUP 0x0000014
+#define HT_IRQ_LOW_MT_EXTINT 0x0000018
+#define HT_IRQ_LOW_MT_LINT1 0x000008c
+#define HT_IRQ_LOW_MT_LINT0 0x0000098
+
+#define HT_IRQ_LOW_IRQ_MASKED 0x0000001
+
+
+#define HT_IRQ_HIGH_DEST_ID_SHIFT 0
+#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff
+#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
+
+#endif /* ASM_HYPERTRANSPORT_H */
diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h
index b3724fe93ff1..68df0dc3ab8f 100644
--- a/include/asm-i386/io.h
+++ b/include/asm-i386/io.h
@@ -224,33 +224,6 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, int
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void __force *)(b),(c),(d))
-/**
- * check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the mmio address io_addr. This
- * address should have been obtained by ioremap.
- * Returns 1 on a match.
- */
-
-static inline int check_signature(volatile void __iomem * io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
/*
* Cache management
*
diff --git a/include/asm-i386/io_apic.h b/include/asm-i386/io_apic.h
index 5d309275a1dc..276ea7e8144a 100644
--- a/include/asm-i386/io_apic.h
+++ b/include/asm-i386/io_apic.h
@@ -12,46 +12,6 @@
#ifdef CONFIG_X86_IO_APIC
-#ifdef CONFIG_PCI_MSI
-static inline int use_pci_vector(void) {return 1;}
-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
-static inline void end_edge_ioapic_vector (unsigned int vector) { }
-#define startup_level_ioapic startup_level_ioapic_vector
-#define shutdown_level_ioapic mask_IO_APIC_vector
-#define enable_level_ioapic unmask_IO_APIC_vector
-#define disable_level_ioapic mask_IO_APIC_vector
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
-#define end_level_ioapic end_level_ioapic_vector
-#define set_ioapic_affinity set_ioapic_affinity_vector
-
-#define startup_edge_ioapic startup_edge_ioapic_vector
-#define shutdown_edge_ioapic disable_edge_ioapic_vector
-#define enable_edge_ioapic unmask_IO_APIC_vector
-#define disable_edge_ioapic disable_edge_ioapic_vector
-#define ack_edge_ioapic ack_edge_ioapic_vector
-#define end_edge_ioapic end_edge_ioapic_vector
-#else
-static inline int use_pci_vector(void) {return 0;}
-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
-static inline void end_edge_ioapic_irq (unsigned int irq) { }
-#define startup_level_ioapic startup_level_ioapic_irq
-#define shutdown_level_ioapic mask_IO_APIC_irq
-#define enable_level_ioapic unmask_IO_APIC_irq
-#define disable_level_ioapic mask_IO_APIC_irq
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
-#define end_level_ioapic end_level_ioapic_irq
-#define set_ioapic_affinity set_ioapic_affinity_irq
-
-#define startup_edge_ioapic startup_edge_ioapic_irq
-#define shutdown_edge_ioapic disable_edge_ioapic_irq
-#define enable_edge_ioapic unmask_IO_APIC_irq
-#define disable_edge_ioapic disable_edge_ioapic_irq
-#define ack_edge_ioapic ack_edge_ioapic_irq
-#define end_edge_ioapic end_edge_ioapic_irq
-#endif
-
#define IO_APIC_BASE(idx) \
((volatile int *)(__fix_to_virt(FIX_IO_APIC_BASE_0 + idx) \
+ (mp_ioapics[idx].mpc_apicaddr & ~PAGE_MASK)))
@@ -219,6 +179,4 @@ extern int (*ioapic_renumber_irq)(int ioapic, int irq);
static inline void disable_ioapic_setup(void) { }
#endif
-extern int assign_irq_vector(int irq);
-
#endif
diff --git a/include/asm-i386/irq_regs.h b/include/asm-i386/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-i386/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-i386/mach-default/do_timer.h
index 6312c3e79814..7d606e3364ae 100644
--- a/include/asm-i386/mach-default/do_timer.h
+++ b/include/asm-i386/mach-default/do_timer.h
@@ -14,11 +14,11 @@
* timer interrupt as a means of triggering reschedules etc.
**/
-static inline void do_timer_interrupt_hook(struct pt_regs *regs)
+static inline void do_timer_interrupt_hook(void)
{
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode_vm(regs));
+ update_process_times(user_mode_vm(get_irq_regs()));
#endif
/*
* In the SMP case we use the local APIC timer interrupt to do the
@@ -26,10 +26,10 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs)
* system, in that case we have to call the local interrupt handler.
*/
#ifndef CONFIG_X86_LOCAL_APIC
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#else
if (!using_apic_timer)
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
#endif
}
diff --git a/include/asm-i386/mach-default/irq_vectors_limits.h b/include/asm-i386/mach-default/irq_vectors_limits.h
index b330026e6f7f..7f161e760be6 100644
--- a/include/asm-i386/mach-default/irq_vectors_limits.h
+++ b/include/asm-i386/mach-default/irq_vectors_limits.h
@@ -1,10 +1,6 @@
#ifndef _ASM_IRQ_VECTORS_LIMITS_H
#define _ASM_IRQ_VECTORS_LIMITS_H
-#ifdef CONFIG_PCI_MSI
-#define NR_IRQS FIRST_SYSTEM_VECTOR
-#define NR_IRQ_VECTORS NR_IRQS
-#else
#ifdef CONFIG_X86_IO_APIC
#define NR_IRQS 224
# if (224 >= 32 * NR_CPUS)
@@ -16,6 +12,5 @@
#define NR_IRQS 16
#define NR_IRQ_VECTORS NR_IRQS
#endif
-#endif
#endif /* _ASM_IRQ_VECTORS_LIMITS_H */
diff --git a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h
index a81b05961595..ef0671e5d5c5 100644
--- a/include/asm-i386/mach-summit/mach_apic.h
+++ b/include/asm-i386/mach-summit/mach_apic.h
@@ -88,7 +88,7 @@ static inline void clustered_apic_check(void)
static inline int apicid_to_node(int logical_apicid)
{
- return logical_apicid >> 5; /* 2 clusterids per CEC */
+ return apicid_2_node[hard_smp_processor_id()];
}
/* Mapping from cpu number to logical apicid */
diff --git a/include/asm-i386/mach-visws/do_timer.h b/include/asm-i386/mach-visws/do_timer.h
index 95568e6ca91c..21cd696d4d0f 100644
--- a/include/asm-i386/mach-visws/do_timer.h
+++ b/include/asm-i386/mach-visws/do_timer.h
@@ -4,14 +4,14 @@
#include <asm/i8259.h>
#include "cobalt.h"
-static inline void do_timer_interrupt_hook(struct pt_regs *regs)
+static inline void do_timer_interrupt_hook(void)
{
/* Clear the interrupt */
co_cpu_write(CO_CPU_STAT,co_cpu_read(CO_CPU_STAT) & ~CO_STAT_TIMEINTR);
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode_vm(regs));
+ update_process_times(user_mode_vm(irq_regs));
#endif
/*
* In the SMP case we use the local APIC timer interrupt to do the
@@ -19,10 +19,10 @@ static inline void do_timer_interrupt_hook(struct pt_regs *regs)
* system, in that case we have to call the local interrupt handler.
*/
#ifndef CONFIG_X86_LOCAL_APIC
- profile_tick(CPU_PROFILING, regs);
+ profile_tick(CPU_PROFILING);
#else
if (!using_apic_timer)
- smp_local_timer_interrupt(regs);
+ smp_local_timer_interrupt();
#endif
}
diff --git a/include/asm-i386/mach-voyager/do_timer.h b/include/asm-i386/mach-voyager/do_timer.h
index eaf518098981..04e69c104a74 100644
--- a/include/asm-i386/mach-voyager/do_timer.h
+++ b/include/asm-i386/mach-voyager/do_timer.h
@@ -1,14 +1,14 @@
/* defines for inline arch setup functions */
#include <asm/voyager.h>
-static inline void do_timer_interrupt_hook(struct pt_regs *regs)
+static inline void do_timer_interrupt_hook(void)
{
- do_timer(regs);
+ do_timer(1);
#ifndef CONFIG_SMP
- update_process_times(user_mode_vm(regs));
+ update_process_times(user_mode_vm(irq_regs));
#endif
- voyager_timer_interrupt(regs);
+ voyager_timer_interrupt();
}
static inline int do_timer_overflow(int count)
diff --git a/include/asm-i386/mca_dma.h b/include/asm-i386/mca_dma.h
index 4b3b526c5a3f..fbb1f3b71279 100644
--- a/include/asm-i386/mca_dma.h
+++ b/include/asm-i386/mca_dma.h
@@ -181,7 +181,7 @@ static __inline__ void mca_set_dma_io(unsigned int dmanr, unsigned int io_addr)
* @mode: mode to set
*
* The DMA controller supports several modes. The mode values you can
- * set are :
+ * set are-
*
* %MCA_DMA_MODE_READ when reading from the DMA device.
*
@@ -190,7 +190,6 @@ static __inline__ void mca_set_dma_io(unsigned int dmanr, unsigned int io_addr)
* %MCA_DMA_MODE_IO to do DMA to or from an I/O port.
*
* %MCA_DMA_MODE_16 to do 16bit transfers.
- *
*/
static __inline__ void mca_set_dma_mode(unsigned int dmanr, unsigned int mode)
diff --git a/include/asm-i386/msi.h b/include/asm-i386/msi.h
deleted file mode 100644
index b11c4b7dfaef..000000000000
--- a/include/asm-i386/msi.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <mach_apic.h>
-
-#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
-#define MSI_TARGET_CPU_SHIFT 12
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
- msi_register(&msi_apic_ops);
- return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-i386/msidef.h b/include/asm-i386/msidef.h
new file mode 100644
index 000000000000..5b8acddb70fb
--- /dev/null
+++ b/include/asm-i386/msidef.h
@@ -0,0 +1,47 @@
+#ifndef ASM_MSIDEF_H
+#define ASM_MSIDEF_H
+
+/*
+ * Constants for Intel APIC based MSI messages.
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT 0
+#define MSI_DATA_VECTOR_MASK 0x000000ff
+#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT 8
+#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
+#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT 14
+#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT 15
+#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_BASE_HI 0
+#define MSI_ADDR_BASE_LO 0xfee00000
+
+#define MSI_ADDR_DEST_MODE_SHIFT 2
+#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
+#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT 3
+#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
+#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
+
+#define MSI_ADDR_DEST_ID_SHIFT 12
+#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
+#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
+
+#endif /* ASM_MSIDEF_H */
diff --git a/include/asm-i386/nmi.h b/include/asm-i386/nmi.h
index 303bcd4592bb..269d315719ca 100644
--- a/include/asm-i386/nmi.h
+++ b/include/asm-i386/nmi.h
@@ -36,4 +36,10 @@ extern unsigned int nmi_watchdog;
#define NMI_LOCAL_APIC 2
#define NMI_INVALID 3
+struct ctl_table;
+struct file;
+extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
+ void __user *, size_t *, loff_t *);
+extern int unknown_nmi_panic;
+
#endif /* ASM_NMI_H */
diff --git a/include/asm-i386/pgtable-2level.h b/include/asm-i386/pgtable-2level.h
index 201c86a6711e..8d8d3b9ecdb0 100644
--- a/include/asm-i386/pgtable-2level.h
+++ b/include/asm-i386/pgtable-2level.h
@@ -16,6 +16,7 @@
#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
#define set_pte_atomic(pteptr, pteval) set_pte(pteptr,pteval)
+#define set_pte_present(mm,addr,ptep,pteval) set_pte_at(mm,addr,ptep,pteval)
#define set_pmd(pmdptr, pmdval) (*(pmdptr) = (pmdval))
#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
diff --git a/include/asm-i386/pgtable-3level.h b/include/asm-i386/pgtable-3level.h
index 0d899173232e..c2d701ea35be 100644
--- a/include/asm-i386/pgtable-3level.h
+++ b/include/asm-i386/pgtable-3level.h
@@ -58,7 +58,21 @@ static inline void set_pte(pte_t *ptep, pte_t pte)
}
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-#define __HAVE_ARCH_SET_PTE_ATOMIC
+/*
+ * Since this is only called on user PTEs, and the page fault handler
+ * must handle the already racy situation of simultaneous page faults,
+ * we are justified in merely clearing the PTE present bit, followed
+ * by a set. The ordering here is important.
+ */
+static inline void set_pte_present(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte)
+{
+ ptep->pte_low = 0;
+ smp_wmb();
+ ptep->pte_high = pte.pte_high;
+ smp_wmb();
+ ptep->pte_low = pte.pte_low;
+}
+
#define set_pte_atomic(pteptr,pteval) \
set_64bit((unsigned long long *)(pteptr),pte_val(pteval))
#define set_pmd(pmdptr,pmdval) \
diff --git a/include/asm-i386/pgtable.h b/include/asm-i386/pgtable.h
index 541b3e234335..7d398f493dde 100644
--- a/include/asm-i386/pgtable.h
+++ b/include/asm-i386/pgtable.h
@@ -247,6 +247,23 @@ static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return p
#endif
/*
+ * Rules for using pte_update - it must be called after any PTE update which
+ * has not been done using the set_pte / clear_pte interfaces. It is used by
+ * shadow mode hypervisors to resynchronize the shadow page tables. Kernel PTE
+ * updates should either be sets, clears, or set_pte_atomic for P->P
+ * transitions, which means this hook should only be called for user PTEs.
+ * This hook implies a P->P protection or access change has taken place, which
+ * requires a subsequent TLB flush. The notification can optionally be delayed
+ * until the TLB flush event by using the pte_update_defer form of the
+ * interface, but care must be taken to assure that the flush happens while
+ * still holding the same page table lock so that the shadow and primary pages
+ * do not become out of sync on SMP.
+ */
+#define pte_update(mm, addr, ptep) do { } while (0)
+#define pte_update_defer(mm, addr, ptep) do { } while (0)
+
+
+/*
* We only update the dirty/accessed state if we set
* the dirty bit by hand in the kernel, since the hardware
* will do the accessed bit for us, and we don't want to
@@ -258,25 +275,54 @@ static inline pte_t pte_mkhuge(pte_t pte) { (pte).pte_low |= _PAGE_PSE; return p
do { \
if (dirty) { \
(ptep)->pte_low = (entry).pte_low; \
+ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \
flush_tlb_page(vma, address); \
} \
} while (0)
+/*
+ * We don't actually have these, but we want to advertise them so that
+ * we can encompass the flush here.
+ */
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
-static inline int ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
- if (!pte_dirty(*ptep))
- return 0;
- return test_and_clear_bit(_PAGE_BIT_DIRTY, &ptep->pte_low);
-}
-
#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
-static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr, pte_t *ptep)
-{
- if (!pte_young(*ptep))
- return 0;
- return test_and_clear_bit(_PAGE_BIT_ACCESSED, &ptep->pte_low);
-}
+
+/*
+ * Rules for using ptep_establish: the pte MUST be a user pte, and
+ * must be a present->present transition.
+ */
+#define __HAVE_ARCH_PTEP_ESTABLISH
+#define ptep_establish(vma, address, ptep, pteval) \
+do { \
+ set_pte_present((vma)->vm_mm, address, ptep, pteval); \
+ flush_tlb_page(vma, address); \
+} while (0)
+
+#define __HAVE_ARCH_PTEP_CLEAR_DIRTY_FLUSH
+#define ptep_clear_flush_dirty(vma, address, ptep) \
+({ \
+ int __dirty; \
+ __dirty = pte_dirty(*(ptep)); \
+ if (__dirty) { \
+ clear_bit(_PAGE_BIT_DIRTY, &(ptep)->pte_low); \
+ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \
+ flush_tlb_page(vma, address); \
+ } \
+ __dirty; \
+})
+
+#define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
+#define ptep_clear_flush_young(vma, address, ptep) \
+({ \
+ int __young; \
+ __young = pte_young(*(ptep)); \
+ if (__young) { \
+ clear_bit(_PAGE_BIT_ACCESSED, &(ptep)->pte_low); \
+ pte_update_defer((vma)->vm_mm, (addr), (ptep)); \
+ flush_tlb_page(vma, address); \
+ } \
+ __young; \
+})
#define __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL
static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long addr, pte_t *ptep, int full)
@@ -295,6 +341,7 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, unsigned long
static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
{
clear_bit(_PAGE_BIT_RW, &ptep->pte_low);
+ pte_update(mm, addr, ptep);
}
/*
@@ -426,6 +473,13 @@ extern pte_t *lookup_address(unsigned long address);
#define pte_unmap_nested(pte) do { } while (0)
#endif
+/* Clear a kernel PTE and flush it from the TLB */
+#define kpte_clear_flush(ptep, vaddr) \
+do { \
+ pte_clear(&init_mm, vaddr, ptep); \
+ __flush_tlb_one(vaddr); \
+} while (0)
+
/*
* The i386 doesn't have any external MMU info: the kernel page
* tables contain all the necessary information.
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index 2277127696d2..e0ddca94d50c 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -306,6 +306,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
: :"a" (eax), "c" (ecx));
}
+extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
+
/* from system description table in BIOS. Mostly for MCA use, but
others may find it useful. */
extern unsigned int machine_id;
diff --git a/include/asm-i386/ptrace.h b/include/asm-i386/ptrace.h
index a4a0e5207db5..d505f501077a 100644
--- a/include/asm-i386/ptrace.h
+++ b/include/asm-i386/ptrace.h
@@ -47,7 +47,10 @@ static inline int user_mode_vm(struct pt_regs *regs)
{
return ((regs->xcs & SEGMENT_RPL_MASK) | (regs->eflags & VM_MASK)) >= USER_RPL;
}
+
#define instruction_pointer(regs) ((regs)->eip)
+#define regs_return_value(regs) ((regs)->eax)
+
extern unsigned long profile_pc(struct pt_regs *regs);
#endif /* __KERNEL__ */
diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h
index e63b6a68f04c..4e34a468c383 100644
--- a/include/asm-i386/semaphore.h
+++ b/include/asm-i386/semaphore.h
@@ -126,7 +126,7 @@ static inline int down_interruptible(struct semaphore * sem)
"lea %1,%%eax\n\t"
"call __down_failed_interruptible\n"
"2:"
- :"=a" (result), "+m" (sem->count)
+ :"=&a" (result), "+m" (sem->count)
:
:"memory");
return result;
@@ -148,7 +148,7 @@ static inline int down_trylock(struct semaphore * sem)
"lea %1,%%eax\n\t"
"call __down_failed_trylock\n\t"
"2:\n"
- :"=a" (result), "+m" (sem->count)
+ :"=&a" (result), "+m" (sem->count)
:
:"memory");
return result;
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 32ac8c91d5c5..bd59c1508e71 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -82,6 +82,7 @@ static inline int hard_smp_processor_id(void)
#endif
#endif
+extern int safe_smp_processor_id(void);
extern int __cpu_disable(void);
extern void __cpu_die(unsigned int cpu);
extern unsigned int num_processors;
@@ -90,6 +91,7 @@ extern unsigned int num_processors;
#else /* CONFIG_SMP */
+#define safe_smp_processor_id() 0
#define cpu_physical_id(cpu) boot_cpu_physical_apicid
#define NO_PROC_ID 0xFF /* No processor magic marker */
@@ -97,6 +99,9 @@ extern unsigned int num_processors;
#endif
#ifndef __ASSEMBLY__
+
+extern u8 apicid_2_node[];
+
#ifdef CONFIG_X86_LOCAL_APIC
static __inline int logical_smp_processor_id(void)
{
diff --git a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h
index b0b3043f05e1..c18b71fae6b3 100644
--- a/include/asm-i386/spinlock.h
+++ b/include/asm-i386/spinlock.h
@@ -205,4 +205,8 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
: "+m" (rw->lock) : : "memory");
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index 6adbd9b1ae88..978d09596130 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -74,6 +74,7 @@ static inline int node_to_first_cpu(int node)
#define SD_NODE_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 8, \
.max_interval = 32, \
diff --git a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
index 54d905ebc63d..eef5133b9ce2 100644
--- a/include/asm-i386/uaccess.h
+++ b/include/asm-i386/uaccess.h
@@ -404,20 +404,6 @@ unsigned long __must_check __copy_from_user_ll_nocache_nozero(void *to,
* anything, so this is accurate.
*/
-/**
- * __copy_to_user: - Copy a block of data into user space, with less checking.
- * @to: Destination address, in user space.
- * @from: Source address, in kernel space.
- * @n: Number of bytes to copy.
- *
- * Context: User context only. This function may sleep.
- *
- * Copy data from kernel space to user space. Caller must check
- * the specified block with access_ok() before calling this function.
- *
- * Returns number of bytes that could not be copied.
- * On success, this will be zero.
- */
static __always_inline unsigned long __must_check
__copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
{
@@ -439,35 +425,27 @@ __copy_to_user_inatomic(void __user *to, const void *from, unsigned long n)
return __copy_to_user_ll(to, from, n);
}
-static __always_inline unsigned long __must_check
-__copy_to_user(void __user *to, const void *from, unsigned long n)
-{
- might_sleep();
- return __copy_to_user_inatomic(to, from, n);
-}
-
/**
- * __copy_from_user: - Copy a block of data from user space, with less checking.
- * @to: Destination address, in kernel space.
- * @from: Source address, in user space.
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to: Destination address, in user space.
+ * @from: Source address, in kernel space.
* @n: Number of bytes to copy.
*
* Context: User context only. This function may sleep.
*
- * Copy data from user space to kernel space. Caller must check
+ * Copy data from kernel space to user space. Caller must check
* the specified block with access_ok() before calling this function.
*
* Returns number of bytes that could not be copied.
* On success, this will be zero.
- *
- * If some data could not be copied, this function will pad the copied
- * data to the requested size using zero bytes.
- *
- * An alternate version - __copy_from_user_inatomic() - may be called from
- * atomic context and will fail rather than sleep. In this case the
- * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h
- * for explanation of why this is needed.
*/
+static __always_inline unsigned long __must_check
+__copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+ might_sleep();
+ return __copy_to_user_inatomic(to, from, n);
+}
+
static __always_inline unsigned long
__copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
{
@@ -493,6 +471,29 @@ __copy_from_user_inatomic(void *to, const void __user *from, unsigned long n)
}
return __copy_from_user_ll_nozero(to, from, n);
}
+
+/**
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to: Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n: Number of bytes to copy.
+ *
+ * Context: User context only. This function may sleep.
+ *
+ * Copy data from user space to kernel space. Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ *
+ * An alternate version - __copy_from_user_inatomic() - may be called from
+ * atomic context and will fail rather than sleep. In this case the
+ * uncopied bytes will *NOT* be padded with zeros. See fs/filemap.h
+ * for explanation of why this is needed.
+ */
static __always_inline unsigned long
__copy_from_user(void *to, const void __user *from, unsigned long n)
{
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 565d0897b205..beeeaf6b054a 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -324,18 +324,20 @@
#define __NR_vmsplice 316
#define __NR_move_pages 317
#define __NR_getcpu 318
+#define __NR_epoll_pwait 319
#ifdef __KERNEL__
-#define NR_syscalls 319
+#define NR_syscalls 320
+#include <linux/err.h>
/*
- * user-visible error numbers are in the range -1 - -128: see
+ * user-visible error numbers are in the range -1 - -MAX_ERRNO: see
* <asm-i386/errno.h>
*/
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-(128 + 1))) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
errno = -(res); \
res = -1; \
} \
@@ -450,45 +452,6 @@ __syscall_return(type,__res); \
#define __ARCH_WANT_SYS_RT_SIGACTION
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-
-asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount);
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(struct pt_regs regs);
-asmlinkage int sys_clone(struct pt_regs regs);
-asmlinkage int sys_fork(struct pt_regs regs);
-asmlinkage int sys_vfork(struct pt_regs regs);
-asmlinkage int sys_pipe(unsigned long __user *fildes);
-asmlinkage long sys_iopl(unsigned long unused);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-i386/vic.h b/include/asm-i386/vic.h
index 4abfcfb91eb8..53100f353612 100644
--- a/include/asm-i386/vic.h
+++ b/include/asm-i386/vic.h
@@ -58,4 +58,4 @@ static const int VIC_CPI_Registers[] =
#define VIC_BOOT_INTERRUPT_MASK 0xfe
-extern void smp_vic_timer_interrupt(struct pt_regs *regs);
+extern void smp_vic_timer_interrupt(void);
diff --git a/include/asm-i386/voyager.h b/include/asm-i386/voyager.h
index aaf432dd7673..5b27838905b2 100644
--- a/include/asm-i386/voyager.h
+++ b/include/asm-i386/voyager.h
@@ -118,33 +118,33 @@ typedef struct voyager_module {
} voyager_module_t;
typedef struct voyager_eeprom_hdr {
- __u8 module_id[4] __attribute__((packed));
- __u8 version_id __attribute__((packed));
- __u8 config_id __attribute__((packed));
- __u16 boundry_id __attribute__((packed)); /* boundary scan id */
- __u16 ee_size __attribute__((packed)); /* size of EEPROM */
- __u8 assembly[11] __attribute__((packed)); /* assembly # */
- __u8 assembly_rev __attribute__((packed)); /* assembly rev */
- __u8 tracer[4] __attribute__((packed)); /* tracer number */
- __u16 assembly_cksum __attribute__((packed)); /* asm checksum */
- __u16 power_consump __attribute__((packed)); /* pwr requirements */
- __u16 num_asics __attribute__((packed)); /* number of asics */
- __u16 bist_time __attribute__((packed)); /* min. bist time */
- __u16 err_log_offset __attribute__((packed)); /* error log offset */
- __u16 scan_path_offset __attribute__((packed));/* scan path offset */
- __u16 cct_offset __attribute__((packed));
- __u16 log_length __attribute__((packed)); /* length of err log */
- __u16 xsum_end __attribute__((packed)); /* offset to end of
+ __u8 module_id[4];
+ __u8 version_id;
+ __u8 config_id;
+ __u16 boundry_id; /* boundary scan id */
+ __u16 ee_size; /* size of EEPROM */
+ __u8 assembly[11]; /* assembly # */
+ __u8 assembly_rev; /* assembly rev */
+ __u8 tracer[4]; /* tracer number */
+ __u16 assembly_cksum; /* asm checksum */
+ __u16 power_consump; /* pwr requirements */
+ __u16 num_asics; /* number of asics */
+ __u16 bist_time; /* min. bist time */
+ __u16 err_log_offset; /* error log offset */
+ __u16 scan_path_offset;/* scan path offset */
+ __u16 cct_offset;
+ __u16 log_length; /* length of err log */
+ __u16 xsum_end; /* offset to end of
checksum */
- __u8 reserved[4] __attribute__((packed));
- __u8 sflag __attribute__((packed)); /* starting sentinal */
- __u8 part_number[13] __attribute__((packed)); /* prom part number */
- __u8 version[10] __attribute__((packed)); /* version number */
- __u8 signature[8] __attribute__((packed));
- __u16 eeprom_chksum __attribute__((packed));
- __u32 data_stamp_offset __attribute__((packed));
- __u8 eflag __attribute__((packed)); /* ending sentinal */
-} voyager_eprom_hdr_t;
+ __u8 reserved[4];
+ __u8 sflag; /* starting sentinal */
+ __u8 part_number[13]; /* prom part number */
+ __u8 version[10]; /* version number */
+ __u8 signature[8];
+ __u16 eeprom_chksum;
+ __u32 data_stamp_offset;
+ __u8 eflag ; /* ending sentinal */
+} __attribute__((packed)) voyager_eprom_hdr_t;
@@ -155,30 +155,30 @@ typedef struct voyager_eeprom_hdr {
* in the module EPROMs. We really only care about the IDs and
* offsets */
typedef struct voyager_sp_table {
- __u8 asic_id __attribute__((packed));
- __u8 bypass_flag __attribute__((packed));
- __u16 asic_data_offset __attribute__((packed));
- __u16 config_data_offset __attribute__((packed));
-} voyager_sp_table_t;
+ __u8 asic_id;
+ __u8 bypass_flag;
+ __u16 asic_data_offset;
+ __u16 config_data_offset;
+} __attribute__((packed)) voyager_sp_table_t;
typedef struct voyager_jtag_table {
- __u8 icode[4] __attribute__((packed));
- __u8 runbist[4] __attribute__((packed));
- __u8 intest[4] __attribute__((packed));
- __u8 samp_preld[4] __attribute__((packed));
- __u8 ireg_len __attribute__((packed));
-} voyager_jtt_t;
+ __u8 icode[4];
+ __u8 runbist[4];
+ __u8 intest[4];
+ __u8 samp_preld[4];
+ __u8 ireg_len;
+} __attribute__((packed)) voyager_jtt_t;
typedef struct voyager_asic_data_table {
- __u8 jtag_id[4] __attribute__((packed));
- __u16 length_bsr __attribute__((packed));
- __u16 length_bist_reg __attribute__((packed));
- __u32 bist_clk __attribute__((packed));
- __u16 subaddr_bits __attribute__((packed));
- __u16 seed_bits __attribute__((packed));
- __u16 sig_bits __attribute__((packed));
- __u16 jtag_offset __attribute__((packed));
-} voyager_at_t;
+ __u8 jtag_id[4];
+ __u16 length_bsr;
+ __u16 length_bist_reg;
+ __u32 bist_clk;
+ __u16 subaddr_bits;
+ __u16 seed_bits;
+ __u16 sig_bits;
+ __u16 jtag_offset;
+} __attribute__((packed)) voyager_at_t;
/* Voyager Interrupt Controller (VIC) registers */
@@ -328,52 +328,52 @@ struct voyager_bios_info {
#define NUMBER_OF_POS_REGS 8
typedef struct {
- __u8 MC_Slot __attribute__((packed));
- __u8 POS_Values[NUMBER_OF_POS_REGS] __attribute__((packed));
-} MC_SlotInformation_t;
+ __u8 MC_Slot;
+ __u8 POS_Values[NUMBER_OF_POS_REGS];
+} __attribute__((packed)) MC_SlotInformation_t;
struct QuadDescription {
- __u8 Type __attribute__((packed)); /* for type 0 (DYADIC or MONADIC) all fields
+ __u8 Type; /* for type 0 (DYADIC or MONADIC) all fields
* will be zero except for slot */
- __u8 StructureVersion __attribute__((packed));
- __u32 CPI_BaseAddress __attribute__((packed));
- __u32 LARC_BankSize __attribute__((packed));
- __u32 LocalMemoryStateBits __attribute__((packed));
- __u8 Slot __attribute__((packed)); /* Processor slots 1 - 4 */
-};
+ __u8 StructureVersion;
+ __u32 CPI_BaseAddress;
+ __u32 LARC_BankSize;
+ __u32 LocalMemoryStateBits;
+ __u8 Slot; /* Processor slots 1 - 4 */
+} __attribute__((packed));
struct ProcBoardInfo {
- __u8 Type __attribute__((packed));
- __u8 StructureVersion __attribute__((packed));
- __u8 NumberOfBoards __attribute__((packed));
- struct QuadDescription QuadData[MAX_PROCESSOR_BOARDS] __attribute__((packed));
-};
+ __u8 Type;
+ __u8 StructureVersion;
+ __u8 NumberOfBoards;
+ struct QuadDescription QuadData[MAX_PROCESSOR_BOARDS];
+} __attribute__((packed));
struct CacheDescription {
- __u8 Level __attribute__((packed));
- __u32 TotalSize __attribute__((packed));
- __u16 LineSize __attribute__((packed));
- __u8 Associativity __attribute__((packed));
- __u8 CacheType __attribute__((packed));
- __u8 WriteType __attribute__((packed));
- __u8 Number_CPUs_SharedBy __attribute__((packed));
- __u8 Shared_CPUs_Hardware_IDs[MAX_SHARED_CPUS] __attribute__((packed));
+ __u8 Level;
+ __u32 TotalSize;
+ __u16 LineSize;
+ __u8 Associativity;
+ __u8 CacheType;
+ __u8 WriteType;
+ __u8 Number_CPUs_SharedBy;
+ __u8 Shared_CPUs_Hardware_IDs[MAX_SHARED_CPUS];
-};
+} __attribute__((packed));
struct CPU_Description {
- __u8 CPU_HardwareId __attribute__((packed));
- char *FRU_String __attribute__((packed));
- __u8 NumberOfCacheLevels __attribute__((packed));
- struct CacheDescription CacheLevelData[MAX_CACHE_LEVELS] __attribute__((packed));
-};
+ __u8 CPU_HardwareId;
+ char *FRU_String;
+ __u8 NumberOfCacheLevels;
+ struct CacheDescription CacheLevelData[MAX_CACHE_LEVELS];
+} __attribute__((packed));
struct CPU_Info {
- __u8 Type __attribute__((packed));
- __u8 StructureVersion __attribute__((packed));
- __u8 NumberOf_CPUs __attribute__((packed));
- struct CPU_Description CPU_Data[MAX_CPUS] __attribute__((packed));
-};
+ __u8 Type;
+ __u8 StructureVersion;
+ __u8 NumberOf_CPUs;
+ struct CPU_Description CPU_Data[MAX_CPUS];
+} __attribute__((packed));
/*
@@ -505,8 +505,8 @@ extern int voyager_memory_detect(int region, __u32 *addr, __u32 *length);
extern void voyager_smp_intr_init(void);
extern __u8 voyager_extended_cmos_read(__u16 cmos_address);
extern void voyager_smp_dump(void);
-extern void voyager_timer_interrupt(struct pt_regs *regs);
-extern void smp_local_timer_interrupt(struct pt_regs * regs);
+extern void voyager_timer_interrupt(void);
+extern void smp_local_timer_interrupt(void);
extern void voyager_power_off(void);
extern void smp_voyager_power_off(void *dummy);
extern void voyager_restart(void);
diff --git a/include/asm-ia64/esi.h b/include/asm-ia64/esi.h
new file mode 100644
index 000000000000..84aac0e0b583
--- /dev/null
+++ b/include/asm-ia64/esi.h
@@ -0,0 +1,30 @@
+/*
+ * ESI service calls.
+ *
+ * Copyright (c) Copyright 2005-2006 Hewlett-Packard Development Company, L.P.
+ * Alex Williamson <alex.williamson@hp.com>
+ */
+#ifndef esi_h
+#define esi_h
+
+#include <linux/efi.h>
+
+#define ESI_QUERY 0x00000001
+#define ESI_OPEN_HANDLE 0x02000000
+#define ESI_CLOSE_HANDLE 0x02000001
+
+enum esi_proc_type {
+ ESI_PROC_SERIALIZED, /* calls need to be serialized */
+ ESI_PROC_MP_SAFE, /* MP-safe, but not reentrant */
+ ESI_PROC_REENTRANT /* MP-safe and reentrant */
+};
+
+extern int ia64_esi_init (void);
+extern struct ia64_sal_retval esi_call_phys (void *, u64 *);
+extern int ia64_esi_call(efi_guid_t, struct ia64_sal_retval *,
+ enum esi_proc_type,
+ u64, u64, u64, u64, u64, u64, u64, u64);
+extern int ia64_esi_call_phys(efi_guid_t, struct ia64_sal_retval *, u64, u64,
+ u64, u64, u64, u64, u64, u64);
+
+#endif /* esi_h */
diff --git a/include/asm-ia64/futex.h b/include/asm-ia64/futex.h
index 6a332a9f099c..07d77f3a8cbe 100644
--- a/include/asm-ia64/futex.h
+++ b/include/asm-ia64/futex.h
@@ -1,6 +1,124 @@
#ifndef _ASM_FUTEX_H
#define _ASM_FUTEX_H
-#include <asm-generic/futex.h>
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
-#endif
+#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \
+do { \
+ register unsigned long r8 __asm ("r8") = 0; \
+ __asm__ __volatile__( \
+ " mf;; \n" \
+ "[1:] " insn ";; \n" \
+ " .xdata4 \"__ex_table\", 1b-., 2f-. \n" \
+ "[2:]" \
+ : "+r" (r8), "=r" (oldval) \
+ : "r" (uaddr), "r" (oparg) \
+ : "memory"); \
+ ret = r8; \
+} while (0)
+
+#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \
+do { \
+ register unsigned long r8 __asm ("r8") = 0; \
+ int val, newval; \
+ do { \
+ __asm__ __volatile__( \
+ " mf;; \n" \
+ "[1:] ld4 %3=[%4];; \n" \
+ " mov %2=%3 \n" \
+ insn ";; \n" \
+ " mov ar.ccv=%2;; \n" \
+ "[2:] cmpxchg4.acq %1=[%4],%3,ar.ccv;; \n" \
+ " .xdata4 \"__ex_table\", 1b-., 3f-.\n" \
+ " .xdata4 \"__ex_table\", 2b-., 3f-.\n" \
+ "[3:]" \
+ : "+r" (r8), "=r" (val), "=&r" (oldval), \
+ "=&r" (newval) \
+ : "r" (uaddr), "r" (oparg) \
+ : "memory"); \
+ if (unlikely (r8)) \
+ break; \
+ } while (unlikely (val != oldval)); \
+ ret = r8; \
+} while (0)
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ __futex_atomic_op1("xchg4 %1=[%2],%3", ret, oldval, uaddr,
+ oparg);
+ break;
+ case FUTEX_OP_ADD:
+ __futex_atomic_op2("add %3=%3,%5", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_OR:
+ __futex_atomic_op2("or %3=%3,%5", ret, oldval, uaddr, oparg);
+ break;
+ case FUTEX_OP_ANDN:
+ __futex_atomic_op2("and %3=%3,%5", ret, oldval, uaddr,
+ ~oparg);
+ break;
+ case FUTEX_OP_XOR:
+ __futex_atomic_op2("xor %3=%3,%5", ret, oldval, uaddr, oparg);
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ {
+ register unsigned long r8 __asm ("r8");
+ __asm__ __volatile__(
+ " mf;; \n"
+ " mov ar.ccv=%3;; \n"
+ "[1:] cmpxchg4.acq %0=[%1],%2,ar.ccv \n"
+ " .xdata4 \"__ex_table\", 1b-., 2f-. \n"
+ "[2:]"
+ : "=r" (r8)
+ : "r" (uaddr), "r" (newval),
+ "rO" ((long) (unsigned) oldval)
+ : "memory");
+ return r8;
+ }
+}
+
+#endif /* _ASM_FUTEX_H */
diff --git a/include/asm-ia64/io.h b/include/asm-ia64/io.h
index 43bfff6c6b87..855c30af72a9 100644
--- a/include/asm-ia64/io.h
+++ b/include/asm-ia64/io.h
@@ -417,6 +417,8 @@ __writeq (unsigned long val, volatile void __iomem *addr)
# define outl_p outl
#endif
+# ifdef __KERNEL__
+
extern void __iomem * ioremap(unsigned long offset, unsigned long size);
extern void __iomem * ioremap_nocache (unsigned long offset, unsigned long size);
@@ -430,8 +432,6 @@ iounmap (volatile void __iomem *addr)
#define dmi_iounmap(x,l) iounmap(x)
#define dmi_alloc(l) kmalloc(l, GFP_ATOMIC)
-# ifdef __KERNEL__
-
/*
* String version of IO memory access ops:
*/
diff --git a/include/asm-ia64/irq_regs.h b/include/asm-ia64/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-ia64/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index 938904910115..1b45b71c79b9 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -29,7 +29,8 @@
#include <linux/percpu.h>
#include <asm/break.h>
-#define MAX_INSN_SIZE 16
+#define __ARCH_WANT_KPROBES_INSN_SLOT
+#define MAX_INSN_SIZE 1
#define BREAK_INST (long)(__IA64_BREAK_KPROBE << 6)
typedef union cmp_inst {
@@ -94,7 +95,7 @@ struct kprobe_ctlblk {
#define IP_RELATIVE_PREDICT_OPCODE (7)
#define LONG_BRANCH_OPCODE (0xC)
#define LONG_CALL_OPCODE (0xD)
-#define arch_remove_kprobe(p) do {} while (0)
+#define flush_insn_slot(p) do { } while (0)
typedef struct kprobe_opcode {
bundle_t bundle;
@@ -108,7 +109,7 @@ struct fnptr {
/* Architecture specific copy of original instruction*/
struct arch_specific_insn {
/* copy of the instruction to be emulated */
- kprobe_opcode_t insn;
+ kprobe_opcode_t *insn;
#define INST_FLAG_FIX_RELATIVE_IP_ADDR 1
#define INST_FLAG_FIX_BRANCH_REG 2
#define INST_FLAG_BREAK_INST 4
@@ -125,6 +126,6 @@ static inline void jprobe_return(void)
}
extern void invalidate_stacked_regs(void);
extern void flush_register_stack(void);
-extern void flush_insn_slot(struct kprobe *p);
+extern void arch_remove_kprobe(struct kprobe *p);
#endif /* _ASM_KPROBES_H */
diff --git a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
index 15b545a897a4..7ffbddf5306f 100644
--- a/include/asm-ia64/machvec.h
+++ b/include/asm-ia64/machvec.h
@@ -20,12 +20,13 @@ struct page;
struct mm_struct;
struct pci_bus;
struct task_struct;
+struct pci_dev;
typedef void ia64_mv_setup_t (char **);
typedef void ia64_mv_cpu_init_t (void);
typedef void ia64_mv_irq_init_t (void);
typedef void ia64_mv_send_ipi_t (int, int, int, int);
-typedef void ia64_mv_timer_interrupt_t (int, void *, struct pt_regs *);
+typedef void ia64_mv_timer_interrupt_t (int, void *);
typedef void ia64_mv_global_tlb_purge_t (struct mm_struct *, unsigned long, unsigned long, unsigned long);
typedef void ia64_mv_tlb_migrate_finish_t (struct mm_struct *);
typedef unsigned int ia64_mv_local_vector_to_irq (u8);
@@ -75,7 +76,9 @@ typedef unsigned char ia64_mv_readb_relaxed_t (const volatile void __iomem *);
typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
-typedef int ia64_mv_msi_init_t (void);
+
+typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
static inline void
machvec_noop (void)
@@ -93,7 +96,7 @@ machvec_noop_task (struct task_struct *task)
}
extern void machvec_setup (char **);
-extern void machvec_timer_interrupt (int, void *, struct pt_regs *);
+extern void machvec_timer_interrupt (int, void *);
extern void machvec_dma_sync_single (struct device *, dma_addr_t, size_t, int);
extern void machvec_dma_sync_sg (struct device *, struct scatterlist *, int, int);
extern void machvec_tlb_migrate_finish (struct mm_struct *);
@@ -154,7 +157,8 @@ extern void machvec_tlb_migrate_finish (struct mm_struct *);
# define platform_readl_relaxed ia64_mv.readl_relaxed
# define platform_readq_relaxed ia64_mv.readq_relaxed
# define platform_migrate ia64_mv.migrate
-# define platform_msi_init ia64_mv.msi_init
+# define platform_setup_msi_irq ia64_mv.setup_msi_irq
+# define platform_teardown_msi_irq ia64_mv.teardown_msi_irq
# endif
/* __attribute__((__aligned__(16))) is required to make size of the
@@ -204,7 +208,8 @@ struct ia64_machine_vector {
ia64_mv_readl_relaxed_t *readl_relaxed;
ia64_mv_readq_relaxed_t *readq_relaxed;
ia64_mv_migrate_t *migrate;
- ia64_mv_msi_init_t *msi_init;
+ ia64_mv_setup_msi_irq_t *setup_msi_irq;
+ ia64_mv_teardown_msi_irq_t *teardown_msi_irq;
} __attribute__((__aligned__(16))); /* align attrib? see above comment */
#define MACHVEC_INIT(name) \
@@ -250,7 +255,8 @@ struct ia64_machine_vector {
platform_readl_relaxed, \
platform_readq_relaxed, \
platform_migrate, \
- platform_msi_init, \
+ platform_setup_msi_irq, \
+ platform_teardown_msi_irq, \
}
extern struct ia64_machine_vector ia64_mv;
@@ -404,8 +410,11 @@ extern int ia64_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size
#ifndef platform_migrate
# define platform_migrate machvec_noop_task
#endif
-#ifndef platform_msi_init
-# define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
+#ifndef platform_setup_msi_irq
+# define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL)
+#endif
+#ifndef platform_teardown_msi_irq
+# define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL)
#endif
#endif /* _ASM_IA64_MACHVEC_H */
diff --git a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
index cf724dc79d8c..c54b165b1c17 100644
--- a/include/asm-ia64/machvec_sn2.h
+++ b/include/asm-ia64/machvec_sn2.h
@@ -67,7 +67,8 @@ extern ia64_mv_dma_sync_sg_for_device sn_dma_sync_sg_for_device;
extern ia64_mv_dma_mapping_error sn_dma_mapping_error;
extern ia64_mv_dma_supported sn_dma_supported;
extern ia64_mv_migrate_t sn_migrate;
-extern ia64_mv_msi_init_t sn_msi_init;
+extern ia64_mv_setup_msi_irq_t sn_setup_msi_irq;
+extern ia64_mv_teardown_msi_irq_t sn_teardown_msi_irq;
/*
@@ -120,9 +121,11 @@ extern ia64_mv_msi_init_t sn_msi_init;
#define platform_dma_supported sn_dma_supported
#define platform_migrate sn_migrate
#ifdef CONFIG_PCI_MSI
-#define platform_msi_init sn_msi_init
+#define platform_setup_msi_irq sn_setup_msi_irq
+#define platform_teardown_msi_irq sn_teardown_msi_irq
#else
-#define platform_msi_init ((ia64_mv_msi_init_t*)NULL)
+#define platform_setup_msi_irq ((ia64_mv_setup_msi_irq_t*)NULL)
+#define platform_teardown_msi_irq ((ia64_mv_teardown_msi_irq_t*)NULL)
#endif
#include <asm/sn/io.h>
diff --git a/include/asm-ia64/mca_asm.h b/include/asm-ia64/mca_asm.h
index 27c9203d8ce3..76203f9a8718 100644
--- a/include/asm-ia64/mca_asm.h
+++ b/include/asm-ia64/mca_asm.h
@@ -197,9 +197,9 @@
movl temp2 = start_addr; \
;; \
mov cr.iip = temp2; \
+ movl gp = __gp \
;; \
DATA_PA_TO_VA(sp, temp1); \
- DATA_PA_TO_VA(gp, temp2); \
srlz.i; \
;; \
nop 1; \
diff --git a/include/asm-ia64/meminit.h b/include/asm-ia64/meminit.h
index 6a33a07b3f1d..c3b1f862e6e7 100644
--- a/include/asm-ia64/meminit.h
+++ b/include/asm-ia64/meminit.h
@@ -55,6 +55,7 @@ extern void efi_memmap_init(unsigned long *, unsigned long *);
extern unsigned long vmalloc_end;
extern struct page *vmem_map;
extern int find_largest_hole (u64 start, u64 end, void *arg);
+ extern int register_active_ranges (u64 start, u64 end, void *arg);
extern int create_mem_map_page_table (u64 start, u64 end, void *arg);
extern int vmemmap_find_next_valid_pfn(int, int);
#else
diff --git a/include/asm-ia64/msi.h b/include/asm-ia64/msi.h
deleted file mode 100644
index bb92b0dbde2f..000000000000
--- a/include/asm-ia64/msi.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#define NR_VECTORS NR_IRQS
-#define FIRST_DEVICE_VECTOR IA64_FIRST_DEVICE_VECTOR
-#define LAST_DEVICE_VECTOR IA64_LAST_DEVICE_VECTOR
-static inline void set_intr_gate (int nr, void *func) {}
-#define IO_APIC_VECTOR(irq) (irq)
-#define ack_APIC_irq ia64_eoi
-#define MSI_TARGET_CPU_SHIFT 4
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
- if (platform_msi_init)
- return platform_msi_init();
-
- /* default ops for most ia64 platforms */
- msi_register(&msi_apic_ops);
- return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-ia64/numa.h b/include/asm-ia64/numa.h
index e0a1d173e42d..7d5e2ccc37a0 100644
--- a/include/asm-ia64/numa.h
+++ b/include/asm-ia64/numa.h
@@ -69,6 +69,8 @@ extern void unmap_cpu_from_node(int cpu, int nid);
#else /* !CONFIG_NUMA */
+#define map_cpu_to_node(cpu, nid) do{}while(0)
+#define unmap_cpu_from_node(cpu, nid) do{}while(0)
#define paddr_to_nid(addr) 0
diff --git a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
index 20a8d618c845..4283ddcc25fb 100644
--- a/include/asm-ia64/pal.h
+++ b/include/asm-ia64/pal.h
@@ -78,6 +78,7 @@
#define PAL_VM_TR_READ 261 /* read contents of translation register */
#define PAL_GET_PSTATE 262 /* get the current P-state */
#define PAL_SET_PSTATE 263 /* set the P-state */
+#define PAL_BRAND_INFO 274 /* Processor branding information */
#ifndef __ASSEMBLY__
@@ -763,7 +764,7 @@ struct ia64_pal_retval {
* (generally 0) MUST be passed. Reserved parameters are not optional
* parameters.
*/
-extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64, u64);
+extern struct ia64_pal_retval ia64_pal_call_static (u64, u64, u64, u64);
extern struct ia64_pal_retval ia64_pal_call_stacked (u64, u64, u64, u64);
extern struct ia64_pal_retval ia64_pal_call_phys_static (u64, u64, u64, u64);
extern struct ia64_pal_retval ia64_pal_call_phys_stacked (u64, u64, u64, u64);
@@ -773,14 +774,7 @@ extern void ia64_load_scratch_fpregs (struct ia64_fpreg *);
#define PAL_CALL(iprv,a0,a1,a2,a3) do { \
struct ia64_fpreg fr[6]; \
ia64_save_scratch_fpregs(fr); \
- iprv = ia64_pal_call_static(a0, a1, a2, a3, 0); \
- ia64_load_scratch_fpregs(fr); \
-} while (0)
-
-#define PAL_CALL_IC_OFF(iprv,a0,a1,a2,a3) do { \
- struct ia64_fpreg fr[6]; \
- ia64_save_scratch_fpregs(fr); \
- iprv = ia64_pal_call_static(a0, a1, a2, a3, 1); \
+ iprv = ia64_pal_call_static(a0, a1, a2, a3); \
ia64_load_scratch_fpregs(fr); \
} while (0)
@@ -963,7 +957,8 @@ static inline s64
ia64_pal_cache_read (pal_cache_line_id_u_t line_id, u64 physical_addr)
{
struct ia64_pal_retval iprv;
- PAL_CALL(iprv, PAL_CACHE_READ, line_id.pclid_data, physical_addr, 0);
+ PAL_CALL_PHYS_STK(iprv, PAL_CACHE_READ, line_id.pclid_data,
+ physical_addr, 0);
return iprv.status;
}
@@ -985,7 +980,8 @@ static inline s64
ia64_pal_cache_write (pal_cache_line_id_u_t line_id, u64 physical_addr, u64 data)
{
struct ia64_pal_retval iprv;
- PAL_CALL(iprv, PAL_CACHE_WRITE, line_id.pclid_data, physical_addr, data);
+ PAL_CALL_PHYS_STK(iprv, PAL_CACHE_WRITE, line_id.pclid_data,
+ physical_addr, data);
return iprv.status;
}
@@ -1133,6 +1129,15 @@ ia64_pal_set_pstate (u64 pstate_index)
return iprv.status;
}
+/* Processor branding information*/
+static inline s64
+ia64_pal_get_brand_info (char *brand_info)
+{
+ struct ia64_pal_retval iprv;
+ PAL_CALL_STK(iprv, PAL_BRAND_INFO, 0, (u64)brand_info, 0);
+ return iprv.status;
+}
+
/* Cause the processor to enter LIGHT HALT state, where prefetching and execution are
* suspended, but cache and TLB coherency is maintained.
*/
diff --git a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
index 265f4824db0e..5830d36fd8e6 100644
--- a/include/asm-ia64/processor.h
+++ b/include/asm-ia64/processor.h
@@ -20,12 +20,6 @@
#include <asm/ustack.h>
#define IA64_NUM_DBG_REGS 8
-/*
- * Limits for PMC and PMD are set to less than maximum architected values
- * but should be sufficient for a while
- */
-#define IA64_NUM_PMC_REGS 64
-#define IA64_NUM_PMD_REGS 64
#define DEFAULT_MAP_BASE __IA64_UL_CONST(0x2000000000000000)
#define DEFAULT_TASK_SIZE __IA64_UL_CONST(0xa000000000000000)
@@ -163,6 +157,7 @@ struct cpuinfo_ia64 {
__u8 family;
__u8 archrev;
char vendor[16];
+ char *model_name;
#ifdef CONFIG_NUMA
struct ia64_node_data *node_data;
@@ -262,13 +257,9 @@ struct thread_struct {
# define INIT_THREAD_IA32
#endif /* CONFIG_IA32_SUPPORT */
#ifdef CONFIG_PERFMON
- __u64 pmcs[IA64_NUM_PMC_REGS];
- __u64 pmds[IA64_NUM_PMD_REGS];
void *pfm_context; /* pointer to detailed PMU context */
unsigned long pfm_needs_checking; /* when >0, pending perfmon work on kernel exit */
-# define INIT_THREAD_PM .pmcs = {0UL, }, \
- .pmds = {0UL, }, \
- .pfm_context = NULL, \
+# define INIT_THREAD_PM .pfm_context = NULL, \
.pfm_needs_checking = 0UL,
#else
# define INIT_THREAD_PM
diff --git a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h
index 1414316efd40..f4ef87a36236 100644
--- a/include/asm-ia64/ptrace.h
+++ b/include/asm-ia64/ptrace.h
@@ -241,6 +241,9 @@ struct switch_stack {
* the canonical representation by adding to instruction pointer.
*/
# define instruction_pointer(regs) ((regs)->cr_iip + ia64_psr(regs)->ri)
+
+#define regs_return_value(regs) ((regs)->r8)
+
/* Conserve space in histogram by encoding slot bits in address
* bits 2 and 3 rather than bits 0 and 1.
*/
diff --git a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h
index 74bde1c2bb1a..60fd4ae014f6 100644
--- a/include/asm-ia64/smp.h
+++ b/include/asm-ia64/smp.h
@@ -126,6 +126,7 @@ extern void smp_send_reschedule (int cpu);
extern void lock_ipi_calllock(void);
extern void unlock_ipi_calllock(void);
extern void identify_siblings (struct cpuinfo_ia64 *);
+extern int is_multithreading_enabled(void);
#else
diff --git a/include/asm-ia64/sn/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h
index e3b0c3fe5eed..da3eade0cae2 100644
--- a/include/asm-ia64/sn/pcibr_provider.h
+++ b/include/asm-ia64/sn/pcibr_provider.h
@@ -135,7 +135,7 @@ extern void pcireg_intr_addr_addr_set(struct pcibus_info *, int, u64
extern void pcireg_force_intr_set(struct pcibus_info *, int);
extern u64 pcireg_wrb_flush_get(struct pcibus_info *, int);
extern void pcireg_int_ate_set(struct pcibus_info *, int, u64);
-extern u64 * pcireg_int_ate_addr(struct pcibus_info *, int);
+extern u64 __iomem * pcireg_int_ate_addr(struct pcibus_info *, int);
extern void pcibr_force_interrupt(struct sn_irq_info *sn_irq_info);
extern void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info);
extern int pcibr_ate_alloc(struct pcibus_info *, int);
diff --git a/include/asm-ia64/sn/tioca_provider.h b/include/asm-ia64/sn/tioca_provider.h
index 65cdd73c2a57..9a820ac61be3 100644
--- a/include/asm-ia64/sn/tioca_provider.h
+++ b/include/asm-ia64/sn/tioca_provider.h
@@ -162,11 +162,11 @@ static inline void
tioca_tlbflush(struct tioca_kernel *tioca_kernel)
{
volatile u64 tmp;
- volatile struct tioca *ca_base;
+ volatile struct tioca __iomem *ca_base;
struct tioca_common *tioca_common;
tioca_common = tioca_kernel->ca_common;
- ca_base = (struct tioca *)tioca_common->ca_common.bs_base;
+ ca_base = (struct tioca __iomem *)tioca_common->ca_common.bs_base;
/*
* Explicit flushes not needed if GART is in cached mode
diff --git a/include/asm-ia64/sn/tioce_provider.h b/include/asm-ia64/sn/tioce_provider.h
index 6d62b13f7ae7..32c32f30b099 100644
--- a/include/asm-ia64/sn/tioce_provider.h
+++ b/include/asm-ia64/sn/tioce_provider.h
@@ -53,7 +53,7 @@ struct tioce_dmamap {
u64 ct_start; /* coretalk start address */
u64 pci_start; /* bus start address */
- u64 *ate_hw; /* hw ptr of first ate in map */
+ u64 __iomem *ate_hw;/* hw ptr of first ate in map */
u64 *ate_shadow; /* shadow ptr of firat ate */
u16 ate_count; /* # ate's in the map */
};
diff --git a/include/asm-ia64/sn/xpc.h b/include/asm-ia64/sn/xpc.h
index 35e1386f37ab..1d45e1518fb3 100644
--- a/include/asm-ia64/sn/xpc.h
+++ b/include/asm-ia64/sn/xpc.h
@@ -669,7 +669,7 @@ extern struct device *xpc_part;
extern struct device *xpc_chan;
extern int xpc_disengage_request_timelimit;
extern int xpc_disengage_request_timedout;
-extern irqreturn_t xpc_notify_IRQ_handler(int, void *, struct pt_regs *);
+extern irqreturn_t xpc_notify_IRQ_handler(int, void *);
extern void xpc_dropped_IPI_check(struct xpc_partition *);
extern void xpc_activate_partition(struct xpc_partition *);
extern void xpc_activate_kthreads(struct xpc_channel *, int);
diff --git a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h
index 9e83210dc312..ff857e31738a 100644
--- a/include/asm-ia64/spinlock.h
+++ b/include/asm-ia64/spinlock.h
@@ -213,4 +213,8 @@ static inline int __raw_read_trylock(raw_rwlock_t *x)
return (u32)ia64_cmpxchg4_acq((__u32 *)(x), new.word, old.word) == old.word;
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* _ASM_IA64_SPINLOCK_H */
diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
index 937c21257523..a6e38565ab4c 100644
--- a/include/asm-ia64/topology.h
+++ b/include/asm-ia64/topology.h
@@ -59,6 +59,7 @@ void build_cpu_to_node_map(void);
#define SD_CPU_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 1, \
.max_interval = 4, \
@@ -84,6 +85,7 @@ void build_cpu_to_node_map(void);
#define SD_NODE_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 8, \
.max_interval = 8*(min(num_online_cpus(), 32)), \
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index f581662c5ab8..53c5c0ee122c 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -286,7 +286,8 @@
/* 1294, 1295 reserved for pselect/ppoll */
#define __NR_unshare 1296
#define __NR_splice 1297
-/* 1298, 1299 reserved for set_robust_list/get_robust_list */
+#define __NR_set_robust_list 1298
+#define __NR_get_robust_list 1299
#define __NR_sync_file_range 1300
#define __NR_tee 1301
#define __NR_vmsplice 1302
@@ -318,78 +319,6 @@
extern long __ia64_syscall (long a0, long a1, long a2, long a3, long a4, long nr);
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/string.h>
-#include <linux/signal.h>
-#include <asm/ptrace.h>
-#include <linux/stringify.h>
-#include <linux/syscalls.h>
-
-static inline long
-open (const char * name, int mode, int flags)
-{
- return sys_open(name, mode, flags);
-}
-
-static inline long
-dup (int fd)
-{
- return sys_dup(fd);
-}
-
-static inline long
-close (int fd)
-{
- return sys_close(fd);
-}
-
-static inline off_t
-lseek (int fd, off_t off, int whence)
-{
- return sys_lseek(fd, off, whence);
-}
-
-static inline void
-_exit (int value)
-{
- sys_exit(value);
-}
-
-#define exit(x) _exit(x)
-
-static inline long
-write (int fd, const char * buf, size_t nr)
-{
- return sys_write(fd, buf, nr);
-}
-
-static inline long
-read (int fd, char * buf, size_t nr)
-{
- return sys_read(fd, buf, nr);
-}
-
-
-static inline long
-setsid (void)
-{
- return sys_setsid();
-}
-
-static inline pid_t
-waitpid (int pid, int * wait_stat, int flags)
-{
- return sys_wait4(pid, wait_stat, flags, NULL);
-}
-
-
-extern int execve (const char *filename, char *const av[], char *const ep[]);
-extern pid_t clone (unsigned long flags, void *sp);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
asmlinkage unsigned long sys_mmap(
unsigned long addr, unsigned long len,
int prot, int flags,
diff --git a/include/asm-m32r/io.h b/include/asm-m32r/io.h
index 70ad1c949c2b..d06933bd6318 100644
--- a/include/asm-m32r/io.h
+++ b/include/asm-m32r/io.h
@@ -166,38 +166,6 @@ static inline void _writel(unsigned long l, unsigned long addr)
#define flush_write_buffers() do { } while (0) /* M32R_FIXME */
-/**
- * check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the ISA mmio address io_addr.
- * Returns 1 on a match.
- *
- * This function is deprecated. New drivers should use ioremap and
- * check_signature.
- */
-
-static inline int check_signature(void __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
-#if 0
-printk("check_signature\n");
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
-#endif
- return retval;
-}
-
static inline void
memset_io(volatile void __iomem *addr, unsigned char val, int count)
{
diff --git a/include/asm-m32r/irq_regs.h b/include/asm-m32r/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-m32r/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-m32r/m32104ut/m32104ut_pld.h b/include/asm-m32r/m32104ut/m32104ut_pld.h
index 6ba4ddf7dcf7..cbdbc5891445 100644
--- a/include/asm-m32r/m32104ut/m32104ut_pld.h
+++ b/include/asm-m32r/m32104ut/m32104ut_pld.h
@@ -1,5 +1,5 @@
/*
- * include/asm/m32104ut/m32104ut_pld.h
+ * include/asm-m32r/m32104ut/m32104ut_pld.h
*
* Definitions for Programable Logic Device(PLD) on M32104UT board.
* Based on m32700ut_pld.h
diff --git a/include/asm-m32r/m32700ut/m32700ut_lan.h b/include/asm-m32r/m32700ut/m32700ut_lan.h
index c050b19e8101..f1e47ae1f891 100644
--- a/include/asm-m32r/m32700ut/m32700ut_lan.h
+++ b/include/asm-m32r/m32700ut/m32700ut_lan.h
@@ -1,5 +1,5 @@
/*
- * include/asm/m32700ut_lan.h
+ * include/asm-m32r/m32700ut/m32700ut_lan.h
*
* M32700UT-LAN board
*
diff --git a/include/asm-m32r/m32700ut/m32700ut_lcd.h b/include/asm-m32r/m32700ut/m32700ut_lcd.h
index 4da4e822e2f3..e41c4aa48b4c 100644
--- a/include/asm-m32r/m32700ut/m32700ut_lcd.h
+++ b/include/asm-m32r/m32700ut/m32700ut_lcd.h
@@ -1,5 +1,5 @@
/*
- * include/asm/m32700ut_lcd.h
+ * include/asm-m32r/m32700ut/m32700ut_lcd.h
*
* M32700UT-LCD board
*
diff --git a/include/asm-m32r/m32700ut/m32700ut_pld.h b/include/asm-m32r/m32700ut/m32700ut_pld.h
index f35f9159acff..a48c22c978ca 100644
--- a/include/asm-m32r/m32700ut/m32700ut_pld.h
+++ b/include/asm-m32r/m32700ut/m32700ut_pld.h
@@ -1,5 +1,5 @@
/*
- * include/asm/m32700ut/m32700ut_pld.h
+ * include/asm-m32r/m32700ut/m32700ut_pld.h
*
* Definitions for Programable Logic Device(PLD) on M32700UT board.
*
diff --git a/include/asm-m32r/mappi2/mappi2_pld.h b/include/asm-m32r/mappi2/mappi2_pld.h
index 01dcdd19dbe6..56a2b12f2bfc 100644
--- a/include/asm-m32r/mappi2/mappi2_pld.h
+++ b/include/asm-m32r/mappi2/mappi2_pld.h
@@ -1,5 +1,5 @@
/*
- * include/asm/mappi2/mappi2_pld.h
+ * include/asm-m32r/mappi2/mappi2_pld.h
*
* Definitions for Extended IO Logic on MAPPI2 board.
* based on m32700ut_pld.h by
diff --git a/include/asm-m32r/mappi3/mappi3_pld.h b/include/asm-m32r/mappi3/mappi3_pld.h
index 031369a7afc8..92f10defaef8 100644
--- a/include/asm-m32r/mappi3/mappi3_pld.h
+++ b/include/asm-m32r/mappi3/mappi3_pld.h
@@ -1,5 +1,5 @@
/*
- * include/asm/mappi3/mappi3_pld.h
+ * include/asm-m32r/mappi3/mappi3_pld.h
*
* Definitions for Extended IO Logic on MAPPI3 board.
* based on m32700ut_pld.h
diff --git a/include/asm-m32r/opsput/opsput_lan.h b/include/asm-m32r/opsput/opsput_lan.h
index 61948296f445..f53e10187c03 100644
--- a/include/asm-m32r/opsput/opsput_lan.h
+++ b/include/asm-m32r/opsput/opsput_lan.h
@@ -1,5 +1,5 @@
/*
- * include/asm/opsput_lan.h
+ * include/asm-m32r/opsput/opsput_lan.h
*
* OPSPUT-LAN board
*
diff --git a/include/asm-m32r/opsput/opsput_lcd.h b/include/asm-m32r/opsput/opsput_lcd.h
index 44cfd7fe2d88..99f296e1b61b 100644
--- a/include/asm-m32r/opsput/opsput_lcd.h
+++ b/include/asm-m32r/opsput/opsput_lcd.h
@@ -1,5 +1,5 @@
/*
- * include/asm/opsput_lcd.h
+ * include/asm-m32r/opsput/opsput_lcd.h
*
* OPSPUT-LCD board
*
diff --git a/include/asm-m32r/opsput/opsput_pld.h b/include/asm-m32r/opsput/opsput_pld.h
index 46296fe1ec1a..a8d6452076f1 100644
--- a/include/asm-m32r/opsput/opsput_pld.h
+++ b/include/asm-m32r/opsput/opsput_pld.h
@@ -1,5 +1,5 @@
/*
- * include/asm/opsput/opsput_pld.h
+ * include/asm-m32r/opsput/opsput_pld.h
*
* Definitions for Programable Logic Device(PLD) on OPSPUT board.
*
diff --git a/include/asm-m32r/pgtable-2level.h b/include/asm-m32r/pgtable-2level.h
index 6a674e3d37a2..84152760e0b5 100644
--- a/include/asm-m32r/pgtable-2level.h
+++ b/include/asm-m32r/pgtable-2level.h
@@ -44,7 +44,7 @@ static inline int pgd_present(pgd_t pgd) { return 1; }
*/
#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
-#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval)
+
/*
* (pmds are folded into pgds so this doesnt get actually called,
* but the define is needed for a generic inline function.)
diff --git a/include/asm-m32r/spinlock.h b/include/asm-m32r/spinlock.h
index f94c1a673569..f5cfba81ee10 100644
--- a/include/asm-m32r/spinlock.h
+++ b/include/asm-m32r/spinlock.h
@@ -298,7 +298,14 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
);
}
-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
+static inline int __raw_read_trylock(raw_rwlock_t *lock)
+{
+ atomic_t *count = (atomic_t*)lock;
+ if (atomic_dec_return(count) >= 0)
+ return 1;
+ atomic_inc(count);
+ return 0;
+}
static inline int __raw_write_trylock(raw_rwlock_t *lock)
{
@@ -309,4 +316,8 @@ static inline int __raw_write_trylock(raw_rwlock_t *lock)
return 0;
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* _ASM_M32R_SPINLOCK_H */
diff --git a/include/asm-m32r/system.h b/include/asm-m32r/system.h
index 9e618afec6ed..4ce0619f6989 100644
--- a/include/asm-m32r/system.h
+++ b/include/asm-m32r/system.h
@@ -328,15 +328,15 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
#define smp_rmb() rmb()
#define smp_wmb() wmb()
#define smp_read_barrier_depends() read_barrier_depends()
+#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
#else
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
#define smp_read_barrier_depends() do { } while (0)
+#define set_mb(var, value) do { var = value; barrier(); } while (0)
#endif
-#define set_mb(var, value) do { xchg(&var, value); } while (0)
-
#define arch_align_stack(x) (x)
#endif /* _ASM_M32R_SYSTEM_H */
diff --git a/include/asm-m32r/timex.h b/include/asm-m32r/timex.h
index e89bfd17db51..019441c1d7a0 100644
--- a/include/asm-m32r/timex.h
+++ b/include/asm-m32r/timex.h
@@ -12,9 +12,6 @@
#define CLOCK_TICK_RATE (CONFIG_BUS_CLOCK / CONFIG_TIMER_DIVIDE)
#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
-#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
- (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
- << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
#ifdef __KERNEL__
/*
diff --git a/include/asm-m32r/unistd.h b/include/asm-m32r/unistd.h
index 89f376e6229f..95aa34298d82 100644
--- a/include/asm-m32r/unistd.h
+++ b/include/asm-m32r/unistd.h
@@ -296,8 +296,9 @@
#ifdef __KERNEL__
#define NR_syscalls 285
+#include <linux/err.h>
-/* user-visible error numbers are in the range -1 - -124: see
+/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
* <asm-m32r/errno.h>
*/
@@ -305,7 +306,7 @@
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-(124 + 1))) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
/* Avoid using "res" which is declared to be in register r0; \
errno might expand to a function call and clobber it. */ \
int __err = -(res); \
@@ -423,43 +424,6 @@ __syscall_return(type,__res); \
#define __ARCH_WANT_SYS_OLDUMOUNT
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(struct pt_regs regs);
-asmlinkage int sys_clone(struct pt_regs regs);
-asmlinkage int sys_fork(struct pt_regs regs);
-asmlinkage int sys_vfork(struct pt_regs regs);
-asmlinkage int sys_pipe(unsigned long __user *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-m68k/atari_stdma.h b/include/asm-m68k/atari_stdma.h
index b4eadf852738..8e389b7fa70c 100644
--- a/include/asm-m68k/atari_stdma.h
+++ b/include/asm-m68k/atari_stdma.h
@@ -8,8 +8,7 @@
/***************************** Prototypes *****************************/
-void stdma_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *),
- void *data);
+void stdma_lock(irq_handler_t handler, void *data);
void stdma_release( void );
int stdma_others_waiting( void );
int stdma_islocked( void );
diff --git a/include/asm-m68k/dma-mapping.h b/include/asm-m68k/dma-mapping.h
index cebbb03370ec..d90d841d3dfd 100644
--- a/include/asm-m68k/dma-mapping.h
+++ b/include/asm-m68k/dma-mapping.h
@@ -5,6 +5,7 @@
struct scatterlist;
+#ifndef CONFIG_MMU_SUN3
static inline int dma_supported(struct device *dev, u64 mask)
{
return 1;
@@ -26,7 +27,7 @@ static inline int dma_is_consistent(dma_addr_t dma_addr)
}
extern void *dma_alloc_coherent(struct device *, size_t,
- dma_addr_t *, int);
+ dma_addr_t *, gfp_t);
extern void dma_free_coherent(struct device *, size_t,
void *, dma_addr_t);
@@ -88,4 +89,8 @@ static inline int dma_mapping_error(dma_addr_t handle)
return 0;
}
+#else
+#include <asm-generic/dma-mapping-broken.h>
+#endif
+
#endif /* _M68K_DMA_MAPPING_H */
diff --git a/include/asm-m68k/floppy.h b/include/asm-m68k/floppy.h
index 57f4fdda65ab..45dc908932a3 100644
--- a/include/asm-m68k/floppy.h
+++ b/include/asm-m68k/floppy.h
@@ -17,8 +17,7 @@
#include <linux/vmalloc.h>
-asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id,
- struct pt_regs *regs);
+asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id);
/* constants... */
@@ -184,8 +183,7 @@ static void fd_disable_dma(void)
/* this is the only truly Q40 specific function */
-asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id,
- struct pt_regs *regs)
+asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id)
{
register unsigned char st;
@@ -198,7 +196,7 @@ asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id,
static int dma_wait=0;
#endif
if(!doing_pdma) {
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
@@ -246,7 +244,7 @@ asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id,
dma_wait=0;
#endif
doing_pdma = 0;
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
#ifdef TRACE_FLPY_INT
diff --git a/include/asm-m68k/ide.h b/include/asm-m68k/ide.h
index 365f76fb8013..f9ffb2cbbae8 100644
--- a/include/asm-m68k/ide.h
+++ b/include/asm-m68k/ide.h
@@ -123,7 +123,7 @@ static __inline__ void ide_release_lock (void)
}
static __inline__ void
-ide_get_lock(irqreturn_t (*handler)(int, void *, struct pt_regs *), void *data)
+ide_get_lock(irq_handler_t handler, void *data)
{
if (MACH_IS_ATARI) {
if (falconide_intr_lock == 0) {
diff --git a/include/asm-m68k/irq.h b/include/asm-m68k/irq.h
index 3257f9881002..4901cb105e2f 100644
--- a/include/asm-m68k/irq.h
+++ b/include/asm-m68k/irq.h
@@ -83,7 +83,7 @@ struct pt_regs;
* interrupt source (if it supports chaining).
*/
typedef struct irq_node {
- int (*handler)(int, void *, struct pt_regs *);
+ int (*handler)(int, void *);
void *dev_id;
struct irq_node *next;
unsigned long flags;
@@ -93,12 +93,12 @@ typedef struct irq_node {
/*
* This structure has only 4 elements for speed reasons
*/
-typedef struct irq_handler {
- int (*handler)(int, void *, struct pt_regs *);
+struct irq_handler {
+ int (*handler)(int, void *);
unsigned long flags;
void *dev_id;
const char *devname;
-} irq_handler_t;
+};
struct irq_controller {
const char *name;
@@ -122,6 +122,7 @@ extern void m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt,
void (*handler)(unsigned int, struct pt_regs *));
extern void m68k_setup_irq_controller(struct irq_controller *, unsigned int, unsigned int);
-asmlinkage void m68k_handle_int(unsigned int, struct pt_regs *);
+asmlinkage void m68k_handle_int(unsigned int);
+asmlinkage void __m68k_handle_int(unsigned int, struct pt_regs *);
#endif /* _M68K_IRQ_H_ */
diff --git a/include/asm-m68k/irq_regs.h b/include/asm-m68k/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-m68k/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-m68k/mac_iop.h b/include/asm-m68k/mac_iop.h
index b0d2e3473537..a2c7e6fcca38 100644
--- a/include/asm-m68k/mac_iop.h
+++ b/include/asm-m68k/mac_iop.h
@@ -143,17 +143,17 @@ struct iop_msg {
int status; /* status of this message */
__u8 message[IOP_MSG_LEN]; /* the message being sent/received */
__u8 reply[IOP_MSG_LEN]; /* the reply to the message */
- void (*handler)(struct iop_msg *, struct pt_regs *);
+ void (*handler)(struct iop_msg *);
/* function to call when reply recvd */
};
extern int iop_scc_present,iop_ism_present;
extern int iop_listen(uint, uint,
- void (*handler)(struct iop_msg *, struct pt_regs *),
+ void (*handler)(struct iop_msg *),
const char *);
extern int iop_send_message(uint, uint, void *, uint, __u8 *,
- void (*)(struct iop_msg *, struct pt_regs *));
+ void (*)(struct iop_msg *));
extern void iop_complete_message(struct iop_msg *);
extern void iop_upload_code(uint, __u8 *, uint, __u16);
extern void iop_download_code(uint, __u8 *, uint, __u16);
diff --git a/include/asm-m68k/machdep.h b/include/asm-m68k/machdep.h
index df898f27e434..26d2b91209c5 100644
--- a/include/asm-m68k/machdep.h
+++ b/include/asm-m68k/machdep.h
@@ -10,7 +10,7 @@ struct rtc_time;
struct rtc_pll_info;
struct buffer_head;
-extern void (*mach_sched_init) (irqreturn_t (*handler)(int, void *, struct pt_regs *));
+extern void (*mach_sched_init) (irq_handler_t handler);
/* machine dependent irq functions */
extern void (*mach_init_IRQ) (void);
extern void (*mach_get_model) (char *model);
diff --git a/include/asm-m68k/rtc.h b/include/asm-m68k/rtc.h
index 71406fc4e599..5d3e03859844 100644
--- a/include/asm-m68k/rtc.h
+++ b/include/asm-m68k/rtc.h
@@ -1,4 +1,4 @@
-/* asm-m68k/rtc.h
+/* include/asm-m68k/rtc.h
*
* Copyright Richard Zidlicky
* implementation details for genrtc/q40rtc driver
diff --git a/include/asm-m68k/signal.h b/include/asm-m68k/signal.h
index de1ba6ead3b4..3db8a81942f1 100644
--- a/include/asm-m68k/signal.h
+++ b/include/asm-m68k/signal.h
@@ -198,6 +198,7 @@ static inline int sigfindinword(unsigned long word)
return word ^ 31;
}
+struct pt_regs;
extern void ptrace_signal_deliver(struct pt_regs *regs, void *cookie);
#endif /* __KERNEL__ */
diff --git a/include/asm-m68k/string.h b/include/asm-m68k/string.h
index 6c59215b285e..2eb7df1e0f5d 100644
--- a/include/asm-m68k/string.h
+++ b/include/asm-m68k/string.h
@@ -1,138 +1,114 @@
#ifndef _M68K_STRING_H_
#define _M68K_STRING_H_
-#include <asm/setup.h>
-#include <asm/page.h>
+#include <linux/types.h>
+#include <linux/compiler.h>
-#define __HAVE_ARCH_STRCPY
-static inline char * strcpy(char * dest,const char *src)
+static inline size_t __kernel_strlen(const char *s)
{
- char *xdest = dest;
-
- __asm__ __volatile__
- ("1:\tmoveb %1@+,%0@+\n\t"
- "jne 1b"
- : "=a" (dest), "=a" (src)
- : "0" (dest), "1" (src) : "memory");
- return xdest;
-}
+ const char *sc;
-#define __HAVE_ARCH_STRNCPY
-static inline char * strncpy(char *dest, const char *src, size_t n)
-{
- char *xdest = dest;
-
- if (n == 0)
- return xdest;
-
- __asm__ __volatile__
- ("1:\tmoveb %1@+,%0@+\n\t"
- "jeq 2f\n\t"
- "subql #1,%2\n\t"
- "jne 1b\n\t"
- "2:"
- : "=a" (dest), "=a" (src), "=d" (n)
- : "0" (dest), "1" (src), "2" (n)
- : "memory");
- return xdest;
+ for (sc = s; *sc++; )
+ ;
+ return sc - s - 1;
}
-#define __HAVE_ARCH_STRCAT
-static inline char * strcat(char * dest, const char * src)
+static inline char *__kernel_strcpy(char *dest, const char *src)
{
- char *tmp = dest;
-
- while (*dest)
- dest++;
- while ((*dest++ = *src++))
- ;
-
- return tmp;
+ char *xdest = dest;
+
+ asm volatile ("\n"
+ "1: move.b (%1)+,(%0)+\n"
+ " jne 1b"
+ : "+a" (dest), "+a" (src)
+ : : "memory");
+ return xdest;
}
-#define __HAVE_ARCH_STRNCAT
-static inline char * strncat(char *dest, const char *src, size_t count)
-{
- char *tmp = dest;
-
- if (count) {
- while (*dest)
- dest++;
- while ((*dest++ = *src++)) {
- if (--count == 0) {
- *dest++='\0';
- break;
- }
- }
- }
+#ifndef __IN_STRING_C
- return tmp;
-}
+#define __HAVE_ARCH_STRLEN
+#define strlen(s) (__builtin_constant_p(s) ? \
+ __builtin_strlen(s) : \
+ __kernel_strlen(s))
-#define __HAVE_ARCH_STRCHR
-static inline char * strchr(const char * s, int c)
+#define __HAVE_ARCH_STRNLEN
+static inline size_t strnlen(const char *s, size_t count)
{
- const char ch = c;
-
- for(; *s != ch; ++s)
- if (*s == '\0')
- return( NULL );
- return( (char *) s);
+ const char *sc = s;
+
+ asm volatile ("\n"
+ "1: subq.l #1,%1\n"
+ " jcs 2f\n"
+ " tst.b (%0)+\n"
+ " jne 1b\n"
+ " subq.l #1,%0\n"
+ "2:"
+ : "+a" (sc), "+d" (count));
+ return sc - s;
}
-/* strstr !! */
+#define __HAVE_ARCH_STRCPY
+#if __GNUC__ >= 4
+#define strcpy(d, s) (__builtin_constant_p(s) && \
+ __builtin_strlen(s) <= 32 ? \
+ __builtin_strcpy(d, s) : \
+ __kernel_strcpy(d, s))
+#else
+#define strcpy(d, s) __kernel_strcpy(d, s)
+#endif
-#define __HAVE_ARCH_STRLEN
-static inline size_t strlen(const char * s)
+#define __HAVE_ARCH_STRNCPY
+static inline char *strncpy(char *dest, const char *src, size_t n)
{
- const char *sc;
- for (sc = s; *sc != '\0'; ++sc) ;
- return(sc - s);
+ char *xdest = dest;
+
+ asm volatile ("\n"
+ " jra 2f\n"
+ "1: move.b (%1),(%0)+\n"
+ " jeq 2f\n"
+ " addq.l #1,%1\n"
+ "2: subq.l #1,%2\n"
+ " jcc 1b\n"
+ : "+a" (dest), "+a" (src), "+d" (n)
+ : : "memory");
+ return xdest;
}
-/* strnlen !! */
+#define __HAVE_ARCH_STRCAT
+#define strcat(d, s) ({ \
+ char *__d = (d); \
+ strcpy(__d + strlen(__d), (s)); \
+})
-#define __HAVE_ARCH_STRCMP
-static inline int strcmp(const char * cs,const char * ct)
+#define __HAVE_ARCH_STRCHR
+static inline char *strchr(const char *s, int c)
{
- char __res;
-
- __asm__
- ("1:\tmoveb %0@+,%2\n\t" /* get *cs */
- "cmpb %1@+,%2\n\t" /* compare a byte */
- "jne 2f\n\t" /* not equal, break out */
- "tstb %2\n\t" /* at end of cs? */
- "jne 1b\n\t" /* no, keep going */
- "jra 3f\n\t" /* strings are equal */
- "2:\tsubb %1@-,%2\n\t" /* *cs - *ct */
- "3:"
- : "=a" (cs), "=a" (ct), "=d" (__res)
- : "0" (cs), "1" (ct));
- return __res;
+ char sc, ch = c;
+
+ for (; (sc = *s++) != ch; ) {
+ if (!sc)
+ return NULL;
+ }
+ return (char *)s - 1;
}
-#define __HAVE_ARCH_STRNCMP
-static inline int strncmp(const char * cs,const char * ct,size_t count)
+#define __HAVE_ARCH_STRCMP
+static inline int strcmp(const char *cs, const char *ct)
{
- char __res;
-
- if (!count)
- return 0;
- __asm__
- ("1:\tmovb %0@+,%3\n\t" /* get *cs */
- "cmpb %1@+,%3\n\t" /* compare a byte */
- "jne 3f\n\t" /* not equal, break out */
- "tstb %3\n\t" /* at end of cs? */
- "jeq 4f\n\t" /* yes, all done */
- "subql #1,%2\n\t" /* no, adjust count */
- "jne 1b\n\t" /* more to do, keep going */
- "2:\tmoveq #0,%3\n\t" /* strings are equal */
- "jra 4f\n\t"
- "3:\tsubb %1@-,%3\n\t" /* *cs - *ct */
- "4:"
- : "=a" (cs), "=a" (ct), "=d" (count), "=d" (__res)
- : "0" (cs), "1" (ct), "2" (count));
- return __res;
+ char res;
+
+ asm ("\n"
+ "1: move.b (%0)+,%2\n" /* get *cs */
+ " cmp.b (%1)+,%2\n" /* compare a byte */
+ " jne 2f\n" /* not equal, break out */
+ " tst.b %2\n" /* at end of cs? */
+ " jne 1b\n" /* no, keep going */
+ " jra 3f\n" /* strings are equal */
+ "2: sub.b -(%1),%2\n" /* *cs - *ct */
+ "3:"
+ : "+a" (cs), "+a" (ct), "=d" (res));
+ return res;
}
#define __HAVE_ARCH_MEMSET
@@ -150,4 +126,6 @@ extern void *memmove(void *, const void *, __kernel_size_t);
extern int memcmp(const void *, const void *, __kernel_size_t);
#define memcmp(d, s, n) __builtin_memcmp(d, s, n)
+#endif
+
#endif /* _M68K_STRING_H_ */
diff --git a/include/asm-m68k/sun3mmu.h b/include/asm-m68k/sun3mmu.h
index 6c8c17d047a1..d8f17a0d8c9f 100644
--- a/include/asm-m68k/sun3mmu.h
+++ b/include/asm-m68k/sun3mmu.h
@@ -4,6 +4,7 @@
#ifndef __SUN3_MMU_H__
#define __SUN3_MMU_H__
+#include <linux/types.h>
#include <asm/movs.h>
#include <asm/sun3-head.h>
@@ -160,7 +161,7 @@ static inline void sun3_put_context(unsigned char c)
return;
}
-extern void *sun3_ioremap(unsigned long phys, unsigned long size,
+extern void __iomem *sun3_ioremap(unsigned long phys, unsigned long size,
unsigned long type);
extern int sun3_map_test(unsigned long addr, char *val);
diff --git a/include/asm-m68k/sun3xflop.h b/include/asm-m68k/sun3xflop.h
index ca8cc4113843..32c45f84ac60 100644
--- a/include/asm-m68k/sun3xflop.h
+++ b/include/asm-m68k/sun3xflop.h
@@ -111,8 +111,7 @@ static void sun3x_82072_fd_outb(unsigned char value, int port)
}
-asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id,
- struct pt_regs * regs)
+asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id)
{
register unsigned char st;
@@ -125,7 +124,7 @@ asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id,
static int dma_wait=0;
#endif
if(!doing_pdma) {
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
@@ -189,7 +188,7 @@ asmlinkage irqreturn_t sun3xflop_hardint(int irq, void *dev_id,
dma_wait=0;
#endif
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h
index 131a0cb0f491..243dd13e6bfc 100644
--- a/include/asm-m68k/system.h
+++ b/include/asm-m68k/system.h
@@ -78,13 +78,13 @@ static inline int irqs_disabled(void)
#define mb() barrier()
#define rmb() barrier()
#define wmb() barrier()
-#define read_barrier_depends() do { } while(0)
-#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#define read_barrier_depends() ((void)0)
+#define set_mb(var, value) ({ (var) = (value); wmb(); })
#define smp_mb() barrier()
#define smp_rmb() barrier()
#define smp_wmb() barrier()
-#define smp_read_barrier_depends() do { } while(0)
+#define smp_read_barrier_depends() ((void)0)
#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
diff --git a/include/asm-m68k/uaccess.h b/include/asm-m68k/uaccess.h
index 88b1f47400e1..e4c9f080ff20 100644
--- a/include/asm-m68k/uaccess.h
+++ b/include/asm-m68k/uaccess.h
@@ -76,7 +76,7 @@ asm volatile ("\n" \
break; \
case 8: \
{ \
- const void *__pu_ptr = (ptr); \
+ const void __user *__pu_ptr = (ptr); \
asm volatile ("\n" \
"1: moves.l %2,(%1)+\n" \
"2: moves.l %R2,(%1)\n" \
@@ -125,7 +125,7 @@ asm volatile ("\n" \
" .previous" \
: "+d" (res), "=&" #reg (__gu_val) \
: "m" (*(ptr)), "i" (err)); \
- (x) = (typeof(*(ptr)))(long)__gu_val; \
+ (x) = (typeof(*(ptr)))(unsigned long)__gu_val; \
})
#define __get_user(x, ptr) \
@@ -221,16 +221,16 @@ __constant_copy_from_user(void *to, const void __user *from, unsigned long n)
switch (n) {
case 1:
- __get_user_asm(res, *(u8 *)to, (u8 *)from, u8, b, d, 1);
+ __get_user_asm(res, *(u8 *)to, (u8 __user *)from, u8, b, d, 1);
break;
case 2:
- __get_user_asm(res, *(u16 *)to, (u16 *)from, u16, w, d, 2);
+ __get_user_asm(res, *(u16 *)to, (u16 __user *)from, u16, w, d, 2);
break;
case 3:
__constant_copy_from_user_asm(res, to, from, tmp, 3, w, b,);
break;
case 4:
- __get_user_asm(res, *(u32 *)to, (u32 *)from, u32, l, r, 4);
+ __get_user_asm(res, *(u32 *)to, (u32 __user *)from, u32, l, r, 4);
break;
case 5:
__constant_copy_from_user_asm(res, to, from, tmp, 5, l, b,);
@@ -302,16 +302,16 @@ __constant_copy_to_user(void __user *to, const void *from, unsigned long n)
switch (n) {
case 1:
- __put_user_asm(res, *(u8 *)from, (u8 *)to, b, d, 1);
+ __put_user_asm(res, *(u8 *)from, (u8 __user *)to, b, d, 1);
break;
case 2:
- __put_user_asm(res, *(u16 *)from, (u16 *)to, w, d, 2);
+ __put_user_asm(res, *(u16 *)from, (u16 __user *)to, w, d, 2);
break;
case 3:
__constant_copy_to_user_asm(res, to, from, tmp, 3, w, b,);
break;
case 4:
- __put_user_asm(res, *(u32 *)from, (u32 *)to, l, r, 4);
+ __put_user_asm(res, *(u32 *)from, (u32 __user *)to, l, r, 4);
break;
case 5:
__constant_copy_to_user_asm(res, to, from, tmp, 5, l, b,);
diff --git a/include/asm-m68k/unistd.h b/include/asm-m68k/unistd.h
index 7c0b6296b45c..ad4348058c66 100644
--- a/include/asm-m68k/unistd.h
+++ b/include/asm-m68k/unistd.h
@@ -284,17 +284,47 @@
#define __NR_add_key 279
#define __NR_request_key 280
#define __NR_keyctl 281
+#define __NR_ioprio_set 282
+#define __NR_ioprio_get 283
+#define __NR_inotify_init 284
+#define __NR_inotify_add_watch 285
+#define __NR_inotify_rm_watch 286
+#define __NR_migrate_pages 287
+#define __NR_openat 288
+#define __NR_mkdirat 289
+#define __NR_mknodat 290
+#define __NR_fchownat 291
+#define __NR_futimesat 292
+#define __NR_fstatat64 293
+#define __NR_unlinkat 294
+#define __NR_renameat 295
+#define __NR_linkat 296
+#define __NR_symlinkat 297
+#define __NR_readlinkat 298
+#define __NR_fchmodat 299
+#define __NR_faccessat 300
+#define __NR_pselect6 301
+#define __NR_ppoll 302
+#define __NR_unshare 303
+#define __NR_set_robust_list 304
+#define __NR_get_robust_list 305
+#define __NR_splice 306
+#define __NR_sync_file_range 307
+#define __NR_tee 308
+#define __NR_vmsplice 309
+#define __NR_move_pages 310
#ifdef __KERNEL__
-#define NR_syscalls 282
+#define NR_syscalls 311
+#include <linux/err.h>
-/* user-visible error numbers are in the range -1 - -124: see
+/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
<asm-m68k/errno.h> */
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
/* avoid using res which is declared to be in register d0; \
errno might expand to a function call and clobber it. */ \
int __err = -(res); \
@@ -408,12 +438,6 @@ __syscall_return(type,__res); \
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-m68k/user.h b/include/asm-m68k/user.h
index e8d5a64c7e79..d7c0b109bd45 100644
--- a/include/asm-m68k/user.h
+++ b/include/asm-m68k/user.h
@@ -81,7 +81,7 @@ struct user{
unsigned long magic; /* To uniquely identify a core file */
char u_comm[32]; /* User command that was responsible */
};
-#define NBPG PAGE_SIZE
+#define NBPG 4096
#define UPAGES 1
#define HOST_TEXT_START_ADDR (u.start_code)
#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
diff --git a/include/asm-m68knommu/processor.h b/include/asm-m68knommu/processor.h
index 9d3a1bf41231..91cba18acdd3 100644
--- a/include/asm-m68knommu/processor.h
+++ b/include/asm-m68knommu/processor.h
@@ -1,5 +1,5 @@
/*
- * include/asm-m68k/processor.h
+ * include/asm-m68knommu/processor.h
*
* Copyright (C) 1995 Hamish Macdonald
*/
diff --git a/include/asm-m68knommu/unistd.h b/include/asm-m68knommu/unistd.h
index 1b2abdf281e1..ebaf03197114 100644
--- a/include/asm-m68knommu/unistd.h
+++ b/include/asm-m68knommu/unistd.h
@@ -281,21 +281,51 @@
#define __NR_mq_notify 275
#define __NR_mq_getsetattr 276
#define __NR_waitid 277
-#define __NR_sys_setaltroot 278
+#define __NR_vserver 278
#define __NR_add_key 279
#define __NR_request_key 280
#define __NR_keyctl 281
-
+#define __NR_ioprio_set 282
+#define __NR_ioprio_get 283
+#define __NR_inotify_init 284
+#define __NR_inotify_add_watch 285
+#define __NR_inotify_rm_watch 286
+#define __NR_migrate_pages 287
+#define __NR_openat 288
+#define __NR_mkdirat 289
+#define __NR_mknodat 290
+#define __NR_fchownat 291
+#define __NR_futimesat 292
+#define __NR_fstatat64 293
+#define __NR_unlinkat 294
+#define __NR_renameat 295
+#define __NR_linkat 296
+#define __NR_symlinkat 297
+#define __NR_readlinkat 298
+#define __NR_fchmodat 299
+#define __NR_faccessat 300
+#define __NR_pselect6 301
+#define __NR_ppoll 302
+#define __NR_unshare 303
+#define __NR_set_robust_list 304
+#define __NR_get_robust_list 305
+#define __NR_splice 306
+#define __NR_sync_file_range 307
+#define __NR_tee 308
+#define __NR_vmsplice 309
+#define __NR_move_pages 310
+
#ifdef __KERNEL__
-#define NR_syscalls 282
+#define NR_syscalls 311
+#include <linux/err.h>
-/* user-visible error numbers are in the range -1 - -122: see
+/* user-visible error numbers are in the range -1 - -MAX_ERRNO: see
<asm-m68k/errno.h> */
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
/* avoid using res which is declared to be in register d0; \
errno might expand to a function call and clobber it. */ \
int __err = -(res); \
@@ -462,61 +492,6 @@ type name(atype a, btype b, ctype c, dtype d, etype e) \
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/interrupt.h>
-#include <linux/types.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall0(int,pause)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall1(int,delete_module,const char *,name)
-
-static inline pid_t wait(int * wait_stat)
-{
- return waitpid(-1,wait_stat,0);
-}
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(char *name, char **argv, char **envp);
-asmlinkage int sys_pipe(unsigned long *fildes);
-struct pt_regs;
-int sys_request_irq(unsigned int,
- irqreturn_t (*)(int, void *, struct pt_regs *),
- unsigned long, const char *, void *);
-void sys_free_irq(unsigned int, void *);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-mips/Kbuild b/include/asm-mips/Kbuild
index c68e1680da01..7897f05e3165 100644
--- a/include/asm-mips/Kbuild
+++ b/include/asm-mips/Kbuild
@@ -1 +1,3 @@
include include/asm-generic/Kbuild.asm
+
+header-y += cachectl.h sgidefs.h sysmips.h
diff --git a/include/asm-mips/bootinfo.h b/include/asm-mips/bootinfo.h
index 3b745e76f429..1e5ccdad3b02 100644
--- a/include/asm-mips/bootinfo.h
+++ b/include/asm-mips/bootinfo.h
@@ -112,8 +112,7 @@
* Valid machtype for group GALILEO
*/
#define MACH_GROUP_GALILEO 11 /* Galileo Eval Boards */
-#define MACH_EV96100 0 /* EV96100 */
-#define MACH_EV64120A 1 /* EV64120A */
+#define MACH_EV64120A 0 /* EV64120A */
/*
* Valid machtype for group MOMENCO
@@ -126,12 +125,6 @@
#define MACH_MOMENCO_OCELOT_3 4
/*
- * Valid machtype for group ITE
- */
-#define MACH_GROUP_ITE 13 /* ITE Semi Eval Boards */
-#define MACH_QED_4N_S01B 0 /* ITE8172 based eval board */
-
-/*
* Valid machtype for group PHILIPS
*/
#define MACH_GROUP_PHILIPS 14
@@ -140,12 +133,6 @@
#define MACH_PHILIPS_JBS 2 /* JBS */
/*
- * Valid machtype for group Globespan
- */
-#define MACH_GROUP_GLOBESPAN 15 /* Globespan */
-#define MACH_IVR 0 /* IVR eval board */
-
-/*
* Valid machtype for group SIBYTE
*/
#define MACH_GROUP_SIBYTE 16 /* Sibyte / Broadcom */
diff --git a/include/asm-mips/cacheflush.h b/include/asm-mips/cacheflush.h
index 47bc8f6c20d2..9ab59e2bb233 100644
--- a/include/asm-mips/cacheflush.h
+++ b/include/asm-mips/cacheflush.h
@@ -21,7 +21,6 @@
* - flush_cache_range(vma, start, end) flushes a range of pages
* - flush_icache_range(start, end) flush a range of instructions
* - flush_dcache_page(pg) flushes(wback&invalidates) a page for dcache
- * - flush_icache_page(vma, pg) flushes(invalidates) a page for icache
*
* MIPS specific flush operations:
*
@@ -39,7 +38,7 @@ extern void __flush_dcache_page(struct page *page);
static inline void flush_dcache_page(struct page *page)
{
- if (cpu_has_dc_aliases)
+ if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
__flush_dcache_page(page);
}
@@ -47,8 +46,11 @@ static inline void flush_dcache_page(struct page *page)
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-extern void (*flush_icache_page)(struct vm_area_struct *vma,
- struct page *page);
+static inline void flush_icache_page(struct vm_area_struct *vma,
+ struct page *page)
+{
+}
+
extern void (*flush_icache_range)(unsigned long start, unsigned long end);
#define flush_cache_vmap(start, end) flush_cache_all()
#define flush_cache_vunmap(start, end) flush_cache_all()
@@ -60,7 +62,7 @@ static inline void copy_to_user_page(struct vm_area_struct *vma,
if (cpu_has_dc_aliases)
flush_cache_page(vma, vaddr, page_to_pfn(page));
memcpy(dst, src, len);
- flush_icache_page(vma, page);
+ __flush_icache_page(vma, page);
}
static inline void copy_from_user_page(struct vm_area_struct *vma,
diff --git a/include/asm-mips/dec/ecc.h b/include/asm-mips/dec/ecc.h
index 19495a490e72..707ffdbc9add 100644
--- a/include/asm-mips/dec/ecc.h
+++ b/include/asm-mips/dec/ecc.h
@@ -49,8 +49,7 @@ struct pt_regs;
extern void dec_ecc_be_init(void);
extern int dec_ecc_be_handler(struct pt_regs *regs, int is_fixup);
-extern irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+extern irqreturn_t dec_ecc_be_interrupt(int irq, void *dev_id);
#endif
#endif /* __ASM_MIPS_DEC_ECC_H */
diff --git a/include/asm-mips/dec/kn01.h b/include/asm-mips/dec/kn01.h
index eb522aa1e226..28fa717ac423 100644
--- a/include/asm-mips/dec/kn01.h
+++ b/include/asm-mips/dec/kn01.h
@@ -84,8 +84,7 @@ extern spinlock_t kn01_lock;
extern void dec_kn01_be_init(void);
extern int dec_kn01_be_handler(struct pt_regs *regs, int is_fixup);
-extern irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+extern irqreturn_t dec_kn01_be_interrupt(int irq, void *dev_id);
#endif
#endif /* __ASM_MIPS_DEC_KN01_H */
diff --git a/include/asm-mips/dec/kn02xa.h b/include/asm-mips/dec/kn02xa.h
index a25f3d7da7f7..b56b4577f6ef 100644
--- a/include/asm-mips/dec/kn02xa.h
+++ b/include/asm-mips/dec/kn02xa.h
@@ -78,8 +78,7 @@ struct pt_regs;
extern void dec_kn02xa_be_init(void);
extern int dec_kn02xa_be_handler(struct pt_regs *regs, int is_fixup);
-extern irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+extern irqreturn_t dec_kn02xa_be_interrupt(int irq, void *dev_id);
#endif
#endif /* __ASM_MIPS_DEC_KN02XA_H */
diff --git a/include/asm-mips/fcntl.h b/include/asm-mips/fcntl.h
index 787220e6c1fc..00a50ec1c19f 100644
--- a/include/asm-mips/fcntl.h
+++ b/include/asm-mips/fcntl.h
@@ -25,8 +25,6 @@
#define F_SETOWN 24 /* for sockets. */
#define F_GETOWN 23 /* for sockets. */
-#define F_SETSIG 10 /* for sockets. */
-#define F_GETSIG 11 /* for sockets. */
#ifndef __mips64
#define F_GETLK64 33 /* using 'struct flock64' */
diff --git a/include/asm-mips/fpu.h b/include/asm-mips/fpu.h
index 58c561a9ec6b..efef843b93f0 100644
--- a/include/asm-mips/fpu.h
+++ b/include/asm-mips/fpu.h
@@ -134,9 +134,11 @@ static inline void restore_fp(struct task_struct *tsk)
static inline fpureg_t *get_fpu_regs(struct task_struct *tsk)
{
- if (cpu_has_fpu) {
- if ((tsk == current) && __is_fpu_owner())
+ if (tsk == current) {
+ preempt_disable();
+ if (is_fpu_owner())
_save_fp(current);
+ preempt_enable();
}
return tsk->thread.fpu.fpr;
diff --git a/include/asm-mips/galileo-boards/ev96100.h b/include/asm-mips/galileo-boards/ev96100.h
deleted file mode 100644
index 070dfd84a8e8..000000000000
--- a/include/asm-mips/galileo-boards/ev96100.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- */
-#ifndef _MIPS_EV96100_H
-#define _MIPS_EV96100_H
-
-#include <asm/addrspace.h>
-
-/*
- * GT64120 config space base address
- */
-#define GT64120_BASE (KSEG1ADDR(0x14000000))
-#define MIPS_GT_BASE GT64120_BASE
-
-/*
- * PCI Bus allocation
- */
-#define GT_PCI_MEM_BASE 0x12000000UL
-#define GT_PCI_MEM_SIZE 0x02000000UL
-#define GT_PCI_IO_BASE 0x10000000UL
-#define GT_PCI_IO_SIZE 0x02000000UL
-#define GT_ISA_IO_BASE PCI_IO_BASE
-
-/*
- * Duart I/O ports.
- */
-#define EV96100_COM1_BASE_ADDR (0xBD000000 + 0x20)
-#define EV96100_COM2_BASE_ADDR (0xBD000000 + 0x00)
-
-
-/*
- * EV96100 interrupt controller register base.
- */
-#define EV96100_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000))
-
-/*
- * EV96100 UART register base.
- */
-#define EV96100_UART0_REGS_BASE EV96100_COM1_BASE_ADDR
-#define EV96100_UART1_REGS_BASE EV96100_COM2_BASE_ADDR
-#define EV96100_BASE_BAUD ( 3686400 / 16 )
-
-
-/*
- * Because of an error/peculiarity in the Galileo chip, we need to swap the
- * bytes when running bigendian.
- */
-#define __GT_READ(ofs) \
- (*(volatile u32 *)(GT64120_BASE+(ofs)))
-#define __GT_WRITE(ofs, data) \
- do { *(volatile u32 *)(GT64120_BASE+(ofs)) = (data); } while (0)
-#define GT_READ(ofs) le32_to_cpu(__GT_READ(ofs))
-#define GT_WRITE(ofs, data) __GT_WRITE(ofs, cpu_to_le32(data))
-
-#endif /* !(_MIPS_EV96100_H) */
diff --git a/include/asm-mips/galileo-boards/ev96100int.h b/include/asm-mips/galileo-boards/ev96100int.h
deleted file mode 100644
index c58b16d06d6e..000000000000
--- a/include/asm-mips/galileo-boards/ev96100int.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
- *
- */
-#ifndef _MIPS_EV96100INT_H
-#define _MIPS_EV96100INT_H
-
-#define EV96100INT_UART_0 6 /* IP 6 */
-#define EV96100INT_TIMER 7 /* IP 7 */
-
-extern void ev96100int_init(void);
-
-#endif /* !(_MIPS_EV96100_H) */
diff --git a/include/asm-mips/galileo-boards/gt96100.h b/include/asm-mips/galileo-boards/gt96100.h
deleted file mode 100644
index aabd1b629c19..000000000000
--- a/include/asm-mips/galileo-boards/gt96100.h
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.com
- *
- * This program is free software; you can distribute 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 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.
- *
- * Register offsets of the MIPS GT96100 Advanced Communication Controller.
- */
-#ifndef _GT96100_H
-#define _GT96100_H
-
-/*
- * Galileo GT96100 internal register base.
- */
-#define MIPS_GT96100_BASE (KSEG1ADDR(0x14000000))
-
-#define GT96100_WRITE(ofs, data) \
- *(volatile u32 *)(MIPS_GT96100_BASE+ofs) = cpu_to_le32(data)
-#define GT96100_READ(ofs) \
- le32_to_cpu(*(volatile u32 *)(MIPS_GT96100_BASE+ofs))
-
-#define GT96100_ETH_IO_SIZE 0x4000
-
-/************************************************************************
- * Register offset addresses follow
- ************************************************************************/
-
-/* CPU Interface Control Registers */
-#define GT96100_CPU_INTERF_CONFIG 0x000000
-
-/* Ethernet Ports */
-#define GT96100_ETH_PHY_ADDR_REG 0x080800
-#define GT96100_ETH_SMI_REG 0x080810
-/*
- These are offsets to port 0 registers. Add GT96100_ETH_IO_SIZE to
- get offsets to port 1 registers.
-*/
-#define GT96100_ETH_PORT_CONFIG 0x084800
-#define GT96100_ETH_PORT_CONFIG_EXT 0x084808
-#define GT96100_ETH_PORT_COMM 0x084810
-#define GT96100_ETH_PORT_STATUS 0x084818
-#define GT96100_ETH_SER_PARAM 0x084820
-#define GT96100_ETH_HASH_TBL_PTR 0x084828
-#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_L 0x084830
-#define GT96100_ETH_FLOW_CNTRL_SRC_ADDR_H 0x084838
-#define GT96100_ETH_SDMA_CONFIG 0x084840
-#define GT96100_ETH_SDMA_COMM 0x084848
-#define GT96100_ETH_INT_CAUSE 0x084850
-#define GT96100_ETH_INT_MASK 0x084858
-#define GT96100_ETH_1ST_RX_DESC_PTR0 0x084880
-#define GT96100_ETH_1ST_RX_DESC_PTR1 0x084884
-#define GT96100_ETH_1ST_RX_DESC_PTR2 0x084888
-#define GT96100_ETH_1ST_RX_DESC_PTR3 0x08488C
-#define GT96100_ETH_CURR_RX_DESC_PTR0 0x0848A0
-#define GT96100_ETH_CURR_RX_DESC_PTR1 0x0848A4
-#define GT96100_ETH_CURR_RX_DESC_PTR2 0x0848A8
-#define GT96100_ETH_CURR_RX_DESC_PTR3 0x0848AC
-#define GT96100_ETH_CURR_TX_DESC_PTR0 0x0848E0
-#define GT96100_ETH_CURR_TX_DESC_PTR1 0x0848E4
-#define GT96100_ETH_MIB_COUNT_BASE 0x085800
-
-/* SDMAs */
-#define GT96100_SDMA_GROUP_CONFIG 0x101AF0
-/* SDMA Group 0 */
-#define GT96100_SDMA_G0_CHAN0_CONFIG 0x000900
-#define GT96100_SDMA_G0_CHAN0_COMM 0x000908
-#define GT96100_SDMA_G0_CHAN0_RX_DESC_BASE 0x008900
-#define GT96100_SDMA_G0_CHAN0_CURR_RX_DESC_PTR 0x008910
-#define GT96100_SDMA_G0_CHAN0_TX_DESC_BASE 0x00C900
-#define GT96100_SDMA_G0_CHAN0_CURR_TX_DESC_PTR 0x00C910
-#define GT96100_SDMA_G0_CHAN0_1ST_TX_DESC_PTR 0x00C914
-#define GT96100_SDMA_G0_CHAN1_CONFIG 0x010900
-#define GT96100_SDMA_G0_CHAN1_COMM 0x010908
-#define GT96100_SDMA_G0_CHAN1_RX_DESC_BASE 0x018900
-#define GT96100_SDMA_G0_CHAN1_CURR_RX_DESC_PTR 0x018910
-#define GT96100_SDMA_G0_CHAN1_TX_DESC_BASE 0x01C900
-#define GT96100_SDMA_G0_CHAN1_CURR_TX_DESC_PTR 0x01C910
-#define GT96100_SDMA_G0_CHAN1_1ST_TX_DESC_PTR 0x01C914
-#define GT96100_SDMA_G0_CHAN2_CONFIG 0x020900
-#define GT96100_SDMA_G0_CHAN2_COMM 0x020908
-#define GT96100_SDMA_G0_CHAN2_RX_DESC_BASE 0x028900
-#define GT96100_SDMA_G0_CHAN2_CURR_RX_DESC_PTR 0x028910
-#define GT96100_SDMA_G0_CHAN2_TX_DESC_BASE 0x02C900
-#define GT96100_SDMA_G0_CHAN2_CURR_TX_DESC_PTR 0x02C910
-#define GT96100_SDMA_G0_CHAN2_1ST_TX_DESC_PTR 0x02C914
-#define GT96100_SDMA_G0_CHAN3_CONFIG 0x030900
-#define GT96100_SDMA_G0_CHAN3_COMM 0x030908
-#define GT96100_SDMA_G0_CHAN3_RX_DESC_BASE 0x038900
-#define GT96100_SDMA_G0_CHAN3_CURR_RX_DESC_PTR 0x038910
-#define GT96100_SDMA_G0_CHAN3_TX_DESC_BASE 0x03C900
-#define GT96100_SDMA_G0_CHAN3_CURR_TX_DESC_PTR 0x03C910
-#define GT96100_SDMA_G0_CHAN3_1ST_TX_DESC_PTR 0x03C914
-#define GT96100_SDMA_G0_CHAN4_CONFIG 0x040900
-#define GT96100_SDMA_G0_CHAN4_COMM 0x040908
-#define GT96100_SDMA_G0_CHAN4_RX_DESC_BASE 0x048900
-#define GT96100_SDMA_G0_CHAN4_CURR_RX_DESC_PTR 0x048910
-#define GT96100_SDMA_G0_CHAN4_TX_DESC_BASE 0x04C900
-#define GT96100_SDMA_G0_CHAN4_CURR_TX_DESC_PTR 0x04C910
-#define GT96100_SDMA_G0_CHAN4_1ST_TX_DESC_PTR 0x04C914
-#define GT96100_SDMA_G0_CHAN5_CONFIG 0x050900
-#define GT96100_SDMA_G0_CHAN5_COMM 0x050908
-#define GT96100_SDMA_G0_CHAN5_RX_DESC_BASE 0x058900
-#define GT96100_SDMA_G0_CHAN5_CURR_RX_DESC_PTR 0x058910
-#define GT96100_SDMA_G0_CHAN5_TX_DESC_BASE 0x05C900
-#define GT96100_SDMA_G0_CHAN5_CURR_TX_DESC_PTR 0x05C910
-#define GT96100_SDMA_G0_CHAN5_1ST_TX_DESC_PTR 0x05C914
-#define GT96100_SDMA_G0_CHAN6_CONFIG 0x060900
-#define GT96100_SDMA_G0_CHAN6_COMM 0x060908
-#define GT96100_SDMA_G0_CHAN6_RX_DESC_BASE 0x068900
-#define GT96100_SDMA_G0_CHAN6_CURR_RX_DESC_PTR 0x068910
-#define GT96100_SDMA_G0_CHAN6_TX_DESC_BASE 0x06C900
-#define GT96100_SDMA_G0_CHAN6_CURR_TX_DESC_PTR 0x06C910
-#define GT96100_SDMA_G0_CHAN6_1ST_TX_DESC_PTR 0x06C914
-#define GT96100_SDMA_G0_CHAN7_CONFIG 0x070900
-#define GT96100_SDMA_G0_CHAN7_COMM 0x070908
-#define GT96100_SDMA_G0_CHAN7_RX_DESC_BASE 0x078900
-#define GT96100_SDMA_G0_CHAN7_CURR_RX_DESC_PTR 0x078910
-#define GT96100_SDMA_G0_CHAN7_TX_DESC_BASE 0x07C900
-#define GT96100_SDMA_G0_CHAN7_CURR_TX_DESC_PTR 0x07C910
-#define GT96100_SDMA_G0_CHAN7_1ST_TX_DESC_PTR 0x07C914
-/* SDMA Group 1 */
-#define GT96100_SDMA_G1_CHAN0_CONFIG 0x100900
-#define GT96100_SDMA_G1_CHAN0_COMM 0x100908
-#define GT96100_SDMA_G1_CHAN0_RX_DESC_BASE 0x108900
-#define GT96100_SDMA_G1_CHAN0_CURR_RX_DESC_PTR 0x108910
-#define GT96100_SDMA_G1_CHAN0_TX_DESC_BASE 0x10C900
-#define GT96100_SDMA_G1_CHAN0_CURR_TX_DESC_PTR 0x10C910
-#define GT96100_SDMA_G1_CHAN0_1ST_TX_DESC_PTR 0x10C914
-#define GT96100_SDMA_G1_CHAN1_CONFIG 0x110900
-#define GT96100_SDMA_G1_CHAN1_COMM 0x110908
-#define GT96100_SDMA_G1_CHAN1_RX_DESC_BASE 0x118900
-#define GT96100_SDMA_G1_CHAN1_CURR_RX_DESC_PTR 0x118910
-#define GT96100_SDMA_G1_CHAN1_TX_DESC_BASE 0x11C900
-#define GT96100_SDMA_G1_CHAN1_CURR_TX_DESC_PTR 0x11C910
-#define GT96100_SDMA_G1_CHAN1_1ST_TX_DESC_PTR 0x11C914
-#define GT96100_SDMA_G1_CHAN2_CONFIG 0x120900
-#define GT96100_SDMA_G1_CHAN2_COMM 0x120908
-#define GT96100_SDMA_G1_CHAN2_RX_DESC_BASE 0x128900
-#define GT96100_SDMA_G1_CHAN2_CURR_RX_DESC_PTR 0x128910
-#define GT96100_SDMA_G1_CHAN2_TX_DESC_BASE 0x12C900
-#define GT96100_SDMA_G1_CHAN2_CURR_TX_DESC_PTR 0x12C910
-#define GT96100_SDMA_G1_CHAN2_1ST_TX_DESC_PTR 0x12C914
-#define GT96100_SDMA_G1_CHAN3_CONFIG 0x130900
-#define GT96100_SDMA_G1_CHAN3_COMM 0x130908
-#define GT96100_SDMA_G1_CHAN3_RX_DESC_BASE 0x138900
-#define GT96100_SDMA_G1_CHAN3_CURR_RX_DESC_PTR 0x138910
-#define GT96100_SDMA_G1_CHAN3_TX_DESC_BASE 0x13C900
-#define GT96100_SDMA_G1_CHAN3_CURR_TX_DESC_PTR 0x13C910
-#define GT96100_SDMA_G1_CHAN3_1ST_TX_DESC_PTR 0x13C914
-#define GT96100_SDMA_G1_CHAN4_CONFIG 0x140900
-#define GT96100_SDMA_G1_CHAN4_COMM 0x140908
-#define GT96100_SDMA_G1_CHAN4_RX_DESC_BASE 0x148900
-#define GT96100_SDMA_G1_CHAN4_CURR_RX_DESC_PTR 0x148910
-#define GT96100_SDMA_G1_CHAN4_TX_DESC_BASE 0x14C900
-#define GT96100_SDMA_G1_CHAN4_CURR_TX_DESC_PTR 0x14C910
-#define GT96100_SDMA_G1_CHAN4_1ST_TX_DESC_PTR 0x14C914
-#define GT96100_SDMA_G1_CHAN5_CONFIG 0x150900
-#define GT96100_SDMA_G1_CHAN5_COMM 0x150908
-#define GT96100_SDMA_G1_CHAN5_RX_DESC_BASE 0x158900
-#define GT96100_SDMA_G1_CHAN5_CURR_RX_DESC_PTR 0x158910
-#define GT96100_SDMA_G1_CHAN5_TX_DESC_BASE 0x15C900
-#define GT96100_SDMA_G1_CHAN5_CURR_TX_DESC_PTR 0x15C910
-#define GT96100_SDMA_G1_CHAN5_1ST_TX_DESC_PTR 0x15C914
-#define GT96100_SDMA_G1_CHAN6_CONFIG 0x160900
-#define GT96100_SDMA_G1_CHAN6_COMM 0x160908
-#define GT96100_SDMA_G1_CHAN6_RX_DESC_BASE 0x168900
-#define GT96100_SDMA_G1_CHAN6_CURR_RX_DESC_PTR 0x168910
-#define GT96100_SDMA_G1_CHAN6_TX_DESC_BASE 0x16C900
-#define GT96100_SDMA_G1_CHAN6_CURR_TX_DESC_PTR 0x16C910
-#define GT96100_SDMA_G1_CHAN6_1ST_TX_DESC_PTR 0x16C914
-#define GT96100_SDMA_G1_CHAN7_CONFIG 0x170900
-#define GT96100_SDMA_G1_CHAN7_COMM 0x170908
-#define GT96100_SDMA_G1_CHAN7_RX_DESC_BASE 0x178900
-#define GT96100_SDMA_G1_CHAN7_CURR_RX_DESC_PTR 0x178910
-#define GT96100_SDMA_G1_CHAN7_TX_DESC_BASE 0x17C900
-#define GT96100_SDMA_G1_CHAN7_CURR_TX_DESC_PTR 0x17C910
-#define GT96100_SDMA_G1_CHAN7_1ST_TX_DESC_PTR 0x17C914
-/* MPSCs */
-#define GT96100_MPSC0_MAIN_CONFIG_LOW 0x000A00
-#define GT96100_MPSC0_MAIN_CONFIG_HIGH 0x000A04
-#define GT96100_MPSC0_PROTOCOL_CONFIG 0x000A08
-#define GT96100_MPSC_CHAN0_REG1 0x000A0C
-#define GT96100_MPSC_CHAN0_REG2 0x000A10
-#define GT96100_MPSC_CHAN0_REG3 0x000A14
-#define GT96100_MPSC_CHAN0_REG4 0x000A18
-#define GT96100_MPSC_CHAN0_REG5 0x000A1C
-#define GT96100_MPSC_CHAN0_REG6 0x000A20
-#define GT96100_MPSC_CHAN0_REG7 0x000A24
-#define GT96100_MPSC_CHAN0_REG8 0x000A28
-#define GT96100_MPSC_CHAN0_REG9 0x000A2C
-#define GT96100_MPSC_CHAN0_REG10 0x000A30
-#define GT96100_MPSC_CHAN0_REG11 0x000A34
-#define GT96100_MPSC1_MAIN_CONFIG_LOW 0x008A00
-#define GT96100_MPSC1_MAIN_CONFIG_HIGH 0x008A04
-#define GT96100_MPSC1_PROTOCOL_CONFIG 0x008A08
-#define GT96100_MPSC_CHAN1_REG1 0x008A0C
-#define GT96100_MPSC_CHAN1_REG2 0x008A10
-#define GT96100_MPSC_CHAN1_REG3 0x008A14
-#define GT96100_MPSC_CHAN1_REG4 0x008A18
-#define GT96100_MPSC_CHAN1_REG5 0x008A1C
-#define GT96100_MPSC_CHAN1_REG6 0x008A20
-#define GT96100_MPSC_CHAN1_REG7 0x008A24
-#define GT96100_MPSC_CHAN1_REG8 0x008A28
-#define GT96100_MPSC_CHAN1_REG9 0x008A2C
-#define GT96100_MPSC_CHAN1_REG10 0x008A30
-#define GT96100_MPSC_CHAN1_REG11 0x008A34
-#define GT96100_MPSC2_MAIN_CONFIG_LOW 0x010A00
-#define GT96100_MPSC2_MAIN_CONFIG_HIGH 0x010A04
-#define GT96100_MPSC2_PROTOCOL_CONFIG 0x010A08
-#define GT96100_MPSC_CHAN2_REG1 0x010A0C
-#define GT96100_MPSC_CHAN2_REG2 0x010A10
-#define GT96100_MPSC_CHAN2_REG3 0x010A14
-#define GT96100_MPSC_CHAN2_REG4 0x010A18
-#define GT96100_MPSC_CHAN2_REG5 0x010A1C
-#define GT96100_MPSC_CHAN2_REG6 0x010A20
-#define GT96100_MPSC_CHAN2_REG7 0x010A24
-#define GT96100_MPSC_CHAN2_REG8 0x010A28
-#define GT96100_MPSC_CHAN2_REG9 0x010A2C
-#define GT96100_MPSC_CHAN2_REG10 0x010A30
-#define GT96100_MPSC_CHAN2_REG11 0x010A34
-#define GT96100_MPSC3_MAIN_CONFIG_LOW 0x018A00
-#define GT96100_MPSC3_MAIN_CONFIG_HIGH 0x018A04
-#define GT96100_MPSC3_PROTOCOL_CONFIG 0x018A08
-#define GT96100_MPSC_CHAN3_REG1 0x018A0C
-#define GT96100_MPSC_CHAN3_REG2 0x018A10
-#define GT96100_MPSC_CHAN3_REG3 0x018A14
-#define GT96100_MPSC_CHAN3_REG4 0x018A18
-#define GT96100_MPSC_CHAN3_REG5 0x018A1C
-#define GT96100_MPSC_CHAN3_REG6 0x018A20
-#define GT96100_MPSC_CHAN3_REG7 0x018A24
-#define GT96100_MPSC_CHAN3_REG8 0x018A28
-#define GT96100_MPSC_CHAN3_REG9 0x018A2C
-#define GT96100_MPSC_CHAN3_REG10 0x018A30
-#define GT96100_MPSC_CHAN3_REG11 0x018A34
-#define GT96100_MPSC4_MAIN_CONFIG_LOW 0x020A00
-#define GT96100_MPSC4_MAIN_CONFIG_HIGH 0x020A04
-#define GT96100_MPSC4_PROTOCOL_CONFIG 0x020A08
-#define GT96100_MPSC_CHAN4_REG1 0x020A0C
-#define GT96100_MPSC_CHAN4_REG2 0x020A10
-#define GT96100_MPSC_CHAN4_REG3 0x020A14
-#define GT96100_MPSC_CHAN4_REG4 0x020A18
-#define GT96100_MPSC_CHAN4_REG5 0x020A1C
-#define GT96100_MPSC_CHAN4_REG6 0x020A20
-#define GT96100_MPSC_CHAN4_REG7 0x020A24
-#define GT96100_MPSC_CHAN4_REG8 0x020A28
-#define GT96100_MPSC_CHAN4_REG9 0x020A2C
-#define GT96100_MPSC_CHAN4_REG10 0x020A30
-#define GT96100_MPSC_CHAN4_REG11 0x020A34
-#define GT96100_MPSC5_MAIN_CONFIG_LOW 0x028A00
-#define GT96100_MPSC5_MAIN_CONFIG_HIGH 0x028A04
-#define GT96100_MPSC5_PROTOCOL_CONFIG 0x028A08
-#define GT96100_MPSC_CHAN5_REG1 0x028A0C
-#define GT96100_MPSC_CHAN5_REG2 0x028A10
-#define GT96100_MPSC_CHAN5_REG3 0x028A14
-#define GT96100_MPSC_CHAN5_REG4 0x028A18
-#define GT96100_MPSC_CHAN5_REG5 0x028A1C
-#define GT96100_MPSC_CHAN5_REG6 0x028A20
-#define GT96100_MPSC_CHAN5_REG7 0x028A24
-#define GT96100_MPSC_CHAN5_REG8 0x028A28
-#define GT96100_MPSC_CHAN5_REG9 0x028A2C
-#define GT96100_MPSC_CHAN5_REG10 0x028A30
-#define GT96100_MPSC_CHAN5_REG11 0x028A34
-#define GT96100_MPSC6_MAIN_CONFIG_LOW 0x030A00
-#define GT96100_MPSC6_MAIN_CONFIG_HIGH 0x030A04
-#define GT96100_MPSC6_PROTOCOL_CONFIG 0x030A08
-#define GT96100_MPSC_CHAN6_REG1 0x030A0C
-#define GT96100_MPSC_CHAN6_REG2 0x030A10
-#define GT96100_MPSC_CHAN6_REG3 0x030A14
-#define GT96100_MPSC_CHAN6_REG4 0x030A18
-#define GT96100_MPSC_CHAN6_REG5 0x030A1C
-#define GT96100_MPSC_CHAN6_REG6 0x030A20
-#define GT96100_MPSC_CHAN6_REG7 0x030A24
-#define GT96100_MPSC_CHAN6_REG8 0x030A28
-#define GT96100_MPSC_CHAN6_REG9 0x030A2C
-#define GT96100_MPSC_CHAN6_REG10 0x030A30
-#define GT96100_MPSC_CHAN6_REG11 0x030A34
-#define GT96100_MPSC7_MAIN_CONFIG_LOW 0x038A00
-#define GT96100_MPSC7_MAIN_CONFIG_HIGH 0x038A04
-#define GT96100_MPSC7_PROTOCOL_CONFIG 0x038A08
-#define GT96100_MPSC_CHAN7_REG1 0x038A0C
-#define GT96100_MPSC_CHAN7_REG2 0x038A10
-#define GT96100_MPSC_CHAN7_REG3 0x038A14
-#define GT96100_MPSC_CHAN7_REG4 0x038A18
-#define GT96100_MPSC_CHAN7_REG5 0x038A1C
-#define GT96100_MPSC_CHAN7_REG6 0x038A20
-#define GT96100_MPSC_CHAN7_REG7 0x038A24
-#define GT96100_MPSC_CHAN7_REG8 0x038A28
-#define GT96100_MPSC_CHAN7_REG9 0x038A2C
-#define GT96100_MPSC_CHAN7_REG10 0x038A30
-#define GT96100_MPSC_CHAN7_REG11 0x038A34
-/* FlexTDMs */
-/* TDPR0 - Transmit Dual Port RAM. block size 0xff */
-#define GT96100_FXTDM0_TDPR0_BLK0_BASE 0x000B00
-#define GT96100_FXTDM0_TDPR0_BLK1_BASE 0x001B00
-#define GT96100_FXTDM0_TDPR0_BLK2_BASE 0x002B00
-#define GT96100_FXTDM0_TDPR0_BLK3_BASE 0x003B00
-/* RDPR0 - Receive Dual Port RAM. block size 0xff */
-#define GT96100_FXTDM0_RDPR0_BLK0_BASE 0x004B00
-#define GT96100_FXTDM0_RDPR0_BLK1_BASE 0x005B00
-#define GT96100_FXTDM0_RDPR0_BLK2_BASE 0x006B00
-#define GT96100_FXTDM0_RDPR0_BLK3_BASE 0x007B00
-#define GT96100_FXTDM0_TX_READ_PTR 0x008B00
-#define GT96100_FXTDM0_RX_READ_PTR 0x008B04
-#define GT96100_FXTDM0_CONFIG 0x008B08
-#define GT96100_FXTDM0_AUX_CHANA_TX 0x008B0C
-#define GT96100_FXTDM0_AUX_CHANA_RX 0x008B10
-#define GT96100_FXTDM0_AUX_CHANB_TX 0x008B14
-#define GT96100_FXTDM0_AUX_CHANB_RX 0x008B18
-#define GT96100_FXTDM1_TDPR1_BLK0_BASE 0x010B00
-#define GT96100_FXTDM1_TDPR1_BLK1_BASE 0x011B00
-#define GT96100_FXTDM1_TDPR1_BLK2_BASE 0x012B00
-#define GT96100_FXTDM1_TDPR1_BLK3_BASE 0x013B00
-#define GT96100_FXTDM1_RDPR1_BLK0_BASE 0x014B00
-#define GT96100_FXTDM1_RDPR1_BLK1_BASE 0x015B00
-#define GT96100_FXTDM1_RDPR1_BLK2_BASE 0x016B00
-#define GT96100_FXTDM1_RDPR1_BLK3_BASE 0x017B00
-#define GT96100_FXTDM1_TX_READ_PTR 0x018B00
-#define GT96100_FXTDM1_RX_READ_PTR 0x018B04
-#define GT96100_FXTDM1_CONFIG 0x018B08
-#define GT96100_FXTDM1_AUX_CHANA_TX 0x018B0C
-#define GT96100_FXTDM1_AUX_CHANA_RX 0x018B10
-#define GT96100_FLTDM1_AUX_CHANB_TX 0x018B14
-#define GT96100_FLTDM1_AUX_CHANB_RX 0x018B18
-#define GT96100_FLTDM2_TDPR2_BLK0_BASE 0x020B00
-#define GT96100_FLTDM2_TDPR2_BLK1_BASE 0x021B00
-#define GT96100_FLTDM2_TDPR2_BLK2_BASE 0x022B00
-#define GT96100_FLTDM2_TDPR2_BLK3_BASE 0x023B00
-#define GT96100_FLTDM2_RDPR2_BLK0_BASE 0x024B00
-#define GT96100_FLTDM2_RDPR2_BLK1_BASE 0x025B00
-#define GT96100_FLTDM2_RDPR2_BLK2_BASE 0x026B00
-#define GT96100_FLTDM2_RDPR2_BLK3_BASE 0x027B00
-#define GT96100_FLTDM2_TX_READ_PTR 0x028B00
-#define GT96100_FLTDM2_RX_READ_PTR 0x028B04
-#define GT96100_FLTDM2_CONFIG 0x028B08
-#define GT96100_FLTDM2_AUX_CHANA_TX 0x028B0C
-#define GT96100_FLTDM2_AUX_CHANA_RX 0x028B10
-#define GT96100_FLTDM2_AUX_CHANB_TX 0x028B14
-#define GT96100_FLTDM2_AUX_CHANB_RX 0x028B18
-#define GT96100_FLTDM3_TDPR3_BLK0_BASE 0x030B00
-#define GT96100_FLTDM3_TDPR3_BLK1_BASE 0x031B00
-#define GT96100_FLTDM3_TDPR3_BLK2_BASE 0x032B00
-#define GT96100_FLTDM3_TDPR3_BLK3_BASE 0x033B00
-#define GT96100_FXTDM3_RDPR3_BLK0_BASE 0x034B00
-#define GT96100_FXTDM3_RDPR3_BLK1_BASE 0x035B00
-#define GT96100_FXTDM3_RDPR3_BLK2_BASE 0x036B00
-#define GT96100_FXTDM3_RDPR3_BLK3_BASE 0x037B00
-#define GT96100_FXTDM3_TX_READ_PTR 0x038B00
-#define GT96100_FXTDM3_RX_READ_PTR 0x038B04
-#define GT96100_FXTDM3_CONFIG 0x038B08
-#define GT96100_FXTDM3_AUX_CHANA_TX 0x038B0C
-#define GT96100_FXTDM3_AUX_CHANA_RX 0x038B10
-#define GT96100_FXTDM3_AUX_CHANB_TX 0x038B14
-#define GT96100_FXTDM3_AUX_CHANB_RX 0x038B18
-/* Baud Rate Generators */
-#define GT96100_BRG0_CONFIG 0x102A00
-#define GT96100_BRG0_BAUD_TUNE 0x102A04
-#define GT96100_BRG1_CONFIG 0x102A08
-#define GT96100_BRG1_BAUD_TUNE 0x102A0C
-#define GT96100_BRG2_CONFIG 0x102A10
-#define GT96100_BRG2_BAUD_TUNE 0x102A14
-#define GT96100_BRG3_CONFIG 0x102A18
-#define GT96100_BRG3_BAUD_TUNE 0x102A1C
-#define GT96100_BRG4_CONFIG 0x102A20
-#define GT96100_BRG4_BAUD_TUNE 0x102A24
-#define GT96100_BRG5_CONFIG 0x102A28
-#define GT96100_BRG5_BAUD_TUNE 0x102A2C
-#define GT96100_BRG6_CONFIG 0x102A30
-#define GT96100_BRG6_BAUD_TUNE 0x102A34
-#define GT96100_BRG7_CONFIG 0x102A38
-#define GT96100_BRG7_BAUD_TUNE 0x102A3C
-/* Routing Registers */
-#define GT96100_ROUTE_MAIN 0x101A00
-#define GT96100_ROUTE_RX_CLOCK 0x101A10
-#define GT96100_ROUTE_TX_CLOCK 0x101A20
-/* General Purpose Ports */
-#define GT96100_GPP_CONFIG0 0x100A00
-#define GT96100_GPP_CONFIG1 0x100A04
-#define GT96100_GPP_CONFIG2 0x100A08
-#define GT96100_GPP_CONFIG3 0x100A0C
-#define GT96100_GPP_IO0 0x100A20
-#define GT96100_GPP_IO1 0x100A24
-#define GT96100_GPP_IO2 0x100A28
-#define GT96100_GPP_IO3 0x100A2C
-#define GT96100_GPP_DATA0 0x100A40
-#define GT96100_GPP_DATA1 0x100A44
-#define GT96100_GPP_DATA2 0x100A48
-#define GT96100_GPP_DATA3 0x100A4C
-#define GT96100_GPP_LEVEL0 0x100A60
-#define GT96100_GPP_LEVEL1 0x100A64
-#define GT96100_GPP_LEVEL2 0x100A68
-#define GT96100_GPP_LEVEL3 0x100A6C
-/* Watchdog */
-#define GT96100_WD_CONFIG 0x101A80
-#define GT96100_WD_VALUE 0x101A84
-/* Communication Unit Arbiter */
-#define GT96100_COMM_UNIT_ARBTR_CONFIG 0x101AC0
-/* PCI Arbiters */
-#define GT96100_PCI0_ARBTR_CONFIG 0x101AE0
-#define GT96100_PCI1_ARBTR_CONFIG 0x101AE4
-/* CIU Arbiter */
-#define GT96100_CIU_ARBITER_CONFIG 0x101AC0
-/* Interrupt Controller */
-#define GT96100_MAIN_CAUSE 0x000C18
-#define GT96100_INT0_MAIN_MASK 0x000C1C
-#define GT96100_INT1_MAIN_MASK 0x000C24
-#define GT96100_HIGH_CAUSE 0x000C98
-#define GT96100_INT0_HIGH_MASK 0x000C9C
-#define GT96100_INT1_HIGH_MASK 0x000CA4
-#define GT96100_INT0_SELECT 0x000C70
-#define GT96100_INT1_SELECT 0x000C74
-#define GT96100_SERIAL_CAUSE 0x103A00
-#define GT96100_SERINT0_MASK 0x103A80
-#define GT96100_SERINT1_MASK 0x103A88
-
-#endif /* _GT96100_H */
diff --git a/include/asm-mips/hazards.h b/include/asm-mips/hazards.h
index 25f5e8a4177d..0fe02945feba 100644
--- a/include/asm-mips/hazards.h
+++ b/include/asm-mips/hazards.h
@@ -12,102 +12,95 @@
#ifdef __ASSEMBLY__
-
- .macro _ssnop
- sll $0, $0, 1
- .endm
-
- .macro _ehb
- sll $0, $0, 3
- .endm
-
-/*
- * RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
- * use of the JTLB for instructions should not occur for 4 cpu cycles and use
- * for data translations should not occur for 3 cpu cycles.
- */
-#ifdef CONFIG_CPU_RM9000
-
- .macro mtc0_tlbw_hazard
- .set push
- .set mips32
- _ssnop; _ssnop; _ssnop; _ssnop
- .set pop
- .endm
-
- .macro tlbw_eret_hazard
- .set push
- .set mips32
- _ssnop; _ssnop; _ssnop; _ssnop
- .set pop
- .endm
-
+#define ASMMACRO(name, code...) .macro name; code; .endm
#else
-/*
- * The taken branch will result in a two cycle penalty for the two killed
- * instructions on R4000 / R4400. Other processors only have a single cycle
- * hazard so this is nice trick to have an optimal code for a range of
- * processors.
- */
- .macro mtc0_tlbw_hazard
- b . + 8
- .endm
+#define ASMMACRO(name, code...) \
+__asm__(".macro " #name "; " #code "; .endm"); \
+ \
+static inline void name(void) \
+{ \
+ __asm__ __volatile__ (#name); \
+}
- .macro tlbw_eret_hazard
- .endm
#endif
+ASMMACRO(_ssnop,
+ sll $0, $0, 1
+ )
+
+ASMMACRO(_ehb,
+ sll $0, $0, 3
+ )
+
/*
- * mtc0->mfc0 hazard
- * The 24K has a 2 cycle mtc0/mfc0 execution hazard.
- * It is a MIPS32R2 processor so ehb will clear the hazard.
+ * TLB hazards
*/
+#if defined(CONFIG_CPU_MIPSR2)
-#ifdef CONFIG_CPU_MIPSR2
/*
- * Use a macro for ehb unless explicit support for MIPSR2 is enabled
+ * MIPSR2 defines ehb for hazard avoidance
*/
-#define irq_enable_hazard \
+ASMMACRO(mtc0_tlbw_hazard,
+ _ehb
+ )
+ASMMACRO(tlbw_use_hazard,
+ _ehb
+ )
+ASMMACRO(tlb_probe_hazard,
+ _ehb
+ )
+ASMMACRO(irq_enable_hazard,
+ )
+ASMMACRO(irq_disable_hazard,
_ehb
-
-#define irq_disable_hazard \
- _ehb
-
-#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
-
+ )
+ASMMACRO(back_to_back_c0_hazard,
+ _ehb
+ )
/*
- * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
+ * gcc has a tradition of misscompiling the previous construct using the
+ * address of a label as argument to inline assembler. Gas otoh has the
+ * annoying difference between la and dla which are only usable for 32-bit
+ * rsp. 64-bit code, so can't be used without conditional compilation.
+ * The alterantive is switching the assembler to 64-bit code which happens
+ * to work right even for 32-bit code ...
*/
+#define instruction_hazard() \
+do { \
+ unsigned long tmp; \
+ \
+ __asm__ __volatile__( \
+ " .set mips64r2 \n" \
+ " dla %0, 1f \n" \
+ " jr.hb %0 \n" \
+ " .set mips0 \n" \
+ "1: \n" \
+ : "=r" (tmp)); \
+} while (0)
-#define irq_enable_hazard
-
-#define irq_disable_hazard
-
-#else
+#elif defined(CONFIG_CPU_R10000)
/*
- * Classic MIPS needs 1 - 3 nops or ssnops
+ * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
*/
-#define irq_enable_hazard
-#define irq_disable_hazard \
- _ssnop; _ssnop; _ssnop
-#endif
-
-#else /* __ASSEMBLY__ */
-
-__asm__(
- " .macro _ssnop \n"
- " sll $0, $0, 1 \n"
- " .endm \n"
- " \n"
- " .macro _ehb \n"
- " sll $0, $0, 3 \n"
- " .endm \n");
+ASMMACRO(mtc0_tlbw_hazard,
+ )
+ASMMACRO(tlbw_use_hazard,
+ )
+ASMMACRO(tlb_probe_hazard,
+ )
+ASMMACRO(irq_enable_hazard,
+ )
+ASMMACRO(irq_disable_hazard,
+ )
+ASMMACRO(back_to_back_c0_hazard,
+ )
+#define instruction_hazard() do { } while (0)
-#ifdef CONFIG_CPU_RM9000
+#elif defined(CONFIG_CPU_RM9000)
/*
* RM9000 hazards. When the JTLB is updated by tlbwi or tlbwr, a subsequent
@@ -115,176 +108,73 @@ __asm__(
* for data translations should not occur for 3 cpu cycles.
*/
-#define mtc0_tlbw_hazard() \
- __asm__ __volatile__( \
- " .set mips32 \n" \
- " _ssnop \n" \
- " _ssnop \n" \
- " _ssnop \n" \
- " _ssnop \n" \
- " .set mips0 \n")
-
-#define tlbw_use_hazard() \
- __asm__ __volatile__( \
- " .set mips32 \n" \
- " _ssnop \n" \
- " _ssnop \n" \
- " _ssnop \n" \
- " _ssnop \n" \
- " .set mips0 \n")
-
-#else
-
-/*
- * Overkill warning ...
- */
-#define mtc0_tlbw_hazard() \
- __asm__ __volatile__( \
- " .set noreorder \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " .set reorder \n")
-
-#define tlbw_use_hazard() \
- __asm__ __volatile__( \
- " .set noreorder \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " nop \n" \
- " .set reorder \n")
-
-#endif
-
-/*
- * Interrupt enable/disable hazards
- * Some processors have hazards when modifying
- * the status register to change the interrupt state
- */
-
-#ifdef CONFIG_CPU_MIPSR2
-
-__asm__(" .macro irq_enable_hazard \n"
- " _ehb \n"
- " .endm \n"
- " \n"
- " .macro irq_disable_hazard \n"
- " _ehb \n"
- " .endm \n");
+ASMMACRO(mtc0_tlbw_hazard,
+ _ssnop; _ssnop; _ssnop; _ssnop
+ )
+ASMMACRO(tlbw_use_hazard,
+ _ssnop; _ssnop; _ssnop; _ssnop
+ )
+ASMMACRO(tlb_probe_hazard,
+ _ssnop; _ssnop; _ssnop; _ssnop
+ )
+ASMMACRO(irq_enable_hazard,
+ )
+ASMMACRO(irq_disable_hazard,
+ )
+ASMMACRO(back_to_back_c0_hazard,
+ )
+#define instruction_hazard() do { } while (0)
-#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000)
+#elif defined(CONFIG_CPU_SB1)
/*
- * R10000 rocks - all hazards handled in hardware, so this becomes a nobrainer.
+ * Mostly like R4000 for historic reasons
*/
-
-__asm__(
- " .macro irq_enable_hazard \n"
- " .endm \n"
- " \n"
- " .macro irq_disable_hazard \n"
- " .endm \n");
+ASMMACRO(mtc0_tlbw_hazard,
+ )
+ASMMACRO(tlbw_use_hazard,
+ )
+ASMMACRO(tlb_probe_hazard,
+ )
+ASMMACRO(irq_enable_hazard,
+ )
+ASMMACRO(irq_disable_hazard,
+ _ssnop; _ssnop; _ssnop
+ )
+ASMMACRO(back_to_back_c0_hazard,
+ )
+#define instruction_hazard() do { } while (0)
#else
/*
- * Default for classic MIPS processors. Assume worst case hazards but don't
- * care about the irq_enable_hazard - sooner or later the hardware will
- * enable it and we don't care when exactly.
- */
-
-__asm__(
- " # \n"
- " # There is a hazard but we do not care \n"
- " # \n"
- " .macro\tirq_enable_hazard \n"
- " .endm \n"
- " \n"
- " .macro\tirq_disable_hazard \n"
- " _ssnop \n"
- " _ssnop \n"
- " _ssnop \n"
- " .endm \n");
-
-#endif
-
-#define irq_enable_hazard() \
- __asm__ __volatile__("irq_enable_hazard")
-#define irq_disable_hazard() \
- __asm__ __volatile__("irq_disable_hazard")
-
-
-/*
- * Back-to-back hazards -
+ * Finally the catchall case for all other processors including R4000, R4400,
+ * R4600, R4700, R5000, RM7000, NEC VR41xx etc.
*
- * What is needed to separate a move to cp0 from a subsequent read from the
- * same cp0 register?
- */
-#ifdef CONFIG_CPU_MIPSR2
-
-__asm__(" .macro back_to_back_c0_hazard \n"
- " _ehb \n"
- " .endm \n");
-
-#elif defined(CONFIG_CPU_R10000) || defined(CONFIG_CPU_RM9000) || \
- defined(CONFIG_CPU_SB1)
-
-__asm__(" .macro back_to_back_c0_hazard \n"
- " .endm \n");
-
-#else
-
-__asm__(" .macro back_to_back_c0_hazard \n"
- " .set noreorder \n"
- " _ssnop \n"
- " _ssnop \n"
- " _ssnop \n"
- " .set reorder \n"
- " .endm");
-
-#endif
-
-#define back_to_back_c0_hazard() \
- __asm__ __volatile__("back_to_back_c0_hazard")
-
-
-/*
- * Instruction execution hazard
- */
-#ifdef CONFIG_CPU_MIPSR2
-/*
- * gcc has a tradition of misscompiling the previous construct using the
- * address of a label as argument to inline assembler. Gas otoh has the
- * annoying difference between la and dla which are only usable for 32-bit
- * rsp. 64-bit code, so can't be used without conditional compilation.
- * The alterantive is switching the assembler to 64-bit code which happens
- * to work right even for 32-bit code ...
+ * The taken branch will result in a two cycle penalty for the two killed
+ * instructions on R4000 / R4400. Other processors only have a single cycle
+ * hazard so this is nice trick to have an optimal code for a range of
+ * processors.
*/
-#define instruction_hazard() \
-do { \
- unsigned long tmp; \
- \
- __asm__ __volatile__( \
- " .set mips64r2 \n" \
- " dla %0, 1f \n" \
- " jr.hb %0 \n" \
- " .set mips0 \n" \
- "1: \n" \
- : "=r" (tmp)); \
-} while (0)
-
-#else
+ASMMACRO(mtc0_tlbw_hazard,
+ nop
+ )
+ASMMACRO(tlbw_use_hazard,
+ nop; nop; nop
+ )
+ASMMACRO(tlb_probe_hazard,
+ nop; nop; nop
+ )
+ASMMACRO(irq_enable_hazard,
+ )
+ASMMACRO(irq_disable_hazard,
+ nop; nop; nop
+ )
+ASMMACRO(back_to_back_c0_hazard,
+ _ssnop; _ssnop; _ssnop;
+ )
#define instruction_hazard() do { } while (0)
-#endif
-
-extern void mips_ihb(void);
-#endif /* __ASSEMBLY__ */
+#endif
#endif /* _ASM_HAZARDS_H */
diff --git a/include/asm-mips/io.h b/include/asm-mips/io.h
index df624e1ee6e2..bc5f3c53155f 100644
--- a/include/asm-mips/io.h
+++ b/include/asm-mips/io.h
@@ -172,7 +172,7 @@ extern unsigned long isa_slot_offset;
#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT)
extern void __iomem * __ioremap(phys_t offset, phys_t size, unsigned long flags);
-extern void __iounmap(volatile void __iomem *addr);
+extern void __iounmap(const volatile void __iomem *addr);
static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
unsigned long flags)
@@ -279,7 +279,7 @@ static inline void __iomem * __ioremap_mode(phys_t offset, unsigned long size,
#define ioremap_uncached_accelerated(offset, size) \
__ioremap_mode((offset), (size), _CACHE_UNCACHED_ACCELERATED)
-static inline void iounmap(volatile void __iomem *addr)
+static inline void iounmap(const volatile void __iomem *addr)
{
#define __IS_KSEG1(addr) (((unsigned long)(addr) & ~0x1fffffffUL) == CKSEG1)
@@ -562,32 +562,6 @@ extern void pci_iounmap(struct pci_dev *dev, void __iomem *);
#define eth_io_copy_and_sum(skb,src,len,unused) memcpy_fromio((skb)->data,(src),(len))
/*
- * check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the mmio address io_addr. This
- * address should have been obtained by ioremap.
- * Returns 1 on a match.
- */
-static inline int check_signature(char __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
-/*
* The caches on some architectures aren't dma-coherent and have need to
* handle this in software. There are three types of operations that
* can be applied to dma buffers.
diff --git a/include/asm-mips/irq.h b/include/asm-mips/irq.h
index 896550bad322..0ce2a80b689e 100644
--- a/include/asm-mips/irq.h
+++ b/include/asm-mips/irq.h
@@ -24,9 +24,7 @@ static inline int irq_canonicalize(int irq)
#define irq_canonicalize(irq) (irq) /* Sane hardware, sane code ... */
#endif
-struct pt_regs;
-
-extern asmlinkage unsigned int do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern asmlinkage unsigned int do_IRQ(unsigned int irq);
#ifdef CONFIG_MIPS_MT_SMTC
/*
@@ -55,18 +53,18 @@ do { \
* Ideally there should be away to get this into kernel/irq/handle.c to
* avoid the overhead of a call for just a tiny function ...
*/
-#define do_IRQ(irq, regs) \
+#define do_IRQ(irq) \
do { \
irq_enter(); \
__DO_IRQ_SMTC_HOOK(); \
- __do_IRQ((irq), (regs)); \
+ __do_IRQ((irq)); \
irq_exit(); \
} while (0)
#endif
extern void arch_init_irq(void);
-extern void spurious_interrupt(struct pt_regs *regs);
+extern void spurious_interrupt(void);
#ifdef CONFIG_MIPS_MT_SMTC
struct irqaction;
@@ -76,8 +74,4 @@ extern int setup_irq_smtc(unsigned int irq, struct irqaction * new,
unsigned long hwmask);
#endif /* CONFIG_MIPS_MT_SMTC */
-#ifdef CONFIG_SMP
-#define ARCH_HAS_IRQ_PER_CPU
-#endif
-
#endif /* _ASM_IRQ_H */
diff --git a/include/asm-mips/irq_regs.h b/include/asm-mips/irq_regs.h
new file mode 100644
index 000000000000..33bd2a06de57
--- /dev/null
+++ b/include/asm-mips/irq_regs.h
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ *
+ * Copyright (C) 2006 Ralf Baechle (ralf@linux-mips.org)
+ */
+#ifndef __ASM_IRQ_REGS_H
+#define __ASM_IRQ_REGS_H
+
+#define ARCH_HAS_OWN_IRQ_REGS
+
+#include <linux/thread_info.h>
+
+static inline struct pt_regs *get_irq_regs(void)
+{
+ return current_thread_info()->regs;
+}
+
+#endif /* __ASM_IRQ_REGS_H */
diff --git a/include/asm-mips/irqflags.h b/include/asm-mips/irqflags.h
index 43ca09a3a3d0..46bf5de5ac72 100644
--- a/include/asm-mips/irqflags.h
+++ b/include/asm-mips/irqflags.h
@@ -213,12 +213,37 @@ static inline int raw_irqs_disabled_flags(unsigned long flags)
* Do the CPU's IRQ-state tracing from assembly code.
*/
#ifdef CONFIG_TRACE_IRQFLAGS
+/* Reload some registers clobbered by trace_hardirqs_on */
+#ifdef CONFIG_64BIT
+# define TRACE_IRQS_RELOAD_REGS \
+ LONG_L $11, PT_R11(sp); \
+ LONG_L $10, PT_R10(sp); \
+ LONG_L $9, PT_R9(sp); \
+ LONG_L $8, PT_R8(sp); \
+ LONG_L $7, PT_R7(sp); \
+ LONG_L $6, PT_R6(sp); \
+ LONG_L $5, PT_R5(sp); \
+ LONG_L $4, PT_R4(sp); \
+ LONG_L $2, PT_R2(sp)
+#else
+# define TRACE_IRQS_RELOAD_REGS \
+ LONG_L $7, PT_R7(sp); \
+ LONG_L $6, PT_R6(sp); \
+ LONG_L $5, PT_R5(sp); \
+ LONG_L $4, PT_R4(sp); \
+ LONG_L $2, PT_R2(sp)
+#endif
# define TRACE_IRQS_ON \
+ CLI; /* make sure trace_hardirqs_on() is called in kernel level */ \
jal trace_hardirqs_on
+# define TRACE_IRQS_ON_RELOAD \
+ TRACE_IRQS_ON; \
+ TRACE_IRQS_RELOAD_REGS
# define TRACE_IRQS_OFF \
jal trace_hardirqs_off
#else
# define TRACE_IRQS_ON
+# define TRACE_IRQS_ON_RELOAD
# define TRACE_IRQS_OFF
#endif
diff --git a/include/asm-mips/it8172/it8172.h b/include/asm-mips/it8172/it8172.h
deleted file mode 100644
index 8f23af0a1ee8..000000000000
--- a/include/asm-mips/it8172/it8172.h
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * IT8172 system controller defines.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#ifndef __IT8172__H__
-#define __IT8172__H__
-
-#include <asm/addrspace.h>
-
-#define IT8172_BASE 0x18000000
-#define IT8172_PCI_IO_BASE 0x14000000
-#define IT8172_PCI_MEM_BASE 0x10000000
-
-// System registers offsets from IT8172_BASE
-#define IT_CMFPCR 0x0
-#define IT_DSRR 0x2
-#define IT_PCDCR 0x4
-#define IT_SPLLCR 0x6
-#define IT_CIDR 0x10
-#define IT_CRNR 0x12
-#define IT_CPUTR 0x14
-#define IT_CTCR 0x16
-#define IT_SDPR 0xF0
-
-// Power management register offset from IT8172_PCI_IO_BASE
-// Power Management Device Standby Register
-#define IT_PM_DSR 0x15800
-
-#define IT_PM_DSR_TMR0SB 0x0001
-#define IT_PM_DSR_TMR1SB 0x0002
-#define IT_PM_DSR_CIR0SB 0x0004
-#define IT_PM_DSR_CIR1SB 0x0008
-#define IT_PM_DSR_SCR0SB 0x0010
-#define IT_PM_DSR_SCR1SB 0x0020
-#define IT_PM_DSR_PPSB 0x0040
-#define IT_PM_DSR_I2CSB 0x0080
-#define IT_PM_DSR_UARTSB 0x0100
-#define IT_PM_DSR_IDESB 0x0200
-#define IT_PM_DSR_ACSB 0x0400
-#define IT_PM_DSR_M68KSB 0x0800
-
-// Power Management PCI Device Software Reset Register
-#define IT_PM_PCISR 0x15802
-
-#define IT_PM_PCISR_IDESR 0x0001
-#define IT_PM_PCISR_CDMASR 0x0002
-#define IT_PM_PCISR_USBSR 0x0004
-#define IT_PM_PCISR_DMASR 0x0008
-#define IT_PM_PCISR_ACSR 0x0010
-#define IT_PM_PCISR_MEMSR 0x0020
-#define IT_PM_PCISR_68KSR 0x0040
-
-
-// PCI Configuration address and data register offsets
-// from IT8172_BASE
-#define IT_CONFADDR 0x4000
-#define IT_BUSNUM_SHF 16
-#define IT_DEVNUM_SHF 11
-#define IT_FUNCNUM_SHF 8
-#define IT_REGNUM_SHF 2
-
-#define IT_CONFDATA 0x4004
-
-// PCI configuration header common register offsets
-#define IT_VID 0x00
-#define IT_DID 0x02
-#define IT_PCICMD 0x04
-#define IT_PCISTS 0x06
-#define IT_RID 0x08
-#define IT_CLASSC 0x09
-#define IT_HEADT 0x0E
-#define IT_SERIRQC 0x49
-
-// PCI to Internal/LPC Bus Bridge configuration header register offset
-#define IT_P2I_BCR 0x4C
-#define IT_P2I_D0IOSC 0x50
-#define IT_P2I_D1IOSC 0x54
-#define IT_P2I_D2IOSC 0x58
-#define IT_P2I_D3IOSC 0x5C
-#define IT_P2I_D4IOSC 0x60
-#define IT_P2I_D5IOSC 0x64
-#define IT_P2I_D6IOSC 0x68
-#define IT_P2I_D7IOSC 0x6C
-#define IT_P2I_D8IOSC 0x70
-#define IT_P2I_D9IOSC 0x74
-#define IT_P2I_D10IOSC 0x78
-#define IT_P2I_D11IOSC 0x7C
-
-// Memory controller register offsets from IT8172_BASE
-#define IT_MC_SDRMR 0x1000
-#define IT_MC_SDRTR 0x1004
-#define IT_MC_MCR 0x1008
-#define IT_MC_SDTYPE 0x100C
-#define IT_MC_WPBA 0x1010
-#define IT_MC_WPTA 0x1014
-#define IT_MC_HATR 0x1018
-#define IT_MC_PCICR 0x101C
-
-// Flash/ROM control register offsets from IT8172_BASE
-#define IT_FC_BRCR 0x2000
-#define IT_FC_FCR 0x2004
-#define IT_FC_DCR 0x2008
-
-// M68K interface bridge configuration header register offset
-#define IT_M68K_MBCSR 0x54
-#define IT_M68K_TMR 0x58
-#define IT_M68K_BCR 0x5C
-#define IT_M68K_BSR 0x5D
-#define IT_M68K_DTR 0x5F
-
-// Register offset from IT8172_PCI_IO_BASE
-// These registers are accessible through 8172 PCI IO window.
-
-// INTC
-#define IT_INTC_BASE 0x10000
-#define IT_INTC_LBDNIRR 0x10000
-#define IT_INTC_LBDNIMR 0x10002
-#define IT_INTC_LBDNITR 0x10004
-#define IT_INTC_LBDNIAR 0x10006
-#define IT_INTC_LPCNIRR 0x10010
-#define IT_INTC_LPCNIMR 0x10012
-#define IT_INTC_LPCNITR 0x10014
-#define IT_INTC_LPCNIAR 0x10016
-#define IT_INTC_PDNIRR 0x10020
-#define IT_INTC_PDNIMR 0x10022
-#define IT_INTC_PDNITR 0x10024
-#define IT_INTC_PDNIAR 0x10026
-#define IT_INTC_UMNIRR 0x10030
-#define IT_INTC_UMNITR 0x10034
-#define IT_INTC_UMNIAR 0x10036
-#define IT_INTC_TYPER 0x107FE
-
-// IT8172 PCI device number
-#define IT_C2P_DEVICE 0
-#define IT_AUDIO_DEVICE 1
-#define IT_DMAC_DEVICE 1
-#define IT_CDMAC_DEVICE 1
-#define IT_USB_DEVICE 1
-#define IT_P2I_DEVICE 1
-#define IT_IDE_DEVICE 1
-#define IT_M68K_DEVICE 1
-
-// IT8172 PCI function number
-#define IT_C2P_FUNCION 0
-#define IT_AUDIO_FUNCTION 0
-#define IT_DMAC_FUNCTION 1
-#define IT_CDMAC_FUNCTION 2
-#define IT_USB_FUNCTION 3
-#define IT_P2I_FUNCTION 4
-#define IT_IDE_FUNCTION 5
-#define IT_M68K_FUNCTION 6
-
-// IT8172 GPIO
-#define IT_GPADR 0x13800
-#define IT_GPBDR 0x13808
-#define IT_GPCDR 0x13810
-#define IT_GPACR 0x13802
-#define IT_GPBCR 0x1380A
-#define IT_GPCCR 0x13812
-#define IT_GPAICR 0x13804
-#define IT_GPBICR 0x1380C
-#define IT_GPCICR 0x13814
-#define IT_GPAISR 0x13806
-#define IT_GPBISR 0x1380E
-#define IT_GPCISR 0x13816
-#define IT_GCR 0x13818
-
-// IT8172 RTC
-#define IT_RTC_BASE 0x14800
-#define IT_RTC_CENTURY 0x14808
-
-#define IT_RTC_RIR0 0x00
-#define IT_RTC_RTR0 0x01
-#define IT_RTC_RIR1 0x02
-#define IT_RTC_RTR1 0x03
-#define IT_RTC_RIR2 0x04
-#define IT_RTC_RTR2 0x05
-#define IT_RTC_RCTR 0x08
-#define IT_RTC_RA 0x0A
-#define IT_RTC_RB 0x0B
-#define IT_RTC_RC 0x0C
-#define IT_RTC_RD 0x0D
-
-#define RTC_SEC_INDEX 0x00
-#define RTC_MIN_INDEX 0x02
-#define RTC_HOUR_INDEX 0x04
-#define RTC_DAY_INDEX 0x06
-#define RTC_DATE_INDEX 0x07
-#define RTC_MONTH_INDEX 0x08
-#define RTC_YEAR_INDEX 0x09
-
-// IT8172 internal device registers
-#define IT_TIMER_BASE 0x10800
-#define IT_CIR0_BASE 0x11000
-#define IT_UART_BASE 0x11800
-#define IT_SCR0_BASE 0x12000
-#define IT_SCR1_BASE 0x12800
-#define IT_PP_BASE 0x13000
-#define IT_I2C_BASE 0x14000
-#define IT_CIR1_BASE 0x15000
-
-// IT8172 Smart Card Reader offsets from IT_SCR*_BASE
-#define IT_SCR_SFR 0x08
-#define IT_SCR_SCDR 0x09
-
-// IT8172 IT_SCR_SFR bit definition & mask
-#define IT_SCR_SFR_GATE_UART 0x40
-#define IT_SCR_SFR_GATE_UART_BIT 6
-#define IT_SCR_SFR_GATE_UART_OFF 0
-#define IT_SCR_SFR_GATE_UART_ON 1
-#define IT_SCR_SFR_FET_CHARGE 0x30
-#define IT_SCR_SFR_FET_CHARGE_BIT 4
-#define IT_SCR_SFR_FET_CHARGE_3_3_US 3
-#define IT_SCR_SFR_FET_CHARGE_13_US 2
-#define IT_SCR_SFR_FET_CHARGE_53_US 1
-#define IT_SCR_SFR_FET_CHARGE_213_US 0
-#define IT_SCR_SFR_CARD_FREQ 0x0C
-#define IT_SCR_SFR_CARD_FREQ_BIT 2
-#define IT_SCR_SFR_CARD_FREQ_STOP 3
-#define IT_SCR_SFR_CARD_FREQ_3_5_MHZ 0
-#define IT_SCR_SFR_CARD_FREQ_7_1_MHZ 2
-#define IT_SCR_SFR_CARD_FREQ_96_DIV_MHZ 1
-#define IT_SCR_SFR_FET_ACTIVE 0x02
-#define IT_SCR_SFR_FET_ACTIVE_BIT 1
-#define IT_SCR_SFR_FET_ACTIVE_INVERT 0
-#define IT_SCR_SFR_FET_ACTIVE_NONINVERT 1
-#define IT_SCR_SFR_ENABLE 0x01
-#define IT_SCR_SFR_ENABLE_BIT 0
-#define IT_SCR_SFR_ENABLE_OFF 0
-#define IT_SCR_SFR_ENABLE_ON 1
-
-// IT8172 IT_SCR_SCDR bit definition & mask
-#define IT_SCR_SCDR_RESET_MODE 0x80
-#define IT_SCR_SCDR_RESET_MODE_BIT 7
-#define IT_SCR_SCDR_RESET_MODE_ASYNC 0
-#define IT_SCR_SCDR_RESET_MODE_SYNC 1
-#define IT_SCR_SCDR_DIVISOR 0x7F
-#define IT_SCR_SCDR_DIVISOR_BIT 0
-#define IT_SCR_SCDR_DIVISOR_STOP_VAL_1 0x00
-#define IT_SCR_SCDR_DIVISOR_STOP_VAL_2 0x01
-#define IT_SCR_SCDR_DIVISOR_STOP_VAL_3 0x7F
-
-// IT8172 DMA
-#define IT_DMAC_BASE 0x16000
-#define IT_DMAC_BCAR0 0x00
-#define IT_DMAC_BCAR1 0x04
-#define IT_DMAC_BCAR2 0x08
-#define IT_DMAC_BCAR3 0x0C
-#define IT_DMAC_BCCR0 0x02
-#define IT_DMAC_BCCR1 0x06
-#define IT_DMAC_BCCR2 0x0a
-#define IT_DMAC_BCCR3 0x0e
-#define IT_DMAC_CR 0x10
-#define IT_DMAC_SR 0x12
-#define IT_DMAC_ESR 0x13
-#define IT_DMAC_RQR 0x14
-#define IT_DMAC_MR 0x16
-#define IT_DMAC_EMR 0x17
-#define IT_DMAC_MKR 0x18
-#define IT_DMAC_PAR0 0x20
-#define IT_DMAC_PAR1 0x22
-#define IT_DMAC_PAR2 0x24
-#define IT_DMAC_PAR3 0x26
-
-// IT8172 IDE
-#define IT_IDE_BASE 0x17800
-#define IT_IDE_STATUS 0x1F7
-
-// IT8172 Audio Controller
-#define IT_AC_BASE 0x17000
-#define IT_AC_PCMOV 0x00
-#define IT_AC_FMOV 0x02
-#define IT_AC_I2SV 0x04
-#define IT_AC_DRSS 0x06
-#define IT_AC_PCC 0x08
-#define IT_AC_PCDL 0x0A
-#define IT_AC_PCB1STA 0x0C
-#define IT_AC_PCB2STA 0x10
-#define IT_AC_CAPCC 0x14
-#define IT_AC_CAPCDL 0x16
-#define IT_AC_CAPB1STA 0x18
-#define IT_AC_CAPB2STA 0x1C
-#define IT_AC_CODECC 0x22
-#define IT_AC_I2SMC 0x24
-#define IT_AC_VS 0x26
-#define IT_AC_SRCS 0x28
-#define IT_AC_CIRCP 0x2A
-#define IT_AC_CIRDP 0x2C
-#define IT_AC_TM 0x4A
-#define IT_AC_PFDP 0x4C
-#define IT_AC_GC 0x54
-#define IT_AC_IMC 0x56
-#define IT_AC_ISC 0x5B
-#define IT_AC_OPL3SR 0x68
-#define IT_AC_OPL3DWDR 0x69
-#define IT_AC_OPL3AB1W 0x6A
-#define IT_AC_OPL3DW 0x6B
-#define IT_AC_BPDC 0x70
-
-
-// IT8172 Timer
-#define IT_TIMER_BASE 0x10800
-#define TIMER_TCVR0 0x00
-#define TIMER_TRVR0 0x02
-#define TIMER_TCR0 0x04
-#define TIMER_TIRR 0x06
-#define TIMER_TCVR1 0x08
-#define TIMER_TRVR1 0x0A
-#define TIMER_TCR1 0x0C
-#define TIMER_TIDR 0x0E
-
-
-#define IT_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs)) = data
-#define IT_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_BASE+ofs))
-
-#define IT_IO_WRITE(ofs, data) *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
-#define IT_IO_READ(ofs, data) data = *(volatile u32 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
-
-#define IT_IO_WRITE16(ofs, data) *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs)) = data
-#define IT_IO_READ16(ofs, data) data = *(volatile u16 *)KSEG1ADDR((IT8172_PCI_IO_BASE+ofs))
-
-#endif
diff --git a/include/asm-mips/it8172/it8172_cir.h b/include/asm-mips/it8172/it8172_cir.h
deleted file mode 100644
index 6a1dbd29f6d1..000000000000
--- a/include/asm-mips/it8172/it8172_cir.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * IT8172 Consumer IR port defines.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#define NUM_CIR_PORTS 2
-
-/* Master Control Register */
-#define CIR_RESET 0x1
-#define CIR_FIFO_CLEAR 0x2
-#define CIR_SET_FIFO_TL(x) (((x)&0x3)<<2)
-#define CIR_ILE 0x10
-#define CIR_ILSEL 0x20
-
-/* Interrupt Enable Register */
-#define CIR_TLDLIE 0x1
-#define CIR_RDAIE 0x2
-#define CIR_RFOIE 0x4
-#define CIR_IEC 0x80
-
-/* Interrupt Identification Register */
-#define CIR_TLDLI 0x1
-#define CIR_RDAI 0x2
-#define CIR_RFOI 0x4
-#define CIR_NIP 0x80
-
-/* Carrier Frequency Register */
-#define CIR_SET_CF(x) ((x)&0x1f)
- #define CFQ_38_480 0xB /* 38 KHz low, 480 KHz high */
-#define CIR_HCFS 0x20
- #define CIR_SET_HS(x) (((x)&0x1)<<5)
-
-
-/* Receiver Control Register */
-#define CIR_SET_RXDCR(x) ((x)&0x7)
-#define CIR_RXACT 0x8
-#define CIR_RXEND 0x10
-#define CIR_RDWOS 0x20
- #define CIR_SET_RDWOS(x) (((x)&0x1)<<5)
-#define CIR_RXEN 0x80
-
-/* Transmitter Control Register */
-#define CIR_SET_TXMPW(x) ((x)&0x7)
-#define CIR_SET_TXMPM(x) (((x)&0x3)<<3)
-#define CIR_TXENDF 0x20
-#define CIR_TXRLE 0x40
-
-/* Receiver FIFO Status Register */
-#define CIR_RXFBC_MASK 0x3f
-#define CIR_RXFTO 0x80
-
-/* Wakeup Code Length Register */
-#define CIR_SET_WCL ((x)&0x3f)
-#define CIR_WCL_MASK(x) ((x)&0x3f)
-
-/* Wakeup Power Control/Status Register */
-#define CIR_BTMON 0x2
-#define CIR_CIRON 0x4
-#define CIR_RCRST 0x10
-#define CIR_WCRST 0x20
-
-struct cir_port {
- int port;
- unsigned short baud_rate;
- unsigned char fifo_tl;
- unsigned char cfq;
- unsigned char hcfs;
- unsigned char rdwos;
- unsigned char rxdcr;
-};
-
-struct it8172_cir_regs {
- unsigned char dr; /* data */
- char pad;
- unsigned char mstcr; /* master control */
- char pad1;
- unsigned char ier; /* interrupt enable */
- char pad2;
- unsigned char iir; /* interrupt identification */
- char pad3;
- unsigned char cfr; /* carrier frequency */
- char pad4;
- unsigned char rcr; /* receiver control */
- char pad5;
- unsigned char tcr; /* transmitter control */
- char pad6;
- char pad7;
- char pad8;
- unsigned char bdlr; /* baud rate divisor low byte */
- char pad9;
- unsigned char bdhr; /* baud rate divisor high byte */
- char pad10;
- unsigned char tfsr; /* tx fifo byte count */
- char pad11;
- unsigned char rfsr; /* rx fifo status */
- char pad12;
- unsigned char wcl; /* wakeup code length */
- char pad13;
- unsigned char wcr; /* wakeup code read/write */
- char pad14;
- unsigned char wps; /* wakeup power control/status */
-};
-
-int cir_port_init(struct cir_port *cir);
-extern void clear_fifo(struct cir_port *cir);
-extern void enable_receiver(struct cir_port *cir);
-extern void disable_receiver(struct cir_port *cir);
-extern void enable_rx_demodulation(struct cir_port *cir);
-extern void disable_rx_demodulation(struct cir_port *cir);
-extern void set_rx_active(struct cir_port *cir);
-extern void int_enable(struct cir_port *cir);
-extern void rx_int_enable(struct cir_port *cir);
-extern char get_int_status(struct cir_port *cir);
-extern int cir_get_rx_count(struct cir_port *cir);
-extern char cir_read_data(struct cir_port *cir);
diff --git a/include/asm-mips/it8172/it8172_dbg.h b/include/asm-mips/it8172/it8172_dbg.h
deleted file mode 100644
index f404ec7c03ac..000000000000
--- a/include/asm-mips/it8172/it8172_dbg.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * Function prototypes for low level uart routines to
- * directly access a 16550 uart.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#include <linux/types.h>
-
-extern void putch(const unsigned char c);
-extern void puts(unsigned char *cp);
-extern void fputs(unsigned char *cp);
-extern void put64(uint64_t ul);
-extern void put32(unsigned u);
diff --git a/include/asm-mips/it8172/it8172_int.h b/include/asm-mips/it8172/it8172_int.h
deleted file mode 100644
index 837e83ac25f5..000000000000
--- a/include/asm-mips/it8172/it8172_int.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * ITE 8172 Interrupt Numbering
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#ifndef _MIPS_ITEINT_H
-#define _MIPS_ITEINT_H
-
-/*
- * Here's the "strategy":
- * We number the LPC serial irqs from 0 to 15,
- * the local bus irqs from 16 to 31,
- * the pci dev register interrupts from 32 to 47,
- * and the non-maskable ints from 48 to 53.
- */
-
-#define IT8172_LPC_IRQ_BASE 0 /* first LPC int number */
-#define IT8172_SERIRQ_0 (IT8172_LPC_IRQ_BASE + 0)
-#define IT8172_SERIRQ_1 (IT8172_LPC_IRQ_BASE + 1)
-#define IT8172_SERIRQ_2 (IT8172_LPC_IRQ_BASE + 2)
-#define IT8172_SERIRQ_3 (IT8172_LPC_IRQ_BASE + 3)
-#define IT8172_SERIRQ_4 (IT8172_LPC_IRQ_BASE + 4)
-#define IT8172_SERIRQ_5 (IT8172_LPC_IRQ_BASE + 5)
-#define IT8172_SERIRQ_6 (IT8172_LPC_IRQ_BASE + 6)
-#define IT8172_SERIRQ_7 (IT8172_LPC_IRQ_BASE + 7)
-#define IT8172_SERIRQ_8 (IT8172_LPC_IRQ_BASE + 8)
-#define IT8172_SERIRQ_9 (IT8172_LPC_IRQ_BASE + 9)
-#define IT8172_SERIRQ_10 (IT8172_LPC_IRQ_BASE + 10)
-#define IT8172_SERIRQ_11 (IT8172_LPC_IRQ_BASE + 11)
-#define IT8172_SERIRQ_12 (IT8172_LPC_IRQ_BASE + 12)
-#define IT8172_SERIRQ_13 (IT8172_LPC_IRQ_BASE + 13)
-#define IT8172_SERIRQ_14 (IT8172_LPC_IRQ_BASE + 14)
-#define IT8172_SERIRQ_15 (IT8172_LPC_IRQ_BASE + 15)
-
-#define IT8172_LB_IRQ_BASE 16 /* first local bus int number */
-#define IT8172_PPR_IRQ (IT8172_LB_IRQ_BASE + 0) /* parallel port */
-#define IT8172_TIMER0_IRQ (IT8172_LB_IRQ_BASE + 1)
-#define IT8172_TIMER1_IRQ (IT8172_LB_IRQ_BASE + 2)
-#define IT8172_I2C_IRQ (IT8172_LB_IRQ_BASE + 3)
-#define IT8172_GPIO_IRQ (IT8172_LB_IRQ_BASE + 4)
-#define IT8172_CIR0_IRQ (IT8172_LB_IRQ_BASE + 5)
-#define IT8172_CIR1_IRQ (IT8172_LB_IRQ_BASE + 6)
-#define IT8172_UART_IRQ (IT8172_LB_IRQ_BASE + 7)
-#define IT8172_SCR0_IRQ (IT8172_LB_IRQ_BASE + 8)
-#define IT8172_SCR1_IRQ (IT8172_LB_IRQ_BASE + 9)
-#define IT8172_RTC_IRQ (IT8172_LB_IRQ_BASE + 10)
-#define IT8172_IOCHK_IRQ (IT8172_LB_IRQ_BASE + 11)
-/* 12 - 15 reserved */
-
-/*
- * Note here that the pci dev registers includes bits for more than
- * just the pci devices.
- */
-#define IT8172_PCI_DEV_IRQ_BASE 32 /* first pci dev irq */
-#define IT8172_AC97_IRQ (IT8172_PCI_DEV_IRQ_BASE + 0)
-#define IT8172_MC68K_IRQ (IT8172_PCI_DEV_IRQ_BASE + 1)
-#define IT8172_IDE_IRQ (IT8172_PCI_DEV_IRQ_BASE + 2)
-#define IT8172_USB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 3)
-#define IT8172_BRIDGE_MASTER_IRQ (IT8172_PCI_DEV_IRQ_BASE + 4)
-#define IT8172_BRIDGE_TARGET_IRQ (IT8172_PCI_DEV_IRQ_BASE + 5)
-#define IT8172_PCI_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 6)
-#define IT8172_PCI_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 7)
-#define IT8172_PCI_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 8)
-#define IT8172_PCI_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 9)
-#define IT8172_S_INTA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 10)
-#define IT8172_S_INTB_IRQ (IT8172_PCI_DEV_IRQ_BASE + 11)
-#define IT8172_S_INTC_IRQ (IT8172_PCI_DEV_IRQ_BASE + 12)
-#define IT8172_S_INTD_IRQ (IT8172_PCI_DEV_IRQ_BASE + 13)
-#define IT8172_CDMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 14)
-#define IT8172_DMA_IRQ (IT8172_PCI_DEV_IRQ_BASE + 15)
-
-#define IT8172_NMI_IRQ_BASE 48
-#define IT8172_SER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 0)
-#define IT8172_PCI_NMI_IRQ (IT8172_NMI_IRQ_BASE + 1)
-#define IT8172_RTC_NMI_IRQ (IT8172_NMI_IRQ_BASE + 2)
-#define IT8172_CPUIF_NMI_IRQ (IT8172_NMI_IRQ_BASE + 3)
-#define IT8172_PMER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 4)
-#define IT8172_POWER_NMI_IRQ (IT8172_NMI_IRQ_BASE + 5)
-
-#define IT8172_LAST_IRQ (IT8172_POWER_NMI_IRQ)
-/* Finally, let's move over here the mips cpu timer interrupt.
- */
-#define MIPS_CPU_TIMER_IRQ (NR_IRQS-1)
-
-/*
- * IT8172 Interrupt Controller Registers
- */
-struct it8172_intc_regs {
- volatile unsigned short lb_req; /* offset 0 */
- volatile unsigned short lb_mask;
- volatile unsigned short lb_trigger;
- volatile unsigned short lb_level;
- unsigned char pad0[8];
-
- volatile unsigned short lpc_req; /* offset 0x10 */
- volatile unsigned short lpc_mask;
- volatile unsigned short lpc_trigger;
- volatile unsigned short lpc_level;
- unsigned char pad1[8];
-
- volatile unsigned short pci_req; /* offset 0x20 */
- volatile unsigned short pci_mask;
- volatile unsigned short pci_trigger;
- volatile unsigned short pci_level;
- unsigned char pad2[8];
-
- volatile unsigned short nmi_req; /* offset 0x30 */
- volatile unsigned short nmi_mask;
- volatile unsigned short nmi_trigger;
- volatile unsigned short nmi_level;
- unsigned char pad3[6];
-
- volatile unsigned short nmi_redir; /* offset 0x3E */
- unsigned char pad4[0xBE];
-
- volatile unsigned short intstatus; /* offset 0xFE */
-};
-
-#endif /* _MIPS_ITEINT_H */
diff --git a/include/asm-mips/it8172/it8172_pci.h b/include/asm-mips/it8172/it8172_pci.h
deleted file mode 100644
index 42c61f56eeba..000000000000
--- a/include/asm-mips/it8172/it8172_pci.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- *
- * BRIEF MODULE DESCRIPTION
- * IT8172 system controller specific pci defines.
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * ppopov@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#ifndef _8172PCI_H_
-#define _8172PCI_H_
-
-// PCI configuration space Type0
-#define PCI_IDREG 0x00
-#define PCI_CMDSTSREG 0x04
-#define PCI_CLASSREG 0x08
-#define PCI_BHLCREG 0x0C
-#define PCI_BASE1REG 0x10
-#define PCI_BASE2REG 0x14
-#define PCI_BASE3REG 0x18
-#define PCI_BASE4REG 0x1C
-#define PCI_BASE5REG 0x20
-#define PCI_BASE6REG 0x24
-#define PCI_ROMBASEREG 0x30
-#define PCI_INTRREG 0x3C
-
-// PCI configuration space Type1
-#define PCI_BUSNOREG 0x18
-
-#define IT_PCI_VENDORID(x) ((x) & 0xFFFF)
-#define IT_PCI_DEVICEID(x) (((x)>>16) & 0xFFFF)
-
-// Command register
-#define PCI_CMD_IOEN 0x00000001
-#define PCI_CMD_MEMEN 0x00000002
-#define PCI_CMD_BUSMASTER 0x00000004
-#define PCI_CMD_SPCYCLE 0x00000008
-#define PCI_CMD_WRINV 0x00000010
-#define PCI_CMD_VGASNOOP 0x00000020
-#define PCI_CMD_PERR 0x00000040
-#define PCI_CMD_WAITCTRL 0x00000080
-#define PCI_CMD_SERR 0x00000100
-#define PCI_CMD_FAST_BACKTOBACK 0x00000200
-
-// Status register
-#define PCI_STS_66MHZ 0x00200000
-#define PCI_STS_SUPPORT_UDF 0x00400000
-#define PCI_STS_FAST_BACKTOBACK 0x00800000
-#define PCI_STS_DATA_PERR 0x01000000
-#define PCI_STS_DEVSEL0 0x02000000
-#define PCI_STS_DEVSEL1 0x04000000
-#define PCI_STS_SIG_TGTABORT 0x08000000
-#define PCI_STS_RCV_TGTABORT 0x10000000
-#define PCI_STS_RCV_MSTABORT 0x20000000
-#define PCI_STS_SYSERR 0x40000000
-#define PCI_STS_DETCT_PERR 0x80000000
-
-#define IT_PCI_CLASS(x) (((x)>>24) & 0xFF)
-#define IT_PCI_SUBCLASS(x) (((x)>>16) & 0xFF)
-#define IT_PCI_INTERFACE(x) (((x)>>8) & 0xFF)
-#define IT_PCI_REVISION(x) ((x) & 0xFF)
-
-// PCI class code
-#define PCI_CLASS_BRIDGE 0x06
-
-// bridge subclass
-#define PCI_SUBCLASS_BRIDGE_HOST 0x00
-#define PCI_SUBCLASS_BRIDGE_PCI 0x04
-
-// BHLCREG
-#define IT_PCI_BIST(x) (((x)>>24) & 0xFF)
-#define IT_PCI_HEADERTYPE(x) (((x)>>16) & 0xFF)
-#define IT_PCI_LATENCYTIMER(x) (((x)>>8) & 0xFF)
-#define IT_PCI_CACHELINESIZE(x) ((x) & 0xFF)
-
-#define PCI_MULTIFUNC 0x80
-
-// INTRREG
-#define IT_PCI_MAXLAT(x) (((x)>>24) & 0xFF)
-#define IT_PCI_MINGNT(x) (((x)>>16) & 0xFF)
-#define IT_PCI_INTRPIN(x) (((x)>>8) & 0xFF)
-#define IT_PCI_INTRLINE(x) ((x) & 0xFF)
-
-#define PCI_VENDOR_NEC 0x1033
-#define PCI_VENDOR_DEC 0x1101
-
-#endif // _8172PCI_H_
diff --git a/include/asm-mips/it8712.h b/include/asm-mips/it8712.h
deleted file mode 100644
index ca2dee02a011..000000000000
--- a/include/asm-mips/it8712.h
+++ /dev/null
@@ -1,28 +0,0 @@
-
-#ifndef __IT8712_H__
-#define __IT8712_H__
-
-#define LPC_BASE_ADDR 0x14000000
-
-// MB PnP configuration register
-#define LPC_KEY_ADDR 0x1400002E
-#define LPC_DATA_ADDR 0x1400002F
-
-// Device LDN
-#define LDN_SERIAL1 0x01
-#define LDN_SERIAL2 0x02
-#define LDN_PARALLEL 0x03
-#define LDN_KEYBOARD 0x05
-#define LDN_MOUSE 0x06
-
-#define IT8712_UART1_PORT 0x3F8
-#define IT8712_UART2_PORT 0x2F8
-
-#ifndef ASM_ONLY
-
-void LPCSetConfig(char LdnNumber, char Index, char data);
-char LPCGetConfig(char LdnNumber, char Index);
-
-#endif
-
-#endif
diff --git a/include/asm-mips/jmr3927/irq.h b/include/asm-mips/jmr3927/irq.h
index fe551f33a74f..e3e7ed38da6c 100644
--- a/include/asm-mips/jmr3927/irq.h
+++ b/include/asm-mips/jmr3927/irq.h
@@ -45,10 +45,6 @@ extern int
toshibaboards_setup_irq(int irq, struct irqaction * new);
-#ifdef CONFIG_TX_BRANCH_LIKELY_BUG_WORKAROUND
-extern void tx_branch_likely_bug_fixup(struct pt_regs *regs);
-#endif
-
extern int (*toshibaboards_gen_iack)(void);
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-mips/mach-atlas/mc146818rtc.h b/include/asm-mips/mach-atlas/mc146818rtc.h
index 397522ea5565..a73a5698420c 100644
--- a/include/asm-mips/mach-atlas/mc146818rtc.h
+++ b/include/asm-mips/mach-atlas/mc146818rtc.h
@@ -28,10 +28,12 @@
#include <asm/mips-boards/atlas.h>
#include <asm/mips-boards/atlasint.h>
+#define ARCH_RTC_LOCATION
+
#define RTC_PORT(x) (ATLAS_RTC_ADR_REG + (x) * 8)
#define RTC_IO_EXTENT 0x100
#define RTC_IOMAPPED 0
-#define RTC_IRQ ATLASINT_RTC
+#define RTC_IRQ ATLAS_INT_RTC
static inline unsigned char CMOS_READ(unsigned long addr)
{
diff --git a/include/asm-mips/mach-au1x00/au1000_dma.h b/include/asm-mips/mach-au1x00/au1000_dma.h
index 810f2fa33444..9f29520e8fb0 100644
--- a/include/asm-mips/mach-au1x00/au1000_dma.h
+++ b/include/asm-mips/mach-au1x00/au1000_dma.h
@@ -123,8 +123,7 @@ struct dma_chan {
extern struct dma_chan au1000_dma_table[];
extern int request_au1000_dma(int dev_id,
const char *dev_str,
- irqreturn_t (*irqhandler)(int, void *,
- struct pt_regs *),
+ irq_handler_t irqhandler,
unsigned long irqflags,
void *irq_dev_id);
extern void free_au1000_dma(unsigned int dmanr);
diff --git a/include/asm-mips/mach-au1x00/au1000_usbdev.h b/include/asm-mips/mach-au1x00/au1000_usbdev.h
deleted file mode 100644
index 05bc74bed0b1..000000000000
--- a/include/asm-mips/mach-au1x00/au1000_usbdev.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * BRIEF MODULE DESCRIPTION
- * Au1000 USB Device-Side Driver
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#define USBDEV_REV 0x0110 // BCD
-#define USBDEV_EP0_MAX_PACKET_SIZE 64
-
-typedef enum {
- ATTACHED = 0,
- POWERED,
- DEFAULT,
- ADDRESS,
- CONFIGURED
-} usbdev_state_t;
-
-typedef enum {
- CB_NEW_STATE = 0,
- CB_PKT_COMPLETE
-} usbdev_cb_type_t;
-
-
-typedef struct usbdev_pkt {
- int ep_addr; // ep addr this packet routed to
- int size; // size of payload in bytes
- unsigned status; // packet status
- struct usbdev_pkt* next; // function layer can't touch this
- u8 payload[0]; // the payload
-} usbdev_pkt_t;
-
-#define PKT_STATUS_ACK (1<<0)
-#define PKT_STATUS_NAK (1<<1)
-#define PKT_STATUS_SU (1<<2)
-
-extern int usbdev_init(struct usb_device_descriptor* dev_desc,
- struct usb_config_descriptor* config_desc,
- struct usb_interface_descriptor* if_desc,
- struct usb_endpoint_descriptor* ep_desc,
- struct usb_string_descriptor* str_desc[],
- void (*cb)(usbdev_cb_type_t, unsigned long, void *),
- void* cb_data);
-
-extern void usbdev_exit(void);
-
-extern int usbdev_alloc_packet (int ep_addr, int data_size,
- usbdev_pkt_t** pkt);
-extern int usbdev_send_packet (int ep_addr, usbdev_pkt_t* pkt);
-extern int usbdev_receive_packet(int ep_addr, usbdev_pkt_t** pkt);
-extern int usbdev_get_byte_count(int ep_addr);
diff --git a/include/asm-mips/mach-ev64120/mach-gt64120.h b/include/asm-mips/mach-ev64120/mach-gt64120.h
index 13b1443a7a65..7e272ce57ea3 100644
--- a/include/asm-mips/mach-ev64120/mach-gt64120.h
+++ b/include/asm-mips/mach-ev64120/mach-gt64120.h
@@ -42,6 +42,7 @@ extern unsigned long gt64120_base;
#define EV64120_UART0_REGS_BASE (KSEG1ADDR(EV64120_COM1_BASE_ADDR))
#define EV64120_UART1_REGS_BASE (KSEG1ADDR(EV64120_COM2_BASE_ADDR))
#define EV64120_BASE_BAUD ( 3686400 / 16 )
+#define EV64120_UART_IRQ 6
/*
* PCI interrupts will come in on either the INTA or INTD interrups lines,
diff --git a/include/asm-mips/mach-ev96100/mach-gt64120.h b/include/asm-mips/mach-ev96100/mach-gt64120.h
deleted file mode 100644
index 0ef1e6c25acf..000000000000
--- a/include/asm-mips/mach-ev96100/mach-gt64120.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * This is a direct copy of the ev96100.h file, with a global
- * search and replace. The numbers are the same.
- *
- * The reason I'm duplicating this is so that the 64120/96100
- * defines won't be confusing in the source code.
- */
-#ifndef _ASM_GT64120_EV96100_GT64120_DEP_H
-#define _ASM_GT64120_EV96100_GT64120_DEP_H
-
-/*
- * GT96100 config space base address
- */
-#define GT64120_BASE (KSEG1ADDR(0x14000000))
-
-/*
- * PCI Bus allocation
- *
- * (Guessing ...)
- */
-#define GT_PCI_MEM_BASE 0x12000000UL
-#define GT_PCI_MEM_SIZE 0x02000000UL
-#define GT_PCI_IO_BASE 0x10000000UL
-#define GT_PCI_IO_SIZE 0x02000000UL
-#define GT_ISA_IO_BASE PCI_IO_BASE
-
-/*
- * Duart I/O ports.
- */
-#define EV96100_COM1_BASE_ADDR (0xBD000000 + 0x20)
-#define EV96100_COM2_BASE_ADDR (0xBD000000 + 0x00)
-
-
-/*
- * EV96100 interrupt controller register base.
- */
-#define EV96100_ICTRL_REGS_BASE (KSEG1ADDR(0x1f000000))
-
-/*
- * EV96100 UART register base.
- */
-#define EV96100_UART0_REGS_BASE EV96100_COM1_BASE_ADDR
-#define EV96100_UART1_REGS_BASE EV96100_COM2_BASE_ADDR
-#define EV96100_BASE_BAUD ( 3686400 / 16 )
-
-#endif /* _ASM_GT64120_EV96100_GT64120_DEP_H */
diff --git a/include/asm-mips/mach-excite/excite.h b/include/asm-mips/mach-excite/excite.h
index 130bd4b8edce..4c29ba44992c 100644
--- a/include/asm-mips/mach-excite/excite.h
+++ b/include/asm-mips/mach-excite/excite.h
@@ -7,7 +7,7 @@
#define EXCITE_CPU_EXT_CLOCK 100000000
-#if !defined(__ASSEMBLER__)
+#if !defined(__ASSEMBLY__)
void __init excite_kgdb_init(void);
void excite_procfs_init(void);
extern unsigned long memsize;
diff --git a/arch/mips/basler/excite/excite_fpga.h b/include/asm-mips/mach-excite/excite_fpga.h
index 38fcda703a0b..38fcda703a0b 100644
--- a/arch/mips/basler/excite/excite_fpga.h
+++ b/include/asm-mips/mach-excite/excite_fpga.h
diff --git a/include/asm-mips/mach-ip27/topology.h b/include/asm-mips/mach-ip27/topology.h
index 59d26b52ba32..a13b715fd9ca 100644
--- a/include/asm-mips/mach-ip27/topology.h
+++ b/include/asm-mips/mach-ip27/topology.h
@@ -22,6 +22,7 @@ extern unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
#define SD_NODE_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 8, \
.max_interval = 32, \
diff --git a/include/asm-mips/mach-pnx8550/uart.h b/include/asm-mips/mach-pnx8550/uart.h
index e32b9a23d70e..814a7a15ab49 100644
--- a/include/asm-mips/mach-pnx8550/uart.h
+++ b/include/asm-mips/mach-pnx8550/uart.h
@@ -13,4 +13,18 @@
#define PNX8550_UART_INT(x) (PNX8550_INT_GIC_MIN+19+x)
#define IRQ_TO_UART(x) (x-PNX8550_INT_GIC_MIN-19)
+/* early macros needed for prom/kgdb */
+
+#define ip3106_lcr(base,port) *(volatile u32 *)(base+(port*0x1000) + 0x000)
+#define ip3106_mcr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x004)
+#define ip3106_baud(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x008)
+#define ip3106_cfg(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x00C)
+#define ip3106_fifo(base, port) *(volatile u32 *)(base+(port*0x1000) + 0x028)
+#define ip3106_istat(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE0)
+#define ip3106_ien(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE4)
+#define ip3106_iclr(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFE8)
+#define ip3106_iset(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFEC)
+#define ip3106_pd(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFF4)
+#define ip3106_mid(base, port) *(volatile u32 *)(base+(port*0x1000) + 0xFFC)
+
#endif
diff --git a/include/asm-mips/mach-qemu/cpu-feature-overrides.h b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
index f4e370e27168..529445dacedb 100644
--- a/include/asm-mips/mach-qemu/cpu-feature-overrides.h
+++ b/include/asm-mips/mach-qemu/cpu-feature-overrides.h
@@ -20,7 +20,7 @@
#define cpu_has_llsc 1
#define cpu_has_vtag_icache 0
-#define cpu_has_dc_aliases (PAGE_SIZE < 0x4000)
+#define cpu_has_dc_aliases 0
#define cpu_has_ic_fills_f_dc 0
#define cpu_has_dsp 0
diff --git a/include/asm-mips/marvell.h b/include/asm-mips/marvell.h
index 6bb2125bb053..df94955b098a 100644
--- a/include/asm-mips/marvell.h
+++ b/include/asm-mips/marvell.h
@@ -53,6 +53,6 @@ struct mv_pci_controller {
unsigned long config_vreg;
};
-extern void ll_mv64340_irq(struct pt_regs *regs);
+extern void ll_mv64340_irq(void);
#endif /* __ASM_MIPS_MARVELL_H */
diff --git a/include/asm-mips/mips-boards/atlasint.h b/include/asm-mips/mips-boards/atlasint.h
index fd7ebc54fa90..b15e4ea0b091 100644
--- a/include/asm-mips/mips-boards/atlasint.h
+++ b/include/asm-mips/mips-boards/atlasint.h
@@ -1,6 +1,7 @@
/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999 MIPS Technologies, Inc. All rights reserved.
+ * Copyright (C) 1999, 2006 MIPS Technologies, Inc. All rights reserved.
+ * Authors: Carsten Langgaard <carstenl@mips.com>
+ * Maciej W. Rozycki <macro@mips.com>
*
* ########################################################################
*
@@ -25,41 +26,88 @@
#ifndef _MIPS_ATLASINT_H
#define _MIPS_ATLASINT_H
-#define ATLASINT_BASE 1
-#define ATLASINT_UART (ATLASINT_BASE+0)
-#define ATLASINT_TIM0 (ATLASINT_BASE+1)
-#define ATLASINT_RES2 (ATLASINT_BASE+2)
-#define ATLASINT_RES3 (ATLASINT_BASE+3)
-#define ATLASINT_RTC (ATLASINT_BASE+4)
-#define ATLASINT_COREHI (ATLASINT_BASE+5)
-#define ATLASINT_CORELO (ATLASINT_BASE+6)
-#define ATLASINT_RES7 (ATLASINT_BASE+7)
-#define ATLASINT_PCIA (ATLASINT_BASE+8)
-#define ATLASINT_PCIB (ATLASINT_BASE+9)
-#define ATLASINT_PCIC (ATLASINT_BASE+10)
-#define ATLASINT_PCID (ATLASINT_BASE+11)
-#define ATLASINT_ENUM (ATLASINT_BASE+12)
-#define ATLASINT_DEG (ATLASINT_BASE+13)
-#define ATLASINT_ATXFAIL (ATLASINT_BASE+14)
-#define ATLASINT_INTA (ATLASINT_BASE+15)
-#define ATLASINT_INTB (ATLASINT_BASE+16)
-#define ATLASINT_ETH ATLASINT_INTB
-#define ATLASINT_INTC (ATLASINT_BASE+17)
-#define ATLASINT_SCSI ATLASINT_INTC
-#define ATLASINT_INTD (ATLASINT_BASE+18)
-#define ATLASINT_SERR (ATLASINT_BASE+19)
-#define ATLASINT_RES20 (ATLASINT_BASE+20)
-#define ATLASINT_RES21 (ATLASINT_BASE+21)
-#define ATLASINT_RES22 (ATLASINT_BASE+22)
-#define ATLASINT_RES23 (ATLASINT_BASE+23)
-#define ATLASINT_RES24 (ATLASINT_BASE+24)
-#define ATLASINT_RES25 (ATLASINT_BASE+25)
-#define ATLASINT_RES26 (ATLASINT_BASE+26)
-#define ATLASINT_RES27 (ATLASINT_BASE+27)
-#define ATLASINT_RES28 (ATLASINT_BASE+28)
-#define ATLASINT_RES29 (ATLASINT_BASE+29)
-#define ATLASINT_RES30 (ATLASINT_BASE+30)
-#define ATLASINT_RES31 (ATLASINT_BASE+31)
-#define ATLASINT_END (ATLASINT_BASE+31)
+/*
+ * Interrupts 0..7 are used for Atlas CPU interrupts (nonEIC mode)
+ */
+#define MIPSCPU_INT_BASE 0
+
+/* CPU interrupt offsets */
+#define MIPSCPU_INT_SW0 0
+#define MIPSCPU_INT_SW1 1
+#define MIPSCPU_INT_MB0 2
+#define MIPSCPU_INT_ATLAS MIPSCPU_INT_MB0
+#define MIPSCPU_INT_MB1 3
+#define MIPSCPU_INT_MB2 4
+#define MIPSCPU_INT_MB3 5
+#define MIPSCPU_INT_MB4 6
+#define MIPSCPU_INT_CPUCTR 7
+
+/*
+ * Interrupts 8..39 are used for Atlas interrupt controller interrupts
+ */
+#define ATLAS_INT_BASE 8
+#define ATLAS_INT_UART (ATLAS_INT_BASE + 0)
+#define ATLAS_INT_TIM0 (ATLAS_INT_BASE + 1)
+#define ATLAS_INT_RES2 (ATLAS_INT_BASE + 2)
+#define ATLAS_INT_RES3 (ATLAS_INT_BASE + 3)
+#define ATLAS_INT_RTC (ATLAS_INT_BASE + 4)
+#define ATLAS_INT_COREHI (ATLAS_INT_BASE + 5)
+#define ATLAS_INT_CORELO (ATLAS_INT_BASE + 6)
+#define ATLAS_INT_RES7 (ATLAS_INT_BASE + 7)
+#define ATLAS_INT_PCIA (ATLAS_INT_BASE + 8)
+#define ATLAS_INT_PCIB (ATLAS_INT_BASE + 9)
+#define ATLAS_INT_PCIC (ATLAS_INT_BASE + 10)
+#define ATLAS_INT_PCID (ATLAS_INT_BASE + 11)
+#define ATLAS_INT_ENUM (ATLAS_INT_BASE + 12)
+#define ATLAS_INT_DEG (ATLAS_INT_BASE + 13)
+#define ATLAS_INT_ATXFAIL (ATLAS_INT_BASE + 14)
+#define ATLAS_INT_INTA (ATLAS_INT_BASE + 15)
+#define ATLAS_INT_INTB (ATLAS_INT_BASE + 16)
+#define ATLAS_INT_ETH ATLAS_INT_INTB
+#define ATLAS_INT_INTC (ATLAS_INT_BASE + 17)
+#define ATLAS_INT_SCSI ATLAS_INT_INTC
+#define ATLAS_INT_INTD (ATLAS_INT_BASE + 18)
+#define ATLAS_INT_SERR (ATLAS_INT_BASE + 19)
+#define ATLAS_INT_RES20 (ATLAS_INT_BASE + 20)
+#define ATLAS_INT_RES21 (ATLAS_INT_BASE + 21)
+#define ATLAS_INT_RES22 (ATLAS_INT_BASE + 22)
+#define ATLAS_INT_RES23 (ATLAS_INT_BASE + 23)
+#define ATLAS_INT_RES24 (ATLAS_INT_BASE + 24)
+#define ATLAS_INT_RES25 (ATLAS_INT_BASE + 25)
+#define ATLAS_INT_RES26 (ATLAS_INT_BASE + 26)
+#define ATLAS_INT_RES27 (ATLAS_INT_BASE + 27)
+#define ATLAS_INT_RES28 (ATLAS_INT_BASE + 28)
+#define ATLAS_INT_RES29 (ATLAS_INT_BASE + 29)
+#define ATLAS_INT_RES30 (ATLAS_INT_BASE + 30)
+#define ATLAS_INT_RES31 (ATLAS_INT_BASE + 31)
+#define ATLAS_INT_END (ATLAS_INT_BASE + 31)
+
+/*
+ * Interrupts 64..127 are used for Soc-it Classic interrupts
+ */
+#define MSC01C_INT_BASE 64
+
+/* SOC-it Classic interrupt offsets */
+#define MSC01C_INT_TMR 0
+#define MSC01C_INT_PCI 1
+
+/*
+ * Interrupts 64..127 are used for Soc-it EIC interrupts
+ */
+#define MSC01E_INT_BASE 64
+
+/* SOC-it EIC interrupt offsets */
+#define MSC01E_INT_SW0 1
+#define MSC01E_INT_SW1 2
+#define MSC01E_INT_MB0 3
+#define MSC01E_INT_ATLAS MSC01E_INT_MB0
+#define MSC01E_INT_MB1 4
+#define MSC01E_INT_MB2 5
+#define MSC01E_INT_MB3 6
+#define MSC01E_INT_MB4 7
+#define MSC01E_INT_TMR 8
+#define MSC01E_INT_PCI 9
+#define MSC01E_INT_PERFCTR 10
+#define MSC01E_INT_CPUCTR 11
#endif /* !(_MIPS_ATLASINT_H) */
diff --git a/include/asm-mips/mmu_context.h b/include/asm-mips/mmu_context.h
index 18b69de87daa..fe065d6070ca 100644
--- a/include/asm-mips/mmu_context.h
+++ b/include/asm-mips/mmu_context.h
@@ -262,10 +262,10 @@ drop_mmu_context(struct mm_struct *mm, unsigned cpu)
/* See comments for similar code above */
prevvpe = dvpe();
oldasid = (read_c0_entryhi() & ASID_MASK);
- if(smtc_live_asid[mytlb][oldasid]) {
- smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
- if(smtc_live_asid[mytlb][oldasid] == 0)
- smtc_flush_tlb_asid(oldasid);
+ if (smtc_live_asid[mytlb][oldasid]) {
+ smtc_live_asid[mytlb][oldasid] &= ~(0x1 << cpu);
+ if(smtc_live_asid[mytlb][oldasid] == 0)
+ smtc_flush_tlb_asid(oldasid);
}
/* See comments for similar code above */
write_c0_entryhi((read_c0_entryhi() & ~HW_ASID_MASK)
diff --git a/include/asm-mips/msc01_ic.h b/include/asm-mips/msc01_ic.h
index 64f17208d602..aa7ad9a71762 100644
--- a/include/asm-mips/msc01_ic.h
+++ b/include/asm-mips/msc01_ic.h
@@ -145,7 +145,7 @@ typedef struct msc_irqmap {
#define MSC01_IRQ_EDGE 1
extern void __init init_msc_irqs(unsigned int base, msc_irqmap_t *imp, int nirq);
-extern void ll_msc_irq(struct pt_regs *regs);
+extern void ll_msc_irq(void);
#endif /* __ASM_MIPS_BOARDS_MSC01_IC_H */
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index 219d359861f3..85b258ee7090 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -34,6 +34,8 @@
#ifndef __ASSEMBLY__
+#include <asm/cpu-features.h>
+
extern void clear_page(void * page);
extern void copy_page(void * to, void * from);
@@ -53,7 +55,7 @@ static inline void clear_user_page(void *addr, unsigned long vaddr,
extern void (*flush_data_cache_page)(unsigned long addr);
clear_page(addr);
- if (pages_do_alias((unsigned long) addr, vaddr))
+ if (pages_do_alias((unsigned long) addr, vaddr & PAGE_MASK))
flush_data_cache_page((unsigned long)addr);
}
@@ -63,7 +65,8 @@ static inline void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
extern void (*flush_data_cache_page)(unsigned long addr);
copy_page(vto, vfrom);
- if (pages_do_alias((unsigned long)vto, vaddr))
+ if (!cpu_has_ic_fills_f_dc ||
+ pages_do_alias((unsigned long)vto, vaddr & PAGE_MASK))
flush_data_cache_page((unsigned long)vto);
}
@@ -74,15 +77,17 @@ static inline void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
#ifdef CONFIG_CPU_MIPS32
typedef struct { unsigned long pte_low, pte_high; } pte_t;
#define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32))
+ #define __pte(x) ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; })
#else
typedef struct { unsigned long long pte; } pte_t;
#define pte_val(x) ((x).pte)
+ #define __pte(x) ((pte_t) { (x) } )
#endif
#else
typedef struct { unsigned long pte; } pte_t;
#define pte_val(x) ((x).pte)
-#endif
#define __pte(x) ((pte_t) { (x) } )
+#endif
/*
* For 3-level pagetables we defines these ourselves, for 2-level the
diff --git a/include/asm-mips/pgtable-64.h b/include/asm-mips/pgtable-64.h
index c59a1e21f5b0..d05fb6f38aa7 100644
--- a/include/asm-mips/pgtable-64.h
+++ b/include/asm-mips/pgtable-64.h
@@ -93,8 +93,12 @@
#define PTRS_PER_PMD ((PAGE_SIZE << PMD_ORDER) / sizeof(pmd_t))
#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
+#if PGDIR_SIZE >= TASK_SIZE
+#define USER_PTRS_PER_PGD (1)
+#else
#define USER_PTRS_PER_PGD (TASK_SIZE / PGDIR_SIZE)
-#define FIRST_USER_ADDRESS 0
+#endif
+#define FIRST_USER_ADDRESS 0UL
#define VMALLOC_START MAP_BASE
#define VMALLOC_END \
diff --git a/include/asm-mips/ptrace.h b/include/asm-mips/ptrace.h
index 4113316ee0da..5f3a9075cd28 100644
--- a/include/asm-mips/ptrace.h
+++ b/include/asm-mips/ptrace.h
@@ -10,8 +10,6 @@
#define _ASM_PTRACE_H
-#include <asm/isadep.h>
-
/* 0 - 31 are integer registers, 32 - 63 are fp registers. */
#define FPR_BASE 32
#define PC 64
@@ -46,9 +44,8 @@ struct pt_regs {
unsigned long cp0_epc;
#ifdef CONFIG_MIPS_MT_SMTC
unsigned long cp0_tcstatus;
- unsigned long smtc_pad;
#endif /* CONFIG_MIPS_MT_SMTC */
-};
+} __attribute__ ((aligned (8)));
/* Arbitrarily choose the same ptrace numbers as used by the Sparc code. */
#define PTRACE_GETREGS 12
@@ -73,6 +70,7 @@ struct pt_regs {
#ifdef __KERNEL__
#include <linux/linkage.h>
+#include <asm/isadep.h>
/*
* Does the process account for user or for system time?
diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h
index 584bd9c0ab2e..d7a65135d837 100644
--- a/include/asm-mips/serial.h
+++ b/include/asm-mips/serial.h
@@ -52,54 +52,21 @@
#endif
/*
- * Both Galileo boards have the same UART mappings.
+ * Galileo EV64120 evaluation board
*/
-#if defined (CONFIG_MIPS_EV96100) || defined (CONFIG_MIPS_EV64120)
-#include <asm/galileo-boards/ev96100.h>
-#include <asm/galileo-boards/ev96100int.h>
-#define EV96100_SERIAL_PORT_DEFNS \
- { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \
+#ifdef CONFIG_MIPS_EV64120
+#include <mach-gt64120.h>
+#define EV64120_SERIAL_PORT_DEFNS \
+ { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \
.flags = STD_COM_FLAGS, \
- .iomem_base = EV96100_UART0_REGS_BASE, .iomem_reg_shift = 2, \
+ .iomem_base = EV64120_UART0_REGS_BASE, .iomem_reg_shift = 2, \
.io_type = SERIAL_IO_MEM }, \
- { .baud_base = EV96100_BASE_BAUD, .irq = EV96100INT_UART_0, \
+ { .baud_base = EV64120_BASE_BAUD, .irq = EV64120_UART_IRQ, \
.flags = STD_COM_FLAGS, \
- .iomem_base = EV96100_UART1_REGS_BASE, .iomem_reg_shift = 2, \
+ .iomem_base = EV64120_UART1_REGS_BASE, .iomem_reg_shift = 2, \
.io_type = SERIAL_IO_MEM },
#else
-#define EV96100_SERIAL_PORT_DEFNS
-#endif
-
-#ifdef CONFIG_MIPS_ITE8172
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_int.h>
-#include <asm/it8712.h>
-#define ITE_SERIAL_PORT_DEFNS \
- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \
- .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
- { .baud_base = (24000000/(16*13)), .port = (IT8172_PCI_IO_BASE + IT8712_UART1_PORT), \
- .irq = IT8172_SERIRQ_4, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
- /* Smart Card Reader 0 */ \
- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR0_BASE), \
- .irq = IT8172_SCR0_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
- /* Smart Card Reader 1 */ \
- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \
- .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 },
-#else
-#define ITE_SERIAL_PORT_DEFNS
-#endif
-
-#ifdef CONFIG_MIPS_IVR
-#include <asm/it8172/it8172.h>
-#include <asm/it8172/it8172_int.h>
-#define IVR_SERIAL_PORT_DEFNS \
- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_UART_BASE), \
- .irq = IT8172_UART_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 }, \
- /* Smart Card Reader 1 */ \
- { .baud_base = BASE_BAUD, .port = (IT8172_PCI_IO_BASE + IT_SCR1_BASE), \
- .irq = IT8172_SCR1_IRQ, .flags = STD_COM_FLAGS, .port = PORT_16550 },
-#else
-#define IVR_SERIAL_PORT_DEFNS
+#define EV64120_SERIAL_PORT_DEFNS
#endif
#ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT
@@ -239,10 +206,8 @@
#define SERIAL_PORT_DFNS \
DDB5477_SERIAL_PORT_DEFNS \
- EV96100_SERIAL_PORT_DEFNS \
+ EV64120_SERIAL_PORT_DEFNS \
IP32_SERIAL_PORT_DEFNS \
- ITE_SERIAL_PORT_DEFNS \
- IVR_SERIAL_PORT_DEFNS \
JAZZ_SERIAL_PORT_DEFNS \
STD_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \
diff --git a/include/asm-mips/sibyte/sb1250_defs.h b/include/asm-mips/sibyte/sb1250_defs.h
index 335dbaf1d831..a885491217c1 100644
--- a/include/asm-mips/sibyte/sb1250_defs.h
+++ b/include/asm-mips/sibyte/sb1250_defs.h
@@ -212,7 +212,7 @@
* Note: you'll need to define uint32_t and uint64_t in your headers.
*/
-#if !defined(__ASSEMBLER__)
+#if !defined(__ASSEMBLY__)
#define _SB_MAKE64(x) ((uint64_t)(x))
#define _SB_MAKE32(x) ((uint32_t)(x))
#else
@@ -251,9 +251,9 @@
*/
-#if defined(__mips64) && !defined(__ASSEMBLER__)
+#if defined(__mips64) && !defined(__ASSEMBLY__)
#define SBWRITECSR(csr,val) *((volatile uint64_t *) PHYS_TO_K1(csr)) = (val)
#define SBREADCSR(csr) (*((volatile uint64_t *) PHYS_TO_K1(csr)))
-#endif /* __ASSEMBLER__ */
+#endif /* __ASSEMBLY__ */
#endif
diff --git a/include/asm-mips/sibyte/sb1250_scd.h b/include/asm-mips/sibyte/sb1250_scd.h
index f4178bdcfcb0..7ed0bb611e56 100644
--- a/include/asm-mips/sibyte/sb1250_scd.h
+++ b/include/asm-mips/sibyte/sb1250_scd.h
@@ -149,7 +149,7 @@
* (For the assembler version, sysrev and dest may be the same register.
* Also, it clobbers AT.)
*/
-#ifdef __ASSEMBLER__
+#ifdef __ASSEMBLY__
#define SYS_SOC_TYPE(dest, sysrev) \
.set push ; \
.set reorder ; \
diff --git a/include/asm-mips/signal.h b/include/asm-mips/signal.h
index 87a1dff95199..8b391a2f0814 100644
--- a/include/asm-mips/signal.h
+++ b/include/asm-mips/signal.h
@@ -108,17 +108,8 @@ typedef unsigned long old_sigset_t; /* at least 32 bits */
#define SIG_BLOCK 1 /* for blocking signals */
#define SIG_UNBLOCK 2 /* for unblocking signals */
#define SIG_SETMASK 3 /* for setting the signal mask */
-#define SIG_SETMASK32 256 /* Goodie from SGI for BSD compatibility:
- set only the low 32 bit of the sigset. */
-/* Type of a signal handler. */
-typedef void __signalfn_t(int);
-typedef __signalfn_t __user *__sighandler_t;
-
-/* Fake signal functions */
-#define SIG_DFL ((__sighandler_t)0) /* default signal handling */
-#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
-#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
+#include <asm-generic/signal.h>
struct sigaction {
unsigned int sa_flags;
diff --git a/include/asm-mips/spinlock.h b/include/asm-mips/spinlock.h
index 669b8e349ff2..c8d5587467bb 100644
--- a/include/asm-mips/spinlock.h
+++ b/include/asm-mips/spinlock.h
@@ -239,7 +239,51 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
: "memory");
}
-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
+static inline int __raw_read_trylock(raw_rwlock_t *rw)
+{
+ unsigned int tmp;
+ int ret;
+
+ if (R10000_LLSC_WAR) {
+ __asm__ __volatile__(
+ " .set noreorder # __raw_read_trylock \n"
+ " li %2, 0 \n"
+ "1: ll %1, %3 \n"
+ " bnez %1, 2f \n"
+ " addu %1, 1 \n"
+ " sc %1, %0 \n"
+ " beqzl %1, 1b \n"
+ " .set reorder \n"
+#ifdef CONFIG_SMP
+ " sync \n"
+#endif
+ " li %2, 1 \n"
+ "2: \n"
+ : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+ : "m" (rw->lock)
+ : "memory");
+ } else {
+ __asm__ __volatile__(
+ " .set noreorder # __raw_read_trylock \n"
+ " li %2, 0 \n"
+ "1: ll %1, %3 \n"
+ " bnez %1, 2f \n"
+ " addu %1, 1 \n"
+ " sc %1, %0 \n"
+ " beqz %1, 1b \n"
+ " .set reorder \n"
+#ifdef CONFIG_SMP
+ " sync \n"
+#endif
+ " li %2, 1 \n"
+ "2: \n"
+ : "=m" (rw->lock), "=&r" (tmp), "=&r" (ret)
+ : "m" (rw->lock)
+ : "memory");
+ }
+
+ return ret;
+}
static inline int __raw_write_trylock(raw_rwlock_t *rw)
{
@@ -283,4 +327,9 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
return ret;
}
+
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* _ASM_SPINLOCK_H */
diff --git a/include/asm-mips/stackframe.h b/include/asm-mips/stackframe.h
index 158a4cd12e46..1fae5dc58138 100644
--- a/include/asm-mips/stackframe.h
+++ b/include/asm-mips/stackframe.h
@@ -59,69 +59,43 @@
.endm
#ifdef CONFIG_SMP
- .macro get_saved_sp /* SMP variation */
-#ifdef CONFIG_32BIT
#ifdef CONFIG_MIPS_MT_SMTC
- .set mips32
- mfc0 k0, CP0_TCBIND;
- .set mips0
- lui k1, %hi(kernelsp)
- srl k0, k0, 19
- /* No need to shift down and up to clear bits 0-1 */
+#define PTEBASE_SHIFT 19 /* TCBIND */
#else
- mfc0 k0, CP0_CONTEXT
- lui k1, %hi(kernelsp)
- srl k0, k0, 23
-#endif
- addu k1, k0
- LONG_L k1, %lo(kernelsp)(k1)
+#define PTEBASE_SHIFT 23 /* CONTEXT */
#endif
-#ifdef CONFIG_64BIT
+ .macro get_saved_sp /* SMP variation */
#ifdef CONFIG_MIPS_MT_SMTC
- .set mips64
- mfc0 k0, CP0_TCBIND;
- .set mips0
- lui k0, %highest(kernelsp)
- dsrl k1, 19
- /* No need to shift down and up to clear bits 0-2 */
+ mfc0 k0, CP0_TCBIND
#else
- MFC0 k1, CP0_CONTEXT
- lui k0, %highest(kernelsp)
- dsrl k1, 23
- daddiu k0, %higher(kernelsp)
- dsll k0, k0, 16
- daddiu k0, %hi(kernelsp)
- dsll k0, k0, 16
-#endif /* CONFIG_MIPS_MT_SMTC */
- daddu k1, k1, k0
+ MFC0 k0, CP0_CONTEXT
+#endif
+#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4)
+ lui k1, %highest(kernelsp)
+ daddiu k1, %higher(kernelsp)
+ dsll k1, 16
+ daddiu k1, %hi(kernelsp)
+ dsll k1, 16
+#else
+ lui k1, %hi(kernelsp)
+#endif
+ LONG_SRL k0, PTEBASE_SHIFT
+ LONG_ADDU k1, k0
LONG_L k1, %lo(kernelsp)(k1)
-#endif /* CONFIG_64BIT */
.endm
.macro set_saved_sp stackp temp temp2
-#ifdef CONFIG_32BIT
-#ifdef CONFIG_MIPS_MT_SMTC
- mfc0 \temp, CP0_TCBIND
- srl \temp, 19
-#else
- mfc0 \temp, CP0_CONTEXT
- srl \temp, 23
-#endif
-#endif
-#ifdef CONFIG_64BIT
#ifdef CONFIG_MIPS_MT_SMTC
mfc0 \temp, CP0_TCBIND
- dsrl \temp, 19
#else
MFC0 \temp, CP0_CONTEXT
- dsrl \temp, 23
-#endif
#endif
+ LONG_SRL \temp, PTEBASE_SHIFT
LONG_S \stackp, kernelsp(\temp)
.endm
#else
.macro get_saved_sp /* Uniprocessor variation */
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_BUILD_ELF64) || (defined(CONFIG_64BIT) && __GNUC__ < 4)
lui k1, %highest(kernelsp)
daddiu k1, %higher(kernelsp)
dsll k1, k1, 16
diff --git a/include/asm-mips/stacktrace.h b/include/asm-mips/stacktrace.h
new file mode 100644
index 000000000000..07f873351a86
--- /dev/null
+++ b/include/asm-mips/stacktrace.h
@@ -0,0 +1,44 @@
+#ifndef _ASM_STACKTRACE_H
+#define _ASM_STACKTRACE_H
+
+#include <asm/ptrace.h>
+
+#ifdef CONFIG_KALLSYMS
+extern int raw_show_trace;
+extern unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
+ unsigned long pc, unsigned long *ra);
+#else
+#define raw_show_trace 1
+#define unwind_stack(task, sp, pc, ra) 0
+#endif
+
+static __always_inline void prepare_frametrace(struct pt_regs *regs)
+{
+#ifndef CONFIG_KALLSYMS
+ /*
+ * Remove any garbage that may be in regs (specially func
+ * addresses) to avoid show_raw_backtrace() to report them
+ */
+ memset(regs, 0, sizeof(*regs));
+#endif
+ __asm__ __volatile__(
+ ".set push\n\t"
+ ".set noat\n\t"
+#ifdef CONFIG_64BIT
+ "1: dla $1, 1b\n\t"
+ "sd $1, %0\n\t"
+ "sd $29, %1\n\t"
+ "sd $31, %2\n\t"
+#else
+ "1: la $1, 1b\n\t"
+ "sw $1, %0\n\t"
+ "sw $29, %1\n\t"
+ "sw $31, %2\n\t"
+#endif
+ ".set pop\n\t"
+ : "=m" (regs->cp0_epc),
+ "=m" (regs->regs[29]), "=m" (regs->regs[31])
+ : : "memory");
+}
+
+#endif /* _ASM_STACKTRACE_H */
diff --git a/include/asm-mips/termbits.h b/include/asm-mips/termbits.h
index fa6d04dac56b..b62ec7c521cc 100644
--- a/include/asm-mips/termbits.h
+++ b/include/asm-mips/termbits.h
@@ -3,7 +3,7 @@
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
- * Copyright (C) 1995, 1996, 1999, 2001 Ralf Baechle
+ * Copyright (C) 1995, 96, 99, 2001, 06 Ralf Baechle
* Copyright (C) 1999 Silicon Graphics, Inc.
* Copyright (C) 2001 MIPS Technologies, Inc.
*/
@@ -13,14 +13,8 @@
#include <linux/posix_types.h>
typedef unsigned char cc_t;
-#if (_MIPS_SZLONG == 32)
-typedef unsigned long speed_t;
-typedef unsigned long tcflag_t;
-#endif
-#if (_MIPS_SZLONG == 64)
-typedef __u32 speed_t;
-typedef __u32 tcflag_t;
-#endif
+typedef unsigned int speed_t;
+typedef unsigned int tcflag_t;
/*
* The ABI says nothing about NCC but seems to use NCCS as
diff --git a/include/asm-mips/thread_info.h b/include/asm-mips/thread_info.h
index ae8ada5b42a9..e475c45ea263 100644
--- a/include/asm-mips/thread_info.h
+++ b/include/asm-mips/thread_info.h
@@ -34,6 +34,7 @@ struct thread_info {
0-0xFFFFFFFF for kernel-thread
*/
struct restart_block restart_block;
+ struct pt_regs *regs;
};
/*
diff --git a/include/asm-mips/time.h b/include/asm-mips/time.h
index 2d543735668b..28512ba2266e 100644
--- a/include/asm-mips/time.h
+++ b/include/asm-mips/time.h
@@ -67,18 +67,18 @@ extern unsigned long (*do_gettimeoffset)(void);
/*
* high-level timer interrupt routines.
*/
-extern irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t timer_interrupt(int irq, void *dev_id);
/*
* the corresponding low-level timer interrupt routine.
*/
-extern asmlinkage void ll_timer_interrupt(int irq, struct pt_regs *regs);
+extern asmlinkage void ll_timer_interrupt(int irq);
/*
* profiling and process accouting is done separately in local_timer_interrupt
*/
-extern void local_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-extern asmlinkage void ll_local_timer_interrupt(int irq, struct pt_regs *regs);
+extern void local_timer_interrupt(int irq, void *dev_id);
+extern asmlinkage void ll_local_timer_interrupt(int irq);
/*
* board specific routines required by time_init().
diff --git a/include/asm-mips/timex.h b/include/asm-mips/timex.h
index 98aa737b34aa..b80de8e0fbbd 100644
--- a/include/asm-mips/timex.h
+++ b/include/asm-mips/timex.h
@@ -8,6 +8,8 @@
#ifndef _ASM_TIMEX_H
#define _ASM_TIMEX_H
+#ifdef __KERNEL__
+
#include <asm/mipsregs.h>
/*
@@ -51,4 +53,6 @@ static inline cycles_t get_cycles (void)
return read_c0_count();
}
+#endif /* __KERNEL__ */
+
#endif /* _ASM_TIMEX_H */
diff --git a/include/asm-mips/tx4938/tx4938_mips.h b/include/asm-mips/tx4938/tx4938_mips.h
index cf89b205f103..5f8498fef005 100644
--- a/include/asm-mips/tx4938/tx4938_mips.h
+++ b/include/asm-mips/tx4938/tx4938_mips.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-mips/tx4938/tx4938_bitmask.h
+ * linux/include/asm-mips/tx4938/tx4938_mips.h
* Generic bitmask definitions
*
* 2003-2005 (c) MontaVista Software, Inc. This file is licensed under the
diff --git a/include/asm-mips/unistd.h b/include/asm-mips/unistd.h
index 610ccb8a50b3..30240a445dbb 100644
--- a/include/asm-mips/unistd.h
+++ b/include/asm-mips/unistd.h
@@ -313,7 +313,7 @@
#define __NR_mknodat (__NR_Linux + 290)
#define __NR_fchownat (__NR_Linux + 291)
#define __NR_futimesat (__NR_Linux + 292)
-#define __NR_fstatat (__NR_Linux + 293)
+#define __NR_fstatat64 (__NR_Linux + 293)
#define __NR_unlinkat (__NR_Linux + 294)
#define __NR_renameat (__NR_Linux + 295)
#define __NR_linkat (__NR_Linux + 296)
@@ -329,16 +329,19 @@
#define __NR_tee (__NR_Linux + 306)
#define __NR_vmsplice (__NR_Linux + 307)
#define __NR_move_pages (__NR_Linux + 308)
+#define __NR_set_robust_list (__NR_Linux + 309)
+#define __NR_get_robust_list (__NR_Linux + 310)
+#define __NR_kexec_load (__NR_Linux + 311)
/*
* Offset of the last Linux o32 flavoured syscall
*/
-#define __NR_Linux_syscalls 308
+#define __NR_Linux_syscalls 311
#endif /* _MIPS_SIM == _MIPS_SIM_ABI32 */
#define __NR_O32_Linux 4000
-#define __NR_O32_Linux_syscalls 308
+#define __NR_O32_Linux_syscalls 311
#if _MIPS_SIM == _MIPS_SIM_ABI64
@@ -598,7 +601,7 @@
#define __NR_mknodat (__NR_Linux + 249)
#define __NR_fchownat (__NR_Linux + 250)
#define __NR_futimesat (__NR_Linux + 251)
-#define __NR_fstatat (__NR_Linux + 252)
+#define __NR_newfstatat (__NR_Linux + 252)
#define __NR_unlinkat (__NR_Linux + 253)
#define __NR_renameat (__NR_Linux + 254)
#define __NR_linkat (__NR_Linux + 255)
@@ -614,16 +617,19 @@
#define __NR_tee (__NR_Linux + 265)
#define __NR_vmsplice (__NR_Linux + 266)
#define __NR_move_pages (__NR_Linux + 267)
+#define __NR_set_robust_list (__NR_Linux + 268)
+#define __NR_get_robust_list (__NR_Linux + 269)
+#define __NR_kexec_load (__NR_Linux + 270)
/*
* Offset of the last Linux 64-bit flavoured syscall
*/
-#define __NR_Linux_syscalls 267
+#define __NR_Linux_syscalls 270
#endif /* _MIPS_SIM == _MIPS_SIM_ABI64 */
#define __NR_64_Linux 5000
-#define __NR_64_Linux_syscalls 267
+#define __NR_64_Linux_syscalls 270
#if _MIPS_SIM == _MIPS_SIM_NABI32
@@ -887,7 +893,7 @@
#define __NR_mknodat (__NR_Linux + 253)
#define __NR_fchownat (__NR_Linux + 254)
#define __NR_futimesat (__NR_Linux + 255)
-#define __NR_fstatat (__NR_Linux + 256)
+#define __NR_newfstatat (__NR_Linux + 256)
#define __NR_unlinkat (__NR_Linux + 257)
#define __NR_renameat (__NR_Linux + 258)
#define __NR_linkat (__NR_Linux + 259)
@@ -903,16 +909,19 @@
#define __NR_tee (__NR_Linux + 269)
#define __NR_vmsplice (__NR_Linux + 270)
#define __NR_move_pages (__NR_Linux + 271)
+#define __NR_set_robust_list (__NR_Linux + 272)
+#define __NR_get_robust_list (__NR_Linux + 273)
+#define __NR_kexec_load (__NR_Linux + 274)
/*
* Offset of the last N32 flavoured syscall
*/
-#define __NR_Linux_syscalls 271
+#define __NR_Linux_syscalls 274
#endif /* _MIPS_SIM == _MIPS_SIM_NABI32 */
#define __NR_N32_Linux 6000
-#define __NR_N32_Linux_syscalls 271
+#define __NR_N32_Linux_syscalls 274
#ifdef __KERNEL__
@@ -1206,45 +1215,6 @@ type name (atype a,btype b,ctype c,dtype d,etype e,ftype f) \
# define __ARCH_WANT_COMPAT_SYS_TIME
# endif
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-#include <asm/sim.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-
-asmlinkage unsigned long sys_mmap(
- unsigned long addr, size_t len,
- int prot, int flags,
- int fd, off_t offset);
-asmlinkage long sys_mmap2(
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(nabi_no_regargs struct pt_regs regs);
-asmlinkage int sys_pipe(nabi_no_regargs struct pt_regs regs);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
#endif /* !__ASSEMBLY__ */
/*
diff --git a/include/asm-mips/user.h b/include/asm-mips/user.h
index 89bf8b4cab3c..61f2a093b91b 100644
--- a/include/asm-mips/user.h
+++ b/include/asm-mips/user.h
@@ -8,6 +8,8 @@
#ifndef _ASM_USER_H
#define _ASM_USER_H
+#ifdef __KERNEL__
+
#include <asm/page.h>
#include <asm/reg.h>
@@ -55,4 +57,6 @@ struct user {
#define HOST_DATA_START_ADDR (u.start_data)
#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
+#endif /* __KERNEL__ */
+
#endif /* _ASM_USER_H */
diff --git a/include/asm-mips/vr41xx/vr41xx.h b/include/asm-mips/vr41xx/vr41xx.h
index dd3eb3dc5886..88b492f6ea9c 100644
--- a/include/asm-mips/vr41xx/vr41xx.h
+++ b/include/asm-mips/vr41xx/vr41xx.h
@@ -75,7 +75,7 @@ extern void vr41xx_mask_clock(vr41xx_clock_t clock);
* Interrupt Control Unit
*/
extern int vr41xx_set_intassign(unsigned int irq, unsigned char intassign);
-extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int, struct pt_regs *));
+extern int cascade_irq(unsigned int irq, int (*get_irq)(unsigned int));
#define PIUINT_COMMAND 0x0040
#define PIUINT_DATA 0x0020
diff --git a/include/asm-parisc/agp.h b/include/asm-parisc/agp.h
new file mode 100644
index 000000000000..9f61d4eb6c01
--- /dev/null
+++ b/include/asm-parisc/agp.h
@@ -0,0 +1,25 @@
+#ifndef _ASM_PARISC_AGP_H
+#define _ASM_PARISC_AGP_H
+
+/*
+ * PARISC specific AGP definitions.
+ * Copyright (c) 2006 Kyle McMartin <kyle@parisc-linux.org>
+ *
+ */
+
+#define map_page_into_agp(page) /* nothing */
+#define unmap_page_from_agp(page) /* nothing */
+#define flush_agp_mappings() /* nothing */
+#define flush_agp_cache() mb()
+
+/* Convert a physical address to an address suitable for the GART. */
+#define phys_to_gart(x) (x)
+#define gart_to_phys(x) (x)
+
+/* GATT allocation. Returns/accepts GATT kernel virtual address. */
+#define alloc_gatt_pages(order) \
+ ((char *)__get_free_pages(GFP_KERNEL, (order)))
+#define free_gatt_pages(table, order) \
+ free_pages((unsigned long)(table), (order))
+
+#endif /* _ASM_PARISC_AGP_H */
diff --git a/include/asm-parisc/assembly.h b/include/asm-parisc/assembly.h
index 1a7bfe699e0c..5a1e0e8b1c32 100644
--- a/include/asm-parisc/assembly.h
+++ b/include/asm-parisc/assembly.h
@@ -29,7 +29,8 @@
#define LDREGX ldd,s
#define LDREGM ldd,mb
#define STREGM std,ma
-#define SHRREG shrd
+#define SHRREG shrd
+#define SHLREG shld
#define RP_OFFSET 16
#define FRAME_SIZE 128
#define CALLEE_REG_FRAME_SIZE 144
@@ -39,7 +40,8 @@
#define LDREGX ldwx,s
#define LDREGM ldwm
#define STREGM stwm
-#define SHRREG shr
+#define SHRREG shr
+#define SHLREG shlw
#define RP_OFFSET 20
#define FRAME_SIZE 64
#define CALLEE_REG_FRAME_SIZE 128
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
index 0b459cdfbd6f..2bc41f2e0271 100644
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -191,16 +191,38 @@ flush_anon_page(struct page *page, unsigned long vmaddr)
}
#define ARCH_HAS_FLUSH_ANON_PAGE
-static inline void
-flush_kernel_dcache_page(struct page *page)
+#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
+void flush_kernel_dcache_page_addr(void *addr);
+static inline void flush_kernel_dcache_page(struct page *page)
{
- flush_kernel_dcache_page_asm(page_address(page));
+ flush_kernel_dcache_page_addr(page_address(page));
}
-#define ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE
#ifdef CONFIG_DEBUG_RODATA
void mark_rodata_ro(void);
#endif
+#ifdef CONFIG_PA8X00
+/* Only pa8800, pa8900 needs this */
+#define ARCH_HAS_KMAP
+
+void kunmap_parisc(void *addr);
+
+static inline void *kmap(struct page *page)
+{
+ might_sleep();
+ return page_address(page);
+}
+
+#define kunmap(page) kunmap_parisc(page_address(page))
+
+#define kmap_atomic(page, idx) page_address(page)
+
+#define kunmap_atomic(addr, idx) kunmap_parisc(addr)
+
+#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn))
+#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
+#endif
+
#endif /* _PARISC_CACHEFLUSH_H */
diff --git a/include/asm-parisc/compat.h b/include/asm-parisc/compat.h
index 71b4eeea205a..fe8579023531 100644
--- a/include/asm-parisc/compat.h
+++ b/include/asm-parisc/compat.h
@@ -5,7 +5,7 @@
*/
#include <linux/types.h>
#include <linux/sched.h>
-#include <linux/personality.h>
+#include <linux/thread_info.h>
#define COMPAT_USER_HZ 100
@@ -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 personality(t->personality) == PER_LINUX32;
+ return test_ti_thread_flag(t->thread_info, TIF_32BIT);
}
static inline int is_compat_task(void)
diff --git a/include/asm-parisc/dma.h b/include/asm-parisc/dma.h
index 9979c3cb3745..da2cf373e31c 100644
--- a/include/asm-parisc/dma.h
+++ b/include/asm-parisc/dma.h
@@ -72,18 +72,13 @@
#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */
#define DMA2_EXT_MODE_REG (0x400 | DMA2_MODE_REG)
-extern spinlock_t dma_spin_lock;
-
static __inline__ unsigned long claim_dma_lock(void)
{
- unsigned long flags;
- spin_lock_irqsave(&dma_spin_lock, flags);
- return flags;
+ return 0;
}
static __inline__ void release_dma_lock(unsigned long flags)
{
- spin_unlock_irqrestore(&dma_spin_lock, flags);
}
diff --git a/include/asm-parisc/futex.h b/include/asm-parisc/futex.h
index 6a332a9f099c..d84bbb283fd1 100644
--- a/include/asm-parisc/futex.h
+++ b/include/asm-parisc/futex.h
@@ -1,6 +1,71 @@
-#ifndef _ASM_FUTEX_H
-#define _ASM_FUTEX_H
+#ifndef _ASM_PARISC_FUTEX_H
+#define _ASM_PARISC_FUTEX_H
-#include <asm-generic/futex.h>
+#ifdef __KERNEL__
+#include <linux/futex.h>
+#include <asm/errno.h>
+#include <asm/uaccess.h>
+
+static inline int
+futex_atomic_op_inuser (int encoded_op, int __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval = 0, ret;
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ if (! access_ok (VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ inc_preempt_count();
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ case FUTEX_OP_ADD:
+ case FUTEX_OP_OR:
+ case FUTEX_OP_ANDN:
+ case FUTEX_OP_XOR:
+ default:
+ ret = -ENOSYS;
+ }
+
+ dec_preempt_count();
+
+ if (!ret) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+/* Non-atomic version */
+static inline int
+futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval)
+{
+ int err = 0;
+ int uval;
+
+ if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int)))
+ return -EFAULT;
+
+ err = get_user(uval, uaddr);
+ if (err) return -EFAULT;
+ if (uval == oldval)
+ err = put_user(newval, uaddr);
+ if (err) return -EFAULT;
+ return uval;
+}
+
+#endif
#endif
diff --git a/include/asm-parisc/io.h b/include/asm-parisc/io.h
index b9eb245b8874..c1963ce19dd2 100644
--- a/include/asm-parisc/io.h
+++ b/include/asm-parisc/io.h
@@ -134,7 +134,7 @@ extern inline void __iomem * ioremap(unsigned long offset, unsigned long size)
}
#define ioremap_nocache(off, sz) ioremap((off), (sz))
-extern void iounmap(void __iomem *addr);
+extern void iounmap(const volatile void __iomem *addr);
static inline unsigned char __raw_readb(const volatile void __iomem *addr)
{
diff --git a/include/asm-parisc/iosapic.h b/include/asm-parisc/iosapic.h
deleted file mode 100644
index 613390e6805c..000000000000
--- a/include/asm-parisc/iosapic.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-** This file is private to iosapic driver.
-** If stuff needs to be used by another driver, move it to a common file.
-**
-** WARNING: fields most data structures here are ordered to make sure
-** they pack nicely for 64-bit compilation. (ie sizeof(long) == 8)
-*/
-
-
-/*
-** I/O SAPIC init function
-** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
-** Call setup as part of per instance initialization.
-** (ie *not* init_module() function unless only one is present.)
-** fixup_irq is to initialize PCI IRQ line support and
-** virtualize pcidev->irq value. To be called by pci_fixup_bus().
-*/
-extern void *iosapic_register(unsigned long hpa);
-extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
-
-
-#ifdef __IA64__
-/*
-** PA: PIB (Processor Interrupt Block) is handled by Runway bus adapter.
-** and is hardcoded to 0xfeeNNNN0 where NNNN is id_eid field.
-**
-** IA64: PIB is handled by "Local SAPIC" (integrated in the processor).
-*/
-struct local_sapic_info {
- struct local_sapic_info *lsi_next; /* point to next CPU info */
- int *lsi_cpu_id; /* point to logical CPU id */
- unsigned long *lsi_id_eid; /* point to IA-64 CPU id */
- int *lsi_status; /* point to CPU status */
- void *lsi_private; /* point to special info */
-};
-
-/*
-** "root" data structure which ties everything together.
-** Should always be able to start with sapic_root and locate
-** the desired information.
-*/
-struct sapic_info {
- struct sapic_info *si_next; /* info is per cell */
- int si_cellid; /* cell id */
- unsigned int si_status; /* status */
- char *si_pib_base; /* intr blk base address */
- local_sapic_info_t *si_local_info;
- io_sapic_info_t *si_io_info;
- extint_info_t *si_extint_info;/* External Intr info */
-};
-
-#endif /* IA64 */
-
diff --git a/include/asm-parisc/irq.h b/include/asm-parisc/irq.h
index 5cae260615a2..399c81981ed5 100644
--- a/include/asm-parisc/irq.h
+++ b/include/asm-parisc/irq.h
@@ -31,7 +31,7 @@ static __inline__ int irq_canonicalize(int irq)
return (irq == 2) ? 9 : irq;
}
-struct hw_interrupt_type;
+struct irq_chip;
/*
* Some useful "we don't have to do anything here" handlers. Should
@@ -39,6 +39,8 @@ struct hw_interrupt_type;
*/
void no_ack_irq(unsigned int irq);
void no_end_irq(unsigned int irq);
+void cpu_ack_irq(unsigned int irq);
+void cpu_end_irq(unsigned int irq);
extern int txn_alloc_irq(unsigned int nbits);
extern int txn_claim_irq(int);
@@ -46,7 +48,7 @@ extern unsigned int txn_alloc_data(unsigned int);
extern unsigned long txn_alloc_addr(unsigned int);
extern unsigned long txn_affinity_addr(unsigned int irq, int cpu);
-extern int cpu_claim_irq(unsigned int irq, struct hw_interrupt_type *, void *);
+extern int cpu_claim_irq(unsigned int irq, struct irq_chip *, void *);
extern int cpu_check_affinity(unsigned int irq, cpumask_t *dest);
/* soft power switch support (power.c) */
diff --git a/include/asm-parisc/irq_regs.h b/include/asm-parisc/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-parisc/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-parisc/mckinley.h b/include/asm-parisc/mckinley.h
new file mode 100644
index 000000000000..d1ea6f12915e
--- /dev/null
+++ b/include/asm-parisc/mckinley.h
@@ -0,0 +1,9 @@
+#ifndef ASM_PARISC_MCKINLEY_H
+#define ASM_PARISC_MCKINLEY_H
+#ifdef __KERNEL__
+
+/* declared in arch/parisc/kernel/setup.c */
+extern struct proc_dir_entry * proc_mckinley_root;
+
+#endif /*__KERNEL__*/
+#endif /*ASM_PARISC_MCKINLEY_H*/
diff --git a/include/asm-parisc/page.h b/include/asm-parisc/page.h
index 57d6d82756dd..3567208191e3 100644
--- a/include/asm-parisc/page.h
+++ b/include/asm-parisc/page.h
@@ -26,24 +26,10 @@
struct page;
-extern void purge_kernel_dcache_page(unsigned long);
-extern void copy_user_page_asm(void *to, void *from);
-extern void clear_user_page_asm(void *page, unsigned long vaddr);
-
-static inline void
-copy_user_page(void *vto, void *vfrom, unsigned long vaddr, struct page *pg)
-{
- copy_user_page_asm(vto, vfrom);
- flush_kernel_dcache_page_asm(vto);
- /* XXX: ppc flushes icache too, should we? */
-}
-
-static inline void
-clear_user_page(void *page, unsigned long vaddr, struct page *pg)
-{
- purge_kernel_dcache_page((unsigned long)page);
- clear_user_page_asm(page, vaddr);
-}
+void copy_user_page_asm(void *to, void *from);
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+ struct page *pg);
+void clear_user_page(void *page, unsigned long vaddr, struct page *pg);
/*
* These are used to make use of C type-checking..
diff --git a/include/asm-parisc/param.h b/include/asm-parisc/param.h
index 07cb9b93cfe2..32e03d877858 100644
--- a/include/asm-parisc/param.h
+++ b/include/asm-parisc/param.h
@@ -2,13 +2,9 @@
#define _ASMPARISC_PARAM_H
#ifdef __KERNEL__
-# ifdef CONFIG_PA20
-# define HZ 1000 /* Faster machines */
-# else
-# define HZ 100 /* Internal kernel timer frequency */
-# endif
-# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
-# define CLOCKS_PER_SEC (USER_HZ) /* like times() */
+#define HZ CONFIG_HZ
+#define USER_HZ 100 /* some user API use "ticks" */
+#define CLOCKS_PER_SEC (USER_HZ) /* like times() */
#endif
#ifndef HZ
diff --git a/include/asm-parisc/parisc-device.h b/include/asm-parisc/parisc-device.h
index 1d247e32a608..e12624d8941d 100644
--- a/include/asm-parisc/parisc-device.h
+++ b/include/asm-parisc/parisc-device.h
@@ -1,3 +1,6 @@
+#ifndef _ASM_PARISC_PARISC_DEVICE_H_
+#define _ASM_PARISC_PARISC_DEVICE_H_
+
#include <linux/device.h>
struct parisc_device {
@@ -57,3 +60,5 @@ parisc_get_drvdata(struct parisc_device *d)
}
extern struct bus_type parisc_bus_type;
+
+#endif /*_ASM_PARISC_PARISC_DEVICE_H_*/
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
index 8b631f47eb25..7b8ad118d2fe 100644
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -293,4 +293,9 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
/* We don't need to penalize isa irq's */
}
+static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
+{
+ return channel ? 15 : 14;
+}
+
#endif /* __ASM_PARISC_PCI_H */
diff --git a/include/asm-parisc/pdc.h b/include/asm-parisc/pdc.h
index c9b2e35326ee..423c2b84b4a0 100644
--- a/include/asm-parisc/pdc.h
+++ b/include/asm-parisc/pdc.h
@@ -774,8 +774,6 @@ int pdc_sti_call(unsigned long func, unsigned long flags,
unsigned long inptr, unsigned long outputr,
unsigned long glob_cfg);
-extern void pdc_init(void);
-
static inline char * os_id_to_string(u16 os_id) {
switch(os_id) {
case OS_ID_NONE: return "No OS";
diff --git a/include/asm-parisc/prefetch.h b/include/asm-parisc/prefetch.h
new file mode 100644
index 000000000000..5d021726fa33
--- /dev/null
+++ b/include/asm-parisc/prefetch.h
@@ -0,0 +1,39 @@
+/*
+ * include/asm-parisc/prefetch.h
+ *
+ * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
+ * In addition, many implementations do hardware prefetching of both
+ * instructions and data.
+ *
+ * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
+ * to gr0 but not in a way that Linux can use. If the load would cause an
+ * interruption (eg due to prefetching 0), it is suppressed on PA2.0
+ * processors, but not on 7300LC.
+ *
+ */
+
+#ifndef __ASM_PARISC_PREFETCH_H
+#define __ASM_PARISC_PREFETCH_H
+
+#ifndef __ASSEMBLY__
+#ifdef CONFIG_PREFETCH
+
+#define ARCH_HAS_PREFETCH
+extern inline void prefetch(const void *addr)
+{
+ __asm__("ldw 0(%0), %%r0" : : "r" (addr));
+}
+
+/* LDD is a PA2.0 addition. */
+#ifdef CONFIG_PA20
+#define ARCH_HAS_PREFETCHW
+extern inline void prefetchw(const void *addr)
+{
+ __asm__("ldd 0(%0), %%r0" : : "r" (addr));
+}
+#endif /* CONFIG_PA20 */
+
+#endif /* CONFIG_PREFETCH */
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_PARISC_PROCESSOR_H */
diff --git a/include/asm-parisc/processor.h b/include/asm-parisc/processor.h
index b73626f040da..fd7866dc8c83 100644
--- a/include/asm-parisc/processor.h
+++ b/include/asm-parisc/processor.h
@@ -9,6 +9,8 @@
#define __ASM_PARISC_PROCESSOR_H
#ifndef __ASSEMBLY__
+#include <asm/prefetch.h> /* lockdep.h needs <linux/prefetch.h> */
+
#include <linux/threads.h>
#include <linux/spinlock_types.h>
@@ -276,7 +278,7 @@ on downward growing arches, it looks like this:
*/
#ifdef __LP64__
-#define USER_WIDE_MODE (personality(current->personality) == PER_LINUX)
+#define USER_WIDE_MODE (!test_thread_flag(TIF_32BIT))
#else
#define USER_WIDE_MODE 0
#endif
@@ -328,33 +330,20 @@ extern unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk) ((tsk)->thread.regs.iaoq[0])
#define KSTK_ESP(tsk) ((tsk)->thread.regs.gr[30])
+#define cpu_relax() barrier()
-/*
- * PA 2.0 defines data prefetch instructions on page 6-11 of the Kane book.
- * In addition, many implementations do hardware prefetching of both
- * instructions and data.
- *
- * PA7300LC (page 14-4 of the ERS) also implements prefetching by a load
- * to gr0 but not in a way that Linux can use. If the load would cause an
- * interruption (eg due to prefetching 0), it is suppressed on PA2.0
- * processors, but not on 7300LC.
- */
-#ifdef CONFIG_PREFETCH
-#define ARCH_HAS_PREFETCH
-#define ARCH_HAS_PREFETCHW
-
-extern inline void prefetch(const void *addr)
-{
- __asm__("ldw 0(%0), %%r0" : : "r" (addr));
-}
-
-extern inline void prefetchw(const void *addr)
+/* Used as a macro to identify the combined VIPT/PIPT cached
+ * CPUs which require a guarantee of coherency (no inequivalent
+ * aliases with different data, whether clean or not) to operate */
+static inline int parisc_requires_coherency(void)
{
- __asm__("ldd 0(%0), %%r0" : : "r" (addr));
-}
+#ifdef CONFIG_PA8X00
+ /* FIXME: also pa8900 - when we see one */
+ return boot_cpu_data.cpu_type == mako;
+#else
+ return 0;
#endif
-
-#define cpu_relax() barrier()
+}
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-parisc/ropes.h b/include/asm-parisc/ropes.h
new file mode 100644
index 000000000000..5542dd00472b
--- /dev/null
+++ b/include/asm-parisc/ropes.h
@@ -0,0 +1,322 @@
+#ifndef _ASM_PARISC_ROPES_H_
+#define _ASM_PARISC_ROPES_H_
+
+#include <asm-parisc/parisc-device.h>
+
+#ifdef CONFIG_64BIT
+/* "low end" PA8800 machines use ZX1 chipset: PAT PDC and only run 64-bit */
+#define ZX1_SUPPORT
+#endif
+
+#ifdef CONFIG_PROC_FS
+/* depends on proc fs support. But costs CPU performance */
+#undef SBA_COLLECT_STATS
+#endif
+
+/*
+** The number of pdir entries to "free" before issueing
+** a read to PCOM register to flush out PCOM writes.
+** Interacts with allocation granularity (ie 4 or 8 entries
+** allocated and free'd/purged at a time might make this
+** less interesting).
+*/
+#define DELAYED_RESOURCE_CNT 16
+
+#define MAX_IOC 2 /* per Ike. Pluto/Astro only have 1. */
+#define ROPES_PER_IOC 8 /* per Ike half or Pluto/Astro */
+
+struct ioc {
+ void __iomem *ioc_hpa; /* I/O MMU base address */
+ char *res_map; /* resource map, bit == pdir entry */
+ u64 *pdir_base; /* physical base address */
+ unsigned long ibase; /* pdir IOV Space base - shared w/lba_pci */
+ unsigned long imask; /* pdir IOV Space mask - shared w/lba_pci */
+#ifdef ZX1_SUPPORT
+ unsigned long iovp_mask; /* help convert IOVA to IOVP */
+#endif
+ unsigned long *res_hint; /* next avail IOVP - circular search */
+ spinlock_t res_lock;
+ unsigned int res_bitshift; /* from the LEFT! */
+ unsigned int res_size; /* size of resource map in bytes */
+#ifdef SBA_HINT_SUPPORT
+/* FIXME : DMA HINTs not used */
+ unsigned long hint_mask_pdir; /* bits used for DMA hints */
+ unsigned int hint_shift_pdir;
+#endif
+#if DELAYED_RESOURCE_CNT > 0
+ int saved_cnt;
+ struct sba_dma_pair {
+ dma_addr_t iova;
+ size_t size;
+ } saved[DELAYED_RESOURCE_CNT];
+#endif
+
+#ifdef SBA_COLLECT_STATS
+#define SBA_SEARCH_SAMPLE 0x100
+ unsigned long avg_search[SBA_SEARCH_SAMPLE];
+ unsigned long avg_idx; /* current index into avg_search */
+ unsigned long used_pages;
+ unsigned long msingle_calls;
+ unsigned long msingle_pages;
+ unsigned long msg_calls;
+ unsigned long msg_pages;
+ unsigned long usingle_calls;
+ unsigned long usingle_pages;
+ unsigned long usg_calls;
+ unsigned long usg_pages;
+#endif
+ /* STUFF We don't need in performance path */
+ unsigned int pdir_size; /* in bytes, determined by IOV Space size */
+};
+
+struct sba_device {
+ struct sba_device *next; /* list of SBA's in system */
+ struct parisc_device *dev; /* dev found in bus walk */
+ const char *name;
+ void __iomem *sba_hpa; /* base address */
+ spinlock_t sba_lock;
+ unsigned int flags; /* state/functionality enabled */
+ unsigned int hw_rev; /* HW revision of chip */
+
+ struct resource chip_resv; /* MMIO reserved for chip */
+ struct resource iommu_resv; /* MMIO reserved for iommu */
+
+ unsigned int num_ioc; /* number of on-board IOC's */
+ struct ioc ioc[MAX_IOC];
+};
+
+#define ASTRO_RUNWAY_PORT 0x582
+#define IKE_MERCED_PORT 0x803
+#define REO_MERCED_PORT 0x804
+#define REOG_MERCED_PORT 0x805
+#define PLUTO_MCKINLEY_PORT 0x880
+
+static inline int IS_ASTRO(struct parisc_device *d) {
+ return d->id.hversion == ASTRO_RUNWAY_PORT;
+}
+
+static inline int IS_IKE(struct parisc_device *d) {
+ return d->id.hversion == IKE_MERCED_PORT;
+}
+
+static inline int IS_PLUTO(struct parisc_device *d) {
+ return d->id.hversion == PLUTO_MCKINLEY_PORT;
+}
+
+#define PLUTO_IOVA_BASE (1UL*1024*1024*1024) /* 1GB */
+#define PLUTO_IOVA_SIZE (1UL*1024*1024*1024) /* 1GB */
+#define PLUTO_GART_SIZE (PLUTO_IOVA_SIZE / 2)
+
+#define SBA_PDIR_VALID_BIT 0x8000000000000000ULL
+
+#define SBA_AGPGART_COOKIE 0x0000badbadc0ffeeULL
+
+#define SBA_FUNC_ID 0x0000 /* function id */
+#define SBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+
+#define SBA_FUNC_SIZE 4096 /* SBA configuration function reg set */
+
+#define ASTRO_IOC_OFFSET (32 * SBA_FUNC_SIZE)
+#define PLUTO_IOC_OFFSET (1 * SBA_FUNC_SIZE)
+/* Ike's IOC's occupy functions 2 and 3 */
+#define IKE_IOC_OFFSET(p) ((p+2) * SBA_FUNC_SIZE)
+
+#define IOC_CTRL 0x8 /* IOC_CTRL offset */
+#define IOC_CTRL_TC (1 << 0) /* TOC Enable */
+#define IOC_CTRL_CE (1 << 1) /* Coalesce Enable */
+#define IOC_CTRL_DE (1 << 2) /* Dillon Enable */
+#define IOC_CTRL_RM (1 << 8) /* Real Mode */
+#define IOC_CTRL_NC (1 << 9) /* Non Coherent Mode */
+#define IOC_CTRL_D4 (1 << 11) /* Disable 4-byte coalescing */
+#define IOC_CTRL_DD (1 << 13) /* Disable distr. LMMIO range coalescing */
+
+/*
+** Offsets into MBIB (Function 0 on Ike and hopefully Astro)
+** Firmware programs this stuff. Don't touch it.
+*/
+#define LMMIO_DIRECT0_BASE 0x300
+#define LMMIO_DIRECT0_MASK 0x308
+#define LMMIO_DIRECT0_ROUTE 0x310
+
+#define LMMIO_DIST_BASE 0x360
+#define LMMIO_DIST_MASK 0x368
+#define LMMIO_DIST_ROUTE 0x370
+
+#define IOS_DIST_BASE 0x390
+#define IOS_DIST_MASK 0x398
+#define IOS_DIST_ROUTE 0x3A0
+
+#define IOS_DIRECT_BASE 0x3C0
+#define IOS_DIRECT_MASK 0x3C8
+#define IOS_DIRECT_ROUTE 0x3D0
+
+/*
+** Offsets into I/O TLB (Function 2 and 3 on Ike)
+*/
+#define ROPE0_CTL 0x200 /* "regbus pci0" */
+#define ROPE1_CTL 0x208
+#define ROPE2_CTL 0x210
+#define ROPE3_CTL 0x218
+#define ROPE4_CTL 0x220
+#define ROPE5_CTL 0x228
+#define ROPE6_CTL 0x230
+#define ROPE7_CTL 0x238
+
+#define IOC_ROPE0_CFG 0x500 /* pluto only */
+#define IOC_ROPE_AO 0x10 /* Allow "Relaxed Ordering" */
+
+#define HF_ENABLE 0x40
+
+#define IOC_IBASE 0x300 /* IO TLB */
+#define IOC_IMASK 0x308
+#define IOC_PCOM 0x310
+#define IOC_TCNFG 0x318
+#define IOC_PDIR_BASE 0x320
+
+/*
+** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
+** It's safer (avoid memory corruption) to keep DMA page mappings
+** equivalently sized to VM PAGE_SIZE.
+**
+** We really can't avoid generating a new mapping for each
+** page since the Virtual Coherence Index has to be generated
+** and updated for each page.
+**
+** PAGE_SIZE could be greater than IOVP_SIZE. But not the inverse.
+*/
+#define IOVP_SIZE PAGE_SIZE
+#define IOVP_SHIFT PAGE_SHIFT
+#define IOVP_MASK PAGE_MASK
+
+#define SBA_PERF_CFG 0x708 /* Performance Counter stuff */
+#define SBA_PERF_MASK1 0x718
+#define SBA_PERF_MASK2 0x730
+
+/*
+** Offsets into PCI Performance Counters (functions 12 and 13)
+** Controlled by PERF registers in function 2 & 3 respectively.
+*/
+#define SBA_PERF_CNT1 0x200
+#define SBA_PERF_CNT2 0x208
+#define SBA_PERF_CNT3 0x210
+
+/*
+** lba_device: Per instance Elroy data structure
+*/
+struct lba_device {
+ struct pci_hba_data hba;
+
+ spinlock_t lba_lock;
+ void *iosapic_obj;
+
+#ifdef CONFIG_64BIT
+ void __iomem *iop_base; /* PA_VIEW - for IO port accessor funcs */
+#endif
+
+ int flags; /* state/functionality enabled */
+ int hw_rev; /* HW revision of chip */
+};
+
+#define ELROY_HVERS 0x782
+#define MERCURY_HVERS 0x783
+#define QUICKSILVER_HVERS 0x784
+
+static inline int IS_ELROY(struct parisc_device *d) {
+ return (d->id.hversion == ELROY_HVERS);
+}
+
+static inline int IS_MERCURY(struct parisc_device *d) {
+ return (d->id.hversion == MERCURY_HVERS);
+}
+
+static inline int IS_QUICKSILVER(struct parisc_device *d) {
+ return (d->id.hversion == QUICKSILVER_HVERS);
+}
+
+static inline int agp_mode_mercury(void __iomem *hpa) {
+ u64 bus_mode;
+
+ bus_mode = readl(hpa + 0x0620);
+ if (bus_mode & 1)
+ return 1;
+
+ return 0;
+}
+
+/*
+** I/O SAPIC init function
+** Caller knows where an I/O SAPIC is. LBA has an integrated I/O SAPIC.
+** Call setup as part of per instance initialization.
+** (ie *not* init_module() function unless only one is present.)
+** fixup_irq is to initialize PCI IRQ line support and
+** virtualize pcidev->irq value. To be called by pci_fixup_bus().
+*/
+extern void *iosapic_register(unsigned long hpa);
+extern int iosapic_fixup_irq(void *obj, struct pci_dev *pcidev);
+
+#define LBA_FUNC_ID 0x0000 /* function id */
+#define LBA_FCLASS 0x0008 /* function class, bist, header, rev... */
+#define LBA_CAPABLE 0x0030 /* capabilities register */
+
+#define LBA_PCI_CFG_ADDR 0x0040 /* poke CFG address here */
+#define LBA_PCI_CFG_DATA 0x0048 /* read or write data here */
+
+#define LBA_PMC_MTLT 0x0050 /* Firmware sets this - read only. */
+#define LBA_FW_SCRATCH 0x0058 /* Firmware writes the PCI bus number here. */
+#define LBA_ERROR_ADDR 0x0070 /* On error, address gets logged here */
+
+#define LBA_ARB_MASK 0x0080 /* bit 0 enable arbitration. PAT/PDC enables */
+#define LBA_ARB_PRI 0x0088 /* firmware sets this. */
+#define LBA_ARB_MODE 0x0090 /* firmware sets this. */
+#define LBA_ARB_MTLT 0x0098 /* firmware sets this. */
+
+#define LBA_MOD_ID 0x0100 /* Module ID. PDC_PAT_CELL reports 4 */
+
+#define LBA_STAT_CTL 0x0108 /* Status & Control */
+#define LBA_BUS_RESET 0x01 /* Deassert PCI Bus Reset Signal */
+#define CLEAR_ERRLOG 0x10 /* "Clear Error Log" cmd */
+#define CLEAR_ERRLOG_ENABLE 0x20 /* "Clear Error Log" Enable */
+#define HF_ENABLE 0x40 /* enable HF mode (default is -1 mode) */
+
+#define LBA_LMMIO_BASE 0x0200 /* < 4GB I/O address range */
+#define LBA_LMMIO_MASK 0x0208
+
+#define LBA_GMMIO_BASE 0x0210 /* > 4GB I/O address range */
+#define LBA_GMMIO_MASK 0x0218
+
+#define LBA_WLMMIO_BASE 0x0220 /* All < 4GB ranges under the same *SBA* */
+#define LBA_WLMMIO_MASK 0x0228
+
+#define LBA_WGMMIO_BASE 0x0230 /* All > 4GB ranges under the same *SBA* */
+#define LBA_WGMMIO_MASK 0x0238
+
+#define LBA_IOS_BASE 0x0240 /* I/O port space for this LBA */
+#define LBA_IOS_MASK 0x0248
+
+#define LBA_ELMMIO_BASE 0x0250 /* Extra LMMIO range */
+#define LBA_ELMMIO_MASK 0x0258
+
+#define LBA_EIOS_BASE 0x0260 /* Extra I/O port space */
+#define LBA_EIOS_MASK 0x0268
+
+#define LBA_GLOBAL_MASK 0x0270 /* Mercury only: Global Address Mask */
+#define LBA_DMA_CTL 0x0278 /* firmware sets this */
+
+#define LBA_IBASE 0x0300 /* SBA DMA support */
+#define LBA_IMASK 0x0308
+
+/* FIXME: ignore DMA Hint stuff until we can measure performance */
+#define LBA_HINT_CFG 0x0310
+#define LBA_HINT_BASE 0x0380 /* 14 registers at every 8 bytes. */
+
+#define LBA_BUS_MODE 0x0620
+
+/* ERROR regs are needed for config cycle kluges */
+#define LBA_ERROR_CONFIG 0x0680
+#define LBA_SMART_MODE 0x20
+#define LBA_ERROR_STATUS 0x0688
+#define LBA_ROPE_CTL 0x06A0
+
+#define LBA_IOSAPIC_BASE 0x800 /* Offset of IRQ logic */
+
+#endif /*_ASM_PARISC_ROPES_H_*/
diff --git a/include/asm-parisc/rtc.h b/include/asm-parisc/rtc.h
index f3d3d6b110ba..f4ebff11dcbd 100644
--- a/include/asm-parisc/rtc.h
+++ b/include/asm-parisc/rtc.h
@@ -1,5 +1,5 @@
/*
- * inclue/asm-parisc/rtc.h
+ * include/asm-parisc/rtc.h
*
* Copyright 2002 Randolph CHung <tausq@debian.org>
*
diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
index 82fd820d684f..d7e3cc60dbc3 100644
--- a/include/asm-parisc/serial.h
+++ b/include/asm-parisc/serial.h
@@ -3,20 +3,8 @@
*/
/*
- * This assumes you have a 7.272727 MHz clock for your UART.
- * The documentation implies a 40Mhz clock, and elsewhere a 7Mhz clock
- * Clarified: 7.2727MHz on LASI. Not yet clarified for DINO
+ * This is used for 16550-compatible UARTs
*/
+#define BASE_BAUD ( 1843200 / 16 )
-#define LASI_BASE_BAUD ( 7272727 / 16 )
-#define BASE_BAUD LASI_BASE_BAUD
-
-/*
- * We don't use the ISA probing code, so these entries are just to reserve
- * space. Some example (maximal) configurations:
- * - 712 w/ additional Lasi & RJ16 ports: 4
- * - J5k w/ PCI serial cards: 2 + 4 * card ~= 34
- * A500 w/ PCI serial cards: 5 + 4 * card ~= 17
- */
-
#define SERIAL_PORT_DFNS
diff --git a/include/asm-parisc/spinlock.h b/include/asm-parisc/spinlock.h
index a93960e232cf..f3d2090a18dc 100644
--- a/include/asm-parisc/spinlock.h
+++ b/include/asm-parisc/spinlock.h
@@ -56,50 +56,79 @@ static inline int __raw_spin_trylock(raw_spinlock_t *x)
}
/*
- * Read-write spinlocks, allowing multiple readers
- * but only one writer.
+ * Read-write spinlocks, allowing multiple readers but only one writer.
+ * Linux rwlocks are unfair to writers; they can be starved for an indefinite
+ * time by readers. With care, they can also be taken in interrupt context.
+ *
+ * In the PA-RISC implementation, we have a spinlock and a counter.
+ * Readers use the lock to serialise their access to the counter (which
+ * records how many readers currently hold the lock).
+ * Writers hold the spinlock, preventing any readers or other writers from
+ * grabbing the rwlock.
*/
-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
-
-/* read_lock, read_unlock are pretty straightforward. Of course it somehow
- * sucks we end up saving/restoring flags twice for read_lock_irqsave aso. */
-
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock */
static __inline__ void __raw_read_lock(raw_rwlock_t *rw)
{
- __raw_spin_lock(&rw->lock);
-
+ unsigned long flags;
+ local_irq_save(flags);
+ __raw_spin_lock_flags(&rw->lock, flags);
rw->counter++;
-
__raw_spin_unlock(&rw->lock);
+ local_irq_restore(flags);
}
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock */
static __inline__ void __raw_read_unlock(raw_rwlock_t *rw)
{
- __raw_spin_lock(&rw->lock);
-
+ unsigned long flags;
+ local_irq_save(flags);
+ __raw_spin_lock_flags(&rw->lock, flags);
rw->counter--;
-
__raw_spin_unlock(&rw->lock);
+ local_irq_restore(flags);
}
-/* write_lock is less trivial. We optimistically grab the lock and check
- * if we surprised any readers. If so we release the lock and wait till
- * they're all gone before trying again
- *
- * Also note that we don't use the _irqsave / _irqrestore suffixes here.
- * If we're called with interrupts enabled and we've got readers (or other
- * writers) in interrupt handlers someone fucked up and we'd dead-lock
- * sooner or later anyway. prumpf */
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to grab the same read lock */
+static __inline__ int __raw_read_trylock(raw_rwlock_t *rw)
+{
+ unsigned long flags;
+ retry:
+ local_irq_save(flags);
+ if (__raw_spin_trylock(&rw->lock)) {
+ rw->counter++;
+ __raw_spin_unlock(&rw->lock);
+ local_irq_restore(flags);
+ return 1;
+ }
+
+ local_irq_restore(flags);
+ /* If write-locked, we fail to acquire the lock */
+ if (rw->counter < 0)
+ return 0;
+
+ /* Wait until we have a realistic chance at the lock */
+ while (__raw_spin_is_locked(&rw->lock) && rw->counter >= 0)
+ cpu_relax();
+
+ goto retry;
+}
-static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to read_trylock() this lock */
+static __inline__ void __raw_write_lock(raw_rwlock_t *rw)
{
+ unsigned long flags;
retry:
- __raw_spin_lock(&rw->lock);
+ local_irq_save(flags);
+ __raw_spin_lock_flags(&rw->lock, flags);
- if(rw->counter != 0) {
- /* this basically never happens */
+ if (rw->counter != 0) {
__raw_spin_unlock(&rw->lock);
+ local_irq_restore(flags);
while (rw->counter != 0)
cpu_relax();
@@ -107,31 +136,37 @@ retry:
goto retry;
}
- /* got it. now leave without unlocking */
- rw->counter = -1; /* remember we are locked */
+ rw->counter = -1; /* mark as write-locked */
+ mb();
+ local_irq_restore(flags);
}
-/* write_unlock is absolutely trivial - we don't have to wait for anything */
-
-static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
+static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
{
rw->counter = 0;
__raw_spin_unlock(&rw->lock);
}
-static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
+/* Note that we have to ensure interrupts are disabled in case we're
+ * interrupted by some other code that wants to read_trylock() this lock */
+static __inline__ int __raw_write_trylock(raw_rwlock_t *rw)
{
- __raw_spin_lock(&rw->lock);
- if (rw->counter != 0) {
- /* this basically never happens */
- __raw_spin_unlock(&rw->lock);
-
- return 0;
+ unsigned long flags;
+ int result = 0;
+
+ local_irq_save(flags);
+ if (__raw_spin_trylock(&rw->lock)) {
+ if (rw->counter == 0) {
+ rw->counter = -1;
+ result = 1;
+ } else {
+ /* Read-locked. Oh well. */
+ __raw_spin_unlock(&rw->lock);
+ }
}
+ local_irq_restore(flags);
- /* got it. now leave without unlocking */
- rw->counter = -1; /* remember we are locked */
- return 1;
+ return result;
}
/*
@@ -152,4 +187,8 @@ static __inline__ int __raw_write_can_lock(raw_rwlock_t *rw)
return !rw->counter;
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
index 27bcfad1c3e3..53b0f5d290e4 100644
--- a/include/asm-parisc/unistd.h
+++ b/include/asm-parisc/unistd.h
@@ -952,92 +952,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) \
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-/* mmap & mmap2 take 6 arguments */
-#define _syscall6(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5,type6,arg6) \
-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6) \
-{ \
- return K_INLINE_SYSCALL(name, 6, arg1, arg2, arg3, arg4, arg5, arg6); \
-}
-
-#ifdef __KERNEL_SYSCALLS__
-
-#include <asm/current.h>
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/syscalls.h>
-
-static inline pid_t setsid(void)
-{
- return sys_setsid();
-}
-
-static inline int write(int fd, const char *buf, off_t count)
-{
- return sys_write(fd, buf, count);
-}
-
-static inline int read(int fd, char *buf, off_t count)
-{
- return sys_read(fd, buf, count);
-}
-
-static inline off_t lseek(int fd, off_t offset, int count)
-{
- return sys_lseek(fd, offset, count);
-}
-
-static inline int dup(int fd)
-{
- return sys_dup(fd);
-}
-
-static inline int execve(char *filename, char * argv [],
- char * envp[])
-{
- extern int __execve(char *, char **, char **, struct task_struct *);
- return __execve(filename, argv, envp, current);
-}
-
-static inline int open(const char *file, int flag, int mode)
-{
- return sys_open(file, flag, mode);
-}
-
-static inline int close(int fd)
-{
- return sys_close(fd);
-}
-
-static inline void _exit(int exitcode)
-{
- sys_exit(exitcode);
-}
-
-static inline pid_t waitpid(pid_t pid, int *wait_stat, int options)
-{
- return sys_wait4(pid, wait_stat, options, NULL);
-}
-
-asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long offset);
-asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-struct pt_regs;
-asmlinkage int sys_execve(struct pt_regs *regs);
-int sys_clone(unsigned long clone_flags, unsigned long usp,
- struct pt_regs *regs);
-int sys_vfork(struct pt_regs *regs);
-int sys_pipe(int *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
#endif /* __ASSEMBLY__ */
#undef STR
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
index f44b529e3298..978b2c7e84ea 100644
--- a/include/asm-powerpc/bug.h
+++ b/include/asm-powerpc/bug.h
@@ -70,9 +70,10 @@ struct bug_entry *find_bug(unsigned long bugaddr);
"i" (__FILE__), "i" (__FUNCTION__)); \
} while (0)
-#define WARN_ON(x) do { \
- if (__builtin_constant_p(x)) { \
- if (x) \
+#define WARN_ON(x) ({ \
+ typeof(x) __ret_warn_on = (x); \
+ if (__builtin_constant_p(__ret_warn_on)) { \
+ if (__ret_warn_on) \
__WARN(); \
} else { \
__asm__ __volatile__( \
@@ -80,11 +81,12 @@ struct bug_entry *find_bug(unsigned long bugaddr);
".section __bug_table,\"a\"\n" \
"\t"PPC_LONG" 1b,%1,%2,%3\n" \
".previous" \
- : : "r" ((long)(x)), \
+ : : "r" (__ret_warn_on), \
"i" (__LINE__ + BUG_WARNING_TRAP), \
"i" (__FILE__), "i" (__FUNCTION__)); \
} \
-} while (0)
+ unlikely(__ret_warn_on); \
+})
#define HAVE_ARCH_BUG
#define HAVE_ARCH_BUG_ON
diff --git a/include/asm-powerpc/firmware.h b/include/asm-powerpc/firmware.h
index 77069df92bf8..1022737f4f34 100644
--- a/include/asm-powerpc/firmware.h
+++ b/include/asm-powerpc/firmware.h
@@ -14,34 +14,36 @@
#ifdef __KERNEL__
-#ifndef __ASSEMBLY__
+#include <asm/asm-compat.h>
/* firmware feature bitmask values */
#define FIRMWARE_MAX_FEATURES 63
-#define FW_FEATURE_PFT (1UL<<0)
-#define FW_FEATURE_TCE (1UL<<1)
-#define FW_FEATURE_SPRG0 (1UL<<2)
-#define FW_FEATURE_DABR (1UL<<3)
-#define FW_FEATURE_COPY (1UL<<4)
-#define FW_FEATURE_ASR (1UL<<5)
-#define FW_FEATURE_DEBUG (1UL<<6)
-#define FW_FEATURE_TERM (1UL<<7)
-#define FW_FEATURE_PERF (1UL<<8)
-#define FW_FEATURE_DUMP (1UL<<9)
-#define FW_FEATURE_INTERRUPT (1UL<<10)
-#define FW_FEATURE_MIGRATE (1UL<<11)
-#define FW_FEATURE_PERFMON (1UL<<12)
-#define FW_FEATURE_CRQ (1UL<<13)
-#define FW_FEATURE_VIO (1UL<<14)
-#define FW_FEATURE_RDMA (1UL<<15)
-#define FW_FEATURE_LLAN (1UL<<16)
-#define FW_FEATURE_BULK (1UL<<17)
-#define FW_FEATURE_XDABR (1UL<<18)
-#define FW_FEATURE_MULTITCE (1UL<<19)
-#define FW_FEATURE_SPLPAR (1UL<<20)
-#define FW_FEATURE_ISERIES (1UL<<21)
-#define FW_FEATURE_LPAR (1UL<<22)
+#define FW_FEATURE_PFT ASM_CONST(0x0000000000000001)
+#define FW_FEATURE_TCE ASM_CONST(0x0000000000000002)
+#define FW_FEATURE_SPRG0 ASM_CONST(0x0000000000000004)
+#define FW_FEATURE_DABR ASM_CONST(0x0000000000000008)
+#define FW_FEATURE_COPY ASM_CONST(0x0000000000000010)
+#define FW_FEATURE_ASR ASM_CONST(0x0000000000000020)
+#define FW_FEATURE_DEBUG ASM_CONST(0x0000000000000040)
+#define FW_FEATURE_TERM ASM_CONST(0x0000000000000080)
+#define FW_FEATURE_PERF ASM_CONST(0x0000000000000100)
+#define FW_FEATURE_DUMP ASM_CONST(0x0000000000000200)
+#define FW_FEATURE_INTERRUPT ASM_CONST(0x0000000000000400)
+#define FW_FEATURE_MIGRATE ASM_CONST(0x0000000000000800)
+#define FW_FEATURE_PERFMON ASM_CONST(0x0000000000001000)
+#define FW_FEATURE_CRQ ASM_CONST(0x0000000000002000)
+#define FW_FEATURE_VIO ASM_CONST(0x0000000000004000)
+#define FW_FEATURE_RDMA ASM_CONST(0x0000000000008000)
+#define FW_FEATURE_LLAN ASM_CONST(0x0000000000010000)
+#define FW_FEATURE_BULK ASM_CONST(0x0000000000020000)
+#define FW_FEATURE_XDABR ASM_CONST(0x0000000000040000)
+#define FW_FEATURE_MULTITCE ASM_CONST(0x0000000000080000)
+#define FW_FEATURE_SPLPAR ASM_CONST(0x0000000000100000)
+#define FW_FEATURE_ISERIES ASM_CONST(0x0000000000200000)
+#define FW_FEATURE_LPAR ASM_CONST(0x0000000000400000)
+
+#ifndef __ASSEMBLY__
enum {
#ifdef CONFIG_PPC64
@@ -94,6 +96,23 @@ extern void machine_check_fwnmi(void);
/* This is true if we are using the firmware NMI handler (typically LPAR) */
extern int fwnmi_active;
+#else /* __ASSEMBLY__ */
+
+#define BEGIN_FW_FTR_SECTION 96:
+
+#define END_FW_FTR_SECTION(msk, val) \
+97: \
+ .section __fw_ftr_fixup,"a"; \
+ .align 3; \
+ .llong msk; \
+ .llong val; \
+ .llong 96b; \
+ .llong 97b; \
+ .previous
+
+#define END_FW_FTR_SECTION_IFSET(msk) END_FW_FTR_SECTION((msk), (msk))
+#define END_FW_FTR_SECTION_IFCLR(msk) END_FW_FTR_SECTION((msk), 0)
+
#endif /* __ASSEMBLY__ */
#endif /* __KERNEL__ */
#endif /* __ASM_POWERPC_FIRMWARE_H */
diff --git a/include/asm-powerpc/fs_pd.h b/include/asm-powerpc/fs_pd.h
new file mode 100644
index 000000000000..3d0e819d37f1
--- /dev/null
+++ b/include/asm-powerpc/fs_pd.h
@@ -0,0 +1,45 @@
+/*
+ * Platform information definitions.
+ *
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef FS_PD_H
+#define FS_PD_H
+#include <asm/cpm2.h>
+#include <sysdev/fsl_soc.h>
+#include <asm/time.h>
+
+static inline int uart_baudrate(void)
+{
+ return get_baudrate();
+}
+
+static inline int uart_clock(void)
+{
+ return ppc_proc_freq;
+}
+
+#define cpm2_map(member) \
+({ \
+ u32 offset = offsetof(cpm2_map_t, member); \
+ void *addr = ioremap (CPM_MAP_ADDR + offset, \
+ sizeof( ((cpm2_map_t*)0)->member)); \
+ addr; \
+})
+
+#define cpm2_map_size(member, size) \
+({ \
+ u32 offset = offsetof(cpm2_map_t, member); \
+ void *addr = ioremap (CPM_MAP_ADDR + offset, size); \
+ addr; \
+})
+
+#define cpm2_unmap(addr) iounmap(addr)
+
+#endif
diff --git a/include/asm-powerpc/i8259.h b/include/asm-powerpc/i8259.h
index c80e113052cd..78489fb8d140 100644
--- a/include/asm-powerpc/i8259.h
+++ b/include/asm-powerpc/i8259.h
@@ -6,10 +6,10 @@
#ifdef CONFIG_PPC_MERGE
extern void i8259_init(struct device_node *node, unsigned long intack_addr);
-extern unsigned int i8259_irq(struct pt_regs *regs);
+extern unsigned int i8259_irq(void);
#else
extern void i8259_init(unsigned long intack_addr, int offset);
-extern int i8259_irq(struct pt_regs *regs);
+extern int i8259_irq(void);
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/ibmebus.h b/include/asm-powerpc/ibmebus.h
index 7ab195a27888..3493429b70f5 100644
--- a/include/asm-powerpc/ibmebus.h
+++ b/include/asm-powerpc/ibmebus.h
@@ -65,7 +65,7 @@ void ibmebus_unregister_driver(struct ibmebus_driver *drv);
int ibmebus_request_irq(struct ibmebus_dev *dev,
u32 ist,
- irqreturn_t (*handler)(int, void*, struct pt_regs *),
+ irq_handler_t handler,
unsigned long irq_flags, const char * devname,
void *dev_id);
void ibmebus_free_irq(struct ibmebus_dev *dev, u32 ist, void *dev_id);
diff --git a/include/asm-powerpc/immap_qe.h b/include/asm-powerpc/immap_qe.h
new file mode 100644
index 000000000000..ce12f85fff9b
--- /dev/null
+++ b/include/asm-powerpc/immap_qe.h
@@ -0,0 +1,477 @@
+/*
+ * include/asm-powerpc/immap_qe.h
+ *
+ * QUICC Engine (QE) Internal Memory Map.
+ * The Internal Memory Map for devices with QE on them. This
+ * is the superset of all QE devices (8360, etc.).
+
+ * Copyright (C) 2006. Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.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.
+ */
+#ifndef _ASM_POWERPC_IMMAP_QE_H
+#define _ASM_POWERPC_IMMAP_QE_H
+#ifdef __KERNEL__
+
+#include <linux/kernel.h>
+
+#define QE_IMMAP_SIZE (1024 * 1024) /* 1MB from 1MB+IMMR */
+
+/* QE I-RAM */
+struct qe_iram {
+ __be32 iadd; /* I-RAM Address Register */
+ __be32 idata; /* I-RAM Data Register */
+ u8 res0[0x78];
+} __attribute__ ((packed));
+
+/* QE Interrupt Controller */
+struct qe_ic_regs {
+ __be32 qicr;
+ __be32 qivec;
+ __be32 qripnr;
+ __be32 qipnr;
+ __be32 qipxcc;
+ __be32 qipycc;
+ __be32 qipwcc;
+ __be32 qipzcc;
+ __be32 qimr;
+ __be32 qrimr;
+ __be32 qicnr;
+ u8 res0[0x4];
+ __be32 qiprta;
+ __be32 qiprtb;
+ u8 res1[0x4];
+ __be32 qricr;
+ u8 res2[0x20];
+ __be32 qhivec;
+ u8 res3[0x1C];
+} __attribute__ ((packed));
+
+/* Communications Processor */
+struct cp_qe {
+ __be32 cecr; /* QE command register */
+ __be32 ceccr; /* QE controller configuration register */
+ __be32 cecdr; /* QE command data register */
+ u8 res0[0xA];
+ __be16 ceter; /* QE timer event register */
+ u8 res1[0x2];
+ __be16 cetmr; /* QE timers mask register */
+ __be32 cetscr; /* QE time-stamp timer control register */
+ __be32 cetsr1; /* QE time-stamp register 1 */
+ __be32 cetsr2; /* QE time-stamp register 2 */
+ u8 res2[0x8];
+ __be32 cevter; /* QE virtual tasks event register */
+ __be32 cevtmr; /* QE virtual tasks mask register */
+ __be16 cercr; /* QE RAM control register */
+ u8 res3[0x2];
+ u8 res4[0x24];
+ __be16 ceexe1; /* QE external request 1 event register */
+ u8 res5[0x2];
+ __be16 ceexm1; /* QE external request 1 mask register */
+ u8 res6[0x2];
+ __be16 ceexe2; /* QE external request 2 event register */
+ u8 res7[0x2];
+ __be16 ceexm2; /* QE external request 2 mask register */
+ u8 res8[0x2];
+ __be16 ceexe3; /* QE external request 3 event register */
+ u8 res9[0x2];
+ __be16 ceexm3; /* QE external request 3 mask register */
+ u8 res10[0x2];
+ __be16 ceexe4; /* QE external request 4 event register */
+ u8 res11[0x2];
+ __be16 ceexm4; /* QE external request 4 mask register */
+ u8 res12[0x2];
+ u8 res13[0x280];
+} __attribute__ ((packed));
+
+/* QE Multiplexer */
+struct qe_mux {
+ __be32 cmxgcr; /* CMX general clock route register */
+ __be32 cmxsi1cr_l; /* CMX SI1 clock route low register */
+ __be32 cmxsi1cr_h; /* CMX SI1 clock route high register */
+ __be32 cmxsi1syr; /* CMX SI1 SYNC route register */
+ __be32 cmxucr1; /* CMX UCC1, UCC3 clock route register */
+ __be32 cmxucr2; /* CMX UCC5, UCC7 clock route register */
+ __be32 cmxucr3; /* CMX UCC2, UCC4 clock route register */
+ __be32 cmxucr4; /* CMX UCC6, UCC8 clock route register */
+ __be32 cmxupcr; /* CMX UPC clock route register */
+ u8 res0[0x1C];
+} __attribute__ ((packed));
+
+/* QE Timers */
+struct qe_timers {
+ u8 gtcfr1; /* Timer 1 and Timer 2 global config register*/
+ u8 res0[0x3];
+ u8 gtcfr2; /* Timer 3 and timer 4 global config register*/
+ u8 res1[0xB];
+ __be16 gtmdr1; /* Timer 1 mode register */
+ __be16 gtmdr2; /* Timer 2 mode register */
+ __be16 gtrfr1; /* Timer 1 reference register */
+ __be16 gtrfr2; /* Timer 2 reference register */
+ __be16 gtcpr1; /* Timer 1 capture register */
+ __be16 gtcpr2; /* Timer 2 capture register */
+ __be16 gtcnr1; /* Timer 1 counter */
+ __be16 gtcnr2; /* Timer 2 counter */
+ __be16 gtmdr3; /* Timer 3 mode register */
+ __be16 gtmdr4; /* Timer 4 mode register */
+ __be16 gtrfr3; /* Timer 3 reference register */
+ __be16 gtrfr4; /* Timer 4 reference register */
+ __be16 gtcpr3; /* Timer 3 capture register */
+ __be16 gtcpr4; /* Timer 4 capture register */
+ __be16 gtcnr3; /* Timer 3 counter */
+ __be16 gtcnr4; /* Timer 4 counter */
+ __be16 gtevr1; /* Timer 1 event register */
+ __be16 gtevr2; /* Timer 2 event register */
+ __be16 gtevr3; /* Timer 3 event register */
+ __be16 gtevr4; /* Timer 4 event register */
+ __be16 gtps; /* Timer 1 prescale register */
+ u8 res2[0x46];
+} __attribute__ ((packed));
+
+/* BRG */
+struct qe_brg {
+ __be32 brgc1; /* BRG1 configuration register */
+ __be32 brgc2; /* BRG2 configuration register */
+ __be32 brgc3; /* BRG3 configuration register */
+ __be32 brgc4; /* BRG4 configuration register */
+ __be32 brgc5; /* BRG5 configuration register */
+ __be32 brgc6; /* BRG6 configuration register */
+ __be32 brgc7; /* BRG7 configuration register */
+ __be32 brgc8; /* BRG8 configuration register */
+ __be32 brgc9; /* BRG9 configuration register */
+ __be32 brgc10; /* BRG10 configuration register */
+ __be32 brgc11; /* BRG11 configuration register */
+ __be32 brgc12; /* BRG12 configuration register */
+ __be32 brgc13; /* BRG13 configuration register */
+ __be32 brgc14; /* BRG14 configuration register */
+ __be32 brgc15; /* BRG15 configuration register */
+ __be32 brgc16; /* BRG16 configuration register */
+ u8 res0[0x40];
+} __attribute__ ((packed));
+
+/* SPI */
+struct spi {
+ u8 res0[0x20];
+ __be32 spmode; /* SPI mode register */
+ u8 res1[0x2];
+ u8 spie; /* SPI event register */
+ u8 res2[0x1];
+ u8 res3[0x2];
+ u8 spim; /* SPI mask register */
+ u8 res4[0x1];
+ u8 res5[0x1];
+ u8 spcom; /* SPI command register */
+ u8 res6[0x2];
+ __be32 spitd; /* SPI transmit data register (cpu mode) */
+ __be32 spird; /* SPI receive data register (cpu mode) */
+ u8 res7[0x8];
+} __attribute__ ((packed));
+
+/* SI */
+struct si1 {
+ __be16 siamr1; /* SI1 TDMA mode register */
+ __be16 sibmr1; /* SI1 TDMB mode register */
+ __be16 sicmr1; /* SI1 TDMC mode register */
+ __be16 sidmr1; /* SI1 TDMD mode register */
+ u8 siglmr1_h; /* SI1 global mode register high */
+ u8 res0[0x1];
+ u8 sicmdr1_h; /* SI1 command register high */
+ u8 res2[0x1];
+ u8 sistr1_h; /* SI1 status register high */
+ u8 res3[0x1];
+ __be16 sirsr1_h; /* SI1 RAM shadow address register high */
+ u8 sitarc1; /* SI1 RAM counter Tx TDMA */
+ u8 sitbrc1; /* SI1 RAM counter Tx TDMB */
+ u8 sitcrc1; /* SI1 RAM counter Tx TDMC */
+ u8 sitdrc1; /* SI1 RAM counter Tx TDMD */
+ u8 sirarc1; /* SI1 RAM counter Rx TDMA */
+ u8 sirbrc1; /* SI1 RAM counter Rx TDMB */
+ u8 sircrc1; /* SI1 RAM counter Rx TDMC */
+ u8 sirdrc1; /* SI1 RAM counter Rx TDMD */
+ u8 res4[0x8];
+ __be16 siemr1; /* SI1 TDME mode register 16 bits */
+ __be16 sifmr1; /* SI1 TDMF mode register 16 bits */
+ __be16 sigmr1; /* SI1 TDMG mode register 16 bits */
+ __be16 sihmr1; /* SI1 TDMH mode register 16 bits */
+ u8 siglmg1_l; /* SI1 global mode register low 8 bits */
+ u8 res5[0x1];
+ u8 sicmdr1_l; /* SI1 command register low 8 bits */
+ u8 res6[0x1];
+ u8 sistr1_l; /* SI1 status register low 8 bits */
+ u8 res7[0x1];
+ __be16 sirsr1_l; /* SI1 RAM shadow address register low 16 bits*/
+ u8 siterc1; /* SI1 RAM counter Tx TDME 8 bits */
+ u8 sitfrc1; /* SI1 RAM counter Tx TDMF 8 bits */
+ u8 sitgrc1; /* SI1 RAM counter Tx TDMG 8 bits */
+ u8 sithrc1; /* SI1 RAM counter Tx TDMH 8 bits */
+ u8 sirerc1; /* SI1 RAM counter Rx TDME 8 bits */
+ u8 sirfrc1; /* SI1 RAM counter Rx TDMF 8 bits */
+ u8 sirgrc1; /* SI1 RAM counter Rx TDMG 8 bits */
+ u8 sirhrc1; /* SI1 RAM counter Rx TDMH 8 bits */
+ u8 res8[0x8];
+ __be32 siml1; /* SI1 multiframe limit register */
+ u8 siedm1; /* SI1 extended diagnostic mode register */
+ u8 res9[0xBB];
+} __attribute__ ((packed));
+
+/* SI Routing Tables */
+struct sir {
+ u8 tx[0x400];
+ u8 rx[0x400];
+ u8 res0[0x800];
+} __attribute__ ((packed));
+
+/* USB Controller */
+struct usb_ctlr {
+ u8 usb_usmod;
+ u8 usb_usadr;
+ u8 usb_uscom;
+ u8 res1[1];
+ __be16 usb_usep1;
+ __be16 usb_usep2;
+ __be16 usb_usep3;
+ __be16 usb_usep4;
+ u8 res2[4];
+ __be16 usb_usber;
+ u8 res3[2];
+ __be16 usb_usbmr;
+ u8 res4[1];
+ u8 usb_usbs;
+ __be16 usb_ussft;
+ u8 res5[2];
+ __be16 usb_usfrn;
+ u8 res6[0x22];
+} __attribute__ ((packed));
+
+/* MCC */
+struct mcc {
+ __be32 mcce; /* MCC event register */
+ __be32 mccm; /* MCC mask register */
+ __be32 mccf; /* MCC configuration register */
+ __be32 merl; /* MCC emergency request level register */
+ u8 res0[0xF0];
+} __attribute__ ((packed));
+
+/* QE UCC Slow */
+struct ucc_slow {
+ __be32 gumr_l; /* UCCx general mode register (low) */
+ __be32 gumr_h; /* UCCx general mode register (high) */
+ __be16 upsmr; /* UCCx protocol-specific mode register */
+ u8 res0[0x2];
+ __be16 utodr; /* UCCx transmit on demand register */
+ __be16 udsr; /* UCCx data synchronization register */
+ __be16 ucce; /* UCCx event register */
+ u8 res1[0x2];
+ __be16 uccm; /* UCCx mask register */
+ u8 res2[0x1];
+ u8 uccs; /* UCCx status register */
+ u8 res3[0x24];
+ __be16 utpt;
+ u8 guemr; /* UCC general extended mode register */
+ u8 res4[0x200 - 0x091];
+} __attribute__ ((packed));
+
+/* QE UCC Fast */
+struct ucc_fast {
+ __be32 gumr; /* UCCx general mode register */
+ __be32 upsmr; /* UCCx protocol-specific mode register */
+ __be16 utodr; /* UCCx transmit on demand register */
+ u8 res0[0x2];
+ __be16 udsr; /* UCCx data synchronization register */
+ u8 res1[0x2];
+ __be32 ucce; /* UCCx event register */
+ __be32 uccm; /* UCCx mask register */
+ u8 uccs; /* UCCx status register */
+ u8 res2[0x7];
+ __be32 urfb; /* UCC receive FIFO base */
+ __be16 urfs; /* UCC receive FIFO size */
+ u8 res3[0x2];
+ __be16 urfet; /* UCC receive FIFO emergency threshold */
+ __be16 urfset; /* UCC receive FIFO special emergency
+ threshold */
+ __be32 utfb; /* UCC transmit FIFO base */
+ __be16 utfs; /* UCC transmit FIFO size */
+ u8 res4[0x2];
+ __be16 utfet; /* UCC transmit FIFO emergency threshold */
+ u8 res5[0x2];
+ __be16 utftt; /* UCC transmit FIFO transmit threshold */
+ u8 res6[0x2];
+ __be16 utpt; /* UCC transmit polling timer */
+ u8 res7[0x2];
+ __be32 urtry; /* UCC retry counter register */
+ u8 res8[0x4C];
+ u8 guemr; /* UCC general extended mode register */
+ u8 res9[0x100 - 0x091];
+} __attribute__ ((packed));
+
+/* QE UCC */
+struct ucc_common {
+ u8 res1[0x90];
+ u8 guemr;
+ u8 res2[0x200 - 0x091];
+} __attribute__ ((packed));
+
+struct ucc {
+ union {
+ struct ucc_slow slow;
+ struct ucc_fast fast;
+ struct ucc_common common;
+ };
+} __attribute__ ((packed));
+
+/* MultiPHY UTOPIA POS Controllers (UPC) */
+struct upc {
+ __be32 upgcr; /* UTOPIA/POS general configuration register */
+ __be32 uplpa; /* UTOPIA/POS last PHY address */
+ __be32 uphec; /* ATM HEC register */
+ __be32 upuc; /* UTOPIA/POS UCC configuration */
+ __be32 updc1; /* UTOPIA/POS device 1 configuration */
+ __be32 updc2; /* UTOPIA/POS device 2 configuration */
+ __be32 updc3; /* UTOPIA/POS device 3 configuration */
+ __be32 updc4; /* UTOPIA/POS device 4 configuration */
+ __be32 upstpa; /* UTOPIA/POS STPA threshold */
+ u8 res0[0xC];
+ __be32 updrs1_h; /* UTOPIA/POS device 1 rate select */
+ __be32 updrs1_l; /* UTOPIA/POS device 1 rate select */
+ __be32 updrs2_h; /* UTOPIA/POS device 2 rate select */
+ __be32 updrs2_l; /* UTOPIA/POS device 2 rate select */
+ __be32 updrs3_h; /* UTOPIA/POS device 3 rate select */
+ __be32 updrs3_l; /* UTOPIA/POS device 3 rate select */
+ __be32 updrs4_h; /* UTOPIA/POS device 4 rate select */
+ __be32 updrs4_l; /* UTOPIA/POS device 4 rate select */
+ __be32 updrp1; /* UTOPIA/POS device 1 receive priority low */
+ __be32 updrp2; /* UTOPIA/POS device 2 receive priority low */
+ __be32 updrp3; /* UTOPIA/POS device 3 receive priority low */
+ __be32 updrp4; /* UTOPIA/POS device 4 receive priority low */
+ __be32 upde1; /* UTOPIA/POS device 1 event */
+ __be32 upde2; /* UTOPIA/POS device 2 event */
+ __be32 upde3; /* UTOPIA/POS device 3 event */
+ __be32 upde4; /* UTOPIA/POS device 4 event */
+ __be16 uprp1;
+ __be16 uprp2;
+ __be16 uprp3;
+ __be16 uprp4;
+ u8 res1[0x8];
+ __be16 uptirr1_0; /* Device 1 transmit internal rate 0 */
+ __be16 uptirr1_1; /* Device 1 transmit internal rate 1 */
+ __be16 uptirr1_2; /* Device 1 transmit internal rate 2 */
+ __be16 uptirr1_3; /* Device 1 transmit internal rate 3 */
+ __be16 uptirr2_0; /* Device 2 transmit internal rate 0 */
+ __be16 uptirr2_1; /* Device 2 transmit internal rate 1 */
+ __be16 uptirr2_2; /* Device 2 transmit internal rate 2 */
+ __be16 uptirr2_3; /* Device 2 transmit internal rate 3 */
+ __be16 uptirr3_0; /* Device 3 transmit internal rate 0 */
+ __be16 uptirr3_1; /* Device 3 transmit internal rate 1 */
+ __be16 uptirr3_2; /* Device 3 transmit internal rate 2 */
+ __be16 uptirr3_3; /* Device 3 transmit internal rate 3 */
+ __be16 uptirr4_0; /* Device 4 transmit internal rate 0 */
+ __be16 uptirr4_1; /* Device 4 transmit internal rate 1 */
+ __be16 uptirr4_2; /* Device 4 transmit internal rate 2 */
+ __be16 uptirr4_3; /* Device 4 transmit internal rate 3 */
+ __be32 uper1; /* Device 1 port enable register */
+ __be32 uper2; /* Device 2 port enable register */
+ __be32 uper3; /* Device 3 port enable register */
+ __be32 uper4; /* Device 4 port enable register */
+ u8 res2[0x150];
+} __attribute__ ((packed));
+
+/* SDMA */
+struct sdma {
+ __be32 sdsr; /* Serial DMA status register */
+ __be32 sdmr; /* Serial DMA mode register */
+ __be32 sdtr1; /* SDMA system bus threshold register */
+ __be32 sdtr2; /* SDMA secondary bus threshold register */
+ __be32 sdhy1; /* SDMA system bus hysteresis register */
+ __be32 sdhy2; /* SDMA secondary bus hysteresis register */
+ __be32 sdta1; /* SDMA system bus address register */
+ __be32 sdta2; /* SDMA secondary bus address register */
+ __be32 sdtm1; /* SDMA system bus MSNUM register */
+ __be32 sdtm2; /* SDMA secondary bus MSNUM register */
+ u8 res0[0x10];
+ __be32 sdaqr; /* SDMA address bus qualify register */
+ __be32 sdaqmr; /* SDMA address bus qualify mask register */
+ u8 res1[0x4];
+ __be32 sdebcr; /* SDMA CAM entries base register */
+ u8 res2[0x38];
+} __attribute__ ((packed));
+
+/* Debug Space */
+struct dbg {
+ __be32 bpdcr; /* Breakpoint debug command register */
+ __be32 bpdsr; /* Breakpoint debug status register */
+ __be32 bpdmr; /* Breakpoint debug mask register */
+ __be32 bprmrr0; /* Breakpoint request mode risc register 0 */
+ __be32 bprmrr1; /* Breakpoint request mode risc register 1 */
+ u8 res0[0x8];
+ __be32 bprmtr0; /* Breakpoint request mode trb register 0 */
+ __be32 bprmtr1; /* Breakpoint request mode trb register 1 */
+ u8 res1[0x8];
+ __be32 bprmir; /* Breakpoint request mode immediate register */
+ __be32 bprmsr; /* Breakpoint request mode serial register */
+ __be32 bpemr; /* Breakpoint exit mode register */
+ u8 res2[0x48];
+} __attribute__ ((packed));
+
+/* RISC Special Registers (Trap and Breakpoint) */
+struct rsp {
+ u8 fixme[0x100];
+} __attribute__ ((packed));
+
+struct qe_immap {
+ struct qe_iram iram; /* I-RAM */
+ struct qe_ic_regs ic; /* Interrupt Controller */
+ struct cp_qe cp; /* Communications Processor */
+ struct qe_mux qmx; /* QE Multiplexer */
+ struct qe_timers qet; /* QE Timers */
+ struct spi spi[0x2]; /* spi */
+ struct mcc mcc; /* mcc */
+ struct qe_brg brg; /* brg */
+ struct usb_ctlr usb; /* USB */
+ struct si1 si1; /* SI */
+ u8 res11[0x800];
+ struct sir sir; /* SI Routing Tables */
+ struct ucc ucc1; /* ucc1 */
+ struct ucc ucc3; /* ucc3 */
+ struct ucc ucc5; /* ucc5 */
+ struct ucc ucc7; /* ucc7 */
+ u8 res12[0x600];
+ struct upc upc1; /* MultiPHY UTOPIA POS Ctrlr 1*/
+ struct ucc ucc2; /* ucc2 */
+ struct ucc ucc4; /* ucc4 */
+ struct ucc ucc6; /* ucc6 */
+ struct ucc ucc8; /* ucc8 */
+ u8 res13[0x600];
+ struct upc upc2; /* MultiPHY UTOPIA POS Ctrlr 2*/
+ struct sdma sdma; /* SDMA */
+ struct dbg dbg; /* Debug Space */
+ struct rsp rsp[0x2]; /* RISC Special Registers
+ (Trap and Breakpoint) */
+ u8 res14[0x300];
+ u8 res15[0x3A00];
+ u8 res16[0x8000]; /* 0x108000 - 0x110000 */
+ u8 muram[0xC000]; /* 0x110000 - 0x11C000
+ Multi-user RAM */
+ u8 res17[0x24000]; /* 0x11C000 - 0x140000 */
+ u8 res18[0xC0000]; /* 0x140000 - 0x200000 */
+} __attribute__ ((packed));
+
+extern struct qe_immap *qe_immr;
+extern phys_addr_t get_qe_base(void);
+
+static inline unsigned long immrbar_virt_to_phys(volatile void * address)
+{
+ if ( ((u32)address >= (u32)qe_immr) &&
+ ((u32)address < ((u32)qe_immr + QE_IMMAP_SIZE)) )
+ return (unsigned long)(address - (u32)qe_immr +
+ (u32)get_qe_base());
+ return (unsigned long)virt_to_phys(address);
+}
+
+#endif /* __KERNEL__ */
+#endif /* _ASM_POWERPC_IMMAP_QE_H */
diff --git a/include/asm-powerpc/io.h b/include/asm-powerpc/io.h
index 46bae1cf385b..3baff8b0fd5a 100644
--- a/include/asm-powerpc/io.h
+++ b/include/asm-powerpc/io.h
@@ -11,6 +11,7 @@
/* Check of existence of legacy devices */
extern int check_legacy_ioport(unsigned long base_port);
+#define PNPBIOS_BASE 0xf000 /* only relevant for PReP */
#ifndef CONFIG_PPC64
#include <asm-ppc/io.h>
@@ -403,32 +404,6 @@ static inline void __out_be64(volatile unsigned long __iomem *addr, unsigned lon
#include <asm/eeh.h>
-/**
- * check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the mmio address io_addr. This
- * address should have been obtained by ioremap.
- * Returns 1 on a match.
- */
-static inline int check_signature(const volatile void __iomem * io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
/* Nothing to do */
#define dma_cache_inv(_start,_size) do { } while (0)
diff --git a/include/asm-powerpc/ipic.h b/include/asm-powerpc/ipic.h
index 53079ec3a515..9fbb03415860 100644
--- a/include/asm-powerpc/ipic.h
+++ b/include/asm-powerpc/ipic.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/ipic.h
+ * include/asm-powerpc/ipic.h
*
* IPIC external definitions and structure.
*
@@ -79,12 +79,12 @@ extern void ipic_clear_mcp_status(u32 mask);
#ifdef CONFIG_PPC_MERGE
extern void ipic_init(struct device_node *node, unsigned int flags);
-extern unsigned int ipic_get_irq(struct pt_regs *regs);
+extern unsigned int ipic_get_irq(void);
#else
extern void ipic_init(phys_addr_t phys_addr, unsigned int flags,
unsigned int irq_offset,
unsigned char *senses, unsigned int senses_count);
-extern int ipic_get_irq(struct pt_regs *regs);
+extern int ipic_get_irq(void);
#endif
#endif /* __ASM_IPIC_H__ */
diff --git a/include/asm-powerpc/irq.h b/include/asm-powerpc/irq.h
index 4da41efb1319..f960f5346f40 100644
--- a/include/asm-powerpc/irq.h
+++ b/include/asm-powerpc/irq.h
@@ -9,7 +9,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/threads.h>
#include <linux/list.h>
#include <linux/radix-tree.h>
@@ -826,7 +825,7 @@ extern struct thread_info *softirq_ctx[NR_CPUS];
extern void irq_ctx_init(void);
extern void call_do_softirq(struct thread_info *tp);
-extern int call_handle_irq(int irq, void *p1, void *p2,
+extern int call_handle_irq(int irq, void *p1,
struct thread_info *tp, void *func);
#else
#define irq_ctx_init()
diff --git a/include/asm-powerpc/irq_regs.h b/include/asm-powerpc/irq_regs.h
new file mode 100644
index 000000000000..ba94b51a0a70
--- /dev/null
+++ b/include/asm-powerpc/irq_regs.h
@@ -0,0 +1,2 @@
+#include <asm-generic/irq_regs.h>
+
diff --git a/include/asm-powerpc/iseries/hv_lp_event.h b/include/asm-powerpc/iseries/hv_lp_event.h
index 4065a4de4935..6ce2ce1e2690 100644
--- a/include/asm-powerpc/iseries/hv_lp_event.h
+++ b/include/asm-powerpc/iseries/hv_lp_event.h
@@ -50,7 +50,7 @@ struct HvLpEvent {
u64 xCorrelationToken; /* Unique value for source/type x10-x17 */
};
-typedef void (*LpEventHandler)(struct HvLpEvent *, struct pt_regs *);
+typedef void (*LpEventHandler)(struct HvLpEvent *);
/* Register a handler for an event type - returns 0 on success */
extern int HvLpEvent_registerHandler(HvLpEvent_Type eventType,
diff --git a/include/asm-powerpc/iseries/it_lp_queue.h b/include/asm-powerpc/iseries/it_lp_queue.h
index 3f6814769295..428278838821 100644
--- a/include/asm-powerpc/iseries/it_lp_queue.h
+++ b/include/asm-powerpc/iseries/it_lp_queue.h
@@ -72,7 +72,7 @@ struct hvlpevent_queue {
extern struct hvlpevent_queue hvlpevent_queue;
extern int hvlpevent_is_pending(void);
-extern void process_hvlpevents(struct pt_regs *);
+extern void process_hvlpevents(void);
extern void setup_hvlpevent_queue(void);
#endif /* _ASM_POWERPC_ISERIES_IT_LP_QUEUE_H */
diff --git a/include/asm-powerpc/kprobes.h b/include/asm-powerpc/kprobes.h
index 34e1f89a5fa0..2dafa376a63f 100644
--- a/include/asm-powerpc/kprobes.h
+++ b/include/asm-powerpc/kprobes.h
@@ -44,6 +44,28 @@ typedef unsigned int kprobe_opcode_t;
#define IS_TDI(instr) (((instr) & 0xfc000000) == 0x08000000)
#define IS_TWI(instr) (((instr) & 0xfc000000) == 0x0c000000)
+/*
+ * 64bit powerpc uses function descriptors.
+ * Handle cases where:
+ * - User passes a <.symbol> or <module:.symbol>
+ * - User passes a <symbol> or <module:symbol>
+ * - User passes a non-existant symbol, kallsyms_lookup_name
+ * returns 0. Don't deref the NULL pointer in that case
+ */
+#define kprobe_lookup_name(name, addr) \
+{ \
+ addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \
+ if (addr) { \
+ char *colon; \
+ if ((colon = strchr(name, ':')) != NULL) { \
+ colon++; \
+ if (*colon != '\0' && *colon != '.') \
+ addr = *(kprobe_opcode_t **)addr; \
+ } else if (name[0] != '.') \
+ addr = *(kprobe_opcode_t **)addr; \
+ } \
+}
+
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry)
#define is_trap(instr) (IS_TW(instr) || IS_TD(instr) || \
diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h
index c17c13742401..dac90dc341cb 100644
--- a/include/asm-powerpc/machdep.h
+++ b/include/asm-powerpc/machdep.h
@@ -97,7 +97,7 @@ struct machdep_calls {
void (*show_percpuinfo)(struct seq_file *m, int i);
void (*init_IRQ)(void);
- unsigned int (*get_irq)(struct pt_regs *);
+ unsigned int (*get_irq)(void);
#ifdef CONFIG_KEXEC
void (*kexec_cpu_down)(int crash_shutdown, int secondary);
#endif
diff --git a/include/asm-powerpc/mpc85xx.h b/include/asm-powerpc/mpc85xx.h
new file mode 100644
index 000000000000..ccdb8a21138f
--- /dev/null
+++ b/include/asm-powerpc/mpc85xx.h
@@ -0,0 +1,53 @@
+/*
+ * include/asm-powerpc/mpc85xx.h
+ *
+ * MPC85xx definitions
+ *
+ * Maintainer: Kumar Gala <galak@kernel.crashing.org>
+ *
+ * Copyright 2004 Freescale Semiconductor, Inc
+ *
+ * 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.
+ */
+
+#ifdef __KERNEL__
+#ifndef __ASM_MPC85xx_H__
+#define __ASM_MPC85xx_H__
+
+#include <asm/mmu.h>
+
+#ifdef CONFIG_85xx
+
+#if defined(CONFIG_MPC8540_ADS) || defined(CONFIG_MPC8560_ADS)
+#include <platforms/85xx/mpc85xx_ads.h>
+#endif
+#if defined(CONFIG_MPC8555_CDS) || defined(CONFIG_MPC8548_CDS)
+#include <platforms/85xx/mpc8555_cds.h>
+#endif
+#ifdef CONFIG_MPC85xx_CDS
+#include <platforms/85xx/mpc85xx_cds.h>
+#endif
+
+#define _IO_BASE isa_io_base
+#define _ISA_MEM_BASE isa_mem_base
+#ifdef CONFIG_PCI
+#define PCI_DRAM_OFFSET pci_dram_offset
+#else
+#define PCI_DRAM_OFFSET 0
+#endif
+
+/* Let modules/drivers get at CCSRBAR */
+extern phys_addr_t get_ccsrbar(void);
+
+#ifdef MODULE
+#define CCSRBAR get_ccsrbar()
+#else
+#define CCSRBAR BOARD_CCSRBAR
+#endif
+
+#endif /* CONFIG_85xx */
+#endif /* __ASM_MPC85xx_H__ */
+#endif /* __KERNEL__ */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index a9f9604b9eff..ef0a5458d2b2 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -409,9 +409,9 @@ extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask);
void smp_mpic_message_pass(int target, int msg);
/* Fetch interrupt from a given mpic */
-extern unsigned int mpic_get_one_irq(struct mpic *mpic, struct pt_regs *regs);
+extern unsigned int mpic_get_one_irq(struct mpic *mpic);
/* This one gets to the primary mpic */
-extern unsigned int mpic_get_irq(struct pt_regs *regs);
+extern unsigned int mpic_get_irq(void);
/* Set the EPIC clock ratio */
void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio);
diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h
index 4f55573762bb..86ee46b09b8a 100644
--- a/include/asm-powerpc/pci-bridge.h
+++ b/include/asm-powerpc/pci-bridge.h
@@ -6,7 +6,6 @@
#include <asm-ppc/pci-bridge.h>
#else
-#include <linux/config.h>
#include <linux/pci.h>
#include <linux/list.h>
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h
index 4435efe85d0e..4ad77a13f865 100644
--- a/include/asm-powerpc/ptrace.h
+++ b/include/asm-powerpc/ptrace.h
@@ -73,6 +73,8 @@ struct pt_regs {
#ifndef __ASSEMBLY__
#define instruction_pointer(regs) ((regs)->nip)
+#define regs_return_value(regs) ((regs)->gpr[3])
+
#ifdef CONFIG_SMP
extern unsigned long profile_pc(struct pt_regs *regs);
#else
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
new file mode 100644
index 000000000000..a62168ec535f
--- /dev/null
+++ b/include/asm-powerpc/qe.h
@@ -0,0 +1,457 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * QUICC Engine (QE) external definitions and structure.
+ *
+ * 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.
+ */
+#ifndef _ASM_POWERPC_QE_H
+#define _ASM_POWERPC_QE_H
+#ifdef __KERNEL__
+
+#include <asm/immap_qe.h>
+
+#define QE_NUM_OF_SNUM 28
+#define QE_NUM_OF_BRGS 16
+#define QE_NUM_OF_PORTS 1024
+
+/* Memory partitions
+*/
+#define MEM_PART_SYSTEM 0
+#define MEM_PART_SECONDARY 1
+#define MEM_PART_MURAM 2
+
+/* Export QE common operations */
+extern void qe_reset(void);
+extern int par_io_init(struct device_node *np);
+extern int par_io_of_config(struct device_node *np);
+
+/* QE internal API */
+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);
+void qe_muram_dump(void);
+void *qe_muram_addr(u32 offset);
+
+/* Buffer descriptors */
+struct qe_bd {
+ u16 status;
+ u16 length;
+ u32 buf;
+} __attribute__ ((packed));
+
+#define BD_STATUS_MASK 0xffff0000
+#define BD_LENGTH_MASK 0x0000ffff
+
+/* Alignment */
+#define QE_INTR_TABLE_ALIGN 16 /* ??? */
+#define QE_ALIGNMENT_OF_BD 8
+#define QE_ALIGNMENT_OF_PRAM 64
+
+/* RISC allocation */
+enum qe_risc_allocation {
+ QE_RISC_ALLOCATION_RISC1 = 1, /* RISC 1 */
+ QE_RISC_ALLOCATION_RISC2 = 2, /* RISC 2 */
+ QE_RISC_ALLOCATION_RISC1_AND_RISC2 = 3 /* Dynamically choose
+ RISC 1 or RISC 2 */
+};
+
+/* QE extended filtering Table Lookup Key Size */
+enum qe_fltr_tbl_lookup_key_size {
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES
+ = 0x3f, /* LookupKey parsed by the Generate LookupKey
+ CMD is truncated to 8 bytes */
+ QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES
+ = 0x5f, /* LookupKey parsed by the Generate LookupKey
+ CMD is truncated to 16 bytes */
+};
+
+/* QE FLTR extended filtering Largest External Table Lookup Key Size */
+enum qe_fltr_largest_external_tbl_lookup_key_size {
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_NONE
+ = 0x0,/* not used */
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_8_BYTES
+ = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_8_BYTES, /* 8 bytes */
+ QE_FLTR_LARGEST_EXTERNAL_TABLE_LOOKUP_KEY_SIZE_16_BYTES
+ = QE_FLTR_TABLE_LOOKUP_KEY_SIZE_16_BYTES, /* 16 bytes */
+};
+
+/* structure representing QE parameter RAM */
+struct qe_timer_tables {
+ u16 tm_base; /* QE timer table base adr */
+ u16 tm_ptr; /* QE timer table pointer */
+ u16 r_tmr; /* QE timer mode register */
+ u16 r_tmv; /* QE timer valid register */
+ u32 tm_cmd; /* QE timer cmd register */
+ u32 tm_cnt; /* QE timer internal cnt */
+} __attribute__ ((packed));
+
+#define QE_FLTR_TAD_SIZE 8
+
+/* QE extended filtering Termination Action Descriptor (TAD) */
+struct qe_fltr_tad {
+ u8 serialized[QE_FLTR_TAD_SIZE];
+} __attribute__ ((packed));
+
+/* Communication Direction */
+enum comm_dir {
+ COMM_DIR_NONE = 0,
+ COMM_DIR_RX = 1,
+ COMM_DIR_TX = 2,
+ COMM_DIR_RX_AND_TX = 3
+};
+
+/* Clocks and BRGs */
+enum qe_clock {
+ QE_CLK_NONE = 0,
+ QE_BRG1, /* Baud Rate Generator 1 */
+ QE_BRG2, /* Baud Rate Generator 2 */
+ QE_BRG3, /* Baud Rate Generator 3 */
+ QE_BRG4, /* Baud Rate Generator 4 */
+ QE_BRG5, /* Baud Rate Generator 5 */
+ QE_BRG6, /* Baud Rate Generator 6 */
+ QE_BRG7, /* Baud Rate Generator 7 */
+ QE_BRG8, /* Baud Rate Generator 8 */
+ QE_BRG9, /* Baud Rate Generator 9 */
+ QE_BRG10, /* Baud Rate Generator 10 */
+ QE_BRG11, /* Baud Rate Generator 11 */
+ QE_BRG12, /* Baud Rate Generator 12 */
+ QE_BRG13, /* Baud Rate Generator 13 */
+ QE_BRG14, /* Baud Rate Generator 14 */
+ QE_BRG15, /* Baud Rate Generator 15 */
+ QE_BRG16, /* Baud Rate Generator 16 */
+ QE_CLK1, /* Clock 1 */
+ QE_CLK2, /* Clock 2 */
+ QE_CLK3, /* Clock 3 */
+ QE_CLK4, /* Clock 4 */
+ QE_CLK5, /* Clock 5 */
+ QE_CLK6, /* Clock 6 */
+ QE_CLK7, /* Clock 7 */
+ QE_CLK8, /* Clock 8 */
+ QE_CLK9, /* Clock 9 */
+ QE_CLK10, /* Clock 10 */
+ QE_CLK11, /* Clock 11 */
+ QE_CLK12, /* Clock 12 */
+ QE_CLK13, /* Clock 13 */
+ QE_CLK14, /* Clock 14 */
+ QE_CLK15, /* Clock 15 */
+ QE_CLK16, /* Clock 16 */
+ QE_CLK17, /* Clock 17 */
+ QE_CLK18, /* Clock 18 */
+ QE_CLK19, /* Clock 19 */
+ QE_CLK20, /* Clock 20 */
+ QE_CLK21, /* Clock 21 */
+ QE_CLK22, /* Clock 22 */
+ QE_CLK23, /* Clock 23 */
+ QE_CLK24, /* Clock 24 */
+ QE_CLK_DUMMY,
+};
+
+/* QE CMXUCR Registers.
+ * There are two UCCs represented in each of the four CMXUCR registers.
+ * These values are for the UCC in the LSBs
+ */
+#define QE_CMXUCR_MII_ENET_MNG 0x00007000
+#define QE_CMXUCR_MII_ENET_MNG_SHIFT 12
+#define QE_CMXUCR_GRANT 0x00008000
+#define QE_CMXUCR_TSA 0x00004000
+#define QE_CMXUCR_BKPT 0x00000100
+#define QE_CMXUCR_TX_CLK_SRC_MASK 0x0000000F
+
+/* QE CMXGCR Registers.
+*/
+#define QE_CMXGCR_MII_ENET_MNG 0x00007000
+#define QE_CMXGCR_MII_ENET_MNG_SHIFT 12
+#define QE_CMXGCR_USBCS 0x0000000f
+
+/* QE CECR Commands.
+*/
+#define QE_CR_FLG 0x00010000
+#define QE_RESET 0x80000000
+#define QE_INIT_TX_RX 0x00000000
+#define QE_INIT_RX 0x00000001
+#define QE_INIT_TX 0x00000002
+#define QE_ENTER_HUNT_MODE 0x00000003
+#define QE_STOP_TX 0x00000004
+#define QE_GRACEFUL_STOP_TX 0x00000005
+#define QE_RESTART_TX 0x00000006
+#define QE_CLOSE_RX_BD 0x00000007
+#define QE_SWITCH_COMMAND 0x00000007
+#define QE_SET_GROUP_ADDRESS 0x00000008
+#define QE_START_IDMA 0x00000009
+#define QE_MCC_STOP_RX 0x00000009
+#define QE_ATM_TRANSMIT 0x0000000a
+#define QE_HPAC_CLEAR_ALL 0x0000000b
+#define QE_GRACEFUL_STOP_RX 0x0000001a
+#define QE_RESTART_RX 0x0000001b
+#define QE_HPAC_SET_PRIORITY 0x0000010b
+#define QE_HPAC_STOP_TX 0x0000020b
+#define QE_HPAC_STOP_RX 0x0000030b
+#define QE_HPAC_GRACEFUL_STOP_TX 0x0000040b
+#define QE_HPAC_GRACEFUL_STOP_RX 0x0000050b
+#define QE_HPAC_START_TX 0x0000060b
+#define QE_HPAC_START_RX 0x0000070b
+#define QE_USB_STOP_TX 0x0000000a
+#define QE_USB_RESTART_TX 0x0000000b
+#define QE_QMC_STOP_TX 0x0000000c
+#define QE_QMC_STOP_RX 0x0000000d
+#define QE_SS7_SU_FIL_RESET 0x0000000e
+/* jonathbr added from here down for 83xx */
+#define QE_RESET_BCS 0x0000000a
+#define QE_MCC_INIT_TX_RX_16 0x00000003
+#define QE_MCC_STOP_TX 0x00000004
+#define QE_MCC_INIT_TX_1 0x00000005
+#define QE_MCC_INIT_RX_1 0x00000006
+#define QE_MCC_RESET 0x00000007
+#define QE_SET_TIMER 0x00000008
+#define QE_RANDOM_NUMBER 0x0000000c
+#define QE_ATM_MULTI_THREAD_INIT 0x00000011
+#define QE_ASSIGN_PAGE 0x00000012
+#define QE_ADD_REMOVE_HASH_ENTRY 0x00000013
+#define QE_START_FLOW_CONTROL 0x00000014
+#define QE_STOP_FLOW_CONTROL 0x00000015
+#define QE_ASSIGN_PAGE_TO_DEVICE 0x00000016
+
+#define QE_ASSIGN_RISC 0x00000010
+#define QE_CR_MCN_NORMAL_SHIFT 6
+#define QE_CR_MCN_USB_SHIFT 4
+#define QE_CR_MCN_RISC_ASSIGN_SHIFT 8
+#define QE_CR_SNUM_SHIFT 17
+
+/* QE CECR Sub Block - sub block of QE command.
+*/
+#define QE_CR_SUBBLOCK_INVALID 0x00000000
+#define QE_CR_SUBBLOCK_USB 0x03200000
+#define QE_CR_SUBBLOCK_UCCFAST1 0x02000000
+#define QE_CR_SUBBLOCK_UCCFAST2 0x02200000
+#define QE_CR_SUBBLOCK_UCCFAST3 0x02400000
+#define QE_CR_SUBBLOCK_UCCFAST4 0x02600000
+#define QE_CR_SUBBLOCK_UCCFAST5 0x02800000
+#define QE_CR_SUBBLOCK_UCCFAST6 0x02a00000
+#define QE_CR_SUBBLOCK_UCCFAST7 0x02c00000
+#define QE_CR_SUBBLOCK_UCCFAST8 0x02e00000
+#define QE_CR_SUBBLOCK_UCCSLOW1 0x00000000
+#define QE_CR_SUBBLOCK_UCCSLOW2 0x00200000
+#define QE_CR_SUBBLOCK_UCCSLOW3 0x00400000
+#define QE_CR_SUBBLOCK_UCCSLOW4 0x00600000
+#define QE_CR_SUBBLOCK_UCCSLOW5 0x00800000
+#define QE_CR_SUBBLOCK_UCCSLOW6 0x00a00000
+#define QE_CR_SUBBLOCK_UCCSLOW7 0x00c00000
+#define QE_CR_SUBBLOCK_UCCSLOW8 0x00e00000
+#define QE_CR_SUBBLOCK_MCC1 0x03800000
+#define QE_CR_SUBBLOCK_MCC2 0x03a00000
+#define QE_CR_SUBBLOCK_MCC3 0x03000000
+#define QE_CR_SUBBLOCK_IDMA1 0x02800000
+#define QE_CR_SUBBLOCK_IDMA2 0x02a00000
+#define QE_CR_SUBBLOCK_IDMA3 0x02c00000
+#define QE_CR_SUBBLOCK_IDMA4 0x02e00000
+#define QE_CR_SUBBLOCK_HPAC 0x01e00000
+#define QE_CR_SUBBLOCK_SPI1 0x01400000
+#define QE_CR_SUBBLOCK_SPI2 0x01600000
+#define QE_CR_SUBBLOCK_RAND 0x01c00000
+#define QE_CR_SUBBLOCK_TIMER 0x01e00000
+#define QE_CR_SUBBLOCK_GENERAL 0x03c00000
+
+/* QE CECR Protocol - For non-MCC, specifies mode for QE CECR command */
+#define QE_CR_PROTOCOL_UNSPECIFIED 0x00 /* For all other protocols */
+#define QE_CR_PROTOCOL_HDLC_TRANSPARENT 0x00
+#define QE_CR_PROTOCOL_ATM_POS 0x0A
+#define QE_CR_PROTOCOL_ETHERNET 0x0C
+#define QE_CR_PROTOCOL_L2_SWITCH 0x0D
+
+/* BMR byte order */
+#define QE_BMR_BYTE_ORDER_BO_PPC 0x08 /* powerpc little endian */
+#define QE_BMR_BYTE_ORDER_BO_MOT 0x10 /* motorola big endian */
+#define QE_BMR_BYTE_ORDER_BO_MAX 0x18
+
+/* BRG configuration register */
+#define QE_BRGC_ENABLE 0x00010000
+#define QE_BRGC_DIVISOR_SHIFT 1
+#define QE_BRGC_DIVISOR_MAX 0xFFF
+#define QE_BRGC_DIV16 1
+
+/* QE Timers registers */
+#define QE_GTCFR1_PCAS 0x80
+#define QE_GTCFR1_STP2 0x20
+#define QE_GTCFR1_RST2 0x10
+#define QE_GTCFR1_GM2 0x08
+#define QE_GTCFR1_GM1 0x04
+#define QE_GTCFR1_STP1 0x02
+#define QE_GTCFR1_RST1 0x01
+
+/* SDMA registers */
+#define QE_SDSR_BER1 0x02000000
+#define QE_SDSR_BER2 0x01000000
+
+#define QE_SDMR_GLB_1_MSK 0x80000000
+#define QE_SDMR_ADR_SEL 0x20000000
+#define QE_SDMR_BER1_MSK 0x02000000
+#define QE_SDMR_BER2_MSK 0x01000000
+#define QE_SDMR_EB1_MSK 0x00800000
+#define QE_SDMR_ER1_MSK 0x00080000
+#define QE_SDMR_ER2_MSK 0x00040000
+#define QE_SDMR_CEN_MASK 0x0000E000
+#define QE_SDMR_SBER_1 0x00000200
+#define QE_SDMR_SBER_2 0x00000200
+#define QE_SDMR_EB1_PR_MASK 0x000000C0
+#define QE_SDMR_ER1_PR 0x00000008
+
+#define QE_SDMR_CEN_SHIFT 13
+#define QE_SDMR_EB1_PR_SHIFT 6
+
+#define QE_SDTM_MSNUM_SHIFT 24
+
+#define QE_SDEBCR_BA_MASK 0x01FFFFFF
+
+/* UPC */
+#define UPGCR_PROTOCOL 0x80000000 /* protocol ul2 or pl2 */
+#define UPGCR_TMS 0x40000000 /* Transmit master/slave mode */
+#define UPGCR_RMS 0x20000000 /* Receive master/slave mode */
+#define UPGCR_ADDR 0x10000000 /* Master MPHY Addr multiplexing */
+#define UPGCR_DIAG 0x01000000 /* Diagnostic mode */
+
+/* UCC */
+#define UCC_GUEMR_MODE_MASK_RX 0x02
+#define UCC_GUEMR_MODE_MASK_TX 0x01
+#define UCC_GUEMR_MODE_FAST_RX 0x02
+#define UCC_GUEMR_MODE_FAST_TX 0x01
+#define UCC_GUEMR_MODE_SLOW_RX 0x00
+#define UCC_GUEMR_MODE_SLOW_TX 0x00
+#define UCC_GUEMR_SET_RESERVED3 0x10 /* Bit 3 in the guemr is reserved but
+ must be set 1 */
+
+/* structure representing UCC SLOW parameter RAM */
+struct ucc_slow_pram {
+ u16 rbase; /* RX BD base address */
+ u16 tbase; /* TX BD base address */
+ u8 rfcr; /* Rx function code */
+ u8 tfcr; /* Tx function code */
+ u16 mrblr; /* Rx buffer length */
+ u32 rstate; /* Rx internal state */
+ u32 rptr; /* Rx internal data pointer */
+ u16 rbptr; /* rb BD Pointer */
+ u16 rcount; /* Rx internal byte count */
+ u32 rtemp; /* Rx temp */
+ u32 tstate; /* Tx internal state */
+ u32 tptr; /* Tx internal data pointer */
+ u16 tbptr; /* Tx BD pointer */
+ u16 tcount; /* Tx byte count */
+ u32 ttemp; /* Tx temp */
+ u32 rcrc; /* temp receive CRC */
+ u32 tcrc; /* temp transmit CRC */
+} __attribute__ ((packed));
+
+/* General UCC SLOW Mode Register (GUMRH & GUMRL) */
+#define UCC_SLOW_GUMR_H_CRC16 0x00004000
+#define UCC_SLOW_GUMR_H_CRC16CCITT 0x00000000
+#define UCC_SLOW_GUMR_H_CRC32CCITT 0x00008000
+#define UCC_SLOW_GUMR_H_REVD 0x00002000
+#define UCC_SLOW_GUMR_H_TRX 0x00001000
+#define UCC_SLOW_GUMR_H_TTX 0x00000800
+#define UCC_SLOW_GUMR_H_CDP 0x00000400
+#define UCC_SLOW_GUMR_H_CTSP 0x00000200
+#define UCC_SLOW_GUMR_H_CDS 0x00000100
+#define UCC_SLOW_GUMR_H_CTSS 0x00000080
+#define UCC_SLOW_GUMR_H_TFL 0x00000040
+#define UCC_SLOW_GUMR_H_RFW 0x00000020
+#define UCC_SLOW_GUMR_H_TXSY 0x00000010
+#define UCC_SLOW_GUMR_H_4SYNC 0x00000004
+#define UCC_SLOW_GUMR_H_8SYNC 0x00000008
+#define UCC_SLOW_GUMR_H_16SYNC 0x0000000c
+#define UCC_SLOW_GUMR_H_RTSM 0x00000002
+#define UCC_SLOW_GUMR_H_RSYN 0x00000001
+
+#define UCC_SLOW_GUMR_L_TCI 0x10000000
+#define UCC_SLOW_GUMR_L_RINV 0x02000000
+#define UCC_SLOW_GUMR_L_TINV 0x01000000
+#define UCC_SLOW_GUMR_L_TEND 0x00020000
+#define UCC_SLOW_GUMR_L_ENR 0x00000020
+#define UCC_SLOW_GUMR_L_ENT 0x00000010
+
+/* General UCC FAST Mode Register */
+#define UCC_FAST_GUMR_TCI 0x20000000
+#define UCC_FAST_GUMR_TRX 0x10000000
+#define UCC_FAST_GUMR_TTX 0x08000000
+#define UCC_FAST_GUMR_CDP 0x04000000
+#define UCC_FAST_GUMR_CTSP 0x02000000
+#define UCC_FAST_GUMR_CDS 0x01000000
+#define UCC_FAST_GUMR_CTSS 0x00800000
+#define UCC_FAST_GUMR_TXSY 0x00020000
+#define UCC_FAST_GUMR_RSYN 0x00010000
+#define UCC_FAST_GUMR_RTSM 0x00002000
+#define UCC_FAST_GUMR_REVD 0x00000400
+#define UCC_FAST_GUMR_ENR 0x00000020
+#define UCC_FAST_GUMR_ENT 0x00000010
+
+/* Slow UCC Event Register (UCCE) */
+#define UCC_SLOW_UCCE_GLR 0x1000
+#define UCC_SLOW_UCCE_GLT 0x0800
+#define UCC_SLOW_UCCE_DCC 0x0400
+#define UCC_SLOW_UCCE_FLG 0x0200
+#define UCC_SLOW_UCCE_AB 0x0200
+#define UCC_SLOW_UCCE_IDLE 0x0100
+#define UCC_SLOW_UCCE_GRA 0x0080
+#define UCC_SLOW_UCCE_TXE 0x0010
+#define UCC_SLOW_UCCE_RXF 0x0008
+#define UCC_SLOW_UCCE_CCR 0x0008
+#define UCC_SLOW_UCCE_RCH 0x0008
+#define UCC_SLOW_UCCE_BSY 0x0004
+#define UCC_SLOW_UCCE_TXB 0x0002
+#define UCC_SLOW_UCCE_TX 0x0002
+#define UCC_SLOW_UCCE_RX 0x0001
+#define UCC_SLOW_UCCE_GOV 0x0001
+#define UCC_SLOW_UCCE_GUN 0x0002
+#define UCC_SLOW_UCCE_GINT 0x0004
+#define UCC_SLOW_UCCE_IQOV 0x0008
+
+#define UCC_SLOW_UCCE_HDLC_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF | \
+ UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_ENET_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_RXF)
+#define UCC_SLOW_UCCE_TRANS_SET (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \
+ UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_UART_SET (UCC_SLOW_UCCE_BSY | UCC_SLOW_UCCE_GRA | \
+ UCC_SLOW_UCCE_TXB | UCC_SLOW_UCCE_TX | UCC_SLOW_UCCE_RX | \
+ UCC_SLOW_UCCE_GLT | UCC_SLOW_UCCE_GLR)
+#define UCC_SLOW_UCCE_QMC_SET (UCC_SLOW_UCCE_IQOV | UCC_SLOW_UCCE_GINT | \
+ UCC_SLOW_UCCE_GUN | UCC_SLOW_UCCE_GOV)
+
+#define UCC_SLOW_UCCE_OTHER (UCC_SLOW_UCCE_TXE | UCC_SLOW_UCCE_BSY | \
+ UCC_SLOW_UCCE_GRA | UCC_SLOW_UCCE_DCC | UCC_SLOW_UCCE_GLT | \
+ UCC_SLOW_UCCE_GLR)
+
+#define UCC_SLOW_INTR_TX UCC_SLOW_UCCE_TXB
+#define UCC_SLOW_INTR_RX (UCC_SLOW_UCCE_RXF | UCC_SLOW_UCCE_RX)
+#define UCC_SLOW_INTR (UCC_SLOW_INTR_TX | UCC_SLOW_INTR_RX)
+
+/* UCC Transmit On Demand Register (UTODR) */
+#define UCC_SLOW_TOD 0x8000
+#define UCC_FAST_TOD 0x8000
+
+/* Function code masks */
+#define FC_GBL 0x20
+#define FC_DTB_LCL 0x02
+#define UCC_FAST_FUNCTION_CODE_GBL 0x20
+#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/qe_ic.h b/include/asm-powerpc/qe_ic.h
new file mode 100644
index 000000000000..e386fb7e44b0
--- /dev/null
+++ b/include/asm-powerpc/qe_ic.h
@@ -0,0 +1,64 @@
+/*
+ * include/asm-powerpc/qe_ic.h
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * QE IC external definitions and structure.
+ *
+ * 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.
+ */
+#ifndef _ASM_POWERPC_QE_IC_H
+#define _ASM_POWERPC_QE_IC_H
+
+#include <linux/irq.h>
+
+#define NUM_OF_QE_IC_GROUPS 6
+
+/* Flags when we init the QE IC */
+#define QE_IC_SPREADMODE_GRP_W 0x00000001
+#define QE_IC_SPREADMODE_GRP_X 0x00000002
+#define QE_IC_SPREADMODE_GRP_Y 0x00000004
+#define QE_IC_SPREADMODE_GRP_Z 0x00000008
+#define QE_IC_SPREADMODE_GRP_RISCA 0x00000010
+#define QE_IC_SPREADMODE_GRP_RISCB 0x00000020
+
+#define QE_IC_LOW_SIGNAL 0x00000100
+#define QE_IC_HIGH_SIGNAL 0x00000200
+
+#define QE_IC_GRP_W_PRI0_DEST_SIGNAL_HIGH 0x00001000
+#define QE_IC_GRP_W_PRI1_DEST_SIGNAL_HIGH 0x00002000
+#define QE_IC_GRP_X_PRI0_DEST_SIGNAL_HIGH 0x00004000
+#define QE_IC_GRP_X_PRI1_DEST_SIGNAL_HIGH 0x00008000
+#define QE_IC_GRP_Y_PRI0_DEST_SIGNAL_HIGH 0x00010000
+#define QE_IC_GRP_Y_PRI1_DEST_SIGNAL_HIGH 0x00020000
+#define QE_IC_GRP_Z_PRI0_DEST_SIGNAL_HIGH 0x00040000
+#define QE_IC_GRP_Z_PRI1_DEST_SIGNAL_HIGH 0x00080000
+#define QE_IC_GRP_RISCA_PRI0_DEST_SIGNAL_HIGH 0x00100000
+#define QE_IC_GRP_RISCA_PRI1_DEST_SIGNAL_HIGH 0x00200000
+#define QE_IC_GRP_RISCB_PRI0_DEST_SIGNAL_HIGH 0x00400000
+#define QE_IC_GRP_RISCB_PRI1_DEST_SIGNAL_HIGH 0x00800000
+#define QE_IC_GRP_W_DEST_SIGNAL_SHIFT (12)
+
+/* QE interrupt sources groups */
+enum qe_ic_grp_id {
+ QE_IC_GRP_W = 0, /* QE interrupt controller group W */
+ QE_IC_GRP_X, /* QE interrupt controller group X */
+ QE_IC_GRP_Y, /* QE interrupt controller group Y */
+ QE_IC_GRP_Z, /* QE interrupt controller group Z */
+ QE_IC_GRP_RISCA, /* QE interrupt controller RISC group A */
+ QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */
+};
+
+void qe_ic_init(struct device_node *node, unsigned int flags);
+void qe_ic_set_highest_priority(unsigned int virq, int high);
+int qe_ic_set_priority(unsigned int virq, unsigned int priority);
+int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
+
+#endif /* _ASM_POWERPC_QE_IC_H */
diff --git a/include/asm-powerpc/reg.h b/include/asm-powerpc/reg.h
index 3a9fcc15811b..8fb96811b55d 100644
--- a/include/asm-powerpc/reg.h
+++ b/include/asm-powerpc/reg.h
@@ -503,7 +503,7 @@
/*
* An mtfsf instruction with the L bit set. On CPUs that support this a
- * full 64bits of FPSCR is restored and on other CPUs it is ignored.
+ * full 64bits of FPSCR is restored and on other CPUs the L bit is ignored.
*
* Until binutils gets the new form of mtfsf, hardwire the instruction.
*/
diff --git a/include/asm-powerpc/smp.h b/include/asm-powerpc/smp.h
index 068f119aa298..20ea7c70bc38 100644
--- a/include/asm-powerpc/smp.h
+++ b/include/asm-powerpc/smp.h
@@ -34,8 +34,7 @@ extern void cpu_die(void);
#ifdef CONFIG_SMP
extern void smp_send_debugger_break(int cpu);
-struct pt_regs;
-extern void smp_message_recv(int, struct pt_regs *);
+extern void smp_message_recv(int);
#ifdef CONFIG_HOTPLUG_CPU
extern void fixup_irqs(cpumask_t map);
diff --git a/include/asm-powerpc/spinlock.h b/include/asm-powerpc/spinlock.h
index c31e4382a775..cc4cfceac67c 100644
--- a/include/asm-powerpc/spinlock.h
+++ b/include/asm-powerpc/spinlock.h
@@ -285,5 +285,9 @@ static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
rw->lock = 0;
}
+#define _raw_spin_relax(lock) __spin_yield(lock)
+#define _raw_read_relax(lock) __rw_yield(lock)
+#define _raw_write_relax(lock) __rw_yield(lock)
+
#endif /* __KERNEL__ */
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-powerpc/spu.h b/include/asm-powerpc/spu.h
index b42b53c40f5d..e73ea00efd8b 100644
--- a/include/asm-powerpc/spu.h
+++ b/include/asm-powerpc/spu.h
@@ -138,6 +138,7 @@ struct spu {
void (* ibox_callback)(struct spu *spu);
void (* stop_callback)(struct spu *spu);
void (* mfc_callback)(struct spu *spu);
+ void (* dma_callback)(struct spu *spu, int type);
char irq_c0[8];
char irq_c1[8];
@@ -147,6 +148,7 @@ struct spu {
};
struct spu *spu_alloc(void);
+struct spu *spu_alloc_node(int node);
void spu_free(struct spu *spu);
int spu_irq_class_0_bottom(struct spu *spu);
int spu_irq_class_1_bottom(struct spu *spu);
@@ -168,6 +170,22 @@ extern struct spufs_calls {
struct module *owner;
} spufs_calls;
+/* return status from spu_run, same as in libspe */
+#define SPE_EVENT_DMA_ALIGNMENT 0x0008 /*A DMA alignment error */
+#define SPE_EVENT_SPE_ERROR 0x0010 /*An illegal instruction error*/
+#define SPE_EVENT_SPE_DATA_SEGMENT 0x0020 /*A DMA segmentation error */
+#define SPE_EVENT_SPE_DATA_STORAGE 0x0040 /*A DMA storage error */
+#define SPE_EVENT_INVALID_DMA 0x0800 /* Invalid MFC DMA */
+
+/*
+ * Flags for sys_spu_create.
+ */
+#define SPU_CREATE_EVENTS_ENABLED 0x0001
+#define SPU_CREATE_GANG 0x0002
+
+#define SPU_CREATE_FLAG_ALL 0x0003 /* mask of all valid flags */
+
+
#ifdef CONFIG_SPU_FS_MODULE
int register_spu_syscalls(struct spufs_calls *calls);
void unregister_spu_syscalls(struct spufs_calls *calls);
@@ -183,6 +201,24 @@ static inline void unregister_spu_syscalls(struct spufs_calls *calls)
/*
+ * Notifier blocks:
+ *
+ * oprofile can get notified when a context switch is performed
+ * on an spe. The notifer function that gets called is passed
+ * a pointer to the SPU structure as well as the object-id that
+ * identifies the binary running on that SPU now.
+ *
+ * For a context save, the object-id that is passed is zero,
+ * identifying that the kernel will run from that moment on.
+ *
+ * For a context restore, the object-id is the value written
+ * to object-id spufs file from user space and the notifer
+ * function can assume that spu->ctx is valid.
+ */
+int spu_switch_event_register(struct notifier_block * n);
+int spu_switch_event_unregister(struct notifier_block * n);
+
+/*
* This defines the Local Store, Problem Area and Privlege Area of an SPU.
*/
diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 4b41deaa8d8d..43627596003b 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -91,10 +91,6 @@ DEBUGGER_BOILERPLATE(debugger_iabr_match)
DEBUGGER_BOILERPLATE(debugger_dabr_match)
DEBUGGER_BOILERPLATE(debugger_fault_handler)
-#ifdef CONFIG_XMON
-extern void xmon_init(int enable);
-#endif
-
#else
static inline int debugger(struct pt_regs *regs) { return 0; }
static inline int debugger_ipi(struct pt_regs *regs) { return 0; }
diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h
index 5785ac4737b5..b051d4c88c3b 100644
--- a/include/asm-powerpc/time.h
+++ b/include/asm-powerpc/time.h
@@ -39,6 +39,10 @@ extern void generic_calibrate_decr(void);
extern void wakeup_decrementer(void);
extern void snapshot_timebase(void);
+#ifdef CONFIG_RTC_CLASS
+extern int __init rtc_class_hookup(void);
+#endif
+
/* Some sane defaults: 125 MHz timebase, 1GHz processor */
extern unsigned long ppc_proc_freq;
#define DEFAULT_PROC_FREQ (DEFAULT_TB_FREQ * 8)
@@ -234,4 +238,4 @@ extern void snapshot_timebases(void);
#endif
#endif /* __KERNEL__ */
-#endif /* __PPC64_TIME_H */
+#endif /* __POWERPC_TIME_H */
diff --git a/include/asm-powerpc/topology.h b/include/asm-powerpc/topology.h
index bbc3844b086f..8f7ee16781a4 100644
--- a/include/asm-powerpc/topology.h
+++ b/include/asm-powerpc/topology.h
@@ -43,6 +43,7 @@ extern int pcibus_to_node(struct pci_bus *bus);
#define SD_NODE_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 8, \
.max_interval = 32, \
diff --git a/include/asm-powerpc/ucc.h b/include/asm-powerpc/ucc.h
new file mode 100644
index 000000000000..afe3076bdc03
--- /dev/null
+++ b/include/asm-powerpc/ucc.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * Internal header file for UCC unit routines.
+ *
+ * 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.
+ */
+#ifndef __UCC_H__
+#define __UCC_H__
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#define STATISTICS
+
+#define UCC_MAX_NUM 8
+
+/* Slow or fast type for UCCs.
+*/
+enum ucc_speed_type {
+ UCC_SPEED_TYPE_FAST, UCC_SPEED_TYPE_SLOW
+};
+
+/* Initial UCCs Parameter RAM address relative to: MEM_MAP_BASE (IMMR).
+*/
+enum ucc_pram_initial_offset {
+ UCC_PRAM_OFFSET_UCC1 = 0x8400,
+ UCC_PRAM_OFFSET_UCC2 = 0x8500,
+ UCC_PRAM_OFFSET_UCC3 = 0x8600,
+ UCC_PRAM_OFFSET_UCC4 = 0x9000,
+ UCC_PRAM_OFFSET_UCC5 = 0x8000,
+ UCC_PRAM_OFFSET_UCC6 = 0x8100,
+ UCC_PRAM_OFFSET_UCC7 = 0x8200,
+ UCC_PRAM_OFFSET_UCC8 = 0x8300
+};
+
+/* ucc_set_type
+ * Sets UCC to slow or fast mode.
+ *
+ * ucc_num - (In) number of UCC (0-7).
+ * regs - (In) pointer to registers base for the UCC.
+ * speed - (In) slow or fast mode for UCC.
+ */
+int ucc_set_type(int ucc_num, struct ucc_common *regs,
+ enum ucc_speed_type speed);
+
+/* ucc_init_guemr
+ * Init the Guemr register.
+ *
+ * regs - (In) pointer to registers base for the UCC.
+ */
+int ucc_init_guemr(struct ucc_common *regs);
+
+int ucc_set_qe_mux_mii_mng(int ucc_num);
+
+int ucc_set_qe_mux_rxtx(int ucc_num, enum qe_clock clock, enum comm_dir mode);
+
+int ucc_mux_set_grant_tsa_bkpt(int ucc_num, int set, u32 mask);
+
+/* QE MUX clock routing for UCC
+*/
+static inline int ucc_set_qe_mux_grant(int ucc_num, int set)
+{
+ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_GRANT);
+}
+
+static inline int ucc_set_qe_mux_tsa(int ucc_num, int set)
+{
+ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_TSA);
+}
+
+static inline int ucc_set_qe_mux_bkpt(int ucc_num, int set)
+{
+ return ucc_mux_set_grant_tsa_bkpt(ucc_num, set, QE_CMXUCR_BKPT);
+}
+
+#endif /* __UCC_H__ */
diff --git a/include/asm-powerpc/ucc_fast.h b/include/asm-powerpc/ucc_fast.h
new file mode 100644
index 000000000000..39d1c90fd2ca
--- /dev/null
+++ b/include/asm-powerpc/ucc_fast.h
@@ -0,0 +1,243 @@
+/*
+ * include/asm-powerpc/ucc_fast.h
+ *
+ * Internal header file for UCC FAST unit routines.
+ *
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.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.
+ */
+#ifndef __UCC_FAST_H__
+#define __UCC_FAST_H__
+
+#include <linux/kernel.h>
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include "ucc.h"
+
+/* Receive BD's status */
+#define R_E 0x80000000 /* buffer empty */
+#define R_W 0x20000000 /* wrap bit */
+#define R_I 0x10000000 /* interrupt on reception */
+#define R_L 0x08000000 /* last */
+#define R_F 0x04000000 /* first */
+
+/* transmit BD's status */
+#define T_R 0x80000000 /* ready bit */
+#define T_W 0x20000000 /* wrap bit */
+#define T_I 0x10000000 /* interrupt on completion */
+#define T_L 0x08000000 /* last */
+
+/* Rx Data buffer must be 4 bytes aligned in most cases */
+#define UCC_FAST_RX_ALIGN 4
+#define UCC_FAST_MRBLR_ALIGNMENT 4
+#define UCC_FAST_VIRT_FIFO_REGS_ALIGNMENT 8
+
+/* Sizes */
+#define UCC_FAST_URFS_MIN_VAL 0x88
+#define UCC_FAST_RECEIVE_VIRTUAL_FIFO_SIZE_FUDGE_FACTOR 8
+
+/* ucc_fast_channel_protocol_mode - UCC FAST mode */
+enum ucc_fast_channel_protocol_mode {
+ UCC_FAST_PROTOCOL_MODE_HDLC = 0x00000000,
+ UCC_FAST_PROTOCOL_MODE_RESERVED01 = 0x00000001,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_QMC = 0x00000002,
+ UCC_FAST_PROTOCOL_MODE_RESERVED02 = 0x00000003,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_UART = 0x00000004,
+ UCC_FAST_PROTOCOL_MODE_RESERVED03 = 0x00000005,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_1 = 0x00000006,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_EX_MAC_2 = 0x00000007,
+ UCC_FAST_PROTOCOL_MODE_RESERVED_BISYNC = 0x00000008,
+ UCC_FAST_PROTOCOL_MODE_RESERVED04 = 0x00000009,
+ UCC_FAST_PROTOCOL_MODE_ATM = 0x0000000A,
+ UCC_FAST_PROTOCOL_MODE_RESERVED05 = 0x0000000B,
+ UCC_FAST_PROTOCOL_MODE_ETHERNET = 0x0000000C,
+ UCC_FAST_PROTOCOL_MODE_RESERVED06 = 0x0000000D,
+ UCC_FAST_PROTOCOL_MODE_POS = 0x0000000E,
+ UCC_FAST_PROTOCOL_MODE_RESERVED07 = 0x0000000F
+};
+
+/* ucc_fast_transparent_txrx - UCC Fast Transparent TX & RX */
+enum ucc_fast_transparent_txrx {
+ UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL = 0x00000000,
+ UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_TRANSPARENT = 0x18000000
+};
+
+/* UCC fast diagnostic mode */
+enum ucc_fast_diag_mode {
+ UCC_FAST_DIAGNOSTIC_NORMAL = 0x0,
+ UCC_FAST_DIAGNOSTIC_LOCAL_LOOP_BACK = 0x40000000,
+ UCC_FAST_DIAGNOSTIC_AUTO_ECHO = 0x80000000,
+ UCC_FAST_DIAGNOSTIC_LOOP_BACK_AND_ECHO = 0xC0000000
+};
+
+/* UCC fast Sync length (transparent mode only) */
+enum ucc_fast_sync_len {
+ UCC_FAST_SYNC_LEN_NOT_USED = 0x0,
+ UCC_FAST_SYNC_LEN_AUTOMATIC = 0x00004000,
+ UCC_FAST_SYNC_LEN_8_BIT = 0x00008000,
+ UCC_FAST_SYNC_LEN_16_BIT = 0x0000C000
+};
+
+/* UCC fast RTS mode */
+enum ucc_fast_ready_to_send {
+ UCC_FAST_SEND_IDLES_BETWEEN_FRAMES = 0x00000000,
+ UCC_FAST_SEND_FLAGS_BETWEEN_FRAMES = 0x00002000
+};
+
+/* UCC fast receiver decoding mode */
+enum ucc_fast_rx_decoding_method {
+ UCC_FAST_RX_ENCODING_NRZ = 0x00000000,
+ UCC_FAST_RX_ENCODING_NRZI = 0x00000800,
+ UCC_FAST_RX_ENCODING_RESERVED0 = 0x00001000,
+ UCC_FAST_RX_ENCODING_RESERVED1 = 0x00001800
+};
+
+/* UCC fast transmitter encoding mode */
+enum ucc_fast_tx_encoding_method {
+ UCC_FAST_TX_ENCODING_NRZ = 0x00000000,
+ UCC_FAST_TX_ENCODING_NRZI = 0x00000100,
+ UCC_FAST_TX_ENCODING_RESERVED0 = 0x00000200,
+ UCC_FAST_TX_ENCODING_RESERVED1 = 0x00000300
+};
+
+/* UCC fast CRC length */
+enum ucc_fast_transparent_tcrc {
+ UCC_FAST_16_BIT_CRC = 0x00000000,
+ UCC_FAST_CRC_RESERVED0 = 0x00000040,
+ UCC_FAST_32_BIT_CRC = 0x00000080,
+ UCC_FAST_CRC_RESERVED1 = 0x000000C0
+};
+
+/* Fast UCC initialization structure */
+struct ucc_fast_info {
+ int ucc_num;
+ enum qe_clock rx_clock;
+ enum qe_clock tx_clock;
+ u32 regs;
+ int irq;
+ u32 uccm_mask;
+ int bd_mem_part;
+ int brkpt_support;
+ int grant_support;
+ int tsa;
+ int cdp;
+ int cds;
+ int ctsp;
+ int ctss;
+ int tci;
+ int txsy;
+ int rtsm;
+ int revd;
+ int rsyn;
+ u16 max_rx_buf_length;
+ u16 urfs;
+ u16 urfet;
+ u16 urfset;
+ u16 utfs;
+ u16 utfet;
+ u16 utftt;
+ u16 ufpt;
+ enum ucc_fast_channel_protocol_mode mode;
+ enum ucc_fast_transparent_txrx ttx_trx;
+ enum ucc_fast_tx_encoding_method tenc;
+ enum ucc_fast_rx_decoding_method renc;
+ enum ucc_fast_transparent_tcrc tcrc;
+ enum ucc_fast_sync_len synl;
+};
+
+struct ucc_fast_private {
+ struct ucc_fast_info *uf_info;
+ struct ucc_fast *uf_regs; /* a pointer to memory map of UCC regs. */
+ u32 *p_ucce; /* a pointer to the event register in memory. */
+ u32 *p_uccm; /* a pointer to the mask register in memory. */
+ int enabled_tx; /* Whether channel is enabled for Tx (ENT) */
+ int enabled_rx; /* Whether channel is enabled for Rx (ENR) */
+ int stopped_tx; /* Whether channel has been stopped for Tx
+ (STOP_TX, etc.) */
+ int stopped_rx; /* Whether channel has been stopped for Rx */
+ u32 ucc_fast_tx_virtual_fifo_base_offset;/* pointer to base of Tx
+ virtual fifo */
+ u32 ucc_fast_rx_virtual_fifo_base_offset;/* pointer to base of Rx
+ virtual fifo */
+#ifdef STATISTICS
+ u32 tx_frames; /* Transmitted frames counter. */
+ u32 rx_frames; /* Received frames counter (only frames
+ passed to application). */
+ u32 tx_discarded; /* Discarded tx frames counter (frames that
+ were discarded by the driver due to errors).
+ */
+ u32 rx_discarded; /* Discarded rx frames counter (frames that
+ were discarded by the driver due to errors).
+ */
+#endif /* STATISTICS */
+ u16 mrblr; /* maximum receive buffer length */
+};
+
+/* ucc_fast_init
+ * Initializes Fast UCC according to user provided parameters.
+ *
+ * uf_info - (In) pointer to the fast UCC info structure.
+ * uccf_ret - (Out) pointer to the fast UCC structure.
+ */
+int ucc_fast_init(struct ucc_fast_info * uf_info, struct ucc_fast_private ** uccf_ret);
+
+/* ucc_fast_free
+ * Frees all resources for fast UCC.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_free(struct ucc_fast_private * uccf);
+
+/* ucc_fast_enable
+ * Enables a fast UCC port.
+ * This routine enables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_fast_enable(struct ucc_fast_private * uccf, enum comm_dir mode);
+
+/* ucc_fast_disable
+ * Disables a fast UCC port.
+ * This routine disables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_fast_disable(struct ucc_fast_private * uccf, enum comm_dir mode);
+
+/* ucc_fast_irq
+ * Handles interrupts on fast UCC.
+ * Called from the general interrupt routine to handle interrupts on fast UCC.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_irq(struct ucc_fast_private * uccf);
+
+/* ucc_fast_transmit_on_demand
+ * Immediately forces a poll of the transmitter for data to be sent.
+ * Typically, the hardware performs a periodic poll for data that the
+ * transmit routine has set up to be transmitted. In cases where
+ * this polling cycle is not soon enough, this optional routine can
+ * be invoked to force a poll right away, instead. Proper use for
+ * each transmission for which this functionality is desired is to
+ * call the transmit routine and then this routine right after.
+ *
+ * uccf - (In) pointer to the fast UCC structure.
+ */
+void ucc_fast_transmit_on_demand(struct ucc_fast_private * uccf);
+
+u32 ucc_fast_get_qe_cr_subblock(int uccf_num);
+
+void ucc_fast_dump_regs(struct ucc_fast_private * uccf);
+
+#endif /* __UCC_FAST_H__ */
diff --git a/include/asm-powerpc/ucc_slow.h b/include/asm-powerpc/ucc_slow.h
new file mode 100644
index 000000000000..ca93bc99237e
--- /dev/null
+++ b/include/asm-powerpc/ucc_slow.h
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2006 Freescale Semicondutor, Inc. All rights reserved.
+ *
+ * Authors: Shlomi Gridish <gridish@freescale.com>
+ * Li Yang <leoli@freescale.com>
+ *
+ * Description:
+ * Internal header file for UCC SLOW unit routines.
+ *
+ * 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.
+ */
+#ifndef __UCC_SLOW_H__
+#define __UCC_SLOW_H__
+
+#include <linux/kernel.h>
+
+#include <asm/immap_qe.h>
+#include <asm/qe.h>
+
+#include "ucc.h"
+
+/* transmit BD's status */
+#define T_R 0x80000000 /* ready bit */
+#define T_PAD 0x40000000 /* add pads to short frames */
+#define T_W 0x20000000 /* wrap bit */
+#define T_I 0x10000000 /* interrupt on completion */
+#define T_L 0x08000000 /* last */
+
+#define T_A 0x04000000 /* Address - the data transmitted as address
+ chars */
+#define T_TC 0x04000000 /* transmit CRC */
+#define T_CM 0x02000000 /* continuous mode */
+#define T_DEF 0x02000000 /* collision on previous attempt to transmit */
+#define T_P 0x01000000 /* Preamble - send Preamble sequence before
+ data */
+#define T_HB 0x01000000 /* heartbeat */
+#define T_NS 0x00800000 /* No Stop */
+#define T_LC 0x00800000 /* late collision */
+#define T_RL 0x00400000 /* retransmission limit */
+#define T_UN 0x00020000 /* underrun */
+#define T_CT 0x00010000 /* CTS lost */
+#define T_CSL 0x00010000 /* carrier sense lost */
+#define T_RC 0x003c0000 /* retry count */
+
+/* Receive BD's status */
+#define R_E 0x80000000 /* buffer empty */
+#define R_W 0x20000000 /* wrap bit */
+#define R_I 0x10000000 /* interrupt on reception */
+#define R_L 0x08000000 /* last */
+#define R_C 0x08000000 /* the last byte in this buffer is a cntl
+ char */
+#define R_F 0x04000000 /* first */
+#define R_A 0x04000000 /* the first byte in this buffer is address
+ byte */
+#define R_CM 0x02000000 /* continuous mode */
+#define R_ID 0x01000000 /* buffer close on reception of idles */
+#define R_M 0x01000000 /* Frame received because of promiscuous
+ mode */
+#define R_AM 0x00800000 /* Address match */
+#define R_DE 0x00800000 /* Address match */
+#define R_LG 0x00200000 /* Break received */
+#define R_BR 0x00200000 /* Frame length violation */
+#define R_NO 0x00100000 /* Rx Non Octet Aligned Packet */
+#define R_FR 0x00100000 /* Framing Error (no stop bit) character
+ received */
+#define R_PR 0x00080000 /* Parity Error character received */
+#define R_AB 0x00080000 /* Frame Aborted */
+#define R_SH 0x00080000 /* frame is too short */
+#define R_CR 0x00040000 /* CRC Error */
+#define R_OV 0x00020000 /* Overrun */
+#define R_CD 0x00010000 /* CD lost */
+#define R_CL 0x00010000 /* this frame is closed because of a
+ collision */
+
+/* Rx Data buffer must be 4 bytes aligned in most cases.*/
+#define UCC_SLOW_RX_ALIGN 4
+#define UCC_SLOW_MRBLR_ALIGNMENT 4
+#define UCC_SLOW_PRAM_SIZE 0x100
+#define ALIGNMENT_OF_UCC_SLOW_PRAM 64
+
+/* UCC Slow Channel Protocol Mode */
+enum ucc_slow_channel_protocol_mode {
+ UCC_SLOW_CHANNEL_PROTOCOL_MODE_QMC = 0x00000002,
+ UCC_SLOW_CHANNEL_PROTOCOL_MODE_UART = 0x00000004,
+ UCC_SLOW_CHANNEL_PROTOCOL_MODE_BISYNC = 0x00000008,
+};
+
+/* UCC Slow Transparent Transmit CRC (TCRC) */
+enum ucc_slow_transparent_tcrc {
+ /* 16-bit CCITT CRC (HDLC). (X16 + X12 + X5 + 1) */
+ UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC16 = 0x00000000,
+ /* CRC16 (BISYNC). (X16 + X15 + X2 + 1) */
+ UCC_SLOW_TRANSPARENT_TCRC_CRC16 = 0x00004000,
+ /* 32-bit CCITT CRC (Ethernet and HDLC) */
+ UCC_SLOW_TRANSPARENT_TCRC_CCITT_CRC32 = 0x00008000,
+};
+
+/* UCC Slow oversampling rate for transmitter (TDCR) */
+enum ucc_slow_tx_oversampling_rate {
+ /* 1x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_1 = 0x00000000,
+ /* 8x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_8 = 0x00010000,
+ /* 16x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_16 = 0x00020000,
+ /* 32x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_TX_TDCR_32 = 0x00030000,
+};
+
+/* UCC Slow Oversampling rate for receiver (RDCR)
+*/
+enum ucc_slow_rx_oversampling_rate {
+ /* 1x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_1 = 0x00000000,
+ /* 8x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_8 = 0x00004000,
+ /* 16x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_16 = 0x00008000,
+ /* 32x clock mode */
+ UCC_SLOW_OVERSAMPLING_RATE_RX_RDCR_32 = 0x0000c000,
+};
+
+/* UCC Slow Transmitter encoding method (TENC)
+*/
+enum ucc_slow_tx_encoding_method {
+ UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZ = 0x00000000,
+ UCC_SLOW_TRANSMITTER_ENCODING_METHOD_TENC_NRZI = 0x00000100
+};
+
+/* UCC Slow Receiver decoding method (RENC)
+*/
+enum ucc_slow_rx_decoding_method {
+ UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZ = 0x00000000,
+ UCC_SLOW_RECEIVER_DECODING_METHOD_RENC_NRZI = 0x00000800
+};
+
+/* UCC Slow Diagnostic mode (DIAG)
+*/
+enum ucc_slow_diag_mode {
+ UCC_SLOW_DIAG_MODE_NORMAL = 0x00000000,
+ UCC_SLOW_DIAG_MODE_LOOPBACK = 0x00000040,
+ UCC_SLOW_DIAG_MODE_ECHO = 0x00000080,
+ UCC_SLOW_DIAG_MODE_LOOPBACK_ECHO = 0x000000c0
+};
+
+struct ucc_slow_info {
+ int ucc_num;
+ enum qe_clock rx_clock;
+ enum qe_clock tx_clock;
+ struct ucc_slow *us_regs;
+ int irq;
+ u16 uccm_mask;
+ int data_mem_part;
+ int init_tx;
+ int init_rx;
+ u32 tx_bd_ring_len;
+ u32 rx_bd_ring_len;
+ int rx_interrupts;
+ int brkpt_support;
+ int grant_support;
+ int tsa;
+ int cdp;
+ int cds;
+ int ctsp;
+ int ctss;
+ int rinv;
+ int tinv;
+ int rtsm;
+ int rfw;
+ int tci;
+ int tend;
+ int tfl;
+ int txsy;
+ u16 max_rx_buf_length;
+ enum ucc_slow_transparent_tcrc tcrc;
+ enum ucc_slow_channel_protocol_mode mode;
+ enum ucc_slow_diag_mode diag;
+ enum ucc_slow_tx_oversampling_rate tdcr;
+ enum ucc_slow_rx_oversampling_rate rdcr;
+ enum ucc_slow_tx_encoding_method tenc;
+ enum ucc_slow_rx_decoding_method renc;
+};
+
+struct ucc_slow_private {
+ struct ucc_slow_info *us_info;
+ struct ucc_slow *us_regs; /* a pointer to memory map of UCC regs */
+ struct ucc_slow_pram *us_pram; /* a pointer to the parameter RAM */
+ u32 us_pram_offset;
+ int enabled_tx; /* Whether channel is enabled for Tx (ENT) */
+ int enabled_rx; /* Whether channel is enabled for Rx (ENR) */
+ int stopped_tx; /* Whether channel has been stopped for Tx
+ (STOP_TX, etc.) */
+ int stopped_rx; /* Whether channel has been stopped for Rx */
+ struct list_head confQ; /* frames passed to chip waiting for tx */
+ u32 first_tx_bd_mask; /* mask is used in Tx routine to save status
+ and length for first BD in a frame */
+ u32 tx_base_offset; /* first BD in Tx BD table offset (In MURAM) */
+ u32 rx_base_offset; /* first BD in Rx BD table offset (In MURAM) */
+ u8 *confBd; /* next BD for confirm after Tx */
+ u8 *tx_bd; /* next BD for new Tx request */
+ u8 *rx_bd; /* next BD to collect after Rx */
+ void *p_rx_frame; /* accumulating receive frame */
+ u16 *p_ucce; /* a pointer to the event register in memory.
+ */
+ u16 *p_uccm; /* a pointer to the mask register in memory */
+ u16 saved_uccm; /* a saved mask for the RX Interrupt bits */
+#ifdef STATISTICS
+ u32 tx_frames; /* Transmitted frames counters */
+ u32 rx_frames; /* Received frames counters (only frames
+ passed to application) */
+ u32 rx_discarded; /* Discarded frames counters (frames that
+ were discarded by the driver due to
+ errors) */
+#endif /* STATISTICS */
+};
+
+/* ucc_slow_init
+ * Initializes Slow UCC according to provided parameters.
+ *
+ * us_info - (In) pointer to the slow UCC info structure.
+ * uccs_ret - (Out) pointer to the slow UCC structure.
+ */
+int ucc_slow_init(struct ucc_slow_info * us_info, struct ucc_slow_private ** uccs_ret);
+
+/* ucc_slow_free
+ * Frees all resources for slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_free(struct ucc_slow_private * uccs);
+
+/* ucc_slow_enable
+ * Enables a fast UCC port.
+ * This routine enables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_slow_enable(struct ucc_slow_private * uccs, enum comm_dir mode);
+
+/* ucc_slow_disable
+ * Disables a fast UCC port.
+ * This routine disables Tx and/or Rx through the General UCC Mode Register.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ * mode - (In) TX, RX, or both.
+ */
+void ucc_slow_disable(struct ucc_slow_private * uccs, enum comm_dir mode);
+
+/* ucc_slow_poll_transmitter_now
+ * Immediately forces a poll of the transmitter for data to be sent.
+ * Typically, the hardware performs a periodic poll for data that the
+ * transmit routine has set up to be transmitted. In cases where
+ * this polling cycle is not soon enough, this optional routine can
+ * be invoked to force a poll right away, instead. Proper use for
+ * each transmission for which this functionality is desired is to
+ * call the transmit routine and then this routine right after.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_poll_transmitter_now(struct ucc_slow_private * uccs);
+
+/* ucc_slow_graceful_stop_tx
+ * Smoothly stops transmission on a specified slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_graceful_stop_tx(struct ucc_slow_private * uccs);
+
+/* ucc_slow_stop_tx
+ * Stops transmission on a specified slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_stop_tx(struct ucc_slow_private * uccs);
+
+/* ucc_slow_restart_x
+ * Restarts transmitting on a specified slow UCC.
+ *
+ * uccs - (In) pointer to the slow UCC structure.
+ */
+void ucc_slow_restart_x(struct ucc_slow_private * uccs);
+
+u32 ucc_slow_get_qe_cr_subblock(int uccs_num);
+
+#endif /* __UCC_SLOW_H__ */
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h
index eb66eae6616f..464a48cce7f5 100644
--- a/include/asm-powerpc/unistd.h
+++ b/include/asm-powerpc/unistd.h
@@ -479,13 +479,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5, type6 arg6
#endif
/*
- * System call prototypes.
- */
-#ifdef __KERNEL_SYSCALLS__
-extern int execve(const char *file, char **argv, char **envp);
-#endif /* __KERNEL_SYSCALLS__ */
-
-/*
* "Conditional" syscalls
*
* What we want is __attribute__((weak,alias("sys_ni_syscall"))),
diff --git a/include/asm-powerpc/xmon.h b/include/asm-powerpc/xmon.h
index 43f7129984c7..f1d337ed68d5 100644
--- a/include/asm-powerpc/xmon.h
+++ b/include/asm-powerpc/xmon.h
@@ -1,12 +1,22 @@
-#ifndef __PPC_XMON_H
-#define __PPC_XMON_H
-#ifdef __KERNEL__
+#ifndef __ASM_POWERPC_XMON_H
+#define __ASM_POWERPC_XMON_H
-struct pt_regs;
+/*
+ * Copyrignt (C) 2006 IBM Corp
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
-extern int xmon(struct pt_regs *excp);
-extern void xmon_printf(const char *fmt, ...);
-extern void xmon_init(int);
+#ifdef __KERNEL__
+#ifdef CONFIG_XMON
+extern void xmon_setup(void);
+#else
+static inline void xmon_setup(void) { };
#endif
-#endif
+
+#endif /* __KERNEL __ */
+#endif /* __ASM_POWERPC_XMON_H */
diff --git a/include/asm-ppc/commproc.h b/include/asm-ppc/commproc.h
index 3247bea5fc2b..7b06b4e6bf30 100644
--- a/include/asm-ppc/commproc.h
+++ b/include/asm-ppc/commproc.h
@@ -690,8 +690,7 @@ typedef struct risc_timer_pram {
#define CICR_IEN ((uint)0x00000080) /* Int. enable */
#define CICR_SPS ((uint)0x00000001) /* SCC Spread */
-extern void cpm_install_handler(int vec,
- void (*handler)(void *, struct pt_regs *regs), void *dev_id);
+extern void cpm_install_handler(int vec, void (*handler)(void *), void *dev_id);
extern void cpm_free_handler(int vec);
#endif /* __CPM_8XX__ */
diff --git a/include/asm-ppc/cpm2.h b/include/asm-ppc/cpm2.h
index f6a7ff04ffe5..220cc2debe08 100644
--- a/include/asm-ppc/cpm2.h
+++ b/include/asm-ppc/cpm2.h
@@ -42,6 +42,8 @@
#define CPM_CR_IDMA4_SBLOCK (0x17)
#define CPM_CR_MCC1_SBLOCK (0x1c)
+#define CPM_CR_FCC_SBLOCK(x) (x + 0x10)
+
#define CPM_CR_SCC1_PAGE (0x00)
#define CPM_CR_SCC2_PAGE (0x01)
#define CPM_CR_SCC3_PAGE (0x02)
@@ -62,6 +64,8 @@
#define CPM_CR_MCC1_PAGE (0x07)
#define CPM_CR_MCC2_PAGE (0x08)
+#define CPM_CR_FCC_PAGE(x) (x + 0x04)
+
/* Some opcodes (there are more...later)
*/
#define CPM_CR_INIT_TRX ((ushort)0x0000)
@@ -173,6 +177,10 @@ typedef struct cpm_buf_desc {
#define PROFF_I2C_BASE ((uint)0x8afc)
#define PROFF_IDMA4_BASE ((uint)0x8afe)
+#define PROFF_SCC_SIZE ((uint)0x100)
+#define PROFF_FCC_SIZE ((uint)0x100)
+#define PROFF_SMC_SIZE ((uint)64)
+
/* The SMCs are relocated to any of the first eight DPRAM pages.
* We will fix these at the first locations of DPRAM, until we
* get some microcode patches :-).
@@ -1186,7 +1194,60 @@ typedef struct im_idma {
#define FCC_MEM_OFFSET(x) (CPM_FCC_SPECIAL_BASE + (x*128))
#define FCC1_MEM_OFFSET FCC_MEM_OFFSET(0)
#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(1)
-#define FCC2_MEM_OFFSET FCC_MEM_OFFSET(2)
+#define FCC3_MEM_OFFSET FCC_MEM_OFFSET(2)
+
+/* Clocks and GRG's */
+
+enum cpm_clk_dir {
+ CPM_CLK_RX,
+ CPM_CLK_TX,
+ CPM_CLK_RTX
+};
+
+enum cpm_clk_target {
+ CPM_CLK_SCC1,
+ CPM_CLK_SCC2,
+ CPM_CLK_SCC3,
+ CPM_CLK_SCC4,
+ CPM_CLK_FCC1,
+ CPM_CLK_FCC2,
+ CPM_CLK_FCC3
+};
+
+enum cpm_clk {
+ CPM_CLK_NONE = 0,
+ CPM_BRG1, /* Baud Rate Generator 1 */
+ CPM_BRG2, /* Baud Rate Generator 2 */
+ CPM_BRG3, /* Baud Rate Generator 3 */
+ CPM_BRG4, /* Baud Rate Generator 4 */
+ CPM_BRG5, /* Baud Rate Generator 5 */
+ CPM_BRG6, /* Baud Rate Generator 6 */
+ CPM_BRG7, /* Baud Rate Generator 7 */
+ CPM_BRG8, /* Baud Rate Generator 8 */
+ CPM_CLK1, /* Clock 1 */
+ CPM_CLK2, /* Clock 2 */
+ CPM_CLK3, /* Clock 3 */
+ CPM_CLK4, /* Clock 4 */
+ CPM_CLK5, /* Clock 5 */
+ CPM_CLK6, /* Clock 6 */
+ CPM_CLK7, /* Clock 7 */
+ CPM_CLK8, /* Clock 8 */
+ CPM_CLK9, /* Clock 9 */
+ CPM_CLK10, /* Clock 10 */
+ CPM_CLK11, /* Clock 11 */
+ CPM_CLK12, /* Clock 12 */
+ CPM_CLK13, /* Clock 13 */
+ CPM_CLK14, /* Clock 14 */
+ CPM_CLK15, /* Clock 15 */
+ CPM_CLK16, /* Clock 16 */
+ CPM_CLK17, /* Clock 17 */
+ CPM_CLK18, /* Clock 18 */
+ CPM_CLK19, /* Clock 19 */
+ CPM_CLK20, /* Clock 20 */
+ CPM_CLK_DUMMY
+};
+
+extern int cpm2_clk_setup(enum cpm_clk_target target, int clock, int mode);
#endif /* __CPM2__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/floppy.h b/include/asm-ppc/floppy.h
index d3963ca79ad8..ae316e6d2ca9 100644
--- a/include/asm-ppc/floppy.h
+++ b/include/asm-ppc/floppy.h
@@ -38,14 +38,14 @@ static int virtual_dma_mode;
static int doing_vdma;
static struct fd_dma_ops *fd_ops;
-static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t floppy_hardint(int irq, void *dev_id)
{
unsigned char st;
int lcount;
char *lptr;
if (!doing_vdma)
- return floppy_interrupt(irq, dev_id, regs);
+ return floppy_interrupt(irq, dev_id);
st = 1;
@@ -69,7 +69,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
virtual_dma_residue += virtual_dma_count;
virtual_dma_count=0;
doing_vdma = 0;
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
return IRQ_HANDLED;
diff --git a/include/asm-ppc/fs_pd.h b/include/asm-ppc/fs_pd.h
new file mode 100644
index 000000000000..8691327653af
--- /dev/null
+++ b/include/asm-ppc/fs_pd.h
@@ -0,0 +1,36 @@
+/*
+ * Platform information definitions.
+ *
+ * 2006 (c) MontaVista Software, Inc.
+ * Vitaly Bordug <vbordug@ru.mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef FS_PD_H
+#define FS_PD_H
+
+static inline int uart_baudrate(void)
+{
+ int baud;
+ bd_t *bd = (bd_t *) __res;
+
+ if (bd->bi_baudrate)
+ baud = bd->bi_baudrate;
+ else
+ baud = -1;
+ return baud;
+}
+
+static inline int uart_clock(void)
+{
+ return (((bd_t *) __res)->bi_intfreq);
+}
+
+#define cpm2_map(member) (&cpm2_immr->member)
+#define cpm2_map_size(member, size) (&cpm2_immr->member)
+#define cpm2_unmap(addr) do {} while(0)
+
+#endif
diff --git a/include/asm-ppc/gt64260.h b/include/asm-ppc/gt64260.h
index cd0ef644943d..9e63b3cfffca 100644
--- a/include/asm-ppc/gt64260.h
+++ b/include/asm-ppc/gt64260.h
@@ -315,7 +315,7 @@ int gt64260_get_base(u32 *base);
int gt64260_pci_exclude_device(u8 bus, u8 devfn);
void gt64260_init_irq(void);
-int gt64260_get_irq(struct pt_regs *regs);
+int gt64260_get_irq(void);
void gt64260_mpsc_progress(char *s, unsigned short hex);
diff --git a/include/asm-ppc/io.h b/include/asm-ppc/io.h
index 3d9a9e6f3321..a4c411b753ef 100644
--- a/include/asm-ppc/io.h
+++ b/include/asm-ppc/io.h
@@ -439,22 +439,6 @@ extern inline void * phys_to_virt(unsigned long address)
#define iobarrier_r() eieio()
#define iobarrier_w() eieio()
-static inline int check_signature(volatile void __iomem * io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
/*
* Here comes the ppc implementation of the IOMAP
* interfaces.
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index da7746738aee..293a444a1d77 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -43,7 +43,7 @@ struct machdep_calls {
/* Optional, may be NULL. */
unsigned int (*irq_canonicalize)(unsigned int irq);
void (*init_IRQ)(void);
- int (*get_irq)(struct pt_regs *);
+ int (*get_irq)(void);
/* A general init function, called by ppc_init in init/main.c.
May be NULL. DEPRECATED ! */
diff --git a/include/asm-ppc/mpc52xx.h b/include/asm-ppc/mpc52xx.h
index 7e9842805a28..64c8874618dc 100644
--- a/include/asm-ppc/mpc52xx.h
+++ b/include/asm-ppc/mpc52xx.h
@@ -415,7 +415,7 @@ struct mpc52xx_cdm {
#ifndef __ASSEMBLY__
extern void mpc52xx_init_irq(void);
-extern int mpc52xx_get_irq(struct pt_regs *regs);
+extern int mpc52xx_get_irq(void);
extern unsigned long mpc52xx_find_end_of_memory(void);
extern void mpc52xx_set_bat(void);
diff --git a/include/asm-ppc/mv64x60.h b/include/asm-ppc/mv64x60.h
index 663edbee3e91..db3776f18198 100644
--- a/include/asm-ppc/mv64x60.h
+++ b/include/asm-ppc/mv64x60.h
@@ -336,9 +336,9 @@ int mv64x60_pci_exclude_device(u8 bus, u8 devfn);
void gt64260_init_irq(void);
-int gt64260_get_irq(struct pt_regs *regs);
+int gt64260_get_irq(void);
void mv64360_init_irq(void);
-int mv64360_get_irq(struct pt_regs *regs);
+int mv64360_get_irq(void);
u32 mv64x60_mask(u32 val, u32 num_bits);
u32 mv64x60_shift_left(u32 val, u32 num_bits);
diff --git a/include/asm-ppc/mv64x60_defs.h b/include/asm-ppc/mv64x60_defs.h
index f8f7f16b9b53..5b0704a3e6ea 100644
--- a/include/asm-ppc/mv64x60_defs.h
+++ b/include/asm-ppc/mv64x60_defs.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/gt64260_defs.h
+ * include/asm-ppc/mv64x60_defs.h
*
* Register definitions for the Marvell/Galileo GT64260, MV64360, etc.
* host bridges.
diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
index a4fe962d9f73..778d5726212c 100644
--- a/include/asm-ppc/open_pic.h
+++ b/include/asm-ppc/open_pic.h
@@ -48,12 +48,12 @@ extern void openpic_init(int linux_irq_offset);
extern void openpic_init_nmi_irq(u_int irq);
extern void openpic_set_irq_priority(u_int irq, u_int pri);
extern void openpic_hookup_cascade(u_int irq, char *name,
- int (*cascade_fn)(struct pt_regs *));
+ int (*cascade_fn)(void));
extern u_int openpic_irq(void);
extern void openpic_eoi(void);
extern void openpic_request_IPIs(void);
extern void do_openpic_setup_cpu(void);
-extern int openpic_get_irq(struct pt_regs *regs);
+extern int openpic_get_irq(void);
extern void openpic_reset_processor_phys(u_int cpumask);
extern void openpic_setup_ISU(int isu_num, unsigned long addr);
extern void openpic_cause_IPI(u_int ipi, cpumask_t cpumask);
@@ -93,6 +93,6 @@ extern void openpic2_init(int linux_irq_offset);
extern void openpic2_init_nmi_irq(u_int irq);
extern u_int openpic2_irq(void);
extern void openpic2_eoi(void);
-extern int openpic2_get_irq(struct pt_regs *regs);
+extern int openpic2_get_irq(void);
extern void openpic2_setup_ISU(int isu_num, unsigned long addr);
#endif /* _PPC_KERNEL_OPEN_PIC_H */
diff --git a/include/asm-ppc/rheap.h b/include/asm-ppc/rheap.h
index e6ca1f67cedc..39a10d862244 100644
--- a/include/asm-ppc/rheap.h
+++ b/include/asm-ppc/rheap.h
@@ -1,5 +1,5 @@
/*
- * include/asm-ppc/rheap.c
+ * include/asm-ppc/rheap.h
*
* Header file for the implementation of a remote heap.
*
@@ -62,6 +62,10 @@ extern int rh_attach_region(rh_info_t * info, void *start, int size);
/* Detach a free region */
extern void *rh_detach_region(rh_info_t * info, void *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,
+ const char *owner);
+
/* Allocate the given size from the remote heap */
extern void *rh_alloc(rh_info_t * info, int size, const char *owner);
diff --git a/include/asm-ppc/rtc.h b/include/asm-ppc/rtc.h
index 05fbf912ab4d..6025b46d0a2a 100644
--- a/include/asm-ppc/rtc.h
+++ b/include/asm-ppc/rtc.h
@@ -1,5 +1,5 @@
/*
- * inclue/asm-ppc/rtc.h
+ * include/asm-ppc/rtc.h
*
* Author: Tom Rini <trini@mvista.com>
*
diff --git a/include/asm-ppc/smp.h b/include/asm-ppc/smp.h
index 0b7fa89589df..e75791ea33a6 100644
--- a/include/asm-ppc/smp.h
+++ b/include/asm-ppc/smp.h
@@ -39,7 +39,7 @@ extern struct smp_ops_t *smp_ops;
extern void smp_send_tlb_invalidate(int);
extern void smp_send_xmon_break(int cpu);
struct pt_regs;
-extern void smp_message_recv(int, struct pt_regs *);
+extern void smp_message_recv(int);
extern int __cpu_disable(void);
extern void __cpu_die(unsigned int cpu);
diff --git a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
index 5c64b75f0295..fccaf5531e57 100644
--- a/include/asm-ppc/spinlock.h
+++ b/include/asm-ppc/spinlock.h
@@ -161,4 +161,8 @@ static __inline__ void __raw_write_unlock(raw_rwlock_t *rw)
rw->lock = 0;
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-s390/appldata.h b/include/asm-s390/appldata.h
index b1770703b706..79283dac8281 100644
--- a/include/asm-s390/appldata.h
+++ b/include/asm-s390/appldata.h
@@ -80,7 +80,7 @@ static inline int appldata_asm(struct appldata_product_id *id,
parm_list.product_id_addr = (unsigned long) id;
parm_list.buffer_addr = virt_to_phys(buffer);
asm volatile(
- "diag %1,%0,0xdc"
+ " diag %1,%0,0xdc"
: "=d" (ry)
: "d" (&parm_list), "m" (parm_list), "m" (*id)
: "cc");
diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h
index 399bf02894dd..af20c7462485 100644
--- a/include/asm-s390/atomic.h
+++ b/include/asm-s390/atomic.h
@@ -30,20 +30,43 @@ typedef struct {
#ifdef __KERNEL__
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+
#define __CS_LOOP(ptr, op_val, op_string) ({ \
typeof(ptr->counter) old_val, new_val; \
- __asm__ __volatile__(" l %0,0(%3)\n" \
- "0: lr %1,%0\n" \
- op_string " %1,%4\n" \
- " cs %0,%1,0(%3)\n" \
- " jl 0b" \
- : "=&d" (old_val), "=&d" (new_val), \
- "=m" (((atomic_t *)(ptr))->counter) \
- : "a" (ptr), "d" (op_val), \
- "m" (((atomic_t *)(ptr))->counter) \
- : "cc", "memory" ); \
+ asm volatile( \
+ " l %0,%2\n" \
+ "0: lr %1,%0\n" \
+ op_string " %1,%3\n" \
+ " cs %0,%1,%2\n" \
+ " jl 0b" \
+ : "=&d" (old_val), "=&d" (new_val), \
+ "=Q" (((atomic_t *)(ptr))->counter) \
+ : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \
+ : "cc", "memory"); \
new_val; \
})
+
+#else /* __GNUC__ */
+
+#define __CS_LOOP(ptr, op_val, op_string) ({ \
+ typeof(ptr->counter) old_val, new_val; \
+ asm volatile( \
+ " l %0,0(%3)\n" \
+ "0: lr %1,%0\n" \
+ op_string " %1,%4\n" \
+ " cs %0,%1,0(%3)\n" \
+ " jl 0b" \
+ : "=&d" (old_val), "=&d" (new_val), \
+ "=m" (((atomic_t *)(ptr))->counter) \
+ : "a" (ptr), "d" (op_val), \
+ "m" (((atomic_t *)(ptr))->counter) \
+ : "cc", "memory"); \
+ new_val; \
+})
+
+#endif /* __GNUC__ */
+
#define atomic_read(v) ((v)->counter)
#define atomic_set(v,i) (((v)->counter) = (i))
@@ -81,10 +104,19 @@ static __inline__ void atomic_set_mask(unsigned long mask, atomic_t * v)
static __inline__ int atomic_cmpxchg(atomic_t *v, int old, int new)
{
- __asm__ __volatile__(" cs %0,%3,0(%2)\n"
- : "+d" (old), "=m" (v->counter)
- : "a" (v), "d" (new), "m" (v->counter)
- : "cc", "memory" );
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+ asm volatile(
+ " cs %0,%2,%1"
+ : "+d" (old), "=Q" (v->counter)
+ : "d" (new), "Q" (v->counter)
+ : "cc", "memory");
+#else /* __GNUC__ */
+ asm volatile(
+ " cs %0,%3,0(%2)"
+ : "+d" (old), "=m" (v->counter)
+ : "a" (v), "d" (new), "m" (v->counter)
+ : "cc", "memory");
+#endif /* __GNUC__ */
return old;
}
@@ -113,20 +145,43 @@ typedef struct {
} __attribute__ ((aligned (8))) atomic64_t;
#define ATOMIC64_INIT(i) { (i) }
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+
#define __CSG_LOOP(ptr, op_val, op_string) ({ \
typeof(ptr->counter) old_val, new_val; \
- __asm__ __volatile__(" lg %0,0(%3)\n" \
- "0: lgr %1,%0\n" \
- op_string " %1,%4\n" \
- " csg %0,%1,0(%3)\n" \
- " jl 0b" \
- : "=&d" (old_val), "=&d" (new_val), \
- "=m" (((atomic_t *)(ptr))->counter) \
- : "a" (ptr), "d" (op_val), \
- "m" (((atomic_t *)(ptr))->counter) \
- : "cc", "memory" ); \
+ asm volatile( \
+ " lg %0,%2\n" \
+ "0: lgr %1,%0\n" \
+ op_string " %1,%3\n" \
+ " csg %0,%1,%2\n" \
+ " jl 0b" \
+ : "=&d" (old_val), "=&d" (new_val), \
+ "=Q" (((atomic_t *)(ptr))->counter) \
+ : "d" (op_val), "Q" (((atomic_t *)(ptr))->counter) \
+ : "cc", "memory" ); \
new_val; \
})
+
+#else /* __GNUC__ */
+
+#define __CSG_LOOP(ptr, op_val, op_string) ({ \
+ typeof(ptr->counter) old_val, new_val; \
+ asm volatile( \
+ " lg %0,0(%3)\n" \
+ "0: lgr %1,%0\n" \
+ op_string " %1,%4\n" \
+ " csg %0,%1,0(%3)\n" \
+ " jl 0b" \
+ : "=&d" (old_val), "=&d" (new_val), \
+ "=m" (((atomic_t *)(ptr))->counter) \
+ : "a" (ptr), "d" (op_val), \
+ "m" (((atomic_t *)(ptr))->counter) \
+ : "cc", "memory" ); \
+ new_val; \
+})
+
+#endif /* __GNUC__ */
+
#define atomic64_read(v) ((v)->counter)
#define atomic64_set(v,i) (((v)->counter) = (i))
@@ -163,10 +218,19 @@ static __inline__ void atomic64_set_mask(unsigned long mask, atomic64_t * v)
static __inline__ long long atomic64_cmpxchg(atomic64_t *v,
long long old, long long new)
{
- __asm__ __volatile__(" csg %0,%3,0(%2)\n"
- : "+d" (old), "=m" (v->counter)
- : "a" (v), "d" (new), "m" (v->counter)
- : "cc", "memory" );
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+ asm volatile(
+ " csg %0,%2,%1"
+ : "+d" (old), "=Q" (v->counter)
+ : "d" (new), "Q" (v->counter)
+ : "cc", "memory");
+#else /* __GNUC__ */
+ asm volatile(
+ " csg %0,%3,0(%2)"
+ : "+d" (old), "=m" (v->counter)
+ : "a" (v), "d" (new), "m" (v->counter)
+ : "cc", "memory");
+#endif /* __GNUC__ */
return old;
}
diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h
index 0ddcdba79e4a..f79c9b792af1 100644
--- a/include/asm-s390/bitops.h
+++ b/include/asm-s390/bitops.h
@@ -67,16 +67,35 @@ extern const char _sb_findmap[];
#define __BITOPS_AND "nr"
#define __BITOPS_XOR "xr"
-#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
- __asm__ __volatile__(" l %0,0(%4)\n" \
- "0: lr %1,%0\n" \
- __op_string " %1,%3\n" \
- " cs %0,%1,0(%4)\n" \
- " jl 0b" \
- : "=&d" (__old), "=&d" (__new), \
- "=m" (*(unsigned long *) __addr) \
- : "d" (__val), "a" (__addr), \
- "m" (*(unsigned long *) __addr) : "cc" );
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+
+#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
+ asm volatile( \
+ " l %0,%2\n" \
+ "0: lr %1,%0\n" \
+ __op_string " %1,%3\n" \
+ " cs %0,%1,%2\n" \
+ " jl 0b" \
+ : "=&d" (__old), "=&d" (__new), \
+ "=Q" (*(unsigned long *) __addr) \
+ : "d" (__val), "Q" (*(unsigned long *) __addr) \
+ : "cc");
+
+#else /* __GNUC__ */
+
+#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
+ asm volatile( \
+ " l %0,0(%4)\n" \
+ "0: lr %1,%0\n" \
+ __op_string " %1,%3\n" \
+ " cs %0,%1,0(%4)\n" \
+ " jl 0b" \
+ : "=&d" (__old), "=&d" (__new), \
+ "=m" (*(unsigned long *) __addr) \
+ : "d" (__val), "a" (__addr), \
+ "m" (*(unsigned long *) __addr) : "cc");
+
+#endif /* __GNUC__ */
#else /* __s390x__ */
@@ -86,21 +105,41 @@ extern const char _sb_findmap[];
#define __BITOPS_AND "ngr"
#define __BITOPS_XOR "xgr"
-#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
- __asm__ __volatile__(" lg %0,0(%4)\n" \
- "0: lgr %1,%0\n" \
- __op_string " %1,%3\n" \
- " csg %0,%1,0(%4)\n" \
- " jl 0b" \
- : "=&d" (__old), "=&d" (__new), \
- "=m" (*(unsigned long *) __addr) \
- : "d" (__val), "a" (__addr), \
- "m" (*(unsigned long *) __addr) : "cc" );
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+
+#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
+ asm volatile( \
+ " lg %0,%2\n" \
+ "0: lgr %1,%0\n" \
+ __op_string " %1,%3\n" \
+ " csg %0,%1,%2\n" \
+ " jl 0b" \
+ : "=&d" (__old), "=&d" (__new), \
+ "=Q" (*(unsigned long *) __addr) \
+ : "d" (__val), "Q" (*(unsigned long *) __addr) \
+ : "cc");
+
+#else /* __GNUC__ */
+
+#define __BITOPS_LOOP(__old, __new, __addr, __val, __op_string) \
+ asm volatile( \
+ " lg %0,0(%4)\n" \
+ "0: lgr %1,%0\n" \
+ __op_string " %1,%3\n" \
+ " csg %0,%1,0(%4)\n" \
+ " jl 0b" \
+ : "=&d" (__old), "=&d" (__new), \
+ "=m" (*(unsigned long *) __addr) \
+ : "d" (__val), "a" (__addr), \
+ "m" (*(unsigned long *) __addr) : "cc");
+
+
+#endif /* __GNUC__ */
#endif /* __s390x__ */
#define __BITOPS_WORDS(bits) (((bits)+__BITOPS_WORDSIZE-1)/__BITOPS_WORDSIZE)
-#define __BITOPS_BARRIER() __asm__ __volatile__ ( "" : : : "memory" )
+#define __BITOPS_BARRIER() asm volatile("" : : : "memory")
#ifdef CONFIG_SMP
/*
@@ -217,10 +256,10 @@ static inline void __set_bit(unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
- asm volatile("oc 0(1,%1),0(%2)"
- : "=m" (*(char *) addr)
- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
- "m" (*(char *) addr) : "cc" );
+ asm volatile(
+ " oc 0(1,%1),0(%2)"
+ : "=m" (*(char *) addr) : "a" (addr),
+ "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" );
}
static inline void
@@ -229,40 +268,7 @@ __constant_set_bit(const unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
- switch (nr&7) {
- case 0:
- asm volatile ("oi 0(%1),0x01" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 1:
- asm volatile ("oi 0(%1),0x02" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 2:
- asm volatile ("oi 0(%1),0x04" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 3:
- asm volatile ("oi 0(%1),0x08" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 4:
- asm volatile ("oi 0(%1),0x10" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 5:
- asm volatile ("oi 0(%1),0x20" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 6:
- asm volatile ("oi 0(%1),0x40" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 7:
- asm volatile ("oi 0(%1),0x80" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- }
+ *(unsigned char *) addr |= 1 << (nr & 7);
}
#define set_bit_simple(nr,addr) \
@@ -279,10 +285,10 @@ __clear_bit(unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
- asm volatile("nc 0(1,%1),0(%2)"
- : "=m" (*(char *) addr)
- : "a" (addr), "a" (_ni_bitmap + (nr & 7)),
- "m" (*(char *) addr) : "cc" );
+ asm volatile(
+ " nc 0(1,%1),0(%2)"
+ : "=m" (*(char *) addr) : "a" (addr),
+ "a" (_ni_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc");
}
static inline void
@@ -291,40 +297,7 @@ __constant_clear_bit(const unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
- switch (nr&7) {
- case 0:
- asm volatile ("ni 0(%1),0xFE" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 1:
- asm volatile ("ni 0(%1),0xFD": "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 2:
- asm volatile ("ni 0(%1),0xFB" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 3:
- asm volatile ("ni 0(%1),0xF7" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 4:
- asm volatile ("ni 0(%1),0xEF" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 5:
- asm volatile ("ni 0(%1),0xDF" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 6:
- asm volatile ("ni 0(%1),0xBF" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 7:
- asm volatile ("ni 0(%1),0x7F" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- }
+ *(unsigned char *) addr &= ~(1 << (nr & 7));
}
#define clear_bit_simple(nr,addr) \
@@ -340,10 +313,10 @@ static inline void __change_bit(unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
- asm volatile("xc 0(1,%1),0(%2)"
- : "=m" (*(char *) addr)
- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
- "m" (*(char *) addr) : "cc" );
+ asm volatile(
+ " xc 0(1,%1),0(%2)"
+ : "=m" (*(char *) addr) : "a" (addr),
+ "a" (_oi_bitmap + (nr & 7)), "m" (*(char *) addr) : "cc" );
}
static inline void
@@ -352,40 +325,7 @@ __constant_change_bit(const unsigned long nr, volatile unsigned long *ptr)
unsigned long addr;
addr = ((unsigned long) ptr) + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
- switch (nr&7) {
- case 0:
- asm volatile ("xi 0(%1),0x01" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 1:
- asm volatile ("xi 0(%1),0x02" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 2:
- asm volatile ("xi 0(%1),0x04" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 3:
- asm volatile ("xi 0(%1),0x08" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 4:
- asm volatile ("xi 0(%1),0x10" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 5:
- asm volatile ("xi 0(%1),0x20" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 6:
- asm volatile ("xi 0(%1),0x40" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- case 7:
- asm volatile ("xi 0(%1),0x80" : "=m" (*(char *) addr)
- : "a" (addr), "m" (*(char *) addr) : "cc" );
- break;
- }
+ *(unsigned char *) addr ^= 1 << (nr & 7);
}
#define change_bit_simple(nr,addr) \
@@ -404,10 +344,11 @@ test_and_set_bit_simple(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
ch = *(unsigned char *) addr;
- asm volatile("oc 0(1,%1),0(%2)"
- : "=m" (*(char *) addr)
- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
- "m" (*(char *) addr) : "cc", "memory" );
+ asm volatile(
+ " oc 0(1,%1),0(%2)"
+ : "=m" (*(char *) addr)
+ : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
+ "m" (*(char *) addr) : "cc", "memory");
return (ch >> (nr & 7)) & 1;
}
#define __test_and_set_bit(X,Y) test_and_set_bit_simple(X,Y)
@@ -423,10 +364,11 @@ test_and_clear_bit_simple(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
ch = *(unsigned char *) addr;
- asm volatile("nc 0(1,%1),0(%2)"
- : "=m" (*(char *) addr)
- : "a" (addr), "a" (_ni_bitmap + (nr & 7)),
- "m" (*(char *) addr) : "cc", "memory" );
+ asm volatile(
+ " nc 0(1,%1),0(%2)"
+ : "=m" (*(char *) addr)
+ : "a" (addr), "a" (_ni_bitmap + (nr & 7)),
+ "m" (*(char *) addr) : "cc", "memory");
return (ch >> (nr & 7)) & 1;
}
#define __test_and_clear_bit(X,Y) test_and_clear_bit_simple(X,Y)
@@ -442,10 +384,11 @@ test_and_change_bit_simple(unsigned long nr, volatile unsigned long *ptr)
addr = (unsigned long) ptr + ((nr ^ (__BITOPS_WORDSIZE - 8)) >> 3);
ch = *(unsigned char *) addr;
- asm volatile("xc 0(1,%1),0(%2)"
- : "=m" (*(char *) addr)
- : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
- "m" (*(char *) addr) : "cc", "memory" );
+ asm volatile(
+ " xc 0(1,%1),0(%2)"
+ : "=m" (*(char *) addr)
+ : "a" (addr), "a" (_oi_bitmap + (nr & 7)),
+ "m" (*(char *) addr) : "cc", "memory");
return (ch >> (nr & 7)) & 1;
}
#define __test_and_change_bit(X,Y) test_and_change_bit_simple(X,Y)
@@ -557,35 +500,36 @@ find_first_zero_bit(const unsigned long * addr, unsigned long size)
if (!size)
return 0;
- __asm__(" lhi %1,-1\n"
- " lr %2,%3\n"
- " slr %0,%0\n"
- " ahi %2,31\n"
- " srl %2,5\n"
- "0: c %1,0(%0,%4)\n"
- " jne 1f\n"
- " la %0,4(%0)\n"
- " brct %2,0b\n"
- " lr %0,%3\n"
- " j 4f\n"
- "1: l %2,0(%0,%4)\n"
- " sll %0,3\n"
- " lhi %1,0xff\n"
- " tml %2,0xffff\n"
- " jno 2f\n"
- " ahi %0,16\n"
- " srl %2,16\n"
- "2: tml %2,0x00ff\n"
- " jno 3f\n"
- " ahi %0,8\n"
- " srl %2,8\n"
- "3: nr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " alr %0,%2\n"
- "4:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (addr), "a" (&_zb_findmap),
- "m" (*(addrtype *) addr) : "cc" );
+ asm volatile(
+ " lhi %1,-1\n"
+ " lr %2,%3\n"
+ " slr %0,%0\n"
+ " ahi %2,31\n"
+ " srl %2,5\n"
+ "0: c %1,0(%0,%4)\n"
+ " jne 1f\n"
+ " la %0,4(%0)\n"
+ " brct %2,0b\n"
+ " lr %0,%3\n"
+ " j 4f\n"
+ "1: l %2,0(%0,%4)\n"
+ " sll %0,3\n"
+ " lhi %1,0xff\n"
+ " tml %2,0xffff\n"
+ " jno 2f\n"
+ " ahi %0,16\n"
+ " srl %2,16\n"
+ "2: tml %2,0x00ff\n"
+ " jno 3f\n"
+ " ahi %0,8\n"
+ " srl %2,8\n"
+ "3: nr %2,%1\n"
+ " ic %2,0(%2,%5)\n"
+ " alr %0,%2\n"
+ "4:"
+ : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ : "a" (size), "a" (addr), "a" (&_zb_findmap),
+ "m" (*(addrtype *) addr) : "cc");
return (res < size) ? res : size;
}
@@ -598,35 +542,36 @@ find_first_bit(const unsigned long * addr, unsigned long size)
if (!size)
return 0;
- __asm__(" slr %1,%1\n"
- " lr %2,%3\n"
- " slr %0,%0\n"
- " ahi %2,31\n"
- " srl %2,5\n"
- "0: c %1,0(%0,%4)\n"
- " jne 1f\n"
- " la %0,4(%0)\n"
- " brct %2,0b\n"
- " lr %0,%3\n"
- " j 4f\n"
- "1: l %2,0(%0,%4)\n"
- " sll %0,3\n"
- " lhi %1,0xff\n"
- " tml %2,0xffff\n"
- " jnz 2f\n"
- " ahi %0,16\n"
- " srl %2,16\n"
- "2: tml %2,0x00ff\n"
- " jnz 3f\n"
- " ahi %0,8\n"
- " srl %2,8\n"
- "3: nr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " alr %0,%2\n"
- "4:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (addr), "a" (&_sb_findmap),
- "m" (*(addrtype *) addr) : "cc" );
+ asm volatile(
+ " slr %1,%1\n"
+ " lr %2,%3\n"
+ " slr %0,%0\n"
+ " ahi %2,31\n"
+ " srl %2,5\n"
+ "0: c %1,0(%0,%4)\n"
+ " jne 1f\n"
+ " la %0,4(%0)\n"
+ " brct %2,0b\n"
+ " lr %0,%3\n"
+ " j 4f\n"
+ "1: l %2,0(%0,%4)\n"
+ " sll %0,3\n"
+ " lhi %1,0xff\n"
+ " tml %2,0xffff\n"
+ " jnz 2f\n"
+ " ahi %0,16\n"
+ " srl %2,16\n"
+ "2: tml %2,0x00ff\n"
+ " jnz 3f\n"
+ " ahi %0,8\n"
+ " srl %2,8\n"
+ "3: nr %2,%1\n"
+ " ic %2,0(%2,%5)\n"
+ " alr %0,%2\n"
+ "4:"
+ : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ : "a" (size), "a" (addr), "a" (&_sb_findmap),
+ "m" (*(addrtype *) addr) : "cc");
return (res < size) ? res : size;
}
@@ -640,39 +585,40 @@ find_first_zero_bit(const unsigned long * addr, unsigned long size)
if (!size)
return 0;
- __asm__(" lghi %1,-1\n"
- " lgr %2,%3\n"
- " slgr %0,%0\n"
- " aghi %2,63\n"
- " srlg %2,%2,6\n"
- "0: cg %1,0(%0,%4)\n"
- " jne 1f\n"
- " la %0,8(%0)\n"
- " brct %2,0b\n"
- " lgr %0,%3\n"
- " j 5f\n"
- "1: lg %2,0(%0,%4)\n"
- " sllg %0,%0,3\n"
- " clr %2,%1\n"
- " jne 2f\n"
- " aghi %0,32\n"
- " srlg %2,%2,32\n"
- "2: lghi %1,0xff\n"
- " tmll %2,0xffff\n"
- " jno 3f\n"
- " aghi %0,16\n"
- " srl %2,16\n"
- "3: tmll %2,0x00ff\n"
- " jno 4f\n"
- " aghi %0,8\n"
- " srl %2,8\n"
- "4: ngr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " algr %0,%2\n"
- "5:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ asm volatile(
+ " lghi %1,-1\n"
+ " lgr %2,%3\n"
+ " slgr %0,%0\n"
+ " aghi %2,63\n"
+ " srlg %2,%2,6\n"
+ "0: cg %1,0(%0,%4)\n"
+ " jne 1f\n"
+ " la %0,8(%0)\n"
+ " brct %2,0b\n"
+ " lgr %0,%3\n"
+ " j 5f\n"
+ "1: lg %2,0(%0,%4)\n"
+ " sllg %0,%0,3\n"
+ " clr %2,%1\n"
+ " jne 2f\n"
+ " aghi %0,32\n"
+ " srlg %2,%2,32\n"
+ "2: lghi %1,0xff\n"
+ " tmll %2,0xffff\n"
+ " jno 3f\n"
+ " aghi %0,16\n"
+ " srl %2,16\n"
+ "3: tmll %2,0x00ff\n"
+ " jno 4f\n"
+ " aghi %0,8\n"
+ " srl %2,8\n"
+ "4: ngr %2,%1\n"
+ " ic %2,0(%2,%5)\n"
+ " algr %0,%2\n"
+ "5:"
+ : "=&a" (res), "=&d" (cmp), "=&a" (count)
: "a" (size), "a" (addr), "a" (&_zb_findmap),
- "m" (*(addrtype *) addr) : "cc" );
+ "m" (*(addrtype *) addr) : "cc");
return (res < size) ? res : size;
}
@@ -684,39 +630,40 @@ find_first_bit(const unsigned long * addr, unsigned long size)
if (!size)
return 0;
- __asm__(" slgr %1,%1\n"
- " lgr %2,%3\n"
- " slgr %0,%0\n"
- " aghi %2,63\n"
- " srlg %2,%2,6\n"
- "0: cg %1,0(%0,%4)\n"
- " jne 1f\n"
- " aghi %0,8\n"
- " brct %2,0b\n"
- " lgr %0,%3\n"
- " j 5f\n"
- "1: lg %2,0(%0,%4)\n"
- " sllg %0,%0,3\n"
- " clr %2,%1\n"
- " jne 2f\n"
- " aghi %0,32\n"
- " srlg %2,%2,32\n"
- "2: lghi %1,0xff\n"
- " tmll %2,0xffff\n"
- " jnz 3f\n"
- " aghi %0,16\n"
- " srl %2,16\n"
- "3: tmll %2,0x00ff\n"
- " jnz 4f\n"
- " aghi %0,8\n"
- " srl %2,8\n"
- "4: ngr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " algr %0,%2\n"
- "5:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ asm volatile(
+ " slgr %1,%1\n"
+ " lgr %2,%3\n"
+ " slgr %0,%0\n"
+ " aghi %2,63\n"
+ " srlg %2,%2,6\n"
+ "0: cg %1,0(%0,%4)\n"
+ " jne 1f\n"
+ " aghi %0,8\n"
+ " brct %2,0b\n"
+ " lgr %0,%3\n"
+ " j 5f\n"
+ "1: lg %2,0(%0,%4)\n"
+ " sllg %0,%0,3\n"
+ " clr %2,%1\n"
+ " jne 2f\n"
+ " aghi %0,32\n"
+ " srlg %2,%2,32\n"
+ "2: lghi %1,0xff\n"
+ " tmll %2,0xffff\n"
+ " jnz 3f\n"
+ " aghi %0,16\n"
+ " srl %2,16\n"
+ "3: tmll %2,0x00ff\n"
+ " jnz 4f\n"
+ " aghi %0,8\n"
+ " srl %2,8\n"
+ "4: ngr %2,%1\n"
+ " ic %2,0(%2,%5)\n"
+ " algr %0,%2\n"
+ "5:"
+ : "=&a" (res), "=&d" (cmp), "=&a" (count)
: "a" (size), "a" (addr), "a" (&_sb_findmap),
- "m" (*(addrtype *) addr) : "cc" );
+ "m" (*(addrtype *) addr) : "cc");
return (res < size) ? res : size;
}
@@ -832,36 +779,37 @@ ext2_find_first_zero_bit(void *vaddr, unsigned int size)
if (!size)
return 0;
- __asm__(" lhi %1,-1\n"
- " lr %2,%3\n"
- " ahi %2,31\n"
- " srl %2,5\n"
- " slr %0,%0\n"
- "0: cl %1,0(%0,%4)\n"
- " jne 1f\n"
- " ahi %0,4\n"
- " brct %2,0b\n"
- " lr %0,%3\n"
- " j 4f\n"
- "1: l %2,0(%0,%4)\n"
- " sll %0,3\n"
- " ahi %0,24\n"
- " lhi %1,0xff\n"
- " tmh %2,0xffff\n"
- " jo 2f\n"
- " ahi %0,-16\n"
- " srl %2,16\n"
- "2: tml %2,0xff00\n"
- " jo 3f\n"
- " ahi %0,-8\n"
- " srl %2,8\n"
- "3: nr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " alr %0,%2\n"
- "4:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
- : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
- "m" (*(addrtype *) vaddr) : "cc" );
+ asm volatile(
+ " lhi %1,-1\n"
+ " lr %2,%3\n"
+ " ahi %2,31\n"
+ " srl %2,5\n"
+ " slr %0,%0\n"
+ "0: cl %1,0(%0,%4)\n"
+ " jne 1f\n"
+ " ahi %0,4\n"
+ " brct %2,0b\n"
+ " lr %0,%3\n"
+ " j 4f\n"
+ "1: l %2,0(%0,%4)\n"
+ " sll %0,3\n"
+ " ahi %0,24\n"
+ " lhi %1,0xff\n"
+ " tmh %2,0xffff\n"
+ " jo 2f\n"
+ " ahi %0,-16\n"
+ " srl %2,16\n"
+ "2: tml %2,0xff00\n"
+ " jo 3f\n"
+ " ahi %0,-8\n"
+ " srl %2,8\n"
+ "3: nr %2,%1\n"
+ " ic %2,0(%2,%5)\n"
+ " alr %0,%2\n"
+ "4:"
+ : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ : "a" (size), "a" (vaddr), "a" (&_zb_findmap),
+ "m" (*(addrtype *) vaddr) : "cc");
return (res < size) ? res : size;
}
@@ -875,39 +823,40 @@ ext2_find_first_zero_bit(void *vaddr, unsigned long size)
if (!size)
return 0;
- __asm__(" lghi %1,-1\n"
- " lgr %2,%3\n"
- " aghi %2,63\n"
- " srlg %2,%2,6\n"
- " slgr %0,%0\n"
- "0: clg %1,0(%0,%4)\n"
- " jne 1f\n"
- " aghi %0,8\n"
- " brct %2,0b\n"
- " lgr %0,%3\n"
- " j 5f\n"
- "1: cl %1,0(%0,%4)\n"
- " jne 2f\n"
- " aghi %0,4\n"
- "2: l %2,0(%0,%4)\n"
- " sllg %0,%0,3\n"
- " aghi %0,24\n"
- " lghi %1,0xff\n"
- " tmlh %2,0xffff\n"
- " jo 3f\n"
- " aghi %0,-16\n"
- " srl %2,16\n"
- "3: tmll %2,0xff00\n"
- " jo 4f\n"
- " aghi %0,-8\n"
- " srl %2,8\n"
- "4: ngr %2,%1\n"
- " ic %2,0(%2,%5)\n"
- " algr %0,%2\n"
- "5:"
- : "=&a" (res), "=&d" (cmp), "=&a" (count)
+ asm volatile(
+ " lghi %1,-1\n"
+ " lgr %2,%3\n"
+ " aghi %2,63\n"
+ " srlg %2,%2,6\n"
+ " slgr %0,%0\n"
+ "0: clg %1,0(%0,%4)\n"
+ " jne 1f\n"
+ " aghi %0,8\n"
+ " brct %2,0b\n"
+ " lgr %0,%3\n"
+ " j 5f\n"
+ "1: cl %1,0(%0,%4)\n"
+ " jne 2f\n"
+ " aghi %0,4\n"
+ "2: l %2,0(%0,%4)\n"
+ " sllg %0,%0,3\n"
+ " aghi %0,24\n"
+ " lghi %1,0xff\n"
+ " tmlh %2,0xffff\n"
+ " jo 3f\n"
+ " aghi %0,-16\n"
+ " srl %2,16\n"
+ "3: tmll %2,0xff00\n"
+ " jo 4f\n"
+ " aghi %0,-8\n"
+ " srl %2,8\n"
+ "4: ngr %2,%1\n"
+ " ic %2,0(%2,%5)\n"
+ " algr %0,%2\n"
+ "5:"
+ : "=&a" (res), "=&d" (cmp), "=&a" (count)
: "a" (size), "a" (vaddr), "a" (&_zb_findmap),
- "m" (*(addrtype *) vaddr) : "cc" );
+ "m" (*(addrtype *) vaddr) : "cc");
return (res < size) ? res : size;
}
@@ -927,13 +876,16 @@ ext2_find_next_zero_bit(void *vaddr, unsigned long size, unsigned long offset)
p = addr + offset / __BITOPS_WORDSIZE;
if (bit) {
#ifndef __s390x__
- asm(" ic %0,0(%1)\n"
- " icm %0,2,1(%1)\n"
- " icm %0,4,2(%1)\n"
- " icm %0,8,3(%1)"
- : "=&a" (word) : "a" (p), "m" (*p) : "cc" );
+ asm volatile(
+ " ic %0,0(%1)\n"
+ " icm %0,2,1(%1)\n"
+ " icm %0,4,2(%1)\n"
+ " icm %0,8,3(%1)"
+ : "=&a" (word) : "a" (p), "m" (*p) : "cc");
#else
- asm(" lrvg %0,%1" : "=a" (word) : "m" (*p) );
+ asm volatile(
+ " lrvg %0,%1"
+ : "=a" (word) : "m" (*p) );
#endif
/*
* s390 version of ffz returns __BITOPS_WORDSIZE
diff --git a/include/asm-s390/byteorder.h b/include/asm-s390/byteorder.h
index 2cc35a0e188e..1fe2492baa8d 100644
--- a/include/asm-s390/byteorder.h
+++ b/include/asm-s390/byteorder.h
@@ -14,60 +14,54 @@
#ifdef __GNUC__
#ifdef __s390x__
-static __inline__ __u64 ___arch__swab64p(const __u64 *x)
+static inline __u64 ___arch__swab64p(const __u64 *x)
{
__u64 result;
- __asm__ __volatile__ (
- " lrvg %0,%1"
- : "=d" (result) : "m" (*x) );
+ asm volatile("lrvg %0,%1" : "=d" (result) : "m" (*x));
return result;
}
-static __inline__ __u64 ___arch__swab64(__u64 x)
+static inline __u64 ___arch__swab64(__u64 x)
{
__u64 result;
- __asm__ __volatile__ (
- " lrvgr %0,%1"
- : "=d" (result) : "d" (x) );
+ asm volatile("lrvgr %0,%1" : "=d" (result) : "d" (x));
return result;
}
-static __inline__ void ___arch__swab64s(__u64 *x)
+static inline void ___arch__swab64s(__u64 *x)
{
*x = ___arch__swab64p(x);
}
#endif /* __s390x__ */
-static __inline__ __u32 ___arch__swab32p(const __u32 *x)
+static inline __u32 ___arch__swab32p(const __u32 *x)
{
__u32 result;
- __asm__ __volatile__ (
+ asm volatile(
#ifndef __s390x__
- " icm %0,8,3(%1)\n"
- " icm %0,4,2(%1)\n"
- " icm %0,2,1(%1)\n"
- " ic %0,0(%1)"
- : "=&d" (result) : "a" (x), "m" (*x) : "cc" );
+ " icm %0,8,3(%1)\n"
+ " icm %0,4,2(%1)\n"
+ " icm %0,2,1(%1)\n"
+ " ic %0,0(%1)"
+ : "=&d" (result) : "a" (x), "m" (*x) : "cc");
#else /* __s390x__ */
- " lrv %0,%1"
- : "=d" (result) : "m" (*x) );
+ " lrv %0,%1"
+ : "=d" (result) : "m" (*x));
#endif /* __s390x__ */
return result;
}
-static __inline__ __u32 ___arch__swab32(__u32 x)
+static inline __u32 ___arch__swab32(__u32 x)
{
#ifndef __s390x__
return ___arch__swab32p(&x);
#else /* __s390x__ */
__u32 result;
- __asm__ __volatile__ (
- " lrvr %0,%1"
- : "=d" (result) : "d" (x) );
+ asm volatile("lrvr %0,%1" : "=d" (result) : "d" (x));
return result;
#endif /* __s390x__ */
}
@@ -81,14 +75,14 @@ static __inline__ __u16 ___arch__swab16p(const __u16 *x)
{
__u16 result;
- __asm__ __volatile__ (
+ asm volatile(
#ifndef __s390x__
- " icm %0,2,1(%1)\n"
- " ic %0,0(%1)\n"
- : "=&d" (result) : "a" (x), "m" (*x) : "cc" );
+ " icm %0,2,1(%1)\n"
+ " ic %0,0(%1)\n"
+ : "=&d" (result) : "a" (x), "m" (*x) : "cc");
#else /* __s390x__ */
- " lrvh %0,%1"
- : "=d" (result) : "m" (*x) );
+ " lrvh %0,%1"
+ : "=d" (result) : "m" (*x));
#endif /* __s390x__ */
return result;
}
diff --git a/include/asm-s390/checksum.h b/include/asm-s390/checksum.h
index 471f2af2b16a..37c362d89fad 100644
--- a/include/asm-s390/checksum.h
+++ b/include/asm-s390/checksum.h
@@ -30,57 +30,13 @@
static inline unsigned int
csum_partial(const unsigned char * buff, int len, unsigned int sum)
{
- /*
- * Experiments with ethernet and slip connections show that buf
- * is aligned on either a 2-byte or 4-byte boundary.
- */
-#ifndef __s390x__
- register_pair rp;
-
- rp.subreg.even = (unsigned long) buff;
- rp.subreg.odd = (unsigned long) len;
- __asm__ __volatile__ (
- "0: cksm %0,%1\n" /* do checksum on longs */
- " jo 0b\n"
- : "+&d" (sum), "+&a" (rp) : : "cc", "memory" );
-#else /* __s390x__ */
- __asm__ __volatile__ (
- " lgr 2,%1\n" /* address in gpr 2 */
- " lgfr 3,%2\n" /* length in gpr 3 */
- "0: cksm %0,2\n" /* do checksum on longs */
- " jo 0b\n"
- : "+&d" (sum)
- : "d" (buff), "d" (len)
- : "cc", "memory", "2", "3" );
-#endif /* __s390x__ */
- return sum;
-}
-
-/*
- * csum_partial as an inline function
- */
-static inline unsigned int
-csum_partial_inline(const unsigned char * buff, int len, unsigned int sum)
-{
-#ifndef __s390x__
- register_pair rp;
+ register unsigned long reg2 asm("2") = (unsigned long) buff;
+ register unsigned long reg3 asm("3") = (unsigned long) len;
- rp.subreg.even = (unsigned long) buff;
- rp.subreg.odd = (unsigned long) len;
- __asm__ __volatile__ (
- "0: cksm %0,%1\n" /* do checksum on longs */
- " jo 0b\n"
- : "+&d" (sum), "+&a" (rp) : : "cc", "memory" );
-#else /* __s390x__ */
- __asm__ __volatile__ (
- " lgr 2,%1\n" /* address in gpr 2 */
- " lgfr 3,%2\n" /* length in gpr 3 */
- "0: cksm %0,2\n" /* do checksum on longs */
- " jo 0b\n"
- : "+&d" (sum)
- : "d" (buff), "d" (len)
- : "cc", "memory", "2", "3" );
-#endif /* __s390x__ */
+ asm volatile(
+ "0: cksm %0,%1\n" /* do checksum on longs */
+ " jo 0b\n"
+ : "+d" (sum), "+d" (reg2), "+d" (reg3) : : "cc", "memory");
return sum;
}
@@ -114,7 +70,7 @@ static inline unsigned int
csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
{
memcpy(dst,src,len);
- return csum_partial_inline(dst, len, sum);
+ return csum_partial(dst, len, sum);
}
/*
@@ -126,22 +82,22 @@ csum_fold(unsigned int sum)
#ifndef __s390x__
register_pair rp;
- __asm__ __volatile__ (
- " slr %N1,%N1\n" /* %0 = H L */
- " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */
- " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */
- " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */
- " alr %0,%1\n" /* %0 = H+L+C L+H */
- " srl %0,16\n" /* %0 = H+L+C */
- : "+&d" (sum), "=d" (rp) : : "cc" );
+ asm volatile(
+ " slr %N1,%N1\n" /* %0 = H L */
+ " lr %1,%0\n" /* %0 = H L, %1 = H L 0 0 */
+ " srdl %1,16\n" /* %0 = H L, %1 = 0 H L 0 */
+ " alr %1,%N1\n" /* %0 = H L, %1 = L H L 0 */
+ " alr %0,%1\n" /* %0 = H+L+C L+H */
+ " srl %0,16\n" /* %0 = H+L+C */
+ : "+&d" (sum), "=d" (rp) : : "cc");
#else /* __s390x__ */
- __asm__ __volatile__ (
- " sr 3,3\n" /* %0 = H*65536 + L */
- " lr 2,%0\n" /* %0 = H L, R2/R3 = H L / 0 0 */
- " srdl 2,16\n" /* %0 = H L, R2/R3 = 0 H / L 0 */
- " alr 2,3\n" /* %0 = H L, R2/R3 = L H / L 0 */
- " alr %0,2\n" /* %0 = H+L+C L+H */
- " srl %0,16\n" /* %0 = H+L+C */
+ asm volatile(
+ " sr 3,3\n" /* %0 = H*65536 + L */
+ " lr 2,%0\n" /* %0 = H L, 2/3 = H L / 0 0 */
+ " srdl 2,16\n" /* %0 = H L, 2/3 = 0 H / L 0 */
+ " alr 2,3\n" /* %0 = H L, 2/3 = L H / L 0 */
+ " alr %0,2\n" /* %0 = H+L+C L+H */
+ " srl %0,16\n" /* %0 = H+L+C */
: "+&d" (sum) : : "cc", "2", "3");
#endif /* __s390x__ */
return ((unsigned short) ~sum);
@@ -155,29 +111,7 @@ csum_fold(unsigned int sum)
static inline unsigned short
ip_fast_csum(unsigned char *iph, unsigned int ihl)
{
- unsigned long sum;
-#ifndef __s390x__
- register_pair rp;
-
- rp.subreg.even = (unsigned long) iph;
- rp.subreg.odd = (unsigned long) ihl*4;
- __asm__ __volatile__ (
- " sr %0,%0\n" /* set sum to zero */
- "0: cksm %0,%1\n" /* do checksum on longs */
- " jo 0b\n"
- : "=&d" (sum), "+&a" (rp) : : "cc", "memory" );
-#else /* __s390x__ */
- __asm__ __volatile__ (
- " slgr %0,%0\n" /* set sum to zero */
- " lgr 2,%1\n" /* address in gpr 2 */
- " lgfr 3,%2\n" /* length in gpr 3 */
- "0: cksm %0,2\n" /* do checksum on ints */
- " jo 0b\n"
- : "=&d" (sum)
- : "d" (iph), "d" (ihl*4)
- : "cc", "memory", "2", "3" );
-#endif /* __s390x__ */
- return csum_fold(sum);
+ return csum_fold(csum_partial(iph, ihl*4, 0));
}
/*
@@ -190,47 +124,47 @@ csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr,
unsigned int sum)
{
#ifndef __s390x__
- __asm__ __volatile__ (
- " alr %0,%1\n" /* sum += saddr */
- " brc 12,0f\n"
- " ahi %0,1\n" /* add carry */
+ asm volatile(
+ " alr %0,%1\n" /* sum += saddr */
+ " brc 12,0f\n"
+ " ahi %0,1\n" /* add carry */
"0:"
- : "+&d" (sum) : "d" (saddr) : "cc" );
- __asm__ __volatile__ (
- " alr %0,%1\n" /* sum += daddr */
- " brc 12,1f\n"
- " ahi %0,1\n" /* add carry */
+ : "+&d" (sum) : "d" (saddr) : "cc");
+ asm volatile(
+ " alr %0,%1\n" /* sum += daddr */
+ " brc 12,1f\n"
+ " ahi %0,1\n" /* add carry */
"1:"
- : "+&d" (sum) : "d" (daddr) : "cc" );
- __asm__ __volatile__ (
- " alr %0,%1\n" /* sum += (len<<16) + (proto<<8) */
- " brc 12,2f\n"
- " ahi %0,1\n" /* add carry */
+ : "+&d" (sum) : "d" (daddr) : "cc");
+ asm volatile(
+ " alr %0,%1\n" /* sum += (len<<16) + (proto<<8) */
+ " brc 12,2f\n"
+ " ahi %0,1\n" /* add carry */
"2:"
: "+&d" (sum)
: "d" (((unsigned int) len<<16) + (unsigned int) proto)
- : "cc" );
+ : "cc");
#else /* __s390x__ */
- __asm__ __volatile__ (
- " lgfr %0,%0\n"
- " algr %0,%1\n" /* sum += saddr */
- " brc 12,0f\n"
- " aghi %0,1\n" /* add carry */
- "0: algr %0,%2\n" /* sum += daddr */
- " brc 12,1f\n"
- " aghi %0,1\n" /* add carry */
- "1: algfr %0,%3\n" /* sum += (len<<16) + proto */
- " brc 12,2f\n"
- " aghi %0,1\n" /* add carry */
- "2: srlg 0,%0,32\n"
- " alr %0,0\n" /* fold to 32 bits */
- " brc 12,3f\n"
- " ahi %0,1\n" /* add carry */
- "3: llgfr %0,%0"
+ asm volatile(
+ " lgfr %0,%0\n"
+ " algr %0,%1\n" /* sum += saddr */
+ " brc 12,0f\n"
+ " aghi %0,1\n" /* add carry */
+ "0: algr %0,%2\n" /* sum += daddr */
+ " brc 12,1f\n"
+ " aghi %0,1\n" /* add carry */
+ "1: algfr %0,%3\n" /* sum += (len<<16) + proto */
+ " brc 12,2f\n"
+ " aghi %0,1\n" /* add carry */
+ "2: srlg 0,%0,32\n"
+ " alr %0,0\n" /* fold to 32 bits */
+ " brc 12,3f\n"
+ " ahi %0,1\n" /* add carry */
+ "3: llgfr %0,%0"
: "+&d" (sum)
: "d" (saddr), "d" (daddr),
"d" (((unsigned int) len<<16) + (unsigned int) proto)
- : "cc", "0" );
+ : "cc", "0");
#endif /* __s390x__ */
return sum;
}
diff --git a/include/asm-s390/cio.h b/include/asm-s390/cio.h
index da063cd5f0a0..81287d86329d 100644
--- a/include/asm-s390/cio.h
+++ b/include/asm-s390/cio.h
@@ -275,6 +275,12 @@ struct ccw_dev_id {
u16 devno;
};
+static inline int ccw_dev_id_is_equal(struct ccw_dev_id *dev_id1,
+ struct ccw_dev_id *dev_id2)
+{
+ return !memcmp(dev_id1, dev_id2, sizeof(struct ccw_dev_id));
+}
+
extern int diag210(struct diag210 *addr);
extern void wait_cons_dev(void);
diff --git a/include/asm-s390/div64.h b/include/asm-s390/div64.h
index af098dc3cf59..6cd978cefb28 100644
--- a/include/asm-s390/div64.h
+++ b/include/asm-s390/div64.h
@@ -1,49 +1 @@
-#ifndef __S390_DIV64
-#define __S390_DIV64
-
-#ifndef __s390x__
-
-/* for do_div "base" needs to be smaller than 2^31-1 */
-#define do_div(n, base) ({ \
- unsigned long long __n = (n); \
- unsigned long __r; \
- \
- asm (" slr 0,0\n" \
- " l 1,%1\n" \
- " srdl 0,1\n" \
- " dr 0,%2\n" \
- " alr 1,1\n" \
- " alr 0,0\n" \
- " lhi 2,1\n" \
- " n 2,%1\n" \
- " alr 0,2\n" \
- " clr 0,%2\n" \
- " jl 0f\n" \
- " slr 0,%2\n" \
- " ahi 1,1\n" \
- "0: st 1,%1\n" \
- " l 1,4+%1\n" \
- " srdl 0,1\n" \
- " dr 0,%2\n" \
- " alr 1,1\n" \
- " alr 0,0\n" \
- " lhi 2,1\n" \
- " n 2,4+%1\n" \
- " alr 0,2\n" \
- " clr 0,%2\n" \
- " jl 1f\n" \
- " slr 0,%2\n" \
- " ahi 1,1\n" \
- "1: st 1,4+%1\n" \
- " lr %0,0" \
- : "=d" (__r), "=m" (__n) \
- : "d" (base), "m" (__n) : "0", "1", "2", "cc" ); \
- (n) = (__n); \
- __r; \
-})
-
-#else /* __s390x__ */
#include <asm-generic/div64.h>
-#endif /* __s390x__ */
-
-#endif
diff --git a/include/asm-s390/ebcdic.h b/include/asm-s390/ebcdic.h
index 15fd2eda6c90..7f6f641d32f4 100644
--- a/include/asm-s390/ebcdic.h
+++ b/include/asm-s390/ebcdic.h
@@ -26,16 +26,16 @@ codepage_convert(const __u8 *codepage, volatile __u8 * addr, unsigned long nr)
{
if (nr-- <= 0)
return;
- __asm__ __volatile__(
- " bras 1,1f\n"
- " tr 0(1,%0),0(%2)\n"
- "0: tr 0(256,%0),0(%2)\n"
- " la %0,256(%0)\n"
- "1: ahi %1,-256\n"
- " jnm 0b\n"
- " ex %1,0(1)"
- : "+&a" (addr), "+&a" (nr)
- : "a" (codepage) : "cc", "memory", "1" );
+ asm volatile(
+ " bras 1,1f\n"
+ " tr 0(1,%0),0(%2)\n"
+ "0: tr 0(256,%0),0(%2)\n"
+ " la %0,256(%0)\n"
+ "1: ahi %1,-256\n"
+ " jnm 0b\n"
+ " ex %1,0(1)"
+ : "+&a" (addr), "+&a" (nr)
+ : "a" (codepage) : "cc", "memory", "1");
}
#define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr)
diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h
index e84b7ef54aac..c2f6a8782d31 100644
--- a/include/asm-s390/hardirq.h
+++ b/include/asm-s390/hardirq.h
@@ -32,6 +32,6 @@ typedef struct {
#define HARDIRQ_BITS 8
-extern void account_ticks(struct pt_regs *);
+extern void account_ticks(void);
#endif /* __ASM_HARDIRQ_H */
diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h
index a6cc27e77007..efb7de9c1c6b 100644
--- a/include/asm-s390/io.h
+++ b/include/asm-s390/io.h
@@ -27,18 +27,16 @@
static inline unsigned long virt_to_phys(volatile void * address)
{
unsigned long real_address;
- __asm__ (
+ asm volatile(
#ifndef __s390x__
- " lra %0,0(%1)\n"
- " jz 0f\n"
- " sr %0,%0\n"
+ " lra %0,0(%1)\n"
#else /* __s390x__ */
- " lrag %0,0(%1)\n"
- " jz 0f\n"
- " slgr %0,%0\n"
+ " lrag %0,0(%1)\n"
#endif /* __s390x__ */
+ " jz 0f\n"
+ " la %0,0\n"
"0:"
- : "=a" (real_address) : "a" (address) : "cc" );
+ : "=a" (real_address) : "a" (address) : "cc");
return real_address;
}
@@ -47,11 +45,6 @@ static inline void * phys_to_virt(unsigned long address)
return __io_virt(address);
}
-/*
- * Change "struct page" to physical address.
- */
-#define page_to_phys(page) ((page - mem_map) << PAGE_SHIFT)
-
extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
static inline void * ioremap (unsigned long offset, unsigned long size)
diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h
index bd1a721f7aa2..7da991a858f8 100644
--- a/include/asm-s390/irq.h
+++ b/include/asm-s390/irq.h
@@ -19,8 +19,5 @@ enum interruption_class {
NR_IRQS,
};
-#define touch_nmi_watchdog() do { } while(0)
-
#endif /* __KERNEL__ */
#endif
-
diff --git a/include/asm-s390/irq_regs.h b/include/asm-s390/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-s390/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-s390/irqflags.h b/include/asm-s390/irqflags.h
index 3b566a5b3cc7..3f26131120b7 100644
--- a/include/asm-s390/irqflags.h
+++ b/include/asm-s390/irqflags.h
@@ -10,43 +10,93 @@
#ifdef __KERNEL__
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+
+/* store then or system mask. */
+#define __raw_local_irq_stosm(__or) \
+({ \
+ unsigned long __mask; \
+ asm volatile( \
+ " stosm %0,%1" \
+ : "=Q" (__mask) : "i" (__or) : "memory"); \
+ __mask; \
+})
+
+/* store then and system mask. */
+#define __raw_local_irq_stnsm(__and) \
+({ \
+ unsigned long __mask; \
+ asm volatile( \
+ " stnsm %0,%1" \
+ : "=Q" (__mask) : "i" (__and) : "memory"); \
+ __mask; \
+})
+
+/* set system mask. */
+#define __raw_local_irq_ssm(__mask) \
+({ \
+ asm volatile("ssm %0" : : "Q" (__mask) : "memory"); \
+})
+
+#else /* __GNUC__ */
+
+/* store then or system mask. */
+#define __raw_local_irq_stosm(__or) \
+({ \
+ unsigned long __mask; \
+ asm volatile( \
+ " stosm 0(%1),%2" \
+ : "=m" (__mask) \
+ : "a" (&__mask), "i" (__or) : "memory"); \
+ __mask; \
+})
+
+/* store then and system mask. */
+#define __raw_local_irq_stnsm(__and) \
+({ \
+ unsigned long __mask; \
+ asm volatile( \
+ " stnsm 0(%1),%2" \
+ : "=m" (__mask) \
+ : "a" (&__mask), "i" (__and) : "memory"); \
+ __mask; \
+})
+
+/* set system mask. */
+#define __raw_local_irq_ssm(__mask) \
+({ \
+ asm volatile( \
+ " ssm 0(%0)" \
+ : : "a" (&__mask), "m" (__mask) : "memory"); \
+})
+
+#endif /* __GNUC__ */
+
/* interrupt control.. */
-#define raw_local_irq_enable() ({ \
- unsigned long __dummy; \
- __asm__ __volatile__ ( \
- "stosm 0(%1),0x03" \
- : "=m" (__dummy) : "a" (&__dummy) : "memory" ); \
- })
-
-#define raw_local_irq_disable() ({ \
- unsigned long __flags; \
- __asm__ __volatile__ ( \
- "stnsm 0(%1),0xfc" : "=m" (__flags) : "a" (&__flags) ); \
- __flags; \
- })
-
-#define raw_local_save_flags(x) \
-do { \
- typecheck(unsigned long, x); \
- __asm__ __volatile__("stosm 0(%1),0" : "=m" (x) : "a" (&x), "m" (x) ); \
-} while (0)
+static inline unsigned long raw_local_irq_enable(void)
+{
+ return __raw_local_irq_stosm(0x03);
+}
-#define raw_local_irq_restore(x) \
-do { \
- typecheck(unsigned long, x); \
- __asm__ __volatile__("ssm 0(%0)" : : "a" (&x), "m" (x) : "memory"); \
+static inline unsigned long raw_local_irq_disable(void)
+{
+ return __raw_local_irq_stnsm(0xfc);
+}
+
+#define raw_local_save_flags(x) \
+do { \
+ typecheck(unsigned long, x); \
+ (x) = __raw_local_irq_stosm(0x00); \
} while (0)
-#define raw_irqs_disabled() \
-({ \
- unsigned long flags; \
- raw_local_save_flags(flags); \
- !((flags >> __FLAG_SHIFT) & 3); \
-})
+static inline void raw_local_irq_restore(unsigned long flags)
+{
+ __raw_local_irq_ssm(flags);
+}
static inline int raw_irqs_disabled_flags(unsigned long flags)
{
- return !((flags >> __FLAG_SHIFT) & 3);
+ return !(flags & (3UL << (BITS_PER_LONG - 8)));
}
/* For spinlocks etc */
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index 18695d10dedf..06583ed0bde7 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -359,7 +359,7 @@ extern struct _lowcore *lowcore_ptr[];
static inline void set_prefix(__u32 address)
{
- __asm__ __volatile__ ("spx %0" : : "m" (address) : "memory" );
+ asm volatile("spx %0" : : "m" (address) : "memory");
}
#define __PANIC_MAGIC 0xDEADC0DE
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index b2628dc5c490..363ea761d5ee 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -22,89 +22,45 @@
#include <asm/setup.h>
#ifndef __ASSEMBLY__
-#ifndef __s390x__
-
-static inline void clear_page(void *page)
-{
- register_pair rp;
-
- rp.subreg.even = (unsigned long) page;
- rp.subreg.odd = (unsigned long) 4096;
- asm volatile (" slr 1,1\n"
- " mvcl %0,0"
- : "+&a" (rp) : : "memory", "cc", "1" );
-}
-
-static inline void copy_page(void *to, void *from)
-{
- if (MACHINE_HAS_MVPG)
- asm volatile (" sr 0,0\n"
- " mvpg %0,%1"
- : : "a" ((void *)(to)), "a" ((void *)(from))
- : "memory", "cc", "0" );
- else
- asm volatile (" mvc 0(256,%0),0(%1)\n"
- " mvc 256(256,%0),256(%1)\n"
- " mvc 512(256,%0),512(%1)\n"
- " mvc 768(256,%0),768(%1)\n"
- " mvc 1024(256,%0),1024(%1)\n"
- " mvc 1280(256,%0),1280(%1)\n"
- " mvc 1536(256,%0),1536(%1)\n"
- " mvc 1792(256,%0),1792(%1)\n"
- " mvc 2048(256,%0),2048(%1)\n"
- " mvc 2304(256,%0),2304(%1)\n"
- " mvc 2560(256,%0),2560(%1)\n"
- " mvc 2816(256,%0),2816(%1)\n"
- " mvc 3072(256,%0),3072(%1)\n"
- " mvc 3328(256,%0),3328(%1)\n"
- " mvc 3584(256,%0),3584(%1)\n"
- " mvc 3840(256,%0),3840(%1)\n"
- : : "a"((void *)(to)),"a"((void *)(from))
- : "memory" );
-}
-
-#else /* __s390x__ */
-
static inline void clear_page(void *page)
{
- asm volatile (" lgr 2,%0\n"
- " lghi 3,4096\n"
- " slgr 1,1\n"
- " mvcl 2,0"
- : : "a" ((void *) (page))
- : "memory", "cc", "1", "2", "3" );
+ register unsigned long reg1 asm ("1") = 0;
+ register void *reg2 asm ("2") = page;
+ register unsigned long reg3 asm ("3") = 4096;
+ asm volatile(
+ " mvcl 2,0"
+ : "+d" (reg2), "+d" (reg3) : "d" (reg1) : "memory", "cc");
}
static inline void copy_page(void *to, void *from)
{
- if (MACHINE_HAS_MVPG)
- asm volatile (" sgr 0,0\n"
- " mvpg %0,%1"
- : : "a" ((void *)(to)), "a" ((void *)(from))
- : "memory", "cc", "0" );
- else
- asm volatile (" mvc 0(256,%0),0(%1)\n"
- " mvc 256(256,%0),256(%1)\n"
- " mvc 512(256,%0),512(%1)\n"
- " mvc 768(256,%0),768(%1)\n"
- " mvc 1024(256,%0),1024(%1)\n"
- " mvc 1280(256,%0),1280(%1)\n"
- " mvc 1536(256,%0),1536(%1)\n"
- " mvc 1792(256,%0),1792(%1)\n"
- " mvc 2048(256,%0),2048(%1)\n"
- " mvc 2304(256,%0),2304(%1)\n"
- " mvc 2560(256,%0),2560(%1)\n"
- " mvc 2816(256,%0),2816(%1)\n"
- " mvc 3072(256,%0),3072(%1)\n"
- " mvc 3328(256,%0),3328(%1)\n"
- " mvc 3584(256,%0),3584(%1)\n"
- " mvc 3840(256,%0),3840(%1)\n"
- : : "a"((void *)(to)),"a"((void *)(from))
- : "memory" );
+ if (MACHINE_HAS_MVPG) {
+ register unsigned long reg0 asm ("0") = 0;
+ asm volatile(
+ " mvpg %0,%1"
+ : : "a" (to), "a" (from), "d" (reg0)
+ : "memory", "cc");
+ } else
+ asm volatile(
+ " mvc 0(256,%0),0(%1)\n"
+ " mvc 256(256,%0),256(%1)\n"
+ " mvc 512(256,%0),512(%1)\n"
+ " mvc 768(256,%0),768(%1)\n"
+ " mvc 1024(256,%0),1024(%1)\n"
+ " mvc 1280(256,%0),1280(%1)\n"
+ " mvc 1536(256,%0),1536(%1)\n"
+ " mvc 1792(256,%0),1792(%1)\n"
+ " mvc 2048(256,%0),2048(%1)\n"
+ " mvc 2304(256,%0),2304(%1)\n"
+ " mvc 2560(256,%0),2560(%1)\n"
+ " mvc 2816(256,%0),2816(%1)\n"
+ " mvc 3072(256,%0),3072(%1)\n"
+ " mvc 3328(256,%0),3328(%1)\n"
+ " mvc 3584(256,%0),3584(%1)\n"
+ " mvc 3840(256,%0),3840(%1)\n"
+ : : "a" (to), "a" (from) : "memory");
}
-#endif /* __s390x__ */
-
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
@@ -159,7 +115,7 @@ extern unsigned int default_storage_key;
static inline void
page_set_storage_key(unsigned long addr, unsigned int skey)
{
- asm volatile ( "sske %0,%1" : : "d" (skey), "a" (addr) );
+ asm volatile("sske %0,%1" : : "d" (skey), "a" (addr));
}
static inline unsigned int
@@ -167,8 +123,7 @@ page_get_storage_key(unsigned long addr)
{
unsigned int skey;
- asm volatile ( "iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0) );
-
+ asm volatile("iske %0,%1" : "=d" (skey) : "a" (addr), "0" (0));
return skey;
}
@@ -182,6 +137,7 @@ page_get_storage_key(unsigned long addr)
#define __pa(x) (unsigned long)(x)
#define __va(x) (void *)(unsigned long)(x)
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
#define pfn_valid(pfn) ((pfn) < max_mapnr)
#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
diff --git a/include/asm-s390/percpu.h b/include/asm-s390/percpu.h
index 495ad99c7635..9ea7f1023e57 100644
--- a/include/asm-s390/percpu.h
+++ b/include/asm-s390/percpu.h
@@ -16,7 +16,7 @@
#if defined(__s390x__) && defined(MODULE)
#define __reloc_hide(var,offset) (*({ \
- extern int simple_indentifier_##var(void); \
+ extern int simple_identifier_##var(void); \
unsigned long *__ptr; \
asm ( "larl %0,per_cpu__"#var"@GOTENT" \
: "=a" (__ptr) : "X" (per_cpu__##var) ); \
@@ -25,7 +25,7 @@
#else
#define __reloc_hide(var, offset) (*({ \
- extern int simple_indentifier_##var(void); \
+ extern int simple_identifier_##var(void); \
unsigned long __ptr; \
asm ( "" : "=a" (__ptr) : "0" (&per_cpu__##var) ); \
(typeof(&per_cpu__##var)) (__ptr + (offset)); }))
diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h
index 803bc7064418..28619de5ecae 100644
--- a/include/asm-s390/pgalloc.h
+++ b/include/asm-s390/pgalloc.h
@@ -116,7 +116,7 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
static inline void
pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
{
- pmd_populate_kernel(mm, pmd, (pte_t *)((page-mem_map) << PAGE_SHIFT));
+ pmd_populate_kernel(mm, pmd, (pte_t *)page_to_phys(page));
}
/*
diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h
index e965309fedac..36bb6dacf008 100644
--- a/include/asm-s390/pgtable.h
+++ b/include/asm-s390/pgtable.h
@@ -31,9 +31,9 @@
* the S390 page table tree.
*/
#ifndef __ASSEMBLY__
+#include <linux/mm_types.h>
#include <asm/bug.h>
#include <asm/processor.h>
-#include <linux/threads.h>
struct vm_area_struct; /* forward declaration (include/linux/mm.h) */
struct mm_struct;
@@ -200,18 +200,45 @@ extern char empty_zero_page[PAGE_SIZE];
*/
/* Hardware bits in the page table entry */
-#define _PAGE_RO 0x200 /* HW read-only */
-#define _PAGE_INVALID 0x400 /* HW invalid */
+#define _PAGE_RO 0x200 /* HW read-only bit */
+#define _PAGE_INVALID 0x400 /* HW invalid bit */
+#define _PAGE_SWT 0x001 /* SW pte type bit t */
+#define _PAGE_SWX 0x002 /* SW pte type bit x */
-/* Mask and six different types of pages. */
-#define _PAGE_TYPE_MASK 0x601
+/* Six different types of pages. */
#define _PAGE_TYPE_EMPTY 0x400
#define _PAGE_TYPE_NONE 0x401
-#define _PAGE_TYPE_SWAP 0x600
-#define _PAGE_TYPE_FILE 0x601
+#define _PAGE_TYPE_SWAP 0x403
+#define _PAGE_TYPE_FILE 0x601 /* bit 0x002 is used for offset !! */
#define _PAGE_TYPE_RO 0x200
#define _PAGE_TYPE_RW 0x000
+/*
+ * PTE type bits are rather complicated. handle_pte_fault uses pte_present,
+ * pte_none and pte_file to find out the pte type WITHOUT holding the page
+ * table lock. ptep_clear_flush on the other hand uses ptep_clear_flush to
+ * invalidate a given pte. ipte sets the hw invalid bit and clears all tlbs
+ * for the page. The page table entry is set to _PAGE_TYPE_EMPTY afterwards.
+ * This change is done while holding the lock, but the intermediate step
+ * of a previously valid pte with the hw invalid bit set can be observed by
+ * handle_pte_fault. That makes it necessary that all valid pte types with
+ * the hw invalid bit set must be distinguishable from the four pte types
+ * empty, none, swap and file.
+ *
+ * irxt ipte irxt
+ * _PAGE_TYPE_EMPTY 1000 -> 1000
+ * _PAGE_TYPE_NONE 1001 -> 1001
+ * _PAGE_TYPE_SWAP 1011 -> 1011
+ * _PAGE_TYPE_FILE 11?1 -> 11?1
+ * _PAGE_TYPE_RO 0100 -> 1100
+ * _PAGE_TYPE_RW 0000 -> 1000
+ *
+ * pte_none is true for bits combinations 1000, 1100
+ * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
+ * pte_file is true for bits combinations 1101, 1111
+ * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid.
+ */
+
#ifndef __s390x__
/* Bits in the segment table entry */
@@ -365,18 +392,21 @@ static inline int pmd_bad(pmd_t pmd)
static inline int pte_none(pte_t pte)
{
- return (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_EMPTY;
+ return (pte_val(pte) & _PAGE_INVALID) && !(pte_val(pte) & _PAGE_SWT);
}
static inline int pte_present(pte_t pte)
{
- return !(pte_val(pte) & _PAGE_INVALID) ||
- (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_NONE;
+ unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT | _PAGE_SWX;
+ return (pte_val(pte) & mask) == _PAGE_TYPE_NONE ||
+ (!(pte_val(pte) & _PAGE_INVALID) &&
+ !(pte_val(pte) & _PAGE_SWT));
}
static inline int pte_file(pte_t pte)
{
- return (pte_val(pte) & _PAGE_TYPE_MASK) == _PAGE_TYPE_FILE;
+ unsigned long mask = _PAGE_RO | _PAGE_INVALID | _PAGE_SWT;
+ return (pte_val(pte) & mask) == _PAGE_TYPE_FILE;
}
#define pte_same(a,b) (pte_val(a) == pte_val(b))
@@ -554,9 +584,10 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
/* ipte in zarch mode can do the math */
pte_t *pto = ptep;
#endif
- asm volatile ("ipte %2,%3"
- : "=m" (*ptep) : "m" (*ptep),
- "a" (pto), "a" (address) );
+ asm volatile(
+ " ipte %2,%3"
+ : "=m" (*ptep) : "m" (*ptep),
+ "a" (pto), "a" (address));
}
pte_val(*ptep) = _PAGE_TYPE_EMPTY;
}
@@ -596,30 +627,31 @@ ptep_establish(struct vm_area_struct *vma,
* should therefore only be called if it is not mapped in any
* address space.
*/
-#define page_test_and_clear_dirty(_page) \
-({ \
- struct page *__page = (_page); \
- unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \
- int __skey = page_get_storage_key(__physpage); \
- if (__skey & _PAGE_CHANGED) \
- page_set_storage_key(__physpage, __skey & ~_PAGE_CHANGED);\
- (__skey & _PAGE_CHANGED); \
-})
+static inline int page_test_and_clear_dirty(struct page *page)
+{
+ unsigned long physpage = page_to_phys(page);
+ int skey = page_get_storage_key(physpage);
+
+ if (skey & _PAGE_CHANGED)
+ page_set_storage_key(physpage, skey & ~_PAGE_CHANGED);
+ return skey & _PAGE_CHANGED;
+}
/*
* Test and clear referenced bit in storage key.
*/
-#define page_test_and_clear_young(page) \
-({ \
- struct page *__page = (page); \
- unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \
- int __ccode; \
- asm volatile ("rrbe 0,%1\n\t" \
- "ipm %0\n\t" \
- "srl %0,28\n\t" \
- : "=d" (__ccode) : "a" (__physpage) : "cc" ); \
- (__ccode & 2); \
-})
+static inline int page_test_and_clear_young(struct page *page)
+{
+ unsigned long physpage = page_to_phys(page);
+ int ccode;
+
+ asm volatile(
+ " rrbe 0,%1\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode) : "a" (physpage) : "cc" );
+ return ccode & 2;
+}
/*
* Conversion functions: convert a page and protection to a page entry,
@@ -632,32 +664,28 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
return __pte;
}
-#define mk_pte(pg, pgprot) \
-({ \
- struct page *__page = (pg); \
- pgprot_t __pgprot = (pgprot); \
- unsigned long __physpage = __pa((__page-mem_map) << PAGE_SHIFT); \
- pte_t __pte = mk_pte_phys(__physpage, __pgprot); \
- __pte; \
-})
+static inline pte_t mk_pte(struct page *page, pgprot_t pgprot)
+{
+ unsigned long physpage = page_to_phys(page);
+
+ return mk_pte_phys(physpage, pgprot);
+}
+
+static inline pte_t pfn_pte(unsigned long pfn, pgprot_t pgprot)
+{
+ unsigned long physpage = __pa((pfn) << PAGE_SHIFT);
-#define pfn_pte(pfn, pgprot) \
-({ \
- pgprot_t __pgprot = (pgprot); \
- unsigned long __physpage = __pa((pfn) << PAGE_SHIFT); \
- pte_t __pte = mk_pte_phys(__physpage, __pgprot); \
- __pte; \
-})
+ return mk_pte_phys(physpage, pgprot);
+}
#ifdef __s390x__
-#define pfn_pmd(pfn, pgprot) \
-({ \
- pgprot_t __pgprot = (pgprot); \
- unsigned long __physpage = __pa((pfn) << PAGE_SHIFT); \
- pmd_t __pmd = __pmd(__physpage + pgprot_val(__pgprot)); \
- __pmd; \
-})
+static inline pmd_t pfn_pmd(unsigned long pfn, pgprot_t pgprot)
+{
+ unsigned long physpage = __pa((pfn) << PAGE_SHIFT);
+
+ return __pmd(physpage + pgprot_val(pgprot));
+}
#endif /* __s390x__ */
@@ -666,11 +694,11 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
#define pmd_page_vaddr(pmd) (pmd_val(pmd) & PAGE_MASK)
-#define pmd_page(pmd) (mem_map+(pmd_val(pmd) >> PAGE_SHIFT))
+#define pmd_page(pmd) pfn_to_page(pmd_val(pmd) >> PAGE_SHIFT)
#define pgd_page_vaddr(pgd) (pgd_val(pgd) & PAGE_MASK)
-#define pgd_page(pgd) (mem_map+(pgd_val(pgd) >> PAGE_SHIFT))
+#define pgd_page(pgd) pfn_to_page(pgd_val(pgd) >> PAGE_SHIFT)
/* to find an entry in a page-table-directory */
#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index 578c2209fa76..cbbedc63ba25 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -13,7 +13,6 @@
#ifndef __ASM_S390_PROCESSOR_H
#define __ASM_S390_PROCESSOR_H
-#include <asm/page.h>
#include <asm/ptrace.h>
#ifdef __KERNEL__
@@ -21,7 +20,7 @@
* Default implementation of macro that returns current
* instruction pointer ("program counter").
*/
-#define current_text_addr() ({ void *pc; __asm__("basr %0,0":"=a"(pc)); pc; })
+#define current_text_addr() ({ void *pc; asm("basr %0,0" : "=a" (pc)); pc; })
/*
* CPU type and hardware bug flags. Kept separately for each CPU.
@@ -202,7 +201,7 @@ unsigned long get_wchan(struct task_struct *p);
static inline void cpu_relax(void)
{
if (MACHINE_HAS_DIAG44)
- asm volatile ("diag 0,0,68" : : : "memory");
+ asm volatile("diag 0,0,68" : : : "memory");
else
barrier();
}
@@ -213,9 +212,9 @@ static inline void cpu_relax(void)
static inline void __load_psw(psw_t psw)
{
#ifndef __s390x__
- asm volatile ("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+ asm volatile("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc");
#else
- asm volatile ("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+ asm volatile("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc");
#endif
}
@@ -232,20 +231,20 @@ static inline void __load_psw_mask (unsigned long mask)
psw.mask = mask;
#ifndef __s390x__
- asm volatile (
- " basr %0,0\n"
- "0: ahi %0,1f-0b\n"
- " st %0,4(%1)\n"
- " lpsw 0(%1)\n"
+ asm volatile(
+ " basr %0,0\n"
+ "0: ahi %0,1f-0b\n"
+ " st %0,4(%1)\n"
+ " lpsw 0(%1)\n"
"1:"
- : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc" );
+ : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc");
#else /* __s390x__ */
- asm volatile (
- " larl %0,1f\n"
- " stg %0,8(%1)\n"
- " lpswe 0(%1)\n"
+ asm volatile(
+ " larl %0,1f\n"
+ " stg %0,8(%1)\n"
+ " lpswe 0(%1)\n"
"1:"
- : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc" );
+ : "=&d" (addr) : "a" (&psw), "m" (psw) : "memory", "cc");
#endif /* __s390x__ */
}
@@ -274,56 +273,57 @@ static inline void disabled_wait(unsigned long code)
* the processor is dead afterwards
*/
#ifndef __s390x__
- asm volatile (" stctl 0,0,0(%2)\n"
- " ni 0(%2),0xef\n" /* switch off protection */
- " lctl 0,0,0(%2)\n"
- " stpt 0xd8\n" /* store timer */
- " stckc 0xe0\n" /* store clock comparator */
- " stpx 0x108\n" /* store prefix register */
- " stam 0,15,0x120\n" /* store access registers */
- " std 0,0x160\n" /* store f0 */
- " std 2,0x168\n" /* store f2 */
- " std 4,0x170\n" /* store f4 */
- " std 6,0x178\n" /* store f6 */
- " stm 0,15,0x180\n" /* store general registers */
- " stctl 0,15,0x1c0\n" /* store control registers */
- " oi 0x1c0,0x10\n" /* fake protection bit */
- " lpsw 0(%1)"
- : "=m" (ctl_buf)
- : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
+ asm volatile(
+ " stctl 0,0,0(%2)\n"
+ " ni 0(%2),0xef\n" /* switch off protection */
+ " lctl 0,0,0(%2)\n"
+ " stpt 0xd8\n" /* store timer */
+ " stckc 0xe0\n" /* store clock comparator */
+ " stpx 0x108\n" /* store prefix register */
+ " stam 0,15,0x120\n" /* store access registers */
+ " std 0,0x160\n" /* store f0 */
+ " std 2,0x168\n" /* store f2 */
+ " std 4,0x170\n" /* store f4 */
+ " std 6,0x178\n" /* store f6 */
+ " stm 0,15,0x180\n" /* store general registers */
+ " stctl 0,15,0x1c0\n" /* store control registers */
+ " oi 0x1c0,0x10\n" /* fake protection bit */
+ " lpsw 0(%1)"
+ : "=m" (ctl_buf)
+ : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc");
#else /* __s390x__ */
- asm volatile (" stctg 0,0,0(%2)\n"
- " ni 4(%2),0xef\n" /* switch off protection */
- " lctlg 0,0,0(%2)\n"
- " lghi 1,0x1000\n"
- " stpt 0x328(1)\n" /* store timer */
- " stckc 0x330(1)\n" /* store clock comparator */
- " stpx 0x318(1)\n" /* store prefix register */
- " stam 0,15,0x340(1)\n" /* store access registers */
- " stfpc 0x31c(1)\n" /* store fpu control */
- " std 0,0x200(1)\n" /* store f0 */
- " std 1,0x208(1)\n" /* store f1 */
- " std 2,0x210(1)\n" /* store f2 */
- " std 3,0x218(1)\n" /* store f3 */
- " std 4,0x220(1)\n" /* store f4 */
- " std 5,0x228(1)\n" /* store f5 */
- " std 6,0x230(1)\n" /* store f6 */
- " std 7,0x238(1)\n" /* store f7 */
- " std 8,0x240(1)\n" /* store f8 */
- " std 9,0x248(1)\n" /* store f9 */
- " std 10,0x250(1)\n" /* store f10 */
- " std 11,0x258(1)\n" /* store f11 */
- " std 12,0x260(1)\n" /* store f12 */
- " std 13,0x268(1)\n" /* store f13 */
- " std 14,0x270(1)\n" /* store f14 */
- " std 15,0x278(1)\n" /* store f15 */
- " stmg 0,15,0x280(1)\n" /* store general registers */
- " stctg 0,15,0x380(1)\n" /* store control registers */
- " oi 0x384(1),0x10\n" /* fake protection bit */
- " lpswe 0(%1)"
- : "=m" (ctl_buf)
- : "a" (&dw_psw), "a" (&ctl_buf),
- "m" (dw_psw) : "cc", "0", "1");
+ asm volatile(
+ " stctg 0,0,0(%2)\n"
+ " ni 4(%2),0xef\n" /* switch off protection */
+ " lctlg 0,0,0(%2)\n"
+ " lghi 1,0x1000\n"
+ " stpt 0x328(1)\n" /* store timer */
+ " stckc 0x330(1)\n" /* store clock comparator */
+ " stpx 0x318(1)\n" /* store prefix register */
+ " stam 0,15,0x340(1)\n"/* store access registers */
+ " stfpc 0x31c(1)\n" /* store fpu control */
+ " std 0,0x200(1)\n" /* store f0 */
+ " std 1,0x208(1)\n" /* store f1 */
+ " std 2,0x210(1)\n" /* store f2 */
+ " std 3,0x218(1)\n" /* store f3 */
+ " std 4,0x220(1)\n" /* store f4 */
+ " std 5,0x228(1)\n" /* store f5 */
+ " std 6,0x230(1)\n" /* store f6 */
+ " std 7,0x238(1)\n" /* store f7 */
+ " std 8,0x240(1)\n" /* store f8 */
+ " std 9,0x248(1)\n" /* store f9 */
+ " std 10,0x250(1)\n" /* store f10 */
+ " std 11,0x258(1)\n" /* store f11 */
+ " std 12,0x260(1)\n" /* store f12 */
+ " std 13,0x268(1)\n" /* store f13 */
+ " std 14,0x270(1)\n" /* store f14 */
+ " std 15,0x278(1)\n" /* store f15 */
+ " stmg 0,15,0x280(1)\n"/* store general registers */
+ " stctg 0,15,0x380(1)\n"/* store control registers */
+ " oi 0x384(1),0x10\n"/* fake protection bit */
+ " lpswe 0(%1)"
+ : "=m" (ctl_buf)
+ : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc", "0");
#endif /* __s390x__ */
}
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
index 4d75d77b0f99..7b768c5c68a8 100644
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -472,6 +472,7 @@ struct user_regs_struct
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
+#define regs_return_value(regs)((regs)->gprs[2])
#define profile_pc(regs) instruction_pointer(regs)
extern void show_regs(struct pt_regs * regs);
#endif
@@ -479,7 +480,7 @@ extern void show_regs(struct pt_regs * regs);
static inline void
psw_set_key(unsigned int key)
{
- asm volatile ( "spka 0(%0)" : : "d" (key) );
+ asm volatile("spka 0(%0)" : : "d" (key));
}
#endif /* __ASSEMBLY__ */
diff --git a/include/asm-s390/qdio.h b/include/asm-s390/qdio.h
index a2f37a9353d3..7189c79bc673 100644
--- a/include/asm-s390/qdio.h
+++ b/include/asm-s390/qdio.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm/qdio.h
+ * linux/include/asm-s390/qdio.h
*
* Linux for S/390 QDIO base support, Hipersocket base support
* version 2
diff --git a/include/asm-s390/rwsem.h b/include/asm-s390/rwsem.h
index 13ec16965150..90f4eccaa290 100644
--- a/include/asm-s390/rwsem.h
+++ b/include/asm-s390/rwsem.h
@@ -122,23 +122,23 @@ static inline void __down_read(struct rw_semaphore *sem)
{
signed long old, new;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: lr %1,%0\n"
- " ahi %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b"
+ " l %0,0(%3)\n"
+ "0: lr %1,%0\n"
+ " ahi %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: lgr %1,%0\n"
- " aghi %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b"
+ " lg %0,0(%3)\n"
+ "0: lgr %1,%0\n"
+ " aghi %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count),
- "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory" );
+ "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
if (old < 0)
rwsem_down_read_failed(sem);
}
@@ -150,27 +150,27 @@ static inline int __down_read_trylock(struct rw_semaphore *sem)
{
signed long old, new;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: ltr %1,%0\n"
- " jm 1f\n"
- " ahi %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b\n"
+ " l %0,0(%3)\n"
+ "0: ltr %1,%0\n"
+ " jm 1f\n"
+ " ahi %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b\n"
"1:"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: ltgr %1,%0\n"
- " jm 1f\n"
- " aghi %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b\n"
+ " lg %0,0(%3)\n"
+ "0: ltgr %1,%0\n"
+ " jm 1f\n"
+ " aghi %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b\n"
"1:"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count),
- "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory" );
+ "i" (RWSEM_ACTIVE_READ_BIAS) : "cc", "memory");
return old >= 0 ? 1 : 0;
}
@@ -182,23 +182,23 @@ static inline void __down_write_nested(struct rw_semaphore *sem, int subclass)
signed long old, new, tmp;
tmp = RWSEM_ACTIVE_WRITE_BIAS;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: lr %1,%0\n"
- " a %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b"
+ " l %0,0(%3)\n"
+ "0: lr %1,%0\n"
+ " a %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: lgr %1,%0\n"
- " ag %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b"
+ " lg %0,0(%3)\n"
+ "0: lgr %1,%0\n"
+ " ag %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count), "m" (tmp)
- : "cc", "memory" );
+ : "cc", "memory");
if (old != 0)
rwsem_down_write_failed(sem);
}
@@ -215,24 +215,24 @@ static inline int __down_write_trylock(struct rw_semaphore *sem)
{
signed long old;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%2)\n"
- "0: ltr %0,%0\n"
- " jnz 1f\n"
- " cs %0,%4,0(%2)\n"
- " jl 0b\n"
+ " l %0,0(%2)\n"
+ "0: ltr %0,%0\n"
+ " jnz 1f\n"
+ " cs %0,%4,0(%2)\n"
+ " jl 0b\n"
#else /* __s390x__ */
- " lg %0,0(%2)\n"
- "0: ltgr %0,%0\n"
- " jnz 1f\n"
- " csg %0,%4,0(%2)\n"
- " jl 0b\n"
+ " lg %0,0(%2)\n"
+ "0: ltgr %0,%0\n"
+ " jnz 1f\n"
+ " csg %0,%4,0(%2)\n"
+ " jl 0b\n"
#endif /* __s390x__ */
"1:"
- : "=&d" (old), "=m" (sem->count)
+ : "=&d" (old), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count),
- "d" (RWSEM_ACTIVE_WRITE_BIAS) : "cc", "memory" );
+ "d" (RWSEM_ACTIVE_WRITE_BIAS) : "cc", "memory");
return (old == RWSEM_UNLOCKED_VALUE) ? 1 : 0;
}
@@ -243,24 +243,24 @@ static inline void __up_read(struct rw_semaphore *sem)
{
signed long old, new;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: lr %1,%0\n"
- " ahi %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b"
+ " l %0,0(%3)\n"
+ "0: lr %1,%0\n"
+ " ahi %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: lgr %1,%0\n"
- " aghi %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b"
+ " lg %0,0(%3)\n"
+ "0: lgr %1,%0\n"
+ " aghi %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count),
"i" (-RWSEM_ACTIVE_READ_BIAS)
- : "cc", "memory" );
+ : "cc", "memory");
if (new < 0)
if ((new & RWSEM_ACTIVE_MASK) == 0)
rwsem_wake(sem);
@@ -274,23 +274,23 @@ static inline void __up_write(struct rw_semaphore *sem)
signed long old, new, tmp;
tmp = -RWSEM_ACTIVE_WRITE_BIAS;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: lr %1,%0\n"
- " a %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b"
+ " l %0,0(%3)\n"
+ "0: lr %1,%0\n"
+ " a %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: lgr %1,%0\n"
- " ag %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b"
+ " lg %0,0(%3)\n"
+ "0: lgr %1,%0\n"
+ " ag %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count), "m" (tmp)
- : "cc", "memory" );
+ : "cc", "memory");
if (new < 0)
if ((new & RWSEM_ACTIVE_MASK) == 0)
rwsem_wake(sem);
@@ -304,23 +304,23 @@ static inline void __downgrade_write(struct rw_semaphore *sem)
signed long old, new, tmp;
tmp = -RWSEM_WAITING_BIAS;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: lr %1,%0\n"
- " a %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b"
+ " l %0,0(%3)\n"
+ "0: lr %1,%0\n"
+ " a %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: lgr %1,%0\n"
- " ag %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b"
+ " lg %0,0(%3)\n"
+ "0: lgr %1,%0\n"
+ " ag %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count), "m" (tmp)
- : "cc", "memory" );
+ : "cc", "memory");
if (new > 1)
rwsem_downgrade_wake(sem);
}
@@ -332,23 +332,23 @@ static inline void rwsem_atomic_add(long delta, struct rw_semaphore *sem)
{
signed long old, new;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: lr %1,%0\n"
- " ar %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b"
+ " l %0,0(%3)\n"
+ "0: lr %1,%0\n"
+ " ar %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: lgr %1,%0\n"
- " agr %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b"
+ " lg %0,0(%3)\n"
+ "0: lgr %1,%0\n"
+ " agr %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count), "d" (delta)
- : "cc", "memory" );
+ : "cc", "memory");
}
/*
@@ -358,23 +358,23 @@ static inline long rwsem_atomic_update(long delta, struct rw_semaphore *sem)
{
signed long old, new;
- __asm__ __volatile__(
+ asm volatile(
#ifndef __s390x__
- " l %0,0(%3)\n"
- "0: lr %1,%0\n"
- " ar %1,%5\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b"
+ " l %0,0(%3)\n"
+ "0: lr %1,%0\n"
+ " ar %1,%5\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b"
#else /* __s390x__ */
- " lg %0,0(%3)\n"
- "0: lgr %1,%0\n"
- " agr %1,%5\n"
- " csg %0,%1,0(%3)\n"
- " jl 0b"
+ " lg %0,0(%3)\n"
+ "0: lgr %1,%0\n"
+ " agr %1,%5\n"
+ " csg %0,%1,0(%3)\n"
+ " jl 0b"
#endif /* __s390x__ */
- : "=&d" (old), "=&d" (new), "=m" (sem->count)
+ : "=&d" (old), "=&d" (new), "=m" (sem->count)
: "a" (&sem->count), "m" (sem->count), "d" (delta)
- : "cc", "memory" );
+ : "cc", "memory");
return new;
}
diff --git a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h
index e9a2862b230d..df9b1017b703 100644
--- a/include/asm-s390/s390_ext.h
+++ b/include/asm-s390/s390_ext.h
@@ -10,7 +10,7 @@
* Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
-typedef void (*ext_int_handler_t)(struct pt_regs *regs, __u16 code);
+typedef void (*ext_int_handler_t)(__u16 code);
/*
* Warning: if you change ext_int_info_t you have to change the
diff --git a/include/asm-s390/semaphore.h b/include/asm-s390/semaphore.h
index 32cdc69f39f4..dbce058aefa9 100644
--- a/include/asm-s390/semaphore.h
+++ b/include/asm-s390/semaphore.h
@@ -85,17 +85,17 @@ static inline int down_trylock(struct semaphore * sem)
* sem->count.counter = --new_val;
* In the ppc code this is called atomic_dec_if_positive.
*/
- __asm__ __volatile__ (
- " l %0,0(%3)\n"
- "0: ltr %1,%0\n"
- " jle 1f\n"
- " ahi %1,-1\n"
- " cs %0,%1,0(%3)\n"
- " jl 0b\n"
+ asm volatile(
+ " l %0,0(%3)\n"
+ "0: ltr %1,%0\n"
+ " jle 1f\n"
+ " ahi %1,-1\n"
+ " cs %0,%1,0(%3)\n"
+ " jl 0b\n"
"1:"
: "=&d" (old_val), "=&d" (new_val), "=m" (sem->count.counter)
: "a" (&sem->count.counter), "m" (sem->count.counter)
- : "cc", "memory" );
+ : "cc", "memory");
return old_val <= 0;
}
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index f1959732b6fd..5d72eda8a11b 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -39,6 +39,7 @@ extern unsigned long machine_flags;
#define MACHINE_IS_P390 (machine_flags & 4)
#define MACHINE_HAS_MVPG (machine_flags & 16)
#define MACHINE_HAS_IDTE (machine_flags & 128)
+#define MACHINE_HAS_DIAG9C (machine_flags & 256)
#ifndef __s390x__
#define MACHINE_HAS_IEEE (machine_flags & 2)
diff --git a/include/asm-s390/sfp-machine.h b/include/asm-s390/sfp-machine.h
index de69dfa46fbb..8ca8c77b2d04 100644
--- a/include/asm-s390/sfp-machine.h
+++ b/include/asm-s390/sfp-machine.h
@@ -76,21 +76,23 @@
unsigned int __r2 = (x2) + (y2); \
unsigned int __r1 = (x1); \
unsigned int __r0 = (x0); \
- __asm__ (" alr %2,%3\n" \
- " brc 12,0f\n" \
- " lhi 0,1\n" \
- " alr %1,0\n" \
- " brc 12,0f\n" \
- " alr %0,0\n" \
- "0:" \
- : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
- : "d" (y0), "i" (1) : "cc", "0" ); \
- __asm__ (" alr %1,%2\n" \
- " brc 12,0f\n" \
- " ahi %0,1\n" \
- "0:" \
- : "+&d" (__r2), "+&d" (__r1) \
- : "d" (y1) : "cc" ); \
+ asm volatile( \
+ " alr %2,%3\n" \
+ " brc 12,0f\n" \
+ " lhi 0,1\n" \
+ " alr %1,0\n" \
+ " brc 12,0f\n" \
+ " alr %0,0\n" \
+ "0:" \
+ : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
+ : "d" (y0), "i" (1) : "cc", "0" ); \
+ asm volatile( \
+ " alr %1,%2\n" \
+ " brc 12,0f\n" \
+ " ahi %0,1\n" \
+ "0:" \
+ : "+&d" (__r2), "+&d" (__r1) \
+ : "d" (y1) : "cc"); \
(r2) = __r2; \
(r1) = __r1; \
(r0) = __r0; \
@@ -100,21 +102,23 @@
unsigned int __r2 = (x2) - (y2); \
unsigned int __r1 = (x1); \
unsigned int __r0 = (x0); \
- __asm__ (" slr %2,%3\n" \
- " brc 3,0f\n" \
- " lhi 0,1\n" \
- " slr %1,0\n" \
- " brc 3,0f\n" \
- " slr %0,0\n" \
- "0:" \
- : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
- : "d" (y0) : "cc", "0" ); \
- __asm__ (" slr %1,%2\n" \
- " brc 3,0f\n" \
- " ahi %0,-1\n" \
- "0:" \
- : "+&d" (__r2), "+&d" (__r1) \
- : "d" (y1) : "cc" ); \
+ asm volatile( \
+ " slr %2,%3\n" \
+ " brc 3,0f\n" \
+ " lhi 0,1\n" \
+ " slr %1,0\n" \
+ " brc 3,0f\n" \
+ " slr %0,0\n" \
+ "0:" \
+ : "+&d" (__r2), "+&d" (__r1), "+&d" (__r0) \
+ : "d" (y0) : "cc", "0"); \
+ asm volatile( \
+ " slr %1,%2\n" \
+ " brc 3,0f\n" \
+ " ahi %0,-1\n" \
+ "0:" \
+ : "+&d" (__r2), "+&d" (__r1) \
+ : "d" (y1) : "cc"); \
(r2) = __r2; \
(r1) = __r1; \
(r0) = __r0; \
diff --git a/include/asm-s390/sigp.h b/include/asm-s390/sigp.h
index fc56458aff66..e16d56f8dfe1 100644
--- a/include/asm-s390/sigp.h
+++ b/include/asm-s390/sigp.h
@@ -70,16 +70,16 @@ typedef enum
static inline sigp_ccode
signal_processor(__u16 cpu_addr, sigp_order_code order_code)
{
+ register unsigned long reg1 asm ("1") = 0;
sigp_ccode ccode;
- __asm__ __volatile__(
- " sr 1,1\n" /* parameter=0 in gpr 1 */
- " sigp 1,%1,0(%2)\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (ccode)
- : "d" (__cpu_logical_map[cpu_addr]), "a" (order_code)
- : "cc" , "memory", "1" );
+ asm volatile(
+ " sigp %1,%2,0(%3)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode)
+ : "d" (reg1), "d" (__cpu_logical_map[cpu_addr]),
+ "a" (order_code) : "cc" , "memory");
return ccode;
}
@@ -87,20 +87,18 @@ signal_processor(__u16 cpu_addr, sigp_order_code order_code)
* Signal processor with parameter
*/
static inline sigp_ccode
-signal_processor_p(__u32 parameter, __u16 cpu_addr,
- sigp_order_code order_code)
+signal_processor_p(__u32 parameter, __u16 cpu_addr, sigp_order_code order_code)
{
+ register unsigned int reg1 asm ("1") = parameter;
sigp_ccode ccode;
-
- __asm__ __volatile__(
- " lr 1,%1\n" /* parameter in gpr 1 */
- " sigp 1,%2,0(%3)\n"
- " ipm %0\n"
- " srl %0,28\n"
+
+ asm volatile(
+ " sigp %1,%2,0(%3)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
: "=d" (ccode)
- : "d" (parameter), "d" (__cpu_logical_map[cpu_addr]),
- "a" (order_code)
- : "cc" , "memory", "1" );
+ : "d" (reg1), "d" (__cpu_logical_map[cpu_addr]),
+ "a" (order_code) : "cc" , "memory");
return ccode;
}
@@ -108,24 +106,21 @@ signal_processor_p(__u32 parameter, __u16 cpu_addr,
* Signal processor with parameter and return status
*/
static inline sigp_ccode
-signal_processor_ps(__u32 *statusptr, __u32 parameter,
- __u16 cpu_addr, sigp_order_code order_code)
+signal_processor_ps(__u32 *statusptr, __u32 parameter, __u16 cpu_addr,
+ sigp_order_code order_code)
{
+ register unsigned int reg1 asm ("1") = parameter;
sigp_ccode ccode;
-
- __asm__ __volatile__(
- " sr 2,2\n" /* clear status */
- " lr 3,%2\n" /* parameter in gpr 3 */
- " sigp 2,%3,0(%4)\n"
- " st 2,%1\n"
- " ipm %0\n"
- " srl %0,28\n"
- : "=d" (ccode), "=m" (*statusptr)
- : "d" (parameter), "d" (__cpu_logical_map[cpu_addr]),
- "a" (order_code)
- : "cc" , "memory", "2" , "3"
- );
- return ccode;
+
+ asm volatile(
+ " sigp %1,%2,0(%3)\n"
+ " ipm %0\n"
+ " srl %0,28\n"
+ : "=d" (ccode), "+d" (reg1)
+ : "d" (__cpu_logical_map[cpu_addr]), "a" (order_code)
+ : "cc" , "memory");
+ *statusptr = reg1;
+ return ccode;
}
#endif /* __SIGP__ */
diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h
index 9fb02e9779c9..c3cf030ada4d 100644
--- a/include/asm-s390/smp.h
+++ b/include/asm-s390/smp.h
@@ -56,7 +56,7 @@ static inline __u16 hard_smp_processor_id(void)
{
__u16 cpu_address;
- __asm__ ("stap %0\n" : "=m" (cpu_address));
+ asm volatile("stap %0" : "=m" (cpu_address));
return cpu_address;
}
diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h
index 273dbecf8ace..3fd43826fd0b 100644
--- a/include/asm-s390/spinlock.h
+++ b/include/asm-s390/spinlock.h
@@ -11,17 +11,38 @@
#ifndef __ASM_SPINLOCK_H
#define __ASM_SPINLOCK_H
+#include <linux/smp.h>
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+
static inline int
_raw_compare_and_swap(volatile unsigned int *lock,
unsigned int old, unsigned int new)
{
- asm volatile ("cs %0,%3,0(%4)"
- : "=d" (old), "=m" (*lock)
- : "0" (old), "d" (new), "a" (lock), "m" (*lock)
- : "cc", "memory" );
+ asm volatile(
+ " cs %0,%3,%1"
+ : "=d" (old), "=Q" (*lock)
+ : "0" (old), "d" (new), "Q" (*lock)
+ : "cc", "memory" );
return old;
}
+#else /* __GNUC__ */
+
+static inline int
+_raw_compare_and_swap(volatile unsigned int *lock,
+ unsigned int old, unsigned int new)
+{
+ asm volatile(
+ " cs %0,%3,0(%4)"
+ : "=d" (old), "=m" (*lock)
+ : "0" (old), "d" (new), "a" (lock), "m" (*lock)
+ : "cc", "memory" );
+ return old;
+}
+
+#endif /* __GNUC__ */
+
/*
* Simple spin lock operations. There are two variants, one clears IRQ's
* on the local processor, one does not.
@@ -31,34 +52,46 @@ _raw_compare_and_swap(volatile unsigned int *lock,
* (the type definitions are in asm/spinlock_types.h)
*/
-#define __raw_spin_is_locked(x) ((x)->lock != 0)
+#define __raw_spin_is_locked(x) ((x)->owner_cpu != 0)
#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
#define __raw_spin_unlock_wait(lock) \
- do { while (__raw_spin_is_locked(lock)) cpu_relax(); } while (0)
+ do { while (__raw_spin_is_locked(lock)) \
+ _raw_spin_relax(lock); } while (0)
-extern void _raw_spin_lock_wait(raw_spinlock_t *lp, unsigned int pc);
-extern int _raw_spin_trylock_retry(raw_spinlock_t *lp, unsigned int pc);
+extern void _raw_spin_lock_wait(raw_spinlock_t *, unsigned int pc);
+extern int _raw_spin_trylock_retry(raw_spinlock_t *, unsigned int pc);
+extern void _raw_spin_relax(raw_spinlock_t *lock);
static inline void __raw_spin_lock(raw_spinlock_t *lp)
{
unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
-
- if (unlikely(_raw_compare_and_swap(&lp->lock, 0, pc) != 0))
- _raw_spin_lock_wait(lp, pc);
+ int old;
+
+ old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
+ if (likely(old == 0)) {
+ lp->owner_pc = pc;
+ return;
+ }
+ _raw_spin_lock_wait(lp, pc);
}
static inline int __raw_spin_trylock(raw_spinlock_t *lp)
{
unsigned long pc = 1 | (unsigned long) __builtin_return_address(0);
+ int old;
- if (likely(_raw_compare_and_swap(&lp->lock, 0, pc) == 0))
+ old = _raw_compare_and_swap(&lp->owner_cpu, 0, ~smp_processor_id());
+ if (likely(old == 0)) {
+ lp->owner_pc = pc;
return 1;
+ }
return _raw_spin_trylock_retry(lp, pc);
}
static inline void __raw_spin_unlock(raw_spinlock_t *lp)
{
- _raw_compare_and_swap(&lp->lock, lp->lock, 0);
+ lp->owner_pc = 0;
+ _raw_compare_and_swap(&lp->owner_cpu, lp->owner_cpu, 0);
}
/*
@@ -135,4 +168,7 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
return _raw_write_trylock_retry(rw);
}
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-s390/spinlock_types.h b/include/asm-s390/spinlock_types.h
index f79a2216204f..b7ac13f7aa37 100644
--- a/include/asm-s390/spinlock_types.h
+++ b/include/asm-s390/spinlock_types.h
@@ -6,16 +6,16 @@
#endif
typedef struct {
- volatile unsigned int lock;
+ volatile unsigned int owner_cpu;
+ volatile unsigned int owner_pc;
} __attribute__ ((aligned (4))) raw_spinlock_t;
#define __RAW_SPIN_LOCK_UNLOCKED { 0 }
typedef struct {
volatile unsigned int lock;
- volatile unsigned int owner_pc;
} raw_rwlock_t;
-#define __RAW_RW_LOCK_UNLOCKED { 0, 0 }
+#define __RAW_RW_LOCK_UNLOCKED { 0 }
#endif
diff --git a/include/asm-s390/string.h b/include/asm-s390/string.h
index 23a4c390489f..d074673a6d9b 100644
--- a/include/asm-s390/string.h
+++ b/include/asm-s390/string.h
@@ -60,12 +60,13 @@ static inline void *memchr(const void * s, int c, size_t n)
register int r0 asm("0") = (char) c;
const void *ret = s + n;
- asm volatile ("0: srst %0,%1\n"
- " jo 0b\n"
- " jl 1f\n"
- " la %0,0\n"
- "1:"
- : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
+ asm volatile(
+ "0: srst %0,%1\n"
+ " jo 0b\n"
+ " jl 1f\n"
+ " la %0,0\n"
+ "1:"
+ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc");
return (void *) ret;
}
@@ -74,9 +75,10 @@ static inline void *memscan(void *s, int c, size_t n)
register int r0 asm("0") = (char) c;
const void *ret = s + n;
- asm volatile ("0: srst %0,%1\n"
- " jo 0b\n"
- : "+a" (ret), "+&a" (s) : "d" (r0) : "cc" );
+ asm volatile(
+ "0: srst %0,%1\n"
+ " jo 0b\n"
+ : "+a" (ret), "+&a" (s) : "d" (r0) : "cc");
return (void *) ret;
}
@@ -86,12 +88,13 @@ static inline char *strcat(char *dst, const char *src)
unsigned long dummy;
char *ret = dst;
- asm volatile ("0: srst %0,%1\n"
- " jo 0b\n"
- "1: mvst %0,%2\n"
- " jo 1b"
- : "=&a" (dummy), "+a" (dst), "+a" (src)
- : "d" (r0), "0" (0) : "cc", "memory" );
+ asm volatile(
+ "0: srst %0,%1\n"
+ " jo 0b\n"
+ "1: mvst %0,%2\n"
+ " jo 1b"
+ : "=&a" (dummy), "+a" (dst), "+a" (src)
+ : "d" (r0), "0" (0) : "cc", "memory" );
return ret;
}
@@ -100,10 +103,11 @@ static inline char *strcpy(char *dst, const char *src)
register int r0 asm("0") = 0;
char *ret = dst;
- asm volatile ("0: mvst %0,%1\n"
- " jo 0b"
- : "+&a" (dst), "+&a" (src) : "d" (r0)
- : "cc", "memory" );
+ asm volatile(
+ "0: mvst %0,%1\n"
+ " jo 0b"
+ : "+&a" (dst), "+&a" (src) : "d" (r0)
+ : "cc", "memory");
return ret;
}
@@ -112,9 +116,10 @@ static inline size_t strlen(const char *s)
register unsigned long r0 asm("0") = 0;
const char *tmp = s;
- asm volatile ("0: srst %0,%1\n"
- " jo 0b"
- : "+d" (r0), "+a" (tmp) : : "cc" );
+ asm volatile(
+ "0: srst %0,%1\n"
+ " jo 0b"
+ : "+d" (r0), "+a" (tmp) : : "cc");
return r0 - (unsigned long) s;
}
@@ -124,9 +129,10 @@ static inline size_t strnlen(const char * s, size_t n)
const char *tmp = s;
const char *end = s + n;
- asm volatile ("0: srst %0,%1\n"
- " jo 0b"
- : "+a" (end), "+a" (tmp) : "d" (r0) : "cc" );
+ asm volatile(
+ "0: srst %0,%1\n"
+ " jo 0b"
+ : "+a" (end), "+a" (tmp) : "d" (r0) : "cc");
return end - s;
}
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index 16040048cd1b..ccbafe4bf2cb 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -23,74 +23,68 @@ struct task_struct;
extern struct task_struct *__switch_to(void *, void *);
-#ifdef __s390x__
-#define __FLAG_SHIFT 56
-#else /* ! __s390x__ */
-#define __FLAG_SHIFT 24
-#endif /* ! __s390x__ */
-
static inline void save_fp_regs(s390_fp_regs *fpregs)
{
- asm volatile (
- " std 0,8(%1)\n"
- " std 2,24(%1)\n"
- " std 4,40(%1)\n"
- " std 6,56(%1)"
- : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory" );
+ asm volatile(
+ " std 0,8(%1)\n"
+ " std 2,24(%1)\n"
+ " std 4,40(%1)\n"
+ " std 6,56(%1)"
+ : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory");
if (!MACHINE_HAS_IEEE)
return;
asm volatile(
- " stfpc 0(%1)\n"
- " std 1,16(%1)\n"
- " std 3,32(%1)\n"
- " std 5,48(%1)\n"
- " std 7,64(%1)\n"
- " std 8,72(%1)\n"
- " std 9,80(%1)\n"
- " std 10,88(%1)\n"
- " std 11,96(%1)\n"
- " std 12,104(%1)\n"
- " std 13,112(%1)\n"
- " std 14,120(%1)\n"
- " std 15,128(%1)\n"
- : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory" );
+ " stfpc 0(%1)\n"
+ " std 1,16(%1)\n"
+ " std 3,32(%1)\n"
+ " std 5,48(%1)\n"
+ " std 7,64(%1)\n"
+ " std 8,72(%1)\n"
+ " std 9,80(%1)\n"
+ " std 10,88(%1)\n"
+ " std 11,96(%1)\n"
+ " std 12,104(%1)\n"
+ " std 13,112(%1)\n"
+ " std 14,120(%1)\n"
+ " std 15,128(%1)\n"
+ : "=m" (*fpregs) : "a" (fpregs), "m" (*fpregs) : "memory");
}
static inline void restore_fp_regs(s390_fp_regs *fpregs)
{
- asm volatile (
- " ld 0,8(%0)\n"
- " ld 2,24(%0)\n"
- " ld 4,40(%0)\n"
- " ld 6,56(%0)"
- : : "a" (fpregs), "m" (*fpregs) );
+ asm volatile(
+ " ld 0,8(%0)\n"
+ " ld 2,24(%0)\n"
+ " ld 4,40(%0)\n"
+ " ld 6,56(%0)"
+ : : "a" (fpregs), "m" (*fpregs));
if (!MACHINE_HAS_IEEE)
return;
asm volatile(
- " lfpc 0(%0)\n"
- " ld 1,16(%0)\n"
- " ld 3,32(%0)\n"
- " ld 5,48(%0)\n"
- " ld 7,64(%0)\n"
- " ld 8,72(%0)\n"
- " ld 9,80(%0)\n"
- " ld 10,88(%0)\n"
- " ld 11,96(%0)\n"
- " ld 12,104(%0)\n"
- " ld 13,112(%0)\n"
- " ld 14,120(%0)\n"
- " ld 15,128(%0)\n"
- : : "a" (fpregs), "m" (*fpregs) );
+ " lfpc 0(%0)\n"
+ " ld 1,16(%0)\n"
+ " ld 3,32(%0)\n"
+ " ld 5,48(%0)\n"
+ " ld 7,64(%0)\n"
+ " ld 8,72(%0)\n"
+ " ld 9,80(%0)\n"
+ " ld 10,88(%0)\n"
+ " ld 11,96(%0)\n"
+ " ld 12,104(%0)\n"
+ " ld 13,112(%0)\n"
+ " ld 14,120(%0)\n"
+ " ld 15,128(%0)\n"
+ : : "a" (fpregs), "m" (*fpregs));
}
static inline void save_access_regs(unsigned int *acrs)
{
- asm volatile ("stam 0,15,0(%0)" : : "a" (acrs) : "memory" );
+ asm volatile("stam 0,15,0(%0)" : : "a" (acrs) : "memory");
}
static inline void restore_access_regs(unsigned int *acrs)
{
- asm volatile ("lam 0,15,0(%0)" : : "a" (acrs) );
+ asm volatile("lam 0,15,0(%0)" : : "a" (acrs));
}
#define switch_to(prev,next,last) do { \
@@ -126,7 +120,7 @@ extern void account_system_vtime(struct task_struct *);
account_vtime(prev); \
} while (0)
-#define nop() __asm__ __volatile__ ("nop")
+#define nop() asm volatile("nop")
#define xchg(ptr,x) \
({ \
@@ -147,15 +141,15 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
shift = (3 ^ (addr & 3)) << 3;
addr ^= addr & 3;
asm volatile(
- " l %0,0(%4)\n"
- "0: lr 0,%0\n"
- " nr 0,%3\n"
- " or 0,%2\n"
- " cs %0,0,0(%4)\n"
- " jl 0b\n"
+ " l %0,0(%4)\n"
+ "0: lr 0,%0\n"
+ " nr 0,%3\n"
+ " or 0,%2\n"
+ " cs %0,0,0(%4)\n"
+ " jl 0b\n"
: "=&d" (old), "=m" (*(int *) addr)
: "d" (x << shift), "d" (~(255 << shift)), "a" (addr),
- "m" (*(int *) addr) : "memory", "cc", "0" );
+ "m" (*(int *) addr) : "memory", "cc", "0");
x = old >> shift;
break;
case 2:
@@ -163,36 +157,36 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size)
shift = (2 ^ (addr & 2)) << 3;
addr ^= addr & 2;
asm volatile(
- " l %0,0(%4)\n"
- "0: lr 0,%0\n"
- " nr 0,%3\n"
- " or 0,%2\n"
- " cs %0,0,0(%4)\n"
- " jl 0b\n"
+ " l %0,0(%4)\n"
+ "0: lr 0,%0\n"
+ " nr 0,%3\n"
+ " or 0,%2\n"
+ " cs %0,0,0(%4)\n"
+ " jl 0b\n"
: "=&d" (old), "=m" (*(int *) addr)
: "d" (x << shift), "d" (~(65535 << shift)), "a" (addr),
- "m" (*(int *) addr) : "memory", "cc", "0" );
+ "m" (*(int *) addr) : "memory", "cc", "0");
x = old >> shift;
break;
case 4:
- asm volatile (
- " l %0,0(%3)\n"
- "0: cs %0,%2,0(%3)\n"
- " jl 0b\n"
+ asm volatile(
+ " l %0,0(%3)\n"
+ "0: cs %0,%2,0(%3)\n"
+ " jl 0b\n"
: "=&d" (old), "=m" (*(int *) ptr)
: "d" (x), "a" (ptr), "m" (*(int *) ptr)
- : "memory", "cc" );
+ : "memory", "cc");
x = old;
break;
#ifdef __s390x__
case 8:
- asm volatile (
- " lg %0,0(%3)\n"
- "0: csg %0,%2,0(%3)\n"
- " jl 0b\n"
+ asm volatile(
+ " lg %0,0(%3)\n"
+ "0: csg %0,%2,0(%3)\n"
+ " jl 0b\n"
: "=&d" (old), "=m" (*(long *) ptr)
: "d" (x), "a" (ptr), "m" (*(long *) ptr)
- : "memory", "cc" );
+ : "memory", "cc");
x = old;
break;
#endif /* __s390x__ */
@@ -224,55 +218,55 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
shift = (3 ^ (addr & 3)) << 3;
addr ^= addr & 3;
asm volatile(
- " l %0,0(%4)\n"
- "0: nr %0,%5\n"
- " lr %1,%0\n"
- " or %0,%2\n"
- " or %1,%3\n"
- " cs %0,%1,0(%4)\n"
- " jnl 1f\n"
- " xr %1,%0\n"
- " nr %1,%5\n"
- " jnz 0b\n"
+ " l %0,0(%4)\n"
+ "0: nr %0,%5\n"
+ " lr %1,%0\n"
+ " or %0,%2\n"
+ " or %1,%3\n"
+ " cs %0,%1,0(%4)\n"
+ " jnl 1f\n"
+ " xr %1,%0\n"
+ " nr %1,%5\n"
+ " jnz 0b\n"
"1:"
: "=&d" (prev), "=&d" (tmp)
: "d" (old << shift), "d" (new << shift), "a" (ptr),
"d" (~(255 << shift))
- : "memory", "cc" );
+ : "memory", "cc");
return prev >> shift;
case 2:
addr = (unsigned long) ptr;
shift = (2 ^ (addr & 2)) << 3;
addr ^= addr & 2;
asm volatile(
- " l %0,0(%4)\n"
- "0: nr %0,%5\n"
- " lr %1,%0\n"
- " or %0,%2\n"
- " or %1,%3\n"
- " cs %0,%1,0(%4)\n"
- " jnl 1f\n"
- " xr %1,%0\n"
- " nr %1,%5\n"
- " jnz 0b\n"
+ " l %0,0(%4)\n"
+ "0: nr %0,%5\n"
+ " lr %1,%0\n"
+ " or %0,%2\n"
+ " or %1,%3\n"
+ " cs %0,%1,0(%4)\n"
+ " jnl 1f\n"
+ " xr %1,%0\n"
+ " nr %1,%5\n"
+ " jnz 0b\n"
"1:"
: "=&d" (prev), "=&d" (tmp)
: "d" (old << shift), "d" (new << shift), "a" (ptr),
"d" (~(65535 << shift))
- : "memory", "cc" );
+ : "memory", "cc");
return prev >> shift;
case 4:
- asm volatile (
- " cs %0,%2,0(%3)\n"
+ asm volatile(
+ " cs %0,%2,0(%3)\n"
: "=&d" (prev) : "0" (old), "d" (new), "a" (ptr)
- : "memory", "cc" );
+ : "memory", "cc");
return prev;
#ifdef __s390x__
case 8:
- asm volatile (
- " csg %0,%2,0(%3)\n"
+ asm volatile(
+ " csg %0,%2,0(%3)\n"
: "=&d" (prev) : "0" (old), "d" (new), "a" (ptr)
- : "memory", "cc" );
+ : "memory", "cc");
return prev;
#endif /* __s390x__ */
}
@@ -289,8 +283,8 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
* all memory ops have completed wrt other CPU's ( see 7-15 POP DJB ).
*/
-#define eieio() __asm__ __volatile__ ( "bcr 15,0" : : : "memory" )
-# define SYNC_OTHER_CORES(x) eieio()
+#define eieio() asm volatile("bcr 15,0" : : : "memory")
+#define SYNC_OTHER_CORES(x) eieio()
#define mb() eieio()
#define rmb() eieio()
#define wmb() eieio()
@@ -307,117 +301,56 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
#ifdef __s390x__
-#define __ctl_load(array, low, high) ({ \
- typedef struct { char _[sizeof(array)]; } addrtype; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" \
- " lctlg 0,0,0(%0)\n" \
- "0: ex %1,0(1)" \
- : : "a" (&array), "a" (((low)<<4)+(high)), \
- "m" (*(addrtype *)(array)) : "1" ); \
+#define __ctl_load(array, low, high) ({ \
+ typedef struct { char _[sizeof(array)]; } addrtype; \
+ asm volatile( \
+ " lctlg %1,%2,0(%0)\n" \
+ : : "a" (&array), "i" (low), "i" (high), \
+ "m" (*(addrtype *)(array))); \
})
-#define __ctl_store(array, low, high) ({ \
- typedef struct { char _[sizeof(array)]; } addrtype; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" \
- " stctg 0,0,0(%1)\n" \
- "0: ex %2,0(1)" \
- : "=m" (*(addrtype *)(array)) \
- : "a" (&array), "a" (((low)<<4)+(high)) : "1" ); \
+#define __ctl_store(array, low, high) ({ \
+ typedef struct { char _[sizeof(array)]; } addrtype; \
+ asm volatile( \
+ " stctg %2,%3,0(%1)\n" \
+ : "=m" (*(addrtype *)(array)) \
+ : "a" (&array), "i" (low), "i" (high)); \
})
-#define __ctl_set_bit(cr, bit) ({ \
- __u8 __dummy[24]; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" /* skip indirect insns */ \
- " stctg 0,0,0(%1)\n" \
- " lctlg 0,0,0(%1)\n" \
- "0: ex %2,0(1)\n" /* execute stctl */ \
- " lg 0,0(%1)\n" \
- " ogr 0,%3\n" /* set the bit */ \
- " stg 0,0(%1)\n" \
- "1: ex %2,6(1)" /* execute lctl */ \
- : "=m" (__dummy) \
- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
- "a" (cr*17), "a" (1L<<(bit)) \
- : "cc", "0", "1" ); \
- })
-
-#define __ctl_clear_bit(cr, bit) ({ \
- __u8 __dummy[16]; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" /* skip indirect insns */ \
- " stctg 0,0,0(%1)\n" \
- " lctlg 0,0,0(%1)\n" \
- "0: ex %2,0(1)\n" /* execute stctl */ \
- " lg 0,0(%1)\n" \
- " ngr 0,%3\n" /* set the bit */ \
- " stg 0,0(%1)\n" \
- "1: ex %2,6(1)" /* execute lctl */ \
- : "=m" (__dummy) \
- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
- "a" (cr*17), "a" (~(1L<<(bit))) \
- : "cc", "0", "1" ); \
- })
-
#else /* __s390x__ */
-#define __ctl_load(array, low, high) ({ \
- typedef struct { char _[sizeof(array)]; } addrtype; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" \
- " lctl 0,0,0(%0)\n" \
- "0: ex %1,0(1)" \
- : : "a" (&array), "a" (((low)<<4)+(high)), \
- "m" (*(addrtype *)(array)) : "1" ); \
- })
+#define __ctl_load(array, low, high) ({ \
+ typedef struct { char _[sizeof(array)]; } addrtype; \
+ asm volatile( \
+ " lctl %1,%2,0(%0)\n" \
+ : : "a" (&array), "i" (low), "i" (high), \
+ "m" (*(addrtype *)(array))); \
+})
-#define __ctl_store(array, low, high) ({ \
- typedef struct { char _[sizeof(array)]; } addrtype; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" \
- " stctl 0,0,0(%1)\n" \
- "0: ex %2,0(1)" \
- : "=m" (*(addrtype *)(array)) \
- : "a" (&array), "a" (((low)<<4)+(high)): "1" ); \
+#define __ctl_store(array, low, high) ({ \
+ typedef struct { char _[sizeof(array)]; } addrtype; \
+ asm volatile( \
+ " stctl %2,%3,0(%1)\n" \
+ : "=m" (*(addrtype *)(array)) \
+ : "a" (&array), "i" (low), "i" (high)); \
})
-#define __ctl_set_bit(cr, bit) ({ \
- __u8 __dummy[16]; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" /* skip indirect insns */ \
- " stctl 0,0,0(%1)\n" \
- " lctl 0,0,0(%1)\n" \
- "0: ex %2,0(1)\n" /* execute stctl */ \
- " l 0,0(%1)\n" \
- " or 0,%3\n" /* set the bit */ \
- " st 0,0(%1)\n" \
- "1: ex %2,4(1)" /* execute lctl */ \
- : "=m" (__dummy) \
- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
- "a" (cr*17), "a" (1<<(bit)) \
- : "cc", "0", "1" ); \
- })
-
-#define __ctl_clear_bit(cr, bit) ({ \
- __u8 __dummy[16]; \
- __asm__ __volatile__ ( \
- " bras 1,0f\n" /* skip indirect insns */ \
- " stctl 0,0,0(%1)\n" \
- " lctl 0,0,0(%1)\n" \
- "0: ex %2,0(1)\n" /* execute stctl */ \
- " l 0,0(%1)\n" \
- " nr 0,%3\n" /* set the bit */ \
- " st 0,0(%1)\n" \
- "1: ex %2,4(1)" /* execute lctl */ \
- : "=m" (__dummy) \
- : "a" ((((unsigned long) &__dummy) + 7) & ~7UL), \
- "a" (cr*17), "a" (~(1<<(bit))) \
- : "cc", "0", "1" ); \
- })
#endif /* __s390x__ */
+#define __ctl_set_bit(cr, bit) ({ \
+ unsigned long __dummy; \
+ __ctl_store(__dummy, cr, cr); \
+ __dummy |= 1UL << (bit); \
+ __ctl_load(__dummy, cr, cr); \
+})
+
+#define __ctl_clear_bit(cr, bit) ({ \
+ unsigned long __dummy; \
+ __ctl_store(__dummy, cr, cr); \
+ __dummy &= ~(1UL << (bit)); \
+ __ctl_load(__dummy, cr, cr); \
+})
+
#include <linux/irqflags.h>
/*
@@ -427,8 +360,7 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
static inline void
__set_psw_mask(unsigned long mask)
{
- local_save_flags(mask);
- __load_psw_mask(mask);
+ __load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
}
#define local_mcck_enable() __set_psw_mask(PSW_KERNEL_BITS)
diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h
index fcd6c256a2d1..30e5cbe570f2 100644
--- a/include/asm-s390/timer.h
+++ b/include/asm-s390/timer.h
@@ -26,7 +26,7 @@ struct vtimer_list {
spinlock_t lock;
unsigned long magic;
- void (*function)(unsigned long, struct pt_regs*);
+ void (*function)(unsigned long);
unsigned long data;
};
diff --git a/include/asm-s390/timex.h b/include/asm-s390/timex.h
index 5d0332a4c2bd..4df4a41029a3 100644
--- a/include/asm-s390/timex.h
+++ b/include/asm-s390/timex.h
@@ -15,20 +15,21 @@
typedef unsigned long long cycles_t;
-static inline cycles_t get_cycles(void)
-{
- cycles_t cycles;
-
- __asm__ __volatile__ ("stck 0(%1)" : "=m" (cycles) : "a" (&cycles) : "cc");
- return cycles >> 2;
-}
-
static inline unsigned long long get_clock (void)
{
unsigned long long clk;
- __asm__ __volatile__ ("stck 0(%1)" : "=m" (clk) : "a" (&clk) : "cc");
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+ asm volatile("stck %0" : "=Q" (clk) : : "cc");
+#else /* __GNUC__ */
+ asm volatile("stck 0(%1)" : "=m" (clk) : "a" (&clk) : "cc");
+#endif /* __GNUC__ */
return clk;
}
+static inline cycles_t get_cycles(void)
+{
+ return (cycles_t) get_clock() >> 2;
+}
+
#endif
diff --git a/include/asm-s390/tlbflush.h b/include/asm-s390/tlbflush.h
index 73cd85bebfb2..fa4dc916a9bf 100644
--- a/include/asm-s390/tlbflush.h
+++ b/include/asm-s390/tlbflush.h
@@ -25,7 +25,7 @@
*/
#define local_flush_tlb() \
-do { __asm__ __volatile__("ptlb": : :"memory"); } while (0)
+do { asm volatile("ptlb": : :"memory"); } while (0)
#ifndef CONFIG_SMP
@@ -68,24 +68,24 @@ extern void smp_ptlb_all(void);
static inline void global_flush_tlb(void)
{
+ register unsigned long reg2 asm("2");
+ register unsigned long reg3 asm("3");
+ register unsigned long reg4 asm("4");
+ long dummy;
+
#ifndef __s390x__
if (!MACHINE_HAS_CSP) {
smp_ptlb_all();
return;
}
#endif /* __s390x__ */
- {
- register unsigned long addr asm("4");
- long dummy;
-
- dummy = 0;
- addr = ((unsigned long) &dummy) + 1;
- __asm__ __volatile__ (
- " slr 2,2\n"
- " slr 3,3\n"
- " csp 2,%0"
- : : "a" (addr), "m" (dummy) : "cc", "2", "3" );
- }
+
+ dummy = 0;
+ reg2 = reg3 = 0;
+ reg4 = ((unsigned long) &dummy) + 1;
+ asm volatile(
+ " csp %0,%2"
+ : : "d" (reg2), "d" (reg3), "d" (reg4), "m" (dummy) : "cc" );
}
/*
@@ -102,9 +102,9 @@ static inline void __flush_tlb_mm(struct mm_struct * mm)
if (unlikely(cpus_empty(mm->cpu_vm_mask)))
return;
if (MACHINE_HAS_IDTE) {
- asm volatile (".insn rrf,0xb98e0000,0,%0,%1,0"
- : : "a" (2048),
- "a" (__pa(mm->pgd)&PAGE_MASK) : "cc" );
+ asm volatile(
+ " .insn rrf,0xb98e0000,0,%0,%1,0"
+ : : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc");
return;
}
preempt_disable();
diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h
index e2047b0c9092..72ae4efddb49 100644
--- a/include/asm-s390/uaccess.h
+++ b/include/asm-s390/uaccess.h
@@ -38,25 +38,14 @@
#define get_ds() (KERNEL_DS)
#define get_fs() (current->thread.mm_segment)
-#ifdef __s390x__
#define set_fs(x) \
({ \
unsigned long __pto; \
current->thread.mm_segment = (x); \
__pto = current->thread.mm_segment.ar4 ? \
S390_lowcore.user_asce : S390_lowcore.kernel_asce; \
- asm volatile ("lctlg 7,7,%0" : : "m" (__pto) ); \
+ __ctl_load(__pto, 7, 7); \
})
-#else /* __s390x__ */
-#define set_fs(x) \
-({ \
- unsigned long __pto; \
- current->thread.mm_segment = (x); \
- __pto = current->thread.mm_segment.ar4 ? \
- S390_lowcore.user_asce : S390_lowcore.kernel_asce; \
- asm volatile ("lctl 7,7,%0" : : "m" (__pto) ); \
-})
-#endif /* __s390x__ */
#define segment_eq(a,b) ((a).ar4 == (b).ar4)
diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h
index 02b942d85c37..71d3c21b84f0 100644
--- a/include/asm-s390/unistd.h
+++ b/include/asm-s390/unistd.h
@@ -247,8 +247,11 @@
#define __NR_sync_file_range 307
#define __NR_tee 308
#define __NR_vmsplice 309
+/* Number 310 is reserved for new sys_move_pages */
+#define __NR_getcpu 311
+#define __NR_epoll_pwait 312
-#define NR_syscalls 310
+#define NR_syscalls 313
/*
* There are some system calls that are not present on 64 bit, some
@@ -342,9 +345,11 @@
#ifdef __KERNEL__
+#include <linux/err.h>
+
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-4095)) {\
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
errno = -(res); \
res = -1; \
} \
@@ -353,145 +358,145 @@ do { \
#define _svc_clobber "1", "cc", "memory"
-#define _syscall0(type,name) \
-type name(void) { \
- register long __svcres asm("2"); \
- long __res; \
- __asm__ __volatile__ ( \
- " .if %1 < 256\n" \
- " svc %b1\n" \
- " .else\n" \
- " la %%r1,%1\n" \
- " svc 0\n" \
- " .endif" \
- : "=d" (__svcres) \
- : "i" (__NR_##name) \
- : _svc_clobber ); \
- __res = __svcres; \
- __syscall_return(type,__res); \
+#define _syscall0(type,name) \
+type name(void) { \
+ register long __svcres asm("2"); \
+ long __res; \
+ asm volatile( \
+ " .if %1 < 256\n" \
+ " svc %b1\n" \
+ " .else\n" \
+ " la %%r1,%1\n" \
+ " svc 0\n" \
+ " .endif" \
+ : "=d" (__svcres) \
+ : "i" (__NR_##name) \
+ : _svc_clobber); \
+ __res = __svcres; \
+ __syscall_return(type,__res); \
}
-#define _syscall1(type,name,type1,arg1) \
-type name(type1 arg1) { \
- register type1 __arg1 asm("2") = arg1; \
- register long __svcres asm("2"); \
- long __res; \
- __asm__ __volatile__ ( \
- " .if %1 < 256\n" \
- " svc %b1\n" \
- " .else\n" \
- " la %%r1,%1\n" \
- " svc 0\n" \
- " .endif" \
- : "=d" (__svcres) \
- : "i" (__NR_##name), \
- "0" (__arg1) \
- : _svc_clobber ); \
- __res = __svcres; \
- __syscall_return(type,__res); \
+#define _syscall1(type,name,type1,arg1) \
+type name(type1 arg1) { \
+ register type1 __arg1 asm("2") = arg1; \
+ register long __svcres asm("2"); \
+ long __res; \
+ asm volatile( \
+ " .if %1 < 256\n" \
+ " svc %b1\n" \
+ " .else\n" \
+ " la %%r1,%1\n" \
+ " svc 0\n" \
+ " .endif" \
+ : "=d" (__svcres) \
+ : "i" (__NR_##name), \
+ "0" (__arg1) \
+ : _svc_clobber); \
+ __res = __svcres; \
+ __syscall_return(type,__res); \
}
-#define _syscall2(type,name,type1,arg1,type2,arg2) \
-type name(type1 arg1, type2 arg2) { \
- register type1 __arg1 asm("2") = arg1; \
- register type2 __arg2 asm("3") = arg2; \
- register long __svcres asm("2"); \
- long __res; \
- __asm__ __volatile__ ( \
- " .if %1 < 256\n" \
- " svc %b1\n" \
- " .else\n" \
- " la %%r1,%1\n" \
- " svc 0\n" \
- " .endif" \
- : "=d" (__svcres) \
- : "i" (__NR_##name), \
- "0" (__arg1), \
- "d" (__arg2) \
- : _svc_clobber ); \
- __res = __svcres; \
- __syscall_return(type,__res); \
+#define _syscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1, type2 arg2) { \
+ register type1 __arg1 asm("2") = arg1; \
+ register type2 __arg2 asm("3") = arg2; \
+ register long __svcres asm("2"); \
+ long __res; \
+ asm volatile( \
+ " .if %1 < 256\n" \
+ " svc %b1\n" \
+ " .else\n" \
+ " la %%r1,%1\n" \
+ " svc 0\n" \
+ " .endif" \
+ : "=d" (__svcres) \
+ : "i" (__NR_##name), \
+ "0" (__arg1), \
+ "d" (__arg2) \
+ : _svc_clobber ); \
+ __res = __svcres; \
+ __syscall_return(type,__res); \
}
-#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)\
-type name(type1 arg1, type2 arg2, type3 arg3) { \
- register type1 __arg1 asm("2") = arg1; \
- register type2 __arg2 asm("3") = arg2; \
- register type3 __arg3 asm("4") = arg3; \
- register long __svcres asm("2"); \
- long __res; \
- __asm__ __volatile__ ( \
- " .if %1 < 256\n" \
- " svc %b1\n" \
- " .else\n" \
- " la %%r1,%1\n" \
- " svc 0\n" \
- " .endif" \
- : "=d" (__svcres) \
- : "i" (__NR_##name), \
- "0" (__arg1), \
- "d" (__arg2), \
- "d" (__arg3) \
- : _svc_clobber ); \
- __res = __svcres; \
- __syscall_return(type,__res); \
+#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1, type2 arg2, type3 arg3) { \
+ register type1 __arg1 asm("2") = arg1; \
+ register type2 __arg2 asm("3") = arg2; \
+ register type3 __arg3 asm("4") = arg3; \
+ register long __svcres asm("2"); \
+ long __res; \
+ asm volatile( \
+ " .if %1 < 256\n" \
+ " svc %b1\n" \
+ " .else\n" \
+ " la %%r1,%1\n" \
+ " svc 0\n" \
+ " .endif" \
+ : "=d" (__svcres) \
+ : "i" (__NR_##name), \
+ "0" (__arg1), \
+ "d" (__arg2), \
+ "d" (__arg3) \
+ : _svc_clobber); \
+ __res = __svcres; \
+ __syscall_return(type,__res); \
}
-#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,\
- type4,name4) \
-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
- register type1 __arg1 asm("2") = arg1; \
- register type2 __arg2 asm("3") = arg2; \
- register type3 __arg3 asm("4") = arg3; \
- register type4 __arg4 asm("5") = arg4; \
- register long __svcres asm("2"); \
- long __res; \
- __asm__ __volatile__ ( \
- " .if %1 < 256\n" \
- " svc %b1\n" \
- " .else\n" \
- " la %%r1,%1\n" \
- " svc 0\n" \
- " .endif" \
- : "=d" (__svcres) \
- : "i" (__NR_##name), \
- "0" (__arg1), \
- "d" (__arg2), \
- "d" (__arg3), \
- "d" (__arg4) \
- : _svc_clobber ); \
- __res = __svcres; \
- __syscall_return(type,__res); \
+#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3, \
+ type4,name4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \
+ register type1 __arg1 asm("2") = arg1; \
+ register type2 __arg2 asm("3") = arg2; \
+ register type3 __arg3 asm("4") = arg3; \
+ register type4 __arg4 asm("5") = arg4; \
+ register long __svcres asm("2"); \
+ long __res; \
+ asm volatile( \
+ " .if %1 < 256\n" \
+ " svc %b1\n" \
+ " .else\n" \
+ " la %%r1,%1\n" \
+ " svc 0\n" \
+ " .endif" \
+ : "=d" (__svcres) \
+ : "i" (__NR_##name), \
+ "0" (__arg1), \
+ "d" (__arg2), \
+ "d" (__arg3), \
+ "d" (__arg4) \
+ : _svc_clobber); \
+ __res = __svcres; \
+ __syscall_return(type,__res); \
}
-#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,\
- type4,name4,type5,name5) \
-type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
- type5 arg5) { \
- register type1 __arg1 asm("2") = arg1; \
- register type2 __arg2 asm("3") = arg2; \
- register type3 __arg3 asm("4") = arg3; \
- register type4 __arg4 asm("5") = arg4; \
- register type5 __arg5 asm("6") = arg5; \
- register long __svcres asm("2"); \
- long __res; \
- __asm__ __volatile__ ( \
- " .if %1 < 256\n" \
- " svc %b1\n" \
- " .else\n" \
- " la %%r1,%1\n" \
- " svc 0\n" \
- " .endif" \
- : "=d" (__svcres) \
- : "i" (__NR_##name), \
- "0" (__arg1), \
- "d" (__arg2), \
- "d" (__arg3), \
- "d" (__arg4), \
- "d" (__arg5) \
- : _svc_clobber ); \
- __res = __svcres; \
- __syscall_return(type,__res); \
+#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3, \
+ type4,name4,type5,name5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5) { \
+ register type1 __arg1 asm("2") = arg1; \
+ register type2 __arg2 asm("3") = arg2; \
+ register type3 __arg3 asm("4") = arg3; \
+ register type4 __arg4 asm("5") = arg4; \
+ register type5 __arg5 asm("6") = arg5; \
+ register long __svcres asm("2"); \
+ long __res; \
+ asm volatile( \
+ " .if %1 < 256\n" \
+ " svc %b1\n" \
+ " .else\n" \
+ " la %%r1,%1\n" \
+ " svc 0\n" \
+ " .endif" \
+ : "=d" (__svcres) \
+ : "i" (__NR_##name), \
+ "0" (__arg1), \
+ "d" (__arg2), \
+ "d" (__arg3), \
+ "d" (__arg4), \
+ "d" (__arg5) \
+ : _svc_clobber); \
+ __res = __svcres; \
+ __syscall_return(type,__res); \
}
#define __ARCH_WANT_IPC_PARSE_VERSION
@@ -521,57 +526,6 @@ type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
# define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
# endif
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <asm/ptrace.h>
-#include <asm/stat.h>
-#include <linux/syscalls.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf)
-
-static inline pid_t waitpid(int pid, int *wait_stat, int flags)
-{
- return sys_wait4(pid, wait_stat, flags, NULL);
-}
-struct mmap_arg_struct;
-asmlinkage long sys_mmap2(struct mmap_arg_struct __user *arg);
-
-asmlinkage long sys_execve(struct pt_regs regs);
-asmlinkage long sys_clone(struct pt_regs regs);
-asmlinkage long sys_fork(struct pt_regs regs);
-asmlinkage long sys_vfork(struct pt_regs regs);
-asmlinkage long sys_pipe(unsigned long __user *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-sh/.gitignore b/include/asm-sh/.gitignore
new file mode 100644
index 000000000000..9218ef82b698
--- /dev/null
+++ b/include/asm-sh/.gitignore
@@ -0,0 +1,3 @@
+cpu
+mach
+machtypes.h
diff --git a/include/asm-sh/addrspace.h b/include/asm-sh/addrspace.h
index 720afc11c2ca..b860218e402e 100644
--- a/include/asm-sh/addrspace.h
+++ b/include/asm-sh/addrspace.h
@@ -14,11 +14,19 @@
#include <asm/cpu/addrspace.h>
/* Memory segments (32bit Privileged mode addresses) */
+#ifndef CONFIG_CPU_SH2A
#define P0SEG 0x00000000
#define P1SEG 0x80000000
#define P2SEG 0xa0000000
#define P3SEG 0xc0000000
#define P4SEG 0xe0000000
+#else
+#define P0SEG 0x00000000
+#define P1SEG 0x00000000
+#define P2SEG 0x20000000
+#define P3SEG 0x00000000
+#define P4SEG 0x80000000
+#endif
/* Returns the privileged segment base of a given address */
#define PXSEG(a) (((unsigned long)(a)) & 0xe0000000)
diff --git a/include/asm-sh/adx/io.h b/include/asm-sh/adx/io.h
deleted file mode 100644
index ab1225f1d557..000000000000
--- a/include/asm-sh/adx/io.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * include/asm-sh/io_adx.h
- *
- * Copyright (C) 2001 A&D Co., Ltd.
- *
- * This file may be copied or modified under the terms of the GNU
- * General Public License. See linux/COPYING for more information.
- *
- * IO functions for an A&D ADX Board
- */
-
-#ifndef _ASM_SH_IO_ADX_H
-#define _ASM_SH_IO_ADX_H
-
-#include <asm/io_generic.h>
-
-extern unsigned char adx_inb(unsigned long port);
-extern unsigned short adx_inw(unsigned long port);
-extern unsigned int adx_inl(unsigned long port);
-
-extern void adx_outb(unsigned char value, unsigned long port);
-extern void adx_outw(unsigned short value, unsigned long port);
-extern void adx_outl(unsigned int value, unsigned long port);
-
-extern unsigned char adx_inb_p(unsigned long port);
-extern void adx_outb_p(unsigned char value, unsigned long port);
-
-extern void adx_insb(unsigned long port, void *addr, unsigned long count);
-extern void adx_insw(unsigned long port, void *addr, unsigned long count);
-extern void adx_insl(unsigned long port, void *addr, unsigned long count);
-extern void adx_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void adx_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void adx_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned char adx_readb(unsigned long addr);
-extern unsigned short adx_readw(unsigned long addr);
-extern unsigned int adx_readl(unsigned long addr);
-extern void adx_writeb(unsigned char b, unsigned long addr);
-extern void adx_writew(unsigned short b, unsigned long addr);
-extern void adx_writel(unsigned int b, unsigned long addr);
-
-extern void * adx_ioremap(unsigned long offset, unsigned long size);
-extern void adx_iounmap(void *addr);
-
-extern unsigned long adx_isa_port2addr(unsigned long offset);
-
-extern void setup_adx(void);
-extern void init_adx_IRQ(void);
-
-#ifdef __WANT_IO_DEF
-
-#define __inb adx_inb
-#define __inw adx_inw
-#define __inl adx_inl
-#define __outb adx_outb
-#define __outw adx_outw
-#define __outl adx_outl
-
-#define __inb_p adx_inb_p
-#define __inw_p adx_inw
-#define __inl_p adx_inl
-#define __outb_p adx_outb_p
-#define __outw_p adx_outw
-#define __outl_p adx_outl
-
-#define __insb adx_insb
-#define __insw adx_insw
-#define __insl adx_insl
-#define __outsb adx_outsb
-#define __outsw adx_outsw
-#define __outsl adx_outsl
-
-#define __readb adx_readb
-#define __readw adx_readw
-#define __readl adx_readl
-#define __writeb adx_writeb
-#define __writew adx_writew
-#define __writel adx_writel
-
-#define __isa_port2addr adx_isa_port2addr
-#define __ioremap adx_ioremap
-#define __iounmap adx_iounmap
-
-#endif
-
-#endif /* _ASM_SH_IO_AANDD_H */
diff --git a/include/asm-sh/apm.h b/include/asm-sh/apm.h
new file mode 100644
index 000000000000..8b091e93651f
--- /dev/null
+++ b/include/asm-sh/apm.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.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 __ASM_SH_APM_H
+#define __ASM_SH_APM_H
+
+#define APM_AC_OFFLINE 0
+#define APM_AC_ONLINE 1
+#define APM_AC_BACKUP 2
+#define APM_AC_UNKNOWN 0xff
+
+#define APM_BATTERY_STATUS_HIGH 0
+#define APM_BATTERY_STATUS_LOW 1
+#define APM_BATTERY_STATUS_CRITICAL 2
+#define APM_BATTERY_STATUS_CHARGING 3
+#define APM_BATTERY_STATUS_NOT_PRESENT 4
+#define APM_BATTERY_STATUS_UNKNOWN 0xff
+
+#define APM_BATTERY_LIFE_UNKNOWN 0xFFFF
+#define APM_BATTERY_LIFE_MINUTES 0x8000
+#define APM_BATTERY_LIFE_VALUE_MASK 0x7FFF
+
+#define APM_BATTERY_FLAG_HIGH (1 << 0)
+#define APM_BATTERY_FLAG_LOW (1 << 1)
+#define APM_BATTERY_FLAG_CRITICAL (1 << 2)
+#define APM_BATTERY_FLAG_CHARGING (1 << 3)
+#define APM_BATTERY_FLAG_NOT_PRESENT (1 << 7)
+#define APM_BATTERY_FLAG_UNKNOWN 0xff
+
+#define APM_UNITS_MINS 0
+#define APM_UNITS_SECS 1
+#define APM_UNITS_UNKNOWN -1
+
+
+extern int (*apm_get_info)(char *buf, char **start, off_t fpos, int length);
+extern int apm_suspended;
+
+void apm_queue_event(apm_event_t event);
+
+#endif
diff --git a/include/asm-sh/atomic.h b/include/asm-sh/atomic.h
index fb627de217f2..8bdc1ba56f73 100644
--- a/include/asm-sh/atomic.h
+++ b/include/asm-sh/atomic.h
@@ -14,6 +14,7 @@ typedef struct { volatile int counter; } atomic_t;
#define atomic_read(v) ((v)->counter)
#define atomic_set(v,i) ((v)->counter = (i))
+#include <linux/compiler.h>
#include <asm/system.h>
/*
@@ -21,49 +22,110 @@ typedef struct { volatile int counter; } atomic_t;
* forward to code at the end of this object's .text section, then
* branch back to restart the operation.
*/
-
-static __inline__ void atomic_add(int i, atomic_t * v)
+static inline void atomic_add(int i, atomic_t *v)
{
+#ifdef CONFIG_CPU_SH4A
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%3, %0 ! atomic_add \n"
+" add %2, %0 \n"
+" movco.l %0, @%3 \n"
+" bf 1b \n"
+ : "=&z" (tmp), "=r" (&v->counter)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+#else
unsigned long flags;
local_irq_save(flags);
*(long *)v += i;
local_irq_restore(flags);
+#endif
}
-static __inline__ void atomic_sub(int i, atomic_t *v)
+static inline void atomic_sub(int i, atomic_t *v)
{
+#ifdef CONFIG_CPU_SH4A
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%3, %0 ! atomic_sub \n"
+" sub %2, %0 \n"
+" movco.l %0, @%3 \n"
+" bf 1b \n"
+ : "=&z" (tmp), "=r" (&v->counter)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+#else
unsigned long flags;
local_irq_save(flags);
*(long *)v -= i;
local_irq_restore(flags);
+#endif
}
-static __inline__ int atomic_add_return(int i, atomic_t * v)
+/*
+ * SH-4A note:
+ *
+ * We basically get atomic_xxx_return() for free compared with
+ * atomic_xxx(). movli.l/movco.l require r0 due to the instruction
+ * encoding, so the retval is automatically set without having to
+ * do any special work.
+ */
+static inline int atomic_add_return(int i, atomic_t *v)
{
- unsigned long temp, flags;
+ unsigned long temp;
+
+#ifdef CONFIG_CPU_SH4A
+ __asm__ __volatile__ (
+"1: movli.l @%3, %0 ! atomic_add_return \n"
+" add %2, %0 \n"
+" movco.l %0, @%3 \n"
+" bf 1b \n"
+" synco \n"
+ : "=&z" (temp), "=r" (&v->counter)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+#else
+ unsigned long flags;
local_irq_save(flags);
temp = *(long *)v;
temp += i;
*(long *)v = temp;
local_irq_restore(flags);
+#endif
return temp;
}
#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0)
-static __inline__ int atomic_sub_return(int i, atomic_t * v)
+static inline int atomic_sub_return(int i, atomic_t *v)
{
- unsigned long temp, flags;
+ unsigned long temp;
+
+#ifdef CONFIG_CPU_SH4A
+ __asm__ __volatile__ (
+"1: movli.l @%3, %0 ! atomic_sub_return \n"
+" sub %2, %0 \n"
+" movco.l %0, @%3 \n"
+" bf 1b \n"
+" synco \n"
+ : "=&z" (temp), "=r" (&v->counter)
+ : "r" (i), "r" (&v->counter)
+ : "t");
+#else
+ unsigned long flags;
local_irq_save(flags);
temp = *(long *)v;
temp -= i;
*(long *)v = temp;
local_irq_restore(flags);
+#endif
return temp;
}
@@ -118,22 +180,48 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u)
}
#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0)
-static __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
+static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
{
+#ifdef CONFIG_CPU_SH4A
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%3, %0 ! atomic_clear_mask \n"
+" and %2, %0 \n"
+" movco.l %0, @%3 \n"
+" bf 1b \n"
+ : "=&z" (tmp), "=r" (&v->counter)
+ : "r" (~mask), "r" (&v->counter)
+ : "t");
+#else
unsigned long flags;
local_irq_save(flags);
*(long *)v &= ~mask;
local_irq_restore(flags);
+#endif
}
-static __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
+static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
{
+#ifdef CONFIG_CPU_SH4A
+ unsigned long tmp;
+
+ __asm__ __volatile__ (
+"1: movli.l @%3, %0 ! atomic_set_mask \n"
+" or %2, %0 \n"
+" movco.l %0, @%3 \n"
+" bf 1b \n"
+ : "=&z" (tmp), "=r" (&v->counter)
+ : "r" (mask), "r" (&v->counter)
+ : "t");
+#else
unsigned long flags;
local_irq_save(flags);
*(long *)v |= mask;
local_irq_restore(flags);
+#endif
}
/* Atomic operations are already serializing on SH */
diff --git a/include/asm-sh/auxvec.h b/include/asm-sh/auxvec.h
index fc21e4db5881..1b6916e63e90 100644
--- a/include/asm-sh/auxvec.h
+++ b/include/asm-sh/auxvec.h
@@ -1,4 +1,18 @@
#ifndef __ASM_SH_AUXVEC_H
#define __ASM_SH_AUXVEC_H
+/*
+ * Architecture-neutral AT_ values in 0-17, leave some room
+ * for more of them.
+ */
+
+#ifdef CONFIG_VSYSCALL
+/*
+ * Only define this in the vsyscall case, the entry point to
+ * the vsyscall page gets placed here. The kernel will attempt
+ * to build a gate VMA we don't care about otherwise..
+ */
+#define AT_SYSINFO_EHDR 33
+#endif
+
#endif /* __ASM_SH_AUXVEC_H */
diff --git a/include/asm-sh/bigsur/io.h b/include/asm-sh/bigsur/io.h
index 939735ee8dc5..1470ac8d4a39 100644
--- a/include/asm-sh/bigsur/io.h
+++ b/include/asm-sh/bigsur/io.h
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/io_bigsur.h
+ * include/asm-sh/bigsur/io.h
*
* By Dustin McIntire (dustin@sensoria.com) (c)2001
* Derived from io_hd64465.h, which bore the message:
diff --git a/include/asm-sh/bigsur/serial.h b/include/asm-sh/bigsur/serial.h
index 7233af42f755..a08fa82fe45a 100644
--- a/include/asm-sh/bigsur/serial.h
+++ b/include/asm-sh/bigsur/serial.h
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/serial-bigsur.h
+ * include/asm-sh/bigsur/serial.h
*
* Configuration details for Big Sur 16550 based serial ports
* i.e. HD64465, PCMCIA, etc.
diff --git a/include/asm-sh/bitops.h b/include/asm-sh/bitops.h
index e34f82508568..1c16792cee1d 100644
--- a/include/asm-sh/bitops.h
+++ b/include/asm-sh/bitops.h
@@ -6,7 +6,7 @@
/* For __swab32 */
#include <asm/byteorder.h>
-static __inline__ void set_bit(int nr, volatile void * addr)
+static inline void set_bit(int nr, volatile void * addr)
{
int mask;
volatile unsigned int *a = addr;
@@ -24,7 +24,7 @@ static __inline__ void set_bit(int nr, volatile void * addr)
*/
#define smp_mb__before_clear_bit() barrier()
#define smp_mb__after_clear_bit() barrier()
-static __inline__ void clear_bit(int nr, volatile void * addr)
+static inline void clear_bit(int nr, volatile void * addr)
{
int mask;
volatile unsigned int *a = addr;
@@ -37,7 +37,7 @@ static __inline__ void clear_bit(int nr, volatile void * addr)
local_irq_restore(flags);
}
-static __inline__ void change_bit(int nr, volatile void * addr)
+static inline void change_bit(int nr, volatile void * addr)
{
int mask;
volatile unsigned int *a = addr;
@@ -50,7 +50,7 @@ static __inline__ void change_bit(int nr, volatile void * addr)
local_irq_restore(flags);
}
-static __inline__ int test_and_set_bit(int nr, volatile void * addr)
+static inline int test_and_set_bit(int nr, volatile void * addr)
{
int mask, retval;
volatile unsigned int *a = addr;
@@ -66,7 +66,7 @@ static __inline__ int test_and_set_bit(int nr, volatile void * addr)
return retval;
}
-static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+static inline int test_and_clear_bit(int nr, volatile void * addr)
{
int mask, retval;
volatile unsigned int *a = addr;
@@ -82,7 +82,7 @@ static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
return retval;
}
-static __inline__ int test_and_change_bit(int nr, volatile void * addr)
+static inline int test_and_change_bit(int nr, volatile void * addr)
{
int mask, retval;
volatile unsigned int *a = addr;
@@ -100,7 +100,7 @@ static __inline__ int test_and_change_bit(int nr, volatile void * addr)
#include <asm-generic/bitops/non-atomic.h>
-static __inline__ unsigned long ffz(unsigned long word)
+static inline unsigned long ffz(unsigned long word)
{
unsigned long result;
@@ -120,7 +120,7 @@ static __inline__ unsigned long ffz(unsigned long word)
*
* Undefined if no bit exists, so code should check against 0 first.
*/
-static __inline__ unsigned long __ffs(unsigned long word)
+static inline unsigned long __ffs(unsigned long word)
{
unsigned long result;
diff --git a/include/asm-sh/bugs.h b/include/asm-sh/bugs.h
index a6de3d06a3d9..beeea40f549e 100644
--- a/include/asm-sh/bugs.h
+++ b/include/asm-sh/bugs.h
@@ -18,7 +18,7 @@ static void __init check_bugs(void)
{
extern char *get_cpu_subtype(void);
extern unsigned long loops_per_jiffy;
- char *p= &system_utsname.machine[2]; /* "sh" */
+ char *p= &init_utsname()->machine[2]; /* "sh" */
cpu_data->loops_per_jiffy = loops_per_jiffy;
@@ -32,6 +32,10 @@ static void __init check_bugs(void)
case CPU_SH7750 ... CPU_SH4_501:
*p++ = '4';
break;
+ case CPU_SH7770 ... CPU_SH7781:
+ *p++ = '4';
+ *p++ = 'a';
+ break;
default:
*p++ = '?';
*p++ = '!';
diff --git a/include/asm-sh/cache.h b/include/asm-sh/cache.h
index 656fdfe9e8b4..e3a180cf5062 100644
--- a/include/asm-sh/cache.h
+++ b/include/asm-sh/cache.h
@@ -10,7 +10,6 @@
#ifdef __KERNEL__
#include <asm/cpu/cache.h>
-#include <asm/cpu/cacheflush.h>
#define SH_CACHE_VALID 1
#define SH_CACHE_UPDATED 2
@@ -23,24 +22,31 @@
#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1))
struct cache_info {
- unsigned int ways;
- unsigned int sets;
- unsigned int linesz;
+ unsigned int ways; /* Number of cache ways */
+ unsigned int sets; /* Number of cache sets */
+ unsigned int linesz; /* Cache line size (bytes) */
- unsigned int way_incr;
+ unsigned int way_size; /* sets * line size */
+ /*
+ * way_incr is the address offset for accessing the next way
+ * in memory mapped cache array ops.
+ */
+ unsigned int way_incr;
unsigned int entry_shift;
unsigned int entry_mask;
+ /*
+ * Compute a mask which selects the address bits which overlap between
+ * 1. those used to select the cache set during indexing
+ * 2. those in the physical page number.
+ */
+ unsigned int alias_mask;
+
+ unsigned int n_aliases; /* Number of aliases */
+
unsigned long flags;
};
-/* Flush (write-back only) a region (smaller than a page) */
-extern void __flush_wback_region(void *start, int size);
-/* Flush (write-back & invalidate) a region (smaller than a page) */
-extern void __flush_purge_region(void *start, int size);
-/* Flush (invalidate only) a region (smaller than a page) */
-extern void __flush_invalidate_region(void *start, int size);
-
#endif /* __KERNEL__ */
#endif /* __ASM_SH_CACHE_H */
diff --git a/include/asm-sh/cacheflush.h b/include/asm-sh/cacheflush.h
index 9dfb33edb008..07f62ec9ff0c 100644
--- a/include/asm-sh/cacheflush.h
+++ b/include/asm-sh/cacheflush.h
@@ -2,6 +2,7 @@
#define __ASM_SH_CACHEFLUSH_H
#ifdef __KERNEL__
+#include <linux/mm.h>
#include <asm/cpu/cacheflush.h>
/* Flush (write-back only) a region (smaller than a page) */
@@ -27,5 +28,7 @@ extern void __flush_invalidate_region(void *start, int size);
memcpy(dst, src, len); \
} while (0)
+#define HAVE_ARCH_UNMAPPED_AREA
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_CACHEFLUSH_H */
diff --git a/include/asm-sh/cat68701/io.h b/include/asm-sh/cat68701/io.h
deleted file mode 100644
index 753b8466ad11..000000000000
--- a/include/asm-sh/cat68701/io.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * include/asm-sh/io_cat68701.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- * 2001 Yutarou Ebihar (ebihara@si-linux.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an AONE Corp. CAT-68701 SH7708 Borad
- */
-
-#ifndef _ASM_SH_IO_CAT68701_H
-#define _ASM_SH_IO_CAT68701_H
-
-extern unsigned long cat68701_isa_port2addr(unsigned long offset);
-extern int cat68701_irq_demux(int irq);
-
-extern void init_cat68701_IRQ(void);
-extern void heartbeat_cat68701(void);
-
-#endif /* _ASM_SH_IO_CAT68701_H */
diff --git a/include/asm-sh/checksum.h b/include/asm-sh/checksum.h
index fa03b30c4269..08168afe6746 100644
--- a/include/asm-sh/checksum.h
+++ b/include/asm-sh/checksum.h
@@ -159,6 +159,7 @@ static __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
}
#define _HAVE_ARCH_IPV6_CSUM
+#ifdef CONFIG_IPV6
static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
struct in6_addr *daddr,
__u32 len,
@@ -194,6 +195,7 @@ static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
return csum_fold(sum);
}
+#endif
/*
* Copy and checksum to user
diff --git a/include/asm-sh/cpu-features.h b/include/asm-sh/cpu-features.h
new file mode 100644
index 000000000000..4bccd7c032f9
--- /dev/null
+++ b/include/asm-sh/cpu-features.h
@@ -0,0 +1,24 @@
+#ifndef __ASM_SH_CPU_FEATURES_H
+#define __ASM_SH_CPU_FEATURES_H
+
+/*
+ * Processor flags
+ *
+ * Note: When adding a new flag, keep cpu_flags[] in
+ * arch/sh/kernel/setup.c in sync so symbolic name
+ * mapping of the processor flags has a chance of being
+ * reasonably accurate.
+ *
+ * These flags are also available through the ELF
+ * auxiliary vector as AT_HWCAP.
+ */
+#define CPU_HAS_FPU 0x0001 /* Hardware FPU support */
+#define CPU_HAS_P2_FLUSH_BUG 0x0002 /* Need to flush the cache in P2 area */
+#define CPU_HAS_MMU_PAGE_ASSOC 0x0004 /* SH3: TLB way selection bit support */
+#define CPU_HAS_DSP 0x0008 /* SH-DSP: DSP support */
+#define CPU_HAS_PERF_COUNTER 0x0010 /* Hardware performance counters */
+#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 */
+
+#endif /* __ASM_SH_CPU_FEATURES_H */
diff --git a/include/asm-sh/cpu-sh2/shmparam.h b/include/asm-sh/cpu-sh2/shmparam.h
deleted file mode 100644
index 817c1821ee4b..000000000000
--- a/include/asm-sh/cpu-sh2/shmparam.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * include/asm-sh/cpu-sh2/shmparam.h
- *
- * Copyright (C) 2003 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.
- */
-#ifndef __ASM_CPU_SH2_SHMPARAM_H
-#define __ASM_CPU_SH2_SHMPARAM_H
-
-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
-
-#endif /* __ASM_CPU_SH2_SHMPARAM_H */
-
diff --git a/include/asm-sh/cpu-sh3/cache.h b/include/asm-sh/cpu-sh3/cache.h
index 406aa8d9b947..ffe08d2813f9 100644
--- a/include/asm-sh/cpu-sh3/cache.h
+++ b/include/asm-sh/cpu-sh3/cache.h
@@ -26,12 +26,10 @@
#define CCR_CACHE_ENABLE CCR_CACHE_CE
#define CCR_CACHE_INVALIDATE CCR_CACHE_CF
-#if defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7705) || defined(CONFIG_CPU_SUBTYPE_SH7710)
#define CCR3 0xa40000b4
#define CCR_CACHE_16KB 0x00010000
#define CCR_CACHE_32KB 0x00020000
#endif
-
#endif /* __ASM_CPU_SH3_CACHE_H */
-
diff --git a/include/asm-sh/cpu-sh3/cacheflush.h b/include/asm-sh/cpu-sh3/cacheflush.h
index f51aed00c68f..03fde97a7fd0 100644
--- a/include/asm-sh/cpu-sh3/cacheflush.h
+++ b/include/asm-sh/cpu-sh3/cacheflush.h
@@ -10,7 +10,7 @@
#ifndef __ASM_CPU_SH3_CACHEFLUSH_H
#define __ASM_CPU_SH3_CACHEFLUSH_H
-/*
+/*
* Cache flushing:
*
* - flush_cache_all() flushes entire cache
@@ -35,53 +35,33 @@
/* 32KB cache, 4kb PAGE sizes need to check bit 12 */
#define CACHE_ALIAS 0x00001000
-struct page;
-struct mm_struct;
-struct vm_area_struct;
-
-extern void flush_cache_all(void);
-extern void flush_cache_mm(struct mm_struct *mm);
-extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end);
-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
-extern void flush_dcache_page(struct page *pg);
-extern void flush_icache_range(unsigned long start, unsigned long end);
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
-
-#define flush_dcache_mmap_lock(mapping) do { } while (0)
-#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-
-/* SH3 has unified cache so no special action needed here */
-#define flush_cache_sigtramp(vaddr) do { } while (0)
-#define flush_page_to_ram(page) do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
-
-#define p3_cache_init() do { } while (0)
-
#define PG_mapped PG_arch_1
-/* We provide our own get_unmapped_area to avoid cache alias issue */
-#define HAVE_ARCH_UNMAPPED_AREA
-
+void flush_cache_all(void);
+void flush_cache_mm(struct mm_struct *mm);
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end);
+void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
+void flush_dcache_page(struct page *pg);
+void flush_icache_range(unsigned long start, unsigned long end);
+void flush_icache_page(struct vm_area_struct *vma, struct page *page);
#else
-
#define flush_cache_all() do { } while (0)
#define flush_cache_mm(mm) do { } while (0)
#define flush_cache_range(vma, start, end) do { } while (0)
#define flush_cache_page(vma, vmaddr, pfn) do { } while (0)
#define flush_dcache_page(page) do { } while (0)
-#define flush_dcache_mmap_lock(mapping) do { } while (0)
-#define flush_dcache_mmap_unlock(mapping) do { } while (0)
#define flush_icache_range(start, end) do { } while (0)
#define flush_icache_page(vma,pg) do { } while (0)
-#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
-#define flush_cache_sigtramp(vaddr) do { } while (0)
+#endif
-#define p3_cache_init() do { } while (0)
+#define flush_dcache_mmap_lock(mapping) do { } while (0)
+#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-#define HAVE_ARCH_UNMAPPED_AREA
+/* SH3 has unified cache so no special action needed here */
+#define flush_cache_sigtramp(vaddr) do { } while (0)
+#define flush_icache_user_range(vma,pg,adr,len) do { } while (0)
-#endif
+#define p3_cache_init() do { } while (0)
#endif /* __ASM_CPU_SH3_CACHEFLUSH_H */
-
diff --git a/include/asm-sh/cpu-sh3/freq.h b/include/asm-sh/cpu-sh3/freq.h
index b61b6e331df0..273f3229785c 100644
--- a/include/asm-sh/cpu-sh3/freq.h
+++ b/include/asm-sh/cpu-sh3/freq.h
@@ -18,5 +18,9 @@
#define MIN_DIVISOR_NR 0
#define MAX_DIVISOR_NR 4
+#define FRQCR_CKOEN 0x0100
+#define FRQCR_PLLEN 0x0080
+#define FRQCR_PSTBY 0x0040
+
#endif /* __ASM_CPU_SH3_FREQ_H */
diff --git a/include/asm-sh/cpu-sh3/mmu_context.h b/include/asm-sh/cpu-sh3/mmu_context.h
index a844ea0965b6..bccb7ddb438b 100644
--- a/include/asm-sh/cpu-sh3/mmu_context.h
+++ b/include/asm-sh/cpu-sh3/mmu_context.h
@@ -27,8 +27,12 @@
#define TRA 0xffffffd0
#define EXPEVT 0xffffffd4
-#if defined(CONFIG_CPU_SUBTYPE_SH7707) || defined(CONFIG_CPU_SUBTYPE_SH7709) || \
- defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7705)
+#if defined(CONFIG_CPU_SUBTYPE_SH7707) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7300) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710)
#define INTEVT 0xa4000000 /* INTEVTE2(0xa4000000) */
#else
#define INTEVT 0xffffffd8
diff --git a/include/asm-sh/cpu-sh3/rtc.h b/include/asm-sh/cpu-sh3/rtc.h
deleted file mode 100644
index 2d926671115a..000000000000
--- a/include/asm-sh/cpu-sh3/rtc.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __ASM_CPU_SH3_RTC_H
-#define __ASM_CPU_SH3_RTC_H
-
-/* SH-3 RTC */
-#define R64CNT 0xfffffec0
-#define RSECCNT 0xfffffec2
-#define RMINCNT 0xfffffec4
-#define RHRCNT 0xfffffec6
-#define RWKCNT 0xfffffec8
-#define RDAYCNT 0xfffffeca
-#define RMONCNT 0xfffffecc
-#define RYRCNT 0xfffffece
-#define RSECAR 0xfffffed0
-#define RMINAR 0xfffffed2
-#define RHRAR 0xfffffed4
-#define RWKAR 0xfffffed6
-#define RDAYAR 0xfffffed8
-#define RMONAR 0xfffffeda
-#define RCR1 0xfffffedc
-#define RCR2 0xfffffede
-
-#define RTC_BIT_INVERTED 0 /* No bug on SH7708, SH7709A */
-
-#endif /* __ASM_CPU_SH3_RTC_H */
-
diff --git a/include/asm-sh/cpu-sh3/shmparam.h b/include/asm-sh/cpu-sh3/shmparam.h
deleted file mode 100644
index da5b5eec81ee..000000000000
--- a/include/asm-sh/cpu-sh3/shmparam.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * include/asm-sh/cpu-sh3/shmparam.h
- *
- * Copyright (C) 1999 Niibe Yutaka
- *
- * 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 __ASM_CPU_SH3_SHMPARAM_H
-#define __ASM_CPU_SH3_SHMPARAM_H
-
-#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */
-
-#endif /* __ASM_CPU_SH3_SHMPARAM_H */
-
diff --git a/include/asm-sh/cpu-sh3/timer.h b/include/asm-sh/cpu-sh3/timer.h
index 3d8e95e8d10c..b2394cf76f49 100644
--- a/include/asm-sh/cpu-sh3/timer.h
+++ b/include/asm-sh/cpu-sh3/timer.h
@@ -20,9 +20,14 @@
* SH7710
* SH7720
* SH7300
+ * SH7710
* ---------------------------------------------------------------------------
*/
+#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
+#define TMU_TOCR 0xfffffe90 /* Byte access */
+#endif
+
#if defined(CONFIG_CPU_SUBTYPE_SH7300) || defined(CONFIG_CPU_SUBTYPE_SH7710)
#define TMU_TSTR 0xa412fe92 /* Byte access */
@@ -39,9 +44,6 @@
#define TMU2_TCR 0xa412feb4 /* Word access */
#else
-#if !defined(CONFIG_CPU_SUBTYPE_SH7727)
-#define TMU_TOCR 0xfffffe90 /* Byte access */
-#endif
#define TMU_TSTR 0xfffffe92 /* Byte access */
#define TMU0_TCOR 0xfffffe94 /* Long access */
diff --git a/include/asm-sh/cpu-sh3/ubc.h b/include/asm-sh/cpu-sh3/ubc.h
index 0f809dec4e17..9d308cbe9b29 100644
--- a/include/asm-sh/cpu-sh3/ubc.h
+++ b/include/asm-sh/cpu-sh3/ubc.h
@@ -11,6 +11,19 @@
#ifndef __ASM_CPU_SH3_UBC_H
#define __ASM_CPU_SH3_UBC_H
+#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+#define UBC_BARA 0xa4ffffb0
+#define UBC_BAMRA 0xa4ffffb4
+#define UBC_BBRA 0xa4ffffb8
+#define UBC_BASRA 0xffffffe4
+#define UBC_BARB 0xa4ffffa0
+#define UBC_BAMRB 0xa4ffffa4
+#define UBC_BBRB 0xa4ffffa8
+#define UBC_BASRB 0xffffffe8
+#define UBC_BDRB 0xa4ffff90
+#define UBC_BDMRB 0xa4ffff94
+#define UBC_BRCR 0xa4ffff98
+#else
#define UBC_BARA 0xffffffb0
#define UBC_BAMRA 0xffffffb4
#define UBC_BBRA 0xffffffb8
@@ -22,6 +35,6 @@
#define UBC_BDRB 0xffffff90
#define UBC_BDMRB 0xffffff94
#define UBC_BRCR 0xffffff98
+#endif
#endif /* __ASM_CPU_SH3_UBC_H */
-
diff --git a/include/asm-sh/cpu-sh4/addrspace.h b/include/asm-sh/cpu-sh4/addrspace.h
index 727634d886ce..bb2e1b03060c 100644
--- a/include/asm-sh/cpu-sh4/addrspace.h
+++ b/include/asm-sh/cpu-sh4/addrspace.h
@@ -22,5 +22,8 @@
#define P4SEG_TLB_DATA 0xf7000000
#define P4SEG_REG_BASE 0xff000000
+#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
+#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
+
#endif /* __ASM_CPU_SH4_ADDRSPACE_H */
diff --git a/include/asm-sh/cpu-sh4/cache.h b/include/asm-sh/cpu-sh4/cache.h
index 1fe20359312c..6e9c7e6ee8e4 100644
--- a/include/asm-sh/cpu-sh4/cache.h
+++ b/include/asm-sh/cpu-sh4/cache.h
@@ -22,7 +22,9 @@
#define CCR_CACHE_ICE 0x0100 /* Instruction Cache Enable */
#define CCR_CACHE_ICI 0x0800 /* IC Invalidate */
#define CCR_CACHE_IIX 0x8000 /* IC Index Enable */
+#ifndef CONFIG_CPU_SUBTYPE_SH7780
#define CCR_CACHE_EMODE 0x80000000 /* EMODE Enable */
+#endif
/* Default CCR setup: 8k+16k-byte cache,P1-wb,enable */
#define CCR_CACHE_ENABLE (CCR_CACHE_OCE|CCR_CACHE_ICE)
diff --git a/include/asm-sh/cpu-sh4/cacheflush.h b/include/asm-sh/cpu-sh4/cacheflush.h
index f323567e085f..515fd574267c 100644
--- a/include/asm-sh/cpu-sh4/cacheflush.h
+++ b/include/asm-sh/cpu-sh4/cacheflush.h
@@ -16,40 +16,29 @@
* caching; in which case they're only semi-broken),
* so we need them.
*/
-
-/* Page is 4K, OC size is 16K, there are four lines. */
-#define CACHE_ALIAS 0x00003000
-
-struct page;
-struct mm_struct;
-struct vm_area_struct;
-
-extern void flush_cache_all(void);
-extern void flush_cache_mm(struct mm_struct *mm);
-extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end);
-extern void flush_cache_page(struct vm_area_struct *vma, unsigned long addr, unsigned long pfn);
-extern void flush_dcache_page(struct page *pg);
+void flush_cache_all(void);
+void flush_cache_mm(struct mm_struct *mm);
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end);
+void flush_cache_page(struct vm_area_struct *vma, unsigned long addr,
+ unsigned long pfn);
+void flush_dcache_page(struct page *pg);
#define flush_dcache_mmap_lock(mapping) do { } while (0)
#define flush_dcache_mmap_unlock(mapping) do { } while (0)
-extern void flush_icache_range(unsigned long start, unsigned long end);
-extern void flush_cache_sigtramp(unsigned long addr);
-extern void flush_icache_user_range(struct vm_area_struct *vma,
- struct page *page, unsigned long addr,
- int len);
+void flush_icache_range(unsigned long start, unsigned long end);
+void flush_cache_sigtramp(unsigned long addr);
+void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
+ unsigned long addr, int len);
#define flush_icache_page(vma,pg) do { } while (0)
/* Initialization of P3 area for copy_user_page */
-extern void p3_cache_init(void);
+void p3_cache_init(void);
#define PG_mapped PG_arch_1
-/* We provide our own get_unmapped_area to avoid cache alias issue */
-#define HAVE_ARCH_UNMAPPED_AREA
-
#ifdef CONFIG_MMU
extern int remap_area_pages(unsigned long addr, unsigned long phys_addr,
unsigned long size, unsigned long flags);
@@ -61,4 +50,3 @@ static inline int remap_area_pages(unsigned long addr, unsigned long phys_addr,
}
#endif /* CONFIG_MMU */
#endif /* __ASM_CPU_SH4_CACHEFLUSH_H */
-
diff --git a/include/asm-sh/cpu-sh4/dma-sh7780.h b/include/asm-sh/cpu-sh4/dma-sh7780.h
new file mode 100644
index 000000000000..6c90d28331b2
--- /dev/null
+++ b/include/asm-sh/cpu-sh4/dma-sh7780.h
@@ -0,0 +1,39 @@
+#ifndef __ASM_SH_CPU_SH4_DMA_SH7780_H
+#define __ASM_SH_CPU_SH4_DMA_SH7780_H
+
+#define REQ_HE 0x000000C0
+#define REQ_H 0x00000080
+#define REQ_LE 0x00000040
+#define TM_BURST 0x0000020
+#define TS_8 0x00000000
+#define TS_16 0x00000008
+#define TS_32 0x00000010
+#define TS_16BLK 0x00000018
+#define TS_32BLK 0x00100000
+
+/*
+ * The SuperH DMAC supports a number of transmit sizes, we list them here,
+ * with their respective values as they appear in the CHCR registers.
+ *
+ * Defaults to a 64-bit transfer size.
+ */
+enum {
+ XMIT_SZ_8BIT,
+ XMIT_SZ_16BIT,
+ XMIT_SZ_32BIT,
+ XMIT_SZ_128BIT,
+ XMIT_SZ_256BIT,
+};
+
+/*
+ * The DMA count is defined as the number of bytes to transfer.
+ */
+static unsigned int __attribute__ ((used)) ts_shift[] = {
+ [XMIT_SZ_8BIT] = 0,
+ [XMIT_SZ_16BIT] = 1,
+ [XMIT_SZ_32BIT] = 2,
+ [XMIT_SZ_128BIT] = 4,
+ [XMIT_SZ_256BIT] = 5,
+};
+
+#endif /* __ASM_SH_CPU_SH4_DMA_SH7780_H */
diff --git a/include/asm-sh/cpu-sh4/dma.h b/include/asm-sh/cpu-sh4/dma.h
index 0dfe61f14802..3e4b3e6d80c0 100644
--- a/include/asm-sh/cpu-sh4/dma.h
+++ b/include/asm-sh/cpu-sh4/dma.h
@@ -1,11 +1,17 @@
#ifndef __ASM_CPU_SH4_DMA_H
#define __ASM_CPU_SH4_DMA_H
+#define DMAOR_INIT ( 0x8000 | DMAOR_DME )
+
#ifdef CONFIG_CPU_SH4A
#define SH_DMAC_BASE 0xfc808020
+
+#define CHCR_TS_MASK 0x18
+#define CHCR_TS_SHIFT 3
+
+#include <asm/cpu/dma-sh7780.h>
#else
#define SH_DMAC_BASE 0xffa00000
-#endif
/* Definitions for the SuperH DMAC */
#define TM_BURST 0x0000080
@@ -19,8 +25,6 @@
#define DMAOR_COD 0x00000008
-#define DMAOR_INIT ( 0x8000 | DMAOR_DME )
-
/*
* The SuperH DMAC supports a number of transmit sizes, we list them here,
* with their respective values as they appear in the CHCR registers.
@@ -45,5 +49,6 @@ static unsigned int ts_shift[] __attribute__ ((used)) = {
[XMIT_SZ_32BIT] = 2,
[XMIT_SZ_256BIT] = 5,
};
+#endif
#endif /* __ASM_CPU_SH4_DMA_H */
diff --git a/include/asm-sh/cpu-sh4/rtc.h b/include/asm-sh/cpu-sh4/rtc.h
deleted file mode 100644
index e091e32a67b7..000000000000
--- a/include/asm-sh/cpu-sh4/rtc.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __ASM_CPU_SH4_RTC_H
-#define __ASM_CPU_SH4_RTC_H
-
-/* SH-4 RTC */
-#define R64CNT 0xffc80000
-#define RSECCNT 0xffc80004
-#define RMINCNT 0xffc80008
-#define RHRCNT 0xffc8000c
-#define RWKCNT 0xffc80010
-#define RDAYCNT 0xffc80014
-#define RMONCNT 0xffc80018
-#define RYRCNT 0xffc8001c /* 16bit */
-#define RSECAR 0xffc80020
-#define RMINAR 0xffc80024
-#define RHRAR 0xffc80028
-#define RWKAR 0xffc8002c
-#define RDAYAR 0xffc80030
-#define RMONAR 0xffc80034
-#define RCR1 0xffc80038
-#define RCR2 0xffc8003c
-
-#define RTC_BIT_INVERTED 0x40 /* bug on SH7750, SH7750S */
-
-#endif /* __ASM_CPU_SH4_RTC_H */
-
diff --git a/include/asm-sh/cpu-sh4/shmparam.h b/include/asm-sh/cpu-sh4/shmparam.h
deleted file mode 100644
index a5a0aa9425fe..000000000000
--- a/include/asm-sh/cpu-sh4/shmparam.h
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * include/asm-sh/cpu-sh4/shmparam.h
- *
- * Copyright (C) 1999 Niibe Yutaka
- *
- * 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 __ASM_CPU_SH4_SHMPARAM_H
-#define __ASM_CPU_SH4_SHMPARAM_H
-
-/*
- * SH-4 has D-cache alias issue
- */
-#define SHMLBA (PAGE_SIZE*4) /* attach addr a multiple of this */
-
-#endif /* __ASM_CPU_SH4_SHMPARAM_H */
-
diff --git a/include/asm-sh/cpu-sh4/sq.h b/include/asm-sh/cpu-sh4/sq.h
index 366b09166d3b..586d6491816a 100644
--- a/include/asm-sh/cpu-sh4/sq.h
+++ b/include/asm-sh/cpu-sh4/sq.h
@@ -17,7 +17,7 @@
* Store queues range from e0000000-e3fffffc, allowing approx. 64MB to be
* mapped to any physical address space. Since data is written (and aligned)
* to 32-byte boundaries, we need to be sure that all allocations are aligned.
- */
+ */
#define SQ_SIZE 32
#define SQ_ALIGN_MASK (~(SQ_SIZE - 1))
#define SQ_ALIGN(addr) (((addr)+SQ_SIZE-1) & SQ_ALIGN_MASK)
@@ -26,23 +26,10 @@
#define SQ_QACR1 (P4SEG_REG_BASE + 0x3c)
#define SQ_ADDRMAX (P4SEG_STORE_QUE + 0x04000000)
-struct sq_mapping {
- const char *name;
-
- unsigned long sq_addr;
- unsigned long addr;
- unsigned int size;
-
- struct list_head list;
-};
-
/* arch/sh/kernel/cpu/sh4/sq.c */
-extern struct sq_mapping *sq_remap(unsigned long phys, unsigned int size, const char *name);
-extern void sq_unmap(struct sq_mapping *map);
-
-extern void sq_clear(unsigned long addr, unsigned int len);
-extern void sq_flush(void *addr);
-extern void sq_flush_range(unsigned long start, unsigned int len);
+unsigned long sq_remap(unsigned long phys, unsigned int size,
+ const char *name, unsigned long flags);
+void sq_unmap(unsigned long vaddr);
+void sq_flush_range(unsigned long start, unsigned int len);
#endif /* __ASM_CPU_SH4_SQ_H */
-
diff --git a/include/asm-sh/cpu-sh4/ubc.h b/include/asm-sh/cpu-sh4/ubc.h
index 3d0943167659..c86e17050935 100644
--- a/include/asm-sh/cpu-sh4/ubc.h
+++ b/include/asm-sh/cpu-sh4/ubc.h
@@ -3,6 +3,7 @@
*
* Copyright (C) 1999 Niibe Yutaka
* Copyright (C) 2003 Paul Mundt
+ * Copyright (C) 2006 Lineo Solutions Inc. support SH4A UBC
*
* 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
@@ -11,6 +12,41 @@
#ifndef __ASM_CPU_SH4_UBC_H
#define __ASM_CPU_SH4_UBC_H
+#if defined(CONFIG_CPU_SH4A)
+#define UBC_CBR0 0xff200000
+#define UBC_CRR0 0xff200004
+#define UBC_CAR0 0xff200008
+#define UBC_CAMR0 0xff20000c
+#define UBC_CBR1 0xff200020
+#define UBC_CRR1 0xff200024
+#define UBC_CAR1 0xff200028
+#define UBC_CAMR1 0xff20002c
+#define UBC_CDR1 0xff200030
+#define UBC_CDMR1 0xff200034
+#define UBC_CETR1 0xff200038
+#define UBC_CCMFR 0xff200600
+#define UBC_CBCR 0xff200620
+
+/* CBR */
+#define UBC_CBR_AIE (0x01<<30)
+#define UBC_CBR_ID_INST (0x01<<4)
+#define UBC_CBR_RW_READ (0x01<<1)
+#define UBC_CBR_CE (0x01)
+
+#define UBC_CBR_AIV_MASK (0x00FF0000)
+#define UBC_CBR_AIV_SHIFT (16)
+#define UBC_CBR_AIV_SET(asid) (((asid)<<UBC_CBR_AIV_SHIFT) & UBC_CBR_AIV_MASK)
+
+#define UBC_CBR_INIT 0x20000000
+
+/* CRR */
+#define UBC_CRR_RES (0x01<<13)
+#define UBC_CRR_PCB (0x01<<1)
+#define UBC_CRR_BIE (0x01)
+
+#define UBC_CRR_INIT 0x00002000
+
+#else /* CONFIG_CPU_SH4 */
#define UBC_BARA 0xff200000
#define UBC_BAMRA 0xff200004
#define UBC_BBRA 0xff200008
@@ -22,6 +58,7 @@
#define UBC_BDRB 0xff200018
#define UBC_BDMRB 0xff20001c
#define UBC_BRCR 0xff200020
+#endif /* CONFIG_CPU_SH4 */
#endif /* __ASM_CPU_SH4_UBC_H */
diff --git a/include/asm-sh/cqreek/cqreek.h b/include/asm-sh/cqreek/cqreek.h
deleted file mode 100644
index 09aecc06693e..000000000000
--- a/include/asm-sh/cqreek/cqreek.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __ASM_SH_CQREEK_CQREEK_H
-#define __ASM_SH_CQREEK_CQREEK_H
-
-#define BRIDGE_FEATURE 0x0002
-
-#define BRIDGE_IDE_CTRL 0x0018
-#define BRIDGE_IDE_INTR_LVL 0x001A
-#define BRIDGE_IDE_INTR_MASK 0x001C
-#define BRIDGE_IDE_INTR_STAT 0x001E
-
-#define BRIDGE_ISA_CTRL 0x0028
-#define BRIDGE_ISA_INTR_LVL 0x002A
-#define BRIDGE_ISA_INTR_MASK 0x002C
-#define BRIDGE_ISA_INTR_STAT 0x002E
-
-/* arch/sh/boards/cqreek/setup.c */
-extern void setup_cqreek(void);
-
-/* arch/sh/boards/cqreek/irq.c */
-extern int cqreek_has_ide, cqreek_has_isa;
-extern void init_cqreek_IRQ(void);
-
-/* arch/sh/boards/cqreek/io.c */
-extern unsigned long cqreek_port2addr(unsigned long port);
-
-#endif /* __ASM_SH_CQREEK_CQREEK_H */
-
diff --git a/include/asm-sh/dma-mapping.h b/include/asm-sh/dma-mapping.h
index 124968f9866e..56cd4b977232 100644
--- a/include/asm-sh/dma-mapping.h
+++ b/include/asm-sh/dma-mapping.h
@@ -141,25 +141,35 @@ static inline void dma_sync_sg(struct device *dev, struct scatterlist *sg,
}
}
-static void dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t dma_handle, size_t size,
- enum dma_data_direction dir)
- __attribute__ ((alias("dma_sync_single")));
+static inline void dma_sync_single_for_cpu(struct device *dev,
+ dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction dir)
+{
+ dma_sync_single(dev, dma_handle, size, dir);
+}
+
+static inline void dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle,
+ size_t size,
+ enum dma_data_direction dir)
+{
+ dma_sync_single(dev, dma_handle, size, dir);
+}
-static void dma_sync_single_for_device(struct device *dev,
- dma_addr_t dma_handle, size_t size,
+static inline void dma_sync_sg_for_cpu(struct device *dev,
+ struct scatterlist *sg, int nelems,
enum dma_data_direction dir)
- __attribute__ ((alias("dma_sync_single")));
+{
+ dma_sync_sg(dev, sg, nelems, dir);
+}
-static void dma_sync_sg_for_cpu(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
- __attribute__ ((alias("dma_sync_sg")));
+static inline void dma_sync_sg_for_device(struct device *dev,
+ struct scatterlist *sg, int nelems,
+ enum dma_data_direction dir)
+{
+ dma_sync_sg(dev, sg, nelems, dir);
+}
-static void dma_sync_sg_for_device(struct device *dev,
- struct scatterlist *sg, int nelems,
- enum dma_data_direction dir)
- __attribute__ ((alias("dma_sync_sg")));
static inline int dma_get_cache_alignment(void)
{
@@ -174,6 +184,4 @@ static inline int dma_mapping_error(dma_addr_t dma_addr)
{
return dma_addr == 0;
}
-
#endif /* __ASM_SH_DMA_MAPPING_H */
-
diff --git a/include/asm-sh/dma.h b/include/asm-sh/dma.h
index e62a6d0ed932..d9daa028689f 100644
--- a/include/asm-sh/dma.h
+++ b/include/asm-sh/dma.h
@@ -89,6 +89,7 @@ struct dma_channel {
wait_queue_head_t wait_queue;
struct sys_device dev;
+ char *name;
};
struct dma_info {
diff --git a/include/asm-sh/dmida/io.h b/include/asm-sh/dmida/io.h
deleted file mode 100644
index 21bd416c01c3..000000000000
--- a/include/asm-sh/dmida/io.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_SH_DMIDA_IO_H
-#define __ASM_SH_DMIDA_IO_H
-
-/*
- * Nothing special here.. just use the generic cchip io routines.
- */
-#include <asm/hd64465/io.h>
-
-#endif /* __ASM_SH_DMIDA_IO_H */
-
diff --git a/include/asm-sh/dreamcast/sysasic.h b/include/asm-sh/dreamcast/sysasic.h
index c8858537803c..7874e3dac736 100644
--- a/include/asm-sh/dreamcast/sysasic.h
+++ b/include/asm-sh/dreamcast/sysasic.h
@@ -1,4 +1,4 @@
-/* include/asm-sh/dc_sysasic.h
+/* include/asm-sh/dreamcast/sysasic.h
*
* Definitions for the Dreamcast System ASIC and related peripherals.
*
diff --git a/include/asm-sh/ec3104/keyboard.h b/include/asm-sh/ec3104/keyboard.h
index 0dee7b05b49d..c1253a683197 100644
--- a/include/asm-sh/ec3104/keyboard.h
+++ b/include/asm-sh/ec3104/keyboard.h
@@ -6,8 +6,6 @@ extern char ec3104_kbd_unexpected_up(unsigned char);
extern void ec3104_kbd_leds(unsigned char);
extern void ec3104_kbd_init_hw(void);
-#define SYSRQ_KEY 0x54
-
#define kbd_sysrq_xlate ec3104_kbd_sysrq_xlate
#define kbd_setkeycode ec3104_kbd_setkeycode
#define kbd_getkeycode ec3104_kbd_getkeycode
diff --git a/include/asm-sh/elf.h b/include/asm-sh/elf.h
index 1b63dfeea4f2..fc050fd7645e 100644
--- a/include/asm-sh/elf.h
+++ b/include/asm-sh/elf.h
@@ -1,6 +1,10 @@
#ifndef __ASM_SH_ELF_H
#define __ASM_SH_ELF_H
+#include <asm/auxvec.h>
+#include <asm/ptrace.h>
+#include <asm/user.h>
+
/* SH relocation types */
#define R_SH_NONE 0
#define R_SH_DIR32 1
@@ -46,9 +50,6 @@
* ELF register definitions..
*/
-#include <asm/ptrace.h>
-#include <asm/user.h>
-
typedef unsigned long elf_greg_t;
#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
@@ -91,7 +92,7 @@ typedef struct user_fpu_struct elf_fpregset_t;
instruction set this CPU supports. This could be done in user space,
but it's not easy, and we've already done it here. */
-#define ELF_HWCAP (0)
+#define ELF_HWCAP (boot_cpu_data.flags)
/* This yields a string that ld.so will use to load implementation
specific libraries for optimization. This is more specific in
@@ -119,4 +120,24 @@ extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
#endif
+#ifdef CONFIG_VSYSCALL
+/* vDSO has arch_setup_additional_pages */
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int executable_stack);
+
+extern unsigned int vdso_enabled;
+extern void __kernel_vsyscall;
+
+#define VDSO_BASE ((unsigned long)current->mm->context.vdso)
+#define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x))
+
+#define ARCH_DLINFO \
+do { \
+ if (vdso_enabled) \
+ NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \
+} while (0)
+#endif /* CONFIG_VSYSCALL */
+
#endif /* __ASM_SH_ELF_H */
diff --git a/include/asm-sh/fixmap.h b/include/asm-sh/fixmap.h
index 412bccaa07e6..458e9fa59545 100644
--- a/include/asm-sh/fixmap.h
+++ b/include/asm-sh/fixmap.h
@@ -25,7 +25,7 @@
* addresses. The point is to have a constant address at
* compile time, but to set the physical address only
* in the boot process. We allocate these special addresses
- * from the end of virtual memory (0xfffff000) backwards.
+ * from the end of P3 backwards.
* Also this lets us do fail-safe vmalloc(), we
* can guarantee that these special addresses and
* vmalloc()-ed addresses never overlap.
diff --git a/include/asm-sh/flat.h b/include/asm-sh/flat.h
index f29072e1c87e..0d5cc04ab005 100644
--- a/include/asm-sh/flat.h
+++ b/include/asm-sh/flat.h
@@ -13,7 +13,7 @@
#define __ASM_SH_FLAT_H
#define flat_stack_align(sp) /* nothing needed */
-#define flat_argvp_envp_on_stack() 1
+#define flat_argvp_envp_on_stack() 0
#define flat_old_ram_flag(flags) (flags)
#define flat_reloc_valid(reloc, size) ((reloc) <= (size))
#define flat_get_addr_from_rp(rp, relval, flags) get_unaligned(rp)
diff --git a/include/asm-sh/harp/harp.h b/include/asm-sh/harp/harp.h
deleted file mode 100644
index b2fbcfae9940..000000000000
--- a/include/asm-sh/harp/harp.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2001 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * Defintions applicable to the STMicroelectronics ST40STB1 HARP and
- * compatible boards.
- */
-
-#if defined(CONFIG_SH_STB1_HARP)
-
-#define EPLD_BASE 0xa0800000
-
-#define EPLD_LED (EPLD_BASE+0x000c0000)
-#define EPLD_INTSTAT0 (EPLD_BASE+0x00200000)
-#define EPLD_INTSTAT1 (EPLD_BASE+0x00240000)
-#define EPLD_INTMASK0 (EPLD_BASE+0x00280000)
-#define EPLD_INTMASK1 (EPLD_BASE+0x002c0000)
-#define EPLD_PAGEADDR (EPLD_BASE+0x00300000)
-#define EPLD_REVID1 (EPLD_BASE+0x00380000)
-#define EPLD_REVID2 (EPLD_BASE+0x003c0000)
-
-#define EPLD_LED_ON 1
-#define EPLD_LED_OFF 0
-
-#elif defined(CONFIG_SH_STB1_OVERDRIVE)
-
-#define EPLD_BASE 0xa7000000
-
-#define EPLD_REVID (EPLD_BASE+0x00000000)
-#define EPLD_LED (EPLD_BASE+0x00040000)
-#define EPLD_INTMASK0 (EPLD_BASE+0x001c0000)
-#define EPLD_INTMASK1 (EPLD_BASE+0x00200000)
-#define EPLD_INTSTAT0 (EPLD_BASE+0x00240000)
-#define EPLD_INTSTAT1 (EPLD_BASE+0x00280000)
-
-#define EPLD_LED_ON 0
-#define EPLD_LED_OFF 1
-
-#else
-#error Unknown board
-#endif
diff --git a/include/asm-sh/harp/io.h b/include/asm-sh/harp/io.h
deleted file mode 100644
index 68f39e0b39de..000000000000
--- a/include/asm-sh/harp/io.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef __ASM_SH_HARP_IO_H
-#define __ASM_SH_HARP_IO_H
-
-/*
- * Nothing special here.. just use the generic cchip io routines.
- */
-#include <asm/hd64465/io.h>
-
-#endif /* __ASM_SH_HARP_IO_H */
-
diff --git a/include/asm-sh/hd64461/hd64461.h b/include/asm-sh/hd64461.h
index 87f13d24c630..27e5c34e2659 100644
--- a/include/asm-sh/hd64461/hd64461.h
+++ b/include/asm-sh/hd64461.h
@@ -40,7 +40,12 @@
#define HD64461_LCDCBAR 0x11000
#define HD64461_LCDCLOR 0x11002
#define HD64461_LCDCCR 0x11004
-#define HD64461_LCDCCR_MOFF 0x80
+#define HD64461_LCDCCR_STBACK 0x0400
+#define HD64461_LCDCCR_STREQ 0x0100
+#define HD64461_LCDCCR_MOFF 0x0080
+#define HD64461_LCDCCR_REFSEL 0x0040
+#define HD64461_LCDCCR_EPON 0x0020
+#define HD64461_LCDCCR_SPON 0x0010
#define HD64461_LDR1 0x11010
#define HD64461_LDR1_DON 0x01
@@ -54,9 +59,9 @@
#define HD64461_LDVSPR 0x1101c
#define HD64461_LDR3 0x1101e
-#define HD64461_CPTWAR 0x11030
+#define HD64461_CPTWAR 0x11030
#define HD64461_CPTWDR 0x11032
-#define HD64461_CPTRAR 0x11034
+#define HD64461_CPTRAR 0x11034
#define HD64461_CPTRDR 0x11036
#define HD64461_GRDOR 0x11040
@@ -111,7 +116,7 @@
#define HD64461_PCCISR_BVD1 0x01 /* battery 1 */
#define HD64461_PCCISR_PCD_MASK 0x0c /* card detect */
-#define HD64461_PCCISR_BVD_MASK 0x03 /* battery voltage */
+#define HD64461_PCCISR_BVD_MASK 0x03 /* battery voltage */
#define HD64461_PCCISR_BVD_BATGOOD 0x03 /* battery good */
#define HD64461_PCCISR_BVD_BATWARN 0x01 /* battery low warning */
#define HD64461_PCCISR_BVD_BATDEAD1 0x02 /* battery dead */
@@ -139,11 +144,11 @@
/* PCC Card Status Change Interrupt Enable Register */
#define HD64461_PCCCSCIER_CRE 0x80 /* change reset enable */
-#define HD64461_PCCCSCIER_IREQE_MASK 0x60 /* IREQ enable */
+#define HD64461_PCCCSCIER_IREQE_MASK 0x60 /* IREQ enable */
#define HD64461_PCCCSCIER_IREQE_DISABLED 0x00 /* IREQ disabled */
-#define HD64461_PCCCSCIER_IREQE_LEVEL 0x20 /* IREQ level-triggered */
+#define HD64461_PCCCSCIER_IREQE_LEVEL 0x20 /* IREQ level-triggered */
#define HD64461_PCCCSCIER_IREQE_FALLING 0x40 /* IREQ falling-edge-trig */
-#define HD64461_PCCCSCIER_IREQE_RISING 0x60 /* IREQ rising-edge-trig */
+#define HD64461_PCCCSCIER_IREQE_RISING 0x60 /* IREQ rising-edge-trig */
#define HD64461_PCCCSCIER_SCE 0x10 /* status change enable */
#define HD64461_PCCCSCIER_CDE 0x08 /* card detect change enable */
@@ -155,7 +160,6 @@
#define HD64461_PCCSCR_VCC1 0x02 /* voltage control pin 1 */
#define HD64461_PCCSCR_SWP 0x01 /* write protect */
-
#define HD64461_P0OCR 0x1202a
#define HD64461_P1OCR 0x1202c
#define HD64461_PGCR 0x1202e
@@ -180,23 +184,25 @@
#define HD64461_NIRR 0x15000
#define HD64461_NIMR 0x15002
-#ifndef CONFIG_HD64461_IOBASE
-#define CONFIG_HD64461_IOBASE 0xb0000000
-#endif
-#ifndef CONFIG_HD64461_IRQ
-#define CONFIG_HD64461_IRQ 36
-#endif
-
#define HD64461_IRQBASE OFFCHIP_IRQ_BASE
-#define HD64461_IRQ_NUM 16
-
-#define HD64461_IRQ_UART (HD64461_IRQBASE+5)
-#define HD64461_IRQ_IRDA (HD64461_IRQBASE+6)
-#define HD64461_IRQ_TMU1 (HD64461_IRQBASE+9)
-#define HD64461_IRQ_TMU0 (HD64461_IRQBASE+10)
-#define HD64461_IRQ_GPIO (HD64461_IRQBASE+11)
-#define HD64461_IRQ_AFE (HD64461_IRQBASE+12)
-#define HD64461_IRQ_PCC1 (HD64461_IRQBASE+13)
-#define HD64461_IRQ_PCC0 (HD64461_IRQBASE+14)
+#define HD64461_IRQ_NUM 16
+
+#define HD64461_IRQ_UART (HD64461_IRQBASE+5)
+#define HD64461_IRQ_IRDA (HD64461_IRQBASE+6)
+#define HD64461_IRQ_TMU1 (HD64461_IRQBASE+9)
+#define HD64461_IRQ_TMU0 (HD64461_IRQBASE+10)
+#define HD64461_IRQ_GPIO (HD64461_IRQBASE+11)
+#define HD64461_IRQ_AFE (HD64461_IRQBASE+12)
+#define HD64461_IRQ_PCC1 (HD64461_IRQBASE+13)
+#define HD64461_IRQ_PCC0 (HD64461_IRQBASE+14)
+
+#define __IO_PREFIX hd64461
+#include <asm/io_generic.h>
+
+/* arch/sh/cchips/hd6446x/hd64461/setup.c */
+int hd64461_irq_demux(int irq);
+void hd64461_register_irq_demux(int irq,
+ int (*demux) (int irq, void *dev), void *dev);
+void hd64461_unregister_irq_demux(int irq);
#endif
diff --git a/include/asm-sh/hd64461/io.h b/include/asm-sh/hd64461/io.h
deleted file mode 100644
index 67f2489088d9..000000000000
--- a/include/asm-sh/hd64461/io.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * include/asm-sh/io_hd64461.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an HD64461
- */
-
-#ifndef _ASM_SH_IO_HD64461_H
-#define _ASM_SH_IO_HD64461_H
-
-extern unsigned char hd64461_inb(unsigned long port);
-extern unsigned short hd64461_inw(unsigned long port);
-extern unsigned int hd64461_inl(unsigned long port);
-
-extern void hd64461_outb(unsigned char value, unsigned long port);
-extern void hd64461_outw(unsigned short value, unsigned long port);
-extern void hd64461_outl(unsigned int value, unsigned long port);
-
-extern unsigned char hd64461_inb_p(unsigned long port);
-extern void hd64461_outb_p(unsigned char value, unsigned long port);
-
-extern void hd64461_insb(unsigned long port, void *addr, unsigned long count);
-extern void hd64461_insw(unsigned long port, void *addr, unsigned long count);
-extern void hd64461_insl(unsigned long port, void *addr, unsigned long count);
-
-extern void hd64461_outsb(unsigned long port, const void *buffer, unsigned long count);
-extern void hd64461_outsw(unsigned long port, const void *buffer, unsigned long count);
-extern void hd64461_outsl(unsigned long port, const void *buffer, unsigned long count);
-
-extern unsigned short hd64461_readw(unsigned long addr);
-extern void hd64461_writew(unsigned short b, unsigned long addr);
-
-
-extern int hd64461_irq_demux(int irq);
-extern void hd64461_register_irq_demux(int irq,
- int (*demux)(int irq, void *dev), void *dev);
-extern void hd64461_unregister_irq_demux(int irq);
-
-#endif /* _ASM_SH_IO_HD64461_H */
diff --git a/include/asm-sh/hd64465/io.h b/include/asm-sh/hd64465/io.h
index 1100bcf4968e..139f1472e5bb 100644
--- a/include/asm-sh/hd64465/io.h
+++ b/include/asm-sh/hd64465/io.h
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/io_hd64465.h
+ * include/asm-sh/hd64465/io.h
*
* By Greg Banks <gbanks@pocketpenguins.com>
* (c) 2000 PocketPenguins Inc.
diff --git a/include/asm-sh/hp6xx/hp6xx.h b/include/asm-sh/hp6xx/hp6xx.h
index a26247fd3d87..f35134c159dd 100644
--- a/include/asm-sh/hp6xx/hp6xx.h
+++ b/include/asm-sh/hp6xx/hp6xx.h
@@ -2,16 +2,33 @@
#define __ASM_SH_HP6XX_H
/*
- * Copyright (C) 2003 Andriy Skulysh
+ * Copyright (C) 2003, 2004, 2005 Andriy Skulysh
+ *
+ * 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.
+ *
*/
-#define HP680_TS_IRQ IRQ3_IRQ
+#define HP680_BTN_IRQ IRQ0_IRQ
+#define HP680_TS_IRQ IRQ3_IRQ
+#define HP680_HD64461_IRQ IRQ4_IRQ
#define DAC_LCD_BRIGHTNESS 0
#define DAC_SPEAKER_VOLUME 1
+#define PGDR_OPENED 0x01
+#define PGDR_MAIN_BATTERY_OUT 0x04
+#define PGDR_PLAY_BUTTON 0x08
+#define PGDR_REWIND_BUTTON 0x10
+#define PGDR_RECORD_BUTTON 0x20
+
#define PHDR_TS_PEN_DOWN 0x08
+#define PJDR_LED_BLINK 0x02
+
+#define PKDR_LED_GREEN 0x10
+
#define SCPDR_TS_SCAN_ENABLE 0x20
#define SCPDR_TS_SCAN_Y 0x02
#define SCPDR_TS_SCAN_X 0x01
@@ -21,11 +38,43 @@
#define ADC_CHANNEL_TS_Y 1
#define ADC_CHANNEL_TS_X 2
+#define ADC_CHANNEL_BATTERY 3
+#define ADC_CHANNEL_BACKUP 4
+#define ADC_CHANNEL_CHARGE 5
#define HD64461_GPADR_SPEAKER 0x01
#define HD64461_GPADR_PCMCIA0 (0x02|0x08)
+
#define HD64461_GPBDR_LCDOFF 0x01
+#define HD64461_GPBDR_LCD_CONTRAST_MASK 0x78
#define HD64461_GPBDR_LED_RED 0x80
+#include <asm/hd64461.h>
+#include <asm/io.h>
+
+#define PJDR 0xa4000130
+#define PKDR 0xa4000132
+
+static inline void hp6xx_led_red(int on)
+{
+ u16 v16;
+ v16 = ctrl_inw(CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
+ if (on)
+ ctrl_outw(v16 & (~HD64461_GPBDR_LED_RED), CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
+ else
+ ctrl_outw(v16 | HD64461_GPBDR_LED_RED, CONFIG_HD64461_IOBASE + HD64461_GPBDR - 0x10000);
+}
+
+static inline void hp6xx_led_green(int on)
+{
+ u8 v8;
+
+ v8 = ctrl_inb(PKDR);
+ if (on)
+ ctrl_outb(v8 & (~PKDR_LED_GREEN), PKDR);
+ else
+ ctrl_outb(v8 | PKDR_LED_GREEN, PKDR);
+}
+
#endif /* __ASM_SH_HP6XX_H */
diff --git a/include/asm-sh/hp6xx/io.h b/include/asm-sh/hp6xx/io.h
index 731798003550..2044476ab199 100644
--- a/include/asm-sh/hp6xx/io.h
+++ b/include/asm-sh/hp6xx/io.h
@@ -4,7 +4,7 @@
/*
* Nothing special here.. just use the generic cchip io routines.
*/
-#include <asm/hd64461/io.h>
+#include <asm/hd64461.h>
#endif /* __ASM_SH_HP6XX_IO_H */
diff --git a/include/asm-sh/hs7751rvoip/hs7751rvoip.h b/include/asm-sh/hs7751rvoip/hs7751rvoip.h
index 5f995f937a44..c4cff9d33927 100644
--- a/include/asm-sh/hs7751rvoip/hs7751rvoip.h
+++ b/include/asm-sh/hs7751rvoip/hs7751rvoip.h
@@ -19,8 +19,6 @@
#define PA_OUTPORTR 0xa400000e /* Output Port Reguster */
#define PA_VERREG 0xa4000014 /* FPGA Version Register */
-#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
-#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
@@ -44,4 +42,13 @@
#define IRQ_RINGING 4 /* Ringing IRQ */
#define IRQ_CODEC 5 /* CODEC IRQ */
+#define __IO_PREFIX hs7751rvoip
+#include <asm/io_generic.h>
+
+/* arch/sh/boards/renesas/hs7751rvoip/irq.c */
+void init_hs7751rvoip_IRQ(void);
+
+/* arch/sh/boards/renesas/hs7751rvoip/io.c */
+void *hs7751rvoip_ioremap(unsigned long, unsigned long);
+
#endif /* __ASM_SH_RENESAS_HS7751RVOIP */
diff --git a/include/asm-sh/hs7751rvoip/io.h b/include/asm-sh/hs7751rvoip/io.h
deleted file mode 100644
index 513c8514001b..000000000000
--- a/include/asm-sh/hs7751rvoip/io.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * include/asm-sh/hs7751rvoip/hs7751rvoip.h
- *
- * Modified version of io_se.h for the hs7751rvoip-specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an Renesas Technology sales HS7751RVOIP
- */
-
-#ifndef _ASM_SH_IO_HS7751RVOIP_H
-#define _ASM_SH_IO_HS7751RVOIP_H
-
-#include <asm/io_generic.h>
-
-extern unsigned char hs7751rvoip_inb(unsigned long port);
-extern unsigned short hs7751rvoip_inw(unsigned long port);
-extern unsigned int hs7751rvoip_inl(unsigned long port);
-
-extern void hs7751rvoip_outb(unsigned char value, unsigned long port);
-extern void hs7751rvoip_outw(unsigned short value, unsigned long port);
-extern void hs7751rvoip_outl(unsigned int value, unsigned long port);
-
-extern unsigned char hs7751rvoip_inb_p(unsigned long port);
-extern void hs7751rvoip_outb_p(unsigned char value, unsigned long port);
-
-extern void hs7751rvoip_insb(unsigned long port, void *addr, unsigned long count);
-extern void hs7751rvoip_insw(unsigned long port, void *addr, unsigned long count);
-extern void hs7751rvoip_insl(unsigned long port, void *addr, unsigned long count);
-extern void hs7751rvoip_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void hs7751rvoip_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void hs7751rvoip_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern void *hs7751rvoip_ioremap(unsigned long offset, unsigned long size);
-
-extern unsigned long hs7751rvoip_isa_port2addr(unsigned long offset);
-
-#endif /* _ASM_SH_IO_HS7751RVOIP_H */
diff --git a/include/asm-sh/hw_irq.h b/include/asm-sh/hw_irq.h
index fed26616967a..80ee1cda7498 100644
--- a/include/asm-sh/hw_irq.h
+++ b/include/asm-sh/hw_irq.h
@@ -1,4 +1,8 @@
#ifndef __ASM_SH_HW_IRQ_H
#define __ASM_SH_HW_IRQ_H
+#include <asm/atomic.h>
+
+extern atomic_t irq_err_count;
+
#endif /* __ASM_SH_HW_IRQ_H */
diff --git a/include/asm-sh/io.h b/include/asm-sh/io.h
index 894e64b2d5f0..a0e55b09e4fd 100644
--- a/include/asm-sh/io.h
+++ b/include/asm-sh/io.h
@@ -107,6 +107,9 @@
#define __raw_writew(v, a) __writew(v, (void __iomem *)(a))
#define __raw_writel(v, a) __writel(v, (void __iomem *)(a))
+void __raw_writesl(unsigned long addr, const void *data, int longlen);
+void __raw_readsl(unsigned long addr, void *data, int longlen);
+
/*
* The platform header files may define some of these macros to use
* the inlined versions where appropriate. These macros may also be
@@ -132,6 +135,9 @@
# define writel(v,a) ({ __raw_writel((v),(a)); mb(); })
#endif
+#define writesl __raw_writesl
+#define readsl __raw_readsl
+
#define readb_relaxed(a) readb(a)
#define readw_relaxed(a) readw(a)
#define readl_relaxed(a) readl(a)
@@ -209,8 +215,14 @@ static inline void ctrl_outl(unsigned int b, unsigned long addr)
*(volatile unsigned long*)addr = b;
}
+static inline void ctrl_delay(void)
+{
+ ctrl_inw(P2SEG);
+}
+
#define IO_SPACE_LIMIT 0xffffffff
+#ifdef CONFIG_MMU
/*
* Change virtual addresses to physical addresses and vv.
* These are trivial on the 1:1 Linux/SuperH mapping
@@ -224,6 +236,10 @@ static inline void *phys_to_virt(unsigned long address)
{
return (void *)P1SEGADDR(address);
}
+#else
+#define phys_to_virt(address) ((void *)(address))
+#define virt_to_phys(address) ((unsigned long)(address))
+#endif
#define virt_to_bus virt_to_phys
#define bus_to_virt phys_to_virt
@@ -288,22 +304,6 @@ __ioremap_mode(unsigned long offset, unsigned long size, unsigned long flags)
#define iounmap(addr) \
__iounmap((addr))
-static inline int check_signature(char __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
/*
* The caches on some architectures aren't dma-coherent and have need to
* handle this in software. There are three types of operations that
diff --git a/include/asm-sh/irq-sh73180.h b/include/asm-sh/irq-sh73180.h
index d705252be260..b28af9a69d72 100644
--- a/include/asm-sh/irq-sh73180.h
+++ b/include/asm-sh/irq-sh73180.h
@@ -311,6 +311,4 @@
#define IRQ6_PRIORITY 1
#define IRQ7_PRIORITY 1
-int shmse_irq_demux(int irq);
-
#endif /* __ASM_SH_IRQ_SH73180_H */
diff --git a/include/asm-sh/irq-sh7343.h b/include/asm-sh/irq-sh7343.h
new file mode 100644
index 000000000000..5d15419b53b0
--- /dev/null
+++ b/include/asm-sh/irq-sh7343.h
@@ -0,0 +1,317 @@
+#ifndef __ASM_SH_IRQ_SH7343_H
+#define __ASM_SH_IRQ_SH7343_H
+
+/*
+ * linux/include/asm-sh/irq-sh7343.h
+ *
+ * Copyright (C) 2006 Kenati Technologies Inc.
+ * Andre Mccurdy <andre@kenati.com>
+ * Ranjit Deshpande <ranjit@kenati.com>
+ */
+
+#undef INTC_IPRA
+#undef INTC_IPRB
+#undef INTC_IPRC
+#undef INTC_IPRD
+
+#undef DMTE0_IRQ
+#undef DMTE1_IRQ
+#undef DMTE2_IRQ
+#undef DMTE3_IRQ
+#undef DMTE4_IRQ
+#undef DMTE5_IRQ
+#undef DMTE6_IRQ
+#undef DMTE7_IRQ
+#undef DMAE_IRQ
+#undef DMA_IPR_ADDR
+#undef DMA_IPR_POS
+#undef DMA_PRIORITY
+
+#undef INTC_IMCR0
+#undef INTC_IMCR1
+#undef INTC_IMCR2
+#undef INTC_IMCR3
+#undef INTC_IMCR4
+#undef INTC_IMCR5
+#undef INTC_IMCR6
+#undef INTC_IMCR7
+#undef INTC_IMCR8
+#undef INTC_IMCR9
+#undef INTC_IMCR10
+
+
+#define INTC_IPRA 0xA4080000UL
+#define INTC_IPRB 0xA4080004UL
+#define INTC_IPRC 0xA4080008UL
+#define INTC_IPRD 0xA408000CUL
+#define INTC_IPRE 0xA4080010UL
+#define INTC_IPRF 0xA4080014UL
+#define INTC_IPRG 0xA4080018UL
+#define INTC_IPRH 0xA408001CUL
+#define INTC_IPRI 0xA4080020UL
+#define INTC_IPRJ 0xA4080024UL
+#define INTC_IPRK 0xA4080028UL
+#define INTC_IPRL 0xA408002CUL
+
+#define INTC_IMR0 0xA4080080UL
+#define INTC_IMR1 0xA4080084UL
+#define INTC_IMR2 0xA4080088UL
+#define INTC_IMR3 0xA408008CUL
+#define INTC_IMR4 0xA4080090UL
+#define INTC_IMR5 0xA4080094UL
+#define INTC_IMR6 0xA4080098UL
+#define INTC_IMR7 0xA408009CUL
+#define INTC_IMR8 0xA40800A0UL
+#define INTC_IMR9 0xA40800A4UL
+#define INTC_IMR10 0xA40800A8UL
+#define INTC_IMR11 0xA40800ACUL
+
+#define INTC_IMCR0 0xA40800C0UL
+#define INTC_IMCR1 0xA40800C4UL
+#define INTC_IMCR2 0xA40800C8UL
+#define INTC_IMCR3 0xA40800CCUL
+#define INTC_IMCR4 0xA40800D0UL
+#define INTC_IMCR5 0xA40800D4UL
+#define INTC_IMCR6 0xA40800D8UL
+#define INTC_IMCR7 0xA40800DCUL
+#define INTC_IMCR8 0xA40800E0UL
+#define INTC_IMCR9 0xA40800E4UL
+#define INTC_IMCR10 0xA40800E8UL
+#define INTC_IMCR11 0xA40800ECUL
+
+#define INTC_ICR0 0xA4140000UL
+#define INTC_ICR1 0xA414001CUL
+
+#define INTMSK0 0xa4140044
+#define INTMSKCLR0 0xa4140064
+#define INTC_INTPRI0 0xa4140010
+
+/*
+ NOTE:
+
+ *_IRQ = (INTEVT2 - 0x200)/0x20
+*/
+
+/* TMU0 */
+#define TMU0_IRQ 16
+#define TMU0_IPR_ADDR INTC_IPRA
+#define TMU0_IPR_POS 3
+#define TMU0_PRIORITY 2
+
+#define TIMER_IRQ 16
+#define TIMER_IPR_ADDR INTC_IPRA
+#define TIMER_IPR_POS 3
+#define TIMER_PRIORITY 2
+
+/* TMU1 */
+#define TMU1_IRQ 17
+#define TMU1_IPR_ADDR INTC_IPRA
+#define TMU1_IPR_POS 2
+#define TMU1_PRIORITY 2
+
+/* TMU2 */
+#define TMU2_IRQ 18
+#define TMU2_IPR_ADDR INTC_IPRA
+#define TMU2_IPR_POS 1
+#define TMU2_PRIORITY 2
+
+/* LCDC */
+#define LCDC_IRQ 28
+#define LCDC_IPR_ADDR INTC_IPRB
+#define LCDC_IPR_POS 2
+#define LCDC_PRIORITY 2
+
+/* VIO (Video I/O) */
+#define CEU_IRQ 52
+#define BEU_IRQ 53
+#define VEU_IRQ 54
+#define VOU_IRQ 55
+#define VIO_IPR_ADDR INTC_IPRE
+#define VIO_IPR_POS 2
+#define VIO_PRIORITY 2
+
+/* MFI (Multi Functional Interface) */
+#define MFI_IRQ 56
+#define MFI_IPR_ADDR INTC_IPRE
+#define MFI_IPR_POS 1
+#define MFI_PRIORITY 2
+
+/* VPU (Video Processing Unit) */
+#define VPU_IRQ 60
+#define VPU_IPR_ADDR INTC_IPRE
+#define VPU_IPR_POS 0
+#define VPU_PRIORITY 2
+
+/* 3DG */
+#define TDG_IRQ 63
+#define TDG_IPR_ADDR INTC_IPRJ
+#define TDG_IPR_POS 2
+#define TDG_PRIORITY 2
+
+/* DMAC(1) */
+#define DMTE0_IRQ 48
+#define DMTE1_IRQ 49
+#define DMTE2_IRQ 50
+#define DMTE3_IRQ 51
+#define DMA1_IPR_ADDR INTC_IPRE
+#define DMA1_IPR_POS 3
+#define DMA1_PRIORITY 7
+
+/* DMAC(2) */
+#define DMTE4_IRQ 76
+#define DMTE5_IRQ 77
+#define DMA2_IPR_ADDR INTC_IPRF
+#define DMA2_IPR_POS 2
+#define DMA2_PRIORITY 7
+
+/* SCIF0 */
+#define SCIF_ERI_IRQ 80
+#define SCIF_RXI_IRQ 81
+#define SCIF_BRI_IRQ 82
+#define SCIF_TXI_IRQ 83
+#define SCIF_IPR_ADDR INTC_IPRG
+#define SCIF_IPR_POS 3
+#define SCIF_PRIORITY 3
+
+/* SIOF0 */
+#define SIOF0_IRQ 84
+#define SIOF0_IPR_ADDR INTC_IPRH
+#define SIOF0_IPR_POS 3
+#define SIOF0_PRIORITY 3
+
+/* FLCTL (Flash Memory Controller) */
+#define FLSTE_IRQ 92
+#define FLTEND_IRQ 93
+#define FLTRQ0_IRQ 94
+#define FLTRQ1_IRQ 95
+#define FLCTL_IPR_ADDR INTC_IPRH
+#define FLCTL_IPR_POS 1
+#define FLCTL_PRIORITY 3
+
+/* IIC(0) (IIC Bus Interface) */
+#define IIC0_ALI_IRQ 96
+#define IIC0_TACKI_IRQ 97
+#define IIC0_WAITI_IRQ 98
+#define IIC0_DTEI_IRQ 99
+#define IIC0_IPR_ADDR INTC_IPRH
+#define IIC0_IPR_POS 0
+#define IIC0_PRIORITY 3
+
+/* IIC(1) (IIC Bus Interface) */
+#define IIC1_ALI_IRQ 44
+#define IIC1_TACKI_IRQ 45
+#define IIC1_WAITI_IRQ 46
+#define IIC1_DTEI_IRQ 47
+#define IIC1_IPR_ADDR INTC_IPRI
+#define IIC1_IPR_POS 0
+#define IIC1_PRIORITY 3
+
+/* SIO0 */
+#define SIO0_IRQ 88
+#define SIO0_IPR_ADDR INTC_IPRI
+#define SIO0_IPR_POS 3
+#define SIO0_PRIORITY 3
+
+/* SDHI */
+#define SDHI_SDHII0_IRQ 100
+#define SDHI_SDHII1_IRQ 101
+#define SDHI_SDHII2_IRQ 102
+#define SDHI_SDHII3_IRQ 103
+#define SDHI_IPR_ADDR INTC_IPRK
+#define SDHI_IPR_POS 0
+#define SDHI_PRIORITY 3
+
+/* SIU (Sound Interface Unit) */
+#define SIU_IRQ 108
+#define SIU_IPR_ADDR INTC_IPRJ
+#define SIU_IPR_POS 1
+#define SIU_PRIORITY 3
+
+#define PORT_PACR 0xA4050100UL
+#define PORT_PBCR 0xA4050102UL
+#define PORT_PCCR 0xA4050104UL
+#define PORT_PDCR 0xA4050106UL
+#define PORT_PECR 0xA4050108UL
+#define PORT_PFCR 0xA405010AUL
+#define PORT_PGCR 0xA405010CUL
+#define PORT_PHCR 0xA405010EUL
+#define PORT_PJCR 0xA4050110UL
+#define PORT_PKCR 0xA4050112UL
+#define PORT_PLCR 0xA4050114UL
+#define PORT_SCPCR 0xA4050116UL
+#define PORT_PMCR 0xA4050118UL
+#define PORT_PNCR 0xA405011AUL
+#define PORT_PQCR 0xA405011CUL
+#define PORT_PRCR 0xA405011EUL
+#define PORT_PTCR 0xA405014CUL
+#define PORT_PUCR 0xA405014EUL
+#define PORT_PVCR 0xA4050150UL
+
+#define PORT_PSELA 0xA4050140UL
+#define PORT_PSELB 0xA4050142UL
+#define PORT_PSELC 0xA4050144UL
+#define PORT_PSELE 0xA4050158UL
+
+#define PORT_HIZCRA 0xA4050146UL
+#define PORT_HIZCRB 0xA4050148UL
+#define PORT_DRVCR 0xA405014AUL
+
+#define PORT_PADR 0xA4050120UL
+#define PORT_PBDR 0xA4050122UL
+#define PORT_PCDR 0xA4050124UL
+#define PORT_PDDR 0xA4050126UL
+#define PORT_PEDR 0xA4050128UL
+#define PORT_PFDR 0xA405012AUL
+#define PORT_PGDR 0xA405012CUL
+#define PORT_PHDR 0xA405012EUL
+#define PORT_PJDR 0xA4050130UL
+#define PORT_PKDR 0xA4050132UL
+#define PORT_PLDR 0xA4050134UL
+#define PORT_SCPDR 0xA4050136UL
+#define PORT_PMDR 0xA4050138UL
+#define PORT_PNDR 0xA405013AUL
+#define PORT_PQDR 0xA405013CUL
+#define PORT_PRDR 0xA405013EUL
+#define PORT_PTDR 0xA405016CUL
+#define PORT_PUDR 0xA405016EUL
+#define PORT_PVDR 0xA4050170UL
+
+#define IRQ0_IRQ 32
+#define IRQ1_IRQ 33
+#define IRQ2_IRQ 34
+#define IRQ3_IRQ 35
+#define IRQ4_IRQ 36
+#define IRQ5_IRQ 37
+#define IRQ6_IRQ 38
+#define IRQ7_IRQ 39
+
+#define INTPRI00 0xA4140010UL
+
+#define IRQ0_IPR_ADDR INTPRI00
+#define IRQ1_IPR_ADDR INTPRI00
+#define IRQ2_IPR_ADDR INTPRI00
+#define IRQ3_IPR_ADDR INTPRI00
+#define IRQ4_IPR_ADDR INTPRI00
+#define IRQ5_IPR_ADDR INTPRI00
+#define IRQ6_IPR_ADDR INTPRI00
+#define IRQ7_IPR_ADDR INTPRI00
+
+#define IRQ0_IPR_POS 7
+#define IRQ1_IPR_POS 6
+#define IRQ2_IPR_POS 5
+#define IRQ3_IPR_POS 4
+#define IRQ4_IPR_POS 3
+#define IRQ5_IPR_POS 2
+#define IRQ6_IPR_POS 1
+#define IRQ7_IPR_POS 0
+
+#define IRQ0_PRIORITY 1
+#define IRQ1_PRIORITY 1
+#define IRQ2_PRIORITY 1
+#define IRQ3_PRIORITY 1
+#define IRQ4_PRIORITY 1
+#define IRQ5_PRIORITY 1
+#define IRQ6_PRIORITY 1
+#define IRQ7_PRIORITY 1
+
+#endif /* __ASM_SH_IRQ_SH7343_H */
diff --git a/include/asm-sh/irq-sh7780.h b/include/asm-sh/irq-sh7780.h
index 7f90315cd830..895c5780e454 100644
--- a/include/asm-sh/irq-sh7780.h
+++ b/include/asm-sh/irq-sh7780.h
@@ -145,11 +145,6 @@
#define TMU_CH5_IPR_POS 1
#define TMU_CH5_PRIORITY 2
-#define RTC_IRQ 22
-#define RTC_IPR_ADDR INTC_INT2PRI1
-#define RTC_IPR_POS 0
-#define RTC_PRIORITY TIMER_PRIORITY
-
/* SCIF0 */
#define SCIF0_ERI_IRQ 40
#define SCIF0_RXI_IRQ 41
diff --git a/include/asm-sh/irq.h b/include/asm-sh/irq.h
index 611e67cd0627..28996f9c58cc 100644
--- a/include/asm-sh/irq.h
+++ b/include/asm-sh/irq.h
@@ -192,7 +192,7 @@
#if defined (CONFIG_CPU_SUBTYPE_SH7707) || defined (CONFIG_CPU_SUBTYPE_SH7708) || \
defined (CONFIG_CPU_SUBTYPE_SH7709) || defined (CONFIG_CPU_SUBTYPE_SH7750) || \
- defined (CONFIG_CPU_SUBTYPE_SH7751)
+ defined (CONFIG_CPU_SUBTYPE_SH7751) || defined (CONFIG_CPU_SUBTYPE_SH7706)
#define SCI_ERI_IRQ 23
#define SCI_RXI_IRQ 24
#define SCI_TXI_IRQ 25
@@ -207,6 +207,7 @@
#define SCIF0_IPR_POS 3
#define SCIF0_PRIORITY 3
#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
defined(CONFIG_CPU_SUBTYPE_SH7709)
#define SCIF_ERI_IRQ 56
@@ -261,9 +262,12 @@
#elif defined(CONFIG_CPU_SUBTYPE_SH7708)
# define ONCHIP_NR_IRQS 32
#elif defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7705)
# define ONCHIP_NR_IRQS 64 // Actually 61
# define PINT_NR_IRQS 16
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+# define ONCHIP_NR_IRQS 104
#elif defined(CONFIG_CPU_SUBTYPE_SH7750)
# define ONCHIP_NR_IRQS 48 // Actually 44
#elif defined(CONFIG_CPU_SUBTYPE_SH7751)
@@ -275,7 +279,8 @@
#elif defined(CONFIG_CPU_SUBTYPE_ST40STB1)
# define ONCHIP_NR_IRQS 144
#elif defined(CONFIG_CPU_SUBTYPE_SH7300) || \
- defined(CONFIG_CPU_SUBTYPE_SH73180)
+ defined(CONFIG_CPU_SUBTYPE_SH73180) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7343)
# define ONCHIP_NR_IRQS 109
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
# define ONCHIP_NR_IRQS 111
@@ -311,6 +316,8 @@
# define OFFCHIP_NR_IRQS 4
#elif defined(CONFIG_SH_R7780RP)
# define OFFCHIP_NR_IRQS 16
+#elif defined(CONFIG_SH_7343_SOLUTION_ENGINE)
+# define OFFCHIP_NR_IRQS 12
#elif defined(CONFIG_SH_UNKNOWN)
# define OFFCHIP_NR_IRQS 16 /* Must also be last */
#else
@@ -335,6 +342,11 @@ extern void make_maskreg_irq(unsigned int irq);
extern unsigned short *irq_mask_register;
/*
+ * PINT IRQs
+ */
+void init_IRQ_pint(void);
+
+/*
* Function for "on chip support modules".
*/
extern void make_ipr_irq(unsigned int irq, unsigned int addr,
@@ -471,8 +483,10 @@ extern int ipr_irq_demux(int irq);
#define INTC_ICR 0xfffffee0UL
#elif defined(CONFIG_CPU_SUBTYPE_SH7705) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7706) || \
defined(CONFIG_CPU_SUBTYPE_SH7707) || \
- defined(CONFIG_CPU_SUBTYPE_SH7709)
+ defined(CONFIG_CPU_SUBTYPE_SH7709) || \
+ defined(CONFIG_CPU_SUBTYPE_SH7710)
#define INTC_IRR0 0xa4000004UL
#define INTC_IRR1 0xa4000006UL
#define INTC_IRR2 0xa4000008UL
@@ -491,8 +505,105 @@ extern int ipr_irq_demux(int irq);
#define INTC_IPRF 0xa4080000UL
#define INTC_IPRG 0xa4080002UL
#define INTC_IPRH 0xa4080004UL
-#endif
+#elif defined(CONFIG_CPU_SUBTYPE_SH7710)
+/* Interrupt Controller Registers */
+#undef INTC_IPRA
+#undef INTC_IPRB
+#define INTC_IPRA 0xA414FEE2UL
+#define INTC_IPRB 0xA414FEE4UL
+#define INTC_IPRF 0xA4080000UL
+#define INTC_IPRG 0xA4080002UL
+#define INTC_IPRH 0xA4080004UL
+#define INTC_IPRI 0xA4080006UL
+
+#undef INTC_ICR0
+#undef INTC_ICR1
+#define INTC_ICR0 0xA414FEE0UL
+#define INTC_ICR1 0xA4140010UL
+
+#define INTC_IRR0 0xa4000004UL
+#define INTC_IRR1 0xa4000006UL
+#define INTC_IRR2 0xa4000008UL
+#define INTC_IRR3 0xa400000AUL
+#define INTC_IRR4 0xa400000CUL
+#define INTC_IRR5 0xa4080020UL
+#define INTC_IRR7 0xa4080024UL
+#define INTC_IRR8 0xa4080026UL
+
+/* Interrupt numbers */
+#define TIMER2_IRQ 18
+#define TIMER2_IPR_ADDR INTC_IPRA
+#define TIMER2_IPR_POS 1
+#define TIMER2_PRIORITY 2
+/* WDT */
+#define WDT_IRQ 27
+#define WDT_IPR_ADDR INTC_IPRB
+#define WDT_IPR_POS 3
+#define WDT_PRIORITY 2
+
+#define SCIF0_ERI_IRQ 52
+#define SCIF0_RXI_IRQ 53
+#define SCIF0_BRI_IRQ 54
+#define SCIF0_TXI_IRQ 55
+#define SCIF0_IPR_ADDR INTC_IPRE
+#define SCIF0_IPR_POS 2
+#define SCIF0_PRIORITY 3
+
+#define DMTE4_IRQ 76
+#define DMTE5_IRQ 77
+#define DMA2_IPR_ADDR INTC_IPRF
+#define DMA2_IPR_POS 2
+#define DMA2_PRIORITY 7
+
+#define IPSEC_IRQ 79
+#define IPSEC_IPR_ADDR INTC_IPRF
+#define IPSEC_IPR_POS 3
+#define IPSEC_PRIORITY 3
+
+/* EDMAC */
+#define EDMAC0_IRQ 80
+#define EDMAC0_IPR_ADDR INTC_IPRG
+#define EDMAC0_IPR_POS 3
+#define EDMAC0_PRIORITY 3
+
+#define EDMAC1_IRQ 81
+#define EDMAC1_IPR_ADDR INTC_IPRG
+#define EDMAC1_IPR_POS 2
+#define EDMAC1_PRIORITY 3
+
+#define EDMAC2_IRQ 82
+#define EDMAC2_IPR_ADDR INTC_IPRG
+#define EDMAC2_IPR_POS 1
+#define EDMAC2_PRIORITY 3
+
+/* SIOF */
+#define SIOF0_ERI_IRQ 96
+#define SIOF0_TXI_IRQ 97
+#define SIOF0_RXI_IRQ 98
+#define SIOF0_CCI_IRQ 99
+#define SIOF0_IPR_ADDR INTC_IPRH
+#define SIOF0_IPR_POS 0
+#define SIOF0_PRIORITY 7
+
+#define SIOF1_ERI_IRQ 100
+#define SIOF1_TXI_IRQ 101
+#define SIOF1_RXI_IRQ 102
+#define SIOF1_CCI_IRQ 103
+#define SIOF1_IPR_ADDR INTC_IPRI
+#define SIOF1_IPR_POS 1
+#define SIOF1_PRIORITY 7
+#endif /* CONFIG_CPU_SUBTYPE_SH7710 */
+
+#if defined(CONFIG_CPU_SUBTYPE_SH7710)
+#define PORT_PACR 0xa4050100UL
+#define PORT_PBCR 0xa4050102UL
+#define PORT_PCCR 0xa4050104UL
+#define PORT_PETCR 0xa4050106UL
+#define PORT_PADR 0xa4050120UL
+#define PORT_PBDR 0xa4050122UL
+#define PORT_PCDR 0xa4050124UL
+#else
#define PORT_PACR 0xa4000100UL
#define PORT_PBCR 0xa4000102UL
#define PORT_PCCR 0xa4000104UL
@@ -501,6 +612,7 @@ extern int ipr_irq_demux(int irq);
#define PORT_PBDR 0xa4000122UL
#define PORT_PCDR 0xa4000124UL
#define PORT_PFDR 0xa400012aUL
+#endif
#define IRQ0_IRQ 32
#define IRQ1_IRQ 33
@@ -577,7 +689,7 @@ extern int ipr_irq_demux(int irq);
#define NR_INTC2_IRQS 64
#elif defined(CONFIG_CPU_SUBTYPE_SH7780)
#define INTC2_BASE 0xffd40000
-#define INTC2_FIRST_IRQ 22
+#define INTC2_FIRST_IRQ 21
#define INTC2_INTMSK_OFFSET (0x38)
#define INTC2_INTMSKCLR_OFFSET (0x3c)
#define NR_INTC2_IRQS 60
@@ -585,15 +697,19 @@ extern int ipr_irq_demux(int irq);
#define INTC2_INTPRI_OFFSET 0x00
-void make_intc2_irq(unsigned int irq,
- unsigned int ipr_offset, unsigned int ipr_shift,
- unsigned int msk_offset, unsigned int msk_shift,
- unsigned int priority);
-void init_IRQ_intc2(void);
-void intc2_add_clear_irq(int irq, int (*fn)(int));
+struct intc2_data {
+ unsigned short irq;
+ unsigned char ipr_offset, ipr_shift;
+ unsigned char msk_offset, msk_shift;
+ unsigned char priority;
+};
+void make_intc2_irq(struct intc2_data *);
+void init_IRQ_intc2(void);
#endif
+extern int shmse_irq_demux(int irq);
+
static inline int generic_irq_demux(int irq)
{
return irq;
@@ -605,8 +721,21 @@ static inline int generic_irq_demux(int irq)
#define irq_canonicalize(irq) (irq)
#define irq_demux(irq) __irq_demux(sh_mv.mv_irq_demux(irq))
+#ifdef CONFIG_4KSTACKS
+extern void irq_ctx_init(int cpu);
+extern void irq_ctx_exit(int cpu);
+# define __ARCH_HAS_DO_SOFTIRQ
+#else
+# define irq_ctx_init(cpu) do { } while (0)
+# define irq_ctx_exit(cpu) do { } while (0)
+#endif
+
#if defined(CONFIG_CPU_SUBTYPE_SH73180)
#include <asm/irq-sh73180.h>
#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7343)
+#include <asm/irq-sh7343.h>
+#endif
+
#endif /* __ASM_SH_IRQ_H */
diff --git a/include/asm-sh/irq_regs.h b/include/asm-sh/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-sh/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-sh/kexec.h b/include/asm-sh/kexec.h
index 9dfe59f6fcb5..9d235af20cdd 100644
--- a/include/asm-sh/kexec.h
+++ b/include/asm-sh/kexec.h
@@ -23,11 +23,10 @@
/* The native architecture */
#define KEXEC_ARCH KEXEC_ARCH_SH
-#ifndef __ASSEMBLY__
+#define MAX_NOTE_BYTES 1024
-extern void machine_shutdown(void);
-extern void *crash_notes;
-
-#endif /* __ASSEMBLY__ */
+/* Provide a dummy definition to avoid build failures. */
+static inline void crash_setup_regs(struct pt_regs *newregs,
+ struct pt_regs *oldregs) { }
#endif /* _SH_KEXEC_H */
diff --git a/include/asm-sh/kgdb.h b/include/asm-sh/kgdb.h
index 1653ffb75fbe..7b26f53fe343 100644
--- a/include/asm-sh/kgdb.h
+++ b/include/asm-sh/kgdb.h
@@ -128,4 +128,19 @@ extern int setjmp(jmp_buf __jmpb);
#define KGDB_ASSERT(condition, message)
#endif
+/* Taken from sh-stub.c of GDB 4.18 */
+static const char hexchars[] = "0123456789abcdef";
+
+/* Get high hex bits */
+static inline char highhex(const int x)
+{
+ return hexchars[(x >> 4) & 0xf];
+}
+
+/* Get low hex bits */
+static inline char lowhex(const int x)
+{
+ return hexchars[x & 0xf];
+}
+
#endif
diff --git a/include/asm-sh/landisk/gio.h b/include/asm-sh/landisk/gio.h
new file mode 100644
index 000000000000..3fce4c451a46
--- /dev/null
+++ b/include/asm-sh/landisk/gio.h
@@ -0,0 +1,45 @@
+#ifndef __ASM_SH_LANDISK_GIO_H
+#define __ASM_SH_LANDISK_GIO_H
+
+#include <linux/ioctl.h>
+
+/* version */
+#define VERSION_STR "1.00"
+
+/* Driver name */
+#define GIO_DRIVER_NAME "/dev/giodrv"
+
+/* Use 'k' as magic number */
+#define GIODRV_IOC_MAGIC 'k'
+
+#define GIODRV_IOCRESET _IO(GIODRV_IOC_MAGIC, 0)
+/*
+ * S means "Set" through a ptr,
+ * T means "Tell" directly
+ * G means "Get" (to a pointed var)
+ * Q means "Query", response is on the return value
+ * X means "eXchange": G and S atomically
+ * H means "sHift": T and Q atomically
+ */
+#define GIODRV_IOCSGIODATA1 _IOW(GIODRV_IOC_MAGIC, 1, unsigned char *)
+#define GIODRV_IOCGGIODATA1 _IOR(GIODRV_IOC_MAGIC, 2, unsigned char *)
+#define GIODRV_IOCSGIODATA2 _IOW(GIODRV_IOC_MAGIC, 3, unsigned short *)
+#define GIODRV_IOCGGIODATA2 _IOR(GIODRV_IOC_MAGIC, 4, unsigned short *)
+#define GIODRV_IOCSGIODATA4 _IOW(GIODRV_IOC_MAGIC, 5, unsigned long *)
+#define GIODRV_IOCGGIODATA4 _IOR(GIODRV_IOC_MAGIC, 6, unsigned long *)
+#define GIODRV_IOCSGIOSETADDR _IOW(GIODRV_IOC_MAGIC, 7, unsigned long *)
+#define GIODRV_IOCHARDRESET _IO(GIODRV_IOC_MAGIC, 8) /* debugging tool */
+
+#define GIODRV_IOCSGIO_LED _IOW(GIODRV_IOC_MAGIC, 9, unsigned long *)
+#define GIODRV_IOCGGIO_LED _IOR(GIODRV_IOC_MAGIC, 10, unsigned long *)
+#define GIODRV_IOCSGIO_BUZZER _IOW(GIODRV_IOC_MAGIC, 11, unsigned long *)
+#define GIODRV_IOCGGIO_LANDISK _IOR(GIODRV_IOC_MAGIC, 14, unsigned long *)
+#define GIODRV_IOCGGIO_BTN _IOR(GIODRV_IOC_MAGIC, 22, unsigned long *)
+#define GIODRV_IOCSGIO_BTNPID _IOW(GIODRV_IOC_MAGIC, 23, unsigned long *)
+#define GIODRV_IOCGGIO_BTNPID _IOR(GIODRV_IOC_MAGIC, 24, unsigned long *)
+
+#define GIODRV_IOC_MAXNR 8
+#define GIO_READ 0x00000000
+#define GIO_WRITE 0x00000001
+
+#endif /* __ASM_SH_LANDISK_GIO_H */
diff --git a/include/asm-sh/landisk/ide.h b/include/asm-sh/landisk/ide.h
new file mode 100644
index 000000000000..6490e28415ed
--- /dev/null
+++ b/include/asm-sh/landisk/ide.h
@@ -0,0 +1,14 @@
+/*
+ * modifed by kogiidena
+ * 2005.03.03
+ */
+
+#ifndef __ASM_SH_LANDISK_IDE_H
+#define __ASM_SH_LANDISK_IDE_H
+
+/* Nothing to see here.. */
+#include <asm/landisk/iodata_landisk.h>
+#define IRQ_CFCARD IRQ_FATA /* CF Card IRQ */
+#define IRQ_PCMCIA IRQ_ATA /* PCMCIA IRQ */
+
+#endif /* __ASM_SH_LANDISK_IDE_H */
diff --git a/include/asm-sh/landisk/iodata_landisk.h b/include/asm-sh/landisk/iodata_landisk.h
new file mode 100644
index 000000000000..c74d3c73f377
--- /dev/null
+++ b/include/asm-sh/landisk/iodata_landisk.h
@@ -0,0 +1,79 @@
+#ifndef __ASM_SH_IODATA_LANDISK_H
+#define __ASM_SH_IODATA_LANDISK_H
+
+/*
+ * linux/include/asm-sh/landisk/iodata_landisk.h
+ *
+ * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
+ *
+ * IO-DATA LANDISK support
+ */
+
+/* Box specific addresses. */
+
+#define PA_USB 0xa4000000 /* USB Controller M66590 */
+
+#define PA_ATARST 0xb0000000 /* ATA/FATA Access Control Register */
+#define PA_LED 0xb0000001 /* LED Control Register */
+#define PA_STATUS 0xb0000002 /* Switch Status Register */
+#define PA_SHUTDOWN 0xb0000003 /* Shutdown Control Register */
+#define PA_PCIPME 0xb0000004 /* PCI PME Status Register */
+#define PA_IMASK 0xb0000005 /* Interrupt Mask Register */
+/* 2003.10.31 I-O DATA NSD NWG add. for shutdown port clear */
+#define PA_PWRINT_CLR 0xb0000006 /* Shutdown Interrupt clear Register */
+
+#define PA_LCD_CLRDSP 0x00 /* LCD Clear Display Offset */
+#define PA_LCD_RTNHOME 0x00 /* LCD Return Home Offset */
+#define PA_LCD_ENTMODE 0x00 /* LCD Entry Mode Offset */
+#define PA_LCD_DSPCTL 0x00 /* LCD Display ON/OFF Control Offset */
+#define PA_LCD_FUNC 0x00 /* LCD Function Set Offset */
+#define PA_LCD_CGRAM 0x00 /* LCD Set CGRAM Address Offset */
+#define PA_LCD_DDRAM 0x00 /* LCD Set DDRAM Address Offset */
+#define PA_LCD_RDFLAG 0x01 /* LCD Read Busy Flag Offset */
+#define PA_LCD_WTDATA 0x02 /* LCD Write Datat to RAM Offset */
+#define PA_LCD_RDDATA 0x03 /* LCD Read Data from RAM Offset */
+#define PA_PIDE_OFFSET 0x40 /* CF IDE Offset */
+#define PA_SIDE_OFFSET 0x40 /* HDD IDE Offset */
+
+#define IRQ_PCIINTA 5 /* PCI INTA IRQ */
+#define IRQ_PCIINTB 6 /* PCI INTB IRQ */
+#define IRQ_PCIINDC 7 /* PCI INTC IRQ */
+#define IRQ_PCIINTD 8 /* PCI INTD IRQ */
+#define IRQ_ATA 9 /* ATA IRQ */
+#define IRQ_FATA 10 /* FATA IRQ */
+#define IRQ_POWER 11 /* Power Switch IRQ */
+#define IRQ_BUTTON 12 /* USL-5P Button IRQ */
+#define IRQ_FAULT 13 /* USL-5P Fault IRQ */
+
+#define SHUTDOWN_BTN_MAJOR 99 /* Shutdown button device major no. */
+
+#define SHUTDOWN_LOOP_CNT 5 /* Shutdown button Detection loop */
+#define SHUTDOWN_DELAY 200 /* Shutdown button delay value(ms) */
+
+
+/* added by kogiidena */
+/*
+ * landisk_ledparam
+ *
+ * led ------10 -6543210 -6543210 -6543210
+ * |000000..|0.......|0.......|U.......|
+ * | HARD |fastblik| blink | on |
+ *
+ * led0: power U:update flag
+ * led1: error
+ * led2: usb1
+ * led3: usb2
+ * led4: usb3
+ * led5: usb4
+ * led6: usb5
+ *
+ */
+extern int landisk_ledparam; /* from setup.c */
+extern int landisk_buzzerparam; /* from setup.c */
+extern int landisk_arch; /* from setup.c */
+
+#define __IO_PREFIX landisk
+#include <asm/io_generic.h>
+
+#endif /* __ASM_SH_IODATA_LANDISK_H */
+
diff --git a/include/asm-sh/machvec.h b/include/asm-sh/machvec.h
index 550501fa4fed..70389b72ffef 100644
--- a/include/asm-sh/machvec.h
+++ b/include/asm-sh/machvec.h
@@ -8,17 +8,18 @@
*/
#ifndef _ASM_SH_MACHVEC_H
-#define _ASM_SH_MACHVEC_H 1
+#define _ASM_SH_MACHVEC_H
#include <linux/types.h>
#include <linux/time.h>
-
#include <asm/machtypes.h>
#include <asm/machvec_init.h>
struct device;
struct sh_machine_vector {
+ void (*mv_setup)(char **cmdline_p);
+ const char *mv_name;
int mv_nr_irqs;
u8 (*mv_inb)(unsigned long);
@@ -65,4 +66,6 @@ struct sh_machine_vector {
extern struct sh_machine_vector sh_mv;
+#define get_system_type() sh_mv.mv_name
+
#endif /* _ASM_SH_MACHVEC_H */
diff --git a/include/asm-sh/mc146818rtc.h b/include/asm-sh/mc146818rtc.h
index 1707cfb2915d..0aee96a97330 100644
--- a/include/asm-sh/mc146818rtc.h
+++ b/include/asm-sh/mc146818rtc.h
@@ -4,173 +4,4 @@
#ifndef _ASM_MC146818RTC_H
#define _ASM_MC146818RTC_H
-#ifdef CONFIG_SH_MPC1211
-#undef _ASM_MC146818RTC_H
-#undef RTC_IRQ
-#include <asm/mpc1211/mc146818rtc.h>
-#else
-
-#include <asm/rtc.h>
-
-#define RTC_ALWAYS_BCD 1
-
-/* FIXME:RTC Interrupt feature is not implemented yet. */
-#undef RTC_IRQ
-#define RTC_IRQ 0
-
-#if defined(CONFIG_CPU_SH3)
-#define RTC_PORT(n) (R64CNT+(n)*2)
-#define CMOS_READ(addr) __CMOS_READ(addr,b)
-#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,b)
-
-#elif defined(CONFIG_SH_SECUREEDGE5410)
-#include <asm/snapgear/io.h>
-
-#define RTC_PORT(n) SECUREEDGE_IOPORT_ADDR
-#define CMOS_READ(addr) secureedge5410_cmos_read(addr)
-#define CMOS_WRITE(val,addr) secureedge5410_cmos_write(val,addr)
-extern unsigned char secureedge5410_cmos_read(int addr);
-extern void secureedge5410_cmos_write(unsigned char val, int addr);
-
-#elif defined(CONFIG_CPU_SH4)
-#define RTC_PORT(n) (R64CNT+(n)*4)
-#define CMOS_READ(addr) __CMOS_READ(addr,w)
-#define CMOS_WRITE(val,addr) __CMOS_WRITE(val,addr,w)
-#endif
-
-#define __CMOS_READ(addr, s) ({ \
- unsigned char val=0, rcr1, rcr2, r64cnt, retry; \
- switch(addr) { \
- case RTC_SECONDS: \
- val = ctrl_inb(RSECCNT); \
- break; \
- case RTC_SECONDS_ALARM: \
- val = ctrl_inb(RSECAR); \
- break; \
- case RTC_MINUTES: \
- val = ctrl_inb(RMINCNT); \
- break; \
- case RTC_MINUTES_ALARM: \
- val = ctrl_inb(RMINAR); \
- break; \
- case RTC_HOURS: \
- val = ctrl_inb(RHRCNT); \
- break; \
- case RTC_HOURS_ALARM: \
- val = ctrl_inb(RHRAR); \
- break; \
- case RTC_DAY_OF_WEEK: \
- val = ctrl_inb(RWKCNT); \
- break; \
- case RTC_DAY_OF_MONTH: \
- val = ctrl_inb(RDAYCNT); \
- break; \
- case RTC_MONTH: \
- val = ctrl_inb(RMONCNT); \
- break; \
- case RTC_YEAR: \
- val = ctrl_in##s(RYRCNT); \
- break; \
- case RTC_REG_A: /* RTC_FREQ_SELECT */ \
- rcr2 = ctrl_inb(RCR2); \
- val = (rcr2 & RCR2_PESMASK) >> 4; \
- rcr1 = ctrl_inb(RCR1); \
- rcr1 = (rcr1 & (RCR1_CIE | RCR1_AIE)) | RCR1_AF;\
- retry = 0; \
- do { \
- ctrl_outb(rcr1, RCR1); /* clear CF */ \
- r64cnt = ctrl_inb(R64CNT); \
- } while((ctrl_inb(RCR1) & RCR1_CF) && retry++ < 1000);\
- r64cnt ^= RTC_BIT_INVERTED; \
- if(r64cnt == 0x7f || r64cnt == 0) \
- val |= RTC_UIP; \
- break; \
- case RTC_REG_B: /* RTC_CONTROL */ \
- rcr1 = ctrl_inb(RCR1); \
- rcr2 = ctrl_inb(RCR2); \
- if(rcr1 & RCR1_CIE) val |= RTC_UIE; \
- if(rcr1 & RCR1_AIE) val |= RTC_AIE; \
- if(rcr2 & RCR2_PESMASK) val |= RTC_PIE; \
- if(!(rcr2 & RCR2_START))val |= RTC_SET; \
- val |= RTC_24H; \
- break; \
- case RTC_REG_C: /* RTC_INTR_FLAGS */ \
- rcr1 = ctrl_inb(RCR1); \
- rcr1 &= ~(RCR1_CF | RCR1_AF); \
- ctrl_outb(rcr1, RCR1); \
- rcr2 = ctrl_inb(RCR2); \
- rcr2 &= ~RCR2_PEF; \
- ctrl_outb(rcr2, RCR2); \
- break; \
- case RTC_REG_D: /* RTC_VALID */ \
- /* Always valid ... */ \
- val = RTC_VRT; \
- break; \
- default: \
- break; \
- } \
- val; \
-})
-
-#define __CMOS_WRITE(val, addr, s) ({ \
- unsigned char rcr1,rcr2; \
- switch(addr) { \
- case RTC_SECONDS: \
- ctrl_outb(val, RSECCNT); \
- break; \
- case RTC_SECONDS_ALARM: \
- ctrl_outb(val, RSECAR); \
- break; \
- case RTC_MINUTES: \
- ctrl_outb(val, RMINCNT); \
- break; \
- case RTC_MINUTES_ALARM: \
- ctrl_outb(val, RMINAR); \
- break; \
- case RTC_HOURS: \
- ctrl_outb(val, RHRCNT); \
- break; \
- case RTC_HOURS_ALARM: \
- ctrl_outb(val, RHRAR); \
- break; \
- case RTC_DAY_OF_WEEK: \
- ctrl_outb(val, RWKCNT); \
- break; \
- case RTC_DAY_OF_MONTH: \
- ctrl_outb(val, RDAYCNT); \
- break; \
- case RTC_MONTH: \
- ctrl_outb(val, RMONCNT); \
- break; \
- case RTC_YEAR: \
- ctrl_out##s((ctrl_in##s(RYRCNT) & 0xff00) | (val & 0xff), RYRCNT);\
- break; \
- case RTC_REG_A: /* RTC_FREQ_SELECT */ \
- rcr2 = ctrl_inb(RCR2); \
- if((val & RTC_DIV_CTL) == RTC_DIV_RESET2) \
- rcr2 |= RCR2_RESET; \
- ctrl_outb(rcr2, RCR2); \
- break; \
- case RTC_REG_B: /* RTC_CONTROL */ \
- rcr1 = (ctrl_inb(RCR1) & 0x99) | RCR1_AF; \
- if(val & RTC_AIE) rcr1 |= RCR1_AIE; \
- else rcr1 &= ~RCR1_AIE; \
- if(val & RTC_UIE) rcr1 |= RCR1_CIE; \
- else rcr1 &= ~RCR1_CIE; \
- ctrl_outb(rcr1, RCR1); \
- rcr2 = ctrl_inb(RCR2); \
- if(val & RTC_SET) rcr2 &= ~RCR2_START; \
- else rcr2 |= RCR2_START; \
- ctrl_outb(rcr2, RCR2); \
- break; \
- case RTC_REG_C: /* RTC_INTR_FLAGS */ \
- break; \
- case RTC_REG_D: /* RTC_VALID */ \
- break; \
- default: \
- break; \
- } \
-})
-
-#endif /* CONFIG_SH_MPC1211 */
#endif /* _ASM_MC146818RTC_H */
diff --git a/include/asm-sh/mmu.h b/include/asm-sh/mmu.h
index 72f07be6117f..cf47df79bb94 100644
--- a/include/asm-sh/mmu.h
+++ b/include/asm-sh/mmu.h
@@ -3,27 +3,76 @@
#if !defined(CONFIG_MMU)
-struct mm_rblock_struct {
- int size;
- int refcount;
- void *kblock;
-};
-
-struct mm_tblock_struct {
- struct mm_rblock_struct *rblock;
- struct mm_tblock_struct *next;
-};
-
typedef struct {
- struct mm_tblock_struct tblock;
+ struct vm_list_struct *vmlist;
unsigned long end_brk;
} mm_context_t;
#else
/* Default "unsigned long" context */
-typedef unsigned long mm_context_t;
+typedef unsigned long mm_context_id_t;
+
+typedef struct {
+ mm_context_id_t id;
+ void *vdso;
+} mm_context_t;
#endif /* CONFIG_MMU */
-#endif /* __MMH_H */
+
+/*
+ * Privileged Space Mapping Buffer (PMB) definitions
+ */
+#define PMB_PASCR 0xff000070
+#define PMB_IRMCR 0xff000078
+
+#define PMB_ADDR 0xf6100000
+#define PMB_DATA 0xf7100000
+#define PMB_ENTRY_MAX 16
+#define PMB_E_MASK 0x0000000f
+#define PMB_E_SHIFT 8
+
+#define PMB_SZ_16M 0x00000000
+#define PMB_SZ_64M 0x00000010
+#define PMB_SZ_128M 0x00000080
+#define PMB_SZ_512M 0x00000090
+#define PMB_SZ_MASK PMB_SZ_512M
+#define PMB_C 0x00000008
+#define PMB_WT 0x00000001
+#define PMB_UB 0x00000200
+#define PMB_V 0x00000100
+
+#define PMB_NO_ENTRY (-1)
+
+struct pmb_entry;
+
+struct pmb_entry {
+ unsigned long vpn;
+ unsigned long ppn;
+ unsigned long flags;
+
+ /*
+ * 0 .. NR_PMB_ENTRIES for specific entry selection, or
+ * PMB_NO_ENTRY to search for a free one
+ */
+ int entry;
+
+ struct pmb_entry *next;
+ /* Adjacent entry link for contiguous multi-entry mappings */
+ struct pmb_entry *link;
+};
+
+/* arch/sh/mm/pmb.c */
+int __set_pmb_entry(unsigned long vpn, unsigned long ppn,
+ unsigned long flags, int *entry);
+int set_pmb_entry(struct pmb_entry *pmbe);
+void clear_pmb_entry(struct pmb_entry *pmbe);
+struct pmb_entry *pmb_alloc(unsigned long vpn, unsigned long ppn,
+ unsigned long flags);
+void pmb_free(struct pmb_entry *pmbe);
+long pmb_remap(unsigned long virt, unsigned long phys,
+ unsigned long size, unsigned long flags);
+void pmb_unmap(unsigned long addr);
+
+#endif /* __MMU_H */
diff --git a/include/asm-sh/mmu_context.h b/include/asm-sh/mmu_context.h
index 6760d064bd02..c7088efe579a 100644
--- a/include/asm-sh/mmu_context.h
+++ b/include/asm-sh/mmu_context.h
@@ -49,7 +49,7 @@ get_mmu_context(struct mm_struct *mm)
unsigned long mc = mmu_context_cache;
/* Check if we have old version of context. */
- if (((mm->context ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
+ if (((mm->context.id ^ mc) & MMU_CONTEXT_VERSION_MASK) == 0)
/* It's up to date, do nothing */
return;
@@ -68,7 +68,7 @@ get_mmu_context(struct mm_struct *mm)
if (!mc)
mmu_context_cache = mc = MMU_CONTEXT_FIRST_VERSION;
}
- mm->context = mc;
+ mm->context.id = mc;
}
/*
@@ -78,7 +78,7 @@ get_mmu_context(struct mm_struct *mm)
static __inline__ int init_new_context(struct task_struct *tsk,
struct mm_struct *mm)
{
- mm->context = NO_CONTEXT;
+ mm->context.id = NO_CONTEXT;
return 0;
}
@@ -123,7 +123,7 @@ static __inline__ unsigned long get_asid(void)
static __inline__ void activate_context(struct mm_struct *mm)
{
get_mmu_context(mm);
- set_asid(mm->context & MMU_CONTEXT_ASID_MASK);
+ set_asid(mm->context.id & MMU_CONTEXT_ASID_MASK);
}
/* MMU_TTB can be used for optimizing the fault handling.
@@ -174,9 +174,7 @@ static inline void enable_mmu(void)
{
/* Enable MMU */
ctrl_outl(MMU_CONTROL_INIT, MMUCR);
-
- /* The manual suggests doing some nops after turning on the MMU */
- __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop\n\t");
+ ctrl_barrier();
if (mmu_context_cache == NO_CONTEXT)
mmu_context_cache = MMU_CONTEXT_FIRST_VERSION;
@@ -191,7 +189,8 @@ static inline void disable_mmu(void)
cr = ctrl_inl(MMUCR);
cr &= ~MMU_CONTROL_INIT;
ctrl_outl(cr, MMUCR);
- __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop\n\t");
+
+ ctrl_barrier();
}
#else
/*
diff --git a/include/asm-sh/mpc1211/io.h b/include/asm-sh/mpc1211/io.h
index eba8a0b5fd7b..6298370bec2d 100644
--- a/include/asm-sh/mpc1211/io.h
+++ b/include/asm-sh/mpc1211/io.h
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/io_mpc1211.h
+ * include/asm-sh/mpc1211/io.h
*
* Copyright 2001 Saito.K & Jeanne
*
diff --git a/include/asm-sh/mpc1211/keyboard.h b/include/asm-sh/mpc1211/keyboard.h
index 71ef4cf4242d..9020feee7b4c 100644
--- a/include/asm-sh/mpc1211/keyboard.h
+++ b/include/asm-sh/mpc1211/keyboard.h
@@ -24,7 +24,6 @@ extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
extern int pckbd_pm_resume(struct pm_dev *, pm_request_t, void *);
extern pm_callback pm_kbd_request_override;
-extern unsigned char pckbd_sysrq_xlate[128];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
@@ -32,9 +31,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
-#define kbd_sysrq_xlate pckbd_sysrq_xlate
-
-#define SYSRQ_KEY 0x54
/* resource allocation */
#define kbd_request_region()
diff --git a/include/asm-sh/overdrive/fpga.h b/include/asm-sh/overdrive/fpga.h
deleted file mode 100644
index 1cd87992c124..000000000000
--- a/include/asm-sh/overdrive/fpga.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- */
-
-#ifndef __FPGA_OD_H__
-#define __FPGA_OD_H__
-
-/* This routine will program up the fpga which interfaces to the galileo */
-int init_overdrive_fpga(void);
-
-#endif
diff --git a/include/asm-sh/overdrive/gt64111.h b/include/asm-sh/overdrive/gt64111.h
deleted file mode 100644
index 01d58bc13a44..000000000000
--- a/include/asm-sh/overdrive/gt64111.h
+++ /dev/null
@@ -1,109 +0,0 @@
-#ifndef _GT64111_H_
-#define _GT64111_H_
-
-#define MASTER_INTERFACE 0x0
-#define RAS10_LO_DEC_ADR 0x8
-#define RAS10_HI_DEC_ADR 0x10
-#define RAS32_LO_DEC_ADR 0x18
-#define RAS32_HI_DEC_ADR 0x20
-#define CS20_LO_DEC_ADR 0x28
-#define CS20_HI_DEC_ADR 0x30
-#define CS3_LO_DEC_ADR 0x38
-#define CS3_HI_DEC_ADR 0x40
-#define PCI_IO_LO_DEC_ADR 0x48
-#define PCI_IO_HI_DEC_ADR 0x50
-#define PCI_MEM0_LO_DEC_ADR 0x58
-#define PCI_MEM0_HI_DEC_ADR 0x60
-#define INTERNAL_SPACE_DEC 0x68
-#define BUS_ERR_ADR_LO_CPU 0x70
-#define READONLY0 0x78
-#define PCI_MEM1_LO_DEC_ADR 0x80
-#define PCI_MEM1_HI_DEC_ADR 0x88
-#define RAS0_LO_DEC_ADR 0x400
-#define RAS0_HI_DEC_ADR 0x404
-#define RAS1_LO_DEC_ADR 0x408
-#define RAS1_HI_DEC_ADR 0x40c
-#define RAS2_LO_DEC_ADR 0x410
-#define RAS2_HI_DEC_ADR 0x414
-#define RAS3_LO_DEC_ADR 0x418
-#define RAS3_HI_DEC_ADR 0x41c
-#define DEV_CS0_LO_DEC_ADR 0x420
-#define DEV_CS0_HI_DEC_ADR 0x424
-#define DEV_CS1_LO_DEC_ADR 0x428
-#define DEV_CS1_HI_DEC_ADR 0x42c
-#define DEV_CS2_LO_DEC_ADR 0x430
-#define DEV_CS2_HI_DEC_ADR 0x434
-#define DEV_CS3_LO_DEC_ADR 0x438
-#define DEV_CS3_HI_DEC_ADR 0x43c
-#define DEV_BOOTCS_LO_DEC_ADR 0x440
-#define DEV_BOOTCS_HI_DEC_ADR 0x444
-#define DEV_ADR_DEC_ERR 0x470
-#define DRAM_CFG 0x448
-#define DRAM_BANK0_PARMS 0x44c
-#define DRAM_BANK1_PARMS 0x450
-#define DRAM_BANK2_PARMS 0x454
-#define DRAM_BANK3_PARMS 0x458
-#define DEV_BANK0_PARMS 0x45c
-#define DEV_BANK1_PARMS 0x460
-#define DEV_BANK2_PARMS 0x464
-#define DEV_BANK3_PARMS 0x468
-#define DEV_BOOT_BANK_PARMS 0x46c
-#define CH0_DMA_BYTECOUNT 0x800
-#define CH1_DMA_BYTECOUNT 0x804
-#define CH2_DMA_BYTECOUNT 0x808
-#define CH3_DMA_BYTECOUNT 0x80c
-#define CH0_DMA_SRC_ADR 0x810
-#define CH1_DMA_SRC_ADR 0x814
-#define CH2_DMA_SRC_ADR 0x818
-#define CH3_DMA_SRC_ADR 0x81c
-#define CH0_DMA_DST_ADR 0x820
-#define CH1_DMA_DST_ADR 0x824
-#define CH2_DMA_DST_ADR 0x828
-#define CH3_DMA_DST_ADR 0x82c
-#define CH0_NEXT_REC_PTR 0x830
-#define CH1_NEXT_REC_PTR 0x834
-#define CH2_NEXT_REC_PTR 0x838
-#define CH3_NEXT_REC_PTR 0x83c
-#define CH0_CTRL 0x840
-#define CH1_CTRL 0x844
-#define CH2_CTRL 0x848
-#define CH3_CTRL 0x84c
-#define DMA_ARBITER 0x860
-#define TIMER0 0x850
-#define TIMER1 0x854
-#define TIMER2 0x858
-#define TIMER3 0x85c
-#define TIMER_CTRL 0x864
-#define PCI_CMD 0xc00
-#define PCI_TIMEOUT 0xc04
-#define PCI_RAS10_BANK_SIZE 0xc08
-#define PCI_RAS32_BANK_SIZE 0xc0c
-#define PCI_CS20_BANK_SIZE 0xc10
-#define PCI_CS3_BANK_SIZE 0xc14
-#define PCI_SERRMASK 0xc28
-#define PCI_INTACK 0xc34
-#define PCI_BAR_EN 0xc3c
-#define PCI_CFG_ADR 0xcf8
-#define PCI_CFG_DATA 0xcfc
-#define PCI_INTCAUSE 0xc18
-#define PCI_MAST_MASK 0xc1c
-#define PCI_PCIMASK 0xc24
-#define BAR_ENABLE_ADR 0xc3c
-
-/* These are config registers, accessible via PCI space */
-#define PCI_CONFIG_RAS10_BASE_ADR 0x010
-#define PCI_CONFIG_RAS32_BASE_ADR 0x014
-#define PCI_CONFIG_CS20_BASE_ADR 0x018
-#define PCI_CONFIG_CS3_BASE_ADR 0x01c
-#define PCI_CONFIG_INT_REG_MM_ADR 0x020
-#define PCI_CONFIG_INT_REG_IO_ADR 0x024
-#define PCI_CONFIG_BOARD_VENDOR 0x02c
-#define PCI_CONFIG_ROM_ADR 0x030
-#define PCI_CONFIG_INT_PIN_LINE 0x03c
-
-
-
-
-
-#endif
-
diff --git a/include/asm-sh/overdrive/io.h b/include/asm-sh/overdrive/io.h
deleted file mode 100644
index 0dba700e9643..000000000000
--- a/include/asm-sh/overdrive/io.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * include/asm-sh/io_od.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an STMicroelectronics Overdrive
- */
-
-#ifndef _ASM_SH_IO_OD_H
-#define _ASM_SH_IO_OD_H
-
-extern unsigned char od_inb(unsigned long port);
-extern unsigned short od_inw(unsigned long port);
-extern unsigned int od_inl(unsigned long port);
-
-extern void od_outb(unsigned char value, unsigned long port);
-extern void od_outw(unsigned short value, unsigned long port);
-extern void od_outl(unsigned int value, unsigned long port);
-
-extern unsigned char od_inb_p(unsigned long port);
-extern unsigned short od_inw_p(unsigned long port);
-extern unsigned int od_inl_p(unsigned long port);
-extern void od_outb_p(unsigned char value, unsigned long port);
-extern void od_outw_p(unsigned short value, unsigned long port);
-extern void od_outl_p(unsigned int value, unsigned long port);
-
-extern void od_insb(unsigned long port, void *addr, unsigned long count);
-extern void od_insw(unsigned long port, void *addr, unsigned long count);
-extern void od_insl(unsigned long port, void *addr, unsigned long count);
-extern void od_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void od_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned long od_isa_port2addr(unsigned long offset);
-
-#endif /* _ASM_SH_IO_OD_H */
diff --git a/include/asm-sh/overdrive/overdrive.h b/include/asm-sh/overdrive/overdrive.h
deleted file mode 100644
index fc746c244f83..000000000000
--- a/include/asm-sh/overdrive/overdrive.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- */
-
-
-#ifndef __OVERDRIVE_H__
-#define __OVERDRIVE_H__
-
-#define OVERDRIVE_INT_CT 0xa3a00000
-#define OVERDRIVE_INT_DT 0xa3b00000
-
-#define OVERDRIVE_CTRL 0xa3000000
-
-/* Shoving all these bits into the same register is not a good idea.
- * As soon as I get a spare moment, I'll change the FPGA and put each
- * bit in a separate register
- */
-
-#define VALID_CTRL_BITS 0x1f
-
-#define ENABLE_RS232_MASK 0x1e
-#define DISABLE_RS232_BIT 0x01
-
-#define ENABLE_NMI_MASK 0x1d
-#define DISABLE_NMI_BIT 0x02
-
-#define RESET_PCI_MASK 0x1b
-#define ENABLE_PCI_BIT 0x04
-
-#define ENABLE_LED_MASK 0x17
-#define DISABLE_LED_BIT 0x08
-
-#define RESET_FPGA_MASK 0x0f
-#define ENABLE_FPGA_BIT 0x10
-
-
-#define FPGA_DCLK_ADDRESS 0xA3C00000
-
-#define FPGA_DATA 0x01 /* W */
-#define FPGA_CONFDONE 0x02 /* R */
-#define FPGA_NOT_STATUS 0x04 /* R */
-#define FPGA_INITDONE 0x08 /* R */
-
-#define FPGA_TIMEOUT 100000
-
-
-/* Interrupts for the overdrive. Note that these numbers have
- * nothing to do with the actual IRQ numbers they appear on,
- * this is all programmable. This is simply the position in the
- * INT_CT register.
- */
-
-#define OVERDRIVE_PCI_INTA 0
-#define OVERDRIVE_PCI_INTB 1
-#define OVERDRIVE_PCI_INTC 2
-#define OVERDRIVE_PCI_INTD 3
-#define OVERDRIVE_GALILEO_INT 4
-#define OVERDRIVE_GALILEO_LOCAL_INT 5
-#define OVERDRIVE_AUDIO_INT 6
-#define OVERDRIVE_KEYBOARD_INT 7
-
-/* Which Linux IRQ should we assign to each interrupt source? */
-#define OVERDRIVE_PCI_IRQ1 2
-#ifdef CONFIG_HACKED_NE2K
-#define OVERDRIVE_PCI_IRQ2 7
-#else
-#define OVERDRIVE_PCI_IRQ2 2
-#undef OVERDRIVE_PCI_INTB
-#define OVERDRIVE_PCI_INTB OVERDRIVE_PCI_INTA
-
-#endif
-
-/* Put the ESS solo audio chip on IRQ 4 */
-#define OVERDRIVE_ESS_IRQ 4
-
-/* Where the memory behind the PCI bus appears */
-#define PCI_DRAM_BASE 0xb7000000
-#define PCI_DRAM_SIZE (16*1024*1024)
-#define PCI_DRAM_FINISH (PCI_DRAM_BASE+PCI_DRAM_SIZE-1)
-
-/* Where the IO region appears in the memory */
-#define PCI_GTIO_BASE 0xb8000000
-
-#endif
diff --git a/include/asm-sh/page.h b/include/asm-sh/page.h
index 6f7eb8a3aba5..ca8b26d90475 100644
--- a/include/asm-sh/page.h
+++ b/include/asm-sh/page.h
@@ -16,7 +16,13 @@
/* PAGE_SHIFT determines the page size */
#define PAGE_SHIFT 12
+
+#ifdef __ASSEMBLY__
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#else
#define PAGE_SIZE (1UL << PAGE_SHIFT)
+#endif
+
#define PAGE_MASK (~(PAGE_SIZE-1))
#define PTE_MASK PAGE_MASK
@@ -30,7 +36,6 @@
#define HPAGE_SIZE (1UL << HPAGE_SHIFT)
#define HPAGE_MASK (~(HPAGE_SIZE-1))
#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT-PAGE_SHIFT)
-#define ARCH_HAS_SETCLEAR_HUGE_PTE
#endif
#ifdef __KERNEL__
@@ -39,10 +44,18 @@
extern void (*clear_page)(void *to);
extern void (*copy_page)(void *to, void *from);
+extern unsigned long shm_align_mask;
+
+#ifdef CONFIG_MMU
extern void clear_page_slow(void *to);
extern void copy_page_slow(void *to, void *from);
+#else
+extern void clear_page_nommu(void *to);
+extern void copy_page_nommu(void *to, void *from);
+#endif
-#if defined(CONFIG_SH7705_CACHE_32KB) && defined(CONFIG_MMU)
+#if defined(CONFIG_MMU) && (defined(CONFIG_CPU_SH4) || \
+ defined(CONFIG_SH7705_CACHE_32KB))
struct page;
extern void clear_user_page(void *to, unsigned long address, struct page *pg);
extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
@@ -51,29 +64,20 @@ extern void __copy_user_page(void *to, void *from, void *orig_to);
#elif defined(CONFIG_CPU_SH2) || defined(CONFIG_CPU_SH3) || !defined(CONFIG_MMU)
#define clear_user_page(page, vaddr, pg) clear_page(page)
#define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
-#elif defined(CONFIG_CPU_SH4)
-struct page;
-extern void clear_user_page(void *to, unsigned long address, struct page *pg);
-extern void copy_user_page(void *to, void *from, unsigned long address, struct page *pg);
-extern void __clear_user_page(void *to, void *orig_to);
-extern void __copy_user_page(void *to, void *from, void *orig_to);
#endif
/*
* These are used to make use of C type-checking..
*/
typedef struct { unsigned long pte; } pte_t;
-typedef struct { unsigned long pmd; } pmd_t;
typedef struct { unsigned long pgd; } pgd_t;
typedef struct { unsigned long pgprot; } pgprot_t;
#define pte_val(x) ((x).pte)
-#define pmd_val(x) ((x).pmd)
#define pgd_val(x) ((x).pgd)
#define pgprot_val(x) ((x).pgprot)
#define __pte(x) ((pte_t) { (x) } )
-#define __pmd(x) ((pmd_t) { (x) } )
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
@@ -93,7 +97,7 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#define __MEMORY_START CONFIG_MEMORY_START
#define __MEMORY_SIZE CONFIG_MEMORY_SIZE
-#define PAGE_OFFSET (0x80000000UL)
+#define PAGE_OFFSET CONFIG_PAGE_OFFSET
#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET))
@@ -115,5 +119,10 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#include <asm-generic/memory_model.h>
#include <asm-generic/page.h>
+/* vDSO support */
+#ifdef CONFIG_VSYSCALL
+#define __HAVE_ARCH_GATE_AREA
+#endif
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_PAGE_H */
diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
index 0a523c85b11c..6ccc948fe216 100644
--- a/include/asm-sh/pci.h
+++ b/include/asm-sh/pci.h
@@ -32,6 +32,34 @@ extern struct pci_channel board_pci_channels[];
#define PCIBIOS_MIN_IO board_pci_channels->io_resource->start
#define PCIBIOS_MIN_MEM board_pci_channels->mem_resource->start
+/*
+ * I/O routine helpers
+ */
+#ifdef CONFIG_CPU_SUBTYPE_SH7780
+#define PCI_IO_AREA 0xFE400000
+#define PCI_IO_SIZE 0x00400000
+#else
+#define PCI_IO_AREA 0xFE240000
+#define PCI_IO_SIZE 0X00040000
+#endif
+
+#define PCI_MEM_SIZE 0x01000000
+
+#define SH4_PCIIOBR_MASK 0xFFFC0000
+#define pci_ioaddr(addr) (PCI_IO_AREA + (addr & ~SH4_PCIIOBR_MASK))
+
+#if defined(CONFIG_PCI)
+#define is_pci_ioaddr(port) \
+ (((port) >= PCIBIOS_MIN_IO) && \
+ ((port) < (PCIBIOS_MIN_IO + PCI_IO_SIZE)))
+#define is_pci_memaddr(port) \
+ (((port) >= PCIBIOS_MIN_MEM) && \
+ ((port) < (PCIBIOS_MIN_MEM + PCI_MEM_SIZE)))
+#else
+#define is_pci_ioaddr(port) (0)
+#define is_pci_memaddr(port) (0)
+#endif
+
struct pci_dev;
extern void pcibios_set_master(struct pci_dev *dev);
@@ -87,15 +115,6 @@ static inline void pcibios_penalize_isa_irq(int irq, int active)
*/
#define pci_dac_dma_supported(pci_dev, mask) (0)
-/* These macros should be used after a pci_map_sg call has been done
- * to get bus addresses of each of the SG entries and their lengths.
- * You should only work with the number of sg entries pci_map_sg
- * returns, or alternatively stop on the first sg_dma_len(sg) which
- * is 0.
- */
-#define sg_dma_address(sg) (virt_to_bus((sg)->dma_address))
-#define sg_dma_len(sg) ((sg)->length)
-
#ifdef CONFIG_PCI
static inline void pci_dma_burst_advice(struct pci_dev *pdev,
enum pci_dma_burst_strategy *strat,
@@ -107,11 +126,12 @@ static inline void pci_dma_burst_advice(struct pci_dev *pdev,
#endif
/* Board-specific fixup routines. */
-extern void pcibios_fixup(void);
-extern void pcibios_fixup_irqs(void);
+void pcibios_fixup(void);
+int pcibios_init_platform(void);
+int pcibios_map_platform_irq(struct pci_dev *dev, u8 slot, u8 pin);
#ifdef CONFIG_PCI_AUTO
-extern int pciauto_assign_resources(int busno, struct pci_channel *hose);
+int pciauto_assign_resources(int busno, struct pci_channel *hose);
#endif
static inline void pcibios_add_platform_entries(struct pci_dev *dev)
diff --git a/include/asm-sh/pgalloc.h b/include/asm-sh/pgalloc.h
index f4f233f7a4f5..e841465ab4d2 100644
--- a/include/asm-sh/pgalloc.h
+++ b/include/asm-sh/pgalloc.h
@@ -1,15 +1,6 @@
#ifndef __ASM_SH_PGALLOC_H
#define __ASM_SH_PGALLOC_H
-#include <linux/threads.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-
-#define pgd_quicklist ((unsigned long *)0)
-#define pmd_quicklist ((unsigned long *)0)
-#define pte_quicklist ((unsigned long *)0)
-#define pgtable_cache_size 0L
-
#define pmd_populate_kernel(mm, pmd, pte) \
set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte)))
@@ -24,38 +15,24 @@ static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
*/
static inline pgd_t *pgd_alloc(struct mm_struct *mm)
{
- unsigned int pgd_size = (USER_PTRS_PER_PGD * sizeof(pgd_t));
- pgd_t *pgd = (pgd_t *)kmalloc(pgd_size, GFP_KERNEL);
-
- if (pgd)
- memset(pgd, 0, pgd_size);
-
- return pgd;
+ return (pgd_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
}
static inline void pgd_free(pgd_t *pgd)
{
- kfree(pgd);
+ free_page((unsigned long)pgd);
}
static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
unsigned long address)
{
- pte_t *pte;
-
- pte = (pte_t *) __get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
-
- return pte;
+ return (pte_t *)__get_free_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
}
static inline struct page *pte_alloc_one(struct mm_struct *mm,
unsigned long address)
{
- struct page *pte;
-
- pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO, 0);
-
- return pte;
+ return alloc_page(GFP_KERNEL | __GFP_REPEAT | __GFP_ZERO);
}
static inline void pte_free_kernel(pte_t *pte)
@@ -75,14 +52,8 @@ static inline void pte_free(struct page *pte)
* inside the pgd, so has no extra memory associated with it.
*/
-#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); })
#define pmd_free(x) do { } while (0)
#define __pmd_free_tlb(tlb,x) do { } while (0)
-#define pgd_populate(mm, pmd, pte) BUG()
#define check_pgt_cache() do { } while (0)
-#ifdef CONFIG_CPU_SH4
-#define PG_mapped PG_arch_1
-#endif
-
#endif /* __ASM_SH_PGALLOC_H */
diff --git a/include/asm-sh/pgtable.h b/include/asm-sh/pgtable.h
index 40d41a78041e..2c8682ad1012 100644
--- a/include/asm-sh/pgtable.h
+++ b/include/asm-sh/pgtable.h
@@ -1,42 +1,42 @@
-#ifndef __ASM_SH_PGTABLE_H
-#define __ASM_SH_PGTABLE_H
-
-#include <asm-generic/4level-fixup.h>
-
/*
+ * This file contains the functions and defines necessary to modify and
+ * use the SuperH page table tree.
+ *
* Copyright (C) 1999 Niibe Yutaka
- * Copyright (C) 2002, 2003, 2004 Paul Mundt
+ * Copyright (C) 2002 - 2005 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.
*/
+#ifndef __ASM_SH_PGTABLE_H
+#define __ASM_SH_PGTABLE_H
-#include <asm/pgtable-2level.h>
+#include <asm-generic/pgtable-nopmd.h>
+#include <asm/page.h>
+
+#define PTRS_PER_PGD 1024
-/*
- * This file contains the functions and defines necessary to modify and use
- * the SuperH page table tree.
- */
#ifndef __ASSEMBLY__
-#include <asm/processor.h>
#include <asm/addrspace.h>
#include <asm/fixmap.h>
-#include <linux/threads.h>
extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
extern void paging_init(void);
/*
- * Basically we have the same two-level (which is the logical three level
- * Linux page table layout folded) page tables as the i386.
- */
-
-/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
*/
-extern unsigned long empty_zero_page[1024];
+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
#endif /* !__ASSEMBLY__ */
+/* traditional two-level paging structure */
+#define PGDIR_SHIFT 22
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PTE 1024
#define PMD_SIZE (1UL << PMD_SHIFT)
#define PMD_MASK (~(PMD_SIZE-1))
#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
@@ -47,7 +47,6 @@ extern unsigned long empty_zero_page[1024];
#define PTE_PHYS_MASK 0x1ffff000
-#ifndef __ASSEMBLY__
/*
* First 1MB map is used by fixed purpose.
* Currently only 4-enty (16kB) is used (see arch/sh/mm/cache.c)
@@ -55,20 +54,41 @@ extern unsigned long empty_zero_page[1024];
#define VMALLOC_START (P3SEG+0x00100000)
#define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE)
-#define _PAGE_WT 0x001 /* WT-bit on SH-4, 0 on SH-3 */
-#define _PAGE_HW_SHARED 0x002 /* SH-bit : page is shared among processes */
-#define _PAGE_DIRTY 0x004 /* D-bit : page changed */
-#define _PAGE_CACHABLE 0x008 /* C-bit : cachable */
-#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */
-#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */
-#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed */
-#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */
-#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */
-#define _PAGE_PROTNONE 0x200 /* software: if not present */
-#define _PAGE_ACCESSED 0x400 /* software: page referenced */
-#define _PAGE_U0_SHARED 0x800 /* software: page is shared in user space */
-
-#define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */
+/*
+ * Linux PTEL encoding.
+ *
+ * Hardware and software bit definitions for the PTEL value:
+ *
+ * - Bits 0 and 7 are reserved on SH-3 (_PAGE_WT and _PAGE_SZ1 on SH-4).
+ *
+ * - Bit 1 is the SH-bit, but is unused on SH-3 due to an MMU bug (the
+ * hardware PTEL value can't have the SH-bit set when MMUCR.IX is set,
+ * which is the default in cpu-sh3/mmu_context.h:MMU_CONTROL_INIT).
+ *
+ * In order to keep this relatively clean, do not use these for defining
+ * SH-3 specific flags until all of the other unused bits have been
+ * exhausted.
+ *
+ * - Bit 9 is reserved by everyone and used by _PAGE_PROTNONE.
+ *
+ * - Bits 10 and 11 are low bits of the PPN that are reserved on >= 4K pages.
+ * Bit 10 is used for _PAGE_ACCESSED, bit 11 remains unused.
+ *
+ * - Bits 31, 30, and 29 remain unused by everyone and can be used for future
+ * software flags, although care must be taken to update _PAGE_CLEAR_FLAGS.
+ */
+#define _PAGE_WT 0x001 /* WT-bit on SH-4, 0 on SH-3 */
+#define _PAGE_HW_SHARED 0x002 /* SH-bit : shared among processes */
+#define _PAGE_DIRTY 0x004 /* D-bit : page changed */
+#define _PAGE_CACHABLE 0x008 /* C-bit : cachable */
+#define _PAGE_SZ0 0x010 /* SZ0-bit : Size of page */
+#define _PAGE_RW 0x020 /* PR0-bit : write access allowed */
+#define _PAGE_USER 0x040 /* PR1-bit : user space access allowed */
+#define _PAGE_SZ1 0x080 /* SZ1-bit : Size of page (on SH-4) */
+#define _PAGE_PRESENT 0x100 /* V-bit : page is valid */
+#define _PAGE_PROTNONE 0x200 /* software: if not present */
+#define _PAGE_ACCESSED 0x400 /* software: page referenced */
+#define _PAGE_FILE _PAGE_WT /* software: pagecache or swap? */
/* software: moves to PTEA.TC (Timing Control) */
#define _PAGE_PCC_AREA5 0x00000000 /* use BSC registers for area5 */
@@ -83,23 +103,17 @@ extern unsigned long empty_zero_page[1024];
#define _PAGE_PCC_ATR8 0x60000000 /* Attribute Memory space, 8 bit bus */
#define _PAGE_PCC_ATR16 0x60000001 /* Attribute Memory space, 6 bit bus */
-
-/* Mask which drop software flags
- * We also drop WT bit since it is used for _PAGE_FILE
- * bit in this implementation.
- */
-#define _PAGE_CLEAR_FLAGS (_PAGE_WT | _PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_U0_SHARED)
-
-#if defined(CONFIG_CPU_SH3)
-/*
- * MMU on SH-3 has bug on SH-bit: We can't use it if MMUCR.IX=1.
- * Work around: Just drop SH-bit.
- */
-#define _PAGE_FLAGS_HARDWARE_MASK (0x1fffffff & ~(_PAGE_CLEAR_FLAGS | _PAGE_HW_SHARED))
+/* Mask which drops unused bits from the PTEL value */
+#ifdef CONFIG_CPU_SH3
+#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED| \
+ _PAGE_FILE | _PAGE_SZ1 | \
+ _PAGE_HW_SHARED)
#else
-#define _PAGE_FLAGS_HARDWARE_MASK (0x1fffffff & ~(_PAGE_CLEAR_FLAGS))
+#define _PAGE_CLEAR_FLAGS (_PAGE_PROTNONE | _PAGE_ACCESSED | _PAGE_FILE)
#endif
+#define _PAGE_FLAGS_HARDWARE_MASK (0x1fffffff & ~(_PAGE_CLEAR_FLAGS))
+
/* Hardware flags: SZ0=1 (4k-byte) */
#define _PAGE_FLAGS_HARD _PAGE_SZ0
@@ -109,15 +123,15 @@ extern unsigned long empty_zero_page[1024];
#define _PAGE_SZHUGE (_PAGE_SZ0 | _PAGE_SZ1)
#endif
-#define _PAGE_SHARED _PAGE_U0_SHARED
-
#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_SHARED)
+#define _PAGE_CHG_MASK (PTE_MASK | _PAGE_ACCESSED | _PAGE_CACHABLE | _PAGE_DIRTY)
+
+#ifndef __ASSEMBLY__
#ifdef CONFIG_MMU
#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD)
-#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_SHARED | _PAGE_FLAGS_HARD)
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_CACHABLE |_PAGE_ACCESSED | _PAGE_FLAGS_HARD)
#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_CACHABLE | _PAGE_ACCESSED | _PAGE_FLAGS_HARD)
#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_CACHABLE | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_HW_SHARED | _PAGE_FLAGS_HARD)
@@ -137,12 +151,13 @@ extern unsigned long empty_zero_page[1024];
#define PAGE_KERNEL_PCC __pgprot(0)
#endif
+#endif /* __ASSEMBLY__ */
+
/*
* As i386 and MIPS, SuperH can't do page protection for execute, and
* considers that the same as a read. Also, write permissions imply
- * read permissions. This is the closest we can get..
+ * read permissions. This is the closest we can get..
*/
-
#define __P000 PAGE_NONE
#define __P001 PAGE_READONLY
#define __P010 PAGE_COPY
@@ -161,6 +176,26 @@ extern unsigned long empty_zero_page[1024];
#define __S110 PAGE_SHARED
#define __S111 PAGE_SHARED
+#ifndef __ASSEMBLY__
+
+/*
+ * Certain architectures need to do special things when PTEs
+ * within a page table are directly modified. Thus, the following
+ * hook is made available.
+ */
+#define set_pte(pteptr, pteval) (*(pteptr) = pteval)
+#define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
+
+/*
+ * (pmds are folded into pgds so this doesn't get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval)
+
+#define pte_pfn(x) ((unsigned long)(((x).pte >> PAGE_SHIFT)))
+#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define pfn_pmd(pfn, prot) __pmd(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+
#define pte_none(x) (!pte_val(x))
#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE))
#define pte_clear(mm,addr,xp) do { set_pte_at(mm, addr, xp, __pte(0)); } while (0)
@@ -171,7 +206,7 @@ extern unsigned long empty_zero_page[1024];
#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
-#define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK)
+#define pte_page(x) phys_to_page(pte_val(x)&PTE_PHYS_MASK)
/*
* The following only work if pte_present() is true.
@@ -248,6 +283,11 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
#define pte_unmap(pte) do { } while (0)
#define pte_unmap_nested(pte) do { } while (0)
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
struct vm_area_struct;
extern void update_mmu_cache(struct vm_area_struct * vma,
unsigned long address, pte_t pte);
@@ -272,8 +312,6 @@ extern void update_mmu_cache(struct vm_area_struct * vma,
typedef pte_t *pte_addr_t;
-#endif /* !__ASSEMBLY__ */
-
#define kern_addr_valid(addr) (1)
#define io_remap_pfn_range(vma, vaddr, pfn, size, prot) \
@@ -301,5 +339,5 @@ extern pte_t ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t
#include <asm-generic/pgtable.h>
+#endif /* !__ASSEMBLY__ */
#endif /* __ASM_SH_PAGE_H */
-
diff --git a/include/asm-sh/pm.h b/include/asm-sh/pm.h
new file mode 100644
index 000000000000..56fdbd6b1c94
--- /dev/null
+++ b/include/asm-sh/pm.h
@@ -0,0 +1,17 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright 2006 (c) Andriy Skulysh <askulysh@gmail.com>
+ *
+ */
+#ifndef __ASM_SH_PM_H
+#define __ASM_SH_PM_H
+
+extern u8 wakeup_start;
+extern u8 wakeup_end;
+
+void pm_enter(void);
+
+#endif
diff --git a/include/asm-sh/processor.h b/include/asm-sh/processor.h
index eeb0f48bb99e..474773853cd1 100644
--- a/include/asm-sh/processor.h
+++ b/include/asm-sh/processor.h
@@ -14,6 +14,7 @@
#include <asm/types.h>
#include <asm/cache.h>
#include <asm/ptrace.h>
+#include <asm/cpu-features.h>
/*
* Default implementation of macro that returns current
@@ -38,27 +39,30 @@ enum cpu_type {
CPU_SH7604,
/* SH-3 types */
- CPU_SH7705, CPU_SH7707, CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
- CPU_SH7709, CPU_SH7709A, CPU_SH7729, CPU_SH7300,
+ CPU_SH7705, CPU_SH7706, CPU_SH7707,
+ CPU_SH7708, CPU_SH7708S, CPU_SH7708R,
+ CPU_SH7709, CPU_SH7709A, CPU_SH7710,
+ CPU_SH7729, CPU_SH7300,
/* SH-4 types */
CPU_SH7750, CPU_SH7750S, CPU_SH7750R, CPU_SH7751, CPU_SH7751R,
CPU_SH7760, CPU_ST40RA, CPU_ST40GX1, CPU_SH4_202, CPU_SH4_501,
- CPU_SH73180, CPU_SH7770, CPU_SH7780, CPU_SH7781,
+ CPU_SH73180, CPU_SH7343, CPU_SH7770, CPU_SH7780, CPU_SH7781,
/* Unknown subtype */
CPU_SH_NONE
};
struct sh_cpuinfo {
- enum cpu_type type;
+ unsigned int type;
unsigned long loops_per_jiffy;
- struct cache_info icache;
- struct cache_info dcache;
+ struct cache_info icache; /* Primary I-cache */
+ struct cache_info dcache; /* Primary D-cache */
+ struct cache_info scache; /* Secondary cache */
unsigned long flags;
-};
+} __attribute__ ((aligned(SMP_CACHE_BYTES)));
extern struct sh_cpuinfo boot_cpu_data;
@@ -125,17 +129,6 @@ union sh_fpu_union {
struct sh_fpu_soft_struct soft;
};
-/*
- * Processor flags
- */
-
-#define CPU_HAS_FPU 0x0001 /* Hardware FPU support */
-#define CPU_HAS_P2_FLUSH_BUG 0x0002 /* Need to flush the cache in P2 area */
-#define CPU_HAS_MMU_PAGE_ASSOC 0x0004 /* SH3: TLB way selection bit support */
-#define CPU_HAS_DSP 0x0008 /* SH-DSP: DSP support */
-#define CPU_HAS_PERF_COUNTER 0x0010 /* Hardware performance counters */
-#define CPU_HAS_PTEA 0x0020 /* PTEA register */
-
struct thread_struct {
unsigned long sp;
unsigned long pc;
@@ -149,6 +142,10 @@ struct thread_struct {
union sh_fpu_union fpu;
};
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
+
/* Count of active tasks with UBC settings */
extern int ubc_usercnt;
@@ -266,5 +263,24 @@ extern unsigned long get_wchan(struct task_struct *p);
#define cpu_sleep() __asm__ __volatile__ ("sleep" : : : "memory")
#define cpu_relax() barrier()
+#if defined(CONFIG_CPU_SH2A) || defined(CONFIG_CPU_SH3) || \
+ defined(CONFIG_CPU_SH4)
+#define PREFETCH_STRIDE L1_CACHE_BYTES
+#define ARCH_HAS_PREFETCH
+#define ARCH_HAS_PREFETCHW
+static inline void prefetch(void *x)
+{
+ __asm__ __volatile__ ("pref @%0\n\t" : : "r" (x) : "memory");
+}
+
+#define prefetchw(x) prefetch(x)
+#endif
+
+#ifdef CONFIG_VSYSCALL
+extern int vsyscall_init(void);
+#else
+#define vsyscall_init() do { } while (0)
+#endif
+
#endif /* __KERNEL__ */
#endif /* __ASM_SH_PROCESSOR_H */
diff --git a/include/asm-sh/r7780rp/ide.h b/include/asm-sh/r7780rp/ide.h
new file mode 100644
index 000000000000..a1ed78e0f617
--- /dev/null
+++ b/include/asm-sh/r7780rp/ide.h
@@ -0,0 +1,8 @@
+#ifndef __ASM_SH_R7780RP_IDE_H
+#define __ASM_SH_R7780RP_IDE_H
+
+/* Nothing to see here.. */
+#include <asm/mach/r7780rp.h>
+
+#endif /* __ASM_SH_R7780RP_IDE_H */
+
diff --git a/include/asm-sh/r7780rp/r7780rp.h b/include/asm-sh/r7780rp/r7780rp.h
new file mode 100644
index 000000000000..f95d9dba31a2
--- /dev/null
+++ b/include/asm-sh/r7780rp/r7780rp.h
@@ -0,0 +1,177 @@
+#ifndef __ASM_SH_RENESAS_R7780RP_H
+#define __ASM_SH_RENESAS_R7780RP_H
+
+/*
+ * linux/include/asm-sh/r7780rp.h
+ *
+ * Copyright (C) 2000 Atom Create Engineering Co., Ltd.
+ *
+ * Renesas Solutions Highlander R7780RP support
+ */
+
+/* Box specific addresses. */
+#if defined(CONFIG_SH_R7780MP)
+#define PA_BCR 0xa4000000 /* FPGA */
+#define PA_IRLMSK (PA_BCR+0x0000) /* Interrupt Mask control */
+#define PA_IRLMON (PA_BCR+0x0002) /* Interrupt Status control */
+#define PA_IRLPRI1 (PA_BCR+0x0004) /* Interrupt Priorty 1 */
+#define PA_IRLPRI2 (PA_BCR+0x0006) /* Interrupt Priorty 2 */
+#define PA_IRLPRI3 (PA_BCR+0x0008) /* Interrupt Priorty 3 */
+#define PA_IRLPRI4 (PA_BCR+0x000a) /* Interrupt Priorty 4 */
+#define PA_RSTCTL (PA_BCR+0x000c) /* Reset Control */
+#define PA_PCIBD (PA_BCR+0x000e) /* PCI Board detect control */
+#define PA_PCICD (PA_BCR+0x0010) /* PCI Conector detect control */
+#define PA_EXTGIO (PA_BCR+0x0016) /* Extension GPIO Control */
+#define PA_IVDRMON (PA_BCR+0x0018) /* iVDR Moniter control */
+#define PA_IVDRCTL (PA_BCR+0x001a) /* iVDR control */
+#define PA_OBLED (PA_BCR+0x001c) /* On Board LED control */
+#define PA_OBSW (PA_BCR+0x001e) /* On Board Switch control */
+#define PA_AUDIOSEL (PA_BCR+0x0020) /* Sound Interface Select control */
+#define PA_EXTPLR (PA_BCR+0x001e) /* Extention Pin Polarity control */
+#define PA_TPCTL (PA_BCR+0x0100) /* Touch Panel Access control */
+#define PA_TPDCKCTL (PA_BCR+0x0102) /* Touch Panel Access data control */
+#define PA_TPCTLCLR (PA_BCR+0x0104) /* Touch Panel Access control */
+#define PA_TPXPOS (PA_BCR+0x0106) /* Touch Panel X position control */
+#define PA_TPYPOS (PA_BCR+0x0108) /* Touch Panel Y position control */
+#define PA_DBSW (PA_BCR+0x0200) /* Debug Board Switch control */
+#define PA_CFCTL (PA_BCR+0x0300) /* CF Timing control */
+#define PA_CFPOW (PA_BCR+0x0302) /* CF Power control */
+#define PA_CFCDINTCLR (PA_BCR+0x0304) /* CF Insert Interrupt clear */
+#define PA_SCSMR0 (PA_BCR+0x0400) /* SCIF0 Serial mode control */
+#define PA_SCBRR0 (PA_BCR+0x0404) /* SCIF0 Bit rate control */
+#define PA_SCSCR0 (PA_BCR+0x0408) /* SCIF0 Serial control */
+#define PA_SCFTDR0 (PA_BCR+0x040c) /* SCIF0 Send FIFO control */
+#define PA_SCFSR0 (PA_BCR+0x0410) /* SCIF0 Serial status control */
+#define PA_SCFRDR0 (PA_BCR+0x0414) /* SCIF0 Receive FIFO control */
+#define PA_SCFCR0 (PA_BCR+0x0418) /* SCIF0 FIFO control */
+#define PA_SCTFDR0 (PA_BCR+0x041c) /* SCIF0 Send FIFO data control */
+#define PA_SCRFDR0 (PA_BCR+0x0420) /* SCIF0 Receive FIFO data control */
+#define PA_SCSPTR0 (PA_BCR+0x0424) /* SCIF0 Serial Port control */
+#define PA_SCLSR0 (PA_BCR+0x0428) /* SCIF0 Line Status control */
+#define PA_SCRER0 (PA_BCR+0x042c) /* SCIF0 Serial Error control */
+#define PA_SCSMR1 (PA_BCR+0x0500) /* SCIF1 Serial mode control */
+#define PA_SCBRR1 (PA_BCR+0x0504) /* SCIF1 Bit rate control */
+#define PA_SCSCR1 (PA_BCR+0x0508) /* SCIF1 Serial control */
+#define PA_SCFTDR1 (PA_BCR+0x050c) /* SCIF1 Send FIFO control */
+#define PA_SCFSR1 (PA_BCR+0x0510) /* SCIF1 Serial status control */
+#define PA_SCFRDR1 (PA_BCR+0x0514) /* SCIF1 Receive FIFO control */
+#define PA_SCFCR1 (PA_BCR+0x0518) /* SCIF1 FIFO control */
+#define PA_SCTFDR1 (PA_BCR+0x051c) /* SCIF1 Send FIFO data control */
+#define PA_SCRFDR1 (PA_BCR+0x0520) /* SCIF1 Receive FIFO data control */
+#define PA_SCSPTR1 (PA_BCR+0x0524) /* SCIF1 Serial Port control */
+#define PA_SCLSR1 (PA_BCR+0x0528) /* SCIF1 Line Status control */
+#define PA_SCRER1 (PA_BCR+0x052c) /* SCIF1 Serial Error control */
+#define PA_ICCR (PA_BCR+0x0600) /* Serial control */
+#define PA_SAR (PA_BCR+0x0602) /* Serial Slave control */
+#define PA_MDR (PA_BCR+0x0604) /* Serial Mode control */
+#define PA_ADR1 (PA_BCR+0x0606) /* Serial Address1 control */
+#define PA_DAR1 (PA_BCR+0x0646) /* Serial Data1 control */
+#define PA_VERREG (PA_BCR+0x0700) /* FPGA Version Register */
+#define PA_POFF (PA_BCR+0x0800) /* System Power Off control */
+#define PA_PMR (PA_BCR+0x0900) /* */
+
+#define PA_AX88796L 0xa4100400 /* AX88796L Area */
+#define PA_SC1602BSLB 0xa6000000 /* SC1602BSLB Area */
+#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
+#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
+#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
+#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
+
+#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
+
+#define IRQ_PCISLOT1 65 /* PCI Slot #1 IRQ */
+#define IRQ_PCISLOT2 66 /* PCI Slot #2 IRQ */
+#define IRQ_PCISLOT3 67 /* PCI Slot #3 IRQ */
+#define IRQ_PCISLOT4 68 /* PCI Slot #4 IRQ */
+#define IRQ_CFCARD 1 /* CF Card IRQ */
+// #define IRQ_CFINST 0 /* CF Card Insert IRQ */
+#define IRQ_TP 2 /* Touch Panel IRQ */
+#define IRQ_SCI1 3 /* SCI1 IRQ */
+#define IRQ_SCI0 4 /* SCI0 IRQ */
+#define IRQ_2SERIAL 5 /* Serial IRQ */
+#define IRQ_RTC 6 /* RTC A / B IRQ */
+#define IRQ_EXTENTION6 7 /* EXT6n IRQ */
+#define IRQ_EXTENTION5 8 /* EXT5n IRQ */
+#define IRQ_EXTENTION4 9 /* EXT4n IRQ */
+#define IRQ_EXTENTION2 10 /* EXT2n IRQ */
+#define IRQ_EXTENTION1 11 /* EXT1n IRQ */
+#define IRQ_ONETH 13 /* On board Ethernet IRQ */
+#define IRQ_PSW 14 /* Push Switch IRQ */
+
+#else /* R7780RP */
+
+#define PA_BCR 0xa5000000 /* FPGA */
+#define PA_IRLMSK (PA_BCR+0x0000) /* Interrupt Mask control */
+#define PA_IRLMON (PA_BCR+0x0002) /* Interrupt Status control */
+#define PA_SDPOW (PA_BCR+0x0004) /* SD Power control */
+#define PA_RSTCTL (PA_BCR+0x0006) /* Device Reset control */
+#define PA_PCIBD (PA_BCR+0x0008) /* PCI Board detect control */
+#define PA_PCICD (PA_BCR+0x000a) /* PCI Conector detect control */
+#define PA_ZIGIO1 (PA_BCR+0x000c) /* Zigbee IO control 1 */
+#define PA_ZIGIO2 (PA_BCR+0x000e) /* Zigbee IO control 2 */
+#define PA_ZIGIO3 (PA_BCR+0x0010) /* Zigbee IO control 3 */
+#define PA_ZIGIO4 (PA_BCR+0x0012) /* Zigbee IO control 4 */
+#define PA_IVDRMON (PA_BCR+0x0014) /* iVDR Moniter control */
+#define PA_IVDRCTL (PA_BCR+0x0016) /* iVDR control */
+#define PA_OBLED (PA_BCR+0x0018) /* On Board LED control */
+#define PA_OBSW (PA_BCR+0x001a) /* On Board Switch control */
+#define PA_AUDIOSEL (PA_BCR+0x001c) /* Sound Interface Select control */
+#define PA_EXTPLR (PA_BCR+0x001e) /* Extention Pin Polarity control */
+#define PA_TPCTL (PA_BCR+0x0100) /* Touch Panel Access control */
+#define PA_TPDCKCTL (PA_BCR+0x0102) /* Touch Panel Access data control */
+#define PA_TPCTLCLR (PA_BCR+0x0104) /* Touch Panel Access control */
+#define PA_TPXPOS (PA_BCR+0x0106) /* Touch Panel X position control */
+#define PA_TPYPOS (PA_BCR+0x0108) /* Touch Panel Y position control */
+#define PA_DBDET (PA_BCR+0x0200) /* Debug Board detect control */
+#define PA_DBDISPCTL (PA_BCR+0x0202) /* Debug Board Dot timing control */
+#define PA_DBSW (PA_BCR+0x0204) /* Debug Board Switch control */
+#define PA_CFCTL (PA_BCR+0x0300) /* CF Timing control */
+#define PA_CFPOW (PA_BCR+0x0302) /* CF Power control */
+#define PA_CFCDINTCLR (PA_BCR+0x0304) /* CF Insert Interrupt clear */
+#define PA_SCSMR (PA_BCR+0x0400) /* SCIF Serial mode control */
+#define PA_SCBRR (PA_BCR+0x0402) /* SCIF Bit rate control */
+#define PA_SCSCR (PA_BCR+0x0404) /* SCIF Serial control */
+#define PA_SCFDTR (PA_BCR+0x0406) /* SCIF Send FIFO control */
+#define PA_SCFSR (PA_BCR+0x0408) /* SCIF Serial status control */
+#define PA_SCFRDR (PA_BCR+0x040a) /* SCIF Receive FIFO control */
+#define PA_SCFCR (PA_BCR+0x040c) /* SCIF FIFO control */
+#define PA_SCFDR (PA_BCR+0x040e) /* SCIF FIFO data control */
+#define PA_SCLSR (PA_BCR+0x0412) /* SCIF Line Status control */
+#define PA_ICCR (PA_BCR+0x0500) /* Serial control */
+#define PA_SAR (PA_BCR+0x0502) /* Serial Slave control */
+#define PA_MDR (PA_BCR+0x0504) /* Serial Mode control */
+#define PA_ADR1 (PA_BCR+0x0506) /* Serial Address1 control */
+#define PA_DAR1 (PA_BCR+0x0546) /* Serial Data1 control */
+#define PA_VERREG (PA_BCR+0x0600) /* FPGA Version Register */
+
+#define PA_AX88796L 0xa5800400 /* AX88796L Area */
+#define PA_SC1602BSLB 0xa6000000 /* SC1602BSLB Area */
+#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
+#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
+#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
+#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
+
+#define IRLCNTR1 (PA_BCR + 0) /* Interrupt Control Register1 */
+
+#define IRQ_PCISLOT1 0 /* PCI Slot #1 IRQ */
+#define IRQ_PCISLOT2 1 /* PCI Slot #2 IRQ */
+#define IRQ_PCISLOT3 2 /* PCI Slot #3 IRQ */
+#define IRQ_PCISLOT4 3 /* PCI Slot #4 IRQ */
+#define IRQ_CFCARD 4 /* CF Card IRQ */
+#define IRQ_CFINST 5 /* CF Card Insert IRQ */
+#define IRQ_M66596 6 /* M66596 IRQ */
+#define IRQ_SDCARD 7 /* SD Card IRQ */
+#define IRQ_TUCHPANEL 8 /* Touch Panel IRQ */
+#define IRQ_SCI 9 /* SCI IRQ */
+#define IRQ_2SERIAL 10 /* Serial IRQ */
+#define IRQ_EXTENTION 11 /* EXTn IRQ */
+#define IRQ_ONETH 12 /* On board Ethernet IRQ */
+#define IRQ_PSW 13 /* Push Switch IRQ */
+#define IRQ_ZIGBEE 14 /* Ziggbee IO IRQ */
+
+#endif /* CONFIG_SH_R7780MP */
+
+#define __IO_PREFIX r7780rp
+#include <asm/io_generic.h>
+
+#endif /* __ASM_SH_RENESAS_R7780RP */
diff --git a/include/asm-sh/rtc.h b/include/asm-sh/rtc.h
index cea9cdf9b925..91aacc96151b 100644
--- a/include/asm-sh/rtc.h
+++ b/include/asm-sh/rtc.h
@@ -1,29 +1,8 @@
#ifndef _ASM_RTC_H
#define _ASM_RTC_H
-#ifdef __KERNEL__
-#include <asm/machvec.h>
-#include <asm/cpu/rtc.h>
-
-extern void sh_rtc_gettimeofday(struct timespec *ts);
-extern int sh_rtc_settimeofday(const time_t secs);
extern void (*board_time_init)(void);
-extern void (*rtc_get_time)(struct timespec *);
-extern int (*rtc_set_time)(const time_t);
-
-/* RCR1 Bits */
-#define RCR1_CF 0x80 /* Carry Flag */
-#define RCR1_CIE 0x10 /* Carry Interrupt Enable */
-#define RCR1_AIE 0x08 /* Alarm Interrupt Enable */
-#define RCR1_AF 0x01 /* Alarm Flag */
-
-/* RCR2 Bits */
-#define RCR2_PEF 0x80 /* PEriodic interrupt Flag */
-#define RCR2_PESMASK 0x70 /* Periodic interrupt Set */
-#define RCR2_RTCEN 0x08 /* ENable RTC */
-#define RCR2_ADJ 0x04 /* ADJustment (30-second) */
-#define RCR2_RESET 0x02 /* Reset bit */
-#define RCR2_START 0x01 /* Start bit */
+extern void (*rtc_sh_get_time)(struct timespec *);
+extern int (*rtc_sh_set_time)(const time_t);
-#endif /* __KERNEL__ */
#endif /* _ASM_RTC_H */
diff --git a/include/asm-sh/rts7751r2d/io.h b/include/asm-sh/rts7751r2d/io.h
deleted file mode 100644
index 241094020567..000000000000
--- a/include/asm-sh/rts7751r2d/io.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * include/asm-sh/io_rts7751r2d.h
- *
- * Modified version of io_se.h for the rts7751r2d-specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an Renesas Technology sales RTS7751R2D
- */
-
-#ifndef _ASM_SH_IO_RTS7751R2D_H
-#define _ASM_SH_IO_RTS7751R2D_H
-
-extern unsigned char rts7751r2d_inb(unsigned long port);
-extern unsigned short rts7751r2d_inw(unsigned long port);
-extern unsigned int rts7751r2d_inl(unsigned long port);
-
-extern void rts7751r2d_outb(unsigned char value, unsigned long port);
-extern void rts7751r2d_outw(unsigned short value, unsigned long port);
-extern void rts7751r2d_outl(unsigned int value, unsigned long port);
-
-extern unsigned char rts7751r2d_inb_p(unsigned long port);
-extern void rts7751r2d_outb_p(unsigned char value, unsigned long port);
-
-extern void rts7751r2d_insb(unsigned long port, void *addr, unsigned long count);
-extern void rts7751r2d_insw(unsigned long port, void *addr, unsigned long count);
-extern void rts7751r2d_insl(unsigned long port, void *addr, unsigned long count);
-extern void rts7751r2d_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void rts7751r2d_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void rts7751r2d_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern void *rts7751r2d_ioremap(unsigned long offset, unsigned long size);
-
-extern unsigned long rts7751r2d_isa_port2addr(unsigned long offset);
-
-#endif /* _ASM_SH_IO_RTS7751R2D_H */
diff --git a/include/asm-sh/rts7751r2d/rts7751r2d.h b/include/asm-sh/rts7751r2d/rts7751r2d.h
index 4e09ba597e9a..796b8fcb81a8 100644
--- a/include/asm-sh/rts7751r2d/rts7751r2d.h
+++ b/include/asm-sh/rts7751r2d/rts7751r2d.h
@@ -41,8 +41,6 @@
#define PA_AX88796L 0xaa000400 /* AX88796L Area */
#define PA_VOYAGER 0xab000000 /* VOYAGER GX Area */
-#define PA_AREA5_IO 0xb4000000 /* Area 5 IO Memory */
-#define PA_AREA6_IO 0xb8000000 /* Area 6 IO Memory */
#define PA_IDE_OFFSET 0x1f0 /* CF IDE Offset */
#define AX88796L_IO_BASE 0x1000 /* AX88796L IO Base Address */
@@ -70,4 +68,7 @@
#define IRQ_PCISLOT2 10 /* PCI Slot #2 IRQ */
#define IRQ_EXTENTION 11 /* EXTn IRQ */
+#define __IO_PREFIX rts7751r2d
+#include <asm/io_generic.h>
+
#endif /* __ASM_SH_RENESAS_RTS7751R2D */
diff --git a/include/asm-sh/scatterlist.h b/include/asm-sh/scatterlist.h
index 7b91df140022..d19e7cd3b023 100644
--- a/include/asm-sh/scatterlist.h
+++ b/include/asm-sh/scatterlist.h
@@ -10,4 +10,13 @@ struct scatterlist {
#define ISA_DMA_THRESHOLD (0x1fffffff)
+/* These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg) ((sg)->dma_address)
+#define sg_dma_len(sg) ((sg)->length)
+
#endif /* !(__ASM_SH_SCATTERLIST_H) */
diff --git a/include/asm-sh/sci.h b/include/asm-sh/sci.h
new file mode 100644
index 000000000000..52e73660c129
--- /dev/null
+++ b/include/asm-sh/sci.h
@@ -0,0 +1,34 @@
+#ifndef __ASM_SH_SCI_H
+#define __ASM_SH_SCI_H
+
+#include <linux/serial_core.h>
+
+/*
+ * Generic header for SuperH SCI(F)
+ *
+ * Do not place SH-specific parts in here, sh64 and h8300 depend on this too.
+ */
+
+/* Offsets into the sci_port->irqs array */
+enum {
+ SCIx_ERI_IRQ,
+ SCIx_RXI_IRQ,
+ SCIx_TXI_IRQ,
+ SCIx_BRI_IRQ,
+ SCIx_NR_IRQS,
+};
+
+/*
+ * Platform device specific platform_data struct
+ */
+struct plat_sci_port {
+ void __iomem *membase; /* io cookie */
+ unsigned long mapbase; /* resource base */
+ unsigned int irqs[SCIx_NR_IRQS]; /* ERI, RXI, TXI, BRI */
+ unsigned int type; /* SCI / SCIF / IRDA */
+ upf_t flags; /* UPF_* flags */
+};
+
+int early_sci_setup(struct uart_port *port);
+
+#endif /* __ASM_SH_SCI_H */
diff --git a/include/asm-sh/se/se.h b/include/asm-sh/se.h
index 791c5da0388a..a1832154a3aa 100644
--- a/include/asm-sh/se/se.h
+++ b/include/asm-sh/se.h
@@ -74,4 +74,7 @@
#define IRQ_STNIC 10
#endif
+#define __IO_PREFIX se
+#include <asm/io_generic.h>
+
#endif /* __ASM_SH_HITACHI_SE_H */
diff --git a/include/asm-sh/se/io.h b/include/asm-sh/se/io.h
deleted file mode 100644
index 9eeb86cd6cef..000000000000
--- a/include/asm-sh/se/io.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * include/asm-sh/io_se.h
- *
- * Copyright 2000 Stuart Menefy (stuart.menefy@st.com)
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an Hitachi SolutionEngine
- */
-
-#ifndef _ASM_SH_IO_SE_H
-#define _ASM_SH_IO_SE_H
-
-extern unsigned char se_inb(unsigned long port);
-extern unsigned short se_inw(unsigned long port);
-extern unsigned int se_inl(unsigned long port);
-
-extern void se_outb(unsigned char value, unsigned long port);
-extern void se_outw(unsigned short value, unsigned long port);
-extern void se_outl(unsigned int value, unsigned long port);
-
-extern unsigned char se_inb_p(unsigned long port);
-extern void se_outb_p(unsigned char value, unsigned long port);
-
-extern void se_insb(unsigned long port, void *addr, unsigned long count);
-extern void se_insw(unsigned long port, void *addr, unsigned long count);
-extern void se_insl(unsigned long port, void *addr, unsigned long count);
-extern void se_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void se_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void se_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned long se_isa_port2addr(unsigned long offset);
-
-#endif /* _ASM_SH_IO_SE_H */
diff --git a/include/asm-sh/se7300/se7300.h b/include/asm-sh/se7300.h
index 3ec1ded86c97..4e24edccb30d 100644
--- a/include/asm-sh/se7300/se7300.h
+++ b/include/asm-sh/se7300.h
@@ -58,4 +58,7 @@
#define PA_LCD1 0xb8000000
#define PA_LCD2 0xb8800000
+#define __IO_PREFIX sh7300se
+#include <asm/io_generic.h>
+
#endif /* __ASM_SH_HITACHI_SE7300_H */
diff --git a/include/asm-sh/se7300/io.h b/include/asm-sh/se7300/io.h
deleted file mode 100644
index c6af85529714..000000000000
--- a/include/asm-sh/se7300/io.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * include/asm-sh/se7300/io.h
- *
- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
- * IO functions for SH-Mobile(SH7300) SolutionEngine
- */
-
-#ifndef _ASM_SH_IO_7300SE_H
-#define _ASM_SH_IO_7300SE_H
-
-extern unsigned char sh7300se_inb(unsigned long port);
-extern unsigned short sh7300se_inw(unsigned long port);
-extern unsigned int sh7300se_inl(unsigned long port);
-
-extern void sh7300se_outb(unsigned char value, unsigned long port);
-extern void sh7300se_outw(unsigned short value, unsigned long port);
-extern void sh7300se_outl(unsigned int value, unsigned long port);
-
-extern unsigned char sh7300se_inb_p(unsigned long port);
-extern void sh7300se_outb_p(unsigned char value, unsigned long port);
-
-extern void sh7300se_insb(unsigned long port, void *addr, unsigned long count);
-extern void sh7300se_insw(unsigned long port, void *addr, unsigned long count);
-extern void sh7300se_insl(unsigned long port, void *addr, unsigned long count);
-extern void sh7300se_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void sh7300se_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void sh7300se_outsl(unsigned long port, const void *addr, unsigned long count);
-
-#endif /* _ASM_SH_IO_7300SE_H */
diff --git a/include/asm-sh/se73180/se73180.h b/include/asm-sh/se73180.h
index f5b93e39e768..3a4acb3e38a1 100644
--- a/include/asm-sh/se73180/se73180.h
+++ b/include/asm-sh/se73180.h
@@ -59,4 +59,7 @@
#define PA_LCD1 0xb8000000
#define PA_LCD2 0xb8800000
+#define __IO_PREFIX sh73180se
+#include <asm/io_generic.h>
+
#endif /* __ASM_SH_HITACHI_SE73180_H */
diff --git a/include/asm-sh/se73180/io.h b/include/asm-sh/se73180/io.h
deleted file mode 100644
index c9cb1b9412c6..000000000000
--- a/include/asm-sh/se73180/io.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * include/asm-sh/se73180/io.h
- *
- * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
- * Based on include/asm-sh/se7300/io.h
- *
- * IO functions for SH-Mobile3(SH73180) SolutionEngine
- *
- */
-
-#ifndef _ASM_SH_IO_73180SE_H
-#define _ASM_SH_IO_73180SE_H
-
-extern unsigned char sh73180se_inb(unsigned long port);
-extern unsigned short sh73180se_inw(unsigned long port);
-extern unsigned int sh73180se_inl(unsigned long port);
-
-extern void sh73180se_outb(unsigned char value, unsigned long port);
-extern void sh73180se_outw(unsigned short value, unsigned long port);
-extern void sh73180se_outl(unsigned int value, unsigned long port);
-
-extern unsigned char sh73180se_inb_p(unsigned long port);
-extern void sh73180se_outb_p(unsigned char value, unsigned long port);
-
-extern void sh73180se_insb(unsigned long port, void *addr, unsigned long count);
-extern void sh73180se_insw(unsigned long port, void *addr, unsigned long count);
-extern void sh73180se_insl(unsigned long port, void *addr, unsigned long count);
-extern void sh73180se_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void sh73180se_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void sh73180se_outsl(unsigned long port, const void *addr, unsigned long count);
-
-#endif /* _ASM_SH_IO_73180SE_H */
diff --git a/include/asm-sh/se7343.h b/include/asm-sh/se7343.h
new file mode 100644
index 000000000000..e7914a54aa96
--- /dev/null
+++ b/include/asm-sh/se7343.h
@@ -0,0 +1,82 @@
+#ifndef __ASM_SH_HITACHI_SE7343_H
+#define __ASM_SH_HITACHI_SE7343_H
+
+/*
+ * include/asm-sh/se/se7343.h
+ *
+ * Copyright (C) 2003 Takashi Kusuda <kusuda-takashi@hitachi-ul.co.jp>
+ *
+ * SH-Mobile SolutionEngine 7343 support
+ */
+
+/* Box specific addresses. */
+
+/* Area 0 */
+#define PA_ROM 0x00000000 /* EPROM */
+#define PA_ROM_SIZE 0x00400000 /* EPROM size 4M byte(Actually 2MB) */
+#define PA_FROM 0x00400000 /* Flash ROM */
+#define PA_FROM_SIZE 0x00400000 /* Flash size 4M byte */
+#define PA_SRAM 0x00800000 /* SRAM */
+#define PA_FROM_SIZE 0x00400000 /* SRAM size 4M byte */
+/* Area 1 */
+#define PA_EXT1 0x04000000
+#define PA_EXT1_SIZE 0x04000000
+/* Area 2 */
+#define PA_EXT2 0x08000000
+#define PA_EXT2_SIZE 0x04000000
+/* Area 3 */
+#define PA_SDRAM 0x0c000000
+#define PA_SDRAM_SIZE 0x04000000
+/* Area 4 */
+#define PA_PCIC 0x10000000 /* MR-SHPC-01 PCMCIA */
+#define PA_MRSHPC 0xb03fffe0 /* MR-SHPC-01 PCMCIA controller */
+#define PA_MRSHPC_MW1 0xb0400000 /* MR-SHPC-01 memory window base */
+#define PA_MRSHPC_MW2 0xb0500000 /* MR-SHPC-01 attribute window base */
+#define PA_MRSHPC_IO 0xb0600000 /* MR-SHPC-01 I/O window base */
+#define MRSHPC_OPTION (PA_MRSHPC + 6)
+#define MRSHPC_CSR (PA_MRSHPC + 8)
+#define MRSHPC_ISR (PA_MRSHPC + 10)
+#define MRSHPC_ICR (PA_MRSHPC + 12)
+#define MRSHPC_CPWCR (PA_MRSHPC + 14)
+#define MRSHPC_MW0CR1 (PA_MRSHPC + 16)
+#define MRSHPC_MW1CR1 (PA_MRSHPC + 18)
+#define MRSHPC_IOWCR1 (PA_MRSHPC + 20)
+#define MRSHPC_MW0CR2 (PA_MRSHPC + 22)
+#define MRSHPC_MW1CR2 (PA_MRSHPC + 24)
+#define MRSHPC_IOWCR2 (PA_MRSHPC + 26)
+#define MRSHPC_CDCR (PA_MRSHPC + 28)
+#define MRSHPC_PCIC_INFO (PA_MRSHPC + 30)
+#define PA_LED 0xb0C00000 /* LED */
+#define LED_SHIFT 0
+#define PA_DIPSW 0xb0900000 /* Dip switch 31 */
+#define PA_CPLD_MODESET 0xb1400004 /* CPLD Mode set register */
+#define PA_CPLD_ST 0xb1400008 /* CPLD Interrupt status register */
+#define PA_CPLD_IMSK 0xb140000a /* CPLD Interrupt mask register */
+/* Area 5 */
+#define PA_EXT5 0x14000000
+#define PA_EXT5_SIZE 0x04000000
+/* Area 6 */
+#define PA_LCD1 0xb8000000
+#define PA_LCD2 0xb8800000
+
+#define __IO_PREFIX sh7343se
+#include <asm/io_generic.h>
+
+/* External Multiplexed interrupts */
+#define PC_IRQ0 OFFCHIP_IRQ_BASE
+#define PC_IRQ1 (PC_IRQ0 + 1)
+#define PC_IRQ2 (PC_IRQ1 + 1)
+#define PC_IRQ3 (PC_IRQ2 + 1)
+
+#define EXT_IRQ0 (PC_IRQ3 + 1)
+#define EXT_IRQ1 (EXT_IRQ0 + 1)
+#define EXT_IRQ2 (EXT_IRQ1 + 1)
+#define EXT_IRQ3 (EXT_IRQ2 + 1)
+
+#define USB_IRQ0 (EXT_IRQ3 + 1)
+#define USB_IRQ1 (USB_IRQ0 + 1)
+
+#define UART_IRQ0 (USB_IRQ1 + 1)
+#define UART_IRQ1 (UART_IRQ0 + 1)
+
+#endif /* __ASM_SH_HITACHI_SE7343_H */
diff --git a/include/asm-sh/se7751/se7751.h b/include/asm-sh/se7751.h
index 738e22bebdfb..88cd379d9084 100644
--- a/include/asm-sh/se7751/se7751.h
+++ b/include/asm-sh/se7751.h
@@ -65,4 +65,7 @@
#define IRQ_79C973 13
+#define __IO_PREFIX sh7751se
+#include <asm/io_generic.h>
+
#endif /* __ASM_SH_HITACHI_7751SE_H */
diff --git a/include/asm-sh/se7751/io.h b/include/asm-sh/se7751/io.h
deleted file mode 100644
index 78d8f5744bc5..000000000000
--- a/include/asm-sh/se7751/io.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * include/asm-sh/io_7751se.h
- *
- * Modified version of io_se.h for the 7751se-specific functions.
- *
- * May be copied or modified under the terms of the GNU General Public
- * License. See linux/COPYING for more information.
- *
- * IO functions for an Hitachi SolutionEngine
- */
-
-#ifndef _ASM_SH_IO_7751SE_H
-#define _ASM_SH_IO_7751SE_H
-
-extern unsigned char sh7751se_inb(unsigned long port);
-extern unsigned short sh7751se_inw(unsigned long port);
-extern unsigned int sh7751se_inl(unsigned long port);
-
-extern void sh7751se_outb(unsigned char value, unsigned long port);
-extern void sh7751se_outw(unsigned short value, unsigned long port);
-extern void sh7751se_outl(unsigned int value, unsigned long port);
-
-extern unsigned char sh7751se_inb_p(unsigned long port);
-extern void sh7751se_outb_p(unsigned char value, unsigned long port);
-
-extern void sh7751se_insb(unsigned long port, void *addr, unsigned long count);
-extern void sh7751se_insw(unsigned long port, void *addr, unsigned long count);
-extern void sh7751se_insl(unsigned long port, void *addr, unsigned long count);
-extern void sh7751se_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void sh7751se_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void sh7751se_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned char sh7751se_readb(unsigned long addr);
-extern unsigned short sh7751se_readw(unsigned long addr);
-extern unsigned int sh7751se_readl(unsigned long addr);
-extern void sh7751se_writeb(unsigned char b, unsigned long addr);
-extern void sh7751se_writew(unsigned short b, unsigned long addr);
-extern void sh7751se_writel(unsigned int b, unsigned long addr);
-
-extern unsigned long sh7751se_isa_port2addr(unsigned long offset);
-
-#endif /* _ASM_SH_IO_7751SE_H */
diff --git a/include/asm-sh/setup.h b/include/asm-sh/setup.h
index d19de7c8df4e..34ca8a7f06ba 100644
--- a/include/asm-sh/setup.h
+++ b/include/asm-sh/setup.h
@@ -4,5 +4,7 @@
#define COMMAND_LINE_SIZE 256
+int setup_early_printk(char *);
+
#endif /* _SH_SETUP_H */
#endif /* __KERNEL__ */
diff --git a/include/asm-sh/sfp-machine.h b/include/asm-sh/sfp-machine.h
new file mode 100644
index 000000000000..d3c548443f2a
--- /dev/null
+++ b/include/asm-sh/sfp-machine.h
@@ -0,0 +1,84 @@
+/* Machine-dependent software floating-point definitions.
+ SuperH kernel version.
+ Copyright (C) 1997,1998,1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Richard Henderson (rth@cygnus.com),
+ Jakub Jelinek (jj@ultra.linux.cz),
+ David S. Miller (davem@redhat.com) and
+ Peter Maydell (pmaydell@chiark.greenend.org.uk).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If
+ not, write to the Free Software Foundation, Inc.,
+ 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#ifndef _SFP_MACHINE_H
+#define _SFP_MACHINE_H
+
+#define _FP_W_TYPE_SIZE 32
+#define _FP_W_TYPE unsigned long
+#define _FP_WS_TYPE signed long
+#define _FP_I_TYPE long
+
+#define _FP_MUL_MEAT_S(R,X,Y) \
+ _FP_MUL_MEAT_1_wide(_FP_WFRACBITS_S,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_D(R,X,Y) \
+ _FP_MUL_MEAT_2_wide(_FP_WFRACBITS_D,R,X,Y,umul_ppmm)
+#define _FP_MUL_MEAT_Q(R,X,Y) \
+ _FP_MUL_MEAT_4_wide(_FP_WFRACBITS_Q,R,X,Y,umul_ppmm)
+
+#define _FP_DIV_MEAT_S(R,X,Y) _FP_DIV_MEAT_1_udiv(S,R,X,Y)
+#define _FP_DIV_MEAT_D(R,X,Y) _FP_DIV_MEAT_2_udiv(D,R,X,Y)
+#define _FP_DIV_MEAT_Q(R,X,Y) _FP_DIV_MEAT_4_udiv(Q,R,X,Y)
+
+#define _FP_NANFRAC_S ((_FP_QNANBIT_S << 1) - 1)
+#define _FP_NANFRAC_D ((_FP_QNANBIT_D << 1) - 1), -1
+#define _FP_NANFRAC_Q ((_FP_QNANBIT_Q << 1) - 1), -1, -1, -1
+#define _FP_NANSIGN_S 0
+#define _FP_NANSIGN_D 0
+#define _FP_NANSIGN_Q 0
+
+#define _FP_KEEPNANFRACP 1
+
+/*
+ * If one NaN is signaling and the other is not,
+ * we choose that one, otherwise we choose X.
+ */
+#define _FP_CHOOSENAN(fs, wc, R, X, Y, OP) \
+ do { \
+ if ((_FP_FRAC_HIGH_RAW_##fs(X) & _FP_QNANBIT_##fs) \
+ && !(_FP_FRAC_HIGH_RAW_##fs(Y) & _FP_QNANBIT_##fs)) \
+ { \
+ R##_s = Y##_s; \
+ _FP_FRAC_COPY_##wc(R,Y); \
+ } \
+ else \
+ { \
+ R##_s = X##_s; \
+ _FP_FRAC_COPY_##wc(R,X); \
+ } \
+ R##_c = FP_CLS_NAN; \
+ } while (0)
+
+//#define FP_ROUNDMODE FPSCR_RM
+#define FP_DENORM_ZERO 1/*FPSCR_DN*/
+
+/* Exception flags. */
+#define FP_EX_INVALID (1<<4)
+#define FP_EX_DIVZERO (1<<3)
+#define FP_EX_OVERFLOW (1<<2)
+#define FP_EX_UNDERFLOW (1<<1)
+#define FP_EX_INEXACT (1<<0)
+
+#endif
+
diff --git a/include/asm-sh/sh03/io.h b/include/asm-sh/sh03/io.h
index 25792e9831ea..df3b187ef883 100644
--- a/include/asm-sh/sh03/io.h
+++ b/include/asm-sh/sh03/io.h
@@ -33,14 +33,6 @@
#define IRL3_IPR_POS 0
#define IRL3_PRIORITY 4
-
-extern unsigned long sh03_isa_port2addr(unsigned long offset);
-
-extern void setup_sh03(void);
-extern void init_sh03_IRQ(void);
-extern void heartbeat_sh03(void);
-
-extern void sh03_rtc_gettimeofday(struct timeval *tv);
-extern int sh03_rtc_settimeofday(const struct timeval *tv);
+void heartbeat_sh03(void);
#endif /* _ASM_SH_IO_SH03_H */
diff --git a/include/asm-sh/sh2000/sh2000.h b/include/asm-sh/sh2000/sh2000.h
deleted file mode 100644
index 8d547324d59a..000000000000
--- a/include/asm-sh/sh2000/sh2000.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __ASM_SH_SH2000_SH2000_H
-#define __ASM_SH_SH2000_SH2000_H
-
-/* arch/sh/boards/sh2000/setup.c */
-extern int setup_sh2000(void);
-
-#endif /* __ASM_SH_SH2000_SH2000_H */
-
diff --git a/include/asm-sh/shmin/shmin.h b/include/asm-sh/shmin/shmin.h
new file mode 100644
index 000000000000..36ba138a81fb
--- /dev/null
+++ b/include/asm-sh/shmin/shmin.h
@@ -0,0 +1,9 @@
+#ifndef __ASM_SH_SHMIN_H
+#define __ASM_SH_SHMIN_H
+
+#define SHMIN_IO_BASE 0xb0000000UL
+
+#define SHMIN_NE_IRQ IRQ2_IRQ
+#define SHMIN_NE_BASE 0x300
+
+#endif
diff --git a/include/asm-sh/shmparam.h b/include/asm-sh/shmparam.h
index 0a95604b9b66..ba1758d90106 100644
--- a/include/asm-sh/shmparam.h
+++ b/include/asm-sh/shmparam.h
@@ -1,8 +1,22 @@
+/*
+ * include/asm-sh/shmparam.h
+ *
+ * Copyright (C) 1999 Niibe Yutaka
+ * Copyright (C) 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.
+ */
#ifndef __ASM_SH_SHMPARAM_H
#define __ASM_SH_SHMPARAM_H
-#ifdef __KERNEL__
-#include <asm/cpu/shmparam.h>
+/*
+ * SH-4 and SH-3 7705 have an aliasing dcache. Bump this up to a sensible value
+ * for everyone, and work out the specifics from the probed cache descriptor.
+ */
+#define SHMLBA 0x4000 /* attach addr a multiple of this */
+
+#define __ARCH_FORCE_SHMLBA
-#endif /* __KERNEL__ */
#endif /* __ASM_SH_SHMPARAM_H */
diff --git a/include/asm-sh/se/smc37c93x.h b/include/asm-sh/smc37c93x.h
index 585da2a8fc45..585da2a8fc45 100644
--- a/include/asm-sh/se/smc37c93x.h
+++ b/include/asm-sh/smc37c93x.h
diff --git a/include/asm-sh/smp.h b/include/asm-sh/smp.h
index f57c4fe9692a..71ecddf70db3 100644
--- a/include/asm-sh/smp.h
+++ b/include/asm-sh/smp.h
@@ -19,11 +19,6 @@
#include <asm/atomic.h>
#include <asm/current.h>
-extern cpumask_t cpu_online_map;
-extern cpumask_t cpu_possible_map;
-
-#define cpu_online(cpu) cpu_isset(cpu, cpu_online_map)
-
#define raw_smp_processor_id() (current_thread_info()->cpu)
/* I've no idea what the real meaning of this is */
diff --git a/include/asm-sh/snapgear/io.h b/include/asm-sh/snapgear.h
index bfa97ac06280..6b5e4ddc073a 100644
--- a/include/asm-sh/snapgear/io.h
+++ b/include/asm-sh/snapgear.h
@@ -40,21 +40,8 @@
#define IRL3_PRIORITY 4
#endif
-extern unsigned char snapgear_inb(unsigned long port);
-extern unsigned short snapgear_inw(unsigned long port);
-extern unsigned int snapgear_inl(unsigned long port);
-
-extern void snapgear_outb(unsigned char value, unsigned long port);
-extern void snapgear_outw(unsigned short value, unsigned long port);
-extern void snapgear_outl(unsigned int value, unsigned long port);
-
-extern unsigned char snapgear_inb_p(unsigned long port);
-extern void snapgear_outb_p(unsigned char value, unsigned long port);
-
-extern void snapgear_insl(unsigned long port, void *addr, unsigned long count);
-extern void snapgear_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned long snapgear_isa_port2addr(unsigned long offset);
+#define __IO_PREFIX snapgear
+#include <asm/io_generic.h>
#ifdef CONFIG_SH_SECUREEDGE5410
/*
@@ -79,14 +66,14 @@ extern unsigned long snapgear_isa_port2addr(unsigned long offset);
* D12 - RTS RESET
*/
- #define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
- extern unsigned short secureedge5410_ioport;
+#define SECUREEDGE_IOPORT_ADDR ((volatile short *) 0xb0000000)
+extern unsigned short secureedge5410_ioport;
- #define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
- (secureedge5410_ioport = \
- ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
- #define SECUREEDGE_READ_IOPORT() \
- ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
+#define SECUREEDGE_WRITE_IOPORT(val, mask) (*SECUREEDGE_IOPORT_ADDR = \
+ (secureedge5410_ioport = \
+ ((secureedge5410_ioport & ~(mask)) | ((val) & (mask)))))
+#define SECUREEDGE_READ_IOPORT() \
+ ((*SECUREEDGE_IOPORT_ADDR&0x0817) | (secureedge5410_ioport&~0x0817))
#endif
#endif /* _ASM_SH_IO_SNAPGEAR_H */
diff --git a/include/asm-sh/spinlock.h b/include/asm-sh/spinlock.h
index 846322d4c35d..2586eef07d57 100644
--- a/include/asm-sh/spinlock.h
+++ b/include/asm-sh/spinlock.h
@@ -88,7 +88,14 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
__raw_spin_unlock(&rw->lock);
}
-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
+static inline int __raw_read_trylock(raw_rwlock_t *lock)
+{
+ atomic_t *count = (atomic_t*)lock;
+ if (atomic_dec_return(count) >= 0)
+ return 1;
+ atomic_inc(count);
+ return 0;
+}
static inline int __raw_write_trylock(raw_rwlock_t *rw)
{
@@ -100,4 +107,8 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
return 0;
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_SH_SPINLOCK_H */
diff --git a/include/asm-sh/string.h b/include/asm-sh/string.h
index 3e0cff04caec..95bc7db006b0 100644
--- a/include/asm-sh/string.h
+++ b/include/asm-sh/string.h
@@ -1,13 +1,15 @@
#ifndef __ASM_SH_STRING_H
#define __ASM_SH_STRING_H
+#ifdef __KERNEL__
+
/*
* Copyright (C) 1999 Niibe Yutaka
* But consider these trivial functions to be public domain.
*/
#define __HAVE_ARCH_STRCPY
-static __inline__ char *strcpy(char *__dest, const char *__src)
+static inline char *strcpy(char *__dest, const char *__src)
{
register char *__xdest = __dest;
unsigned long __dummy;
@@ -26,7 +28,7 @@ static __inline__ char *strcpy(char *__dest, const char *__src)
}
#define __HAVE_ARCH_STRNCPY
-static __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+static inline char *strncpy(char *__dest, const char *__src, size_t __n)
{
register char *__xdest = __dest;
unsigned long __dummy;
@@ -52,7 +54,7 @@ static __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
}
#define __HAVE_ARCH_STRCMP
-static __inline__ int strcmp(const char *__cs, const char *__ct)
+static inline int strcmp(const char *__cs, const char *__ct)
{
register int __res;
unsigned long __dummy;
@@ -78,7 +80,7 @@ static __inline__ int strcmp(const char *__cs, const char *__ct)
}
#define __HAVE_ARCH_STRNCMP
-static __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+static inline int strncmp(const char *__cs, const char *__ct, size_t __n)
{
register int __res;
unsigned long __dummy;
@@ -124,4 +126,9 @@ extern void *memchr(const void *__s, int __c, size_t __n);
#define __HAVE_ARCH_STRLEN
extern size_t strlen(const char *);
+/* arch/sh/lib/strcasecmp.c */
+extern int strcasecmp(const char *, const char *);
+
+#endif /* __KERNEL__ */
+
#endif /* __ASM_SH_STRING_H */
diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h
index ad35ad4958f4..6c1f8fde5ac4 100644
--- a/include/asm-sh/system.h
+++ b/include/asm-sh/system.h
@@ -6,6 +6,7 @@
* Copyright (C) 2002 Paul Mundt
*/
+#include <asm/types.h>
/*
* switch_to() should switch tasks to task nr n, first
@@ -66,13 +67,20 @@ static inline void sched_cacheflush(void)
{
}
-#define nop() __asm__ __volatile__ ("nop")
-
-
-#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+#ifdef CONFIG_CPU_SH4A
+#define __icbi() \
+{ \
+ unsigned long __addr; \
+ __addr = 0xa8000000; \
+ __asm__ __volatile__( \
+ "icbi %0\n\t" \
+ : /* no output */ \
+ : "m" (__m(__addr))); \
+}
+#endif
-static __inline__ unsigned long tas(volatile int *m)
-{ /* #define tas(ptr) (xchg((ptr),1)) */
+static inline unsigned long tas(volatile int *m)
+{
unsigned long retval;
__asm__ __volatile__ ("tas.b @%1\n\t"
@@ -81,12 +89,33 @@ static __inline__ unsigned long tas(volatile int *m)
return retval;
}
-extern void __xchg_called_with_bad_pointer(void);
-
-#define mb() __asm__ __volatile__ ("": : :"memory")
-#define rmb() mb()
-#define wmb() __asm__ __volatile__ ("": : :"memory")
+/*
+ * A brief note on ctrl_barrier(), the control register write barrier.
+ *
+ * Legacy SH cores typically require a sequence of 8 nops after
+ * modification of a control register in order for the changes to take
+ * effect. On newer cores (like the sh4a and sh5) this is accomplished
+ * with icbi.
+ *
+ * Also note that on sh4a in the icbi case we can forego a synco for the
+ * write barrier, as it's not necessary for control registers.
+ *
+ * Historically we have only done this type of barrier for the MMUCR, but
+ * it's also necessary for the CCR, so we make it generic here instead.
+ */
+#ifdef CONFIG_CPU_SH4A
+#define mb() __asm__ __volatile__ ("synco": : :"memory")
+#define rmb() mb()
+#define wmb() __asm__ __volatile__ ("synco": : :"memory")
+#define ctrl_barrier() __icbi()
+#define read_barrier_depends() do { } while(0)
+#else
+#define mb() __asm__ __volatile__ ("": : :"memory")
+#define rmb() mb()
+#define wmb() __asm__ __volatile__ ("": : :"memory")
+#define ctrl_barrier() __asm__ __volatile__ ("nop;nop;nop;nop;nop;nop;nop;nop")
#define read_barrier_depends() do { } while(0)
+#endif
#ifdef CONFIG_SMP
#define smp_mb() mb()
@@ -103,7 +132,8 @@ extern void __xchg_called_with_bad_pointer(void);
#define set_mb(var, value) do { xchg(&var, value); } while (0)
/* Interrupt Control */
-static __inline__ void local_irq_enable(void)
+#ifdef CONFIG_CPU_HAS_SR_RB
+static inline void local_irq_enable(void)
{
unsigned long __dummy0, __dummy1;
@@ -116,8 +146,22 @@ static __inline__ void local_irq_enable(void)
: "1" (~0x000000f0)
: "memory");
}
+#else
+static inline void local_irq_enable(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ (
+ "stc sr, %0\n\t"
+ "and %1, %0\n\t"
+ "ldc %0, sr\n\t"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~0x000000f0)
+ : "memory");
+}
+#endif
-static __inline__ void local_irq_disable(void)
+static inline void local_irq_disable(void)
{
unsigned long __dummy;
__asm__ __volatile__("stc sr, %0\n\t"
@@ -128,6 +172,31 @@ static __inline__ void local_irq_disable(void)
: "memory");
}
+static inline void set_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ ("stc sr, %0\n\t"
+ "or %2, %0\n\t"
+ "and %3, %0\n\t"
+ "ldc %0, sr"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "r" (0x10000000), "r" (0xffffff0f)
+ : "memory");
+}
+
+static inline void clear_bl_bit(void)
+{
+ unsigned long __dummy0, __dummy1;
+
+ __asm__ __volatile__ ("stc sr, %0\n\t"
+ "and %2, %0\n\t"
+ "ldc %0, sr"
+ : "=&r" (__dummy0), "=r" (__dummy1)
+ : "1" (~0x10000000)
+ : "memory");
+}
+
#define local_save_flags(x) \
__asm__("stc sr, %0; and #0xf0, %0" : "=&z" (x) :/**/: "memory" )
@@ -138,7 +207,7 @@ static __inline__ void local_irq_disable(void)
(flags != 0); \
})
-static __inline__ unsigned long local_irq_save(void)
+static inline unsigned long local_irq_save(void)
{
unsigned long flags, __dummy;
@@ -154,35 +223,9 @@ static __inline__ unsigned long local_irq_save(void)
return flags;
}
-#ifdef DEBUG_CLI_STI
-static __inline__ void local_irq_restore(unsigned long x)
-{
- if ((x & 0x000000f0) != 0x000000f0)
- local_irq_enable();
- else {
- unsigned long flags;
- local_save_flags(flags);
-
- if (flags == 0) {
- extern void dump_stack(void);
- printk(KERN_ERR "BUG!\n");
- dump_stack();
- local_irq_disable();
- }
- }
-}
-#else
-#define local_irq_restore(x) do { \
- if ((x & 0x000000f0) != 0x000000f0) \
- local_irq_enable(); \
-} while (0)
-#endif
-
-#define really_restore_flags(x) do { \
+#define local_irq_restore(x) do { \
if ((x & 0x000000f0) != 0x000000f0) \
- local_irq_enable(); \
- else \
- local_irq_disable(); \
+ local_irq_enable(); \
} while (0)
/*
@@ -210,8 +253,8 @@ do { \
#define back_to_P1() \
do { \
unsigned long __dummy; \
+ ctrl_barrier(); \
__asm__ __volatile__( \
- "nop;nop;nop;nop;nop;nop;nop\n\t" \
"mov.l 1f, %0\n\t" \
"jmp @%0\n\t" \
" nop\n\t" \
@@ -224,7 +267,7 @@ do { \
/* For spinlocks etc */
#define local_irq_save(x) x = local_irq_save()
-static __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
+static inline unsigned long xchg_u32(volatile u32 *m, unsigned long val)
{
unsigned long flags, retval;
@@ -235,7 +278,7 @@ static __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
return retval;
}
-static __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned long val)
+static inline unsigned long xchg_u8(volatile u8 *m, unsigned long val)
{
unsigned long flags, retval;
@@ -246,20 +289,70 @@ static __inline__ unsigned long xchg_u8(volatile unsigned char * m, unsigned lon
return retval;
}
-static __inline__ unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+extern void __xchg_called_with_bad_pointer(void);
+
+#define __xchg(ptr, x, size) \
+({ \
+ unsigned long __xchg__res; \
+ volatile void *__xchg_ptr = (ptr); \
+ switch (size) { \
+ case 4: \
+ __xchg__res = xchg_u32(__xchg_ptr, x); \
+ break; \
+ case 1: \
+ __xchg__res = xchg_u8(__xchg_ptr, x); \
+ break; \
+ default: \
+ __xchg_called_with_bad_pointer(); \
+ __xchg__res = x; \
+ break; \
+ } \
+ \
+ __xchg__res; \
+})
+
+#define xchg(ptr,x) \
+ ((__typeof__(*(ptr)))__xchg((ptr),(unsigned long)(x), sizeof(*(ptr))))
+
+static inline unsigned long __cmpxchg_u32(volatile int * m, unsigned long old,
+ unsigned long new)
+{
+ __u32 retval;
+ unsigned long flags;
+
+ local_irq_save(flags);
+ retval = *m;
+ if (retval == old)
+ *m = new;
+ local_irq_restore(flags); /* implies memory barrier */
+ return retval;
+}
+
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+#define __HAVE_ARCH_CMPXCHG 1
+
+static inline unsigned long __cmpxchg(volatile void * ptr, unsigned long old,
+ unsigned long new, int size)
{
switch (size) {
case 4:
- return xchg_u32(ptr, x);
- break;
- case 1:
- return xchg_u8(ptr, x);
- break;
+ return __cmpxchg_u32(ptr, old, new);
}
- __xchg_called_with_bad_pointer();
- return x;
+ __cmpxchg_called_with_bad_pointer();
+ return old;
}
+#define cmpxchg(ptr,o,n) \
+ ({ \
+ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
+ (unsigned long)_n_, sizeof(*(ptr))); \
+ })
+
/* XXX
* disable hlt during certain critical i/o operations
*/
diff --git a/include/asm-sh/systemh/io.h b/include/asm-sh/systemh/io.h
deleted file mode 100644
index 327849b49db8..000000000000
--- a/include/asm-sh/systemh/io.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * include/asm-sh/systemh/io.h
- *
- * Stupid I/O definitions for SystemH, cloned from SE7751.
- *
- * Copyright (C) 2003 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.
- */
-#ifndef __ASM_SH_SYSTEMH_IO_H
-#define __ASM_SH_SYSTEMH_IO_H
-
-extern unsigned char sh7751systemh_inb(unsigned long port);
-extern unsigned short sh7751systemh_inw(unsigned long port);
-extern unsigned int sh7751systemh_inl(unsigned long port);
-
-extern void sh7751systemh_outb(unsigned char value, unsigned long port);
-extern void sh7751systemh_outw(unsigned short value, unsigned long port);
-extern void sh7751systemh_outl(unsigned int value, unsigned long port);
-
-extern unsigned char sh7751systemh_inb_p(unsigned long port);
-extern void sh7751systemh_outb_p(unsigned char value, unsigned long port);
-
-extern void sh7751systemh_insb(unsigned long port, void *addr, unsigned long count);
-extern void sh7751systemh_insw(unsigned long port, void *addr, unsigned long count);
-extern void sh7751systemh_insl(unsigned long port, void *addr, unsigned long count);
-extern void sh7751systemh_outsb(unsigned long port, const void *addr, unsigned long count);
-extern void sh7751systemh_outsw(unsigned long port, const void *addr, unsigned long count);
-extern void sh7751systemh_outsl(unsigned long port, const void *addr, unsigned long count);
-
-extern unsigned char sh7751systemh_readb(unsigned long addr);
-extern unsigned short sh7751systemh_readw(unsigned long addr);
-extern unsigned int sh7751systemh_readl(unsigned long addr);
-extern void sh7751systemh_writeb(unsigned char b, unsigned long addr);
-extern void sh7751systemh_writew(unsigned short b, unsigned long addr);
-extern void sh7751systemh_writel(unsigned int b, unsigned long addr);
-
-extern unsigned long sh7751systemh_isa_port2addr(unsigned long offset);
-
-#endif /* __ASM_SH_SYSTEMH_IO_H */
-
diff --git a/include/asm-sh/systemh/7751systemh.h b/include/asm-sh/systemh7751.h
index 4170531bdbd9..b143bb2a2ca7 100644
--- a/include/asm-sh/systemh/7751systemh.h
+++ b/include/asm-sh/systemh7751.h
@@ -65,4 +65,7 @@
#define IRQ_79C973 13
+#define __IO_PREFIX sh7751systemh
+#include <asm/io_generic.h>
+
#endif /* __ASM_SH_SYSTEMH_7751SYSTEMH_H */
diff --git a/include/asm-sh/thread_info.h b/include/asm-sh/thread_info.h
index 7345350d98c0..3ebc3f9039eb 100644
--- a/include/asm-sh/thread_info.h
+++ b/include/asm-sh/thread_info.h
@@ -9,8 +9,8 @@
* Copyright (C) 2002 David Howells (dhowells@redhat.com)
* - Incorporating suggestions made by Linus Torvalds and Dave Miller
*/
-
#ifdef __KERNEL__
+#include <asm/page.h>
#ifndef __ASSEMBLY__
#include <asm/processor.h>
@@ -21,7 +21,10 @@ struct thread_info {
unsigned long flags; /* low level flags */
__u32 cpu;
int preempt_count; /* 0 => preemptable, <0 => BUG */
+ mm_segment_t addr_limit; /* thread address space */
struct restart_block restart_block;
+ unsigned long previous_sp; /* sp of previous stack in case
+ of nested IRQ stacks */
__u8 supervisor_stack[0];
};
@@ -29,6 +32,13 @@ struct thread_info {
#define PREEMPT_ACTIVE 0x10000000
+#ifdef CONFIG_4KSTACKS
+#define THREAD_SIZE (PAGE_SIZE)
+#else
+#define THREAD_SIZE (PAGE_SIZE * 2)
+#endif
+#define STACK_WARN (THREAD_SIZE / 8)
+
/*
* macros/functions for gaining access to the thread information structure
*/
@@ -40,6 +50,7 @@ struct thread_info {
.flags = 0, \
.cpu = 0, \
.preempt_count = 1, \
+ .addr_limit = KERNEL_DS, \
.restart_block = { \
.fn = do_no_restart_syscall, \
}, \
@@ -48,24 +59,42 @@ struct thread_info {
#define init_thread_info (init_thread_union.thread_info)
#define init_stack (init_thread_union.stack)
+/* how to get the current stack pointer from C */
+register unsigned long current_stack_pointer asm("r15") __attribute_used__;
+
/* how to get the thread information struct from C */
static inline struct thread_info *current_thread_info(void)
{
struct thread_info *ti;
+#ifdef CONFIG_CPU_HAS_SR_RB
__asm__("stc r7_bank, %0" : "=r" (ti));
+#else
+ unsigned long __dummy;
+
+ __asm__ __volatile__ (
+ "mov r15, %0\n\t"
+ "and %1, %0\n\t"
+ : "=&r" (ti), "=r" (__dummy)
+ : "1" (~(THREAD_SIZE - 1))
+ : "memory");
+#endif
+
return ti;
}
/* thread information allocation */
-#define THREAD_SIZE (2*PAGE_SIZE)
-#define alloc_thread_info(ti) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
-#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#ifdef CONFIG_DEBUG_STACK_USAGE
+#define alloc_thread_info(ti) kzalloc(THREAD_SIZE, GFP_KERNEL)
+#else
+#define alloc_thread_info(ti) kmalloc(THREAD_SIZE, GFP_KERNEL)
+#endif
+#define free_thread_info(ti) kfree(ti)
#else /* !__ASSEMBLY__ */
/* how to get the thread information struct from ASM */
#define GET_THREAD_INFO(reg) \
- stc r7_bank, reg
+ stc r7_bank, reg
#endif
@@ -79,18 +108,18 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
#define TIF_SIGPENDING 2 /* signal pending */
#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_RESTORE_SIGMASK 4 /* restore signal mask in do_signal() */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling TIF_NEED_RESCHED */
#define TIF_MEMDIE 18
-#define TIF_USERSPACE 31 /* true if FS sets userspace */
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_RESTORE_SIGMASK (1<<TIF_RESTORE_SIGMASK)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_USERSPACE (1<<TIF_USERSPACE)
#define _TIF_WORK_MASK 0x000000FE /* work to do on interrupt/exception return */
#define _TIF_ALLWORK_MASK 0x000000FF /* work to do on any return to u-space */
diff --git a/include/asm-sh/timer.h b/include/asm-sh/timer.h
index dd6579c0b04c..5df842bcf7b6 100644
--- a/include/asm-sh/timer.h
+++ b/include/asm-sh/timer.h
@@ -6,8 +6,11 @@
struct sys_timer_ops {
int (*init)(void);
+ int (*start)(void);
+ int (*stop)(void);
+#ifndef CONFIG_GENERIC_TIME
unsigned long (*get_offset)(void);
- unsigned long (*get_frequency)(void);
+#endif
};
struct sys_timer {
@@ -22,21 +25,17 @@ struct sys_timer {
extern struct sys_timer tmu_timer;
extern struct sys_timer *sys_timer;
+#ifndef CONFIG_GENERIC_TIME
static inline unsigned long get_timer_offset(void)
{
return sys_timer->ops->get_offset();
}
-
-static inline unsigned long get_timer_frequency(void)
-{
- return sys_timer->ops->get_frequency();
-}
+#endif
/* arch/sh/kernel/timers/timer.c */
struct sys_timer *get_sys_timer(void);
/* arch/sh/kernel/time.c */
-void handle_timer_tick(struct pt_regs *);
+void handle_timer_tick(void);
#endif /* __ASM_SH_TIMER_H */
-
diff --git a/include/asm-sh/titan.h b/include/asm-sh/titan.h
new file mode 100644
index 000000000000..270a4f4bc8a9
--- /dev/null
+++ b/include/asm-sh/titan.h
@@ -0,0 +1,43 @@
+/*
+ * Platform defintions for Titan
+ */
+
+#ifndef _ASM_SH_TITAN_TITAN_H
+#define _ASM_SH_TITAN_TITAN_H
+
+#define __IO_PREFIX titan
+#include <asm/io_generic.h>
+
+/* IRQ assignments */
+#define TITAN_IRQ_WAN 2 /* eth0 (WAN) */
+#define TITAN_IRQ_LAN 5 /* eth1 (LAN) */
+#define TITAN_IRQ_MPCIA 8 /* mPCI A */
+#define TITAN_IRQ_MPCIB 11 /* mPCI B */
+#define TITAN_IRQ_USB 11 /* USB */
+
+/*
+ * The external interrupt lines, these take up ints 0 - 15 inclusive
+ * depending on the priority for the interrupt. In fact the priority
+ * is the interrupt :-)
+ */
+#define IRL0_IRQ 0
+#define IRL0_IPR_ADDR INTC_IPRD
+#define IRL0_IPR_POS 3
+#define IRL0_PRIORITY 8
+
+#define IRL1_IRQ 1
+#define IRL1_IPR_ADDR INTC_IPRD
+#define IRL1_IPR_POS 2
+#define IRL1_PRIORITY 8
+
+#define IRL2_IRQ 2
+#define IRL2_IPR_ADDR INTC_IPRD
+#define IRL2_IPR_POS 1
+#define IRL2_PRIORITY 8
+
+#define IRL3_IRQ 3
+#define IRL3_IPR_ADDR INTC_IPRD
+#define IRL3_IPR_POS 0
+#define IRL3_PRIORITY 8
+
+#endif
diff --git a/include/asm-sh/uaccess.h b/include/asm-sh/uaccess.h
index 2cb01861e7c5..5c49ed6715f2 100644
--- a/include/asm-sh/uaccess.h
+++ b/include/asm-sh/uaccess.h
@@ -16,21 +16,9 @@
#include <linux/errno.h>
#include <linux/sched.h>
-/*
- * NOTE: Macro/functions in this file depends on threads_info.h implementation.
- * Assumes:
- * TI_FLAGS == 8
- * TIF_USERSPACE == 31
- * USER_ADDR_LIMIT == 0x80000000
- */
-
#define VERIFY_READ 0
#define VERIFY_WRITE 1
-typedef struct {
- unsigned int is_user_space;
-} mm_segment_t;
-
/*
* The fs value determines whether argument validity checking should be
* performed or not. If get_fs() == USER_DS, checking is performed, with
@@ -40,16 +28,18 @@ typedef struct {
*/
#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define segment_eq(a,b) ((a).is_user_space == (b).is_user_space)
-#define USER_ADDR_LIMIT 0x80000000
+#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFFUL)
+#define USER_DS MAKE_MM_SEG(PAGE_OFFSET)
-#define KERNEL_DS MAKE_MM_SEG(0)
-#define USER_DS MAKE_MM_SEG(1)
+#define segment_eq(a,b) ((a).seg == (b).seg)
#define get_ds() (KERNEL_DS)
#if !defined(CONFIG_MMU)
+/* NOMMU is always true */
+#define __addr_ok(addr) (1)
+
static inline mm_segment_t get_fs(void)
{
return USER_DS;
@@ -76,31 +66,11 @@ static inline int __access_ok(unsigned long addr, unsigned long size)
return ((addr >= memory_start) && ((addr + size) < memory_end));
}
#else /* CONFIG_MMU */
-static inline mm_segment_t get_fs(void)
-{
- return MAKE_MM_SEG(test_thread_flag(TIF_USERSPACE));
-}
+#define __addr_ok(addr) \
+ ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
-static inline void set_fs(mm_segment_t s)
-{
- unsigned long ti, flag;
- __asm__ __volatile__(
- "stc r7_bank, %0\n\t"
- "mov.l @(8,%0), %1\n\t"
- "shal %1\n\t"
- "cmp/pl %2\n\t"
- "rotcr %1\n\t"
- "mov.l %1, @(8,%0)"
- : "=&r" (ti), "=&r" (flag)
- : "r" (s.is_user_space)
- : "t");
-/****
- if (s.is_user_space)
- set_thread_flag(TIF_USERSPACE);
- else
- clear_thread_flag(TIF_USERSPACE);
-****/
-}
+#define get_fs() (current_thread_info()->addr_limit)
+#define set_fs(x) (current_thread_info()->addr_limit = (x))
/*
* __access_ok: Check if address with size is OK or not.
@@ -108,7 +78,7 @@ static inline void set_fs(mm_segment_t s)
* We do three checks:
* (1) is it user space?
* (2) addr + size --> carry?
- * (3) addr + size >= 0x80000000 (USER_ADDR_LIMIT)
+ * (3) addr + size >= 0x80000000 (PAGE_OFFSET)
*
* (1) (2) (3) | RESULT
* 0 0 0 | ok
@@ -201,6 +171,7 @@ do { \
__gu_err; \
})
+#ifdef CONFIG_MMU
#define __get_user_check(x,ptr,size) \
({ \
long __gu_err, __gu_val; \
@@ -290,6 +261,18 @@ __asm__("stc r7_bank, %1\n\t" \
: "r" (addr) \
: "t"); \
})
+#else /* CONFIG_MMU */
+#define __get_user_check(x,ptr,size) \
+({ \
+ long __gu_err, __gu_val; \
+ if (__access_ok((unsigned long)(ptr), (size))) { \
+ __get_user_size(__gu_val, (ptr), (size), __gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ } else \
+ __gu_err = -EFAULT; \
+ __gu_err; \
+})
+#endif
#define __get_user_asm(x, addr, err, insn) \
({ \
@@ -541,7 +524,7 @@ static __inline__ long __strnlen_user(const char __user *__s, long __n)
"3:\n\t"
"mov.l 4f, %1\n\t"
"jmp @%1\n\t"
- " mov %5, %0\n"
+ " mov #0, %0\n"
".balign 4\n"
"4: .long 2b\n"
".previous\n"
@@ -550,26 +533,20 @@ static __inline__ long __strnlen_user(const char __user *__s, long __n)
" .long 1b,3b\n"
".previous"
: "=z" (res), "=&r" (__dummy)
- : "0" (0), "r" (__s), "r" (__n), "i" (-EFAULT)
+ : "0" (0), "r" (__s), "r" (__n)
: "t");
return res;
}
static __inline__ long strnlen_user(const char __user *s, long n)
{
- if (!access_ok(VERIFY_READ, s, n))
+ if (!__addr_ok(s))
return 0;
else
return __strnlen_user(s, n);
}
-static __inline__ long strlen_user(const char __user *s)
-{
- if (!access_ok(VERIFY_READ, s, 0))
- return 0;
- else
- return __strnlen_user(s, ~0UL >> 1);
-}
+#define strlen_user(str) strnlen_user(str, ~0UL >> 1)
/*
* The exception table consists of pairs of addresses: the first is the
diff --git a/include/asm-sh/unistd.h b/include/asm-sh/unistd.h
index 76b5430cb458..f1a0cbc966be 100644
--- a/include/asm-sh/unistd.h
+++ b/include/asm-sh/unistd.h
@@ -292,25 +292,51 @@
#define __NR_mq_getsetattr (__NR_mq_open+5)
#define __NR_kexec_load 283
#define __NR_waitid 284
-#define __NR_add_key 285
-#define __NR_request_key 286
-#define __NR_keyctl 287
-#define __NR_ioprio_set 288
-#define __NR_ioprio_get 289
-#define __NR_inotify_init 290
-#define __NR_inotify_add_watch 291
-#define __NR_inotify_rm_watch 292
+/* #define __NR_sys_setaltroot 285 */
+#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_newfstatat 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_syscalls 293
+#define NR_syscalls 317
#ifdef __KERNEL__
-/* user-visible error numbers are in the range -1 - -124: see <asm-sh/errno.h> */
+#include <linux/err.h>
+
+/* user-visible error numbers are in the range -1 - -MAX_ERRNO:
+ * see <asm-sh/errno.h> */
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-124)) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
/* Avoid using "res" which is declared to be in register r0; \
errno might expand to a function call and clobber it. */ \
int __err = -(res); \
@@ -444,76 +470,7 @@ __syscall_return(type,__sc0); \
#define __ARCH_WANT_SYS_SIGPENDING
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <linux/linkage.h>
-#include <asm/ptrace.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static __inline__ _syscall0(int,pause)
-static __inline__ _syscall0(int,sync)
-static __inline__ _syscall0(pid_t,setsid)
-static __inline__ _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static __inline__ _syscall1(int,dup,int,fd)
-static __inline__ _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static __inline__ _syscall3(int,open,const char *,file,int,flag,int,mode)
-static __inline__ _syscall1(int,close,int,fd)
-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static __inline__ _syscall1(int,delete_module,const char *,name)
-
-static __inline__ pid_t wait(int * wait_stat)
-{
- return waitpid(-1,wait_stat,0);
-}
-
-asmlinkage long sys_mmap2(
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-asmlinkage int sys_execve(char *ufilename, char **uargv,
- char **uenvp, unsigned long r7,
- struct pt_regs regs);
-asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
- unsigned long parent_tidptr,
- unsigned long child_tidptr,
- struct pt_regs regs);
-asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs regs);
-asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs regs);
-asmlinkage int sys_pipe(unsigned long r4, unsigned long r5,
- unsigned long r6, unsigned long r7,
- struct pt_regs regs);
-asmlinkage ssize_t sys_pread_wrapper(unsigned int fd, char *buf,
- size_t count, long dummy, loff_t pos);
-asmlinkage ssize_t sys_pwrite_wrapper(unsigned int fd, const char *buf,
- size_t count, long dummy, loff_t pos);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
+#define __ARCH_WANT_SYS_RT_SIGSUSPEND
/*
* "Conditional" syscalls
diff --git a/include/asm-sh/rts7751r2d/voyagergx_reg.h b/include/asm-sh/voyagergx.h
index f031b5d6cf54..99b0807d1c9f 100644
--- a/include/asm-sh/rts7751r2d/voyagergx_reg.h
+++ b/include/asm-sh/voyagergx.h
@@ -1,5 +1,5 @@
/* -------------------------------------------------------------------- */
-/* voyagergx_reg.h */
+/* voyagergx.h */
/* -------------------------------------------------------------------- */
/* 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-sh/watchdog.h b/include/asm-sh/watchdog.h
index 09ca41972a11..d19ea62ef8c6 100644
--- a/include/asm-sh/watchdog.h
+++ b/include/asm-sh/watchdog.h
@@ -62,7 +62,6 @@
/**
* sh_wdt_read_cnt - Read from Counter
- *
* Reads back the WTCNT value.
*/
static inline __u8 sh_wdt_read_cnt(void)
@@ -72,7 +71,6 @@ static inline __u8 sh_wdt_read_cnt(void)
/**
* sh_wdt_write_cnt - Write to Counter
- *
* @val: Value to write
*
* Writes the given value @val to the lower byte of the timer counter.
@@ -95,7 +93,6 @@ static inline __u8 sh_wdt_read_csr(void)
/**
* sh_wdt_write_csr - Write to Control/Status Register
- *
* @val: Value to write
*
* Writes the given value @val to the lower byte of the control/status
diff --git a/include/asm-sh64/io.h b/include/asm-sh64/io.h
index 252fedbb6621..14d8e7b4bf4b 100644
--- a/include/asm-sh64/io.h
+++ b/include/asm-sh64/io.h
@@ -178,22 +178,6 @@ extern void iounmap(void *addr);
unsigned long onchip_remap(unsigned long addr, unsigned long size, const char* name);
extern void onchip_unmap(unsigned long vaddr);
-static __inline__ int check_signature(volatile void __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
/*
* The caches on some architectures aren't dma-coherent and have need to
* handle this in software. There are three types of operations that
diff --git a/include/asm-sh64/keyboard.h b/include/asm-sh64/keyboard.h
index 1fab96d792bf..0b01c3beb2f8 100644
--- a/include/asm-sh64/keyboard.h
+++ b/include/asm-sh64/keyboard.h
@@ -30,7 +30,6 @@ extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
extern char pckbd_unexpected_up(unsigned char keycode);
extern void pckbd_leds(unsigned char leds);
extern void pckbd_init_hw(void);
-extern unsigned char pckbd_sysrq_xlate[128];
#define kbd_setkeycode pckbd_setkeycode
#define kbd_getkeycode pckbd_getkeycode
@@ -38,9 +37,6 @@ extern unsigned char pckbd_sysrq_xlate[128];
#define kbd_unexpected_up pckbd_unexpected_up
#define kbd_leds pckbd_leds
#define kbd_init_hw pckbd_init_hw
-#define kbd_sysrq_xlate pckbd_sysrq_xlate
-
-#define SYSRQ_KEY 0x54
/* resource allocation */
#define kbd_request_region()
diff --git a/include/asm-sh64/serial.h b/include/asm-sh64/serial.h
index 29c9be15112b..e8d7b3f2da57 100644
--- a/include/asm-sh64/serial.h
+++ b/include/asm-sh64/serial.h
@@ -1,5 +1,5 @@
/*
- * include/asm-sh/serial.h
+ * include/asm-sh64/serial.h
*
* Configuration details for 8250, 16450, 16550, etc. serial ports
*/
diff --git a/include/asm-sh64/timex.h b/include/asm-sh64/timex.h
index af0b79269661..163e2b62fe27 100644
--- a/include/asm-sh64/timex.h
+++ b/include/asm-sh64/timex.h
@@ -17,9 +17,6 @@
#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
-#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
- (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
- << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
typedef unsigned long cycles_t;
diff --git a/include/asm-sh64/unistd.h b/include/asm-sh64/unistd.h
index 9a1590fffc15..ee7828b27ad1 100644
--- a/include/asm-sh64/unistd.h
+++ b/include/asm-sh64/unistd.h
@@ -347,8 +347,10 @@
#ifdef __KERNEL__
#define NR_syscalls 321
+#include <linux/err.h>
-/* user-visible error numbers are in the range -1 - -125: see <asm-sh64/errno.h> */
+/* user-visible error numbers are in the range -1 - -MAX_ERRNO:
+ * see <asm-sh64/errno.h> */
#define __syscall_return(type, res) \
do { \
@@ -358,7 +360,7 @@ do { \
** life easier in the system call epilogue (see entry.S) \
*/ \
register unsigned long __sr2 __asm__ ("r2") = res; \
- if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
errno = -(res); \
__sr2 = -1; \
} \
@@ -511,47 +513,6 @@ __syscall_return(type,__sc0); \
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-/* Copy from sh */
-#include <linux/compiler.h>
-#include <linux/types.h>
-#include <asm/ptrace.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static inline _syscall0(int,pause)
-static inline _syscall1(int,setup,int,magic)
-static inline _syscall0(int,sync)
-static inline _syscall0(pid_t,setsid)
-static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-static inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static inline _syscall1(int,dup,int,fd)
-static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-static inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-static inline _syscall1(int,close,int,fd)
-static inline _syscall1(int,_exit,int,exitcode)
-static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-static inline _syscall1(int,delete_module,const char *,name)
-
-static inline pid_t wait(int * wait_stat)
-{
- return waitpid(-1,wait_stat,0);
-}
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h
index 83a3dd15a6ed..aaf6ef40ee2f 100644
--- a/include/asm-sparc/elf.h
+++ b/include/asm-sparc/elf.h
@@ -8,11 +8,6 @@
#include <asm/ptrace.h>
-#ifdef __KERNEL__
-#include <asm/mbus.h>
-#include <asm/uaccess.h>
-#endif
-
/*
* Sparc section types
*/
@@ -77,6 +72,23 @@ typedef unsigned long elf_greg_t;
#define ELF_NGREG 38
typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+typedef struct {
+ union {
+ unsigned long pr_regs[32];
+ double pr_dregs[16];
+ } pr_fr;
+ unsigned long __unused;
+ unsigned long pr_fsr;
+ unsigned char pr_qcnt;
+ unsigned char pr_q_entrysize;
+ unsigned char pr_en;
+ unsigned int pr_q[64];
+} elf_fpregset_t;
+
+#ifdef __KERNEL__
+#include <asm/mbus.h>
+#include <asm/uaccess.h>
+
/* Format is:
* G0 --> G7
* O0 --> O7
@@ -99,20 +111,7 @@ do { unsigned long *dest = &(__elf_regs[0]); \
dest[34] = src->npc; \
dest[35] = src->y; \
dest[36] = dest[37] = 0; /* XXX */ \
-} while(0); /* Janitors: Don't touch this colon. */
-
-typedef struct {
- union {
- unsigned long pr_regs[32];
- double pr_dregs[16];
- } pr_fr;
- unsigned long __unused;
- unsigned long pr_fsr;
- unsigned char pr_qcnt;
- unsigned char pr_q_entrysize;
- unsigned char pr_en;
- unsigned int pr_q[64];
-} elf_fpregset_t;
+} while(0); /* Janitors: Don't touch this semicolon. */
#define ELF_CORE_COPY_TASK_REGS(__tsk, __elf_regs) \
({ ELF_CORE_COPY_REGS((*(__elf_regs)), (__tsk)->thread.kregs); 1; })
@@ -165,8 +164,8 @@ typedef struct {
#define ELF_PLATFORM (NULL)
-#ifdef __KERNEL__
#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
-#endif
+
+#endif /* __KERNEL__ */
#endif /* !(__ASMSPARC_ELF_H) */
diff --git a/include/asm-sparc/floppy.h b/include/asm-sparc/floppy.h
index c53b332c850a..9073c84218ce 100644
--- a/include/asm-sparc/floppy.h
+++ b/include/asm-sparc/floppy.h
@@ -262,7 +262,7 @@ static __inline__ void sun_fd_enable_dma(void)
}
/* Our low-level entry point in arch/sparc/kernel/entry.S */
-irqreturn_t floppy_hardint(int irq, void *unused, struct pt_regs *regs);
+irqreturn_t floppy_hardint(int irq, void *unused);
static int sun_fd_request_irq(void)
{
diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h
index 3141ddfea97d..ff520ea97473 100644
--- a/include/asm-sparc/irq.h
+++ b/include/asm-sparc/irq.h
@@ -76,8 +76,8 @@ static inline void load_profile_irq(int cpu, int limit)
BTFIXUP_CALL(load_profile_irq)(cpu, limit);
}
-extern void (*sparc_init_timers)(irqreturn_t (*lvl10_irq)(int, void *, struct pt_regs *));
-extern void claim_ticker14(irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
+extern void (*sparc_init_timers)(irq_handler_t lvl10_irq);
+extern void claim_ticker14(irq_handler_t irq_handler,
int irq,
unsigned int timeout);
@@ -91,7 +91,7 @@ BTFIXUPDEF_CALL(void, set_irq_udt, int)
#define set_irq_udt(cpu) BTFIXUP_CALL(set_irq_udt)(cpu)
#endif
-extern int request_fast_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, __const__ char *devname);
+extern int request_fast_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, __const__ char *devname);
/* On the sun4m, just like the timers, we have both per-cpu and master
* interrupt registers.
diff --git a/include/asm-sparc/irq_regs.h b/include/asm-sparc/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-sparc/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-sparc/reg.h b/include/asm-sparc/reg.h
index ed60ebec5930..ea0a7e590bb3 100644
--- a/include/asm-sparc/reg.h
+++ b/include/asm-sparc/reg.h
@@ -1,5 +1,5 @@
/*
- * linux/asm-sparc/reg.h
+ * linux/include/asm-sparc/reg.h
* Layout of the registers as expected by gdb on the Sparc
* we should replace the user.h definitions with those in
* this file, we don't even use the other
diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h
index 1c75474ba1df..de2249b267c6 100644
--- a/include/asm-sparc/spinlock.h
+++ b/include/asm-sparc/spinlock.h
@@ -129,6 +129,7 @@ static inline void __raw_write_lock(raw_rwlock_t *rw)
: /* no outputs */
: "r" (lp)
: "g2", "g4", "memory", "cc");
+ *(volatile __u32 *)&lp->lock = ~0U;
}
static inline int __raw_write_trylock(raw_rwlock_t *rw)
@@ -144,15 +145,44 @@ static inline int __raw_write_trylock(raw_rwlock_t *rw)
val = rw->lock & ~0xff;
if (val)
((volatile u8*)&rw->lock)[3] = 0;
+ else
+ *(volatile u32*)&rw->lock = ~0U;
}
return (val == 0);
}
+static inline int __read_trylock(raw_rwlock_t *rw)
+{
+ register raw_rwlock_t *lp asm("g1");
+ register int res asm("o0");
+ lp = rw;
+ __asm__ __volatile__(
+ "mov %%o7, %%g4\n\t"
+ "call ___rw_read_try\n\t"
+ " ldstub [%%g1 + 3], %%g2\n"
+ : "=r" (res)
+ : "r" (lp)
+ : "g2", "g4", "memory", "cc");
+ return res;
+}
+
+#define __raw_read_trylock(lock) \
+({ unsigned long flags; \
+ int res; \
+ local_irq_save(flags); \
+ res = __read_trylock(lock); \
+ local_irq_restore(flags); \
+ res; \
+})
+
#define __raw_write_unlock(rw) do { (rw)->lock = 0; } while(0)
#define __raw_spin_lock_flags(lock, flags) __raw_spin_lock(lock)
-#define __raw_read_trylock(lock) generic__raw_read_trylock(lock)
+
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
#define __raw_read_can_lock(rw) (!((rw)->lock & 0xff))
#define __raw_write_can_lock(rw) (!(rw)->lock)
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index 2553762465ca..c7a495afc82e 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -478,53 +478,6 @@ return -1; \
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static __inline__ _syscall0(pid_t,setsid)
-static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count)
-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static __inline__ _syscall1(int,dup,int,fd)
-static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp)
-static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode)
-static __inline__ _syscall1(int,close,int,fd)
-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-
-#include <linux/linkage.h>
-
-asmlinkage unsigned long sys_mmap(
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long off);
-asmlinkage unsigned long sys_mmap2(
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- void __user *restorer,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*
diff --git a/include/asm-sparc64/compat_signal.h b/include/asm-sparc64/compat_signal.h
new file mode 100644
index 000000000000..b759eab9b51c
--- /dev/null
+++ b/include/asm-sparc64/compat_signal.h
@@ -0,0 +1,29 @@
+#ifndef _COMPAT_SIGNAL_H
+#define _COMPAT_SIGNAL_H
+
+#include <linux/compat.h>
+#include <asm/signal.h>
+
+#ifdef CONFIG_COMPAT
+struct __new_sigaction32 {
+ unsigned sa_handler;
+ unsigned int sa_flags;
+ unsigned sa_restorer; /* not used by Linux/SPARC yet */
+ compat_sigset_t sa_mask;
+};
+
+struct __old_sigaction32 {
+ unsigned sa_handler;
+ compat_old_sigset_t sa_mask;
+ unsigned int sa_flags;
+ unsigned sa_restorer; /* not used by Linux/SPARC yet */
+};
+
+typedef struct sigaltstack32 {
+ u32 ss_sp;
+ int ss_flags;
+ compat_size_t ss_size;
+} stack_t32;
+#endif
+
+#endif /* !(_COMPAT_SIGNAL_H) */
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index abf150038019..dbe033e494db 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -208,7 +208,7 @@ static void sun_fd_enable_dma(void)
pdma_areasize = pdma_size;
}
-irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
+irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie)
{
if (likely(doing_pdma)) {
void __iomem *stat = (void __iomem *) fdc_status;
@@ -255,7 +255,7 @@ irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
}
main_interrupt:
- return floppy_interrupt(irq, dev_cookie, regs);
+ return floppy_interrupt(irq, dev_cookie);
}
static int sun_fd_request_irq(void)
@@ -311,7 +311,7 @@ struct sun_pci_dma_op {
static struct sun_pci_dma_op sun_pci_dma_current = { -1U, 0, 0, NULL};
static struct sun_pci_dma_op sun_pci_dma_pending = { -1U, 0, 0, NULL};
-extern irqreturn_t floppy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t floppy_interrupt(int irq, void *dev_id);
static unsigned char sun_pci_fd_inb(unsigned long port)
{
@@ -446,7 +446,7 @@ static int sun_pci_fd_eject(int drive)
void sun_pci_fd_dma_callback(struct ebus_dma_info *p, int event, void *cookie)
{
- floppy_interrupt(0, NULL, NULL);
+ floppy_interrupt(0, NULL);
}
/*
diff --git a/include/asm-sparc64/io.h b/include/asm-sparc64/io.h
index 0056770e83ad..30b912d8e8bc 100644
--- a/include/asm-sparc64/io.h
+++ b/include/asm-sparc64/io.h
@@ -440,21 +440,6 @@ _memcpy_toio(volatile void __iomem *dst, const void *src, __kernel_size_t n)
#define memcpy_toio(d,s,sz) _memcpy_toio(d,s,sz)
-static inline int check_signature(void __iomem *io_addr,
- const unsigned char *signature,
- int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature++)
- goto out;
- io_addr++;
- } while (--length);
- retval = 1;
-out:
- return retval;
-}
-
#define mmiowb()
#ifdef __KERNEL__
diff --git a/include/asm-sparc64/irq_regs.h b/include/asm-sparc64/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-sparc64/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h
index 9968871103bc..fa6f467389db 100644
--- a/include/asm-sparc64/signal.h
+++ b/include/asm-sparc64/signal.h
@@ -8,7 +8,6 @@
#ifndef __ASSEMBLY__
#include <linux/personality.h>
#include <linux/types.h>
-#include <linux/compat.h>
#endif
#endif
@@ -167,23 +166,6 @@ struct __new_sigaction {
__new_sigset_t sa_mask;
};
-#ifdef __KERNEL__
-
-#ifdef CONFIG_COMPAT
-struct __new_sigaction32 {
- unsigned sa_handler;
- unsigned int sa_flags;
- unsigned sa_restorer; /* not used by Linux/SPARC yet */
- compat_sigset_t sa_mask;
-};
-#endif
-
-struct k_sigaction {
- struct __new_sigaction sa;
- void __user *ka_restorer;
-};
-#endif
-
struct __old_sigaction {
__sighandler_t sa_handler;
__old_sigset_t sa_mask;
@@ -191,19 +173,6 @@ struct __old_sigaction {
void (*sa_restorer)(void); /* not used by Linux/SPARC yet */
};
-#ifdef __KERNEL__
-
-#ifdef CONFIG_COMPAT
-struct __old_sigaction32 {
- unsigned sa_handler;
- compat_old_sigset_t sa_mask;
- unsigned int sa_flags;
- unsigned sa_restorer; /* not used by Linux/SPARC yet */
-};
-#endif
-
-#endif
-
typedef struct sigaltstack {
void __user *ss_sp;
int ss_flags;
@@ -212,13 +181,10 @@ typedef struct sigaltstack {
#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
-typedef struct sigaltstack32 {
- u32 ss_sp;
- int ss_flags;
- compat_size_t ss_size;
-} stack_t32;
-#endif
+struct k_sigaction {
+ struct __new_sigaction sa;
+ void __user *ka_restorer;
+};
struct signal_deliver_cookie {
int restart_syscall;
diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h
index bd5ffc76bc7e..0006fe9f8c7a 100644
--- a/include/asm-sparc64/spinlock.h
+++ b/include/asm-sparc64/spinlock.h
@@ -241,6 +241,10 @@ static int inline __write_trylock(raw_rwlock_t *lock)
#define __raw_read_can_lock(rw) (!((rw)->lock & 0x80000000UL))
#define __raw_write_can_lock(rw) (!(rw)->lock)
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* !(__ASSEMBLY__) */
#endif /* !(__SPARC64_SPINLOCK_H) */
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index badc73fdcb97..124cf076717f 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -445,48 +445,6 @@ if (__res>=0) \
errno = -__res; \
return -1; \
}
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-static __inline__ _syscall0(pid_t,setsid)
-static __inline__ _syscall3(int,write,int,fd,__const__ char *,buf,off_t,count)
-static __inline__ _syscall3(int,read,int,fd,char *,buf,off_t,count)
-static __inline__ _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-static __inline__ _syscall1(int,dup,int,fd)
-static __inline__ _syscall3(int,execve,__const__ char *,file,char **,argv,char **,envp)
-static __inline__ _syscall3(int,open,__const__ char *,file,int,flag,int,mode)
-static __inline__ _syscall1(int,close,int,fd)
-static __inline__ _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-
-#include <linux/linkage.h>
-
-asmlinkage unsigned long sys_mmap(
- unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long off);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- void __user *restorer,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
/* sysconf options, for SunOS compatibility */
#define _SC_ARG_MAX 1
diff --git a/include/asm-um/archparam-ppc.h b/include/asm-um/archparam-ppc.h
index 172cd6ffacc4..4269d8a37b4f 100644
--- a/include/asm-um/archparam-ppc.h
+++ b/include/asm-um/archparam-ppc.h
@@ -1,15 +1,6 @@
#ifndef __UM_ARCHPARAM_PPC_H
#define __UM_ARCHPARAM_PPC_H
-/********* Bits for asm-um/hw_irq.h **********/
-
-struct hw_interrupt_type;
-
-/********* Bits for asm-um/hardirq.h **********/
-
-#define irq_enter(cpu, irq) hardirq_enter(cpu)
-#define irq_exit(cpu, irq) hardirq_exit(cpu)
-
/********* Bits for asm-um/string.h **********/
#define __HAVE_ARCH_STRRCHR
diff --git a/include/asm-um/irq_regs.h b/include/asm-um/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-um/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
index 4862daf8b906..188f72621776 100644
--- a/include/asm-um/pgtable.h
+++ b/include/asm-um/pgtable.h
@@ -274,12 +274,6 @@ static inline pte_t pte_mkread(pte_t pte)
return(pte_mknewprot(pte));
}
-static inline pte_t pte_mkexec(pte_t pte)
-{
- pte_set_bits(pte, _PAGE_USER);
- return(pte_mknewprot(pte));
-}
-
static inline pte_t pte_mkdirty(pte_t pte)
{
pte_set_bits(pte, _PAGE_DIRTY);
diff --git a/include/asm-um/processor-generic.h b/include/asm-um/processor-generic.h
index afa4fe1ca9f1..d99bbddffdb9 100644
--- a/include/asm-um/processor-generic.h
+++ b/include/asm-um/processor-generic.h
@@ -13,6 +13,7 @@ struct task_struct;
#include "asm/ptrace.h"
#include "choose-mode.h"
#include "registers.h"
+#include "sysdep/archsetjmp.h"
struct mm_struct;
@@ -43,8 +44,7 @@ struct thread_struct {
#endif
#ifdef CONFIG_MODE_SKAS
struct {
- void *switch_buf;
- void *fork_buf;
+ jmp_buf switch_buf;
int mm_count;
} skas;
#endif
@@ -138,7 +138,7 @@ extern struct cpuinfo_um cpu_data[];
#ifdef CONFIG_MODE_SKAS
#define KSTK_REG(tsk, reg) \
- get_thread_reg(reg, tsk->thread.mode.skas.switch_buf)
+ get_thread_reg(reg, &tsk->thread.mode.skas.switch_buf)
#else
#define KSTK_REG(tsk, reg) (0xbadbabe)
#endif
diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h
index 2074483e6ca4..03b4af4ac09a 100644
--- a/include/asm-um/ptrace-x86_64.h
+++ b/include/asm-um/ptrace-x86_64.h
@@ -16,12 +16,15 @@
#define HOST_AUDIT_ARCH AUDIT_ARCH_X86_64
+/* Also defined in sysdep/ptrace.h, so may already be defined. */
+#ifndef FS_BASE
#define FS_BASE (21 * sizeof(unsigned long))
#define GS_BASE (22 * sizeof(unsigned long))
#define DS (23 * sizeof(unsigned long))
#define ES (24 * sizeof(unsigned long))
#define FS (25 * sizeof(unsigned long))
#define GS (26 * sizeof(unsigned long))
+#endif
#define PT_REGS_RBX(r) UPT_RBX(&(r)->regs)
#define PT_REGS_RCX(r) UPT_RCX(&(r)->regs)
diff --git a/include/asm-um/unistd.h b/include/asm-um/unistd.h
index afccfcaa9ea9..732c83f04c3d 100644
--- a/include/asm-um/unistd.h
+++ b/include/asm-um/unistd.h
@@ -37,34 +37,6 @@ extern int um_execve(const char *file, char *const argv[], char *const env[]);
#define __ARCH_WANT_SYS_RT_SIGSUSPEND
#endif
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-
-static inline int execve(const char *filename, char *const argv[],
- char *const envp[])
-{
- mm_segment_t fs;
- int ret;
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- ret = um_execve(filename, argv, envp);
- set_fs(fs);
-
- if (ret >= 0)
- return ret;
-
- errno = -(long)ret;
- return -1;
-}
-
-int sys_execve(char *file, char **argv, char **env);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
-#undef __KERNEL_SYSCALLS__
#include "asm/arch/unistd.h"
#endif /* _UM_UNISTD_H_*/
diff --git a/include/asm-v850/unistd.h b/include/asm-v850/unistd.h
index bcb44bfe577a..737401e7d3ad 100644
--- a/include/asm-v850/unistd.h
+++ b/include/asm-v850/unistd.h
@@ -238,12 +238,13 @@
#ifdef __KERNEL__
#include <asm/clinkage.h>
+#include <linux/err.h>
#define __syscall_return(type, res) \
do { \
- /* user-visible error numbers are in the range -1 - -124: \
+ /* user-visible error numbers are in the range -1 - -MAX_ERRNO: \
see <asm-v850/errno.h> */ \
- if (__builtin_expect ((unsigned long)(res) >= (unsigned long)(-125), 0)) { \
+ if (__builtin_expect ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO), 0)) { \
errno = -(res); \
res = -1; \
} \
@@ -386,57 +387,6 @@ type name (atype a, btype b, ctype c, dtype d, etype e, ftype f) \
#define __ARCH_WANT_SYS_SIGPROCMASK
#define __ARCH_WANT_SYS_RT_SIGACTION
-#ifdef __KERNEL_SYSCALLS__
-
-#include <linux/compiler.h>
-#include <linux/types.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-extern inline _syscall0(pid_t,setsid)
-extern inline _syscall3(int,write,int,fd,const char *,buf,off_t,count)
-extern inline _syscall3(int,read,int,fd,char *,buf,off_t,count)
-extern inline _syscall3(off_t,lseek,int,fd,off_t,offset,int,count)
-extern inline _syscall1(int,dup,int,fd)
-extern inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp)
-extern inline _syscall3(int,open,const char *,file,int,flag,int,mode)
-extern inline _syscall1(int,close,int,fd)
-extern inline _syscall1(int,_exit,int,exitcode)
-extern inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options)
-
-extern inline pid_t wait(int * wait_stat)
-{
- return waitpid (-1, wait_stat, 0);
-}
-
-unsigned long sys_mmap(unsigned long addr, size_t len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, off_t offset);
-unsigned long sys_mmap2(unsigned long addr, size_t len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long pgoff);
-struct pt_regs;
-int sys_execve (char *name, char **argv, char **envp, struct pt_regs *regs);
-int sys_pipe (int *fildes);
-struct sigaction;
-asmlinkage long sys_rt_sigaction(int sig,
- const struct sigaction __user *act,
- struct sigaction __user *oact,
- size_t sigsetsize);
-
-#endif /* __KERNEL_SYSCALLS__ */
-
/*
* "Conditional" syscalls
*/
diff --git a/include/asm-x86_64/alternative-asm.i b/include/asm-x86_64/alternative-asm.i
index e4041f4fa4dc..0b3f1a2bb2cb 100644
--- a/include/asm-x86_64/alternative-asm.i
+++ b/include/asm-x86_64/alternative-asm.i
@@ -1,5 +1,3 @@
-#include <linux/config.h>
-
#ifdef CONFIG_SMP
.macro LOCK_PREFIX
1: lock
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index 9e66d32330c9..e81d0f289f0b 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -77,7 +77,7 @@ extern void sync_Arb_IDs (void);
extern void init_bsp_APIC (void);
extern void setup_local_APIC (void);
extern void init_apic_mappings (void);
-extern void smp_local_timer_interrupt (struct pt_regs * regs);
+extern void smp_local_timer_interrupt (void);
extern void setup_boot_APIC_clock (void);
extern void setup_secondary_APIC_clock (void);
extern int APIC_init_uniprocessor (void);
diff --git a/include/asm-x86_64/cache.h b/include/asm-x86_64/cache.h
index ed8a9d25272d..052df758ae61 100644
--- a/include/asm-x86_64/cache.h
+++ b/include/asm-x86_64/cache.h
@@ -1,5 +1,5 @@
/*
- * include/asm-x8664/cache.h
+ * include/asm-x86_64/cache.h
*/
#ifndef __ARCH_X8664_CACHE_H
#define __ARCH_X8664_CACHE_H
diff --git a/include/asm-x86_64/dma-mapping.h b/include/asm-x86_64/dma-mapping.h
index b6da83dcc7a6..10174b110a5c 100644
--- a/include/asm-x86_64/dma-mapping.h
+++ b/include/asm-x86_64/dma-mapping.h
@@ -55,13 +55,6 @@ extern dma_addr_t bad_dma_address;
extern struct dma_mapping_ops* dma_ops;
extern int iommu_merge;
-static inline int valid_dma_direction(int dma_direction)
-{
- return ((dma_direction == DMA_BIDIRECTIONAL) ||
- (dma_direction == DMA_TO_DEVICE) ||
- (dma_direction == DMA_FROM_DEVICE));
-}
-
static inline int dma_mapping_error(dma_addr_t dma_addr)
{
if (dma_ops->mapping_error)
diff --git a/include/asm-x86_64/e820.h b/include/asm-x86_64/e820.h
index e15d3c8628f3..fa2086774105 100644
--- a/include/asm-x86_64/e820.h
+++ b/include/asm-x86_64/e820.h
@@ -47,10 +47,9 @@ extern void e820_print_map(char *who);
extern int e820_any_mapped(unsigned long start, unsigned long end, unsigned type);
extern int e820_all_mapped(unsigned long start, unsigned long end, unsigned type);
-extern void e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end);
extern void e820_setup_gap(void);
-extern unsigned long e820_hole_size(unsigned long start_pfn,
- unsigned long end_pfn);
+extern void e820_register_active_regions(int nid,
+ unsigned long start_pfn, unsigned long end_pfn);
extern void finish_e820_parsing(void);
diff --git a/include/asm-x86_64/floppy.h b/include/asm-x86_64/floppy.h
index 32ff5d132714..6ea13c3806f3 100644
--- a/include/asm-x86_64/floppy.h
+++ b/include/asm-x86_64/floppy.h
@@ -51,7 +51,7 @@ static char *virtual_dma_addr;
static int virtual_dma_mode;
static int doing_pdma;
-static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t floppy_hardint(int irq, void *dev_id)
{
register unsigned char st;
@@ -63,7 +63,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
static int dma_wait=0;
#endif
if (!doing_pdma)
- return floppy_interrupt(irq, dev_id, regs);
+ return floppy_interrupt(irq, dev_id);
#ifdef TRACE_FLPY_INT
if(!calls)
@@ -106,7 +106,7 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
dma_wait=0;
#endif
doing_pdma = 0;
- floppy_interrupt(irq, dev_id, regs);
+ floppy_interrupt(irq, dev_id);
return IRQ_HANDLED;
}
#ifdef TRACE_FLPY_INT
diff --git a/include/asm-x86_64/genapic.h b/include/asm-x86_64/genapic.h
index 81e714665344..a0e9a4b93484 100644
--- a/include/asm-x86_64/genapic.h
+++ b/include/asm-x86_64/genapic.h
@@ -18,6 +18,7 @@ struct genapic {
u32 int_dest_mode;
int (*apic_id_registered)(void);
cpumask_t (*target_cpus)(void);
+ cpumask_t (*vector_allocation_domain)(int cpu);
void (*init_apic_ldr)(void);
/* ipi */
void (*send_IPI_mask)(cpumask_t mask, int vector);
diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
index 64a65ce2f41f..95d5e090ed89 100644
--- a/include/asm-x86_64/hardirq.h
+++ b/include/asm-x86_64/hardirq.h
@@ -6,6 +6,9 @@
#include <asm/pda.h>
#include <asm/apic.h>
+/* We can have at most NR_VECTORS irqs routed to a cpu at a time */
+#define MAX_HARDIRQS_PER_CPU NR_VECTORS
+
#define __ARCH_IRQ_STAT 1
#define local_softirq_pending() read_pda(__softirq_pending)
diff --git a/include/asm-x86_64/hw_irq.h b/include/asm-x86_64/hw_irq.h
index 48a4a5364e85..792dd52fcd70 100644
--- a/include/asm-x86_64/hw_irq.h
+++ b/include/asm-x86_64/hw_irq.h
@@ -19,8 +19,7 @@
#include <asm/irq.h>
#include <linux/profile.h>
#include <linux/smp.h>
-
-struct hw_interrupt_type;
+#include <linux/percpu.h>
#endif
#define NMI_VECTOR 0x02
@@ -75,9 +74,8 @@ struct hw_interrupt_type;
#ifndef __ASSEMBLY__
-extern u8 irq_vector[NR_IRQ_VECTORS];
-#define IO_APIC_VECTOR(irq) (irq_vector[irq])
-#define AUTO_ASSIGN -1
+typedef int vector_irq_t[NR_VECTORS];
+DECLARE_PER_CPU(vector_irq_t, vector_irq);
/*
* Various low-level irq details needed by irq.c, process.c,
diff --git a/include/asm-x86_64/hypertransport.h b/include/asm-x86_64/hypertransport.h
new file mode 100644
index 000000000000..c16c6ff4bdd7
--- /dev/null
+++ b/include/asm-x86_64/hypertransport.h
@@ -0,0 +1,42 @@
+#ifndef ASM_HYPERTRANSPORT_H
+#define ASM_HYPERTRANSPORT_H
+
+/*
+ * Constants for x86 Hypertransport Interrupts.
+ */
+
+#define HT_IRQ_LOW_BASE 0xf8000000
+
+#define HT_IRQ_LOW_VECTOR_SHIFT 16
+#define HT_IRQ_LOW_VECTOR_MASK 0x00ff0000
+#define HT_IRQ_LOW_VECTOR(v) (((v) << HT_IRQ_LOW_VECTOR_SHIFT) & HT_IRQ_LOW_VECTOR_MASK)
+
+#define HT_IRQ_LOW_DEST_ID_SHIFT 8
+#define HT_IRQ_LOW_DEST_ID_MASK 0x0000ff00
+#define HT_IRQ_LOW_DEST_ID(v) (((v) << HT_IRQ_LOW_DEST_ID_SHIFT) & HT_IRQ_LOW_DEST_ID_MASK)
+
+#define HT_IRQ_LOW_DM_PHYSICAL 0x0000000
+#define HT_IRQ_LOW_DM_LOGICAL 0x0000040
+
+#define HT_IRQ_LOW_RQEOI_EDGE 0x0000000
+#define HT_IRQ_LOW_RQEOI_LEVEL 0x0000020
+
+
+#define HT_IRQ_LOW_MT_FIXED 0x0000000
+#define HT_IRQ_LOW_MT_ARBITRATED 0x0000004
+#define HT_IRQ_LOW_MT_SMI 0x0000008
+#define HT_IRQ_LOW_MT_NMI 0x000000c
+#define HT_IRQ_LOW_MT_INIT 0x0000010
+#define HT_IRQ_LOW_MT_STARTUP 0x0000014
+#define HT_IRQ_LOW_MT_EXTINT 0x0000018
+#define HT_IRQ_LOW_MT_LINT1 0x000008c
+#define HT_IRQ_LOW_MT_LINT0 0x0000098
+
+#define HT_IRQ_LOW_IRQ_MASKED 0x0000001
+
+
+#define HT_IRQ_HIGH_DEST_ID_SHIFT 0
+#define HT_IRQ_HIGH_DEST_ID_MASK 0x00ffffff
+#define HT_IRQ_HIGH_DEST_ID(v) ((((v) >> 8) << HT_IRQ_HIGH_DEST_ID_SHIFT) & HT_IRQ_HIGH_DEST_ID_MASK)
+
+#endif /* ASM_HYPERTRANSPORT_H */
diff --git a/include/asm-x86_64/io.h b/include/asm-x86_64/io.h
index 70e91fe76344..6ee9fadaaacb 100644
--- a/include/asm-x86_64/io.h
+++ b/include/asm-x86_64/io.h
@@ -254,33 +254,6 @@ void memset_io(volatile void __iomem *a, int b, size_t c);
#define eth_io_copy_and_sum(a,b,c,d) eth_copy_and_sum((a),(void *)(b),(c),(d))
-/**
- * check_signature - find BIOS signatures
- * @io_addr: mmio address to check
- * @signature: signature block
- * @length: length of signature
- *
- * Perform a signature comparison with the mmio address io_addr. This
- * address should have been obtained by ioremap.
- * Returns 1 on a match.
- */
-
-static inline int check_signature(void __iomem *io_addr,
- const unsigned char *signature, int length)
-{
- int retval = 0;
- do {
- if (readb(io_addr) != *signature)
- goto out;
- io_addr++;
- signature++;
- length--;
- } while (length);
- retval = 1;
-out:
- return retval;
-}
-
/* Nothing to do */
#define dma_cache_inv(_start,_size) do { } while (0)
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
index 5d1b5c68e36e..171ec2dc8c04 100644
--- a/include/asm-x86_64/io_apic.h
+++ b/include/asm-x86_64/io_apic.h
@@ -10,46 +10,6 @@
* Copyright (C) 1997, 1998, 1999, 2000 Ingo Molnar
*/
-#ifdef CONFIG_PCI_MSI
-static inline int use_pci_vector(void) {return 1;}
-static inline void disable_edge_ioapic_vector(unsigned int vector) { }
-static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
-static inline void end_edge_ioapic_vector (unsigned int vector) { }
-#define startup_level_ioapic startup_level_ioapic_vector
-#define shutdown_level_ioapic mask_IO_APIC_vector
-#define enable_level_ioapic unmask_IO_APIC_vector
-#define disable_level_ioapic mask_IO_APIC_vector
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_vector
-#define end_level_ioapic end_level_ioapic_vector
-#define set_ioapic_affinity set_ioapic_affinity_vector
-
-#define startup_edge_ioapic startup_edge_ioapic_vector
-#define shutdown_edge_ioapic disable_edge_ioapic_vector
-#define enable_edge_ioapic unmask_IO_APIC_vector
-#define disable_edge_ioapic disable_edge_ioapic_vector
-#define ack_edge_ioapic ack_edge_ioapic_vector
-#define end_edge_ioapic end_edge_ioapic_vector
-#else
-static inline int use_pci_vector(void) {return 0;}
-static inline void disable_edge_ioapic_irq(unsigned int irq) { }
-static inline void mask_and_ack_level_ioapic_irq(unsigned int irq) { }
-static inline void end_edge_ioapic_irq (unsigned int irq) { }
-#define startup_level_ioapic startup_level_ioapic_irq
-#define shutdown_level_ioapic mask_IO_APIC_irq
-#define enable_level_ioapic unmask_IO_APIC_irq
-#define disable_level_ioapic mask_IO_APIC_irq
-#define mask_and_ack_level_ioapic mask_and_ack_level_ioapic_irq
-#define end_level_ioapic end_level_ioapic_irq
-#define set_ioapic_affinity set_ioapic_affinity_irq
-
-#define startup_edge_ioapic startup_edge_ioapic_irq
-#define shutdown_edge_ioapic disable_edge_ioapic_irq
-#define enable_edge_ioapic unmask_IO_APIC_irq
-#define disable_edge_ioapic disable_edge_ioapic_irq
-#define ack_edge_ioapic ack_edge_ioapic_irq
-#define end_edge_ioapic end_edge_ioapic_irq
-#endif
-
#define APIC_MISMATCH_DEBUG
#define IO_APIC_BASE(idx) \
@@ -202,13 +162,10 @@ extern int skip_ioapic_setup;
extern int io_apic_get_version (int ioapic);
extern int io_apic_get_redir_entries (int ioapic);
extern int io_apic_set_pci_routing (int ioapic, int pin, int irq, int, int);
-extern int timer_uses_ioapic_pin_0;
#endif
extern int sis_apic_bug; /* dummy */
-extern int assign_irq_vector(int irq);
-
void enable_NMI_through_LVT0 (void * dummy);
extern spinlock_t i8259A_lock;
diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h
index 43469d8ab71a..5006c6e75656 100644
--- a/include/asm-x86_64/irq.h
+++ b/include/asm-x86_64/irq.h
@@ -31,13 +31,8 @@
#define FIRST_SYSTEM_VECTOR 0xef /* duplicated in hw_irq.h */
-#ifdef CONFIG_PCI_MSI
-#define NR_IRQS FIRST_SYSTEM_VECTOR
+#define NR_IRQS (NR_VECTORS + (32 *NR_CPUS))
#define NR_IRQ_VECTORS NR_IRQS
-#else
-#define NR_IRQS 224
-#define NR_IRQ_VECTORS (32 * NR_CPUS)
-#endif
static __inline__ int irq_canonicalize(int irq)
{
diff --git a/include/asm-x86_64/irq_regs.h b/include/asm-x86_64/irq_regs.h
new file mode 100644
index 000000000000..3dd9c0b70270
--- /dev/null
+++ b/include/asm-x86_64/irq_regs.h
@@ -0,0 +1 @@
+#include <asm-generic/irq_regs.h>
diff --git a/include/asm-x86_64/mach_apic.h b/include/asm-x86_64/mach_apic.h
index d33422450c00..7b7115a0c1c9 100644
--- a/include/asm-x86_64/mach_apic.h
+++ b/include/asm-x86_64/mach_apic.h
@@ -17,6 +17,7 @@
#define INT_DELIVERY_MODE (genapic->int_delivery_mode)
#define INT_DEST_MODE (genapic->int_dest_mode)
#define TARGET_CPUS (genapic->target_cpus())
+#define vector_allocation_domain (genapic->vector_allocation_domain)
#define apic_id_registered (genapic->apic_id_registered)
#define init_apic_ldr (genapic->init_apic_ldr)
#define send_IPI_mask (genapic->send_IPI_mask)
diff --git a/include/asm-x86_64/msi.h b/include/asm-x86_64/msi.h
deleted file mode 100644
index 3ad2346624b2..000000000000
--- a/include/asm-x86_64/msi.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2003-2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
- */
-
-#ifndef ASM_MSI_H
-#define ASM_MSI_H
-
-#include <asm/desc.h>
-#include <asm/mach_apic.h>
-#include <asm/smp.h>
-
-#define LAST_DEVICE_VECTOR (FIRST_SYSTEM_VECTOR - 1)
-#define MSI_TARGET_CPU_SHIFT 12
-
-extern struct msi_ops msi_apic_ops;
-
-static inline int msi_arch_init(void)
-{
- msi_register(&msi_apic_ops);
- return 0;
-}
-
-#endif /* ASM_MSI_H */
diff --git a/include/asm-x86_64/msidef.h b/include/asm-x86_64/msidef.h
new file mode 100644
index 000000000000..5b8acddb70fb
--- /dev/null
+++ b/include/asm-x86_64/msidef.h
@@ -0,0 +1,47 @@
+#ifndef ASM_MSIDEF_H
+#define ASM_MSIDEF_H
+
+/*
+ * Constants for Intel APIC based MSI messages.
+ */
+
+/*
+ * Shifts for MSI data
+ */
+
+#define MSI_DATA_VECTOR_SHIFT 0
+#define MSI_DATA_VECTOR_MASK 0x000000ff
+#define MSI_DATA_VECTOR(v) (((v) << MSI_DATA_VECTOR_SHIFT) & MSI_DATA_VECTOR_MASK)
+
+#define MSI_DATA_DELIVERY_MODE_SHIFT 8
+#define MSI_DATA_DELIVERY_FIXED (0 << MSI_DATA_DELIVERY_MODE_SHIFT)
+#define MSI_DATA_DELIVERY_LOWPRI (1 << MSI_DATA_DELIVERY_MODE_SHIFT)
+
+#define MSI_DATA_LEVEL_SHIFT 14
+#define MSI_DATA_LEVEL_DEASSERT (0 << MSI_DATA_LEVEL_SHIFT)
+#define MSI_DATA_LEVEL_ASSERT (1 << MSI_DATA_LEVEL_SHIFT)
+
+#define MSI_DATA_TRIGGER_SHIFT 15
+#define MSI_DATA_TRIGGER_EDGE (0 << MSI_DATA_TRIGGER_SHIFT)
+#define MSI_DATA_TRIGGER_LEVEL (1 << MSI_DATA_TRIGGER_SHIFT)
+
+/*
+ * Shift/mask fields for msi address
+ */
+
+#define MSI_ADDR_BASE_HI 0
+#define MSI_ADDR_BASE_LO 0xfee00000
+
+#define MSI_ADDR_DEST_MODE_SHIFT 2
+#define MSI_ADDR_DEST_MODE_PHYSICAL (0 << MSI_ADDR_DEST_MODE_SHIFT)
+#define MSI_ADDR_DEST_MODE_LOGICAL (1 << MSI_ADDR_DEST_MODE_SHIFT)
+
+#define MSI_ADDR_REDIRECTION_SHIFT 3
+#define MSI_ADDR_REDIRECTION_CPU (0 << MSI_ADDR_REDIRECTION_SHIFT) /* dedicated cpu */
+#define MSI_ADDR_REDIRECTION_LOWPRI (1 << MSI_ADDR_REDIRECTION_SHIFT) /* lowest priority */
+
+#define MSI_ADDR_DEST_ID_SHIFT 12
+#define MSI_ADDR_DEST_ID_MASK 0x00ffff0
+#define MSI_ADDR_DEST_ID(dest) (((dest) << MSI_ADDR_DEST_ID_SHIFT) & MSI_ADDR_DEST_ID_MASK)
+
+#endif /* ASM_MSIDEF_H */
diff --git a/include/asm-x86_64/nmi.h b/include/asm-x86_64/nmi.h
index cbf2669bca71..f367d4014b42 100644
--- a/include/asm-x86_64/nmi.h
+++ b/include/asm-x86_64/nmi.h
@@ -70,4 +70,11 @@ extern unsigned int nmi_watchdog;
#define NMI_LOCAL_APIC 2
#define NMI_INVALID 3
+struct ctl_table;
+struct file;
+extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
+ void __user *, size_t *, loff_t *);
+
+extern int unknown_nmi_panic;
+
#endif /* ASM_NMI_H */
diff --git a/include/asm-x86_64/percpu.h b/include/asm-x86_64/percpu.h
index 285756010c51..5ed0ef340842 100644
--- a/include/asm-x86_64/percpu.h
+++ b/include/asm-x86_64/percpu.h
@@ -32,13 +32,13 @@
/* var is in discarded region: offset to particular copy we want */
#define per_cpu(var, cpu) (*({ \
- extern int simple_indentifier_##var(void); \
+ extern int simple_identifier_##var(void); \
RELOC_HIDE(&per_cpu__##var, __per_cpu_offset(cpu)); }))
#define __get_cpu_var(var) (*({ \
- extern int simple_indentifier_##var(void); \
+ extern int simple_identifier_##var(void); \
RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()); }))
#define __raw_get_cpu_var(var) (*({ \
- extern int simple_indentifier_##var(void); \
+ extern int simple_identifier_##var(void); \
RELOC_HIDE(&per_cpu__##var, __my_cpu_offset()); }))
/* A macro to avoid #include hell... */
diff --git a/include/asm-x86_64/pgtable.h b/include/asm-x86_64/pgtable.h
index 6899e770b173..0555c1c4d8fa 100644
--- a/include/asm-x86_64/pgtable.h
+++ b/include/asm-x86_64/pgtable.h
@@ -366,6 +366,7 @@ static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot)
{
pte_t pte;
pte_val(pte) = physpage | pgprot_val(pgprot);
+ pte_val(pte) &= __supported_pte_mask;
return pte;
}
diff --git a/include/asm-x86_64/processor.h b/include/asm-x86_64/processor.h
index de9c3147ee4c..cef17e0f828c 100644
--- a/include/asm-x86_64/processor.h
+++ b/include/asm-x86_64/processor.h
@@ -475,6 +475,8 @@ static inline void __mwait(unsigned long eax, unsigned long ecx)
: :"a" (eax), "c" (ecx));
}
+extern void mwait_idle_with_hints(unsigned long eax, unsigned long ecx);
+
#define stack_current() \
({ \
struct thread_info *ti; \
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index b73d0c76613c..e72cfcdf5344 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -24,8 +24,6 @@ extern void mtrr_bp_init(void);
#define mtrr_bp_init() do {} while (0)
#endif
extern void init_memory_mapping(unsigned long start, unsigned long end);
-extern void size_zones(unsigned long *z, unsigned long *h,
- unsigned long start_pfn, unsigned long end_pfn);
extern void system_call(void);
extern int kernel_syscall(void);
@@ -68,7 +66,7 @@ extern void free_bootmem_generic(unsigned long phys, unsigned len);
extern void load_gs_index(unsigned gs);
extern void stop_timer_interrupt(void);
-extern void main_timer_handler(struct pt_regs *regs);
+extern void main_timer_handler(void);
extern unsigned long end_pfn_map;
@@ -124,9 +122,11 @@ extern int fix_aperture;
extern int reboot_force;
extern int notsc_setup(char *);
+extern int timer_over_8254;
+
extern int gsi_irq_sharing(int gsi);
-extern void smp_local_timer_interrupt(struct pt_regs * regs);
+extern void smp_local_timer_interrupt(void);
long do_arch_prctl(struct task_struct *task, int code, unsigned long addr);
diff --git a/include/asm-x86_64/ptrace.h b/include/asm-x86_64/ptrace.h
index ab827dc381d7..5ea84dbb1e9c 100644
--- a/include/asm-x86_64/ptrace.h
+++ b/include/asm-x86_64/ptrace.h
@@ -39,6 +39,8 @@ struct pt_regs {
#define user_mode(regs) (!!((regs)->cs & 3))
#define user_mode_vm(regs) user_mode(regs)
#define instruction_pointer(regs) ((regs)->rip)
+#define regs_return_value(regs) ((regs)->rax)
+
extern unsigned long profile_pc(struct pt_regs *regs);
void signal_fault(struct pt_regs *regs, void __user *frame, char *where);
diff --git a/include/asm-x86_64/semaphore.h b/include/asm-x86_64/semaphore.h
index 107bd90429e8..1194888536b9 100644
--- a/include/asm-x86_64/semaphore.h
+++ b/include/asm-x86_64/semaphore.h
@@ -132,7 +132,7 @@ static inline int down_interruptible(struct semaphore * sem)
"jns 2f\n\t"
"call __down_failed_interruptible\n"
"2:\n"
- :"=a" (result), "=m" (sem->count)
+ :"=&a" (result), "=m" (sem->count)
:"D" (sem)
:"memory");
return result;
@@ -153,7 +153,7 @@ static inline int down_trylock(struct semaphore * sem)
"jns 2f\n\t"
"call __down_failed_trylock\n\t"
"2:\n"
- :"=a" (result), "=m" (sem->count)
+ :"=&a" (result), "=m" (sem->count)
:"D" (sem)
:"memory","cc");
return result;
diff --git a/include/asm-x86_64/spinlock.h b/include/asm-x86_64/spinlock.h
index be7a9e629fb2..05ef097ba55b 100644
--- a/include/asm-x86_64/spinlock.h
+++ b/include/asm-x86_64/spinlock.h
@@ -4,6 +4,7 @@
#include <asm/atomic.h>
#include <asm/rwlock.h>
#include <asm/page.h>
+#include <asm/processor.h>
/*
* Your basic SMP spinlocks, allowing only a single CPU anywhere
@@ -132,4 +133,8 @@ static inline void __raw_write_unlock(raw_rwlock_t *rw)
: "=m" (rw->lock) : : "memory");
}
+#define _raw_spin_relax(lock) cpu_relax()
+#define _raw_read_relax(lock) cpu_relax()
+#define _raw_write_relax(lock) cpu_relax()
+
#endif /* __ASM_SPINLOCK_H */
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 6e7a2e976b04..5c8f49280dbc 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -31,6 +31,7 @@ extern int __node_distance(int, int);
#define SD_NODE_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 8, \
.max_interval = 32, \
diff --git a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h
index e856570c0689..19f99178fe83 100644
--- a/include/asm-x86_64/uaccess.h
+++ b/include/asm-x86_64/uaccess.h
@@ -361,6 +361,11 @@ __must_check unsigned long clear_user(void __user *mem, unsigned long len);
__must_check unsigned long __clear_user(void __user *mem, unsigned long len);
__must_check long __copy_from_user_inatomic(void *dst, const void __user *src, unsigned size);
-#define __copy_to_user_inatomic copy_user_generic
+
+static __must_check __always_inline int
+__copy_to_user_inatomic(void __user *dst, const void *src, unsigned size)
+{
+ return copy_user_generic((__force void *)dst, src, size);
+}
#endif /* __X86_64_UACCESS_H */
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index eeb98c168e98..777288eb7e75 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -620,19 +620,21 @@ __SYSCALL(__NR_vmsplice, sys_vmsplice)
#define __NR_move_pages 279
__SYSCALL(__NR_move_pages, sys_move_pages)
-#ifdef __KERNEL__
-
#define __NR_syscall_max __NR_move_pages
+#ifdef __KERNEL__
+#include <linux/err.h>
+#endif
+
#ifndef __NO_STUBS
-/* user-visible error numbers are in the range -1 - -4095 */
+/* user-visible error numbers are in the range -1 - -MAX_ERRNO */
#define __syscall_clobber "r11","rcx","memory"
#define __syscall_return(type, res) \
do { \
- if ((unsigned long)(res) >= (unsigned long)(-127)) { \
+ if ((unsigned long)(res) >= (unsigned long)(-MAX_ERRNO)) { \
errno = -(res); \
res = -1; \
} \
@@ -662,8 +664,6 @@ do { \
#define __ARCH_WANT_SYS_TIME
#define __ARCH_WANT_COMPAT_SYS_TIME
-#ifndef __KERNEL_SYSCALLS__
-
#define __syscall "syscall"
#define _syscall0(type,name) \
@@ -745,83 +745,7 @@ __asm__ volatile ("movq %5,%%r10 ; movq %6,%%r8 ; movq %7,%%r9 ; " __syscall \
__syscall_return(type,__res); \
}
-#else /* __KERNEL_SYSCALLS__ */
-
-#include <linux/syscalls.h>
-#include <asm/ptrace.h>
-
-/*
- * we need this inline - forking from kernel space will result
- * in NO COPY ON WRITE (!!!), until an execve is executed. This
- * is no problem, but for the stack. This is handled by not letting
- * main() use the stack at all after fork(). Thus, no function
- * calls - which means inline code for fork too, as otherwise we
- * would use the stack upon exit from 'fork()'.
- *
- * Actually only pause and fork are needed inline, so that there
- * won't be any messing with the stack from main(), but we define
- * some others too.
- */
-#define __NR__exit __NR_exit
-
-static inline pid_t setsid(void)
-{
- return sys_setsid();
-}
-
-static inline ssize_t write(unsigned int fd, char * buf, size_t count)
-{
- return sys_write(fd, buf, count);
-}
-
-static inline ssize_t read(unsigned int fd, char * buf, size_t count)
-{
- return sys_read(fd, buf, count);
-}
-
-static inline off_t lseek(unsigned int fd, off_t offset, unsigned int origin)
-{
- return sys_lseek(fd, offset, origin);
-}
-
-static inline long dup(unsigned int fd)
-{
- return sys_dup(fd);
-}
-
-/* implemented in asm in arch/x86_64/kernel/entry.S */
-extern int execve(const char *, char * const *, char * const *);
-
-static inline long open(const char * filename, int flags, int mode)
-{
- return sys_open(filename, flags, mode);
-}
-
-static inline long close(unsigned int fd)
-{
- return sys_close(fd);
-}
-
-static inline pid_t waitpid(int pid, int * wait_stat, int flags)
-{
- return sys_wait4(pid, wait_stat, flags, NULL);
-}
-
-extern long sys_mmap(unsigned long addr, unsigned long len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, unsigned long off);
-
-extern int sys_modify_ldt(int func, void *ptr, unsigned long bytecount);
-
-asmlinkage long sys_execve(char *name, char **argv, char **envp,
- struct pt_regs regs);
-asmlinkage long sys_clone(unsigned long clone_flags, unsigned long newsp,
- void *parent_tid, void *child_tid,
- struct pt_regs regs);
-asmlinkage long sys_fork(struct pt_regs regs);
-asmlinkage long sys_vfork(struct pt_regs regs);
-asmlinkage long sys_pipe(int *fildes);
-
+#ifdef __KERNEL__
#ifndef __ASSEMBLY__
#include <linux/linkage.h>
@@ -838,8 +762,8 @@ asmlinkage long sys_rt_sigaction(int sig,
size_t sigsetsize);
#endif /* __ASSEMBLY__ */
-
-#endif /* __KERNEL_SYSCALLS__ */
+#endif /* __KERNEL__ */
+#endif /* __NO_STUBS */
/*
* "Conditional" syscalls
@@ -849,8 +773,4 @@ asmlinkage long sys_rt_sigaction(int sig,
*/
#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall")
-#endif /* __NO_STUBS */
-
-#endif /* __KERNEL__ */
-
#endif /* _ASM_X86_64_UNISTD_H_ */
diff --git a/include/asm-x86_64/vsyscall.h b/include/asm-x86_64/vsyscall.h
index 2281e9399b96..fd452fc2c037 100644
--- a/include/asm-x86_64/vsyscall.h
+++ b/include/asm-x86_64/vsyscall.h
@@ -17,7 +17,6 @@ enum vsyscall_num {
#define __section_vxtime __attribute__ ((unused, __section__ (".vxtime"), aligned(16)))
#define __section_vgetcpu_mode __attribute__ ((unused, __section__ (".vgetcpu_mode"), aligned(16)))
-#define __section_wall_jiffies __attribute__ ((unused, __section__ (".wall_jiffies"), aligned(16)))
#define __section_jiffies __attribute__ ((unused, __section__ (".jiffies"), aligned(16)))
#define __section_sys_tz __attribute__ ((unused, __section__ (".sys_tz"), aligned(16)))
#define __section_sysctl_vsyscall __attribute__ ((unused, __section__ (".sysctl_vsyscall"), aligned(16)))
@@ -48,14 +47,12 @@ extern struct vxtime_data __vxtime;
extern int __vgetcpu_mode;
extern struct timespec __xtime;
extern volatile unsigned long __jiffies;
-extern unsigned long __wall_jiffies;
extern struct timezone __sys_tz;
extern seqlock_t __xtime_lock;
/* kernel space (writeable) */
extern struct vxtime_data vxtime;
extern int vgetcpu_mode;
-extern unsigned long wall_jiffies;
extern struct timezone sys_tz;
extern int sysctl_vsyscall;
extern seqlock_t xtime_lock;
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
index 3be701dfe098..ffc4dcfd6ac1 100644
--- a/include/asm-xtensa/a.out.h
+++ b/include/asm-xtensa/a.out.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/addrspace.h
+ * include/asm-xtensa/a.out.h
*
* Dummy a.out file. Xtensa does not support the a.out format, but the kernel
* seems to depend on it.
diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h
index 5aae3f12407c..1e79c0e27460 100644
--- a/include/asm-xtensa/cache.h
+++ b/include/asm-xtensa/cache.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/cacheflush.h
+ * include/asm-xtensa/cache.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
diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h
index a91b96dc0efe..5093034723be 100644
--- a/include/asm-xtensa/coprocessor.h
+++ b/include/asm-xtensa/coprocessor.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/cpextra.h
+ * include/asm-xtensa/coprocessor.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
diff --git a/include/asm-xtensa/dma-mapping.h b/include/asm-xtensa/dma-mapping.h
index c425f10d086a..c39c91dfcc69 100644
--- a/include/asm-xtensa/dma-mapping.h
+++ b/include/asm-xtensa/dma-mapping.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/dma_mapping.h
+ * include/asm-xtensa/dma-mapping.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
diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h
index 3b89a772d0a0..39e6f23921bb 100644
--- a/include/asm-xtensa/ioctls.h
+++ b/include/asm-xtensa/ioctls.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/ioctl.h
+ * include/asm-xtensa/ioctls.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
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
index a47cc734c20c..b4318934b10d 100644
--- a/include/asm-xtensa/pgtable.h
+++ b/include/asm-xtensa/pgtable.h
@@ -1,5 +1,5 @@
/*
- * linux/include/asm-xtensa/page.h
+ * linux/include/asm-xtensa/pgtable.h
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version2 as
diff --git a/include/asm-xtensa/siginfo.h b/include/asm-xtensa/siginfo.h
index 44f0ae77b539..6916248295df 100644
--- a/include/asm-xtensa/siginfo.h
+++ b/include/asm-xtensa/siginfo.h
@@ -1,5 +1,5 @@
/*
- * include/asm-xtensa/processor.h
+ * include/asm-xtensa/siginfo.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
diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h
index d14a3755a12b..c7b705e66655 100644
--- a/include/asm-xtensa/timex.h
+++ b/include/asm-xtensa/timex.h
@@ -31,9 +31,6 @@
#define CLOCK_TICK_RATE 1193180 /* (everyone is using this value) */
#define CLOCK_TICK_FACTOR 20 /* Factor of both 10^6 and CLOCK_TICK_RATE */
-#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
- (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
- << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
extern unsigned long ccount_per_jiffy;
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
index 5e1b99dc4ab3..411f810a55c6 100644
--- a/include/asm-xtensa/unistd.h
+++ b/include/asm-xtensa/unistd.h
@@ -402,11 +402,6 @@ __asm__ __volatile__ ( \
__syscall_return(type,__res); \
}
-
-#ifdef __KERNEL_SYSCALLS__
-static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp)
-#endif
-
/*
* "Conditional" syscalls
*
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 1df2ac30a4d2..a1155a2beb32 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -46,6 +46,7 @@ header-y += coff.h
header-y += comstats.h
header-y += consolemap.h
header-y += cycx_cfm.h
+header-y += dlm_device.h
header-y += dm-ioctl.h
header-y += dn.h
header-y += dqblk_v1.h
@@ -58,6 +59,7 @@ header-y += elf-em.h
header-y += fadvise.h
header-y += fd.h
header-y += fdreg.h
+header-y += fib_rules.h
header-y += ftape-header-segment.h
header-y += ftape-vendors.h
header-y += fuse.h
@@ -70,6 +72,7 @@ header-y += hysdn_if.h
header-y += i2c-dev.h
header-y += i8k.h
header-y += icmp.h
+header-y += if_addr.h
header-y += if_arcnet.h
header-y += if_arp.h
header-y += if_bonding.h
@@ -79,6 +82,7 @@ header-y += if_fddi.h
header-y += if.h
header-y += if_hippi.h
header-y += if_infiniband.h
+header-y += if_link.h
header-y += if_packet.h
header-y += if_plip.h
header-y += if_ppp.h
@@ -96,11 +100,11 @@ header-y += ipx.h
header-y += irda.h
header-y += isdn_divertif.h
header-y += iso_fs.h
-header-y += ite_gpio.h
header-y += ixjuser.h
header-y += jffs2.h
header-y += keyctl.h
header-y += limits.h
+header-y += lock_dlm_plock.h
header-y += magic.h
header-y += major.h
header-y += matroxfb.h
@@ -110,11 +114,13 @@ header-y += mmtimer.h
header-y += mqueue.h
header-y += mtio.h
header-y += ncp_no.h
+header-y += neighbour.h
header-y += netfilter_arp.h
header-y += netrom.h
header-y += nfs2.h
header-y += nfs4_mount.h
header-y += nfs_mount.h
+header-y += oom.h
header-y += param.h
header-y += pci_ids.h
header-y += pci_regs.h
@@ -152,12 +158,10 @@ header-y += toshiba.h
header-y += ultrasound.h
header-y += un.h
header-y += utime.h
-header-y += utsname.h
header-y += video_decoder.h
header-y += video_encoder.h
header-y += videotext.h
header-y += vt.h
-header-y += wavefront.h
header-y += wireless.h
header-y += xattr.h
header-y += x25.h
@@ -190,6 +194,7 @@ unifdef-y += cyclades.h
unifdef-y += dccp.h
unifdef-y += dirent.h
unifdef-y += divert.h
+unifdef-y += dlm.h
unifdef-y += elfcore.h
unifdef-y += errno.h
unifdef-y += errqueue.h
@@ -206,6 +211,7 @@ unifdef-y += ftape.h
unifdef-y += gameport.h
unifdef-y += generic_serial.h
unifdef-y += genhd.h
+unifdef-y += gfs2_ondisk.h
unifdef-y += hayesesp.h
unifdef-y += hdlcdrv.h
unifdef-y += hdlc.h
@@ -329,6 +335,7 @@ unifdef-y += unistd.h
unifdef-y += usb_ch9.h
unifdef-y += usbdevice_fs.h
unifdef-y += user.h
+unifdef-y += utsname.h
unifdef-y += videodev2.h
unifdef-y += videodev.h
unifdef-y += wait.h
diff --git a/include/linux/ac97_codec.h b/include/linux/ac97_codec.h
index 2ed2fd855133..22eb9367235a 100644
--- a/include/linux/ac97_codec.h
+++ b/include/linux/ac97_codec.h
@@ -331,8 +331,6 @@ extern int ac97_read_proc (char *page_out, char **start, off_t off,
extern int ac97_probe_codec(struct ac97_codec *);
extern unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate);
extern unsigned int ac97_set_dac_rate(struct ac97_codec *codec, unsigned int rate);
-extern int ac97_save_state(struct ac97_codec *codec);
-extern int ac97_restore_state(struct ac97_codec *codec);
extern struct ac97_codec *ac97_alloc_codec(void);
extern void ac97_release_codec(struct ac97_codec *codec);
@@ -346,9 +344,6 @@ struct ac97_driver {
void (*remove) (struct ac97_codec *codec, struct ac97_driver *driver);
};
-extern int ac97_register_driver(struct ac97_driver *driver);
-extern void ac97_unregister_driver(struct ac97_driver *driver);
-
/* quirk types */
enum {
AC97_TUNE_DEFAULT = -1, /* use default from quirk list (not valid in list) */
diff --git a/include/linux/acct.h b/include/linux/acct.h
index e86bae7324d2..0496d1f09952 100644
--- a/include/linux/acct.h
+++ b/include/linux/acct.h
@@ -124,16 +124,12 @@ extern void acct_auto_close(struct super_block *sb);
extern void acct_init_pacct(struct pacct_struct *pacct);
extern void acct_collect(long exitcode, int group_dead);
extern void acct_process(void);
-extern void acct_update_integrals(struct task_struct *tsk);
-extern void acct_clear_integrals(struct task_struct *tsk);
#else
#define acct_auto_close_mnt(x) do { } while (0)
#define acct_auto_close(x) do { } while (0)
#define acct_init_pacct(x) do { } while (0)
#define acct_collect(x,y) do { } while (0)
#define acct_process() do { } while (0)
-#define acct_update_integrals(x) do { } while (0)
-#define acct_clear_integrals(task) do { } while (0)
#endif
/*
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 88b5dfd8ee12..2b0c955590fe 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -494,6 +494,9 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
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);
#endif /*CONFIG_ACPI_EC*/
diff --git a/include/linux/adb.h b/include/linux/adb.h
index b7305b178279..64d8878e1444 100644
--- a/include/linux/adb.h
+++ b/include/linux/adb.h
@@ -90,10 +90,10 @@ extern struct blocking_notifier_head adb_client_list;
int adb_request(struct adb_request *req, void (*done)(struct adb_request *),
int flags, int nbytes, ...);
int adb_register(int default_id,int handler_id,struct adb_ids *ids,
- void (*handler)(unsigned char *, int, struct pt_regs *, int));
+ void (*handler)(unsigned char *, int, int));
int adb_unregister(int index);
void adb_poll(void);
-void adb_input(unsigned char *, int, struct pt_regs *, int);
+void adb_input(unsigned char *, int, int);
int adb_reset_bus(void);
int adb_try_handler_change(int address, int new_id);
diff --git a/include/linux/aer.h b/include/linux/aer.h
new file mode 100644
index 000000000000..402e178b38eb
--- /dev/null
+++ b/include/linux/aer.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2006 Intel Corp.
+ * Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Zhang Yanmin (yanmin.zhang@intel.com)
+ */
+
+#ifndef _AER_H_
+#define _AER_H_
+
+#if defined(CONFIG_PCIEAER)
+/* pci-e port driver needs this function to enable aer */
+extern int pci_enable_pcie_error_reporting(struct pci_dev *dev);
+extern int pci_find_aer_capability(struct pci_dev *dev);
+extern int pci_disable_pcie_error_reporting(struct pci_dev *dev);
+extern int pci_cleanup_aer_uncorrect_error_status(struct pci_dev *dev);
+#else
+#define pci_enable_pcie_error_reporting(dev) do { } while (0)
+#define pci_find_aer_capability(dev) do { } while (0)
+#define pci_disable_pcie_error_reporting(dev) do { } while (0)
+#define pci_cleanup_aer_uncorrect_error_status(dev) do { } while (0)
+#endif
+
+#endif //_AER_H_
+
diff --git a/include/linux/aio.h b/include/linux/aio.h
index 00c8efa95cc3..0d71c0041f13 100644
--- a/include/linux/aio.h
+++ b/include/linux/aio.h
@@ -4,8 +4,10 @@
#include <linux/list.h>
#include <linux/workqueue.h>
#include <linux/aio_abi.h>
+#include <linux/uio.h>
#include <asm/atomic.h>
+#include <linux/uio.h>
#define AIO_MAXSEGS 4
#define AIO_KIOGRP_NR_ATOMIC 8
@@ -110,8 +112,10 @@ struct kiocb {
char __user *ki_buf; /* remaining iocb->aio_buf */
size_t ki_left; /* remaining bytes */
long ki_retried; /* just for testing */
- long ki_kicked; /* just for testing */
- long ki_queued; /* just for testing */
+ struct iovec ki_inline_vec; /* inline vector */
+ struct iovec *ki_iovec;
+ unsigned long ki_nr_segs;
+ unsigned long ki_cur_seg;
struct list_head ki_list; /* the aio core uses this
* for cancellation */
@@ -213,11 +217,11 @@ int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
struct iocb *iocb));
#define get_ioctx(kioctx) do { \
- BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \
+ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
atomic_inc(&(kioctx)->users); \
} while (0)
#define put_ioctx(kioctx) do { \
- BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \
+ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \
__put_ioctx(kioctx); \
} while (0)
diff --git a/include/linux/aio_abi.h b/include/linux/aio_abi.h
index 30fdcc89d142..e3ca0a485cc6 100644
--- a/include/linux/aio_abi.h
+++ b/include/linux/aio_abi.h
@@ -1,4 +1,4 @@
-/* linux/aio_abi.h
+/* include/linux/aio_abi.h
*
* Copyright 2000,2001,2002 Red Hat.
*
@@ -41,6 +41,8 @@ enum {
* IOCB_CMD_POLL = 5,
*/
IOCB_CMD_NOOP = 6,
+ IOCB_CMD_PREADV = 7,
+ IOCB_CMD_PWRITEV = 8,
};
/* read() from /dev/aio returns these structures. */
diff --git a/include/linux/arcdevice.h b/include/linux/arcdevice.h
index 231ba090ae34..2f85049cfb3d 100644
--- a/include/linux/arcdevice.h
+++ b/include/linux/arcdevice.h
@@ -334,7 +334,7 @@ void arcnet_dump_skb(struct net_device *dev, struct sk_buff *skb, char *desc);
#endif
void arcnet_unregister_proto(struct ArcProto *proto);
-irqreturn_t arcnet_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t arcnet_interrupt(int irq, void *dev_id);
struct net_device *alloc_arcdev(char *name);
#endif /* __KERNEL__ */
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
index 6ba3aa8a81f4..75b8baca08f3 100644
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -88,15 +88,7 @@ static inline struct atalk_sock *at_sk(struct sock *sk)
#include <asm/byteorder.h>
struct ddpehdr {
-#ifdef __LITTLE_ENDIAN_BITFIELD
- __u16 deh_len:10,
- deh_hops:4,
- deh_pad:2;
-#else
- __u16 deh_pad:2,
- deh_hops:4,
- deh_len:10;
-#endif
+ __be16 deh_len_hops; /* lower 10 bits are length, next 4 - hops */
__be16 deh_sum;
__be16 deh_dnet;
__be16 deh_snet;
@@ -112,36 +104,6 @@ static __inline__ struct ddpehdr *ddp_hdr(struct sk_buff *skb)
return (struct ddpehdr *)skb->h.raw;
}
-/*
- * Don't drop the struct into the struct above. You'll get some
- * surprise padding.
- */
-struct ddpebits {
-#ifdef __LITTLE_ENDIAN_BITFIELD
- __u16 deh_len:10,
- deh_hops:4,
- deh_pad:2;
-#else
- __u16 deh_pad:2,
- deh_hops:4,
- deh_len:10;
-#endif
-};
-
-/* Short form header */
-struct ddpshdr {
-#ifdef __LITTLE_ENDIAN_BITFIELD
- __u16 dsh_len:10,
- dsh_pad:6;
-#else
- __u16 dsh_pad:6,
- dsh_len:10;
-#endif
- __u8 dsh_dport;
- __u8 dsh_sport;
- /* And netatalk apps expect to stick the type in themselves */
-};
-
/* AppleTalk AARP headers */
struct elapaarp {
__be16 hw_type;
diff --git a/include/linux/atmlec.h b/include/linux/atmlec.h
index f267f2442766..6f5a1bab8f50 100644
--- a/include/linux/atmlec.h
+++ b/include/linux/atmlec.h
@@ -1,9 +1,7 @@
/*
- *
- * ATM Lan Emulation Daemon vs. driver interface
- *
- * mkiiskila@yahoo.com
+ * ATM Lan Emulation Daemon driver interface
*
+ * Marko Kiiskila <mkiiskila@yahoo.com>
*/
#ifndef _ATMLEC_H_
@@ -13,76 +11,87 @@
#include <linux/atmioc.h>
#include <linux/atm.h>
#include <linux/if_ether.h>
+
/* ATM lec daemon control socket */
-#define ATMLEC_CTRL _IO('a',ATMIOC_LANE)
-#define ATMLEC_DATA _IO('a',ATMIOC_LANE+1)
-#define ATMLEC_MCAST _IO('a',ATMIOC_LANE+2)
+#define ATMLEC_CTRL _IO('a', ATMIOC_LANE)
+#define ATMLEC_DATA _IO('a', ATMIOC_LANE+1)
+#define ATMLEC_MCAST _IO('a', ATMIOC_LANE+2)
/* Maximum number of LEC interfaces (tweakable) */
#define MAX_LEC_ITF 48
-/* From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring.
+/*
+ * From the total of MAX_LEC_ITF, last NUM_TR_DEVS are reserved for Token Ring.
* E.g. if MAX_LEC_ITF = 48 and NUM_TR_DEVS = 8, then lec0-lec39 are for
* Ethernet ELANs and lec40-lec47 are for Token Ring ELANS.
*/
#define NUM_TR_DEVS 8
-typedef enum {
- l_set_mac_addr, l_del_mac_addr,
- l_svc_setup,
- l_addr_delete, l_topology_change,
- l_flush_complete, l_arp_update,
- l_narp_req, /* LANE2 mandates the use of this */
- l_config, l_flush_tran_id,
- l_set_lecid, l_arp_xmt,
- l_rdesc_arp_xmt,
- l_associate_req,
- l_should_bridge /* should we bridge this MAC? */
+typedef enum {
+ l_set_mac_addr,
+ l_del_mac_addr,
+ l_svc_setup,
+ l_addr_delete,
+ l_topology_change,
+ l_flush_complete,
+ l_arp_update,
+ l_narp_req, /* LANE2 mandates the use of this */
+ l_config,
+ l_flush_tran_id,
+ l_set_lecid,
+ l_arp_xmt,
+ l_rdesc_arp_xmt,
+ l_associate_req,
+ l_should_bridge /* should we bridge this MAC? */
} atmlec_msg_type;
#define ATMLEC_MSG_TYPE_MAX l_should_bridge
struct atmlec_config_msg {
- unsigned int maximum_unknown_frame_count;
- unsigned int max_unknown_frame_time;
- unsigned short max_retry_count;
- unsigned int aging_time;
- unsigned int forward_delay_time;
- unsigned int arp_response_time;
- unsigned int flush_timeout;
- unsigned int path_switching_delay;
- unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */
- int mtu;
- int is_proxy;
+ unsigned int maximum_unknown_frame_count;
+ unsigned int max_unknown_frame_time;
+ unsigned short max_retry_count;
+ unsigned int aging_time;
+ unsigned int forward_delay_time;
+ unsigned int arp_response_time;
+ unsigned int flush_timeout;
+ unsigned int path_switching_delay;
+ unsigned int lane_version; /* LANE2: 1 for LANEv1, 2 for LANEv2 */
+ int mtu;
+ int is_proxy;
};
-
+
struct atmlec_msg {
- atmlec_msg_type type;
- int sizeoftlvs; /* LANE2: if != 0, tlvs follow */
- union {
- struct {
- unsigned char mac_addr[ETH_ALEN];
- unsigned char atm_addr[ATM_ESA_LEN];
- unsigned int flag;/* Topology_change flag,
- remoteflag, permanent flag,
- lecid, transaction id */
- unsigned int targetless_le_arp; /* LANE2 */
- unsigned int no_source_le_narp; /* LANE2 */
- } normal;
- struct atmlec_config_msg config;
- struct {
- uint16_t lec_id; /* requestor lec_id */
- uint32_t tran_id; /* transaction id */
- unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */
- unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */
- } proxy;
- /* For mapping LE_ARP requests to responses. Filled by */
- } content; /* zeppelin, returned by kernel. Used only when proxying */
+ atmlec_msg_type type;
+ int sizeoftlvs; /* LANE2: if != 0, tlvs follow */
+ union {
+ struct {
+ unsigned char mac_addr[ETH_ALEN];
+ unsigned char atm_addr[ATM_ESA_LEN];
+ unsigned int flag; /*
+ * Topology_change flag,
+ * remoteflag, permanent flag,
+ * lecid, transaction id
+ */
+ unsigned int targetless_le_arp; /* LANE2 */
+ unsigned int no_source_le_narp; /* LANE2 */
+ } normal;
+ struct atmlec_config_msg config;
+ struct {
+ uint16_t lec_id; /* requestor lec_id */
+ uint32_t tran_id; /* transaction id */
+ unsigned char mac_addr[ETH_ALEN]; /* dst mac addr */
+ unsigned char atm_addr[ATM_ESA_LEN]; /* reqestor ATM addr */
+ } proxy; /*
+ * For mapping LE_ARP requests to responses. Filled by
+ * zeppelin, returned by kernel. Used only when proxying
+ */
+ } content;
} __ATM_API_ALIGN;
struct atmlec_ioc {
- int dev_num;
- unsigned char atm_addr[ATM_ESA_LEN];
- unsigned char receive; /* 1= receive vcc, 0 = send vcc */
+ int dev_num;
+ unsigned char atm_addr[ATM_ESA_LEN];
+ unsigned char receive; /* 1= receive vcc, 0 = send vcc */
};
#endif /* _ATMLEC_H_ */
diff --git a/include/linux/audit.h b/include/linux/audit.h
index 40a6c26294ae..b2ca666d9997 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -75,7 +75,7 @@
#define AUDIT_DAEMON_CONFIG 1203 /* Daemon config change */
#define AUDIT_SYSCALL 1300 /* Syscall event */
-#define AUDIT_FS_WATCH 1301 /* Filesystem watch event */
+/* #define AUDIT_FS_WATCH 1301 * Deprecated */
#define AUDIT_PATH 1302 /* Filename path information */
#define AUDIT_IPC 1303 /* IPC record */
#define AUDIT_SOCKETCALL 1304 /* sys_socketcall arguments */
@@ -88,6 +88,7 @@
#define AUDIT_MQ_SENDRECV 1313 /* POSIX MQ send/receive record type */
#define AUDIT_MQ_NOTIFY 1314 /* POSIX MQ notify record type */
#define AUDIT_MQ_GETSETATTR 1315 /* POSIX MQ get/set attribute record type */
+#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -95,6 +96,11 @@
#define AUDIT_MAC_POLICY_LOAD 1403 /* Policy file load */
#define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */
#define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */
+#define AUDIT_MAC_UNLBL_ALLOW 1406 /* NetLabel: allow unlabeled traffic */
+#define AUDIT_MAC_CIPSOV4_ADD 1407 /* NetLabel: add CIPSOv4 DOI entry */
+#define AUDIT_MAC_CIPSOV4_DEL 1408 /* NetLabel: del CIPSOv4 DOI entry */
+#define AUDIT_MAC_MAP_ADD 1409 /* NetLabel: add LSM domain mapping */
+#define AUDIT_MAC_MAP_DEL 1410 /* NetLabel: del LSM domain mapping */
#define AUDIT_FIRST_KERN_ANOM_MSG 1700
#define AUDIT_LAST_KERN_ANOM_MSG 1799
diff --git a/include/linux/awe_voice.h b/include/linux/awe_voice.h
index 4bf9f33048e2..bf33f17bea99 100644
--- a/include/linux/awe_voice.h
+++ b/include/linux/awe_voice.h
@@ -1,5 +1,5 @@
/*
- * sound/awe_voice.h
+ * include/linux/awe_voice.h
*
* Voice information definitions for the low level driver for the
* AWE32/SB32/AWE64 wave table synth.
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index f7a1390d67f5..7011d6255593 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -10,6 +10,8 @@
#include <asm/atomic.h>
+struct page;
+
/*
* Bits in backing_dev_info.state
*/
@@ -88,6 +90,11 @@ static inline int bdi_rw_congested(struct backing_dev_info *bdi)
(1 << BDI_write_congested));
}
+void clear_bdi_congested(struct backing_dev_info *bdi, int rw);
+void set_bdi_congested(struct backing_dev_info *bdi, int rw);
+long congestion_wait(int rw, long timeout);
+void congestion_end(int rw);
+
#define bdi_cap_writeback_dirty(bdi) \
(!((bdi)->capabilities & BDI_CAP_NO_WRITEBACK))
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 76bdaeab6f62..092dbd0e7658 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -70,7 +70,8 @@ typedef void (bio_destructor_t) (struct bio *);
* stacking drivers)
*/
struct bio {
- sector_t bi_sector;
+ sector_t bi_sector; /* device address in 512 byte
+ sectors */
struct bio *bi_next; /* request queue link */
struct block_device *bi_bdev;
unsigned long bi_flags; /* status, command, etc */
@@ -148,6 +149,7 @@ struct bio {
#define BIO_RW_BARRIER 2
#define BIO_RW_FAILFAST 3
#define BIO_RW_SYNC 4
+#define BIO_RW_META 5
/*
* upper 16 bits of bi_rw define the io priority of this bio
@@ -178,6 +180,7 @@ struct bio {
#define bio_sync(bio) ((bio)->bi_rw & (1 << BIO_RW_SYNC))
#define bio_failfast(bio) ((bio)->bi_rw & (1 << BIO_RW_FAILFAST))
#define bio_rw_ahead(bio) ((bio)->bi_rw & (1 << BIO_RW_AHEAD))
+#define bio_rw_meta(bio) ((bio)->bi_rw & (1 << BIO_RW_META))
/*
* will die
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
index dcc5de7cc487..64b4641904fe 100644
--- a/include/linux/bitmap.h
+++ b/include/linux/bitmap.h
@@ -46,7 +46,8 @@
* bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
* bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
* bitmap_scnprintf(buf, len, src, nbits) Print bitmap src to buf
- * bitmap_parse(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf
+ * bitmap_parse(buf, buflen, dst, nbits) Parse bitmap dst from kernel buf
+ * bitmap_parse_user(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf
* bitmap_scnlistprintf(buf, len, src, nbits) Print bitmap src as list to buf
* bitmap_parselist(buf, dst, nbits) Parse bitmap dst from list
* bitmap_find_free_region(bitmap, bits, order) Find and allocate bit region
@@ -106,7 +107,9 @@ extern int __bitmap_weight(const unsigned long *bitmap, int bits);
extern int bitmap_scnprintf(char *buf, unsigned int len,
const unsigned long *src, int nbits);
-extern int bitmap_parse(const char __user *ubuf, unsigned int ulen,
+extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user,
+ unsigned long *dst, int nbits);
+extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
unsigned long *dst, int nbits);
extern int bitmap_scnlistprintf(char *buf, unsigned int len,
const unsigned long *src, int nbits);
@@ -270,6 +273,12 @@ static inline void bitmap_shift_left(unsigned long *dst,
__bitmap_shift_left(dst, src, n, nbits);
}
+static inline int bitmap_parse(const char *buf, unsigned int buflen,
+ unsigned long *maskp, int nmaskbits)
+{
+ return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits);
+}
+
#endif /* __ASSEMBLY__ */
#endif /* __LINUX_BITMAP_H */
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index c773ee545ebd..7bfcde2d5578 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1,6 +1,7 @@
#ifndef _LINUX_BLKDEV_H
#define _LINUX_BLKDEV_H
+#include <linux/sched.h>
#include <linux/major.h>
#include <linux/genhd.h>
#include <linux/list.h>
@@ -16,6 +17,22 @@
#include <asm/scatterlist.h>
+#ifdef CONFIG_LBD
+# include <asm/div64.h>
+# define sector_div(a, b) do_div(a, b)
+#else
+# define sector_div(n, b)( \
+{ \
+ int _res; \
+ _res = (n) % (b); \
+ (n) /= (b); \
+ _res; \
+} \
+)
+#endif
+
+#ifdef CONFIG_BLOCK
+
struct scsi_ioctl_command;
struct request_queue;
@@ -90,7 +107,7 @@ struct io_context {
atomic_t refcount;
struct task_struct *task;
- int (*set_ioprio)(struct io_context *, unsigned int);
+ unsigned int ioprio_changed;
/*
* For request batching
@@ -104,8 +121,7 @@ struct io_context {
void put_io_context(struct io_context *ioc);
void exit_io_context(void);
-struct io_context *current_io_context(gfp_t gfp_flags);
-struct io_context *get_io_context(gfp_t gfp_flags);
+struct io_context *get_io_context(gfp_t gfp_flags, int node);
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
@@ -120,6 +136,91 @@ struct request_list {
wait_queue_head_t wait[2];
};
+/*
+ * request command types
+ */
+enum rq_cmd_type_bits {
+ REQ_TYPE_FS = 1, /* fs request */
+ REQ_TYPE_BLOCK_PC, /* scsi command */
+ REQ_TYPE_SENSE, /* sense request */
+ REQ_TYPE_PM_SUSPEND, /* suspend request */
+ REQ_TYPE_PM_RESUME, /* resume request */
+ REQ_TYPE_PM_SHUTDOWN, /* shutdown request */
+ REQ_TYPE_FLUSH, /* flush request */
+ REQ_TYPE_SPECIAL, /* driver defined type */
+ REQ_TYPE_LINUX_BLOCK, /* generic block layer message */
+ /*
+ * for ATA/ATAPI devices. this really doesn't belong here, ide should
+ * use REQ_TYPE_SPECIAL and use rq->cmd[0] with the range of driver
+ * private REQ_LB opcodes to differentiate what type of request this is
+ */
+ REQ_TYPE_ATA_CMD,
+ REQ_TYPE_ATA_TASK,
+ REQ_TYPE_ATA_TASKFILE,
+ REQ_TYPE_ATA_PC,
+};
+
+/*
+ * For request of type REQ_TYPE_LINUX_BLOCK, rq->cmd[0] is the opcode being
+ * sent down (similar to how REQ_TYPE_BLOCK_PC means that ->cmd[] holds a
+ * SCSI cdb.
+ *
+ * 0x00 -> 0x3f are driver private, to be used for whatever purpose they need,
+ * typically to differentiate REQ_TYPE_SPECIAL requests.
+ *
+ */
+enum {
+ /*
+ * just examples for now
+ */
+ REQ_LB_OP_EJECT = 0x40, /* eject request */
+ REQ_LB_OP_FLUSH = 0x41, /* flush device */
+};
+
+/*
+ * request type modified bits. first three bits match BIO_RW* bits, important
+ */
+enum rq_flag_bits {
+ __REQ_RW, /* not set, read. set, write */
+ __REQ_FAILFAST, /* no low level driver retries */
+ __REQ_SORTED, /* elevator knows about this request */
+ __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */
+ __REQ_HARDBARRIER, /* may not be passed by drive either */
+ __REQ_FUA, /* forced unit access */
+ __REQ_NOMERGE, /* don't touch this for merging */
+ __REQ_STARTED, /* drive already may have started this one */
+ __REQ_DONTPREP, /* don't call prep for this one */
+ __REQ_QUEUED, /* uses queueing */
+ __REQ_ELVPRIV, /* elevator private data attached */
+ __REQ_FAILED, /* set if the request failed */
+ __REQ_QUIET, /* don't worry about errors */
+ __REQ_PREEMPT, /* set for "ide_preempt" requests */
+ __REQ_ORDERED_COLOR, /* is before or after barrier */
+ __REQ_RW_SYNC, /* request is sync (O_DIRECT) */
+ __REQ_ALLOCED, /* request came from our alloc pool */
+ __REQ_RW_META, /* metadata io request */
+ __REQ_NR_BITS, /* stops here */
+};
+
+#define REQ_RW (1 << __REQ_RW)
+#define REQ_FAILFAST (1 << __REQ_FAILFAST)
+#define REQ_SORTED (1 << __REQ_SORTED)
+#define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER)
+#define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER)
+#define REQ_FUA (1 << __REQ_FUA)
+#define REQ_NOMERGE (1 << __REQ_NOMERGE)
+#define REQ_STARTED (1 << __REQ_STARTED)
+#define REQ_DONTPREP (1 << __REQ_DONTPREP)
+#define REQ_QUEUED (1 << __REQ_QUEUED)
+#define REQ_ELVPRIV (1 << __REQ_ELVPRIV)
+#define REQ_FAILED (1 << __REQ_FAILED)
+#define REQ_QUIET (1 << __REQ_QUIET)
+#define REQ_PREEMPT (1 << __REQ_PREEMPT)
+#define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR)
+#define REQ_RW_SYNC (1 << __REQ_RW_SYNC)
+#define REQ_ALLOCED (1 << __REQ_ALLOCED)
+#define REQ_RW_META (1 << __REQ_RW_META)
+
#define BLK_MAX_CDB 16
/*
@@ -129,30 +230,46 @@ struct request {
struct list_head queuelist;
struct list_head donelist;
- unsigned long flags; /* see REQ_ bits below */
+ request_queue_t *q;
+
+ unsigned int cmd_flags;
+ enum rq_cmd_type_bits cmd_type;
/* Maintain bio traversal state for part by part I/O submission.
* hard_* are block layer internals, no driver should touch them!
*/
sector_t sector; /* next sector to submit */
+ sector_t hard_sector; /* next sector to complete */
unsigned long nr_sectors; /* no. of sectors left to submit */
+ unsigned long hard_nr_sectors; /* no. of sectors left to complete */
/* no. of sectors left to submit in the current segment */
unsigned int current_nr_sectors;
- sector_t hard_sector; /* next sector to complete */
- unsigned long hard_nr_sectors; /* no. of sectors left to complete */
/* no. of sectors left to complete in the current segment */
unsigned int hard_cur_sectors;
struct bio *bio;
struct bio *biotail;
+ struct hlist_node hash; /* merge hash */
+ /*
+ * The rb_node is only used inside the io scheduler, requests
+ * are pruned when moved to the dispatch queue. So let the
+ * completion_data share space with the rb_node.
+ */
+ union {
+ struct rb_node rb_node; /* sort/lookup */
+ void *completion_data;
+ };
+
+ /*
+ * two pointers are available for the IO schedulers, if they need
+ * more they have to dynamically allocate it.
+ */
void *elevator_private;
- void *completion_data;
+ void *elevator_private2;
- int rq_status; /* should split this into a few status bits */
- int errors;
struct gendisk *rq_disk;
unsigned long start_time;
@@ -170,15 +287,13 @@ struct request {
unsigned short ioprio;
+ void *special;
+ char *buffer;
+
int tag;
+ int errors;
int ref_count;
- request_queue_t *q;
- struct request_list *rl;
-
- struct completion *waiting;
- void *special;
- char *buffer;
/*
* when request is used as a packet command carrier
@@ -195,80 +310,14 @@ struct request {
int retries;
/*
- * completion callback. end_io_data should be folded in with waiting
+ * completion callback.
*/
rq_end_io_fn *end_io;
void *end_io_data;
};
/*
- * first three bits match BIO_RW* bits, important
- */
-enum rq_flag_bits {
- __REQ_RW, /* not set, read. set, write */
- __REQ_FAILFAST, /* no low level driver retries */
- __REQ_SORTED, /* elevator knows about this request */
- __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */
- __REQ_HARDBARRIER, /* may not be passed by drive either */
- __REQ_FUA, /* forced unit access */
- __REQ_CMD, /* is a regular fs rw request */
- __REQ_NOMERGE, /* don't touch this for merging */
- __REQ_STARTED, /* drive already may have started this one */
- __REQ_DONTPREP, /* don't call prep for this one */
- __REQ_QUEUED, /* uses queueing */
- __REQ_ELVPRIV, /* elevator private data attached */
- /*
- * for ATA/ATAPI devices
- */
- __REQ_PC, /* packet command (special) */
- __REQ_BLOCK_PC, /* queued down pc from block layer */
- __REQ_SENSE, /* sense retrival */
-
- __REQ_FAILED, /* set if the request failed */
- __REQ_QUIET, /* don't worry about errors */
- __REQ_SPECIAL, /* driver suplied command */
- __REQ_DRIVE_CMD,
- __REQ_DRIVE_TASK,
- __REQ_DRIVE_TASKFILE,
- __REQ_PREEMPT, /* set for "ide_preempt" requests */
- __REQ_PM_SUSPEND, /* suspend request */
- __REQ_PM_RESUME, /* resume request */
- __REQ_PM_SHUTDOWN, /* shutdown request */
- __REQ_ORDERED_COLOR, /* is before or after barrier */
- __REQ_RW_SYNC, /* request is sync (O_DIRECT) */
- __REQ_NR_BITS, /* stops here */
-};
-
-#define REQ_RW (1 << __REQ_RW)
-#define REQ_FAILFAST (1 << __REQ_FAILFAST)
-#define REQ_SORTED (1 << __REQ_SORTED)
-#define REQ_SOFTBARRIER (1 << __REQ_SOFTBARRIER)
-#define REQ_HARDBARRIER (1 << __REQ_HARDBARRIER)
-#define REQ_FUA (1 << __REQ_FUA)
-#define REQ_CMD (1 << __REQ_CMD)
-#define REQ_NOMERGE (1 << __REQ_NOMERGE)
-#define REQ_STARTED (1 << __REQ_STARTED)
-#define REQ_DONTPREP (1 << __REQ_DONTPREP)
-#define REQ_QUEUED (1 << __REQ_QUEUED)
-#define REQ_ELVPRIV (1 << __REQ_ELVPRIV)
-#define REQ_PC (1 << __REQ_PC)
-#define REQ_BLOCK_PC (1 << __REQ_BLOCK_PC)
-#define REQ_SENSE (1 << __REQ_SENSE)
-#define REQ_FAILED (1 << __REQ_FAILED)
-#define REQ_QUIET (1 << __REQ_QUIET)
-#define REQ_SPECIAL (1 << __REQ_SPECIAL)
-#define REQ_DRIVE_CMD (1 << __REQ_DRIVE_CMD)
-#define REQ_DRIVE_TASK (1 << __REQ_DRIVE_TASK)
-#define REQ_DRIVE_TASKFILE (1 << __REQ_DRIVE_TASKFILE)
-#define REQ_PREEMPT (1 << __REQ_PREEMPT)
-#define REQ_PM_SUSPEND (1 << __REQ_PM_SUSPEND)
-#define REQ_PM_RESUME (1 << __REQ_PM_RESUME)
-#define REQ_PM_SHUTDOWN (1 << __REQ_PM_SHUTDOWN)
-#define REQ_ORDERED_COLOR (1 << __REQ_ORDERED_COLOR)
-#define REQ_RW_SYNC (1 << __REQ_RW_SYNC)
-
-/*
- * State information carried for REQ_PM_SUSPEND and REQ_PM_RESUME
+ * State information carried for REQ_TYPE_PM_SUSPEND and REQ_TYPE_PM_RESUME
* requests. Some step values could eventually be made generic.
*/
struct request_pm_state
@@ -417,9 +466,9 @@ struct request_queue
unsigned int sg_timeout;
unsigned int sg_reserved_size;
int node;
-
+#ifdef CONFIG_BLK_DEV_IO_TRACE
struct blk_trace *blk_trace;
-
+#endif
/*
* reserved for flush operations
*/
@@ -432,9 +481,6 @@ struct request_queue
struct mutex sysfs_lock;
};
-#define RQ_INACTIVE (-1)
-#define RQ_ACTIVE 1
-
#define QUEUE_FLAG_CLUSTER 0 /* cluster several segments into 1 */
#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */
#define QUEUE_FLAG_STOPPED 2 /* queue is stopped */
@@ -490,25 +536,34 @@ enum {
#define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags)
#define blk_queue_flushing(q) ((q)->ordseq)
-#define blk_fs_request(rq) ((rq)->flags & REQ_CMD)
-#define blk_pc_request(rq) ((rq)->flags & REQ_BLOCK_PC)
-#define blk_noretry_request(rq) ((rq)->flags & REQ_FAILFAST)
-#define blk_rq_started(rq) ((rq)->flags & REQ_STARTED)
+#define blk_fs_request(rq) ((rq)->cmd_type == REQ_TYPE_FS)
+#define blk_pc_request(rq) ((rq)->cmd_type == REQ_TYPE_BLOCK_PC)
+#define blk_special_request(rq) ((rq)->cmd_type == REQ_TYPE_SPECIAL)
+#define blk_sense_request(rq) ((rq)->cmd_type == REQ_TYPE_SENSE)
+
+#define blk_noretry_request(rq) ((rq)->cmd_flags & REQ_FAILFAST)
+#define blk_rq_started(rq) ((rq)->cmd_flags & REQ_STARTED)
#define blk_account_rq(rq) (blk_rq_started(rq) && blk_fs_request(rq))
-#define blk_pm_suspend_request(rq) ((rq)->flags & REQ_PM_SUSPEND)
-#define blk_pm_resume_request(rq) ((rq)->flags & REQ_PM_RESUME)
+#define blk_pm_suspend_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_SUSPEND)
+#define blk_pm_resume_request(rq) ((rq)->cmd_type == REQ_TYPE_PM_RESUME)
#define blk_pm_request(rq) \
- ((rq)->flags & (REQ_PM_SUSPEND | REQ_PM_RESUME))
+ (blk_pm_suspend_request(rq) || blk_pm_resume_request(rq))
-#define blk_sorted_rq(rq) ((rq)->flags & REQ_SORTED)
-#define blk_barrier_rq(rq) ((rq)->flags & REQ_HARDBARRIER)
-#define blk_fua_rq(rq) ((rq)->flags & REQ_FUA)
+#define blk_sorted_rq(rq) ((rq)->cmd_flags & REQ_SORTED)
+#define blk_barrier_rq(rq) ((rq)->cmd_flags & REQ_HARDBARRIER)
+#define blk_fua_rq(rq) ((rq)->cmd_flags & REQ_FUA)
#define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist)
-#define rq_data_dir(rq) ((rq)->flags & 1)
+#define rq_data_dir(rq) ((rq)->cmd_flags & 1)
+
+/*
+ * We regard a request as sync, if it's a READ or a SYNC write.
+ */
+#define rq_is_sync(rq) (rq_data_dir((rq)) == READ || (rq)->cmd_flags & REQ_RW_SYNC)
+#define rq_is_meta(rq) ((rq)->cmd_flags & REQ_RW_META)
static inline int blk_queue_full(struct request_queue *q, int rw)
{
@@ -541,13 +596,7 @@ static inline void blk_clear_queue_full(struct request_queue *q, int rw)
#define RQ_NOMERGE_FLAGS \
(REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER)
#define rq_mergeable(rq) \
- (!((rq)->flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq)))
-
-/*
- * noop, requests are automagically marked as active/inactive by I/O
- * scheduler -- see elv_next_request
- */
-#define blk_queue_headactive(q, head_active)
+ (!((rq)->cmd_flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq)))
/*
* q->prep_rq_fn return values
@@ -586,11 +635,6 @@ static inline void blk_queue_bounce(request_queue_t *q, struct bio **bio)
if ((rq->bio)) \
for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next)
-struct sec_size {
- unsigned block_size;
- unsigned block_size_bits;
-};
-
extern int blk_register_queue(struct gendisk *disk);
extern void blk_unregister_queue(struct gendisk *disk);
extern void register_disk(struct gendisk *dev);
@@ -607,11 +651,32 @@ extern void blk_recount_segments(request_queue_t *, struct bio *);
extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
extern int sg_scsi_ioctl(struct file *, struct request_queue *,
struct gendisk *, struct scsi_ioctl_command __user *);
+
+/*
+ * A queue has just exitted congestion. Note this in the global counter of
+ * congested queues, and wake up anyone who was waiting for requests to be
+ * put back.
+ */
+static inline void blk_clear_queue_congested(request_queue_t *q, int rw)
+{
+ clear_bdi_congested(&q->backing_dev_info, rw);
+}
+
+/*
+ * A queue has just entered congestion. Flag that in the queue's VM-visible
+ * state flags and increment the global gounter of congested queues.
+ */
+static inline void blk_set_queue_congested(request_queue_t *q, int rw)
+{
+ set_bdi_congested(&q->backing_dev_info, rw);
+}
+
extern void blk_start_queue(request_queue_t *q);
extern void blk_stop_queue(request_queue_t *q);
extern void blk_sync_queue(struct request_queue *q);
extern void __blk_stop_queue(request_queue_t *q);
extern void blk_run_queue(request_queue_t *);
+extern void blk_start_queueing(request_queue_t *);
extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *);
extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int);
extern int blk_rq_unmap_user(struct bio *, unsigned int);
@@ -655,16 +720,6 @@ extern void end_that_request_last(struct request *, int);
extern void end_request(struct request *req, int uptodate);
extern void blk_complete_request(struct request *);
-static inline int rq_all_done(struct request *rq, unsigned int nr_bytes)
-{
- if (blk_fs_request(rq))
- return (nr_bytes >= (rq->hard_nr_sectors << 9));
- else if (blk_pc_request(rq))
- return nr_bytes >= rq->data_len;
-
- return 0;
-}
-
/*
* end_that_request_first/chunk() takes an uptodate argument. we account
* any value <= as an io error. 0 means -EIO for compatability reasons,
@@ -679,21 +734,6 @@ static inline void blkdev_dequeue_request(struct request *req)
}
/*
- * This should be in elevator.h, but that requires pulling in rq and q
- */
-static inline void elv_dispatch_add_tail(struct request_queue *q,
- struct request *rq)
-{
- if (q->last_merge == rq)
- q->last_merge = NULL;
- q->nr_sorted--;
-
- q->end_sector = rq_end_sector(rq);
- q->boundary_rq = rq;
- list_add_tail(&rq->queuelist, &q->queue_head);
-}
-
-/*
* Access functions for manipulating queue properties
*/
extern request_queue_t *blk_init_queue_node(request_fn_proc *rfn,
@@ -737,7 +777,7 @@ extern void blk_put_queue(request_queue_t *);
*/
#define blk_queue_tag_depth(q) ((q)->queue_tags->busy)
#define blk_queue_tag_queue(q) ((q)->queue_tags->busy < (q)->queue_tags->max_depth)
-#define blk_rq_tagged(rq) ((rq)->flags & REQ_QUEUED)
+#define blk_rq_tagged(rq) ((rq)->cmd_flags & REQ_QUEUED)
extern int blk_queue_start_tag(request_queue_t *, struct request *);
extern struct request *blk_queue_find_tag(request_queue_t *, int);
extern void blk_queue_end_tag(request_queue_t *, struct request *);
@@ -745,10 +785,16 @@ extern int blk_queue_init_tags(request_queue_t *, int, struct blk_queue_tag *);
extern void blk_queue_free_tags(request_queue_t *);
extern int blk_queue_resize_tags(request_queue_t *, int);
extern void blk_queue_invalidate_tags(request_queue_t *);
-extern long blk_congestion_wait(int rw, long timeout);
extern struct blk_queue_tag *blk_init_tags(int);
extern void blk_free_tags(struct blk_queue_tag *);
-extern void blk_congestion_end(int rw);
+
+static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
+ int tag)
+{
+ if (unlikely(bqt == NULL || tag >= bqt->real_max_depth))
+ return NULL;
+ return bqt->tag_index[tag];
+}
extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *);
extern int blkdev_issue_flush(struct block_device *, sector_t *);
@@ -787,14 +833,6 @@ static inline int queue_dma_alignment(request_queue_t *q)
return retval;
}
-static inline int bdev_dma_aligment(struct block_device *bdev)
-{
- return queue_dma_alignment(bdev_get_queue(bdev));
-}
-
-#define blk_finished_io(nsects) do { } while (0)
-#define blk_started_io(nsects) do { } while (0)
-
/* assumes size > 256 */
static inline unsigned int blksize_bits(unsigned int size)
{
@@ -824,24 +862,32 @@ struct work_struct;
int kblockd_schedule_work(struct work_struct *work);
void kblockd_flush(void);
-#ifdef CONFIG_LBD
-# include <asm/div64.h>
-# define sector_div(a, b) do_div(a, b)
-#else
-# define sector_div(n, b)( \
-{ \
- int _res; \
- _res = (n) % (b); \
- (n) /= (b); \
- _res; \
-} \
-)
-#endif
-
#define MODULE_ALIAS_BLOCKDEV(major,minor) \
MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor))
#define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \
MODULE_ALIAS("block-major-" __stringify(major) "-*")
+#else /* CONFIG_BLOCK */
+/*
+ * stubs for when the block layer is configured out
+ */
+#define buffer_heads_over_limit 0
+
+static inline long blk_congestion_wait(int rw, long timeout)
+{
+ return io_schedule_timeout(timeout);
+}
+
+static inline long nr_blockdev_pages(void)
+{
+ return 0;
+}
+
+static inline void exit_io_context(void)
+{
+}
+
+#endif /* CONFIG_BLOCK */
+
#endif
diff --git a/include/linux/blktrace_api.h b/include/linux/blktrace_api.h
index 7520cc1ff9e2..b99a714fcac6 100644
--- a/include/linux/blktrace_api.h
+++ b/include/linux/blktrace_api.h
@@ -20,6 +20,7 @@ enum blktrace_cat {
BLK_TC_PC = 1 << 9, /* pc requests */
BLK_TC_NOTIFY = 1 << 10, /* special message */
BLK_TC_AHEAD = 1 << 11, /* readahead */
+ BLK_TC_META = 1 << 12, /* metadata */
BLK_TC_END = 1 << 15, /* only 16-bits, reminder */
};
@@ -148,7 +149,7 @@ static inline void blk_add_trace_rq(struct request_queue *q, struct request *rq,
u32 what)
{
struct blk_trace *bt = q->blk_trace;
- int rw = rq->flags & 0x03;
+ int rw = rq->cmd_flags & 0x03;
if (likely(!bt))
return;
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 737e407d0cd1..5d9fb0e94156 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -14,6 +14,8 @@
#include <linux/wait.h>
#include <asm/atomic.h>
+#ifdef CONFIG_BLOCK
+
enum bh_state_bits {
BH_Uptodate, /* Contains valid data */
BH_Dirty, /* Is dirty */
@@ -67,6 +69,8 @@ struct buffer_head {
bh_end_io_t *b_end_io; /* I/O completion */
void *b_private; /* reserved for b_end_io */
struct list_head b_assoc_buffers; /* associated with another mapping */
+ struct address_space *b_assoc_map; /* mapping this buffer is
+ associated with */
atomic_t b_count; /* users using this buffer_head */
};
@@ -190,9 +194,7 @@ extern int buffer_heads_over_limit;
* Generic address_space_operations implementations for buffer_head-backed
* address_spaces.
*/
-int try_to_release_page(struct page * page, gfp_t gfp_mask);
void block_invalidatepage(struct page *page, unsigned long offset);
-void do_invalidatepage(struct page *page, unsigned long offset);
int block_write_full_page(struct page *page, get_block_t *get_block,
struct writeback_control *wbc);
int block_read_full_page(struct page*, get_block_t*);
@@ -302,4 +304,19 @@ static inline void lock_buffer(struct buffer_head *bh)
__lock_buffer(bh);
}
+extern int __set_page_dirty_buffers(struct page *page);
+
+#else /* CONFIG_BLOCK */
+
+static inline void buffer_init(void) {}
+static inline int try_to_free_buffers(struct page *page) { return 1; }
+static inline int sync_blockdev(struct block_device *bdev) { return 0; }
+static inline int inode_has_buffers(struct inode *inode) { return 0; }
+static inline void invalidate_inode_buffers(struct inode *inode) {}
+static inline int remove_inode_buffers(struct inode *inode) { return 1; }
+static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; }
+static inline void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers) {}
+
+
+#endif /* CONFIG_BLOCK */
#endif /* _LINUX_BUFFER_HEAD_H */
diff --git a/include/linux/carta_random32.h b/include/linux/carta_random32.h
new file mode 100644
index 000000000000..f6f3bd9f20b5
--- /dev/null
+++ b/include/linux/carta_random32.h
@@ -0,0 +1,29 @@
+/*
+ * Fast, simple, yet decent quality random number generator based on
+ * a paper by David G. Carta ("Two Fast Implementations of the
+ * `Minimal Standard' Random Number Generator," Communications of the
+ * ACM, January, 1990).
+ *
+ * Copyright (c) 2002-2006 Hewlett-Packard Development Company, L.P.
+ * Contributed by Stephane Eranian <eranian@hpl.hp.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it 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_CARTA_RANDOM32_H_
+#define _LINUX_CARTA_RANDOM32_H_
+
+u64 carta_random32(u64 seed);
+
+#endif /* _LINUX_CARTA_RANDOM32_H_ */
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index 2216638962d2..ee5f53f2ca15 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -23,5 +23,7 @@ void cdev_del(struct cdev *);
void cd_forget(struct inode *);
+extern struct backing_dev_info directly_mappable_cdev_bdi;
+
#endif
#endif
diff --git a/include/linux/cdrom.h b/include/linux/cdrom.h
index 3c9b0bc05123..bbbe7b4da0bb 100644
--- a/include/linux/cdrom.h
+++ b/include/linux/cdrom.h
@@ -749,7 +749,7 @@ struct request_sense {
#define MRW_MODE_PC 0x03
struct mrw_feature_desc {
- __u16 feature_code;
+ __be16 feature_code;
#if defined(__BIG_ENDIAN_BITFIELD)
__u8 reserved1 : 2;
__u8 feature_version : 4;
@@ -776,7 +776,7 @@ struct mrw_feature_desc {
/* cf. mmc4r02g.pdf 5.3.10 Random Writable Feature (0020h) pg 197 of 635 */
struct rwrt_feature_desc {
- __u16 feature_code;
+ __be16 feature_code;
#if defined(__BIG_ENDIAN_BITFIELD)
__u8 reserved1 : 2;
__u8 feature_version : 4;
@@ -803,7 +803,7 @@ struct rwrt_feature_desc {
};
typedef struct {
- __u16 disc_information_length;
+ __be16 disc_information_length;
#if defined(__BIG_ENDIAN_BITFIELD)
__u8 reserved1 : 3;
__u8 erasable : 1;
@@ -849,7 +849,7 @@ typedef struct {
} disc_information;
typedef struct {
- __u16 track_information_length;
+ __be16 track_information_length;
__u8 track_lsb;
__u8 session_lsb;
__u8 reserved1;
@@ -880,12 +880,12 @@ typedef struct {
__u8 lra_v : 1;
__u8 reserved3 : 6;
#endif
- __u32 track_start;
- __u32 next_writable;
- __u32 free_blocks;
- __u32 fixed_packet_size;
- __u32 track_size;
- __u32 last_rec_address;
+ __be32 track_start;
+ __be32 next_writable;
+ __be32 free_blocks;
+ __be32 fixed_packet_size;
+ __be32 track_size;
+ __be32 last_rec_address;
} track_information;
struct feature_header {
@@ -896,12 +896,12 @@ struct feature_header {
};
struct mode_page_header {
- __u16 mode_data_length;
+ __be16 mode_data_length;
__u8 medium_type;
__u8 reserved1;
__u8 reserved2;
__u8 reserved3;
- __u16 desc_length;
+ __be16 desc_length;
};
#ifdef __KERNEL__
@@ -1106,7 +1106,7 @@ typedef struct {
#endif
__u8 session_format;
__u8 reserved6;
- __u32 packet_size;
+ __be32 packet_size;
__u16 audio_pause;
__u8 mcn[16];
__u8 isrc[16];
@@ -1151,7 +1151,7 @@ typedef struct {
} rpc_state_t;
struct event_header {
- __u16 data_len;
+ __be16 data_len;
#if defined(__BIG_ENDIAN_BITFIELD)
__u8 nea : 1;
__u8 reserved1 : 4;
diff --git a/include/linux/compat.h b/include/linux/compat.h
index 9760753e662b..f4ebf96f5308 100644
--- a/include/linux/compat.h
+++ b/include/linux/compat.h
@@ -13,6 +13,7 @@
#include <asm/compat.h>
#include <asm/siginfo.h>
+#include <asm/signal.h>
#define compat_jiffies_to_clock_t(x) \
(((unsigned long)(x) * COMPAT_USER_HZ) / HZ)
@@ -162,7 +163,7 @@ asmlinkage long
compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
compat_size_t len);
asmlinkage long
-compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr,
+compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
compat_size_t __user *len_ptr);
long compat_sys_semctl(int first, int second, int third, void __user *uptr);
@@ -227,6 +228,7 @@ static inline int compat_timespec_compare(struct compat_timespec *lhs,
asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp);
extern int compat_printk(const char *fmt, ...);
+extern void sigset_from_compat(sigset_t *set, compat_sigset_t *compat);
#endif /* CONFIG_COMPAT */
#endif /* _LINUX_COMPAT_H */
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index bea0255196c4..c26c3adcfacf 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -61,17 +61,23 @@ COMPATIBLE_IOCTL(FIGETBSZ)
* Some need translations, these do not.
*/
COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
-COMPATIBLE_IOCTL(HDIO_SET_DMA)
-COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR)
-COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
-COMPATIBLE_IOCTL(HDIO_SET_32BIT)
-COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
-COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
COMPATIBLE_IOCTL(HDIO_DRIVE_TASK)
-COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
-COMPATIBLE_IOCTL(HDIO_SET_NICE)
-COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS)
+COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
+ULONG_IOCTL(HDIO_SET_MULTCOUNT)
+ULONG_IOCTL(HDIO_SET_UNMASKINTR)
+ULONG_IOCTL(HDIO_SET_KEEPSETTINGS)
+ULONG_IOCTL(HDIO_SET_32BIT)
+ULONG_IOCTL(HDIO_SET_NOWERR)
+ULONG_IOCTL(HDIO_SET_DMA)
+ULONG_IOCTL(HDIO_SET_PIO_MODE)
+ULONG_IOCTL(HDIO_SET_NICE)
+ULONG_IOCTL(HDIO_SET_WCACHE)
+ULONG_IOCTL(HDIO_SET_ACOUSTIC)
+ULONG_IOCTL(HDIO_SET_BUSSTATE)
+ULONG_IOCTL(HDIO_SET_ADDRESS)
COMPATIBLE_IOCTL(HDIO_SCAN_HWIF)
+/* 0x330 is reserved -- it used to be HDIO_GETGEO_BIG */
+COMPATIBLE_IOCTL(0x330)
/* 0x02 -- Floppy ioctls */
COMPATIBLE_IOCTL(FDMSGON)
COMPATIBLE_IOCTL(FDMSGOFF)
@@ -90,6 +96,7 @@ COMPATIBLE_IOCTL(FDTWADDLE)
COMPATIBLE_IOCTL(FDFMTTRK)
COMPATIBLE_IOCTL(FDRAWCMD)
/* 0x12 */
+#ifdef CONFIG_BLOCK
COMPATIBLE_IOCTL(BLKRASET)
COMPATIBLE_IOCTL(BLKROSET)
COMPATIBLE_IOCTL(BLKROGET)
@@ -103,6 +110,7 @@ COMPATIBLE_IOCTL(BLKTRACESETUP)
COMPATIBLE_IOCTL(BLKTRACETEARDOWN)
ULONG_IOCTL(BLKRASET)
ULONG_IOCTL(BLKFRASET)
+#endif
/* RAID */
COMPATIBLE_IOCTL(RAID_VERSION)
COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -120,10 +128,11 @@ COMPATIBLE_IOCTL(PROTECT_ARRAY)
ULONG_IOCTL(HOT_ADD_DISK)
ULONG_IOCTL(SET_DISK_FAULTY)
COMPATIBLE_IOCTL(RUN_ARRAY)
-ULONG_IOCTL(START_ARRAY)
COMPATIBLE_IOCTL(STOP_ARRAY)
COMPATIBLE_IOCTL(STOP_ARRAY_RO)
COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
+COMPATIBLE_IOCTL(GET_BITMAP_FILE)
+ULONG_IOCTL(SET_BITMAP_FILE)
/* DM */
COMPATIBLE_IOCTL(DM_VERSION_32)
COMPATIBLE_IOCTL(DM_REMOVE_ALL_32)
@@ -395,12 +404,6 @@ COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
COMPATIBLE_IOCTL(DVD_AUTH)
/* pktcdvd */
COMPATIBLE_IOCTL(PACKET_CTRL_CMD)
-/* Big L */
-ULONG_IOCTL(LOOP_SET_FD)
-ULONG_IOCTL(LOOP_CHANGE_FD)
-COMPATIBLE_IOCTL(LOOP_CLR_FD)
-COMPATIBLE_IOCTL(LOOP_GET_STATUS64)
-COMPATIBLE_IOCTL(LOOP_SET_STATUS64)
/* Big A */
/* sparc only */
/* Big Q for sound/OSS */
@@ -573,18 +576,6 @@ COMPATIBLE_IOCTL(RAW_SETBIND)
COMPATIBLE_IOCTL(RAW_GETBIND)
/* SMB ioctls which do not need any translations */
COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
-/* NCP ioctls which do not need any translations */
-COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
-COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
-COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED)
-COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED)
-COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK)
-COMPATIBLE_IOCTL(NCP_IOC_GETROOT)
-COMPATIBLE_IOCTL(NCP_IOC_SETROOT)
-COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS)
-COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS)
-COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL)
-COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL)
/* Little a */
COMPATIBLE_IOCTL(ATMSIGD_CTRL)
COMPATIBLE_IOCTL(ATMARPD_CTRL)
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index 060b96112ec6..538423d4a865 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -10,11 +10,11 @@
# define __force __attribute__((force))
# define __nocast __attribute__((nocast))
# define __iomem __attribute__((noderef, address_space(2)))
-# define __acquires(x) __attribute__((context(0,1)))
-# define __releases(x) __attribute__((context(1,0)))
-# define __acquire(x) __context__(1)
-# define __release(x) __context__(-1)
-# define __cond_lock(x) ((x) ? ({ __context__(1); 1; }) : 0)
+# define __acquires(x) __attribute__((context(x,0,1)))
+# define __releases(x) __attribute__((context(x,1,0)))
+# define __acquire(x) __context__(x,1)
+# define __release(x) __context__(x,-1)
+# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0)
extern void __chk_user_ptr(void __user *);
extern void __chk_io_ptr(void __iomem *);
#else
@@ -31,7 +31,7 @@ extern void __chk_io_ptr(void __iomem *);
# define __releases(x)
# define __acquire(x) (void)0
# define __release(x) (void)0
-# define __cond_lock(x) (x)
+# define __cond_lock(x,c) (c)
#endif
#ifdef __KERNEL__
diff --git a/include/linux/config.h b/include/linux/config.h
deleted file mode 100644
index a91f5e55b525..000000000000
--- a/include/linux/config.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef _LINUX_CONFIG_H
-#define _LINUX_CONFIG_H
-/* This file is no longer in use and kept only for backward compatibility.
- * autoconf.h is now included via -imacros on the commandline
- */
-#include <linux/autoconf.h>
-
-#endif
diff --git a/include/linux/console.h b/include/linux/console.h
index 76a1807726eb..7d0420274de0 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -129,6 +129,9 @@ static inline void suspend_console(void) {}
static inline void resume_console(void) {}
#endif /* CONFIG_DISABLE_CONSOLE_SUSPEND */
+int mda_console_init(void);
+void prom_con_init(void);
+
/* Some debug stub to catch some of the obvious races in the VT code */
#if 1
#define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress)
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index 25423f79bf9f..ed6c0fee1ac7 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -54,7 +54,7 @@ struct vc_data {
struct tty_struct *vc_tty; /* TTY we are attached to */
/* data for manual vt switching */
struct vt_mode vt_mode;
- int vt_pid;
+ struct pid *vt_pid;
int vt_newvt;
wait_queue_head_t paste_wait;
/* mode flags */
diff --git a/include/linux/consolemap.h b/include/linux/consolemap.h
index 65842efc1b70..82c9a1f11020 100644
--- a/include/linux/consolemap.h
+++ b/include/linux/consolemap.h
@@ -13,3 +13,4 @@ struct vc_data;
extern unsigned char inverse_translate(struct vc_data *conp, int glyph);
extern unsigned short *set_translate(int m, struct vc_data *vc);
extern int conv_uni_to_pc(struct vc_data *conp, long ucs);
+void console_map_init(void);
diff --git a/include/linux/cpumask.h b/include/linux/cpumask.h
index b268a3c0c376..d0e8c8b0e34d 100644
--- a/include/linux/cpumask.h
+++ b/include/linux/cpumask.h
@@ -8,8 +8,8 @@
* See detailed comments in the file linux/bitmap.h describing the
* data type on which these cpumasks are based.
*
- * For details of cpumask_scnprintf() and cpumask_parse(),
- * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ * For details of cpumask_scnprintf() and cpumask_parse_user(),
+ * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
* For details of cpulist_scnprintf() and cpulist_parse(), see
* bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
* For details of cpu_remap(), see bitmap_bitremap in lib/bitmap.c
@@ -49,7 +49,7 @@
* unsigned long *cpus_addr(mask) Array of unsigned long's in mask
*
* int cpumask_scnprintf(buf, len, mask) Format cpumask for printing
- * int cpumask_parse(ubuf, ulen, mask) Parse ascii string as cpumask
+ * int cpumask_parse_user(ubuf, ulen, mask) Parse ascii string as cpumask
* int cpulist_scnprintf(buf, len, mask) Format cpumask as list for printing
* int cpulist_parse(buf, map) Parse ascii string as cpulist
* int cpu_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
@@ -273,12 +273,12 @@ static inline int __cpumask_scnprintf(char *buf, int len,
return bitmap_scnprintf(buf, len, srcp->bits, nbits);
}
-#define cpumask_parse(ubuf, ulen, dst) \
- __cpumask_parse((ubuf), (ulen), &(dst), NR_CPUS)
-static inline int __cpumask_parse(const char __user *buf, int len,
+#define cpumask_parse_user(ubuf, ulen, dst) \
+ __cpumask_parse_user((ubuf), (ulen), &(dst), NR_CPUS)
+static inline int __cpumask_parse_user(const char __user *buf, int len,
cpumask_t *dstp, int nbits)
{
- return bitmap_parse(buf, len, dstp->bits, nbits);
+ return bitmap_parse_user(buf, len, dstp->bits, nbits);
}
#define cpulist_scnprintf(buf, len, src) \
diff --git a/include/linux/cpuset.h b/include/linux/cpuset.h
index 9354722a9217..4d8adf663681 100644
--- a/include/linux/cpuset.h
+++ b/include/linux/cpuset.h
@@ -63,6 +63,8 @@ static inline int cpuset_do_slab_mem_spread(void)
return current->flags & PF_SPREAD_SLAB;
}
+extern void cpuset_track_online_nodes(void);
+
#else /* !CONFIG_CPUSETS */
static inline int cpuset_init_early(void) { return 0; }
@@ -126,6 +128,8 @@ static inline int cpuset_do_slab_mem_spread(void)
return 0;
}
+static inline void cpuset_track_online_nodes(void) {}
+
#endif /* !CONFIG_CPUSETS */
#endif /* _LINUX_CPUSET_H */
diff --git a/include/linux/cramfs_fs.h b/include/linux/cramfs_fs.h
index a41f38428c37..1dba681e428d 100644
--- a/include/linux/cramfs_fs.h
+++ b/include/linux/cramfs_fs.h
@@ -87,6 +87,6 @@ struct cramfs_super {
/* Uncompression interfaces to the underlying zlib */
int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen);
int cramfs_uncompress_init(void);
-int cramfs_uncompress_exit(void);
+void cramfs_uncompress_exit(void);
#endif
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index 44605be59409..63f64a9a5bf7 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -230,6 +230,7 @@ extern struct dentry * d_alloc_anon(struct inode *);
extern struct dentry * d_splice_alias(struct inode *, struct dentry *);
extern void shrink_dcache_sb(struct super_block *);
extern void shrink_dcache_parent(struct dentry *);
+extern void shrink_dcache_for_umount(struct super_block *);
extern int d_invalidate(struct dentry *);
/* only used at mount-time */
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index d6f4ec467a4b..53553c99cad6 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -191,7 +191,7 @@ enum {
/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */
struct dccp_so_feat {
__u8 dccpsf_feat;
- __u8 *dccpsf_val;
+ __u8 __user *dccpsf_val;
__u8 dccpsf_len;
};
diff --git a/include/linux/debug_locks.h b/include/linux/debug_locks.h
index 88dafa246d87..952bee79a8f3 100644
--- a/include/linux/debug_locks.h
+++ b/include/linux/debug_locks.h
@@ -43,6 +43,8 @@ extern int debug_locks_off(void);
# define locking_selftest() do { } while (0)
#endif
+struct task_struct;
+
#ifdef CONFIG_LOCKDEP
extern void debug_show_all_locks(void);
extern void debug_show_held_locks(struct task_struct *task);
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index e3d1c33d1558..03ef41c1eaac 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -55,8 +55,10 @@ typedef int (*dm_endio_fn) (struct dm_target *ti,
struct bio *bio, int error,
union map_info *map_context);
+typedef void (*dm_flush_fn) (struct dm_target *ti);
typedef void (*dm_presuspend_fn) (struct dm_target *ti);
typedef void (*dm_postsuspend_fn) (struct dm_target *ti);
+typedef int (*dm_preresume_fn) (struct dm_target *ti);
typedef void (*dm_resume_fn) (struct dm_target *ti);
typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
@@ -64,9 +66,18 @@ typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type,
typedef int (*dm_message_fn) (struct dm_target *ti, unsigned argc, char **argv);
+typedef int (*dm_ioctl_fn) (struct dm_target *ti, struct inode *inode,
+ struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
void dm_error(const char *message);
/*
+ * Combine device limits.
+ */
+void dm_set_device_limits(struct dm_target *ti, struct block_device *bdev);
+
+/*
* Constructors should call these functions to ensure destination devices
* are opened/closed correctly.
* FIXME: too many arguments.
@@ -86,11 +97,14 @@ struct target_type {
dm_dtr_fn dtr;
dm_map_fn map;
dm_endio_fn end_io;
+ dm_flush_fn flush;
dm_presuspend_fn presuspend;
dm_postsuspend_fn postsuspend;
+ dm_preresume_fn preresume;
dm_resume_fn resume;
dm_status_fn status;
dm_message_fn message;
+ dm_ioctl_fn ioctl;
};
struct io_restrictions {
diff --git a/include/linux/dlm.h b/include/linux/dlm.h
new file mode 100644
index 000000000000..1b1dcb9a40bb
--- /dev/null
+++ b/include/linux/dlm.h
@@ -0,0 +1,302 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+#ifndef __DLM_DOT_H__
+#define __DLM_DOT_H__
+
+/*
+ * Interface to Distributed Lock Manager (DLM)
+ * routines and structures to use DLM lockspaces
+ */
+
+/*
+ * Lock Modes
+ */
+
+#define DLM_LOCK_IV -1 /* invalid */
+#define DLM_LOCK_NL 0 /* null */
+#define DLM_LOCK_CR 1 /* concurrent read */
+#define DLM_LOCK_CW 2 /* concurrent write */
+#define DLM_LOCK_PR 3 /* protected read */
+#define DLM_LOCK_PW 4 /* protected write */
+#define DLM_LOCK_EX 5 /* exclusive */
+
+/*
+ * Maximum size in bytes of a dlm_lock name
+ */
+
+#define DLM_RESNAME_MAXLEN 64
+
+/*
+ * Flags to dlm_lock
+ *
+ * DLM_LKF_NOQUEUE
+ *
+ * Do not queue the lock request on the wait queue if it cannot be granted
+ * immediately. If the lock cannot be granted because of this flag, DLM will
+ * either return -EAGAIN from the dlm_lock call or will return 0 from
+ * dlm_lock and -EAGAIN in the lock status block when the AST is executed.
+ *
+ * DLM_LKF_CANCEL
+ *
+ * Used to cancel a pending lock request or conversion. A converting lock is
+ * returned to its previously granted mode.
+ *
+ * DLM_LKF_CONVERT
+ *
+ * Indicates a lock conversion request. For conversions the name and namelen
+ * are ignored and the lock ID in the LKSB is used to identify the lock.
+ *
+ * DLM_LKF_VALBLK
+ *
+ * Requests DLM to return the current contents of the lock value block in the
+ * lock status block. When this flag is set in a lock conversion from PW or EX
+ * modes, DLM assigns the value specified in the lock status block to the lock
+ * value block of the lock resource. The LVB is a DLM_LVB_LEN size array
+ * containing application-specific information.
+ *
+ * DLM_LKF_QUECVT
+ *
+ * Force a conversion request to be queued, even if it is compatible with
+ * the granted modes of other locks on the same resource.
+ *
+ * DLM_LKF_IVVALBLK
+ *
+ * Invalidate the lock value block.
+ *
+ * DLM_LKF_CONVDEADLK
+ *
+ * Allows the dlm to resolve conversion deadlocks internally by demoting the
+ * granted mode of a converting lock to NL. The DLM_SBF_DEMOTED flag is
+ * returned for a conversion that's been effected by this.
+ *
+ * DLM_LKF_PERSISTENT
+ *
+ * Only relevant to locks originating in userspace. A persistent lock will not
+ * be removed if the process holding the lock exits.
+ *
+ * DLM_LKF_NODLKWT
+ * DLM_LKF_NODLCKBLK
+ *
+ * net yet implemented
+ *
+ * DLM_LKF_EXPEDITE
+ *
+ * Used only with new requests for NL mode locks. Tells the lock manager
+ * to grant the lock, ignoring other locks in convert and wait queues.
+ *
+ * DLM_LKF_NOQUEUEBAST
+ *
+ * Send blocking AST's before returning -EAGAIN to the caller. It is only
+ * used along with the NOQUEUE flag. Blocking AST's are not sent for failed
+ * NOQUEUE requests otherwise.
+ *
+ * DLM_LKF_HEADQUE
+ *
+ * Add a lock to the head of the convert or wait queue rather than the tail.
+ *
+ * DLM_LKF_NOORDER
+ *
+ * Disregard the standard grant order rules and grant a lock as soon as it
+ * is compatible with other granted locks.
+ *
+ * DLM_LKF_ORPHAN
+ *
+ * not yet implemented
+ *
+ * DLM_LKF_ALTPR
+ *
+ * If the requested mode cannot be granted immediately, try to grant the lock
+ * in PR mode instead. If this alternate mode is granted instead of the
+ * requested mode, DLM_SBF_ALTMODE is returned in the lksb.
+ *
+ * DLM_LKF_ALTCW
+ *
+ * The same as ALTPR, but the alternate mode is CW.
+ *
+ * DLM_LKF_FORCEUNLOCK
+ *
+ * Unlock the lock even if it is converting or waiting or has sublocks.
+ * Only really for use by the userland device.c code.
+ *
+ */
+
+#define DLM_LKF_NOQUEUE 0x00000001
+#define DLM_LKF_CANCEL 0x00000002
+#define DLM_LKF_CONVERT 0x00000004
+#define DLM_LKF_VALBLK 0x00000008
+#define DLM_LKF_QUECVT 0x00000010
+#define DLM_LKF_IVVALBLK 0x00000020
+#define DLM_LKF_CONVDEADLK 0x00000040
+#define DLM_LKF_PERSISTENT 0x00000080
+#define DLM_LKF_NODLCKWT 0x00000100
+#define DLM_LKF_NODLCKBLK 0x00000200
+#define DLM_LKF_EXPEDITE 0x00000400
+#define DLM_LKF_NOQUEUEBAST 0x00000800
+#define DLM_LKF_HEADQUE 0x00001000
+#define DLM_LKF_NOORDER 0x00002000
+#define DLM_LKF_ORPHAN 0x00004000
+#define DLM_LKF_ALTPR 0x00008000
+#define DLM_LKF_ALTCW 0x00010000
+#define DLM_LKF_FORCEUNLOCK 0x00020000
+
+/*
+ * Some return codes that are not in errno.h
+ */
+
+#define DLM_ECANCEL 0x10001
+#define DLM_EUNLOCK 0x10002
+
+typedef void dlm_lockspace_t;
+
+/*
+ * Lock status block
+ *
+ * Use this structure to specify the contents of the lock value block. For a
+ * conversion request, this structure is used to specify the lock ID of the
+ * lock. DLM writes the status of the lock request and the lock ID assigned
+ * to the request in the lock status block.
+ *
+ * sb_lkid: the returned lock ID. It is set on new (non-conversion) requests.
+ * It is available when dlm_lock returns.
+ *
+ * sb_lvbptr: saves or returns the contents of the lock's LVB according to rules
+ * shown for the DLM_LKF_VALBLK flag.
+ *
+ * sb_flags: DLM_SBF_DEMOTED is returned if in the process of promoting a lock,
+ * it was first demoted to NL to avoid conversion deadlock.
+ * DLM_SBF_VALNOTVALID is returned if the resource's LVB is marked invalid.
+ *
+ * sb_status: the returned status of the lock request set prior to AST
+ * execution. Possible return values:
+ *
+ * 0 if lock request was successful
+ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
+ * -ENOMEM if there is no memory to process request
+ * -EINVAL if there are invalid parameters
+ * -DLM_EUNLOCK if unlock request was successful
+ * -DLM_ECANCEL if a cancel completed successfully
+ */
+
+#define DLM_SBF_DEMOTED 0x01
+#define DLM_SBF_VALNOTVALID 0x02
+#define DLM_SBF_ALTMODE 0x04
+
+struct dlm_lksb {
+ int sb_status;
+ uint32_t sb_lkid;
+ char sb_flags;
+ char * sb_lvbptr;
+};
+
+
+#ifdef __KERNEL__
+
+#define DLM_LSFL_NODIR 0x00000001
+
+/*
+ * dlm_new_lockspace
+ *
+ * Starts a lockspace with the given name. If the named lockspace exists in
+ * the cluster, the calling node joins it.
+ */
+
+int dlm_new_lockspace(char *name, int namelen, dlm_lockspace_t **lockspace,
+ uint32_t flags, int lvblen);
+
+/*
+ * dlm_release_lockspace
+ *
+ * Stop a lockspace.
+ */
+
+int dlm_release_lockspace(dlm_lockspace_t *lockspace, int force);
+
+/*
+ * dlm_lock
+ *
+ * Make an asyncronous request to acquire or convert a lock on a named
+ * resource.
+ *
+ * lockspace: context for the request
+ * mode: the requested mode of the lock (DLM_LOCK_)
+ * lksb: lock status block for input and async return values
+ * flags: input flags (DLM_LKF_)
+ * name: name of the resource to lock, can be binary
+ * namelen: the length in bytes of the resource name (MAX_RESNAME_LEN)
+ * parent: the lock ID of a parent lock or 0 if none
+ * lockast: function DLM executes when it completes processing the request
+ * astarg: argument passed to lockast and bast functions
+ * bast: function DLM executes when this lock later blocks another request
+ *
+ * Returns:
+ * 0 if request is successfully queued for processing
+ * -EINVAL if any input parameters are invalid
+ * -EAGAIN if request would block and is flagged DLM_LKF_NOQUEUE
+ * -ENOMEM if there is no memory to process request
+ * -ENOTCONN if there is a communication error
+ *
+ * If the call to dlm_lock returns an error then the operation has failed and
+ * the AST routine will not be called. If dlm_lock returns 0 it is still
+ * possible that the lock operation will fail. The AST routine will be called
+ * when the locking is complete and the status is returned in the lksb.
+ *
+ * If the AST routines or parameter are passed to a conversion operation then
+ * they will overwrite those values that were passed to a previous dlm_lock
+ * call.
+ *
+ * AST routines should not block (at least not for long), but may make
+ * any locking calls they please.
+ */
+
+int dlm_lock(dlm_lockspace_t *lockspace,
+ int mode,
+ struct dlm_lksb *lksb,
+ uint32_t flags,
+ void *name,
+ unsigned int namelen,
+ uint32_t parent_lkid,
+ void (*lockast) (void *astarg),
+ void *astarg,
+ void (*bast) (void *astarg, int mode));
+
+/*
+ * dlm_unlock
+ *
+ * Asynchronously release a lock on a resource. The AST routine is called
+ * when the resource is successfully unlocked.
+ *
+ * lockspace: context for the request
+ * lkid: the lock ID as returned in the lksb
+ * flags: input flags (DLM_LKF_)
+ * lksb: if NULL the lksb parameter passed to last lock request is used
+ * astarg: the arg used with the completion ast for the unlock
+ *
+ * Returns:
+ * 0 if request is successfully queued for processing
+ * -EINVAL if any input parameters are invalid
+ * -ENOTEMPTY if the lock still has sublocks
+ * -EBUSY if the lock is waiting for a remote lock operation
+ * -ENOTCONN if there is a communication error
+ */
+
+int dlm_unlock(dlm_lockspace_t *lockspace,
+ uint32_t lkid,
+ uint32_t flags,
+ struct dlm_lksb *lksb,
+ void *astarg);
+
+#endif /* __KERNEL__ */
+
+#endif /* __DLM_DOT_H__ */
+
diff --git a/include/linux/dlm_device.h b/include/linux/dlm_device.h
new file mode 100644
index 000000000000..2a2dd189b9fd
--- /dev/null
+++ b/include/linux/dlm_device.h
@@ -0,0 +1,86 @@
+/******************************************************************************
+*******************************************************************************
+**
+** Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+** Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved.
+**
+** This copyrighted material is made available to anyone wishing to use,
+** modify, copy, or redistribute it subject to the terms and conditions
+** of the GNU General Public License v.2.
+**
+*******************************************************************************
+******************************************************************************/
+
+/* This is the device interface for dlm, most users will use a library
+ * interface.
+ */
+
+#define DLM_USER_LVB_LEN 32
+
+/* Version of the device interface */
+#define DLM_DEVICE_VERSION_MAJOR 5
+#define DLM_DEVICE_VERSION_MINOR 0
+#define DLM_DEVICE_VERSION_PATCH 0
+
+/* struct passed to the lock write */
+struct dlm_lock_params {
+ __u8 mode;
+ __u8 namelen;
+ __u16 flags;
+ __u32 lkid;
+ __u32 parent;
+ void __user *castparam;
+ void __user *castaddr;
+ void __user *bastparam;
+ void __user *bastaddr;
+ struct dlm_lksb __user *lksb;
+ char lvb[DLM_USER_LVB_LEN];
+ char name[0];
+};
+
+struct dlm_lspace_params {
+ __u32 flags;
+ __u32 minor;
+ char name[0];
+};
+
+struct dlm_write_request {
+ __u32 version[3];
+ __u8 cmd;
+ __u8 is64bit;
+ __u8 unused[2];
+
+ union {
+ struct dlm_lock_params lock;
+ struct dlm_lspace_params lspace;
+ } i;
+};
+
+/* struct read from the "device" fd,
+ consists mainly of userspace pointers for the library to use */
+struct dlm_lock_result {
+ __u32 length;
+ void __user * user_astaddr;
+ void __user * user_astparam;
+ struct dlm_lksb __user * user_lksb;
+ struct dlm_lksb lksb;
+ __u8 bast_mode;
+ __u8 unused[3];
+ /* Offsets may be zero if no data is present */
+ __u32 lvb_offset;
+};
+
+/* Commands passed to the device */
+#define DLM_USER_LOCK 1
+#define DLM_USER_UNLOCK 2
+#define DLM_USER_QUERY 3
+#define DLM_USER_CREATE_LOCKSPACE 4
+#define DLM_USER_REMOVE_LOCKSPACE 5
+
+/* Arbitrary length restriction */
+#define MAX_LS_NAME_LEN 64
+
+/* Lockspace flags */
+#define DLM_USER_LSFLG_AUTOFREE 1
+#define DLM_USER_LSFLG_FORCEFREE 2
+
diff --git a/include/linux/dm-ioctl.h b/include/linux/dm-ioctl.h
index 9623bb625090..8853fc4d1c5e 100644
--- a/include/linux/dm-ioctl.h
+++ b/include/linux/dm-ioctl.h
@@ -285,9 +285,9 @@ typedef char ioctl_struct[308];
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
#define DM_VERSION_MAJOR 4
-#define DM_VERSION_MINOR 7
+#define DM_VERSION_MINOR 10
#define DM_VERSION_PATCHLEVEL 0
-#define DM_VERSION_EXTRA "-ioctl (2006-06-24)"
+#define DM_VERSION_EXTRA "-ioctl (2006-09-14)"
/* Status bits */
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 635690cf3e3d..ff203c465fed 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -24,6 +24,13 @@ enum dma_data_direction {
#define DMA_28BIT_MASK 0x000000000fffffffULL
#define DMA_24BIT_MASK 0x0000000000ffffffULL
+static inline int valid_dma_direction(int dma_direction)
+{
+ return ((dma_direction == DMA_BIDIRECTIONAL) ||
+ (dma_direction == DMA_TO_DEVICE) ||
+ (dma_direction == DMA_FROM_DEVICE));
+}
+
#include <asm/dma-mapping.h>
/* Backwards compat, remove in 2.7.x */
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index b2cd2071d432..904bf3d2d90b 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -27,7 +27,8 @@ enum dmi_device_type {
DMI_DEV_TYPE_ETHERNET,
DMI_DEV_TYPE_TOKENRING,
DMI_DEV_TYPE_SOUND,
- DMI_DEV_TYPE_IPMI = -1
+ DMI_DEV_TYPE_IPMI = -1,
+ DMI_DEV_TYPE_OEM_STRING = -2
};
struct dmi_header {
@@ -68,6 +69,7 @@ extern struct dmi_device * dmi_find_device(int type, const char *name,
struct dmi_device *from);
extern void dmi_scan_machine(void);
extern int dmi_get_year(int field);
+extern int dmi_name_in_vendors(char *str);
#else
@@ -76,6 +78,7 @@ static inline char * dmi_get_system_info(int field) { return NULL; }
static inline struct dmi_device * dmi_find_device(int type, const char *name,
struct dmi_device *from) { return NULL; }
static inline int dmi_get_year(int year) { return 0; }
+static inline int dmi_name_in_vendors(char *s) { return 0; }
#endif
diff --git a/include/linux/eisa.h b/include/linux/eisa.h
index 4079242dced8..1ff7c1392525 100644
--- a/include/linux/eisa.h
+++ b/include/linux/eisa.h
@@ -3,8 +3,8 @@
#include <linux/ioport.h>
#include <linux/device.h>
+#include <linux/mod_devicetable.h>
-#define EISA_SIG_LEN 8
#define EISA_MAX_SLOTS 8
#define EISA_MAX_RESOURCES 4
@@ -27,12 +27,6 @@
#define EISA_CONFIG_ENABLED 1
#define EISA_CONFIG_FORCED 2
-/* The EISA signature, in ASCII form, null terminated */
-struct eisa_device_id {
- char sig[EISA_SIG_LEN];
- unsigned long driver_data;
-};
-
/* There is not much we can say about an EISA device, apart from
* signature, slot number, and base address. dma_mask is set by
* default to parent device mask..*/
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index 1713ace808bf..2fa9f1144228 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -1,12 +1,16 @@
#ifndef _LINUX_ELEVATOR_H
#define _LINUX_ELEVATOR_H
+#include <linux/percpu.h>
+
+#ifdef CONFIG_BLOCK
+
typedef int (elevator_merge_fn) (request_queue_t *, struct request **,
struct bio *);
typedef void (elevator_merge_req_fn) (request_queue_t *, struct request *, struct request *);
-typedef void (elevator_merged_fn) (request_queue_t *, struct request *);
+typedef void (elevator_merged_fn) (request_queue_t *, struct request *, int);
typedef int (elevator_dispatch_fn) (request_queue_t *, int);
@@ -14,9 +18,9 @@ typedef void (elevator_add_req_fn) (request_queue_t *, struct request *);
typedef int (elevator_queue_empty_fn) (request_queue_t *);
typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *);
typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *);
-typedef int (elevator_may_queue_fn) (request_queue_t *, int, struct bio *);
+typedef int (elevator_may_queue_fn) (request_queue_t *, int);
-typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, gfp_t);
+typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, gfp_t);
typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
typedef void (elevator_activate_req_fn) (request_queue_t *, struct request *);
typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *);
@@ -66,7 +70,6 @@ struct elevator_type
{
struct list_head list;
struct elevator_ops ops;
- struct elevator_type *elevator_type;
struct elv_fs_entry *elevator_attrs;
char elevator_name[ELV_NAME_MAX];
struct module *elevator_owner;
@@ -82,19 +85,21 @@ struct elevator_queue
struct kobject kobj;
struct elevator_type *elevator_type;
struct mutex sysfs_lock;
+ struct hlist_head *hash;
};
/*
* block elevator interface
*/
extern void elv_dispatch_sort(request_queue_t *, struct request *);
+extern void elv_dispatch_add_tail(request_queue_t *, struct request *);
extern void elv_add_request(request_queue_t *, struct request *, int, int);
extern void __elv_add_request(request_queue_t *, struct request *, int, int);
extern void elv_insert(request_queue_t *, struct request *, int);
extern int elv_merge(request_queue_t *, struct request **, struct bio *);
extern void elv_merge_requests(request_queue_t *, struct request *,
struct request *);
-extern void elv_merged_request(request_queue_t *, struct request *);
+extern void elv_merged_request(request_queue_t *, struct request *, int);
extern void elv_dequeue_request(request_queue_t *, struct request *);
extern void elv_requeue_request(request_queue_t *, struct request *);
extern int elv_queue_empty(request_queue_t *);
@@ -103,9 +108,9 @@ extern struct request *elv_former_request(request_queue_t *, struct request *);
extern struct request *elv_latter_request(request_queue_t *, struct request *);
extern int elv_register_queue(request_queue_t *q);
extern void elv_unregister_queue(request_queue_t *q);
-extern int elv_may_queue(request_queue_t *, int, struct bio *);
+extern int elv_may_queue(request_queue_t *, int);
extern void elv_completed_request(request_queue_t *, struct request *);
-extern int elv_set_request(request_queue_t *, struct request *, struct bio *, gfp_t);
+extern int elv_set_request(request_queue_t *, struct request *, gfp_t);
extern void elv_put_request(request_queue_t *, struct request *);
/*
@@ -125,6 +130,19 @@ extern void elevator_exit(elevator_t *);
extern int elv_rq_merge_ok(struct request *, struct bio *);
/*
+ * Helper functions.
+ */
+extern struct request *elv_rb_former_request(request_queue_t *, struct request *);
+extern struct request *elv_rb_latter_request(request_queue_t *, struct request *);
+
+/*
+ * rb support functions.
+ */
+extern struct request *elv_rb_add(struct rb_root *, struct request *);
+extern void elv_rb_del(struct rb_root *, struct request *);
+extern struct request *elv_rb_find(struct rb_root *, sector_t);
+
+/*
* Return values from elevator merger
*/
#define ELEVATOR_NO_MERGE 0
@@ -149,5 +167,42 @@ enum {
};
#define rq_end_sector(rq) ((rq)->sector + (rq)->nr_sectors)
+#define rb_entry_rq(node) rb_entry((node), struct request, rb_node)
+/*
+ * Hack to reuse the donelist list_head as the fifo time holder while
+ * the request is in the io scheduler. Saves an unsigned long in rq.
+ */
+#define rq_fifo_time(rq) ((unsigned long) (rq)->donelist.next)
+#define rq_set_fifo_time(rq,exp) ((rq)->donelist.next = (void *) (exp))
+#define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
+#define rq_fifo_clear(rq) do { \
+ list_del_init(&(rq)->queuelist); \
+ INIT_LIST_HEAD(&(rq)->donelist); \
+ } while (0)
+
+/*
+ * io context count accounting
+ */
+#define elv_ioc_count_mod(name, __val) \
+ do { \
+ preempt_disable(); \
+ __get_cpu_var(name) += (__val); \
+ preempt_enable(); \
+ } while (0)
+
+#define elv_ioc_count_inc(name) elv_ioc_count_mod(name, 1)
+#define elv_ioc_count_dec(name) elv_ioc_count_mod(name, -1)
+
+#define elv_ioc_count_read(name) \
+({ \
+ unsigned long __val = 0; \
+ int __cpu; \
+ smp_wmb(); \
+ for_each_possible_cpu(__cpu) \
+ __val += per_cpu(name, __cpu); \
+ __val; \
+})
+
+#endif /* CONFIG_BLOCK */
#endif
diff --git a/include/linux/err.h b/include/linux/err.h
index cd3b367f7445..1ab1d44f8d3b 100644
--- a/include/linux/err.h
+++ b/include/linux/err.h
@@ -15,6 +15,8 @@
*/
#define MAX_ERRNO 4095
+#ifndef __ASSEMBLY__
+
#define IS_ERR_VALUE(x) unlikely((x) >= (unsigned long)-MAX_ERRNO)
static inline void *ERR_PTR(long error)
@@ -32,4 +34,6 @@ static inline long IS_ERR(const void *ptr)
return IS_ERR_VALUE((unsigned long)ptr);
}
+#endif
+
#endif /* _LINUX_ERR_H */
diff --git a/include/linux/errqueue.h b/include/linux/errqueue.h
index 408118a07763..92f8d4fab32b 100644
--- a/include/linux/errqueue.h
+++ b/include/linux/errqueue.h
@@ -38,7 +38,7 @@ struct sock_exterr_skb
} header;
struct sock_extended_err ee;
u16 addr_offset;
- u16 port;
+ __be16 port;
};
#endif
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index 33a1aa107329..153d755376a4 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -165,41 +165,49 @@ struct ext2_group_desc
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
/*
- * Inode flags
+ * Inode flags (GETFLAGS/SETFLAGS)
*/
-#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
-#define EXT2_UNRM_FL 0x00000002 /* Undelete */
-#define EXT2_COMPR_FL 0x00000004 /* Compress file */
-#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
-#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
-#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
-#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
-#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
+#define EXT2_SECRM_FL FS_SECRM_FL /* Secure deletion */
+#define EXT2_UNRM_FL FS_UNRM_FL /* Undelete */
+#define EXT2_COMPR_FL FS_COMPR_FL /* Compress file */
+#define EXT2_SYNC_FL FS_SYNC_FL /* Synchronous updates */
+#define EXT2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */
+#define EXT2_APPEND_FL FS_APPEND_FL /* writes to file may only append */
+#define EXT2_NODUMP_FL FS_NODUMP_FL /* do not dump file */
+#define EXT2_NOATIME_FL FS_NOATIME_FL /* do not update atime */
/* Reserved for compression usage... */
-#define EXT2_DIRTY_FL 0x00000100
-#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
-#define EXT2_NOCOMP_FL 0x00000400 /* Don't compress */
-#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
+#define EXT2_DIRTY_FL FS_DIRTY_FL
+#define EXT2_COMPRBLK_FL FS_COMPRBLK_FL /* One or more compressed clusters */
+#define EXT2_NOCOMP_FL FS_NOCOMP_FL /* Don't compress */
+#define EXT2_ECOMPR_FL FS_ECOMPR_FL /* Compression error */
/* End compression flags --- maybe not all used */
-#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
-#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
-#define EXT2_IMAGIC_FL 0x00002000 /* AFS directory */
-#define EXT2_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */
-#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
-#define EXT2_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
-#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
-#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
-
-#define EXT2_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
-#define EXT2_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
+#define EXT2_BTREE_FL FS_BTREE_FL /* btree format dir */
+#define EXT2_INDEX_FL FS_INDEX_FL /* hash-indexed directory */
+#define EXT2_IMAGIC_FL FS_IMAGIC_FL /* AFS directory */
+#define EXT2_JOURNAL_DATA_FL FS_JOURNAL_DATA_FL /* Reserved for ext3 */
+#define EXT2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */
+#define EXT2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */
+#define EXT2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/
+#define EXT2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */
+
+#define EXT2_FL_USER_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */
+#define EXT2_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */
/*
* ioctl commands
*/
-#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
-#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
-#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
-#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
+#define EXT2_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define EXT2_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define EXT2_IOC_GETVERSION FS_IOC_GETVERSION
+#define EXT2_IOC_SETVERSION FS_IOC_SETVERSION
+
+/*
+ * ioctl commands in 32 bit emulation
+ */
+#define EXT2_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define EXT2_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define EXT2_IOC32_GETVERSION FS_IOC32_GETVERSION
+#define EXT2_IOC32_SETVERSION FS_IOC32_SETVERSION
/*
* Structure of an inode on the disk
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 0eed918b3816..11cca1bdc0c7 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -216,14 +216,14 @@ struct ext3_new_group_data {
/*
* ioctl commands
*/
-#define EXT3_IOC_GETFLAGS _IOR('f', 1, long)
-#define EXT3_IOC_SETFLAGS _IOW('f', 2, long)
+#define EXT3_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define EXT3_IOC_SETFLAGS FS_IOC_SETFLAGS
#define EXT3_IOC_GETVERSION _IOR('f', 3, long)
#define EXT3_IOC_SETVERSION _IOW('f', 4, long)
#define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
#define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input)
-#define EXT3_IOC_GETVERSION_OLD _IOR('v', 1, long)
-#define EXT3_IOC_SETVERSION_OLD _IOW('v', 2, long)
+#define EXT3_IOC_GETVERSION_OLD FS_IOC_GETVERSION
+#define EXT3_IOC_SETVERSION_OLD FS_IOC_SETVERSION
#ifdef CONFIG_JBD_DEBUG
#define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
#endif
@@ -231,6 +231,23 @@ struct ext3_new_group_data {
#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long)
/*
+ * ioctl commands in 32 bit emulation
+ */
+#define EXT3_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define EXT3_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define EXT3_IOC32_GETVERSION _IOR('f', 3, int)
+#define EXT3_IOC32_SETVERSION _IOW('f', 4, int)
+#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int)
+#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int)
+#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
+#ifdef CONFIG_JBD_DEBUG
+#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
+#endif
+#define EXT3_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
+#define EXT3_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
+
+
+/*
* Mount options
*/
struct ext3_mount_options {
@@ -460,7 +477,7 @@ struct ext3_super_block {
*/
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
- __u16 s_reserved_gdt_blocks; /* Per group desc for online growth */
+ __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
/*
* Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set.
*/
@@ -473,7 +490,7 @@ struct ext3_super_block {
__u8 s_reserved_char_pad;
__u16 s_reserved_word_pad;
__le32 s_default_mount_opts;
- __le32 s_first_meta_bg; /* First metablock block group */
+ __le32 s_first_meta_bg; /* First metablock block group */
__u32 s_reserved[190]; /* Padding to the end of the block */
};
@@ -812,6 +829,7 @@ extern void ext3_set_aops(struct inode *inode);
/* ioctl.c */
extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
unsigned long);
+extern long ext3_compat_ioctl (struct file *, unsigned int, unsigned long);
/* namei.c */
extern int ext3_orphan_add(handle_t *, struct inode *);
diff --git a/include/linux/ext3_fs_i.h b/include/linux/ext3_fs_i.h
index 2f18b9511f21..4395e5206746 100644
--- a/include/linux/ext3_fs_i.h
+++ b/include/linux/ext3_fs_i.h
@@ -35,7 +35,7 @@ struct ext3_reserve_window {
};
struct ext3_reserve_window_node {
- struct rb_node rsv_node;
+ struct rb_node rsv_node;
__u32 rsv_goal_size;
__u32 rsv_alloc_hit;
struct ext3_reserve_window rsv_window;
diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
index c8307c02dd07..ce0e6109aff0 100644
--- a/include/linux/ext3_jbd.h
+++ b/include/linux/ext3_jbd.h
@@ -23,7 +23,7 @@
/* Define the number of blocks we need to account to a transaction to
* modify one block of data.
- *
+ *
* We may have to touch one inode, one bitmap buffer, up to three
* indirection blocks, the group and superblock summaries, and the data
* block to complete the transaction. */
@@ -88,16 +88,16 @@
#endif
int
-ext3_mark_iloc_dirty(handle_t *handle,
+ext3_mark_iloc_dirty(handle_t *handle,
struct inode *inode,
struct ext3_iloc *iloc);
-/*
+/*
* On success, We end up with an outstanding reference count against
- * iloc->bh. This _must_ be cleaned up later.
+ * iloc->bh. This _must_ be cleaned up later.
*/
-int ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
+int ext3_reserve_inode_write(handle_t *handle, struct inode *inode,
struct ext3_iloc *iloc);
int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode);
diff --git a/include/linux/ext4_fs.h b/include/linux/ext4_fs.h
new file mode 100644
index 000000000000..498503ee613d
--- /dev/null
+++ b/include/linux/ext4_fs.h
@@ -0,0 +1,994 @@
+/*
+ * linux/include/linux/ext4_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT4_FS_H
+#define _LINUX_EXT4_FS_H
+
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/magic.h>
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT4FS_DEBUG to produce debug messages
+ */
+#undef EXT4FS_DEBUG
+
+/*
+ * Define EXT4_RESERVATION to reserve data blocks for expanding files
+ */
+#define EXT4_DEFAULT_RESERVE_BLOCKS 8
+/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */
+#define EXT4_MAX_RESERVE_BLOCKS 1027
+#define EXT4_RESERVE_WINDOW_NOT_ALLOCATED 0
+/*
+ * Always enable hashed directories
+ */
+#define CONFIG_EXT4_INDEX
+
+/*
+ * Debug code
+ */
+#ifdef EXT4FS_DEBUG
+#define ext4_debug(f, a...) \
+ do { \
+ printk (KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ printk (KERN_DEBUG f, ## a); \
+ } while (0)
+#else
+#define ext4_debug(f, a...) do {} while (0)
+#endif
+
+/*
+ * Special inodes numbers
+ */
+#define EXT4_BAD_INO 1 /* Bad blocks inode */
+#define EXT4_ROOT_INO 2 /* Root inode */
+#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */
+#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */
+#define EXT4_JOURNAL_INO 8 /* Journal inode */
+
+/* First non-reserved inode for old ext4 filesystems */
+#define EXT4_GOOD_OLD_FIRST_INO 11
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT4_LINK_MAX 32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT4_MIN_BLOCK_SIZE 1024
+#define EXT4_MAX_BLOCK_SIZE 4096
+#define EXT4_MIN_BLOCK_LOG_SIZE 10
+#ifdef __KERNEL__
+# define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize)
+#else
+# define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#endif
+#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof (__u32))
+#ifdef __KERNEL__
+# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
+#else
+# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#endif
+#ifdef __KERNEL__
+#define EXT4_ADDR_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_addr_per_block_bits)
+#define EXT4_INODE_SIZE(s) (EXT4_SB(s)->s_inode_size)
+#define EXT4_FIRST_INO(s) (EXT4_SB(s)->s_first_ino)
+#else
+#define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \
+ EXT4_GOOD_OLD_INODE_SIZE : \
+ (s)->s_inode_size)
+#define EXT4_FIRST_INO(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \
+ EXT4_GOOD_OLD_FIRST_INO : \
+ (s)->s_first_ino)
+#endif
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT4_MIN_FRAG_SIZE 1024
+#define EXT4_MAX_FRAG_SIZE 4096
+#define EXT4_MIN_FRAG_LOG_SIZE 10
+#ifdef __KERNEL__
+# define EXT4_FRAG_SIZE(s) (EXT4_SB(s)->s_frag_size)
+# define EXT4_FRAGS_PER_BLOCK(s) (EXT4_SB(s)->s_frags_per_block)
+#else
+# define EXT4_FRAG_SIZE(s) (EXT4_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+# define EXT4_FRAGS_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_FRAG_SIZE(s))
+#endif
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext4_group_desc
+{
+ __le32 bg_block_bitmap; /* Blocks bitmap block */
+ __le32 bg_inode_bitmap; /* Inodes bitmap block */
+ __le32 bg_inode_table; /* Inodes table block */
+ __le16 bg_free_blocks_count; /* Free blocks count */
+ __le16 bg_free_inodes_count; /* Free inodes count */
+ __le16 bg_used_dirs_count; /* Directories count */
+ __u16 bg_flags;
+ __u32 bg_reserved[3];
+ __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
+ __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
+ __le32 bg_inode_table_hi; /* Inodes table block MSB */
+};
+
+#ifdef __KERNEL__
+#include <linux/ext4_fs_i.h>
+#include <linux/ext4_fs_sb.h>
+#endif
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT4_MIN_DESC_SIZE 32
+#define EXT4_MIN_DESC_SIZE_64BIT 64
+#define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE
+#define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size)
+#ifdef __KERNEL__
+# define EXT4_BLOCKS_PER_GROUP(s) (EXT4_SB(s)->s_blocks_per_group)
+# define EXT4_DESC_PER_BLOCK(s) (EXT4_SB(s)->s_desc_per_block)
+# define EXT4_INODES_PER_GROUP(s) (EXT4_SB(s)->s_inodes_per_group)
+# define EXT4_DESC_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_desc_per_block_bits)
+#else
+# define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
+# define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s))
+# define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
+#endif
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT4_NDIR_BLOCKS 12
+#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
+#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
+#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
+#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */
+#define EXT4_UNRM_FL 0x00000002 /* Undelete */
+#define EXT4_COMPR_FL 0x00000004 /* Compress file */
+#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */
+#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */
+#define EXT4_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT4_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT4_DIRTY_FL 0x00000100
+#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */
+#define EXT4_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */
+#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */
+#define EXT4_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
+#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
+#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
+#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
+
+#define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
+#define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
+
+/*
+ * Inode dynamic state flags
+ */
+#define EXT4_STATE_JDATA 0x00000001 /* journaled data exists */
+#define EXT4_STATE_NEW 0x00000002 /* inode is newly created */
+#define EXT4_STATE_XATTR 0x00000004 /* has in-inode xattrs */
+
+/* Used to pass group descriptor data when online resize is done */
+struct ext4_new_group_input {
+ __u32 group; /* Group number for this data */
+ __u64 block_bitmap; /* Absolute block number of block bitmap */
+ __u64 inode_bitmap; /* Absolute block number of inode bitmap */
+ __u64 inode_table; /* Absolute block number of inode table start */
+ __u32 blocks_count; /* Total number of blocks in this group */
+ __u16 reserved_blocks; /* Number of reserved blocks in this group */
+ __u16 unused;
+};
+
+/* The struct ext4_new_group_input in kernel space, with free_blocks_count */
+struct ext4_new_group_data {
+ __u32 group;
+ __u64 block_bitmap;
+ __u64 inode_bitmap;
+ __u64 inode_table;
+ __u32 blocks_count;
+ __u16 reserved_blocks;
+ __u16 unused;
+ __u32 free_blocks_count;
+};
+
+
+/*
+ * ioctl commands
+ */
+#define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define EXT4_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define EXT4_IOC_GETVERSION _IOR('f', 3, long)
+#define EXT4_IOC_SETVERSION _IOW('f', 4, long)
+#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
+#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input)
+#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION
+#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION
+#ifdef CONFIG_JBD_DEBUG
+#define EXT4_IOC_WAIT_FOR_READONLY _IOR('f', 99, long)
+#endif
+#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
+#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long)
+
+/*
+ * ioctl commands in 32 bit emulation
+ */
+#define EXT4_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define EXT4_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define EXT4_IOC32_GETVERSION _IOR('f', 3, int)
+#define EXT4_IOC32_SETVERSION _IOW('f', 4, int)
+#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int)
+#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int)
+#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
+#ifdef CONFIG_JBD_DEBUG
+#define EXT4_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int)
+#endif
+#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
+#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
+
+
+/*
+ * Mount options
+ */
+struct ext4_mount_options {
+ unsigned long s_mount_opt;
+ uid_t s_resuid;
+ gid_t s_resgid;
+ unsigned long s_commit_interval;
+#ifdef CONFIG_QUOTA
+ int s_jquota_fmt;
+ char *s_qf_names[MAXQUOTAS];
+#endif
+};
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext4_inode {
+ __le16 i_mode; /* File mode */
+ __le16 i_uid; /* Low 16 bits of Owner Uid */
+ __le32 i_size; /* Size in bytes */
+ __le32 i_atime; /* Access time */
+ __le32 i_ctime; /* Creation time */
+ __le32 i_mtime; /* Modification time */
+ __le32 i_dtime; /* Deletion Time */
+ __le16 i_gid; /* Low 16 bits of Group Id */
+ __le16 i_links_count; /* Links count */
+ __le32 i_blocks; /* Blocks count */
+ __le32 i_flags; /* File flags */
+ union {
+ struct {
+ __u32 l_i_reserved1;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
+ __le32 i_generation; /* File version (for NFS) */
+ __le32 i_file_acl; /* File ACL */
+ __le32 i_dir_acl; /* Directory ACL */
+ __le32 i_faddr; /* Fragment address */
+ union {
+ struct {
+ __u8 l_i_frag; /* Fragment number */
+ __u8 l_i_fsize; /* Fragment size */
+ __le16 l_i_file_acl_high;
+ __le16 l_i_uid_high; /* these 2 fields */
+ __le16 l_i_gid_high; /* were reserved2[0] */
+ __u32 l_i_reserved2;
+ } linux2;
+ struct {
+ __u8 h_i_frag; /* Fragment number */
+ __u8 h_i_fsize; /* Fragment size */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __u8 m_i_frag; /* Fragment number */
+ __u8 m_i_fsize; /* Fragment size */
+ __le16 m_i_file_acl_high;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+ __le16 i_extra_isize;
+ __le16 i_pad1;
+};
+
+#define i_size_high i_dir_acl
+
+#if defined(__KERNEL__) || defined(__linux__)
+#define i_reserved1 osd1.linux1.l_i_reserved1
+#define i_frag osd2.linux2.l_i_frag
+#define i_fsize osd2.linux2.l_i_fsize
+#define i_file_acl_high osd2.linux2.l_i_file_acl_high
+#define i_uid_low i_uid
+#define i_gid_low i_gid
+#define i_uid_high osd2.linux2.l_i_uid_high
+#define i_gid_high osd2.linux2.l_i_gid_high
+#define i_reserved2 osd2.linux2.l_i_reserved2
+
+#elif defined(__GNU__)
+
+#define i_translator osd1.hurd1.h_i_translator
+#define i_frag osd2.hurd2.h_i_frag;
+#define i_fsize osd2.hurd2.h_i_fsize;
+#define i_uid_high osd2.hurd2.h_i_uid_high
+#define i_gid_high osd2.hurd2.h_i_gid_high
+#define i_author osd2.hurd2.h_i_author
+
+#elif defined(__masix__)
+
+#define i_reserved1 osd1.masix1.m_i_reserved1
+#define i_frag osd2.masix2.m_i_frag
+#define i_fsize osd2.masix2.m_i_fsize
+#define i_file_acl_high osd2.masix2.m_i_file_acl_high
+#define i_reserved2 osd2.masix2.m_i_reserved2
+
+#endif /* defined(__KERNEL__) || defined(__linux__) */
+
+/*
+ * File system states
+ */
+#define EXT4_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT4_ERROR_FS 0x0002 /* Errors detected */
+#define EXT4_ORPHAN_FS 0x0004 /* Orphans being recovered */
+
+/*
+ * Mount flags
+ */
+#define EXT4_MOUNT_CHECK 0x00001 /* Do mount-time checks */
+#define EXT4_MOUNT_OLDALLOC 0x00002 /* Don't use the new Orlov allocator */
+#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
+#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
+#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
+#define EXT4_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */
+#define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */
+#define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */
+#define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/
+#define EXT4_MOUNT_ABORT 0x00200 /* Fatal error detected */
+#define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */
+#define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */
+#define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */
+#define EXT4_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */
+#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
+#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
+#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
+#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
+#define EXT4_MOUNT_RESERVATION 0x10000 /* Preallocation */
+#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
+#define EXT4_MOUNT_NOBH 0x40000 /* No bufferheads */
+#define EXT4_MOUNT_QUOTA 0x80000 /* Some quota option set */
+#define EXT4_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
+#define EXT4_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
+#define EXT4_MOUNT_EXTENTS 0x400000 /* Extents support */
+
+/* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */
+#ifndef _LINUX_EXT2_FS_H
+#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT4_MOUNT_##opt
+#define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \
+ EXT4_MOUNT_##opt)
+#else
+#define EXT2_MOUNT_NOLOAD EXT4_MOUNT_NOLOAD
+#define EXT2_MOUNT_ABORT EXT4_MOUNT_ABORT
+#define EXT2_MOUNT_DATA_FLAGS EXT4_MOUNT_DATA_FLAGS
+#endif
+
+#define ext4_set_bit ext2_set_bit
+#define ext4_set_bit_atomic ext2_set_bit_atomic
+#define ext4_clear_bit ext2_clear_bit
+#define ext4_clear_bit_atomic ext2_clear_bit_atomic
+#define ext4_test_bit ext2_test_bit
+#define ext4_find_first_zero_bit ext2_find_first_zero_bit
+#define ext4_find_next_zero_bit ext2_find_next_zero_bit
+
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT4_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT4_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT4_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT4_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT4_ERRORS_PANIC 3 /* Panic */
+#define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext4_super_block {
+/*00*/ __le32 s_inodes_count; /* Inodes count */
+ __le32 s_blocks_count; /* Blocks count */
+ __le32 s_r_blocks_count; /* Reserved blocks count */
+ __le32 s_free_blocks_count; /* Free blocks count */
+/*10*/ __le32 s_free_inodes_count; /* Free inodes count */
+ __le32 s_first_data_block; /* First Data Block */
+ __le32 s_log_block_size; /* Block size */
+ __le32 s_log_frag_size; /* Fragment size */
+/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */
+ __le32 s_frags_per_group; /* # Fragments per group */
+ __le32 s_inodes_per_group; /* # Inodes per group */
+ __le32 s_mtime; /* Mount time */
+/*30*/ __le32 s_wtime; /* Write time */
+ __le16 s_mnt_count; /* Mount count */
+ __le16 s_max_mnt_count; /* Maximal mount count */
+ __le16 s_magic; /* Magic signature */
+ __le16 s_state; /* File system state */
+ __le16 s_errors; /* Behaviour when detecting errors */
+ __le16 s_minor_rev_level; /* minor revision level */
+/*40*/ __le32 s_lastcheck; /* time of last check */
+ __le32 s_checkinterval; /* max. time between checks */
+ __le32 s_creator_os; /* OS */
+ __le32 s_rev_level; /* Revision level */
+/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */
+ __le16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT4_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __le32 s_first_ino; /* First non-reserved inode */
+ __le16 s_inode_size; /* size of inode structure */
+ __le16 s_block_group_nr; /* block group # of this superblock */
+ __le32 s_feature_compat; /* compatible feature set */
+/*60*/ __le32 s_feature_incompat; /* incompatible feature set */
+ __le32 s_feature_ro_compat; /* readonly-compatible feature set */
+/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+/*78*/ char s_volume_name[16]; /* volume name */
+/*88*/ char s_last_mounted[64]; /* directory where last mounted */
+/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
+ /*
+ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
+/*E0*/ __le32 s_journal_inum; /* inode number of journal file */
+ __le32 s_journal_dev; /* device number of journal file */
+ __le32 s_last_orphan; /* start of list of inodes to delete */
+ __le32 s_hash_seed[4]; /* HTREE hash seed */
+ __u8 s_def_hash_version; /* Default hash version to use */
+ __u8 s_reserved_char_pad;
+ __le16 s_desc_size; /* size of group descriptor */
+/*100*/ __le32 s_default_mount_opts;
+ __le32 s_first_meta_bg; /* First metablock block group */
+ __le32 s_mkfs_time; /* When the filesystem was created */
+ __le32 s_jnl_blocks[17]; /* Backup of the journal inode */
+ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+/*150*/ __le32 s_blocks_count_hi; /* Blocks count */
+ __le32 s_r_blocks_count_hi; /* Reserved blocks count */
+ __le32 s_free_blocks_count_hi; /* Free blocks count */
+ __u32 s_reserved[169]; /* Padding to the end of the block */
+};
+
+#ifdef __KERNEL__
+static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
+{
+ return container_of(inode, struct ext4_inode_info, vfs_inode);
+}
+
+static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
+{
+ return ino == EXT4_ROOT_INO ||
+ ino == EXT4_JOURNAL_INO ||
+ ino == EXT4_RESIZE_INO ||
+ (ino >= EXT4_FIRST_INO(sb) &&
+ ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
+}
+#else
+/* Assume that user mode programs are passing in an ext4fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT4_SB(sb) (sb)
+#endif
+
+#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
+
+/*
+ * Codes for operating systems
+ */
+#define EXT4_OS_LINUX 0
+#define EXT4_OS_HURD 1
+#define EXT4_OS_MASIX 2
+#define EXT4_OS_FREEBSD 3
+#define EXT4_OS_LITES 4
+
+/*
+ * Revision levels
+ */
+#define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT4_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV
+#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV
+
+#define EXT4_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT4_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT4_SET_COMPAT_FEATURE(sb,mask) \
+ EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT4_SET_RO_COMPAT_FEATURE(sb,mask) \
+ EXT4_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT4_SET_INCOMPAT_FEATURE(sb,mask) \
+ EXT4_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT4_CLEAR_COMPAT_FEATURE(sb,mask) \
+ EXT4_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT4_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
+ EXT4_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT4_CLEAR_INCOMPAT_FEATURE(sb,mask) \
+ EXT4_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
+
+#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+
+#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
+#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+
+#define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
+ EXT4_FEATURE_INCOMPAT_RECOVER| \
+ EXT4_FEATURE_INCOMPAT_META_BG| \
+ EXT4_FEATURE_INCOMPAT_EXTENTS| \
+ EXT4_FEATURE_INCOMPAT_64BIT)
+#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT4_DEF_RESUID 0
+#define EXT4_DEF_RESGID 0
+
+/*
+ * Default mount options
+ */
+#define EXT4_DEFM_DEBUG 0x0001
+#define EXT4_DEFM_BSDGROUPS 0x0002
+#define EXT4_DEFM_XATTR_USER 0x0004
+#define EXT4_DEFM_ACL 0x0008
+#define EXT4_DEFM_UID16 0x0010
+#define EXT4_DEFM_JMODE 0x0060
+#define EXT4_DEFM_JMODE_DATA 0x0020
+#define EXT4_DEFM_JMODE_ORDERED 0x0040
+#define EXT4_DEFM_JMODE_WBACK 0x0060
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT4_NAME_LEN 255
+
+struct ext4_dir_entry {
+ __le32 inode; /* Inode number */
+ __le16 rec_len; /* Directory entry length */
+ __le16 name_len; /* Name length */
+ char name[EXT4_NAME_LEN]; /* File name */
+};
+
+/*
+ * The new version of the directory entry. Since EXT4 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext4_dir_entry_2 {
+ __le32 inode; /* Inode number */
+ __le16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT4_NAME_LEN]; /* File name */
+};
+
+/*
+ * Ext4 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT4_FT_UNKNOWN 0
+#define EXT4_FT_REG_FILE 1
+#define EXT4_FT_DIR 2
+#define EXT4_FT_CHRDEV 3
+#define EXT4_FT_BLKDEV 4
+#define EXT4_FT_FIFO 5
+#define EXT4_FT_SOCK 6
+#define EXT4_FT_SYMLINK 7
+
+#define EXT4_FT_MAX 8
+
+/*
+ * EXT4_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT4_DIR_PAD 4
+#define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1)
+#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \
+ ~EXT4_DIR_ROUND)
+/*
+ * Hash Tree Directory indexing
+ * (c) Daniel Phillips, 2001
+ */
+
+#ifdef CONFIG_EXT4_INDEX
+ #define is_dx(dir) (EXT4_HAS_COMPAT_FEATURE(dir->i_sb, \
+ EXT4_FEATURE_COMPAT_DIR_INDEX) && \
+ (EXT4_I(dir)->i_flags & EXT4_INDEX_FL))
+#define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX)
+#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
+#else
+ #define is_dx(dir) 0
+#define EXT4_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT4_LINK_MAX)
+#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2)
+#endif
+
+/* Legal values for the dx_root hash_version field: */
+
+#define DX_HASH_LEGACY 0
+#define DX_HASH_HALF_MD4 1
+#define DX_HASH_TEA 2
+
+#ifdef __KERNEL__
+
+/* hash info structure used by the directory hash */
+struct dx_hash_info
+{
+ u32 hash;
+ u32 minor_hash;
+ int hash_version;
+ u32 *seed;
+};
+
+#define EXT4_HTREE_EOF 0x7fffffff
+
+/*
+ * Control parameters used by ext4_htree_next_block
+ */
+#define HASH_NB_ALWAYS 1
+
+
+/*
+ * Describe an inode's exact location on disk and in memory
+ */
+struct ext4_iloc
+{
+ struct buffer_head *bh;
+ unsigned long offset;
+ unsigned long block_group;
+};
+
+static inline struct ext4_inode *ext4_raw_inode(struct ext4_iloc *iloc)
+{
+ return (struct ext4_inode *) (iloc->bh->b_data + iloc->offset);
+}
+
+/*
+ * This structure is stuffed into the struct file's private_data field
+ * for directories. It is where we put information so that we can do
+ * readdir operations in hash tree order.
+ */
+struct dir_private_info {
+ struct rb_root root;
+ struct rb_node *curr_node;
+ struct fname *extra_fname;
+ loff_t last_pos;
+ __u32 curr_hash;
+ __u32 curr_minor_hash;
+ __u32 next_hash;
+};
+
+/* calculate the first block number of the group */
+static inline ext4_fsblk_t
+ext4_group_first_block_no(struct super_block *sb, unsigned long group_no)
+{
+ return group_no * (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) +
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+}
+
+/*
+ * Special error return code only used by dx_probe() and its callers.
+ */
+#define ERR_BAD_DX_DIR -75000
+
+void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
+ unsigned long *blockgrpp, ext4_grpblk_t *offsetp);
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext4 source programs needs to include it so they are duplicated here.
+ */
+# define NORET_TYPE /**/
+# define ATTRIB_NORET __attribute__((noreturn))
+# define NORET_AND noreturn,
+
+/* balloc.c */
+extern unsigned int ext4_block_group(struct super_block *sb,
+ ext4_fsblk_t blocknr);
+extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
+ ext4_fsblk_t blocknr);
+extern int ext4_bg_has_super(struct super_block *sb, int group);
+extern unsigned long ext4_bg_num_gdb(struct super_block *sb, int group);
+extern ext4_fsblk_t ext4_new_block (handle_t *handle, struct inode *inode,
+ ext4_fsblk_t goal, int *errp);
+extern ext4_fsblk_t ext4_new_blocks (handle_t *handle, struct inode *inode,
+ ext4_fsblk_t goal, unsigned long *count, int *errp);
+extern void ext4_free_blocks (handle_t *handle, struct inode *inode,
+ ext4_fsblk_t block, unsigned long count);
+extern void ext4_free_blocks_sb (handle_t *handle, struct super_block *sb,
+ ext4_fsblk_t block, unsigned long count,
+ unsigned long *pdquot_freed_blocks);
+extern ext4_fsblk_t ext4_count_free_blocks (struct super_block *);
+extern void ext4_check_blocks_bitmap (struct super_block *);
+extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
+ unsigned int block_group,
+ struct buffer_head ** bh);
+extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
+extern void ext4_init_block_alloc_info(struct inode *);
+extern void ext4_rsv_window_add(struct super_block *sb, struct ext4_reserve_window_node *rsv);
+
+/* dir.c */
+extern int ext4_check_dir_entry(const char *, struct inode *,
+ struct ext4_dir_entry_2 *,
+ struct buffer_head *, unsigned long);
+extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
+ __u32 minor_hash,
+ struct ext4_dir_entry_2 *dirent);
+extern void ext4_htree_free_dir_info(struct dir_private_info *p);
+
+/* fsync.c */
+extern int ext4_sync_file (struct file *, struct dentry *, int);
+
+/* hash.c */
+extern int ext4fs_dirhash(const char *name, int len, struct
+ dx_hash_info *hinfo);
+
+/* ialloc.c */
+extern struct inode * ext4_new_inode (handle_t *, struct inode *, int);
+extern void ext4_free_inode (handle_t *, struct inode *);
+extern struct inode * ext4_orphan_get (struct super_block *, unsigned long);
+extern unsigned long ext4_count_free_inodes (struct super_block *);
+extern unsigned long ext4_count_dirs (struct super_block *);
+extern void ext4_check_inodes_bitmap (struct super_block *);
+extern unsigned long ext4_count_free (struct buffer_head *, unsigned);
+
+
+/* inode.c */
+int ext4_forget(handle_t *handle, int is_metadata, struct inode *inode,
+ struct buffer_head *bh, ext4_fsblk_t blocknr);
+struct buffer_head * ext4_getblk (handle_t *, struct inode *, long, int, int *);
+struct buffer_head * ext4_bread (handle_t *, struct inode *, int, int, int *);
+int ext4_get_blocks_handle(handle_t *handle, struct inode *inode,
+ sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result,
+ int create, int extend_disksize);
+
+extern void ext4_read_inode (struct inode *);
+extern int ext4_write_inode (struct inode *, int);
+extern int ext4_setattr (struct dentry *, struct iattr *);
+extern void ext4_delete_inode (struct inode *);
+extern int ext4_sync_inode (handle_t *, struct inode *);
+extern void ext4_discard_reservation (struct inode *);
+extern void ext4_dirty_inode(struct inode *);
+extern int ext4_change_inode_journal_flag(struct inode *, int);
+extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
+extern void ext4_truncate (struct inode *);
+extern void ext4_set_inode_flags(struct inode *);
+extern void ext4_set_aops(struct inode *inode);
+extern int ext4_writepage_trans_blocks(struct inode *);
+extern int ext4_block_truncate_page(handle_t *handle, struct page *page,
+ struct address_space *mapping, loff_t from);
+
+/* ioctl.c */
+extern int ext4_ioctl (struct inode *, struct file *, unsigned int,
+ unsigned long);
+extern long ext4_compat_ioctl (struct file *, unsigned int, unsigned long);
+
+/* namei.c */
+extern int ext4_orphan_add(handle_t *, struct inode *);
+extern int ext4_orphan_del(handle_t *, struct inode *);
+extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+ __u32 start_minor_hash, __u32 *next_hash);
+
+/* resize.c */
+extern int ext4_group_add(struct super_block *sb,
+ struct ext4_new_group_data *input);
+extern int ext4_group_extend(struct super_block *sb,
+ struct ext4_super_block *es,
+ ext4_fsblk_t n_blocks_count);
+
+/* super.c */
+extern void ext4_error (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern void __ext4_std_error (struct super_block *, const char *, int);
+extern void ext4_abort (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern void ext4_warning (struct super_block *, const char *, const char *, ...)
+ __attribute__ ((format (printf, 3, 4)));
+extern void ext4_update_dynamic_rev (struct super_block *sb);
+extern ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern ext4_fsblk_t ext4_inode_table(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern void ext4_block_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk);
+extern void ext4_inode_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk);
+extern void ext4_inode_table_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk);
+
+static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_blocks_count);
+}
+
+static inline ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_r_blocks_count);
+}
+
+static inline ext4_fsblk_t ext4_free_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_free_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_free_blocks_count);
+}
+
+static inline void ext4_blocks_count_set(struct ext4_super_block *es,
+ ext4_fsblk_t blk)
+{
+ es->s_blocks_count = cpu_to_le32((u32)blk);
+ es->s_blocks_count_hi = cpu_to_le32(blk >> 32);
+}
+
+static inline void ext4_free_blocks_count_set(struct ext4_super_block *es,
+ ext4_fsblk_t blk)
+{
+ es->s_free_blocks_count = cpu_to_le32((u32)blk);
+ es->s_free_blocks_count_hi = cpu_to_le32(blk >> 32);
+}
+
+static inline void ext4_r_blocks_count_set(struct ext4_super_block *es,
+ ext4_fsblk_t blk)
+{
+ es->s_r_blocks_count = cpu_to_le32((u32)blk);
+ es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32);
+}
+
+
+
+#define ext4_std_error(sb, errno) \
+do { \
+ if ((errno)) \
+ __ext4_std_error((sb), __FUNCTION__, (errno)); \
+} while (0)
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern const struct file_operations ext4_dir_operations;
+
+/* file.c */
+extern struct inode_operations ext4_file_inode_operations;
+extern const struct file_operations ext4_file_operations;
+
+/* namei.c */
+extern struct inode_operations ext4_dir_inode_operations;
+extern struct inode_operations ext4_special_inode_operations;
+
+/* symlink.c */
+extern struct inode_operations ext4_symlink_inode_operations;
+extern struct inode_operations ext4_fast_symlink_inode_operations;
+
+/* extents.c */
+extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
+extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
+extern int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
+ ext4_fsblk_t iblock,
+ unsigned long max_blocks, struct buffer_head *bh_result,
+ int create, int extend_disksize);
+extern void ext4_ext_truncate(struct inode *, struct page *);
+extern void ext4_ext_init(struct super_block *);
+extern void ext4_ext_release(struct super_block *);
+static inline int
+ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
+ unsigned long max_blocks, struct buffer_head *bh,
+ int create, int extend_disksize)
+{
+ if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
+ return ext4_ext_get_blocks(handle, inode, block, max_blocks,
+ bh, create, extend_disksize);
+ return ext4_get_blocks_handle(handle, inode, block, max_blocks, bh,
+ create, extend_disksize);
+}
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_EXT4_FS_H */
diff --git a/include/linux/ext4_fs_extents.h b/include/linux/ext4_fs_extents.h
new file mode 100644
index 000000000000..a41cc24568ca
--- /dev/null
+++ b/include/linux/ext4_fs_extents.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com
+ * Written by Alex Tomas <alex@clusterfs.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 Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
+ */
+
+#ifndef _LINUX_EXT4_EXTENTS
+#define _LINUX_EXT4_EXTENTS
+
+#include <linux/ext4_fs.h>
+
+/*
+ * With AGRESSIVE_TEST defined, the capacity of index/leaf blocks
+ * becomes very small, so index split, in-depth growing and
+ * other hard changes happen much more often.
+ * This is for debug purposes only.
+ */
+#define AGRESSIVE_TEST_
+
+/*
+ * With EXTENTS_STATS defined, the number of blocks and extents
+ * are collected in the truncate path. They'll be shown at
+ * umount time.
+ */
+#define EXTENTS_STATS__
+
+/*
+ * If CHECK_BINSEARCH is defined, then the results of the binary search
+ * will also be checked by linear search.
+ */
+#define CHECK_BINSEARCH__
+
+/*
+ * If EXT_DEBUG is defined you can use the 'extdebug' mount option
+ * to get lots of info about what's going on.
+ */
+#define EXT_DEBUG__
+#ifdef EXT_DEBUG
+#define ext_debug(a...) printk(a)
+#else
+#define ext_debug(a...)
+#endif
+
+/*
+ * If EXT_STATS is defined then stats numbers are collected.
+ * These number will be displayed at umount time.
+ */
+#define EXT_STATS_
+
+
+/*
+ * ext4_inode has i_block array (60 bytes total).
+ * The first 12 bytes store ext4_extent_header;
+ * the remainder stores an array of ext4_extent.
+ */
+
+/*
+ * This is the extent on-disk structure.
+ * It's used at the bottom of the tree.
+ */
+struct ext4_extent {
+ __le32 ee_block; /* first logical block extent covers */
+ __le16 ee_len; /* number of blocks covered by extent */
+ __le16 ee_start_hi; /* high 16 bits of physical block */
+ __le32 ee_start; /* low 32 bits of physical block */
+};
+
+/*
+ * This is index on-disk structure.
+ * It's used at all the levels except the bottom.
+ */
+struct ext4_extent_idx {
+ __le32 ei_block; /* index covers logical blocks from 'block' */
+ __le32 ei_leaf; /* pointer to the physical block of the next *
+ * level. leaf or next index could be there */
+ __le16 ei_leaf_hi; /* high 16 bits of physical block */
+ __u16 ei_unused;
+};
+
+/*
+ * Each block (leaves and indexes), even inode-stored has header.
+ */
+struct ext4_extent_header {
+ __le16 eh_magic; /* probably will support different formats */
+ __le16 eh_entries; /* number of valid entries */
+ __le16 eh_max; /* capacity of store in entries */
+ __le16 eh_depth; /* has tree real underlying blocks? */
+ __le32 eh_generation; /* generation of the tree */
+};
+
+#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a)
+
+/*
+ * Array of ext4_ext_path contains path to some extent.
+ * Creation/lookup routines use it for traversal/splitting/etc.
+ * Truncate uses it to simulate recursive walking.
+ */
+struct ext4_ext_path {
+ ext4_fsblk_t p_block;
+ __u16 p_depth;
+ struct ext4_extent *p_ext;
+ struct ext4_extent_idx *p_idx;
+ struct ext4_extent_header *p_hdr;
+ struct buffer_head *p_bh;
+};
+
+/*
+ * structure for external API
+ */
+
+#define EXT4_EXT_CACHE_NO 0
+#define EXT4_EXT_CACHE_GAP 1
+#define EXT4_EXT_CACHE_EXTENT 2
+
+/*
+ * to be called by ext4_ext_walk_space()
+ * negative retcode - error
+ * positive retcode - signal for ext4_ext_walk_space(), see below
+ * callback must return valid extent (passed or newly created)
+ */
+typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
+ struct ext4_ext_cache *,
+ void *);
+
+#define EXT_CONTINUE 0
+#define EXT_BREAK 1
+#define EXT_REPEAT 2
+
+
+#define EXT_MAX_BLOCK 0xffffffff
+
+#define EXT_MAX_LEN ((1UL << 15) - 1)
+
+
+#define EXT_FIRST_EXTENT(__hdr__) \
+ ((struct ext4_extent *) (((char *) (__hdr__)) + \
+ sizeof(struct ext4_extent_header)))
+#define EXT_FIRST_INDEX(__hdr__) \
+ ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \
+ sizeof(struct ext4_extent_header)))
+#define EXT_HAS_FREE_INDEX(__path__) \
+ (le16_to_cpu((__path__)->p_hdr->eh_entries) \
+ < le16_to_cpu((__path__)->p_hdr->eh_max))
+#define EXT_LAST_EXTENT(__hdr__) \
+ (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
+#define EXT_LAST_INDEX(__hdr__) \
+ (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
+#define EXT_MAX_EXTENT(__hdr__) \
+ (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
+#define EXT_MAX_INDEX(__hdr__) \
+ (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
+
+static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode)
+{
+ return (struct ext4_extent_header *) EXT4_I(inode)->i_data;
+}
+
+static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh)
+{
+ return (struct ext4_extent_header *) bh->b_data;
+}
+
+static inline unsigned short ext_depth(struct inode *inode)
+{
+ return le16_to_cpu(ext_inode_hdr(inode)->eh_depth);
+}
+
+static inline void ext4_ext_tree_changed(struct inode *inode)
+{
+ EXT4_I(inode)->i_ext_generation++;
+}
+
+static inline void
+ext4_ext_invalidate_cache(struct inode *inode)
+{
+ EXT4_I(inode)->i_cached_extent.ec_type = EXT4_EXT_CACHE_NO;
+}
+
+extern int ext4_extent_tree_init(handle_t *, struct inode *);
+extern int ext4_ext_calc_credits_for_insert(struct inode *, struct ext4_ext_path *);
+extern int ext4_ext_insert_extent(handle_t *, struct inode *, struct ext4_ext_path *, struct ext4_extent *);
+extern int ext4_ext_walk_space(struct inode *, unsigned long, unsigned long, ext_prepare_callback, void *);
+extern struct ext4_ext_path * ext4_ext_find_extent(struct inode *, int, struct ext4_ext_path *);
+
+#endif /* _LINUX_EXT4_EXTENTS */
+
diff --git a/include/linux/ext4_fs_i.h b/include/linux/ext4_fs_i.h
new file mode 100644
index 000000000000..bb42379cb7fd
--- /dev/null
+++ b/include/linux/ext4_fs_i.h
@@ -0,0 +1,158 @@
+/*
+ * linux/include/linux/ext4_fs_i.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs_i.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT4_FS_I
+#define _LINUX_EXT4_FS_I
+
+#include <linux/rwsem.h>
+#include <linux/rbtree.h>
+#include <linux/seqlock.h>
+#include <linux/mutex.h>
+
+/* data type for block offset of block group */
+typedef int ext4_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long long ext4_fsblk_t;
+
+struct ext4_reserve_window {
+ ext4_fsblk_t _rsv_start; /* First byte reserved */
+ ext4_fsblk_t _rsv_end; /* Last byte reserved or 0 */
+};
+
+struct ext4_reserve_window_node {
+ struct rb_node rsv_node;
+ __u32 rsv_goal_size;
+ __u32 rsv_alloc_hit;
+ struct ext4_reserve_window rsv_window;
+};
+
+struct ext4_block_alloc_info {
+ /* information about reservation window */
+ struct ext4_reserve_window_node rsv_window_node;
+ /*
+ * was i_next_alloc_block in ext4_inode_info
+ * is the logical (file-relative) number of the
+ * most-recently-allocated block in this file.
+ * We use this for detecting linearly ascending allocation requests.
+ */
+ __u32 last_alloc_logical_block;
+ /*
+ * 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
+ * allocated to this file. This give us the goal (target) for the next
+ * allocation when we detect linearly ascending requests.
+ */
+ ext4_fsblk_t last_alloc_physical_block;
+};
+
+#define rsv_start rsv_window._rsv_start
+#define rsv_end rsv_window._rsv_end
+
+/*
+ * storage for cached extent
+ */
+struct ext4_ext_cache {
+ ext4_fsblk_t ec_start;
+ __u32 ec_block;
+ __u32 ec_len; /* must be 32bit to return holes */
+ __u32 ec_type;
+};
+
+/*
+ * third extended file system inode data in memory
+ */
+struct ext4_inode_info {
+ __le32 i_data[15]; /* unconverted */
+ __u32 i_flags;
+#ifdef EXT4_FRAGMENTS
+ __u32 i_faddr;
+ __u8 i_frag_no;
+ __u8 i_frag_size;
+#endif
+ ext4_fsblk_t i_file_acl;
+ __u32 i_dir_acl;
+ __u32 i_dtime;
+
+ /*
+ * i_block_group is the number of the block group which contains
+ * this file's inode. Constant across the lifetime of the inode,
+ * it is ued for making block allocation decisions - we try to
+ * place a file's data blocks near its inode block, and new inodes
+ * near to their parent directory's inode.
+ */
+ __u32 i_block_group;
+ __u32 i_state; /* Dynamic state flags for ext4 */
+
+ /* block reservation info */
+ struct ext4_block_alloc_info *i_block_alloc_info;
+
+ __u32 i_dir_start_lookup;
+#ifdef CONFIG_EXT4DEV_FS_XATTR
+ /*
+ * Extended attributes can be read independently of the main file
+ * data. Taking i_mutex even when reading would cause contention
+ * between readers of EAs and writers of regular file data, so
+ * instead we synchronize on xattr_sem when reading or changing
+ * EAs.
+ */
+ struct rw_semaphore xattr_sem;
+#endif
+#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
+ struct posix_acl *i_acl;
+ struct posix_acl *i_default_acl;
+#endif
+
+ struct list_head i_orphan; /* unlinked but open inodes */
+
+ /*
+ * i_disksize keeps track of what the inode size is ON DISK, not
+ * in memory. During truncate, i_size is set to the new size by
+ * the VFS prior to calling ext4_truncate(), but the filesystem won't
+ * set i_disksize to 0 until the truncate is actually under way.
+ *
+ * The intent is that i_disksize always represents the blocks which
+ * are used by this file. This allows recovery to restart truncate
+ * on orphans if we crash during truncate. We actually write i_disksize
+ * into the on-disk inode when writing inodes out, instead of i_size.
+ *
+ * The only time when i_disksize and i_size may be different is when
+ * a truncate is in progress. The only things which change i_disksize
+ * are ext4_get_block (growth) and ext4_truncate (shrinkth).
+ */
+ loff_t i_disksize;
+
+ /* on-disk additional length */
+ __u16 i_extra_isize;
+
+ /*
+ * truncate_mutex is for serialising ext4_truncate() against
+ * ext4_getblock(). In the 2.4 ext2 design, great chunks of inode's
+ * data tree are chopped off during truncate. We can't do that in
+ * ext4 because whenever we perform intermediate commits during
+ * truncate, the inode and all the metadata blocks *must* be in a
+ * consistent state which allows truncation of the orphans to restart
+ * during recovery. Hence we must fix the get_block-vs-truncate race
+ * by other means, so we have truncate_mutex.
+ */
+ struct mutex truncate_mutex;
+ struct inode vfs_inode;
+
+ unsigned long i_ext_generation;
+ struct ext4_ext_cache i_cached_extent;
+};
+
+#endif /* _LINUX_EXT4_FS_I */
diff --git a/include/linux/ext4_fs_sb.h b/include/linux/ext4_fs_sb.h
new file mode 100644
index 000000000000..691a713139ce
--- /dev/null
+++ b/include/linux/ext4_fs_sb.h
@@ -0,0 +1,94 @@
+/*
+ * linux/include/linux/ext4_fs_sb.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs_sb.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT4_FS_SB
+#define _LINUX_EXT4_FS_SB
+
+#ifdef __KERNEL__
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/blockgroup_lock.h>
+#include <linux/percpu_counter.h>
+#endif
+#include <linux/rbtree.h>
+
+/*
+ * third extended-fs super-block data in memory
+ */
+struct ext4_sb_info {
+ unsigned long s_frag_size; /* Size of a fragment in bytes */
+ unsigned long s_desc_size; /* Size of a group descriptor in bytes */
+ unsigned long s_frags_per_block;/* Number of fragments per block */
+ unsigned long s_inodes_per_block;/* Number of inodes per block */
+ unsigned long s_frags_per_group;/* Number of fragments in a group */
+ unsigned long s_blocks_per_group;/* Number of blocks in a group */
+ unsigned long s_inodes_per_group;/* Number of inodes in a group */
+ unsigned long s_itb_per_group; /* Number of inode table blocks per group */
+ unsigned long s_gdb_count; /* Number of group descriptor blocks */
+ unsigned long s_desc_per_block; /* Number of group descriptors per block */
+ unsigned long s_groups_count; /* Number of groups in the fs */
+ struct buffer_head * s_sbh; /* Buffer containing the super block */
+ struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
+ struct buffer_head ** s_group_desc;
+ unsigned long s_mount_opt;
+ uid_t s_resuid;
+ gid_t s_resgid;
+ unsigned short s_mount_state;
+ unsigned short s_pad;
+ int s_addr_per_block_bits;
+ int s_desc_per_block_bits;
+ int s_inode_size;
+ int s_first_ino;
+ spinlock_t s_next_gen_lock;
+ u32 s_next_generation;
+ u32 s_hash_seed[4];
+ int s_def_hash_version;
+ struct percpu_counter s_freeblocks_counter;
+ struct percpu_counter s_freeinodes_counter;
+ struct percpu_counter s_dirs_counter;
+ struct blockgroup_lock s_blockgroup_lock;
+
+ /* root of the per fs reservation window tree */
+ spinlock_t s_rsv_window_lock;
+ struct rb_root s_rsv_window_root;
+ struct ext4_reserve_window_node s_rsv_window_head;
+
+ /* Journaling */
+ struct inode * s_journal_inode;
+ struct journal_s * s_journal;
+ struct list_head s_orphan;
+ unsigned long s_commit_interval;
+ struct block_device *journal_bdev;
+#ifdef CONFIG_JBD_DEBUG
+ struct timer_list turn_ro_timer; /* For turning read-only (crash simulation) */
+ wait_queue_head_t ro_wait_queue; /* For people waiting for the fs to go read-only */
+#endif
+#ifdef CONFIG_QUOTA
+ char *s_qf_names[MAXQUOTAS]; /* Names of quota files with journalled quota */
+ int s_jquota_fmt; /* Format of quota to use */
+#endif
+
+#ifdef EXTENTS_STATS
+ /* ext4 extents stats */
+ unsigned long s_ext_min;
+ unsigned long s_ext_max;
+ unsigned long s_depth_max;
+ spinlock_t s_ext_stats_lock;
+ unsigned long s_ext_blocks;
+ unsigned long s_ext_extents;
+#endif
+};
+
+#endif /* _LINUX_EXT4_FS_SB */
diff --git a/include/linux/ext4_jbd2.h b/include/linux/ext4_jbd2.h
new file mode 100644
index 000000000000..72dd631912e4
--- /dev/null
+++ b/include/linux/ext4_jbd2.h
@@ -0,0 +1,273 @@
+/*
+ * linux/include/linux/ext4_jbd2.h
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1998--1999 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Ext4-specific journaling extensions.
+ */
+
+#ifndef _LINUX_EXT4_JBD_H
+#define _LINUX_EXT4_JBD_H
+
+#include <linux/fs.h>
+#include <linux/jbd2.h>
+#include <linux/ext4_fs.h>
+
+#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal)
+
+/* Define the number of blocks we need to account to a transaction to
+ * modify one block of data.
+ *
+ * We may have to touch one inode, one bitmap buffer, up to three
+ * indirection blocks, the group and superblock summaries, and the data
+ * block to complete the transaction.
+ *
+ * For extents-enabled fs we may have to allocate and modify up to
+ * 5 levels of tree + root which are stored in the inode. */
+
+#define EXT4_SINGLEDATA_TRANS_BLOCKS(sb) \
+ (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_EXTENTS) \
+ || test_opt(sb, EXTENTS) ? 27U : 8U)
+
+/* Extended attribute operations touch at most two data buffers,
+ * two bitmap buffers, and two group summaries, in addition to the inode
+ * and the superblock, which are already accounted for. */
+
+#define EXT4_XATTR_TRANS_BLOCKS 6U
+
+/* Define the minimum size for a transaction which modifies data. This
+ * needs to take into account the fact that we may end up modifying two
+ * quota files too (one for the group, one for the user quota). The
+ * superblock only gets updated once, of course, so don't bother
+ * counting that again for the quota updates. */
+
+#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \
+ EXT4_XATTR_TRANS_BLOCKS - 2 + \
+ 2*EXT4_QUOTA_TRANS_BLOCKS(sb))
+
+/* Delete operations potentially hit one directory's namespace plus an
+ * entire inode, plus arbitrary amounts of bitmap/indirection data. Be
+ * generous. We can grow the delete transaction later if necessary. */
+
+#define EXT4_DELETE_TRANS_BLOCKS(sb) (2 * EXT4_DATA_TRANS_BLOCKS(sb) + 64)
+
+/* Define an arbitrary limit for the amount of data we will anticipate
+ * writing to any given transaction. For unbounded transactions such as
+ * write(2) and truncate(2) we can write more than this, but we always
+ * start off at the maximum transaction size and grow the transaction
+ * optimistically as we go. */
+
+#define EXT4_MAX_TRANS_DATA 64U
+
+/* We break up a large truncate or write transaction once the handle's
+ * buffer credits gets this low, we need either to extend the
+ * transaction or to start a new one. Reserve enough space here for
+ * inode, bitmap, superblock, group and indirection updates for at least
+ * one block, plus two quota updates. Quota allocations are not
+ * needed. */
+
+#define EXT4_RESERVE_TRANS_BLOCKS 12U
+
+#define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8
+
+#ifdef CONFIG_QUOTA
+/* Amount of blocks needed for quota update - we know that the structure was
+ * allocated so we need to update only inode+data */
+#define EXT4_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0)
+/* Amount of blocks needed for quota insert/delete - we do some block writes
+ * but inode, sb and group updates are done only once */
+#define EXT4_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
+ (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_INIT_REWRITE) : 0)
+#define EXT4_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
+ (EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)+3+DQUOT_DEL_REWRITE) : 0)
+#else
+#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0
+#define EXT4_QUOTA_INIT_BLOCKS(sb) 0
+#define EXT4_QUOTA_DEL_BLOCKS(sb) 0
+#endif
+
+int
+ext4_mark_iloc_dirty(handle_t *handle,
+ struct inode *inode,
+ struct ext4_iloc *iloc);
+
+/*
+ * On success, We end up with an outstanding reference count against
+ * iloc->bh. This _must_ be cleaned up later.
+ */
+
+int ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
+ struct ext4_iloc *iloc);
+
+int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode);
+
+/*
+ * Wrapper functions with which ext4 calls into JBD. The intent here is
+ * to allow these to be turned into appropriate stubs so ext4 can control
+ * ext2 filesystems, so ext2+ext4 systems only nee one fs. This work hasn't
+ * been done yet.
+ */
+
+void ext4_journal_abort_handle(const char *caller, const char *err_fn,
+ struct buffer_head *bh, handle_t *handle, int err);
+
+static inline int
+__ext4_journal_get_undo_access(const char *where, handle_t *handle,
+ struct buffer_head *bh)
+{
+ int err = jbd2_journal_get_undo_access(handle, bh);
+ if (err)
+ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ return err;
+}
+
+static inline int
+__ext4_journal_get_write_access(const char *where, handle_t *handle,
+ struct buffer_head *bh)
+{
+ int err = jbd2_journal_get_write_access(handle, bh);
+ if (err)
+ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ return err;
+}
+
+static inline void
+ext4_journal_release_buffer(handle_t *handle, struct buffer_head *bh)
+{
+ jbd2_journal_release_buffer(handle, bh);
+}
+
+static inline int
+__ext4_journal_forget(const char *where, handle_t *handle, struct buffer_head *bh)
+{
+ int err = jbd2_journal_forget(handle, bh);
+ if (err)
+ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ return err;
+}
+
+static inline int
+__ext4_journal_revoke(const char *where, handle_t *handle,
+ ext4_fsblk_t blocknr, struct buffer_head *bh)
+{
+ int err = jbd2_journal_revoke(handle, blocknr, bh);
+ if (err)
+ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ return err;
+}
+
+static inline int
+__ext4_journal_get_create_access(const char *where,
+ handle_t *handle, struct buffer_head *bh)
+{
+ int err = jbd2_journal_get_create_access(handle, bh);
+ if (err)
+ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ return err;
+}
+
+static inline int
+__ext4_journal_dirty_metadata(const char *where,
+ handle_t *handle, struct buffer_head *bh)
+{
+ int err = jbd2_journal_dirty_metadata(handle, bh);
+ if (err)
+ ext4_journal_abort_handle(where, __FUNCTION__, bh, handle,err);
+ return err;
+}
+
+
+#define ext4_journal_get_undo_access(handle, bh) \
+ __ext4_journal_get_undo_access(__FUNCTION__, (handle), (bh))
+#define ext4_journal_get_write_access(handle, bh) \
+ __ext4_journal_get_write_access(__FUNCTION__, (handle), (bh))
+#define ext4_journal_revoke(handle, blocknr, bh) \
+ __ext4_journal_revoke(__FUNCTION__, (handle), (blocknr), (bh))
+#define ext4_journal_get_create_access(handle, bh) \
+ __ext4_journal_get_create_access(__FUNCTION__, (handle), (bh))
+#define ext4_journal_dirty_metadata(handle, bh) \
+ __ext4_journal_dirty_metadata(__FUNCTION__, (handle), (bh))
+#define ext4_journal_forget(handle, bh) \
+ __ext4_journal_forget(__FUNCTION__, (handle), (bh))
+
+int ext4_journal_dirty_data(handle_t *handle, struct buffer_head *bh);
+
+handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks);
+int __ext4_journal_stop(const char *where, handle_t *handle);
+
+static inline handle_t *ext4_journal_start(struct inode *inode, int nblocks)
+{
+ return ext4_journal_start_sb(inode->i_sb, nblocks);
+}
+
+#define ext4_journal_stop(handle) \
+ __ext4_journal_stop(__FUNCTION__, (handle))
+
+static inline handle_t *ext4_journal_current_handle(void)
+{
+ return journal_current_handle();
+}
+
+static inline int ext4_journal_extend(handle_t *handle, int nblocks)
+{
+ return jbd2_journal_extend(handle, nblocks);
+}
+
+static inline int ext4_journal_restart(handle_t *handle, int nblocks)
+{
+ return jbd2_journal_restart(handle, nblocks);
+}
+
+static inline int ext4_journal_blocks_per_page(struct inode *inode)
+{
+ return jbd2_journal_blocks_per_page(inode);
+}
+
+static inline int ext4_journal_force_commit(journal_t *journal)
+{
+ return jbd2_journal_force_commit(journal);
+}
+
+/* super.c */
+int ext4_force_commit(struct super_block *sb);
+
+static inline int ext4_should_journal_data(struct inode *inode)
+{
+ if (!S_ISREG(inode->i_mode))
+ return 1;
+ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
+ return 1;
+ if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
+ return 1;
+ return 0;
+}
+
+static inline int ext4_should_order_data(struct inode *inode)
+{
+ if (!S_ISREG(inode->i_mode))
+ return 0;
+ if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
+ return 0;
+ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
+ return 1;
+ return 0;
+}
+
+static inline int ext4_should_writeback_data(struct inode *inode)
+{
+ if (!S_ISREG(inode->i_mode))
+ return 0;
+ if (EXT4_I(inode)->i_flags & EXT4_JOURNAL_DATA_FL)
+ return 0;
+ if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA)
+ return 1;
+ return 0;
+}
+
+#endif /* _LINUX_EXT4_JBD_H */
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 2f335e966011..3e69241e6a81 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -2,6 +2,7 @@
#define _LINUX_FB_H
#include <asm/types.h>
+#include <linux/i2c.h>
/* Definitions of frame buffers */
@@ -775,6 +776,7 @@ struct fb_info {
struct fb_ops *fbops;
struct device *device;
struct class_device *class_device; /* sysfs per device attrs */
+ int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
@@ -940,6 +942,7 @@ extern void fb_edid_to_monspecs(unsigned char *edid,
struct fb_monspecs *specs);
extern void fb_destroy_modedb(struct fb_videomode *modedb);
extern int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb);
+extern unsigned char *fb_ddc_read(struct i2c_adapter *adapter);
/* drivers/video/modedb.c */
#define VESA_MODEDB_SIZE 34
diff --git a/include/linux/file.h b/include/linux/file.h
index 9f7c2513866f..74183e6f7f45 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -112,5 +112,6 @@ struct task_struct;
struct files_struct *get_files_struct(struct task_struct *);
void FASTCALL(put_files_struct(struct files_struct *fs));
+void reset_files_struct(struct task_struct *, struct files_struct *);
#endif /* __LINUX_FILE_H */
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 1d3e601ece73..2fe6e3f900ba 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -79,8 +79,8 @@ extern int dir_notify_enable;
#define WRITE 1
#define READA 2 /* read-ahead - don't block if no resources */
#define SWRITE 3 /* for ll_rw_block() - wait for buffer lock */
-#define SPECIAL 4 /* For non-blockdevice requests in request queue */
#define READ_SYNC (READ | (1 << BIO_RW_SYNC))
+#define READ_META (READ | (1 << BIO_RW_META))
#define WRITE_SYNC (WRITE | (1 << BIO_RW_SYNC))
#define WRITE_BARRIER ((1 << BIO_RW) | (1 << BIO_RW_BARRIER))
@@ -217,6 +217,47 @@ extern int dir_notify_enable;
#define FIBMAP _IO(0x00,1) /* bmap access */
#define FIGETBSZ _IO(0x00,2) /* get the block size used for bmap */
+#define FS_IOC_GETFLAGS _IOR('f', 1, long)
+#define FS_IOC_SETFLAGS _IOW('f', 2, long)
+#define FS_IOC_GETVERSION _IOR('v', 1, long)
+#define FS_IOC_SETVERSION _IOW('v', 2, long)
+#define FS_IOC32_GETFLAGS _IOR('f', 1, int)
+#define FS_IOC32_SETFLAGS _IOW('f', 2, int)
+#define FS_IOC32_GETVERSION _IOR('v', 1, int)
+#define FS_IOC32_SETVERSION _IOW('v', 2, int)
+
+/*
+ * Inode flags (FS_IOC_GETFLAGS / FS_IOC_SETFLAGS)
+ */
+#define FS_SECRM_FL 0x00000001 /* Secure deletion */
+#define FS_UNRM_FL 0x00000002 /* Undelete */
+#define FS_COMPR_FL 0x00000004 /* Compress file */
+#define FS_SYNC_FL 0x00000008 /* Synchronous updates */
+#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define FS_APPEND_FL 0x00000020 /* writes to file may only append */
+#define FS_NODUMP_FL 0x00000040 /* do not dump file */
+#define FS_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define FS_DIRTY_FL 0x00000100
+#define FS_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define FS_NOCOMP_FL 0x00000400 /* Don't compress */
+#define FS_ECOMPR_FL 0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */
+#define FS_BTREE_FL 0x00001000 /* btree format dir */
+#define FS_INDEX_FL 0x00001000 /* hash-indexed directory */
+#define FS_IMAGIC_FL 0x00002000 /* AFS directory */
+#define FS_JOURNAL_DATA_FL 0x00004000 /* Reserved for ext3 */
+#define FS_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+#define FS_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
+#define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+#define FS_EXTENT_FL 0x00080000 /* Extents */
+#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */
+#define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
+
+#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
+#define FS_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */
+
+
#define SYNC_FILE_RANGE_WAIT_BEFORE 1
#define SYNC_FILE_RANGE_WRITE 2
#define SYNC_FILE_RANGE_WAIT_AFTER 4
@@ -512,7 +553,6 @@ struct inode {
struct timespec i_mtime;
struct timespec i_ctime;
unsigned int i_blkbits;
- unsigned long i_blksize;
unsigned long i_version;
blkcnt_t i_blocks;
unsigned short i_bytes;
@@ -528,11 +568,12 @@ struct inode {
#ifdef CONFIG_QUOTA
struct dquot *i_dquot[MAXQUOTAS];
#endif
- /* These three should probably be a union */
struct list_head i_devices;
- struct pipe_inode_info *i_pipe;
- struct block_device *i_bdev;
- struct cdev *i_cdev;
+ union {
+ struct pipe_inode_info *i_pipe;
+ struct block_device *i_bdev;
+ struct cdev *i_cdev;
+ };
int i_cindex;
__u32 i_generation;
@@ -553,10 +594,10 @@ struct inode {
unsigned int i_flags;
atomic_t i_writecount;
+#ifdef CONFIG_SECURITY
void *i_security;
- union {
- void *generic_ip;
- } u;
+#endif
+ void *i_private; /* fs or device private pointer */
#ifdef __NEED_I_SIZE_ORDERED
seqcount_t i_size_seqcount;
#endif
@@ -582,6 +623,9 @@ enum inode_i_mutex_lock_class
I_MUTEX_QUOTA
};
+extern void inode_double_lock(struct inode *inode1, struct inode *inode2);
+extern void inode_double_unlock(struct inode *inode1, struct inode *inode2);
+
/*
* NOTE: in a 32bit arch with a preemptable kernel and
* an UP compile the i_size_read/write must be atomic
@@ -615,7 +659,11 @@ static inline loff_t i_size_read(struct inode *inode)
#endif
}
-
+/*
+ * NOTE: unlike i_size_read(), i_size_write() does need locking around it
+ * (normally i_mutex), otherwise on 32bit/SMP an update of i_size_seqcount
+ * can be lost, resulting in subsequent i_size_read() calls spinning forever.
+ */
static inline void i_size_write(struct inode *inode, loff_t i_size)
{
#if BITS_PER_LONG==32 && defined(CONFIG_SMP)
@@ -645,9 +693,9 @@ extern struct block_device *I_BDEV(struct inode *inode);
struct fown_struct {
rwlock_t lock; /* protects pid, uid, euid fields */
- int pid; /* pid or -pgrp where SIGIO should be sent */
+ struct pid *pid; /* pid or -pgrp where SIGIO should be sent */
+ enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */
uid_t uid, euid; /* uid/euid of process setting the owner */
- void *security;
int signum; /* posix.1b rt signal to be delivered on IO */
};
@@ -690,8 +738,9 @@ struct file {
struct file_ra_state f_ra;
unsigned long f_version;
+#ifdef CONFIG_SECURITY
void *f_security;
-
+#endif
/* needed for tty driver, and maybe others */
void *private_data;
@@ -841,8 +890,10 @@ extern void kill_fasync(struct fasync_struct **, int, int);
/* only for net: no internal synchronization */
extern void __kill_fasync(struct fasync_struct *, int, int);
+extern int __f_setown(struct file *filp, struct pid *, enum pid_type, int force);
extern int f_setown(struct file *filp, unsigned long arg, int force);
extern void f_delown(struct file *filp);
+extern pid_t f_getown(struct file *filp);
extern int send_sigurg(struct fown_struct *fown);
/*
@@ -879,7 +930,9 @@ struct super_block {
int s_syncing;
int s_need_sync_fs;
atomic_t s_active;
+#ifdef CONFIG_SECURITY
void *s_security;
+#endif
struct xattr_handler **s_xattr;
struct list_head s_inodes; /* all inodes */
@@ -1005,7 +1058,7 @@ int generic_osync_inode(struct inode *, struct address_space *, int);
* This allows the kernel to read directories into kernel space or
* to have different dirent layouts depending on the binary type.
*/
-typedef int (*filldir_t)(void *, const char *, int, loff_t, ino_t, unsigned);
+typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
struct block_device_operations {
int (*open) (struct inode *, struct file *);
@@ -1056,9 +1109,9 @@ struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
- ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
- ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
+ ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
+ ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
@@ -1072,8 +1125,6 @@ struct file_operations {
int (*aio_fsync) (struct kiocb *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
- ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
- ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
@@ -1111,6 +1162,11 @@ struct inode_operations {
struct seq_file;
+ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
+ unsigned long nr_segs, unsigned long fast_segs,
+ struct iovec *fast_pointer,
+ struct iovec **ret_pointer);
+
extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *);
extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *);
extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
@@ -1145,9 +1201,10 @@ struct super_operations {
int (*show_options)(struct seq_file *, struct vfsmount *);
int (*show_stats)(struct seq_file *, struct vfsmount *);
-
+#ifdef CONFIG_QUOTA
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
+#endif
};
/* Inode state bits. Protected by inode_lock. */
@@ -1174,15 +1231,30 @@ static inline void mark_inode_dirty_sync(struct inode *inode)
__mark_inode_dirty(inode, I_DIRTY_SYNC);
}
-static inline void inode_inc_link_count(struct inode *inode)
+static inline void inc_nlink(struct inode *inode)
{
inode->i_nlink++;
+}
+
+static inline void inode_inc_link_count(struct inode *inode)
+{
+ inc_nlink(inode);
mark_inode_dirty(inode);
}
-static inline void inode_dec_link_count(struct inode *inode)
+static inline void drop_nlink(struct inode *inode)
{
inode->i_nlink--;
+}
+
+static inline void clear_nlink(struct inode *inode)
+{
+ inode->i_nlink = 0;
+}
+
+static inline void inode_dec_link_count(struct inode *inode)
+{
+ drop_nlink(inode);
mark_inode_dirty(inode);
}
@@ -1440,6 +1512,7 @@ extern void __init vfs_caches_init(unsigned long);
extern void putname(const char *name);
#endif
+#ifdef CONFIG_BLOCK
extern int register_blkdev(unsigned int, const char *);
extern int unregister_blkdev(unsigned int, const char *);
extern struct block_device *bdget(dev_t);
@@ -1448,13 +1521,20 @@ extern void bd_forget(struct inode *inode);
extern void bdput(struct block_device *);
extern struct block_device *open_by_devnum(dev_t, unsigned);
extern struct block_device *open_partition_by_devnum(dev_t, unsigned);
-extern const struct file_operations def_blk_fops;
extern const struct address_space_operations def_blk_aops;
+#else
+static inline void bd_forget(struct inode *inode) {}
+#endif
+extern const struct file_operations def_blk_fops;
extern const struct file_operations def_chr_fops;
extern const struct file_operations bad_sock_fops;
extern const struct file_operations def_fifo_fops;
+#ifdef CONFIG_BLOCK
extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long);
extern int blkdev_ioctl(struct inode *, struct file *, unsigned, unsigned long);
+extern int blkdev_driver_ioctl(struct inode *inode, struct file *file,
+ struct gendisk *disk, unsigned cmd,
+ unsigned long arg);
extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long);
extern int blkdev_get(struct block_device *, mode_t, unsigned);
extern int blkdev_put(struct block_device *);
@@ -1468,6 +1548,7 @@ extern void bd_release_from_disk(struct block_device *, struct gendisk *);
#define bd_claim_by_disk(bdev, holder, disk) bd_claim(bdev, holder)
#define bd_release_from_disk(bdev, disk) bd_release(bdev)
#endif
+#endif
/* fs/char_dev.c */
#define CHRDEV_MAJOR_HASH_SIZE 255
@@ -1481,14 +1562,19 @@ extern int chrdev_open(struct inode *, struct file *);
extern void chrdev_show(struct seq_file *,off_t);
/* fs/block_dev.c */
-#define BLKDEV_MAJOR_HASH_SIZE 255
#define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */
+
+#ifdef CONFIG_BLOCK
+#define BLKDEV_MAJOR_HASH_SIZE 255
extern const char *__bdevname(dev_t, char *buffer);
extern const char *bdevname(struct block_device *bdev, char *buffer);
extern struct block_device *lookup_bdev(const char *);
extern struct block_device *open_bdev_excl(const char *, int, void *);
extern void close_bdev_excl(struct block_device *);
extern void blkdev_show(struct seq_file *,off_t);
+#else
+#define BLKDEV_MAJOR_HASH_SIZE 0
+#endif
extern void init_special_inode(struct inode *, umode_t, dev_t);
@@ -1502,6 +1588,7 @@ extern const struct file_operations rdwr_fifo_fops;
extern int fs_may_remount_ro(struct super_block *);
+#ifdef CONFIG_BLOCK
/*
* return READ, READA, or WRITE
*/
@@ -1513,9 +1600,10 @@ extern int fs_may_remount_ro(struct super_block *);
#define bio_data_dir(bio) ((bio)->bi_rw & 1)
extern int check_disk_change(struct block_device *);
-extern int invalidate_inodes(struct super_block *);
extern int __invalidate_device(struct block_device *);
extern int invalidate_partition(struct gendisk *, int);
+#endif
+extern int invalidate_inodes(struct super_block *);
unsigned long invalidate_mapping_pages(struct address_space *mapping,
pgoff_t start, pgoff_t end);
unsigned long invalidate_inode_pages(struct address_space *mapping);
@@ -1543,11 +1631,14 @@ extern int __filemap_fdatawrite_range(struct address_space *mapping,
extern long do_fsync(struct file *file, int datasync);
extern void sync_supers(void);
extern void sync_filesystems(int wait);
+extern void __fsync_super(struct super_block *sb);
extern void emergency_sync(void);
extern void emergency_remount(void);
extern int do_remount_sb(struct super_block *sb, int flags,
void *data, int force);
+#ifdef CONFIG_BLOCK
extern sector_t bmap(struct inode *, sector_t);
+#endif
extern int notify_change(struct dentry *, struct iattr *);
extern int permission(struct inode *, int, struct nameidata *);
extern int generic_permission(struct inode *, int,
@@ -1565,6 +1656,9 @@ static inline void allow_write_access(struct file *file)
atomic_inc(&file->f_dentry->d_inode->i_writecount);
}
extern int do_pipe(int *);
+extern struct file *create_read_pipe(struct file *f);
+extern struct file *create_write_pipe(void);
+extern void free_write_pipe(struct file *);
extern int open_namei(int dfd, const char *, int, int, struct nameidata *);
extern int may_open(struct nameidata *, int, int);
@@ -1618,6 +1712,8 @@ extern void __iget(struct inode * inode);
extern void clear_inode(struct inode *);
extern void destroy_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);
+extern int __remove_suid(struct dentry *, int);
+extern int should_remove_suid(struct dentry *);
extern int remove_suid(struct dentry *);
extern void remove_dquot_ref(struct super_block *, int, struct list_head *);
@@ -1630,9 +1726,11 @@ static inline void insert_inode_hash(struct inode *inode) {
extern struct file * get_empty_filp(void);
extern void file_move(struct file *f, struct list_head *list);
extern void file_kill(struct file *f);
+#ifdef CONFIG_BLOCK
struct bio;
extern void submit_bio(int, struct bio *);
extern int bdev_read_only(struct block_device *);
+#endif
extern int set_blocksize(struct block_device *, int);
extern int sb_set_blocksize(struct super_block *, int);
extern int sb_min_blocksize(struct super_block *, int);
@@ -1641,22 +1739,17 @@ extern int generic_file_mmap(struct file *, struct vm_area_struct *);
extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *);
extern int file_read_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
extern int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size);
-extern ssize_t generic_file_read(struct file *, char __user *, size_t, loff_t *);
int generic_write_checks(struct file *file, loff_t *pos, size_t *count, int isblk);
-extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *);
-extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t);
-extern ssize_t __generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t *);
-extern ssize_t generic_file_aio_write(struct kiocb *, const char __user *, size_t, loff_t);
+extern ssize_t generic_file_aio_read(struct kiocb *, const struct iovec *, unsigned long, loff_t);
+extern ssize_t generic_file_aio_write(struct kiocb *, const struct iovec *, unsigned long, loff_t);
extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *,
- unsigned long, loff_t *);
+ unsigned long, loff_t);
extern ssize_t generic_file_direct_write(struct kiocb *, const struct iovec *,
unsigned long *, loff_t, loff_t *, size_t, size_t);
extern ssize_t generic_file_buffered_write(struct kiocb *, const struct iovec *,
unsigned long, loff_t, loff_t *, size_t, ssize_t);
extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
-ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos);
extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
extern void do_generic_mapping_read(struct address_space *mapping,
struct file_ra_state *, struct file *,
@@ -1667,6 +1760,8 @@ extern ssize_t generic_file_splice_read(struct file *, loff_t *,
struct pipe_inode_info *, size_t, unsigned int);
extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
struct file *, loff_t *, size_t, unsigned int);
+extern ssize_t generic_file_splice_write_nolock(struct pipe_inode_info *,
+ struct file *, loff_t *, size_t, unsigned int);
extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
struct file *out, loff_t *, size_t len, unsigned int flags);
extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
@@ -1674,10 +1769,6 @@ extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
extern void
file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping);
-extern ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos);
-ssize_t generic_file_writev(struct file *filp, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos);
extern loff_t no_llseek(struct file *file, loff_t offset, int origin);
extern loff_t generic_file_llseek(struct file *file, loff_t offset, int origin);
extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
@@ -1713,6 +1804,7 @@ static inline void do_generic_file_read(struct file * filp, loff_t *ppos,
actor);
}
+#ifdef CONFIG_BLOCK
ssize_t __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
struct block_device *bdev, const struct iovec *iov, loff_t offset,
unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io,
@@ -1750,6 +1842,7 @@ static inline ssize_t blockdev_direct_IO_own_locking(int rw, struct kiocb *iocb,
return __blockdev_direct_IO(rw, iocb, inode, bdev, iov, offset,
nr_segs, get_block, end_io, DIO_OWN_LOCKING);
}
+#endif
extern const struct file_operations generic_ro_fops;
diff --git a/include/linux/fs_enet_pd.h b/include/linux/fs_enet_pd.h
index 74ed35a00a94..543cd3cd9e77 100644
--- a/include/linux/fs_enet_pd.h
+++ b/include/linux/fs_enet_pd.h
@@ -55,6 +55,30 @@ static inline int fs_get_scc_index(enum fs_id id)
return -1;
}
+static inline int fs_fec_index2id(int index)
+{
+ int id = fsid_fec1 + index - 1;
+ if (id >= fsid_fec1 && id <= fsid_fec2)
+ return id;
+ return FS_MAX_INDEX;
+ }
+
+static inline int fs_fcc_index2id(int index)
+{
+ int id = fsid_fcc1 + index - 1;
+ if (id >= fsid_fcc1 && id <= fsid_fcc3)
+ return id;
+ return FS_MAX_INDEX;
+}
+
+static inline int fs_scc_index2id(int index)
+{
+ int id = fsid_scc1 + index - 1;
+ if (id >= fsid_scc1 && id <= fsid_scc4)
+ return id;
+ return FS_MAX_INDEX;
+}
+
enum fs_mii_method {
fsmii_fixed,
fsmii_fec,
@@ -87,18 +111,21 @@ struct fs_mii_bb_platform_info {
};
struct fs_platform_info {
-
- void(*init_ioports)(void);
+
+ void(*init_ioports)(struct fs_platform_info *);
/* device specific information */
int fs_no; /* controller index */
+ char fs_type[4]; /* controller type */
u32 cp_page; /* CPM page */
u32 cp_block; /* CPM sblock */
-
+
u32 clk_trx; /* some stuff for pins & mux configuration*/
+ u32 clk_rx;
+ u32 clk_tx;
u32 clk_route;
u32 clk_mask;
-
+
u32 mem_offset;
u32 dpram_offset;
u32 fcc_regs_c;
@@ -124,4 +151,16 @@ struct fs_mii_fec_platform_info {
u32 irq[32];
u32 mii_speed;
};
+
+static inline int fs_get_id(struct fs_platform_info *fpi)
+{
+ if(strstr(fpi->fs_type, "SCC"))
+ return fs_scc_index2id(fpi->fs_no);
+ if(strstr(fpi->fs_type, "FCC"))
+ return fs_fcc_index2id(fpi->fs_no);
+ if(strstr(fpi->fs_type, "FEC"))
+ return fs_fec_index2id(fpi->fs_no);
+ return fpi->fs_no;
+}
+
#endif
diff --git a/include/linux/fs_uart_pd.h b/include/linux/fs_uart_pd.h
index f5975126b712..809bb9ffc788 100644
--- a/include/linux/fs_uart_pd.h
+++ b/include/linux/fs_uart_pd.h
@@ -46,15 +46,27 @@ static inline int fs_uart_id_fsid2smc(int id)
}
struct fs_uart_platform_info {
- void(*init_ioports)(void);
+ void(*init_ioports)(struct fs_uart_platform_info *);
/* device specific information */
int fs_no; /* controller index */
+ char fs_type[4]; /* controller type */
u32 uart_clk;
u8 tx_num_fifo;
u8 tx_buf_size;
u8 rx_num_fifo;
u8 rx_buf_size;
u8 brg;
+ u8 clk_rx;
+ u8 clk_tx;
};
+static inline int fs_uart_get_id(struct fs_uart_platform_info *fpi)
+{
+ if(strstr(fpi->fs_type, "SMC"))
+ return fs_uart_id_smc2fsid(fpi->fs_no);
+ if(strstr(fpi->fs_type, "SCC"))
+ return fs_uart_id_scc2fsid(fpi->fs_no);
+ return fpi->fs_no;
+}
+
#endif
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 16fbe59edeb1..3da29e2d524a 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -46,18 +46,17 @@
struct gianfar_platform_data {
/* device specific information */
- u32 device_flags;
-
+ u32 device_flags;
/* board specific information */
- u32 board_flags;
- u32 bus_id;
- u32 phy_id;
- u8 mac_addr[6];
+ u32 board_flags;
+ u32 bus_id;
+ u32 phy_id;
+ u8 mac_addr[6];
};
struct gianfar_mdio_data {
/* board specific information */
- int irq[32];
+ int irq[32];
};
/* Flags related to gianfar device features */
@@ -76,14 +75,13 @@ struct gianfar_mdio_data {
struct fsl_i2c_platform_data {
/* device specific information */
- u32 device_flags;
+ u32 device_flags;
};
/* Flags related to I2C device features */
#define FSL_I2C_DEV_SEPARATE_DFSRR 0x00000001
#define FSL_I2C_DEV_CLOCK_5200 0x00000002
-
enum fsl_usb2_operating_modes {
FSL_USB2_MPH_HOST,
FSL_USB2_DR_HOST,
@@ -101,9 +99,9 @@ enum fsl_usb2_phy_modes {
struct fsl_usb2_platform_data {
/* board specific information */
- enum fsl_usb2_operating_modes operating_mode;
- enum fsl_usb2_phy_modes phy_mode;
- unsigned int port_enables;
+ enum fsl_usb2_operating_modes operating_mode;
+ enum fsl_usb2_phy_modes phy_mode;
+ unsigned int port_enables;
};
/* Flags in fsl_usb2_mph_platform_data */
@@ -121,5 +119,44 @@ struct fsl_spi_platform_data {
u32 sysclk;
};
-#endif /* _FSL_DEVICE_H_ */
-#endif /* __KERNEL__ */
+/* Ethernet interface (phy management and speed)
+*/
+enum enet_interface {
+ ENET_10_MII, /* 10 Base T, MII interface */
+ ENET_10_RMII, /* 10 Base T, RMII interface */
+ ENET_10_RGMII, /* 10 Base T, RGMII interface */
+ ENET_100_MII, /* 100 Base T, MII interface */
+ ENET_100_RMII, /* 100 Base T, RMII interface */
+ ENET_100_RGMII, /* 100 Base T, RGMII interface */
+ ENET_1000_GMII, /* 1000 Base T, GMII interface */
+ ENET_1000_RGMII, /* 1000 Base T, RGMII interface */
+ ENET_1000_TBI, /* 1000 Base T, TBI interface */
+ ENET_1000_RTBI /* 1000 Base T, RTBI interface */
+};
+
+struct ucc_geth_platform_data {
+ /* device specific information */
+ u32 device_flags;
+ u32 phy_reg_addr;
+
+ /* board specific information */
+ u32 board_flags;
+ u8 rx_clock;
+ u8 tx_clock;
+ u32 phy_id;
+ enum enet_interface phy_interface;
+ u32 phy_interrupt;
+ u8 mac_addr[6];
+};
+
+/* Flags related to UCC Gigabit Ethernet device features */
+#define FSL_UGETH_DEV_HAS_GIGABIT 0x00000001
+#define FSL_UGETH_DEV_HAS_COALESCE 0x00000002
+#define FSL_UGETH_DEV_HAS_RMON 0x00000004
+
+/* Flags in ucc_geth_platform_data */
+#define FSL_UGETH_BRD_HAS_PHY_INTR 0x00000001
+ /* if not set use a timer */
+
+#endif /* _FSL_DEVICE_H_ */
+#endif /* __KERNEL__ */
diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h
index 690c42803d2e..9869ef3674ac 100644
--- a/include/linux/genalloc.h
+++ b/include/linux/genalloc.h
@@ -31,5 +31,6 @@ struct gen_pool_chunk {
extern struct gen_pool *gen_pool_create(int, int);
extern int gen_pool_add(struct gen_pool *, unsigned long, size_t, int);
+extern void gen_pool_destroy(struct gen_pool *);
extern unsigned long gen_pool_alloc(struct gen_pool *, size_t);
extern void gen_pool_free(struct gen_pool *, unsigned long, size_t);
diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h
new file mode 100644
index 000000000000..80764f40be75
--- /dev/null
+++ b/include/linux/generic_acl.h
@@ -0,0 +1,36 @@
+/*
+ * fs/generic_acl.c
+ *
+ * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
+ *
+ * This file is released under the GPL.
+ */
+
+#ifndef GENERIC_ACL_H
+#define GENERIC_ACL_H
+
+#include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
+
+/**
+ * struct generic_acl_operations - filesystem operations
+ *
+ * Filesystems must make these operations available to the generic
+ * operations.
+ */
+struct generic_acl_operations {
+ struct posix_acl *(*getacl)(struct inode *, int);
+ void (*setacl)(struct inode *, int, struct posix_acl *);
+};
+
+size_t generic_acl_list(struct inode *, struct generic_acl_operations *, int,
+ char *, size_t);
+int generic_acl_get(struct inode *, struct generic_acl_operations *, int,
+ void *, size_t);
+int generic_acl_set(struct inode *, struct generic_acl_operations *, int,
+ const void *, size_t);
+int generic_acl_init(struct inode *, struct inode *,
+ struct generic_acl_operations *);
+int generic_acl_chmod(struct inode *, struct generic_acl_operations *);
+
+#endif
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index e4af57e87c17..41f276fdd185 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -11,6 +11,8 @@
#include <linux/types.h>
+#ifdef CONFIG_BLOCK
+
enum {
/* These three have identical behaviour; use the second one if DOS FDISK gets
confused about extended/logical partitions starting past cylinder 1023. */
@@ -420,3 +422,5 @@ static inline struct block_device *bdget_disk(struct gendisk *disk, int index)
#endif
#endif
+
+#endif
diff --git a/include/linux/getcpu.h b/include/linux/getcpu.h
index 031ed3780e45..c7372d7a97be 100644
--- a/include/linux/getcpu.h
+++ b/include/linux/getcpu.h
@@ -1,16 +1,18 @@
#ifndef _LINUX_GETCPU_H
#define _LINUX_GETCPU_H 1
-/* Cache for getcpu() to speed it up. Results might be upto a jiffie
+/* Cache for getcpu() to speed it up. Results might be a short time
out of date, but will be faster.
+
User programs should not refer to the contents of this structure.
- It is only a cache for vgetcpu(). It might change in future kernels.
+ I repeat they should not refer to it. If they do they will break
+ in future kernels.
+
+ It is only a private cache for vgetcpu(). It will change in future kernels.
The user program must store this information per thread (__thread)
If you want 100% accurate information pass NULL instead. */
struct getcpu_cache {
- unsigned long t0;
- unsigned long t1;
- unsigned long res[4];
+ unsigned long blob[128 / sizeof(long)];
};
#endif
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 8b34aabfe4c6..bf2b6bc3f6fd 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -67,7 +67,12 @@ struct vm_area_struct;
#define GFP_HIGHUSER (__GFP_WAIT | __GFP_IO | __GFP_FS | __GFP_HARDWALL | \
__GFP_HIGHMEM)
+#ifdef CONFIG_NUMA
#define GFP_THISNODE (__GFP_THISNODE | __GFP_NOWARN | __GFP_NORETRY)
+#else
+#define GFP_THISNODE 0
+#endif
+
/* Flag - indicates that the buffer will be suitable for DMA. Ignored on some
platforms, used as appropriate on others */
diff --git a/include/linux/gfs2_ondisk.h b/include/linux/gfs2_ondisk.h
new file mode 100644
index 000000000000..a7ae7c177cac
--- /dev/null
+++ b/include/linux/gfs2_ondisk.h
@@ -0,0 +1,443 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __GFS2_ONDISK_DOT_H__
+#define __GFS2_ONDISK_DOT_H__
+
+#define GFS2_MAGIC 0x01161970
+#define GFS2_BASIC_BLOCK 512
+#define GFS2_BASIC_BLOCK_SHIFT 9
+
+/* Lock numbers of the LM_TYPE_NONDISK type */
+
+#define GFS2_MOUNT_LOCK 0
+#define GFS2_LIVE_LOCK 1
+#define GFS2_TRANS_LOCK 2
+#define GFS2_RENAME_LOCK 3
+
+/* Format numbers for various metadata types */
+
+#define GFS2_FORMAT_NONE 0
+#define GFS2_FORMAT_SB 100
+#define GFS2_FORMAT_RG 200
+#define GFS2_FORMAT_RB 300
+#define GFS2_FORMAT_DI 400
+#define GFS2_FORMAT_IN 500
+#define GFS2_FORMAT_LF 600
+#define GFS2_FORMAT_JD 700
+#define GFS2_FORMAT_LH 800
+#define GFS2_FORMAT_LD 900
+#define GFS2_FORMAT_LB 1000
+#define GFS2_FORMAT_EA 1600
+#define GFS2_FORMAT_ED 1700
+#define GFS2_FORMAT_QC 1400
+/* These are format numbers for entities contained in files */
+#define GFS2_FORMAT_RI 1100
+#define GFS2_FORMAT_DE 1200
+#define GFS2_FORMAT_QU 1500
+/* These are part of the superblock */
+#define GFS2_FORMAT_FS 1801
+#define GFS2_FORMAT_MULTI 1900
+
+/*
+ * An on-disk inode number
+ */
+
+struct gfs2_inum {
+ __be64 no_formal_ino;
+ __be64 no_addr;
+};
+
+static inline int gfs2_inum_equal(const struct gfs2_inum *ino1,
+ const struct gfs2_inum *ino2)
+{
+ return ino1->no_formal_ino == ino2->no_formal_ino &&
+ ino1->no_addr == ino2->no_addr;
+}
+
+/*
+ * Generic metadata head structure
+ * Every inplace buffer logged in the journal must start with this.
+ */
+
+#define GFS2_METATYPE_NONE 0
+#define GFS2_METATYPE_SB 1
+#define GFS2_METATYPE_RG 2
+#define GFS2_METATYPE_RB 3
+#define GFS2_METATYPE_DI 4
+#define GFS2_METATYPE_IN 5
+#define GFS2_METATYPE_LF 6
+#define GFS2_METATYPE_JD 7
+#define GFS2_METATYPE_LH 8
+#define GFS2_METATYPE_LD 9
+#define GFS2_METATYPE_LB 12
+#define GFS2_METATYPE_EA 10
+#define GFS2_METATYPE_ED 11
+#define GFS2_METATYPE_QC 14
+
+struct gfs2_meta_header {
+ __be32 mh_magic;
+ __be32 mh_type;
+ __be64 __pad0; /* Was generation number in gfs1 */
+ __be32 mh_format;
+ __be32 __pad1; /* Was incarnation number in gfs1 */
+};
+
+/*
+ * super-block structure
+ *
+ * It's probably good if SIZEOF_SB <= GFS2_BASIC_BLOCK (512 bytes)
+ *
+ * Order is important, need to be able to read old superblocks to do on-disk
+ * version upgrades.
+ */
+
+/* Address of superblock in GFS2 basic blocks */
+#define GFS2_SB_ADDR 128
+
+/* The lock number for the superblock (must be zero) */
+#define GFS2_SB_LOCK 0
+
+/* Requirement: GFS2_LOCKNAME_LEN % 8 == 0
+ Includes: the fencing zero at the end */
+#define GFS2_LOCKNAME_LEN 64
+
+struct gfs2_sb {
+ struct gfs2_meta_header sb_header;
+
+ __be32 sb_fs_format;
+ __be32 sb_multihost_format;
+ __u32 __pad0; /* Was superblock flags in gfs1 */
+
+ __be32 sb_bsize;
+ __be32 sb_bsize_shift;
+ __u32 __pad1; /* Was journal segment size in gfs1 */
+
+ struct gfs2_inum sb_master_dir; /* Was jindex dinode in gfs1 */
+ struct gfs2_inum __pad2; /* Was rindex dinode in gfs1 */
+ struct gfs2_inum sb_root_dir;
+
+ char sb_lockproto[GFS2_LOCKNAME_LEN];
+ char sb_locktable[GFS2_LOCKNAME_LEN];
+ /* In gfs1, quota and license dinodes followed */
+};
+
+/*
+ * resource index structure
+ */
+
+struct gfs2_rindex {
+ __be64 ri_addr; /* grp block disk address */
+ __be32 ri_length; /* length of rgrp header in fs blocks */
+ __u32 __pad;
+
+ __be64 ri_data0; /* first data location */
+ __be32 ri_data; /* num of data blocks in rgrp */
+
+ __be32 ri_bitbytes; /* number of bytes in data bitmaps */
+
+ __u8 ri_reserved[64];
+};
+
+/*
+ * resource group header structure
+ */
+
+/* Number of blocks per byte in rgrp */
+#define GFS2_NBBY 4
+#define GFS2_BIT_SIZE 2
+#define GFS2_BIT_MASK 0x00000003
+
+#define GFS2_BLKST_FREE 0
+#define GFS2_BLKST_USED 1
+#define GFS2_BLKST_UNLINKED 2
+#define GFS2_BLKST_DINODE 3
+
+#define GFS2_RGF_JOURNAL 0x00000001
+#define GFS2_RGF_METAONLY 0x00000002
+#define GFS2_RGF_DATAONLY 0x00000004
+#define GFS2_RGF_NOALLOC 0x00000008
+
+struct gfs2_rgrp {
+ struct gfs2_meta_header rg_header;
+
+ __be32 rg_flags;
+ __be32 rg_free;
+ __be32 rg_dinodes;
+ __be32 __pad;
+ __be64 rg_igeneration;
+
+ __u8 rg_reserved[80]; /* Several fields from gfs1 now reserved */
+};
+
+/*
+ * quota structure
+ */
+
+struct gfs2_quota {
+ __be64 qu_limit;
+ __be64 qu_warn;
+ __be64 qu_value;
+ __u8 qu_reserved[64];
+};
+
+/*
+ * dinode structure
+ */
+
+#define GFS2_MAX_META_HEIGHT 10
+#define GFS2_DIR_MAX_DEPTH 17
+
+#define DT2IF(dt) (((dt) << 12) & S_IFMT)
+#define IF2DT(sif) (((sif) & S_IFMT) >> 12)
+
+enum {
+ gfs2fl_Jdata = 0,
+ gfs2fl_ExHash = 1,
+ gfs2fl_Unused = 2,
+ gfs2fl_EaIndirect = 3,
+ gfs2fl_Directio = 4,
+ gfs2fl_Immutable = 5,
+ gfs2fl_AppendOnly = 6,
+ gfs2fl_NoAtime = 7,
+ gfs2fl_Sync = 8,
+ gfs2fl_System = 9,
+ gfs2fl_TruncInProg = 29,
+ gfs2fl_InheritDirectio = 30,
+ gfs2fl_InheritJdata = 31,
+};
+
+/* Dinode flags */
+#define GFS2_DIF_JDATA 0x00000001
+#define GFS2_DIF_EXHASH 0x00000002
+#define GFS2_DIF_UNUSED 0x00000004 /* only in gfs1 */
+#define GFS2_DIF_EA_INDIRECT 0x00000008
+#define GFS2_DIF_DIRECTIO 0x00000010
+#define GFS2_DIF_IMMUTABLE 0x00000020
+#define GFS2_DIF_APPENDONLY 0x00000040
+#define GFS2_DIF_NOATIME 0x00000080
+#define GFS2_DIF_SYNC 0x00000100
+#define GFS2_DIF_SYSTEM 0x00000200 /* New in gfs2 */
+#define GFS2_DIF_TRUNC_IN_PROG 0x20000000 /* New in gfs2 */
+#define GFS2_DIF_INHERIT_DIRECTIO 0x40000000
+#define GFS2_DIF_INHERIT_JDATA 0x80000000
+
+struct gfs2_dinode {
+ struct gfs2_meta_header di_header;
+
+ struct gfs2_inum di_num;
+
+ __be32 di_mode; /* mode of file */
+ __be32 di_uid; /* owner's user id */
+ __be32 di_gid; /* owner's group id */
+ __be32 di_nlink; /* number of links to this file */
+ __be64 di_size; /* number of bytes in file */
+ __be64 di_blocks; /* number of blocks in file */
+ __be64 di_atime; /* time last accessed */
+ __be64 di_mtime; /* time last modified */
+ __be64 di_ctime; /* time last changed */
+ __be32 di_major; /* device major number */
+ __be32 di_minor; /* device minor number */
+
+ /* This section varies from gfs1. Padding added to align with
+ * remainder of dinode
+ */
+ __be64 di_goal_meta; /* rgrp to alloc from next */
+ __be64 di_goal_data; /* data block goal */
+ __be64 di_generation; /* generation number for NFS */
+
+ __be32 di_flags; /* GFS2_DIF_... */
+ __be32 di_payload_format; /* GFS2_FORMAT_... */
+ __u16 __pad1; /* Was ditype in gfs1 */
+ __be16 di_height; /* height of metadata */
+ __u32 __pad2; /* Unused incarnation number from gfs1 */
+
+ /* These only apply to directories */
+ __u16 __pad3; /* Padding */
+ __be16 di_depth; /* Number of bits in the table */
+ __be32 di_entries; /* The number of entries in the directory */
+
+ struct gfs2_inum __pad4; /* Unused even in current gfs1 */
+
+ __be64 di_eattr; /* extended attribute block number */
+
+ __u8 di_reserved[56];
+};
+
+/*
+ * directory structure - many of these per directory file
+ */
+
+#define GFS2_FNAMESIZE 255
+#define GFS2_DIRENT_SIZE(name_len) ((sizeof(struct gfs2_dirent) + (name_len) + 7) & ~7)
+
+struct gfs2_dirent {
+ struct gfs2_inum de_inum;
+ __be32 de_hash;
+ __be16 de_rec_len;
+ __be16 de_name_len;
+ __be16 de_type;
+ __u8 __pad[14];
+};
+
+/*
+ * Header of leaf directory nodes
+ */
+
+struct gfs2_leaf {
+ struct gfs2_meta_header lf_header;
+
+ __be16 lf_depth; /* Depth of leaf */
+ __be16 lf_entries; /* Number of dirents in leaf */
+ __be32 lf_dirent_format; /* Format of the dirents */
+ __be64 lf_next; /* Next leaf, if overflow */
+
+ __u8 lf_reserved[64];
+};
+
+/*
+ * Extended attribute header format
+ */
+
+#define GFS2_EA_MAX_NAME_LEN 255
+#define GFS2_EA_MAX_DATA_LEN 65536
+
+#define GFS2_EATYPE_UNUSED 0
+#define GFS2_EATYPE_USR 1
+#define GFS2_EATYPE_SYS 2
+#define GFS2_EATYPE_SECURITY 3
+
+#define GFS2_EATYPE_LAST 3
+#define GFS2_EATYPE_VALID(x) ((x) <= GFS2_EATYPE_LAST)
+
+#define GFS2_EAFLAG_LAST 0x01 /* last ea in block */
+
+struct gfs2_ea_header {
+ __be32 ea_rec_len;
+ __be32 ea_data_len;
+ __u8 ea_name_len; /* no NULL pointer after the string */
+ __u8 ea_type; /* GFS2_EATYPE_... */
+ __u8 ea_flags; /* GFS2_EAFLAG_... */
+ __u8 ea_num_ptrs;
+ __u32 __pad;
+};
+
+/*
+ * Log header structure
+ */
+
+#define GFS2_LOG_HEAD_UNMOUNT 0x00000001 /* log is clean */
+
+struct gfs2_log_header {
+ struct gfs2_meta_header lh_header;
+
+ __be64 lh_sequence; /* Sequence number of this transaction */
+ __be32 lh_flags; /* GFS2_LOG_HEAD_... */
+ __be32 lh_tail; /* Block number of log tail */
+ __be32 lh_blkno;
+ __be32 lh_hash;
+};
+
+/*
+ * Log type descriptor
+ */
+
+#define GFS2_LOG_DESC_METADATA 300
+/* ld_data1 is the number of metadata blocks in the descriptor.
+ ld_data2 is unused. */
+
+#define GFS2_LOG_DESC_REVOKE 301
+/* ld_data1 is the number of revoke blocks in the descriptor.
+ ld_data2 is unused. */
+
+#define GFS2_LOG_DESC_JDATA 302
+/* ld_data1 is the number of data blocks in the descriptor.
+ ld_data2 is unused. */
+
+struct gfs2_log_descriptor {
+ struct gfs2_meta_header ld_header;
+
+ __be32 ld_type; /* GFS2_LOG_DESC_... */
+ __be32 ld_length; /* Number of buffers in this chunk */
+ __be32 ld_data1; /* descriptor-specific field */
+ __be32 ld_data2; /* descriptor-specific field */
+
+ __u8 ld_reserved[32];
+};
+
+/*
+ * Inum Range
+ * Describe a range of formal inode numbers allocated to
+ * one machine to assign to inodes.
+ */
+
+#define GFS2_INUM_QUANTUM 1048576
+
+struct gfs2_inum_range {
+ __be64 ir_start;
+ __be64 ir_length;
+};
+
+/*
+ * Statfs change
+ * Describes an change to the pool of free and allocated
+ * blocks.
+ */
+
+struct gfs2_statfs_change {
+ __be64 sc_total;
+ __be64 sc_free;
+ __be64 sc_dinodes;
+};
+
+/*
+ * Quota change
+ * Describes an allocation change for a particular
+ * user or group.
+ */
+
+#define GFS2_QCF_USER 0x00000001
+
+struct gfs2_quota_change {
+ __be64 qc_change;
+ __be32 qc_flags; /* GFS2_QCF_... */
+ __be32 qc_id;
+};
+
+#ifdef __KERNEL__
+/* Translation functions */
+
+extern void gfs2_inum_in(struct gfs2_inum *no, const void *buf);
+extern void gfs2_inum_out(const struct gfs2_inum *no, void *buf);
+extern void gfs2_sb_in(struct gfs2_sb *sb, const void *buf);
+extern void gfs2_rindex_in(struct gfs2_rindex *ri, const void *buf);
+extern void gfs2_rindex_out(const struct gfs2_rindex *ri, void *buf);
+extern void gfs2_rgrp_in(struct gfs2_rgrp *rg, const void *buf);
+extern void gfs2_rgrp_out(const struct gfs2_rgrp *rg, void *buf);
+extern void gfs2_quota_in(struct gfs2_quota *qu, const void *buf);
+extern void gfs2_quota_out(const struct gfs2_quota *qu, void *buf);
+extern void gfs2_dinode_in(struct gfs2_dinode *di, const void *buf);
+extern void gfs2_dinode_out(const struct gfs2_dinode *di, void *buf);
+extern void gfs2_ea_header_in(struct gfs2_ea_header *ea, const void *buf);
+extern void gfs2_ea_header_out(const struct gfs2_ea_header *ea, void *buf);
+extern void gfs2_log_header_in(struct gfs2_log_header *lh, const void *buf);
+extern void gfs2_inum_range_in(struct gfs2_inum_range *ir, const void *buf);
+extern void gfs2_inum_range_out(const struct gfs2_inum_range *ir, void *buf);
+extern void gfs2_statfs_change_in(struct gfs2_statfs_change *sc, const void *buf);
+extern void gfs2_statfs_change_out(const struct gfs2_statfs_change *sc, void *buf);
+extern void gfs2_quota_change_in(struct gfs2_quota_change *qc, const void *buf);
+
+/* Printing functions */
+
+extern void gfs2_rindex_print(const struct gfs2_rindex *ri);
+extern void gfs2_dinode_print(const struct gfs2_dinode *di);
+
+#endif /* __KERNEL__ */
+
+#endif /* __GFS2_ONDISK_DOT_H__ */
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 50d8b5744cf6..612472aaa79c 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -28,11 +28,16 @@
#ifndef HARDIRQ_BITS
#define HARDIRQ_BITS 12
+
+#ifndef MAX_HARDIRQS_PER_CPU
+#define MAX_HARDIRQS_PER_CPU NR_IRQS
+#endif
+
/*
* The hardirq mask has to be large enough to have space for potentially
* all IRQ sources in the system nesting on a single CPU.
*/
-#if (1 << HARDIRQ_BITS) < NR_IRQS
+#if (1 << HARDIRQ_BITS) < MAX_HARDIRQS_PER_CPU
# error HARDIRQ_BITS is too low!
#endif
#endif
diff --git a/include/linux/harrier_defs.h b/include/linux/harrier_defs.h
index 685b252e16cc..efef11db790f 100644
--- a/include/linux/harrier_defs.h
+++ b/include/linux/harrier_defs.h
@@ -1,5 +1,5 @@
/*
- * asm-ppc/harrier_defs.h
+ * include/linux/harrier_defs.h
*
* Definitions for Motorola MCG Harrier North Bridge & Memory controller
*
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index d5ebbb29aeae..d4b333938f73 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -11,95 +11,46 @@
#ifndef __HDLC_H
#define __HDLC_H
-#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
-
-#define CLOCK_DEFAULT 0 /* Default setting */
-#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
-#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
-#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
-#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
-
-
-#define ENCODING_DEFAULT 0 /* Default setting */
-#define ENCODING_NRZ 1
-#define ENCODING_NRZI 2
-#define ENCODING_FM_MARK 3
-#define ENCODING_FM_SPACE 4
-#define ENCODING_MANCHESTER 5
-
-
-#define PARITY_DEFAULT 0 /* Default setting */
-#define PARITY_NONE 1 /* No parity */
-#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
-#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
-#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
-#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
-#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
-#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
-
-#define LMI_DEFAULT 0 /* Default setting */
-#define LMI_NONE 1 /* No LMI, all PVCs are static */
-#define LMI_ANSI 2 /* ANSI Annex D */
-#define LMI_CCITT 3 /* ITU-T Annex A */
-#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
+#if 0
#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */
+#else
+#define HDLC_MAX_MRU 1600 /* as required for FR network */
+#endif
#ifdef __KERNEL__
#include <linux/skbuff.h>
#include <linux/netdevice.h>
-#include <net/syncppp.h>
#include <linux/hdlc/ioctl.h>
-typedef struct { /* Used in Cisco and PPP mode */
- u8 address;
- u8 control;
- u16 protocol;
-}__attribute__ ((packed)) hdlc_header;
-
-
-
-typedef struct {
- u32 type; /* code */
- u32 par1;
- u32 par2;
- u16 rel; /* reliability */
- u32 time;
-}__attribute__ ((packed)) cisco_packet;
-#define CISCO_PACKET_LEN 18
-#define CISCO_BIG_PACKET_LEN 20
-
-
-
-typedef struct pvc_device_struct {
- struct net_device *master;
- struct net_device *main;
- struct net_device *ether; /* bridged Ethernet interface */
- struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
- int dlci;
- int open_count;
-
- struct {
- unsigned int new: 1;
- unsigned int active: 1;
- unsigned int exist: 1;
- unsigned int deleted: 1;
- unsigned int fecn: 1;
- unsigned int becn: 1;
- unsigned int bandwidth; /* Cisco LMI reporting only */
- }state;
-}pvc_device;
-
-
-
-typedef struct hdlc_device_struct {
- /* To be initialized by hardware driver */
+/* Used by all network devices here, pointed to by netdev_priv(dev) */
+struct hdlc_device_desc {
+ int (*netif_rx)(struct sk_buff *skb);
struct net_device_stats stats;
-
+};
+
+/* This structure is a private property of HDLC protocols.
+ Hardware drivers have no interest here */
+
+struct hdlc_proto {
+ int (*open)(struct net_device *dev);
+ void (*close)(struct net_device *dev);
+ void (*start)(struct net_device *dev); /* if open & DCD */
+ void (*stop)(struct net_device *dev); /* if open & !DCD */
+ void (*detach)(struct net_device *dev);
+ int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
+ unsigned short (*type_trans)(struct sk_buff *skb,
+ struct net_device *dev);
+ struct module *module;
+ struct hdlc_proto *next; /* next protocol in the list */
+};
+
+
+typedef struct hdlc_device {
/* used by HDLC layer to take control over HDLC device from hw driver*/
int (*attach)(struct net_device *dev,
unsigned short encoding, unsigned short parity);
@@ -107,82 +58,18 @@ typedef struct hdlc_device_struct {
/* hardware driver must handle this instead of dev->hard_start_xmit */
int (*xmit)(struct sk_buff *skb, struct net_device *dev);
-
/* Things below are for HDLC layer internal use only */
- struct {
- int (*open)(struct net_device *dev);
- void (*close)(struct net_device *dev);
-
- /* if open & DCD */
- void (*start)(struct net_device *dev);
- /* if open & !DCD */
- void (*stop)(struct net_device *dev);
-
- void (*detach)(struct hdlc_device_struct *hdlc);
- int (*netif_rx)(struct sk_buff *skb);
- unsigned short (*type_trans)(struct sk_buff *skb,
- struct net_device *dev);
- int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */
- }proto;
-
+ const struct hdlc_proto *proto;
int carrier;
int open;
spinlock_t state_lock;
-
- union {
- struct {
- fr_proto settings;
- pvc_device *first_pvc;
- int dce_pvc_count;
-
- struct timer_list timer;
- unsigned long last_poll;
- int reliable;
- int dce_changed;
- int request;
- int fullrep_sent;
- u32 last_errors; /* last errors bit list */
- u8 n391cnt;
- u8 txseq; /* TX sequence number */
- u8 rxseq; /* RX sequence number */
- }fr;
-
- struct {
- cisco_proto settings;
-
- struct timer_list timer;
- unsigned long last_poll;
- int up;
- int request_sent;
- u32 txseq; /* TX sequence number */
- u32 rxseq; /* RX sequence number */
- }cisco;
-
- struct {
- raw_hdlc_proto settings;
- }raw_hdlc;
-
- struct {
- struct ppp_device pppdev;
- struct ppp_device *syncppp_ptr;
- int (*old_change_mtu)(struct net_device *dev,
- int new_mtu);
- }ppp;
- }state;
+ void *state;
void *priv;
}hdlc_device;
-int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr);
-int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
-int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
-int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
-int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr);
-int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr);
-
-
-/* Exported from hdlc.o */
+/* Exported from hdlc module */
/* Called by hardware driver when a user requests HDLC service */
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
@@ -191,17 +78,21 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
#define register_hdlc_device(dev) register_netdev(dev)
void unregister_hdlc_device(struct net_device *dev);
+
+void register_hdlc_protocol(struct hdlc_proto *proto);
+void unregister_hdlc_protocol(struct hdlc_proto *proto);
+
struct net_device *alloc_hdlcdev(void *priv);
-static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+
+static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev)
{
return netdev_priv(dev);
}
-
-static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
{
- return (pvc_device*)dev->priv;
+ return netdev_priv(dev) + sizeof(struct hdlc_device_desc);
}
@@ -225,18 +116,14 @@ int hdlc_open(struct net_device *dev);
/* Must be called by hardware driver when HDLC device is being closed */
void hdlc_close(struct net_device *dev);
+int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
+ int (*rx)(struct sk_buff *skb), size_t size);
/* May be used by hardware driver to gain control over HDLC device */
-static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
-{
- if (hdlc->proto.detach)
- hdlc->proto.detach(hdlc);
- hdlc->proto.detach = NULL;
-}
-
+void detach_hdlc_protocol(struct net_device *dev);
static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
{
- return &dev_to_hdlc(dev)->stats;
+ return &dev_to_desc(dev)->stats;
}
@@ -248,8 +135,8 @@ static __inline__ __be16 hdlc_type_trans(struct sk_buff *skb,
skb->mac.raw = skb->data;
skb->dev = dev;
- if (hdlc->proto.type_trans)
- return hdlc->proto.type_trans(skb, dev);
+ if (hdlc->proto->type_trans)
+ return hdlc->proto->type_trans(skb, dev);
else
return htons(ETH_P_HDLC);
}
diff --git a/include/linux/hdlc/ioctl.h b/include/linux/hdlc/ioctl.h
index 78430ba3ea69..583972364357 100644
--- a/include/linux/hdlc/ioctl.h
+++ b/include/linux/hdlc/ioctl.h
@@ -1,6 +1,39 @@
#ifndef __HDLC_IOCTL_H__
#define __HDLC_IOCTL_H__
+
+#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
+
+#define CLOCK_DEFAULT 0 /* Default setting */
+#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
+#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
+#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
+#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
+
+
+#define ENCODING_DEFAULT 0 /* Default setting */
+#define ENCODING_NRZ 1
+#define ENCODING_NRZI 2
+#define ENCODING_FM_MARK 3
+#define ENCODING_FM_SPACE 4
+#define ENCODING_MANCHESTER 5
+
+
+#define PARITY_DEFAULT 0 /* Default setting */
+#define PARITY_NONE 1 /* No parity */
+#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
+#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
+#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
+#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
+#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
+#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
+
+#define LMI_DEFAULT 0 /* Default setting */
+#define LMI_NONE 1 /* No LMI, all PVCs are static */
+#define LMI_ANSI 2 /* ANSI Annex D */
+#define LMI_CCITT 3 /* ITU-T Annex A */
+#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
+
typedef struct {
unsigned int clock_rate; /* bits per second */
unsigned int clock_type; /* internal, external, TX-internal etc. */
diff --git a/include/linux/hiddev.h b/include/linux/hiddev.h
index 945ba1ad14ac..acbdae6d7ae1 100644
--- a/include/linux/hiddev.h
+++ b/include/linux/hiddev.h
@@ -222,7 +222,7 @@ struct hid_report;
int hiddev_connect(struct hid_device *);
void hiddev_disconnect(struct hid_device *);
void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value, struct pt_regs *regs);
+ struct hid_usage *usage, __s32 value);
void hiddev_report_event(struct hid_device *hid, struct hid_report *report);
int __init hiddev_init(void);
void hiddev_exit(void);
@@ -230,7 +230,7 @@ void hiddev_exit(void);
static inline int hiddev_connect(struct hid_device *hid) { return -1; }
static inline void hiddev_disconnect(struct hid_device *hid) { }
static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value, struct pt_regs *regs) { }
+ struct hid_usage *usage, __s32 value) { }
static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { }
static inline int hiddev_init(void) { return 0; }
static inline void hiddev_exit(void) { }
diff --git a/include/linux/hrtimer.h b/include/linux/hrtimer.h
index 4fc379de6c2f..fca93025ab51 100644
--- a/include/linux/hrtimer.h
+++ b/include/linux/hrtimer.h
@@ -138,6 +138,7 @@ extern long hrtimer_nanosleep(struct timespec *rqtp,
struct timespec __user *rmtp,
const enum hrtimer_mode mode,
const clockid_t clockid);
+extern long hrtimer_nanosleep_restart(struct restart_block *restart_block);
extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
struct task_struct *tsk);
diff --git a/include/linux/htirq.h b/include/linux/htirq.h
new file mode 100644
index 000000000000..1f15ce279a23
--- /dev/null
+++ b/include/linux/htirq.h
@@ -0,0 +1,15 @@
+#ifndef LINUX_HTIRQ_H
+#define LINUX_HTIRQ_H
+
+/* Helper functions.. */
+void write_ht_irq_low(unsigned int irq, u32 data);
+void write_ht_irq_high(unsigned int irq, u32 data);
+u32 read_ht_irq_low(unsigned int irq);
+u32 read_ht_irq_high(unsigned int irq);
+void mask_ht_irq(unsigned int irq);
+void unmask_ht_irq(unsigned int irq);
+
+/* The arch hook for getting things started */
+int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev);
+
+#endif /* LINUX_HTIRQ_H */
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index c25a38d8f600..5081d27bfa27 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -17,6 +17,7 @@ int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void __user *
int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *);
int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int);
void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
+void __unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
int hugetlb_report_meminfo(char *);
int hugetlb_report_node_meminfo(int, char *);
diff --git a/include/linux/i2c-algo-bit.h b/include/linux/i2c-algo-bit.h
index c0e7fab28ce3..c8f8df25c7e0 100644
--- a/include/linux/i2c-algo-bit.h
+++ b/include/linux/i2c-algo-bit.h
@@ -40,7 +40,6 @@ struct i2c_algo_bit_data {
/* local settings */
int udelay; /* half-clock-cycle time in microsecs */
/* i.e. clock is (500 / udelay) KHz */
- int mdelay; /* in millisecs, unused */
int timeout; /* in jiffies */
};
diff --git a/include/linux/i2c-algo-pcf.h b/include/linux/i2c-algo-pcf.h
index 18b0adf57a3d..9908f3fc4839 100644
--- a/include/linux/i2c-algo-pcf.h
+++ b/include/linux/i2c-algo-pcf.h
@@ -35,7 +35,6 @@ struct i2c_algo_pcf_data {
/* local settings */
int udelay;
- int mdelay;
int timeout;
};
diff --git a/include/linux/i2c-algo-sibyte.h b/include/linux/i2c-algo-sibyte.h
deleted file mode 100644
index 03914ded8614..000000000000
--- a/include/linux/i2c-algo-sibyte.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2001,2002,2003 Broadcom 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 I2C_ALGO_SIBYTE_H
-#define I2C_ALGO_SIBYTE_H 1
-
-#include <linux/i2c.h>
-
-struct i2c_algo_sibyte_data {
- void *data; /* private data */
- int bus; /* which bus */
- void *reg_base; /* CSR base */
-};
-
-int i2c_sibyte_add_bus(struct i2c_adapter *, int speed);
-int i2c_sibyte_del_bus(struct i2c_adapter *);
-
-#endif /* I2C_ALGO_SIBYTE_H */
diff --git a/include/linux/i2c-id.h b/include/linux/i2c-id.h
index 9418519a55d1..0a8f750cbede 100644
--- a/include/linux/i2c-id.h
+++ b/include/linux/i2c-id.h
@@ -193,6 +193,7 @@
#define I2C_HW_B_RADEON 0x01001e /* radeon framebuffer driver */
#define I2C_HW_B_EM28XX 0x01001f /* em28xx video capture cards */
#define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */
+#define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */
/* --- PCF 8584 based algorithms */
#define I2C_HW_P_LP 0x020000 /* Parallel port interface */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index eb0628a7ecc6..9b5d04768c2c 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -64,14 +64,6 @@ extern int i2c_master_recv(struct i2c_client *,char* ,int);
*/
extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
-/*
- * Some adapter types (i.e. PCF 8584 based ones) may support slave behaviuor.
- * This is not tested/implemented yet and will change in the future.
- */
-extern int i2c_slave_send(struct i2c_client *,char*,int);
-extern int i2c_slave_recv(struct i2c_client *,char*,int);
-
-
/* This is the very generalized SMBus access routine. You probably do not
want to use this, though; one of the functions below may be much easier,
@@ -201,10 +193,6 @@ struct i2c_algorithm {
unsigned short flags, char read_write,
u8 command, int size, union i2c_smbus_data * data);
- /* --- these optional/future use for some adapter types.*/
- int (*slave_send)(struct i2c_adapter *,char*,int);
- int (*slave_recv)(struct i2c_adapter *,char*,int);
-
/* --- ioctl like call to set div. parameters. */
int (*algo_control)(struct i2c_adapter *, unsigned int, unsigned long);
@@ -220,7 +208,7 @@ struct i2c_adapter {
struct module *owner;
unsigned int id;
unsigned int class;
- struct i2c_algorithm *algo;/* the algorithm to access the bus */
+ const struct i2c_algorithm *algo; /* the algorithm to access the bus */
void *algo_data;
/* --- administration stuff. */
diff --git a/include/linux/icmp.h b/include/linux/icmp.h
index f0b571f1060b..878cfe4e587f 100644
--- a/include/linux/icmp.h
+++ b/include/linux/icmp.h
@@ -68,16 +68,16 @@
struct icmphdr {
__u8 type;
__u8 code;
- __u16 checksum;
+ __be16 checksum;
union {
struct {
- __u16 id;
- __u16 sequence;
+ __be16 id;
+ __be16 sequence;
} echo;
- __u32 gateway;
+ __be32 gateway;
struct {
- __u16 __unused;
- __u16 mtu;
+ __be16 __unused;
+ __be16 mtu;
} frag;
} un;
};
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 99620451d958..9c2050293f17 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -251,7 +251,8 @@ static inline void ide_std_init_ports(hw_regs_t *hw,
#include <asm/ide.h>
-#ifndef MAX_HWIFS
+#if !defined(MAX_HWIFS) || defined(CONFIG_EMBEDDED)
+#undef MAX_HWIFS
#define MAX_HWIFS CONFIG_IDE_MAX_HWIFS
#endif
@@ -773,12 +774,13 @@ typedef struct hwif_s {
unsigned long dma_status; /* dma status register */
unsigned long dma_vendor3; /* dma vendor 3 register */
unsigned long dma_prdtable; /* actual prd table address */
- unsigned long dma_base2; /* extended base addr for dma ports */
- unsigned dma_extra; /* extra addr for dma ports */
unsigned long config_data; /* for use by chipset-specific code */
unsigned long select_data; /* for use by chipset-specific code */
+ unsigned long extra_base; /* extra addr for dma ports */
+ unsigned extra_ports; /* number of extra dma ports */
+
unsigned noprobe : 1; /* don't probe for this interface */
unsigned present : 1; /* this interface exists */
unsigned hold : 1; /* this interface is always present */
@@ -823,6 +825,9 @@ typedef struct hwgroup_s {
unsigned int sleeping : 1;
/* BOOL: polling active & poll_timeout field valid */
unsigned int polling : 1;
+ /* BOOL: in a polling reset situation. Must not trigger another reset yet */
+ unsigned int resetting : 1;
+
/* current drive */
ide_drive_t *drive;
/* ptr to current hwif in linked-list */
@@ -1180,7 +1185,7 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
extern int ide_spin_wait_hwgroup(ide_drive_t *);
extern void ide_timer_expiry(unsigned long);
-extern irqreturn_t ide_intr(int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t ide_intr(int irq, void *dev_id);
extern void do_ide_request(request_queue_t *);
void ide_init_disk(struct gendisk *, ide_drive_t *);
@@ -1190,7 +1195,6 @@ extern int ideprobe_init(void);
extern void ide_scan_pcibus(int scan_direction) __init;
extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner);
#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE)
-extern void ide_pci_unregister_driver(struct pci_driver *driver);
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);
diff --git a/include/linux/if.h b/include/linux/if.h
index cd080d765324..32bf419351f1 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -59,6 +59,8 @@
#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */
#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
+#define IFF_BONDING 0x20 /* bonding master or slave */
+#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
#define IF_GET_IFACE 0x0001 /* for querying only */
#define IF_GET_PROTO 0x0002
@@ -212,134 +214,4 @@ struct ifconf
#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */
#define ifc_req ifc_ifcu.ifcu_req /* array of structures */
-/* The struct should be in sync with struct net_device_stats */
-struct rtnl_link_stats
-{
- __u32 rx_packets; /* total packets received */
- __u32 tx_packets; /* total packets transmitted */
- __u32 rx_bytes; /* total bytes received */
- __u32 tx_bytes; /* total bytes transmitted */
- __u32 rx_errors; /* bad packets received */
- __u32 tx_errors; /* packet transmit problems */
- __u32 rx_dropped; /* no space in linux buffers */
- __u32 tx_dropped; /* no space available in linux */
- __u32 multicast; /* multicast packets received */
- __u32 collisions;
-
- /* detailed rx_errors: */
- __u32 rx_length_errors;
- __u32 rx_over_errors; /* receiver ring buff overflow */
- __u32 rx_crc_errors; /* recved pkt with crc error */
- __u32 rx_frame_errors; /* recv'd frame alignment error */
- __u32 rx_fifo_errors; /* recv'r fifo overrun */
- __u32 rx_missed_errors; /* receiver missed packet */
-
- /* detailed tx_errors */
- __u32 tx_aborted_errors;
- __u32 tx_carrier_errors;
- __u32 tx_fifo_errors;
- __u32 tx_heartbeat_errors;
- __u32 tx_window_errors;
-
- /* for cslip etc */
- __u32 rx_compressed;
- __u32 tx_compressed;
-};
-
-/* The struct should be in sync with struct ifmap */
-struct rtnl_link_ifmap
-{
- __u64 mem_start;
- __u64 mem_end;
- __u64 base_addr;
- __u16 irq;
- __u8 dma;
- __u8 port;
-};
-
-enum
-{
- IFLA_UNSPEC,
- IFLA_ADDRESS,
- IFLA_BROADCAST,
- IFLA_IFNAME,
- IFLA_MTU,
- IFLA_LINK,
- IFLA_QDISC,
- IFLA_STATS,
- IFLA_COST,
-#define IFLA_COST IFLA_COST
- IFLA_PRIORITY,
-#define IFLA_PRIORITY IFLA_PRIORITY
- IFLA_MASTER,
-#define IFLA_MASTER IFLA_MASTER
- IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
-#define IFLA_WIRELESS IFLA_WIRELESS
- IFLA_PROTINFO, /* Protocol specific information for a link */
-#define IFLA_PROTINFO IFLA_PROTINFO
- IFLA_TXQLEN,
-#define IFLA_TXQLEN IFLA_TXQLEN
- IFLA_MAP,
-#define IFLA_MAP IFLA_MAP
- IFLA_WEIGHT,
-#define IFLA_WEIGHT IFLA_WEIGHT
- IFLA_OPERSTATE,
- IFLA_LINKMODE,
- __IFLA_MAX
-};
-
-
-#define IFLA_MAX (__IFLA_MAX - 1)
-
-/* ifi_flags.
-
- IFF_* flags.
-
- The only change is:
- IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
- more not changeable by user. They describe link media
- characteristics and set by device driver.
-
- Comments:
- - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
- - If neither of these three flags are set;
- the interface is NBMA.
-
- - IFF_MULTICAST does not mean anything special:
- multicasts can be used on all not-NBMA links.
- IFF_MULTICAST means that this media uses special encapsulation
- for multicast frames. Apparently, all IFF_POINTOPOINT and
- IFF_BROADCAST devices are able to use multicasts too.
- */
-
-/* IFLA_LINK.
- For usual devices it is equal ifi_index.
- If it is a "virtual interface" (f.e. tunnel), ifi_link
- can point to real physical interface (f.e. for bandwidth calculations),
- or maybe 0, what means, that real media is unknown (usual
- for IPIP tunnels, when route to endpoint is allowed to change)
- */
-
-/* Subtype attributes for IFLA_PROTINFO */
-enum
-{
- IFLA_INET6_UNSPEC,
- IFLA_INET6_FLAGS, /* link flags */
- IFLA_INET6_CONF, /* sysctl parameters */
- IFLA_INET6_STATS, /* statistics */
- IFLA_INET6_MCAST, /* MC things. What of them? */
- IFLA_INET6_CACHEINFO, /* time values and max reasm size */
- __IFLA_INET6_MAX
-};
-
-#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
-
-struct ifla_cacheinfo
-{
- __u32 max_reasm_len;
- __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
- __u32 reachable_time;
- __u32 retrans_time;
-};
-
#endif /* _LINUX_IF_H */
diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h
index a8b1a2071838..7f5714214ee3 100644
--- a/include/linux/if_arp.h
+++ b/include/linux/if_arp.h
@@ -130,11 +130,11 @@ struct arpreq_old {
struct arphdr
{
- unsigned short ar_hrd; /* format of hardware address */
- unsigned short ar_pro; /* format of protocol address */
+ __be16 ar_hrd; /* format of hardware address */
+ __be16 ar_pro; /* format of protocol address */
unsigned char ar_hln; /* length of hardware address */
unsigned char ar_pln; /* length of protocol address */
- unsigned short ar_op; /* ARP opcode (command) */
+ __be16 ar_op; /* ARP opcode (command) */
#if 0
/*
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
new file mode 100644
index 000000000000..e963a077e6f5
--- /dev/null
+++ b/include/linux/if_link.h
@@ -0,0 +1,136 @@
+#ifndef _LINUX_IF_LINK_H
+#define _LINUX_IF_LINK_H
+
+#include <linux/netlink.h>
+
+/* The struct should be in sync with struct net_device_stats */
+struct rtnl_link_stats
+{
+ __u32 rx_packets; /* total packets received */
+ __u32 tx_packets; /* total packets transmitted */
+ __u32 rx_bytes; /* total bytes received */
+ __u32 tx_bytes; /* total bytes transmitted */
+ __u32 rx_errors; /* bad packets received */
+ __u32 tx_errors; /* packet transmit problems */
+ __u32 rx_dropped; /* no space in linux buffers */
+ __u32 tx_dropped; /* no space available in linux */
+ __u32 multicast; /* multicast packets received */
+ __u32 collisions;
+
+ /* detailed rx_errors: */
+ __u32 rx_length_errors;
+ __u32 rx_over_errors; /* receiver ring buff overflow */
+ __u32 rx_crc_errors; /* recved pkt with crc error */
+ __u32 rx_frame_errors; /* recv'd frame alignment error */
+ __u32 rx_fifo_errors; /* recv'r fifo overrun */
+ __u32 rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ __u32 tx_aborted_errors;
+ __u32 tx_carrier_errors;
+ __u32 tx_fifo_errors;
+ __u32 tx_heartbeat_errors;
+ __u32 tx_window_errors;
+
+ /* for cslip etc */
+ __u32 rx_compressed;
+ __u32 tx_compressed;
+};
+
+/* The struct should be in sync with struct ifmap */
+struct rtnl_link_ifmap
+{
+ __u64 mem_start;
+ __u64 mem_end;
+ __u64 base_addr;
+ __u16 irq;
+ __u8 dma;
+ __u8 port;
+};
+
+enum
+{
+ IFLA_UNSPEC,
+ IFLA_ADDRESS,
+ IFLA_BROADCAST,
+ IFLA_IFNAME,
+ IFLA_MTU,
+ IFLA_LINK,
+ IFLA_QDISC,
+ IFLA_STATS,
+ IFLA_COST,
+#define IFLA_COST IFLA_COST
+ IFLA_PRIORITY,
+#define IFLA_PRIORITY IFLA_PRIORITY
+ IFLA_MASTER,
+#define IFLA_MASTER IFLA_MASTER
+ IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */
+#define IFLA_WIRELESS IFLA_WIRELESS
+ IFLA_PROTINFO, /* Protocol specific information for a link */
+#define IFLA_PROTINFO IFLA_PROTINFO
+ IFLA_TXQLEN,
+#define IFLA_TXQLEN IFLA_TXQLEN
+ IFLA_MAP,
+#define IFLA_MAP IFLA_MAP
+ IFLA_WEIGHT,
+#define IFLA_WEIGHT IFLA_WEIGHT
+ IFLA_OPERSTATE,
+ IFLA_LINKMODE,
+ __IFLA_MAX
+};
+
+
+#define IFLA_MAX (__IFLA_MAX - 1)
+
+/* ifi_flags.
+
+ IFF_* flags.
+
+ The only change is:
+ IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are
+ more not changeable by user. They describe link media
+ characteristics and set by device driver.
+
+ Comments:
+ - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
+ - If neither of these three flags are set;
+ the interface is NBMA.
+
+ - IFF_MULTICAST does not mean anything special:
+ multicasts can be used on all not-NBMA links.
+ IFF_MULTICAST means that this media uses special encapsulation
+ for multicast frames. Apparently, all IFF_POINTOPOINT and
+ IFF_BROADCAST devices are able to use multicasts too.
+ */
+
+/* IFLA_LINK.
+ For usual devices it is equal ifi_index.
+ If it is a "virtual interface" (f.e. tunnel), ifi_link
+ can point to real physical interface (f.e. for bandwidth calculations),
+ or maybe 0, what means, that real media is unknown (usual
+ for IPIP tunnels, when route to endpoint is allowed to change)
+ */
+
+/* Subtype attributes for IFLA_PROTINFO */
+enum
+{
+ IFLA_INET6_UNSPEC,
+ IFLA_INET6_FLAGS, /* link flags */
+ IFLA_INET6_CONF, /* sysctl parameters */
+ IFLA_INET6_STATS, /* statistics */
+ IFLA_INET6_MCAST, /* MC things. What of them? */
+ IFLA_INET6_CACHEINFO, /* time values and max reasm size */
+ __IFLA_INET6_MAX
+};
+
+#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1)
+
+struct ifla_cacheinfo
+{
+ __u32 max_reasm_len;
+ __u32 tstamp; /* ipv6InterfaceTable updated timestamp */
+ __u32 reachable_time;
+ __u32 retrans_time;
+};
+
+#endif /* _LINUX_IF_LINK_H */
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index ab2740832742..35cb38573583 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -44,7 +44,7 @@ struct vlan_ethhdr {
unsigned char h_source[ETH_ALEN]; /* source ether addr */
__be16 h_vlan_proto; /* Should always be 0x8100 */
__be16 h_vlan_TCI; /* Encapsulates priority and VLAN ID */
- unsigned short h_vlan_encapsulated_proto; /* packet type ID field (or len) */
+ __be16 h_vlan_encapsulated_proto; /* packet type ID field (or len) */
};
#include <linux/skbuff.h>
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 899c3d4776f3..03f43e2893a4 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -30,8 +30,8 @@ struct igmphdr
{
__u8 type;
__u8 code; /* For newer IGMP */
- __u16 csum;
- __u32 group;
+ __be16 csum;
+ __be32 group;
};
/* V3 group record types [grec_type] */
@@ -45,25 +45,25 @@ struct igmphdr
struct igmpv3_grec {
__u8 grec_type;
__u8 grec_auxwords;
- __u16 grec_nsrcs;
- __u32 grec_mca;
- __u32 grec_src[0];
+ __be16 grec_nsrcs;
+ __be32 grec_mca;
+ __be32 grec_src[0];
};
struct igmpv3_report {
__u8 type;
__u8 resv1;
- __u16 csum;
- __u16 resv2;
- __u16 ngrec;
+ __be16 csum;
+ __be16 resv2;
+ __be16 ngrec;
struct igmpv3_grec grec[0];
};
struct igmpv3_query {
__u8 type;
__u8 code;
- __u16 csum;
- __u32 group;
+ __be16 csum;
+ __be32 group;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 qrv:3,
suppress:1,
@@ -76,8 +76,8 @@ struct igmpv3_query {
#error "Please fix <asm/byteorder.h>"
#endif
__u8 qqic;
- __u16 nsrcs;
- __u32 srcs[0];
+ __be16 nsrcs;
+ __be32 srcs[0];
};
#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */
@@ -136,11 +136,11 @@ struct ip_sf_socklist
{
unsigned int sl_max;
unsigned int sl_count;
- __u32 sl_addr[0];
+ __be32 sl_addr[0];
};
#define IP_SFLSIZE(count) (sizeof(struct ip_sf_socklist) + \
- (count) * sizeof(__u32))
+ (count) * sizeof(__be32))
#define IP_SFBLOCK 10 /* allocate this many at once */
@@ -159,7 +159,7 @@ struct ip_mc_socklist
struct ip_sf_list
{
struct ip_sf_list *sf_next;
- __u32 sf_inaddr;
+ __be32 sf_inaddr;
unsigned long sf_count[2]; /* include/exclude counts */
unsigned char sf_gsresp; /* include in g & s response? */
unsigned char sf_oldin; /* change state */
@@ -197,7 +197,7 @@ struct ip_mc_list
#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value)
#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value)
-extern int ip_check_mc(struct in_device *dev, u32 mc_addr, u32 src_addr, u16 proto);
+extern int ip_check_mc(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u16 proto);
extern int igmp_rcv(struct sk_buff *);
extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
@@ -209,13 +209,13 @@ extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
struct ip_msfilter __user *optval, int __user *optlen);
extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
struct group_filter __user *optval, int __user *optlen);
-extern int ip_mc_sf_allow(struct sock *sk, u32 local, u32 rmt, int dif);
+extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif);
extern void ip_mr_init(void);
extern void ip_mc_init_dev(struct in_device *);
extern void ip_mc_destroy_dev(struct in_device *);
extern void ip_mc_up(struct in_device *);
extern void ip_mc_down(struct in_device *);
-extern void ip_mc_dec_group(struct in_device *in_dev, u32 addr);
-extern void ip_mc_inc_group(struct in_device *in_dev, u32 addr);
+extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr);
+extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr);
#endif
#endif
diff --git a/include/linux/in.h b/include/linux/in.h
index bcaca8399aed..2619859f6e1b 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -40,6 +40,7 @@ enum {
IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
IPPROTO_AH = 51, /* Authentication Header protocol */
+ IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
IPPROTO_PIM = 103, /* Protocol Independent Multicast */
IPPROTO_COMP = 108, /* Compression Header protocol */
@@ -123,17 +124,17 @@ struct ip_mreqn
};
struct ip_mreq_source {
- __u32 imr_multiaddr;
- __u32 imr_interface;
- __u32 imr_sourceaddr;
+ __be32 imr_multiaddr;
+ __be32 imr_interface;
+ __be32 imr_sourceaddr;
};
struct ip_msfilter {
- __u32 imsf_multiaddr;
- __u32 imsf_interface;
+ __be32 imsf_multiaddr;
+ __be32 imsf_interface;
__u32 imsf_fmode;
__u32 imsf_numsrc;
- __u32 imsf_slist[1];
+ __be32 imsf_slist[1];
};
#define IP_MSFILTER_SIZE(numsrc) \
diff --git a/include/linux/in6.h b/include/linux/in6.h
index d776829b443f..9be6a4756f0b 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -32,8 +32,8 @@ struct in6_addr
union
{
__u8 u6_addr8[16];
- __u16 u6_addr16[8];
- __u32 u6_addr32[4];
+ __be16 u6_addr16[8];
+ __be32 u6_addr32[4];
} in6_u;
#define s6_addr in6_u.u6_addr8
#define s6_addr16 in6_u.u6_addr16
@@ -53,7 +53,7 @@ extern const struct in6_addr in6addr_loopback;
struct sockaddr_in6 {
unsigned short int sin6_family; /* AF_INET6 */
- __u16 sin6_port; /* Transport layer port # */
+ __be16 sin6_port; /* Transport layer port # */
__u32 sin6_flowinfo; /* IPv6 flow information */
struct in6_addr sin6_addr; /* IPv6 address */
__u32 sin6_scope_id; /* scope id (new in RFC2553) */
diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h
index a4606e5810e5..6e8bc548635a 100644
--- a/include/linux/inet_diag.h
+++ b/include/linux/inet_diag.h
@@ -9,10 +9,10 @@
/* Socket identity */
struct inet_diag_sockid {
- __u16 idiag_sport;
- __u16 idiag_dport;
- __u32 idiag_src[4];
- __u32 idiag_dst[4];
+ __be16 idiag_sport;
+ __be16 idiag_dport;
+ __be32 idiag_src[4];
+ __be32 idiag_dst[4];
__u32 idiag_if;
__u32 idiag_cookie[2];
#define INET_DIAG_NOCOOKIE (~0U)
@@ -67,7 +67,7 @@ struct inet_diag_hostcond {
__u8 family;
__u8 prefix_len;
int port;
- __u32 addr[0];
+ __be32 addr[0];
};
/* Base info structure. It contains socket identity (addrs/ports/cookie)
diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h
index 92297ff24e85..5a0ab04627bc 100644
--- a/include/linux/inetdevice.h
+++ b/include/linux/inetdevice.h
@@ -90,11 +90,11 @@ struct in_ifaddr
struct in_ifaddr *ifa_next;
struct in_device *ifa_dev;
struct rcu_head rcu_head;
- u32 ifa_local;
- u32 ifa_address;
- u32 ifa_mask;
- u32 ifa_broadcast;
- u32 ifa_anycast;
+ __be32 ifa_local;
+ __be32 ifa_address;
+ __be32 ifa_mask;
+ __be32 ifa_broadcast;
+ __be32 ifa_anycast;
unsigned char ifa_scope;
unsigned char ifa_flags;
unsigned char ifa_prefixlen;
@@ -104,18 +104,18 @@ struct in_ifaddr
extern int register_inetaddr_notifier(struct notifier_block *nb);
extern int unregister_inetaddr_notifier(struct notifier_block *nb);
-extern struct net_device *ip_dev_find(u32 addr);
-extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b);
+extern struct net_device *ip_dev_find(__be32 addr);
+extern int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b);
extern int devinet_ioctl(unsigned int cmd, void __user *);
extern void devinet_init(void);
extern struct in_device *inetdev_init(struct net_device *dev);
extern struct in_device *inetdev_by_index(int);
-extern u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope);
-extern u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope);
-extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
+extern __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope);
+extern __be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope);
+extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, __be32 mask);
extern void inet_forward_change(void);
-static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
+static __inline__ int inet_ifa_match(__be32 addr, struct in_ifaddr *ifa)
{
return !((addr^ifa->ifa_address)&ifa->ifa_mask);
}
@@ -183,7 +183,7 @@ static inline void in_dev_put(struct in_device *idev)
#endif /* __KERNEL__ */
-static __inline__ __u32 inet_make_mask(int logmask)
+static __inline__ __be32 inet_make_mask(int logmask)
{
if (logmask)
return htonl(~((1<<(32-logmask))-1));
diff --git a/include/linux/init.h b/include/linux/init.h
index 6667785dd1ff..e92b1455d7af 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -68,6 +68,7 @@ extern initcall_t __security_initcall_start[], __security_initcall_end[];
/* Defined in init/main.c */
extern char saved_command_line[];
+extern unsigned int reset_devices;
/* used by init/main.c */
extern void setup_arch(char **);
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 60aac2cea0cf..33c5daacc743 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -4,7 +4,9 @@
#include <linux/file.h>
#include <linux/rcupdate.h>
#include <linux/irqflags.h>
+#include <linux/utsname.h>
#include <linux/lockdep.h>
+#include <linux/ipc.h>
#define INIT_FDTABLE \
{ \
@@ -68,6 +70,15 @@
.session = 1, \
}
+extern struct nsproxy init_nsproxy;
+#define INIT_NSPROXY(nsproxy) { \
+ .count = ATOMIC_INIT(1), \
+ .nslock = SPIN_LOCK_UNLOCKED, \
+ .uts_ns = &init_uts_ns, \
+ .namespace = NULL, \
+ INIT_IPC_NS(ipc_ns) \
+}
+
#define INIT_SIGHAND(sighand) { \
.count = ATOMIC_INIT(1), \
.action = { { { .sa_handler = NULL, } }, }, \
@@ -117,6 +128,7 @@ extern struct group_info init_groups;
.files = &init_files, \
.signal = &init_signals, \
.sighand = &init_sighand, \
+ .nsproxy = &init_nsproxy, \
.pending = { \
.list = LIST_HEAD_INIT(tsk.pending.list), \
.signal = {{0}}}, \
diff --git a/include/linux/input.h b/include/linux/input.h
index b3253ab72ff7..c38507ba38b5 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -349,6 +349,9 @@ struct input_absinfo {
#define KEY_BATTERY 236
+#define KEY_BLUETOOTH 237
+#define KEY_WLAN 238
+
#define KEY_UNKNOWN 240
#define BTN_MISC 0x100
@@ -645,6 +648,7 @@ struct input_absinfo {
#define BUS_USB 0x03
#define BUS_HIL 0x04
#define BUS_BLUETOOTH 0x05
+#define BUS_VIRTUAL 0x06
#define BUS_ISA 0x10
#define BUS_I8042 0x11
@@ -667,98 +671,167 @@ struct input_absinfo {
/*
* Structures used in ioctls to upload effects to a device
- * The first structures are not passed directly by using ioctls.
- * They are sub-structures of the actually sent structure (called ff_effect)
+ * They are pieces of a bigger structure (called ff_effect)
+ */
+
+/*
+ * All duration values are expressed in ms. Values above 32767 ms (0x7fff)
+ * should not be used and have unspecified results.
*/
+/**
+ * struct ff_replay - defines scheduling of the effect
+ * @length: duration of the effect
+ * @delay: delay before effect should start playing
+ */
struct ff_replay {
- __u16 length; /* Duration of an effect in ms. All other times are also expressed in ms */
- __u16 delay; /* Time to wait before to start playing an effect */
+ __u16 length;
+ __u16 delay;
};
+/**
+ * struct ff_trigger - defines what triggers the effect
+ * @button: number of the button triggering the effect
+ * @interval: controls how soon the effect can be re-triggered
+ */
struct ff_trigger {
- __u16 button; /* Number of button triggering an effect */
- __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */
+ __u16 button;
+ __u16 interval;
};
+/**
+ * struct ff_envelope - generic effect envelope
+ * @attack_length: duration of the attack (ms)
+ * @attack_level: level at the beginning of the attack
+ * @fade_length: duration of fade (ms)
+ * @fade_level: level at the end of fade
+ *
+ * The @attack_level and @fade_level are absolute values; when applying
+ * envelope force-feedback core will convert to positive/negative
+ * value based on polarity of the default level of the effect.
+ * Valid range for the attack and fade levels is 0x0000 - 0x7fff
+ */
struct ff_envelope {
- __u16 attack_length; /* Duration of attack (ms) */
- __u16 attack_level; /* Level at beginning of attack */
- __u16 fade_length; /* Duration of fade (ms) */
- __u16 fade_level; /* Level at end of fade */
+ __u16 attack_length;
+ __u16 attack_level;
+ __u16 fade_length;
+ __u16 fade_level;
};
-/* FF_CONSTANT */
+/**
+ * struct ff_constant_effect - defines parameters of a constant effect
+ * @level: strength of the effect; may be negative
+ * @envelope: envelope data
+ */
struct ff_constant_effect {
- __s16 level; /* Strength of effect. Negative values are OK */
+ __s16 level;
struct ff_envelope envelope;
};
-/* FF_RAMP */
+/**
+ * struct ff_ramp_effect - defines parameters of a ramp effect
+ * @start_level: beginning strength of the effect; may be negative
+ * @end_level: final strength of the effect; may be negative
+ * @envelope: envelope data
+ */
struct ff_ramp_effect {
__s16 start_level;
__s16 end_level;
struct ff_envelope envelope;
};
-/* FF_SPRING of FF_FRICTION */
+/**
+ * struct ff_condition_effect - defines a spring or friction effect
+ * @right_saturation: maximum level when joystick moved all way to the right
+ * @left_saturation: same for the left side
+ * @right_coeff: controls how fast the force grows when the joystick moves
+ * to the right
+ * @left_coeff: same for the left side
+ * @deadband: size of the dead zone, where no force is produced
+ * @center: position of the dead zone
+ */
struct ff_condition_effect {
- __u16 right_saturation; /* Max level when joystick is on the right */
- __u16 left_saturation; /* Max level when joystick in on the left */
-
- __s16 right_coeff; /* Indicates how fast the force grows when the
- joystick moves to the right */
- __s16 left_coeff; /* Same for left side */
+ __u16 right_saturation;
+ __u16 left_saturation;
- __u16 deadband; /* Size of area where no force is produced */
- __s16 center; /* Position of dead zone */
+ __s16 right_coeff;
+ __s16 left_coeff;
+ __u16 deadband;
+ __s16 center;
};
-/* FF_PERIODIC */
+/**
+ * struct ff_periodic_effect - defines parameters of a periodic effect
+ * @waveform: kind of the effect (wave)
+ * @period: period of the wave (ms)
+ * @magnitude: peak value
+ * @offset: mean value of the wave (roughly)
+ * @phase: 'horizontal' shift
+ * @envelope: envelope data
+ * @custom_len: number of samples (FF_CUSTOM only)
+ * @custom_data: buffer of samples (FF_CUSTOM only)
+ *
+ * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP,
+ * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined
+ * for the time being as no driver supports it yet.
+ *
+ * Note: the data pointed by custom_data is copied by the driver.
+ * You can therefore dispose of the memory after the upload/update.
+ */
struct ff_periodic_effect {
- __u16 waveform; /* Kind of wave (sine, square...) */
- __u16 period; /* in ms */
- __s16 magnitude; /* Peak value */
- __s16 offset; /* Mean value of wave (roughly) */
- __u16 phase; /* 'Horizontal' shift */
+ __u16 waveform;
+ __u16 period;
+ __s16 magnitude;
+ __s16 offset;
+ __u16 phase;
struct ff_envelope envelope;
-/* Only used if waveform == FF_CUSTOM */
- __u32 custom_len; /* Number of samples */
- __s16 *custom_data; /* Buffer of samples */
-/* Note: the data pointed by custom_data is copied by the driver. You can
- * therefore dispose of the memory after the upload/update */
+ __u32 custom_len;
+ __s16 *custom_data;
};
-/* FF_RUMBLE */
-/* Some rumble pads have two motors of different weight.
- strong_magnitude represents the magnitude of the vibration generated
- by the heavy motor.
-*/
+/**
+ * struct ff_rumble_effect - defines parameters of a periodic effect
+ * @strong_magnitude: magnitude of the heavy motor
+ * @weak_magnitude: magnitude of the light one
+ *
+ * Some rumble pads have two motors of different weight. Strong_magnitude
+ * represents the magnitude of the vibration generated by the heavy one.
+ */
struct ff_rumble_effect {
- __u16 strong_magnitude; /* Magnitude of the heavy motor */
- __u16 weak_magnitude; /* Magnitude of the light one */
+ __u16 strong_magnitude;
+ __u16 weak_magnitude;
};
-/*
- * Structure sent through ioctl from the application to the driver
+/**
+ * struct ff_effect - defines force feedback effect
+ * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING,
+ * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM)
+ * @id: an unique id assigned to an effect
+ * @direction: direction of the effect
+ * @trigger: trigger conditions (struct ff_trigger)
+ * @replay: scheduling of the effect (struct ff_replay)
+ * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect,
+ * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further
+ * defining effect parameters
+ *
+ * This structure is sent through ioctl from the application to the driver.
+ * To create a new effect aplication should set its @id to -1; the kernel
+ * will return assigned @id which can later be used to update or delete
+ * this effect.
+ *
+ * Direction of the effect is encoded as follows:
+ * 0 deg -> 0x0000 (down)
+ * 90 deg -> 0x4000 (left)
+ * 180 deg -> 0x8000 (up)
+ * 270 deg -> 0xC000 (right)
*/
struct ff_effect {
__u16 type;
-/* Following field denotes the unique id assigned to an effect.
- * If user sets if to -1, a new effect is created, and its id is returned in the same field
- * Else, the user sets it to the effect id it wants to update.
- */
__s16 id;
-
- __u16 direction; /* Direction. 0 deg -> 0x0000 (down)
- 90 deg -> 0x4000 (left)
- 180 deg -> 0x8000 (up)
- 270 deg -> 0xC000 (right)
- */
-
+ __u16 direction;
struct ff_trigger trigger;
struct ff_replay replay;
@@ -784,6 +857,9 @@ struct ff_effect {
#define FF_INERTIA 0x56
#define FF_RAMP 0x57
+#define FF_EFFECT_MIN FF_RUMBLE
+#define FF_EFFECT_MAX FF_RAMP
+
/*
* Force feedback periodic effect types
*/
@@ -795,6 +871,9 @@ struct ff_effect {
#define FF_SAW_DOWN 0x5c
#define FF_CUSTOM 0x5d
+#define FF_WAVEFORM_MIN FF_SQUARE
+#define FF_WAVEFORM_MAX FF_CUSTOM
+
/*
* Set ff device properties
*/
@@ -864,16 +943,16 @@ struct input_dev {
unsigned long sndbit[NBITS(SND_MAX)];
unsigned long ffbit[NBITS(FF_MAX)];
unsigned long swbit[NBITS(SW_MAX)];
- int ff_effects_max;
unsigned int keycodemax;
unsigned int keycodesize;
void *keycode;
+ struct ff_device *ff;
+
unsigned int repeat_key;
struct timer_list timer;
- struct pt_regs *regs;
int state;
int sync;
@@ -895,8 +974,6 @@ struct input_dev {
void (*close)(struct input_dev *dev);
int (*flush)(struct input_dev *dev, struct file *file);
int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value);
- int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect);
- int (*erase_effect)(struct input_dev *dev, int effect_id);
struct input_handle *grab;
@@ -904,9 +981,6 @@ struct input_dev {
unsigned int users;
struct class_device cdev;
- struct device *dev; /* will be removed soon */
-
- int dynalloc; /* temporarily */
struct list_head h_list;
struct list_head node;
@@ -985,16 +1059,16 @@ struct input_handler {
void *private;
void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value);
- struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id);
+ struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id);
void (*disconnect)(struct input_handle *handle);
void (*start)(struct input_handle *handle);
const struct file_operations *fops;
int minor;
- char *name;
+ const char *name;
- struct input_device_id *id_table;
- struct input_device_id *blacklist;
+ const struct input_device_id *id_table;
+ const struct input_device_id *blacklist;
struct list_head h_list;
struct list_head node;
@@ -1005,7 +1079,7 @@ struct input_handle {
void *private;
int open;
- char *name;
+ const char *name;
struct input_dev *dev;
struct input_handler *handler;
@@ -1019,12 +1093,6 @@ struct input_handle {
#define to_handle(n) container_of(n,struct input_handle,d_node)
#define to_handle_h(n) container_of(n,struct input_handle,h_node)
-static inline void init_input_dev(struct input_dev *dev)
-{
- INIT_LIST_HEAD(&dev->h_list);
- INIT_LIST_HEAD(&dev->node);
-}
-
struct input_dev *input_allocate_device(void);
void input_free_device(struct input_dev *dev);
@@ -1041,7 +1109,7 @@ static inline void input_put_device(struct input_dev *dev)
int input_register_device(struct input_dev *);
void input_unregister_device(struct input_dev *);
-void input_register_handler(struct input_handler *);
+int input_register_handler(struct input_handler *);
void input_unregister_handler(struct input_handler *);
int input_grab_device(struct input_handle *);
@@ -1070,11 +1138,6 @@ static inline void input_report_abs(struct input_dev *dev, unsigned int code, in
input_event(dev, EV_ABS, code, value);
}
-static inline void input_report_ff(struct input_dev *dev, unsigned int code, int value)
-{
- input_event(dev, EV_FF, code, value);
-}
-
static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_FF_STATUS, code, value);
@@ -1085,15 +1148,9 @@ static inline void input_report_switch(struct input_dev *dev, unsigned int code,
input_event(dev, EV_SW, code, !!value);
}
-static inline void input_regs(struct input_dev *dev, struct pt_regs *regs)
-{
- dev->regs = regs;
-}
-
static inline void input_sync(struct input_dev *dev)
{
input_event(dev, EV_SYN, SYN_REPORT, 0);
- dev->regs = NULL;
}
static inline void input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat)
@@ -1108,5 +1165,61 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min
extern struct class input_class;
+/**
+ * struct ff_device - force-feedback part of an input device
+ * @upload: Called to upload an new effect into device
+ * @erase: Called to erase an effect from device
+ * @playback: Called to request device to start playing specified effect
+ * @set_gain: Called to set specified gain
+ * @set_autocenter: Called to auto-center device
+ * @destroy: called by input core when parent input device is being
+ * destroyed
+ * @private: driver-specific data, will be freed automatically
+ * @ffbit: bitmap of force feedback capabilities truly supported by
+ * device (not emulated like ones in input_dev->ffbit)
+ * @mutex: mutex for serializing access to the device
+ * @max_effects: maximum number of effects supported by device
+ * @effects: pointer to an array of effects currently loaded into device
+ * @effect_owners: array of effect owners; when file handle owning
+ * an effect gets closed the effcet is automatically erased
+ *
+ * Every force-feedback device must implement upload() and playback()
+ * methods; erase() is optional. set_gain() and set_autocenter() need
+ * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER
+ * bits.
+ */
+struct ff_device {
+ int (*upload)(struct input_dev *dev, struct ff_effect *effect,
+ struct ff_effect *old);
+ int (*erase)(struct input_dev *dev, int effect_id);
+
+ int (*playback)(struct input_dev *dev, int effect_id, int value);
+ void (*set_gain)(struct input_dev *dev, u16 gain);
+ void (*set_autocenter)(struct input_dev *dev, u16 magnitude);
+
+ void (*destroy)(struct ff_device *);
+
+ void *private;
+
+ unsigned long ffbit[NBITS(FF_MAX)];
+
+ struct mutex mutex;
+
+ int max_effects;
+ struct ff_effect *effects;
+ struct file *effect_owners[];
+};
+
+int input_ff_create(struct input_dev *dev, int max_effects);
+void input_ff_destroy(struct input_dev *dev);
+
+int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+
+int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file);
+int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file);
+
+int input_ff_create_memless(struct input_dev *dev, void *data,
+ int (*play_effect)(struct input_dev *, void *, struct ff_effect *));
+
#endif
#endif
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
index d5afee95fd43..5b83e7b59621 100644
--- a/include/linux/interrupt.h
+++ b/include/linux/interrupt.h
@@ -64,8 +64,10 @@
#define SA_TRIGGER_RISING IRQF_TRIGGER_RISING
#define SA_TRIGGER_MASK IRQF_TRIGGER_MASK
+typedef irqreturn_t (*irq_handler_t)(int, void *);
+
struct irqaction {
- irqreturn_t (*handler)(int, void *, struct pt_regs *);
+ irq_handler_t handler;
unsigned long flags;
cpumask_t mask;
const char *name;
@@ -75,9 +77,8 @@ struct irqaction {
struct proc_dir_entry *dir;
};
-extern irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs);
-extern int request_irq(unsigned int,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+extern irqreturn_t no_action(int cpl, void *dev_id);
+extern int request_irq(unsigned int, irq_handler_t handler,
unsigned long, const char *, void *);
extern void free_irq(unsigned int, void *);
@@ -123,6 +124,14 @@ static inline void disable_irq_nosync_lockdep(unsigned int irq)
#endif
}
+static inline void disable_irq_nosync_lockdep_irqsave(unsigned int irq, unsigned long *flags)
+{
+ disable_irq_nosync(irq);
+#ifdef CONFIG_LOCKDEP
+ local_irq_save(*flags);
+#endif
+}
+
static inline void disable_irq_lockdep(unsigned int irq)
{
disable_irq(irq);
@@ -139,6 +148,14 @@ static inline void enable_irq_lockdep(unsigned int irq)
enable_irq(irq);
}
+static inline void enable_irq_lockdep_irqrestore(unsigned int irq, unsigned long *flags)
+{
+#ifdef CONFIG_LOCKDEP
+ local_irq_restore(*flags);
+#endif
+ enable_irq(irq);
+}
+
/* IRQ wakeup (PM) control: */
extern int set_irq_wake(unsigned int irq, unsigned int on);
diff --git a/include/linux/io.h b/include/linux/io.h
index 420e2fdf26f6..81877ea39309 100644
--- a/include/linux/io.h
+++ b/include/linux/io.h
@@ -18,9 +18,41 @@
#ifndef _LINUX_IO_H
#define _LINUX_IO_H
+#include <linux/types.h>
#include <asm/io.h>
+#include <asm/page.h>
void __iowrite32_copy(void __iomem *to, const void *from, size_t count);
void __iowrite64_copy(void __iomem *to, const void *from, size_t count);
+int ioremap_page_range(unsigned long addr, unsigned long end,
+ unsigned long phys_addr, pgprot_t prot);
+
+/**
+ * check_signature - find BIOS signatures
+ * @io_addr: mmio address to check
+ * @signature: signature block
+ * @length: length of signature
+ *
+ * Perform a signature comparison with the mmio address io_addr. This
+ * address should have been obtained by ioremap.
+ * Returns 1 on a match.
+ */
+
+static inline int check_signature(const volatile void __iomem *io_addr,
+ const unsigned char *signature, int length)
+{
+ int retval = 0;
+ do {
+ if (readb(io_addr) != *signature)
+ goto out;
+ io_addr++;
+ signature++;
+ length--;
+ } while (length);
+ retval = 1;
+out:
+ return retval;
+}
+
#endif /* _LINUX_IO_H */
diff --git a/include/linux/ioc3.h b/include/linux/ioc3.h
index da7c09e4ede6..38b286e9a46c 100644
--- a/include/linux/ioc3.h
+++ b/include/linux/ioc3.h
@@ -63,7 +63,7 @@ struct ioc3_submodule {
/* IRQ stuff */
unsigned int irq_mask; /* IOC3 IRQ mask, leave clear for Ethernet */
int reset_mask; /* non-zero if you want the ioc3.c module to reset interrupts */
- int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int, struct pt_regs *);
+ int (*intr) (struct ioc3_submodule *, struct ioc3_driver_data *, unsigned int);
/* private submodule data */
void *data; /* assigned by submodule */
};
diff --git a/include/linux/ioc4.h b/include/linux/ioc4.h
index de73a3289cc2..51e2b9fb6372 100644
--- a/include/linux/ioc4.h
+++ b/include/linux/ioc4.h
@@ -157,7 +157,7 @@ struct ioc4_driver_data {
unsigned long idd_bar0;
struct pci_dev *idd_pdev;
const struct pci_device_id *idd_pci_id;
- struct __iomem ioc4_misc_regs *idd_misc_regs;
+ struct ioc4_misc_regs __iomem *idd_misc_regs;
unsigned long count_period;
void *idd_serial_data;
unsigned int idd_variant;
diff --git a/include/linux/ip.h b/include/linux/ip.h
index 2f4600146f83..ecee9bb27d0e 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -80,6 +80,8 @@
#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */
#define IPOPT_TS_PRESPEC 3 /* specified modules only */
+#define IPV4_BEET_PHMAXLEN 8
+
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
@@ -96,7 +98,7 @@ struct iphdr {
__be16 frag_off;
__u8 ttl;
__u8 protocol;
- __u16 check;
+ __be16 check;
__be32 saddr;
__be32 daddr;
/*The options start here. */
@@ -105,22 +107,29 @@ struct iphdr {
struct ip_auth_hdr {
__u8 nexthdr;
__u8 hdrlen; /* This one is measured in 32 bit units! */
- __u16 reserved;
- __u32 spi;
- __u32 seq_no; /* Sequence number */
+ __be16 reserved;
+ __be32 spi;
+ __be32 seq_no; /* Sequence number */
__u8 auth_data[0]; /* Variable len but >=4. Mind the 64 bit alignment! */
};
struct ip_esp_hdr {
- __u32 spi;
- __u32 seq_no; /* Sequence number */
+ __be32 spi;
+ __be32 seq_no; /* Sequence number */
__u8 enc_data[0]; /* Variable len but >=8. Mind the 64 bit alignment! */
};
struct ip_comp_hdr {
__u8 nexthdr;
__u8 flags;
- __u16 cpi;
+ __be16 cpi;
+};
+
+struct ip_beet_phdr {
+ __u8 nexthdr;
+ __u8 hdrlen;
+ __u8 padlen;
+ __u8 reserved;
};
#endif /* _LINUX_IP_H */
diff --git a/include/linux/ipc.h b/include/linux/ipc.h
index b291189737e7..636094c29b16 100644
--- a/include/linux/ipc.h
+++ b/include/linux/ipc.h
@@ -51,6 +51,8 @@ struct ipc_perm
#ifdef __KERNEL__
+#include <linux/kref.h>
+
#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */
/* used by in-kernel data structures */
@@ -68,6 +70,59 @@ struct kern_ipc_perm
void *security;
};
+struct ipc_ids;
+struct ipc_namespace {
+ struct kref kref;
+ struct ipc_ids *ids[3];
+
+ int sem_ctls[4];
+ int used_sems;
+
+ int msg_ctlmax;
+ int msg_ctlmnb;
+ int msg_ctlmni;
+
+ size_t shm_ctlmax;
+ size_t shm_ctlall;
+ int shm_ctlmni;
+ int shm_tot;
+};
+
+extern struct ipc_namespace init_ipc_ns;
+
+#ifdef CONFIG_SYSVIPC
+#define INIT_IPC_NS(ns) .ns = &init_ipc_ns,
+#else
+#define INIT_IPC_NS(ns)
+#endif
+
+#ifdef CONFIG_IPC_NS
+extern void free_ipc_ns(struct kref *kref);
+extern int copy_ipcs(unsigned long flags, struct task_struct *tsk);
+extern int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns);
+#else
+static inline int copy_ipcs(unsigned long flags, struct task_struct *tsk)
+{
+ return 0;
+}
+#endif
+
+static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns)
+{
+#ifdef CONFIG_IPC_NS
+ if (ns)
+ kref_get(&ns->kref);
+#endif
+ return ns;
+}
+
+static inline void put_ipc_ns(struct ipc_namespace *ns)
+{
+#ifdef CONFIG_IPC_NS
+ kref_put(&ns->kref, free_ipc_ns);
+#endif
+}
+
#endif /* __KERNEL__ */
#endif /* _LINUX_IPC_H */
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index d09fbeabf1dc..796ca009fd46 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -148,6 +148,13 @@ struct ipmi_lan_addr
#define IPMI_BMC_CHANNEL 0xf
#define IPMI_NUM_CHANNELS 0x10
+/*
+ * Used to signify an "all channel" bitmask. This is more than the
+ * actual number of channels because this is used in userland and
+ * will cover us if the number of channels is extended.
+ */
+#define IPMI_CHAN_ALL (~0)
+
/*
* A raw IPMI message without any addressing. This covers both
@@ -350,18 +357,21 @@ int ipmi_request_supply_msgs(ipmi_user_t user,
/*
* When commands come in to the SMS, the user can register to receive
- * them. Only one user can be listening on a specific netfn/cmd pair
+ * them. Only one user can be listening on a specific netfn/cmd/chan tuple
* at a time, you will get an EBUSY error if the command is already
* registered. If a command is received that does not have a user
* registered, the driver will automatically return the proper
- * error.
+ * error. Channels are specified as a bitfield, use IPMI_CHAN_ALL to
+ * mean all channels.
*/
int ipmi_register_for_cmd(ipmi_user_t user,
unsigned char netfn,
- unsigned char cmd);
+ unsigned char cmd,
+ unsigned int chans);
int ipmi_unregister_for_cmd(ipmi_user_t user,
unsigned char netfn,
- unsigned char cmd);
+ unsigned char cmd,
+ unsigned int chans);
/*
* Allow run-to-completion mode to be set for the interface of
@@ -571,6 +581,36 @@ struct ipmi_cmdspec
#define IPMICTL_UNREGISTER_FOR_CMD _IOR(IPMI_IOC_MAGIC, 15, \
struct ipmi_cmdspec)
+/*
+ * Register to get commands from other entities on specific channels.
+ * This way, you can only listen on specific channels, or have messages
+ * from some channels go to one place and other channels to someplace
+ * else. The chans field is a bitmask, (1 << channel) for each channel.
+ * It may be IPMI_CHAN_ALL for all channels.
+ */
+struct ipmi_cmdspec_chans
+{
+ unsigned int netfn;
+ unsigned int cmd;
+ unsigned int chans;
+};
+
+/*
+ * Register to receive a specific command on specific channels. error values:
+ * - EFAULT - an address supplied was invalid.
+ * - EBUSY - One of the netfn/cmd/chans supplied was already in use.
+ * - ENOMEM - could not allocate memory for the entry.
+ */
+#define IPMICTL_REGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 28, \
+ struct ipmi_cmdspec_chans)
+/*
+ * Unregister some netfn/cmd/chans. error values:
+ * - EFAULT - an address supplied was invalid.
+ * - ENOENT - None of the netfn/cmd/chans were found registered for this user.
+ */
+#define IPMICTL_UNREGISTER_FOR_CMD_CHANS _IOR(IPMI_IOC_MAGIC, 29, \
+ struct ipmi_cmdspec_chans)
+
/*
* Set whether this interface receives events. Note that the first
* user registered for events will get all pending events for the
diff --git a/include/linux/ipsec.h b/include/linux/ipsec.h
index d3c527616b5e..d17a6302a0e9 100644
--- a/include/linux/ipsec.h
+++ b/include/linux/ipsec.h
@@ -12,7 +12,8 @@
enum {
IPSEC_MODE_ANY = 0, /* We do not support this for SA */
IPSEC_MODE_TRANSPORT = 1,
- IPSEC_MODE_TUNNEL = 2
+ IPSEC_MODE_TUNNEL = 2,
+ IPSEC_MODE_BEET = 3
};
enum {
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index caca57df0d7d..4f435c59de06 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -99,22 +99,22 @@ struct ipv6_destopt_hao {
struct ipv6_auth_hdr {
__u8 nexthdr;
__u8 hdrlen; /* This one is measured in 32 bit units! */
- __u16 reserved;
- __u32 spi;
- __u32 seq_no; /* Sequence number */
+ __be16 reserved;
+ __be32 spi;
+ __be32 seq_no; /* Sequence number */
__u8 auth_data[0]; /* Length variable but >=4. Mind the 64 bit alignment! */
};
struct ipv6_esp_hdr {
- __u32 spi;
- __u32 seq_no; /* Sequence number */
+ __be32 spi;
+ __be32 seq_no; /* Sequence number */
__u8 enc_data[0]; /* Length variable but >=8. Mind the 64 bit alignment! */
};
struct ipv6_comp_hdr {
__u8 nexthdr;
__u8 flags;
- __u16 cpi;
+ __be16 cpi;
};
/*
@@ -136,7 +136,7 @@ struct ipv6hdr {
#endif
__u8 flow_lbl[3];
- __u16 payload_len;
+ __be16 payload_len;
__u8 nexthdr;
__u8 hop_limit;
@@ -461,7 +461,7 @@ static inline struct raw6_sock *raw6_sk(const struct sock *sk)
#define INET6_MATCH(__sk, __hash, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash)) && \
- ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
((__sk)->sk_family == AF_INET6) && \
ipv6_addr_equal(&inet6_sk(__sk)->daddr, (__saddr)) && \
ipv6_addr_equal(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 48d3cb3b6a47..52fc4052a0ae 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -21,6 +21,12 @@
#include <asm/irq.h>
#include <asm/ptrace.h>
+#include <asm/irq_regs.h>
+
+struct irq_desc;
+typedef void fastcall (*irq_flow_handler_t)(unsigned int irq,
+ struct irq_desc *desc);
+
/*
* IRQ line status.
@@ -59,6 +65,7 @@
#define IRQ_NOAUTOEN 0x08000000 /* IRQ will not be enabled on request irq */
#define IRQ_DELAYED_DISABLE 0x10000000 /* IRQ disable (masking) happens delayed. */
#define IRQ_WAKEUP 0x20000000 /* IRQ triggers system wakeup */
+#define IRQ_MOVE_PENDING 0x40000000 /* need to re-target IRQ destination */
struct proc_dir_entry;
@@ -132,16 +139,14 @@ struct irq_chip {
* @affinity: IRQ affinity on SMP
* @cpu: cpu index useful for balancing
* @pending_mask: pending rebalanced interrupts
- * @move_irq: need to re-target IRQ destination
* @dir: /proc/irq/ procfs entry
* @affinity_entry: /proc/irq/smp_affinity procfs entry on SMP
+ * @name: flow handler name for /proc/interrupts output
*
* Pad this out to 32 bytes for cache and indexing reasons.
*/
struct irq_desc {
- void fastcall (*handle_irq)(unsigned int irq,
- struct irq_desc *desc,
- struct pt_regs *regs);
+ irq_flow_handler_t handle_irq;
struct irq_chip *chip;
void *handler_data;
void *chip_data;
@@ -159,11 +164,11 @@ struct irq_desc {
#endif
#if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)
cpumask_t pending_mask;
- unsigned int move_irq; /* need to re-target IRQ dest */
#endif
#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *dir;
+ struct proc_dir_entry *dir;
#endif
+ const char *name;
} ____cacheline_aligned;
extern struct irq_desc irq_desc[NR_IRQS];
@@ -206,36 +211,7 @@ static inline void set_native_irq_info(int irq, cpumask_t mask)
void set_pending_irq(unsigned int irq, cpumask_t mask);
void move_native_irq(int irq);
-
-#ifdef CONFIG_PCI_MSI
-/*
- * Wonder why these are dummies?
- * For e.g the set_ioapic_affinity_vector() calls the set_ioapic_affinity_irq()
- * counter part after translating the vector to irq info. We need to perform
- * this operation on the real irq, when we dont use vector, i.e when
- * pci_use_vector() is false.
- */
-static inline void move_irq(int irq)
-{
-}
-
-static inline void set_irq_info(int irq, cpumask_t mask)
-{
-}
-
-#else /* CONFIG_PCI_MSI */
-
-static inline void move_irq(int irq)
-{
- move_native_irq(irq);
-}
-
-static inline void set_irq_info(int irq, cpumask_t mask)
-{
- set_native_irq_info(irq, mask);
-}
-
-#endif /* CONFIG_PCI_MSI */
+void move_masked_irq(int irq);
#else /* CONFIG_GENERIC_PENDING_IRQ || CONFIG_IRQBALANCE */
@@ -247,21 +223,20 @@ static inline void move_native_irq(int irq)
{
}
-static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
+static inline void move_masked_irq(int irq)
{
}
-static inline void set_irq_info(int irq, cpumask_t mask)
+static inline void set_pending_irq(unsigned int irq, cpumask_t mask)
{
- set_native_irq_info(irq, mask);
}
#endif /* CONFIG_GENERIC_PENDING_IRQ */
#else /* CONFIG_SMP */
-#define move_irq(x)
#define move_native_irq(x)
+#define move_masked_irq(x)
#endif /* CONFIG_SMP */
@@ -285,43 +260,25 @@ static inline int select_smp_affinity(unsigned int irq)
extern int no_irq_affinity;
/* Handle irq action chains: */
-extern int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
- struct irqaction *action);
+extern int handle_IRQ_event(unsigned int irq, struct irqaction *action);
/*
* Built-in IRQ handlers for various IRQ types,
* callable via desc->chip->handle_irq()
*/
-extern void fastcall
-handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
-extern void fastcall
-handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
-extern void fastcall
-handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
-extern void fastcall
-handle_simple_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
-extern void fastcall
-handle_percpu_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs);
-extern void fastcall
-handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs);
-
-/*
- * Get a descriptive string for the highlevel handler, for
- * /proc/interrupts output:
- */
-extern const char *
-handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
- struct pt_regs *));
+extern void fastcall handle_level_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_edge_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_simple_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_percpu_irq(unsigned int irq, struct irq_desc *desc);
+extern void fastcall handle_bad_irq(unsigned int irq, struct irq_desc *desc);
/*
* Monolithic do_IRQ implementation.
* (is an explicit fastcall, because i386 4KSTACKS calls it from assembly)
*/
#ifndef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
-extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
+extern fastcall unsigned int __do_IRQ(unsigned int irq);
#endif
/*
@@ -330,23 +287,23 @@ extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
* irqchip-style controller then we call the ->handle_irq() handler,
* and it calls __do_IRQ() if it's attached to an irqtype-style controller.
*/
-static inline void generic_handle_irq(unsigned int irq, struct pt_regs *regs)
+static inline void generic_handle_irq(unsigned int irq)
{
struct irq_desc *desc = irq_desc + irq;
#ifdef CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
- desc->handle_irq(irq, desc, regs);
+ desc->handle_irq(irq, desc);
#else
if (likely(desc->handle_irq))
- desc->handle_irq(irq, desc, regs);
+ desc->handle_irq(irq, desc);
else
- __do_IRQ(irq, regs);
+ __do_IRQ(irq);
#endif
}
/* Handling of unhandled and spurious interrupts: */
extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
- int action_ret, struct pt_regs *regs);
+ int action_ret);
/* Resending of interrupts :*/
void check_irq_resend(struct irq_desc *desc, unsigned int irq);
@@ -366,24 +323,22 @@ extern struct irq_chip dummy_irq_chip;
extern void
set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
- void fastcall (*handle)(unsigned int,
- struct irq_desc *,
- struct pt_regs *));
+ irq_flow_handler_t handle);
extern void
-__set_irq_handler(unsigned int irq,
- void fastcall (*handle)(unsigned int, struct irq_desc *,
- struct pt_regs *),
- int is_chained);
+set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
+ irq_flow_handler_t handle, const char *name);
+
+extern void
+__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+ const char *name);
/*
* Set a highlevel flow handler for a given IRQ:
*/
static inline void
-set_irq_handler(unsigned int irq,
- void fastcall (*handle)(unsigned int, struct irq_desc *,
- struct pt_regs *))
+set_irq_handler(unsigned int irq, irq_flow_handler_t handle)
{
- __set_irq_handler(irq, handle, 0);
+ __set_irq_handler(irq, handle, 0, NULL);
}
/*
@@ -393,14 +348,27 @@ set_irq_handler(unsigned int irq,
*/
static inline void
set_irq_chained_handler(unsigned int irq,
- void fastcall (*handle)(unsigned int, struct irq_desc *,
- struct pt_regs *))
+ irq_flow_handler_t handle)
{
- __set_irq_handler(irq, handle, 1);
+ __set_irq_handler(irq, handle, 1, NULL);
}
-/* Set/get chip/data for an IRQ: */
+/* Handle dynamic irq creation and destruction */
+extern int create_irq(void);
+extern void destroy_irq(unsigned int irq);
+
+/* Test to see if a driver has successfully requested an irq */
+static inline int irq_has_action(unsigned int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+ return desc->action != NULL;
+}
+/* Dynamic irq helper functions */
+extern void dynamic_irq_init(unsigned int irq);
+extern void dynamic_irq_cleanup(unsigned int irq);
+
+/* Set/get chip/data for an IRQ: */
extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
extern int set_irq_data(unsigned int irq, void *data);
extern int set_irq_chip_data(unsigned int irq, void *data);
diff --git a/include/linux/istallion.h b/include/linux/istallion.h
index 1f996621bc9c..b55e2a035605 100644
--- a/include/linux/istallion.h
+++ b/include/linux/istallion.h
@@ -100,7 +100,7 @@ typedef struct stlibrd {
unsigned int iobase;
int iosize;
unsigned long memaddr;
- void *membase;
+ void __iomem *membase;
int memsize;
int pagesize;
int hostoffset;
@@ -113,7 +113,7 @@ typedef struct stlibrd {
void (*enable)(struct stlibrd *brdp);
void (*reenable)(struct stlibrd *brdp);
void (*disable)(struct stlibrd *brdp);
- char *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
+ void __iomem *(*getmemptr)(struct stlibrd *brdp, unsigned long offset, int line);
void (*intr)(struct stlibrd *brdp);
void (*reset)(struct stlibrd *brdp);
stliport_t *ports[STL_MAXPORTS];
diff --git a/include/linux/ite_gpio.h b/include/linux/ite_gpio.h
deleted file mode 100644
index b123a14292d3..000000000000
--- a/include/linux/ite_gpio.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * FILE NAME ite_gpio.h
- *
- * BRIEF MODULE DESCRIPTION
- * Generic gpio.
- *
- * Author: MontaVista Software, Inc. <source@mvista.com>
- * Hai-Pao Fan <haipao@mvista.com>
- *
- * Copyright 2001 MontaVista Software Inc.
- *
- * 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- */
-
-#ifndef __ITE_GPIO_H
-#define __ITE_GPIO_H
-
-#include <linux/ioctl.h>
-
-struct ite_gpio_ioctl_data {
- __u32 device;
- __u32 mask;
- __u32 data;
-};
-
-#define ITE_GPIO_IOCTL_BASE 'Z'
-
-#define ITE_GPIO_IN _IOWR(ITE_GPIO_IOCTL_BASE, 0, struct ite_gpio_ioctl_data)
-#define ITE_GPIO_OUT _IOW (ITE_GPIO_IOCTL_BASE, 1, struct ite_gpio_ioctl_data)
-#define ITE_GPIO_INT_CTRL _IOW (ITE_GPIO_IOCTL_BASE, 2, struct ite_gpio_ioctl_data)
-#define ITE_GPIO_IN_STATUS _IOW (ITE_GPIO_IOCTL_BASE, 3, struct ite_gpio_ioctl_data)
-#define ITE_GPIO_OUT_STATUS _IOW (ITE_GPIO_IOCTL_BASE, 4, struct ite_gpio_ioctl_data)
-#define ITE_GPIO_GEN_CTRL _IOW (ITE_GPIO_IOCTL_BASE, 5, struct ite_gpio_ioctl_data)
-#define ITE_GPIO_INT_WAIT _IOW (ITE_GPIO_IOCTL_BASE, 6, struct ite_gpio_ioctl_data)
-
-#define ITE_GPIO_PORTA 0x01
-#define ITE_GPIO_PORTB 0x02
-#define ITE_GPIO_PORTC 0x04
-
-extern int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data);
-extern int ite_gpio_out(__u32 device, __u32 mask, __u32 data);
-extern int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data);
-extern int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data);
-extern int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data);
-extern int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data);
-extern int ite_gpio_int_wait(__u32 device, __u32 mask, __u32 data);
-
-#endif
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index a04c154c5207..fe89444b1c6f 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -1,6 +1,6 @@
/*
* linux/include/linux/jbd.h
- *
+ *
* Written by Stephen C. Tweedie <sct@redhat.com>
*
* Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
@@ -64,7 +64,7 @@ extern int journal_enable_debug;
if ((n) <= journal_enable_debug) { \
printk (KERN_DEBUG "(%s, %d): %s: ", \
__FILE__, __LINE__, __FUNCTION__); \
- printk (f, ## a); \
+ printk (f, ## a); \
} \
} while (0)
#else
@@ -97,8 +97,8 @@ extern void jbd_slab_free(void *ptr, size_t size);
* number of outstanding buffers possible at any time. When the
* operation completes, any buffer credits not used are credited back to
* the transaction, so that at all times we know how many buffers the
- * outstanding updates on a transaction might possibly touch.
- *
+ * outstanding updates on a transaction might possibly touch.
+ *
* This is an opaque datatype.
**/
typedef struct handle_s handle_t; /* Atomic operation type */
@@ -108,7 +108,7 @@ typedef struct handle_s handle_t; /* Atomic operation type */
* typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem.
*
* journal_t is linked to from the fs superblock structure.
- *
+ *
* We use the journal_t to keep track of all outstanding transaction
* activity on the filesystem, and to manage the state of the log
* writing process.
@@ -128,7 +128,7 @@ typedef struct journal_s journal_t; /* Journal control structure */
* On-disk structures
*/
-/*
+/*
* Descriptor block types:
*/
@@ -149,8 +149,8 @@ typedef struct journal_header_s
} journal_header_t;
-/*
- * The block tag: used to describe a single buffer in the journal
+/*
+ * The block tag: used to describe a single buffer in the journal
*/
typedef struct journal_block_tag_s
{
@@ -158,9 +158,9 @@ typedef struct journal_block_tag_s
__be32 t_flags; /* See below */
} journal_block_tag_t;
-/*
+/*
* The revoke descriptor: used on disk to describe a series of blocks to
- * be revoked from the log
+ * be revoked from the log
*/
typedef struct journal_revoke_header_s
{
@@ -201,9 +201,9 @@ typedef struct journal_superblock_s
/* 0x0024 */
/* Remaining fields are only valid in a version-2 superblock */
- __be32 s_feature_compat; /* compatible feature set */
- __be32 s_feature_incompat; /* incompatible feature set */
- __be32 s_feature_ro_compat; /* readonly-compatible feature set */
+ __be32 s_feature_compat; /* compatible feature set */
+ __be32 s_feature_incompat; /* incompatible feature set */
+ __be32 s_feature_ro_compat; /* readonly-compatible feature set */
/* 0x0030 */
__u8 s_uuid[16]; /* 128-bit uuid for journal */
@@ -374,10 +374,10 @@ struct jbd_revoke_table_s;
**/
/* Docbook can't yet cope with the bit fields, but will leave the documentation
- * in so it can be fixed later.
+ * in so it can be fixed later.
*/
-struct handle_s
+struct handle_s
{
/* Which compound transaction is this update a part of? */
transaction_t *h_transaction;
@@ -435,7 +435,7 @@ struct handle_s
*
*/
-struct transaction_s
+struct transaction_s
{
/* Pointer to the journal for this transaction. [no locking] */
journal_t *t_journal;
@@ -455,7 +455,7 @@ struct transaction_s
T_RUNDOWN,
T_FLUSH,
T_COMMIT,
- T_FINISHED
+ T_FINISHED
} t_state;
/*
@@ -569,7 +569,7 @@ struct transaction_s
* journal_t.
* @j_flags: General journaling state flags
* @j_errno: Is there an outstanding uncleared error on the journal (from a
- * prior abort)?
+ * prior abort)?
* @j_sb_buffer: First part of superblock buffer
* @j_superblock: Second part of superblock buffer
* @j_format_version: Version of the superblock format
@@ -583,7 +583,7 @@ struct transaction_s
* @j_wait_transaction_locked: Wait queue for waiting for a locked transaction
* to start committing, or for a barrier lock to be released
* @j_wait_logspace: Wait queue for waiting for checkpointing to complete
- * @j_wait_done_commit: Wait queue for waiting for commit to complete
+ * @j_wait_done_commit: Wait queue for waiting for commit to complete
* @j_wait_checkpoint: Wait queue to trigger checkpointing
* @j_wait_commit: Wait queue to trigger commit
* @j_wait_updates: Wait queue to wait for updates to complete
@@ -592,7 +592,7 @@ struct transaction_s
* @j_tail: Journal tail - identifies the oldest still-used block in the
* journal.
* @j_free: Journal free - how many free blocks are there in the journal?
- * @j_first: The block number of the first usable block
+ * @j_first: The block number of the first usable block
* @j_last: The block number one beyond the last usable block
* @j_dev: Device where we store the journal
* @j_blocksize: blocksize for the location where we store the journal.
@@ -604,12 +604,12 @@ struct transaction_s
* @j_list_lock: Protects the buffer lists and internal buffer state.
* @j_inode: Optional inode where we store the journal. If present, all journal
* block numbers are mapped into this inode via bmap().
- * @j_tail_sequence: Sequence number of the oldest transaction in the log
+ * @j_tail_sequence: Sequence number of the oldest transaction in the log
* @j_transaction_sequence: Sequence number of the next transaction to grant
* @j_commit_sequence: Sequence number of the most recently committed
* transaction
* @j_commit_request: Sequence number of the most recent transaction wanting
- * commit
+ * commit
* @j_uuid: Uuid of client object.
* @j_task: Pointer to the current commit thread for this journal
* @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a
@@ -699,7 +699,7 @@ struct journal_s
wait_queue_head_t j_wait_updates;
/* Semaphore for locking against concurrent checkpoints */
- struct mutex j_checkpoint_mutex;
+ struct mutex j_checkpoint_mutex;
/*
* Journal head: identifies the first unused block in the journal.
@@ -732,7 +732,7 @@ struct journal_s
*/
struct block_device *j_dev;
int j_blocksize;
- unsigned int j_blk_offset;
+ unsigned long j_blk_offset;
/*
* Device which holds the client fs. For internal journal this will be
@@ -823,8 +823,8 @@ struct journal_s
void *j_private;
};
-/*
- * Journal flag definitions
+/*
+ * Journal flag definitions
*/
#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */
#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */
@@ -833,7 +833,7 @@ struct journal_s
#define JFS_LOADED 0x010 /* The journal superblock has been loaded */
#define JFS_BARRIER 0x020 /* Use IDE barriers */
-/*
+/*
* Function declarations for the journaling transaction and buffer
* management
*/
@@ -862,11 +862,11 @@ int __journal_remove_checkpoint(struct journal_head *);
void __journal_insert_checkpoint(struct journal_head *, transaction_t *);
/* Buffer IO */
-extern int
+extern int
journal_write_metadata_buffer(transaction_t *transaction,
struct journal_head *jh_in,
struct journal_head **jh_out,
- int blocknr);
+ unsigned long blocknr);
/* Transaction locking */
extern void __wait_on_journal (journal_t *);
@@ -890,7 +890,7 @@ static inline handle_t *journal_current_handle(void)
/* The journaling code user interface:
*
* Create and destroy handles
- * Register buffer modifications against the current transaction.
+ * Register buffer modifications against the current transaction.
*/
extern handle_t *journal_start(journal_t *, int nblocks);
@@ -917,11 +917,11 @@ extern journal_t * journal_init_dev(struct block_device *bdev,
int start, int len, int bsize);
extern journal_t * journal_init_inode (struct inode *);
extern int journal_update_format (journal_t *);
-extern int journal_check_used_features
+extern int journal_check_used_features
(journal_t *, unsigned long, unsigned long, unsigned long);
-extern int journal_check_available_features
+extern int journal_check_available_features
(journal_t *, unsigned long, unsigned long, unsigned long);
-extern int journal_set_features
+extern int journal_set_features
(journal_t *, unsigned long, unsigned long, unsigned long);
extern int journal_create (journal_t *);
extern int journal_load (journal_t *journal);
@@ -977,7 +977,6 @@ extern void journal_write_revoke_records(journal_t *, transaction_t *);
extern int journal_set_revoke(journal_t *, unsigned long, tid_t);
extern int journal_test_revoke(journal_t *, unsigned long, tid_t);
extern void journal_clear_revoke(journal_t *);
-extern void journal_brelse_array(struct buffer_head *b[], int n);
extern void journal_switch_revoke_table(journal_t *journal);
/*
@@ -1015,7 +1014,7 @@ do { \
* bit, when set, indicates that we have had a fatal error somewhere,
* either inside the journaling layer or indicated to us by the client
* (eg. ext3), and that we and should not commit any further
- * transactions.
+ * transactions.
*/
static inline int is_journal_aborted(journal_t *journal)
@@ -1082,7 +1081,7 @@ static inline int jbd_space_needed(journal_t *journal)
#define BJ_Reserved 7 /* Buffer is reserved for access by journal */
#define BJ_Locked 8 /* Locked for I/O during commit */
#define BJ_Types 9
-
+
extern int jbd_blocks_per_page(struct inode *inode);
#ifdef __KERNEL__
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
new file mode 100644
index 000000000000..ddb128795781
--- /dev/null
+++ b/include/linux/jbd2.h
@@ -0,0 +1,1107 @@
+/*
+ * linux/include/linux/jbd2.h
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>
+ *
+ * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Definitions for transaction data structures for the buffer cache
+ * filesystem journaling support.
+ */
+
+#ifndef _LINUX_JBD_H
+#define _LINUX_JBD_H
+
+/* Allow this file to be included directly into e2fsprogs */
+#ifndef __KERNEL__
+#include "jfs_compat.h"
+#define JBD2_DEBUG
+#define jfs_debug jbd_debug
+#else
+
+#include <linux/types.h>
+#include <linux/buffer_head.h>
+#include <linux/journal-head.h>
+#include <linux/stddef.h>
+#include <linux/bit_spinlock.h>
+#include <linux/mutex.h>
+#include <linux/timer.h>
+
+#include <asm/semaphore.h>
+#endif
+
+#define journal_oom_retry 1
+
+/*
+ * Define JBD_PARANIOD_IOFAIL to cause a kernel BUG() if ext3 finds
+ * certain classes of error which can occur due to failed IOs. Under
+ * normal use we want ext3 to continue after such errors, because
+ * hardware _can_ fail, but for debugging purposes when running tests on
+ * known-good hardware we may want to trap these errors.
+ */
+#undef JBD_PARANOID_IOFAIL
+
+/*
+ * The default maximum commit age, in seconds.
+ */
+#define JBD_DEFAULT_MAX_COMMIT_AGE 5
+
+#ifdef CONFIG_JBD_DEBUG
+/*
+ * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal
+ * consistency checks. By default we don't do this unless
+ * CONFIG_JBD_DEBUG is on.
+ */
+#define JBD_EXPENSIVE_CHECKING
+extern int jbd2_journal_enable_debug;
+
+#define jbd_debug(n, f, a...) \
+ do { \
+ if ((n) <= jbd2_journal_enable_debug) { \
+ printk (KERN_DEBUG "(%s, %d): %s: ", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ printk (f, ## a); \
+ } \
+ } while (0)
+#else
+#define jbd_debug(f, a...) /**/
+#endif
+
+extern void * __jbd2_kmalloc (const char *where, size_t size, gfp_t flags, int retry);
+extern void * jbd2_slab_alloc(size_t size, gfp_t flags);
+extern void jbd2_slab_free(void *ptr, size_t size);
+
+#define jbd_kmalloc(size, flags) \
+ __jbd2_kmalloc(__FUNCTION__, (size), (flags), journal_oom_retry)
+#define jbd_rep_kmalloc(size, flags) \
+ __jbd2_kmalloc(__FUNCTION__, (size), (flags), 1)
+
+#define JBD2_MIN_JOURNAL_BLOCKS 1024
+
+#ifdef __KERNEL__
+
+/**
+ * typedef handle_t - The handle_t type represents a single atomic update being performed by some process.
+ *
+ * All filesystem modifications made by the process go
+ * through this handle. Recursive operations (such as quota operations)
+ * are gathered into a single update.
+ *
+ * The buffer credits field is used to account for journaled buffers
+ * being modified by the running process. To ensure that there is
+ * enough log space for all outstanding operations, we need to limit the
+ * number of outstanding buffers possible at any time. When the
+ * operation completes, any buffer credits not used are credited back to
+ * the transaction, so that at all times we know how many buffers the
+ * outstanding updates on a transaction might possibly touch.
+ *
+ * This is an opaque datatype.
+ **/
+typedef struct handle_s handle_t; /* Atomic operation type */
+
+
+/**
+ * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem.
+ *
+ * journal_t is linked to from the fs superblock structure.
+ *
+ * We use the journal_t to keep track of all outstanding transaction
+ * activity on the filesystem, and to manage the state of the log
+ * writing process.
+ *
+ * This is an opaque datatype.
+ **/
+typedef struct journal_s journal_t; /* Journal control structure */
+#endif
+
+/*
+ * Internal structures used by the logging mechanism:
+ */
+
+#define JBD2_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
+
+/*
+ * On-disk structures
+ */
+
+/*
+ * Descriptor block types:
+ */
+
+#define JBD2_DESCRIPTOR_BLOCK 1
+#define JBD2_COMMIT_BLOCK 2
+#define JBD2_SUPERBLOCK_V1 3
+#define JBD2_SUPERBLOCK_V2 4
+#define JBD2_REVOKE_BLOCK 5
+
+/*
+ * Standard header for all descriptor blocks:
+ */
+typedef struct journal_header_s
+{
+ __be32 h_magic;
+ __be32 h_blocktype;
+ __be32 h_sequence;
+} journal_header_t;
+
+
+/*
+ * The block tag: used to describe a single buffer in the journal.
+ * t_blocknr_high is only used if INCOMPAT_64BIT is set, so this
+ * raw struct shouldn't be used for pointer math or sizeof() - use
+ * journal_tag_bytes(journal) instead to compute this.
+ */
+typedef struct journal_block_tag_s
+{
+ __be32 t_blocknr; /* The on-disk block number */
+ __be32 t_flags; /* See below */
+ __be32 t_blocknr_high; /* most-significant high 32bits. */
+} journal_block_tag_t;
+
+#define JBD_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high))
+#define JBD_TAG_SIZE64 (sizeof(journal_block_tag_t))
+
+/*
+ * The revoke descriptor: used on disk to describe a series of blocks to
+ * be revoked from the log
+ */
+typedef struct jbd2_journal_revoke_header_s
+{
+ journal_header_t r_header;
+ __be32 r_count; /* Count of bytes used in the block */
+} jbd2_journal_revoke_header_t;
+
+
+/* Definitions for the journal tag flags word: */
+#define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */
+#define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */
+#define JBD2_FLAG_DELETED 4 /* block deleted by this transaction */
+#define JBD2_FLAG_LAST_TAG 8 /* last tag in this descriptor block */
+
+
+/*
+ * The journal superblock. All fields are in big-endian byte order.
+ */
+typedef struct journal_superblock_s
+{
+/* 0x0000 */
+ journal_header_t s_header;
+
+/* 0x000C */
+ /* Static information describing the journal */
+ __be32 s_blocksize; /* journal device blocksize */
+ __be32 s_maxlen; /* total blocks in journal file */
+ __be32 s_first; /* first block of log information */
+
+/* 0x0018 */
+ /* Dynamic information describing the current state of the log */
+ __be32 s_sequence; /* first commit ID expected in log */
+ __be32 s_start; /* blocknr of start of log */
+
+/* 0x0020 */
+ /* Error value, as set by jbd2_journal_abort(). */
+ __be32 s_errno;
+
+/* 0x0024 */
+ /* Remaining fields are only valid in a version-2 superblock */
+ __be32 s_feature_compat; /* compatible feature set */
+ __be32 s_feature_incompat; /* incompatible feature set */
+ __be32 s_feature_ro_compat; /* readonly-compatible feature set */
+/* 0x0030 */
+ __u8 s_uuid[16]; /* 128-bit uuid for journal */
+
+/* 0x0040 */
+ __be32 s_nr_users; /* Nr of filesystems sharing log */
+
+ __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/
+
+/* 0x0048 */
+ __be32 s_max_transaction; /* Limit of journal blocks per trans.*/
+ __be32 s_max_trans_data; /* Limit of data blocks per trans. */
+
+/* 0x0050 */
+ __u32 s_padding[44];
+
+/* 0x0100 */
+ __u8 s_users[16*48]; /* ids of all fs'es sharing the log */
+/* 0x0400 */
+} journal_superblock_t;
+
+#define JBD2_HAS_COMPAT_FEATURE(j,mask) \
+ ((j)->j_format_version >= 2 && \
+ ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
+#define JBD2_HAS_RO_COMPAT_FEATURE(j,mask) \
+ ((j)->j_format_version >= 2 && \
+ ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
+#define JBD2_HAS_INCOMPAT_FEATURE(j,mask) \
+ ((j)->j_format_version >= 2 && \
+ ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
+
+#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001
+#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002
+
+/* Features known to this kernel version: */
+#define JBD2_KNOWN_COMPAT_FEATURES 0
+#define JBD2_KNOWN_ROCOMPAT_FEATURES 0
+#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \
+ JBD2_FEATURE_INCOMPAT_64BIT)
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+#include <linux/sched.h>
+
+#define JBD_ASSERTIONS
+#ifdef JBD_ASSERTIONS
+#define J_ASSERT(assert) \
+do { \
+ if (!(assert)) { \
+ printk (KERN_EMERG \
+ "Assertion failure in %s() at %s:%d: \"%s\"\n", \
+ __FUNCTION__, __FILE__, __LINE__, # assert); \
+ BUG(); \
+ } \
+} while (0)
+
+#if defined(CONFIG_BUFFER_DEBUG)
+void buffer_assertion_failure(struct buffer_head *bh);
+#define J_ASSERT_BH(bh, expr) \
+ do { \
+ if (!(expr)) \
+ buffer_assertion_failure(bh); \
+ J_ASSERT(expr); \
+ } while (0)
+#define J_ASSERT_JH(jh, expr) J_ASSERT_BH(jh2bh(jh), expr)
+#else
+#define J_ASSERT_BH(bh, expr) J_ASSERT(expr)
+#define J_ASSERT_JH(jh, expr) J_ASSERT(expr)
+#endif
+
+#else
+#define J_ASSERT(assert) do { } while (0)
+#endif /* JBD_ASSERTIONS */
+
+#if defined(JBD_PARANOID_IOFAIL)
+#define J_EXPECT(expr, why...) J_ASSERT(expr)
+#define J_EXPECT_BH(bh, expr, why...) J_ASSERT_BH(bh, expr)
+#define J_EXPECT_JH(jh, expr, why...) J_ASSERT_JH(jh, expr)
+#else
+#define __journal_expect(expr, why...) \
+ ({ \
+ int val = (expr); \
+ if (!val) { \
+ printk(KERN_ERR \
+ "EXT3-fs unexpected failure: %s;\n",# expr); \
+ printk(KERN_ERR why "\n"); \
+ } \
+ val; \
+ })
+#define J_EXPECT(expr, why...) __journal_expect(expr, ## why)
+#define J_EXPECT_BH(bh, expr, why...) __journal_expect(expr, ## why)
+#define J_EXPECT_JH(jh, expr, why...) __journal_expect(expr, ## why)
+#endif
+
+enum jbd_state_bits {
+ BH_JBD /* Has an attached ext3 journal_head */
+ = BH_PrivateStart,
+ BH_JWrite, /* Being written to log (@@@ DEBUGGING) */
+ BH_Freed, /* Has been freed (truncated) */
+ BH_Revoked, /* Has been revoked from the log */
+ BH_RevokeValid, /* Revoked flag is valid */
+ BH_JBDDirty, /* Is dirty but journaled */
+ BH_State, /* Pins most journal_head state */
+ BH_JournalHead, /* Pins bh->b_private and jh->b_bh */
+ BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */
+};
+
+BUFFER_FNS(JBD, jbd)
+BUFFER_FNS(JWrite, jwrite)
+BUFFER_FNS(JBDDirty, jbddirty)
+TAS_BUFFER_FNS(JBDDirty, jbddirty)
+BUFFER_FNS(Revoked, revoked)
+TAS_BUFFER_FNS(Revoked, revoked)
+BUFFER_FNS(RevokeValid, revokevalid)
+TAS_BUFFER_FNS(RevokeValid, revokevalid)
+BUFFER_FNS(Freed, freed)
+
+static inline struct buffer_head *jh2bh(struct journal_head *jh)
+{
+ return jh->b_bh;
+}
+
+static inline struct journal_head *bh2jh(struct buffer_head *bh)
+{
+ return bh->b_private;
+}
+
+static inline void jbd_lock_bh_state(struct buffer_head *bh)
+{
+ bit_spin_lock(BH_State, &bh->b_state);
+}
+
+static inline int jbd_trylock_bh_state(struct buffer_head *bh)
+{
+ return bit_spin_trylock(BH_State, &bh->b_state);
+}
+
+static inline int jbd_is_locked_bh_state(struct buffer_head *bh)
+{
+ return bit_spin_is_locked(BH_State, &bh->b_state);
+}
+
+static inline void jbd_unlock_bh_state(struct buffer_head *bh)
+{
+ bit_spin_unlock(BH_State, &bh->b_state);
+}
+
+static inline void jbd_lock_bh_journal_head(struct buffer_head *bh)
+{
+ bit_spin_lock(BH_JournalHead, &bh->b_state);
+}
+
+static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh)
+{
+ bit_spin_unlock(BH_JournalHead, &bh->b_state);
+}
+
+struct jbd2_revoke_table_s;
+
+/**
+ * struct handle_s - The handle_s type is the concrete type associated with
+ * handle_t.
+ * @h_transaction: Which compound transaction is this update a part of?
+ * @h_buffer_credits: Number of remaining buffers we are allowed to dirty.
+ * @h_ref: Reference count on this handle
+ * @h_err: Field for caller's use to track errors through large fs operations
+ * @h_sync: flag for sync-on-close
+ * @h_jdata: flag to force data journaling
+ * @h_aborted: flag indicating fatal error on handle
+ **/
+
+/* Docbook can't yet cope with the bit fields, but will leave the documentation
+ * in so it can be fixed later.
+ */
+
+struct handle_s
+{
+ /* Which compound transaction is this update a part of? */
+ transaction_t *h_transaction;
+
+ /* Number of remaining buffers we are allowed to dirty: */
+ int h_buffer_credits;
+
+ /* Reference count on this handle */
+ int h_ref;
+
+ /* Field for caller's use to track errors through large fs */
+ /* operations */
+ int h_err;
+
+ /* Flags [no locking] */
+ unsigned int h_sync: 1; /* sync-on-close */
+ unsigned int h_jdata: 1; /* force data journaling */
+ unsigned int h_aborted: 1; /* fatal error on handle */
+};
+
+
+/* The transaction_t type is the guts of the journaling mechanism. It
+ * tracks a compound transaction through its various states:
+ *
+ * RUNNING: accepting new updates
+ * LOCKED: Updates still running but we don't accept new ones
+ * RUNDOWN: Updates are tidying up but have finished requesting
+ * new buffers to modify (state not used for now)
+ * FLUSH: All updates complete, but we are still writing to disk
+ * COMMIT: All data on disk, writing commit record
+ * FINISHED: We still have to keep the transaction for checkpointing.
+ *
+ * The transaction keeps track of all of the buffers modified by a
+ * running transaction, and all of the buffers committed but not yet
+ * flushed to home for finished transactions.
+ */
+
+/*
+ * Lock ranking:
+ *
+ * j_list_lock
+ * ->jbd_lock_bh_journal_head() (This is "innermost")
+ *
+ * j_state_lock
+ * ->jbd_lock_bh_state()
+ *
+ * jbd_lock_bh_state()
+ * ->j_list_lock
+ *
+ * j_state_lock
+ * ->t_handle_lock
+ *
+ * j_state_lock
+ * ->j_list_lock (journal_unmap_buffer)
+ *
+ */
+
+struct transaction_s
+{
+ /* Pointer to the journal for this transaction. [no locking] */
+ journal_t *t_journal;
+
+ /* Sequence number for this transaction [no locking] */
+ tid_t t_tid;
+
+ /*
+ * Transaction's current state
+ * [no locking - only kjournald2 alters this]
+ * FIXME: needs barriers
+ * KLUDGE: [use j_state_lock]
+ */
+ enum {
+ T_RUNNING,
+ T_LOCKED,
+ T_RUNDOWN,
+ T_FLUSH,
+ T_COMMIT,
+ T_FINISHED
+ } t_state;
+
+ /*
+ * Where in the log does this transaction's commit start? [no locking]
+ */
+ unsigned long t_log_start;
+
+ /* Number of buffers on the t_buffers list [j_list_lock] */
+ int t_nr_buffers;
+
+ /*
+ * Doubly-linked circular list of all buffers reserved but not yet
+ * modified by this transaction [j_list_lock]
+ */
+ struct journal_head *t_reserved_list;
+
+ /*
+ * Doubly-linked circular list of all buffers under writeout during
+ * commit [j_list_lock]
+ */
+ struct journal_head *t_locked_list;
+
+ /*
+ * Doubly-linked circular list of all metadata buffers owned by this
+ * transaction [j_list_lock]
+ */
+ struct journal_head *t_buffers;
+
+ /*
+ * Doubly-linked circular list of all data buffers still to be
+ * flushed before this transaction can be committed [j_list_lock]
+ */
+ struct journal_head *t_sync_datalist;
+
+ /*
+ * Doubly-linked circular list of all forget buffers (superseded
+ * buffers which we can un-checkpoint once this transaction commits)
+ * [j_list_lock]
+ */
+ struct journal_head *t_forget;
+
+ /*
+ * Doubly-linked circular list of all buffers still to be flushed before
+ * this transaction can be checkpointed. [j_list_lock]
+ */
+ struct journal_head *t_checkpoint_list;
+
+ /*
+ * Doubly-linked circular list of all buffers submitted for IO while
+ * checkpointing. [j_list_lock]
+ */
+ struct journal_head *t_checkpoint_io_list;
+
+ /*
+ * Doubly-linked circular list of temporary buffers currently undergoing
+ * IO in the log [j_list_lock]
+ */
+ struct journal_head *t_iobuf_list;
+
+ /*
+ * Doubly-linked circular list of metadata buffers being shadowed by log
+ * IO. The IO buffers on the iobuf list and the shadow buffers on this
+ * list match each other one for one at all times. [j_list_lock]
+ */
+ struct journal_head *t_shadow_list;
+
+ /*
+ * Doubly-linked circular list of control buffers being written to the
+ * log. [j_list_lock]
+ */
+ struct journal_head *t_log_list;
+
+ /*
+ * Protects info related to handles
+ */
+ spinlock_t t_handle_lock;
+
+ /*
+ * Number of outstanding updates running on this transaction
+ * [t_handle_lock]
+ */
+ int t_updates;
+
+ /*
+ * Number of buffers reserved for use by all handles in this transaction
+ * handle but not yet modified. [t_handle_lock]
+ */
+ int t_outstanding_credits;
+
+ /*
+ * Forward and backward links for the circular list of all transactions
+ * awaiting checkpoint. [j_list_lock]
+ */
+ transaction_t *t_cpnext, *t_cpprev;
+
+ /*
+ * When will the transaction expire (become due for commit), in jiffies?
+ * [no locking]
+ */
+ unsigned long t_expires;
+
+ /*
+ * How many handles used this transaction? [t_handle_lock]
+ */
+ int t_handle_count;
+
+};
+
+/**
+ * struct journal_s - The journal_s type is the concrete type associated with
+ * journal_t.
+ * @j_flags: General journaling state flags
+ * @j_errno: Is there an outstanding uncleared error on the journal (from a
+ * prior abort)?
+ * @j_sb_buffer: First part of superblock buffer
+ * @j_superblock: Second part of superblock buffer
+ * @j_format_version: Version of the superblock format
+ * @j_state_lock: Protect the various scalars in the journal
+ * @j_barrier_count: Number of processes waiting to create a barrier lock
+ * @j_barrier: The barrier lock itself
+ * @j_running_transaction: The current running transaction..
+ * @j_committing_transaction: the transaction we are pushing to disk
+ * @j_checkpoint_transactions: a linked circular list of all transactions
+ * waiting for checkpointing
+ * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction
+ * to start committing, or for a barrier lock to be released
+ * @j_wait_logspace: Wait queue for waiting for checkpointing to complete
+ * @j_wait_done_commit: Wait queue for waiting for commit to complete
+ * @j_wait_checkpoint: Wait queue to trigger checkpointing
+ * @j_wait_commit: Wait queue to trigger commit
+ * @j_wait_updates: Wait queue to wait for updates to complete
+ * @j_checkpoint_mutex: Mutex for locking against concurrent checkpoints
+ * @j_head: Journal head - identifies the first unused block in the journal
+ * @j_tail: Journal tail - identifies the oldest still-used block in the
+ * journal.
+ * @j_free: Journal free - how many free blocks are there in the journal?
+ * @j_first: The block number of the first usable block
+ * @j_last: The block number one beyond the last usable block
+ * @j_dev: Device where we store the journal
+ * @j_blocksize: blocksize for the location where we store the journal.
+ * @j_blk_offset: starting block offset for into the device where we store the
+ * journal
+ * @j_fs_dev: Device which holds the client fs. For internal journal this will
+ * be equal to j_dev
+ * @j_maxlen: Total maximum capacity of the journal region on disk.
+ * @j_list_lock: Protects the buffer lists and internal buffer state.
+ * @j_inode: Optional inode where we store the journal. If present, all journal
+ * block numbers are mapped into this inode via bmap().
+ * @j_tail_sequence: Sequence number of the oldest transaction in the log
+ * @j_transaction_sequence: Sequence number of the next transaction to grant
+ * @j_commit_sequence: Sequence number of the most recently committed
+ * transaction
+ * @j_commit_request: Sequence number of the most recent transaction wanting
+ * commit
+ * @j_uuid: Uuid of client object.
+ * @j_task: Pointer to the current commit thread for this journal
+ * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a
+ * single compound commit transaction
+ * @j_commit_interval: What is the maximum transaction lifetime before we begin
+ * a commit?
+ * @j_commit_timer: The timer used to wakeup the commit thread
+ * @j_revoke_lock: Protect the revoke table
+ * @j_revoke: The revoke table - maintains the list of revoked blocks in the
+ * current transaction.
+ * @j_revoke_table: alternate revoke tables for j_revoke
+ * @j_wbuf: array of buffer_heads for jbd2_journal_commit_transaction
+ * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the
+ * number that will fit in j_blocksize
+ * @j_last_sync_writer: most recent pid which did a synchronous write
+ * @j_private: An opaque pointer to fs-private information.
+ */
+
+struct journal_s
+{
+ /* General journaling state flags [j_state_lock] */
+ unsigned long j_flags;
+
+ /*
+ * Is there an outstanding uncleared error on the journal (from a prior
+ * abort)? [j_state_lock]
+ */
+ int j_errno;
+
+ /* The superblock buffer */
+ struct buffer_head *j_sb_buffer;
+ journal_superblock_t *j_superblock;
+
+ /* Version of the superblock format */
+ int j_format_version;
+
+ /*
+ * Protect the various scalars in the journal
+ */
+ spinlock_t j_state_lock;
+
+ /*
+ * Number of processes waiting to create a barrier lock [j_state_lock]
+ */
+ int j_barrier_count;
+
+ /* The barrier lock itself */
+ struct mutex j_barrier;
+
+ /*
+ * Transactions: The current running transaction...
+ * [j_state_lock] [caller holding open handle]
+ */
+ transaction_t *j_running_transaction;
+
+ /*
+ * the transaction we are pushing to disk
+ * [j_state_lock] [caller holding open handle]
+ */
+ transaction_t *j_committing_transaction;
+
+ /*
+ * ... and a linked circular list of all transactions waiting for
+ * checkpointing. [j_list_lock]
+ */
+ transaction_t *j_checkpoint_transactions;
+
+ /*
+ * Wait queue for waiting for a locked transaction to start committing,
+ * or for a barrier lock to be released
+ */
+ wait_queue_head_t j_wait_transaction_locked;
+
+ /* Wait queue for waiting for checkpointing to complete */
+ wait_queue_head_t j_wait_logspace;
+
+ /* Wait queue for waiting for commit to complete */
+ wait_queue_head_t j_wait_done_commit;
+
+ /* Wait queue to trigger checkpointing */
+ wait_queue_head_t j_wait_checkpoint;
+
+ /* Wait queue to trigger commit */
+ wait_queue_head_t j_wait_commit;
+
+ /* Wait queue to wait for updates to complete */
+ wait_queue_head_t j_wait_updates;
+
+ /* Semaphore for locking against concurrent checkpoints */
+ struct mutex j_checkpoint_mutex;
+
+ /*
+ * Journal head: identifies the first unused block in the journal.
+ * [j_state_lock]
+ */
+ unsigned long j_head;
+
+ /*
+ * Journal tail: identifies the oldest still-used block in the journal.
+ * [j_state_lock]
+ */
+ unsigned long j_tail;
+
+ /*
+ * Journal free: how many free blocks are there in the journal?
+ * [j_state_lock]
+ */
+ unsigned long j_free;
+
+ /*
+ * Journal start and end: the block numbers of the first usable block
+ * and one beyond the last usable block in the journal. [j_state_lock]
+ */
+ unsigned long j_first;
+ unsigned long j_last;
+
+ /*
+ * Device, blocksize and starting block offset for the location where we
+ * store the journal.
+ */
+ struct block_device *j_dev;
+ int j_blocksize;
+ unsigned long long j_blk_offset;
+
+ /*
+ * Device which holds the client fs. For internal journal this will be
+ * equal to j_dev.
+ */
+ struct block_device *j_fs_dev;
+
+ /* Total maximum capacity of the journal region on disk. */
+ unsigned int j_maxlen;
+
+ /*
+ * Protects the buffer lists and internal buffer state.
+ */
+ spinlock_t j_list_lock;
+
+ /* Optional inode where we store the journal. If present, all */
+ /* journal block numbers are mapped into this inode via */
+ /* bmap(). */
+ struct inode *j_inode;
+
+ /*
+ * Sequence number of the oldest transaction in the log [j_state_lock]
+ */
+ tid_t j_tail_sequence;
+
+ /*
+ * Sequence number of the next transaction to grant [j_state_lock]
+ */
+ tid_t j_transaction_sequence;
+
+ /*
+ * Sequence number of the most recently committed transaction
+ * [j_state_lock].
+ */
+ tid_t j_commit_sequence;
+
+ /*
+ * Sequence number of the most recent transaction wanting commit
+ * [j_state_lock]
+ */
+ tid_t j_commit_request;
+
+ /*
+ * Journal uuid: identifies the object (filesystem, LVM volume etc)
+ * backed by this journal. This will eventually be replaced by an array
+ * of uuids, allowing us to index multiple devices within a single
+ * journal and to perform atomic updates across them.
+ */
+ __u8 j_uuid[16];
+
+ /* Pointer to the current commit thread for this journal */
+ struct task_struct *j_task;
+
+ /*
+ * Maximum number of metadata buffers to allow in a single compound
+ * commit transaction
+ */
+ int j_max_transaction_buffers;
+
+ /*
+ * What is the maximum transaction lifetime before we begin a commit?
+ */
+ unsigned long j_commit_interval;
+
+ /* The timer used to wakeup the commit thread: */
+ struct timer_list j_commit_timer;
+
+ /*
+ * The revoke table: maintains the list of revoked blocks in the
+ * current transaction. [j_revoke_lock]
+ */
+ spinlock_t j_revoke_lock;
+ struct jbd2_revoke_table_s *j_revoke;
+ struct jbd2_revoke_table_s *j_revoke_table[2];
+
+ /*
+ * array of bhs for jbd2_journal_commit_transaction
+ */
+ struct buffer_head **j_wbuf;
+ int j_wbufsize;
+
+ pid_t j_last_sync_writer;
+
+ /*
+ * An opaque pointer to fs-private information. ext3 puts its
+ * superblock pointer here
+ */
+ void *j_private;
+};
+
+/*
+ * Journal flag definitions
+ */
+#define JBD2_UNMOUNT 0x001 /* Journal thread is being destroyed */
+#define JBD2_ABORT 0x002 /* Journaling has been aborted for errors. */
+#define JBD2_ACK_ERR 0x004 /* The errno in the sb has been acked */
+#define JBD2_FLUSHED 0x008 /* The journal superblock has been flushed */
+#define JBD2_LOADED 0x010 /* The journal superblock has been loaded */
+#define JBD2_BARRIER 0x020 /* Use IDE barriers */
+
+/*
+ * Function declarations for the journaling transaction and buffer
+ * management
+ */
+
+/* Filing buffers */
+extern void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh);
+extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *);
+extern void __jbd2_journal_unfile_buffer(struct journal_head *);
+extern void __jbd2_journal_refile_buffer(struct journal_head *);
+extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *);
+extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
+extern void __journal_free_buffer(struct journal_head *bh);
+extern void jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int);
+extern void __journal_clean_data_list(transaction_t *transaction);
+
+/* Log buffer allocation */
+extern struct journal_head * jbd2_journal_get_descriptor_buffer(journal_t *);
+int jbd2_journal_next_log_block(journal_t *, unsigned long long *);
+
+/* Commit management */
+extern void jbd2_journal_commit_transaction(journal_t *);
+
+/* Checkpoint list management */
+int __jbd2_journal_clean_checkpoint_list(journal_t *journal);
+int __jbd2_journal_remove_checkpoint(struct journal_head *);
+void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *);
+
+/* Buffer IO */
+extern int
+jbd2_journal_write_metadata_buffer(transaction_t *transaction,
+ struct journal_head *jh_in,
+ struct journal_head **jh_out,
+ unsigned long long blocknr);
+
+/* Transaction locking */
+extern void __wait_on_journal (journal_t *);
+
+/*
+ * Journal locking.
+ *
+ * We need to lock the journal during transaction state changes so that nobody
+ * ever tries to take a handle on the running transaction while we are in the
+ * middle of moving it to the commit phase. j_state_lock does this.
+ *
+ * Note that the locking is completely interrupt unsafe. We never touch
+ * journal structures from interrupts.
+ */
+
+static inline handle_t *journal_current_handle(void)
+{
+ return current->journal_info;
+}
+
+/* The journaling code user interface:
+ *
+ * Create and destroy handles
+ * Register buffer modifications against the current transaction.
+ */
+
+extern handle_t *jbd2_journal_start(journal_t *, int nblocks);
+extern int jbd2_journal_restart (handle_t *, int nblocks);
+extern int jbd2_journal_extend (handle_t *, int nblocks);
+extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *);
+extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *);
+extern int jbd2_journal_get_undo_access(handle_t *, struct buffer_head *);
+extern int jbd2_journal_dirty_data (handle_t *, struct buffer_head *);
+extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *);
+extern void jbd2_journal_release_buffer (handle_t *, struct buffer_head *);
+extern int jbd2_journal_forget (handle_t *, struct buffer_head *);
+extern void journal_sync_buffer (struct buffer_head *);
+extern void jbd2_journal_invalidatepage(journal_t *,
+ struct page *, unsigned long);
+extern int jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t);
+extern int jbd2_journal_stop(handle_t *);
+extern int jbd2_journal_flush (journal_t *);
+extern void jbd2_journal_lock_updates (journal_t *);
+extern void jbd2_journal_unlock_updates (journal_t *);
+
+extern journal_t * jbd2_journal_init_dev(struct block_device *bdev,
+ struct block_device *fs_dev,
+ unsigned long long start, int len, int bsize);
+extern journal_t * jbd2_journal_init_inode (struct inode *);
+extern int jbd2_journal_update_format (journal_t *);
+extern int jbd2_journal_check_used_features
+ (journal_t *, unsigned long, unsigned long, unsigned long);
+extern int jbd2_journal_check_available_features
+ (journal_t *, unsigned long, unsigned long, unsigned long);
+extern int jbd2_journal_set_features
+ (journal_t *, unsigned long, unsigned long, unsigned long);
+extern int jbd2_journal_create (journal_t *);
+extern int jbd2_journal_load (journal_t *journal);
+extern void jbd2_journal_destroy (journal_t *);
+extern int jbd2_journal_recover (journal_t *journal);
+extern int jbd2_journal_wipe (journal_t *, int);
+extern int jbd2_journal_skip_recovery (journal_t *);
+extern void jbd2_journal_update_superblock (journal_t *, int);
+extern void __jbd2_journal_abort_hard (journal_t *);
+extern void jbd2_journal_abort (journal_t *, int);
+extern int jbd2_journal_errno (journal_t *);
+extern void jbd2_journal_ack_err (journal_t *);
+extern int jbd2_journal_clear_err (journal_t *);
+extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *);
+extern int jbd2_journal_force_commit(journal_t *);
+
+/*
+ * journal_head management
+ */
+struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh);
+struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh);
+void jbd2_journal_remove_journal_head(struct buffer_head *bh);
+void jbd2_journal_put_journal_head(struct journal_head *jh);
+
+/*
+ * handle management
+ */
+extern kmem_cache_t *jbd2_handle_cache;
+
+static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags)
+{
+ return kmem_cache_alloc(jbd2_handle_cache, gfp_flags);
+}
+
+static inline void jbd_free_handle(handle_t *handle)
+{
+ kmem_cache_free(jbd2_handle_cache, handle);
+}
+
+/* Primary revoke support */
+#define JOURNAL_REVOKE_DEFAULT_HASH 256
+extern int jbd2_journal_init_revoke(journal_t *, int);
+extern void jbd2_journal_destroy_revoke_caches(void);
+extern int jbd2_journal_init_revoke_caches(void);
+
+extern void jbd2_journal_destroy_revoke(journal_t *);
+extern int jbd2_journal_revoke (handle_t *, unsigned long long, struct buffer_head *);
+extern int jbd2_journal_cancel_revoke(handle_t *, struct journal_head *);
+extern void jbd2_journal_write_revoke_records(journal_t *, transaction_t *);
+
+/* Recovery revoke support */
+extern int jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t);
+extern int jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t);
+extern void jbd2_journal_clear_revoke(journal_t *);
+extern void jbd2_journal_switch_revoke_table(journal_t *journal);
+
+/*
+ * The log thread user interface:
+ *
+ * Request space in the current transaction, and force transaction commit
+ * transitions on demand.
+ */
+
+int __jbd2_log_space_left(journal_t *); /* Called with journal locked */
+int jbd2_log_start_commit(journal_t *journal, tid_t tid);
+int __jbd2_log_start_commit(journal_t *journal, tid_t tid);
+int jbd2_journal_start_commit(journal_t *journal, tid_t *tid);
+int jbd2_journal_force_commit_nested(journal_t *journal);
+int jbd2_log_wait_commit(journal_t *journal, tid_t tid);
+int jbd2_log_do_checkpoint(journal_t *journal);
+
+void __jbd2_log_wait_for_space(journal_t *journal);
+extern void __jbd2_journal_drop_transaction(journal_t *, transaction_t *);
+extern int jbd2_cleanup_journal_tail(journal_t *);
+
+/* Debugging code only: */
+
+#define jbd_ENOSYS() \
+do { \
+ printk (KERN_ERR "JBD unimplemented function %s\n", __FUNCTION__); \
+ current->state = TASK_UNINTERRUPTIBLE; \
+ schedule(); \
+} while (1)
+
+/*
+ * is_journal_abort
+ *
+ * Simple test wrapper function to test the JBD2_ABORT state flag. This
+ * bit, when set, indicates that we have had a fatal error somewhere,
+ * either inside the journaling layer or indicated to us by the client
+ * (eg. ext3), and that we and should not commit any further
+ * transactions.
+ */
+
+static inline int is_journal_aborted(journal_t *journal)
+{
+ return journal->j_flags & JBD2_ABORT;
+}
+
+static inline int is_handle_aborted(handle_t *handle)
+{
+ if (handle->h_aborted)
+ return 1;
+ return is_journal_aborted(handle->h_transaction->t_journal);
+}
+
+static inline void jbd2_journal_abort_handle(handle_t *handle)
+{
+ handle->h_aborted = 1;
+}
+
+#endif /* __KERNEL__ */
+
+/* Comparison functions for transaction IDs: perform comparisons using
+ * modulo arithmetic so that they work over sequence number wraps. */
+
+static inline int tid_gt(tid_t x, tid_t y)
+{
+ int difference = (x - y);
+ return (difference > 0);
+}
+
+static inline int tid_geq(tid_t x, tid_t y)
+{
+ int difference = (x - y);
+ return (difference >= 0);
+}
+
+extern int jbd2_journal_blocks_per_page(struct inode *inode);
+extern size_t journal_tag_bytes(journal_t *journal);
+
+/*
+ * Return the minimum number of blocks which must be free in the journal
+ * before a new transaction may be started. Must be called under j_state_lock.
+ */
+static inline int jbd_space_needed(journal_t *journal)
+{
+ int nblocks = journal->j_max_transaction_buffers;
+ if (journal->j_committing_transaction)
+ nblocks += journal->j_committing_transaction->
+ t_outstanding_credits;
+ return nblocks;
+}
+
+/*
+ * Definitions which augment the buffer_head layer
+ */
+
+/* journaling buffer types */
+#define BJ_None 0 /* Not journaled */
+#define BJ_SyncData 1 /* Normal data: flush before commit */
+#define BJ_Metadata 2 /* Normal journaled metadata */
+#define BJ_Forget 3 /* Buffer superseded by this transaction */
+#define BJ_IO 4 /* Buffer is for temporary IO use */
+#define BJ_Shadow 5 /* Buffer contents being shadowed to the log */
+#define BJ_LogCtl 6 /* Buffer contains log descriptors */
+#define BJ_Reserved 7 /* Buffer is reserved for access by journal */
+#define BJ_Locked 8 /* Locked for I/O during commit */
+#define BJ_Types 9
+
+extern int jbd_blocks_per_page(struct inode *inode);
+
+#ifdef __KERNEL__
+
+#define buffer_trace_init(bh) do {} while (0)
+#define print_buffer_fields(bh) do {} while (0)
+#define print_buffer_trace(bh) do {} while (0)
+#define BUFFER_TRACE(bh, info) do {} while (0)
+#define BUFFER_TRACE2(bh, bh2, info) do {} while (0)
+#define JBUFFER_TRACE(jh, info) do {} while (0)
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_JBD_H */
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 849043ce4ed6..1cebcbc28b47 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -12,6 +12,10 @@
/* Lookup the address for a symbol. Returns 0 if not found. */
unsigned long kallsyms_lookup_name(const char *name);
+extern int kallsyms_lookup_size_offset(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset);
+
/* Lookup an address. modname is set to NULL if it's in the kernel. */
const char *kallsyms_lookup(unsigned long addr,
unsigned long *symbolsize,
@@ -28,6 +32,13 @@ static inline unsigned long kallsyms_lookup_name(const char *name)
return 0;
}
+static inline int kallsyms_lookup_size_offset(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset)
+{
+ return 0;
+}
+
static inline const char *kallsyms_lookup(unsigned long addr,
unsigned long *symbolsize,
unsigned long *offset,
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 4fa373bb18ac..80f39cab470a 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -216,8 +216,10 @@ extern void dump_stack(void);
#define pr_debug(fmt,arg...) \
printk(KERN_DEBUG fmt,##arg)
#else
-#define pr_debug(fmt,arg...) \
- do { } while (0)
+static inline int __attribute__ ((format (printf, 1, 2))) pr_debug(const char * fmt, ...)
+{
+ return 0;
+}
#endif
#define pr_info(fmt,arg...) \
@@ -350,4 +352,11 @@ struct sysinfo {
/* Trap pasters of __FUNCTION__ at compile-time */
#define __FUNCTION__ (__func__)
+/* This helps us to avoid #ifdef CONFIG_NUMA */
+#ifdef CONFIG_NUMA
+#define NUMA_BUILD 1
+#else
+#define NUMA_BUILD 0
+#endif
+
#endif
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 0db22a1ab474..10f505c8431d 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -47,4 +47,8 @@ call_usermodehelper(char *path, char **argv, char **envp, int wait)
extern void usermodehelper_init(void);
+struct file;
+extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[],
+ struct file **filp);
+
#endif /* __LINUX_KMOD_H__ */
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 8bf6702da2a0..ac4c0559f751 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -77,6 +77,12 @@ struct kprobe {
/* location of the probe point */
kprobe_opcode_t *addr;
+ /* Allow user to indicate symbol name of the probe point */
+ char *symbol_name;
+
+ /* Offset into the symbol */
+ unsigned int offset;
+
/* Called before addr is executed. */
kprobe_pre_handler_t pre_handler;
@@ -196,7 +202,7 @@ void unregister_kretprobe(struct kretprobe *rp);
struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp);
void add_rp_inst(struct kretprobe_instance *ri);
void kprobe_flush_task(struct task_struct *tk);
-void recycle_rp_inst(struct kretprobe_instance *ri);
+void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head);
#else /* CONFIG_KPROBES */
#define __kprobes /**/
diff --git a/include/linux/latency.h b/include/linux/latency.h
new file mode 100644
index 000000000000..c08b52bb55b0
--- /dev/null
+++ b/include/linux/latency.h
@@ -0,0 +1,25 @@
+/*
+ * latency.h: Explicit system-wide latency-expectation infrastructure
+ *
+ * (C) Copyright 2006 Intel Corporation
+ * Author: Arjan van de Ven <arjan@linux.intel.com>
+ *
+ */
+
+#ifndef _INCLUDE_GUARD_LATENCY_H_
+#define _INCLUDE_GUARD_LATENCY_H_
+
+#include <linux/notifier.h>
+
+void set_acceptable_latency(char *identifier, int usecs);
+void modify_acceptable_latency(char *identifier, int usecs);
+void remove_acceptable_latency(char *identifier);
+void synchronize_acceptable_latency(void);
+int system_latency_constraint(void);
+
+int register_latency_notifier(struct notifier_block * nb);
+int unregister_latency_notifier(struct notifier_block * nb);
+
+#define INFINITE_LATENCY 1000000
+
+#endif
diff --git a/include/linux/leds.h b/include/linux/leds.h
index dc23c7c639f3..88afceffb7cb 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -12,6 +12,9 @@
#ifndef __LINUX_LEDS_H_INCLUDED
#define __LINUX_LEDS_H_INCLUDED
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
struct device;
struct class_device;
/*
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d6a3d4b345fc..d0a7ad5ed518 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -109,6 +109,10 @@ static inline u32 ata_msg_init(int dval, int default_msg_enable_bits)
#define ATA_TAG_POISON 0xfafbfcfdU
/* move to PCI layer? */
+#define PCI_VDEVICE(vendor, device) \
+ PCI_VENDOR_ID_##vendor, (device), \
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0
+
static inline struct device *pci_dev_to_dev(struct pci_dev *pdev)
{
return &pdev->dev;
@@ -138,8 +142,9 @@ enum {
ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,
- ATA_DFLAG_PIO = (1 << 8), /* device currently in PIO mode */
- ATA_DFLAG_SUSPENDED = (1 << 9), /* device suspended */
+ ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
+ ATA_DFLAG_NCQ_OFF = (1 << 9), /* devied limited to non-NCQ mode */
+ ATA_DFLAG_SUSPENDED = (1 << 10), /* device suspended */
ATA_DFLAG_INIT_MASK = (1 << 16) - 1,
ATA_DFLAG_DETACH = (1 << 16),
@@ -623,7 +628,7 @@ struct ata_port_operations {
void (*error_handler) (struct ata_port *ap);
void (*post_internal_cmd) (struct ata_queued_cmd *qc);
- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *);
+ irq_handler_t irq_handler;
void (*irq_clear) (struct ata_port *);
u32 (*scr_read) (struct ata_port *ap, unsigned int sc_reg);
@@ -764,7 +769,7 @@ extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf)
extern int ata_port_start (struct ata_port *ap);
extern void ata_port_stop (struct ata_port *ap);
extern void ata_host_stop (struct ata_host *host);
-extern irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+extern irqreturn_t ata_interrupt (int irq, void *dev_instance);
extern void ata_mmio_data_xfer(struct ata_device *adev, unsigned char *buf,
unsigned int buflen, int write_data);
extern void ata_pio_data_xfer(struct ata_device *adev, unsigned char *buf,
diff --git a/include/linux/libps2.h b/include/linux/libps2.h
index 08a450a9dbf7..f6f301e2b0f5 100644
--- a/include/linux/libps2.h
+++ b/include/linux/libps2.h
@@ -47,5 +47,6 @@ int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int comman
int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data);
void ps2_cmd_aborted(struct ps2dev *ps2dev);
+int ps2_is_keyboard_id(char id);
#endif /* _LIBPS2_H */
diff --git a/include/linux/list.h b/include/linux/list.h
index 65a5b5ceda49..a9c90287c0ff 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -39,6 +39,7 @@ static inline void INIT_LIST_HEAD(struct list_head *list)
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
+#ifndef CONFIG_DEBUG_LIST
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
@@ -48,6 +49,11 @@ static inline void __list_add(struct list_head *new,
new->prev = prev;
prev->next = new;
}
+#else
+extern void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next);
+#endif
/**
* list_add - add a new entry
@@ -57,10 +63,15 @@ static inline void __list_add(struct list_head *new,
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
+#ifndef CONFIG_DEBUG_LIST
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}
+#else
+extern void list_add(struct list_head *new, struct list_head *head);
+#endif
+
/**
* list_add_tail - add a new entry
@@ -153,12 +164,16 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
+#ifndef CONFIG_DEBUG_LIST
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
+#else
+extern void list_del(struct list_head *entry);
+#endif
/**
* list_del_rcu - deletes entry from list without re-initialization
diff --git a/include/linux/lm_interface.h b/include/linux/lm_interface.h
new file mode 100644
index 000000000000..1418fdc9ac02
--- /dev/null
+++ b/include/linux/lm_interface.h
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
+ * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License version 2.
+ */
+
+#ifndef __LM_INTERFACE_DOT_H__
+#define __LM_INTERFACE_DOT_H__
+
+
+typedef void (*lm_callback_t) (void *ptr, unsigned int type, void *data);
+
+/*
+ * lm_mount() flags
+ *
+ * LM_MFLAG_SPECTATOR
+ * GFS is asking to join the filesystem's lockspace, but it doesn't want to
+ * modify the filesystem. The lock module shouldn't assign a journal to the FS
+ * mount. It shouldn't send recovery callbacks to the FS mount. If the node
+ * dies or withdraws, all locks can be wiped immediately.
+ */
+
+#define LM_MFLAG_SPECTATOR 0x00000001
+
+/*
+ * lm_lockstruct flags
+ *
+ * LM_LSFLAG_LOCAL
+ * The lock_nolock module returns LM_LSFLAG_LOCAL to GFS, indicating that GFS
+ * can make single-node optimizations.
+ */
+
+#define LM_LSFLAG_LOCAL 0x00000001
+
+/*
+ * lm_lockname types
+ */
+
+#define LM_TYPE_RESERVED 0x00
+#define LM_TYPE_NONDISK 0x01
+#define LM_TYPE_INODE 0x02
+#define LM_TYPE_RGRP 0x03
+#define LM_TYPE_META 0x04
+#define LM_TYPE_IOPEN 0x05
+#define LM_TYPE_FLOCK 0x06
+#define LM_TYPE_PLOCK 0x07
+#define LM_TYPE_QUOTA 0x08
+#define LM_TYPE_JOURNAL 0x09
+
+/*
+ * lm_lock() states
+ *
+ * SHARED is compatible with SHARED, not with DEFERRED or EX.
+ * DEFERRED is compatible with DEFERRED, not with SHARED or EX.
+ */
+
+#define LM_ST_UNLOCKED 0
+#define LM_ST_EXCLUSIVE 1
+#define LM_ST_DEFERRED 2
+#define LM_ST_SHARED 3
+
+/*
+ * lm_lock() flags
+ *
+ * LM_FLAG_TRY
+ * Don't wait to acquire the lock if it can't be granted immediately.
+ *
+ * LM_FLAG_TRY_1CB
+ * Send one blocking callback if TRY is set and the lock is not granted.
+ *
+ * LM_FLAG_NOEXP
+ * GFS sets this flag on lock requests it makes while doing journal recovery.
+ * These special requests should not be blocked due to the recovery like
+ * ordinary locks would be.
+ *
+ * LM_FLAG_ANY
+ * A SHARED request may also be granted in DEFERRED, or a DEFERRED request may
+ * also be granted in SHARED. The preferred state is whichever is compatible
+ * with other granted locks, or the specified state if no other locks exist.
+ *
+ * LM_FLAG_PRIORITY
+ * Override fairness considerations. Suppose a lock is held in a shared state
+ * and there is a pending request for the deferred state. A shared lock
+ * request with the priority flag would be allowed to bypass the deferred
+ * request and directly join the other shared lock. A shared lock request
+ * without the priority flag might be forced to wait until the deferred
+ * requested had acquired and released the lock.
+ */
+
+#define LM_FLAG_TRY 0x00000001
+#define LM_FLAG_TRY_1CB 0x00000002
+#define LM_FLAG_NOEXP 0x00000004
+#define LM_FLAG_ANY 0x00000008
+#define LM_FLAG_PRIORITY 0x00000010
+
+/*
+ * lm_lock() and lm_async_cb return flags
+ *
+ * LM_OUT_ST_MASK
+ * Masks the lower two bits of lock state in the returned value.
+ *
+ * LM_OUT_CACHEABLE
+ * The lock hasn't been released so GFS can continue to cache data for it.
+ *
+ * LM_OUT_CANCELED
+ * The lock request was canceled.
+ *
+ * LM_OUT_ASYNC
+ * The result of the request will be returned in an LM_CB_ASYNC callback.
+ */
+
+#define LM_OUT_ST_MASK 0x00000003
+#define LM_OUT_CACHEABLE 0x00000004
+#define LM_OUT_CANCELED 0x00000008
+#define LM_OUT_ASYNC 0x00000080
+#define LM_OUT_ERROR 0x00000100
+
+/*
+ * lm_callback_t types
+ *
+ * LM_CB_NEED_E LM_CB_NEED_D LM_CB_NEED_S
+ * Blocking callback, a remote node is requesting the given lock in
+ * EXCLUSIVE, DEFERRED, or SHARED.
+ *
+ * LM_CB_NEED_RECOVERY
+ * The given journal needs to be recovered.
+ *
+ * LM_CB_DROPLOCKS
+ * Reduce the number of cached locks.
+ *
+ * LM_CB_ASYNC
+ * The given lock has been granted.
+ */
+
+#define LM_CB_NEED_E 257
+#define LM_CB_NEED_D 258
+#define LM_CB_NEED_S 259
+#define LM_CB_NEED_RECOVERY 260
+#define LM_CB_DROPLOCKS 261
+#define LM_CB_ASYNC 262
+
+/*
+ * lm_recovery_done() messages
+ */
+
+#define LM_RD_GAVEUP 308
+#define LM_RD_SUCCESS 309
+
+
+struct lm_lockname {
+ u64 ln_number;
+ unsigned int ln_type;
+};
+
+#define lm_name_equal(name1, name2) \
+ (((name1)->ln_number == (name2)->ln_number) && \
+ ((name1)->ln_type == (name2)->ln_type)) \
+
+struct lm_async_cb {
+ struct lm_lockname lc_name;
+ int lc_ret;
+};
+
+struct lm_lockstruct;
+
+struct lm_lockops {
+ const char *lm_proto_name;
+
+ /*
+ * Mount/Unmount
+ */
+
+ int (*lm_mount) (char *table_name, char *host_data,
+ lm_callback_t cb, void *cb_data,
+ unsigned int min_lvb_size, int flags,
+ struct lm_lockstruct *lockstruct,
+ struct kobject *fskobj);
+
+ void (*lm_others_may_mount) (void *lockspace);
+
+ void (*lm_unmount) (void *lockspace);
+
+ void (*lm_withdraw) (void *lockspace);
+
+ /*
+ * Lock oriented operations
+ */
+
+ int (*lm_get_lock) (void *lockspace, struct lm_lockname *name, void **lockp);
+
+ void (*lm_put_lock) (void *lock);
+
+ unsigned int (*lm_lock) (void *lock, unsigned int cur_state,
+ unsigned int req_state, unsigned int flags);
+
+ unsigned int (*lm_unlock) (void *lock, unsigned int cur_state);
+
+ void (*lm_cancel) (void *lock);
+
+ int (*lm_hold_lvb) (void *lock, char **lvbp);
+ void (*lm_unhold_lvb) (void *lock, char *lvb);
+
+ /*
+ * Posix Lock oriented operations
+ */
+
+ int (*lm_plock_get) (void *lockspace, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl);
+
+ int (*lm_plock) (void *lockspace, struct lm_lockname *name,
+ struct file *file, int cmd, struct file_lock *fl);
+
+ int (*lm_punlock) (void *lockspace, struct lm_lockname *name,
+ struct file *file, struct file_lock *fl);
+
+ /*
+ * Client oriented operations
+ */
+
+ void (*lm_recovery_done) (void *lockspace, unsigned int jid,
+ unsigned int message);
+
+ struct module *lm_owner;
+};
+
+/*
+ * lm_mount() return values
+ *
+ * ls_jid - the journal ID this node should use
+ * ls_first - this node is the first to mount the file system
+ * ls_lvb_size - size in bytes of lock value blocks
+ * ls_lockspace - lock module's context for this file system
+ * ls_ops - lock module's functions
+ * ls_flags - lock module features
+ */
+
+struct lm_lockstruct {
+ unsigned int ls_jid;
+ unsigned int ls_first;
+ unsigned int ls_lvb_size;
+ void *ls_lockspace;
+ const struct lm_lockops *ls_ops;
+ int ls_flags;
+};
+
+/*
+ * Lock module bottom interface. A lock module makes itself available to GFS
+ * with these functions.
+ */
+
+int gfs2_register_lockproto(const struct lm_lockops *proto);
+void gfs2_unregister_lockproto(const struct lm_lockops *proto);
+
+/*
+ * Lock module top interface. GFS calls these functions when mounting or
+ * unmounting a file system.
+ */
+
+int gfs2_mount_lockproto(char *proto_name, char *table_name, char *host_data,
+ lm_callback_t cb, void *cb_data,
+ unsigned int min_lvb_size, int flags,
+ struct lm_lockstruct *lockstruct,
+ struct kobject *fskobj);
+
+void gfs2_unmount_lockproto(struct lm_lockstruct *lockstruct);
+
+void gfs2_withdraw_lockproto(struct lm_lockstruct *lockstruct);
+
+#endif /* __LM_INTERFACE_DOT_H__ */
+
diff --git a/include/linux/lock_dlm_plock.h b/include/linux/lock_dlm_plock.h
new file mode 100644
index 000000000000..fc3415113973
--- /dev/null
+++ b/include/linux/lock_dlm_plock.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2005 Red Hat, Inc. All rights reserved.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ */
+
+#ifndef __LOCK_DLM_PLOCK_DOT_H__
+#define __LOCK_DLM_PLOCK_DOT_H__
+
+#define GDLM_PLOCK_MISC_NAME "lock_dlm_plock"
+
+#define GDLM_PLOCK_VERSION_MAJOR 1
+#define GDLM_PLOCK_VERSION_MINOR 1
+#define GDLM_PLOCK_VERSION_PATCH 0
+
+enum {
+ GDLM_PLOCK_OP_LOCK = 1,
+ GDLM_PLOCK_OP_UNLOCK,
+ GDLM_PLOCK_OP_GET,
+};
+
+struct gdlm_plock_info {
+ __u32 version[3];
+ __u8 optype;
+ __u8 ex;
+ __u8 wait;
+ __u8 pad;
+ __u32 pid;
+ __s32 nodeid;
+ __s32 rv;
+ __u32 fsid;
+ __u64 number;
+ __u64 start;
+ __u64 end;
+ __u64 owner;
+};
+
+#endif
+
diff --git a/include/linux/lockd/bind.h b/include/linux/lockd/bind.h
index b054debef2e0..aa50d89eacd7 100644
--- a/include/linux/lockd/bind.h
+++ b/include/linux/lockd/bind.h
@@ -10,6 +10,11 @@
#define LINUX_LOCKD_BIND_H
#include <linux/lockd/nlm.h>
+/* need xdr-encoded error codes too, so... */
+#include <linux/lockd/xdr.h>
+#ifdef CONFIG_LOCKD_V4
+#include <linux/lockd/xdr4.h>
+#endif
/* Dummy declarations */
struct svc_rqst;
@@ -30,7 +35,7 @@ extern struct nlmsvc_binding * nlmsvc_ops;
* Functions exported by the lockd module
*/
extern int nlmclnt_proc(struct inode *, int, struct file_lock *);
-extern int lockd_up(void);
+extern int lockd_up(int proto);
extern void lockd_down(void);
#endif /* LINUX_LOCKD_BIND_H */
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 0d92c468d55a..862d9730a60d 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -37,17 +37,15 @@
* Lockd host handle (used both by the client and server personality).
*/
struct nlm_host {
- struct nlm_host * h_next; /* linked list (hash table) */
+ struct hlist_node h_hash; /* doubly linked list */
struct sockaddr_in h_addr; /* peer address */
struct rpc_clnt * h_rpcclnt; /* RPC client to talk to peer */
- char h_name[20]; /* remote hostname */
+ char * h_name; /* remote hostname */
u32 h_version; /* interface version */
unsigned short h_proto; /* transport proto */
unsigned short h_reclaiming : 1,
h_server : 1, /* server side, not client side */
- h_inuse : 1,
- h_killed : 1,
- h_monitored : 1;
+ h_inuse : 1;
wait_queue_head_t h_gracewait; /* wait while reclaiming */
struct rw_semaphore h_rwsem; /* Reboot recovery lock */
u32 h_state; /* pseudo-state counter */
@@ -61,6 +59,16 @@ struct nlm_host {
spinlock_t h_lock;
struct list_head h_granted; /* Locks in GRANTED state */
struct list_head h_reclaim; /* Locks in RECLAIM state */
+ struct nsm_handle * h_nsmhandle; /* NSM status handle */
+};
+
+struct nsm_handle {
+ struct list_head sm_link;
+ atomic_t sm_count;
+ char * sm_name;
+ struct sockaddr_in sm_addr;
+ unsigned int sm_monitored : 1,
+ sm_sticky : 1; /* don't unmonitor */
};
/*
@@ -80,7 +88,7 @@ struct nlm_wait;
/*
* Memory chunk for NLM client RPC request.
*/
-#define NLMCLNT_OHSIZE (sizeof(system_utsname.nodename)+10)
+#define NLMCLNT_OHSIZE (sizeof(utsname()->nodename)+10)
struct nlm_rqst {
unsigned int a_flags; /* initial RPC task flags */
struct nlm_host * a_host; /* host handle */
@@ -96,15 +104,14 @@ struct nlm_rqst {
* an NFS client.
*/
struct nlm_file {
- struct nlm_file * f_next; /* linked list */
+ struct hlist_node f_list; /* linked list */
struct nfs_fh f_handle; /* NFS file handle */
struct file * f_file; /* VFS file pointer */
struct nlm_share * f_shares; /* DOS shares */
- struct nlm_block * f_blocks; /* blocked locks */
+ struct list_head f_blocks; /* blocked locks */
unsigned int f_locks; /* guesstimate # of locks */
unsigned int f_count; /* reference count */
- struct semaphore f_sema; /* avoid concurrent access */
- int f_hash; /* hash of f_handle */
+ struct mutex f_mutex; /* avoid concurrent access */
};
/*
@@ -114,26 +121,18 @@ struct nlm_file {
#define NLM_NEVER (~(unsigned long) 0)
struct nlm_block {
struct kref b_count; /* Reference count */
- struct nlm_block * b_next; /* linked list (all blocks) */
- struct nlm_block * b_fnext; /* linked list (per file) */
+ struct list_head b_list; /* linked list of all blocks */
+ struct list_head b_flist; /* linked list (per file) */
struct nlm_rqst * b_call; /* RPC args & callback info */
struct svc_serv * b_daemon; /* NLM service */
struct nlm_host * b_host; /* host handle for RPC clnt */
unsigned long b_when; /* next re-xmit */
unsigned int b_id; /* block id */
- unsigned char b_queued; /* re-queued */
unsigned char b_granted; /* VFS granted lock */
struct nlm_file * b_file; /* file in question */
};
/*
- * Valid actions for nlmsvc_traverse_files
- */
-#define NLM_ACT_CHECK 0 /* check for locks */
-#define NLM_ACT_MARK 1 /* mark & sweep */
-#define NLM_ACT_UNLOCK 2 /* release all locks */
-
-/*
* Global variables
*/
extern struct rpc_program nlm_program;
@@ -143,6 +142,7 @@ extern struct svc_procedure nlmsvc_procedures4[];
#endif
extern int nlmsvc_grace_period;
extern unsigned long nlmsvc_timeout;
+extern int nsm_use_hostnames;
/*
* Lockd client functions
@@ -154,42 +154,51 @@ int nlm_async_reply(struct nlm_rqst *, u32, const struct rpc_call_ops *);
struct nlm_wait * nlmclnt_prepare_block(struct nlm_host *host, struct file_lock *fl);
void nlmclnt_finish_block(struct nlm_wait *block);
int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout);
-u32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
-void nlmclnt_recovery(struct nlm_host *, u32);
+__be32 nlmclnt_grant(const struct sockaddr_in *addr, const struct nlm_lock *);
+void nlmclnt_recovery(struct nlm_host *);
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
+void nlmclnt_next_cookie(struct nlm_cookie *);
/*
* Host cache
*/
-struct nlm_host * nlmclnt_lookup_host(struct sockaddr_in *, int, int);
-struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *);
-struct nlm_host * nlm_lookup_host(int server, struct sockaddr_in *, int, int);
+struct nlm_host * nlmclnt_lookup_host(const struct sockaddr_in *, int, int, const char *, int);
+struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *, const char *, int);
+struct nlm_host * nlm_lookup_host(int server, const struct sockaddr_in *, int, int, const char *, int);
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *);
void nlm_release_host(struct nlm_host *);
void nlm_shutdown_hosts(void);
-extern struct nlm_host *nlm_find_client(void);
+extern void nlm_host_rebooted(const struct sockaddr_in *, const char *, int, u32);
+struct nsm_handle *nsm_find(const struct sockaddr_in *, const char *, int);
+void nsm_release(struct nsm_handle *);
+
+/*
+ * This is used in garbage collection and resource reclaim
+ * A return value != 0 means destroy the lock/block/share
+ */
+typedef int (*nlm_host_match_fn_t)(struct nlm_host *cur, struct nlm_host *ref);
/*
* Server-side lock handling
*/
-u32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
+__be32 nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
struct nlm_lock *, int, struct nlm_cookie *);
-u32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
-u32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
+__be32 nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
+__be32 nlmsvc_testlock(struct nlm_file *, struct nlm_lock *,
struct nlm_lock *);
-u32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
+__be32 nlmsvc_cancel_blocked(struct nlm_file *, struct nlm_lock *);
unsigned long nlmsvc_retry_blocked(void);
void nlmsvc_traverse_blocks(struct nlm_host *, struct nlm_file *,
- int action);
-void nlmsvc_grant_reply(struct svc_rqst *, struct nlm_cookie *, u32);
+ nlm_host_match_fn_t match);
+void nlmsvc_grant_reply(struct nlm_cookie *, u32);
/*
* File handling for the server personality
*/
-u32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
+__be32 nlm_lookup_file(struct svc_rqst *, struct nlm_file **,
struct nfs_fh *);
void nlm_release_file(struct nlm_file *);
void nlmsvc_mark_resources(void);
diff --git a/include/linux/lockd/share.h b/include/linux/lockd/share.h
index c75a424ebe4c..630c5bf69b07 100644
--- a/include/linux/lockd/share.h
+++ b/include/linux/lockd/share.h
@@ -21,10 +21,11 @@ struct nlm_share {
u32 s_mode; /* deny mode */
};
-u32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *,
+__be32 nlmsvc_share_file(struct nlm_host *, struct nlm_file *,
struct nlm_args *);
-u32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
+__be32 nlmsvc_unshare_file(struct nlm_host *, struct nlm_file *,
struct nlm_args *);
-void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *, int);
+void nlmsvc_traverse_shares(struct nlm_host *, struct nlm_file *,
+ nlm_host_match_fn_t);
#endif /* LINUX_LOCKD_SHARE_H */
diff --git a/include/linux/lockd/sm_inter.h b/include/linux/lockd/sm_inter.h
index 1080bb6ae315..fc61d40964da 100644
--- a/include/linux/lockd/sm_inter.h
+++ b/include/linux/lockd/sm_inter.h
@@ -28,7 +28,8 @@ struct nsm_args {
u32 prog; /* RPC callback info */
u32 vers;
u32 proc;
- u32 proto; /* protocol (udp/tcp) plus server/client flag */
+
+ char * mon_name;
};
/*
@@ -41,6 +42,6 @@ struct nsm_res {
int nsm_monitor(struct nlm_host *);
int nsm_unmonitor(struct nlm_host *);
-extern u32 nsm_local_state;
+extern int nsm_local_state;
#endif /* LINUX_LOCKD_SM_INTER_H */
diff --git a/include/linux/lockd/xdr.h b/include/linux/lockd/xdr.h
index bb0a0f1caa91..29e7d9fc9dad 100644
--- a/include/linux/lockd/xdr.h
+++ b/include/linux/lockd/xdr.h
@@ -13,6 +13,8 @@
#include <linux/nfs.h>
#include <linux/sunrpc/xdr.h>
+struct svc_rqst;
+
#define NLM_MAXCOOKIELEN 32
#define NLM_MAXSTRLEN 1024
@@ -22,6 +24,8 @@
#define nlm_lck_blocked __constant_htonl(NLM_LCK_BLOCKED)
#define nlm_lck_denied_grace_period __constant_htonl(NLM_LCK_DENIED_GRACE_PERIOD)
+#define nlm_drop_reply __constant_htonl(30000)
+
/* Lock info passed via NLM */
struct nlm_lock {
char * caller;
@@ -86,19 +90,19 @@ struct nlm_reboot {
*/
#define NLMSVC_XDRSIZE sizeof(struct nlm_args)
-int nlmsvc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlmsvc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlmsvc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlmsvc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlmsvc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlmsvc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlmsvc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlmsvc_encode_void(struct svc_rqst *, u32 *, void *);
-int nlmsvc_decode_void(struct svc_rqst *, u32 *, void *);
-int nlmsvc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlmsvc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlmsvc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlmsvc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
+int nlmsvc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlmsvc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlmsvc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlmsvc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlmsvc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlmsvc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlmsvc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlmsvc_encode_void(struct svc_rqst *, __be32 *, void *);
+int nlmsvc_decode_void(struct svc_rqst *, __be32 *, void *);
+int nlmsvc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlmsvc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlmsvc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlmsvc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
/*
int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
diff --git a/include/linux/lockd/xdr4.h b/include/linux/lockd/xdr4.h
index cee36e7c0548..dd12b4c9e613 100644
--- a/include/linux/lockd/xdr4.h
+++ b/include/linux/lockd/xdr4.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/lockd/xdr.h
+ * linux/include/linux/lockd/xdr4.h
*
* XDR types for the NLM protocol
*
@@ -23,19 +23,19 @@
-int nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlm4svc_encode_void(struct svc_rqst *, u32 *, void *);
-int nlm4svc_decode_void(struct svc_rqst *, u32 *, void *);
-int nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
-int nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
-int nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
+int nlm4svc_decode_testargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlm4svc_encode_testres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlm4svc_decode_lockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlm4svc_decode_cancargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlm4svc_decode_unlockargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlm4svc_encode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlm4svc_decode_res(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlm4svc_encode_void(struct svc_rqst *, __be32 *, void *);
+int nlm4svc_decode_void(struct svc_rqst *, __be32 *, void *);
+int nlm4svc_decode_shareargs(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlm4svc_encode_shareres(struct svc_rqst *, __be32 *, struct nlm_res *);
+int nlm4svc_decode_notify(struct svc_rqst *, __be32 *, struct nlm_args *);
+int nlm4svc_decode_reboot(struct svc_rqst *, __be32 *, struct nlm_reboot *);
/*
int nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
int nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index c040a8c969aa..819f08f1310d 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -8,13 +8,13 @@
#ifndef __LINUX_LOCKDEP_H
#define __LINUX_LOCKDEP_H
+#ifdef CONFIG_LOCKDEP
+
#include <linux/linkage.h>
#include <linux/list.h>
#include <linux/debug_locks.h>
#include <linux/stacktrace.h>
-#ifdef CONFIG_LOCKDEP
-
/*
* Lock-class usage-state bits:
*/
@@ -202,7 +202,7 @@ extern int lockdep_internal(void);
*/
extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
- struct lock_class_key *key);
+ struct lock_class_key *key, int subclass);
/*
* Reinitialize a lock key - for cases where there is special locking or
@@ -211,9 +211,14 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
* or they are too narrow (they suffer from a false class-split):
*/
#define lockdep_set_class(lock, key) \
- lockdep_init_map(&(lock)->dep_map, #key, key)
+ lockdep_init_map(&(lock)->dep_map, #key, key, 0)
#define lockdep_set_class_and_name(lock, key, name) \
- lockdep_init_map(&(lock)->dep_map, name, key)
+ lockdep_init_map(&(lock)->dep_map, name, key, 0)
+#define lockdep_set_class_and_subclass(lock, key, sub) \
+ lockdep_init_map(&(lock)->dep_map, #key, key, sub)
+#define lockdep_set_subclass(lock, sub) \
+ lockdep_init_map(&(lock)->dep_map, #lock, \
+ (lock)->dep_map.key, sub)
/*
* Acquire a lock.
@@ -257,10 +262,14 @@ static inline int lockdep_internal(void)
# define lock_release(l, n, i) do { } while (0)
# define lockdep_init() do { } while (0)
# define lockdep_info() do { } while (0)
-# define lockdep_init_map(lock, name, key) do { (void)(key); } while (0)
+# define lockdep_init_map(lock, name, key, sub) do { (void)(key); } while (0)
# define lockdep_set_class(lock, key) do { (void)(key); } while (0)
# define lockdep_set_class_and_name(lock, key, name) \
do { (void)(key); } while (0)
+#define lockdep_set_class_and_subclass(lock, key, sub) \
+ do { (void)(key); } while (0)
+#define lockdep_set_subclass(lock, sub) do { } while (0)
+
# define INIT_LOCKDEP
# define lockdep_reset() do { debug_locks = 1; } while (0)
# define lockdep_free_key_range(start, size) do { } while (0)
diff --git a/include/linux/loop.h b/include/linux/loop.h
index e76c7611d6cc..191a595055f0 100644
--- a/include/linux/loop.h
+++ b/include/linux/loop.h
@@ -59,10 +59,9 @@ struct loop_device {
struct bio *lo_bio;
struct bio *lo_biotail;
int lo_state;
- struct completion lo_done;
- struct completion lo_bh_done;
struct mutex lo_ctl_mutex;
- int lo_pending;
+ struct task_struct *lo_thread;
+ wait_queue_head_t lo_event;
request_queue_t *lo_queue;
};
diff --git a/include/linux/magic.h b/include/linux/magic.h
index 22036dd2ba36..156c40fc664e 100644
--- a/include/linux/magic.h
+++ b/include/linux/magic.h
@@ -8,6 +8,7 @@
#define EFS_SUPER_MAGIC 0x414A53
#define EXT2_SUPER_MAGIC 0xEF53
#define EXT3_SUPER_MAGIC 0xEF53
+#define EXT4_SUPER_MAGIC 0xEF53
#define HPFS_SUPER_MAGIC 0xf995e849
#define ISOFS_SUPER_MAGIC 0x9660
#define JFFS2_SUPER_MAGIC 0x72b6
diff --git a/include/linux/memory.h b/include/linux/memory.h
index 8f04143ca363..654ef5544878 100644
--- a/include/linux/memory.h
+++ b/include/linux/memory.h
@@ -57,7 +57,7 @@ struct memory_block {
struct notifier_block;
struct mem_section;
-#ifndef CONFIG_MEMORY_HOTPLUG
+#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE
static inline int memory_dev_init(void)
{
return 0;
@@ -78,7 +78,7 @@ extern int remove_memory_block(unsigned long, struct mem_section *, int);
#define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION<<PAGE_SHIFT)
-#endif /* CONFIG_MEMORY_HOTPLUG */
+#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
#define hotplug_memory_notifier(fn, pri) { \
static struct notifier_block fn##_mem_nb = \
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 218501cfaeb9..7b54666cea8e 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -172,5 +172,7 @@ static inline int __remove_pages(struct zone *zone, unsigned long start_pfn,
extern int add_memory(int nid, u64 start, u64 size);
extern int arch_add_memory(int nid, u64 start, u64 size);
extern int remove_memory(u64 start, u64 size);
+extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
+ int nr_pages);
#endif /* __LINUX_MEMORY_HOTPLUG_H */
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index 09f0f575ddff..daabb3aa1ec6 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -150,7 +150,7 @@ extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
extern void mpol_fix_fork_child_flag(struct task_struct *p);
#define set_cpuset_being_rebound(x) (cpuset_being_rebound = (x))
-#ifdef CONFIG_CPUSET
+#ifdef CONFIG_CPUSETS
#define current_cpuset_is_being_rebound() \
(cpuset_being_rebound == current->cpuset)
#else
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 856f0ee7e84a..d538de901965 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -16,6 +16,7 @@
#include <linux/mutex.h>
#include <linux/debug_locks.h>
#include <linux/backing-dev.h>
+#include <linux/mm_types.h>
struct mempolicy;
struct anon_vma;
@@ -198,6 +199,7 @@ struct vm_operations_struct {
void (*open)(struct vm_area_struct * area);
void (*close)(struct vm_area_struct * area);
struct page * (*nopage)(struct vm_area_struct * area, unsigned long address, int *type);
+ unsigned long (*nopfn)(struct vm_area_struct * area, unsigned long address);
int (*populate)(struct vm_area_struct * area, unsigned long address, unsigned long len, pgprot_t prot, unsigned long pgoff, int nonblock);
/* notification that a previously read-only page is about to become
@@ -215,62 +217,6 @@ struct vm_operations_struct {
struct mmu_gather;
struct inode;
-/*
- * Each physical page in the system has a struct page associated with
- * it to keep track of whatever it is we are using the page for at the
- * moment. Note that we have no way to track which tasks are using
- * a page, though if it is a pagecache page, rmap structures can tell us
- * who is mapping it.
- */
-struct page {
- unsigned long flags; /* Atomic flags, some possibly
- * updated asynchronously */
- atomic_t _count; /* Usage count, see below. */
- atomic_t _mapcount; /* Count of ptes mapped in mms,
- * to show when page is mapped
- * & limit reverse map searches.
- */
- union {
- struct {
- unsigned long private; /* Mapping-private opaque data:
- * usually used for buffer_heads
- * if PagePrivate set; used for
- * swp_entry_t if PageSwapCache;
- * indicates order in the buddy
- * system if PG_buddy is set.
- */
- struct address_space *mapping; /* If low bit clear, points to
- * inode address_space, or NULL.
- * If page mapped as anonymous
- * memory, low bit is set, and
- * it points to anon_vma object:
- * see PAGE_MAPPING_ANON below.
- */
- };
-#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
- spinlock_t ptl;
-#endif
- };
- pgoff_t index; /* Our offset within mapping. */
- struct list_head lru; /* Pageout list, eg. active_list
- * protected by zone->lru_lock !
- */
- /*
- * On machines where all RAM is mapped into kernel address space,
- * we can simply calculate the virtual address. On machines with
- * highmem some memory is mapped into kernel virtual memory
- * dynamically, so we need a place to store that address.
- * Note that this field could be 16 bits on x86 ... ;)
- *
- * Architectures with slow multiplication can define
- * WANT_PAGE_VIRTUAL in asm/page.h
- */
-#if defined(WANT_PAGE_VIRTUAL)
- void *virtual; /* Kernel virtual address (NULL if
- not kmapped, ie. highmem) */
-#endif /* WANT_PAGE_VIRTUAL */
-};
-
#define page_private(page) ((page)->private)
#define set_page_private(page, v) ((page)->private = (v))
@@ -501,7 +447,11 @@ static inline struct zone *page_zone(struct page *page)
static inline unsigned long zone_to_nid(struct zone *zone)
{
- return zone->zone_pgdat->node_id;
+#ifdef CONFIG_NUMA
+ return zone->node;
+#else
+ return 0;
+#endif
}
static inline unsigned long page_to_nid(struct page *page)
@@ -546,11 +496,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
*/
#include <linux/vmstat.h>
-#ifndef CONFIG_DISCONTIGMEM
-/* The array of struct pages - for discontigmem use pgdat->lmem_map */
-extern struct page *mem_map;
-#endif
-
static __always_inline void *lowmem_page_address(struct page *page)
{
return __va(page_to_pfn(page) << PAGE_SHIFT);
@@ -648,6 +593,13 @@ static inline int page_mapped(struct page *page)
*/
#define NOPAGE_SIGBUS (NULL)
#define NOPAGE_OOM ((struct page *) (-1))
+#define NOPAGE_REFAULT ((struct page *) (-2)) /* Return to userspace, rerun */
+
+/*
+ * Error return values for the *_nopfn functions
+ */
+#define NOPFN_SIGBUS ((unsigned long) -1)
+#define NOPFN_OOM ((unsigned long) -2)
/*
* Different kinds of faults, as returned by handle_mm_fault().
@@ -792,7 +744,9 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long
int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
void print_bad_pte(struct vm_area_struct *, pte_t, unsigned long);
-int __set_page_dirty_buffers(struct page *page);
+extern int try_to_release_page(struct page * page, gfp_t gfp_mask);
+extern void do_invalidatepage(struct page *page, unsigned long offset);
+
int __set_page_dirty_nobuffers(struct page *page);
int redirty_page_for_writepage(struct writeback_control *wbc,
struct page *page);
@@ -937,12 +891,64 @@ extern void free_area_init(unsigned long * zones_size);
extern void free_area_init_node(int nid, pg_data_t *pgdat,
unsigned long * zones_size, unsigned long zone_start_pfn,
unsigned long *zholes_size);
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+/*
+ * With CONFIG_ARCH_POPULATES_NODE_MAP set, an architecture may initialise its
+ * zones, allocate the backing mem_map and account for memory holes in a more
+ * architecture independent manner. This is a substitute for creating the
+ * zone_sizes[] and zholes_size[] arrays and passing them to
+ * free_area_init_node()
+ *
+ * An architecture is expected to register range of page frames backed by
+ * physical memory with add_active_range() before calling
+ * free_area_init_nodes() passing in the PFN each zone ends at. At a basic
+ * usage, an architecture is expected to do something like
+ *
+ * unsigned long max_zone_pfns[MAX_NR_ZONES] = {max_dma, max_normal_pfn,
+ * max_highmem_pfn};
+ * for_each_valid_physical_page_range()
+ * add_active_range(node_id, start_pfn, end_pfn)
+ * free_area_init_nodes(max_zone_pfns);
+ *
+ * If the architecture guarantees that there are no holes in the ranges
+ * registered with add_active_range(), free_bootmem_active_regions()
+ * will call free_bootmem_node() for each registered physical page range.
+ * Similarly sparse_memory_present_with_active_regions() calls
+ * memory_present() for each range when SPARSEMEM is enabled.
+ *
+ * See mm/page_alloc.c for more information on each function exposed by
+ * CONFIG_ARCH_POPULATES_NODE_MAP
+ */
+extern void free_area_init_nodes(unsigned long *max_zone_pfn);
+extern void add_active_range(unsigned int nid, unsigned long start_pfn,
+ unsigned long end_pfn);
+extern void shrink_active_range(unsigned int nid, unsigned long old_end_pfn,
+ unsigned long new_end_pfn);
+extern void push_node_boundaries(unsigned int nid, unsigned long start_pfn,
+ unsigned long end_pfn);
+extern void remove_all_active_ranges(void);
+extern unsigned long absent_pages_in_range(unsigned long start_pfn,
+ unsigned long end_pfn);
+extern void get_pfn_range_for_nid(unsigned int nid,
+ unsigned long *start_pfn, unsigned long *end_pfn);
+extern unsigned long find_min_pfn_with_active_regions(void);
+extern unsigned long find_max_pfn_with_active_regions(void);
+extern void free_bootmem_with_active_regions(int nid,
+ unsigned long max_low_pfn);
+extern void sparse_memory_present_with_active_regions(int nid);
+#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
+extern int early_pfn_to_nid(unsigned long pfn);
+#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
+#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
+extern void set_dma_reserve(unsigned long new_dma_reserve);
extern void memmap_init_zone(unsigned long, int, unsigned long, unsigned long);
extern void setup_per_zone_pages_min(void);
extern void mem_init(void);
extern void show_mem(void);
extern void si_meminfo(struct sysinfo * val);
extern void si_meminfo_node(struct sysinfo *val, int nid);
+extern void zonetable_add(struct zone *zone, int nid, enum zone_type zid,
+ unsigned long pfn, unsigned long size);
#ifdef CONFIG_NUMA
extern void setup_per_cpu_pageset(void);
@@ -1097,12 +1103,7 @@ static inline void vm_stat_account(struct mm_struct *mm,
#ifndef CONFIG_DEBUG_PAGEALLOC
static inline void
-kernel_map_pages(struct page *page, int numpages, int enable)
-{
- if (!PageHighMem(page) && !enable)
- debug_check_no_locks_freed(page_address(page),
- numpages * PAGE_SIZE);
-}
+kernel_map_pages(struct page *page, int numpages, int enable) {}
#endif
extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk);
@@ -1114,9 +1115,6 @@ int in_gate_area_no_task(unsigned long addr);
#define in_gate_area(task, addr) ({(void)task; in_gate_area_no_task(addr);})
#endif /* __HAVE_ARCH_GATE_AREA */
-/* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
-#define OOM_DISABLE -17
-
int drop_caches_sysctl_handler(struct ctl_table *, int, struct file *,
void __user *, size_t *, loff_t *);
unsigned long shrink_slab(unsigned long scanned, gfp_t gfp_mask,
@@ -1130,7 +1128,7 @@ void drop_slab(void);
extern int randomize_va_space;
#endif
-const char *arch_vma_name(struct vm_area_struct *vma);
+__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma);
#endif /* __KERNEL__ */
#endif /* _LINUX_MM_H */
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
new file mode 100644
index 000000000000..c3852fd4a1cc
--- /dev/null
+++ b/include/linux/mm_types.h
@@ -0,0 +1,67 @@
+#ifndef _LINUX_MM_TYPES_H
+#define _LINUX_MM_TYPES_H
+
+#include <linux/types.h>
+#include <linux/threads.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+struct address_space;
+
+/*
+ * Each physical page in the system has a struct page associated with
+ * it to keep track of whatever it is we are using the page for at the
+ * moment. Note that we have no way to track which tasks are using
+ * a page, though if it is a pagecache page, rmap structures can tell us
+ * who is mapping it.
+ */
+struct page {
+ unsigned long flags; /* Atomic flags, some possibly
+ * updated asynchronously */
+ atomic_t _count; /* Usage count, see below. */
+ atomic_t _mapcount; /* Count of ptes mapped in mms,
+ * to show when page is mapped
+ * & limit reverse map searches.
+ */
+ union {
+ struct {
+ unsigned long private; /* Mapping-private opaque data:
+ * usually used for buffer_heads
+ * if PagePrivate set; used for
+ * swp_entry_t if PageSwapCache;
+ * indicates order in the buddy
+ * system if PG_buddy is set.
+ */
+ struct address_space *mapping; /* If low bit clear, points to
+ * inode address_space, or NULL.
+ * If page mapped as anonymous
+ * memory, low bit is set, and
+ * it points to anon_vma object:
+ * see PAGE_MAPPING_ANON below.
+ */
+ };
+#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS
+ spinlock_t ptl;
+#endif
+ };
+ pgoff_t index; /* Our offset within mapping. */
+ struct list_head lru; /* Pageout list, eg. active_list
+ * protected by zone->lru_lock !
+ */
+ /*
+ * On machines where all RAM is mapped into kernel address space,
+ * we can simply calculate the virtual address. On machines with
+ * highmem some memory is mapped into kernel virtual memory
+ * dynamically, so we need a place to store that address.
+ * Note that this field could be 16 bits on x86 ... ;)
+ *
+ * Architectures with slow multiplication can define
+ * WANT_PAGE_VIRTUAL in asm/page.h
+ */
+#if defined(WANT_PAGE_VIRTUAL)
+ void *virtual; /* Kernel virtual address (NULL if
+ not kmapped, ie. highmem) */
+#endif /* WANT_PAGE_VIRTUAL */
+};
+
+#endif /* _LINUX_MM_TYPES_H */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index ba095aebedff..587264a58d56 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -85,6 +85,8 @@ struct mmc_host {
unsigned long caps; /* Host capabilities */
#define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
+#define MMC_CAP_MULTIWRITE (1 << 1) /* Can accurately report bytes sent to card on error */
+#define MMC_CAP_BYTEBLOCK (1 << 2) /* Can do non-log2 block sizes */
/* host specific block data */
unsigned int max_seg_size; /* see blk_queue_max_segment_size */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 627e2c08ce41..a3594dfd6963 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -68,7 +68,6 @@ struct mmc_command {
struct mmc_data {
unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */
unsigned int timeout_clks; /* data timeout (in clocks) */
- unsigned int blksz_bits; /* data block size */
unsigned int blksz; /* data block size */
unsigned int blocks; /* number of blocks */
unsigned int error; /* data error */
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
index 81c3f77f652c..08dec8d9e703 100644
--- a/include/linux/mmc/protocol.h
+++ b/include/linux/mmc/protocol.h
@@ -83,6 +83,7 @@
/* Application commands */
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
+#define SD_APP_SEND_NUM_WR_BLKS 22 /* adtc R1 */
#define SD_APP_OP_COND 41 /* bcr [31:0] OCR R3 */
#define SD_APP_SEND_SCR 51 /* adtc R1 */
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 3693f1a52788..ed0762b283a9 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -58,6 +58,7 @@ enum zone_stat_item {
NR_WRITEBACK,
NR_UNSTABLE_NFS, /* NFS unstable pages */
NR_BOUNCE,
+ NR_VMSCAN_WRITE,
#ifdef CONFIG_NUMA
NUMA_HIT, /* allocated in intended node */
NUMA_MISS, /* allocated in non intended node */
@@ -167,6 +168,7 @@ struct zone {
unsigned long lowmem_reserve[MAX_NR_ZONES];
#ifdef CONFIG_NUMA
+ int node;
/*
* zone reclaim becomes active if more unmapped pages exist.
*/
@@ -305,6 +307,18 @@ struct zonelist {
struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited
};
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+struct node_active_region {
+ unsigned long start_pfn;
+ unsigned long end_pfn;
+ int nid;
+};
+#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
+
+#ifndef CONFIG_DISCONTIGMEM
+/* The array of struct pages - for discontigmem use pgdat->lmem_map */
+extern struct page *mem_map;
+#endif
/*
* The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM
@@ -518,7 +532,8 @@ extern struct zone *next_zone(struct zone *zone);
#endif
-#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
+#if !defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) && \
+ !defined(CONFIG_ARCH_POPULATES_NODE_MAP)
#define early_pfn_to_nid(nid) (0UL)
#endif
@@ -659,6 +674,12 @@ void sparse_init(void);
#define sparse_index_init(_sec, _nid) do {} while (0)
#endif /* CONFIG_SPARSEMEM */
+#ifdef CONFIG_NODES_SPAN_OTHER_NODES
+#define early_pfn_in_nid(pfn, nid) (early_pfn_to_nid(pfn) == (nid))
+#else
+#define early_pfn_in_nid(pfn, nid) (1)
+#endif
+
#ifndef early_pfn_valid
#define early_pfn_valid(pfn) (1)
#endif
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index f7ca0b09075d..e0c393cc7240 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -308,4 +308,16 @@ struct input_device_id {
kernel_ulong_t driver_info;
};
+/* EISA */
+
+#define EISA_SIG_LEN 8
+
+/* The EISA signature, in ASCII form, null terminated */
+struct eisa_device_id {
+ char sig[EISA_SIG_LEN];
+ kernel_ulong_t driver_data;
+};
+
+#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s"
+
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/module.h b/include/linux/module.h
index d4486cc2e7fe..d1d00ce8f4ed 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -232,17 +232,17 @@ enum module_state
};
/* Similar stuff for section attributes. */
-#define MODULE_SECT_NAME_LEN 32
struct module_sect_attr
{
struct module_attribute mattr;
- char name[MODULE_SECT_NAME_LEN];
+ char *name;
unsigned long address;
};
struct module_sect_attrs
{
struct attribute_group grp;
+ int nsections;
struct module_sect_attr attrs[0];
};
@@ -317,8 +317,7 @@ struct module
/* Am I unsafe to unload? */
int unsafe;
- /* Am I GPL-compatible */
- int license_gplok;
+ unsigned int taints; /* same bits as kernel:tainted */
#ifdef CONFIG_MODULE_UNLOAD
/* Reference counts */
diff --git a/include/linux/mpage.h b/include/linux/mpage.h
index 3ca880463c47..cc5fb75af78a 100644
--- a/include/linux/mpage.h
+++ b/include/linux/mpage.h
@@ -9,6 +9,7 @@
* (And no, it doesn't do the #ifdef __MPAGE_H thing, and it doesn't do
* nested includes. Get it right in the .c file).
*/
+#ifdef CONFIG_BLOCK
struct writeback_control;
typedef int (writepage_t)(struct page *page, struct writeback_control *wbc);
@@ -21,8 +22,4 @@ int mpage_writepages(struct address_space *mapping,
int mpage_writepage(struct page *page, get_block_t *get_block,
struct writeback_control *wbc);
-static inline int
-generic_writepages(struct address_space *mapping, struct writeback_control *wbc)
-{
- return mpage_writepages(mapping, wbc, NULL);
-}
+#endif
diff --git a/include/linux/mroute.h b/include/linux/mroute.h
index e05d54a90743..7da2cee8e132 100644
--- a/include/linux/mroute.h
+++ b/include/linux/mroute.h
@@ -142,7 +142,7 @@ struct vif_device
unsigned long rate_limit; /* Traffic shaping (NI) */
unsigned char threshold; /* TTL threshold */
unsigned short flags; /* Control flags */
- __u32 local,remote; /* Addresses(remote for tunnels)*/
+ __be32 local,remote; /* Addresses(remote for tunnels)*/
int link; /* Physical interface index */
};
@@ -151,8 +151,8 @@ struct vif_device
struct mfc_cache
{
struct mfc_cache *next; /* Next entry on cache line */
- __u32 mfc_mcastgrp; /* Group the entry belongs to */
- __u32 mfc_origin; /* Source of packet */
+ __be32 mfc_mcastgrp; /* Group the entry belongs to */
+ __be32 mfc_origin; /* Source of packet */
vifi_t mfc_parent; /* Source interface */
int mfc_flags; /* Flags on line */
@@ -179,9 +179,9 @@ struct mfc_cache
#define MFC_LINES 64
#ifdef __BIG_ENDIAN
-#define MFC_HASH(a,b) ((((a)>>24)^((b)>>26))&(MFC_LINES-1))
+#define MFC_HASH(a,b) (((((__force u32)(__be32)a)>>24)^(((__force u32)(__be32)b)>>26))&(MFC_LINES-1))
#else
-#define MFC_HASH(a,b) (((a)^((b)>>2))&(MFC_LINES-1))
+#define MFC_HASH(a,b) ((((__force u32)(__be32)a)^(((__force u32)(__be32)b)>>2))&(MFC_LINES-1))
#endif
#endif
@@ -213,8 +213,8 @@ struct pimreghdr
{
__u8 type;
__u8 reserved;
- __u16 csum;
- __u32 flags;
+ __be16 csum;
+ __be32 flags;
};
extern int pim_rcv_v1(struct sk_buff *);
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
index bae62d62dc3e..ce6c85815cbd 100644
--- a/include/linux/msdos_fs.h
+++ b/include/linux/msdos_fs.h
@@ -204,6 +204,7 @@ struct fat_mount_options {
unicode_xlate:1, /* create escape sequences for unhandled Unicode */
numtail:1, /* Does first alias have a numeric '~1' type tail? */
atari:1, /* Use Atari GEMDOS variation of MS-DOS fs */
+ flush:1, /* write things quickly */
nocase:1; /* Does this need case conversion? 0=need case conversion*/
};
@@ -412,6 +413,8 @@ extern int fat_sync_inode(struct inode *inode);
extern int fat_fill_super(struct super_block *sb, void *data, int silent,
struct inode_operations *fs_dir_inode_ops, int isvfat);
+extern int fat_flush_inodes(struct super_block *sb, struct inode *i1,
+ struct inode *i2);
/* fat/misc.c */
extern void fat_fs_panic(struct super_block *s, const char *fmt, ...);
extern void fat_clusters_flush(struct super_block *sb);
diff --git a/include/linux/msi.h b/include/linux/msi.h
new file mode 100644
index 000000000000..c7ef94343673
--- /dev/null
+++ b/include/linux/msi.h
@@ -0,0 +1,49 @@
+#ifndef LINUX_MSI_H
+#define LINUX_MSI_H
+
+struct msi_msg {
+ u32 address_lo; /* low 32 bits of msi message address */
+ u32 address_hi; /* high 32 bits of msi message address */
+ u32 data; /* 16 bits of msi message data */
+};
+
+/* Heper functions */
+extern void mask_msi_irq(unsigned int irq);
+extern void unmask_msi_irq(unsigned int irq);
+extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+struct msi_desc {
+ struct {
+ __u8 type : 5; /* {0: unused, 5h:MSI, 11h:MSI-X} */
+ __u8 maskbit : 1; /* mask-pending bit supported ? */
+ __u8 unused : 1;
+ __u8 is_64 : 1; /* Address size: 0=32bit 1=64bit */
+ __u8 pos; /* Location of the msi capability */
+ __u16 entry_nr; /* specific enabled entry */
+ unsigned default_irq; /* default pre-assigned irq */
+ }msi_attrib;
+
+ struct {
+ __u16 head;
+ __u16 tail;
+ }link;
+
+ void __iomem *mask_base;
+ struct pci_dev *dev;
+
+#ifdef CONFIG_PM
+ /* PM save area for MSIX address/data */
+ struct msi_msg msg_save;
+#endif
+};
+
+/*
+ * The arch hook for setup up msi irqs
+ */
+int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+void arch_teardown_msi_irq(unsigned int irq);
+
+
+#endif /* LINUX_MSI_H */
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 0b4cd2fa64aa..70420bbae82b 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -27,9 +27,17 @@
struct mtd_info;
/* Scan and identify a NAND device */
extern int nand_scan (struct mtd_info *mtd, int max_chips);
+/* Separate phases of nand_scan(), allowing board driver to intervene
+ * and override command or ECC setup according to flash type */
+extern int nand_scan_ident(struct mtd_info *mtd, int max_chips);
+extern int nand_scan_tail(struct mtd_info *mtd);
+
/* Free resources held by the NAND device */
extern void nand_release (struct mtd_info *mtd);
+/* Internal helper for board drivers which need to override command function */
+extern void nand_wait_ready(struct mtd_info *mtd);
+
/* The maximum number of NAND chips in an array */
#define NAND_MAX_CHIPS 8
@@ -178,7 +186,9 @@ typedef enum {
#define NAND_USE_FLASH_BBT 0x00010000
/* This option skips the bbt scan during initialization. */
#define NAND_SKIP_BBTSCAN 0x00020000
-
+/* This option is defined if the board driver allocates its own buffers
+ (e.g. because it needs them DMA-coherent */
+#define NAND_OWN_BUFFERS 0x00040000
/* Options set by nand scan */
/* Nand scan has allocated controller struct */
#define NAND_CONTROLLER_ALLOC 0x80000000
@@ -228,6 +238,8 @@ struct nand_hw_control {
* be provided if an hardware ECC is available
* @calculate: function for ecc calculation or readback from ecc hardware
* @correct: function for ecc correction, matching to ecc generator (sw/hw)
+ * @read_page_raw: function to read a raw page without ECC
+ * @write_page_raw: function to write a raw page without ECC
* @read_page: function to read a page according to the ecc generator requirements
* @write_page: function to write a page according to the ecc generator requirements
* @read_oob: function to read chip OOB data
@@ -249,6 +261,12 @@ struct nand_ecc_ctrl {
int (*correct)(struct mtd_info *mtd, uint8_t *dat,
uint8_t *read_ecc,
uint8_t *calc_ecc);
+ int (*read_page_raw)(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ uint8_t *buf);
+ void (*write_page_raw)(struct mtd_info *mtd,
+ struct nand_chip *chip,
+ const uint8_t *buf);
int (*read_page)(struct mtd_info *mtd,
struct nand_chip *chip,
uint8_t *buf);
@@ -337,6 +355,7 @@ struct nand_buffers {
* @priv: [OPTIONAL] pointer to private chip date
* @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
* (determine if errors are correctable)
+ * @write_page [REPLACEABLE] High-level page write function
*/
struct nand_chip {
@@ -359,6 +378,8 @@ struct nand_chip {
void (*erase_cmd)(struct mtd_info *mtd, int page);
int (*scan_bbt)(struct mtd_info *mtd);
int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
+ int (*write_page)(struct mtd_info *mtd, struct nand_chip *chip,
+ const uint8_t *buf, int page, int cached, int raw);
int chip_delay;
unsigned int options;
@@ -380,7 +401,7 @@ struct nand_chip {
struct nand_ecclayout *ecclayout;
struct nand_ecc_ctrl ecc;
- struct nand_buffers buffers;
+ struct nand_buffers *buffers;
struct nand_hw_control hwcontrol;
struct mtd_oob_ops ops;
diff --git a/include/linux/mtd/onenand.h b/include/linux/mtd/onenand.h
index 1f4972155249..6f045b586e76 100644
--- a/include/linux/mtd/onenand.h
+++ b/include/linux/mtd/onenand.h
@@ -1,7 +1,7 @@
/*
* linux/include/linux/mtd/onenand.h
*
- * Copyright (C) 2005 Samsung Electronics
+ * Copyright (C) 2005-2006 Samsung Electronics
* Kyungmin Park <kyungmin.park@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -96,6 +96,7 @@ struct onenand_chip {
void __iomem *base;
unsigned int chipsize;
unsigned int device_id;
+ unsigned int version_id;
unsigned int density_mask;
unsigned int options;
@@ -149,7 +150,8 @@ struct onenand_chip {
/*
* Options bits
*/
-#define ONENAND_CONT_LOCK (0x0001)
+#define ONENAND_HAS_CONT_LOCK (0x0001)
+#define ONENAND_HAS_UNLOCK_ALL (0x0002)
#define ONENAND_PAGEBUF_ALLOC (0x1000)
/*
diff --git a/include/linux/mtd/onenand_regs.h b/include/linux/mtd/onenand_regs.h
index 4a72818d2545..9e409fe6ded6 100644
--- a/include/linux/mtd/onenand_regs.h
+++ b/include/linux/mtd/onenand_regs.h
@@ -3,7 +3,7 @@
*
* OneNAND Register header file
*
- * Copyright (C) 2005 Samsung Electronics
+ * Copyright (C) 2005-2006 Samsung Electronics
*
* 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
@@ -72,6 +72,7 @@
#define ONENAND_DEVICE_VCC_MASK (0x3)
#define ONENAND_DEVICE_DENSITY_512Mb (0x002)
+#define ONENAND_DEVICE_DENSITY_1Gb (0x003)
/*
* Version ID Register F002h (R)
@@ -110,6 +111,7 @@
#define ONENAND_CMD_UNLOCK (0x23)
#define ONENAND_CMD_LOCK (0x2A)
#define ONENAND_CMD_LOCK_TIGHT (0x2C)
+#define ONENAND_CMD_UNLOCK_ALL (0x27)
#define ONENAND_CMD_ERASE (0x94)
#define ONENAND_CMD_RESET (0xF0)
#define ONENAND_CMD_OTP_ACCESS (0x65)
diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h
index 2332eda07e0e..9667863bd7e3 100644
--- a/include/linux/mtd/plat-ram.h
+++ b/include/linux/mtd/plat-ram.h
@@ -1,4 +1,4 @@
-/* linux/include/mtd/plat-ram.h
+/* linux/include/linux/mtd/plat-ram.h
*
* (c) 2004 Simtec Electronics
* http://www.simtec.co.uk/products/SWLINUX/
diff --git a/include/linux/namei.h b/include/linux/namei.h
index 45511a5918d3..f5f19606effb 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -1,6 +1,7 @@
#ifndef _LINUX_NAMEI_H
#define _LINUX_NAMEI_H
+#include <linux/dcache.h>
#include <linux/linkage.h>
struct vfsmount;
@@ -54,6 +55,7 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
#define LOOKUP_OPEN (0x0100)
#define LOOKUP_CREATE (0x0200)
#define LOOKUP_ACCESS (0x0400)
+#define LOOKUP_CHDIR (0x0800)
extern int FASTCALL(__user_walk(const char __user *, unsigned, struct nameidata *));
extern int FASTCALL(__user_walk_fd(int dfd, const char __user *, unsigned, struct nameidata *));
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index 3abc8e3b4879..d137009f0b2b 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -4,6 +4,7 @@
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/nsproxy.h>
struct namespace {
atomic_t count;
@@ -26,11 +27,8 @@ static inline void put_namespace(struct namespace *namespace)
static inline void exit_namespace(struct task_struct *p)
{
- struct namespace *namespace = p->namespace;
+ struct namespace *namespace = p->nsproxy->namespace;
if (namespace) {
- task_lock(p);
- p->namespace = NULL;
- task_unlock(p);
put_namespace(namespace);
}
}
diff --git a/include/linux/nbd.h b/include/linux/nbd.h
index e712e7d47cc2..d6b6dc09ad97 100644
--- a/include/linux/nbd.h
+++ b/include/linux/nbd.h
@@ -15,6 +15,8 @@
#ifndef LINUX_NBD_H
#define LINUX_NBD_H
+#include <linux/types.h>
+
#define NBD_SET_SOCK _IO( 0xab, 0 )
#define NBD_SET_BLKSIZE _IO( 0xab, 1 )
#define NBD_SET_SIZE _IO( 0xab, 2 )
diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h
index 02e352be717e..0ea7f89e613c 100644
--- a/include/linux/ncp_fs.h
+++ b/include/linux/ncp_fs.h
@@ -212,6 +212,7 @@ void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date);
/* linux/fs/ncpfs/ioctl.c */
int ncp_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+long ncp_compat_ioctl(struct file *, unsigned int, unsigned long);
/* linux/fs/ncpfs/sock.c */
int ncp_request2(struct ncp_server *server, int function,
diff --git a/include/linux/net.h b/include/linux/net.h
index c257f716e00f..15c733b816f0 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -19,6 +19,7 @@
#define _LINUX_NET_H
#include <linux/wait.h>
+#include <linux/random.h>
#include <asm/socket.h>
struct poll_table_struct;
@@ -193,9 +194,9 @@ extern int sock_map_fd(struct socket *sock);
extern struct socket *sockfd_lookup(int fd, int *err);
#define sockfd_put(sock) fput(sock->file)
extern int net_ratelimit(void);
-extern unsigned long net_random(void);
-extern void net_srandom(unsigned long);
-extern void net_random_init(void);
+
+#define net_random() random32()
+#define net_srandom(seed) srandom32(seed)
extern int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
struct kvec *vec, size_t num, size_t len);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 43289127b458..9264139bd8df 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -187,7 +187,7 @@ struct hh_cache
{
struct hh_cache *hh_next; /* Next entry */
atomic_t hh_refcnt; /* number of users */
- unsigned short hh_type; /* protocol identifier, f.e ETH_P_IP
+ __be16 hh_type; /* protocol identifier, f.e ETH_P_IP
* NOTE: For VLANs, this will be the
* encapuslated type. --BLG
*/
@@ -334,7 +334,6 @@ struct net_device
struct net_device_stats* (*get_stats)(struct net_device *dev);
- struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
/* List of functions to handle Wireless Extensions (instead of ioctl).
* See <net/iw_handler.h> for details. Jean II */
@@ -1016,7 +1015,8 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
}
/* On bonding slaves other than the currently active slave, suppress
- * duplicates except for 802.3ad ETH_P_SLOW and alb non-mcast/bcast.
+ * duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
+ * ARP on active-backup slaves with arp_validate enabled.
*/
static inline int skb_bond_should_drop(struct sk_buff *skb)
{
@@ -1025,6 +1025,10 @@ static inline int skb_bond_should_drop(struct sk_buff *skb)
if (master &&
(dev->priv_flags & IFF_SLAVE_INACTIVE)) {
+ if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
+ skb->protocol == __constant_htons(ETH_P_ARP))
+ return 0;
+
if (master->priv_flags & IFF_MASTER_ALB) {
if (skb->pkt_type != PACKET_BROADCAST &&
skb->pkt_type != PACKET_MULTICAST)
diff --git a/include/linux/netfilter_arp/arp_tables.h b/include/linux/netfilter_arp/arp_tables.h
index 149e87c9ab13..44e39b61d9e7 100644
--- a/include/linux/netfilter_arp/arp_tables.h
+++ b/include/linux/netfilter_arp/arp_tables.h
@@ -46,11 +46,11 @@ struct arpt_arp {
struct arpt_devaddr_info tgt_devaddr;
/* ARP operation code. */
- u_int16_t arpop, arpop_mask;
+ __be16 arpop, arpop_mask;
/* ARP hardware address and protocol address format. */
- u_int16_t arhrd, arhrd_mask;
- u_int16_t arpro, arpro_mask;
+ __be16 arhrd, arhrd_mask;
+ __be16 arpro, arpro_mask;
/* The protocol address length is only accepted if it is 4
* so there is no use in offering a way to do filtering on it.
diff --git a/include/linux/netfilter_bridge/ebt_mark_t.h b/include/linux/netfilter_bridge/ebt_mark_t.h
index 110fec6a40a2..6270f6f33693 100644
--- a/include/linux/netfilter_bridge/ebt_mark_t.h
+++ b/include/linux/netfilter_bridge/ebt_mark_t.h
@@ -1,6 +1,18 @@
#ifndef __LINUX_BRIDGE_EBT_MARK_T_H
#define __LINUX_BRIDGE_EBT_MARK_T_H
+/* The target member is reused for adding new actions, the
+ * value of the real target is -1 to -NUM_STANDARD_TARGETS.
+ * For backward compatibility, the 4 lsb (2 would be enough,
+ * but let's play it safe) are kept to designate this target.
+ * The remaining bits designate the action. By making the set
+ * action 0xfffffff0, the result will look ok for older
+ * versions. [September 2006] */
+#define MARK_SET_VALUE (0xfffffff0)
+#define MARK_OR_VALUE (0xffffffe0)
+#define MARK_AND_VALUE (0xffffffd0)
+#define MARK_XOR_VALUE (0xffffffc0)
+
struct ebt_mark_t_info
{
unsigned long mark;
diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
index ce02c984f3ba..5b63a231a76b 100644
--- a/include/linux/netfilter_ipv4.h
+++ b/include/linux/netfilter_ipv4.h
@@ -77,7 +77,7 @@ enum nf_ip_hook_priorities {
#define SO_ORIGINAL_DST 80
#ifdef __KERNEL__
-extern int ip_route_me_harder(struct sk_buff **pskb);
+extern int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type);
extern int ip_xfrm_me_harder(struct sk_buff **pskb);
extern unsigned int nf_ip_checksum(struct sk_buff *skb, unsigned int hook,
unsigned int dataoff, u_int8_t protocol);
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
index 51dbec1892c8..64e868034c4a 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -157,7 +157,7 @@ struct ip_conntrack_expect
unsigned int flags;
#ifdef CONFIG_IP_NF_NAT_NEEDED
- u_int32_t saved_ip;
+ __be32 saved_ip;
/* This is the original per-proto part, used to map the
* expected connection the way the recipient expects. */
union ip_conntrack_manip_proto saved_proto;
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_h323.h b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
index 3cbff7379002..943cc6a4871d 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_h323.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_h323.h
@@ -30,7 +30,7 @@ struct ip_ct_h323_master {
struct ip_conntrack_expect;
extern int get_h225_addr(unsigned char *data, TransportAddress * addr,
- u_int32_t * ip, u_int16_t * port);
+ __be32 * ip, u_int16_t * port);
extern void ip_conntrack_h245_expect(struct ip_conntrack *new,
struct ip_conntrack_expect *this);
extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
@@ -38,11 +38,11 @@ extern void ip_conntrack_q931_expect(struct ip_conntrack *new,
extern int (*set_h245_addr_hook) (struct sk_buff ** pskb,
unsigned char **data, int dataoff,
H245_TransportAddress * addr,
- u_int32_t ip, u_int16_t port);
+ __be32 ip, u_int16_t port);
extern int (*set_h225_addr_hook) (struct sk_buff ** pskb,
unsigned char **data, int dataoff,
TransportAddress * addr,
- u_int32_t ip, u_int16_t port);
+ __be32 ip, u_int16_t port);
extern int (*set_sig_addr_hook) (struct sk_buff ** pskb,
struct ip_conntrack * ct,
enum ip_conntrack_info ctinfo,
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
index 2fdabdb4c0ef..c228bde74c33 100644
--- a/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_tuple.h
@@ -23,13 +23,13 @@ union ip_conntrack_manip_proto
__be16 port;
} tcp;
struct {
- u_int16_t port;
+ __be16 port;
} udp;
struct {
- u_int16_t id;
+ __be16 id;
} icmp;
struct {
- u_int16_t port;
+ __be16 port;
} sctp;
struct {
__be16 key; /* key is 32bit, pptp only uses 16 */
@@ -39,7 +39,7 @@ union ip_conntrack_manip_proto
/* The manipulable part of the tuple. */
struct ip_conntrack_manip
{
- u_int32_t ip;
+ __be32 ip;
union ip_conntrack_manip_proto u;
};
@@ -50,22 +50,22 @@ struct ip_conntrack_tuple
/* These are the parts of the tuple which are fixed. */
struct {
- u_int32_t ip;
+ __be32 ip;
union {
/* Add other protocols here. */
u_int16_t all;
struct {
- u_int16_t port;
+ __be16 port;
} tcp;
struct {
- u_int16_t port;
+ __be16 port;
} udp;
struct {
u_int8_t type, code;
} icmp;
struct {
- u_int16_t port;
+ __be16 port;
} sctp;
struct {
__be16 key; /* key is 32bit,
diff --git a/include/linux/netfilter_ipv4/ip_nat.h b/include/linux/netfilter_ipv4/ip_nat.h
index 98f8407e4cb5..bdf553620ca1 100644
--- a/include/linux/netfilter_ipv4/ip_nat.h
+++ b/include/linux/netfilter_ipv4/ip_nat.h
@@ -33,7 +33,7 @@ struct ip_nat_range
unsigned int flags;
/* Inclusive: network order. */
- u_int32_t min_ip, max_ip;
+ __be32 min_ip, max_ip;
/* Inclusive: network order */
union ip_conntrack_manip_proto min, max;
diff --git a/include/linux/netfilter_ipv4/ip_queue.h b/include/linux/netfilter_ipv4/ip_queue.h
index aa08d68c4841..a03507f465f8 100644
--- a/include/linux/netfilter_ipv4/ip_queue.h
+++ b/include/linux/netfilter_ipv4/ip_queue.h
@@ -26,7 +26,7 @@ typedef struct ipq_packet_msg {
unsigned int hook; /* Netfilter hook we rode in on */
char indev_name[IFNAMSIZ]; /* Name of incoming interface */
char outdev_name[IFNAMSIZ]; /* Name of outgoing interface */
- unsigned short hw_protocol; /* Hardware protocol (network order) */
+ __be16 hw_protocol; /* Hardware protocol (network order) */
unsigned short hw_type; /* Hardware type */
unsigned char hw_addrlen; /* Hardware address length */
unsigned char hw_addr[8]; /* Hardware address */
diff --git a/include/linux/netfilter_ipv4/ipt_iprange.h b/include/linux/netfilter_ipv4/ipt_iprange.h
index 3ecb3bd63676..34ab0fb736e2 100644
--- a/include/linux/netfilter_ipv4/ipt_iprange.h
+++ b/include/linux/netfilter_ipv4/ipt_iprange.h
@@ -8,7 +8,7 @@
struct ipt_iprange {
/* Inclusive: network order. */
- u_int32_t min_ip, max_ip;
+ __be32 min_ip, max_ip;
};
struct ipt_iprange_info
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index 36f5bcf513b0..45228c1a1195 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -157,7 +157,7 @@ struct nfs_inode {
* This is the cookie verifier used for NFSv3 readdir
* operations
*/
- __u32 cookieverf[2];
+ __be32 cookieverf[2];
/*
* This is the list of dirty unwritten pages.
@@ -290,6 +290,7 @@ static inline int nfs_verify_change_attribute(struct inode *inode, unsigned long
* linux/fs/nfs/inode.c
*/
extern int nfs_sync_mapping(struct address_space *mapping);
+extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping);
extern void nfs_zap_caches(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
struct nfs_fattr *);
@@ -315,10 +316,6 @@ extern void nfs_end_data_update(struct inode *);
extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx);
extern void put_nfs_open_context(struct nfs_open_context *ctx);
extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, int mode);
-extern struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent,
- const struct dentry *dentry,
- struct nfs_fh *fh,
- struct nfs_fattr *fattr);
/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */
extern u32 root_nfs_parse_addr(char *name); /*__init*/
@@ -371,10 +368,12 @@ extern int nfs3_removexattr (struct dentry *, const char *name);
*/
extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
unsigned long);
-extern ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf,
- size_t count, loff_t pos);
-extern ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos);
+extern ssize_t nfs_file_direct_read(struct kiocb *iocb,
+ const struct iovec *iov, unsigned long nr_segs,
+ loff_t pos);
+extern ssize_t nfs_file_direct_write(struct kiocb *iocb,
+ const struct iovec *iov, unsigned long nr_segs,
+ loff_t pos);
/*
* linux/fs/nfs/dir.c
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index dc5397d9d23c..768c1ad5ff6f 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -266,7 +266,7 @@ struct nfs_writeargs {
struct nfs_writeverf {
enum nfs3_stable_how committed;
- __u32 verifier[2];
+ __be32 verifier[2];
};
struct nfs_writeres {
@@ -420,7 +420,7 @@ struct nfs3_createargs {
unsigned int len;
struct iattr * sattr;
enum nfs3_createmode createmode;
- __u32 verifier[2];
+ __be32 verifier[2];
};
struct nfs3_mkdirargs {
@@ -467,7 +467,7 @@ struct nfs3_linkargs {
struct nfs3_readdirargs {
struct nfs_fh * fh;
__u64 cookie;
- __u32 verf[2];
+ __be32 verf[2];
int plus;
unsigned int count;
struct page ** pages;
@@ -503,7 +503,7 @@ struct nfs3_linkres {
struct nfs3_readdirres {
struct nfs_fattr * dir_attr;
- __u32 * verf;
+ __be32 * verf;
int plus;
};
@@ -811,7 +811,7 @@ struct nfs_rpc_ops {
int (*pathconf) (struct nfs_server *, struct nfs_fh *,
struct nfs_pathconf *);
int (*set_capabilities)(struct nfs_server *, struct nfs_fh *);
- u32 * (*decode_dirent)(u32 *, struct nfs_entry *, int plus);
+ __be32 *(*decode_dirent)(__be32 *, struct nfs_entry *, int plus);
void (*read_setup) (struct nfs_read_data *);
int (*read_done) (struct rpc_task *, struct nfs_read_data *);
void (*write_setup) (struct nfs_write_data *, int how);
diff --git a/include/linux/nfsd/cache.h b/include/linux/nfsd/cache.h
index c3a3557c2a5b..007480cd6a60 100644
--- a/include/linux/nfsd/cache.h
+++ b/include/linux/nfsd/cache.h
@@ -26,14 +26,14 @@ struct svc_cacherep {
c_type, /* status, buffer */
c_secure : 1; /* req came from port < 1024 */
struct sockaddr_in c_addr;
- u32 c_xid;
+ __be32 c_xid;
u32 c_prot;
u32 c_proc;
u32 c_vers;
unsigned long c_timestamp;
union {
struct kvec u_vec;
- u32 u_status;
+ __be32 u_status;
} c_u;
};
@@ -75,7 +75,7 @@ enum {
void nfsd_cache_init(void);
void nfsd_cache_shutdown(void);
int nfsd_cache_lookup(struct svc_rqst *, int);
-void nfsd_cache_update(struct svc_rqst *, int, u32 *);
+void nfsd_cache_update(struct svc_rqst *, int, __be32 *);
#endif /* __KERNEL__ */
#endif /* NFSCACHE_H */
diff --git a/include/linux/nfsd/const.h b/include/linux/nfsd/const.h
index b75bb1b38d09..f0cc77790527 100644
--- a/include/linux/nfsd/const.h
+++ b/include/linux/nfsd/const.h
@@ -20,17 +20,31 @@
#define NFSSVC_MAXVERS 3
/*
- * Maximum blocksize supported by daemon currently at 32K
+ * Maximum blocksizes supported by daemon under various circumstances.
*/
-#define NFSSVC_MAXBLKSIZE (32*1024)
+#define NFSSVC_MAXBLKSIZE RPCSVC_MAXPAYLOAD
+/* NFSv2 is limited by the protocol specification, see RFC 1094 */
+#define NFSSVC_MAXBLKSIZE_V2 (8*1024)
#ifdef __KERNEL__
+#include <linux/sunrpc/msg_prot.h>
+
#ifndef NFS_SUPER_MAGIC
# define NFS_SUPER_MAGIC 0x6969
#endif
-#define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE)
+/*
+ * Largest number of bytes we need to allocate for an NFS
+ * call or reply. Used to control buffer sizes. We use
+ * the length of v3 WRITE, READDIR and READDIR replies
+ * which are an RPC header, up to 26 XDR units of reply
+ * data, and some page data.
+ *
+ * Note that accuracy here doesn't matter too much as the
+ * size is rounded up to a page size when allocating space.
+ */
+#define NFSD_BUFSIZE ((RPC_MAX_HEADER_WITH_AUTH+26)*XDR_UNIT + NFSSVC_MAXBLKSIZE)
#ifdef CONFIG_NFSD_V4
# define NFSSVC_XDRSIZE NFS4_SVC_XDRSIZE
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index d2a8abb5011a..045e38cdbe64 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -45,15 +45,36 @@
#ifdef __KERNEL__
+/*
+ * FS Locations
+ */
+
+#define MAX_FS_LOCATIONS 128
+
+struct nfsd4_fs_location {
+ char *hosts; /* colon separated list of hosts */
+ char *path; /* slash separated list of path components */
+};
+
+struct nfsd4_fs_locations {
+ uint32_t locations_count;
+ struct nfsd4_fs_location *locations;
+/* If we're not actually serving this data ourselves (only providing a
+ * list of replicas that do serve it) then we set "migrated": */
+ int migrated;
+};
+
struct svc_export {
struct cache_head h;
struct auth_domain * ex_client;
int ex_flags;
struct vfsmount * ex_mnt;
struct dentry * ex_dentry;
+ char * ex_path;
uid_t ex_anon_uid;
gid_t ex_anon_gid;
int ex_fsid;
+ struct nfsd4_fs_locations ex_fslocs;
};
/* an "export key" (expkey) maps a filehandlefragement to an
@@ -96,8 +117,8 @@ struct svc_export * exp_parent(struct auth_domain *clp,
struct cache_req *reqp);
int exp_rootfh(struct auth_domain *,
char *path, struct knfsd_fh *, int maxsize);
-int exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
-int nfserrno(int errno);
+__be32 exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
+__be32 nfserrno(int errno);
extern struct cache_detail svc_export_cache;
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 2dcad295fece..eb231143d579 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -50,7 +50,7 @@
* Callback function for readdir
*/
struct readdir_cd {
- int err; /* 0, nfserr, or nfserr_eof */
+ __be32 err; /* 0, nfserr, or nfserr_eof */
};
typedef int (*encode_dent_fn)(struct readdir_cd *, const char *,
int, loff_t, ino_t, unsigned int);
@@ -64,7 +64,7 @@ extern struct svc_serv *nfsd_serv;
* Function prototypes.
*/
int nfsd_svc(unsigned short port, int nrservs);
-int nfsd_dispatch(struct svc_rqst *rqstp, u32 *statp);
+int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);
/* nfsd/vfs.c */
int fh_lock_parent(struct svc_fh *, struct dentry *);
@@ -72,57 +72,57 @@ int nfsd_racache_init(int);
void nfsd_racache_shutdown(void);
int nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
struct svc_export **expp);
-int nfsd_lookup(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_lookup(struct svc_rqst *, struct svc_fh *,
const char *, int, struct svc_fh *);
-int nfsd_setattr(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_setattr(struct svc_rqst *, struct svc_fh *,
struct iattr *, int, time_t);
#ifdef CONFIG_NFSD_V4
-int nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
struct nfs4_acl *);
int nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
#endif /* CONFIG_NFSD_V4 */
-int nfsd_create(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
int type, dev_t rdev, struct svc_fh *res);
#ifdef CONFIG_NFSD_V3
-int nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
-int nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *, u32 *);
+__be32 nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
char *name, int len, struct iattr *attrs,
struct svc_fh *res, int createmode,
u32 *verifier, int *truncp);
-int nfsd_commit(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_commit(struct svc_rqst *, struct svc_fh *,
loff_t, unsigned long);
#endif /* CONFIG_NFSD_V3 */
-int nfsd_open(struct svc_rqst *, struct svc_fh *, int,
+__be32 nfsd_open(struct svc_rqst *, struct svc_fh *, int,
int, struct file **);
void nfsd_close(struct file *);
-int nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
+__be32 nfsd_read(struct svc_rqst *, struct svc_fh *, struct file *,
loff_t, struct kvec *, int, unsigned long *);
-int nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
+__be32 nfsd_write(struct svc_rqst *, struct svc_fh *,struct file *,
loff_t, struct kvec *,int, unsigned long, int *);
-int nfsd_readlink(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
char *, int *);
-int nfsd_symlink(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
char *name, int len, char *path, int plen,
struct svc_fh *res, struct iattr *);
-int nfsd_link(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_link(struct svc_rqst *, struct svc_fh *,
char *, int, struct svc_fh *);
-int nfsd_rename(struct svc_rqst *,
+__be32 nfsd_rename(struct svc_rqst *,
struct svc_fh *, char *, int,
struct svc_fh *, char *, int);
-int nfsd_remove(struct svc_rqst *,
+__be32 nfsd_remove(struct svc_rqst *,
struct svc_fh *, char *, int);
-int nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
+__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
char *name, int len);
int nfsd_truncate(struct svc_rqst *, struct svc_fh *,
unsigned long size);
-int nfsd_readdir(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
loff_t *, struct readdir_cd *, encode_dent_fn);
-int nfsd_statfs(struct svc_rqst *, struct svc_fh *,
+__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct kstatfs *);
int nfsd_notify_change(struct inode *, struct iattr *);
-int nfsd_permission(struct svc_export *, struct dentry *, int);
+__be32 nfsd_permission(struct svc_export *, struct dentry *, int);
int nfsd_sync_dir(struct dentry *dp);
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
@@ -140,6 +140,12 @@ struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
#endif
+enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
+int nfsd_vers(int vers, enum vers_op change);
+void nfsd_reset_versions(void);
+int nfsd_create_serv(void);
+
+extern int nfsd_max_blksize;
/*
* NFSv4 State
@@ -210,6 +216,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_clid_inuse __constant_htonl(NFSERR_CLID_INUSE)
#define nfserr_stale_clientid __constant_htonl(NFSERR_STALE_CLIENTID)
#define nfserr_resource __constant_htonl(NFSERR_RESOURCE)
+#define nfserr_moved __constant_htonl(NFSERR_MOVED)
#define nfserr_nofilehandle __constant_htonl(NFSERR_NOFILEHANDLE)
#define nfserr_minor_vers_mismatch __constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
#define nfserr_share_denied __constant_htonl(NFSERR_SHARE_DENIED)
@@ -231,6 +238,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_badname __constant_htonl(NFSERR_BADNAME)
#define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN)
#define nfserr_locked __constant_htonl(NFSERR_LOCKED)
+#define nfserr_replay_me __constant_htonl(NFSERR_REPLAY_ME)
/* error codes for internal use */
/* if a request fails due to kmalloc failure, it gets dropped.
@@ -286,7 +294,6 @@ static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh)
/*
* The following attributes are currently not supported by the NFSv4 server:
* ARCHIVE (deprecated anyway)
- * FS_LOCATIONS (will be supported eventually)
* HIDDEN (unlikely to be supported any time soon)
* MIMETYPE (unlikely to be supported any time soon)
* QUOTA_* (will be supported in a forthcoming patch)
@@ -302,7 +309,7 @@ static inline int is_fsid(struct svc_fh *fh, struct knfsd_fh *reffh)
| FATTR4_WORD0_ACLSUPPORT | FATTR4_WORD0_CANSETTIME | FATTR4_WORD0_CASE_INSENSITIVE \
| FATTR4_WORD0_CASE_PRESERVING | FATTR4_WORD0_CHOWN_RESTRICTED \
| FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FILEID | FATTR4_WORD0_FILES_AVAIL \
- | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_HOMOGENEOUS \
+ | FATTR4_WORD0_FILES_FREE | FATTR4_WORD0_FILES_TOTAL | FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_HOMOGENEOUS \
| FATTR4_WORD0_MAXFILESIZE | FATTR4_WORD0_MAXLINK | FATTR4_WORD0_MAXNAME \
| FATTR4_WORD0_MAXREAD | FATTR4_WORD0_MAXWRITE | FATTR4_WORD0_ACL)
diff --git a/include/linux/nfsd/nfsfh.h b/include/linux/nfsd/nfsfh.h
index f9edcd2ff3c8..f3b51d62ec7d 100644
--- a/include/linux/nfsd/nfsfh.h
+++ b/include/linux/nfsd/nfsfh.h
@@ -157,7 +157,7 @@ typedef struct svc_fh {
__u64 fh_post_size; /* i_size */
unsigned long fh_post_blocks; /* i_blocks */
unsigned long fh_post_blksize;/* i_blksize */
- __u32 fh_post_rdev[2];/* i_rdev */
+ __be32 fh_post_rdev[2];/* i_rdev */
struct timespec fh_post_atime; /* i_atime */
struct timespec fh_post_mtime; /* i_mtime */
struct timespec fh_post_ctime; /* i_ctime */
@@ -209,9 +209,9 @@ extern char * SVCFH_fmt(struct svc_fh *fhp);
/*
* Function prototypes
*/
-u32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
-int fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
-int fh_update(struct svc_fh *);
+__be32 fh_verify(struct svc_rqst *, struct svc_fh *, int, int);
+__be32 fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
+__be32 fh_update(struct svc_fh *);
void fh_put(struct svc_fh *);
static __inline__ struct svc_fh *
@@ -269,14 +269,8 @@ fill_post_wcc(struct svc_fh *fhp)
fhp->fh_post_uid = inode->i_uid;
fhp->fh_post_gid = inode->i_gid;
fhp->fh_post_size = inode->i_size;
- if (inode->i_blksize) {
- fhp->fh_post_blksize = inode->i_blksize;
- fhp->fh_post_blocks = inode->i_blocks;
- } else {
- fhp->fh_post_blksize = BLOCK_SIZE;
- /* how much do we care for accuracy with MinixFS? */
- fhp->fh_post_blocks = (inode->i_size+511) >> 9;
- }
+ fhp->fh_post_blksize = BLOCK_SIZE;
+ fhp->fh_post_blocks = inode->i_blocks;
fhp->fh_post_rdev[0] = htonl((u32)imajor(inode));
fhp->fh_post_rdev[1] = htonl((u32)iminor(inode));
fhp->fh_post_atime = inode->i_atime;
@@ -296,8 +290,9 @@ fill_post_wcc(struct svc_fh *fhp)
* vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
* so, any changes here should be reflected there.
*/
+
static inline void
-fh_lock(struct svc_fh *fhp)
+fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
{
struct dentry *dentry = fhp->fh_dentry;
struct inode *inode;
@@ -316,11 +311,17 @@ fh_lock(struct svc_fh *fhp)
}
inode = dentry->d_inode;
- mutex_lock(&inode->i_mutex);
+ mutex_lock_nested(&inode->i_mutex, subclass);
fill_pre_wcc(fhp);
fhp->fh_locked = 1;
}
+static inline void
+fh_lock(struct svc_fh *fhp)
+{
+ fh_lock_nested(fhp, I_MUTEX_NORMAL);
+}
+
/*
* Unlock a file handle/inode
*/
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index 8bf23cf8b603..c3673f487e84 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -125,7 +125,7 @@ struct nfs4_client {
char cl_recdir[HEXDIR_LEN]; /* recovery dir */
nfs4_verifier cl_verifier; /* generated by client */
time_t cl_time; /* time of last lease renewal */
- u32 cl_addr; /* client ipaddress */
+ __be32 cl_addr; /* client ipaddress */
struct svc_cred cl_cred; /* setclientid principal */
clientid_t cl_clientid; /* generated by server */
nfs4_verifier cl_confirm; /* generated by server */
@@ -164,7 +164,7 @@ update_stateid(stateid_t *stateid)
* is cached.
*/
struct nfs4_replay {
- u32 rp_status;
+ __be32 rp_status;
unsigned int rp_buflen;
char *rp_buf;
unsigned intrp_allocated;
@@ -273,19 +273,19 @@ struct nfs4_stateid {
((err) != nfserr_stale_stateid) && \
((err) != nfserr_bad_stateid))
-extern int nfsd4_renew(clientid_t *clid);
-extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh,
+extern __be32 nfsd4_renew(clientid_t *clid);
+extern __be32 nfs4_preprocess_stateid_op(struct svc_fh *current_fh,
stateid_t *stateid, int flags, struct file **filp);
extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void);
extern int nfs4_in_grace(void);
-extern int nfs4_check_open_reclaim(clientid_t *clid);
+extern __be32 nfs4_check_open_reclaim(clientid_t *clid);
extern void put_nfs4_client(struct nfs4_client *clp);
extern void nfs4_free_stateowner(struct kref *kref);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
-extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
+extern __be32 nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
extern void nfsd4_init_recdir(char *recdir_name);
extern int nfsd4_recdir_load(void);
extern void nfsd4_shutdown_recdir(void);
diff --git a/include/linux/nfsd/stats.h b/include/linux/nfsd/stats.h
index 28a82fdd922f..7678cfbe9960 100644
--- a/include/linux/nfsd/stats.h
+++ b/include/linux/nfsd/stats.h
@@ -1,5 +1,5 @@
/*
- * linux/include/nfsd/stats.h
+ * linux/include/linux/nfsd/stats.h
*
* Statistics for NFS server.
*
diff --git a/include/linux/nfsd/syscall.h b/include/linux/nfsd/syscall.h
index dae0faea2807..8bcddccb6c42 100644
--- a/include/linux/nfsd/syscall.h
+++ b/include/linux/nfsd/syscall.h
@@ -38,21 +38,6 @@
#define NFSCTL_GETFD 7 /* get an fh by path (used by mountd) */
#define NFSCTL_GETFS 8 /* get an fh by path with max FH len */
-/*
- * Macros used to set version
- */
-#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << (_v)))
-#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v)))
-#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << (_v)))
-
-#if defined(CONFIG_NFSD_V4)
-#define NFSCTL_VERALL (0x1c /* 0b011100 */)
-#elif defined(CONFIG_NFSD_V3)
-#define NFSCTL_VERALL (0x0c /* 0b001100 */)
-#else
-#define NFSCTL_VERALL (0x04 /* 0b000100 */)
-#endif
-
/* SVC */
struct nfsctl_svc {
unsigned short svc_port;
@@ -134,8 +119,6 @@ extern int exp_delclient(struct nfsctl_client *ncp);
extern int exp_export(struct nfsctl_export *nxp);
extern int exp_unexport(struct nfsctl_export *nxp);
-extern unsigned int nfsd_versbits;
-
#endif /* __KERNEL__ */
#endif /* NFSD_SYSCALL_H */
diff --git a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
index 3f4f7142bbe3..877192d3ae79 100644
--- a/include/linux/nfsd/xdr.h
+++ b/include/linux/nfsd/xdr.h
@@ -1,5 +1,5 @@
/*
- * linux/inxlude/linux/nfsd/xdr.h
+ * linux/include/linux/nfsd/xdr.h
*
* XDR types for nfsd. This is mainly a typing exercise.
*/
@@ -30,7 +30,6 @@ struct nfsd_readargs {
struct svc_fh fh;
__u32 offset;
__u32 count;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
@@ -38,7 +37,6 @@ struct nfsd_writeargs {
svc_fh fh;
__u32 offset;
int len;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
@@ -83,7 +81,7 @@ struct nfsd_readdirargs {
struct svc_fh fh;
__u32 cookie;
__u32 count;
- u32 * buffer;
+ __be32 * buffer;
};
struct nfsd_attrstat {
@@ -110,9 +108,9 @@ struct nfsd_readdirres {
int count;
struct readdir_cd common;
- u32 * buffer;
+ __be32 * buffer;
int buflen;
- u32 * offset;
+ __be32 * offset;
};
struct nfsd_statfsres {
@@ -137,43 +135,43 @@ union nfsd_xdrstore {
#define NFS2_SVC_XDRSIZE sizeof(union nfsd_xdrstore)
-int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
-int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
-int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_void(struct svc_rqst *, __be32 *, void *);
+int nfssvc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
+int nfssvc_decode_sattrargs(struct svc_rqst *, __be32 *,
struct nfsd_sattrargs *);
-int nfssvc_decode_diropargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_diropargs(struct svc_rqst *, __be32 *,
struct nfsd_diropargs *);
-int nfssvc_decode_readargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_readargs(struct svc_rqst *, __be32 *,
struct nfsd_readargs *);
-int nfssvc_decode_writeargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_writeargs(struct svc_rqst *, __be32 *,
struct nfsd_writeargs *);
-int nfssvc_decode_createargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_createargs(struct svc_rqst *, __be32 *,
struct nfsd_createargs *);
-int nfssvc_decode_renameargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_renameargs(struct svc_rqst *, __be32 *,
struct nfsd_renameargs *);
-int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_readlinkargs(struct svc_rqst *, __be32 *,
struct nfsd_readlinkargs *);
-int nfssvc_decode_linkargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *,
struct nfsd_linkargs *);
-int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *,
struct nfsd_symlinkargs *);
-int nfssvc_decode_readdirargs(struct svc_rqst *, u32 *,
+int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *,
struct nfsd_readdirargs *);
-int nfssvc_encode_void(struct svc_rqst *, u32 *, void *);
-int nfssvc_encode_attrstat(struct svc_rqst *, u32 *, struct nfsd_attrstat *);
-int nfssvc_encode_diropres(struct svc_rqst *, u32 *, struct nfsd_diropres *);
-int nfssvc_encode_readlinkres(struct svc_rqst *, u32 *, struct nfsd_readlinkres *);
-int nfssvc_encode_readres(struct svc_rqst *, u32 *, struct nfsd_readres *);
-int nfssvc_encode_statfsres(struct svc_rqst *, u32 *, struct nfsd_statfsres *);
-int nfssvc_encode_readdirres(struct svc_rqst *, u32 *, struct nfsd_readdirres *);
+int nfssvc_encode_void(struct svc_rqst *, __be32 *, void *);
+int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *, struct nfsd_attrstat *);
+int nfssvc_encode_diropres(struct svc_rqst *, __be32 *, struct nfsd_diropres *);
+int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *, struct nfsd_readlinkres *);
+int nfssvc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd_readres *);
+int nfssvc_encode_statfsres(struct svc_rqst *, __be32 *, struct nfsd_statfsres *);
+int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *, struct nfsd_readdirres *);
int nfssvc_encode_entry(struct readdir_cd *, const char *name,
int namlen, loff_t offset, ino_t ino, unsigned int);
-int nfssvc_release_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
+int nfssvc_release_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
/* Helper functions for NFSv2 ACL code */
-u32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp);
-u32 *nfs2svc_decode_fh(u32 *p, struct svc_fh *fhp);
+__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp);
+__be32 *nfs2svc_decode_fh(__be32 *p, struct svc_fh *fhp);
#endif /* LINUX_NFSD_H */
diff --git a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
index a4322741f8b9..79963867b0d7 100644
--- a/include/linux/nfsd/xdr3.h
+++ b/include/linux/nfsd/xdr3.h
@@ -33,7 +33,6 @@ struct nfsd3_readargs {
struct svc_fh fh;
__u64 offset;
__u32 count;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
@@ -43,7 +42,6 @@ struct nfsd3_writeargs {
__u32 count;
int stable;
__u32 len;
- struct kvec vec[RPCSVC_MAXPAGES];
int vlen;
};
@@ -53,7 +51,7 @@ struct nfsd3_createargs {
int len;
int createmode;
struct iattr attrs;
- __u32 * verf;
+ __be32 * verf;
};
struct nfsd3_mknodargs {
@@ -100,8 +98,8 @@ struct nfsd3_readdirargs {
__u64 cookie;
__u32 dircount;
__u32 count;
- __u32 * verf;
- u32 * buffer;
+ __be32 * verf;
+ __be32 * buffer;
};
struct nfsd3_commitargs {
@@ -124,79 +122,79 @@ struct nfsd3_setaclargs {
};
struct nfsd3_attrstat {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
struct kstat stat;
};
/* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */
struct nfsd3_diropres {
- __u32 status;
+ __be32 status;
struct svc_fh dirfh;
struct svc_fh fh;
};
struct nfsd3_accessres {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
__u32 access;
};
struct nfsd3_readlinkres {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
__u32 len;
};
struct nfsd3_readres {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
unsigned long count;
int eof;
};
struct nfsd3_writeres {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
unsigned long count;
int committed;
};
struct nfsd3_renameres {
- __u32 status;
+ __be32 status;
struct svc_fh ffh;
struct svc_fh tfh;
};
struct nfsd3_linkres {
- __u32 status;
+ __be32 status;
struct svc_fh tfh;
struct svc_fh fh;
};
struct nfsd3_readdirres {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
int count;
- __u32 verf[2];
+ __be32 verf[2];
struct readdir_cd common;
- u32 * buffer;
+ __be32 * buffer;
int buflen;
- u32 * offset;
- u32 * offset1;
+ __be32 * offset;
+ __be32 * offset1;
struct svc_rqst * rqstp;
};
struct nfsd3_fsstatres {
- __u32 status;
+ __be32 status;
struct kstatfs stats;
__u32 invarsec;
};
struct nfsd3_fsinfores {
- __u32 status;
+ __be32 status;
__u32 f_rtmax;
__u32 f_rtpref;
__u32 f_rtmult;
@@ -209,7 +207,7 @@ struct nfsd3_fsinfores {
};
struct nfsd3_pathconfres {
- __u32 status;
+ __be32 status;
__u32 p_link_max;
__u32 p_name_max;
__u32 p_no_trunc;
@@ -219,12 +217,12 @@ struct nfsd3_pathconfres {
};
struct nfsd3_commitres {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
};
struct nfsd3_getaclres {
- __u32 status;
+ __be32 status;
struct svc_fh fh;
int mask;
struct posix_acl *acl_access;
@@ -268,70 +266,70 @@ union nfsd3_xdrstore {
#define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
-int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
-int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *, struct nfsd_fhandle *);
+int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *,
struct nfsd3_sattrargs *);
-int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *,
struct nfsd3_diropargs *);
-int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_accessargs(struct svc_rqst *, __be32 *,
struct nfsd3_accessargs *);
-int nfs3svc_decode_readargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readargs(struct svc_rqst *, __be32 *,
struct nfsd3_readargs *);
-int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_writeargs(struct svc_rqst *, __be32 *,
struct nfsd3_writeargs *);
-int nfs3svc_decode_createargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_createargs(struct svc_rqst *, __be32 *,
struct nfsd3_createargs *);
-int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_mkdirargs(struct svc_rqst *, __be32 *,
struct nfsd3_createargs *);
-int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_mknodargs(struct svc_rqst *, __be32 *,
struct nfsd3_mknodargs *);
-int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_renameargs(struct svc_rqst *, __be32 *,
struct nfsd3_renameargs *);
-int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readlinkargs(struct svc_rqst *, __be32 *,
struct nfsd3_readlinkargs *);
-int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_linkargs(struct svc_rqst *, __be32 *,
struct nfsd3_linkargs *);
-int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_symlinkargs(struct svc_rqst *, __be32 *,
struct nfsd3_symlinkargs *);
-int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readdirargs(struct svc_rqst *, __be32 *,
struct nfsd3_readdirargs *);
-int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readdirplusargs(struct svc_rqst *, __be32 *,
struct nfsd3_readdirargs *);
-int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *,
+int nfs3svc_decode_commitargs(struct svc_rqst *, __be32 *,
struct nfsd3_commitargs *);
-int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *);
-int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *,
+int nfs3svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
+int nfs3svc_encode_attrstat(struct svc_rqst *, __be32 *,
struct nfsd3_attrstat *);
-int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *,
+int nfs3svc_encode_wccstat(struct svc_rqst *, __be32 *,
struct nfsd3_attrstat *);
-int nfs3svc_encode_diropres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_diropres(struct svc_rqst *, __be32 *,
struct nfsd3_diropres *);
-int nfs3svc_encode_accessres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_accessres(struct svc_rqst *, __be32 *,
struct nfsd3_accessres *);
-int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_readlinkres(struct svc_rqst *, __be32 *,
struct nfsd3_readlinkres *);
-int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *);
-int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *);
-int nfs3svc_encode_createres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_readres(struct svc_rqst *, __be32 *, struct nfsd3_readres *);
+int nfs3svc_encode_writeres(struct svc_rqst *, __be32 *, struct nfsd3_writeres *);
+int nfs3svc_encode_createres(struct svc_rqst *, __be32 *,
struct nfsd3_diropres *);
-int nfs3svc_encode_renameres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_renameres(struct svc_rqst *, __be32 *,
struct nfsd3_renameres *);
-int nfs3svc_encode_linkres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_linkres(struct svc_rqst *, __be32 *,
struct nfsd3_linkres *);
-int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_readdirres(struct svc_rqst *, __be32 *,
struct nfsd3_readdirres *);
-int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_fsstatres(struct svc_rqst *, __be32 *,
struct nfsd3_fsstatres *);
-int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *,
+int nfs3svc_encode_fsinfores(struct svc_rqst *, __be32 *,
struct nfsd3_fsinfores *);
-int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_pathconfres(struct svc_rqst *, __be32 *,
struct nfsd3_pathconfres *);
-int nfs3svc_encode_commitres(struct svc_rqst *, u32 *,
+int nfs3svc_encode_commitres(struct svc_rqst *, __be32 *,
struct nfsd3_commitres *);
-int nfs3svc_release_fhandle(struct svc_rqst *, u32 *,
+int nfs3svc_release_fhandle(struct svc_rqst *, __be32 *,
struct nfsd3_attrstat *);
-int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *,
+int nfs3svc_release_fhandle2(struct svc_rqst *, __be32 *,
struct nfsd3_fhandle_pair *);
int nfs3svc_encode_entry(struct readdir_cd *, const char *name,
int namlen, loff_t offset, ino_t ino,
@@ -340,9 +338,9 @@ int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name,
int namlen, loff_t offset, ino_t ino,
unsigned int);
/* Helper functions for NFSv3 ACL code */
-u32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, u32 *p,
+__be32 *nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p,
struct svc_fh *fhp);
-u32 *nfs3svc_decode_fh(u32 *p, struct svc_fh *fhp);
+__be32 *nfs3svc_decode_fh(__be32 *p, struct svc_fh *fhp);
#endif /* _LINUX_NFSD_XDR3_H */
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index 77adba7d2281..45ca01b5f844 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -241,7 +241,6 @@ struct nfsd4_read {
stateid_t rd_stateid; /* request */
u64 rd_offset; /* request */
u32 rd_length; /* request */
- struct kvec rd_iov[RPCSVC_MAXPAGES];
int rd_vlen;
struct file *rd_filp;
@@ -259,9 +258,9 @@ struct nfsd4_readdir {
struct svc_fh * rd_fhp; /* response */
struct readdir_cd common;
- u32 * buffer;
+ __be32 * buffer;
int buflen;
- u32 * offset;
+ __be32 * offset;
};
struct nfsd4_release_lockowner {
@@ -326,7 +325,6 @@ struct nfsd4_write {
u64 wr_offset; /* request */
u32 wr_stable_how; /* request */
u32 wr_buflen; /* request */
- struct kvec wr_vec[RPCSVC_MAXPAGES]; /* request */
int wr_vlen;
u32 wr_bytes_written; /* response */
@@ -336,7 +334,7 @@ struct nfsd4_write {
struct nfsd4_op {
int opnum;
- int status;
+ __be32 status;
union {
struct nfsd4_access access;
struct nfsd4_close close;
@@ -373,12 +371,12 @@ struct nfsd4_op {
struct nfsd4_compoundargs {
/* scratch variables for XDR decode */
- u32 * p;
- u32 * end;
+ __be32 * p;
+ __be32 * end;
struct page ** pagelist;
int pagelen;
- u32 tmp[8];
- u32 * tmpp;
+ __be32 tmp[8];
+ __be32 * tmpp;
struct tmpbuf {
struct tmpbuf *next;
void (*release)(const void *);
@@ -397,15 +395,15 @@ struct nfsd4_compoundargs {
struct nfsd4_compoundres {
/* scratch variables for XDR encode */
- u32 * p;
- u32 * end;
+ __be32 * p;
+ __be32 * end;
struct xdr_buf * xbuf;
struct svc_rqst * rqstp;
u32 taglen;
char * tag;
u32 opcnt;
- u32 * tagp; /* where to encode tag and opcount */
+ __be32 * tagp; /* where to encode tag and opcount */
};
#define NFS4_SVC_XDRSIZE sizeof(struct nfsd4_compoundargs)
@@ -421,45 +419,45 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
cinfo->after_ctime_nsec = fhp->fh_post_ctime.tv_nsec;
}
-int nfs4svc_encode_voidres(struct svc_rqst *, u32 *, void *);
-int nfs4svc_decode_compoundargs(struct svc_rqst *, u32 *,
+int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *, void *);
+int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
struct nfsd4_compoundargs *);
-int nfs4svc_encode_compoundres(struct svc_rqst *, u32 *,
+int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *,
struct nfsd4_compoundres *);
void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
void nfsd4_encode_replay(struct nfsd4_compoundres *resp, struct nfsd4_op *op);
-int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
- struct dentry *dentry, u32 *buffer, int *countp,
+__be32 nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
+ struct dentry *dentry, __be32 *buffer, int *countp,
u32 *bmval, struct svc_rqst *);
-extern int nfsd4_setclientid(struct svc_rqst *rqstp,
+extern __be32 nfsd4_setclientid(struct svc_rqst *rqstp,
struct nfsd4_setclientid *setclid);
-extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
+extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
struct nfsd4_setclientid_confirm *setclientid_confirm);
-extern int nfsd4_process_open1(struct nfsd4_open *open);
-extern int nfsd4_process_open2(struct svc_rqst *rqstp,
+extern __be32 nfsd4_process_open1(struct nfsd4_open *open);
+extern __be32 nfsd4_process_open2(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open *open);
-extern int nfsd4_open_confirm(struct svc_rqst *rqstp,
+extern __be32 nfsd4_open_confirm(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open_confirm *oc,
struct nfs4_stateowner **);
-extern int nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+extern __be32 nfsd4_close(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_close *close,
struct nfs4_stateowner **replay_owner);
-extern int nfsd4_open_downgrade(struct svc_rqst *rqstp,
+extern __be32 nfsd4_open_downgrade(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_open_downgrade *od,
struct nfs4_stateowner **replay_owner);
-extern int nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+extern __be32 nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_lock *lock,
struct nfs4_stateowner **replay_owner);
-extern int nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+extern __be32 nfsd4_lockt(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_lockt *lockt);
-extern int nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh,
+extern __be32 nfsd4_locku(struct svc_rqst *rqstp, struct svc_fh *current_fh,
struct nfsd4_locku *locku,
struct nfs4_stateowner **replay_owner);
-extern int
+extern __be32
nfsd4_release_lockowner(struct svc_rqst *rqstp,
struct nfsd4_release_lockowner *rlockowner);
extern void nfsd4_release_compoundargs(struct nfsd4_compoundargs *);
-extern int nfsd4_delegreturn(struct svc_rqst *rqstp,
+extern __be32 nfsd4_delegreturn(struct svc_rqst *rqstp,
struct svc_fh *current_fh, struct nfsd4_delegreturn *dr);
#endif
diff --git a/include/linux/nmi.h b/include/linux/nmi.h
index c8f4d2f627d7..e16904e28c3a 100644
--- a/include/linux/nmi.h
+++ b/include/linux/nmi.h
@@ -4,6 +4,7 @@
#ifndef LINUX_NMI_H
#define LINUX_NMI_H
+#include <linux/sched.h>
#include <asm/irq.h>
/**
@@ -16,7 +17,7 @@
#ifdef ARCH_HAS_NMI_WATCHDOG
extern void touch_nmi_watchdog(void);
#else
-# define touch_nmi_watchdog() do { } while(0)
+# define touch_nmi_watchdog() touch_softlockup_watchdog()
#endif
#endif
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index 1a9ef3e627d1..b1063e9cdb1b 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -8,8 +8,8 @@
* See detailed comments in the file linux/bitmap.h describing the
* data type on which these nodemasks are based.
*
- * For details of nodemask_scnprintf() and nodemask_parse(),
- * see bitmap_scnprintf() and bitmap_parse() in lib/bitmap.c.
+ * For details of nodemask_scnprintf() and nodemask_parse_user(),
+ * see bitmap_scnprintf() and bitmap_parse_user() in lib/bitmap.c.
* For details of nodelist_scnprintf() and nodelist_parse(), see
* bitmap_scnlistprintf() and bitmap_parselist(), also in bitmap.c.
* For details of node_remap(), see bitmap_bitremap in lib/bitmap.c.
@@ -51,7 +51,7 @@
* unsigned long *nodes_addr(mask) Array of unsigned long's in mask
*
* int nodemask_scnprintf(buf, len, mask) Format nodemask for printing
- * int nodemask_parse(ubuf, ulen, mask) Parse ascii string as nodemask
+ * int nodemask_parse_user(ubuf, ulen, mask) Parse ascii string as nodemask
* int nodelist_scnprintf(buf, len, mask) Format nodemask as list for printing
* int nodelist_parse(buf, map) Parse ascii string as nodelist
* int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit)
@@ -288,12 +288,12 @@ static inline int __nodemask_scnprintf(char *buf, int len,
return bitmap_scnprintf(buf, len, srcp->bits, nbits);
}
-#define nodemask_parse(ubuf, ulen, dst) \
- __nodemask_parse((ubuf), (ulen), &(dst), MAX_NUMNODES)
-static inline int __nodemask_parse(const char __user *buf, int len,
+#define nodemask_parse_user(ubuf, ulen, dst) \
+ __nodemask_parse_user((ubuf), (ulen), &(dst), MAX_NUMNODES)
+static inline int __nodemask_parse_user(const char __user *buf, int len,
nodemask_t *dstp, int nbits)
{
- return bitmap_parse(buf, len, dstp->bits, nbits);
+ return bitmap_parse_user(buf, len, dstp->bits, nbits);
}
#define nodelist_scnprintf(buf, len, src) \
@@ -352,6 +352,7 @@ extern nodemask_t node_possible_map;
#define node_possible(node) node_isset((node), node_possible_map)
#define first_online_node first_node(node_online_map)
#define next_online_node(nid) next_node((nid), node_online_map)
+int highest_possible_node_id(void);
#else
#define num_online_nodes() 1
#define num_possible_nodes() 1
@@ -359,6 +360,7 @@ extern nodemask_t node_possible_map;
#define node_possible(node) ((node) == 0)
#define first_online_node 0
#define next_online_node(nid) (MAX_NUMNODES)
+#define highest_possible_node_id() 0
#endif
#define any_online_node(mask) \
diff --git a/include/linux/notifier.h b/include/linux/notifier.h
index 7ff386a6ae87..10a43ed0527e 100644
--- a/include/linux/notifier.h
+++ b/include/linux/notifier.h
@@ -12,9 +12,10 @@
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
+#include <linux/srcu.h>
/*
- * Notifier chains are of three types:
+ * Notifier chains are of four types:
*
* Atomic notifier chains: Chain callbacks run in interrupt/atomic
* context. Callouts are not allowed to block.
@@ -23,13 +24,27 @@
* Raw notifier chains: There are no restrictions on callbacks,
* registration, or unregistration. All locking and protection
* must be provided by the caller.
+ * SRCU notifier chains: A variant of blocking notifier chains, with
+ * the same restrictions.
*
* atomic_notifier_chain_register() may be called from an atomic context,
- * but blocking_notifier_chain_register() must be called from a process
- * context. Ditto for the corresponding _unregister() routines.
+ * but blocking_notifier_chain_register() and srcu_notifier_chain_register()
+ * must be called from a process context. Ditto for the corresponding
+ * _unregister() routines.
*
- * atomic_notifier_chain_unregister() and blocking_notifier_chain_unregister()
- * _must not_ be called from within the call chain.
+ * atomic_notifier_chain_unregister(), blocking_notifier_chain_unregister(),
+ * and srcu_notifier_chain_unregister() _must not_ be called from within
+ * the call chain.
+ *
+ * SRCU notifier chains are an alternative form of blocking notifier chains.
+ * They use SRCU (Sleepable Read-Copy Update) instead of rw-semaphores for
+ * protection of the chain links. This means there is _very_ low overhead
+ * in srcu_notifier_call_chain(): no cache bounces and no memory barriers.
+ * As compensation, srcu_notifier_chain_unregister() is rather expensive.
+ * SRCU notifier chains should be used when the chain will be called very
+ * often but notifier_blocks will seldom be removed. Also, SRCU notifier
+ * chains are slightly more difficult to use because they require special
+ * runtime initialization.
*/
struct notifier_block {
@@ -52,6 +67,12 @@ struct raw_notifier_head {
struct notifier_block *head;
};
+struct srcu_notifier_head {
+ struct mutex mutex;
+ struct srcu_struct srcu;
+ struct notifier_block *head;
+};
+
#define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \
spin_lock_init(&(name)->lock); \
(name)->head = NULL; \
@@ -64,6 +85,11 @@ struct raw_notifier_head {
(name)->head = NULL; \
} while (0)
+/* srcu_notifier_heads must be initialized and cleaned up dynamically */
+extern void srcu_init_notifier_head(struct srcu_notifier_head *nh);
+#define srcu_cleanup_notifier_head(name) \
+ cleanup_srcu_struct(&(name)->srcu);
+
#define ATOMIC_NOTIFIER_INIT(name) { \
.lock = __SPIN_LOCK_UNLOCKED(name.lock), \
.head = NULL }
@@ -72,6 +98,7 @@ struct raw_notifier_head {
.head = NULL }
#define RAW_NOTIFIER_INIT(name) { \
.head = NULL }
+/* srcu_notifier_heads cannot be initialized statically */
#define ATOMIC_NOTIFIER_HEAD(name) \
struct atomic_notifier_head name = \
@@ -91,6 +118,8 @@ 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 *);
@@ -98,6 +127,8 @@ 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 *,
unsigned long val, void *v);
@@ -105,6 +136,8 @@ extern int blocking_notifier_call_chain(struct blocking_notifier_head *,
unsigned long val, void *v);
extern int raw_notifier_call_chain(struct raw_notifier_head *,
unsigned long val, void *v);
+extern int srcu_notifier_call_chain(struct srcu_notifier_head *,
+ unsigned long val, void *v);
#define NOTIFY_DONE 0x0000 /* Don't care */
#define NOTIFY_OK 0x0001 /* Suits me */
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
new file mode 100644
index 000000000000..f6baecdeecd6
--- /dev/null
+++ b/include/linux/nsproxy.h
@@ -0,0 +1,52 @@
+#ifndef _LINUX_NSPROXY_H
+#define _LINUX_NSPROXY_H
+
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+
+struct namespace;
+struct uts_namespace;
+struct ipc_namespace;
+
+/*
+ * A structure to contain pointers to all per-process
+ * namespaces - fs (mount), uts, network, sysvipc, etc.
+ *
+ * 'count' is the number of tasks holding a reference.
+ * The count for each namespace, then, will be the number
+ * of nsproxies pointing to it, not the number of tasks.
+ *
+ * The nsproxy is shared by tasks which share all namespaces.
+ * As soon as a single namespace is cloned or unshared, the
+ * nsproxy is copied.
+ */
+struct nsproxy {
+ atomic_t count;
+ spinlock_t nslock;
+ struct uts_namespace *uts_ns;
+ struct ipc_namespace *ipc_ns;
+ struct namespace *namespace;
+};
+extern struct nsproxy init_nsproxy;
+
+struct nsproxy *dup_namespaces(struct nsproxy *orig);
+int copy_namespaces(int flags, struct task_struct *tsk);
+void get_task_namespaces(struct task_struct *tsk);
+void free_nsproxy(struct nsproxy *ns);
+
+static inline void put_nsproxy(struct nsproxy *ns)
+{
+ if (atomic_dec_and_test(&ns->count)) {
+ free_nsproxy(ns);
+ }
+}
+
+static inline void exit_task_namespaces(struct task_struct *p)
+{
+ struct nsproxy *ns = p->nsproxy;
+ if (ns) {
+ put_nsproxy(ns);
+ p->nsproxy = NULL;
+ }
+}
+#endif
diff --git a/include/linux/oom.h b/include/linux/oom.h
new file mode 100644
index 000000000000..ad76463629a0
--- /dev/null
+++ b/include/linux/oom.h
@@ -0,0 +1,10 @@
+#ifndef __INCLUDE_LINUX_OOM_H
+#define __INCLUDE_LINUX_OOM_H
+
+/* /proc/<pid>/oom_adj set to -17 protects from the oom-killer */
+#define OOM_DISABLE (-17)
+/* inclusive */
+#define OOM_ADJUST_MIN (-16)
+#define OOM_ADJUST_MAX 15
+
+#endif
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 9d7921dd50f0..4830a3bedfb2 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -128,12 +128,11 @@
#define PageUptodate(page) test_bit(PG_uptodate, &(page)->flags)
#ifdef CONFIG_S390
-#define SetPageUptodate(_page) \
- do { \
- struct page *__page = (_page); \
- if (!test_and_set_bit(PG_uptodate, &__page->flags)) \
- page_test_and_clear_dirty(_page); \
- } while (0)
+static inline void SetPageUptodate(struct page *page)
+{
+ if (!test_and_set_bit(PG_uptodate, &page->flags))
+ page_test_and_clear_dirty(page);
+}
#else
#define SetPageUptodate(page) set_bit(PG_uptodate, &(page)->flags)
#endif
diff --git a/include/linux/parport.h b/include/linux/parport.h
index 5bf321e82c99..80682aaa8f18 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -229,7 +229,7 @@ struct pardevice {
int (*preempt)(void *);
void (*wakeup)(void *);
void *private;
- void (*irq_func)(int, void *, struct pt_regs *);
+ void (*irq_func)(int, void *);
unsigned int flags;
struct pardevice *next;
struct pardevice *prev;
@@ -375,7 +375,7 @@ extern void parport_put_port (struct parport *);
struct pardevice *parport_register_device(struct parport *port,
const char *name,
int (*pf)(void *), void (*kf)(void *),
- void (*irq_func)(int, void *, struct pt_regs *),
+ void (*irq_func)(int, void *),
int flags, void *handle);
/* parport_unregister unlinks a device from the chain. */
@@ -457,7 +457,7 @@ static __inline__ int parport_yield_blocking(struct pardevice *dev)
#define PARPORT_FLAG_EXCL (1<<1) /* EXCL driver registered. */
/* IEEE1284 functions */
-extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *);
+extern void parport_ieee1284_interrupt (int, void *);
extern int parport_negotiate (struct parport *, int mode);
extern ssize_t parport_write (struct parport *, const void *buf, size_t len);
extern ssize_t parport_read (struct parport *, void *buf, size_t len);
@@ -502,8 +502,7 @@ extern void parport_daisy_fini (struct parport *port);
extern struct pardevice *parport_open (int devnum, const char *name,
int (*pf) (void *),
void (*kf) (void *),
- void (*irqf) (int, void *,
- struct pt_regs *),
+ void (*irqf) (int, void *),
int flags, void *handle);
extern void parport_close (struct pardevice *dev);
extern ssize_t parport_device_id (int devnum, char *buffer, size_t len);
@@ -512,13 +511,12 @@ extern void parport_daisy_deselect_all (struct parport *port);
extern int parport_daisy_select (struct parport *port, int daisy, int mode);
/* Lowlevel drivers _can_ call this support function to handle irqs. */
-static __inline__ void parport_generic_irq(int irq, struct parport *port,
- struct pt_regs *regs)
+static __inline__ void parport_generic_irq(int irq, struct parport *port)
{
- parport_ieee1284_interrupt (irq, port, regs);
+ parport_ieee1284_interrupt (irq, port);
read_lock(&port->cad_lock);
if (port->cad && port->cad->irq_func)
- port->cad->irq_func(irq, port->cad->private, regs);
+ port->cad->irq_func(irq, port->cad->private);
read_unlock(&port->cad_lock);
}
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 3ec72551ac31..09be0f81b27b 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -356,6 +356,8 @@ struct pci_driver {
struct pci_error_handlers *err_handler;
struct device_driver driver;
struct pci_dynids dynids;
+
+ int multithread_probe;
};
#define to_pci_driver(drv) container_of(drv,struct pci_driver, driver)
@@ -431,7 +433,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn);
struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus);
unsigned int pci_scan_child_bus(struct pci_bus *bus);
-void pci_bus_add_device(struct pci_dev *dev);
+int __must_check pci_bus_add_device(struct pci_dev *dev);
void pci_read_bridge_bases(struct pci_bus *child);
struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res);
int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge);
@@ -439,7 +441,9 @@ extern struct pci_dev *pci_dev_get(struct pci_dev *dev);
extern void pci_dev_put(struct pci_dev *dev);
extern void pci_remove_bus(struct pci_bus *b);
extern void pci_remove_bus_device(struct pci_dev *dev);
+extern void pci_stop_bus_device(struct pci_dev *dev);
void pci_setup_cardbus(struct pci_bus *bus);
+extern void pci_sort_breadthfirst(void);
/* Generic PCI functions exported to card drivers */
@@ -449,13 +453,18 @@ struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
int pci_find_capability (struct pci_dev *dev, int cap);
int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
int pci_find_ext_capability (struct pci_dev *dev, int cap);
-struct pci_bus * pci_find_next_bus(const struct pci_bus *from);
+struct pci_bus *pci_find_next_bus(const struct pci_bus *from);
+
+struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
+ struct pci_dev *from);
+struct pci_dev *pci_get_device_reverse(unsigned int vendor, unsigned int device,
+ struct pci_dev *from);
-struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from);
struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
unsigned int ss_vendor, unsigned int ss_device,
struct pci_dev *from);
struct pci_dev *pci_get_slot (struct pci_bus *bus, unsigned int devfn);
+struct pci_dev *pci_get_bus_and_slot (unsigned int bus, unsigned int devfn);
struct pci_dev *pci_get_class (unsigned int class, struct pci_dev *from);
int pci_dev_present(const struct pci_device_id *ids);
@@ -592,6 +601,7 @@ struct msix_entry {
u16 entry; /* driver uses to specify entry, OS writes */
};
+
#ifndef CONFIG_PCI_MSI
static inline void pci_scan_msi_device(struct pci_dev *dev) {}
static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
@@ -610,6 +620,12 @@ extern void pci_disable_msix(struct pci_dev *dev);
extern void msi_remove_pci_irq_vectors(struct pci_dev *dev);
#endif
+#ifdef CONFIG_HT_IRQ
+/* The functions a driver should call */
+int ht_create_irq(struct pci_dev *dev, int idx);
+void ht_destroy_irq(unsigned int irq);
+#endif /* CONFIG_HT_IRQ */
+
extern void pci_block_user_cfg_access(struct pci_dev *dev);
extern void pci_unblock_user_cfg_access(struct pci_dev *dev);
@@ -648,7 +664,12 @@ static inline struct pci_dev *pci_find_device(unsigned int vendor, unsigned int
static inline struct pci_dev *pci_find_slot(unsigned int bus, unsigned int devfn)
{ return NULL; }
-static inline struct pci_dev *pci_get_device (unsigned int vendor, unsigned int device, struct pci_dev *from)
+static inline struct pci_dev *pci_get_device(unsigned int vendor,
+ unsigned int device, struct pci_dev *from)
+{ return NULL; }
+
+static inline struct pci_dev *pci_get_device_reverse(unsigned int vendor,
+ unsigned int device, struct pci_dev *from)
{ return NULL; }
static inline struct pci_dev *pci_get_subsys (unsigned int vendor, unsigned int device,
@@ -784,12 +805,13 @@ enum pci_fixup_pass {
void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev);
extern int pci_pci_problems;
-#define PCIPCI_FAIL 1
+#define PCIPCI_FAIL 1 /* No PCI PCI DMA */
#define PCIPCI_TRITON 2
#define PCIPCI_NATOMA 4
#define PCIPCI_VIAETBF 8
#define PCIPCI_VSFX 16
-#define PCIPCI_ALIMAGIK 32
+#define PCIPCI_ALIMAGIK 32 /* Need low latency setting */
+#define PCIAGP_FAIL 64 /* No PCI to AGP DMA */
#endif /* __KERNEL__ */
#endif /* LINUX_PCI_H */
diff --git a/drivers/pci/hotplug/pci_hotplug.h b/include/linux/pci_hotplug.h
index e929b7c11429..a675a05c4091 100644
--- a/drivers/pci/hotplug/pci_hotplug.h
+++ b/include/linux/pci_hotplug.h
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Send feedback to <greg@kroah.com>
+ * Send feedback to <kristen.c.accardi@intel.com>
*
*/
#ifndef _PCI_HOTPLUG_H
@@ -172,8 +172,8 @@ struct hotplug_slot {
extern int pci_hp_register (struct hotplug_slot *slot);
extern int pci_hp_deregister (struct hotplug_slot *slot);
-extern int pci_hp_change_slot_info (struct hotplug_slot *slot,
- struct hotplug_slot_info *info);
+extern int __must_check pci_hp_change_slot_info (struct hotplug_slot *slot,
+ struct hotplug_slot_info *info);
extern struct subsystem pci_hotplug_slots_subsys;
/* PCI Setting Record (Type 0) */
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 6a1e09834559..f3a168f3c9df 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -479,6 +479,7 @@
#define PCI_VENDOR_ID_AMD 0x1022
#define PCI_DEVICE_ID_AMD_K8_NB 0x1100
+#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103
#define PCI_DEVICE_ID_AMD_LANCE 0x2000
#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001
#define PCI_DEVICE_ID_AMD_SCSI 0x2020
@@ -506,6 +507,7 @@
#define PCI_DEVICE_ID_AMD_8151_0 0x7454
#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450
#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451
+#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458
#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090
#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091
#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093
@@ -1411,6 +1413,7 @@
#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009
#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017
#define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103
+#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132
#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200
#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201
#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203
@@ -1482,9 +1485,6 @@
#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430
#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460
#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480
-#define PCI_DEVICE_ID_MARVELL_GT96100 0x9652
-#define PCI_DEVICE_ID_MARVELL_GT96100A 0x9653
-
#define PCI_VENDOR_ID_V3 0x11b0
#define PCI_DEVICE_ID_V3_V960 0x0001
@@ -1615,8 +1615,6 @@
#define PCI_VENDOR_ID_ROCKWELL 0x127A
#define PCI_VENDOR_ID_ITE 0x1283
-#define PCI_DEVICE_ID_ITE_IT8172G 0x8172
-#define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
#define PCI_DEVICE_ID_ITE_8211 0x8211
#define PCI_DEVICE_ID_ITE_8212 0x8212
#define PCI_DEVICE_ID_ITE_8872 0x8872
@@ -1883,6 +1881,8 @@
#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400
#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402
+#define PCI_VENDOR_ID_SIPACKETS 0x14d9
+#define PCI_DEVICE_ID_SP1011 0x0010
#define PCI_VENDOR_ID_AFAVLAB 0x14db
#define PCI_DEVICE_ID_AFAVLAB_P028 0x2180
@@ -1905,6 +1905,7 @@
#define PCI_DEVICE_ID_TIGON3_5705_2 0x1654
#define PCI_DEVICE_ID_TIGON3_5720 0x1658
#define PCI_DEVICE_ID_TIGON3_5721 0x1659
+#define PCI_DEVICE_ID_TIGON3_5722 0x165a
#define PCI_DEVICE_ID_TIGON3_5705M 0x165d
#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e
#define PCI_DEVICE_ID_TIGON3_5714 0x1668
@@ -1914,6 +1915,7 @@
#define PCI_DEVICE_ID_TIGON3_5705F 0x166e
#define PCI_DEVICE_ID_TIGON3_5754M 0x1672
#define PCI_DEVICE_ID_TIGON3_5755M 0x1673
+#define PCI_DEVICE_ID_TIGON3_5756 0x1674
#define PCI_DEVICE_ID_TIGON3_5750 0x1676
#define PCI_DEVICE_ID_TIGON3_5751 0x1677
#define PCI_DEVICE_ID_TIGON3_5715 0x1678
@@ -1943,6 +1945,8 @@
#define PCI_DEVICE_ID_TIGON3_5901 0x170d
#define PCI_DEVICE_ID_BCM4401B1 0x170c
#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e
+#define PCI_DEVICE_ID_TIGON3_5906 0x1712
+#define PCI_DEVICE_ID_TIGON3_5906M 0x1713
#define PCI_DEVICE_ID_BCM4401 0x4401
#define PCI_DEVICE_ID_BCM4401B0 0x4402
@@ -1993,6 +1997,7 @@
#define PCI_DEVICE_ID_FARSITE_TE1C 0x1612
#define PCI_VENDOR_ID_SIBYTE 0x166d
+#define PCI_DEVICE_ID_BCM1250_PCI 0x0001
#define PCI_DEVICE_ID_BCM1250_HT 0x0002
#define PCI_VENDOR_ID_NETCELL 0x169c
@@ -2346,3 +2351,5 @@
#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897
#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898
+#define PCI_VENDOR_ID_QUICKNET 0x15E2
+#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500
diff --git a/include/linux/pci_regs.h b/include/linux/pci_regs.h
index 96930cb5927c..c312a12ad2d6 100644
--- a/include/linux/pci_regs.h
+++ b/include/linux/pci_regs.h
@@ -12,6 +12,11 @@
* PCI Local Bus Specification
* PCI to PCI Bridge Specification
* PCI System Design Guide
+ *
+ * For hypertransport information, please consult the following manuals
+ * from http://www.hypertransport.org
+ *
+ * The Hypertransport I/O Link Specification
*/
#ifndef LINUX_PCI_REGS_H
@@ -196,7 +201,7 @@
#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */
#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */
#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */
-#define PCI_CAP_ID_HT_IRQCONF 0x08 /* HyperTransport IRQ Configuration */
+#define PCI_CAP_ID_HT 0x08 /* HyperTransport */
#define PCI_CAP_ID_VNDR 0x09 /* Vendor specific capability */
#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */
#define PCI_CAP_ID_EXP 0x10 /* PCI Express */
@@ -463,4 +468,20 @@
#define PCI_PWR_CAP 12 /* Capability */
#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */
+/* Hypertransport sub capability types */
+#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */
+#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */
+#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */
+#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */
+#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */
+#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */
+#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */
+#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */
+#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */
+#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */
+#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */
+#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 hypertransport configuration */
+#define HT_CAPTYPE_PM 0xE0 /* Hypertransport powermanagement configuration */
+
+
#endif /* LINUX_PCI_REGS_H */
diff --git a/include/linux/pcieport_if.h b/include/linux/pcieport_if.h
index b44e01a70914..6cd91e3f9820 100644
--- a/include/linux/pcieport_if.h
+++ b/include/linux/pcieport_if.h
@@ -62,6 +62,12 @@ struct pcie_port_service_driver {
int (*suspend) (struct pcie_device *dev, pm_message_t state);
int (*resume) (struct pcie_device *dev);
+ /* Service Error Recovery Handler */
+ struct pci_error_handlers *err_handler;
+
+ /* Link Reset Capability - AER service driver specific */
+ pci_ers_result_t (*reset_link) (struct pci_dev *dev);
+
const struct pcie_port_service_id *id_table;
struct device_driver driver;
};
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 3835a9642f13..600e3d387ffc 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -19,7 +19,7 @@
* we force a syntax error here if it isn't.
*/
#define get_cpu_var(var) (*({ \
- extern int simple_indentifier_##var(void); \
+ extern int simple_identifier_##var(void); \
preempt_disable(); \
&__get_cpu_var(var); }))
#define put_cpu_var(var) preempt_enable()
@@ -74,7 +74,7 @@ static inline int __percpu_populate_mask(void *__pdata, size_t size, gfp_t gfp,
return 0;
}
-static inline void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
+static __always_inline void *__percpu_alloc_mask(size_t size, gfp_t gfp, cpumask_t *mask)
{
return kzalloc(size, gfp);
}
diff --git a/include/linux/personality.h b/include/linux/personality.h
index 80d780e5a8f5..bf4cf2080e5c 100644
--- a/include/linux/personality.h
+++ b/include/linux/personality.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_PERSONALITY_H
#define _LINUX_PERSONALITY_H
+#ifdef __KERNEL__
+
/*
* Handling of different ABIs (personalities).
*/
@@ -12,6 +14,8 @@ extern int register_exec_domain(struct exec_domain *);
extern int unregister_exec_domain(struct exec_domain *);
extern int __set_personality(unsigned long);
+#endif /* __KERNEL__ */
+
/*
* Flags for bug emulation.
*
@@ -71,6 +75,7 @@ enum {
PER_MASK = 0x00ff,
};
+#ifdef __KERNEL__
/*
* Description of an execution domain.
@@ -111,4 +116,6 @@ struct exec_domain {
#define set_personality(pers) \
((current->personality == pers) ? 0 : __set_personality(pers))
+#endif /* __KERNEL__ */
+
#endif /* _LINUX_PERSONALITY_H */
diff --git a/include/linux/pid.h b/include/linux/pid.h
index 29960b03bef7..2c0007d17218 100644
--- a/include/linux/pid.h
+++ b/include/linux/pid.h
@@ -68,6 +68,8 @@ extern struct task_struct *FASTCALL(pid_task(struct pid *pid, enum pid_type));
extern struct task_struct *FASTCALL(get_pid_task(struct pid *pid,
enum pid_type));
+extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type);
+
/*
* attach_pid() and detach_pid() must be called with the tasklist_lock
* write-held.
@@ -76,6 +78,8 @@ extern int FASTCALL(attach_pid(struct task_struct *task,
enum pid_type type, int nr));
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));
/*
* look up a PID in the hash table. Must be called with the tasklist_lock
@@ -87,33 +91,42 @@ extern struct pid *FASTCALL(find_pid(int nr));
* Lookup a PID in the hash table, and return with it's count elevated.
*/
extern struct pid *find_get_pid(int nr);
+extern struct pid *find_ge_pid(int nr);
extern struct pid *alloc_pid(void);
extern void FASTCALL(free_pid(struct pid *pid));
-#define pid_next(task, type) \
- ((task)->pids[(type)].node.next)
-
-#define pid_next_task(task, type) \
- hlist_entry(pid_next(task, type), struct task_struct, \
- pids[(type)].node)
+static inline pid_t pid_nr(struct pid *pid)
+{
+ pid_t nr = 0;
+ if (pid)
+ nr = pid->nr;
+ return nr;
+}
-/* We could use hlist_for_each_entry_rcu here but it takes more arguments
- * than the do_each_task_pid/while_each_task_pid. So we roll our own
- * to preserve the existing interface.
- */
#define do_each_task_pid(who, type, task) \
- if ((task = find_task_by_pid_type(type, who))) { \
- prefetch(pid_next(task, type)); \
- do {
+ do { \
+ struct hlist_node *pos___; \
+ struct pid *pid___ = find_pid(who); \
+ if (pid___ != NULL) \
+ hlist_for_each_entry_rcu((task), pos___, \
+ &pid___->tasks[type], pids[type].node) {
#define while_each_task_pid(who, type, task) \
- } while (pid_next(task, type) && ({ \
- task = pid_next_task(task, type); \
- rcu_dereference(task); \
- prefetch(pid_next(task, type)); \
- 1; }) ); \
- }
+ } \
+ } while (0)
+
+
+#define do_each_pid_task(pid, type, task) \
+ do { \
+ struct hlist_node *pos___; \
+ if (pid != NULL) \
+ hlist_for_each_entry_rcu((task), pos___, \
+ &pid->tasks[type], pids[type].node) {
+
+#define while_each_pid_task(pid, type, task) \
+ } \
+ } while (0)
#endif /* _LINUX_PID_H */
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h
index 95572c434bc9..a7dd38f30ade 100644
--- a/include/linux/posix-timers.h
+++ b/include/linux/posix-timers.h
@@ -72,6 +72,7 @@ struct k_clock {
int (*timer_create) (struct k_itimer *timer);
int (*nsleep) (const clockid_t which_clock, int flags,
struct timespec *, struct timespec __user *);
+ long (*nsleep_restart) (struct restart_block *restart_block);
int (*timer_set) (struct k_itimer * timr, int flags,
struct itimerspec * new_setting,
struct itimerspec * old_setting);
@@ -97,6 +98,7 @@ int posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *ts);
int posix_cpu_timer_create(struct k_itimer *timer);
int posix_cpu_nsleep(const clockid_t which_clock, int flags,
struct timespec *rqtp, struct timespec __user *rmtp);
+long posix_cpu_nsleep_restart(struct restart_block *restart_block);
int posix_cpu_timer_set(struct k_itimer *timer, int flags,
struct itimerspec *new, struct itimerspec *old);
int posix_cpu_timer_del(struct k_itimer *timer);
@@ -111,4 +113,6 @@ void posix_cpu_timers_exit_group(struct task_struct *task);
void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
cputime_t *newval, cputime_t *oldval);
+long clock_nanosleep_restart(struct restart_block *restart_block);
+
#endif
diff --git a/include/linux/ppdev.h b/include/linux/ppdev.h
index f376a7598a78..dc18c5d23ebe 100644
--- a/include/linux/ppdev.h
+++ b/include/linux/ppdev.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/char/ppdev.h
+ * linux/include/linux/ppdev.h
*
* User-space parallel port device driver (header file).
*
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 3435ca38dd14..87dec8fe6de9 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -244,13 +244,15 @@ static inline void kclist_add(struct kcore_list *new, void *addr, size_t size)
extern void kclist_add(struct kcore_list *, void *, size_t);
#endif
+union proc_op {
+ int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
+ int (*proc_read)(struct task_struct *task, char *page);
+};
+
struct proc_inode {
struct pid *pid;
int fd;
- union {
- int (*proc_get_link)(struct inode *, struct dentry **, struct vfsmount **);
- int (*proc_read)(struct task_struct *task, char *page);
- } op;
+ union proc_op op;
struct proc_dir_entry *pde;
struct inode vfs_inode;
};
@@ -268,7 +270,9 @@ static inline struct proc_dir_entry *PDE(const struct inode *inode)
struct proc_maps_private {
struct pid *pid;
struct task_struct *task;
+#ifdef CONFIG_MMU
struct vm_area_struct *tail_vma;
+#endif
};
#endif /* _LINUX_PROC_FS_H */
diff --git a/include/linux/profile.h b/include/linux/profile.h
index e633004ae052..acce53fd38b6 100644
--- a/include/linux/profile.h
+++ b/include/linux/profile.h
@@ -17,7 +17,7 @@ struct notifier_block;
/* init basic kernel profiler */
void __init profile_init(void);
-void profile_tick(int, struct pt_regs *);
+void profile_tick(int);
void profile_hit(int, void *);
#ifdef CONFIG_PROC_FS
void create_prof_cpu_mask(struct proc_dir_entry *);
diff --git a/include/linux/pspace.h b/include/linux/pspace.h
new file mode 100644
index 000000000000..91d48b8b2d99
--- /dev/null
+++ b/include/linux/pspace.h
@@ -0,0 +1,23 @@
+#ifndef _LINUX_PSPACE_H
+#define _LINUX_PSPACE_H
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/threads.h>
+#include <linux/pid.h>
+
+struct pidmap {
+ atomic_t nr_free;
+ void *page;
+};
+
+#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
+
+struct pspace {
+ struct pidmap pidmap[PIDMAP_ENTRIES];
+ int last_pid;
+};
+
+extern struct pspace init_pspace;
+
+#endif /* _LINUX_PSPACE_H */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 8b2749a259dc..eeb1976ef7bf 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -16,8 +16,8 @@
#define PTRACE_KILL 8
#define PTRACE_SINGLESTEP 9
-#define PTRACE_ATTACH 0x10
-#define PTRACE_DETACH 0x11
+#define PTRACE_ATTACH 16
+#define PTRACE_DETACH 17
#define PTRACE_SYSCALL 24
diff --git a/include/linux/raid/bitmap.h b/include/linux/raid/bitmap.h
index 63df898fe2e9..ebd42a3710b4 100644
--- a/include/linux/raid/bitmap.h
+++ b/include/linux/raid/bitmap.h
@@ -146,16 +146,16 @@ enum bitmap_state {
/* the superblock at the front of the bitmap file -- little endian */
typedef struct bitmap_super_s {
- __u32 magic; /* 0 BITMAP_MAGIC */
- __u32 version; /* 4 the bitmap major for now, could change... */
- __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */
- __u64 events; /* 24 event counter for the bitmap (1)*/
- __u64 events_cleared;/*32 event counter when last bit cleared (2) */
- __u64 sync_size; /* 40 the size of the md device's sync range(3) */
- __u32 state; /* 48 bitmap state information */
- __u32 chunksize; /* 52 the bitmap chunk size in bytes */
- __u32 daemon_sleep; /* 56 seconds between disk flushes */
- __u32 write_behind; /* 60 number of outstanding write-behind writes */
+ __le32 magic; /* 0 BITMAP_MAGIC */
+ __le32 version; /* 4 the bitmap major for now, could change... */
+ __u8 uuid[16]; /* 8 128 bit uuid - must match md device uuid */
+ __le64 events; /* 24 event counter for the bitmap (1)*/
+ __le64 events_cleared;/*32 event counter when last bit cleared (2) */
+ __le64 sync_size; /* 40 the size of the md device's sync range(3) */
+ __le32 state; /* 48 bitmap state information */
+ __le32 chunksize; /* 52 the bitmap chunk size in bytes */
+ __le32 daemon_sleep; /* 56 seconds between disk flushes */
+ __le32 write_behind; /* 60 number of outstanding write-behind writes */
__u8 pad[256 - 64]; /* set to zero */
} bitmap_super_t;
@@ -265,6 +265,8 @@ int bitmap_update_sb(struct bitmap *bitmap);
int bitmap_setallbits(struct bitmap *bitmap);
void bitmap_write_all(struct bitmap *bitmap);
+void bitmap_dirty_bits(struct bitmap *bitmap, unsigned long s, unsigned long e);
+
/* these are exported */
int bitmap_startwrite(struct bitmap *bitmap, sector_t offset,
unsigned long sectors, int behind);
diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h
index eb3e547c8fee..866a1e2b0ce0 100644
--- a/include/linux/raid/md.h
+++ b/include/linux/raid/md.h
@@ -53,6 +53,8 @@
#include <linux/raid/md_u.h>
#include <linux/raid/md_k.h>
+#ifdef CONFIG_MD
+
/*
* Different major versions are not compatible.
* Different minor versions are only downward compatible.
@@ -93,7 +95,7 @@ extern int sync_page_io(struct block_device *bdev, sector_t sector, int size,
extern void md_do_sync(mddev_t *mddev);
extern void md_new_event(mddev_t *mddev);
-extern void md_update_sb(mddev_t * mddev);
+#endif /* CONFIG_MD */
#endif
diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h
index d28890295852..8245c282168b 100644
--- a/include/linux/raid/md_k.h
+++ b/include/linux/raid/md_k.h
@@ -18,6 +18,8 @@
/* and dm-bio-list.h is not under include/linux because.... ??? */
#include "../../../drivers/md/dm-bio-list.h"
+#ifdef CONFIG_BLOCK
+
#define LEVEL_MULTIPATH (-4)
#define LEVEL_LINEAR (-1)
#define LEVEL_FAULTY (-5)
@@ -29,18 +31,15 @@
#define LEVEL_NONE (-1000000)
#define MaxSector (~(sector_t)0)
-#define MD_THREAD_NAME_MAX 14
typedef struct mddev_s mddev_t;
typedef struct mdk_rdev_s mdk_rdev_t;
-#define MAX_MD_DEVS 256 /* Max number of md dev */
-
/*
* options passed in raidrun:
*/
-/* Currently this must fix in an 'int' */
+/* Currently this must fit in an 'int' */
#define MAX_CHUNK_SIZE (1<<30)
/*
@@ -114,7 +113,11 @@ struct mddev_s
dev_t unit;
int md_minor;
struct list_head disks;
- int sb_dirty;
+ unsigned long flags;
+#define MD_CHANGE_DEVS 0 /* Some device status has changed */
+#define MD_CHANGE_CLEAN 1 /* transition to or from 'clean' */
+#define MD_CHANGE_PENDING 2 /* superblock update in progress */
+
int ro;
struct gendisk *gendisk;
@@ -362,5 +365,6 @@ static inline void safe_put_page(struct page *p)
if (p) put_page(p);
}
+#endif /* CONFIG_BLOCK */
#endif
diff --git a/include/linux/raid/md_p.h b/include/linux/raid/md_p.h
index b6ebc69bae54..3f2cd98c508b 100644
--- a/include/linux/raid/md_p.h
+++ b/include/linux/raid/md_p.h
@@ -206,52 +206,52 @@ static inline __u64 md_event(mdp_super_t *sb) {
*/
struct mdp_superblock_1 {
/* constant array information - 128 bytes */
- __u32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */
- __u32 major_version; /* 1 */
- __u32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */
- __u32 pad0; /* always set to 0 when writing */
+ __le32 magic; /* MD_SB_MAGIC: 0xa92b4efc - little endian */
+ __le32 major_version; /* 1 */
+ __le32 feature_map; /* bit 0 set if 'bitmap_offset' is meaningful */
+ __le32 pad0; /* always set to 0 when writing */
__u8 set_uuid[16]; /* user-space generated. */
char set_name[32]; /* set and interpreted by user-space */
- __u64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/
- __u32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */
- __u32 layout; /* only for raid5 and raid10 currently */
- __u64 size; /* used size of component devices, in 512byte sectors */
+ __le64 ctime; /* lo 40 bits are seconds, top 24 are microseconds or 0*/
+ __le32 level; /* -4 (multipath), -1 (linear), 0,1,4,5 */
+ __le32 layout; /* only for raid5 and raid10 currently */
+ __le64 size; /* used size of component devices, in 512byte sectors */
- __u32 chunksize; /* in 512byte sectors */
- __u32 raid_disks;
- __u32 bitmap_offset; /* sectors after start of superblock that bitmap starts
+ __le32 chunksize; /* in 512byte sectors */
+ __le32 raid_disks;
+ __le32 bitmap_offset; /* sectors after start of superblock that bitmap starts
* NOTE: signed, so bitmap can be before superblock
* only meaningful of feature_map[0] is set.
*/
/* These are only valid with feature bit '4' */
- __u32 new_level; /* new level we are reshaping to */
- __u64 reshape_position; /* next address in array-space for reshape */
- __u32 delta_disks; /* change in number of raid_disks */
- __u32 new_layout; /* new layout */
- __u32 new_chunk; /* new chunk size (bytes) */
+ __le32 new_level; /* new level we are reshaping to */
+ __le64 reshape_position; /* next address in array-space for reshape */
+ __le32 delta_disks; /* change in number of raid_disks */
+ __le32 new_layout; /* new layout */
+ __le32 new_chunk; /* new chunk size (bytes) */
__u8 pad1[128-124]; /* set to 0 when written */
/* constant this-device information - 64 bytes */
- __u64 data_offset; /* sector start of data, often 0 */
- __u64 data_size; /* sectors in this device that can be used for data */
- __u64 super_offset; /* sector start of this superblock */
- __u64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
- __u32 dev_number; /* permanent identifier of this device - not role in raid */
- __u32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */
+ __le64 data_offset; /* sector start of data, often 0 */
+ __le64 data_size; /* sectors in this device that can be used for data */
+ __le64 super_offset; /* sector start of this superblock */
+ __le64 recovery_offset;/* sectors before this offset (from data_offset) have been recovered */
+ __le32 dev_number; /* permanent identifier of this device - not role in raid */
+ __le32 cnt_corrected_read; /* number of read errors that were corrected by re-writing */
__u8 device_uuid[16]; /* user-space setable, ignored by kernel */
__u8 devflags; /* per-device flags. Only one defined...*/
#define WriteMostly1 1 /* mask for writemostly flag in above */
__u8 pad2[64-57]; /* set to 0 when writing */
/* array state information - 64 bytes */
- __u64 utime; /* 40 bits second, 24 btes microseconds */
- __u64 events; /* incremented when superblock updated */
- __u64 resync_offset; /* data before this offset (from data_offset) known to be in sync */
- __u32 sb_csum; /* checksum upto devs[max_dev] */
- __u32 max_dev; /* size of devs[] array to consider */
+ __le64 utime; /* 40 bits second, 24 btes microseconds */
+ __le64 events; /* incremented when superblock updated */
+ __le64 resync_offset; /* data before this offset (from data_offset) known to be in sync */
+ __le32 sb_csum; /* checksum upto devs[max_dev] */
+ __le32 max_dev; /* size of devs[] array to consider */
__u8 pad3[64-32]; /* set to 0 when writing */
/* device state information. Indexed by dev_number.
@@ -260,7 +260,7 @@ struct mdp_superblock_1 {
* into the 'roles' value. If a device is spare or faulty, then it doesn't
* have a meaningful role.
*/
- __u16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
+ __le16 dev_roles[0]; /* role in array, or 0xffff for a spare, or 0xfffe for faulty */
};
/* feature_map bits */
diff --git a/include/linux/raid/md_u.h b/include/linux/raid/md_u.h
index 81da20ccec4d..7192035fc4b0 100644
--- a/include/linux/raid/md_u.h
+++ b/include/linux/raid/md_u.h
@@ -41,7 +41,7 @@
/* usage */
#define RUN_ARRAY _IOW (MD_MAJOR, 0x30, mdu_param_t)
-#define START_ARRAY _IO (MD_MAJOR, 0x31)
+/* 0x31 was START_ARRAY */
#define STOP_ARRAY _IO (MD_MAJOR, 0x32)
#define STOP_ARRAY_RO _IO (MD_MAJOR, 0x33)
#define RESTART_ARRAY_RW _IO (MD_MAJOR, 0x34)
diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h
index 3009c813d83d..0a9ba7c3302e 100644
--- a/include/linux/raid/raid1.h
+++ b/include/linux/raid/raid1.h
@@ -30,7 +30,6 @@ struct r1_private_data_s {
mddev_t *mddev;
mirror_info_t *mirrors;
int raid_disks;
- int working_disks;
int last_used;
sector_t next_seq_sect;
spinlock_t device_lock;
diff --git a/include/linux/raid/raid10.h b/include/linux/raid/raid10.h
index c41e56a7c090..e9091cfeb286 100644
--- a/include/linux/raid/raid10.h
+++ b/include/linux/raid/raid10.h
@@ -16,7 +16,6 @@ struct r10_private_data_s {
mddev_t *mddev;
mirror_info_t *mirrors;
int raid_disks;
- int working_disks;
spinlock_t device_lock;
/* geometry */
diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h
index 20ed4c997636..f13299a15591 100644
--- a/include/linux/raid/raid5.h
+++ b/include/linux/raid/raid5.h
@@ -195,8 +195,9 @@ struct stripe_head {
* it to the count of prereading stripes.
* When write is initiated, or the stripe refcnt == 0 (just in case) we
* clear the PREREAD_ACTIVE flag and decrement the count
- * Whenever the delayed queue is empty and the device is not plugged, we
- * move any strips from delayed to handle and clear the DELAYED flag and set PREREAD_ACTIVE.
+ * Whenever the 'handle' queue is empty and the device is not plugged, we
+ * move any strips from delayed to handle and clear the DELAYED flag and set
+ * PREREAD_ACTIVE.
* In stripe_handle, if we find pre-reading is necessary, we do it if
* PREREAD_ACTIVE is set, else we set DELAYED which will send it to the delayed queue.
* HANDLE gets cleared if stripe_handle leave nothing locked.
@@ -213,7 +214,7 @@ struct raid5_private_data {
struct disk_info *spare;
int chunk_size, level, algorithm;
int max_degraded;
- int raid_disks, working_disks, failed_disks;
+ int raid_disks;
int max_nr_stripes;
/* used during an expand */
diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h
index d0dd38b3a2fd..d22ad392242a 100644
--- a/include/linux/raid_class.h
+++ b/include/linux/raid_class.h
@@ -77,5 +77,6 @@ DEFINE_RAID_ATTRIBUTE(enum raid_state, state)
struct raid_template *raid_class_attach(struct raid_function_template *);
void raid_class_release(struct raid_template *);
-void raid_component_add(struct raid_template *, struct device *,
- struct device *);
+int __must_check raid_component_add(struct raid_template *, struct device *,
+ struct device *);
+
diff --git a/include/linux/ramfs.h b/include/linux/ramfs.h
index 00b340ba6612..b160fb18e8d6 100644
--- a/include/linux/ramfs.h
+++ b/include/linux/ramfs.h
@@ -17,5 +17,6 @@ extern int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma);
extern const struct file_operations ramfs_file_operations;
extern struct vm_operations_struct generic_file_vm_ops;
+extern int __init init_rootfs(void);
#endif
diff --git a/include/linux/random.h b/include/linux/random.h
index 5d6456bcdeba..0248b30e306d 100644
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -69,6 +69,9 @@ extern struct file_operations random_fops, urandom_fops;
unsigned int get_random_int(void);
unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
+u32 random32(void);
+void srandom32(u32 seed);
+
#endif /* __KERNEL___ */
#endif /* _LINUX_RANDOM_H */
diff --git a/include/linux/rbtree.h b/include/linux/rbtree.h
index 8d5382e62c08..344bc3495ddb 100644
--- a/include/linux/rbtree.h
+++ b/include/linux/rbtree.h
@@ -133,7 +133,7 @@ static inline void rb_set_color(struct rb_node *rb, int color)
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
-#define RB_EMPTY_NODE(node) (rb_parent(node) != node)
+#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
extern void rb_insert_color(struct rb_node *, struct rb_root *);
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index b4ca73d65891..c6b7485eac7c 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -19,7 +19,7 @@
*
* Author: Dipankar Sarma <dipankar@in.ibm.com>
*
- * Based on the original work by Paul McKenney <paul.mckenney@us.ibm.com>
+ * Based on the original work by Paul McKenney <paulmck@us.ibm.com>
* and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen.
* Papers:
* http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf
@@ -66,6 +66,8 @@ struct rcu_ctrlblk {
long completed; /* Number of the last completed batch */
int next_pending; /* Is the next batch already waiting? */
+ int signaled;
+
spinlock_t lock ____cacheline_internodealigned_in_smp;
cpumask_t cpumask; /* CPUs that need to switch in order */
/* for current batch to proceed. */
@@ -106,9 +108,6 @@ struct rcu_data {
long blimit; /* Upper limit on a processed batch */
int cpu;
struct rcu_head barrier;
-#ifdef CONFIG_SMP
- long last_rs_qlen; /* qlen during the last resched */
-#endif
};
DECLARE_PER_CPU(struct rcu_data, rcu_data);
diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h
index 806ec5b06707..fe00f781a622 100644
--- a/include/linux/reiserfs_acl.h
+++ b/include/linux/reiserfs_acl.h
@@ -56,6 +56,16 @@ extern int reiserfs_xattr_posix_acl_init(void) __init;
extern int reiserfs_xattr_posix_acl_exit(void);
extern struct reiserfs_xattr_handler posix_acl_default_handler;
extern struct reiserfs_xattr_handler posix_acl_access_handler;
+
+static inline void reiserfs_init_acl_access(struct inode *inode)
+{
+ REISERFS_I(inode)->i_acl_access = NULL;
+}
+
+static inline void reiserfs_init_acl_default(struct inode *inode)
+{
+ REISERFS_I(inode)->i_acl_default = NULL;
+}
#else
#define reiserfs_cache_default_acl(inode) 0
@@ -87,4 +97,11 @@ reiserfs_inherit_default_acl(const struct inode *dir, struct dentry *dentry,
return 0;
}
+static inline void reiserfs_init_acl_access(struct inode *inode)
+{
+}
+
+static inline void reiserfs_init_acl_default(struct inode *inode)
+{
+}
#endif
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 28493ffaafe7..7bc6bfb86253 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -807,21 +807,19 @@ struct stat_data_v1 {
#define set_sd_v1_first_direct_byte(sdp,v) \
((sdp)->sd_first_direct_byte = cpu_to_le32(v))
-#include <linux/ext2_fs.h>
-
/* inode flags stored in sd_attrs (nee sd_reserved) */
/* we want common flags to have the same values as in ext2,
so chattr(1) will work without problems */
-#define REISERFS_IMMUTABLE_FL EXT2_IMMUTABLE_FL
-#define REISERFS_APPEND_FL EXT2_APPEND_FL
-#define REISERFS_SYNC_FL EXT2_SYNC_FL
-#define REISERFS_NOATIME_FL EXT2_NOATIME_FL
-#define REISERFS_NODUMP_FL EXT2_NODUMP_FL
-#define REISERFS_SECRM_FL EXT2_SECRM_FL
-#define REISERFS_UNRM_FL EXT2_UNRM_FL
-#define REISERFS_COMPR_FL EXT2_COMPR_FL
-#define REISERFS_NOTAIL_FL EXT2_NOTAIL_FL
+#define REISERFS_IMMUTABLE_FL FS_IMMUTABLE_FL
+#define REISERFS_APPEND_FL FS_APPEND_FL
+#define REISERFS_SYNC_FL FS_SYNC_FL
+#define REISERFS_NOATIME_FL FS_NOATIME_FL
+#define REISERFS_NODUMP_FL FS_NODUMP_FL
+#define REISERFS_SECRM_FL FS_SECRM_FL
+#define REISERFS_UNRM_FL FS_UNRM_FL
+#define REISERFS_COMPR_FL FS_COMPR_FL
+#define REISERFS_NOTAIL_FL FS_NOTAIL_FL
/* persistent flags that file inherits from the parent directory */
#define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \
@@ -2075,6 +2073,10 @@ void reiserfs_init_alloc_options(struct super_block *s);
*/
__le32 reiserfs_choose_packing(struct inode *dir);
+int reiserfs_init_bitmap_cache(struct super_block *sb);
+void reiserfs_free_bitmap_cache(struct super_block *sb);
+void reiserfs_cache_bitmap_metadata(struct super_block *sb, struct buffer_head *bh, struct reiserfs_bitmap_info *info);
+struct buffer_head *reiserfs_read_bitmap_block(struct super_block *sb, unsigned int bitmap);
int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *,
b_blocknr_t, int for_unformatted);
@@ -2163,15 +2165,24 @@ __u32 r5_hash(const signed char *msg, int len);
/* prototypes from ioctl.c */
int reiserfs_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+long reiserfs_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg);
/* ioctl's command */
#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
/* define following flags to be the same as in ext2, so that chattr(1),
lsattr(1) will work with us. */
-#define REISERFS_IOC_GETFLAGS EXT2_IOC_GETFLAGS
-#define REISERFS_IOC_SETFLAGS EXT2_IOC_SETFLAGS
-#define REISERFS_IOC_GETVERSION EXT2_IOC_GETVERSION
-#define REISERFS_IOC_SETVERSION EXT2_IOC_SETVERSION
+#define REISERFS_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define REISERFS_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define REISERFS_IOC_GETVERSION FS_IOC_GETVERSION
+#define REISERFS_IOC_SETVERSION FS_IOC_SETVERSION
+
+/* the 32 bit compat definitions with int argument */
+#define REISERFS_IOC32_UNPACK _IOW(0xCD, 1, int)
+#define REISERFS_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define REISERFS_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define REISERFS_IOC32_GETVERSION FS_IOC32_GETVERSION
+#define REISERFS_IOC32_SETVERSION FS_IOC32_SETVERSION
/* Locking primitives */
/* Right now we are still falling back to (un)lock_kernel, but eventually that
diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
index 149be8d9a0c9..5b3b297aa2c5 100644
--- a/include/linux/reiserfs_fs_i.h
+++ b/include/linux/reiserfs_fs_i.h
@@ -52,10 +52,13 @@ struct reiserfs_inode_info {
** flushed */
unsigned long i_trans_id;
struct reiserfs_journal_list *i_jl;
-
+#ifdef CONFIG_REISERFS_FS_POSIX_ACL
struct posix_acl *i_acl_access;
struct posix_acl *i_acl_default;
+#endif
+#ifdef CONFIG_REISERFS_FS_XATTR
struct rw_semaphore xattr_sem;
+#endif
struct inode vfs_inode;
};
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 31b4c0bd4fa0..73e0becec086 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -267,7 +267,6 @@ struct reiserfs_bitmap_info {
// FIXME: Won't work with block sizes > 8K
__u16 first_zero_hint;
__u16 free_count;
- struct buffer_head *bh; /* the actual bitmap */
};
struct proc_dir_entry;
@@ -414,6 +413,7 @@ struct reiserfs_sb_info {
/* Definitions of reiserfs on-disk properties: */
#define REISERFS_3_5 0
#define REISERFS_3_6 1
+#define REISERFS_OLD_FORMAT 2
enum reiserfs_mount_options {
/* Mount options */
diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h
index 5e961035c725..966c35851b2e 100644
--- a/include/linux/reiserfs_xattr.h
+++ b/include/linux/reiserfs_xattr.h
@@ -97,6 +97,11 @@ static inline void reiserfs_mark_inode_private(struct inode *inode)
inode->i_flags |= S_PRIVATE;
}
+static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
+{
+ init_rwsem(&REISERFS_I(inode)->xattr_sem);
+}
+
#else
#define is_reiserfs_priv_object(inode) 0
@@ -129,6 +134,9 @@ static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags)
sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */
return 0;
};
+static inline void reiserfs_init_xattr_rwsem(struct inode *inode)
+{
+}
#endif
#endif /* __KERNEL__ */
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index 5371e4e74595..09ff4c3e2713 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -141,7 +141,7 @@ struct rtc_device
int id;
char name[RTC_DEVICE_NAME_SIZE];
- struct rtc_class_ops *ops;
+ const struct rtc_class_ops *ops;
struct mutex ops_lock;
struct class_device *rtc_dev;
@@ -172,7 +172,7 @@ struct rtc_device
extern struct rtc_device *rtc_device_register(const char *name,
struct device *dev,
- struct rtc_class_ops *ops,
+ const struct rtc_class_ops *ops,
struct module *owner);
extern void rtc_device_unregister(struct rtc_device *rdev);
extern int rtc_interface_register(struct class_interface *intf);
@@ -208,7 +208,7 @@ int rtc_register(rtc_task_t *task);
int rtc_unregister(rtc_task_t *task);
int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg);
void rtc_get_rtc_time(struct rtc_time *rtc_tm);
-irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t rtc_interrupt(int irq, void *dev_id);
#endif /* __KERNEL__ */
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 9c92dc8b9a08..3a18addaed4c 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -2,7 +2,7 @@
#define __LINUX_RTNETLINK_H
#include <linux/netlink.h>
-#include <linux/if.h>
+#include <linux/if_link.h>
/****
* Routing/neighbour discovery messages.
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 9d4aa7f95bc8..6735c1cf334c 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -24,6 +24,8 @@
#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */
#define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */
#define CLONE_STOPPED 0x02000000 /* Start in stopped state */
+#define CLONE_NEWUTS 0x04000000 /* New utsname group? */
+#define CLONE_NEWIPC 0x08000000 /* New ipcs */
/*
* Scheduling policies
@@ -118,7 +120,6 @@ extern unsigned long avenrun[]; /* Load averages */
extern unsigned long total_forks;
extern int nr_threads;
-extern int last_pid;
DECLARE_PER_CPU(unsigned long, process_counts);
extern int nr_processes(void);
extern unsigned long nr_running(void);
@@ -148,6 +149,7 @@ extern unsigned long weighted_cpuload(const int cpu);
#define EXIT_DEAD 32
/* in tsk->state again */
#define TASK_NONINTERACTIVE 64
+#define TASK_DEAD 128
#define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0)
@@ -238,7 +240,7 @@ extern signed long schedule_timeout_interruptible(signed long timeout);
extern signed long schedule_timeout_uninterruptible(signed long timeout);
asmlinkage void schedule(void);
-struct namespace;
+struct nsproxy;
/* Maximum number of active map areas.. This is a random (large) number */
#define DEFAULT_MAX_MAP_COUNT 65536
@@ -504,8 +506,8 @@ struct signal_struct {
#define rt_prio(prio) unlikely((prio) < MAX_RT_PRIO)
#define rt_task(p) rt_prio((p)->prio)
#define batch_task(p) (unlikely((p)->policy == SCHED_BATCH))
-#define has_rt_policy(p) \
- unlikely((p)->policy != SCHED_NORMAL && (p)->policy != SCHED_BATCH)
+#define is_rt_policy(p) ((p) != SCHED_NORMAL && (p) != SCHED_BATCH)
+#define has_rt_policy(p) unlikely(is_rt_policy((p)->policy))
/*
* Some day this will be a full-fledged user tracking system..
@@ -623,9 +625,17 @@ enum idle_type
#define SD_WAKE_BALANCE 64 /* Perform balancing at task wakeup */
#define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */
#define SD_POWERSAVINGS_BALANCE 256 /* Balance for power savings */
+#define SD_SHARE_PKG_RESOURCES 512 /* Domain members share cpu pkg resources */
-#define BALANCE_FOR_POWER ((sched_mc_power_savings || sched_smt_power_savings) \
- ? SD_POWERSAVINGS_BALANCE : 0)
+#define BALANCE_FOR_MC_POWER \
+ (sched_smt_power_savings ? SD_POWERSAVINGS_BALANCE : 0)
+
+#define BALANCE_FOR_PKG_POWER \
+ ((sched_mc_power_savings || sched_smt_power_savings) ? \
+ SD_POWERSAVINGS_BALANCE : 0)
+
+#define test_sd_parent(sd, flag) ((sd->parent && \
+ (sd->parent->flags & flag)) ? 1 : 0)
struct sched_group {
@@ -642,6 +652,7 @@ struct sched_group {
struct sched_domain {
/* These fields must be setup */
struct sched_domain *parent; /* top domain must be null terminated */
+ struct sched_domain *child; /* bottom domain must be null terminated */
struct sched_group *groups; /* the balancing groups of the domain */
cpumask_t span; /* span of all CPUs in this domain */
unsigned long min_interval; /* Minimum balance interval ms */
@@ -709,7 +720,6 @@ extern unsigned int max_cache_size;
struct io_context; /* See blkdev.h */
-void exit_io_context(void);
struct cpuset;
#define NGROUPS_SMALL 32
@@ -754,6 +764,7 @@ static inline void prefetch_stack(struct task_struct *t) { }
struct audit_context; /* See audit.c */
struct mempolicy;
struct pipe_inode_info;
+struct uts_namespace;
enum sleep_type {
SLEEP_NORMAL,
@@ -784,8 +795,9 @@ struct task_struct {
struct prio_array *array;
unsigned short ioprio;
+#ifdef CONFIG_BLK_DEV_IO_TRACE
unsigned int btrace_seq;
-
+#endif
unsigned long sleep_avg;
unsigned long long timestamp, last_ran;
unsigned long long sched_time; /* sched_clock time spent running */
@@ -886,16 +898,18 @@ struct task_struct {
- initialized normally by flush_old_exec */
/* file system info */
int link_count, total_link_count;
+#ifdef CONFIG_SYSVIPC
/* ipc stuff */
struct sysv_sem sysvsem;
+#endif
/* CPU-specific state of this task */
struct thread_struct thread;
/* filesystem information */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
-/* namespace */
- struct namespace *namespace;
+/* namespaces */
+ struct nsproxy *nsproxy;
/* signal handlers */
struct signal_struct *signal;
struct sighand_struct *sighand;
@@ -978,10 +992,10 @@ struct task_struct {
wait_queue_t *io_wait;
/* i/o counters(bytes read/written, #syscalls */
u64 rchar, wchar, syscr, syscw;
-#if defined(CONFIG_BSD_PROCESS_ACCT)
+#if defined(CONFIG_TASK_XACCT)
u64 acct_rss_mem1; /* accumulated rss usage */
u64 acct_vm_mem1; /* accumulated virtual memory usage */
- clock_t acct_stimexpd; /* clock_t-converted stime since last update */
+ cputime_t acct_stimexpd;/* stime since last update */
#endif
#ifdef CONFIG_NUMA
struct mempolicy *mempolicy;
@@ -1017,6 +1031,26 @@ static inline pid_t process_group(struct task_struct *tsk)
return tsk->signal->pgrp;
}
+static inline struct pid *task_pid(struct task_struct *task)
+{
+ return task->pids[PIDTYPE_PID].pid;
+}
+
+static inline struct pid *task_tgid(struct task_struct *task)
+{
+ return task->group_leader->pids[PIDTYPE_PID].pid;
+}
+
+static inline struct pid *task_pgrp(struct task_struct *task)
+{
+ return task->group_leader->pids[PIDTYPE_PGID].pid;
+}
+
+static inline struct pid *task_session(struct task_struct *task)
+{
+ return task->group_leader->pids[PIDTYPE_SID].pid;
+}
+
/**
* pid_alive - check that a task structure is not stale
* @p: Task structure to be checked.
@@ -1030,6 +1064,19 @@ static inline int pid_alive(struct task_struct *p)
return p->pids[PIDTYPE_PID].pid != NULL;
}
+/**
+ * is_init - check if a task structure is init
+ * @tsk: Task structure to be checked.
+ *
+ * Check if a task structure is the first user space task the kernel created.
+ */
+static inline int is_init(struct task_struct *tsk)
+{
+ return tsk->pid == 1;
+}
+
+extern struct pid *cad_pid;
+
extern void free_task(struct task_struct *tsk);
#define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0)
@@ -1048,7 +1095,6 @@ static inline void put_task_struct(struct task_struct *t)
/* Not implemented yet, only for 486*/
#define PF_STARTING 0x00000002 /* being created */
#define PF_EXITING 0x00000004 /* getting shut down */
-#define PF_DEAD 0x00000008 /* Dead */
#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */
#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */
#define PF_DUMPCORE 0x00000200 /* dumped core */
@@ -1193,7 +1239,7 @@ extern void switch_uid(struct user_struct *);
#include <asm/current.h>
-extern void do_timer(struct pt_regs *);
+extern void do_timer(unsigned long ticks);
extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state));
extern int FASTCALL(wake_up_process(struct task_struct * tsk));
@@ -1235,10 +1281,15 @@ extern int send_sig_info(int, struct siginfo *, struct task_struct *);
extern int send_group_sig_info(int, struct siginfo *, struct task_struct *);
extern int force_sigsegv(int, struct task_struct *);
extern int force_sig_info(int, struct siginfo *, struct task_struct *);
+extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
+extern int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
+extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid);
+extern int kill_pid_info_as_uid(int, struct siginfo *, struct pid *, uid_t, uid_t, u32);
+extern int kill_pgrp(struct pid *pid, int sig, int priv);
+extern int kill_pid(struct pid *pid, int sig, int priv);
extern int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp);
extern int kill_pg_info(int, struct siginfo *, pid_t);
extern int kill_proc_info(int, struct siginfo *, pid_t);
-extern int kill_proc_info_as_uid(int, struct siginfo *, pid_t, uid_t, uid_t, u32);
extern void do_notify_parent(struct task_struct *, int);
extern void force_sig(int, struct task_struct *);
extern void force_sig_specific(int, struct task_struct *);
@@ -1253,6 +1304,11 @@ extern int send_group_sigqueue(int, struct sigqueue *, struct task_struct *);
extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
+static inline int kill_cad_pid(int sig, int priv)
+{
+ return kill_pid(cad_pid, sig, priv);
+}
+
/* These can be the second arg to send_sig_info/send_group_sig_info. */
#define SEND_SIG_NOINFO ((struct siginfo *) 0)
#define SEND_SIG_PRIV ((struct siginfo *) 1)
@@ -1346,6 +1402,17 @@ extern void wait_task_inactive(struct task_struct * p);
/* de_thread depends on thread_group_leader not being a pid based check */
#define thread_group_leader(p) (p == p->group_leader)
+/* Do to the insanities of de_thread it is possible for a process
+ * to have the pid of the thread group leader without actually being
+ * the thread group leader. For iteration through the pids in proc
+ * all we care about is that we have a task with the appropriate
+ * pid, we don't actually care if we have the right task.
+ */
+static inline int has_group_leader_pid(struct task_struct *p)
+{
+ return p->pid == p->tgid;
+}
+
static inline struct task_struct *next_thread(const struct task_struct *p)
{
return list_entry(rcu_dereference(p->thread_group.next),
diff --git a/include/linux/scx200.h b/include/linux/scx200.h
index 693c0557e70b..de466e11e271 100644
--- a/include/linux/scx200.h
+++ b/include/linux/scx200.h
@@ -32,7 +32,7 @@ extern unsigned scx200_cb_base;
/* High Resolution Timer */
#define SCx200_TIMER_OFFSET 0x08
-#define SCx200_TIMER_SIZE 0x05
+#define SCx200_TIMER_SIZE 0x06
/* Clock Generators */
#define SCx200_CLOCKGEN_OFFSET 0x10
diff --git a/include/linux/scx200_gpio.h b/include/linux/scx200_gpio.h
index 90dd069cc145..1a82d30c4b17 100644
--- a/include/linux/scx200_gpio.h
+++ b/include/linux/scx200_gpio.h
@@ -4,6 +4,7 @@ u32 scx200_gpio_configure(unsigned index, u32 set, u32 clear);
extern unsigned scx200_gpio_base;
extern long scx200_gpio_shadow[2];
+extern struct nsc_gpio_ops scx200_gpio_ops;
#define scx200_gpio_present() (scx200_gpio_base!=0)
diff --git a/include/linux/security.h b/include/linux/security.h
index 9f56fb8a4a6c..b200b9856f32 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -882,7 +882,8 @@ struct request_sock;
* Check permission when a flow selects a xfrm_policy for processing
* XFRMs on a packet. The hook is called when selecting either a
* per-socket policy or a generic xfrm policy.
- * Return 0 if permission is granted.
+ * Return 0 if permission is granted, -ESRCH otherwise, or -errno
+ * on other errors.
* @xfrm_state_pol_flow_match:
* @x contains the state to match.
* @xp contains the policy to check for a match.
@@ -891,6 +892,7 @@ struct request_sock;
* @xfrm_flow_state_match:
* @fl contains the flow key to match.
* @xfrm points to the xfrm_state to match.
+ * @xp points to the xfrm_policy to match.
* Return 1 if there is a match.
* @xfrm_decode_session:
* @skb points to skb to decode.
@@ -1388,7 +1390,8 @@ struct security_operations {
int (*xfrm_policy_lookup)(struct xfrm_policy *xp, u32 fl_secid, u8 dir);
int (*xfrm_state_pol_flow_match)(struct xfrm_state *x,
struct xfrm_policy *xp, struct flowi *fl);
- int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm);
+ int (*xfrm_flow_state_match)(struct flowi *fl, struct xfrm_state *xfrm,
+ struct xfrm_policy *xp);
int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall);
#endif /* CONFIG_SECURITY_NETWORK_XFRM */
@@ -1595,6 +1598,7 @@ static inline void security_sb_post_pivotroot (struct nameidata *old_nd,
static inline int security_inode_alloc (struct inode *inode)
{
+ inode->i_security = NULL;
return security_ops->inode_alloc_security (inode);
}
@@ -3119,11 +3123,6 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm
return security_ops->xfrm_policy_alloc_security(xp, sec_ctx, NULL);
}
-static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk)
-{
- return security_ops->xfrm_policy_alloc_security(xp, NULL, sk);
-}
-
static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new)
{
return security_ops->xfrm_policy_clone_security(old, new);
@@ -3174,9 +3173,10 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
return security_ops->xfrm_state_pol_flow_match(x, xp, fl);
}
-static inline int security_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm)
+static inline int security_xfrm_flow_state_match(struct flowi *fl,
+ struct xfrm_state *xfrm, struct xfrm_policy *xp)
{
- return security_ops->xfrm_flow_state_match(fl, xfrm);
+ return security_ops->xfrm_flow_state_match(fl, xfrm, xp);
}
static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid)
@@ -3196,11 +3196,6 @@ static inline int security_xfrm_policy_alloc(struct xfrm_policy *xp, struct xfrm
return 0;
}
-static inline int security_xfrm_sock_policy_alloc(struct xfrm_policy *xp, struct sock *sk)
-{
- return 0;
-}
-
static inline int security_xfrm_policy_clone(struct xfrm_policy *old, struct xfrm_policy *new)
{
return 0;
@@ -3248,7 +3243,7 @@ static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x,
}
static inline int security_xfrm_flow_state_match(struct flowi *fl,
- struct xfrm_state *xfrm)
+ struct xfrm_state *xfrm, struct xfrm_policy *xp)
{
return 1;
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 86501a3de2ac..463ab953b092 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -67,8 +67,8 @@
/* Parisc type numbers. */
#define PORT_MUX 48
-/* Atmel AT91xxx SoC */
-#define PORT_AT91 49
+/* Atmel AT91 / AT32 SoC */
+#define PORT_ATMEL 49
/* Macintosh Zilog type numbers */
#define PORT_MAC_ZILOG 50 /* m68k : not yet implemented */
@@ -319,6 +319,7 @@ struct uart_info {
#define UIF_CTS_FLOW ((__force uif_t) (1 << 26))
#define UIF_NORMAL_ACTIVE ((__force uif_t) (1 << 29))
#define UIF_INITIALIZED ((__force uif_t) (1 << 31))
+#define UIF_SUSPENDED ((__force uif_t) (1 << 30))
int blocked_open;
@@ -408,13 +409,12 @@ int uart_resume_port(struct uart_driver *reg, struct uart_port *port);
* The following are helper functions for the low level drivers.
*/
static inline int
-uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
- struct pt_regs *regs)
+uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
{
#ifdef SUPPORT_SYSRQ
if (port->sysrq) {
if (ch && time_before(jiffies, port->sysrq)) {
- handle_sysrq(ch, regs, NULL);
+ handle_sysrq(ch, port->info->tty);
port->sysrq = 0;
return 1;
}
@@ -424,7 +424,7 @@ uart_handle_sysrq_char(struct uart_port *port, unsigned int ch,
return 0;
}
#ifndef SUPPORT_SYSRQ
-#define uart_handle_sysrq_char(port,ch,regs) uart_handle_sysrq_char(port, 0, NULL)
+#define uart_handle_sysrq_char(port,ch) uart_handle_sysrq_char(port, 0)
#endif
/*
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 6348e8330897..b99c5ca9708d 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -41,6 +41,7 @@ struct serio {
void (*stop)(struct serio *);
struct serio *parent, *child;
+ unsigned int depth; /* level of nesting in serio hierarchy */
struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */
struct mutex drv_mutex; /* protects serio->drv so attributes can pin driver */
@@ -60,8 +61,7 @@ struct serio_driver {
unsigned int manual_bind;
void (*write_wakeup)(struct serio *);
- irqreturn_t (*interrupt)(struct serio *, unsigned char,
- unsigned int, struct pt_regs *);
+ irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int);
int (*connect)(struct serio *, struct serio_driver *drv);
int (*reconnect)(struct serio *);
void (*disconnect)(struct serio *);
@@ -75,7 +75,7 @@ int serio_open(struct serio *serio, struct serio_driver *drv);
void serio_close(struct serio *serio);
void serio_rescan(struct serio *serio);
void serio_reconnect(struct serio *serio);
-irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags, struct pt_regs *regs);
+irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags);
void __serio_register_port(struct serio *serio, struct module *owner);
static inline void serio_register_port(struct serio *serio)
@@ -217,5 +217,8 @@ static inline void serio_unpin_driver(struct serio *serio)
#define SERIO_LKKBD 0x28
#define SERIO_ELO 0x29
#define SERIO_MICROTOUCH 0x30
+#define SERIO_PENMOUNT 0x31
+#define SERIO_TOUCHRIGHT 0x32
+#define SERIO_TOUCHWIN 0x33
#endif
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index c057f0b32318..f3c51899117f 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -19,6 +19,10 @@ struct shmem_inode_info {
swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* first blocks */
struct list_head swaplist; /* chain of maybes on swap */
struct inode vfs_inode;
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ struct posix_acl *i_acl;
+ struct posix_acl *i_default_acl;
+#endif
};
struct shmem_sb_info {
@@ -36,4 +40,24 @@ static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
return container_of(inode, struct shmem_inode_info, vfs_inode);
}
+#ifdef CONFIG_TMPFS_POSIX_ACL
+int shmem_permission(struct inode *, int, struct nameidata *);
+int shmem_acl_init(struct inode *, struct inode *);
+void shmem_acl_destroy_inode(struct inode *);
+
+extern struct xattr_handler shmem_xattr_acl_access_handler;
+extern struct xattr_handler shmem_xattr_acl_default_handler;
+
+extern struct generic_acl_operations shmem_acl_ops;
+
+#else
+static inline int shmem_acl_init(struct inode *inode, struct inode *dir)
+{
+ return 0;
+}
+static inline void shmem_acl_destroy_inode(struct inode *inode)
+{
+}
+#endif /* CONFIG_TMPFS_POSIX_ACL */
+
#endif
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 66d6eb78d1c6..c4947b8a2c03 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -1,5 +1,5 @@
/*
- * linux/mm/slab.h
+ * linux/include/linux/slab.h
* Written by Mark Hemment, 1996.
* (markhe@nextd.demon.co.uk)
*/
@@ -60,7 +60,7 @@ extern void __init kmem_cache_init(void);
extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
void (*)(void *, kmem_cache_t *, unsigned long),
void (*)(void *, kmem_cache_t *, unsigned long));
-extern int kmem_cache_destroy(kmem_cache_t *);
+extern void kmem_cache_destroy(kmem_cache_t *);
extern int kmem_cache_shrink(kmem_cache_t *);
extern void *kmem_cache_alloc(kmem_cache_t *, gfp_t);
extern void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
@@ -77,13 +77,6 @@ struct cache_sizes {
extern struct cache_sizes malloc_sizes[];
extern void *__kmalloc(size_t, gfp_t);
-#ifndef CONFIG_DEBUG_SLAB
-#define ____kmalloc(size, flags) __kmalloc(size, flags)
-#else
-extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
-#define ____kmalloc(size, flags) \
- __kmalloc_track_caller(size, flags, __builtin_return_address(0))
-#endif
/**
* kmalloc - allocate memory
@@ -153,6 +146,23 @@ found:
return __kmalloc(size, flags);
}
+/*
+ * kmalloc_track_caller is a special version of kmalloc that records the
+ * calling function of the routine calling it for slab leak tracking instead
+ * of just the calling function (confusing, eh?).
+ * It's useful when the call to kmalloc comes from a widely-used standard
+ * allocator where we care about the real place the memory allocation
+ * request comes from.
+ */
+#ifndef CONFIG_DEBUG_SLAB
+#define kmalloc_track_caller(size, flags) \
+ __kmalloc(size, flags)
+#else
+extern void *__kmalloc_track_caller(size_t, gfp_t, void*);
+#define kmalloc_track_caller(size, flags) \
+ __kmalloc_track_caller(size, flags, __builtin_return_address(0))
+#endif
+
extern void *__kzalloc(size_t, gfp_t);
/**
@@ -249,7 +259,7 @@ struct kmem_cache *kmem_cache_create(const char *c, size_t, size_t,
unsigned long,
void (*)(void *, struct kmem_cache *, unsigned long),
void (*)(void *, struct kmem_cache *, unsigned long));
-int kmem_cache_destroy(struct kmem_cache *c);
+void kmem_cache_destroy(struct kmem_cache *c);
void *kmem_cache_alloc(struct kmem_cache *c, gfp_t flags);
void *kmem_cache_zalloc(struct kmem_cache *, gfp_t);
void kmem_cache_free(struct kmem_cache *c, void *b);
@@ -271,7 +281,7 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags)
#define kmem_cache_alloc_node(c, f, n) kmem_cache_alloc(c, f)
#define kmalloc_node(s, f, n) kmalloc(s, f)
#define kzalloc(s, f) __kzalloc(s, f)
-#define ____kmalloc kmalloc
+#define kmalloc_track_caller kmalloc
#endif /* CONFIG_SLOB */
diff --git a/include/linux/smb.h b/include/linux/smb.h
index 6df3b1501559..f098dff93f6b 100644
--- a/include/linux/smb.h
+++ b/include/linux/smb.h
@@ -89,7 +89,6 @@ struct smb_fattr {
struct timespec f_atime;
struct timespec f_mtime;
struct timespec f_ctime;
- unsigned long f_blksize;
unsigned long f_blocks;
int f_unix;
};
diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h
index 367d6c3e8ed4..13b3af547864 100644
--- a/include/linux/smb_fs.h
+++ b/include/linux/smb_fs.h
@@ -43,17 +43,17 @@ static inline struct smb_inode_info *SMB_I(struct inode *inode)
/* macro names are short for word, double-word, long value (?) */
#define WVAL(buf,pos) \
- (le16_to_cpu(get_unaligned((u16 *)((u8 *)(buf) + (pos)))))
+ (le16_to_cpu(get_unaligned((__le16 *)((u8 *)(buf) + (pos)))))
#define DVAL(buf,pos) \
- (le32_to_cpu(get_unaligned((u32 *)((u8 *)(buf) + (pos)))))
+ (le32_to_cpu(get_unaligned((__le32 *)((u8 *)(buf) + (pos)))))
#define LVAL(buf,pos) \
- (le64_to_cpu(get_unaligned((u64 *)((u8 *)(buf) + (pos)))))
+ (le64_to_cpu(get_unaligned((__le64 *)((u8 *)(buf) + (pos)))))
#define WSET(buf,pos,val) \
- put_unaligned(cpu_to_le16((u16)(val)), (u16 *)((u8 *)(buf) + (pos)))
+ put_unaligned(cpu_to_le16((u16)(val)), (__le16 *)((u8 *)(buf) + (pos)))
#define DSET(buf,pos,val) \
- put_unaligned(cpu_to_le32((u32)(val)), (u32 *)((u8 *)(buf) + (pos)))
+ put_unaligned(cpu_to_le32((u32)(val)), (__le32 *)((u8 *)(buf) + (pos)))
#define LSET(buf,pos,val) \
- put_unaligned(cpu_to_le64((u64)(val)), (u64 *)((u8 *)(buf) + (pos)))
+ put_unaligned(cpu_to_le64((u64)(val)), (__le64 *)((u8 *)(buf) + (pos)))
/* where to find the base of the SMB packet proper */
#define smb_base(buf) ((u8 *)(((u8 *)(buf))+4))
diff --git a/include/linux/sound.h b/include/linux/sound.h
index f63d8342ffa3..9e2a94feed6b 100644
--- a/include/linux/sound.h
+++ b/include/linux/sound.h
@@ -35,10 +35,8 @@ extern int register_sound_special_device(const struct file_operations *fops, int
extern int register_sound_mixer(const struct file_operations *fops, int dev);
extern int register_sound_midi(const struct file_operations *fops, int dev);
extern int register_sound_dsp(const struct file_operations *fops, int dev);
-extern int register_sound_synth(const struct file_operations *fops, int dev);
extern void unregister_sound_special(int unit);
extern void unregister_sound_mixer(int unit);
extern void unregister_sound_midi(int unit);
extern void unregister_sound_dsp(int unit);
-extern void unregister_sound_synth(int unit);
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index 31473db92d3b..b800d2d68b32 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -167,9 +167,9 @@ do { \
* regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various
* methods are defined as nops in the case they are not required.
*/
-#define spin_trylock(lock) __cond_lock(_spin_trylock(lock))
-#define read_trylock(lock) __cond_lock(_read_trylock(lock))
-#define write_trylock(lock) __cond_lock(_write_trylock(lock))
+#define spin_trylock(lock) __cond_lock(lock, _spin_trylock(lock))
+#define read_trylock(lock) __cond_lock(lock, _read_trylock(lock))
+#define write_trylock(lock) __cond_lock(lock, _write_trylock(lock))
#define spin_lock(lock) _spin_lock(lock)
@@ -236,19 +236,19 @@ do { \
_write_unlock_irqrestore(lock, flags)
#define write_unlock_bh(lock) _write_unlock_bh(lock)
-#define spin_trylock_bh(lock) __cond_lock(_spin_trylock_bh(lock))
+#define spin_trylock_bh(lock) __cond_lock(lock, _spin_trylock_bh(lock))
#define spin_trylock_irq(lock) \
({ \
local_irq_disable(); \
- _spin_trylock(lock) ? \
+ spin_trylock(lock) ? \
1 : ({ local_irq_enable(); 0; }); \
})
#define spin_trylock_irqsave(lock, flags) \
({ \
local_irq_save(flags); \
- _spin_trylock(lock) ? \
+ spin_trylock(lock) ? \
1 : ({ local_irq_restore(flags); 0; }); \
})
@@ -264,7 +264,7 @@ do { \
*/
extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock);
#define atomic_dec_and_lock(atomic, lock) \
- __cond_lock(_atomic_dec_and_lock(atomic, lock))
+ __cond_lock(lock, _atomic_dec_and_lock(atomic, lock))
/**
* spin_can_lock - would spin_trylock() succeed?
diff --git a/include/linux/spinlock_api_smp.h b/include/linux/spinlock_api_smp.h
index b2c4f8299464..8828b8155e9c 100644
--- a/include/linux/spinlock_api_smp.h
+++ b/include/linux/spinlock_api_smp.h
@@ -19,41 +19,41 @@ int in_lock_functions(unsigned long addr);
#define assert_spin_locked(x) BUG_ON(!spin_is_locked(x))
-void __lockfunc _spin_lock(spinlock_t *lock) __acquires(spinlock_t);
+void __lockfunc _spin_lock(spinlock_t *lock) __acquires(lock);
void __lockfunc _spin_lock_nested(spinlock_t *lock, int subclass)
- __acquires(spinlock_t);
-void __lockfunc _read_lock(rwlock_t *lock) __acquires(rwlock_t);
-void __lockfunc _write_lock(rwlock_t *lock) __acquires(rwlock_t);
-void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(spinlock_t);
-void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(rwlock_t);
-void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(rwlock_t);
-void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(spinlock_t);
-void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(rwlock_t);
-void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(rwlock_t);
+ __acquires(lock);
+void __lockfunc _read_lock(rwlock_t *lock) __acquires(lock);
+void __lockfunc _write_lock(rwlock_t *lock) __acquires(lock);
+void __lockfunc _spin_lock_bh(spinlock_t *lock) __acquires(lock);
+void __lockfunc _read_lock_bh(rwlock_t *lock) __acquires(lock);
+void __lockfunc _write_lock_bh(rwlock_t *lock) __acquires(lock);
+void __lockfunc _spin_lock_irq(spinlock_t *lock) __acquires(lock);
+void __lockfunc _read_lock_irq(rwlock_t *lock) __acquires(lock);
+void __lockfunc _write_lock_irq(rwlock_t *lock) __acquires(lock);
unsigned long __lockfunc _spin_lock_irqsave(spinlock_t *lock)
- __acquires(spinlock_t);
+ __acquires(lock);
unsigned long __lockfunc _read_lock_irqsave(rwlock_t *lock)
- __acquires(rwlock_t);
+ __acquires(lock);
unsigned long __lockfunc _write_lock_irqsave(rwlock_t *lock)
- __acquires(rwlock_t);
+ __acquires(lock);
int __lockfunc _spin_trylock(spinlock_t *lock);
int __lockfunc _read_trylock(rwlock_t *lock);
int __lockfunc _write_trylock(rwlock_t *lock);
int __lockfunc _spin_trylock_bh(spinlock_t *lock);
-void __lockfunc _spin_unlock(spinlock_t *lock) __releases(spinlock_t);
-void __lockfunc _read_unlock(rwlock_t *lock) __releases(rwlock_t);
-void __lockfunc _write_unlock(rwlock_t *lock) __releases(rwlock_t);
-void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(spinlock_t);
-void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(rwlock_t);
-void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(rwlock_t);
-void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(spinlock_t);
-void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(rwlock_t);
-void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(rwlock_t);
+void __lockfunc _spin_unlock(spinlock_t *lock) __releases(lock);
+void __lockfunc _read_unlock(rwlock_t *lock) __releases(lock);
+void __lockfunc _write_unlock(rwlock_t *lock) __releases(lock);
+void __lockfunc _spin_unlock_bh(spinlock_t *lock) __releases(lock);
+void __lockfunc _read_unlock_bh(rwlock_t *lock) __releases(lock);
+void __lockfunc _write_unlock_bh(rwlock_t *lock) __releases(lock);
+void __lockfunc _spin_unlock_irq(spinlock_t *lock) __releases(lock);
+void __lockfunc _read_unlock_irq(rwlock_t *lock) __releases(lock);
+void __lockfunc _write_unlock_irq(rwlock_t *lock) __releases(lock);
void __lockfunc _spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags)
- __releases(spinlock_t);
+ __releases(lock);
void __lockfunc _read_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
- __releases(rwlock_t);
+ __releases(lock);
void __lockfunc _write_unlock_irqrestore(rwlock_t *lock, unsigned long flags)
- __releases(rwlock_t);
+ __releases(lock);
#endif /* __LINUX_SPINLOCK_API_SMP_H */
diff --git a/include/linux/srcu.h b/include/linux/srcu.h
new file mode 100644
index 000000000000..aca0eee53930
--- /dev/null
+++ b/include/linux/srcu.h
@@ -0,0 +1,53 @@
+/*
+ * Sleepable Read-Copy Update mechanism for mutual exclusion
+ *
+ * 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) IBM Corporation, 2006
+ *
+ * Author: Paul McKenney <paulmck@us.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * Documentation/RCU/ *.txt
+ *
+ */
+
+#ifndef _LINUX_SRCU_H
+#define _LINUX_SRCU_H
+
+struct srcu_struct_array {
+ int c[2];
+};
+
+struct srcu_struct {
+ int completed;
+ struct srcu_struct_array *per_cpu_ref;
+ struct mutex mutex;
+};
+
+#ifndef CONFIG_PREEMPT
+#define srcu_barrier() barrier()
+#else /* #ifndef CONFIG_PREEMPT */
+#define srcu_barrier()
+#endif /* #else #ifndef CONFIG_PREEMPT */
+
+int init_srcu_struct(struct srcu_struct *sp);
+void cleanup_srcu_struct(struct srcu_struct *sp);
+int srcu_read_lock(struct srcu_struct *sp) __acquires(sp);
+void srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp);
+void synchronize_srcu(struct srcu_struct *sp);
+long srcu_batches_completed(struct srcu_struct *sp);
+
+#endif
diff --git a/include/linux/stat.h b/include/linux/stat.h
index 8669291352db..679ef0d70b6b 100644
--- a/include/linux/stat.h
+++ b/include/linux/stat.h
@@ -57,7 +57,7 @@
#include <linux/time.h>
struct kstat {
- unsigned long ino;
+ u64 ino;
dev_t dev;
umode_t mode;
unsigned int nlink;
diff --git a/include/linux/stddef.h b/include/linux/stddef.h
index ea65dfb60cd8..6a40c76bdcf1 100644
--- a/include/linux/stddef.h
+++ b/include/linux/stddef.h
@@ -11,6 +11,12 @@
#endif
#ifdef __KERNEL__
+
+enum {
+ false = 0,
+ true = 1
+};
+
#undef offsetof
#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
diff --git a/include/linux/string.h b/include/linux/string.h
index e4c755860316..4f69ef9e6eb5 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -99,6 +99,7 @@ extern void * memchr(const void *,int,__kernel_size_t);
#endif
extern char *kstrdup(const char *s, gfp_t gfp);
+extern void *kmemdup(const void *src, size_t len, gfp_t gfp);
#ifdef __cplusplus
}
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index a6de332e57d4..534cdc7be58d 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -20,9 +20,6 @@
/* size of the nodename buffer */
#define UNX_MAXNODENAME 32
-/* Maximum size (in bytes) of an rpc credential or verifier */
-#define RPC_MAX_AUTH_SIZE (400)
-
/* Work around the lack of a VFS credential */
struct auth_cred {
uid_t uid;
@@ -109,13 +106,13 @@ struct rpc_credops {
void (*crdestroy)(struct rpc_cred *);
int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
- u32 * (*crmarshal)(struct rpc_task *, u32 *);
+ __be32 * (*crmarshal)(struct rpc_task *, __be32 *);
int (*crrefresh)(struct rpc_task *);
- u32 * (*crvalidate)(struct rpc_task *, u32 *);
+ __be32 * (*crvalidate)(struct rpc_task *, __be32 *);
int (*crwrap_req)(struct rpc_task *, kxdrproc_t,
- void *, u32 *, void *);
+ void *, __be32 *, void *);
int (*crunwrap_resp)(struct rpc_task *, kxdrproc_t,
- void *, u32 *, void *);
+ void *, __be32 *, void *);
};
extern struct rpc_authops authunix_ops;
@@ -134,10 +131,10 @@ struct rpc_cred * rpcauth_bindcred(struct rpc_task *);
void rpcauth_holdcred(struct rpc_task *);
void put_rpccred(struct rpc_cred *);
void rpcauth_unbindcred(struct rpc_task *);
-u32 * rpcauth_marshcred(struct rpc_task *, u32 *);
-u32 * rpcauth_checkverf(struct rpc_task *, u32 *);
-int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, u32 *data, void *obj);
-int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, u32 *data, void *obj);
+__be32 * rpcauth_marshcred(struct rpc_task *, __be32 *);
+__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *);
+int rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp, __be32 *data, void *obj);
+int rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp, __be32 *data, void *obj);
int rpcauth_refreshcred(struct rpc_task *);
void rpcauth_invalcred(struct rpc_task *);
int rpcauth_uptodatecred(struct rpc_task *);
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h
index 03084dc4bb6a..97b62e97dd8d 100644
--- a/include/linux/sunrpc/auth_gss.h
+++ b/include/linux/sunrpc/auth_gss.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/auth_gss.h
+ * linux/include/linux/sunrpc/auth_gss.h
*
* Declarations for RPCSEC_GSS
*
diff --git a/include/linux/sunrpc/cache.h b/include/linux/sunrpc/cache.h
index b5612c958cce..3699dff7db8f 100644
--- a/include/linux/sunrpc/cache.h
+++ b/include/linux/sunrpc/cache.h
@@ -163,6 +163,17 @@ static inline void cache_put(struct cache_head *h, struct cache_detail *cd)
kref_put(&h->ref, cd->cache_put);
}
+static inline int cache_valid(struct cache_head *h)
+{
+ /* If an item has been unhashed pending removal when
+ * the refcount drops to 0, the expiry_time will be
+ * set to 0. We don't want to consider such items
+ * valid in this context even though CACHE_VALID is
+ * set.
+ */
+ return (h->expiry_time != 0 && test_bit(CACHE_VALID, &h->flags));
+}
+
extern int cache_check(struct cache_detail *detail,
struct cache_head *h, struct cache_req *rqstp);
extern void cache_flush(void);
diff --git a/include/linux/sunrpc/gss_api.h b/include/linux/sunrpc/gss_api.h
index 6e112cc5cdda..5eca9e442051 100644
--- a/include/linux/sunrpc/gss_api.h
+++ b/include/linux/sunrpc/gss_api.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/gss_api.h
+ * linux/include/linux/sunrpc/gss_api.h
*
* Somewhat simplified version of the gss api.
*
diff --git a/include/linux/sunrpc/msg_prot.h b/include/linux/sunrpc/msg_prot.h
index f43f237360ae..606cb2165232 100644
--- a/include/linux/sunrpc/msg_prot.h
+++ b/include/linux/sunrpc/msg_prot.h
@@ -1,5 +1,5 @@
/*
- * linux/include/net/sunrpc/msg_prot.h
+ * linux/include/linux/sunrpc/msg_prot.h
*
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
@@ -11,6 +11,9 @@
#define RPC_VERSION 2
+/* size of an XDR encoding unit in bytes, i.e. 32bit */
+#define XDR_UNIT (4)
+
/* spec defines authentication flavor as an unsigned 32 bit integer */
typedef u32 rpc_authflavor_t;
@@ -34,6 +37,9 @@ enum rpc_auth_flavors {
RPC_AUTH_GSS_SPKMP = 390011,
};
+/* Maximum size (in bytes) of an rpc credential or verifier */
+#define RPC_MAX_AUTH_SIZE (400)
+
enum rpc_msg_type {
RPC_CALL = 0,
RPC_REPLY = 1
@@ -50,7 +56,9 @@ enum rpc_accept_stat {
RPC_PROG_MISMATCH = 2,
RPC_PROC_UNAVAIL = 3,
RPC_GARBAGE_ARGS = 4,
- RPC_SYSTEM_ERR = 5
+ RPC_SYSTEM_ERR = 5,
+ /* internal use only */
+ RPC_DROP_REPLY = 60000,
};
enum rpc_reject_stat {
@@ -95,11 +103,45 @@ enum rpc_auth_stat {
* 2GB.
*/
-typedef u32 rpc_fraghdr;
+typedef __be32 rpc_fraghdr;
#define RPC_LAST_STREAM_FRAGMENT (1U << 31)
#define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT)
#define RPC_MAX_FRAGMENT_SIZE ((1U << 31) - 1)
+/*
+ * RPC call and reply header size as number of 32bit words (verifier
+ * size computed separately, see below)
+ */
+#define RPC_CALLHDRSIZE (6)
+#define RPC_REPHDRSIZE (4)
+
+
+/*
+ * Maximum RPC header size, including authentication,
+ * as number of 32bit words (see RFCs 1831, 1832).
+ *
+ * xid 1 xdr unit = 4 bytes
+ * mtype 1
+ * rpc_version 1
+ * program 1
+ * prog_version 1
+ * procedure 1
+ * cred {
+ * flavor 1
+ * length 1
+ * body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
+ * }
+ * verf {
+ * flavor 1
+ * length 1
+ * body<RPC_MAX_AUTH_SIZE> 100 xdr units = 400 bytes
+ * }
+ * TOTAL 210 xdr units = 840 bytes
+ */
+#define RPC_MAX_HEADER_WITH_AUTH \
+ (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4))
+
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_MSGPROT_H_ */
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index 7b27c09b5604..965d6c20086e 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -13,11 +13,36 @@
#include <linux/in.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/auth.h>
#include <linux/sunrpc/svcauth.h>
#include <linux/wait.h>
#include <linux/mm.h>
/*
+ * This is the RPC server thread function prototype
+ */
+typedef void (*svc_thread_fn)(struct svc_rqst *);
+
+/*
+ *
+ * RPC service thread pool.
+ *
+ * Pool of threads and temporary sockets. Generally there is only
+ * a single one of these per RPC service, but on NUMA machines those
+ * services that can benefit from it (i.e. nfs but not lockd) will
+ * have one pool per NUMA node. This optimisation reduces cross-
+ * node traffic on multi-node NUMA NFS servers.
+ */
+struct svc_pool {
+ unsigned int sp_id; /* pool id; also node id on NUMA */
+ spinlock_t sp_lock; /* protects all fields */
+ struct list_head sp_threads; /* idle server threads */
+ struct list_head sp_sockets; /* pending sockets */
+ unsigned int sp_nrthreads; /* # of threads in pool */
+ struct list_head sp_all_threads; /* all server threads */
+} ____cacheline_aligned_in_smp;
+
+/*
* RPC service.
*
* An RPC service is a ``daemon,'' possibly multithreaded, which
@@ -28,28 +53,72 @@
* We currently do not support more than one RPC program per daemon.
*/
struct svc_serv {
- struct list_head sv_threads; /* idle server threads */
- struct list_head sv_sockets; /* pending sockets */
struct svc_program * sv_program; /* RPC program */
struct svc_stat * sv_stats; /* RPC statistics */
spinlock_t sv_lock;
unsigned int sv_nrthreads; /* # of server threads */
- unsigned int sv_bufsz; /* datagram buffer size */
+ unsigned int sv_max_payload; /* datagram payload size */
+ unsigned int sv_max_mesg; /* max_payload + 1 page for overheads */
unsigned int sv_xdrsize; /* XDR buffer size */
struct list_head sv_permsocks; /* all permanent sockets */
struct list_head sv_tempsocks; /* all temporary sockets */
int sv_tmpcnt; /* count of temporary sockets */
+ struct timer_list sv_temptimer; /* timer for aging temporary sockets */
char * sv_name; /* service name */
+
+ unsigned int sv_nrpools; /* number of thread pools */
+ struct svc_pool * sv_pools; /* array of thread pools */
+
+ void (*sv_shutdown)(struct svc_serv *serv);
+ /* Callback to use when last thread
+ * exits.
+ */
+
+ struct module * sv_module; /* optional module to count when
+ * adding threads */
+ svc_thread_fn sv_function; /* main function for threads */
+ int sv_kill_signal; /* signal to kill threads */
};
/*
+ * We use sv_nrthreads as a reference count. svc_destroy() drops
+ * this refcount, so we need to bump it up around operations that
+ * change the number of threads. Horrible, but there it is.
+ * Should be called with the BKL held.
+ */
+static inline void svc_get(struct svc_serv *serv)
+{
+ serv->sv_nrthreads++;
+}
+
+/*
* Maximum payload size supported by a kernel RPC server.
* This is use to determine the max number of pages nfsd is
* willing to return in a single READ operation.
+ *
+ * These happen to all be powers of 2, which is not strictly
+ * necessary but helps enforce the real limitation, which is
+ * that they should be multiples of PAGE_CACHE_SIZE.
+ *
+ * For UDP transports, a block plus NFS,RPC, and UDP headers
+ * has to fit into the IP datagram limit of 64K. The largest
+ * feasible number for all known page sizes is probably 48K,
+ * but we choose 32K here. This is the same as the historical
+ * Linux limit; someone who cares more about NFS/UDP performance
+ * can test a larger number.
+ *
+ * For TCP transports we have more freedom. A size of 1MB is
+ * chosen to match the client limit. Other OSes are known to
+ * have larger limits, but those numbers are probably beyond
+ * the point of diminishing returns.
*/
-#define RPCSVC_MAXPAYLOAD (64*1024u)
+#define RPCSVC_MAXPAYLOAD (1*1024*1024u)
+#define RPCSVC_MAXPAYLOAD_TCP RPCSVC_MAXPAYLOAD
+#define RPCSVC_MAXPAYLOAD_UDP (32*1024u)
+
+extern u32 svc_max_payload(const struct svc_rqst *rqstp);
/*
* RPC Requsts and replies are stored in one or more pages.
@@ -78,43 +147,61 @@ struct svc_serv {
*/
#define RPCSVC_MAXPAGES ((RPCSVC_MAXPAYLOAD+PAGE_SIZE-1)/PAGE_SIZE + 2)
-static inline u32 svc_getu32(struct kvec *iov)
+static inline u32 svc_getnl(struct kvec *iov)
+{
+ __be32 val, *vp;
+ vp = iov->iov_base;
+ val = *vp++;
+ iov->iov_base = (void*)vp;
+ iov->iov_len -= sizeof(__be32);
+ return ntohl(val);
+}
+
+static inline void svc_putnl(struct kvec *iov, u32 val)
+{
+ __be32 *vp = iov->iov_base + iov->iov_len;
+ *vp = htonl(val);
+ iov->iov_len += sizeof(__be32);
+}
+
+static inline __be32 svc_getu32(struct kvec *iov)
{
- u32 val, *vp;
+ __be32 val, *vp;
vp = iov->iov_base;
val = *vp++;
iov->iov_base = (void*)vp;
- iov->iov_len -= sizeof(u32);
+ iov->iov_len -= sizeof(__be32);
return val;
}
static inline void svc_ungetu32(struct kvec *iov)
{
- u32 *vp = (u32 *)iov->iov_base;
+ __be32 *vp = (__be32 *)iov->iov_base;
iov->iov_base = (void *)(vp - 1);
iov->iov_len += sizeof(*vp);
}
-static inline void svc_putu32(struct kvec *iov, u32 val)
+static inline void svc_putu32(struct kvec *iov, __be32 val)
{
- u32 *vp = iov->iov_base + iov->iov_len;
+ __be32 *vp = iov->iov_base + iov->iov_len;
*vp = val;
- iov->iov_len += sizeof(u32);
+ iov->iov_len += sizeof(__be32);
}
/*
* The context of a single thread, including the request currently being
* processed.
- * NOTE: First two items must be prev/next.
*/
struct svc_rqst {
struct list_head rq_list; /* idle list */
+ struct list_head rq_all; /* all threads list */
struct svc_sock * rq_sock; /* socket */
struct sockaddr_in rq_addr; /* peer address */
int rq_addrlen;
struct svc_serv * rq_server; /* RPC service definition */
+ struct svc_pool * rq_pool; /* thread pool */
struct svc_procedure * rq_procinfo; /* procedure info */
struct auth_ops * rq_authop; /* authentication flavour */
struct svc_cred rq_cred; /* auth info */
@@ -123,14 +210,13 @@ struct svc_rqst {
struct xdr_buf rq_arg;
struct xdr_buf rq_res;
- struct page * rq_argpages[RPCSVC_MAXPAGES];
- struct page * rq_respages[RPCSVC_MAXPAGES];
- int rq_restailpage;
- short rq_argused; /* pages used for argument */
- short rq_arghi; /* pages available in argument page list */
- short rq_resused; /* pages used for result */
-
- u32 rq_xid; /* transmission id */
+ struct page * rq_pages[RPCSVC_MAXPAGES];
+ struct page * *rq_respages; /* points into rq_pages */
+ int rq_resused; /* number of pages used for result */
+
+ struct kvec rq_vec[RPCSVC_MAXPAGES]; /* generally useful.. */
+
+ __be32 rq_xid; /* transmission id */
u32 rq_prog; /* program number */
u32 rq_vers; /* program version */
u32 rq_proc; /* procedure number */
@@ -139,7 +225,7 @@ struct svc_rqst {
rq_secure : 1; /* secure port */
- __u32 rq_daddr; /* dest addr of request - reply from here */
+ __be32 rq_daddr; /* dest addr of request - reply from here */
void * rq_argp; /* decoded arguments */
void * rq_resp; /* xdr'd results */
@@ -163,13 +249,14 @@ struct svc_rqst {
* to prevent encrypting page
* cache pages */
wait_queue_head_t rq_wait; /* synchronization */
+ struct task_struct *rq_task; /* service thread */
};
/*
* Check buffer bounds after decoding arguments
*/
static inline int
-xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
+xdr_argsize_check(struct svc_rqst *rqstp, __be32 *p)
{
char *cp = (char *)p;
struct kvec *vec = &rqstp->rq_arg.head[0];
@@ -178,7 +265,7 @@ xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
}
static inline int
-xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
+xdr_ressize_check(struct svc_rqst *rqstp, __be32 *p)
{
struct kvec *vec = &rqstp->rq_res.head[0];
char *cp = (char*)p;
@@ -188,71 +275,26 @@ xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
return vec->iov_len <= PAGE_SIZE;
}
-static inline struct page *
-svc_take_res_page(struct svc_rqst *rqstp)
-{
- if (rqstp->rq_arghi <= rqstp->rq_argused)
- return NULL;
- rqstp->rq_arghi--;
- rqstp->rq_respages[rqstp->rq_resused] =
- rqstp->rq_argpages[rqstp->rq_arghi];
- return rqstp->rq_respages[rqstp->rq_resused++];
-}
-
-static inline void svc_take_page(struct svc_rqst *rqstp)
-{
- if (rqstp->rq_arghi <= rqstp->rq_argused) {
- WARN_ON(1);
- return;
- }
- rqstp->rq_arghi--;
- rqstp->rq_respages[rqstp->rq_resused] =
- rqstp->rq_argpages[rqstp->rq_arghi];
- rqstp->rq_resused++;
-}
-
-static inline void svc_pushback_allpages(struct svc_rqst *rqstp)
-{
- while (rqstp->rq_resused) {
- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
- continue;
- rqstp->rq_argpages[rqstp->rq_arghi++] =
- rqstp->rq_respages[rqstp->rq_resused];
- rqstp->rq_respages[rqstp->rq_resused] = NULL;
- }
-}
-
-static inline void svc_pushback_unused_pages(struct svc_rqst *rqstp)
+static inline void svc_free_res_pages(struct svc_rqst *rqstp)
{
- while (rqstp->rq_resused &&
- rqstp->rq_res.pages != &rqstp->rq_respages[rqstp->rq_resused]) {
-
- if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) {
- rqstp->rq_argpages[rqstp->rq_arghi++] =
- rqstp->rq_respages[rqstp->rq_resused];
- rqstp->rq_respages[rqstp->rq_resused] = NULL;
+ while (rqstp->rq_resused) {
+ struct page **pp = (rqstp->rq_respages +
+ --rqstp->rq_resused);
+ if (*pp) {
+ put_page(*pp);
+ *pp = NULL;
}
}
}
-static inline void svc_free_allpages(struct svc_rqst *rqstp)
-{
- while (rqstp->rq_resused) {
- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
- continue;
- put_page(rqstp->rq_respages[rqstp->rq_resused]);
- rqstp->rq_respages[rqstp->rq_resused] = NULL;
- }
-}
-
struct svc_deferred_req {
u32 prot; /* protocol (UDP or TCP) */
struct sockaddr_in addr;
struct svc_sock *svsk; /* where reply must go */
- u32 daddr; /* where reply must come from */
+ __be32 daddr; /* where reply must come from */
struct cache_deferred_req handle;
int argslen;
- u32 args[0];
+ __be32 args[0];
};
/*
@@ -280,17 +322,20 @@ struct svc_version {
struct svc_procedure * vs_proc; /* per-procedure info */
u32 vs_xdrsize; /* xdrsize needed for this version */
+ unsigned int vs_hidden : 1; /* Don't register with portmapper.
+ * Only used for nfsacl so far. */
+
/* Override dispatch function (e.g. when caching replies).
* A return value of 0 means drop the request.
* vs_dispatch == NULL means use default dispatcher.
*/
- int (*vs_dispatch)(struct svc_rqst *, u32 *);
+ int (*vs_dispatch)(struct svc_rqst *, __be32 *);
};
/*
* RPC procedure info
*/
-typedef int (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp);
+typedef __be32 (*svc_procfunc)(struct svc_rqst *, void *argp, void *resp);
struct svc_procedure {
svc_procfunc pc_func; /* process the request */
kxdrproc_t pc_decode; /* XDR decode args */
@@ -304,20 +349,21 @@ struct svc_procedure {
};
/*
- * This is the RPC server thread function prototype
- */
-typedef void (*svc_thread_fn)(struct svc_rqst *);
-
-/*
* Function prototypes.
*/
-struct svc_serv * svc_create(struct svc_program *, unsigned int);
+struct svc_serv * svc_create(struct svc_program *, unsigned int,
+ void (*shutdown)(struct svc_serv*));
int svc_create_thread(svc_thread_fn, struct svc_serv *);
void svc_exit_thread(struct svc_rqst *);
+struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
+ void (*shutdown)(struct svc_serv*),
+ svc_thread_fn, int sig, struct module *);
+int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
void svc_destroy(struct svc_serv *);
-int svc_process(struct svc_serv *, struct svc_rqst *);
+int svc_process(struct svc_rqst *);
int svc_register(struct svc_serv *, int, unsigned short);
void svc_wake_up(struct svc_serv *);
void svc_reserve(struct svc_rqst *rqstp, int space);
+struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
#endif /* SUNRPC_SVC_H */
diff --git a/include/linux/sunrpc/svcauth.h b/include/linux/sunrpc/svcauth.h
index 2fe2087edd66..de92619b0826 100644
--- a/include/linux/sunrpc/svcauth.h
+++ b/include/linux/sunrpc/svcauth.h
@@ -95,7 +95,7 @@ struct auth_ops {
char * name;
struct module *owner;
int flavour;
- int (*accept)(struct svc_rqst *rq, u32 *authp);
+ int (*accept)(struct svc_rqst *rq, __be32 *authp);
int (*release)(struct svc_rqst *rq);
void (*domain_release)(struct auth_domain *);
int (*set_client)(struct svc_rqst *rq);
@@ -112,7 +112,7 @@ struct auth_ops {
#define SVC_COMPLETE 9
-extern int svc_authenticate(struct svc_rqst *rqstp, u32 *authp);
+extern int svc_authenticate(struct svc_rqst *rqstp, __be32 *authp);
extern int svc_authorise(struct svc_rqst *rqstp);
extern int svc_set_client(struct svc_rqst *rqstp);
extern int svc_auth_register(rpc_authflavor_t flavor, struct auth_ops *aops);
@@ -126,6 +126,7 @@ extern struct auth_domain *auth_domain_find(char *name);
extern struct auth_domain *auth_unix_lookup(struct in_addr addr);
extern int auth_unix_forget_old(struct auth_domain *dom);
extern void svcauth_unix_purge(void);
+extern void svcauth_unix_info_release(void *);
static inline unsigned long hash_str(char *name, int bits)
{
diff --git a/include/linux/sunrpc/svcauth_gss.h b/include/linux/sunrpc/svcauth_gss.h
index 3a2206f61de0..5a5db16ab660 100644
--- a/include/linux/sunrpc/svcauth_gss.h
+++ b/include/linux/sunrpc/svcauth_gss.h
@@ -1,5 +1,5 @@
/*
- * linux/include/linux/svcauth_gss.h
+ * linux/include/linux/sunrpc/svcauth_gss.h
*
* Bruce Fields <bfields@umich.edu>
* Copyright (c) 2002 The Regents of the Unviersity of Michigan
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index b4acb3d37c3f..98b21ad370fd 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -20,8 +20,9 @@ struct svc_sock {
struct socket * sk_sock; /* berkeley socket layer */
struct sock * sk_sk; /* INET layer */
+ struct svc_pool * sk_pool; /* current pool iff queued */
struct svc_serv * sk_server; /* service for this socket */
- unsigned int sk_inuse; /* use count */
+ atomic_t sk_inuse; /* use count */
unsigned long sk_flags;
#define SK_BUSY 0 /* enqueued/receiving */
#define SK_CONN 1 /* conn pending */
@@ -31,9 +32,12 @@ struct svc_sock {
#define SK_DEAD 6 /* socket closed */
#define SK_CHNGBUF 7 /* need to change snd/rcv buffer sizes */
#define SK_DEFERRED 8 /* request on sk_deferred */
+#define SK_OLD 9 /* used for temp socket aging mark+sweep */
+#define SK_DETACHED 10 /* detached from tempsocks list */
- int sk_reserved; /* space on outq that is reserved */
+ atomic_t sk_reserved; /* space on outq that is reserved */
+ spinlock_t sk_defer_lock; /* protects sk_deferred */
struct list_head sk_deferred; /* deferred requests that need to
* be revisted */
struct mutex sk_mutex; /* to serialize sending data */
@@ -50,6 +54,9 @@ struct svc_sock {
int sk_reclen; /* length of record */
int sk_tcplen; /* current read length */
time_t sk_lastrecv; /* time of last received request */
+
+ /* cache of various info for TCP sockets */
+ void *sk_info_authunix;
};
/*
@@ -57,9 +64,14 @@ struct svc_sock {
*/
int svc_makesock(struct svc_serv *, int, unsigned short);
void svc_delete_socket(struct svc_sock *);
-int svc_recv(struct svc_serv *, struct svc_rqst *, long);
+int svc_recv(struct svc_rqst *, long);
int svc_send(struct svc_rqst *);
void svc_drop(struct svc_rqst *);
void svc_sock_update_bufs(struct svc_serv *serv);
+int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
+int svc_addsock(struct svc_serv *serv,
+ int fd,
+ char *name_return,
+ int *proto);
#endif /* SUNRPC_SVCSOCK_H */
diff --git a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
index e6d3d349506c..ac69e5511606 100644
--- a/include/linux/sunrpc/xdr.h
+++ b/include/linux/sunrpc/xdr.h
@@ -32,7 +32,7 @@ struct xdr_netobj {
* side) or svc_rqst pointer (server side).
* Encode functions always assume there's enough room in the buffer.
*/
-typedef int (*kxdrproc_t)(void *rqstp, u32 *data, void *obj);
+typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj);
/*
* Basic structure for transmission/reception of a client XDR message.
@@ -74,6 +74,7 @@ struct xdr_buf {
#define rpc_proc_unavail __constant_htonl(RPC_PROC_UNAVAIL)
#define rpc_garbage_args __constant_htonl(RPC_GARBAGE_ARGS)
#define rpc_system_err __constant_htonl(RPC_SYSTEM_ERR)
+#define rpc_drop_reply __constant_htonl(RPC_DROP_REPLY)
#define rpc_auth_ok __constant_htonl(RPC_AUTH_OK)
#define rpc_autherr_badcred __constant_htonl(RPC_AUTH_BADCRED)
@@ -88,19 +89,19 @@ struct xdr_buf {
/*
* Miscellaneous XDR helper functions
*/
-u32 * xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int len);
-u32 * xdr_encode_opaque(u32 *p, const void *ptr, unsigned int len);
-u32 * xdr_encode_string(u32 *p, const char *s);
-u32 * xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen);
-u32 * xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
-u32 * xdr_decode_netobj(u32 *p, struct xdr_netobj *);
+__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len);
+__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len);
+__be32 *xdr_encode_string(__be32 *p, const char *s);
+__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen);
+__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *);
+__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *);
void xdr_encode_pages(struct xdr_buf *, struct page **, unsigned int,
unsigned int);
void xdr_inline_pages(struct xdr_buf *, unsigned int,
struct page **, unsigned int, unsigned int);
-static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len)
+static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len)
{
return xdr_encode_opaque(p, s, len);
}
@@ -108,16 +109,16 @@ static inline u32 *xdr_encode_array(u32 *p, const void *s, unsigned int len)
/*
* Decode 64bit quantities (NFSv3 support)
*/
-static inline u32 *
-xdr_encode_hyper(u32 *p, __u64 val)
+static inline __be32 *
+xdr_encode_hyper(__be32 *p, __u64 val)
{
*p++ = htonl(val >> 32);
*p++ = htonl(val & 0xFFFFFFFF);
return p;
}
-static inline u32 *
-xdr_decode_hyper(u32 *p, __u64 *valp)
+static inline __be32 *
+xdr_decode_hyper(__be32 *p, __u64 *valp)
{
*valp = ((__u64) ntohl(*p++)) << 32;
*valp |= ntohl(*p++);
@@ -128,7 +129,7 @@ xdr_decode_hyper(u32 *p, __u64 *valp)
* Adjust kvec to reflect end of xdr'ed data (RPC client XDR)
*/
static inline int
-xdr_adjust_iovec(struct kvec *iov, u32 *p)
+xdr_adjust_iovec(struct kvec *iov, __be32 *p)
{
return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
}
@@ -180,19 +181,19 @@ extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
* Provide some simple tools for XDR buffer overflow-checking etc.
*/
struct xdr_stream {
- uint32_t *p; /* start of available buffer */
+ __be32 *p; /* start of available buffer */
struct xdr_buf *buf; /* XDR buffer to read/write */
- uint32_t *end; /* end of available buffer space */
+ __be32 *end; /* end of available buffer space */
struct kvec *iov; /* pointer to the current kvec */
};
-extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
-extern uint32_t *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
+extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages,
unsigned int base, unsigned int len);
-extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p);
-extern uint32_t *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
+extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p);
+extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes);
extern void xdr_read_pages(struct xdr_stream *xdr, unsigned int len);
extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len);
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index bdeba8538c71..60394fbc4c70 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -15,6 +15,7 @@
#include <linux/kref.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/msg_prot.h>
extern unsigned int xprt_udp_slot_table_entries;
extern unsigned int xprt_tcp_slot_table_entries;
@@ -24,13 +25,6 @@ extern unsigned int xprt_tcp_slot_table_entries;
#define RPC_MAX_SLOT_TABLE (128U)
/*
- * RPC call and reply header size as number of 32bit words (verifier
- * size computed separately)
- */
-#define RPC_CALLHDRSIZE 6
-#define RPC_REPHDRSIZE 4
-
-/*
* Parameters for choosing a free port
*/
extern unsigned int xprt_min_resvport;
@@ -79,7 +73,7 @@ struct rpc_rqst {
* This is the private part
*/
struct rpc_task * rq_task; /* RPC task data */
- __u32 rq_xid; /* request XID */
+ __be32 rq_xid; /* request XID */
int rq_cong; /* has incremented xprt->cong */
int rq_received; /* receive completed */
u32 rq_seqno; /* gss seq no. used on req. */
@@ -171,9 +165,9 @@ struct rpc_xprt {
/*
* State of TCP reply receive stuff
*/
- u32 tcp_recm, /* Fragment header */
- tcp_xid, /* Current XID */
- tcp_reclen, /* fragment length */
+ __be32 tcp_recm, /* Fragment header */
+ tcp_xid; /* Current XID */
+ u32 tcp_reclen, /* fragment length */
tcp_offset; /* fragment offset */
unsigned long tcp_copied, /* copied to request */
tcp_flags;
@@ -253,7 +247,7 @@ void xprt_release(struct rpc_task *task);
struct rpc_xprt * xprt_get(struct rpc_xprt *xprt);
void xprt_put(struct rpc_xprt *xprt);
-static inline u32 *xprt_skip_transport_header(struct rpc_xprt *xprt, u32 *p)
+static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
{
return p + xprt->tsh_size;
}
@@ -268,7 +262,7 @@ void xprt_wait_for_buffer_space(struct rpc_task *task);
void xprt_write_space(struct rpc_xprt *xprt);
void xprt_update_rtt(struct rpc_task *task);
void xprt_adjust_cwnd(struct rpc_task *task, int result);
-struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid);
+struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid);
void xprt_complete_rqst(struct rpc_task *task, int copied);
void xprt_release_rqst_cong(struct rpc_task *task);
void xprt_disconnect(struct rpc_xprt *xprt);
diff --git a/include/linux/synclink.h b/include/linux/synclink.h
index 0577f5284cbc..c8b042667af1 100644
--- a/include/linux/synclink.h
+++ b/include/linux/synclink.h
@@ -1,7 +1,7 @@
/*
* SyncLink Multiprotocol Serial Adapter Driver
*
- * $Id: synclink.h,v 3.13 2006/05/23 18:25:06 paulkf Exp $
+ * $Id: synclink.h,v 3.14 2006/07/17 20:15:43 paulkf Exp $
*
* Copyright (C) 1998-2000 by Microgate Corporation
*
@@ -124,6 +124,8 @@
#define MGSL_MODE_ASYNC 1
#define MGSL_MODE_HDLC 2
+#define MGSL_MODE_MONOSYNC 3
+#define MGSL_MODE_BISYNC 4
#define MGSL_MODE_RAW 6
#define MGSL_BUS_TYPE_ISA 1
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 3f0f716225ec..1912c6cbef55 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -431,6 +431,10 @@ asmlinkage long sys_epoll_ctl(int epfd, int op, int fd,
struct epoll_event __user *event);
asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events,
int maxevents, int timeout);
+asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events,
+ int maxevents, int timeout,
+ const sigset_t __user *sigmask,
+ size_t sigsetsize);
asmlinkage long sys_gethostname(char __user *name, int len);
asmlinkage long sys_sethostname(char __user *name, int len);
asmlinkage long sys_setdomainname(char __user *name, int len);
@@ -593,10 +597,12 @@ asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags);
asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes,
unsigned int flags);
asmlinkage long sys_get_robust_list(int pid,
- struct robust_list_head __user **head_ptr,
+ struct robust_list_head __user * __user *head_ptr,
size_t __user *len_ptr);
asmlinkage long sys_set_robust_list(struct robust_list_head __user *head,
size_t len);
-asmlinkage long sys_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *cache);
+asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache);
+
+int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
#endif
diff --git a/include/linux/sysrq.h b/include/linux/sysrq.h
index 4812ff60561c..9df8833670cb 100644
--- a/include/linux/sysrq.h
+++ b/include/linux/sysrq.h
@@ -11,6 +11,8 @@
* based upon discusions in irc://irc.openprojects.net/#kernelnewbies
*/
+#ifndef _LINUX_SYSRQ_H
+#define _LINUX_SYSRQ_H
struct pt_regs;
struct tty_struct;
@@ -27,7 +29,7 @@ struct tty_struct;
#define SYSRQ_ENABLE_RTNICE 0x0100
struct sysrq_key_op {
- void (*handler)(int, struct pt_regs *, struct tty_struct *);
+ void (*handler)(int, struct tty_struct *);
char *help_msg;
char *action_msg;
int enable_mask;
@@ -40,8 +42,8 @@ struct sysrq_key_op {
* are available -- else NULL's).
*/
-void handle_sysrq(int, struct pt_regs *, struct tty_struct *);
-void __handle_sysrq(int, struct pt_regs *, struct tty_struct *, int check_mask);
+void handle_sysrq(int, struct tty_struct *);
+void __handle_sysrq(int, struct tty_struct *, int check_mask);
int register_sysrq_key(int, struct sysrq_key_op *);
int unregister_sysrq_key(int, struct sysrq_key_op *);
struct sysrq_key_op *__sysrq_get_key_op(int key);
@@ -57,3 +59,5 @@ static inline int __reterr(void)
#define unregister_sysrq_key(ig,nore) __reterr()
#endif
+
+#endif /* _LINUX_SYSRQ_H */
diff --git a/include/linux/taskstats.h b/include/linux/taskstats.h
index f1cb6cddd19d..45248806ae9c 100644
--- a/include/linux/taskstats.h
+++ b/include/linux/taskstats.h
@@ -2,6 +2,7 @@
*
* Copyright (C) Shailabh Nagar, IBM Corp. 2006
* (C) Balbir Singh, IBM Corp. 2006
+ * (C) Jay Lan, SGI, 2006
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2.1 of the GNU Lesser General Public License
@@ -29,16 +30,25 @@
* c) add new fields after version comment; maintain 64-bit alignment
*/
-#define TASKSTATS_VERSION 1
+
+#define TASKSTATS_VERSION 2
+#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN
+ * in linux/sched.h */
struct taskstats {
- /* Version 1 */
+ /* The version number of this struct. This field is always set to
+ * TAKSTATS_VERSION, which is defined in <linux/taskstats.h>.
+ * Each time the struct is changed, the value should be incremented.
+ */
__u16 version;
- __u16 padding[3]; /* Userspace should not interpret the padding
- * field which can be replaced by useful
- * fields if struct taskstats is extended.
- */
+ __u32 ac_exitcode; /* Exit status */
+
+ /* The accounting flags of a task as defined in <linux/acct.h>
+ * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG.
+ */
+ __u8 ac_flag; /* Record flags */
+ __u8 ac_nice; /* task_nice */
/* Delay accounting fields start
*
@@ -88,6 +98,48 @@ struct taskstats {
__u64 cpu_run_virtual_total;
/* Delay accounting fields end */
/* version 1 ends here */
+
+ /* Basic Accounting Fields start */
+ char ac_comm[TS_COMM_LEN]; /* Command name */
+ __u8 ac_sched; /* Scheduling discipline */
+ __u8 ac_pad[3];
+ __u32 ac_uid; /* User ID */
+ __u32 ac_gid; /* Group ID */
+ __u32 ac_pid; /* Process ID */
+ __u32 ac_ppid; /* Parent process ID */
+ __u32 ac_btime; /* Begin time [sec since 1970] */
+ __u64 ac_etime; /* Elapsed time [usec] */
+ __u64 ac_utime; /* User CPU time [usec] */
+ __u64 ac_stime; /* SYstem CPU time [usec] */
+ __u64 ac_minflt; /* Minor Page Fault Count */
+ __u64 ac_majflt; /* Major Page Fault Count */
+ /* Basic Accounting Fields end */
+
+ /* Extended accounting fields start */
+ /* Accumulated RSS usage in duration of a task, in MBytes-usecs.
+ * The current rss usage is added to this counter every time
+ * a tick is charged to a task's system time. So, at the end we
+ * will have memory usage multiplied by system time. Thus an
+ * average usage per system time unit can be calculated.
+ */
+ __u64 coremem; /* accumulated RSS usage in MB-usec */
+ /* Accumulated virtual memory usage in duration of a task.
+ * Same as acct_rss_mem1 above except that we keep track of VM usage.
+ */
+ __u64 virtmem; /* accumulated VM usage in MB-usec */
+
+ /* High watermark of RSS and virtual memory usage in duration of
+ * a task, in KBytes.
+ */
+ __u64 hiwater_rss; /* High-watermark of RSS usage, in KB */
+ __u64 hiwater_vm; /* High-water VM usage, in KB */
+
+ /* The following four fields are I/O statistics of a task. */
+ __u64 read_char; /* bytes read */
+ __u64 write_char; /* bytes written */
+ __u64 read_syscalls; /* read syscalls */
+ __u64 write_syscalls; /* write syscalls */
+ /* Extended accounting fields end */
};
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 8ebf497907f8..2d36f6db3706 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -21,10 +21,10 @@
#include <asm/byteorder.h>
struct tcphdr {
- __u16 source;
- __u16 dest;
- __u32 seq;
- __u32 ack_seq;
+ __be16 source;
+ __be16 dest;
+ __be32 seq;
+ __be32 ack_seq;
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u16 res1:4,
doff:4,
@@ -50,9 +50,9 @@ struct tcphdr {
#else
#error "Adjust your <asm/byteorder.h> defines"
#endif
- __u16 window;
- __u16 check;
- __u16 urg_ptr;
+ __be16 window;
+ __be16 check;
+ __be16 urg_ptr;
};
/*
@@ -62,7 +62,7 @@ struct tcphdr {
*/
union tcp_word_hdr {
struct tcphdr hdr;
- __u32 words[5];
+ __be32 words[5];
};
#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3])
@@ -166,6 +166,11 @@ struct tcp_info
#include <net/inet_timewait_sock.h>
/* This defines a selective acknowledgement block. */
+struct tcp_sack_block_wire {
+ __be32 start_seq;
+ __be32 end_seq;
+};
+
struct tcp_sack_block {
__u32 start_seq;
__u32 end_seq;
@@ -211,7 +216,7 @@ struct tcp_sock {
* Header prediction flags
* 0x5?10 << 16 + snd_wnd in net byte order
*/
- __u32 pred_flags;
+ __be32 pred_flags;
/*
* RFC793 variables by their proper names. This means you can
@@ -337,6 +342,8 @@ struct tcp_sock {
unsigned long last_synq_overflow;
+ __u32 tso_deferred;
+
/* Receiver side RTT estimation */
struct {
__u32 rtt;
diff --git a/include/linux/tifm.h b/include/linux/tifm.h
new file mode 100644
index 000000000000..dfb8052eee5e
--- /dev/null
+++ b/include/linux/tifm.h
@@ -0,0 +1,159 @@
+/*
+ * tifm.h - TI FlashMedia driver
+ *
+ * Copyright (C) 2006 Alex Dubov <oakad@yahoo.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 _TIFM_H
+#define _TIFM_H
+
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+
+/* Host registers (relative to pci base address): */
+enum {
+ FM_SET_INTERRUPT_ENABLE = 0x008,
+ FM_CLEAR_INTERRUPT_ENABLE = 0x00c,
+ FM_INTERRUPT_STATUS = 0x014 };
+
+/* Socket registers (relative to socket base address): */
+enum {
+ SOCK_CONTROL = 0x004,
+ SOCK_PRESENT_STATE = 0x008,
+ SOCK_DMA_ADDRESS = 0x00c,
+ SOCK_DMA_CONTROL = 0x010,
+ SOCK_DMA_FIFO_INT_ENABLE_SET = 0x014,
+ SOCK_DMA_FIFO_INT_ENABLE_CLEAR = 0x018,
+ SOCK_DMA_FIFO_STATUS = 0x020,
+ SOCK_FIFO_CONTROL = 0x024,
+ SOCK_FIFO_PAGE_SIZE = 0x028,
+ SOCK_MMCSD_COMMAND = 0x104,
+ SOCK_MMCSD_ARG_LOW = 0x108,
+ SOCK_MMCSD_ARG_HIGH = 0x10c,
+ SOCK_MMCSD_CONFIG = 0x110,
+ SOCK_MMCSD_STATUS = 0x114,
+ SOCK_MMCSD_INT_ENABLE = 0x118,
+ SOCK_MMCSD_COMMAND_TO = 0x11c,
+ SOCK_MMCSD_DATA_TO = 0x120,
+ SOCK_MMCSD_DATA = 0x124,
+ SOCK_MMCSD_BLOCK_LEN = 0x128,
+ SOCK_MMCSD_NUM_BLOCKS = 0x12c,
+ SOCK_MMCSD_BUFFER_CONFIG = 0x130,
+ SOCK_MMCSD_SPI_CONFIG = 0x134,
+ SOCK_MMCSD_SDIO_MODE_CONFIG = 0x138,
+ SOCK_MMCSD_RESPONSE = 0x144,
+ SOCK_MMCSD_SDIO_SR = 0x164,
+ SOCK_MMCSD_SYSTEM_CONTROL = 0x168,
+ SOCK_MMCSD_SYSTEM_STATUS = 0x16c,
+ SOCK_MS_COMMAND = 0x184,
+ SOCK_MS_DATA = 0x188,
+ SOCK_MS_STATUS = 0x18c,
+ SOCK_MS_SYSTEM = 0x190,
+ SOCK_FIFO_ACCESS = 0x200 };
+
+
+#define TIFM_IRQ_ENABLE 0x80000000
+#define TIFM_IRQ_SOCKMASK 0x00000001
+#define TIFM_IRQ_CARDMASK 0x00000100
+#define TIFM_IRQ_FIFOMASK 0x00010000
+#define TIFM_IRQ_SETALL 0xffffffff
+#define TIFM_IRQ_SETALLSOCK 0x0000000f
+
+#define TIFM_CTRL_LED 0x00000040
+#define TIFM_CTRL_FAST_CLK 0x00000100
+
+#define TIFM_SOCK_STATE_OCCUPIED 0x00000008
+#define TIFM_SOCK_STATE_POWERED 0x00000080
+
+#define TIFM_FIFO_ENABLE 0x00000001 /* Meaning of this constant is unverified */
+#define TIFM_FIFO_INT_SETALL 0x0000ffff
+#define TIFM_FIFO_INTMASK 0x00000005 /* Meaning of this constant is unverified */
+
+#define TIFM_DMA_RESET 0x00000002 /* Meaning of this constant is unverified */
+#define TIFM_DMA_TX 0x00008000 /* Meaning of this constant is unverified */
+#define TIFM_DMA_EN 0x00000001 /* Meaning of this constant is unverified */
+
+typedef enum {FM_NULL = 0, FM_XD = 0x01, FM_MS = 0x02, FM_SD = 0x03} tifm_media_id;
+
+struct tifm_driver;
+struct tifm_dev {
+ char __iomem *addr;
+ spinlock_t lock;
+ tifm_media_id media_id;
+ char wq_name[KOBJ_NAME_LEN];
+ struct workqueue_struct *wq;
+
+ unsigned int (*signal_irq)(struct tifm_dev *sock,
+ unsigned int sock_irq_status);
+
+ struct tifm_driver *drv;
+ struct device dev;
+};
+
+struct tifm_driver {
+ tifm_media_id *id_table;
+ int (*probe)(struct tifm_dev *dev);
+ void (*remove)(struct tifm_dev *dev);
+
+ struct device_driver driver;
+};
+
+struct tifm_adapter {
+ char __iomem *addr;
+ unsigned int irq_status;
+ unsigned int insert_mask;
+ unsigned int remove_mask;
+ spinlock_t lock;
+ unsigned int id;
+ unsigned int max_sockets;
+ char wq_name[KOBJ_NAME_LEN];
+ unsigned int inhibit_new_cards;
+ struct workqueue_struct *wq;
+ struct work_struct media_inserter;
+ struct work_struct media_remover;
+ struct tifm_dev **sockets;
+ struct class_device cdev;
+ struct device *dev;
+
+ void (*eject)(struct tifm_adapter *fm, struct tifm_dev *sock);
+};
+
+struct tifm_adapter *tifm_alloc_adapter(void);
+void tifm_free_device(struct device *dev);
+void tifm_free_adapter(struct tifm_adapter *fm);
+int tifm_add_adapter(struct tifm_adapter *fm);
+void tifm_remove_adapter(struct tifm_adapter *fm);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id);
+int tifm_register_driver(struct tifm_driver *drv);
+void tifm_unregister_driver(struct tifm_driver *drv);
+void tifm_eject(struct tifm_dev *sock);
+int tifm_map_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction);
+void tifm_unmap_sg(struct tifm_dev *sock, struct scatterlist *sg, int nents,
+ int direction);
+
+
+static inline void *tifm_get_drvdata(struct tifm_dev *dev)
+{
+ return dev_get_drvdata(&dev->dev);
+}
+
+static inline void tifm_set_drvdata(struct tifm_dev *dev, void *data)
+{
+ dev_set_drvdata(&dev->dev, data);
+}
+
+struct tifm_device_id {
+ tifm_media_id media_id;
+};
+
+#endif
diff --git a/include/linux/timex.h b/include/linux/timex.h
index d543d3871e38..db501dc23c29 100644
--- a/include/linux/timex.h
+++ b/include/linux/timex.h
@@ -69,34 +69,28 @@
* zero to MAXTC, the PLL will converge in 15 minutes to 16 hours,
* respectively.
*/
-#define SHIFT_KG 6 /* phase factor (shift) */
-#define SHIFT_KF 16 /* PLL frequency factor (shift) */
-#define SHIFT_KH 2 /* FLL frequency factor (shift) */
-#define MAXTC 6 /* maximum time constant (shift) */
+#define SHIFT_PLL 4 /* PLL frequency factor (shift) */
+#define SHIFT_FLL 2 /* FLL frequency factor (shift) */
+#define MAXTC 10 /* maximum time constant (shift) */
/*
- * The SHIFT_SCALE define establishes the decimal point of the time_phase
- * variable which serves as an extension to the low-order bits of the
- * system clock variable. The SHIFT_UPDATE define establishes the decimal
- * point of the time_offset variable which represents the current offset
- * with respect to standard time. The FINENSEC define represents 1 nsec in
- * scaled units.
+ * The SHIFT_UPDATE define establishes the decimal point of the
+ * time_offset variable which represents the current offset with
+ * respect to standard time.
*
* SHIFT_USEC defines the scaling (shift) of the time_freq and
* time_tolerance variables, which represent the current frequency
* offset and maximum frequency tolerance.
- *
- * FINENSEC is 1 ns in SHIFT_UPDATE units of the time_phase variable.
*/
-#define SHIFT_SCALE 22 /* phase scale (shift) */
-#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */
+#define SHIFT_UPDATE (SHIFT_HZ + 1) /* time offset scale (shift) */
#define SHIFT_USEC 16 /* frequency offset scale (shift) */
-#define FINENSEC (1L << (SHIFT_SCALE - 10)) /* ~1 ns in phase units */
+#define SHIFT_NSEC 12 /* kernel frequency offset scale */
#define MAXPHASE 512000L /* max phase error (us) */
#define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */
-#define MINSEC 16L /* min interval between updates (s) */
-#define MAXSEC 1200L /* max interval between updates (s) */
+#define MAXFREQ_NSEC (512000L << SHIFT_NSEC) /* max frequency error (ppb) */
+#define MINSEC 256 /* min interval between updates (s) */
+#define MAXSEC 2048 /* max interval between updates (s) */
#define NTP_PHASE_LIMIT (MAXPHASE << 5) /* beyond max. dispersion */
/*
@@ -204,33 +198,15 @@ extern int tickadj; /* amount of adjustment per tick */
/*
* phase-lock loop variables
*/
-extern int time_state; /* clock status */
extern int time_status; /* clock synchronization status bits */
-extern long time_offset; /* time adjustment (us) */
-extern long time_constant; /* pll time constant */
-extern long time_tolerance; /* frequency tolerance (ppm) */
-extern long time_precision; /* clock precision (us) */
extern long time_maxerror; /* maximum error */
extern long time_esterror; /* estimated error */
extern long time_freq; /* frequency offset (scaled ppm) */
-extern long time_reftime; /* time at last adjustment (s) */
extern long time_adjust; /* The amount of adjtime left */
-extern long time_next_adjust; /* Value for time_adjust at next tick */
-/**
- * ntp_clear - Clears the NTP state variables
- *
- * Must be called while holding a write on the xtime_lock
- */
-static inline void ntp_clear(void)
-{
- time_adjust = 0; /* stop active adjtime() */
- time_status |= STA_UNSYNC;
- time_maxerror = NTP_PHASE_LIMIT;
- time_esterror = NTP_PHASE_LIMIT;
-}
+extern void ntp_clear(void);
/**
* ntp_synced - Returns 1 if the NTP status is not UNSYNC
@@ -294,11 +270,15 @@ extern void register_time_interpolator(struct time_interpolator *);
extern void unregister_time_interpolator(struct time_interpolator *);
extern void time_interpolator_reset(void);
extern unsigned long time_interpolator_get_offset(void);
+extern void time_interpolator_update(long delta_nsec);
#else /* !CONFIG_TIME_INTERPOLATION */
-static inline void
-time_interpolator_reset(void)
+static inline void time_interpolator_reset(void)
+{
+}
+
+static inline void time_interpolator_update(long delta_nsec)
{
}
@@ -309,8 +289,13 @@ time_interpolator_reset(void)
/* Returns how long ticks are at present, in ns / 2^(SHIFT_SCALE-10). */
extern u64 current_tick_length(void);
+extern void second_overflow(void);
+extern void update_ntp_one_tick(void);
extern int do_adjtimex(struct timex *);
+/* Don't use! Compatibility define for existing users. */
+#define tickadj (500/HZ ? : 1)
+
#endif /* KERNEL */
#endif /* LINUX_TIMEX_H */
diff --git a/include/linux/tipc.h b/include/linux/tipc.h
index 243a15f54002..bea469455a0c 100644
--- a/include/linux/tipc.h
+++ b/include/linux/tipc.h
@@ -129,6 +129,7 @@ static inline unsigned int tipc_node(__u32 addr)
#define TIPC_SUB_PORTS 0x01 /* filter for port availability */
#define TIPC_SUB_SERVICE 0x02 /* filter for service availability */
+#define TIPC_SUB_CANCEL 0x04 /* cancel a subscription */
#if 0
/* The following filter options are not currently implemented */
#define TIPC_SUB_NO_BIND_EVTS 0x04 /* filter out "publish" events */
diff --git a/include/linux/topology.h b/include/linux/topology.h
index ec1eca85290a..da508d1998e4 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -89,6 +89,7 @@
#define SD_SIBLING_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 1, \
.max_interval = 2, \
@@ -114,11 +115,44 @@
#endif
#endif /* CONFIG_SCHED_SMT */
+#ifdef CONFIG_SCHED_MC
+/* Common values for MC siblings. for now mostly derived from SD_CPU_INIT */
+#ifndef SD_MC_INIT
+#define SD_MC_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
+ .child = NULL, \
+ .groups = NULL, \
+ .min_interval = 1, \
+ .max_interval = 4, \
+ .busy_factor = 64, \
+ .imbalance_pct = 125, \
+ .cache_nice_tries = 1, \
+ .per_cpu_gain = 100, \
+ .busy_idx = 2, \
+ .idle_idx = 1, \
+ .newidle_idx = 2, \
+ .wake_idx = 1, \
+ .forkexec_idx = 1, \
+ .flags = SD_LOAD_BALANCE \
+ | SD_BALANCE_NEWIDLE \
+ | SD_BALANCE_EXEC \
+ | SD_WAKE_AFFINE \
+ | SD_SHARE_PKG_RESOURCES\
+ | BALANCE_FOR_MC_POWER, \
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+ .nr_balance_failed = 0, \
+}
+#endif
+#endif /* CONFIG_SCHED_MC */
+
/* Common values for CPUs */
#ifndef SD_CPU_INIT
#define SD_CPU_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 1, \
.max_interval = 4, \
@@ -135,7 +169,7 @@
| SD_BALANCE_NEWIDLE \
| SD_BALANCE_EXEC \
| SD_WAKE_AFFINE \
- | BALANCE_FOR_POWER, \
+ | BALANCE_FOR_PKG_POWER,\
.last_balance = jiffies, \
.balance_interval = 1, \
.nr_balance_failed = 0, \
@@ -146,6 +180,7 @@
#define SD_ALLNODES_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
+ .child = NULL, \
.groups = NULL, \
.min_interval = 64, \
.max_interval = 64*num_online_cpus(), \
@@ -165,15 +200,6 @@
.nr_balance_failed = 0, \
}
-#ifdef CONFIG_SCHED_MC
-#ifndef SD_MC_INIT
-/* for now its same as SD_CPU_INIT.
- * TBD: Tune Domain parameters!
- */
-#define SD_MC_INIT SD_CPU_INIT
-#endif
-#endif
-
#ifdef CONFIG_NUMA
#ifndef SD_NODE_INIT
#error Please define an appropriate SD_NODE_INIT in include/asm/topology.h!!!
diff --git a/include/linux/trdevice.h b/include/linux/trdevice.h
index 99e02ef54c47..bfc84a7aecc5 100644
--- a/include/linux/trdevice.h
+++ b/include/linux/trdevice.h
@@ -28,7 +28,7 @@
#include <linux/if_tr.h>
#ifdef __KERNEL__
-extern unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev);
+extern __be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev);
extern void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh, struct net_device *dev);
extern struct net_device *alloc_trdev(int sizeof_priv);
diff --git a/include/linux/tsacct_kern.h b/include/linux/tsacct_kern.h
new file mode 100644
index 000000000000..7e50ac795b0b
--- /dev/null
+++ b/include/linux/tsacct_kern.h
@@ -0,0 +1,34 @@
+/*
+ * tsacct_kern.h - kernel header for system accounting over taskstats interface
+ *
+ * Copyright (C) Jay Lan SGI
+ */
+
+#ifndef _LINUX_TSACCT_KERN_H
+#define _LINUX_TSACCT_KERN_H
+
+#include <linux/taskstats.h>
+
+#ifdef CONFIG_TASKSTATS
+extern void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk);
+#else
+static inline void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
+{}
+#endif /* CONFIG_TASKSTATS */
+
+#ifdef CONFIG_TASK_XACCT
+extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p);
+extern void acct_update_integrals(struct task_struct *tsk);
+extern void acct_clear_integrals(struct task_struct *tsk);
+#else
+static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
+{}
+static inline void acct_update_integrals(struct task_struct *tsk)
+{}
+static inline void acct_clear_integrals(struct task_struct *tsk)
+{}
+#endif /* CONFIG_TASK_XACCT */
+
+#endif
+
+
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 04827ca65781..44091c0db0b4 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -174,7 +174,7 @@ struct tty_struct {
struct tty_driver *driver;
int index;
struct tty_ldisc ldisc;
- struct semaphore termios_sem;
+ struct mutex termios_mutex;
struct termios *termios, *termios_locked;
char name[64];
int pgrp;
@@ -190,7 +190,6 @@ struct tty_struct {
struct tty_struct *link;
struct fasync_struct *fasync;
struct tty_bufhead buf;
- int max_flip_cnt;
int alt_speed; /* For magic substitution of 38400 bps */
wait_queue_head_t write_wait;
wait_queue_head_t read_wait;
@@ -308,6 +307,9 @@ extern void tty_ldisc_put(int);
extern void tty_wakeup(struct tty_struct *tty);
extern void tty_ldisc_flush(struct tty_struct *tty);
+extern int tty_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+ unsigned long arg);
+
extern struct mutex tty_mutex;
/* n_tty.c */
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h
index 58c961c9e170..5c8473bb6882 100644
--- a/include/linux/tty_driver.h
+++ b/include/linux/tty_driver.h
@@ -219,7 +219,8 @@ extern struct list_head tty_drivers;
struct tty_driver *alloc_tty_driver(int lines);
void put_tty_driver(struct tty_driver *driver);
-void tty_set_operations(struct tty_driver *driver, struct tty_operations *op);
+void tty_set_operations(struct tty_driver *driver,
+ const struct tty_operations *op);
/* tty driver magic number */
#define TTY_DRIVER_MAGIC 0x5402
diff --git a/include/linux/types.h b/include/linux/types.h
index 3f235660a3cd..750f085fa564 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -33,6 +33,8 @@ typedef __kernel_clockid_t clockid_t;
typedef __kernel_mqd_t mqd_t;
#ifdef __KERNEL__
+typedef _Bool bool;
+
typedef __kernel_uid32_t uid_t;
typedef __kernel_gid32_t gid_t;
typedef __kernel_uid16_t uid16_t;
@@ -127,8 +129,12 @@ typedef __s64 int64_t;
/* this is a special 64bit data type that is 8-byte aligned */
#define aligned_u64 unsigned long long __attribute__((aligned(8)))
-/*
+/**
* The type used for indexing onto a disc or disc partition.
+ *
+ * Linux always considers sectors to be 512 bytes long independently
+ * of the devices real block size.
+ *
* If required, asm/types.h can override it and define
* HAVE_SECTOR_T
*/
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 391e7ed1eb3f..a48d7f11c7be 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -19,4 +19,26 @@ static inline unsigned long __copy_from_user_nocache(void *to,
#endif /* ARCH_HAS_NOCACHE_UACCESS */
+/**
+ * probe_kernel_address(): safely attempt to read from a location
+ * @addr: address to read from - its type is type typeof(retval)*
+ * @retval: read into this variable
+ *
+ * Safely read from address @addr into variable @revtal. If a kernel fault
+ * happens, handle that and return -EFAULT.
+ * We ensure that the __get_user() is executed in atomic context so that
+ * do_page_fault() doesn't attempt to take mmap_sem. This makes
+ * probe_kernel_address() suitable for use within regions where the caller
+ * already holds mmap_sem, or other locks which nest inside mmap_sem.
+ */
+#define probe_kernel_address(addr, retval) \
+ ({ \
+ long ret; \
+ \
+ inc_preempt_count(); \
+ ret = __get_user(retval, addr); \
+ dec_preempt_count(); \
+ ret; \
+ })
+
#endif /* __LINUX_UACCESS_H__ */
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 90223f057d50..014b41d1e308 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -20,10 +20,10 @@
#include <linux/types.h>
struct udphdr {
- __u16 source;
- __u16 dest;
- __u16 len;
- __u16 check;
+ __be16 source;
+ __be16 dest;
+ __be16 len;
+ __be16 check;
};
/* UDP socket options */
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index fc62887c5206..61eef508b041 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -351,6 +351,14 @@ struct ufs2_csum_total {
__fs64 cs_spare[3]; /* future expansion */
};
+struct ufs_csum_core {
+ __u64 cs_ndir; /* number of directories */
+ __u64 cs_nbfree; /* number of free blocks */
+ __u64 cs_nifree; /* number of free inodes */
+ __u64 cs_nffree; /* number of free frags */
+ __u64 cs_numclusters; /* number of free clusters */
+};
+
/*
* File system flags
*/
@@ -715,7 +723,7 @@ struct ufs_cg_private_info {
struct ufs_sb_private_info {
struct ufs_buffer_head s_ubh; /* buffer containing super block */
- struct ufs2_csum_total cs_total;
+ struct ufs_csum_core cs_total;
__u32 s_sblkno; /* offset of super-blocks in filesys */
__u32 s_cblkno; /* offset of cg-block in filesys */
__u32 s_iblkno; /* offset of inode-blocks in filesys */
diff --git a/include/linux/uinput.h b/include/linux/uinput.h
index 7168302f9844..1fd61eeed664 100644
--- a/include/linux/uinput.h
+++ b/include/linux/uinput.h
@@ -22,12 +22,18 @@
* Author: Aristeu Sergio Rozanski Filho <aris@cathedrallabs.org>
*
* Changes/Revisions:
+ * 0.3 24/05/2006 (Anssi Hannula <anssi.hannulagmail.com>)
+ * - update ff support for the changes in kernel interface
+ * - add UINPUT_VERSION
* 0.2 16/10/2004 (Micah Dowty <micah@navi.cx>)
* - added force feedback support
* - added UI_SET_PHYS
* 0.1 20/06/2002
* - first public version
*/
+
+#define UINPUT_VERSION 3
+
#ifdef __KERNEL__
#define UINPUT_MINOR 223
#define UINPUT_NAME "uinput"
@@ -45,7 +51,10 @@ struct uinput_request {
union {
int effect_id;
- struct ff_effect* effect;
+ struct {
+ struct ff_effect *effect;
+ struct ff_effect *old;
+ } upload;
} u;
};
@@ -58,6 +67,7 @@ struct uinput_device {
unsigned char head;
unsigned char tail;
struct input_event buff[UINPUT_BUFFER_SIZE];
+ int ff_effects_max;
struct uinput_request *requests[UINPUT_NUM_REQUESTS];
wait_queue_head_t requests_waitq;
@@ -69,6 +79,7 @@ struct uinput_ff_upload {
int request_id;
int retval;
struct ff_effect effect;
+ struct ff_effect old;
};
struct uinput_ff_erase {
@@ -98,33 +109,33 @@ struct uinput_ff_erase {
#define UI_BEGIN_FF_ERASE _IOWR(UINPUT_IOCTL_BASE, 202, struct uinput_ff_erase)
#define UI_END_FF_ERASE _IOW(UINPUT_IOCTL_BASE, 203, struct uinput_ff_erase)
-/* To write a force-feedback-capable driver, the upload_effect
+/*
+ * To write a force-feedback-capable driver, the upload_effect
* and erase_effect callbacks in input_dev must be implemented.
* The uinput driver will generate a fake input event when one of
* these callbacks are invoked. The userspace code then uses
* ioctls to retrieve additional parameters and send the return code.
* The callback blocks until this return code is sent.
*
- * The described callback mechanism is only used if EV_FF is set.
- * Otherwise, default implementations of upload_effect and erase_effect
- * are used.
+ * The described callback mechanism is only used if ff_effects_max
+ * is set.
*
* To implement upload_effect():
- * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_UPLOAD.
+ * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_UPLOAD.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_upload struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
* 3. Issue a UI_BEGIN_FF_UPLOAD ioctl, giving it the
* uinput_ff_upload struct. It will be filled in with the
- * ff_effect passed to upload_effect().
- * 4. Perform the effect upload, and place the modified ff_effect
- * and a return code back into the uinput_ff_upload struct.
+ * ff_effects passed to upload_effect().
+ * 4. Perform the effect upload, and place a return code back into
+ the uinput_ff_upload struct.
* 5. Issue a UI_END_FF_UPLOAD ioctl, also giving it the
* uinput_ff_upload_effect struct. This will complete execution
* of our upload_effect() handler.
*
* To implement erase_effect():
- * 1. Wait for an event with type==EV_UINPUT and code==UI_FF_ERASE.
+ * 1. Wait for an event with type == EV_UINPUT and code == UI_FF_ERASE.
* A request ID will be given in 'value'.
* 2. Allocate a uinput_ff_erase struct, fill in request_id with
* the 'value' from the EV_UINPUT event.
@@ -133,13 +144,13 @@ struct uinput_ff_erase {
* effect ID passed to erase_effect().
* 4. Perform the effect erasure, and place a return code back
* into the uinput_ff_erase struct.
- * and a return code back into the uinput_ff_erase struct.
* 5. Issue a UI_END_FF_ERASE ioctl, also giving it the
* uinput_ff_erase_effect struct. This will complete execution
* of our erase_effect() handler.
*/
-/* This is the new event type, used only by uinput.
+/*
+ * This is the new event type, used only by uinput.
* 'code' is UI_FF_UPLOAD or UI_FF_ERASE, and 'value'
* is the unique request ID. This number was picked
* arbitrarily, above EV_MAX (since the input system
diff --git a/include/linux/unistd.h b/include/linux/unistd.h
index c18c60f3254e..aa8d5b5e2e3e 100644
--- a/include/linux/unistd.h
+++ b/include/linux/unistd.h
@@ -1,12 +1,8 @@
#ifndef _LINUX_UNISTD_H_
#define _LINUX_UNISTD_H_
-#ifdef __KERNEL__
-extern int errno;
-#endif
-
/*
- * Include machine specific syscallX macros
+ * Include machine specific syscall numbers
*/
#include <asm/unistd.h>
diff --git a/include/linux/unwind.h b/include/linux/unwind.h
index ce48e2cd37a2..749928c161fb 100644
--- a/include/linux/unwind.h
+++ b/include/linux/unwind.h
@@ -12,8 +12,6 @@
* is not much point in implementing the full Dwarf2 unwind API.
*/
-#include <linux/config.h>
-
struct module;
#ifdef CONFIG_STACK_UNWIND
@@ -28,6 +26,7 @@ struct module;
* Initialize unwind support.
*/
extern void unwind_init(void);
+extern void unwind_setup(void);
#ifdef CONFIG_MODULES
@@ -75,6 +74,7 @@ extern int unwind_to_user(struct unwind_frame_info *);
struct unwind_frame_info {};
static inline void unwind_init(void) {}
+static inline void unwind_setup(void) {}
#ifdef CONFIG_MODULES
diff --git a/include/linux/usb.h b/include/linux/usb.h
index d2bd0c8e0154..5482bfb3303d 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -19,6 +19,7 @@
#include <linux/fs.h> /* for struct file_operations */
#include <linux/completion.h> /* for struct completion */
#include <linux/sched.h> /* for current && schedule_timeout */
+#include <linux/mutex.h> /* for struct mutex */
struct usb_device;
struct usb_driver;
@@ -102,8 +103,13 @@ enum usb_interface_condition {
* number from the USB core by calling usb_register_dev().
* @condition: binding state of the interface: not bound, binding
* (in probe()), bound to a driver, or unbinding (in disconnect())
+ * @is_active: flag set when the interface is bound and not suspended.
+ * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
+ * capability during autosuspend.
* @dev: driver model's view of this device
* @class_dev: driver model's class view of this device.
+ * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
+ * allowed unless the counter is 0.
*
* USB device drivers attach to interfaces on a physical device. Each
* interface encapsulates a single high level function, such as feeding
@@ -142,8 +148,12 @@ struct usb_interface {
int minor; /* minor number this interface is
* bound to */
enum usb_interface_condition condition; /* state of binding */
+ unsigned is_active:1; /* the interface is not suspended */
+ unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
+
struct device dev; /* interface specific device info */
struct class_device *class_dev;
+ int pm_usage_cnt; /* usage counter for autosuspend */
};
#define to_usb_interface(d) container_of(d, struct usb_interface, dev)
#define interface_to_usbdev(intf) \
@@ -254,8 +264,6 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
/* ----------------------------------------------------------------------- */
-struct usb_operations;
-
/* USB device number allocation bitmap */
struct usb_devmap {
unsigned long devicemap[128 / (8*sizeof(unsigned long))];
@@ -268,6 +276,7 @@ struct usb_bus {
struct device *controller; /* host/master side hardware */
int busnum; /* Bus number (in order of reg) */
char *bus_name; /* stable id (PCI slot_name etc) */
+ u8 uses_dma; /* Does the host controller use DMA? */
u8 otg_port; /* 0, or number of OTG/HNP port */
unsigned is_b_host:1; /* true during some HNP roleswitches */
unsigned b_hnp_enable:1; /* OTG: did A-Host enable HNP? */
@@ -276,10 +285,8 @@ struct usb_bus {
* round-robin allocation */
struct usb_devmap devmap; /* device address allocation map */
- struct usb_operations *op; /* Operations (specific to the HC) */
struct usb_device *root_hub; /* Root hub */
struct list_head bus_list; /* list of busses */
- void *hcpriv; /* Host Controller private data */
int bandwidth_allocated; /* on this bus: how much of the time
* reserved for periodic (intr/iso)
@@ -294,8 +301,6 @@ struct usb_bus {
struct dentry *usbfs_dentry; /* usbfs dentry entry for the bus */
struct class_device *class_dev; /* class device for this bus */
- struct kref kref; /* reference counting for this bus */
- void (*release)(struct usb_bus *bus);
#if defined(CONFIG_USB_MON)
struct mon_bus *mon_bus; /* non-null when associated */
@@ -350,6 +355,7 @@ struct usb_device {
unsigned short bus_mA; /* Current available from the bus */
u8 portnum; /* Parent port number (origin 1) */
+ u8 level; /* Number of USB hub ancestors */
int have_langid; /* whether string_langid is valid */
int string_langid; /* language ID for strings */
@@ -373,6 +379,15 @@ struct usb_device {
int maxchild; /* Number of ports if hub */
struct usb_device *children[USB_MAXCHILDREN];
+
+ int pm_usage_cnt; /* usage counter for autosuspend */
+#ifdef CONFIG_PM
+ struct work_struct autosuspend; /* for delayed autosuspends */
+ struct mutex pm_mutex; /* protects PM operations */
+
+ unsigned auto_pm:1; /* autosuspend/resume in progress */
+ unsigned do_remote_wakeup:1; /* remote wakeup should be enabled */
+#endif
};
#define to_usb_device(d) container_of(d, struct usb_device, dev)
@@ -384,7 +399,7 @@ extern void usb_put_dev(struct usb_device *dev);
#define usb_unlock_device(udev) up(&(udev)->dev.sem)
#define usb_trylock_device(udev) down_trylock(&(udev)->dev.sem)
extern int usb_lock_device_for_reset(struct usb_device *udev,
- struct usb_interface *iface);
+ const struct usb_interface *iface);
/* USB port reset for device reinitialization */
extern int usb_reset_device(struct usb_device *dev);
@@ -393,6 +408,17 @@ extern int usb_reset_composite_device(struct usb_device *dev,
extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
+/* USB autosuspend and autoresume */
+#ifdef CONFIG_USB_SUSPEND
+extern int usb_autopm_get_interface(struct usb_interface *intf);
+extern void usb_autopm_put_interface(struct usb_interface *intf);
+
+#else
+#define usb_autopm_get_interface(intf) 0
+#define usb_autopm_put_interface(intf) do {} while (0)
+#endif
+
+
/*-------------------------------------------------------------------------*/
/* for drivers using iso endpoints */
@@ -423,10 +449,10 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
int minor);
-extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev,
+extern struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
unsigned ifnum);
extern struct usb_host_interface *usb_altnum_to_altsetting(
- struct usb_interface *intf, unsigned int altnum);
+ const struct usb_interface *intf, unsigned int altnum);
/**
@@ -464,6 +490,20 @@ static inline int usb_make_path (struct usb_device *dev, char *buf,
/*-------------------------------------------------------------------------*/
+extern int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_xfer_isoc(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_is_int_out(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_is_isoc_in(const struct usb_endpoint_descriptor *epd);
+extern int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor *epd);
+
+/*-------------------------------------------------------------------------*/
+
#define USB_DEVICE_ID_MATCH_DEVICE \
(USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
#define USB_DEVICE_ID_MATCH_DEV_RANGE \
@@ -540,7 +580,17 @@ struct usb_dynids {
};
/**
- * struct usb_driver - identifies USB driver to usbcore
+ * struct usbdrv_wrap - wrapper for driver-model structure
+ * @driver: The driver-model core driver structure.
+ * @for_devices: Non-zero for device drivers, 0 for interface drivers.
+ */
+struct usbdrv_wrap {
+ struct device_driver driver;
+ int for_devices;
+};
+
+/**
+ * struct usb_driver - identifies USB interface driver to usbcore
* @name: The driver name should be unique among USB drivers,
* and should normally be the same as the module name.
* @probe: Called to see if the driver is willing to manage a particular
@@ -567,12 +617,14 @@ struct usb_dynids {
* or your driver's probe function will never get called.
* @dynids: used internally to hold the list of dynamically added device
* ids for this driver.
- * @driver: the driver model core driver structure.
+ * @drvwrap: Driver-model core structure wrapper.
* @no_dynamic_id: if set to 1, the USB core will not allow dynamic ids to be
* added to this driver by preventing the sysfs file from being created.
+ * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
+ * for interfaces bound to this driver.
*
- * USB drivers must provide a name, probe() and disconnect() methods,
- * and an id_table. Other driver fields are optional.
+ * USB interface drivers must provide a name, probe() and disconnect()
+ * methods, and an id_table. Other driver fields are optional.
*
* The id_table is used in hotplugging. It holds a set of descriptors,
* and specialized data may be associated with each entry. That table
@@ -606,10 +658,44 @@ struct usb_driver {
const struct usb_device_id *id_table;
struct usb_dynids dynids;
- struct device_driver driver;
+ struct usbdrv_wrap drvwrap;
unsigned int no_dynamic_id:1;
+ unsigned int supports_autosuspend:1;
};
-#define to_usb_driver(d) container_of(d, struct usb_driver, driver)
+#define to_usb_driver(d) container_of(d, struct usb_driver, drvwrap.driver)
+
+/**
+ * struct usb_device_driver - identifies USB device driver to usbcore
+ * @name: The driver name should be unique among USB drivers,
+ * and should normally be the same as the module name.
+ * @probe: Called to see if the driver is willing to manage a particular
+ * device. If it is, probe returns zero and uses dev_set_drvdata()
+ * to associate driver-specific data with the device. If unwilling
+ * to manage the device, return a negative errno value.
+ * @disconnect: Called when the device is no longer accessible, usually
+ * because it has been (or is being) disconnected or the driver's
+ * module is being unloaded.
+ * @suspend: Called when the device is going to be suspended by the system.
+ * @resume: Called when the device is being resumed by the system.
+ * @drvwrap: Driver-model core structure wrapper.
+ * @supports_autosuspend: if set to 0, the USB core will not allow autosuspend
+ * for devices bound to this driver.
+ *
+ * USB drivers must provide all the fields listed above except drvwrap.
+ */
+struct usb_device_driver {
+ const char *name;
+
+ int (*probe) (struct usb_device *udev);
+ void (*disconnect) (struct usb_device *udev);
+
+ int (*suspend) (struct usb_device *udev, pm_message_t message);
+ int (*resume) (struct usb_device *udev);
+ struct usbdrv_wrap drvwrap;
+ unsigned int supports_autosuspend:1;
+};
+#define to_usb_device_driver(d) container_of(d, struct usb_device_driver, \
+ drvwrap.driver)
extern struct bus_type usb_bus_type;
@@ -633,13 +719,17 @@ struct usb_class_driver {
* use these in module_init()/module_exit()
* and don't forget MODULE_DEVICE_TABLE(usb, ...)
*/
-int usb_register_driver(struct usb_driver *, struct module *);
+extern int usb_register_driver(struct usb_driver *, struct module *);
static inline int usb_register(struct usb_driver *driver)
{
return usb_register_driver(driver, THIS_MODULE);
}
extern void usb_deregister(struct usb_driver *);
+extern int usb_register_device_driver(struct usb_device_driver *,
+ struct module *);
+extern void usb_deregister_device_driver(struct usb_device_driver *);
+
extern int usb_register_dev(struct usb_interface *intf,
struct usb_class_driver *class_driver);
extern void usb_deregister_dev(struct usb_interface *intf,
@@ -674,9 +764,8 @@ struct usb_iso_packet_descriptor {
};
struct urb;
-struct pt_regs;
-typedef void (*usb_complete_t)(struct urb *, struct pt_regs *);
+typedef void (*usb_complete_t)(struct urb *);
/**
* struct urb - USB Request Block
@@ -885,7 +974,7 @@ struct urb
* @setup_packet: pointer to the setup_packet buffer
* @transfer_buffer: pointer to the transfer buffer
* @buffer_length: length of the transfer buffer
- * @complete: pointer to the usb_complete_t function
+ * @complete_fn: pointer to the usb_complete_t function
* @context: what to set the urb context to.
*
* Initializes a control urb with the proper information needed to submit
@@ -897,7 +986,7 @@ static inline void usb_fill_control_urb (struct urb *urb,
unsigned char *setup_packet,
void *transfer_buffer,
int buffer_length,
- usb_complete_t complete,
+ usb_complete_t complete_fn,
void *context)
{
spin_lock_init(&urb->lock);
@@ -906,7 +995,7 @@ static inline void usb_fill_control_urb (struct urb *urb,
urb->setup_packet = setup_packet;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
- urb->complete = complete;
+ urb->complete = complete_fn;
urb->context = context;
}
@@ -917,7 +1006,7 @@ static inline void usb_fill_control_urb (struct urb *urb,
* @pipe: the endpoint pipe
* @transfer_buffer: pointer to the transfer buffer
* @buffer_length: length of the transfer buffer
- * @complete: pointer to the usb_complete_t function
+ * @complete_fn: pointer to the usb_complete_t function
* @context: what to set the urb context to.
*
* Initializes a bulk urb with the proper information needed to submit it
@@ -928,7 +1017,7 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
- usb_complete_t complete,
+ usb_complete_t complete_fn,
void *context)
{
spin_lock_init(&urb->lock);
@@ -936,7 +1025,7 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
- urb->complete = complete;
+ urb->complete = complete_fn;
urb->context = context;
}
@@ -947,7 +1036,7 @@ static inline void usb_fill_bulk_urb (struct urb *urb,
* @pipe: the endpoint pipe
* @transfer_buffer: pointer to the transfer buffer
* @buffer_length: length of the transfer buffer
- * @complete: pointer to the usb_complete_t function
+ * @complete_fn: pointer to the usb_complete_t function
* @context: what to set the urb context to.
* @interval: what to set the urb interval to, encoded like
* the endpoint descriptor's bInterval value.
@@ -963,7 +1052,7 @@ static inline void usb_fill_int_urb (struct urb *urb,
unsigned int pipe,
void *transfer_buffer,
int buffer_length,
- usb_complete_t complete,
+ usb_complete_t complete_fn,
void *context,
int interval)
{
@@ -972,7 +1061,7 @@ static inline void usb_fill_int_urb (struct urb *urb,
urb->pipe = pipe;
urb->transfer_buffer = transfer_buffer;
urb->transfer_buffer_length = buffer_length;
- urb->complete = complete;
+ urb->complete = complete_fn;
urb->context = context;
if (dev->speed == USB_SPEED_HIGH)
urb->interval = 1 << (interval - 1);
@@ -990,7 +1079,6 @@ extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
extern int usb_unlink_urb(struct urb *urb);
extern void usb_kill_urb(struct urb *urb);
-#define HAVE_USB_BUFFERS
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
gfp_t mem_flags, dma_addr_t *dma);
void usb_buffer_free (struct usb_device *dev, size_t size,
@@ -1003,14 +1091,14 @@ void usb_buffer_unmap (struct urb *urb);
#endif
struct scatterlist;
-int usb_buffer_map_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int nents);
+int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int nents);
#if 0
-void usb_buffer_dmasync_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int n_hw_ents);
+void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents);
#endif
-void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
- struct scatterlist *sg, int n_hw_ents);
+void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+ struct scatterlist *sg, int n_hw_ents);
/*-------------------------------------------------------------------*
* SYNCHRONOUS CALL SUPPORT *
@@ -1038,6 +1126,9 @@ extern int usb_clear_halt(struct usb_device *dev, int pipe);
extern int usb_reset_configuration(struct usb_device *dev);
extern int usb_set_interface(struct usb_device *dev, int ifnum, int alternate);
+/* this request isn't really synchronous, but it belongs with the others */
+extern int usb_driver_set_configuration(struct usb_device *udev, int config);
+
/*
* timeouts, in milliseconds, used for sending/receiving control messages
* they typically complete within a few frames (msec) after they're issued
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h
new file mode 100644
index 000000000000..6bd235994dc2
--- /dev/null
+++ b/include/linux/usb/audio.h
@@ -0,0 +1,53 @@
+/*
+ * <linux/usb/audio.h> -- USB Audio definitions.
+ *
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Developed for Thumtronics by Grey Innovation
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License ("GPL") version 2, as published by the Free Software Foundation.
+ *
+ * This file holds USB constants and structures defined
+ * by the USB Device Class Definition for Audio Devices.
+ * Comments below reference relevant sections of that document:
+ *
+ * http://www.usb.org/developers/devclass_docs/audio10.pdf
+ */
+
+#ifndef __LINUX_USB_AUDIO_H
+#define __LINUX_USB_AUDIO_H
+
+#include <linux/types.h>
+
+/* A.2 Audio Interface Subclass Codes */
+#define USB_SUBCLASS_AUDIOCONTROL 0x01
+#define USB_SUBCLASS_AUDIOSTREAMING 0x02
+#define USB_SUBCLASS_MIDISTREAMING 0x03
+
+/* 4.3.2 Class-Specific AC Interface Descriptor */
+struct usb_ac_header_descriptor {
+ __u8 bLength; // 8+n
+ __u8 bDescriptorType; // USB_DT_CS_INTERFACE
+ __u8 bDescriptorSubtype; // USB_MS_HEADER
+ __le16 bcdADC; // 0x0100
+ __le16 wTotalLength; // includes Unit and Terminal desc.
+ __u8 bInCollection; // n
+ __u8 baInterfaceNr[]; // [n]
+} __attribute__ ((packed));
+
+#define USB_DT_AC_HEADER_SIZE(n) (8+(n))
+
+/* As above, but more useful for defining your own descriptors: */
+#define DECLARE_USB_AC_HEADER_DESCRIPTOR(n) \
+struct usb_ac_header_descriptor_##n { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubtype; \
+ __le16 bcdADC; \
+ __le16 wTotalLength; \
+ __u8 bInCollection; \
+ __u8 baInterfaceNr[n]; \
+} __attribute__ ((packed))
+
+#endif
diff --git a/include/linux/usb/midi.h b/include/linux/usb/midi.h
new file mode 100644
index 000000000000..11a97d5ffd34
--- /dev/null
+++ b/include/linux/usb/midi.h
@@ -0,0 +1,112 @@
+/*
+ * <linux/usb/midi.h> -- USB MIDI definitions.
+ *
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Developed for Thumtronics by Grey Innovation
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * This software is distributed under the terms of the GNU General Public
+ * License ("GPL") version 2, as published by the Free Software Foundation.
+ *
+ * This file holds USB constants and structures defined
+ * by the USB Device Class Definition for MIDI Devices.
+ * Comments below reference relevant sections of that document:
+ *
+ * http://www.usb.org/developers/devclass_docs/midi10.pdf
+ */
+
+#ifndef __LINUX_USB_MIDI_H
+#define __LINUX_USB_MIDI_H
+
+#include <linux/types.h>
+
+/* A.1 MS Class-Specific Interface Descriptor Subtypes */
+#define USB_MS_HEADER 0x01
+#define USB_MS_MIDI_IN_JACK 0x02
+#define USB_MS_MIDI_OUT_JACK 0x03
+#define USB_MS_ELEMENT 0x04
+
+/* A.2 MS Class-Specific Endpoint Descriptor Subtypes */
+#define USB_MS_GENERAL 0x01
+
+/* A.3 MS MIDI IN and OUT Jack Types */
+#define USB_MS_EMBEDDED 0x01
+#define USB_MS_EXTERNAL 0x02
+
+/* 6.1.2.1 Class-Specific MS Interface Header Descriptor */
+struct usb_ms_header_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubtype;
+ __le16 bcdMSC;
+ __le16 wTotalLength;
+} __attribute__ ((packed));
+
+#define USB_DT_MS_HEADER_SIZE 7
+
+/* 6.1.2.2 MIDI IN Jack Descriptor */
+struct usb_midi_in_jack_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType; // USB_DT_CS_INTERFACE
+ __u8 bDescriptorSubtype; // USB_MS_MIDI_IN_JACK
+ __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL
+ __u8 bJackID;
+ __u8 iJack;
+} __attribute__ ((packed));
+
+#define USB_DT_MIDI_IN_SIZE 6
+
+struct usb_midi_source_pin {
+ __u8 baSourceID;
+ __u8 baSourcePin;
+} __attribute__ ((packed));
+
+/* 6.1.2.3 MIDI OUT Jack Descriptor */
+struct usb_midi_out_jack_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType; // USB_DT_CS_INTERFACE
+ __u8 bDescriptorSubtype; // USB_MS_MIDI_OUT_JACK
+ __u8 bJackType; // USB_MS_EMBEDDED/EXTERNAL
+ __u8 bJackID;
+ __u8 bNrInputPins; // p
+ struct usb_midi_source_pin pins[]; // [p]
+ /*__u8 iJack; -- ommitted due to variable-sized pins[] */
+} __attribute__ ((packed));
+
+#define USB_DT_MIDI_OUT_SIZE(p) (7 + 2 * (p))
+
+/* As above, but more useful for defining your own descriptors: */
+#define DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(p) \
+struct usb_midi_out_jack_descriptor_##p { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubtype; \
+ __u8 bJackType; \
+ __u8 bJackID; \
+ __u8 bNrInputPins; \
+ struct usb_midi_source_pin pins[p]; \
+ __u8 iJack; \
+} __attribute__ ((packed))
+
+/* 6.2.2 Class-Specific MS Bulk Data Endpoint Descriptor */
+struct usb_ms_endpoint_descriptor {
+ __u8 bLength; // 4+n
+ __u8 bDescriptorType; // USB_DT_CS_ENDPOINT
+ __u8 bDescriptorSubtype; // USB_MS_GENERAL
+ __u8 bNumEmbMIDIJack; // n
+ __u8 baAssocJackID[]; // [n]
+} __attribute__ ((packed));
+
+#define USB_DT_MS_ENDPOINT_SIZE(n) (4 + (n))
+
+/* As above, but more useful for defining your own descriptors: */
+#define DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(n) \
+struct usb_ms_endpoint_descriptor_##n { \
+ __u8 bLength; \
+ __u8 bDescriptorType; \
+ __u8 bDescriptorSubtype; \
+ __u8 bNumEmbMIDIJack; \
+ __u8 baAssocJackID[n]; \
+} __attribute__ ((packed))
+
+#endif
diff --git a/include/linux/usb_otg.h b/include/linux/usb/otg.h
index f827f6e203c2..9897f7a818c5 100644
--- a/include/linux/usb_otg.h
+++ b/include/linux/usb/otg.h
@@ -1,4 +1,4 @@
-// include/linux/usb_otg.h
+// include/linux/usb/otg.h
/*
* These APIs may be used between USB controllers. USB device drivers
@@ -52,7 +52,7 @@ struct otg_transceiver {
u16 port_change;
/* bind/unbind the host controller */
- int (*set_host)(struct otg_transceiver *otg,
+ int (*set_host)(struct otg_transceiver *otg,
struct usb_bus *host);
/* bind/unbind the peripheral controller */
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 91c983eef899..91b3ea2bbb14 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -226,10 +226,10 @@ struct usb_serial_driver {
int (*tiocmget) (struct usb_serial_port *port, struct file *file);
int (*tiocmset) (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear);
- void (*read_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_int_callback)(struct urb *urb, struct pt_regs *regs);
- void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
- void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
+ void (*read_int_callback)(struct urb *urb);
+ void (*write_int_callback)(struct urb *urb);
+ void (*read_bulk_callback)(struct urb *urb);
+ void (*write_bulk_callback)(struct urb *urb);
};
#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
@@ -262,8 +262,8 @@ extern int usb_serial_generic_write (struct usb_serial_port *port, const unsigne
extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
extern int usb_serial_generic_write_room (struct usb_serial_port *port);
extern int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port);
-extern void usb_serial_generic_read_bulk_callback (struct urb *urb, struct pt_regs *regs);
-extern void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *regs);
+extern void usb_serial_generic_read_bulk_callback (struct urb *urb);
+extern void usb_serial_generic_write_bulk_callback (struct urb *urb);
extern void usb_serial_generic_shutdown (struct usb_serial *serial);
extern int usb_serial_generic_register (int debug);
extern void usb_serial_generic_deregister (void);
diff --git a/include/linux/usb_usual.h b/include/linux/usb_usual.h
index e7fc5fed5b98..2ae76fe52ff7 100644
--- a/include/linux/usb_usual.h
+++ b/include/linux/usb_usual.h
@@ -108,6 +108,9 @@ enum { US_DO_ALL_FLAGS };
#ifdef CONFIG_USB_STORAGE_ALAUDA
#define US_PR_ALAUDA 0xf4 /* Alauda chipsets */
#endif
+#ifdef CONFIG_USB_STORAGE_KARMA
+#define US_PR_KARMA 0xf5 /* Rio Karma */
+#endif
#define US_PR_DEVICE 0xff /* Use device's value */
diff --git a/include/linux/utime.h b/include/linux/utime.h
index c6bf27b7897e..640be6a1959e 100644
--- a/include/linux/utime.h
+++ b/include/linux/utime.h
@@ -1,6 +1,8 @@
#ifndef _LINUX_UTIME_H
#define _LINUX_UTIME_H
+#include <linux/types.h>
+
struct utimbuf {
time_t actime;
time_t modtime;
diff --git a/include/linux/utsname.h b/include/linux/utsname.h
index 13e1da0c538d..a4555fe3754c 100644
--- a/include/linux/utsname.h
+++ b/include/linux/utsname.h
@@ -30,7 +30,65 @@ struct new_utsname {
char domainname[65];
};
-extern struct new_utsname system_utsname;
+#ifdef __KERNEL__
-extern struct rw_semaphore uts_sem;
+#include <linux/sched.h>
+#include <linux/kref.h>
+#include <linux/nsproxy.h>
+#include <asm/atomic.h>
+
+struct uts_namespace {
+ struct kref kref;
+ struct new_utsname name;
+};
+extern struct uts_namespace init_uts_ns;
+
+static inline void get_uts_ns(struct uts_namespace *ns)
+{
+ kref_get(&ns->kref);
+}
+
+#ifdef CONFIG_UTS_NS
+extern int unshare_utsname(unsigned long unshare_flags,
+ struct uts_namespace **new_uts);
+extern int copy_utsname(int flags, struct task_struct *tsk);
+extern void free_uts_ns(struct kref *kref);
+
+static inline void put_uts_ns(struct uts_namespace *ns)
+{
+ kref_put(&ns->kref, free_uts_ns);
+}
+#else
+static inline int unshare_utsname(unsigned long unshare_flags,
+ struct uts_namespace **new_uts)
+{
+ if (unshare_flags & CLONE_NEWUTS)
+ return -EINVAL;
+
+ return 0;
+}
+
+static inline int copy_utsname(int flags, struct task_struct *tsk)
+{
+ return 0;
+}
+static inline void put_uts_ns(struct uts_namespace *ns)
+{
+}
#endif
+
+static inline struct new_utsname *utsname(void)
+{
+ return &current->nsproxy->uts_ns->name;
+}
+
+static inline struct new_utsname *init_utsname(void)
+{
+ return &init_uts_ns.name;
+}
+
+extern struct rw_semaphore uts_sem;
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_UTSNAME_H */
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index e3715d774197..df5c4654360d 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -243,7 +243,7 @@ struct v4l2_pix_format
#define V4L2_PIX_FMT_YUV420 v4l2_fourcc('Y','U','1','2') /* 12 YUV 4:2:0 */
#define V4L2_PIX_FMT_YYUV v4l2_fourcc('Y','Y','U','V') /* 16 YUV 4:2:2 */
#define V4L2_PIX_FMT_HI240 v4l2_fourcc('H','I','2','4') /* 8 8-bit color */
-#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:1:1 16x16 macroblocks */
+#define V4L2_PIX_FMT_HM12 v4l2_fourcc('H','M','1','2') /* 8 YUV 4:2:0 16x16 macroblocks */
/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */
@@ -276,6 +276,82 @@ struct v4l2_fmtdesc
#define V4L2_FMT_FLAG_COMPRESSED 0x0001
+#if 1
+ /* Experimental Frame Size and frame rate enumeration */
+/*
+ * F R A M E S I Z E E N U M E R A T I O N
+ */
+enum v4l2_frmsizetypes
+{
+ V4L2_FRMSIZE_TYPE_DISCRETE = 1,
+ V4L2_FRMSIZE_TYPE_CONTINUOUS = 2,
+ V4L2_FRMSIZE_TYPE_STEPWISE = 3,
+};
+
+struct v4l2_frmsize_discrete
+{
+ __u32 width; /* Frame width [pixel] */
+ __u32 height; /* Frame height [pixel] */
+};
+
+struct v4l2_frmsize_stepwise
+{
+ __u32 min_width; /* Minimum frame width [pixel] */
+ __u32 max_width; /* Maximum frame width [pixel] */
+ __u32 step_width; /* Frame width step size [pixel] */
+ __u32 min_height; /* Minimum frame height [pixel] */
+ __u32 max_height; /* Maximum frame height [pixel] */
+ __u32 step_height; /* Frame height step size [pixel] */
+};
+
+struct v4l2_frmsizeenum
+{
+ __u32 index; /* Frame size number */
+ __u32 pixel_format; /* Pixel format */
+ __u32 type; /* Frame size type the device supports. */
+
+ union { /* Frame size */
+ struct v4l2_frmsize_discrete discrete;
+ struct v4l2_frmsize_stepwise stepwise;
+ };
+
+ __u32 reserved[2]; /* Reserved space for future use */
+};
+
+/*
+ * F R A M E R A T E E N U M E R A T I O N
+ */
+enum v4l2_frmivaltypes
+{
+ V4L2_FRMIVAL_TYPE_DISCRETE = 1,
+ V4L2_FRMIVAL_TYPE_CONTINUOUS = 2,
+ V4L2_FRMIVAL_TYPE_STEPWISE = 3,
+};
+
+struct v4l2_frmival_stepwise
+{
+ struct v4l2_fract min; /* Minimum frame interval [s] */
+ struct v4l2_fract max; /* Maximum frame interval [s] */
+ struct v4l2_fract step; /* Frame interval step size [s] */
+};
+
+struct v4l2_frmivalenum
+{
+ __u32 index; /* Frame format index */
+ __u32 pixel_format; /* Pixel format */
+ __u32 width; /* Frame width */
+ __u32 height; /* Frame height */
+ __u32 type; /* Frame interval type the device supports. */
+
+ union { /* Frame interval */
+ struct v4l2_fract discrete;
+ struct v4l2_frmival_stepwise stepwise;
+ };
+
+ __u32 reserved[2]; /* Reserved space for future use */
+};
+#endif
+
/*
* T I M E C O D E
*/
@@ -1135,7 +1211,8 @@ struct v4l2_sliced_vbi_cap
(equals frame lines 313-336 for 625 line video
standards, 263-286 for 525 line standards) */
__u16 service_lines[2][24];
- __u32 reserved[4]; /* must be 0 */
+ enum v4l2_buf_type type;
+ __u32 reserved[3]; /* must be 0 */
};
struct v4l2_sliced_vbi_data
@@ -1242,12 +1319,16 @@ struct v4l2_streamparm
#define VIDIOC_G_PRIORITY _IOR ('V', 67, enum v4l2_priority)
#define VIDIOC_S_PRIORITY _IOW ('V', 68, enum v4l2_priority)
#if 1
-#define VIDIOC_G_SLICED_VBI_CAP _IOR ('V', 69, struct v4l2_sliced_vbi_cap)
+#define VIDIOC_G_SLICED_VBI_CAP _IOWR ('V', 69, struct v4l2_sliced_vbi_cap)
#endif
#define VIDIOC_LOG_STATUS _IO ('V', 70)
#define VIDIOC_G_EXT_CTRLS _IOWR ('V', 71, struct v4l2_ext_controls)
#define VIDIOC_S_EXT_CTRLS _IOWR ('V', 72, struct v4l2_ext_controls)
#define VIDIOC_TRY_EXT_CTRLS _IOWR ('V', 73, struct v4l2_ext_controls)
+#if 1
+#define VIDIOC_ENUM_FRAMESIZES _IOWR ('V', 74, struct v4l2_frmsizeenum)
+#define VIDIOC_ENUM_FRAMEINTERVALS _IOWR ('V', 75, struct v4l2_frmivalenum)
+#endif
#ifdef __OLD_VIDIOC_
/* for compatibility, will go away some day */
diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
index dee88c6b6fa7..ce5f1482e6be 100644
--- a/include/linux/vmalloc.h
+++ b/include/linux/vmalloc.h
@@ -62,7 +62,6 @@ extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
extern struct vm_struct *get_vm_area_node(unsigned long size,
unsigned long flags, int node);
extern struct vm_struct *remove_vm_area(void *addr);
-extern struct vm_struct *__remove_vm_area(void *addr);
extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
struct page ***pages);
extern void unmap_vm_area(struct vm_struct *area);
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 176c7f797339..c89df55f6e03 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -3,7 +3,6 @@
#include <linux/types.h>
#include <linux/percpu.h>
-#include <linux/config.h>
#include <linux/mmzone.h>
#include <asm/atomic.h>
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index 918a29763aea..37a1a41f5b65 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -33,7 +33,8 @@ extern int fg_console, last_console, want_console;
int vc_allocate(unsigned int console);
int vc_cons_allocated(unsigned int console);
int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
-void vc_disallocate(unsigned int console);
+int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
+void vc_deallocate(unsigned int console);
void reset_palette(struct vc_data *vc);
void do_blank_screen(int entering_gfx);
void do_unblank_screen(int leaving_gfx);
@@ -83,4 +84,11 @@ void reset_vc(struct vc_data *vc);
extern char con_buf[CON_BUF_SIZE];
extern struct semaphore con_buf_sem;
+struct vt_spawn_console {
+ spinlock_t lock;
+ struct pid *pid;
+ int sig;
+};
+extern struct vt_spawn_console vt_spawn_con;
+
#endif /* _VT_KERN_H */
diff --git a/include/linux/wavefront.h b/include/linux/wavefront.h
deleted file mode 100644
index 51ab3c933acd..000000000000
--- a/include/linux/wavefront.h
+++ /dev/null
@@ -1,675 +0,0 @@
-#ifndef __wavefront_h__
-#define __wavefront_h__
-
-/* WaveFront header file.
- *
- * Copyright (C) by Paul Barton-Davis 1998
- *
- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-
-#if (!defined(__GNUC__) && !defined(__GNUG__))
-
- You will not be able to compile this file correctly without gcc, because
- it is necessary to pack the "wavefront_alias" structure to a size
- of 22 bytes, corresponding to 16-bit alignment (as would have been
- the case on the original platform, MS-DOS). If this is not done,
- then WavePatch-format files cannot be read/written correctly.
- The method used to do this here ("__attribute__((packed)") is
- completely compiler dependent.
-
- All other wavefront_* types end up aligned to 32 bit values and
- still have the same (correct) size.
-
-#else
-
- /* However, note that as of G++ 2.7.3.2, g++ was unable to
- correctly parse *type* __attribute__ tags. It will do the
- right thing if we use the "packed" attribute on each struct
- member, which has the same semantics anyway.
- */
-
-#endif /* __GNUC__ */
-
-/***************************** WARNING ********************************
- PLEASE DO NOT MODIFY THIS FILE IN ANY WAY THAT AFFECTS ITS ABILITY TO
- BE USED WITH EITHER C *OR* C++.
- **********************************************************************/
-
-#ifndef NUM_MIDIKEYS
-#define NUM_MIDIKEYS 128
-#endif /* NUM_MIDIKEYS */
-
-#ifndef NUM_MIDICHANNELS
-#define NUM_MIDICHANNELS 16
-#endif /* NUM_MIDICHANNELS */
-
-/* These are very useful/important. the original wavefront interface
- was developed on a 16 bit system, where sizeof(int) = 2
- bytes. Defining things like this makes the code much more portable, and
- easier to understand without having to toggle back and forth
- between a 16-bit view of the world and a 32-bit one.
- */
-
-typedef short INT16;
-typedef unsigned short UINT16;
-typedef int INT32;
-typedef unsigned int UINT32;
-typedef char CHAR8;
-typedef unsigned char UCHAR8;
-
-/* Pseudo-commands not part of the WaveFront command set.
- These are used for various driver controls and direct
- hardware control.
- */
-
-#define WFC_DEBUG_DRIVER 0
-#define WFC_FX_IOCTL 1
-#define WFC_PATCH_STATUS 2
-#define WFC_PROGRAM_STATUS 3
-#define WFC_SAMPLE_STATUS 4
-#define WFC_DISABLE_INTERRUPTS 5
-#define WFC_ENABLE_INTERRUPTS 6
-#define WFC_INTERRUPT_STATUS 7
-#define WFC_ROMSAMPLES_RDONLY 8
-#define WFC_IDENTIFY_SLOT_TYPE 9
-
-/* Wavefront synth commands
- */
-
-#define WFC_DOWNLOAD_SAMPLE 0x80
-#define WFC_DOWNLOAD_BLOCK 0x81
-#define WFC_DOWNLOAD_MULTISAMPLE 0x82
-#define WFC_DOWNLOAD_SAMPLE_ALIAS 0x83
-#define WFC_DELETE_SAMPLE 0x84
-#define WFC_REPORT_FREE_MEMORY 0x85
-#define WFC_DOWNLOAD_PATCH 0x86
-#define WFC_DOWNLOAD_PROGRAM 0x87
-#define WFC_SET_SYNTHVOL 0x89
-#define WFC_SET_NVOICES 0x8B
-#define WFC_DOWNLOAD_DRUM 0x90
-#define WFC_GET_SYNTHVOL 0x92
-#define WFC_GET_NVOICES 0x94
-#define WFC_DISABLE_CHANNEL 0x9A
-#define WFC_ENABLE_CHANNEL 0x9B
-#define WFC_MISYNTH_OFF 0x9D
-#define WFC_MISYNTH_ON 0x9E
-#define WFC_FIRMWARE_VERSION 0x9F
-#define WFC_GET_NSAMPLES 0xA0
-#define WFC_DISABLE_DRUM_PROGRAM 0xA2
-#define WFC_UPLOAD_PATCH 0xA3
-#define WFC_UPLOAD_PROGRAM 0xA4
-#define WFC_SET_TUNING 0xA6
-#define WFC_GET_TUNING 0xA7
-#define WFC_VMIDI_ON 0xA8
-#define WFC_VMIDI_OFF 0xA9
-#define WFC_MIDI_STATUS 0xAA
-#define WFC_GET_CHANNEL_STATUS 0xAB
-#define WFC_DOWNLOAD_SAMPLE_HEADER 0xAC
-#define WFC_UPLOAD_SAMPLE_HEADER 0xAD
-#define WFC_UPLOAD_MULTISAMPLE 0xAE
-#define WFC_UPLOAD_SAMPLE_ALIAS 0xAF
-#define WFC_IDENTIFY_SAMPLE_TYPE 0xB0
-#define WFC_DOWNLOAD_EDRUM_PROGRAM 0xB1
-#define WFC_UPLOAD_EDRUM_PROGRAM 0xB2
-#define WFC_SET_EDRUM_CHANNEL 0xB3
-#define WFC_INSTOUT_LEVELS 0xB4
-#define WFC_PEAKOUT_LEVELS 0xB5
-#define WFC_REPORT_CHANNEL_PROGRAMS 0xB6
-#define WFC_HARDWARE_VERSION 0xCF
-#define WFC_UPLOAD_SAMPLE_PARAMS 0xD7
-#define WFC_DOWNLOAD_OS 0xF1
-#define WFC_NOOP 0xFF
-
-#define WF_MAX_SAMPLE 512
-#define WF_MAX_PATCH 256
-#define WF_MAX_PROGRAM 128
-
-#define WF_SECTION_MAX 44 /* longest OS section length */
-
-/* # of bytes we send to the board when sending it various kinds of
- substantive data, such as samples, patches and programs.
-*/
-
-#define WF_PROGRAM_BYTES 32
-#define WF_PATCH_BYTES 132
-#define WF_SAMPLE_BYTES 27
-#define WF_SAMPLE_HDR_BYTES 25
-#define WF_ALIAS_BYTES 25
-#define WF_DRUM_BYTES 9
-#define WF_MSAMPLE_BYTES 259 /* (MIDI_KEYS * 2) + 3 */
-
-#define WF_ACK 0x80
-#define WF_DMA_ACK 0x81
-
-/* OR-values for MIDI status bits */
-
-#define WF_MIDI_VIRTUAL_ENABLED 0x1
-#define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2
-#define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4
-
-/* slot indexes for struct address_info: makes code a little more mnemonic */
-
-#define WF_SYNTH_SLOT 0
-#define WF_INTERNAL_MIDI_SLOT 1
-#define WF_EXTERNAL_MIDI_SLOT 2
-
-/* Magic MIDI bytes used to switch I/O streams on the ICS2115 MPU401
- emulation. Note these NEVER show up in output from the device and
- should NEVER be used in input unless Virtual MIDI mode has been
- disabled. If they do show up as input, the results are unpredictable.
-*/
-
-#define WF_EXTERNAL_SWITCH 0xFD
-#define WF_INTERNAL_SWITCH 0xF9
-
-/* Debugging flags */
-
-#define WF_DEBUG_CMD 0x1
-#define WF_DEBUG_DATA 0x2
-#define WF_DEBUG_LOAD_PATCH 0x4
-#define WF_DEBUG_IO 0x8
-
-/* WavePatch file format stuff */
-
-#define WF_WAVEPATCH_VERSION 120; /* Current version number (1.2) */
-#define WF_MAX_COMMENT 64 /* Comment length */
-#define WF_NUM_LAYERS 4
-#define WF_NAME_LENGTH 32
-#define WF_SOURCE_LENGTH 260
-
-#define BankFileID "Bank"
-#define DrumkitFileID "DrumKit"
-#define ProgramFileID "Program"
-
-struct wf_envelope
-{
- UCHAR8 attack_time:7;
- UCHAR8 Unused1:1;
-
- UCHAR8 decay1_time:7;
- UCHAR8 Unused2:1;
-
- UCHAR8 decay2_time:7;
- UCHAR8 Unused3:1;
-
- UCHAR8 sustain_time:7;
- UCHAR8 Unused4:1;
-
- UCHAR8 release_time:7;
- UCHAR8 Unused5:1;
-
- UCHAR8 release2_time:7;
- UCHAR8 Unused6:1;
-
- CHAR8 attack_level;
- CHAR8 decay1_level;
- CHAR8 decay2_level;
- CHAR8 sustain_level;
- CHAR8 release_level;
-
- UCHAR8 attack_velocity:7;
- UCHAR8 Unused7:1;
-
- UCHAR8 volume_velocity:7;
- UCHAR8 Unused8:1;
-
- UCHAR8 keyboard_scaling:7;
- UCHAR8 Unused9:1;
-};
-typedef struct wf_envelope wavefront_envelope;
-
-struct wf_lfo
-{
- UCHAR8 sample_number;
-
- UCHAR8 frequency:7;
- UCHAR8 Unused1:1;
-
- UCHAR8 am_src:4;
- UCHAR8 fm_src:4;
-
- CHAR8 fm_amount;
- CHAR8 am_amount;
- CHAR8 start_level;
- CHAR8 end_level;
-
- UCHAR8 ramp_delay:7;
- UCHAR8 wave_restart:1; /* for LFO2 only */
-
- UCHAR8 ramp_time:7;
- UCHAR8 Unused2:1;
-};
-typedef struct wf_lfo wavefront_lfo;
-
-struct wf_patch
-{
- INT16 frequency_bias; /* ** THIS IS IN MOTOROLA FORMAT!! ** */
-
- UCHAR8 amplitude_bias:7;
- UCHAR8 Unused1:1;
-
- UCHAR8 portamento:7;
- UCHAR8 Unused2:1;
-
- UCHAR8 sample_number;
-
- UCHAR8 pitch_bend:4;
- UCHAR8 sample_msb:1;
- UCHAR8 Unused3:3;
-
- UCHAR8 mono:1;
- UCHAR8 retrigger:1;
- UCHAR8 nohold:1;
- UCHAR8 restart:1;
- UCHAR8 filterconfig:2; /* SDK says "not used" */
- UCHAR8 reuse:1;
- UCHAR8 reset_lfo:1;
-
- UCHAR8 fm_src2:4;
- UCHAR8 fm_src1:4;
-
- CHAR8 fm_amount1;
- CHAR8 fm_amount2;
-
- UCHAR8 am_src:4;
- UCHAR8 Unused4:4;
-
- CHAR8 am_amount;
-
- UCHAR8 fc1_mode:4;
- UCHAR8 fc2_mode:4;
-
- CHAR8 fc1_mod_amount;
- CHAR8 fc1_keyboard_scaling;
- CHAR8 fc1_bias;
- CHAR8 fc2_mod_amount;
- CHAR8 fc2_keyboard_scaling;
- CHAR8 fc2_bias;
-
- UCHAR8 randomizer:7;
- UCHAR8 Unused5:1;
-
- struct wf_envelope envelope1;
- struct wf_envelope envelope2;
- struct wf_lfo lfo1;
- struct wf_lfo lfo2;
-};
-typedef struct wf_patch wavefront_patch;
-
-struct wf_layer
-{
- UCHAR8 patch_number;
-
- UCHAR8 mix_level:7;
- UCHAR8 mute:1;
-
- UCHAR8 split_point:7;
- UCHAR8 play_below:1;
-
- UCHAR8 pan_mod_src:2;
- UCHAR8 pan_or_mod:1;
- UCHAR8 pan:4;
- UCHAR8 split_type:1;
-};
-typedef struct wf_layer wavefront_layer;
-
-struct wf_program
-{
- struct wf_layer layer[WF_NUM_LAYERS];
-};
-typedef struct wf_program wavefront_program;
-
-struct wf_sample_offset
-{
- INT32 Fraction:4;
- INT32 Integer:20;
- INT32 Unused:8;
-};
-typedef struct wf_sample_offset wavefront_sample_offset;
-
-/* Sample slot types */
-
-#define WF_ST_SAMPLE 0
-#define WF_ST_MULTISAMPLE 1
-#define WF_ST_ALIAS 2
-#define WF_ST_EMPTY 3
-
-/* pseudo's */
-
-#define WF_ST_DRUM 4
-#define WF_ST_PROGRAM 5
-#define WF_ST_PATCH 6
-#define WF_ST_SAMPLEHDR 7
-
-#define WF_ST_MASK 0xf
-
-/* Flags for slot status. These occupy the upper bits of the same byte
- as a sample type.
-*/
-
-#define WF_SLOT_USED 0x80 /* XXX don't rely on this being accurate */
-#define WF_SLOT_FILLED 0x40
-#define WF_SLOT_ROM 0x20
-
-#define WF_SLOT_MASK 0xf0
-
-/* channel constants */
-
-#define WF_CH_MONO 0
-#define WF_CH_LEFT 1
-#define WF_CH_RIGHT 2
-
-/* Sample formats */
-
-#define LINEAR_16BIT 0
-#define WHITE_NOISE 1
-#define LINEAR_8BIT 2
-#define MULAW_8BIT 3
-
-#define WF_SAMPLE_IS_8BIT(smpl) ((smpl)->SampleResolution&2)
-
-
-/*
-
- Because most/all of the sample data we pass in via pointers has
- never been copied (just mmap-ed into user space straight from the
- disk), it would be nice to allow handling of multi-channel sample
- data without forcing user-level extraction of the relevant bytes.
-
- So, we need a way of specifying which channel to use (the WaveFront
- only handles mono samples in a given slot), and the only way to do
- this without using some struct other than wavefront_sample as the
- interface is the awful hack of using the unused bits in a
- wavefront_sample:
-
- Val Meaning
- --- -------
- 0 no channel selection (use channel 1, sample is MONO)
- 1 use first channel, and skip one
- 2 use second channel, and skip one
- 3 use third channel, and skip two
- 4 use fourth channel, skip three
- 5 use fifth channel, skip four
- 6 use six channel, skip five
-
-
- This can handle up to 4 channels, and anyone downloading >4 channels
- of sample data just to select one of them needs to find some tools
- like sox ...
-
- NOTE: values 0, 1 and 2 correspond to WF_CH_* above. This is
- important.
-
-*/
-
-#define WF_SET_CHANNEL(samp,chn) \
- (samp)->Unused1 = chn & 0x1; \
- (samp)->Unused2 = chn & 0x2; \
- (samp)->Unused3 = chn & 0x4
-
-#define WF_GET_CHANNEL(samp) \
- (((samp)->Unused3 << 2)|((samp)->Unused2<<1)|(samp)->Unused1)
-
-typedef struct wf_sample {
- struct wf_sample_offset sampleStartOffset;
- struct wf_sample_offset loopStartOffset;
- struct wf_sample_offset loopEndOffset;
- struct wf_sample_offset sampleEndOffset;
- INT16 FrequencyBias;
- UCHAR8 SampleResolution:2; /* sample_format */
- UCHAR8 Unused1:1;
- UCHAR8 Loop:1;
- UCHAR8 Bidirectional:1;
- UCHAR8 Unused2:1;
- UCHAR8 Reverse:1;
- UCHAR8 Unused3:1;
-} wavefront_sample;
-
-typedef struct wf_multisample {
- INT16 NumberOfSamples; /* log2 of the number of samples */
- INT16 SampleNumber[NUM_MIDIKEYS];
-} wavefront_multisample;
-
-typedef struct wf_alias {
- INT16 OriginalSample;
-
- struct wf_sample_offset sampleStartOffset;
- struct wf_sample_offset loopStartOffset;
- struct wf_sample_offset sampleEndOffset;
- struct wf_sample_offset loopEndOffset;
-
- INT16 FrequencyBias;
-
- UCHAR8 SampleResolution:2;
- UCHAR8 Unused1:1;
- UCHAR8 Loop:1;
- UCHAR8 Bidirectional:1;
- UCHAR8 Unused2:1;
- UCHAR8 Reverse:1;
- UCHAR8 Unused3:1;
-
- /* This structure is meant to be padded only to 16 bits on their
- original. Of course, whoever wrote their documentation didn't
- realize that sizeof(struct) can be >=
- sum(sizeof(struct-fields)) and so thought that giving a C level
- description of the structs used in WavePatch files was
- sufficient. I suppose it was, as long as you remember the
- standard 16->32 bit issues.
- */
-
- UCHAR8 sixteen_bit_padding;
-} __attribute__((packed)) wavefront_alias;
-
-typedef struct wf_drum {
- UCHAR8 PatchNumber;
- UCHAR8 MixLevel:7;
- UCHAR8 Unmute:1;
- UCHAR8 Group:4;
- UCHAR8 Unused1:4;
- UCHAR8 PanModSource:2;
- UCHAR8 PanModulated:1;
- UCHAR8 PanAmount:4;
- UCHAR8 Unused2:1;
-} wavefront_drum;
-
-typedef struct wf_drumkit {
- struct wf_drum drum[NUM_MIDIKEYS];
-} wavefront_drumkit;
-
-typedef struct wf_channel_programs {
- UCHAR8 Program[NUM_MIDICHANNELS];
-} wavefront_channel_programs;
-
-/* How to get MIDI channel status from the data returned by
- a WFC_GET_CHANNEL_STATUS command (a struct wf_channel_programs)
-*/
-
-#define WF_CHANNEL_STATUS(ch,wcp) (wcp)[(ch/7)] & (1<<((ch)%7))
-
-typedef union wf_any {
- wavefront_sample s;
- wavefront_multisample ms;
- wavefront_alias a;
- wavefront_program pr;
- wavefront_patch p;
- wavefront_drum d;
-} wavefront_any;
-
-/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h
- might work for other wave-table based patch loading situations.
- Alas, his fears were correct. The WaveFront doesn't even come with
- just "patches", but several different kind of structures that
- control the sound generation process.
- */
-
-typedef struct wf_patch_info {
-
- /* the first two fields are used by the OSS "patch loading" interface
- only, and are unused by the current user-level library.
- */
-
- INT16 key; /* Use WAVEFRONT_PATCH here */
- UINT16 devno; /* fill in when sending */
- UCHAR8 subkey; /* WF_ST_{SAMPLE,ALIAS,etc.} */
-
-#define WAVEFRONT_FIND_FREE_SAMPLE_SLOT 999
-
- UINT16 number; /* patch/sample/prog number */
-
- UINT32 size; /* size of any data included in
- one of the fields in `hdrptr', or
- as `dataptr'.
-
- NOTE: for actual samples, this is
- the size of the *SELECTED CHANNEL*
- even if more data is actually available.
-
- So, a stereo sample (2 channels) of
- 6000 bytes total has `size' = 3000.
-
- See the macros and comments for
- WF_{GET,SET}_CHANNEL above.
-
- */
- wavefront_any __user *hdrptr; /* user-space ptr to hdr bytes */
- UINT16 __user *dataptr; /* actual sample data */
-
- wavefront_any hdr; /* kernel-space copy of hdr bytes */
-} wavefront_patch_info;
-
-/* The maximum number of bytes we will ever move to or from user space
- in response to a WFC_* command. This obviously doesn't cover
- actual sample data.
-*/
-
-#define WF_MAX_READ sizeof(wavefront_multisample)
-#define WF_MAX_WRITE sizeof(wavefront_multisample)
-
-/*
- This allows us to execute any WF command except the download/upload
- ones, which are handled differently due to copyin/copyout issues as
- well as data-nybbling to/from the card.
- */
-
-typedef struct wavefront_control {
- int cmd; /* WFC_* */
- char status; /* return status to user-space */
- unsigned char rbuf[WF_MAX_READ]; /* bytes read from card */
- unsigned char wbuf[WF_MAX_WRITE]; /* bytes written to card */
-} wavefront_control;
-
-#define WFCTL_WFCMD 0x1
-#define WFCTL_LOAD_SPP 0x2
-
-/* Modulator table */
-
-#define WF_MOD_LFO1 0
-#define WF_MOD_LFO2 1
-#define WF_MOD_ENV1 2
-#define WF_MOD_ENV2 3
-#define WF_MOD_KEYBOARD 4
-#define WF_MOD_LOGKEY 5
-#define WF_MOD_VELOCITY 6
-#define WF_MOD_LOGVEL 7
-#define WF_MOD_RANDOM 8
-#define WF_MOD_PRESSURE 9
-#define WF_MOD_MOD_WHEEL 10
-#define WF_MOD_1 WF_MOD_MOD_WHEEL
-#define WF_MOD_BREATH 11
-#define WF_MOD_2 WF_MOD_BREATH
-#define WF_MOD_FOOT 12
-#define WF_MOD_4 WF_MOD_FOOT
-#define WF_MOD_VOLUME 13
-#define WF_MOD_7 WF_MOD_VOLUME
-#define WF_MOD_PAN 14
-#define WF_MOD_10 WF_MOD_PAN
-#define WF_MOD_EXPR 15
-#define WF_MOD_11 WF_MOD_EXPR
-
-/* FX-related material */
-
-typedef struct wf_fx_info {
- int request; /* see list below */
- int data[4]; /* we don't need much */
-} wavefront_fx_info;
-
-/* support for each of these will be forthcoming once I or someone
- else has figured out which of the addresses on page 6 and page 7 of
- the YSS225 control each parameter. Incidentally, these come from
- the Windows driver interface, but again, Turtle Beach didn't
- document the API to use them.
-*/
-
-#define WFFX_SETOUTGAIN 0
-#define WFFX_SETSTEREOOUTGAIN 1
-#define WFFX_SETREVERBIN1GAIN 2
-#define WFFX_SETREVERBIN2GAIN 3
-#define WFFX_SETREVERBIN3GAIN 4
-#define WFFX_SETCHORUSINPORT 5
-#define WFFX_SETREVERBIN1PORT 6
-#define WFFX_SETREVERBIN2PORT 7
-#define WFFX_SETREVERBIN3PORT 8
-#define WFFX_SETEFFECTPORT 9
-#define WFFX_SETAUXPORT 10
-#define WFFX_SETREVERBTYPE 11
-#define WFFX_SETREVERBDELAY 12
-#define WFFX_SETCHORUSLFO 13
-#define WFFX_SETCHORUSPMD 14
-#define WFFX_SETCHORUSAMD 15
-#define WFFX_SETEFFECT 16
-#define WFFX_SETBASEALL 17
-#define WFFX_SETREVERBALL 18
-#define WFFX_SETCHORUSALL 20
-#define WFFX_SETREVERBDEF 22
-#define WFFX_SETCHORUSDEF 23
-#define WFFX_DELAYSETINGAIN 24
-#define WFFX_DELAYSETFBGAIN 25
-#define WFFX_DELAYSETFBLPF 26
-#define WFFX_DELAYSETGAIN 27
-#define WFFX_DELAYSETTIME 28
-#define WFFX_DELAYSETFBTIME 29
-#define WFFX_DELAYSETALL 30
-#define WFFX_DELAYSETDEF 32
-#define WFFX_SDELAYSETINGAIN 33
-#define WFFX_SDELAYSETFBGAIN 34
-#define WFFX_SDELAYSETFBLPF 35
-#define WFFX_SDELAYSETGAIN 36
-#define WFFX_SDELAYSETTIME 37
-#define WFFX_SDELAYSETFBTIME 38
-#define WFFX_SDELAYSETALL 39
-#define WFFX_SDELAYSETDEF 41
-#define WFFX_DEQSETINGAIN 42
-#define WFFX_DEQSETFILTER 43
-#define WFFX_DEQSETALL 44
-#define WFFX_DEQSETDEF 46
-#define WFFX_MUTE 47
-#define WFFX_FLANGESETBALANCE 48
-#define WFFX_FLANGESETDELAY 49
-#define WFFX_FLANGESETDWFFX_TH 50
-#define WFFX_FLANGESETFBGAIN 51
-#define WFFX_FLANGESETINGAIN 52
-#define WFFX_FLANGESETLFO 53
-#define WFFX_FLANGESETALL 54
-#define WFFX_FLANGESETDEF 56
-#define WFFX_PITCHSETSHIFT 57
-#define WFFX_PITCHSETBALANCE 58
-#define WFFX_PITCHSETALL 59
-#define WFFX_PITCHSETDEF 61
-#define WFFX_SRSSETINGAIN 62
-#define WFFX_SRSSETSPACE 63
-#define WFFX_SRSSETCENTER 64
-#define WFFX_SRSSETGAIN 65
-#define WFFX_SRSSETMODE 66
-#define WFFX_SRSSETDEF 68
-
-/* Allow direct user-space control over FX memory/coefficient data.
- In theory this could be used to download the FX microprogram,
- but it would be a little slower, and involve some weird code.
- */
-
-#define WFFX_MEMSET 69
-
-#endif /* __wavefront_h__ */
diff --git a/include/linux/wireless.h b/include/linux/wireless.h
index 13588564b42b..a50a0130fd9e 100644
--- a/include/linux/wireless.h
+++ b/include/linux/wireless.h
@@ -1,7 +1,7 @@
/*
* This file define a set of standard wireless extensions
*
- * Version : 20 17.2.06
+ * Version : 21 14.3.06
*
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
* Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
@@ -69,9 +69,14 @@
/***************************** INCLUDES *****************************/
+/* This header is used in user-space, therefore need to be sanitised
+ * for that purpose. Those includes are usually not compatible with glibc.
+ * To know which includes to use in user-space, check iwlib.h. */
+#ifdef __KERNEL__
#include <linux/types.h> /* for "caddr_t" et al */
#include <linux/socket.h> /* for "struct sockaddr" et al */
#include <linux/if.h> /* for IFNAMSIZ and co... */
+#endif /* __KERNEL__ */
/***************************** VERSION *****************************/
/*
@@ -80,7 +85,7 @@
* (there is some stuff that will be added in the future...)
* I just plan to increment with each new version.
*/
-#define WIRELESS_EXT 20
+#define WIRELESS_EXT 21
/*
* Changes :
@@ -208,6 +213,14 @@
* V19 to V20
* ----------
* - RtNetlink requests support (SET/GET)
+ *
+ * V20 to V21
+ * ----------
+ * - Remove (struct net_device *)->get_wireless_stats()
+ * - Change length in ESSID and NICK to strlen() instead of strlen()+1
+ * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers
+ * - Power/Retry relative values no longer * 100000
+ * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI
*/
/**************************** CONSTANTS ****************************/
@@ -448,6 +461,7 @@
#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
#define IW_QUAL_LEVEL_INVALID 0x20
#define IW_QUAL_NOISE_INVALID 0x40
+#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */
#define IW_QUAL_ALL_INVALID 0x70
/* Frequency flags */
@@ -500,10 +514,12 @@
#define IW_RETRY_TYPE 0xF000 /* Type of parameter */
#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/
#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */
-#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */
+#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */
#define IW_RETRY_MIN 0x0001 /* Value is a minimum */
#define IW_RETRY_MAX 0x0002 /* Value is a maximum */
#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
+#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */
+#define IW_RETRY_LONG 0x0020 /* Value is for long packets */
/* Scanning request flags */
#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */
@@ -1017,7 +1033,7 @@ struct iw_range
/* Note : this frequency list doesn't need to fit channel numbers,
* because each entry contain its channel index */
- __u32 enc_capa; /* IW_ENC_CAPA_* bit field */
+ __u32 enc_capa; /* IW_ENC_CAPA_* bit field */
};
/*
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 56a23a0e7f2e..fc35e6bdfb93 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -1,5 +1,5 @@
/*
- * include/linux/writeback.h.
+ * include/linux/writeback.h
*/
#ifndef WRITEBACK_H
#define WRITEBACK_H
@@ -85,7 +85,6 @@ int wakeup_pdflush(long nr_pages);
void laptop_io_completion(void);
void laptop_sync_completion(void);
void throttle_vm_writeout(void);
-void writeback_congestion_end(void);
/* These are exported to sysctl. */
extern int dirty_background_ratio;
@@ -111,12 +110,15 @@ balance_dirty_pages_ratelimited(struct address_space *mapping)
}
int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0);
+extern int generic_writepages(struct address_space *mapping,
+ struct writeback_control *wbc);
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);
int sync_page_range_nolock(struct inode *inode, struct address_space *mapping,
loff_t pos, loff_t count);
void set_page_dirty_balance(struct page *page);
+void writeback_set_ratelimit(void);
/* pdflush.c */
extern int nr_pdflush_threads; /* Global so it can be exported to sysctl
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index cda8a96e2fa0..0e7f1e20ea45 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -41,6 +41,7 @@ struct xattr_handler {
};
ssize_t vfs_getxattr(struct dentry *, char *, void *, size_t);
+ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
int vfs_setxattr(struct dentry *, char *, void *, size_t, int);
int vfs_removexattr(struct dentry *, char *);
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 14ecd19f4cdc..8ae7f744917b 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -12,8 +12,8 @@
*/
typedef union
{
- __u32 a4;
- __u32 a6[4];
+ __be32 a4;
+ __be32 a6[4];
} xfrm_address_t;
/* Ident of a specific xfrm_state. It is used on input to lookup
@@ -23,7 +23,7 @@ typedef union
struct xfrm_id
{
xfrm_address_t daddr;
- __u32 spi;
+ __be32 spi;
__u8 proto;
};
@@ -49,10 +49,10 @@ struct xfrm_selector
{
xfrm_address_t daddr;
xfrm_address_t saddr;
- __u16 dport;
- __u16 dport_mask;
- __u16 sport;
- __u16 sport_mask;
+ __be16 dport;
+ __be16 dport_mask;
+ __be16 sport;
+ __be16 sport_mask;
__u16 family;
__u8 prefixlen_d;
__u8 prefixlen_s;
@@ -129,7 +129,8 @@ enum
#define XFRM_MODE_TUNNEL 1
#define XFRM_MODE_ROUTEOPTIMIZATION 2
#define XFRM_MODE_IN_TRIGGER 3
-#define XFRM_MODE_MAX 4
+#define XFRM_MODE_BEET 4
+#define XFRM_MODE_MAX 5
/* Netlink configuration messages. */
enum {
@@ -281,7 +282,7 @@ struct xfrm_usersa_info {
struct xfrm_usersa_id {
xfrm_address_t daddr;
- __u32 spi;
+ __be32 spi;
__u16 family;
__u8 proto;
};
diff --git a/include/media/audiochip.h b/include/media/audiochip.h
index 1fd4a2207574..db8823d45a7d 100644
--- a/include/media/audiochip.h
+++ b/include/media/audiochip.h
@@ -18,7 +18,9 @@ enum audiochip {
AUDIO_CHIP_TDA9874,
AUDIO_CHIP_PIC16C54,
/* Provided by msp3400.c */
- AUDIO_CHIP_MSP34XX
+ AUDIO_CHIP_MSP34XX,
+ /* Provided by wm8775.c */
+ AUDIO_CHIP_WM8775
};
#endif /* AUDIOCHIP_H */
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 7bab09b0ed45..8f58406533c6 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -90,6 +90,8 @@ extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_pinnacle_color[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_npgtech[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_norwood[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_proteus_2309[IR_KEYTAB_SIZE];
#endif
diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
index 3c43b95f4c0d..37dad07a8439 100644
--- a/include/media/tuner-types.h
+++ b/include/media/tuner-types.h
@@ -72,6 +72,9 @@ struct tuner_params {
unsigned int port2_invert_for_secam_lc:1;
/* Some cards require PORT1 to be 1 for mono Radio FM and 0 for stereo. */
unsigned int port1_set_for_fm_mono:1;
+ /* Select 18% (or according to datasheet 0%) L standard PLL gating,
+ vs the driver default of 36%. */
+ unsigned int default_pll_gating_18:1;
/* Default tda9887 TOP value in dB for the low band. Default is 0.
Range: -16:+15 */
signed int default_top_low:5;
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 2f7b00b08e88..3116e750132f 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -144,6 +144,7 @@ extern int tuner_debug;
#define TDA9887_DEEMPHASIS_50 (2<<16)
#define TDA9887_DEEMPHASIS_75 (3<<16)
#define TDA9887_AUTOMUTE (1<<18)
+#define TDA9887_GATING_18 (1<<19)
#ifdef __KERNEL__
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 5564db13c0d5..aecc946980a3 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -121,10 +121,17 @@ enum v4l2_chip_ident {
/* general idents: reserved range 0-49 */
V4L2_IDENT_UNKNOWN = 0,
- /* module saa7115: reserved range 100-149 */
+ /* module saa7110: just ident= 100 */
+ V4L2_IDENT_SAA7110 = 100,
+
+ /* module saa7111: just ident= 101 */
+ V4L2_IDENT_SAA7111 = 101,
+
+ /* module saa7115: reserved range 102-149 */
V4L2_IDENT_SAA7113 = 103,
V4L2_IDENT_SAA7114 = 104,
V4L2_IDENT_SAA7115 = 105,
+ V4L2_IDENT_SAA7118 = 108,
/* module saa7127: reserved range 150-199 */
V4L2_IDENT_SAA7127 = 157,
@@ -166,11 +173,12 @@ enum v4l2_chip_ident {
#define VIDIOC_INT_S_STANDBY _IOW('d', 94, u32)
/* only implemented if CONFIG_VIDEO_ADV_DEBUG is defined */
-#define VIDIOC_INT_S_REGISTER _IOR ('d', 100, struct v4l2_register)
+#define VIDIOC_INT_S_REGISTER _IOW ('d', 100, struct v4l2_register)
#define VIDIOC_INT_G_REGISTER _IOWR('d', 101, struct v4l2_register)
-/* Reset the I2C chip */
-#define VIDIOC_INT_RESET _IO ('d', 102)
+/* Generic reset command. The argument selects which subsystems to reset.
+ Passing 0 will always reset the whole chip. */
+#define VIDIOC_INT_RESET _IOW ('d', 102, u32)
/* Set the frequency (in Hz) of the audio clock output.
Used to slave an audio processor to the video decoder, ensuring that audio
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index bb495b7f4680..6a11d772700f 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -9,7 +9,8 @@
#ifndef _V4L2_DEV_H
#define _V4L2_DEV_H
-#define OBSOLETE_OWNER 1 /* to be removed soon */
+#define OBSOLETE_OWNER 1 /* to be removed soon */
+#define OBSOLETE_DEVDATA 1 /* to be removed soon */
#include <linux/poll.h>
#include <linux/fs.h>
@@ -338,8 +339,6 @@ extern int video_usercopy(struct inode *inode, struct file *file,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
#include <linux/mm.h>
-extern struct video_device* video_devdata(struct file*);
-
#define to_video_device(cd) container_of(cd, struct video_device, class_dev)
static inline int __must_check
video_device_create_file(struct video_device *vfd,
@@ -370,9 +369,14 @@ static inline void video_set_drvdata(struct video_device *dev, void *data)
{
dev->priv = data;
}
+
#endif
+#ifdef OBSOLETE_DEVDATA /* to be removed soon */
+/* Obsolete stuff - Still needed for radio devices and obsolete drivers */
+extern struct video_device* video_devdata(struct file*);
extern int video_exclusive_open(struct inode *inode, struct file *file);
extern int video_exclusive_release(struct inode *inode, struct file *file);
+#endif
#endif /* _V4L2_DEV_H */
diff --git a/include/mtd/Kbuild b/include/mtd/Kbuild
index 13e7a3c6d794..e0fe92b03a4e 100644
--- a/include/mtd/Kbuild
+++ b/include/mtd/Kbuild
@@ -1,6 +1,5 @@
header-y += inftl-user.h
header-y += jffs2-user.h
+header-y += mtd-abi.h
header-y += mtd-user.h
header-y += nftl-user.h
-
-unifdef-y += mtd-abi.h
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index b0a67b7ffdcd..f913c30d7b89 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -7,12 +7,6 @@
#ifndef __MTD_ABI_H__
#define __MTD_ABI_H__
-#ifndef __KERNEL__
-/* Urgh. The whole point of splitting this out into
- separate files was to avoid #ifdef __KERNEL__ */
-#define __user
-#endif
-
struct erase_info_user {
uint32_t start;
uint32_t length;
diff --git a/include/net/arp.h b/include/net/arp.h
index 643bded9f557..6a3d9a7d302b 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -12,15 +12,15 @@ extern struct neigh_table arp_tbl;
extern void arp_init(void);
extern int arp_find(unsigned char *haddr, struct sk_buff *skb);
extern int arp_ioctl(unsigned int cmd, void __user *arg);
-extern void arp_send(int type, int ptype, u32 dest_ip,
- struct net_device *dev, u32 src_ip,
+extern void arp_send(int type, int ptype, __be32 dest_ip,
+ struct net_device *dev, __be32 src_ip,
unsigned char *dest_hw, unsigned char *src_hw, unsigned char *th);
extern int arp_bind_neighbour(struct dst_entry *dst);
extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir);
extern void arp_ifdown(struct net_device *dev);
-extern struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
- struct net_device *dev, u32 src_ip,
+extern struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+ struct net_device *dev, __be32 src_ip,
unsigned char *dest_hw, unsigned char *src_hw,
unsigned char *target_hw);
extern void arp_xmit(struct sk_buff *skb);
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index b2bdb1aa0429..10a3eec191fd 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -44,12 +44,13 @@
#define HCI_NOTIFY_VOICE_SETTING 3
/* HCI device types */
-#define HCI_VHCI 0
+#define HCI_VIRTUAL 0
#define HCI_USB 1
#define HCI_PCCARD 2
#define HCI_UART 3
#define HCI_RS232 4
#define HCI_PCI 5
+#define HCI_SDIO 6
/* HCI device quirks */
enum {
@@ -296,6 +297,7 @@ struct hci_cp_host_buffer_size {
/* Link Control */
#define OGF_LINK_CTL 0x01
+
#define OCF_CREATE_CONN 0x0005
struct hci_cp_create_conn {
bdaddr_t bdaddr;
@@ -306,6 +308,11 @@ struct hci_cp_create_conn {
__u8 role_switch;
} __attribute__ ((packed));
+#define OCF_CREATE_CONN_CANCEL 0x0008
+struct hci_cp_create_conn_cancel {
+ bdaddr_t bdaddr;
+} __attribute__ ((packed));
+
#define OCF_ACCEPT_CONN_REQ 0x0009
struct hci_cp_accept_conn_req {
bdaddr_t bdaddr;
@@ -339,6 +346,8 @@ struct hci_cp_inquiry {
#define OCF_INQUIRY_CANCEL 0x0002
+#define OCF_EXIT_PERIODIC_INQ 0x0004
+
#define OCF_LINK_KEY_REPLY 0x000B
struct hci_cp_link_key_reply {
bdaddr_t bdaddr;
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index d84855fe7336..c0fc39620f36 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -72,6 +72,9 @@ struct hci_dev {
__u8 type;
bdaddr_t bdaddr;
__u8 features[8];
+ __u8 hci_ver;
+ __u16 hci_rev;
+ __u16 manufacturer;
__u16 voice_setting;
__u16 pkt_type;
@@ -150,6 +153,7 @@ struct hci_conn {
__u8 mode;
__u8 type;
__u8 out;
+ __u8 attempt;
__u8 dev_class[3];
__u8 features[8];
__u16 interval;
@@ -165,6 +169,10 @@ struct hci_conn {
struct timer_list disc_timer;
struct timer_list idle_timer;
+ struct work_struct work;
+
+ struct device dev;
+
struct hci_dev *hdev;
void *l2cap_data;
void *sco_data;
@@ -282,6 +290,22 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
return NULL;
}
+static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
+ __u8 type, __u16 state)
+{
+ struct hci_conn_hash *h = &hdev->conn_hash;
+ struct list_head *p;
+ struct hci_conn *c;
+
+ list_for_each(p, &h->list) {
+ c = list_entry(p, struct hci_conn, list);
+ if (c->type == type && c->state == state)
+ return c;
+ }
+ return NULL;
+}
+
+void hci_acl_connect(struct hci_conn *conn);
void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
void hci_add_sco(struct hci_conn *conn, __u16 handle);
@@ -309,10 +333,13 @@ static inline void hci_conn_put(struct hci_conn *conn)
if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo;
if (conn->type == ACL_LINK) {
- timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
- if (!conn->out)
- timeo *= 2;
del_timer(&conn->idle_timer);
+ if (conn->state == BT_CONNECTED) {
+ timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
+ if (!conn->out)
+ timeo *= 2;
+ } else
+ timeo = msecs_to_jiffies(10);
} else
timeo = msecs_to_jiffies(10);
mod_timer(&conn->disc_timer, jiffies + timeo);
@@ -412,6 +439,8 @@ static inline int hci_recv_frame(struct sk_buff *skb)
int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
+void hci_conn_add_sysfs(struct hci_conn *conn);
+void hci_conn_del_sysfs(struct hci_conn *conn);
#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))
diff --git a/include/net/cipso_ipv4.h b/include/net/cipso_ipv4.h
index 2d72496c2029..718b4d9c891f 100644
--- a/include/net/cipso_ipv4.h
+++ b/include/net/cipso_ipv4.h
@@ -128,7 +128,9 @@ extern int cipso_v4_rbm_strictvalid;
#ifdef CONFIG_NETLABEL
int cipso_v4_doi_add(struct cipso_v4_doi *doi_def);
-int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head));
+int cipso_v4_doi_remove(u32 doi,
+ struct netlbl_audit *audit_info,
+ void (*callback) (struct rcu_head * head));
struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi);
int cipso_v4_doi_walk(u32 *skip_cnt,
int (*callback) (struct cipso_v4_doi *doi_def, void *arg),
@@ -143,6 +145,7 @@ static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def)
}
static inline int cipso_v4_doi_remove(u32 doi,
+ struct netlbl_audit *audit_info,
void (*callback) (struct rcu_head * head))
{
return 0;
diff --git a/include/net/dst.h b/include/net/dst.h
index a8d825f90305..e156e38e4ac3 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -84,7 +84,7 @@ struct dst_entry
struct dst_ops
{
unsigned short family;
- unsigned short protocol;
+ __be16 protocol;
unsigned gc_thresh;
int (*gc)(void);
diff --git a/include/net/flow.h b/include/net/flow.h
index 3ca210ec1379..3b44d72b27d3 100644
--- a/include/net/flow.h
+++ b/include/net/flow.h
@@ -16,8 +16,8 @@ struct flowi {
union {
struct {
- __u32 daddr;
- __u32 saddr;
+ __be32 daddr;
+ __be32 saddr;
__u32 fwmark;
__u8 tos;
__u8 scope;
@@ -56,8 +56,8 @@ struct flowi {
#define FLOWI_FLAG_MULTIPATHOLDROUTE 0x01
union {
struct {
- __u16 sport;
- __u16 dport;
+ __be16 sport;
+ __be16 dport;
} ports;
struct {
@@ -73,7 +73,7 @@ struct flowi {
__u8 objname[16]; /* Not zero terminated */
} dnports;
- __u32 spi;
+ __be32 spi;
#ifdef CONFIG_IPV6_MIP6
struct {
@@ -97,7 +97,7 @@ struct flowi {
#define FLOW_DIR_FWD 2
struct sock;
-typedef void (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir,
+typedef int (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir,
void **objp, atomic_t **obj_refp);
extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
diff --git a/include/net/genetlink.h b/include/net/genetlink.h
index 4a38d85e4e25..b619314218a6 100644
--- a/include/net/genetlink.h
+++ b/include/net/genetlink.h
@@ -169,4 +169,22 @@ static inline int genlmsg_len(const struct genlmsghdr *gnlh)
return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
}
+/**
+ * genlmsg_msg_size - length of genetlink message not including padding
+ * @payload: length of message payload
+ */
+static inline int genlmsg_msg_size(int payload)
+{
+ return GENL_HDRLEN + payload;
+}
+
+/**
+ * genlmsg_total_size - length of genetlink message including padding
+ * @payload: length of message payload
+ */
+static inline int genlmsg_total_size(int payload)
+{
+ return NLMSG_ALIGN(genlmsg_msg_size(payload));
+}
+
#endif /* __NET_GENERIC_NETLINK_H */
diff --git a/include/net/icmp.h b/include/net/icmp.h
index 05f8ff7d9316..dc09474efcf3 100644
--- a/include/net/icmp.h
+++ b/include/net/icmp.h
@@ -38,7 +38,7 @@ struct dst_entry;
struct net_proto_family;
struct sk_buff;
-extern void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info);
+extern void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info);
extern int icmp_rcv(struct sk_buff *skb);
extern int icmp_ioctl(struct sock *sk, int cmd, unsigned long arg);
extern void icmp_init(struct net_proto_family *ops);
diff --git a/include/net/inet_connection_sock.h b/include/net/inet_connection_sock.h
index de4e83b6da4b..0bcf9f237e1f 100644
--- a/include/net/inet_connection_sock.h
+++ b/include/net/inet_connection_sock.h
@@ -238,9 +238,9 @@ extern struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);
extern struct request_sock *inet_csk_search_req(const struct sock *sk,
struct request_sock ***prevp,
- const __u16 rport,
- const __u32 raddr,
- const __u32 laddr);
+ const __be16 rport,
+ const __be32 raddr,
+ const __be32 laddr);
extern int inet_csk_bind_conflict(const struct sock *sk,
const struct inet_bind_bucket *tb);
extern int inet_csk_get_port(struct inet_hashinfo *hashinfo,
diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h
index b4491c9e2a5a..a9eb2eaf094e 100644
--- a/include/net/inet_hashtables.h
+++ b/include/net/inet_hashtables.h
@@ -272,42 +272,56 @@ static inline int inet_iif(const struct sk_buff *skb)
}
extern struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
- const u32 daddr,
+ const __be32 daddr,
const unsigned short hnum,
const int dif);
static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo,
- u32 daddr, u16 dport, int dif)
+ __be32 daddr, __be16 dport, int dif)
{
return __inet_lookup_listener(hashinfo, daddr, ntohs(dport), dif);
}
/* Socket demux engine toys. */
+/* What happens here is ugly; there's a pair of adjacent fields in
+ struct inet_sock; __be16 dport followed by __u16 num. We want to
+ search by pair, so we combine the keys into a single 32bit value
+ and compare with 32bit value read from &...->dport. Let's at least
+ make sure that it's not mixed with anything else...
+ On 64bit targets we combine comparisons with pair of adjacent __be32
+ fields in the same way.
+*/
+typedef __u32 __bitwise __portpair;
#ifdef __BIG_ENDIAN
#define INET_COMBINED_PORTS(__sport, __dport) \
- (((__u32)(__sport) << 16) | (__u32)(__dport))
+ ((__force __portpair)(((__force __u32)(__be16)(__sport) << 16) | (__u32)(__dport)))
#else /* __LITTLE_ENDIAN */
#define INET_COMBINED_PORTS(__sport, __dport) \
- (((__u32)(__dport) << 16) | (__u32)(__sport))
+ ((__force __portpair)(((__u32)(__dport) << 16) | (__force __u32)(__be16)(__sport)))
#endif
#if (BITS_PER_LONG == 64)
+typedef __u64 __bitwise __addrpair;
#ifdef __BIG_ENDIAN
#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
- const __u64 __name = (((__u64)(__saddr)) << 32) | ((__u64)(__daddr));
+ const __addrpair __name = (__force __addrpair) ( \
+ (((__force __u64)(__be32)(__saddr)) << 32) | \
+ ((__force __u64)(__be32)(__daddr)));
#else /* __LITTLE_ENDIAN */
#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \
- const __u64 __name = (((__u64)(__daddr)) << 32) | ((__u64)(__saddr));
+ const __addrpair __name = (__force __addrpair) ( \
+ (((__force __u64)(__be32)(__daddr)) << 32) | \
+ ((__force __u64)(__be32)(__saddr)));
#endif /* __BIG_ENDIAN */
#define INET_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash)) && \
- ((*((__u64 *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \
- ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \
+ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#define INET_TW_MATCH(__sk, __hash, __cookie, __saddr, __daddr, __ports, __dif)\
(((__sk)->sk_hash == (__hash)) && \
- ((*((__u64 *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \
- ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
+ ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \
+ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#else /* 32-bit arch */
#define INET_ADDR_COOKIE(__name, __saddr, __daddr)
@@ -315,13 +329,13 @@ static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo,
(((__sk)->sk_hash == (__hash)) && \
(inet_sk(__sk)->daddr == (__saddr)) && \
(inet_sk(__sk)->rcv_saddr == (__daddr)) && \
- ((*((__u32 *)&(inet_sk(__sk)->dport))) == (__ports)) && \
+ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#define INET_TW_MATCH(__sk, __hash,__cookie, __saddr, __daddr, __ports, __dif) \
(((__sk)->sk_hash == (__hash)) && \
(inet_twsk(__sk)->tw_daddr == (__saddr)) && \
(inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \
- ((*((__u32 *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
+ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \
(!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif))))
#endif /* 64-bit arch */
@@ -333,12 +347,12 @@ static inline struct sock *inet_lookup_listener(struct inet_hashinfo *hashinfo,
*/
static inline struct sock *
__inet_lookup_established(struct inet_hashinfo *hashinfo,
- const u32 saddr, const u16 sport,
- const u32 daddr, const u16 hnum,
+ const __be32 saddr, const __be16 sport,
+ const __be32 daddr, const u16 hnum,
const int dif)
{
INET_ADDR_COOKIE(acookie, saddr, daddr)
- const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
+ const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
struct sock *sk;
const struct hlist_node *node;
/* Optimize here for direct hit, only listening connections can
@@ -370,8 +384,8 @@ hit:
static inline struct sock *
inet_lookup_established(struct inet_hashinfo *hashinfo,
- const u32 saddr, const u16 sport,
- const u32 daddr, const u16 dport,
+ const __be32 saddr, const __be16 sport,
+ const __be32 daddr, const __be16 dport,
const int dif)
{
return __inet_lookup_established(hashinfo, saddr, sport, daddr,
@@ -379,8 +393,8 @@ static inline struct sock *
}
static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
- const u32 saddr, const u16 sport,
- const u32 daddr, const u16 dport,
+ const __be32 saddr, const __be16 sport,
+ const __be32 daddr, const __be16 dport,
const int dif)
{
u16 hnum = ntohs(dport);
@@ -390,8 +404,8 @@ static inline struct sock *__inet_lookup(struct inet_hashinfo *hashinfo,
}
static inline struct sock *inet_lookup(struct inet_hashinfo *hashinfo,
- const u32 saddr, const u16 sport,
- const u32 daddr, const u16 dport,
+ const __be32 saddr, const __be16 sport,
+ const __be32 daddr, const __be16 dport,
const int dif)
{
struct sock *sk;
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h
index f6242710f2ff..ce6da97bc848 100644
--- a/include/net/inet_sock.h
+++ b/include/net/inet_sock.h
@@ -36,7 +36,7 @@
* @ts_needaddr - Need to record addr of outgoing dev
*/
struct ip_options {
- __u32 faddr;
+ __be32 faddr;
unsigned char optlen;
unsigned char srr;
unsigned char rr;
@@ -62,9 +62,9 @@ struct inet_request_sock {
u16 inet6_rsk_offset;
/* 2 bytes hole, try to pack */
#endif
- u32 loc_addr;
- u32 rmt_addr;
- u16 rmt_port;
+ __be32 loc_addr;
+ __be32 rmt_addr;
+ __be16 rmt_port;
u16 snd_wscale : 4,
rcv_wscale : 4,
tstamp_ok : 1,
@@ -110,15 +110,15 @@ struct inet_sock {
struct ipv6_pinfo *pinet6;
#endif
/* Socket demultiplex comparisons on incoming packets. */
- __u32 daddr;
- __u32 rcv_saddr;
- __u16 dport;
+ __be32 daddr;
+ __be32 rcv_saddr;
+ __be16 dport;
__u16 num;
- __u32 saddr;
+ __be32 saddr;
__s16 uc_ttl;
__u16 cmsg_flags;
struct ip_options *opt;
- __u16 sport;
+ __be16 sport;
__u16 id;
__u8 tos;
__u8 mc_ttl;
@@ -129,7 +129,7 @@ struct inet_sock {
hdrincl:1,
mc_loop:1;
int mc_index;
- __u32 mc_addr;
+ __be32 mc_addr;
struct ip_mc_socklist *mc_list;
struct {
unsigned int flags;
@@ -137,7 +137,7 @@ struct inet_sock {
struct ip_options *opt;
struct rtable *rt;
int length; /* Total length of all frames */
- u32 addr;
+ __be32 addr;
struct flowi fl;
} cork;
};
@@ -167,10 +167,10 @@ static inline void inet_sk_copy_descendant(struct sock *sk_to,
extern int inet_sk_rebuild_header(struct sock *sk);
-static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport,
- const __u32 faddr, const __u16 fport)
+static inline unsigned int inet_ehashfn(const __be32 laddr, const __u16 lport,
+ const __be32 faddr, const __be16 fport)
{
- unsigned int h = (laddr ^ lport) ^ (faddr ^ fport);
+ unsigned int h = ((__force __u32)laddr ^ lport) ^ ((__force __u32)faddr ^ (__force __u32)fport);
h ^= h >> 16;
h ^= h >> 8;
return h;
@@ -179,10 +179,10 @@ static inline unsigned int inet_ehashfn(const __u32 laddr, const __u16 lport,
static inline int inet_sk_ehashfn(const struct sock *sk)
{
const struct inet_sock *inet = inet_sk(sk);
- const __u32 laddr = inet->rcv_saddr;
+ const __be32 laddr = inet->rcv_saddr;
const __u16 lport = inet->num;
- const __u32 faddr = inet->daddr;
- const __u16 fport = inet->dport;
+ const __be32 faddr = inet->daddr;
+ const __be16 fport = inet->dport;
return inet_ehashfn(laddr, lport, faddr, fport);
}
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index 600cb543550d..5f48748fe017 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -120,10 +120,10 @@ struct inet_timewait_sock {
unsigned char tw_rcv_wscale;
/* Socket demultiplex comparisons on incoming packets. */
/* these five are in inet_sock */
- __u16 tw_sport;
- __u32 tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
- __u32 tw_rcv_saddr;
- __u16 tw_dport;
+ __be16 tw_sport;
+ __be32 tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
+ __be32 tw_rcv_saddr;
+ __be16 tw_dport;
__u16 tw_num;
/* And these are ours. */
__u8 tw_ipv6only:1;
@@ -186,7 +186,7 @@ static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk)
return (struct inet_timewait_sock *)sk;
}
-static inline u32 inet_rcv_saddr(const struct sock *sk)
+static inline __be32 inet_rcv_saddr(const struct sock *sk)
{
return likely(sk->sk_state != TCP_TIME_WAIT) ?
inet_sk(sk)->rcv_saddr : inet_twsk(sk)->tw_rcv_saddr;
@@ -196,6 +196,7 @@ static inline void inet_twsk_put(struct inet_timewait_sock *tw)
{
if (atomic_dec_and_test(&tw->tw_refcnt)) {
struct module *owner = tw->tw_prot->owner;
+ twsk_destructor((struct sock *)tw);
#ifdef SOCK_REFCNT_DEBUG
printk(KERN_DEBUG "%s timewait_sock %p released\n",
tw->tw_prot->name, tw);
diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h
index 0965515f40cf..aa10a8178e70 100644
--- a/include/net/inetpeer.h
+++ b/include/net/inetpeer.h
@@ -17,14 +17,15 @@
struct inet_peer
{
+ /* group together avl_left,avl_right,v4daddr to speedup lookups */
struct inet_peer *avl_left, *avl_right;
+ __be32 v4daddr; /* peer's address */
+ __u16 avl_height;
+ __u16 ip_id_count; /* IP ID for the next packet */
struct inet_peer *unused_next, **unused_prevp;
- unsigned long dtime; /* the time of last use of not
+ __u32 dtime; /* the time of last use of not
* referenced entries */
atomic_t refcnt;
- __u32 v4daddr; /* peer's address */
- __u16 avl_height;
- __u16 ip_id_count; /* IP ID for the next packet */
atomic_t rid; /* Frag reception counter */
__u32 tcp_ts;
unsigned long tcp_ts_stamp;
@@ -33,23 +34,10 @@ struct inet_peer
void inet_initpeers(void) __init;
/* can be called with or without local BH being disabled */
-struct inet_peer *inet_getpeer(__u32 daddr, int create);
+struct inet_peer *inet_getpeer(__be32 daddr, int create);
-extern spinlock_t inet_peer_unused_lock;
-extern struct inet_peer **inet_peer_unused_tailp;
/* can be called from BH context or outside */
-static inline void inet_putpeer(struct inet_peer *p)
-{
- spin_lock_bh(&inet_peer_unused_lock);
- if (atomic_dec_and_test(&p->refcnt)) {
- p->unused_prevp = inet_peer_unused_tailp;
- p->unused_next = NULL;
- *inet_peer_unused_tailp = p;
- inet_peer_unused_tailp = &p->unused_next;
- p->dtime = jiffies;
- }
- spin_unlock_bh(&inet_peer_unused_lock);
-}
+extern void inet_putpeer(struct inet_peer *p);
extern spinlock_t inet_peer_idlock;
/* can be called with or without local BH being disabled */
diff --git a/include/net/ip.h b/include/net/ip.h
index 98f908400771..b6d95e553401 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -45,7 +45,7 @@ struct inet_skb_parm
struct ipcm_cookie
{
- u32 addr;
+ __be32 addr;
int oif;
struct ip_options *opt;
};
@@ -86,7 +86,7 @@ extern int igmp_mc_proc_init(void);
*/
extern int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
- u32 saddr, u32 daddr,
+ __be32 saddr, __be32 daddr,
struct ip_options *opt);
extern int ip_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev);
@@ -335,7 +335,7 @@ extern int ip_net_unreachable(struct sk_buff *skb);
* Functions provided by ip_options.c
*/
-extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, u32 daddr, struct rtable *rt, int is_frag);
+extern void ip_options_build(struct sk_buff *skb, struct ip_options *opt, __be32 daddr, struct rtable *rt, int is_frag);
extern int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb);
extern void ip_options_fragment(struct sk_buff *skb);
extern int ip_options_compile(struct ip_options *opt, struct sk_buff *skb);
@@ -363,8 +363,8 @@ extern int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(s
extern int ip_recv_error(struct sock *sk, struct msghdr *msg, int len);
extern void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
- u16 port, u32 info, u8 *payload);
-extern void ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
+ __be16 port, u32 info, u8 *payload);
+extern void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport,
u32 info);
/* sysctl helpers - any sysctl which holds a value that ends up being
diff --git a/include/net/ip6_route.h b/include/net/ip6_route.h
index 6ca6b71dfe0f..c14b70ed4c57 100644
--- a/include/net/ip6_route.h
+++ b/include/net/ip6_route.h
@@ -36,13 +36,6 @@ struct route_info {
#define RT6_LOOKUP_F_REACHABLE 0x2
#define RT6_LOOKUP_F_HAS_SADDR 0x4
-struct pol_chain {
- int type;
- int priority;
- struct fib6_node *rules;
- struct pol_chain *next;
-};
-
extern struct rt6_info ip6_null_entry;
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index fcc159a4ac17..949b932d2f08 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -21,22 +21,19 @@
#include <net/fib_rules.h>
struct fib_config {
- u8 fc_family;
u8 fc_dst_len;
- u8 fc_src_len;
u8 fc_tos;
u8 fc_protocol;
u8 fc_scope;
u8 fc_type;
- /* 1 byte unused */
+ /* 3 bytes unused */
u32 fc_table;
- u32 fc_dst;
- u32 fc_src;
- u32 fc_gw;
+ __be32 fc_dst;
+ __be32 fc_gw;
int fc_oif;
u32 fc_flags;
u32 fc_priority;
- u32 fc_prefsrc;
+ __be32 fc_prefsrc;
struct nlattr *fc_mx;
struct rtnexthop *fc_mp;
int fc_mx_len;
@@ -63,7 +60,7 @@ struct fib_nh {
__u32 nh_tclassid;
#endif
int nh_oif;
- u32 nh_gw;
+ __be32 nh_gw;
};
/*
@@ -78,7 +75,7 @@ struct fib_info {
int fib_dead;
unsigned fib_flags;
int fib_protocol;
- u32 fib_prefsrc;
+ __be32 fib_prefsrc;
u32 fib_priority;
u32 fib_metrics[RTAX_MAX];
#define fib_mtu fib_metrics[RTAX_MTU-1]
@@ -107,8 +104,8 @@ struct fib_result {
unsigned char type;
unsigned char scope;
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
- __u32 network;
- __u32 netmask;
+ __be32 network;
+ __be32 netmask;
#endif
struct fib_info *fi;
#ifdef CONFIG_IP_MULTIPLE_TABLES
@@ -117,7 +114,7 @@ struct fib_result {
};
struct fib_result_nl {
- u32 fl_addr; /* To be looked up*/
+ __be32 fl_addr; /* To be looked up*/
u32 fl_fwmark;
unsigned char fl_tos;
unsigned char fl_scope;
@@ -222,17 +219,17 @@ extern int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *ar
extern int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
extern int inet_rtm_getroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg);
extern int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb);
-extern int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
- struct net_device *dev, u32 *spec_dst, u32 *itag);
+extern int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
+ struct net_device *dev, __be32 *spec_dst, u32 *itag);
extern void fib_select_multipath(const struct flowi *flp, struct fib_result *res);
struct rtentry;
/* Exported by fib_semantics.c */
-extern int ip_fib_check_default(u32 gw, struct net_device *dev);
-extern int fib_sync_down(u32 local, struct net_device *dev, int force);
+extern int ip_fib_check_default(__be32 gw, struct net_device *dev);
+extern int fib_sync_down(__be32 local, struct net_device *dev, int force);
extern int fib_sync_up(struct net_device *dev);
-extern u32 __fib_res_prefsrc(struct fib_result *res);
+extern __be32 __fib_res_prefsrc(struct fib_result *res);
/* Exported by fib_hash.c */
extern struct fib_table *fib_hash_init(u32 id);
diff --git a/include/net/ip_mp_alg.h b/include/net/ip_mp_alg.h
index ac747b64734c..beffdd66ad74 100644
--- a/include/net/ip_mp_alg.h
+++ b/include/net/ip_mp_alg.h
@@ -17,7 +17,7 @@ struct ip_mp_alg_ops {
void (*mp_alg_select_route)(const struct flowi *flp,
struct rtable *rth, struct rtable **rp);
void (*mp_alg_flush)(void);
- void (*mp_alg_set_nhinfo)(__u32 network, __u32 netmask,
+ void (*mp_alg_set_nhinfo)(__be32 network, __be32 netmask,
unsigned char prefixlen,
const struct fib_nh *nh);
void (*mp_alg_remove)(struct rtable *rth);
@@ -59,7 +59,7 @@ static inline void multipath_flush(void)
}
static inline void multipath_set_nhinfo(struct rtable *rth,
- __u32 network, __u32 netmask,
+ __be32 network, __be32 netmask,
unsigned char prefixlen,
const struct fib_nh *nh)
{
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 3b57b159b653..49c717e3b040 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -100,22 +100,22 @@
struct ip_vs_service_user {
/* virtual service addresses */
u_int16_t protocol;
- u_int32_t addr; /* virtual ip address */
- u_int16_t port;
+ __be32 addr; /* virtual ip address */
+ __be16 port;
u_int32_t fwmark; /* firwall mark of service */
/* virtual service options */
char sched_name[IP_VS_SCHEDNAME_MAXLEN];
unsigned flags; /* virtual service flags */
unsigned timeout; /* persistent timeout in sec */
- u_int32_t netmask; /* persistent netmask */
+ __be32 netmask; /* persistent netmask */
};
struct ip_vs_dest_user {
/* destination server address */
- u_int32_t addr;
- u_int16_t port;
+ __be32 addr;
+ __be16 port;
/* real server options */
unsigned conn_flags; /* connection flags */
@@ -163,15 +163,15 @@ struct ip_vs_getinfo {
struct ip_vs_service_entry {
/* which service: user fills in these */
u_int16_t protocol;
- u_int32_t addr; /* virtual address */
- u_int16_t port;
+ __be32 addr; /* virtual address */
+ __be16 port;
u_int32_t fwmark; /* firwall mark of service */
/* service options */
char sched_name[IP_VS_SCHEDNAME_MAXLEN];
unsigned flags; /* virtual service flags */
unsigned timeout; /* persistent timeout */
- u_int32_t netmask; /* persistent netmask */
+ __be32 netmask; /* persistent netmask */
/* number of real servers */
unsigned int num_dests;
@@ -182,8 +182,8 @@ struct ip_vs_service_entry {
struct ip_vs_dest_entry {
- u_int32_t addr; /* destination address */
- u_int16_t port;
+ __be32 addr; /* destination address */
+ __be16 port;
unsigned conn_flags; /* connection flags */
int weight; /* destination weight */
@@ -203,8 +203,8 @@ struct ip_vs_dest_entry {
struct ip_vs_get_dests {
/* which service: user fills in these */
u_int16_t protocol;
- u_int32_t addr; /* virtual address */
- u_int16_t port;
+ __be32 addr; /* virtual address */
+ __be16 port;
u_int32_t fwmark; /* firwall mark of service */
/* number of real servers */
@@ -502,12 +502,12 @@ struct ip_vs_conn {
struct list_head c_list; /* hashed list heads */
/* Protocol, addresses and port numbers */
- __u32 caddr; /* client address */
- __u32 vaddr; /* virtual address */
- __u32 daddr; /* destination address */
- __u16 cport;
- __u16 vport;
- __u16 dport;
+ __be32 caddr; /* client address */
+ __be32 vaddr; /* virtual address */
+ __be32 daddr; /* destination address */
+ __be16 cport;
+ __be16 vport;
+ __be16 dport;
__u16 protocol; /* Which protocol (TCP/UDP) */
/* counter and timer */
@@ -554,12 +554,12 @@ struct ip_vs_service {
atomic_t usecnt; /* use counter */
__u16 protocol; /* which protocol (TCP/UDP) */
- __u32 addr; /* IP address for virtual service */
- __u16 port; /* port number for the service */
+ __be32 addr; /* IP address for virtual service */
+ __be16 port; /* port number for the service */
__u32 fwmark; /* firewall mark of the service */
unsigned flags; /* service status flags */
unsigned timeout; /* persistent timeout in ticks */
- __u32 netmask; /* grouping granularity */
+ __be32 netmask; /* grouping granularity */
struct list_head destinations; /* real server d-linked list */
__u32 num_dests; /* number of servers */
@@ -581,8 +581,8 @@ struct ip_vs_dest {
struct list_head n_list; /* for the dests in the service */
struct list_head d_list; /* for table with all the dests */
- __u32 addr; /* IP address of the server */
- __u16 port; /* port number of the server */
+ __be32 addr; /* IP address of the server */
+ __be16 port; /* port number of the server */
volatile unsigned flags; /* dest status flags */
atomic_t conn_flags; /* flags to copy to conn */
atomic_t weight; /* server weight */
@@ -605,8 +605,8 @@ struct ip_vs_dest {
/* for virtual service */
struct ip_vs_service *svc; /* service it belongs to */
__u16 protocol; /* which protocol (TCP/UDP) */
- __u32 vaddr; /* virtual IP address */
- __u16 vport; /* virtual port number */
+ __be32 vaddr; /* virtual IP address */
+ __be16 vport; /* virtual port number */
__u32 vfwmark; /* firewall mark of service */
};
@@ -648,7 +648,7 @@ struct ip_vs_app
/* members for application incarnations */
struct list_head p_list; /* member in proto app list */
struct ip_vs_app *app; /* its real application */
- __u16 port; /* port number in net order */
+ __be16 port; /* port number in net order */
atomic_t usecnt; /* usage counter */
/* output hook: return false if can't linearize. diff set for TCP. */
@@ -740,11 +740,11 @@ enum {
};
extern struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
extern struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
extern struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port);
/* put back the conn without restarting its timer */
static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
@@ -752,11 +752,11 @@ static inline void __ip_vs_conn_put(struct ip_vs_conn *cp)
atomic_dec(&cp->refcnt);
}
extern void ip_vs_conn_put(struct ip_vs_conn *cp);
-extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __u16 cport);
+extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
extern struct ip_vs_conn *
-ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
- __u32 daddr, __u16 dport, unsigned flags,
+ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
+ __be32 daddr, __be16 dport, unsigned flags,
struct ip_vs_dest *dest);
extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
@@ -887,7 +887,7 @@ extern int sysctl_ip_vs_nat_icmp_send;
extern struct ip_vs_stats ip_vs_stats;
extern struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport);
+ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport);
static inline void ip_vs_service_put(struct ip_vs_service *svc)
{
@@ -895,7 +895,7 @@ static inline void ip_vs_service_put(struct ip_vs_service *svc)
}
extern struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport);
+ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport);
extern int ip_vs_use_count_inc(void);
extern void ip_vs_use_count_dec(void);
extern int ip_vs_control_init(void);
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 72bf47b2a4e0..8223c4410b4b 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -318,8 +318,8 @@ static inline void ipv6_addr_prefix(struct in6_addr *pfx,
#ifndef __HAVE_ARCH_ADDR_SET
static inline void ipv6_addr_set(struct in6_addr *addr,
- __u32 w1, __u32 w2,
- __u32 w3, __u32 w4)
+ __be32 w1, __be32 w2,
+ __be32 w3, __be32 w4)
{
addr->s6_addr32[0] = w1;
addr->s6_addr32[1] = w2;
@@ -337,7 +337,7 @@ static inline int ipv6_addr_equal(const struct in6_addr *a1,
a1->s6_addr32[3] == a2->s6_addr32[3]);
}
-static inline int __ipv6_prefix_equal(const u32 *a1, const u32 *a2,
+static inline int __ipv6_prefix_equal(const __be32 *a1, const __be32 *a2,
unsigned int prefixlen)
{
unsigned pdw, pbi;
diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h
index 1c73bdbc3eb3..9592c374b41d 100644
--- a/include/net/irda/irlan_common.h
+++ b/include/net/irda/irlan_common.h
@@ -98,7 +98,15 @@
#define IRLAN_SHORT 1
#define IRLAN_ARRAY 2
-#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_MAX_HEADER)
+/* IrLAN sits on top if IrTTP */
+#define IRLAN_MAX_HEADER (TTP_HEADER+LMP_HEADER)
+/* 1 byte for the command code and 1 byte for the parameter count */
+#define IRLAN_CMD_HEADER 2
+
+#define IRLAN_STRING_PARAMETER_LEN(name, value) (1 + strlen((name)) + 2 \
+ + strlen ((value)))
+#define IRLAN_BYTE_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 1)
+#define IRLAN_SHORT_PARAMETER_LEN(name) (1 + strlen((name)) + 2 + 2)
/*
* IrLAN client
diff --git a/include/net/irda/irlap_frame.h b/include/net/irda/irlap_frame.h
index 3452ae257c84..9dd54a5002b2 100644
--- a/include/net/irda/irlap_frame.h
+++ b/include/net/irda/irlap_frame.h
@@ -74,6 +74,19 @@ struct discovery_t;
#define PF_BIT 0x10 /* Poll/final bit */
+/* Some IrLAP field lengths */
+/*
+ * Only baud rate triplet is 4 bytes (PV can be 2 bytes).
+ * All others params (7) are 3 bytes, so that's 7*3 + 1*4 bytes.
+ */
+#define IRLAP_NEGOCIATION_PARAMS_LEN 25
+#define IRLAP_DISCOVERY_INFO_LEN 32
+
+struct disc_frame {
+ __u8 caddr; /* Connection address */
+ __u8 control;
+} IRDA_PACK;
+
struct xid_frame {
__u8 caddr; /* Connection address */
__u8 control;
@@ -95,11 +108,25 @@ struct test_frame {
struct ua_frame {
__u8 caddr;
__u8 control;
-
__u32 saddr; /* Source device address */
__u32 daddr; /* Dest device address */
} IRDA_PACK;
-
+
+struct dm_frame {
+ __u8 caddr; /* Connection address */
+ __u8 control;
+} IRDA_PACK;
+
+struct rd_frame {
+ __u8 caddr; /* Connection address */
+ __u8 control;
+} IRDA_PACK;
+
+struct rr_frame {
+ __u8 caddr; /* Connection address */
+ __u8 control;
+} IRDA_PACK;
+
struct i_frame {
__u8 caddr;
__u8 control;
diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h
index 11ecfa58a648..e212b9bc2503 100644
--- a/include/net/irda/irlmp.h
+++ b/include/net/irda/irlmp.h
@@ -48,7 +48,7 @@
#define DEV_ADDR_ANY 0xffffffff
#define LMP_HEADER 2 /* Dest LSAP + Source LSAP */
-#define LMP_CONTROL_HEADER 4
+#define LMP_CONTROL_HEADER 4 /* LMP_HEADER + opcode + parameter */
#define LMP_PID_HEADER 1 /* Used by Ultra */
#define LMP_MAX_HEADER (LMP_CONTROL_HEADER+LAP_MAX_HEADER)
diff --git a/include/net/netdma.h b/include/net/netdma.h
index 7f53cd1d8b1e..f28c6e064e8f 100644
--- a/include/net/netdma.h
+++ b/include/net/netdma.h
@@ -20,7 +20,6 @@
*/
#ifndef NETDMA_H
#define NETDMA_H
-#include <linux/config.h>
#ifdef CONFIG_NET_DMA
#include <linux/dmaengine.h>
#include <linux/skbuff.h>
diff --git a/include/net/netlabel.h b/include/net/netlabel.h
index 6692430063fd..12c214b9eadf 100644
--- a/include/net/netlabel.h
+++ b/include/net/netlabel.h
@@ -34,6 +34,7 @@
#include <linux/net.h>
#include <linux/skbuff.h>
#include <net/netlink.h>
+#include <asm/atomic.h>
/*
* NetLabel - A management interface for maintaining network packet label
@@ -92,14 +93,21 @@
*
*/
+/* NetLabel audit information */
+struct netlbl_audit {
+ u32 secid;
+ uid_t loginuid;
+};
+
/* Domain mapping definition struct */
struct netlbl_dom_map;
/* Domain mapping operations */
-int netlbl_domhsh_remove(const char *domain);
+int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info);
/* LSM security attributes */
struct netlbl_lsm_cache {
+ atomic_t refcount;
void (*free) (const void *data);
void *data;
};
@@ -111,7 +119,7 @@ struct netlbl_lsm_secattr {
unsigned char *mls_cat;
size_t mls_cat_len;
- struct netlbl_lsm_cache cache;
+ struct netlbl_lsm_cache *cache;
};
/*
@@ -120,6 +128,43 @@ struct netlbl_lsm_secattr {
/**
+ * netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache
+ * @flags: the memory allocation flags
+ *
+ * Description:
+ * Allocate and initialize a netlbl_lsm_cache structure. Returns a pointer
+ * on success, NULL on failure.
+ *
+ */
+static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(gfp_t flags)
+{
+ struct netlbl_lsm_cache *cache;
+
+ cache = kzalloc(sizeof(*cache), flags);
+ if (cache)
+ atomic_set(&cache->refcount, 1);
+ return cache;
+}
+
+/**
+ * netlbl_secattr_cache_free - Frees a netlbl_lsm_cache struct
+ * @cache: the struct to free
+ *
+ * Description:
+ * Frees @secattr including all of the internal buffers.
+ *
+ */
+static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache)
+{
+ if (!atomic_dec_and_test(&cache->refcount))
+ return;
+
+ if (cache->free)
+ cache->free(cache->data);
+ kfree(cache);
+}
+
+/**
* netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct
* @secattr: the struct to initialize
*
@@ -137,20 +182,16 @@ static inline int netlbl_secattr_init(struct netlbl_lsm_secattr *secattr)
/**
* netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct
* @secattr: the struct to clear
- * @clear_cache: cache clear flag
*
* Description:
* Destroys the @secattr struct, including freeing all of the internal buffers.
- * If @clear_cache is true then free the cache fields, otherwise leave them
- * intact. The struct must be reset with a call to netlbl_secattr_init()
- * before reuse.
+ * The struct must be reset with a call to netlbl_secattr_init() before reuse.
*
*/
-static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr,
- u32 clear_cache)
+static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr)
{
- if (clear_cache && secattr->cache.data != NULL && secattr->cache.free)
- secattr->cache.free(secattr->cache.data);
+ if (secattr->cache)
+ netlbl_secattr_cache_free(secattr->cache);
kfree(secattr->domain);
kfree(secattr->mls_cat);
}
@@ -172,17 +213,14 @@ static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(int flags)
/**
* netlbl_secattr_free - Frees a netlbl_lsm_secattr struct
* @secattr: the struct to free
- * @clear_cache: cache clear flag
*
* Description:
- * Frees @secattr including all of the internal buffers. If @clear_cache is
- * true then free the cache fields, otherwise leave them intact.
+ * Frees @secattr including all of the internal buffers.
*
*/
-static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr,
- u32 clear_cache)
+static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr)
{
- netlbl_secattr_destroy(secattr, clear_cache);
+ netlbl_secattr_destroy(secattr);
kfree(secattr);
}
diff --git a/include/net/netlink.h b/include/net/netlink.h
index 4ab68a7a636a..ce5cba19c393 100644
--- a/include/net/netlink.h
+++ b/include/net/netlink.h
@@ -831,6 +831,9 @@ static inline int nla_put_msecs(struct sk_buff *skb, int attrtype,
#define NLA_PUT_U32(skb, attrtype, value) \
NLA_PUT_TYPE(skb, u32, attrtype, value)
+#define NLA_PUT_BE32(skb, attrtype, value) \
+ NLA_PUT_TYPE(skb, __be32, attrtype, value)
+
#define NLA_PUT_U64(skb, attrtype, value) \
NLA_PUT_TYPE(skb, u64, attrtype, value)
@@ -853,6 +856,15 @@ static inline u32 nla_get_u32(struct nlattr *nla)
}
/**
+ * nla_get_be32 - return payload of __be32 attribute
+ * @nla: __be32 netlink attribute
+ */
+static inline __be32 nla_get_be32(struct nlattr *nla)
+{
+ return *(__be32 *) nla_data(nla);
+}
+
+/**
* nla_get_u16 - return payload of u16 attribute
* @nla: u16 netlink attribute
*/
diff --git a/include/net/route.h b/include/net/route.h
index 7f93ac0e0899..486e37aff06c 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -62,18 +62,18 @@ struct rtable
__u16 rt_type;
__u16 rt_multipath_alg;
- __u32 rt_dst; /* Path destination */
- __u32 rt_src; /* Path source */
+ __be32 rt_dst; /* Path destination */
+ __be32 rt_src; /* Path source */
int rt_iif;
/* Info on neighbour */
- __u32 rt_gateway;
+ __be32 rt_gateway;
/* Cache lookup keys */
struct flowi fl;
/* Miscellaneous cached information */
- __u32 rt_spec_dst; /* RFC1122 specific destination */
+ __be32 rt_spec_dst; /* RFC1122 specific destination */
struct inet_peer *peer; /* long-living peer info */
};
@@ -109,18 +109,18 @@ extern struct ip_rt_acct *ip_rt_acct;
struct in_device;
extern int ip_rt_init(void);
-extern void ip_rt_redirect(u32 old_gw, u32 dst, u32 new_gw,
- u32 src, struct net_device *dev);
+extern void ip_rt_redirect(__be32 old_gw, __be32 dst, __be32 new_gw,
+ __be32 src, struct net_device *dev);
extern void ip_rt_advice(struct rtable **rp, int advice);
extern void rt_cache_flush(int how);
extern int __ip_route_output_key(struct rtable **, const struct flowi *flp);
extern int ip_route_output_key(struct rtable **, struct flowi *flp);
extern int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
-extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
+extern int ip_route_input(struct sk_buff*, __be32 dst, __be32 src, u8 tos, struct net_device *devin);
extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
extern void ip_rt_send_redirect(struct sk_buff *skb);
-extern unsigned inet_addr_type(u32 addr);
+extern unsigned inet_addr_type(__be32 addr);
extern void ip_rt_multicast_event(struct in_device *);
extern int ip_rt_ioctl(unsigned int cmd, void __user *arg);
extern void ip_rt_get_source(u8 *src, struct rtable *rt);
@@ -144,9 +144,9 @@ static inline char rt_tos2priority(u8 tos)
return ip_tos2prio[IPTOS_TOS(tos)>>1];
}
-static inline int ip_route_connect(struct rtable **rp, u32 dst,
- u32 src, u32 tos, int oif, u8 protocol,
- u16 sport, u16 dport, struct sock *sk)
+static inline int ip_route_connect(struct rtable **rp, __be32 dst,
+ __be32 src, u32 tos, int oif, u8 protocol,
+ __be16 sport, __be16 dport, struct sock *sk)
{
struct flowi fl = { .oif = oif,
.nl_u = { .ip4_u = { .daddr = dst,
@@ -172,7 +172,7 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst,
}
static inline int ip_route_newports(struct rtable **rp, u8 protocol,
- u16 sport, u16 dport, struct sock *sk)
+ __be16 sport, __be16 dport, struct sock *sk)
{
if (sport != (*rp)->fl.fl_ip_sport ||
dport != (*rp)->fl.fl_ip_dport) {
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index ee68a3124076..764e3af5be93 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -139,6 +139,7 @@ int sctp_inet_listen(struct socket *sock, int backlog);
void sctp_write_space(struct sock *sk);
unsigned int sctp_poll(struct file *file, struct socket *sock,
poll_table *wait);
+void sctp_sock_rfree(struct sk_buff *skb);
/*
* sctp/primitive.c
@@ -444,6 +445,19 @@ static inline struct list_head *sctp_list_dequeue(struct list_head *list)
return result;
}
+/* SCTP version of skb_set_owner_r. We need this one because
+ * of the way we have to do receive buffer accounting on bundled
+ * chunks.
+ */
+static inline void sctp_skb_set_owner_r(struct sk_buff *skb, struct sock *sk)
+{
+ struct sctp_ulpevent *event = sctp_skb2event(skb);
+
+ skb->sk = sk;
+ skb->destructor = sctp_sock_rfree;
+ atomic_add(event->rmem_len, &sk->sk_rmem_alloc);
+}
+
/* Tests if the list has one and only one entry. */
static inline int sctp_list_single_entry(struct list_head *head)
{
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
index 6c40cfc4832d..1a4ddc1ec7d2 100644
--- a/include/net/sctp/ulpevent.h
+++ b/include/net/sctp/ulpevent.h
@@ -63,6 +63,7 @@ struct sctp_ulpevent {
__u32 cumtsn;
int msg_flags;
int iif;
+ unsigned int rmem_len;
};
/* Retrieve the skb this event sits inside of. */
diff --git a/include/net/sock.h b/include/net/sock.h
index edd4d73ce7f5..40bb90ebb2d1 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -665,7 +665,6 @@ struct sock_iocb {
struct sock *sk;
struct scm_cookie *scm;
struct msghdr *msg, async_msg;
- struct iovec async_iov;
struct kiocb *kiocb;
};
diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h
index 2544281e1d5e..be293d795e38 100644
--- a/include/net/timewait_sock.h
+++ b/include/net/timewait_sock.h
@@ -19,6 +19,7 @@ struct timewait_sock_ops {
unsigned int twsk_obj_size;
int (*twsk_unique)(struct sock *sk,
struct sock *sktw, void *twp);
+ void (*twsk_destructor)(struct sock *sk);
};
static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
@@ -28,4 +29,10 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
return 0;
}
+static inline void twsk_destructor(struct sock *sk)
+{
+ if (sk->sk_prot->twsk_prot->twsk_destructor != NULL)
+ sk->sk_prot->twsk_prot->twsk_destructor(sk);
+}
+
#endif /* _TIMEWAIT_SOCK_H */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 11e0b1d6bd47..737fdb2ee8a4 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -437,8 +437,8 @@ static inline void xfrm_state_hold(struct xfrm_state *x)
static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
{
- __u32 *a1 = token1;
- __u32 *a2 = token2;
+ __be32 *a1 = token1;
+ __be32 *a2 = token2;
int pdw;
int pbi;
@@ -450,7 +450,7 @@ static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
return 0;
if (pbi) {
- __u32 mask;
+ __be32 mask;
mask = htonl((0xffffffff) << (32 - pbi));
@@ -462,9 +462,9 @@ static __inline__ int addr_match(void *token1, void *token2, int prefixlen)
}
static __inline__
-u16 xfrm_flowi_sport(struct flowi *fl)
+__be16 xfrm_flowi_sport(struct flowi *fl)
{
- u16 port;
+ __be16 port;
switch(fl->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
@@ -487,9 +487,9 @@ u16 xfrm_flowi_sport(struct flowi *fl)
}
static __inline__
-u16 xfrm_flowi_dport(struct flowi *fl)
+__be16 xfrm_flowi_dport(struct flowi *fl)
{
- u16 port;
+ __be16 port;
switch(fl->proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
@@ -912,7 +912,7 @@ extern int xfrm_state_check_expire(struct xfrm_state *x);
extern void xfrm_state_insert(struct xfrm_state *x);
extern int xfrm_state_add(struct xfrm_state *x);
extern int xfrm_state_update(struct xfrm_state *x);
-extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family);
+extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family);
extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family);
#ifdef CONFIG_XFRM_SUB_POLICY
extern int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src,
@@ -935,8 +935,8 @@ static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **s
extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
extern int xfrm_state_delete(struct xfrm_state *x);
extern void xfrm_state_flush(u8 proto);
-extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
-extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
+extern int xfrm_replay_check(struct xfrm_state *x, __be32 seq);
+extern void xfrm_replay_advance(struct xfrm_state *x, __be32 seq);
extern void xfrm_replay_notify(struct xfrm_state *x, int event);
extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb);
extern int xfrm_state_mtu(struct xfrm_state *x, int mtu);
@@ -945,7 +945,7 @@ extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm4_output(struct sk_buff *skb);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
-extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi);
+extern int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi);
extern int xfrm6_rcv(struct sk_buff **pskb);
extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr,
xfrm_address_t *saddr, u8 proto);
@@ -989,13 +989,14 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete);
void xfrm_policy_flush(u8 type);
u32 xfrm_get_acqseq(void);
-void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
+void xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi);
struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto,
xfrm_address_t *daddr, xfrm_address_t *saddr,
int create, unsigned short family);
extern void xfrm_policy_flush(u8 type);
extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
-extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family, int strict);
+extern int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *xdst,
+ struct flowi *fl, int family, int strict);
extern void xfrm_init_pmtu(struct dst_entry *dst);
extern wait_queue_head_t km_waitq;
@@ -1004,7 +1005,7 @@ extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pi
extern int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr);
extern void xfrm_input_init(void);
-extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq);
+extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq);
extern void xfrm_probe_algs(void);
extern int xfrm_count_auth_supported(void);
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 895d212864cd..b401c82036be 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -298,9 +298,9 @@ extern int scsi_execute_async(struct scsi_device *sdev,
void (*done)(void *, char *, int, int),
gfp_t gfp);
-static inline void scsi_device_reprobe(struct scsi_device *sdev)
+static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev)
{
- device_reprobe(&sdev->sdev_gendev);
+ return device_reprobe(&sdev->sdev_gendev);
}
static inline unsigned int sdev_channel(struct scsi_device *sdev)
diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h
index d04d05adfa9b..cf4c219c0b5c 100644
--- a/include/scsi/scsi_tcq.h
+++ b/include/scsi/scsi_tcq.h
@@ -6,7 +6,6 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_host.h>
-
#define MSG_SIMPLE_TAG 0x20
#define MSG_HEAD_TAG 0x21
#define MSG_ORDERED_TAG 0x22
@@ -14,6 +13,7 @@
#define SCSI_NO_TAG (-1) /* identify no tag in use */
+#ifdef CONFIG_BLOCK
/**
* scsi_get_tag_type - get the type of tag the device supports
@@ -100,7 +100,7 @@ static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
struct scsi_device *sdev = cmd->device;
if (blk_rq_tagged(req)) {
- if (sdev->ordered_tags && req->flags & REQ_HARDBARRIER)
+ if (sdev->ordered_tags && req->cmd_flags & REQ_HARDBARRIER)
*msg++ = MSG_ORDERED_TAG;
else
*msg++ = MSG_SIMPLE_TAG;
@@ -144,4 +144,25 @@ static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
return shost->bqt ? 0 : -ENOMEM;
}
+/**
+ * scsi_host_find_tag - find the tagged command by host
+ * @shost: pointer to scsi_host
+ * @tag: tag of the scsi_cmnd
+ *
+ * Notes:
+ * Only works with tags allocated by the generic blk layer.
+ **/
+static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
+ int tag)
+{
+ struct request *req;
+
+ if (tag != SCSI_NO_TAG) {
+ req = blk_map_queue_find_tag(shost->bqt, tag);
+ return req ? (struct scsi_cmnd *)req->special : NULL;
+ }
+ return NULL;
+}
+
+#endif /* CONFIG_BLOCK */
#endif /* _SCSI_SCSI_TCQ_H */
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 0a487fe26d4f..519c49a0fc11 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -11,26 +11,10 @@
Original driver (sg.h):
* Copyright (C) 1992 Lawrence Foard
Version 2 and 3 extensions to driver:
-* Copyright (C) 1998 - 2003 Douglas Gilbert
-
- Version: 3.5.29 (20030529)
- This version is for 2.5 series kernels.
-
- Changes since 3.5.28 (20030308)
- - fix bug introduced in version 3.1.24 (last segment of sgat list)
- Changes since 3.5.27 (20020812)
- - remove procfs entries: hosts, host_hdr + host_strs (now in sysfs)
- - add sysfs sg driver params: def_reserved_size, allow_dio, version
- - new boot option: "sg_allow_dio" and module parameter: "allow_dio"
- - multiple internal changes due to scsi subsystem rework
- Changes since 3.5.26 (20020708)
- - re-add direct IO using Kai Makisara's work
- - re-tab to 8, start using C99-isms
- - simplify memory management
- Changes since 3.5.25 (20020504)
- - driverfs additions
- - copy_to/from_user() fixes [William Stinson]
- - disable kiobufs support
+* Copyright (C) 1998 - 2006 Douglas Gilbert
+
+ Version: 3.5.34 (20060920)
+ This version is for 2.6 series kernels.
For a full changelog see http://www.torque.net/sg
@@ -40,7 +24,7 @@ Map of SG verions to the Linux kernels in which they appear:
2.1.40 2.2.20
3.0.x optional version 3 sg driver for 2.2 series
3.1.17++ 2.4.0++
- 3.5.23++ 2.5.0++
+ 3.5.30++ 2.6.0++
Major new features in SG 3.x driver (cf SG 2.x drivers)
- SG_IO ioctl() combines function if write() and read()
@@ -51,14 +35,15 @@ Major new features in SG 3.x driver (cf SG 2.x drivers)
data into kernel buffers and then use the CPU to copy the data into the
user space (vice versa for writes). That is called "indirect" IO due to
the double handling of data. There are two methods offered to remove the
- redundant copy: 1) direct IO which uses the kernel kiobuf mechanism and
- 2) using the mmap() system call to map the reserve buffer (this driver has
- one reserve buffer per fd) into the user space. Both have their advantages.
+ redundant copy: 1) direct IO and 2) using the mmap() system call to map
+ the reserve buffer (this driver has one reserve buffer per fd) into the
+ user space. Both have their advantages.
In terms of absolute speed mmap() is faster. If speed is not a concern,
indirect IO should be fine. Read the documentation for more information.
- ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' may be
- needed. That pseudo file's content is defaulted to 0. **
+ ** N.B. To use direct IO 'echo 1 > /proc/scsi/sg/allow_dio' or
+ 'echo 1 > /sys/module/sg/parameters/allow_dio' is needed.
+ That attribute is 0 by default. **
Historical note: this SCSI pass-through driver has been known as "sg" for
a decade. In broader kernel discussions "sg" is used to refer to scatter
@@ -72,20 +57,17 @@ Major new features in SG 3.x driver (cf SG 2.x drivers)
http://www.torque.net/sg/p/sg_v3_ho.html
This is a rendering from DocBook source [change the extension to "sgml"
or "xml"]. There are renderings in "ps", "pdf", "rtf" and "txt" (soon).
+ The SG_IO ioctl is now found in other parts kernel (e.g. the block layer).
+ For more information see http://www.torque.net/sg/sg_io.html
The older, version 2 documents discuss the original sg interface in detail:
http://www.torque.net/sg/p/scsi-generic.txt
http://www.torque.net/sg/p/scsi-generic_long.txt
- A version of this document (potentially out of date) may also be found in
- the kernel source tree, probably at:
- Documentation/scsi/scsi-generic.txt .
+ Also available: <kernel_source>/Documentation/scsi/scsi-generic.txt
Utility and test programs are available at the sg web site. They are
- bundled as sg_utils (for the lk 2.2 series) and sg3_utils (for the
- lk 2.4 series).
-
- There is a HOWTO on the Linux SCSI subsystem in the lk 2.4 series at:
- http://www.linuxdoc.org/HOWTO/SCSI-2.4-HOWTO
+ packaged as sg3_utils (for the lk 2.4 and 2.6 series) and sg_utils
+ (for the lk 2.2 series).
*/
@@ -238,13 +220,12 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
#define SG_GET_ACCESS_COUNT 0x2289
-#define SG_SCATTER_SZ (8 * 4096) /* PAGE_SIZE not available to user */
+#define SG_SCATTER_SZ (8 * 4096)
/* Largest size (in bytes) a single scatter-gather list element can have.
- The value must be a power of 2 and <= (PAGE_SIZE * 32) [131072 bytes on
- i386]. The minimum value is PAGE_SIZE. If scatter-gather not supported
- by adapter then this value is the largest data block that can be
- read/written by a single scsi command. The user can find the value of
- PAGE_SIZE by calling getpagesize() defined in unistd.h . */
+ The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'.
+ This value should be a power of 2 (and may be rounded up internally).
+ If scatter-gather is not supported by adapter then this value is the
+ largest data block that can be read/written by a single scsi command. */
#define SG_DEFAULT_RETRIES 0
diff --git a/include/sound/core.h b/include/sound/core.h
index b056ea925ecf..fa1ca0127bab 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -89,10 +89,10 @@ struct snd_device {
struct snd_monitor_file {
struct file *file;
struct snd_monitor_file *next;
+ const struct file_operations *disconnected_f_op;
+ struct list_head shutdown_list;
};
-struct snd_shutdown_f_ops; /* define it later in init.c */
-
/* main structure for soundcard */
struct snd_card {
diff --git a/include/sound/cs4231.h b/include/sound/cs4231.h
index 60b5b92a1319..ab51ce1ba9a5 100644
--- a/include/sound/cs4231.h
+++ b/include/sound/cs4231.h
@@ -273,7 +273,7 @@ unsigned char snd_cs4236_ext_in(struct snd_cs4231 *chip, unsigned char reg);
void snd_cs4231_mce_up(struct snd_cs4231 *chip);
void snd_cs4231_mce_down(struct snd_cs4231 *chip);
-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id);
const char *snd_cs4231_chip_id(struct snd_cs4231 *chip);
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 892e310c504d..3d3c1514cf71 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1194,7 +1194,7 @@ int snd_emu10k1_mixer(struct snd_emu10k1 * emu, int pcm_device, int multi_device
int snd_emu10k1_timer(struct snd_emu10k1 * emu, int device);
int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep);
-irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id);
void snd_emu10k1_voice_init(struct snd_emu10k1 * emu, int voice);
int snd_emu10k1_init_efx(struct snd_emu10k1 *emu);
diff --git a/include/sound/gus.h b/include/sound/gus.h
index 68a664ab97f3..c49ea57db8cc 100644
--- a/include/sound/gus.h
+++ b/include/sound/gus.h
@@ -638,7 +638,7 @@ int snd_gus_initialize(struct snd_gus_card * gus);
/* gus_irq.c */
-irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t snd_gus_interrupt(int irq, void *dev_id);
#ifdef CONFIG_SND_DEBUG
void snd_gus_irq_profile_init(struct snd_gus_card *gus);
#endif
diff --git a/include/sound/initval.h b/include/sound/initval.h
index 2ae76efc696f..e85b90750a59 100644
--- a/include/sound/initval.h
+++ b/include/sound/initval.h
@@ -53,7 +53,7 @@
#ifdef SNDRV_LEGACY_FIND_FREE_IRQ
#include <linux/interrupt.h>
-static irqreturn_t snd_legacy_empty_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_legacy_empty_irq_handler(int irq, void *dev_id)
{
return IRQ_HANDLED;
}
diff --git a/include/sound/mpu401.h b/include/sound/mpu401.h
index ac504321ea56..8c88267e9bea 100644
--- a/include/sound/mpu401.h
+++ b/include/sound/mpu401.h
@@ -106,10 +106,8 @@ struct snd_mpu401 {
*/
-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
-irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
- struct pt_regs *regs);
+irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id);
+irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id);
int snd_mpu401_uart_new(struct snd_card *card,
int device,
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 60d40b34efc0..afaf3e88e086 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -347,6 +347,7 @@ struct snd_pcm_substream {
int number;
char name[32]; /* substream name */
int stream; /* stream (direction) */
+ char latency_id[20]; /* latency identifier */
size_t buffer_bytes_max; /* limit ring buffer size */
struct snd_dma_buffer dma_buffer;
unsigned int dma_buf_id;
diff --git a/include/sound/sb.h b/include/sound/sb.h
index 431d06675e36..2dd5c8e5b4fe 100644
--- a/include/sound/sb.h
+++ b/include/sound/sb.h
@@ -100,7 +100,7 @@ struct snd_sb {
struct snd_rawmidi *rmidi;
struct snd_rawmidi_substream *midi_substream_input;
struct snd_rawmidi_substream *midi_substream_output;
- irqreturn_t (*rmidi_callback)(int irq, void *dev_id, struct pt_regs *regs);
+ irq_handler_t rmidi_callback;
spinlock_t reg_lock;
spinlock_t open_lock;
@@ -286,7 +286,7 @@ int snd_sbdsp_reset(struct snd_sb *chip);
int snd_sbdsp_create(struct snd_card *card,
unsigned long port,
int irq,
- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
+ irq_handler_t irq_handler,
int dma8, int dma16,
unsigned short hardware,
struct snd_sb **r_chip);
@@ -316,7 +316,7 @@ int snd_sb16dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
const struct snd_pcm_ops *snd_sb16dsp_get_pcm_ops(int direction);
int snd_sb16dsp_configure(struct snd_sb *chip);
/* sb16.c */
-irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id);
/* exported mixer stuffs */
enum {
diff --git a/include/sound/version.h b/include/sound/version.h
index 2ee849d0e198..4ad86eb6440b 100644
--- a/include/sound/version.h
+++ b/include/sound/version.h
@@ -1,3 +1,3 @@
-/* include/version.h. Generated by configure. */
-#define CONFIG_SND_VERSION "1.0.12rc1"
-#define CONFIG_SND_DATE " (Thu Jun 22 13:55:50 2006 UTC)"
+/* include/version.h. Generated by alsa/ksync script. */
+#define CONFIG_SND_VERSION "1.0.13"
+#define CONFIG_SND_DATE " (Fri Oct 06 18:28:19 2006 UTC)"
diff --git a/include/sound/vx_core.h b/include/sound/vx_core.h
index dbca14170615..217394652090 100644
--- a/include/sound/vx_core.h
+++ b/include/sound/vx_core.h
@@ -228,7 +228,7 @@ void snd_vx_free_firmware(struct vx_core *chip);
/*
* interrupt handler; exported for pcmcia
*/
-irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs);
+irqreturn_t snd_vx_irq_handler(int irq, void *dev);
/*
* lowlevel functions
diff --git a/include/video/s1d13xxxfb.h b/include/video/s1d13xxxfb.h
index f06cc88607f5..c99d261df8f7 100644
--- a/include/video/s1d13xxxfb.h
+++ b/include/video/s1d13xxxfb.h
@@ -1,4 +1,4 @@
-/* drivers/video/s1d3xxxfb.h
+/* include/video/s1d13xxxfb.h
*
* (c) 2004 Simtec Electronics
* (c) 2005 Thibaut VARENE <varenet@parisc-linux.org>
diff --git a/include/video/sstfb.h b/include/video/sstfb.h
index 3570f9c9b111..5dbf5e7e50a8 100644
--- a/include/video/sstfb.h
+++ b/include/video/sstfb.h
@@ -68,10 +68,6 @@
# define print_var(X,Y...)
#endif
-#define eprintk(X...) printk(KERN_ERR "sstfb: " X)
-#define iprintk(X...) printk(KERN_INFO "sstfb: " X)
-#define wprintk(X...) printk(KERN_WARNING "sstfb: " X)
-
#define BIT(x) (1ul<<(x))
#define POW2(x) (1ul<<(x))
diff --git a/init/Kconfig b/init/Kconfig
index 9a7656f0b5ec..c8b2624af176 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1,5 +1,6 @@
config DEFCONFIG_LIST
string
+ depends on !UML
option defconfig_list
default "/lib/modules/$UNAME_RELEASE/.config"
default "/etc/kernel-config"
@@ -92,7 +93,7 @@ config LOCALVERSION_AUTO
config SWAP
bool "Support for paging of anonymous memory (swap)"
- depends on MMU
+ depends on MMU && BLOCK
default y
help
This option allows you to choose whether you want to have support
@@ -115,6 +116,15 @@ config SYSVIPC
section 6.4 of the Linux Programmer's Guide, available from
<http://www.tldp.org/guides.html>.
+config IPC_NS
+ bool "IPC Namespaces"
+ depends on SYSVIPC
+ default n
+ help
+ Support ipc namespaces. This allows containers, i.e. virtual
+ environments, to use ipc namespaces to provide different ipc
+ objects for different servers. If unsure, say N.
+
config POSIX_MQUEUE
bool "POSIX Message Queues"
depends on NET && EXPERIMENTAL
@@ -182,6 +192,14 @@ config TASK_DELAY_ACCT
Say N if unsure.
+config UTS_NS
+ bool "UTS Namespaces"
+ default n
+ help
+ Support uts namespaces. This allows containers, i.e.
+ vservers, to use uts namespaces to provide different
+ uts info for different servers. If unsure, say N.
+
config AUDIT
bool "Auditing support"
depends on NET
@@ -202,7 +220,7 @@ config AUDITSYSCALL
ensure that INOTIFY is configured.
config IKCONFIG
- bool "Kernel .config support"
+ tristate "Kernel .config support"
---help---
This option enables the complete Linux kernel ".config" file
contents to be saved in the kernel. It provides documentation
@@ -257,6 +275,18 @@ config CC_OPTIMIZE_FOR_SIZE
If unsure, say N.
+config TASK_XACCT
+ bool "Enable extended accounting over taskstats (EXPERIMENTAL)"
+ depends on TASKSTATS
+ help
+ Collect extended task accounting data and send the data
+ to userland for processing over the taskstats interface.
+
+ Say N if unsure.
+
+config SYSCTL
+ bool
+
menuconfig EMBEDDED
bool "Configure standard kernel features (for small systems)"
help
@@ -272,22 +302,22 @@ config UID16
help
This enables the legacy 16-bit UID syscall wrappers.
-config SYSCTL
- bool "Sysctl support" if EMBEDDED
- default y
+config SYSCTL_SYSCALL
+ bool "Sysctl syscall support" if EMBEDDED
+ default n
+ select SYSCTL
---help---
- The sysctl interface provides a means of dynamically changing
- certain kernel parameters and variables on the fly without requiring
- a recompile of the kernel or reboot of the system. The primary
- interface consists of a system call, but if you say Y to "/proc
- file system support", a tree of modifiable sysctl entries will be
- generated beneath the /proc/sys directory. They are explained in the
- files in <file:Documentation/sysctl/>. Note that enabling this
- option will enlarge the kernel by at least 8 KB.
-
- As it is generally a good thing, you should say Y here unless
- building a kernel for install/rescue disks or your system is very
- limited in memory.
+ Enable the deprecated sysctl system call. sys_sysctl uses
+ binary paths that have been found to be a major pain to maintain
+ and use. The interface in /proc/sys is now the primary and what
+ everyone uses.
+
+ Nothing has been using the binary sysctl interface for some
+ time now so nothing should break if you disable sysctl syscall
+ support, and your kernel will get marginally smaller.
+
+ Unless you have an application that uses the sys_sysctl interface
+ you should probably say N here.
config KALLSYMS
bool "Load all symbols for debugging/kksymoops" if EMBEDDED
diff --git a/init/do_mounts.c b/init/do_mounts.c
index b290aadb1d3f..dc1ec0803ef9 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -285,7 +285,11 @@ void __init mount_block_root(char *name, int flags)
{
char *fs_names = __getname();
char *p;
+#ifdef CONFIG_BLOCK
char b[BDEVNAME_SIZE];
+#else
+ const char *b = name;
+#endif
get_fs_names(fs_names);
retry:
@@ -304,7 +308,9 @@ retry:
* Allow the user to distinguish between failed sys_open
* and bad superblock on root device.
*/
+#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");
@@ -316,7 +322,10 @@ retry:
for (p = fs_names; *p; p += strlen(p)+1)
printk(" %s", p);
printk("\n");
- panic("VFS: Unable to mount root fs on %s", __bdevname(ROOT_DEV, b));
+#ifdef CONFIG_BLOCK
+ __bdevname(ROOT_DEV, b);
+#endif
+ panic("VFS: Unable to mount root fs on %s", b);
out:
putname(fs_names);
}
@@ -387,8 +396,10 @@ void __init mount_root(void)
change_floppy("root floppy");
}
#endif
+#ifdef CONFIG_BLOCK
create_dev("/dev/root", ROOT_DEV);
mount_block_root("/dev/root", root_mountflags);
+#endif
}
/*
diff --git a/init/do_mounts.h b/init/do_mounts.h
index e7f2e7fa066e..735705d137ff 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/syscalls.h>
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index a06f037fa000..919a80cb322e 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -1,4 +1,3 @@
-#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
#include <linux/kernel.h>
#include <linux/fs.h>
@@ -35,7 +34,7 @@ static int __init do_linuxrc(void * shell)
(void) sys_open("/dev/console",O_RDWR,0);
(void) sys_dup(0);
(void) sys_dup(0);
- return execve(shell, argv, envp_init);
+ return kernel_execve(shell, argv, envp_init);
}
static void __init handle_initrd(void)
diff --git a/init/do_mounts_md.c b/init/do_mounts_md.c
index 2429e1bf8c60..753dc54a6649 100644
--- a/init/do_mounts_md.c
+++ b/init/do_mounts_md.c
@@ -20,7 +20,7 @@ static struct {
int level;
int chunk;
char *device_names;
-} md_setup_args[MAX_MD_DEVS] __initdata;
+} md_setup_args[256] __initdata;
static int md_setup_ents __initdata;
@@ -61,10 +61,6 @@ static int __init md_setup(char *str)
return 0;
}
str1 = str;
- if (minor >= MAX_MD_DEVS) {
- printk(KERN_WARNING "md: md=%d, Minor device number too high.\n", minor);
- return 0;
- }
for (ent=0 ; ent< md_setup_ents ; ent++)
if (md_setup_args[ent].minor == minor &&
md_setup_args[ent].partitioned == partitioned) {
@@ -72,7 +68,7 @@ static int __init md_setup(char *str)
"Replacing previous definition.\n", partitioned?"d":"", minor);
break;
}
- if (ent >= MAX_MD_DEVS) {
+ if (ent >= ARRAY_SIZE(md_setup_args)) {
printk(KERN_WARNING "md: md=%s%d - too many md initialisations\n", partitioned?"d":"", minor);
return 0;
}
diff --git a/init/main.c b/init/main.c
index 913e48d658ee..36f608a7cfba 100644
--- a/init/main.c
+++ b/init/main.c
@@ -9,8 +9,6 @@
* Simplified starting of init: Michael A. Griffith <grif@acm.org>
*/
-#define __KERNEL_SYSCALLS__
-
#include <linux/types.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
@@ -128,6 +126,18 @@ static char *ramdisk_execute_command;
static unsigned int max_cpus = NR_CPUS;
/*
+ * If set, this is an indication to the drivers that reset the underlying
+ * device before going ahead with the initialization otherwise driver might
+ * rely on the BIOS and skip the reset operation.
+ *
+ * This is useful if kernel is booting in an unreliable environment.
+ * For ex. kdump situaiton where previous kernel has crashed, BIOS has been
+ * skipped and devices will be in unknown state.
+ */
+unsigned int reset_devices;
+EXPORT_SYMBOL(reset_devices);
+
+/*
* Setup routine for controlling SMP activation
*
* Command-line option of "nosmp" or "maxcpus=0" will disable SMP
@@ -153,6 +163,14 @@ static int __init maxcpus(char *str)
__setup("maxcpus=", maxcpus);
+static int __init set_reset_devices(char *str)
+{
+ reset_devices = 1;
+ return 1;
+}
+
+__setup("reset_devices", set_reset_devices);
+
static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
static const char *panic_later, *panic_param;
@@ -485,6 +503,7 @@ asmlinkage void __init start_kernel(void)
printk(KERN_NOTICE);
printk(linux_banner);
setup_arch(&command_line);
+ unwind_setup();
setup_per_cpu_areas();
smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */
@@ -683,7 +702,7 @@ static void do_pre_smp_initcalls(void)
static void run_init_process(char *init_filename)
{
argv_init[0] = init_filename;
- execve(init_filename, argv_init, envp_init);
+ kernel_execve(init_filename, argv_init, envp_init);
}
static int init(void * unused)
@@ -703,6 +722,8 @@ static int init(void * unused)
*/
child_reaper = current;
+ cad_pid = task_pid(current);
+
smp_prepare_cpus(max_cpus);
do_pre_smp_initcalls();
diff --git a/init/version.c b/init/version.c
index e290802c6bd2..8f28344d9c70 100644
--- a/init/version.c
+++ b/init/version.c
@@ -12,22 +12,27 @@
#include <linux/utsname.h>
#include <linux/utsrelease.h>
#include <linux/version.h>
+#include <linux/sched.h>
#define version(a) Version_ ## a
#define version_string(a) version(a)
int version_string(LINUX_VERSION_CODE);
-struct new_utsname system_utsname = {
- .sysname = UTS_SYSNAME,
- .nodename = UTS_NODENAME,
- .release = UTS_RELEASE,
- .version = UTS_VERSION,
- .machine = UTS_MACHINE,
- .domainname = UTS_DOMAINNAME,
+struct uts_namespace init_uts_ns = {
+ .kref = {
+ .refcount = ATOMIC_INIT(2),
+ },
+ .name = {
+ .sysname = UTS_SYSNAME,
+ .nodename = UTS_NODENAME,
+ .release = UTS_RELEASE,
+ .version = UTS_VERSION,
+ .machine = UTS_MACHINE,
+ .domainname = UTS_DOMAINNAME,
+ },
};
-
-EXPORT_SYMBOL(system_utsname);
+EXPORT_SYMBOL_GPL(init_uts_ns);
const char linux_banner[] =
"Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@"
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 02e6f6798972..7c274002c9f5 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -2,7 +2,7 @@
* POSIX message queues filesystem for Linux.
*
* Copyright (C) 2003,2004 Krzysztof Benedyczak (golbi@mat.uni.torun.pl)
- * Michal Wronski (Michal.Wronski@motorola.com)
+ * Michal Wronski (michal.wronski@gmail.com)
*
* Spinlocks: Mohamed Abbas (abbas.mohamed@intel.com)
* Lockless receive & send, fd based notify:
@@ -73,7 +73,7 @@ struct mqueue_inode_info {
struct mq_attr attr;
struct sigevent notify;
- pid_t notify_owner;
+ struct pid* notify_owner;
struct user_struct *user; /* user who created, for accounting */
struct sock *notify_sock;
struct sk_buff *notify_cookie;
@@ -115,7 +115,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mtime = inode->i_ctime = inode->i_atime =
CURRENT_TIME;
@@ -135,7 +134,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
INIT_LIST_HEAD(&info->e_wait_q[0].list);
INIT_LIST_HEAD(&info->e_wait_q[1].list);
info->messages = NULL;
- info->notify_owner = 0;
+ info->notify_owner = NULL;
info->qsize = 0;
info->user = NULL; /* set when all is ok */
memset(&info->attr, 0, sizeof(info->attr));
@@ -169,7 +168,7 @@ static struct inode *mqueue_get_inode(struct super_block *sb, int mode,
/* all is ok */
info->user = get_uid(u);
} else if (S_ISDIR(mode)) {
- inode->i_nlink++;
+ inc_nlink(inode);
/* Some things misbehave if size == 0 on a directory */
inode->i_size = 2 * DIRENT_SIZE;
inode->i_op = &mqueue_dir_inode_operations;
@@ -308,7 +307,7 @@ static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
dir->i_size -= DIRENT_SIZE;
- inode->i_nlink--;
+ drop_nlink(inode);
dput(dentry);
return 0;
}
@@ -339,7 +338,7 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data,
(info->notify_owner &&
info->notify.sigev_notify == SIGEV_SIGNAL) ?
info->notify.sigev_signo : 0,
- info->notify_owner);
+ pid_nr(info->notify_owner));
spin_unlock(&info->lock);
buffer[sizeof(buffer)-1] = '\0';
slen = strlen(buffer)+1;
@@ -364,7 +363,7 @@ static int mqueue_flush_file(struct file *filp, fl_owner_t id)
struct mqueue_inode_info *info = MQUEUE_I(filp->f_dentry->d_inode);
spin_lock(&info->lock);
- if (current->tgid == info->notify_owner)
+ if (task_tgid(current) == info->notify_owner)
remove_notification(info);
spin_unlock(&info->lock);
@@ -519,8 +518,8 @@ static void __do_notify(struct mqueue_inode_info *info)
sig_i.si_pid = current->tgid;
sig_i.si_uid = current->uid;
- kill_proc_info(info->notify.sigev_signo,
- &sig_i, info->notify_owner);
+ kill_pid_info(info->notify.sigev_signo,
+ &sig_i, info->notify_owner);
break;
case SIGEV_THREAD:
set_cookie(info->notify_cookie, NOTIFY_WOKENUP);
@@ -529,7 +528,8 @@ static void __do_notify(struct mqueue_inode_info *info)
break;
}
/* after notification unregisters process */
- info->notify_owner = 0;
+ put_pid(info->notify_owner);
+ info->notify_owner = NULL;
}
wake_up(&info->wait_q);
}
@@ -567,12 +567,13 @@ static long prepare_timeout(const struct timespec __user *u_arg)
static void remove_notification(struct mqueue_inode_info *info)
{
- if (info->notify_owner != 0 &&
+ if (info->notify_owner != NULL &&
info->notify.sigev_notify == SIGEV_THREAD) {
set_cookie(info->notify_cookie, NOTIFY_REMOVED);
netlink_sendskb(info->notify_sock, info->notify_cookie, 0);
}
- info->notify_owner = 0;
+ put_pid(info->notify_owner);
+ info->notify_owner = NULL;
}
static int mq_attr_ok(struct mq_attr *attr)
@@ -1063,11 +1064,11 @@ retry:
ret = 0;
spin_lock(&info->lock);
if (u_notification == NULL) {
- if (info->notify_owner == current->tgid) {
+ if (info->notify_owner == task_tgid(current)) {
remove_notification(info);
inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
- } else if (info->notify_owner != 0) {
+ } else if (info->notify_owner != NULL) {
ret = -EBUSY;
} else {
switch (notification.sigev_notify) {
@@ -1087,7 +1088,8 @@ retry:
info->notify.sigev_notify = SIGEV_SIGNAL;
break;
}
- info->notify_owner = current->tgid;
+
+ info->notify_owner = get_pid(task_tgid(current));
inode->i_atime = inode->i_ctime = CURRENT_TIME;
}
spin_unlock(&info->lock);
@@ -1275,10 +1277,7 @@ out_filesystem:
out_sysctl:
if (mq_sysctl_table)
unregister_sysctl_table(mq_sysctl_table);
- if (kmem_cache_destroy(mqueue_inode_cachep)) {
- printk(KERN_INFO
- "mqueue_inode_cache: not all structures were freed\n");
- }
+ kmem_cache_destroy(mqueue_inode_cachep);
return error;
}
diff --git a/ipc/msg.c b/ipc/msg.c
index 2b4fccf8ea55..5b213d952545 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -16,6 +16,10 @@
*
* support for audit of ipc object properties and permission changes
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
+ *
+ * namespaces support
+ * OpenVZ, SWsoft Inc.
+ * Pavel Emelianov <xemul@openvz.org>
*/
#include <linux/capability.h>
@@ -31,16 +35,12 @@
#include <linux/audit.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
+#include <linux/nsproxy.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include "util.h"
-/* sysctl: */
-int msg_ctlmax = MSGMAX;
-int msg_ctlmnb = MSGMNB;
-int msg_ctlmni = MSGMNI;
-
/*
* one msg_receiver structure for each sleeping receiver:
*/
@@ -69,30 +69,75 @@ struct msg_sender {
static atomic_t msg_bytes = ATOMIC_INIT(0);
static atomic_t msg_hdrs = ATOMIC_INIT(0);
-static struct ipc_ids msg_ids;
+static struct ipc_ids init_msg_ids;
-#define msg_lock(id) ((struct msg_queue *)ipc_lock(&msg_ids, id))
-#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
-#define msg_rmid(id) ((struct msg_queue *)ipc_rmid(&msg_ids, id))
-#define msg_checkid(msq, msgid) ipc_checkid(&msg_ids, &msq->q_perm, msgid)
-#define msg_buildid(id, seq) ipc_buildid(&msg_ids, id, seq)
+#define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS]))
-static void freeque(struct msg_queue *msq, int id);
-static int newque(key_t key, int msgflg);
+#define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id))
+#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
+#define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id))
+#define msg_checkid(ns, msq, msgid) \
+ ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid)
+#define msg_buildid(ns, id, seq) \
+ ipc_buildid(&msg_ids(ns), id, seq)
+
+static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id);
+static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
#endif
+static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
+{
+ ns->ids[IPC_MSG_IDS] = ids;
+ ns->msg_ctlmax = MSGMAX;
+ ns->msg_ctlmnb = MSGMNB;
+ ns->msg_ctlmni = MSGMNI;
+ ipc_init_ids(ids, ns->msg_ctlmni);
+}
+
+#ifdef CONFIG_IPC_NS
+int msg_init_ns(struct ipc_namespace *ns)
+{
+ struct ipc_ids *ids;
+
+ ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
+ if (ids == NULL)
+ return -ENOMEM;
+
+ __msg_init_ns(ns, ids);
+ return 0;
+}
+
+void msg_exit_ns(struct ipc_namespace *ns)
+{
+ int i;
+ struct msg_queue *msq;
+
+ mutex_lock(&msg_ids(ns).mutex);
+ for (i = 0; i <= msg_ids(ns).max_id; i++) {
+ msq = msg_lock(ns, i);
+ if (msq == NULL)
+ continue;
+
+ freeque(ns, msq, i);
+ }
+ mutex_unlock(&msg_ids(ns).mutex);
+
+ kfree(ns->ids[IPC_MSG_IDS]);
+ ns->ids[IPC_MSG_IDS] = NULL;
+}
+#endif
+
void __init msg_init(void)
{
- ipc_init_ids(&msg_ids, msg_ctlmni);
+ __msg_init_ns(&init_ipc_ns, &init_msg_ids);
ipc_init_proc_interface("sysvipc/msg",
" key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
- &msg_ids,
- sysvipc_msg_proc_show);
+ IPC_MSG_IDS, sysvipc_msg_proc_show);
}
-static int newque(key_t key, int msgflg)
+static int newque (struct ipc_namespace *ns, key_t key, int msgflg)
{
struct msg_queue *msq;
int id, retval;
@@ -111,18 +156,18 @@ static int newque(key_t key, int msgflg)
return retval;
}
- id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
+ id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
if (id == -1) {
security_msg_queue_free(msq);
ipc_rcu_putref(msq);
return -ENOSPC;
}
- msq->q_id = msg_buildid(id, msq->q_perm.seq);
+ msq->q_id = msg_buildid(ns, id, msq->q_perm.seq);
msq->q_stime = msq->q_rtime = 0;
msq->q_ctime = get_seconds();
msq->q_cbytes = msq->q_qnum = 0;
- msq->q_qbytes = msg_ctlmnb;
+ msq->q_qbytes = ns->msg_ctlmnb;
msq->q_lspid = msq->q_lrpid = 0;
INIT_LIST_HEAD(&msq->q_messages);
INIT_LIST_HEAD(&msq->q_receivers);
@@ -186,13 +231,13 @@ static void expunge_all(struct msg_queue *msq, int res)
* msg_ids.mutex and the spinlock for this message queue is hold
* before freeque() is called. msg_ids.mutex remains locked on exit.
*/
-static void freeque(struct msg_queue *msq, int id)
+static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id)
{
struct list_head *tmp;
expunge_all(msq, -EIDRM);
ss_wakeup(&msq->q_senders, 1);
- msq = msg_rmid(id);
+ msq = msg_rmid(ns, id);
msg_unlock(msq);
tmp = msq->q_messages.next;
@@ -212,24 +257,27 @@ asmlinkage long sys_msgget(key_t key, int msgflg)
{
struct msg_queue *msq;
int id, ret = -EPERM;
+ struct ipc_namespace *ns;
+
+ ns = current->nsproxy->ipc_ns;
- mutex_lock(&msg_ids.mutex);
+ mutex_lock(&msg_ids(ns).mutex);
if (key == IPC_PRIVATE)
- ret = newque(key, msgflg);
- else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
+ ret = newque(ns, key, msgflg);
+ else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */
if (!(msgflg & IPC_CREAT))
ret = -ENOENT;
else
- ret = newque(key, msgflg);
+ ret = newque(ns, key, msgflg);
} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
ret = -EEXIST;
} else {
- msq = msg_lock(id);
+ msq = msg_lock(ns, id);
BUG_ON(msq == NULL);
if (ipcperms(&msq->q_perm, msgflg))
ret = -EACCES;
else {
- int qid = msg_buildid(id, msq->q_perm.seq);
+ int qid = msg_buildid(ns, id, msq->q_perm.seq);
ret = security_msg_queue_associate(msq, msgflg);
if (!ret)
@@ -237,7 +285,7 @@ asmlinkage long sys_msgget(key_t key, int msgflg)
}
msg_unlock(msq);
}
- mutex_unlock(&msg_ids.mutex);
+ mutex_unlock(&msg_ids(ns).mutex);
return ret;
}
@@ -341,11 +389,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
struct msq_setbuf setbuf;
struct msg_queue *msq;
int err, version;
+ struct ipc_namespace *ns;
if (msqid < 0 || cmd < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
+ ns = current->nsproxy->ipc_ns;
switch (cmd) {
case IPC_INFO:
@@ -366,14 +416,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
return err;
memset(&msginfo, 0, sizeof(msginfo));
- msginfo.msgmni = msg_ctlmni;
- msginfo.msgmax = msg_ctlmax;
- msginfo.msgmnb = msg_ctlmnb;
+ msginfo.msgmni = ns->msg_ctlmni;
+ msginfo.msgmax = ns->msg_ctlmax;
+ msginfo.msgmnb = ns->msg_ctlmnb;
msginfo.msgssz = MSGSSZ;
msginfo.msgseg = MSGSEG;
- mutex_lock(&msg_ids.mutex);
+ mutex_lock(&msg_ids(ns).mutex);
if (cmd == MSG_INFO) {
- msginfo.msgpool = msg_ids.in_use;
+ msginfo.msgpool = msg_ids(ns).in_use;
msginfo.msgmap = atomic_read(&msg_hdrs);
msginfo.msgtql = atomic_read(&msg_bytes);
} else {
@@ -381,8 +431,8 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
msginfo.msgpool = MSGPOOL;
msginfo.msgtql = MSGTQL;
}
- max_id = msg_ids.max_id;
- mutex_unlock(&msg_ids.mutex);
+ max_id = msg_ids(ns).max_id;
+ mutex_unlock(&msg_ids(ns).mutex);
if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
return -EFAULT;
return (max_id < 0) ? 0 : max_id;
@@ -395,20 +445,20 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
if (!buf)
return -EFAULT;
- if (cmd == MSG_STAT && msqid >= msg_ids.entries->size)
+ if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size)
return -EINVAL;
memset(&tbuf, 0, sizeof(tbuf));
- msq = msg_lock(msqid);
+ msq = msg_lock(ns, msqid);
if (msq == NULL)
return -EINVAL;
if (cmd == MSG_STAT) {
- success_return = msg_buildid(msqid, msq->q_perm.seq);
+ success_return = msg_buildid(ns, msqid, msq->q_perm.seq);
} else {
err = -EIDRM;
- if (msg_checkid(msq, msqid))
+ if (msg_checkid(ns, msq, msqid))
goto out_unlock;
success_return = 0;
}
@@ -446,14 +496,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
return -EINVAL;
}
- mutex_lock(&msg_ids.mutex);
- msq = msg_lock(msqid);
+ mutex_lock(&msg_ids(ns).mutex);
+ msq = msg_lock(ns, msqid);
err = -EINVAL;
if (msq == NULL)
goto out_up;
err = -EIDRM;
- if (msg_checkid(msq, msqid))
+ if (msg_checkid(ns, msq, msqid))
goto out_unlock_up;
ipcp = &msq->q_perm;
@@ -481,7 +531,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
case IPC_SET:
{
err = -EPERM;
- if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
+ if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
msq->q_qbytes = setbuf.qbytes;
@@ -503,12 +553,12 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
break;
}
case IPC_RMID:
- freeque(msq, msqid);
+ freeque(ns, msq, msqid);
break;
}
err = 0;
out_up:
- mutex_unlock(&msg_ids.mutex);
+ mutex_unlock(&msg_ids(ns).mutex);
return err;
out_unlock_up:
msg_unlock(msq);
@@ -582,8 +632,11 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
struct msg_msg *msg;
long mtype;
int err;
+ struct ipc_namespace *ns;
+
+ ns = current->nsproxy->ipc_ns;
- if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0)
+ if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
return -EINVAL;
if (get_user(mtype, &msgp->mtype))
return -EFAULT;
@@ -597,13 +650,13 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
msg->m_type = mtype;
msg->m_ts = msgsz;
- msq = msg_lock(msqid);
+ msq = msg_lock(ns, msqid);
err = -EINVAL;
if (msq == NULL)
goto out_free;
err= -EIDRM;
- if (msg_checkid(msq, msqid))
+ if (msg_checkid(ns, msq, msqid))
goto out_unlock_free;
for (;;) {
@@ -694,17 +747,19 @@ asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
struct msg_queue *msq;
struct msg_msg *msg;
int mode;
+ struct ipc_namespace *ns;
if (msqid < 0 || (long) msgsz < 0)
return -EINVAL;
mode = convert_mode(&msgtyp, msgflg);
+ ns = current->nsproxy->ipc_ns;
- msq = msg_lock(msqid);
+ msq = msg_lock(ns, msqid);
if (msq == NULL)
return -EINVAL;
msg = ERR_PTR(-EIDRM);
- if (msg_checkid(msq, msqid))
+ if (msg_checkid(ns, msq, msqid))
goto out_unlock;
for (;;) {
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index 66cfb87646eb..0992616eeed6 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -1,5 +1,5 @@
/*
- * linux/ipc/util.c
+ * linux/ipc/msgutil.c
* Copyright (C) 1999, 2004 Manfred Spraul
*
* This file is released under GNU General Public Licence version 2 or
diff --git a/ipc/sem.c b/ipc/sem.c
index 6013c751156f..0dafcc455f92 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -64,6 +64,10 @@
*
* support for audit of ipc object properties and permission changes
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
+ *
+ * namespaces support
+ * OpenVZ, SWsoft Inc.
+ * Pavel Emelianov <xemul@openvz.org>
*/
#include <linux/slab.h>
@@ -78,22 +82,25 @@
#include <linux/capability.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
+#include <linux/nsproxy.h>
#include <asm/uaccess.h>
#include "util.h"
+#define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS]))
+
+#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id))
+#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
+#define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id))
+#define sem_checkid(ns, sma, semid) \
+ ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid)
+#define sem_buildid(ns, id, seq) \
+ ipc_buildid(&sem_ids(ns), id, seq)
-#define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id))
-#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
-#define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id))
-#define sem_checkid(sma, semid) \
- ipc_checkid(&sem_ids,&sma->sem_perm,semid)
-#define sem_buildid(id, seq) \
- ipc_buildid(&sem_ids, id, seq)
-static struct ipc_ids sem_ids;
+static struct ipc_ids init_sem_ids;
-static int newary (key_t, int, int);
-static void freeary (struct sem_array *sma, int id);
+static int newary(struct ipc_namespace *, key_t, int, int);
+static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id);
#ifdef CONFIG_PROC_FS
static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
#endif
@@ -110,22 +117,61 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
*
*/
-int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI};
-#define sc_semmsl (sem_ctls[0])
-#define sc_semmns (sem_ctls[1])
-#define sc_semopm (sem_ctls[2])
-#define sc_semmni (sem_ctls[3])
+#define sc_semmsl sem_ctls[0]
+#define sc_semmns sem_ctls[1]
+#define sc_semopm sem_ctls[2]
+#define sc_semmni sem_ctls[3]
-static int used_sems;
+static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
+{
+ ns->ids[IPC_SEM_IDS] = ids;
+ ns->sc_semmsl = SEMMSL;
+ ns->sc_semmns = SEMMNS;
+ ns->sc_semopm = SEMOPM;
+ ns->sc_semmni = SEMMNI;
+ ns->used_sems = 0;
+ ipc_init_ids(ids, ns->sc_semmni);
+}
+
+#ifdef CONFIG_IPC_NS
+int sem_init_ns(struct ipc_namespace *ns)
+{
+ struct ipc_ids *ids;
+
+ ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
+ if (ids == NULL)
+ return -ENOMEM;
+
+ __sem_init_ns(ns, ids);
+ return 0;
+}
+
+void sem_exit_ns(struct ipc_namespace *ns)
+{
+ int i;
+ struct sem_array *sma;
+
+ mutex_lock(&sem_ids(ns).mutex);
+ for (i = 0; i <= sem_ids(ns).max_id; i++) {
+ sma = sem_lock(ns, i);
+ if (sma == NULL)
+ continue;
+
+ freeary(ns, sma, i);
+ }
+ mutex_unlock(&sem_ids(ns).mutex);
+
+ kfree(ns->ids[IPC_SEM_IDS]);
+ ns->ids[IPC_SEM_IDS] = NULL;
+}
+#endif
void __init sem_init (void)
{
- used_sems = 0;
- ipc_init_ids(&sem_ids,sc_semmni);
+ __sem_init_ns(&init_ipc_ns, &init_sem_ids);
ipc_init_proc_interface("sysvipc/sem",
" key semid perms nsems uid gid cuid cgid otime ctime\n",
- &sem_ids,
- sysvipc_sem_proc_show);
+ IPC_SEM_IDS, sysvipc_sem_proc_show);
}
/*
@@ -162,7 +208,7 @@ void __init sem_init (void)
*/
#define IN_WAKEUP 1
-static int newary (key_t key, int nsems, int semflg)
+static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg)
{
int id;
int retval;
@@ -171,7 +217,7 @@ static int newary (key_t key, int nsems, int semflg)
if (!nsems)
return -EINVAL;
- if (used_sems + nsems > sc_semmns)
+ if (ns->used_sems + nsems > ns->sc_semmns)
return -ENOSPC;
size = sizeof (*sma) + nsems * sizeof (struct sem);
@@ -191,15 +237,15 @@ static int newary (key_t key, int nsems, int semflg)
return retval;
}
- id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
+ id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
if(id == -1) {
security_sem_free(sma);
ipc_rcu_putref(sma);
return -ENOSPC;
}
- used_sems += nsems;
+ ns->used_sems += nsems;
- sma->sem_id = sem_buildid(id, sma->sem_perm.seq);
+ sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq);
sma->sem_base = (struct sem *) &sma[1];
/* sma->sem_pending = NULL; */
sma->sem_pending_last = &sma->sem_pending;
@@ -215,29 +261,32 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg)
{
int id, err = -EINVAL;
struct sem_array *sma;
+ struct ipc_namespace *ns;
- if (nsems < 0 || nsems > sc_semmsl)
+ ns = current->nsproxy->ipc_ns;
+
+ if (nsems < 0 || nsems > ns->sc_semmsl)
return -EINVAL;
- mutex_lock(&sem_ids.mutex);
+ mutex_lock(&sem_ids(ns).mutex);
if (key == IPC_PRIVATE) {
- err = newary(key, nsems, semflg);
- } else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */
+ err = newary(ns, key, nsems, semflg);
+ } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */
if (!(semflg & IPC_CREAT))
err = -ENOENT;
else
- err = newary(key, nsems, semflg);
+ err = newary(ns, key, nsems, semflg);
} else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
err = -EEXIST;
} else {
- sma = sem_lock(id);
+ sma = sem_lock(ns, id);
BUG_ON(sma==NULL);
if (nsems > sma->sem_nsems)
err = -EINVAL;
else if (ipcperms(&sma->sem_perm, semflg))
err = -EACCES;
else {
- int semid = sem_buildid(id, sma->sem_perm.seq);
+ int semid = sem_buildid(ns, id, sma->sem_perm.seq);
err = security_sem_associate(sma, semflg);
if (!err)
err = semid;
@@ -245,7 +294,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg)
sem_unlock(sma);
}
- mutex_unlock(&sem_ids.mutex);
+ mutex_unlock(&sem_ids(ns).mutex);
return err;
}
@@ -444,7 +493,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
* the spinlock for this semaphore set hold. sem_ids.mutex remains locked
* on exit.
*/
-static void freeary (struct sem_array *sma, int id)
+static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id)
{
struct sem_undo *un;
struct sem_queue *q;
@@ -472,10 +521,10 @@ static void freeary (struct sem_array *sma, int id)
}
/* Remove the semaphore set from the ID array*/
- sma = sem_rmid(id);
+ sma = sem_rmid(ns, id);
sem_unlock(sma);
- used_sems -= sma->sem_nsems;
+ ns->used_sems -= sma->sem_nsems;
size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
security_sem_free(sma);
ipc_rcu_putref(sma);
@@ -503,7 +552,8 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,
}
}
-static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
+ int cmd, int version, union semun arg)
{
int err = -EINVAL;
struct sem_array *sma;
@@ -520,24 +570,24 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu
return err;
memset(&seminfo,0,sizeof(seminfo));
- seminfo.semmni = sc_semmni;
- seminfo.semmns = sc_semmns;
- seminfo.semmsl = sc_semmsl;
- seminfo.semopm = sc_semopm;
+ seminfo.semmni = ns->sc_semmni;
+ seminfo.semmns = ns->sc_semmns;
+ seminfo.semmsl = ns->sc_semmsl;
+ seminfo.semopm = ns->sc_semopm;
seminfo.semvmx = SEMVMX;
seminfo.semmnu = SEMMNU;
seminfo.semmap = SEMMAP;
seminfo.semume = SEMUME;
- mutex_lock(&sem_ids.mutex);
+ mutex_lock(&sem_ids(ns).mutex);
if (cmd == SEM_INFO) {
- seminfo.semusz = sem_ids.in_use;
- seminfo.semaem = used_sems;
+ seminfo.semusz = sem_ids(ns).in_use;
+ seminfo.semaem = ns->used_sems;
} else {
seminfo.semusz = SEMUSZ;
seminfo.semaem = SEMAEM;
}
- max_id = sem_ids.max_id;
- mutex_unlock(&sem_ids.mutex);
+ max_id = sem_ids(ns).max_id;
+ mutex_unlock(&sem_ids(ns).mutex);
if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
return -EFAULT;
return (max_id < 0) ? 0: max_id;
@@ -547,12 +597,12 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu
struct semid64_ds tbuf;
int id;
- if(semid >= sem_ids.entries->size)
+ if(semid >= sem_ids(ns).entries->size)
return -EINVAL;
memset(&tbuf,0,sizeof(tbuf));
- sma = sem_lock(semid);
+ sma = sem_lock(ns, semid);
if(sma == NULL)
return -EINVAL;
@@ -564,7 +614,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu
if (err)
goto out_unlock;
- id = sem_buildid(semid, sma->sem_perm.seq);
+ id = sem_buildid(ns, semid, sma->sem_perm.seq);
kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
tbuf.sem_otime = sma->sem_otime;
@@ -584,7 +634,8 @@ out_unlock:
return err;
}
-static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
+ int cmd, int version, union semun arg)
{
struct sem_array *sma;
struct sem* curr;
@@ -593,14 +644,14 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun
ushort* sem_io = fast_sem_io;
int nsems;
- sma = sem_lock(semid);
+ sma = sem_lock(ns, semid);
if(sma==NULL)
return -EINVAL;
nsems = sma->sem_nsems;
err=-EIDRM;
- if (sem_checkid(sma,semid))
+ if (sem_checkid(ns,sma,semid))
goto out_unlock;
err = -EACCES;
@@ -802,7 +853,8 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __
}
}
-static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
+static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
+ int cmd, int version, union semun arg)
{
struct sem_array *sma;
int err;
@@ -813,11 +865,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT;
}
- sma = sem_lock(semid);
+ sma = sem_lock(ns, semid);
if(sma==NULL)
return -EINVAL;
- if (sem_checkid(sma,semid)) {
+ if (sem_checkid(ns,sma,semid)) {
err=-EIDRM;
goto out_unlock;
}
@@ -844,7 +896,7 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
switch(cmd){
case IPC_RMID:
- freeary(sma, semid);
+ freeary(ns, sma, semid);
err = 0;
break;
case IPC_SET:
@@ -872,17 +924,19 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
{
int err = -EINVAL;
int version;
+ struct ipc_namespace *ns;
if (semid < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
+ ns = current->nsproxy->ipc_ns;
switch(cmd) {
case IPC_INFO:
case SEM_INFO:
case SEM_STAT:
- err = semctl_nolock(semid,semnum,cmd,version,arg);
+ err = semctl_nolock(ns,semid,semnum,cmd,version,arg);
return err;
case GETALL:
case GETVAL:
@@ -892,13 +946,13 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
case IPC_STAT:
case SETVAL:
case SETALL:
- err = semctl_main(semid,semnum,cmd,version,arg);
+ err = semctl_main(ns,semid,semnum,cmd,version,arg);
return err;
case IPC_RMID:
case IPC_SET:
- mutex_lock(&sem_ids.mutex);
- err = semctl_down(semid,semnum,cmd,version,arg);
- mutex_unlock(&sem_ids.mutex);
+ mutex_lock(&sem_ids(ns).mutex);
+ err = semctl_down(ns,semid,semnum,cmd,version,arg);
+ mutex_unlock(&sem_ids(ns).mutex);
return err;
default:
return -EINVAL;
@@ -949,15 +1003,12 @@ static inline void unlock_semundo(void)
static inline int get_undo_list(struct sem_undo_list **undo_listp)
{
struct sem_undo_list *undo_list;
- int size;
undo_list = current->sysvsem.undo_list;
if (!undo_list) {
- size = sizeof(struct sem_undo_list);
- undo_list = (struct sem_undo_list *) kmalloc(size, GFP_KERNEL);
+ undo_list = kzalloc(sizeof(*undo_list), GFP_KERNEL);
if (undo_list == NULL)
return -ENOMEM;
- memset(undo_list, 0, size);
spin_lock_init(&undo_list->lock);
atomic_set(&undo_list->refcnt, 1);
current->sysvsem.undo_list = undo_list;
@@ -986,7 +1037,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
return un;
}
-static struct sem_undo *find_undo(int semid)
+static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
{
struct sem_array *sma;
struct sem_undo_list *ulp;
@@ -1005,12 +1056,12 @@ static struct sem_undo *find_undo(int semid)
goto out;
/* no undo structure around - allocate one. */
- sma = sem_lock(semid);
+ sma = sem_lock(ns, semid);
un = ERR_PTR(-EINVAL);
if(sma==NULL)
goto out;
un = ERR_PTR(-EIDRM);
- if (sem_checkid(sma,semid)) {
+ if (sem_checkid(ns,sma,semid)) {
sem_unlock(sma);
goto out;
}
@@ -1070,10 +1121,13 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
int undos = 0, alter = 0, max;
struct sem_queue queue;
unsigned long jiffies_left = 0;
+ struct ipc_namespace *ns;
+
+ ns = current->nsproxy->ipc_ns;
if (nsops < 1 || semid < 0)
return -EINVAL;
- if (nsops > sc_semopm)
+ if (nsops > ns->sc_semopm)
return -E2BIG;
if(nsops > SEMOPM_FAST) {
sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
@@ -1109,7 +1163,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
retry_undos:
if (undos) {
- un = find_undo(semid);
+ un = find_undo(ns, semid);
if (IS_ERR(un)) {
error = PTR_ERR(un);
goto out_free;
@@ -1117,12 +1171,12 @@ retry_undos:
} else
un = NULL;
- sma = sem_lock(semid);
+ sma = sem_lock(ns, semid);
error=-EINVAL;
if(sma==NULL)
goto out_free;
error = -EIDRM;
- if (sem_checkid(sma,semid))
+ if (sem_checkid(ns,sma,semid))
goto out_unlock_free;
/*
* semid identifies are not unique - find_undo may have
@@ -1190,7 +1244,7 @@ retry_undos:
goto out_free;
}
- sma = sem_lock(semid);
+ sma = sem_lock(ns, semid);
if(sma==NULL) {
BUG_ON(queue.prev != NULL);
error = -EIDRM;
@@ -1267,6 +1321,7 @@ void exit_sem(struct task_struct *tsk)
{
struct sem_undo_list *undo_list;
struct sem_undo *u, **up;
+ struct ipc_namespace *ns;
undo_list = tsk->sysvsem.undo_list;
if (!undo_list)
@@ -1275,6 +1330,7 @@ void exit_sem(struct task_struct *tsk)
if (!atomic_dec_and_test(&undo_list->refcnt))
return;
+ ns = tsk->nsproxy->ipc_ns;
/* There's no need to hold the semundo list lock, as current
* is the last task exiting for this undo list.
*/
@@ -1288,14 +1344,14 @@ void exit_sem(struct task_struct *tsk)
if(semid == -1)
continue;
- sma = sem_lock(semid);
+ sma = sem_lock(ns, semid);
if (sma == NULL)
continue;
if (u->semid == -1)
goto next_entry;
- BUG_ON(sem_checkid(sma,u->semid));
+ BUG_ON(sem_checkid(ns,sma,u->semid));
/* remove u from the sma->undo list */
for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
diff --git a/ipc/shm.c b/ipc/shm.c
index 940b0c9b13aa..bfbd317ec11c 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -15,6 +15,10 @@
*
* support for audit of ipc object properties and permission changes
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
+ *
+ * namespaces support
+ * OpenVZ, SWsoft Inc.
+ * Pavel Emelianov <xemul@openvz.org>
*/
#include <linux/slab.h>
@@ -32,6 +36,7 @@
#include <linux/ptrace.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
+#include <linux/nsproxy.h>
#include <asm/uaccess.h>
@@ -40,59 +45,115 @@
static struct file_operations shm_file_operations;
static struct vm_operations_struct shm_vm_ops;
-static struct ipc_ids shm_ids;
+static struct ipc_ids init_shm_ids;
+
+#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS]))
-#define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id))
-#define shm_unlock(shp) ipc_unlock(&(shp)->shm_perm)
-#define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id))
-#define shm_buildid(id, seq) \
- ipc_buildid(&shm_ids, id, seq)
+#define shm_lock(ns, id) \
+ ((struct shmid_kernel*)ipc_lock(&shm_ids(ns),id))
+#define shm_unlock(shp) \
+ ipc_unlock(&(shp)->shm_perm)
+#define shm_get(ns, id) \
+ ((struct shmid_kernel*)ipc_get(&shm_ids(ns),id))
+#define shm_buildid(ns, id, seq) \
+ ipc_buildid(&shm_ids(ns), id, seq)
-static int newseg (key_t key, int shmflg, size_t size);
+static int newseg (struct ipc_namespace *ns, key_t key,
+ int shmflg, size_t size);
static void shm_open (struct vm_area_struct *shmd);
static void shm_close (struct vm_area_struct *shmd);
+static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
#ifdef CONFIG_PROC_FS
static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
#endif
-size_t shm_ctlmax = SHMMAX;
-size_t shm_ctlall = SHMALL;
-int shm_ctlmni = SHMMNI;
+static void __ipc_init __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
+{
+ ns->ids[IPC_SHM_IDS] = ids;
+ ns->shm_ctlmax = SHMMAX;
+ ns->shm_ctlall = SHMALL;
+ ns->shm_ctlmni = SHMMNI;
+ ns->shm_tot = 0;
+ ipc_init_ids(ids, 1);
+}
+
+static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
+{
+ if (shp->shm_nattch){
+ shp->shm_perm.mode |= SHM_DEST;
+ /* Do not find it any more */
+ shp->shm_perm.key = IPC_PRIVATE;
+ shm_unlock(shp);
+ } else
+ shm_destroy(ns, shp);
+}
+
+#ifdef CONFIG_IPC_NS
+int shm_init_ns(struct ipc_namespace *ns)
+{
+ struct ipc_ids *ids;
+
+ ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
+ if (ids == NULL)
+ return -ENOMEM;
-static int shm_tot; /* total number of shared memory pages */
+ __shm_init_ns(ns, ids);
+ return 0;
+}
+
+void shm_exit_ns(struct ipc_namespace *ns)
+{
+ int i;
+ struct shmid_kernel *shp;
+
+ mutex_lock(&shm_ids(ns).mutex);
+ for (i = 0; i <= shm_ids(ns).max_id; i++) {
+ shp = shm_lock(ns, i);
+ if (shp == NULL)
+ continue;
+
+ do_shm_rmid(ns, shp);
+ }
+ mutex_unlock(&shm_ids(ns).mutex);
+
+ kfree(ns->ids[IPC_SHM_IDS]);
+ ns->ids[IPC_SHM_IDS] = NULL;
+}
+#endif
void __init shm_init (void)
{
- ipc_init_ids(&shm_ids, 1);
+ __shm_init_ns(&init_ipc_ns, &init_shm_ids);
ipc_init_proc_interface("sysvipc/shm",
" key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n",
- &shm_ids,
- sysvipc_shm_proc_show);
+ IPC_SHM_IDS, sysvipc_shm_proc_show);
}
-static inline int shm_checkid(struct shmid_kernel *s, int id)
+static inline int shm_checkid(struct ipc_namespace *ns,
+ struct shmid_kernel *s, int id)
{
- if (ipc_checkid(&shm_ids,&s->shm_perm,id))
+ if (ipc_checkid(&shm_ids(ns), &s->shm_perm, id))
return -EIDRM;
return 0;
}
-static inline struct shmid_kernel *shm_rmid(int id)
+static inline struct shmid_kernel *shm_rmid(struct ipc_namespace *ns, int id)
{
- return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
+ return (struct shmid_kernel *)ipc_rmid(&shm_ids(ns), id);
}
-static inline int shm_addid(struct shmid_kernel *shp)
+static inline int shm_addid(struct ipc_namespace *ns, struct shmid_kernel *shp)
{
- return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
+ return ipc_addid(&shm_ids(ns), &shp->shm_perm, ns->shm_ctlmni);
}
-static inline void shm_inc (int id) {
+static inline void shm_inc(struct ipc_namespace *ns, int id)
+{
struct shmid_kernel *shp;
- shp = shm_lock(id);
+ shp = shm_lock(ns, id);
BUG_ON(!shp);
shp->shm_atim = get_seconds();
shp->shm_lprid = current->tgid;
@@ -100,10 +161,13 @@ static inline void shm_inc (int id) {
shm_unlock(shp);
}
+#define shm_file_ns(file) (*((struct ipc_namespace **)&(file)->private_data))
+
/* This is called by fork, once for every shm attach. */
-static void shm_open (struct vm_area_struct *shmd)
+static void shm_open(struct vm_area_struct *shmd)
{
- shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino);
+ shm_inc(shm_file_ns(shmd->vm_file),
+ shmd->vm_file->f_dentry->d_inode->i_ino);
}
/*
@@ -114,10 +178,10 @@ static void shm_open (struct vm_area_struct *shmd)
* It has to be called with shp and shm_ids.mutex locked,
* but returns with shp unlocked and freed.
*/
-static void shm_destroy (struct shmid_kernel *shp)
+static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
{
- shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
- shm_rmid (shp->id);
+ ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ shm_rmid(ns, shp->id);
shm_unlock(shp);
if (!is_file_hugepages(shp->shm_file))
shmem_lock(shp->shm_file, 0, shp->mlock_user);
@@ -140,20 +204,23 @@ static void shm_close (struct vm_area_struct *shmd)
struct file * file = shmd->vm_file;
int id = file->f_dentry->d_inode->i_ino;
struct shmid_kernel *shp;
+ struct ipc_namespace *ns;
- mutex_lock(&shm_ids.mutex);
+ ns = shm_file_ns(file);
+
+ mutex_lock(&shm_ids(ns).mutex);
/* remove from the list of attaches of the shm segment */
- shp = shm_lock(id);
+ shp = shm_lock(ns, id);
BUG_ON(!shp);
shp->shm_lprid = current->tgid;
shp->shm_dtim = get_seconds();
shp->shm_nattch--;
if(shp->shm_nattch == 0 &&
shp->shm_perm.mode & SHM_DEST)
- shm_destroy (shp);
+ shm_destroy(ns, shp);
else
shm_unlock(shp);
- mutex_unlock(&shm_ids.mutex);
+ mutex_unlock(&shm_ids(ns).mutex);
}
static int shm_mmap(struct file * file, struct vm_area_struct * vma)
@@ -165,14 +232,25 @@ static int shm_mmap(struct file * file, struct vm_area_struct * vma)
vma->vm_ops = &shm_vm_ops;
if (!(vma->vm_flags & VM_WRITE))
vma->vm_flags &= ~VM_MAYWRITE;
- shm_inc(file->f_dentry->d_inode->i_ino);
+ shm_inc(shm_file_ns(file), file->f_dentry->d_inode->i_ino);
}
return ret;
}
+static int shm_release(struct inode *ino, struct file *file)
+{
+ struct ipc_namespace *ns;
+
+ ns = shm_file_ns(file);
+ put_ipc_ns(ns);
+ shm_file_ns(file) = NULL;
+ return 0;
+}
+
static struct file_operations shm_file_operations = {
- .mmap = shm_mmap,
+ .mmap = shm_mmap,
+ .release = shm_release,
#ifndef CONFIG_MMU
.get_unmapped_area = shmem_get_unmapped_area,
#endif
@@ -188,7 +266,7 @@ static struct vm_operations_struct shm_vm_ops = {
#endif
};
-static int newseg (key_t key, int shmflg, size_t size)
+static int newseg (struct ipc_namespace *ns, key_t key, int shmflg, size_t size)
{
int error;
struct shmid_kernel *shp;
@@ -197,10 +275,10 @@ static int newseg (key_t key, int shmflg, size_t size)
char name[13];
int id;
- if (size < SHMMIN || size > shm_ctlmax)
+ if (size < SHMMIN || size > ns->shm_ctlmax)
return -EINVAL;
- if (shm_tot + numpages >= shm_ctlall)
+ if (ns->shm_tot + numpages >= ns->shm_ctlall)
return -ENOSPC;
shp = ipc_rcu_alloc(sizeof(*shp));
@@ -239,7 +317,7 @@ static int newseg (key_t key, int shmflg, size_t size)
goto no_file;
error = -ENOSPC;
- id = shm_addid(shp);
+ id = shm_addid(ns, shp);
if(id == -1)
goto no_id;
@@ -249,15 +327,17 @@ static int newseg (key_t key, int shmflg, size_t size)
shp->shm_ctim = get_seconds();
shp->shm_segsz = size;
shp->shm_nattch = 0;
- shp->id = shm_buildid(id,shp->shm_perm.seq);
+ shp->id = shm_buildid(ns, id, shp->shm_perm.seq);
shp->shm_file = file;
file->f_dentry->d_inode->i_ino = shp->id;
+ shm_file_ns(file) = get_ipc_ns(ns);
+
/* Hugetlb ops would have already been assigned. */
if (!(shmflg & SHM_HUGETLB))
file->f_op = &shm_file_operations;
- shm_tot += numpages;
+ ns->shm_tot += numpages;
shm_unlock(shp);
return shp->id;
@@ -273,33 +353,36 @@ asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
{
struct shmid_kernel *shp;
int err, id = 0;
+ struct ipc_namespace *ns;
+
+ ns = current->nsproxy->ipc_ns;
- mutex_lock(&shm_ids.mutex);
+ mutex_lock(&shm_ids(ns).mutex);
if (key == IPC_PRIVATE) {
- err = newseg(key, shmflg, size);
- } else if ((id = ipc_findkey(&shm_ids, key)) == -1) {
+ err = newseg(ns, key, shmflg, size);
+ } else if ((id = ipc_findkey(&shm_ids(ns), key)) == -1) {
if (!(shmflg & IPC_CREAT))
err = -ENOENT;
else
- err = newseg(key, shmflg, size);
+ err = newseg(ns, key, shmflg, size);
} else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
err = -EEXIST;
} else {
- shp = shm_lock(id);
+ shp = shm_lock(ns, id);
BUG_ON(shp==NULL);
if (shp->shm_segsz < size)
err = -EINVAL;
else if (ipcperms(&shp->shm_perm, shmflg))
err = -EACCES;
else {
- int shmid = shm_buildid(id, shp->shm_perm.seq);
+ int shmid = shm_buildid(ns, id, shp->shm_perm.seq);
err = security_shm_associate(shp, shmflg);
if (!err)
err = shmid;
}
shm_unlock(shp);
}
- mutex_unlock(&shm_ids.mutex);
+ mutex_unlock(&shm_ids(ns).mutex);
return err;
}
@@ -395,18 +478,19 @@ static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminf
}
}
-static void shm_get_stat(unsigned long *rss, unsigned long *swp)
+static void shm_get_stat(struct ipc_namespace *ns, unsigned long *rss,
+ unsigned long *swp)
{
int i;
*rss = 0;
*swp = 0;
- for (i = 0; i <= shm_ids.max_id; i++) {
+ for (i = 0; i <= shm_ids(ns).max_id; i++) {
struct shmid_kernel *shp;
struct inode *inode;
- shp = shm_get(i);
+ shp = shm_get(ns, i);
if(!shp)
continue;
@@ -430,6 +514,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
struct shm_setbuf setbuf;
struct shmid_kernel *shp;
int err, version;
+ struct ipc_namespace *ns;
if (cmd < 0 || shmid < 0) {
err = -EINVAL;
@@ -437,6 +522,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
}
version = ipc_parse_version(&cmd);
+ ns = current->nsproxy->ipc_ns;
switch (cmd) { /* replace with proc interface ? */
case IPC_INFO:
@@ -448,15 +534,15 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
return err;
memset(&shminfo,0,sizeof(shminfo));
- shminfo.shmmni = shminfo.shmseg = shm_ctlmni;
- shminfo.shmmax = shm_ctlmax;
- shminfo.shmall = shm_ctlall;
+ shminfo.shmmni = shminfo.shmseg = ns->shm_ctlmni;
+ shminfo.shmmax = ns->shm_ctlmax;
+ shminfo.shmall = ns->shm_ctlall;
shminfo.shmmin = SHMMIN;
if(copy_shminfo_to_user (buf, &shminfo, version))
return -EFAULT;
/* reading a integer is always atomic */
- err= shm_ids.max_id;
+ err= shm_ids(ns).max_id;
if(err<0)
err = 0;
goto out;
@@ -470,14 +556,14 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
return err;
memset(&shm_info,0,sizeof(shm_info));
- mutex_lock(&shm_ids.mutex);
- shm_info.used_ids = shm_ids.in_use;
- shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp);
- shm_info.shm_tot = shm_tot;
+ mutex_lock(&shm_ids(ns).mutex);
+ shm_info.used_ids = shm_ids(ns).in_use;
+ shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
+ shm_info.shm_tot = ns->shm_tot;
shm_info.swap_attempts = 0;
shm_info.swap_successes = 0;
- err = shm_ids.max_id;
- mutex_unlock(&shm_ids.mutex);
+ err = shm_ids(ns).max_id;
+ mutex_unlock(&shm_ids(ns).mutex);
if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
err = -EFAULT;
goto out;
@@ -492,17 +578,17 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
struct shmid64_ds tbuf;
int result;
memset(&tbuf, 0, sizeof(tbuf));
- shp = shm_lock(shmid);
+ shp = shm_lock(ns, shmid);
if(shp==NULL) {
err = -EINVAL;
goto out;
} else if(cmd==SHM_STAT) {
err = -EINVAL;
- if (shmid > shm_ids.max_id)
+ if (shmid > shm_ids(ns).max_id)
goto out_unlock;
- result = shm_buildid(shmid, shp->shm_perm.seq);
+ result = shm_buildid(ns, shmid, shp->shm_perm.seq);
} else {
- err = shm_checkid(shp,shmid);
+ err = shm_checkid(ns, shp,shmid);
if(err)
goto out_unlock;
result = 0;
@@ -534,12 +620,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
case SHM_LOCK:
case SHM_UNLOCK:
{
- shp = shm_lock(shmid);
+ shp = shm_lock(ns, shmid);
if(shp==NULL) {
err = -EINVAL;
goto out;
}
- err = shm_checkid(shp,shmid);
+ err = shm_checkid(ns, shp,shmid);
if(err)
goto out_unlock;
@@ -590,12 +676,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
* Instead we set a destroyed flag, and then blow
* the name away when the usage hits zero.
*/
- mutex_lock(&shm_ids.mutex);
- shp = shm_lock(shmid);
+ mutex_lock(&shm_ids(ns).mutex);
+ shp = shm_lock(ns, shmid);
err = -EINVAL;
if (shp == NULL)
goto out_up;
- err = shm_checkid(shp, shmid);
+ err = shm_checkid(ns, shp, shmid);
if(err)
goto out_unlock_up;
@@ -614,14 +700,8 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
if (err)
goto out_unlock_up;
- if (shp->shm_nattch){
- shp->shm_perm.mode |= SHM_DEST;
- /* Do not find it any more */
- shp->shm_perm.key = IPC_PRIVATE;
- shm_unlock(shp);
- } else
- shm_destroy (shp);
- mutex_unlock(&shm_ids.mutex);
+ do_shm_rmid(ns, shp);
+ mutex_unlock(&shm_ids(ns).mutex);
goto out;
}
@@ -631,12 +711,12 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
err = -EFAULT;
goto out;
}
- mutex_lock(&shm_ids.mutex);
- shp = shm_lock(shmid);
+ mutex_lock(&shm_ids(ns).mutex);
+ shp = shm_lock(ns, shmid);
err=-EINVAL;
if(shp==NULL)
goto out_up;
- err = shm_checkid(shp,shmid);
+ err = shm_checkid(ns, shp,shmid);
if(err)
goto out_unlock_up;
err = audit_ipc_obj(&(shp->shm_perm));
@@ -673,7 +753,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
out_unlock_up:
shm_unlock(shp);
out_up:
- mutex_unlock(&shm_ids.mutex);
+ mutex_unlock(&shm_ids(ns).mutex);
goto out;
out_unlock:
shm_unlock(shp);
@@ -699,6 +779,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
unsigned long prot;
int acc_mode;
void *user_addr;
+ struct ipc_namespace *ns;
if (shmid < 0) {
err = -EINVAL;
@@ -737,12 +818,13 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
* We cannot rely on the fs check since SYSV IPC does have an
* additional creator id...
*/
- shp = shm_lock(shmid);
+ ns = current->nsproxy->ipc_ns;
+ shp = shm_lock(ns, shmid);
if(shp == NULL) {
err = -EINVAL;
goto out;
}
- err = shm_checkid(shp,shmid);
+ err = shm_checkid(ns, shp,shmid);
if (err) {
shm_unlock(shp);
goto out;
@@ -783,16 +865,16 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
invalid:
up_write(&current->mm->mmap_sem);
- mutex_lock(&shm_ids.mutex);
- shp = shm_lock(shmid);
+ mutex_lock(&shm_ids(ns).mutex);
+ shp = shm_lock(ns, shmid);
BUG_ON(!shp);
shp->shm_nattch--;
if(shp->shm_nattch == 0 &&
shp->shm_perm.mode & SHM_DEST)
- shm_destroy (shp);
+ shm_destroy(ns, shp);
else
shm_unlock(shp);
- mutex_unlock(&shm_ids.mutex);
+ mutex_unlock(&shm_ids(ns).mutex);
*raddr = (unsigned long) user_addr;
err = 0;
diff --git a/ipc/util.c b/ipc/util.c
index 67b6d178db6e..42479e4eec59 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -12,6 +12,9 @@
* Mingming Cao <cmm@us.ibm.com>
* Mar 2006 - support for audit of ipc object properties
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
+ * Jun 2006 - namespaces ssupport
+ * OpenVZ, SWsoft Inc.
+ * Pavel Emelianov <xemul@openvz.org>
*/
#include <linux/mm.h>
@@ -29,6 +32,7 @@
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/audit.h>
+#include <linux/nsproxy.h>
#include <asm/unistd.h>
@@ -37,10 +41,111 @@
struct ipc_proc_iface {
const char *path;
const char *header;
- struct ipc_ids *ids;
+ int ids;
int (*show)(struct seq_file *, void *);
};
+struct ipc_namespace init_ipc_ns = {
+ .kref = {
+ .refcount = ATOMIC_INIT(2),
+ },
+};
+
+#ifdef CONFIG_IPC_NS
+static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
+{
+ int err;
+ struct ipc_namespace *ns;
+
+ err = -ENOMEM;
+ ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
+ if (ns == NULL)
+ goto err_mem;
+
+ err = sem_init_ns(ns);
+ if (err)
+ goto err_sem;
+ err = msg_init_ns(ns);
+ if (err)
+ goto err_msg;
+ err = shm_init_ns(ns);
+ if (err)
+ goto err_shm;
+
+ kref_init(&ns->kref);
+ return ns;
+
+err_shm:
+ msg_exit_ns(ns);
+err_msg:
+ sem_exit_ns(ns);
+err_sem:
+ kfree(ns);
+err_mem:
+ return ERR_PTR(err);
+}
+
+int unshare_ipcs(unsigned long unshare_flags, struct ipc_namespace **new_ipc)
+{
+ struct ipc_namespace *new;
+
+ if (unshare_flags & CLONE_NEWIPC) {
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ new = clone_ipc_ns(current->nsproxy->ipc_ns);
+ if (IS_ERR(new))
+ return PTR_ERR(new);
+
+ *new_ipc = new;
+ }
+
+ return 0;
+}
+
+int copy_ipcs(unsigned long flags, struct task_struct *tsk)
+{
+ struct ipc_namespace *old_ns = tsk->nsproxy->ipc_ns;
+ struct ipc_namespace *new_ns;
+ int err = 0;
+
+ if (!old_ns)
+ return 0;
+
+ get_ipc_ns(old_ns);
+
+ if (!(flags & CLONE_NEWIPC))
+ return 0;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto out;
+ }
+
+ new_ns = clone_ipc_ns(old_ns);
+ if (!new_ns) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ tsk->nsproxy->ipc_ns = new_ns;
+out:
+ put_ipc_ns(old_ns);
+ return err;
+}
+
+void free_ipc_ns(struct kref *kref)
+{
+ struct ipc_namespace *ns;
+
+ ns = container_of(kref, struct ipc_namespace, kref);
+ sem_exit_ns(ns);
+ msg_exit_ns(ns);
+ shm_exit_ns(ns);
+ kfree(ns);
+}
+#endif
+
/**
* ipc_init - initialise IPC subsystem
*
@@ -67,7 +172,7 @@ __initcall(ipc_init);
* array itself.
*/
-void __init ipc_init_ids(struct ipc_ids* ids, int size)
+void __ipc_init ipc_init_ids(struct ipc_ids* ids, int size)
{
int i;
@@ -110,8 +215,7 @@ static struct file_operations sysvipc_proc_fops;
* @show: show routine.
*/
void __init ipc_init_proc_interface(const char *path, const char *header,
- struct ipc_ids *ids,
- int (*show)(struct seq_file *, void *))
+ int ids, int (*show)(struct seq_file *, void *))
{
struct proc_dir_entry *pde;
struct ipc_proc_iface *iface;
@@ -635,6 +739,9 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
struct ipc_proc_iface *iface = s->private;
struct kern_ipc_perm *ipc = it;
loff_t p;
+ struct ipc_ids *ids;
+
+ ids = current->nsproxy->ipc_ns->ids[iface->ids];
/* If we had an ipc id locked before, unlock it */
if (ipc && ipc != SEQ_START_TOKEN)
@@ -644,8 +751,8 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
* p = *pos - 1 (because id 0 starts at position 1)
* + 1 (because we increment the position by one)
*/
- for (p = *pos; p <= iface->ids->max_id; p++) {
- if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
+ for (p = *pos; p <= ids->max_id; p++) {
+ if ((ipc = ipc_lock(ids, p)) != NULL) {
*pos = p + 1;
return ipc;
}
@@ -664,12 +771,15 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
struct ipc_proc_iface *iface = s->private;
struct kern_ipc_perm *ipc;
loff_t p;
+ struct ipc_ids *ids;
+
+ ids = current->nsproxy->ipc_ns->ids[iface->ids];
/*
* Take the lock - this will be released by the corresponding
* call to stop().
*/
- mutex_lock(&iface->ids->mutex);
+ mutex_lock(&ids->mutex);
/* pos < 0 is invalid */
if (*pos < 0)
@@ -680,8 +790,8 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
return SEQ_START_TOKEN;
/* Find the (pos-1)th ipc */
- for (p = *pos - 1; p <= iface->ids->max_id; p++) {
- if ((ipc = ipc_lock(iface->ids, p)) != NULL) {
+ for (p = *pos - 1; p <= ids->max_id; p++) {
+ if ((ipc = ipc_lock(ids, p)) != NULL) {
*pos = p + 1;
return ipc;
}
@@ -693,13 +803,15 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it)
{
struct kern_ipc_perm *ipc = it;
struct ipc_proc_iface *iface = s->private;
+ struct ipc_ids *ids;
/* If we had a locked segment, release it */
if (ipc && ipc != SEQ_START_TOKEN)
ipc_unlock(ipc);
+ ids = current->nsproxy->ipc_ns->ids[iface->ids];
/* Release the lock we took in start() */
- mutex_unlock(&iface->ids->mutex);
+ mutex_unlock(&ids->mutex);
}
static int sysvipc_proc_show(struct seq_file *s, void *it)
diff --git a/ipc/util.h b/ipc/util.h
index 0181553d31d8..c8fd6b9d77b5 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -3,6 +3,8 @@
* Copyright (C) 1999 Christoph Rohland
*
* ipc helper functions (c) 1999 Manfred Spraul <manfred@colorfullife.com>
+ * namespaces support. 2006 OpenVZ, SWsoft Inc.
+ * Pavel Emelianov <xemul@openvz.org>
*/
#ifndef _IPC_UTIL_H
@@ -15,6 +17,14 @@ void sem_init (void);
void msg_init (void);
void shm_init (void);
+int sem_init_ns(struct ipc_namespace *ns);
+int msg_init_ns(struct ipc_namespace *ns);
+int shm_init_ns(struct ipc_namespace *ns);
+
+void sem_exit_ns(struct ipc_namespace *ns);
+void msg_exit_ns(struct ipc_namespace *ns);
+void shm_exit_ns(struct ipc_namespace *ns);
+
struct ipc_id_ary {
int size;
struct kern_ipc_perm *p[0];
@@ -31,15 +41,23 @@ struct ipc_ids {
};
struct seq_file;
-void __init ipc_init_ids(struct ipc_ids* ids, int size);
+#ifdef CONFIG_IPC_NS
+#define __ipc_init
+#else
+#define __ipc_init __init
+#endif
+void __ipc_init ipc_init_ids(struct ipc_ids *ids, int size);
#ifdef CONFIG_PROC_FS
void __init ipc_init_proc_interface(const char *path, const char *header,
- struct ipc_ids *ids,
- int (*show)(struct seq_file *, void *));
+ int ids, int (*show)(struct seq_file *, void *));
#else
#define ipc_init_proc_interface(path, header, ids, show) do {} while (0)
#endif
+#define IPC_SEM_IDS 0
+#define IPC_MSG_IDS 1
+#define IPC_SHM_IDS 2
+
/* must be called with ids->mutex acquired.*/
int ipc_findkey(struct ipc_ids* ids, key_t key);
int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size);
diff --git a/kernel/Makefile b/kernel/Makefile
index d62ec66c1af2..5e3f3b75563a 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -8,7 +8,7 @@ obj-y = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
signal.o sys.o kmod.o workqueue.o pid.o \
rcupdate.o extable.o params.o posix-timers.o \
kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
- hrtimer.o rwsem.o
+ hrtimer.o rwsem.o latency.o nsproxy.o srcu.o
obj-$(CONFIG_STACKTRACE) += stacktrace.o
obj-y += time/
@@ -48,8 +48,9 @@ obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_SECCOMP) += seccomp.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
obj-$(CONFIG_RELAY) += relay.o
+obj-$(CONFIG_UTS_NS) += utsname.o
obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
-obj-$(CONFIG_TASKSTATS) += taskstats.o
+obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
diff --git a/kernel/acct.c b/kernel/acct.c
index 2a7c933651c7..0aad5ca36a81 100644
--- a/kernel/acct.c
+++ b/kernel/acct.c
@@ -483,10 +483,14 @@ static void do_acct_process(struct file *file)
ac.ac_ppid = current->parent->tgid;
#endif
- read_lock(&tasklist_lock); /* pin current->signal */
+ mutex_lock(&tty_mutex);
+ /* FIXME: Whoever is responsible for current->signal locking needs
+ to use the same locking all over the kernel and document it */
+ read_lock(&tasklist_lock);
ac.ac_tty = current->signal->tty ?
old_encode_dev(tty_devnum(current->signal->tty)) : 0;
read_unlock(&tasklist_lock);
+ mutex_unlock(&tty_mutex);
spin_lock_irq(&current->sighand->siglock);
ac.ac_utime = encode_comp_t(jiffies_to_AHZ(cputime_to_jiffies(pacct->ac_utime)));
@@ -598,33 +602,3 @@ void acct_process(void)
do_acct_process(file);
fput(file);
}
-
-
-/**
- * acct_update_integrals - update mm integral fields in task_struct
- * @tsk: task_struct for accounting
- */
-void acct_update_integrals(struct task_struct *tsk)
-{
- if (likely(tsk->mm)) {
- long delta =
- cputime_to_jiffies(tsk->stime) - tsk->acct_stimexpd;
-
- if (delta == 0)
- return;
- tsk->acct_stimexpd = tsk->stime;
- tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm);
- tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
- }
-}
-
-/**
- * acct_clear_integrals - clear the mm integral fields in task_struct
- * @tsk: task_struct whose accounting fields are cleared
- */
-void acct_clear_integrals(struct task_struct *tsk)
-{
- tsk->acct_stimexpd = 0;
- tsk->acct_rss_mem1 = 0;
- tsk->acct_vm_mem1 = 0;
-}
diff --git a/kernel/audit.c b/kernel/audit.c
index f9889ee77825..98106f6078b0 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -340,7 +340,7 @@ static int kauditd_thread(void *dummy)
{
struct sk_buff *skb;
- while (1) {
+ while (!kthread_should_stop()) {
skb = skb_dequeue(&audit_skb_queue);
wake_up(&audit_backlog_wait);
if (skb) {
@@ -369,6 +369,7 @@ static int kauditd_thread(void *dummy)
remove_wait_queue(&kauditd_wait, &wait);
}
}
+ return 0;
}
int audit_send_list(void *_dest)
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 1a58a81fb09d..4f40d923af8e 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -411,7 +411,6 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
case AUDIT_FSGID:
case AUDIT_LOGINUID:
case AUDIT_PERS:
- case AUDIT_ARCH:
case AUDIT_MSGTYPE:
case AUDIT_PPID:
case AUDIT_DEVMAJOR:
@@ -423,6 +422,14 @@ static struct audit_entry *audit_rule_to_entry(struct audit_rule *rule)
case AUDIT_ARG2:
case AUDIT_ARG3:
break;
+ /* arch is only allowed to be = or != */
+ case AUDIT_ARCH:
+ if ((f->op != AUDIT_NOT_EQUAL) && (f->op != AUDIT_EQUAL)
+ && (f->op != AUDIT_NEGATE) && (f->op)) {
+ err = -EINVAL;
+ goto exit_free;
+ }
+ break;
case AUDIT_PERM:
if (f->val & ~15)
goto exit_free;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index fb83c5cb8c32..42f2f1179711 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -278,8 +278,11 @@ static int audit_filter_rules(struct task_struct *tsk,
result = audit_comparator(tsk->pid, f->op, f->val);
break;
case AUDIT_PPID:
- if (ctx)
+ if (ctx) {
+ if (!ctx->ppid)
+ ctx->ppid = sys_getppid();
result = audit_comparator(ctx->ppid, f->op, f->val);
+ }
break;
case AUDIT_UID:
result = audit_comparator(tsk->uid, f->op, f->val);
@@ -795,7 +798,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
/* tsk == current */
context->pid = tsk->pid;
- context->ppid = sys_getppid(); /* sic. tsk == current in all cases */
+ if (!context->ppid)
+ context->ppid = sys_getppid();
context->uid = tsk->uid;
context->gid = tsk->gid;
context->euid = tsk->euid;
@@ -817,6 +821,8 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
audit_log_format(ab, " success=%s exit=%ld",
(context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
context->return_code);
+
+ mutex_lock(&tty_mutex);
if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name)
tty = tsk->signal->tty->name;
else
@@ -838,6 +844,9 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
context->gid,
context->euid, context->suid, context->fsuid,
context->egid, context->sgid, context->fsgid, tty);
+
+ mutex_unlock(&tty_mutex);
+
audit_log_task_info(ab, tsk);
if (context->filterkey) {
audit_log_format(ab, " key=");
@@ -1132,6 +1141,7 @@ void audit_syscall_entry(int arch, int major,
context->ctime = CURRENT_TIME;
context->in_syscall = 1;
context->auditable = !!(state == AUDIT_RECORD_CONTEXT);
+ context->ppid = 0;
}
/**
@@ -1347,7 +1357,13 @@ void __audit_inode_child(const char *dname, const struct inode *inode,
}
update_context:
- idx = context->name_count++;
+ idx = context->name_count;
+ if (context->name_count == AUDIT_NAMES) {
+ printk(KERN_DEBUG "name_count maxed and losing %s\n",
+ found_name ?: "(null)");
+ return;
+ }
+ context->name_count++;
#if AUDIT_DEBUG
context->ino_count++;
#endif
@@ -1365,7 +1381,16 @@ update_context:
/* A parent was not found in audit_names, so copy the inode data for the
* provided parent. */
if (!found_name) {
- idx = context->name_count++;
+ idx = context->name_count;
+ if (context->name_count == AUDIT_NAMES) {
+ printk(KERN_DEBUG
+ "name_count maxed and losing parent inode data: dev=%02x:%02x, inode=%lu",
+ MAJOR(parent->i_sb->s_dev),
+ MINOR(parent->i_sb->s_dev),
+ parent->i_ino);
+ return;
+ }
+ context->name_count++;
#if AUDIT_DEBUG
context->ino_count++;
#endif
diff --git a/kernel/capability.c b/kernel/capability.c
index c7685ad00a97..edb845a6e84a 100644
--- a/kernel/capability.c
+++ b/kernel/capability.c
@@ -133,7 +133,7 @@ static inline int cap_set_all(kernel_cap_t *effective,
int found = 0;
do_each_thread(g, target) {
- if (target == current || target->pid == 1)
+ if (target == current || is_init(target))
continue;
found = 1;
if (security_capset_check(target, effective, inheritable,
diff --git a/kernel/compat.c b/kernel/compat.c
index 126dee9530aa..75573e5d27b0 100644
--- a/kernel/compat.c
+++ b/kernel/compat.c
@@ -22,6 +22,7 @@
#include <linux/security.h>
#include <linux/timex.h>
#include <linux/migrate.h>
+#include <linux/posix-timers.h>
#include <asm/uaccess.h>
@@ -601,6 +602,30 @@ long compat_sys_clock_getres(clockid_t which_clock,
return err;
}
+static long compat_clock_nanosleep_restart(struct restart_block *restart)
+{
+ long err;
+ mm_segment_t oldfs;
+ struct timespec tu;
+ struct compat_timespec *rmtp = (struct compat_timespec *)(restart->arg1);
+
+ restart->arg1 = (unsigned long) &tu;
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ err = clock_nanosleep_restart(restart);
+ set_fs(oldfs);
+
+ if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
+ put_compat_timespec(&tu, rmtp))
+ return -EFAULT;
+
+ if (err == -ERESTART_RESTARTBLOCK) {
+ restart->fn = compat_clock_nanosleep_restart;
+ restart->arg1 = (unsigned long) rmtp;
+ }
+ return err;
+}
+
long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
struct compat_timespec __user *rqtp,
struct compat_timespec __user *rmtp)
@@ -608,6 +633,7 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
long err;
mm_segment_t oldfs;
struct timespec in, out;
+ struct restart_block *restart;
if (get_compat_timespec(&in, rqtp))
return -EFAULT;
@@ -618,9 +644,16 @@ long compat_sys_clock_nanosleep(clockid_t which_clock, int flags,
(struct timespec __user *) &in,
(struct timespec __user *) &out);
set_fs(oldfs);
+
if ((err == -ERESTART_RESTARTBLOCK) && rmtp &&
put_compat_timespec(&out, rmtp))
return -EFAULT;
+
+ if (err == -ERESTART_RESTARTBLOCK) {
+ restart = &current_thread_info()->restart_block;
+ restart->fn = compat_clock_nanosleep_restart;
+ restart->arg1 = (unsigned long) rmtp;
+ }
return err;
}
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 32c96628463e..27dd3ee47099 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -19,7 +19,7 @@
static DEFINE_MUTEX(cpu_add_remove_lock);
static DEFINE_MUTEX(cpu_bitmask_lock);
-static __cpuinitdata BLOCKING_NOTIFIER_HEAD(cpu_chain);
+static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain);
/* If set, cpu_up and cpu_down will return -EBUSY and do nothing.
* Should always be manipulated under cpu_add_remove_lock
@@ -68,7 +68,11 @@ EXPORT_SYMBOL_GPL(unlock_cpu_hotplug);
/* Need to know about CPUs going up/down? */
int __cpuinit register_cpu_notifier(struct notifier_block *nb)
{
- return blocking_notifier_chain_register(&cpu_chain, nb);
+ int ret;
+ mutex_lock(&cpu_add_remove_lock);
+ ret = raw_notifier_chain_register(&cpu_chain, nb);
+ mutex_unlock(&cpu_add_remove_lock);
+ return ret;
}
#ifdef CONFIG_HOTPLUG_CPU
@@ -77,7 +81,9 @@ EXPORT_SYMBOL(register_cpu_notifier);
void unregister_cpu_notifier(struct notifier_block *nb)
{
- blocking_notifier_chain_unregister(&cpu_chain, nb);
+ mutex_lock(&cpu_add_remove_lock);
+ raw_notifier_chain_unregister(&cpu_chain, nb);
+ mutex_unlock(&cpu_add_remove_lock);
}
EXPORT_SYMBOL(unregister_cpu_notifier);
@@ -126,7 +132,7 @@ static int _cpu_down(unsigned int cpu)
if (!cpu_online(cpu))
return -EINVAL;
- err = blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
+ err = raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE,
(void *)(long)cpu);
if (err == NOTIFY_BAD) {
printk("%s: attempt to take down CPU %u failed\n",
@@ -146,7 +152,7 @@ static int _cpu_down(unsigned int cpu)
if (IS_ERR(p)) {
/* CPU didn't die: tell everyone. Can't complain. */
- if (blocking_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
+ if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED,
(void *)(long)cpu) == NOTIFY_BAD)
BUG();
@@ -169,7 +175,7 @@ static int _cpu_down(unsigned int cpu)
put_cpu();
/* CPU is completely dead: tell everyone. Too late to complain. */
- if (blocking_notifier_call_chain(&cpu_chain, CPU_DEAD,
+ if (raw_notifier_call_chain(&cpu_chain, CPU_DEAD,
(void *)(long)cpu) == NOTIFY_BAD)
BUG();
@@ -206,7 +212,7 @@ static int __devinit _cpu_up(unsigned int cpu)
if (cpu_online(cpu) || !cpu_present(cpu))
return -EINVAL;
- ret = blocking_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
+ ret = raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE, hcpu);
if (ret == NOTIFY_BAD) {
printk("%s: attempt to bring up CPU %u failed\n",
__FUNCTION__, cpu);
@@ -223,11 +229,11 @@ static int __devinit _cpu_up(unsigned int cpu)
BUG_ON(!cpu_online(cpu));
/* Now call notifier in preparation. */
- blocking_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
+ raw_notifier_call_chain(&cpu_chain, CPU_ONLINE, hcpu);
out_notify:
if (ret != 0)
- blocking_notifier_call_chain(&cpu_chain,
+ raw_notifier_call_chain(&cpu_chain,
CPU_UP_CANCELED, hcpu);
return ret;
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index cff41511269f..6313c38c930e 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -240,7 +240,7 @@ static struct super_block *cpuset_sb;
* A cpuset can only be deleted if both its 'count' of using tasks
* is zero, and its list of 'children' cpusets is empty. Since all
* tasks in the system use _some_ cpuset, and since there is always at
- * least one task in the system (init, pid == 1), therefore, top_cpuset
+ * least one task in the system (init), therefore, top_cpuset
* always has either children cpusets and/or using tasks. So we don't
* need a special hack to ensure that top_cpuset cannot be deleted.
*
@@ -289,7 +289,6 @@ static struct inode *cpuset_new_inode(mode_t mode)
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->backing_dev_info = &cpuset_backing_dev_info;
@@ -378,7 +377,7 @@ static int cpuset_fill_super(struct super_block *sb, void *unused_data,
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
/* directories start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
} else {
return -ENOMEM;
}
@@ -913,6 +912,10 @@ static int update_nodemask(struct cpuset *cs, char *buf)
int fudge;
int retval;
+ /* top_cpuset.mems_allowed tracks node_online_map; it's read-only */
+ if (cs == &top_cpuset)
+ return -EACCES;
+
trialcs = *cs;
retval = nodelist_parse(buf, trialcs.mems_allowed);
if (retval < 0)
@@ -1222,7 +1225,12 @@ static int attach_task(struct cpuset *cs, char *pidbuf, char **ppathbuf)
task_lock(tsk);
oldcs = tsk->cpuset;
- if (!oldcs) {
+ /*
+ * After getting 'oldcs' cpuset ptr, be sure still not exiting.
+ * If 'oldcs' might be the top_cpuset due to the_top_cpuset_hack
+ * then fail this attach_task(), to avoid breaking top_cpuset.count.
+ */
+ if (tsk->flags & PF_EXITING) {
task_unlock(tsk);
mutex_unlock(&callback_mutex);
put_task_struct(tsk);
@@ -1557,7 +1565,7 @@ static int cpuset_create_file(struct dentry *dentry, int mode)
inode->i_fop = &simple_dir_operations;
/* start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
} else if (S_ISREG(mode)) {
inode->i_size = 0;
inode->i_fop = &cpuset_file_operations;
@@ -1590,7 +1598,7 @@ static int cpuset_create_dir(struct cpuset *cs, const char *name, int mode)
error = cpuset_create_file(dentry, S_IFDIR | mode);
if (!error) {
dentry->d_fsdata = cs;
- parent->d_inode->i_nlink++;
+ inc_nlink(parent->d_inode);
cs->dentry = dentry;
}
dput(dentry);
@@ -2025,7 +2033,7 @@ int __init cpuset_init(void)
}
root = cpuset_mount->mnt_sb->s_root;
root->d_fsdata = &top_cpuset;
- root->d_inode->i_nlink++;
+ inc_nlink(root->d_inode);
top_cpuset.dentry = root;
root->d_inode->i_op = &cpuset_dir_inode_operations;
number_of_cpusets = 1;
@@ -2037,33 +2045,104 @@ out:
return err;
}
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_MEMORY_HOTPLUG)
/*
- * The top_cpuset tracks what CPUs and Memory Nodes are online,
- * period. This is necessary in order to make cpusets transparent
- * (of no affect) on systems that are actively using CPU hotplug
- * but making no active use of cpusets.
- *
- * This handles CPU hotplug (cpuhp) events. If someday Memory
- * Nodes can be hotplugged (dynamically changing node_online_map)
- * then we should handle that too, perhaps in a similar way.
+ * If common_cpu_mem_hotplug_unplug(), below, unplugs any CPUs
+ * or memory nodes, we need to walk over the cpuset hierarchy,
+ * removing that CPU or node from all cpusets. If this removes the
+ * last CPU or node from a cpuset, then the guarantee_online_cpus()
+ * or guarantee_online_mems() code will use that emptied cpusets
+ * parent online CPUs or nodes. Cpusets that were already empty of
+ * CPUs or nodes are left empty.
+ *
+ * This routine is intentionally inefficient in a couple of regards.
+ * It will check all cpusets in a subtree even if the top cpuset of
+ * the subtree has no offline CPUs or nodes. It checks both CPUs and
+ * nodes, even though the caller could have been coded to know that
+ * only one of CPUs or nodes needed to be checked on a given call.
+ * This was done to minimize text size rather than cpu cycles.
+ *
+ * Call with both manage_mutex and callback_mutex held.
+ *
+ * Recursive, on depth of cpuset subtree.
*/
-#ifdef CONFIG_HOTPLUG_CPU
-static int cpuset_handle_cpuhp(struct notifier_block *nb,
- unsigned long phase, void *cpu)
+static void guarantee_online_cpus_mems_in_subtree(const struct cpuset *cur)
+{
+ struct cpuset *c;
+
+ /* Each of our child cpusets mems must be online */
+ list_for_each_entry(c, &cur->children, sibling) {
+ guarantee_online_cpus_mems_in_subtree(c);
+ if (!cpus_empty(c->cpus_allowed))
+ guarantee_online_cpus(c, &c->cpus_allowed);
+ if (!nodes_empty(c->mems_allowed))
+ guarantee_online_mems(c, &c->mems_allowed);
+ }
+}
+
+/*
+ * The cpus_allowed and mems_allowed nodemasks in the top_cpuset track
+ * cpu_online_map and node_online_map. Force the top cpuset to track
+ * whats online after any CPU or memory node hotplug or unplug event.
+ *
+ * To ensure that we don't remove a CPU or node from the top cpuset
+ * that is currently in use by a child cpuset (which would violate
+ * the rule that cpusets must be subsets of their parent), we first
+ * call the recursive routine guarantee_online_cpus_mems_in_subtree().
+ *
+ * Since there are two callers of this routine, one for CPU hotplug
+ * events and one for memory node hotplug events, we could have coded
+ * two separate routines here. We code it as a single common routine
+ * in order to minimize text size.
+ */
+
+static void common_cpu_mem_hotplug_unplug(void)
{
mutex_lock(&manage_mutex);
mutex_lock(&callback_mutex);
+ guarantee_online_cpus_mems_in_subtree(&top_cpuset);
top_cpuset.cpus_allowed = cpu_online_map;
+ top_cpuset.mems_allowed = node_online_map;
mutex_unlock(&callback_mutex);
mutex_unlock(&manage_mutex);
+}
+#endif
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * The top_cpuset tracks what CPUs and Memory Nodes are online,
+ * period. This is necessary in order to make cpusets transparent
+ * (of no affect) on systems that are actively using CPU hotplug
+ * but making no active use of cpusets.
+ *
+ * This routine ensures that top_cpuset.cpus_allowed tracks
+ * cpu_online_map on each CPU hotplug (cpuhp) event.
+ */
+static int cpuset_handle_cpuhp(struct notifier_block *nb,
+ unsigned long phase, void *cpu)
+{
+ common_cpu_mem_hotplug_unplug();
return 0;
}
#endif
+#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Keep top_cpuset.mems_allowed tracking node_online_map.
+ * Call this routine anytime after you change node_online_map.
+ * See also the previous routine cpuset_handle_cpuhp().
+ */
+
+void cpuset_track_online_nodes(void)
+{
+ common_cpu_mem_hotplug_unplug();
+}
+#endif
+
/**
* cpuset_init_smp - initialize cpus_allowed
*
diff --git a/kernel/dma.c b/kernel/dma.c
index aef0a45b7893..2020644c938a 100644
--- a/kernel/dma.c
+++ b/kernel/dma.c
@@ -62,6 +62,11 @@ static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
};
+/**
+ * request_dma - request and reserve a system DMA channel
+ * @dmanr: DMA channel number
+ * @device_id: reserving device ID string, used in /proc/dma
+ */
int request_dma(unsigned int dmanr, const char * device_id)
{
if (dmanr >= MAX_DMA_CHANNELS)
@@ -76,7 +81,10 @@ int request_dma(unsigned int dmanr, const char * device_id)
return 0;
} /* request_dma */
-
+/**
+ * free_dma - free a reserved system DMA channel
+ * @dmanr: DMA channel number
+ */
void free_dma(unsigned int dmanr)
{
if (dmanr >= MAX_DMA_CHANNELS) {
diff --git a/kernel/exit.c b/kernel/exit.c
index d891883420f7..f250a5e3e281 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -18,8 +18,10 @@
#include <linux/security.h>
#include <linux/cpu.h>
#include <linux/acct.h>
+#include <linux/tsacct_kern.h>
#include <linux/file.h>
#include <linux/binfmts.h>
+#include <linux/nsproxy.h>
#include <linux/ptrace.h>
#include <linux/profile.h>
#include <linux/mount.h>
@@ -38,6 +40,7 @@
#include <linux/pipe_fs_i.h>
#include <linux/audit.h> /* for audit_free() */
#include <linux/resource.h>
+#include <linux/blkdev.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
@@ -219,7 +222,7 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct *ignored_task)
do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
if (p == ignored_task
|| p->exit_state
- || p->real_parent->pid == 1)
+ || is_init(p->real_parent))
continue;
if (process_group(p->real_parent) != pgrp
&& p->real_parent->signal->session == p->signal->session) {
@@ -249,17 +252,6 @@ static int has_stopped_jobs(int pgrp)
do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
if (p->state != TASK_STOPPED)
continue;
-
- /* If p is stopped by a debugger on a signal that won't
- stop it, then don't count p as stopped. This isn't
- perfect but it's a good approximation. */
- if (unlikely (p->ptrace)
- && p->exit_code != SIGSTOP
- && p->exit_code != SIGTSTP
- && p->exit_code != SIGTTOU
- && p->exit_code != SIGTTIN)
- continue;
-
retval = 1;
break;
} while_each_task_pid(pgrp, PIDTYPE_PGID, p);
@@ -292,9 +284,7 @@ static void reparent_to_init(void)
/* Set the exit signal to SIGCHLD so we signal init on exit */
current->exit_signal = SIGCHLD;
- if ((current->policy == SCHED_NORMAL ||
- current->policy == SCHED_BATCH)
- && (task_nice(current) < 0))
+ if (!has_rt_policy(current) && (task_nice(current) < 0))
set_user_nice(current, 0);
/* cpus_allowed? */
/* rt_priority? */
@@ -408,9 +398,11 @@ void daemonize(const char *name, ...)
fs = init_task.fs;
current->fs = fs;
atomic_inc(&fs->count);
- exit_namespace(current);
- current->namespace = init_task.namespace;
- get_namespace(current->namespace);
+
+ exit_task_namespaces(current);
+ current->nsproxy = init_task.nsproxy;
+ get_task_namespaces(current);
+
exit_files(current);
current->files = init_task.files;
atomic_inc(&current->files->count);
@@ -487,6 +479,18 @@ void fastcall put_files_struct(struct files_struct *files)
EXPORT_SYMBOL(put_files_struct);
+void reset_files_struct(struct task_struct *tsk, struct files_struct *files)
+{
+ struct files_struct *old;
+
+ old = tsk->files;
+ task_lock(tsk);
+ tsk->files = files;
+ task_unlock(tsk);
+ put_files_struct(old);
+}
+EXPORT_SYMBOL(reset_files_struct);
+
static inline void __exit_files(struct task_struct *tsk)
{
struct files_struct * files = tsk->files;
@@ -916,7 +920,6 @@ fastcall NORET_TYPE void do_exit(long code)
exit_sem(tsk);
__exit_files(tsk);
__exit_fs(tsk);
- exit_namespace(tsk);
exit_thread();
cpuset_exit(tsk);
exit_keys(tsk);
@@ -931,6 +934,7 @@ fastcall NORET_TYPE void do_exit(long code)
tsk->exit_code = code;
proc_exit_connector(tsk);
exit_notify(tsk);
+ exit_task_namespaces(tsk);
#ifdef CONFIG_NUMA
mpol_free(tsk->mempolicy);
tsk->mempolicy = NULL;
@@ -954,15 +958,15 @@ fastcall NORET_TYPE void do_exit(long code)
if (tsk->splice_pipe)
__free_pipe_info(tsk->splice_pipe);
- /* PF_DEAD causes final put_task_struct after we schedule. */
preempt_disable();
- BUG_ON(tsk->flags & PF_DEAD);
- tsk->flags |= PF_DEAD;
+ /* causes final put_task_struct in finish_task_switch(). */
+ tsk->state = TASK_DEAD;
schedule();
BUG();
/* Avoid "noreturn function does return". */
- for (;;) ;
+ for (;;)
+ cpu_relax(); /* For when BUG is null */
}
EXPORT_SYMBOL_GPL(do_exit);
@@ -971,7 +975,7 @@ NORET_TYPE void complete_and_exit(struct completion *comp, long code)
{
if (comp)
complete(comp);
-
+
do_exit(code);
}
diff --git a/kernel/fork.c b/kernel/fork.c
index a0dad84567c9..29ebb30850ed 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -27,6 +27,7 @@
#include <linux/binfmts.h>
#include <linux/mman.h>
#include <linux/fs.h>
+#include <linux/nsproxy.h>
#include <linux/capability.h>
#include <linux/cpu.h>
#include <linux/cpuset.h>
@@ -42,6 +43,7 @@
#include <linux/profile.h>
#include <linux/rmap.h>
#include <linux/acct.h>
+#include <linux/tsacct_kern.h>
#include <linux/cn_proc.h>
#include <linux/delayacct.h>
#include <linux/taskstats_kern.h>
@@ -183,7 +185,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig)
/* One for us, one for whoever does the "release_task()" (usually parent) */
atomic_set(&tsk->usage,2);
atomic_set(&tsk->fs_excl, 0);
+#ifdef CONFIG_BLK_DEV_IO_TRACE
tsk->btrace_seq = 0;
+#endif
tsk->splice_pipe = NULL;
return tsk;
}
@@ -980,6 +984,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
if (!p)
goto fork_out;
+ rt_mutex_init_task(p);
+
#ifdef CONFIG_TRACE_IRQFLAGS
DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled);
DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled);
@@ -1061,7 +1067,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
#endif
#ifdef CONFIG_TRACE_IRQFLAGS
p->irq_events = 0;
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+ p->hardirqs_enabled = 1;
+#else
p->hardirqs_enabled = 0;
+#endif
p->hardirq_enable_ip = 0;
p->hardirq_enable_event = 0;
p->hardirq_disable_ip = _THIS_IP_;
@@ -1080,8 +1090,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
p->lockdep_recursion = 0;
#endif
- rt_mutex_init_task(p);
-
#ifdef CONFIG_DEBUG_MUTEXES
p->blocked_on = NULL; /* not blocked yet */
#endif
@@ -1109,11 +1117,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
goto bad_fork_cleanup_signal;
if ((retval = copy_keys(clone_flags, p)))
goto bad_fork_cleanup_mm;
- if ((retval = copy_namespace(clone_flags, p)))
+ if ((retval = copy_namespaces(clone_flags, p)))
goto bad_fork_cleanup_keys;
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
if (retval)
- goto bad_fork_cleanup_namespace;
+ goto bad_fork_cleanup_namespaces;
p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
/*
@@ -1144,7 +1152,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
/* Our parent execution domain becomes current domain
These must match for thread signalling to apply */
-
p->parent_exec_id = p->self_exec_id;
/* ok, now we should be set up.. */
@@ -1167,6 +1174,9 @@ static struct task_struct *copy_process(unsigned long clone_flags,
/* Need tasklist lock for parent etc handling! */
write_lock_irq(&tasklist_lock);
+ /* for sys_ioprio_set(IOPRIO_WHO_PGRP) */
+ p->ioprio = current->ioprio;
+
/*
* The task hasn't been attached yet, so its cpus_allowed mask will
* not be changed, nor will its assigned CPU.
@@ -1203,7 +1213,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
spin_unlock(&current->sighand->siglock);
write_unlock_irq(&tasklist_lock);
retval = -ERESTARTNOINTR;
- goto bad_fork_cleanup_namespace;
+ goto bad_fork_cleanup_namespaces;
}
if (clone_flags & CLONE_THREAD) {
@@ -1226,11 +1236,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
}
}
- /*
- * inherit ioprio
- */
- p->ioprio = current->ioprio;
-
if (likely(p->pid)) {
add_parent(p);
if (unlikely(p->ptrace & PT_PTRACED))
@@ -1256,8 +1261,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
proc_fork_connector(p);
return p;
-bad_fork_cleanup_namespace:
- exit_namespace(p);
+bad_fork_cleanup_namespaces:
+ exit_task_namespaces(p);
bad_fork_cleanup_keys:
exit_keys(p);
bad_fork_cleanup_mm:
@@ -1510,10 +1515,9 @@ static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp)
*/
static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
{
- struct namespace *ns = current->namespace;
+ struct namespace *ns = current->nsproxy->namespace;
- if ((unshare_flags & CLONE_NEWNS) &&
- (ns && atomic_read(&ns->count) > 1)) {
+ if ((unshare_flags & CLONE_NEWNS) && ns) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
@@ -1585,6 +1589,16 @@ static int unshare_semundo(unsigned long unshare_flags, struct sem_undo_list **n
return 0;
}
+#ifndef CONFIG_IPC_NS
+static inline int unshare_ipcs(unsigned long flags, struct ipc_namespace **ns)
+{
+ if (flags & CLONE_NEWIPC)
+ return -EINVAL;
+
+ return 0;
+}
+#endif
+
/*
* unshare allows a process to 'unshare' part of the process
* context which was originally shared using clone. copy_*
@@ -1602,13 +1616,17 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
struct mm_struct *mm, *new_mm = NULL, *active_mm = NULL;
struct files_struct *fd, *new_fd = NULL;
struct sem_undo_list *new_ulist = NULL;
+ struct nsproxy *new_nsproxy = NULL, *old_nsproxy = NULL;
+ struct uts_namespace *uts, *new_uts = NULL;
+ struct ipc_namespace *ipc, *new_ipc = NULL;
check_unshare_flags(&unshare_flags);
/* Return -EINVAL for all unsupported flags */
err = -EINVAL;
if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
- CLONE_VM|CLONE_FILES|CLONE_SYSVSEM))
+ CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
+ CLONE_NEWUTS|CLONE_NEWIPC))
goto bad_unshare_out;
if ((err = unshare_thread(unshare_flags)))
@@ -1625,11 +1643,30 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
goto bad_unshare_cleanup_vm;
if ((err = unshare_semundo(unshare_flags, &new_ulist)))
goto bad_unshare_cleanup_fd;
+ if ((err = unshare_utsname(unshare_flags, &new_uts)))
+ goto bad_unshare_cleanup_semundo;
+ if ((err = unshare_ipcs(unshare_flags, &new_ipc)))
+ goto bad_unshare_cleanup_uts;
+
+ if (new_ns || new_uts || new_ipc) {
+ old_nsproxy = current->nsproxy;
+ new_nsproxy = dup_namespaces(old_nsproxy);
+ if (!new_nsproxy) {
+ err = -ENOMEM;
+ goto bad_unshare_cleanup_ipc;
+ }
+ }
- if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist) {
+ if (new_fs || new_ns || new_sigh || new_mm || new_fd || new_ulist ||
+ new_uts || new_ipc) {
task_lock(current);
+ if (new_nsproxy) {
+ current->nsproxy = new_nsproxy;
+ new_nsproxy = old_nsproxy;
+ }
+
if (new_fs) {
fs = current->fs;
current->fs = new_fs;
@@ -1637,8 +1674,8 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
}
if (new_ns) {
- ns = current->namespace;
- current->namespace = new_ns;
+ ns = current->nsproxy->namespace;
+ current->nsproxy->namespace = new_ns;
new_ns = ns;
}
@@ -1663,9 +1700,33 @@ asmlinkage long sys_unshare(unsigned long unshare_flags)
new_fd = fd;
}
+ if (new_uts) {
+ uts = current->nsproxy->uts_ns;
+ current->nsproxy->uts_ns = new_uts;
+ new_uts = uts;
+ }
+
+ if (new_ipc) {
+ ipc = current->nsproxy->ipc_ns;
+ current->nsproxy->ipc_ns = new_ipc;
+ new_ipc = ipc;
+ }
+
task_unlock(current);
}
+ if (new_nsproxy)
+ put_nsproxy(new_nsproxy);
+
+bad_unshare_cleanup_ipc:
+ if (new_ipc)
+ put_ipc_ns(new_ipc);
+
+bad_unshare_cleanup_uts:
+ if (new_uts)
+ put_uts_ns(new_uts);
+
+bad_unshare_cleanup_semundo:
bad_unshare_cleanup_fd:
if (new_fd)
put_files_struct(new_fd);
diff --git a/kernel/futex.c b/kernel/futex.c
index 9d260e838cff..b364e0026191 100644
--- a/kernel/futex.c
+++ b/kernel/futex.c
@@ -389,7 +389,7 @@ static struct task_struct * futex_find_get_task(pid_t pid)
{
struct task_struct *p;
- read_lock(&tasklist_lock);
+ rcu_read_lock();
p = find_task_by_pid(pid);
if (!p)
goto out_unlock;
@@ -403,7 +403,7 @@ static struct task_struct * futex_find_get_task(pid_t pid)
}
get_task_struct(p);
out_unlock:
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
return p;
}
@@ -1527,7 +1527,7 @@ static int futex_fd(u32 __user *uaddr, int signal)
filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
if (signal) {
- err = f_setown(filp, current->pid, 1);
+ err = __f_setown(filp, task_pid(current), PIDTYPE_PID, 1);
if (err < 0) {
goto error;
}
@@ -1612,10 +1612,10 @@ sys_set_robust_list(struct robust_list_head __user *head,
* @len_ptr: pointer to a length field, the kernel fills in the header size
*/
asmlinkage long
-sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
+sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr,
size_t __user *len_ptr)
{
- struct robust_list_head *head;
+ struct robust_list_head __user *head;
unsigned long ret;
if (!pid)
@@ -1624,7 +1624,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
struct task_struct *p;
ret = -ESRCH;
- read_lock(&tasklist_lock);
+ rcu_read_lock();
p = find_task_by_pid(pid);
if (!p)
goto err_unlock;
@@ -1633,7 +1633,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
!capable(CAP_SYS_PTRACE))
goto err_unlock;
head = p->robust_list;
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
}
if (put_user(sizeof(*head), len_ptr))
@@ -1641,7 +1641,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user **head_ptr,
return put_user(head, head_ptr);
err_unlock:
- read_unlock(&tasklist_lock);
+ rcu_read_unlock();
return ret;
}
@@ -1694,14 +1694,15 @@ retry:
* Fetch a robust-list pointer. Bit 0 signals PI futexes:
*/
static inline int fetch_robust_entry(struct robust_list __user **entry,
- struct robust_list __user **head, int *pi)
+ struct robust_list __user * __user *head,
+ int *pi)
{
unsigned long uentry;
- if (get_user(uentry, (unsigned long *)head))
+ if (get_user(uentry, (unsigned long __user *)head))
return -EFAULT;
- *entry = (void *)(uentry & ~1UL);
+ *entry = (void __user *)(uentry & ~1UL);
*pi = uentry & 1;
return 0;
@@ -1739,7 +1740,7 @@ void exit_robust_list(struct task_struct *curr)
return;
if (pending)
- handle_futex_death((void *)pending + futex_offset, curr, pip);
+ handle_futex_death((void __user *)pending + futex_offset, curr, pip);
while (entry != &head->list) {
/*
@@ -1747,7 +1748,7 @@ void exit_robust_list(struct task_struct *curr)
* don't process it twice:
*/
if (entry != pending)
- if (handle_futex_death((void *)entry + futex_offset,
+ if (handle_futex_death((void __user *)entry + futex_offset,
curr, pi))
return;
/*
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c
index c5cca3f65cb7..50f24eea6cd0 100644
--- a/kernel/futex_compat.c
+++ b/kernel/futex_compat.c
@@ -18,7 +18,7 @@
*/
static inline int
fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
- compat_uptr_t *head, int *pi)
+ compat_uptr_t __user *head, int *pi)
{
if (get_user(*uentry, head))
return -EFAULT;
@@ -62,7 +62,7 @@ void compat_exit_robust_list(struct task_struct *curr)
&head->list_op_pending, &pip))
return;
if (upending)
- handle_futex_death((void *)pending + futex_offset, curr, pip);
+ handle_futex_death((void __user *)pending + futex_offset, curr, pip);
while (compat_ptr(uentry) != &head->list) {
/*
@@ -70,7 +70,7 @@ void compat_exit_robust_list(struct task_struct *curr)
* dont process it twice:
*/
if (entry != pending)
- if (handle_futex_death((void *)entry + futex_offset,
+ if (handle_futex_death((void __user *)entry + futex_offset,
curr, pi))
return;
@@ -78,7 +78,7 @@ void compat_exit_robust_list(struct task_struct *curr)
* Fetch the next entry in the list:
*/
if (fetch_robust_entry(&uentry, &entry,
- (compat_uptr_t *)&entry->next, &pi))
+ (compat_uptr_t __user *)&entry->next, &pi))
return;
/*
* Avoid excessively long or circular lists:
@@ -103,10 +103,10 @@ compat_sys_set_robust_list(struct compat_robust_list_head __user *head,
}
asmlinkage long
-compat_sys_get_robust_list(int pid, compat_uptr_t *head_ptr,
+compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr,
compat_size_t __user *len_ptr)
{
- struct compat_robust_list_head *head;
+ struct compat_robust_list_head __user *head;
unsigned long ret;
if (!pid)
diff --git a/kernel/hrtimer.c b/kernel/hrtimer.c
index 21c38a7e666b..d0ba190dfeb6 100644
--- a/kernel/hrtimer.c
+++ b/kernel/hrtimer.c
@@ -693,7 +693,7 @@ static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mod
return t->task == NULL;
}
-static long __sched nanosleep_restart(struct restart_block *restart)
+long __sched hrtimer_nanosleep_restart(struct restart_block *restart)
{
struct hrtimer_sleeper t;
struct timespec __user *rmtp;
@@ -702,13 +702,13 @@ static long __sched nanosleep_restart(struct restart_block *restart)
restart->fn = do_no_restart_syscall;
- hrtimer_init(&t.timer, restart->arg3, HRTIMER_ABS);
- t.timer.expires.tv64 = ((u64)restart->arg1 << 32) | (u64) restart->arg0;
+ hrtimer_init(&t.timer, restart->arg0, HRTIMER_ABS);
+ t.timer.expires.tv64 = ((u64)restart->arg3 << 32) | (u64) restart->arg2;
if (do_nanosleep(&t, HRTIMER_ABS))
return 0;
- rmtp = (struct timespec __user *) restart->arg2;
+ rmtp = (struct timespec __user *) restart->arg1;
if (rmtp) {
time = ktime_sub(t.timer.expires, t.timer.base->get_time());
if (time.tv64 <= 0)
@@ -718,7 +718,7 @@ static long __sched nanosleep_restart(struct restart_block *restart)
return -EFAULT;
}
- restart->fn = nanosleep_restart;
+ restart->fn = hrtimer_nanosleep_restart;
/* The other values in restart are already filled in */
return -ERESTART_RESTARTBLOCK;
@@ -751,11 +751,11 @@ long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp,
}
restart = &current_thread_info()->restart_block;
- restart->fn = nanosleep_restart;
- restart->arg0 = t.timer.expires.tv64 & 0xFFFFFFFF;
- restart->arg1 = t.timer.expires.tv64 >> 32;
- restart->arg2 = (unsigned long) rmtp;
- restart->arg3 = (unsigned long) t.timer.base->index;
+ restart->fn = hrtimer_nanosleep_restart;
+ restart->arg0 = (unsigned long) t.timer.base->index;
+ restart->arg1 = (unsigned long) rmtp;
+ restart->arg2 = t.timer.expires.tv64 & 0xFFFFFFFF;
+ restart->arg3 = t.timer.expires.tv64 >> 32;
return -ERESTART_RESTARTBLOCK;
}
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index ac1f850d4937..2d0dc3efe813 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -18,6 +18,69 @@
#include "internals.h"
/**
+ * dynamic_irq_init - initialize a dynamically allocated irq
+ * @irq: irq number to initialize
+ */
+void dynamic_irq_init(unsigned int irq)
+{
+ struct irq_desc *desc;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS) {
+ printk(KERN_ERR "Trying to initialize invalid IRQ%d\n", irq);
+ WARN_ON(1);
+ return;
+ }
+
+ /* Ensure we don't have left over values from a previous use of this irq */
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock, flags);
+ desc->status = IRQ_DISABLED;
+ desc->chip = &no_irq_chip;
+ desc->handle_irq = handle_bad_irq;
+ desc->depth = 1;
+ desc->handler_data = NULL;
+ desc->chip_data = NULL;
+ desc->action = NULL;
+ desc->irq_count = 0;
+ desc->irqs_unhandled = 0;
+#ifdef CONFIG_SMP
+ desc->affinity = CPU_MASK_ALL;
+#endif
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+/**
+ * dynamic_irq_cleanup - cleanup a dynamically allocated irq
+ * @irq: irq number to initialize
+ */
+void dynamic_irq_cleanup(unsigned int irq)
+{
+ struct irq_desc *desc;
+ unsigned long flags;
+
+ if (irq >= NR_IRQS) {
+ printk(KERN_ERR "Trying to cleanup invalid IRQ%d\n", irq);
+ WARN_ON(1);
+ return;
+ }
+
+ desc = irq_desc + irq;
+ spin_lock_irqsave(&desc->lock, flags);
+ if (desc->action) {
+ spin_unlock_irqrestore(&desc->lock, flags);
+ printk(KERN_ERR "Destroying IRQ%d without calling free_irq\n",
+ irq);
+ WARN_ON(1);
+ return;
+ }
+ desc->handle_irq = handle_bad_irq;
+ desc->chip = &no_irq_chip;
+ spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+
+/**
* set_irq_chip - set the irq chip for an irq
* @irq: irq number
* @chip: pointer to irq chip description structure
@@ -40,10 +103,6 @@ int set_irq_chip(unsigned int irq, struct irq_chip *chip)
spin_lock_irqsave(&desc->lock, flags);
irq_chip_set_defaults(chip);
desc->chip = chip;
- /*
- * For compatibility only:
- */
- desc->chip = chip;
spin_unlock_irqrestore(&desc->lock, flags);
return 0;
@@ -146,7 +205,7 @@ static void default_disable(unsigned int irq)
struct irq_desc *desc = irq_desc + irq;
if (!(desc->status & IRQ_DELAYED_DISABLE))
- irq_desc[irq].chip->mask(irq);
+ desc->chip->mask(irq);
}
/*
@@ -190,7 +249,6 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
* handle_simple_irq - Simple and software-decoded IRQs.
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
- * @regs: pointer to a register structure
*
* Simple interrupts are either sent from a demultiplexing interrupt
* handler or come from hardware, where no interrupt hardware control
@@ -200,7 +258,7 @@ static inline void mask_ack_irq(struct irq_desc *desc, int irq)
* unmask issues if necessary.
*/
void fastcall
-handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+handle_simple_irq(unsigned int irq, struct irq_desc *desc)
{
struct irqaction *action;
irqreturn_t action_ret;
@@ -220,9 +278,9 @@ handle_simple_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
desc->status |= IRQ_INPROGRESS;
spin_unlock(&desc->lock);
- action_ret = handle_IRQ_event(irq, regs, action);
+ action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
+ note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
@@ -234,7 +292,6 @@ out_unlock:
* handle_level_irq - Level type irq handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
- * @regs: pointer to a register structure
*
* Level type interrupts are active as long as the hardware line has
* the active level. This may require to mask the interrupt and unmask
@@ -242,7 +299,7 @@ out_unlock:
* interrupt line is back to inactive.
*/
void fastcall
-handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+handle_level_irq(unsigned int irq, struct irq_desc *desc)
{
unsigned int cpu = smp_processor_id();
struct irqaction *action;
@@ -270,9 +327,9 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
desc->status &= ~IRQ_PENDING;
spin_unlock(&desc->lock);
- action_ret = handle_IRQ_event(irq, regs, action);
+ action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
+ note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
@@ -286,7 +343,6 @@ out_unlock:
* handle_fasteoi_irq - irq handler for transparent controllers
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
- * @regs: pointer to a register structure
*
* Only a single callback will be issued to the chip: an ->eoi()
* call when the interrupt has been serviced. This enables support
@@ -294,8 +350,7 @@ out_unlock:
* details in hardware, transparently.
*/
void fastcall
-handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
- struct pt_regs *regs)
+handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
{
unsigned int cpu = smp_processor_id();
struct irqaction *action;
@@ -323,9 +378,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc,
desc->status &= ~IRQ_PENDING;
spin_unlock(&desc->lock);
- action_ret = handle_IRQ_event(irq, regs, action);
+ action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
+ note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);
desc->status &= ~IRQ_INPROGRESS;
@@ -339,7 +394,6 @@ out:
* handle_edge_irq - edge type IRQ handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
- * @regs: pointer to a register structure
*
* Interrupt occures on the falling and/or rising edge of a hardware
* signal. The occurence is latched into the irq controller hardware
@@ -353,7 +407,7 @@ out:
* loop is left.
*/
void fastcall
-handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+handle_edge_irq(unsigned int irq, struct irq_desc *desc)
{
const unsigned int cpu = smp_processor_id();
@@ -404,9 +458,9 @@ handle_edge_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
desc->status &= ~IRQ_PENDING;
spin_unlock(&desc->lock);
- action_ret = handle_IRQ_event(irq, regs, action);
+ action_ret = handle_IRQ_event(irq, action);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
+ note_interrupt(irq, desc, action_ret);
spin_lock(&desc->lock);
} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
@@ -421,12 +475,11 @@ out_unlock:
* handle_percpu_IRQ - Per CPU local irq handler
* @irq: the interrupt number
* @desc: the interrupt description structure for this irq
- * @regs: pointer to a register structure
*
* Per CPU interrupts on SMP machines without locking requirements
*/
void fastcall
-handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+handle_percpu_irq(unsigned int irq, struct irq_desc *desc)
{
irqreturn_t action_ret;
@@ -435,9 +488,9 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
if (desc->chip->ack)
desc->chip->ack(irq);
- action_ret = handle_IRQ_event(irq, regs, desc->action);
+ action_ret = handle_IRQ_event(irq, desc->action);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
+ note_interrupt(irq, desc, action_ret);
if (desc->chip->eoi)
desc->chip->eoi(irq);
@@ -446,10 +499,8 @@ handle_percpu_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
#endif /* CONFIG_SMP */
void
-__set_irq_handler(unsigned int irq,
- void fastcall (*handle)(unsigned int, irq_desc_t *,
- struct pt_regs *),
- int is_chained)
+__set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
+ const char *name)
{
struct irq_desc *desc;
unsigned long flags;
@@ -490,6 +541,7 @@ __set_irq_handler(unsigned int irq,
desc->depth = 1;
}
desc->handle_irq = handle;
+ desc->name = name;
if (handle != handle_bad_irq && is_chained) {
desc->status &= ~IRQ_DISABLED;
@@ -502,36 +554,16 @@ __set_irq_handler(unsigned int irq,
void
set_irq_chip_and_handler(unsigned int irq, struct irq_chip *chip,
- void fastcall (*handle)(unsigned int,
- struct irq_desc *,
- struct pt_regs *))
+ irq_flow_handler_t handle)
{
set_irq_chip(irq, chip);
- __set_irq_handler(irq, handle, 0);
+ __set_irq_handler(irq, handle, 0, NULL);
}
-/*
- * Get a descriptive string for the highlevel handler, for
- * /proc/interrupts output:
- */
-const char *
-handle_irq_name(void fastcall (*handle)(unsigned int, struct irq_desc *,
- struct pt_regs *))
+void
+set_irq_chip_and_handler_name(unsigned int irq, struct irq_chip *chip,
+ irq_flow_handler_t handle, const char *name)
{
- if (handle == handle_level_irq)
- return "level ";
- if (handle == handle_fasteoi_irq)
- return "fasteoi";
- if (handle == handle_edge_irq)
- return "edge ";
- if (handle == handle_simple_irq)
- return "simple ";
-#ifdef CONFIG_SMP
- if (handle == handle_percpu_irq)
- return "percpu ";
-#endif
- if (handle == handle_bad_irq)
- return "bad ";
-
- return NULL;
+ set_irq_chip(irq, chip);
+ __set_irq_handler(irq, handle, 0, name);
}
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 4c6cdbaed661..42aa6f1a3f0f 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -27,7 +27,7 @@
* Handles spurious and unhandled IRQ's. It also prints a debugmessage.
*/
void fastcall
-handle_bad_irq(unsigned int irq, struct irq_desc *desc, struct pt_regs *regs)
+handle_bad_irq(unsigned int irq, struct irq_desc *desc)
{
print_irq_desc(irq, desc);
kstat_this_cpu.irqs[irq]++;
@@ -115,7 +115,7 @@ struct irq_chip dummy_irq_chip = {
/*
* Special, empty irq handler:
*/
-irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
+irqreturn_t no_action(int cpl, void *dev_id)
{
return IRQ_NONE;
}
@@ -123,13 +123,11 @@ irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
/**
* handle_IRQ_event - irq action chain handler
* @irq: the interrupt number
- * @regs: pointer to a register structure
* @action: the interrupt action chain for this irq
*
* Handles the action chain of an irq event
*/
-irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
- struct irqaction *action)
+irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action)
{
irqreturn_t ret, retval = IRQ_NONE;
unsigned int status = 0;
@@ -140,7 +138,7 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
local_irq_enable_in_hardirq();
do {
- ret = action->handler(irq, action->dev_id, regs);
+ ret = action->handler(irq, action->dev_id);
if (ret == IRQ_HANDLED)
status |= action->flags;
retval |= ret;
@@ -158,7 +156,6 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
/**
* __do_IRQ - original all in one highlevel IRQ handler
* @irq: the interrupt number
- * @regs: pointer to a register structure
*
* __do_IRQ handles all normal device IRQ's (the special
* SMP cross-CPU interrupts have their own specific
@@ -167,7 +164,7 @@ irqreturn_t handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
* This is the original x86 implementation which is used for every
* interrupt type.
*/
-fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
+fastcall unsigned int __do_IRQ(unsigned int irq)
{
struct irq_desc *desc = irq_desc + irq;
struct irqaction *action;
@@ -182,7 +179,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
*/
if (desc->chip->ack)
desc->chip->ack(irq);
- action_ret = handle_IRQ_event(irq, regs, desc->action);
+ action_ret = handle_IRQ_event(irq, desc->action);
desc->chip->end(irq);
return 1;
}
@@ -233,11 +230,11 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
spin_unlock(&desc->lock);
- action_ret = handle_IRQ_event(irq, regs, action);
+ action_ret = handle_IRQ_event(irq, action);
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret, regs);
+ note_interrupt(irq, desc, action_ret);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 92be519eff26..6879202afe9a 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -427,8 +427,7 @@ EXPORT_SYMBOL(free_irq);
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
*
*/
-int request_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
+int request_irq(unsigned int irq, irq_handler_t handler,
unsigned long irqflags, const char *devname, void *dev_id)
{
struct irqaction *action;
@@ -475,4 +474,3 @@ int request_irq(unsigned int irq,
return retval;
}
EXPORT_SYMBOL(request_irq);
-
diff --git a/kernel/irq/migration.c b/kernel/irq/migration.c
index a57ebe9fa6f6..4baa3bbcd25a 100644
--- a/kernel/irq/migration.c
+++ b/kernel/irq/migration.c
@@ -7,17 +7,17 @@ void set_pending_irq(unsigned int irq, cpumask_t mask)
unsigned long flags;
spin_lock_irqsave(&desc->lock, flags);
- desc->move_irq = 1;
+ desc->status |= IRQ_MOVE_PENDING;
irq_desc[irq].pending_mask = mask;
spin_unlock_irqrestore(&desc->lock, flags);
}
-void move_native_irq(int irq)
+void move_masked_irq(int irq)
{
struct irq_desc *desc = irq_desc + irq;
cpumask_t tmp;
- if (likely(!desc->move_irq))
+ if (likely(!(desc->status & IRQ_MOVE_PENDING)))
return;
/*
@@ -28,7 +28,7 @@ void move_native_irq(int irq)
return;
}
- desc->move_irq = 0;
+ desc->status &= ~IRQ_MOVE_PENDING;
if (unlikely(cpus_empty(irq_desc[irq].pending_mask)))
return;
@@ -48,15 +48,29 @@ void move_native_irq(int irq)
* when an active trigger is comming in. This could
* cause some ioapics to mal-function.
* Being paranoid i guess!
+ *
+ * For correct operation this depends on the caller
+ * masking the irqs.
*/
if (likely(!cpus_empty(tmp))) {
- if (likely(!(desc->status & IRQ_DISABLED)))
- desc->chip->disable(irq);
-
desc->chip->set_affinity(irq,tmp);
-
- if (likely(!(desc->status & IRQ_DISABLED)))
- desc->chip->enable(irq);
}
cpus_clear(irq_desc[irq].pending_mask);
}
+
+void move_native_irq(int irq)
+{
+ struct irq_desc *desc = irq_desc + irq;
+
+ if (likely(!(desc->status & IRQ_MOVE_PENDING)))
+ return;
+
+ if (likely(!(desc->status & IRQ_DISABLED)))
+ desc->chip->disable(irq);
+
+ move_masked_irq(irq);
+
+ if (likely(!(desc->status & IRQ_DISABLED)))
+ desc->chip->enable(irq);
+}
+
diff --git a/kernel/irq/proc.c b/kernel/irq/proc.c
index 607c7809ad01..9a352667007c 100644
--- a/kernel/irq/proc.c
+++ b/kernel/irq/proc.c
@@ -57,7 +57,7 @@ static int irq_affinity_write_proc(struct file *file, const char __user *buffer,
if (!irq_desc[irq].chip->set_affinity || no_irq_affinity)
return -EIO;
- err = cpumask_parse(buffer, count, new_value);
+ err = cpumask_parse_user(buffer, count, new_value);
if (err)
return err;
diff --git a/kernel/irq/resend.c b/kernel/irq/resend.c
index 35f10f7ff94a..5bfeaed7e487 100644
--- a/kernel/irq/resend.c
+++ b/kernel/irq/resend.c
@@ -38,7 +38,7 @@ static void resend_irqs(unsigned long arg)
clear_bit(irq, irqs_resend);
desc = irq_desc + irq;
local_irq_disable();
- desc->handle_irq(irq, desc, NULL);
+ desc->handle_irq(irq, desc);
local_irq_enable();
}
}
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 417e98092cf2..543ea2e5ad93 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -16,7 +16,7 @@ static int irqfixup __read_mostly;
/*
* Recovery handler for misrouted interrupts.
*/
-static int misrouted_irq(int irq, struct pt_regs *regs)
+static int misrouted_irq(int irq)
{
int i;
int ok = 0;
@@ -49,7 +49,7 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
while (action) {
/* Only shared IRQ handlers are safe to call */
if (action->flags & IRQF_SHARED) {
- if (action->handler(i, action->dev_id, regs) ==
+ if (action->handler(i, action->dev_id) ==
IRQ_HANDLED)
ok = 1;
}
@@ -70,7 +70,7 @@ static int misrouted_irq(int irq, struct pt_regs *regs)
*/
work = 1;
spin_unlock(&desc->lock);
- handle_IRQ_event(i, regs, action);
+ handle_IRQ_event(i, action);
spin_lock(&desc->lock);
desc->status &= ~IRQ_PENDING;
}
@@ -136,7 +136,7 @@ report_bad_irq(unsigned int irq, struct irq_desc *desc, irqreturn_t action_ret)
}
void note_interrupt(unsigned int irq, struct irq_desc *desc,
- irqreturn_t action_ret, struct pt_regs *regs)
+ irqreturn_t action_ret)
{
if (unlikely(action_ret != IRQ_HANDLED)) {
desc->irqs_unhandled++;
@@ -147,7 +147,7 @@ void note_interrupt(unsigned int irq, struct irq_desc *desc,
if (unlikely(irqfixup)) {
/* Don't punish working computers */
if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
- int ok = misrouted_irq(irq, regs);
+ int ok = misrouted_irq(irq);
if (action_ret == IRQ_NONE)
desc->irqs_unhandled -= ok;
}
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index ab16a5a4cfe9..eeac3e313b2b 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -69,6 +69,15 @@ static inline int is_kernel(unsigned long addr)
return in_gate_area_no_task(addr);
}
+static int is_ksym_addr(unsigned long addr)
+{
+ if (all_var)
+ return is_kernel(addr);
+
+ return is_kernel_text(addr) || is_kernel_inittext(addr) ||
+ is_kernel_extratext(addr);
+}
+
/* expand a compressed symbol data into the resulting uncompressed string,
given the offset to where the symbol is in the compressed stream */
static unsigned int kallsyms_expand_symbol(unsigned int off, char *result)
@@ -154,7 +163,73 @@ unsigned long kallsyms_lookup_name(const char *name)
}
return module_kallsyms_lookup_name(name);
}
-EXPORT_SYMBOL_GPL(kallsyms_lookup_name);
+
+static unsigned long get_symbol_pos(unsigned long addr,
+ unsigned long *symbolsize,
+ unsigned long *offset)
+{
+ unsigned long symbol_start = 0, symbol_end = 0;
+ unsigned long i, low, high, mid;
+
+ /* This kernel should never had been booted. */
+ BUG_ON(!kallsyms_addresses);
+
+ /* do a binary search on the sorted kallsyms_addresses array */
+ low = 0;
+ high = kallsyms_num_syms;
+
+ while (high - low > 1) {
+ mid = (low + high) / 2;
+ if (kallsyms_addresses[mid] <= addr)
+ low = mid;
+ else
+ high = mid;
+ }
+
+ /*
+ * search for the first aliased symbol. Aliased
+ * symbols are symbols with the same address
+ */
+ while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
+ --low;
+
+ symbol_start = kallsyms_addresses[low];
+
+ /* Search for next non-aliased symbol */
+ for (i = low + 1; i < kallsyms_num_syms; i++) {
+ if (kallsyms_addresses[i] > symbol_start) {
+ symbol_end = kallsyms_addresses[i];
+ break;
+ }
+ }
+
+ /* if we found no next symbol, we use the end of the section */
+ if (!symbol_end) {
+ if (is_kernel_inittext(addr))
+ symbol_end = (unsigned long)_einittext;
+ else if (all_var)
+ symbol_end = (unsigned long)_end;
+ else
+ symbol_end = (unsigned long)_etext;
+ }
+
+ *symbolsize = symbol_end - symbol_start;
+ *offset = addr - symbol_start;
+
+ return low;
+}
+
+/*
+ * Lookup an address but don't bother to find any names.
+ */
+int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
+ unsigned long *offset)
+{
+ if (is_ksym_addr(addr))
+ return !!get_symbol_pos(addr, symbolsize, offset);
+
+ return !!module_address_lookup(addr, symbolsize, offset, NULL);
+}
/*
* Lookup an address
@@ -168,57 +243,18 @@ const char *kallsyms_lookup(unsigned long addr,
unsigned long *offset,
char **modname, char *namebuf)
{
- unsigned long i, low, high, mid;
const char *msym;
- /* This kernel should never had been booted. */
- BUG_ON(!kallsyms_addresses);
-
namebuf[KSYM_NAME_LEN] = 0;
namebuf[0] = 0;
- if ((all_var && is_kernel(addr)) ||
- (!all_var && (is_kernel_text(addr) || is_kernel_inittext(addr) ||
- is_kernel_extratext(addr)))) {
- unsigned long symbol_end = 0;
-
- /* do a binary search on the sorted kallsyms_addresses array */
- low = 0;
- high = kallsyms_num_syms;
-
- while (high-low > 1) {
- mid = (low + high) / 2;
- if (kallsyms_addresses[mid] <= addr) low = mid;
- else high = mid;
- }
-
- /* search for the first aliased symbol. Aliased symbols are
- symbols with the same address */
- while (low && kallsyms_addresses[low - 1] == kallsyms_addresses[low])
- --low;
+ if (is_ksym_addr(addr)) {
+ unsigned long pos;
+ pos = get_symbol_pos(addr, symbolsize, offset);
/* Grab name */
- kallsyms_expand_symbol(get_symbol_offset(low), namebuf);
-
- /* Search for next non-aliased symbol */
- for (i = low + 1; i < kallsyms_num_syms; i++) {
- if (kallsyms_addresses[i] > kallsyms_addresses[low]) {
- symbol_end = kallsyms_addresses[i];
- break;
- }
- }
-
- /* if we found no next symbol, we use the end of the section */
- if (!symbol_end) {
- if (is_kernel_inittext(addr))
- symbol_end = (unsigned long)_einittext;
- else
- symbol_end = all_var ? (unsigned long)_end : (unsigned long)_etext;
- }
-
- *symbolsize = symbol_end - kallsyms_addresses[low];
+ kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
*modname = NULL;
- *offset = addr - kallsyms_addresses[low];
return namebuf;
}
diff --git a/kernel/kexec.c b/kernel/kexec.c
index 50087ecf337e..fcdd5d2bc3f4 100644
--- a/kernel/kexec.c
+++ b/kernel/kexec.c
@@ -40,7 +40,7 @@ struct resource crashk_res = {
int kexec_should_crash(struct task_struct *p)
{
- if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops)
+ if (in_interrupt() || !p->pid || is_init(p) || panic_on_oops)
return 1;
return 0;
}
@@ -995,7 +995,8 @@ asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
image = xchg(dest_image, image);
out:
- xchg(&kexec_lock, 0); /* Release the mutex */
+ locked = xchg(&kexec_lock, 0); /* Release the mutex */
+ BUG_ON(!locked);
kimage_free(image);
return result;
@@ -1061,7 +1062,8 @@ void crash_kexec(struct pt_regs *regs)
machine_crash_shutdown(&fixed_regs);
machine_kexec(kexec_crash_image);
}
- xchg(&kexec_lock, 0);
+ locked = xchg(&kexec_lock, 0);
+ BUG_ON(!locked);
}
}
diff --git a/kernel/kfifo.c b/kernel/kfifo.c
index 64ab045c3d9d..5d1d907378a2 100644
--- a/kernel/kfifo.c
+++ b/kernel/kfifo.c
@@ -122,6 +122,13 @@ unsigned int __kfifo_put(struct kfifo *fifo,
len = min(len, fifo->size - fifo->in + fifo->out);
+ /*
+ * Ensure that we sample the fifo->out index -before- we
+ * start putting bytes into the kfifo.
+ */
+
+ smp_mb();
+
/* first put the data starting from fifo->in to buffer end */
l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
@@ -129,6 +136,13 @@ unsigned int __kfifo_put(struct kfifo *fifo,
/* then put the rest (if any) at the beginning of the buffer */
memcpy(fifo->buffer, buffer + l, len - l);
+ /*
+ * Ensure that we add the bytes to the kfifo -before-
+ * we update the fifo->in index.
+ */
+
+ smp_wmb();
+
fifo->in += len;
return len;
@@ -154,6 +168,13 @@ unsigned int __kfifo_get(struct kfifo *fifo,
len = min(len, fifo->in - fifo->out);
+ /*
+ * Ensure that we sample the fifo->in index -before- we
+ * start removing bytes from the kfifo.
+ */
+
+ smp_rmb();
+
/* first get the data from fifo->out until the end of the buffer */
l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
@@ -161,6 +182,13 @@ unsigned int __kfifo_get(struct kfifo *fifo,
/* then get the rest (if any) from the beginning of the buffer */
memcpy(buffer + l, fifo->buffer, len - l);
+ /*
+ * Ensure that we remove the bytes from the kfifo -before-
+ * we update the fifo->out index.
+ */
+
+ smp_mb();
+
fifo->out += len;
return len;
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 5c470c57fb57..bb4e29d924e4 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -18,8 +18,6 @@
call_usermodehelper wait flag, and remove exec_usermodehelper.
Rusty Russell <rusty@rustcorp.com.au> Jan 2003
*/
-#define __KERNEL_SYSCALLS__
-
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
@@ -35,6 +33,7 @@
#include <linux/mount.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/resource.h>
#include <asm/uaccess.h>
extern int max_threads;
@@ -122,6 +121,7 @@ struct subprocess_info {
struct key *ring;
int wait;
int retval;
+ struct file *stdin;
};
/*
@@ -145,12 +145,30 @@ static int ____call_usermodehelper(void *data)
key_put(old_session);
+ /* Install input pipe when needed */
+ if (sub_info->stdin) {
+ struct files_struct *f = current->files;
+ struct fdtable *fdt;
+ /* no races because files should be private here */
+ sys_close(0);
+ fd_install(0, sub_info->stdin);
+ spin_lock(&f->file_lock);
+ fdt = files_fdtable(f);
+ FD_SET(0, fdt->open_fds);
+ FD_CLR(0, fdt->close_on_exec);
+ spin_unlock(&f->file_lock);
+
+ /* and disallow core files too */
+ current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0};
+ }
+
/* We can run anywhere, unlike our parent keventd(). */
set_cpus_allowed(current, CPU_MASK_ALL);
retval = -EPERM;
if (current->fs->root)
- retval = execve(sub_info->path, sub_info->argv,sub_info->envp);
+ retval = kernel_execve(sub_info->path,
+ sub_info->argv, sub_info->envp);
/* Exec failed? */
sub_info->retval = retval;
@@ -176,6 +194,8 @@ static int wait_for_helper(void *data)
if (pid < 0) {
sub_info->retval = pid;
} else {
+ int ret;
+
/*
* Normally it is bogus to call wait4() from in-kernel because
* wait4() wants to write the exit code to a userspace address.
@@ -185,7 +205,15 @@ static int wait_for_helper(void *data)
*
* Thus the __user pointer cast is valid here.
*/
- sys_wait4(pid, (int __user *) &sub_info->retval, 0, NULL);
+ sys_wait4(pid, (int __user *)&ret, 0, NULL);
+
+ /*
+ * If ret is 0, either ____call_usermodehelper failed and the
+ * real error code is already in sub_info->retval or
+ * sub_info->retval is 0 anyway, so don't mess with it then.
+ */
+ if (ret)
+ sub_info->retval = ret;
}
complete(sub_info->complete);
@@ -258,6 +286,44 @@ int call_usermodehelper_keys(char *path, char **argv, char **envp,
}
EXPORT_SYMBOL(call_usermodehelper_keys);
+int call_usermodehelper_pipe(char *path, char **argv, char **envp,
+ struct file **filp)
+{
+ DECLARE_COMPLETION(done);
+ struct subprocess_info sub_info = {
+ .complete = &done,
+ .path = path,
+ .argv = argv,
+ .envp = envp,
+ .retval = 0,
+ };
+ struct file *f;
+ DECLARE_WORK(work, __call_usermodehelper, &sub_info);
+
+ if (!khelper_wq)
+ return -EBUSY;
+
+ if (path[0] == '\0')
+ return 0;
+
+ f = create_write_pipe();
+ if (!f)
+ return -ENOMEM;
+ *filp = f;
+
+ f = create_read_pipe(f);
+ if (!f) {
+ free_write_pipe(*filp);
+ return -ENOMEM;
+ }
+ sub_info.stdin = f;
+
+ queue_work(khelper_wq, &work);
+ wait_for_completion(&done);
+ return sub_info.retval;
+}
+EXPORT_SYMBOL(call_usermodehelper_pipe);
+
void __init usermodehelper_init(void)
{
khelper_wq = create_singlethread_workqueue("khelper");
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 3f57dfdc8f92..610c837ad9e0 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleloader.h>
+#include <linux/kallsyms.h>
#include <asm-generic/sections.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
@@ -45,6 +46,16 @@
#define KPROBE_HASH_BITS 6
#define KPROBE_TABLE_SIZE (1 << KPROBE_HASH_BITS)
+
+/*
+ * Some oddball architectures like 64bit powerpc have function descriptors
+ * so this must be overridable.
+ */
+#ifndef kprobe_lookup_name
+#define kprobe_lookup_name(name, addr) \
+ addr = ((kprobe_opcode_t *)(kallsyms_lookup_name(name)))
+#endif
+
static struct hlist_head kprobe_table[KPROBE_TABLE_SIZE];
static struct hlist_head kretprobe_inst_table[KPROBE_TABLE_SIZE];
static atomic_t kprobe_count;
@@ -308,7 +319,8 @@ void __kprobes add_rp_inst(struct kretprobe_instance *ri)
}
/* Called with kretprobe_lock held */
-void __kprobes recycle_rp_inst(struct kretprobe_instance *ri)
+void __kprobes recycle_rp_inst(struct kretprobe_instance *ri,
+ struct hlist_head *head)
{
/* remove rp inst off the rprobe_inst_table */
hlist_del(&ri->hlist);
@@ -320,7 +332,7 @@ void __kprobes recycle_rp_inst(struct kretprobe_instance *ri)
hlist_add_head(&ri->uflist, &ri->rp->free_instances);
} else
/* Unregistering */
- kfree(ri);
+ hlist_add_head(&ri->hlist, head);
}
struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
@@ -336,18 +348,24 @@ struct hlist_head __kprobes *kretprobe_inst_table_head(struct task_struct *tsk)
*/
void __kprobes kprobe_flush_task(struct task_struct *tk)
{
- struct kretprobe_instance *ri;
- struct hlist_head *head;
+ struct kretprobe_instance *ri;
+ struct hlist_head *head, empty_rp;
struct hlist_node *node, *tmp;
unsigned long flags = 0;
+ INIT_HLIST_HEAD(&empty_rp);
spin_lock_irqsave(&kretprobe_lock, flags);
- head = kretprobe_inst_table_head(tk);
- hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
- if (ri->task == tk)
- recycle_rp_inst(ri);
- }
+ head = kretprobe_inst_table_head(tk);
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task == tk)
+ recycle_rp_inst(ri, &empty_rp);
+ }
spin_unlock_irqrestore(&kretprobe_lock, flags);
+
+ hlist_for_each_entry_safe(ri, node, tmp, &empty_rp, hlist) {
+ hlist_del(&ri->hlist);
+ kfree(ri);
+ }
}
static inline void free_rp_inst(struct kretprobe *rp)
@@ -447,6 +465,21 @@ static int __kprobes __register_kprobe(struct kprobe *p,
struct kprobe *old_p;
struct module *probed_mod;
+ /*
+ * If we have a symbol_name argument look it up,
+ * and add it to the address. That way the addr
+ * field can either be global or relative to a symbol.
+ */
+ if (p->symbol_name) {
+ if (p->addr)
+ return -EINVAL;
+ kprobe_lookup_name(p->symbol_name, p->addr);
+ }
+
+ if (!p->addr)
+ return -EINVAL;
+ p->addr = (kprobe_opcode_t *)(((char *)p->addr)+ p->offset);
+
if ((!kernel_text_address((unsigned long) p->addr)) ||
in_kprobes_functions((unsigned long) p->addr))
return -EINVAL;
@@ -488,7 +521,7 @@ static int __kprobes __register_kprobe(struct kprobe *p,
(ARCH_INACTIVE_KPROBE_COUNT + 1))
register_page_fault_notifier(&kprobe_page_fault_nb);
- arch_arm_kprobe(p);
+ arch_arm_kprobe(p);
out:
mutex_unlock(&kprobe_mutex);
diff --git a/kernel/latency.c b/kernel/latency.c
new file mode 100644
index 000000000000..258f2555abbc
--- /dev/null
+++ b/kernel/latency.c
@@ -0,0 +1,279 @@
+/*
+ * latency.c: Explicit system-wide latency-expectation infrastructure
+ *
+ * The purpose of this infrastructure is to allow device drivers to set
+ * latency constraint they have and to collect and summarize these
+ * expectations globally. The cummulated result can then be used by
+ * power management and similar users to make decisions that have
+ * tradoffs with a latency component.
+ *
+ * An example user of this are the x86 C-states; each higher C state saves
+ * more power, but has a higher exit latency. For the idle loop power
+ * code to make a good decision which C-state to use, information about
+ * acceptable latencies is required.
+ *
+ * An example announcer of latency is an audio driver that knowns it
+ * will get an interrupt when the hardware has 200 usec of samples
+ * left in the DMA buffer; in that case the driver can set a latency
+ * constraint of, say, 150 usec.
+ *
+ * Multiple drivers can each announce their maximum accepted latency,
+ * to keep these appart, a string based identifier is used.
+ *
+ *
+ * (C) Copyright 2006 Intel Corporation
+ * Author: Arjan van de Ven <arjan@linux.intel.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; version 2
+ * of the License.
+ */
+
+#include <linux/latency.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+
+struct latency_info {
+ struct list_head list;
+ int usecs;
+ char *identifier;
+};
+
+/*
+ * locking rule: all modifications to current_max_latency and
+ * latency_list need to be done while holding the latency_lock.
+ * latency_lock needs to be taken _irqsave.
+ */
+static atomic_t current_max_latency;
+static DEFINE_SPINLOCK(latency_lock);
+
+static LIST_HEAD(latency_list);
+static BLOCKING_NOTIFIER_HEAD(latency_notifier);
+
+/*
+ * This function returns the maximum latency allowed, which
+ * happens to be the minimum of all maximum latencies on the
+ * list.
+ */
+static int __find_max_latency(void)
+{
+ int min = INFINITE_LATENCY;
+ struct latency_info *info;
+
+ list_for_each_entry(info, &latency_list, list) {
+ if (info->usecs < min)
+ min = info->usecs;
+ }
+ return min;
+}
+
+/**
+ * set_acceptable_latency - sets the maximum latency acceptable
+ * @identifier: string that identifies this driver
+ * @usecs: maximum acceptable latency for this driver
+ *
+ * This function informs the kernel that this device(driver)
+ * can accept at most usecs latency. This setting is used for
+ * power management and similar tradeoffs.
+ *
+ * This function sleeps and can only be called from process
+ * context.
+ * Calling this function with an existing identifier is valid
+ * and will cause the existing latency setting to be changed.
+ */
+void set_acceptable_latency(char *identifier, int usecs)
+{
+ struct latency_info *info, *iter;
+ unsigned long flags;
+ int found_old = 0;
+
+ info = kzalloc(sizeof(struct latency_info), GFP_KERNEL);
+ if (!info)
+ return;
+ info->usecs = usecs;
+ info->identifier = kstrdup(identifier, GFP_KERNEL);
+ if (!info->identifier)
+ goto free_info;
+
+ spin_lock_irqsave(&latency_lock, flags);
+ list_for_each_entry(iter, &latency_list, list) {
+ if (strcmp(iter->identifier, identifier)==0) {
+ found_old = 1;
+ iter->usecs = usecs;
+ break;
+ }
+ }
+ if (!found_old)
+ list_add(&info->list, &latency_list);
+
+ if (usecs < atomic_read(&current_max_latency))
+ atomic_set(&current_max_latency, usecs);
+
+ spin_unlock_irqrestore(&latency_lock, flags);
+
+ blocking_notifier_call_chain(&latency_notifier,
+ atomic_read(&current_max_latency), NULL);
+
+ /*
+ * if we inserted the new one, we're done; otherwise there was
+ * an existing one so we need to free the redundant data
+ */
+ if (!found_old)
+ return;
+
+ kfree(info->identifier);
+free_info:
+ kfree(info);
+}
+EXPORT_SYMBOL_GPL(set_acceptable_latency);
+
+/**
+ * modify_acceptable_latency - changes the maximum latency acceptable
+ * @identifier: string that identifies this driver
+ * @usecs: maximum acceptable latency for this driver
+ *
+ * This function informs the kernel that this device(driver)
+ * can accept at most usecs latency. This setting is used for
+ * power management and similar tradeoffs.
+ *
+ * This function does not sleep and can be called in any context.
+ * Trying to use a non-existing identifier silently gets ignored.
+ *
+ * Due to the atomic nature of this function, the modified latency
+ * value will only be used for future decisions; past decisions
+ * can still lead to longer latencies in the near future.
+ */
+void modify_acceptable_latency(char *identifier, int usecs)
+{
+ struct latency_info *iter;
+ unsigned long flags;
+
+ spin_lock_irqsave(&latency_lock, flags);
+ list_for_each_entry(iter, &latency_list, list) {
+ if (strcmp(iter->identifier, identifier) == 0) {
+ iter->usecs = usecs;
+ break;
+ }
+ }
+ if (usecs < atomic_read(&current_max_latency))
+ atomic_set(&current_max_latency, usecs);
+ spin_unlock_irqrestore(&latency_lock, flags);
+}
+EXPORT_SYMBOL_GPL(modify_acceptable_latency);
+
+/**
+ * remove_acceptable_latency - removes the maximum latency acceptable
+ * @identifier: string that identifies this driver
+ *
+ * This function removes a previously set maximum latency setting
+ * for the driver and frees up any resources associated with the
+ * bookkeeping needed for this.
+ *
+ * This function does not sleep and can be called in any context.
+ * Trying to use a non-existing identifier silently gets ignored.
+ */
+void remove_acceptable_latency(char *identifier)
+{
+ unsigned long flags;
+ int newmax = 0;
+ struct latency_info *iter, *temp;
+
+ spin_lock_irqsave(&latency_lock, flags);
+
+ list_for_each_entry_safe(iter, temp, &latency_list, list) {
+ if (strcmp(iter->identifier, identifier) == 0) {
+ list_del(&iter->list);
+ newmax = iter->usecs;
+ kfree(iter->identifier);
+ kfree(iter);
+ break;
+ }
+ }
+
+ /* If we just deleted the system wide value, we need to
+ * recalculate with a full search
+ */
+ if (newmax == atomic_read(&current_max_latency)) {
+ newmax = __find_max_latency();
+ atomic_set(&current_max_latency, newmax);
+ }
+ spin_unlock_irqrestore(&latency_lock, flags);
+}
+EXPORT_SYMBOL_GPL(remove_acceptable_latency);
+
+/**
+ * system_latency_constraint - queries the system wide latency maximum
+ *
+ * This function returns the system wide maximum latency in
+ * microseconds.
+ *
+ * This function does not sleep and can be called in any context.
+ */
+int system_latency_constraint(void)
+{
+ return atomic_read(&current_max_latency);
+}
+EXPORT_SYMBOL_GPL(system_latency_constraint);
+
+/**
+ * synchronize_acceptable_latency - recalculates all latency decisions
+ *
+ * This function will cause a callback to various kernel pieces that
+ * will make those pieces rethink their latency decisions. This implies
+ * that if there are overlong latencies in hardware state already, those
+ * latencies get taken right now. When this call completes no overlong
+ * latency decisions should be active anymore.
+ *
+ * Typical usecase of this is after a modify_acceptable_latency() call,
+ * which in itself is non-blocking and non-synchronizing.
+ *
+ * This function blocks and should not be called with locks held.
+ */
+
+void synchronize_acceptable_latency(void)
+{
+ blocking_notifier_call_chain(&latency_notifier,
+ atomic_read(&current_max_latency), NULL);
+}
+EXPORT_SYMBOL_GPL(synchronize_acceptable_latency);
+
+/*
+ * Latency notifier: this notifier gets called when a non-atomic new
+ * latency value gets set. The expectation nof the caller of the
+ * non-atomic set is that when the call returns, future latencies
+ * are within bounds, so the functions on the notifier list are
+ * expected to take the overlong latencies immediately, inside the
+ * callback, and not make a overlong latency decision anymore.
+ *
+ * The callback gets called when the new latency value is made
+ * active so system_latency_constraint() returns the new latency.
+ */
+int register_latency_notifier(struct notifier_block * nb)
+{
+ return blocking_notifier_chain_register(&latency_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(register_latency_notifier);
+
+int unregister_latency_notifier(struct notifier_block * nb)
+{
+ return blocking_notifier_chain_unregister(&latency_notifier, nb);
+}
+EXPORT_SYMBOL_GPL(unregister_latency_notifier);
+
+static __init int latency_init(void)
+{
+ atomic_set(&current_max_latency, INFINITE_LATENCY);
+ /*
+ * we don't want by default to have longer latencies than 2 ticks,
+ * since that would cause lost ticks
+ */
+ set_acceptable_latency("kernel", 2*1000000/HZ);
+ return 0;
+}
+
+module_init(latency_init);
diff --git a/kernel/lockdep.c b/kernel/lockdep.c
index c088e5542e84..b739be2a6dc9 100644
--- a/kernel/lockdep.c
+++ b/kernel/lockdep.c
@@ -36,6 +36,7 @@
#include <linux/stacktrace.h>
#include <linux/debug_locks.h>
#include <linux/irqflags.h>
+#include <linux/utsname.h>
#include <asm/sections.h>
@@ -121,8 +122,8 @@ static struct list_head chainhash_table[CHAINHASH_SIZE];
* unique.
*/
#define iterate_chain_key(key1, key2) \
- (((key1) << MAX_LOCKDEP_KEYS_BITS/2) ^ \
- ((key1) >> (64-MAX_LOCKDEP_KEYS_BITS/2)) ^ \
+ (((key1) << MAX_LOCKDEP_KEYS_BITS) ^ \
+ ((key1) >> (64-MAX_LOCKDEP_KEYS_BITS)) ^ \
(key2))
void lockdep_off(void)
@@ -515,6 +516,13 @@ print_circular_bug_entry(struct lock_list *target, unsigned int depth)
return 0;
}
+static void print_kernel_version(void)
+{
+ printk("%s %.*s\n", init_utsname()->release,
+ (int)strcspn(init_utsname()->version, " "),
+ init_utsname()->version);
+}
+
/*
* When a circular dependency is detected, print the
* header first:
@@ -531,6 +539,7 @@ print_circular_bug_header(struct lock_list *entry, unsigned int depth)
printk("\n=======================================================\n");
printk( "[ INFO: possible circular locking dependency detected ]\n");
+ print_kernel_version();
printk( "-------------------------------------------------------\n");
printk("%s/%d is trying to acquire lock:\n",
curr->comm, curr->pid);
@@ -566,6 +575,8 @@ static noinline int print_circular_bug_tail(void)
return 0;
}
+#define RECURSION_LIMIT 40
+
static int noinline print_infinite_recursion_bug(void)
{
__raw_spin_unlock(&hash_lock);
@@ -586,7 +597,7 @@ check_noncircular(struct lock_class *source, unsigned int depth)
debug_atomic_inc(&nr_cyclic_check_recursions);
if (depth > max_recursion_depth)
max_recursion_depth = depth;
- if (depth >= 20)
+ if (depth >= RECURSION_LIMIT)
return print_infinite_recursion_bug();
/*
* Check this lock's dependency list:
@@ -636,7 +647,7 @@ find_usage_forwards(struct lock_class *source, unsigned int depth)
if (depth > max_recursion_depth)
max_recursion_depth = depth;
- if (depth >= 20)
+ if (depth >= RECURSION_LIMIT)
return print_infinite_recursion_bug();
debug_atomic_inc(&nr_find_usage_forwards_checks);
@@ -675,7 +686,7 @@ find_usage_backwards(struct lock_class *source, unsigned int depth)
if (depth > max_recursion_depth)
max_recursion_depth = depth;
- if (depth >= 20)
+ if (depth >= RECURSION_LIMIT)
return print_infinite_recursion_bug();
debug_atomic_inc(&nr_find_usage_backwards_checks);
@@ -712,6 +723,7 @@ print_bad_irq_dependency(struct task_struct *curr,
printk("\n======================================================\n");
printk( "[ INFO: %s-safe -> %s-unsafe lock order detected ]\n",
irqclass, irqclass);
+ print_kernel_version();
printk( "------------------------------------------------------\n");
printk("%s/%d [HC%u[%lu]:SC%u[%lu]:HE%u:SE%u] is trying to acquire:\n",
curr->comm, curr->pid,
@@ -793,6 +805,7 @@ print_deadlock_bug(struct task_struct *curr, struct held_lock *prev,
printk("\n=============================================\n");
printk( "[ INFO: possible recursive locking detected ]\n");
+ print_kernel_version();
printk( "---------------------------------------------\n");
printk("%s/%d is trying to acquire lock:\n",
curr->comm, curr->pid);
@@ -1103,8 +1116,6 @@ static int count_matching_names(struct lock_class *new_class)
return count + 1;
}
-extern void __error_too_big_MAX_LOCKDEP_SUBCLASSES(void);
-
/*
* Register a lock's class in the hash-table, if the class is not present
* yet. Otherwise we look it up. We cache the result in the lock object
@@ -1142,8 +1153,7 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
* (or spin_lock_init()) call - which acts as the key. For static
* locks we use the lock object itself as the key.
*/
- if (sizeof(struct lock_class_key) > sizeof(struct lock_class))
- __error_too_big_MAX_LOCKDEP_SUBCLASSES();
+ BUILD_BUG_ON(sizeof(struct lock_class_key) > sizeof(struct lock_class));
key = lock->key->subkeys + subclass;
@@ -1166,7 +1176,7 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
* itself, so actual lookup of the hash should be once per lock object.
*/
static inline struct lock_class *
-register_lock_class(struct lockdep_map *lock, unsigned int subclass)
+register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
{
struct lockdep_subclass_key *key;
struct list_head *hash_head;
@@ -1238,7 +1248,7 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass)
out_unlock_set:
__raw_spin_unlock(&hash_lock);
- if (!subclass)
+ if (!subclass || force)
lock->class_cache = class;
DEBUG_LOCKS_WARN_ON(class->subclass != subclass);
@@ -1375,6 +1385,7 @@ print_irq_inversion_bug(struct task_struct *curr, struct lock_class *other,
printk("\n=========================================================\n");
printk( "[ INFO: possible irq lock inversion dependency detected ]\n");
+ print_kernel_version();
printk( "---------------------------------------------------------\n");
printk("%s/%d just changed the state of lock:\n",
curr->comm, curr->pid);
@@ -1469,6 +1480,7 @@ print_usage_bug(struct task_struct *curr, struct held_lock *this,
printk("\n=================================\n");
printk( "[ INFO: inconsistent lock state ]\n");
+ print_kernel_version();
printk( "---------------------------------\n");
printk("inconsistent {%s} -> {%s} usage.\n",
@@ -1924,7 +1936,7 @@ void trace_softirqs_off(unsigned long ip)
* Initialize a lock instance's lock-class mapping info:
*/
void lockdep_init_map(struct lockdep_map *lock, const char *name,
- struct lock_class_key *key)
+ struct lock_class_key *key, int subclass)
{
if (unlikely(!debug_locks))
return;
@@ -1944,6 +1956,8 @@ void lockdep_init_map(struct lockdep_map *lock, const char *name,
lock->name = name;
lock->key = key;
lock->class_cache = NULL;
+ if (subclass)
+ register_lock_class(lock, subclass, 1);
}
EXPORT_SYMBOL_GPL(lockdep_init_map);
@@ -1982,7 +1996,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
* Not cached yet or subclass?
*/
if (unlikely(!class)) {
- class = register_lock_class(lock, subclass);
+ class = register_lock_class(lock, subclass, 0);
if (!class)
return 0;
}
diff --git a/kernel/module.c b/kernel/module.c
index b7fe6e840963..67009bd56c52 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -87,6 +87,12 @@ static inline int strong_try_module_get(struct module *mod)
return try_module_get(mod);
}
+static inline void add_taint_module(struct module *mod, unsigned flag)
+{
+ add_taint(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.
@@ -847,11 +853,10 @@ static int check_version(Elf_Shdr *sechdrs,
return 0;
}
/* Not in module's version table. OK, but that taints the kernel. */
- if (!(tainted & TAINT_FORCED_MODULE)) {
+ if (!(tainted & TAINT_FORCED_MODULE))
printk("%s: no version for \"%s\" found: kernel tainted.\n",
mod->name, symname);
- add_taint(TAINT_FORCED_MODULE);
- }
+ add_taint_module(mod, TAINT_FORCED_MODULE);
return 1;
}
@@ -909,7 +914,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
unsigned long ret;
const unsigned long *crc;
- ret = __find_symbol(name, &owner, &crc, mod->license_gplok);
+ ret = __find_symbol(name, &owner, &crc,
+ !(mod->taints & TAINT_PROPRIETARY_MODULE));
if (ret) {
/* use_module can fail due to OOM, or module unloading */
if (!check_version(sechdrs, versindex, name, mod, crc) ||
@@ -933,6 +939,15 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
return sprintf(buf, "0x%lx\n", sattr->address);
}
+static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
+{
+ int section;
+
+ for (section = 0; section < sect_attrs->nsections; section++)
+ kfree(sect_attrs->attrs[section].name);
+ kfree(sect_attrs);
+}
+
static void add_sect_attrs(struct module *mod, unsigned int nsect,
char *secstrings, Elf_Shdr *sechdrs)
{
@@ -949,21 +964,26 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
+ nloaded * sizeof(sect_attrs->attrs[0]),
sizeof(sect_attrs->grp.attrs[0]));
size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
- if (! (sect_attrs = kmalloc(size[0] + size[1], GFP_KERNEL)))
+ sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
+ if (sect_attrs == NULL)
return;
/* Setup section attributes. */
sect_attrs->grp.name = "sections";
sect_attrs->grp.attrs = (void *)sect_attrs + size[0];
+ sect_attrs->nsections = 0;
sattr = &sect_attrs->attrs[0];
gattr = &sect_attrs->grp.attrs[0];
for (i = 0; i < nsect; i++) {
if (! (sechdrs[i].sh_flags & SHF_ALLOC))
continue;
sattr->address = sechdrs[i].sh_addr;
- strlcpy(sattr->name, secstrings + sechdrs[i].sh_name,
- MODULE_SECT_NAME_LEN);
+ sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
+ GFP_KERNEL);
+ if (sattr->name == NULL)
+ goto out;
+ sect_attrs->nsections++;
sattr->mattr.show = module_sect_show;
sattr->mattr.store = NULL;
sattr->mattr.attr.name = sattr->name;
@@ -979,7 +999,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
mod->sect_attrs = sect_attrs;
return;
out:
- kfree(sect_attrs);
+ free_sect_attrs(sect_attrs);
}
static void remove_sect_attrs(struct module *mod)
@@ -989,13 +1009,13 @@ static void remove_sect_attrs(struct module *mod)
&mod->sect_attrs->grp);
/* We are positive that no one is using any sect attrs
* at this point. Deallocate immediately. */
- kfree(mod->sect_attrs);
+ free_sect_attrs(mod->sect_attrs);
mod->sect_attrs = NULL;
}
}
-
#else
+
static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
char *sectstrings, Elf_Shdr *sechdrs)
{
@@ -1320,11 +1340,11 @@ static void set_license(struct module *mod, const char *license)
if (!license)
license = "unspecified";
- mod->license_gplok = license_is_gpl_compatible(license);
- if (!mod->license_gplok && !(tainted & TAINT_PROPRIETARY_MODULE)) {
- printk(KERN_WARNING "%s: module license '%s' taints kernel.\n",
- mod->name, license);
- add_taint(TAINT_PROPRIETARY_MODULE);
+ if (!license_is_gpl_compatible(license)) {
+ if (!(tainted & TAINT_PROPRIETARY_MODULE))
+ printk(KERN_WARNING "%s: module license '%s' taints"
+ "kernel.\n", mod->name, license);
+ add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
}
}
@@ -1603,7 +1623,7 @@ static struct module *load_module(void __user *umod,
modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
/* This is allowed: modprobe --force will invalidate it. */
if (!modmagic) {
- add_taint(TAINT_FORCED_MODULE);
+ add_taint_module(mod, TAINT_FORCED_MODULE);
printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
mod->name);
} else if (!same_magic(modmagic, vermagic)) {
@@ -1698,9 +1718,9 @@ static struct module *load_module(void __user *umod,
set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
if (strcmp(mod->name, "ndiswrapper") == 0)
- add_taint(TAINT_PROPRIETARY_MODULE);
+ add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
if (strcmp(mod->name, "driverloader") == 0)
- add_taint(TAINT_PROPRIETARY_MODULE);
+ add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
/* Set up MODINFO_ATTR fields */
setup_modinfo(mod, sechdrs, infoindex);
@@ -1745,7 +1765,7 @@ static struct module *load_module(void __user *umod,
(mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
printk(KERN_WARNING "%s: No versions for exported symbols."
" Tainting kernel.\n", mod->name);
- add_taint(TAINT_FORCED_MODULE);
+ add_taint_module(mod, TAINT_FORCED_MODULE);
}
#endif
@@ -2018,7 +2038,8 @@ const char *module_address_lookup(unsigned long addr,
list_for_each_entry(mod, &modules, list) {
if (within(addr, mod->module_init, mod->init_size)
|| within(addr, mod->module_core, mod->core_size)) {
- *modname = mod->name;
+ if (modname)
+ *modname = mod->name;
return get_ksymbol(mod, addr, size, offset);
}
}
@@ -2109,9 +2130,33 @@ static void m_stop(struct seq_file *m, void *p)
mutex_unlock(&module_mutex);
}
+static char *taint_flags(unsigned int taints, char *buf)
+{
+ int bx = 0;
+
+ if (taints) {
+ buf[bx++] = '(';
+ if (taints & TAINT_PROPRIETARY_MODULE)
+ buf[bx++] = 'P';
+ if (taints & TAINT_FORCED_MODULE)
+ buf[bx++] = 'F';
+ /*
+ * TAINT_FORCED_RMMOD: could be added.
+ * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
+ * apply to modules.
+ */
+ buf[bx++] = ')';
+ }
+ buf[bx] = '\0';
+
+ return buf;
+}
+
static int m_show(struct seq_file *m, void *p)
{
struct module *mod = list_entry(p, struct module, list);
+ char buf[8];
+
seq_printf(m, "%s %lu",
mod->name, mod->init_size + mod->core_size);
print_unload_info(m, mod);
@@ -2124,6 +2169,10 @@ static int m_show(struct seq_file *m, void *p)
/* Used by oprofile and other similar tools. */
seq_printf(m, " 0x%p", mod->module_core);
+ /* Taints info */
+ if (mod->taints)
+ seq_printf(m, " %s", taint_flags(mod->taints, buf));
+
seq_printf(m, "\n");
return 0;
}
@@ -2216,10 +2265,11 @@ struct module *module_text_address(unsigned long addr)
void print_modules(void)
{
struct module *mod;
+ char buf[8];
printk("Modules linked in:");
list_for_each_entry(mod, &modules, list)
- printk(" %s", mod->name);
+ printk(" %s%s", mod->name, taint_flags(mod->taints, buf));
printk("\n");
}
diff --git a/kernel/mutex-debug.c b/kernel/mutex-debug.c
index e3203c654dda..18651641a7b5 100644
--- a/kernel/mutex-debug.c
+++ b/kernel/mutex-debug.c
@@ -91,7 +91,7 @@ void debug_mutex_init(struct mutex *lock, const char *name,
* Make sure we are not reinitializing a held lock:
*/
debug_check_no_locks_freed((void *)lock, sizeof(*lock));
- lockdep_init_map(&lock->dep_map, name, key);
+ lockdep_init_map(&lock->dep_map, name, key, 0);
#endif
lock->owner = NULL;
lock->magic = lock;
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
new file mode 100644
index 000000000000..674aceb7335a
--- /dev/null
+++ b/kernel/nsproxy.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2006 IBM Corporation
+ *
+ * Author: Serge Hallyn <serue@us.ibm.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, version 2 of the
+ * License.
+ *
+ * Jun 2006 - namespaces support
+ * OpenVZ, SWsoft Inc.
+ * Pavel Emelianov <xemul@openvz.org>
+ */
+
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/nsproxy.h>
+#include <linux/init_task.h>
+#include <linux/namespace.h>
+#include <linux/utsname.h>
+
+struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
+
+static inline void get_nsproxy(struct nsproxy *ns)
+{
+ atomic_inc(&ns->count);
+}
+
+void get_task_namespaces(struct task_struct *tsk)
+{
+ struct nsproxy *ns = tsk->nsproxy;
+ if (ns) {
+ get_nsproxy(ns);
+ }
+}
+
+/*
+ * creates a copy of "orig" with refcount 1.
+ * This does not grab references to the contained namespaces,
+ * so that needs to be done by dup_namespaces.
+ */
+static inline struct nsproxy *clone_namespaces(struct nsproxy *orig)
+{
+ struct nsproxy *ns;
+
+ ns = kmemdup(orig, sizeof(struct nsproxy), GFP_KERNEL);
+ if (ns)
+ atomic_set(&ns->count, 1);
+ return ns;
+}
+
+/*
+ * copies the nsproxy, setting refcount to 1, and grabbing a
+ * reference to all contained namespaces. Called from
+ * sys_unshare()
+ */
+struct nsproxy *dup_namespaces(struct nsproxy *orig)
+{
+ struct nsproxy *ns = clone_namespaces(orig);
+
+ if (ns) {
+ if (ns->namespace)
+ get_namespace(ns->namespace);
+ if (ns->uts_ns)
+ get_uts_ns(ns->uts_ns);
+ if (ns->ipc_ns)
+ get_ipc_ns(ns->ipc_ns);
+ }
+
+ return ns;
+}
+
+/*
+ * called from clone. This now handles copy for nsproxy and all
+ * namespaces therein.
+ */
+int copy_namespaces(int flags, struct task_struct *tsk)
+{
+ struct nsproxy *old_ns = tsk->nsproxy;
+ struct nsproxy *new_ns;
+ int err = 0;
+
+ if (!old_ns)
+ return 0;
+
+ get_nsproxy(old_ns);
+
+ if (!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC)))
+ return 0;
+
+ new_ns = clone_namespaces(old_ns);
+ if (!new_ns) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ tsk->nsproxy = new_ns;
+
+ err = copy_namespace(flags, tsk);
+ if (err)
+ goto out_ns;
+
+ err = copy_utsname(flags, tsk);
+ if (err)
+ goto out_uts;
+
+ err = copy_ipcs(flags, tsk);
+ if (err)
+ goto out_ipc;
+
+out:
+ put_nsproxy(old_ns);
+ return err;
+
+out_ipc:
+ if (new_ns->uts_ns)
+ put_uts_ns(new_ns->uts_ns);
+out_uts:
+ if (new_ns->namespace)
+ put_namespace(new_ns->namespace);
+out_ns:
+ tsk->nsproxy = old_ns;
+ kfree(new_ns);
+ goto out;
+}
+
+void free_nsproxy(struct nsproxy *ns)
+{
+ if (ns->namespace)
+ put_namespace(ns->namespace);
+ if (ns->uts_ns)
+ put_uts_ns(ns->uts_ns);
+ if (ns->ipc_ns)
+ put_ipc_ns(ns->ipc_ns);
+ kfree(ns);
+}
diff --git a/kernel/panic.c b/kernel/panic.c
index 6ceb664fb52a..525e365f7239 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -21,7 +21,6 @@
#include <linux/debug_locks.h>
int panic_on_oops;
-int panic_on_unrecovered_nmi;
int tainted;
static int pause_on_oops;
static int pause_on_oops_flag;
diff --git a/kernel/params.c b/kernel/params.c
index 91aea7aa532e..f406655d6653 100644
--- a/kernel/params.c
+++ b/kernel/params.c
@@ -547,6 +547,7 @@ static void __init kernel_param_sysfs_setup(const char *name,
unsigned int name_skip)
{
struct module_kobject *mk;
+ int ret;
mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL);
BUG_ON(!mk);
@@ -554,7 +555,8 @@ static void __init kernel_param_sysfs_setup(const char *name,
mk->mod = THIS_MODULE;
kobj_set_kset_s(mk, module_subsys);
kobject_set_name(&mk->kobj, name);
- kobject_register(&mk->kobj);
+ ret = kobject_register(&mk->kobj);
+ BUG_ON(ret < 0);
/* no need to keep the kobject if no parameter is exported */
if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) {
@@ -684,13 +686,20 @@ decl_subsys(module, &module_ktype, NULL);
*/
static int __init param_sysfs_init(void)
{
- subsystem_register(&module_subsys);
+ int ret;
+
+ ret = subsystem_register(&module_subsys);
+ if (ret < 0) {
+ printk(KERN_WARNING "%s (%d): subsystem_register error: %d\n",
+ __FILE__, __LINE__, ret);
+ return ret;
+ }
param_sysfs_builtin();
return 0;
}
-__initcall(param_sysfs_init);
+subsys_initcall(param_sysfs_init);
EXPORT_SYMBOL(param_set_byte);
EXPORT_SYMBOL(param_get_byte);
diff --git a/kernel/pid.c b/kernel/pid.c
index 93e212f20671..b914392085f9 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -26,6 +26,7 @@
#include <linux/init.h>
#include <linux/bootmem.h>
#include <linux/hash.h>
+#include <linux/pspace.h>
#define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift)
static struct hlist_head *pid_hash;
@@ -33,17 +34,20 @@ static int pidhash_shift;
static kmem_cache_t *pid_cachep;
int pid_max = PID_MAX_DEFAULT;
-int last_pid;
#define RESERVED_PIDS 300
int pid_max_min = RESERVED_PIDS + 1;
int pid_max_max = PID_MAX_LIMIT;
-#define PIDMAP_ENTRIES ((PID_MAX_LIMIT + 8*PAGE_SIZE - 1)/PAGE_SIZE/8)
#define BITS_PER_PAGE (PAGE_SIZE*8)
#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1)
-#define mk_pid(map, off) (((map) - pidmap_array)*BITS_PER_PAGE + (off))
+
+static inline int mk_pid(struct pspace *pspace, struct pidmap *map, int off)
+{
+ return (map - pspace->pidmap)*BITS_PER_PAGE + off;
+}
+
#define find_next_offset(map, off) \
find_next_zero_bit((map)->page, BITS_PER_PAGE, off)
@@ -53,13 +57,12 @@ int pid_max_max = PID_MAX_LIMIT;
* value does not cause lots of bitmaps to be allocated, but
* the scheme scales to up to 4 million PIDs, runtime.
*/
-typedef struct pidmap {
- atomic_t nr_free;
- void *page;
-} pidmap_t;
-
-static pidmap_t pidmap_array[PIDMAP_ENTRIES] =
- { [ 0 ... PIDMAP_ENTRIES-1 ] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } };
+struct pspace init_pspace = {
+ .pidmap = {
+ [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL }
+ },
+ .last_pid = 0
+};
/*
* Note: disable interrupts while the pidmap_lock is held as an
@@ -74,40 +77,41 @@ static pidmap_t pidmap_array[PIDMAP_ENTRIES] =
* irq handlers that take it we can leave the interrupts enabled.
* For now it is easier to be safe than to prove it can't happen.
*/
+
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock);
-static fastcall void free_pidmap(int pid)
+static fastcall void free_pidmap(struct pspace *pspace, int pid)
{
- pidmap_t *map = pidmap_array + pid / BITS_PER_PAGE;
+ struct pidmap *map = pspace->pidmap + pid / BITS_PER_PAGE;
int offset = pid & BITS_PER_PAGE_MASK;
clear_bit(offset, map->page);
atomic_inc(&map->nr_free);
}
-static int alloc_pidmap(void)
+static int alloc_pidmap(struct pspace *pspace)
{
- int i, offset, max_scan, pid, last = last_pid;
- pidmap_t *map;
+ int i, offset, max_scan, pid, last = pspace->last_pid;
+ struct pidmap *map;
pid = last + 1;
if (pid >= pid_max)
pid = RESERVED_PIDS;
offset = pid & BITS_PER_PAGE_MASK;
- map = &pidmap_array[pid/BITS_PER_PAGE];
+ map = &pspace->pidmap[pid/BITS_PER_PAGE];
max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset;
for (i = 0; i <= max_scan; ++i) {
if (unlikely(!map->page)) {
- unsigned long page = get_zeroed_page(GFP_KERNEL);
+ void *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
/*
* Free the page if someone raced with us
* installing it:
*/
spin_lock_irq(&pidmap_lock);
if (map->page)
- free_page(page);
+ kfree(page);
else
- map->page = (void *)page;
+ map->page = page;
spin_unlock_irq(&pidmap_lock);
if (unlikely(!map->page))
break;
@@ -116,11 +120,11 @@ static int alloc_pidmap(void)
do {
if (!test_and_set_bit(offset, map->page)) {
atomic_dec(&map->nr_free);
- last_pid = pid;
+ pspace->last_pid = pid;
return pid;
}
offset = find_next_offset(map, offset);
- pid = mk_pid(map, offset);
+ pid = mk_pid(pspace, map, offset);
/*
* find_next_offset() found a bit, the pid from it
* is in-bounds, and if we fell back to the last
@@ -131,16 +135,34 @@ static int alloc_pidmap(void)
(i != max_scan || pid < last ||
!((last+1) & BITS_PER_PAGE_MASK)));
}
- if (map < &pidmap_array[(pid_max-1)/BITS_PER_PAGE]) {
+ if (map < &pspace->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
++map;
offset = 0;
} else {
- map = &pidmap_array[0];
+ map = &pspace->pidmap[0];
offset = RESERVED_PIDS;
if (unlikely(last == offset))
break;
}
- pid = mk_pid(map, offset);
+ pid = mk_pid(pspace, map, offset);
+ }
+ return -1;
+}
+
+static int next_pidmap(struct pspace *pspace, int last)
+{
+ int offset;
+ struct pidmap *map, *end;
+
+ offset = (last + 1) & BITS_PER_PAGE_MASK;
+ map = &pspace->pidmap[(last + 1)/BITS_PER_PAGE];
+ end = &pspace->pidmap[PIDMAP_ENTRIES];
+ for (; map < end; map++, offset = 0) {
+ if (unlikely(!map->page))
+ continue;
+ offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);
+ if (offset < BITS_PER_PAGE)
+ return mk_pid(pspace, map, offset);
}
return -1;
}
@@ -153,6 +175,7 @@ fastcall void put_pid(struct pid *pid)
atomic_dec_and_test(&pid->count))
kmem_cache_free(pid_cachep, pid);
}
+EXPORT_SYMBOL_GPL(put_pid);
static void delayed_put_pid(struct rcu_head *rhp)
{
@@ -169,7 +192,7 @@ fastcall void free_pid(struct pid *pid)
hlist_del_rcu(&pid->pid_chain);
spin_unlock_irqrestore(&pidmap_lock, flags);
- free_pidmap(pid->nr);
+ free_pidmap(&init_pspace, pid->nr);
call_rcu(&pid->rcu, delayed_put_pid);
}
@@ -183,7 +206,7 @@ struct pid *alloc_pid(void)
if (!pid)
goto out;
- nr = alloc_pidmap();
+ nr = alloc_pidmap(&init_pspace);
if (nr < 0)
goto out_free;
@@ -217,15 +240,13 @@ struct pid * fastcall find_pid(int nr)
}
return NULL;
}
+EXPORT_SYMBOL_GPL(find_pid);
int fastcall attach_pid(struct task_struct *task, enum pid_type type, int nr)
{
struct pid_link *link;
struct pid *pid;
- WARN_ON(!task->pid); /* to be removed soon */
- WARN_ON(!nr); /* to be removed soon */
-
link = &task->pids[type];
link->pid = pid = find_pid(nr);
hlist_add_head_rcu(&link->node, &pid->tasks[type]);
@@ -252,6 +273,15 @@ void fastcall detach_pid(struct task_struct *task, enum pid_type type)
free_pid(pid);
}
+/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */
+void fastcall transfer_pid(struct task_struct *old, struct task_struct *new,
+ enum pid_type type)
+{
+ new->pids[type].pid = old->pids[type].pid;
+ hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node);
+ old->pids[type].pid = NULL;
+}
+
struct task_struct * fastcall pid_task(struct pid *pid, enum pid_type type)
{
struct task_struct *result = NULL;
@@ -274,6 +304,15 @@ struct task_struct *find_task_by_pid_type(int type, int nr)
EXPORT_SYMBOL(find_task_by_pid_type);
+struct pid *get_task_pid(struct task_struct *task, enum pid_type type)
+{
+ struct pid *pid;
+ rcu_read_lock();
+ pid = get_pid(task->pids[type].pid);
+ rcu_read_unlock();
+ return pid;
+}
+
struct task_struct *fastcall get_pid_task(struct pid *pid, enum pid_type type)
{
struct task_struct *result;
@@ -297,6 +336,26 @@ struct pid *find_get_pid(pid_t nr)
}
/*
+ * Used by proc to find the first pid that is greater then or equal to nr.
+ *
+ * If there is a pid at nr this function is exactly the same as find_pid.
+ */
+struct pid *find_ge_pid(int nr)
+{
+ struct pid *pid;
+
+ do {
+ pid = find_pid(nr);
+ if (pid)
+ break;
+ nr = next_pidmap(&init_pspace, nr);
+ } while (nr > 0);
+
+ return pid;
+}
+EXPORT_SYMBOL_GPL(find_get_pid);
+
+/*
* The pid hash table is scaled according to the amount of memory in the
* machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or
* more.
@@ -323,10 +382,10 @@ void __init pidhash_init(void)
void __init pidmap_init(void)
{
- pidmap_array->page = (void *)get_zeroed_page(GFP_KERNEL);
+ init_pspace.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL);
/* Reserve PID 0. We never call free_pidmap(0) */
- set_bit(0, pidmap_array->page);
- atomic_dec(&pidmap_array->nr_free);
+ set_bit(0, init_pspace.pidmap[0].page);
+ atomic_dec(&init_pspace.pidmap[0].nr_free);
pid_cachep = kmem_cache_create("pid", sizeof(struct pid),
__alignof__(struct pid),
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index d38d9ec3276c..7c3e1e6dfb5b 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -88,6 +88,19 @@ static inline union cpu_time_count cpu_time_sub(const clockid_t which_clock,
}
/*
+ * Divide and limit the result to res >= 1
+ *
+ * This is necessary to prevent signal delivery starvation, when the result of
+ * the division would be rounded down to 0.
+ */
+static inline cputime_t cputime_div_non_zero(cputime_t time, unsigned long div)
+{
+ cputime_t res = cputime_div(time, div);
+
+ return max_t(cputime_t, res, 1);
+}
+
+/*
* Update expiry time from increment, and increase overrun count,
* given the current clock sample.
*/
@@ -483,8 +496,8 @@ static void process_timer_rebalance(struct task_struct *p,
BUG();
break;
case CPUCLOCK_PROF:
- left = cputime_div(cputime_sub(expires.cpu, val.cpu),
- nthreads);
+ left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu),
+ nthreads);
do {
if (likely(!(t->flags & PF_EXITING))) {
ticks = cputime_add(prof_ticks(t), left);
@@ -498,8 +511,8 @@ static void process_timer_rebalance(struct task_struct *p,
} while (t != p);
break;
case CPUCLOCK_VIRT:
- left = cputime_div(cputime_sub(expires.cpu, val.cpu),
- nthreads);
+ left = cputime_div_non_zero(cputime_sub(expires.cpu, val.cpu),
+ nthreads);
do {
if (likely(!(t->flags & PF_EXITING))) {
ticks = cputime_add(virt_ticks(t), left);
@@ -515,6 +528,7 @@ static void process_timer_rebalance(struct task_struct *p,
case CPUCLOCK_SCHED:
nsleft = expires.sched - val.sched;
do_div(nsleft, nthreads);
+ nsleft = max_t(unsigned long long, nsleft, 1);
do {
if (likely(!(t->flags & PF_EXITING))) {
ns = t->sched_time + nsleft;
@@ -1159,12 +1173,13 @@ static void check_process_timers(struct task_struct *tsk,
prof_left = cputime_sub(prof_expires, utime);
prof_left = cputime_sub(prof_left, stime);
- prof_left = cputime_div(prof_left, nthreads);
+ prof_left = cputime_div_non_zero(prof_left, nthreads);
virt_left = cputime_sub(virt_expires, utime);
- virt_left = cputime_div(virt_left, nthreads);
+ virt_left = cputime_div_non_zero(virt_left, nthreads);
if (sched_expires) {
sched_left = sched_expires - sched_time;
do_div(sched_left, nthreads);
+ sched_left = max_t(unsigned long long, sched_left, 1);
} else {
sched_left = 0;
}
@@ -1393,25 +1408,13 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,
}
}
-static long posix_cpu_clock_nanosleep_restart(struct restart_block *);
-
-int posix_cpu_nsleep(const clockid_t which_clock, int flags,
- struct timespec *rqtp, struct timespec __user *rmtp)
+static int do_cpu_nanosleep(const clockid_t which_clock, int flags,
+ struct timespec *rqtp, struct itimerspec *it)
{
- struct restart_block *restart_block =
- &current_thread_info()->restart_block;
struct k_itimer timer;
int error;
/*
- * Diagnose required errors first.
- */
- if (CPUCLOCK_PERTHREAD(which_clock) &&
- (CPUCLOCK_PID(which_clock) == 0 ||
- CPUCLOCK_PID(which_clock) == current->pid))
- return -EINVAL;
-
- /*
* Set up a temporary timer and then wait for it to go off.
*/
memset(&timer, 0, sizeof timer);
@@ -1422,11 +1425,12 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
timer.it_process = current;
if (!error) {
static struct itimerspec zero_it;
- struct itimerspec it = { .it_value = *rqtp,
- .it_interval = {} };
+
+ memset(it, 0, sizeof *it);
+ it->it_value = *rqtp;
spin_lock_irq(&timer.it_lock);
- error = posix_cpu_timer_set(&timer, flags, &it, NULL);
+ error = posix_cpu_timer_set(&timer, flags, it, NULL);
if (error) {
spin_unlock_irq(&timer.it_lock);
return error;
@@ -1454,49 +1458,89 @@ int posix_cpu_nsleep(const clockid_t which_clock, int flags,
* We were interrupted by a signal.
*/
sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp);
- posix_cpu_timer_set(&timer, 0, &zero_it, &it);
+ posix_cpu_timer_set(&timer, 0, &zero_it, it);
spin_unlock_irq(&timer.it_lock);
- if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {
+ if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) {
/*
* It actually did fire already.
*/
return 0;
}
+ error = -ERESTART_RESTARTBLOCK;
+ }
+
+ return error;
+}
+
+int posix_cpu_nsleep(const clockid_t which_clock, int flags,
+ struct timespec *rqtp, struct timespec __user *rmtp)
+{
+ struct restart_block *restart_block =
+ &current_thread_info()->restart_block;
+ struct itimerspec it;
+ int error;
+
+ /*
+ * Diagnose required errors first.
+ */
+ if (CPUCLOCK_PERTHREAD(which_clock) &&
+ (CPUCLOCK_PID(which_clock) == 0 ||
+ CPUCLOCK_PID(which_clock) == current->pid))
+ return -EINVAL;
+
+ error = do_cpu_nanosleep(which_clock, flags, rqtp, &it);
+
+ if (error == -ERESTART_RESTARTBLOCK) {
+
+ if (flags & TIMER_ABSTIME)
+ return -ERESTARTNOHAND;
/*
- * Report back to the user the time still remaining.
- */
- if (rmtp != NULL && !(flags & TIMER_ABSTIME) &&
- copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+ * Report back to the user the time still remaining.
+ */
+ if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
return -EFAULT;
- restart_block->fn = posix_cpu_clock_nanosleep_restart;
- /* Caller already set restart_block->arg1 */
+ restart_block->fn = posix_cpu_nsleep_restart;
restart_block->arg0 = which_clock;
restart_block->arg1 = (unsigned long) rmtp;
restart_block->arg2 = rqtp->tv_sec;
restart_block->arg3 = rqtp->tv_nsec;
-
- error = -ERESTART_RESTARTBLOCK;
}
-
return error;
}
-static long
-posix_cpu_clock_nanosleep_restart(struct restart_block *restart_block)
+long posix_cpu_nsleep_restart(struct restart_block *restart_block)
{
clockid_t which_clock = restart_block->arg0;
struct timespec __user *rmtp;
struct timespec t;
+ struct itimerspec it;
+ int error;
rmtp = (struct timespec __user *) restart_block->arg1;
t.tv_sec = restart_block->arg2;
t.tv_nsec = restart_block->arg3;
restart_block->fn = do_no_restart_syscall;
- return posix_cpu_nsleep(which_clock, TIMER_ABSTIME, &t, rmtp);
+ error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it);
+
+ if (error == -ERESTART_RESTARTBLOCK) {
+ /*
+ * Report back to the user the time still remaining.
+ */
+ if (rmtp != NULL && copy_to_user(rmtp, &it.it_value, sizeof *rmtp))
+ return -EFAULT;
+
+ restart_block->fn = posix_cpu_nsleep_restart;
+ restart_block->arg0 = which_clock;
+ restart_block->arg1 = (unsigned long) rmtp;
+ restart_block->arg2 = t.tv_sec;
+ restart_block->arg3 = t.tv_nsec;
+ }
+ return error;
+
}
@@ -1524,6 +1568,10 @@ static int process_cpu_nsleep(const clockid_t which_clock, int flags,
{
return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp);
}
+static long process_cpu_nsleep_restart(struct restart_block *restart_block)
+{
+ return -EINVAL;
+}
static int thread_cpu_clock_getres(const clockid_t which_clock,
struct timespec *tp)
{
@@ -1544,6 +1592,10 @@ static int thread_cpu_nsleep(const clockid_t which_clock, int flags,
{
return -EINVAL;
}
+static long thread_cpu_nsleep_restart(struct restart_block *restart_block)
+{
+ return -EINVAL;
+}
static __init int init_posix_cpu_timers(void)
{
@@ -1553,6 +1605,7 @@ static __init int init_posix_cpu_timers(void)
.clock_set = do_posix_clock_nosettime,
.timer_create = process_cpu_timer_create,
.nsleep = process_cpu_nsleep,
+ .nsleep_restart = process_cpu_nsleep_restart,
};
struct k_clock thread = {
.clock_getres = thread_cpu_clock_getres,
@@ -1560,6 +1613,7 @@ static __init int init_posix_cpu_timers(void)
.clock_set = do_posix_clock_nosettime,
.timer_create = thread_cpu_timer_create,
.nsleep = thread_cpu_nsleep,
+ .nsleep_restart = thread_cpu_nsleep_restart,
};
register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c
index ac6dc8744429..9cbb5d1be06f 100644
--- a/kernel/posix-timers.c
+++ b/kernel/posix-timers.c
@@ -1,5 +1,5 @@
/*
- * linux/kernel/posix_timers.c
+ * linux/kernel/posix-timers.c
*
*
* 2002-10-15 Posix Clocks & timers
@@ -973,3 +973,24 @@ sys_clock_nanosleep(const clockid_t which_clock, int flags,
return CLOCK_DISPATCH(which_clock, nsleep,
(which_clock, flags, &t, rmtp));
}
+
+/*
+ * nanosleep_restart for monotonic and realtime clocks
+ */
+static int common_nsleep_restart(struct restart_block *restart_block)
+{
+ return hrtimer_nanosleep_restart(restart_block);
+}
+
+/*
+ * This will restart clock_nanosleep. This is required only by
+ * compat_clock_nanosleep_restart for now.
+ */
+long
+clock_nanosleep_restart(struct restart_block *restart_block)
+{
+ clockid_t which_clock = restart_block->arg0;
+
+ return CLOCK_DISPATCH(which_clock, nsleep_restart,
+ (restart_block));
+}
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index d72234942798..d3a158a60312 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -18,6 +18,7 @@
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/pm.h>
+#include <linux/console.h>
#include <linux/cpu.h>
#include "power.h"
@@ -119,8 +120,10 @@ int pm_suspend_disk(void)
if (error)
return error;
+ suspend_console();
error = device_suspend(PMSG_FREEZE);
if (error) {
+ resume_console();
printk("Some devices failed to suspend\n");
unprepare_processes();
return error;
@@ -133,6 +136,7 @@ int pm_suspend_disk(void)
if (in_suspend) {
device_resume();
+ resume_console();
pr_debug("PM: writing image.\n");
error = swsusp_write();
if (!error)
@@ -148,6 +152,7 @@ int pm_suspend_disk(void)
swsusp_free();
Done:
device_resume();
+ resume_console();
unprepare_processes();
return error;
}
@@ -212,7 +217,9 @@ static int software_resume(void)
pr_debug("PM: Preparing devices for restore.\n");
+ suspend_console();
if ((error = device_suspend(PMSG_PRETHAW))) {
+ resume_console();
printk("Some devices failed to suspend\n");
swsusp_free();
goto Thaw;
@@ -224,6 +231,7 @@ static int software_resume(void)
swsusp_resume();
pr_debug("PM: Restore failed, recovering.n");
device_resume();
+ resume_console();
Thaw:
unprepare_processes();
Done:
diff --git a/kernel/power/poweroff.c b/kernel/power/poweroff.c
index 7a4144ba3afd..f1f900ac3164 100644
--- a/kernel/power/poweroff.c
+++ b/kernel/power/poweroff.c
@@ -23,8 +23,7 @@ static void do_poweroff(void *dummy)
static DECLARE_WORK(poweroff_work, do_poweroff, NULL);
-static void handle_poweroff(int key, struct pt_regs *pt_regs,
- struct tty_struct *tty)
+static void handle_poweroff(int key, struct tty_struct *tty)
{
schedule_work(&poweroff_work);
}
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 1b84313cbab5..99f9b7d177d6 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -906,7 +906,7 @@ static void init_header(struct swsusp_info *info)
memset(info, 0, sizeof(struct swsusp_info));
info->version_code = LINUX_VERSION_CODE;
info->num_physpages = num_physpages;
- memcpy(&info->uts, &system_utsname, sizeof(system_utsname));
+ memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname));
info->cpus = num_online_cpus();
info->image_pages = nr_copy_pages;
info->pages = nr_copy_pages + nr_meta_pages + 1;
@@ -1050,13 +1050,13 @@ static inline int check_header(struct swsusp_info *info)
reason = "kernel version";
if (info->num_physpages != num_physpages)
reason = "memory size";
- if (strcmp(info->uts.sysname,system_utsname.sysname))
+ if (strcmp(info->uts.sysname,init_utsname()->sysname))
reason = "system type";
- if (strcmp(info->uts.release,system_utsname.release))
+ if (strcmp(info->uts.release,init_utsname()->release))
reason = "kernel release";
- if (strcmp(info->uts.version,system_utsname.version))
+ if (strcmp(info->uts.version,init_utsname()->version))
reason = "version";
- if (strcmp(info->uts.machine,system_utsname.machine))
+ if (strcmp(info->uts.machine,init_utsname()->machine))
reason = "machine";
if (reason) {
printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 9b2ee5344dee..1a3b0dd2c3fc 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -425,7 +425,8 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
bio_set_pages_dirty(bio);
bio_put(bio);
} else {
- get_page(page);
+ if (rw == READ)
+ get_page(page); /* These pages are freed later */
bio->bi_private = *bio_chain;
*bio_chain = bio;
submit_bio(rw | (1 << BIO_RW_SYNC), bio);
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 72825c853cd7..d991d3b0e5a4 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -19,6 +19,7 @@
#include <linux/swapops.h>
#include <linux/pm.h>
#include <linux/fs.h>
+#include <linux/console.h>
#include <linux/cpu.h>
#include <asm/uaccess.h>
@@ -145,10 +146,10 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
error = freeze_processes();
if (error) {
thaw_processes();
+ enable_nonboot_cpus();
error = -EBUSY;
}
}
- enable_nonboot_cpus();
up(&pm_sem);
if (!error)
data->frozen = 1;
@@ -173,12 +174,14 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
/* Free memory before shutting down devices. */
error = swsusp_shrink_memory();
if (!error) {
+ suspend_console();
error = device_suspend(PMSG_FREEZE);
if (!error) {
in_suspend = 1;
error = swsusp_suspend();
device_resume();
}
+ resume_console();
}
up(&pm_sem);
if (!error)
@@ -196,11 +199,13 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
snapshot_free_unused_memory(&data->handle);
down(&pm_sem);
pm_prepare_console();
+ suspend_console();
error = device_suspend(PMSG_PRETHAW);
if (!error) {
error = swsusp_resume();
device_resume();
}
+ resume_console();
pm_restore_console();
up(&pm_sem);
break;
@@ -289,6 +294,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
}
/* Put devices to sleep */
+ suspend_console();
error = device_suspend(PMSG_SUSPEND);
if (error) {
printk(KERN_ERR "Failed to suspend some devices.\n");
@@ -299,7 +305,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
/* Wake up devices */
device_resume();
}
-
+ resume_console();
if (pm_ops->finish)
pm_ops->finish(PM_SUSPEND_MEM);
diff --git a/kernel/printk.c b/kernel/printk.c
index 771f5e861bcd..f7d427ef5038 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -820,15 +820,8 @@ void release_console_sem(void)
console_locked = 0;
up(&console_sem);
spin_unlock_irqrestore(&logbuf_lock, flags);
- if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait)) {
- /*
- * If we printk from within the lock dependency code,
- * from within the scheduler code, then do not lock
- * up due to self-recursion:
- */
- if (!lockdep_internal())
- wake_up_interruptible(&log_wait);
- }
+ if (wake_klogd && !oops_in_progress && waitqueue_active(&log_wait))
+ wake_up_interruptible(&log_wait);
}
EXPORT_SYMBOL(release_console_sem);
diff --git a/kernel/profile.c b/kernel/profile.c
index fb660c7d35ba..f940b462eec9 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -25,6 +25,7 @@
#include <linux/mutex.h>
#include <asm/sections.h>
#include <asm/semaphore.h>
+#include <asm/irq_regs.h>
struct profile_hit {
u32 pc, hits;
@@ -366,8 +367,10 @@ void profile_hit(int type, void *__pc)
}
#endif /* !CONFIG_SMP */
-void profile_tick(int type, struct pt_regs *regs)
+void profile_tick(int type)
{
+ struct pt_regs *regs = get_irq_regs();
+
if (type == CPU_PROFILING && timer_hook)
timer_hook(regs);
if (!user_mode(regs) && cpu_isset(smp_processor_id(), prof_cpu_mask))
@@ -396,7 +399,7 @@ static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffe
unsigned long full_count = count, err;
cpumask_t new_value;
- err = cpumask_parse(buffer, count, new_value);
+ err = cpumask_parse_user(buffer, count, new_value);
if (err)
return err;
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 9a111f70145c..4d50e06fd745 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -241,60 +241,6 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
return 0;
}
-/*
- * Access another process' address space.
- * Source/target buffer must be kernel space,
- * Do not walk the page table directly, use get_user_pages
- */
-
-int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
-{
- struct mm_struct *mm;
- struct vm_area_struct *vma;
- struct page *page;
- void *old_buf = buf;
-
- mm = get_task_mm(tsk);
- if (!mm)
- return 0;
-
- down_read(&mm->mmap_sem);
- /* ignore errors, just check how much was sucessfully transfered */
- while (len) {
- int bytes, ret, offset;
- void *maddr;
-
- ret = get_user_pages(tsk, mm, addr, 1,
- write, 1, &page, &vma);
- if (ret <= 0)
- break;
-
- bytes = len;
- offset = addr & (PAGE_SIZE-1);
- if (bytes > PAGE_SIZE-offset)
- bytes = PAGE_SIZE-offset;
-
- maddr = kmap(page);
- if (write) {
- copy_to_user_page(vma, page, addr,
- maddr + offset, buf, bytes);
- set_page_dirty_lock(page);
- } else {
- copy_from_user_page(vma, page, addr,
- buf, maddr + offset, bytes);
- }
- kunmap(page);
- page_cache_release(page);
- len -= bytes;
- buf += bytes;
- addr += bytes;
- }
- up_read(&mm->mmap_sem);
- mmput(mm);
-
- return buf - old_buf;
-}
-
int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
{
int copied = 0;
@@ -494,6 +440,7 @@ struct task_struct *ptrace_get_task_struct(pid_t pid)
child = find_task_by_pid(pid);
if (child)
get_task_struct(child);
+
read_unlock(&tasklist_lock);
if (!child)
return ERR_PTR(-ESRCH);
diff --git a/kernel/rcupdate.c b/kernel/rcupdate.c
index 523e46483b99..26bb5ffe1ef1 100644
--- a/kernel/rcupdate.c
+++ b/kernel/rcupdate.c
@@ -71,9 +71,6 @@ static DEFINE_PER_CPU(struct tasklet_struct, rcu_tasklet) = {NULL};
static int blimit = 10;
static int qhimark = 10000;
static int qlowmark = 100;
-#ifdef CONFIG_SMP
-static int rsinterval = 1000;
-#endif
static atomic_t rcu_barrier_cpu_count;
static DEFINE_MUTEX(rcu_barrier_mutex);
@@ -86,8 +83,8 @@ static void force_quiescent_state(struct rcu_data *rdp,
int cpu;
cpumask_t cpumask;
set_need_resched();
- if (unlikely(rdp->qlen - rdp->last_rs_qlen > rsinterval)) {
- rdp->last_rs_qlen = rdp->qlen;
+ if (unlikely(!rcp->signaled)) {
+ rcp->signaled = 1;
/*
* Don't send IPI to itself. With irqs disabled,
* rdp->cpu is the current cpu.
@@ -301,6 +298,7 @@ static void rcu_start_batch(struct rcu_ctrlblk *rcp)
smp_mb();
cpus_andnot(rcp->cpumask, cpu_online_map, nohz_cpu_mask);
+ rcp->signaled = 0;
}
}
@@ -628,9 +626,6 @@ void synchronize_rcu(void)
module_param(blimit, int, 0);
module_param(qhimark, int, 0);
module_param(qlowmark, int, 0);
-#ifdef CONFIG_SMP
-module_param(rsinterval, int, 0);
-#endif
EXPORT_SYMBOL_GPL(rcu_batches_completed);
EXPORT_SYMBOL_GPL(rcu_batches_completed_bh);
EXPORT_SYMBOL_GPL(call_rcu);
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 4d1c3d247127..e2bda18f6f42 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -15,9 +15,10 @@
* 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) IBM Corporation, 2005
+ * Copyright (C) IBM Corporation, 2005, 2006
*
* Authors: Paul E. McKenney <paulmck@us.ibm.com>
+ * Josh Triplett <josh@freedesktop.org>
*
* See also: Documentation/RCU/torture.txt
*/
@@ -44,19 +45,25 @@
#include <linux/delay.h>
#include <linux/byteorder/swabb.h>
#include <linux/stat.h>
+#include <linux/srcu.h>
MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and "
+ "Josh Triplett <josh@freedesktop.org>");
-static int nreaders = -1; /* # reader threads, defaults to 4*ncpus */
+static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */
+static int nfakewriters = 4; /* # fake writer threads */
static int stat_interval; /* Interval between stats, in seconds. */
/* Defaults to "only at end of test". */
static int verbose; /* Print more debug info. */
static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */
static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
-static char *torture_type = "rcu"; /* What to torture. */
+static char *torture_type = "rcu"; /* What RCU implementation to torture. */
module_param(nreaders, int, 0);
MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
+module_param(nfakewriters, int, 0);
+MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
module_param(stat_interval, int, 0);
MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
module_param(verbose, bool, 0);
@@ -66,7 +73,7 @@ MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
module_param(shuffle_interval, int, 0);
MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
module_param(torture_type, charp, 0);
-MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh)");
+MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)");
#define TORTURE_FLAG "-torture:"
#define PRINTK_STRING(s) \
@@ -80,6 +87,7 @@ static char printk_buf[4096];
static int nrealreaders;
static struct task_struct *writer_task;
+static struct task_struct **fakewriter_tasks;
static struct task_struct **reader_tasks;
static struct task_struct *stats_task;
static struct task_struct *shuffler_task;
@@ -104,11 +112,12 @@ static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_batch) =
{ 0 };
static atomic_t rcu_torture_wcount[RCU_TORTURE_PIPE_LEN + 1];
-atomic_t n_rcu_torture_alloc;
-atomic_t n_rcu_torture_alloc_fail;
-atomic_t n_rcu_torture_free;
-atomic_t n_rcu_torture_mberror;
-atomic_t n_rcu_torture_error;
+static atomic_t n_rcu_torture_alloc;
+static atomic_t n_rcu_torture_alloc_fail;
+static atomic_t n_rcu_torture_free;
+static atomic_t n_rcu_torture_mberror;
+static atomic_t n_rcu_torture_error;
+static struct list_head rcu_torture_removed;
/*
* Allocate an element from the rcu_tortures pool.
@@ -145,7 +154,7 @@ rcu_torture_free(struct rcu_torture *p)
struct rcu_random_state {
unsigned long rrs_state;
- unsigned long rrs_count;
+ long rrs_count;
};
#define RCU_RANDOM_MULT 39916801 /* prime */
@@ -158,7 +167,7 @@ struct rcu_random_state {
* Crude but fast random-number generator. Uses a linear congruential
* generator, with occasional help from get_random_bytes().
*/
-static long
+static unsigned long
rcu_random(struct rcu_random_state *rrsp)
{
long refresh;
@@ -180,9 +189,11 @@ struct rcu_torture_ops {
void (*init)(void);
void (*cleanup)(void);
int (*readlock)(void);
+ void (*readdelay)(struct rcu_random_state *rrsp);
void (*readunlock)(int idx);
int (*completed)(void);
void (*deferredfree)(struct rcu_torture *p);
+ void (*sync)(void);
int (*stats)(char *page);
char *name;
};
@@ -192,13 +203,25 @@ static struct rcu_torture_ops *cur_ops = NULL;
* Definitions for rcu torture testing.
*/
-static int rcu_torture_read_lock(void)
+static int rcu_torture_read_lock(void) __acquires(RCU)
{
rcu_read_lock();
return 0;
}
-static void rcu_torture_read_unlock(int idx)
+static void rcu_read_delay(struct rcu_random_state *rrsp)
+{
+ long delay;
+ const long longdelay = 200;
+
+ /* We want there to be long-running readers, but not all the time. */
+
+ delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay);
+ if (!delay)
+ udelay(longdelay);
+}
+
+static void rcu_torture_read_unlock(int idx) __releases(RCU)
{
rcu_read_unlock();
}
@@ -239,24 +262,65 @@ static struct rcu_torture_ops rcu_ops = {
.init = NULL,
.cleanup = NULL,
.readlock = rcu_torture_read_lock,
+ .readdelay = rcu_read_delay,
.readunlock = rcu_torture_read_unlock,
.completed = rcu_torture_completed,
.deferredfree = rcu_torture_deferred_free,
+ .sync = synchronize_rcu,
.stats = NULL,
.name = "rcu"
};
+static void rcu_sync_torture_deferred_free(struct rcu_torture *p)
+{
+ int i;
+ struct rcu_torture *rp;
+ struct rcu_torture *rp1;
+
+ cur_ops->sync();
+ list_add(&p->rtort_free, &rcu_torture_removed);
+ list_for_each_entry_safe(rp, rp1, &rcu_torture_removed, rtort_free) {
+ i = rp->rtort_pipe_count;
+ if (i > RCU_TORTURE_PIPE_LEN)
+ i = RCU_TORTURE_PIPE_LEN;
+ atomic_inc(&rcu_torture_wcount[i]);
+ if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {
+ rp->rtort_mbtest = 0;
+ list_del(&rp->rtort_free);
+ rcu_torture_free(rp);
+ }
+ }
+}
+
+static void rcu_sync_torture_init(void)
+{
+ INIT_LIST_HEAD(&rcu_torture_removed);
+}
+
+static struct rcu_torture_ops rcu_sync_ops = {
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = rcu_torture_read_lock,
+ .readdelay = rcu_read_delay,
+ .readunlock = rcu_torture_read_unlock,
+ .completed = rcu_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = synchronize_rcu,
+ .stats = NULL,
+ .name = "rcu_sync"
+};
+
/*
* Definitions for rcu_bh torture testing.
*/
-static int rcu_bh_torture_read_lock(void)
+static int rcu_bh_torture_read_lock(void) __acquires(RCU_BH)
{
rcu_read_lock_bh();
return 0;
}
-static void rcu_bh_torture_read_unlock(int idx)
+static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH)
{
rcu_read_unlock_bh();
}
@@ -271,19 +335,176 @@ static void rcu_bh_torture_deferred_free(struct rcu_torture *p)
call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
}
+struct rcu_bh_torture_synchronize {
+ struct rcu_head head;
+ struct completion completion;
+};
+
+static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
+{
+ struct rcu_bh_torture_synchronize *rcu;
+
+ rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
+ complete(&rcu->completion);
+}
+
+static void rcu_bh_torture_synchronize(void)
+{
+ struct rcu_bh_torture_synchronize rcu;
+
+ init_completion(&rcu.completion);
+ call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
+ wait_for_completion(&rcu.completion);
+}
+
static struct rcu_torture_ops rcu_bh_ops = {
.init = NULL,
.cleanup = NULL,
.readlock = rcu_bh_torture_read_lock,
+ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
.readunlock = rcu_bh_torture_read_unlock,
.completed = rcu_bh_torture_completed,
.deferredfree = rcu_bh_torture_deferred_free,
+ .sync = rcu_bh_torture_synchronize,
.stats = NULL,
.name = "rcu_bh"
};
+static struct rcu_torture_ops rcu_bh_sync_ops = {
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = rcu_bh_torture_read_lock,
+ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = rcu_bh_torture_read_unlock,
+ .completed = rcu_bh_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = rcu_bh_torture_synchronize,
+ .stats = NULL,
+ .name = "rcu_bh_sync"
+};
+
+/*
+ * Definitions for srcu torture testing.
+ */
+
+static struct srcu_struct srcu_ctl;
+
+static void srcu_torture_init(void)
+{
+ init_srcu_struct(&srcu_ctl);
+ rcu_sync_torture_init();
+}
+
+static void srcu_torture_cleanup(void)
+{
+ synchronize_srcu(&srcu_ctl);
+ cleanup_srcu_struct(&srcu_ctl);
+}
+
+static int srcu_torture_read_lock(void)
+{
+ return srcu_read_lock(&srcu_ctl);
+}
+
+static void srcu_read_delay(struct rcu_random_state *rrsp)
+{
+ long delay;
+ const long uspertick = 1000000 / HZ;
+ const long longdelay = 10;
+
+ /* We want there to be long-running readers, but not all the time. */
+
+ delay = rcu_random(rrsp) % (nrealreaders * 2 * longdelay * uspertick);
+ if (!delay)
+ schedule_timeout_interruptible(longdelay);
+}
+
+static void srcu_torture_read_unlock(int idx)
+{
+ srcu_read_unlock(&srcu_ctl, idx);
+}
+
+static int srcu_torture_completed(void)
+{
+ return srcu_batches_completed(&srcu_ctl);
+}
+
+static void srcu_torture_synchronize(void)
+{
+ synchronize_srcu(&srcu_ctl);
+}
+
+static int srcu_torture_stats(char *page)
+{
+ int cnt = 0;
+ int cpu;
+ int idx = srcu_ctl.completed & 0x1;
+
+ cnt += sprintf(&page[cnt], "%s%s per-CPU(idx=%d):",
+ torture_type, TORTURE_FLAG, idx);
+ for_each_possible_cpu(cpu) {
+ cnt += sprintf(&page[cnt], " %d(%d,%d)", cpu,
+ per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx],
+ per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx]);
+ }
+ cnt += sprintf(&page[cnt], "\n");
+ return cnt;
+}
+
+static struct rcu_torture_ops srcu_ops = {
+ .init = srcu_torture_init,
+ .cleanup = srcu_torture_cleanup,
+ .readlock = srcu_torture_read_lock,
+ .readdelay = srcu_read_delay,
+ .readunlock = srcu_torture_read_unlock,
+ .completed = srcu_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = srcu_torture_synchronize,
+ .stats = srcu_torture_stats,
+ .name = "srcu"
+};
+
+/*
+ * Definitions for sched torture testing.
+ */
+
+static int sched_torture_read_lock(void)
+{
+ preempt_disable();
+ return 0;
+}
+
+static void sched_torture_read_unlock(int idx)
+{
+ preempt_enable();
+}
+
+static int sched_torture_completed(void)
+{
+ return 0;
+}
+
+static void sched_torture_synchronize(void)
+{
+ synchronize_sched();
+}
+
+static struct rcu_torture_ops sched_ops = {
+ .init = rcu_sync_torture_init,
+ .cleanup = NULL,
+ .readlock = sched_torture_read_lock,
+ .readdelay = rcu_read_delay, /* just reuse rcu's version. */
+ .readunlock = sched_torture_read_unlock,
+ .completed = sched_torture_completed,
+ .deferredfree = rcu_sync_torture_deferred_free,
+ .sync = sched_torture_synchronize,
+ .stats = NULL,
+ .name = "sched"
+};
+
static struct rcu_torture_ops *torture_ops[] =
- { &rcu_ops, &rcu_bh_ops, NULL };
+ { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops, &srcu_ops,
+ &sched_ops, NULL };
/*
* RCU torture writer kthread. Repeatedly substitutes a new structure
@@ -330,6 +551,30 @@ rcu_torture_writer(void *arg)
}
/*
+ * RCU torture fake writer kthread. Repeatedly calls sync, with a random
+ * delay between calls.
+ */
+static int
+rcu_torture_fakewriter(void *arg)
+{
+ DEFINE_RCU_RANDOM(rand);
+
+ VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
+ set_user_nice(current, 19);
+
+ do {
+ schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
+ udelay(rcu_random(&rand) & 0x3ff);
+ cur_ops->sync();
+ } while (!kthread_should_stop() && !fullstop);
+
+ VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
+ while (!kthread_should_stop())
+ schedule_timeout_uninterruptible(1);
+ return 0;
+}
+
+/*
* RCU torture reader kthread. Repeatedly dereferences rcu_torture_current,
* incrementing the corresponding element of the pipeline array. The
* counter in the element should never be greater than 1, otherwise, the
@@ -359,7 +604,7 @@ rcu_torture_reader(void *arg)
}
if (p->rtort_mbtest == 0)
atomic_inc(&n_rcu_torture_mberror);
- udelay(rcu_random(&rand) & 0x7f);
+ cur_ops->readdelay(&rand);
preempt_disable();
pipe_count = p->rtort_pipe_count;
if (pipe_count > RCU_TORTURE_PIPE_LEN) {
@@ -483,7 +728,7 @@ static int rcu_idle_cpu; /* Force all torture tasks off this CPU */
/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
* is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
*/
-void rcu_torture_shuffle_tasks(void)
+static void rcu_torture_shuffle_tasks(void)
{
cpumask_t tmp_mask = CPU_MASK_ALL;
int i;
@@ -507,6 +752,12 @@ void rcu_torture_shuffle_tasks(void)
set_cpus_allowed(reader_tasks[i], tmp_mask);
}
+ if (fakewriter_tasks != NULL) {
+ for (i = 0; i < nfakewriters; i++)
+ if (fakewriter_tasks[i])
+ set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
+ }
+
if (writer_task)
set_cpus_allowed(writer_task, tmp_mask);
@@ -540,11 +791,12 @@ rcu_torture_shuffle(void *arg)
static inline void
rcu_torture_print_module_parms(char *tag)
{
- printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
+ printk(KERN_ALERT "%s" TORTURE_FLAG
+ "--- %s: nreaders=%d nfakewriters=%d "
"stat_interval=%d verbose=%d test_no_idle_hz=%d "
"shuffle_interval = %d\n",
- torture_type, tag, nrealreaders, stat_interval, verbose,
- test_no_idle_hz, shuffle_interval);
+ torture_type, tag, nrealreaders, nfakewriters,
+ stat_interval, verbose, test_no_idle_hz, shuffle_interval);
}
static void
@@ -579,6 +831,19 @@ rcu_torture_cleanup(void)
}
rcu_torture_current = NULL;
+ if (fakewriter_tasks != NULL) {
+ for (i = 0; i < nfakewriters; i++) {
+ if (fakewriter_tasks[i] != NULL) {
+ VERBOSE_PRINTK_STRING(
+ "Stopping rcu_torture_fakewriter task");
+ kthread_stop(fakewriter_tasks[i]);
+ }
+ fakewriter_tasks[i] = NULL;
+ }
+ kfree(fakewriter_tasks);
+ fakewriter_tasks = NULL;
+ }
+
if (stats_task != NULL) {
VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
kthread_stop(stats_task);
@@ -666,7 +931,25 @@ rcu_torture_init(void)
writer_task = NULL;
goto unwind;
}
- reader_tasks = kmalloc(nrealreaders * sizeof(reader_tasks[0]),
+ fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
+ GFP_KERNEL);
+ if (fakewriter_tasks == NULL) {
+ VERBOSE_PRINTK_ERRSTRING("out of memory");
+ firsterr = -ENOMEM;
+ goto unwind;
+ }
+ for (i = 0; i < nfakewriters; i++) {
+ VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
+ fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
+ "rcu_torture_fakewriter");
+ if (IS_ERR(fakewriter_tasks[i])) {
+ firsterr = PTR_ERR(fakewriter_tasks[i]);
+ VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
+ fakewriter_tasks[i] = NULL;
+ goto unwind;
+ }
+ }
+ reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
GFP_KERNEL);
if (reader_tasks == NULL) {
VERBOSE_PRINTK_ERRSTRING("out of memory");
diff --git a/kernel/relay.c b/kernel/relay.c
index 33345e73485c..f04bbdb56ac2 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -95,7 +95,7 @@ int relay_mmap_buf(struct rchan_buf *buf, struct vm_area_struct *vma)
* @buf: the buffer struct
* @size: total size of the buffer
*
- * Returns a pointer to the resulting buffer, NULL if unsuccessful. The
+ * Returns a pointer to the resulting buffer, %NULL if unsuccessful. The
* passed in size will get page aligned, if it isn't already.
*/
static void *relay_alloc_buf(struct rchan_buf *buf, size_t *size)
@@ -132,10 +132,9 @@ depopulate:
/**
* relay_create_buf - allocate and initialize a channel buffer
- * @alloc_size: size of the buffer to allocate
- * @n_subbufs: number of sub-buffers in the channel
+ * @chan: the relay channel
*
- * Returns channel buffer if successful, NULL otherwise
+ * Returns channel buffer if successful, %NULL otherwise.
*/
struct rchan_buf *relay_create_buf(struct rchan *chan)
{
@@ -163,6 +162,7 @@ free_buf:
/**
* relay_destroy_channel - free the channel struct
+ * @kref: target kernel reference that contains the relay channel
*
* Should only be called from kref_put().
*/
@@ -194,6 +194,7 @@ void relay_destroy_buf(struct rchan_buf *buf)
/**
* relay_remove_buf - remove a channel buffer
+ * @kref: target kernel reference that contains the relay buffer
*
* Removes the file from the fileystem, which also frees the
* rchan_buf_struct and the channel buffer. Should only be called from
@@ -374,7 +375,7 @@ void relay_reset(struct rchan *chan)
}
EXPORT_SYMBOL_GPL(relay_reset);
-/**
+/*
* relay_open_buf - create a new relay channel buffer
*
* Internal - used by relay_open().
@@ -448,12 +449,12 @@ static inline void setup_callbacks(struct rchan *chan,
/**
* relay_open - create a new relay channel
* @base_filename: base name of files to create
- * @parent: dentry of parent directory, NULL for root directory
+ * @parent: dentry of parent directory, %NULL for root directory
* @subbuf_size: size of sub-buffers
* @n_subbufs: number of sub-buffers
* @cb: client callback functions
*
- * Returns channel pointer if successful, NULL otherwise.
+ * Returns channel pointer if successful, %NULL otherwise.
*
* Creates a channel buffer for each cpu using the sizes and
* attributes specified. The created channel buffer files
@@ -585,7 +586,7 @@ EXPORT_SYMBOL_GPL(relay_switch_subbuf);
* subbufs_consumed should be the number of sub-buffers newly consumed,
* not the total consumed.
*
- * NOTE: kernel clients don't need to call this function if the channel
+ * NOTE: Kernel clients don't need to call this function if the channel
* mode is 'overwrite'.
*/
void relay_subbufs_consumed(struct rchan *chan,
@@ -641,7 +642,7 @@ EXPORT_SYMBOL_GPL(relay_close);
* relay_flush - close the channel
* @chan: the channel
*
- * Flushes all channel buffers i.e. forces buffer switch.
+ * Flushes all channel buffers, i.e. forces buffer switch.
*/
void relay_flush(struct rchan *chan)
{
@@ -669,7 +670,7 @@ EXPORT_SYMBOL_GPL(relay_flush);
*/
static int relay_file_open(struct inode *inode, struct file *filp)
{
- struct rchan_buf *buf = inode->u.generic_ip;
+ struct rchan_buf *buf = inode->i_private;
kref_get(&buf->kref);
filp->private_data = buf;
@@ -729,7 +730,7 @@ static int relay_file_release(struct inode *inode, struct file *filp)
return 0;
}
-/**
+/*
* relay_file_read_consume - update the consumed count for the buffer
*/
static void relay_file_read_consume(struct rchan_buf *buf,
@@ -756,7 +757,7 @@ static void relay_file_read_consume(struct rchan_buf *buf,
}
}
-/**
+/*
* relay_file_read_avail - boolean, are there unconsumed bytes available?
*/
static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos)
@@ -793,6 +794,8 @@ static int relay_file_read_avail(struct rchan_buf *buf, size_t read_pos)
/**
* relay_file_read_subbuf_avail - return bytes available in sub-buffer
+ * @read_pos: file read position
+ * @buf: relay channel buffer
*/
static size_t relay_file_read_subbuf_avail(size_t read_pos,
struct rchan_buf *buf)
@@ -818,6 +821,8 @@ static size_t relay_file_read_subbuf_avail(size_t read_pos,
/**
* relay_file_read_start_pos - find the first available byte to read
+ * @read_pos: file read position
+ * @buf: relay channel buffer
*
* If the read_pos is in the middle of padding, return the
* position of the first actually available byte, otherwise
@@ -844,6 +849,9 @@ static size_t relay_file_read_start_pos(size_t read_pos,
/**
* relay_file_read_end_pos - return the new read position
+ * @read_pos: file read position
+ * @buf: relay channel buffer
+ * @count: number of bytes to be read
*/
static size_t relay_file_read_end_pos(struct rchan_buf *buf,
size_t read_pos,
@@ -865,7 +873,7 @@ static size_t relay_file_read_end_pos(struct rchan_buf *buf,
return end_pos;
}
-/**
+/*
* subbuf_read_actor - read up to one subbuf's worth of data
*/
static int subbuf_read_actor(size_t read_start,
@@ -879,7 +887,7 @@ static int subbuf_read_actor(size_t read_start,
from = buf->start + read_start;
ret = avail;
- if (copy_to_user(desc->arg.data, from, avail)) {
+ if (copy_to_user(desc->arg.buf, from, avail)) {
desc->error = -EFAULT;
ret = 0;
}
@@ -890,7 +898,7 @@ static int subbuf_read_actor(size_t read_start,
return ret;
}
-/**
+/*
* subbuf_send_actor - send up to one subbuf's worth of data
*/
static int subbuf_send_actor(size_t read_start,
@@ -933,29 +941,22 @@ typedef int (*subbuf_actor_t) (size_t read_start,
read_descriptor_t *desc,
read_actor_t actor);
-/**
+/*
* relay_file_read_subbufs - read count bytes, bridging subbuf boundaries
*/
static inline ssize_t relay_file_read_subbufs(struct file *filp,
loff_t *ppos,
- size_t count,
subbuf_actor_t subbuf_actor,
read_actor_t actor,
- void *target)
+ read_descriptor_t *desc)
{
struct rchan_buf *buf = filp->private_data;
size_t read_start, avail;
- read_descriptor_t desc;
int ret;
- if (!count)
+ if (!desc->count)
return 0;
- desc.written = 0;
- desc.count = count;
- desc.arg.data = target;
- desc.error = 0;
-
mutex_lock(&filp->f_dentry->d_inode->i_mutex);
do {
if (!relay_file_read_avail(buf, *ppos))
@@ -966,19 +967,19 @@ static inline ssize_t relay_file_read_subbufs(struct file *filp,
if (!avail)
break;
- avail = min(desc.count, avail);
- ret = subbuf_actor(read_start, buf, avail, &desc, actor);
- if (desc.error < 0)
+ avail = min(desc->count, avail);
+ ret = subbuf_actor(read_start, buf, avail, desc, actor);
+ if (desc->error < 0)
break;
if (ret) {
relay_file_read_consume(buf, read_start, ret);
*ppos = relay_file_read_end_pos(buf, read_start, ret);
}
- } while (desc.count && ret);
+ } while (desc->count && ret);
mutex_unlock(&filp->f_dentry->d_inode->i_mutex);
- return desc.written;
+ return desc->written;
}
static ssize_t relay_file_read(struct file *filp,
@@ -986,8 +987,13 @@ static ssize_t relay_file_read(struct file *filp,
size_t count,
loff_t *ppos)
{
- return relay_file_read_subbufs(filp, ppos, count, subbuf_read_actor,
- NULL, buffer);
+ read_descriptor_t desc;
+ desc.written = 0;
+ desc.count = count;
+ desc.arg.buf = buffer;
+ desc.error = 0;
+ return relay_file_read_subbufs(filp, ppos, subbuf_read_actor,
+ NULL, &desc);
}
static ssize_t relay_file_sendfile(struct file *filp,
@@ -996,8 +1002,13 @@ static ssize_t relay_file_sendfile(struct file *filp,
read_actor_t actor,
void *target)
{
- return relay_file_read_subbufs(filp, ppos, count, subbuf_send_actor,
- actor, target);
+ read_descriptor_t desc;
+ desc.written = 0;
+ desc.count = count;
+ desc.arg.data = target;
+ desc.error = 0;
+ return relay_file_read_subbufs(filp, ppos, subbuf_send_actor,
+ actor, &desc);
}
struct file_operations relay_file_operations = {
diff --git a/kernel/resource.c b/kernel/resource.c
index 46286434af80..6de60c12143e 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -193,6 +193,13 @@ static int __release_resource(struct resource *old)
return -EINVAL;
}
+/**
+ * request_resource - request and reserve an I/O or memory resource
+ * @root: root resource descriptor
+ * @new: resource descriptor desired by caller
+ *
+ * Returns 0 for success, negative error code on error.
+ */
int request_resource(struct resource *root, struct resource *new)
{
struct resource *conflict;
@@ -205,6 +212,15 @@ int request_resource(struct resource *root, struct resource *new)
EXPORT_SYMBOL(request_resource);
+/**
+ * ____request_resource - reserve a resource, with resource conflict returned
+ * @root: root resource descriptor
+ * @new: resource descriptor desired by caller
+ *
+ * Returns:
+ * On success, NULL is returned.
+ * On error, a pointer to the conflicting resource is returned.
+ */
struct resource *____request_resource(struct resource *root, struct resource *new)
{
struct resource *conflict;
@@ -217,6 +233,10 @@ struct resource *____request_resource(struct resource *root, struct resource *ne
EXPORT_SYMBOL(____request_resource);
+/**
+ * release_resource - release a previously reserved resource
+ * @old: resource pointer
+ */
int release_resource(struct resource *old)
{
int retval;
@@ -315,8 +335,16 @@ static int find_resource(struct resource *root, struct resource *new,
return -EBUSY;
}
-/*
- * Allocate empty slot in the resource tree given range and alignment.
+/**
+ * allocate_resource - allocate empty slot in the resource tree given range & alignment
+ * @root: root resource descriptor
+ * @new: resource descriptor desired by caller
+ * @size: requested resource region size
+ * @min: minimum size to allocate
+ * @max: maximum size to allocate
+ * @align: alignment requested, in bytes
+ * @alignf: alignment function, optional, called if not NULL
+ * @alignf_data: arbitrary data to pass to the @alignf function
*/
int allocate_resource(struct resource *root, struct resource *new,
resource_size_t size, resource_size_t min,
@@ -344,12 +372,11 @@ EXPORT_SYMBOL(allocate_resource);
*
* Returns 0 on success, -EBUSY if the resource can't be inserted.
*
- * This function is equivalent of request_resource when no conflict
+ * This function is equivalent to request_resource when no conflict
* happens. If a conflict happens, and the conflicting resources
* entirely fit within the range of the new resource, then the new
- * resource is inserted and the conflicting resources become childs of
- * the new resource. Otherwise the new resource becomes the child of
- * the conflicting resource
+ * resource is inserted and the conflicting resources become children of
+ * the new resource.
*/
int insert_resource(struct resource *parent, struct resource *new)
{
@@ -357,20 +384,21 @@ int insert_resource(struct resource *parent, struct resource *new)
struct resource *first, *next;
write_lock(&resource_lock);
- begin:
- result = 0;
- first = __request_resource(parent, new);
- if (!first)
- goto out;
- result = -EBUSY;
- if (first == parent)
- goto out;
+ for (;; parent = first) {
+ result = 0;
+ first = __request_resource(parent, new);
+ if (!first)
+ goto out;
- /* Resource fully contained by the clashing resource? Recurse into it */
- if (first->start <= new->start && first->end >= new->end) {
- parent = first;
- goto begin;
+ result = -EBUSY;
+ if (first == parent)
+ goto out;
+
+ if ((first->start > new->start) || (first->end < new->end))
+ break;
+ if ((first->start == new->start) && (first->end == new->end))
+ break;
}
for (next = first; ; next = next->sibling) {
@@ -407,10 +435,15 @@ int insert_resource(struct resource *parent, struct resource *new)
return result;
}
-/*
+/**
+ * adjust_resource - modify a resource's start and size
+ * @res: resource to modify
+ * @start: new start value
+ * @size: new size
+ *
* Given an existing resource, change its start and size to match the
- * arguments. Returns -EBUSY if it can't fit. Existing children of
- * the resource are assumed to be immutable.
+ * arguments. Returns 0 on success, -EBUSY if it can't fit.
+ * Existing children of the resource are assumed to be immutable.
*/
int adjust_resource(struct resource *res, resource_size_t start, resource_size_t size)
{
@@ -456,11 +489,19 @@ EXPORT_SYMBOL(adjust_resource);
* Note how this, unlike the above, knows about
* the IO flag meanings (busy etc).
*
- * Request-region creates a new busy region.
+ * request_region creates a new busy region.
*
- * Check-region returns non-zero if the area is already busy
+ * check_region returns non-zero if the area is already busy.
*
- * Release-region releases a matching busy region.
+ * release_region releases a matching busy region.
+ */
+
+/**
+ * __request_region - create a new busy resource region
+ * @parent: parent resource descriptor
+ * @start: resource start address
+ * @n: resource region size
+ * @name: reserving caller's ID string
*/
struct resource * __request_region(struct resource *parent,
resource_size_t start, resource_size_t n,
@@ -497,9 +538,23 @@ struct resource * __request_region(struct resource *parent,
}
return res;
}
-
EXPORT_SYMBOL(__request_region);
+/**
+ * __check_region - check if a resource region is busy or free
+ * @parent: parent resource descriptor
+ * @start: resource start address
+ * @n: resource region size
+ *
+ * Returns 0 if the region is free at the moment it is checked,
+ * returns %-EBUSY if the region is busy.
+ *
+ * NOTE:
+ * This function is deprecated because its use is racy.
+ * Even if it returns 0, a subsequent call to request_region()
+ * may fail because another driver etc. just allocated the region.
+ * Do NOT use it. It will be removed from the kernel.
+ */
int __check_region(struct resource *parent, resource_size_t start,
resource_size_t n)
{
@@ -513,9 +568,16 @@ int __check_region(struct resource *parent, resource_size_t start,
kfree(res);
return 0;
}
-
EXPORT_SYMBOL(__check_region);
+/**
+ * __release_region - release a previously reserved resource region
+ * @parent: parent resource descriptor
+ * @start: resource start address
+ * @n: resource region size
+ *
+ * The described resource region must match a currently busy region.
+ */
void __release_region(struct resource *parent, resource_size_t start,
resource_size_t n)
{
@@ -553,7 +615,6 @@ void __release_region(struct resource *parent, resource_size_t start,
"<%016llx-%016llx>\n", (unsigned long long)start,
(unsigned long long)end);
}
-
EXPORT_SYMBOL(__release_region);
/*
diff --git a/kernel/rtmutex-debug.c b/kernel/rtmutex-debug.c
index 0c1faa950af7..da8d6bf46457 100644
--- a/kernel/rtmutex-debug.c
+++ b/kernel/rtmutex-debug.c
@@ -16,7 +16,6 @@
*
* See rt.c in preempt-rt for proper credits and further information
*/
-#include <linux/config.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/module.h>
diff --git a/kernel/rtmutex-tester.c b/kernel/rtmutex-tester.c
index 948bd8f643e2..6dcea9dd8c94 100644
--- a/kernel/rtmutex-tester.c
+++ b/kernel/rtmutex-tester.c
@@ -6,7 +6,6 @@
* Copyright (C) 2006, Timesys Corp., Thomas Gleixner <tglx@timesys.com>
*
*/
-#include <linux/config.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/sched.h>
diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
index 3e13a1e5856f..4ab17da46fd8 100644
--- a/kernel/rtmutex.c
+++ b/kernel/rtmutex.c
@@ -251,6 +251,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
/* Grab the next task */
task = rt_mutex_owner(lock);
+ get_task_struct(task);
spin_lock_irqsave(&task->pi_lock, flags);
if (waiter == rt_mutex_top_waiter(lock)) {
@@ -269,7 +270,6 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
__rt_mutex_adjust_prio(task);
}
- get_task_struct(task);
spin_unlock_irqrestore(&task->pi_lock, flags);
top_waiter = rt_mutex_top_waiter(lock);
@@ -409,7 +409,7 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
struct task_struct *owner = rt_mutex_owner(lock);
struct rt_mutex_waiter *top_waiter = waiter;
unsigned long flags;
- int boost = 0, res;
+ int chain_walk = 0, res;
spin_lock_irqsave(&current->pi_lock, flags);
__rt_mutex_adjust_prio(current);
@@ -433,25 +433,23 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
__rt_mutex_adjust_prio(owner);
- if (owner->pi_blocked_on) {
- boost = 1;
- /* gets dropped in rt_mutex_adjust_prio_chain()! */
- get_task_struct(owner);
- }
- spin_unlock_irqrestore(&owner->pi_lock, flags);
- }
- else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock)) {
- spin_lock_irqsave(&owner->pi_lock, flags);
- if (owner->pi_blocked_on) {
- boost = 1;
- /* gets dropped in rt_mutex_adjust_prio_chain()! */
- get_task_struct(owner);
- }
+ if (owner->pi_blocked_on)
+ chain_walk = 1;
spin_unlock_irqrestore(&owner->pi_lock, flags);
}
- if (!boost)
+ else if (debug_rt_mutex_detect_deadlock(waiter, detect_deadlock))
+ chain_walk = 1;
+
+ if (!chain_walk)
return 0;
+ /*
+ * The owner can't disappear while holding a lock,
+ * so the owner struct is protected by wait_lock.
+ * Gets dropped in rt_mutex_adjust_prio_chain()!
+ */
+ get_task_struct(owner);
+
spin_unlock(&lock->wait_lock);
res = rt_mutex_adjust_prio_chain(owner, detect_deadlock, lock, waiter,
@@ -532,7 +530,7 @@ static void remove_waiter(struct rt_mutex *lock,
int first = (waiter == rt_mutex_top_waiter(lock));
struct task_struct *owner = rt_mutex_owner(lock);
unsigned long flags;
- int boost = 0;
+ int chain_walk = 0;
spin_lock_irqsave(&current->pi_lock, flags);
plist_del(&waiter->list_entry, &lock->wait_list);
@@ -554,19 +552,20 @@ static void remove_waiter(struct rt_mutex *lock,
}
__rt_mutex_adjust_prio(owner);
- if (owner->pi_blocked_on) {
- boost = 1;
- /* gets dropped in rt_mutex_adjust_prio_chain()! */
- get_task_struct(owner);
- }
+ if (owner->pi_blocked_on)
+ chain_walk = 1;
+
spin_unlock_irqrestore(&owner->pi_lock, flags);
}
WARN_ON(!plist_node_empty(&waiter->pi_list_entry));
- if (!boost)
+ if (!chain_walk)
return;
+ /* gets dropped in rt_mutex_adjust_prio_chain()! */
+ get_task_struct(owner);
+
spin_unlock(&lock->wait_lock);
rt_mutex_adjust_prio_chain(owner, 0, lock, NULL, current);
@@ -592,10 +591,10 @@ void rt_mutex_adjust_pi(struct task_struct *task)
return;
}
- /* gets dropped in rt_mutex_adjust_prio_chain()! */
- get_task_struct(task);
spin_unlock_irqrestore(&task->pi_lock, flags);
+ /* gets dropped in rt_mutex_adjust_prio_chain()! */
+ get_task_struct(task);
rt_mutex_adjust_prio_chain(task, 0, NULL, NULL, task);
}
diff --git a/kernel/sched.c b/kernel/sched.c
index 5c848fd4e461..3399701c680e 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -49,7 +49,7 @@
#include <linux/seq_file.h>
#include <linux/syscalls.h>
#include <linux/times.h>
-#include <linux/acct.h>
+#include <linux/tsacct_kern.h>
#include <linux/kprobes.h>
#include <linux/delayacct.h>
#include <asm/tlb.h>
@@ -160,15 +160,6 @@
#define TASK_PREEMPTS_CURR(p, rq) \
((p)->prio < (rq)->curr->prio)
-/*
- * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
- * to time slice values: [800ms ... 100ms ... 5ms]
- *
- * The higher a thread's priority, the bigger timeslices
- * it gets during one round of execution. But even the lowest
- * priority thread gets MIN_TIMESLICE worth of execution time.
- */
-
#define SCALE_PRIO(x, prio) \
max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO / 2), MIN_TIMESLICE)
@@ -180,6 +171,15 @@ static unsigned int static_prio_timeslice(int static_prio)
return SCALE_PRIO(DEF_TIMESLICE, static_prio);
}
+/*
+ * task_timeslice() scales user-nice values [ -20 ... 0 ... 19 ]
+ * to time slice values: [800ms ... 100ms ... 5ms]
+ *
+ * The higher a thread's priority, the bigger timeslices
+ * it gets during one round of execution. But even the lowest
+ * priority thread gets MIN_TIMESLICE worth of execution time.
+ */
+
static inline unsigned int task_timeslice(struct task_struct *p)
{
return static_prio_timeslice(p->static_prio);
@@ -1232,7 +1232,7 @@ nextgroup:
}
/*
- * find_idlest_queue - find the idlest runqueue among the cpus in group.
+ * find_idlest_cpu - find the idlest cpu among the cpus in group.
*/
static int
find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
@@ -1286,21 +1286,29 @@ static int sched_balance_self(int cpu, int flag)
while (sd) {
cpumask_t span;
struct sched_group *group;
- int new_cpu;
- int weight;
+ int new_cpu, weight;
+
+ if (!(sd->flags & flag)) {
+ sd = sd->child;
+ continue;
+ }
span = sd->span;
group = find_idlest_group(sd, t, cpu);
- if (!group)
- goto nextlevel;
+ if (!group) {
+ sd = sd->child;
+ continue;
+ }
new_cpu = find_idlest_cpu(group, t, cpu);
- if (new_cpu == -1 || new_cpu == cpu)
- goto nextlevel;
+ if (new_cpu == -1 || new_cpu == cpu) {
+ /* Now try balancing at a lower domain level of cpu */
+ sd = sd->child;
+ continue;
+ }
- /* Now try balancing at a lower domain level */
+ /* Now try balancing at a lower domain level of new_cpu */
cpu = new_cpu;
-nextlevel:
sd = NULL;
weight = cpus_weight(span);
for_each_domain(cpu, tmp) {
@@ -1755,27 +1763,27 @@ static inline void finish_task_switch(struct rq *rq, struct task_struct *prev)
__releases(rq->lock)
{
struct mm_struct *mm = rq->prev_mm;
- unsigned long prev_task_flags;
+ long prev_state;
rq->prev_mm = NULL;
/*
* A task struct has one reference for the use as "current".
- * If a task dies, then it sets EXIT_ZOMBIE in tsk->exit_state and
- * calls schedule one last time. The schedule call will never return,
- * and the scheduled task must drop that reference.
- * The test for EXIT_ZOMBIE must occur while the runqueue locks are
+ * If a task dies, then it sets TASK_DEAD in tsk->state and calls
+ * schedule one last time. The schedule call will never return, and
+ * the scheduled task must drop that reference.
+ * The test for TASK_DEAD must occur while the runqueue locks are
* still held, otherwise prev could be scheduled on another cpu, die
* there before we look at prev->state, and then the reference would
* be dropped twice.
* Manfred Spraul <manfred@colorfullife.com>
*/
- prev_task_flags = prev->flags;
+ prev_state = prev->state;
finish_arch_switch(prev);
finish_lock_switch(rq, prev);
if (mm)
mmdrop(mm);
- if (unlikely(prev_task_flags & PF_DEAD)) {
+ if (unlikely(prev_state == TASK_DEAD)) {
/*
* Remove function-return probe instances associated with this
* task and put them back on the free list.
@@ -1814,14 +1822,14 @@ context_switch(struct rq *rq, struct task_struct *prev,
struct mm_struct *mm = next->mm;
struct mm_struct *oldmm = prev->active_mm;
- if (unlikely(!mm)) {
+ if (!mm) {
next->active_mm = oldmm;
atomic_inc(&oldmm->mm_count);
enter_lazy_tlb(oldmm, next);
} else
switch_mm(oldmm, mm, next);
- if (unlikely(!prev->mm)) {
+ if (!prev->mm) {
prev->active_mm = NULL;
WARN_ON(rq->prev_mm);
rq->prev_mm = oldmm;
@@ -2533,8 +2541,14 @@ static int load_balance(int this_cpu, struct rq *this_rq,
struct rq *busiest;
cpumask_t cpus = CPU_MASK_ALL;
+ /*
+ * When power savings policy is enabled for the parent domain, idle
+ * sibling can pick up load irrespective of busy siblings. In this case,
+ * let the state of idle sibling percolate up as IDLE, instead of
+ * portraying it as NOT_IDLE.
+ */
if (idle != NOT_IDLE && sd->flags & SD_SHARE_CPUPOWER &&
- !sched_smt_power_savings)
+ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
sd_idle = 1;
schedstat_inc(sd, lb_cnt[idle]);
@@ -2630,7 +2644,7 @@ redo:
}
if (!nr_moved && !sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
- !sched_smt_power_savings)
+ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
return -1;
return nr_moved;
@@ -2646,7 +2660,7 @@ out_one_pinned:
sd->balance_interval *= 2;
if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
- !sched_smt_power_savings)
+ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
return -1;
return 0;
}
@@ -2668,7 +2682,14 @@ load_balance_newidle(int this_cpu, struct rq *this_rq, struct sched_domain *sd)
int sd_idle = 0;
cpumask_t cpus = CPU_MASK_ALL;
- if (sd->flags & SD_SHARE_CPUPOWER && !sched_smt_power_savings)
+ /*
+ * When power savings policy is enabled for the parent domain, idle
+ * sibling can pick up load irrespective of busy siblings. In this case,
+ * let the state of idle sibling percolate up as IDLE, instead of
+ * portraying it as NOT_IDLE.
+ */
+ if (sd->flags & SD_SHARE_CPUPOWER &&
+ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
sd_idle = 1;
schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
@@ -2709,7 +2730,8 @@ redo:
if (!nr_moved) {
schedstat_inc(sd, lb_failed[NEWLY_IDLE]);
- if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER)
+ if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
+ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
return -1;
} else
sd->nr_balance_failed = 0;
@@ -2719,7 +2741,7 @@ redo:
out_balanced:
schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
if (!sd_idle && sd->flags & SD_SHARE_CPUPOWER &&
- !sched_smt_power_savings)
+ !test_sd_parent(sd, SD_POWERSAVINGS_BALANCE))
return -1;
sd->nr_balance_failed = 0;
@@ -3348,9 +3370,6 @@ need_resched_nonpreemptible:
spin_lock_irq(&rq->lock);
- if (unlikely(prev->flags & PF_DEAD))
- prev->state = EXIT_DEAD;
-
switch_count = &prev->nivcsw;
if (prev->state && !(preempt_count() & PREEMPT_ACTIVE)) {
switch_count = &prev->nvcsw;
@@ -3472,7 +3491,7 @@ asmlinkage void __sched preempt_schedule(void)
* If there is a non-zero preempt_count or interrupts are disabled,
* we do not want to preempt the current task. Just return..
*/
- if (unlikely(ti->preempt_count || irqs_disabled()))
+ if (likely(ti->preempt_count || irqs_disabled()))
return;
need_resched:
@@ -4080,6 +4099,8 @@ static void __setscheduler(struct task_struct *p, int policy, int prio)
* @p: the task in question.
* @policy: new policy.
* @param: structure containing the new RT priority.
+ *
+ * NOTE: the task may be already dead
*/
int sched_setscheduler(struct task_struct *p, int policy,
struct sched_param *param)
@@ -4107,28 +4128,32 @@ recheck:
(p->mm && param->sched_priority > MAX_USER_RT_PRIO-1) ||
(!p->mm && param->sched_priority > MAX_RT_PRIO-1))
return -EINVAL;
- if ((policy == SCHED_NORMAL || policy == SCHED_BATCH)
- != (param->sched_priority == 0))
+ if (is_rt_policy(policy) != (param->sched_priority != 0))
return -EINVAL;
/*
* Allow unprivileged RT tasks to decrease priority:
*/
if (!capable(CAP_SYS_NICE)) {
- /*
- * can't change policy, except between SCHED_NORMAL
- * and SCHED_BATCH:
- */
- if (((policy != SCHED_NORMAL && p->policy != SCHED_BATCH) &&
- (policy != SCHED_BATCH && p->policy != SCHED_NORMAL)) &&
- !p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
- return -EPERM;
- /* can't increase priority */
- if ((policy != SCHED_NORMAL && policy != SCHED_BATCH) &&
- param->sched_priority > p->rt_priority &&
- param->sched_priority >
- p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
- return -EPERM;
+ if (is_rt_policy(policy)) {
+ unsigned long rlim_rtprio;
+ unsigned long flags;
+
+ if (!lock_task_sighand(p, &flags))
+ return -ESRCH;
+ rlim_rtprio = p->signal->rlim[RLIMIT_RTPRIO].rlim_cur;
+ unlock_task_sighand(p, &flags);
+
+ /* can't set/change the rt policy */
+ if (policy != p->policy && !rlim_rtprio)
+ return -EPERM;
+
+ /* can't increase priority */
+ if (param->sched_priority > p->rt_priority &&
+ param->sched_priority > rlim_rtprio)
+ return -EPERM;
+ }
+
/* can't change other user's priorities */
if ((current->euid != p->euid) &&
(current->euid != p->uid))
@@ -4193,14 +4218,13 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param)
return -EINVAL;
if (copy_from_user(&lparam, param, sizeof(struct sched_param)))
return -EFAULT;
- read_lock_irq(&tasklist_lock);
+
+ rcu_read_lock();
+ retval = -ESRCH;
p = find_process_by_pid(pid);
- if (!p) {
- read_unlock_irq(&tasklist_lock);
- return -ESRCH;
- }
- retval = sched_setscheduler(p, policy, &lparam);
- read_unlock_irq(&tasklist_lock);
+ if (p != NULL)
+ retval = sched_setscheduler(p, policy, &lparam);
+ rcu_read_unlock();
return retval;
}
@@ -4382,7 +4406,10 @@ EXPORT_SYMBOL(cpu_present_map);
#ifndef CONFIG_SMP
cpumask_t cpu_online_map __read_mostly = CPU_MASK_ALL;
+EXPORT_SYMBOL(cpu_online_map);
+
cpumask_t cpu_possible_map __read_mostly = CPU_MASK_ALL;
+EXPORT_SYMBOL(cpu_possible_map);
#endif
long sched_getaffinity(pid_t pid, cpumask_t *mask)
@@ -4812,7 +4839,7 @@ void show_state(void)
* NOTE: this function does not set the idle thread's NEED_RESCHED
* flag, to make booting more robust.
*/
-void __devinit init_idle(struct task_struct *idle, int cpu)
+void __cpuinit init_idle(struct task_struct *idle, int cpu)
{
struct rq *rq = cpu_rq(cpu);
unsigned long flags;
@@ -5151,7 +5178,7 @@ static void migrate_dead(unsigned int dead_cpu, struct task_struct *p)
BUG_ON(p->exit_state != EXIT_ZOMBIE && p->exit_state != EXIT_DEAD);
/* Cannot have done final schedule yet: would have vanished. */
- BUG_ON(p->flags & PF_DEAD);
+ BUG_ON(p->state == TASK_DEAD);
get_task_struct(p);
@@ -5272,9 +5299,11 @@ static struct notifier_block __cpuinitdata migration_notifier = {
int __init migration_init(void)
{
void *cpu = (void *)(long)smp_processor_id();
+ int err;
/* Start one for the boot CPU: */
- migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
+ err = migration_call(&migration_notifier, CPU_UP_PREPARE, cpu);
+ BUG_ON(err == NOTIFY_BAD);
migration_call(&migration_notifier, CPU_ONLINE, cpu);
register_cpu_notifier(&migration_notifier);
@@ -5385,7 +5414,9 @@ static int sd_degenerate(struct sched_domain *sd)
if (sd->flags & (SD_LOAD_BALANCE |
SD_BALANCE_NEWIDLE |
SD_BALANCE_FORK |
- SD_BALANCE_EXEC)) {
+ SD_BALANCE_EXEC |
+ SD_SHARE_CPUPOWER |
+ SD_SHARE_PKG_RESOURCES)) {
if (sd->groups != sd->groups->next)
return 0;
}
@@ -5419,7 +5450,9 @@ sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent)
pflags &= ~(SD_LOAD_BALANCE |
SD_BALANCE_NEWIDLE |
SD_BALANCE_FORK |
- SD_BALANCE_EXEC);
+ SD_BALANCE_EXEC |
+ SD_SHARE_CPUPOWER |
+ SD_SHARE_PKG_RESOURCES);
}
if (~cflags & pflags)
return 0;
@@ -5441,12 +5474,18 @@ static void cpu_attach_domain(struct sched_domain *sd, int cpu)
struct sched_domain *parent = tmp->parent;
if (!parent)
break;
- if (sd_parent_degenerate(tmp, parent))
+ if (sd_parent_degenerate(tmp, parent)) {
tmp->parent = parent->parent;
+ if (parent->parent)
+ parent->parent->child = tmp;
+ }
}
- if (sd && sd_degenerate(sd))
+ if (sd && sd_degenerate(sd)) {
sd = sd->parent;
+ if (sd)
+ sd->child = NULL;
+ }
sched_domain_debug(sd, cpu);
@@ -5454,7 +5493,7 @@ static void cpu_attach_domain(struct sched_domain *sd, int cpu)
}
/* cpus with isolated domains */
-static cpumask_t __devinitdata cpu_isolated_map = CPU_MASK_NONE;
+static cpumask_t __cpuinitdata cpu_isolated_map = CPU_MASK_NONE;
/* Setup the mask of cpus configured for isolated domains */
static int __init isolated_cpu_setup(char *str)
@@ -5482,15 +5521,17 @@ __setup ("isolcpus=", isolated_cpu_setup);
* covered by the given span, and will set each group's ->cpumask correctly,
* and ->cpu_power to 0.
*/
-static void init_sched_build_groups(struct sched_group groups[], cpumask_t span,
- int (*group_fn)(int cpu))
+static void
+init_sched_build_groups(struct sched_group groups[], cpumask_t span,
+ const cpumask_t *cpu_map,
+ int (*group_fn)(int cpu, const cpumask_t *cpu_map))
{
struct sched_group *first = NULL, *last = NULL;
cpumask_t covered = CPU_MASK_NONE;
int i;
for_each_cpu_mask(i, span) {
- int group = group_fn(i);
+ int group = group_fn(i, cpu_map);
struct sched_group *sg = &groups[group];
int j;
@@ -5501,7 +5542,7 @@ static void init_sched_build_groups(struct sched_group groups[], cpumask_t span,
sg->cpu_power = 0;
for_each_cpu_mask(j, span) {
- if (group_fn(j) != group)
+ if (group_fn(j, cpu_map) != group)
continue;
cpu_set(j, covered);
@@ -5968,13 +6009,15 @@ static void calibrate_migration_costs(const cpumask_t *cpu_map)
#endif
);
if (system_state == SYSTEM_BOOTING) {
- printk("migration_cost=");
- for (distance = 0; distance <= max_distance; distance++) {
- if (distance)
- printk(",");
- printk("%ld", (long)migration_cost[distance] / 1000);
+ if (num_online_cpus() > 1) {
+ printk("migration_cost=");
+ for (distance = 0; distance <= max_distance; distance++) {
+ if (distance)
+ printk(",");
+ printk("%ld", (long)migration_cost[distance] / 1000);
+ }
+ printk("\n");
}
- printk("\n");
}
j1 = jiffies;
if (migration_debug)
@@ -6077,7 +6120,7 @@ int sched_smt_power_savings = 0, sched_mc_power_savings = 0;
static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
static struct sched_group sched_group_cpus[NR_CPUS];
-static int cpu_to_cpu_group(int cpu)
+static int cpu_to_cpu_group(int cpu, const cpumask_t *cpu_map)
{
return cpu;
}
@@ -6088,31 +6131,36 @@ static int cpu_to_cpu_group(int cpu)
*/
#ifdef CONFIG_SCHED_MC
static DEFINE_PER_CPU(struct sched_domain, core_domains);
-static struct sched_group *sched_group_core_bycpu[NR_CPUS];
+static struct sched_group sched_group_core[NR_CPUS];
#endif
#if defined(CONFIG_SCHED_MC) && defined(CONFIG_SCHED_SMT)
-static int cpu_to_core_group(int cpu)
+static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
{
- return first_cpu(cpu_sibling_map[cpu]);
+ cpumask_t mask = cpu_sibling_map[cpu];
+ cpus_and(mask, mask, *cpu_map);
+ return first_cpu(mask);
}
#elif defined(CONFIG_SCHED_MC)
-static int cpu_to_core_group(int cpu)
+static int cpu_to_core_group(int cpu, const cpumask_t *cpu_map)
{
return cpu;
}
#endif
static DEFINE_PER_CPU(struct sched_domain, phys_domains);
-static struct sched_group *sched_group_phys_bycpu[NR_CPUS];
+static struct sched_group sched_group_phys[NR_CPUS];
-static int cpu_to_phys_group(int cpu)
+static int cpu_to_phys_group(int cpu, const cpumask_t *cpu_map)
{
#ifdef CONFIG_SCHED_MC
cpumask_t mask = cpu_coregroup_map(cpu);
+ cpus_and(mask, mask, *cpu_map);
return first_cpu(mask);
#elif defined(CONFIG_SCHED_SMT)
- return first_cpu(cpu_sibling_map[cpu]);
+ cpumask_t mask = cpu_sibling_map[cpu];
+ cpus_and(mask, mask, *cpu_map);
+ return first_cpu(mask);
#else
return cpu;
#endif
@@ -6130,7 +6178,7 @@ static struct sched_group **sched_group_nodes_bycpu[NR_CPUS];
static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
static struct sched_group *sched_group_allnodes_bycpu[NR_CPUS];
-static int cpu_to_allnodes_group(int cpu)
+static int cpu_to_allnodes_group(int cpu, const cpumask_t *cpu_map)
{
return cpu_to_node(cpu);
}
@@ -6162,12 +6210,11 @@ next_sg:
}
#endif
+#ifdef CONFIG_NUMA
/* Free memory allocated for various sched_group structures */
static void free_sched_groups(const cpumask_t *cpu_map)
{
- int cpu;
-#ifdef CONFIG_NUMA
- int i;
+ int cpu, i;
for_each_cpu_mask(cpu, *cpu_map) {
struct sched_group *sched_group_allnodes
@@ -6204,19 +6251,63 @@ next_sg:
kfree(sched_group_nodes);
sched_group_nodes_bycpu[cpu] = NULL;
}
+}
+#else
+static void free_sched_groups(const cpumask_t *cpu_map)
+{
+}
#endif
- for_each_cpu_mask(cpu, *cpu_map) {
- if (sched_group_phys_bycpu[cpu]) {
- kfree(sched_group_phys_bycpu[cpu]);
- sched_group_phys_bycpu[cpu] = NULL;
- }
-#ifdef CONFIG_SCHED_MC
- if (sched_group_core_bycpu[cpu]) {
- kfree(sched_group_core_bycpu[cpu]);
- sched_group_core_bycpu[cpu] = NULL;
- }
-#endif
+
+/*
+ * Initialize sched groups cpu_power.
+ *
+ * cpu_power indicates the capacity of sched group, which is used while
+ * distributing the load between different sched groups in a sched domain.
+ * Typically cpu_power for all the groups in a sched domain will be same unless
+ * there are asymmetries in the topology. If there are asymmetries, group
+ * having more cpu_power will pickup more load compared to the group having
+ * less cpu_power.
+ *
+ * cpu_power will be a multiple of SCHED_LOAD_SCALE. This multiple represents
+ * the maximum number of tasks a group can handle in the presence of other idle
+ * or lightly loaded groups in the same sched domain.
+ */
+static void init_sched_groups_power(int cpu, struct sched_domain *sd)
+{
+ struct sched_domain *child;
+ struct sched_group *group;
+
+ WARN_ON(!sd || !sd->groups);
+
+ if (cpu != first_cpu(sd->groups->cpumask))
+ return;
+
+ child = sd->child;
+
+ /*
+ * For perf policy, if the groups in child domain share resources
+ * (for example cores sharing some portions of the cache hierarchy
+ * or SMT), then set this domain groups cpu_power such that each group
+ * can handle only one task, when there are other idle groups in the
+ * same sched domain.
+ */
+ if (!child || (!(sd->flags & SD_POWERSAVINGS_BALANCE) &&
+ (child->flags &
+ (SD_SHARE_CPUPOWER | SD_SHARE_PKG_RESOURCES)))) {
+ sd->groups->cpu_power = SCHED_LOAD_SCALE;
+ return;
}
+
+ sd->groups->cpu_power = 0;
+
+ /*
+ * add cpu_power of each child group to this groups cpu_power
+ */
+ group = child->groups;
+ do {
+ sd->groups->cpu_power += group->cpu_power;
+ group = group->next;
+ } while (group != child->groups);
}
/*
@@ -6226,10 +6317,7 @@ next_sg:
static int build_sched_domains(const cpumask_t *cpu_map)
{
int i;
- struct sched_group *sched_group_phys = NULL;
-#ifdef CONFIG_SCHED_MC
- struct sched_group *sched_group_core = NULL;
-#endif
+ struct sched_domain *sd;
#ifdef CONFIG_NUMA
struct sched_group **sched_group_nodes = NULL;
struct sched_group *sched_group_allnodes = NULL;
@@ -6261,9 +6349,10 @@ static int build_sched_domains(const cpumask_t *cpu_map)
> SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
if (!sched_group_allnodes) {
sched_group_allnodes
- = kmalloc(sizeof(struct sched_group)
- * MAX_NUMNODES,
- GFP_KERNEL);
+ = kmalloc_node(sizeof(struct sched_group)
+ * MAX_NUMNODES,
+ GFP_KERNEL,
+ cpu_to_node(i));
if (!sched_group_allnodes) {
printk(KERN_WARNING
"Can not alloc allnodes sched group\n");
@@ -6275,7 +6364,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
sd = &per_cpu(allnodes_domains, i);
*sd = SD_ALLNODES_INIT;
sd->span = *cpu_map;
- group = cpu_to_allnodes_group(i);
+ group = cpu_to_allnodes_group(i, cpu_map);
sd->groups = &sched_group_allnodes[group];
p = sd;
} else
@@ -6285,60 +6374,42 @@ static int build_sched_domains(const cpumask_t *cpu_map)
*sd = SD_NODE_INIT;
sd->span = sched_domain_node_span(cpu_to_node(i));
sd->parent = p;
+ if (p)
+ p->child = sd;
cpus_and(sd->span, sd->span, *cpu_map);
#endif
- if (!sched_group_phys) {
- sched_group_phys
- = kmalloc(sizeof(struct sched_group) * NR_CPUS,
- GFP_KERNEL);
- if (!sched_group_phys) {
- printk (KERN_WARNING "Can not alloc phys sched"
- "group\n");
- goto error;
- }
- sched_group_phys_bycpu[i] = sched_group_phys;
- }
-
p = sd;
sd = &per_cpu(phys_domains, i);
- group = cpu_to_phys_group(i);
+ group = cpu_to_phys_group(i, cpu_map);
*sd = SD_CPU_INIT;
sd->span = nodemask;
sd->parent = p;
+ if (p)
+ p->child = sd;
sd->groups = &sched_group_phys[group];
#ifdef CONFIG_SCHED_MC
- if (!sched_group_core) {
- sched_group_core
- = kmalloc(sizeof(struct sched_group) * NR_CPUS,
- GFP_KERNEL);
- if (!sched_group_core) {
- printk (KERN_WARNING "Can not alloc core sched"
- "group\n");
- goto error;
- }
- sched_group_core_bycpu[i] = sched_group_core;
- }
-
p = sd;
sd = &per_cpu(core_domains, i);
- group = cpu_to_core_group(i);
+ group = cpu_to_core_group(i, cpu_map);
*sd = SD_MC_INIT;
sd->span = cpu_coregroup_map(i);
cpus_and(sd->span, sd->span, *cpu_map);
sd->parent = p;
+ p->child = sd;
sd->groups = &sched_group_core[group];
#endif
#ifdef CONFIG_SCHED_SMT
p = sd;
sd = &per_cpu(cpu_domains, i);
- group = cpu_to_cpu_group(i);
+ group = cpu_to_cpu_group(i, cpu_map);
*sd = SD_SIBLING_INIT;
sd->span = cpu_sibling_map[i];
cpus_and(sd->span, sd->span, *cpu_map);
sd->parent = p;
+ p->child = sd;
sd->groups = &sched_group_cpus[group];
#endif
}
@@ -6352,7 +6423,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
continue;
init_sched_build_groups(sched_group_cpus, this_sibling_map,
- &cpu_to_cpu_group);
+ cpu_map, &cpu_to_cpu_group);
}
#endif
@@ -6364,7 +6435,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
if (i != first_cpu(this_core_map))
continue;
init_sched_build_groups(sched_group_core, this_core_map,
- &cpu_to_core_group);
+ cpu_map, &cpu_to_core_group);
}
#endif
@@ -6378,14 +6449,14 @@ static int build_sched_domains(const cpumask_t *cpu_map)
continue;
init_sched_build_groups(sched_group_phys, nodemask,
- &cpu_to_phys_group);
+ cpu_map, &cpu_to_phys_group);
}
#ifdef CONFIG_NUMA
/* Set up node groups */
if (sched_group_allnodes)
init_sched_build_groups(sched_group_allnodes, *cpu_map,
- &cpu_to_allnodes_group);
+ cpu_map, &cpu_to_allnodes_group);
for (i = 0; i < MAX_NUMNODES; i++) {
/* Set up node groups */
@@ -6457,72 +6528,20 @@ static int build_sched_domains(const cpumask_t *cpu_map)
/* Calculate CPU power for physical packages and nodes */
#ifdef CONFIG_SCHED_SMT
for_each_cpu_mask(i, *cpu_map) {
- struct sched_domain *sd;
sd = &per_cpu(cpu_domains, i);
- sd->groups->cpu_power = SCHED_LOAD_SCALE;
+ init_sched_groups_power(i, sd);
}
#endif
#ifdef CONFIG_SCHED_MC
for_each_cpu_mask(i, *cpu_map) {
- int power;
- struct sched_domain *sd;
sd = &per_cpu(core_domains, i);
- if (sched_smt_power_savings)
- power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
- else
- power = SCHED_LOAD_SCALE + (cpus_weight(sd->groups->cpumask)-1)
- * SCHED_LOAD_SCALE / 10;
- sd->groups->cpu_power = power;
+ init_sched_groups_power(i, sd);
}
#endif
for_each_cpu_mask(i, *cpu_map) {
- struct sched_domain *sd;
-#ifdef CONFIG_SCHED_MC
- sd = &per_cpu(phys_domains, i);
- if (i != first_cpu(sd->groups->cpumask))
- continue;
-
- sd->groups->cpu_power = 0;
- if (sched_mc_power_savings || sched_smt_power_savings) {
- int j;
-
- for_each_cpu_mask(j, sd->groups->cpumask) {
- struct sched_domain *sd1;
- sd1 = &per_cpu(core_domains, j);
- /*
- * for each core we will add once
- * to the group in physical domain
- */
- if (j != first_cpu(sd1->groups->cpumask))
- continue;
-
- if (sched_smt_power_savings)
- sd->groups->cpu_power += sd1->groups->cpu_power;
- else
- sd->groups->cpu_power += SCHED_LOAD_SCALE;
- }
- } else
- /*
- * This has to be < 2 * SCHED_LOAD_SCALE
- * Lets keep it SCHED_LOAD_SCALE, so that
- * while calculating NUMA group's cpu_power
- * we can simply do
- * numa_group->cpu_power += phys_group->cpu_power;
- *
- * See "only add power once for each physical pkg"
- * comment below
- */
- sd->groups->cpu_power = SCHED_LOAD_SCALE;
-#else
- int power;
sd = &per_cpu(phys_domains, i);
- if (sched_smt_power_savings)
- power = SCHED_LOAD_SCALE * cpus_weight(sd->groups->cpumask);
- else
- power = SCHED_LOAD_SCALE;
- sd->groups->cpu_power = power;
-#endif
+ init_sched_groups_power(i, sd);
}
#ifdef CONFIG_NUMA
@@ -6530,7 +6549,7 @@ static int build_sched_domains(const cpumask_t *cpu_map)
init_numa_sched_groups_power(sched_group_nodes[i]);
if (sched_group_allnodes) {
- int group = cpu_to_allnodes_group(first_cpu(*cpu_map));
+ int group = cpu_to_allnodes_group(first_cpu(*cpu_map), cpu_map);
struct sched_group *sg = &sched_group_allnodes[group];
init_numa_sched_groups_power(sg);
@@ -6556,9 +6575,11 @@ static int build_sched_domains(const cpumask_t *cpu_map)
return 0;
+#ifdef CONFIG_NUMA
error:
free_sched_groups(cpu_map);
return -ENOMEM;
+#endif
}
/*
* Set up scheduler domains and groups. Callers must hold the hotplug lock.
@@ -6740,11 +6761,20 @@ static int update_sched_domains(struct notifier_block *nfb,
void __init sched_init_smp(void)
{
+ cpumask_t non_isolated_cpus;
+
lock_cpu_hotplug();
arch_init_sched_domains(&cpu_online_map);
+ cpus_andnot(non_isolated_cpus, cpu_online_map, cpu_isolated_map);
+ if (cpus_empty(non_isolated_cpus))
+ cpu_set(smp_processor_id(), non_isolated_cpus);
unlock_cpu_hotplug();
/* XXX: Theoretical race here - CPU may be hotplugged now */
hotcpu_notifier(update_sched_domains, 0);
+
+ /* Move init over to a non-isolated CPU */
+ if (set_cpus_allowed(current, non_isolated_cpus) < 0)
+ BUG();
}
#else
void __init sched_init_smp(void)
diff --git a/kernel/signal.c b/kernel/signal.c
index bfdb5686fa3e..7ed8d5304bec 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -417,9 +417,8 @@ static int collect_signal(int sig, struct sigpending *list, siginfo_t *info)
static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
siginfo_t *info)
{
- int sig = 0;
+ int sig = next_signal(pending, mask);
- sig = next_signal(pending, mask);
if (sig) {
if (current->notifier) {
if (sigismember(current->notifier_mask, sig)) {
@@ -432,9 +431,7 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
if (!collect_signal(sig, pending, info))
sig = 0;
-
}
- recalc_sigpending();
return sig;
}
@@ -451,6 +448,7 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
if (!signr)
signr = __dequeue_signal(&tsk->signal->shared_pending,
mask, info);
+ recalc_sigpending_tsk(tsk);
if (signr && unlikely(sig_kernel_stop(signr))) {
/*
* Set a marker that we have dequeued a stop signal. Our
@@ -1057,28 +1055,44 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
}
/*
- * kill_pg_info() sends a signal to a process group: this is what the tty
+ * kill_pgrp_info() sends a signal to a process group: this is what the tty
* control characters do (^C, ^Z etc)
*/
-int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
+int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
{
struct task_struct *p = NULL;
int retval, success;
- if (pgrp <= 0)
- return -EINVAL;
-
success = 0;
retval = -ESRCH;
- do_each_task_pid(pgrp, PIDTYPE_PGID, p) {
+ do_each_pid_task(pgrp, PIDTYPE_PGID, p) {
int err = group_send_sig_info(sig, info, p);
success |= !err;
retval = err;
- } while_each_task_pid(pgrp, PIDTYPE_PGID, p);
+ } while_each_pid_task(pgrp, PIDTYPE_PGID, p);
return success ? 0 : retval;
}
+int kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp)
+{
+ int retval;
+
+ read_lock(&tasklist_lock);
+ retval = __kill_pgrp_info(sig, info, pgrp);
+ read_unlock(&tasklist_lock);
+
+ return retval;
+}
+
+int __kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
+{
+ if (pgrp <= 0)
+ return -EINVAL;
+
+ return __kill_pgrp_info(sig, info, find_pid(pgrp));
+}
+
int
kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
{
@@ -1091,8 +1105,7 @@ kill_pg_info(int sig, struct siginfo *info, pid_t pgrp)
return retval;
}
-int
-kill_proc_info(int sig, struct siginfo *info, pid_t pid)
+int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
{
int error;
int acquired_tasklist_lock = 0;
@@ -1103,7 +1116,7 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
read_lock(&tasklist_lock);
acquired_tasklist_lock = 1;
}
- p = find_task_by_pid(pid);
+ p = pid_task(pid, PIDTYPE_PID);
error = -ESRCH;
if (p)
error = group_send_sig_info(sig, info, p);
@@ -1113,8 +1126,18 @@ kill_proc_info(int sig, struct siginfo *info, pid_t pid)
return error;
}
-/* like kill_proc_info(), but doesn't use uid/euid of "current" */
-int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid,
+int
+kill_proc_info(int sig, struct siginfo *info, pid_t pid)
+{
+ int error;
+ rcu_read_lock();
+ error = kill_pid_info(sig, info, find_pid(pid));
+ rcu_read_unlock();
+ return error;
+}
+
+/* like kill_pid_info(), but doesn't use uid/euid of "current" */
+int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid,
uid_t uid, uid_t euid, u32 secid)
{
int ret = -EINVAL;
@@ -1124,7 +1147,7 @@ int kill_proc_info_as_uid(int sig, struct siginfo *info, pid_t pid,
return ret;
read_lock(&tasklist_lock);
- p = find_task_by_pid(pid);
+ p = pid_task(pid, PIDTYPE_PID);
if (!p) {
ret = -ESRCH;
goto out_unlock;
@@ -1148,7 +1171,7 @@ out_unlock:
read_unlock(&tasklist_lock);
return ret;
}
-EXPORT_SYMBOL_GPL(kill_proc_info_as_uid);
+EXPORT_SYMBOL_GPL(kill_pid_info_as_uid);
/*
* kill_something_info() interprets pid in interesting ways just like kill(2).
@@ -1266,6 +1289,18 @@ force_sigsegv(int sig, struct task_struct *p)
return 0;
}
+int kill_pgrp(struct pid *pid, int sig, int priv)
+{
+ return kill_pgrp_info(sig, __si_special(priv), pid);
+}
+EXPORT_SYMBOL(kill_pgrp);
+
+int kill_pid(struct pid *pid, int sig, int priv)
+{
+ return kill_pid_info(sig, __si_special(priv), pid);
+}
+EXPORT_SYMBOL(kill_pid);
+
int
kill_pg(pid_t pgrp, int sig, int priv)
{
@@ -2577,6 +2612,11 @@ asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize)
}
#endif /* __ARCH_WANT_SYS_RT_SIGSUSPEND */
+__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ return NULL;
+}
+
void __init signals_init(void)
{
sigqueue_cachep =
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 3789ca98197c..bf25015dce16 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -612,7 +612,9 @@ static struct notifier_block __cpuinitdata cpu_nfb = {
__init int spawn_ksoftirqd(void)
{
void *cpu = (void *)(long)smp_processor_id();
- cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+ int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+
+ BUG_ON(err == NOTIFY_BAD);
cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
register_cpu_notifier(&cpu_nfb);
return 0;
diff --git a/kernel/softlockup.c b/kernel/softlockup.c
index 03e6a2b0b787..50afeb813305 100644
--- a/kernel/softlockup.c
+++ b/kernel/softlockup.c
@@ -149,8 +149,9 @@ static struct notifier_block __cpuinitdata cpu_nfb = {
__init void spawn_softlockup_task(void)
{
void *cpu = (void *)(long)smp_processor_id();
+ int err = cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
- cpu_callback(&cpu_nfb, CPU_UP_PREPARE, cpu);
+ BUG_ON(err == NOTIFY_BAD);
cpu_callback(&cpu_nfb, CPU_ONLINE, cpu);
register_cpu_notifier(&cpu_nfb);
diff --git a/kernel/spinlock.c b/kernel/spinlock.c
index 9644a41e0bef..476c3741511b 100644
--- a/kernel/spinlock.c
+++ b/kernel/spinlock.c
@@ -21,17 +21,6 @@
#include <linux/debug_locks.h>
#include <linux/module.h>
-/*
- * Generic declaration of the raw read_trylock() function,
- * architectures are supposed to optimize this:
- */
-int __lockfunc generic__raw_read_trylock(raw_rwlock_t *lock)
-{
- __raw_read_lock(lock);
- return 1;
-}
-EXPORT_SYMBOL(generic__raw_read_trylock);
-
int __lockfunc _spin_trylock(spinlock_t *lock)
{
preempt_disable();
@@ -226,7 +215,7 @@ void __lockfunc _##op##_lock(locktype##_t *lock) \
if (!(lock)->break_lock) \
(lock)->break_lock = 1; \
while (!op##_can_lock(lock) && (lock)->break_lock) \
- cpu_relax(); \
+ _raw_##op##_relax(&lock->raw_lock); \
} \
(lock)->break_lock = 0; \
} \
@@ -248,7 +237,7 @@ unsigned long __lockfunc _##op##_lock_irqsave(locktype##_t *lock) \
if (!(lock)->break_lock) \
(lock)->break_lock = 1; \
while (!op##_can_lock(lock) && (lock)->break_lock) \
- cpu_relax(); \
+ _raw_##op##_relax(&lock->raw_lock); \
} \
(lock)->break_lock = 0; \
return flags; \
diff --git a/kernel/srcu.c b/kernel/srcu.c
new file mode 100644
index 000000000000..3507cabe963b
--- /dev/null
+++ b/kernel/srcu.c
@@ -0,0 +1,258 @@
+/*
+ * Sleepable Read-Copy Update mechanism for mutual exclusion.
+ *
+ * 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) IBM Corporation, 2006
+ *
+ * Author: Paul McKenney <paulmck@us.ibm.com>
+ *
+ * For detailed explanation of Read-Copy Update mechanism see -
+ * Documentation/RCU/ *.txt
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/percpu.h>
+#include <linux/preempt.h>
+#include <linux/rcupdate.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+#include <linux/srcu.h>
+
+/**
+ * init_srcu_struct - initialize a sleep-RCU structure
+ * @sp: structure to initialize.
+ *
+ * Must invoke this on a given srcu_struct before passing that srcu_struct
+ * to any other function. Each srcu_struct represents a separate domain
+ * of SRCU protection.
+ */
+int init_srcu_struct(struct srcu_struct *sp)
+{
+ sp->completed = 0;
+ mutex_init(&sp->mutex);
+ sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array);
+ return (sp->per_cpu_ref ? 0 : -ENOMEM);
+}
+
+/*
+ * srcu_readers_active_idx -- returns approximate number of readers
+ * active on the specified rank of per-CPU counters.
+ */
+
+static int srcu_readers_active_idx(struct srcu_struct *sp, int idx)
+{
+ int cpu;
+ int sum;
+
+ sum = 0;
+ for_each_possible_cpu(cpu)
+ sum += per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx];
+ return sum;
+}
+
+/**
+ * srcu_readers_active - returns approximate number of readers.
+ * @sp: which srcu_struct to count active readers (holding srcu_read_lock).
+ *
+ * Note that this is not an atomic primitive, and can therefore suffer
+ * severe errors when invoked on an active srcu_struct. That said, it
+ * can be useful as an error check at cleanup time.
+ */
+int srcu_readers_active(struct srcu_struct *sp)
+{
+ return srcu_readers_active_idx(sp, 0) + srcu_readers_active_idx(sp, 1);
+}
+
+/**
+ * cleanup_srcu_struct - deconstruct a sleep-RCU structure
+ * @sp: structure to clean up.
+ *
+ * Must invoke this after you are finished using a given srcu_struct that
+ * was initialized via init_srcu_struct(), else you leak memory.
+ */
+void cleanup_srcu_struct(struct srcu_struct *sp)
+{
+ int sum;
+
+ sum = srcu_readers_active(sp);
+ WARN_ON(sum); /* Leakage unless caller handles error. */
+ if (sum != 0)
+ return;
+ free_percpu(sp->per_cpu_ref);
+ sp->per_cpu_ref = NULL;
+}
+
+/**
+ * srcu_read_lock - register a new reader for an SRCU-protected structure.
+ * @sp: srcu_struct in which to register the new reader.
+ *
+ * Counts the new reader in the appropriate per-CPU element of the
+ * srcu_struct. Must be called from process context.
+ * Returns an index that must be passed to the matching srcu_read_unlock().
+ */
+int srcu_read_lock(struct srcu_struct *sp)
+{
+ int idx;
+
+ preempt_disable();
+ idx = sp->completed & 0x1;
+ barrier(); /* ensure compiler looks -once- at sp->completed. */
+ per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]++;
+ srcu_barrier(); /* ensure compiler won't misorder critical section. */
+ preempt_enable();
+ return idx;
+}
+
+/**
+ * srcu_read_unlock - unregister a old reader from an SRCU-protected structure.
+ * @sp: srcu_struct in which to unregister the old reader.
+ * @idx: return value from corresponding srcu_read_lock().
+ *
+ * Removes the count for the old reader from the appropriate per-CPU
+ * element of the srcu_struct. Note that this may well be a different
+ * CPU than that which was incremented by the corresponding srcu_read_lock().
+ * Must be called from process context.
+ */
+void srcu_read_unlock(struct srcu_struct *sp, int idx)
+{
+ preempt_disable();
+ srcu_barrier(); /* ensure compiler won't misorder critical section. */
+ per_cpu_ptr(sp->per_cpu_ref, smp_processor_id())->c[idx]--;
+ preempt_enable();
+}
+
+/**
+ * synchronize_srcu - wait for prior SRCU read-side critical-section completion
+ * @sp: srcu_struct with which to synchronize.
+ *
+ * Flip the completed counter, and wait for the old count to drain to zero.
+ * As with classic RCU, the updater must use some separate means of
+ * synchronizing concurrent updates. Can block; must be called from
+ * process context.
+ *
+ * Note that it is illegal to call synchornize_srcu() from the corresponding
+ * SRCU read-side critical section; doing so will result in deadlock.
+ * However, it is perfectly legal to call synchronize_srcu() on one
+ * srcu_struct from some other srcu_struct's read-side critical section.
+ */
+void synchronize_srcu(struct srcu_struct *sp)
+{
+ int idx;
+
+ idx = sp->completed;
+ mutex_lock(&sp->mutex);
+
+ /*
+ * Check to see if someone else did the work for us while we were
+ * waiting to acquire the lock. We need -two- advances of
+ * the counter, not just one. If there was but one, we might have
+ * shown up -after- our helper's first synchronize_sched(), thus
+ * having failed to prevent CPU-reordering races with concurrent
+ * srcu_read_unlock()s on other CPUs (see comment below). So we
+ * either (1) wait for two or (2) supply the second ourselves.
+ */
+
+ if ((sp->completed - idx) >= 2) {
+ mutex_unlock(&sp->mutex);
+ return;
+ }
+
+ synchronize_sched(); /* Force memory barrier on all CPUs. */
+
+ /*
+ * The preceding synchronize_sched() ensures that any CPU that
+ * sees the new value of sp->completed will also see any preceding
+ * changes to data structures made by this CPU. This prevents
+ * some other CPU from reordering the accesses in its SRCU
+ * read-side critical section to precede the corresponding
+ * srcu_read_lock() -- ensuring that such references will in
+ * fact be protected.
+ *
+ * So it is now safe to do the flip.
+ */
+
+ idx = sp->completed & 0x1;
+ sp->completed++;
+
+ synchronize_sched(); /* Force memory barrier on all CPUs. */
+
+ /*
+ * At this point, because of the preceding synchronize_sched(),
+ * all srcu_read_lock() calls using the old counters have completed.
+ * Their corresponding critical sections might well be still
+ * executing, but the srcu_read_lock() primitives themselves
+ * will have finished executing.
+ */
+
+ while (srcu_readers_active_idx(sp, idx))
+ schedule_timeout_interruptible(1);
+
+ synchronize_sched(); /* Force memory barrier on all CPUs. */
+
+ /*
+ * The preceding synchronize_sched() forces all srcu_read_unlock()
+ * primitives that were executing concurrently with the preceding
+ * for_each_possible_cpu() loop to have completed by this point.
+ * More importantly, it also forces the corresponding SRCU read-side
+ * critical sections to have also completed, and the corresponding
+ * references to SRCU-protected data items to be dropped.
+ *
+ * Note:
+ *
+ * Despite what you might think at first glance, the
+ * preceding synchronize_sched() -must- be within the
+ * critical section ended by the following mutex_unlock().
+ * Otherwise, a task taking the early exit can race
+ * with a srcu_read_unlock(), which might have executed
+ * just before the preceding srcu_readers_active() check,
+ * and whose CPU might have reordered the srcu_read_unlock()
+ * with the preceding critical section. In this case, there
+ * is nothing preventing the synchronize_sched() task that is
+ * taking the early exit from freeing a data structure that
+ * is still being referenced (out of order) by the task
+ * doing the srcu_read_unlock().
+ *
+ * Alternatively, the comparison with "2" on the early exit
+ * could be changed to "3", but this increases synchronize_srcu()
+ * latency for bulk loads. So the current code is preferred.
+ */
+
+ mutex_unlock(&sp->mutex);
+}
+
+/**
+ * srcu_batches_completed - return batches completed.
+ * @sp: srcu_struct on which to report batch completion.
+ *
+ * Report the number of batches, correlated with, but not necessarily
+ * precisely the same as, the number of grace periods that have elapsed.
+ */
+
+long srcu_batches_completed(struct srcu_struct *sp)
+{
+ return sp->completed;
+}
+
+EXPORT_SYMBOL_GPL(init_srcu_struct);
+EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
+EXPORT_SYMBOL_GPL(srcu_read_lock);
+EXPORT_SYMBOL_GPL(srcu_read_unlock);
+EXPORT_SYMBOL_GPL(synchronize_srcu);
+EXPORT_SYMBOL_GPL(srcu_batches_completed);
+EXPORT_SYMBOL_GPL(srcu_readers_active);
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c
index 51cacd111dbd..12458040e665 100644
--- a/kernel/stop_machine.c
+++ b/kernel/stop_machine.c
@@ -1,3 +1,6 @@
+/* Copyright 2005 Rusty Russell rusty@rustcorp.com.au IBM Corporation.
+ * GPL v2 and any later version.
+ */
#include <linux/stop_machine.h>
#include <linux/kthread.h>
#include <linux/sched.h>
diff --git a/kernel/sys.c b/kernel/sys.c
index 3f894775488d..98489d82801b 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -92,7 +92,8 @@ EXPORT_SYMBOL(fs_overflowgid);
*/
int C_A_D = 1;
-int cad_pid = 1;
+struct pid *cad_pid;
+EXPORT_SYMBOL(cad_pid);
/*
* Notifier list for kernel code which wants to be called
@@ -152,7 +153,7 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl,
/*
* Atomic notifier chain routines. Registration and unregistration
- * use a mutex, and call_chain is synchronized by RCU (no locks).
+ * use a spinlock, and call_chain is synchronized by RCU (no locks).
*/
/**
@@ -221,7 +222,7 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
* of the last notifier function called.
*/
-int atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
unsigned long val, void *v)
{
int ret;
@@ -400,6 +401,129 @@ int raw_notifier_call_chain(struct raw_notifier_head *nh,
EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
+/*
+ * SRCU notifier chain routines. Registration and unregistration
+ * use a mutex, and call_chain is synchronized by SRCU (no locks).
+ */
+
+/**
+ * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain
+ * @nh: Pointer to head of the SRCU notifier chain
+ * @n: New entry in notifier chain
+ *
+ * Adds a notifier to an SRCU notifier chain.
+ * Must be called in process context.
+ *
+ * Currently always returns zero.
+ */
+
+int srcu_notifier_chain_register(struct srcu_notifier_head *nh,
+ struct notifier_block *n)
+{
+ int ret;
+
+ /*
+ * This code gets used during boot-up, when task switching is
+ * not yet working and interrupts must remain disabled. At
+ * such times we must not call mutex_lock().
+ */
+ if (unlikely(system_state == SYSTEM_BOOTING))
+ return notifier_chain_register(&nh->head, n);
+
+ mutex_lock(&nh->mutex);
+ ret = notifier_chain_register(&nh->head, n);
+ mutex_unlock(&nh->mutex);
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_chain_register);
+
+/**
+ * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain
+ * @nh: Pointer to head of the SRCU notifier chain
+ * @n: Entry to remove from notifier chain
+ *
+ * Removes a notifier from an SRCU notifier chain.
+ * Must be called from process context.
+ *
+ * Returns zero on success or %-ENOENT on failure.
+ */
+int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
+ struct notifier_block *n)
+{
+ int ret;
+
+ /*
+ * This code gets used during boot-up, when task switching is
+ * not yet working and interrupts must remain disabled. At
+ * such times we must not call mutex_lock().
+ */
+ if (unlikely(system_state == SYSTEM_BOOTING))
+ return notifier_chain_unregister(&nh->head, n);
+
+ mutex_lock(&nh->mutex);
+ ret = notifier_chain_unregister(&nh->head, n);
+ mutex_unlock(&nh->mutex);
+ synchronize_srcu(&nh->srcu);
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
+
+/**
+ * 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
+ *
+ * Calls each function in a notifier chain in turn. The functions
+ * run in a process context, so they are allowed to block.
+ *
+ * If the return value of the notifier can be and'ed
+ * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain
+ * will return immediately, with the return value of
+ * the notifier function which halted execution.
+ * Otherwise the return value is the return value
+ * of the last notifier function called.
+ */
+
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+ unsigned long val, void *v)
+{
+ int ret;
+ int idx;
+
+ idx = srcu_read_lock(&nh->srcu);
+ ret = notifier_call_chain(&nh->head, val, v);
+ srcu_read_unlock(&nh->srcu, idx);
+ return ret;
+}
+
+EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
+
+/**
+ * srcu_init_notifier_head - Initialize an SRCU notifier head
+ * @nh: Pointer to head of the srcu notifier chain
+ *
+ * Unlike other sorts of notifier heads, SRCU notifier heads require
+ * dynamic initialization. Be sure to call this routine before
+ * calling any of the other SRCU notifier routines for this head.
+ *
+ * If an SRCU notifier head is deallocated, it must first be cleaned
+ * up by calling srcu_cleanup_notifier_head(). Otherwise the head's
+ * per-cpu data (used by the SRCU mechanism) will leak.
+ */
+
+void srcu_init_notifier_head(struct srcu_notifier_head *nh)
+{
+ mutex_init(&nh->mutex);
+ if (init_srcu_struct(&nh->srcu) < 0)
+ BUG();
+ nh->head = NULL;
+}
+
+EXPORT_SYMBOL_GPL(srcu_init_notifier_head);
+
/**
* register_reboot_notifier - Register function to be called at reboot time
* @nb: Info about notifier function to be called
@@ -607,12 +731,10 @@ static void kernel_restart_prepare(char *cmd)
void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);
- if (!cmd) {
+ if (!cmd)
printk(KERN_EMERG "Restarting system.\n");
- } else {
+ else
printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
- }
- printk(".\n");
machine_restart(cmd);
}
EXPORT_SYMBOL_GPL(kernel_restart);
@@ -628,9 +750,8 @@ static void kernel_kexec(void)
#ifdef CONFIG_KEXEC
struct kimage *image;
image = xchg(&kexec_image, NULL);
- if (!image) {
+ if (!image)
return;
- }
kernel_restart_prepare(NULL);
printk(KERN_EMERG "Starting new kernel\n");
machine_shutdown();
@@ -776,10 +897,9 @@ void ctrl_alt_del(void)
if (C_A_D)
schedule_work(&cad_work);
else
- kill_proc(cad_pid, SIGINT, 1);
+ kill_cad_pid(SIGINT, 1);
}
-
/*
* Unprivileged users may change the real gid to the effective gid
* or vice versa. (BSD-style)
@@ -824,12 +944,10 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
(current->sgid == egid) ||
capable(CAP_SETGID))
new_egid = egid;
- else {
+ else
return -EPERM;
- }
}
- if (new_egid != old_egid)
- {
+ if (new_egid != old_egid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -858,19 +976,14 @@ asmlinkage long sys_setgid(gid_t gid)
if (retval)
return retval;
- if (capable(CAP_SETGID))
- {
- if(old_egid != gid)
- {
+ if (capable(CAP_SETGID)) {
+ if (old_egid != gid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
current->gid = current->egid = current->sgid = current->fsgid = gid;
- }
- else if ((gid == current->gid) || (gid == current->sgid))
- {
- if(old_egid != gid)
- {
+ } else if ((gid == current->gid) || (gid == current->sgid)) {
+ if (old_egid != gid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -901,8 +1014,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
switch_uid(new_user);
- if(dumpclear)
- {
+ if (dumpclear) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -958,8 +1070,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0)
return -EAGAIN;
- if (new_euid != old_euid)
- {
+ if (new_euid != old_euid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -1009,8 +1120,7 @@ asmlinkage long sys_setuid(uid_t uid)
} else if ((uid != current->uid) && (uid != new_suid))
return -EPERM;
- if (old_euid != uid)
- {
+ if (old_euid != uid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -1055,8 +1165,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
return -EAGAIN;
}
if (euid != (uid_t) -1) {
- if (euid != current->euid)
- {
+ if (euid != current->euid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -1106,8 +1215,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
return -EPERM;
}
if (egid != (gid_t) -1) {
- if (egid != current->egid)
- {
+ if (egid != current->egid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -1152,10 +1260,8 @@ asmlinkage long sys_setfsuid(uid_t uid)
if (uid == current->uid || uid == current->euid ||
uid == current->suid || uid == current->fsuid ||
- capable(CAP_SETUID))
- {
- if (uid != old_fsuid)
- {
+ capable(CAP_SETUID)) {
+ if (uid != old_fsuid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -1183,10 +1289,8 @@ asmlinkage long sys_setfsgid(gid_t gid)
if (gid == current->gid || gid == current->egid ||
gid == current->sgid || gid == current->fsgid ||
- capable(CAP_SETGID))
- {
- if (gid != old_fsgid)
- {
+ capable(CAP_SETGID)) {
+ if (gid != old_fsgid) {
current->mm->dumpable = suid_dumpable;
smp_wmb();
}
@@ -1322,9 +1426,9 @@ out:
asmlinkage long sys_getpgid(pid_t pid)
{
- if (!pid) {
+ if (!pid)
return process_group(current);
- } else {
+ else {
int retval;
struct task_struct *p;
@@ -1354,9 +1458,9 @@ asmlinkage long sys_getpgrp(void)
asmlinkage long sys_getsid(pid_t pid)
{
- if (!pid) {
+ if (!pid)
return current->signal->session;
- } else {
+ else {
int retval;
struct task_struct *p;
@@ -1364,7 +1468,7 @@ asmlinkage long sys_getsid(pid_t pid)
p = find_task_by_pid(pid);
retval = -ESRCH;
- if(p) {
+ if (p) {
retval = security_task_getsid(p);
if (!retval)
retval = p->signal->session;
@@ -1432,9 +1536,9 @@ struct group_info *groups_alloc(int gidsetsize)
group_info->nblocks = nblocks;
atomic_set(&group_info->usage, 1);
- if (gidsetsize <= NGROUPS_SMALL) {
+ if (gidsetsize <= NGROUPS_SMALL)
group_info->blocks[0] = group_info->small_block;
- } else {
+ else {
for (i = 0; i < nblocks; i++) {
gid_t *b;
b = (void *)__get_free_page(GFP_USER);
@@ -1490,7 +1594,7 @@ static int groups_to_user(gid_t __user *grouplist,
/* fill a group_info from a user-space array - it must be allocated already */
static int groups_from_user(struct group_info *group_info,
gid_t __user *grouplist)
- {
+{
int i;
int count = group_info->ngroups;
@@ -1648,9 +1752,8 @@ asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
int in_group_p(gid_t grp)
{
int retval = 1;
- if (grp != current->fsgid) {
+ if (grp != current->fsgid)
retval = groups_search(current->group_info, grp);
- }
return retval;
}
@@ -1659,9 +1762,8 @@ EXPORT_SYMBOL(in_group_p);
int in_egroup_p(gid_t grp)
{
int retval = 1;
- if (grp != current->egid) {
+ if (grp != current->egid)
retval = groups_search(current->group_info, grp);
- }
return retval;
}
@@ -1676,7 +1778,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name)
int errno = 0;
down_read(&uts_sem);
- if (copy_to_user(name,&system_utsname,sizeof *name))
+ if (copy_to_user(name, utsname(), sizeof *name))
errno = -EFAULT;
up_read(&uts_sem);
return errno;
@@ -1694,8 +1796,8 @@ asmlinkage long sys_sethostname(char __user *name, int len)
down_write(&uts_sem);
errno = -EFAULT;
if (!copy_from_user(tmp, name, len)) {
- memcpy(system_utsname.nodename, tmp, len);
- system_utsname.nodename[len] = 0;
+ memcpy(utsname()->nodename, tmp, len);
+ utsname()->nodename[len] = 0;
errno = 0;
}
up_write(&uts_sem);
@@ -1711,11 +1813,11 @@ asmlinkage long sys_gethostname(char __user *name, int len)
if (len < 0)
return -EINVAL;
down_read(&uts_sem);
- i = 1 + strlen(system_utsname.nodename);
+ i = 1 + strlen(utsname()->nodename);
if (i > len)
i = len;
errno = 0;
- if (copy_to_user(name, system_utsname.nodename, i))
+ if (copy_to_user(name, utsname()->nodename, i))
errno = -EFAULT;
up_read(&uts_sem);
return errno;
@@ -1740,8 +1842,8 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
down_write(&uts_sem);
errno = -EFAULT;
if (!copy_from_user(tmp, name, len)) {
- memcpy(system_utsname.domainname, tmp, len);
- system_utsname.domainname[len] = 0;
+ memcpy(utsname()->domainname, tmp, len);
+ utsname()->domainname[len] = 0;
errno = 0;
}
up_write(&uts_sem);
@@ -1776,9 +1878,9 @@ asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *r
task_lock(current->group_leader);
x = current->signal->rlim[resource];
task_unlock(current->group_leader);
- if(x.rlim_cur > 0x7FFFFFFF)
+ if (x.rlim_cur > 0x7FFFFFFF)
x.rlim_cur = 0x7FFFFFFF;
- if(x.rlim_max > 0x7FFFFFFF)
+ if (x.rlim_max > 0x7FFFFFFF)
x.rlim_max = 0x7FFFFFFF;
return copy_to_user(rlim, &x, sizeof(x))?-EFAULT:0;
}
@@ -2084,12 +2186,12 @@ asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep,
* padding
*/
unsigned long t0, t1;
- get_user(t0, &cache->t0);
- get_user(t1, &cache->t1);
+ get_user(t0, &cache->blob[0]);
+ get_user(t1, &cache->blob[1]);
t0++;
t1++;
- put_user(t0, &cache->t0);
- put_user(t1, &cache->t1);
+ put_user(t0, &cache->blob[0]);
+ put_user(t1, &cache->blob[1]);
}
return err ? -EFAULT : 0;
}
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 6991bece67e8..0e53314b14de 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -49,6 +49,7 @@ cond_syscall(compat_sys_get_robust_list);
cond_syscall(sys_epoll_create);
cond_syscall(sys_epoll_ctl);
cond_syscall(sys_epoll_wait);
+cond_syscall(sys_epoll_pwait);
cond_syscall(sys_semget);
cond_syscall(sys_semop);
cond_syscall(sys_semtimedop);
@@ -134,3 +135,8 @@ cond_syscall(sys_madvise);
cond_syscall(sys_mremap);
cond_syscall(sys_remap_file_pages);
cond_syscall(compat_sys_move_pages);
+
+/* block-layer dependent */
+cond_syscall(sys_bdflush);
+cond_syscall(sys_ioprio_set);
+cond_syscall(sys_ioprio_get);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index bcb3a181dbb2..8bff2c18fb5a 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -52,6 +52,10 @@
extern int proc_nr_files(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
+#ifdef CONFIG_X86
+#include <asm/nmi.h>
+#endif
+
#if defined(CONFIG_SYSCTL)
/* External variables not in a header file. */
@@ -64,7 +68,6 @@ extern int sysrq_enabled;
extern int core_uses_pid;
extern int suid_dumpable;
extern char core_pattern[];
-extern int cad_pid;
extern int pid_max;
extern int min_free_kbytes;
extern int printk_ratelimit_jiffies;
@@ -74,13 +77,6 @@ extern int sysctl_drop_caches;
extern int percpu_pagelist_fraction;
extern int compat_log;
-#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
-int unknown_nmi_panic;
-int nmi_watchdog_enabled;
-extern int proc_nmi_enabled(struct ctl_table *, int , struct file *,
- void __user *, size_t *, loff_t *);
-#endif
-
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
static int maxolduid = 65535;
static int minolduid;
@@ -95,13 +91,8 @@ extern char modprobe_path[];
extern int sg_big_buff;
#endif
#ifdef CONFIG_SYSVIPC
-extern size_t shm_ctlmax;
-extern size_t shm_ctlall;
-extern int shm_ctlmni;
-extern int msg_ctlmax;
-extern int msg_ctlmnb;
-extern int msg_ctlmni;
-extern int sem_ctls[];
+static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
#endif
#ifdef __sparc__
@@ -137,11 +128,19 @@ extern int no_unaligned_warning;
extern int max_lock_depth;
#endif
-static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
- ctl_table *, void **);
-static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+#ifdef CONFIG_SYSCTL_SYSCALL
+static int parse_table(int __user *, int, void __user *, size_t __user *,
+ void __user *, size_t, ctl_table *, void **);
+#endif
+
+static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos);
+#ifdef CONFIG_PROC_SYSCTL
+static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos);
+#endif
+
static ctl_table root_table[];
static struct ctl_table_header root_table_header =
{ root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
@@ -165,7 +164,7 @@ int sysctl_legacy_va_layout;
/* /proc declarations: */
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *);
static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *);
@@ -229,51 +228,100 @@ static ctl_table root_table[] = {
};
static ctl_table kern_table[] = {
+#ifndef CONFIG_UTS_NS
+ {
+ .ctl_name = KERN_OSTYPE,
+ .procname = "ostype",
+ .data = init_uts_ns.name.sysname,
+ .maxlen = sizeof(init_uts_ns.name.sysname),
+ .mode = 0444,
+ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_OSRELEASE,
+ .procname = "osrelease",
+ .data = init_uts_ns.name.release,
+ .maxlen = sizeof(init_uts_ns.name.release),
+ .mode = 0444,
+ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_VERSION,
+ .procname = "version",
+ .data = init_uts_ns.name.version,
+ .maxlen = sizeof(init_uts_ns.name.version),
+ .mode = 0444,
+ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_NODENAME,
+ .procname = "hostname",
+ .data = init_uts_ns.name.nodename,
+ .maxlen = sizeof(init_uts_ns.name.nodename),
+ .mode = 0644,
+ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+ {
+ .ctl_name = KERN_DOMAINNAME,
+ .procname = "domainname",
+ .data = init_uts_ns.name.domainname,
+ .maxlen = sizeof(init_uts_ns.name.domainname),
+ .mode = 0644,
+ .proc_handler = &proc_do_uts_string,
+ .strategy = &sysctl_string,
+ },
+#else /* !CONFIG_UTS_NS */
{
.ctl_name = KERN_OSTYPE,
.procname = "ostype",
- .data = system_utsname.sysname,
- .maxlen = sizeof(system_utsname.sysname),
+ .data = NULL,
+ /* could maybe use __NEW_UTS_LEN here? */
+ .maxlen = FIELD_SIZEOF(struct new_utsname, sysname),
.mode = 0444,
- .proc_handler = &proc_doutsstring,
+ .proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_OSRELEASE,
.procname = "osrelease",
- .data = system_utsname.release,
- .maxlen = sizeof(system_utsname.release),
+ .data = NULL,
+ .maxlen = FIELD_SIZEOF(struct new_utsname, release),
.mode = 0444,
- .proc_handler = &proc_doutsstring,
+ .proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_VERSION,
.procname = "version",
- .data = system_utsname.version,
- .maxlen = sizeof(system_utsname.version),
+ .data = NULL,
+ .maxlen = FIELD_SIZEOF(struct new_utsname, version),
.mode = 0444,
- .proc_handler = &proc_doutsstring,
+ .proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_NODENAME,
.procname = "hostname",
- .data = system_utsname.nodename,
- .maxlen = sizeof(system_utsname.nodename),
+ .data = NULL,
+ .maxlen = FIELD_SIZEOF(struct new_utsname, nodename),
.mode = 0644,
- .proc_handler = &proc_doutsstring,
+ .proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
{
.ctl_name = KERN_DOMAINNAME,
.procname = "domainname",
- .data = system_utsname.domainname,
- .maxlen = sizeof(system_utsname.domainname),
+ .data = NULL,
+ .maxlen = FIELD_SIZEOF(struct new_utsname, domainname),
.mode = 0644,
- .proc_handler = &proc_doutsstring,
+ .proc_handler = &proc_do_uts_string,
.strategy = &sysctl_string,
},
+#endif /* !CONFIG_UTS_NS */
{
.ctl_name = KERN_PANIC,
.procname = "panic",
@@ -294,7 +342,7 @@ static ctl_table kern_table[] = {
.ctl_name = KERN_CORE_PATTERN,
.procname = "core_pattern",
.data = core_pattern,
- .maxlen = 64,
+ .maxlen = 128,
.mode = 0644,
.proc_handler = &proc_dostring,
.strategy = &sysctl_string,
@@ -432,58 +480,58 @@ static ctl_table kern_table[] = {
{
.ctl_name = KERN_SHMMAX,
.procname = "shmmax",
- .data = &shm_ctlmax,
+ .data = NULL,
.maxlen = sizeof (size_t),
.mode = 0644,
- .proc_handler = &proc_doulongvec_minmax,
+ .proc_handler = &proc_do_ipc_string,
},
{
.ctl_name = KERN_SHMALL,
.procname = "shmall",
- .data = &shm_ctlall,
+ .data = NULL,
.maxlen = sizeof (size_t),
.mode = 0644,
- .proc_handler = &proc_doulongvec_minmax,
+ .proc_handler = &proc_do_ipc_string,
},
{
.ctl_name = KERN_SHMMNI,
.procname = "shmmni",
- .data = &shm_ctlmni,
+ .data = NULL,
.maxlen = sizeof (int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_do_ipc_string,
},
{
.ctl_name = KERN_MSGMAX,
.procname = "msgmax",
- .data = &msg_ctlmax,
+ .data = NULL,
.maxlen = sizeof (int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_do_ipc_string,
},
{
.ctl_name = KERN_MSGMNI,
.procname = "msgmni",
- .data = &msg_ctlmni,
+ .data = NULL,
.maxlen = sizeof (int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_do_ipc_string,
},
{
.ctl_name = KERN_MSGMNB,
.procname = "msgmnb",
- .data = &msg_ctlmnb,
+ .data = NULL,
.maxlen = sizeof (int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_do_ipc_string,
},
{
.ctl_name = KERN_SEM,
.procname = "sem",
- .data = &sem_ctls,
+ .data = NULL,
.maxlen = 4*sizeof (int),
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_do_ipc_string,
},
#endif
#ifdef CONFIG_MAGIC_SYSRQ
@@ -496,14 +544,16 @@ static ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
+#ifdef CONFIG_PROC_SYSCTL
{
.ctl_name = KERN_CADPID,
.procname = "cad_pid",
- .data = &cad_pid,
+ .data = NULL,
.maxlen = sizeof (int),
.mode = 0600,
- .proc_handler = &proc_dointvec,
+ .proc_handler = &proc_do_cad_pid,
},
+#endif
{
.ctl_name = KERN_MAX_THREADS,
.procname = "threads-max",
@@ -1166,12 +1216,13 @@ static void start_unregistering(struct ctl_table_header *p)
void __init sysctl_init(void)
{
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
register_proc_table(root_table, proc_sys_root, &root_table_header);
init_irq_proc();
#endif
}
+#ifdef CONFIG_SYSCTL_SYSCALL
int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen)
{
@@ -1225,6 +1276,7 @@ asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
unlock_kernel();
return error;
}
+#endif /* CONFIG_SYSCTL_SYSCALL */
/*
* ctl_perm does NOT grant the superuser all rights automatically, because
@@ -1251,6 +1303,7 @@ static inline int ctl_perm(ctl_table *table, int op)
return test_perm(table->mode, op);
}
+#ifdef CONFIG_SYSCTL_SYSCALL
static int parse_table(int __user *name, int nlen,
void __user *oldval, size_t __user *oldlenp,
void __user *newval, size_t newlen,
@@ -1340,6 +1393,7 @@ int do_sysctl_strategy (ctl_table *table,
}
return 0;
}
+#endif /* CONFIG_SYSCTL_SYSCALL */
/**
* register_sysctl_table - register a sysctl hierarchy
@@ -1427,7 +1481,7 @@ struct ctl_table_header *register_sysctl_table(ctl_table * table,
else
list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
spin_unlock(&sysctl_lock);
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
register_proc_table(table, proc_sys_root, tmp);
#endif
return tmp;
@@ -1445,18 +1499,31 @@ void unregister_sysctl_table(struct ctl_table_header * header)
might_sleep();
spin_lock(&sysctl_lock);
start_unregistering(header);
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
unregister_proc_table(header->ctl_table, proc_sys_root);
#endif
spin_unlock(&sysctl_lock);
kfree(header);
}
+#else /* !CONFIG_SYSCTL */
+struct ctl_table_header * register_sysctl_table(ctl_table * table,
+ int insert_at_head)
+{
+ return NULL;
+}
+
+void unregister_sysctl_table(struct ctl_table_header * table)
+{
+}
+
+#endif /* CONFIG_SYSCTL */
+
/*
* /proc/sys support
*/
-#ifdef CONFIG_PROC_FS
+#ifdef CONFIG_PROC_SYSCTL
/* Scan the sysctl entries in table and add them all into /proc */
static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set)
@@ -1607,32 +1674,15 @@ static ssize_t proc_writesys(struct file * file, const char __user * buf,
return do_rw_proc(1, file, (char __user *) buf, count, ppos);
}
-/**
- * proc_dostring - read a string sysctl
- * @table: the sysctl table
- * @write: %TRUE if this is a write to the sysctl file
- * @filp: the file structure
- * @buffer: the user buffer
- * @lenp: the size of the user buffer
- * @ppos: file position
- *
- * Reads/writes a string from/to the user buffer. If the kernel
- * buffer provided is not large enough to hold the string, the
- * string is truncated. The copied string is %NULL-terminated.
- * If the string is being read by the user process, it is copied
- * and a newline '\n' is added. It is truncated if the buffer is
- * not large enough.
- *
- * Returns 0 on success.
- */
-int proc_dostring(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
+static int _proc_do_string(void* data, int maxlen, int write,
+ struct file *filp, void __user *buffer,
+ size_t *lenp, loff_t *ppos)
{
size_t len;
char __user *p;
char c;
- if (!table->data || !table->maxlen || !*lenp ||
+ if (!data || !maxlen || !*lenp ||
(*ppos && !write)) {
*lenp = 0;
return 0;
@@ -1648,20 +1698,20 @@ int proc_dostring(ctl_table *table, int write, struct file *filp,
break;
len++;
}
- if (len >= table->maxlen)
- len = table->maxlen-1;
- if(copy_from_user(table->data, buffer, len))
+ if (len >= maxlen)
+ len = maxlen-1;
+ if(copy_from_user(data, buffer, len))
return -EFAULT;
- ((char *) table->data)[len] = 0;
+ ((char *) data)[len] = 0;
*ppos += *lenp;
} else {
- len = strlen(table->data);
- if (len > table->maxlen)
- len = table->maxlen;
+ len = strlen(data);
+ if (len > maxlen)
+ len = maxlen;
if (len > *lenp)
len = *lenp;
if (len)
- if(copy_to_user(buffer, table->data, len))
+ if(copy_to_user(buffer, data, len))
return -EFAULT;
if (len < *lenp) {
if(put_user('\n', ((char __user *) buffer) + len))
@@ -1674,12 +1724,38 @@ int proc_dostring(ctl_table *table, int write, struct file *filp,
return 0;
}
+/**
+ * proc_dostring - read a string sysctl
+ * @table: the sysctl table
+ * @write: %TRUE if this is a write to the sysctl file
+ * @filp: the file structure
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * Reads/writes a string from/to the user buffer. If the kernel
+ * buffer provided is not large enough to hold the string, the
+ * string is truncated. The copied string is %NULL-terminated.
+ * If the string is being read by the user process, it is copied
+ * and a newline '\n' is added. It is truncated if the buffer is
+ * not large enough.
+ *
+ * Returns 0 on success.
+ */
+int proc_dostring(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return _proc_do_string(table->data, table->maxlen, write, filp,
+ buffer, lenp, ppos);
+}
+
/*
* Special case of dostring for the UTS structure. This has locks
* to observe. Should this be in kernel/sys.c ????
*/
-static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
+#ifndef CONFIG_UTS_NS
+static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int r;
@@ -1695,6 +1771,48 @@ static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
}
return r;
}
+#else /* !CONFIG_UTS_NS */
+static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ int r;
+ struct uts_namespace* uts_ns = current->nsproxy->uts_ns;
+ char* which;
+
+ switch (table->ctl_name) {
+ case KERN_OSTYPE:
+ which = uts_ns->name.sysname;
+ break;
+ case KERN_NODENAME:
+ which = uts_ns->name.nodename;
+ break;
+ case KERN_OSRELEASE:
+ which = uts_ns->name.release;
+ break;
+ case KERN_VERSION:
+ which = uts_ns->name.version;
+ break;
+ case KERN_DOMAINNAME:
+ which = uts_ns->name.domainname;
+ break;
+ default:
+ r = -EINVAL;
+ goto out;
+ }
+
+ if (!write) {
+ down_read(&uts_sem);
+ r=_proc_do_string(which,table->maxlen,0,filp,buffer,lenp, ppos);
+ up_read(&uts_sem);
+ } else {
+ down_write(&uts_sem);
+ r=_proc_do_string(which,table->maxlen,1,filp,buffer,lenp, ppos);
+ up_write(&uts_sem);
+ }
+ out:
+ return r;
+}
+#endif /* !CONFIG_UTS_NS */
static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
int *valp,
@@ -1715,8 +1833,9 @@ static int do_proc_dointvec_conv(int *negp, unsigned long *lvalp,
return 0;
}
-static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos,
+static int __do_proc_dointvec(void *tbl_data, ctl_table *table,
+ int write, struct file *filp, void __user *buffer,
+ size_t *lenp, loff_t *ppos,
int (*conv)(int *negp, unsigned long *lvalp, int *valp,
int write, void *data),
void *data)
@@ -1729,13 +1848,13 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
char buf[TMPBUFLEN], *p;
char __user *s = buffer;
- if (!table->data || !table->maxlen || !*lenp ||
+ if (!tbl_data || !table->maxlen || !*lenp ||
(*ppos && !write)) {
*lenp = 0;
return 0;
}
- i = (int *) table->data;
+ i = (int *) tbl_data;
vleft = table->maxlen / sizeof(*i);
left = *lenp;
@@ -1824,6 +1943,16 @@ static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
#undef TMPBUFLEN
}
+static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos,
+ int (*conv)(int *negp, unsigned long *lvalp, int *valp,
+ int write, void *data),
+ void *data)
+{
+ return __do_proc_dointvec(table->data, table, write, filp,
+ buffer, lenp, ppos, conv, data);
+}
+
/**
* proc_dointvec - read a vector of integers
* @table: the sysctl table
@@ -1895,7 +2024,7 @@ int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
return -EPERM;
}
- op = (current->pid == 1) ? OP_SET : OP_AND;
+ op = is_init(current) ? OP_SET : OP_AND;
return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
do_proc_dointvec_bset_conv,&op);
}
@@ -1957,7 +2086,7 @@ int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
do_proc_dointvec_minmax_conv, &param);
}
-static int do_proc_doulongvec_minmax(ctl_table *table, int write,
+static int __do_proc_doulongvec_minmax(void *data, ctl_table *table, int write,
struct file *filp,
void __user *buffer,
size_t *lenp, loff_t *ppos,
@@ -1971,13 +2100,13 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write,
char buf[TMPBUFLEN], *p;
char __user *s = buffer;
- if (!table->data || !table->maxlen || !*lenp ||
+ if (!data || !table->maxlen || !*lenp ||
(*ppos && !write)) {
*lenp = 0;
return 0;
}
- i = (unsigned long *) table->data;
+ i = (unsigned long *) data;
min = (unsigned long *) table->extra1;
max = (unsigned long *) table->extra2;
vleft = table->maxlen / sizeof(unsigned long);
@@ -2062,6 +2191,17 @@ static int do_proc_doulongvec_minmax(ctl_table *table, int write,
#undef TMPBUFLEN
}
+static int do_proc_doulongvec_minmax(ctl_table *table, int write,
+ struct file *filp,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos,
+ unsigned long convmul,
+ unsigned long convdiv)
+{
+ return __do_proc_doulongvec_minmax(table->data, table, write,
+ filp, buffer, lenp, ppos, convmul, convdiv);
+}
+
/**
* proc_doulongvec_minmax - read a vector of long integers with min/max values
* @table: the sysctl table
@@ -2250,6 +2390,71 @@ int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp,
do_proc_dointvec_ms_jiffies_conv, NULL);
}
+#ifdef CONFIG_SYSVIPC
+static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ void *data;
+ struct ipc_namespace *ns;
+
+ ns = current->nsproxy->ipc_ns;
+
+ switch (table->ctl_name) {
+ case KERN_SHMMAX:
+ data = &ns->shm_ctlmax;
+ goto proc_minmax;
+ case KERN_SHMALL:
+ data = &ns->shm_ctlall;
+ goto proc_minmax;
+ case KERN_SHMMNI:
+ data = &ns->shm_ctlmni;
+ break;
+ case KERN_MSGMAX:
+ data = &ns->msg_ctlmax;
+ break;
+ case KERN_MSGMNI:
+ data = &ns->msg_ctlmni;
+ break;
+ case KERN_MSGMNB:
+ data = &ns->msg_ctlmnb;
+ break;
+ case KERN_SEM:
+ data = &ns->sem_ctls;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return __do_proc_dointvec(data, table, write, filp, buffer,
+ lenp, ppos, NULL, NULL);
+proc_minmax:
+ return __do_proc_doulongvec_minmax(data, table, write, filp, buffer,
+ lenp, ppos, 1l, 1l);
+}
+#endif
+
+static int proc_do_cad_pid(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ struct pid *new_pid;
+ pid_t tmp;
+ int r;
+
+ tmp = pid_nr(cad_pid);
+
+ r = __do_proc_dointvec(&tmp, table, write, filp, buffer,
+ lenp, ppos, NULL, NULL);
+ if (r || !write)
+ return r;
+
+ new_pid = find_get_pid(tmp);
+ if (!new_pid)
+ return -ESRCH;
+
+ put_pid(xchg(&cad_pid, new_pid));
+ return 0;
+}
+
#else /* CONFIG_PROC_FS */
int proc_dostring(ctl_table *table, int write, struct file *filp,
@@ -2258,12 +2463,20 @@ int proc_dostring(ctl_table *table, int write, struct file *filp,
return -ENOSYS;
}
-static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_do_uts_string(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
{
return -ENOSYS;
}
+#ifdef CONFIG_SYSVIPC
+static int proc_do_ipc_string(ctl_table *table, int write, struct file *filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ return -ENOSYS;
+}
+#endif
+
int proc_dointvec(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
@@ -2318,6 +2531,7 @@ int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
#endif /* CONFIG_PROC_FS */
+#ifdef CONFIG_SYSCTL_SYSCALL
/*
* General sysctl support routines
*/
@@ -2460,11 +2674,19 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
return 1;
}
-#else /* CONFIG_SYSCTL */
+#else /* CONFIG_SYSCTL_SYSCALL */
asmlinkage long sys_sysctl(struct __sysctl_args __user *args)
{
+ static int msg_count;
+
+ if (msg_count < 5) {
+ msg_count++;
+ printk(KERN_INFO
+ "warning: process `%s' used the removed sysctl "
+ "system call\n", current->comm);
+ }
return -ENOSYS;
}
@@ -2496,73 +2718,7 @@ int sysctl_ms_jiffies(ctl_table *table, int __user *name, int nlen,
return -ENOSYS;
}
-int proc_dostring(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_dointvec(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_dointvec_userhz_jiffies(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_dointvec_ms_jiffies(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
- void __user *buffer, size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
- struct file *filp,
- void __user *buffer,
- size_t *lenp, loff_t *ppos)
-{
- return -ENOSYS;
-}
-
-struct ctl_table_header * register_sysctl_table(ctl_table * table,
- int insert_at_head)
-{
- return NULL;
-}
-
-void unregister_sysctl_table(struct ctl_table_header * table)
-{
-}
-
-#endif /* CONFIG_SYSCTL */
+#endif /* CONFIG_SYSCTL_SYSCALL */
/*
* No sense putting this after each symbol definition, twice,
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index 2ed4040d0dc5..5d6a8c54ee85 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -18,7 +18,9 @@
#include <linux/kernel.h>
#include <linux/taskstats_kern.h>
+#include <linux/tsacct_kern.h>
#include <linux/delayacct.h>
+#include <linux/tsacct_kern.h>
#include <linux/cpumask.h>
#include <linux/percpu.h>
#include <net/genetlink.h>
@@ -75,7 +77,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
/*
* If new attributes are added, please revisit this allocation
*/
- skb = nlmsg_new(size, GFP_KERNEL);
+ skb = nlmsg_new(genlmsg_total_size(size), GFP_KERNEL);
if (!skb)
return -ENOMEM;
@@ -198,7 +200,13 @@ static int fill_pid(pid_t pid, struct task_struct *pidtsk,
*/
delayacct_add_tsk(stats, tsk);
+
+ /* fill in basic acct fields */
stats->version = TASKSTATS_VERSION;
+ bacct_add_tsk(stats, tsk);
+
+ /* fill in extended acct fields */
+ xacct_add_tsk(stats, tsk);
/* Define err: label here if needed */
put_task_struct(tsk);
diff --git a/kernel/time.c b/kernel/time.c
index 5bd489747643..0e017bff4c19 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -202,179 +202,6 @@ asmlinkage long sys_settimeofday(struct timeval __user *tv,
return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
}
-/* we call this to notify the arch when the clock is being
- * controlled. If no such arch routine, do nothing.
- */
-void __attribute__ ((weak)) notify_arch_cmos_timer(void)
-{
- return;
-}
-
-/* adjtimex mainly allows reading (and writing, if superuser) of
- * kernel time-keeping variables. used by xntpd.
- */
-int do_adjtimex(struct timex *txc)
-{
- long ltemp, mtemp, save_adjust;
- int result;
-
- /* In order to modify anything, you gotta be super-user! */
- if (txc->modes && !capable(CAP_SYS_TIME))
- return -EPERM;
-
- /* Now we validate the data before disabling interrupts */
-
- if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
- /* singleshot must not be used with any other mode bits */
- if (txc->modes != ADJ_OFFSET_SINGLESHOT)
- return -EINVAL;
-
- if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
- /* adjustment Offset limited to +- .512 seconds */
- if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
- return -EINVAL;
-
- /* if the quartz is off by more than 10% something is VERY wrong ! */
- if (txc->modes & ADJ_TICK)
- if (txc->tick < 900000/USER_HZ ||
- txc->tick > 1100000/USER_HZ)
- return -EINVAL;
-
- write_seqlock_irq(&xtime_lock);
- result = time_state; /* mostly `TIME_OK' */
-
- /* Save for later - semantics of adjtime is to return old value */
- save_adjust = time_next_adjust ? time_next_adjust : time_adjust;
-
-#if 0 /* STA_CLOCKERR is never set yet */
- time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
-#endif
- /* If there are input parameters, then process them */
- if (txc->modes)
- {
- if (txc->modes & ADJ_STATUS) /* only set allowed bits */
- time_status = (txc->status & ~STA_RONLY) |
- (time_status & STA_RONLY);
-
- if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */
- if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
- result = -EINVAL;
- goto leave;
- }
- time_freq = txc->freq;
- }
-
- if (txc->modes & ADJ_MAXERROR) {
- if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
- result = -EINVAL;
- goto leave;
- }
- time_maxerror = txc->maxerror;
- }
-
- if (txc->modes & ADJ_ESTERROR) {
- if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
- result = -EINVAL;
- goto leave;
- }
- time_esterror = txc->esterror;
- }
-
- if (txc->modes & ADJ_TIMECONST) { /* p. 24 */
- if (txc->constant < 0) { /* NTP v4 uses values > 6 */
- result = -EINVAL;
- goto leave;
- }
- time_constant = txc->constant;
- }
-
- if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
- if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
- /* adjtime() is independent from ntp_adjtime() */
- if ((time_next_adjust = txc->offset) == 0)
- time_adjust = 0;
- }
- else if (time_status & STA_PLL) {
- ltemp = txc->offset;
-
- /*
- * Scale the phase adjustment and
- * clamp to the operating range.
- */
- if (ltemp > MAXPHASE)
- time_offset = MAXPHASE << SHIFT_UPDATE;
- else if (ltemp < -MAXPHASE)
- time_offset = -(MAXPHASE << SHIFT_UPDATE);
- else
- time_offset = ltemp << SHIFT_UPDATE;
-
- /*
- * Select whether the frequency is to be controlled
- * and in which mode (PLL or FLL). Clamp to the operating
- * range. Ugly multiply/divide should be replaced someday.
- */
-
- if (time_status & STA_FREQHOLD || time_reftime == 0)
- time_reftime = xtime.tv_sec;
- mtemp = xtime.tv_sec - time_reftime;
- time_reftime = xtime.tv_sec;
- if (time_status & STA_FLL) {
- if (mtemp >= MINSEC) {
- ltemp = (time_offset / mtemp) << (SHIFT_USEC -
- SHIFT_UPDATE);
- time_freq += shift_right(ltemp, SHIFT_KH);
- } else /* calibration interval too short (p. 12) */
- result = TIME_ERROR;
- } else { /* PLL mode */
- if (mtemp < MAXSEC) {
- ltemp *= mtemp;
- time_freq += shift_right(ltemp,(time_constant +
- time_constant +
- SHIFT_KF - SHIFT_USEC));
- } else /* calibration interval too long (p. 12) */
- result = TIME_ERROR;
- }
- time_freq = min(time_freq, time_tolerance);
- time_freq = max(time_freq, -time_tolerance);
- } /* STA_PLL */
- } /* txc->modes & ADJ_OFFSET */
- if (txc->modes & ADJ_TICK) {
- tick_usec = txc->tick;
- tick_nsec = TICK_USEC_TO_NSEC(tick_usec);
- }
- } /* txc->modes */
-leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
- result = TIME_ERROR;
-
- if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
- txc->offset = save_adjust;
- else {
- txc->offset = shift_right(time_offset, SHIFT_UPDATE);
- }
- txc->freq = time_freq;
- txc->maxerror = time_maxerror;
- txc->esterror = time_esterror;
- txc->status = time_status;
- txc->constant = time_constant;
- txc->precision = time_precision;
- txc->tolerance = time_tolerance;
- txc->tick = tick_usec;
-
- /* PPS is not implemented, so these are zero */
- txc->ppsfreq = 0;
- txc->jitter = 0;
- txc->shift = 0;
- txc->stabil = 0;
- txc->jitcnt = 0;
- txc->calcnt = 0;
- txc->errcnt = 0;
- txc->stbcnt = 0;
- write_sequnlock_irq(&xtime_lock);
- do_gettimeofday(&txc->time);
- notify_arch_cmos_timer();
- return(result);
-}
-
asmlinkage long sys_adjtimex(struct timex __user *txc_p)
{
struct timex txc; /* Local copy of parameter */
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index e1dfd8e86cce..61a3907d16fb 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -1 +1 @@
-obj-y += clocksource.o jiffies.o
+obj-y += ntp.o clocksource.o jiffies.o
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
index 126bb30c4afe..a99b2a6e6a07 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -57,7 +57,7 @@ static cycle_t jiffies_read(void)
struct clocksource clocksource_jiffies = {
.name = "jiffies",
- .rating = 0, /* lowest rating*/
+ .rating = 1, /* lowest valid rating*/
.read = jiffies_read,
.mask = 0xffffffff, /*32bits*/
.mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
diff --git a/kernel/time/ntp.c b/kernel/time/ntp.c
new file mode 100644
index 000000000000..47195fa0ec4f
--- /dev/null
+++ b/kernel/time/ntp.c
@@ -0,0 +1,350 @@
+/*
+ * linux/kernel/time/ntp.c
+ *
+ * NTP state machine interfaces and logic.
+ *
+ * This code was mainly moved from kernel/timer.c and kernel/time.c
+ * Please see those files for relevant copyright info and historical
+ * changelogs.
+ */
+
+#include <linux/mm.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+
+#include <asm/div64.h>
+#include <asm/timex.h>
+
+/*
+ * Timekeeping variables
+ */
+unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */
+unsigned long tick_nsec; /* ACTHZ period (nsec) */
+static u64 tick_length, tick_length_base;
+
+#define MAX_TICKADJ 500 /* microsecs */
+#define MAX_TICKADJ_SCALED (((u64)(MAX_TICKADJ * NSEC_PER_USEC) << \
+ TICK_LENGTH_SHIFT) / HZ)
+
+/*
+ * phase-lock loop variables
+ */
+/* TIME_ERROR prevents overwriting the CMOS clock */
+static int time_state = TIME_OK; /* clock synchronization status */
+int time_status = STA_UNSYNC; /* clock status bits */
+static long time_offset; /* time adjustment (ns) */
+static long time_constant = 2; /* pll time constant */
+long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
+long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
+long time_freq; /* frequency offset (scaled ppm)*/
+static long time_reftime; /* time at last adjustment (s) */
+long time_adjust;
+
+#define CLOCK_TICK_OVERFLOW (LATCH * HZ - CLOCK_TICK_RATE)
+#define CLOCK_TICK_ADJUST (((s64)CLOCK_TICK_OVERFLOW * NSEC_PER_SEC) / \
+ (s64)CLOCK_TICK_RATE)
+
+static void ntp_update_frequency(void)
+{
+ tick_length_base = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) << TICK_LENGTH_SHIFT;
+ tick_length_base += (s64)CLOCK_TICK_ADJUST << TICK_LENGTH_SHIFT;
+ tick_length_base += (s64)time_freq << (TICK_LENGTH_SHIFT - SHIFT_NSEC);
+
+ do_div(tick_length_base, HZ);
+
+ tick_nsec = tick_length_base >> TICK_LENGTH_SHIFT;
+}
+
+/**
+ * ntp_clear - Clears the NTP state variables
+ *
+ * Must be called while holding a write on the xtime_lock
+ */
+void ntp_clear(void)
+{
+ time_adjust = 0; /* stop active adjtime() */
+ time_status |= STA_UNSYNC;
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_esterror = NTP_PHASE_LIMIT;
+
+ ntp_update_frequency();
+
+ tick_length = tick_length_base;
+ time_offset = 0;
+}
+
+/*
+ * this routine handles the overflow of the microsecond field
+ *
+ * The tricky bits of code to handle the accurate clock support
+ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
+ * They were originally developed for SUN and DEC kernels.
+ * All the kudos should go to Dave for this stuff.
+ */
+void second_overflow(void)
+{
+ long time_adj;
+
+ /* Bump the maxerror field */
+ time_maxerror += MAXFREQ >> SHIFT_USEC;
+ if (time_maxerror > NTP_PHASE_LIMIT) {
+ time_maxerror = NTP_PHASE_LIMIT;
+ time_status |= STA_UNSYNC;
+ }
+
+ /*
+ * Leap second processing. If in leap-insert state at the end of the
+ * day, the system clock is set back one second; if in leap-delete
+ * state, the system clock is set ahead one second. The microtime()
+ * routine or external clock driver will insure that reported time is
+ * always monotonic. The ugly divides should be replaced.
+ */
+ switch (time_state) {
+ case TIME_OK:
+ if (time_status & STA_INS)
+ time_state = TIME_INS;
+ else if (time_status & STA_DEL)
+ time_state = TIME_DEL;
+ break;
+ case TIME_INS:
+ if (xtime.tv_sec % 86400 == 0) {
+ xtime.tv_sec--;
+ wall_to_monotonic.tv_sec++;
+ /*
+ * The timer interpolator will make time change
+ * gradually instead of an immediate jump by one second
+ */
+ time_interpolator_update(-NSEC_PER_SEC);
+ time_state = TIME_OOP;
+ clock_was_set();
+ printk(KERN_NOTICE "Clock: inserting leap second "
+ "23:59:60 UTC\n");
+ }
+ break;
+ case TIME_DEL:
+ if ((xtime.tv_sec + 1) % 86400 == 0) {
+ xtime.tv_sec++;
+ wall_to_monotonic.tv_sec--;
+ /*
+ * Use of time interpolator for a gradual change of
+ * time
+ */
+ time_interpolator_update(NSEC_PER_SEC);
+ time_state = TIME_WAIT;
+ clock_was_set();
+ printk(KERN_NOTICE "Clock: deleting leap second "
+ "23:59:59 UTC\n");
+ }
+ break;
+ case TIME_OOP:
+ time_state = TIME_WAIT;
+ break;
+ case TIME_WAIT:
+ if (!(time_status & (STA_INS | STA_DEL)))
+ time_state = TIME_OK;
+ }
+
+ /*
+ * Compute the phase adjustment for the next second. The offset is
+ * reduced by a fixed factor times the time constant.
+ */
+ tick_length = tick_length_base;
+ time_adj = shift_right(time_offset, SHIFT_PLL + time_constant);
+ time_offset -= time_adj;
+ tick_length += (s64)time_adj << (TICK_LENGTH_SHIFT - SHIFT_UPDATE);
+
+ if (unlikely(time_adjust)) {
+ if (time_adjust > MAX_TICKADJ) {
+ time_adjust -= MAX_TICKADJ;
+ tick_length += MAX_TICKADJ_SCALED;
+ } else if (time_adjust < -MAX_TICKADJ) {
+ time_adjust += MAX_TICKADJ;
+ tick_length -= MAX_TICKADJ_SCALED;
+ } else {
+ time_adjust = 0;
+ tick_length += (s64)(time_adjust * NSEC_PER_USEC /
+ HZ) << TICK_LENGTH_SHIFT;
+ }
+ }
+}
+
+/*
+ * Return how long ticks are at the moment, that is, how much time
+ * update_wall_time_one_tick will add to xtime next time we call it
+ * (assuming no calls to do_adjtimex in the meantime).
+ * The return value is in fixed-point nanoseconds shifted by the
+ * specified number of bits to the right of the binary point.
+ * This function has no side-effects.
+ */
+u64 current_tick_length(void)
+{
+ return tick_length;
+}
+
+
+void __attribute__ ((weak)) notify_arch_cmos_timer(void)
+{
+ return;
+}
+
+/* adjtimex mainly allows reading (and writing, if superuser) of
+ * kernel time-keeping variables. used by xntpd.
+ */
+int do_adjtimex(struct timex *txc)
+{
+ long ltemp, mtemp, save_adjust;
+ s64 freq_adj, temp64;
+ int result;
+
+ /* In order to modify anything, you gotta be super-user! */
+ if (txc->modes && !capable(CAP_SYS_TIME))
+ return -EPERM;
+
+ /* Now we validate the data before disabling interrupts */
+
+ if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
+ /* singleshot must not be used with any other mode bits */
+ if (txc->modes != ADJ_OFFSET_SINGLESHOT)
+ return -EINVAL;
+
+ if (txc->modes != ADJ_OFFSET_SINGLESHOT && (txc->modes & ADJ_OFFSET))
+ /* adjustment Offset limited to +- .512 seconds */
+ if (txc->offset <= - MAXPHASE || txc->offset >= MAXPHASE )
+ return -EINVAL;
+
+ /* if the quartz is off by more than 10% something is VERY wrong ! */
+ if (txc->modes & ADJ_TICK)
+ if (txc->tick < 900000/USER_HZ ||
+ txc->tick > 1100000/USER_HZ)
+ return -EINVAL;
+
+ write_seqlock_irq(&xtime_lock);
+ result = time_state; /* mostly `TIME_OK' */
+
+ /* Save for later - semantics of adjtime is to return old value */
+ save_adjust = time_adjust;
+
+#if 0 /* STA_CLOCKERR is never set yet */
+ time_status &= ~STA_CLOCKERR; /* reset STA_CLOCKERR */
+#endif
+ /* If there are input parameters, then process them */
+ if (txc->modes)
+ {
+ if (txc->modes & ADJ_STATUS) /* only set allowed bits */
+ time_status = (txc->status & ~STA_RONLY) |
+ (time_status & STA_RONLY);
+
+ if (txc->modes & ADJ_FREQUENCY) { /* p. 22 */
+ if (txc->freq > MAXFREQ || txc->freq < -MAXFREQ) {
+ result = -EINVAL;
+ goto leave;
+ }
+ time_freq = ((s64)txc->freq * NSEC_PER_USEC) >> (SHIFT_USEC - SHIFT_NSEC);
+ }
+
+ if (txc->modes & ADJ_MAXERROR) {
+ if (txc->maxerror < 0 || txc->maxerror >= NTP_PHASE_LIMIT) {
+ result = -EINVAL;
+ goto leave;
+ }
+ time_maxerror = txc->maxerror;
+ }
+
+ if (txc->modes & ADJ_ESTERROR) {
+ if (txc->esterror < 0 || txc->esterror >= NTP_PHASE_LIMIT) {
+ result = -EINVAL;
+ goto leave;
+ }
+ time_esterror = txc->esterror;
+ }
+
+ if (txc->modes & ADJ_TIMECONST) { /* p. 24 */
+ if (txc->constant < 0) { /* NTP v4 uses values > 6 */
+ result = -EINVAL;
+ goto leave;
+ }
+ time_constant = min(txc->constant + 4, (long)MAXTC);
+ }
+
+ if (txc->modes & ADJ_OFFSET) { /* values checked earlier */
+ if (txc->modes == ADJ_OFFSET_SINGLESHOT) {
+ /* adjtime() is independent from ntp_adjtime() */
+ time_adjust = txc->offset;
+ }
+ else if (time_status & STA_PLL) {
+ ltemp = txc->offset * NSEC_PER_USEC;
+
+ /*
+ * Scale the phase adjustment and
+ * clamp to the operating range.
+ */
+ time_offset = min(ltemp, MAXPHASE * NSEC_PER_USEC);
+ time_offset = max(time_offset, -MAXPHASE * NSEC_PER_USEC);
+
+ /*
+ * Select whether the frequency is to be controlled
+ * and in which mode (PLL or FLL). Clamp to the operating
+ * range. Ugly multiply/divide should be replaced someday.
+ */
+
+ if (time_status & STA_FREQHOLD || time_reftime == 0)
+ time_reftime = xtime.tv_sec;
+ mtemp = xtime.tv_sec - time_reftime;
+ time_reftime = xtime.tv_sec;
+
+ freq_adj = (s64)time_offset * mtemp;
+ freq_adj = shift_right(freq_adj, time_constant * 2 +
+ (SHIFT_PLL + 2) * 2 - SHIFT_NSEC);
+ if (mtemp >= MINSEC && (time_status & STA_FLL || mtemp > MAXSEC)) {
+ temp64 = (s64)time_offset << (SHIFT_NSEC - SHIFT_FLL);
+ if (time_offset < 0) {
+ temp64 = -temp64;
+ do_div(temp64, mtemp);
+ freq_adj -= temp64;
+ } else {
+ do_div(temp64, mtemp);
+ freq_adj += temp64;
+ }
+ }
+ freq_adj += time_freq;
+ freq_adj = min(freq_adj, (s64)MAXFREQ_NSEC);
+ time_freq = max(freq_adj, (s64)-MAXFREQ_NSEC);
+ time_offset = (time_offset / HZ) << SHIFT_UPDATE;
+ } /* STA_PLL */
+ } /* txc->modes & ADJ_OFFSET */
+ if (txc->modes & ADJ_TICK)
+ tick_usec = txc->tick;
+
+ if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET))
+ ntp_update_frequency();
+ } /* txc->modes */
+leave: if ((time_status & (STA_UNSYNC|STA_CLOCKERR)) != 0)
+ result = TIME_ERROR;
+
+ if ((txc->modes & ADJ_OFFSET_SINGLESHOT) == ADJ_OFFSET_SINGLESHOT)
+ txc->offset = save_adjust;
+ else
+ txc->offset = shift_right(time_offset, SHIFT_UPDATE) * HZ / 1000;
+ txc->freq = (time_freq / NSEC_PER_USEC) << (SHIFT_USEC - SHIFT_NSEC);
+ txc->maxerror = time_maxerror;
+ txc->esterror = time_esterror;
+ txc->status = time_status;
+ txc->constant = time_constant;
+ txc->precision = 1;
+ txc->tolerance = MAXFREQ;
+ txc->tick = tick_usec;
+
+ /* PPS is not implemented, so these are zero */
+ txc->ppsfreq = 0;
+ txc->jitter = 0;
+ txc->shift = 0;
+ txc->stabil = 0;
+ txc->jitcnt = 0;
+ txc->calcnt = 0;
+ txc->errcnt = 0;
+ txc->stbcnt = 0;
+ write_sequnlock_irq(&xtime_lock);
+ do_gettimeofday(&txc->time);
+ notify_arch_cmos_timer();
+ return(result);
+}
diff --git a/kernel/timer.c b/kernel/timer.c
index 1d7dd6267c2d..c1c7fbcffec1 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -41,12 +41,6 @@
#include <asm/timex.h>
#include <asm/io.h>
-#ifdef CONFIG_TIME_INTERPOLATION
-static void time_interpolator_update(long delta_nsec);
-#else
-#define time_interpolator_update(x)
-#endif
-
u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES;
EXPORT_SYMBOL(jiffies_64);
@@ -136,7 +130,7 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
list_add_tail(&timer->entry, vec);
}
-/***
+/**
* init_timer - initialize a timer.
* @timer: the timer to be initialized
*
@@ -175,6 +169,7 @@ static inline void detach_timer(struct timer_list *timer,
*/
static tvec_base_t *lock_timer_base(struct timer_list *timer,
unsigned long *flags)
+ __acquires(timer->base->lock)
{
tvec_base_t *base;
@@ -235,7 +230,7 @@ int __mod_timer(struct timer_list *timer, unsigned long expires)
EXPORT_SYMBOL(__mod_timer);
-/***
+/**
* add_timer_on - start a timer on a particular CPU
* @timer: the timer to be added
* @cpu: the CPU to start it on
@@ -255,9 +250,10 @@ void add_timer_on(struct timer_list *timer, int cpu)
}
-/***
+/**
* mod_timer - modify a timer's timeout
* @timer: the timer to be modified
+ * @expires: new timeout in jiffies
*
* mod_timer is a more efficient way to update the expire field of an
* active timer (if the timer is inactive it will be activated)
@@ -291,7 +287,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
EXPORT_SYMBOL(mod_timer);
-/***
+/**
* del_timer - deactive a timer.
* @timer: the timer to be deactivated
*
@@ -323,7 +319,10 @@ int del_timer(struct timer_list *timer)
EXPORT_SYMBOL(del_timer);
#ifdef CONFIG_SMP
-/*
+/**
+ * try_to_del_timer_sync - Try to deactivate a timer
+ * @timer: timer do del
+ *
* This function tries to deactivate a timer. Upon successful (ret >= 0)
* exit the timer is not queued and the handler is not running on any CPU.
*
@@ -351,7 +350,7 @@ out:
return ret;
}
-/***
+/**
* del_timer_sync - deactivate a timer and wait for the handler to finish.
* @timer: the timer to be deactivated
*
@@ -401,15 +400,15 @@ static int cascade(tvec_base_t *base, tvec_t *tv, int index)
return index;
}
-/***
+#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
+
+/**
* __run_timers - run all expired timers (if any) on this CPU.
* @base: the timer vector to be processed.
*
* This function cascades all vectors and executes all expired timer
* vectors.
*/
-#define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
-
static inline void __run_timers(tvec_base_t *base)
{
struct timer_list *timer;
@@ -563,12 +562,6 @@ found:
/******************************************************************/
-/*
- * Timekeeping variables
- */
-unsigned long tick_usec = TICK_USEC; /* USER_HZ period (usec) */
-unsigned long tick_nsec = TICK_NSEC; /* ACTHZ period (nsec) */
-
/*
* The current time
* wall_to_monotonic is what we need to add to xtime (or xtime corrected
@@ -582,209 +575,6 @@ struct timespec wall_to_monotonic __attribute__ ((aligned (16)));
EXPORT_SYMBOL(xtime);
-/* Don't completely fail for HZ > 500. */
-int tickadj = 500/HZ ? : 1; /* microsecs */
-
-
-/*
- * phase-lock loop variables
- */
-/* TIME_ERROR prevents overwriting the CMOS clock */
-int time_state = TIME_OK; /* clock synchronization status */
-int time_status = STA_UNSYNC; /* clock status bits */
-long time_offset; /* time adjustment (us) */
-long time_constant = 2; /* pll time constant */
-long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
-long time_precision = 1; /* clock precision (us) */
-long time_maxerror = NTP_PHASE_LIMIT; /* maximum error (us) */
-long time_esterror = NTP_PHASE_LIMIT; /* estimated error (us) */
-long time_freq = (((NSEC_PER_SEC + HZ/2) % HZ - HZ/2) << SHIFT_USEC) / NSEC_PER_USEC;
- /* frequency offset (scaled ppm)*/
-static long time_adj; /* tick adjust (scaled 1 / HZ) */
-long time_reftime; /* time at last adjustment (s) */
-long time_adjust;
-long time_next_adjust;
-
-/*
- * this routine handles the overflow of the microsecond field
- *
- * The tricky bits of code to handle the accurate clock support
- * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
- * They were originally developed for SUN and DEC kernels.
- * All the kudos should go to Dave for this stuff.
- *
- */
-static void second_overflow(void)
-{
- long ltemp;
-
- /* Bump the maxerror field */
- time_maxerror += time_tolerance >> SHIFT_USEC;
- if (time_maxerror > NTP_PHASE_LIMIT) {
- time_maxerror = NTP_PHASE_LIMIT;
- time_status |= STA_UNSYNC;
- }
-
- /*
- * Leap second processing. If in leap-insert state at the end of the
- * day, the system clock is set back one second; if in leap-delete
- * state, the system clock is set ahead one second. The microtime()
- * routine or external clock driver will insure that reported time is
- * always monotonic. The ugly divides should be replaced.
- */
- switch (time_state) {
- case TIME_OK:
- if (time_status & STA_INS)
- time_state = TIME_INS;
- else if (time_status & STA_DEL)
- time_state = TIME_DEL;
- break;
- case TIME_INS:
- if (xtime.tv_sec % 86400 == 0) {
- xtime.tv_sec--;
- wall_to_monotonic.tv_sec++;
- /*
- * The timer interpolator will make time change
- * gradually instead of an immediate jump by one second
- */
- time_interpolator_update(-NSEC_PER_SEC);
- time_state = TIME_OOP;
- clock_was_set();
- printk(KERN_NOTICE "Clock: inserting leap second "
- "23:59:60 UTC\n");
- }
- break;
- case TIME_DEL:
- if ((xtime.tv_sec + 1) % 86400 == 0) {
- xtime.tv_sec++;
- wall_to_monotonic.tv_sec--;
- /*
- * Use of time interpolator for a gradual change of
- * time
- */
- time_interpolator_update(NSEC_PER_SEC);
- time_state = TIME_WAIT;
- clock_was_set();
- printk(KERN_NOTICE "Clock: deleting leap second "
- "23:59:59 UTC\n");
- }
- break;
- case TIME_OOP:
- time_state = TIME_WAIT;
- break;
- case TIME_WAIT:
- if (!(time_status & (STA_INS | STA_DEL)))
- time_state = TIME_OK;
- }
-
- /*
- * Compute the phase adjustment for the next second. In PLL mode, the
- * offset is reduced by a fixed factor times the time constant. In FLL
- * mode the offset is used directly. In either mode, the maximum phase
- * adjustment for each second is clamped so as to spread the adjustment
- * over not more than the number of seconds between updates.
- */
- ltemp = time_offset;
- if (!(time_status & STA_FLL))
- ltemp = shift_right(ltemp, SHIFT_KG + time_constant);
- ltemp = min(ltemp, (MAXPHASE / MINSEC) << SHIFT_UPDATE);
- ltemp = max(ltemp, -(MAXPHASE / MINSEC) << SHIFT_UPDATE);
- time_offset -= ltemp;
- time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
-
- /*
- * Compute the frequency estimate and additional phase adjustment due
- * to frequency error for the next second.
- */
- ltemp = time_freq;
- time_adj += shift_right(ltemp,(SHIFT_USEC + SHIFT_HZ - SHIFT_SCALE));
-
-#if HZ == 100
- /*
- * Compensate for (HZ==100) != (1 << SHIFT_HZ). Add 25% and 3.125% to
- * get 128.125; => only 0.125% error (p. 14)
- */
- time_adj += shift_right(time_adj, 2) + shift_right(time_adj, 5);
-#endif
-#if HZ == 250
- /*
- * Compensate for (HZ==250) != (1 << SHIFT_HZ). Add 1.5625% and
- * 0.78125% to get 255.85938; => only 0.05% error (p. 14)
- */
- time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7);
-#endif
-#if HZ == 1000
- /*
- * Compensate for (HZ==1000) != (1 << SHIFT_HZ). Add 1.5625% and
- * 0.78125% to get 1023.4375; => only 0.05% error (p. 14)
- */
- time_adj += shift_right(time_adj, 6) + shift_right(time_adj, 7);
-#endif
-}
-
-/*
- * Returns how many microseconds we need to add to xtime this tick
- * in doing an adjustment requested with adjtime.
- */
-static long adjtime_adjustment(void)
-{
- long time_adjust_step;
-
- time_adjust_step = time_adjust;
- if (time_adjust_step) {
- /*
- * We are doing an adjtime thing. Prepare time_adjust_step to
- * be within bounds. Note that a positive time_adjust means we
- * want the clock to run faster.
- *
- * Limit the amount of the step to be in the range
- * -tickadj .. +tickadj
- */
- time_adjust_step = min(time_adjust_step, (long)tickadj);
- time_adjust_step = max(time_adjust_step, (long)-tickadj);
- }
- return time_adjust_step;
-}
-
-/* in the NTP reference this is called "hardclock()" */
-static void update_ntp_one_tick(void)
-{
- long time_adjust_step;
-
- time_adjust_step = adjtime_adjustment();
- if (time_adjust_step)
- /* Reduce by this step the amount of time left */
- time_adjust -= time_adjust_step;
-
- /* Changes by adjtime() do not take effect till next tick. */
- if (time_next_adjust != 0) {
- time_adjust = time_next_adjust;
- time_next_adjust = 0;
- }
-}
-
-/*
- * Return how long ticks are at the moment, that is, how much time
- * update_wall_time_one_tick will add to xtime next time we call it
- * (assuming no calls to do_adjtimex in the meantime).
- * The return value is in fixed-point nanoseconds shifted by the
- * specified number of bits to the right of the binary point.
- * This function has no side-effects.
- */
-u64 current_tick_length(void)
-{
- long delta_nsec;
- u64 ret;
-
- /* calculate the finest interval NTP will allow.
- * ie: nanosecond value shifted by (SHIFT_SCALE - 10)
- */
- delta_nsec = tick_nsec + adjtime_adjustment() * 1000;
- ret = (u64)delta_nsec << TICK_LENGTH_SHIFT;
- ret += (s64)time_adj << (TICK_LENGTH_SHIFT - (SHIFT_SCALE - 10));
-
- return ret;
-}
/* XXX - all of this timekeeping code should be later moved to time.c */
#include <linux/clocksource.h>
@@ -961,21 +751,24 @@ void __init timekeeping_init(void)
unsigned long flags;
write_seqlock_irqsave(&xtime_lock, flags);
+
+ ntp_clear();
+
clock = clocksource_get_next();
clocksource_calculate_interval(clock, tick_nsec);
clock->cycle_last = clocksource_read(clock);
- ntp_clear();
+
write_sequnlock_irqrestore(&xtime_lock, flags);
}
static int timekeeping_suspended;
-/*
+/**
* timekeeping_resume - Resumes the generic timekeeping subsystem.
* @dev: unused
*
* This is for the generic clocksource timekeeping.
- * xtime/wall_to_monotonic/jiffies/wall_jiffies/etc are
+ * xtime/wall_to_monotonic/jiffies/etc are
* still managed by arch specific suspend/resume code.
*/
static int timekeeping_resume(struct sys_device *dev)
@@ -1106,7 +899,7 @@ static void clocksource_adjust(struct clocksource *clock, s64 offset)
clock->error -= (interval - offset) << (TICK_LENGTH_SHIFT - clock->shift);
}
-/*
+/**
* update_wall_time - Uses the current clocksource to increment the wall time
*
* Called from the timer interrupt, must hold a write on xtime_lock.
@@ -1144,8 +937,6 @@ static void update_wall_time(void)
/* interpolator bits */
time_interpolator_update(clock->xtime_interval
>> clock->shift);
- /* increment the NTP state machine */
- update_ntp_one_tick();
/* accumulate error between NTP and clock interval */
clock->error += current_tick_length();
@@ -1217,19 +1008,14 @@ static inline void calc_load(unsigned long ticks)
unsigned long active_tasks; /* fixed-point */
static int count = LOAD_FREQ;
- count -= ticks;
- if (count < 0) {
- count += LOAD_FREQ;
- active_tasks = count_active_tasks();
+ active_tasks = count_active_tasks();
+ for (count -= ticks; count < 0; count += LOAD_FREQ) {
CALC_LOAD(avenrun[0], EXP_1, active_tasks);
CALC_LOAD(avenrun[1], EXP_5, active_tasks);
CALC_LOAD(avenrun[2], EXP_15, active_tasks);
}
}
-/* jiffies at the most recent update of wall time */
-unsigned long wall_jiffies = INITIAL_JIFFIES;
-
/*
* This read-write spinlock protects us from races in SMP while
* playing with xtime and avenrun.
@@ -1265,12 +1051,8 @@ void run_local_timers(void)
* Called by the timer interrupt. xtime_lock must already be taken
* by the timer IRQ!
*/
-static inline void update_times(void)
+static inline void update_times(unsigned long ticks)
{
- unsigned long ticks;
-
- ticks = jiffies - wall_jiffies;
- wall_jiffies += ticks;
update_wall_time();
calc_load(ticks);
}
@@ -1281,12 +1063,10 @@ static inline void update_times(void)
* jiffies is defined in the linker script...
*/
-void do_timer(struct pt_regs *regs)
+void do_timer(unsigned long ticks)
{
- jiffies_64++;
- /* prevent loading jiffies before storing new jiffies_64 value. */
- barrier();
- update_times();
+ jiffies_64 += ticks;
+ update_times(ticks);
}
#ifdef __ARCH_WANT_SYS_ALARM
@@ -1470,8 +1250,9 @@ asmlinkage long sys_gettid(void)
return current->pid;
}
-/*
+/**
* sys_sysinfo - fill in sysinfo struct
+ * @info: pointer to buffer to fill
*/
asmlinkage long sys_sysinfo(struct sysinfo __user *info)
{
@@ -1688,8 +1469,10 @@ static struct notifier_block __cpuinitdata timers_nb = {
void __init init_timers(void)
{
- timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
+ int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
(void *)(long)smp_processor_id());
+
+ BUG_ON(err == NOTIFY_BAD);
register_cpu_notifier(&timers_nb);
open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);
}
@@ -1774,7 +1557,7 @@ unsigned long time_interpolator_get_offset(void)
#define INTERPOLATOR_ADJUST 65536
#define INTERPOLATOR_MAX_SKIP 10*INTERPOLATOR_ADJUST
-static void time_interpolator_update(long delta_nsec)
+void time_interpolator_update(long delta_nsec)
{
u64 counter;
unsigned long offset;
diff --git a/kernel/tsacct.c b/kernel/tsacct.c
new file mode 100644
index 000000000000..db443221ba5b
--- /dev/null
+++ b/kernel/tsacct.c
@@ -0,0 +1,124 @@
+/*
+ * tsacct.c - System accounting over taskstats interface
+ *
+ * Copyright (C) Jay Lan, <jlan@sgi.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.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/tsacct_kern.h>
+#include <linux/acct.h>
+#include <linux/jiffies.h>
+
+
+#define USEC_PER_TICK (USEC_PER_SEC/HZ)
+/*
+ * fill in basic accounting fields
+ */
+void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk)
+{
+ struct timespec uptime, ts;
+ s64 ac_etime;
+
+ BUILD_BUG_ON(TS_COMM_LEN < TASK_COMM_LEN);
+
+ /* calculate task elapsed time in timespec */
+ do_posix_clock_monotonic_gettime(&uptime);
+ ts = timespec_sub(uptime, current->group_leader->start_time);
+ /* rebase elapsed time to usec */
+ ac_etime = timespec_to_ns(&ts);
+ do_div(ac_etime, NSEC_PER_USEC);
+ stats->ac_etime = ac_etime;
+ stats->ac_btime = xtime.tv_sec - ts.tv_sec;
+ if (thread_group_leader(tsk)) {
+ stats->ac_exitcode = tsk->exit_code;
+ if (tsk->flags & PF_FORKNOEXEC)
+ stats->ac_flag |= AFORK;
+ }
+ if (tsk->flags & PF_SUPERPRIV)
+ stats->ac_flag |= ASU;
+ if (tsk->flags & PF_DUMPCORE)
+ stats->ac_flag |= ACORE;
+ if (tsk->flags & PF_SIGNALED)
+ stats->ac_flag |= AXSIG;
+ stats->ac_nice = task_nice(tsk);
+ stats->ac_sched = tsk->policy;
+ stats->ac_uid = tsk->uid;
+ stats->ac_gid = tsk->gid;
+ stats->ac_pid = tsk->pid;
+ stats->ac_ppid = (tsk->parent) ? tsk->parent->pid : 0;
+ stats->ac_utime = cputime_to_msecs(tsk->utime) * USEC_PER_MSEC;
+ stats->ac_stime = cputime_to_msecs(tsk->stime) * USEC_PER_MSEC;
+ stats->ac_minflt = tsk->min_flt;
+ stats->ac_majflt = tsk->maj_flt;
+
+ strncpy(stats->ac_comm, tsk->comm, sizeof(stats->ac_comm));
+}
+
+
+#ifdef CONFIG_TASK_XACCT
+
+#define KB 1024
+#define MB (1024*KB)
+/*
+ * fill in extended accounting fields
+ */
+void xacct_add_tsk(struct taskstats *stats, struct task_struct *p)
+{
+ /* convert pages-jiffies to Mbyte-usec */
+ stats->coremem = jiffies_to_usecs(p->acct_rss_mem1) * PAGE_SIZE / MB;
+ stats->virtmem = jiffies_to_usecs(p->acct_vm_mem1) * PAGE_SIZE / MB;
+ if (p->mm) {
+ /* adjust to KB unit */
+ stats->hiwater_rss = p->mm->hiwater_rss * PAGE_SIZE / KB;
+ stats->hiwater_vm = p->mm->hiwater_vm * PAGE_SIZE / KB;
+ }
+ stats->read_char = p->rchar;
+ stats->write_char = p->wchar;
+ stats->read_syscalls = p->syscr;
+ stats->write_syscalls = p->syscw;
+}
+#undef KB
+#undef MB
+
+/**
+ * acct_update_integrals - update mm integral fields in task_struct
+ * @tsk: task_struct for accounting
+ */
+void acct_update_integrals(struct task_struct *tsk)
+{
+ if (likely(tsk->mm)) {
+ long delta = cputime_to_jiffies(
+ cputime_sub(tsk->stime, tsk->acct_stimexpd));
+
+ if (delta == 0)
+ return;
+ tsk->acct_stimexpd = tsk->stime;
+ tsk->acct_rss_mem1 += delta * get_mm_rss(tsk->mm);
+ tsk->acct_vm_mem1 += delta * tsk->mm->total_vm;
+ }
+}
+
+/**
+ * acct_clear_integrals - clear the mm integral fields in task_struct
+ * @tsk: task_struct whose accounting fields are cleared
+ */
+void acct_clear_integrals(struct task_struct *tsk)
+{
+ tsk->acct_stimexpd = 0;
+ tsk->acct_rss_mem1 = 0;
+ tsk->acct_vm_mem1 = 0;
+}
+#endif
diff --git a/kernel/unwind.c b/kernel/unwind.c
index 3430475fcd88..f7e50d16dbf6 100644
--- a/kernel/unwind.c
+++ b/kernel/unwind.c
@@ -11,13 +11,15 @@
#include <linux/unwind.h>
#include <linux/module.h>
-#include <linux/delay.h>
+#include <linux/bootmem.h>
+#include <linux/sort.h>
#include <linux/stop_machine.h>
#include <asm/sections.h>
#include <asm/uaccess.h>
#include <asm/unaligned.h>
extern char __start_unwind[], __end_unwind[];
+extern const u8 __start_unwind_hdr[], __end_unwind_hdr[];
#define MAX_STACK_DEPTH 8
@@ -100,9 +102,11 @@ static struct unwind_table {
} core, init;
const void *address;
unsigned long size;
+ const unsigned char *header;
+ unsigned long hdrsz;
struct unwind_table *link;
const char *name;
-} root_table, *last_table;
+} root_table;
struct unwind_item {
enum item_location {
@@ -145,6 +149,10 @@ static struct unwind_table *find_table(unsigned long pc)
return table;
}
+static unsigned long read_pointer(const u8 **pLoc,
+ const void *end,
+ signed ptrType);
+
static void init_unwind_table(struct unwind_table *table,
const char *name,
const void *core_start,
@@ -152,14 +160,30 @@ static void init_unwind_table(struct unwind_table *table,
const void *init_start,
unsigned long init_size,
const void *table_start,
- unsigned long table_size)
+ unsigned long table_size,
+ const u8 *header_start,
+ unsigned long header_size)
{
+ const u8 *ptr = header_start + 4;
+ const u8 *end = header_start + header_size;
+
table->core.pc = (unsigned long)core_start;
table->core.range = core_size;
table->init.pc = (unsigned long)init_start;
table->init.range = init_size;
table->address = table_start;
table->size = table_size;
+ /* See if the linker provided table looks valid. */
+ if (header_size <= 4
+ || header_start[0] != 1
+ || (void *)read_pointer(&ptr, end, header_start[1]) != table_start
+ || header_start[2] == DW_EH_PE_omit
+ || read_pointer(&ptr, end, header_start[2]) <= 0
+ || header_start[3] == DW_EH_PE_omit)
+ header_start = NULL;
+ table->hdrsz = header_size;
+ smp_wmb();
+ table->header = header_start;
table->link = NULL;
table->name = name;
}
@@ -169,11 +193,149 @@ void __init unwind_init(void)
init_unwind_table(&root_table, "kernel",
_text, _end - _text,
NULL, 0,
- __start_unwind, __end_unwind - __start_unwind);
+ __start_unwind, __end_unwind - __start_unwind,
+ __start_unwind_hdr, __end_unwind_hdr - __start_unwind_hdr);
+}
+
+static const u32 bad_cie, not_fde;
+static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *);
+static signed fde_pointer_type(const u32 *cie);
+
+struct eh_frame_hdr_table_entry {
+ unsigned long start, fde;
+};
+
+static int cmp_eh_frame_hdr_table_entries(const void *p1, const void *p2)
+{
+ const struct eh_frame_hdr_table_entry *e1 = p1;
+ const struct eh_frame_hdr_table_entry *e2 = p2;
+
+ return (e1->start > e2->start) - (e1->start < e2->start);
+}
+
+static void swap_eh_frame_hdr_table_entries(void *p1, void *p2, int size)
+{
+ struct eh_frame_hdr_table_entry *e1 = p1;
+ struct eh_frame_hdr_table_entry *e2 = p2;
+ unsigned long v;
+
+ v = e1->start;
+ e1->start = e2->start;
+ e2->start = v;
+ v = e1->fde;
+ e1->fde = e2->fde;
+ e2->fde = v;
+}
+
+static void __init setup_unwind_table(struct unwind_table *table,
+ void *(*alloc)(unsigned long))
+{
+ const u8 *ptr;
+ unsigned long tableSize = table->size, hdrSize;
+ unsigned n;
+ const u32 *fde;
+ struct {
+ u8 version;
+ u8 eh_frame_ptr_enc;
+ u8 fde_count_enc;
+ u8 table_enc;
+ unsigned long eh_frame_ptr;
+ unsigned int fde_count;
+ struct eh_frame_hdr_table_entry table[];
+ } __attribute__((__packed__)) *header;
+
+ if (table->header)
+ return;
+
+ if (table->hdrsz)
+ printk(KERN_WARNING ".eh_frame_hdr for '%s' present but unusable\n",
+ table->name);
+
+ if (tableSize & (sizeof(*fde) - 1))
+ return;
+
+ for (fde = table->address, n = 0;
+ tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
+ tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
+ const u32 *cie = cie_for_fde(fde, table);
+ signed ptrType;
+
+ if (cie == &not_fde)
+ continue;
+ if (cie == NULL
+ || cie == &bad_cie
+ || (ptrType = fde_pointer_type(cie)) < 0)
+ return;
+ ptr = (const u8 *)(fde + 2);
+ if (!read_pointer(&ptr,
+ (const u8 *)(fde + 1) + *fde,
+ ptrType))
+ return;
+ ++n;
+ }
+
+ if (tableSize || !n)
+ return;
+
+ hdrSize = 4 + sizeof(unsigned long) + sizeof(unsigned int)
+ + 2 * n * sizeof(unsigned long);
+ header = alloc(hdrSize);
+ if (!header)
+ return;
+ header->version = 1;
+ header->eh_frame_ptr_enc = DW_EH_PE_abs|DW_EH_PE_native;
+ header->fde_count_enc = DW_EH_PE_abs|DW_EH_PE_data4;
+ header->table_enc = DW_EH_PE_abs|DW_EH_PE_native;
+ put_unaligned((unsigned long)table->address, &header->eh_frame_ptr);
+ BUILD_BUG_ON(offsetof(typeof(*header), fde_count)
+ % __alignof(typeof(header->fde_count)));
+ header->fde_count = n;
+
+ BUILD_BUG_ON(offsetof(typeof(*header), table)
+ % __alignof(typeof(*header->table)));
+ for (fde = table->address, tableSize = table->size, n = 0;
+ tableSize;
+ tableSize -= sizeof(*fde) + *fde, fde += 1 + *fde / sizeof(*fde)) {
+ const u32 *cie = fde + 1 - fde[1] / sizeof(*fde);
+
+ if (!fde[1])
+ continue; /* this is a CIE */
+ ptr = (const u8 *)(fde + 2);
+ header->table[n].start = read_pointer(&ptr,
+ (const u8 *)(fde + 1) + *fde,
+ fde_pointer_type(cie));
+ header->table[n].fde = (unsigned long)fde;
+ ++n;
+ }
+ WARN_ON(n != header->fde_count);
+
+ sort(header->table,
+ n,
+ sizeof(*header->table),
+ cmp_eh_frame_hdr_table_entries,
+ swap_eh_frame_hdr_table_entries);
+
+ table->hdrsz = hdrSize;
+ smp_wmb();
+ table->header = (const void *)header;
+}
+
+static void *__init balloc(unsigned long sz)
+{
+ return __alloc_bootmem_nopanic(sz,
+ sizeof(unsigned int),
+ __pa(MAX_DMA_ADDRESS));
+}
+
+void __init unwind_setup(void)
+{
+ setup_unwind_table(&root_table, balloc);
}
#ifdef CONFIG_MODULES
+static struct unwind_table *last_table;
+
/* Must be called with module_mutex held. */
void *unwind_add_table(struct module *module,
const void *table_start,
@@ -191,7 +353,8 @@ void *unwind_add_table(struct module *module,
init_unwind_table(table, module->name,
module->module_core, module->core_size,
module->module_init, module->init_size,
- table_start, table_size);
+ table_start, table_size,
+ NULL, 0);
if (last_table)
last_table->link = table;
@@ -301,6 +464,26 @@ static sleb128_t get_sleb128(const u8 **pcur, const u8 *end)
return value;
}
+static const u32 *cie_for_fde(const u32 *fde, const struct unwind_table *table)
+{
+ const u32 *cie;
+
+ if (!*fde || (*fde & (sizeof(*fde) - 1)))
+ return &bad_cie;
+ if (!fde[1])
+ return &not_fde; /* this is a CIE */
+ if ((fde[1] & (sizeof(*fde) - 1))
+ || fde[1] > (unsigned long)(fde + 1) - (unsigned long)table->address)
+ return NULL; /* this is not a valid FDE */
+ cie = fde + 1 - fde[1] / sizeof(*fde);
+ if (*cie <= sizeof(*cie) + 4
+ || *cie >= fde[1] - sizeof(*fde)
+ || (*cie & (sizeof(*cie) - 1))
+ || cie[1])
+ return NULL; /* this is not a (valid) CIE */
+ return cie;
+}
+
static unsigned long read_pointer(const u8 **pLoc,
const void *end,
signed ptrType)
@@ -608,49 +791,108 @@ int unwind(struct unwind_frame_info *frame)
unsigned i;
signed ptrType = -1;
uleb128_t retAddrReg = 0;
- struct unwind_table *table;
+ const struct unwind_table *table;
struct unwind_state state;
if (UNW_PC(frame) == 0)
return -EINVAL;
if ((table = find_table(pc)) != NULL
&& !(table->size & (sizeof(*fde) - 1))) {
- unsigned long tableSize = table->size;
-
- for (fde = table->address;
- tableSize > sizeof(*fde) && tableSize - sizeof(*fde) >= *fde;
- tableSize -= sizeof(*fde) + *fde,
- fde += 1 + *fde / sizeof(*fde)) {
- if (!*fde || (*fde & (sizeof(*fde) - 1)))
- break;
- if (!fde[1])
- continue; /* this is a CIE */
- if ((fde[1] & (sizeof(*fde) - 1))
- || fde[1] > (unsigned long)(fde + 1)
- - (unsigned long)table->address)
- continue; /* this is not a valid FDE */
- cie = fde + 1 - fde[1] / sizeof(*fde);
- if (*cie <= sizeof(*cie) + 4
- || *cie >= fde[1] - sizeof(*fde)
- || (*cie & (sizeof(*cie) - 1))
- || cie[1]
- || (ptrType = fde_pointer_type(cie)) < 0) {
- cie = NULL; /* this is not a (valid) CIE */
- continue;
+ const u8 *hdr = table->header;
+ unsigned long tableSize;
+
+ smp_rmb();
+ if (hdr && hdr[0] == 1) {
+ switch(hdr[3] & DW_EH_PE_FORM) {
+ case DW_EH_PE_native: tableSize = sizeof(unsigned long); break;
+ case DW_EH_PE_data2: tableSize = 2; break;
+ case DW_EH_PE_data4: tableSize = 4; break;
+ case DW_EH_PE_data8: tableSize = 8; break;
+ default: tableSize = 0; break;
+ }
+ ptr = hdr + 4;
+ end = hdr + table->hdrsz;
+ if (tableSize
+ && read_pointer(&ptr, end, hdr[1])
+ == (unsigned long)table->address
+ && (i = read_pointer(&ptr, end, hdr[2])) > 0
+ && i == (end - ptr) / (2 * tableSize)
+ && !((end - ptr) % (2 * tableSize))) {
+ do {
+ const u8 *cur = ptr + (i / 2) * (2 * tableSize);
+
+ startLoc = read_pointer(&cur,
+ cur + tableSize,
+ hdr[3]);
+ if (pc < startLoc)
+ i /= 2;
+ else {
+ ptr = cur - tableSize;
+ i = (i + 1) / 2;
+ }
+ } while (startLoc && i > 1);
+ if (i == 1
+ && (startLoc = read_pointer(&ptr,
+ ptr + tableSize,
+ hdr[3])) != 0
+ && pc >= startLoc)
+ fde = (void *)read_pointer(&ptr,
+ ptr + tableSize,
+ hdr[3]);
}
+ }
+
+ if (fde != NULL) {
+ cie = cie_for_fde(fde, table);
ptr = (const u8 *)(fde + 2);
- startLoc = read_pointer(&ptr,
- (const u8 *)(fde + 1) + *fde,
- ptrType);
- endLoc = startLoc
- + read_pointer(&ptr,
- (const u8 *)(fde + 1) + *fde,
- ptrType & DW_EH_PE_indirect
- ? ptrType
- : ptrType & (DW_EH_PE_FORM|DW_EH_PE_signed));
- if (pc >= startLoc && pc < endLoc)
- break;
- cie = NULL;
+ if(cie != NULL
+ && cie != &bad_cie
+ && cie != &not_fde
+ && (ptrType = fde_pointer_type(cie)) >= 0
+ && read_pointer(&ptr,
+ (const u8 *)(fde + 1) + *fde,
+ ptrType) == startLoc) {
+ if (!(ptrType & DW_EH_PE_indirect))
+ ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed;
+ endLoc = startLoc
+ + read_pointer(&ptr,
+ (const u8 *)(fde + 1) + *fde,
+ ptrType);
+ if(pc >= endLoc)
+ fde = NULL;
+ } else
+ fde = NULL;
+ }
+ if (fde == NULL) {
+ for (fde = table->address, tableSize = table->size;
+ cie = NULL, tableSize > sizeof(*fde)
+ && tableSize - sizeof(*fde) >= *fde;
+ tableSize -= sizeof(*fde) + *fde,
+ fde += 1 + *fde / sizeof(*fde)) {
+ cie = cie_for_fde(fde, table);
+ if (cie == &bad_cie) {
+ cie = NULL;
+ break;
+ }
+ if (cie == NULL
+ || cie == &not_fde
+ || (ptrType = fde_pointer_type(cie)) < 0)
+ continue;
+ ptr = (const u8 *)(fde + 2);
+ startLoc = read_pointer(&ptr,
+ (const u8 *)(fde + 1) + *fde,
+ ptrType);
+ if (!startLoc)
+ continue;
+ if (!(ptrType & DW_EH_PE_indirect))
+ ptrType &= DW_EH_PE_FORM|DW_EH_PE_signed;
+ endLoc = startLoc
+ + read_pointer(&ptr,
+ (const u8 *)(fde + 1) + *fde,
+ ptrType);
+ if (pc >= startLoc && pc < endLoc)
+ break;
+ }
}
}
if (cie != NULL) {
diff --git a/kernel/utsname.c b/kernel/utsname.c
new file mode 100644
index 000000000000..c859164a6993
--- /dev/null
+++ b/kernel/utsname.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Author: Serge Hallyn <serue@us.ibm.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, version 2 of the
+ * License.
+ */
+
+#include <linux/module.h>
+#include <linux/uts.h>
+#include <linux/utsname.h>
+#include <linux/version.h>
+
+/*
+ * Clone a new ns copying an original utsname, setting refcount to 1
+ * @old_ns: namespace to clone
+ * Return NULL on error (failure to kmalloc), new ns otherwise
+ */
+static struct uts_namespace *clone_uts_ns(struct uts_namespace *old_ns)
+{
+ struct uts_namespace *ns;
+
+ ns = kmalloc(sizeof(struct uts_namespace), GFP_KERNEL);
+ if (ns) {
+ memcpy(&ns->name, &old_ns->name, sizeof(ns->name));
+ kref_init(&ns->kref);
+ }
+ return ns;
+}
+
+/*
+ * unshare the current process' utsname namespace.
+ * called only in sys_unshare()
+ */
+int unshare_utsname(unsigned long unshare_flags, struct uts_namespace **new_uts)
+{
+ if (unshare_flags & CLONE_NEWUTS) {
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ *new_uts = clone_uts_ns(current->nsproxy->uts_ns);
+ if (!*new_uts)
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Copy task tsk's utsname namespace, or clone it if flags
+ * specifies CLONE_NEWUTS. In latter case, changes to the
+ * utsname of this process won't be seen by parent, and vice
+ * versa.
+ */
+int copy_utsname(int flags, struct task_struct *tsk)
+{
+ struct uts_namespace *old_ns = tsk->nsproxy->uts_ns;
+ struct uts_namespace *new_ns;
+ int err = 0;
+
+ if (!old_ns)
+ return 0;
+
+ get_uts_ns(old_ns);
+
+ if (!(flags & CLONE_NEWUTS))
+ return 0;
+
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto out;
+ }
+
+ new_ns = clone_uts_ns(old_ns);
+ if (!new_ns) {
+ err = -ENOMEM;
+ goto out;
+ }
+ tsk->nsproxy->uts_ns = new_ns;
+
+out:
+ put_uts_ns(old_ns);
+ return err;
+}
+
+void free_uts_ns(struct kref *kref)
+{
+ struct uts_namespace *ns;
+
+ ns = container_of(kref, struct uts_namespace, kref);
+ kfree(ns);
+}
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 835fe28b87a8..3df9bfc7ff78 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -28,13 +28,14 @@
#include <linux/notifier.h>
#include <linux/kthread.h>
#include <linux/hardirq.h>
+#include <linux/mempolicy.h>
/*
* 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 until all currently-scheduled works are completed, but it doesn't
+ * 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.
@@ -245,6 +246,12 @@ static int worker_thread(void *__cwq)
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;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index f1ac3184dc08..77491e311791 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -71,7 +71,7 @@ config LOG_BUF_SHIFT
config DETECT_SOFTLOCKUP
bool "Detect Soft Lockups"
- depends on DEBUG_KERNEL
+ depends on DEBUG_KERNEL && !S390
default y
help
Say Y here to enable the kernel to detect "soft lockups",
@@ -284,7 +284,7 @@ config DEBUG_HIGHMEM
config DEBUG_BUGVERBOSE
bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
depends on BUG
- depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV
+ depends on ARM || ARM26 || AVR32 || M32R || M68K || SPARC32 || SPARC64 || X86_32 || FRV || SUPERH
default !EMBEDDED
help
Say Y here to make BUG() panics output the file name and line number
@@ -320,9 +320,18 @@ config DEBUG_VM
If unsure, say N.
+config DEBUG_LIST
+ bool "Debug linked list manipulation"
+ depends on DEBUG_KERNEL
+ help
+ Enable this to turn on extended checks in the linked-list
+ walking routines.
+
+ If unsure, say N.
+
config FRAME_POINTER
bool "Compile the kernel with frame pointers"
- depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32)
+ depends on DEBUG_KERNEL && (X86 || CRIS || M68K || M68KNOMMU || FRV || UML || S390 || AVR32 || SUPERH)
default y if DEBUG_INFO && UML
help
If you say Y here the resulting kernel image will be slightly larger
@@ -362,6 +371,20 @@ config FORCED_INLINING
become the default in the future, until then this option is there to
test gcc for this.
+config HEADERS_CHECK
+ bool "Run 'make headers_check' when building vmlinux"
+ depends on !UML
+ help
+ This option will extract the user-visible kernel headers whenever
+ building the kernel, and will run basic sanity checks on them to
+ ensure that exported files do not attempt to include files which
+ were not exported, etc.
+
+ If you're making modifications to header files which are
+ relevant for userspace, say 'Y', and check the headers
+ exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in
+ your build tree), to make sure they're suitable.
+
config RCU_TORTURE_TEST
tristate "torture tests for RCU"
depends on DEBUG_KERNEL
@@ -375,3 +398,17 @@ config RCU_TORTURE_TEST
at boot time (you probably don't).
Say M if you want the RCU torture tests to build as a module.
Say N if you are unsure.
+
+config LKDTM
+ tristate "Linux Kernel Dump Test Tool Module"
+ depends on KPROBES
+ default n
+ help
+ This module enables testing of the different dumping mechanisms by
+ inducing system failures at predefined crash points.
+ If you don't need it: say N
+ Choose M here to compile this code as a module. The module will be
+ called lkdtm.
+
+ Documentation on how to use the module can be found in
+ drivers/misc/lkdtm.c
diff --git a/lib/Makefile b/lib/Makefile
index ef1d37afbbb6..cf98fabaa549 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -2,16 +2,17 @@
# Makefile for some libs needed in the kernel.
#
-lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
+lib-y := ctype.o string.o vsprintf.o cmdline.o \
bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
idr.o div64.o int_sqrt.o bitmap.o extable.o prio_tree.o \
- sha1.o
+ sha1.o irq_regs.o
+lib-$(CONFIG_MMU) += ioremap.o
lib-$(CONFIG_SMP) += cpumask.o
lib-y += kobject.o kref.o kobject_uevent.o klist.o
-obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o
+obj-y += sort.o parser.o halfmd4.o iomap_copy.o debug_locks.o random32.o
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
@@ -28,6 +29,7 @@ lib-$(CONFIG_GENERIC_HWEIGHT) += hweight.o
obj-$(CONFIG_LOCK_KERNEL) += kernel_lock.o
obj-$(CONFIG_PLIST) += plist.o
obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
+obj-$(CONFIG_DEBUG_LIST) += list_debug.o
ifneq ($(CONFIG_HAVE_DEC_LOCK),y)
lib-y += dec_and_lock.o
diff --git a/lib/bitmap.c b/lib/bitmap.c
index d71e38c54ea5..037fa9aa2ed7 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -316,10 +316,11 @@ int bitmap_scnprintf(char *buf, unsigned int buflen,
EXPORT_SYMBOL(bitmap_scnprintf);
/**
- * bitmap_parse - convert an ASCII hex string into a bitmap.
- * @ubuf: pointer to buffer in user space containing string.
- * @ubuflen: buffer size in bytes. If string is smaller than this
+ * __bitmap_parse - convert an ASCII hex string into a bitmap.
+ * @buf: pointer to buffer containing string.
+ * @buflen: buffer size in bytes. If string is smaller than this
* then it must be terminated with a \0.
+ * @is_user: location of buffer, 0 indicates kernel space
* @maskp: pointer to bitmap array that will contain result.
* @nmaskbits: size of bitmap, in bits.
*
@@ -330,11 +331,13 @@ EXPORT_SYMBOL(bitmap_scnprintf);
* characters and for grouping errors such as "1,,5", ",44", "," and "".
* Leading and trailing whitespace accepted, but not embedded whitespace.
*/
-int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
- unsigned long *maskp, int nmaskbits)
+int __bitmap_parse(const char *buf, unsigned int buflen,
+ int is_user, unsigned long *maskp,
+ int nmaskbits)
{
int c, old_c, totaldigits, ndigits, nchunks, nbits;
u32 chunk;
+ const char __user *ubuf = buf;
bitmap_zero(maskp, nmaskbits);
@@ -343,11 +346,15 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
chunk = ndigits = 0;
/* Get the next chunk of the bitmap */
- while (ubuflen) {
+ while (buflen) {
old_c = c;
- if (get_user(c, ubuf++))
- return -EFAULT;
- ubuflen--;
+ if (is_user) {
+ if (__get_user(c, ubuf++))
+ return -EFAULT;
+ }
+ else
+ c = *buf++;
+ buflen--;
if (isspace(c))
continue;
@@ -388,11 +395,36 @@ int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ;
if (nbits > nmaskbits)
return -EOVERFLOW;
- } while (ubuflen && c == ',');
+ } while (buflen && c == ',');
return 0;
}
-EXPORT_SYMBOL(bitmap_parse);
+EXPORT_SYMBOL(__bitmap_parse);
+
+/**
+ * bitmap_parse_user()
+ *
+ * @ubuf: pointer to user buffer containing string.
+ * @ulen: buffer size in bytes. If string is smaller than this
+ * then it must be terminated with a \0.
+ * @maskp: pointer to bitmap array that will contain result.
+ * @nmaskbits: size of bitmap, in bits.
+ *
+ * Wrapper for __bitmap_parse(), providing it with user buffer.
+ *
+ * We cannot have this as an inline function in bitmap.h because it needs
+ * linux/uaccess.h to get the access_ok() declaration and this causes
+ * cyclic dependencies.
+ */
+int bitmap_parse_user(const char __user *ubuf,
+ unsigned int ulen, unsigned long *maskp,
+ int nmaskbits)
+{
+ if (!access_ok(VERIFY_READ, ubuf, ulen))
+ return -EFAULT;
+ return __bitmap_parse((const char *)ubuf, ulen, 1, maskp, nmaskbits);
+}
+EXPORT_SYMBOL(bitmap_parse_user);
/*
* bscnl_emit(buf, buflen, rbot, rtop, bp)
diff --git a/lib/errno.c b/lib/errno.c
deleted file mode 100644
index 41cb9d76c052..000000000000
--- a/lib/errno.c
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
- * linux/lib/errno.c
- *
- * Copyright (C) 1991, 1992 Linus Torvalds
- */
-
-int errno;
diff --git a/lib/genalloc.c b/lib/genalloc.c
index 71338b48e889..75ae68ce03e1 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -14,11 +14,13 @@
#include <linux/genalloc.h>
-/*
- * Create a new special memory pool.
- *
+/**
+ * gen_pool_create - create a new special memory pool
* @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
* @nid: node id of the node the pool structure should be allocated on, or -1
+ *
+ * Create a new special memory pool that can be used to manage special purpose
+ * memory not managed by the regular kmalloc/kfree interface.
*/
struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
{
@@ -34,15 +36,15 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
}
EXPORT_SYMBOL(gen_pool_create);
-
-/*
- * Add a new chunk of memory to the specified pool.
- *
+/**
+ * gen_pool_add - add a new chunk of special memory to the pool
* @pool: pool to add new memory chunk to
* @addr: starting address of memory chunk to add to pool
* @size: size in bytes of the memory chunk to add to pool
* @nid: node id of the node the chunk structure and bitmap should be
* allocated on, or -1
+ *
+ * Add a new chunk of special memory to the specified pool.
*/
int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
int nid)
@@ -69,13 +71,44 @@ int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
}
EXPORT_SYMBOL(gen_pool_add);
-
-/*
- * Allocate the requested number of bytes from the specified pool.
- * Uses a first-fit algorithm.
+/**
+ * gen_pool_destroy - destroy a special memory pool
+ * @pool: pool to destroy
*
+ * Destroy the specified special memory pool. Verifies that there are no
+ * outstanding allocations.
+ */
+void gen_pool_destroy(struct gen_pool *pool)
+{
+ struct list_head *_chunk, *_next_chunk;
+ struct gen_pool_chunk *chunk;
+ int order = pool->min_alloc_order;
+ int bit, end_bit;
+
+
+ write_lock(&pool->lock);
+ list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
+ chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+ list_del(&chunk->next_chunk);
+
+ end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+ bit = find_next_bit(chunk->bits, end_bit, 0);
+ BUG_ON(bit < end_bit);
+
+ kfree(chunk);
+ }
+ kfree(pool);
+ return;
+}
+EXPORT_SYMBOL(gen_pool_destroy);
+
+/**
+ * gen_pool_alloc - allocate special memory from the pool
* @pool: pool to allocate from
* @size: number of bytes to allocate from the pool
+ *
+ * Allocate the requested number of bytes from the specified pool.
+ * Uses a first-fit algorithm.
*/
unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
{
@@ -127,13 +160,13 @@ unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
}
EXPORT_SYMBOL(gen_pool_alloc);
-
-/*
- * Free the specified memory back to the specified pool.
- *
+/**
+ * gen_pool_free - free allocated special memory back to the pool
* @pool: pool to free to
* @addr: starting address of memory to free back to pool
* @size: size in bytes of memory to free
+ *
+ * Free previously allocated special memory back to the specified pool.
*/
void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
{
diff --git a/lib/ioremap.c b/lib/ioremap.c
new file mode 100644
index 000000000000..99fa277f9f7b
--- /dev/null
+++ b/lib/ioremap.c
@@ -0,0 +1,92 @@
+/*
+ * Re-map IO memory to kernel address space so that we can access it.
+ * This is needed for high PCI addresses that aren't mapped in the
+ * 640k-1MB IO memory area on PC's
+ *
+ * (C) Copyright 1995 1996 Linus Torvalds
+ */
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+
+#include <asm/cacheflush.h>
+#include <asm/pgtable.h>
+
+static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
+ unsigned long end, unsigned long phys_addr, pgprot_t prot)
+{
+ pte_t *pte;
+ unsigned long pfn;
+
+ pfn = phys_addr >> PAGE_SHIFT;
+ pte = pte_alloc_kernel(pmd, addr);
+ if (!pte)
+ return -ENOMEM;
+ do {
+ BUG_ON(!pte_none(*pte));
+ set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
+ pfn++;
+ } while (pte++, addr += PAGE_SIZE, addr != end);
+ return 0;
+}
+
+static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
+ unsigned long end, unsigned long phys_addr, pgprot_t prot)
+{
+ pmd_t *pmd;
+ unsigned long next;
+
+ phys_addr -= addr;
+ pmd = pmd_alloc(&init_mm, pud, addr);
+ if (!pmd)
+ return -ENOMEM;
+ do {
+ next = pmd_addr_end(addr, end);
+ if (ioremap_pte_range(pmd, addr, next, phys_addr + addr, prot))
+ return -ENOMEM;
+ } while (pmd++, addr = next, addr != end);
+ return 0;
+}
+
+static inline int ioremap_pud_range(pgd_t *pgd, unsigned long addr,
+ unsigned long end, unsigned long phys_addr, pgprot_t prot)
+{
+ pud_t *pud;
+ unsigned long next;
+
+ phys_addr -= addr;
+ pud = pud_alloc(&init_mm, pgd, addr);
+ if (!pud)
+ return -ENOMEM;
+ do {
+ next = pud_addr_end(addr, end);
+ if (ioremap_pmd_range(pud, addr, next, phys_addr + addr, prot))
+ return -ENOMEM;
+ } while (pud++, addr = next, addr != end);
+ return 0;
+}
+
+int ioremap_page_range(unsigned long addr,
+ unsigned long end, unsigned long phys_addr, pgprot_t prot)
+{
+ pgd_t *pgd;
+ unsigned long start;
+ unsigned long next;
+ int err;
+
+ BUG_ON(addr >= end);
+
+ start = addr;
+ phys_addr -= addr;
+ pgd = pgd_offset_k(addr);
+ do {
+ next = pgd_addr_end(addr, end);
+ err = ioremap_pud_range(pgd, addr, next, phys_addr+addr, prot);
+ if (err)
+ break;
+ } while (pgd++, addr = next, addr != end);
+
+ flush_cache_vmap(start, end);
+
+ return err;
+}
diff --git a/lib/irq_regs.c b/lib/irq_regs.c
new file mode 100644
index 000000000000..753880a5440c
--- /dev/null
+++ b/lib/irq_regs.c
@@ -0,0 +1,17 @@
+/* saved per-CPU IRQ register pointer
+ *
+ * Copyright (C) 2006 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/module.h>
+#include <asm/irq_regs.h>
+
+#ifndef ARCH_HAS_OWN_IRQ_REGS
+DEFINE_PER_CPU(struct pt_regs *, __irq_regs);
+EXPORT_PER_CPU_SYMBOL(__irq_regs);
+#endif
diff --git a/lib/kobject.c b/lib/kobject.c
index 1699eb9161f3..7dd5c0e9d996 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -119,6 +119,7 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
return path;
}
+EXPORT_SYMBOL_GPL(kobject_get_path);
/**
* kobject_init - initialize object.
diff --git a/lib/list_debug.c b/lib/list_debug.c
new file mode 100644
index 000000000000..7ba9d823d388
--- /dev/null
+++ b/lib/list_debug.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2006, Red Hat, Inc., Dave Jones
+ * Released under the General Public License (GPL).
+ *
+ * This file contains the linked list implementations for
+ * DEBUG_LIST.
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+
+void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ if (unlikely(next->prev != prev)) {
+ printk(KERN_ERR "list_add corruption. next->prev should be %p, but was %p\n",
+ prev, next->prev);
+ BUG();
+ }
+ if (unlikely(prev->next != next)) {
+ printk(KERN_ERR "list_add corruption. prev->next should be %p, but was %p\n",
+ next, prev->next);
+ BUG();
+ }
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+EXPORT_SYMBOL(__list_add);
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+EXPORT_SYMBOL(list_add);
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+void list_del(struct list_head *entry)
+{
+ if (unlikely(entry->prev->next != entry)) {
+ printk(KERN_ERR "list_del corruption. prev->next should be %p, "
+ "but was %p\n", entry, entry->prev->next);
+ BUG();
+ }
+ if (unlikely(entry->next->prev != entry)) {
+ printk(KERN_ERR "list_del corruption. next->prev should be %p, "
+ "but was %p\n", entry, entry->next->prev);
+ BUG();
+ }
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+EXPORT_SYMBOL(list_del);
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 637d55608de5..aa9bfd0bdbd1 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -160,13 +160,13 @@ static inline int tag_get(struct radix_tree_node *node, unsigned int tag,
static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag)
{
- root->gfp_mask |= (1 << (tag + __GFP_BITS_SHIFT));
+ root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT));
}
static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag)
{
- root->gfp_mask &= ~(1 << (tag + __GFP_BITS_SHIFT));
+ root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT));
}
static inline void root_tag_clear_all(struct radix_tree_root *root)
@@ -176,7 +176,7 @@ static inline void root_tag_clear_all(struct radix_tree_root *root)
static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag)
{
- return root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
+ return (__force unsigned)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT));
}
/*
diff --git a/lib/random32.c b/lib/random32.c
new file mode 100644
index 000000000000..4a15ce51cea7
--- /dev/null
+++ b/lib/random32.c
@@ -0,0 +1,142 @@
+/*
+ This is a maximally equidistributed combined Tausworthe generator
+ based on code from GNU Scientific Library 1.5 (30 Jun 2004)
+
+ x_n = (s1_n ^ s2_n ^ s3_n)
+
+ s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
+ s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
+ s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
+
+ The period of this generator is about 2^88.
+
+ From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
+ Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
+
+ This is available on the net from L'Ecuyer's home page,
+
+ http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
+ ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
+
+ There is an erratum in the paper "Tables of Maximally
+ Equidistributed Combined LFSR Generators", Mathematics of
+ Computation, 68, 225 (1999), 261--269:
+ http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
+
+ ... the k_j most significant bits of z_j must be non-
+ zero, for each j. (Note: this restriction also applies to the
+ computer code given in [4], but was mistakenly not mentioned in
+ that paper.)
+
+ This affects the seeding procedure by imposing the requirement
+ s1 > 1, s2 > 7, s3 > 15.
+
+*/
+
+#include <linux/types.h>
+#include <linux/percpu.h>
+#include <linux/module.h>
+#include <linux/random.h>
+
+struct rnd_state {
+ u32 s1, s2, s3;
+};
+
+static DEFINE_PER_CPU(struct rnd_state, net_rand_state);
+
+static u32 __random32(struct rnd_state *state)
+{
+#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
+
+ state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
+ state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
+ state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
+
+ return (state->s1 ^ state->s2 ^ state->s3);
+}
+
+static void __set_random32(struct rnd_state *state, unsigned long s)
+{
+ if (s == 0)
+ s = 1; /* default seed is 1 */
+
+#define LCG(n) (69069 * n)
+ state->s1 = LCG(s);
+ state->s2 = LCG(state->s1);
+ state->s3 = LCG(state->s2);
+
+ /* "warm it up" */
+ __random32(state);
+ __random32(state);
+ __random32(state);
+ __random32(state);
+ __random32(state);
+ __random32(state);
+}
+
+/**
+ * random32 - pseudo random number generator
+ *
+ * A 32 bit pseudo-random number is generated using a fast
+ * algorithm suitable for simulation. This algorithm is NOT
+ * considered safe for cryptographic use.
+ */
+u32 random32(void)
+{
+ unsigned long r;
+ struct rnd_state *state = &get_cpu_var(net_rand_state);
+ r = __random32(state);
+ put_cpu_var(state);
+ return r;
+}
+EXPORT_SYMBOL(random32);
+
+/**
+ * srandom32 - add entropy to pseudo random number generator
+ * @seed: seed value
+ *
+ * Add some additional seeding to the random32() pool.
+ * Note: this pool is per cpu so it only affects current CPU.
+ */
+void srandom32(u32 entropy)
+{
+ struct rnd_state *state = &get_cpu_var(net_rand_state);
+ __set_random32(state, state->s1 ^ entropy);
+ put_cpu_var(state);
+}
+EXPORT_SYMBOL(srandom32);
+
+/*
+ * Generate some initially weak seeding values to allow
+ * to start the random32() engine.
+ */
+static int __init random32_init(void)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ struct rnd_state *state = &per_cpu(net_rand_state,i);
+ __set_random32(state, i + jiffies);
+ }
+ return 0;
+}
+core_initcall(random32_init);
+
+/*
+ * Generate better values after random number generator
+ * is fully initalized.
+ */
+static int __init random32_reseed(void)
+{
+ int i;
+ unsigned long seed;
+
+ for_each_possible_cpu(i) {
+ struct rnd_state *state = &per_cpu(net_rand_state,i);
+
+ get_random_bytes(&seed, sizeof(seed));
+ __set_random32(state, seed);
+ }
+ return 0;
+}
+late_initcall(random32_reseed);
diff --git a/lib/rbtree.c b/lib/rbtree.c
index 1e55ba1c2edf..48499c2d88cc 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -322,6 +322,9 @@ struct rb_node *rb_next(struct rb_node *node)
{
struct rb_node *parent;
+ if (rb_parent(node) == node)
+ return NULL;
+
/* If we have a right-hand child, go down and then left as far
as we can. */
if (node->rb_right) {
@@ -348,6 +351,9 @@ struct rb_node *rb_prev(struct rb_node *node)
{
struct rb_node *parent;
+ if (rb_parent(node) == node)
+ return NULL;
+
/* If we have a left-hand child, go down and then right as far
as we can. */
if (node->rb_left) {
diff --git a/lib/reed_solomon/reed_solomon.c b/lib/reed_solomon/reed_solomon.c
index 2cc11faa4ff1..a4b730a2180c 100644
--- a/lib/reed_solomon/reed_solomon.c
+++ b/lib/reed_solomon/reed_solomon.c
@@ -1,5 +1,5 @@
/*
- * lib/reed_solomon/rslib.c
+ * lib/reed_solomon/reed_solomon.c
*
* Overview:
* Generic Reed Solomon encoder / decoder library
diff --git a/lib/rwsem-spinlock.c b/lib/rwsem-spinlock.c
index db4fed74b940..c4cfd6c0342f 100644
--- a/lib/rwsem-spinlock.c
+++ b/lib/rwsem-spinlock.c
@@ -28,7 +28,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name,
* Make sure we are not reinitializing a held semaphore:
*/
debug_check_no_locks_freed((void *)sem, sizeof(*sem));
- lockdep_init_map(&sem->dep_map, name, key);
+ lockdep_init_map(&sem->dep_map, name, key, 0);
#endif
sem->activity = 0;
spin_lock_init(&sem->wait_lock);
diff --git a/lib/rwsem.c b/lib/rwsem.c
index b322421c2969..cdb4e3d05607 100644
--- a/lib/rwsem.c
+++ b/lib/rwsem.c
@@ -19,7 +19,7 @@ void __init_rwsem(struct rw_semaphore *sem, const char *name,
* Make sure we are not reinitializing a held semaphore:
*/
debug_check_no_locks_freed((void *)sem, sizeof(*sem));
- lockdep_init_map(&sem->dep_map, name, key);
+ lockdep_init_map(&sem->dep_map, name, key, 0);
#endif
sem->count = RWSEM_UNLOCKED_VALUE;
spin_lock_init(&sem->wait_lock);
@@ -146,7 +146,7 @@ __rwsem_do_wake(struct rw_semaphore *sem, int downgrading)
/*
* wait for a lock to be granted
*/
-static inline struct rw_semaphore *
+static struct rw_semaphore *
rwsem_down_failed_common(struct rw_semaphore *sem,
struct rwsem_waiter *waiter, signed long adjustment)
{
diff --git a/lib/sort.c b/lib/sort.c
index 5f3b51ffa1dc..488788b341cb 100644
--- a/lib/sort.c
+++ b/lib/sort.c
@@ -49,15 +49,15 @@ void sort(void *base, size_t num, size_t size,
void (*swap)(void *, void *, int size))
{
/* pre-scale counters for performance */
- int i = (num/2) * size, n = num * size, c, r;
+ int i = (num/2 - 1) * size, n = num * size, c, r;
if (!swap)
swap = (size == 4 ? u32_swap : generic_swap);
/* heapify */
for ( ; i >= 0; i -= size) {
- for (r = i; r * 2 < n; r = c) {
- c = r * 2;
+ for (r = i; r * 2 + size < n; r = c) {
+ c = r * 2 + size;
if (c < n - size && cmp(base + c, base + c + size) < 0)
c += size;
if (cmp(base + r, base + c) >= 0)
@@ -69,8 +69,8 @@ void sort(void *base, size_t num, size_t size,
/* sort */
for (i = n - size; i >= 0; i -= size) {
swap(base, base + i, size);
- for (r = 0; r * 2 < i; r = c) {
- c = r * 2;
+ for (r = 0; r * 2 + size < i; r = c) {
+ c = r * 2 + size;
if (c < i - size && cmp(base + c, base + c + size) < 0)
c += size;
if (cmp(base + r, base + c) >= 0)
diff --git a/lib/spinlock_debug.c b/lib/spinlock_debug.c
index 58c577dd82e5..b6c4f898197c 100644
--- a/lib/spinlock_debug.c
+++ b/lib/spinlock_debug.c
@@ -20,7 +20,7 @@ void __spin_lock_init(spinlock_t *lock, const char *name,
* Make sure we are not reinitializing a held lock:
*/
debug_check_no_locks_freed((void *)lock, sizeof(*lock));
- lockdep_init_map(&lock->dep_map, name, key);
+ lockdep_init_map(&lock->dep_map, name, key, 0);
#endif
lock->raw_lock = (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
lock->magic = SPINLOCK_MAGIC;
@@ -38,7 +38,7 @@ void __rwlock_init(rwlock_t *lock, const char *name,
* Make sure we are not reinitializing a held lock:
*/
debug_check_no_locks_freed((void *)lock, sizeof(*lock));
- lockdep_init_map(&lock->dep_map, name, key);
+ lockdep_init_map(&lock->dep_map, name, key, 0);
#endif
lock->raw_lock = (raw_rwlock_t) __RAW_RW_LOCK_UNLOCKED;
lock->magic = RWLOCK_MAGIC;
@@ -99,11 +99,12 @@ static inline void debug_spin_unlock(spinlock_t *lock)
static void __spin_lock_debug(spinlock_t *lock)
{
- int print_once = 1;
u64 i;
+ u64 loops = loops_per_jiffy * HZ;
+ int print_once = 1;
for (;;) {
- for (i = 0; i < loops_per_jiffy * HZ; i++) {
+ for (i = 0; i < loops; i++) {
if (__raw_spin_trylock(&lock->raw_lock))
return;
__delay(1);
@@ -165,11 +166,12 @@ static void rwlock_bug(rwlock_t *lock, const char *msg)
#if 0 /* __write_lock_debug() can lock up - maybe this can too? */
static void __read_lock_debug(rwlock_t *lock)
{
- int print_once = 1;
u64 i;
+ u64 loops = loops_per_jiffy * HZ;
+ int print_once = 1;
for (;;) {
- for (i = 0; i < loops_per_jiffy * HZ; i++) {
+ for (i = 0; i < loops; i++) {
if (__raw_read_trylock(&lock->raw_lock))
return;
__delay(1);
@@ -239,11 +241,12 @@ static inline void debug_write_unlock(rwlock_t *lock)
#if 0 /* This can cause lockups */
static void __write_lock_debug(rwlock_t *lock)
{
- int print_once = 1;
u64 i;
+ u64 loops = loops_per_jiffy * HZ;
+ int print_once = 1;
for (;;) {
- for (i = 0; i < loops_per_jiffy * HZ; i++) {
+ for (i = 0; i < loops; i++) {
if (__raw_write_trylock(&lock->raw_lock))
return;
__delay(1);
diff --git a/lib/ts_fsm.c b/lib/ts_fsm.c
index 87847c2ae9e2..af575b61526b 100644
--- a/lib/ts_fsm.c
+++ b/lib/ts_fsm.c
@@ -12,13 +12,13 @@
*
* A finite state machine consists of n states (struct ts_fsm_token)
* representing the pattern as a finite automation. The data is read
- * sequentially on a octet basis. Every state token specifies the number
+ * sequentially on an octet basis. Every state token specifies the number
* of recurrences and the type of value accepted which can be either a
* specific character or ctype based set of characters. The available
* type of recurrences include 1, (0|1), [0 n], and [1 n].
*
- * The algorithm differs between strict/non-strict mode specyfing
- * whether the pattern has to start at the first octect. Strict mode
+ * The algorithm differs between strict/non-strict mode specifying
+ * whether the pattern has to start at the first octet. Strict mode
* is enabled by default and can be disabled by inserting
* TS_FSM_HEAD_IGNORE as the first token in the chain.
*
@@ -44,7 +44,7 @@ struct ts_fsm
#define _W 0x200 /* wildcard */
/* Map to _ctype flags and some magic numbers */
-static u16 token_map[TS_FSM_TYPE_MAX+1] = {
+static const u16 token_map[TS_FSM_TYPE_MAX+1] = {
[TS_FSM_SPECIFIC] = 0,
[TS_FSM_WILDCARD] = _W,
[TS_FSM_CNTRL] = _C,
@@ -61,7 +61,7 @@ static u16 token_map[TS_FSM_TYPE_MAX+1] = {
[TS_FSM_ASCII] = _A,
};
-static u16 token_lookup_tbl[256] = {
+static const u16 token_lookup_tbl[256] = {
_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 0- 3 */
_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 4- 7 */
_W|_A|_C, _W|_A|_C|_S, _W|_A|_C|_S, _W|_A|_C|_S, /* 8- 11 */
diff --git a/mm/Kconfig b/mm/Kconfig
index 8f5b45615f7b..db7c55de92cd 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -92,7 +92,7 @@ config HAVE_MEMORY_PRESENT
#
# SPARSEMEM_EXTREME (which is the default) does some bootmem
-# allocations when memory_present() is called. If this can not
+# allocations when memory_present() is called. If this cannot
# be done on your architecture, select this option. However,
# statically allocating the mem_section[] array can potentially
# consume vast quantities of .bss, so be careful.
@@ -104,7 +104,7 @@ config SPARSEMEM_STATIC
def_bool n
#
-# Architectecture platforms which require a two level mem_section in SPARSEMEM
+# Architecture platforms which require a two level mem_section in SPARSEMEM
# must select this option. This is usually for architecture platforms with
# an extremely sparse physical address space.
#
@@ -115,12 +115,17 @@ config SPARSEMEM_EXTREME
# eventually, we can have this option just 'select SPARSEMEM'
config MEMORY_HOTPLUG
bool "Allow for memory hot-add"
- depends on SPARSEMEM && HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
+ depends on SPARSEMEM || X86_64_ACPI_NUMA
+ depends on HOTPLUG && !SOFTWARE_SUSPEND && ARCH_ENABLE_MEMORY_HOTPLUG
depends on (IA64 || X86 || PPC64)
comment "Memory hotplug is currently incompatible with Software Suspend"
depends on SPARSEMEM && HOTPLUG && SOFTWARE_SUSPEND
+config MEMORY_HOTPLUG_SPARSE
+ def_bool y
+ depends on SPARSEMEM && MEMORY_HOTPLUG
+
# Heavily threaded applications may benefit from splitting the mm-wide
# page_table_lock, so that faults on different parts of the user address
# space can be handled with less contention: split it at this NR_CPUS.
diff --git a/mm/Makefile b/mm/Makefile
index 60c56c0b5e10..f3c077eb0b8e 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -10,13 +10,18 @@ mmu-$(CONFIG_MMU) := fremap.o highmem.o madvise.o memory.o mincore.o \
obj-y := bootmem.o filemap.o mempool.o oom_kill.o fadvise.o \
page_alloc.o page-writeback.o pdflush.o \
readahead.o swap.o truncate.o vmscan.o \
- prio_tree.o util.o mmzone.o vmstat.o $(mmu-y)
+ prio_tree.o util.o mmzone.o vmstat.o backing-dev.o \
+ $(mmu-y)
+ifeq ($(CONFIG_MMU)$(CONFIG_BLOCK),yy)
+obj-y += bounce.o
+endif
obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o thrash.o
obj-$(CONFIG_HUGETLBFS) += hugetlb.o
obj-$(CONFIG_NUMA) += mempolicy.o
obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SHMEM) += shmem.o
+obj-$(CONFIG_TMPFS_POSIX_ACL) += shmem_acl.o
obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
obj-$(CONFIG_SLOB) += slob.o
obj-$(CONFIG_SLAB) += slab.o
diff --git a/mm/backing-dev.c b/mm/backing-dev.c
new file mode 100644
index 000000000000..f50a2811f9dc
--- /dev/null
+++ b/mm/backing-dev.c
@@ -0,0 +1,69 @@
+
+#include <linux/wait.h>
+#include <linux/backing-dev.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/module.h>
+
+static wait_queue_head_t congestion_wqh[2] = {
+ __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]),
+ __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1])
+ };
+
+
+void clear_bdi_congested(struct backing_dev_info *bdi, int rw)
+{
+ enum bdi_state bit;
+ wait_queue_head_t *wqh = &congestion_wqh[rw];
+
+ bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
+ clear_bit(bit, &bdi->state);
+ smp_mb__after_clear_bit();
+ if (waitqueue_active(wqh))
+ wake_up(wqh);
+}
+EXPORT_SYMBOL(clear_bdi_congested);
+
+void set_bdi_congested(struct backing_dev_info *bdi, int rw)
+{
+ enum bdi_state bit;
+
+ bit = (rw == WRITE) ? BDI_write_congested : BDI_read_congested;
+ set_bit(bit, &bdi->state);
+}
+EXPORT_SYMBOL(set_bdi_congested);
+
+/**
+ * congestion_wait - wait for a backing_dev to become uncongested
+ * @rw: READ or WRITE
+ * @timeout: timeout in jiffies
+ *
+ * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit
+ * write congestion. If no backing_devs are congested then just wait for the
+ * next write to be completed.
+ */
+long congestion_wait(int rw, long timeout)
+{
+ long ret;
+ DEFINE_WAIT(wait);
+ wait_queue_head_t *wqh = &congestion_wqh[rw];
+
+ prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE);
+ ret = io_schedule_timeout(timeout);
+ finish_wait(wqh, &wait);
+ return ret;
+}
+EXPORT_SYMBOL(congestion_wait);
+
+/**
+ * congestion_end - wake up sleepers on a congested backing_dev_info
+ * @rw: READ or WRITE
+ */
+void congestion_end(int rw)
+{
+ wait_queue_head_t *wqh = &congestion_wqh[rw];
+
+ if (waitqueue_active(wqh))
+ wake_up(wqh);
+}
+EXPORT_SYMBOL(congestion_end);
diff --git a/mm/bounce.c b/mm/bounce.c
new file mode 100644
index 000000000000..e4b62d2a4024
--- /dev/null
+++ b/mm/bounce.c
@@ -0,0 +1,302 @@
+/* bounce buffer handling for block devices
+ *
+ * - Split from highmem.c
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/swap.h>
+#include <linux/bio.h>
+#include <linux/pagemap.h>
+#include <linux/mempool.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/hash.h>
+#include <linux/highmem.h>
+#include <linux/blktrace_api.h>
+#include <asm/tlbflush.h>
+
+#define POOL_SIZE 64
+#define ISA_POOL_SIZE 16
+
+static mempool_t *page_pool, *isa_page_pool;
+
+#ifdef CONFIG_HIGHMEM
+static __init int init_emergency_pool(void)
+{
+ struct sysinfo i;
+ si_meminfo(&i);
+ si_swapinfo(&i);
+
+ if (!i.totalhigh)
+ return 0;
+
+ page_pool = mempool_create_page_pool(POOL_SIZE, 0);
+ BUG_ON(!page_pool);
+ printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
+
+ return 0;
+}
+
+__initcall(init_emergency_pool);
+
+/*
+ * highmem version, map in to vec
+ */
+static void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom)
+{
+ unsigned long flags;
+ unsigned char *vto;
+
+ local_irq_save(flags);
+ vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ);
+ memcpy(vto + to->bv_offset, vfrom, to->bv_len);
+ kunmap_atomic(vto, KM_BOUNCE_READ);
+ local_irq_restore(flags);
+}
+
+#else /* CONFIG_HIGHMEM */
+
+#define bounce_copy_vec(to, vfrom) \
+ memcpy(page_address((to)->bv_page) + (to)->bv_offset, vfrom, (to)->bv_len)
+
+#endif /* CONFIG_HIGHMEM */
+
+/*
+ * allocate pages in the DMA region for the ISA pool
+ */
+static void *mempool_alloc_pages_isa(gfp_t gfp_mask, void *data)
+{
+ return mempool_alloc_pages(gfp_mask | GFP_DMA, data);
+}
+
+/*
+ * gets called "every" time someone init's a queue with BLK_BOUNCE_ISA
+ * as the max address, so check if the pool has already been created.
+ */
+int init_emergency_isa_pool(void)
+{
+ if (isa_page_pool)
+ return 0;
+
+ isa_page_pool = mempool_create(ISA_POOL_SIZE, mempool_alloc_pages_isa,
+ mempool_free_pages, (void *) 0);
+ BUG_ON(!isa_page_pool);
+
+ printk("isa bounce pool size: %d pages\n", ISA_POOL_SIZE);
+ return 0;
+}
+
+/*
+ * Simple bounce buffer support for highmem pages. Depending on the
+ * queue gfp mask set, *to may or may not be a highmem page. kmap it
+ * always, it will do the Right Thing
+ */
+static void copy_to_high_bio_irq(struct bio *to, struct bio *from)
+{
+ unsigned char *vfrom;
+ struct bio_vec *tovec, *fromvec;
+ int i;
+
+ __bio_for_each_segment(tovec, to, i, 0) {
+ fromvec = from->bi_io_vec + i;
+
+ /*
+ * not bounced
+ */
+ if (tovec->bv_page == fromvec->bv_page)
+ continue;
+
+ /*
+ * fromvec->bv_offset and fromvec->bv_len might have been
+ * modified by the block layer, so use the original copy,
+ * bounce_copy_vec already uses tovec->bv_len
+ */
+ vfrom = page_address(fromvec->bv_page) + tovec->bv_offset;
+
+ flush_dcache_page(tovec->bv_page);
+ bounce_copy_vec(tovec, vfrom);
+ }
+}
+
+static void bounce_end_io(struct bio *bio, mempool_t *pool, int err)
+{
+ struct bio *bio_orig = bio->bi_private;
+ struct bio_vec *bvec, *org_vec;
+ int i;
+
+ if (test_bit(BIO_EOPNOTSUPP, &bio->bi_flags))
+ set_bit(BIO_EOPNOTSUPP, &bio_orig->bi_flags);
+
+ /*
+ * free up bounce indirect pages used
+ */
+ __bio_for_each_segment(bvec, bio, i, 0) {
+ org_vec = bio_orig->bi_io_vec + i;
+ if (bvec->bv_page == org_vec->bv_page)
+ continue;
+
+ dec_zone_page_state(bvec->bv_page, NR_BOUNCE);
+ mempool_free(bvec->bv_page, pool);
+ }
+
+ bio_endio(bio_orig, bio_orig->bi_size, err);
+ bio_put(bio);
+}
+
+static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
+{
+ if (bio->bi_size)
+ return 1;
+
+ bounce_end_io(bio, page_pool, err);
+ return 0;
+}
+
+static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err)
+{
+ if (bio->bi_size)
+ return 1;
+
+ bounce_end_io(bio, isa_page_pool, err);
+ return 0;
+}
+
+static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err)
+{
+ struct bio *bio_orig = bio->bi_private;
+
+ if (test_bit(BIO_UPTODATE, &bio->bi_flags))
+ copy_to_high_bio_irq(bio_orig, bio);
+
+ bounce_end_io(bio, pool, err);
+}
+
+static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
+{
+ if (bio->bi_size)
+ return 1;
+
+ __bounce_end_io_read(bio, page_pool, err);
+ return 0;
+}
+
+static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err)
+{
+ if (bio->bi_size)
+ return 1;
+
+ __bounce_end_io_read(bio, isa_page_pool, err);
+ return 0;
+}
+
+static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig,
+ mempool_t *pool)
+{
+ struct page *page;
+ struct bio *bio = NULL;
+ int i, rw = bio_data_dir(*bio_orig);
+ struct bio_vec *to, *from;
+
+ bio_for_each_segment(from, *bio_orig, i) {
+ page = from->bv_page;
+
+ /*
+ * is destination page below bounce pfn?
+ */
+ if (page_to_pfn(page) < q->bounce_pfn)
+ continue;
+
+ /*
+ * irk, bounce it
+ */
+ if (!bio)
+ bio = bio_alloc(GFP_NOIO, (*bio_orig)->bi_vcnt);
+
+ to = bio->bi_io_vec + i;
+
+ to->bv_page = mempool_alloc(pool, q->bounce_gfp);
+ to->bv_len = from->bv_len;
+ to->bv_offset = from->bv_offset;
+ inc_zone_page_state(to->bv_page, NR_BOUNCE);
+
+ if (rw == WRITE) {
+ char *vto, *vfrom;
+
+ flush_dcache_page(from->bv_page);
+ vto = page_address(to->bv_page) + to->bv_offset;
+ vfrom = kmap(from->bv_page) + from->bv_offset;
+ memcpy(vto, vfrom, to->bv_len);
+ kunmap(from->bv_page);
+ }
+ }
+
+ /*
+ * no pages bounced
+ */
+ if (!bio)
+ return;
+
+ /*
+ * at least one page was bounced, fill in possible non-highmem
+ * pages
+ */
+ __bio_for_each_segment(from, *bio_orig, i, 0) {
+ to = bio_iovec_idx(bio, i);
+ if (!to->bv_page) {
+ to->bv_page = from->bv_page;
+ to->bv_len = from->bv_len;
+ to->bv_offset = from->bv_offset;
+ }
+ }
+
+ bio->bi_bdev = (*bio_orig)->bi_bdev;
+ bio->bi_flags |= (1 << BIO_BOUNCED);
+ bio->bi_sector = (*bio_orig)->bi_sector;
+ bio->bi_rw = (*bio_orig)->bi_rw;
+
+ bio->bi_vcnt = (*bio_orig)->bi_vcnt;
+ bio->bi_idx = (*bio_orig)->bi_idx;
+ bio->bi_size = (*bio_orig)->bi_size;
+
+ if (pool == page_pool) {
+ bio->bi_end_io = bounce_end_io_write;
+ if (rw == READ)
+ bio->bi_end_io = bounce_end_io_read;
+ } else {
+ bio->bi_end_io = bounce_end_io_write_isa;
+ if (rw == READ)
+ bio->bi_end_io = bounce_end_io_read_isa;
+ }
+
+ bio->bi_private = *bio_orig;
+ *bio_orig = bio;
+}
+
+void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig)
+{
+ mempool_t *pool;
+
+ /*
+ * for non-isa bounce case, just check if the bounce pfn is equal
+ * to or bigger than the highest pfn in the system -- in that case,
+ * don't waste time iterating over bio segments
+ */
+ if (!(q->bounce_gfp & GFP_DMA)) {
+ if (q->bounce_pfn >= blk_max_pfn)
+ return;
+ pool = page_pool;
+ } else {
+ BUG_ON(!isa_page_pool);
+ pool = isa_page_pool;
+ }
+
+ blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
+
+ /*
+ * slow path
+ */
+ __blk_queue_bounce(q, bio_orig, pool);
+}
+
+EXPORT_SYMBOL(blk_queue_bounce);
diff --git a/mm/filemap.c b/mm/filemap.c
index afcdc72b5e90..cb26e33fd0ff 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -75,8 +75,8 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
* ->mmap_sem
* ->lock_page (access_process_vm)
*
- * ->mmap_sem
- * ->i_mutex (msync)
+ * ->i_mutex (generic_file_buffered_write)
+ * ->mmap_sem (fault_in_pages_readable->do_page_fault)
*
* ->i_mutex
* ->i_alloc_sem (various)
@@ -1139,23 +1139,24 @@ success:
}
/**
- * __generic_file_aio_read - generic filesystem read routine
+ * generic_file_aio_read - generic filesystem read routine
* @iocb: kernel I/O control block
* @iov: io vector request
* @nr_segs: number of segments in the iovec
- * @ppos: current file position
+ * @pos: current file position
*
* This is the "read()" routine for all filesystems
* that can use the page cache directly.
*/
ssize_t
-__generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
+generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct file *filp = iocb->ki_filp;
ssize_t retval;
unsigned long seg;
size_t count;
+ loff_t *ppos = &iocb->ki_pos;
count = 0;
for (seg = 0; seg < nr_segs; seg++) {
@@ -1179,7 +1180,7 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
if (filp->f_flags & O_DIRECT) {
- loff_t pos = *ppos, size;
+ loff_t size;
struct address_space *mapping;
struct inode *inode;
@@ -1197,8 +1198,10 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
if (retval > 0)
*ppos = pos + retval;
}
- file_accessed(filp);
- goto out;
+ if (likely(retval != 0)) {
+ file_accessed(filp);
+ goto out;
+ }
}
retval = 0;
@@ -1223,33 +1226,8 @@ __generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
out:
return retval;
}
-EXPORT_SYMBOL(__generic_file_aio_read);
-
-ssize_t
-generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
-{
- struct iovec local_iov = { .iov_base = buf, .iov_len = count };
-
- BUG_ON(iocb->ki_pos != pos);
- return __generic_file_aio_read(iocb, &local_iov, 1, &iocb->ki_pos);
-}
EXPORT_SYMBOL(generic_file_aio_read);
-ssize_t
-generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
-{
- struct iovec local_iov = { .iov_base = buf, .iov_len = count };
- struct kiocb kiocb;
- ssize_t ret;
-
- init_sync_kiocb(&kiocb, filp);
- ret = __generic_file_aio_read(&kiocb, &local_iov, 1, ppos);
- if (-EIOCBQUEUED == ret)
- ret = wait_on_sync_kiocb(&kiocb);
- return ret;
-}
-EXPORT_SYMBOL(generic_file_read);
-
int file_send_actor(read_descriptor_t * desc, struct page *page, unsigned long offset, unsigned long size)
{
ssize_t written;
@@ -1471,7 +1449,7 @@ outside_data_content:
* accessible..
*/
if (area->vm_mm == current->mm)
- return NULL;
+ return NOPAGE_SIGBUS;
/* Fall through to the non-read-ahead case */
no_cached_page:
/*
@@ -1496,7 +1474,7 @@ no_cached_page:
*/
if (error == -ENOMEM)
return NOPAGE_OOM;
- return NULL;
+ return NOPAGE_SIGBUS;
page_not_uptodate:
if (!did_readaround) {
@@ -1565,7 +1543,7 @@ page_not_uptodate:
*/
shrink_readahead_size_eio(file, ra);
page_cache_release(page);
- return NULL;
+ return NOPAGE_SIGBUS;
}
EXPORT_SYMBOL(filemap_nopage);
@@ -1906,11 +1884,10 @@ repeat:
* if suid or (sgid and xgrp)
* remove privs
*/
-int remove_suid(struct dentry *dentry)
+int should_remove_suid(struct dentry *dentry)
{
mode_t mode = dentry->d_inode->i_mode;
int kill = 0;
- int result = 0;
/* suid always must be killed */
if (unlikely(mode & S_ISUID))
@@ -1923,13 +1900,28 @@ int remove_suid(struct dentry *dentry)
if (unlikely((mode & S_ISGID) && (mode & S_IXGRP)))
kill |= ATTR_KILL_SGID;
- if (unlikely(kill && !capable(CAP_FSETID))) {
- struct iattr newattrs;
+ if (unlikely(kill && !capable(CAP_FSETID)))
+ return kill;
- newattrs.ia_valid = ATTR_FORCE | kill;
- result = notify_change(dentry, &newattrs);
- }
- return result;
+ return 0;
+}
+
+int __remove_suid(struct dentry *dentry, int kill)
+{
+ struct iattr newattrs;
+
+ newattrs.ia_valid = ATTR_FORCE | kill;
+ return notify_change(dentry, &newattrs);
+}
+
+int remove_suid(struct dentry *dentry)
+{
+ int kill = should_remove_suid(dentry);
+
+ if (unlikely(kill))
+ return __remove_suid(dentry, kill);
+
+ return 0;
}
EXPORT_SYMBOL(remove_suid);
@@ -2020,6 +2012,7 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, i
if (unlikely(*pos + *count > inode->i_sb->s_maxbytes))
*count = inode->i_sb->s_maxbytes - *pos;
} else {
+#ifdef CONFIG_BLOCK
loff_t isize;
if (bdev_read_only(I_BDEV(inode)))
return -EPERM;
@@ -2031,6 +2024,9 @@ inline int generic_write_checks(struct file *file, loff_t *pos, size_t *count, i
if (*pos + *count > isize)
*count = isize - *pos;
+#else
+ return -EPERM;
+#endif
}
return 0;
}
@@ -2240,7 +2236,7 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
unsigned long nr_segs, loff_t *ppos)
{
struct file *file = iocb->ki_filp;
- const struct address_space * mapping = file->f_mapping;
+ struct address_space * mapping = file->f_mapping;
size_t ocount; /* original count */
size_t count; /* after file limit checks */
struct inode *inode = mapping->host;
@@ -2293,8 +2289,11 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
/* coalesce the iovecs and go direct-to-BIO for O_DIRECT */
if (unlikely(file->f_flags & O_DIRECT)) {
- written = generic_file_direct_write(iocb, iov,
- &nr_segs, pos, ppos, count, ocount);
+ loff_t endbyte;
+ ssize_t written_buffered;
+
+ written = generic_file_direct_write(iocb, iov, &nr_segs, pos,
+ ppos, count, ocount);
if (written < 0 || written == count)
goto out;
/*
@@ -2303,30 +2302,66 @@ __generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
*/
pos += written;
count -= written;
- }
+ written_buffered = generic_file_buffered_write(iocb, iov,
+ nr_segs, pos, ppos, count,
+ written);
+ /*
+ * If generic_file_buffered_write() retuned a synchronous error
+ * then we want to return the number of bytes which were
+ * direct-written, or the error code if that was zero. Note
+ * that this differs from normal direct-io semantics, which
+ * will return -EFOO even if some bytes were written.
+ */
+ if (written_buffered < 0) {
+ err = written_buffered;
+ goto out;
+ }
- written = generic_file_buffered_write(iocb, iov, nr_segs,
- pos, ppos, count, written);
+ /*
+ * We need to ensure that the page cache pages are written to
+ * disk and invalidated to preserve the expected O_DIRECT
+ * semantics.
+ */
+ endbyte = pos + written_buffered - written - 1;
+ err = do_sync_file_range(file, pos, endbyte,
+ SYNC_FILE_RANGE_WAIT_BEFORE|
+ SYNC_FILE_RANGE_WRITE|
+ SYNC_FILE_RANGE_WAIT_AFTER);
+ if (err == 0) {
+ written = written_buffered;
+ invalidate_mapping_pages(mapping,
+ pos >> PAGE_CACHE_SHIFT,
+ endbyte >> PAGE_CACHE_SHIFT);
+ } else {
+ /*
+ * We don't know how much we wrote, so just return
+ * the number of bytes which were direct-written
+ */
+ }
+ } else {
+ written = generic_file_buffered_write(iocb, iov, nr_segs,
+ pos, ppos, count, written);
+ }
out:
current->backing_dev_info = NULL;
return written ? written : err;
}
-EXPORT_SYMBOL(generic_file_aio_write_nolock);
-ssize_t
-generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
+ssize_t generic_file_aio_write_nolock(struct kiocb *iocb,
+ const struct iovec *iov, unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
ssize_t ret;
- loff_t pos = *ppos;
- ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs, ppos);
+ BUG_ON(iocb->ki_pos != pos);
+
+ ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs,
+ &iocb->ki_pos);
if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
- int err;
+ ssize_t err;
err = sync_page_range_nolock(inode, mapping, pos, ret);
if (err < 0)
@@ -2334,51 +2369,21 @@ generic_file_aio_write_nolock(struct kiocb *iocb, const struct iovec *iov,
}
return ret;
}
+EXPORT_SYMBOL(generic_file_aio_write_nolock);
-static ssize_t
-__generic_file_write_nolock(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
-{
- struct kiocb kiocb;
- ssize_t ret;
-
- init_sync_kiocb(&kiocb, file);
- ret = __generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
- if (ret == -EIOCBQUEUED)
- ret = wait_on_sync_kiocb(&kiocb);
- return ret;
-}
-
-ssize_t
-generic_file_write_nolock(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
-{
- struct kiocb kiocb;
- ssize_t ret;
-
- init_sync_kiocb(&kiocb, file);
- ret = generic_file_aio_write_nolock(&kiocb, iov, nr_segs, ppos);
- if (-EIOCBQUEUED == ret)
- ret = wait_on_sync_kiocb(&kiocb);
- return ret;
-}
-EXPORT_SYMBOL(generic_file_write_nolock);
-
-ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
+ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct file *file = iocb->ki_filp;
struct address_space *mapping = file->f_mapping;
struct inode *inode = mapping->host;
ssize_t ret;
- struct iovec local_iov = { .iov_base = (void __user *)buf,
- .iov_len = count };
BUG_ON(iocb->ki_pos != pos);
mutex_lock(&inode->i_mutex);
- ret = __generic_file_aio_write_nolock(iocb, &local_iov, 1,
- &iocb->ki_pos);
+ ret = __generic_file_aio_write_nolock(iocb, iov, nr_segs,
+ &iocb->ki_pos);
mutex_unlock(&inode->i_mutex);
if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
@@ -2392,66 +2397,6 @@ ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf,
}
EXPORT_SYMBOL(generic_file_aio_write);
-ssize_t generic_file_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct address_space *mapping = file->f_mapping;
- struct inode *inode = mapping->host;
- ssize_t ret;
- struct iovec local_iov = { .iov_base = (void __user *)buf,
- .iov_len = count };
-
- mutex_lock(&inode->i_mutex);
- ret = __generic_file_write_nolock(file, &local_iov, 1, ppos);
- mutex_unlock(&inode->i_mutex);
-
- if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
- ssize_t err;
-
- err = sync_page_range(inode, mapping, *ppos - ret, ret);
- if (err < 0)
- ret = err;
- }
- return ret;
-}
-EXPORT_SYMBOL(generic_file_write);
-
-ssize_t generic_file_readv(struct file *filp, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
-{
- struct kiocb kiocb;
- ssize_t ret;
-
- init_sync_kiocb(&kiocb, filp);
- ret = __generic_file_aio_read(&kiocb, iov, nr_segs, ppos);
- if (-EIOCBQUEUED == ret)
- ret = wait_on_sync_kiocb(&kiocb);
- return ret;
-}
-EXPORT_SYMBOL(generic_file_readv);
-
-ssize_t generic_file_writev(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
-{
- struct address_space *mapping = file->f_mapping;
- struct inode *inode = mapping->host;
- ssize_t ret;
-
- mutex_lock(&inode->i_mutex);
- ret = __generic_file_write_nolock(file, iov, nr_segs, ppos);
- mutex_unlock(&inode->i_mutex);
-
- if (ret > 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
- int err;
-
- err = sync_page_range(inode, mapping, *ppos - ret, ret);
- if (err < 0)
- ret = err;
- }
- return ret;
-}
-EXPORT_SYMBOL(generic_file_writev);
-
/*
* Called under i_mutex for writes to S_ISREG files. Returns -EIO if something
* went wrong during pagecache shootdown.
@@ -2491,3 +2436,33 @@ generic_file_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
}
return retval;
}
+
+/**
+ * try_to_release_page() - release old fs-specific metadata on a page
+ *
+ * @page: the page which the kernel is trying to free
+ * @gfp_mask: memory allocation flags (and I/O mode)
+ *
+ * The address_space is to try to release any data against the page
+ * (presumably at page->private). If the release was successful, return `1'.
+ * Otherwise return zero.
+ *
+ * The @gfp_mask argument specifies whether I/O may be performed to release
+ * this page (__GFP_IO), and whether the call may block (__GFP_WAIT).
+ *
+ * NOTE: @gfp_mask may go away, and this function may become non-blocking.
+ */
+int try_to_release_page(struct page *page, gfp_t gfp_mask)
+{
+ struct address_space * const mapping = page->mapping;
+
+ BUG_ON(!PageLocked(page));
+ if (PageWriteback(page))
+ return 0;
+
+ if (mapping && mapping->a_ops->releasepage)
+ return mapping->a_ops->releasepage(page, gfp_mask);
+ return try_to_free_buffers(page);
+}
+
+EXPORT_SYMBOL(try_to_release_page);
diff --git a/mm/filemap.h b/mm/filemap.h
index 3f2a343c6015..c2bff04c84ed 100644
--- a/mm/filemap.h
+++ b/mm/filemap.h
@@ -12,7 +12,6 @@
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/uio.h>
-#include <linux/config.h>
#include <linux/uaccess.h>
size_t
diff --git a/mm/fremap.c b/mm/fremap.c
index aa30618ec6b2..7a9d0f5d246d 100644
--- a/mm/fremap.c
+++ b/mm/fremap.c
@@ -39,7 +39,7 @@ static int zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
} else {
if (!pte_file(pte))
free_swap_and_cache(pte_to_swp_entry(pte));
- pte_clear(mm, addr, ptep);
+ pte_clear_not_present_full(mm, addr, ptep, 0);
}
return !!page;
}
diff --git a/mm/highmem.c b/mm/highmem.c
index ee5519b176ee..0206e7e5018c 100644
--- a/mm/highmem.c
+++ b/mm/highmem.c
@@ -29,13 +29,6 @@
#include <linux/blktrace_api.h>
#include <asm/tlbflush.h>
-static mempool_t *page_pool, *isa_page_pool;
-
-static void *mempool_alloc_pages_isa(gfp_t gfp_mask, void *data)
-{
- return mempool_alloc_pages(gfp_mask | GFP_DMA, data);
-}
-
/*
* Virtual_count is not a pure "count".
* 0 means that it is not mapped, and has not been mapped
@@ -217,282 +210,8 @@ void fastcall kunmap_high(struct page *page)
}
EXPORT_SYMBOL(kunmap_high);
-
-#define POOL_SIZE 64
-
-static __init int init_emergency_pool(void)
-{
- struct sysinfo i;
- si_meminfo(&i);
- si_swapinfo(&i);
-
- if (!i.totalhigh)
- return 0;
-
- page_pool = mempool_create_page_pool(POOL_SIZE, 0);
- BUG_ON(!page_pool);
- printk("highmem bounce pool size: %d pages\n", POOL_SIZE);
-
- return 0;
-}
-
-__initcall(init_emergency_pool);
-
-/*
- * highmem version, map in to vec
- */
-static void bounce_copy_vec(struct bio_vec *to, unsigned char *vfrom)
-{
- unsigned long flags;
- unsigned char *vto;
-
- local_irq_save(flags);
- vto = kmap_atomic(to->bv_page, KM_BOUNCE_READ);
- memcpy(vto + to->bv_offset, vfrom, to->bv_len);
- kunmap_atomic(vto, KM_BOUNCE_READ);
- local_irq_restore(flags);
-}
-
-#else /* CONFIG_HIGHMEM */
-
-#define bounce_copy_vec(to, vfrom) \
- memcpy(page_address((to)->bv_page) + (to)->bv_offset, vfrom, (to)->bv_len)
-
#endif
-#define ISA_POOL_SIZE 16
-
-/*
- * gets called "every" time someone init's a queue with BLK_BOUNCE_ISA
- * as the max address, so check if the pool has already been created.
- */
-int init_emergency_isa_pool(void)
-{
- if (isa_page_pool)
- return 0;
-
- isa_page_pool = mempool_create(ISA_POOL_SIZE, mempool_alloc_pages_isa,
- mempool_free_pages, (void *) 0);
- BUG_ON(!isa_page_pool);
-
- printk("isa bounce pool size: %d pages\n", ISA_POOL_SIZE);
- return 0;
-}
-
-/*
- * Simple bounce buffer support for highmem pages. Depending on the
- * queue gfp mask set, *to may or may not be a highmem page. kmap it
- * always, it will do the Right Thing
- */
-static void copy_to_high_bio_irq(struct bio *to, struct bio *from)
-{
- unsigned char *vfrom;
- struct bio_vec *tovec, *fromvec;
- int i;
-
- __bio_for_each_segment(tovec, to, i, 0) {
- fromvec = from->bi_io_vec + i;
-
- /*
- * not bounced
- */
- if (tovec->bv_page == fromvec->bv_page)
- continue;
-
- /*
- * fromvec->bv_offset and fromvec->bv_len might have been
- * modified by the block layer, so use the original copy,
- * bounce_copy_vec already uses tovec->bv_len
- */
- vfrom = page_address(fromvec->bv_page) + tovec->bv_offset;
-
- flush_dcache_page(tovec->bv_page);
- bounce_copy_vec(tovec, vfrom);
- }
-}
-
-static void bounce_end_io(struct bio *bio, mempool_t *pool, int err)
-{
- struct bio *bio_orig = bio->bi_private;
- struct bio_vec *bvec, *org_vec;
- int i;
-
- if (test_bit(BIO_EOPNOTSUPP, &bio->bi_flags))
- set_bit(BIO_EOPNOTSUPP, &bio_orig->bi_flags);
-
- /*
- * free up bounce indirect pages used
- */
- __bio_for_each_segment(bvec, bio, i, 0) {
- org_vec = bio_orig->bi_io_vec + i;
- if (bvec->bv_page == org_vec->bv_page)
- continue;
-
- dec_zone_page_state(bvec->bv_page, NR_BOUNCE);
- mempool_free(bvec->bv_page, pool);
- }
-
- bio_endio(bio_orig, bio_orig->bi_size, err);
- bio_put(bio);
-}
-
-static int bounce_end_io_write(struct bio *bio, unsigned int bytes_done, int err)
-{
- if (bio->bi_size)
- return 1;
-
- bounce_end_io(bio, page_pool, err);
- return 0;
-}
-
-static int bounce_end_io_write_isa(struct bio *bio, unsigned int bytes_done, int err)
-{
- if (bio->bi_size)
- return 1;
-
- bounce_end_io(bio, isa_page_pool, err);
- return 0;
-}
-
-static void __bounce_end_io_read(struct bio *bio, mempool_t *pool, int err)
-{
- struct bio *bio_orig = bio->bi_private;
-
- if (test_bit(BIO_UPTODATE, &bio->bi_flags))
- copy_to_high_bio_irq(bio_orig, bio);
-
- bounce_end_io(bio, pool, err);
-}
-
-static int bounce_end_io_read(struct bio *bio, unsigned int bytes_done, int err)
-{
- if (bio->bi_size)
- return 1;
-
- __bounce_end_io_read(bio, page_pool, err);
- return 0;
-}
-
-static int bounce_end_io_read_isa(struct bio *bio, unsigned int bytes_done, int err)
-{
- if (bio->bi_size)
- return 1;
-
- __bounce_end_io_read(bio, isa_page_pool, err);
- return 0;
-}
-
-static void __blk_queue_bounce(request_queue_t *q, struct bio **bio_orig,
- mempool_t *pool)
-{
- struct page *page;
- struct bio *bio = NULL;
- int i, rw = bio_data_dir(*bio_orig);
- struct bio_vec *to, *from;
-
- bio_for_each_segment(from, *bio_orig, i) {
- page = from->bv_page;
-
- /*
- * is destination page below bounce pfn?
- */
- if (page_to_pfn(page) < q->bounce_pfn)
- continue;
-
- /*
- * irk, bounce it
- */
- if (!bio)
- bio = bio_alloc(GFP_NOIO, (*bio_orig)->bi_vcnt);
-
- to = bio->bi_io_vec + i;
-
- to->bv_page = mempool_alloc(pool, q->bounce_gfp);
- to->bv_len = from->bv_len;
- to->bv_offset = from->bv_offset;
- inc_zone_page_state(to->bv_page, NR_BOUNCE);
-
- if (rw == WRITE) {
- char *vto, *vfrom;
-
- flush_dcache_page(from->bv_page);
- vto = page_address(to->bv_page) + to->bv_offset;
- vfrom = kmap(from->bv_page) + from->bv_offset;
- memcpy(vto, vfrom, to->bv_len);
- kunmap(from->bv_page);
- }
- }
-
- /*
- * no pages bounced
- */
- if (!bio)
- return;
-
- /*
- * at least one page was bounced, fill in possible non-highmem
- * pages
- */
- __bio_for_each_segment(from, *bio_orig, i, 0) {
- to = bio_iovec_idx(bio, i);
- if (!to->bv_page) {
- to->bv_page = from->bv_page;
- to->bv_len = from->bv_len;
- to->bv_offset = from->bv_offset;
- }
- }
-
- bio->bi_bdev = (*bio_orig)->bi_bdev;
- bio->bi_flags |= (1 << BIO_BOUNCED);
- bio->bi_sector = (*bio_orig)->bi_sector;
- bio->bi_rw = (*bio_orig)->bi_rw;
-
- bio->bi_vcnt = (*bio_orig)->bi_vcnt;
- bio->bi_idx = (*bio_orig)->bi_idx;
- bio->bi_size = (*bio_orig)->bi_size;
-
- if (pool == page_pool) {
- bio->bi_end_io = bounce_end_io_write;
- if (rw == READ)
- bio->bi_end_io = bounce_end_io_read;
- } else {
- bio->bi_end_io = bounce_end_io_write_isa;
- if (rw == READ)
- bio->bi_end_io = bounce_end_io_read_isa;
- }
-
- bio->bi_private = *bio_orig;
- *bio_orig = bio;
-}
-
-void blk_queue_bounce(request_queue_t *q, struct bio **bio_orig)
-{
- mempool_t *pool;
-
- /*
- * for non-isa bounce case, just check if the bounce pfn is equal
- * to or bigger than the highest pfn in the system -- in that case,
- * don't waste time iterating over bio segments
- */
- if (!(q->bounce_gfp & GFP_DMA)) {
- if (q->bounce_pfn >= blk_max_pfn)
- return;
- pool = page_pool;
- } else {
- BUG_ON(!isa_page_pool);
- pool = isa_page_pool;
- }
-
- blk_add_trace_bio(q, *bio_orig, BLK_TA_BOUNCE);
-
- /*
- * slow path
- */
- __blk_queue_bounce(q, bio_orig, pool);
-}
-
-EXPORT_SYMBOL(blk_queue_bounce);
-
#if defined(HASHED_PAGE_VIRTUAL)
#define PA_HASH_ORDER 7
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 7c7d03dbf73d..2dbec90dc3ba 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -356,14 +356,16 @@ nomem:
return -ENOMEM;
}
-void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
+void __unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
{
struct mm_struct *mm = vma->vm_mm;
unsigned long address;
pte_t *ptep;
pte_t pte;
struct page *page;
+ struct page *tmp;
+ LIST_HEAD(page_list);
WARN_ON(!is_vm_hugetlb_page(vma));
BUG_ON(start & ~HPAGE_MASK);
@@ -384,12 +386,34 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
continue;
page = pte_page(pte);
- put_page(page);
+ list_add(&page->lru, &page_list);
add_mm_counter(mm, file_rss, (int) -(HPAGE_SIZE / PAGE_SIZE));
}
spin_unlock(&mm->page_table_lock);
flush_tlb_range(vma, start, end);
+ list_for_each_entry_safe(page, tmp, &page_list, lru) {
+ list_del(&page->lru);
+ put_page(page);
+ }
+}
+
+void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ /*
+ * It is undesirable to test vma->vm_file as it should be non-null
+ * for valid hugetlb area. However, vm_file will be NULL in the error
+ * cleanup path of do_mmap_pgoff. When hugetlbfs ->mmap method fails,
+ * do_mmap_pgoff() nullifies vma->vm_file before calling this function
+ * to clean up. Since no pte has actually been setup, it is safe to
+ * do nothing in this case.
+ */
+ if (vma->vm_file) {
+ spin_lock(&vma->vm_file->f_mapping->i_mmap_lock);
+ __unmap_hugepage_range(vma, start, end);
+ spin_unlock(&vma->vm_file->f_mapping->i_mmap_lock);
+ }
}
static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
diff --git a/mm/memory.c b/mm/memory.c
index 92a3ebd8d795..156861fcac43 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -467,7 +467,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
*/
if (is_cow_mapping(vm_flags)) {
ptep_set_wrprotect(src_mm, addr, src_pte);
- pte = *src_pte;
+ pte = pte_wrprotect(pte);
}
/*
@@ -506,6 +506,7 @@ again:
src_pte = pte_offset_map_nested(src_pmd, addr);
src_ptl = pte_lockptr(src_mm, src_pmd);
spin_lock_nested(src_ptl, SINGLE_DEPTH_NESTING);
+ arch_enter_lazy_mmu_mode();
do {
/*
@@ -527,6 +528,7 @@ again:
progress += 8;
} while (dst_pte++, src_pte++, addr += PAGE_SIZE, addr != end);
+ arch_leave_lazy_mmu_mode();
spin_unlock(src_ptl);
pte_unmap_nested(src_pte - 1);
add_mm_rss(dst_mm, rss[0], rss[1]);
@@ -628,6 +630,7 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
int anon_rss = 0;
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ arch_enter_lazy_mmu_mode();
do {
pte_t ptent = *pte;
if (pte_none(ptent)) {
@@ -690,10 +693,11 @@ static unsigned long zap_pte_range(struct mmu_gather *tlb,
continue;
if (!pte_file(ptent))
free_swap_and_cache(pte_to_swp_entry(ptent));
- pte_clear_full(mm, addr, pte, tlb->fullmm);
+ pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
} while (pte++, addr += PAGE_SIZE, (addr != end && *zap_work > 0));
add_mm_rss(mm, file_rss, anon_rss);
+ arch_leave_lazy_mmu_mode();
pte_unmap_unlock(pte - 1, ptl);
return addr;
@@ -1082,6 +1086,7 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
default:
BUG();
}
+ cond_resched();
}
if (pages) {
pages[i] = page;
@@ -1109,6 +1114,7 @@ static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd,
pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
if (!pte)
return -ENOMEM;
+ arch_enter_lazy_mmu_mode();
do {
struct page *page = ZERO_PAGE(addr);
pte_t zero_pte = pte_wrprotect(mk_pte(page, prot));
@@ -1118,6 +1124,7 @@ static int zeromap_pte_range(struct mm_struct *mm, pmd_t *pmd,
BUG_ON(!pte_none(*pte));
set_pte_at(mm, addr, pte, zero_pte);
} while (pte++, addr += PAGE_SIZE, addr != end);
+ arch_leave_lazy_mmu_mode();
pte_unmap_unlock(pte - 1, ptl);
return 0;
}
@@ -1275,11 +1282,13 @@ static int remap_pte_range(struct mm_struct *mm, pmd_t *pmd,
pte = pte_alloc_map_lock(mm, pmd, addr, &ptl);
if (!pte)
return -ENOMEM;
+ arch_enter_lazy_mmu_mode();
do {
BUG_ON(!pte_none(*pte));
set_pte_at(mm, addr, pte, pfn_pte(pfn, prot));
pfn++;
} while (pte++, addr += PAGE_SIZE, addr != end);
+ arch_leave_lazy_mmu_mode();
pte_unmap_unlock(pte - 1, ptl);
return 0;
}
@@ -1443,6 +1452,7 @@ static inline void cow_user_page(struct page *dst, struct page *src, unsigned lo
if (__copy_from_user_inatomic(kaddr, uaddr, PAGE_SIZE))
memset(kaddr, 0, PAGE_SIZE);
kunmap_atomic(kaddr, KM_USER0);
+ flush_dcache_page(dst);
return;
}
@@ -1577,7 +1587,14 @@ gotten:
entry = mk_pte(new_page, vma->vm_page_prot);
entry = maybe_mkwrite(pte_mkdirty(entry), vma);
lazy_mmu_prot_update(entry);
- ptep_establish(vma, address, page_table, entry);
+ /*
+ * Clear the pte entry and flush it first, before updating the
+ * pte with the new entry. This will avoid a race condition
+ * seen in the presence of one thread doing SMC and another
+ * thread doing COW.
+ */
+ ptep_clear_flush(vma, address, page_table);
+ set_pte_at(mm, address, page_table, entry);
update_mmu_cache(vma, address, entry);
lru_cache_add_active(new_page);
page_add_new_anon_rmap(new_page, vma, address);
@@ -2154,11 +2171,13 @@ retry:
* after the next truncate_count read.
*/
- /* no page was available -- either SIGBUS or OOM */
- if (new_page == NOPAGE_SIGBUS)
+ /* no page was available -- either SIGBUS, OOM or REFAULT */
+ if (unlikely(new_page == NOPAGE_SIGBUS))
return VM_FAULT_SIGBUS;
- if (new_page == NOPAGE_OOM)
+ else if (unlikely(new_page == NOPAGE_OOM))
return VM_FAULT_OOM;
+ else if (unlikely(new_page == NOPAGE_REFAULT))
+ return VM_FAULT_MINOR;
/*
* Should we do an early C-O-W break?
@@ -2256,6 +2275,54 @@ oom:
}
/*
+ * do_no_pfn() tries to create a new page mapping for a page without
+ * a struct_page backing it
+ *
+ * As this is called only for pages that do not currently exist, we
+ * do not need to flush old virtual caches or the TLB.
+ *
+ * We enter with non-exclusive mmap_sem (to exclude vma changes,
+ * but allow concurrent faults), and pte mapped but not yet locked.
+ * We return with mmap_sem still held, but pte unmapped and unlocked.
+ *
+ * It is expected that the ->nopfn handler always returns the same pfn
+ * for a given virtual mapping.
+ *
+ * Mark this `noinline' to prevent it from bloating the main pagefault code.
+ */
+static noinline int do_no_pfn(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long address, pte_t *page_table, pmd_t *pmd,
+ int write_access)
+{
+ spinlock_t *ptl;
+ pte_t entry;
+ unsigned long pfn;
+ int ret = VM_FAULT_MINOR;
+
+ pte_unmap(page_table);
+ BUG_ON(!(vma->vm_flags & VM_PFNMAP));
+ BUG_ON(is_cow_mapping(vma->vm_flags));
+
+ pfn = vma->vm_ops->nopfn(vma, address & PAGE_MASK);
+ if (pfn == NOPFN_OOM)
+ return VM_FAULT_OOM;
+ if (pfn == NOPFN_SIGBUS)
+ return VM_FAULT_SIGBUS;
+
+ page_table = pte_offset_map_lock(mm, pmd, address, &ptl);
+
+ /* Only go through if we didn't race with anybody else... */
+ if (pte_none(*page_table)) {
+ entry = pfn_pte(pfn, vma->vm_page_prot);
+ if (write_access)
+ entry = maybe_mkwrite(pte_mkdirty(entry), vma);
+ set_pte_at(mm, address, page_table, entry);
+ }
+ pte_unmap_unlock(page_table, ptl);
+ return ret;
+}
+
+/*
* Fault of a previously existing named mapping. Repopulate the pte
* from the encoded file_pte if possible. This enables swappable
* nonlinear vmas.
@@ -2317,11 +2384,17 @@ static inline int handle_pte_fault(struct mm_struct *mm,
old_entry = entry = *pte;
if (!pte_present(entry)) {
if (pte_none(entry)) {
- if (!vma->vm_ops || !vma->vm_ops->nopage)
- return do_anonymous_page(mm, vma, address,
- pte, pmd, write_access);
- return do_no_page(mm, vma, address,
- pte, pmd, write_access);
+ if (vma->vm_ops) {
+ if (vma->vm_ops->nopage)
+ return do_no_page(mm, vma, address,
+ pte, pmd,
+ write_access);
+ if (unlikely(vma->vm_ops->nopfn))
+ return do_no_pfn(mm, vma, address, pte,
+ pmd, write_access);
+ }
+ return do_anonymous_page(mm, vma, address,
+ pte, pmd, write_access);
}
if (pte_file(entry))
return do_file_page(mm, vma, address,
@@ -2550,3 +2623,56 @@ int in_gate_area_no_task(unsigned long addr)
}
#endif /* __HAVE_ARCH_GATE_AREA */
+
+/*
+ * Access another process' address space.
+ * Source/target buffer must be kernel space,
+ * Do not walk the page table directly, use get_user_pages
+ */
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ struct page *page;
+ void *old_buf = buf;
+
+ mm = get_task_mm(tsk);
+ if (!mm)
+ return 0;
+
+ down_read(&mm->mmap_sem);
+ /* ignore errors, just check how much was sucessfully transfered */
+ while (len) {
+ int bytes, ret, offset;
+ void *maddr;
+
+ ret = get_user_pages(tsk, mm, addr, 1,
+ write, 1, &page, &vma);
+ if (ret <= 0)
+ break;
+
+ bytes = len;
+ offset = addr & (PAGE_SIZE-1);
+ if (bytes > PAGE_SIZE-offset)
+ bytes = PAGE_SIZE-offset;
+
+ maddr = kmap(page);
+ if (write) {
+ copy_to_user_page(vma, page, addr,
+ maddr + offset, buf, bytes);
+ set_page_dirty_lock(page);
+ } else {
+ copy_from_user_page(vma, page, addr,
+ buf, maddr + offset, bytes);
+ }
+ kunmap(page);
+ page_cache_release(page);
+ len -= bytes;
+ buf += bytes;
+ addr += bytes;
+ }
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+
+ return buf - old_buf;
+}
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index c37319542b70..fd678a662eae 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -13,6 +13,7 @@
#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/pagevec.h>
+#include <linux/writeback.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/cpu.h>
@@ -21,11 +22,41 @@
#include <linux/highmem.h>
#include <linux/vmalloc.h>
#include <linux/ioport.h>
+#include <linux/cpuset.h>
#include <asm/tlbflush.h>
-extern void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn,
- unsigned long size);
+/* add this memory to iomem resource */
+static struct resource *register_memory_resource(u64 start, u64 size)
+{
+ struct resource *res;
+ res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+ BUG_ON(!res);
+
+ res->name = "System RAM";
+ res->start = start;
+ res->end = start + size - 1;
+ res->flags = IORESOURCE_MEM;
+ if (request_resource(&iomem_resource, res) < 0) {
+ printk("System RAM resource %llx - %llx cannot be added\n",
+ (unsigned long long)res->start, (unsigned long long)res->end);
+ kfree(res);
+ res = NULL;
+ }
+ return res;
+}
+
+static void release_memory_resource(struct resource *res)
+{
+ if (!res)
+ return;
+ release_resource(res);
+ kfree(res);
+ return;
+}
+
+
+#ifdef CONFIG_MEMORY_HOTPLUG_SPARSE
static int __add_zone(struct zone *zone, unsigned long phys_start_pfn)
{
struct pglist_data *pgdat = zone->zone_pgdat;
@@ -45,8 +76,6 @@ static int __add_zone(struct zone *zone, unsigned long phys_start_pfn)
return 0;
}
-extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
- int nr_pages);
static int __add_section(struct zone *zone, unsigned long phys_start_pfn)
{
int nr_pages = PAGES_PER_SECTION;
@@ -191,8 +220,10 @@ int online_pages(unsigned long pfn, unsigned long nr_pages)
if (need_zonelists_rebuild)
build_all_zonelists();
vm_total_pages = nr_free_pagecache_pages();
+ writeback_set_ratelimit();
return 0;
}
+#endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
static pg_data_t *hotadd_new_pgdat(int nid, u64 start)
{
@@ -222,36 +253,6 @@ static void rollback_node_hotadd(int nid, pg_data_t *pgdat)
return;
}
-/* add this memory to iomem resource */
-static struct resource *register_memory_resource(u64 start, u64 size)
-{
- struct resource *res;
- res = kzalloc(sizeof(struct resource), GFP_KERNEL);
- BUG_ON(!res);
-
- res->name = "System RAM";
- res->start = start;
- res->end = start + size - 1;
- res->flags = IORESOURCE_MEM;
- if (request_resource(&iomem_resource, res) < 0) {
- printk("System RAM resource %llx - %llx cannot be added\n",
- (unsigned long long)res->start, (unsigned long long)res->end);
- kfree(res);
- res = NULL;
- }
- return res;
-}
-
-static void release_memory_resource(struct resource *res)
-{
- if (!res)
- return;
- release_resource(res);
- kfree(res);
- return;
-}
-
-
int add_memory(int nid, u64 start, u64 size)
{
@@ -283,6 +284,8 @@ int add_memory(int nid, u64 start, u64 size)
/* we online node here. we can't roll back from here. */
node_set_online(nid);
+ cpuset_track_online_nodes();
+
if (new_pgdat) {
ret = register_one_node(nid);
/*
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 38f89650bc84..617fb31086ee 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -727,7 +727,7 @@ int do_migrate_pages(struct mm_struct *mm,
return -ENOSYS;
}
-static struct page *new_vma_page(struct page *page, unsigned long private)
+static struct page *new_vma_page(struct page *page, unsigned long private, int **x)
{
return NULL;
}
@@ -1136,7 +1136,9 @@ static unsigned interleave_nodes(struct mempolicy *policy)
*/
unsigned slab_node(struct mempolicy *policy)
{
- switch (policy->policy) {
+ int pol = policy ? policy->policy : MPOL_DEFAULT;
+
+ switch (pol) {
case MPOL_INTERLEAVE:
return interleave_nodes(policy);
@@ -1322,12 +1324,11 @@ struct mempolicy *__mpol_copy(struct mempolicy *old)
atomic_set(&new->refcnt, 1);
if (new->policy == MPOL_BIND) {
int sz = ksize(old->v.zonelist);
- new->v.zonelist = kmalloc(sz, SLAB_KERNEL);
+ new->v.zonelist = kmemdup(old->v.zonelist, sz, SLAB_KERNEL);
if (!new->v.zonelist) {
kmem_cache_free(policy_cache, new);
return ERR_PTR(-ENOMEM);
}
- memcpy(new->v.zonelist, old->v.zonelist, sz);
}
return new;
}
diff --git a/mm/migrate.c b/mm/migrate.c
index 20a8c2687b1e..ba2453f9483d 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -409,6 +409,7 @@ int migrate_page(struct address_space *mapping,
}
EXPORT_SYMBOL(migrate_page);
+#ifdef CONFIG_BLOCK
/*
* Migration function for pages with buffers. This function can only be used
* if the underlying filesystem guarantees that no other references to "page"
@@ -466,6 +467,7 @@ int buffer_migrate_page(struct address_space *mapping,
return 0;
}
EXPORT_SYMBOL(buffer_migrate_page);
+#endif
/*
* Writeback a page to clean the dirty state
@@ -525,7 +527,7 @@ static int fallback_migrate_page(struct address_space *mapping,
* Buffers may be managed in a filesystem specific way.
* We must have no buffers or drop them.
*/
- if (page_has_buffers(page) &&
+ if (PagePrivate(page) &&
!try_to_release_page(page, GFP_KERNEL))
return -EAGAIN;
diff --git a/mm/mmap.c b/mm/mmap.c
index eea8eefd51a8..497e502dfd6b 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -900,17 +900,6 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
int accountable = 1;
unsigned long charged = 0, reqprot = prot;
- if (file) {
- if (is_file_hugepages(file))
- accountable = 0;
-
- if (!file->f_op || !file->f_op->mmap)
- return -ENODEV;
-
- if ((prot & PROT_EXEC) &&
- (file->f_vfsmnt->mnt_flags & MNT_NOEXEC))
- return -EPERM;
- }
/*
* Does the application expect PROT_READ to imply PROT_EXEC?
*
@@ -1000,6 +989,16 @@ unsigned long do_mmap_pgoff(struct file * file, unsigned long addr,
case MAP_PRIVATE:
if (!(file->f_mode & FMODE_READ))
return -EACCES;
+ if (file->f_vfsmnt->mnt_flags & MNT_NOEXEC) {
+ if (vm_flags & VM_EXEC)
+ return -EPERM;
+ vm_flags &= ~VM_MAYEXEC;
+ }
+ if (is_file_hugepages(file))
+ accountable = 0;
+
+ if (!file->f_op || !file->f_op->mmap)
+ return -ENODEV;
break;
default:
diff --git a/mm/mprotect.c b/mm/mprotect.c
index 955f9d0e38aa..3b8f3c0c63f3 100644
--- a/mm/mprotect.c
+++ b/mm/mprotect.c
@@ -34,6 +34,7 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
spinlock_t *ptl;
pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+ arch_enter_lazy_mmu_mode();
do {
oldpte = *pte;
if (pte_present(oldpte)) {
@@ -70,6 +71,7 @@ static void change_pte_range(struct mm_struct *mm, pmd_t *pmd,
}
} while (pte++, addr += PAGE_SIZE, addr != end);
+ arch_leave_lazy_mmu_mode();
pte_unmap_unlock(pte - 1, ptl);
}
diff --git a/mm/mremap.c b/mm/mremap.c
index 7c15cf3373ad..9c769fa29f32 100644
--- a/mm/mremap.c
+++ b/mm/mremap.c
@@ -98,6 +98,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
new_ptl = pte_lockptr(mm, new_pmd);
if (new_ptl != old_ptl)
spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
+ arch_enter_lazy_mmu_mode();
for (; old_addr < old_end; old_pte++, old_addr += PAGE_SIZE,
new_pte++, new_addr += PAGE_SIZE) {
@@ -109,6 +110,7 @@ static void move_ptes(struct vm_area_struct *vma, pmd_t *old_pmd,
set_pte_at(mm, new_addr, new_pte, pte);
}
+ arch_leave_lazy_mmu_mode();
if (new_ptl != old_ptl)
spin_unlock(new_ptl);
pte_unmap_nested(new_pte - 1);
diff --git a/mm/nommu.c b/mm/nommu.c
index d99dea31e443..8bdde9508f3b 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -122,26 +122,50 @@ unsigned int kobjsize(const void *objp)
}
/*
- * The nommu dodgy version :-)
+ * get a list of pages in an address range belonging to the specified process
+ * and indicate the VMA that covers each page
+ * - this is potentially dodgy as we may end incrementing the page count of a
+ * slab page or a secondary page from a compound page
+ * - don't permit access to VMAs that don't support it, such as I/O mappings
*/
int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
unsigned long start, int len, int write, int force,
struct page **pages, struct vm_area_struct **vmas)
{
+ struct vm_area_struct *vma;
+ unsigned long vm_flags;
int i;
- static struct vm_area_struct dummy_vma;
+
+ /* calculate required read or write permissions.
+ * - if 'force' is set, we only require the "MAY" flags.
+ */
+ vm_flags = write ? (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD);
+ vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE);
for (i = 0; i < len; i++) {
+ vma = find_vma(mm, start);
+ if (!vma)
+ goto finish_or_fault;
+
+ /* protect what we can, including chardevs */
+ if (vma->vm_flags & (VM_IO | VM_PFNMAP) ||
+ !(vm_flags & vma->vm_flags))
+ goto finish_or_fault;
+
if (pages) {
pages[i] = virt_to_page(start);
if (pages[i])
page_cache_get(pages[i]);
}
if (vmas)
- vmas[i] = &dummy_vma;
+ vmas[i] = vma;
start += PAGE_SIZE;
}
- return(i);
+
+ return i;
+
+finish_or_fault:
+ return i ? : -EFAULT;
}
EXPORT_SYMBOL(get_user_pages);
@@ -197,7 +221,7 @@ long vwrite(char *buf, char *addr, unsigned long count)
* Allocate enough pages to cover @size from the page level
* allocator and map them into continguos kernel virtual space.
*
- * For tight cotrol over page level allocator and protection flags
+ * For tight control over page level allocator and protection flags
* use __vmalloc() instead.
*/
void *vmalloc(unsigned long size)
@@ -286,6 +310,77 @@ static void show_process_blocks(void)
}
#endif /* DEBUG */
+/*
+ * add a VMA into a process's mm_struct in the appropriate place in the list
+ * - should be called with mm->mmap_sem held writelocked
+ */
+static void add_vma_to_mm(struct mm_struct *mm, struct vm_list_struct *vml)
+{
+ struct vm_list_struct **ppv;
+
+ for (ppv = &current->mm->context.vmlist; *ppv; ppv = &(*ppv)->next)
+ if ((*ppv)->vma->vm_start > vml->vma->vm_start)
+ break;
+
+ vml->next = *ppv;
+ *ppv = vml;
+}
+
+/*
+ * look up the first VMA in which addr resides, NULL if none
+ * - should be called with mm->mmap_sem at least held readlocked
+ */
+struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
+{
+ struct vm_list_struct *loop, *vml;
+
+ /* search the vm_start ordered list */
+ vml = NULL;
+ for (loop = mm->context.vmlist; loop; loop = loop->next) {
+ if (loop->vma->vm_start > addr)
+ break;
+ vml = loop;
+ }
+
+ if (vml && vml->vma->vm_end > addr)
+ return vml->vma;
+
+ return NULL;
+}
+EXPORT_SYMBOL(find_vma);
+
+/*
+ * find a VMA
+ * - we don't extend stack VMAs under NOMMU conditions
+ */
+struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
+{
+ return find_vma(mm, addr);
+}
+
+/*
+ * look up the first VMA exactly that exactly matches addr
+ * - should be called with mm->mmap_sem at least held readlocked
+ */
+static inline struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
+ unsigned long addr)
+{
+ struct vm_list_struct *vml;
+
+ /* search the vm_start ordered list */
+ for (vml = mm->context.vmlist; vml; vml = vml->next) {
+ if (vml->vma->vm_start == addr)
+ return vml->vma;
+ if (vml->vma->vm_start > addr)
+ break;
+ }
+
+ return NULL;
+}
+
+/*
+ * find a VMA in the global tree
+ */
static inline struct vm_area_struct *find_nommu_vma(unsigned long start)
{
struct vm_area_struct *vma;
@@ -305,6 +400,9 @@ static inline struct vm_area_struct *find_nommu_vma(unsigned long start)
return NULL;
}
+/*
+ * add a VMA in the global tree
+ */
static void add_nommu_vma(struct vm_area_struct *vma)
{
struct vm_area_struct *pvma;
@@ -351,6 +449,9 @@ static void add_nommu_vma(struct vm_area_struct *vma)
rb_insert_color(&vma->vm_rb, &nommu_vma_tree);
}
+/*
+ * delete a VMA from the global list
+ */
static void delete_nommu_vma(struct vm_area_struct *vma)
{
struct address_space *mapping;
@@ -828,8 +929,7 @@ unsigned long do_mmap_pgoff(struct file *file,
realalloc += kobjsize(vml);
askedalloc += sizeof(*vml);
- vml->next = current->mm->context.vmlist;
- current->mm->context.vmlist = vml;
+ add_vma_to_mm(current->mm, vml);
up_write(&nommu_vma_sem);
@@ -848,7 +948,8 @@ unsigned long do_mmap_pgoff(struct file *file,
up_write(&nommu_vma_sem);
kfree(vml);
if (vma) {
- fput(vma->vm_file);
+ if (vma->vm_file)
+ fput(vma->vm_file);
kfree(vma);
}
return ret;
@@ -908,6 +1009,11 @@ static void put_vma(struct vm_area_struct *vma)
}
}
+/*
+ * release a mapping
+ * - under NOMMU conditions the parameters must match exactly to the mapping to
+ * be removed
+ */
int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
{
struct vm_list_struct *vml, **parent;
@@ -917,10 +1023,13 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
printk("do_munmap:\n");
#endif
- for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next)
+ for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) {
+ if ((*parent)->vma->vm_start > addr)
+ break;
if ((*parent)->vma->vm_start == addr &&
((len == 0) || ((*parent)->vma->vm_end == end)))
goto found;
+ }
printk("munmap of non-mmaped memory by process %d (%s): %p\n",
current->pid, current->comm, (void *) addr);
@@ -946,7 +1055,20 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len)
return 0;
}
-/* Release all mmaps. */
+asmlinkage long sys_munmap(unsigned long addr, size_t len)
+{
+ int ret;
+ struct mm_struct *mm = current->mm;
+
+ down_write(&mm->mmap_sem);
+ ret = do_munmap(mm, addr, len);
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+/*
+ * Release all mappings
+ */
void exit_mmap(struct mm_struct * mm)
{
struct vm_list_struct *tmp;
@@ -973,37 +1095,26 @@ void exit_mmap(struct mm_struct * mm)
}
}
-asmlinkage long sys_munmap(unsigned long addr, size_t len)
-{
- int ret;
- struct mm_struct *mm = current->mm;
-
- down_write(&mm->mmap_sem);
- ret = do_munmap(mm, addr, len);
- up_write(&mm->mmap_sem);
- return ret;
-}
-
unsigned long do_brk(unsigned long addr, unsigned long len)
{
return -ENOMEM;
}
/*
- * Expand (or shrink) an existing mapping, potentially moving it at the
- * same time (controlled by the MREMAP_MAYMOVE flag and available VM space)
+ * expand (or shrink) an existing mapping, potentially moving it at the same
+ * time (controlled by the MREMAP_MAYMOVE flag and available VM space)
*
- * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise
- * This option implies MREMAP_MAYMOVE.
+ * under NOMMU conditions, we only permit changing a mapping's size, and only
+ * as long as it stays within the hole allocated by the kmalloc() call in
+ * do_mmap_pgoff() and the block is not shareable
*
- * on uClinux, we only permit changing a mapping's size, and only as long as it stays within the
- * hole allocated by the kmalloc() call in do_mmap_pgoff() and the block is not shareable
+ * MREMAP_FIXED is not supported under NOMMU conditions
*/
unsigned long do_mremap(unsigned long addr,
unsigned long old_len, unsigned long new_len,
unsigned long flags, unsigned long new_addr)
{
- struct vm_list_struct *vml = NULL;
+ struct vm_area_struct *vma;
/* insanity checks first */
if (new_len == 0)
@@ -1012,58 +1123,46 @@ unsigned long do_mremap(unsigned long addr,
if (flags & MREMAP_FIXED && new_addr != addr)
return (unsigned long) -EINVAL;
- for (vml = current->mm->context.vmlist; vml; vml = vml->next)
- if (vml->vma->vm_start == addr)
- goto found;
-
- return (unsigned long) -EINVAL;
+ vma = find_vma_exact(current->mm, addr);
+ if (!vma)
+ return (unsigned long) -EINVAL;
- found:
- if (vml->vma->vm_end != vml->vma->vm_start + old_len)
+ if (vma->vm_end != vma->vm_start + old_len)
return (unsigned long) -EFAULT;
- if (vml->vma->vm_flags & VM_MAYSHARE)
+ if (vma->vm_flags & VM_MAYSHARE)
return (unsigned long) -EPERM;
if (new_len > kobjsize((void *) addr))
return (unsigned long) -ENOMEM;
/* all checks complete - do it */
- vml->vma->vm_end = vml->vma->vm_start + new_len;
+ vma->vm_end = vma->vm_start + new_len;
askedalloc -= old_len;
askedalloc += new_len;
- return vml->vma->vm_start;
+ return vma->vm_start;
}
-/*
- * Look up the first VMA which satisfies addr < vm_end, NULL if none
- */
-struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
+asmlinkage unsigned long sys_mremap(unsigned long addr,
+ unsigned long old_len, unsigned long new_len,
+ unsigned long flags, unsigned long new_addr)
{
- struct vm_list_struct *vml;
-
- for (vml = mm->context.vmlist; vml; vml = vml->next)
- if (addr >= vml->vma->vm_start && addr < vml->vma->vm_end)
- return vml->vma;
+ unsigned long ret;
- return NULL;
+ down_write(&current->mm->mmap_sem);
+ ret = do_mremap(addr, old_len, new_len, flags, new_addr);
+ up_write(&current->mm->mmap_sem);
+ return ret;
}
-EXPORT_SYMBOL(find_vma);
-
struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
unsigned int foll_flags)
{
return NULL;
}
-struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr)
-{
- return NULL;
-}
-
int remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
unsigned long to, unsigned long size, pgprot_t prot)
{
@@ -1206,3 +1305,44 @@ struct page *filemap_nopage(struct vm_area_struct *area,
BUG();
return NULL;
}
+
+/*
+ * Access another process' address space.
+ * - source/target buffer must be kernel space
+ */
+int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, int write)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm;
+
+ if (addr + len < addr)
+ return 0;
+
+ mm = get_task_mm(tsk);
+ if (!mm)
+ return 0;
+
+ down_read(&mm->mmap_sem);
+
+ /* the access must start within one of the target process's mappings */
+ vma = find_vma(mm, addr);
+ if (vma) {
+ /* don't overrun this mapping */
+ if (addr + len >= vma->vm_end)
+ len = vma->vm_end - addr;
+
+ /* only read or write mappings where it is permitted */
+ if (write && vma->vm_flags & VM_MAYWRITE)
+ len -= copy_to_user((void *) addr, buf, len);
+ else if (!write && vma->vm_flags & VM_MAYREAD)
+ len -= copy_from_user(buf, (void *) addr, len);
+ else
+ len = 0;
+ } else {
+ len = 0;
+ }
+
+ up_read(&mm->mmap_sem);
+ mmput(mm);
+ return len;
+}
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index bada3d03119f..2e3ce3a928b9 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -15,6 +15,7 @@
* kernel subsystems and hints as to where to find out what things do.
*/
+#include <linux/oom.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/swap.h>
@@ -204,16 +205,30 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
do_posix_clock_monotonic_gettime(&uptime);
do_each_thread(g, p) {
unsigned long points;
- int releasing;
- /* skip kernel threads */
+ /*
+ * skip kernel threads and tasks which have already released
+ * their mm.
+ */
if (!p->mm)
continue;
- /* skip the init task with pid == 1 */
- if (p->pid == 1)
+ /* skip the init task */
+ if (is_init(p))
continue;
/*
+ * This task already has access to memory reserves and is
+ * being killed. Don't allow any other task access to the
+ * memory reserve.
+ *
+ * Note: this may have a chance of deadlock if it gets
+ * blocked waiting for another task which itself is waiting
+ * for memory. Is there a better alternative?
+ */
+ if (test_tsk_thread_flag(p, TIF_MEMDIE))
+ return ERR_PTR(-1UL);
+
+ /*
* This is in the process of releasing memory so wait for it
* to finish before killing some other task by mistake.
*
@@ -221,21 +236,16 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
* go ahead if it is exiting: this will simply set TIF_MEMDIE,
* which will allow it to gain access to memory reserves in
* the process of exiting and releasing its resources.
- * Otherwise we could get an OOM deadlock.
+ * Otherwise we could get an easy OOM deadlock.
*/
- releasing = test_tsk_thread_flag(p, TIF_MEMDIE) ||
- p->flags & PF_EXITING;
- if (releasing) {
- /* PF_DEAD tasks have already released their mm */
- if (p->flags & PF_DEAD)
- continue;
- if (p->flags & PF_EXITING && p == current) {
- chosen = p;
- *ppoints = ULONG_MAX;
- break;
- }
- return ERR_PTR(-1UL);
+ if (p->flags & PF_EXITING) {
+ if (p != current)
+ return ERR_PTR(-1UL);
+
+ chosen = p;
+ *ppoints = ULONG_MAX;
}
+
if (p->oomkilladj == OOM_DISABLE)
continue;
@@ -245,6 +255,7 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
*ppoints = points;
}
} while_each_thread(g, p);
+
return chosen;
}
@@ -255,20 +266,17 @@ static struct task_struct *select_bad_process(unsigned long *ppoints)
*/
static void __oom_kill_task(struct task_struct *p, const char *message)
{
- if (p->pid == 1) {
+ if (is_init(p)) {
WARN_ON(1);
printk(KERN_WARNING "tried to kill init!\n");
return;
}
- task_lock(p);
- if (!p->mm || p->mm == &init_mm) {
+ if (!p->mm) {
WARN_ON(1);
printk(KERN_WARNING "tried to kill an mm-less task!\n");
- task_unlock(p);
return;
}
- task_unlock(p);
if (message) {
printk(KERN_ERR "%s: Killed process %d (%s).\n",
@@ -302,7 +310,7 @@ static int oom_kill_task(struct task_struct *p, const char *message)
* However, this is of no concern to us.
*/
- if (mm == NULL || mm == &init_mm)
+ if (mm == NULL)
return 1;
__oom_kill_task(p, message);
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 555752907dc3..8d9b19f239c3 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -1,5 +1,5 @@
/*
- * mm/page-writeback.c.
+ * mm/page-writeback.c
*
* Copyright (C) 2002, Linus Torvalds.
*
@@ -30,6 +30,8 @@
#include <linux/sysctl.h>
#include <linux/cpu.h>
#include <linux/syscalls.h>
+#include <linux/buffer_head.h>
+#include <linux/pagevec.h>
/*
* The maximum number of pages to writeout in a single bdflush/kupdate
@@ -46,7 +48,6 @@
*/
static long ratelimit_pages = 32;
-static long total_pages; /* The total number of pages in the machine. */
static int dirty_exceeded __cacheline_aligned_in_smp; /* Dirty mem may be over limit */
/*
@@ -126,7 +127,7 @@ get_dirty_limits(long *pbackground, long *pdirty,
int unmapped_ratio;
long background;
long dirty;
- unsigned long available_memory = total_pages;
+ unsigned long available_memory = vm_total_pages;
struct task_struct *tsk;
#ifdef CONFIG_HIGHMEM
@@ -141,7 +142,7 @@ get_dirty_limits(long *pbackground, long *pdirty,
unmapped_ratio = 100 - ((global_page_state(NR_FILE_MAPPED) +
global_page_state(NR_ANON_PAGES)) * 100) /
- total_pages;
+ vm_total_pages;
dirty_ratio = vm_dirty_ratio;
if (dirty_ratio > unmapped_ratio / 2)
@@ -221,7 +222,7 @@ static void balance_dirty_pages(struct address_space *mapping)
if (pages_written >= write_chunk)
break; /* We've done our duty */
}
- blk_congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, HZ/10);
}
if (nr_reclaimable + global_page_state(NR_WRITEBACK)
@@ -313,7 +314,7 @@ void throttle_vm_writeout(void)
if (global_page_state(NR_UNSTABLE_NFS) +
global_page_state(NR_WRITEBACK) <= dirty_thresh)
break;
- blk_congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, HZ/10);
}
}
@@ -350,7 +351,7 @@ static void background_writeout(unsigned long _min_pages)
min_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write;
if (wbc.nr_to_write > 0 || wbc.pages_skipped > 0) {
/* Wrote less than expected */
- blk_congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, HZ/10);
if (!wbc.encountered_congestion)
break;
}
@@ -421,7 +422,7 @@ static void wb_kupdate(unsigned long arg)
writeback_inodes(&wbc);
if (wbc.nr_to_write > 0) {
if (wbc.encountered_congestion)
- blk_congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, HZ/10);
else
break; /* All the old data is written */
}
@@ -502,9 +503,9 @@ void laptop_sync_completion(void)
* will write six megabyte chunks, max.
*/
-static void set_ratelimit(void)
+void writeback_set_ratelimit(void)
{
- ratelimit_pages = total_pages / (num_online_cpus() * 32);
+ ratelimit_pages = vm_total_pages / (num_online_cpus() * 32);
if (ratelimit_pages < 16)
ratelimit_pages = 16;
if (ratelimit_pages * PAGE_CACHE_SIZE > 4096 * 1024)
@@ -514,7 +515,7 @@ static void set_ratelimit(void)
static int __cpuinit
ratelimit_handler(struct notifier_block *self, unsigned long u, void *v)
{
- set_ratelimit();
+ writeback_set_ratelimit();
return 0;
}
@@ -533,9 +534,7 @@ void __init page_writeback_init(void)
long buffer_pages = nr_free_buffer_pages();
long correction;
- total_pages = nr_free_pagecache_pages();
-
- correction = (100 * 4 * buffer_pages) / total_pages;
+ correction = (100 * 4 * buffer_pages) / vm_total_pages;
if (correction < 100) {
dirty_background_ratio *= correction;
@@ -549,10 +548,143 @@ void __init page_writeback_init(void)
vm_dirty_ratio = 1;
}
mod_timer(&wb_timer, jiffies + dirty_writeback_interval);
- set_ratelimit();
+ writeback_set_ratelimit();
register_cpu_notifier(&ratelimit_nb);
}
+/**
+ * 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.
+ *
+ * If a page is already under I/O, generic_writepages() 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)
+{
+ 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;
+ 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 = 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 */
+ 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;
+ }
+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;
+ }
+
+ ret = (*writepage)(page, wbc);
+ if (ret) {
+ if (ret == -ENOSPC)
+ set_bit(AS_ENOSPC, &mapping->flags);
+ else
+ set_bit(AS_EIO, &mapping->flags);
+ }
+
+ 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;
+ return ret;
+}
+
+EXPORT_SYMBOL(generic_writepages);
+
int do_writepages(struct address_space *mapping, struct writeback_control *wbc)
{
int ret;
@@ -675,9 +807,11 @@ int fastcall set_page_dirty(struct page *page)
if (likely(mapping)) {
int (*spd)(struct page *) = mapping->a_ops->set_page_dirty;
- if (spd)
- return (*spd)(page);
- return __set_page_dirty_buffers(page);
+#ifdef CONFIG_BLOCK
+ if (!spd)
+ spd = __set_page_dirty_buffers;
+#endif
+ return (*spd)(page);
}
if (!PageDirty(page)) {
if (!TestSetPageDirty(page))
@@ -822,15 +956,6 @@ int test_set_page_writeback(struct page *page)
EXPORT_SYMBOL(test_set_page_writeback);
/*
- * Wakes up tasks that are being throttled due to writeback congestion
- */
-void writeback_congestion_end(void)
-{
- blk_congestion_end(WRITE);
-}
-EXPORT_SYMBOL(writeback_congestion_end);
-
-/*
* Return true if any of the pages in the mapping are marged with the
* passed tag.
*/
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 9810f0a60db7..f5fc45472d5c 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -37,6 +37,9 @@
#include <linux/vmalloc.h>
#include <linux/mempolicy.h>
#include <linux/stop_machine.h>
+#include <linux/sort.h>
+#include <linux/pfn.h>
+#include <linux/backing-dev.h>
#include <asm/tlbflush.h>
#include <asm/div64.h>
@@ -102,6 +105,38 @@ int min_free_kbytes = 1024;
unsigned long __meminitdata nr_kernel_pages;
unsigned long __meminitdata nr_all_pages;
+static unsigned long __initdata dma_reserve;
+
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+ /*
+ * MAX_ACTIVE_REGIONS determines the maxmimum number of distinct
+ * ranges of memory (RAM) that may be registered with add_active_range().
+ * Ranges passed to add_active_range() will be merged if possible
+ * so the number of times add_active_range() can be called is
+ * related to the number of nodes and the number of holes
+ */
+ #ifdef CONFIG_MAX_ACTIVE_REGIONS
+ /* Allow an architecture to set MAX_ACTIVE_REGIONS to save memory */
+ #define MAX_ACTIVE_REGIONS CONFIG_MAX_ACTIVE_REGIONS
+ #else
+ #if MAX_NUMNODES >= 32
+ /* If there can be many nodes, allow up to 50 holes per node */
+ #define MAX_ACTIVE_REGIONS (MAX_NUMNODES*50)
+ #else
+ /* By default, allow up to 256 distinct regions */
+ #define MAX_ACTIVE_REGIONS 256
+ #endif
+ #endif
+
+ struct node_active_region __initdata early_node_map[MAX_ACTIVE_REGIONS];
+ int __initdata nr_nodemap_entries;
+ unsigned long __initdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES];
+ unsigned long __initdata arch_zone_highest_possible_pfn[MAX_NR_ZONES];
+#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
+ unsigned long __initdata node_boundary_start_pfn[MAX_NUMNODES];
+ unsigned long __initdata node_boundary_end_pfn[MAX_NUMNODES];
+#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
+#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
#ifdef CONFIG_DEBUG_VM
static int page_outside_zone_boundaries(struct zone *zone, struct page *page)
@@ -461,17 +496,16 @@ static void __free_pages_ok(struct page *page, unsigned int order)
int i;
int reserved = 0;
- arch_free_page(page, order);
- if (!PageHighMem(page))
- debug_check_no_locks_freed(page_address(page),
- PAGE_SIZE<<order);
-
for (i = 0 ; i < (1 << order) ; ++i)
reserved += free_pages_check(page + i);
if (reserved)
return;
+ if (!PageHighMem(page))
+ debug_check_no_locks_freed(page_address(page),PAGE_SIZE<<order);
+ arch_free_page(page, order);
kernel_map_pages(page, 1 << order, 0);
+
local_irq_save(flags);
__count_vm_events(PGFREE, 1 << order);
free_one_page(page_zone(page), page, order);
@@ -747,13 +781,14 @@ static void fastcall free_hot_cold_page(struct page *page, int cold)
struct per_cpu_pages *pcp;
unsigned long flags;
- arch_free_page(page, 0);
-
if (PageAnon(page))
page->mapping = NULL;
if (free_pages_check(page))
return;
+ if (!PageHighMem(page))
+ debug_check_no_locks_freed(page_address(page), PAGE_SIZE);
+ arch_free_page(page, 0);
kernel_map_pages(page, 1, 0);
pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
@@ -866,7 +901,8 @@ int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
int classzone_idx, int alloc_flags)
{
/* free_pages my go negative - that's OK */
- long min = mark, free_pages = z->free_pages - (1 << order) + 1;
+ unsigned long min = mark;
+ long free_pages = z->free_pages - (1 << order) + 1;
int o;
if (alloc_flags & ALLOC_HIGH)
@@ -908,7 +944,7 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
*/
do {
zone = *z;
- if (unlikely((gfp_mask & __GFP_THISNODE) &&
+ if (unlikely(NUMA_BUILD && (gfp_mask & __GFP_THISNODE) &&
zone->zone_pgdat != zonelist->zones[0]->zone_pgdat))
break;
if ((alloc_flags & ALLOC_CPUSET) &&
@@ -1015,7 +1051,7 @@ nofail_alloc:
if (page)
goto got_pg;
if (gfp_mask & __GFP_NOFAIL) {
- blk_congestion_wait(WRITE, HZ/50);
+ congestion_wait(WRITE, HZ/50);
goto nofail_alloc;
}
}
@@ -1078,7 +1114,7 @@ rebalance:
do_retry = 1;
}
if (do_retry) {
- blk_congestion_wait(WRITE, HZ/50);
+ congestion_wait(WRITE, HZ/50);
goto rebalance;
}
@@ -1222,14 +1258,12 @@ unsigned int nr_free_pagecache_pages(void)
{
return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER));
}
-#ifdef CONFIG_NUMA
-static void show_node(struct zone *zone)
+
+static inline void show_node(struct zone *zone)
{
- printk("Node %ld ", zone_to_nid(zone));
+ if (NUMA_BUILD)
+ printk("Node %ld ", zone_to_nid(zone));
}
-#else
-#define show_node(zone) do { } while (0)
-#endif
void si_meminfo(struct sysinfo *val)
{
@@ -1271,34 +1305,30 @@ void si_meminfo_node(struct sysinfo *val, int nid)
*/
void show_free_areas(void)
{
- int cpu, temperature;
+ int cpu;
unsigned long active;
unsigned long inactive;
unsigned long free;
struct zone *zone;
for_each_zone(zone) {
- show_node(zone);
- printk("%s per-cpu:", zone->name);
-
- if (!populated_zone(zone)) {
- printk(" empty\n");
+ if (!populated_zone(zone))
continue;
- } else
- printk("\n");
+
+ show_node(zone);
+ printk("%s per-cpu:\n", zone->name);
for_each_online_cpu(cpu) {
struct per_cpu_pageset *pageset;
pageset = zone_pcp(zone, cpu);
- for (temperature = 0; temperature < 2; temperature++)
- printk("cpu %d %s: high %d, batch %d used:%d\n",
- cpu,
- temperature ? "cold" : "hot",
- pageset->pcp[temperature].high,
- pageset->pcp[temperature].batch,
- pageset->pcp[temperature].count);
+ printk("CPU %4d: Hot: hi:%5d, btch:%4d usd:%4d "
+ "Cold: hi:%5d, btch:%4d usd:%4d\n",
+ cpu, pageset->pcp[0].high,
+ pageset->pcp[0].batch, pageset->pcp[0].count,
+ pageset->pcp[1].high, pageset->pcp[1].batch,
+ pageset->pcp[1].count);
}
}
@@ -1320,6 +1350,9 @@ void show_free_areas(void)
for_each_zone(zone) {
int i;
+ if (!populated_zone(zone))
+ continue;
+
show_node(zone);
printk("%s"
" free:%lukB"
@@ -1352,12 +1385,11 @@ void show_free_areas(void)
for_each_zone(zone) {
unsigned long nr[MAX_ORDER], flags, order, total = 0;
+ if (!populated_zone(zone))
+ continue;
+
show_node(zone);
printk("%s: ", zone->name);
- if (!populated_zone(zone)) {
- printk("empty\n");
- continue;
- }
spin_lock_irqsave(&zone->lock, flags);
for (order = 0; order < MAX_ORDER; order++) {
@@ -1561,7 +1593,7 @@ static int __meminit __build_all_zonelists(void *dummy)
void __meminit build_all_zonelists(void)
{
if (system_state == SYSTEM_BOOTING) {
- __build_all_zonelists(0);
+ __build_all_zonelists(NULL);
cpuset_init_current_mems_allowed();
} else {
/* we have to stop all cpus to guaranntee there is no user
@@ -1642,25 +1674,6 @@ static inline unsigned long wait_table_bits(unsigned long size)
#define LONG_ALIGN(x) (((x)+(sizeof(long))-1)&~((sizeof(long))-1))
-static void __init calculate_zone_totalpages(struct pglist_data *pgdat,
- unsigned long *zones_size, unsigned long *zholes_size)
-{
- unsigned long realtotalpages, totalpages = 0;
- enum zone_type i;
-
- for (i = 0; i < MAX_NR_ZONES; i++)
- totalpages += zones_size[i];
- pgdat->node_spanned_pages = totalpages;
-
- realtotalpages = totalpages;
- if (zholes_size)
- for (i = 0; i < MAX_NR_ZONES; i++)
- realtotalpages -= zholes_size[i];
- pgdat->node_present_pages = realtotalpages;
- printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id, realtotalpages);
-}
-
-
/*
* Initially all pages are reserved - free ones are freed
* up by free_all_bootmem() once the early boot process is
@@ -1676,6 +1689,8 @@ void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone,
for (pfn = start_pfn; pfn < end_pfn; pfn++) {
if (!early_pfn_valid(pfn))
continue;
+ if (!early_pfn_in_nid(pfn, nid))
+ continue;
page = pfn_to_page(pfn);
set_page_links(page, zone, nid, pfn);
init_page_count(page);
@@ -1818,6 +1833,9 @@ static int __cpuinit process_zones(int cpu)
for_each_zone(zone) {
+ if (!populated_zone(zone))
+ continue;
+
zone_pcp(zone, cpu) = kmalloc_node(sizeof(struct per_cpu_pageset),
GFP_KERNEL, cpu_to_node(cpu));
if (!zone_pcp(zone, cpu))
@@ -1977,6 +1995,349 @@ __meminit int init_currently_empty_zone(struct zone *zone,
return 0;
}
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+/*
+ * Basic iterator support. Return the first range of PFNs for a node
+ * Note: nid == MAX_NUMNODES returns first region regardless of node
+ */
+static int __init first_active_region_index_in_nid(int nid)
+{
+ int i;
+
+ for (i = 0; i < nr_nodemap_entries; i++)
+ if (nid == MAX_NUMNODES || early_node_map[i].nid == nid)
+ return i;
+
+ return -1;
+}
+
+/*
+ * Basic iterator support. Return the next active range of PFNs for a node
+ * Note: nid == MAX_NUMNODES returns next region regardles of node
+ */
+static int __init next_active_region_index_in_nid(int index, int nid)
+{
+ for (index = index + 1; index < nr_nodemap_entries; index++)
+ if (nid == MAX_NUMNODES || early_node_map[index].nid == nid)
+ return index;
+
+ return -1;
+}
+
+#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
+/*
+ * Required by SPARSEMEM. Given a PFN, return what node the PFN is on.
+ * Architectures may implement their own version but if add_active_range()
+ * was used and there are no special requirements, this is a convenient
+ * alternative
+ */
+int __init early_pfn_to_nid(unsigned long pfn)
+{
+ int i;
+
+ for (i = 0; i < nr_nodemap_entries; i++) {
+ unsigned long start_pfn = early_node_map[i].start_pfn;
+ unsigned long end_pfn = early_node_map[i].end_pfn;
+
+ if (start_pfn <= pfn && pfn < end_pfn)
+ return early_node_map[i].nid;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
+
+/* Basic iterator support to walk early_node_map[] */
+#define for_each_active_range_index_in_nid(i, nid) \
+ for (i = first_active_region_index_in_nid(nid); i != -1; \
+ i = next_active_region_index_in_nid(i, nid))
+
+/**
+ * free_bootmem_with_active_regions - Call free_bootmem_node for each active range
+ * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed.
+ * @max_low_pfn: The highest PFN that will be passed to free_bootmem_node
+ *
+ * If an architecture guarantees that all ranges registered with
+ * add_active_ranges() contain no holes and may be freed, this
+ * this function may be used instead of calling free_bootmem() manually.
+ */
+void __init free_bootmem_with_active_regions(int nid,
+ unsigned long max_low_pfn)
+{
+ int i;
+
+ for_each_active_range_index_in_nid(i, nid) {
+ unsigned long size_pages = 0;
+ unsigned long end_pfn = early_node_map[i].end_pfn;
+
+ if (early_node_map[i].start_pfn >= max_low_pfn)
+ continue;
+
+ if (end_pfn > max_low_pfn)
+ end_pfn = max_low_pfn;
+
+ size_pages = end_pfn - early_node_map[i].start_pfn;
+ free_bootmem_node(NODE_DATA(early_node_map[i].nid),
+ PFN_PHYS(early_node_map[i].start_pfn),
+ size_pages << PAGE_SHIFT);
+ }
+}
+
+/**
+ * sparse_memory_present_with_active_regions - Call memory_present for each active range
+ * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used.
+ *
+ * If an architecture guarantees that all ranges registered with
+ * add_active_ranges() contain no holes and may be freed, this
+ * function may be used instead of calling memory_present() manually.
+ */
+void __init sparse_memory_present_with_active_regions(int nid)
+{
+ int i;
+
+ for_each_active_range_index_in_nid(i, nid)
+ memory_present(early_node_map[i].nid,
+ early_node_map[i].start_pfn,
+ early_node_map[i].end_pfn);
+}
+
+/**
+ * push_node_boundaries - Push node boundaries to at least the requested boundary
+ * @nid: The nid of the node to push the boundary for
+ * @start_pfn: The start pfn of the node
+ * @end_pfn: The end pfn of the node
+ *
+ * In reserve-based hot-add, mem_map is allocated that is unused until hotadd
+ * time. Specifically, on x86_64, SRAT will report ranges that can potentially
+ * be hotplugged even though no physical memory exists. This function allows
+ * an arch to push out the node boundaries so mem_map is allocated that can
+ * be used later.
+ */
+#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
+void __init push_node_boundaries(unsigned int nid,
+ unsigned long start_pfn, unsigned long end_pfn)
+{
+ printk(KERN_DEBUG "Entering push_node_boundaries(%u, %lu, %lu)\n",
+ nid, start_pfn, end_pfn);
+
+ /* Initialise the boundary for this node if necessary */
+ if (node_boundary_end_pfn[nid] == 0)
+ node_boundary_start_pfn[nid] = -1UL;
+
+ /* Update the boundaries */
+ if (node_boundary_start_pfn[nid] > start_pfn)
+ node_boundary_start_pfn[nid] = start_pfn;
+ if (node_boundary_end_pfn[nid] < end_pfn)
+ node_boundary_end_pfn[nid] = end_pfn;
+}
+
+/* If necessary, push the node boundary out for reserve hotadd */
+static void __init account_node_boundary(unsigned int nid,
+ unsigned long *start_pfn, unsigned long *end_pfn)
+{
+ printk(KERN_DEBUG "Entering account_node_boundary(%u, %lu, %lu)\n",
+ nid, *start_pfn, *end_pfn);
+
+ /* Return if boundary information has not been provided */
+ if (node_boundary_end_pfn[nid] == 0)
+ return;
+
+ /* Check the boundaries and update if necessary */
+ if (node_boundary_start_pfn[nid] < *start_pfn)
+ *start_pfn = node_boundary_start_pfn[nid];
+ if (node_boundary_end_pfn[nid] > *end_pfn)
+ *end_pfn = node_boundary_end_pfn[nid];
+}
+#else
+void __init push_node_boundaries(unsigned int nid,
+ unsigned long start_pfn, unsigned long end_pfn) {}
+
+static void __init account_node_boundary(unsigned int nid,
+ unsigned long *start_pfn, unsigned long *end_pfn) {}
+#endif
+
+
+/**
+ * get_pfn_range_for_nid - Return the start and end page frames for a node
+ * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned.
+ * @start_pfn: Passed by reference. On return, it will have the node start_pfn.
+ * @end_pfn: Passed by reference. On return, it will have the node end_pfn.
+ *
+ * It returns the start and end page frame of a node based on information
+ * provided by an arch calling add_active_range(). If called for a node
+ * with no available memory, a warning is printed and the start and end
+ * PFNs will be 0.
+ */
+void __init get_pfn_range_for_nid(unsigned int nid,
+ unsigned long *start_pfn, unsigned long *end_pfn)
+{
+ int i;
+ *start_pfn = -1UL;
+ *end_pfn = 0;
+
+ for_each_active_range_index_in_nid(i, nid) {
+ *start_pfn = min(*start_pfn, early_node_map[i].start_pfn);
+ *end_pfn = max(*end_pfn, early_node_map[i].end_pfn);
+ }
+
+ if (*start_pfn == -1UL) {
+ printk(KERN_WARNING "Node %u active with no memory\n", nid);
+ *start_pfn = 0;
+ }
+
+ /* Push the node boundaries out if requested */
+ account_node_boundary(nid, start_pfn, end_pfn);
+}
+
+/*
+ * Return the number of pages a zone spans in a node, including holes
+ * present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node()
+ */
+unsigned long __init zone_spanned_pages_in_node(int nid,
+ unsigned long zone_type,
+ unsigned long *ignored)
+{
+ unsigned long node_start_pfn, node_end_pfn;
+ unsigned long zone_start_pfn, zone_end_pfn;
+
+ /* Get the start and end of the node and zone */
+ get_pfn_range_for_nid(nid, &node_start_pfn, &node_end_pfn);
+ zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type];
+ zone_end_pfn = arch_zone_highest_possible_pfn[zone_type];
+
+ /* Check that this node has pages within the zone's required range */
+ if (zone_end_pfn < node_start_pfn || zone_start_pfn > node_end_pfn)
+ return 0;
+
+ /* Move the zone boundaries inside the node if necessary */
+ zone_end_pfn = min(zone_end_pfn, node_end_pfn);
+ zone_start_pfn = max(zone_start_pfn, node_start_pfn);
+
+ /* Return the spanned pages */
+ return zone_end_pfn - zone_start_pfn;
+}
+
+/*
+ * Return the number of holes in a range on a node. If nid is MAX_NUMNODES,
+ * then all holes in the requested range will be accounted for.
+ */
+unsigned long __init __absent_pages_in_range(int nid,
+ unsigned long range_start_pfn,
+ unsigned long range_end_pfn)
+{
+ int i = 0;
+ unsigned long prev_end_pfn = 0, hole_pages = 0;
+ unsigned long start_pfn;
+
+ /* Find the end_pfn of the first active range of pfns in the node */
+ i = first_active_region_index_in_nid(nid);
+ if (i == -1)
+ return 0;
+
+ /* Account for ranges before physical memory on this node */
+ if (early_node_map[i].start_pfn > range_start_pfn)
+ hole_pages = early_node_map[i].start_pfn - range_start_pfn;
+
+ prev_end_pfn = early_node_map[i].start_pfn;
+
+ /* Find all holes for the zone within the node */
+ for (; i != -1; i = next_active_region_index_in_nid(i, nid)) {
+
+ /* No need to continue if prev_end_pfn is outside the zone */
+ if (prev_end_pfn >= range_end_pfn)
+ break;
+
+ /* Make sure the end of the zone is not within the hole */
+ start_pfn = min(early_node_map[i].start_pfn, range_end_pfn);
+ prev_end_pfn = max(prev_end_pfn, range_start_pfn);
+
+ /* Update the hole size cound and move on */
+ if (start_pfn > range_start_pfn) {
+ BUG_ON(prev_end_pfn > start_pfn);
+ hole_pages += start_pfn - prev_end_pfn;
+ }
+ prev_end_pfn = early_node_map[i].end_pfn;
+ }
+
+ /* Account for ranges past physical memory on this node */
+ if (range_end_pfn > prev_end_pfn)
+ hole_pages = range_end_pfn -
+ max(range_start_pfn, prev_end_pfn);
+
+ return hole_pages;
+}
+
+/**
+ * absent_pages_in_range - Return number of page frames in holes within a range
+ * @start_pfn: The start PFN to start searching for holes
+ * @end_pfn: The end PFN to stop searching for holes
+ *
+ * It returns the number of pages frames in memory holes within a range.
+ */
+unsigned long __init absent_pages_in_range(unsigned long start_pfn,
+ unsigned long end_pfn)
+{
+ return __absent_pages_in_range(MAX_NUMNODES, start_pfn, end_pfn);
+}
+
+/* Return the number of page frames in holes in a zone on a node */
+unsigned long __init zone_absent_pages_in_node(int nid,
+ unsigned long zone_type,
+ unsigned long *ignored)
+{
+ unsigned long node_start_pfn, node_end_pfn;
+ unsigned long zone_start_pfn, zone_end_pfn;
+
+ get_pfn_range_for_nid(nid, &node_start_pfn, &node_end_pfn);
+ zone_start_pfn = max(arch_zone_lowest_possible_pfn[zone_type],
+ node_start_pfn);
+ zone_end_pfn = min(arch_zone_highest_possible_pfn[zone_type],
+ node_end_pfn);
+
+ return __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn);
+}
+
+#else
+static inline unsigned long zone_spanned_pages_in_node(int nid,
+ unsigned long zone_type,
+ unsigned long *zones_size)
+{
+ return zones_size[zone_type];
+}
+
+static inline unsigned long zone_absent_pages_in_node(int nid,
+ unsigned long zone_type,
+ unsigned long *zholes_size)
+{
+ if (!zholes_size)
+ return 0;
+
+ return zholes_size[zone_type];
+}
+
+#endif
+
+static void __init calculate_node_totalpages(struct pglist_data *pgdat,
+ unsigned long *zones_size, unsigned long *zholes_size)
+{
+ unsigned long realtotalpages, totalpages = 0;
+ enum zone_type i;
+
+ for (i = 0; i < MAX_NR_ZONES; i++)
+ totalpages += zone_spanned_pages_in_node(pgdat->node_id, i,
+ zones_size);
+ pgdat->node_spanned_pages = totalpages;
+
+ realtotalpages = totalpages;
+ for (i = 0; i < MAX_NR_ZONES; i++)
+ realtotalpages -=
+ zone_absent_pages_in_node(pgdat->node_id, i,
+ zholes_size);
+ pgdat->node_present_pages = realtotalpages;
+ printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id,
+ realtotalpages);
+}
+
/*
* Set up the zone data structures:
* - mark all pages reserved
@@ -1998,11 +2359,34 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat,
for (j = 0; j < MAX_NR_ZONES; j++) {
struct zone *zone = pgdat->node_zones + j;
- unsigned long size, realsize;
+ unsigned long size, realsize, memmap_pages;
- realsize = size = zones_size[j];
- if (zholes_size)
- realsize -= zholes_size[j];
+ size = zone_spanned_pages_in_node(nid, j, zones_size);
+ realsize = size - zone_absent_pages_in_node(nid, j,
+ zholes_size);
+
+ /*
+ * Adjust realsize so that it accounts for how much memory
+ * is used by this zone for memmap. This affects the watermark
+ * and per-cpu initialisations
+ */
+ memmap_pages = (size * sizeof(struct page)) >> PAGE_SHIFT;
+ if (realsize >= memmap_pages) {
+ realsize -= memmap_pages;
+ printk(KERN_DEBUG
+ " %s zone: %lu pages used for memmap\n",
+ zone_names[j], memmap_pages);
+ } else
+ printk(KERN_WARNING
+ " %s zone: %lu pages exceeds realsize %lu\n",
+ zone_names[j], memmap_pages, realsize);
+
+ /* Account for reserved DMA pages */
+ if (j == ZONE_DMA && realsize > dma_reserve) {
+ realsize -= dma_reserve;
+ printk(KERN_DEBUG " DMA zone: %lu pages reserved\n",
+ dma_reserve);
+ }
if (!is_highmem_idx(j))
nr_kernel_pages += realsize;
@@ -2011,6 +2395,7 @@ static void __meminit free_area_init_core(struct pglist_data *pgdat,
zone->spanned_pages = size;
zone->present_pages = realsize;
#ifdef CONFIG_NUMA
+ zone->node = nid;
zone->min_unmapped_pages = (realsize*sysctl_min_unmapped_ratio)
/ 100;
zone->min_slab_pages = (realsize * sysctl_min_slab_ratio) / 100;
@@ -2073,8 +2458,13 @@ static void __init alloc_node_mem_map(struct pglist_data *pgdat)
/*
* With no DISCONTIG, the global mem_map is just set as node 0's
*/
- if (pgdat == NODE_DATA(0))
+ if (pgdat == NODE_DATA(0)) {
mem_map = NODE_DATA(0)->node_mem_map;
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+ if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
+ mem_map -= pgdat->node_start_pfn;
+#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
+ }
#endif
#endif /* CONFIG_FLAT_NODE_MEM_MAP */
}
@@ -2085,13 +2475,254 @@ void __meminit free_area_init_node(int nid, struct pglist_data *pgdat,
{
pgdat->node_id = nid;
pgdat->node_start_pfn = node_start_pfn;
- calculate_zone_totalpages(pgdat, zones_size, zholes_size);
+ calculate_node_totalpages(pgdat, zones_size, zholes_size);
alloc_node_mem_map(pgdat);
free_area_init_core(pgdat, zones_size, zholes_size);
}
+#ifdef CONFIG_ARCH_POPULATES_NODE_MAP
+/**
+ * add_active_range - Register a range of PFNs backed by physical memory
+ * @nid: The node ID the range resides on
+ * @start_pfn: The start PFN of the available physical memory
+ * @end_pfn: The end PFN of the available physical memory
+ *
+ * These ranges are stored in an early_node_map[] and later used by
+ * free_area_init_nodes() to calculate zone sizes and holes. If the
+ * range spans a memory hole, it is up to the architecture to ensure
+ * the memory is not freed by the bootmem allocator. If possible
+ * the range being registered will be merged with existing ranges.
+ */
+void __init add_active_range(unsigned int nid, unsigned long start_pfn,
+ unsigned long end_pfn)
+{
+ int i;
+
+ printk(KERN_DEBUG "Entering add_active_range(%d, %lu, %lu) "
+ "%d entries of %d used\n",
+ nid, start_pfn, end_pfn,
+ nr_nodemap_entries, MAX_ACTIVE_REGIONS);
+
+ /* Merge with existing active regions if possible */
+ for (i = 0; i < nr_nodemap_entries; i++) {
+ if (early_node_map[i].nid != nid)
+ continue;
+
+ /* Skip if an existing region covers this new one */
+ if (start_pfn >= early_node_map[i].start_pfn &&
+ end_pfn <= early_node_map[i].end_pfn)
+ return;
+
+ /* Merge forward if suitable */
+ if (start_pfn <= early_node_map[i].end_pfn &&
+ end_pfn > early_node_map[i].end_pfn) {
+ early_node_map[i].end_pfn = end_pfn;
+ return;
+ }
+
+ /* Merge backward if suitable */
+ if (start_pfn < early_node_map[i].end_pfn &&
+ end_pfn >= early_node_map[i].start_pfn) {
+ early_node_map[i].start_pfn = start_pfn;
+ return;
+ }
+ }
+
+ /* Check that early_node_map is large enough */
+ if (i >= MAX_ACTIVE_REGIONS) {
+ printk(KERN_CRIT "More than %d memory regions, truncating\n",
+ MAX_ACTIVE_REGIONS);
+ return;
+ }
+
+ early_node_map[i].nid = nid;
+ early_node_map[i].start_pfn = start_pfn;
+ early_node_map[i].end_pfn = end_pfn;
+ nr_nodemap_entries = i + 1;
+}
+
+/**
+ * shrink_active_range - Shrink an existing registered range of PFNs
+ * @nid: The node id the range is on that should be shrunk
+ * @old_end_pfn: The old end PFN of the range
+ * @new_end_pfn: The new PFN of the range
+ *
+ * i386 with NUMA use alloc_remap() to store a node_mem_map on a local node.
+ * The map is kept at the end physical page range that has already been
+ * registered with add_active_range(). This function allows an arch to shrink
+ * an existing registered range.
+ */
+void __init shrink_active_range(unsigned int nid, unsigned long old_end_pfn,
+ unsigned long new_end_pfn)
+{
+ int i;
+
+ /* Find the old active region end and shrink */
+ for_each_active_range_index_in_nid(i, nid)
+ if (early_node_map[i].end_pfn == old_end_pfn) {
+ early_node_map[i].end_pfn = new_end_pfn;
+ break;
+ }
+}
+
+/**
+ * remove_all_active_ranges - Remove all currently registered regions
+ *
+ * During discovery, it may be found that a table like SRAT is invalid
+ * and an alternative discovery method must be used. This function removes
+ * all currently registered regions.
+ */
+void __init remove_all_active_ranges(void)
+{
+ memset(early_node_map, 0, sizeof(early_node_map));
+ nr_nodemap_entries = 0;
+#ifdef CONFIG_MEMORY_HOTPLUG_RESERVE
+ memset(node_boundary_start_pfn, 0, sizeof(node_boundary_start_pfn));
+ memset(node_boundary_end_pfn, 0, sizeof(node_boundary_end_pfn));
+#endif /* CONFIG_MEMORY_HOTPLUG_RESERVE */
+}
+
+/* Compare two active node_active_regions */
+static int __init cmp_node_active_region(const void *a, const void *b)
+{
+ struct node_active_region *arange = (struct node_active_region *)a;
+ struct node_active_region *brange = (struct node_active_region *)b;
+
+ /* Done this way to avoid overflows */
+ if (arange->start_pfn > brange->start_pfn)
+ return 1;
+ if (arange->start_pfn < brange->start_pfn)
+ return -1;
+
+ return 0;
+}
+
+/* sort the node_map by start_pfn */
+static void __init sort_node_map(void)
+{
+ sort(early_node_map, (size_t)nr_nodemap_entries,
+ sizeof(struct node_active_region),
+ cmp_node_active_region, NULL);
+}
+
+/* Find the lowest pfn for a node. This depends on a sorted early_node_map */
+unsigned long __init find_min_pfn_for_node(unsigned long nid)
+{
+ int i;
+
+ /* Assuming a sorted map, the first range found has the starting pfn */
+ for_each_active_range_index_in_nid(i, nid)
+ return early_node_map[i].start_pfn;
+
+ printk(KERN_WARNING "Could not find start_pfn for node %lu\n", nid);
+ return 0;
+}
+
+/**
+ * find_min_pfn_with_active_regions - Find the minimum PFN registered
+ *
+ * It returns the minimum PFN based on information provided via
+ * add_active_range().
+ */
+unsigned long __init find_min_pfn_with_active_regions(void)
+{
+ return find_min_pfn_for_node(MAX_NUMNODES);
+}
+
+/**
+ * find_max_pfn_with_active_regions - Find the maximum PFN registered
+ *
+ * It returns the maximum PFN based on information provided via
+ * add_active_range().
+ */
+unsigned long __init find_max_pfn_with_active_regions(void)
+{
+ int i;
+ unsigned long max_pfn = 0;
+
+ for (i = 0; i < nr_nodemap_entries; i++)
+ max_pfn = max(max_pfn, early_node_map[i].end_pfn);
+
+ return max_pfn;
+}
+
+/**
+ * free_area_init_nodes - Initialise all pg_data_t and zone data
+ * @max_zone_pfn: an array of max PFNs for each zone
+ *
+ * This will call free_area_init_node() for each active node in the system.
+ * Using the page ranges provided by add_active_range(), the size of each
+ * zone in each node and their holes is calculated. If the maximum PFN
+ * between two adjacent zones match, it is assumed that the zone is empty.
+ * For example, if arch_max_dma_pfn == arch_max_dma32_pfn, it is assumed
+ * that arch_max_dma32_pfn has no pages. It is also assumed that a zone
+ * starts where the previous one ended. For example, ZONE_DMA32 starts
+ * at arch_max_dma_pfn.
+ */
+void __init free_area_init_nodes(unsigned long *max_zone_pfn)
+{
+ unsigned long nid;
+ enum zone_type i;
+
+ /* Record where the zone boundaries are */
+ memset(arch_zone_lowest_possible_pfn, 0,
+ sizeof(arch_zone_lowest_possible_pfn));
+ memset(arch_zone_highest_possible_pfn, 0,
+ sizeof(arch_zone_highest_possible_pfn));
+ arch_zone_lowest_possible_pfn[0] = find_min_pfn_with_active_regions();
+ arch_zone_highest_possible_pfn[0] = max_zone_pfn[0];
+ for (i = 1; i < MAX_NR_ZONES; i++) {
+ arch_zone_lowest_possible_pfn[i] =
+ arch_zone_highest_possible_pfn[i-1];
+ arch_zone_highest_possible_pfn[i] =
+ max(max_zone_pfn[i], arch_zone_lowest_possible_pfn[i]);
+ }
+
+ /* Regions in the early_node_map can be in any order */
+ sort_node_map();
+
+ /* Print out the zone ranges */
+ printk("Zone PFN ranges:\n");
+ for (i = 0; i < MAX_NR_ZONES; i++)
+ printk(" %-8s %8lu -> %8lu\n",
+ zone_names[i],
+ arch_zone_lowest_possible_pfn[i],
+ arch_zone_highest_possible_pfn[i]);
+
+ /* Print out the early_node_map[] */
+ printk("early_node_map[%d] active PFN ranges\n", nr_nodemap_entries);
+ for (i = 0; i < nr_nodemap_entries; i++)
+ printk(" %3d: %8lu -> %8lu\n", early_node_map[i].nid,
+ early_node_map[i].start_pfn,
+ early_node_map[i].end_pfn);
+
+ /* Initialise every node */
+ for_each_online_node(nid) {
+ pg_data_t *pgdat = NODE_DATA(nid);
+ free_area_init_node(nid, pgdat, NULL,
+ find_min_pfn_for_node(nid), NULL);
+ }
+}
+#endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
+
+/**
+ * set_dma_reserve - set the specified number of pages reserved in the first zone
+ * @new_dma_reserve: The number of pages to mark reserved
+ *
+ * The per-cpu batchsize and zone watermarks are determined by present_pages.
+ * In the DMA zone, a significant percentage may be consumed by kernel image
+ * and other unfreeable allocations which can skew the watermarks badly. This
+ * function may optionally be used to account for unfreeable pages in the
+ * first zone (e.g., ZONE_DMA). The effect will be lower watermarks and
+ * smaller per-cpu batchsize.
+ */
+void __init set_dma_reserve(unsigned long new_dma_reserve)
+{
+ dma_reserve = new_dma_reserve;
+}
+
#ifndef CONFIG_NEED_MULTIPLE_NODES
static bootmem_data_t contig_bootmem_data;
struct pglist_data contig_page_data = { .bdata = &contig_bootmem_data };
@@ -2198,10 +2829,11 @@ static void setup_per_zone_lowmem_reserve(void)
calculate_totalreserve_pages();
}
-/*
- * setup_per_zone_pages_min - called when min_free_kbytes changes. Ensures
- * that the pages_{min,low,high} values for each zone are set correctly
- * with respect to min_free_kbytes.
+/**
+ * setup_per_zone_pages_min - called when min_free_kbytes changes.
+ *
+ * Ensures that the pages_{min,low,high} values for each zone are set correctly
+ * with respect to min_free_kbytes.
*/
void setup_per_zone_pages_min(void)
{
@@ -2490,3 +3122,19 @@ unsigned long page_to_pfn(struct page *page)
EXPORT_SYMBOL(pfn_to_page);
EXPORT_SYMBOL(page_to_pfn);
#endif /* CONFIG_OUT_OF_LINE_PFN_TO_PAGE */
+
+#if MAX_NUMNODES > 1
+/*
+ * Find the highest possible node id.
+ */
+int highest_possible_node_id(void)
+{
+ unsigned int node;
+ unsigned int highest = 0;
+
+ for_each_node_mask(node, node_possible_map)
+ highest = node;
+ return highest;
+}
+EXPORT_SYMBOL(highest_possible_node_id);
+#endif
diff --git a/mm/readahead.c b/mm/readahead.c
index aa7ec424656a..1ba736ac0367 100644
--- a/mm/readahead.c
+++ b/mm/readahead.c
@@ -38,6 +38,7 @@ file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping)
ra->ra_pages = mapping->backing_dev_info->ra_pages;
ra->prev_page = -1;
}
+EXPORT_SYMBOL_GPL(file_ra_state_init);
/*
* Return max readahead size for this inode in number-of-pages.
diff --git a/mm/rmap.c b/mm/rmap.c
index e2155d791d99..d8a842a586db 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -21,27 +21,21 @@
* Lock ordering in mm:
*
* inode->i_mutex (while writing or truncating, not reading or faulting)
- * inode->i_alloc_sem
- *
- * When a page fault occurs in writing from user to file, down_read
- * of mmap_sem nests within i_mutex; in sys_msync, i_mutex nests within
- * down_read of mmap_sem; i_mutex and down_write of mmap_sem are never
- * taken together; in truncation, i_mutex is taken outermost.
- *
- * mm->mmap_sem
- * page->flags PG_locked (lock_page)
- * mapping->i_mmap_lock
- * anon_vma->lock
- * mm->page_table_lock or pte_lock
- * zone->lru_lock (in mark_page_accessed, isolate_lru_page)
- * swap_lock (in swap_duplicate, swap_info_get)
- * mmlist_lock (in mmput, drain_mmlist and others)
- * mapping->private_lock (in __set_page_dirty_buffers)
- * inode_lock (in set_page_dirty's __mark_inode_dirty)
- * sb_lock (within inode_lock in fs/fs-writeback.c)
- * mapping->tree_lock (widely used, in set_page_dirty,
- * in arch-dependent flush_dcache_mmap_lock,
- * within inode_lock in __sync_single_inode)
+ * inode->i_alloc_sem (vmtruncate_range)
+ * mm->mmap_sem
+ * page->flags PG_locked (lock_page)
+ * mapping->i_mmap_lock
+ * anon_vma->lock
+ * mm->page_table_lock or pte_lock
+ * zone->lru_lock (in mark_page_accessed, isolate_lru_page)
+ * swap_lock (in swap_duplicate, swap_info_get)
+ * mmlist_lock (in mmput, drain_mmlist and others)
+ * mapping->private_lock (in __set_page_dirty_buffers)
+ * inode_lock (in set_page_dirty's __mark_inode_dirty)
+ * sb_lock (within inode_lock in fs/fs-writeback.c)
+ * mapping->tree_lock (widely used, in set_page_dirty,
+ * in arch-dependent flush_dcache_mmap_lock,
+ * within inode_lock in __sync_single_inode)
*/
#include <linux/mm.h>
@@ -576,15 +570,14 @@ void page_add_file_rmap(struct page *page)
void page_remove_rmap(struct page *page)
{
if (atomic_add_negative(-1, &page->_mapcount)) {
-#ifdef CONFIG_DEBUG_VM
if (unlikely(page_mapcount(page) < 0)) {
printk (KERN_EMERG "Eeek! page_mapcount(page) went negative! (%d)\n", page_mapcount(page));
printk (KERN_EMERG " page->flags = %lx\n", page->flags);
printk (KERN_EMERG " page->count = %x\n", page_count(page));
printk (KERN_EMERG " page->mapping = %p\n", page->mapping);
+ BUG();
}
-#endif
- BUG_ON(page_mapcount(page) < 0);
+
/*
* It would be tidy to reset the PageAnon mapping here,
* but that might overwrite a racing page_add_anon_rmap
diff --git a/mm/shmem.c b/mm/shmem.c
index 8631be45b40d..4959535fc14c 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -26,6 +26,8 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/xattr.h>
+#include <linux/generic_acl.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/file.h>
@@ -46,6 +48,7 @@
#include <linux/ctype.h>
#include <linux/migrate.h>
#include <linux/highmem.h>
+#include <linux/backing-dev.h>
#include <asm/uaccess.h>
#include <asm/div64.h>
@@ -177,6 +180,7 @@ static const struct address_space_operations shmem_aops;
static struct file_operations shmem_file_operations;
static struct inode_operations shmem_inode_operations;
static struct inode_operations shmem_dir_inode_operations;
+static struct inode_operations shmem_special_inode_operations;
static struct vm_operations_struct shmem_vm_ops;
static struct backing_dev_info shmem_backing_dev_info __read_mostly = {
@@ -637,7 +641,7 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
struct page *page = NULL;
int error;
- if (attr->ia_valid & ATTR_SIZE) {
+ if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) {
if (attr->ia_size < inode->i_size) {
/*
* If truncating down to a partial page, then
@@ -670,6 +674,10 @@ static int shmem_notify_change(struct dentry *dentry, struct iattr *attr)
error = inode_change_ok(inode, attr);
if (!error)
error = inode_setattr(inode, attr);
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ if (!error && (attr->ia_valid & ATTR_MODE))
+ error = generic_acl_chmod(inode, &shmem_acl_ops);
+#endif
if (page)
page_cache_release(page);
return error;
@@ -1124,7 +1132,7 @@ repeat:
page_cache_release(swappage);
if (error == -ENOMEM) {
/* let kswapd refresh zone for GFP_ATOMICs */
- blk_congestion_wait(WRITE, HZ/50);
+ congestion_wait(WRITE, HZ/50);
}
goto repeat;
}
@@ -1351,11 +1359,11 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
inode->i_mode = mode;
inode->i_uid = current->fsuid;
inode->i_gid = current->fsgid;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_mapping->a_ops = &shmem_aops;
inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ inode->i_generation = get_seconds();
info = SHMEM_I(inode);
memset(info, 0, (char *)inode - (char *)info);
spin_lock_init(&info->lock);
@@ -1363,6 +1371,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
switch (mode & S_IFMT) {
default:
+ inode->i_op = &shmem_special_inode_operations;
init_special_inode(inode, mode, dev);
break;
case S_IFREG:
@@ -1372,7 +1381,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
&sbinfo->policy_nodes);
break;
case S_IFDIR:
- inode->i_nlink++;
+ inc_nlink(inode);
/* Some things misbehave if size == 0 on a directory */
inode->i_size = 2 * BOGO_DIRENT_SIZE;
inode->i_op = &shmem_dir_inode_operations;
@@ -1683,7 +1692,11 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
iput(inode);
return error;
}
- error = 0;
+ }
+ error = shmem_acl_init(inode, dir);
+ if (error) {
+ iput(inode);
+ return error;
}
if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
@@ -1704,7 +1717,7 @@ static int shmem_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0)))
return error;
- dir->i_nlink++;
+ inc_nlink(dir);
return 0;
}
@@ -1739,7 +1752,7 @@ static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentr
dir->i_size += BOGO_DIRENT_SIZE;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- inode->i_nlink++;
+ inc_nlink(inode);
atomic_inc(&inode->i_count); /* New dentry reference */
dget(dentry); /* Extra pinning count for the created dentry */
d_instantiate(dentry, inode);
@@ -1761,7 +1774,7 @@ static int shmem_unlink(struct inode *dir, struct dentry *dentry)
dir->i_size -= BOGO_DIRENT_SIZE;
inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- inode->i_nlink--;
+ drop_nlink(inode);
dput(dentry); /* Undo the count from "create" - this does all the work */
return 0;
}
@@ -1771,8 +1784,8 @@ static int shmem_rmdir(struct inode *dir, struct dentry *dentry)
if (!simple_empty(dentry))
return -ENOTEMPTY;
- dentry->d_inode->i_nlink--;
- dir->i_nlink--;
+ drop_nlink(dentry->d_inode);
+ drop_nlink(dir);
return shmem_unlink(dir, dentry);
}
@@ -1793,10 +1806,10 @@ static int shmem_rename(struct inode *old_dir, struct dentry *old_dentry, struct
if (new_dentry->d_inode) {
(void) shmem_unlink(new_dir, new_dentry);
if (they_are_dirs)
- old_dir->i_nlink--;
+ drop_nlink(old_dir);
} else if (they_are_dirs) {
- old_dir->i_nlink--;
- new_dir->i_nlink++;
+ drop_nlink(old_dir);
+ inc_nlink(new_dir);
}
old_dir->i_size -= BOGO_DIRENT_SIZE;
@@ -1898,6 +1911,132 @@ static struct inode_operations shmem_symlink_inode_operations = {
.put_link = shmem_put_link,
};
+#ifdef CONFIG_TMPFS_POSIX_ACL
+/**
+ * Superblocks without xattr inode operations will get security.* xattr
+ * support from the VFS "for free". As soon as we have any other xattrs
+ * like ACLs, we also need to implement the security.* handlers at
+ * filesystem level, though.
+ */
+
+static size_t shmem_xattr_security_list(struct inode *inode, char *list,
+ size_t list_len, const char *name,
+ size_t name_len)
+{
+ return security_inode_listsecurity(inode, list, list_len);
+}
+
+static int shmem_xattr_security_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ return security_inode_getsecurity(inode, name, buffer, size,
+ -EOPNOTSUPP);
+}
+
+static int shmem_xattr_security_set(struct inode *inode, const char *name,
+ const void *value, size_t size, int flags)
+{
+ if (strcmp(name, "") == 0)
+ return -EINVAL;
+ return security_inode_setsecurity(inode, name, value, size, flags);
+}
+
+struct xattr_handler shmem_xattr_security_handler = {
+ .prefix = XATTR_SECURITY_PREFIX,
+ .list = shmem_xattr_security_list,
+ .get = shmem_xattr_security_get,
+ .set = shmem_xattr_security_set,
+};
+
+static struct xattr_handler *shmem_xattr_handlers[] = {
+ &shmem_xattr_acl_access_handler,
+ &shmem_xattr_acl_default_handler,
+ &shmem_xattr_security_handler,
+ NULL
+};
+#endif
+
+static struct dentry *shmem_get_parent(struct dentry *child)
+{
+ return ERR_PTR(-ESTALE);
+}
+
+static int shmem_match(struct inode *ino, void *vfh)
+{
+ __u32 *fh = vfh;
+ __u64 inum = fh[2];
+ inum = (inum << 32) | fh[1];
+ return ino->i_ino == inum && fh[0] == ino->i_generation;
+}
+
+static struct dentry *shmem_get_dentry(struct super_block *sb, void *vfh)
+{
+ struct dentry *de = NULL;
+ struct inode *inode;
+ __u32 *fh = vfh;
+ __u64 inum = fh[2];
+ inum = (inum << 32) | fh[1];
+
+ inode = ilookup5(sb, (unsigned long)(inum+fh[0]), shmem_match, vfh);
+ if (inode) {
+ de = d_find_alias(inode);
+ iput(inode);
+ }
+
+ return de? de: ERR_PTR(-ESTALE);
+}
+
+static struct dentry *shmem_decode_fh(struct super_block *sb, __u32 *fh,
+ int len, int type,
+ int (*acceptable)(void *context, struct dentry *de),
+ void *context)
+{
+ if (len < 3)
+ return ERR_PTR(-ESTALE);
+
+ return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable,
+ context);
+}
+
+static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
+ int connectable)
+{
+ struct inode *inode = dentry->d_inode;
+
+ if (*len < 3)
+ return 255;
+
+ if (hlist_unhashed(&inode->i_hash)) {
+ /* Unfortunately insert_inode_hash is not idempotent,
+ * so as we hash inodes here rather than at creation
+ * time, we need a lock to ensure we only try
+ * to do it once
+ */
+ static DEFINE_SPINLOCK(lock);
+ spin_lock(&lock);
+ if (hlist_unhashed(&inode->i_hash))
+ __insert_inode_hash(inode,
+ inode->i_ino + inode->i_generation);
+ spin_unlock(&lock);
+ }
+
+ fh[0] = inode->i_generation;
+ fh[1] = inode->i_ino;
+ fh[2] = ((__u64)inode->i_ino) >> 32;
+
+ *len = 3;
+ return 1;
+}
+
+static struct export_operations shmem_export_ops = {
+ .get_parent = shmem_get_parent,
+ .get_dentry = shmem_get_dentry,
+ .encode_fh = shmem_encode_fh,
+ .decode_fh = shmem_decode_fh,
+};
+
static int shmem_parse_options(char *options, int *mode, uid_t *uid,
gid_t *gid, unsigned long *blocks, unsigned long *inodes,
int *policy, nodemask_t *policy_nodes)
@@ -2070,6 +2209,7 @@ static int shmem_fill_super(struct super_block *sb,
&inodes, &policy, &policy_nodes))
return -EINVAL;
}
+ sb->s_export_op = &shmem_export_ops;
#else
sb->s_flags |= MS_NOUSER;
#endif
@@ -2095,6 +2235,10 @@ static int shmem_fill_super(struct super_block *sb,
sb->s_magic = TMPFS_MAGIC;
sb->s_op = &shmem_ops;
sb->s_time_gran = 1;
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ sb->s_xattr = shmem_xattr_handlers;
+ sb->s_flags |= MS_POSIXACL;
+#endif
inode = shmem_get_inode(sb, S_IFDIR | mode, 0);
if (!inode)
@@ -2131,6 +2275,7 @@ static void shmem_destroy_inode(struct inode *inode)
/* only struct inode is valid if it's an inline symlink */
mpol_free_shared_policy(&SHMEM_I(inode)->policy);
}
+ shmem_acl_destroy_inode(inode);
kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));
}
@@ -2142,6 +2287,10 @@ static void init_once(void *foo, struct kmem_cache *cachep,
if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
inode_init_once(&p->vfs_inode);
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ p->i_acl = NULL;
+ p->i_default_acl = NULL;
+#endif
}
}
@@ -2157,8 +2306,7 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
- if (kmem_cache_destroy(shmem_inode_cachep))
- printk(KERN_INFO "shmem_inode_cache: not all structures were freed\n");
+ kmem_cache_destroy(shmem_inode_cachep);
}
static const struct address_space_operations shmem_aops = {
@@ -2186,6 +2334,14 @@ static struct inode_operations shmem_inode_operations = {
.truncate = shmem_truncate,
.setattr = shmem_notify_change,
.truncate_range = shmem_truncate_range,
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = generic_listxattr,
+ .removexattr = generic_removexattr,
+ .permission = shmem_permission,
+#endif
+
};
static struct inode_operations shmem_dir_inode_operations = {
@@ -2200,6 +2356,25 @@ static struct inode_operations shmem_dir_inode_operations = {
.mknod = shmem_mknod,
.rename = shmem_rename,
#endif
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ .setattr = shmem_notify_change,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = generic_listxattr,
+ .removexattr = generic_removexattr,
+ .permission = shmem_permission,
+#endif
+};
+
+static struct inode_operations shmem_special_inode_operations = {
+#ifdef CONFIG_TMPFS_POSIX_ACL
+ .setattr = shmem_notify_change,
+ .setxattr = generic_setxattr,
+ .getxattr = generic_getxattr,
+ .listxattr = generic_listxattr,
+ .removexattr = generic_removexattr,
+ .permission = shmem_permission,
+#endif
};
static struct super_operations shmem_ops = {
diff --git a/mm/shmem_acl.c b/mm/shmem_acl.c
new file mode 100644
index 000000000000..f5664c5b9eb1
--- /dev/null
+++ b/mm/shmem_acl.c
@@ -0,0 +1,197 @@
+/*
+ * mm/shmem_acl.c
+ *
+ * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
+ *
+ * This file is released under the GPL.
+ */
+
+#include <linux/fs.h>
+#include <linux/shmem_fs.h>
+#include <linux/xattr.h>
+#include <linux/generic_acl.h>
+
+/**
+ * shmem_get_acl - generic_acl_operations->getacl() operation
+ */
+static struct posix_acl *
+shmem_get_acl(struct inode *inode, int type)
+{
+ struct posix_acl *acl = NULL;
+
+ spin_lock(&inode->i_lock);
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ acl = posix_acl_dup(SHMEM_I(inode)->i_acl);
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ acl = posix_acl_dup(SHMEM_I(inode)->i_default_acl);
+ break;
+ }
+ spin_unlock(&inode->i_lock);
+
+ return acl;
+}
+
+/**
+ * shmem_set_acl - generic_acl_operations->setacl() operation
+ */
+static void
+shmem_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+{
+ struct posix_acl *free = NULL;
+
+ spin_lock(&inode->i_lock);
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ free = SHMEM_I(inode)->i_acl;
+ SHMEM_I(inode)->i_acl = posix_acl_dup(acl);
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ free = SHMEM_I(inode)->i_default_acl;
+ SHMEM_I(inode)->i_default_acl = posix_acl_dup(acl);
+ break;
+ }
+ spin_unlock(&inode->i_lock);
+ posix_acl_release(free);
+}
+
+struct generic_acl_operations shmem_acl_ops = {
+ .getacl = shmem_get_acl,
+ .setacl = shmem_set_acl,
+};
+
+/**
+ * shmem_list_acl_access, shmem_get_acl_access, shmem_set_acl_access,
+ * shmem_xattr_acl_access_handler - plumbing code to implement the
+ * system.posix_acl_access xattr using the generic acl functions.
+ */
+
+static size_t
+shmem_list_acl_access(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_ACCESS,
+ list, list_size);
+}
+
+static int
+shmem_get_acl_access(struct inode *inode, const char *name, void *buffer,
+ size_t size)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, buffer,
+ size);
+}
+
+static int
+shmem_set_acl_access(struct inode *inode, const char *name, const void *value,
+ size_t size, int flags)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_ACCESS, value,
+ size);
+}
+
+struct xattr_handler shmem_xattr_acl_access_handler = {
+ .prefix = POSIX_ACL_XATTR_ACCESS,
+ .list = shmem_list_acl_access,
+ .get = shmem_get_acl_access,
+ .set = shmem_set_acl_access,
+};
+
+/**
+ * shmem_list_acl_default, shmem_get_acl_default, shmem_set_acl_default,
+ * shmem_xattr_acl_default_handler - plumbing code to implement the
+ * system.posix_acl_default xattr using the generic acl functions.
+ */
+
+static size_t
+shmem_list_acl_default(struct inode *inode, char *list, size_t list_size,
+ const char *name, size_t name_len)
+{
+ return generic_acl_list(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT,
+ list, list_size);
+}
+
+static int
+shmem_get_acl_default(struct inode *inode, const char *name, void *buffer,
+ size_t size)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return generic_acl_get(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, buffer,
+ size);
+}
+
+static int
+shmem_set_acl_default(struct inode *inode, const char *name, const void *value,
+ size_t size, int flags)
+{
+ if (strcmp(name, "") != 0)
+ return -EINVAL;
+ return generic_acl_set(inode, &shmem_acl_ops, ACL_TYPE_DEFAULT, value,
+ size);
+}
+
+struct xattr_handler shmem_xattr_acl_default_handler = {
+ .prefix = POSIX_ACL_XATTR_DEFAULT,
+ .list = shmem_list_acl_default,
+ .get = shmem_get_acl_default,
+ .set = shmem_set_acl_default,
+};
+
+/**
+ * shmem_acl_init - Inizialize the acl(s) of a new inode
+ */
+int
+shmem_acl_init(struct inode *inode, struct inode *dir)
+{
+ return generic_acl_init(inode, dir, &shmem_acl_ops);
+}
+
+/**
+ * shmem_acl_destroy_inode - destroy acls hanging off the in-memory inode
+ *
+ * This is done before destroying the actual inode.
+ */
+
+void
+shmem_acl_destroy_inode(struct inode *inode)
+{
+ if (SHMEM_I(inode)->i_acl)
+ posix_acl_release(SHMEM_I(inode)->i_acl);
+ SHMEM_I(inode)->i_acl = NULL;
+ if (SHMEM_I(inode)->i_default_acl)
+ posix_acl_release(SHMEM_I(inode)->i_default_acl);
+ SHMEM_I(inode)->i_default_acl = NULL;
+}
+
+/**
+ * shmem_check_acl - check_acl() callback for generic_permission()
+ */
+static int
+shmem_check_acl(struct inode *inode, int mask)
+{
+ struct posix_acl *acl = shmem_get_acl(inode, ACL_TYPE_ACCESS);
+
+ if (acl) {
+ int error = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ return error;
+ }
+ return -EAGAIN;
+}
+
+/**
+ * shmem_permission - permission() inode operation
+ */
+int
+shmem_permission(struct inode *inode, int mask, struct nameidata *nd)
+{
+ return generic_permission(inode, mask, shmem_check_acl);
+}
diff --git a/mm/slab.c b/mm/slab.c
index 7a48eb1a60c8..84c631f30741 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -86,7 +86,6 @@
* All object allocations for a node occur from node specific slab lists.
*/
-#include <linux/config.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/poison.h>
@@ -972,7 +971,39 @@ static int transfer_objects(struct array_cache *to,
return nr;
}
-#ifdef CONFIG_NUMA
+#ifndef CONFIG_NUMA
+
+#define drain_alien_cache(cachep, alien) do { } while (0)
+#define reap_alien(cachep, l3) do { } while (0)
+
+static inline struct array_cache **alloc_alien_cache(int node, int limit)
+{
+ return (struct array_cache **)BAD_ALIEN_MAGIC;
+}
+
+static inline void free_alien_cache(struct array_cache **ac_ptr)
+{
+}
+
+static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
+{
+ return 0;
+}
+
+static inline void *alternate_node_alloc(struct kmem_cache *cachep,
+ gfp_t flags)
+{
+ return NULL;
+}
+
+static inline void *__cache_alloc_node(struct kmem_cache *cachep,
+ gfp_t flags, int nodeid)
+{
+ return NULL;
+}
+
+#else /* CONFIG_NUMA */
+
static void *__cache_alloc_node(struct kmem_cache *, gfp_t, int);
static void *alternate_node_alloc(struct kmem_cache *, gfp_t);
@@ -1075,15 +1106,18 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
int nodeid = slabp->nodeid;
struct kmem_list3 *l3;
struct array_cache *alien = NULL;
+ int node;
+
+ node = numa_node_id();
/*
* Make sure we are not freeing a object from another node to the array
* cache on this cpu.
*/
- if (likely(slabp->nodeid == numa_node_id()))
+ if (likely(slabp->nodeid == node))
return 0;
- l3 = cachep->nodelists[numa_node_id()];
+ l3 = cachep->nodelists[node];
STATS_INC_NODEFREES(cachep);
if (l3->alien && l3->alien[nodeid]) {
alien = l3->alien[nodeid];
@@ -1101,26 +1135,6 @@ static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
}
return 1;
}
-
-#else
-
-#define drain_alien_cache(cachep, alien) do { } while (0)
-#define reap_alien(cachep, l3) do { } while (0)
-
-static inline struct array_cache **alloc_alien_cache(int node, int limit)
-{
- return (struct array_cache **)BAD_ALIEN_MAGIC;
-}
-
-static inline void free_alien_cache(struct array_cache **ac_ptr)
-{
-}
-
-static inline int cache_free_alien(struct kmem_cache *cachep, void *objp)
-{
- return 0;
-}
-
#endif
static int __cpuinit cpuup_callback(struct notifier_block *nfb,
@@ -1314,7 +1328,6 @@ static void init_list(struct kmem_cache *cachep, struct kmem_list3 *list,
{
struct kmem_list3 *ptr;
- BUG_ON(cachep->nodelists[nodeid] != list);
ptr = kmalloc_node(sizeof(struct kmem_list3), GFP_KERNEL, nodeid);
BUG_ON(!ptr);
@@ -1341,6 +1354,7 @@ void __init kmem_cache_init(void)
struct cache_names *names;
int i;
int order;
+ int node;
for (i = 0; i < NUM_INIT_LISTS; i++) {
kmem_list3_init(&initkmem_list3[i]);
@@ -1375,12 +1389,14 @@ void __init kmem_cache_init(void)
* 6) Resize the head arrays of the kmalloc caches to their final sizes.
*/
+ node = numa_node_id();
+
/* 1) create the cache_cache */
INIT_LIST_HEAD(&cache_chain);
list_add(&cache_cache.next, &cache_chain);
cache_cache.colour_off = cache_line_size();
cache_cache.array[smp_processor_id()] = &initarray_cache.cache;
- cache_cache.nodelists[numa_node_id()] = &initkmem_list3[CACHE_CACHE];
+ cache_cache.nodelists[node] = &initkmem_list3[CACHE_CACHE];
cache_cache.buffer_size = ALIGN(cache_cache.buffer_size,
cache_line_size());
@@ -1485,19 +1501,18 @@ void __init kmem_cache_init(void)
}
/* 5) Replace the bootstrap kmem_list3's */
{
- int node;
+ int nid;
+
/* Replace the static kmem_list3 structures for the boot cpu */
- init_list(&cache_cache, &initkmem_list3[CACHE_CACHE],
- numa_node_id());
+ init_list(&cache_cache, &initkmem_list3[CACHE_CACHE], node);
- for_each_online_node(node) {
+ for_each_online_node(nid) {
init_list(malloc_sizes[INDEX_AC].cs_cachep,
- &initkmem_list3[SIZE_AC + node], node);
+ &initkmem_list3[SIZE_AC + nid], nid);
if (INDEX_AC != INDEX_L3) {
init_list(malloc_sizes[INDEX_L3].cs_cachep,
- &initkmem_list3[SIZE_L3 + node],
- node);
+ &initkmem_list3[SIZE_L3 + nid], nid);
}
}
}
@@ -1564,7 +1579,13 @@ static void *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, int nodeid)
*/
flags |= __GFP_COMP;
#endif
- flags |= cachep->gfpflags;
+
+ /*
+ * Under NUMA we want memory on the indicated node. We will handle
+ * the needed fallback ourselves since we want to serve from our
+ * per node object lists first for other nodes.
+ */
+ flags |= cachep->gfpflags | GFP_THISNODE;
page = alloc_pages_node(nodeid, flags, cachep->gfporder);
if (!page)
@@ -1665,10 +1686,32 @@ static void poison_obj(struct kmem_cache *cachep, void *addr, unsigned char val)
static void dump_line(char *data, int offset, int limit)
{
int i;
+ unsigned char error = 0;
+ int bad_count = 0;
+
printk(KERN_ERR "%03x:", offset);
- for (i = 0; i < limit; i++)
+ for (i = 0; i < limit; i++) {
+ if (data[offset + i] != POISON_FREE) {
+ error = data[offset + i];
+ bad_count++;
+ }
printk(" %02x", (unsigned char)data[offset + i]);
+ }
printk("\n");
+
+ if (bad_count == 1) {
+ error ^= POISON_FREE;
+ if (!(error & (error - 1))) {
+ printk(KERN_ERR "Single bit error detected. Probably "
+ "bad RAM.\n");
+#ifdef CONFIG_X86
+ printk(KERN_ERR "Run memtest86+ or a similar memory "
+ "test tool.\n");
+#else
+ printk(KERN_ERR "Run a memory test tool.\n");
+#endif
+ }
+ }
}
#endif
@@ -2442,7 +2485,6 @@ EXPORT_SYMBOL(kmem_cache_shrink);
* @cachep: the cache to destroy
*
* Remove a struct kmem_cache object from the slab cache.
- * Returns 0 on success.
*
* It is expected this function will be called by a module when it is
* unloaded. This will remove the cache completely, and avoid a duplicate
@@ -2454,7 +2496,7 @@ EXPORT_SYMBOL(kmem_cache_shrink);
* The caller must guarantee that noone will allocate memory from the cache
* during the kmem_cache_destroy().
*/
-int kmem_cache_destroy(struct kmem_cache *cachep)
+void kmem_cache_destroy(struct kmem_cache *cachep)
{
BUG_ON(!cachep || in_interrupt());
@@ -2475,7 +2517,7 @@ int kmem_cache_destroy(struct kmem_cache *cachep)
list_add(&cachep->next, &cache_chain);
mutex_unlock(&cache_chain_mutex);
unlock_cpu_hotplug();
- return 1;
+ return;
}
if (unlikely(cachep->flags & SLAB_DESTROY_BY_RCU))
@@ -2483,7 +2525,6 @@ int kmem_cache_destroy(struct kmem_cache *cachep)
__kmem_cache_destroy(cachep);
unlock_cpu_hotplug();
- return 0;
}
EXPORT_SYMBOL(kmem_cache_destroy);
@@ -2881,6 +2922,9 @@ static void *cache_alloc_refill(struct kmem_cache *cachep, gfp_t flags)
int batchcount;
struct kmem_list3 *l3;
struct array_cache *ac;
+ int node;
+
+ node = numa_node_id();
check_irq_off();
ac = cpu_cache_get(cachep);
@@ -2894,7 +2938,7 @@ retry:
*/
batchcount = BATCHREFILL_LIMIT;
}
- l3 = cachep->nodelists[numa_node_id()];
+ l3 = cachep->nodelists[node];
BUG_ON(ac->avail > 0 || !l3);
spin_lock(&l3->list_lock);
@@ -2924,7 +2968,7 @@ retry:
STATS_SET_HIGH(cachep);
ac->entry[ac->avail++] = slab_get_obj(cachep, slabp,
- numa_node_id());
+ node);
}
check_slabp(cachep, slabp);
@@ -2943,7 +2987,7 @@ alloc_done:
if (unlikely(!ac->avail)) {
int x;
- x = cache_grow(cachep, flags, numa_node_id());
+ x = cache_grow(cachep, flags, node);
/* cache_grow can reenable interrupts, then ac could change. */
ac = cpu_cache_get(cachep);
@@ -3030,14 +3074,6 @@ static inline void *____cache_alloc(struct kmem_cache *cachep, gfp_t flags)
void *objp;
struct array_cache *ac;
-#ifdef CONFIG_NUMA
- if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) {
- objp = alternate_node_alloc(cachep, flags);
- if (objp != NULL)
- return objp;
- }
-#endif
-
check_irq_off();
ac = cpu_cache_get(cachep);
if (likely(ac->avail)) {
@@ -3055,12 +3091,24 @@ static __always_inline void *__cache_alloc(struct kmem_cache *cachep,
gfp_t flags, void *caller)
{
unsigned long save_flags;
- void *objp;
+ void *objp = NULL;
cache_alloc_debugcheck_before(cachep, flags);
local_irq_save(save_flags);
- objp = ____cache_alloc(cachep, flags);
+
+ if (unlikely(NUMA_BUILD &&
+ current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY)))
+ objp = alternate_node_alloc(cachep, flags);
+
+ if (!objp)
+ objp = ____cache_alloc(cachep, flags);
+ /*
+ * We may just have run out of memory on the local node.
+ * __cache_alloc_node() knows how to locate memory on other nodes
+ */
+ if (NUMA_BUILD && !objp)
+ objp = __cache_alloc_node(cachep, flags, numa_node_id());
local_irq_restore(save_flags);
objp = cache_alloc_debugcheck_after(cachep, flags, objp,
caller);
@@ -3079,7 +3127,7 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
{
int nid_alloc, nid_here;
- if (in_interrupt())
+ if (in_interrupt() || (flags & __GFP_THISNODE))
return NULL;
nid_alloc = nid_here = numa_node_id();
if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
@@ -3092,6 +3140,31 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
}
/*
+ * Fallback function if there was no memory available and no objects on a
+ * certain node and we are allowed to fall back. We mimick the behavior of
+ * the page allocator. We fall back according to a zonelist determined by
+ * the policy layer while obeying cpuset constraints.
+ */
+void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
+{
+ struct zonelist *zonelist = &NODE_DATA(slab_node(current->mempolicy))
+ ->node_zonelists[gfp_zone(flags)];
+ struct zone **z;
+ void *obj = NULL;
+
+ for (z = zonelist->zones; *z && !obj; z++) {
+ int nid = zone_to_nid(*z);
+
+ if (zone_idx(*z) <= ZONE_NORMAL &&
+ cpuset_zone_allowed(*z, flags) &&
+ cache->nodelists[nid])
+ obj = __cache_alloc_node(cache,
+ flags | __GFP_THISNODE, nid);
+ }
+ return obj;
+}
+
+/*
* A interface to enable slab creation on nodeid
*/
static void *__cache_alloc_node(struct kmem_cache *cachep, gfp_t flags,
@@ -3144,11 +3217,15 @@ retry:
must_grow:
spin_unlock(&l3->list_lock);
x = cache_grow(cachep, flags, nodeid);
+ if (x)
+ goto retry;
- if (!x)
- return NULL;
+ if (!(flags & __GFP_THISNODE))
+ /* Unable to grow the cache. Fall back to other nodes. */
+ return fallback_alloc(cachep, flags);
+
+ return NULL;
- goto retry;
done:
return obj;
}
@@ -3420,22 +3497,25 @@ static __always_inline void *__do_kmalloc(size_t size, gfp_t flags,
}
+#ifdef CONFIG_DEBUG_SLAB
void *__kmalloc(size_t size, gfp_t flags)
{
-#ifndef CONFIG_DEBUG_SLAB
- return __do_kmalloc(size, flags, NULL);
-#else
return __do_kmalloc(size, flags, __builtin_return_address(0));
-#endif
}
EXPORT_SYMBOL(__kmalloc);
-#ifdef CONFIG_DEBUG_SLAB
void *__kmalloc_track_caller(size_t size, gfp_t flags, void *caller)
{
return __do_kmalloc(size, flags, caller);
}
EXPORT_SYMBOL(__kmalloc_track_caller);
+
+#else
+void *__kmalloc(size_t size, gfp_t flags)
+{
+ return __do_kmalloc(size, flags, NULL);
+}
+EXPORT_SYMBOL(__kmalloc);
#endif
/**
diff --git a/mm/slob.c b/mm/slob.c
index 20188627347c..542394184a58 100644
--- a/mm/slob.c
+++ b/mm/slob.c
@@ -270,10 +270,9 @@ struct kmem_cache *kmem_cache_create(const char *name, size_t size,
}
EXPORT_SYMBOL(kmem_cache_create);
-int kmem_cache_destroy(struct kmem_cache *c)
+void kmem_cache_destroy(struct kmem_cache *c)
{
slob_free(c, sizeof(struct kmem_cache));
- return 0;
}
EXPORT_SYMBOL(kmem_cache_destroy);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f1f5ec783781..a15def63f28f 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1723,13 +1723,14 @@ get_swap_info_struct(unsigned type)
*/
int valid_swaphandles(swp_entry_t entry, unsigned long *offset)
{
- int ret = 0, i = 1 << page_cluster;
+ int our_page_cluster = page_cluster;
+ int ret = 0, i = 1 << our_page_cluster;
unsigned long toff;
struct swap_info_struct *swapdev = swp_type(entry) + swap_info;
- if (!page_cluster) /* no readahead */
+ if (!our_page_cluster) /* no readahead */
return 0;
- toff = (swp_offset(entry) >> page_cluster) << page_cluster;
+ toff = (swp_offset(entry) >> our_page_cluster) << our_page_cluster;
if (!toff) /* first page is swap header */
toff++, i--;
*offset = toff;
diff --git a/mm/truncate.c b/mm/truncate.c
index c6ab55ec6883..e07b1e682c38 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/swap.h>
#include <linux/module.h>
#include <linux/pagemap.h>
#include <linux/pagevec.h>
@@ -16,6 +17,32 @@
do_invalidatepage */
+/**
+ * do_invalidatepage - invalidate part of all of a page
+ * @page: the page which is affected
+ * @offset: the index of the truncation point
+ *
+ * do_invalidatepage() is called when all or part of the page has become
+ * invalidated by a truncate operation.
+ *
+ * do_invalidatepage() does not have to release all buffers, but it must
+ * ensure that no dirty buffer is left outside @offset and that no I/O
+ * is underway against any of the blocks which are outside the truncation
+ * point. Because the caller is about to free (and possibly reuse) those
+ * blocks on-disk.
+ */
+void do_invalidatepage(struct page *page, unsigned long offset)
+{
+ void (*invalidatepage)(struct page *, unsigned long);
+ invalidatepage = page->mapping->a_ops->invalidatepage;
+#ifdef CONFIG_BLOCK
+ if (!invalidatepage)
+ invalidatepage = block_invalidatepage;
+#endif
+ if (invalidatepage)
+ (*invalidatepage)(page, offset);
+}
+
static inline void truncate_partial_page(struct page *page, unsigned partial)
{
memclear_highpage_flush(page, partial, PAGE_CACHE_SIZE-partial);
@@ -52,36 +79,25 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
/*
* This is for invalidate_inode_pages(). That function can be called at
* any time, and is not supposed to throw away dirty pages. But pages can
- * be marked dirty at any time too. So we re-check the dirtiness inside
- * ->tree_lock. That provides exclusion against the __set_page_dirty
- * functions.
+ * be marked dirty at any time too, so use remove_mapping which safely
+ * discards clean, unused pages.
*
* Returns non-zero if the page was successfully invalidated.
*/
static int
invalidate_complete_page(struct address_space *mapping, struct page *page)
{
+ int ret;
+
if (page->mapping != mapping)
return 0;
if (PagePrivate(page) && !try_to_release_page(page, 0))
return 0;
- write_lock_irq(&mapping->tree_lock);
- if (PageDirty(page))
- goto failed;
- if (page_count(page) != 2) /* caller's ref + pagecache ref */
- goto failed;
+ ret = remove_mapping(mapping, page);
- BUG_ON(PagePrivate(page));
- __remove_from_page_cache(page);
- write_unlock_irq(&mapping->tree_lock);
- ClearPageUptodate(page);
- page_cache_release(page); /* pagecache ref */
- return 1;
-failed:
- write_unlock_irq(&mapping->tree_lock);
- return 0;
+ return ret;
}
/**
@@ -270,9 +286,39 @@ unsigned long invalidate_inode_pages(struct address_space *mapping)
{
return invalidate_mapping_pages(mapping, 0, ~0UL);
}
-
EXPORT_SYMBOL(invalidate_inode_pages);
+/*
+ * This is like invalidate_complete_page(), except it ignores the page's
+ * refcount. We do this because invalidate_inode_pages2() needs stronger
+ * invalidation guarantees, and cannot afford to leave pages behind because
+ * shrink_list() has a temp ref on them, or because they're transiently sitting
+ * in the lru_cache_add() pagevecs.
+ */
+static int
+invalidate_complete_page2(struct address_space *mapping, struct page *page)
+{
+ if (page->mapping != mapping)
+ return 0;
+
+ if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL))
+ return 0;
+
+ write_lock_irq(&mapping->tree_lock);
+ if (PageDirty(page))
+ goto failed;
+
+ BUG_ON(PagePrivate(page));
+ __remove_from_page_cache(page);
+ write_unlock_irq(&mapping->tree_lock);
+ ClearPageUptodate(page);
+ page_cache_release(page); /* pagecache ref */
+ return 1;
+failed:
+ write_unlock_irq(&mapping->tree_lock);
+ return 0;
+}
+
/**
* invalidate_inode_pages2_range - remove range of pages from an address_space
* @mapping: the address_space
@@ -339,7 +385,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
}
}
was_dirty = test_clear_page_dirty(page);
- if (!invalidate_complete_page(mapping, page)) {
+ if (!invalidate_complete_page2(mapping, page)) {
if (was_dirty)
set_page_dirty(page);
ret = -EIO;
@@ -349,6 +395,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
pagevec_release(&pvec);
cond_resched();
}
+ WARN_ON_ONCE(ret);
return ret;
}
EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);
diff --git a/mm/util.c b/mm/util.c
index 7368479220b3..ace2aea69f1a 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -11,7 +11,7 @@
*/
void *__kzalloc(size_t size, gfp_t flags)
{
- void *ret = ____kmalloc(size, flags);
+ void *ret = kmalloc_track_caller(size, flags);
if (ret)
memset(ret, 0, size);
return ret;
@@ -33,13 +33,31 @@ char *kstrdup(const char *s, gfp_t gfp)
return NULL;
len = strlen(s) + 1;
- buf = ____kmalloc(len, gfp);
+ buf = kmalloc_track_caller(len, gfp);
if (buf)
memcpy(buf, s, len);
return buf;
}
EXPORT_SYMBOL(kstrdup);
+/**
+ * kmemdup - duplicate region of memory
+ *
+ * @src: memory region to duplicate
+ * @len: memory region length
+ * @gfp: GFP mask to use
+ */
+void *kmemdup(const void *src, size_t len, gfp_t gfp)
+{
+ void *p;
+
+ p = kmalloc_track_caller(len, gfp);
+ if (p)
+ memcpy(p, src, len);
+ return p;
+}
+EXPORT_SYMBOL(kmemdup);
+
/*
* strndup_user - duplicate an existing string from user space
*
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 9aad8b0cc6ee..1133dd3aafcf 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -241,7 +241,6 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
/**
* get_vm_area - reserve a contingous kernel virtual area
- *
* @size: size of the area
* @flags: %VM_IOREMAP for I/O mappings or VM_ALLOC
*
@@ -273,7 +272,7 @@ static struct vm_struct *__find_vm_area(void *addr)
}
/* Caller must hold vmlist_lock */
-struct vm_struct *__remove_vm_area(void *addr)
+static struct vm_struct *__remove_vm_area(void *addr)
{
struct vm_struct **p, *tmp;
@@ -296,7 +295,6 @@ found:
/**
* remove_vm_area - find and remove a contingous kernel virtual area
- *
* @addr: base address
*
* Search for the kernel VM area starting at @addr, and remove it.
@@ -355,7 +353,6 @@ void __vunmap(void *addr, int deallocate_pages)
/**
* vfree - release memory allocated by vmalloc()
- *
* @addr: memory base address
*
* Free the virtually contiguous memory area starting at @addr, as
@@ -373,7 +370,6 @@ EXPORT_SYMBOL(vfree);
/**
* vunmap - release virtual mapping obtained by vmap()
- *
* @addr: memory base address
*
* Free the virtually contiguous memory area starting at @addr,
@@ -390,7 +386,6 @@ EXPORT_SYMBOL(vunmap);
/**
* vmap - map an array of pages into virtually contiguous space
- *
* @pages: array of page pointers
* @count: number of pages to map
* @flags: vm_area->flags
@@ -433,8 +428,11 @@ void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
if (array_size > PAGE_SIZE) {
pages = __vmalloc_node(array_size, gfp_mask, PAGE_KERNEL, node);
area->flags |= VM_VPAGES;
- } else
- pages = kmalloc_node(array_size, (gfp_mask & ~__GFP_HIGHMEM), node);
+ } else {
+ pages = kmalloc_node(array_size,
+ (gfp_mask & ~(__GFP_HIGHMEM | __GFP_ZERO)),
+ node);
+ }
area->pages = pages;
if (!area->pages) {
remove_vm_area(area->addr);
@@ -471,7 +469,6 @@ void *__vmalloc_area(struct vm_struct *area, gfp_t gfp_mask, pgprot_t prot)
/**
* __vmalloc_node - allocate virtually contiguous memory
- *
* @size: allocation size
* @gfp_mask: flags for the page level allocator
* @prot: protection mask for the allocated pages
@@ -505,13 +502,11 @@ EXPORT_SYMBOL(__vmalloc);
/**
* vmalloc - allocate virtually contiguous memory
- *
* @size: allocation size
- *
* Allocate enough pages to cover @size from the page level
* allocator and map them into contiguous kernel virtual space.
*
- * For tight cotrol over page level allocator and protection flags
+ * For tight control over page level allocator and protection flags
* use __vmalloc() instead.
*/
void *vmalloc(unsigned long size)
@@ -521,11 +516,11 @@ void *vmalloc(unsigned long size)
EXPORT_SYMBOL(vmalloc);
/**
- * vmalloc_user - allocate virtually contiguous memory which has
- * been zeroed so it can be mapped to userspace without
- * leaking data.
+ * vmalloc_user - allocate zeroed virtually contiguous memory for userspace
+ * @size: allocation size
*
- * @size: allocation size
+ * The resulting memory area is zeroed so it can be mapped to userspace
+ * without leaking data.
*/
void *vmalloc_user(unsigned long size)
{
@@ -544,14 +539,13 @@ EXPORT_SYMBOL(vmalloc_user);
/**
* vmalloc_node - allocate memory on a specific node
- *
* @size: allocation size
* @node: numa node
*
* Allocate enough pages to cover @size from the page level
* allocator and map them into contiguous kernel virtual space.
*
- * For tight cotrol over page level allocator and protection flags
+ * For tight control over page level allocator and protection flags
* use __vmalloc() instead.
*/
void *vmalloc_node(unsigned long size, int node)
@@ -566,14 +560,13 @@ EXPORT_SYMBOL(vmalloc_node);
/**
* vmalloc_exec - allocate virtually contiguous, executable memory
- *
* @size: allocation size
*
* Kernel-internal function to allocate enough pages to cover @size
* the page level allocator and map them into contiguous and
* executable kernel virtual space.
*
- * For tight cotrol over page level allocator and protection flags
+ * For tight control over page level allocator and protection flags
* use __vmalloc() instead.
*/
@@ -584,7 +577,6 @@ void *vmalloc_exec(unsigned long size)
/**
* vmalloc_32 - allocate virtually contiguous memory (32bit addressable)
- *
* @size: allocation size
*
* Allocate enough 32bit PA addressable pages to cover @size from the
@@ -597,11 +589,11 @@ void *vmalloc_32(unsigned long size)
EXPORT_SYMBOL(vmalloc_32);
/**
- * vmalloc_32_user - allocate virtually contiguous memory (32bit
- * addressable) which is zeroed so it can be
- * mapped to userspace without leaking data.
- *
+ * vmalloc_32_user - allocate zeroed virtually contiguous 32bit memory
* @size: allocation size
+ *
+ * The resulting memory area is 32bit addressable and zeroed so it can be
+ * mapped to userspace without leaking data.
*/
void *vmalloc_32_user(unsigned long size)
{
@@ -695,7 +687,6 @@ finished:
/**
* remap_vmalloc_range - map vmalloc pages to userspace
- *
* @vma: vma to cover (map full range of vma)
* @addr: vmalloc memory
* @pgoff: number of pages into addr before first page to map
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 87779dda4ec6..f05527bf792b 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -19,6 +19,7 @@
#include <linux/pagemap.h>
#include <linux/init.h>
#include <linux/highmem.h>
+#include <linux/vmstat.h>
#include <linux/file.h>
#include <linux/writeback.h>
#include <linux/blkdev.h>
@@ -370,24 +371,49 @@ static pageout_t pageout(struct page *page, struct address_space *mapping)
/* synchronous write or broken a_ops? */
ClearPageReclaim(page);
}
-
+ inc_zone_page_state(page, NR_VMSCAN_WRITE);
return PAGE_SUCCESS;
}
return PAGE_CLEAN;
}
+/*
+ * Attempt to detach a locked page from its ->mapping. If it is dirty or if
+ * someone else has a ref on the page, abort and return 0. If it was
+ * successfully detached, return 1. Assumes the caller has a single ref on
+ * this page.
+ */
int remove_mapping(struct address_space *mapping, struct page *page)
{
BUG_ON(!PageLocked(page));
BUG_ON(mapping != page_mapping(page));
write_lock_irq(&mapping->tree_lock);
-
/*
- * The non-racy check for busy page. It is critical to check
- * PageDirty _after_ making sure that the page is freeable and
- * not in use by anybody. (pagecache + us == 2)
+ * The non racy check for a busy page.
+ *
+ * Must be careful with the order of the tests. When someone has
+ * a ref to the page, it may be possible that they dirty it then
+ * drop the reference. So if PageDirty is tested before page_count
+ * here, then the following race may occur:
+ *
+ * get_user_pages(&page);
+ * [user mapping goes away]
+ * write_to(page);
+ * !PageDirty(page) [good]
+ * SetPageDirty(page);
+ * put_page(page);
+ * !page_count(page) [good, discard it]
+ *
+ * [oops, our write_to data is lost]
+ *
+ * Reversing the order of the tests ensures such a situation cannot
+ * escape unnoticed. The smp_rmb is needed to ensure the page->flags
+ * load is not satisfied before that of page->_count.
+ *
+ * Note that if SetPageDirty is always performed via set_page_dirty,
+ * and thus under tree_lock, then this ordering is not required.
*/
if (unlikely(page_count(page) != 2))
goto cannot_free;
@@ -1033,7 +1059,7 @@ unsigned long try_to_free_pages(struct zone **zones, gfp_t gfp_mask)
/* Take a nap, wait for some writeback to complete */
if (sc.nr_scanned && priority < DEF_PRIORITY - 2)
- blk_congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, HZ/10);
}
/* top priority shrink_caches still had more to do? don't OOM, then */
if (!sc.all_unreclaimable)
@@ -1188,7 +1214,7 @@ scan:
* another pass across the zones.
*/
if (total_scanned && priority < DEF_PRIORITY - 2)
- blk_congestion_wait(WRITE, HZ/10);
+ congestion_wait(WRITE, HZ/10);
/*
* We do this so kswapd doesn't build up large priorities for
@@ -1432,7 +1458,7 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
goto out;
if (sc.nr_scanned && prio < DEF_PRIORITY - 2)
- blk_congestion_wait(WRITE, HZ / 10);
+ congestion_wait(WRITE, HZ / 10);
}
lru_pages = 0;
diff --git a/mm/vmstat.c b/mm/vmstat.c
index 490d8c1a0ded..45b124e012f5 100644
--- a/mm/vmstat.c
+++ b/mm/vmstat.c
@@ -9,7 +9,6 @@
* Christoph Lameter <christoph@lameter.com>
*/
-#include <linux/config.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/cpu.h>
@@ -371,7 +370,7 @@ void zone_statistics(struct zonelist *zonelist, struct zone *z)
__inc_zone_state(z, NUMA_MISS);
__inc_zone_state(zonelist->zones[0], NUMA_FOREIGN);
}
- if (z->zone_pgdat == NODE_DATA(numa_node_id()))
+ if (z->node == numa_node_id())
__inc_zone_state(z, NUMA_LOCAL);
else
__inc_zone_state(z, NUMA_OTHER);
@@ -465,6 +464,7 @@ static char *vmstat_text[] = {
"nr_writeback",
"nr_unstable",
"nr_bounce",
+ "nr_vmscan_write",
#ifdef CONFIG_NUMA
"numa_hit",
diff --git a/net/802/tr.c b/net/802/tr.c
index d7d8f40c4fed..829deb41ce81 100644
--- a/net/802/tr.c
+++ b/net/802/tr.c
@@ -164,7 +164,7 @@ static int tr_rebuild_header(struct sk_buff *skb)
*/
if(trllc->ethertype != htons(ETH_P_IP)) {
- printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype));
+ printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n", ntohs(trllc->ethertype));
return 0;
}
@@ -186,7 +186,7 @@ static int tr_rebuild_header(struct sk_buff *skb)
* it via SNAP.
*/
-unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev)
+__be16 tr_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct trh_hdr *trh=(struct trh_hdr *)skb->data;
@@ -229,15 +229,15 @@ unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev)
*/
if (trllc->dsap == EXTENDED_SAP &&
- (trllc->ethertype == ntohs(ETH_P_IP) ||
- trllc->ethertype == ntohs(ETH_P_IPV6) ||
- trllc->ethertype == ntohs(ETH_P_ARP)))
+ (trllc->ethertype == htons(ETH_P_IP) ||
+ trllc->ethertype == htons(ETH_P_IPV6) ||
+ trllc->ethertype == htons(ETH_P_ARP)))
{
skb_pull(skb, sizeof(struct trllc));
return trllc->ethertype;
}
- return ntohs(ETH_P_TR_802_2);
+ return htons(ETH_P_TR_802_2);
}
/*
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index da9cfe927158..60a508eb1945 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -62,7 +62,7 @@ int vlan_dev_rebuild_header(struct sk_buff *skb)
default:
printk(VLAN_DBG
"%s: unable to resolve type %X addresses.\n",
- dev->name, (int)veth->h_vlan_encapsulated_proto);
+ dev->name, ntohs(veth->h_vlan_encapsulated_proto));
memcpy(veth->h_source, dev->dev_addr, ETH_ALEN);
break;
diff --git a/net/Kconfig b/net/Kconfig
index 6528a935622c..a81aca43932f 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -231,7 +231,7 @@ config NET_TCPPROBE
TCP congestion avoidance modules. If you don't understand
what was just said, you don't need it: say N.
- Documentation on how to use the packet generator can be found
+ Documentation on how to use TCP connection probing can be found
at http://linux-net.osdl.org/index.php/TcpProbe
To compile this code as a module, choose M here: the
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c
index 96dc6bb52d14..708e2e0371af 100644
--- a/net/appletalk/ddp.c
+++ b/net/appletalk/ddp.c
@@ -1002,7 +1002,7 @@ static unsigned long atalk_sum_skb(const struct sk_buff *skb, int offset,
return sum;
}
-static unsigned short atalk_checksum(const struct sk_buff *skb, int len)
+static __be16 atalk_checksum(const struct sk_buff *skb, int len)
{
unsigned long sum;
@@ -1010,7 +1010,7 @@ static unsigned short atalk_checksum(const struct sk_buff *skb, int len)
sum = atalk_sum_skb(skb, 4, len-4, 0);
/* Use 0xFFFF for 0. 0 itself means none */
- return sum ? htons((unsigned short)sum) : 0xFFFF;
+ return sum ? htons((unsigned short)sum) : htons(0xFFFF);
}
static struct proto ddp_proto = {
@@ -1289,7 +1289,7 @@ static int handle_ip_over_ddp(struct sk_buff *skb)
#endif
static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
- struct ddpehdr *ddp, struct ddpebits *ddphv,
+ struct ddpehdr *ddp, __u16 len_hops,
int origlen)
{
struct atalk_route *rt;
@@ -1317,10 +1317,12 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
/* Route the packet */
rt = atrtr_find(&ta);
- if (!rt || ddphv->deh_hops == DDP_MAXHOPS)
+ /* increment hops count */
+ len_hops += 1 << 10;
+ if (!rt || !(len_hops & (15 << 10)))
goto free_it;
+
/* FIXME: use skb->cb to be able to use shared skbs */
- ddphv->deh_hops++;
/*
* Route goes through another gateway, so set the target to the
@@ -1335,11 +1337,10 @@ static void atalk_route_packet(struct sk_buff *skb, struct net_device *dev,
/* Fix up skb->len field */
skb_trim(skb, min_t(unsigned int, origlen,
(rt->dev->hard_header_len +
- ddp_dl->header_length + ddphv->deh_len)));
+ ddp_dl->header_length + (len_hops & 1023))));
- /* Mend the byte order */
/* FIXME: use skb->cb to be able to use shared skbs */
- *((__u16 *)ddp) = ntohs(*((__u16 *)ddphv));
+ ddp->deh_len_hops = htons(len_hops);
/*
* Send the buffer onwards
@@ -1394,7 +1395,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
struct atalk_iface *atif;
struct sockaddr_at tosat;
int origlen;
- struct ddpebits ddphv;
+ __u16 len_hops;
/* Don't mangle buffer if shared */
if (!(skb = skb_share_check(skb, GFP_ATOMIC)))
@@ -1406,16 +1407,11 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
ddp = ddp_hdr(skb);
- /*
- * Fix up the length field [Ok this is horrible but otherwise
- * I end up with unions of bit fields and messy bit field order
- * compiler/endian dependencies..]
- */
- *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
+ len_hops = ntohs(ddp->deh_len_hops);
/* Trim buffer in case of stray trailing data */
origlen = skb->len;
- skb_trim(skb, min_t(unsigned int, skb->len, ddphv.deh_len));
+ skb_trim(skb, min_t(unsigned int, skb->len, len_hops & 1023));
/*
* Size check to see if ddp->deh_len was crap
@@ -1430,7 +1426,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
* valid for net byte orders all over the networking code...
*/
if (ddp->deh_sum &&
- atalk_checksum(skb, ddphv.deh_len) != ddp->deh_sum)
+ atalk_checksum(skb, len_hops & 1023) != ddp->deh_sum)
/* Not a valid AppleTalk frame - dustbin time */
goto freeit;
@@ -1444,7 +1440,7 @@ static int atalk_rcv(struct sk_buff *skb, struct net_device *dev,
/* Not ours, so we route the packet via the correct
* AppleTalk iface
*/
- atalk_route_packet(skb, dev, ddp, &ddphv, origlen);
+ atalk_route_packet(skb, dev, ddp, len_hops, origlen);
goto out;
}
@@ -1489,7 +1485,7 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
/* Find our address */
struct atalk_addr *ap = atalk_find_dev_addr(dev);
- if (!ap || skb->len < sizeof(struct ddpshdr))
+ if (!ap || skb->len < sizeof(__be16) || skb->len > 1023)
goto freeit;
/* Don't mangle buffer if shared */
@@ -1519,11 +1515,8 @@ static int ltalk_rcv(struct sk_buff *skb, struct net_device *dev,
/*
* Not sure about this bit...
*/
- ddp->deh_len = skb->len;
- ddp->deh_hops = DDP_MAXHOPS; /* Non routable, so force a drop
- if we slip up later */
- /* Mend the byte order */
- *((__u16 *)ddp) = htons(*((__u16 *)ddp));
+ /* Non routable, so force a drop if we slip up later */
+ ddp->deh_len_hops = htons(skb->len + (DDP_MAXHOPS << 10));
}
skb->h.raw = skb->data;
@@ -1622,16 +1615,7 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
SOCK_DEBUG(sk, "SK %p: Begin build.\n", sk);
ddp = (struct ddpehdr *)skb_put(skb, sizeof(struct ddpehdr));
- ddp->deh_pad = 0;
- ddp->deh_hops = 0;
- ddp->deh_len = len + sizeof(*ddp);
- /*
- * Fix up the length field [Ok this is horrible but otherwise
- * I end up with unions of bit fields and messy bit field order
- * compiler/endian dependencies..
- */
- *((__u16 *)ddp) = ntohs(*((__u16 *)ddp));
-
+ ddp->deh_len_hops = htons(len + sizeof(*ddp));
ddp->deh_dnet = usat->sat_addr.s_net;
ddp->deh_snet = at->src_net;
ddp->deh_dnode = usat->sat_addr.s_node;
@@ -1712,8 +1696,8 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
struct sockaddr_at *sat = (struct sockaddr_at *)msg->msg_name;
struct ddpehdr *ddp;
int copied = 0;
+ int offset = 0;
int err = 0;
- struct ddpebits ddphv;
struct sk_buff *skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err);
if (!skb)
@@ -1721,25 +1705,18 @@ static int atalk_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
/* FIXME: use skb->cb to be able to use shared skbs */
ddp = ddp_hdr(skb);
- *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp));
+ copied = ntohs(ddp->deh_len_hops) & 1023;
- if (sk->sk_type == SOCK_RAW) {
- copied = ddphv.deh_len;
- if (copied > size) {
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
+ if (sk->sk_type != SOCK_RAW) {
+ offset = sizeof(*ddp);
+ copied -= offset;
+ }
- err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
- } else {
- copied = ddphv.deh_len - sizeof(*ddp);
- if (copied > size) {
- copied = size;
- msg->msg_flags |= MSG_TRUNC;
- }
- err = skb_copy_datagram_iovec(skb, sizeof(*ddp),
- msg->msg_iov, copied);
+ if (copied > size) {
+ copied = size;
+ msg->msg_flags |= MSG_TRUNC;
}
+ err = skb_copy_datagram_iovec(skb, offset, msg->msg_iov, copied);
if (!err) {
if (sat) {
diff --git a/net/atm/lec.c b/net/atm/lec.c
index b4aa489849df..66c57c1091a8 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -1,7 +1,7 @@
/*
* lec.c: Lan Emulation driver
- * Marko Kiiskila mkiiskila@yahoo.com
*
+ * Marko Kiiskila <mkiiskila@yahoo.com>
*/
#include <linux/kernel.h>
@@ -38,7 +38,7 @@
#include <linux/if_bridge.h>
#include "../bridge/br_private.h"
-static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
+static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
#endif
/* Modular too */
@@ -55,38 +55,41 @@ static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
#define DPRINTK(format,args...)
#endif
-#define DUMP_PACKETS 0 /* 0 = None,
- * 1 = 30 first bytes
- * 2 = Whole packet
- */
+#define DUMP_PACKETS 0 /*
+ * 0 = None,
+ * 1 = 30 first bytes
+ * 2 = Whole packet
+ */
-#define LEC_UNRES_QUE_LEN 8 /* number of tx packets to queue for a
- single destination while waiting for SVC */
+#define LEC_UNRES_QUE_LEN 8 /*
+ * number of tx packets to queue for a
+ * single destination while waiting for SVC
+ */
static int lec_open(struct net_device *dev);
static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lec_close(struct net_device *dev);
static struct net_device_stats *lec_get_stats(struct net_device *dev);
static void lec_init(struct net_device *dev);
-static struct lec_arp_table* lec_arp_find(struct lec_priv *priv,
- unsigned char *mac_addr);
+static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
+ unsigned char *mac_addr);
static int lec_arp_remove(struct lec_priv *priv,
- struct lec_arp_table *to_remove);
+ struct lec_arp_table *to_remove);
/* LANE2 functions */
-static void lane2_associate_ind (struct net_device *dev, u8 *mac_address,
- u8 *tlvs, u32 sizeoftlvs);
+static void lane2_associate_ind(struct net_device *dev, u8 *mac_address,
+ u8 *tlvs, u32 sizeoftlvs);
static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
- u8 **tlvs, u32 *sizeoftlvs);
-static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
- u8 *tlvs, u32 sizeoftlvs);
+ u8 **tlvs, u32 *sizeoftlvs);
+static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
+ u8 *tlvs, u32 sizeoftlvs);
-static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
+static int lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
unsigned long permanent);
static void lec_arp_check_empties(struct lec_priv *priv,
struct atm_vcc *vcc, struct sk_buff *skb);
static void lec_arp_destroy(struct lec_priv *priv);
static void lec_arp_init(struct lec_priv *priv);
-static struct atm_vcc* lec_arp_resolve(struct lec_priv *priv,
+static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
unsigned char *mac_to_find,
int is_rdesc,
struct lec_arp_table **ret_entry);
@@ -100,16 +103,30 @@ static void lec_set_flush_tran_id(struct lec_priv *priv,
unsigned long tran_id);
static void lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
struct atm_vcc *vcc,
- void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb));
+ void (*old_push) (struct atm_vcc *vcc,
+ struct sk_buff *skb));
static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc);
+/* must be done under lec_arp_lock */
+static inline void lec_arp_hold(struct lec_arp_table *entry)
+{
+ atomic_inc(&entry->usage);
+}
+
+static inline void lec_arp_put(struct lec_arp_table *entry)
+{
+ if (atomic_dec_and_test(&entry->usage))
+ kfree(entry);
+}
+
+
static struct lane2_ops lane2_ops = {
- lane2_resolve, /* resolve, spec 3.1.3 */
- lane2_associate_req, /* associate_req, spec 3.1.4 */
- NULL /* associate indicator, spec 3.1.5 */
+ lane2_resolve, /* resolve, spec 3.1.3 */
+ lane2_associate_req, /* associate_req, spec 3.1.4 */
+ NULL /* associate indicator, spec 3.1.5 */
};
-static unsigned char bus_mac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
+static unsigned char bus_mac[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
/* Device structures */
static struct net_device *dev_lec[MAX_LEC_ITF];
@@ -117,36 +134,39 @@ static struct net_device *dev_lec[MAX_LEC_ITF];
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
{
- struct ethhdr *eth;
- char *buff;
- struct lec_priv *priv;
-
- /* Check if this is a BPDU. If so, ask zeppelin to send
- * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
- * as the Config BPDU has */
- eth = (struct ethhdr *)skb->data;
- buff = skb->data + skb->dev->hard_header_len;
- if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
+ struct ethhdr *eth;
+ char *buff;
+ struct lec_priv *priv;
+
+ /*
+ * Check if this is a BPDU. If so, ask zeppelin to send
+ * LE_TOPOLOGY_REQUEST with the same value of Topology Change bit
+ * as the Config BPDU has
+ */
+ eth = (struct ethhdr *)skb->data;
+ buff = skb->data + skb->dev->hard_header_len;
+ if (*buff++ == 0x42 && *buff++ == 0x42 && *buff++ == 0x03) {
struct sock *sk;
- struct sk_buff *skb2;
- struct atmlec_msg *mesg;
-
- skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
- if (skb2 == NULL) return;
- skb2->len = sizeof(struct atmlec_msg);
- mesg = (struct atmlec_msg *)skb2->data;
- mesg->type = l_topology_change;
- buff += 4;
- mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */
-
- priv = (struct lec_priv *)dev->priv;
- atm_force_charge(priv->lecd, skb2->truesize);
+ struct sk_buff *skb2;
+ struct atmlec_msg *mesg;
+
+ skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
+ if (skb2 == NULL)
+ return;
+ skb2->len = sizeof(struct atmlec_msg);
+ mesg = (struct atmlec_msg *)skb2->data;
+ mesg->type = l_topology_change;
+ buff += 4;
+ mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */
+
+ priv = (struct lec_priv *)dev->priv;
+ atm_force_charge(priv->lecd, skb2->truesize);
sk = sk_atm(priv->lecd);
- skb_queue_tail(&sk->sk_receive_queue, skb2);
- sk->sk_data_ready(sk, skb2->len);
- }
+ skb_queue_tail(&sk->sk_receive_queue, skb2);
+ sk->sk_data_ready(sk, skb2->len);
+ }
- return;
+ return;
}
#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
@@ -162,36 +182,35 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev)
#ifdef CONFIG_TR
static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
{
- struct trh_hdr *trh;
- int riflen, num_rdsc;
-
- trh = (struct trh_hdr *)packet;
- if (trh->daddr[0] & (uint8_t)0x80)
- return bus_mac; /* multicast */
-
- if (trh->saddr[0] & TR_RII) {
- riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
- if ((ntohs(trh->rcf) >> 13) != 0)
- return bus_mac; /* ARE or STE */
- }
- else
- return trh->daddr; /* not source routed */
-
- if (riflen < 6)
- return trh->daddr; /* last hop, source routed */
-
- /* riflen is 6 or more, packet has more than one route descriptor */
- num_rdsc = (riflen/2) - 1;
- memset(rdesc, 0, ETH_ALEN);
- /* offset 4 comes from LAN destination field in LE control frames */
- if (trh->rcf & htons((uint16_t)TR_RCF_DIR_BIT))
- memcpy(&rdesc[4], &trh->rseg[num_rdsc-2], sizeof(uint16_t));
- else {
- memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
- rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
- }
-
- return NULL;
+ struct trh_hdr *trh;
+ int riflen, num_rdsc;
+
+ trh = (struct trh_hdr *)packet;
+ if (trh->daddr[0] & (uint8_t) 0x80)
+ return bus_mac; /* multicast */
+
+ if (trh->saddr[0] & TR_RII) {
+ riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
+ if ((ntohs(trh->rcf) >> 13) != 0)
+ return bus_mac; /* ARE or STE */
+ } else
+ return trh->daddr; /* not source routed */
+
+ if (riflen < 6)
+ return trh->daddr; /* last hop, source routed */
+
+ /* riflen is 6 or more, packet has more than one route descriptor */
+ num_rdsc = (riflen / 2) - 1;
+ memset(rdesc, 0, ETH_ALEN);
+ /* offset 4 comes from LAN destination field in LE control frames */
+ if (trh->rcf & htons((uint16_t) TR_RCF_DIR_BIT))
+ memcpy(&rdesc[4], &trh->rseg[num_rdsc - 2], sizeof(uint16_t));
+ else {
+ memcpy(&rdesc[4], &trh->rseg[1], sizeof(uint16_t));
+ rdesc[5] = ((ntohs(trh->rseg[0]) & 0x000f) | (rdesc[5] & 0xf0));
+ }
+
+ return NULL;
}
#endif /* CONFIG_TR */
@@ -204,15 +223,14 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
* there is non-reboot way to recover if something goes wrong.
*/
-static int
-lec_open(struct net_device *dev)
+static int lec_open(struct net_device *dev)
{
- struct lec_priv *priv = (struct lec_priv *)dev->priv;
-
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+
netif_start_queue(dev);
- memset(&priv->stats,0,sizeof(struct net_device_stats));
-
- return 0;
+ memset(&priv->stats, 0, sizeof(struct net_device_stats));
+
+ return 0;
}
static __inline__ void
@@ -231,160 +249,166 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
priv->stats.tx_bytes += skb->len;
}
-static void
-lec_tx_timeout(struct net_device *dev)
+static void lec_tx_timeout(struct net_device *dev)
{
printk(KERN_INFO "%s: tx timeout\n", dev->name);
dev->trans_start = jiffies;
netif_wake_queue(dev);
}
-static int
-lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct sk_buff *skb2;
- struct lec_priv *priv = (struct lec_priv *)dev->priv;
- struct lecdatahdr_8023 *lec_h;
- struct atm_vcc *vcc;
+ struct sk_buff *skb2;
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+ struct lecdatahdr_8023 *lec_h;
+ struct atm_vcc *vcc;
struct lec_arp_table *entry;
- unsigned char *dst;
+ unsigned char *dst;
int min_frame_size;
#ifdef CONFIG_TR
- unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
+ unsigned char rdesc[ETH_ALEN]; /* Token Ring route descriptor */
#endif
- int is_rdesc;
+ int is_rdesc;
#if DUMP_PACKETS > 0
- char buf[300];
- int i=0;
+ char buf[300];
+ int i = 0;
#endif /* DUMP_PACKETS >0 */
-
- DPRINTK("lec_start_xmit called\n");
- if (!priv->lecd) {
- printk("%s:No lecd attached\n",dev->name);
- priv->stats.tx_errors++;
- netif_stop_queue(dev);
- return -EUNATCH;
- }
-
- DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
- (long)skb->head, (long)skb->data, (long)skb->tail,
- (long)skb->end);
+
+ DPRINTK("lec_start_xmit called\n");
+ if (!priv->lecd) {
+ printk("%s:No lecd attached\n", dev->name);
+ priv->stats.tx_errors++;
+ netif_stop_queue(dev);
+ return -EUNATCH;
+ }
+
+ DPRINTK("skbuff head:%lx data:%lx tail:%lx end:%lx\n",
+ (long)skb->head, (long)skb->data, (long)skb->tail,
+ (long)skb->end);
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
- if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
- lec_handle_bridge(skb, dev);
+ if (memcmp(skb->data, bridge_ula_lec, sizeof(bridge_ula_lec)) == 0)
+ lec_handle_bridge(skb, dev);
#endif
- /* Make sure we have room for lec_id */
- if (skb_headroom(skb) < 2) {
+ /* Make sure we have room for lec_id */
+ if (skb_headroom(skb) < 2) {
- DPRINTK("lec_start_xmit: reallocating skb\n");
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- kfree_skb(skb);
- if (skb2 == NULL) return 0;
- skb = skb2;
- }
- skb_push(skb, 2);
+ DPRINTK("lec_start_xmit: reallocating skb\n");
+ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+ kfree_skb(skb);
+ if (skb2 == NULL)
+ return 0;
+ skb = skb2;
+ }
+ skb_push(skb, 2);
- /* Put le header to place, works for TokenRing too */
- lec_h = (struct lecdatahdr_8023*)skb->data;
- lec_h->le_header = htons(priv->lecid);
+ /* Put le header to place, works for TokenRing too */
+ lec_h = (struct lecdatahdr_8023 *)skb->data;
+ lec_h->le_header = htons(priv->lecid);
#ifdef CONFIG_TR
- /* Ugly. Use this to realign Token Ring packets for
- * e.g. PCA-200E driver. */
- if (priv->is_trdev) {
- skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
- kfree_skb(skb);
- if (skb2 == NULL) return 0;
- skb = skb2;
- }
+ /*
+ * Ugly. Use this to realign Token Ring packets for
+ * e.g. PCA-200E driver.
+ */
+ if (priv->is_trdev) {
+ skb2 = skb_realloc_headroom(skb, LEC_HEADER_LEN);
+ kfree_skb(skb);
+ if (skb2 == NULL)
+ return 0;
+ skb = skb2;
+ }
#endif
#if DUMP_PACKETS > 0
- printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
- skb->len, priv->lecid);
+ printk("%s: send datalen:%ld lecid:%4.4x\n", dev->name,
+ skb->len, priv->lecid);
#if DUMP_PACKETS >= 2
- for(i=0;i<skb->len && i <99;i++) {
- sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
- }
+ for (i = 0; i < skb->len && i < 99; i++) {
+ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
+ }
#elif DUMP_PACKETS >= 1
- for(i=0;i<skb->len && i < 30;i++) {
- sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
- }
+ for (i = 0; i < skb->len && i < 30; i++) {
+ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
+ }
#endif /* DUMP_PACKETS >= 1 */
- if (i==skb->len)
- printk("%s\n",buf);
- else
- printk("%s...\n",buf);
+ if (i == skb->len)
+ printk("%s\n", buf);
+ else
+ printk("%s...\n", buf);
#endif /* DUMP_PACKETS > 0 */
- /* Minimum ethernet-frame size */
+ /* Minimum ethernet-frame size */
#ifdef CONFIG_TR
- if (priv->is_trdev)
- min_frame_size = LEC_MINIMUM_8025_SIZE;
+ if (priv->is_trdev)
+ min_frame_size = LEC_MINIMUM_8025_SIZE;
else
#endif
- min_frame_size = LEC_MINIMUM_8023_SIZE;
- if (skb->len < min_frame_size) {
- if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
- skb2 = skb_copy_expand(skb, 0,
- min_frame_size - skb->truesize, GFP_ATOMIC);
- dev_kfree_skb(skb);
- if (skb2 == NULL) {
- priv->stats.tx_dropped++;
- return 0;
- }
- skb = skb2;
- }
+ min_frame_size = LEC_MINIMUM_8023_SIZE;
+ if (skb->len < min_frame_size) {
+ if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
+ skb2 = skb_copy_expand(skb, 0,
+ min_frame_size - skb->truesize,
+ GFP_ATOMIC);
+ dev_kfree_skb(skb);
+ if (skb2 == NULL) {
+ priv->stats.tx_dropped++;
+ return 0;
+ }
+ skb = skb2;
+ }
skb_put(skb, min_frame_size - skb->len);
- }
-
- /* Send to right vcc */
- is_rdesc = 0;
- dst = lec_h->h_dest;
+ }
+
+ /* Send to right vcc */
+ is_rdesc = 0;
+ dst = lec_h->h_dest;
#ifdef CONFIG_TR
- if (priv->is_trdev) {
- dst = get_tr_dst(skb->data+2, rdesc);
- if (dst == NULL) {
- dst = rdesc;
- is_rdesc = 1;
- }
- }
+ if (priv->is_trdev) {
+ dst = get_tr_dst(skb->data + 2, rdesc);
+ if (dst == NULL) {
+ dst = rdesc;
+ is_rdesc = 1;
+ }
+ }
#endif
- entry = NULL;
- vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
- DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
- vcc, vcc?vcc->flags:0, entry);
- if (!vcc || !test_bit(ATM_VF_READY,&vcc->flags)) {
- if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
- DPRINTK("%s:lec_start_xmit: queuing packet, ", dev->name);
- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
- skb_queue_tail(&entry->tx_wait, skb);
- } else {
- DPRINTK("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name);
- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
- priv->stats.tx_dropped++;
- dev_kfree_skb(skb);
- }
- return 0;
- }
-
-#if DUMP_PACKETS > 0
- printk("%s:sending to vpi:%d vci:%d\n", dev->name,
- vcc->vpi, vcc->vci);
+ entry = NULL;
+ vcc = lec_arp_resolve(priv, dst, is_rdesc, &entry);
+ DPRINTK("%s:vcc:%p vcc_flags:%x, entry:%p\n", dev->name,
+ vcc, vcc ? vcc->flags : 0, entry);
+ if (!vcc || !test_bit(ATM_VF_READY, &vcc->flags)) {
+ if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) {
+ DPRINTK("%s:lec_start_xmit: queuing packet, ",
+ dev->name);
+ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ lec_h->h_dest[0], lec_h->h_dest[1],
+ lec_h->h_dest[2], lec_h->h_dest[3],
+ lec_h->h_dest[4], lec_h->h_dest[5]);
+ skb_queue_tail(&entry->tx_wait, skb);
+ } else {
+ DPRINTK
+ ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
+ dev->name);
+ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ lec_h->h_dest[0], lec_h->h_dest[1],
+ lec_h->h_dest[2], lec_h->h_dest[3],
+ lec_h->h_dest[4], lec_h->h_dest[5]);
+ priv->stats.tx_dropped++;
+ dev_kfree_skb(skb);
+ }
+ goto out;
+ }
+#if DUMP_PACKETS > 0
+ printk("%s:sending to vpi:%d vci:%d\n", dev->name, vcc->vpi, vcc->vci);
#endif /* DUMP_PACKETS > 0 */
-
- while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
- DPRINTK("lec.c: emptying tx queue, ");
- DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
- lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
+
+ while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
+ DPRINTK("lec.c: emptying tx queue, ");
+ DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
+ lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
lec_send(vcc, skb2, priv);
- }
+ }
lec_send(vcc, skb, priv);
@@ -404,210 +428,219 @@ lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_wake_queue(dev);
}
+out:
+ if (entry)
+ lec_arp_put(entry);
dev->trans_start = jiffies;
- return 0;
+ return 0;
}
/* The inverse routine to net_open(). */
-static int
-lec_close(struct net_device *dev)
+static int lec_close(struct net_device *dev)
{
- netif_stop_queue(dev);
- return 0;
+ netif_stop_queue(dev);
+ return 0;
}
/*
* Get the current statistics.
* This may be called with the card open or closed.
*/
-static struct net_device_stats *
-lec_get_stats(struct net_device *dev)
+static struct net_device_stats *lec_get_stats(struct net_device *dev)
{
- return &((struct lec_priv *)dev->priv)->stats;
+ return &((struct lec_priv *)dev->priv)->stats;
}
-static int
-lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
- struct net_device *dev = (struct net_device*)vcc->proto_data;
- struct lec_priv *priv = (struct lec_priv*)dev->priv;
- struct atmlec_msg *mesg;
- struct lec_arp_table *entry;
- int i;
- char *tmp; /* FIXME */
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+ struct atmlec_msg *mesg;
+ struct lec_arp_table *entry;
+ int i;
+ char *tmp; /* FIXME */
atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
- mesg = (struct atmlec_msg *)skb->data;
- tmp = skb->data;
- tmp += sizeof(struct atmlec_msg);
- DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
- switch(mesg->type) {
- case l_set_mac_addr:
- for (i=0;i<6;i++) {
- dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
- }
- break;
- case l_del_mac_addr:
- for(i=0;i<6;i++) {
- dev->dev_addr[i] = 0;
- }
- break;
- case l_addr_delete:
- lec_addr_delete(priv, mesg->content.normal.atm_addr,
- mesg->content.normal.flag);
- break;
- case l_topology_change:
- priv->topology_change = mesg->content.normal.flag;
- break;
- case l_flush_complete:
- lec_flush_complete(priv, mesg->content.normal.flag);
- break;
- case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
+ mesg = (struct atmlec_msg *)skb->data;
+ tmp = skb->data;
+ tmp += sizeof(struct atmlec_msg);
+ DPRINTK("%s: msg from zeppelin:%d\n", dev->name, mesg->type);
+ switch (mesg->type) {
+ case l_set_mac_addr:
+ for (i = 0; i < 6; i++) {
+ dev->dev_addr[i] = mesg->content.normal.mac_addr[i];
+ }
+ break;
+ case l_del_mac_addr:
+ for (i = 0; i < 6; i++) {
+ dev->dev_addr[i] = 0;
+ }
+ break;
+ case l_addr_delete:
+ lec_addr_delete(priv, mesg->content.normal.atm_addr,
+ mesg->content.normal.flag);
+ break;
+ case l_topology_change:
+ priv->topology_change = mesg->content.normal.flag;
+ break;
+ case l_flush_complete:
+ lec_flush_complete(priv, mesg->content.normal.flag);
+ break;
+ case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
- lec_arp_remove(priv, entry);
+ entry = lec_arp_find(priv, mesg->content.normal.mac_addr);
+ lec_arp_remove(priv, entry);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- if (mesg->content.normal.no_source_le_narp)
- break;
- /* FALL THROUGH */
- case l_arp_update:
- lec_arp_update(priv, mesg->content.normal.mac_addr,
- mesg->content.normal.atm_addr,
- mesg->content.normal.flag,
- mesg->content.normal.targetless_le_arp);
- DPRINTK("lec: in l_arp_update\n");
- if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */
- DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n", mesg->sizeoftlvs);
- lane2_associate_ind(dev,
- mesg->content.normal.mac_addr,
- tmp, mesg->sizeoftlvs);
- }
- break;
- case l_config:
- priv->maximum_unknown_frame_count =
- mesg->content.config.maximum_unknown_frame_count;
- priv->max_unknown_frame_time =
- (mesg->content.config.max_unknown_frame_time*HZ);
- priv->max_retry_count =
- mesg->content.config.max_retry_count;
- priv->aging_time = (mesg->content.config.aging_time*HZ);
- priv->forward_delay_time =
- (mesg->content.config.forward_delay_time*HZ);
- priv->arp_response_time =
- (mesg->content.config.arp_response_time*HZ);
- priv->flush_timeout = (mesg->content.config.flush_timeout*HZ);
- priv->path_switching_delay =
- (mesg->content.config.path_switching_delay*HZ);
- priv->lane_version = mesg->content.config.lane_version; /* LANE2 */
+ if (mesg->content.normal.no_source_le_narp)
+ break;
+ /* FALL THROUGH */
+ case l_arp_update:
+ lec_arp_update(priv, mesg->content.normal.mac_addr,
+ mesg->content.normal.atm_addr,
+ mesg->content.normal.flag,
+ mesg->content.normal.targetless_le_arp);
+ DPRINTK("lec: in l_arp_update\n");
+ if (mesg->sizeoftlvs != 0) { /* LANE2 3.1.5 */
+ DPRINTK("lec: LANE2 3.1.5, got tlvs, size %d\n",
+ mesg->sizeoftlvs);
+ lane2_associate_ind(dev, mesg->content.normal.mac_addr,
+ tmp, mesg->sizeoftlvs);
+ }
+ break;
+ case l_config:
+ priv->maximum_unknown_frame_count =
+ mesg->content.config.maximum_unknown_frame_count;
+ priv->max_unknown_frame_time =
+ (mesg->content.config.max_unknown_frame_time * HZ);
+ priv->max_retry_count = mesg->content.config.max_retry_count;
+ priv->aging_time = (mesg->content.config.aging_time * HZ);
+ priv->forward_delay_time =
+ (mesg->content.config.forward_delay_time * HZ);
+ priv->arp_response_time =
+ (mesg->content.config.arp_response_time * HZ);
+ priv->flush_timeout = (mesg->content.config.flush_timeout * HZ);
+ priv->path_switching_delay =
+ (mesg->content.config.path_switching_delay * HZ);
+ priv->lane_version = mesg->content.config.lane_version; /* LANE2 */
priv->lane2_ops = NULL;
if (priv->lane_version > 1)
priv->lane2_ops = &lane2_ops;
if (dev->change_mtu(dev, mesg->content.config.mtu))
printk("%s: change_mtu to %d failed\n", dev->name,
- mesg->content.config.mtu);
+ mesg->content.config.mtu);
priv->is_proxy = mesg->content.config.is_proxy;
- break;
- case l_flush_tran_id:
- lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr,
- mesg->content.normal.flag);
- break;
- case l_set_lecid:
- priv->lecid=(unsigned short)(0xffff&mesg->content.normal.flag);
- break;
- case l_should_bridge: {
+ break;
+ case l_flush_tran_id:
+ lec_set_flush_tran_id(priv, mesg->content.normal.atm_addr,
+ mesg->content.normal.flag);
+ break;
+ case l_set_lecid:
+ priv->lecid =
+ (unsigned short)(0xffff & mesg->content.normal.flag);
+ break;
+ case l_should_bridge:
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
- struct net_bridge_fdb_entry *f;
-
- DPRINTK("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
- dev->name,
- mesg->content.proxy.mac_addr[0], mesg->content.proxy.mac_addr[1],
- mesg->content.proxy.mac_addr[2], mesg->content.proxy.mac_addr[3],
- mesg->content.proxy.mac_addr[4], mesg->content.proxy.mac_addr[5]);
-
- if (br_fdb_get_hook == NULL || dev->br_port == NULL)
- break;
-
- f = br_fdb_get_hook(dev->br_port->br, mesg->content.proxy.mac_addr);
- if (f != NULL &&
- f->dst->dev != dev &&
- f->dst->state == BR_STATE_FORWARDING) {
- /* hit from bridge table, send LE_ARP_RESPONSE */
- struct sk_buff *skb2;
- struct sock *sk;
-
- DPRINTK("%s: entry found, responding to zeppelin\n", dev->name);
- skb2 = alloc_skb(sizeof(struct atmlec_msg), GFP_ATOMIC);
- if (skb2 == NULL) {
- br_fdb_put_hook(f);
- break;
- }
- skb2->len = sizeof(struct atmlec_msg);
- memcpy(skb2->data, mesg, sizeof(struct atmlec_msg));
- atm_force_charge(priv->lecd, skb2->truesize);
- sk = sk_atm(priv->lecd);
- skb_queue_tail(&sk->sk_receive_queue, skb2);
- sk->sk_data_ready(sk, skb2->len);
- }
- if (f != NULL) br_fdb_put_hook(f);
+ {
+ struct net_bridge_fdb_entry *f;
+
+ DPRINTK
+ ("%s: bridge zeppelin asks about 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
+ dev->name, mesg->content.proxy.mac_addr[0],
+ mesg->content.proxy.mac_addr[1],
+ mesg->content.proxy.mac_addr[2],
+ mesg->content.proxy.mac_addr[3],
+ mesg->content.proxy.mac_addr[4],
+ mesg->content.proxy.mac_addr[5]);
+
+ if (br_fdb_get_hook == NULL || dev->br_port == NULL)
+ break;
+
+ f = br_fdb_get_hook(dev->br_port->br,
+ mesg->content.proxy.mac_addr);
+ if (f != NULL && f->dst->dev != dev
+ && f->dst->state == BR_STATE_FORWARDING) {
+ /* hit from bridge table, send LE_ARP_RESPONSE */
+ struct sk_buff *skb2;
+ struct sock *sk;
+
+ DPRINTK
+ ("%s: entry found, responding to zeppelin\n",
+ dev->name);
+ skb2 =
+ alloc_skb(sizeof(struct atmlec_msg),
+ GFP_ATOMIC);
+ if (skb2 == NULL) {
+ br_fdb_put_hook(f);
+ break;
+ }
+ skb2->len = sizeof(struct atmlec_msg);
+ memcpy(skb2->data, mesg,
+ sizeof(struct atmlec_msg));
+ atm_force_charge(priv->lecd, skb2->truesize);
+ sk = sk_atm(priv->lecd);
+ skb_queue_tail(&sk->sk_receive_queue, skb2);
+ sk->sk_data_ready(sk, skb2->len);
+ }
+ if (f != NULL)
+ br_fdb_put_hook(f);
+ }
#endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */
- }
- break;
- default:
- printk("%s: Unknown message type %d\n", dev->name, mesg->type);
- dev_kfree_skb(skb);
- return -EINVAL;
- }
- dev_kfree_skb(skb);
- return 0;
+ break;
+ default:
+ printk("%s: Unknown message type %d\n", dev->name, mesg->type);
+ dev_kfree_skb(skb);
+ return -EINVAL;
+ }
+ dev_kfree_skb(skb);
+ return 0;
}
-static void
-lec_atm_close(struct atm_vcc *vcc)
+static void lec_atm_close(struct atm_vcc *vcc)
{
- struct sk_buff *skb;
- struct net_device *dev = (struct net_device *)vcc->proto_data;
- struct lec_priv *priv = (struct lec_priv *)dev->priv;
+ struct sk_buff *skb;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
- priv->lecd = NULL;
- /* Do something needful? */
+ priv->lecd = NULL;
+ /* Do something needful? */
- netif_stop_queue(dev);
- lec_arp_destroy(priv);
+ netif_stop_queue(dev);
+ lec_arp_destroy(priv);
- if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
+ if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
printk("%s lec_atm_close: closing with messages pending\n",
- dev->name);
- while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
- atm_return(vcc, skb->truesize);
+ dev->name);
+ while ((skb = skb_dequeue(&sk_atm(vcc)->sk_receive_queue)) != NULL) {
+ atm_return(vcc, skb->truesize);
dev_kfree_skb(skb);
- }
-
+ }
+
printk("%s: Shut down!\n", dev->name);
- module_put(THIS_MODULE);
+ module_put(THIS_MODULE);
}
static struct atmdev_ops lecdev_ops = {
- .close = lec_atm_close,
- .send = lec_atm_send
+ .close = lec_atm_close,
+ .send = lec_atm_send
};
static struct atm_dev lecatm_dev = {
- .ops = &lecdev_ops,
- .type = "lec",
- .number = 999, /* dummy device number */
- .lock = SPIN_LOCK_UNLOCKED
+ .ops = &lecdev_ops,
+ .type = "lec",
+ .number = 999, /* dummy device number */
+ .lock = SPIN_LOCK_UNLOCKED
};
/*
* LANE2: new argument struct sk_buff *data contains
* the LE_ARP based TLVs introduced in the LANE2 spec
*/
-static int
-send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
- unsigned char *mac_addr, unsigned char *atm_addr,
- struct sk_buff *data)
+static int
+send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
+ unsigned char *mac_addr, unsigned char *atm_addr,
+ struct sk_buff *data)
{
struct sock *sk;
struct sk_buff *skb;
@@ -621,187 +654,193 @@ send_to_lecd(struct lec_priv *priv, atmlec_msg_type type,
return -1;
skb->len = sizeof(struct atmlec_msg);
mesg = (struct atmlec_msg *)skb->data;
- memset(mesg, 0, sizeof(struct atmlec_msg));
+ memset(mesg, 0, sizeof(struct atmlec_msg));
mesg->type = type;
- if (data != NULL)
- mesg->sizeoftlvs = data->len;
+ if (data != NULL)
+ mesg->sizeoftlvs = data->len;
if (mac_addr)
memcpy(&mesg->content.normal.mac_addr, mac_addr, ETH_ALEN);
- else
- mesg->content.normal.targetless_le_arp = 1;
+ else
+ mesg->content.normal.targetless_le_arp = 1;
if (atm_addr)
memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN);
- atm_force_charge(priv->lecd, skb->truesize);
+ atm_force_charge(priv->lecd, skb->truesize);
sk = sk_atm(priv->lecd);
skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk, skb->len);
+ sk->sk_data_ready(sk, skb->len);
- if (data != NULL) {
- DPRINTK("lec: about to send %d bytes of data\n", data->len);
- atm_force_charge(priv->lecd, data->truesize);
- skb_queue_tail(&sk->sk_receive_queue, data);
- sk->sk_data_ready(sk, skb->len);
- }
+ if (data != NULL) {
+ DPRINTK("lec: about to send %d bytes of data\n", data->len);
+ atm_force_charge(priv->lecd, data->truesize);
+ skb_queue_tail(&sk->sk_receive_queue, data);
+ sk->sk_data_ready(sk, skb->len);
+ }
- return 0;
+ return 0;
}
/* shamelessly stolen from drivers/net/net_init.c */
static int lec_change_mtu(struct net_device *dev, int new_mtu)
{
- if ((new_mtu < 68) || (new_mtu > 18190))
- return -EINVAL;
- dev->mtu = new_mtu;
- return 0;
+ if ((new_mtu < 68) || (new_mtu > 18190))
+ return -EINVAL;
+ dev->mtu = new_mtu;
+ return 0;
}
static void lec_set_multicast_list(struct net_device *dev)
{
- /* by default, all multicast frames arrive over the bus.
- * eventually support selective multicast service
- */
- return;
+ /*
+ * by default, all multicast frames arrive over the bus.
+ * eventually support selective multicast service
+ */
+ return;
}
-static void
-lec_init(struct net_device *dev)
+static void lec_init(struct net_device *dev)
{
- dev->change_mtu = lec_change_mtu;
- dev->open = lec_open;
- dev->stop = lec_close;
- dev->hard_start_xmit = lec_start_xmit;
+ dev->change_mtu = lec_change_mtu;
+ dev->open = lec_open;
+ dev->stop = lec_close;
+ dev->hard_start_xmit = lec_start_xmit;
dev->tx_timeout = lec_tx_timeout;
- dev->get_stats = lec_get_stats;
- dev->set_multicast_list = lec_set_multicast_list;
- dev->do_ioctl = NULL;
- printk("%s: Initialized!\n",dev->name);
- return;
+ dev->get_stats = lec_get_stats;
+ dev->set_multicast_list = lec_set_multicast_list;
+ dev->do_ioctl = NULL;
+ printk("%s: Initialized!\n", dev->name);
+ return;
}
static unsigned char lec_ctrl_magic[] = {
- 0xff,
- 0x00,
- 0x01,
- 0x01 };
+ 0xff,
+ 0x00,
+ 0x01,
+ 0x01
+};
#define LEC_DATA_DIRECT_8023 2
#define LEC_DATA_DIRECT_8025 3
static int lec_is_data_direct(struct atm_vcc *vcc)
-{
+{
return ((vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8023) ||
(vcc->sap.blli[0].l3.tr9577.snap[4] == LEC_DATA_DIRECT_8025));
-}
+}
-static void
-lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
+static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
- struct net_device *dev = (struct net_device *)vcc->proto_data;
- struct lec_priv *priv = (struct lec_priv *)dev->priv;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
#if DUMP_PACKETS >0
- int i=0;
- char buf[300];
+ int i = 0;
+ char buf[300];
- printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
- vcc->vpi, vcc->vci);
+ printk("%s: lec_push vcc vpi:%d vci:%d\n", dev->name,
+ vcc->vpi, vcc->vci);
#endif
- if (!skb) {
- DPRINTK("%s: null skb\n",dev->name);
- lec_vcc_close(priv, vcc);
- return;
- }
+ if (!skb) {
+ DPRINTK("%s: null skb\n", dev->name);
+ lec_vcc_close(priv, vcc);
+ return;
+ }
#if DUMP_PACKETS > 0
- printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
- skb->len, priv->lecid);
+ printk("%s: rcv datalen:%ld lecid:%4.4x\n", dev->name,
+ skb->len, priv->lecid);
#if DUMP_PACKETS >= 2
- for(i=0;i<skb->len && i <99;i++) {
- sprintf(buf+i*3,"%2.2x ",0xff&skb->data[i]);
- }
+ for (i = 0; i < skb->len && i < 99; i++) {
+ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
+ }
#elif DUMP_PACKETS >= 1
- for(i=0;i<skb->len && i < 30;i++) {
- sprintf(buf+i*3,"%2.2x ", 0xff&skb->data[i]);
- }
+ for (i = 0; i < skb->len && i < 30; i++) {
+ sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
+ }
#endif /* DUMP_PACKETS >= 1 */
- if (i==skb->len)
- printk("%s\n",buf);
- else
- printk("%s...\n",buf);
+ if (i == skb->len)
+ printk("%s\n", buf);
+ else
+ printk("%s...\n", buf);
#endif /* DUMP_PACKETS > 0 */
- if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/
+ if (memcmp(skb->data, lec_ctrl_magic, 4) == 0) { /* Control frame, to daemon */
struct sock *sk = sk_atm(vcc);
- DPRINTK("%s: To daemon\n",dev->name);
- skb_queue_tail(&sk->sk_receive_queue, skb);
- sk->sk_data_ready(sk, skb->len);
- } else { /* Data frame, queue to protocol handlers */
+ DPRINTK("%s: To daemon\n", dev->name);
+ skb_queue_tail(&sk->sk_receive_queue, skb);
+ sk->sk_data_ready(sk, skb->len);
+ } else { /* Data frame, queue to protocol handlers */
struct lec_arp_table *entry;
- unsigned char *src, *dst;
-
- atm_return(vcc,skb->truesize);
- if (*(uint16_t *)skb->data == htons(priv->lecid) ||
- !priv->lecd ||
- !(dev->flags & IFF_UP)) {
- /* Probably looping back, or if lecd is missing,
- lecd has gone down */
- DPRINTK("Ignoring frame...\n");
- dev_kfree_skb(skb);
- return;
- }
+ unsigned char *src, *dst;
+
+ atm_return(vcc, skb->truesize);
+ if (*(uint16_t *) skb->data == htons(priv->lecid) ||
+ !priv->lecd || !(dev->flags & IFF_UP)) {
+ /*
+ * Probably looping back, or if lecd is missing,
+ * lecd has gone down
+ */
+ DPRINTK("Ignoring frame...\n");
+ dev_kfree_skb(skb);
+ return;
+ }
#ifdef CONFIG_TR
- if (priv->is_trdev)
- dst = ((struct lecdatahdr_8025 *) skb->data)->h_dest;
- else
+ if (priv->is_trdev)
+ dst = ((struct lecdatahdr_8025 *)skb->data)->h_dest;
+ else
#endif
- dst = ((struct lecdatahdr_8023 *) skb->data)->h_dest;
+ dst = ((struct lecdatahdr_8023 *)skb->data)->h_dest;
- /* If this is a Data Direct VCC, and the VCC does not match
+ /*
+ * If this is a Data Direct VCC, and the VCC does not match
* the LE_ARP cache entry, delete the LE_ARP cache entry.
*/
spin_lock_irqsave(&priv->lec_arp_lock, flags);
if (lec_is_data_direct(vcc)) {
#ifdef CONFIG_TR
if (priv->is_trdev)
- src = ((struct lecdatahdr_8025 *) skb->data)->h_source;
+ src =
+ ((struct lecdatahdr_8025 *)skb->data)->
+ h_source;
else
#endif
- src = ((struct lecdatahdr_8023 *) skb->data)->h_source;
+ src =
+ ((struct lecdatahdr_8023 *)skb->data)->
+ h_source;
entry = lec_arp_find(priv, src);
if (entry && entry->vcc != vcc) {
lec_arp_remove(priv, entry);
- kfree(entry);
+ lec_arp_put(entry);
}
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- if (!(dst[0]&0x01) && /* Never filter Multi/Broadcast */
- !priv->is_proxy && /* Proxy wants all the packets */
+ if (!(dst[0] & 0x01) && /* Never filter Multi/Broadcast */
+ !priv->is_proxy && /* Proxy wants all the packets */
memcmp(dst, dev->dev_addr, dev->addr_len)) {
- dev_kfree_skb(skb);
- return;
- }
- if (priv->lec_arp_empty_ones) {
- lec_arp_check_empties(priv, vcc, skb);
- }
- skb->dev = dev;
- skb_pull(skb, 2); /* skip lec_id */
+ dev_kfree_skb(skb);
+ return;
+ }
+ if (!hlist_empty(&priv->lec_arp_empty_ones)) {
+ lec_arp_check_empties(priv, vcc, skb);
+ }
+ skb->dev = dev;
+ skb_pull(skb, 2); /* skip lec_id */
#ifdef CONFIG_TR
- if (priv->is_trdev) skb->protocol = tr_type_trans(skb, dev);
- else
+ if (priv->is_trdev)
+ skb->protocol = tr_type_trans(skb, dev);
+ else
#endif
- skb->protocol = eth_type_trans(skb, dev);
- priv->stats.rx_packets++;
- priv->stats.rx_bytes += skb->len;
- memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
- netif_rx(skb);
- }
+ skb->protocol = eth_type_trans(skb, dev);
+ priv->stats.rx_packets++;
+ priv->stats.rx_bytes += skb->len;
+ memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
+ netif_rx(skb);
+ }
}
-static void
-lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+static void lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
struct net_device *dev = skb->dev;
@@ -820,123 +859,121 @@ lec_pop(struct atm_vcc *vcc, struct sk_buff *skb)
}
}
-static int
-lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
+static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg)
{
struct lec_vcc_priv *vpriv;
- int bytes_left;
- struct atmlec_ioc ioc_data;
-
- /* Lecd must be up in this case */
- bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
- if (bytes_left != 0) {
- printk("lec: lec_vcc_attach, copy from user failed for %d bytes\n",
- bytes_left);
- }
- if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
- !dev_lec[ioc_data.dev_num])
- return -EINVAL;
+ int bytes_left;
+ struct atmlec_ioc ioc_data;
+
+ /* Lecd must be up in this case */
+ bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmlec_ioc));
+ if (bytes_left != 0) {
+ printk
+ ("lec: lec_vcc_attach, copy from user failed for %d bytes\n",
+ bytes_left);
+ }
+ if (ioc_data.dev_num < 0 || ioc_data.dev_num >= MAX_LEC_ITF ||
+ !dev_lec[ioc_data.dev_num])
+ return -EINVAL;
if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
return -ENOMEM;
vpriv->xoff = 0;
vpriv->old_pop = vcc->pop;
vcc->user_back = vpriv;
vcc->pop = lec_pop;
- lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
- &ioc_data, vcc, vcc->push);
- vcc->proto_data = dev_lec[ioc_data.dev_num];
- vcc->push = lec_push;
- return 0;
+ lec_vcc_added(dev_lec[ioc_data.dev_num]->priv,
+ &ioc_data, vcc, vcc->push);
+ vcc->proto_data = dev_lec[ioc_data.dev_num];
+ vcc->push = lec_push;
+ return 0;
}
-static int
-lec_mcast_attach(struct atm_vcc *vcc, int arg)
+static int lec_mcast_attach(struct atm_vcc *vcc, int arg)
{
- if (arg <0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
- return -EINVAL;
- vcc->proto_data = dev_lec[arg];
- return (lec_mcast_make((struct lec_priv*)dev_lec[arg]->priv, vcc));
+ if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg])
+ return -EINVAL;
+ vcc->proto_data = dev_lec[arg];
+ return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc));
}
/* Initialize device. */
-static int
-lecd_attach(struct atm_vcc *vcc, int arg)
-{
- int i;
- struct lec_priv *priv;
-
- if (arg<0)
- i = 0;
- else
- i = arg;
+static int lecd_attach(struct atm_vcc *vcc, int arg)
+{
+ int i;
+ struct lec_priv *priv;
+
+ if (arg < 0)
+ i = 0;
+ else
+ i = arg;
#ifdef CONFIG_TR
- if (arg >= MAX_LEC_ITF)
- return -EINVAL;
-#else /* Reserve the top NUM_TR_DEVS for TR */
- if (arg >= (MAX_LEC_ITF-NUM_TR_DEVS))
- return -EINVAL;
+ if (arg >= MAX_LEC_ITF)
+ return -EINVAL;
+#else /* Reserve the top NUM_TR_DEVS for TR */
+ if (arg >= (MAX_LEC_ITF - NUM_TR_DEVS))
+ return -EINVAL;
#endif
- if (!dev_lec[i]) {
- int is_trdev, size;
+ if (!dev_lec[i]) {
+ int is_trdev, size;
- is_trdev = 0;
- if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
- is_trdev = 1;
+ is_trdev = 0;
+ if (i >= (MAX_LEC_ITF - NUM_TR_DEVS))
+ is_trdev = 1;
- size = sizeof(struct lec_priv);
+ size = sizeof(struct lec_priv);
#ifdef CONFIG_TR
- if (is_trdev)
- dev_lec[i] = alloc_trdev(size);
- else
+ if (is_trdev)
+ dev_lec[i] = alloc_trdev(size);
+ else
#endif
- dev_lec[i] = alloc_etherdev(size);
- if (!dev_lec[i])
- return -ENOMEM;
- snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
- if (register_netdev(dev_lec[i])) {
- free_netdev(dev_lec[i]);
- return -EINVAL;
- }
-
- priv = dev_lec[i]->priv;
- priv->is_trdev = is_trdev;
- lec_init(dev_lec[i]);
- } else {
- priv = dev_lec[i]->priv;
- if (priv->lecd)
- return -EADDRINUSE;
- }
- lec_arp_init(priv);
- priv->itfnum = i; /* LANE2 addition */
- priv->lecd = vcc;
- vcc->dev = &lecatm_dev;
- vcc_insert_socket(sk_atm(vcc));
-
- vcc->proto_data = dev_lec[i];
- set_bit(ATM_VF_META,&vcc->flags);
- set_bit(ATM_VF_READY,&vcc->flags);
-
- /* Set default values to these variables */
- priv->maximum_unknown_frame_count = 1;
- priv->max_unknown_frame_time = (1*HZ);
- priv->vcc_timeout_period = (1200*HZ);
- priv->max_retry_count = 1;
- priv->aging_time = (300*HZ);
- priv->forward_delay_time = (15*HZ);
- priv->topology_change = 0;
- priv->arp_response_time = (1*HZ);
- priv->flush_timeout = (4*HZ);
- priv->path_switching_delay = (6*HZ);
-
- if (dev_lec[i]->flags & IFF_UP) {
- netif_start_queue(dev_lec[i]);
- }
- __module_get(THIS_MODULE);
- return i;
+ dev_lec[i] = alloc_etherdev(size);
+ if (!dev_lec[i])
+ return -ENOMEM;
+ snprintf(dev_lec[i]->name, IFNAMSIZ, "lec%d", i);
+ if (register_netdev(dev_lec[i])) {
+ free_netdev(dev_lec[i]);
+ return -EINVAL;
+ }
+
+ priv = dev_lec[i]->priv;
+ priv->is_trdev = is_trdev;
+ lec_init(dev_lec[i]);
+ } else {
+ priv = dev_lec[i]->priv;
+ if (priv->lecd)
+ return -EADDRINUSE;
+ }
+ lec_arp_init(priv);
+ priv->itfnum = i; /* LANE2 addition */
+ priv->lecd = vcc;
+ vcc->dev = &lecatm_dev;
+ vcc_insert_socket(sk_atm(vcc));
+
+ vcc->proto_data = dev_lec[i];
+ set_bit(ATM_VF_META, &vcc->flags);
+ set_bit(ATM_VF_READY, &vcc->flags);
+
+ /* Set default values to these variables */
+ priv->maximum_unknown_frame_count = 1;
+ priv->max_unknown_frame_time = (1 * HZ);
+ priv->vcc_timeout_period = (1200 * HZ);
+ priv->max_retry_count = 1;
+ priv->aging_time = (300 * HZ);
+ priv->forward_delay_time = (15 * HZ);
+ priv->topology_change = 0;
+ priv->arp_response_time = (1 * HZ);
+ priv->flush_timeout = (4 * HZ);
+ priv->path_switching_delay = (6 * HZ);
+
+ if (dev_lec[i]->flags & IFF_UP) {
+ netif_start_queue(dev_lec[i]);
+ }
+ __module_get(THIS_MODULE);
+ return i;
}
#ifdef CONFIG_PROC_FS
-static char* lec_arp_get_status_string(unsigned char status)
+static char *lec_arp_get_status_string(unsigned char status)
{
static char *lec_arp_status_string[] = {
"ESI_UNKNOWN ",
@@ -966,52 +1003,54 @@ static void lec_info(struct seq_file *seq, struct lec_arp_table *entry)
if (entry->vcc)
seq_printf(seq, "%3d %3d ", entry->vcc->vpi, entry->vcc->vci);
else
- seq_printf(seq, " ");
+ seq_printf(seq, " ");
if (entry->recv_vcc) {
seq_printf(seq, " %3d %3d", entry->recv_vcc->vpi,
entry->recv_vcc->vci);
- }
- seq_putc(seq, '\n');
+ }
+ seq_putc(seq, '\n');
}
-
struct lec_state {
unsigned long flags;
struct lec_priv *locked;
- struct lec_arp_table *entry;
+ struct hlist_node *node;
struct net_device *dev;
int itf;
int arp_table;
int misc_table;
};
-static void *lec_tbl_walk(struct lec_state *state, struct lec_arp_table *tbl,
+static void *lec_tbl_walk(struct lec_state *state, struct hlist_head *tbl,
loff_t *l)
{
- struct lec_arp_table *e = state->entry;
+ struct hlist_node *e = state->node;
+ struct lec_arp_table *tmp;
if (!e)
- e = tbl;
+ e = tbl->first;
if (e == (void *)1) {
- e = tbl;
+ e = tbl->first;
--*l;
}
- for (; e; e = e->next) {
+
+ hlist_for_each_entry_from(tmp, e, next) {
if (--*l < 0)
break;
}
- state->entry = e;
+ state->node = e;
+
return (*l < 0) ? state : NULL;
}
static void *lec_arp_walk(struct lec_state *state, loff_t *l,
- struct lec_priv *priv)
+ struct lec_priv *priv)
{
void *v = NULL;
int p;
for (p = state->arp_table; p < LEC_ARP_TABLE_SIZE; p++) {
- v = lec_tbl_walk(state, priv->lec_arp_tables[p], l);
+ v = lec_tbl_walk(state, &priv->lec_arp_tables[p], l);
if (v)
break;
}
@@ -1022,10 +1061,10 @@ static void *lec_arp_walk(struct lec_state *state, loff_t *l,
static void *lec_misc_walk(struct lec_state *state, loff_t *l,
struct lec_priv *priv)
{
- struct lec_arp_table *lec_misc_tables[] = {
- priv->lec_arp_empty_ones,
- priv->lec_no_forward,
- priv->mcast_fwds
+ struct hlist_head *lec_misc_tables[] = {
+ &priv->lec_arp_empty_ones,
+ &priv->lec_no_forward,
+ &priv->mcast_fwds
};
void *v = NULL;
int q;
@@ -1046,8 +1085,7 @@ static void *lec_priv_walk(struct lec_state *state, loff_t *l,
state->locked = priv;
spin_lock_irqsave(&priv->lec_arp_lock, state->flags);
}
- if (!lec_arp_walk(state, l, priv) &&
- !lec_misc_walk(state, l, priv)) {
+ if (!lec_arp_walk(state, l, priv) && !lec_misc_walk(state, l, priv)) {
spin_unlock_irqrestore(&priv->lec_arp_lock, state->flags);
state->locked = NULL;
/* Partial state reset for the next time we get called */
@@ -1081,7 +1119,7 @@ static void *lec_get_idx(struct lec_state *state, loff_t l)
if (v)
break;
}
- return v;
+ return v;
}
static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
@@ -1093,9 +1131,9 @@ static void *lec_seq_start(struct seq_file *seq, loff_t *pos)
state->locked = NULL;
state->arp_table = 0;
state->misc_table = 0;
- state->entry = (void *)1;
+ state->node = (void *)1;
- return *pos ? lec_get_idx(state, *pos) : (void*)1;
+ return *pos ? lec_get_idx(state, *pos) : (void *)1;
}
static void lec_seq_stop(struct seq_file *seq, void *v)
@@ -1120,27 +1158,28 @@ static void *lec_seq_next(struct seq_file *seq, void *v, loff_t *pos)
static int lec_seq_show(struct seq_file *seq, void *v)
{
- static char lec_banner[] = "Itf MAC ATM destination"
- " Status Flags "
- "VPI/VCI Recv VPI/VCI\n";
+ static char lec_banner[] = "Itf MAC ATM destination"
+ " Status Flags "
+ "VPI/VCI Recv VPI/VCI\n";
if (v == (void *)1)
seq_puts(seq, lec_banner);
else {
struct lec_state *state = seq->private;
- struct net_device *dev = state->dev;
+ struct net_device *dev = state->dev;
+ struct lec_arp_table *entry = hlist_entry(state->node, struct lec_arp_table, next);
seq_printf(seq, "%s ", dev->name);
- lec_info(seq, state->entry);
+ lec_info(seq, entry);
}
return 0;
}
static struct seq_operations lec_seq_ops = {
- .start = lec_seq_start,
- .next = lec_seq_next,
- .stop = lec_seq_stop,
- .show = lec_seq_show,
+ .start = lec_seq_start,
+ .next = lec_seq_next,
+ .stop = lec_seq_stop,
+ .show = lec_seq_show,
};
static int lec_seq_open(struct inode *inode, struct file *file)
@@ -1174,11 +1213,11 @@ static int lec_seq_release(struct inode *inode, struct file *file)
}
static struct file_operations lec_seq_fops = {
- .owner = THIS_MODULE,
- .open = lec_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = lec_seq_release,
+ .owner = THIS_MODULE,
+ .open = lec_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = lec_seq_release,
};
#endif
@@ -1186,38 +1225,38 @@ static int lane_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct atm_vcc *vcc = ATM_SD(sock);
int err = 0;
-
+
switch (cmd) {
- case ATMLEC_CTRL:
- case ATMLEC_MCAST:
- case ATMLEC_DATA:
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
- break;
- default:
- return -ENOIOCTLCMD;
+ case ATMLEC_CTRL:
+ case ATMLEC_MCAST:
+ case ATMLEC_DATA:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ break;
+ default:
+ return -ENOIOCTLCMD;
}
switch (cmd) {
- case ATMLEC_CTRL:
- err = lecd_attach(vcc, (int) arg);
- if (err >= 0)
- sock->state = SS_CONNECTED;
- break;
- case ATMLEC_MCAST:
- err = lec_mcast_attach(vcc, (int) arg);
- break;
- case ATMLEC_DATA:
- err = lec_vcc_attach(vcc, (void __user *) arg);
- break;
+ case ATMLEC_CTRL:
+ err = lecd_attach(vcc, (int)arg);
+ if (err >= 0)
+ sock->state = SS_CONNECTED;
+ break;
+ case ATMLEC_MCAST:
+ err = lec_mcast_attach(vcc, (int)arg);
+ break;
+ case ATMLEC_DATA:
+ err = lec_vcc_attach(vcc, (void __user *)arg);
+ break;
}
return err;
}
static struct atm_ioctl lane_ioctl_ops = {
- .owner = THIS_MODULE,
- .ioctl = lane_ioctl,
+ .owner = THIS_MODULE,
+ .ioctl = lane_ioctl,
};
static int __init lane_module_init(void)
@@ -1231,29 +1270,29 @@ static int __init lane_module_init(void)
#endif
register_atm_ioctl(&lane_ioctl_ops);
- printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
- return 0;
+ printk("lec.c: " __DATE__ " " __TIME__ " initialized\n");
+ return 0;
}
static void __exit lane_module_cleanup(void)
{
- int i;
- struct lec_priv *priv;
+ int i;
+ struct lec_priv *priv;
remove_proc_entry("lec", atm_proc_root);
deregister_atm_ioctl(&lane_ioctl_ops);
- for (i = 0; i < MAX_LEC_ITF; i++) {
- if (dev_lec[i] != NULL) {
- priv = (struct lec_priv *)dev_lec[i]->priv;
+ for (i = 0; i < MAX_LEC_ITF; i++) {
+ if (dev_lec[i] != NULL) {
+ priv = (struct lec_priv *)dev_lec[i]->priv;
unregister_netdev(dev_lec[i]);
- free_netdev(dev_lec[i]);
- dev_lec[i] = NULL;
- }
- }
+ free_netdev(dev_lec[i]);
+ dev_lec[i] = NULL;
+ }
+ }
- return;
+ return;
}
module_init(lane_module_init);
@@ -1267,34 +1306,34 @@ module_exit(lane_module_cleanup);
* If dst_mac == NULL, targetless LE_ARP will be sent
*/
static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
- u8 **tlvs, u32 *sizeoftlvs)
+ u8 **tlvs, u32 *sizeoftlvs)
{
unsigned long flags;
- struct lec_priv *priv = (struct lec_priv *)dev->priv;
- struct lec_arp_table *table;
- struct sk_buff *skb;
- int retval;
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+ struct lec_arp_table *table;
+ struct sk_buff *skb;
+ int retval;
- if (force == 0) {
+ if (force == 0) {
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- table = lec_arp_find(priv, dst_mac);
+ table = lec_arp_find(priv, dst_mac);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- if(table == NULL)
- return -1;
-
- *tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
- if (*tlvs == NULL)
- return -1;
-
- memcpy(*tlvs, table->tlvs, table->sizeoftlvs);
- *sizeoftlvs = table->sizeoftlvs;
-
- return 0;
- }
+ if (table == NULL)
+ return -1;
+
+ *tlvs = kmalloc(table->sizeoftlvs, GFP_ATOMIC);
+ if (*tlvs == NULL)
+ return -1;
+
+ memcpy(*tlvs, table->tlvs, table->sizeoftlvs);
+ *sizeoftlvs = table->sizeoftlvs;
+
+ return 0;
+ }
if (sizeoftlvs == NULL)
retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, NULL);
-
+
else {
skb = alloc_skb(*sizeoftlvs, GFP_ATOMIC);
if (skb == NULL)
@@ -1303,9 +1342,8 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
memcpy(skb->data, *tlvs, *sizeoftlvs);
retval = send_to_lecd(priv, l_arp_xmt, dst_mac, NULL, skb);
}
- return retval;
-}
-
+ return retval;
+}
/*
* LANE2: 3.1.4, LE_ASSOCIATE.request
@@ -1314,80 +1352,85 @@ static int lane2_resolve(struct net_device *dev, u8 *dst_mac, int force,
* Returns 1 for success, 0 for failure (out of memory)
*
*/
-static int lane2_associate_req (struct net_device *dev, u8 *lan_dst,
- u8 *tlvs, u32 sizeoftlvs)
+static int lane2_associate_req(struct net_device *dev, u8 *lan_dst,
+ u8 *tlvs, u32 sizeoftlvs)
{
- int retval;
- struct sk_buff *skb;
- struct lec_priv *priv = (struct lec_priv*)dev->priv;
-
- if (compare_ether_addr(lan_dst, dev->dev_addr))
- return (0); /* not our mac address */
-
- kfree(priv->tlvs); /* NULL if there was no previous association */
-
- priv->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
- if (priv->tlvs == NULL)
- return (0);
- priv->sizeoftlvs = sizeoftlvs;
- memcpy(priv->tlvs, tlvs, sizeoftlvs);
-
- skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
- if (skb == NULL)
- return 0;
- skb->len = sizeoftlvs;
- memcpy(skb->data, tlvs, sizeoftlvs);
- retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
- if (retval != 0)
- printk("lec.c: lane2_associate_req() failed\n");
- /* If the previous association has changed we must
- * somehow notify other LANE entities about the change
- */
- return (1);
+ int retval;
+ struct sk_buff *skb;
+ struct lec_priv *priv = (struct lec_priv *)dev->priv;
+
+ if (compare_ether_addr(lan_dst, dev->dev_addr))
+ return (0); /* not our mac address */
+
+ kfree(priv->tlvs); /* NULL if there was no previous association */
+
+ priv->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
+ if (priv->tlvs == NULL)
+ return (0);
+ priv->sizeoftlvs = sizeoftlvs;
+ memcpy(priv->tlvs, tlvs, sizeoftlvs);
+
+ skb = alloc_skb(sizeoftlvs, GFP_ATOMIC);
+ if (skb == NULL)
+ return 0;
+ skb->len = sizeoftlvs;
+ memcpy(skb->data, tlvs, sizeoftlvs);
+ retval = send_to_lecd(priv, l_associate_req, NULL, NULL, skb);
+ if (retval != 0)
+ printk("lec.c: lane2_associate_req() failed\n");
+ /*
+ * If the previous association has changed we must
+ * somehow notify other LANE entities about the change
+ */
+ return (1);
}
/*
* LANE2: 3.1.5, LE_ASSOCIATE.indication
*
*/
-static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
- u8 *tlvs, u32 sizeoftlvs)
+static void lane2_associate_ind(struct net_device *dev, u8 *mac_addr,
+ u8 *tlvs, u32 sizeoftlvs)
{
#if 0
- int i = 0;
+ int i = 0;
#endif
struct lec_priv *priv = (struct lec_priv *)dev->priv;
-#if 0 /* Why have the TLVs in LE_ARP entries since we do not use them? When you
- uncomment this code, make sure the TLVs get freed when entry is killed */
- struct lec_arp_table *entry = lec_arp_find(priv, mac_addr);
+#if 0 /*
+ * Why have the TLVs in LE_ARP entries
+ * since we do not use them? When you
+ * uncomment this code, make sure the
+ * TLVs get freed when entry is killed
+ */
+ struct lec_arp_table *entry = lec_arp_find(priv, mac_addr);
- if (entry == NULL)
- return; /* should not happen */
+ if (entry == NULL)
+ return; /* should not happen */
- kfree(entry->tlvs);
+ kfree(entry->tlvs);
- entry->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
- if (entry->tlvs == NULL)
- return;
+ entry->tlvs = kmalloc(sizeoftlvs, GFP_KERNEL);
+ if (entry->tlvs == NULL)
+ return;
- entry->sizeoftlvs = sizeoftlvs;
- memcpy(entry->tlvs, tlvs, sizeoftlvs);
+ entry->sizeoftlvs = sizeoftlvs;
+ memcpy(entry->tlvs, tlvs, sizeoftlvs);
#endif
#if 0
- printk("lec.c: lane2_associate_ind()\n");
- printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
- while (i < sizeoftlvs)
- printk("%02x ", tlvs[i++]);
-
- printk("\n");
+ printk("lec.c: lane2_associate_ind()\n");
+ printk("dump of tlvs, sizeoftlvs=%d\n", sizeoftlvs);
+ while (i < sizeoftlvs)
+ printk("%02x ", tlvs[i++]);
+
+ printk("\n");
#endif
- /* tell MPOA about the TLVs we saw */
- if (priv->lane2_ops && priv->lane2_ops->associate_indicator) {
- priv->lane2_ops->associate_indicator(dev, mac_addr,
- tlvs, sizeoftlvs);
- }
- return;
+ /* tell MPOA about the TLVs we saw */
+ if (priv->lane2_ops && priv->lane2_ops->associate_indicator) {
+ priv->lane2_ops->associate_indicator(dev, mac_addr,
+ tlvs, sizeoftlvs);
+ }
+ return;
}
/*
@@ -1395,7 +1438,6 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
*
* lec_arpc.c was added here when making
* lane client modular. October 1997
- *
*/
#include <linux/types.h>
@@ -1406,7 +1448,6 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
#include <linux/inetdevice.h>
#include <net/route.h>
-
#if 0
#define DPRINTK(format,args...)
/*
@@ -1417,7 +1458,7 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
#define LEC_ARP_REFRESH_INTERVAL (3*HZ)
-static void lec_arp_check_expire(unsigned long data);
+static void lec_arp_check_expire(void *data);
static void lec_arp_expire_arp(unsigned long data);
/*
@@ -1429,474 +1470,397 @@ static void lec_arp_expire_arp(unsigned long data);
/*
* Initialization of arp-cache
*/
-static void
-lec_arp_init(struct lec_priv *priv)
+static void lec_arp_init(struct lec_priv *priv)
{
- unsigned short i;
+ unsigned short i;
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- priv->lec_arp_tables[i] = NULL;
- }
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
+ }
+ INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
+ INIT_HLIST_HEAD(&priv->lec_no_forward);
+ INIT_HLIST_HEAD(&priv->mcast_fwds);
spin_lock_init(&priv->lec_arp_lock);
- init_timer(&priv->lec_arp_timer);
- priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
- priv->lec_arp_timer.data = (unsigned long)priv;
- priv->lec_arp_timer.function = lec_arp_check_expire;
- add_timer(&priv->lec_arp_timer);
+ INIT_WORK(&priv->lec_arp_work, lec_arp_check_expire, priv);
+ schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
}
-static void
-lec_arp_clear_vccs(struct lec_arp_table *entry)
+static void lec_arp_clear_vccs(struct lec_arp_table *entry)
{
- if (entry->vcc) {
+ if (entry->vcc) {
struct atm_vcc *vcc = entry->vcc;
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
- struct net_device *dev = (struct net_device*) vcc->proto_data;
+ struct net_device *dev = (struct net_device *)vcc->proto_data;
- vcc->pop = vpriv->old_pop;
+ vcc->pop = vpriv->old_pop;
if (vpriv->xoff)
netif_wake_queue(dev);
kfree(vpriv);
vcc->user_back = NULL;
- vcc->push = entry->old_push;
+ vcc->push = entry->old_push;
vcc_release_async(vcc, -EPIPE);
- vcc = NULL;
- }
- if (entry->recv_vcc) {
- entry->recv_vcc->push = entry->old_recv_push;
+ entry->vcc = NULL;
+ }
+ if (entry->recv_vcc) {
+ entry->recv_vcc->push = entry->old_recv_push;
vcc_release_async(entry->recv_vcc, -EPIPE);
- entry->recv_vcc = NULL;
- }
+ entry->recv_vcc = NULL;
+ }
}
/*
* Insert entry to lec_arp_table
* LANE2: Add to the end of the list to satisfy 8.1.13
*/
-static inline void
-lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add)
+static inline void
+lec_arp_add(struct lec_priv *priv, struct lec_arp_table *entry)
{
- unsigned short place;
- struct lec_arp_table *tmp;
-
- place = HASH(to_add->mac_addr[ETH_ALEN-1]);
- tmp = priv->lec_arp_tables[place];
- to_add->next = NULL;
- if (tmp == NULL)
- priv->lec_arp_tables[place] = to_add;
-
- else { /* add to the end */
- while (tmp->next)
- tmp = tmp->next;
- tmp->next = to_add;
- }
-
- DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
- 0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
- 0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
- 0xff&to_add->mac_addr[4], 0xff&to_add->mac_addr[5]);
+ struct hlist_head *tmp;
+
+ tmp = &priv->lec_arp_tables[HASH(entry->mac_addr[ETH_ALEN - 1])];
+ hlist_add_head(&entry->next, tmp);
+
+ DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+ 0xff & entry->mac_addr[0], 0xff & entry->mac_addr[1],
+ 0xff & entry->mac_addr[2], 0xff & entry->mac_addr[3],
+ 0xff & entry->mac_addr[4], 0xff & entry->mac_addr[5]);
}
/*
* Remove entry from lec_arp_table
*/
-static int
-lec_arp_remove(struct lec_priv *priv,
- struct lec_arp_table *to_remove)
+static int
+lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove)
{
- unsigned short place;
- struct lec_arp_table *tmp;
- int remove_vcc=1;
-
- if (!to_remove) {
- return -1;
- }
- place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
- tmp = priv->lec_arp_tables[place];
- if (tmp == to_remove) {
- priv->lec_arp_tables[place] = tmp->next;
- } else {
- while(tmp && tmp->next != to_remove) {
- tmp = tmp->next;
- }
- if (!tmp) {/* Entry was not found */
- return -1;
- }
- }
- tmp->next = to_remove->next;
- del_timer(&to_remove->timer);
-
- /* If this is the only MAC connected to this VCC, also tear down
- the VCC */
- if (to_remove->status >= ESI_FLUSH_PENDING) {
- /*
- * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
- */
- for(place = 0; place < LEC_ARP_TABLE_SIZE; place++) {
- for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) {
- if (memcmp(tmp->atm_addr, to_remove->atm_addr,
- ATM_ESA_LEN)==0) {
- remove_vcc=0;
- break;
- }
- }
- }
- if (remove_vcc)
- lec_arp_clear_vccs(to_remove);
- }
- skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
-
- DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
- 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
- 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
- 0xff&to_remove->mac_addr[4], 0xff&to_remove->mac_addr[5]);
- return 0;
+ struct hlist_node *node;
+ struct lec_arp_table *entry;
+ int i, remove_vcc = 1;
+
+ if (!to_remove) {
+ return -1;
+ }
+
+ hlist_del(&to_remove->next);
+ del_timer(&to_remove->timer);
+
+ /* If this is the only MAC connected to this VCC, also tear down the VCC */
+ if (to_remove->status >= ESI_FLUSH_PENDING) {
+ /*
+ * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT
+ */
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
+ if (memcmp(to_remove->atm_addr,
+ entry->atm_addr, ATM_ESA_LEN) == 0) {
+ remove_vcc = 0;
+ break;
+ }
+ }
+ }
+ if (remove_vcc)
+ lec_arp_clear_vccs(to_remove);
+ }
+ skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
+
+ DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+ 0xff & to_remove->mac_addr[0], 0xff & to_remove->mac_addr[1],
+ 0xff & to_remove->mac_addr[2], 0xff & to_remove->mac_addr[3],
+ 0xff & to_remove->mac_addr[4], 0xff & to_remove->mac_addr[5]);
+ return 0;
}
#if DEBUG_ARP_TABLE
-static char*
-get_status_string(unsigned char st)
+static char *get_status_string(unsigned char st)
{
- switch(st) {
- case ESI_UNKNOWN:
- return "ESI_UNKNOWN";
- case ESI_ARP_PENDING:
- return "ESI_ARP_PENDING";
- case ESI_VC_PENDING:
- return "ESI_VC_PENDING";
- case ESI_FLUSH_PENDING:
- return "ESI_FLUSH_PENDING";
- case ESI_FORWARD_DIRECT:
- return "ESI_FORWARD_DIRECT";
- default:
- return "<UNKNOWN>";
- }
+ switch (st) {
+ case ESI_UNKNOWN:
+ return "ESI_UNKNOWN";
+ case ESI_ARP_PENDING:
+ return "ESI_ARP_PENDING";
+ case ESI_VC_PENDING:
+ return "ESI_VC_PENDING";
+ case ESI_FLUSH_PENDING:
+ return "ESI_FLUSH_PENDING";
+ case ESI_FORWARD_DIRECT:
+ return "ESI_FORWARD_DIRECT";
+ default:
+ return "<UNKNOWN>";
+ }
}
-#endif
-static void
-dump_arp_table(struct lec_priv *priv)
+static void dump_arp_table(struct lec_priv *priv)
{
-#if DEBUG_ARP_TABLE
- int i,j, offset;
- struct lec_arp_table *rulla;
- char buf[1024];
- struct lec_arp_table **lec_arp_tables =
- (struct lec_arp_table **)priv->lec_arp_tables;
- struct lec_arp_table *lec_arp_empty_ones =
- (struct lec_arp_table *)priv->lec_arp_empty_ones;
- struct lec_arp_table *lec_no_forward =
- (struct lec_arp_table *)priv->lec_no_forward;
- struct lec_arp_table *mcast_fwds = priv->mcast_fwds;
-
-
- printk("Dump %p:\n",priv);
- for (i=0;i<LEC_ARP_TABLE_SIZE;i++) {
- rulla = lec_arp_tables[i];
- offset = 0;
- offset += sprintf(buf,"%d: %p\n",i, rulla);
- while (rulla) {
- offset += sprintf(buf+offset,"Mac:");
- for(j=0;j<ETH_ALEN;j++) {
- offset+=sprintf(buf+offset,
- "%2.2x ",
- rulla->mac_addr[j]&0xff);
- }
- offset +=sprintf(buf+offset,"Atm:");
- for(j=0;j<ATM_ESA_LEN;j++) {
- offset+=sprintf(buf+offset,
- "%2.2x ",
- rulla->atm_addr[j]&0xff);
- }
- offset+=sprintf(buf+offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc?rulla->vcc->vpi:0,
- rulla->vcc?rulla->vcc->vci:0,
- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
- rulla->recv_vcc?rulla->recv_vcc->vci:0,
- rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset+=sprintf(buf+offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- offset+=sprintf(buf+offset,"->%p\n",rulla->next);
- rulla = rulla->next;
- }
- printk("%s",buf);
- }
- rulla = lec_no_forward;
- if (rulla)
- printk("No forward\n");
- while(rulla) {
- offset=0;
- offset += sprintf(buf+offset,"Mac:");
- for(j=0;j<ETH_ALEN;j++) {
- offset+=sprintf(buf+offset,"%2.2x ",
- rulla->mac_addr[j]&0xff);
- }
- offset +=sprintf(buf+offset,"Atm:");
- for(j=0;j<ATM_ESA_LEN;j++) {
- offset+=sprintf(buf+offset,"%2.2x ",
- rulla->atm_addr[j]&0xff);
- }
- offset+=sprintf(buf+offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc?rulla->vcc->vpi:0,
- rulla->vcc?rulla->vcc->vci:0,
- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
- rulla->recv_vcc?rulla->recv_vcc->vci:0,
- rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset+=sprintf(buf+offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
- rulla = rulla->next;
- printk("%s",buf);
- }
- rulla = lec_arp_empty_ones;
- if (rulla)
- printk("Empty ones\n");
- while(rulla) {
- offset=0;
- offset += sprintf(buf+offset,"Mac:");
- for(j=0;j<ETH_ALEN;j++) {
- offset+=sprintf(buf+offset,"%2.2x ",
- rulla->mac_addr[j]&0xff);
- }
- offset +=sprintf(buf+offset,"Atm:");
- for(j=0;j<ATM_ESA_LEN;j++) {
- offset+=sprintf(buf+offset,"%2.2x ",
- rulla->atm_addr[j]&0xff);
- }
- offset+=sprintf(buf+offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc?rulla->vcc->vpi:0,
- rulla->vcc?rulla->vcc->vci:0,
- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
- rulla->recv_vcc?rulla->recv_vcc->vci:0,
- rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset+=sprintf(buf+offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
- rulla = rulla->next;
- printk("%s",buf);
- }
-
- rulla = mcast_fwds;
- if (rulla)
- printk("Multicast Forward VCCs\n");
- while(rulla) {
- offset=0;
- offset += sprintf(buf+offset,"Mac:");
- for(j=0;j<ETH_ALEN;j++) {
- offset+=sprintf(buf+offset,"%2.2x ",
- rulla->mac_addr[j]&0xff);
- }
- offset +=sprintf(buf+offset,"Atm:");
- for(j=0;j<ATM_ESA_LEN;j++) {
- offset+=sprintf(buf+offset,"%2.2x ",
- rulla->atm_addr[j]&0xff);
- }
- offset+=sprintf(buf+offset,
- "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
- rulla->vcc?rulla->vcc->vpi:0,
- rulla->vcc?rulla->vcc->vci:0,
- rulla->recv_vcc?rulla->recv_vcc->vpi:0,
- rulla->recv_vcc?rulla->recv_vcc->vci:0,
- rulla->last_used,
- rulla->timestamp, rulla->no_tries);
- offset+=sprintf(buf+offset,
- "Flags:%x, Packets_flooded:%x, Status: %s ",
- rulla->flags, rulla->packets_flooded,
- get_status_string(rulla->status));
- offset+=sprintf(buf+offset,"->%lx\n",(long)rulla->next);
- rulla = rulla->next;
- printk("%s",buf);
- }
+ struct hlist_node *node;
+ struct lec_arp_table *rulla;
+ char buf[256];
+ int i, j, offset;
+
+ printk("Dump %p:\n", priv);
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry(rulla, node, &priv->lec_arp_tables[i], next) {
+ offset = 0;
+ offset += sprintf(buf, "%d: %p\n", i, rulla);
+ offset += sprintf(buf + offset, "Mac:");
+ for (j = 0; j < ETH_ALEN; j++) {
+ offset += sprintf(buf + offset,
+ "%2.2x ",
+ rulla->mac_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset, "Atm:");
+ for (j = 0; j < ATM_ESA_LEN; j++) {
+ offset += sprintf(buf + offset,
+ "%2.2x ",
+ rulla->atm_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset,
+ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+ rulla->vcc ? rulla->vcc->vpi : 0,
+ rulla->vcc ? rulla->vcc->vci : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->
+ vpi : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->
+ vci : 0, rulla->last_used,
+ rulla->timestamp, rulla->no_tries);
+ offset +=
+ sprintf(buf + offset,
+ "Flags:%x, Packets_flooded:%x, Status: %s ",
+ rulla->flags, rulla->packets_flooded,
+ get_status_string(rulla->status));
+ printk("%s\n", buf);
+ }
+ }
+
+ if (!hlist_empty(&priv->lec_no_forward))
+ printk("No forward\n");
+ hlist_for_each_entry(rulla, node, &priv->lec_no_forward, next) {
+ offset = 0;
+ offset += sprintf(buf + offset, "Mac:");
+ for (j = 0; j < ETH_ALEN; j++) {
+ offset += sprintf(buf + offset, "%2.2x ",
+ rulla->mac_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset, "Atm:");
+ for (j = 0; j < ATM_ESA_LEN; j++) {
+ offset += sprintf(buf + offset, "%2.2x ",
+ rulla->atm_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset,
+ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+ rulla->vcc ? rulla->vcc->vpi : 0,
+ rulla->vcc ? rulla->vcc->vci : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
+ rulla->last_used,
+ rulla->timestamp, rulla->no_tries);
+ offset += sprintf(buf + offset,
+ "Flags:%x, Packets_flooded:%x, Status: %s ",
+ rulla->flags, rulla->packets_flooded,
+ get_status_string(rulla->status));
+ printk("%s\n", buf);
+ }
+
+ if (!hlist_empty(&priv->lec_arp_empty_ones))
+ printk("Empty ones\n");
+ hlist_for_each_entry(rulla, node, &priv->lec_arp_empty_ones, next) {
+ offset = 0;
+ offset += sprintf(buf + offset, "Mac:");
+ for (j = 0; j < ETH_ALEN; j++) {
+ offset += sprintf(buf + offset, "%2.2x ",
+ rulla->mac_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset, "Atm:");
+ for (j = 0; j < ATM_ESA_LEN; j++) {
+ offset += sprintf(buf + offset, "%2.2x ",
+ rulla->atm_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset,
+ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+ rulla->vcc ? rulla->vcc->vpi : 0,
+ rulla->vcc ? rulla->vcc->vci : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
+ rulla->last_used,
+ rulla->timestamp, rulla->no_tries);
+ offset += sprintf(buf + offset,
+ "Flags:%x, Packets_flooded:%x, Status: %s ",
+ rulla->flags, rulla->packets_flooded,
+ get_status_string(rulla->status));
+ printk("%s", buf);
+ }
+
+ if (!hlist_empty(&priv->mcast_fwds))
+ printk("Multicast Forward VCCs\n");
+ hlist_for_each_entry(rulla, node, &priv->mcast_fwds, next) {
+ offset = 0;
+ offset += sprintf(buf + offset, "Mac:");
+ for (j = 0; j < ETH_ALEN; j++) {
+ offset += sprintf(buf + offset, "%2.2x ",
+ rulla->mac_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset, "Atm:");
+ for (j = 0; j < ATM_ESA_LEN; j++) {
+ offset += sprintf(buf + offset, "%2.2x ",
+ rulla->atm_addr[j] & 0xff);
+ }
+ offset += sprintf(buf + offset,
+ "Vcc vpi:%d vci:%d, Recv_vcc vpi:%d vci:%d Last_used:%lx, Timestamp:%lx, No_tries:%d ",
+ rulla->vcc ? rulla->vcc->vpi : 0,
+ rulla->vcc ? rulla->vcc->vci : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->vpi : 0,
+ rulla->recv_vcc ? rulla->recv_vcc->vci : 0,
+ rulla->last_used,
+ rulla->timestamp, rulla->no_tries);
+ offset += sprintf(buf + offset,
+ "Flags:%x, Packets_flooded:%x, Status: %s ",
+ rulla->flags, rulla->packets_flooded,
+ get_status_string(rulla->status));
+ printk("%s\n", buf);
+ }
-#endif
}
+#else
+#define dump_arp_table(priv) do { } while (0)
+#endif
/*
* Destruction of arp-cache
*/
-static void
-lec_arp_destroy(struct lec_priv *priv)
+static void lec_arp_destroy(struct lec_priv *priv)
{
unsigned long flags;
- struct lec_arp_table *entry, *next;
- int i;
+ struct hlist_node *node, *next;
+ struct lec_arp_table *entry;
+ int i;
+
+ cancel_rearming_delayed_work(&priv->lec_arp_work);
- del_timer_sync(&priv->lec_arp_timer);
-
- /*
- * Remove all entries
- */
+ /*
+ * Remove all entries
+ */
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- for(entry = priv->lec_arp_tables[i]; entry != NULL; entry=next) {
- next = entry->next;
- lec_arp_remove(priv, entry);
- kfree(entry);
- }
- }
- entry = priv->lec_arp_empty_ones;
- while(entry) {
- next = entry->next;
- del_timer_sync(&entry->timer);
- lec_arp_clear_vccs(entry);
- kfree(entry);
- entry = next;
- }
- priv->lec_arp_empty_ones = NULL;
- entry = priv->lec_no_forward;
- while(entry) {
- next = entry->next;
- del_timer_sync(&entry->timer);
- lec_arp_clear_vccs(entry);
- kfree(entry);
- entry = next;
- }
- priv->lec_no_forward = NULL;
- entry = priv->mcast_fwds;
- while(entry) {
- next = entry->next;
- /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
- lec_arp_clear_vccs(entry);
- kfree(entry);
- entry = next;
- }
- priv->mcast_fwds = NULL;
- priv->mcast_vcc = NULL;
- memset(priv->lec_arp_tables, 0,
- sizeof(struct lec_arp_table *) * LEC_ARP_TABLE_SIZE);
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
+ lec_arp_remove(priv, entry);
+ lec_arp_put(entry);
+ }
+ INIT_HLIST_HEAD(&priv->lec_arp_tables[i]);
+ }
+
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+ del_timer_sync(&entry->timer);
+ lec_arp_clear_vccs(entry);
+ hlist_del(&entry->next);
+ lec_arp_put(entry);
+ }
+ INIT_HLIST_HEAD(&priv->lec_arp_empty_ones);
+
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {
+ del_timer_sync(&entry->timer);
+ lec_arp_clear_vccs(entry);
+ hlist_del(&entry->next);
+ lec_arp_put(entry);
+ }
+ INIT_HLIST_HEAD(&priv->lec_no_forward);
+
+ hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
+ /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
+ lec_arp_clear_vccs(entry);
+ hlist_del(&entry->next);
+ lec_arp_put(entry);
+ }
+ INIT_HLIST_HEAD(&priv->mcast_fwds);
+ priv->mcast_vcc = NULL;
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
-
/*
* Find entry by mac_address
*/
-static struct lec_arp_table*
-lec_arp_find(struct lec_priv *priv,
- unsigned char *mac_addr)
+static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
+ unsigned char *mac_addr)
{
- unsigned short place;
- struct lec_arp_table *to_return;
-
- DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
- mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff,
- mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff);
- place = HASH(mac_addr[ETH_ALEN-1]);
-
- to_return = priv->lec_arp_tables[place];
- while(to_return) {
- if (!compare_ether_addr(mac_addr, to_return->mac_addr)) {
- return to_return;
- }
- to_return = to_return->next;
- }
- return NULL;
+ struct hlist_node *node;
+ struct hlist_head *head;
+ struct lec_arp_table *entry;
+
+ DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
+ mac_addr[0] & 0xff, mac_addr[1] & 0xff, mac_addr[2] & 0xff,
+ mac_addr[3] & 0xff, mac_addr[4] & 0xff, mac_addr[5] & 0xff);
+
+ head = &priv->lec_arp_tables[HASH(mac_addr[ETH_ALEN - 1])];
+ hlist_for_each_entry(entry, node, head, next) {
+ if (!compare_ether_addr(mac_addr, entry->mac_addr)) {
+ return entry;
+ }
+ }
+ return NULL;
}
-static struct lec_arp_table*
-make_entry(struct lec_priv *priv, unsigned char *mac_addr)
+static struct lec_arp_table *make_entry(struct lec_priv *priv,
+ unsigned char *mac_addr)
{
- struct lec_arp_table *to_return;
-
- to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
- if (!to_return) {
- printk("LEC: Arp entry kmalloc failed\n");
- return NULL;
- }
- memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
- init_timer(&to_return->timer);
- to_return->timer.function = lec_arp_expire_arp;
- to_return->timer.data = (unsigned long) to_return;
- to_return->last_used = jiffies;
- to_return->priv = priv;
- skb_queue_head_init(&to_return->tx_wait);
- return to_return;
+ struct lec_arp_table *to_return;
+
+ to_return = kzalloc(sizeof(struct lec_arp_table), GFP_ATOMIC);
+ if (!to_return) {
+ printk("LEC: Arp entry kmalloc failed\n");
+ return NULL;
+ }
+ memcpy(to_return->mac_addr, mac_addr, ETH_ALEN);
+ INIT_HLIST_NODE(&to_return->next);
+ init_timer(&to_return->timer);
+ to_return->timer.function = lec_arp_expire_arp;
+ to_return->timer.data = (unsigned long)to_return;
+ to_return->last_used = jiffies;
+ to_return->priv = priv;
+ skb_queue_head_init(&to_return->tx_wait);
+ atomic_set(&to_return->usage, 1);
+ return to_return;
}
-/*
- *
- * Arp sent timer expired
- *
- */
-static void
-lec_arp_expire_arp(unsigned long data)
+/* Arp sent timer expired */
+static void lec_arp_expire_arp(unsigned long data)
{
- struct lec_arp_table *entry;
-
- entry = (struct lec_arp_table *)data;
-
- DPRINTK("lec_arp_expire_arp\n");
- if (entry->status == ESI_ARP_PENDING) {
- if (entry->no_tries <= entry->priv->max_retry_count) {
- if (entry->is_rdesc)
- send_to_lecd(entry->priv, l_rdesc_arp_xmt, entry->mac_addr, NULL, NULL);
- else
- send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL);
- entry->no_tries++;
- }
- mod_timer(&entry->timer, jiffies + (1*HZ));
- }
+ struct lec_arp_table *entry;
+
+ entry = (struct lec_arp_table *)data;
+
+ DPRINTK("lec_arp_expire_arp\n");
+ if (entry->status == ESI_ARP_PENDING) {
+ if (entry->no_tries <= entry->priv->max_retry_count) {
+ if (entry->is_rdesc)
+ send_to_lecd(entry->priv, l_rdesc_arp_xmt,
+ entry->mac_addr, NULL, NULL);
+ else
+ send_to_lecd(entry->priv, l_arp_xmt,
+ entry->mac_addr, NULL, NULL);
+ entry->no_tries++;
+ }
+ mod_timer(&entry->timer, jiffies + (1 * HZ));
+ }
}
-/*
- *
- * Unknown/unused vcc expire, remove associated entry
- *
- */
-static void
-lec_arp_expire_vcc(unsigned long data)
+/* Unknown/unused vcc expire, remove associated entry */
+static void lec_arp_expire_vcc(unsigned long data)
{
unsigned long flags;
- struct lec_arp_table *to_remove = (struct lec_arp_table*)data;
- struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
- struct lec_arp_table *entry = NULL;
+ struct lec_arp_table *to_remove = (struct lec_arp_table *)data;
+ struct lec_priv *priv = (struct lec_priv *)to_remove->priv;
- del_timer(&to_remove->timer);
+ del_timer(&to_remove->timer);
- DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",
- to_remove, priv,
- to_remove->vcc?to_remove->recv_vcc->vpi:0,
- to_remove->vcc?to_remove->recv_vcc->vci:0);
- DPRINTK("eo:%p nf:%p\n",priv->lec_arp_empty_ones,priv->lec_no_forward);
+ DPRINTK("LEC_ARP %p %p: lec_arp_expire_vcc vpi:%d vci:%d\n",
+ to_remove, priv,
+ to_remove->vcc ? to_remove->recv_vcc->vpi : 0,
+ to_remove->vcc ? to_remove->recv_vcc->vci : 0);
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- if (to_remove == priv->lec_arp_empty_ones)
- priv->lec_arp_empty_ones = to_remove->next;
- else {
- entry = priv->lec_arp_empty_ones;
- while (entry && entry->next != to_remove)
- entry = entry->next;
- if (entry)
- entry->next = to_remove->next;
- }
- if (!entry) {
- if (to_remove == priv->lec_no_forward) {
- priv->lec_no_forward = to_remove->next;
- } else {
- entry = priv->lec_no_forward;
- while (entry && entry->next != to_remove)
- entry = entry->next;
- if (entry)
- entry->next = to_remove->next;
- }
- }
+ hlist_del(&to_remove->next);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- lec_arp_clear_vccs(to_remove);
- kfree(to_remove);
+ lec_arp_clear_vccs(to_remove);
+ lec_arp_put(to_remove);
}
/*
@@ -1915,158 +1879,171 @@ lec_arp_expire_vcc(unsigned long data)
* to ESI_FORWARD_DIRECT. This causes the flush period to end
* regardless of the progress of the flush protocol.
*/
-static void
-lec_arp_check_expire(unsigned long data)
+static void lec_arp_check_expire(void *data)
{
unsigned long flags;
- struct lec_priv *priv = (struct lec_priv *)data;
- struct lec_arp_table *entry, *next;
- unsigned long now;
- unsigned long time_to_check;
- int i;
-
- DPRINTK("lec_arp_check_expire %p\n",priv);
- DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
- priv->lec_no_forward);
+ struct lec_priv *priv = data;
+ struct hlist_node *node, *next;
+ struct lec_arp_table *entry;
+ unsigned long now;
+ unsigned long time_to_check;
+ int i;
+
+ DPRINTK("lec_arp_check_expire %p\n", priv);
now = jiffies;
+restart:
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- for(entry = priv->lec_arp_tables[i]; entry != NULL; ) {
- if ((entry->flags) & LEC_REMOTE_FLAG &&
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
+ if ((entry->flags) & LEC_REMOTE_FLAG &&
priv->topology_change)
time_to_check = priv->forward_delay_time;
else
time_to_check = priv->aging_time;
DPRINTK("About to expire: %lx - %lx > %lx\n",
- now,entry->last_used, time_to_check);
- if( time_after(now, entry->last_used+
- time_to_check) &&
- !(entry->flags & LEC_PERMANENT_FLAG) &&
- !(entry->mac_addr[0] & 0x01) ) { /* LANE2: 7.1.20 */
+ now, entry->last_used, time_to_check);
+ if (time_after(now, entry->last_used + time_to_check)
+ && !(entry->flags & LEC_PERMANENT_FLAG)
+ && !(entry->mac_addr[0] & 0x01)) { /* LANE2: 7.1.20 */
/* Remove entry */
DPRINTK("LEC:Entry timed out\n");
- next = entry->next;
lec_arp_remove(priv, entry);
- kfree(entry);
- entry = next;
+ lec_arp_put(entry);
} else {
/* Something else */
if ((entry->status == ESI_VC_PENDING ||
- entry->status == ESI_ARP_PENDING)
+ entry->status == ESI_ARP_PENDING)
&& time_after_eq(now,
- entry->timestamp +
- priv->max_unknown_frame_time)) {
+ entry->timestamp +
+ priv->
+ max_unknown_frame_time)) {
entry->timestamp = jiffies;
entry->packets_flooded = 0;
if (entry->status == ESI_VC_PENDING)
- send_to_lecd(priv, l_svc_setup, entry->mac_addr, entry->atm_addr, NULL);
+ send_to_lecd(priv, l_svc_setup,
+ entry->mac_addr,
+ entry->atm_addr,
+ NULL);
}
- if (entry->status == ESI_FLUSH_PENDING
- &&
- time_after_eq(now, entry->timestamp+
- priv->path_switching_delay)) {
+ if (entry->status == ESI_FLUSH_PENDING
+ &&
+ time_after_eq(now, entry->timestamp +
+ priv->path_switching_delay)) {
struct sk_buff *skb;
+ struct atm_vcc *vcc = entry->vcc;
+ lec_arp_hold(entry);
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
- lec_send(entry->vcc, skb, entry->priv);
+ lec_send(vcc, skb, entry->priv);
entry->last_used = jiffies;
- entry->status =
- ESI_FORWARD_DIRECT;
+ entry->status = ESI_FORWARD_DIRECT;
+ lec_arp_put(entry);
+ goto restart;
}
- entry = entry->next;
}
}
}
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL);
+ schedule_delayed_work(&priv->lec_arp_work, LEC_ARP_REFRESH_INTERVAL);
}
+
/*
* Try to find vcc where mac_address is attached.
*
*/
-static struct atm_vcc*
-lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find,
- int is_rdesc, struct lec_arp_table **ret_entry)
+static struct atm_vcc *lec_arp_resolve(struct lec_priv *priv,
+ unsigned char *mac_to_find, int is_rdesc,
+ struct lec_arp_table **ret_entry)
{
unsigned long flags;
- struct lec_arp_table *entry;
+ struct lec_arp_table *entry;
struct atm_vcc *found;
- if (mac_to_find[0] & 0x01) {
- switch (priv->lane_version) {
- case 1:
- return priv->mcast_vcc;
- break;
- case 2: /* LANE2 wants arp for multicast addresses */
- if (!compare_ether_addr(mac_to_find, bus_mac))
- return priv->mcast_vcc;
- break;
- default:
- break;
- }
- }
+ if (mac_to_find[0] & 0x01) {
+ switch (priv->lane_version) {
+ case 1:
+ return priv->mcast_vcc;
+ break;
+ case 2: /* LANE2 wants arp for multicast addresses */
+ if (!compare_ether_addr(mac_to_find, bus_mac))
+ return priv->mcast_vcc;
+ break;
+ default:
+ break;
+ }
+ }
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- entry = lec_arp_find(priv, mac_to_find);
-
- if (entry) {
- if (entry->status == ESI_FORWARD_DIRECT) {
- /* Connection Ok */
- entry->last_used = jiffies;
- *ret_entry = entry;
- found = entry->vcc;
+ entry = lec_arp_find(priv, mac_to_find);
+
+ if (entry) {
+ if (entry->status == ESI_FORWARD_DIRECT) {
+ /* Connection Ok */
+ entry->last_used = jiffies;
+ lec_arp_hold(entry);
+ *ret_entry = entry;
+ found = entry->vcc;
goto out;
- }
- /* If the LE_ARP cache entry is still pending, reset count to 0
+ }
+ /*
+ * If the LE_ARP cache entry is still pending, reset count to 0
* so another LE_ARP request can be made for this frame.
*/
if (entry->status == ESI_ARP_PENDING) {
entry->no_tries = 0;
}
- /* Data direct VC not yet set up, check to see if the unknown
- frame count is greater than the limit. If the limit has
- not been reached, allow the caller to send packet to
- BUS. */
- if (entry->status != ESI_FLUSH_PENDING &&
- entry->packets_flooded<priv->maximum_unknown_frame_count) {
- entry->packets_flooded++;
- DPRINTK("LEC_ARP: Flooding..\n");
- found = priv->mcast_vcc;
+ /*
+ * Data direct VC not yet set up, check to see if the unknown
+ * frame count is greater than the limit. If the limit has
+ * not been reached, allow the caller to send packet to
+ * BUS.
+ */
+ if (entry->status != ESI_FLUSH_PENDING &&
+ entry->packets_flooded <
+ priv->maximum_unknown_frame_count) {
+ entry->packets_flooded++;
+ DPRINTK("LEC_ARP: Flooding..\n");
+ found = priv->mcast_vcc;
goto out;
- }
- /* We got here because entry->status == ESI_FLUSH_PENDING
+ }
+ /*
+ * We got here because entry->status == ESI_FLUSH_PENDING
* or BUS flood limit was reached for an entry which is
* in ESI_ARP_PENDING or ESI_VC_PENDING state.
*/
- *ret_entry = entry;
- DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status, entry->vcc);
- found = NULL;
- } else {
- /* No matching entry was found */
- entry = make_entry(priv, mac_to_find);
- DPRINTK("LEC_ARP: Making entry\n");
- if (!entry) {
- found = priv->mcast_vcc;
+ lec_arp_hold(entry);
+ *ret_entry = entry;
+ DPRINTK("lec: entry->status %d entry->vcc %p\n", entry->status,
+ entry->vcc);
+ found = NULL;
+ } else {
+ /* No matching entry was found */
+ entry = make_entry(priv, mac_to_find);
+ DPRINTK("LEC_ARP: Making entry\n");
+ if (!entry) {
+ found = priv->mcast_vcc;
goto out;
- }
- lec_arp_add(priv, entry);
- /* We want arp-request(s) to be sent */
- entry->packets_flooded =1;
- entry->status = ESI_ARP_PENDING;
- entry->no_tries = 1;
- entry->last_used = entry->timestamp = jiffies;
- entry->is_rdesc = is_rdesc;
- if (entry->is_rdesc)
- send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL, NULL);
- else
- send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
- entry->timer.expires = jiffies + (1*HZ);
- entry->timer.function = lec_arp_expire_arp;
- add_timer(&entry->timer);
- found = priv->mcast_vcc;
- }
+ }
+ lec_arp_add(priv, entry);
+ /* We want arp-request(s) to be sent */
+ entry->packets_flooded = 1;
+ entry->status = ESI_ARP_PENDING;
+ entry->no_tries = 1;
+ entry->last_used = entry->timestamp = jiffies;
+ entry->is_rdesc = is_rdesc;
+ if (entry->is_rdesc)
+ send_to_lecd(priv, l_rdesc_arp_xmt, mac_to_find, NULL,
+ NULL);
+ else
+ send_to_lecd(priv, l_arp_xmt, mac_to_find, NULL, NULL);
+ entry->timer.expires = jiffies + (1 * HZ);
+ entry->timer.function = lec_arp_expire_arp;
+ add_timer(&entry->timer);
+ found = priv->mcast_vcc;
+ }
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
@@ -2074,30 +2051,30 @@ out:
}
static int
-lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
- unsigned long permanent)
+lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
+ unsigned long permanent)
{
unsigned long flags;
- struct lec_arp_table *entry, *next;
- int i;
+ struct hlist_node *node, *next;
+ struct lec_arp_table *entry;
+ int i;
- DPRINTK("lec_addr_delete\n");
+ DPRINTK("lec_addr_delete\n");
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- for(entry = priv->lec_arp_tables[i]; entry != NULL; entry = next) {
- next = entry->next;
- if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
- && (permanent ||
- !(entry->flags & LEC_PERMANENT_FLAG))) {
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
+ if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)
+ && (permanent ||
+ !(entry->flags & LEC_PERMANENT_FLAG))) {
lec_arp_remove(priv, entry);
- kfree(entry);
- }
+ lec_arp_put(entry);
+ }
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- return 0;
- }
- }
+ return 0;
+ }
+ }
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- return -1;
+ return -1;
}
/*
@@ -2105,109 +2082,98 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
*/
static void
lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
- unsigned char *atm_addr, unsigned long remoteflag,
- unsigned int targetless_le_arp)
+ unsigned char *atm_addr, unsigned long remoteflag,
+ unsigned int targetless_le_arp)
{
unsigned long flags;
- struct lec_arp_table *entry, *tmp;
- int i;
+ struct hlist_node *node, *next;
+ struct lec_arp_table *entry, *tmp;
+ int i;
- DPRINTK("lec:%s", (targetless_le_arp) ? "targetless ": " ");
- DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
- mac_addr[0],mac_addr[1],mac_addr[2],mac_addr[3],
- mac_addr[4],mac_addr[5]);
+ DPRINTK("lec:%s", (targetless_le_arp) ? "targetless " : " ");
+ DPRINTK("lec_arp_update mac:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+ mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
+ mac_addr[4], mac_addr[5]);
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- entry = lec_arp_find(priv, mac_addr);
- if (entry == NULL && targetless_le_arp)
- goto out; /* LANE2: ignore targetless LE_ARPs for which
- * we have no entry in the cache. 7.1.30
- */
- if (priv->lec_arp_empty_ones) {
- entry = priv->lec_arp_empty_ones;
- if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) {
- priv->lec_arp_empty_ones = entry->next;
- } else {
- while(entry->next && memcmp(entry->next->atm_addr,
- atm_addr, ATM_ESA_LEN))
- entry = entry->next;
- if (entry->next) {
- tmp = entry;
- entry = entry->next;
- tmp->next = entry->next;
- } else
- entry = NULL;
-
- }
- if (entry) {
- del_timer(&entry->timer);
- tmp = lec_arp_find(priv, mac_addr);
- if (tmp) {
- del_timer(&tmp->timer);
- tmp->status = ESI_FORWARD_DIRECT;
- memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
- tmp->vcc = entry->vcc;
- tmp->old_push = entry->old_push;
- tmp->last_used = jiffies;
- del_timer(&entry->timer);
- kfree(entry);
- entry=tmp;
- } else {
- entry->status = ESI_FORWARD_DIRECT;
- memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
- entry->last_used = jiffies;
- lec_arp_add(priv, entry);
- }
- if (remoteflag)
- entry->flags|=LEC_REMOTE_FLAG;
- else
- entry->flags&=~LEC_REMOTE_FLAG;
- DPRINTK("After update\n");
- dump_arp_table(priv);
- goto out;
- }
- }
- entry = lec_arp_find(priv, mac_addr);
- if (!entry) {
- entry = make_entry(priv, mac_addr);
- if (!entry)
+ entry = lec_arp_find(priv, mac_addr);
+ if (entry == NULL && targetless_le_arp)
+ goto out; /*
+ * LANE2: ignore targetless LE_ARPs for which
+ * we have no entry in the cache. 7.1.30
+ */
+ if (!hlist_empty(&priv->lec_arp_empty_ones)) {
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+ if (memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN) == 0) {
+ hlist_del(&entry->next);
+ del_timer(&entry->timer);
+ tmp = lec_arp_find(priv, mac_addr);
+ if (tmp) {
+ del_timer(&tmp->timer);
+ tmp->status = ESI_FORWARD_DIRECT;
+ memcpy(tmp->atm_addr, atm_addr, ATM_ESA_LEN);
+ tmp->vcc = entry->vcc;
+ tmp->old_push = entry->old_push;
+ tmp->last_used = jiffies;
+ del_timer(&entry->timer);
+ lec_arp_put(entry);
+ entry = tmp;
+ } else {
+ entry->status = ESI_FORWARD_DIRECT;
+ memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
+ entry->last_used = jiffies;
+ lec_arp_add(priv, entry);
+ }
+ if (remoteflag)
+ entry->flags |= LEC_REMOTE_FLAG;
+ else
+ entry->flags &= ~LEC_REMOTE_FLAG;
+ DPRINTK("After update\n");
+ dump_arp_table(priv);
+ goto out;
+ }
+ }
+ }
+
+ entry = lec_arp_find(priv, mac_addr);
+ if (!entry) {
+ entry = make_entry(priv, mac_addr);
+ if (!entry)
goto out;
- entry->status = ESI_UNKNOWN;
- lec_arp_add(priv, entry);
- /* Temporary, changes before end of function */
- }
- memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
- del_timer(&entry->timer);
- for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- for(tmp = priv->lec_arp_tables[i]; tmp; tmp=tmp->next) {
- if (entry != tmp &&
- !memcmp(tmp->atm_addr, atm_addr,
- ATM_ESA_LEN)) {
- /* Vcc to this host exists */
- if (tmp->status > ESI_VC_PENDING) {
- /*
- * ESI_FLUSH_PENDING,
- * ESI_FORWARD_DIRECT
- */
- entry->vcc = tmp->vcc;
- entry->old_push=tmp->old_push;
- }
- entry->status=tmp->status;
- break;
- }
- }
- }
- if (remoteflag)
- entry->flags|=LEC_REMOTE_FLAG;
- else
- entry->flags&=~LEC_REMOTE_FLAG;
- if (entry->status == ESI_ARP_PENDING ||
- entry->status == ESI_UNKNOWN) {
- entry->status = ESI_VC_PENDING;
- send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
- }
- DPRINTK("After update2\n");
- dump_arp_table(priv);
+ entry->status = ESI_UNKNOWN;
+ lec_arp_add(priv, entry);
+ /* Temporary, changes before end of function */
+ }
+ memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
+ del_timer(&entry->timer);
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry(tmp, node, &priv->lec_arp_tables[i], next) {
+ if (entry != tmp &&
+ !memcmp(tmp->atm_addr, atm_addr, ATM_ESA_LEN)) {
+ /* Vcc to this host exists */
+ if (tmp->status > ESI_VC_PENDING) {
+ /*
+ * ESI_FLUSH_PENDING,
+ * ESI_FORWARD_DIRECT
+ */
+ entry->vcc = tmp->vcc;
+ entry->old_push = tmp->old_push;
+ }
+ entry->status = tmp->status;
+ break;
+ }
+ }
+ }
+ if (remoteflag)
+ entry->flags |= LEC_REMOTE_FLAG;
+ else
+ entry->flags &= ~LEC_REMOTE_FLAG;
+ if (entry->status == ESI_ARP_PENDING || entry->status == ESI_UNKNOWN) {
+ entry->status = ESI_VC_PENDING;
+ send_to_lecd(priv, l_svc_setup, entry->mac_addr, atm_addr, NULL);
+ }
+ DPRINTK("After update2\n");
+ dump_arp_table(priv);
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
@@ -2217,299 +2183,299 @@ out:
*/
static void
lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
- struct atm_vcc *vcc,
- void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb))
+ struct atm_vcc *vcc,
+ void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb))
{
unsigned long flags;
- struct lec_arp_table *entry;
- int i, found_entry=0;
+ struct hlist_node *node;
+ struct lec_arp_table *entry;
+ int i, found_entry = 0;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- if (ioc_data->receive == 2) {
- /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
+ if (ioc_data->receive == 2) {
+ /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
- DPRINTK("LEC_ARP: Attaching mcast forward\n");
+ DPRINTK("LEC_ARP: Attaching mcast forward\n");
#if 0
- entry = lec_arp_find(priv, bus_mac);
- if (!entry) {
- printk("LEC_ARP: Multicast entry not found!\n");
+ entry = lec_arp_find(priv, bus_mac);
+ if (!entry) {
+ printk("LEC_ARP: Multicast entry not found!\n");
goto out;
- }
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- entry->recv_vcc = vcc;
- entry->old_recv_push = old_push;
+ }
+ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+ entry->recv_vcc = vcc;
+ entry->old_recv_push = old_push;
#endif
- entry = make_entry(priv, bus_mac);
- if (entry == NULL)
+ entry = make_entry(priv, bus_mac);
+ if (entry == NULL)
goto out;
- del_timer(&entry->timer);
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- entry->recv_vcc = vcc;
- entry->old_recv_push = old_push;
- entry->next = priv->mcast_fwds;
- priv->mcast_fwds = entry;
- goto out;
- } else if (ioc_data->receive == 1) {
- /* Vcc which we don't want to make default vcc, attach it
- anyway. */
- DPRINTK("LEC_ARP:Attaching data direct, not default :%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
- ioc_data->atm_addr[0],ioc_data->atm_addr[1],
- ioc_data->atm_addr[2],ioc_data->atm_addr[3],
- ioc_data->atm_addr[4],ioc_data->atm_addr[5],
- ioc_data->atm_addr[6],ioc_data->atm_addr[7],
- ioc_data->atm_addr[8],ioc_data->atm_addr[9],
- ioc_data->atm_addr[10],ioc_data->atm_addr[11],
- ioc_data->atm_addr[12],ioc_data->atm_addr[13],
- ioc_data->atm_addr[14],ioc_data->atm_addr[15],
- ioc_data->atm_addr[16],ioc_data->atm_addr[17],
- ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
- entry = make_entry(priv, bus_mac);
- if (entry == NULL)
+ del_timer(&entry->timer);
+ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+ entry->recv_vcc = vcc;
+ entry->old_recv_push = old_push;
+ hlist_add_head(&entry->next, &priv->mcast_fwds);
+ goto out;
+ } else if (ioc_data->receive == 1) {
+ /*
+ * Vcc which we don't want to make default vcc,
+ * attach it anyway.
+ */
+ DPRINTK
+ ("LEC_ARP:Attaching data direct, not default: "
+ "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+ ioc_data->atm_addr[0], ioc_data->atm_addr[1],
+ ioc_data->atm_addr[2], ioc_data->atm_addr[3],
+ ioc_data->atm_addr[4], ioc_data->atm_addr[5],
+ ioc_data->atm_addr[6], ioc_data->atm_addr[7],
+ ioc_data->atm_addr[8], ioc_data->atm_addr[9],
+ ioc_data->atm_addr[10], ioc_data->atm_addr[11],
+ ioc_data->atm_addr[12], ioc_data->atm_addr[13],
+ ioc_data->atm_addr[14], ioc_data->atm_addr[15],
+ ioc_data->atm_addr[16], ioc_data->atm_addr[17],
+ ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
+ entry = make_entry(priv, bus_mac);
+ if (entry == NULL)
goto out;
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- memset(entry->mac_addr, 0, ETH_ALEN);
- entry->recv_vcc = vcc;
- entry->old_recv_push = old_push;
- entry->status = ESI_UNKNOWN;
- entry->timer.expires = jiffies + priv->vcc_timeout_period;
- entry->timer.function = lec_arp_expire_vcc;
- add_timer(&entry->timer);
- entry->next = priv->lec_no_forward;
- priv->lec_no_forward = entry;
+ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+ memset(entry->mac_addr, 0, ETH_ALEN);
+ entry->recv_vcc = vcc;
+ entry->old_recv_push = old_push;
+ entry->status = ESI_UNKNOWN;
+ entry->timer.expires = jiffies + priv->vcc_timeout_period;
+ entry->timer.function = lec_arp_expire_vcc;
+ hlist_add_head(&entry->next, &priv->lec_no_forward);
+ add_timer(&entry->timer);
dump_arp_table(priv);
goto out;
- }
- DPRINTK("LEC_ARP:Attaching data direct, default:%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
- ioc_data->atm_addr[0],ioc_data->atm_addr[1],
- ioc_data->atm_addr[2],ioc_data->atm_addr[3],
- ioc_data->atm_addr[4],ioc_data->atm_addr[5],
- ioc_data->atm_addr[6],ioc_data->atm_addr[7],
- ioc_data->atm_addr[8],ioc_data->atm_addr[9],
- ioc_data->atm_addr[10],ioc_data->atm_addr[11],
- ioc_data->atm_addr[12],ioc_data->atm_addr[13],
- ioc_data->atm_addr[14],ioc_data->atm_addr[15],
- ioc_data->atm_addr[16],ioc_data->atm_addr[17],
- ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
- if (memcmp(ioc_data->atm_addr, entry->atm_addr,
- ATM_ESA_LEN)==0) {
- DPRINTK("LEC_ARP: Attaching data direct\n");
- DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n",
- entry->vcc?entry->vcc->vci:0,
- entry->recv_vcc?entry->recv_vcc->vci:0);
- found_entry=1;
- del_timer(&entry->timer);
- entry->vcc = vcc;
- entry->old_push = old_push;
- if (entry->status == ESI_VC_PENDING) {
- if(priv->maximum_unknown_frame_count
- ==0)
- entry->status =
- ESI_FORWARD_DIRECT;
- else {
- entry->timestamp = jiffies;
- entry->status =
- ESI_FLUSH_PENDING;
+ }
+ DPRINTK
+ ("LEC_ARP:Attaching data direct, default: "
+ "%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x\n",
+ ioc_data->atm_addr[0], ioc_data->atm_addr[1],
+ ioc_data->atm_addr[2], ioc_data->atm_addr[3],
+ ioc_data->atm_addr[4], ioc_data->atm_addr[5],
+ ioc_data->atm_addr[6], ioc_data->atm_addr[7],
+ ioc_data->atm_addr[8], ioc_data->atm_addr[9],
+ ioc_data->atm_addr[10], ioc_data->atm_addr[11],
+ ioc_data->atm_addr[12], ioc_data->atm_addr[13],
+ ioc_data->atm_addr[14], ioc_data->atm_addr[15],
+ ioc_data->atm_addr[16], ioc_data->atm_addr[17],
+ ioc_data->atm_addr[18], ioc_data->atm_addr[19]);
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
+ if (memcmp
+ (ioc_data->atm_addr, entry->atm_addr,
+ ATM_ESA_LEN) == 0) {
+ DPRINTK("LEC_ARP: Attaching data direct\n");
+ DPRINTK("Currently -> Vcc: %d, Rvcc:%d\n",
+ entry->vcc ? entry->vcc->vci : 0,
+ entry->recv_vcc ? entry->recv_vcc->
+ vci : 0);
+ found_entry = 1;
+ del_timer(&entry->timer);
+ entry->vcc = vcc;
+ entry->old_push = old_push;
+ if (entry->status == ESI_VC_PENDING) {
+ if (priv->maximum_unknown_frame_count
+ == 0)
+ entry->status =
+ ESI_FORWARD_DIRECT;
+ else {
+ entry->timestamp = jiffies;
+ entry->status =
+ ESI_FLUSH_PENDING;
#if 0
- send_to_lecd(priv,l_flush_xmt,
- NULL,
- entry->atm_addr,
- NULL);
+ send_to_lecd(priv, l_flush_xmt,
+ NULL,
+ entry->atm_addr,
+ NULL);
#endif
- }
- } else {
- /* They were forming a connection
- to us, and we to them. Our
- ATM address is numerically lower
- than theirs, so we make connection
- we formed into default VCC (8.1.11).
- Connection they made gets torn
- down. This might confuse some
- clients. Can be changed if
- someone reports trouble... */
- ;
- }
- }
- }
- }
- if (found_entry) {
- DPRINTK("After vcc was added\n");
- dump_arp_table(priv);
+ }
+ } else {
+ /*
+ * They were forming a connection
+ * to us, and we to them. Our
+ * ATM address is numerically lower
+ * than theirs, so we make connection
+ * we formed into default VCC (8.1.11).
+ * Connection they made gets torn
+ * down. This might confuse some
+ * clients. Can be changed if
+ * someone reports trouble...
+ */
+ ;
+ }
+ }
+ }
+ }
+ if (found_entry) {
+ DPRINTK("After vcc was added\n");
+ dump_arp_table(priv);
goto out;
- }
- /* Not found, snatch address from first data packet that arrives from
- this vcc */
- entry = make_entry(priv, bus_mac);
- if (!entry)
+ }
+ /*
+ * Not found, snatch address from first data packet that arrives
+ * from this vcc
+ */
+ entry = make_entry(priv, bus_mac);
+ if (!entry)
goto out;
- entry->vcc = vcc;
- entry->old_push = old_push;
- memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
- memset(entry->mac_addr, 0, ETH_ALEN);
- entry->status = ESI_UNKNOWN;
- entry->next = priv->lec_arp_empty_ones;
- priv->lec_arp_empty_ones = entry;
- entry->timer.expires = jiffies + priv->vcc_timeout_period;
- entry->timer.function = lec_arp_expire_vcc;
- add_timer(&entry->timer);
- DPRINTK("After vcc was added\n");
+ entry->vcc = vcc;
+ entry->old_push = old_push;
+ memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
+ memset(entry->mac_addr, 0, ETH_ALEN);
+ entry->status = ESI_UNKNOWN;
+ hlist_add_head(&entry->next, &priv->lec_arp_empty_ones);
+ entry->timer.expires = jiffies + priv->vcc_timeout_period;
+ entry->timer.function = lec_arp_expire_vcc;
+ add_timer(&entry->timer);
+ DPRINTK("After vcc was added\n");
dump_arp_table(priv);
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
-static void
-lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
+static void lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
{
unsigned long flags;
- struct lec_arp_table *entry;
- int i;
-
- DPRINTK("LEC:lec_flush_complete %lx\n",tran_id);
+ struct hlist_node *node;
+ struct lec_arp_table *entry;
+ int i;
+
+ DPRINTK("LEC:lec_flush_complete %lx\n", tran_id);
+restart:
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
- for (entry = priv->lec_arp_tables[i]; entry; entry=entry->next) {
- if (entry->flush_tran_id == tran_id &&
- entry->status == ESI_FLUSH_PENDING) {
- struct sk_buff *skb;
-
- while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
- lec_send(entry->vcc, skb, entry->priv);
- entry->status = ESI_FORWARD_DIRECT;
- DPRINTK("LEC_ARP: Flushed\n");
- }
- }
- }
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
+ if (entry->flush_tran_id == tran_id
+ && entry->status == ESI_FLUSH_PENDING) {
+ struct sk_buff *skb;
+ struct atm_vcc *vcc = entry->vcc;
+
+ lec_arp_hold(entry);
+ spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
+ while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
+ lec_send(vcc, skb, entry->priv);
+ entry->last_used = jiffies;
+ entry->status = ESI_FORWARD_DIRECT;
+ lec_arp_put(entry);
+ DPRINTK("LEC_ARP: Flushed\n");
+ goto restart;
+ }
+ }
+ }
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- dump_arp_table(priv);
+ dump_arp_table(priv);
}
static void
lec_set_flush_tran_id(struct lec_priv *priv,
- unsigned char *atm_addr, unsigned long tran_id)
+ unsigned char *atm_addr, unsigned long tran_id)
{
unsigned long flags;
- struct lec_arp_table *entry;
- int i;
+ struct hlist_node *node;
+ struct lec_arp_table *entry;
+ int i;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
- for(entry = priv->lec_arp_tables[i]; entry; entry=entry->next)
- if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
- entry->flush_tran_id = tran_id;
- DPRINTK("Set flush transaction id to %lx for %p\n",tran_id,entry);
- }
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++)
+ hlist_for_each_entry(entry, node, &priv->lec_arp_tables[i], next) {
+ if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN)) {
+ entry->flush_tran_id = tran_id;
+ DPRINTK("Set flush transaction id to %lx for %p\n",
+ tran_id, entry);
+ }
+ }
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
-static int
-lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
+static int lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
{
unsigned long flags;
- unsigned char mac_addr[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- struct lec_arp_table *to_add;
+ unsigned char mac_addr[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+ struct lec_arp_table *to_add;
struct lec_vcc_priv *vpriv;
int err = 0;
-
+
if (!(vpriv = kmalloc(sizeof(struct lec_vcc_priv), GFP_KERNEL)))
return -ENOMEM;
vpriv->xoff = 0;
vpriv->old_pop = vcc->pop;
vcc->user_back = vpriv;
- vcc->pop = lec_pop;
+ vcc->pop = lec_pop;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- to_add = make_entry(priv, mac_addr);
- if (!to_add) {
+ to_add = make_entry(priv, mac_addr);
+ if (!to_add) {
vcc->pop = vpriv->old_pop;
kfree(vpriv);
- err = -ENOMEM;
+ err = -ENOMEM;
goto out;
- }
- memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
- to_add->status = ESI_FORWARD_DIRECT;
- to_add->flags |= LEC_PERMANENT_FLAG;
- to_add->vcc = vcc;
- to_add->old_push = vcc->push;
- vcc->push = lec_push;
- priv->mcast_vcc = vcc;
- lec_arp_add(priv, to_add);
+ }
+ memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
+ to_add->status = ESI_FORWARD_DIRECT;
+ to_add->flags |= LEC_PERMANENT_FLAG;
+ to_add->vcc = vcc;
+ to_add->old_push = vcc->push;
+ vcc->push = lec_push;
+ priv->mcast_vcc = vcc;
+ lec_arp_add(priv, to_add);
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
- return err;
+ return err;
}
-static void
-lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
+static void lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
{
unsigned long flags;
- struct lec_arp_table *entry, *next;
- int i;
+ struct hlist_node *node, *next;
+ struct lec_arp_table *entry;
+ int i;
+
+ DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n", vcc->vpi, vcc->vci);
+ dump_arp_table(priv);
- DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci);
- dump_arp_table(priv);
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
- for(entry = priv->lec_arp_tables[i];entry; entry=next) {
- next = entry->next;
- if (vcc == entry->vcc) {
- lec_arp_remove(priv, entry);
- kfree(entry);
- if (priv->mcast_vcc == vcc) {
- priv->mcast_vcc = NULL;
- }
- }
- }
- }
-
- entry = priv->lec_arp_empty_ones;
- priv->lec_arp_empty_ones = NULL;
- while (entry != NULL) {
- next = entry->next;
- if (entry->vcc == vcc) { /* leave it out from the list */
- lec_arp_clear_vccs(entry);
- del_timer(&entry->timer);
- kfree(entry);
- }
- else { /* put it back to the list */
- entry->next = priv->lec_arp_empty_ones;
- priv->lec_arp_empty_ones = entry;
- }
- entry = next;
- }
-
- entry = priv->lec_no_forward;
- priv->lec_no_forward = NULL;
- while (entry != NULL) {
- next = entry->next;
- if (entry->recv_vcc == vcc) {
- lec_arp_clear_vccs(entry);
- del_timer(&entry->timer);
- kfree(entry);
- }
- else {
- entry->next = priv->lec_no_forward;
- priv->lec_no_forward = entry;
- }
- entry = next;
- }
-
- entry = priv->mcast_fwds;
- priv->mcast_fwds = NULL;
- while (entry != NULL) {
- next = entry->next;
- if (entry->recv_vcc == vcc) {
- lec_arp_clear_vccs(entry);
- /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
- kfree(entry);
- }
- else {
- entry->next = priv->mcast_fwds;
- priv->mcast_fwds = entry;
- }
- entry = next;
- }
+
+ for (i = 0; i < LEC_ARP_TABLE_SIZE; i++) {
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_tables[i], next) {
+ if (vcc == entry->vcc) {
+ lec_arp_remove(priv, entry);
+ lec_arp_put(entry);
+ if (priv->mcast_vcc == vcc) {
+ priv->mcast_vcc = NULL;
+ }
+ }
+ }
+ }
+
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+ if (entry->vcc == vcc) {
+ lec_arp_clear_vccs(entry);
+ del_timer(&entry->timer);
+ hlist_del(&entry->next);
+ lec_arp_put(entry);
+ }
+ }
+
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_no_forward, next) {
+ if (entry->recv_vcc == vcc) {
+ lec_arp_clear_vccs(entry);
+ del_timer(&entry->timer);
+ hlist_del(&entry->next);
+ lec_arp_put(entry);
+ }
+ }
+
+ hlist_for_each_entry_safe(entry, node, next, &priv->mcast_fwds, next) {
+ if (entry->recv_vcc == vcc) {
+ lec_arp_clear_vccs(entry);
+ /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
+ hlist_del(&entry->next);
+ lec_arp_put(entry);
+ }
+ }
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
dump_arp_table(priv);
@@ -2517,57 +2483,42 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
static void
lec_arp_check_empties(struct lec_priv *priv,
- struct atm_vcc *vcc, struct sk_buff *skb)
+ struct atm_vcc *vcc, struct sk_buff *skb)
{
- unsigned long flags;
- struct lec_arp_table *entry, *prev;
- struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
- unsigned char *src;
+ unsigned long flags;
+ struct hlist_node *node, *next;
+ struct lec_arp_table *entry, *tmp;
+ struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
+ unsigned char *src;
#ifdef CONFIG_TR
- struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
+ struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
- if (priv->is_trdev) src = tr_hdr->h_source;
- else
+ if (priv->is_trdev)
+ src = tr_hdr->h_source;
+ else
#endif
- src = hdr->h_source;
+ src = hdr->h_source;
spin_lock_irqsave(&priv->lec_arp_lock, flags);
- entry = priv->lec_arp_empty_ones;
- if (vcc == entry->vcc) {
- del_timer(&entry->timer);
- memcpy(entry->mac_addr, src, ETH_ALEN);
- entry->status = ESI_FORWARD_DIRECT;
- entry->last_used = jiffies;
- priv->lec_arp_empty_ones = entry->next;
- /* We might have got an entry */
- if ((prev = lec_arp_find(priv,src))) {
- lec_arp_remove(priv, prev);
- kfree(prev);
- }
- lec_arp_add(priv, entry);
- goto out;
- }
- prev = entry;
- entry = entry->next;
- while (entry && entry->vcc != vcc) {
- prev= entry;
- entry = entry->next;
- }
- if (!entry) {
- DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
- goto out;
- }
- del_timer(&entry->timer);
- memcpy(entry->mac_addr, src, ETH_ALEN);
- entry->status = ESI_FORWARD_DIRECT;
- entry->last_used = jiffies;
- prev->next = entry->next;
- if ((prev = lec_arp_find(priv, src))) {
- lec_arp_remove(priv, prev);
- kfree(prev);
- }
- lec_arp_add(priv, entry);
+ hlist_for_each_entry_safe(entry, node, next, &priv->lec_arp_empty_ones, next) {
+ if (vcc == entry->vcc) {
+ del_timer(&entry->timer);
+ memcpy(entry->mac_addr, src, ETH_ALEN);
+ entry->status = ESI_FORWARD_DIRECT;
+ entry->last_used = jiffies;
+ /* We might have got an entry */
+ if ((tmp = lec_arp_find(priv, src))) {
+ lec_arp_remove(priv, tmp);
+ lec_arp_put(tmp);
+ }
+ hlist_del(&entry->next);
+ lec_arp_add(priv, entry);
+ goto out;
+ }
+ }
+ DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
out:
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
}
+
MODULE_LICENSE("GPL");
diff --git a/net/atm/lec.h b/net/atm/lec.h
index c22a8bfa1f81..877f50939696 100644
--- a/net/atm/lec.h
+++ b/net/atm/lec.h
@@ -1,9 +1,7 @@
/*
- *
* Lan Emulation client header file
*
- * Marko Kiiskila mkiiskila@yahoo.com
- *
+ * Marko Kiiskila <mkiiskila@yahoo.com>
*/
#ifndef _LEC_H_
@@ -16,18 +14,18 @@
#define LEC_HEADER_LEN 16
struct lecdatahdr_8023 {
- unsigned short le_header;
- unsigned char h_dest[ETH_ALEN];
- unsigned char h_source[ETH_ALEN];
- unsigned short h_type;
+ unsigned short le_header;
+ unsigned char h_dest[ETH_ALEN];
+ unsigned char h_source[ETH_ALEN];
+ unsigned short h_type;
};
struct lecdatahdr_8025 {
- unsigned short le_header;
- unsigned char ac_pad;
- unsigned char fc;
- unsigned char h_dest[ETH_ALEN];
- unsigned char h_source[ETH_ALEN];
+ unsigned short le_header;
+ unsigned char ac_pad;
+ unsigned char fc;
+ unsigned char h_dest[ETH_ALEN];
+ unsigned char h_source[ETH_ALEN];
};
#define LEC_MINIMUM_8023_SIZE 62
@@ -44,17 +42,18 @@ struct lecdatahdr_8025 {
*
*/
struct lane2_ops {
- int (*resolve)(struct net_device *dev, u8 *dst_mac, int force,
- u8 **tlvs, u32 *sizeoftlvs);
- int (*associate_req)(struct net_device *dev, u8 *lan_dst,
- u8 *tlvs, u32 sizeoftlvs);
- void (*associate_indicator)(struct net_device *dev, u8 *mac_addr,
- u8 *tlvs, u32 sizeoftlvs);
+ int (*resolve) (struct net_device *dev, u8 *dst_mac, int force,
+ u8 **tlvs, u32 *sizeoftlvs);
+ int (*associate_req) (struct net_device *dev, u8 *lan_dst,
+ u8 *tlvs, u32 sizeoftlvs);
+ void (*associate_indicator) (struct net_device *dev, u8 *mac_addr,
+ u8 *tlvs, u32 sizeoftlvs);
};
/*
* ATM LAN Emulation supports both LLC & Dix Ethernet EtherType
* frames.
+ *
* 1. Dix Ethernet EtherType frames encoded by placing EtherType
* field in h_type field. Data follows immediatelly after header.
* 2. LLC Data frames whose total length, including LLC field and data,
@@ -70,72 +69,88 @@ struct lane2_ops {
#define LEC_ARP_TABLE_SIZE 16
struct lec_priv {
- struct net_device_stats stats;
- unsigned short lecid; /* Lecid of this client */
- struct lec_arp_table *lec_arp_empty_ones;
- /* Used for storing VCC's that don't have a MAC address attached yet */
- struct lec_arp_table *lec_arp_tables[LEC_ARP_TABLE_SIZE];
- /* Actual LE ARP table */
- struct lec_arp_table *lec_no_forward;
- /* Used for storing VCC's (and forward packets from) which are to
- age out by not using them to forward packets.
- This is because to some LE clients there will be 2 VCCs. Only
- one of them gets used. */
- struct lec_arp_table *mcast_fwds;
- /* With LANEv2 it is possible that BUS (or a special multicast server)
- establishes multiple Multicast Forward VCCs to us. This list
- collects all those VCCs. LANEv1 client has only one item in this
- list. These entries are not aged out. */
- spinlock_t lec_arp_lock;
- struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
- struct atm_vcc *lecd;
- struct timer_list lec_arp_timer;
- /* C10 */
- unsigned int maximum_unknown_frame_count;
-/* Within the period of time defined by this variable, the client will send
- no more than C10 frames to BUS for a given unicast destination. (C11) */
- unsigned long max_unknown_frame_time;
-/* If no traffic has been sent in this vcc for this period of time,
- vcc will be torn down (C12)*/
- unsigned long vcc_timeout_period;
-/* An LE Client MUST not retry an LE_ARP_REQUEST for a
- given frame's LAN Destination more than maximum retry count times,
- after the first LEC_ARP_REQUEST (C13)*/
- unsigned short max_retry_count;
-/* Max time the client will maintain an entry in its arp cache in
- absence of a verification of that relationship (C17)*/
- unsigned long aging_time;
-/* Max time the client will maintain an entry in cache when
- topology change flag is true (C18) */
- unsigned long forward_delay_time;
-/* Topology change flag (C19)*/
- int topology_change;
-/* Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE
- cycle to take (C20)*/
- unsigned long arp_response_time;
-/* Time limit ot wait to receive an LE_FLUSH_RESPONSE after the
- LE_FLUSH_REQUEST has been sent before taking recover action. (C21)*/
- unsigned long flush_timeout;
-/* The time since sending a frame to the bus after which the
- LE Client may assume that the frame has been either discarded or
- delivered to the recipient (C22) */
- unsigned long path_switching_delay;
+ struct net_device_stats stats;
+ unsigned short lecid; /* Lecid of this client */
+ struct hlist_head lec_arp_empty_ones;
+ /* Used for storing VCC's that don't have a MAC address attached yet */
+ struct hlist_head lec_arp_tables[LEC_ARP_TABLE_SIZE];
+ /* Actual LE ARP table */
+ struct hlist_head lec_no_forward;
+ /*
+ * Used for storing VCC's (and forward packets from) which are to
+ * age out by not using them to forward packets.
+ * This is because to some LE clients there will be 2 VCCs. Only
+ * one of them gets used.
+ */
+ struct hlist_head mcast_fwds;
+ /*
+ * With LANEv2 it is possible that BUS (or a special multicast server)
+ * establishes multiple Multicast Forward VCCs to us. This list
+ * collects all those VCCs. LANEv1 client has only one item in this
+ * list. These entries are not aged out.
+ */
+ spinlock_t lec_arp_lock;
+ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
+ struct atm_vcc *lecd;
+ struct work_struct lec_arp_work; /* C10 */
+ unsigned int maximum_unknown_frame_count;
+ /*
+ * Within the period of time defined by this variable, the client will send
+ * no more than C10 frames to BUS for a given unicast destination. (C11)
+ */
+ unsigned long max_unknown_frame_time;
+ /*
+ * If no traffic has been sent in this vcc for this period of time,
+ * vcc will be torn down (C12)
+ */
+ unsigned long vcc_timeout_period;
+ /*
+ * An LE Client MUST not retry an LE_ARP_REQUEST for a
+ * given frame's LAN Destination more than maximum retry count times,
+ * after the first LEC_ARP_REQUEST (C13)
+ */
+ unsigned short max_retry_count;
+ /*
+ * Max time the client will maintain an entry in its arp cache in
+ * absence of a verification of that relationship (C17)
+ */
+ unsigned long aging_time;
+ /*
+ * Max time the client will maintain an entry in cache when
+ * topology change flag is true (C18)
+ */
+ unsigned long forward_delay_time; /* Topology change flag (C19) */
+ int topology_change;
+ /*
+ * Max time the client expects an LE_ARP_REQUEST/LE_ARP_RESPONSE
+ * cycle to take (C20)
+ */
+ unsigned long arp_response_time;
+ /*
+ * Time limit ot wait to receive an LE_FLUSH_RESPONSE after the
+ * LE_FLUSH_REQUEST has been sent before taking recover action. (C21)
+ */
+ unsigned long flush_timeout;
+ /* The time since sending a frame to the bus after which the
+ * LE Client may assume that the frame has been either discarded or
+ * delivered to the recipient (C22)
+ */
+ unsigned long path_switching_delay;
- u8 *tlvs; /* LANE2: TLVs are new */
- u32 sizeoftlvs; /* The size of the tlv array in bytes */
- int lane_version; /* LANE2 */
- int itfnum; /* e.g. 2 for lec2, 5 for lec5 */
- struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */
- int is_proxy; /* bridge between ATM and Ethernet */
- int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */
+ u8 *tlvs; /* LANE2: TLVs are new */
+ u32 sizeoftlvs; /* The size of the tlv array in bytes */
+ int lane_version; /* LANE2 */
+ int itfnum; /* e.g. 2 for lec2, 5 for lec5 */
+ struct lane2_ops *lane2_ops; /* can be NULL for LANE v1 */
+ int is_proxy; /* bridge between ATM and Ethernet */
+ int is_trdev; /* Device type, 0 = Ethernet, 1 = TokenRing */
};
struct lec_vcc_priv {
- void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
+ void (*old_pop) (struct atm_vcc *vcc, struct sk_buff *skb);
int xoff;
};
#define LEC_VCC_PRIV(vcc) ((struct lec_vcc_priv *)((vcc)->user_back))
-#endif /* _LEC_H_ */
-
+#endif /* _LEC_H_ */
diff --git a/net/atm/lec_arpc.h b/net/atm/lec_arpc.h
index 397448094648..ec67435a40a6 100644
--- a/net/atm/lec_arpc.h
+++ b/net/atm/lec_arpc.h
@@ -1,92 +1,96 @@
/*
* Lec arp cache
- * Marko Kiiskila mkiiskila@yahoo.com
*
+ * Marko Kiiskila <mkiiskila@yahoo.com>
*/
-#ifndef _LEC_ARP_H
-#define _LEC_ARP_H
+#ifndef _LEC_ARP_H_
+#define _LEC_ARP_H_
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/if_ether.h>
#include <linux/atmlec.h>
struct lec_arp_table {
- struct lec_arp_table *next; /* Linked entry list */
- unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */
- unsigned char mac_addr[ETH_ALEN]; /* Mac address */
- int is_rdesc; /* Mac address is a route descriptor */
- struct atm_vcc *vcc; /* Vcc this entry is attached */
- struct atm_vcc *recv_vcc; /* Vcc we receive data from */
- void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
- /* Push that leads to daemon */
- void (*old_recv_push)(struct atm_vcc *vcc, struct sk_buff *skb);
- /* Push that leads to daemon */
- void (*old_close)(struct atm_vcc *vcc);
- /* We want to see when this
- * vcc gets closed */
- unsigned long last_used; /* For expiry */
- unsigned long timestamp; /* Used for various timestamping
- * things:
- * 1. FLUSH started
- * (status=ESI_FLUSH_PENDING)
- * 2. Counting to
- * max_unknown_frame_time
- * (status=ESI_ARP_PENDING||
- * status=ESI_VC_PENDING)
- */
- unsigned char no_tries; /* No of times arp retry has been
- tried */
- unsigned char status; /* Status of this entry */
- unsigned short flags; /* Flags for this entry */
- unsigned short packets_flooded; /* Data packets flooded */
- unsigned long flush_tran_id; /* Transaction id in flush protocol */
- struct timer_list timer; /* Arping timer */
- struct lec_priv *priv; /* Pointer back */
+ struct hlist_node next; /* Linked entry list */
+ unsigned char atm_addr[ATM_ESA_LEN]; /* Atm address */
+ unsigned char mac_addr[ETH_ALEN]; /* Mac address */
+ int is_rdesc; /* Mac address is a route descriptor */
+ struct atm_vcc *vcc; /* Vcc this entry is attached */
+ struct atm_vcc *recv_vcc; /* Vcc we receive data from */
- u8 *tlvs; /* LANE2: Each MAC address can have TLVs */
- u32 sizeoftlvs; /* associated with it. sizeoftlvs tells the */
- /* the length of the tlvs array */
- struct sk_buff_head tx_wait; /* wait queue for outgoing packets */
+ void (*old_push) (struct atm_vcc *vcc, struct sk_buff *skb);
+ /* Push that leads to daemon */
+
+ void (*old_recv_push) (struct atm_vcc *vcc, struct sk_buff *skb);
+ /* Push that leads to daemon */
+
+ unsigned long last_used; /* For expiry */
+ unsigned long timestamp; /* Used for various timestamping things:
+ * 1. FLUSH started
+ * (status=ESI_FLUSH_PENDING)
+ * 2. Counting to
+ * max_unknown_frame_time
+ * (status=ESI_ARP_PENDING||
+ * status=ESI_VC_PENDING)
+ */
+ unsigned char no_tries; /* No of times arp retry has been tried */
+ unsigned char status; /* Status of this entry */
+ unsigned short flags; /* Flags for this entry */
+ unsigned short packets_flooded; /* Data packets flooded */
+ unsigned long flush_tran_id; /* Transaction id in flush protocol */
+ struct timer_list timer; /* Arping timer */
+ struct lec_priv *priv; /* Pointer back */
+ u8 *tlvs;
+ u32 sizeoftlvs; /*
+ * LANE2: Each MAC address can have TLVs
+ * associated with it. sizeoftlvs tells the
+ * the length of the tlvs array
+ */
+ struct sk_buff_head tx_wait; /* wait queue for outgoing packets */
+ atomic_t usage; /* usage count */
};
-struct tlv { /* LANE2: Template tlv struct for accessing */
- /* the tlvs in the lec_arp_table->tlvs array*/
- u32 type;
- u8 length;
- u8 value[255];
+/*
+ * LANE2: Template tlv struct for accessing
+ * the tlvs in the lec_arp_table->tlvs array
+ */
+struct tlv {
+ u32 type;
+ u8 length;
+ u8 value[255];
};
/* Status fields */
-#define ESI_UNKNOWN 0 /*
- * Next packet sent to this mac address
- * causes ARP-request to be sent
- */
-#define ESI_ARP_PENDING 1 /*
- * There is no ATM address associated with this
- * 48-bit address. The LE-ARP protocol is in
- * progress.
- */
-#define ESI_VC_PENDING 2 /*
- * There is a valid ATM address associated with
- * this 48-bit address but there is no VC set
- * up to that ATM address. The signaling
- * protocol is in process.
- */
-#define ESI_FLUSH_PENDING 4 /*
- * The LEC has been notified of the FLUSH_START
- * status and it is assumed that the flush
- * protocol is in process.
- */
-#define ESI_FORWARD_DIRECT 5 /*
- * Either the Path Switching Delay (C22) has
- * elapsed or the LEC has notified the Mapping
- * that the flush protocol has completed. In
- * either case, it is safe to forward packets
- * to this address via the data direct VC.
- */
+#define ESI_UNKNOWN 0 /*
+ * Next packet sent to this mac address
+ * causes ARP-request to be sent
+ */
+#define ESI_ARP_PENDING 1 /*
+ * There is no ATM address associated with this
+ * 48-bit address. The LE-ARP protocol is in
+ * progress.
+ */
+#define ESI_VC_PENDING 2 /*
+ * There is a valid ATM address associated with
+ * this 48-bit address but there is no VC set
+ * up to that ATM address. The signaling
+ * protocol is in process.
+ */
+#define ESI_FLUSH_PENDING 4 /*
+ * The LEC has been notified of the FLUSH_START
+ * status and it is assumed that the flush
+ * protocol is in process.
+ */
+#define ESI_FORWARD_DIRECT 5 /*
+ * Either the Path Switching Delay (C22) has
+ * elapsed or the LEC has notified the Mapping
+ * that the flush protocol has completed. In
+ * either case, it is safe to forward packets
+ * to this address via the data direct VC.
+ */
/* Flag values */
#define LEC_REMOTE_FLAG 0x0001
#define LEC_PERMANENT_FLAG 0x0002
-#endif
+#endif /* _LEC_ARP_H_ */
diff --git a/net/atm/mpc.c b/net/atm/mpc.c
index b87c2a88bdce..0d2b994af511 100644
--- a/net/atm/mpc.c
+++ b/net/atm/mpc.c
@@ -560,7 +560,6 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
struct atmmpc_ioc ioc_data;
in_cache_entry *in_entry;
uint32_t ipaddr;
- unsigned char *ip;
bytes_left = copy_from_user(&ioc_data, arg, sizeof(struct atmmpc_ioc));
if (bytes_left != 0) {
@@ -583,9 +582,8 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
if (in_entry != NULL) mpc->in_ops->put(in_entry);
return -EINVAL;
}
- ip = (unsigned char*)&in_entry->ctrl_info.in_dst_ip;
printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n",
- mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+ mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
in_entry->shortcut = vcc;
mpc->in_ops->put(in_entry);
} else {
@@ -616,10 +614,8 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev)
dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name);
in_entry = mpc->in_ops->get_by_vcc(vcc, mpc);
if (in_entry) {
- unsigned char *ip __attribute__ ((unused)) =
- (unsigned char *)&in_entry->ctrl_info.in_dst_ip;
dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n",
- mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+ mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip));
in_entry->shortcut = NULL;
mpc->in_ops->put(in_entry);
}
@@ -1154,18 +1150,17 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc)
{
uint32_t dst_ip = msg->content.in_info.in_dst_ip;
uint32_t mask = msg->ip_mask;
- unsigned char *ip = (unsigned char *)&dst_ip;
in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask);
if(entry == NULL){
printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ", mpc->dev->name);
- printk("ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
+ printk("ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
return;
}
do {
dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" ,
- mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+ mpc->dev->name, NIPQUAD(dst_ip));
write_lock_bh(&mpc->ingress_lock);
mpc->in_ops->remove_entry(entry, mpc);
write_unlock_bh(&mpc->ingress_lock);
diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c
index 781ed1b9329d..fbf13cdcf46e 100644
--- a/net/atm/mpoa_caches.c
+++ b/net/atm/mpoa_caches.c
@@ -87,7 +87,6 @@ static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc,
static in_cache_entry *in_cache_add_entry(uint32_t dst_ip,
struct mpoa_client *client)
{
- unsigned char *ip __attribute__ ((unused)) = (unsigned char *)&dst_ip;
in_cache_entry* entry = kmalloc(sizeof(in_cache_entry), GFP_KERNEL);
if (entry == NULL) {
@@ -95,7 +94,7 @@ static in_cache_entry *in_cache_add_entry(uint32_t dst_ip,
return NULL;
}
- dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", ip[0], ip[1], ip[2], ip[3]);
+ dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip));
memset(entry,0,sizeof(in_cache_entry));
atomic_set(&entry->use, 1);
@@ -152,10 +151,7 @@ static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc)
if( entry->count > mpc->parameters.mpc_p1 &&
entry->entry_state == INGRESS_INVALID){
- unsigned char *ip __attribute__ ((unused)) =
- (unsigned char *)&entry->ctrl_info.in_dst_ip;
-
- dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, ip[0], ip[1], ip[2], ip[3]);
+ dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, NIPQUAD(entry->ctrl_info.in_dst_ip));
entry->entry_state = INGRESS_RESOLVING;
msg.type = SND_MPOA_RES_RQST;
memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
@@ -187,11 +183,9 @@ static void in_cache_remove_entry(in_cache_entry *entry,
{
struct atm_vcc *vcc;
struct k_message msg;
- unsigned char *ip;
vcc = entry->shortcut;
- ip = (unsigned char *)&entry->ctrl_info.in_dst_ip;
- dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",ip[0], ip[1], ip[2], ip[3]);
+ dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",NIPQUAD(entry->ctrl_info.in_dst_ip));
if (entry->prev != NULL)
entry->prev->next = entry->next;
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 788ea7a2b744..67df99e2e5c8 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -48,41 +48,56 @@
#define BT_DBG(D...)
#endif
-#define VERSION "2.10"
+#define VERSION "2.11"
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
static struct net_proto_family *bt_proto[BT_MAX_PROTO];
+static DEFINE_RWLOCK(bt_proto_lock);
int bt_sock_register(int proto, struct net_proto_family *ops)
{
+ int err = 0;
+
if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL;
+ write_lock(&bt_proto_lock);
+
if (bt_proto[proto])
- return -EEXIST;
+ err = -EEXIST;
+ else
+ bt_proto[proto] = ops;
- bt_proto[proto] = ops;
- return 0;
+ write_unlock(&bt_proto_lock);
+
+ return err;
}
EXPORT_SYMBOL(bt_sock_register);
int bt_sock_unregister(int proto)
{
+ int err = 0;
+
if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL;
+ write_lock(&bt_proto_lock);
+
if (!bt_proto[proto])
- return -ENOENT;
+ err = -ENOENT;
+ else
+ bt_proto[proto] = NULL;
- bt_proto[proto] = NULL;
- return 0;
+ write_unlock(&bt_proto_lock);
+
+ return err;
}
EXPORT_SYMBOL(bt_sock_unregister);
static int bt_sock_create(struct socket *sock, int proto)
{
- int err = 0;
+ int err;
if (proto < 0 || proto >= BT_MAX_PROTO)
return -EINVAL;
@@ -92,11 +107,18 @@ static int bt_sock_create(struct socket *sock, int proto)
request_module("bt-proto-%d", proto);
}
#endif
+
err = -EPROTONOSUPPORT;
+
+ read_lock(&bt_proto_lock);
+
if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
err = bt_proto[proto]->create(sock, proto);
module_put(bt_proto[proto]->owner);
}
+
+ read_unlock(&bt_proto_lock);
+
return err;
}
@@ -276,7 +298,7 @@ int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo)
set_current_state(TASK_INTERRUPTIBLE);
if (!timeo) {
- err = -EAGAIN;
+ err = -EINPROGRESS;
break;
}
diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
index e620061fb50f..4d3424c2421c 100644
--- a/net/bluetooth/bnep/core.c
+++ b/net/bluetooth/bnep/core.c
@@ -51,6 +51,7 @@
#include <asm/unaligned.h>
#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "bnep.h"
@@ -515,6 +516,24 @@ static int bnep_session(void *arg)
return 0;
}
+static struct device *bnep_get_device(struct bnep_session *session)
+{
+ bdaddr_t *src = &bt_sk(session->sock->sk)->src;
+ bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+
+ hdev = hci_get_route(dst, src);
+ if (!hdev)
+ return NULL;
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+
+ hci_dev_put(hdev);
+
+ return conn ? &conn->dev : NULL;
+}
+
int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
{
struct net_device *dev;
@@ -534,7 +553,6 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
if (!dev)
return -ENOMEM;
-
down_write(&bnep_session_sem);
ss = __bnep_get_session(dst);
@@ -551,7 +569,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
memcpy(s->eh.h_source, &dst, ETH_ALEN);
memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
- s->dev = dev;
+ s->dev = dev;
s->sock = sock;
s->role = req->role;
s->state = BT_CONNECTED;
@@ -568,6 +586,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
bnep_set_default_proto_filter(s);
#endif
+ SET_NETDEV_DEV(dev, bnep_get_device(s));
+
err = register_netdev(dev);
if (err) {
goto failed;
diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
index 28c55835422a..5563db1bf526 100644
--- a/net/bluetooth/bnep/sock.c
+++ b/net/bluetooth/bnep/sock.c
@@ -43,6 +43,7 @@
#include <linux/ioctl.h>
#include <linux/file.h>
#include <linux/init.h>
+#include <linux/compat.h>
#include <net/sock.h>
#include <asm/system.h>
@@ -146,24 +147,56 @@ static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return 0;
}
+#ifdef CONFIG_COMPAT
+static int bnep_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == BNEPGETCONNLIST) {
+ struct bnep_connlist_req cl;
+ uint32_t uci;
+ int err;
+
+ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+ get_user(uci, (u32 __user *) (arg + 4)))
+ return -EFAULT;
+
+ cl.ci = compat_ptr(uci);
+
+ if (cl.cnum <= 0)
+ return -EINVAL;
+
+ err = bnep_get_connlist(&cl);
+
+ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+ err = -EFAULT;
+
+ return err;
+ }
+
+ return bnep_sock_ioctl(sock, cmd, arg);
+}
+#endif
+
static const struct proto_ops bnep_sock_ops = {
- .family = PF_BLUETOOTH,
- .owner = THIS_MODULE,
- .release = bnep_sock_release,
- .ioctl = bnep_sock_ioctl,
- .bind = sock_no_bind,
- .getname = sock_no_getname,
- .sendmsg = sock_no_sendmsg,
- .recvmsg = sock_no_recvmsg,
- .poll = sock_no_poll,
- .listen = sock_no_listen,
- .shutdown = sock_no_shutdown,
- .setsockopt = sock_no_setsockopt,
- .getsockopt = sock_no_getsockopt,
- .connect = sock_no_connect,
- .socketpair = sock_no_socketpair,
- .accept = sock_no_accept,
- .mmap = sock_no_mmap
+ .family = PF_BLUETOOTH,
+ .owner = THIS_MODULE,
+ .release = bnep_sock_release,
+ .ioctl = bnep_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = bnep_sock_compat_ioctl,
+#endif
+ .bind = sock_no_bind,
+ .getname = sock_no_getname,
+ .sendmsg = sock_no_sendmsg,
+ .recvmsg = sock_no_recvmsg,
+ .poll = sock_no_poll,
+ .listen = sock_no_listen,
+ .shutdown = sock_no_shutdown,
+ .setsockopt = sock_no_setsockopt,
+ .getsockopt = sock_no_getsockopt,
+ .connect = sock_no_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = sock_no_accept,
+ .mmap = sock_no_mmap
};
static struct proto bnep_proto = {
@@ -181,7 +214,7 @@ static int bnep_sock_create(struct socket *sock, int protocol)
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &bnep_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &bnep_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c
index 10ad7fd91d83..53295d33dc5c 100644
--- a/net/bluetooth/cmtp/sock.c
+++ b/net/bluetooth/cmtp/sock.c
@@ -34,6 +34,7 @@
#include <linux/socket.h>
#include <linux/ioctl.h>
#include <linux/file.h>
+#include <linux/compat.h>
#include <net/sock.h>
#include <linux/isdn/capilli.h>
@@ -137,11 +138,43 @@ static int cmtp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+static int cmtp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == CMTPGETCONNLIST) {
+ struct cmtp_connlist_req cl;
+ uint32_t uci;
+ int err;
+
+ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+ get_user(uci, (u32 __user *) (arg + 4)))
+ return -EFAULT;
+
+ cl.ci = compat_ptr(uci);
+
+ if (cl.cnum <= 0)
+ return -EINVAL;
+
+ err = cmtp_get_connlist(&cl);
+
+ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+ err = -EFAULT;
+
+ return err;
+ }
+
+ return cmtp_sock_ioctl(sock, cmd, arg);
+}
+#endif
+
static const struct proto_ops cmtp_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = cmtp_sock_release,
.ioctl = cmtp_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = cmtp_sock_compat_ioctl,
+#endif
.bind = sock_no_bind,
.getname = sock_no_getname,
.sendmsg = sock_no_sendmsg,
@@ -172,7 +205,7 @@ static int cmtp_sock_create(struct socket *sock, int protocol)
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &cmtp_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &cmtp_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 420ed4d7e57e..6cd5711fa28a 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -51,7 +51,7 @@
#define BT_DBG(D...)
#endif
-static void hci_acl_connect(struct hci_conn *conn)
+void hci_acl_connect(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct inquiry_entry *ie;
@@ -63,6 +63,8 @@ static void hci_acl_connect(struct hci_conn *conn)
conn->out = 1;
conn->link_mode = HCI_LM_MASTER;
+ conn->attempt++;
+
memset(&cp, 0, sizeof(cp));
bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02;
@@ -80,10 +82,24 @@ static void hci_acl_connect(struct hci_conn *conn)
cp.role_switch = 0x01;
else
cp.role_switch = 0x00;
-
+
hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
}
+static void hci_acl_connect_cancel(struct hci_conn *conn)
+{
+ struct hci_cp_create_conn_cancel cp;
+
+ BT_DBG("%p", conn);
+
+ if (conn->hdev->hci_ver < 2)
+ return;
+
+ bacpy(&cp.bdaddr, &conn->dst);
+ hci_send_cmd(conn->hdev, OGF_LINK_CTL,
+ OCF_CREATE_CONN_CANCEL, sizeof(cp), &cp);
+}
+
void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
{
struct hci_cp_disconnect cp;
@@ -94,7 +110,8 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
cp.handle = __cpu_to_le16(conn->handle);
cp.reason = reason;
- hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, sizeof(cp), &cp);
+ hci_send_cmd(conn->hdev, OGF_LINK_CTL,
+ OCF_DISCONNECT, sizeof(cp), &cp);
}
void hci_add_sco(struct hci_conn *conn, __u16 handle)
@@ -124,12 +141,20 @@ static void hci_conn_timeout(unsigned long arg)
return;
hci_dev_lock(hdev);
- if (conn->state == BT_CONNECTED)
+
+ switch (conn->state) {
+ case BT_CONNECT:
+ hci_acl_connect_cancel(conn);
+ break;
+ case BT_CONNECTED:
hci_acl_disconn(conn, 0x13);
- else
+ break;
+ default:
conn->state = BT_CLOSED;
+ break;
+ }
+
hci_dev_unlock(hdev);
- return;
}
static void hci_conn_idle(unsigned long arg)
@@ -179,6 +204,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
+ hci_conn_add_sysfs(conn);
+
tasklet_enable(&hdev->tx_task);
return conn;
@@ -211,6 +238,8 @@ int hci_conn_del(struct hci_conn *conn)
tasklet_disable(&hdev->tx_task);
+ hci_conn_del_sysfs(conn);
+
hci_conn_hash_del(hdev, conn);
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -221,7 +250,9 @@ int hci_conn_del(struct hci_conn *conn)
hci_dev_put(hdev);
- kfree(conn);
+ /* will free via device release */
+ put_device(&conn->dev);
+
return 0;
}
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 5ed474277903..338ae977a31b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -206,6 +206,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
/* Read Local Supported Features */
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
+ /* Read Local Version */
+ hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
+
/* Read Buffer Size (ACL mtu, max pkt, etc.) */
hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 3896dabab11d..65f094845719 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -62,6 +62,7 @@ static void hci_cc_link_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
switch (ocf) {
case OCF_INQUIRY_CANCEL:
+ case OCF_EXIT_PERIODIC_INQ:
status = *((__u8 *) skb->data);
if (status) {
@@ -297,6 +298,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb
/* Command Complete OGF INFO_PARAM */
static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb)
{
+ struct hci_rp_read_loc_version *lv;
struct hci_rp_read_local_features *lf;
struct hci_rp_read_buffer_size *bs;
struct hci_rp_read_bd_addr *ba;
@@ -304,6 +306,23 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
BT_DBG("%s ocf 0x%x", hdev->name, ocf);
switch (ocf) {
+ case OCF_READ_LOCAL_VERSION:
+ lv = (struct hci_rp_read_loc_version *) skb->data;
+
+ if (lv->status) {
+ BT_DBG("%s READ_LOCAL_VERSION failed %d", hdev->name, lf->status);
+ break;
+ }
+
+ hdev->hci_ver = lv->hci_ver;
+ hdev->hci_rev = btohs(lv->hci_rev);
+ hdev->manufacturer = btohs(lv->manufacturer);
+
+ BT_DBG("%s: manufacturer %d hci_ver %d hci_rev %d", hdev->name,
+ hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
+
+ break;
+
case OCF_READ_LOCAL_FEATURES:
lf = (struct hci_rp_read_local_features *) skb->data;
@@ -328,7 +347,8 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s
if (hdev->features[1] & LMP_HV3)
hdev->pkt_type |= (HCI_HV3);
- BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name, lf->features[0], lf->features[1], lf->features[2]);
+ BT_DBG("%s: features 0x%x 0x%x 0x%x", hdev->name,
+ lf->features[0], lf->features[1], lf->features[2]);
break;
@@ -394,9 +414,12 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
if (status) {
if (conn && conn->state == BT_CONNECT) {
- conn->state = BT_CLOSED;
- hci_proto_connect_cfm(conn, status);
- hci_conn_del(conn);
+ if (status != 0x0c || conn->attempt > 2) {
+ conn->state = BT_CLOSED;
+ hci_proto_connect_cfm(conn, status);
+ hci_conn_del(conn);
+ } else
+ conn->state = BT_CONNECT2;
}
} else {
if (!conn) {
@@ -708,7 +731,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data;
- struct hci_conn *conn;
+ struct hci_conn *conn, *pend;
BT_DBG("%s", hdev->name);
@@ -757,6 +780,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
hci_send_cmd(hdev, OGF_LINK_CTL,
OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp);
+ } else {
+ /* Update disconnect timer */
+ hci_conn_hold(conn);
+ hci_conn_put(conn);
}
} else
conn->state = BT_CLOSED;
@@ -777,6 +804,10 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (ev->status)
hci_conn_del(conn);
+ pend = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
+ if (pend)
+ hci_acl_connect(pend);
+
hci_dev_unlock(hdev);
}
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 1a35d343e08a..f26a9eb49945 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -618,7 +618,7 @@ static int hci_sock_create(struct socket *sock, int protocol)
sock->ops = &hci_sock_ops;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hci_sk_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hci_sk_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 3987d167f04e..954eb74eb370 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -13,16 +13,32 @@
#define BT_DBG(D...)
#endif
-static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
+static inline char *typetostr(int type)
{
- struct hci_dev *hdev = dev_get_drvdata(dev);
- return sprintf(buf, "%s\n", hdev->name);
+ switch (type) {
+ case HCI_VIRTUAL:
+ return "VIRTUAL";
+ case HCI_USB:
+ return "USB";
+ case HCI_PCCARD:
+ return "PCCARD";
+ case HCI_UART:
+ return "UART";
+ case HCI_RS232:
+ return "RS232";
+ case HCI_PCI:
+ return "PCI";
+ case HCI_SDIO:
+ return "SDIO";
+ default:
+ return "UNKNOWN";
+ }
}
static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
- return sprintf(buf, "%d\n", hdev->type);
+ return sprintf(buf, "%s\n", typetostr(hdev->type));
}
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
@@ -33,10 +49,22 @@ static ssize_t show_address(struct device *dev, struct device_attribute *attr, c
return sprintf(buf, "%s\n", batostr(&bdaddr));
}
-static ssize_t show_flags(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
{
struct hci_dev *hdev = dev_get_drvdata(dev);
- return sprintf(buf, "0x%lx\n", hdev->flags);
+ return sprintf(buf, "%d\n", hdev->manufacturer);
+}
+
+static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", hdev->hci_ver);
+}
+
+static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_dev *hdev = dev_get_drvdata(dev);
+ return sprintf(buf, "%d\n", hdev->hci_rev);
}
static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf)
@@ -141,10 +169,11 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib
return count;
}
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
-static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
+static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
+static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
+static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
@@ -155,10 +184,11 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
show_sniff_min_interval, store_sniff_min_interval);
static struct device_attribute *bt_attrs[] = {
- &dev_attr_name,
&dev_attr_type,
&dev_attr_address,
- &dev_attr_flags,
+ &dev_attr_manufacturer,
+ &dev_attr_hci_version,
+ &dev_attr_hci_revision,
&dev_attr_inquiry_cache,
&dev_attr_idle_timeout,
&dev_attr_sniff_max_interval,
@@ -166,6 +196,32 @@ static struct device_attribute *bt_attrs[] = {
NULL
};
+static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_conn *conn = dev_get_drvdata(dev);
+ return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO");
+}
+
+static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct hci_conn *conn = dev_get_drvdata(dev);
+ bdaddr_t bdaddr;
+ baswap(&bdaddr, &conn->dst);
+ return sprintf(buf, "%s\n", batostr(&bdaddr));
+}
+
+#define CONN_ATTR(_name,_mode,_show,_store) \
+struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
+
+static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
+static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);
+
+static struct device_attribute *conn_attrs[] = {
+ &conn_attr_type,
+ &conn_attr_address,
+ NULL
+};
+
struct class *bt_class = NULL;
EXPORT_SYMBOL_GPL(bt_class);
@@ -177,8 +233,61 @@ static struct platform_device *bt_platform;
static void bt_release(struct device *dev)
{
- struct hci_dev *hdev = dev_get_drvdata(dev);
- kfree(hdev);
+ void *data = dev_get_drvdata(dev);
+ kfree(data);
+}
+
+static void add_conn(void *data)
+{
+ struct hci_conn *conn = data;
+ int i;
+
+ if (device_register(&conn->dev) < 0) {
+ BT_ERR("Failed to register connection device");
+ return;
+ }
+
+ for (i = 0; conn_attrs[i]; i++)
+ if (device_create_file(&conn->dev, conn_attrs[i]) < 0)
+ BT_ERR("Failed to create connection attribute");
+}
+
+void hci_conn_add_sysfs(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+ bdaddr_t *ba = &conn->dst;
+
+ BT_DBG("conn %p", conn);
+
+ conn->dev.parent = &hdev->dev;
+ conn->dev.release = bt_release;
+
+ snprintf(conn->dev.bus_id, BUS_ID_SIZE,
+ "%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
+ conn->type == ACL_LINK ? "acl" : "sco",
+ ba->b[5], ba->b[4], ba->b[3],
+ ba->b[2], ba->b[1], ba->b[0]);
+
+ dev_set_drvdata(&conn->dev, conn);
+
+ INIT_WORK(&conn->work, add_conn, (void *) conn);
+
+ schedule_work(&conn->work);
+}
+
+static void del_conn(void *data)
+{
+ struct hci_conn *conn = data;
+ device_del(&conn->dev);
+}
+
+void hci_conn_del_sysfs(struct hci_conn *conn)
+{
+ BT_DBG("conn %p", conn);
+
+ INIT_WORK(&conn->work, del_conn, (void *) conn);
+
+ schedule_work(&conn->work);
}
int hci_register_sysfs(struct hci_dev *hdev)
@@ -190,11 +299,7 @@ int hci_register_sysfs(struct hci_dev *hdev)
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
dev->class = bt_class;
-
- if (hdev->parent)
- dev->parent = hdev->parent;
- else
- dev->parent = &bt_platform->dev;
+ dev->parent = hdev->parent;
strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
@@ -207,18 +312,17 @@ int hci_register_sysfs(struct hci_dev *hdev)
return err;
for (i = 0; bt_attrs[i]; i++)
- device_create_file(dev, bt_attrs[i]);
+ if (device_create_file(dev, bt_attrs[i]) < 0)
+ BT_ERR("Failed to create device attribute");
return 0;
}
void hci_unregister_sysfs(struct hci_dev *hdev)
{
- struct device *dev = &hdev->dev;
-
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
- device_del(dev);
+ device_del(&hdev->dev);
}
int __init bt_sysfs_init(void)
@@ -245,7 +349,7 @@ int __init bt_sysfs_init(void)
return 0;
}
-void __exit bt_sysfs_cleanup(void)
+void bt_sysfs_cleanup(void)
{
class_destroy(bt_class);
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index c6e3a2c27c6e..66782010f82c 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -40,6 +40,7 @@
#include <linux/input.h>
#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include "hidp.h"
@@ -506,14 +507,12 @@ static int hidp_session(void *arg)
hidp_del_timer(session);
- if (intr_sk->sk_state != BT_CONNECTED)
- wait_event_timeout(*(ctrl_sk->sk_sleep), (ctrl_sk->sk_state == BT_CLOSED), HZ);
-
- fput(session->ctrl_sock->file);
+ fput(session->intr_sock->file);
- wait_event_timeout(*(intr_sk->sk_sleep), (intr_sk->sk_state == BT_CLOSED), HZ);
+ wait_event_timeout(*(ctrl_sk->sk_sleep),
+ (ctrl_sk->sk_state == BT_CLOSED), msecs_to_jiffies(500));
- fput(session->intr_sock->file);
+ fput(session->ctrl_sock->file);
__hidp_unlink_session(session);
@@ -528,6 +527,24 @@ static int hidp_session(void *arg)
return 0;
}
+static struct device *hidp_get_device(struct hidp_session *session)
+{
+ bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
+ bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+
+ hdev = hci_get_route(dst, src);
+ if (!hdev)
+ return NULL;
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+
+ hci_dev_put(hdev);
+
+ return conn ? &conn->dev : NULL;
+}
+
static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req)
{
struct input_dev *input = session->input;
@@ -566,6 +583,8 @@ 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->event = hidp_input_event;
input_register_device(input);
diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c
index 099646e4e2ef..407fba43c1b9 100644
--- a/net/bluetooth/hidp/sock.c
+++ b/net/bluetooth/hidp/sock.c
@@ -35,6 +35,7 @@
#include <linux/ioctl.h>
#include <linux/file.h>
#include <linux/init.h>
+#include <linux/compat.h>
#include <net/sock.h>
#include "hidp.h"
@@ -143,11 +144,88 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+struct compat_hidp_connadd_req {
+ int ctrl_sock; // Connected control socket
+ int intr_sock; // Connteted interrupt socket
+ __u16 parser;
+ __u16 rd_size;
+ compat_uptr_t rd_data;
+ __u8 country;
+ __u8 subclass;
+ __u16 vendor;
+ __u16 product;
+ __u16 version;
+ __u32 flags;
+ __u32 idle_to;
+ char name[128];
+};
+
+static int hidp_sock_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+ if (cmd == HIDPGETCONNLIST) {
+ struct hidp_connlist_req cl;
+ uint32_t uci;
+ int err;
+
+ if (get_user(cl.cnum, (uint32_t __user *) arg) ||
+ get_user(uci, (u32 __user *) (arg + 4)))
+ return -EFAULT;
+
+ cl.ci = compat_ptr(uci);
+
+ if (cl.cnum <= 0)
+ return -EINVAL;
+
+ err = hidp_get_connlist(&cl);
+
+ if (!err && put_user(cl.cnum, (uint32_t __user *) arg))
+ err = -EFAULT;
+
+ return err;
+ } else if (cmd == HIDPCONNADD) {
+ struct compat_hidp_connadd_req ca;
+ struct hidp_connadd_req __user *uca;
+
+ uca = compat_alloc_user_space(sizeof(*uca));
+
+ if (copy_from_user(&ca, (void *) arg, sizeof(ca)))
+ return -EFAULT;
+
+ if (put_user(ca.ctrl_sock, &uca->ctrl_sock) ||
+ put_user(ca.intr_sock, &uca->intr_sock) ||
+ put_user(ca.parser, &uca->parser) ||
+ put_user(ca.rd_size, &uca->parser) ||
+ put_user(compat_ptr(ca.rd_data), &uca->rd_data) ||
+ put_user(ca.country, &uca->country) ||
+ put_user(ca.subclass, &uca->subclass) ||
+ put_user(ca.vendor, &uca->vendor) ||
+ put_user(ca.product, &uca->product) ||
+ put_user(ca.version, &uca->version) ||
+ put_user(ca.flags, &uca->flags) ||
+ put_user(ca.idle_to, &uca->idle_to) ||
+ copy_to_user(&uca->name[0], &ca.name[0], 128))
+ return -EFAULT;
+
+ arg = (unsigned long) uca;
+
+ /* Fall through. We don't actually write back any _changes_
+ to the structure anyway, so there's no need to copy back
+ into the original compat version */
+ }
+
+ return hidp_sock_ioctl(sock, cmd, arg);
+}
+#endif
+
static const struct proto_ops hidp_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.release = hidp_sock_release,
.ioctl = hidp_sock_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hidp_sock_compat_ioctl,
+#endif
.bind = sock_no_bind,
.getname = sock_no_getname,
.sendmsg = sock_no_sendmsg,
@@ -178,7 +256,7 @@ static int hidp_sock_create(struct socket *sock, int protocol)
if (sock->type != SOCK_RAW)
return -ESOCKTNOSUPPORT;
- sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, &hidp_proto, 1);
+ sk = sk_alloc(PF_BLUETOOTH, GFP_ATOMIC, &hidp_proto, 1);
if (!sk)
return -ENOMEM;
diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
index d56f60b392ac..2b3dcb8f90fa 100644
--- a/net/bluetooth/l2cap.c
+++ b/net/bluetooth/l2cap.c
@@ -559,7 +559,7 @@ static int l2cap_sock_create(struct socket *sock, int protocol)
sock->ops = &l2cap_sock_ops;
- sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL);
+ sk = l2cap_sock_alloc(sock, protocol, GFP_ATOMIC);
if (!sk)
return -ENOMEM;
@@ -2216,7 +2216,8 @@ static int __init l2cap_init(void)
goto error;
}
- class_create_file(bt_class, &class_attr_l2cap);
+ if (class_create_file(bt_class, &class_attr_l2cap) < 0)
+ BT_ERR("Failed to create L2CAP info file");
BT_INFO("L2CAP ver %s", VERSION);
BT_INFO("L2CAP socket layer initialized");
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 332dd8f436ea..ddc4e9d5963e 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -644,7 +644,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM);
*err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
- if (*err == 0 || *err == -EAGAIN)
+ if (*err == 0 || *err == -EINPROGRESS)
return s;
rfcomm_session_del(s);
@@ -2058,7 +2058,8 @@ static int __init rfcomm_init(void)
kernel_thread(rfcomm_run, NULL, CLONE_KERNEL);
- class_create_file(bt_class, &class_attr_rfcomm_dlc);
+ if (class_create_file(bt_class, &class_attr_rfcomm_dlc) < 0)
+ BT_ERR("Failed to create RFCOMM info file");
rfcomm_init_sockets();
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 220fee04e7f2..544d65b7baa7 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -336,7 +336,8 @@ static int rfcomm_sock_create(struct socket *sock, int protocol)
sock->ops = &rfcomm_sock_ops;
- if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL)))
+ sk = rfcomm_sock_alloc(sock, protocol, GFP_ATOMIC);
+ if (!sk)
return -ENOMEM;
rfcomm_sock_init(sk, NULL);
@@ -944,7 +945,8 @@ int __init rfcomm_init_sockets(void)
if (err < 0)
goto error;
- class_create_file(bt_class, &class_attr_rfcomm);
+ if (class_create_file(bt_class, &class_attr_rfcomm) < 0)
+ BT_ERR("Failed to create RFCOMM info file");
BT_INFO("RFCOMM socket layer initialized");
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index bd8d671a0ba6..b8e3a5f1c8a8 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -38,6 +38,7 @@
#include <linux/skbuff.h>
#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/rfcomm.h>
#ifndef CONFIG_BT_RFCOMM_DEBUG
@@ -161,6 +162,22 @@ static inline struct rfcomm_dev *rfcomm_dev_get(int id)
return dev;
}
+static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
+{
+ struct hci_dev *hdev;
+ struct hci_conn *conn;
+
+ hdev = hci_get_route(&dev->dst, &dev->src);
+ if (!hdev)
+ return NULL;
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
+
+ hci_dev_put(hdev);
+
+ return conn ? &conn->dev : NULL;
+}
+
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
{
struct rfcomm_dev *dev;
@@ -244,7 +261,7 @@ out:
return err;
}
- tty_register_device(rfcomm_tty_driver, dev->id, NULL);
+ tty_register_device(rfcomm_tty_driver, dev->id, rfcomm_get_device(dev));
return dev->id;
}
@@ -748,6 +765,9 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old)
BT_DBG("tty %p termios %p", tty, old);
+ if (!dev)
+ return;
+
/* Handle turning off CRTSCTS */
if ((old->c_cflag & CRTSCTS) && !(new->c_cflag & CRTSCTS))
BT_DBG("Turning off CRTSCTS unsupported");
@@ -992,7 +1012,7 @@ static int rfcomm_tty_tiocmset(struct tty_struct *tty, struct file *filp, unsign
/* ---- TTY structure ---- */
-static struct tty_operations rfcomm_ops = {
+static const struct tty_operations rfcomm_ops = {
.open = rfcomm_tty_open,
.close = rfcomm_tty_close,
.write = rfcomm_tty_write,
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index 7714a2ec3854..5d13d4f31753 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -452,7 +452,8 @@ static int sco_sock_create(struct socket *sock, int protocol)
sock->ops = &sco_sock_ops;
- if (!(sk = sco_sock_alloc(sock, protocol, GFP_KERNEL)))
+ sk = sco_sock_alloc(sock, protocol, GFP_ATOMIC);
+ if (!sk)
return -ENOMEM;
sco_sock_init(sk, NULL);
@@ -967,7 +968,8 @@ static int __init sco_init(void)
goto error;
}
- class_create_file(bt_class, &class_attr_sco);
+ if (class_create_file(bt_class, &class_attr_sco) < 0)
+ BT_ERR("Failed to create SCO info file");
BT_INFO("SCO (Voice Link) ver %s", VERSION);
BT_INFO("SCO socket layer initialized");
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 3a73b8c94271..d9f04864d15d 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -128,7 +128,10 @@ void br_fdb_cleanup(unsigned long _data)
mod_timer(&br->gc_timer, jiffies + HZ/10);
}
-void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
+
+void br_fdb_delete_by_port(struct net_bridge *br,
+ const struct net_bridge_port *p,
+ int do_all)
{
int i;
@@ -142,6 +145,8 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p)
if (f->dst != p)
continue;
+ if (f->is_static && !do_all)
+ continue;
/*
* if multiple ports all have the same device address
* then when one port is deleted, assign
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index b1211d5342f6..f753c40c11d2 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -163,7 +163,7 @@ static void del_nbp(struct net_bridge_port *p)
br_stp_disable_port(p);
spin_unlock_bh(&br->lock);
- br_fdb_delete_by_port(br, p);
+ br_fdb_delete_by_port(br, p, 1);
list_del_rcu(&p->list);
@@ -448,7 +448,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
return 0;
err2:
- br_fdb_delete_by_port(br, p);
+ br_fdb_delete_by_port(br, p, 1);
err1:
kobject_del(&p->kobj);
err0:
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index c491fb2f280e..74258d86f256 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -143,7 +143,7 @@ extern void br_fdb_changeaddr(struct net_bridge_port *p,
const unsigned char *newaddr);
extern void br_fdb_cleanup(unsigned long arg);
extern void br_fdb_delete_by_port(struct net_bridge *br,
- struct net_bridge_port *p);
+ const struct net_bridge_port *p, int do_all);
extern struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br,
const unsigned char *addr);
extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index 14cd025079af..d294224592db 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -113,6 +113,8 @@ void br_stp_disable_port(struct net_bridge_port *p)
del_timer(&p->forward_delay_timer);
del_timer(&p->hold_timer);
+ br_fdb_delete_by_port(br, p, 0);
+
br_configuration_update(br);
br_port_state_selection(br);
diff --git a/net/bridge/netfilter/ebt_arpreply.c b/net/bridge/netfilter/ebt_arpreply.c
index d19fc4b328dc..0aa7b9910a86 100644
--- a/net/bridge/netfilter/ebt_arpreply.c
+++ b/net/bridge/netfilter/ebt_arpreply.c
@@ -20,7 +20,7 @@ static int ebt_target_reply(struct sk_buff **pskb, unsigned int hooknr,
const void *data, unsigned int datalen)
{
struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
- u32 _sip, *siptr, _dip, *diptr;
+ __be32 _sip, *siptr, _dip, *diptr;
struct arphdr _ah, *ap;
unsigned char _sha[ETH_ALEN], *shp;
struct sk_buff *skb = *pskb;
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index 770c0df972a3..b54306a934e5 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -22,24 +22,37 @@ static int ebt_target_mark(struct sk_buff **pskb, unsigned int hooknr,
const void *data, unsigned int datalen)
{
struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+ int action = info->target & -16;
- if ((*pskb)->nfmark != info->mark)
+ if (action == MARK_SET_VALUE)
(*pskb)->nfmark = info->mark;
+ else if (action == MARK_OR_VALUE)
+ (*pskb)->nfmark |= info->mark;
+ else if (action == MARK_AND_VALUE)
+ (*pskb)->nfmark &= info->mark;
+ else
+ (*pskb)->nfmark ^= info->mark;
- return info->target;
+ return info->target | -16;
}
static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
const struct ebt_entry *e, void *data, unsigned int datalen)
{
struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
+ int tmp;
if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
return -EINVAL;
- if (BASE_CHAIN && info->target == EBT_RETURN)
+ tmp = info->target | -16;
+ if (BASE_CHAIN && tmp == EBT_RETURN)
return -EINVAL;
CLEAR_BASE_CHAIN_BIT;
- if (INVALID_TARGET)
+ if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0)
+ return -EINVAL;
+ tmp = info->target & -16;
+ if (tmp != MARK_SET_VALUE && tmp != MARK_OR_VALUE &&
+ tmp != MARK_AND_VALUE && tmp != MARK_XOR_VALUE)
return -EINVAL;
return 0;
}
diff --git a/net/compat.c b/net/compat.c
index d5d69fa15d07..52d32f1bc728 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -285,8 +285,7 @@ void scm_detach_fds_compat(struct msghdr *kmsg, struct scm_cookie *scm)
if (i > 0) {
int cmlen = CMSG_COMPAT_LEN(i * sizeof(int));
- if (!err)
- err = put_user(SOL_SOCKET, &cm->cmsg_level);
+ err = put_user(SOL_SOCKET, &cm->cmsg_level);
if (!err)
err = put_user(SCM_RIGHTS, &cm->cmsg_type);
if (!err)
diff --git a/net/core/dev.c b/net/core/dev.c
index 14de297d024d..81c426adcd1e 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -1480,14 +1480,16 @@ gso:
if (q->enqueue) {
/* Grab device queue */
spin_lock(&dev->queue_lock);
+ q = dev->qdisc;
+ if (q->enqueue) {
+ rc = q->enqueue(skb, q);
+ qdisc_run(dev);
+ spin_unlock(&dev->queue_lock);
- rc = q->enqueue(skb, q);
-
- qdisc_run(dev);
-
+ rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
+ goto out;
+ }
spin_unlock(&dev->queue_lock);
- rc = rc == NET_XMIT_BYPASS ? NET_XMIT_SUCCESS : rc;
- goto out;
}
/* The device has no queue. Common case for software devices:
@@ -3500,8 +3502,6 @@ static int __init net_dev_init(void)
BUG_ON(!dev_boot_phase);
- net_random_init();
-
if (dev_proc_init())
goto out;
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index e0ca04f38cef..87dc556fd9d6 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -806,13 +806,6 @@ int dev_ethtool(struct ifreq *ifr)
int rc;
unsigned long old_features;
- /*
- * XXX: This can be pushed down into the ethtool_* handlers that
- * need it. Keep existing behaviour for the moment.
- */
- if (!capable(CAP_NET_ADMIN))
- return -EPERM;
-
if (!dev || !netif_device_present(dev))
return -ENODEV;
@@ -822,6 +815,27 @@ int dev_ethtool(struct ifreq *ifr)
if (copy_from_user(&ethcmd, useraddr, sizeof (ethcmd)))
return -EFAULT;
+ /* Allow some commands to be done by anyone */
+ switch(ethcmd) {
+ case ETHTOOL_GDRVINFO:
+ case ETHTOOL_GMSGLVL:
+ case ETHTOOL_GCOALESCE:
+ case ETHTOOL_GRINGPARAM:
+ case ETHTOOL_GPAUSEPARAM:
+ case ETHTOOL_GRXCSUM:
+ case ETHTOOL_GTXCSUM:
+ case ETHTOOL_GSG:
+ case ETHTOOL_GSTRINGS:
+ case ETHTOOL_GTSO:
+ case ETHTOOL_GPERMADDR:
+ case ETHTOOL_GUFO:
+ case ETHTOOL_GGSO:
+ break;
+ default:
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ }
+
if(dev->ethtool_ops->begin)
if ((rc = dev->ethtool_ops->begin(dev)) < 0)
return rc;
@@ -947,6 +961,10 @@ int dev_ethtool(struct ifreq *ifr)
return rc;
ioctl:
+ /* Keep existing behaviour for the moment. */
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
if (dev->do_ioctl)
return dev->do_ioctl(dev, ifr, SIOCETHTOOL);
return -EOPNOTSUPP;
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index a99d87d82b7f..6b0e63cacd93 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -8,7 +8,6 @@
* Authors: Thomas Graf <tgraf@suug.ch>
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/list.h>
diff --git a/net/core/flow.c b/net/core/flow.c
index f23e7e386543..b16d31ae5e54 100644
--- a/net/core/flow.c
+++ b/net/core/flow.c
@@ -85,6 +85,14 @@ static void flow_cache_new_hashrnd(unsigned long arg)
add_timer(&flow_hash_rnd_timer);
}
+static void flow_entry_kill(int cpu, struct flow_cache_entry *fle)
+{
+ if (fle->object)
+ atomic_dec(fle->object_ref);
+ kmem_cache_free(flow_cachep, fle);
+ flow_count(cpu)--;
+}
+
static void __flow_cache_shrink(int cpu, int shrink_to)
{
struct flow_cache_entry *fle, **flp;
@@ -100,10 +108,7 @@ static void __flow_cache_shrink(int cpu, int shrink_to)
}
while ((fle = *flp) != NULL) {
*flp = fle->next;
- if (fle->object)
- atomic_dec(fle->object_ref);
- kmem_cache_free(flow_cachep, fle);
- flow_count(cpu)--;
+ flow_entry_kill(cpu, fle);
}
}
}
@@ -220,24 +225,33 @@ void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
nocache:
{
+ int err;
void *obj;
atomic_t *obj_ref;
- resolver(key, family, dir, &obj, &obj_ref);
+ err = resolver(key, family, dir, &obj, &obj_ref);
if (fle) {
- fle->genid = atomic_read(&flow_cache_genid);
-
- if (fle->object)
- atomic_dec(fle->object_ref);
-
- fle->object = obj;
- fle->object_ref = obj_ref;
- if (obj)
- atomic_inc(fle->object_ref);
+ if (err) {
+ /* Force security policy check on next lookup */
+ *head = fle->next;
+ flow_entry_kill(cpu, fle);
+ } else {
+ fle->genid = atomic_read(&flow_cache_genid);
+
+ if (fle->object)
+ atomic_dec(fle->object_ref);
+
+ fle->object = obj;
+ fle->object_ref = obj_ref;
+ if (obj)
+ atomic_inc(fle->object_ref);
+ }
}
local_bh_enable();
+ if (err)
+ obj = ERR_PTR(err);
return obj;
}
}
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index b6c69e1463e8..b4b478353b27 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -344,12 +344,12 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey,
{
struct neighbour *n;
int key_len = tbl->key_len;
- u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask;
+ u32 hash_val = tbl->hash(pkey, dev);
NEIGH_CACHE_STAT_INC(tbl, lookups);
read_lock_bh(&tbl->lock);
- for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
+ for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) {
neigh_hold(n);
NEIGH_CACHE_STAT_INC(tbl, hits);
@@ -364,12 +364,12 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey)
{
struct neighbour *n;
int key_len = tbl->key_len;
- u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask;
+ u32 hash_val = tbl->hash(pkey, NULL);
NEIGH_CACHE_STAT_INC(tbl, lookups);
read_lock_bh(&tbl->lock);
- for (n = tbl->hash_buckets[hash_val]; n; n = n->next) {
+ for (n = tbl->hash_buckets[hash_val & tbl->hash_mask]; n; n = n->next) {
if (!memcmp(n->primary_key, pkey, key_len)) {
neigh_hold(n);
NEIGH_CACHE_STAT_INC(tbl, hits);
@@ -1079,7 +1079,7 @@ struct neighbour *neigh_event_ns(struct neigh_table *tbl,
}
static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
- u16 protocol)
+ __be16 protocol)
{
struct hh_cache *hh;
struct net_device *dev = dst->dev;
@@ -1998,12 +1998,12 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
int rc, h, s_h = cb->args[1];
int idx, s_idx = idx = cb->args[2];
+ read_lock_bh(&tbl->lock);
for (h = 0; h <= tbl->hash_mask; h++) {
if (h < s_h)
continue;
if (h > s_h)
s_idx = 0;
- read_lock_bh(&tbl->lock);
for (n = tbl->hash_buckets[h], idx = 0; n; n = n->next, idx++) {
if (idx < s_idx)
continue;
@@ -2016,8 +2016,8 @@ static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb,
goto out;
}
}
- read_unlock_bh(&tbl->lock);
}
+ read_unlock_bh(&tbl->lock);
rc = skb->len;
out:
cb->args[1] = h;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 13472762b18b..f47f319bb7dc 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -344,8 +344,6 @@ static ssize_t wireless_show(struct class_device *cd, char *buf,
if(dev->wireless_handlers &&
dev->wireless_handlers->get_wireless_stats)
iw = dev->wireless_handlers->get_wireless_stats(dev);
- else if (dev->get_wireless_stats)
- iw = dev->get_wireless_stats(dev);
if (iw != NULL)
ret = (*format)(iw, buf);
}
@@ -465,8 +463,7 @@ int netdev_register_sysfs(struct net_device *net)
*groups++ = &netstat_group;
#ifdef WIRELESS_EXT
- if (net->get_wireless_stats
- || (net->wireless_handlers && net->wireless_handlers->get_wireless_stats))
+ if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
*groups++ = &wireless_group;
#endif
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index ead5920c26d6..9308af060b44 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -335,13 +335,13 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
memcpy(skb->data, msg, len);
skb->len += len;
- udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
+ skb->h.uh = udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
udph->check = 0;
- iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
+ skb->nh.iph = iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
/* iph->version = 4; iph->ihl = 5; */
put_unaligned(0x45, (unsigned char *)iph);
@@ -357,8 +357,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
-
- eth->h_proto = htons(ETH_P_IP);
+ skb->mac.raw = skb->data;
+ skb->protocol = eth->h_proto = htons(ETH_P_IP);
memcpy(eth->h_source, np->local_mac, 6);
memcpy(eth->h_dest, np->remote_mac, 6);
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 72145d4a2600..dd023fd28304 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -109,6 +109,8 @@
*
* MPLS support by Steven Whitehouse <steve@chygwyn.com>
*
+ * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
+ *
*/
#include <linux/sys.h>
#include <linux/types.h>
@@ -137,6 +139,7 @@
#include <linux/inetdevice.h>
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
+#include <linux/if_vlan.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
@@ -157,7 +160,7 @@
#include <asm/div64.h> /* do_div */
#include <asm/timex.h>
-#define VERSION "pktgen v2.67: Packet Generator for packet performance testing.\n"
+#define VERSION "pktgen v2.68: Packet Generator for packet performance testing.\n"
/* #define PG_DEBUG(a) a */
#define PG_DEBUG(a)
@@ -178,6 +181,8 @@
#define F_TXSIZE_RND (1<<6) /* Transmit size is random */
#define F_IPV6 (1<<7) /* Interface in IPV6 Mode */
#define F_MPLS_RND (1<<8) /* Random MPLS labels */
+#define F_VID_RND (1<<9) /* Random VLAN ID */
+#define F_SVID_RND (1<<10) /* Random SVLAN ID */
/* Thread control flag bits */
#define T_TERMINATE (1<<0)
@@ -198,6 +203,9 @@ static struct proc_dir_entry *pg_proc_dir = NULL;
#define MAX_CFLOWS 65536
+#define VLAN_TAG_SIZE(x) ((x)->vlan_id == 0xffff ? 0 : 4)
+#define SVLAN_TAG_SIZE(x) ((x)->svlan_id == 0xffff ? 0 : 4)
+
struct flow_state {
__u32 cur_daddr;
int count;
@@ -284,10 +292,23 @@ struct pktgen_dev {
__u16 udp_dst_min; /* inclusive, dest UDP port */
__u16 udp_dst_max; /* exclusive, dest UDP port */
+ /* DSCP + ECN */
+ __u8 tos; /* six most significant bits of (former) IPv4 TOS are for dscp codepoint */
+ __u8 traffic_class; /* ditto for the (former) Traffic Class in IPv6 (see RFC 3260, sec. 4) */
+
/* MPLS */
unsigned nr_labels; /* Depth of stack, 0 = no MPLS */
__be32 labels[MAX_MPLS_LABELS];
+ /* VLAN/SVLAN (802.1Q/Q-in-Q) */
+ __u8 vlan_p;
+ __u8 vlan_cfi;
+ __u16 vlan_id; /* 0xffff means no vlan tag */
+
+ __u8 svlan_p;
+ __u8 svlan_cfi;
+ __u16 svlan_id; /* 0xffff means no svlan tag */
+
__u32 src_mac_count; /* How many MACs to iterate through */
__u32 dst_mac_count; /* How many MACs to iterate through */
@@ -644,6 +665,24 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
i == pkt_dev->nr_labels-1 ? "\n" : ", ");
}
+ if (pkt_dev->vlan_id != 0xffff) {
+ seq_printf(seq, " vlan_id: %u vlan_p: %u vlan_cfi: %u\n",
+ pkt_dev->vlan_id, pkt_dev->vlan_p, pkt_dev->vlan_cfi);
+ }
+
+ if (pkt_dev->svlan_id != 0xffff) {
+ seq_printf(seq, " svlan_id: %u vlan_p: %u vlan_cfi: %u\n",
+ pkt_dev->svlan_id, pkt_dev->svlan_p, pkt_dev->svlan_cfi);
+ }
+
+ if (pkt_dev->tos) {
+ seq_printf(seq, " tos: 0x%02x\n", pkt_dev->tos);
+ }
+
+ if (pkt_dev->traffic_class) {
+ seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class);
+ }
+
seq_printf(seq, " Flags: ");
if (pkt_dev->flags & F_IPV6)
@@ -673,6 +712,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
if (pkt_dev->flags & F_MACDST_RND)
seq_printf(seq, "MACDST_RND ");
+ if (pkt_dev->flags & F_VID_RND)
+ seq_printf(seq, "VID_RND ");
+
+ if (pkt_dev->flags & F_SVID_RND)
+ seq_printf(seq, "SVID_RND ");
+
seq_puts(seq, "\n");
sa = pkt_dev->started_at;
@@ -715,12 +760,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
}
-static int hex32_arg(const char __user *user_buffer, __u32 *num)
+static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32 *num)
{
int i = 0;
*num = 0;
- for(; i < 8; i++) {
+ for(; i < maxlen; i++) {
char c;
*num <<= 4;
if (get_user(c, &user_buffer[i]))
@@ -815,7 +860,7 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
pkt_dev->nr_labels = 0;
do {
__u32 tmp;
- len = hex32_arg(&buffer[i], &tmp);
+ len = hex32_arg(&buffer[i], 8, &tmp);
if (len <= 0)
return len;
pkt_dev->labels[n] = htonl(tmp);
@@ -1140,11 +1185,27 @@ static ssize_t pktgen_if_write(struct file *file,
else if (strcmp(f, "!MPLS_RND") == 0)
pkt_dev->flags &= ~F_MPLS_RND;
+ else if (strcmp(f, "VID_RND") == 0)
+ pkt_dev->flags |= F_VID_RND;
+
+ else if (strcmp(f, "!VID_RND") == 0)
+ pkt_dev->flags &= ~F_VID_RND;
+
+ else if (strcmp(f, "SVID_RND") == 0)
+ pkt_dev->flags |= F_SVID_RND;
+
+ else if (strcmp(f, "!SVID_RND") == 0)
+ pkt_dev->flags &= ~F_SVID_RND;
+
+ else if (strcmp(f, "!IPV6") == 0)
+ pkt_dev->flags &= ~F_IPV6;
+
else {
sprintf(pg_result,
"Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
f,
- "IPSRC_RND, IPDST_RND, TXSIZE_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
+ "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
+ "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND\n");
return count;
}
sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
@@ -1445,6 +1506,160 @@ static ssize_t pktgen_if_write(struct file *file,
offset += sprintf(pg_result + offset,
"%08x%s", ntohl(pkt_dev->labels[n]),
n == pkt_dev->nr_labels-1 ? "" : ",");
+
+ if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
+ pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
+ pkt_dev->svlan_id = 0xffff;
+
+ if (debug)
+ printk("pktgen: VLAN/SVLAN auto turned off\n");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "vlan_id")) {
+ len = num_arg(&user_buffer[i], 4, &value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if (value <= 4095) {
+ pkt_dev->vlan_id = value; /* turn on VLAN */
+
+ if (debug)
+ printk("pktgen: VLAN turned on\n");
+
+ if (debug && pkt_dev->nr_labels)
+ printk("pktgen: MPLS auto turned off\n");
+
+ pkt_dev->nr_labels = 0; /* turn off MPLS */
+ sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
+ } else {
+ pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
+ pkt_dev->svlan_id = 0xffff;
+
+ if (debug)
+ printk("pktgen: VLAN/SVLAN turned off\n");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "vlan_p")) {
+ len = num_arg(&user_buffer[i], 1, &value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if ((value <= 7) && (pkt_dev->vlan_id != 0xffff)) {
+ pkt_dev->vlan_p = value;
+ sprintf(pg_result, "OK: vlan_p=%u", pkt_dev->vlan_p);
+ } else {
+ sprintf(pg_result, "ERROR: vlan_p must be 0-7");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "vlan_cfi")) {
+ len = num_arg(&user_buffer[i], 1, &value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if ((value <= 1) && (pkt_dev->vlan_id != 0xffff)) {
+ pkt_dev->vlan_cfi = value;
+ sprintf(pg_result, "OK: vlan_cfi=%u", pkt_dev->vlan_cfi);
+ } else {
+ sprintf(pg_result, "ERROR: vlan_cfi must be 0-1");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "svlan_id")) {
+ len = num_arg(&user_buffer[i], 4, &value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if ((value <= 4095) && ((pkt_dev->vlan_id != 0xffff))) {
+ pkt_dev->svlan_id = value; /* turn on SVLAN */
+
+ if (debug)
+ printk("pktgen: SVLAN turned on\n");
+
+ if (debug && pkt_dev->nr_labels)
+ printk("pktgen: MPLS auto turned off\n");
+
+ pkt_dev->nr_labels = 0; /* turn off MPLS */
+ sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
+ } else {
+ pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
+ pkt_dev->svlan_id = 0xffff;
+
+ if (debug)
+ printk("pktgen: VLAN/SVLAN turned off\n");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "svlan_p")) {
+ len = num_arg(&user_buffer[i], 1, &value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if ((value <= 7) && (pkt_dev->svlan_id != 0xffff)) {
+ pkt_dev->svlan_p = value;
+ sprintf(pg_result, "OK: svlan_p=%u", pkt_dev->svlan_p);
+ } else {
+ sprintf(pg_result, "ERROR: svlan_p must be 0-7");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "svlan_cfi")) {
+ len = num_arg(&user_buffer[i], 1, &value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if ((value <= 1) && (pkt_dev->svlan_id != 0xffff)) {
+ pkt_dev->svlan_cfi = value;
+ sprintf(pg_result, "OK: svlan_cfi=%u", pkt_dev->svlan_cfi);
+ } else {
+ sprintf(pg_result, "ERROR: svlan_cfi must be 0-1");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "tos")) {
+ __u32 tmp_value = 0;
+ len = hex32_arg(&user_buffer[i], 2, &tmp_value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if (len == 2) {
+ pkt_dev->tos = tmp_value;
+ sprintf(pg_result, "OK: tos=0x%02x", pkt_dev->tos);
+ } else {
+ sprintf(pg_result, "ERROR: tos must be 00-ff");
+ }
+ return count;
+ }
+
+ if (!strcmp(name, "traffic_class")) {
+ __u32 tmp_value = 0;
+ len = hex32_arg(&user_buffer[i], 2, &tmp_value);
+ if (len < 0) {
+ return len;
+ }
+ i += len;
+ if (len == 2) {
+ pkt_dev->traffic_class = tmp_value;
+ sprintf(pg_result, "OK: traffic_class=0x%02x", pkt_dev->traffic_class);
+ } else {
+ sprintf(pg_result, "ERROR: traffic_class must be 00-ff");
+ }
return count;
}
@@ -1949,6 +2164,14 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
htonl(0x000fffff));
}
+ if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
+ pkt_dev->vlan_id = pktgen_random() % 4096;
+ }
+
+ if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
+ pkt_dev->svlan_id = pktgen_random() % 4096;
+ }
+
if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
if (pkt_dev->flags & F_UDPSRC_RND)
pkt_dev->cur_udp_src =
@@ -2092,10 +2315,18 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
struct pktgen_hdr *pgh = NULL;
__be16 protocol = __constant_htons(ETH_P_IP);
__be32 *mpls;
+ __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */
+ __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */
+ __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */
+ __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
+
if (pkt_dev->nr_labels)
protocol = __constant_htons(ETH_P_MPLS_UC);
+ if (pkt_dev->vlan_id != 0xffff)
+ protocol = __constant_htons(ETH_P_8021Q);
+
/* Update any of the values, used when we're incrementing various
* fields.
*/
@@ -2103,7 +2334,9 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
datalen = (odev->hard_header_len + 16) & ~0xf;
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
- pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC);
+ pkt_dev->nr_labels*sizeof(u32) +
+ VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
+ GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
@@ -2116,6 +2349,24 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
if (pkt_dev->nr_labels)
mpls_push(mpls, pkt_dev);
+
+ if (pkt_dev->vlan_id != 0xffff) {
+ if(pkt_dev->svlan_id != 0xffff) {
+ svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
+ *svlan_tci = htons(pkt_dev->svlan_id);
+ *svlan_tci |= pkt_dev->svlan_p << 5;
+ *svlan_tci |= pkt_dev->svlan_cfi << 4;
+ svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
+ *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
+ }
+ vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
+ *vlan_tci = htons(pkt_dev->vlan_id);
+ *vlan_tci |= pkt_dev->vlan_p << 5;
+ *vlan_tci |= pkt_dev->vlan_cfi << 4;
+ vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
+ *vlan_encapsulated_proto = __constant_htons(ETH_P_IP);
+ }
+
iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
@@ -2124,7 +2375,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
/* Eth + IPh + UDPh + mpls */
datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
- pkt_dev->nr_labels*sizeof(u32);
+ pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
if (datalen < sizeof(struct pktgen_hdr))
datalen = sizeof(struct pktgen_hdr);
@@ -2136,7 +2387,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
iph->ihl = 5;
iph->version = 4;
iph->ttl = 32;
- iph->tos = 0;
+ iph->tos = pkt_dev->tos;
iph->protocol = IPPROTO_UDP; /* UDP */
iph->saddr = pkt_dev->cur_saddr;
iph->daddr = pkt_dev->cur_daddr;
@@ -2146,7 +2397,8 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
iph->check = 0;
iph->check = ip_fast_csum((void *)iph, iph->ihl);
skb->protocol = protocol;
- skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
+ skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) -
+ VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
skb->dev = odev;
skb->pkt_type = PACKET_HOST;
skb->nh.iph = iph;
@@ -2218,7 +2470,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
pgh->tv_sec = htonl(timestamp.tv_sec);
pgh->tv_usec = htonl(timestamp.tv_usec);
}
- pkt_dev->seq_num++;
return skb;
}
@@ -2402,17 +2653,26 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
struct pktgen_hdr *pgh = NULL;
__be16 protocol = __constant_htons(ETH_P_IPV6);
__be32 *mpls;
+ __be16 *vlan_tci = NULL; /* Encapsulates priority and VLAN ID */
+ __be16 *vlan_encapsulated_proto = NULL; /* packet type ID field (or len) for VLAN tag */
+ __be16 *svlan_tci = NULL; /* Encapsulates priority and SVLAN ID */
+ __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
if (pkt_dev->nr_labels)
protocol = __constant_htons(ETH_P_MPLS_UC);
+ if (pkt_dev->vlan_id != 0xffff)
+ protocol = __constant_htons(ETH_P_8021Q);
+
/* Update any of the values, used when we're incrementing various
* fields.
*/
mod_cur_headers(pkt_dev);
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
- pkt_dev->nr_labels*sizeof(u32), GFP_ATOMIC);
+ pkt_dev->nr_labels*sizeof(u32) +
+ VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
+ GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
return NULL;
@@ -2425,16 +2685,34 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
mpls = (__be32 *)skb_put(skb, pkt_dev->nr_labels*sizeof(__u32));
if (pkt_dev->nr_labels)
mpls_push(mpls, pkt_dev);
+
+ if (pkt_dev->vlan_id != 0xffff) {
+ if(pkt_dev->svlan_id != 0xffff) {
+ svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
+ *svlan_tci = htons(pkt_dev->svlan_id);
+ *svlan_tci |= pkt_dev->svlan_p << 5;
+ *svlan_tci |= pkt_dev->svlan_cfi << 4;
+ svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
+ *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
+ }
+ vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
+ *vlan_tci = htons(pkt_dev->vlan_id);
+ *vlan_tci |= pkt_dev->vlan_p << 5;
+ *vlan_tci |= pkt_dev->vlan_cfi << 4;
+ vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
+ *vlan_encapsulated_proto = __constant_htons(ETH_P_IPV6);
+ }
+
iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
memcpy(eth, pkt_dev->hh, 12);
- *(u16 *) & eth[12] = __constant_htons(ETH_P_IPV6);
+ *(u16 *) & eth[12] = protocol;
/* Eth + IPh + UDPh + mpls */
datalen = pkt_dev->cur_pkt_size - 14 -
sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
- pkt_dev->nr_labels*sizeof(u32);
+ pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
if (datalen < sizeof(struct pktgen_hdr)) {
datalen = sizeof(struct pktgen_hdr);
@@ -2450,6 +2728,11 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
*(u32 *) iph = __constant_htonl(0x60000000); /* Version + flow */
+ if (pkt_dev->traffic_class) {
+ /* Version + traffic class + flow (0) */
+ *(u32 *)iph |= htonl(0x60000000 | (pkt_dev->traffic_class << 20));
+ }
+
iph->hop_limit = 32;
iph->payload_len = htons(sizeof(struct udphdr) + datalen);
@@ -2458,7 +2741,8 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
- skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32);
+ skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) -
+ VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
skb->protocol = protocol;
skb->dev = odev;
skb->pkt_type = PACKET_HOST;
@@ -2531,7 +2815,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
pgh->tv_sec = htonl(timestamp.tv_sec);
pgh->tv_usec = htonl(timestamp.tv_usec);
}
- pkt_dev->seq_num++;
+ /* pkt_dev->seq_num++; FF: you really mean this? */
return skb;
}
@@ -3177,6 +3461,13 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
pkt_dev->udp_dst_min = 9;
pkt_dev->udp_dst_max = 9;
+ pkt_dev->vlan_p = 0;
+ pkt_dev->vlan_cfi = 0;
+ pkt_dev->vlan_id = 0xffff;
+ pkt_dev->svlan_p = 0;
+ pkt_dev->svlan_cfi = 0;
+ pkt_dev->svlan_id = 0xffff;
+
strncpy(pkt_dev->ifname, ifname, IFNAMSIZ);
if (!pktgen_setup_dev(pkt_dev)) {
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index d8e25e08cb7e..02f3c7947898 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -562,7 +562,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy);
if (err < 0)
- goto errout;
+ return err;
ifm = nlmsg_data(nlh);
if (ifm->ifi_index >= 0) {
@@ -602,7 +602,7 @@ static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
goto errout;
}
- err = rtnl_unicast(skb, NETLINK_CB(skb).pid);
+ err = rtnl_unicast(nskb, NETLINK_CB(skb).pid);
errout:
kfree(iw_buf);
dev_put(dev);
diff --git a/net/core/scm.c b/net/core/scm.c
index 649d01ef35b6..271cf060ef8c 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -245,8 +245,7 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
if (i > 0)
{
int cmlen = CMSG_LEN(i*sizeof(int));
- if (!err)
- err = put_user(SOL_SOCKET, &cm->cmsg_level);
+ err = put_user(SOL_SOCKET, &cm->cmsg_level);
if (!err)
err = put_user(SCM_RIGHTS, &cm->cmsg_type);
if (!err)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index c448c7f6fde2..3c23760c5827 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -156,7 +156,8 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
/* Get the DATA. Size must match skb_add_mtu(). */
size = SKB_DATA_ALIGN(size);
- data = ____kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
+ data = kmalloc_track_caller(size + sizeof(struct skb_shared_info),
+ gfp_mask);
if (!data)
goto nodata;
diff --git a/net/core/sock.c b/net/core/sock.c
index b77e155cbe6c..d472db4776c3 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -823,7 +823,7 @@ static void inline sock_lock_init(struct sock *sk)
af_family_slock_key_strings[sk->sk_family]);
lockdep_init_map(&sk->sk_lock.dep_map,
af_family_key_strings[sk->sk_family],
- af_family_keys + sk->sk_family);
+ af_family_keys + sk->sk_family, 0);
}
/**
diff --git a/net/core/utils.c b/net/core/utils.c
index 2682490777de..d93fe64f6693 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -3,7 +3,7 @@
*
* Authors:
* net_random Alan Cox
- * net_ratelimit Andy Kleen
+ * net_ratelimit Andi Kleen
* in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
*
* Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
@@ -30,119 +30,6 @@
#include <asm/system.h>
#include <asm/uaccess.h>
-/*
- This is a maximally equidistributed combined Tausworthe generator
- based on code from GNU Scientific Library 1.5 (30 Jun 2004)
-
- x_n = (s1_n ^ s2_n ^ s3_n)
-
- s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
- s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
- s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
-
- The period of this generator is about 2^88.
-
- From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
- Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
-
- This is available on the net from L'Ecuyer's home page,
-
- http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
- ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps
-
- There is an erratum in the paper "Tables of Maximally
- Equidistributed Combined LFSR Generators", Mathematics of
- Computation, 68, 225 (1999), 261--269:
- http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
-
- ... the k_j most significant bits of z_j must be non-
- zero, for each j. (Note: this restriction also applies to the
- computer code given in [4], but was mistakenly not mentioned in
- that paper.)
-
- This affects the seeding procedure by imposing the requirement
- s1 > 1, s2 > 7, s3 > 15.
-
-*/
-struct nrnd_state {
- u32 s1, s2, s3;
-};
-
-static DEFINE_PER_CPU(struct nrnd_state, net_rand_state);
-
-static u32 __net_random(struct nrnd_state *state)
-{
-#define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
-
- state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
- state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
- state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
-
- return (state->s1 ^ state->s2 ^ state->s3);
-}
-
-static void __net_srandom(struct nrnd_state *state, unsigned long s)
-{
- if (s == 0)
- s = 1; /* default seed is 1 */
-
-#define LCG(n) (69069 * n)
- state->s1 = LCG(s);
- state->s2 = LCG(state->s1);
- state->s3 = LCG(state->s2);
-
- /* "warm it up" */
- __net_random(state);
- __net_random(state);
- __net_random(state);
- __net_random(state);
- __net_random(state);
- __net_random(state);
-}
-
-
-unsigned long net_random(void)
-{
- unsigned long r;
- struct nrnd_state *state = &get_cpu_var(net_rand_state);
- r = __net_random(state);
- put_cpu_var(state);
- return r;
-}
-
-
-void net_srandom(unsigned long entropy)
-{
- struct nrnd_state *state = &get_cpu_var(net_rand_state);
- __net_srandom(state, state->s1^entropy);
- put_cpu_var(state);
-}
-
-void __init net_random_init(void)
-{
- int i;
-
- for_each_possible_cpu(i) {
- struct nrnd_state *state = &per_cpu(net_rand_state,i);
- __net_srandom(state, i+jiffies);
- }
-}
-
-static int net_random_reseed(void)
-{
- int i;
- unsigned long seed;
-
- for_each_possible_cpu(i) {
- struct nrnd_state *state = &per_cpu(net_rand_state,i);
-
- get_random_bytes(&seed, sizeof(seed));
- __net_srandom(state, seed);
- }
- return 0;
-}
-late_initcall(net_random_reseed);
-
int net_msg_cost = 5*HZ;
int net_msg_burst = 10;
@@ -153,10 +40,7 @@ int net_ratelimit(void)
{
return __printk_ratelimit(net_msg_cost, net_msg_burst);
}
-
-EXPORT_SYMBOL(net_random);
EXPORT_SYMBOL(net_ratelimit);
-EXPORT_SYMBOL(net_srandom);
/*
* Convert an ASCII string to binary IP.
diff --git a/net/core/wireless.c b/net/core/wireless.c
index 3168fca312f7..ffff0da46c6e 100644
--- a/net/core/wireless.c
+++ b/net/core/wireless.c
@@ -68,6 +68,14 @@
*
* v8 - 17.02.06 - Jean II
* o RtNetlink requests support (SET/GET)
+ *
+ * v8b - 03.08.06 - Herbert Xu
+ * o Fix Wireless Event locking issues.
+ *
+ * v9 - 14.3.06 - Jean II
+ * o Change length in ESSID and NICK to strlen() instead of strlen()+1
+ * o Make standard_ioctl_num and standard_event_num unsigned
+ * o Remove (struct net_device *)->get_wireless_stats()
*/
/***************************** INCLUDES *****************************/
@@ -234,24 +242,24 @@ static const struct iw_ioctl_description standard_ioctl[] = {
[SIOCSIWESSID - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
- .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ .max_tokens = IW_ESSID_MAX_SIZE,
.flags = IW_DESCR_FLAG_EVENT,
},
[SIOCGIWESSID - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
- .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ .max_tokens = IW_ESSID_MAX_SIZE,
.flags = IW_DESCR_FLAG_DUMP,
},
[SIOCSIWNICKN - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
- .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ .max_tokens = IW_ESSID_MAX_SIZE,
},
[SIOCGIWNICKN - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_POINT,
.token_size = 1,
- .max_tokens = IW_ESSID_MAX_SIZE + 1,
+ .max_tokens = IW_ESSID_MAX_SIZE,
},
[SIOCSIWRATE - SIOCIWFIRST] = {
.header_type = IW_HEADER_TYPE_PARAM,
@@ -338,8 +346,8 @@ static const struct iw_ioctl_description standard_ioctl[] = {
.max_tokens = sizeof(struct iw_pmksa),
},
};
-static const int standard_ioctl_num = (sizeof(standard_ioctl) /
- sizeof(struct iw_ioctl_description));
+static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) /
+ sizeof(struct iw_ioctl_description));
/*
* Meta-data about all the additional standard Wireless Extension events
@@ -389,8 +397,8 @@ static const struct iw_ioctl_description standard_event[] = {
.max_tokens = sizeof(struct iw_pmkid_cand),
},
};
-static const int standard_event_num = (sizeof(standard_event) /
- sizeof(struct iw_ioctl_description));
+static const unsigned standard_event_num = (sizeof(standard_event) /
+ sizeof(struct iw_ioctl_description));
/* Size (in bytes) of the various private data types */
static const char iw_priv_type_size[] = {
@@ -465,17 +473,6 @@ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
(dev->wireless_handlers->get_wireless_stats != NULL))
return dev->wireless_handlers->get_wireless_stats(dev);
- /* Old location, field to be removed in next WE */
- if(dev->get_wireless_stats) {
- static int printed_message;
-
- if (!printed_message++)
- printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n",
- dev->name);
-
- return dev->get_wireless_stats(dev);
- }
-
/* Not found */
return (struct iw_statistics *) NULL;
}
@@ -1843,8 +1840,33 @@ int wireless_rtnetlink_set(struct net_device * dev,
*/
#ifdef WE_EVENT_RTNETLINK
+/* ---------------------------------------------------------------- */
+/*
+ * Locking...
+ * ----------
+ *
+ * Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
+ * the locking issue in here and implementing this code !
+ *
+ * The issue : wireless_send_event() is often called in interrupt context,
+ * while the Netlink layer can never be called in interrupt context.
+ * The fully formed RtNetlink events are queued, and then a tasklet is run
+ * to feed those to Netlink.
+ * The skb_queue is interrupt safe, and its lock is not held while calling
+ * Netlink, so there is no possibility of dealock.
+ * Jean II
+ */
+
static struct sk_buff_head wireless_nlevent_queue;
+static int __init wireless_nlevent_init(void)
+{
+ skb_queue_head_init(&wireless_nlevent_queue);
+ return 0;
+}
+
+subsys_initcall(wireless_nlevent_init);
+
static void wireless_nlevent_process(unsigned long data)
{
struct sk_buff *skb;
@@ -1921,13 +1943,6 @@ static inline void rtmsg_iwinfo(struct net_device * dev,
tasklet_schedule(&wireless_nlevent_tasklet);
}
-static int __init wireless_nlevent_init(void)
-{
- skb_queue_head_init(&wireless_nlevent_queue);
- return 0;
-}
-
-subsys_initcall(wireless_nlevent_init);
#endif /* WE_EVENT_RTNETLINK */
/* ---------------------------------------------------------------- */
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 66be29b6f508..7e746c4c1688 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -50,7 +50,7 @@ int dccp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct dccp_sock *dp = dccp_sk(sk);
const struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct rtable *rt;
- u32 daddr, nexthop;
+ __be32 daddr, nexthop;
int tmp;
int err;
@@ -311,7 +311,7 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
}
if (sk->sk_state == DCCP_TIME_WAIT) {
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
return;
}
@@ -614,7 +614,7 @@ static struct sock *dccp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
bh_lock_sock(nsk);
return nsk;
}
- inet_twsk_put((struct inet_timewait_sock *)nsk);
+ inet_twsk_put(inet_twsk(nsk));
return NULL;
}
@@ -980,7 +980,7 @@ discard_and_relse:
goto discard_it;
do_time_wait:
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
goto no_dccp_socket;
}
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c
index 7a47399cf31f..7171a78671aa 100644
--- a/net/dccp/ipv6.c
+++ b/net/dccp/ipv6.c
@@ -285,7 +285,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
}
if (sk->sk_state == DCCP_TIME_WAIT) {
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
return;
}
@@ -663,7 +663,7 @@ static struct sock *dccp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
bh_lock_sock(nsk);
return nsk;
}
- inet_twsk_put((struct inet_timewait_sock *)nsk);
+ inet_twsk_put(inet_twsk(nsk));
return NULL;
}
@@ -1109,7 +1109,7 @@ discard_and_relse:
goto discard_it;
do_time_wait:
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
goto no_dccp_socket;
}
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 70e027375682..3456cd331835 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1178,8 +1178,10 @@ static int dn_getname(struct socket *sock, struct sockaddr *uaddr,int *uaddr_len
if (peer) {
if ((sock->state != SS_CONNECTED &&
sock->state != SS_CONNECTING) &&
- scp->accept_mode == ACC_IMMED)
+ scp->accept_mode == ACC_IMMED) {
+ release_sock(sk);
return -ENOTCONN;
+ }
memcpy(sa, &scp->peer, sizeof(struct sockaddr_dn));
} else {
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index dd0761e3d280..23489f7232d2 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -267,9 +267,14 @@ static void dn_dst_link_failure(struct sk_buff *skb)
static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
{
- return memcmp(&fl1->nl_u.dn_u, &fl2->nl_u.dn_u, sizeof(fl1->nl_u.dn_u)) == 0 &&
- fl1->oif == fl2->oif &&
- fl1->iif == fl2->iif;
+ return ((fl1->nl_u.dn_u.daddr ^ fl2->nl_u.dn_u.daddr) |
+ (fl1->nl_u.dn_u.saddr ^ fl2->nl_u.dn_u.saddr) |
+#ifdef CONFIG_DECNET_ROUTE_FWMARK
+ (fl1->nl_u.dn_u.fwmark ^ fl2->nl_u.dn_u.fwmark) |
+#endif
+ (fl1->nl_u.dn_u.scope ^ fl2->nl_u.dn_u.scope) |
+ (fl1->oif ^ fl2->oif) |
+ (fl1->iif ^ fl2->iif)) == 0;
}
static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route **rp)
@@ -1270,7 +1275,6 @@ static int dn_route_input_slow(struct sk_buff *skb)
goto e_inval;
res.type = RTN_LOCAL;
- flags |= RTCF_DIRECTSRC;
} else {
__le16 src_map = fl.fld_src;
free_res = 1;
@@ -1341,7 +1345,7 @@ static int dn_route_input_slow(struct sk_buff *skb)
goto make_route;
/* Packet was intra-ethernet, so we know its on-link */
- if (cb->rt_flags | DN_RT_F_IE) {
+ if (cb->rt_flags & DN_RT_F_IE) {
gateway = cb->src;
flags |= RTCF_DIRECTSRC;
goto make_route;
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 43863933f27f..4bd78c8cfb26 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -223,7 +223,7 @@ static int eth_header_parse(struct sk_buff *skb, unsigned char *haddr)
*/
int eth_header_cache(struct neighbour *neigh, struct hh_cache *hh)
{
- unsigned short type = hh->hh_type;
+ __be16 type = hh->hh_type;
struct ethhdr *eth;
struct net_device *dev = neigh->dev;
diff --git a/net/ieee80211/softmac/ieee80211softmac_wx.c b/net/ieee80211/softmac/ieee80211softmac_wx.c
index 75320b6842ab..2aa779d18f38 100644
--- a/net/ieee80211/softmac/ieee80211softmac_wx.c
+++ b/net/ieee80211/softmac/ieee80211softmac_wx.c
@@ -80,10 +80,10 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
* If it's our network, ignore the change, we're already doing it!
*/
if((sm->associnfo.associating || sm->associated) &&
- (data->essid.flags && data->essid.length && extra)) {
+ (data->essid.flags && data->essid.length)) {
/* Get the associating network */
n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
- if(n && n->essid.len == (data->essid.length - 1) &&
+ if(n && n->essid.len == data->essid.length &&
!memcmp(n->essid.data, extra, n->essid.len)) {
dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
MAC_ARG(sm->associnfo.bssid));
@@ -109,8 +109,8 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
sm->associnfo.static_essid = 0;
sm->associnfo.assoc_wait = 0;
- if (data->essid.flags && data->essid.length && extra /*required?*/) {
- length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
+ if (data->essid.flags && data->essid.length) {
+ length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
if (length) {
memcpy(sm->associnfo.req_essid.data, extra, length);
sm->associnfo.static_essid = 1;
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 30af4a4dfcc8..5572071af735 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -64,7 +64,7 @@ config ASK_IP_FIB_HASH
config IP_FIB_TRIE
bool "FIB_TRIE"
---help---
- Use new experimental LC-trie as FIB lookup algoritm.
+ Use new experimental LC-trie as FIB lookup algorithm.
This improves lookup performance if you have a large
number of routes.
@@ -434,6 +434,15 @@ config INET_XFRM_MODE_TUNNEL
If unsure, say Y.
+config INET_XFRM_MODE_BEET
+ tristate "IP: IPsec BEET mode"
+ default y
+ select XFRM
+ ---help---
+ Support for IPsec BEET mode.
+
+ If unsure, say Y.
+
config INET_DIAG
tristate "INET: socket monitoring interface"
default y
@@ -526,7 +535,7 @@ config TCP_CONG_HYBLA
---help---
TCP-Hybla is a sender-side only change that eliminates penalization of
long-RTT, large-bandwidth connections, like when satellite legs are
- involved, expecially when sharing a common bottleneck with normal
+ involved, especially when sharing a common bottleneck with normal
terrestrial connections.
config TCP_CONG_VEGAS
@@ -556,7 +565,7 @@ config TCP_CONG_LP
default n
---help---
TCP Low Priority (TCP-LP), a distributed algorithm whose goal is
- to utiliza only the excess network bandwidth as compared to the
+ to utilize only the excess network bandwidth as compared to the
``fair share`` of bandwidth as targeted by TCP.
See http://www-ece.rice.edu/networks/TCP-LP/
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index f66049e28aeb..15645c51520c 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_INET_AH) += ah4.o
obj-$(CONFIG_INET_ESP) += esp4.o
obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
+obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o
obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index fdd89e37b9aa..edcf0932ac6d 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -996,7 +996,7 @@ static int inet_sk_reselect_saddr(struct sock *sk)
struct rtable *rt;
__u32 old_saddr = inet->saddr;
__u32 new_saddr;
- __u32 daddr = inet->daddr;
+ __be32 daddr = inet->daddr;
if (inet->opt && inet->opt->srr)
daddr = inet->opt->faddr;
@@ -1043,7 +1043,7 @@ int inet_sk_rebuild_header(struct sock *sk)
{
struct inet_sock *inet = inet_sk(sk);
struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0);
- u32 daddr;
+ __be32 daddr;
int err;
/* Route is OK, nothing to do. */
@@ -1342,10 +1342,10 @@ static int __init inet_init(void)
rc = 0;
out:
return rc;
-out_unregister_tcp_proto:
- proto_unregister(&tcp_prot);
out_unregister_udp_proto:
proto_unregister(&udp_prot);
+out_unregister_tcp_proto:
+ proto_unregister(&tcp_prot);
goto out;
}
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index c8a3723bc001..cfb5d3de9c84 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -1,4 +1,4 @@
-/* linux/net/inet/arp.c
+/* linux/net/ipv4/arp.c
*
* Version: $Id: arp.c,v 1.99 2001/08/30 22:55:42 davem Exp $
*
@@ -234,7 +234,7 @@ static u32 arp_hash(const void *pkey, const struct net_device *dev)
static int arp_constructor(struct neighbour *neigh)
{
- u32 addr = *(u32*)neigh->primary_key;
+ __be32 addr = *(__be32*)neigh->primary_key;
struct net_device *dev = neigh->dev;
struct in_device *in_dev;
struct neigh_parms *parms;
@@ -330,10 +330,10 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb)
static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
{
- u32 saddr = 0;
+ __be32 saddr = 0;
u8 *dst_ha = NULL;
struct net_device *dev = neigh->dev;
- u32 target = *(u32*)neigh->primary_key;
+ __be32 target = *(__be32*)neigh->primary_key;
int probes = atomic_read(&neigh->probes);
struct in_device *in_dev = in_dev_get(dev);
@@ -385,7 +385,7 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
}
static int arp_ignore(struct in_device *in_dev, struct net_device *dev,
- u32 sip, u32 tip)
+ __be32 sip, __be32 tip)
{
int scope;
@@ -420,7 +420,7 @@ static int arp_ignore(struct in_device *in_dev, struct net_device *dev,
return !inet_confirm_addr(dev, sip, tip, scope);
}
-static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
+static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = sip,
.saddr = tip } } };
@@ -449,7 +449,7 @@ static int arp_filter(__u32 sip, __u32 tip, struct net_device *dev)
* is allowed to use this function, it is scheduled to be removed. --ANK
*/
-static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, struct net_device * dev)
+static int arp_set_predefined(int addr_hint, unsigned char * haddr, __be32 paddr, struct net_device * dev)
{
switch (addr_hint) {
case RTN_LOCAL:
@@ -470,7 +470,7 @@ static int arp_set_predefined(int addr_hint, unsigned char * haddr, u32 paddr, s
int arp_find(unsigned char *haddr, struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
- u32 paddr;
+ __be32 paddr;
struct neighbour *n;
if (!skb->dst) {
@@ -511,7 +511,7 @@ int arp_bind_neighbour(struct dst_entry *dst)
if (dev == NULL)
return -EINVAL;
if (n == NULL) {
- u32 nexthop = ((struct rtable*)dst)->rt_gateway;
+ __be32 nexthop = ((struct rtable*)dst)->rt_gateway;
if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
nexthop = 0;
n = __neigh_lookup_errno(
@@ -560,8 +560,8 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
* Create an arp packet. If (dest_hw == NULL), we create a broadcast
* message.
*/
-struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
- struct net_device *dev, u32 src_ip,
+struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip,
+ struct net_device *dev, __be32 src_ip,
unsigned char *dest_hw, unsigned char *src_hw,
unsigned char *target_hw)
{
@@ -675,8 +675,8 @@ void arp_xmit(struct sk_buff *skb)
/*
* Create and send an arp packet.
*/
-void arp_send(int type, int ptype, u32 dest_ip,
- struct net_device *dev, u32 src_ip,
+void arp_send(int type, int ptype, __be32 dest_ip,
+ struct net_device *dev, __be32 src_ip,
unsigned char *dest_hw, unsigned char *src_hw,
unsigned char *target_hw)
{
@@ -710,7 +710,7 @@ static int arp_process(struct sk_buff *skb)
unsigned char *arp_ptr;
struct rtable *rt;
unsigned char *sha, *tha;
- u32 sip, tip;
+ __be32 sip, tip;
u16 dev_type = dev->type;
int addr_type;
struct neighbour *n;
@@ -969,13 +969,13 @@ out_of_mem:
static int arp_req_set(struct arpreq *r, struct net_device * dev)
{
- u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+ __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
struct neighbour *neigh;
int err;
if (r->arp_flags&ATF_PUBL) {
- u32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
- if (mask && mask != 0xFFFFFFFF)
+ __be32 mask = ((struct sockaddr_in *) &r->arp_netmask)->sin_addr.s_addr;
+ if (mask && mask != htonl(0xFFFFFFFF))
return -EINVAL;
if (!dev && (r->arp_flags & ATF_COM)) {
dev = dev_getbyhwaddr(r->arp_ha.sa_family, r->arp_ha.sa_data);
@@ -1063,7 +1063,7 @@ static unsigned arp_state_to_flags(struct neighbour *neigh)
static int arp_req_get(struct arpreq *r, struct net_device *dev)
{
- u32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
+ __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr;
struct neighbour *neigh;
int err = -ENXIO;
@@ -1084,13 +1084,13 @@ static int arp_req_get(struct arpreq *r, struct net_device *dev)
static int arp_req_delete(struct arpreq *r, struct net_device * dev)
{
int err;
- u32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
+ __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr;
struct neighbour *neigh;
if (r->arp_flags & ATF_PUBL) {
- u32 mask =
+ __be32 mask =
((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr;
- if (mask == 0xFFFFFFFF)
+ if (mask == htonl(0xFFFFFFFF))
return pneigh_delete(&arp_tbl, &ip, dev);
if (mask == 0) {
if (dev == NULL) {
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c
index e6ce0b3ba62a..e2077a3aa8c0 100644
--- a/net/ipv4/cipso_ipv4.c
+++ b/net/ipv4/cipso_ipv4.c
@@ -43,6 +43,7 @@
#include <net/tcp.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
+#include <asm/atomic.h>
#include <asm/bug.h>
struct cipso_v4_domhsh_entry {
@@ -79,7 +80,7 @@ struct cipso_v4_map_cache_entry {
unsigned char *key;
size_t key_len;
- struct netlbl_lsm_cache lsm_data;
+ struct netlbl_lsm_cache *lsm_data;
u32 activity;
struct list_head list;
@@ -188,13 +189,14 @@ static void cipso_v4_doi_domhsh_free(struct rcu_head *entry)
* @entry: the entry to free
*
* Description:
- * This function frees the memory associated with a cache entry.
+ * This function frees the memory associated with a cache entry including the
+ * LSM cache data if there are no longer any users, i.e. reference count == 0.
*
*/
static void cipso_v4_cache_entry_free(struct cipso_v4_map_cache_entry *entry)
{
- if (entry->lsm_data.free)
- entry->lsm_data.free(entry->lsm_data.data);
+ if (entry->lsm_data)
+ netlbl_secattr_cache_free(entry->lsm_data);
kfree(entry->key);
kfree(entry);
}
@@ -315,8 +317,8 @@ static int cipso_v4_cache_check(const unsigned char *key,
entry->key_len == key_len &&
memcmp(entry->key, key, key_len) == 0) {
entry->activity += 1;
- secattr->cache.free = entry->lsm_data.free;
- secattr->cache.data = entry->lsm_data.data;
+ atomic_inc(&entry->lsm_data->refcount);
+ secattr->cache = entry->lsm_data;
if (prev_entry == NULL) {
spin_unlock_bh(&cipso_v4_cache[bkt].lock);
return 0;
@@ -383,8 +385,8 @@ int cipso_v4_cache_add(const struct sk_buff *skb,
memcpy(entry->key, cipso_ptr, cipso_ptr_len);
entry->key_len = cipso_ptr_len;
entry->hash = cipso_v4_map_cache_hash(cipso_ptr, cipso_ptr_len);
- entry->lsm_data.free = secattr->cache.free;
- entry->lsm_data.data = secattr->cache.data;
+ atomic_inc(&secattr->cache->refcount);
+ entry->lsm_data = secattr->cache;
bkt = entry->hash & (CIPSO_V4_CACHE_BUCKETBITS - 1);
spin_lock_bh(&cipso_v4_cache[bkt].lock);
@@ -474,6 +476,7 @@ doi_add_failure_rlock:
/**
* cipso_v4_doi_remove - Remove an existing DOI from the CIPSO protocol engine
* @doi: the DOI value
+ * @audit_secid: the LSM secid to use in the audit message
* @callback: the DOI cleanup/free callback
*
* Description:
@@ -483,7 +486,9 @@ doi_add_failure_rlock:
* success and negative values on failure.
*
*/
-int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head))
+int cipso_v4_doi_remove(u32 doi,
+ struct netlbl_audit *audit_info,
+ void (*callback) (struct rcu_head * head))
{
struct cipso_v4_doi *doi_def;
struct cipso_v4_domhsh_entry *dom_iter;
@@ -502,7 +507,8 @@ int cipso_v4_doi_remove(u32 doi, void (*callback) (struct rcu_head * head))
spin_unlock(&cipso_v4_doi_list_lock);
list_for_each_entry_rcu(dom_iter, &doi_def->dom_list, list)
if (dom_iter->valid)
- netlbl_domhsh_remove(dom_iter->domain);
+ netlbl_domhsh_remove(dom_iter->domain,
+ audit_info);
cipso_v4_cache_invalidate();
rcu_read_unlock();
@@ -767,13 +773,15 @@ static int cipso_v4_map_cat_rbm_valid(const struct cipso_v4_doi *doi_def,
{
int cat = -1;
u32 bitmap_len_bits = bitmap_len * 8;
- u32 cipso_cat_size = doi_def->map.std->cat.cipso_size;
- u32 *cipso_array = doi_def->map.std->cat.cipso;
+ u32 cipso_cat_size;
+ u32 *cipso_array;
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
return 0;
case CIPSO_V4_MAP_STD:
+ cipso_cat_size = doi_def->map.std->cat.cipso_size;
+ cipso_array = doi_def->map.std->cat.cipso;
for (;;) {
cat = cipso_v4_bitmap_walk(bitmap,
bitmap_len_bits,
@@ -819,19 +827,21 @@ static int cipso_v4_map_cat_rbm_hton(const struct cipso_v4_doi *doi_def,
u32 net_spot_max = 0;
u32 host_clen_bits = host_cat_len * 8;
u32 net_clen_bits = net_cat_len * 8;
- u32 host_cat_size = doi_def->map.std->cat.local_size;
- u32 *host_cat_array = doi_def->map.std->cat.local;
+ u32 host_cat_size;
+ u32 *host_cat_array;
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
- net_spot_max = host_cat_len - 1;
- while (net_spot_max > 0 && host_cat[net_spot_max] == 0)
+ net_spot_max = host_cat_len;
+ while (net_spot_max > 0 && host_cat[net_spot_max - 1] == 0)
net_spot_max--;
if (net_spot_max > net_cat_len)
return -EINVAL;
memcpy(net_cat, host_cat, net_spot_max);
return net_spot_max;
case CIPSO_V4_MAP_STD:
+ host_cat_size = doi_def->map.std->cat.local_size;
+ host_cat_array = doi_def->map.std->cat.local;
for (;;) {
host_spot = cipso_v4_bitmap_walk(host_cat,
host_clen_bits,
@@ -887,8 +897,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
int net_spot = -1;
u32 net_clen_bits = net_cat_len * 8;
u32 host_clen_bits = host_cat_len * 8;
- u32 net_cat_size = doi_def->map.std->cat.cipso_size;
- u32 *net_cat_array = doi_def->map.std->cat.cipso;
+ u32 net_cat_size;
+ u32 *net_cat_array;
switch (doi_def->type) {
case CIPSO_V4_MAP_PASS:
@@ -897,6 +907,8 @@ static int cipso_v4_map_cat_rbm_ntoh(const struct cipso_v4_doi *doi_def,
memcpy(host_cat, net_cat, net_cat_len);
return net_cat_len;
case CIPSO_V4_MAP_STD:
+ net_cat_size = doi_def->map.std->cat.cipso_size;
+ net_cat_array = doi_def->map.std->cat.cipso;
for (;;) {
net_spot = cipso_v4_bitmap_walk(net_cat,
net_clen_bits,
diff --git a/net/ipv4/datagram.c b/net/ipv4/datagram.c
index ec5da4fbd9f4..7b068a891953 100644
--- a/net/ipv4/datagram.c
+++ b/net/ipv4/datagram.c
@@ -25,7 +25,7 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct inet_sock *inet = inet_sk(sk);
struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
struct rtable *rt;
- u32 saddr;
+ __be32 saddr;
int oif;
int err;
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 8e8d1f17d77a..7602c79a389b 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -224,7 +224,7 @@ static void inetdev_destroy(struct in_device *in_dev)
call_rcu(&in_dev->rcu_head, in_dev_rcu_put);
}
-int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b)
+int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b)
{
rcu_read_lock();
for_primary_ifa(in_dev) {
@@ -429,8 +429,8 @@ struct in_device *inetdev_by_index(int ifindex)
/* Called only from RTNL semaphored context. No locks. */
-struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix,
- u32 mask)
+struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix,
+ __be32 mask)
{
ASSERT_RTNL();
@@ -467,7 +467,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL;
ifap = &ifa->ifa_next) {
if (tb[IFA_LOCAL] &&
- ifa->ifa_local != nla_get_u32(tb[IFA_LOCAL]))
+ ifa->ifa_local != nla_get_be32(tb[IFA_LOCAL]))
continue;
if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label))
@@ -475,7 +475,7 @@ static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg
if (tb[IFA_ADDRESS] &&
(ifm->ifa_prefixlen != ifa->ifa_prefixlen ||
- !inet_ifa_match(nla_get_u32(tb[IFA_ADDRESS]), ifa)))
+ !inet_ifa_match(nla_get_be32(tb[IFA_ADDRESS]), ifa)))
continue;
__inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).pid);
@@ -540,14 +540,14 @@ static struct in_ifaddr *rtm_to_ifaddr(struct nlmsghdr *nlh)
ifa->ifa_scope = ifm->ifa_scope;
ifa->ifa_dev = in_dev;
- ifa->ifa_local = nla_get_u32(tb[IFA_LOCAL]);
- ifa->ifa_address = nla_get_u32(tb[IFA_ADDRESS]);
+ ifa->ifa_local = nla_get_be32(tb[IFA_LOCAL]);
+ ifa->ifa_address = nla_get_be32(tb[IFA_ADDRESS]);
if (tb[IFA_BROADCAST])
- ifa->ifa_broadcast = nla_get_u32(tb[IFA_BROADCAST]);
+ ifa->ifa_broadcast = nla_get_be32(tb[IFA_BROADCAST]);
if (tb[IFA_ANYCAST])
- ifa->ifa_anycast = nla_get_u32(tb[IFA_ANYCAST]);
+ ifa->ifa_anycast = nla_get_be32(tb[IFA_ANYCAST]);
if (tb[IFA_LABEL])
nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ);
@@ -805,7 +805,7 @@ int devinet_ioctl(unsigned int cmd, void __user *arg)
break;
ret = 0;
if (ifa->ifa_mask != sin->sin_addr.s_addr) {
- u32 old_mask = ifa->ifa_mask;
+ __be32 old_mask = ifa->ifa_mask;
inet_del_ifa(in_dev, ifap, 0);
ifa->ifa_mask = sin->sin_addr.s_addr;
ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask);
@@ -876,9 +876,9 @@ out:
return done;
}
-u32 inet_select_addr(const struct net_device *dev, u32 dst, int scope)
+__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope)
{
- u32 addr = 0;
+ __be32 addr = 0;
struct in_device *in_dev;
rcu_read_lock();
@@ -927,11 +927,11 @@ out:
return addr;
}
-static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
- u32 local, int scope)
+static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst,
+ __be32 local, int scope)
{
int same = 0;
- u32 addr = 0;
+ __be32 addr = 0;
for_ifa(in_dev) {
if (!addr &&
@@ -971,9 +971,9 @@ static u32 confirm_addr_indev(struct in_device *in_dev, u32 dst,
* - local: address, 0=autoselect the local address
* - scope: maximum allowed scope value for the local address
*/
-u32 inet_confirm_addr(const struct net_device *dev, u32 dst, u32 local, int scope)
+__be32 inet_confirm_addr(const struct net_device *dev, __be32 dst, __be32 local, int scope)
{
- u32 addr = 0;
+ __be32 addr = 0;
struct in_device *in_dev;
if (dev) {
@@ -1138,16 +1138,16 @@ static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa,
ifm->ifa_index = ifa->ifa_dev->dev->ifindex;
if (ifa->ifa_address)
- NLA_PUT_U32(skb, IFA_ADDRESS, ifa->ifa_address);
+ NLA_PUT_BE32(skb, IFA_ADDRESS, ifa->ifa_address);
if (ifa->ifa_local)
- NLA_PUT_U32(skb, IFA_LOCAL, ifa->ifa_local);
+ NLA_PUT_BE32(skb, IFA_LOCAL, ifa->ifa_local);
if (ifa->ifa_broadcast)
- NLA_PUT_U32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
+ NLA_PUT_BE32(skb, IFA_BROADCAST, ifa->ifa_broadcast);
if (ifa->ifa_anycast)
- NLA_PUT_U32(skb, IFA_ANYCAST, ifa->ifa_anycast);
+ NLA_PUT_BE32(skb, IFA_ANYCAST, ifa->ifa_anycast);
if (ifa->ifa_label[0])
NLA_PUT_STRING(skb, IFA_LABEL, ifa->ifa_label);
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 13b29360d102..b5c205b57669 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -253,7 +253,8 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
* as per draft-ietf-ipsec-udp-encaps-06,
* section 3.1.2
*/
- if (x->props.mode == XFRM_MODE_TRANSPORT)
+ if (x->props.mode == XFRM_MODE_TRANSPORT ||
+ x->props.mode == XFRM_MODE_BEET)
skb->ip_summed = CHECKSUM_UNNECESSARY;
}
@@ -271,17 +272,28 @@ static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
{
struct esp_data *esp = x->data;
u32 blksize = ALIGN(crypto_blkcipher_blocksize(esp->conf.tfm), 4);
-
- if (x->props.mode == XFRM_MODE_TUNNEL) {
- mtu = ALIGN(mtu + 2, blksize);
- } else {
- /* The worst case. */
+ int enclen = 0;
+
+ switch (x->props.mode) {
+ case XFRM_MODE_TUNNEL:
+ mtu = ALIGN(mtu +2, blksize);
+ break;
+ default:
+ case XFRM_MODE_TRANSPORT:
+ /* The worst case */
mtu = ALIGN(mtu + 2, 4) + blksize - 4;
+ break;
+ case XFRM_MODE_BEET:
+ /* The worst case. */
+ enclen = IPV4_BEET_PHMAXLEN;
+ mtu = ALIGN(mtu + enclen + 2, blksize);
+ break;
}
+
if (esp->conf.padlen)
mtu = ALIGN(mtu, esp->conf.padlen);
- return mtu + x->props.header_len + esp->auth.icv_trunc_len;
+ return mtu + x->props.header_len + esp->auth.icv_trunc_len - enclen;
}
static void esp4_err(struct sk_buff *skb, u32 info)
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index cfb527c060e4..af0190d8b6c0 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -122,7 +122,7 @@ static void fib_flush(void)
* Find the first device with a given source address.
*/
-struct net_device * ip_dev_find(u32 addr)
+struct net_device * ip_dev_find(__be32 addr)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
@@ -146,7 +146,7 @@ out:
return dev;
}
-unsigned inet_addr_type(u32 addr)
+unsigned inet_addr_type(__be32 addr)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
@@ -180,8 +180,8 @@ unsigned inet_addr_type(u32 addr)
- check, that packet arrived from expected physical interface.
*/
-int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
- struct net_device *dev, u32 *spec_dst, u32 *itag)
+int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
+ struct net_device *dev, __be32 *spec_dst, u32 *itag)
{
struct in_device *in_dev;
struct flowi fl = { .nl_u = { .ip4_u =
@@ -253,7 +253,7 @@ e_inval:
#ifndef CONFIG_IP_NOSIOCRT
-static inline u32 sk_extract_addr(struct sockaddr *addr)
+static inline __be32 sk_extract_addr(struct sockaddr *addr)
{
return ((struct sockaddr_in *) addr)->sin_addr.s_addr;
}
@@ -273,7 +273,7 @@ static int put_rtax(struct nlattr *mx, int len, int type, u32 value)
static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
struct fib_config *cfg)
{
- u32 addr;
+ __be32 addr;
int plen;
memset(cfg, 0, sizeof(*cfg));
@@ -292,7 +292,7 @@ static int rtentry_to_fib_config(int cmd, struct rtentry *rt,
plen = 32;
addr = sk_extract_addr(&rt->rt_dst);
if (!(rt->rt_flags & RTF_HOST)) {
- u32 mask = sk_extract_addr(&rt->rt_genmask);
+ __be32 mask = sk_extract_addr(&rt->rt_genmask);
if (rt->rt_genmask.sa_family != AF_INET) {
if (mask || rt->rt_genmask.sa_family)
@@ -482,9 +482,7 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
memset(cfg, 0, sizeof(*cfg));
rtm = nlmsg_data(nlh);
- cfg->fc_family = rtm->rtm_family;
cfg->fc_dst_len = rtm->rtm_dst_len;
- cfg->fc_src_len = rtm->rtm_src_len;
cfg->fc_tos = rtm->rtm_tos;
cfg->fc_table = rtm->rtm_table;
cfg->fc_protocol = rtm->rtm_protocol;
@@ -499,22 +497,19 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) {
switch (attr->nla_type) {
case RTA_DST:
- cfg->fc_dst = nla_get_u32(attr);
- break;
- case RTA_SRC:
- cfg->fc_src = nla_get_u32(attr);
+ cfg->fc_dst = nla_get_be32(attr);
break;
case RTA_OIF:
cfg->fc_oif = nla_get_u32(attr);
break;
case RTA_GATEWAY:
- cfg->fc_gw = nla_get_u32(attr);
+ cfg->fc_gw = nla_get_be32(attr);
break;
case RTA_PRIORITY:
cfg->fc_priority = nla_get_u32(attr);
break;
case RTA_PREFSRC:
- cfg->fc_prefsrc = nla_get_u32(attr);
+ cfg->fc_prefsrc = nla_get_be32(attr);
break;
case RTA_METRICS:
cfg->fc_mx = nla_data(attr);
@@ -627,8 +622,7 @@ out:
only when netlink is already locked.
*/
-static void fib_magic(int cmd, int type, u32 dst, int dst_len,
- struct in_ifaddr *ifa)
+static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa)
{
struct fib_table *tb;
struct fib_config cfg = {
@@ -667,9 +661,9 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
struct in_device *in_dev = ifa->ifa_dev;
struct net_device *dev = in_dev->dev;
struct in_ifaddr *prim = ifa;
- u32 mask = ifa->ifa_mask;
- u32 addr = ifa->ifa_local;
- u32 prefix = ifa->ifa_address&mask;
+ __be32 mask = ifa->ifa_mask;
+ __be32 addr = ifa->ifa_local;
+ __be32 prefix = ifa->ifa_address&mask;
if (ifa->ifa_flags&IFA_F_SECONDARY) {
prim = inet_ifa_byprefix(in_dev, prefix, mask);
@@ -685,7 +679,7 @@ void fib_add_ifaddr(struct in_ifaddr *ifa)
return;
/* Add broadcast address, if it is explicitly assigned. */
- if (ifa->ifa_broadcast && ifa->ifa_broadcast != 0xFFFFFFFF)
+ if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF))
fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim);
if (!ZERONET(prefix) && !(ifa->ifa_flags&IFA_F_SECONDARY) &&
@@ -707,8 +701,8 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
struct net_device *dev = in_dev->dev;
struct in_ifaddr *ifa1;
struct in_ifaddr *prim = ifa;
- u32 brd = ifa->ifa_address|~ifa->ifa_mask;
- u32 any = ifa->ifa_address&ifa->ifa_mask;
+ __be32 brd = ifa->ifa_address|~ifa->ifa_mask;
+ __be32 any = ifa->ifa_address&ifa->ifa_mask;
#define LOCAL_OK 1
#define BRD_OK 2
#define BRD0_OK 4
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index 88133b383dc5..107bb6cbb0b3 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -51,7 +51,7 @@ static kmem_cache_t *fn_alias_kmem __read_mostly;
struct fib_node {
struct hlist_node fn_hash;
struct list_head fn_alias;
- u32 fn_key;
+ __be32 fn_key;
};
struct fn_zone {
@@ -64,7 +64,7 @@ struct fn_zone {
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
int fz_order; /* Zone order */
- u32 fz_mask;
+ __be32 fz_mask;
#define FZ_MASK(fz) ((fz)->fz_mask)
};
@@ -77,7 +77,7 @@ struct fn_hash {
struct fn_zone *fn_zone_list;
};
-static inline u32 fn_hash(u32 key, struct fn_zone *fz)
+static inline u32 fn_hash(__be32 key, struct fn_zone *fz)
{
u32 h = ntohl(key)>>(32 - fz->fz_order);
h ^= (h>>20);
@@ -87,7 +87,7 @@ static inline u32 fn_hash(u32 key, struct fn_zone *fz)
return h;
}
-static inline u32 fz_key(u32 dst, struct fn_zone *fz)
+static inline __be32 fz_key(__be32 dst, struct fn_zone *fz)
{
return dst & FZ_MASK(fz);
}
@@ -254,7 +254,7 @@ fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result
struct hlist_head *head;
struct hlist_node *node;
struct fib_node *f;
- u32 k = fz_key(flp->fl4_dst, fz);
+ __be32 k = fz_key(flp->fl4_dst, fz);
head = &fz->fz_hash[fn_hash(k, fz)];
hlist_for_each_entry(f, node, head, fn_hash) {
@@ -365,7 +365,7 @@ static inline void fib_insert_node(struct fn_zone *fz, struct fib_node *f)
}
/* Return the node in FZ matching KEY. */
-static struct fib_node *fib_find_node(struct fn_zone *fz, u32 key)
+static struct fib_node *fib_find_node(struct fn_zone *fz, __be32 key)
{
struct hlist_head *head = &fz->fz_hash[fn_hash(key, fz)];
struct hlist_node *node;
@@ -387,7 +387,7 @@ static int fn_hash_insert(struct fib_table *tb, struct fib_config *cfg)
struct fn_zone *fz;
struct fib_info *fi;
u8 tos = cfg->fc_tos;
- u32 key;
+ __be32 key;
int err;
if (cfg->fc_dst_len > 32)
@@ -541,7 +541,7 @@ static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg)
struct fib_node *f;
struct fib_alias *fa, *fa_to_delete;
struct fn_zone *fz;
- u32 key;
+ __be32 key;
if (cfg->fc_dst_len > 32)
return -EINVAL;
@@ -966,7 +966,7 @@ static void fib_seq_stop(struct seq_file *seq, void *v)
read_unlock(&fib_hash_lock);
}
-static unsigned fib_flag_trans(int type, u32 mask, struct fib_info *fi)
+static unsigned fib_flag_trans(int type, __be32 mask, struct fib_info *fi)
{
static const unsigned type2flags[RTN_MAX + 1] = {
[7] = RTF_REJECT, [8] = RTF_REJECT,
@@ -975,7 +975,7 @@ static unsigned fib_flag_trans(int type, u32 mask, struct fib_info *fi)
if (fi && fi->fib_nh->nh_gw)
flags |= RTF_GATEWAY;
- if (mask == 0xFFFFFFFF)
+ if (mask == htonl(0xFFFFFFFF))
flags |= RTF_HOST;
flags |= RTF_UP;
return flags;
@@ -991,7 +991,7 @@ static int fib_seq_show(struct seq_file *seq, void *v)
{
struct fib_iter_state *iter;
char bf[128];
- u32 prefix, mask;
+ __be32 prefix, mask;
unsigned flags;
struct fib_node *f;
struct fib_alias *fa;
diff --git a/net/ipv4/fib_lookup.h b/net/ipv4/fib_lookup.h
index fd6f7769f8ab..0e8b70bad4e1 100644
--- a/net/ipv4/fib_lookup.h
+++ b/net/ipv4/fib_lookup.h
@@ -20,16 +20,16 @@ struct fib_alias {
/* Exported by fib_semantics.c */
extern int fib_semantic_match(struct list_head *head,
const struct flowi *flp,
- struct fib_result *res, __u32 zone, __u32 mask,
+ struct fib_result *res, __be32 zone, __be32 mask,
int prefixlen);
extern void fib_release_info(struct fib_info *);
extern struct fib_info *fib_create_info(struct fib_config *cfg);
extern int fib_nh_match(struct fib_config *cfg, struct fib_info *fi);
extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
- u32 tb_id, u8 type, u8 scope, u32 dst,
+ u32 tb_id, u8 type, u8 scope, __be32 dst,
int dst_len, u8 tos, struct fib_info *fi,
unsigned int);
-extern void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
+extern void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
int dst_len, u32 tb_id, struct nl_info *info);
extern struct fib_alias *fib_find_alias(struct list_head *fah,
u8 tos, u32 prio);
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index 52b2adae4f22..0852b9cd065a 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -40,10 +40,10 @@ struct fib4_rule
u8 dst_len;
u8 src_len;
u8 tos;
- u32 src;
- u32 srcmask;
- u32 dst;
- u32 dstmask;
+ __be32 src;
+ __be32 srcmask;
+ __be32 dst;
+ __be32 dstmask;
#ifdef CONFIG_IP_ROUTE_FWMARK
u32 fwmark;
u32 fwmask;
@@ -150,8 +150,8 @@ void fib_select_default(const struct flowi *flp, struct fib_result *res)
static int fib4_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
{
struct fib4_rule *r = (struct fib4_rule *) rule;
- u32 daddr = fl->fl4_dst;
- u32 saddr = fl->fl4_src;
+ __be32 daddr = fl->fl4_dst;
+ __be32 saddr = fl->fl4_src;
if (((saddr ^ r->src) & r->srcmask) ||
((daddr ^ r->dst) & r->dstmask))
@@ -215,10 +215,10 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
}
if (tb[FRA_SRC])
- rule4->src = nla_get_u32(tb[FRA_SRC]);
+ rule4->src = nla_get_be32(tb[FRA_SRC]);
if (tb[FRA_DST])
- rule4->dst = nla_get_u32(tb[FRA_DST]);
+ rule4->dst = nla_get_be32(tb[FRA_DST]);
#ifdef CONFIG_IP_ROUTE_FWMARK
if (tb[FRA_FWMARK]) {
@@ -277,10 +277,10 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
return 0;
#endif
- if (tb[FRA_SRC] && (rule4->src != nla_get_u32(tb[FRA_SRC])))
+ if (tb[FRA_SRC] && (rule4->src != nla_get_be32(tb[FRA_SRC])))
return 0;
- if (tb[FRA_DST] && (rule4->dst != nla_get_u32(tb[FRA_DST])))
+ if (tb[FRA_DST] && (rule4->dst != nla_get_be32(tb[FRA_DST])))
return 0;
return 1;
@@ -305,10 +305,10 @@ static int fib4_rule_fill(struct fib_rule *rule, struct sk_buff *skb,
#endif
if (rule4->dst_len)
- NLA_PUT_U32(skb, FRA_DST, rule4->dst);
+ NLA_PUT_BE32(skb, FRA_DST, rule4->dst);
if (rule4->src_len)
- NLA_PUT_U32(skb, FRA_SRC, rule4->src);
+ NLA_PUT_BE32(skb, FRA_SRC, rule4->src);
#ifdef CONFIG_NET_CLS_ROUTE
if (rule4->tclassid)
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index 2ead09543f68..884d176e0082 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -203,7 +203,7 @@ static inline unsigned int fib_info_hashfn(const struct fib_info *fi)
unsigned int val = fi->fib_nhs;
val ^= fi->fib_protocol;
- val ^= fi->fib_prefsrc;
+ val ^= (__force u32)fi->fib_prefsrc;
val ^= fi->fib_priority;
return (val ^ (val >> 7) ^ (val >> 12)) & mask;
@@ -248,7 +248,7 @@ static inline unsigned int fib_devindex_hashfn(unsigned int val)
Used only by redirect accept routine.
*/
-int ip_fib_check_default(u32 gw, struct net_device *dev)
+int ip_fib_check_default(__be32 gw, struct net_device *dev)
{
struct hlist_head *head;
struct hlist_node *node;
@@ -273,7 +273,7 @@ int ip_fib_check_default(u32 gw, struct net_device *dev)
return -1;
}
-void rtmsg_fib(int event, u32 key, struct fib_alias *fa,
+void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
int dst_len, u32 tb_id, struct nl_info *info)
{
struct sk_buff *skb;
@@ -374,7 +374,7 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh,
struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
- nh->nh_gw = nla ? nla_get_u32(nla) : 0;
+ nh->nh_gw = nla ? nla_get_be32(nla) : 0;
#ifdef CONFIG_NET_CLS_ROUTE
nla = nla_find(attrs, attrlen, RTA_FLOW);
nh->nh_tclassid = nla ? nla_get_u32(nla) : 0;
@@ -427,7 +427,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi)
struct nlattr *nla, *attrs = rtnh_attrs(rtnh);
nla = nla_find(attrs, attrlen, RTA_GATEWAY);
- if (nla && nla_get_u32(nla) != nh->nh_gw)
+ if (nla && nla_get_be32(nla) != nh->nh_gw)
return 1;
#ifdef CONFIG_NET_CLS_ROUTE
nla = nla_find(attrs, attrlen, RTA_FLOW);
@@ -568,11 +568,11 @@ out:
return 0;
}
-static inline unsigned int fib_laddr_hashfn(u32 val)
+static inline unsigned int fib_laddr_hashfn(__be32 val)
{
unsigned int mask = (fib_hash_size - 1);
- return (val ^ (val >> 7) ^ (val >> 14)) & mask;
+ return ((__force u32)val ^ ((__force u32)val >> 7) ^ ((__force u32)val >> 14)) & mask;
}
static struct hlist_head *fib_hash_alloc(int bytes)
@@ -847,7 +847,7 @@ failure:
/* Note! fib_semantic_match intentionally uses RCU list functions. */
int fib_semantic_match(struct list_head *head, const struct flowi *flp,
- struct fib_result *res, __u32 zone, __u32 mask,
+ struct fib_result *res, __be32 zone, __be32 mask,
int prefixlen)
{
struct fib_alias *fa;
@@ -914,8 +914,7 @@ out_fill_res:
res->fi = fa->fa_info;
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
res->netmask = mask;
- res->network = zone &
- (0xFFFFFFFF >> (32 - prefixlen));
+ res->network = zone & inet_make_mask(prefixlen);
#endif
atomic_inc(&res->fi->fib_clntref);
return 0;
@@ -923,13 +922,13 @@ out_fill_res:
/* Find appropriate source address to this destination */
-u32 __fib_res_prefsrc(struct fib_result *res)
+__be32 __fib_res_prefsrc(struct fib_result *res)
{
return inet_select_addr(FIB_RES_DEV(*res), FIB_RES_GW(*res), res->scope);
}
int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
- u32 tb_id, u8 type, u8 scope, u32 dst, int dst_len, u8 tos,
+ u32 tb_id, u8 type, u8 scope, __be32 dst, int dst_len, u8 tos,
struct fib_info *fi, unsigned int flags)
{
struct nlmsghdr *nlh;
@@ -952,7 +951,7 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
rtm->rtm_protocol = fi->fib_protocol;
if (rtm->rtm_dst_len)
- NLA_PUT_U32(skb, RTA_DST, dst);
+ NLA_PUT_BE32(skb, RTA_DST, dst);
if (fi->fib_priority)
NLA_PUT_U32(skb, RTA_PRIORITY, fi->fib_priority);
@@ -961,11 +960,11 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
goto nla_put_failure;
if (fi->fib_prefsrc)
- NLA_PUT_U32(skb, RTA_PREFSRC, fi->fib_prefsrc);
+ NLA_PUT_BE32(skb, RTA_PREFSRC, fi->fib_prefsrc);
if (fi->fib_nhs == 1) {
if (fi->fib_nh->nh_gw)
- NLA_PUT_U32(skb, RTA_GATEWAY, fi->fib_nh->nh_gw);
+ NLA_PUT_BE32(skb, RTA_GATEWAY, fi->fib_nh->nh_gw);
if (fi->fib_nh->nh_oif)
NLA_PUT_U32(skb, RTA_OIF, fi->fib_nh->nh_oif);
@@ -993,7 +992,7 @@ int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
rtnh->rtnh_ifindex = nh->nh_oif;
if (nh->nh_gw)
- NLA_PUT_U32(skb, RTA_GATEWAY, nh->nh_gw);
+ NLA_PUT_BE32(skb, RTA_GATEWAY, nh->nh_gw);
#ifdef CONFIG_NET_CLS_ROUTE
if (nh->nh_tclassid)
NLA_PUT_U32(skb, RTA_FLOW, nh->nh_tclassid);
@@ -1018,7 +1017,7 @@ nla_put_failure:
- device went down -> we must shutdown all nexthops going via it.
*/
-int fib_sync_down(u32 local, struct net_device *dev, int force)
+int fib_sync_down(__be32 local, struct net_device *dev, int force)
{
int ret = 0;
int scope = RT_SCOPE_NOWHERE;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 9c3ff6ba6e21..d17990ec724f 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -1834,7 +1834,7 @@ static int fn_trie_dump_fa(t_key key, int plen, struct list_head *fah, struct fi
int i, s_i;
struct fib_alias *fa;
- u32 xkey = htonl(key);
+ __be32 xkey = htonl(key);
s_i = cb->args[4];
i = 0;
@@ -2281,7 +2281,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
if (IS_TNODE(n)) {
struct tnode *tn = (struct tnode *) n;
- t_key prf = ntohl(MASK_PFX(tn->key, tn->pos));
+ __be32 prf = htonl(MASK_PFX(tn->key, tn->pos));
if (!NODE_PARENT(n)) {
if (iter->trie == trie_local)
@@ -2297,7 +2297,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v)
} else {
struct leaf *l = (struct leaf *) n;
int i;
- u32 val = ntohl(l->key);
+ __be32 val = htonl(l->key);
seq_indent(seq, iter->depth);
seq_printf(seq, " |-- %d.%d.%d.%d\n", NIPQUAD(val));
@@ -2360,7 +2360,7 @@ static struct file_operations fib_trie_fops = {
.release = seq_release_private,
};
-static unsigned fib_flag_trans(int type, u32 mask, const struct fib_info *fi)
+static unsigned fib_flag_trans(int type, __be32 mask, const struct fib_info *fi)
{
static unsigned type2flags[RTN_MAX + 1] = {
[7] = RTF_REJECT, [8] = RTF_REJECT,
@@ -2369,7 +2369,7 @@ static unsigned fib_flag_trans(int type, u32 mask, const struct fib_info *fi)
if (fi && fi->fib_nh->nh_gw)
flags |= RTF_GATEWAY;
- if (mask == 0xFFFFFFFF)
+ if (mask == htonl(0xFFFFFFFF))
flags |= RTF_HOST;
flags |= RTF_UP;
return flags;
@@ -2403,7 +2403,7 @@ static int fib_route_seq_show(struct seq_file *seq, void *v)
for (i=32; i>=0; i--) {
struct leaf_info *li = find_leaf_info(l, i);
struct fib_alias *fa;
- u32 mask, prefix;
+ __be32 mask, prefix;
if (!li)
continue;
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index c2ad07e48ab4..b39a37a47545 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -104,7 +104,7 @@ struct icmp_bxm {
struct {
struct icmphdr icmph;
- __u32 times[3];
+ __be32 times[3];
} data;
int head_len;
struct ip_options replyopts;
@@ -381,7 +381,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
struct inet_sock *inet = inet_sk(sk);
struct ipcm_cookie ipc;
struct rtable *rt = (struct rtable *)skb->dst;
- u32 daddr;
+ __be32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb))
return;
@@ -430,14 +430,14 @@ out_unlock:
* MUST reply to only the first fragment.
*/
-void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
+void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
{
struct iphdr *iph;
int room;
struct icmp_bxm icmp_param;
struct rtable *rt = (struct rtable *)skb_in->dst;
struct ipcm_cookie ipc;
- u32 saddr;
+ __be32 saddr;
u8 tos;
if (!rt)
@@ -895,7 +895,7 @@ static void icmp_address_reply(struct sk_buff *skb)
if (in_dev->ifa_list &&
IN_DEV_LOG_MARTIANS(in_dev) &&
IN_DEV_FORWARD(in_dev)) {
- u32 _mask, *mp;
+ __be32 _mask, *mp;
mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask);
BUG_ON(mp == NULL);
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 58be8227b0cb..6eee71647b7c 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -138,14 +138,14 @@
time_before(jiffies, (in_dev)->mr_v2_seen)))
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
-static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr);
+static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr);
static void igmpv3_clear_delrec(struct in_device *in_dev);
static int sf_setstate(struct ip_mc_list *pmc);
static void sf_markstate(struct ip_mc_list *pmc);
#endif
static void ip_mc_clear_src(struct ip_mc_list *pmc);
-static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
- int sfcount, __u32 *psfsrc, int delta);
+static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
+ int sfcount, __be32 *psfsrc, int delta);
static void ip_ma_put(struct ip_mc_list *im)
{
@@ -426,7 +426,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
first = 1;
psf_prev = NULL;
for (psf=*psf_list; psf; psf=psf_next) {
- u32 *psrc;
+ __be32 *psrc;
psf_next = psf->sf_next;
@@ -439,7 +439,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
if (isquery)
psf->sf_gsresp = 0;
- if (AVAILABLE(skb) < sizeof(u32) +
+ if (AVAILABLE(skb) < sizeof(__be32) +
first*sizeof(struct igmpv3_grec)) {
if (truncate && !first)
break; /* truncate these */
@@ -455,7 +455,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc,
skb = add_grhead(skb, pmc, type, &pgr);
first = 0;
}
- psrc = (u32 *)skb_put(skb, sizeof(u32));
+ psrc = (__be32 *)skb_put(skb, sizeof(__be32));
*psrc = psf->sf_inaddr;
scount++; stotal++;
if ((type == IGMPV3_ALLOW_NEW_SOURCES ||
@@ -630,8 +630,8 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc,
struct igmphdr *ih;
struct rtable *rt;
struct net_device *dev = in_dev->dev;
- u32 group = pmc ? pmc->multiaddr : 0;
- u32 dst;
+ __be32 group = pmc ? pmc->multiaddr : 0;
+ __be32 dst;
if (type == IGMPV3_HOST_MEMBERSHIP_REPORT)
return igmpv3_send_report(in_dev, pmc);
@@ -748,7 +748,7 @@ static void igmp_timer_expire(unsigned long data)
}
/* mark EXCLUDE-mode sources */
-static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
+static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
{
struct ip_sf_list *psf;
int i, scount;
@@ -775,7 +775,7 @@ static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
return 1;
}
-static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
+static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs)
{
struct ip_sf_list *psf;
int i, scount;
@@ -803,7 +803,7 @@ static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __u32 *srcs)
return 1;
}
-static void igmp_heard_report(struct in_device *in_dev, u32 group)
+static void igmp_heard_report(struct in_device *in_dev, __be32 group)
{
struct ip_mc_list *im;
@@ -828,7 +828,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
struct igmphdr *ih = skb->h.igmph;
struct igmpv3_query *ih3 = (struct igmpv3_query *)ih;
struct ip_mc_list *im;
- u32 group = ih->group;
+ __be32 group = ih->group;
int max_delay;
int mark = 0;
@@ -862,7 +862,7 @@ static void igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb,
ih3 = (struct igmpv3_query *) skb->h.raw;
if (ih3->nsrcs) {
if (!pskb_may_pull(skb, sizeof(struct igmpv3_query)
- + ntohs(ih3->nsrcs)*sizeof(__u32)))
+ + ntohs(ih3->nsrcs)*sizeof(__be32)))
return;
ih3 = (struct igmpv3_query *) skb->h.raw;
}
@@ -985,7 +985,7 @@ drop:
* Add a filter to a device
*/
-static void ip_mc_filter_add(struct in_device *in_dev, u32 addr)
+static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr)
{
char buf[MAX_ADDR_LEN];
struct net_device *dev = in_dev->dev;
@@ -1005,7 +1005,7 @@ static void ip_mc_filter_add(struct in_device *in_dev, u32 addr)
* Remove a filter from a device
*/
-static void ip_mc_filter_del(struct in_device *in_dev, u32 addr)
+static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr)
{
char buf[MAX_ADDR_LEN];
struct net_device *dev = in_dev->dev;
@@ -1055,7 +1055,7 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
spin_unlock_bh(&in_dev->mc_tomb_lock);
}
-static void igmpv3_del_delrec(struct in_device *in_dev, __u32 multiaddr)
+static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
{
struct ip_mc_list *pmc, *pmc_prev;
struct ip_sf_list *psf, *psf_next;
@@ -1193,7 +1193,7 @@ static void igmp_group_added(struct ip_mc_list *im)
* A socket has joined a multicast group on device dev.
*/
-void ip_mc_inc_group(struct in_device *in_dev, u32 addr)
+void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
{
struct ip_mc_list *im;
@@ -1252,7 +1252,7 @@ out:
* A socket has left a multicast group on device dev
*/
-void ip_mc_dec_group(struct in_device *in_dev, u32 addr)
+void ip_mc_dec_group(struct in_device *in_dev, __be32 addr)
{
struct ip_mc_list *i, **ip;
@@ -1402,7 +1402,7 @@ int sysctl_igmp_max_msf __read_mostly = IP_MAX_MSF;
static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
- __u32 *psfsrc)
+ __be32 *psfsrc)
{
struct ip_sf_list *psf, *psf_prev;
int rv = 0;
@@ -1450,8 +1450,8 @@ static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode,
#define igmp_ifc_event(x) do { } while (0)
#endif
-static int ip_mc_del_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
- int sfcount, __u32 *psfsrc, int delta)
+static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
+ int sfcount, __be32 *psfsrc, int delta)
{
struct ip_mc_list *pmc;
int changerec = 0;
@@ -1517,7 +1517,7 @@ out_unlock:
* Add multicast single-source filter to the interface list
*/
static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode,
- __u32 *psfsrc, int delta)
+ __be32 *psfsrc, int delta)
{
struct ip_sf_list *psf, *psf_prev;
@@ -1623,8 +1623,8 @@ static int sf_setstate(struct ip_mc_list *pmc)
/*
* Add multicast source filter list to the interface list
*/
-static int ip_mc_add_src(struct in_device *in_dev, __u32 *pmca, int sfmode,
- int sfcount, __u32 *psfsrc, int delta)
+static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
+ int sfcount, __be32 *psfsrc, int delta)
{
struct ip_mc_list *pmc;
int isexclude;
@@ -1717,7 +1717,7 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc)
int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
{
int err;
- u32 addr = imr->imr_multiaddr.s_addr;
+ __be32 addr = imr->imr_multiaddr.s_addr;
struct ip_mc_socklist *iml=NULL, *i;
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
@@ -1791,7 +1791,7 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
struct inet_sock *inet = inet_sk(sk);
struct ip_mc_socklist *iml, **imlp;
struct in_device *in_dev;
- u32 group = imr->imr_multiaddr.s_addr;
+ __be32 group = imr->imr_multiaddr.s_addr;
u32 ifindex;
int ret = -EADDRNOTAVAIL;
@@ -1829,7 +1829,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
{
int err;
struct ip_mreqn imr;
- u32 addr = mreqs->imr_multiaddr;
+ __be32 addr = mreqs->imr_multiaddr;
struct ip_mc_socklist *pmc;
struct in_device *in_dev = NULL;
struct inet_sock *inet = inet_sk(sk);
@@ -1883,7 +1883,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
rv = !0;
for (i=0; i<psl->sl_count; i++) {
rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
- sizeof(__u32));
+ sizeof(__be32));
if (rv == 0)
break;
}
@@ -1935,7 +1935,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
rv = 1; /* > 0 for insert logic below if sl_count is 0 */
for (i=0; i<psl->sl_count; i++) {
rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
- sizeof(__u32));
+ sizeof(__be32));
if (rv == 0)
break;
}
@@ -1960,7 +1960,7 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
{
int err = 0;
struct ip_mreqn imr;
- u32 addr = msf->imsf_multiaddr;
+ __be32 addr = msf->imsf_multiaddr;
struct ip_mc_socklist *pmc;
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
@@ -2044,7 +2044,7 @@ int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf,
{
int err, len, count, copycount;
struct ip_mreqn imr;
- u32 addr = msf->imsf_multiaddr;
+ __be32 addr = msf->imsf_multiaddr;
struct ip_mc_socklist *pmc;
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
@@ -2103,7 +2103,7 @@ int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf,
{
int err, i, count, copycount;
struct sockaddr_in *psin;
- u32 addr;
+ __be32 addr;
struct ip_mc_socklist *pmc;
struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *psl;
@@ -2156,7 +2156,7 @@ done:
/*
* check if a multicast source filter allows delivery for a given <src,dst,intf>
*/
-int ip_mc_sf_allow(struct sock *sk, u32 loc_addr, u32 rmt_addr, int dif)
+int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif)
{
struct inet_sock *inet = inet_sk(sk);
struct ip_mc_socklist *pmc;
@@ -2216,7 +2216,7 @@ void ip_mc_drop_socket(struct sock *sk)
rtnl_unlock();
}
-int ip_check_mc(struct in_device *in_dev, u32 mc_addr, u32 src_addr, u16 proto)
+int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 proto)
{
struct ip_mc_list *im;
struct ip_sf_list *psf;
diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c
index 07204391d083..96bbe2a0aa1b 100644
--- a/net/ipv4/inet_connection_sock.c
+++ b/net/ipv4/inet_connection_sock.c
@@ -39,7 +39,7 @@ int sysctl_local_port_range[2] = { 1024, 4999 };
int inet_csk_bind_conflict(const struct sock *sk,
const struct inet_bind_bucket *tb)
{
- const u32 sk_rcv_saddr = inet_rcv_saddr(sk);
+ const __be32 sk_rcv_saddr = inet_rcv_saddr(sk);
struct sock *sk2;
struct hlist_node *node;
int reuse = sk->sk_reuse;
@@ -52,7 +52,7 @@ int inet_csk_bind_conflict(const struct sock *sk,
sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
if (!reuse || !sk2->sk_reuse ||
sk2->sk_state == TCP_LISTEN) {
- const u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+ const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
if (!sk2_rcv_saddr || !sk_rcv_saddr ||
sk2_rcv_saddr == sk_rcv_saddr)
break;
@@ -342,10 +342,10 @@ struct dst_entry* inet_csk_route_req(struct sock *sk,
EXPORT_SYMBOL_GPL(inet_csk_route_req);
-static inline u32 inet_synq_hash(const u32 raddr, const u16 rport,
+static inline u32 inet_synq_hash(const __be32 raddr, const __be16 rport,
const u32 rnd, const u16 synq_hsize)
{
- return jhash_2words(raddr, (u32)rport, rnd) & (synq_hsize - 1);
+ return jhash_2words((__force u32)raddr, (__force u32)rport, rnd) & (synq_hsize - 1);
}
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
@@ -356,8 +356,8 @@ static inline u32 inet_synq_hash(const u32 raddr, const u16 rport,
struct request_sock *inet_csk_search_req(const struct sock *sk,
struct request_sock ***prevp,
- const __u16 rport, const __u32 raddr,
- const __u32 laddr)
+ const __be16 rport, const __be32 raddr,
+ const __be32 laddr)
{
const struct inet_connection_sock *icsk = inet_csk(sk);
struct listen_sock *lopt = icsk->icsk_accept_queue.listen_opt;
diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c
index 492858e6faf0..77761ac4f7bb 100644
--- a/net/ipv4/inet_diag.c
+++ b/net/ipv4/inet_diag.c
@@ -36,8 +36,8 @@
static const struct inet_diag_handler **inet_diag_table;
struct inet_diag_entry {
- u32 *saddr;
- u32 *daddr;
+ __be32 *saddr;
+ __be32 *daddr;
u16 sport;
u16 dport;
u16 family;
@@ -294,7 +294,7 @@ out:
return err;
}
-static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
+static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits)
{
int words = bits >> 5;
@@ -305,8 +305,8 @@ static int bitstring_match(const u32 *a1, const u32 *a2, int bits)
return 0;
}
if (bits) {
- __u32 w1, w2;
- __u32 mask;
+ __be32 w1, w2;
+ __be32 mask;
w1 = a1[words];
w2 = a2[words];
@@ -352,7 +352,7 @@ static int inet_diag_bc_run(const void *bc, int len,
case INET_DIAG_BC_S_COND:
case INET_DIAG_BC_D_COND: {
struct inet_diag_hostcond *cond;
- u32 *addr;
+ __be32 *addr;
cond = (struct inet_diag_hostcond *)(op + 1);
if (cond->port != -1 &&
diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c
index fb296c9a7f3f..244c4f445c7d 100644
--- a/net/ipv4/inet_hashtables.c
+++ b/net/ipv4/inet_hashtables.c
@@ -125,7 +125,7 @@ EXPORT_SYMBOL(inet_listen_wlock);
* wildcarded during the search since they can never be otherwise.
*/
static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
- const u32 daddr,
+ const __be32 daddr,
const unsigned short hnum,
const int dif)
{
@@ -137,7 +137,7 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
const struct inet_sock *inet = inet_sk(sk);
if (inet->num == hnum && !ipv6_only_sock(sk)) {
- const __u32 rcv_saddr = inet->rcv_saddr;
+ const __be32 rcv_saddr = inet->rcv_saddr;
int score = sk->sk_family == PF_INET ? 1 : 0;
if (rcv_saddr) {
@@ -163,7 +163,7 @@ static struct sock *inet_lookup_listener_slow(const struct hlist_head *head,
/* Optimize the common listener case. */
struct sock *__inet_lookup_listener(struct inet_hashinfo *hashinfo,
- const u32 daddr, const unsigned short hnum,
+ const __be32 daddr, const unsigned short hnum,
const int dif)
{
struct sock *sk = NULL;
@@ -197,11 +197,11 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row,
{
struct inet_hashinfo *hinfo = death_row->hashinfo;
struct inet_sock *inet = inet_sk(sk);
- u32 daddr = inet->rcv_saddr;
- u32 saddr = inet->daddr;
+ __be32 daddr = inet->rcv_saddr;
+ __be32 saddr = inet->daddr;
int dif = sk->sk_bound_dev_if;
INET_ADDR_COOKIE(acookie, saddr, daddr)
- const __u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
+ const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport);
unsigned int hash = inet_ehashfn(daddr, lport, saddr, inet->dport);
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
struct sock *sk2;
diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
index a675602ef295..f072f3875af8 100644
--- a/net/ipv4/inetpeer.c
+++ b/net/ipv4/inetpeer.c
@@ -94,10 +94,8 @@ int inet_peer_minttl = 120 * HZ; /* TTL under high load: 120 sec */
int inet_peer_maxttl = 10 * 60 * HZ; /* usual time to live: 10 min */
static struct inet_peer *inet_peer_unused_head;
-/* Exported for inet_putpeer inline function. */
-struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
-DEFINE_SPINLOCK(inet_peer_unused_lock);
-#define PEER_MAX_CLEANUP_WORK 30
+static struct inet_peer **inet_peer_unused_tailp = &inet_peer_unused_head;
+static DEFINE_SPINLOCK(inet_peer_unused_lock);
static void peer_check_expire(unsigned long dummy);
static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
@@ -163,7 +161,7 @@ static void unlink_from_unused(struct inet_peer *p)
for (u = peer_root; u != peer_avl_empty; ) { \
if (daddr == u->v4daddr) \
break; \
- if (daddr < u->v4daddr) \
+ if ((__force __u32)daddr < (__force __u32)u->v4daddr) \
v = &u->avl_left; \
else \
v = &u->avl_right; \
@@ -340,7 +338,8 @@ static int cleanup_once(unsigned long ttl)
spin_lock_bh(&inet_peer_unused_lock);
p = inet_peer_unused_head;
if (p != NULL) {
- if (time_after(p->dtime + ttl, jiffies)) {
+ __u32 delta = (__u32)jiffies - p->dtime;
+ if (delta < ttl) {
/* Do not prune fresh entries. */
spin_unlock_bh(&inet_peer_unused_lock);
return -1;
@@ -368,7 +367,7 @@ static int cleanup_once(unsigned long ttl)
}
/* Called with or without local BH being disabled. */
-struct inet_peer *inet_getpeer(__u32 daddr, int create)
+struct inet_peer *inet_getpeer(__be32 daddr, int create)
{
struct inet_peer *p, *n;
struct inet_peer **stack[PEER_MAXDEPTH], ***stackptr;
@@ -432,7 +431,7 @@ out_free:
/* Called with local BH disabled. */
static void peer_check_expire(unsigned long dummy)
{
- int i;
+ unsigned long now = jiffies;
int ttl;
if (peer_total >= inet_peer_threshold)
@@ -441,7 +440,10 @@ static void peer_check_expire(unsigned long dummy)
ttl = inet_peer_maxttl
- (inet_peer_maxttl - inet_peer_minttl) / HZ *
peer_total / inet_peer_threshold * HZ;
- for (i = 0; i < PEER_MAX_CLEANUP_WORK && !cleanup_once(ttl); i++);
+ while (!cleanup_once(ttl)) {
+ if (jiffies != now)
+ break;
+ }
/* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
* interval depending on the total number of entries (more entries,
@@ -455,3 +457,16 @@ static void peer_check_expire(unsigned long dummy)
peer_total / inet_peer_threshold * HZ;
add_timer(&peer_periodic_timer);
}
+
+void inet_putpeer(struct inet_peer *p)
+{
+ spin_lock_bh(&inet_peer_unused_lock);
+ if (atomic_dec_and_test(&p->refcnt)) {
+ p->unused_prevp = inet_peer_unused_tailp;
+ p->unused_next = NULL;
+ *inet_peer_unused_tailp = p;
+ inet_peer_unused_tailp = &p->unused_next;
+ p->dtime = (__u32)jiffies;
+ }
+ spin_unlock_bh(&inet_peer_unused_lock);
+}
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index 165d72859ddf..74046efdf875 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -77,9 +77,9 @@ struct ipq {
struct hlist_node list;
struct list_head lru_list; /* lru list member */
u32 user;
- u32 saddr;
- u32 daddr;
- u16 id;
+ __be32 saddr;
+ __be32 daddr;
+ __be16 id;
u8 protocol;
u8 last_in;
#define COMPLETE 4
@@ -123,9 +123,10 @@ static __inline__ void ipq_unlink(struct ipq *ipq)
write_unlock(&ipfrag_lock);
}
-static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot)
+static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot)
{
- return jhash_3words((u32)id << 16 | prot, saddr, daddr,
+ return jhash_3words((__force u32)id << 16 | prot,
+ (__force u32)saddr, (__force u32)daddr,
ipfrag_hash_rnd) & (IPQ_HASHSZ - 1);
}
@@ -387,8 +388,8 @@ out_nomem:
static inline struct ipq *ip_find(struct iphdr *iph, u32 user)
{
__be16 id = iph->id;
- __u32 saddr = iph->saddr;
- __u32 daddr = iph->daddr;
+ __be32 saddr = iph->saddr;
+ __be32 daddr = iph->daddr;
__u8 protocol = iph->protocol;
unsigned int hash;
struct ipq *qp;
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index f5fba051df3d..d5b5dec075b8 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -611,8 +611,8 @@ static int ipgre_rcv(struct sk_buff *skb)
* - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
*/
if (flags == 0 &&
- skb->protocol == __constant_htons(ETH_P_WCCP)) {
- skb->protocol = __constant_htons(ETH_P_IP);
+ skb->protocol == htons(ETH_P_WCCP)) {
+ skb->protocol = htons(ETH_P_IP);
if ((*(h + offset) & 0xF0) != 0x40)
offset += 4;
}
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index e7437c091326..8dabbfc31267 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -38,7 +38,7 @@
*/
void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
- u32 daddr, struct rtable *rt, int is_frag)
+ __be32 daddr, struct rtable *rt, int is_frag)
{
unsigned char * iph = skb->nh.raw;
@@ -57,7 +57,7 @@ void ip_options_build(struct sk_buff * skb, struct ip_options * opt,
ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, rt);
if (opt->ts_needtime) {
struct timeval tv;
- __u32 midtime;
+ __be32 midtime;
do_gettimeofday(&tv);
midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4);
@@ -91,7 +91,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
unsigned char *sptr, *dptr;
int soffset, doffset;
int optlen;
- u32 daddr;
+ __be32 daddr;
memset(dopt, 0, sizeof(struct ip_options));
@@ -148,7 +148,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
dopt->ts_needtime = 0;
if (soffset + 8 <= optlen) {
- __u32 addr;
+ __be32 addr;
memcpy(&addr, sptr+soffset-1, 4);
if (inet_addr_type(addr) != RTN_LOCAL) {
@@ -165,7 +165,7 @@ int ip_options_echo(struct ip_options * dopt, struct sk_buff * skb)
}
if (sopt->srr) {
unsigned char * start = sptr+sopt->srr;
- u32 faddr;
+ __be32 faddr;
optlen = start[1];
soffset = start[2];
@@ -362,7 +362,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
goto error;
}
if (optptr[2] <= optlen) {
- __u32 * timeptr = NULL;
+ __be32 *timeptr = NULL;
if (optptr[2]+3 > optptr[1]) {
pp_ptr = optptr + 2;
goto error;
@@ -371,7 +371,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
case IPOPT_TS_TSONLY:
opt->ts = optptr - iph;
if (skb)
- timeptr = (__u32*)&optptr[optptr[2]-1];
+ timeptr = (__be32*)&optptr[optptr[2]-1];
opt->ts_needtime = 1;
optptr[2] += 4;
break;
@@ -383,7 +383,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
opt->ts = optptr - iph;
if (skb) {
memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
- timeptr = (__u32*)&optptr[optptr[2]+3];
+ timeptr = (__be32*)&optptr[optptr[2]+3];
}
opt->ts_needaddr = 1;
opt->ts_needtime = 1;
@@ -396,12 +396,12 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
}
opt->ts = optptr - iph;
{
- u32 addr;
+ __be32 addr;
memcpy(&addr, &optptr[optptr[2]-1], 4);
if (inet_addr_type(addr) == RTN_UNICAST)
break;
if (skb)
- timeptr = (__u32*)&optptr[optptr[2]+3];
+ timeptr = (__be32*)&optptr[optptr[2]+3];
}
opt->ts_needtime = 1;
optptr[2] += 8;
@@ -415,10 +415,10 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
}
if (timeptr) {
struct timeval tv;
- __u32 midtime;
+ __be32 midtime;
do_gettimeofday(&tv);
midtime = htonl((tv.tv_sec % 86400) * 1000 + tv.tv_usec / 1000);
- memcpy(timeptr, &midtime, sizeof(__u32));
+ memcpy(timeptr, &midtime, sizeof(__be32));
opt->is_changed = 1;
}
} else {
@@ -607,7 +607,7 @@ int ip_options_rcv_srr(struct sk_buff *skb)
{
struct ip_options *opt = &(IPCB(skb)->opt);
int srrspace, srrptr;
- u32 nexthop;
+ __be32 nexthop;
struct iphdr *iph = skb->nh.iph;
unsigned char * optptr = skb->nh.raw + opt->srr;
struct rtable *rt = (struct rtable*)skb->dst;
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 97aee76fb746..fc195a44fc2e 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -118,7 +118,7 @@ static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst)
*
*/
int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,
- u32 saddr, u32 daddr, struct ip_options *opt)
+ __be32 saddr, __be32 daddr, struct ip_options *opt)
{
struct inet_sock *inet = inet_sk(sk);
struct rtable *rt = (struct rtable *)skb->dst;
@@ -306,7 +306,7 @@ int ip_queue_xmit(struct sk_buff *skb, int ipfragok)
/* Make sure we can route this packet. */
rt = (struct rtable *)__sk_dst_check(sk, 0);
if (rt == NULL) {
- u32 daddr;
+ __be32 daddr;
/* Use correct destination address if we have options. */
daddr = inet->daddr;
@@ -1340,7 +1340,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
char data[40];
} replyopts;
struct ipcm_cookie ipc;
- u32 daddr;
+ __be32 daddr;
struct rtable *rt = (struct rtable*)skb->dst;
if (ip_options_echo(&replyopts.opt, skb))
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 2d05c4133d3e..4b132953bcc2 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -254,7 +254,7 @@ int ip_ra_control(struct sock *sk, unsigned char on, void (*destructor)(struct s
}
void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
- u16 port, u32 info, u8 *payload)
+ __be16 port, u32 info, u8 *payload)
{
struct inet_sock *inet = inet_sk(sk);
struct sock_exterr_skb *serr;
@@ -283,7 +283,7 @@ void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
kfree_skb(skb);
}
-void ip_local_error(struct sock *sk, int err, u32 daddr, u16 port, u32 info)
+void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info)
{
struct inet_sock *inet = inet_sk(sk);
struct sock_exterr_skb *serr;
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 17342430a843..3839b706142e 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -183,7 +183,7 @@ out_ok:
static void ipcomp4_err(struct sk_buff *skb, u32 info)
{
- u32 spi;
+ __be32 spi;
struct iphdr *iph = (struct iphdr *)skb->data;
struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
struct xfrm_state *x;
@@ -206,6 +206,7 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
{
struct xfrm_state *t;
+ u8 mode = XFRM_MODE_TUNNEL;
t = xfrm_state_alloc();
if (t == NULL)
@@ -216,7 +217,9 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
t->id.daddr.a4 = x->id.daddr.a4;
memcpy(&t->sel, &x->sel, sizeof(t->sel));
t->props.family = AF_INET;
- t->props.mode = XFRM_MODE_TUNNEL;
+ if (x->props.mode == XFRM_MODE_BEET)
+ mode = x->props.mode;
+ t->props.mode = mode;
t->props.saddr.a4 = x->props.saddr.a4;
t->props.flags = x->props.flags;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index 1fbb38415b19..f8ce84759159 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -366,7 +366,7 @@ static int __init ic_defaults(void)
*/
if (!ic_host_name_set)
- sprintf(system_utsname.nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
+ sprintf(init_utsname()->nodename, "%u.%u.%u.%u", NIPQUAD(ic_myaddr));
if (root_server_addr == INADDR_NONE)
root_server_addr = ic_servaddr;
@@ -805,7 +805,7 @@ static void __init ic_do_bootp_ext(u8 *ext)
}
break;
case 12: /* Host name */
- ic_bootp_string(system_utsname.nodename, ext+1, *ext, __NEW_UTS_LEN);
+ ic_bootp_string(utsname()->nodename, ext+1, *ext, __NEW_UTS_LEN);
ic_host_name_set = 1;
break;
case 15: /* Domain name (DNS) */
@@ -816,7 +816,7 @@ static void __init ic_do_bootp_ext(u8 *ext)
ic_bootp_string(root_server_path, ext+1, *ext, sizeof(root_server_path));
break;
case 40: /* NIS Domain name (_not_ DNS) */
- ic_bootp_string(system_utsname.domainname, ext+1, *ext, __NEW_UTS_LEN);
+ ic_bootp_string(utsname()->domainname, ext+1, *ext, __NEW_UTS_LEN);
break;
}
}
@@ -1368,7 +1368,7 @@ static int __init ip_auto_config(void)
printk(", mask=%u.%u.%u.%u", NIPQUAD(ic_netmask));
printk(", gw=%u.%u.%u.%u", NIPQUAD(ic_gateway));
printk(",\n host=%s, domain=%s, nis-domain=%s",
- system_utsname.nodename, ic_domain, system_utsname.domainname);
+ utsname()->nodename, ic_domain, utsname()->domainname);
printk(",\n bootserver=%u.%u.%u.%u", NIPQUAD(ic_servaddr));
printk(", rootserver=%u.%u.%u.%u", NIPQUAD(root_server_addr));
printk(", rootpath=%s", root_server_path);
@@ -1478,11 +1478,11 @@ static int __init ip_auto_config_setup(char *addrs)
case 4:
if ((dp = strchr(ip, '.'))) {
*dp++ = '\0';
- strlcpy(system_utsname.domainname, dp,
- sizeof(system_utsname.domainname));
+ strlcpy(utsname()->domainname, dp,
+ sizeof(utsname()->domainname));
}
- strlcpy(system_utsname.nodename, ip,
- sizeof(system_utsname.nodename));
+ strlcpy(utsname()->nodename, ip,
+ sizeof(utsname()->nodename));
ic_host_name_set = 1;
break;
case 5:
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index ba49588da242..97cfa97c8abb 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -462,7 +462,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock)
return 0;
}
-static struct mfc_cache *ipmr_cache_find(__u32 origin, __u32 mcastgrp)
+static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp)
{
int line=MFC_HASH(mcastgrp,origin);
struct mfc_cache *c;
@@ -1097,7 +1097,7 @@ static struct notifier_block ip_mr_notifier={
* important for multicast video.
*/
-static void ip_encap(struct sk_buff *skb, u32 saddr, u32 daddr)
+static void ip_encap(struct sk_buff *skb, __be32 saddr, __be32 daddr)
{
struct iphdr *iph = (struct iphdr *)skb_push(skb,sizeof(struct iphdr));
diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
index c9820bfc493a..891b9355cf96 100644
--- a/net/ipv4/ipvs/Kconfig
+++ b/net/ipv4/ipvs/Kconfig
@@ -81,7 +81,7 @@ config IP_VS_PROTO_ESP
bool "ESP load balancing support"
depends on IP_VS
---help---
- This option enables support for load balancing ESP (Encapsultion
+ This option enables support for load balancing ESP (Encapsulation
Security Payload) transport protocol. Say Y if unsure.
config IP_VS_PROTO_AH
@@ -204,7 +204,7 @@ config IP_VS_SED
connections to the server with the shortest expected delay. 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 connections
- on the the ith server and Ui is the fixed service rate (weight)
+ on the ith server and Ui is the fixed service rate (weight)
of the ith server.
If you want to compile it in kernel, say Y. To compile it as a
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index 87b83813cf2c..8832eb517d52 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -115,9 +115,9 @@ static inline void ct_write_unlock_bh(unsigned key)
/*
* Returns hash value for IPVS connection entry
*/
-static unsigned int ip_vs_conn_hashkey(unsigned proto, __u32 addr, __u16 port)
+static unsigned int ip_vs_conn_hashkey(unsigned proto, __be32 addr, __be16 port)
{
- return jhash_3words(addr, port, proto, ip_vs_conn_rnd)
+ return jhash_3words((__force u32)addr, (__force u32)port, proto, ip_vs_conn_rnd)
& IP_VS_CONN_TAB_MASK;
}
@@ -188,7 +188,7 @@ static inline int ip_vs_conn_unhash(struct ip_vs_conn *cp)
* d_addr, d_port: pkt dest address (load balancer)
*/
static inline struct ip_vs_conn *__ip_vs_conn_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
{
unsigned hash;
struct ip_vs_conn *cp;
@@ -215,7 +215,7 @@ static inline struct ip_vs_conn *__ip_vs_conn_in_get
}
struct ip_vs_conn *ip_vs_conn_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
{
struct ip_vs_conn *cp;
@@ -234,7 +234,7 @@ struct ip_vs_conn *ip_vs_conn_in_get
/* Get reference to connection template */
struct ip_vs_conn *ip_vs_ct_in_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
{
unsigned hash;
struct ip_vs_conn *cp;
@@ -274,7 +274,7 @@ struct ip_vs_conn *ip_vs_ct_in_get
* d_addr, d_port: pkt dest address (foreign host)
*/
struct ip_vs_conn *ip_vs_conn_out_get
-(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+(int protocol, __be32 s_addr, __be16 s_port, __be32 d_addr, __be16 d_port)
{
unsigned hash;
struct ip_vs_conn *cp, *ret=NULL;
@@ -324,7 +324,7 @@ void ip_vs_conn_put(struct ip_vs_conn *cp)
/*
* Fill a no_client_port connection with a client port number
*/
-void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __u16 cport)
+void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport)
{
if (ip_vs_conn_unhash(cp)) {
spin_lock(&cp->lock);
@@ -508,10 +508,10 @@ int ip_vs_check_template(struct ip_vs_conn *ct)
/*
* Invalidate the connection template
*/
- if (ct->vport != 65535) {
+ if (ct->vport != htons(0xffff)) {
if (ip_vs_conn_unhash(ct)) {
- ct->dport = 65535;
- ct->vport = 65535;
+ ct->dport = htons(0xffff);
+ ct->vport = htons(0xffff);
ct->cport = 0;
ip_vs_conn_hash(ct);
}
@@ -596,8 +596,8 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
* Create a new connection entry and hash it into the ip_vs_conn_tab
*/
struct ip_vs_conn *
-ip_vs_conn_new(int proto, __u32 caddr, __u16 cport, __u32 vaddr, __u16 vport,
- __u32 daddr, __u16 dport, unsigned flags,
+ip_vs_conn_new(int proto, __be32 caddr, __be16 cport, __be32 vaddr, __be16 vport,
+ __be32 daddr, __be16 dport, unsigned flags,
struct ip_vs_dest *dest)
{
struct ip_vs_conn *cp;
diff --git a/net/ipv4/ipvs/ip_vs_core.c b/net/ipv4/ipvs/ip_vs_core.c
index 3f47ad8e1cad..1445bb47fea4 100644
--- a/net/ipv4/ipvs/ip_vs_core.c
+++ b/net/ipv4/ipvs/ip_vs_core.c
@@ -209,14 +209,14 @@ int ip_vs_make_skb_writable(struct sk_buff **pskb, int writable_len)
static struct ip_vs_conn *
ip_vs_sched_persist(struct ip_vs_service *svc,
const struct sk_buff *skb,
- __u16 ports[2])
+ __be16 ports[2])
{
struct ip_vs_conn *cp = NULL;
struct iphdr *iph = skb->nh.iph;
struct ip_vs_dest *dest;
struct ip_vs_conn *ct;
- __u16 dport; /* destination port to forward */
- __u32 snet; /* source network of the client, after masking */
+ __be16 dport; /* destination port to forward */
+ __be32 snet; /* source network of the client, after masking */
/* Mask saddr with the netmask to adjust template granularity */
snet = iph->saddr & svc->netmask;
@@ -383,7 +383,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
struct ip_vs_conn *cp = NULL;
struct iphdr *iph = skb->nh.iph;
struct ip_vs_dest *dest;
- __u16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, iph->ihl*4,
sizeof(_ports), _ports);
@@ -446,7 +446,7 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct ip_vs_protocol *pp)
{
- __u16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr;
struct iphdr *iph = skb->nh.iph;
pptr = skb_header_pointer(skb, iph->ihl*4,
@@ -576,7 +576,7 @@ void ip_vs_nat_icmp(struct sk_buff *skb, struct ip_vs_protocol *pp,
/* the TCP/UDP port */
if (IPPROTO_TCP == ciph->protocol || IPPROTO_UDP == ciph->protocol) {
- __u16 *ports = (void *)ciph + ciph->ihl*4;
+ __be16 *ports = (void *)ciph + ciph->ihl*4;
if (inout)
ports[1] = cp->vport;
@@ -775,7 +775,7 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
if (sysctl_ip_vs_nat_icmp_send &&
(pp->protocol == IPPROTO_TCP ||
pp->protocol == IPPROTO_UDP)) {
- __u16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, ihl,
sizeof(_ports), _ports);
@@ -813,6 +813,16 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
skb->nh.iph->saddr = cp->vaddr;
ip_send_check(skb->nh.iph);
+ /* For policy routing, packets originating from this
+ * machine itself may be routed differently to packets
+ * passing through. We want this packet to be routed as
+ * if it came from this machine itself. So re-compute
+ * the routing information.
+ */
+ if (ip_route_me_harder(pskb, RTN_LOCAL) != 0)
+ goto drop;
+ skb = *pskb;
+
IP_VS_DBG_PKT(10, pp, skb, 0, "After SNAT");
ip_vs_out_stats(cp, skb);
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 6a28fafe910c..f261616e4602 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -283,7 +283,7 @@ static atomic_t ip_vs_nullsvc_counter = ATOMIC_INIT(0);
* Returns hash value for virtual service
*/
static __inline__ unsigned
-ip_vs_svc_hashkey(unsigned proto, __u32 addr, __u16 port)
+ip_vs_svc_hashkey(unsigned proto, __be32 addr, __be16 port)
{
register unsigned porth = ntohs(port);
@@ -365,7 +365,7 @@ static int ip_vs_svc_unhash(struct ip_vs_service *svc)
* Get service by {proto,addr,port} in the service table.
*/
static __inline__ struct ip_vs_service *
-__ip_vs_service_get(__u16 protocol, __u32 vaddr, __u16 vport)
+__ip_vs_service_get(__u16 protocol, __be32 vaddr, __be16 vport)
{
unsigned hash;
struct ip_vs_service *svc;
@@ -410,7 +410,7 @@ static __inline__ struct ip_vs_service *__ip_vs_svc_fwm_get(__u32 fwmark)
}
struct ip_vs_service *
-ip_vs_service_get(__u32 fwmark, __u16 protocol, __u32 vaddr, __u16 vport)
+ip_vs_service_get(__u32 fwmark, __u16 protocol, __be32 vaddr, __be16 vport)
{
struct ip_vs_service *svc;
@@ -480,7 +480,7 @@ __ip_vs_unbind_svc(struct ip_vs_dest *dest)
/*
* Returns hash value for real service
*/
-static __inline__ unsigned ip_vs_rs_hashkey(__u32 addr, __u16 port)
+static __inline__ unsigned ip_vs_rs_hashkey(__be32 addr, __be16 port)
{
register unsigned porth = ntohs(port);
@@ -531,7 +531,7 @@ static int ip_vs_rs_unhash(struct ip_vs_dest *dest)
* Lookup real service by <proto,addr,port> in the real service table.
*/
struct ip_vs_dest *
-ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport)
+ip_vs_lookup_real_service(__u16 protocol, __be32 daddr, __be16 dport)
{
unsigned hash;
struct ip_vs_dest *dest;
@@ -562,7 +562,7 @@ ip_vs_lookup_real_service(__u16 protocol, __u32 daddr, __u16 dport)
* Lookup destination by {addr,port} in the given service
*/
static struct ip_vs_dest *
-ip_vs_lookup_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
+ip_vs_lookup_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
{
struct ip_vs_dest *dest;
@@ -591,7 +591,7 @@ ip_vs_lookup_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
* scheduling.
*/
static struct ip_vs_dest *
-ip_vs_trash_get_dest(struct ip_vs_service *svc, __u32 daddr, __u16 dport)
+ip_vs_trash_get_dest(struct ip_vs_service *svc, __be32 daddr, __be16 dport)
{
struct ip_vs_dest *dest, *nxt;
@@ -773,8 +773,8 @@ static int
ip_vs_add_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
{
struct ip_vs_dest *dest;
- __u32 daddr = udest->addr;
- __u16 dport = udest->port;
+ __be32 daddr = udest->addr;
+ __be16 dport = udest->port;
int ret;
EnterFunction(2);
@@ -879,8 +879,8 @@ static int
ip_vs_edit_dest(struct ip_vs_service *svc, struct ip_vs_dest_user *udest)
{
struct ip_vs_dest *dest;
- __u32 daddr = udest->addr;
- __u16 dport = udest->port;
+ __be32 daddr = udest->addr;
+ __be16 dport = udest->port;
EnterFunction(2);
@@ -991,8 +991,8 @@ static int
ip_vs_del_dest(struct ip_vs_service *svc,struct ip_vs_dest_user *udest)
{
struct ip_vs_dest *dest;
- __u32 daddr = udest->addr;
- __u16 dport = udest->port;
+ __be32 daddr = udest->addr;
+ __be16 dport = udest->port;
EnterFunction(2);
diff --git a/net/ipv4/ipvs/ip_vs_dh.c b/net/ipv4/ipvs/ip_vs_dh.c
index 9fee19c4c617..502111fba872 100644
--- a/net/ipv4/ipvs/ip_vs_dh.c
+++ b/net/ipv4/ipvs/ip_vs_dh.c
@@ -66,7 +66,7 @@ struct ip_vs_dh_bucket {
/*
* Returns hash value for IPVS DH entry
*/
-static inline unsigned ip_vs_dh_hashkey(__u32 addr)
+static inline unsigned ip_vs_dh_hashkey(__be32 addr)
{
return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK;
}
@@ -76,7 +76,7 @@ static inline unsigned ip_vs_dh_hashkey(__u32 addr)
* Get ip_vs_dest associated with supplied parameters.
*/
static inline struct ip_vs_dest *
-ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __u32 addr)
+ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __be32 addr)
{
return (tbl[ip_vs_dh_hashkey(addr)]).dest;
}
diff --git a/net/ipv4/ipvs/ip_vs_ftp.c b/net/ipv4/ipvs/ip_vs_ftp.c
index 37fafb1fbcff..6d398f10aa91 100644
--- a/net/ipv4/ipvs/ip_vs_ftp.c
+++ b/net/ipv4/ipvs/ip_vs_ftp.c
@@ -32,6 +32,7 @@
#include <linux/ip.h>
#include <net/protocol.h>
#include <net/tcp.h>
+#include <asm/unaligned.h>
#include <net/ip_vs.h>
@@ -44,8 +45,8 @@
* List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper
* First port is set to the default port.
*/
-static int ports[IP_VS_APP_MAX_PORTS] = {21, 0};
-module_param_array(ports, int, NULL, 0);
+static unsigned short ports[IP_VS_APP_MAX_PORTS] = {21, 0};
+module_param_array(ports, ushort, NULL, 0);
MODULE_PARM_DESC(ports, "Ports to monitor for FTP control commands");
@@ -74,7 +75,7 @@ ip_vs_ftp_done_conn(struct ip_vs_app *app, struct ip_vs_conn *cp)
*/
static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
const char *pattern, size_t plen, char term,
- __u32 *addr, __u16 *port,
+ __be32 *addr, __be16 *port,
char **start, char **end)
{
unsigned char p[6];
@@ -114,8 +115,8 @@ static int ip_vs_ftp_get_addrport(char *data, char *data_limit,
if (i != 5)
return -1;
- *addr = (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
- *port = (p[5]<<8) | p[4];
+ *addr = get_unaligned((__be32 *)p);
+ *port = get_unaligned((__be16 *)(p + 4));
return 1;
}
@@ -140,8 +141,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
struct tcphdr *th;
char *data, *data_limit;
char *start, *end;
- __u32 from;
- __u16 port;
+ __be32 from;
+ __be16 port;
struct ip_vs_conn *n_cp;
char buf[24]; /* xxx.xxx.xxx.xxx,ppp,ppp\000 */
unsigned buf_len;
@@ -199,7 +200,7 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp,
from = n_cp->vaddr;
port = n_cp->vport;
sprintf(buf,"%d,%d,%d,%d,%d,%d", NIPQUAD(from),
- port&255, (port>>8)&255);
+ ntohs(port)&255, (ntohs(port)>>8)&255);
buf_len = strlen(buf);
/*
@@ -243,8 +244,8 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
struct tcphdr *th;
char *data, *data_start, *data_limit;
char *start, *end;
- __u32 to;
- __u16 port;
+ __be32 to;
+ __be16 port;
struct ip_vs_conn *n_cp;
/* no diff required for incoming packets */
@@ -273,7 +274,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp,
while (data <= data_limit - 6) {
if (strnicmp(data, "PASV\r\n", 6) == 0) {
/* Passive mode on */
- IP_VS_DBG(7, "got PASV at %zd of %zd\n",
+ IP_VS_DBG(7, "got PASV at %td of %td\n",
data - data_start,
data_limit - data_start);
cp->app_data = &ip_vs_ftp_pasv;
@@ -365,12 +366,6 @@ static int __init ip_vs_ftp_init(void)
for (i=0; i<IP_VS_APP_MAX_PORTS; i++) {
if (!ports[i])
continue;
- if (ports[i] < 0 || ports[i] > 0xffff) {
- IP_VS_WARNING("ip_vs_ftp: Ignoring invalid "
- "configuration port[%d] = %d\n",
- i, ports[i]);
- continue;
- }
ret = register_ip_vs_app_inc(app, app->protocol, ports[i]);
if (ret)
break;
diff --git a/net/ipv4/ipvs/ip_vs_lblc.c b/net/ipv4/ipvs/ip_vs_lblc.c
index 6e5cb92a5c83..524751e031de 100644
--- a/net/ipv4/ipvs/ip_vs_lblc.c
+++ b/net/ipv4/ipvs/ip_vs_lblc.c
@@ -87,7 +87,7 @@ static int sysctl_ip_vs_lblc_expiration = 24*60*60*HZ;
*/
struct ip_vs_lblc_entry {
struct list_head list;
- __u32 addr; /* destination IP address */
+ __be32 addr; /* destination IP address */
struct ip_vs_dest *dest; /* real server (cache) */
unsigned long lastuse; /* last used time */
};
@@ -160,7 +160,7 @@ static struct ctl_table_header * sysctl_header;
* IP address to a server.
*/
static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_new(__u32 daddr, struct ip_vs_dest *dest)
+ip_vs_lblc_new(__be32 daddr, struct ip_vs_dest *dest)
{
struct ip_vs_lblc_entry *en;
@@ -195,7 +195,7 @@ static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en)
/*
* Returns hash value for IPVS LBLC entry
*/
-static inline unsigned ip_vs_lblc_hashkey(__u32 addr)
+static inline unsigned ip_vs_lblc_hashkey(__be32 addr)
{
return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK;
}
@@ -234,7 +234,7 @@ ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en)
* Get ip_vs_lblc_entry associated with supplied parameters.
*/
static inline struct ip_vs_lblc_entry *
-ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __u32 addr)
+ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr)
{
unsigned hash;
struct ip_vs_lblc_entry *en;
diff --git a/net/ipv4/ipvs/ip_vs_lblcr.c b/net/ipv4/ipvs/ip_vs_lblcr.c
index 32ba37ba72d8..08990192b6ec 100644
--- a/net/ipv4/ipvs/ip_vs_lblcr.c
+++ b/net/ipv4/ipvs/ip_vs_lblcr.c
@@ -276,7 +276,7 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set)
*/
struct ip_vs_lblcr_entry {
struct list_head list;
- __u32 addr; /* destination IP address */
+ __be32 addr; /* destination IP address */
struct ip_vs_dest_set set; /* destination server set */
unsigned long lastuse; /* last used time */
};
@@ -348,7 +348,7 @@ static struct ctl_table_header * sysctl_header;
* new/free a ip_vs_lblcr_entry, which is a mapping of a destination
* IP address to a server.
*/
-static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__u32 daddr)
+static inline struct ip_vs_lblcr_entry *ip_vs_lblcr_new(__be32 daddr)
{
struct ip_vs_lblcr_entry *en;
@@ -381,7 +381,7 @@ static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en)
/*
* Returns hash value for IPVS LBLCR entry
*/
-static inline unsigned ip_vs_lblcr_hashkey(__u32 addr)
+static inline unsigned ip_vs_lblcr_hashkey(__be32 addr)
{
return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK;
}
@@ -420,7 +420,7 @@ ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en)
* Get ip_vs_lblcr_entry associated with supplied parameters.
*/
static inline struct ip_vs_lblcr_entry *
-ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __u32 addr)
+ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr)
{
unsigned hash;
struct ip_vs_lblcr_entry *en;
diff --git a/net/ipv4/ipvs/ip_vs_proto.c b/net/ipv4/ipvs/ip_vs_proto.c
index 867d4e9c6594..c4528b5c800d 100644
--- a/net/ipv4/ipvs/ip_vs_proto.c
+++ b/net/ipv4/ipvs/ip_vs_proto.c
@@ -176,7 +176,7 @@ ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
pp->name, NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr));
else {
- __u16 _ports[2], *pptr
+ __be16 _ports[2], *pptr
;
pptr = skb_header_pointer(skb, offset + ih->ihl*4,
sizeof(_ports), _ports);
diff --git a/net/ipv4/ipvs/ip_vs_proto_tcp.c b/net/ipv4/ipvs/ip_vs_proto_tcp.c
index 820e8318d10d..bfe779e74590 100644
--- a/net/ipv4/ipvs/ip_vs_proto_tcp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_tcp.c
@@ -29,7 +29,7 @@ static struct ip_vs_conn *
tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
- __u16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
if (pptr == NULL)
@@ -50,7 +50,7 @@ static struct ip_vs_conn *
tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
- __u16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
if (pptr == NULL)
@@ -112,12 +112,12 @@ tcp_conn_schedule(struct sk_buff *skb,
static inline void
-tcp_fast_csum_update(struct tcphdr *tcph, u32 oldip, u32 newip,
- u16 oldport, u16 newport)
+tcp_fast_csum_update(struct tcphdr *tcph, __be32 oldip, __be32 newip,
+ __be16 oldport, __be16 newport)
{
tcph->check =
ip_vs_check_diff(~oldip, newip,
- ip_vs_check_diff(oldport ^ 0xFFFF,
+ ip_vs_check_diff(oldport ^ htonl(0xFFFF),
newport, tcph->check));
}
diff --git a/net/ipv4/ipvs/ip_vs_proto_udp.c b/net/ipv4/ipvs/ip_vs_proto_udp.c
index 90c8166c0ec1..54aa7603591f 100644
--- a/net/ipv4/ipvs/ip_vs_proto_udp.c
+++ b/net/ipv4/ipvs/ip_vs_proto_udp.c
@@ -29,7 +29,7 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
struct ip_vs_conn *cp;
- __u16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
if (pptr == NULL)
@@ -54,7 +54,7 @@ udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
struct ip_vs_conn *cp;
- __u16 _ports[2], *pptr;
+ __be16 _ports[2], *pptr;
pptr = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_ports), _ports);
@@ -117,15 +117,15 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
static inline void
-udp_fast_csum_update(struct udphdr *uhdr, u32 oldip, u32 newip,
- u16 oldport, u16 newport)
+udp_fast_csum_update(struct udphdr *uhdr, __be32 oldip, __be32 newip,
+ __be16 oldport, __be16 newport)
{
uhdr->check =
ip_vs_check_diff(~oldip, newip,
- ip_vs_check_diff(oldport ^ 0xFFFF,
+ ip_vs_check_diff(oldport ^ htonl(0xFFFF),
newport, uhdr->check));
if (!uhdr->check)
- uhdr->check = 0xFFFF;
+ uhdr->check = htonl(0xFFFF);
}
static int
@@ -173,7 +173,7 @@ udp_snat_handler(struct sk_buff **pskb,
cp->protocol,
(*pskb)->csum);
if (udph->check == 0)
- udph->check = 0xFFFF;
+ udph->check = htonl(0xFFFF);
IP_VS_DBG(11, "O-pkt: %s O-csum=%d (+%zd)\n",
pp->name, udph->check,
(char*)&(udph->check) - (char*)udph);
diff --git a/net/ipv4/ipvs/ip_vs_sh.c b/net/ipv4/ipvs/ip_vs_sh.c
index 7775e6cc68be..338668f88fe2 100644
--- a/net/ipv4/ipvs/ip_vs_sh.c
+++ b/net/ipv4/ipvs/ip_vs_sh.c
@@ -63,7 +63,7 @@ struct ip_vs_sh_bucket {
/*
* Returns hash value for IPVS SH entry
*/
-static inline unsigned ip_vs_sh_hashkey(__u32 addr)
+static inline unsigned ip_vs_sh_hashkey(__be32 addr)
{
return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK;
}
@@ -73,7 +73,7 @@ static inline unsigned ip_vs_sh_hashkey(__u32 addr)
* Get ip_vs_dest associated with supplied parameters.
*/
static inline struct ip_vs_dest *
-ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __u32 addr)
+ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __be32 addr)
{
return (tbl[ip_vs_sh_hashkey(addr)]).dest;
}
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 1bca714bda3d..91a075edd68e 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -48,16 +48,16 @@ struct ip_vs_sync_conn {
/* Protocol, addresses and port numbers */
__u8 protocol; /* Which protocol (TCP/UDP) */
- __u16 cport;
- __u16 vport;
- __u16 dport;
- __u32 caddr; /* client address */
- __u32 vaddr; /* virtual address */
- __u32 daddr; /* destination address */
+ __be16 cport;
+ __be16 vport;
+ __be16 dport;
+ __be32 caddr; /* client address */
+ __be32 vaddr; /* virtual address */
+ __be32 daddr; /* destination address */
/* Flags and state transition */
- __u16 flags; /* status flags */
- __u16 state; /* state info */
+ __be16 flags; /* status flags */
+ __be16 state; /* state info */
/* The sequence options start here */
};
@@ -464,7 +464,7 @@ join_mcast_group(struct sock *sk, struct in_addr *addr, char *ifname)
static int bind_mcastif_addr(struct socket *sock, char *ifname)
{
struct net_device *dev;
- u32 addr;
+ __be32 addr;
struct sockaddr_in sin;
if ((dev = __dev_get_by_name(ifname)) == NULL)
@@ -836,7 +836,7 @@ static int fork_sync_thread(void *startup)
int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
{
- DECLARE_COMPLETION(startup);
+ DECLARE_COMPLETION_ONSTACK(startup);
pid_t pid;
if ((state == IP_VS_STATE_MASTER && sync_master_pid) ||
diff --git a/net/ipv4/ipvs/ip_vs_xmit.c b/net/ipv4/ipvs/ip_vs_xmit.c
index 52c12e9edbbc..e1f77bd7c9a5 100644
--- a/net/ipv4/ipvs/ip_vs_xmit.c
+++ b/net/ipv4/ipvs/ip_vs_xmit.c
@@ -232,7 +232,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* check if it is a connection of no-client-port */
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
- __u16 _pt, *p;
+ __be16 _pt, *p;
p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt);
if (p == NULL)
goto tx_error;
diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c
index d25ec4ae09e5..92b04823e034 100644
--- a/net/ipv4/multipath_wrandom.c
+++ b/net/ipv4/multipath_wrandom.c
@@ -60,8 +60,8 @@ struct multipath_dest {
struct list_head list;
const struct fib_nh *nh_info;
- __u32 netmask;
- __u32 network;
+ __be32 netmask;
+ __be32 network;
unsigned char prefixlen;
struct rcu_head rcu;
@@ -76,7 +76,7 @@ struct multipath_route {
struct list_head list;
int oif;
- __u32 gw;
+ __be32 gw;
struct list_head dests;
struct rcu_head rcu;
@@ -128,8 +128,8 @@ static unsigned char __multipath_lookup_weight(const struct flowi *fl,
/* find state entry for destination */
list_for_each_entry_rcu(d, &target_route->dests, list) {
- __u32 targetnetwork = fl->fl4_dst &
- (0xFFFFFFFF >> (32 - d->prefixlen));
+ __be32 targetnetwork = fl->fl4_dst &
+ inet_make_mask(d->prefixlen);
if ((targetnetwork & d->netmask) == d->network) {
weight = d->nh_info->nh_weight;
@@ -217,8 +217,8 @@ static void wrandom_select_route(const struct flowi *flp,
*rp = decision;
}
-static void wrandom_set_nhinfo(__u32 network,
- __u32 netmask,
+static void wrandom_set_nhinfo(__be32 network,
+ __be32 netmask,
unsigned char prefixlen,
const struct fib_nh *nh)
{
diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c
index f88347de21a9..e2005c6810a4 100644
--- a/net/ipv4/netfilter.c
+++ b/net/ipv4/netfilter.c
@@ -8,7 +8,7 @@
#include <net/ip.h>
/* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */
-int ip_route_me_harder(struct sk_buff **pskb)
+int ip_route_me_harder(struct sk_buff **pskb, unsigned addr_type)
{
struct iphdr *iph = (*pskb)->nh.iph;
struct rtable *rt;
@@ -16,10 +16,13 @@ int ip_route_me_harder(struct sk_buff **pskb)
struct dst_entry *odst;
unsigned int hh_len;
+ if (addr_type == RTN_UNSPEC)
+ addr_type = inet_addr_type(iph->saddr);
+
/* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
* packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
*/
- if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
+ if (addr_type == RTN_LOCAL) {
fl.nl_u.ip4_u.daddr = iph->daddr;
fl.nl_u.ip4_u.saddr = iph->saddr;
fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
@@ -128,8 +131,8 @@ EXPORT_SYMBOL(ip_nat_decode_session);
*/
struct ip_rt_info {
- u_int32_t daddr;
- u_int32_t saddr;
+ __be32 daddr;
+ __be32 saddr;
u_int8_t tos;
};
@@ -156,7 +159,7 @@ static int nf_ip_reroute(struct sk_buff **pskb, const struct nf_info *info)
if (!(iph->tos == rt_info->tos
&& iph->daddr == rt_info->daddr
&& iph->saddr == rt_info->saddr))
- return ip_route_me_harder(pskb);
+ return ip_route_me_harder(pskb, RTN_UNSPEC);
}
return 0;
}
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig
index a55b8ff70ded..d88c292f118c 100644
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -373,7 +373,7 @@ config IP_NF_TARGET_ULOG
daemon using netlink multicast sockets; unlike the LOG target
which can only be viewed through syslog.
- The apropriate userspace logging daemon (ulogd) may be obtained from
+ The appropriate userspace logging daemon (ulogd) may be obtained from
<http://www.gnumonks.org/projects/ulogd/>
To compile it as a module, choose M here. If unsure, say N.
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index 85f0d73ebfb4..0849f1cced13 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -80,7 +80,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
{
char *arpptr = (char *)(arphdr + 1);
char *src_devaddr, *tgt_devaddr;
- u32 src_ipaddr, tgt_ipaddr;
+ __be32 src_ipaddr, tgt_ipaddr;
int i, ret;
#define FWINV(bool,invflg) ((bool) ^ !!(arpinfo->invflags & invflg))
@@ -1196,6 +1196,8 @@ err1:
static void __exit arp_tables_fini(void)
{
nf_unregister_sockopt(&arpt_sockopts);
+ xt_unregister_target(&arpt_error_target);
+ xt_unregister_target(&arpt_standard_target);
xt_proto_fini(NF_ARP);
}
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
index 0a7bd7f04061..6c7383a8e42b 100644
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -155,11 +155,11 @@ static int help(struct sk_buff **pskb,
exp->tuple.dst.protonum = IPPROTO_TCP;
exp->tuple.dst.u.tcp.port = htons(port);
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
exp->mask.dst.protonum = 0xFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
if (ip_nat_amanda_hook)
ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff,
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index c432b3163609..143c4668538b 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -149,8 +149,8 @@ static unsigned int ip_conntrack_hash_rnd;
static u_int32_t __hash_conntrack(const struct ip_conntrack_tuple *tuple,
unsigned int size, unsigned int rnd)
{
- return (jhash_3words(tuple->src.ip,
- (tuple->dst.ip ^ tuple->dst.protonum),
+ return (jhash_3words((__force u32)tuple->src.ip,
+ ((__force u32)tuple->dst.ip ^ tuple->dst.protonum),
(tuple->src.u.all | (tuple->dst.u.all << 16)),
rnd) % size);
}
@@ -1169,9 +1169,9 @@ void __ip_ct_refresh_acct(struct ip_conntrack *ct,
int ip_ct_port_tuple_to_nfattr(struct sk_buff *skb,
const struct ip_conntrack_tuple *tuple)
{
- NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(u_int16_t),
+ NFA_PUT(skb, CTA_PROTO_SRC_PORT, sizeof(__be16),
&tuple->src.u.tcp.port);
- NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(u_int16_t),
+ NFA_PUT(skb, CTA_PROTO_DST_PORT, sizeof(__be16),
&tuple->dst.u.tcp.port);
return 0;
@@ -1186,9 +1186,9 @@ int ip_ct_port_nfattr_to_tuple(struct nfattr *tb[],
return -EINVAL;
t->src.u.tcp.port =
- *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
+ *(__be16 *)NFA_DATA(tb[CTA_PROTO_SRC_PORT-1]);
t->dst.u.tcp.port =
- *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
+ *(__be16 *)NFA_DATA(tb[CTA_PROTO_DST_PORT-1]);
return 0;
}
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
index 1d18c863f064..93dcf960662f 100644
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -425,8 +425,8 @@ static int help(struct sk_buff **pskb,
exp->tuple.src.u.tcp.port = 0; /* Don't care. */
exp->tuple.dst.protonum = IPPROTO_TCP;
exp->mask = ((struct ip_conntrack_tuple)
- { { 0xFFFFFFFF, { 0 } },
- { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
+ { { htonl(0xFFFFFFFF), { 0 } },
+ { htonl(0xFFFFFFFF), { .tcp = { htons(0xFFFF) } }, 0xFF }});
exp->expectfn = NULL;
exp->flags = 0;
@@ -488,7 +488,7 @@ static int __init ip_conntrack_ftp_init(void)
for (i = 0; i < ports_c; i++) {
ftp[i].tuple.src.u.tcp.port = htons(ports[i]);
ftp[i].tuple.dst.protonum = IPPROTO_TCP;
- ftp[i].mask.src.u.tcp.port = 0xFFFF;
+ ftp[i].mask.src.u.tcp.port = htons(0xFFFF);
ftp[i].mask.dst.protonum = 0xFF;
ftp[i].max_expected = 1;
ftp[i].timeout = 5 * 60; /* 5 minutes */
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_h323.c b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
index 9a39e2969712..7b7441202bfd 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_h323.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_h323.c
@@ -49,11 +49,11 @@ MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations "
int (*set_h245_addr_hook) (struct sk_buff ** pskb,
unsigned char **data, int dataoff,
H245_TransportAddress * addr,
- u_int32_t ip, u_int16_t port);
+ __be32 ip, u_int16_t port);
int (*set_h225_addr_hook) (struct sk_buff ** pskb,
unsigned char **data, int dataoff,
TransportAddress * addr,
- u_int32_t ip, u_int16_t port);
+ __be32 ip, u_int16_t port);
int (*set_sig_addr_hook) (struct sk_buff ** pskb,
struct ip_conntrack * ct,
enum ip_conntrack_info ctinfo,
@@ -209,7 +209,7 @@ static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct,
/****************************************************************************/
static int get_h245_addr(unsigned char *data, H245_TransportAddress * addr,
- u_int32_t * ip, u_int16_t * port)
+ __be32 * ip, u_int16_t * port)
{
unsigned char *p;
@@ -232,7 +232,7 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
{
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
u_int16_t rtp_port;
struct ip_conntrack_expect *rtp_exp;
@@ -254,10 +254,10 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
rtp_exp->tuple.dst.u.udp.port = htons(rtp_port);
rtp_exp->tuple.dst.protonum = IPPROTO_UDP;
- rtp_exp->mask.src.ip = 0xFFFFFFFF;
+ rtp_exp->mask.src.ip = htonl(0xFFFFFFFF);
rtp_exp->mask.src.u.udp.port = 0;
- rtp_exp->mask.dst.ip = 0xFFFFFFFF;
- rtp_exp->mask.dst.u.udp.port = 0xFFFF;
+ rtp_exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ rtp_exp->mask.dst.u.udp.port = htons(0xFFFF);
rtp_exp->mask.dst.protonum = 0xFF;
rtp_exp->flags = 0;
@@ -271,10 +271,10 @@ static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct,
rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1);
rtcp_exp->tuple.dst.protonum = IPPROTO_UDP;
- rtcp_exp->mask.src.ip = 0xFFFFFFFF;
+ rtcp_exp->mask.src.ip = htonl(0xFFFFFFFF);
rtcp_exp->mask.src.u.udp.port = 0;
- rtcp_exp->mask.dst.ip = 0xFFFFFFFF;
- rtcp_exp->mask.dst.u.udp.port = 0xFFFF;
+ rtcp_exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ rtcp_exp->mask.dst.u.udp.port = htons(0xFFFF);
rtcp_exp->mask.dst.protonum = 0xFF;
rtcp_exp->flags = 0;
@@ -325,7 +325,7 @@ static int expect_t120(struct sk_buff **pskb,
{
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp = NULL;
@@ -342,10 +342,10 @@ static int expect_t120(struct sk_buff **pskb,
exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
exp->tuple.dst.u.tcp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */
@@ -626,7 +626,7 @@ void ip_conntrack_h245_expect(struct ip_conntrack *new,
/****************************************************************************/
int get_h225_addr(unsigned char *data, TransportAddress * addr,
- u_int32_t * ip, u_int16_t * port)
+ __be32 * ip, u_int16_t * port)
{
unsigned char *p;
@@ -648,7 +648,7 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
{
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp = NULL;
@@ -665,10 +665,10 @@ static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
exp->tuple.dst.u.tcp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->flags = 0;
@@ -709,7 +709,7 @@ static int expect_callforwarding(struct sk_buff **pskb,
{
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp = NULL;
@@ -751,10 +751,10 @@ static int expect_callforwarding(struct sk_buff **pskb,
exp->tuple.dst.ip = ip;
exp->tuple.dst.u.tcp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->flags = 0;
@@ -791,7 +791,7 @@ static int process_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
int dir = CTINFO2DIR(ctinfo);
int ret;
int i;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
DEBUGP("ip_ct_q931: Setup\n");
@@ -1188,7 +1188,7 @@ static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen)
/****************************************************************************/
static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct,
- u_int32_t ip, u_int16_t port)
+ __be32 ip, u_int16_t port)
{
struct ip_conntrack_expect *exp;
struct ip_conntrack_tuple tuple;
@@ -1228,7 +1228,7 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
int i;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp;
@@ -1251,10 +1251,10 @@ static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip;
exp->tuple.dst.u.tcp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = gkrouted_only ? 0xFFFFFFFF : 0;
+ exp->mask.src.ip = gkrouted_only ? htonl(0xFFFFFFFF) : 0;
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */
@@ -1307,7 +1307,7 @@ static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct,
{
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp;
@@ -1333,10 +1333,10 @@ static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct,
exp->tuple.dst.ip = ip;
exp->tuple.dst.u.tcp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_UDP;
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->flags = 0;
exp->expectfn = ip_conntrack_ras_expect;
@@ -1477,7 +1477,7 @@ static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct,
{
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
int dir = CTINFO2DIR(ctinfo);
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
DEBUGP("ip_ct_ras: ARQ\n");
@@ -1513,7 +1513,7 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
{
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp;
@@ -1538,10 +1538,10 @@ static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
exp->tuple.dst.ip = ip;
exp->tuple.dst.u.tcp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->flags = IP_CT_EXPECT_PERMANENT;
exp->expectfn = ip_conntrack_q931_expect;
@@ -1581,7 +1581,7 @@ static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct,
{
int dir = CTINFO2DIR(ctinfo);
int ret = 0;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
struct ip_conntrack_expect *exp = NULL;
@@ -1598,10 +1598,10 @@ static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct,
exp->tuple.dst.ip = ip;
exp->tuple.dst.u.tcp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.tcp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.tcp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->flags = IP_CT_EXPECT_PERMANENT;
exp->expectfn = ip_conntrack_q931_expect;
diff --git a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
index fb0aee691721..a2af5e0c7f99 100644
--- a/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
+++ b/net/ipv4/netfilter/ip_conntrack_helper_pptp.c
@@ -242,10 +242,10 @@ exp_gre(struct ip_conntrack *ct,
exp_orig->tuple.dst.u.gre.key = callid;
exp_orig->tuple.dst.protonum = IPPROTO_GRE;
- exp_orig->mask.src.ip = 0xffffffff;
+ exp_orig->mask.src.ip = htonl(0xffffffff);
exp_orig->mask.src.u.all = 0;
exp_orig->mask.dst.u.gre.key = htons(0xffff);
- exp_orig->mask.dst.ip = 0xffffffff;
+ exp_orig->mask.dst.ip = htonl(0xffffffff);
exp_orig->mask.dst.protonum = 0xff;
exp_orig->master = ct;
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
index 44889075f3b2..75f7c3db1619 100644
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -218,7 +218,8 @@ static int help(struct sk_buff **pskb,
IPPROTO_TCP }});
exp->mask = ((struct ip_conntrack_tuple)
{ { 0, { 0 } },
- { 0xFFFFFFFF, { .tcp = { 0xFFFF } }, 0xFF }});
+ { htonl(0xFFFFFFFF),
+ { .tcp = { htons(0xFFFF) } }, 0xFF }});
exp->expectfn = NULL;
exp->flags = 0;
if (ip_nat_irc_hook)
@@ -266,7 +267,7 @@ static int __init ip_conntrack_irc_init(void)
hlpr = &irc_helpers[i];
hlpr->tuple.src.u.tcp.port = htons(ports[i]);
hlpr->tuple.dst.protonum = IPPROTO_TCP;
- hlpr->mask.src.u.tcp.port = 0xFFFF;
+ hlpr->mask.src.u.tcp.port = htons(0xFFFF);
hlpr->mask.dst.protonum = 0xFF;
hlpr->max_expected = max_dcc_channels;
hlpr->timeout = dcc_timeout;
diff --git a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
index 3d0b438783db..a1d6a89f64aa 100644
--- a/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
+++ b/net/ipv4/netfilter/ip_conntrack_netbios_ns.c
@@ -48,7 +48,7 @@ static int help(struct sk_buff **pskb,
struct iphdr *iph = (*pskb)->nh.iph;
struct rtable *rt = (struct rtable *)(*pskb)->dst;
struct in_device *in_dev;
- u_int32_t mask = 0;
+ __be32 mask = 0;
/* we're only interested in locally generated packets */
if ((*pskb)->sk == NULL)
@@ -78,12 +78,12 @@ static int help(struct sk_buff **pskb,
goto out;
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
- exp->tuple.src.u.udp.port = ntohs(NMBD_PORT);
+ exp->tuple.src.u.udp.port = htons(NMBD_PORT);
exp->mask.src.ip = mask;
- exp->mask.src.u.udp.port = 0xFFFF;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.udp.port = 0xFFFF;
+ exp->mask.src.u.udp.port = htons(0xFFFF);
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.udp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->expectfn = NULL;
@@ -115,7 +115,7 @@ static struct ip_conntrack_helper helper = {
.src = {
.u = {
.udp = {
- .port = 0xFFFF,
+ .port = __constant_htons(0xFFFF),
}
}
},
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index 52eddea27e93..262d0d44ec1b 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -44,13 +44,6 @@ MODULE_LICENSE("GPL");
static char __initdata version[] = "0.90";
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-
static inline int
ctnetlink_dump_tuples_proto(struct sk_buff *skb,
const struct ip_conntrack_tuple *tuple,
@@ -78,8 +71,8 @@ ctnetlink_dump_tuples_ip(struct sk_buff *skb,
{
struct nfattr *nest_parms = NFA_NEST(skb, CTA_TUPLE_IP);
- NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t), &tuple->src.ip);
- NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t), &tuple->dst.ip);
+ NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(__be32), &tuple->src.ip);
+ NFA_PUT(skb, CTA_IP_V4_DST, sizeof(__be32), &tuple->dst.ip);
NFA_NEST_END(skb, nest_parms);
@@ -110,7 +103,7 @@ ctnetlink_dump_tuples(struct sk_buff *skb,
static inline int
ctnetlink_dump_status(struct sk_buff *skb, const struct ip_conntrack *ct)
{
- u_int32_t status = htonl((u_int32_t) ct->status);
+ __be32 status = htonl((u_int32_t) ct->status);
NFA_PUT(skb, CTA_STATUS, sizeof(status), &status);
return 0;
@@ -122,7 +115,7 @@ static inline int
ctnetlink_dump_timeout(struct sk_buff *skb, const struct ip_conntrack *ct)
{
long timeout_l = ct->timeout.expires - jiffies;
- u_int32_t timeout;
+ __be32 timeout;
if (timeout_l < 0)
timeout = 0;
@@ -192,13 +185,13 @@ ctnetlink_dump_counters(struct sk_buff *skb, const struct ip_conntrack *ct,
{
enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
struct nfattr *nest_count = NFA_NEST(skb, type);
- u_int32_t tmp;
+ __be32 tmp;
tmp = htonl(ct->counters[dir].packets);
- NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
+ NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(__be32), &tmp);
tmp = htonl(ct->counters[dir].bytes);
- NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
+ NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(__be32), &tmp);
NFA_NEST_END(skb, nest_count);
@@ -215,9 +208,9 @@ nfattr_failure:
static inline int
ctnetlink_dump_mark(struct sk_buff *skb, const struct ip_conntrack *ct)
{
- u_int32_t mark = htonl(ct->mark);
+ __be32 mark = htonl(ct->mark);
- NFA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark);
+ NFA_PUT(skb, CTA_MARK, sizeof(__be32), &mark);
return 0;
nfattr_failure:
@@ -230,8 +223,8 @@ nfattr_failure:
static inline int
ctnetlink_dump_id(struct sk_buff *skb, const struct ip_conntrack *ct)
{
- u_int32_t id = htonl(ct->id);
- NFA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id);
+ __be32 id = htonl(ct->id);
+ NFA_PUT(skb, CTA_ID, sizeof(__be32), &id);
return 0;
nfattr_failure:
@@ -241,9 +234,9 @@ nfattr_failure:
static inline int
ctnetlink_dump_use(struct sk_buff *skb, const struct ip_conntrack *ct)
{
- u_int32_t use = htonl(atomic_read(&ct->ct_general.use));
+ __be32 use = htonl(atomic_read(&ct->ct_general.use));
- NFA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use);
+ NFA_PUT(skb, CTA_USE, sizeof(__be32), &use);
return 0;
nfattr_failure:
@@ -398,7 +391,6 @@ nfattr_failure:
static int ctnetlink_done(struct netlink_callback *cb)
{
- DEBUGP("entered %s\n", __FUNCTION__);
if (cb->args[1])
ip_conntrack_put((struct ip_conntrack *)cb->args[1]);
return 0;
@@ -411,9 +403,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct ip_conntrack_tuple_hash *h;
struct list_head *i;
- DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
- cb->args[0], *id);
-
read_lock_bh(&ip_conntrack_lock);
last = (struct ip_conntrack *)cb->args[1];
for (; cb->args[0] < ip_conntrack_htable_size; cb->args[0]++) {
@@ -452,13 +441,12 @@ out:
if (last)
ip_conntrack_put(last);
- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
return skb->len;
}
static const size_t cta_min_ip[CTA_IP_MAX] = {
- [CTA_IP_V4_SRC-1] = sizeof(u_int32_t),
- [CTA_IP_V4_DST-1] = sizeof(u_int32_t),
+ [CTA_IP_V4_SRC-1] = sizeof(__be32),
+ [CTA_IP_V4_DST-1] = sizeof(__be32),
};
static inline int
@@ -466,8 +454,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
{
struct nfattr *tb[CTA_IP_MAX];
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_IP_MAX, attr);
if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
@@ -475,13 +461,11 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct ip_conntrack_tuple *tuple)
if (!tb[CTA_IP_V4_SRC-1])
return -EINVAL;
- tuple->src.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
+ tuple->src.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
if (!tb[CTA_IP_V4_DST-1])
return -EINVAL;
- tuple->dst.ip = *(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
-
- DEBUGP("leaving\n");
+ tuple->dst.ip = *(__be32 *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
return 0;
}
@@ -503,8 +487,6 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr,
struct ip_conntrack_protocol *proto;
int ret = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
@@ -531,8 +513,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
struct nfattr *tb[CTA_TUPLE_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(tuple, 0, sizeof(*tuple));
nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
@@ -557,10 +537,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct ip_conntrack_tuple *tuple,
else
tuple->dst.dir = IP_CT_DIR_ORIGINAL;
- DUMP_TUPLE(tuple);
-
- DEBUGP("leaving\n");
-
return 0;
}
@@ -577,8 +553,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
struct nfattr *tb[CTA_PROTONAT_MAX];
struct ip_nat_protocol *npt;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
@@ -597,13 +571,12 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
ip_nat_proto_put(npt);
- DEBUGP("leaving\n");
return 0;
}
static const size_t cta_min_nat[CTA_NAT_MAX] = {
- [CTA_NAT_MINIP-1] = sizeof(u_int32_t),
- [CTA_NAT_MAXIP-1] = sizeof(u_int32_t),
+ [CTA_NAT_MINIP-1] = sizeof(__be32),
+ [CTA_NAT_MAXIP-1] = sizeof(__be32),
};
static inline int
@@ -613,8 +586,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
struct nfattr *tb[CTA_NAT_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(range, 0, sizeof(*range));
nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
@@ -623,12 +594,12 @@ ctnetlink_parse_nat(struct nfattr *nat,
return -EINVAL;
if (tb[CTA_NAT_MINIP-1])
- range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
+ range->min_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
if (!tb[CTA_NAT_MAXIP-1])
range->max_ip = range->min_ip;
else
- range->max_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
+ range->max_ip = *(__be32 *)NFA_DATA(tb[CTA_NAT_MAXIP-1]);
if (range->min_ip)
range->flags |= IP_NAT_RANGE_MAP_IPS;
@@ -640,7 +611,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
if (err < 0)
return err;
- DEBUGP("leaving\n");
return 0;
}
#endif
@@ -650,8 +620,6 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
{
struct nfattr *tb[CTA_HELP_MAX];
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
if (!tb[CTA_HELP_NAME-1])
@@ -663,11 +631,11 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
}
static const size_t cta_min[CTA_MAX] = {
- [CTA_STATUS-1] = sizeof(u_int32_t),
- [CTA_TIMEOUT-1] = sizeof(u_int32_t),
- [CTA_MARK-1] = sizeof(u_int32_t),
- [CTA_USE-1] = sizeof(u_int32_t),
- [CTA_ID-1] = sizeof(u_int32_t)
+ [CTA_STATUS-1] = sizeof(__be32),
+ [CTA_TIMEOUT-1] = sizeof(__be32),
+ [CTA_MARK-1] = sizeof(__be32),
+ [CTA_USE-1] = sizeof(__be32),
+ [CTA_ID-1] = sizeof(__be32)
};
static int
@@ -679,8 +647,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack *ct;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -698,15 +664,13 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = ip_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash\n");
+ if (!h)
return -ENOENT;
- }
ct = tuplehash_to_ctrack(h);
if (cda[CTA_ID-1]) {
- u_int32_t id = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_ID-1]));
+ u_int32_t id = ntohl(*(__be32 *)NFA_DATA(cda[CTA_ID-1]));
if (ct->id != id) {
ip_conntrack_put(ct);
return -ENOENT;
@@ -716,7 +680,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
ct->timeout.function((unsigned long)ct);
ip_conntrack_put(ct);
- DEBUGP("leaving\n");
return 0;
}
@@ -731,8 +694,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct sk_buff *skb2 = NULL;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nlh->nlmsg_flags & NLM_F_DUMP) {
struct nfgenmsg *msg = NLMSG_DATA(nlh);
u32 rlen;
@@ -770,11 +731,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = ip_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash");
+ if (!h)
return -ENOENT;
- }
- DEBUGP("tuple found\n");
+
ct = tuplehash_to_ctrack(h);
err = -ENOMEM;
@@ -795,7 +754,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
goto out;
- DEBUGP("leaving\n");
return 0;
free:
@@ -808,7 +766,7 @@ static inline int
ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
{
unsigned long d;
- unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
+ unsigned status = ntohl(*(__be32 *)NFA_DATA(cda[CTA_STATUS-1]));
d = ct->status ^ status;
if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
@@ -866,8 +824,6 @@ ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
char *helpname;
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
/* don't change helper of sibling connections */
if (ct->master)
return -EINVAL;
@@ -903,7 +859,7 @@ ctnetlink_change_helper(struct ip_conntrack *ct, struct nfattr *cda[])
static inline int
ctnetlink_change_timeout(struct ip_conntrack *ct, struct nfattr *cda[])
{
- u_int32_t timeout = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+ u_int32_t timeout = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
if (!del_timer(&ct->timeout))
return -ETIME;
@@ -938,8 +894,6 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
{
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (cda[CTA_HELP-1]) {
err = ctnetlink_change_helper(ct, cda);
if (err < 0)
@@ -966,10 +920,9 @@ ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
if (cda[CTA_MARK-1])
- ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+ ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
#endif
- DEBUGP("all done\n");
return 0;
}
@@ -981,15 +934,13 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
struct ip_conntrack *ct;
int err = -EINVAL;
- DEBUGP("entered %s\n", __FUNCTION__);
-
ct = ip_conntrack_alloc(otuple, rtuple);
if (ct == NULL || IS_ERR(ct))
return -ENOMEM;
if (!cda[CTA_TIMEOUT-1])
goto err;
- ct->timeout.expires = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_TIMEOUT-1]));
+ ct->timeout.expires = ntohl(*(__be32 *)NFA_DATA(cda[CTA_TIMEOUT-1]));
ct->timeout.expires = jiffies + ct->timeout.expires * HZ;
ct->status |= IPS_CONFIRMED;
@@ -1006,7 +957,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
if (cda[CTA_MARK-1])
- ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+ ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1]));
#endif
ct->helper = ip_conntrack_helper_find_get(rtuple);
@@ -1017,7 +968,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
if (ct->helper)
ip_conntrack_helper_put(ct->helper);
- DEBUGP("conntrack with id %u inserted\n", ct->id);
return 0;
err:
@@ -1033,8 +983,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack_tuple_hash *h = NULL;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -1058,7 +1006,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (h == NULL) {
write_unlock_bh(&ip_conntrack_lock);
- DEBUGP("no such conntrack, create new\n");
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE)
err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
@@ -1074,7 +1021,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
/* We manipulate the conntrack inside the global conntrack table lock,
* so there's no need to increase the refcount */
- DEBUGP("conntrack found\n");
err = -EEXIST;
if (!(nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_conntrack(tuplehash_to_ctrack(h), cda);
@@ -1138,8 +1084,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
const struct ip_conntrack_expect *exp)
{
struct ip_conntrack *master = exp->master;
- u_int32_t timeout = htonl((exp->timeout.expires - jiffies) / HZ);
- u_int32_t id = htonl(exp->id);
+ __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ);
+ __be32 id = htonl(exp->id);
if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0)
goto nfattr_failure;
@@ -1150,8 +1096,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb,
CTA_EXPECT_MASTER) < 0)
goto nfattr_failure;
- NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout);
- NFA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id);
+ NFA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(__be32), &timeout);
+ NFA_PUT(skb, CTA_EXPECT_ID, sizeof(__be32), &id);
return 0;
@@ -1249,8 +1195,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct list_head *i;
u_int32_t *id = (u_int32_t *) &cb->args[0];
- DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
-
read_lock_bh(&ip_conntrack_lock);
list_for_each_prev(i, &ip_conntrack_expect_list) {
exp = (struct ip_conntrack_expect *) i;
@@ -1266,14 +1210,12 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
out:
read_unlock_bh(&ip_conntrack_lock);
- DEBUGP("leaving, last id=%llu\n", *id);
-
return skb->len;
}
static const size_t cta_min_exp[CTA_EXPECT_MAX] = {
- [CTA_EXPECT_TIMEOUT-1] = sizeof(u_int32_t),
- [CTA_EXPECT_ID-1] = sizeof(u_int32_t)
+ [CTA_EXPECT_TIMEOUT-1] = sizeof(__be32),
+ [CTA_EXPECT_ID-1] = sizeof(__be32)
};
static int
@@ -1285,8 +1227,6 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
struct sk_buff *skb2;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1321,7 +1261,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
return -ENOENT;
if (cda[CTA_EXPECT_ID-1]) {
- u_int32_t id = *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+ __be32 id = *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
if (exp->id != ntohl(id)) {
ip_conntrack_expect_put(exp);
return -ENOENT;
@@ -1375,8 +1315,8 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb,
return -ENOENT;
if (cda[CTA_EXPECT_ID-1]) {
- u_int32_t id =
- *(u_int32_t *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
+ __be32 id =
+ *(__be32 *)NFA_DATA(cda[CTA_EXPECT_ID-1]);
if (exp->id != ntohl(id)) {
ip_conntrack_expect_put(exp);
return -ENOENT;
@@ -1437,8 +1377,6 @@ ctnetlink_create_expect(struct nfattr *cda[])
struct ip_conntrack *ct;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
/* caller guarantees that those three CTA_EXPECT_* exist */
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE);
if (err < 0)
@@ -1490,8 +1428,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
struct ip_conntrack_expect *exp;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1520,8 +1456,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
err = ctnetlink_change_expect(exp, cda);
write_unlock_bh(&ip_conntrack_lock);
- DEBUGP("leaving\n");
-
return err;
}
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
index 09c40ebe3345..295b6fa340db 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_icmp.c
@@ -261,7 +261,7 @@ icmp_error(struct sk_buff *skb, enum ip_conntrack_info *ctinfo,
static int icmp_tuple_to_nfattr(struct sk_buff *skb,
const struct ip_conntrack_tuple *t)
{
- NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t),
+ NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(__be16),
&t->src.u.icmp.id);
NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t),
&t->dst.u.icmp.type);
@@ -287,7 +287,7 @@ static int icmp_nfattr_to_tuple(struct nfattr *tb[],
tuple->dst.u.icmp.code =
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
tuple->src.u.icmp.id =
- *(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
+ *(__be16 *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
if (tuple->dst.u.icmp.type >= sizeof(invmap)
|| !invmap[tuple->dst.u.icmp.type])
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
index b908a4842e18..2443322e4128 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_sctp.c
@@ -210,7 +210,7 @@ static int sctp_print_conntrack(struct seq_file *s,
for (offset = skb->nh.iph->ihl * 4 + sizeof(sctp_sctphdr_t), count = 0; \
offset < skb->len && \
(sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \
- offset += (htons(sch->length) + 3) & ~3, count++)
+ offset += (ntohs(sch->length) + 3) & ~3, count++)
/* Some validity checks to make sure the chunks are fine */
static int do_basic_checks(struct ip_conntrack *conntrack,
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
index 03ae9a04cb37..06e4e8a6dd9f 100644
--- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c
@@ -519,8 +519,8 @@ static void tcp_sack(const struct sk_buff *skb,
/* Fast path for timestamp-only option */
if (length == TCPOLEN_TSTAMP_ALIGNED*4
- && *(__u32 *)ptr ==
- __constant_ntohl((TCPOPT_NOP << 24)
+ && *(__be32 *)ptr ==
+ __constant_htonl((TCPOPT_NOP << 24)
| (TCPOPT_NOP << 16)
| (TCPOPT_TIMESTAMP << 8)
| TCPOLEN_TIMESTAMP))
@@ -551,7 +551,7 @@ static void tcp_sack(const struct sk_buff *skb,
for (i = 0;
i < (opsize - TCPOLEN_SACK_BASE);
i += TCPOLEN_SACK_PERBLOCK) {
- tmp = ntohl(*((u_int32_t *)(ptr+i)+1));
+ tmp = ntohl(*((__be32 *)(ptr+i)+1));
if (after(tmp, *sack))
*sack = tmp;
diff --git a/net/ipv4/netfilter/ip_conntrack_sip.c b/net/ipv4/netfilter/ip_conntrack_sip.c
index 2893e9c74850..f4f75995a9e4 100644
--- a/net/ipv4/netfilter/ip_conntrack_sip.c
+++ b/net/ipv4/netfilter/ip_conntrack_sip.c
@@ -193,7 +193,7 @@ static int skp_digits_len(const char *dptr, const char *limit, int *shift)
/* Simple ipaddr parser.. */
static int parse_ipaddr(const char *cp, const char **endp,
- u_int32_t *ipaddr, const char *limit)
+ __be32 *ipaddr, const char *limit)
{
unsigned long int val;
int i, digit = 0;
@@ -227,7 +227,7 @@ static int parse_ipaddr(const char *cp, const char **endp,
static int epaddr_len(const char *dptr, const char *limit, int *shift)
{
const char *aux = dptr;
- u_int32_t ip;
+ __be32 ip;
if (parse_ipaddr(dptr, &dptr, &ip, limit) < 0) {
DEBUGP("ip: %s parse failed.!\n", dptr);
@@ -302,7 +302,7 @@ int ct_sip_get_info(const char *dptr, size_t dlen,
static int set_expected_rtp(struct sk_buff **pskb,
struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo,
- u_int32_t ipaddr, u_int16_t port,
+ __be32 ipaddr, u_int16_t port,
const char *dptr)
{
struct ip_conntrack_expect *exp;
@@ -319,10 +319,10 @@ static int set_expected_rtp(struct sk_buff **pskb,
exp->tuple.dst.u.udp.port = htons(port);
exp->tuple.dst.protonum = IPPROTO_UDP;
- exp->mask.src.ip = 0xFFFFFFFF;
+ exp->mask.src.ip = htonl(0xFFFFFFFF);
exp->mask.src.u.udp.port = 0;
- exp->mask.dst.ip = 0xFFFFFFFF;
- exp->mask.dst.u.udp.port = 0xFFFF;
+ exp->mask.dst.ip = htonl(0xFFFFFFFF);
+ exp->mask.dst.u.udp.port = htons(0xFFFF);
exp->mask.dst.protonum = 0xFF;
exp->expectfn = NULL;
@@ -349,7 +349,7 @@ static int sip_help(struct sk_buff **pskb,
const char *dptr;
int ret = NF_ACCEPT;
int matchoff, matchlen;
- u_int32_t ipaddr;
+ __be32 ipaddr;
u_int16_t port;
/* No Data ? */
@@ -439,7 +439,7 @@ static int __init init(void)
sip[i].tuple.dst.protonum = IPPROTO_UDP;
sip[i].tuple.src.u.udp.port = htons(ports[i]);
- sip[i].mask.src.u.udp.port = 0xFFFF;
+ sip[i].mask.src.u.udp.port = htons(0xFFFF);
sip[i].mask.dst.protonum = 0xFF;
sip[i].max_expected = 2;
sip[i].timeout = 3 * 60; /* 3 minutes */
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
index 7e33d3bed5e3..fe0b634dd377 100644
--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_tftp.c
@@ -70,10 +70,10 @@ static int tftp_help(struct sk_buff **pskb,
return NF_DROP;
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
- exp->mask.src.ip = 0xffffffff;
+ exp->mask.src.ip = htonl(0xffffffff);
exp->mask.src.u.udp.port = 0;
- exp->mask.dst.ip = 0xffffffff;
- exp->mask.dst.u.udp.port = 0xffff;
+ exp->mask.dst.ip = htonl(0xffffffff);
+ exp->mask.dst.u.udp.port = htons(0xffff);
exp->mask.dst.protonum = 0xff;
exp->expectfn = NULL;
exp->flags = 0;
@@ -129,7 +129,7 @@ static int __init ip_conntrack_tftp_init(void)
tftp[i].tuple.dst.protonum = IPPROTO_UDP;
tftp[i].tuple.src.u.udp.port = htons(ports[i]);
tftp[i].mask.dst.protonum = 0xFF;
- tftp[i].mask.src.u.udp.port = 0xFFFF;
+ tftp[i].mask.src.u.udp.port = htons(0xFFFF);
tftp[i].max_expected = 1;
tftp[i].timeout = 5 * 60; /* 5 minutes */
tftp[i].me = THIS_MODULE;
diff --git a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
index 71f3e09cbc84..4b6260a97408 100644
--- a/net/ipv4/netfilter/ip_nat_core.c
+++ b/net/ipv4/netfilter/ip_nat_core.c
@@ -82,7 +82,7 @@ static inline unsigned int
hash_by_src(const struct ip_conntrack_tuple *tuple)
{
/* Original src, to ensure we map it consistently if poss. */
- return jhash_3words(tuple->src.ip, tuple->src.u.all,
+ return jhash_3words((__force u32)tuple->src.ip, tuple->src.u.all,
tuple->dst.protonum, 0) % ip_nat_htable_size;
}
@@ -190,7 +190,7 @@ find_best_ips_proto(struct ip_conntrack_tuple *tuple,
const struct ip_conntrack *conntrack,
enum ip_nat_manip_type maniptype)
{
- u_int32_t *var_ipp;
+ __be32 *var_ipp;
/* Host order */
u_int32_t minip, maxip, j;
@@ -217,7 +217,7 @@ find_best_ips_proto(struct ip_conntrack_tuple *tuple,
* like this), even across reboots. */
minip = ntohl(range->min_ip);
maxip = ntohl(range->max_ip);
- j = jhash_2words(tuple->src.ip, tuple->dst.ip, 0);
+ j = jhash_2words((__force u32)tuple->src.ip, (__force u32)tuple->dst.ip, 0);
*var_ipp = htonl(minip + j % (maxip - minip + 1));
}
@@ -534,9 +534,9 @@ int
ip_nat_port_range_to_nfattr(struct sk_buff *skb,
const struct ip_nat_range *range)
{
- NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(u_int16_t),
+ NFA_PUT(skb, CTA_PROTONAT_PORT_MIN, sizeof(__be16),
&range->min.tcp.port);
- NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(u_int16_t),
+ NFA_PUT(skb, CTA_PROTONAT_PORT_MAX, sizeof(__be16),
&range->max.tcp.port);
return 0;
@@ -555,7 +555,7 @@ ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range)
if (tb[CTA_PROTONAT_PORT_MIN-1]) {
ret = 1;
range->min.tcp.port =
- *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
+ *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MIN-1]);
}
if (!tb[CTA_PROTONAT_PORT_MAX-1]) {
@@ -564,7 +564,7 @@ ip_nat_port_nfattr_to_range(struct nfattr *tb[], struct ip_nat_range *range)
} else {
ret = 1;
range->max.tcp.port =
- *(u_int16_t *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
+ *(__be16 *)NFA_DATA(tb[CTA_PROTONAT_PORT_MAX-1]);
}
return ret;
diff --git a/net/ipv4/netfilter/ip_nat_ftp.c b/net/ipv4/netfilter/ip_nat_ftp.c
index 3328fc5c5f50..a71c233d8112 100644
--- a/net/ipv4/netfilter/ip_nat_ftp.c
+++ b/net/ipv4/netfilter/ip_nat_ftp.c
@@ -34,7 +34,7 @@ MODULE_DESCRIPTION("ftp NAT helper");
static int
mangle_rfc959_packet(struct sk_buff **pskb,
- u_int32_t newip,
+ __be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
@@ -57,7 +57,7 @@ mangle_rfc959_packet(struct sk_buff **pskb,
/* |1|132.235.1.2|6275| */
static int
mangle_eprt_packet(struct sk_buff **pskb,
- u_int32_t newip,
+ __be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
@@ -79,7 +79,7 @@ mangle_eprt_packet(struct sk_buff **pskb,
/* |1|132.235.1.2|6275| */
static int
mangle_epsv_packet(struct sk_buff **pskb,
- u_int32_t newip,
+ __be32 newip,
u_int16_t port,
unsigned int matchoff,
unsigned int matchlen,
@@ -98,7 +98,7 @@ mangle_epsv_packet(struct sk_buff **pskb,
matchlen, buffer, strlen(buffer));
}
-static int (*mangle[])(struct sk_buff **, u_int32_t, u_int16_t,
+static int (*mangle[])(struct sk_buff **, __be32, u_int16_t,
unsigned int,
unsigned int,
struct ip_conntrack *,
@@ -120,7 +120,7 @@ static unsigned int ip_nat_ftp(struct sk_buff **pskb,
struct ip_conntrack_expect *exp,
u32 *seq)
{
- u_int32_t newip;
+ __be32 newip;
u_int16_t port;
int dir = CTINFO2DIR(ctinfo);
struct ip_conntrack *ct = exp->master;
diff --git a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
index 7f6a75984f6c..3bf858480558 100644
--- a/net/ipv4/netfilter/ip_nat_helper.c
+++ b/net/ipv4/netfilter/ip_nat_helper.c
@@ -189,7 +189,7 @@ ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
datalen, 0));
} else
tcph->check = nf_proto_csum_update(*pskb,
- htons(oldlen) ^ 0xFFFF,
+ htons(oldlen) ^ htons(0xFFFF),
htons(datalen),
tcph->check, 1);
@@ -267,7 +267,7 @@ ip_nat_mangle_udp_packet(struct sk_buff **pskb,
udph->check = -1;
} else
udph->check = nf_proto_csum_update(*pskb,
- htons(oldlen) ^ 0xFFFF,
+ htons(oldlen) ^ htons(0xFFFF),
htons(datalen),
udph->check, 1);
return 1;
@@ -283,27 +283,25 @@ sack_adjust(struct sk_buff *skb,
struct ip_nat_seq *natseq)
{
while (sackoff < sackend) {
- struct tcp_sack_block *sack;
- u_int32_t new_start_seq, new_end_seq;
+ struct tcp_sack_block_wire *sack;
+ __be32 new_start_seq, new_end_seq;
sack = (void *)skb->data + sackoff;
if (after(ntohl(sack->start_seq) - natseq->offset_before,
natseq->correction_pos))
- new_start_seq = ntohl(sack->start_seq)
- - natseq->offset_after;
+ new_start_seq = htonl(ntohl(sack->start_seq)
+ - natseq->offset_after);
else
- new_start_seq = ntohl(sack->start_seq)
- - natseq->offset_before;
- new_start_seq = htonl(new_start_seq);
+ new_start_seq = htonl(ntohl(sack->start_seq)
+ - natseq->offset_before);
if (after(ntohl(sack->end_seq) - natseq->offset_before,
natseq->correction_pos))
- new_end_seq = ntohl(sack->end_seq)
- - natseq->offset_after;
+ new_end_seq = htonl(ntohl(sack->end_seq)
+ - natseq->offset_after);
else
- new_end_seq = ntohl(sack->end_seq)
- - natseq->offset_before;
- new_end_seq = htonl(new_end_seq);
+ new_end_seq = htonl(ntohl(sack->end_seq)
+ - natseq->offset_before);
DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
ntohl(sack->start_seq), new_start_seq,
@@ -375,7 +373,8 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo)
{
struct tcphdr *tcph;
- int dir, newseq, newack;
+ int dir;
+ __be32 newseq, newack;
struct ip_nat_seq *this_way, *other_way;
dir = CTINFO2DIR(ctinfo);
@@ -388,17 +387,15 @@ ip_nat_seq_adjust(struct sk_buff **pskb,
tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
if (after(ntohl(tcph->seq), this_way->correction_pos))
- newseq = ntohl(tcph->seq) + this_way->offset_after;
+ newseq = htonl(ntohl(tcph->seq) + this_way->offset_after);
else
- newseq = ntohl(tcph->seq) + this_way->offset_before;
- newseq = htonl(newseq);
+ newseq = htonl(ntohl(tcph->seq) + this_way->offset_before);
if (after(ntohl(tcph->ack_seq) - other_way->offset_before,
other_way->correction_pos))
- newack = ntohl(tcph->ack_seq) - other_way->offset_after;
+ newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_after);
else
- newack = ntohl(tcph->ack_seq) - other_way->offset_before;
- newack = htonl(newack);
+ newack = htonl(ntohl(tcph->ack_seq) - other_way->offset_before);
tcph->check = nf_proto_csum_update(*pskb, ~tcph->seq, newseq,
tcph->check, 0);
diff --git a/net/ipv4/netfilter/ip_nat_helper_h323.c b/net/ipv4/netfilter/ip_nat_helper_h323.c
index 419b878fb467..4a7d34466ee2 100644
--- a/net/ipv4/netfilter/ip_nat_helper_h323.c
+++ b/net/ipv4/netfilter/ip_nat_helper_h323.c
@@ -32,13 +32,13 @@
/****************************************************************************/
static int set_addr(struct sk_buff **pskb,
unsigned char **data, int dataoff,
- unsigned int addroff, u_int32_t ip, u_int16_t port)
+ unsigned int addroff, __be32 ip, u_int16_t port)
{
enum ip_conntrack_info ctinfo;
struct ip_conntrack *ct = ip_conntrack_get(*pskb, &ctinfo);
struct {
- u_int32_t ip;
- u_int16_t port;
+ __be32 ip;
+ __be16 port;
} __attribute__ ((__packed__)) buf;
struct tcphdr _tcph, *th;
@@ -86,7 +86,7 @@ static int set_addr(struct sk_buff **pskb,
static int set_h225_addr(struct sk_buff **pskb,
unsigned char **data, int dataoff,
TransportAddress * addr,
- u_int32_t ip, u_int16_t port)
+ __be32 ip, u_int16_t port)
{
return set_addr(pskb, data, dataoff, addr->ipAddress.ip, ip, port);
}
@@ -95,7 +95,7 @@ static int set_h225_addr(struct sk_buff **pskb,
static int set_h245_addr(struct sk_buff **pskb,
unsigned char **data, int dataoff,
H245_TransportAddress * addr,
- u_int32_t ip, u_int16_t port)
+ __be32 ip, u_int16_t port)
{
return set_addr(pskb, data, dataoff,
addr->unicastAddress.iPAddress.network, ip, port);
@@ -110,7 +110,7 @@ static int set_sig_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
int dir = CTINFO2DIR(ctinfo);
int i;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
for (i = 0; i < count; i++) {
@@ -164,7 +164,7 @@ static int set_ras_addr(struct sk_buff **pskb, struct ip_conntrack *ct,
{
int dir = CTINFO2DIR(ctinfo);
int i;
- u_int32_t ip;
+ __be32 ip;
u_int16_t port;
for (i = 0; i < count; i++) {
@@ -433,7 +433,7 @@ static int nat_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
int dir = CTINFO2DIR(ctinfo);
u_int16_t nated_port = port;
- u_int32_t ip;
+ __be32 ip;
/* Set expectations for NAT */
exp->saved_proto.tcp.port = exp->tuple.dst.u.tcp.port;
diff --git a/net/ipv4/netfilter/ip_nat_helper_pptp.c b/net/ipv4/netfilter/ip_nat_helper_pptp.c
index 2ff578807123..329fdcd7d702 100644
--- a/net/ipv4/netfilter/ip_nat_helper_pptp.c
+++ b/net/ipv4/netfilter/ip_nat_helper_pptp.c
@@ -51,7 +51,7 @@
#define IP_NAT_PPTP_VERSION "3.0"
-#define REQ_CID(req, off) (*(u_int16_t *)((char *)(req) + (off)))
+#define REQ_CID(req, off) (*(__be16 *)((char *)(req) + (off)))
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
diff --git a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c
index ec50cc295317..3f6efc13ac74 100644
--- a/net/ipv4/netfilter/ip_nat_proto_icmp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c
@@ -67,7 +67,7 @@ icmp_manip_pkt(struct sk_buff **pskb,
hdr = (struct icmphdr *)((*pskb)->data + hdroff);
hdr->checksum = nf_proto_csum_update(*pskb,
- hdr->un.echo.id ^ 0xFFFF,
+ hdr->un.echo.id ^ htons(0xFFFF),
tuple->src.u.icmp.id,
hdr->checksum, 0);
hdr->un.echo.id = tuple->src.u.icmp.id;
diff --git a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
index 72a6307bd2db..12deb13b93b1 100644
--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c
@@ -24,7 +24,7 @@ tcp_in_range(const struct ip_conntrack_tuple *tuple,
const union ip_conntrack_manip_proto *min,
const union ip_conntrack_manip_proto *max)
{
- u_int16_t port;
+ __be16 port;
if (maniptype == IP_NAT_MANIP_SRC)
port = tuple->src.u.tcp.port;
@@ -42,7 +42,7 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple,
const struct ip_conntrack *conntrack)
{
static u_int16_t port;
- u_int16_t *portptr;
+ __be16 *portptr;
unsigned int range_size, min, i;
if (maniptype == IP_NAT_MANIP_SRC)
@@ -93,8 +93,8 @@ tcp_manip_pkt(struct sk_buff **pskb,
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct tcphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
- u32 oldip, newip;
- u16 *portptr, newport, oldport;
+ __be32 oldip, newip;
+ __be16 *portptr, newport, oldport;
int hdrsize = 8; /* TCP connection tracking guarantees this much */
/* this could be a inner header returned in icmp packet; in such
@@ -130,7 +130,7 @@ tcp_manip_pkt(struct sk_buff **pskb,
return 1;
hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip, hdr->check, 1);
- hdr->check = nf_proto_csum_update(*pskb, oldport ^ 0xFFFF, newport,
+ hdr->check = nf_proto_csum_update(*pskb, oldport ^ htons(0xFFFF), newport,
hdr->check, 0);
return 1;
}
diff --git a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c
index 5da196ae758c..4bbec7730d18 100644
--- a/net/ipv4/netfilter/ip_nat_proto_udp.c
+++ b/net/ipv4/netfilter/ip_nat_proto_udp.c
@@ -24,7 +24,7 @@ udp_in_range(const struct ip_conntrack_tuple *tuple,
const union ip_conntrack_manip_proto *min,
const union ip_conntrack_manip_proto *max)
{
- u_int16_t port;
+ __be16 port;
if (maniptype == IP_NAT_MANIP_SRC)
port = tuple->src.u.udp.port;
@@ -42,7 +42,7 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple,
const struct ip_conntrack *conntrack)
{
static u_int16_t port;
- u_int16_t *portptr;
+ __be16 *portptr;
unsigned int range_size, min, i;
if (maniptype == IP_NAT_MANIP_SRC)
@@ -91,8 +91,8 @@ udp_manip_pkt(struct sk_buff **pskb,
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct udphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
- u32 oldip, newip;
- u16 *portptr, newport;
+ __be32 oldip, newip;
+ __be16 *portptr, newport;
if (!skb_make_writable(pskb, hdroff + sizeof(*hdr)))
return 0;
@@ -118,7 +118,7 @@ udp_manip_pkt(struct sk_buff **pskb,
hdr->check = nf_proto_csum_update(*pskb, ~oldip, newip,
hdr->check, 1);
hdr->check = nf_proto_csum_update(*pskb,
- *portptr ^ 0xFFFF, newport,
+ *portptr ^ htons(0xFFFF), newport,
hdr->check, 0);
if (!hdr->check)
hdr->check = -1;
diff --git a/net/ipv4/netfilter/ip_nat_rule.c b/net/ipv4/netfilter/ip_nat_rule.c
index 7b703839aa58..a176aa3031e0 100644
--- a/net/ipv4/netfilter/ip_nat_rule.c
+++ b/net/ipv4/netfilter/ip_nat_rule.c
@@ -119,7 +119,7 @@ static unsigned int ipt_snat_target(struct sk_buff **pskb,
}
/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */
-static void warn_if_extra_mangle(u32 dstip, u32 srcip)
+static void warn_if_extra_mangle(__be32 dstip, __be32 srcip)
{
static int warned = 0;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } };
@@ -205,7 +205,7 @@ alloc_null_binding(struct ip_conntrack *conntrack,
per-proto parts (hence not IP_NAT_RANGE_PROTO_SPECIFIED).
Use reply in case it's already been mangled (eg local packet).
*/
- u_int32_t ip
+ __be32 ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
: conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
@@ -222,7 +222,7 @@ alloc_null_binding_confirmed(struct ip_conntrack *conntrack,
struct ip_nat_info *info,
unsigned int hooknum)
{
- u_int32_t ip
+ __be32 ip
= (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC
? conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip
: conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip);
diff --git a/net/ipv4/netfilter/ip_nat_sip.c b/net/ipv4/netfilter/ip_nat_sip.c
index 6ffba63adca2..71fc2730a007 100644
--- a/net/ipv4/netfilter/ip_nat_sip.c
+++ b/net/ipv4/netfilter/ip_nat_sip.c
@@ -60,8 +60,8 @@ static unsigned int ip_nat_sip(struct sk_buff **pskb,
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
unsigned int bufflen, dataoff;
- u_int32_t ip;
- u_int16_t port;
+ __be32 ip;
+ __be16 port;
dataoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct udphdr);
@@ -159,7 +159,7 @@ static int mangle_content_len(struct sk_buff **pskb,
static unsigned int mangle_sdp(struct sk_buff **pskb,
enum ip_conntrack_info ctinfo,
struct ip_conntrack *ct,
- u_int32_t newip, u_int16_t port,
+ __be32 newip, u_int16_t port,
const char *dptr)
{
char buffer[sizeof("nnn.nnn.nnn.nnn")];
@@ -195,7 +195,7 @@ static unsigned int ip_nat_sdp(struct sk_buff **pskb,
{
struct ip_conntrack *ct = exp->master;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
- u_int32_t newip;
+ __be32 newip;
u_int16_t port;
DEBUGP("ip_nat_sdp():\n");
diff --git a/net/ipv4/netfilter/ip_nat_snmp_basic.c b/net/ipv4/netfilter/ip_nat_snmp_basic.c
index 18b7fbdccb61..168f45fa1898 100644
--- a/net/ipv4/netfilter/ip_nat_snmp_basic.c
+++ b/net/ipv4/netfilter/ip_nat_snmp_basic.c
@@ -1211,7 +1211,7 @@ static int snmp_translate(struct ip_conntrack *ct,
struct sk_buff **pskb)
{
struct iphdr *iph = (*pskb)->nh.iph;
- struct udphdr *udph = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
+ struct udphdr *udph = (struct udphdr *)((__be32 *)iph + iph->ihl);
u_int16_t udplen = ntohs(udph->len);
u_int16_t paylen = udplen - sizeof(struct udphdr);
int dir = CTINFO2DIR(ctinfo);
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index 9c577db62047..d85d2de50449 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -191,7 +191,7 @@ ip_nat_in(unsigned int hooknum,
int (*okfn)(struct sk_buff *))
{
unsigned int ret;
- u_int32_t daddr = (*pskb)->nh.iph->daddr;
+ __be32 daddr = (*pskb)->nh.iph->daddr;
ret = ip_nat_fn(hooknum, pskb, in, out, okfn);
if (ret != NF_DROP && ret != NF_STOLEN
@@ -265,7 +265,8 @@ ip_nat_local_fn(unsigned int hooknum,
ct->tuplehash[!dir].tuple.src.u.all
#endif
)
- return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+ if (ip_route_me_harder(pskb, RTN_UNSPEC))
+ ret = NF_DROP;
}
return ret;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 78a44b01c035..4b90927619b8 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -1932,6 +1932,9 @@ compat_do_ipt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
{
int ret;
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+
switch (cmd) {
case IPT_SO_GET_INFO:
ret = get_info(user, len, 1);
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 41589665fc5d..7a29d6e7baa7 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -52,7 +52,7 @@ struct clusterip_config {
atomic_t entries; /* number of entries/rules
* referencing us */
- u_int32_t clusterip; /* the IP address */
+ __be32 clusterip; /* the IP address */
u_int8_t clustermac[ETH_ALEN]; /* the MAC address */
struct net_device *dev; /* device */
u_int16_t num_total_nodes; /* total number of nodes */
@@ -119,7 +119,7 @@ clusterip_config_entry_put(struct clusterip_config *c)
}
static struct clusterip_config *
-__clusterip_config_find(u_int32_t clusterip)
+__clusterip_config_find(__be32 clusterip)
{
struct list_head *pos;
@@ -136,7 +136,7 @@ __clusterip_config_find(u_int32_t clusterip)
}
static inline struct clusterip_config *
-clusterip_config_find_get(u_int32_t clusterip, int entry)
+clusterip_config_find_get(__be32 clusterip, int entry)
{
struct clusterip_config *c;
@@ -166,7 +166,7 @@ clusterip_config_init_nodelist(struct clusterip_config *c,
}
static struct clusterip_config *
-clusterip_config_init(struct ipt_clusterip_tgt_info *i, u_int32_t ip,
+clusterip_config_init(struct ipt_clusterip_tgt_info *i, __be32 ip,
struct net_device *dev)
{
struct clusterip_config *c;
@@ -387,7 +387,7 @@ checkentry(const char *tablename,
return 0;
}
- if (e->ip.dmsk.s_addr != 0xffffffff
+ if (e->ip.dmsk.s_addr != htonl(0xffffffff)
|| e->ip.dst.s_addr == 0) {
printk(KERN_ERR "CLUSTERIP: Please specify destination IP\n");
return 0;
@@ -476,9 +476,9 @@ static struct ipt_target clusterip_tgt = {
/* hardcoded for 48bit ethernet and 32bit ipv4 addresses */
struct arp_payload {
u_int8_t src_hw[ETH_ALEN];
- u_int32_t src_ip;
+ __be32 src_ip;
u_int8_t dst_hw[ETH_ALEN];
- u_int32_t dst_ip;
+ __be32 dst_ip;
} __attribute__ ((packed));
#ifdef CLUSTERIP_DEBUG
diff --git a/net/ipv4/netfilter/ipt_ECN.c b/net/ipv4/netfilter/ipt_ECN.c
index 23f9c7ebe7eb..1aa4517fbcdb 100644
--- a/net/ipv4/netfilter/ipt_ECN.c
+++ b/net/ipv4/netfilter/ipt_ECN.c
@@ -37,8 +37,8 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
oldtos = iph->tos;
iph->tos &= ~IPT_ECN_IP_MASK;
iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
- iph->check = nf_csum_update(oldtos ^ 0xFFFF, iph->tos,
- iph->check);
+ iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
+ htons(iph->tos), iph->check);
}
return 1;
}
@@ -48,7 +48,7 @@ static inline int
set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
{
struct tcphdr _tcph, *tcph;
- u_int16_t oldval;
+ __be16 oldval;
/* Not enought header? */
tcph = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
@@ -66,15 +66,15 @@ set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
return 0;
tcph = (void *)(*pskb)->nh.iph + (*pskb)->nh.iph->ihl*4;
- oldval = ((u_int16_t *)tcph)[6];
+ oldval = ((__be16 *)tcph)[6];
if (einfo->operation & IPT_ECN_OP_SET_ECE)
tcph->ece = einfo->proto.tcp.ece;
if (einfo->operation & IPT_ECN_OP_SET_CWR)
tcph->cwr = einfo->proto.tcp.cwr;
tcph->check = nf_proto_csum_update((*pskb),
- oldval ^ 0xFFFF,
- ((u_int16_t *)tcph)[6],
+ oldval ^ htons(0xFFFF),
+ ((__be16 *)tcph)[6],
tcph->check, 0);
return 1;
}
diff --git a/net/ipv4/netfilter/ipt_MASQUERADE.c b/net/ipv4/netfilter/ipt_MASQUERADE.c
index bc65168a3437..3dbfcfac8a84 100644
--- a/net/ipv4/netfilter/ipt_MASQUERADE.c
+++ b/net/ipv4/netfilter/ipt_MASQUERADE.c
@@ -70,7 +70,7 @@ masquerade_target(struct sk_buff **pskb,
const struct ip_nat_multi_range_compat *mr;
struct ip_nat_range newrange;
struct rtable *rt;
- u_int32_t newsrc;
+ __be32 newsrc;
IP_NF_ASSERT(hooknum == NF_IP_POST_ROUTING);
diff --git a/net/ipv4/netfilter/ipt_NETMAP.c b/net/ipv4/netfilter/ipt_NETMAP.c
index beb2914225ff..58a88f227108 100644
--- a/net/ipv4/netfilter/ipt_NETMAP.c
+++ b/net/ipv4/netfilter/ipt_NETMAP.c
@@ -58,7 +58,7 @@ target(struct sk_buff **pskb,
{
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
- u_int32_t new_ip, netmask;
+ __be32 new_ip, netmask;
const struct ip_nat_multi_range_compat *mr = targinfo;
struct ip_nat_range newrange;
diff --git a/net/ipv4/netfilter/ipt_REDIRECT.c b/net/ipv4/netfilter/ipt_REDIRECT.c
index f03d43671c6d..c0dcfe9d610c 100644
--- a/net/ipv4/netfilter/ipt_REDIRECT.c
+++ b/net/ipv4/netfilter/ipt_REDIRECT.c
@@ -61,7 +61,7 @@ redirect_target(struct sk_buff **pskb,
{
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
- u_int32_t newdst;
+ __be32 newdst;
const struct ip_nat_multi_range_compat *mr = targinfo;
struct ip_nat_range newrange;
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index b81821edd893..ad0312d0e4fd 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -38,76 +38,16 @@ MODULE_DESCRIPTION("iptables REJECT target module");
#define DEBUGP(format, args...)
#endif
-static inline struct rtable *route_reverse(struct sk_buff *skb,
- struct tcphdr *tcph, int hook)
-{
- struct iphdr *iph = skb->nh.iph;
- struct dst_entry *odst;
- struct flowi fl = {};
- struct rtable *rt;
-
- /* We don't require ip forwarding to be enabled to be able to
- * send a RST reply for bridged traffic. */
- if (hook != NF_IP_FORWARD
-#ifdef CONFIG_BRIDGE_NETFILTER
- || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED)
-#endif
- ) {
- fl.nl_u.ip4_u.daddr = iph->saddr;
- if (hook == NF_IP_LOCAL_IN)
- fl.nl_u.ip4_u.saddr = iph->daddr;
- fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
-
- if (ip_route_output_key(&rt, &fl) != 0)
- return NULL;
- } else {
- /* non-local src, find valid iif to satisfy
- * rp-filter when calling ip_route_input. */
- fl.nl_u.ip4_u.daddr = iph->daddr;
- if (ip_route_output_key(&rt, &fl) != 0)
- return NULL;
-
- odst = skb->dst;
- if (ip_route_input(skb, iph->saddr, iph->daddr,
- RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
- dst_release(&rt->u.dst);
- return NULL;
- }
- dst_release(&rt->u.dst);
- rt = (struct rtable *)skb->dst;
- skb->dst = odst;
-
- fl.nl_u.ip4_u.daddr = iph->saddr;
- fl.nl_u.ip4_u.saddr = iph->daddr;
- fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
- }
-
- if (rt->u.dst.error) {
- dst_release(&rt->u.dst);
- return NULL;
- }
-
- fl.proto = IPPROTO_TCP;
- fl.fl_ip_sport = tcph->dest;
- fl.fl_ip_dport = tcph->source;
- security_skb_classify_flow(skb, &fl);
-
- xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
-
- return rt;
-}
-
/* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int hook)
{
struct sk_buff *nskb;
struct iphdr *iph = oldskb->nh.iph;
struct tcphdr _otcph, *oth, *tcph;
- struct rtable *rt;
- u_int16_t tmp_port;
- u_int32_t tmp_addr;
+ __be16 tmp_port;
+ __be32 tmp_addr;
int needs_ack;
- int hh_len;
+ unsigned int addr_type;
/* IP header checks: fragment. */
if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
@@ -126,23 +66,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
return;
- if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
- return;
-
- hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
-
/* We need a linear, writeable skb. We also need to expand
headroom in case hh_len of incoming interface < hh_len of
outgoing interface */
- nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
+ nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
GFP_ATOMIC);
- if (!nskb) {
- dst_release(&rt->u.dst);
+ if (!nskb)
return;
- }
-
- dst_release(nskb->dst);
- nskb->dst = &rt->u.dst;
/* This packet will not be the same as the other: clear nf fields */
nf_reset(nskb);
@@ -184,6 +114,21 @@ static void send_reset(struct sk_buff *oldskb, int hook)
tcph->window = 0;
tcph->urg_ptr = 0;
+ /* Set DF, id = 0 */
+ nskb->nh.iph->frag_off = htons(IP_DF);
+ nskb->nh.iph->id = 0;
+
+ addr_type = RTN_UNSPEC;
+ if (hook != NF_IP_FORWARD
+#ifdef CONFIG_BRIDGE_NETFILTER
+ || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
+#endif
+ )
+ addr_type = RTN_LOCAL;
+
+ if (ip_route_me_harder(&nskb, addr_type))
+ goto free_nskb;
+
/* Adjust TCP checksum */
nskb->ip_summed = CHECKSUM_NONE;
tcph->check = 0;
@@ -192,12 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook)
nskb->nh.iph->daddr,
csum_partial((char *)tcph,
sizeof(struct tcphdr), 0));
-
- /* Adjust IP TTL, DF */
+ /* Adjust IP TTL */
nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
- /* Set DF, id = 0 */
- nskb->nh.iph->frag_off = htons(IP_DF);
- nskb->nh.iph->id = 0;
/* Adjust IP checksum */
nskb->nh.iph->check = 0;
diff --git a/net/ipv4/netfilter/ipt_SAME.c b/net/ipv4/netfilter/ipt_SAME.c
index efbcb1198832..b38b13328d73 100644
--- a/net/ipv4/netfilter/ipt_SAME.c
+++ b/net/ipv4/netfilter/ipt_SAME.c
@@ -135,7 +135,8 @@ same_target(struct sk_buff **pskb,
{
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
- u_int32_t tmpip, aindex, new_ip;
+ u_int32_t tmpip, aindex;
+ __be32 new_ip;
const struct ipt_same_info *same = targinfo;
struct ip_nat_range newrange;
const struct ip_conntrack_tuple *t;
diff --git a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
index 4246c4321e5b..108b6b76311f 100644
--- a/net/ipv4/netfilter/ipt_TCPMSS.c
+++ b/net/ipv4/netfilter/ipt_TCPMSS.c
@@ -42,7 +42,8 @@ ipt_tcpmss_target(struct sk_buff **pskb,
const struct ipt_tcpmss_info *tcpmssinfo = targinfo;
struct tcphdr *tcph;
struct iphdr *iph;
- u_int16_t tcplen, newtotlen, oldval, newmss;
+ u_int16_t tcplen, newmss;
+ __be16 newtotlen, oldval;
unsigned int i;
u_int8_t *opt;
@@ -97,7 +98,7 @@ ipt_tcpmss_target(struct sk_buff **pskb,
opt[i+3] = (newmss & 0x00ff);
tcph->check = nf_proto_csum_update(*pskb,
- htons(oldmss)^0xFFFF,
+ htons(oldmss)^htons(0xFFFF),
htons(newmss),
tcph->check, 0);
return IPT_CONTINUE;
@@ -126,7 +127,7 @@ ipt_tcpmss_target(struct sk_buff **pskb,
memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
tcph->check = nf_proto_csum_update(*pskb,
- htons(tcplen) ^ 0xFFFF,
+ htons(tcplen) ^ htons(0xFFFF),
htons(tcplen + TCPOLEN_MSS),
tcph->check, 1);
opt[0] = TCPOPT_MSS;
@@ -134,18 +135,18 @@ ipt_tcpmss_target(struct sk_buff **pskb,
opt[2] = (newmss & 0xff00) >> 8;
opt[3] = (newmss & 0x00ff);
- tcph->check = nf_proto_csum_update(*pskb, ~0, *((u_int32_t *)opt),
+ tcph->check = nf_proto_csum_update(*pskb, htonl(~0), *((__be32 *)opt),
tcph->check, 0);
- oldval = ((u_int16_t *)tcph)[6];
+ oldval = ((__be16 *)tcph)[6];
tcph->doff += TCPOLEN_MSS/4;
tcph->check = nf_proto_csum_update(*pskb,
- oldval ^ 0xFFFF,
- ((u_int16_t *)tcph)[6],
+ oldval ^ htons(0xFFFF),
+ ((__be16 *)tcph)[6],
tcph->check, 0);
newtotlen = htons(ntohs(iph->tot_len) + TCPOLEN_MSS);
- iph->check = nf_csum_update(iph->tot_len ^ 0xFFFF,
+ iph->check = nf_csum_update(iph->tot_len ^ htons(0xFFFF),
newtotlen, iph->check);
iph->tot_len = newtotlen;
return IPT_CONTINUE;
diff --git a/net/ipv4/netfilter/ipt_TOS.c b/net/ipv4/netfilter/ipt_TOS.c
index 471a4c438b0a..83b80b3a5d2f 100644
--- a/net/ipv4/netfilter/ipt_TOS.c
+++ b/net/ipv4/netfilter/ipt_TOS.c
@@ -38,8 +38,8 @@ target(struct sk_buff **pskb,
iph = (*pskb)->nh.iph;
oldtos = iph->tos;
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos;
- iph->check = nf_csum_update(oldtos ^ 0xFFFF, iph->tos,
- iph->check);
+ iph->check = nf_csum_update(htons(oldtos) ^ htons(0xFFFF),
+ htons(iph->tos), iph->check);
}
return IPT_CONTINUE;
}
diff --git a/net/ipv4/netfilter/ipt_TTL.c b/net/ipv4/netfilter/ipt_TTL.c
index 96e79cc6d0f2..ac9517d62af0 100644
--- a/net/ipv4/netfilter/ipt_TTL.c
+++ b/net/ipv4/netfilter/ipt_TTL.c
@@ -54,8 +54,8 @@ ipt_ttl_target(struct sk_buff **pskb,
}
if (new_ttl != iph->ttl) {
- iph->check = nf_csum_update(ntohs((iph->ttl << 8)) ^ 0xFFFF,
- ntohs(new_ttl << 8),
+ iph->check = nf_csum_update(htons((iph->ttl << 8)) ^ htons(0xFFFF),
+ htons(new_ttl << 8),
iph->check);
iph->ttl = new_ttl;
}
diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c
index 893dae210b04..7b60eb74788b 100644
--- a/net/ipv4/netfilter/ipt_addrtype.c
+++ b/net/ipv4/netfilter/ipt_addrtype.c
@@ -22,7 +22,7 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_DESCRIPTION("iptables addrtype match");
-static inline int match_type(u_int32_t addr, u_int16_t mask)
+static inline int match_type(__be32 addr, u_int16_t mask)
{
return !!(mask & (1 << inet_addr_type(addr)));
}
diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c
index 4f73a61aa3dd..33ccdbf8e794 100644
--- a/net/ipv4/netfilter/ipt_hashlimit.c
+++ b/net/ipv4/netfilter/ipt_hashlimit.c
@@ -50,11 +50,11 @@ static struct file_operations dl_file_ops;
/* hash table crap */
struct dsthash_dst {
- u_int32_t src_ip;
- u_int32_t dst_ip;
+ __be32 src_ip;
+ __be32 dst_ip;
/* ports have to be consecutive !!! */
- u_int16_t src_port;
- u_int16_t dst_port;
+ __be16 src_port;
+ __be16 dst_port;
};
struct dsthash_ent {
@@ -106,8 +106,10 @@ static inline int dst_cmp(const struct dsthash_ent *ent, struct dsthash_dst *b)
static inline u_int32_t
hash_dst(const struct ipt_hashlimit_htable *ht, const struct dsthash_dst *dst)
{
- return (jhash_3words(dst->dst_ip, (dst->dst_port<<16 | dst->src_port),
- dst->src_ip, ht->rnd) % ht->cfg.size);
+ return (jhash_3words((__force u32)dst->dst_ip,
+ ((__force u32)dst->dst_port<<16 |
+ (__force u32)dst->src_port),
+ (__force u32)dst->src_ip, ht->rnd) % ht->cfg.size);
}
static inline struct dsthash_ent *
@@ -406,7 +408,7 @@ hashlimit_match(const struct sk_buff *skb,
dst.src_ip = skb->nh.iph->saddr;
if (hinfo->cfg.mode & IPT_HASHLIMIT_HASH_DPT
||hinfo->cfg.mode & IPT_HASHLIMIT_HASH_SPT) {
- u_int16_t _ports[2], *ports;
+ __be16 _ports[2], *ports;
switch (skb->nh.iph->protocol) {
case IPPROTO_TCP:
diff --git a/net/ipv4/netfilter/ipt_recent.c b/net/ipv4/netfilter/ipt_recent.c
index 32ae8d7ac506..126db44e71a8 100644
--- a/net/ipv4/netfilter/ipt_recent.c
+++ b/net/ipv4/netfilter/ipt_recent.c
@@ -50,11 +50,10 @@ MODULE_PARM_DESC(ip_list_perms, "permissions on /proc/net/ipt_recent/* files");
MODULE_PARM_DESC(ip_list_uid,"owner of /proc/net/ipt_recent/* files");
MODULE_PARM_DESC(ip_list_gid,"owning group of /proc/net/ipt_recent/* files");
-
struct recent_entry {
struct list_head list;
struct list_head lru_list;
- u_int32_t addr;
+ __be32 addr;
u_int8_t ttl;
u_int8_t index;
u_int16_t nstamps;
@@ -85,17 +84,17 @@ static struct file_operations recent_fops;
static u_int32_t hash_rnd;
static int hash_rnd_initted;
-static unsigned int recent_entry_hash(u_int32_t addr)
+static unsigned int recent_entry_hash(__be32 addr)
{
if (!hash_rnd_initted) {
get_random_bytes(&hash_rnd, 4);
hash_rnd_initted = 1;
}
- return jhash_1word(addr, hash_rnd) & (ip_list_hash_size - 1);
+ return jhash_1word((__force u32)addr, hash_rnd) & (ip_list_hash_size - 1);
}
static struct recent_entry *
-recent_entry_lookup(const struct recent_table *table, u_int32_t addr, u_int8_t ttl)
+recent_entry_lookup(const struct recent_table *table, __be32 addr, u_int8_t ttl)
{
struct recent_entry *e;
unsigned int h;
@@ -116,7 +115,7 @@ static void recent_entry_remove(struct recent_table *t, struct recent_entry *e)
}
static struct recent_entry *
-recent_entry_init(struct recent_table *t, u_int32_t addr, u_int8_t ttl)
+recent_entry_init(struct recent_table *t, __be32 addr, u_int8_t ttl)
{
struct recent_entry *e;
@@ -178,7 +177,7 @@ ipt_recent_match(const struct sk_buff *skb,
const struct ipt_recent_info *info = matchinfo;
struct recent_table *t;
struct recent_entry *e;
- u_int32_t addr;
+ __be32 addr;
u_int8_t ttl;
int ret = info->invert;
@@ -406,7 +405,7 @@ static ssize_t recent_proc_write(struct file *file, const char __user *input,
struct recent_table *t = pde->data;
struct recent_entry *e;
char buf[sizeof("+255.255.255.255")], *c = buf;
- u_int32_t addr;
+ __be32 addr;
int add;
if (size > sizeof(buf))
diff --git a/net/ipv4/netfilter/iptable_mangle.c b/net/ipv4/netfilter/iptable_mangle.c
index 79336cb42527..b91f3582359b 100644
--- a/net/ipv4/netfilter/iptable_mangle.c
+++ b/net/ipv4/netfilter/iptable_mangle.c
@@ -131,7 +131,7 @@ ipt_local_hook(unsigned int hook,
{
unsigned int ret;
u_int8_t tos;
- u_int32_t saddr, daddr;
+ __be32 saddr, daddr;
unsigned long nfmark;
/* root is playing with raw sockets. */
@@ -157,7 +157,8 @@ ipt_local_hook(unsigned int hook,
|| (*pskb)->nfmark != nfmark
#endif
|| (*pskb)->nh.iph->tos != tos))
- return ip_route_me_harder(pskb) == 0 ? ret : NF_DROP;
+ if (ip_route_me_harder(pskb, RTN_UNSPEC))
+ ret = NF_DROP;
return ret;
}
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 0e935b4c8741..b430cf2a4f66 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -381,8 +381,8 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
struct ipcm_cookie ipc;
struct rtable *rt = NULL;
int free = 0;
- u32 daddr;
- u32 saddr;
+ __be32 daddr;
+ __be32 saddr;
u8 tos;
int err;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 20ffe8e88c0f..925ee4dfc32c 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -261,6 +261,10 @@ static unsigned int rt_hash_code(u32 daddr, u32 saddr)
& rt_hash_mask);
}
+#define rt_hash(daddr, saddr, idx) \
+ rt_hash_code((__force u32)(__be32)(daddr),\
+ (__force u32)(__be32)(saddr) ^ ((idx) << 5))
+
#ifdef CONFIG_PROC_FS
struct rt_cache_iter_state {
int bucket;
@@ -562,9 +566,15 @@ static inline u32 rt_score(struct rtable *rt)
static inline int compare_keys(struct flowi *fl1, struct flowi *fl2)
{
- return memcmp(&fl1->nl_u.ip4_u, &fl2->nl_u.ip4_u, sizeof(fl1->nl_u.ip4_u)) == 0 &&
- fl1->oif == fl2->oif &&
- fl1->iif == fl2->iif;
+ return ((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) |
+ (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) |
+#ifdef CONFIG_IP_ROUTE_FWMARK
+ (fl1->nl_u.ip4_u.fwmark ^ fl2->nl_u.ip4_u.fwmark) |
+#endif
+ (*(u16 *)&fl1->nl_u.ip4_u.tos ^
+ *(u16 *)&fl2->nl_u.ip4_u.tos) |
+ (fl1->oif ^ fl2->oif) |
+ (fl1->iif ^ fl2->iif)) == 0;
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
@@ -1074,7 +1084,7 @@ static void ip_select_fb_ident(struct iphdr *iph)
u32 salt;
spin_lock_bh(&ip_fb_id_lock);
- salt = secure_ip_id(ip_fallback_id ^ iph->daddr);
+ salt = secure_ip_id((__force __be32)ip_fallback_id ^ iph->daddr);
iph->id = htons(salt & 0xFFFF);
ip_fallback_id = salt;
spin_unlock_bh(&ip_fb_id_lock);
@@ -1118,13 +1128,13 @@ static void rt_del(unsigned hash, struct rtable *rt)
spin_unlock_bh(rt_hash_lock_addr(hash));
}
-void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
- u32 saddr, struct net_device *dev)
+void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
+ __be32 saddr, struct net_device *dev)
{
int i, k;
struct in_device *in_dev = in_dev_get(dev);
struct rtable *rth, **rthp;
- u32 skeys[2] = { saddr, 0 };
+ __be32 skeys[2] = { saddr, 0 };
int ikeys[2] = { dev->ifindex, 0 };
struct netevent_redirect netevent;
@@ -1147,8 +1157,7 @@ void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
for (i = 0; i < 2; i++) {
for (k = 0; k < 2; k++) {
- unsigned hash = rt_hash_code(daddr,
- skeys[i] ^ (ikeys[k] << 5));
+ unsigned hash = rt_hash(daddr, skeys[i], ikeys[k]);
rthp=&rt_hash_table[hash].chain;
@@ -1260,9 +1269,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst)
ret = NULL;
} else if ((rt->rt_flags & RTCF_REDIRECTED) ||
rt->u.dst.expires) {
- unsigned hash = rt_hash_code(rt->fl.fl4_dst,
- rt->fl.fl4_src ^
- (rt->fl.oif << 5));
+ unsigned hash = rt_hash(rt->fl.fl4_dst, rt->fl.fl4_src,
+ rt->fl.oif);
#if RT_CACHE_DEBUG >= 1
printk(KERN_DEBUG "ip_rt_advice: redirect to "
"%u.%u.%u.%u/%02x dropped\n",
@@ -1397,15 +1405,15 @@ unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu)
int i;
unsigned short old_mtu = ntohs(iph->tot_len);
struct rtable *rth;
- u32 skeys[2] = { iph->saddr, 0, };
- u32 daddr = iph->daddr;
+ __be32 skeys[2] = { iph->saddr, 0, };
+ __be32 daddr = iph->daddr;
unsigned short est_mtu = 0;
if (ipv4_config.no_pmtu_disc)
return 0;
for (i = 0; i < 2; i++) {
- unsigned hash = rt_hash_code(daddr, skeys[i]);
+ unsigned hash = rt_hash(daddr, skeys[i], 0);
rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -1530,7 +1538,7 @@ static int ip_rt_bug(struct sk_buff *skb)
void ip_rt_get_source(u8 *addr, struct rtable *rt)
{
- u32 src;
+ __be32 src;
struct fib_result res;
if (rt->fl.iif == 0)
@@ -1596,12 +1604,12 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
rt->rt_type = res->type;
}
-static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
+static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev, int our)
{
unsigned hash;
struct rtable *rth;
- u32 spec_dst;
+ __be32 spec_dst;
struct in_device *in_dev = in_dev_get(dev);
u32 itag = 0;
@@ -1665,7 +1673,7 @@ static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr,
RT_CACHE_STAT_INC(in_slow_mc);
in_dev_put(in_dev);
- hash = rt_hash_code(daddr, saddr ^ (dev->ifindex << 5));
+ hash = rt_hash(daddr, saddr, dev->ifindex);
return rt_intern_hash(hash, rth, (struct rtable**) &skb->dst);
e_nobufs:
@@ -1681,8 +1689,8 @@ e_inval:
static void ip_handle_martian_source(struct net_device *dev,
struct in_device *in_dev,
struct sk_buff *skb,
- u32 daddr,
- u32 saddr)
+ __be32 daddr,
+ __be32 saddr)
{
RT_CACHE_STAT_INC(in_martian_src);
#ifdef CONFIG_IP_ROUTE_VERBOSE
@@ -1712,7 +1720,7 @@ static void ip_handle_martian_source(struct net_device *dev,
static inline int __mkroute_input(struct sk_buff *skb,
struct fib_result* res,
struct in_device *in_dev,
- u32 daddr, u32 saddr, u32 tos,
+ __be32 daddr, __be32 saddr, u32 tos,
struct rtable **result)
{
@@ -1720,7 +1728,8 @@ static inline int __mkroute_input(struct sk_buff *skb,
int err;
struct in_device *out_dev;
unsigned flags = 0;
- u32 spec_dst, itag;
+ __be32 spec_dst;
+ u32 itag;
/* get a working reference to the output device */
out_dev = in_dev_get(FIB_RES_DEV(*res));
@@ -1813,7 +1822,7 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
struct fib_result* res,
const struct flowi *fl,
struct in_device *in_dev,
- u32 daddr, u32 saddr, u32 tos)
+ __be32 daddr, __be32 saddr, u32 tos)
{
struct rtable* rth = NULL;
int err;
@@ -1830,7 +1839,7 @@ static inline int ip_mkroute_input_def(struct sk_buff *skb,
return err;
/* put it into the cache */
- hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
+ hash = rt_hash(daddr, saddr, fl->iif);
return rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
}
@@ -1838,7 +1847,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
struct fib_result* res,
const struct flowi *fl,
struct in_device *in_dev,
- u32 daddr, u32 saddr, u32 tos)
+ __be32 daddr, __be32 saddr, u32 tos)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
struct rtable* rth = NULL, *rtres;
@@ -1871,7 +1880,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
return err;
/* put it into the cache */
- hash = rt_hash_code(daddr, saddr ^ (fl->iif << 5));
+ hash = rt_hash(daddr, saddr, fl->iif);
err = rt_intern_hash(hash, rth, &rtres);
if (err)
return err;
@@ -1901,7 +1910,7 @@ static inline int ip_mkroute_input(struct sk_buff *skb,
* 2. IP spoofing attempts are filtered with 100% of guarantee.
*/
-static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
+static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
struct fib_result res;
@@ -1920,7 +1929,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
u32 itag = 0;
struct rtable * rth;
unsigned hash;
- u32 spec_dst;
+ __be32 spec_dst;
int err = -EINVAL;
int free_res = 0;
@@ -1936,7 +1945,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
if (MULTICAST(saddr) || BADCLASS(saddr) || LOOPBACK(saddr))
goto martian_source;
- if (daddr == 0xFFFFFFFF || (saddr == 0 && daddr == 0))
+ if (daddr == htonl(0xFFFFFFFF) || (saddr == 0 && daddr == 0))
goto brd_input;
/* Accept zero addresses only to limited broadcast;
@@ -2048,7 +2057,7 @@ local_input:
rth->rt_flags &= ~RTCF_LOCAL;
}
rth->rt_type = res.type;
- hash = rt_hash_code(daddr, saddr ^ (fl.iif << 5));
+ hash = rt_hash(daddr, saddr, fl.iif);
err = rt_intern_hash(hash, rth, (struct rtable**)&skb->dst);
goto done;
@@ -2087,7 +2096,7 @@ martian_source:
goto e_inval;
}
-int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
+int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr,
u8 tos, struct net_device *dev)
{
struct rtable * rth;
@@ -2095,7 +2104,7 @@ int ip_route_input(struct sk_buff *skb, u32 daddr, u32 saddr,
int iif = dev->ifindex;
tos &= IPTOS_RT_MASK;
- hash = rt_hash_code(daddr, saddr ^ (iif << 5));
+ hash = rt_hash(daddr, saddr, iif);
rcu_read_lock();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -2169,7 +2178,7 @@ static inline int __mkroute_output(struct rtable **result,
if (LOOPBACK(fl->fl4_src) && !(dev_out->flags&IFF_LOOPBACK))
return -EINVAL;
- if (fl->fl4_dst == 0xFFFFFFFF)
+ if (fl->fl4_dst == htonl(0xFFFFFFFF))
res->type = RTN_BROADCAST;
else if (MULTICAST(fl->fl4_dst))
res->type = RTN_MULTICAST;
@@ -2293,8 +2302,7 @@ static inline int ip_mkroute_output_def(struct rtable **rp,
int err = __mkroute_output(&rth, res, fl, oldflp, dev_out, flags);
unsigned hash;
if (err == 0) {
- hash = rt_hash_code(oldflp->fl4_dst,
- oldflp->fl4_src ^ (oldflp->oif << 5));
+ hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src, oldflp->oif);
err = rt_intern_hash(hash, rth, rp);
}
@@ -2336,9 +2344,8 @@ static inline int ip_mkroute_output(struct rtable** rp,
if (err != 0)
goto cleanup;
- hash = rt_hash_code(oldflp->fl4_dst,
- oldflp->fl4_src ^
- (oldflp->oif << 5));
+ hash = rt_hash(oldflp->fl4_dst, oldflp->fl4_src,
+ oldflp->oif);
err = rt_intern_hash(hash, rth, rp);
/* forward hop information to multipath impl. */
@@ -2417,7 +2424,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
*/
if (oldflp->oif == 0
- && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF)) {
+ && (MULTICAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF))) {
/* Special hack: user can direct multicasts
and limited broadcast via necessary interface
without fiddling with IP_MULTICAST_IF or IP_PKTINFO.
@@ -2454,7 +2461,7 @@ static int ip_route_output_slow(struct rtable **rp, const struct flowi *oldflp)
goto out; /* Wrong error code */
}
- if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == 0xFFFFFFFF) {
+ if (LOCAL_MCAST(oldflp->fl4_dst) || oldflp->fl4_dst == htonl(0xFFFFFFFF)) {
if (!fl.fl4_src)
fl.fl4_src = inet_select_addr(dev_out, 0,
RT_SCOPE_LINK);
@@ -2567,7 +2574,7 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp)
unsigned hash;
struct rtable *rth;
- hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5));
+ hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif);
rcu_read_lock_bh();
for (rth = rcu_dereference(rt_hash_table[hash].chain); rth;
@@ -2660,11 +2667,11 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
if (rt->rt_flags & RTCF_NOTIFY)
r->rtm_flags |= RTM_F_NOTIFY;
- NLA_PUT_U32(skb, RTA_DST, rt->rt_dst);
+ NLA_PUT_BE32(skb, RTA_DST, rt->rt_dst);
if (rt->fl.fl4_src) {
r->rtm_src_len = 32;
- NLA_PUT_U32(skb, RTA_SRC, rt->fl.fl4_src);
+ NLA_PUT_BE32(skb, RTA_SRC, rt->fl.fl4_src);
}
if (rt->u.dst.dev)
NLA_PUT_U32(skb, RTA_OIF, rt->u.dst.dev->ifindex);
@@ -2677,12 +2684,12 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
NLA_PUT_U32(skb, RTA_MP_ALGO, rt->rt_multipath_alg);
#endif
if (rt->fl.iif)
- NLA_PUT_U32(skb, RTA_PREFSRC, rt->rt_spec_dst);
+ NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_spec_dst);
else if (rt->rt_src != rt->fl.fl4_src)
- NLA_PUT_U32(skb, RTA_PREFSRC, rt->rt_src);
+ NLA_PUT_BE32(skb, RTA_PREFSRC, rt->rt_src);
if (rt->rt_dst != rt->rt_gateway)
- NLA_PUT_U32(skb, RTA_GATEWAY, rt->rt_gateway);
+ NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
goto nla_put_failure;
@@ -2706,7 +2713,7 @@ static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
if (rt->fl.iif) {
#ifdef CONFIG_IP_MROUTE
- u32 dst = rt->rt_dst;
+ __be32 dst = rt->rt_dst;
if (MULTICAST(dst) && !LOCAL_MCAST(dst) &&
ipv4_devconf.mc_forwarding) {
@@ -2740,7 +2747,9 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
struct rtmsg *rtm;
struct nlattr *tb[RTA_MAX+1];
struct rtable *rt = NULL;
- u32 dst, src, iif;
+ __be32 dst = 0;
+ __be32 src = 0;
+ u32 iif;
int err;
struct sk_buff *skb;
@@ -2765,8 +2774,8 @@ int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
skb->nh.iph->protocol = IPPROTO_ICMP;
skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr));
- src = tb[RTA_SRC] ? nla_get_u32(tb[RTA_SRC]) : 0;
- dst = tb[RTA_DST] ? nla_get_u32(tb[RTA_DST]) : 0;
+ src = tb[RTA_SRC] ? nla_get_be32(tb[RTA_SRC]) : 0;
+ dst = tb[RTA_DST] ? nla_get_be32(tb[RTA_DST]) : 0;
iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0;
if (iif) {
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index b3def0df14fb..cf06accbe687 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -935,7 +935,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
const struct inet_connection_sock *icsk = inet_csk(sk);
struct tcp_sock *tp = tcp_sk(sk);
unsigned char *ptr = ack_skb->h.raw + TCP_SKB_CB(ack_skb)->sacked;
- struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
+ struct tcp_sack_block_wire *sp = (struct tcp_sack_block_wire *)(ptr+2);
int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
int reord = tp->packets_out;
int prior_fackets;
@@ -2239,13 +2239,12 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb,
return acked;
}
-static u32 tcp_usrtt(const struct sk_buff *skb)
+static u32 tcp_usrtt(struct timeval *tv)
{
- struct timeval tv, now;
+ struct timeval now;
do_gettimeofday(&now);
- skb_get_timestamp(skb, &tv);
- return (now.tv_sec - tv.tv_sec) * 1000000 + (now.tv_usec - tv.tv_usec);
+ return (now.tv_sec - tv->tv_sec) * 1000000 + (now.tv_usec - tv->tv_usec);
}
/* Remove acknowledged frames from the retransmission queue. */
@@ -2260,6 +2259,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
u32 pkts_acked = 0;
void (*rtt_sample)(struct sock *sk, u32 usrtt)
= icsk->icsk_ca_ops->rtt_sample;
+ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
while ((skb = skb_peek(&sk->sk_write_queue)) &&
skb != sk->sk_send_head) {
@@ -2308,8 +2308,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
seq_rtt = -1;
} else if (seq_rtt < 0) {
seq_rtt = now - scb->when;
- if (rtt_sample)
- (*rtt_sample)(sk, tcp_usrtt(skb));
+ skb_get_timestamp(skb, &tv);
}
if (sacked & TCPCB_SACKED_ACKED)
tp->sacked_out -= tcp_skb_pcount(skb);
@@ -2322,8 +2321,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
}
} else if (seq_rtt < 0) {
seq_rtt = now - scb->when;
- if (rtt_sample)
- (*rtt_sample)(sk, tcp_usrtt(skb));
+ skb_get_timestamp(skb, &tv);
}
tcp_dec_pcount_approx(&tp->fackets_out, skb);
tcp_packets_out_dec(tp, skb);
@@ -2335,6 +2333,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
if (acked&FLAG_ACKED) {
tcp_ack_update_rtt(sk, acked, seq_rtt);
tcp_ack_packets_out(sk, tp);
+ if (rtt_sample && !(acked & FLAG_RETRANS_DATA_ACKED))
+ (*rtt_sample)(sk, tcp_usrtt(&tv));
if (icsk->icsk_ca_ops->pkts_acked)
icsk->icsk_ca_ops->pkts_acked(sk, pkts_acked);
@@ -2629,7 +2629,7 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
switch(opcode) {
case TCPOPT_MSS:
if(opsize==TCPOLEN_MSS && th->syn && !estab) {
- u16 in_mss = ntohs(get_unaligned((__u16 *)ptr));
+ u16 in_mss = ntohs(get_unaligned((__be16 *)ptr));
if (in_mss) {
if (opt_rx->user_mss && opt_rx->user_mss < in_mss)
in_mss = opt_rx->user_mss;
@@ -2657,8 +2657,8 @@ void tcp_parse_options(struct sk_buff *skb, struct tcp_options_received *opt_rx,
if ((estab && opt_rx->tstamp_ok) ||
(!estab && sysctl_tcp_timestamps)) {
opt_rx->saw_tstamp = 1;
- opt_rx->rcv_tsval = ntohl(get_unaligned((__u32 *)ptr));
- opt_rx->rcv_tsecr = ntohl(get_unaligned((__u32 *)(ptr+4)));
+ opt_rx->rcv_tsval = ntohl(get_unaligned((__be32 *)ptr));
+ opt_rx->rcv_tsecr = ntohl(get_unaligned((__be32 *)(ptr+4)));
}
}
break;
@@ -2695,8 +2695,8 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
return 0;
} else if (tp->rx_opt.tstamp_ok &&
th->doff == (sizeof(struct tcphdr)>>2)+(TCPOLEN_TSTAMP_ALIGNED>>2)) {
- __u32 *ptr = (__u32 *)(th + 1);
- if (*ptr == ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+ __be32 *ptr = (__be32 *)(th + 1);
+ if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
| (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) {
tp->rx_opt.saw_tstamp = 1;
++ptr;
@@ -3911,10 +3911,10 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
/* Check timestamp */
if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) {
- __u32 *ptr = (__u32 *)(th + 1);
+ __be32 *ptr = (__be32 *)(th + 1);
/* No? Slow path! */
- if (*ptr != ntohl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
+ if (*ptr != htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16)
| (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP))
goto slow_path;
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 39b179856082..22ef8bd26620 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -159,7 +159,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct tcp_sock *tp = tcp_sk(sk);
struct sockaddr_in *usin = (struct sockaddr_in *)uaddr;
struct rtable *rt;
- u32 daddr, nexthop;
+ __be32 daddr, nexthop;
int tmp;
int err;
@@ -355,7 +355,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
return;
}
if (sk->sk_state == TCP_TIME_WAIT) {
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
return;
}
@@ -373,7 +373,7 @@ void tcp_v4_err(struct sk_buff *skb, u32 info)
seq = ntohl(th->seq);
if (sk->sk_state != TCP_LISTEN &&
!between(seq, tp->snd_una, tp->snd_nxt)) {
- NET_INC_STATS(LINUX_MIB_OUTOFWINDOWICMPS);
+ NET_INC_STATS_BH(LINUX_MIB_OUTOFWINDOWICMPS);
goto out;
}
@@ -578,7 +578,7 @@ static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
struct tcphdr *th = skb->h.th;
struct {
struct tcphdr th;
- u32 tsopt[3];
+ u32 tsopt[TCPOLEN_TSTAMP_ALIGNED >> 2];
} rep;
struct ip_reply_arg arg;
@@ -734,8 +734,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
struct inet_request_sock *ireq;
struct tcp_options_received tmp_opt;
struct request_sock *req;
- __u32 saddr = skb->nh.iph->saddr;
- __u32 daddr = skb->nh.iph->daddr;
+ __be32 saddr = skb->nh.iph->saddr;
+ __be32 daddr = skb->nh.iph->daddr;
__u32 isn = TCP_SKB_CB(skb)->when;
struct dst_entry *dst = NULL;
#ifdef CONFIG_SYN_COOKIES
@@ -960,7 +960,7 @@ static struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
bh_lock_sock(nsk);
return nsk;
}
- inet_twsk_put((struct inet_timewait_sock *)nsk);
+ inet_twsk_put(inet_twsk(nsk));
return NULL;
}
@@ -1154,26 +1154,24 @@ discard_and_relse:
do_time_wait:
if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
- inet_twsk_put((struct inet_timewait_sock *) sk);
+ inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(TCP_MIB_INERRS);
- inet_twsk_put((struct inet_timewait_sock *) sk);
+ inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
- switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
- skb, th)) {
+ switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
case TCP_TW_SYN: {
struct sock *sk2 = inet_lookup_listener(&tcp_hashinfo,
skb->nh.iph->daddr,
th->dest,
inet_iif(skb));
if (sk2) {
- inet_twsk_deschedule((struct inet_timewait_sock *)sk,
- &tcp_death_row);
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_deschedule(inet_twsk(sk), &tcp_death_row);
+ inet_twsk_put(inet_twsk(sk));
sk = sk2;
goto process;
}
@@ -1763,7 +1761,7 @@ static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i)
static void get_timewait4_sock(struct inet_timewait_sock *tw, char *tmpbuf, int i)
{
- unsigned int dest, src;
+ __be32 dest, src;
__u16 destp, srcp;
int ttd = tw->tw_ttd - jiffies;
diff --git a/net/ipv4/tcp_lp.c b/net/ipv4/tcp_lp.c
index 308fb7e071c5..f0ebaf0e21cb 100644
--- a/net/ipv4/tcp_lp.c
+++ b/net/ipv4/tcp_lp.c
@@ -31,8 +31,6 @@
* Hung Hing Lun, Mike <hlhung3i@gmail.com>
* SourceForge project page:
* http://tcp-lp-mod.sourceforge.net/
- *
- * Version: $Id: tcp_lp.c,v 1.24 2006/09/05 20:22:53 hswong3i Exp $
*/
#include <linux/module.h>
@@ -164,7 +162,7 @@ static u32 tcp_lp_remote_hz_estimator(struct sock *sk)
out:
/* record time for successful remote HZ calc */
- if (rhz > 0)
+ if ((rhz >> 6) > 0)
lp->flag |= LP_VALID_RHZ;
else
lp->flag &= ~LP_VALID_RHZ;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index 061edfae0c29..ca406157724c 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -269,14 +269,14 @@ static u16 tcp_select_window(struct sock *sk)
return new_win;
}
-static void tcp_build_and_update_options(__u32 *ptr, struct tcp_sock *tp,
+static void tcp_build_and_update_options(__be32 *ptr, struct tcp_sock *tp,
__u32 tstamp)
{
if (tp->rx_opt.tstamp_ok) {
- *ptr++ = __constant_htonl((TCPOPT_NOP << 24) |
- (TCPOPT_NOP << 16) |
- (TCPOPT_TIMESTAMP << 8) |
- TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
*ptr++ = htonl(tstamp);
*ptr++ = htonl(tp->rx_opt.ts_recent);
}
@@ -305,7 +305,7 @@ static void tcp_build_and_update_options(__u32 *ptr, struct tcp_sock *tp,
* MAX_SYN_SIZE to match the new maximum number of options that you
* can generate.
*/
-static void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
+static void tcp_syn_build_options(__be32 *ptr, int mss, int ts, int sack,
int offer_wscale, int wscale, __u32 tstamp,
__u32 ts_recent)
{
@@ -325,18 +325,27 @@ static void tcp_syn_build_options(__u32 *ptr, int mss, int ts, int sack,
*ptr++ = htonl((TCPOPT_MSS << 24) | (TCPOLEN_MSS << 16) | mss);
if (ts) {
if(sack)
- *ptr++ = __constant_htonl((TCPOPT_SACK_PERM << 24) | (TCPOLEN_SACK_PERM << 16) |
- (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
+ (TCPOLEN_SACK_PERM << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
else
- *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
- (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP);
+ *ptr++ = htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_TIMESTAMP << 8) |
+ TCPOLEN_TIMESTAMP);
*ptr++ = htonl(tstamp); /* TSVAL */
*ptr++ = htonl(ts_recent); /* TSECR */
} else if(sack)
- *ptr++ = __constant_htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
- (TCPOPT_SACK_PERM << 8) | TCPOLEN_SACK_PERM);
+ *ptr++ = htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_SACK_PERM << 8) |
+ TCPOLEN_SACK_PERM);
if (offer_wscale)
- *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_WINDOW << 16) | (TCPOLEN_WINDOW << 8) | (wscale));
+ *ptr++ = htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_WINDOW << 16) |
+ (TCPOLEN_WINDOW << 8) |
+ (wscale));
}
/* This routine actually transmits TCP packets queued in by
@@ -424,7 +433,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
th->dest = inet->dport;
th->seq = htonl(tcb->seq);
th->ack_seq = htonl(tp->rcv_nxt);
- *(((__u16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
+ *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) |
tcb->flags);
if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
@@ -445,7 +454,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
}
if (unlikely(tcb->flags & TCPCB_FLAG_SYN)) {
- tcp_syn_build_options((__u32 *)(th + 1),
+ tcp_syn_build_options((__be32 *)(th + 1),
tcp_advertise_mss(sk),
(sysctl_flags & SYSCTL_FLAG_TSTAMPS),
(sysctl_flags & SYSCTL_FLAG_SACK),
@@ -454,7 +463,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
tcb->when,
tp->rx_opt.ts_recent);
} else {
- tcp_build_and_update_options((__u32 *)(th + 1),
+ tcp_build_and_update_options((__be32 *)(th + 1),
tp, tcb->when);
TCP_ECN_send(sk, tp, skb, tcp_header_size);
}
@@ -1087,10 +1096,14 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
u32 send_win, cong_win, limit, in_flight;
if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
- return 0;
+ goto send_now;
if (icsk->icsk_ca_state != TCP_CA_Open)
- return 0;
+ goto send_now;
+
+ /* Defer for less than two clock ticks. */
+ if (!tp->tso_deferred && ((jiffies<<1)>>1) - (tp->tso_deferred>>1) > 1)
+ goto send_now;
in_flight = tcp_packets_in_flight(tp);
@@ -1106,7 +1119,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
/* If a full-sized TSO skb can be sent, do it. */
if (limit >= 65536)
- return 0;
+ goto send_now;
if (sysctl_tcp_tso_win_divisor) {
u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
@@ -1116,7 +1129,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
*/
chunk /= sysctl_tcp_tso_win_divisor;
if (limit >= chunk)
- return 0;
+ goto send_now;
} else {
/* Different approach, try not to defer past a single
* ACK. Receiver should ACK every other full sized
@@ -1124,11 +1137,17 @@ static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_
* then send now.
*/
if (limit > tcp_max_burst(tp) * tp->mss_cache)
- return 0;
+ goto send_now;
}
/* Ok, it looks like it is advisable to defer. */
+ tp->tso_deferred = 1 | (jiffies<<1);
+
return 1;
+
+send_now:
+ tp->tso_deferred = 0;
+ return 0;
}
/* Create a new MTU probe if we are ready.
@@ -2070,7 +2089,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst,
th->window = htons(req->rcv_wnd);
TCP_SKB_CB(skb)->when = tcp_time_stamp;
- tcp_syn_build_options((__u32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
+ tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok,
ireq->sack_ok, ireq->wscale_ok, ireq->rcv_wscale,
TCP_SKB_CB(skb)->when,
req->ts_recent);
diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c
index dab37d2f65fc..4be336f17883 100644
--- a/net/ipv4/tcp_probe.c
+++ b/net/ipv4/tcp_probe.c
@@ -99,8 +99,10 @@ static int jtcp_sendmsg(struct kiocb *iocb, struct sock *sk,
}
static struct jprobe tcp_send_probe = {
- .kp = { .addr = (kprobe_opcode_t *) &tcp_sendmsg, },
- .entry = (kprobe_opcode_t *) &jtcp_sendmsg,
+ .kp = {
+ .symbol_name = "tcp_sendmsg",
+ },
+ .entry = JPROBE_ENTRY(jtcp_sendmsg),
};
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 77e265d7bb8f..865d75214a9a 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -243,8 +243,8 @@ static void udp_v4_unhash(struct sock *sk)
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try
* harder than this. -DaveM
*/
-static struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport,
- u32 daddr, u16 dport, int dif)
+static struct sock *udp_v4_lookup_longway(__be32 saddr, __be16 sport,
+ __be32 daddr, __be16 dport, int dif)
{
struct sock *sk, *result = NULL;
struct hlist_node *node;
@@ -288,8 +288,8 @@ static struct sock *udp_v4_lookup_longway(u32 saddr, u16 sport,
return result;
}
-static __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport,
- u32 daddr, u16 dport, int dif)
+static __inline__ struct sock *udp_v4_lookup(__be32 saddr, __be16 sport,
+ __be32 daddr, __be16 dport, int dif)
{
struct sock *sk;
@@ -302,8 +302,8 @@ static __inline__ struct sock *udp_v4_lookup(u32 saddr, u16 sport,
}
static inline struct sock *udp_v4_mcast_next(struct sock *sk,
- u16 loc_port, u32 loc_addr,
- u16 rmt_port, u32 rmt_addr,
+ __be16 loc_port, __be32 loc_addr,
+ __be16 rmt_port, __be32 rmt_addr,
int dif)
{
struct hlist_node *node;
@@ -498,7 +498,7 @@ out:
}
-static unsigned short udp_check(struct udphdr *uh, int len, unsigned long saddr, unsigned long daddr, unsigned long base)
+static unsigned short udp_check(struct udphdr *uh, int len, __be32 saddr, __be32 daddr, unsigned long base)
{
return(csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base));
}
@@ -513,8 +513,8 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
struct rtable *rt = NULL;
int free = 0;
int connected = 0;
- u32 daddr, faddr, saddr;
- u16 dport;
+ __be32 daddr, faddr, saddr;
+ __be16 dport;
u8 tos;
int err;
int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
@@ -675,6 +675,8 @@ do_append_data:
udp_flush_pending_frames(sk);
else if (!corkreq)
err = udp_push_pending_frames(sk, up);
+ else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
+ up->pending = 0;
release_sock(sk);
out:
@@ -931,7 +933,7 @@ static int udp_encap_rcv(struct sock * sk, struct sk_buff *skb)
int iphlen, len;
__u8 *udpdata = (__u8 *)uh + sizeof(struct udphdr);
- __u32 *udpdata32 = (__u32 *)udpdata;
+ __be32 *udpdata32 = (__be32 *)udpdata;
__u16 encap_type = up->encap_type;
/* if we're overly short, let UDP handle it */
@@ -1080,7 +1082,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
* so we don't need to lock the hashes.
*/
static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
- u32 saddr, u32 daddr)
+ __be32 saddr, __be32 daddr)
{
struct sock *sk;
int dif;
@@ -1121,7 +1123,7 @@ static int udp_v4_mcast_deliver(struct sk_buff *skb, struct udphdr *uh,
* including udp header and folding it to skb->csum.
*/
static void udp_checksum_init(struct sk_buff *skb, struct udphdr *uh,
- unsigned short ulen, u32 saddr, u32 daddr)
+ unsigned short ulen, __be32 saddr, __be32 daddr)
{
if (uh->check == 0) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -1146,8 +1148,8 @@ int udp_rcv(struct sk_buff *skb)
struct udphdr *uh;
unsigned short ulen;
struct rtable *rt = (struct rtable*)skb->dst;
- u32 saddr = skb->nh.iph->saddr;
- u32 daddr = skb->nh.iph->daddr;
+ __be32 saddr = skb->nh.iph->saddr;
+ __be32 daddr = skb->nh.iph->daddr;
int len = skb->len;
/*
@@ -1563,8 +1565,8 @@ void udp_proc_unregister(struct udp_seq_afinfo *afinfo)
static void udp4_format_sock(struct sock *sp, char *tmpbuf, int bucket)
{
struct inet_sock *inet = inet_sk(sp);
- unsigned int dest = inet->daddr;
- unsigned int src = inet->rcv_saddr;
+ __be32 dest = inet->daddr;
+ __be32 src = inet->rcv_saddr;
__u16 destp = ntohs(inet->dport);
__u16 srcp = ntohs(inet->sport);
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c
index 040e8475f295..8655d038364c 100644
--- a/net/ipv4/xfrm4_input.c
+++ b/net/ipv4/xfrm4_input.c
@@ -23,7 +23,7 @@ int xfrm4_rcv(struct sk_buff *skb)
EXPORT_SYMBOL(xfrm4_rcv);
-static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
{
switch (nexthdr) {
case IPPROTO_IPIP:
@@ -55,7 +55,7 @@ drop:
int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type)
{
int err;
- u32 spi, seq;
+ __be32 spi, seq;
struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x;
int xfrm_nr = 0;
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c
new file mode 100644
index 000000000000..89cf59ea7bbe
--- /dev/null
+++ b/net/ipv4/xfrm4_mode_beet.c
@@ -0,0 +1,139 @@
+/*
+ * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4.
+ *
+ * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com>
+ * Miika Komu <miika@iki.fi>
+ * Herbert Xu <herbert@gondor.apana.org.au>
+ * Abhinav Pathak <abhinav.pathak@hiit.fi>
+ * Jeff Ahrenholz <ahrenholz@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stringify.h>
+#include <net/dst.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+
+/* Add encapsulation header.
+ *
+ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
+ * The following fields in it shall be filled in by x->type->output:
+ * tot_len
+ * check
+ *
+ * On exit, skb->h will be set to the start of the payload to be processed
+ * by x->type->output and skb->nh will be set to the top IP header.
+ */
+static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct iphdr *iph, *top_iph = NULL;
+ int hdrlen, optlen;
+
+ iph = skb->nh.iph;
+ skb->h.ipiph = iph;
+
+ hdrlen = 0;
+ optlen = iph->ihl * 4 - sizeof(*iph);
+ if (unlikely(optlen))
+ hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4);
+
+ skb->nh.raw = skb_push(skb, x->props.header_len + hdrlen);
+ top_iph = skb->nh.iph;
+ hdrlen = iph->ihl * 4 - optlen;
+ skb->h.raw += hdrlen;
+
+ memmove(top_iph, iph, hdrlen);
+ if (unlikely(optlen)) {
+ struct ip_beet_phdr *ph;
+
+ BUG_ON(optlen < 0);
+
+ ph = (struct ip_beet_phdr *)skb->h.raw;
+ ph->padlen = 4 - (optlen & 4);
+ ph->hdrlen = (optlen + ph->padlen + sizeof(*ph)) / 8;
+ ph->nexthdr = top_iph->protocol;
+
+ top_iph->protocol = IPPROTO_BEETPH;
+ top_iph->ihl = sizeof(struct iphdr) / 4;
+ }
+
+ top_iph->saddr = x->props.saddr.a4;
+ top_iph->daddr = x->id.daddr.a4;
+
+ return 0;
+}
+
+static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct iphdr *iph = skb->nh.iph;
+ int phlen = 0;
+ int optlen = 0;
+ __u8 ph_nexthdr = 0, protocol = 0;
+ int err = -EINVAL;
+
+ protocol = iph->protocol;
+
+ if (unlikely(iph->protocol == IPPROTO_BEETPH)) {
+ struct ip_beet_phdr *ph = (struct ip_beet_phdr*)(iph + 1);
+
+ if (!pskb_may_pull(skb, sizeof(*ph)))
+ goto out;
+
+ phlen = ph->hdrlen * 8;
+ optlen = phlen - ph->padlen - sizeof(*ph);
+ if (optlen < 0 || optlen & 3 || optlen > 250)
+ goto out;
+
+ if (!pskb_may_pull(skb, phlen))
+ goto out;
+
+ ph_nexthdr = ph->nexthdr;
+ }
+
+ skb_push(skb, sizeof(*iph) - phlen + optlen);
+ memmove(skb->data, skb->nh.raw, sizeof(*iph));
+ skb->nh.raw = skb->data;
+
+ iph = skb->nh.iph;
+ iph->ihl = (sizeof(*iph) + optlen) / 4;
+ iph->tot_len = htons(skb->len);
+ iph->daddr = x->sel.daddr.a4;
+ iph->saddr = x->sel.saddr.a4;
+ if (ph_nexthdr)
+ iph->protocol = ph_nexthdr;
+ else
+ iph->protocol = protocol;
+ iph->check = 0;
+ iph->check = ip_fast_csum(skb->nh.raw, iph->ihl);
+ err = 0;
+out:
+ return err;
+}
+
+static struct xfrm_mode xfrm4_beet_mode = {
+ .input = xfrm4_beet_input,
+ .output = xfrm4_beet_output,
+ .owner = THIS_MODULE,
+ .encap = XFRM_MODE_BEET,
+};
+
+static int __init xfrm4_beet_init(void)
+{
+ return xfrm_register_mode(&xfrm4_beet_mode, AF_INET);
+}
+
+static void __exit xfrm4_beet_exit(void)
+{
+ int err;
+
+ err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET);
+ BUG_ON(err);
+}
+
+module_init(xfrm4_beet_init);
+module_exit(xfrm4_beet_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET);
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index eabcd27b1767..1bed0cdf53e3 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -52,7 +52,7 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
xdst->u.rt.fl.fl4_dst == fl->fl4_dst &&
xdst->u.rt.fl.fl4_src == fl->fl4_src &&
xdst->u.rt.fl.fl4_tos == fl->fl4_tos &&
- xfrm_bundle_ok(xdst, fl, AF_INET, 0)) {
+ xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) {
dst_clone(dst);
break;
}
@@ -221,7 +221,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
case IPPROTO_ESP:
if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
- u32 *ehdr = (u32 *)xprth;
+ __be32 *ehdr = (__be32 *)xprth;
fl->fl_ipsec_spi = ehdr[0];
}
@@ -229,7 +229,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
case IPPROTO_AH:
if (pskb_may_pull(skb, xprth + 8 - skb->data)) {
- u32 *ah_hdr = (u32*)xprth;
+ __be32 *ah_hdr = (__be32*)xprth;
fl->fl_ipsec_spi = ah_hdr[1];
}
@@ -237,7 +237,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl)
case IPPROTO_COMP:
if (pskb_may_pull(skb, xprth + 4 - skb->data)) {
- u16 *ipcomp_hdr = (u16 *)xprth;
+ __be16 *ipcomp_hdr = (__be16 *)xprth;
fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1]));
}
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
index fe2034494d08..3cc3df0c6ece 100644
--- a/net/ipv4/xfrm4_state.c
+++ b/net/ipv4/xfrm4_state.c
@@ -29,9 +29,9 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl,
x->sel.daddr.a4 = fl->fl4_dst;
x->sel.saddr.a4 = fl->fl4_src;
x->sel.dport = xfrm_flowi_dport(fl);
- x->sel.dport_mask = ~0;
+ x->sel.dport_mask = htons(0xffff);
x->sel.sport = xfrm_flowi_sport(fl);
- x->sel.sport_mask = ~0;
+ x->sel.sport_mask = htons(0xffff);
x->sel.prefixlen_d = 32;
x->sel.prefixlen_s = 32;
x->sel.proto = fl->proto;
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index a2d211da2aba..6e48f52e197c 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -136,6 +136,16 @@ config INET6_XFRM_MODE_TUNNEL
If unsure, say Y.
+config INET6_XFRM_MODE_BEET
+ tristate "IPv6: IPsec BEET mode"
+ depends on IPV6
+ default IPV6
+ select XFRM
+ ---help---
+ Support for IPsec BEET mode.
+
+ If unsure, say Y.
+
config INET6_XFRM_MODE_ROUTEOPTIMIZATION
tristate "IPv6: MIPv6 route optimization mode (EXPERIMENTAL)"
depends on IPV6 && EXPERIMENTAL
@@ -143,6 +153,19 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION
---help---
Support for MIPv6 route optimization mode.
+config IPV6_SIT
+ tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)"
+ depends on IPV6
+ default y
+ ---help---
+ Tunneling means encapsulating data of one protocol type within
+ another protocol and sending it over a channel that understands the
+ encapsulating protocol. This driver implements encapsulation of IPv6
+ into IPv4 packets. This is useful if you want to connect two IPv6
+ networks over an IPv4-only path.
+
+ Saying M here will produce a module called sit.ko. If unsure, say Y.
+
config IPV6_TUNNEL
tristate "IPv6: IPv6-in-IPv6 tunnel"
select INET6_TUNNEL
@@ -152,9 +175,16 @@ config IPV6_TUNNEL
If unsure, say N.
+config IPV6_MULTIPLE_TABLES
+ bool "IPv6: Multiple Routing Tables"
+ depends on IPV6 && EXPERIMENTAL
+ select FIB_RULES
+ ---help---
+ Support multiple routing tables.
+
config IPV6_SUBTREES
bool "IPv6: source address based routing"
- depends on IPV6 && EXPERIMENTAL
+ depends on IPV6_MULTIPLE_TABLES
---help---
Enable routing by source address or prefix.
@@ -166,13 +196,6 @@ config IPV6_SUBTREES
If unsure, say N.
-config IPV6_MULTIPLE_TABLES
- bool "IPv6: Multiple Routing Tables"
- depends on IPV6 && EXPERIMENTAL
- select FIB_RULES
- ---help---
- Support multiple routing tables.
-
config IPV6_ROUTE_FWMARK
bool "IPv6: use netfilter MARK value as routing key"
depends on IPV6_MULTIPLE_TABLES && NETFILTER
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile
index 0213c6612b58..addcc011bc01 100644
--- a/net/ipv6/Makefile
+++ b/net/ipv6/Makefile
@@ -4,7 +4,7 @@
obj-$(CONFIG_IPV6) += ipv6.o
-ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o sit.o \
+ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \
route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o raw.o \
protocol.o icmp.o mcast.o reassembly.o tcp_ipv6.o \
exthdrs.o sysctl_net_ipv6.o datagram.o proc.o \
@@ -26,8 +26,10 @@ obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o
+obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o
obj-$(CONFIG_NETFILTER) += netfilter/
+obj-$(CONFIG_IPV6_SIT) += sit.o
obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o
obj-y += exthdrs_core.o
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index c18676352397..b312a5f7a759 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -396,8 +396,10 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
ndev->regen_timer.data = (unsigned long) ndev;
if ((dev->flags&IFF_LOOPBACK) ||
dev->type == ARPHRD_TUNNEL ||
- dev->type == ARPHRD_NONE ||
- dev->type == ARPHRD_SIT) {
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
+ dev->type == ARPHRD_SIT ||
+#endif
+ dev->type == ARPHRD_NONE) {
printk(KERN_INFO
"%s: Disabled Privacy Extensions\n",
dev->name);
@@ -1258,8 +1260,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
{
const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
- u32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
- u32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+ __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr;
+ __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
int sk_ipv6only = ipv6_only_sock(sk);
int sk2_ipv6only = inet_v6_ipv6only(sk2);
int addr_type = ipv6_addr_type(sk_rcv_saddr6);
@@ -1546,8 +1548,10 @@ addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev,
This thing is done here expecting that the whole
class of non-broadcast devices need not cloning.
*/
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT))
cfg.fc_flags |= RTF_NONEXTHOP;
+#endif
ip6_route_add(&cfg);
}
@@ -1569,6 +1573,7 @@ static void addrconf_add_mroute(struct net_device *dev)
ip6_route_add(&cfg);
}
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
static void sit_route_add(struct net_device *dev)
{
struct fib6_config cfg = {
@@ -1582,6 +1587,7 @@ static void sit_route_add(struct net_device *dev)
/* prefix length - 96 bits "::d.d.d.d" */
ip6_route_add(&cfg);
}
+#endif
static void addrconf_add_lroute(struct net_device *dev)
{
@@ -1852,6 +1858,7 @@ int addrconf_set_dstaddr(void __user *arg)
if (dev == NULL)
goto err_exit;
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
if (dev->type == ARPHRD_SIT) {
struct ifreq ifr;
mm_segment_t oldfs;
@@ -1881,6 +1888,7 @@ int addrconf_set_dstaddr(void __user *arg)
err = dev_open(dev);
}
}
+#endif
err_exit:
rtnl_unlock();
@@ -2010,6 +2018,7 @@ int addrconf_del_ifaddr(void __user *arg)
return err;
}
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
static void sit_add_v4_addrs(struct inet6_dev *idev)
{
struct inet6_ifaddr * ifp;
@@ -2078,6 +2087,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
}
}
}
+#endif
static void init_loopback(struct net_device *dev)
{
@@ -2141,6 +2151,7 @@ static void addrconf_dev_config(struct net_device *dev)
addrconf_add_linklocal(idev, &addr);
}
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
static void addrconf_sit_config(struct net_device *dev)
{
struct inet6_dev *idev;
@@ -2166,6 +2177,7 @@ static void addrconf_sit_config(struct net_device *dev)
} else
sit_route_add(dev);
}
+#endif
static inline int
ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
@@ -2260,9 +2272,11 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
}
switch(dev->type) {
+#if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
case ARPHRD_SIT:
addrconf_sit_config(dev);
break;
+#endif
case ARPHRD_TUNNEL6:
addrconf_ip6_tnl_config(dev);
break;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index bf6e8aff19d4..858cae29581c 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -246,7 +246,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
struct sock *sk = sock->sk;
struct inet_sock *inet = inet_sk(sk);
struct ipv6_pinfo *np = inet6_sk(sk);
- __u32 v4addr = 0;
+ __be32 v4addr = 0;
unsigned short snum;
int addr_type = 0;
int err = 0;
@@ -850,7 +850,6 @@ static int __init inet6_init(void)
err = addrconf_init();
if (err)
goto addrconf_fail;
- sit_init();
/* Init v6 extension headers. */
ipv6_rthdr_init();
@@ -927,7 +926,6 @@ static void __exit inet6_exit(void)
mip6_fini();
#endif
/* Cleanup code parts. */
- sit_cleanup();
ip6_flowlabel_cleanup();
addrconf_cleanup();
ip6_route_cleanup();
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 34f5bfaddfc2..1896ecb52899 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -13,7 +13,6 @@
* Ville Nuorvala <vnuorval@tcs.hut.fi>
*/
-#include <linux/config.h>
#include <linux/netdevice.h>
#include <net/fib_rules.h>
@@ -118,12 +117,15 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
{
struct fib6_rule *r = (struct fib6_rule *) rule;
- if (!ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
+ if (r->dst.plen &&
+ !ipv6_prefix_equal(&fl->fl6_dst, &r->dst.addr, r->dst.plen))
return 0;
- if ((flags & RT6_LOOKUP_F_HAS_SADDR) &&
- !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
- return 0;
+ if (r->src.plen) {
+ if (!(flags & RT6_LOOKUP_F_HAS_SADDR) ||
+ !ipv6_prefix_equal(&fl->fl6_src, &r->src.addr, r->src.plen))
+ return 0;
+ }
if (r->tclass && r->tclass != ((ntohl(fl->fl6_flowlabel) >> 20) & 0xff))
return 0;
diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c
index d2f3fc990bfa..8accd1fbeeda 100644
--- a/net/ipv6/inet6_hashtables.c
+++ b/net/ipv6/inet6_hashtables.c
@@ -64,7 +64,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
{
struct sock *sk;
const struct hlist_node *node;
- const __u32 ports = INET_COMBINED_PORTS(sport, hnum);
+ const __portpair ports = INET_COMBINED_PORTS(sport, hnum);
/* Optimize here for direct hit, only listening connections can
* have wildcards anyways.
*/
@@ -82,7 +82,7 @@ struct sock *__inet6_lookup_established(struct inet_hashinfo *hashinfo,
sk_for_each(sk, node, &(head + hashinfo->ehash_size)->chain) {
const struct inet_timewait_sock *tw = inet_twsk(sk);
- if(*((__u32 *)&(tw->tw_dport)) == ports &&
+ if(*((__portpair *)&(tw->tw_dport)) == ports &&
sk->sk_family == PF_INET6) {
const struct inet6_timewait_sock *tw6 = inet6_twsk(sk);
@@ -171,7 +171,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
const struct in6_addr *daddr = &np->rcv_saddr;
const struct in6_addr *saddr = &np->daddr;
const int dif = sk->sk_bound_dev_if;
- const u32 ports = INET_COMBINED_PORTS(inet->dport, lport);
+ const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport);
const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr,
inet->dport);
struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash);
@@ -188,7 +188,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row,
tw = inet_twsk(sk2);
- if(*((__u32 *)&(tw->tw_dport)) == ports &&
+ if(*((__portpair *)&(tw->tw_dport)) == ports &&
sk2->sk_family == PF_INET6 &&
ipv6_addr_equal(&tw6->tw_v6_daddr, saddr) &&
ipv6_addr_equal(&tw6->tw_v6_rcv_saddr, daddr) &&
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
index ad9c6e824e62..71f59f18ede8 100644
--- a/net/ipv6/ipcomp6.c
+++ b/net/ipv6/ipcomp6.c
@@ -178,7 +178,7 @@ out_ok:
static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
{
- u32 spi;
+ __be32 spi;
struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset);
struct xfrm_state *x;
@@ -199,6 +199,7 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
{
struct xfrm_state *t = NULL;
+ u8 mode = XFRM_MODE_TUNNEL;
t = xfrm_state_alloc();
if (!t)
@@ -212,7 +213,9 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x)
memcpy(t->id.daddr.a6, x->id.daddr.a6, sizeof(struct in6_addr));
memcpy(&t->sel, &x->sel, sizeof(t->sel));
t->props.family = AF_INET6;
- t->props.mode = XFRM_MODE_TUNNEL;
+ if (x->props.mode == XFRM_MODE_BEET)
+ mode = x->props.mode;
+ t->props.mode = mode;
memcpy(t->props.saddr.a6, x->props.saddr.a6, sizeof(struct in6_addr));
if (xfrm_init_state(t))
@@ -234,7 +237,7 @@ static int ipcomp6_tunnel_attach(struct xfrm_state *x)
{
int err = 0;
struct xfrm_state *t = NULL;
- u32 spi;
+ __be32 spi;
spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr);
if (spi)
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 4f3bb7fcc8b5..de6b91981b30 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -123,6 +123,9 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, int features)
struct ipv6hdr *ipv6h;
struct inet6_protocol *ops;
+ if (!(features & NETIF_F_HW_CSUM))
+ features &= ~NETIF_F_SG;
+
if (unlikely(skb_shinfo(skb)->gso_type &
~(SKB_GSO_UDP |
SKB_GSO_DODGY |
diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c
index 99d116caecda..7ccdc8fc5a31 100644
--- a/net/ipv6/mip6.c
+++ b/net/ipv6/mip6.c
@@ -22,7 +22,6 @@
* Masahide NAKAMURA @USAGI
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/time.h>
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 0304b5fe8d6a..41a8a5f06602 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -967,8 +967,6 @@ static void ndisc_recv_na(struct sk_buff *skb)
ipv6_devconf.forwarding && ipv6_devconf.proxy_ndp &&
pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
/* XXX: idev->cnf.prixy_ndp */
- WARN_ON(skb->dst != NULL &&
- ((struct rt6_info *)skb->dst)->rt6i_idev);
goto out;
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d6b4b4f48d18..c953466b7afd 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -141,6 +141,10 @@ struct rt6_info ip6_null_entry = {
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+static int ip6_pkt_prohibit(struct sk_buff *skb);
+static int ip6_pkt_prohibit_out(struct sk_buff *skb);
+static int ip6_pkt_blk_hole(struct sk_buff *skb);
+
struct rt6_info ip6_prohibit_entry = {
.u = {
.dst = {
@@ -150,8 +154,8 @@ struct rt6_info ip6_prohibit_entry = {
.obsolete = -1,
.error = -EACCES,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_discard,
- .output = ip6_pkt_discard_out,
+ .input = ip6_pkt_prohibit,
+ .output = ip6_pkt_prohibit_out,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_prohibit_entry,
}
@@ -170,8 +174,8 @@ struct rt6_info ip6_blk_hole_entry = {
.obsolete = -1,
.error = -EINVAL,
.metrics = { [RTAX_HOPLIMIT - 1] = 255, },
- .input = ip6_pkt_discard,
- .output = ip6_pkt_discard_out,
+ .input = ip6_pkt_blk_hole,
+ .output = ip6_pkt_blk_hole,
.ops = &ip6_dst_ops,
.path = (struct dst_entry*)&ip6_blk_hole_entry,
}
@@ -484,7 +488,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
do { \
if (rt == &ip6_null_entry) { \
struct fib6_node *pn; \
- while (fn) { \
+ while (1) { \
if (fn->fn_flags & RTN_TL_ROOT) \
goto out; \
pn = fn->parent; \
@@ -529,13 +533,17 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
.nl_u = {
.ip6_u = {
.daddr = *daddr,
- /* TODO: saddr */
},
},
};
struct dst_entry *dst;
int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
+ if (saddr) {
+ memcpy(&fl.fl6_src, saddr, sizeof(*saddr));
+ flags |= RT6_LOOKUP_F_HAS_SADDR;
+ }
+
dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
if (dst->error == 0)
return (struct rt6_info *) dst;
@@ -614,8 +622,6 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
rt->rt6i_dst.plen = 128;
rt->rt6i_flags |= RTF_CACHE;
- if (rt->rt6i_flags & RTF_REJECT)
- rt->u.dst.error = ort->u.dst.error;
rt->u.dst.flags |= DST_HOST;
rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
}
@@ -697,6 +703,7 @@ out2:
void ip6_route_input(struct sk_buff *skb)
{
struct ipv6hdr *iph = skb->nh.ipv6h;
+ int flags = RT6_LOOKUP_F_HAS_SADDR;
struct flowi fl = {
.iif = skb->dev->ifindex,
.nl_u = {
@@ -711,7 +718,9 @@ void ip6_route_input(struct sk_buff *skb)
},
.proto = iph->nexthdr,
};
- int flags = rt6_need_strict(&iph->daddr) ? RT6_LOOKUP_F_IFACE : 0;
+
+ if (rt6_need_strict(&iph->daddr))
+ flags |= RT6_LOOKUP_F_IFACE;
skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
}
@@ -794,6 +803,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
if (rt6_need_strict(&fl->fl6_dst))
flags |= RT6_LOOKUP_F_IFACE;
+ if (!ipv6_addr_any(&fl->fl6_src))
+ flags |= RT6_LOOKUP_F_HAS_SADDR;
+
return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
}
@@ -1345,6 +1357,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
struct in6_addr *gateway,
struct net_device *dev)
{
+ int flags = RT6_LOOKUP_F_HAS_SADDR;
struct ip6rd_flowi rdfl = {
.fl = {
.oif = dev->ifindex,
@@ -1357,7 +1370,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
},
.gateway = *gateway,
};
- int flags = rt6_need_strict(dest) ? RT6_LOOKUP_F_IFACE : 0;
+
+ if (rt6_need_strict(dest))
+ flags |= RT6_LOOKUP_F_IFACE;
return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
}
@@ -1527,6 +1542,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
rt->u.dst.output = ort->u.dst.output;
memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
+ rt->u.dst.error = ort->u.dst.error;
rt->u.dst.dev = ort->u.dst.dev;
if (rt->u.dst.dev)
dev_hold(rt->u.dst.dev);
@@ -1730,24 +1746,50 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
* Drop the packet on the floor
*/
-static int ip6_pkt_discard(struct sk_buff *skb)
+static inline int ip6_pkt_drop(struct sk_buff *skb, int code)
{
int type = ipv6_addr_type(&skb->nh.ipv6h->daddr);
if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED)
IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS);
IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
- icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
+ icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev);
kfree_skb(skb);
return 0;
}
+static int ip6_pkt_discard(struct sk_buff *skb)
+{
+ return ip6_pkt_drop(skb, ICMPV6_NOROUTE);
+}
+
static int ip6_pkt_discard_out(struct sk_buff *skb)
{
skb->dev = skb->dst->dev;
return ip6_pkt_discard(skb);
}
+#ifdef CONFIG_IPV6_MULTIPLE_TABLES
+
+static int ip6_pkt_prohibit(struct sk_buff *skb)
+{
+ return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED);
+}
+
+static int ip6_pkt_prohibit_out(struct sk_buff *skb)
+{
+ skb->dev = skb->dst->dev;
+ return ip6_pkt_prohibit(skb);
+}
+
+static int ip6_pkt_blk_hole(struct sk_buff *skb)
+{
+ kfree_skb(skb);
+ return 0;
+}
+
+#endif
+
/*
* Allocate a dst for local (unicast / anycast) address.
*/
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index 836eecd7e62b..b481a4d780c2 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -850,3 +850,7 @@ int __init sit_init(void)
inet_del_protocol(&sit_protocol, IPPROTO_IPV6);
goto out;
}
+
+module_init(sit_init);
+module_exit(sit_cleanup);
+MODULE_LICENSE("GPL");
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2546fc9f0a78..4c2a7c0cafef 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -329,7 +329,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
}
if (sk->sk_state == TCP_TIME_WAIT) {
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
return;
}
@@ -653,7 +653,7 @@ static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32
int tot_len = sizeof(struct tcphdr);
if (ts)
- tot_len += 3*4;
+ tot_len += TCPOLEN_TSTAMP_ALIGNED;
buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len,
GFP_ATOMIC);
@@ -749,7 +749,7 @@ static struct sock *tcp_v6_hnd_req(struct sock *sk,struct sk_buff *skb)
bh_lock_sock(nsk);
return nsk;
}
- inet_twsk_put((struct inet_timewait_sock *)nsk);
+ inet_twsk_put(inet_twsk(nsk));
return NULL;
}
@@ -1237,7 +1237,7 @@ process:
skb->dev = NULL;
- bh_lock_sock(sk);
+ bh_lock_sock_nested(sk);
ret = 0;
if (!sock_owned_by_user(sk)) {
#ifdef CONFIG_NET_DMA
@@ -1283,18 +1283,17 @@ discard_and_relse:
do_time_wait:
if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(TCP_MIB_INERRS);
- inet_twsk_put((struct inet_timewait_sock *)sk);
+ inet_twsk_put(inet_twsk(sk));
goto discard_it;
}
- switch (tcp_timewait_state_process((struct inet_timewait_sock *)sk,
- skb, th)) {
+ switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) {
case TCP_TW_SYN:
{
struct sock *sk2;
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 9662561701d1..e0c3934a7e4b 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -546,7 +546,7 @@ static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk,
struct in6_addr *daddr, *final_p = NULL, final;
struct ipv6_txoptions *opt = NULL;
struct ip6_flowlabel *flowlabel = NULL;
- struct flowi *fl = &inet->cork.fl;
+ struct flowi fl;
struct dst_entry *dst;
int addr_len = msg->msg_namelen;
int ulen = len;
@@ -626,19 +626,19 @@ do_udp_sendmsg:
}
ulen += sizeof(struct udphdr);
- memset(fl, 0, sizeof(*fl));
+ memset(&fl, 0, sizeof(fl));
if (sin6) {
if (sin6->sin6_port == 0)
return -EINVAL;
- fl->fl_ip_dport = sin6->sin6_port;
+ fl.fl_ip_dport = sin6->sin6_port;
daddr = &sin6->sin6_addr;
if (np->sndflow) {
- fl->fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
- if (fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
- flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
+ fl.fl6_flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK;
+ if (fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
if (flowlabel == NULL)
return -EINVAL;
daddr = &flowlabel->dst;
@@ -656,32 +656,32 @@ do_udp_sendmsg:
if (addr_len >= sizeof(struct sockaddr_in6) &&
sin6->sin6_scope_id &&
ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
- fl->oif = sin6->sin6_scope_id;
+ fl.oif = sin6->sin6_scope_id;
} else {
if (sk->sk_state != TCP_ESTABLISHED)
return -EDESTADDRREQ;
- fl->fl_ip_dport = inet->dport;
+ fl.fl_ip_dport = inet->dport;
daddr = &np->daddr;
- fl->fl6_flowlabel = np->flow_label;
+ fl.fl6_flowlabel = np->flow_label;
connected = 1;
}
- if (!fl->oif)
- fl->oif = sk->sk_bound_dev_if;
+ if (!fl.oif)
+ fl.oif = sk->sk_bound_dev_if;
if (msg->msg_controllen) {
opt = &opt_space;
memset(opt, 0, sizeof(struct ipv6_txoptions));
opt->tot_len = sizeof(*opt);
- err = datagram_send_ctl(msg, fl, opt, &hlimit, &tclass);
+ err = datagram_send_ctl(msg, &fl, opt, &hlimit, &tclass);
if (err < 0) {
fl6_sock_release(flowlabel);
return err;
}
- if ((fl->fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
- flowlabel = fl6_sock_lookup(sk, fl->fl6_flowlabel);
+ if ((fl.fl6_flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) {
+ flowlabel = fl6_sock_lookup(sk, fl.fl6_flowlabel);
if (flowlabel == NULL)
return -EINVAL;
}
@@ -695,39 +695,39 @@ do_udp_sendmsg:
opt = fl6_merge_options(&opt_space, flowlabel, opt);
opt = ipv6_fixup_options(&opt_space, opt);
- fl->proto = IPPROTO_UDP;
- ipv6_addr_copy(&fl->fl6_dst, daddr);
- if (ipv6_addr_any(&fl->fl6_src) && !ipv6_addr_any(&np->saddr))
- ipv6_addr_copy(&fl->fl6_src, &np->saddr);
- fl->fl_ip_sport = inet->sport;
+ fl.proto = IPPROTO_UDP;
+ ipv6_addr_copy(&fl.fl6_dst, daddr);
+ if (ipv6_addr_any(&fl.fl6_src) && !ipv6_addr_any(&np->saddr))
+ ipv6_addr_copy(&fl.fl6_src, &np->saddr);
+ fl.fl_ip_sport = inet->sport;
/* merge ip6_build_xmit from ip6_output */
if (opt && opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
- ipv6_addr_copy(&final, &fl->fl6_dst);
- ipv6_addr_copy(&fl->fl6_dst, rt0->addr);
+ ipv6_addr_copy(&final, &fl.fl6_dst);
+ ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
final_p = &final;
connected = 0;
}
- if (!fl->oif && ipv6_addr_is_multicast(&fl->fl6_dst)) {
- fl->oif = np->mcast_oif;
+ if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst)) {
+ fl.oif = np->mcast_oif;
connected = 0;
}
- security_sk_classify_flow(sk, fl);
+ security_sk_classify_flow(sk, &fl);
- err = ip6_sk_dst_lookup(sk, &dst, fl);
+ err = ip6_sk_dst_lookup(sk, &dst, &fl);
if (err)
goto out;
if (final_p)
- ipv6_addr_copy(&fl->fl6_dst, final_p);
+ ipv6_addr_copy(&fl.fl6_dst, final_p);
- if ((err = xfrm_lookup(&dst, fl, sk, 0)) < 0)
+ if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0)
goto out;
if (hlimit < 0) {
- if (ipv6_addr_is_multicast(&fl->fl6_dst))
+ if (ipv6_addr_is_multicast(&fl.fl6_dst))
hlimit = np->mcast_hops;
else
hlimit = np->hop_limit;
@@ -763,21 +763,23 @@ back_from_confirm:
do_append_data:
up->len += ulen;
err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen,
- sizeof(struct udphdr), hlimit, tclass, opt, fl,
+ sizeof(struct udphdr), hlimit, tclass, opt, &fl,
(struct rt6_info*)dst,
corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
if (err)
udp_v6_flush_pending_frames(sk);
else if (!corkreq)
err = udp_v6_push_pending_frames(sk, up);
+ else if (unlikely(skb_queue_empty(&sk->sk_write_queue)))
+ up->pending = 0;
if (dst) {
if (connected) {
ip6_dst_store(sk, dst,
- ipv6_addr_equal(&fl->fl6_dst, &np->daddr) ?
+ ipv6_addr_equal(&fl.fl6_dst, &np->daddr) ?
&np->daddr : NULL,
#ifdef CONFIG_IPV6_SUBTREES
- ipv6_addr_equal(&fl->fl6_src, &np->saddr) ?
+ ipv6_addr_equal(&fl.fl6_src, &np->saddr) ?
&np->saddr :
#endif
NULL);
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c
index a40a05789013..5c8b7a568800 100644
--- a/net/ipv6/xfrm6_input.c
+++ b/net/ipv6/xfrm6_input.c
@@ -16,10 +16,10 @@
#include <net/ipv6.h>
#include <net/xfrm.h>
-int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi)
+int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi)
{
int err;
- u32 seq;
+ __be32 seq;
struct xfrm_state *xfrm_vec[XFRM_MAX_DEPTH];
struct xfrm_state *x;
int xfrm_nr = 0;
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
new file mode 100644
index 000000000000..edcfffa9e87b
--- /dev/null
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -0,0 +1,107 @@
+/*
+ * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6.
+ *
+ * Copyright (c) 2006 Diego Beltrami <diego.beltrami@gmail.com>
+ * Miika Komu <miika@iki.fi>
+ * Herbert Xu <herbert@gondor.apana.org.au>
+ * Abhinav Pathak <abhinav.pathak@hiit.fi>
+ * Jeff Ahrenholz <ahrenholz@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stringify.h>
+#include <net/dsfield.h>
+#include <net/dst.h>
+#include <net/inet_ecn.h>
+#include <net/ipv6.h>
+#include <net/xfrm.h>
+
+/* Add encapsulation header.
+ *
+ * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt.
+ * The following fields in it shall be filled in by x->type->output:
+ * payload_len
+ *
+ * On exit, skb->h will be set to the start of the encapsulation header to be
+ * filled in by x->type->output and skb->nh will be set to the nextheader field
+ * of the extension header directly preceding the encapsulation header, or in
+ * its absence, that of the top IP header. The value of skb->data will always
+ * point to the top IP header.
+ */
+static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ipv6hdr *iph, *top_iph;
+ u8 *prevhdr;
+ int hdr_len;
+
+ skb_push(skb, x->props.header_len);
+ iph = skb->nh.ipv6h;
+
+ hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
+ skb->nh.raw = prevhdr - x->props.header_len;
+ skb->h.raw = skb->data + hdr_len;
+ memmove(skb->data, iph, hdr_len);
+
+ skb->nh.raw = skb->data;
+ top_iph = skb->nh.ipv6h;
+ skb->nh.raw = &top_iph->nexthdr;
+ skb->h.ipv6h = top_iph + 1;
+
+ ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
+ ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
+
+ return 0;
+}
+
+static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+ struct ipv6hdr *ip6h;
+ int size = sizeof(struct ipv6hdr);
+ int err = -EINVAL;
+
+ if (!pskb_may_pull(skb, sizeof(struct ipv6hdr)))
+ goto out;
+
+ skb_push(skb, size);
+ memmove(skb->data, skb->nh.raw, size);
+ skb->nh.raw = skb->data;
+
+ skb->mac.raw = memmove(skb->data - skb->mac_len,
+ skb->mac.raw, skb->mac_len);
+
+ ip6h = skb->nh.ipv6h;
+ ip6h->payload_len = htons(skb->len - size);
+ ipv6_addr_copy(&ip6h->daddr, (struct in6_addr *) &x->sel.daddr.a6);
+ ipv6_addr_copy(&ip6h->saddr, (struct in6_addr *) &x->sel.saddr.a6);
+ err = 0;
+out:
+ return err;
+}
+
+static struct xfrm_mode xfrm6_beet_mode = {
+ .input = xfrm6_beet_input,
+ .output = xfrm6_beet_output,
+ .owner = THIS_MODULE,
+ .encap = XFRM_MODE_BEET,
+};
+
+static int __init xfrm6_beet_init(void)
+{
+ return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6);
+}
+
+static void __exit xfrm6_beet_exit(void)
+{
+ int err;
+
+ err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6);
+ BUG_ON(err);
+}
+
+module_init(xfrm6_beet_init);
+module_exit(xfrm6_beet_exit);
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET);
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
index 6a252e2134d1..d400f8fae129 100644
--- a/net/ipv6/xfrm6_policy.c
+++ b/net/ipv6/xfrm6_policy.c
@@ -25,12 +25,14 @@
static struct dst_ops xfrm6_dst_ops;
static struct xfrm_policy_afinfo xfrm6_policy_afinfo;
-static int xfrm6_dst_lookup(struct xfrm_dst **dst, struct flowi *fl)
+static int xfrm6_dst_lookup(struct xfrm_dst **xdst, struct flowi *fl)
{
- int err = 0;
- *dst = (struct xfrm_dst*)ip6_route_output(NULL, fl);
- if (!*dst)
- err = -ENETUNREACH;
+ struct dst_entry *dst = ip6_route_output(NULL, fl);
+ int err = dst->error;
+ if (!err)
+ *xdst = (struct xfrm_dst *) dst;
+ else
+ dst_release(dst);
return err;
}
@@ -73,7 +75,7 @@ __xfrm6_find_bundle(struct flowi *fl, struct xfrm_policy *policy)
xdst->u.rt6.rt6i_src.plen);
if (ipv6_addr_equal(&xdst->u.rt6.rt6i_dst.addr, &fl_dst_prefix) &&
ipv6_addr_equal(&xdst->u.rt6.rt6i_src.addr, &fl_src_prefix) &&
- xfrm_bundle_ok(xdst, fl, AF_INET6,
+ xfrm_bundle_ok(policy, xdst, fl, AF_INET6,
(xdst->u.rt6.rt6i_dst.plen != 128 ||
xdst->u.rt6.rt6i_src.plen != 128))) {
dst_clone(dst);
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index 711bfafb2472..9ddaa9d41539 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -29,9 +29,9 @@ __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl,
ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, &fl->fl6_dst);
ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, &fl->fl6_src);
x->sel.dport = xfrm_flowi_dport(fl);
- x->sel.dport_mask = ~0;
+ x->sel.dport_mask = htons(0xffff);
x->sel.sport = xfrm_flowi_sport(fl);
- x->sel.sport_mask = ~0;
+ x->sel.sport_mask = htons(0xffff);
x->sel.prefixlen_d = 128;
x->sel.prefixlen_s = 128;
x->sel.proto = fl->proto;
diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c
index 59685ee8f700..7af227bb1551 100644
--- a/net/ipv6/xfrm6_tunnel.c
+++ b/net/ipv6/xfrm6_tunnel.c
@@ -258,7 +258,7 @@ static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb)
static int xfrm6_tunnel_rcv(struct sk_buff *skb)
{
struct ipv6hdr *iph = skb->nh.ipv6h;
- u32 spi;
+ __be32 spi;
spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&iph->saddr);
return xfrm6_rcv_spi(skb, spi);
diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c
index 17699eeb64d7..7e1aea89ef05 100644
--- a/net/irda/af_irda.c
+++ b/net/irda/af_irda.c
@@ -132,13 +132,14 @@ static void irda_disconnect_indication(void *instance, void *sap,
/* Prevent race conditions with irda_release() and irda_shutdown() */
if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) {
+ lock_sock(sk);
sk->sk_state = TCP_CLOSE;
sk->sk_err = ECONNRESET;
sk->sk_shutdown |= SEND_SHUTDOWN;
sk->sk_state_change(sk);
- /* Uh-oh... Should use sock_orphan ? */
- sock_set_flag(sk, SOCK_DEAD);
+ sock_orphan(sk);
+ release_sock(sk);
/* Close our TSAP.
* If we leave it open, IrLMP put it back into the list of
@@ -308,7 +309,8 @@ static void irda_connect_response(struct irda_sock *self)
IRDA_ASSERT(self != NULL, return;);
- skb = alloc_skb(64, GFP_ATOMIC);
+ skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
+ GFP_ATOMIC);
if (skb == NULL) {
IRDA_DEBUG(0, "%s() Unable to allocate sk_buff!\n",
__FUNCTION__);
@@ -1212,6 +1214,7 @@ static int irda_release(struct socket *sock)
if (sk == NULL)
return 0;
+ lock_sock(sk);
sk->sk_state = TCP_CLOSE;
sk->sk_shutdown |= SEND_SHUTDOWN;
sk->sk_state_change(sk);
@@ -1221,6 +1224,7 @@ static int irda_release(struct socket *sock)
sock_orphan(sk);
sock->sk = NULL;
+ release_sock(sk);
/* Purge queues (see sock_init_data()) */
skb_queue_purge(&sk->sk_receive_queue);
@@ -1353,6 +1357,7 @@ static int irda_recvmsg_dgram(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(4, "%s()\n", __FUNCTION__);
IRDA_ASSERT(self != NULL, return -1;);
+ IRDA_ASSERT(!sock_error(sk), return -1;);
skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,
flags & MSG_DONTWAIT, &err);
@@ -1405,6 +1410,7 @@ static int irda_recvmsg_stream(struct kiocb *iocb, struct socket *sock,
IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
IRDA_ASSERT(self != NULL, return -1;);
+ IRDA_ASSERT(!sock_error(sk), return -1;);
if (sock->flags & __SO_ACCEPTCON)
return(-EINVAL);
diff --git a/net/irda/ircomm/ircomm_lmp.c b/net/irda/ircomm/ircomm_lmp.c
index 959874b6451f..c8e0d89ee11f 100644
--- a/net/irda/ircomm/ircomm_lmp.c
+++ b/net/irda/ircomm/ircomm_lmp.c
@@ -81,7 +81,7 @@ static int ircomm_lmp_connect_response(struct ircomm_cb *self,
/* Any userdata supplied? */
if (userdata == NULL) {
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (!tx_skb)
return -ENOMEM;
@@ -115,7 +115,7 @@ static int ircomm_lmp_disconnect_request(struct ircomm_cb *self,
IRDA_DEBUG(0, "%s()\n", __FUNCTION__ );
if (!userdata) {
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (!tx_skb)
return -ENOMEM;
diff --git a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c
index 3bcdb467efc5..d50a02030ad7 100644
--- a/net/irda/ircomm/ircomm_tty.c
+++ b/net/irda/ircomm/ircomm_tty.c
@@ -79,7 +79,7 @@ static struct tty_driver *driver;
hashbin_t *ircomm_tty = NULL;
-static struct tty_operations ops = {
+static const struct tty_operations ops = {
.open = ircomm_tty_open,
.close = ircomm_tty_close,
.write = ircomm_tty_write,
diff --git a/net/irda/iriap.c b/net/irda/iriap.c
index 61128aa05b40..415cf4eec23b 100644
--- a/net/irda/iriap.c
+++ b/net/irda/iriap.c
@@ -345,10 +345,11 @@ static void iriap_disconnect_request(struct iriap_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (tx_skb == NULL) {
- IRDA_DEBUG(0, "%s(), Could not allocate an sk_buff of length %d\n",
- __FUNCTION__, 64);
+ IRDA_DEBUG(0,
+ "%s(), Could not allocate an sk_buff of length %d\n",
+ __FUNCTION__, LMP_MAX_HEADER);
return;
}
@@ -701,7 +702,7 @@ void iriap_send_ack(struct iriap_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IAS_MAGIC, return;);
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(LMP_MAX_HEADER + 1, GFP_ATOMIC);
if (!tx_skb)
return;
diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c
index da17395df05a..99b18dc7a0b7 100644
--- a/net/irda/iriap_event.c
+++ b/net/irda/iriap_event.c
@@ -365,7 +365,7 @@ static void state_r_disconnect(struct iriap_cb *self, IRIAP_EVENT event,
switch (event) {
case IAP_LM_CONNECT_INDICATION:
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (tx_skb == NULL) {
IRDA_WARNING("%s: unable to malloc!\n", __FUNCTION__);
return;
diff --git a/net/irda/irias_object.c b/net/irda/irias_object.c
index a154b1d71c0f..56292ab7d652 100644
--- a/net/irda/irias_object.c
+++ b/net/irda/irias_object.c
@@ -43,7 +43,7 @@ struct ias_value irias_missing = { IAS_MISSING, 0, 0, 0, {0}};
*
* Faster, check boundary... Jean II
*/
-static char *strndup(char *str, int max)
+static char *strndup(char *str, size_t max)
{
char *new_str;
int len;
diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c
index 7dd0a2fe1d20..9b962f247714 100644
--- a/net/irda/irlan/irlan_common.c
+++ b/net/irda/irlan/irlan_common.c
@@ -636,7 +636,8 @@ void irlan_get_provider_info(struct irlan_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(64, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER,
+ GFP_ATOMIC);
if (!skb)
return;
@@ -668,7 +669,10 @@ void irlan_open_data_channel(struct irlan_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(64, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3") +
+ IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "DIRECT"),
+ GFP_ATOMIC);
if (!skb)
return;
@@ -704,7 +708,9 @@ void irlan_close_data_channel(struct irlan_cb *self)
if (self->client.tsap_ctrl == NULL)
return;
- skb = alloc_skb(64, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN"),
+ GFP_ATOMIC);
if (!skb)
return;
@@ -715,7 +721,7 @@ void irlan_close_data_channel(struct irlan_cb *self)
/* Build frame */
frame[0] = CMD_CLOSE_DATA_CHAN;
- frame[1] = 0x01; /* Two parameters */
+ frame[1] = 0x01; /* One parameter */
irlan_insert_byte_param(skb, "DATA_CHAN", self->dtsap_sel_data);
@@ -739,7 +745,11 @@ static void irlan_open_unicast_addr(struct irlan_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(128, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
+ GFP_ATOMIC);
if (!skb)
return;
@@ -777,7 +787,12 @@ void irlan_set_broadcast_filter(struct irlan_cb *self, int status)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(128, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BROADCAST") +
+ /* We may waste one byte here...*/
+ IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "FILTER"),
+ GFP_ATOMIC);
if (!skb)
return;
@@ -816,7 +831,12 @@ void irlan_set_multicast_filter(struct irlan_cb *self, int status)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(128, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
+ /* We may waste one byte here...*/
+ IRLAN_STRING_PARAMETER_LEN("FILTER_MODE", "NONE"),
+ GFP_ATOMIC);
if (!skb)
return;
@@ -856,7 +876,12 @@ static void irlan_get_unicast_addr(struct irlan_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(128, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ IRLAN_BYTE_PARAMETER_LEN("DATA_CHAN") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_OPERATION",
+ "DYNAMIC"),
+ GFP_ATOMIC);
if (!skb)
return;
@@ -891,7 +916,10 @@ void irlan_get_media_char(struct irlan_cb *self)
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(64, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ IRLAN_STRING_PARAMETER_LEN("MEDIA", "802.3"),
+ GFP_ATOMIC);
+
if (!skb)
return;
diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c
index 9c0df86044d7..58efde919667 100644
--- a/net/irda/irlan/irlan_provider.c
+++ b/net/irda/irlan/irlan_provider.c
@@ -296,7 +296,14 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == IRLAN_MAGIC, return;);
- skb = alloc_skb(128, GFP_ATOMIC);
+ skb = alloc_skb(IRLAN_MAX_HEADER + IRLAN_CMD_HEADER +
+ /* Bigger param length comes from CMD_GET_MEDIA_CHAR */
+ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "DIRECTED") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "BORADCAST") +
+ IRLAN_STRING_PARAMETER_LEN("FILTER_TYPE", "MULTICAST") +
+ IRLAN_STRING_PARAMETER_LEN("ACCESS_TYPE", "HOSTED"),
+ GFP_ATOMIC);
+
if (!skb)
return;
@@ -354,8 +361,7 @@ void irlan_provider_send_reply(struct irlan_cb *self, int command,
} else
skb->data[1] = 0x02; /* 2 parameters */
irlan_insert_byte_param(skb, "DATA_CHAN", self->stsap_sel_data);
- irlan_insert_array_param(skb, "RECONNECT_KEY", "LINUX RULES!",
- 12);
+ irlan_insert_string_param(skb, "RECONNECT_KEY", "LINUX RULES!");
break;
case CMD_FILTER_OPERATION:
irlan_filter_request(self, skb);
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index ccb983bf0f4a..dba349c832d0 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -117,7 +117,9 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
/* Allocate frame */
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(sizeof(struct snrm_frame) +
+ IRLAP_NEGOCIATION_PARAMS_LEN,
+ GFP_ATOMIC);
if (!tx_skb)
return;
@@ -136,7 +138,7 @@ void irlap_send_snrm_frame(struct irlap_cb *self, struct qos_info *qos)
* If we are establishing a connection then insert QoS paramerters
*/
if (qos) {
- skb_put(tx_skb, 9); /* 21 left */
+ skb_put(tx_skb, 9); /* 25 left */
frame->saddr = cpu_to_le32(self->saddr);
frame->daddr = cpu_to_le32(self->daddr);
@@ -210,7 +212,9 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
/* Allocate frame */
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(sizeof(struct ua_frame) +
+ IRLAP_NEGOCIATION_PARAMS_LEN,
+ GFP_ATOMIC);
if (!tx_skb)
return;
@@ -245,23 +249,23 @@ void irlap_send_ua_response_frame(struct irlap_cb *self, struct qos_info *qos)
void irlap_send_dm_frame( struct irlap_cb *self)
{
struct sk_buff *tx_skb = NULL;
- __u8 *frame;
+ struct dm_frame *frame;
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- tx_skb = alloc_skb(32, GFP_ATOMIC);
+ tx_skb = alloc_skb(sizeof(struct dm_frame), GFP_ATOMIC);
if (!tx_skb)
return;
- frame = skb_put(tx_skb, 2);
+ frame = (struct dm_frame *)skb_put(tx_skb, 2);
if (self->state == LAP_NDM)
- frame[0] = CBROADCAST;
+ frame->caddr = CBROADCAST;
else
- frame[0] = self->caddr;
+ frame->caddr = self->caddr;
- frame[1] = DM_RSP | PF_BIT;
+ frame->control = DM_RSP | PF_BIT;
irlap_queue_xmit(self, tx_skb);
}
@@ -275,21 +279,21 @@ void irlap_send_dm_frame( struct irlap_cb *self)
void irlap_send_disc_frame(struct irlap_cb *self)
{
struct sk_buff *tx_skb = NULL;
- __u8 *frame;
+ struct disc_frame *frame;
IRDA_DEBUG(3, "%s()\n", __FUNCTION__);
IRDA_ASSERT(self != NULL, return;);
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
- tx_skb = alloc_skb(16, GFP_ATOMIC);
+ tx_skb = alloc_skb(sizeof(struct disc_frame), GFP_ATOMIC);
if (!tx_skb)
return;
- frame = skb_put(tx_skb, 2);
+ frame = (struct disc_frame *)skb_put(tx_skb, 2);
- frame[0] = self->caddr | CMD_FRAME;
- frame[1] = DISC_CMD | PF_BIT;
+ frame->caddr = self->caddr | CMD_FRAME;
+ frame->control = DISC_CMD | PF_BIT;
irlap_queue_xmit(self, tx_skb);
}
@@ -315,7 +319,8 @@ void irlap_send_discovery_xid_frame(struct irlap_cb *self, int S, __u8 s,
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
IRDA_ASSERT(discovery != NULL, return;);
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(sizeof(struct xid_frame) + IRLAP_DISCOVERY_INFO_LEN,
+ GFP_ATOMIC);
if (!tx_skb)
return;
@@ -573,18 +578,18 @@ static void irlap_recv_discovery_xid_cmd(struct irlap_cb *self,
void irlap_send_rr_frame(struct irlap_cb *self, int command)
{
struct sk_buff *tx_skb;
- __u8 *frame;
+ struct rr_frame *frame;
- tx_skb = alloc_skb(16, GFP_ATOMIC);
+ tx_skb = alloc_skb(sizeof(struct rr_frame), GFP_ATOMIC);
if (!tx_skb)
return;
- frame = skb_put(tx_skb, 2);
+ frame = (struct rr_frame *)skb_put(tx_skb, 2);
- frame[0] = self->caddr;
- frame[0] |= (command) ? CMD_FRAME : 0;
+ frame->caddr = self->caddr;
+ frame->caddr |= (command) ? CMD_FRAME : 0;
- frame[1] = RR | PF_BIT | (self->vr << 5);
+ frame->control = RR | PF_BIT | (self->vr << 5);
irlap_queue_xmit(self, tx_skb);
}
@@ -598,16 +603,16 @@ void irlap_send_rr_frame(struct irlap_cb *self, int command)
void irlap_send_rd_frame(struct irlap_cb *self)
{
struct sk_buff *tx_skb;
- __u8 *frame;
+ struct rd_frame *frame;
- tx_skb = alloc_skb(16, GFP_ATOMIC);
+ tx_skb = alloc_skb(sizeof(struct rd_frame), GFP_ATOMIC);
if (!tx_skb)
return;
- frame = skb_put(tx_skb, 2);
+ frame = (struct rd_frame *)skb_put(tx_skb, 2);
- frame[0] = self->caddr;
- frame[1] = RD_RSP | PF_BIT;
+ frame->caddr = self->caddr;
+ frame->caddr = RD_RSP | PF_BIT;
irlap_queue_xmit(self, tx_skb);
}
@@ -1214,7 +1219,7 @@ void irlap_send_test_frame(struct irlap_cb *self, __u8 caddr, __u32 daddr,
struct test_frame *frame;
__u8 *info;
- tx_skb = alloc_skb(cmd->len+sizeof(struct test_frame), GFP_ATOMIC);
+ tx_skb = alloc_skb(cmd->len + sizeof(struct test_frame), GFP_ATOMIC);
if (!tx_skb)
return;
diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c
index c440913dee14..5073261b9d0c 100644
--- a/net/irda/irlmp.c
+++ b/net/irda/irlmp.c
@@ -392,7 +392,7 @@ int irlmp_connect_request(struct lsap_cb *self, __u8 dlsap_sel,
/* Any userdata? */
if (tx_skb == NULL) {
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (!tx_skb)
return -ENOMEM;
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index 42acf1cde737..3c2e70b77df1 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -804,12 +804,12 @@ static inline void irttp_give_credit(struct tsap_cb *self)
self->send_credit, self->avail_credit, self->remote_credit);
/* Give credit to peer */
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(TTP_MAX_HEADER, GFP_ATOMIC);
if (!tx_skb)
return;
/* Reserve space for LMP, and LAP header */
- skb_reserve(tx_skb, self->max_header_size);
+ skb_reserve(tx_skb, LMP_MAX_HEADER);
/*
* Since we can transmit and receive frames concurrently,
@@ -1093,7 +1093,8 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel,
/* Any userdata supplied? */
if (userdata == NULL) {
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
+ GFP_ATOMIC);
if (!tx_skb)
return -ENOMEM;
@@ -1341,7 +1342,8 @@ int irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size,
/* Any userdata supplied? */
if (userdata == NULL) {
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(TTP_MAX_HEADER + TTP_SAR_HEADER,
+ GFP_ATOMIC);
if (!tx_skb)
return -ENOMEM;
@@ -1540,14 +1542,14 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
if (!userdata) {
struct sk_buff *tx_skb;
- tx_skb = alloc_skb(64, GFP_ATOMIC);
+ tx_skb = alloc_skb(LMP_MAX_HEADER, GFP_ATOMIC);
if (!tx_skb)
return -ENOMEM;
/*
* Reserve space for MUX and LAP header
*/
- skb_reserve(tx_skb, TTP_MAX_HEADER);
+ skb_reserve(tx_skb, LMP_MAX_HEADER);
userdata = tx_skb;
}
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 83b443ddc72f..20ff7cca1d07 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -2140,7 +2140,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
if (xp->selector.sport)
- xp->selector.sport_mask = ~0;
+ xp->selector.sport_mask = htons(0xffff);
sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1],
pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr);
@@ -2153,7 +2153,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
if (xp->selector.dport)
- xp->selector.dport_mask = ~0;
+ xp->selector.dport_mask = htons(0xffff);
sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1];
if (sec_ctx != NULL) {
@@ -2243,7 +2243,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port;
if (sel.sport)
- sel.sport_mask = ~0;
+ sel.sport_mask = htons(0xffff);
sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1],
pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
@@ -2251,7 +2251,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg
sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port;
if (sel.dport)
- sel.dport_mask = ~0;
+ sel.dport_mask = htons(0xffff);
sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1];
memset(&tmp, 0, sizeof(struct xfrm_policy));
@@ -2928,11 +2928,6 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt,
if (*dir)
goto out;
}
- else {
- *dir = security_xfrm_sock_policy_alloc(xp, sk);
- if (*dir)
- goto out;
- }
*dir = pol->sadb_x_policy_dir-1;
return xp;
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index 0a28d2c5c44f..f619c6527266 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -209,7 +209,9 @@ config NETFILTER_XT_TARGET_SECMARK
config NETFILTER_XT_TARGET_CONNSECMARK
tristate '"CONNSECMARK" target support'
- depends on NETFILTER_XTABLES && (NF_CONNTRACK_SECMARK || IP_NF_CONNTRACK_SECMARK)
+ depends on NETFILTER_XTABLES && \
+ ((NF_CONNTRACK && NF_CONNTRACK_SECMARK) || \
+ (IP_NF_CONNTRACK && IP_NF_CONNTRACK_SECMARK))
help
The CONNSECMARK target copies security markings from packets
to connections, and restores security markings from connections
@@ -365,7 +367,7 @@ config NETFILTER_XT_MATCH_MULTIPORT
config NETFILTER_XT_MATCH_PHYSDEV
tristate '"physdev" match support'
- depends on NETFILTER_XTABLES && BRIDGE_NETFILTER
+ depends on NETFILTER_XTABLES && BRIDGE && BRIDGE_NETFILTER
help
Physdev packet matching matches against the physical bridge ports
the IP packet arrived on or will leave by.
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 1721f7c78c77..bd0156a28ecd 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -47,13 +47,6 @@ MODULE_LICENSE("GPL");
static char __initdata version[] = "0.93";
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
-
static inline int
ctnetlink_dump_tuples_proto(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple,
@@ -410,7 +403,6 @@ static int ctnetlink_done(struct netlink_callback *cb)
{
if (cb->args[1])
nf_ct_put((struct nf_conn *)cb->args[1]);
- DEBUGP("entered %s\n", __FUNCTION__);
return 0;
}
@@ -425,9 +417,6 @@ ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
- DEBUGP("entered %s, last bucket=%lu id=%u\n", __FUNCTION__,
- cb->args[0], *id);
-
read_lock_bh(&nf_conntrack_lock);
last = (struct nf_conn *)cb->args[1];
for (; cb->args[0] < nf_conntrack_htable_size; cb->args[0]++) {
@@ -471,7 +460,6 @@ out:
if (last)
nf_ct_put(last);
- DEBUGP("leaving, last bucket=%lu id=%u\n", cb->args[0], *id);
return skb->len;
}
@@ -482,8 +470,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple)
struct nf_conntrack_l3proto *l3proto;
int ret = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_IP_MAX, attr);
l3proto = nf_ct_l3proto_find_get(tuple->src.l3num);
@@ -493,8 +479,6 @@ ctnetlink_parse_tuple_ip(struct nfattr *attr, struct nf_conntrack_tuple *tuple)
nf_ct_l3proto_put(l3proto);
- DEBUGP("leaving\n");
-
return ret;
}
@@ -510,8 +494,6 @@ ctnetlink_parse_tuple_proto(struct nfattr *attr,
struct nf_conntrack_protocol *proto;
int ret = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
@@ -538,8 +520,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple,
struct nfattr *tb[CTA_TUPLE_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(tuple, 0, sizeof(*tuple));
nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
@@ -566,10 +546,6 @@ ctnetlink_parse_tuple(struct nfattr *cda[], struct nf_conntrack_tuple *tuple,
else
tuple->dst.dir = IP_CT_DIR_ORIGINAL;
- NF_CT_DUMP_TUPLE(tuple);
-
- DEBUGP("leaving\n");
-
return 0;
}
@@ -586,8 +562,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
struct nfattr *tb[CTA_PROTONAT_MAX];
struct ip_nat_protocol *npt;
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
@@ -606,7 +580,6 @@ static int ctnetlink_parse_nat_proto(struct nfattr *attr,
ip_nat_proto_put(npt);
- DEBUGP("leaving\n");
return 0;
}
@@ -622,8 +595,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
struct nfattr *tb[CTA_NAT_MAX];
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
memset(range, 0, sizeof(*range));
nfattr_parse_nested(tb, CTA_NAT_MAX, nat);
@@ -649,7 +620,6 @@ ctnetlink_parse_nat(struct nfattr *nat,
if (err < 0)
return err;
- DEBUGP("leaving\n");
return 0;
}
#endif
@@ -659,8 +629,6 @@ ctnetlink_parse_help(struct nfattr *attr, char **helper_name)
{
struct nfattr *tb[CTA_HELP_MAX];
- DEBUGP("entered %s\n", __FUNCTION__);
-
nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
if (!tb[CTA_HELP_NAME-1])
@@ -690,8 +658,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -709,10 +675,8 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = nf_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash\n");
+ if (!h)
return -ENOENT;
- }
ct = nf_ct_tuplehash_to_ctrack(h);
@@ -727,7 +691,6 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb,
ct->timeout.function((unsigned long)ct);
nf_ct_put(ct);
- DEBUGP("leaving\n");
return 0;
}
@@ -744,8 +707,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nlh->nlmsg_flags & NLM_F_DUMP) {
u32 rlen;
@@ -779,11 +740,9 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
return err;
h = nf_conntrack_find_get(&tuple, NULL);
- if (!h) {
- DEBUGP("tuple not found in conntrack hash");
+ if (!h)
return -ENOENT;
- }
- DEBUGP("tuple found\n");
+
ct = nf_ct_tuplehash_to_ctrack(h);
err = -ENOMEM;
@@ -804,7 +763,6 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (err < 0)
goto out;
- DEBUGP("leaving\n");
return 0;
free:
@@ -876,8 +834,6 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
char *helpname;
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (!help) {
/* FIXME: we need to reallocate and rehash */
return -EBUSY;
@@ -954,8 +910,6 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[])
{
int err;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (cda[CTA_HELP-1]) {
err = ctnetlink_change_helper(ct, cda);
if (err < 0)
@@ -985,7 +939,6 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nfattr *cda[])
ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
#endif
- DEBUGP("all done\n");
return 0;
}
@@ -997,8 +950,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
struct nf_conn *ct;
int err = -EINVAL;
- DEBUGP("entered %s\n", __FUNCTION__);
-
ct = nf_conntrack_alloc(otuple, rtuple);
if (ct == NULL || IS_ERR(ct))
return -ENOMEM;
@@ -1028,7 +979,6 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
add_timer(&ct->timeout);
nf_conntrack_hash_insert(ct);
- DEBUGP("conntrack with id %u inserted\n", ct->id);
return 0;
err:
@@ -1046,8 +996,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_MAX, cta_min))
return -EINVAL;
@@ -1071,7 +1019,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
if (h == NULL) {
write_unlock_bh(&nf_conntrack_lock);
- DEBUGP("no such conntrack, create new\n");
err = -ENOENT;
if (nlh->nlmsg_flags & NLM_F_CREATE)
err = ctnetlink_create_conntrack(cda, &otuple, &rtuple);
@@ -1087,7 +1034,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb,
/* We manipulate the conntrack inside the global conntrack table lock,
* so there's no need to increase the refcount */
- DEBUGP("conntrack found\n");
err = -EEXIST;
if (!(nlh->nlmsg_flags & NLM_F_EXCL))
err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), cda);
@@ -1268,8 +1214,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
struct nfgenmsg *nfmsg = NLMSG_DATA(cb->nlh);
u_int8_t l3proto = nfmsg->nfgen_family;
- DEBUGP("entered %s, last id=%llu\n", __FUNCTION__, *id);
-
read_lock_bh(&nf_conntrack_lock);
list_for_each_prev(i, &nf_conntrack_expect_list) {
exp = (struct nf_conntrack_expect *) i;
@@ -1287,8 +1231,6 @@ ctnetlink_exp_dump_table(struct sk_buff *skb, struct netlink_callback *cb)
out:
read_unlock_bh(&nf_conntrack_lock);
- DEBUGP("leaving, last id=%llu\n", *id);
-
return skb->len;
}
@@ -1308,8 +1250,6 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1460,8 +1400,6 @@ ctnetlink_create_expect(struct nfattr *cda[], u_int8_t u3)
struct nf_conn_help *help;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
/* caller guarantees that those three CTA_EXPECT_* exist */
err = ctnetlink_parse_tuple(cda, &tuple, CTA_EXPECT_TUPLE, u3);
if (err < 0)
@@ -1516,8 +1454,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
u_int8_t u3 = nfmsg->nfgen_family;
int err = 0;
- DEBUGP("entered %s\n", __FUNCTION__);
-
if (nfattr_bad_size(cda, CTA_EXPECT_MAX, cta_min_exp))
return -EINVAL;
@@ -1546,8 +1482,6 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb,
err = ctnetlink_change_expect(exp, cda);
write_unlock_bh(&nf_conntrack_lock);
- DEBUGP("leaving\n");
-
return err;
}
diff --git a/net/netfilter/xt_NFQUEUE.c b/net/netfilter/xt_NFQUEUE.c
index db9b896e57c8..39e117502bd7 100644
--- a/net/netfilter/xt_NFQUEUE.c
+++ b/net/netfilter/xt_NFQUEUE.c
@@ -68,7 +68,7 @@ static int __init xt_nfqueue_init(void)
static void __exit xt_nfqueue_fini(void)
{
- xt_register_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target));
+ xt_unregister_targets(xt_nfqueue_target, ARRAY_SIZE(xt_nfqueue_target));
}
module_init(xt_nfqueue_init);
diff --git a/net/netfilter/xt_connmark.c b/net/netfilter/xt_connmark.c
index 92a5726ef237..a8f03057dbde 100644
--- a/net/netfilter/xt_connmark.c
+++ b/net/netfilter/xt_connmark.c
@@ -147,7 +147,7 @@ static int __init xt_connmark_init(void)
static void __exit xt_connmark_fini(void)
{
- xt_register_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match));
+ xt_unregister_matches(xt_connmark_match, ARRAY_SIZE(xt_connmark_match));
}
module_init(xt_connmark_init);
diff --git a/net/netlabel/netlabel_cipso_v4.c b/net/netlabel/netlabel_cipso_v4.c
index 4125a55f469f..a6ce1d6d5c59 100644
--- a/net/netlabel/netlabel_cipso_v4.c
+++ b/net/netlabel/netlabel_cipso_v4.c
@@ -32,6 +32,7 @@
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/skbuff.h>
+#include <linux/audit.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -162,8 +163,7 @@ static int netlbl_cipsov4_add_std(struct genl_info *info)
int nla_a_rem;
int nla_b_rem;
- if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
- !info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
+ if (!info->attrs[NLBL_CIPSOV4_A_TAGLST] ||
!info->attrs[NLBL_CIPSOV4_A_MLSLVLLST])
return -EINVAL;
@@ -344,8 +344,7 @@ static int netlbl_cipsov4_add_pass(struct genl_info *info)
int ret_val;
struct cipso_v4_doi *doi_def = NULL;
- if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
- !info->attrs[NLBL_CIPSOV4_A_TAGLST])
+ if (!info->attrs[NLBL_CIPSOV4_A_TAGLST])
return -EINVAL;
doi_def = kmalloc(sizeof(*doi_def), GFP_KERNEL);
@@ -381,21 +380,40 @@ static int netlbl_cipsov4_add(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
- u32 map_type;
+ u32 type;
+ u32 doi;
+ const char *type_str = "(unknown)";
+ struct audit_buffer *audit_buf;
+ struct netlbl_audit audit_info;
- if (!info->attrs[NLBL_CIPSOV4_A_MTYPE])
+ if (!info->attrs[NLBL_CIPSOV4_A_DOI] ||
+ !info->attrs[NLBL_CIPSOV4_A_MTYPE])
return -EINVAL;
- map_type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
- switch (map_type) {
+ doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
+ netlbl_netlink_auditinfo(skb, &audit_info);
+
+ type = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_MTYPE]);
+ switch (type) {
case CIPSO_V4_MAP_STD:
+ type_str = "std";
ret_val = netlbl_cipsov4_add_std(info);
break;
case CIPSO_V4_MAP_PASS:
+ type_str = "pass";
ret_val = netlbl_cipsov4_add_pass(info);
break;
}
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_ADD,
+ &audit_info);
+ audit_log_format(audit_buf,
+ " cipso_doi=%u cipso_type=%s res=%u",
+ doi,
+ type_str,
+ ret_val == 0 ? 1 : 0);
+ audit_log_end(audit_buf);
+
return ret_val;
}
@@ -653,12 +671,27 @@ static int netlbl_cipsov4_listall(struct sk_buff *skb,
static int netlbl_cipsov4_remove(struct sk_buff *skb, struct genl_info *info)
{
int ret_val = -EINVAL;
- u32 doi;
+ u32 doi = 0;
+ struct audit_buffer *audit_buf;
+ struct netlbl_audit audit_info;
- if (info->attrs[NLBL_CIPSOV4_A_DOI]) {
- doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
- ret_val = cipso_v4_doi_remove(doi, netlbl_cipsov4_doi_free);
- }
+ if (!info->attrs[NLBL_CIPSOV4_A_DOI])
+ return -EINVAL;
+
+ doi = nla_get_u32(info->attrs[NLBL_CIPSOV4_A_DOI]);
+ netlbl_netlink_auditinfo(skb, &audit_info);
+
+ ret_val = cipso_v4_doi_remove(doi,
+ &audit_info,
+ netlbl_cipsov4_doi_free);
+
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_CIPSOV4_DEL,
+ &audit_info);
+ audit_log_format(audit_buf,
+ " cipso_doi=%u res=%u",
+ doi,
+ ret_val == 0 ? 1 : 0);
+ audit_log_end(audit_buf);
return ret_val;
}
diff --git a/net/netlabel/netlabel_domainhash.c b/net/netlabel/netlabel_domainhash.c
index f56d7a8ac7b7..af4371d3b459 100644
--- a/net/netlabel/netlabel_domainhash.c
+++ b/net/netlabel/netlabel_domainhash.c
@@ -35,12 +35,14 @@
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/string.h>
+#include <linux/audit.h>
#include <net/netlabel.h>
#include <net/cipso_ipv4.h>
#include <asm/bug.h>
#include "netlabel_mgmt.h"
#include "netlabel_domainhash.h"
+#include "netlabel_user.h"
struct netlbl_domhsh_tbl {
struct list_head *tbl;
@@ -186,6 +188,7 @@ int netlbl_domhsh_init(u32 size)
/**
* netlbl_domhsh_add - Adds a entry to the domain hash table
* @entry: the entry to add
+ * @audit_info: NetLabel audit information
*
* Description:
* Adds a new entry to the domain hash table and handles any updates to the
@@ -193,10 +196,13 @@ int netlbl_domhsh_init(u32 size)
* negative on failure.
*
*/
-int netlbl_domhsh_add(struct netlbl_dom_map *entry)
+int netlbl_domhsh_add(struct netlbl_dom_map *entry,
+ struct netlbl_audit *audit_info)
{
int ret_val;
u32 bkt;
+ struct audit_buffer *audit_buf;
+ char *audit_domain;
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
@@ -236,6 +242,26 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry)
spin_unlock(&netlbl_domhsh_def_lock);
} else
ret_val = -EINVAL;
+
+ if (entry->domain != NULL)
+ audit_domain = entry->domain;
+ else
+ audit_domain = "(default)";
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_ADD, audit_info);
+ audit_log_format(audit_buf, " nlbl_domain=%s", audit_domain);
+ switch (entry->type) {
+ case NETLBL_NLTYPE_UNLABELED:
+ audit_log_format(audit_buf, " nlbl_protocol=unlbl");
+ break;
+ case NETLBL_NLTYPE_CIPSOV4:
+ audit_log_format(audit_buf,
+ " nlbl_protocol=cipsov4 cipso_doi=%u",
+ entry->type_def.cipsov4->doi);
+ break;
+ }
+ audit_log_format(audit_buf, " res=%u", ret_val == 0 ? 1 : 0);
+ audit_log_end(audit_buf);
+
rcu_read_unlock();
if (ret_val != 0) {
@@ -254,6 +280,7 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry)
/**
* netlbl_domhsh_add_default - Adds the default entry to the domain hash table
* @entry: the entry to add
+ * @audit_info: NetLabel audit information
*
* Description:
* Adds a new default entry to the domain hash table and handles any updates
@@ -261,14 +288,16 @@ int netlbl_domhsh_add(struct netlbl_dom_map *entry)
* negative on failure.
*
*/
-int netlbl_domhsh_add_default(struct netlbl_dom_map *entry)
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
+ struct netlbl_audit *audit_info)
{
- return netlbl_domhsh_add(entry);
+ return netlbl_domhsh_add(entry, audit_info);
}
/**
* netlbl_domhsh_remove - Removes an entry from the domain hash table
* @domain: the domain to remove
+ * @audit_info: NetLabel audit information
*
* Description:
* Removes an entry from the domain hash table and handles any updates to the
@@ -276,10 +305,12 @@ int netlbl_domhsh_add_default(struct netlbl_dom_map *entry)
* negative on failure.
*
*/
-int netlbl_domhsh_remove(const char *domain)
+int netlbl_domhsh_remove(const char *domain, struct netlbl_audit *audit_info)
{
int ret_val = -ENOENT;
struct netlbl_dom_map *entry;
+ struct audit_buffer *audit_buf;
+ char *audit_domain;
rcu_read_lock();
if (domain != NULL)
@@ -316,6 +347,18 @@ int netlbl_domhsh_remove(const char *domain)
ret_val = -ENOENT;
spin_unlock(&netlbl_domhsh_def_lock);
}
+
+ if (entry->domain != NULL)
+ audit_domain = entry->domain;
+ else
+ audit_domain = "(default)";
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_MAP_DEL, audit_info);
+ audit_log_format(audit_buf,
+ " nlbl_domain=%s res=%u",
+ audit_domain,
+ ret_val == 0 ? 1 : 0);
+ audit_log_end(audit_buf);
+
if (ret_val == 0)
call_rcu(&entry->rcu, netlbl_domhsh_free_entry);
@@ -326,6 +369,7 @@ remove_return:
/**
* netlbl_domhsh_remove_default - Removes the default entry from the table
+ * @audit_info: NetLabel audit information
*
* Description:
* Removes/resets the default entry for the domain hash table and handles any
@@ -333,9 +377,9 @@ remove_return:
* success, non-zero on failure.
*
*/
-int netlbl_domhsh_remove_default(void)
+int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info)
{
- return netlbl_domhsh_remove(NULL);
+ return netlbl_domhsh_remove(NULL, audit_info);
}
/**
diff --git a/net/netlabel/netlabel_domainhash.h b/net/netlabel/netlabel_domainhash.h
index 02af72a7877c..3689956c3436 100644
--- a/net/netlabel/netlabel_domainhash.h
+++ b/net/netlabel/netlabel_domainhash.h
@@ -57,9 +57,11 @@ struct netlbl_dom_map {
int netlbl_domhsh_init(u32 size);
/* Manipulate the domain hash table */
-int netlbl_domhsh_add(struct netlbl_dom_map *entry);
-int netlbl_domhsh_add_default(struct netlbl_dom_map *entry);
-int netlbl_domhsh_remove_default(void);
+int netlbl_domhsh_add(struct netlbl_dom_map *entry,
+ struct netlbl_audit *audit_info);
+int netlbl_domhsh_add_default(struct netlbl_dom_map *entry,
+ struct netlbl_audit *audit_info);
+int netlbl_domhsh_remove_default(struct netlbl_audit *audit_info);
struct netlbl_dom_map *netlbl_domhsh_getentry(const char *domain);
int netlbl_domhsh_walk(u32 *skip_bkt,
u32 *skip_chain,
diff --git a/net/netlabel/netlabel_kapi.c b/net/netlabel/netlabel_kapi.c
index 54fb7de3c2b1..ff971103fd0c 100644
--- a/net/netlabel/netlabel_kapi.c
+++ b/net/netlabel/netlabel_kapi.c
@@ -200,7 +200,7 @@ void netlbl_cache_invalidate(void)
int netlbl_cache_add(const struct sk_buff *skb,
const struct netlbl_lsm_secattr *secattr)
{
- if (secattr->cache.data == NULL)
+ if (secattr->cache == NULL)
return -ENOMSG;
if (CIPSO_V4_OPTEXIST(skb))
diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c
index 8626c9f678eb..53c9079ad2c3 100644
--- a/net/netlabel/netlabel_mgmt.c
+++ b/net/netlabel/netlabel_mgmt.c
@@ -87,11 +87,14 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
struct netlbl_dom_map *entry = NULL;
size_t tmp_size;
u32 tmp_val;
+ struct netlbl_audit audit_info;
if (!info->attrs[NLBL_MGMT_A_DOMAIN] ||
!info->attrs[NLBL_MGMT_A_PROTOCOL])
goto add_failure;
+ netlbl_netlink_auditinfo(skb, &audit_info);
+
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL) {
ret_val = -ENOMEM;
@@ -108,7 +111,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
- ret_val = netlbl_domhsh_add(entry);
+ ret_val = netlbl_domhsh_add(entry, &audit_info);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
@@ -125,7 +128,7 @@ static int netlbl_mgmt_add(struct sk_buff *skb, struct genl_info *info)
rcu_read_unlock();
goto add_failure;
}
- ret_val = netlbl_domhsh_add(entry);
+ ret_val = netlbl_domhsh_add(entry, &audit_info);
rcu_read_unlock();
break;
default:
@@ -156,12 +159,15 @@ add_failure:
static int netlbl_mgmt_remove(struct sk_buff *skb, struct genl_info *info)
{
char *domain;
+ struct netlbl_audit audit_info;
if (!info->attrs[NLBL_MGMT_A_DOMAIN])
return -EINVAL;
+ netlbl_netlink_auditinfo(skb, &audit_info);
+
domain = nla_data(info->attrs[NLBL_MGMT_A_DOMAIN]);
- return netlbl_domhsh_remove(domain);
+ return netlbl_domhsh_remove(domain, &audit_info);
}
/**
@@ -264,10 +270,13 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
int ret_val = -EINVAL;
struct netlbl_dom_map *entry = NULL;
u32 tmp_val;
+ struct netlbl_audit audit_info;
if (!info->attrs[NLBL_MGMT_A_PROTOCOL])
goto adddef_failure;
+ netlbl_netlink_auditinfo(skb, &audit_info);
+
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL) {
ret_val = -ENOMEM;
@@ -277,7 +286,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
switch (entry->type) {
case NETLBL_NLTYPE_UNLABELED:
- ret_val = netlbl_domhsh_add_default(entry);
+ ret_val = netlbl_domhsh_add_default(entry, &audit_info);
break;
case NETLBL_NLTYPE_CIPSOV4:
if (!info->attrs[NLBL_MGMT_A_CV4DOI])
@@ -294,7 +303,7 @@ static int netlbl_mgmt_adddef(struct sk_buff *skb, struct genl_info *info)
rcu_read_unlock();
goto adddef_failure;
}
- ret_val = netlbl_domhsh_add_default(entry);
+ ret_val = netlbl_domhsh_add_default(entry, &audit_info);
rcu_read_unlock();
break;
default:
@@ -322,7 +331,11 @@ adddef_failure:
*/
static int netlbl_mgmt_removedef(struct sk_buff *skb, struct genl_info *info)
{
- return netlbl_domhsh_remove_default();
+ struct netlbl_audit audit_info;
+
+ netlbl_netlink_auditinfo(skb, &audit_info);
+
+ return netlbl_domhsh_remove_default(&audit_info);
}
/**
diff --git a/net/netlabel/netlabel_unlabeled.c b/net/netlabel/netlabel_unlabeled.c
index 440f5c4e1e2d..1833ad233b39 100644
--- a/net/netlabel/netlabel_unlabeled.c
+++ b/net/netlabel/netlabel_unlabeled.c
@@ -64,6 +64,34 @@ static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
};
/*
+ * Helper Functions
+ */
+
+/**
+ * netlbl_unlabel_acceptflg_set - Set the unlabeled accept flag
+ * @value: desired value
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Set the value of the unlabeled accept flag to @value.
+ *
+ */
+static void netlbl_unlabel_acceptflg_set(u8 value,
+ struct netlbl_audit *audit_info)
+{
+ struct audit_buffer *audit_buf;
+ u8 old_val;
+
+ old_val = atomic_read(&netlabel_unlabel_accept_flg);
+ atomic_set(&netlabel_unlabel_accept_flg, value);
+
+ audit_buf = netlbl_audit_start_common(AUDIT_MAC_UNLBL_ALLOW,
+ audit_info);
+ audit_log_format(audit_buf, " unlbl_accept=%u old=%u", value, old_val);
+ audit_log_end(audit_buf);
+}
+
+/*
* NetLabel Command Handlers
*/
@@ -79,18 +107,19 @@ static struct nla_policy netlbl_unlabel_genl_policy[NLBL_UNLABEL_A_MAX + 1] = {
*/
static int netlbl_unlabel_accept(struct sk_buff *skb, struct genl_info *info)
{
- int ret_val = -EINVAL;
u8 value;
+ struct netlbl_audit audit_info;
if (info->attrs[NLBL_UNLABEL_A_ACPTFLG]) {
value = nla_get_u8(info->attrs[NLBL_UNLABEL_A_ACPTFLG]);
if (value == 1 || value == 0) {
- atomic_set(&netlabel_unlabel_accept_flg, value);
- ret_val = 0;
+ netlbl_netlink_auditinfo(skb, &audit_info);
+ netlbl_unlabel_acceptflg_set(value, &audit_info);
+ return 0;
}
}
- return ret_val;
+ return -EINVAL;
}
/**
@@ -229,16 +258,23 @@ int netlbl_unlabel_defconf(void)
{
int ret_val;
struct netlbl_dom_map *entry;
+ struct netlbl_audit audit_info;
+
+ /* Only the kernel is allowed to call this function and the only time
+ * it is called is at bootup before the audit subsystem is reporting
+ * messages so don't worry to much about these values. */
+ security_task_getsecid(current, &audit_info.secid);
+ audit_info.loginuid = 0;
entry = kzalloc(sizeof(*entry), GFP_KERNEL);
if (entry == NULL)
return -ENOMEM;
entry->type = NETLBL_NLTYPE_UNLABELED;
- ret_val = netlbl_domhsh_add_default(entry);
+ ret_val = netlbl_domhsh_add_default(entry, &audit_info);
if (ret_val != 0)
return ret_val;
- atomic_set(&netlabel_unlabel_accept_flg, 1);
+ netlbl_unlabel_acceptflg_set(1, &audit_info);
return 0;
}
diff --git a/net/netlabel/netlabel_user.c b/net/netlabel/netlabel_user.c
index eeb7d768d2bb..98a416381e61 100644
--- a/net/netlabel/netlabel_user.c
+++ b/net/netlabel/netlabel_user.c
@@ -32,6 +32,9 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/socket.h>
+#include <linux/audit.h>
+#include <linux/tty.h>
+#include <linux/security.h>
#include <net/sock.h>
#include <net/netlink.h>
#include <net/genetlink.h>
@@ -74,3 +77,41 @@ int netlbl_netlink_init(void)
return 0;
}
+
+/*
+ * NetLabel Audit Functions
+ */
+
+/**
+ * netlbl_audit_start_common - Start an audit message
+ * @type: audit message type
+ * @audit_info: NetLabel audit information
+ *
+ * Description:
+ * Start an audit message using the type specified in @type and fill the audit
+ * message with some fields common to all NetLabel audit messages. Returns
+ * a pointer to the audit buffer on success, NULL on failure.
+ *
+ */
+struct audit_buffer *netlbl_audit_start_common(int type,
+ struct netlbl_audit *audit_info)
+{
+ struct audit_context *audit_ctx = current->audit_context;
+ struct audit_buffer *audit_buf;
+ char *secctx;
+ u32 secctx_len;
+
+ audit_buf = audit_log_start(audit_ctx, GFP_ATOMIC, type);
+ if (audit_buf == NULL)
+ return NULL;
+
+ audit_log_format(audit_buf, "netlabel: auid=%u", audit_info->loginuid);
+
+ if (audit_info->secid != 0 &&
+ security_secid_to_secctx(audit_info->secid,
+ &secctx,
+ &secctx_len) == 0)
+ audit_log_format(audit_buf, " subj=%s", secctx);
+
+ return audit_buf;
+}
diff --git a/net/netlabel/netlabel_user.h b/net/netlabel/netlabel_user.h
index 3f9386b917df..47967ef32964 100644
--- a/net/netlabel/netlabel_user.h
+++ b/net/netlabel/netlabel_user.h
@@ -34,6 +34,7 @@
#include <linux/types.h>
#include <linux/skbuff.h>
#include <linux/capability.h>
+#include <linux/audit.h>
#include <net/netlink.h>
#include <net/genetlink.h>
#include <net/netlabel.h>
@@ -71,8 +72,25 @@ static inline void *netlbl_netlink_hdr_put(struct sk_buff *skb,
NETLBL_PROTO_VERSION);
}
+/**
+ * netlbl_netlink_auditinfo - Fetch the audit information from a NETLINK msg
+ * @skb: the packet
+ * @audit_info: NetLabel audit information
+ */
+static inline void netlbl_netlink_auditinfo(struct sk_buff *skb,
+ struct netlbl_audit *audit_info)
+{
+ audit_info->secid = NETLINK_CB(skb).sid;
+ audit_info->loginuid = NETLINK_CB(skb).loginuid;
+}
+
/* NetLabel NETLINK I/O functions */
int netlbl_netlink_init(void);
+/* NetLabel Audit Functions */
+
+struct audit_buffer *netlbl_audit_start_common(int type,
+ struct netlbl_audit *audit_info);
+
#endif
diff --git a/net/rxrpc/transport.c b/net/rxrpc/transport.c
index 465efc86fccf..94b2e2fe6fdb 100644
--- a/net/rxrpc/transport.c
+++ b/net/rxrpc/transport.c
@@ -381,11 +381,10 @@ static int rxrpc_incoming_msg(struct rxrpc_transport *trans,
/* allocate a new message record */
ret = -ENOMEM;
- msg = kmalloc(sizeof(struct rxrpc_message), GFP_KERNEL);
+ msg = kmemdup(jumbomsg, sizeof(struct rxrpc_message), GFP_KERNEL);
if (!msg)
goto error;
- memcpy(msg, jumbomsg, sizeof(*msg));
list_add_tail(&msg->link, msgq);
/* adjust the jumbo packet */
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 7e14f14058e9..37a184021647 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -401,7 +401,7 @@ static int tc_dump_tfilter(struct sk_buff *skb, struct netlink_callback *cb)
if ((dev = dev_get_by_index(tcm->tcm_ifindex)) == NULL)
return skb->len;
- read_lock_bh(&qdisc_tree_lock);
+ read_lock(&qdisc_tree_lock);
if (!tcm->tcm_parent)
q = dev->qdisc_sleeping;
else
@@ -458,7 +458,7 @@ errout:
if (cl)
cops->put(q, cl);
out:
- read_unlock_bh(&qdisc_tree_lock);
+ read_unlock(&qdisc_tree_lock);
dev_put(dev);
return skb->len;
}
diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c
index 86cac49a0531..09fda68c8b39 100644
--- a/net/sched/cls_basic.c
+++ b/net/sched/cls_basic.c
@@ -194,7 +194,7 @@ static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle,
if (handle)
f->handle = handle;
else {
- int i = 0x80000000;
+ unsigned int i = 0x80000000;
do {
if (++head->hgenerator == 0x7FFFFFFF)
head->hgenerator = 1;
diff --git a/net/sched/estimator.c b/net/sched/estimator.c
deleted file mode 100644
index 0ebc98e9be2d..000000000000
--- a/net/sched/estimator.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * net/sched/estimator.c Simple rate estimator.
- *
- * 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.
- *
- * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
- */
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/sockios.h>
-#include <linux/in.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include <linux/rtnetlink.h>
-#include <linux/init.h>
-#include <net/sock.h>
-#include <net/pkt_sched.h>
-
-/*
- This code is NOT intended to be used for statistics collection,
- its purpose is to provide a base for statistical multiplexing
- for controlled load service.
- If you need only statistics, run a user level daemon which
- periodically reads byte counters.
-
- Unfortunately, rate estimation is not a very easy task.
- F.e. I did not find a simple way to estimate the current peak rate
- and even failed to formulate the problem 8)8)
-
- So I preferred not to built an estimator into the scheduler,
- but run this task separately.
- Ideally, it should be kernel thread(s), but for now it runs
- from timers, which puts apparent top bounds on the number of rated
- flows, has minimal overhead on small, but is enough
- to handle controlled load service, sets of aggregates.
-
- We measure rate over A=(1<<interval) seconds and evaluate EWMA:
-
- avrate = avrate*(1-W) + rate*W
-
- where W is chosen as negative power of 2: W = 2^(-ewma_log)
-
- The resulting time constant is:
-
- T = A/(-ln(1-W))
-
-
- NOTES.
-
- * The stored value for avbps is scaled by 2^5, so that maximal
- rate is ~1Gbit, avpps is scaled by 2^10.
-
- * Minimal interval is HZ/4=250msec (it is the greatest common divisor
- for HZ=100 and HZ=1024 8)), maximal interval
- is (HZ*2^EST_MAX_INTERVAL)/4 = 8sec. Shorter intervals
- are too expensive, longer ones can be implemented
- at user level painlessly.
- */
-
-#define EST_MAX_INTERVAL 5
-
-struct qdisc_estimator
-{
- struct qdisc_estimator *next;
- struct tc_stats *stats;
- spinlock_t *stats_lock;
- unsigned interval;
- int ewma_log;
- u64 last_bytes;
- u32 last_packets;
- u32 avpps;
- u32 avbps;
-};
-
-struct qdisc_estimator_head
-{
- struct timer_list timer;
- struct qdisc_estimator *list;
-};
-
-static struct qdisc_estimator_head elist[EST_MAX_INTERVAL+1];
-
-/* Estimator array lock */
-static DEFINE_RWLOCK(est_lock);
-
-static void est_timer(unsigned long arg)
-{
- int idx = (int)arg;
- struct qdisc_estimator *e;
-
- read_lock(&est_lock);
- for (e = elist[idx].list; e; e = e->next) {
- struct tc_stats *st = e->stats;
- u64 nbytes;
- u32 npackets;
- u32 rate;
-
- spin_lock(e->stats_lock);
- nbytes = st->bytes;
- npackets = st->packets;
- rate = (nbytes - e->last_bytes)<<(7 - idx);
- e->last_bytes = nbytes;
- e->avbps += ((long)rate - (long)e->avbps) >> e->ewma_log;
- st->bps = (e->avbps+0xF)>>5;
-
- rate = (npackets - e->last_packets)<<(12 - idx);
- e->last_packets = npackets;
- e->avpps += ((long)rate - (long)e->avpps) >> e->ewma_log;
- e->stats->pps = (e->avpps+0x1FF)>>10;
- spin_unlock(e->stats_lock);
- }
-
- mod_timer(&elist[idx].timer, jiffies + ((HZ<<idx)/4));
- read_unlock(&est_lock);
-}
-
-int qdisc_new_estimator(struct tc_stats *stats, spinlock_t *stats_lock, struct rtattr *opt)
-{
- struct qdisc_estimator *est;
- struct tc_estimator *parm = RTA_DATA(opt);
-
- if (RTA_PAYLOAD(opt) < sizeof(*parm))
- return -EINVAL;
-
- if (parm->interval < -2 || parm->interval > 3)
- return -EINVAL;
-
- est = kzalloc(sizeof(*est), GFP_KERNEL);
- if (est == NULL)
- return -ENOBUFS;
-
- est->interval = parm->interval + 2;
- est->stats = stats;
- est->stats_lock = stats_lock;
- est->ewma_log = parm->ewma_log;
- est->last_bytes = stats->bytes;
- est->avbps = stats->bps<<5;
- est->last_packets = stats->packets;
- est->avpps = stats->pps<<10;
-
- est->next = elist[est->interval].list;
- if (est->next == NULL) {
- init_timer(&elist[est->interval].timer);
- elist[est->interval].timer.data = est->interval;
- elist[est->interval].timer.expires = jiffies + ((HZ<<est->interval)/4);
- elist[est->interval].timer.function = est_timer;
- add_timer(&elist[est->interval].timer);
- }
- write_lock_bh(&est_lock);
- elist[est->interval].list = est;
- write_unlock_bh(&est_lock);
- return 0;
-}
-
-void qdisc_kill_estimator(struct tc_stats *stats)
-{
- int idx;
- struct qdisc_estimator *est, **pest;
-
- for (idx=0; idx <= EST_MAX_INTERVAL; idx++) {
- int killed = 0;
- pest = &elist[idx].list;
- while ((est=*pest) != NULL) {
- if (est->stats != stats) {
- pest = &est->next;
- continue;
- }
-
- write_lock_bh(&est_lock);
- *pest = est->next;
- write_unlock_bh(&est_lock);
-
- kfree(est);
- killed++;
- }
- if (killed && elist[idx].list == NULL)
- del_timer(&elist[idx].timer);
- }
-}
-
-EXPORT_SYMBOL(qdisc_kill_estimator);
-EXPORT_SYMBOL(qdisc_new_estimator);
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index a19eff12cf78..0b6489291140 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -195,14 +195,14 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle)
{
struct Qdisc *q;
- read_lock_bh(&qdisc_tree_lock);
+ read_lock(&qdisc_tree_lock);
list_for_each_entry(q, &dev->qdisc_list, list) {
if (q->handle == handle) {
- read_unlock_bh(&qdisc_tree_lock);
+ read_unlock(&qdisc_tree_lock);
return q;
}
}
- read_unlock_bh(&qdisc_tree_lock);
+ read_unlock(&qdisc_tree_lock);
return NULL;
}
@@ -837,7 +837,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
continue;
if (idx > s_idx)
s_q_idx = 0;
- read_lock_bh(&qdisc_tree_lock);
+ read_lock(&qdisc_tree_lock);
q_idx = 0;
list_for_each_entry(q, &dev->qdisc_list, list) {
if (q_idx < s_q_idx) {
@@ -846,12 +846,12 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
}
if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) {
- read_unlock_bh(&qdisc_tree_lock);
+ read_unlock(&qdisc_tree_lock);
goto done;
}
q_idx++;
}
- read_unlock_bh(&qdisc_tree_lock);
+ read_unlock(&qdisc_tree_lock);
}
done:
@@ -1074,7 +1074,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
s_t = cb->args[0];
t = 0;
- read_lock_bh(&qdisc_tree_lock);
+ read_lock(&qdisc_tree_lock);
list_for_each_entry(q, &dev->qdisc_list, list) {
if (t < s_t || !q->ops->cl_ops ||
(tcm->tcm_parent &&
@@ -1096,7 +1096,7 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb)
break;
t++;
}
- read_unlock_bh(&qdisc_tree_lock);
+ read_unlock(&qdisc_tree_lock);
cb->args[0] = t;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 6f9151899795..88c6a99ce53c 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -45,11 +45,10 @@
The idea is the following:
- enqueue, dequeue are serialized via top level device
spinlock dev->queue_lock.
- - tree walking is protected by read_lock_bh(qdisc_tree_lock)
+ - tree walking is protected by read_lock(qdisc_tree_lock)
and this lock is used only in process context.
- - updates to tree are made under rtnl semaphore or
- from softirq context (__qdisc_destroy rcu-callback)
- hence this lock needs local bh disabling.
+ - updates to tree are made only under rtnl semaphore,
+ hence this lock may be made without local bh disabling.
qdisc_tree_lock must be grabbed BEFORE dev->queue_lock!
*/
@@ -57,14 +56,14 @@ DEFINE_RWLOCK(qdisc_tree_lock);
void qdisc_lock_tree(struct net_device *dev)
{
- write_lock_bh(&qdisc_tree_lock);
+ write_lock(&qdisc_tree_lock);
spin_lock_bh(&dev->queue_lock);
}
void qdisc_unlock_tree(struct net_device *dev)
{
spin_unlock_bh(&dev->queue_lock);
- write_unlock_bh(&qdisc_tree_lock);
+ write_unlock(&qdisc_tree_lock);
}
/*
@@ -483,20 +482,6 @@ void qdisc_reset(struct Qdisc *qdisc)
static void __qdisc_destroy(struct rcu_head *head)
{
struct Qdisc *qdisc = container_of(head, struct Qdisc, q_rcu);
- struct Qdisc_ops *ops = qdisc->ops;
-
-#ifdef CONFIG_NET_ESTIMATOR
- gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
-#endif
- write_lock(&qdisc_tree_lock);
- if (ops->reset)
- ops->reset(qdisc);
- if (ops->destroy)
- ops->destroy(qdisc);
- write_unlock(&qdisc_tree_lock);
- module_put(ops->owner);
-
- dev_put(qdisc->dev);
kfree((char *) qdisc - qdisc->padded);
}
@@ -504,32 +489,23 @@ static void __qdisc_destroy(struct rcu_head *head)
void qdisc_destroy(struct Qdisc *qdisc)
{
- struct list_head cql = LIST_HEAD_INIT(cql);
- struct Qdisc *cq, *q, *n;
+ struct Qdisc_ops *ops = qdisc->ops;
if (qdisc->flags & TCQ_F_BUILTIN ||
- !atomic_dec_and_test(&qdisc->refcnt))
+ !atomic_dec_and_test(&qdisc->refcnt))
return;
- if (!list_empty(&qdisc->list)) {
- if (qdisc->ops->cl_ops == NULL)
- list_del(&qdisc->list);
- else
- list_move(&qdisc->list, &cql);
- }
-
- /* unlink inner qdiscs from dev->qdisc_list immediately */
- list_for_each_entry(cq, &cql, list)
- list_for_each_entry_safe(q, n, &qdisc->dev->qdisc_list, list)
- if (TC_H_MAJ(q->parent) == TC_H_MAJ(cq->handle)) {
- if (q->ops->cl_ops == NULL)
- list_del_init(&q->list);
- else
- list_move_tail(&q->list, &cql);
- }
- list_for_each_entry_safe(cq, n, &cql, list)
- list_del_init(&cq->list);
+ list_del(&qdisc->list);
+#ifdef CONFIG_NET_ESTIMATOR
+ gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est);
+#endif
+ if (ops->reset)
+ ops->reset(qdisc);
+ if (ops->destroy)
+ ops->destroy(qdisc);
+ module_put(ops->owner);
+ dev_put(qdisc->dev);
call_rcu(&qdisc->q_rcu, __qdisc_destroy);
}
@@ -549,15 +525,15 @@ void dev_activate(struct net_device *dev)
printk(KERN_INFO "%s: activation failed\n", dev->name);
return;
}
- write_lock_bh(&qdisc_tree_lock);
+ write_lock(&qdisc_tree_lock);
list_add_tail(&qdisc->list, &dev->qdisc_list);
- write_unlock_bh(&qdisc_tree_lock);
+ write_unlock(&qdisc_tree_lock);
} else {
qdisc = &noqueue_qdisc;
}
- write_lock_bh(&qdisc_tree_lock);
+ write_lock(&qdisc_tree_lock);
dev->qdisc_sleeping = qdisc;
- write_unlock_bh(&qdisc_tree_lock);
+ write_unlock(&qdisc_tree_lock);
}
if (!netif_carrier_ok(dev))
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index bb3ddd4784b1..9b9c555c713f 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -786,11 +786,10 @@ static long htb_do_events(struct htb_sched *q, int level)
for (i = 0; i < 500; i++) {
struct htb_class *cl;
long diff;
- struct rb_node *p = q->wait_pq[level].rb_node;
+ struct rb_node *p = rb_first(&q->wait_pq[level]);
+
if (!p)
return 0;
- while (p->rb_left)
- p = p->rb_left;
cl = rb_entry(p, struct htb_class, pq_node);
if (time_after(cl->pq_key, q->jiffies)) {
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 03f65de75d88..64f630102532 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -218,12 +218,6 @@ int sctp_rcv(struct sk_buff *skb)
}
}
- /* SCTP seems to always need a timestamp right now (FIXME) */
- if (skb->tstamp.off_sec == 0) {
- __net_timestamp(skb);
- sock_enable_timestamp(sk);
- }
-
if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb, family))
goto discard_release;
nf_reset(skb);
@@ -388,7 +382,7 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
* pmtu discovery on this transport.
*/
t->pathmtu = SCTP_DEFAULT_MINSEGMENT;
- t->param_flags = (t->param_flags & ~SPP_HB) |
+ t->param_flags = (t->param_flags & ~SPP_PMTUD) |
SPP_PMTUD_DISABLE;
} else {
t->pathmtu = pmtu;
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 249e5033c1a8..78071c6e6cf1 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -215,17 +215,17 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
}
dst = ip6_route_output(NULL, &fl);
- if (dst) {
+ if (!dst->error) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
SCTP_DEBUG_PRINTK(
"rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
- } else {
- SCTP_DEBUG_PRINTK("NO ROUTE\n");
+ return dst;
}
-
- return dst;
+ SCTP_DEBUG_PRINTK("NO ROUTE\n");
+ dst_release(dst);
+ return NULL;
}
/* Returns the number of consecutive initial bits that match in the 2 ipv6
diff --git a/net/sctp/output.c b/net/sctp/output.c
index cdc5a3936766..3ef4351dd956 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -633,7 +633,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* data will fit or delay in hopes of bundling a full
* sized packet.
*/
- if (len < asoc->pathmtu - packet->overhead) {
+ if (len < asoc->frag_point) {
retval = SCTP_XMIT_NAGLE_DELAY;
goto finish;
}
@@ -645,7 +645,13 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
/* Keep track of how many bytes are in flight to the receiver. */
asoc->outqueue.outstanding_bytes += datasize;
- /* Update our view of the receiver's rwnd. */
+ /* Update our view of the receiver's rwnd. Include sk_buff overhead
+ * while updating peer.rwnd so that it reduces the chances of a
+ * receiver running out of receive buffer space even when receive
+ * window is still open. This can happen when a sender is sending
+ * sending small messages.
+ */
+ datasize += sizeof(struct sk_buff);
if (datasize < rwnd)
rwnd -= datasize;
else
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 37074a39ecbb..739582415bf6 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -416,7 +416,8 @@ void sctp_retransmit_mark(struct sctp_outq *q,
* (Section 7.2.4)), add the data size of those
* chunks to the rwnd.
*/
- q->asoc->peer.rwnd += sctp_data_size(chunk);
+ q->asoc->peer.rwnd += (sctp_data_size(chunk) +
+ sizeof(struct sk_buff));
q->outstanding_bytes -= sctp_data_size(chunk);
transport->flight_size -= sctp_data_size(chunk);
diff --git a/net/sctp/proc.c b/net/sctp/proc.c
index a356d8d310a9..7f49e769080e 100644
--- a/net/sctp/proc.c
+++ b/net/sctp/proc.c
@@ -344,7 +344,7 @@ static int sctp_assocs_seq_show(struct seq_file *seq, void *v)
assoc, sk, sctp_sk(sk)->type, sk->sk_state,
assoc->state, hash, assoc->assoc_id,
assoc->sndbuf_used,
- (sk->sk_rcvbuf - assoc->rwnd),
+ atomic_read(&assoc->rmem_alloc),
sock_i_uid(sk), sock_i_ino(sk),
epb->bind_addr.port,
assoc->peer.port);
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 7745bdea7817..507dff72c585 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -1447,8 +1447,16 @@ no_hmac:
/* Check to see if the cookie is stale. If there is already
* an association, there is no need to check cookie's expiration
* for init collision case of lost COOKIE ACK.
+ * If skb has been timestamped, then use the stamp, otherwise
+ * use current time. This introduces a small possibility that
+ * that a cookie may be considered expired, but his would only slow
+ * down the new association establishment instead of every packet.
*/
- skb_get_timestamp(skb, &tv);
+ if (sock_flag(ep->base.sk, SOCK_TIMESTAMP))
+ skb_get_timestamp(skb, &tv);
+ else
+ do_gettimeofday(&tv);
+
if (!asoc && tv_lt(bear_cookie->expiration, tv)) {
__u16 len;
/*
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index 79c3e072cf28..9f34dec6ff8e 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -821,7 +821,7 @@ out:
* addrs is a pointer to an array of one or more socket addresses. Each
* address is contained in its appropriate structure (i.e. struct
* sockaddr_in or struct sockaddr_in6) the family of the address type
- * must be used to distengish the address length (note that this
+ * must be used to distinguish the address length (note that this
* representation is termed a "packed array" of addresses). The caller
* specifies the number of addresses in the array with addrcnt.
*
@@ -3084,8 +3084,8 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
*/
sp->disable_fragments = 0;
- /* Turn on/off any Nagle-like algorithm. */
- sp->nodelay = 1;
+ /* Enable Nagle algorithm by default. */
+ sp->nodelay = 0;
/* Enable by default. */
sp->v4mapped = 1;
@@ -5362,6 +5362,20 @@ static void sctp_wfree(struct sk_buff *skb)
sctp_association_put(asoc);
}
+/* Do accounting for the receive space on the socket.
+ * Accounting for the association is done in ulpevent.c
+ * We set this as a destructor for the cloned data skbs so that
+ * accounting is done at the correct time.
+ */
+void sctp_sock_rfree(struct sk_buff *skb)
+{
+ struct sock *sk = skb->sk;
+ struct sctp_ulpevent *event = sctp_skb2event(skb);
+
+ atomic_sub(event->rmem_len, &sk->sk_rmem_alloc);
+}
+
+
/* Helper function to wait for space in the sndbuf. */
static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
size_t msg_len)
@@ -5634,10 +5648,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) {
event = sctp_skb2event(skb);
if (event->asoc == assoc) {
- sock_rfree(skb);
+ sctp_sock_rfree(skb);
__skb_unlink(skb, &oldsk->sk_receive_queue);
__skb_queue_tail(&newsk->sk_receive_queue, skb);
- skb_set_owner_r(skb, newsk);
+ sctp_skb_set_owner_r(skb, newsk);
}
}
@@ -5665,10 +5679,10 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
sctp_skb_for_each(skb, &oldsp->pd_lobby, tmp) {
event = sctp_skb2event(skb);
if (event->asoc == assoc) {
- sock_rfree(skb);
+ sctp_sock_rfree(skb);
__skb_unlink(skb, &oldsp->pd_lobby);
__skb_queue_tail(queue, skb);
- skb_set_owner_r(skb, newsk);
+ sctp_skb_set_owner_r(skb, newsk);
}
}
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index ee236784a6bb..a015283a9087 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -55,10 +55,13 @@ static void sctp_ulpevent_release_frag_data(struct sctp_ulpevent *event);
/* Initialize an ULP event from an given skb. */
-SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
+SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event,
+ int msg_flags,
+ unsigned int len)
{
memset(event, 0, sizeof(struct sctp_ulpevent));
event->msg_flags = msg_flags;
+ event->rmem_len = len;
}
/* Create a new sctp_ulpevent. */
@@ -73,7 +76,7 @@ SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags,
goto fail;
event = sctp_skb2event(skb);
- sctp_ulpevent_init(event, msg_flags);
+ sctp_ulpevent_init(event, msg_flags, skb->truesize);
return event;
@@ -101,17 +104,16 @@ static inline void sctp_ulpevent_set_owner(struct sctp_ulpevent *event,
sctp_association_hold((struct sctp_association *)asoc);
skb = sctp_event2skb(event);
event->asoc = (struct sctp_association *)asoc;
- atomic_add(skb->truesize, &event->asoc->rmem_alloc);
- skb_set_owner_r(skb, asoc->base.sk);
+ atomic_add(event->rmem_len, &event->asoc->rmem_alloc);
+ sctp_skb_set_owner_r(skb, asoc->base.sk);
}
/* A simple destructor to give up the reference to the association. */
static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
{
struct sctp_association *asoc = event->asoc;
- struct sk_buff *skb = sctp_event2skb(event);
- atomic_sub(skb->truesize, &asoc->rmem_alloc);
+ atomic_sub(event->rmem_len, &asoc->rmem_alloc);
sctp_association_put(asoc);
}
@@ -372,7 +374,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
/* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb);
- sctp_ulpevent_init(event, MSG_NOTIFICATION);
+ sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
sre = (struct sctp_remote_error *)
skb_push(skb, sizeof(struct sctp_remote_error));
@@ -464,7 +466,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
/* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb);
- sctp_ulpevent_init(event, MSG_NOTIFICATION);
+ sctp_ulpevent_init(event, MSG_NOTIFICATION, skb->truesize);
ssf = (struct sctp_send_failed *)
skb_push(skb, sizeof(struct sctp_send_failed));
@@ -682,8 +684,11 @@ struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
/* Embed the event fields inside the cloned skb. */
event = sctp_skb2event(skb);
- /* Initialize event with flags 0. */
- sctp_ulpevent_init(event, 0);
+ /* Initialize event with flags 0 and correct length
+ * Since this is a clone of the original skb, only account for
+ * the data of this chunk as other chunks will be accounted separately.
+ */
+ sctp_ulpevent_init(event, 0, skb->len + sizeof(struct sk_buff));
sctp_ulpevent_receive_data(event, asoc);
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index 575e556aeb3e..e1d144275f97 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -309,7 +309,7 @@ static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff_head *qu
if (!new)
return NULL; /* try again later */
- new->sk = f_frag->sk;
+ sctp_skb_set_owner_r(new, f_frag->sk);
skb_shinfo(new)->frag_list = pos;
} else
diff --git a/net/socket.c b/net/socket.c
index 1bc4167e0da8..6c9b9b326d76 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -95,10 +95,10 @@
#include <linux/netfilter.h>
static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
-static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf,
- size_t size, loff_t pos);
-static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t size, loff_t pos);
+static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
+static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos);
static int sock_mmap(struct file *file, struct vm_area_struct *vma);
static int sock_close(struct inode *inode, struct file *file);
@@ -110,10 +110,6 @@ static long compat_sock_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
#endif
static int sock_fasync(int fd, struct file *filp, int on);
-static ssize_t sock_readv(struct file *file, const struct iovec *vector,
- unsigned long count, loff_t *ppos);
-static ssize_t sock_writev(struct file *file, const struct iovec *vector,
- unsigned long count, loff_t *ppos);
static ssize_t sock_sendpage(struct file *file, struct page *page,
int offset, size_t size, loff_t *ppos, int more);
@@ -136,8 +132,6 @@ static struct file_operations socket_file_ops = {
.open = sock_no_open, /* special open code to disallow open via /proc */
.release = sock_close,
.fasync = sock_fasync,
- .readv = sock_readv,
- .writev = sock_writev,
.sendpage = sock_sendpage,
.splice_write = generic_splice_sendpage,
};
@@ -664,7 +658,6 @@ static ssize_t sock_sendpage(struct file *file, struct page *page,
}
static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
- char __user *ubuf, size_t size,
struct sock_iocb *siocb)
{
if (!is_sync_kiocb(iocb)) {
@@ -675,16 +668,13 @@ static struct sock_iocb *alloc_sock_iocb(struct kiocb *iocb,
}
siocb->kiocb = iocb;
- siocb->async_iov.iov_base = ubuf;
- siocb->async_iov.iov_len = size;
-
iocb->private = siocb;
return siocb;
}
static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
- struct file *file, struct iovec *iov,
- unsigned long nr_segs)
+ struct file *file, const struct iovec *iov,
+ unsigned long nr_segs)
{
struct socket *sock = file->private_data;
size_t size = 0;
@@ -704,43 +694,27 @@ static ssize_t do_sock_read(struct msghdr *msg, struct kiocb *iocb,
return __sock_recvmsg(iocb, sock, msg, size, msg->msg_flags);
}
-static ssize_t sock_readv(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
-{
- struct kiocb iocb;
- struct sock_iocb siocb;
- struct msghdr msg;
- int ret;
-
- init_sync_kiocb(&iocb, NULL);
- iocb.private = &siocb;
-
- ret = do_sock_read(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
- if (-EIOCBQUEUED == ret)
- ret = wait_on_sync_kiocb(&iocb);
- return ret;
-}
-
-static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
- size_t count, loff_t pos)
+static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct sock_iocb siocb, *x;
if (pos != 0)
return -ESPIPE;
- if (count == 0) /* Match SYS5 behaviour */
+
+ if (iocb->ki_left == 0) /* Match SYS5 behaviour */
return 0;
- x = alloc_sock_iocb(iocb, ubuf, count, &siocb);
+
+ x = alloc_sock_iocb(iocb, &siocb);
if (!x)
return -ENOMEM;
- return do_sock_read(&x->async_msg, iocb, iocb->ki_filp,
- &x->async_iov, 1);
+ return do_sock_read(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
}
static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
- struct file *file, struct iovec *iov,
- unsigned long nr_segs)
+ struct file *file, const struct iovec *iov,
+ unsigned long nr_segs)
{
struct socket *sock = file->private_data;
size_t size = 0;
@@ -762,39 +736,22 @@ static ssize_t do_sock_write(struct msghdr *msg, struct kiocb *iocb,
return __sock_sendmsg(iocb, sock, msg, size);
}
-static ssize_t sock_writev(struct file *file, const struct iovec *iov,
- unsigned long nr_segs, loff_t *ppos)
-{
- struct msghdr msg;
- struct kiocb iocb;
- struct sock_iocb siocb;
- int ret;
-
- init_sync_kiocb(&iocb, NULL);
- iocb.private = &siocb;
-
- ret = do_sock_write(&msg, &iocb, file, (struct iovec *)iov, nr_segs);
- if (-EIOCBQUEUED == ret)
- ret = wait_on_sync_kiocb(&iocb);
- return ret;
-}
-
-static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
- size_t count, loff_t pos)
+static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct sock_iocb siocb, *x;
if (pos != 0)
return -ESPIPE;
- if (count == 0) /* Match SYS5 behaviour */
+
+ if (iocb->ki_left == 0) /* Match SYS5 behaviour */
return 0;
- x = alloc_sock_iocb(iocb, (void __user *)ubuf, count, &siocb);
+ x = alloc_sock_iocb(iocb, &siocb);
if (!x)
return -ENOMEM;
- return do_sock_write(&x->async_msg, iocb, iocb->ki_filp,
- &x->async_iov, 1);
+ return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
}
/*
@@ -868,7 +825,7 @@ static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg)
break;
case FIOGETOWN:
case SIOCGPGRP:
- err = put_user(sock->file->f_owner.pid,
+ err = put_user(f_getown(sock->file),
(int __user *)argp);
break;
case SIOCGIFBR:
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 55163af3dcaf..993ff1a5d945 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -331,8 +331,8 @@ rpcauth_unbindcred(struct rpc_task *task)
task->tk_msg.rpc_cred = NULL;
}
-u32 *
-rpcauth_marshcred(struct rpc_task *task, u32 *p)
+__be32 *
+rpcauth_marshcred(struct rpc_task *task, __be32 *p)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
@@ -342,8 +342,8 @@ rpcauth_marshcred(struct rpc_task *task, u32 *p)
return cred->cr_ops->crmarshal(task, p);
}
-u32 *
-rpcauth_checkverf(struct rpc_task *task, u32 *p)
+__be32 *
+rpcauth_checkverf(struct rpc_task *task, __be32 *p)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
@@ -355,7 +355,7 @@ rpcauth_checkverf(struct rpc_task *task, u32 *p)
int
rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
- u32 *data, void *obj)
+ __be32 *data, void *obj)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
@@ -369,7 +369,7 @@ rpcauth_wrap_req(struct rpc_task *task, kxdrproc_t encode, void *rqstp,
int
rpcauth_unwrap_resp(struct rpc_task *task, kxdrproc_t decode, void *rqstp,
- u32 *data, void *obj)
+ __be32 *data, void *obj)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 6eed3e166ba3..b36b9463f5a4 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -1,5 +1,5 @@
/*
- * linux/net/sunrpc/auth_gss.c
+ * linux/net/sunrpc/auth_gss/auth_gss.c
*
* RPCSEC_GSS client authentication.
*
@@ -826,14 +826,14 @@ out:
* Marshal credentials.
* Maybe we should keep a cached credential for performance reasons.
*/
-static u32 *
-gss_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_marshal(struct rpc_task *task, __be32 *p)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
- u32 *cred_len;
+ __be32 *cred_len;
struct rpc_rqst *req = task->tk_rqstp;
u32 maj_stat = 0;
struct xdr_netobj mic;
@@ -894,12 +894,12 @@ gss_refresh(struct rpc_task *task)
return 0;
}
-static u32 *
-gss_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+gss_validate(struct rpc_task *task, __be32 *p)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
- u32 seq;
+ __be32 seq;
struct kvec iov;
struct xdr_buf verf_buf;
struct xdr_netobj mic;
@@ -940,13 +940,14 @@ out_bad:
static inline int
gss_wrap_req_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+ kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
{
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
struct xdr_buf integ_buf;
- u32 *integ_len = NULL;
+ __be32 *integ_len = NULL;
struct xdr_netobj mic;
- u32 offset, *q;
+ u32 offset;
+ __be32 *q;
struct kvec *iov;
u32 maj_stat = 0;
int status = -EIO;
@@ -1032,13 +1033,13 @@ out:
static inline int
gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- kxdrproc_t encode, struct rpc_rqst *rqstp, u32 *p, void *obj)
+ kxdrproc_t encode, struct rpc_rqst *rqstp, __be32 *p, void *obj)
{
struct xdr_buf *snd_buf = &rqstp->rq_snd_buf;
u32 offset;
u32 maj_stat;
int status;
- u32 *opaque_len;
+ __be32 *opaque_len;
struct page **inpages;
int first;
int pad;
@@ -1095,7 +1096,7 @@ gss_wrap_req_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
static int
gss_wrap_req(struct rpc_task *task,
- kxdrproc_t encode, void *rqstp, u32 *p, void *obj)
+ kxdrproc_t encode, void *rqstp, __be32 *p, void *obj)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
@@ -1132,7 +1133,7 @@ out:
static inline int
gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- struct rpc_rqst *rqstp, u32 **p)
+ struct rpc_rqst *rqstp, __be32 **p)
{
struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
struct xdr_buf integ_buf;
@@ -1169,7 +1170,7 @@ gss_unwrap_resp_integ(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
static inline int
gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
- struct rpc_rqst *rqstp, u32 **p)
+ struct rpc_rqst *rqstp, __be32 **p)
{
struct xdr_buf *rcv_buf = &rqstp->rq_rcv_buf;
u32 offset;
@@ -1198,13 +1199,13 @@ gss_unwrap_resp_priv(struct rpc_cred *cred, struct gss_cl_ctx *ctx,
static int
gss_unwrap_resp(struct rpc_task *task,
- kxdrproc_t decode, void *rqstp, u32 *p, void *obj)
+ kxdrproc_t decode, void *rqstp, __be32 *p, void *obj)
{
struct rpc_cred *cred = task->tk_msg.rpc_cred;
struct gss_cred *gss_cred = container_of(cred, struct gss_cred,
gc_base);
struct gss_cl_ctx *ctx = gss_cred_get_ctx(cred);
- u32 *savedp = p;
+ __be32 *savedp = p;
struct kvec *head = ((struct rpc_rqst *)rqstp)->rq_rcv_buf.head;
int savedlen = head->iov_len;
int status = -EIO;
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 2f312164d6d5..08601ee4cd73 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -115,7 +115,7 @@ gss_get_mic_kerberos(struct gss_ctx *gss_ctx, struct xdr_buf *text,
krb5_hdr = ptr - 2;
msg_start = krb5_hdr + 24;
- *(u16 *)(krb5_hdr + 2) = htons(ctx->signalg);
+ *(__be16 *)(krb5_hdr + 2) = htons(ctx->signalg);
memset(krb5_hdr + 4, 0xff, 4);
if (make_checksum(checksum_type, krb5_hdr, 8, text, 0, &md5cksum))
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index f179415d0c38..cc45c1605f80 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -177,9 +177,9 @@ gss_wrap_kerberos(struct gss_ctx *ctx, int offset,
msg_start = krb5_hdr + 24;
/* XXXJBF: */ BUG_ON(buf->head[0].iov_base + offset + headlen != msg_start + blocksize);
- *(u16 *)(krb5_hdr + 2) = htons(kctx->signalg);
+ *(__be16 *)(krb5_hdr + 2) = htons(kctx->signalg);
memset(krb5_hdr + 4, 0xff, 4);
- *(u16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
+ *(__be16 *)(krb5_hdr + 4) = htons(kctx->sealalg);
make_confounder(msg_start, blocksize);
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index 94217ec9e2dd..1f0f079ffa65 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -607,7 +607,7 @@ svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o)
if (argv->iov_len < 4)
return -1;
- o->len = ntohl(svc_getu32(argv));
+ o->len = svc_getnl(argv);
l = round_up_to_quad(o->len);
if (argv->iov_len < l)
return -1;
@@ -620,17 +620,17 @@ svc_safe_getnetobj(struct kvec *argv, struct xdr_netobj *o)
static inline int
svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
{
- u32 *p;
+ u8 *p;
if (resv->iov_len + 4 > PAGE_SIZE)
return -1;
- svc_putu32(resv, htonl(o->len));
+ svc_putnl(resv, o->len);
p = resv->iov_base + resv->iov_len;
resv->iov_len += round_up_to_quad(o->len);
if (resv->iov_len > PAGE_SIZE)
return -1;
memcpy(p, o->data, o->len);
- memset((u8 *)p + o->len, 0, round_up_to_quad(o->len) - o->len);
+ memset(p + o->len, 0, round_up_to_quad(o->len) - o->len);
return 0;
}
@@ -640,7 +640,7 @@ svc_safe_putnetobj(struct kvec *resv, struct xdr_netobj *o)
*/
static int
gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
- u32 *rpcstart, struct rpc_gss_wire_cred *gc, u32 *authp)
+ __be32 *rpcstart, struct rpc_gss_wire_cred *gc, __be32 *authp)
{
struct gss_ctx *ctx_id = rsci->mechctx;
struct xdr_buf rpchdr;
@@ -657,7 +657,7 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
*authp = rpc_autherr_badverf;
if (argv->iov_len < 4)
return SVC_DENIED;
- flavor = ntohl(svc_getu32(argv));
+ flavor = svc_getnl(argv);
if (flavor != RPC_AUTH_GSS)
return SVC_DENIED;
if (svc_safe_getnetobj(argv, &checksum))
@@ -687,9 +687,9 @@ gss_verify_header(struct svc_rqst *rqstp, struct rsc *rsci,
static int
gss_write_null_verf(struct svc_rqst *rqstp)
{
- u32 *p;
+ __be32 *p;
- svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_NULL));
+ svc_putnl(rqstp->rq_res.head, RPC_AUTH_NULL);
p = rqstp->rq_res.head->iov_base + rqstp->rq_res.head->iov_len;
/* don't really need to check if head->iov_len > PAGE_SIZE ... */
*p++ = 0;
@@ -701,14 +701,14 @@ gss_write_null_verf(struct svc_rqst *rqstp)
static int
gss_write_verf(struct svc_rqst *rqstp, struct gss_ctx *ctx_id, u32 seq)
{
- u32 xdr_seq;
+ __be32 xdr_seq;
u32 maj_stat;
struct xdr_buf verf_data;
struct xdr_netobj mic;
- u32 *p;
+ __be32 *p;
struct kvec iov;
- svc_putu32(rqstp->rq_res.head, htonl(RPC_AUTH_GSS));
+ svc_putnl(rqstp->rq_res.head, RPC_AUTH_GSS);
xdr_seq = htonl(seq);
iov.iov_base = &xdr_seq;
@@ -782,7 +782,7 @@ EXPORT_SYMBOL(svcauth_gss_register_pseudoflavor);
static inline int
read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
{
- u32 raw;
+ __be32 raw;
int status;
status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
@@ -805,7 +805,7 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
struct xdr_netobj mic;
struct xdr_buf integ_buf;
- integ_len = ntohl(svc_getu32(&buf->head[0]));
+ integ_len = svc_getnl(&buf->head[0]);
if (integ_len & 3)
goto out;
if (integ_len > buf->len)
@@ -825,7 +825,7 @@ unwrap_integ_data(struct xdr_buf *buf, u32 seq, struct gss_ctx *ctx)
maj_stat = gss_verify_mic(ctx, &integ_buf, &mic);
if (maj_stat != GSS_S_COMPLETE)
goto out;
- if (ntohl(svc_getu32(&buf->head[0])) != seq)
+ if (svc_getnl(&buf->head[0]) != seq)
goto out;
stat = 0;
out:
@@ -857,7 +857,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs
rqstp->rq_sendfile_ok = 0;
- priv_len = ntohl(svc_getu32(&buf->head[0]));
+ priv_len = svc_getnl(&buf->head[0]);
if (rqstp->rq_deferred) {
/* Already decrypted last time through! The sequence number
* check at out_seq is unnecessary but harmless: */
@@ -895,7 +895,7 @@ unwrap_priv_data(struct svc_rqst *rqstp, struct xdr_buf *buf, u32 seq, struct gs
if (maj_stat != GSS_S_COMPLETE)
return -EINVAL;
out_seq:
- if (ntohl(svc_getu32(&buf->head[0])) != seq)
+ if (svc_getnl(&buf->head[0]) != seq)
return -EINVAL;
return 0;
}
@@ -903,9 +903,9 @@ out_seq:
struct gss_svc_data {
/* decoded gss client cred: */
struct rpc_gss_wire_cred clcred;
- /* pointer to the beginning of the procedure-specific results,
- * which may be encrypted/checksummed in svcauth_gss_release: */
- u32 *body_start;
+ /* save a pointer to the beginning of the encoded verifier,
+ * for use in encryption/checksumming in svcauth_gss_release: */
+ __be32 *verf_start;
struct rsc *rsci;
};
@@ -946,7 +946,7 @@ gss_write_init_verf(struct svc_rqst *rqstp, struct rsi *rsip)
* response here and return SVC_COMPLETE.
*/
static int
-svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
+svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
@@ -956,8 +956,8 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
struct rpc_gss_wire_cred *gc;
struct rsc *rsci = NULL;
struct rsi *rsip, rsikey;
- u32 *rpcstart;
- u32 *reject_stat = resv->iov_base + resv->iov_len;
+ __be32 *rpcstart;
+ __be32 *reject_stat = resv->iov_base + resv->iov_len;
int ret;
dprintk("RPC: svcauth_gss: argv->iov_len = %zd\n",argv->iov_len);
@@ -968,7 +968,7 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
if (!svcdata)
goto auth_err;
rqstp->rq_auth_data = svcdata;
- svcdata->body_start = NULL;
+ svcdata->verf_start = NULL;
svcdata->rsci = NULL;
gc = &svcdata->clcred;
@@ -985,12 +985,12 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
if (argv->iov_len < 5 * 4)
goto auth_err;
- crlen = ntohl(svc_getu32(argv));
- if (ntohl(svc_getu32(argv)) != RPC_GSS_VERSION)
+ crlen = svc_getnl(argv);
+ if (svc_getnl(argv) != RPC_GSS_VERSION)
goto auth_err;
- gc->gc_proc = ntohl(svc_getu32(argv));
- gc->gc_seq = ntohl(svc_getu32(argv));
- gc->gc_svc = ntohl(svc_getu32(argv));
+ gc->gc_proc = svc_getnl(argv);
+ gc->gc_seq = svc_getnl(argv);
+ gc->gc_svc = svc_getnl(argv);
if (svc_safe_getnetobj(argv, &gc->gc_ctx))
goto auth_err;
if (crlen != round_up_to_quad(gc->gc_ctx.len) + 5 * 4)
@@ -1016,9 +1016,9 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
case RPC_GSS_PROC_CONTINUE_INIT:
if (argv->iov_len < 2 * 4)
goto auth_err;
- if (ntohl(svc_getu32(argv)) != RPC_AUTH_NULL)
+ if (svc_getnl(argv) != RPC_AUTH_NULL)
goto auth_err;
- if (ntohl(svc_getu32(argv)) != 0)
+ if (svc_getnl(argv) != 0)
goto auth_err;
break;
case RPC_GSS_PROC_DATA:
@@ -1076,14 +1076,14 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
goto drop;
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
- svc_putu32(resv, rpc_success);
+ svc_putnl(resv, RPC_SUCCESS);
if (svc_safe_putnetobj(resv, &rsip->out_handle))
goto drop;
if (resv->iov_len + 3 * 4 > PAGE_SIZE)
goto drop;
- svc_putu32(resv, htonl(rsip->major_status));
- svc_putu32(resv, htonl(rsip->minor_status));
- svc_putu32(resv, htonl(GSS_SEQ_WIN));
+ svc_putnl(resv, rsip->major_status);
+ svc_putnl(resv, rsip->minor_status);
+ svc_putnl(resv, GSS_SEQ_WIN);
if (svc_safe_putnetobj(resv, &rsip->out_token))
goto drop;
rqstp->rq_client = NULL;
@@ -1093,10 +1093,11 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
set_bit(CACHE_NEGATIVE, &rsci->h.flags);
if (resv->iov_len + 4 > PAGE_SIZE)
goto drop;
- svc_putu32(resv, rpc_success);
+ svc_putnl(resv, RPC_SUCCESS);
goto complete;
case RPC_GSS_PROC_DATA:
*authp = rpcsec_gsserr_ctxproblem;
+ svcdata->verf_start = resv->iov_base + resv->iov_len;
if (gss_write_verf(rqstp, rsci->mechctx, gc->gc_seq))
goto auth_err;
rqstp->rq_cred = rsci->cred;
@@ -1110,18 +1111,16 @@ svcauth_gss_accept(struct svc_rqst *rqstp, u32 *authp)
gc->gc_seq, rsci->mechctx))
goto auth_err;
/* placeholders for length and seq. number: */
- svcdata->body_start = resv->iov_base + resv->iov_len;
- svc_putu32(resv, 0);
- svc_putu32(resv, 0);
+ svc_putnl(resv, 0);
+ svc_putnl(resv, 0);
break;
case RPC_GSS_SVC_PRIVACY:
if (unwrap_priv_data(rqstp, &rqstp->rq_arg,
gc->gc_seq, rsci->mechctx))
goto auth_err;
/* placeholders for length and seq. number: */
- svcdata->body_start = resv->iov_base + resv->iov_len;
- svc_putu32(resv, 0);
- svc_putu32(resv, 0);
+ svc_putnl(resv, 0);
+ svc_putnl(resv, 0);
break;
default:
goto auth_err;
@@ -1147,6 +1146,33 @@ out:
return ret;
}
+static __be32 *
+svcauth_gss_prepare_to_wrap(struct xdr_buf *resbuf, struct gss_svc_data *gsd)
+{
+ __be32 *p;
+ u32 verf_len;
+
+ p = gsd->verf_start;
+ gsd->verf_start = NULL;
+
+ /* If the reply stat is nonzero, don't wrap: */
+ if (*(p-1) != rpc_success)
+ return NULL;
+ /* Skip the verifier: */
+ p += 1;
+ verf_len = ntohl(*p++);
+ p += XDR_QUADLEN(verf_len);
+ /* move accept_stat to right place: */
+ memcpy(p, p + 2, 4);
+ /* Also don't wrap if the accept stat is nonzero: */
+ if (*p != rpc_success) {
+ resbuf->head[0].iov_len -= 2 * 4;
+ return NULL;
+ }
+ p++;
+ return p;
+}
+
static inline int
svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
{
@@ -1156,21 +1182,13 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
struct xdr_buf integ_buf;
struct xdr_netobj mic;
struct kvec *resv;
- u32 *p;
+ __be32 *p;
int integ_offset, integ_len;
int stat = -EINVAL;
- p = gsd->body_start;
- gsd->body_start = NULL;
- /* move accept_stat to right place: */
- memcpy(p, p + 2, 4);
- /* Don't wrap in failure case: */
- /* Counting on not getting here if call was not even accepted! */
- if (*p != rpc_success) {
- resbuf->head[0].iov_len -= 2 * 4;
+ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+ if (p == NULL)
goto out;
- }
- p++;
integ_offset = (u8 *)(p + 1) - (u8 *)resbuf->head[0].iov_base;
integ_len = resbuf->len - integ_offset;
BUG_ON(integ_len % 4);
@@ -1191,7 +1209,6 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ resbuf->head[0].iov_len;
resbuf->tail[0].iov_len = 0;
- rqstp->rq_restailpage = 0;
resv = &resbuf->tail[0];
} else {
resv = &resbuf->tail[0];
@@ -1199,7 +1216,7 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
goto out_err;
- svc_putu32(resv, htonl(mic.len));
+ svc_putnl(resv, mic.len);
memset(mic.data + mic.len, 0,
round_up_to_quad(mic.len) - mic.len);
resv->iov_len += XDR_QUADLEN(mic.len) << 2;
@@ -1219,28 +1236,20 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
struct rpc_gss_wire_cred *gc = &gsd->clcred;
struct xdr_buf *resbuf = &rqstp->rq_res;
struct page **inpages = NULL;
- u32 *p;
- int offset, *len;
+ __be32 *p, *len;
+ int offset;
int pad;
- p = gsd->body_start;
- gsd->body_start = NULL;
- /* move accept_stat to right place: */
- memcpy(p, p + 2, 4);
- /* Don't wrap in failure case: */
- /* Counting on not getting here if call was not even accepted! */
- if (*p != rpc_success) {
- resbuf->head[0].iov_len -= 2 * 4;
+ p = svcauth_gss_prepare_to_wrap(resbuf, gsd);
+ if (p == NULL)
return 0;
- }
- p++;
len = p++;
offset = (u8 *)p - (u8 *)resbuf->head[0].iov_base;
*p++ = htonl(gc->gc_seq);
inpages = resbuf->pages;
/* XXX: Would be better to write some xdr helper functions for
* nfs{2,3,4}xdr.c that place the data right, instead of copying: */
- if (resbuf->tail[0].iov_base && rqstp->rq_restailpage == 0) {
+ if (resbuf->tail[0].iov_base) {
BUG_ON(resbuf->tail[0].iov_base >= resbuf->head[0].iov_base
+ PAGE_SIZE);
BUG_ON(resbuf->tail[0].iov_base < resbuf->head[0].iov_base);
@@ -1258,13 +1267,12 @@ svcauth_gss_wrap_resp_priv(struct svc_rqst *rqstp)
resbuf->tail[0].iov_base = resbuf->head[0].iov_base
+ resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE;
resbuf->tail[0].iov_len = 0;
- rqstp->rq_restailpage = 0;
}
if (gss_wrap(gsd->rsci->mechctx, offset, resbuf, inpages))
return -ENOMEM;
*len = htonl(resbuf->len - offset);
pad = 3 - ((resbuf->len - offset - 1)&3);
- p = (u32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
+ p = (__be32 *)(resbuf->tail[0].iov_base + resbuf->tail[0].iov_len);
memset(p, 0, pad);
resbuf->tail[0].iov_len += pad;
resbuf->len += pad;
@@ -1282,7 +1290,7 @@ svcauth_gss_release(struct svc_rqst *rqstp)
if (gc->gc_proc != RPC_GSS_PROC_DATA)
goto out;
/* Release can be called twice, but we only wrap once. */
- if (gsd->body_start == NULL)
+ if (gsd->verf_start == NULL)
goto out;
/* normally not set till svc_send, but we need it here: */
/* XXX: what for? Do we mess it up the moment we call svc_putu32
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index 2eccffa96ba1..3be257dc32b2 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -60,8 +60,8 @@ nul_match(struct auth_cred *acred, struct rpc_cred *cred, int taskflags)
/*
* Marshal credential.
*/
-static u32 *
-nul_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+nul_marshal(struct rpc_task *task, __be32 *p)
{
*p++ = htonl(RPC_AUTH_NULL);
*p++ = 0;
@@ -81,8 +81,8 @@ nul_refresh(struct rpc_task *task)
return 0;
}
-static u32 *
-nul_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+nul_validate(struct rpc_task *task, __be32 *p)
{
rpc_authflavor_t flavor;
u32 size;
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 74c7406a1054..f7f990c9afe2 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -137,12 +137,12 @@ unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
* Marshal credentials.
* Maybe we should keep a cached credential for performance reasons.
*/
-static u32 *
-unx_marshal(struct rpc_task *task, u32 *p)
+static __be32 *
+unx_marshal(struct rpc_task *task, __be32 *p)
{
struct rpc_clnt *clnt = task->tk_client;
struct unx_cred *cred = (struct unx_cred *) task->tk_msg.rpc_cred;
- u32 *base, *hold;
+ __be32 *base, *hold;
int i;
*p++ = htonl(RPC_AUTH_UNIX);
@@ -178,8 +178,8 @@ unx_refresh(struct rpc_task *task)
return 0;
}
-static u32 *
-unx_validate(struct rpc_task *task, u32 *p)
+static __be32 *
+unx_validate(struct rpc_task *task, __be32 *p)
{
rpc_authflavor_t flavor;
u32 size;
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 084a0ad5c64e..78696f2dc7d6 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -60,8 +60,8 @@ static void call_refreshresult(struct rpc_task *task);
static void call_timeout(struct rpc_task *task);
static void call_connect(struct rpc_task *task);
static void call_connect_status(struct rpc_task *task);
-static u32 * call_header(struct rpc_task *task);
-static u32 * call_verify(struct rpc_task *task);
+static __be32 * call_header(struct rpc_task *task);
+static __be32 * call_verify(struct rpc_task *task);
static int
@@ -161,10 +161,10 @@ static struct rpc_clnt * rpc_new_client(struct rpc_xprt *xprt, char *servname, s
}
/* save the nodename */
- clnt->cl_nodelen = strlen(system_utsname.nodename);
+ clnt->cl_nodelen = strlen(utsname()->nodename);
if (clnt->cl_nodelen > UNX_MAXNODENAME)
clnt->cl_nodelen = UNX_MAXNODENAME;
- memcpy(clnt->cl_nodename, system_utsname.nodename, clnt->cl_nodelen);
+ memcpy(clnt->cl_nodename, utsname()->nodename, clnt->cl_nodelen);
return clnt;
out_no_auth:
@@ -782,7 +782,7 @@ call_encode(struct rpc_task *task)
struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
unsigned int bufsiz;
kxdrproc_t encode;
- u32 *p;
+ __be32 *p;
dprintk("RPC: %4d call_encode (status %d)\n",
task->tk_pid, task->tk_status);
@@ -1100,7 +1100,7 @@ call_decode(struct rpc_task *task)
struct rpc_clnt *clnt = task->tk_client;
struct rpc_rqst *req = task->tk_rqstp;
kxdrproc_t decode = task->tk_msg.rpc_proc->p_decode;
- u32 *p;
+ __be32 *p;
dprintk("RPC: %4d call_decode (status %d)\n",
task->tk_pid, task->tk_status);
@@ -1197,12 +1197,12 @@ call_refreshresult(struct rpc_task *task)
/*
* Call header serialization
*/
-static u32 *
+static __be32 *
call_header(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
struct rpc_rqst *req = task->tk_rqstp;
- u32 *p = req->rq_svec[0].iov_base;
+ __be32 *p = req->rq_svec[0].iov_base;
/* FIXME: check buffer size? */
@@ -1221,12 +1221,13 @@ call_header(struct rpc_task *task)
/*
* Reply header verification
*/
-static u32 *
+static __be32 *
call_verify(struct rpc_task *task)
{
struct kvec *iov = &task->tk_rqstp->rq_rcv_buf.head[0];
int len = task->tk_rqstp->rq_rcv_buf.len >> 2;
- u32 *p = iov->iov_base, n;
+ __be32 *p = iov->iov_base;
+ u32 n;
int error = -EACCES;
if ((task->tk_rqstp->rq_rcv_buf.len & 3) != 0) {
@@ -1303,7 +1304,7 @@ call_verify(struct rpc_task *task)
printk(KERN_WARNING "call_verify: auth check failed\n");
goto out_garbage; /* bad verifier, retry */
}
- len = p - (u32 *)iov->iov_base - 1;
+ len = p - (__be32 *)iov->iov_base - 1;
if (len < 0)
goto out_overflow;
switch ((n = ntohl(*p++))) {
@@ -1358,12 +1359,12 @@ out_overflow:
goto out_garbage;
}
-static int rpcproc_encode_null(void *rqstp, u32 *data, void *obj)
+static int rpcproc_encode_null(void *rqstp, __be32 *data, void *obj)
{
return 0;
}
-static int rpcproc_decode_null(void *rqstp, u32 *data, void *obj)
+static int rpcproc_decode_null(void *rqstp, __be32 *data, void *obj)
{
return 0;
}
diff --git a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
index c04609d3476a..e52afab413de 100644
--- a/net/sunrpc/pmap_clnt.c
+++ b/net/sunrpc/pmap_clnt.c
@@ -101,11 +101,13 @@ void rpc_getport(struct rpc_task *task)
/* Autobind on cloned rpc clients is discouraged */
BUG_ON(clnt->cl_parent != clnt);
- if (xprt_test_and_set_binding(xprt)) {
- task->tk_status = -EACCES; /* tell caller to check again */
- rpc_sleep_on(&xprt->binding, task, NULL, NULL);
- return;
- }
+ /* Put self on queue before sending rpcbind request, in case
+ * pmap_getport_done completes before we return from rpc_run_task */
+ rpc_sleep_on(&xprt->binding, task, NULL, NULL);
+
+ status = -EACCES; /* tell caller to check again */
+ if (xprt_test_and_set_binding(xprt))
+ goto bailout_nofree;
/* Someone else may have bound if we slept */
status = 0;
@@ -134,8 +136,6 @@ void rpc_getport(struct rpc_task *task)
goto bailout;
rpc_release_task(child);
- rpc_sleep_on(&xprt->binding, task, NULL, NULL);
-
task->tk_xprt->stat.bind_count++;
return;
@@ -300,7 +300,7 @@ static struct rpc_clnt *pmap_create(char *hostname, struct sockaddr_in *srvaddr,
/*
* XDR encode/decode functions for PMAP
*/
-static int xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct portmap_args *map)
+static int xdr_encode_mapping(struct rpc_rqst *req, __be32 *p, struct portmap_args *map)
{
dprintk("RPC: xdr_encode_mapping(%u, %u, %u, %u)\n",
map->pm_prog, map->pm_vers, map->pm_prot, map->pm_port);
@@ -313,13 +313,13 @@ static int xdr_encode_mapping(struct rpc_rqst *req, u32 *p, struct portmap_args
return 0;
}
-static int xdr_decode_port(struct rpc_rqst *req, u32 *p, unsigned short *portp)
+static int xdr_decode_port(struct rpc_rqst *req, __be32 *p, unsigned short *portp)
{
*portp = (unsigned short) ntohl(*p++);
return 0;
}
-static int xdr_decode_bool(struct rpc_rqst *req, u32 *p, unsigned int *boolp)
+static int xdr_decode_bool(struct rpc_rqst *req, __be32 *p, unsigned int *boolp)
{
*boolp = (unsigned int) ntohl(*p++);
return 0;
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index dfa504fe383f..9a0b41a97f90 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -488,14 +488,13 @@ rpc_get_inode(struct super_block *sb, int mode)
return NULL;
inode->i_mode = mode;
inode->i_uid = inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch(mode & S_IFMT) {
case S_IFDIR:
inode->i_fop = &simple_dir_operations;
inode->i_op = &simple_dir_inode_operations;
- inode->i_nlink++;
+ inc_nlink(inode);
default:
break;
}
@@ -572,7 +571,7 @@ rpc_populate(struct dentry *parent,
if (private)
rpc_inode_setowner(inode, private);
if (S_ISDIR(mode))
- dir->i_nlink++;
+ inc_nlink(dir);
d_add(dentry, inode);
}
mutex_unlock(&dir->i_mutex);
@@ -594,7 +593,7 @@ __rpc_mkdir(struct inode *dir, struct dentry *dentry)
goto out_err;
inode->i_ino = iunique(dir->i_sb, 100);
d_instantiate(dentry, inode);
- dir->i_nlink++;
+ inc_nlink(dir);
inode_dir_notify(dir, DN_CREATE);
return 0;
out_err:
@@ -858,7 +857,6 @@ int register_rpc_pipefs(void)
void unregister_rpc_pipefs(void)
{
- if (kmem_cache_destroy(rpc_inode_cachep))
- printk(KERN_WARNING "RPC: unable to free inode cache\n");
+ kmem_cache_destroy(rpc_inode_cachep);
unregister_filesystem(&rpc_pipe_fs_type);
}
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index 6390461a9756..a1ab4eed41f4 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -1059,10 +1059,10 @@ rpc_destroy_mempool(void)
mempool_destroy(rpc_buffer_mempool);
if (rpc_task_mempool)
mempool_destroy(rpc_task_mempool);
- if (rpc_task_slabp && kmem_cache_destroy(rpc_task_slabp))
- printk(KERN_INFO "rpc_task: not all structures were freed\n");
- if (rpc_buffer_slabp && kmem_cache_destroy(rpc_buffer_slabp))
- printk(KERN_INFO "rpc_buffers: not all structures were freed\n");
+ if (rpc_task_slabp)
+ kmem_cache_destroy(rpc_task_slabp);
+ if (rpc_buffer_slabp)
+ kmem_cache_destroy(rpc_buffer_slabp);
}
int
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 26c0531d7e25..192dff5dabcb 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -70,6 +70,8 @@ EXPORT_SYMBOL(put_rpccred);
/* RPC server stuff */
EXPORT_SYMBOL(svc_create);
EXPORT_SYMBOL(svc_create_thread);
+EXPORT_SYMBOL(svc_create_pooled);
+EXPORT_SYMBOL(svc_set_num_threads);
EXPORT_SYMBOL(svc_exit_thread);
EXPORT_SYMBOL(svc_destroy);
EXPORT_SYMBOL(svc_drop);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b76a227dd3ad..eb44ec929ca1 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -4,6 +4,10 @@
* High-level RPC service routines
*
* Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ *
+ * Multiple threads pools and NUMAisation
+ * Copyright (c) 2006 Silicon Graphics, Inc.
+ * by Greg Banks <gnb@melbourne.sgi.com>
*/
#include <linux/linkage.h>
@@ -12,6 +16,8 @@
#include <linux/net.h>
#include <linux/in.h>
#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
@@ -23,14 +29,252 @@
#define RPC_PARANOIA 1
/*
+ * Mode for mapping cpus to pools.
+ */
+enum {
+ SVC_POOL_NONE = -1, /* uninitialised, choose one of the others */
+ SVC_POOL_GLOBAL, /* no mapping, just a single global pool
+ * (legacy & UP mode) */
+ SVC_POOL_PERCPU, /* one pool per cpu */
+ SVC_POOL_PERNODE /* one pool per numa node */
+};
+
+/*
+ * Structure for mapping cpus to pools and vice versa.
+ * Setup once during sunrpc initialisation.
+ */
+static struct svc_pool_map {
+ int mode; /* Note: int not enum to avoid
+ * warnings about "enumeration value
+ * not handled in switch" */
+ unsigned int npools;
+ unsigned int *pool_to; /* maps pool id to cpu or node */
+ unsigned int *to_pool; /* maps cpu or node to pool id */
+} svc_pool_map = {
+ .mode = SVC_POOL_NONE
+};
+
+
+/*
+ * Detect best pool mapping mode heuristically,
+ * according to the machine's topology.
+ */
+static int
+svc_pool_map_choose_mode(void)
+{
+ unsigned int node;
+
+ if (num_online_nodes() > 1) {
+ /*
+ * Actually have multiple NUMA nodes,
+ * so split pools on NUMA node boundaries
+ */
+ return SVC_POOL_PERNODE;
+ }
+
+ node = any_online_node(node_online_map);
+ if (nr_cpus_node(node) > 2) {
+ /*
+ * Non-trivial SMP, or CONFIG_NUMA on
+ * non-NUMA hardware, e.g. with a generic
+ * x86_64 kernel on Xeons. In this case we
+ * want to divide the pools on cpu boundaries.
+ */
+ return SVC_POOL_PERCPU;
+ }
+
+ /* default: one global pool */
+ return SVC_POOL_GLOBAL;
+}
+
+/*
+ * Allocate the to_pool[] and pool_to[] arrays.
+ * Returns 0 on success or an errno.
+ */
+static int
+svc_pool_map_alloc_arrays(struct svc_pool_map *m, unsigned int maxpools)
+{
+ m->to_pool = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
+ if (!m->to_pool)
+ goto fail;
+ m->pool_to = kcalloc(maxpools, sizeof(unsigned int), GFP_KERNEL);
+ if (!m->pool_to)
+ goto fail_free;
+
+ return 0;
+
+fail_free:
+ kfree(m->to_pool);
+fail:
+ return -ENOMEM;
+}
+
+/*
+ * Initialise the pool map for SVC_POOL_PERCPU mode.
+ * Returns number of pools or <0 on error.
+ */
+static int
+svc_pool_map_init_percpu(struct svc_pool_map *m)
+{
+ unsigned int maxpools = highest_possible_processor_id()+1;
+ unsigned int pidx = 0;
+ unsigned int cpu;
+ int err;
+
+ err = svc_pool_map_alloc_arrays(m, maxpools);
+ if (err)
+ return err;
+
+ for_each_online_cpu(cpu) {
+ BUG_ON(pidx > maxpools);
+ m->to_pool[cpu] = pidx;
+ m->pool_to[pidx] = cpu;
+ pidx++;
+ }
+ /* cpus brought online later all get mapped to pool0, sorry */
+
+ return pidx;
+};
+
+
+/*
+ * Initialise the pool map for SVC_POOL_PERNODE mode.
+ * Returns number of pools or <0 on error.
+ */
+static int
+svc_pool_map_init_pernode(struct svc_pool_map *m)
+{
+ unsigned int maxpools = highest_possible_node_id()+1;
+ unsigned int pidx = 0;
+ unsigned int node;
+ int err;
+
+ err = svc_pool_map_alloc_arrays(m, maxpools);
+ if (err)
+ return err;
+
+ for_each_node_with_cpus(node) {
+ /* some architectures (e.g. SN2) have cpuless nodes */
+ BUG_ON(pidx > maxpools);
+ m->to_pool[node] = pidx;
+ m->pool_to[pidx] = node;
+ pidx++;
+ }
+ /* nodes brought online later all get mapped to pool0, sorry */
+
+ return pidx;
+}
+
+
+/*
+ * Build the global map of cpus to pools and vice versa.
+ */
+static unsigned int
+svc_pool_map_init(void)
+{
+ struct svc_pool_map *m = &svc_pool_map;
+ int npools = -1;
+
+ if (m->mode != SVC_POOL_NONE)
+ return m->npools;
+
+ m->mode = svc_pool_map_choose_mode();
+
+ switch (m->mode) {
+ case SVC_POOL_PERCPU:
+ npools = svc_pool_map_init_percpu(m);
+ break;
+ case SVC_POOL_PERNODE:
+ npools = svc_pool_map_init_pernode(m);
+ break;
+ }
+
+ if (npools < 0) {
+ /* default, or memory allocation failure */
+ npools = 1;
+ m->mode = SVC_POOL_GLOBAL;
+ }
+ m->npools = npools;
+
+ return m->npools;
+}
+
+/*
+ * Set the current thread's cpus_allowed mask so that it
+ * will only run on cpus in the given pool.
+ *
+ * Returns 1 and fills in oldmask iff a cpumask was applied.
+ */
+static inline int
+svc_pool_map_set_cpumask(unsigned int pidx, cpumask_t *oldmask)
+{
+ struct svc_pool_map *m = &svc_pool_map;
+ unsigned int node; /* or cpu */
+
+ /*
+ * The caller checks for sv_nrpools > 1, which
+ * implies that we've been initialized and the
+ * map mode is not NONE.
+ */
+ BUG_ON(m->mode == SVC_POOL_NONE);
+
+ switch (m->mode)
+ {
+ default:
+ return 0;
+ case SVC_POOL_PERCPU:
+ node = m->pool_to[pidx];
+ *oldmask = current->cpus_allowed;
+ set_cpus_allowed(current, cpumask_of_cpu(node));
+ return 1;
+ case SVC_POOL_PERNODE:
+ node = m->pool_to[pidx];
+ *oldmask = current->cpus_allowed;
+ set_cpus_allowed(current, node_to_cpumask(node));
+ return 1;
+ }
+}
+
+/*
+ * Use the mapping mode to choose a pool for a given CPU.
+ * Used when enqueueing an incoming RPC. Always returns
+ * a non-NULL pool pointer.
+ */
+struct svc_pool *
+svc_pool_for_cpu(struct svc_serv *serv, int cpu)
+{
+ struct svc_pool_map *m = &svc_pool_map;
+ unsigned int pidx = 0;
+
+ /*
+ * SVC_POOL_NONE happens in a pure client when
+ * lockd is brought up, so silently treat it the
+ * same as SVC_POOL_GLOBAL.
+ */
+
+ switch (m->mode) {
+ case SVC_POOL_PERCPU:
+ pidx = m->to_pool[cpu];
+ break;
+ case SVC_POOL_PERNODE:
+ pidx = m->to_pool[cpu_to_node(cpu)];
+ break;
+ }
+ return &serv->sv_pools[pidx % serv->sv_nrpools];
+}
+
+
+/*
* Create an RPC service
*/
-struct svc_serv *
-svc_create(struct svc_program *prog, unsigned int bufsize)
+static struct svc_serv *
+__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
+ void (*shutdown)(struct svc_serv *serv))
{
struct svc_serv *serv;
int vers;
unsigned int xdrsize;
+ unsigned int i;
if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
return NULL;
@@ -38,7 +282,11 @@ svc_create(struct svc_program *prog, unsigned int bufsize)
serv->sv_program = prog;
serv->sv_nrthreads = 1;
serv->sv_stats = prog->pg_stats;
- serv->sv_bufsz = bufsize? bufsize : 4096;
+ if (bufsize > RPCSVC_MAXPAYLOAD)
+ bufsize = RPCSVC_MAXPAYLOAD;
+ serv->sv_max_payload = bufsize? bufsize : 4096;
+ serv->sv_max_mesg = roundup(serv->sv_max_payload + PAGE_SIZE, PAGE_SIZE);
+ serv->sv_shutdown = shutdown;
xdrsize = 0;
while (prog) {
prog->pg_lovers = prog->pg_nvers-1;
@@ -53,20 +301,68 @@ svc_create(struct svc_program *prog, unsigned int bufsize)
prog = prog->pg_next;
}
serv->sv_xdrsize = xdrsize;
- INIT_LIST_HEAD(&serv->sv_threads);
- INIT_LIST_HEAD(&serv->sv_sockets);
INIT_LIST_HEAD(&serv->sv_tempsocks);
INIT_LIST_HEAD(&serv->sv_permsocks);
+ init_timer(&serv->sv_temptimer);
spin_lock_init(&serv->sv_lock);
+ serv->sv_nrpools = npools;
+ serv->sv_pools =
+ kcalloc(sizeof(struct svc_pool), serv->sv_nrpools,
+ GFP_KERNEL);
+ if (!serv->sv_pools) {
+ kfree(serv);
+ return NULL;
+ }
+
+ for (i = 0; i < serv->sv_nrpools; i++) {
+ struct svc_pool *pool = &serv->sv_pools[i];
+
+ dprintk("initialising pool %u for %s\n",
+ i, serv->sv_name);
+
+ pool->sp_id = i;
+ INIT_LIST_HEAD(&pool->sp_threads);
+ INIT_LIST_HEAD(&pool->sp_sockets);
+ INIT_LIST_HEAD(&pool->sp_all_threads);
+ spin_lock_init(&pool->sp_lock);
+ }
+
+
/* Remove any stale portmap registrations */
svc_register(serv, 0, 0);
return serv;
}
+struct svc_serv *
+svc_create(struct svc_program *prog, unsigned int bufsize,
+ void (*shutdown)(struct svc_serv *serv))
+{
+ return __svc_create(prog, bufsize, /*npools*/1, shutdown);
+}
+
+struct svc_serv *
+svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
+ void (*shutdown)(struct svc_serv *serv),
+ svc_thread_fn func, int sig, struct module *mod)
+{
+ struct svc_serv *serv;
+ unsigned int npools = svc_pool_map_init();
+
+ serv = __svc_create(prog, bufsize, npools, shutdown);
+
+ if (serv != NULL) {
+ serv->sv_function = func;
+ serv->sv_kill_signal = sig;
+ serv->sv_module = mod;
+ }
+
+ return serv;
+}
+
/*
- * Destroy an RPC service
+ * Destroy an RPC service. Should be called with the BKL held
*/
void
svc_destroy(struct svc_serv *serv)
@@ -85,12 +381,17 @@ svc_destroy(struct svc_serv *serv)
} else
printk("svc_destroy: no threads for serv=%p!\n", serv);
+ del_timer_sync(&serv->sv_temptimer);
+
while (!list_empty(&serv->sv_tempsocks)) {
svsk = list_entry(serv->sv_tempsocks.next,
struct svc_sock,
sk_list);
svc_delete_socket(svsk);
}
+ if (serv->sv_shutdown)
+ serv->sv_shutdown(serv);
+
while (!list_empty(&serv->sv_permsocks)) {
svsk = list_entry(serv->sv_permsocks.next,
struct svc_sock,
@@ -102,6 +403,7 @@ svc_destroy(struct svc_serv *serv)
/* Unregister service with the portmapper */
svc_register(serv, 0, 0);
+ kfree(serv->sv_pools);
kfree(serv);
}
@@ -115,21 +417,18 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
int pages;
int arghi;
- if (size > RPCSVC_MAXPAYLOAD)
- size = RPCSVC_MAXPAYLOAD;
- pages = 2 + (size+ PAGE_SIZE -1) / PAGE_SIZE;
- rqstp->rq_argused = 0;
- rqstp->rq_resused = 0;
+ pages = size / PAGE_SIZE + 1; /* extra page as we hold both request and reply.
+ * We assume one is at most one page
+ */
arghi = 0;
BUG_ON(pages > RPCSVC_MAXPAGES);
while (pages) {
struct page *p = alloc_page(GFP_KERNEL);
if (!p)
break;
- rqstp->rq_argpages[arghi++] = p;
+ rqstp->rq_pages[arghi++] = p;
pages--;
}
- rqstp->rq_arghi = arghi;
return ! pages;
}
@@ -139,24 +438,25 @@ svc_init_buffer(struct svc_rqst *rqstp, unsigned int size)
static void
svc_release_buffer(struct svc_rqst *rqstp)
{
- while (rqstp->rq_arghi)
- put_page(rqstp->rq_argpages[--rqstp->rq_arghi]);
- while (rqstp->rq_resused) {
- if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
- continue;
- put_page(rqstp->rq_respages[rqstp->rq_resused]);
- }
- rqstp->rq_argused = 0;
+ int i;
+ for (i=0; i<ARRAY_SIZE(rqstp->rq_pages); i++)
+ if (rqstp->rq_pages[i])
+ put_page(rqstp->rq_pages[i]);
}
/*
- * Create a server thread
+ * Create a thread in the given pool. Caller must hold BKL.
+ * On a NUMA or SMP machine, with a multi-pool serv, the thread
+ * will be restricted to run on the cpus belonging to the pool.
*/
-int
-svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
+static int
+__svc_create_thread(svc_thread_fn func, struct svc_serv *serv,
+ struct svc_pool *pool)
{
struct svc_rqst *rqstp;
int error = -ENOMEM;
+ int have_oldmask = 0;
+ cpumask_t oldmask;
rqstp = kzalloc(sizeof(*rqstp), GFP_KERNEL);
if (!rqstp)
@@ -166,12 +466,25 @@ svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
if (!(rqstp->rq_argp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
|| !(rqstp->rq_resp = kmalloc(serv->sv_xdrsize, GFP_KERNEL))
- || !svc_init_buffer(rqstp, serv->sv_bufsz))
+ || !svc_init_buffer(rqstp, serv->sv_max_mesg))
goto out_thread;
serv->sv_nrthreads++;
+ spin_lock_bh(&pool->sp_lock);
+ pool->sp_nrthreads++;
+ list_add(&rqstp->rq_all, &pool->sp_all_threads);
+ spin_unlock_bh(&pool->sp_lock);
rqstp->rq_server = serv;
+ rqstp->rq_pool = pool;
+
+ if (serv->sv_nrpools > 1)
+ have_oldmask = svc_pool_map_set_cpumask(pool->sp_id, &oldmask);
+
error = kernel_thread((int (*)(void *)) func, rqstp, 0);
+
+ if (have_oldmask)
+ set_cpus_allowed(current, oldmask);
+
if (error < 0)
goto out_thread;
svc_sock_update_bufs(serv);
@@ -185,17 +498,136 @@ out_thread:
}
/*
- * Destroy an RPC server thread
+ * Create a thread in the default pool. Caller must hold BKL.
+ */
+int
+svc_create_thread(svc_thread_fn func, struct svc_serv *serv)
+{
+ return __svc_create_thread(func, serv, &serv->sv_pools[0]);
+}
+
+/*
+ * Choose a pool in which to create a new thread, for svc_set_num_threads
+ */
+static inline struct svc_pool *
+choose_pool(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
+{
+ if (pool != NULL)
+ return pool;
+
+ return &serv->sv_pools[(*state)++ % serv->sv_nrpools];
+}
+
+/*
+ * Choose a thread to kill, for svc_set_num_threads
+ */
+static inline struct task_struct *
+choose_victim(struct svc_serv *serv, struct svc_pool *pool, unsigned int *state)
+{
+ unsigned int i;
+ struct task_struct *task = NULL;
+
+ if (pool != NULL) {
+ spin_lock_bh(&pool->sp_lock);
+ } else {
+ /* choose a pool in round-robin fashion */
+ for (i = 0; i < serv->sv_nrpools; i++) {
+ pool = &serv->sv_pools[--(*state) % serv->sv_nrpools];
+ spin_lock_bh(&pool->sp_lock);
+ if (!list_empty(&pool->sp_all_threads))
+ goto found_pool;
+ spin_unlock_bh(&pool->sp_lock);
+ }
+ return NULL;
+ }
+
+found_pool:
+ if (!list_empty(&pool->sp_all_threads)) {
+ struct svc_rqst *rqstp;
+
+ /*
+ * Remove from the pool->sp_all_threads list
+ * so we don't try to kill it again.
+ */
+ rqstp = list_entry(pool->sp_all_threads.next, struct svc_rqst, rq_all);
+ list_del_init(&rqstp->rq_all);
+ task = rqstp->rq_task;
+ }
+ spin_unlock_bh(&pool->sp_lock);
+
+ return task;
+}
+
+/*
+ * Create or destroy enough new threads to make the number
+ * of threads the given number. If `pool' is non-NULL, applies
+ * only to threads in that pool, otherwise round-robins between
+ * all pools. Must be called with a svc_get() reference and
+ * the BKL held.
+ *
+ * Destroying threads relies on the service threads filling in
+ * rqstp->rq_task, which only the nfs ones do. Assumes the serv
+ * has been created using svc_create_pooled().
+ *
+ * Based on code that used to be in nfsd_svc() but tweaked
+ * to be pool-aware.
+ */
+int
+svc_set_num_threads(struct svc_serv *serv, struct svc_pool *pool, int nrservs)
+{
+ struct task_struct *victim;
+ int error = 0;
+ unsigned int state = serv->sv_nrthreads-1;
+
+ if (pool == NULL) {
+ /* The -1 assumes caller has done a svc_get() */
+ nrservs -= (serv->sv_nrthreads-1);
+ } else {
+ spin_lock_bh(&pool->sp_lock);
+ nrservs -= pool->sp_nrthreads;
+ spin_unlock_bh(&pool->sp_lock);
+ }
+
+ /* create new threads */
+ while (nrservs > 0) {
+ nrservs--;
+ __module_get(serv->sv_module);
+ error = __svc_create_thread(serv->sv_function, serv,
+ choose_pool(serv, pool, &state));
+ if (error < 0) {
+ module_put(serv->sv_module);
+ break;
+ }
+ }
+ /* destroy old threads */
+ while (nrservs < 0 &&
+ (victim = choose_victim(serv, pool, &state)) != NULL) {
+ send_sig(serv->sv_kill_signal, victim, 1);
+ nrservs++;
+ }
+
+ return error;
+}
+
+/*
+ * Called from a server thread as it's exiting. Caller must hold BKL.
*/
void
svc_exit_thread(struct svc_rqst *rqstp)
{
struct svc_serv *serv = rqstp->rq_server;
+ struct svc_pool *pool = rqstp->rq_pool;
svc_release_buffer(rqstp);
kfree(rqstp->rq_resp);
kfree(rqstp->rq_argp);
kfree(rqstp->rq_auth_data);
+
+ spin_lock_bh(&pool->sp_lock);
+ pool->sp_nrthreads--;
+ list_del(&rqstp->rq_all);
+ spin_unlock_bh(&pool->sp_lock);
+
kfree(rqstp);
/* Release the server */
@@ -215,23 +647,32 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
unsigned long flags;
int i, error = 0, dummy;
- progp = serv->sv_program;
-
- dprintk("RPC: svc_register(%s, %s, %d)\n",
- progp->pg_name, proto == IPPROTO_UDP? "udp" : "tcp", port);
-
if (!port)
clear_thread_flag(TIF_SIGPENDING);
- for (i = 0; i < progp->pg_nvers; i++) {
- if (progp->pg_vers[i] == NULL)
- continue;
- error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
- if (error < 0)
- break;
- if (port && !dummy) {
- error = -EACCES;
- break;
+ for (progp = serv->sv_program; progp; progp = progp->pg_next) {
+ for (i = 0; i < progp->pg_nvers; i++) {
+ if (progp->pg_vers[i] == NULL)
+ continue;
+
+ dprintk("RPC: svc_register(%s, %s, %d, %d)%s\n",
+ progp->pg_name,
+ proto == IPPROTO_UDP? "udp" : "tcp",
+ port,
+ i,
+ progp->pg_vers[i]->vs_hidden?
+ " (but not telling portmap)" : "");
+
+ if (progp->pg_vers[i]->vs_hidden)
+ continue;
+
+ error = rpc_register(progp->pg_prog, i, proto, port, &dummy);
+ if (error < 0)
+ break;
+ if (port && !dummy) {
+ error = -EACCES;
+ break;
+ }
}
}
@@ -248,19 +689,20 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
* Process the RPC request.
*/
int
-svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
+svc_process(struct svc_rqst *rqstp)
{
struct svc_program *progp;
struct svc_version *versp = NULL; /* compiler food */
struct svc_procedure *procp = NULL;
struct kvec * argv = &rqstp->rq_arg.head[0];
struct kvec * resv = &rqstp->rq_res.head[0];
+ struct svc_serv *serv = rqstp->rq_server;
kxdrproc_t xdr;
- u32 *statp;
- u32 dir, prog, vers, proc,
- auth_stat, rpc_stat;
+ __be32 *statp;
+ u32 dir, prog, vers, proc;
+ __be32 auth_stat, rpc_stat;
int auth_res;
- u32 *accept_statp;
+ __be32 *reply_statp;
rpc_stat = rpc_success;
@@ -270,10 +712,10 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
/* setup response xdr_buf.
* Initially it has just one page
*/
- svc_take_page(rqstp); /* must succeed */
+ rqstp->rq_resused = 1;
resv->iov_base = page_address(rqstp->rq_respages[0]);
resv->iov_len = 0;
- rqstp->rq_res.pages = rqstp->rq_respages+1;
+ rqstp->rq_res.pages = rqstp->rq_respages + 1;
rqstp->rq_res.len = 0;
rqstp->rq_res.page_base = 0;
rqstp->rq_res.page_len = 0;
@@ -284,16 +726,16 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
rqstp->rq_sendfile_ok = 1;
/* tcp needs a space for the record length... */
if (rqstp->rq_prot == IPPROTO_TCP)
- svc_putu32(resv, 0);
+ svc_putnl(resv, 0);
rqstp->rq_xid = svc_getu32(argv);
svc_putu32(resv, rqstp->rq_xid);
- dir = ntohl(svc_getu32(argv));
- vers = ntohl(svc_getu32(argv));
+ dir = svc_getnl(argv);
+ vers = svc_getnl(argv);
/* First words of reply: */
- svc_putu32(resv, xdr_one); /* REPLY */
+ svc_putnl(resv, 1); /* REPLY */
if (dir != 0) /* direction != CALL */
goto err_bad_dir;
@@ -301,13 +743,13 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
goto err_bad_rpc;
/* Save position in case we later decide to reject: */
- accept_statp = resv->iov_base + resv->iov_len;
+ reply_statp = resv->iov_base + resv->iov_len;
- svc_putu32(resv, xdr_zero); /* ACCEPT */
+ svc_putnl(resv, 0); /* ACCEPT */
- rqstp->rq_prog = prog = ntohl(svc_getu32(argv)); /* program number */
- rqstp->rq_vers = vers = ntohl(svc_getu32(argv)); /* version number */
- rqstp->rq_proc = proc = ntohl(svc_getu32(argv)); /* procedure number */
+ rqstp->rq_prog = prog = svc_getnl(argv); /* program number */
+ rqstp->rq_vers = vers = svc_getnl(argv); /* version number */
+ rqstp->rq_proc = proc = svc_getnl(argv); /* procedure number */
progp = serv->sv_program;
@@ -361,7 +803,7 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
/* Build the reply header. */
statp = resv->iov_base +resv->iov_len;
- svc_putu32(resv, rpc_success); /* RPC_SUCCESS */
+ svc_putnl(resv, RPC_SUCCESS);
/* Bump per-procedure stats counter */
procp->pc_count++;
@@ -386,6 +828,11 @@ svc_process(struct svc_serv *serv, struct svc_rqst *rqstp)
*statp = procp->pc_func(rqstp, rqstp->rq_argp, rqstp->rq_resp);
/* Encode reply */
+ if (*statp == rpc_drop_reply) {
+ if (procp->pc_release)
+ procp->pc_release(rqstp, NULL, rqstp->rq_resp);
+ goto dropit;
+ }
if (*statp == rpc_success && (xdr = procp->pc_encode)
&& !xdr(rqstp, resv->iov_base+resv->iov_len, rqstp->rq_resp)) {
dprintk("svc: failed to encode reply\n");
@@ -439,26 +886,26 @@ err_bad_dir:
err_bad_rpc:
serv->sv_stats->rpcbadfmt++;
- svc_putu32(resv, xdr_one); /* REJECT */
- svc_putu32(resv, xdr_zero); /* RPC_MISMATCH */
- svc_putu32(resv, xdr_two); /* Only RPCv2 supported */
- svc_putu32(resv, xdr_two);
+ svc_putnl(resv, 1); /* REJECT */
+ svc_putnl(resv, 0); /* RPC_MISMATCH */
+ svc_putnl(resv, 2); /* Only RPCv2 supported */
+ svc_putnl(resv, 2);
goto sendit;
err_bad_auth:
dprintk("svc: authentication failed (%d)\n", ntohl(auth_stat));
serv->sv_stats->rpcbadauth++;
/* Restore write pointer to location of accept status: */
- xdr_ressize_check(rqstp, accept_statp);
- svc_putu32(resv, xdr_one); /* REJECT */
- svc_putu32(resv, xdr_one); /* AUTH_ERROR */
- svc_putu32(resv, auth_stat); /* status */
+ xdr_ressize_check(rqstp, reply_statp);
+ svc_putnl(resv, 1); /* REJECT */
+ svc_putnl(resv, 1); /* AUTH_ERROR */
+ svc_putnl(resv, ntohl(auth_stat)); /* status */
goto sendit;
err_bad_prog:
dprintk("svc: unknown program %d\n", prog);
serv->sv_stats->rpcbadfmt++;
- svc_putu32(resv, rpc_prog_unavail);
+ svc_putnl(resv, RPC_PROG_UNAVAIL);
goto sendit;
err_bad_vers:
@@ -466,9 +913,9 @@ err_bad_vers:
printk("svc: unknown version (%d)\n", vers);
#endif
serv->sv_stats->rpcbadfmt++;
- svc_putu32(resv, rpc_prog_mismatch);
- svc_putu32(resv, htonl(progp->pg_lovers));
- svc_putu32(resv, htonl(progp->pg_hivers));
+ svc_putnl(resv, RPC_PROG_MISMATCH);
+ svc_putnl(resv, progp->pg_lovers);
+ svc_putnl(resv, progp->pg_hivers);
goto sendit;
err_bad_proc:
@@ -476,7 +923,7 @@ err_bad_proc:
printk("svc: unknown procedure (%d)\n", proc);
#endif
serv->sv_stats->rpcbadfmt++;
- svc_putu32(resv, rpc_proc_unavail);
+ svc_putnl(resv, RPC_PROC_UNAVAIL);
goto sendit;
err_garbage:
@@ -486,6 +933,21 @@ err_garbage:
rpc_stat = rpc_garbage_args;
err_bad:
serv->sv_stats->rpcbadfmt++;
- svc_putu32(resv, rpc_stat);
+ svc_putnl(resv, ntohl(rpc_stat));
goto sendit;
}
+
+/*
+ * Return (transport-specific) limit on the rpc payload.
+ */
+u32 svc_max_payload(const struct svc_rqst *rqstp)
+{
+ int max = RPCSVC_MAXPAYLOAD_TCP;
+
+ if (rqstp->rq_sock->sk_sock->type == SOCK_DGRAM)
+ max = RPCSVC_MAXPAYLOAD_UDP;
+ if (rqstp->rq_server->sv_max_payload < max)
+ max = rqstp->rq_server->sv_max_payload;
+ return max;
+}
+EXPORT_SYMBOL_GPL(svc_max_payload);
diff --git a/net/sunrpc/svcauth.c b/net/sunrpc/svcauth.c
index 5b28c6176806..8f2320aded5c 100644
--- a/net/sunrpc/svcauth.c
+++ b/net/sunrpc/svcauth.c
@@ -35,14 +35,14 @@ static struct auth_ops *authtab[RPC_AUTH_MAXFLAVOR] = {
};
int
-svc_authenticate(struct svc_rqst *rqstp, u32 *authp)
+svc_authenticate(struct svc_rqst *rqstp, __be32 *authp)
{
rpc_authflavor_t flavor;
struct auth_ops *aops;
*authp = rpc_auth_ok;
- flavor = ntohl(svc_getu32(&rqstp->rq_arg.head[0]));
+ flavor = svc_getnl(&rqstp->rq_arg.head[0]);
dprintk("svc: svc_authenticate (%d)\n", flavor);
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 7e5707e2d6b6..e1bd933629fe 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -9,6 +9,7 @@
#include <linux/seq_file.h>
#include <linux/hash.h>
#include <linux/string.h>
+#include <net/sock.h>
#define RPCDBG_FACILITY RPCDBG_AUTH
@@ -145,7 +146,7 @@ static void ip_map_request(struct cache_detail *cd,
{
char text_addr[20];
struct ip_map *im = container_of(h, struct ip_map, h);
- __u32 addr = im->m_addr.s_addr;
+ __be32 addr = im->m_addr.s_addr;
snprintf(text_addr, 20, "%u.%u.%u.%u",
ntohl(addr) >> 24 & 0xff,
@@ -249,10 +250,10 @@ static int ip_map_show(struct seq_file *m,
seq_printf(m, "%s %d.%d.%d.%d %s\n",
im->m_class,
- htonl(addr.s_addr) >> 24 & 0xff,
- htonl(addr.s_addr) >> 16 & 0xff,
- htonl(addr.s_addr) >> 8 & 0xff,
- htonl(addr.s_addr) >> 0 & 0xff,
+ ntohl(addr.s_addr) >> 24 & 0xff,
+ ntohl(addr.s_addr) >> 16 & 0xff,
+ ntohl(addr.s_addr) >> 8 & 0xff,
+ ntohl(addr.s_addr) >> 0 & 0xff,
dom
);
return 0;
@@ -348,12 +349,9 @@ int auth_unix_forget_old(struct auth_domain *dom)
struct auth_domain *auth_unix_lookup(struct in_addr addr)
{
- struct ip_map key, *ipm;
+ struct ip_map *ipm;
struct auth_domain *rv;
- strcpy(key.m_class, "nfsd");
- key.m_addr = addr;
-
ipm = ip_map_lookup("nfsd", addr);
if (!ipm)
@@ -378,6 +376,44 @@ void svcauth_unix_purge(void)
cache_purge(&ip_map_cache);
}
+static inline struct ip_map *
+ip_map_cached_get(struct svc_rqst *rqstp)
+{
+ struct ip_map *ipm = rqstp->rq_sock->sk_info_authunix;
+ if (ipm != NULL) {
+ if (!cache_valid(&ipm->h)) {
+ /*
+ * The entry has been invalidated since it was
+ * remembered, e.g. by a second mount from the
+ * same IP address.
+ */
+ rqstp->rq_sock->sk_info_authunix = NULL;
+ cache_put(&ipm->h, &ip_map_cache);
+ return NULL;
+ }
+ cache_get(&ipm->h);
+ }
+ return ipm;
+}
+
+static inline void
+ip_map_cached_put(struct svc_rqst *rqstp, struct ip_map *ipm)
+{
+ struct svc_sock *svsk = rqstp->rq_sock;
+
+ if (svsk->sk_sock->type == SOCK_STREAM && svsk->sk_info_authunix == NULL)
+ svsk->sk_info_authunix = ipm; /* newly cached, keep the reference */
+ else
+ cache_put(&ipm->h, &ip_map_cache);
+}
+
+void
+svcauth_unix_info_release(void *info)
+{
+ struct ip_map *ipm = info;
+ cache_put(&ipm->h, &ip_map_cache);
+}
+
static int
svcauth_unix_set_client(struct svc_rqst *rqstp)
{
@@ -387,8 +423,10 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
if (rqstp->rq_proc == 0)
return SVC_OK;
- ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
- rqstp->rq_addr.sin_addr);
+ ipm = ip_map_cached_get(rqstp);
+ if (ipm == NULL)
+ ipm = ip_map_lookup(rqstp->rq_server->sv_program->pg_class,
+ rqstp->rq_addr.sin_addr);
if (ipm == NULL)
return SVC_DENIED;
@@ -403,14 +441,14 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
case 0:
rqstp->rq_client = &ipm->m_client->h;
kref_get(&rqstp->rq_client->ref);
- cache_put(&ipm->h, &ip_map_cache);
+ ip_map_cached_put(rqstp, ipm);
break;
}
return SVC_OK;
}
static int
-svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp)
+svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
@@ -427,7 +465,7 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp)
*authp = rpc_autherr_badcred;
return SVC_DENIED;
}
- if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
+ if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
dprintk("svc: bad null verf\n");
*authp = rpc_autherr_badverf;
return SVC_DENIED;
@@ -441,8 +479,8 @@ svcauth_null_accept(struct svc_rqst *rqstp, u32 *authp)
return SVC_DROP; /* kmalloc failure - client must retry */
/* Put NULL verifier */
- svc_putu32(resv, RPC_AUTH_NULL);
- svc_putu32(resv, 0);
+ svc_putnl(resv, RPC_AUTH_NULL);
+ svc_putnl(resv, 0);
return SVC_OK;
}
@@ -472,7 +510,7 @@ struct auth_ops svcauth_null = {
static int
-svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
+svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
{
struct kvec *argv = &rqstp->rq_arg.head[0];
struct kvec *resv = &rqstp->rq_res.head[0];
@@ -488,31 +526,31 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
svc_getu32(argv); /* length */
svc_getu32(argv); /* time stamp */
- slen = XDR_QUADLEN(ntohl(svc_getu32(argv))); /* machname length */
+ slen = XDR_QUADLEN(svc_getnl(argv)); /* machname length */
if (slen > 64 || (len -= (slen + 3)*4) < 0)
goto badcred;
- argv->iov_base = (void*)((u32*)argv->iov_base + slen); /* skip machname */
+ argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */
argv->iov_len -= slen*4;
- cred->cr_uid = ntohl(svc_getu32(argv)); /* uid */
- cred->cr_gid = ntohl(svc_getu32(argv)); /* gid */
- slen = ntohl(svc_getu32(argv)); /* gids length */
+ cred->cr_uid = svc_getnl(argv); /* uid */
+ cred->cr_gid = svc_getnl(argv); /* gid */
+ slen = svc_getnl(argv); /* gids length */
if (slen > 16 || (len -= (slen + 2)*4) < 0)
goto badcred;
cred->cr_group_info = groups_alloc(slen);
if (cred->cr_group_info == NULL)
return SVC_DROP;
for (i = 0; i < slen; i++)
- GROUP_AT(cred->cr_group_info, i) = ntohl(svc_getu32(argv));
+ GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
- if (svc_getu32(argv) != RPC_AUTH_NULL || svc_getu32(argv) != 0) {
+ if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
*authp = rpc_autherr_badverf;
return SVC_DENIED;
}
/* Put NULL verifier */
- svc_putu32(resv, RPC_AUTH_NULL);
- svc_putu32(resv, 0);
+ svc_putnl(resv, RPC_AUTH_NULL);
+ svc_putnl(resv, 0);
return SVC_OK;
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 953aff89bcac..96521f16342b 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
+#include <linux/file.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <net/ip.h>
@@ -45,13 +46,16 @@
/* SMP locking strategy:
*
- * svc_serv->sv_lock protects most stuff for that service.
+ * svc_pool->sp_lock protects most of the fields of that pool.
+ * 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_flags.SK_BUSY prevents a svc_sock being enqueued multiply.
*
* Some flags can be set to certain values at any time
* providing that certain rules are followed:
*
- * SK_BUSY can be set to 0 at any time.
- * svc_sock_enqueue must be called afterwards
* SK_CONN, SK_DATA, can be set or cleared at any time.
* after a set, svc_sock_enqueue must be called.
* after a clear, the socket must be read/accepted
@@ -73,23 +77,30 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk);
static int svc_deferred_recv(struct svc_rqst *rqstp);
static struct cache_deferred_req *svc_defer(struct cache_req *req);
+/* apparently the "standard" is that clients close
+ * idle connections after 5 minutes, servers after
+ * 6 minutes
+ * http://www.connectathon.org/talks96/nfstcp.pdf
+ */
+static int svc_conn_age_period = 6*60;
+
/*
- * Queue up an idle server thread. Must have serv->sv_lock held.
+ * Queue up an idle server thread. Must have pool->sp_lock held.
* Note: this is really a stack rather than a queue, so that we only
- * use as many different threads as we need, and the rest don't polute
+ * use as many different threads as we need, and the rest don't pollute
* the cache.
*/
static inline void
-svc_serv_enqueue(struct svc_serv *serv, struct svc_rqst *rqstp)
+svc_thread_enqueue(struct svc_pool *pool, struct svc_rqst *rqstp)
{
- list_add(&rqstp->rq_list, &serv->sv_threads);
+ list_add(&rqstp->rq_list, &pool->sp_threads);
}
/*
- * Dequeue an nfsd thread. Must have serv->sv_lock held.
+ * Dequeue an nfsd thread. Must have pool->sp_lock held.
*/
static inline void
-svc_serv_dequeue(struct svc_serv *serv, struct svc_rqst *rqstp)
+svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp)
{
list_del(&rqstp->rq_list);
}
@@ -140,7 +151,9 @@ static void
svc_sock_enqueue(struct svc_sock *svsk)
{
struct svc_serv *serv = svsk->sk_server;
+ struct svc_pool *pool;
struct svc_rqst *rqstp;
+ int cpu;
if (!(svsk->sk_flags &
( (1<<SK_CONN)|(1<<SK_DATA)|(1<<SK_CLOSE)|(1<<SK_DEFERRED)) ))
@@ -148,10 +161,14 @@ svc_sock_enqueue(struct svc_sock *svsk)
if (test_bit(SK_DEAD, &svsk->sk_flags))
return;
- spin_lock_bh(&serv->sv_lock);
+ cpu = get_cpu();
+ pool = svc_pool_for_cpu(svsk->sk_server, cpu);
+ put_cpu();
+
+ spin_lock_bh(&pool->sp_lock);
- if (!list_empty(&serv->sv_threads) &&
- !list_empty(&serv->sv_sockets))
+ if (!list_empty(&pool->sp_threads) &&
+ !list_empty(&pool->sp_sockets))
printk(KERN_ERR
"svc_sock_enqueue: threads and sockets both waiting??\n");
@@ -161,73 +178,79 @@ svc_sock_enqueue(struct svc_sock *svsk)
goto out_unlock;
}
- if (test_bit(SK_BUSY, &svsk->sk_flags)) {
- /* Don't enqueue socket while daemon is receiving */
+ /* Mark socket as busy. It will remain in this state until the
+ * server has processed all pending data and put the socket back
+ * on the idle list. We update SK_BUSY atomically because
+ * it also guards against trying to enqueue the svc_sock twice.
+ */
+ if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) {
+ /* Don't enqueue socket while already enqueued */
dprintk("svc: socket %p busy, not enqueued\n", svsk->sk_sk);
goto out_unlock;
}
+ BUG_ON(svsk->sk_pool != NULL);
+ svsk->sk_pool = pool;
set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
- if (((svsk->sk_reserved + serv->sv_bufsz)*2
+ if (((atomic_read(&svsk->sk_reserved) + serv->sv_max_mesg)*2
> svc_sock_wspace(svsk))
&& !test_bit(SK_CLOSE, &svsk->sk_flags)
&& !test_bit(SK_CONN, &svsk->sk_flags)) {
/* Don't enqueue while not enough space for reply */
dprintk("svc: socket %p no space, %d*2 > %ld, not enqueued\n",
- svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
+ svsk->sk_sk, atomic_read(&svsk->sk_reserved)+serv->sv_max_mesg,
svc_sock_wspace(svsk));
+ svsk->sk_pool = NULL;
+ clear_bit(SK_BUSY, &svsk->sk_flags);
goto out_unlock;
}
clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
- /* Mark socket as busy. It will remain in this state until the
- * server has processed all pending data and put the socket back
- * on the idle list.
- */
- set_bit(SK_BUSY, &svsk->sk_flags);
- if (!list_empty(&serv->sv_threads)) {
- rqstp = list_entry(serv->sv_threads.next,
+ if (!list_empty(&pool->sp_threads)) {
+ rqstp = list_entry(pool->sp_threads.next,
struct svc_rqst,
rq_list);
dprintk("svc: socket %p served by daemon %p\n",
svsk->sk_sk, rqstp);
- svc_serv_dequeue(serv, rqstp);
+ svc_thread_dequeue(pool, rqstp);
if (rqstp->rq_sock)
printk(KERN_ERR
"svc_sock_enqueue: server %p, rq_sock=%p!\n",
rqstp, rqstp->rq_sock);
rqstp->rq_sock = svsk;
- svsk->sk_inuse++;
- rqstp->rq_reserved = serv->sv_bufsz;
- svsk->sk_reserved += rqstp->rq_reserved;
+ atomic_inc(&svsk->sk_inuse);
+ rqstp->rq_reserved = serv->sv_max_mesg;
+ atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
+ BUG_ON(svsk->sk_pool != pool);
wake_up(&rqstp->rq_wait);
} else {
dprintk("svc: socket %p put into queue\n", svsk->sk_sk);
- list_add_tail(&svsk->sk_ready, &serv->sv_sockets);
+ list_add_tail(&svsk->sk_ready, &pool->sp_sockets);
+ BUG_ON(svsk->sk_pool != pool);
}
out_unlock:
- spin_unlock_bh(&serv->sv_lock);
+ spin_unlock_bh(&pool->sp_lock);
}
/*
- * Dequeue the first socket. Must be called with the serv->sv_lock held.
+ * Dequeue the first socket. Must be called with the pool->sp_lock held.
*/
static inline struct svc_sock *
-svc_sock_dequeue(struct svc_serv *serv)
+svc_sock_dequeue(struct svc_pool *pool)
{
struct svc_sock *svsk;
- if (list_empty(&serv->sv_sockets))
+ if (list_empty(&pool->sp_sockets))
return NULL;
- svsk = list_entry(serv->sv_sockets.next,
+ svsk = list_entry(pool->sp_sockets.next,
struct svc_sock, sk_ready);
list_del_init(&svsk->sk_ready);
dprintk("svc: socket %p dequeued, inuse=%d\n",
- svsk->sk_sk, svsk->sk_inuse);
+ svsk->sk_sk, atomic_read(&svsk->sk_inuse));
return svsk;
}
@@ -241,6 +264,7 @@ svc_sock_dequeue(struct svc_serv *serv)
static inline void
svc_sock_received(struct svc_sock *svsk)
{
+ svsk->sk_pool = NULL;
clear_bit(SK_BUSY, &svsk->sk_flags);
svc_sock_enqueue(svsk);
}
@@ -262,10 +286,8 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
if (space < rqstp->rq_reserved) {
struct svc_sock *svsk = rqstp->rq_sock;
- spin_lock_bh(&svsk->sk_server->sv_lock);
- svsk->sk_reserved -= (rqstp->rq_reserved - space);
+ atomic_sub((rqstp->rq_reserved - space), &svsk->sk_reserved);
rqstp->rq_reserved = space;
- spin_unlock_bh(&svsk->sk_server->sv_lock);
svc_sock_enqueue(svsk);
}
@@ -277,17 +299,11 @@ void svc_reserve(struct svc_rqst *rqstp, int space)
static inline void
svc_sock_put(struct svc_sock *svsk)
{
- struct svc_serv *serv = svsk->sk_server;
-
- spin_lock_bh(&serv->sv_lock);
- if (!--(svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {
- spin_unlock_bh(&serv->sv_lock);
+ if (atomic_dec_and_test(&svsk->sk_inuse) && test_bit(SK_DEAD, &svsk->sk_flags)) {
dprintk("svc: releasing dead socket\n");
sock_release(svsk->sk_sock);
kfree(svsk);
}
- else
- spin_unlock_bh(&serv->sv_lock);
}
static void
@@ -297,7 +313,7 @@ svc_sock_release(struct svc_rqst *rqstp)
svc_release_skb(rqstp);
- svc_free_allpages(rqstp);
+ svc_free_res_pages(rqstp);
rqstp->rq_res.page_len = 0;
rqstp->rq_res.page_base = 0;
@@ -321,25 +337,33 @@ svc_sock_release(struct svc_rqst *rqstp)
/*
* External function to wake up a server waiting for data
+ * This really only makes sense for services like lockd
+ * which have exactly one thread anyway.
*/
void
svc_wake_up(struct svc_serv *serv)
{
struct svc_rqst *rqstp;
-
- spin_lock_bh(&serv->sv_lock);
- if (!list_empty(&serv->sv_threads)) {
- rqstp = list_entry(serv->sv_threads.next,
- struct svc_rqst,
- rq_list);
- dprintk("svc: daemon %p woken up.\n", rqstp);
- /*
- svc_serv_dequeue(serv, rqstp);
- rqstp->rq_sock = NULL;
- */
- wake_up(&rqstp->rq_wait);
+ unsigned int i;
+ struct svc_pool *pool;
+
+ for (i = 0; i < serv->sv_nrpools; i++) {
+ pool = &serv->sv_pools[i];
+
+ spin_lock_bh(&pool->sp_lock);
+ if (!list_empty(&pool->sp_threads)) {
+ rqstp = list_entry(pool->sp_threads.next,
+ struct svc_rqst,
+ rq_list);
+ dprintk("svc: daemon %p woken up.\n", rqstp);
+ /*
+ svc_thread_dequeue(pool, rqstp);
+ rqstp->rq_sock = NULL;
+ */
+ wake_up(&rqstp->rq_wait);
+ }
+ spin_unlock_bh(&pool->sp_lock);
}
- spin_unlock_bh(&serv->sv_lock);
}
/*
@@ -388,7 +412,8 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
/* send head */
if (slen == xdr->head[0].iov_len)
flags = 0;
- len = kernel_sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags);
+ len = kernel_sendpage(sock, rqstp->rq_respages[0], 0,
+ xdr->head[0].iov_len, flags);
if (len != xdr->head[0].iov_len)
goto out;
slen -= xdr->head[0].iov_len;
@@ -413,8 +438,9 @@ svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
}
/* send tail */
if (xdr->tail[0].iov_len) {
- result = kernel_sendpage(sock, rqstp->rq_respages[rqstp->rq_restailpage],
- ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1),
+ result = kernel_sendpage(sock, rqstp->rq_respages[0],
+ ((unsigned long)xdr->tail[0].iov_base)
+ & (PAGE_SIZE-1),
xdr->tail[0].iov_len, 0);
if (result > 0)
@@ -429,6 +455,56 @@ out:
}
/*
+ * Report socket names for nfsdfs
+ */
+static int one_sock_name(char *buf, struct svc_sock *svsk)
+{
+ int len;
+
+ switch(svsk->sk_sk->sk_family) {
+ case AF_INET:
+ len = sprintf(buf, "ipv4 %s %u.%u.%u.%u %d\n",
+ svsk->sk_sk->sk_protocol==IPPROTO_UDP?
+ "udp" : "tcp",
+ NIPQUAD(inet_sk(svsk->sk_sk)->rcv_saddr),
+ inet_sk(svsk->sk_sk)->num);
+ break;
+ default:
+ len = sprintf(buf, "*unknown-%d*\n",
+ svsk->sk_sk->sk_family);
+ }
+ return len;
+}
+
+int
+svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
+{
+ struct svc_sock *svsk, *closesk = NULL;
+ int len = 0;
+
+ if (!serv)
+ return 0;
+ spin_lock(&serv->sv_lock);
+ list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
+ int onelen = one_sock_name(buf+len, svsk);
+ if (toclose && strcmp(toclose, buf+len) == 0)
+ closesk = svsk;
+ else
+ len += onelen;
+ }
+ spin_unlock(&serv->sv_lock);
+ if (closesk)
+ /* Should unregister with portmap, but you cannot
+ * unregister just one protocol...
+ */
+ svc_delete_socket(closesk);
+ else if (toclose)
+ return -ENOENT;
+ return len;
+}
+EXPORT_SYMBOL(svc_sock_names);
+
+/*
* Check input queue length
*/
static int
@@ -557,11 +633,14 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
/* udp sockets need large rcvbuf as all pending
* requests are still in that buffer. sndbuf must
* also be large enough that there is enough space
- * for one reply per thread.
+ * for one reply per thread. We count all threads
+ * rather than threads in a particular pool, which
+ * provides an upper bound on the number of threads
+ * which will access the socket.
*/
svc_sock_setbufsize(svsk->sk_sock,
- (serv->sv_nrthreads+3) * serv->sv_bufsz,
- (serv->sv_nrthreads+3) * serv->sv_bufsz);
+ (serv->sv_nrthreads+3) * serv->sv_max_mesg,
+ (serv->sv_nrthreads+3) * serv->sv_max_mesg);
if ((rqstp->rq_deferred = svc_deferred_dequeue(svsk))) {
svc_sock_received(svsk);
@@ -631,9 +710,11 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
if (len <= rqstp->rq_arg.head[0].iov_len) {
rqstp->rq_arg.head[0].iov_len = len;
rqstp->rq_arg.page_len = 0;
+ rqstp->rq_respages = rqstp->rq_pages+1;
} else {
rqstp->rq_arg.page_len = len - rqstp->rq_arg.head[0].iov_len;
- rqstp->rq_argused += (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
+ rqstp->rq_respages = rqstp->rq_pages + 1 +
+ (rqstp->rq_arg.page_len + PAGE_SIZE - 1)/ PAGE_SIZE;
}
if (serv->sv_stats)
@@ -668,8 +749,8 @@ svc_udp_init(struct svc_sock *svsk)
* svc_udp_recvfrom will re-adjust if necessary
*/
svc_sock_setbufsize(svsk->sk_sock,
- 3 * svsk->sk_server->sv_bufsz,
- 3 * svsk->sk_server->sv_bufsz);
+ 3 * svsk->sk_server->sv_max_mesg,
+ 3 * svsk->sk_server->sv_max_mesg);
set_bit(SK_DATA, &svsk->sk_flags); /* might have come in before data_ready set up */
set_bit(SK_CHNGBUF, &svsk->sk_flags);
@@ -844,7 +925,7 @@ svc_tcp_accept(struct svc_sock *svsk)
struct svc_sock,
sk_list);
set_bit(SK_CLOSE, &svsk->sk_flags);
- svsk->sk_inuse ++;
+ atomic_inc(&svsk->sk_inuse);
}
spin_unlock_bh(&serv->sv_lock);
@@ -874,7 +955,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
struct svc_sock *svsk = rqstp->rq_sock;
struct svc_serv *serv = svsk->sk_server;
int len;
- struct kvec vec[RPCSVC_MAXPAGES];
+ struct kvec *vec;
int pnum, vlen;
dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
@@ -892,7 +973,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
return 0;
}
- if (test_bit(SK_CONN, &svsk->sk_flags)) {
+ if (svsk->sk_sk->sk_state == TCP_LISTEN) {
svc_tcp_accept(svsk);
svc_sock_received(svsk);
return 0;
@@ -902,13 +983,18 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
/* sndbuf needs to have room for one request
* per thread, otherwise we can stall even when the
* network isn't a bottleneck.
+ *
+ * We count all threads rather than threads in a
+ * particular pool, which provides an upper bound
+ * on the number of threads which will access the socket.
+ *
* rcvbuf just needs to be able to hold a few requests.
* Normally they will be removed from the queue
* as soon a a complete request arrives.
*/
svc_sock_setbufsize(svsk->sk_sock,
- (serv->sv_nrthreads+3) * serv->sv_bufsz,
- 3 * serv->sv_bufsz);
+ (serv->sv_nrthreads+3) * serv->sv_max_mesg,
+ 3 * serv->sv_max_mesg);
clear_bit(SK_DATA, &svsk->sk_flags);
@@ -946,7 +1032,7 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
}
svsk->sk_reclen &= 0x7fffffff;
dprintk("svc: TCP record, %d bytes\n", svsk->sk_reclen);
- if (svsk->sk_reclen > serv->sv_bufsz) {
+ if (svsk->sk_reclen > serv->sv_max_mesg) {
printk(KERN_NOTICE "RPC: bad TCP reclen 0x%08lx (large)\n",
(unsigned long) svsk->sk_reclen);
goto err_delete;
@@ -967,15 +1053,17 @@ svc_tcp_recvfrom(struct svc_rqst *rqstp)
len = svsk->sk_reclen;
set_bit(SK_DATA, &svsk->sk_flags);
+ vec = rqstp->rq_vec;
vec[0] = rqstp->rq_arg.head[0];
vlen = PAGE_SIZE;
pnum = 1;
while (vlen < len) {
- vec[pnum].iov_base = page_address(rqstp->rq_argpages[rqstp->rq_argused++]);
+ vec[pnum].iov_base = page_address(rqstp->rq_pages[pnum]);
vec[pnum].iov_len = PAGE_SIZE;
pnum++;
vlen += PAGE_SIZE;
}
+ rqstp->rq_respages = &rqstp->rq_pages[pnum];
/* Now receive data */
len = svc_recvfrom(rqstp, vec, pnum, len);
@@ -1030,7 +1118,7 @@ svc_tcp_sendto(struct svc_rqst *rqstp)
{
struct xdr_buf *xbufp = &rqstp->rq_res;
int sent;
- u32 reclen;
+ __be32 reclen;
/* Set up the first element of the reply kvec.
* Any other kvecs that may be in use have been taken
@@ -1083,8 +1171,8 @@ svc_tcp_init(struct svc_sock *svsk)
* svc_tcp_recvfrom will re-adjust if necessary
*/
svc_sock_setbufsize(svsk->sk_sock,
- 3 * svsk->sk_server->sv_bufsz,
- 3 * svsk->sk_server->sv_bufsz);
+ 3 * svsk->sk_server->sv_max_mesg,
+ 3 * svsk->sk_server->sv_max_mesg);
set_bit(SK_CHNGBUF, &svsk->sk_flags);
set_bit(SK_DATA, &svsk->sk_flags);
@@ -1117,13 +1205,17 @@ svc_sock_update_bufs(struct svc_serv *serv)
}
/*
- * Receive the next request on any socket.
+ * Receive the next request on any socket. This code is carefully
+ * organised not to touch any cachelines in the shared svc_serv
+ * structure, only cachelines in the local svc_pool.
*/
int
-svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
+svc_recv(struct svc_rqst *rqstp, long timeout)
{
struct svc_sock *svsk =NULL;
- int len;
+ struct svc_serv *serv = rqstp->rq_server;
+ struct svc_pool *pool = rqstp->rq_pool;
+ int len, i;
int pages;
struct xdr_buf *arg;
DECLARE_WAITQUEUE(wait, current);
@@ -1140,27 +1232,22 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
"svc_recv: service %p, wait queue active!\n",
rqstp);
- /* Initialize the buffers */
- /* first reclaim pages that were moved to response list */
- svc_pushback_allpages(rqstp);
/* now allocate needed pages. If we get a failure, sleep briefly */
- pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE;
- while (rqstp->rq_arghi < pages) {
- struct page *p = alloc_page(GFP_KERNEL);
- if (!p) {
- schedule_timeout_uninterruptible(msecs_to_jiffies(500));
- continue;
+ pages = (serv->sv_max_mesg + PAGE_SIZE) / PAGE_SIZE;
+ for (i=0; i < pages ; i++)
+ while (rqstp->rq_pages[i] == NULL) {
+ struct page *p = alloc_page(GFP_KERNEL);
+ if (!p)
+ schedule_timeout_uninterruptible(msecs_to_jiffies(500));
+ rqstp->rq_pages[i] = p;
}
- rqstp->rq_argpages[rqstp->rq_arghi++] = p;
- }
/* Make arg->head point to first page and arg->pages point to rest */
arg = &rqstp->rq_arg;
- arg->head[0].iov_base = page_address(rqstp->rq_argpages[0]);
+ arg->head[0].iov_base = page_address(rqstp->rq_pages[0]);
arg->head[0].iov_len = PAGE_SIZE;
- rqstp->rq_argused = 1;
- arg->pages = rqstp->rq_argpages + 1;
+ arg->pages = rqstp->rq_pages + 1;
arg->page_base = 0;
/* save at least one page for response */
arg->page_len = (pages-2)*PAGE_SIZE;
@@ -1172,32 +1259,15 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
if (signalled())
return -EINTR;
- spin_lock_bh(&serv->sv_lock);
- if (!list_empty(&serv->sv_tempsocks)) {
- svsk = list_entry(serv->sv_tempsocks.next,
- struct svc_sock, sk_list);
- /* apparently the "standard" is that clients close
- * idle connections after 5 minutes, servers after
- * 6 minutes
- * http://www.connectathon.org/talks96/nfstcp.pdf
- */
- if (get_seconds() - svsk->sk_lastrecv < 6*60
- || test_bit(SK_BUSY, &svsk->sk_flags))
- svsk = NULL;
- }
- if (svsk) {
- set_bit(SK_BUSY, &svsk->sk_flags);
- set_bit(SK_CLOSE, &svsk->sk_flags);
- rqstp->rq_sock = svsk;
- svsk->sk_inuse++;
- } else if ((svsk = svc_sock_dequeue(serv)) != NULL) {
+ spin_lock_bh(&pool->sp_lock);
+ if ((svsk = svc_sock_dequeue(pool)) != NULL) {
rqstp->rq_sock = svsk;
- svsk->sk_inuse++;
- rqstp->rq_reserved = serv->sv_bufsz;
- svsk->sk_reserved += rqstp->rq_reserved;
+ atomic_inc(&svsk->sk_inuse);
+ rqstp->rq_reserved = serv->sv_max_mesg;
+ atomic_add(rqstp->rq_reserved, &svsk->sk_reserved);
} else {
/* No data pending. Go to sleep */
- svc_serv_enqueue(serv, rqstp);
+ svc_thread_enqueue(pool, rqstp);
/*
* We have to be able to interrupt this wait
@@ -1205,26 +1275,26 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
*/
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&rqstp->rq_wait, &wait);
- spin_unlock_bh(&serv->sv_lock);
+ spin_unlock_bh(&pool->sp_lock);
schedule_timeout(timeout);
try_to_freeze();
- spin_lock_bh(&serv->sv_lock);
+ spin_lock_bh(&pool->sp_lock);
remove_wait_queue(&rqstp->rq_wait, &wait);
if (!(svsk = rqstp->rq_sock)) {
- svc_serv_dequeue(serv, rqstp);
- spin_unlock_bh(&serv->sv_lock);
+ svc_thread_dequeue(pool, rqstp);
+ spin_unlock_bh(&pool->sp_lock);
dprintk("svc: server %p, no data yet\n", rqstp);
return signalled()? -EINTR : -EAGAIN;
}
}
- spin_unlock_bh(&serv->sv_lock);
+ spin_unlock_bh(&pool->sp_lock);
- dprintk("svc: server %p, socket %p, inuse=%d\n",
- rqstp, svsk, svsk->sk_inuse);
+ dprintk("svc: server %p, pool %u, socket %p, inuse=%d\n",
+ rqstp, pool->sp_id, svsk, atomic_read(&svsk->sk_inuse));
len = svsk->sk_recvfrom(rqstp);
dprintk("svc: got len=%d\n", len);
@@ -1235,13 +1305,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
return -EAGAIN;
}
svsk->sk_lastrecv = get_seconds();
- if (test_bit(SK_TEMP, &svsk->sk_flags)) {
- /* push active sockets to end of list */
- spin_lock_bh(&serv->sv_lock);
- if (!list_empty(&svsk->sk_list))
- list_move_tail(&svsk->sk_list, &serv->sv_tempsocks);
- spin_unlock_bh(&serv->sv_lock);
- }
+ clear_bit(SK_OLD, &svsk->sk_flags);
rqstp->rq_secure = ntohs(rqstp->rq_addr.sin_port) < 1024;
rqstp->rq_chandle.defer = svc_defer;
@@ -1301,6 +1365,58 @@ svc_send(struct svc_rqst *rqstp)
}
/*
+ * Timer function to close old temporary sockets, using
+ * a mark-and-sweep algorithm.
+ */
+static void
+svc_age_temp_sockets(unsigned long closure)
+{
+ struct svc_serv *serv = (struct svc_serv *)closure;
+ struct svc_sock *svsk;
+ struct list_head *le, *next;
+ LIST_HEAD(to_be_aged);
+
+ dprintk("svc_age_temp_sockets\n");
+
+ if (!spin_trylock_bh(&serv->sv_lock)) {
+ /* busy, try again 1 sec later */
+ dprintk("svc_age_temp_sockets: busy\n");
+ mod_timer(&serv->sv_temptimer, jiffies + HZ);
+ return;
+ }
+
+ list_for_each_safe(le, next, &serv->sv_tempsocks) {
+ svsk = list_entry(le, struct svc_sock, sk_list);
+
+ if (!test_and_set_bit(SK_OLD, &svsk->sk_flags))
+ continue;
+ if (atomic_read(&svsk->sk_inuse) || test_bit(SK_BUSY, &svsk->sk_flags))
+ continue;
+ atomic_inc(&svsk->sk_inuse);
+ list_move(le, &to_be_aged);
+ set_bit(SK_CLOSE, &svsk->sk_flags);
+ set_bit(SK_DETACHED, &svsk->sk_flags);
+ }
+ spin_unlock_bh(&serv->sv_lock);
+
+ while (!list_empty(&to_be_aged)) {
+ le = to_be_aged.next;
+ /* fiddling the sk_list node is safe 'cos we're SK_DETACHED */
+ list_del_init(le);
+ svsk = list_entry(le, struct svc_sock, sk_list);
+
+ dprintk("queuing svsk %p for closing, %lu seconds old\n",
+ svsk, get_seconds() - svsk->sk_lastrecv);
+
+ /* a thread will dequeue and close it soon */
+ svc_sock_enqueue(svsk);
+ svc_sock_put(svsk);
+ }
+
+ mod_timer(&serv->sv_temptimer, jiffies + svc_conn_age_period * HZ);
+}
+
+/*
* Initialize socket for RPC use and create svc_sock struct
* XXX: May want to setsockopt SO_SNDBUF and SO_RCVBUF.
*/
@@ -1337,7 +1453,9 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
svsk->sk_odata = inet->sk_data_ready;
svsk->sk_owspace = inet->sk_write_space;
svsk->sk_server = serv;
+ atomic_set(&svsk->sk_inuse, 0);
svsk->sk_lastrecv = get_seconds();
+ spin_lock_init(&svsk->sk_defer_lock);
INIT_LIST_HEAD(&svsk->sk_deferred);
INIT_LIST_HEAD(&svsk->sk_ready);
mutex_init(&svsk->sk_mutex);
@@ -1353,6 +1471,13 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
set_bit(SK_TEMP, &svsk->sk_flags);
list_add(&svsk->sk_list, &serv->sv_tempsocks);
serv->sv_tmpcnt++;
+ if (serv->sv_temptimer.function == NULL) {
+ /* setup timer to age temp sockets */
+ setup_timer(&serv->sv_temptimer, svc_age_temp_sockets,
+ (unsigned long)serv);
+ mod_timer(&serv->sv_temptimer,
+ jiffies + svc_conn_age_period * HZ);
+ }
} else {
clear_bit(SK_TEMP, &svsk->sk_flags);
list_add(&svsk->sk_list, &serv->sv_permsocks);
@@ -1367,6 +1492,38 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
return svsk;
}
+int svc_addsock(struct svc_serv *serv,
+ int fd,
+ char *name_return,
+ int *proto)
+{
+ int err = 0;
+ struct socket *so = sockfd_lookup(fd, &err);
+ struct svc_sock *svsk = NULL;
+
+ if (!so)
+ return err;
+ if (so->sk->sk_family != AF_INET)
+ err = -EAFNOSUPPORT;
+ else if (so->sk->sk_protocol != IPPROTO_TCP &&
+ so->sk->sk_protocol != IPPROTO_UDP)
+ err = -EPROTONOSUPPORT;
+ else if (so->state > SS_UNCONNECTED)
+ err = -EISCONN;
+ else {
+ svsk = svc_setup_socket(serv, so, &err, 1);
+ if (svsk)
+ err = 0;
+ }
+ if (err) {
+ sockfd_put(so);
+ return err;
+ }
+ if (proto) *proto = so->sk->sk_protocol;
+ return one_sock_name(name_return, svsk);
+}
+EXPORT_SYMBOL_GPL(svc_addsock);
+
/*
* Create socket for RPC service.
*/
@@ -1393,14 +1550,12 @@ svc_create_socket(struct svc_serv *serv, int protocol, struct sockaddr_in *sin)
if ((error = sock_create_kern(PF_INET, type, protocol, &sock)) < 0)
return error;
- if (sin != NULL) {
- if (type == SOCK_STREAM)
- sock->sk->sk_reuse = 1; /* allow address reuse */
- error = kernel_bind(sock, (struct sockaddr *) sin,
- sizeof(*sin));
- if (error < 0)
- goto bummer;
- }
+ if (type == SOCK_STREAM)
+ sock->sk->sk_reuse = 1; /* allow address reuse */
+ error = kernel_bind(sock, (struct sockaddr *) sin,
+ sizeof(*sin));
+ if (error < 0)
+ goto bummer;
if (protocol == IPPROTO_TCP) {
if ((error = kernel_listen(sock, 64)) < 0)
@@ -1436,15 +1591,27 @@ svc_delete_socket(struct svc_sock *svsk)
spin_lock_bh(&serv->sv_lock);
- list_del_init(&svsk->sk_list);
- list_del_init(&svsk->sk_ready);
+ if (!test_and_set_bit(SK_DETACHED, &svsk->sk_flags))
+ list_del_init(&svsk->sk_list);
+ /*
+ * We used to delete the svc_sock from whichever list
+ * it's sk_ready node was on, but we don't actually
+ * need to. This is because the only time we're called
+ * while still attached to a queue, the queue itself
+ * is about to be destroyed (in svc_destroy).
+ */
if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags))
if (test_bit(SK_TEMP, &svsk->sk_flags))
serv->sv_tmpcnt--;
- if (!svsk->sk_inuse) {
+ if (!atomic_read(&svsk->sk_inuse)) {
spin_unlock_bh(&serv->sv_lock);
- sock_release(svsk->sk_sock);
+ if (svsk->sk_sock->file)
+ sockfd_put(svsk->sk_sock);
+ else
+ sock_release(svsk->sk_sock);
+ if (svsk->sk_info_authunix != NULL)
+ svcauth_unix_info_release(svsk->sk_info_authunix);
kfree(svsk);
} else {
spin_unlock_bh(&serv->sv_lock);
@@ -1475,7 +1642,6 @@ svc_makesock(struct svc_serv *serv, int protocol, unsigned short port)
static void svc_revisit(struct cache_deferred_req *dreq, int too_many)
{
struct svc_deferred_req *dr = container_of(dreq, struct svc_deferred_req, handle);
- struct svc_serv *serv = dreq->owner;
struct svc_sock *svsk;
if (too_many) {
@@ -1486,9 +1652,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(&serv->sv_lock);
+ spin_lock_bh(&svsk->sk_defer_lock);
list_add(&dr->handle.recent, &svsk->sk_deferred);
- spin_unlock_bh(&serv->sv_lock);
+ spin_unlock_bh(&svsk->sk_defer_lock);
set_bit(SK_DEFERRED, &svsk->sk_flags);
svc_sock_enqueue(svsk);
svc_sock_put(svsk);
@@ -1520,10 +1686,8 @@ svc_defer(struct cache_req *req)
dr->argslen = rqstp->rq_arg.len >> 2;
memcpy(dr->args, rqstp->rq_arg.head[0].iov_base-skip, dr->argslen<<2);
}
- spin_lock_bh(&rqstp->rq_server->sv_lock);
- rqstp->rq_sock->sk_inuse++;
+ atomic_inc(&rqstp->rq_sock->sk_inuse);
dr->svsk = rqstp->rq_sock;
- spin_unlock_bh(&rqstp->rq_server->sv_lock);
dr->handle.revisit = svc_revisit;
return &dr->handle;
@@ -1543,6 +1707,7 @@ static int svc_deferred_recv(struct svc_rqst *rqstp)
rqstp->rq_prot = dr->prot;
rqstp->rq_addr = dr->addr;
rqstp->rq_daddr = dr->daddr;
+ rqstp->rq_respages = rqstp->rq_pages;
return dr->argslen<<2;
}
@@ -1550,11 +1715,10 @@ static int svc_deferred_recv(struct svc_rqst *rqstp)
static struct svc_deferred_req *svc_deferred_dequeue(struct svc_sock *svsk)
{
struct svc_deferred_req *dr = NULL;
- struct svc_serv *serv = svsk->sk_server;
if (!test_bit(SK_DEFERRED, &svsk->sk_flags))
return NULL;
- spin_lock_bh(&serv->sv_lock);
+ spin_lock_bh(&svsk->sk_defer_lock);
clear_bit(SK_DEFERRED, &svsk->sk_flags);
if (!list_empty(&svsk->sk_deferred)) {
dr = list_entry(svsk->sk_deferred.next,
@@ -1563,6 +1727,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(&serv->sv_lock);
+ spin_unlock_bh(&svsk->sk_defer_lock);
return dr;
}
diff --git a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
index 6ac45103a272..9022eb8b37ed 100644
--- a/net/sunrpc/xdr.c
+++ b/net/sunrpc/xdr.c
@@ -18,8 +18,8 @@
/*
* XDR functions for basic NFS types
*/
-u32 *
-xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
+__be32 *
+xdr_encode_netobj(__be32 *p, const struct xdr_netobj *obj)
{
unsigned int quadlen = XDR_QUADLEN(obj->len);
@@ -29,8 +29,8 @@ xdr_encode_netobj(u32 *p, const struct xdr_netobj *obj)
return p + XDR_QUADLEN(obj->len);
}
-u32 *
-xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
+__be32 *
+xdr_decode_netobj(__be32 *p, struct xdr_netobj *obj)
{
unsigned int len;
@@ -55,7 +55,7 @@ xdr_decode_netobj(u32 *p, struct xdr_netobj *obj)
* Returns the updated current XDR buffer position
*
*/
-u32 *xdr_encode_opaque_fixed(u32 *p, const void *ptr, unsigned int nbytes)
+__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int nbytes)
{
if (likely(nbytes != 0)) {
unsigned int quadlen = XDR_QUADLEN(nbytes);
@@ -79,21 +79,21 @@ EXPORT_SYMBOL(xdr_encode_opaque_fixed);
*
* Returns the updated current XDR buffer position
*/
-u32 *xdr_encode_opaque(u32 *p, const void *ptr, unsigned int nbytes)
+__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int nbytes)
{
*p++ = htonl(nbytes);
return xdr_encode_opaque_fixed(p, ptr, nbytes);
}
EXPORT_SYMBOL(xdr_encode_opaque);
-u32 *
-xdr_encode_string(u32 *p, const char *string)
+__be32 *
+xdr_encode_string(__be32 *p, const char *string)
{
return xdr_encode_array(p, string, strlen(string));
}
-u32 *
-xdr_decode_string_inplace(u32 *p, char **sp, int *lenp, int maxlen)
+__be32 *
+xdr_decode_string_inplace(__be32 *p, char **sp, int *lenp, int maxlen)
{
unsigned int len;
@@ -432,7 +432,7 @@ xdr_shift_buf(struct xdr_buf *buf, size_t len)
* of the buffer length, and takes care of adjusting the kvec
* length for us.
*/
-void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
{
struct kvec *iov = buf->head;
int scratch_len = buf->buflen - buf->page_len - buf->tail[0].iov_len;
@@ -440,8 +440,8 @@ void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
BUG_ON(scratch_len < 0);
xdr->buf = buf;
xdr->iov = iov;
- xdr->p = (uint32_t *)((char *)iov->iov_base + iov->iov_len);
- xdr->end = (uint32_t *)((char *)iov->iov_base + scratch_len);
+ xdr->p = (__be32 *)((char *)iov->iov_base + iov->iov_len);
+ xdr->end = (__be32 *)((char *)iov->iov_base + scratch_len);
BUG_ON(iov->iov_len > scratch_len);
if (p != xdr->p && p != NULL) {
@@ -465,10 +465,10 @@ EXPORT_SYMBOL(xdr_init_encode);
* bytes of data. If so, update the total xdr_buf length, and
* adjust the length of the current kvec.
*/
-uint32_t * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
+__be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
{
- uint32_t *p = xdr->p;
- uint32_t *q;
+ __be32 *p = xdr->p;
+ __be32 *q;
/* align nbytes on the next 32-bit boundary */
nbytes += 3;
@@ -524,7 +524,7 @@ EXPORT_SYMBOL(xdr_write_pages);
* @buf: pointer to XDR buffer from which to decode data
* @p: current pointer inside XDR buffer
*/
-void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
+void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p)
{
struct kvec *iov = buf->head;
unsigned int len = iov->iov_len;
@@ -534,7 +534,7 @@ void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, uint32_t *p)
xdr->buf = buf;
xdr->iov = iov;
xdr->p = p;
- xdr->end = (uint32_t *)((char *)iov->iov_base + len);
+ xdr->end = (__be32 *)((char *)iov->iov_base + len);
}
EXPORT_SYMBOL(xdr_init_decode);
@@ -548,10 +548,10 @@ EXPORT_SYMBOL(xdr_init_decode);
* If so return the current pointer, then update the current
* pointer position.
*/
-uint32_t * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
+__be32 * xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes)
{
- uint32_t *p = xdr->p;
- uint32_t *q = p + XDR_QUADLEN(nbytes);
+ __be32 *p = xdr->p;
+ __be32 *q = p + XDR_QUADLEN(nbytes);
if (unlikely(q > xdr->end || q < p))
return NULL;
@@ -599,8 +599,8 @@ void xdr_read_pages(struct xdr_stream *xdr, unsigned int len)
* Position current pointer at beginning of tail, and
* set remaining message length.
*/
- xdr->p = (uint32_t *)((char *)iov->iov_base + padding);
- xdr->end = (uint32_t *)((char *)iov->iov_base + end);
+ xdr->p = (__be32 *)((char *)iov->iov_base + padding);
+ xdr->end = (__be32 *)((char *)iov->iov_base + end);
}
EXPORT_SYMBOL(xdr_read_pages);
@@ -624,8 +624,8 @@ void xdr_enter_page(struct xdr_stream *xdr, unsigned int len)
*/
if (len > PAGE_CACHE_SIZE - xdr->buf->page_base)
len = PAGE_CACHE_SIZE - xdr->buf->page_base;
- xdr->p = (uint32_t *)(kaddr + xdr->buf->page_base);
- xdr->end = (uint32_t *)((char *)xdr->p + len);
+ xdr->p = (__be32 *)(kaddr + xdr->buf->page_base);
+ xdr->end = (__be32 *)((char *)xdr->p + len);
}
EXPORT_SYMBOL(xdr_enter_page);
@@ -743,7 +743,7 @@ out:
int
xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj)
{
- u32 raw;
+ __be32 raw;
int status;
status = read_bytes_from_xdr_buf(buf, base, &raw, sizeof(*obj));
@@ -756,7 +756,7 @@ xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj)
int
xdr_encode_word(struct xdr_buf *buf, int base, u32 obj)
{
- u32 raw = htonl(obj);
+ __be32 raw = htonl(obj);
return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
}
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 1f786f68729d..80857470dc11 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -594,7 +594,7 @@ static void xprt_connect_status(struct rpc_task *task)
* @xid: RPC XID of incoming reply
*
*/
-struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
+struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
{
struct list_head *pos;
@@ -801,7 +801,7 @@ void xprt_reserve(struct rpc_task *task)
spin_unlock(&xprt->reserve_lock);
}
-static inline u32 xprt_alloc_xid(struct rpc_xprt *xprt)
+static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
{
return xprt->xid++;
}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 9b62923a9c06..757fc91ef25d 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -548,7 +548,8 @@ static void xs_udp_data_ready(struct sock *sk, int len)
struct rpc_rqst *rovr;
struct sk_buff *skb;
int err, repsize, copied;
- u32 _xid, *xp;
+ u32 _xid;
+ __be32 *xp;
read_lock(&sk->sk_callback_lock);
dprintk("RPC: xs_udp_data_ready...\n");
@@ -1365,7 +1366,7 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
if (xprt->slot == NULL)
return -ENOMEM;
- if (ntohs(addr->sin_port != 0))
+ if (ntohs(addr->sin_port) != 0)
xprt_set_bound(xprt);
xprt->port = xs_get_random_port();
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 75a5968c2139..39744a33bd36 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -2,7 +2,7 @@
* net/tipc/bearer.c: TIPC bearer code
*
* Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -191,14 +191,14 @@ void tipc_media_addr_printf(struct print_buf *pb, struct tipc_media_addr *a)
if ((i < media_count) && (m_ptr->addr2str != NULL)) {
char addr_str[MAX_ADDR_STR];
- tipc_printf(pb, "%s(%s) ", m_ptr->name,
+ tipc_printf(pb, "%s(%s)", m_ptr->name,
m_ptr->addr2str(a, addr_str, sizeof(addr_str)));
} else {
unchar *addr = (unchar *)&a->dev_addr;
- tipc_printf(pb, "UNKNOWN(%u):", media_type);
+ tipc_printf(pb, "UNKNOWN(%u)", media_type);
for (i = 0; i < (sizeof(*a) - sizeof(a->type)); i++) {
- tipc_printf(pb, "%02x ", addr[i]);
+ tipc_printf(pb, "-%02x", addr[i]);
}
}
}
diff --git a/net/tipc/config.c b/net/tipc/config.c
index 285e1bc2d880..ed1351ed05e1 100644
--- a/net/tipc/config.c
+++ b/net/tipc/config.c
@@ -2,7 +2,7 @@
* net/tipc/config.c: TIPC configuration management code
*
* Copyright (c) 2002-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -613,7 +613,8 @@ struct sk_buff *tipc_cfg_do_cmd(u32 orig_node, u16 cmd, const void *request_area
rep_tlv_buf = tipc_cfg_reply_unsigned(tipc_net_id);
break;
default:
- rep_tlv_buf = NULL;
+ rep_tlv_buf = tipc_cfg_reply_error_string(TIPC_CFG_NOT_SUPPORTED
+ " (unknown command)");
break;
}
diff --git a/net/tipc/core.c b/net/tipc/core.c
index 0539a8362858..6f5b7ee31180 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -57,7 +57,7 @@ void tipc_socket_stop(void);
int tipc_netlink_start(void);
void tipc_netlink_stop(void);
-#define TIPC_MOD_VER "1.6.1"
+#define TIPC_MOD_VER "1.6.2"
#ifndef CONFIG_TIPC_ZONES
#define CONFIG_TIPC_ZONES 3
@@ -90,7 +90,7 @@ int tipc_random;
atomic_t tipc_user_count = ATOMIC_INIT(0);
const char tipc_alphabet[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_";
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.";
/* configurable TIPC parameters */
diff --git a/net/tipc/core.h b/net/tipc/core.h
index 762aac2572be..4638947c2326 100644
--- a/net/tipc/core.h
+++ b/net/tipc/core.h
@@ -65,7 +65,7 @@
#define assert(i) BUG_ON(!(i))
struct tipc_msg;
-extern struct print_buf *TIPC_CONS, *TIPC_LOG;
+extern struct print_buf *TIPC_NULL, *TIPC_CONS, *TIPC_LOG;
extern struct print_buf *TIPC_TEE(struct print_buf *, struct print_buf *);
void tipc_msg_print(struct print_buf*,struct tipc_msg *,const char*);
void tipc_printf(struct print_buf *, const char *fmt, ...);
@@ -83,9 +83,9 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#define warn(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_WARNING "TIPC: " fmt, ## arg)
#define info(fmt, arg...) tipc_printf(TIPC_OUTPUT, KERN_NOTICE "TIPC: " fmt, ## arg)
-#define dbg(fmt, arg...) do {if (DBG_OUTPUT) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
-#define msg_dbg(msg, txt) do {if (DBG_OUTPUT) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
-#define dump(fmt, arg...) do {if (DBG_OUTPUT) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
+#define dbg(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_printf(DBG_OUTPUT, fmt, ## arg);} while(0)
+#define msg_dbg(msg, txt) do {if (DBG_OUTPUT != TIPC_NULL) tipc_msg_print(DBG_OUTPUT, msg, txt);} while(0)
+#define dump(fmt, arg...) do {if (DBG_OUTPUT != TIPC_NULL) tipc_dump(DBG_OUTPUT, fmt, ##arg);} while(0)
/*
@@ -94,11 +94,11 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
* here, or on a per .c file basis, by redefining these symbols. The following
* print buffer options are available:
*
- * NULL : Output to null print buffer (i.e. print nowhere)
- * TIPC_CONS : Output to system console
- * TIPC_LOG : Output to TIPC log buffer
- * &buf : Output to user-defined buffer (struct print_buf *)
- * TIPC_TEE(&buf_a,&buf_b) : Output to two print buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG) )
+ * TIPC_NULL : null buffer (i.e. print nowhere)
+ * TIPC_CONS : system console
+ * TIPC_LOG : TIPC log buffer
+ * &buf : user-defined buffer (struct print_buf *)
+ * TIPC_TEE(&buf_a,&buf_b) : list of buffers (eg. TIPC_TEE(TIPC_CONS,TIPC_LOG))
*/
#ifndef TIPC_OUTPUT
@@ -106,7 +106,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#endif
#ifndef DBG_OUTPUT
-#define DBG_OUTPUT NULL
+#define DBG_OUTPUT TIPC_NULL
#endif
#else
@@ -136,7 +136,7 @@ void tipc_dump(struct print_buf*,const char *fmt, ...);
#define TIPC_OUTPUT TIPC_CONS
#undef DBG_OUTPUT
-#define DBG_OUTPUT NULL
+#define DBG_OUTPUT TIPC_NULL
#endif
@@ -275,11 +275,15 @@ static inline void k_term_timer(struct timer_list *timer)
/*
* TIPC message buffer code
*
- * TIPC message buffer headroom leaves room for 14 byte Ethernet header,
+ * TIPC message buffer headroom reserves space for a link-level header
+ * (in case the message is sent off-node),
* while ensuring TIPC header is word aligned for quicker access
+ *
+ * The largest header currently supported is 18 bytes, which is used when
+ * the standard 14 byte Ethernet header has 4 added bytes for VLAN info
*/
-#define BUF_HEADROOM 16u
+#define BUF_HEADROOM 20u
struct tipc_skb_cb {
void *handle;
diff --git a/net/tipc/dbg.c b/net/tipc/dbg.c
index 55130655e1ed..d8af4c28695d 100644
--- a/net/tipc/dbg.c
+++ b/net/tipc/dbg.c
@@ -1,8 +1,8 @@
/*
- * net/tipc/dbg.c: TIPC print buffer routines for debuggign
+ * net/tipc/dbg.c: TIPC print buffer routines for debugging
*
* Copyright (c) 1996-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,11 +38,12 @@
#include "config.h"
#include "dbg.h"
-#define MAX_STRING 512
-
-static char print_string[MAX_STRING];
+static char print_string[TIPC_PB_MAX_STR];
static DEFINE_SPINLOCK(print_lock);
+static struct print_buf null_buf = { NULL, 0, NULL, NULL };
+struct print_buf *TIPC_NULL = &null_buf;
+
static struct print_buf cons_buf = { NULL, 0, NULL, NULL };
struct print_buf *TIPC_CONS = &cons_buf;
@@ -62,68 +63,83 @@ struct print_buf *TIPC_LOG = &log_buf;
/*
* Locking policy when using print buffers.
*
- * 1) Routines of the form printbuf_XXX() rely on the caller to prevent
- * simultaneous use of the print buffer(s) being manipulated.
- * 2) tipc_printf() uses 'print_lock' to prevent simultaneous use of
- * 'print_string' and to protect its print buffer(s).
- * 3) TIPC_TEE() uses 'print_lock' to protect its print buffer(s).
- * 4) Routines of the form log_XXX() uses 'print_lock' to protect TIPC_LOG.
+ * The following routines use 'print_lock' for protection:
+ * 1) tipc_printf() - to protect its print buffer(s) and 'print_string'
+ * 2) TIPC_TEE() - to protect its print buffer(s)
+ * 3) tipc_dump() - to protect its print buffer(s) and 'print_string'
+ * 4) tipc_log_XXX() - to protect TIPC_LOG
+ *
+ * All routines of the form tipc_printbuf_XXX() rely on the caller to prevent
+ * simultaneous use of the print buffer(s) being manipulated.
*/
/**
* tipc_printbuf_init - initialize print buffer to empty
+ * @pb: pointer to print buffer structure
+ * @raw: pointer to character array used by print buffer
+ * @size: size of character array
+ *
+ * Makes the print buffer a null device that discards anything written to it
+ * if the character array is too small (or absent).
*/
-void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 sz)
+void tipc_printbuf_init(struct print_buf *pb, char *raw, u32 size)
{
- if (!pb || !raw || (sz < (MAX_STRING + 1)))
- return;
-
- pb->crs = pb->buf = raw;
- pb->size = sz;
+ pb->buf = raw;
+ pb->crs = raw;
+ pb->size = size;
pb->next = NULL;
- pb->buf[0] = 0;
- pb->buf[sz-1] = ~0;
+
+ if (size < TIPC_PB_MIN_SIZE) {
+ pb->buf = NULL;
+ } else if (raw) {
+ pb->buf[0] = 0;
+ pb->buf[size-1] = ~0;
+ }
}
/**
* tipc_printbuf_reset - reinitialize print buffer to empty state
+ * @pb: pointer to print buffer structure
*/
void tipc_printbuf_reset(struct print_buf *pb)
{
- if (pb && pb->buf)
- tipc_printbuf_init(pb, pb->buf, pb->size);
+ tipc_printbuf_init(pb, pb->buf, pb->size);
}
/**
* tipc_printbuf_empty - test if print buffer is in empty state
+ * @pb: pointer to print buffer structure
+ *
+ * Returns non-zero if print buffer is empty.
*/
int tipc_printbuf_empty(struct print_buf *pb)
{
- return (!pb || !pb->buf || (pb->crs == pb->buf));
+ return (!pb->buf || (pb->crs == pb->buf));
}
/**
* tipc_printbuf_validate - check for print buffer overflow
+ * @pb: pointer to print buffer structure
*
* Verifies that a print buffer has captured all data written to it.
* If data has been lost, linearize buffer and prepend an error message
*
- * Returns length of print buffer data string (including trailing NULL)
+ * Returns length of print buffer data string (including trailing NUL)
*/
int tipc_printbuf_validate(struct print_buf *pb)
{
- char *err = " *** PRINT BUFFER WRAPPED AROUND ***\n";
+ char *err = "\n\n*** PRINT BUFFER OVERFLOW ***\n\n";
char *cp_buf;
struct print_buf cb;
- if (!pb || !pb->buf)
+ if (!pb->buf)
return 0;
- if (pb->buf[pb->size - 1] == '\0') {
+ if (pb->buf[pb->size - 1] == 0) {
cp_buf = kmalloc(pb->size, GFP_ATOMIC);
if (cp_buf != NULL){
tipc_printbuf_init(&cb, cp_buf, pb->size);
@@ -141,6 +157,8 @@ int tipc_printbuf_validate(struct print_buf *pb)
/**
* tipc_printbuf_move - move print buffer contents to another print buffer
+ * @pb_to: pointer to destination print buffer structure
+ * @pb_from: pointer to source print buffer structure
*
* Current contents of destination print buffer (if any) are discarded.
* Source print buffer becomes empty if a successful move occurs.
@@ -152,21 +170,22 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
/* Handle the cases where contents can't be moved */
- if (!pb_to || !pb_to->buf)
+ if (!pb_to->buf)
return;
- if (!pb_from || !pb_from->buf) {
+ if (!pb_from->buf) {
tipc_printbuf_reset(pb_to);
return;
}
if (pb_to->size < pb_from->size) {
tipc_printbuf_reset(pb_to);
- tipc_printf(pb_to, "*** PRINT BUFFER OVERFLOW ***");
+ tipc_printf(pb_to, "*** PRINT BUFFER MOVE ERROR ***");
return;
}
/* Copy data from char after cursor to end (if used) */
+
len = pb_from->buf + pb_from->size - pb_from->crs - 2;
if ((pb_from->buf[pb_from->size-1] == 0) && (len > 0)) {
strcpy(pb_to->buf, pb_from->crs + 1);
@@ -175,6 +194,7 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
pb_to->crs = pb_to->buf;
/* Copy data from start to cursor (always) */
+
len = pb_from->crs - pb_from->buf;
strcpy(pb_to->crs, pb_from->buf);
pb_to->crs += len;
@@ -184,6 +204,8 @@ void tipc_printbuf_move(struct print_buf *pb_to, struct print_buf *pb_from)
/**
* tipc_printf - append formatted output to print buffer chain
+ * @pb: pointer to chain of print buffers (may be NULL)
+ * @fmt: formatted info to be printed
*/
void tipc_printf(struct print_buf *pb, const char *fmt, ...)
@@ -195,8 +217,8 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
spin_lock_bh(&print_lock);
FORMAT(print_string, chars_to_add, fmt);
- if (chars_to_add >= MAX_STRING)
- strcpy(print_string, "*** STRING TOO LONG ***");
+ if (chars_to_add >= TIPC_PB_MAX_STR)
+ strcpy(print_string, "*** PRINT BUFFER STRING TOO LONG ***");
while (pb) {
if (pb == TIPC_CONS)
@@ -206,6 +228,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
if (chars_to_add <= chars_left) {
strcpy(pb->crs, print_string);
pb->crs += chars_to_add;
+ } else if (chars_to_add >= (pb->size - 1)) {
+ strcpy(pb->buf, print_string + chars_to_add + 1
+ - pb->size);
+ pb->crs = pb->buf + pb->size - 1;
} else {
strcpy(pb->buf, print_string + chars_left);
save_char = print_string[chars_left];
@@ -224,6 +250,10 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
/**
* TIPC_TEE - perform next output operation on both print buffers
+ * @b0: pointer to chain of print buffers (may be NULL)
+ * @b1: pointer to print buffer to add to chain
+ *
+ * Returns pointer to print buffer chain.
*/
struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
@@ -232,8 +262,6 @@ struct print_buf *TIPC_TEE(struct print_buf *b0, struct print_buf *b1)
if (!b0 || (b0 == b1))
return b1;
- if (!b1)
- return b0;
spin_lock_bh(&print_lock);
while (pb->next) {
@@ -256,7 +284,7 @@ static void print_to_console(char *crs, int len)
int rest = len;
while (rest > 0) {
- int sz = rest < MAX_STRING ? rest : MAX_STRING;
+ int sz = rest < TIPC_PB_MAX_STR ? rest : TIPC_PB_MAX_STR;
char c = crs[sz];
crs[sz] = 0;
@@ -275,36 +303,48 @@ static void printbuf_dump(struct print_buf *pb)
{
int len;
+ if (!pb->buf) {
+ printk("*** PRINT BUFFER NOT ALLOCATED ***");
+ return;
+ }
+
/* Dump print buffer from char after cursor to end (if used) */
+
len = pb->buf + pb->size - pb->crs - 2;
if ((pb->buf[pb->size - 1] == 0) && (len > 0))
print_to_console(pb->crs + 1, len);
/* Dump print buffer from start to cursor (always) */
+
len = pb->crs - pb->buf;
print_to_console(pb->buf, len);
}
/**
* tipc_dump - dump non-console print buffer(s) to console
+ * @pb: pointer to chain of print buffers
*/
void tipc_dump(struct print_buf *pb, const char *fmt, ...)
{
+ struct print_buf *pb_next;
int len;
spin_lock_bh(&print_lock);
- FORMAT(TIPC_CONS->buf, len, fmt);
- printk(TIPC_CONS->buf);
+ FORMAT(print_string, len, fmt);
+ printk(print_string);
for (; pb; pb = pb->next) {
- if (pb == TIPC_CONS)
- continue;
- printk("\n---- Start of dump,%s log ----\n\n",
- (pb == TIPC_LOG) ? "global" : "local");
- printbuf_dump(pb);
- tipc_printbuf_reset(pb);
- printk("\n-------- End of dump --------\n");
+ if (pb != TIPC_CONS) {
+ printk("\n---- Start of %s log dump ----\n\n",
+ (pb == TIPC_LOG) ? "global" : "local");
+ printbuf_dump(pb);
+ tipc_printbuf_reset(pb);
+ printk("\n---- End of dump ----\n");
+ }
+ pb_next = pb->next;
+ pb->next = NULL;
+ pb = pb_next;
}
spin_unlock_bh(&print_lock);
}
@@ -324,7 +364,8 @@ void tipc_log_stop(void)
}
/**
- * tipc_log_reinit - set TIPC log print buffer to specified size
+ * tipc_log_reinit - (re)initialize TIPC log print buffer
+ * @log_size: print buffer size to use
*/
void tipc_log_reinit(int log_size)
@@ -332,10 +373,11 @@ void tipc_log_reinit(int log_size)
tipc_log_stop();
if (log_size) {
- if (log_size <= MAX_STRING)
- log_size = MAX_STRING + 1;
+ if (log_size < TIPC_PB_MIN_SIZE)
+ log_size = TIPC_PB_MIN_SIZE;
spin_lock_bh(&print_lock);
- tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC), log_size);
+ tipc_printbuf_init(TIPC_LOG, kmalloc(log_size, GFP_ATOMIC),
+ log_size);
spin_unlock_bh(&print_lock);
}
}
diff --git a/net/tipc/dbg.h b/net/tipc/dbg.h
index 227f050d2a52..467c0bc78a79 100644
--- a/net/tipc/dbg.h
+++ b/net/tipc/dbg.h
@@ -2,7 +2,7 @@
* net/tipc/dbg.h: Include file for TIPC print buffer routines
*
* Copyright (c) 1997-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,6 +37,14 @@
#ifndef _TIPC_DBG_H
#define _TIPC_DBG_H
+/**
+ * struct print_buf - TIPC print buffer structure
+ * @buf: pointer to character array containing print buffer contents
+ * @size: size of character array
+ * @crs: pointer to first unused space in character array (i.e. final NUL)
+ * @next: used to link print buffers when printing to more than one at a time
+ */
+
struct print_buf {
char *buf;
u32 size;
@@ -44,7 +52,10 @@ struct print_buf {
struct print_buf *next;
};
-void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 sz);
+#define TIPC_PB_MIN_SIZE 64 /* minimum size for a print buffer's array */
+#define TIPC_PB_MAX_STR 512 /* max printable string (with trailing NUL) */
+
+void tipc_printbuf_init(struct print_buf *pb, char *buf, u32 size);
void tipc_printbuf_reset(struct print_buf *pb);
int tipc_printbuf_empty(struct print_buf *pb);
int tipc_printbuf_validate(struct print_buf *pb);
diff --git a/net/tipc/discover.c b/net/tipc/discover.c
index ee94de92ae99..3b0cd12f37da 100644
--- a/net/tipc/discover.c
+++ b/net/tipc/discover.c
@@ -132,6 +132,28 @@ static struct sk_buff *tipc_disc_init_msg(u32 type,
}
/**
+ * disc_dupl_alert - issue node address duplication alert
+ * @b_ptr: pointer to bearer detecting duplication
+ * @node_addr: duplicated node address
+ * @media_addr: media address advertised by duplicated node
+ */
+
+static void disc_dupl_alert(struct bearer *b_ptr, u32 node_addr,
+ struct tipc_media_addr *media_addr)
+{
+ char node_addr_str[16];
+ char media_addr_str[64];
+ struct print_buf pb;
+
+ addr_string_fill(node_addr_str, node_addr);
+ tipc_printbuf_init(&pb, media_addr_str, sizeof(media_addr_str));
+ tipc_media_addr_printf(&pb, media_addr);
+ tipc_printbuf_validate(&pb);
+ warn("Duplicate %s using %s seen on <%s>\n",
+ node_addr_str, media_addr_str, b_ptr->publ.name);
+}
+
+/**
* tipc_disc_recv_msg - handle incoming link setup message (request or response)
* @buf: buffer containing message
*/
@@ -157,8 +179,11 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
return;
if (!tipc_addr_node_valid(orig))
return;
- if (orig == tipc_own_addr)
+ if (orig == tipc_own_addr) {
+ if (memcmp(&media_addr, &b_ptr->publ.addr, sizeof(media_addr)))
+ disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
return;
+ }
if (!in_scope(dest, tipc_own_addr))
return;
if (is_slave(tipc_own_addr) && is_slave(orig))
@@ -170,7 +195,8 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
struct sk_buff *rbuf;
struct tipc_media_addr *addr;
struct node *n_ptr = tipc_node_find(orig);
- int link_up;
+ int link_fully_up;
+
dbg(" in own cluster\n");
if (n_ptr == NULL) {
n_ptr = tipc_node_create(orig);
@@ -190,14 +216,19 @@ void tipc_disc_recv_msg(struct sk_buff *buf)
}
addr = &link->media_addr;
if (memcmp(addr, &media_addr, sizeof(*addr))) {
+ if (tipc_link_is_up(link) || (!link->started)) {
+ disc_dupl_alert(b_ptr, orig, &media_addr);
+ spin_unlock_bh(&n_ptr->lock);
+ return;
+ }
warn("Resetting link <%s>, peer interface address changed\n",
link->name);
memcpy(addr, &media_addr, sizeof(*addr));
tipc_link_reset(link);
}
- link_up = tipc_link_is_up(link);
+ link_fully_up = (link->state == WORKING_WORKING);
spin_unlock_bh(&n_ptr->lock);
- if ((type == DSC_RESP_MSG) || link_up)
+ if ((type == DSC_RESP_MSG) || link_fully_up)
return;
rbuf = tipc_disc_init_msg(DSC_RESP_MSG, 1, orig, b_ptr);
if (rbuf != NULL) {
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 693f02eca6d6..1bb983c8130b 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -132,7 +132,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
* allow the output from multiple links to be intermixed. For this reason
* routines of the form "dbg_link_XXX()" have been created that will capture
* debug info into a link's personal print buffer, which can then be dumped
- * into the TIPC system log (LOG) upon request.
+ * into the TIPC system log (TIPC_LOG) upon request.
*
* To enable per-link debugging, use LINK_LOG_BUF_SIZE to specify the size
* of the print buffer used by each link. If LINK_LOG_BUF_SIZE is set to 0,
@@ -141,7 +141,7 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
* when there is only a single link in the system being debugged.
*
* Notes:
- * - When enabled, LINK_LOG_BUF_SIZE should be set to at least 1000 (bytes)
+ * - When enabled, LINK_LOG_BUF_SIZE should be set to at least TIPC_PB_MIN_SIZE
* - "l_ptr" must be valid when using dbg_link_XXX() macros
*/
@@ -159,13 +159,13 @@ static void link_print(struct link *l_ptr, struct print_buf *buf,
static void dbg_print_link(struct link *l_ptr, const char *str)
{
- if (DBG_OUTPUT)
+ if (DBG_OUTPUT != TIPC_NULL)
link_print(l_ptr, DBG_OUTPUT, str);
}
static void dbg_print_buf_chain(struct sk_buff *root_buf)
{
- if (DBG_OUTPUT) {
+ if (DBG_OUTPUT != TIPC_NULL) {
struct sk_buff *buf = root_buf;
while (buf) {
@@ -1666,8 +1666,9 @@ static void link_retransmit_failure(struct link *l_ptr, struct sk_buff *buf)
char addr_string[16];
tipc_printf(TIPC_OUTPUT, "Msg seq number: %u, ", msg_seqno(msg));
- tipc_printf(TIPC_OUTPUT, "Outstanding acks: %u\n", (u32)TIPC_SKB_CB(buf)->handle);
-
+ tipc_printf(TIPC_OUTPUT, "Outstanding acks: %lu\n",
+ (unsigned long) TIPC_SKB_CB(buf)->handle);
+
n_ptr = l_ptr->owner->next;
tipc_node_lock(n_ptr);
diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c
index f0b063bcc2a9..03bd659c43ca 100644
--- a/net/tipc/name_distr.c
+++ b/net/tipc/name_distr.c
@@ -122,7 +122,7 @@ void tipc_named_publish(struct publication *publ)
struct sk_buff *buf;
struct distr_item *item;
- list_add(&publ->local_list, &publ_root);
+ list_add_tail(&publ->local_list, &publ_root);
publ_cnt++;
buf = named_prepare_buf(PUBLICATION, ITEM_SIZE, 0);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index fc6d09630ccd..886bda5e88db 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -648,7 +648,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
return tipc_cfg_reply_error_string(TIPC_CFG_INVALID_VALUE
" (network address)");
- if (!tipc_nodes)
+ if (tipc_mode != TIPC_NET_MODE)
return tipc_cfg_reply_none();
/* Get space for all unicast links + multicast link */
diff --git a/net/tipc/port.c b/net/tipc/port.c
index b9c8c6b9e94f..c1a1a76759b5 100644
--- a/net/tipc/port.c
+++ b/net/tipc/port.c
@@ -505,8 +505,13 @@ static void port_timeout(unsigned long ref)
struct port *p_ptr = tipc_port_lock(ref);
struct sk_buff *buf = NULL;
- if (!p_ptr || !p_ptr->publ.connected)
+ if (!p_ptr)
+ return;
+
+ if (!p_ptr->publ.connected) {
+ tipc_port_unlock(p_ptr);
return;
+ }
/* Last probe answered ? */
if (p_ptr->probing_state == PROBING) {
diff --git a/net/tipc/socket.c b/net/tipc/socket.c
index 32d778448a00..2a6a5a6b4c12 100644
--- a/net/tipc/socket.c
+++ b/net/tipc/socket.c
@@ -2,7 +2,7 @@
* net/tipc/socket.c: TIPC socket API
*
* Copyright (c) 2001-2006, Ericsson AB
- * Copyright (c) 2004-2005, Wind River Systems
+ * Copyright (c) 2004-2006, Wind River Systems
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -629,6 +629,9 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
return -ENOTCONN;
}
+ if (unlikely(m->msg_name))
+ return -EISCONN;
+
/*
* Send each iovec entry using one or more messages
*
@@ -641,6 +644,8 @@ static int send_stream(struct kiocb *iocb, struct socket *sock,
curr_iovlen = m->msg_iovlen;
my_msg.msg_iov = &my_iov;
my_msg.msg_iovlen = 1;
+ my_msg.msg_flags = m->msg_flags;
+ my_msg.msg_name = NULL;
bytes_sent = 0;
while (curr_iovlen--) {
@@ -941,7 +946,7 @@ static int recv_stream(struct kiocb *iocb, struct socket *sock,
int sz_to_copy;
int sz_copied = 0;
int needed;
- char *crs = m->msg_iov->iov_base;
+ char __user *crs = m->msg_iov->iov_base;
unsigned char *buf_crs;
u32 err;
int res;
@@ -1203,7 +1208,8 @@ static u32 dispatch(struct tipc_port *tport, struct sk_buff *buf)
atomic_inc(&tipc_queue_size);
skb_queue_tail(&sock->sk->sk_receive_queue, buf);
- wake_up_interruptible(sock->sk->sk_sleep);
+ if (waitqueue_active(sock->sk->sk_sleep))
+ wake_up_interruptible(sock->sk->sk_sleep);
return TIPC_OK;
}
@@ -1218,7 +1224,8 @@ static void wakeupdispatch(struct tipc_port *tport)
{
struct tipc_sock *tsock = (struct tipc_sock *)tport->usr_handle;
- wake_up_interruptible(tsock->sk.sk_sleep);
+ if (waitqueue_active(tsock->sk.sk_sleep))
+ wake_up_interruptible(tsock->sk.sk_sleep);
}
/**
@@ -1496,7 +1503,7 @@ static int setsockopt(struct socket *sock,
return -ENOPROTOOPT;
if (ol < sizeof(value))
return -EINVAL;
- if ((res = get_user(value, (u32 *)ov)))
+ if ((res = get_user(value, (u32 __user *)ov)))
return res;
if (down_interruptible(&tsock->sem))
@@ -1541,7 +1548,7 @@ static int setsockopt(struct socket *sock,
*/
static int getsockopt(struct socket *sock,
- int lvl, int opt, char __user *ov, int *ol)
+ int lvl, int opt, char __user *ov, int __user *ol)
{
struct tipc_sock *tsock = tipc_sk(sock->sk);
int len;
diff --git a/net/tipc/subscr.c b/net/tipc/subscr.c
index c51600ba5f4a..7a918f12a5df 100644
--- a/net/tipc/subscr.c
+++ b/net/tipc/subscr.c
@@ -155,7 +155,7 @@ void tipc_subscr_report_overlap(struct subscription *sub,
sub->seq.upper, found_lower, found_upper);
if (!tipc_subscr_overlap(sub, found_lower, found_upper))
return;
- if (!must && (sub->filter != TIPC_SUB_PORTS))
+ if (!must && !(sub->filter & TIPC_SUB_PORTS))
return;
subscr_send_event(sub, found_lower, found_upper, event, port_ref, node);
}
@@ -176,6 +176,13 @@ static void subscr_timeout(struct subscription *sub)
if (subscriber == NULL)
return;
+ /* Validate timeout (in case subscription is being cancelled) */
+
+ if (sub->timeout == TIPC_WAIT_FOREVER) {
+ tipc_ref_unlock(subscriber_ref);
+ return;
+ }
+
/* Unlink subscription from name table */
tipc_nametbl_unsubscribe(sub);
@@ -199,6 +206,20 @@ static void subscr_timeout(struct subscription *sub)
}
/**
+ * subscr_del - delete a subscription within a subscription list
+ *
+ * Called with subscriber locked.
+ */
+
+static void subscr_del(struct subscription *sub)
+{
+ tipc_nametbl_unsubscribe(sub);
+ list_del(&sub->subscription_list);
+ kfree(sub);
+ atomic_dec(&topsrv.subscription_count);
+}
+
+/**
* subscr_terminate - terminate communication with a subscriber
*
* Called with subscriber locked. Routine must temporarily release this lock
@@ -227,12 +248,9 @@ static void subscr_terminate(struct subscriber *subscriber)
k_cancel_timer(&sub->timer);
k_term_timer(&sub->timer);
}
- tipc_nametbl_unsubscribe(sub);
- list_del(&sub->subscription_list);
- dbg("Term: Removed sub %u,%u,%u from subscriber %x list\n",
+ dbg("Term: Removing sub %u,%u,%u from subscriber %x list\n",
sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
- kfree(sub);
- atomic_dec(&topsrv.subscription_count);
+ subscr_del(sub);
}
/* Sever connection to subscriber */
@@ -253,6 +271,49 @@ static void subscr_terminate(struct subscriber *subscriber)
}
/**
+ * subscr_cancel - handle subscription cancellation request
+ *
+ * Called with subscriber locked. Routine must temporarily release this lock
+ * to enable the subscription timeout routine to finish without deadlocking;
+ * the lock is then reclaimed to allow caller to release it upon return.
+ *
+ * Note that fields of 's' use subscriber's endianness!
+ */
+
+static void subscr_cancel(struct tipc_subscr *s,
+ struct subscriber *subscriber)
+{
+ struct subscription *sub;
+ struct subscription *sub_temp;
+ int found = 0;
+
+ /* Find first matching subscription, exit if not found */
+
+ list_for_each_entry_safe(sub, sub_temp, &subscriber->subscription_list,
+ subscription_list) {
+ if (!memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return;
+
+ /* Cancel subscription timer (if used), then delete subscription */
+
+ if (sub->timeout != TIPC_WAIT_FOREVER) {
+ sub->timeout = TIPC_WAIT_FOREVER;
+ spin_unlock_bh(subscriber->lock);
+ k_cancel_timer(&sub->timer);
+ k_term_timer(&sub->timer);
+ spin_lock_bh(subscriber->lock);
+ }
+ dbg("Cancel: removing sub %u,%u,%u from subscriber %x list\n",
+ sub->seq.type, sub->seq.lower, sub->seq.upper, subscriber);
+ subscr_del(sub);
+}
+
+/**
* subscr_subscribe - create subscription for subscriber
*
* Called with subscriber locked
@@ -263,6 +324,21 @@ static void subscr_subscribe(struct tipc_subscr *s,
{
struct subscription *sub;
+ /* Determine/update subscriber's endianness */
+
+ if (s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE))
+ subscriber->swap = 0;
+ else
+ subscriber->swap = 1;
+
+ /* Detect & process a subscription cancellation request */
+
+ if (s->filter & htohl(TIPC_SUB_CANCEL, subscriber->swap)) {
+ s->filter &= ~htohl(TIPC_SUB_CANCEL, subscriber->swap);
+ subscr_cancel(s, subscriber);
+ return;
+ }
+
/* Refuse subscription if global limit exceeded */
if (atomic_read(&topsrv.subscription_count) >= tipc_max_subscriptions) {
@@ -281,13 +357,6 @@ static void subscr_subscribe(struct tipc_subscr *s,
return;
}
- /* Determine/update subscriber's endianness */
-
- if ((s->filter == TIPC_SUB_PORTS) || (s->filter == TIPC_SUB_SERVICE))
- subscriber->swap = 0;
- else
- subscriber->swap = 1;
-
/* Initialize subscription object */
memset(sub, 0, sizeof(*sub));
@@ -296,8 +365,8 @@ static void subscr_subscribe(struct tipc_subscr *s,
sub->seq.upper = htohl(s->seq.upper, subscriber->swap);
sub->timeout = htohl(s->timeout, subscriber->swap);
sub->filter = htohl(s->filter, subscriber->swap);
- if ((((sub->filter != TIPC_SUB_PORTS)
- && (sub->filter != TIPC_SUB_SERVICE)))
+ if ((!(sub->filter & TIPC_SUB_PORTS)
+ == !(sub->filter & TIPC_SUB_SERVICE))
|| (sub->seq.lower > sub->seq.upper)) {
warn("Subscription rejected, illegal request\n");
kfree(sub);
diff --git a/net/xfrm/xfrm_hash.h b/net/xfrm/xfrm_hash.h
index d3abb0b7dc62..d401dc8f05ed 100644
--- a/net/xfrm/xfrm_hash.h
+++ b/net/xfrm/xfrm_hash.h
@@ -41,27 +41,28 @@ static inline unsigned int __xfrm_dst_hash(xfrm_address_t *daddr, xfrm_address_t
return (h ^ (h >> 16)) & hmask;
}
-static inline unsigned __xfrm_src_hash(xfrm_address_t *saddr,
+static inline unsigned __xfrm_src_hash(xfrm_address_t *daddr,
+ xfrm_address_t *saddr,
unsigned short family,
unsigned int hmask)
{
unsigned int h = family;
switch (family) {
case AF_INET:
- h ^= __xfrm4_addr_hash(saddr);
+ h ^= __xfrm4_daddr_saddr_hash(daddr, saddr);
break;
case AF_INET6:
- h ^= __xfrm6_addr_hash(saddr);
+ h ^= __xfrm6_daddr_saddr_hash(daddr, saddr);
break;
};
return (h ^ (h >> 16)) & hmask;
}
static inline unsigned int
-__xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family,
+__xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family,
unsigned int hmask)
{
- unsigned int h = spi ^ proto;
+ unsigned int h = (__force u32)spi ^ proto;
switch (family) {
case AF_INET:
h ^= __xfrm4_addr_hash(daddr);
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index dfc90bb1cf1f..e8198a2c785d 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -46,7 +46,7 @@ EXPORT_SYMBOL(secpath_dup);
/* Fetch spi and seq from ipsec header */
-int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
+int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
{
int offset, offset_seq;
@@ -62,7 +62,7 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
case IPPROTO_COMP:
if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
return -EINVAL;
- *spi = htonl(ntohs(*(u16*)(skb->h.raw + 2)));
+ *spi = htonl(ntohs(*(__be16*)(skb->h.raw + 2)));
*seq = 0;
return 0;
default:
@@ -72,8 +72,8 @@ int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq)
if (!pskb_may_pull(skb, 16))
return -EINVAL;
- *spi = *(u32*)(skb->h.raw + offset);
- *seq = *(u32*)(skb->h.raw + offset_seq);
+ *spi = *(__be32*)(skb->h.raw + offset);
+ *seq = *(__be32*)(skb->h.raw + offset_seq);
return 0;
}
EXPORT_SYMBOL(xfrm_parse_spi);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b6e2e79d7261..7736b23c3f03 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -778,8 +778,9 @@ void xfrm_policy_flush(u8 type)
for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
struct xfrm_policy *pol;
struct hlist_node *entry;
- int i;
+ int i, killed;
+ killed = 0;
again1:
hlist_for_each_entry(pol, entry,
&xfrm_policy_inexact[dir], bydst) {
@@ -790,6 +791,7 @@ void xfrm_policy_flush(u8 type)
write_unlock_bh(&xfrm_policy_lock);
xfrm_policy_kill(pol);
+ killed++;
write_lock_bh(&xfrm_policy_lock);
goto again1;
@@ -807,13 +809,14 @@ void xfrm_policy_flush(u8 type)
write_unlock_bh(&xfrm_policy_lock);
xfrm_policy_kill(pol);
+ killed++;
write_lock_bh(&xfrm_policy_lock);
goto again2;
}
}
- xfrm_policy_count[dir] = 0;
+ xfrm_policy_count[dir] -= killed;
}
atomic_inc(&flow_cache_genid);
write_unlock_bh(&xfrm_policy_lock);
@@ -880,30 +883,32 @@ out:
}
EXPORT_SYMBOL(xfrm_policy_walk);
-/* Find policy to apply to this flow. */
-
+/*
+ * Find policy to apply to this flow.
+ *
+ * Returns 0 if policy found, else an -errno.
+ */
static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl,
u8 type, u16 family, int dir)
{
struct xfrm_selector *sel = &pol->selector;
- int match;
+ int match, ret = -ESRCH;
if (pol->family != family ||
pol->type != type)
- return 0;
+ return ret;
match = xfrm_selector_match(sel, fl, family);
- if (match) {
- if (!security_xfrm_policy_lookup(pol, fl->secid, dir))
- return 1;
- }
+ if (match)
+ ret = security_xfrm_policy_lookup(pol, fl->secid, dir);
- return 0;
+ return ret;
}
static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
u16 family, u8 dir)
{
+ int err;
struct xfrm_policy *pol, *ret;
xfrm_address_t *daddr, *saddr;
struct hlist_node *entry;
@@ -919,7 +924,15 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
chain = policy_hash_direct(daddr, saddr, family, dir);
ret = NULL;
hlist_for_each_entry(pol, entry, chain, bydst) {
- if (xfrm_policy_match(pol, fl, type, family, dir)) {
+ err = xfrm_policy_match(pol, fl, type, family, dir);
+ if (err) {
+ if (err == -ESRCH)
+ continue;
+ else {
+ ret = ERR_PTR(err);
+ goto fail;
+ }
+ } else {
ret = pol;
priority = ret->priority;
break;
@@ -927,36 +940,53 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl,
}
chain = &xfrm_policy_inexact[dir];
hlist_for_each_entry(pol, entry, chain, bydst) {
- if (xfrm_policy_match(pol, fl, type, family, dir) &&
- pol->priority < priority) {
+ err = xfrm_policy_match(pol, fl, type, family, dir);
+ if (err) {
+ if (err == -ESRCH)
+ continue;
+ else {
+ ret = ERR_PTR(err);
+ goto fail;
+ }
+ } else if (pol->priority < priority) {
ret = pol;
break;
}
}
if (ret)
xfrm_pol_hold(ret);
+fail:
read_unlock_bh(&xfrm_policy_lock);
return ret;
}
-static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
+static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
void **objp, atomic_t **obj_refp)
{
struct xfrm_policy *pol;
+ int err = 0;
#ifdef CONFIG_XFRM_SUB_POLICY
pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir);
- if (pol)
+ if (IS_ERR(pol)) {
+ err = PTR_ERR(pol);
+ pol = NULL;
+ }
+ if (pol || err)
goto end;
#endif
pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir);
-
+ if (IS_ERR(pol)) {
+ err = PTR_ERR(pol);
+ pol = NULL;
+ }
#ifdef CONFIG_XFRM_SUB_POLICY
end:
#endif
if ((*objp = (void *) pol) != NULL)
*obj_refp = &pol->refcnt;
+ return err;
}
static inline int policy_to_flow_dir(int dir)
@@ -986,12 +1016,16 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc
sk->sk_family);
int err = 0;
- if (match)
- err = security_xfrm_policy_lookup(pol, fl->secid, policy_to_flow_dir(dir));
-
- if (match && !err)
- xfrm_pol_hold(pol);
- else
+ if (match) {
+ err = security_xfrm_policy_lookup(pol, fl->secid,
+ policy_to_flow_dir(dir));
+ if (!err)
+ xfrm_pol_hold(pol);
+ else if (err == -ESRCH)
+ pol = NULL;
+ else
+ pol = ERR_PTR(err);
+ } else
pol = NULL;
}
read_unlock_bh(&xfrm_policy_lock);
@@ -1283,8 +1317,11 @@ restart:
pol_dead = 0;
xfrm_nr = 0;
- if (sk && sk->sk_policy[1])
+ if (sk && sk->sk_policy[1]) {
policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
+ if (IS_ERR(policy))
+ return PTR_ERR(policy);
+ }
if (!policy) {
/* To accelerate a bit... */
@@ -1294,6 +1331,8 @@ restart:
policy = flow_cache_lookup(fl, dst_orig->ops->family,
dir, xfrm_policy_lookup);
+ if (IS_ERR(policy))
+ return PTR_ERR(policy);
}
if (!policy)
@@ -1340,6 +1379,10 @@ restart:
fl, family,
XFRM_POLICY_OUT);
if (pols[1]) {
+ if (IS_ERR(pols[1])) {
+ err = PTR_ERR(pols[1]);
+ goto error;
+ }
if (pols[1]->action == XFRM_POLICY_BLOCK) {
err = -EPERM;
goto error;
@@ -1571,13 +1614,19 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
}
pol = NULL;
- if (sk && sk->sk_policy[dir])
+ if (sk && sk->sk_policy[dir]) {
pol = xfrm_sk_policy_lookup(sk, dir, &fl);
+ if (IS_ERR(pol))
+ return 0;
+ }
if (!pol)
pol = flow_cache_lookup(&fl, family, fl_dir,
xfrm_policy_lookup);
+ if (IS_ERR(pol))
+ return 0;
+
if (!pol) {
if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) {
xfrm_secpath_reject(xerr_idx, skb, &fl);
@@ -1596,6 +1645,8 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb,
&fl, family,
XFRM_POLICY_IN);
if (pols[1]) {
+ if (IS_ERR(pols[1]))
+ return 0;
pols[1]->curlft.use_time = (unsigned long)xtime.tv_sec;
npols ++;
}
@@ -1703,7 +1754,7 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
static int stale_bundle(struct dst_entry *dst)
{
- return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0);
+ return !xfrm_bundle_ok(NULL, (struct xfrm_dst *)dst, NULL, AF_UNSPEC, 0);
}
void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
@@ -1825,7 +1876,8 @@ EXPORT_SYMBOL(xfrm_init_pmtu);
* still valid.
*/
-int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int strict)
+int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
+ struct flowi *fl, int family, int strict)
{
struct dst_entry *dst = &first->u.dst;
struct xfrm_dst *last;
@@ -1842,7 +1894,7 @@ int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family, int str
if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
return 0;
- if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm))
+ if (fl && !security_xfrm_flow_state_match(fl, dst->xfrm, pol))
return 0;
if (dst->xfrm->km.state != XFRM_STATE_VALID)
return 0;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 9f63edd39346..84bbf8474f3e 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -63,14 +63,15 @@ static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr,
return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask);
}
-static inline unsigned int xfrm_src_hash(xfrm_address_t *addr,
+static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr,
+ xfrm_address_t *saddr,
unsigned short family)
{
- return __xfrm_src_hash(addr, family, xfrm_state_hmask);
+ return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask);
}
static inline unsigned int
-xfrm_spi_hash(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
+xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
{
return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask);
}
@@ -92,13 +93,17 @@ static void xfrm_hash_transfer(struct hlist_head *list,
nhashmask);
hlist_add_head(&x->bydst, ndsttable+h);
- h = __xfrm_src_hash(&x->props.saddr, x->props.family,
+ h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr,
+ x->props.family,
nhashmask);
hlist_add_head(&x->bysrc, nsrctable+h);
- h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
- x->props.family, nhashmask);
- hlist_add_head(&x->byspi, nspitable+h);
+ if (x->id.spi) {
+ h = __xfrm_spi_hash(&x->id.daddr, x->id.spi,
+ x->id.proto, x->props.family,
+ nhashmask);
+ hlist_add_head(&x->byspi, nspitable+h);
+ }
}
}
@@ -421,7 +426,7 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl,
return 0;
}
-static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family)
+static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family)
{
unsigned int h = xfrm_spi_hash(daddr, spi, proto, family);
struct xfrm_state *x;
@@ -455,7 +460,7 @@ static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8
static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family)
{
- unsigned int h = xfrm_src_hash(saddr, family);
+ unsigned int h = xfrm_src_hash(daddr, saddr, family);
struct xfrm_state *x;
struct hlist_node *entry;
@@ -584,7 +589,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
if (km_query(x, tmpl, pol) == 0) {
x->km.state = XFRM_STATE_ACQ;
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
- h = xfrm_src_hash(saddr, family);
+ h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
if (x->id.spi) {
h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
@@ -609,6 +614,14 @@ out:
return x;
}
+static void xfrm_hash_grow_check(int have_hash_collision)
+{
+ if (have_hash_collision &&
+ (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
+ xfrm_state_num > xfrm_state_hmask)
+ schedule_work(&xfrm_hash_work);
+}
+
static void __xfrm_state_insert(struct xfrm_state *x)
{
unsigned int h;
@@ -619,10 +632,10 @@ static void __xfrm_state_insert(struct xfrm_state *x)
x->props.reqid, x->props.family);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
- h = xfrm_src_hash(&x->props.saddr, x->props.family);
+ h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
- if (xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY)) {
+ if (x->id.spi) {
h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto,
x->props.family);
@@ -637,10 +650,7 @@ static void __xfrm_state_insert(struct xfrm_state *x)
xfrm_state_num++;
- if (x->bydst.next != NULL &&
- (xfrm_state_hmask + 1) < xfrm_state_hashmax &&
- xfrm_state_num > xfrm_state_hmask)
- schedule_work(&xfrm_hash_work);
+ xfrm_hash_grow_check(x->bydst.next != NULL);
}
/* xfrm_state_lock is held */
@@ -745,9 +755,13 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re
x->timer.expires = jiffies + XFRM_ACQ_EXPIRES*HZ;
add_timer(&x->timer);
hlist_add_head(&x->bydst, xfrm_state_bydst+h);
- h = xfrm_src_hash(saddr, family);
+ h = xfrm_src_hash(daddr, saddr, family);
hlist_add_head(&x->bysrc, xfrm_state_bysrc+h);
wake_up(&km_waitq);
+
+ xfrm_state_num++;
+
+ xfrm_hash_grow_check(x->bydst.next != NULL);
}
return x;
@@ -916,7 +930,7 @@ err:
EXPORT_SYMBOL(xfrm_state_check);
struct xfrm_state *
-xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto,
+xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto,
unsigned short family)
{
struct xfrm_state *x;
@@ -1040,7 +1054,7 @@ u32 xfrm_get_acqseq(void)
EXPORT_SYMBOL(xfrm_get_acqseq);
void
-xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
+xfrm_alloc_spi(struct xfrm_state *x, __be32 minspi, __be32 maxspi)
{
unsigned int h;
struct xfrm_state *x0;
@@ -1057,10 +1071,10 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
x->id.spi = minspi;
} else {
u32 spi = 0;
- minspi = ntohl(minspi);
- maxspi = ntohl(maxspi);
- for (h=0; h<maxspi-minspi+1; h++) {
- spi = minspi + net_random()%(maxspi-minspi+1);
+ u32 low = ntohl(minspi);
+ u32 high = ntohl(maxspi);
+ for (h=0; h<high-low+1; h++) {
+ spi = low + net_random()%(high-low+1);
x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family);
if (x0 == NULL) {
x->id.spi = htonl(spi);
@@ -1180,11 +1194,10 @@ static void xfrm_replay_timer_handler(unsigned long data)
spin_unlock(&x->lock);
}
-int xfrm_replay_check(struct xfrm_state *x, u32 seq)
+int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq)
{
u32 diff;
-
- seq = ntohl(seq);
+ u32 seq = ntohl(net_seq);
if (unlikely(seq == 0))
return -EINVAL;
@@ -1206,11 +1219,10 @@ int xfrm_replay_check(struct xfrm_state *x, u32 seq)
}
EXPORT_SYMBOL(xfrm_replay_check);
-void xfrm_replay_advance(struct xfrm_state *x, u32 seq)
+void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq)
{
u32 diff;
-
- seq = ntohl(seq);
+ u32 seq = ntohl(net_seq);
if (seq > x->replay.seq) {
diff = seq - x->replay.seq;
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index c59a78d2923a..2b2e59d8ffbc 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -211,6 +211,7 @@ static int verify_newsa_info(struct xfrm_usersa_info *p,
case XFRM_MODE_TRANSPORT:
case XFRM_MODE_TUNNEL:
case XFRM_MODE_ROUTEOPTIMIZATION:
+ case XFRM_MODE_BEET:
break;
default:
@@ -1991,15 +1992,6 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt,
xp->type = XFRM_POLICY_TYPE_MAIN;
copy_templates(xp, ut, nr);
- if (!xp->security) {
- int err = security_xfrm_sock_policy_alloc(xp, sk);
- if (err) {
- kfree(xp);
- *dir = err;
- return NULL;
- }
- }
-
*dir = p->dir;
return xp;
diff --git a/scripts/.gitignore b/scripts/.gitignore
index a234e524a490..a1f52cb47200 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -5,3 +5,4 @@ conmakehash
kallsyms
pnmtologo
bin2c
+unifdef
diff --git a/scripts/Makefile b/scripts/Makefile
index ea41de8fb7f5..1c73c5aea66b 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -13,7 +13,7 @@ hostprogs-$(CONFIG_VT) += conmakehash
hostprogs-$(CONFIG_PROM_CONSOLE) += conmakehash
hostprogs-$(CONFIG_IKCONFIG) += bin2c
-always := $(hostprogs-y)
+always := $(hostprogs-y) $(hostprogs-m)
# The following hostprogs-y programs are only build on demand
hostprogs-y += unifdef
diff --git a/scripts/Makefile.headersinst b/scripts/Makefile.headersinst
index cac8f21a3392..4241e0dfeeaf 100644
--- a/scripts/Makefile.headersinst
+++ b/scripts/Makefile.headersinst
@@ -97,7 +97,7 @@ quiet_cmd_unifdef = UNIFDEF $(patsubst $(INSTALL_HDR_PATH)/%,%,$@)
| $(HDRSED) > $@ || :
quiet_cmd_check = CHECK $(patsubst $(INSTALL_HDR_PATH)/$(_dst)/.check.%,$(_dst)/%,$@)
- cmd_check = $(srctree)/scripts/hdrcheck.sh \
+ cmd_check = $(CONFIG_SHELL) $(srctree)/scripts/hdrcheck.sh \
$(INSTALL_HDR_PATH)/include $(subst /.check.,/,$@) $@
quiet_cmd_remove = REMOVE $(_dst)/$@
@@ -168,7 +168,7 @@ $(objhdr-y) $(header-y) $(unifdef-y): $(KBUILDFILES)
$(call cmd,gen)
else
-$(objhdr-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(srctree)/$(obj)/%.h $(KBUILDFILES)
+$(objhdr-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(objtree)/$(obj)/%.h $(KBUILDFILES)
$(call cmd,o_hdr_install)
$(header-y) : $(INSTALL_HDR_PATH)/$(_dst)/%.h: $(srctree)/$(obj)/%.h $(KBUILDFILES)
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index 4b2721ca97da..65e0a79c36cf 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -32,6 +32,10 @@
# Step 4 is solely used to allow module versioning in external modules,
# where the CRC of each module is retrieved from the Module.symers file.
+# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined
+# symbols in the final module linking stage
+# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules.
+# This is solely usefull to speed up test compiles
PHONY := _modpost
_modpost: __modpost
@@ -40,13 +44,14 @@ include scripts/Kbuild.include
include scripts/Makefile.lib
kernelsymfile := $(objtree)/Module.symvers
-modulesymfile := $(KBUILD_EXTMOD)/Module.symvers
+modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers
# Step 1), find all modules listed in $(MODVERDIR)/
__modules := $(sort $(shell grep -h '\.ko' /dev/null $(wildcard $(MODVERDIR)/*.mod)))
modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o)))
-_modpost: $(modules)
+# Stop after building .o files if NOFINAL is set. Makes compile tests quicker
+_modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules))
# Step 2), invoke modpost
@@ -58,7 +63,7 @@ quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules
$(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \
$(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \
$(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \
- $(if $(KBUILD_EXTMOD),-w) \
+ $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
$(wildcard vmlinux) $(filter-out FORCE,$^)
PHONY += __modpost
@@ -92,7 +97,7 @@ targets += $(modules:.ko=.mod.o)
# Step 6), final link of the modules
quiet_cmd_ld_ko_o = LD [M] $@
- cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
+ cmd_ld_ko_o = $(LD) $(LDFLAGS) $(LDFLAGS_MODULE) -o $@ \
$(filter-out FORCE,$^)
$(modules): %.ko :%.o %.mod.o FORCE
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index cb02baa63256..4ab6cbf09225 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -177,6 +177,7 @@ void find_export_symbols(char * filename)
{
fprintf(stderr, "docproc: ");
perror(real_filename);
+ exit(1);
}
while(fgets(line, MAXLINESZ, fp)) {
char *p;
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index a90d3cc76bfa..7e7e147875bf 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -11,7 +11,6 @@ gconfig: $(obj)/gconf
$< arch/$(ARCH)/Kconfig
menuconfig: $(obj)/mconf
- $(Q)$(MAKE) $(build)=scripts/kconfig/lxdialog
$< arch/$(ARCH)/Kconfig
config: $(obj)/conf
@@ -81,6 +80,23 @@ help:
@echo ' allyesconfig - New config where all options are accepted with yes'
@echo ' allnoconfig - New config where all options are answered with no'
+# lxdialog stuff
+check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh
+
+# Use reursively expanded variables so we do not call gcc unless
+# we really need to do so. (Do not call gcc as part of make mrproper)
+HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
+HOST_LOADLIBES = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+
+HOST_EXTRACFLAGS += -DLOCALE
+
+PHONY += $(obj)/dochecklxdialog
+$(obj)/dochecklxdialog:
+ $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_LOADLIBES)
+
+always := dochecklxdialog
+
+
# ===========================================================================
# Shared Makefile for the various kconfig executables:
# conf: Used for defconfig, oldconfig and related targets
@@ -92,11 +108,19 @@ help:
# Based on GTK which needs to be installed to compile it
# object files used by all kconfig flavours
-hostprogs-y := conf mconf qconf gconf kxgettext
+lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o
+lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o
+
conf-objs := conf.o zconf.tab.o
-mconf-objs := mconf.o zconf.tab.o
+mconf-objs := mconf.o zconf.tab.o $(lxdialog)
kxgettext-objs := kxgettext.o zconf.tab.o
+hostprogs-y := conf qconf gconf kxgettext
+
+ifeq ($(MAKECMDGOALS),menuconfig)
+ hostprogs-y += mconf
+endif
+
ifeq ($(MAKECMDGOALS),xconfig)
qconf-target := 1
endif
@@ -116,7 +140,6 @@ endif
clean-files := lkc_defs.h qconf.moc .tmp_qtcheck \
.tmp_gtkcheck zconf.tab.c lex.zconf.c zconf.hash.c
-subdir- += lxdialog
# Needed for systems without gettext
KBUILD_HAVE_NLS := $(shell \
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 69f96b398c22..66b15ef02931 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -517,7 +517,7 @@ int conf_write(const char *name)
fclose(out);
if (*tmpname) {
- strcat(dirname, name ? name : conf_get_configname());
+ strcat(dirname, basename);
strcat(dirname, ".old");
rename(newname, dirname);
if (rename(tmpname, newname))
diff --git a/scripts/kconfig/lxdialog/Makefile b/scripts/kconfig/lxdialog/Makefile
deleted file mode 100644
index a8b026326247..000000000000
--- a/scripts/kconfig/lxdialog/Makefile
+++ /dev/null
@@ -1,21 +0,0 @@
-# Makefile to build lxdialog package
-#
-
-check-lxdialog := $(srctree)/$(src)/check-lxdialog.sh
-
-# Use reursively expanded variables so we do not call gcc unless
-# we really need to do so. (Do not call gcc as part of make mrproper)
-HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
-HOST_LOADLIBES = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
-
-HOST_EXTRACFLAGS += -DLOCALE
-
-PHONY += dochecklxdialog
-$(obj)/dochecklxdialog:
- $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_LOADLIBES)
-
-hostprogs-y := lxdialog
-always := $(hostprogs-y) dochecklxdialog
-
-lxdialog-objs := checklist.o menubox.o textbox.o yesno.o inputbox.o \
- util.o lxdialog.o msgbox.o
diff --git a/scripts/kconfig/lxdialog/checklist.c b/scripts/kconfig/lxdialog/checklist.c
index 79886413b6d5..cf697080dddd 100644
--- a/scripts/kconfig/lxdialog/checklist.c
+++ b/scripts/kconfig/lxdialog/checklist.c
@@ -28,25 +28,25 @@ static int list_width, check_x, item_x;
/*
* Print list item
*/
-static void print_item(WINDOW * win, const char *item, int status, int choice,
- int selected)
+static void print_item(WINDOW * win, int choice, int selected)
{
int i;
/* Clear 'residue' of last item */
- wattrset(win, menubox_attr);
+ wattrset(win, dlg.menubox.atr);
wmove(win, choice, 0);
for (i = 0; i < list_width; i++)
waddch(win, ' ');
wmove(win, choice, check_x);
- wattrset(win, selected ? check_selected_attr : check_attr);
- wprintw(win, "(%c)", status ? 'X' : ' ');
-
- wattrset(win, selected ? tag_selected_attr : tag_attr);
- mvwaddch(win, choice, item_x, item[0]);
- wattrset(win, selected ? item_selected_attr : item_attr);
- waddstr(win, (char *)item + 1);
+ wattrset(win, selected ? dlg.check_selected.atr
+ : dlg.check.atr);
+ wprintw(win, "(%c)", item_is_tag('X') ? 'X' : ' ');
+
+ wattrset(win, selected ? dlg.tag_selected.atr : dlg.tag.atr);
+ mvwaddch(win, choice, item_x, item_str()[0]);
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ waddstr(win, (char *)item_str() + 1);
if (selected) {
wmove(win, choice, check_x + 1);
wrefresh(win);
@@ -62,11 +62,11 @@ static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
wmove(win, y, x);
if (scroll > 0) {
- wattrset(win, uarrow_attr);
+ wattrset(win, dlg.uarrow.atr);
waddch(win, ACS_UARROW);
waddstr(win, "(-)");
} else {
- wattrset(win, menubox_attr);
+ wattrset(win, dlg.menubox.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
@@ -77,11 +77,11 @@ static void print_arrows(WINDOW * win, int choice, int item_no, int scroll,
wmove(win, y, x);
if ((height < item_no) && (scroll + choice < item_no - 1)) {
- wattrset(win, darrow_attr);
+ wattrset(win, dlg.darrow.atr);
waddch(win, ACS_DARROW);
waddstr(win, "(+)");
} else {
- wattrset(win, menubox_border_attr);
+ wattrset(win, dlg.menubox_border.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
@@ -109,32 +109,29 @@ static void print_buttons(WINDOW * dialog, int height, int width, int selected)
* in the style of radiolist (only one option turned on at a time).
*/
int dialog_checklist(const char *title, const char *prompt, int height,
- int width, int list_height, int item_no,
- const char *const *items)
+ int width, int list_height)
{
int i, x, y, box_x, box_y;
- int key = 0, button = 0, choice = 0, scroll = 0, max_choice, *status;
+ int key = 0, button = 0, choice = 0, scroll = 0, max_choice;
WINDOW *dialog, *list;
- /* Allocate space for storing item on/off status */
- if ((status = malloc(sizeof(int) * item_no)) == NULL) {
- endwin();
- fprintf(stderr,
- "\nCan't allocate memory in dialog_checklist().\n");
- exit(-1);
+ /* which item to highlight */
+ item_foreach() {
+ if (item_is_tag('X'))
+ choice = item_n();
+ if (item_is_selected()) {
+ choice = item_n();
+ break;
+ }
}
- /* Initializes status */
- for (i = 0; i < item_no; i++) {
- status[i] = !strcasecmp(items[i * 3 + 2], "on");
- if ((!choice && status[i])
- || !strcasecmp(items[i * 3 + 2], "selected"))
- choice = i + 1;
- }
- if (choice)
- choice--;
+do_resize:
+ if (getmaxy(stdscr) < (height + 6))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + 6))
+ return -ERRDISPLAYTOOSMALL;
- max_choice = MIN(list_height, item_no);
+ max_choice = MIN(list_height, item_count());
/* center dialog box on screen */
x = (COLS - width) / 2;
@@ -145,17 +142,18 @@ int dialog_checklist(const char *title, const char *prompt, int height,
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
- wattrset(dialog, border_attr);
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
- wattrset(dialog, dialog_attr);
+ wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
- wattrset(dialog, dialog_attr);
+ wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
list_width = width - 6;
@@ -170,12 +168,12 @@ int dialog_checklist(const char *title, const char *prompt, int height,
/* draw a box around the list items */
draw_box(dialog, box_y, box_x, list_height + 2, list_width + 2,
- menubox_border_attr, menubox_attr);
+ dlg.menubox_border.atr, dlg.menubox.atr);
/* Find length of longest item in order to center checklist */
check_x = 0;
- for (i = 0; i < item_no; i++)
- check_x = MAX(check_x, +strlen(items[i * 3 + 1]) + 4);
+ item_foreach()
+ check_x = MAX(check_x, strlen(item_str()) + 4);
check_x = (list_width - check_x) / 2;
item_x = check_x + 4;
@@ -187,14 +185,11 @@ int dialog_checklist(const char *title, const char *prompt, int height,
/* Print the list */
for (i = 0; i < max_choice; i++) {
- if (i != choice)
- print_item(list, items[(scroll + i) * 3 + 1],
- status[i + scroll], i, 0);
+ item_set(scroll + i);
+ print_item(list, i, i == choice);
}
- print_item(list, items[(scroll + choice) * 3 + 1],
- status[choice + scroll], choice, 1);
- print_arrows(dialog, choice, item_no, scroll,
+ print_arrows(dialog, choice, item_count(), scroll,
box_y, box_x + check_x + 5, list_height);
print_buttons(dialog, height, width, 0);
@@ -203,13 +198,14 @@ int dialog_checklist(const char *title, const char *prompt, int height,
wnoutrefresh(list);
doupdate();
- while (key != ESC) {
+ while (key != KEY_ESC) {
key = wgetch(dialog);
- for (i = 0; i < max_choice; i++)
- if (toupper(key) ==
- toupper(items[(scroll + i) * 3 + 1][0]))
+ for (i = 0; i < max_choice; i++) {
+ item_set(i + scroll);
+ if (toupper(key) == toupper(item_str()[0]))
break;
+ }
if (i < max_choice || key == KEY_UP || key == KEY_DOWN ||
key == '+' || key == '-') {
@@ -220,15 +216,16 @@ int dialog_checklist(const char *title, const char *prompt, int height,
/* Scroll list down */
if (list_height > 1) {
/* De-highlight current first item */
- print_item(list, items[scroll * 3 + 1],
- status[scroll], 0, FALSE);
+ item_set(scroll);
+ print_item(list, 0, FALSE);
scrollok(list, TRUE);
wscrl(list, -1);
scrollok(list, FALSE);
}
scroll--;
- print_item(list, items[scroll * 3 + 1], status[scroll], 0, TRUE);
- print_arrows(dialog, choice, item_no,
+ item_set(scroll);
+ print_item(list, 0, TRUE);
+ print_arrows(dialog, choice, item_count(),
scroll, box_y, box_x + check_x + 5, list_height);
wnoutrefresh(dialog);
@@ -239,23 +236,24 @@ int dialog_checklist(const char *title, const char *prompt, int height,
i = choice - 1;
} else if (key == KEY_DOWN || key == '+') {
if (choice == max_choice - 1) {
- if (scroll + choice >= item_no - 1)
+ if (scroll + choice >= item_count() - 1)
continue;
/* Scroll list up */
if (list_height > 1) {
/* De-highlight current last item before scrolling up */
- print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
- status[scroll + max_choice - 1],
- max_choice - 1, FALSE);
+ item_set(scroll + max_choice - 1);
+ print_item(list,
+ max_choice - 1,
+ FALSE);
scrollok(list, TRUE);
wscrl(list, 1);
scrollok(list, FALSE);
}
scroll++;
- print_item(list, items[(scroll + max_choice - 1) * 3 + 1],
- status[scroll + max_choice - 1], max_choice - 1, TRUE);
+ item_set(scroll + max_choice - 1);
+ print_item(list, max_choice - 1, TRUE);
- print_arrows(dialog, choice, item_no,
+ print_arrows(dialog, choice, item_count(),
scroll, box_y, box_x + check_x + 5, list_height);
wnoutrefresh(dialog);
@@ -267,12 +265,12 @@ int dialog_checklist(const char *title, const char *prompt, int height,
}
if (i != choice) {
/* De-highlight current item */
- print_item(list, items[(scroll + choice) * 3 + 1],
- status[scroll + choice], choice, FALSE);
+ item_set(scroll + choice);
+ print_item(list, choice, FALSE);
/* Highlight new item */
choice = i;
- print_item(list, items[(scroll + choice) * 3 + 1],
- status[scroll + choice], choice, TRUE);
+ item_set(scroll + choice);
+ print_item(list, choice, TRUE);
wnoutrefresh(dialog);
wrefresh(list);
}
@@ -282,10 +280,19 @@ int dialog_checklist(const char *title, const char *prompt, int height,
case 'H':
case 'h':
case '?':
- fprintf(stderr, "%s", items[(scroll + choice) * 3]);
+ button = 1;
+ /* fall-through */
+ case 'S':
+ case 's':
+ case ' ':
+ case '\n':
+ item_foreach()
+ item_set_selected(0);
+ item_set(scroll + choice);
+ item_set_selected(1);
+ delwin(list);
delwin(dialog);
- free(status);
- return 1;
+ return button;
case TAB:
case KEY_LEFT:
case KEY_RIGHT:
@@ -295,42 +302,24 @@ int dialog_checklist(const char *title, const char *prompt, int height,
print_buttons(dialog, height, width, button);
wrefresh(dialog);
break;
- case 'S':
- case 's':
- case ' ':
- case '\n':
- if (!button) {
- if (!status[scroll + choice]) {
- for (i = 0; i < item_no; i++)
- status[i] = 0;
- status[scroll + choice] = 1;
- for (i = 0; i < max_choice; i++)
- print_item(list, items[(scroll + i) * 3 + 1],
- status[scroll + i], i, i == choice);
- }
- wnoutrefresh(dialog);
- wrefresh(list);
-
- for (i = 0; i < item_no; i++)
- if (status[i])
- fprintf(stderr, "%s", items[i * 3]);
- } else
- fprintf(stderr, "%s", items[(scroll + choice) * 3]);
- delwin(dialog);
- free(status);
- return button;
case 'X':
case 'x':
- key = ESC;
- case ESC:
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
break;
+ case KEY_RESIZE:
+ delwin(list);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
}
/* Now, update everything... */
doupdate();
}
-
+ delwin(list);
delwin(dialog);
- free(status);
- return -1; /* ESC pressed */
+ return key; /* ESC pressed */
}
diff --git a/scripts/kconfig/lxdialog/colors.h b/scripts/kconfig/lxdialog/colors.h
deleted file mode 100644
index db071df12bbb..000000000000
--- a/scripts/kconfig/lxdialog/colors.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * colors.h -- color attribute definitions
- *
- * AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * Default color definitions
- *
- * *_FG = foreground
- * *_BG = background
- * *_HL = highlight?
- */
-#define SCREEN_FG COLOR_CYAN
-#define SCREEN_BG COLOR_BLUE
-#define SCREEN_HL TRUE
-
-#define SHADOW_FG COLOR_BLACK
-#define SHADOW_BG COLOR_BLACK
-#define SHADOW_HL TRUE
-
-#define DIALOG_FG COLOR_BLACK
-#define DIALOG_BG COLOR_WHITE
-#define DIALOG_HL FALSE
-
-#define TITLE_FG COLOR_YELLOW
-#define TITLE_BG COLOR_WHITE
-#define TITLE_HL TRUE
-
-#define BORDER_FG COLOR_WHITE
-#define BORDER_BG COLOR_WHITE
-#define BORDER_HL TRUE
-
-#define BUTTON_ACTIVE_FG COLOR_WHITE
-#define BUTTON_ACTIVE_BG COLOR_BLUE
-#define BUTTON_ACTIVE_HL TRUE
-
-#define BUTTON_INACTIVE_FG COLOR_BLACK
-#define BUTTON_INACTIVE_BG COLOR_WHITE
-#define BUTTON_INACTIVE_HL FALSE
-
-#define BUTTON_KEY_ACTIVE_FG COLOR_WHITE
-#define BUTTON_KEY_ACTIVE_BG COLOR_BLUE
-#define BUTTON_KEY_ACTIVE_HL TRUE
-
-#define BUTTON_KEY_INACTIVE_FG COLOR_RED
-#define BUTTON_KEY_INACTIVE_BG COLOR_WHITE
-#define BUTTON_KEY_INACTIVE_HL FALSE
-
-#define BUTTON_LABEL_ACTIVE_FG COLOR_YELLOW
-#define BUTTON_LABEL_ACTIVE_BG COLOR_BLUE
-#define BUTTON_LABEL_ACTIVE_HL TRUE
-
-#define BUTTON_LABEL_INACTIVE_FG COLOR_BLACK
-#define BUTTON_LABEL_INACTIVE_BG COLOR_WHITE
-#define BUTTON_LABEL_INACTIVE_HL TRUE
-
-#define INPUTBOX_FG COLOR_BLACK
-#define INPUTBOX_BG COLOR_WHITE
-#define INPUTBOX_HL FALSE
-
-#define INPUTBOX_BORDER_FG COLOR_BLACK
-#define INPUTBOX_BORDER_BG COLOR_WHITE
-#define INPUTBOX_BORDER_HL FALSE
-
-#define SEARCHBOX_FG COLOR_BLACK
-#define SEARCHBOX_BG COLOR_WHITE
-#define SEARCHBOX_HL FALSE
-
-#define SEARCHBOX_TITLE_FG COLOR_YELLOW
-#define SEARCHBOX_TITLE_BG COLOR_WHITE
-#define SEARCHBOX_TITLE_HL TRUE
-
-#define SEARCHBOX_BORDER_FG COLOR_WHITE
-#define SEARCHBOX_BORDER_BG COLOR_WHITE
-#define SEARCHBOX_BORDER_HL TRUE
-
-#define POSITION_INDICATOR_FG COLOR_YELLOW
-#define POSITION_INDICATOR_BG COLOR_WHITE
-#define POSITION_INDICATOR_HL TRUE
-
-#define MENUBOX_FG COLOR_BLACK
-#define MENUBOX_BG COLOR_WHITE
-#define MENUBOX_HL FALSE
-
-#define MENUBOX_BORDER_FG COLOR_WHITE
-#define MENUBOX_BORDER_BG COLOR_WHITE
-#define MENUBOX_BORDER_HL TRUE
-
-#define ITEM_FG COLOR_BLACK
-#define ITEM_BG COLOR_WHITE
-#define ITEM_HL FALSE
-
-#define ITEM_SELECTED_FG COLOR_WHITE
-#define ITEM_SELECTED_BG COLOR_BLUE
-#define ITEM_SELECTED_HL TRUE
-
-#define TAG_FG COLOR_YELLOW
-#define TAG_BG COLOR_WHITE
-#define TAG_HL TRUE
-
-#define TAG_SELECTED_FG COLOR_YELLOW
-#define TAG_SELECTED_BG COLOR_BLUE
-#define TAG_SELECTED_HL TRUE
-
-#define TAG_KEY_FG COLOR_YELLOW
-#define TAG_KEY_BG COLOR_WHITE
-#define TAG_KEY_HL TRUE
-
-#define TAG_KEY_SELECTED_FG COLOR_YELLOW
-#define TAG_KEY_SELECTED_BG COLOR_BLUE
-#define TAG_KEY_SELECTED_HL TRUE
-
-#define CHECK_FG COLOR_BLACK
-#define CHECK_BG COLOR_WHITE
-#define CHECK_HL FALSE
-
-#define CHECK_SELECTED_FG COLOR_WHITE
-#define CHECK_SELECTED_BG COLOR_BLUE
-#define CHECK_SELECTED_HL TRUE
-
-#define UARROW_FG COLOR_GREEN
-#define UARROW_BG COLOR_WHITE
-#define UARROW_HL TRUE
-
-#define DARROW_FG COLOR_GREEN
-#define DARROW_BG COLOR_WHITE
-#define DARROW_HL TRUE
-
-/* End of default color definitions */
-
-#define C_ATTR(x,y) ((x ? A_BOLD : 0) | COLOR_PAIR((y)))
-#define COLOR_NAME_LEN 10
-#define COLOR_COUNT 8
-
-/*
- * Global variables
- */
-
-extern int color_table[][3];
diff --git a/scripts/kconfig/lxdialog/dialog.h b/scripts/kconfig/lxdialog/dialog.h
index af3cf716e215..fd695e1070f7 100644
--- a/scripts/kconfig/lxdialog/dialog.h
+++ b/scripts/kconfig/lxdialog/dialog.h
@@ -24,6 +24,7 @@
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
#ifdef __sun__
#define CURS_MACROS
@@ -48,7 +49,7 @@
#define TR(params) _tracef params
-#define ESC 27
+#define KEY_ESC 27
#define TAB 9
#define MAX_LEN 2048
#define BUF_SIZE (10*1024)
@@ -86,63 +87,111 @@
#define ACS_DARROW 'v'
#endif
+/* error return codes */
+#define ERRDISPLAYTOOSMALL (KEY_MAX + 1)
+
/*
- * Attribute names
+ * Color definitions
*/
-#define screen_attr attributes[0]
-#define shadow_attr attributes[1]
-#define dialog_attr attributes[2]
-#define title_attr attributes[3]
-#define border_attr attributes[4]
-#define button_active_attr attributes[5]
-#define button_inactive_attr attributes[6]
-#define button_key_active_attr attributes[7]
-#define button_key_inactive_attr attributes[8]
-#define button_label_active_attr attributes[9]
-#define button_label_inactive_attr attributes[10]
-#define inputbox_attr attributes[11]
-#define inputbox_border_attr attributes[12]
-#define searchbox_attr attributes[13]
-#define searchbox_title_attr attributes[14]
-#define searchbox_border_attr attributes[15]
-#define position_indicator_attr attributes[16]
-#define menubox_attr attributes[17]
-#define menubox_border_attr attributes[18]
-#define item_attr attributes[19]
-#define item_selected_attr attributes[20]
-#define tag_attr attributes[21]
-#define tag_selected_attr attributes[22]
-#define tag_key_attr attributes[23]
-#define tag_key_selected_attr attributes[24]
-#define check_attr attributes[25]
-#define check_selected_attr attributes[26]
-#define uarrow_attr attributes[27]
-#define darrow_attr attributes[28]
-
-/* number of attributes */
-#define ATTRIBUTE_COUNT 29
+struct dialog_color {
+ chtype atr; /* Color attribute */
+ int fg; /* foreground */
+ int bg; /* background */
+ int hl; /* highlight this item */
+};
+
+struct dialog_info {
+ const char *backtitle;
+ struct dialog_color screen;
+ struct dialog_color shadow;
+ struct dialog_color dialog;
+ struct dialog_color title;
+ struct dialog_color border;
+ struct dialog_color button_active;
+ struct dialog_color button_inactive;
+ struct dialog_color button_key_active;
+ struct dialog_color button_key_inactive;
+ struct dialog_color button_label_active;
+ struct dialog_color button_label_inactive;
+ struct dialog_color inputbox;
+ struct dialog_color inputbox_border;
+ struct dialog_color searchbox;
+ struct dialog_color searchbox_title;
+ struct dialog_color searchbox_border;
+ struct dialog_color position_indicator;
+ struct dialog_color menubox;
+ struct dialog_color menubox_border;
+ struct dialog_color item;
+ struct dialog_color item_selected;
+ struct dialog_color tag;
+ struct dialog_color tag_selected;
+ struct dialog_color tag_key;
+ struct dialog_color tag_key_selected;
+ struct dialog_color check;
+ struct dialog_color check_selected;
+ struct dialog_color uarrow;
+ struct dialog_color darrow;
+};
/*
* Global variables
*/
-extern bool use_colors;
-extern bool use_shadow;
-
-extern chtype attributes[];
-
-extern const char *backtitle;
+extern struct dialog_info dlg;
+extern char dialog_input_result[];
/*
* Function prototypes
*/
-extern void create_rc(const char *filename);
-extern int parse_rc(void);
-void init_dialog(void);
+/* item list as used by checklist and menubox */
+void item_reset(void);
+void item_make(const char *fmt, ...);
+void item_add_str(const char *fmt, ...);
+void item_set_tag(char tag);
+void item_set_data(void *p);
+void item_set_selected(int val);
+int item_activate_selected(void);
+void *item_data(void);
+char item_tag(void);
+
+/* item list manipulation for lxdialog use */
+#define MAXITEMSTR 200
+struct dialog_item {
+ char str[MAXITEMSTR]; /* promtp displayed */
+ char tag;
+ void *data; /* pointer to menu item - used by menubox+checklist */
+ int selected; /* Set to 1 by dialog_*() function if selected. */
+};
+
+/* list of lialog_items */
+struct dialog_list {
+ struct dialog_item node;
+ struct dialog_list *next;
+};
+
+extern struct dialog_list *item_cur;
+extern struct dialog_list item_nil;
+extern struct dialog_list *item_head;
+
+int item_count(void);
+void item_set(int n);
+int item_n(void);
+const char *item_str(void);
+int item_is_selected(void);
+int item_is_tag(char tag);
+#define item_foreach() \
+ for (item_cur = item_head ? item_head: item_cur; \
+ item_cur && (item_cur != &item_nil); item_cur = item_cur->next)
+
+/* generic key handlers */
+int on_key_esc(WINDOW *win);
+int on_key_resize(void);
+
+void init_dialog(const char *backtitle);
+void reset_dialog(void);
void end_dialog(void);
void attr_clear(WINDOW * win, int height, int width, chtype attr);
void dialog_clear(void);
-void color_setup(void);
void print_autowrap(WINDOW * win, const char *prompt, int width, int y, int x);
void print_button(WINDOW * win, const char *label, int y, int x, int selected);
void print_title(WINDOW *dialog, const char *title, int width);
@@ -155,12 +204,10 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width);
int dialog_msgbox(const char *title, const char *prompt, int height,
int width, int pause);
int dialog_textbox(const char *title, const char *file, int height, int width);
-int dialog_menu(const char *title, const char *prompt, int height, int width,
- int menu_height, const char *choice, int item_no,
- const char *const *items);
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll);
int dialog_checklist(const char *title, const char *prompt, int height,
- int width, int list_height, int item_no,
- const char *const *items);
+ int width, int list_height);
extern char dialog_input_result[];
int dialog_inputbox(const char *title, const char *prompt, int height,
int width, const char *init);
diff --git a/scripts/kconfig/lxdialog/inputbox.c b/scripts/kconfig/lxdialog/inputbox.c
index 779503726b0a..05e72066b359 100644
--- a/scripts/kconfig/lxdialog/inputbox.c
+++ b/scripts/kconfig/lxdialog/inputbox.c
@@ -49,6 +49,17 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
char *instr = dialog_input_result;
WINDOW *dialog;
+ if (!init)
+ instr[0] = '\0';
+ else
+ strcpy(instr, init);
+
+do_resize:
+ if (getmaxy(stdscr) <= (height - 2))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) <= (width - 2))
+ return -ERRDISPLAYTOOSMALL;
+
/* center dialog box on screen */
x = (COLS - width) / 2;
y = (LINES - height) / 2;
@@ -58,17 +69,18 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
- wattrset(dialog, border_attr);
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
- wattrset(dialog, dialog_attr);
+ wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
- wattrset(dialog, dialog_attr);
+ wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
/* Draw the input field box */
@@ -76,18 +88,14 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
getyx(dialog, y, x);
box_y = y + 2;
box_x = (width - box_width) / 2;
- draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2, border_attr, dialog_attr);
+ draw_box(dialog, y + 1, box_x - 1, 3, box_width + 2,
+ dlg.border.atr, dlg.dialog.atr);
print_buttons(dialog, height, width, 0);
/* Set up the initial value */
wmove(dialog, box_y, box_x);
- wattrset(dialog, inputbox_attr);
-
- if (!init)
- instr[0] = '\0';
- else
- strcpy(instr, init);
+ wattrset(dialog, dlg.inputbox.atr);
input_x = strlen(instr);
@@ -104,7 +112,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
wrefresh(dialog);
- while (key != ESC) {
+ while (key != KEY_ESC) {
key = wgetch(dialog);
if (button == -1) { /* Input box selected */
@@ -120,7 +128,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
case KEY_BACKSPACE:
case 127:
if (input_x || scroll) {
- wattrset(dialog, inputbox_attr);
+ wattrset(dialog, dlg.inputbox.atr);
if (!input_x) {
scroll = scroll < box_width - 1 ? 0 : scroll - (box_width - 1);
wmove(dialog, box_y, box_x);
@@ -140,7 +148,7 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
default:
if (key < 0x100 && isprint(key)) {
if (scroll + input_x < MAX_LEN) {
- wattrset(dialog, inputbox_attr);
+ wattrset(dialog, dlg.inputbox.atr);
instr[scroll + input_x] = key;
instr[scroll + input_x + 1] = '\0';
if (input_x == box_width - 1) {
@@ -213,12 +221,18 @@ int dialog_inputbox(const char *title, const char *prompt, int height, int width
return (button == -1 ? 0 : button);
case 'X':
case 'x':
- key = ESC;
- case ESC:
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(dialog);
break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
}
}
delwin(dialog);
- return -1; /* ESC pressed */
+ return KEY_ESC; /* ESC pressed */
}
diff --git a/scripts/kconfig/lxdialog/lxdialog.c b/scripts/kconfig/lxdialog/lxdialog.c
deleted file mode 100644
index 79f6c5fb5cef..000000000000
--- a/scripts/kconfig/lxdialog/lxdialog.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * dialog - Display simple dialog boxes from shell scripts
- *
- * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
- * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcap@cfw.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "dialog.h"
-
-static void Usage(const char *name);
-
-typedef int (jumperFn) (const char *title, int argc, const char *const *argv);
-
-struct Mode {
- char *name;
- int argmin, argmax, argmod;
- jumperFn *jumper;
-};
-
-jumperFn j_menu, j_radiolist, j_yesno, j_textbox, j_inputbox;
-jumperFn j_msgbox, j_infobox;
-
-static struct Mode modes[] = {
- {"--menu", 9, 0, 3, j_menu},
- {"--radiolist", 9, 0, 3, j_radiolist},
- {"--yesno", 5, 5, 1, j_yesno},
- {"--textbox", 5, 5, 1, j_textbox},
- {"--inputbox", 5, 6, 1, j_inputbox},
- {"--msgbox", 5, 5, 1, j_msgbox},
- {"--infobox", 5, 5, 1, j_infobox},
- {NULL, 0, 0, 0, NULL}
-};
-
-static struct Mode *modePtr;
-
-#ifdef LOCALE
-#include <locale.h>
-#endif
-
-int main(int argc, const char *const *argv)
-{
- int offset = 0, opt_clear = 0, end_common_opts = 0, retval;
- const char *title = NULL;
-
-#ifdef LOCALE
- (void)setlocale(LC_ALL, "");
-#endif
-
-#ifdef TRACE
- trace(TRACE_CALLS | TRACE_UPDATE);
-#endif
- if (argc < 2) {
- Usage(argv[0]);
- exit(-1);
- }
-
- while (offset < argc - 1 && !end_common_opts) { /* Common options */
- if (!strcmp(argv[offset + 1], "--title")) {
- if (argc - offset < 3 || title != NULL) {
- Usage(argv[0]);
- exit(-1);
- } else {
- title = argv[offset + 2];
- offset += 2;
- }
- } else if (!strcmp(argv[offset + 1], "--backtitle")) {
- if (backtitle != NULL) {
- Usage(argv[0]);
- exit(-1);
- } else {
- backtitle = argv[offset + 2];
- offset += 2;
- }
- } else if (!strcmp(argv[offset + 1], "--clear")) {
- if (opt_clear) { /* Hey, "--clear" can't appear twice! */
- Usage(argv[0]);
- exit(-1);
- } else if (argc == 2) { /* we only want to clear the screen */
- init_dialog();
- refresh(); /* init_dialog() will clear the screen for us */
- end_dialog();
- return 0;
- } else {
- opt_clear = 1;
- offset++;
- }
- } else /* no more common options */
- end_common_opts = 1;
- }
-
- if (argc - 1 == offset) { /* no more options */
- Usage(argv[0]);
- exit(-1);
- }
- /* use a table to look for the requested mode, to avoid code duplication */
-
- for (modePtr = modes; modePtr->name; modePtr++) /* look for the mode */
- if (!strcmp(argv[offset + 1], modePtr->name))
- break;
-
- if (!modePtr->name)
- Usage(argv[0]);
- if (argc - offset < modePtr->argmin)
- Usage(argv[0]);
- if (modePtr->argmax && argc - offset > modePtr->argmax)
- Usage(argv[0]);
-
- init_dialog();
- retval = (*(modePtr->jumper)) (title, argc - offset, argv + offset);
-
- if (opt_clear) { /* clear screen before exit */
- attr_clear(stdscr, LINES, COLS, screen_attr);
- refresh();
- }
- end_dialog();
-
- exit(retval);
-}
-
-/*
- * Print program usage
- */
-static void Usage(const char *name)
-{
- fprintf(stderr, "\
-\ndialog, by Savio Lam (lam836@cs.cuhk.hk).\
-\n patched by Stuart Herbert (S.Herbert@shef.ac.uk)\
-\n modified/gutted for use as a Linux kernel config tool by \
-\n William Roadcap (roadcapw@cfw.com)\
-\n\
-\n* Display dialog boxes from shell scripts *\
-\n\
-\nUsage: %s --clear\
-\n %s [--title <title>] [--backtitle <backtitle>] --clear <Box options>\
-\n\
-\nBox options:\
-\n\
-\n --menu <text> <height> <width> <menu height> <tag1> <item1>...\
-\n --radiolist <text> <height> <width> <list height> <tag1> <item1> <status1>...\
-\n --textbox <file> <height> <width>\
-\n --inputbox <text> <height> <width> [<init>]\
-\n --yesno <text> <height> <width>\
-\n", name, name);
- exit(-1);
-}
-
-/*
- * These are the program jumpers
- */
-
-int j_menu(const char *t, int ac, const char *const *av)
-{
- return dialog_menu(t, av[2], atoi(av[3]), atoi(av[4]),
- atoi(av[5]), av[6], (ac - 6) / 2, av + 7);
-}
-
-int j_radiolist(const char *t, int ac, const char *const *av)
-{
- return dialog_checklist(t, av[2], atoi(av[3]), atoi(av[4]),
- atoi(av[5]), (ac - 6) / 3, av + 6);
-}
-
-int j_textbox(const char *t, int ac, const char *const *av)
-{
- return dialog_textbox(t, av[2], atoi(av[3]), atoi(av[4]));
-}
-
-int j_yesno(const char *t, int ac, const char *const *av)
-{
- return dialog_yesno(t, av[2], atoi(av[3]), atoi(av[4]));
-}
-
-int j_inputbox(const char *t, int ac, const char *const *av)
-{
- int ret = dialog_inputbox(t, av[2], atoi(av[3]), atoi(av[4]),
- ac == 6 ? av[5] : (char *)NULL);
- if (ret == 0)
- fprintf(stderr, dialog_input_result);
- return ret;
-}
-
-int j_msgbox(const char *t, int ac, const char *const *av)
-{
- return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 1);
-}
-
-int j_infobox(const char *t, int ac, const char *const *av)
-{
- return dialog_msgbox(t, av[2], atoi(av[3]), atoi(av[4]), 0);
-}
diff --git a/scripts/kconfig/lxdialog/menubox.c b/scripts/kconfig/lxdialog/menubox.c
index bf8052f4fd4a..0d83159d9012 100644
--- a/scripts/kconfig/lxdialog/menubox.c
+++ b/scripts/kconfig/lxdialog/menubox.c
@@ -63,19 +63,19 @@ static int menu_width, item_x;
/*
* Print menu item
*/
-static void do_print_item(WINDOW * win, const char *item, int choice,
+static void do_print_item(WINDOW * win, const char *item, int line_y,
int selected, int hotkey)
{
int j;
char *menu_item = malloc(menu_width + 1);
strncpy(menu_item, item, menu_width - item_x);
- menu_item[menu_width] = 0;
+ menu_item[menu_width - item_x] = '\0';
j = first_alpha(menu_item, "YyNnMmHh");
/* Clear 'residue' of last item */
- wattrset(win, menubox_attr);
- wmove(win, choice, 0);
+ wattrset(win, dlg.menubox.atr);
+ wmove(win, line_y, 0);
#if OLD_NCURSES
{
int i;
@@ -85,23 +85,24 @@ static void do_print_item(WINDOW * win, const char *item, int choice,
#else
wclrtoeol(win);
#endif
- wattrset(win, selected ? item_selected_attr : item_attr);
- mvwaddstr(win, choice, item_x, menu_item);
+ wattrset(win, selected ? dlg.item_selected.atr : dlg.item.atr);
+ mvwaddstr(win, line_y, item_x, menu_item);
if (hotkey) {
- wattrset(win, selected ? tag_key_selected_attr : tag_key_attr);
- mvwaddch(win, choice, item_x + j, menu_item[j]);
+ wattrset(win, selected ? dlg.tag_key_selected.atr
+ : dlg.tag_key.atr);
+ mvwaddch(win, line_y, item_x + j, menu_item[j]);
}
if (selected) {
- wmove(win, choice, item_x + 1);
+ wmove(win, line_y, item_x + 1);
}
free(menu_item);
wrefresh(win);
}
-#define print_item(index, choice, selected) \
-do {\
- int hotkey = (items[(index) * 2][0] != ':'); \
- do_print_item(menu, items[(index) * 2 + 1], choice, selected, hotkey); \
+#define print_item(index, choice, selected) \
+do { \
+ item_set(index); \
+ do_print_item(menu, item_str(), choice, selected, !item_is_tag(':')); \
} while (0)
/*
@@ -117,11 +118,11 @@ static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
wmove(win, y, x);
if (scroll > 0) {
- wattrset(win, uarrow_attr);
+ wattrset(win, dlg.uarrow.atr);
waddch(win, ACS_UARROW);
waddstr(win, "(-)");
} else {
- wattrset(win, menubox_attr);
+ wattrset(win, dlg.menubox.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
@@ -133,11 +134,11 @@ static void print_arrows(WINDOW * win, int item_no, int scroll, int y, int x,
wrefresh(win);
if ((height < item_no) && (scroll + height < item_no)) {
- wattrset(win, darrow_attr);
+ wattrset(win, dlg.darrow.atr);
waddch(win, ACS_DARROW);
waddstr(win, "(+)");
} else {
- wattrset(win, menubox_border_attr);
+ wattrset(win, dlg.menubox_border.atr);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
waddch(win, ACS_HLINE);
@@ -178,17 +179,26 @@ static void do_scroll(WINDOW *win, int *scroll, int n)
/*
* Display a menu for choosing among a number of options
*/
-int dialog_menu(const char *title, const char *prompt, int height, int width,
- int menu_height, const char *current, int item_no,
- const char *const *items)
+int dialog_menu(const char *title, const char *prompt,
+ const void *selected, int *s_scroll)
{
int i, j, x, y, box_x, box_y;
+ int height, width, menu_height;
int key = 0, button = 0, scroll = 0, choice = 0;
int first_item = 0, max_choice;
WINDOW *dialog, *menu;
- FILE *f;
- max_choice = MIN(menu_height, item_no);
+do_resize:
+ height = getmaxy(stdscr);
+ width = getmaxx(stdscr);
+ if (height < 15 || width < 65)
+ return -ERRDISPLAYTOOSMALL;
+
+ height -= 4;
+ width -= 5;
+ menu_height = height - 10;
+
+ max_choice = MIN(menu_height, item_count());
/* center dialog box on screen */
x = (COLS - width) / 2;
@@ -199,18 +209,19 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
- wattrset(dialog, border_attr);
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
- wattrset(dialog, dialog_attr);
- wbkgdset(dialog, dialog_attr & A_COLOR);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
- wattrset(dialog, dialog_attr);
+ wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
menu_width = width - 6;
@@ -224,33 +235,29 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
/* draw a box around the menu items */
draw_box(dialog, box_y, box_x, menu_height + 2, menu_width + 2,
- menubox_border_attr, menubox_attr);
+ dlg.menubox_border.atr, dlg.menubox.atr);
- item_x = (menu_width - 70) / 2;
+ if (menu_width >= 80)
+ item_x = (menu_width - 70) / 2;
+ else
+ item_x = 4;
/* Set choice to default item */
- for (i = 0; i < item_no; i++)
- if (strcmp(current, items[i * 2]) == 0)
- choice = i;
-
- /* get the scroll info from the temp file */
- if ((f = fopen("lxdialog.scrltmp", "r")) != NULL) {
- if ((fscanf(f, "%d\n", &scroll) == 1) && (scroll <= choice) &&
- (scroll + max_choice > choice) && (scroll >= 0) &&
- (scroll + max_choice <= item_no)) {
- first_item = scroll;
- choice = choice - scroll;
- fclose(f);
- } else {
- scroll = 0;
- remove("lxdialog.scrltmp");
- fclose(f);
- f = NULL;
- }
+ item_foreach()
+ if (selected && (selected == item_data()))
+ choice = item_n();
+ /* get the saved scroll info */
+ scroll = *s_scroll;
+ if ((scroll <= choice) && (scroll + max_choice > choice) &&
+ (scroll >= 0) && (scroll + max_choice <= item_count())) {
+ first_item = scroll;
+ choice = choice - scroll;
+ } else {
+ scroll = 0;
}
- if ((choice >= max_choice) || (f == NULL && choice >= max_choice / 2)) {
- if (choice >= item_no - max_choice / 2)
- scroll = first_item = item_no - max_choice;
+ if ((choice >= max_choice)) {
+ if (choice >= item_count() - max_choice / 2)
+ scroll = first_item = item_count() - max_choice;
else
scroll = first_item = choice - max_choice / 2;
choice = choice - scroll;
@@ -263,14 +270,14 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
wnoutrefresh(menu);
- print_arrows(dialog, item_no, scroll,
+ print_arrows(dialog, item_count(), scroll,
box_y, box_x + item_x + 1, menu_height);
print_buttons(dialog, height, width, 0);
wmove(menu, choice, item_x + 1);
wrefresh(menu);
- while (key != ESC) {
+ while (key != KEY_ESC) {
key = wgetch(menu);
if (key < 256 && isalpha(key))
@@ -280,14 +287,16 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
i = max_choice;
else {
for (i = choice + 1; i < max_choice; i++) {
- j = first_alpha(items[(scroll + i) * 2 + 1], "YyNnMmHh");
- if (key == tolower(items[(scroll + i) * 2 + 1][j]))
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
break;
}
if (i == max_choice)
for (i = 0; i < max_choice; i++) {
- j = first_alpha(items [(scroll + i) * 2 + 1], "YyNnMmHh");
- if (key == tolower(items[(scroll + i) * 2 + 1][j]))
+ item_set(scroll + i);
+ j = first_alpha(item_str(), "YyNnMmHh");
+ if (key == tolower(item_str()[j]))
break;
}
}
@@ -312,7 +321,7 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
print_item(scroll+choice, choice, FALSE);
if ((choice > max_choice - 3) &&
- (scroll + max_choice < item_no)) {
+ (scroll + max_choice < item_count())) {
/* Scroll menu up */
do_scroll(menu, &scroll, 1);
@@ -335,7 +344,7 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
} else if (key == KEY_NPAGE) {
for (i = 0; (i < max_choice); i++) {
- if (scroll + max_choice < item_no) {
+ if (scroll + max_choice < item_count()) {
do_scroll(menu, &scroll, 1);
print_item(scroll+max_choice-1,
max_choice - 1, FALSE);
@@ -349,7 +358,7 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
print_item(scroll + choice, choice, TRUE);
- print_arrows(dialog, item_no, scroll,
+ print_arrows(dialog, item_count(), scroll,
box_y, box_x + item_x + 1, menu_height);
wnoutrefresh(dialog);
@@ -375,12 +384,11 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
case 'm':
case '/':
/* save scroll info */
- if ((f = fopen("lxdialog.scrltmp", "w")) != NULL) {
- fprintf(f, "%d\n", scroll);
- fclose(f);
- }
+ *s_scroll = scroll;
+ delwin(menu);
delwin(dialog);
- fprintf(stderr, "%s\n", items[(scroll + choice) * 2]);
+ item_set(scroll + choice);
+ item_set_selected(1);
switch (key) {
case 's':
return 3;
@@ -400,27 +408,27 @@ int dialog_menu(const char *title, const char *prompt, int height, int width,
case '?':
button = 2;
case '\n':
+ *s_scroll = scroll;
+ delwin(menu);
delwin(dialog);
- if (button == 2)
- fprintf(stderr, "%s \"%s\"\n",
- items[(scroll + choice) * 2],
- items[(scroll + choice) * 2 + 1] +
- first_alpha(items [(scroll + choice) * 2 + 1], ""));
- else
- fprintf(stderr, "%s\n",
- items[(scroll + choice) * 2]);
-
- remove("lxdialog.scrltmp");
+ item_set(scroll + choice);
+ item_set_selected(1);
return button;
case 'e':
case 'x':
- key = ESC;
- case ESC:
+ key = KEY_ESC;
+ break;
+ case KEY_ESC:
+ key = on_key_esc(menu);
break;
+ case KEY_RESIZE:
+ on_key_resize();
+ delwin(menu);
+ delwin(dialog);
+ goto do_resize;
}
}
-
+ delwin(menu);
delwin(dialog);
- remove("lxdialog.scrltmp");
- return -1; /* ESC pressed */
+ return key; /* ESC pressed */
}
diff --git a/scripts/kconfig/lxdialog/msgbox.c b/scripts/kconfig/lxdialog/msgbox.c
deleted file mode 100644
index 7323f5471f69..000000000000
--- a/scripts/kconfig/lxdialog/msgbox.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * msgbox.c -- implements the message box and info box
- *
- * ORIGINAL AUTHOR: Savio Lam (lam836@cs.cuhk.hk)
- * MODIFIED FOR LINUX KERNEL CONFIG BY: William Roadcap (roadcapw@cfw.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include "dialog.h"
-
-/*
- * Display a message box. Program will pause and display an "OK" button
- * if the parameter 'pause' is non-zero.
- */
-int dialog_msgbox(const char *title, const char *prompt, int height, int width,
- int pause)
-{
- int i, x, y, key = 0;
- WINDOW *dialog;
-
- /* center dialog box on screen */
- x = (COLS - width) / 2;
- y = (LINES - height) / 2;
-
- draw_shadow(stdscr, y, x, height, width);
-
- dialog = newwin(height, width, y, x);
- keypad(dialog, TRUE);
-
- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
-
- print_title(dialog, title, width);
-
- wattrset(dialog, dialog_attr);
- print_autowrap(dialog, prompt, width - 2, 1, 2);
-
- if (pause) {
- wattrset(dialog, border_attr);
- mvwaddch(dialog, height - 3, 0, ACS_LTEE);
- for (i = 0; i < width - 2; i++)
- waddch(dialog, ACS_HLINE);
- wattrset(dialog, dialog_attr);
- waddch(dialog, ACS_RTEE);
-
- print_button(dialog, " Ok ", height - 2, width / 2 - 4, TRUE);
-
- wrefresh(dialog);
- while (key != ESC && key != '\n' && key != ' ' &&
- key != 'O' && key != 'o' && key != 'X' && key != 'x')
- key = wgetch(dialog);
- } else {
- key = '\n';
- wrefresh(dialog);
- }
-
- delwin(dialog);
- return key == ESC ? -1 : 0;
-}
diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c
index 77848bb8e07f..fabfc1ad789d 100644
--- a/scripts/kconfig/lxdialog/textbox.c
+++ b/scripts/kconfig/lxdialog/textbox.c
@@ -25,56 +25,62 @@ static void back_lines(int n);
static void print_page(WINDOW * win, int height, int width);
static void print_line(WINDOW * win, int row, int width);
static char *get_line(void);
-static void print_position(WINDOW * win, int height, int width);
+static void print_position(WINDOW * win);
+
+static int hscroll;
+static int begin_reached, end_reached, page_length;
+static const char *buf;
+static const char *page;
+
+/*
+ * refresh window content
+ */
+static void refresh_text_box(WINDOW *dialog, WINDOW *box, int boxh, int boxw,
+ int cur_y, int cur_x)
+{
+ print_page(box, boxh, boxw);
+ print_position(dialog);
+ wmove(dialog, cur_y, cur_x); /* Restore cursor position */
+ wrefresh(dialog);
+}
-static int hscroll, fd, file_size, bytes_read;
-static int begin_reached = 1, end_reached, page_length;
-static char *buf, *page;
/*
* Display text from a file in a dialog box.
*/
-int dialog_textbox(const char *title, const char *file, int height, int width)
+int dialog_textbox(const char *title, const char *tbuf,
+ int initial_height, int initial_width)
{
- int i, x, y, cur_x, cur_y, fpos, key = 0;
+ int i, x, y, cur_x, cur_y, key = 0;
+ int height, width, boxh, boxw;
int passed_end;
- char search_term[MAX_LEN + 1];
- WINDOW *dialog, *text;
-
- search_term[0] = '\0'; /* no search term entered yet */
+ WINDOW *dialog, *box;
- /* Open input file for reading */
- if ((fd = open(file, O_RDONLY)) == -1) {
- endwin();
- fprintf(stderr, "\nCan't open input file in dialog_textbox().\n");
- exit(-1);
- }
- /* Get file size. Actually, 'file_size' is the real file size - 1,
- since it's only the last byte offset from the beginning */
- if ((file_size = lseek(fd, 0, SEEK_END)) == -1) {
- endwin();
- fprintf(stderr, "\nError getting file size in dialog_textbox().\n");
- exit(-1);
- }
- /* Restore file pointer to beginning of file after getting file size */
- if (lseek(fd, 0, SEEK_SET) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
- exit(-1);
- }
- /* Allocate space for read buffer */
- if ((buf = malloc(BUF_SIZE + 1)) == NULL) {
- endwin();
- fprintf(stderr, "\nCan't allocate memory in dialog_textbox().\n");
- exit(-1);
- }
- if ((bytes_read = read(fd, buf, BUF_SIZE)) == -1) {
- endwin();
- fprintf(stderr, "\nError reading file in dialog_textbox().\n");
- exit(-1);
- }
- buf[bytes_read] = '\0'; /* mark end of valid data */
- page = buf; /* page is pointer to start of page to be displayed */
+ begin_reached = 1;
+ end_reached = 0;
+ page_length = 0;
+ hscroll = 0;
+ buf = tbuf;
+ page = buf; /* page is pointer to start of page to be displayed */
+
+do_resize:
+ getmaxyx(stdscr, height, width);
+ if (height < 8 || width < 8)
+ return -ERRDISPLAYTOOSMALL;
+ if (initial_height != 0)
+ height = initial_height;
+ else
+ if (height > 4)
+ height -= 4;
+ else
+ height = 0;
+ if (initial_width != 0)
+ width = initial_width;
+ else
+ if (width > 5)
+ width -= 5;
+ else
+ width = 0;
/* center dialog box on screen */
x = (COLS - width) / 2;
@@ -85,22 +91,25 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
- /* Create window for text region, used for scrolling text */
- text = subwin(dialog, height - 4, width - 2, y + 1, x + 1);
- wattrset(text, dialog_attr);
- wbkgdset(text, dialog_attr & A_COLOR);
+ /* Create window for box region, used for scrolling text */
+ boxh = height - 4;
+ boxw = width - 2;
+ box = subwin(dialog, boxh, boxw, y + 1, x + 1);
+ wattrset(box, dlg.dialog.atr);
+ wbkgdset(box, dlg.dialog.atr & A_COLOR);
- keypad(text, TRUE);
+ keypad(box, TRUE);
/* register the new window, along with its borders */
- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
- wattrset(dialog, border_attr);
+ wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
- wattrset(dialog, dialog_attr);
- wbkgdset(dialog, dialog_attr & A_COLOR);
+ wattrset(dialog, dlg.dialog.atr);
+ wbkgdset(dialog, dlg.dialog.atr & A_COLOR);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
@@ -110,85 +119,37 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
getyx(dialog, cur_y, cur_x); /* Save cursor position */
/* Print first page of text */
- attr_clear(text, height - 4, width - 2, dialog_attr);
- print_page(text, height - 4, width - 2);
- print_position(dialog, height, width);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
+ attr_clear(box, boxh, boxw, dlg.dialog.atr);
+ refresh_text_box(dialog, box, boxh, boxw, cur_y, cur_x);
- while ((key != ESC) && (key != '\n')) {
+ while ((key != KEY_ESC) && (key != '\n')) {
key = wgetch(dialog);
switch (key) {
case 'E': /* Exit */
case 'e':
case 'X':
case 'x':
+ delwin(box);
delwin(dialog);
- free(buf);
- close(fd);
return 0;
case 'g': /* First page */
case KEY_HOME:
if (!begin_reached) {
begin_reached = 1;
- /* First page not in buffer? */
- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
- exit(-1);
- }
- if (fpos > bytes_read) { /* Yes, we have to read it in */
- if (lseek(fd, 0, SEEK_SET) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in "
- "dialog_textbox().\n");
- exit(-1);
- }
- if ((bytes_read =
- read(fd, buf, BUF_SIZE)) == -1) {
- endwin();
- fprintf(stderr, "\nError reading file in dialog_textbox().\n");
- exit(-1);
- }
- buf[bytes_read] = '\0';
- }
page = buf;
- print_page(text, height - 4, width - 2);
- print_position(dialog, height, width);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
}
break;
case 'G': /* Last page */
case KEY_END:
end_reached = 1;
- /* Last page not in buffer? */
- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
- exit(-1);
- }
- if (fpos < file_size) { /* Yes, we have to read it in */
- if (lseek(fd, -BUF_SIZE, SEEK_END) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in dialog_textbox().\n");
- exit(-1);
- }
- if ((bytes_read =
- read(fd, buf, BUF_SIZE)) == -1) {
- endwin();
- fprintf(stderr, "\nError reading file in dialog_textbox().\n");
- exit(-1);
- }
- buf[bytes_read] = '\0';
- }
- page = buf + bytes_read;
- back_lines(height - 4);
- print_page(text, height - 4, width - 2);
- print_position(dialog, height, width);
- wmove(dialog, cur_y, cur_x); /* Restore cursor position */
- wrefresh(dialog);
+ /* point to last char in buf */
+ page = buf + strlen(buf);
+ back_lines(boxh);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
break;
case 'K': /* Previous line */
case 'k':
@@ -196,21 +157,23 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
if (!begin_reached) {
back_lines(page_length + 1);
- /* We don't call print_page() here but use scrolling to ensure
- faster screen update. However, 'end_reached' and
- 'page_length' should still be updated, and 'page' should
- point to start of next page. This is done by calling
- get_line() in the following 'for' loop. */
- scrollok(text, TRUE);
- wscrl(text, -1); /* Scroll text region down one line */
- scrollok(text, FALSE);
+ /* We don't call print_page() here but use
+ * scrolling to ensure faster screen update.
+ * However, 'end_reached' and 'page_length'
+ * should still be updated, and 'page' should
+ * point to start of next page. This is done
+ * by calling get_line() in the following
+ * 'for' loop. */
+ scrollok(box, TRUE);
+ wscrl(box, -1); /* Scroll box region down one line */
+ scrollok(box, FALSE);
page_length = 0;
passed_end = 0;
- for (i = 0; i < height - 4; i++) {
+ for (i = 0; i < boxh; i++) {
if (!i) {
/* print first line of page */
- print_line(text, 0, width - 2);
- wnoutrefresh(text);
+ print_line(box, 0, boxw);
+ wnoutrefresh(box);
} else
/* Called to update 'end_reached' and 'page' */
get_line();
@@ -220,7 +183,7 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
passed_end = 1;
}
- print_position(dialog, height, width);
+ print_position(dialog);
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
wrefresh(dialog);
}
@@ -230,23 +193,21 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
case KEY_PPAGE:
if (begin_reached)
break;
- back_lines(page_length + height - 4);
- print_page(text, height - 4, width - 2);
- print_position(dialog, height, width);
- wmove(dialog, cur_y, cur_x);
- wrefresh(dialog);
+ back_lines(page_length + boxh);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
break;
case 'J': /* Next line */
case 'j':
case KEY_DOWN:
if (!end_reached) {
begin_reached = 0;
- scrollok(text, TRUE);
- scroll(text); /* Scroll text region up one line */
- scrollok(text, FALSE);
- print_line(text, height - 5, width - 2);
- wnoutrefresh(text);
- print_position(dialog, height, width);
+ scrollok(box, TRUE);
+ scroll(box); /* Scroll box region up one line */
+ scrollok(box, FALSE);
+ print_line(box, boxh - 1, boxw);
+ wnoutrefresh(box);
+ print_position(dialog);
wmove(dialog, cur_y, cur_x); /* Restore cursor position */
wrefresh(dialog);
}
@@ -257,10 +218,8 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
break;
begin_reached = 0;
- print_page(text, height - 4, width - 2);
- print_position(dialog, height, width);
- wmove(dialog, cur_y, cur_x);
- wrefresh(dialog);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
break;
case '0': /* Beginning of line */
case 'H': /* Scroll left */
@@ -275,9 +234,8 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
hscroll--;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
- print_page(text, height - 4, width - 2);
- wmove(dialog, cur_y, cur_x);
- wrefresh(dialog);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
break;
case 'L': /* Scroll right */
case 'l':
@@ -287,131 +245,56 @@ int dialog_textbox(const char *title, const char *file, int height, int width)
hscroll++;
/* Reprint current page to scroll horizontally */
back_lines(page_length);
- print_page(text, height - 4, width - 2);
- wmove(dialog, cur_y, cur_x);
- wrefresh(dialog);
+ refresh_text_box(dialog, box, boxh, boxw,
+ cur_y, cur_x);
break;
- case ESC:
+ case KEY_ESC:
+ key = on_key_esc(dialog);
break;
+ case KEY_RESIZE:
+ back_lines(height);
+ delwin(box);
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
}
}
-
+ delwin(box);
delwin(dialog);
- free(buf);
- close(fd);
- return -1; /* ESC pressed */
+ return key; /* ESC pressed */
}
/*
- * Go back 'n' lines in text file. Called by dialog_textbox().
+ * Go back 'n' lines in text. Called by dialog_textbox().
* 'page' will be updated to point to the desired line in 'buf'.
*/
static void back_lines(int n)
{
- int i, fpos;
+ int i;
begin_reached = 0;
- /* We have to distinguish between end_reached and !end_reached
- since at end of file, the line is not ended by a '\n'.
- The code inside 'if' basically does a '--page' to move one
- character backward so as to skip '\n' of the previous line */
- if (!end_reached) {
- /* Either beginning of buffer or beginning of file reached? */
- if (page == buf) {
- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in "
- "back_lines().\n");
- exit(-1);
- }
- if (fpos > bytes_read) { /* Not beginning of file yet */
- /* We've reached beginning of buffer, but not beginning of
- file yet, so read previous part of file into buffer.
- Note that we only move backward for BUF_SIZE/2 bytes,
- but not BUF_SIZE bytes to avoid re-reading again in
- print_page() later */
- /* Really possible to move backward BUF_SIZE/2 bytes? */
- if (fpos < BUF_SIZE / 2 + bytes_read) {
- /* No, move less then */
- if (lseek(fd, 0, SEEK_SET) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in "
- "back_lines().\n");
- exit(-1);
- }
- page = buf + fpos - bytes_read;
- } else { /* Move backward BUF_SIZE/2 bytes */
- if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer "
- "in back_lines().\n");
- exit(-1);
- }
- page = buf + BUF_SIZE / 2;
- }
- if ((bytes_read =
- read(fd, buf, BUF_SIZE)) == -1) {
- endwin();
- fprintf(stderr, "\nError reading file in back_lines().\n");
- exit(-1);
- }
- buf[bytes_read] = '\0';
- } else { /* Beginning of file reached */
- begin_reached = 1;
- return;
+ /* Go back 'n' lines */
+ for (i = 0; i < n; i++) {
+ if (*page == '\0') {
+ if (end_reached) {
+ end_reached = 0;
+ continue;
}
}
- if (*(--page) != '\n') { /* '--page' here */
- /* Something's wrong... */
- endwin();
- fprintf(stderr, "\nInternal error in back_lines().\n");
- exit(-1);
+ if (page == buf) {
+ begin_reached = 1;
+ return;
}
- }
- /* Go back 'n' lines */
- for (i = 0; i < n; i++)
+ page--;
do {
if (page == buf) {
- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in back_lines().\n");
- exit(-1);
- }
- if (fpos > bytes_read) {
- /* Really possible to move backward BUF_SIZE/2 bytes? */
- if (fpos < BUF_SIZE / 2 + bytes_read) {
- /* No, move less then */
- if (lseek(fd, 0, SEEK_SET) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer "
- "in back_lines().\n");
- exit(-1);
- }
- page = buf + fpos - bytes_read;
- } else { /* Move backward BUF_SIZE/2 bytes */
- if (lseek (fd, -(BUF_SIZE / 2 + bytes_read), SEEK_CUR) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer"
- " in back_lines().\n");
- exit(-1);
- }
- page = buf + BUF_SIZE / 2;
- }
- if ((bytes_read =
- read(fd, buf, BUF_SIZE)) == -1) {
- endwin();
- fprintf(stderr, "\nError reading file in "
- "back_lines().\n");
- exit(-1);
- }
- buf[bytes_read] = '\0';
- } else { /* Beginning of file reached */
- begin_reached = 1;
- return;
- }
+ begin_reached = 1;
+ return;
}
- } while (*(--page) != '\n');
- page++;
+ page--;
+ } while (*page != '\n');
+ page++;
+ }
}
/*
@@ -466,33 +349,14 @@ static void print_line(WINDOW * win, int row, int width)
*/
static char *get_line(void)
{
- int i = 0, fpos;
+ int i = 0;
static char line[MAX_LEN + 1];
end_reached = 0;
while (*page != '\n') {
if (*page == '\0') {
- /* Either end of file or end of buffer reached */
- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in "
- "get_line().\n");
- exit(-1);
- }
- if (fpos < file_size) { /* Not end of file yet */
- /* We've reached end of buffer, but not end of file yet,
- so read next part of file into buffer */
- if ((bytes_read =
- read(fd, buf, BUF_SIZE)) == -1) {
- endwin();
- fprintf(stderr, "\nError reading file in get_line().\n");
- exit(-1);
- }
- buf[bytes_read] = '\0';
- page = buf;
- } else {
- if (!end_reached)
- end_reached = 1;
+ if (!end_reached) {
+ end_reached = 1;
break;
}
} else if (i < MAX_LEN)
@@ -515,19 +379,13 @@ static char *get_line(void)
/*
* Print current position
*/
-static void print_position(WINDOW * win, int height, int width)
+static void print_position(WINDOW * win)
{
- int fpos, percent;
+ int percent;
- if ((fpos = lseek(fd, 0, SEEK_CUR)) == -1) {
- endwin();
- fprintf(stderr, "\nError moving file pointer in print_position().\n");
- exit(-1);
- }
- wattrset(win, position_indicator_attr);
- wbkgdset(win, position_indicator_attr & A_COLOR);
- percent = !file_size ?
- 100 : ((fpos - bytes_read + page - buf) * 100) / file_size;
- wmove(win, height - 3, width - 9);
+ wattrset(win, dlg.position_indicator.atr);
+ wbkgdset(win, dlg.position_indicator.atr & A_COLOR);
+ percent = (page - buf) * 100 / strlen(buf);
+ wmove(win, getmaxy(win) - 3, getmaxx(win) - 9);
wprintw(win, "(%3d%%)", percent);
}
diff --git a/scripts/kconfig/lxdialog/util.c b/scripts/kconfig/lxdialog/util.c
index f82cebb9ff06..ebc781b493d7 100644
--- a/scripts/kconfig/lxdialog/util.c
+++ b/scripts/kconfig/lxdialog/util.c
@@ -21,85 +21,217 @@
#include "dialog.h"
-/* use colors by default? */
-bool use_colors = 1;
+struct dialog_info dlg;
-const char *backtitle = NULL;
+static void set_mono_theme(void)
+{
+ dlg.screen.atr = A_NORMAL;
+ dlg.shadow.atr = A_NORMAL;
+ dlg.dialog.atr = A_NORMAL;
+ dlg.title.atr = A_BOLD;
+ dlg.border.atr = A_NORMAL;
+ dlg.button_active.atr = A_REVERSE;
+ dlg.button_inactive.atr = A_DIM;
+ dlg.button_key_active.atr = A_REVERSE;
+ dlg.button_key_inactive.atr = A_BOLD;
+ dlg.button_label_active.atr = A_REVERSE;
+ dlg.button_label_inactive.atr = A_NORMAL;
+ dlg.inputbox.atr = A_NORMAL;
+ dlg.inputbox_border.atr = A_NORMAL;
+ dlg.searchbox.atr = A_NORMAL;
+ dlg.searchbox_title.atr = A_BOLD;
+ dlg.searchbox_border.atr = A_NORMAL;
+ dlg.position_indicator.atr = A_BOLD;
+ dlg.menubox.atr = A_NORMAL;
+ dlg.menubox_border.atr = A_NORMAL;
+ dlg.item.atr = A_NORMAL;
+ dlg.item_selected.atr = A_REVERSE;
+ dlg.tag.atr = A_BOLD;
+ dlg.tag_selected.atr = A_REVERSE;
+ dlg.tag_key.atr = A_BOLD;
+ dlg.tag_key_selected.atr = A_REVERSE;
+ dlg.check.atr = A_BOLD;
+ dlg.check_selected.atr = A_REVERSE;
+ dlg.uarrow.atr = A_BOLD;
+ dlg.darrow.atr = A_BOLD;
+}
+
+#define DLG_COLOR(dialog, f, b, h) \
+do { \
+ dlg.dialog.fg = (f); \
+ dlg.dialog.bg = (b); \
+ dlg.dialog.hl = (h); \
+} while (0)
+
+static void set_classic_theme(void)
+{
+ DLG_COLOR(screen, COLOR_CYAN, COLOR_BLUE, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, true);
+ DLG_COLOR(dialog, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(button_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_inactive, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(button_key_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_WHITE, false);
+ DLG_COLOR(button_label_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_WHITE, true);
+ DLG_COLOR(inputbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(inputbox_border, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(searchbox_border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(position_indicator, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(menubox, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(menubox_border, COLOR_WHITE, COLOR_WHITE, true);
+ DLG_COLOR(item, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(tag, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(tag_key, COLOR_YELLOW, COLOR_WHITE, true);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(check, COLOR_BLACK, COLOR_WHITE, false);
+ DLG_COLOR(check_selected, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(uarrow, COLOR_GREEN, COLOR_WHITE, true);
+ DLG_COLOR(darrow, COLOR_GREEN, COLOR_WHITE, true);
+}
+
+static void set_blackbg_theme(void)
+{
+ DLG_COLOR(screen, COLOR_RED, COLOR_BLACK, true);
+ DLG_COLOR(shadow, COLOR_BLACK, COLOR_BLACK, false);
+ DLG_COLOR(dialog, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(title, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(button_active, COLOR_YELLOW, COLOR_RED, false);
+ DLG_COLOR(button_inactive, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(button_key_inactive, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_RED, false);
+ DLG_COLOR(button_label_inactive, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(inputbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(inputbox_border, COLOR_YELLOW, COLOR_BLACK, false);
+
+ DLG_COLOR(searchbox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(searchbox_title, COLOR_YELLOW, COLOR_BLACK, true);
+ DLG_COLOR(searchbox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(position_indicator, COLOR_RED, COLOR_BLACK, false);
+
+ DLG_COLOR(menubox, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(menubox_border, COLOR_BLACK, COLOR_BLACK, true);
+
+ DLG_COLOR(item, COLOR_WHITE, COLOR_BLACK, false);
+ DLG_COLOR(item_selected, COLOR_WHITE, COLOR_RED, false);
+
+ DLG_COLOR(tag, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_selected, COLOR_YELLOW, COLOR_RED, true);
+ DLG_COLOR(tag_key, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(tag_key_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(check, COLOR_YELLOW, COLOR_BLACK, false);
+ DLG_COLOR(check_selected, COLOR_YELLOW, COLOR_RED, true);
+
+ DLG_COLOR(uarrow, COLOR_RED, COLOR_BLACK, false);
+ DLG_COLOR(darrow, COLOR_RED, COLOR_BLACK, false);
+}
+
+static void set_bluetitle_theme(void)
+{
+ set_classic_theme();
+ DLG_COLOR(title, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(button_key_active, COLOR_YELLOW, COLOR_BLUE, true);
+ DLG_COLOR(button_label_active, COLOR_WHITE, COLOR_BLUE, true);
+ DLG_COLOR(searchbox_title, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(position_indicator, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag, COLOR_BLUE, COLOR_WHITE, true);
+ DLG_COLOR(tag_key, COLOR_BLUE, COLOR_WHITE, true);
+
+}
/*
- * Attribute values, default is for mono display
+ * Select color theme
*/
-chtype attributes[] = {
- A_NORMAL, /* screen_attr */
- A_NORMAL, /* shadow_attr */
- A_NORMAL, /* dialog_attr */
- A_BOLD, /* title_attr */
- A_NORMAL, /* border_attr */
- A_REVERSE, /* button_active_attr */
- A_DIM, /* button_inactive_attr */
- A_REVERSE, /* button_key_active_attr */
- A_BOLD, /* button_key_inactive_attr */
- A_REVERSE, /* button_label_active_attr */
- A_NORMAL, /* button_label_inactive_attr */
- A_NORMAL, /* inputbox_attr */
- A_NORMAL, /* inputbox_border_attr */
- A_NORMAL, /* searchbox_attr */
- A_BOLD, /* searchbox_title_attr */
- A_NORMAL, /* searchbox_border_attr */
- A_BOLD, /* position_indicator_attr */
- A_NORMAL, /* menubox_attr */
- A_NORMAL, /* menubox_border_attr */
- A_NORMAL, /* item_attr */
- A_REVERSE, /* item_selected_attr */
- A_BOLD, /* tag_attr */
- A_REVERSE, /* tag_selected_attr */
- A_BOLD, /* tag_key_attr */
- A_REVERSE, /* tag_key_selected_attr */
- A_BOLD, /* check_attr */
- A_REVERSE, /* check_selected_attr */
- A_BOLD, /* uarrow_attr */
- A_BOLD /* darrow_attr */
-};
-
-#include "colors.h"
+static int set_theme(const char *theme)
+{
+ int use_color = 1;
+ if (!theme)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "classic") == 0)
+ set_classic_theme();
+ else if (strcmp(theme, "bluetitle") == 0)
+ set_bluetitle_theme();
+ else if (strcmp(theme, "blackbg") == 0)
+ set_blackbg_theme();
+ else if (strcmp(theme, "mono") == 0)
+ use_color = 0;
+
+ return use_color;
+}
+
+static void init_one_color(struct dialog_color *color)
+{
+ static int pair = 0;
+
+ pair++;
+ init_pair(pair, color->fg, color->bg);
+ if (color->hl)
+ color->atr = A_BOLD | COLOR_PAIR(pair);
+ else
+ color->atr = COLOR_PAIR(pair);
+}
+
+static void init_dialog_colors(void)
+{
+ init_one_color(&dlg.screen);
+ init_one_color(&dlg.shadow);
+ init_one_color(&dlg.dialog);
+ init_one_color(&dlg.title);
+ init_one_color(&dlg.border);
+ init_one_color(&dlg.button_active);
+ init_one_color(&dlg.button_inactive);
+ init_one_color(&dlg.button_key_active);
+ init_one_color(&dlg.button_key_inactive);
+ init_one_color(&dlg.button_label_active);
+ init_one_color(&dlg.button_label_inactive);
+ init_one_color(&dlg.inputbox);
+ init_one_color(&dlg.inputbox_border);
+ init_one_color(&dlg.searchbox);
+ init_one_color(&dlg.searchbox_title);
+ init_one_color(&dlg.searchbox_border);
+ init_one_color(&dlg.position_indicator);
+ init_one_color(&dlg.menubox);
+ init_one_color(&dlg.menubox_border);
+ init_one_color(&dlg.item);
+ init_one_color(&dlg.item_selected);
+ init_one_color(&dlg.tag);
+ init_one_color(&dlg.tag_selected);
+ init_one_color(&dlg.tag_key);
+ init_one_color(&dlg.tag_key_selected);
+ init_one_color(&dlg.check);
+ init_one_color(&dlg.check_selected);
+ init_one_color(&dlg.uarrow);
+ init_one_color(&dlg.darrow);
+}
/*
- * Table of color values
+ * Setup for color display
*/
-int color_table[][3] = {
- {SCREEN_FG, SCREEN_BG, SCREEN_HL},
- {SHADOW_FG, SHADOW_BG, SHADOW_HL},
- {DIALOG_FG, DIALOG_BG, DIALOG_HL},
- {TITLE_FG, TITLE_BG, TITLE_HL},
- {BORDER_FG, BORDER_BG, BORDER_HL},
- {BUTTON_ACTIVE_FG, BUTTON_ACTIVE_BG, BUTTON_ACTIVE_HL},
- {BUTTON_INACTIVE_FG, BUTTON_INACTIVE_BG, BUTTON_INACTIVE_HL},
- {BUTTON_KEY_ACTIVE_FG, BUTTON_KEY_ACTIVE_BG, BUTTON_KEY_ACTIVE_HL},
- {BUTTON_KEY_INACTIVE_FG, BUTTON_KEY_INACTIVE_BG,
- BUTTON_KEY_INACTIVE_HL},
- {BUTTON_LABEL_ACTIVE_FG, BUTTON_LABEL_ACTIVE_BG,
- BUTTON_LABEL_ACTIVE_HL},
- {BUTTON_LABEL_INACTIVE_FG, BUTTON_LABEL_INACTIVE_BG,
- BUTTON_LABEL_INACTIVE_HL},
- {INPUTBOX_FG, INPUTBOX_BG, INPUTBOX_HL},
- {INPUTBOX_BORDER_FG, INPUTBOX_BORDER_BG, INPUTBOX_BORDER_HL},
- {SEARCHBOX_FG, SEARCHBOX_BG, SEARCHBOX_HL},
- {SEARCHBOX_TITLE_FG, SEARCHBOX_TITLE_BG, SEARCHBOX_TITLE_HL},
- {SEARCHBOX_BORDER_FG, SEARCHBOX_BORDER_BG, SEARCHBOX_BORDER_HL},
- {POSITION_INDICATOR_FG, POSITION_INDICATOR_BG, POSITION_INDICATOR_HL},
- {MENUBOX_FG, MENUBOX_BG, MENUBOX_HL},
- {MENUBOX_BORDER_FG, MENUBOX_BORDER_BG, MENUBOX_BORDER_HL},
- {ITEM_FG, ITEM_BG, ITEM_HL},
- {ITEM_SELECTED_FG, ITEM_SELECTED_BG, ITEM_SELECTED_HL},
- {TAG_FG, TAG_BG, TAG_HL},
- {TAG_SELECTED_FG, TAG_SELECTED_BG, TAG_SELECTED_HL},
- {TAG_KEY_FG, TAG_KEY_BG, TAG_KEY_HL},
- {TAG_KEY_SELECTED_FG, TAG_KEY_SELECTED_BG, TAG_KEY_SELECTED_HL},
- {CHECK_FG, CHECK_BG, CHECK_HL},
- {CHECK_SELECTED_FG, CHECK_SELECTED_BG, CHECK_SELECTED_HL},
- {UARROW_FG, UARROW_BG, UARROW_HL},
- {DARROW_FG, DARROW_BG, DARROW_HL},
-}; /* color_table */
+static void color_setup(const char *theme)
+{
+ if (set_theme(theme)) {
+ if (has_colors()) { /* Terminal supports color? */
+ start_color();
+ init_dialog_colors();
+ }
+ }
+ else
+ {
+ set_mono_theme();
+ }
+}
/*
* Set window to attribute 'attr'
@@ -119,13 +251,13 @@ void attr_clear(WINDOW * win, int height, int width, chtype attr)
void dialog_clear(void)
{
- attr_clear(stdscr, LINES, COLS, screen_attr);
+ attr_clear(stdscr, LINES, COLS, dlg.screen.atr);
/* Display background title if it exists ... - SLH */
- if (backtitle != NULL) {
+ if (dlg.backtitle != NULL) {
int i;
- wattrset(stdscr, screen_attr);
- mvwaddstr(stdscr, 0, 1, (char *)backtitle);
+ wattrset(stdscr, dlg.screen.atr);
+ mvwaddstr(stdscr, 0, 1, (char *)dlg.backtitle);
wmove(stdscr, 1, 1);
for (i = 1; i < COLS - 1; i++)
waddch(stdscr, ACS_HLINE);
@@ -136,40 +268,22 @@ void dialog_clear(void)
/*
* Do some initialization for dialog
*/
-void init_dialog(void)
+void init_dialog(const char *backtitle)
+{
+ dlg.backtitle = backtitle;
+ color_setup(getenv("MENUCONFIG_COLOR"));
+}
+
+void reset_dialog(void)
{
initscr(); /* Init curses */
keypad(stdscr, TRUE);
cbreak();
noecho();
-
- if (use_colors) /* Set up colors */
- color_setup();
-
dialog_clear();
}
/*
- * Setup for color display
- */
-void color_setup(void)
-{
- int i;
-
- if (has_colors()) { /* Terminal supports color? */
- start_color();
-
- /* Initialize color pairs */
- for (i = 0; i < ATTRIBUTE_COUNT; i++)
- init_pair(i + 1, color_table[i][0], color_table[i][1]);
-
- /* Setup color attributes */
- for (i = 0; i < ATTRIBUTE_COUNT; i++)
- attributes[i] = C_ATTR(color_table[i][2], i + 1);
- }
-}
-
-/*
* End using dialog functions.
*/
void end_dialog(void)
@@ -184,7 +298,7 @@ void print_title(WINDOW *dialog, const char *title, int width)
{
if (title) {
int tlen = MIN(width - 2, strlen(title));
- wattrset(dialog, title_attr);
+ wattrset(dialog, dlg.title.atr);
mvwaddch(dialog, 0, (width - tlen) / 2 - 1, ' ');
mvwaddnstr(dialog, 0, (width - tlen)/2, title, tlen);
waddch(dialog, ' ');
@@ -264,21 +378,23 @@ void print_button(WINDOW * win, const char *label, int y, int x, int selected)
int i, temp;
wmove(win, y, x);
- wattrset(win, selected ? button_active_attr : button_inactive_attr);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
waddstr(win, "<");
temp = strspn(label, " ");
label += temp;
- wattrset(win, selected ? button_label_active_attr
- : button_label_inactive_attr);
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
for (i = 0; i < temp; i++)
waddch(win, ' ');
- wattrset(win, selected ? button_key_active_attr
- : button_key_inactive_attr);
+ wattrset(win, selected ? dlg.button_key_active.atr
+ : dlg.button_key_inactive.atr);
waddch(win, label[0]);
- wattrset(win, selected ? button_label_active_attr
- : button_label_inactive_attr);
+ wattrset(win, selected ? dlg.button_label_active.atr
+ : dlg.button_label_inactive.atr);
waddstr(win, (char *)label + 1);
- wattrset(win, selected ? button_active_attr : button_inactive_attr);
+ wattrset(win, selected ? dlg.button_active.atr
+ : dlg.button_inactive.atr);
waddstr(win, ">");
wmove(win, y, x + temp + 1);
}
@@ -326,7 +442,7 @@ void draw_shadow(WINDOW * win, int y, int x, int height, int width)
int i;
if (has_colors()) { /* Whether terminal supports color? */
- wattrset(win, shadow_attr);
+ wattrset(win, dlg.shadow.atr);
wmove(win, y + height, x + 2);
for (i = 0; i < width; i++)
waddch(win, winch(win) & A_CHARTEXT);
@@ -360,3 +476,167 @@ int first_alpha(const char *string, const char *exempt)
return 0;
}
+
+/*
+ * ncurses uses ESC to detect escaped char sequences. This resutl in
+ * a small timeout before ESC is actually delivered to the application.
+ * lxdialog suggest <ESC> <ESC> which is correctly translated to two
+ * times esc. But then we need to ignore the second esc to avoid stepping
+ * out one menu too much. Filter away all escaped key sequences since
+ * keypad(FALSE) turn off ncurses support for escape sequences - and thats
+ * needed to make notimeout() do as expected.
+ */
+int on_key_esc(WINDOW *win)
+{
+ int key;
+ int key2;
+ int key3;
+
+ nodelay(win, TRUE);
+ keypad(win, FALSE);
+ key = wgetch(win);
+ key2 = wgetch(win);
+ do {
+ key3 = wgetch(win);
+ } while (key3 != ERR);
+ nodelay(win, FALSE);
+ keypad(win, TRUE);
+ if (key == KEY_ESC && key2 == ERR)
+ return KEY_ESC;
+ else if (key != ERR && key != KEY_ESC && key2 == ERR)
+ ungetch(key);
+
+ return -1;
+}
+
+/* redraw screen in new size */
+int on_key_resize(void)
+{
+ dialog_clear();
+ return KEY_RESIZE;
+}
+
+struct dialog_list *item_cur;
+struct dialog_list item_nil;
+struct dialog_list *item_head;
+
+void item_reset(void)
+{
+ struct dialog_list *p, *next;
+
+ for (p = item_head; p; p = next) {
+ next = p->next;
+ free(p);
+ }
+ item_head = NULL;
+ item_cur = &item_nil;
+}
+
+void item_make(const char *fmt, ...)
+{
+ va_list ap;
+ struct dialog_list *p = malloc(sizeof(*p));
+
+ if (item_head)
+ item_cur->next = p;
+ else
+ item_head = p;
+ item_cur = p;
+ memset(p, 0, sizeof(*p));
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str, sizeof(item_cur->node.str), fmt, ap);
+ va_end(ap);
+}
+
+void item_add_str(const char *fmt, ...)
+{
+ va_list ap;
+ size_t avail;
+
+ avail = sizeof(item_cur->node.str) - strlen(item_cur->node.str);
+
+ va_start(ap, fmt);
+ vsnprintf(item_cur->node.str + strlen(item_cur->node.str),
+ avail, fmt, ap);
+ item_cur->node.str[sizeof(item_cur->node.str) - 1] = '\0';
+ va_end(ap);
+}
+
+void item_set_tag(char tag)
+{
+ item_cur->node.tag = tag;
+}
+void item_set_data(void *ptr)
+{
+ item_cur->node.data = ptr;
+}
+
+void item_set_selected(int val)
+{
+ item_cur->node.selected = val;
+}
+
+int item_activate_selected(void)
+{
+ item_foreach()
+ if (item_is_selected())
+ return 1;
+ return 0;
+}
+
+void *item_data(void)
+{
+ return item_cur->node.data;
+}
+
+char item_tag(void)
+{
+ return item_cur->node.tag;
+}
+
+int item_count(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next)
+ n++;
+ return n;
+}
+
+void item_set(int n)
+{
+ int i = 0;
+ item_foreach()
+ if (i++ == n)
+ return;
+}
+
+int item_n(void)
+{
+ int n = 0;
+ struct dialog_list *p;
+
+ for (p = item_head; p; p = p->next) {
+ if (p == item_cur)
+ return n;
+ n++;
+ }
+ return 0;
+}
+
+const char *item_str(void)
+{
+ return item_cur->node.str;
+}
+
+int item_is_selected(void)
+{
+ return (item_cur->node.selected != 0);
+}
+
+int item_is_tag(char tag)
+{
+ return (item_cur->node.tag == tag);
+}
diff --git a/scripts/kconfig/lxdialog/yesno.c b/scripts/kconfig/lxdialog/yesno.c
index cb2568aae3ed..ee0a04e3e012 100644
--- a/scripts/kconfig/lxdialog/yesno.c
+++ b/scripts/kconfig/lxdialog/yesno.c
@@ -44,6 +44,12 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
int i, x, y, key = 0, button = 0;
WINDOW *dialog;
+do_resize:
+ if (getmaxy(stdscr) < (height + 4))
+ return -ERRDISPLAYTOOSMALL;
+ if (getmaxx(stdscr) < (width + 4))
+ return -ERRDISPLAYTOOSMALL;
+
/* center dialog box on screen */
x = (COLS - width) / 2;
y = (LINES - height) / 2;
@@ -53,22 +59,23 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
dialog = newwin(height, width, y, x);
keypad(dialog, TRUE);
- draw_box(dialog, 0, 0, height, width, dialog_attr, border_attr);
- wattrset(dialog, border_attr);
+ draw_box(dialog, 0, 0, height, width,
+ dlg.dialog.atr, dlg.border.atr);
+ wattrset(dialog, dlg.border.atr);
mvwaddch(dialog, height - 3, 0, ACS_LTEE);
for (i = 0; i < width - 2; i++)
waddch(dialog, ACS_HLINE);
- wattrset(dialog, dialog_attr);
+ wattrset(dialog, dlg.dialog.atr);
waddch(dialog, ACS_RTEE);
print_title(dialog, title, width);
- wattrset(dialog, dialog_attr);
+ wattrset(dialog, dlg.dialog.atr);
print_autowrap(dialog, prompt, width - 2, 1, 3);
print_buttons(dialog, height, width, 0);
- while (key != ESC) {
+ while (key != KEY_ESC) {
key = wgetch(dialog);
switch (key) {
case 'Y':
@@ -92,11 +99,16 @@ int dialog_yesno(const char *title, const char *prompt, int height, int width)
case '\n':
delwin(dialog);
return button;
- case ESC:
+ case KEY_ESC:
+ key = on_key_esc(dialog);
break;
+ case KEY_RESIZE:
+ delwin(dialog);
+ on_key_resize();
+ goto do_resize;
}
}
delwin(dialog);
- return -1; /* ESC pressed */
+ return key; /* ESC pressed */
}
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index 7f973195e79a..08a4c7af93ea 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -24,6 +24,7 @@
#define LKC_DIRECT_LINK
#include "lkc.h"
+#include "lxdialog/dialog.h"
static char menu_backtitle[128];
static const char mconf_readme[] = N_(
@@ -159,7 +160,21 @@ static const char mconf_readme[] = N_(
"\n"
"Note that this mode can eventually be a little more CPU expensive\n"
"(especially with a larger number of unrolled categories) than the\n"
-"default mode.\n"),
+"default mode.\n"
+"\n"
+"Different color themes available\n"
+"--------------------------------\n"
+"It is possible to select different color themes using the variable\n"
+"MENUCONFIG_COLOR. To select a theme use:\n"
+"\n"
+"make MENUCONFIG_COLOR=<theme> menuconfig\n"
+"\n"
+"Available themes are\n"
+" mono => selects colors suitable for monochrome displays\n"
+" blackbg => selects a color scheme with black background\n"
+" classic => theme with blue background. The classic look\n"
+" bluetitle => a LCD friendly version of classic. (default)\n"
+"\n"),
menu_instructions[] = N_(
"Arrow keys navigate the menu. "
"<Enter> selects submenus --->. "
@@ -256,16 +271,12 @@ search_help[] = N_(
" USB$ => find all CONFIG_ symbols ending with USB\n"
"\n");
-static char buf[4096], *bufptr = buf;
-static char input_buf[4096];
static char filename[PATH_MAX+1] = ".config";
-static char *args[1024], **argptr = args;
static int indent;
static struct termios ios_org;
static int rows = 0, cols = 0;
static struct menu *current_menu;
static int child_count;
-static int do_resize;
static int single_menu_mode;
static void conf(struct menu *menu);
@@ -276,12 +287,6 @@ static void conf_save(void);
static void show_textbox(const char *title, const char *text, int r, int c);
static void show_helptext(const char *title, const char *text);
static void show_help(struct menu *menu);
-static void show_file(const char *filename, const char *title, int r, int c);
-
-static void cprint_init(void);
-static int cprint1(const char *fmt, ...);
-static void cprint_done(void);
-static int cprint(const char *fmt, ...);
static void init_wsize(void)
{
@@ -318,54 +323,6 @@ static void init_wsize(void)
cols -= 5;
}
-static void cprint_init(void)
-{
- bufptr = buf;
- argptr = args;
- memset(args, 0, sizeof(args));
- indent = 0;
- child_count = 0;
- cprint("./scripts/kconfig/lxdialog/lxdialog");
- cprint("--backtitle");
- cprint(menu_backtitle);
-}
-
-static int cprint1(const char *fmt, ...)
-{
- va_list ap;
- int res;
-
- if (!*argptr)
- *argptr = bufptr;
- va_start(ap, fmt);
- res = vsprintf(bufptr, fmt, ap);
- va_end(ap);
- bufptr += res;
-
- return res;
-}
-
-static void cprint_done(void)
-{
- *bufptr++ = 0;
- argptr++;
-}
-
-static int cprint(const char *fmt, ...)
-{
- va_list ap;
- int res;
-
- *argptr++ = bufptr;
- va_start(ap, fmt);
- res = vsprintf(bufptr, fmt, ap);
- va_end(ap);
- bufptr += res;
- *bufptr++ = 0;
-
- return res;
-}
-
static void get_prompt_str(struct gstr *r, struct property *prop)
{
int i, j;
@@ -438,108 +395,17 @@ static struct gstr get_relations_str(struct symbol **sym_arr)
return res;
}
-pid_t pid;
-
-static void winch_handler(int sig)
-{
- if (!do_resize) {
- kill(pid, SIGINT);
- do_resize = 1;
- }
-}
-
-static int exec_conf(void)
-{
- int pipefd[2], stat, size;
- struct sigaction sa;
- sigset_t sset, osset;
-
- sigemptyset(&sset);
- sigaddset(&sset, SIGINT);
- sigprocmask(SIG_BLOCK, &sset, &osset);
-
- signal(SIGINT, SIG_DFL);
-
- sa.sa_handler = winch_handler;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART;
- sigaction(SIGWINCH, &sa, NULL);
-
- *argptr++ = NULL;
-
- pipe(pipefd);
- pid = fork();
- if (pid == 0) {
- sigprocmask(SIG_SETMASK, &osset, NULL);
- dup2(pipefd[1], 2);
- close(pipefd[0]);
- close(pipefd[1]);
- execv(args[0], args);
- _exit(EXIT_FAILURE);
- }
-
- close(pipefd[1]);
- bufptr = input_buf;
- while (1) {
- size = input_buf + sizeof(input_buf) - bufptr;
- size = read(pipefd[0], bufptr, size);
- if (size <= 0) {
- if (size < 0) {
- if (errno == EINTR || errno == EAGAIN)
- continue;
- perror("read");
- }
- break;
- }
- bufptr += size;
- }
- *bufptr++ = 0;
- close(pipefd[0]);
- waitpid(pid, &stat, 0);
-
- if (do_resize) {
- init_wsize();
- do_resize = 0;
- sigprocmask(SIG_SETMASK, &osset, NULL);
- return -1;
- }
- if (WIFSIGNALED(stat)) {
- printf("\finterrupted(%d)\n", WTERMSIG(stat));
- exit(1);
- }
-#if 0
- printf("\fexit state: %d\nexit data: '%s'\n", WEXITSTATUS(stat), input_buf);
- sleep(1);
-#endif
- sigpending(&sset);
- if (sigismember(&sset, SIGINT)) {
- printf("\finterrupted\n");
- exit(1);
- }
- sigprocmask(SIG_SETMASK, &osset, NULL);
-
- return WEXITSTATUS(stat);
-}
-
static void search_conf(void)
{
struct symbol **sym_arr;
- int stat;
struct gstr res;
-
+ int dres;
again:
- cprint_init();
- cprint("--title");
- cprint(_("Search Configuration Parameter"));
- cprint("--inputbox");
- cprint(_("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"));
- cprint("10");
- cprint("75");
- cprint("");
- stat = exec_conf();
- if (stat < 0)
- goto again;
- switch (stat) {
+ dialog_clear();
+ dres = dialog_inputbox(_("Search Configuration Parameter"),
+ _("Enter CONFIG_ (sub)string to search for (omit CONFIG_)"),
+ 10, 75, "");
+ switch (dres) {
case 0:
break;
case 1:
@@ -549,7 +415,7 @@ again:
return;
}
- sym_arr = sym_re_search(input_buf);
+ sym_arr = sym_re_search(dialog_input_result);
res = get_relations_str(sym_arr);
free(sym_arr);
show_textbox(_("Search Results"), str_get(&res), 0, 0);
@@ -576,24 +442,24 @@ static void build_conf(struct menu *menu)
switch (prop->type) {
case P_MENU:
child_count++;
- cprint("m%p", menu);
-
if (single_menu_mode) {
- cprint1("%s%*c%s",
- menu->data ? "-->" : "++>",
- indent + 1, ' ', prompt);
+ item_make("%s%*c%s",
+ menu->data ? "-->" : "++>",
+ indent + 1, ' ', prompt);
} else
- cprint1(" %*c%s --->", indent + 1, ' ', prompt);
+ item_make(" %*c%s --->", indent + 1, ' ', prompt);
- cprint_done();
+ item_set_tag('m');
+ item_set_data(menu);
if (single_menu_mode && menu->data)
goto conf_childs;
return;
default:
if (prompt) {
child_count++;
- cprint(":%p", menu);
- cprint("---%*c%s", indent + 1, ' ', prompt);
+ item_make("---%*c%s", indent + 1, ' ', prompt);
+ item_set_tag(':');
+ item_set_data(menu);
}
}
} else
@@ -614,10 +480,9 @@ static void build_conf(struct menu *menu)
val = sym_get_tristate_value(sym);
if (sym_is_changable(sym)) {
- cprint("t%p", menu);
switch (type) {
case S_BOOLEAN:
- cprint1("[%c]", val == no ? ' ' : '*');
+ item_make("[%c]", val == no ? ' ' : '*');
break;
case S_TRISTATE:
switch (val) {
@@ -625,84 +490,87 @@ static void build_conf(struct menu *menu)
case mod: ch = 'M'; break;
default: ch = ' '; break;
}
- cprint1("<%c>", ch);
+ item_make("<%c>", ch);
break;
}
+ item_set_tag('t');
+ item_set_data(menu);
} else {
- cprint("%c%p", def_menu ? 't' : ':', menu);
- cprint1(" ");
+ item_make(" ");
+ item_set_tag(def_menu ? 't' : ':');
+ item_set_data(menu);
}
- cprint1("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ item_add_str("%*c%s", indent + 1, ' ', menu_get_prompt(menu));
if (val == yes) {
if (def_menu) {
- cprint1(" (%s)", menu_get_prompt(def_menu));
- cprint1(" --->");
- cprint_done();
+ item_add_str(" (%s)", menu_get_prompt(def_menu));
+ item_add_str(" --->");
if (def_menu->list) {
indent += 2;
build_conf(def_menu);
indent -= 2;
}
- } else
- cprint_done();
+ }
return;
}
- cprint_done();
} else {
if (menu == current_menu) {
- cprint(":%p", menu);
- cprint("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ item_make("---%*c%s", indent + 1, ' ', menu_get_prompt(menu));
+ item_set_tag(':');
+ item_set_data(menu);
goto conf_childs;
}
child_count++;
val = sym_get_tristate_value(sym);
if (sym_is_choice_value(sym) && val == yes) {
- cprint(":%p", menu);
- cprint1(" ");
+ item_make(" ");
+ item_set_tag(':');
+ item_set_data(menu);
} else {
switch (type) {
case S_BOOLEAN:
- cprint("t%p", menu);
if (sym_is_changable(sym))
- cprint1("[%c]", val == no ? ' ' : '*');
+ item_make("[%c]", val == no ? ' ' : '*');
else
- cprint1("---");
+ item_make("---");
+ item_set_tag('t');
+ item_set_data(menu);
break;
case S_TRISTATE:
- cprint("t%p", menu);
switch (val) {
case yes: ch = '*'; break;
case mod: ch = 'M'; break;
default: ch = ' '; break;
}
if (sym_is_changable(sym))
- cprint1("<%c>", ch);
+ item_make("<%c>", ch);
else
- cprint1("---");
+ item_make("---");
+ item_set_tag('t');
+ item_set_data(menu);
break;
default:
- cprint("s%p", menu);
- tmp = cprint1("(%s)", sym_get_string_value(sym));
+ tmp = 2 + strlen(sym_get_string_value(sym)); /* () = 2 */
+ item_make("(%s)", sym_get_string_value(sym));
tmp = indent - tmp + 4;
if (tmp < 0)
tmp = 0;
- cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
- (sym_has_value(sym) || !sym_is_changable(sym)) ?
- "" : " (NEW)");
- cprint_done();
+ item_add_str("%*c%s%s", tmp, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : " (NEW)");
+ item_set_tag('s');
+ item_set_data(menu);
goto conf_childs;
}
}
- cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
- (sym_has_value(sym) || !sym_is_changable(sym)) ?
- "" : " (NEW)");
+ item_add_str("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu),
+ (sym_has_value(sym) || !sym_is_changable(sym)) ?
+ "" : " (NEW)");
if (menu->prompt->type == P_MENU) {
- cprint1(" --->");
- cprint_done();
+ item_add_str(" --->");
return;
}
- cprint_done();
}
conf_childs:
@@ -717,59 +585,45 @@ static void conf(struct menu *menu)
struct menu *submenu;
const char *prompt = menu_get_prompt(menu);
struct symbol *sym;
- char active_entry[40];
- int stat, type, i;
+ struct menu *active_menu = NULL;
+ int res;
+ int s_scroll = 0;
- unlink("lxdialog.scrltmp");
- active_entry[0] = 0;
while (1) {
- cprint_init();
- cprint("--title");
- cprint("%s", prompt ? prompt : _("Main Menu"));
- cprint("--menu");
- cprint(_(menu_instructions));
- cprint("%d", rows);
- cprint("%d", cols);
- cprint("%d", rows - 10);
- cprint("%s", active_entry);
+ item_reset();
current_menu = menu;
build_conf(menu);
if (!child_count)
break;
if (menu == &rootmenu) {
- cprint(":");
- cprint("--- ");
- cprint("L");
- cprint(_(" Load an Alternate Configuration File"));
- cprint("S");
- cprint(_(" Save Configuration to an Alternate File"));
+ item_make("--- ");
+ item_set_tag(':');
+ item_make(_(" Load an Alternate Configuration File"));
+ item_set_tag('L');
+ item_make(_(" Save an Alternate Configuration File"));
+ item_set_tag('S');
}
- stat = exec_conf();
- if (stat < 0)
- continue;
-
- if (stat == 1 || stat == 255)
+ dialog_clear();
+ res = dialog_menu(prompt ? prompt : _("Main Menu"),
+ _(menu_instructions),
+ active_menu, &s_scroll);
+ if (res == 1 || res == KEY_ESC || res == -ERRDISPLAYTOOSMALL)
break;
-
- type = input_buf[0];
- if (!type)
+ if (!item_activate_selected())
+ continue;
+ if (!item_tag())
continue;
- for (i = 0; input_buf[i] && !isspace(input_buf[i]); i++)
- ;
- if (i >= sizeof(active_entry))
- i = sizeof(active_entry) - 1;
- input_buf[i] = 0;
- strcpy(active_entry, input_buf);
-
- sym = NULL;
- submenu = NULL;
- if (sscanf(input_buf + 1, "%p", &submenu) == 1)
+ submenu = item_data();
+ active_menu = item_data();
+ if (submenu)
sym = submenu->sym;
+ else
+ sym = NULL;
- switch (stat) {
+ switch (res) {
case 0:
- switch (type) {
+ switch (item_tag()) {
case 'm':
if (single_menu_mode)
submenu->data = (void *) (long) !submenu->data;
@@ -800,7 +654,7 @@ static void conf(struct menu *menu)
show_helptext("README", _(mconf_readme));
break;
case 3:
- if (type == 't') {
+ if (item_is_tag('t')) {
if (sym_set_tristate_value(sym, yes))
break;
if (sym_set_tristate_value(sym, mod))
@@ -808,17 +662,17 @@ static void conf(struct menu *menu)
}
break;
case 4:
- if (type == 't')
+ if (item_is_tag('t'))
sym_set_tristate_value(sym, no);
break;
case 5:
- if (type == 't')
+ if (item_is_tag('t'))
sym_set_tristate_value(sym, mod);
break;
case 6:
- if (type == 't')
+ if (item_is_tag('t'))
sym_toggle_tristate_value(sym);
- else if (type == 'm')
+ else if (item_is_tag('m'))
conf(submenu);
break;
case 7:
@@ -830,13 +684,8 @@ static void conf(struct menu *menu)
static void show_textbox(const char *title, const char *text, int r, int c)
{
- int fd;
-
- fd = creat(".help.tmp", 0777);
- write(fd, text, strlen(text));
- close(fd);
- show_file(".help.tmp", title, r, c);
- unlink(".help.tmp");
+ dialog_clear();
+ dialog_textbox(title, text, r, c);
}
static void show_helptext(const char *title, const char *text)
@@ -864,68 +713,52 @@ static void show_help(struct menu *menu)
str_free(&help);
}
-static void show_file(const char *filename, const char *title, int r, int c)
-{
- do {
- cprint_init();
- if (title) {
- cprint("--title");
- cprint("%s", title);
- }
- cprint("--textbox");
- cprint("%s", filename);
- cprint("%d", r ? r : rows);
- cprint("%d", c ? c : cols);
- } while (exec_conf() < 0);
-}
-
static void conf_choice(struct menu *menu)
{
const char *prompt = menu_get_prompt(menu);
struct menu *child;
struct symbol *active;
- int stat;
active = sym_get_choice_value(menu->sym);
while (1) {
- cprint_init();
- cprint("--title");
- cprint("%s", prompt ? prompt : _("Main Menu"));
- cprint("--radiolist");
- cprint(_(radiolist_instructions));
- cprint("15");
- cprint("70");
- cprint("6");
+ int res;
+ int selected;
+ item_reset();
current_menu = menu;
for (child = menu->list; child; child = child->next) {
if (!menu_is_visible(child))
continue;
- cprint("%p", child);
- cprint("%s", menu_get_prompt(child));
+ item_make("%s", menu_get_prompt(child));
+ item_set_data(child);
+ if (child->sym == active)
+ item_set_selected(1);
if (child->sym == sym_get_choice_value(menu->sym))
- cprint("ON");
- else if (child->sym == active)
- cprint("SELECTED");
- else
- cprint("OFF");
+ item_set_tag('X');
}
-
- stat = exec_conf();
- switch (stat) {
+ dialog_clear();
+ res = dialog_checklist(prompt ? prompt : _("Main Menu"),
+ _(radiolist_instructions),
+ 15, 70, 6);
+ selected = item_activate_selected();
+ switch (res) {
case 0:
- if (sscanf(input_buf, "%p", &child) != 1)
- break;
- sym_set_tristate_value(child->sym, yes);
+ if (selected) {
+ child = item_data();
+ sym_set_tristate_value(child->sym, yes);
+ }
return;
case 1:
- if (sscanf(input_buf, "%p", &child) == 1) {
+ if (selected) {
+ child = item_data();
show_help(child);
active = child->sym;
} else
show_help(menu);
break;
- case 255:
+ case KEY_ESC:
+ return;
+ case -ERRDISPLAYTOOSMALL:
return;
}
}
@@ -934,40 +767,38 @@ static void conf_choice(struct menu *menu)
static void conf_string(struct menu *menu)
{
const char *prompt = menu_get_prompt(menu);
- int stat;
while (1) {
- cprint_init();
- cprint("--title");
- cprint("%s", prompt ? prompt : _("Main Menu"));
- cprint("--inputbox");
+ int res;
+ char *heading;
+
switch (sym_get_type(menu->sym)) {
case S_INT:
- cprint(_(inputbox_instructions_int));
+ heading = _(inputbox_instructions_int);
break;
case S_HEX:
- cprint(_(inputbox_instructions_hex));
+ heading = _(inputbox_instructions_hex);
break;
case S_STRING:
- cprint(_(inputbox_instructions_string));
+ heading = _(inputbox_instructions_string);
break;
default:
- /* panic? */;
+ heading = "Internal mconf error!";
}
- cprint("10");
- cprint("75");
- cprint("%s", sym_get_string_value(menu->sym));
- stat = exec_conf();
- switch (stat) {
+ dialog_clear();
+ res = dialog_inputbox(prompt ? prompt : _("Main Menu"),
+ heading, 10, 75,
+ sym_get_string_value(menu->sym));
+ switch (res) {
case 0:
- if (sym_set_string_value(menu->sym, input_buf))
+ if (sym_set_string_value(menu->sym, dialog_input_result))
return;
show_textbox(NULL, _("You have made an invalid entry."), 5, 43);
break;
case 1:
show_help(menu);
break;
- case 255:
+ case KEY_ESC:
return;
}
}
@@ -975,28 +806,24 @@ static void conf_string(struct menu *menu)
static void conf_load(void)
{
- int stat;
while (1) {
- cprint_init();
- cprint("--inputbox");
- cprint(load_config_text);
- cprint("11");
- cprint("55");
- cprint("%s", filename);
- stat = exec_conf();
- switch(stat) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, load_config_text,
+ 11, 55, filename);
+ switch(res) {
case 0:
- if (!input_buf[0])
+ if (!dialog_input_result[0])
return;
- if (!conf_read(input_buf))
+ if (!conf_read(dialog_input_result))
return;
show_textbox(NULL, _("File does not exist!"), 5, 38);
break;
case 1:
show_helptext(_("Load Alternate Configuration"), load_config_help);
break;
- case 255:
+ case KEY_ESC:
return;
}
}
@@ -1004,28 +831,23 @@ static void conf_load(void)
static void conf_save(void)
{
- int stat;
-
while (1) {
- cprint_init();
- cprint("--inputbox");
- cprint(save_config_text);
- cprint("11");
- cprint("55");
- cprint("%s", filename);
- stat = exec_conf();
- switch(stat) {
+ int res;
+ dialog_clear();
+ res = dialog_inputbox(NULL, save_config_text,
+ 11, 55, filename);
+ switch(res) {
case 0:
- if (!input_buf[0])
+ if (!dialog_input_result[0])
return;
- if (!conf_write(input_buf))
+ if (!conf_write(dialog_input_result))
return;
show_textbox(NULL, _("Can't create file! Probably a nonexistent directory."), 5, 60);
break;
case 1:
show_helptext(_("Save Alternate Configuration"), save_config_help);
break;
- case 255:
+ case KEY_ESC:
return;
}
}
@@ -1034,15 +856,13 @@ static void conf_save(void)
static void conf_cleanup(void)
{
tcsetattr(1, TCSAFLUSH, &ios_org);
- unlink(".help.tmp");
- unlink("lxdialog.scrltmp");
}
int main(int ac, char **av)
{
struct symbol *sym;
char *mode;
- int stat;
+ int res;
setlocale(LC_ALL, "");
bindtextdomain(PACKAGE, LOCALEDIR);
@@ -1065,18 +885,19 @@ int main(int ac, char **av)
tcgetattr(1, &ios_org);
atexit(conf_cleanup);
init_wsize();
- conf(&rootmenu);
-
+ reset_dialog();
+ init_dialog(menu_backtitle);
do {
- cprint_init();
- cprint("--yesno");
- cprint(_("Do you wish to save your new kernel configuration?"));
- cprint("5");
- cprint("60");
- stat = exec_conf();
- } while (stat < 0);
-
- if (stat == 0) {
+ conf(&rootmenu);
+ dialog_clear();
+ res = dialog_yesno(NULL,
+ _("Do you wish to save your "
+ "new kernel configuration?\n"
+ "<ESC><ESC> to continue."),
+ 6, 60);
+ } while (res == KEY_ESC);
+ end_dialog();
+ if (res == 0) {
if (conf_write(NULL)) {
fprintf(stderr, _("\n\n"
"Error during writing of the kernel configuration.\n"
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index c9ca0c23bd91..187f5de4612c 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -57,8 +57,8 @@ use strict;
# other functions are ignored.
#
# -nofunction funcname
-# If set, then only generate documentation for the other function(s). All
-# other functions are ignored. Cannot be used with -function together
+# If set, then only generate documentation for the other function(s).
+# Cannot be used together with -function
# (yes, that's a bug -- perl hackers can fix it 8))
#
# c files - list of 'c' files to process
@@ -1262,7 +1262,9 @@ sub output_intro_text(%) {
}
##
-# generic output function for typedefs
+# generic output function for all types (function, struct/union, typedef, enum);
+# calls the generated, variable output_ function name based on
+# functype and output_mode
sub output_declaration {
no strict 'refs';
my $name = shift;
@@ -1278,8 +1280,7 @@ sub output_declaration {
}
##
-# generic output function - calls the right one based
-# on current output mode.
+# generic output function - calls the right one based on current output mode.
sub output_intro {
no strict 'refs';
my $func = "output_intro_".$output_mode;
@@ -1518,6 +1519,9 @@ sub dump_function($$) {
$prototype =~ s/^asmlinkage +//;
$prototype =~ s/^inline +//;
$prototype =~ s/^__inline__ +//;
+ $prototype =~ s/^__inline +//;
+ $prototype =~ s/^__always_inline +//;
+ $prototype =~ s/^noinline +//;
$prototype =~ s/__devinit +//;
$prototype =~ s/^#define +//; #ak added
$prototype =~ s/__attribute__ \(\([a-z,]*\)\)//;
@@ -1778,8 +1782,9 @@ sub process_file($) {
$in_doc_sect = 1;
$contents = $newcontents;
if ($contents ne "") {
- if (substr($contents, 0, 1) eq " ") {
- $contents = substr($contents, 1);
+ while ((substr($contents, 0, 1) eq " ") ||
+ substr($contents, 0, 1) eq "\t") {
+ $contents = substr($contents, 1);
}
$contents .= "\n";
}
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index de76da80443f..f61c9ccef6aa 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -444,6 +444,14 @@ static int do_input_entry(const char *filename, struct input_device_id *id,
return 1;
}
+static int do_eisa_entry(const char *filename, struct eisa_device_id *eisa,
+ char *alias)
+{
+ if (eisa->sig[0])
+ sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", eisa->sig);
+ return 1;
+}
+
/* Ignore any prefix, eg. v850 prepends _ */
static inline int sym_is(const char *symbol, const char *name)
{
@@ -547,6 +555,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
do_table(symval, sym->st_size,
sizeof(struct input_device_id), "input",
do_input_entry, mod);
+ else if (sym_is(symname, "__mod_eisa_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct eisa_device_id), "eisa",
+ do_eisa_entry, mod);
}
/* Now add out buffered information to the generated C source */
diff --git a/security/Kconfig b/security/Kconfig
index 67785df264e5..460e5c9cf496 100644
--- a/security/Kconfig
+++ b/security/Kconfig
@@ -93,18 +93,6 @@ config SECURITY_ROOTPLUG
If you are unsure how to answer this question, answer N.
-config SECURITY_SECLVL
- tristate "BSD Secure Levels"
- depends on SECURITY
- select CRYPTO
- select CRYPTO_SHA1
- help
- Implements BSD Secure Levels as an LSM. See
- <file:Documentation/seclvl.txt> for instructions on how to use this
- module.
-
- If you are unsure how to answer this question, answer N.
-
source security/selinux/Kconfig
endmenu
diff --git a/security/Makefile b/security/Makefile
index 8cbbf2f36709..ef87df2f50a4 100644
--- a/security/Makefile
+++ b/security/Makefile
@@ -16,4 +16,3 @@ obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o
obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o
obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o
-obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
diff --git a/security/commoncap.c b/security/commoncap.c
index f50fc298cf80..5a5ef5ca7ea9 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -169,7 +169,7 @@ void cap_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
/* For init, we want to retain the capabilities set
* in the init_task struct. Thus we skip the usual
* capability rules */
- if (current->pid != 1) {
+ if (!is_init(current)) {
current->cap_permitted = new_permitted;
current->cap_effective =
cap_intersect (new_permitted, bprm->cap_effective);
diff --git a/security/dummy.c b/security/dummy.c
index aeee70565509..43874c1e6e23 100644
--- a/security/dummy.c
+++ b/security/dummy.c
@@ -881,7 +881,8 @@ static int dummy_xfrm_state_pol_flow_match(struct xfrm_state *x,
return 1;
}
-static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm)
+static int dummy_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
+ struct xfrm_policy *xp)
{
return 1;
}
diff --git a/security/inode.c b/security/inode.c
index 47eb63480dac..9b16e14f3a80 100644
--- a/security/inode.c
+++ b/security/inode.c
@@ -44,8 +44,8 @@ static ssize_t default_write_file(struct file *file, const char __user *buf,
static int default_open(struct inode *inode, struct file *file)
{
- if (inode->u.generic_ip)
- file->private_data = inode->u.generic_ip;
+ if (inode->i_private)
+ file->private_data = inode->i_private;
return 0;
}
@@ -64,7 +64,6 @@ static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)
inode->i_mode = mode;
inode->i_uid = 0;
inode->i_gid = 0;
- inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
switch (mode & S_IFMT) {
@@ -79,7 +78,7 @@ static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
break;
}
}
@@ -112,7 +111,7 @@ static int mkdir(struct inode *dir, struct dentry *dentry, int mode)
mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
res = mknod(dir, dentry, mode, 0);
if (!res)
- dir->i_nlink++;
+ inc_nlink(dir);
return res;
}
@@ -194,7 +193,7 @@ static int create_by_name(const char *name, mode_t mode,
* directory dentry if set. If this paramater is NULL, then the
* file will be created in the root of the securityfs filesystem.
* @data: a pointer to something that the caller will want to get to later
- * on. The inode.u.generic_ip pointer will point to this value on
+ * on. The inode.i_private pointer will point to this value on
* the open() call.
* @fops: a pointer to a struct file_operations that should be used for
* this file.
@@ -240,7 +239,7 @@ struct dentry *securityfs_create_file(const char *name, mode_t mode,
if (fops)
dentry->d_inode->i_fop = fops;
if (data)
- dentry->d_inode->u.generic_ip = data;
+ dentry->d_inode->i_private = data;
}
exit:
return dentry;
diff --git a/security/seclvl.c b/security/seclvl.c
deleted file mode 100644
index 8f6291991fbc..000000000000
--- a/security/seclvl.c
+++ /dev/null
@@ -1,671 +0,0 @@
-/**
- * BSD Secure Levels LSM
- *
- * Maintainers:
- * Michael A. Halcrow <mike@halcrow.us>
- * Serge Hallyn <hallyn@cs.wm.edu>
- *
- * Copyright (c) 2001 WireX Communications, Inc <chris@wirex.com>
- * Copyright (c) 2001 Greg Kroah-Hartman <greg@kroah.com>
- * Copyright (c) 2002 International Business Machines <robb@austin.ibm.com>
- * Copyright (c) 2006 Davi E. M. Arnaut <davi.arnaut@gmail.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/err.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/security.h>
-#include <linux/netlink.h>
-#include <linux/fs.h>
-#include <linux/namei.h>
-#include <linux/mount.h>
-#include <linux/capability.h>
-#include <linux/time.h>
-#include <linux/proc_fs.h>
-#include <linux/kobject.h>
-#include <linux/crypto.h>
-#include <asm/scatterlist.h>
-#include <linux/scatterlist.h>
-#include <linux/gfp.h>
-#include <linux/sysfs.h>
-
-#define SHA1_DIGEST_SIZE 20
-
-/**
- * Module parameter that defines the initial secure level.
- *
- * When built as a module, it defaults to seclvl 1, which is the
- * behavior of BSD secure levels. Note that this default behavior
- * wrecks havoc on a machine when the seclvl module is compiled into
- * the kernel. In that case, we default to seclvl 0.
- */
-#ifdef CONFIG_SECURITY_SECLVL_MODULE
-static int initlvl = 1;
-#else
-static int initlvl;
-#endif
-module_param(initlvl, int, 0);
-MODULE_PARM_DESC(initlvl, "Initial secure level (defaults to 1)");
-
-/* Module parameter that defines the verbosity level */
-static int verbosity;
-module_param(verbosity, int, 0);
-MODULE_PARM_DESC(verbosity, "Initial verbosity level (0 or 1; defaults to "
- "0, which is Quiet)");
-
-/**
- * Optional password which can be passed in to bring seclvl to 0
- * (i.e., for halt/reboot). Defaults to NULL (the passwd attribute
- * file will not be registered in sysfs).
- *
- * This gets converted to its SHA1 hash when stored. It's probably
- * not a good idea to use this parameter when loading seclvl from a
- * script; use sha1_passwd instead.
- */
-
-#define MAX_PASSWD_SIZE 32
-static char passwd[MAX_PASSWD_SIZE];
-module_param_string(passwd, passwd, sizeof(passwd), 0);
-MODULE_PARM_DESC(passwd,
- "Plaintext of password that sets seclvl=0 when written to "
- "(sysfs mount point)/seclvl/passwd\n");
-
-/**
- * SHA1 hashed version of the optional password which can be passed in
- * to bring seclvl to 0 (i.e., for halt/reboot). Must be in
- * hexadecimal format (40 characters). Defaults to NULL (the passwd
- * attribute file will not be registered in sysfs).
- *
- * Use the sha1sum utility to generate the SHA1 hash of a password:
- *
- * echo -n "secret" | sha1sum
- */
-#define MAX_SHA1_PASSWD 41
-static char sha1_passwd[MAX_SHA1_PASSWD];
-module_param_string(sha1_passwd, sha1_passwd, sizeof(sha1_passwd), 0);
-MODULE_PARM_DESC(sha1_passwd,
- "SHA1 hash (40 hexadecimal characters) of password that "
- "sets seclvl=0 when plaintext password is written to "
- "(sysfs mount point)/seclvl/passwd\n");
-
-static int hideHash = 1;
-module_param(hideHash, int, 0);
-MODULE_PARM_DESC(hideHash, "When set to 0, reading seclvl/passwd from sysfs "
- "will return the SHA1-hashed value of the password that "
- "lowers the secure level to 0.\n");
-
-#define MY_NAME "seclvl"
-
-/**
- * This time-limits log writes to one per second.
- */
-#define seclvl_printk(verb, type, fmt, arg...) \
- do { \
- if (verbosity >= verb) { \
- static unsigned long _prior; \
- unsigned long _now = jiffies; \
- if ((_now - _prior) > HZ) { \
- printk(type "%s: %s: " fmt, \
- MY_NAME, __FUNCTION__ , \
- ## arg); \
- _prior = _now; \
- } \
- } \
- } while (0)
-
-/**
- * The actual security level. Ranges between -1 and 2 inclusive.
- */
-static int seclvl;
-
-/**
- * flag to keep track of how we were registered
- */
-static int secondary;
-
-/**
- * Verifies that the requested secure level is valid, given the current
- * secure level.
- */
-static int seclvl_sanity(int reqlvl)
-{
- if ((reqlvl < -1) || (reqlvl > 2)) {
- seclvl_printk(1, KERN_WARNING, "Attempt to set seclvl out of "
- "range: [%d]\n", reqlvl);
- return -EINVAL;
- }
- if ((seclvl == 0) && (reqlvl == -1))
- return 0;
- if (reqlvl < seclvl) {
- seclvl_printk(1, KERN_WARNING, "Attempt to lower seclvl to "
- "[%d]\n", reqlvl);
- return -EPERM;
- }
- return 0;
-}
-
-/**
- * security level advancement rules:
- * Valid levels are -1 through 2, inclusive.
- * From -1, stuck. [ in case compiled into kernel ]
- * From 0 or above, can only increment.
- */
-static void do_seclvl_advance(void *data, u64 val)
-{
- int ret;
- int newlvl = (int)val;
-
- ret = seclvl_sanity(newlvl);
- if (ret)
- return;
-
- if (newlvl > 2) {
- seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
- "[%d]\n", newlvl);
- return;
- }
- if (seclvl == -1) {
- seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
- "seclvl [%d]\n", seclvl);
- return;
- }
- seclvl = newlvl; /* would it be more "correct" to set *data? */
- return;
-}
-
-static u64 seclvl_int_get(void *data)
-{
- return *(int *)data;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%lld\n");
-
-static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
-
-/**
- * Converts a block of plaintext of into its SHA1 hashed value.
- *
- * It would be nice if crypto had a wrapper to do this for us linear
- * people...
- */
-static int
-plaintext_to_sha1(unsigned char *hash, const char *plaintext, unsigned int len)
-{
- struct hash_desc desc;
- struct scatterlist sg;
- int err;
-
- if (len > PAGE_SIZE) {
- seclvl_printk(0, KERN_ERR, "Plaintext password too large (%d "
- "characters). Largest possible is %lu "
- "bytes.\n", len, PAGE_SIZE);
- return -EINVAL;
- }
- desc.tfm = crypto_alloc_hash("sha1", 0, CRYPTO_ALG_ASYNC);
- if (IS_ERR(desc.tfm)) {
- seclvl_printk(0, KERN_ERR,
- "Failed to load transform for SHA1\n");
- return -EINVAL;
- }
- sg_init_one(&sg, (u8 *)plaintext, len);
- desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
- err = crypto_hash_digest(&desc, &sg, len, hash);
- crypto_free_hash(desc.tfm);
- return err;
-}
-
-/**
- * Called whenever the user writes to the sysfs passwd handle to this kernel
- * object. It hashes the password and compares the hashed results.
- */
-static ssize_t
-passwd_write_file(struct file * file, const char __user * buf,
- size_t count, loff_t *ppos)
-{
- char *p;
- int len;
- unsigned char tmp[SHA1_DIGEST_SIZE];
-
- if (!*passwd && !*sha1_passwd) {
- seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
- "seclvl module, but neither a plain text "
- "password nor a SHA1 hashed password was "
- "passed in as a module parameter! This is a "
- "bug, since it should not be possible to be in "
- "this part of the module; please tell a "
- "maintainer about this event.\n");
- return -EINVAL;
- }
-
- if (count >= PAGE_SIZE)
- return -EINVAL;
- if (*ppos != 0)
- return -EINVAL;
- p = kmalloc(count, GFP_KERNEL);
- if (!p)
- return -ENOMEM;
- len = -EFAULT;
- if (copy_from_user(p, buf, count))
- goto out;
-
- len = count;
- /* ``echo "secret" > seclvl/passwd'' includes a newline */
- if (p[len - 1] == '\n')
- len--;
- /* Hash the password, then compare the hashed values */
- if ((len = plaintext_to_sha1(tmp, p, len))) {
- seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
- "[%d]\n", len);
- goto out;
- }
-
- len = -EPERM;
- if (memcmp(hashedPassword, tmp, SHA1_DIGEST_SIZE))
- goto out;
-
- seclvl_printk(0, KERN_INFO,
- "Password accepted; seclvl reduced to 0.\n");
- seclvl = 0;
- len = count;
-
-out:
- kfree (p);
- return len;
-}
-
-static struct file_operations passwd_file_ops = {
- .write = passwd_write_file,
-};
-
-/**
- * Explicitely disallow ptrace'ing the init process.
- */
-static int seclvl_ptrace(struct task_struct *parent, struct task_struct *child)
-{
- if (seclvl >= 0 && child->pid == 1) {
- seclvl_printk(1, KERN_WARNING, "Attempt to ptrace "
- "the init process dissallowed in "
- "secure level %d\n", seclvl);
- return -EPERM;
- }
- return 0;
-}
-
-/**
- * Capability checks for seclvl. The majority of the policy
- * enforcement for seclvl takes place here.
- */
-static int seclvl_capable(struct task_struct *tsk, int cap)
-{
- int rc = 0;
-
- /* init can do anything it wants */
- if (tsk->pid == 1)
- return 0;
-
- if (seclvl > 0) {
- rc = -EPERM;
-
- if (cap == CAP_LINUX_IMMUTABLE)
- seclvl_printk(1, KERN_WARNING, "Attempt to modify "
- "the IMMUTABLE and/or APPEND extended "
- "attribute on a file with the IMMUTABLE "
- "and/or APPEND extended attribute set "
- "denied in seclvl [%d]\n", seclvl);
- else if (cap == CAP_SYS_RAWIO)
- seclvl_printk(1, KERN_WARNING, "Attempt to perform "
- "raw I/O while in secure level [%d] "
- "denied\n", seclvl);
- else if (cap == CAP_NET_ADMIN)
- seclvl_printk(1, KERN_WARNING, "Attempt to perform "
- "network administrative task while "
- "in secure level [%d] denied\n", seclvl);
- else if (cap == CAP_SETUID)
- seclvl_printk(1, KERN_WARNING, "Attempt to setuid "
- "while in secure level [%d] denied\n",
- seclvl);
- else if (cap == CAP_SETGID)
- seclvl_printk(1, KERN_WARNING, "Attempt to setgid "
- "while in secure level [%d] denied\n",
- seclvl);
- else if (cap == CAP_SYS_MODULE)
- seclvl_printk(1, KERN_WARNING, "Attempt to perform "
- "a module operation while in secure "
- "level [%d] denied\n", seclvl);
- else
- rc = 0;
- }
-
- if (!rc) {
- if (!(cap_is_fs_cap(cap) ? tsk->fsuid == 0 : tsk->euid == 0))
- rc = -EPERM;
- }
-
- if (rc)
- seclvl_printk(1, KERN_WARNING, "Capability denied\n");
-
- return rc;
-}
-
-/**
- * Disallow reversing the clock in seclvl > 1
- */
-static int seclvl_settime(struct timespec *tv, struct timezone *tz)
-{
- if (tv && seclvl > 1) {
- struct timespec now;
- now = current_kernel_time();
- if (tv->tv_sec < now.tv_sec ||
- (tv->tv_sec == now.tv_sec && tv->tv_nsec < now.tv_nsec)) {
- seclvl_printk(1, KERN_WARNING, "Attempt to decrement "
- "time in secure level %d denied: "
- "current->pid = [%d], "
- "current->group_leader->pid = [%d]\n",
- seclvl, current->pid,
- current->group_leader->pid);
- return -EPERM;
- } /* if attempt to decrement time */
- } /* if seclvl > 1 */
- return 0;
-}
-
-/* claim the blockdev to exclude mounters, release on file close */
-static int seclvl_bd_claim(struct inode *inode)
-{
- int holder;
- struct block_device *bdev = NULL;
- dev_t dev = inode->i_rdev;
- bdev = open_by_devnum(dev, FMODE_WRITE);
- if (bdev) {
- if (bd_claim(bdev, &holder)) {
- blkdev_put(bdev);
- return -EPERM;
- }
- /* claimed, mark it to release on close */
- inode->i_security = current;
- }
- return 0;
-}
-
-/* release the blockdev if you claimed it */
-static void seclvl_bd_release(struct inode *inode)
-{
- if (inode && S_ISBLK(inode->i_mode) && inode->i_security == current) {
- struct block_device *bdev = inode->i_bdev;
- if (bdev) {
- bd_release(bdev);
- blkdev_put(bdev);
- inode->i_security = NULL;
- }
- }
-}
-
-/**
- * Security for writes to block devices is regulated by this seclvl
- * function. Deny all writes to block devices in seclvl 2. In
- * seclvl 1, we only deny writes to *mounted* block devices.
- */
-static int
-seclvl_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
-{
- if (current->pid != 1 && S_ISBLK(inode->i_mode) && (mask & MAY_WRITE)) {
- switch (seclvl) {
- case 2:
- seclvl_printk(1, KERN_WARNING, "Write to block device "
- "denied in secure level [%d]\n", seclvl);
- return -EPERM;
- case 1:
- if (seclvl_bd_claim(inode)) {
- seclvl_printk(1, KERN_WARNING,
- "Write to mounted block device "
- "denied in secure level [%d]\n",
- seclvl);
- return -EPERM;
- }
- }
- }
- return 0;
-}
-
-/**
- * The SUID and SGID bits cannot be set in seclvl >= 1
- */
-static int seclvl_inode_setattr(struct dentry *dentry, struct iattr *iattr)
-{
- if (seclvl > 0) {
- if (iattr->ia_valid & ATTR_MODE)
- if (iattr->ia_mode & S_ISUID ||
- iattr->ia_mode & S_ISGID) {
- seclvl_printk(1, KERN_WARNING, "Attempt to "
- "modify SUID or SGID bit "
- "denied in seclvl [%d]\n",
- seclvl);
- return -EPERM;
- }
- }
- return 0;
-}
-
-/* release busied block devices */
-static void seclvl_file_free_security(struct file *filp)
-{
- struct dentry *dentry = filp->f_dentry;
-
- if (dentry)
- seclvl_bd_release(dentry->d_inode);
-}
-
-/**
- * Cannot unmount in secure level 2
- */
-static int seclvl_umount(struct vfsmount *mnt, int flags)
-{
- if (current->pid != 1 && seclvl == 2) {
- seclvl_printk(1, KERN_WARNING, "Attempt to unmount in secure "
- "level %d\n", seclvl);
- return -EPERM;
- }
- return 0;
-}
-
-static struct security_operations seclvl_ops = {
- .ptrace = seclvl_ptrace,
- .capable = seclvl_capable,
- .inode_permission = seclvl_inode_permission,
- .inode_setattr = seclvl_inode_setattr,
- .file_free_security = seclvl_file_free_security,
- .settime = seclvl_settime,
- .sb_umount = seclvl_umount,
-};
-
-/**
- * Process the password-related module parameters
- */
-static int processPassword(void)
-{
- int rc = 0;
- if (*passwd) {
- char *p;
-
- if (*sha1_passwd) {
- seclvl_printk(0, KERN_ERR, "Error: Both "
- "passwd and sha1_passwd "
- "were set, but they are mutually "
- "exclusive.\n");
- return -EINVAL;
- }
-
- p = kstrdup(passwd, GFP_KERNEL);
- if (p == NULL)
- return -ENOMEM;
-
- if ((rc = plaintext_to_sha1(hashedPassword, p, strlen(p))))
- seclvl_printk(0, KERN_ERR, "Error: SHA1 support not "
- "in kernel\n");
-
- kfree (p);
- /* All static data goes to the BSS, which zero's the
- * plaintext password out for us. */
- } else if (*sha1_passwd) { // Base 16
- int i;
- i = strlen(sha1_passwd);
- if (i != (SHA1_DIGEST_SIZE * 2)) {
- seclvl_printk(0, KERN_ERR, "Received [%d] bytes; "
- "expected [%d] for the hexadecimal "
- "representation of the SHA1 hash of "
- "the password.\n",
- i, (SHA1_DIGEST_SIZE * 2));
- return -EINVAL;
- }
- while ((i -= 2) + 2) {
- unsigned char tmp;
- tmp = sha1_passwd[i + 2];
- sha1_passwd[i + 2] = '\0';
- hashedPassword[i / 2] = (unsigned char)
- simple_strtol(&sha1_passwd[i], NULL, 16);
- sha1_passwd[i + 2] = tmp;
- }
- }
- return rc;
-}
-
-/**
- * securityfs registrations
- */
-struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
-
-static int seclvlfs_register(void)
-{
- int rc = 0;
-
- dir_ino = securityfs_create_dir("seclvl", NULL);
-
- if (IS_ERR(dir_ino))
- return PTR_ERR(dir_ino);
-
- seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
- dir_ino, &seclvl, &seclvl_file_ops);
- if (IS_ERR(seclvl_ino)) {
- rc = PTR_ERR(seclvl_ino);
- goto out_deldir;
- }
- if (*passwd || *sha1_passwd) {
- passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
- dir_ino, NULL, &passwd_file_ops);
- if (IS_ERR(passwd_ino)) {
- rc = PTR_ERR(passwd_ino);
- goto out_delf;
- }
- }
- return rc;
-
-out_delf:
- securityfs_remove(seclvl_ino);
-
-out_deldir:
- securityfs_remove(dir_ino);
-
- return rc;
-}
-
-static void seclvlfs_unregister(void)
-{
- securityfs_remove(seclvl_ino);
-
- if (*passwd || *sha1_passwd)
- securityfs_remove(passwd_ino);
-
- securityfs_remove(dir_ino);
-}
-
-/**
- * Initialize the seclvl module.
- */
-static int __init seclvl_init(void)
-{
- int rc = 0;
- static char once;
-
- if (verbosity < 0 || verbosity > 1) {
- printk(KERN_ERR "Error: bad verbosity [%d]; only 0 or 1 "
- "are valid values\n", verbosity);
- rc = -EINVAL;
- goto exit;
- }
- if (initlvl < -1 || initlvl > 2) {
- seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
- "[%d].\n", initlvl);
- rc = -EINVAL;
- goto exit;
- }
- seclvl = initlvl;
- if ((rc = processPassword())) {
- seclvl_printk(0, KERN_ERR, "Error processing the password "
- "module parameter(s): rc = [%d]\n", rc);
- goto exit;
- }
-
- if ((rc = seclvlfs_register())) {
- seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
- goto exit;
- }
- /* register ourselves with the security framework */
- if (register_security(&seclvl_ops)) {
- seclvl_printk(0, KERN_ERR,
- "seclvl: Failure registering with the "
- "kernel.\n");
- /* try registering with primary module */
- rc = mod_reg_security(MY_NAME, &seclvl_ops);
- if (rc) {
- seclvl_printk(0, KERN_ERR, "seclvl: Failure "
- "registering with primary security "
- "module.\n");
- seclvlfs_unregister();
- goto exit;
- } /* if primary module registered */
- secondary = 1;
- } /* if we registered ourselves with the security framework */
-
- seclvl_printk(0, KERN_INFO, "seclvl: Successfully initialized.\n");
-
- if (once) {
- once = 1;
- seclvl_printk(0, KERN_INFO, "seclvl is going away. It has been "
- "buggy for ages. Also, be warned that "
- "Securelevels are useless.");
- }
- exit:
- if (rc)
- printk(KERN_ERR "seclvl: Error during initialization: rc = "
- "[%d]\n", rc);
- return rc;
-}
-
-/**
- * Remove the seclvl module.
- */
-static void __exit seclvl_exit(void)
-{
- seclvlfs_unregister();
-
- if (secondary)
- mod_unreg_security(MY_NAME, &seclvl_ops);
- else if (unregister_security(&seclvl_ops))
- seclvl_printk(0, KERN_INFO,
- "seclvl: Failure unregistering with the "
- "kernel\n");
-}
-
-module_init(seclvl_init);
-module_exit(seclvl_exit);
-
-MODULE_AUTHOR("Michael A. Halcrow <mike@halcrow.us>");
-MODULE_DESCRIPTION("LSM implementation of the BSD Secure Levels");
-MODULE_LICENSE("GPL");
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 293dbd6246c1..23b51047494e 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -112,7 +112,7 @@ config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
your distribution will provide these and enable the new controls
in the kernel they also distribute.
- Note that this option can be overriden at boot with the
+ Note that this option can be overridden at boot with the
selinux_compat_net parameter, and after boot via
/selinux/compat_net. See Documentation/kernel-parameters.txt
for details on this parameter.
@@ -122,7 +122,7 @@ config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
well as any conntrack helpers for protocols which you
wish to control.
- If you are unsure what do do here, select N.
+ If you are unsure what to do here, select N.
config SECURITY_SELINUX_POLICYDB_VERSION_MAX
bool "NSA SELinux maximum supported policy format version"
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index e4d81a42fca4..e9969a2fc846 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -398,7 +398,7 @@ static int try_context_mount(struct super_block *sb, void *data)
/* Standard string-based options. */
char *p, *options = data;
- while ((p = strsep(&options, ",")) != NULL) {
+ while ((p = strsep(&options, "|")) != NULL) {
int token;
substring_t args[MAX_OPT_ARGS];
@@ -1923,18 +1923,40 @@ static inline void take_option(char **to, char *from, int *first, int len)
if (!*first) {
**to = ',';
*to += 1;
- }
- else
+ } else
*first = 0;
memcpy(*to, from, len);
*to += len;
}
+static inline void take_selinux_option(char **to, char *from, int *first,
+ int len)
+{
+ int current_size = 0;
+
+ if (!*first) {
+ **to = '|';
+ *to += 1;
+ }
+ else
+ *first = 0;
+
+ while (current_size < len) {
+ if (*from != '"') {
+ **to = *from;
+ *to += 1;
+ }
+ from += 1;
+ current_size += 1;
+ }
+}
+
static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy)
{
int fnosec, fsec, rc = 0;
char *in_save, *in_curr, *in_end;
char *sec_curr, *nosec_save, *nosec;
+ int open_quote = 0;
in_curr = orig;
sec_curr = copy;
@@ -1956,11 +1978,14 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void
in_save = in_end = orig;
do {
- if (*in_end == ',' || *in_end == '\0') {
+ if (*in_end == '"')
+ open_quote = !open_quote;
+ if ((*in_end == ',' && open_quote == 0) ||
+ *in_end == '\0') {
int len = in_end - in_curr;
if (selinux_option(in_curr, len))
- take_option(&sec_curr, in_curr, &fsec, len);
+ take_selinux_option(&sec_curr, in_curr, &fsec, len);
else
take_option(&nosec, in_curr, &fnosec, len);
@@ -3594,7 +3619,9 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent)
struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
struct sk_security_struct *sksec = sk->sk_security;
- isec->sid = sksec->sid;
+ if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
+ sk->sk_family == PF_UNIX)
+ isec->sid = sksec->sid;
selinux_netlbl_sock_graft(sk, parent);
}
diff --git a/security/selinux/include/xfrm.h b/security/selinux/include/xfrm.h
index 81eb59890162..526b28019aca 100644
--- a/security/selinux/include/xfrm.h
+++ b/security/selinux/include/xfrm.h
@@ -19,7 +19,8 @@ int selinux_xfrm_state_delete(struct xfrm_state *x);
int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir);
int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x,
struct xfrm_policy *xp, struct flowi *fl);
-int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm);
+int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
+ struct xfrm_policy *xp);
/*
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 00534c302ba2..cd244419c980 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -771,7 +771,6 @@ static struct inode *sel_make_inode(struct super_block *sb, int mode)
if (ret) {
ret->i_mode = mode;
ret->i_uid = ret->i_gid = 0;
- ret->i_blksize = PAGE_CACHE_SIZE;
ret->i_blocks = 0;
ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
}
@@ -1254,10 +1253,10 @@ static int sel_make_dir(struct inode *dir, struct dentry *dentry)
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
/* directory inodes start off with i_nlink == 2 (for "." entry) */
- inode->i_nlink++;
+ inc_nlink(inode);
d_add(dentry, inode);
/* bump link count on parent directory, too */
- dir->i_nlink++;
+ inc_nlink(dir);
out:
return ret;
}
diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c
index cfed1d30fa6a..d539346ab3a2 100644
--- a/security/selinux/ss/ebitmap.c
+++ b/security/selinux/ss/ebitmap.c
@@ -93,11 +93,15 @@ int ebitmap_export(const struct ebitmap *src,
size_t bitmap_byte;
unsigned char bitmask;
+ if (src->highbit == 0) {
+ *dst = NULL;
+ *dst_len = 0;
+ return 0;
+ }
+
bitmap_len = src->highbit / 8;
if (src->highbit % 7)
bitmap_len += 1;
- if (bitmap_len == 0)
- return -EINVAL;
bitmap = kzalloc((bitmap_len & ~(sizeof(MAPTYPE) - 1)) +
sizeof(MAPTYPE),
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index c713af23250a..2cca8e251624 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -640,8 +640,13 @@ int mls_export_cat(const struct context *context,
{
int rc = -EPERM;
- if (!selinux_mls_enabled)
+ if (!selinux_mls_enabled) {
+ *low = NULL;
+ *low_len = 0;
+ *high = NULL;
+ *high_len = 0;
return 0;
+ }
if (low != NULL) {
rc = ebitmap_export(&context->range.level[0].cat,
@@ -661,10 +666,16 @@ int mls_export_cat(const struct context *context,
return 0;
export_cat_failure:
- if (low != NULL)
+ if (low != NULL) {
kfree(*low);
- if (high != NULL)
+ *low = NULL;
+ *low_len = 0;
+ }
+ if (high != NULL) {
kfree(*high);
+ *high = NULL;
+ *high_len = 0;
+ }
return rc;
}
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index b18895302555..ba48961f9d05 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -618,6 +618,7 @@ void policydb_destroy(struct policydb *p)
c = c->next;
ocontext_destroy(ctmp,i);
}
+ p->ocontexts[i] = NULL;
}
g = p->genfs;
@@ -633,6 +634,7 @@ void policydb_destroy(struct policydb *p)
g = g->next;
kfree(gtmp);
}
+ p->genfs = NULL;
cond_policydb_destroy(p);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 0c219a1b3243..b1f6fb36c699 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2172,7 +2172,12 @@ struct netlbl_cache {
*/
static void selinux_netlbl_cache_free(const void *data)
{
- struct netlbl_cache *cache = NETLBL_CACHE(data);
+ struct netlbl_cache *cache;
+
+ if (data == NULL)
+ return;
+
+ cache = NETLBL_CACHE(data);
switch (cache->type) {
case NETLBL_CACHE_T_MLS:
ebitmap_destroy(&cache->data.mls_label.level[0].cat);
@@ -2197,17 +2202,20 @@ static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
struct netlbl_lsm_secattr secattr;
netlbl_secattr_init(&secattr);
+ secattr.cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
+ if (secattr.cache == NULL)
+ goto netlbl_cache_add_return;
cache = kzalloc(sizeof(*cache), GFP_ATOMIC);
if (cache == NULL)
- goto netlbl_cache_add_failure;
- secattr.cache.free = selinux_netlbl_cache_free;
- secattr.cache.data = (void *)cache;
+ goto netlbl_cache_add_return;
+ secattr.cache->free = selinux_netlbl_cache_free;
+ secattr.cache->data = (void *)cache;
cache->type = NETLBL_CACHE_T_MLS;
if (ebitmap_cpy(&cache->data.mls_label.level[0].cat,
&ctx->range.level[0].cat) != 0)
- goto netlbl_cache_add_failure;
+ goto netlbl_cache_add_return;
cache->data.mls_label.level[1].cat.highbit =
cache->data.mls_label.level[0].cat.highbit;
cache->data.mls_label.level[1].cat.node =
@@ -2215,13 +2223,10 @@ static void selinux_netlbl_cache_add(struct sk_buff *skb, struct context *ctx)
cache->data.mls_label.level[0].sens = ctx->range.level[0].sens;
cache->data.mls_label.level[1].sens = ctx->range.level[0].sens;
- if (netlbl_cache_add(skb, &secattr) != 0)
- goto netlbl_cache_add_failure;
-
- return;
+ netlbl_cache_add(skb, &secattr);
-netlbl_cache_add_failure:
- netlbl_secattr_destroy(&secattr, 1);
+netlbl_cache_add_return:
+ netlbl_secattr_destroy(&secattr);
}
/**
@@ -2263,8 +2268,8 @@ static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
POLICY_RDLOCK;
- if (secattr->cache.data) {
- cache = NETLBL_CACHE(secattr->cache.data);
+ if (secattr->cache) {
+ cache = NETLBL_CACHE(secattr->cache->data);
switch (cache->type) {
case NETLBL_CACHE_T_SID:
*sid = cache->data.sid;
@@ -2331,7 +2336,7 @@ static int selinux_netlbl_secattr_to_sid(struct sk_buff *skb,
selinux_netlbl_cache_add(skb, &ctx_new);
ebitmap_destroy(&ctx_new.range.level[0].cat);
} else {
- *sid = SECINITSID_UNLABELED;
+ *sid = SECSID_NULL;
rc = 0;
}
@@ -2369,7 +2374,7 @@ static int selinux_netlbl_skbuff_getsid(struct sk_buff *skb,
&secattr,
base_sid,
sid);
- netlbl_secattr_destroy(&secattr, 0);
+ netlbl_secattr_destroy(&secattr);
return rc;
}
@@ -2394,31 +2399,33 @@ static int selinux_netlbl_socket_setsid(struct socket *sock, u32 sid)
if (!ss_initialized)
return 0;
+ netlbl_secattr_init(&secattr);
+
POLICY_RDLOCK;
ctx = sidtab_search(&sidtab, sid);
if (ctx == NULL)
goto netlbl_socket_setsid_return;
- netlbl_secattr_init(&secattr);
secattr.domain = kstrdup(policydb.p_type_val_to_name[ctx->type - 1],
GFP_ATOMIC);
mls_export_lvl(ctx, &secattr.mls_lvl, NULL);
secattr.mls_lvl_vld = 1;
- mls_export_cat(ctx,
- &secattr.mls_cat,
- &secattr.mls_cat_len,
- NULL,
- NULL);
+ rc = mls_export_cat(ctx,
+ &secattr.mls_cat,
+ &secattr.mls_cat_len,
+ NULL,
+ NULL);
+ if (rc != 0)
+ goto netlbl_socket_setsid_return;
rc = netlbl_socket_setattr(sock, &secattr);
if (rc == 0)
sksec->nlbl_state = NLBL_LABELED;
- netlbl_secattr_destroy(&secattr, 0);
-
netlbl_socket_setsid_return:
POLICY_RDUNLOCK;
+ netlbl_secattr_destroy(&secattr);
return rc;
}
@@ -2514,10 +2521,10 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
if (netlbl_sock_getattr(sk, &secattr) == 0 &&
selinux_netlbl_secattr_to_sid(NULL,
&secattr,
- sksec->sid,
+ SECINITSID_UNLABELED,
&nlbl_peer_sid) == 0)
sksec->peer_sid = nlbl_peer_sid;
- netlbl_secattr_destroy(&secattr, 0);
+ netlbl_secattr_destroy(&secattr);
sksec->nlbl_state = NLBL_REQUIRE;
@@ -2547,9 +2554,6 @@ u32 selinux_netlbl_inet_conn_request(struct sk_buff *skb, u32 sock_sid)
if (rc != 0)
return SECSID_NULL;
- if (peer_sid == SECINITSID_UNLABELED)
- return SECSID_NULL;
-
return peer_sid;
}
@@ -2611,11 +2615,13 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
u32 netlbl_sid;
u32 recv_perm;
- rc = selinux_netlbl_skbuff_getsid(skb, SECINITSID_NETMSG, &netlbl_sid);
+ rc = selinux_netlbl_skbuff_getsid(skb,
+ SECINITSID_UNLABELED,
+ &netlbl_sid);
if (rc != 0)
return rc;
- if (netlbl_sid == SECINITSID_UNLABELED)
+ if (netlbl_sid == SECSID_NULL)
return 0;
switch (sksec->sclass) {
@@ -2653,10 +2659,6 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
{
struct sk_security_struct *sksec = sock->sk->sk_security;
-
- if (sksec->peer_sid == SECINITSID_UNLABELED)
- return SECSID_NULL;
-
return sksec->peer_sid;
}
@@ -2672,16 +2674,10 @@ u32 selinux_netlbl_socket_getpeersec_stream(struct socket *sock)
u32 selinux_netlbl_socket_getpeersec_dgram(struct sk_buff *skb)
{
int peer_sid;
- struct sock *sk = skb->sk;
- struct inode_security_struct *isec;
- if (sk == NULL || sk->sk_socket == NULL)
- return SECSID_NULL;
-
- isec = SOCK_INODE(sk->sk_socket)->i_security;
- if (selinux_netlbl_skbuff_getsid(skb, isec->sid, &peer_sid) != 0)
- return SECSID_NULL;
- if (peer_sid == SECINITSID_UNLABELED)
+ if (selinux_netlbl_skbuff_getsid(skb,
+ SECINITSID_UNLABELED,
+ &peer_sid) != 0)
return SECSID_NULL;
return peer_sid;
diff --git a/security/selinux/xfrm.c b/security/selinux/xfrm.c
index 3e742b850af6..675b995a67c3 100644
--- a/security/selinux/xfrm.c
+++ b/security/selinux/xfrm.c
@@ -77,8 +77,8 @@ static inline int selinux_authorizable_xfrm(struct xfrm_state *x)
*/
int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
{
- int rc = 0;
- u32 sel_sid = SECINITSID_UNLABELED;
+ int rc;
+ u32 sel_sid;
struct xfrm_sec_ctx *ctx;
/* Context sid is either set to label or ANY_ASSOC */
@@ -88,11 +88,21 @@ int selinux_xfrm_policy_lookup(struct xfrm_policy *xp, u32 fl_secid, u8 dir)
sel_sid = ctx->ctx_sid;
}
+ else
+ /*
+ * All flows should be treated as polmatch'ing an
+ * otherwise applicable "non-labeled" policy. This
+ * would prevent inadvertent "leaks".
+ */
+ return 0;
rc = avc_has_perm(fl_secid, sel_sid, SECCLASS_ASSOCIATION,
ASSOCIATION__POLMATCH,
NULL);
+ if (rc == -EACCES)
+ rc = -ESRCH;
+
return rc;
}
@@ -108,15 +118,20 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *
u32 pol_sid;
int err;
- if (x->security)
- state_sid = x->security->ctx_sid;
- else
- state_sid = SECINITSID_UNLABELED;
-
- if (xp->security)
+ if (xp->security) {
+ if (!x->security)
+ /* unlabeled SA and labeled policy can't match */
+ return 0;
+ else
+ state_sid = x->security->ctx_sid;
pol_sid = xp->security->ctx_sid;
- else
- pol_sid = SECINITSID_UNLABELED;
+ } else
+ if (x->security)
+ /* unlabeled policy and labeled SA can't match */
+ return 0;
+ else
+ /* unlabeled policy and unlabeled SA match all flows */
+ return 1;
err = avc_has_perm(state_sid, pol_sid, SECCLASS_ASSOCIATION,
ASSOCIATION__POLMATCH,
@@ -125,7 +140,11 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *
if (err)
return 0;
- return selinux_xfrm_flow_state_match(fl, x);
+ err = avc_has_perm(fl->secid, state_sid, SECCLASS_ASSOCIATION,
+ ASSOCIATION__SENDTO,
+ NULL)? 0:1;
+
+ return err;
}
/*
@@ -133,12 +152,22 @@ int selinux_xfrm_state_pol_flow_match(struct xfrm_state *x, struct xfrm_policy *
* can use a given security association.
*/
-int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm)
+int selinux_xfrm_flow_state_match(struct flowi *fl, struct xfrm_state *xfrm,
+ struct xfrm_policy *xp)
{
int rc = 0;
u32 sel_sid = SECINITSID_UNLABELED;
struct xfrm_sec_ctx *ctx;
+ if (!xp->security)
+ if (!xfrm->security)
+ return 1;
+ else
+ return 0;
+ else
+ if (!xfrm->security)
+ return 0;
+
/* Context sid is either set to label or ANY_ASSOC */
if ((ctx = xfrm->security)) {
if (!selinux_authorizable_ctx(ctx))
diff --git a/sound/Makefile b/sound/Makefile
index 1f60797afa8a..5f6bef57e825 100644
--- a/sound/Makefile
+++ b/sound/Makefile
@@ -2,6 +2,7 @@
#
obj-$(CONFIG_SOUND) += soundcore.o
+obj-$(CONFIG_SOUND_PRIME) += sound_firmware.o
obj-$(CONFIG_SOUND_PRIME) += oss/
obj-$(CONFIG_DMASOUND) += oss/
obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ mips/
@@ -11,4 +12,4 @@ ifeq ($(CONFIG_SND),y)
obj-y += last.o
endif
-soundcore-objs := sound_core.o sound_firmware.o
+soundcore-objs := sound_core.o
diff --git a/sound/aoa/core/snd-aoa-gpio-feature.c b/sound/aoa/core/snd-aoa-gpio-feature.c
index 7c26089527f6..40eb47eccf9a 100644
--- a/sound/aoa/core/snd-aoa-gpio-feature.c
+++ b/sound/aoa/core/snd-aoa-gpio-feature.c
@@ -283,9 +283,7 @@ static void ftr_gpio_exit(struct gpio_runtime *rt)
mutex_destroy(&rt->line_out_notify.mutex);
}
-static irqreturn_t ftr_handle_notify_irq(int xx,
- void *data,
- struct pt_regs *regs)
+static irqreturn_t ftr_handle_notify_irq(int xx, void *data)
{
struct gpio_notification *notif = data;
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-core.c b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
index 23190aa6bc7b..e593a1333fe3 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-core.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-core.c
@@ -93,7 +93,7 @@ static void i2sbus_release_dev(struct device *dev)
kfree(i2sdev);
}
-static irqreturn_t i2sbus_bus_intr(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t i2sbus_bus_intr(int irq, void *devid)
{
struct i2sbus_dev *dev = devid;
u32 intreg;
@@ -165,8 +165,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
static const char *rnames[] = { "i2sbus: %s (control)",
"i2sbus: %s (tx)",
"i2sbus: %s (rx)" };
- static irqreturn_t (*ints[])(int irq, void *devid,
- struct pt_regs *regs) = {
+ static irq_handler_t ints[] = {
i2sbus_bus_intr,
i2sbus_tx_intr,
i2sbus_rx_intr
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
index 3049015a04f1..5eff30b10201 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
+++ b/sound/aoa/soundbus/i2sbus/i2sbus-pcm.c
@@ -642,13 +642,13 @@ static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in)
spin_unlock(&i2sdev->low_lock);
}
-irqreturn_t i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs)
+irqreturn_t i2sbus_tx_intr(int irq, void *devid)
{
handle_interrupt((struct i2sbus_dev *)devid, 0);
return IRQ_HANDLED;
}
-irqreturn_t i2sbus_rx_intr(int irq, void *devid, struct pt_regs * regs)
+irqreturn_t i2sbus_rx_intr(int irq, void *devid)
{
handle_interrupt((struct i2sbus_dev *)devid, 1);
return IRQ_HANDLED;
diff --git a/sound/aoa/soundbus/i2sbus/i2sbus.h b/sound/aoa/soundbus/i2sbus/i2sbus.h
index 0c69d209be50..ec20ee615d7f 100644
--- a/sound/aoa/soundbus/i2sbus/i2sbus.h
+++ b/sound/aoa/soundbus/i2sbus/i2sbus.h
@@ -97,9 +97,9 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
extern void
i2sbus_detach_codec(struct soundbus_dev *dev, void *data);
extern irqreturn_t
-i2sbus_tx_intr(int irq, void *devid, struct pt_regs *regs);
+i2sbus_tx_intr(int irq, void *devid);
extern irqreturn_t
-i2sbus_rx_intr(int irq, void *devid, struct pt_regs *regs);
+i2sbus_rx_intr(int irq, void *devid);
/* control specific functions */
extern int i2sbus_control_init(struct macio_dev* dev,
diff --git a/sound/aoa/soundbus/sysfs.c b/sound/aoa/soundbus/sysfs.c
index d31f8146952a..f580942b5c09 100644
--- a/sound/aoa/soundbus/sysfs.c
+++ b/sound/aoa/soundbus/sysfs.c
@@ -1,4 +1,3 @@
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/stat.h>
/* FIX UP */
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 8435fdd1c87c..53675cf4de44 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -221,7 +221,7 @@ static void aaci_fifo_irq(struct aaci *aaci, u32 mask)
}
}
-static irqreturn_t aaci_irq(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t aaci_irq(int irq, void *devid)
{
struct aaci *aaci = devid;
u32 mask;
diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c
index 599aff8290e8..dede954b2c65 100644
--- a/sound/arm/pxa2xx-ac97.c
+++ b/sound/arm/pxa2xx-ac97.c
@@ -152,7 +152,7 @@ static void pxa2xx_ac97_reset(struct snd_ac97 *ac97)
GCR |= GCR_SDONE_IE|GCR_CDONE_IE;
}
-static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t pxa2xx_ac97_irq(int irq, void *dev_id)
{
long status;
diff --git a/sound/arm/pxa2xx-pcm.c b/sound/arm/pxa2xx-pcm.c
index 4938ef10b813..e8cf904b8358 100644
--- a/sound/arm/pxa2xx-pcm.c
+++ b/sound/arm/pxa2xx-pcm.c
@@ -137,7 +137,7 @@ static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
return ret;
}
-static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id, struct pt_regs *regs)
+static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
{
struct snd_pcm_substream *substream = dev_id;
struct pxa2xx_runtime_data *rtd = substream->runtime->private_data;
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c
index 9aa9d94891f0..46b47689362c 100644
--- a/sound/core/hwdep.c
+++ b/sound/core/hwdep.c
@@ -158,6 +158,7 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
{
int err = -ENXIO;
struct snd_hwdep *hw = file->private_data;
+ struct module *mod = hw->card->module;
mutex_lock(&hw->open_mutex);
if (hw->ops.release) {
err = hw->ops.release(hw, file);
@@ -167,7 +168,7 @@ static int snd_hwdep_release(struct inode *inode, struct file * file)
hw->used--;
snd_card_file_remove(hw->card, file);
mutex_unlock(&hw->open_mutex);
- module_put(hw->card->module);
+ module_put(mod);
return err;
}
diff --git a/sound/core/hwdep_compat.c b/sound/core/hwdep_compat.c
index 938f77580966..3827c0ceec8f 100644
--- a/sound/core/hwdep_compat.c
+++ b/sound/core/hwdep_compat.c
@@ -33,7 +33,7 @@ struct snd_hwdep_dsp_image32 {
static int snd_hwdep_dsp_load_compat(struct snd_hwdep *hw,
struct snd_hwdep_dsp_image32 __user *src)
{
- struct snd_hwdep_dsp_image *dst;
+ struct snd_hwdep_dsp_image __user *dst;
compat_caddr_t ptr;
u32 val;
diff --git a/sound/core/info_oss.c b/sound/core/info_oss.c
index 3ebc34919c76..a444bfe2cf74 100644
--- a/sound/core/info_oss.c
+++ b/sound/core/info_oss.c
@@ -96,11 +96,11 @@ static void snd_sndstat_proc_read(struct snd_info_entry *entry,
{
snd_iprintf(buffer, "Sound Driver:3.8.1a-980706 (ALSA v" CONFIG_SND_VERSION " emulation code)\n");
snd_iprintf(buffer, "Kernel: %s %s %s %s %s\n",
- system_utsname.sysname,
- system_utsname.nodename,
- system_utsname.release,
- system_utsname.version,
- system_utsname.machine);
+ init_utsname()->sysname,
+ init_utsname()->nodename,
+ init_utsname()->release,
+ init_utsname()->version,
+ init_utsname()->machine);
snd_iprintf(buffer, "Config options: 0\n");
snd_iprintf(buffer, "\nInstalled drivers: \n");
snd_iprintf(buffer, "Type 10: ALSA emulation\n");
diff --git a/sound/core/init.c b/sound/core/init.c
index d7607a25acdf..3058d626a90a 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -33,10 +33,10 @@
#include <sound/control.h>
#include <sound/info.h>
-struct snd_shutdown_f_ops {
- struct file_operations f_ops;
- struct snd_shutdown_f_ops *next;
-};
+static DEFINE_SPINLOCK(shutdown_lock);
+static LIST_HEAD(shutdown_files);
+
+static struct file_operations snd_shutdown_f_ops;
static unsigned int snd_cards_lock; /* locked for registering/using */
struct snd_card *snd_cards[SNDRV_CARDS];
@@ -198,6 +198,25 @@ static ssize_t snd_disconnect_write(struct file *file, const char __user *buf,
return -ENODEV;
}
+static int snd_disconnect_release(struct inode *inode, struct file *file)
+{
+ struct snd_monitor_file *df = NULL, *_df;
+
+ spin_lock(&shutdown_lock);
+ list_for_each_entry(_df, &shutdown_files, shutdown_list) {
+ if (_df->file == file) {
+ df = _df;
+ break;
+ }
+ }
+ spin_unlock(&shutdown_lock);
+
+ if (likely(df))
+ return df->disconnected_f_op->release(inode, file);
+
+ panic("%s(%p, %p) failed!", __FUNCTION__, inode, file);
+}
+
static unsigned int snd_disconnect_poll(struct file * file, poll_table * wait)
{
return POLLERR | POLLNVAL;
@@ -219,6 +238,22 @@ static int snd_disconnect_fasync(int fd, struct file *file, int on)
return -ENODEV;
}
+static struct file_operations snd_shutdown_f_ops =
+{
+ .owner = THIS_MODULE,
+ .llseek = snd_disconnect_llseek,
+ .read = snd_disconnect_read,
+ .write = snd_disconnect_write,
+ .release = snd_disconnect_release,
+ .poll = snd_disconnect_poll,
+ .unlocked_ioctl = snd_disconnect_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = snd_disconnect_ioctl,
+#endif
+ .mmap = snd_disconnect_mmap,
+ .fasync = snd_disconnect_fasync
+};
+
/**
* snd_card_disconnect - disconnect all APIs from the file-operations (user space)
* @card: soundcard structure
@@ -234,9 +269,6 @@ int snd_card_disconnect(struct snd_card *card)
{
struct snd_monitor_file *mfile;
struct file *file;
- struct snd_shutdown_f_ops *s_f_ops;
- struct file_operations *f_ops;
- const struct file_operations *old_f_ops;
int err;
spin_lock(&card->files_lock);
@@ -261,34 +293,14 @@ int snd_card_disconnect(struct snd_card *card)
/* it's critical part, use endless loop */
/* we have no room to fail */
- s_f_ops = kmalloc(sizeof(struct snd_shutdown_f_ops), GFP_ATOMIC);
- if (s_f_ops == NULL)
- panic("Atomic allocation failed for snd_shutdown_f_ops!");
-
- f_ops = &s_f_ops->f_ops;
-
- memset(f_ops, 0, sizeof(*f_ops));
- f_ops->owner = file->f_op->owner;
- f_ops->release = file->f_op->release;
- f_ops->llseek = snd_disconnect_llseek;
- f_ops->read = snd_disconnect_read;
- f_ops->write = snd_disconnect_write;
- f_ops->poll = snd_disconnect_poll;
- f_ops->unlocked_ioctl = snd_disconnect_ioctl;
-#ifdef CONFIG_COMPAT
- f_ops->compat_ioctl = snd_disconnect_ioctl;
-#endif
- f_ops->mmap = snd_disconnect_mmap;
- f_ops->fasync = snd_disconnect_fasync;
+ mfile->disconnected_f_op = mfile->file->f_op;
- s_f_ops->next = card->s_f_ops;
- card->s_f_ops = s_f_ops;
-
- f_ops = fops_get(f_ops);
+ spin_lock(&shutdown_lock);
+ list_add(&mfile->shutdown_list, &shutdown_files);
+ spin_unlock(&shutdown_lock);
- old_f_ops = file->f_op;
- file->f_op = f_ops; /* must be atomic */
- fops_put(old_f_ops);
+ fops_get(&snd_shutdown_f_ops);
+ mfile->file->f_op = &snd_shutdown_f_ops;
mfile = mfile->next;
}
@@ -326,8 +338,6 @@ EXPORT_SYMBOL(snd_card_disconnect);
*/
static int snd_card_do_free(struct snd_card *card)
{
- struct snd_shutdown_f_ops *s_f_ops;
-
#if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
if (snd_mixer_oss_notify_callback)
snd_mixer_oss_notify_callback(card, SND_MIXER_OSS_NOTIFY_FREE);
@@ -351,11 +361,6 @@ static int snd_card_do_free(struct snd_card *card)
snd_printk(KERN_WARNING "unable to free card info\n");
/* Not fatal error */
}
- while (card->s_f_ops) {
- s_f_ops = card->s_f_ops;
- card->s_f_ops = s_f_ops->next;
- kfree(s_f_ops);
- }
kfree(card);
return 0;
}
@@ -670,6 +675,7 @@ int snd_card_file_add(struct snd_card *card, struct file *file)
if (mfile == NULL)
return -ENOMEM;
mfile->file = file;
+ mfile->disconnected_f_op = NULL;
mfile->next = NULL;
spin_lock(&card->files_lock);
if (card->shutdown) {
@@ -716,6 +722,12 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
pfile = mfile;
mfile = mfile->next;
}
+ if (mfile && mfile->disconnected_f_op) {
+ fops_put(mfile->disconnected_f_op);
+ spin_lock(&shutdown_lock);
+ list_del(&mfile->shutdown_list);
+ spin_unlock(&shutdown_lock);
+ }
if (card->files == NULL)
last_close = 1;
spin_unlock(&card->files_lock);
diff --git a/sound/core/memory.c b/sound/core/memory.c
index fe59850be868..93537ab7c2ac 100644
--- a/sound/core/memory.c
+++ b/sound/core/memory.c
@@ -20,7 +20,6 @@
*
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <asm/io.h>
#include <asm/uaccess.h>
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index bf8f412988b8..fbbbcd20c4cc 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -629,6 +629,9 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
substream->number = idx;
substream->stream = stream;
sprintf(substream->name, "subdevice #%i", idx);
+ snprintf(substream->latency_id, sizeof(substream->latency_id),
+ "ALSA-PCM%d-%d%c%d", pcm->card->number, pcm->device,
+ (stream ? 'c' : 'p'), idx);
substream->buffer_bytes_max = UINT_MAX;
if (prev == NULL)
pstr->substream = substream;
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 0224c70414f5..37b4b10850ae 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -25,6 +25,7 @@
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/time.h>
+#include <linux/latency.h>
#include <linux/uio.h>
#include <sound/core.h>
#include <sound/control.h>
@@ -347,11 +348,26 @@ out:
return err;
}
+static int period_to_usecs(struct snd_pcm_runtime *runtime)
+{
+ int usecs;
+
+ if (! runtime->rate)
+ return -1; /* invalid */
+
+ /* take 75% of period time as the deadline */
+ usecs = (750000 / runtime->rate) * runtime->period_size;
+ usecs += ((750000 % runtime->rate) * runtime->period_size) /
+ runtime->rate;
+
+ return usecs;
+}
+
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime;
- int err;
+ int err, usecs;
unsigned int bits;
snd_pcm_uframes_t frames;
@@ -431,6 +447,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
snd_pcm_timer_resolution_change(substream);
runtime->status->state = SNDRV_PCM_STATE_SETUP;
+
+ remove_acceptable_latency(substream->latency_id);
+ if ((usecs = period_to_usecs(runtime)) >= 0)
+ set_acceptable_latency(substream->latency_id, usecs);
return 0;
_error:
/* hardware might be unuseable from this time,
@@ -490,6 +510,7 @@ static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
if (substream->ops->hw_free)
result = substream->ops->hw_free(substream);
runtime->status->state = SNDRV_PCM_STATE_OPEN;
+ remove_acceptable_latency(substream->latency_id);
return result;
}
@@ -2831,8 +2852,8 @@ static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
return result;
}
-static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector,
- unsigned long count, loff_t * offset)
+static ssize_t snd_pcm_aio_read(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct snd_pcm_file *pcm_file;
@@ -2843,22 +2864,22 @@ static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector,
void __user **bufs;
snd_pcm_uframes_t frames;
- pcm_file = file->private_data;
+ pcm_file = iocb->ki_filp->private_data;
substream = pcm_file->substream;
snd_assert(substream != NULL, return -ENXIO);
runtime = substream->runtime;
if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
- if (count > 1024 || count != runtime->channels)
+ if (nr_segs > 1024 || nr_segs != runtime->channels)
return -EINVAL;
- if (!frame_aligned(runtime, _vector->iov_len))
+ if (!frame_aligned(runtime, iov->iov_len))
return -EINVAL;
- frames = bytes_to_samples(runtime, _vector->iov_len);
- bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
+ frames = bytes_to_samples(runtime, iov->iov_len);
+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
if (bufs == NULL)
return -ENOMEM;
- for (i = 0; i < count; ++i)
- bufs[i] = _vector[i].iov_base;
+ for (i = 0; i < nr_segs; ++i)
+ bufs[i] = iov[i].iov_base;
result = snd_pcm_lib_readv(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
@@ -2866,8 +2887,8 @@ static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector,
return result;
}
-static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector,
- unsigned long count, loff_t * offset)
+static ssize_t snd_pcm_aio_write(struct kiocb *iocb, const struct iovec *iov,
+ unsigned long nr_segs, loff_t pos)
{
struct snd_pcm_file *pcm_file;
struct snd_pcm_substream *substream;
@@ -2877,7 +2898,7 @@ static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector,
void __user **bufs;
snd_pcm_uframes_t frames;
- pcm_file = file->private_data;
+ pcm_file = iocb->ki_filp->private_data;
substream = pcm_file->substream;
snd_assert(substream != NULL, result = -ENXIO; goto end);
runtime = substream->runtime;
@@ -2885,17 +2906,17 @@ static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector,
result = -EBADFD;
goto end;
}
- if (count > 128 || count != runtime->channels ||
- !frame_aligned(runtime, _vector->iov_len)) {
+ if (nr_segs > 128 || nr_segs != runtime->channels ||
+ !frame_aligned(runtime, iov->iov_len)) {
result = -EINVAL;
goto end;
}
- frames = bytes_to_samples(runtime, _vector->iov_len);
- bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL);
+ frames = bytes_to_samples(runtime, iov->iov_len);
+ bufs = kmalloc(sizeof(void *) * nr_segs, GFP_KERNEL);
if (bufs == NULL)
return -ENOMEM;
- for (i = 0; i < count; ++i)
- bufs[i] = _vector[i].iov_base;
+ for (i = 0; i < nr_segs; ++i)
+ bufs[i] = iov[i].iov_base;
result = snd_pcm_lib_writev(substream, bufs, frames);
if (result > 0)
result = frames_to_bytes(runtime, result);
@@ -3405,7 +3426,7 @@ struct file_operations snd_pcm_f_ops[2] = {
{
.owner = THIS_MODULE,
.write = snd_pcm_write,
- .writev = snd_pcm_writev,
+ .aio_write = snd_pcm_aio_write,
.open = snd_pcm_playback_open,
.release = snd_pcm_release,
.poll = snd_pcm_playback_poll,
@@ -3417,7 +3438,7 @@ struct file_operations snd_pcm_f_ops[2] = {
{
.owner = THIS_MODULE,
.read = snd_pcm_read,
- .readv = snd_pcm_readv,
+ .aio_read = snd_pcm_aio_read,
.open = snd_pcm_capture_open,
.release = snd_pcm_release,
.poll = snd_pcm_capture_poll,
diff --git a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c
index 4bf07ca9b17d..3daa9fa56c0b 100644
--- a/sound/drivers/mpu401/mpu401_uart.c
+++ b/sound/drivers/mpu401/mpu401_uart.c
@@ -125,12 +125,10 @@ static void _snd_mpu401_uart_interrupt(struct snd_mpu401 *mpu)
* snd_mpu401_uart_interrupt - generic MPU401-UART interrupt handler
* @irq: the irq number
* @dev_id: mpu401 instance
- * @regs: the reigster
*
* Processes the interrupt for MPU401-UART i/o.
*/
-irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+irqreturn_t snd_mpu401_uart_interrupt(int irq, void *dev_id)
{
struct snd_mpu401 *mpu = dev_id;
@@ -146,12 +144,10 @@ EXPORT_SYMBOL(snd_mpu401_uart_interrupt);
* snd_mpu401_uart_interrupt_tx - generic MPU401-UART transmit irq handler
* @irq: the irq number
* @dev_id: mpu401 instance
- * @regs: the reigster
*
* Processes the interrupt for MPU401-UART output.
*/
-irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id,
- struct pt_regs *regs)
+irqreturn_t snd_mpu401_uart_interrupt_tx(int irq, void *dev_id)
{
struct snd_mpu401 *mpu = dev_id;
diff --git a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
index e064d6c5685b..a9ff391258e7 100644
--- a/sound/drivers/mtpav.c
+++ b/sound/drivers/mtpav.c
@@ -570,7 +570,7 @@ static void snd_mtpav_read_bytes(struct mtpav *mcrd)
} while (sbyt & SIGS_BYTE);
}
-static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
{
struct mtpav *mcard = dev_id;
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index ab8d4effcf9e..5327c6f841f4 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -838,7 +838,7 @@ static int __devinit snd_mts64_rawmidi_create(struct snd_card *card)
/*********************************************************************
* parport stuff
*********************************************************************/
-static void snd_mts64_interrupt(int irq, void *private, struct pt_regs *r)
+static void snd_mts64_interrupt(int irq, void *private)
{
struct mts64 *mts = ((struct snd_card*)private)->private_data;
u16 ret;
diff --git a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
index 52afb4bd2079..74028b2219c2 100644
--- a/sound/drivers/serial-u16550.c
+++ b/sound/drivers/serial-u16550.c
@@ -292,7 +292,7 @@ static void snd_uart16550_io_loop(snd_uart16550_t * uart)
* Note that some devices need OUT2 to be set before they will generate
* interrupts at all. (Possibly tied to an internal pull-up on CTS?)
*/
-static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_uart16550_interrupt(int irq, void *dev_id)
{
snd_uart16550_t *uart;
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index a60168268ddd..ed19bc17400b 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -537,7 +537,7 @@ static void vx_interrupt(unsigned long private_data)
/**
* snd_vx_irq_handler - interrupt handler
*/
-irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs)
+irqreturn_t snd_vx_irq_handler(int irq, void *dev)
{
struct vx_core *chip = dev;
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index fd9b61eda0f3..b524e0d9ee44 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -315,7 +315,7 @@ static snd_pcm_uframes_t snd_ad1816a_capture_pointer(struct snd_pcm_substream *s
}
-static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_ad1816a_interrupt(int irq, void *dev_id)
{
struct snd_ad1816a *chip = dev_id;
unsigned char status;
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index a6fbd5d1d62f..666b3bcc19f0 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -583,7 +583,7 @@ static int snd_ad1848_capture_prepare(struct snd_pcm_substream *substream)
return 0;
}
-static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_ad1848_interrupt(int irq, void *dev_id)
{
struct snd_ad1848 *chip = dev_id;
diff --git a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
index fbb20176cca4..75c7c5f01989 100644
--- a/sound/isa/cs423x/cs4231_lib.c
+++ b/sound/isa/cs423x/cs4231_lib.c
@@ -920,7 +920,7 @@ static void snd_cs4231_overrange(struct snd_cs4231 *chip)
chip->capture_substream->runtime->overrange++;
}
-irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_cs4231_interrupt(int irq, void *dev_id)
{
struct snd_cs4231 *chip = dev_id;
unsigned char status;
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index 7e985d3bc510..a2ab99f2ac35 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -479,7 +479,7 @@ static int snd_es1688_capture_trigger(struct snd_pcm_substream *substream,
return snd_es1688_trigger(chip, cmd, 0x0f);
}
-static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es1688_interrupt(int irq, void *dev_id)
{
struct snd_es1688 *chip = dev_id;
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 85818200333f..725c115ff97d 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -754,7 +754,7 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream,
return snd_es18xx_playback2_trigger(chip, substream, cmd);
}
-static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id)
{
struct snd_es18xx *chip = dev_id;
unsigned char status;
@@ -799,7 +799,7 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id, struct pt_regs *r
/* MPU */
if ((status & MPU_IRQ) && chip->rmidi)
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
/* Hardware volume */
if (status & HWV_IRQ) {
@@ -2154,6 +2154,7 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard,
}
/* Control port initialization */
if (pnp_activate_dev(acard->devc) < 0) {
+ kfree(cfg);
snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n");
return -EAGAIN;
}
diff --git a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c
index 42db37552efb..537d3cfe41f3 100644
--- a/sound/isa/gus/gus_irq.c
+++ b/sound/isa/gus/gus_irq.c
@@ -30,7 +30,7 @@
#define STAT_ADD(x) while (0) { ; }
#endif
-irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_gus_interrupt(int irq, void *dev_id)
{
struct snd_gus_card * gus = dev_id;
unsigned char status;
diff --git a/sound/isa/gus/gusmax.c b/sound/isa/gus/gusmax.c
index ac11cae8589a..c1c69e3cbfd0 100644
--- a/sound/isa/gus/gusmax.c
+++ b/sound/isa/gus/gusmax.c
@@ -105,9 +105,9 @@ static int __init snd_gusmax_detect(struct snd_gus_card * gus)
return 0;
}
-static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id)
{
- struct snd_gusmax *maxcard = (struct snd_gusmax *) dev_id;
+ struct snd_gusmax *maxcard = dev_id;
int loop, max = 5;
int handled = 0;
@@ -115,12 +115,12 @@ static irqreturn_t snd_gusmax_interrupt(int irq, void *dev_id, struct pt_regs *r
loop = 0;
if (inb(maxcard->gus_status_reg)) {
handled = 1;
- snd_gus_interrupt(irq, maxcard->gus, regs);
+ snd_gus_interrupt(irq, maxcard->gus);
loop++;
}
if (inb(maxcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
handled = 1;
- snd_cs4231_interrupt(irq, maxcard->cs4231, regs);
+ snd_cs4231_interrupt(irq, maxcard->cs4231);
loop++;
}
} while (loop && --max > 0);
diff --git a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c
index ea69f25506fb..f12cd09d1fcc 100644
--- a/sound/isa/gus/interwave.c
+++ b/sound/isa/gus/interwave.c
@@ -299,9 +299,9 @@ static int __devinit snd_interwave_detect(struct snd_interwave *iwcard,
return -ENODEV;
}
-static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id)
{
- struct snd_interwave *iwcard = (struct snd_interwave *) dev_id;
+ struct snd_interwave *iwcard = dev_id;
int loop, max = 5;
int handled = 0;
@@ -309,12 +309,12 @@ static irqreturn_t snd_interwave_interrupt(int irq, void *dev_id, struct pt_regs
loop = 0;
if (inb(iwcard->gus_status_reg)) {
handled = 1;
- snd_gus_interrupt(irq, iwcard->gus, regs);
+ snd_gus_interrupt(irq, iwcard->gus);
loop++;
}
if (inb(iwcard->pcm_status_reg) & 0x01) { /* IRQ bit is set? */
handled = 1;
- snd_cs4231_interrupt(irq, iwcard->cs4231, regs);
+ snd_cs4231_interrupt(irq, iwcard->cs4231);
loop++;
}
} while (loop && --max > 0);
diff --git a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c
index da92bf6c392b..419b4ebbf00e 100644
--- a/sound/isa/opl3sa2.c
+++ b/sound/isa/opl3sa2.c
@@ -294,7 +294,7 @@ static int __devinit snd_opl3sa2_detect(struct snd_opl3sa2 *chip)
return 0;
}
-static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id)
{
unsigned short status;
struct snd_opl3sa2 *chip = dev_id;
@@ -312,12 +312,12 @@ static irqreturn_t snd_opl3sa2_interrupt(int irq, void *dev_id, struct pt_regs *
if ((status & 0x10) && chip->rmidi != NULL) {
handled = 1;
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
}
if (status & 0x07) { /* TI,CI,PI */
handled = 1;
- snd_cs4231_interrupt(irq, chip->cs4231, regs);
+ snd_cs4231_interrupt(irq, chip->cs4231);
}
if (status & 0x40) { /* hardware volume change */
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 9d528ae00bff..a1ad39a8cdce 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -1090,7 +1090,7 @@ static void snd_opti93x_overrange(struct snd_opti93x *chip)
spin_unlock_irqrestore(&chip->lock, flags);
}
-static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id)
{
struct snd_opti93x *codec = dev_id;
unsigned char status;
diff --git a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c
index d4d65b84265a..d4b218726ce7 100644
--- a/sound/isa/sb/es968.c
+++ b/sound/isa/sb/es968.c
@@ -70,8 +70,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_es968_pnpids);
#define DRIVER_NAME "snd-card-es968"
-static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id)
{
struct snd_sb *chip = dev_id;
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index f183f1845a36..383911b9e74d 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -395,7 +395,7 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream,
return result;
}
-irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id)
{
struct snd_sb *chip = dev_id;
unsigned char status;
@@ -405,7 +405,7 @@ irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS);
spin_unlock(&chip->mixer_lock);
if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback)
- chip->rmidi_callback(irq, chip->rmidi->private_data, regs);
+ chip->rmidi_callback(irq, chip->rmidi->private_data);
if (status & SB_IRQTYPE_8BIT) {
ok = 0;
if (chip->mode & SB_MODE_PLAYBACK_8) {
diff --git a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c
index 141400c01426..268ebd34703e 100644
--- a/sound/isa/sb/sb8.c
+++ b/sound/isa/sb/sb8.c
@@ -63,7 +63,7 @@ struct snd_sb8 {
struct snd_sb *chip;
};
-static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_sb8_interrupt(int irq, void *dev_id)
{
struct snd_sb *chip = dev_id;
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index f17de2bdd9e0..c62a9e3d2ae4 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -205,7 +205,7 @@ static int snd_sbdsp_dev_free(struct snd_device *device)
int snd_sbdsp_create(struct snd_card *card,
unsigned long port,
int irq,
- irqreturn_t (*irq_handler)(int, void *, struct pt_regs *),
+ irq_handler_t irq_handler,
int dma8,
int dma16,
unsigned short hardware,
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index 8742fa517491..4fcd0f4e868c 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -109,7 +109,7 @@ static int __init snd_sgalaxy_sbdsp_command(unsigned long port, unsigned char va
return 0;
}
-static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_sgalaxy_dummy_interrupt(int irq, void *dev_id)
{
return IRQ_NONE;
}
diff --git a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c
index a8f8d2fa9d76..85db535aea9b 100644
--- a/sound/isa/wavefront/wavefront.c
+++ b/sound/isa/wavefront/wavefront.c
@@ -263,9 +263,7 @@ snd_wavefront_pnp (int dev, snd_wavefront_card_t *acard, struct pnp_card_link *c
#endif /* CONFIG_PNP */
-static irqreturn_t snd_wavefront_ics2115_interrupt(int irq,
- void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_wavefront_ics2115_interrupt(int irq, void *dev_id)
{
snd_wavefront_card_t *acard;
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c
index c31b38659221..8a61a1191861 100644
--- a/sound/mips/au1x00.c
+++ b/sound/mips/au1x00.c
@@ -220,7 +220,7 @@ au1000_dma_start(struct audio_stream *stream)
}
static irqreturn_t
-au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+au1000_dma_interrupt(int irq, void *dev_id)
{
struct audio_stream *stream = (struct audio_stream *) dev_id;
struct snd_pcm_substream *substream = stream->substream;
@@ -258,7 +258,7 @@ au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static unsigned int rates[] = {8000, 11025, 16000, 22050};
static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
- .count = sizeof(rates) / sizeof(rates[0]),
+ .count = ARRAY_SIZE(rates),
.list = rates,
.mask = 0,
};
diff --git a/sound/oss/COPYING b/sound/oss/COPYING
deleted file mode 100644
index 916d1f0f2842..000000000000
--- a/sound/oss/COPYING
+++ /dev/null
@@ -1,339 +0,0 @@
- GNU GENERAL PUBLIC LICENSE
- Version 2, June 1991
-
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- Everyone is permitted to copy and distribute verbatim copies
- of this license document, but changing it is not allowed.
-
- Preamble
-
- The licenses for most software are designed to take away your
-freedom to share and change it. By contrast, the GNU General Public
-License is intended to guarantee your freedom to share and change free
-software--to make sure the software is free for all its users. This
-General Public License applies to most of the Free Software
-Foundation's software and to any other program whose authors commit to
-using it. (Some other Free Software Foundation software is covered by
-the GNU Library General Public License instead.) You can apply it to
-your programs, too.
-
- When we speak of free software, we are referring to freedom, not
-price. Our General Public Licenses are designed to make sure that you
-have the freedom to distribute copies of free software (and charge for
-this service if you wish), that you receive source code or can get it
-if you want it, that you can change the software or use pieces of it
-in new free programs; and that you know you can do these things.
-
- To protect your rights, we need to make restrictions that forbid
-anyone to deny you these rights or to ask you to surrender the rights.
-These restrictions translate to certain responsibilities for you if you
-distribute copies of the software, or if you modify it.
-
- For example, if you distribute copies of such a program, whether
-gratis or for a fee, you must give the recipients all the rights that
-you have. You must make sure that they, too, receive or can get the
-source code. And you must show them these terms so they know their
-rights.
-
- We protect your rights with two steps: (1) copyright the software, and
-(2) offer you this license which gives you legal permission to copy,
-distribute and/or modify the software.
-
- Also, for each author's protection and ours, we want to make certain
-that everyone understands that there is no warranty for this free
-software. If the software is modified by someone else and passed on, we
-want its recipients to know that what they have is not the original, so
-that any problems introduced by others will not reflect on the original
-authors' reputations.
-
- Finally, any free program is threatened constantly by software
-patents. We wish to avoid the danger that redistributors of a free
-program will individually obtain patent licenses, in effect making the
-program proprietary. To prevent this, we have made it clear that any
-patent must be licensed for everyone's free use or not licensed at all.
-
- The precise terms and conditions for copying, distribution and
-modification follow.
-
- GNU GENERAL PUBLIC LICENSE
- TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
-
- 0. This License applies to any program or other work which contains
-a notice placed by the copyright holder saying it may be distributed
-under the terms of this General Public License. The "Program", below,
-refers to any such program or work, and a "work based on the Program"
-means either the Program or any derivative work under copyright law:
-that is to say, a work containing the Program or a portion of it,
-either verbatim or with modifications and/or translated into another
-language. (Hereinafter, translation is included without limitation in
-the term "modification".) Each licensee is addressed as "you".
-
-Activities other than copying, distribution and modification are not
-covered by this License; they are outside its scope. The act of
-running the Program is not restricted, and the output from the Program
-is covered only if its contents constitute a work based on the
-Program (independent of having been made by running the Program).
-Whether that is true depends on what the Program does.
-
- 1. You may copy and distribute verbatim copies of the Program's
-source code as you receive it, in any medium, provided that you
-conspicuously and appropriately publish on each copy an appropriate
-copyright notice and disclaimer of warranty; keep intact all the
-notices that refer to this License and to the absence of any warranty;
-and give any other recipients of the Program a copy of this License
-along with the Program.
-
-You may charge a fee for the physical act of transferring a copy, and
-you may at your option offer warranty protection in exchange for a fee.
-
- 2. You may modify your copy or copies of the Program or any portion
-of it, thus forming a work based on the Program, and copy and
-distribute such modifications or work under the terms of Section 1
-above, provided that you also meet all of these conditions:
-
- a) You must cause the modified files to carry prominent notices
- stating that you changed the files and the date of any change.
-
- b) You must cause any work that you distribute or publish, that in
- whole or in part contains or is derived from the Program or any
- part thereof, to be licensed as a whole at no charge to all third
- parties under the terms of this License.
-
- c) If the modified program normally reads commands interactively
- when run, you must cause it, when started running for such
- interactive use in the most ordinary way, to print or display an
- announcement including an appropriate copyright notice and a
- notice that there is no warranty (or else, saying that you provide
- a warranty) and that users may redistribute the program under
- these conditions, and telling the user how to view a copy of this
- License. (Exception: if the Program itself is interactive but
- does not normally print such an announcement, your work based on
- the Program is not required to print an announcement.)
-
-These requirements apply to the modified work as a whole. If
-identifiable sections of that work are not derived from the Program,
-and can be reasonably considered independent and separate works in
-themselves, then this License, and its terms, do not apply to those
-sections when you distribute them as separate works. But when you
-distribute the same sections as part of a whole which is a work based
-on the Program, the distribution of the whole must be on the terms of
-this License, whose permissions for other licensees extend to the
-entire whole, and thus to each and every part regardless of who wrote it.
-
-Thus, it is not the intent of this section to claim rights or contest
-your rights to work written entirely by you; rather, the intent is to
-exercise the right to control the distribution of derivative or
-collective works based on the Program.
-
-In addition, mere aggregation of another work not based on the Program
-with the Program (or with a work based on the Program) on a volume of
-a storage or distribution medium does not bring the other work under
-the scope of this License.
-
- 3. You may copy and distribute the Program (or a work based on it,
-under Section 2) in object code or executable form under the terms of
-Sections 1 and 2 above provided that you also do one of the following:
-
- a) Accompany it with the complete corresponding machine-readable
- source code, which must be distributed under the terms of Sections
- 1 and 2 above on a medium customarily used for software interchange; or,
-
- b) Accompany it with a written offer, valid for at least three
- years, to give any third party, for a charge no more than your
- cost of physically performing source distribution, a complete
- machine-readable copy of the corresponding source code, to be
- distributed under the terms of Sections 1 and 2 above on a medium
- customarily used for software interchange; or,
-
- c) Accompany it with the information you received as to the offer
- to distribute corresponding source code. (This alternative is
- allowed only for noncommercial distribution and only if you
- received the program in object code or executable form with such
- an offer, in accord with Subsection b above.)
-
-The source code for a work means the preferred form of the work for
-making modifications to it. For an executable work, complete source
-code means all the source code for all modules it contains, plus any
-associated interface definition files, plus the scripts used to
-control compilation and installation of the executable. However, as a
-special exception, the source code distributed need not include
-anything that is normally distributed (in either source or binary
-form) with the major components (compiler, kernel, and so on) of the
-operating system on which the executable runs, unless that component
-itself accompanies the executable.
-
-If distribution of executable or object code is made by offering
-access to copy from a designated place, then offering equivalent
-access to copy the source code from the same place counts as
-distribution of the source code, even though third parties are not
-compelled to copy the source along with the object code.
-
- 4. You may not copy, modify, sublicense, or distribute the Program
-except as expressly provided under this License. Any attempt
-otherwise to copy, modify, sublicense or distribute the Program is
-void, and will automatically terminate your rights under this License.
-However, parties who have received copies, or rights, from you under
-this License will not have their licenses terminated so long as such
-parties remain in full compliance.
-
- 5. You are not required to accept this License, since you have not
-signed it. However, nothing else grants you permission to modify or
-distribute the Program or its derivative works. These actions are
-prohibited by law if you do not accept this License. Therefore, by
-modifying or distributing the Program (or any work based on the
-Program), you indicate your acceptance of this License to do so, and
-all its terms and conditions for copying, distributing or modifying
-the Program or works based on it.
-
- 6. Each time you redistribute the Program (or any work based on the
-Program), the recipient automatically receives a license from the
-original licensor to copy, distribute or modify the Program subject to
-these terms and conditions. You may not impose any further
-restrictions on the recipients' exercise of the rights granted herein.
-You are not responsible for enforcing compliance by third parties to
-this License.
-
- 7. If, as a consequence of a court judgment or allegation of patent
-infringement or for any other reason (not limited to patent issues),
-conditions are imposed on you (whether by court order, agreement or
-otherwise) that contradict the conditions of this License, they do not
-excuse you from the conditions of this License. If you cannot
-distribute so as to satisfy simultaneously your obligations under this
-License and any other pertinent obligations, then as a consequence you
-may not distribute the Program at all. For example, if a patent
-license would not permit royalty-free redistribution of the Program by
-all those who receive copies directly or indirectly through you, then
-the only way you could satisfy both it and this License would be to
-refrain entirely from distribution of the Program.
-
-If any portion of this section is held invalid or unenforceable under
-any particular circumstance, the balance of the section is intended to
-apply and the section as a whole is intended to apply in other
-circumstances.
-
-It is not the purpose of this section to induce you to infringe any
-patents or other property right claims or to contest validity of any
-such claims; this section has the sole purpose of protecting the
-integrity of the free software distribution system, which is
-implemented by public license practices. Many people have made
-generous contributions to the wide range of software distributed
-through that system in reliance on consistent application of that
-system; it is up to the author/donor to decide if he or she is willing
-to distribute software through any other system and a licensee cannot
-impose that choice.
-
-This section is intended to make thoroughly clear what is believed to
-be a consequence of the rest of this License.
-
- 8. If the distribution and/or use of the Program is restricted in
-certain countries either by patents or by copyrighted interfaces, the
-original copyright holder who places the Program under this License
-may add an explicit geographical distribution limitation excluding
-those countries, so that distribution is permitted only in or among
-countries not thus excluded. In such case, this License incorporates
-the limitation as if written in the body of this License.
-
- 9. The Free Software Foundation may publish revised and/or new versions
-of the General Public License from time to time. Such new versions will
-be similar in spirit to the present version, but may differ in detail to
-address new problems or concerns.
-
-Each version is given a distinguishing version number. If the Program
-specifies a version number of this License which applies to it and "any
-later version", you have the option of following the terms and conditions
-either of that version or of any later version published by the Free
-Software Foundation. If the Program does not specify a version number of
-this License, you may choose any version ever published by the Free Software
-Foundation.
-
- 10. If you wish to incorporate parts of the Program into other free
-programs whose distribution conditions are different, write to the author
-to ask for permission. For software which is copyrighted by the Free
-Software Foundation, write to the Free Software Foundation; we sometimes
-make exceptions for this. Our decision will be guided by the two goals
-of preserving the free status of all derivatives of our free software and
-of promoting the sharing and reuse of software generally.
-
- NO WARRANTY
-
- 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
-FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
-OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
-PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
-OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
-TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
-PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
-REPAIR OR CORRECTION.
-
- 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
-REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
-INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
-OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
-TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
-YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
-PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGES.
-
- END OF TERMS AND CONDITIONS
-
- Appendix: How to Apply These Terms to Your New Programs
-
- If you develop a new program, and you want it to be of the greatest
-possible use to the public, the best way to achieve this is to make it
-free software which everyone can redistribute and change under these terms.
-
- To do so, attach the following notices to the program. It is safest
-to attach them to the start of each source file to most effectively
-convey the exclusion of warranty; and each file should have at least
-the "copyright" line and a pointer to where the full notice is found.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) 19yy <name of author>
-
- 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
-
-Also add information on how to contact you by electronic and paper mail.
-
-If the program is interactive, make it output a short notice like this
-when it starts in an interactive mode:
-
- Gnomovision version 69, Copyright (C) 19yy name of author
- Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
- This is free software, and you are welcome to redistribute it
- under certain conditions; type `show c' for details.
-
-The hypothetical commands `show w' and `show c' should show the appropriate
-parts of the General Public License. Of course, the commands you use may
-be called something other than `show w' and `show c'; they could even be
-mouse-clicks or menu items--whatever suits your program.
-
-You should also get your employer (if you work as a programmer) or your
-school, if any, to sign a "copyright disclaimer" for the program, if
-necessary. Here is a sample; alter the names:
-
- Yoyodyne, Inc., hereby disclaims all copyright interest in the program
- `Gnomovision' (which makes passes at compilers) written by James Hacker.
-
- <signature of Ty Coon>, 1 April 1989
- Ty Coon, President of Vice
-
-This General Public License does not permit incorporating your program into
-proprietary programs. If your program is a subroutine library, you may
-consider it more useful to permit linking proprietary applications with the
-library. If this is what you want to do, use the GNU Library General
-Public License instead of this License.
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index 97e38b665587..cc2b9ab7f4e5 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -115,10 +115,6 @@ config SOUND_HAL2
Say Y or M if you have an SGI Indy or Indigo2 system and want to be able to
use its on-board A2 audio system.
-config SOUND_IT8172
- tristate "IT8172G Sound"
- depends on SOUND_PRIME && (MIPS_ITE8172 || MIPS_IVR)
-
config SOUND_VRC5477
tristate "NEC Vrc5477 AC97 sound"
depends on SOUND_PRIME && DDB5477
@@ -647,7 +643,7 @@ config SOUND_PSS
command line.
config PSS_MIXER
- bool "Enable PSS mixer (Beethoven ADSP-16 and other compatibile)"
+ bool "Enable PSS mixer (Beethoven ADSP-16 and other compatible)"
depends on SOUND_PSS
help
Answer Y for Beethoven ADSP-16. You may try to say Y also for other
diff --git a/sound/oss/Makefile b/sound/oss/Makefile
index 9bf3ee544d86..2489bd6bb085 100644
--- a/sound/oss/Makefile
+++ b/sound/oss/Makefile
@@ -15,72 +15,42 @@ obj-$(CONFIG_SOUND_HAL2) += hal2.o
obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o
obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o
-obj-$(CONFIG_SOUND_OPL3SA1) += opl3sa.o ad1848.o uart401.o
obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o
-obj-$(CONFIG_SOUND_MAD16) += mad16.o ad1848.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_CS4232) += cs4232.o uart401.o
obj-$(CONFIG_SOUND_MSS) += ad1848.o
obj-$(CONFIG_SOUND_OPL3SA2) += opl3sa2.o ad1848.o mpu401.o
obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o
obj-$(CONFIG_SOUND_KAHLUA) += kahlua.o
-obj-$(CONFIG_SOUND_WAVEFRONT) += wavefront.o
-obj-$(CONFIG_SOUND_MAUI) += maui.o mpu401.o
obj-$(CONFIG_SOUND_MPU401) += mpu401.o
obj-$(CONFIG_SOUND_UART6850) += uart6850.o
-obj-$(CONFIG_SOUND_GUS) += gus.o ad1848.o
obj-$(CONFIG_SOUND_ADLIB) += adlib_card.o opl3.o
obj-$(CONFIG_SOUND_YM3812) += opl3.o
obj-$(CONFIG_SOUND_VMIDI) += v_midi.o
obj-$(CONFIG_SOUND_VIDC) += vidc_mod.o
obj-$(CONFIG_SOUND_WAVEARTIST) += waveartist.o
-obj-$(CONFIG_SOUND_SGALAXY) += sgalaxy.o ad1848.o
obj-$(CONFIG_SOUND_AD1816) += ad1816.o
obj-$(CONFIG_SOUND_AD1889) += ad1889.o ac97_codec.o
obj-$(CONFIG_SOUND_ACI_MIXER) += aci.o
-obj-$(CONFIG_SOUND_AWE32_SYNTH) += awe_wave.o
obj-$(CONFIG_SOUND_VIA82CXXX) += via82cxxx_audio.o ac97_codec.o
ifeq ($(CONFIG_MIDI_VIA82CXXX),y)
obj-$(CONFIG_SOUND_VIA82CXXX) += sound.o uart401.o
endif
-obj-$(CONFIG_SOUND_YMFPCI) += ymfpci.o ac97_codec.o
-ifeq ($(CONFIG_SOUND_YMFPCI_LEGACY),y)
- obj-$(CONFIG_SOUND_YMFPCI) += opl3.o uart401.o
-endif
obj-$(CONFIG_SOUND_MSNDCLAS) += msnd.o msnd_classic.o
obj-$(CONFIG_SOUND_MSNDPIN) += msnd.o msnd_pinnacle.o
obj-$(CONFIG_SOUND_VWSND) += vwsnd.o
obj-$(CONFIG_SOUND_NM256) += nm256_audio.o ac97.o
obj-$(CONFIG_SOUND_ICH) += i810_audio.o ac97_codec.o
-obj-$(CONFIG_SOUND_SONICVIBES) += sonicvibes.o
-obj-$(CONFIG_SOUND_CMPCI) += cmpci.o
-ifeq ($(CONFIG_SOUND_CMPCI_FM),y)
- obj-$(CONFIG_SOUND_CMPCI) += sound.o opl3.o
-endif
-ifeq ($(CONFIG_SOUND_CMPCI_MIDI),y)
- obj-$(CONFIG_SOUND_CMPCI) += sound.o mpu401.o
-endif
-obj-$(CONFIG_SOUND_ES1370) += es1370.o
obj-$(CONFIG_SOUND_ES1371) += es1371.o ac97_codec.o
obj-$(CONFIG_SOUND_VRC5477) += nec_vrc5477.o ac97_codec.o
-obj-$(CONFIG_SOUND_AU1000) += au1000.o ac97_codec.o
obj-$(CONFIG_SOUND_AU1550_AC97) += au1550_ac97.o ac97_codec.o
-obj-$(CONFIG_SOUND_ESSSOLO1) += esssolo1.o
obj-$(CONFIG_SOUND_FUSION) += cs46xx.o ac97_codec.o
-obj-$(CONFIG_SOUND_MAESTRO) += maestro.o
-obj-$(CONFIG_SOUND_MAESTRO3) += maestro3.o ac97_codec.o
obj-$(CONFIG_SOUND_TRIDENT) += trident.o ac97_codec.o
-obj-$(CONFIG_SOUND_HARMONY) += harmony.o
obj-$(CONFIG_SOUND_EMU10K1) += ac97_codec.o
obj-$(CONFIG_SOUND_BCM_CS4297A) += swarm_cs4297a.o
-obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o
obj-$(CONFIG_SOUND_BT878) += btaudio.o
-obj-$(CONFIG_SOUND_ALI5455) += ali5455.o ac97_codec.o
-obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o
-obj-$(CONFIG_SOUND_FORTE) += forte.o ac97_codec.o
-obj-$(CONFIG_SOUND_AD1980) += ac97_plugin_ad1980.o ac97_codec.o
obj-$(CONFIG_SOUND_WM97XX) += ac97_plugin_wm97xx.o
ifeq ($(CONFIG_MIDI_EMU10K1),y)
@@ -88,28 +58,25 @@ ifeq ($(CONFIG_MIDI_EMU10K1),y)
endif
obj-$(CONFIG_SOUND_EMU10K1) += emu10k1/
-obj-$(CONFIG_SOUND_CS4281) += cs4281/
obj-$(CONFIG_DMASOUND) += dmasound/
# Declare multi-part drivers.
sound-objs := \
- dev_table.o soundcard.o sound_syms.o \
- audio.o audio_syms.o dmabuf.o \
- midi_syms.o midi_synth.o midibuf.o \
- sequencer.o sequencer_syms.o sound_timer.o sys_timer.o
+ dev_table.o soundcard.o \
+ audio.o dmabuf.o \
+ midi_synth.o midibuf.o \
+ sequencer.o sound_timer.o sys_timer.o
-gus-objs := gus_card.o gus_midi.o gus_vol.o gus_wave.o ics2101.o
pas2-objs := pas2_card.o pas2_midi.o pas2_mixer.o pas2_pcm.o
sb-objs := sb_card.o
sb_lib-objs := sb_common.o sb_audio.o sb_midi.o sb_mixer.o sb_ess.o
vidc_mod-objs := vidc.o vidc_fill.o
-wavefront-objs := wavfront.o wf_midi.o yss225.o
hostprogs-y := bin2hex hex2hex
# Files generated that shall be removed upon make clean
-clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \
+clean-files := msndperm.c msndinit.c pndsperm.c pndspini.c \
pss_boot.h trix_boot.h
# Firmware files that need translation
@@ -119,21 +86,6 @@ clean-files := maui_boot.h msndperm.c msndinit.c pndsperm.c pndspini.c \
# will be forced to be remade.
#
-# Turtle Beach Maui / Tropez
-
-$(obj)/maui.o: $(obj)/maui_boot.h
-
-ifeq ($(CONFIG_MAUI_HAVE_BOOT),y)
- $(obj)/maui_boot.h: $(patsubst "%", %, $(CONFIG_MAUI_BOOT_FILE)) $(obj)/bin2hex
- $(obj)/bin2hex -i maui_os < $< > $@
-else
- $(obj)/maui_boot.h:
- ( \
- echo 'static unsigned char * maui_os = NULL;'; \
- echo 'static int maui_osLen = 0;'; \
- ) > $@
-endif
-
# Turtle Beach MultiSound
ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y)
diff --git a/sound/oss/ac97.c b/sound/oss/ac97.c
index 3ba6d91e891d..72cf4ed77937 100644
--- a/sound/oss/ac97.c
+++ b/sound/oss/ac97.c
@@ -112,25 +112,6 @@ ac97_init (struct ac97_hwint *dev)
return 0;
}
-/* Reset the mixer to the currently saved settings. */
-int
-ac97_reset (struct ac97_hwint *dev)
-{
- int x;
-
- if (dev->reset_device (dev))
- return -1;
-
- /* Now set the registers back to their last-written values. */
- for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
- int regnum = mixerRegs[x].ac97_regnum;
- int value = dev->last_written_mixer_values [regnum / 2];
- if (value >= 0)
- ac97_put_register (dev, regnum, value);
- }
- return 0;
-}
-
/* Return the contents of register REG; use the cache if the value in it
is valid. Returns a negative error code on failure. */
static int
@@ -441,7 +422,6 @@ EXPORT_SYMBOL(ac97_init);
EXPORT_SYMBOL(ac97_set_values);
EXPORT_SYMBOL(ac97_put_register);
EXPORT_SYMBOL(ac97_mixer_ioctl);
-EXPORT_SYMBOL(ac97_reset);
MODULE_LICENSE("GPL");
diff --git a/sound/oss/ac97.h b/sound/oss/ac97.h
index 77d454ea3202..01837a9d7d6e 100644
--- a/sound/oss/ac97.h
+++ b/sound/oss/ac97.h
@@ -192,9 +192,6 @@ extern int ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value);
extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
void __user * arg);
-/* Do a complete reset on the AC97 mixer, restoring all mixer registers to
- the current values. Normally used after an APM resume event. */
-extern int ac97_reset (struct ac97_hwint *dev);
#endif
/*
diff --git a/sound/oss/ac97_codec.c b/sound/oss/ac97_codec.c
index 972327c97644..602db497929a 100644
--- a/sound/oss/ac97_codec.c
+++ b/sound/oss/ac97_codec.c
@@ -1399,95 +1399,6 @@ unsigned int ac97_set_adc_rate(struct ac97_codec *codec, unsigned int rate)
EXPORT_SYMBOL(ac97_set_adc_rate);
-int ac97_save_state(struct ac97_codec *codec)
-{
- return 0;
-}
-
-EXPORT_SYMBOL(ac97_save_state);
-
-int ac97_restore_state(struct ac97_codec *codec)
-{
- int i;
- unsigned int left, right, val;
-
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!supported_mixer(codec, i))
- continue;
-
- val = codec->mixer_state[i];
- right = val >> 8;
- left = val & 0xff;
- codec->write_mixer(codec, i, left, right);
- }
- return 0;
-}
-
-EXPORT_SYMBOL(ac97_restore_state);
-
-/**
- * ac97_register_driver - register a codec helper
- * @driver: Driver handler
- *
- * Register a handler for codecs matching the codec id. The handler
- * attach function is called for all present codecs and will be
- * called when new codecs are discovered.
- */
-
-int ac97_register_driver(struct ac97_driver *driver)
-{
- struct list_head *l;
- struct ac97_codec *c;
-
- mutex_lock(&codec_mutex);
- INIT_LIST_HEAD(&driver->list);
- list_add(&driver->list, &codec_drivers);
-
- list_for_each(l, &codecs)
- {
- c = list_entry(l, struct ac97_codec, list);
- if(c->driver != NULL || ((c->model ^ driver->codec_id) & driver->codec_mask))
- continue;
- if(driver->probe(c, driver))
- continue;
- c->driver = driver;
- }
- mutex_unlock(&codec_mutex);
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(ac97_register_driver);
-
-/**
- * ac97_unregister_driver - unregister a codec helper
- * @driver: Driver handler
- *
- * Unregister a handler for codecs matching the codec id. The handler
- * remove function is called for all matching codecs.
- */
-
-void ac97_unregister_driver(struct ac97_driver *driver)
-{
- struct list_head *l;
- struct ac97_codec *c;
-
- mutex_lock(&codec_mutex);
- list_del_init(&driver->list);
-
- list_for_each(l, &codecs)
- {
- c = list_entry(l, struct ac97_codec, list);
- if (c->driver == driver) {
- driver->remove(c, driver);
- c->driver = NULL;
- }
- }
-
- mutex_unlock(&codec_mutex);
-}
-
-EXPORT_SYMBOL_GPL(ac97_unregister_driver);
-
static int swap_headphone(int remove_master)
{
struct list_head *l;
diff --git a/sound/oss/ac97_plugin_ad1980.c b/sound/oss/ac97_plugin_ad1980.c
deleted file mode 100644
index 24a9acd28160..000000000000
--- a/sound/oss/ac97_plugin_ad1980.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- ac97_plugin_ad1980.c Copyright (C) 2003 Red Hat, Inc. All rights reserved.
-
- The contents of this file are subject to the Open Software License version 1.1
- that can be found at http://www.opensource.org/licenses/osl-1.1.txt and is
- included herein by reference.
-
- Alternatively, the contents of this file may be used under the
- terms of the GNU General Public License version 2 (the "GPL") as
- distributed in the kernel source COPYING file, in which
- case the provisions of the GPL are applicable instead of the
- above. If you wish to allow the use of your version of this file
- only under the terms of the GPL and not to allow others to use
- your version of this file under the OSL, indicate your decision
- by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL. If you do not delete
- the provisions above, a recipient may use your version of this
- file under either the OSL or the GPL.
-
- Authors: Alan Cox <alan@redhat.com>
-
- This is an example codec plugin. This one switches the connections
- around to match the setups some vendors use with audio switched to
- non standard front connectors not the normal rear ones
-
- This code primarily exists to demonstrate how to use the codec
- interface
-
-*/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/ac97_codec.h>
-
-/**
- * ad1980_remove - codec remove callback
- * @codec: The codec that is being removed
- *
- * This callback occurs when an AC97 codec is being removed. A
- * codec remove call will not occur for a codec during that codec
- * probe callback.
- *
- * Most drivers will need to lock their remove versus their
- * use of the codec after the probe function.
- */
-
-static void __devexit ad1980_remove(struct ac97_codec *codec, struct ac97_driver *driver)
-{
- /* Nothing to do in the simple example */
-}
-
-
-/**
- * ad1980_probe - codec found callback
- * @codec: ac97 codec matching the idents
- * @driver: ac97_driver it matched
- *
- * This entry point is called when a codec is found which matches
- * the driver. At the point it is called the codec is basically
- * operational, mixer operations have been initialised and can
- * be overriden. Called in process context. The field driver_private
- * is available for the driver to use to store stuff.
- *
- * The caller can claim the device by returning zero, or return
- * a negative error code.
- */
-
-static int ad1980_probe(struct ac97_codec *codec, struct ac97_driver *driver)
-{
- u16 control;
-
-#define AC97_AD_MISC 0x76
-
- /* Switch the inputs/outputs over (from Dell code) */
- control = codec->codec_read(codec, AC97_AD_MISC);
- codec->codec_write(codec, AC97_AD_MISC, control | 0x4420);
-
- /* We could refuse the device since we dont need to hang around,
- but we will claim it */
- return 0;
-}
-
-
-static struct ac97_driver ad1980_driver = {
- .codec_id = 0x41445370,
- .codec_mask = 0xFFFFFFFF,
- .name = "AD1980 example",
- .probe = ad1980_probe,
- .remove = __devexit_p(ad1980_remove),
-};
-
-/**
- * ad1980_exit - module exit path
- *
- * Our module is being unloaded. At this point unregister_driver
- * will call back our remove handler for any existing codecs. You
- * may not unregister_driver from interrupt context or from a
- * probe/remove callback.
- */
-
-static void ad1980_exit(void)
-{
- ac97_unregister_driver(&ad1980_driver);
-}
-
-/**
- * ad1980_init - set up ad1980 handlers
- *
- * After we call the register function it will call our probe
- * function for each existing matching device before returning to us.
- * Any devices appearing afterwards whose id's match the codec_id
- * will also cause the probe function to be called.
- * You may not register_driver from interrupt context or from a
- * probe/remove callback.
- */
-
-static int ad1980_init(void)
-{
- return ac97_register_driver(&ad1980_driver);
-}
-
-module_init(ad1980_init);
-module_exit(ad1980_exit);
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/ad1816.c b/sound/oss/ad1816.c
index 29057836c644..caabf31193f7 100644
--- a/sound/oss/ad1816.c
+++ b/sound/oss/ad1816.c
@@ -521,7 +521,7 @@ static struct audio_driver ad1816_audio_driver =
/* Interrupt handler */
-static irqreturn_t ad1816_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t ad1816_interrupt (int irq, void *dev_id)
{
unsigned char status;
ad1816_info *devc = (ad1816_info *)dev_id;
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 3b45e11e5303..0ffa9970bf0f 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -1,5 +1,5 @@
/*
- * sound/ad1848.c
+ * sound/oss/ad1848.c
*
* The low level driver for the AD1848/CS4248 codec chip which
* is used for example in the MS Sound System.
@@ -195,6 +195,7 @@ static void ad1848_halt(int dev);
static void ad1848_halt_input(int dev);
static void ad1848_halt_output(int dev);
static void ad1848_trigger(int dev, int bits);
+static irqreturn_t adintr(int irq, void *dev_id);
#ifndef EXCLUDE_TIMERS
static int ad1848_tmr_install(int dev);
@@ -2195,7 +2196,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
printk(KERN_ERR "ad1848: Can't find device to be unloaded. Base=%x\n", io_base);
}
-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t adintr(int irq, void *dev_id)
{
unsigned char status;
ad1848_info *devc;
@@ -2802,7 +2803,6 @@ EXPORT_SYMBOL(ad1848_detect);
EXPORT_SYMBOL(ad1848_init);
EXPORT_SYMBOL(ad1848_unload);
EXPORT_SYMBOL(ad1848_control);
-EXPORT_SYMBOL(adintr);
EXPORT_SYMBOL(probe_ms_sound);
EXPORT_SYMBOL(attach_ms_sound);
EXPORT_SYMBOL(unload_ms_sound);
diff --git a/sound/oss/ad1848.h b/sound/oss/ad1848.h
index d0573b023973..b95ebe28d426 100644
--- a/sound/oss/ad1848.h
+++ b/sound/oss/ad1848.h
@@ -18,7 +18,6 @@ void ad1848_unload (int io_base, int irq, int dma_playback, int dma_capture, int
int ad1848_detect (struct resource *ports, int *flags, int *osp);
int ad1848_control(int cmd, int arg);
-irqreturn_t adintr(int irq, void *dev_id, struct pt_regs * dummy);
void attach_ms_sound(struct address_info * hw_config, struct resource *ports, struct module * owner);
int probe_ms_sound(struct address_info *hw_config, struct resource *ports);
diff --git a/sound/oss/ad1848_mixer.h b/sound/oss/ad1848_mixer.h
index f9231c6cd4e1..2cf719b5fbbc 100644
--- a/sound/oss/ad1848_mixer.h
+++ b/sound/oss/ad1848_mixer.h
@@ -1,5 +1,5 @@
/*
- * sound/ad1848_mixer.h
+ * sound/oss/ad1848_mixer.h
*
* Definitions for the mixer of AD1848 and compatible codecs.
*/
diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c
index f56f870b4840..09263d72a519 100644
--- a/sound/oss/ad1889.c
+++ b/sound/oss/ad1889.c
@@ -929,7 +929,7 @@ static struct pci_device_id ad1889_id_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, ad1889_id_tbl);
-static irqreturn_t ad1889_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ad1889_interrupt(int irq, void *dev_id)
{
u32 stat;
ad1889_dev_t *dev = (ad1889_dev_t *)dev_id;
diff --git a/sound/oss/adlib_card.c b/sound/oss/adlib_card.c
index 6414ceb8f072..c9a7c9b470de 100644
--- a/sound/oss/adlib_card.c
+++ b/sound/oss/adlib_card.c
@@ -1,5 +1,5 @@
/*
- * sound/adlib_card.c
+ * sound/oss/adlib_card.c
*
* Detection routine for the AdLib card.
*
diff --git a/sound/oss/ali5455.c b/sound/oss/ali5455.c
deleted file mode 100644
index 70dcd703a66f..000000000000
--- a/sound/oss/ali5455.c
+++ /dev/null
@@ -1,3735 +0,0 @@
-/*
- * ALI ali5455 and friends ICH driver for Linux
- * LEI HU <Lei_Hu@ali.com.tw>
- *
- * Built from:
- * drivers/sound/i810_audio
- *
- * The ALi 5455 is similar but not quite identical to the Intel ICH
- * series of controllers. Its easier to keep the driver separated from
- * the i810 driver.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * ALi 5455 theory of operation
- *
- * The chipset provides three DMA channels that talk to an AC97
- * CODEC (AC97 is a digital/analog mixer standard). At its simplest
- * you get 48Khz audio with basic volume and mixer controls. At the
- * best you get rate adaption in the codec. We set the card up so
- * that we never take completion interrupts but instead keep the card
- * chasing its tail around a ring buffer. This is needed for mmap
- * mode audio and happens to work rather well for non-mmap modes too.
- *
- * The board has one output channel for PCM audio (supported) and
- * a stereo line in and mono microphone input. Again these are normally
- * locked to 48Khz only. Right now recording is not finished.
- *
- * There is no midi support, no synth support. Use timidity. To get
- * esd working you need to use esd -r 48000 as it won't probe 48KHz
- * by default. mpg123 can't handle 48Khz only audio so use xmms.
- *
- * If you need to force a specific rate set the clocking= option
- *
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-
-#ifndef PCI_DEVICE_ID_ALI_5455
-#define PCI_DEVICE_ID_ALI_5455 0x5455
-#endif
-
-#ifndef PCI_VENDOR_ID_ALI
-#define PCI_VENDOR_ID_ALI 0x10b9
-#endif
-
-static int strict_clocking = 0;
-static unsigned int clocking = 0;
-static unsigned int codec_pcmout_share_spdif_locked = 0;
-static unsigned int codec_independent_spdif_locked = 0;
-static unsigned int controller_pcmout_share_spdif_locked = 0;
-static unsigned int controller_independent_spdif_locked = 0;
-static unsigned int globel = 0;
-
-#define ADC_RUNNING 1
-#define DAC_RUNNING 2
-#define CODEC_SPDIFOUT_RUNNING 8
-#define CONTROLLER_SPDIFOUT_RUNNING 4
-
-#define SPDIF_ENABLE_OUTPUT 4 /* bits 0,1 are PCM */
-
-#define ALI5455_FMT_16BIT 1
-#define ALI5455_FMT_STEREO 2
-#define ALI5455_FMT_MASK 3
-
-#define SPDIF_ON 0x0004
-#define SURR_ON 0x0010
-#define CENTER_LFE_ON 0x0020
-#define VOL_MUTED 0x8000
-
-
-#define ALI_SPDIF_OUT_CH_STATUS 0xbf
-/* the 810's array of pointers to data buffers */
-
-struct sg_item {
-#define BUSADDR_MASK 0xFFFFFFFE
- u32 busaddr;
-#define CON_IOC 0x80000000 /* interrupt on completion */
-#define CON_BUFPAD 0x40000000 /* pad underrun with last sample, else 0 */
-#define CON_BUFLEN_MASK 0x0000ffff /* buffer length in samples */
- u32 control;
-};
-
-/* an instance of the ali channel */
-#define SG_LEN 32
-struct ali_channel {
- /* these sg guys should probably be allocated
- separately as nocache. Must be 8 byte aligned */
- struct sg_item sg[SG_LEN]; /* 32*8 */
- u32 offset; /* 4 */
- u32 port; /* 4 */
- u32 used;
- u32 num;
-};
-
-/*
- * we have 3 separate dma engines. pcm in, pcm out, and mic.
- * each dma engine has controlling registers. These goofy
- * names are from the datasheet, but make it easy to write
- * code while leafing through it.
- */
-
-#define ENUM_ENGINE(PRE,DIG) \
-enum { \
- PRE##_BDBAR = 0x##DIG##0, /* Buffer Descriptor list Base Address */ \
- PRE##_CIV = 0x##DIG##4, /* Current Index Value */ \
- PRE##_LVI = 0x##DIG##5, /* Last Valid Index */ \
- PRE##_SR = 0x##DIG##6, /* Status Register */ \
- PRE##_PICB = 0x##DIG##8, /* Position In Current Buffer */ \
- PRE##_CR = 0x##DIG##b /* Control Register */ \
-}
-
-ENUM_ENGINE(OFF, 0); /* Offsets */
-ENUM_ENGINE(PI, 4); /* PCM In */
-ENUM_ENGINE(PO, 5); /* PCM Out */
-ENUM_ENGINE(MC, 6); /* Mic In */
-ENUM_ENGINE(CODECSPDIFOUT, 7); /* CODEC SPDIF OUT */
-ENUM_ENGINE(CONTROLLERSPDIFIN, A); /* CONTROLLER SPDIF In */
-ENUM_ENGINE(CONTROLLERSPDIFOUT, B); /* CONTROLLER SPDIF OUT */
-
-
-enum {
- ALI_SCR = 0x00, /* System Control Register */
- ALI_SSR = 0x04, /* System Status Register */
- ALI_DMACR = 0x08, /* DMA Control Register */
- ALI_FIFOCR1 = 0x0c, /* FIFO Control Register 1 */
- ALI_INTERFACECR = 0x10, /* Interface Control Register */
- ALI_INTERRUPTCR = 0x14, /* Interrupt control Register */
- ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */
- ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */
- ALI_CPR = 0x20, /* Command Port Register */
- ALI_SPR = 0x24, /* Status Port Register */
- ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */
- ALI_TTSR = 0x30, /* Transmit Tag Slot Register */
- ALI_RTSR = 0x34, /* Receive Tag Slot Register */
- ALI_CSPSR = 0x38, /* Command/Status Port Status Register */
- ALI_CAS = 0x3c, /* Codec Write Semaphore Register */
- ALI_SPDIFCSR = 0xf8, /* spdif channel status register */
- ALI_SPDIFICS = 0xfc /* spdif interface control/status */
-};
-
-// x-status register(x:pcm in ,pcm out, mic in,)
-/* interrupts for a dma engine */
-#define DMA_INT_FIFO (1<<4) /* fifo under/over flow */
-#define DMA_INT_COMPLETE (1<<3) /* buffer read/write complete and ioc set */
-#define DMA_INT_LVI (1<<2) /* last valid done */
-#define DMA_INT_CELV (1<<1) /* last valid is current */
-#define DMA_INT_DCH (1) /* DMA Controller Halted (happens on LVI interrupts) */ //not eqult intel
-#define DMA_INT_MASK (DMA_INT_FIFO|DMA_INT_COMPLETE|DMA_INT_LVI)
-
-/* interrupts for the whole chip */// by interrupt status register finish
-
-#define INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */
-#define INT_SPDIFIN (1<<22)
-#define INT_CODECSPDIFOUT (1<<19)
-#define INT_MICIN (1<<18)
-#define INT_PCMOUT (1<<17)
-#define INT_PCMIN (1<<16)
-#define INT_CPRAIS (1<<7)
-#define INT_SPRAIS (1<<5)
-#define INT_GPIO (1<<1)
-#define INT_MASK (INT_SPDIFOUT|INT_CODECSPDIFOUT|INT_MICIN|INT_PCMOUT|INT_PCMIN)
-
-#define DRIVER_VERSION "0.02ac"
-
-/* magic numbers to protect our data structures */
-#define ALI5455_CARD_MAGIC 0x5072696E /* "Prin" */
-#define ALI5455_STATE_MAGIC 0x63657373 /* "cess" */
-#define ALI5455_DMA_MASK 0xffffffff /* DMA buffer mask for pci_alloc_consist */
-#define NR_HW_CH 5 //I think 5 channel
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 2
-
-/* Please note that an 8bit mono stream is not valid on this card, you must have a 16bit */
-/* stream at a minimum for this card to be happy */
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-/* Samples are 16bit values, so we are shifting to a word, not to a byte, hence shift */
-/* values are one less than might be expected */
-static const unsigned sample_shift[] = { -1, 0, 0, 1 };
-
-#define ALI5455
-static char *card_names[] = {
- "ALI 5455"
-};
-
-static struct pci_device_id ali_pci_tbl[] = {
- {PCI_VENDOR_ID_ALI, PCI_DEVICE_ID_ALI_5455,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, ALI5455},
- {0,}
-};
-
-MODULE_DEVICE_TABLE(pci, ali_pci_tbl);
-
-#ifdef CONFIG_PM
-#define PM_SUSPENDED(card) (card->pm_suspended)
-#else
-#define PM_SUSPENDED(card) (0)
-#endif
-
-/* "software" or virtual channel, an instance of opened /dev/dsp */
-struct ali_state {
- unsigned int magic;
- struct ali_card *card; /* Card info */
-
- /* single open lock mechanism, only used for recording */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
-
- /* file mode */
- mode_t open_mode;
-
- /* virtual channel number */
- int virt;
-
-#ifdef CONFIG_PM
- unsigned int pm_saved_dac_rate, pm_saved_adc_rate;
-#endif
- struct dmabuf {
- /* wave sample stuff */
- unsigned int rate;
- unsigned char fmt, enable, trigger;
-
- /* hardware channel */
- struct ali_channel *read_channel;
- struct ali_channel *write_channel;
- struct ali_channel *codec_spdifout_channel;
- struct ali_channel *controller_spdifout_channel;
-
- /* OSS buffer management stuff */
- void *rawbuf;
- dma_addr_t dma_handle;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started, updated by update_ptr */
- unsigned swptr; /* where driver last clear/filled, updated by read/write */
- int count; /* bytes to be consumed or been generated by dma machine */
- unsigned total_bytes; /* total bytes dmaed by hardware */
-
- unsigned error; /* number of over/underruns */
- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
- /* redundant, but makes calculations easier */
- /* what the hardware uses */
- unsigned dmasize;
- unsigned fragsize;
- unsigned fragsamples;
-
- /* what we tell the user to expect */
- unsigned userfrags;
- unsigned userfragsize;
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned update_flag;
- unsigned ossfragsize;
- unsigned ossmaxfrags;
- unsigned subdivision;
- } dmabuf;
-};
-
-
-struct ali_card {
- struct ali_channel channel[5];
- unsigned int magic;
-
- /* We keep ali5455 cards in a linked list */
- struct ali_card *next;
-
- /* The ali has a certain amount of cross channel interaction
- so we use a single per card lock */
- spinlock_t lock;
- spinlock_t ac97_lock;
-
- /* PCI device stuff */
- struct pci_dev *pci_dev;
- u16 pci_id;
-#ifdef CONFIG_PM
- u16 pm_suspended;
- int pm_saved_mixer_settings[SOUND_MIXER_NRDEVICES][NR_AC97];
-#endif
- /* soundcore stuff */
- int dev_audio;
-
- /* structures for abstraction of hardware facilities, codecs, banks and channels */
- struct ac97_codec *ac97_codec[NR_AC97];
- struct ali_state *states[NR_HW_CH];
-
- u16 ac97_features;
- u16 ac97_status;
- u16 channels;
-
- /* hardware resources */
- unsigned long iobase;
-
- u32 irq;
-
- /* Function support */
- struct ali_channel *(*alloc_pcm_channel) (struct ali_card *);
- struct ali_channel *(*alloc_rec_pcm_channel) (struct ali_card *);
- struct ali_channel *(*alloc_rec_mic_channel) (struct ali_card *);
- struct ali_channel *(*alloc_codec_spdifout_channel) (struct ali_card *);
- struct ali_channel *(*alloc_controller_spdifout_channel) (struct ali_card *);
- void (*free_pcm_channel) (struct ali_card *, int chan);
-
- /* We have a *very* long init time possibly, so use this to block */
- /* attempts to open our devices before we are ready (stops oops'es) */
- int initializing;
-};
-
-
-static struct ali_card *devs = NULL;
-
-static int ali_open_mixdev(struct inode *inode, struct file *file);
-static int ali_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg);
-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data);
-
-static struct ali_channel *ali_alloc_pcm_channel(struct ali_card *card)
-{
- if (card->channel[1].used == 1)
- return NULL;
- card->channel[1].used = 1;
- return &card->channel[1];
-}
-
-static struct ali_channel *ali_alloc_rec_pcm_channel(struct ali_card *card)
-{
- if (card->channel[0].used == 1)
- return NULL;
- card->channel[0].used = 1;
- return &card->channel[0];
-}
-
-static struct ali_channel *ali_alloc_rec_mic_channel(struct ali_card *card)
-{
- if (card->channel[2].used == 1)
- return NULL;
- card->channel[2].used = 1;
- return &card->channel[2];
-}
-
-static struct ali_channel *ali_alloc_codec_spdifout_channel(struct ali_card *card)
-{
- if (card->channel[3].used == 1)
- return NULL;
- card->channel[3].used = 1;
- return &card->channel[3];
-}
-
-static struct ali_channel *ali_alloc_controller_spdifout_channel(struct ali_card *card)
-{
- if (card->channel[4].used == 1)
- return NULL;
- card->channel[4].used = 1;
- return &card->channel[4];
-}
-static void ali_free_pcm_channel(struct ali_card *card, int channel)
-{
- card->channel[channel].used = 0;
-}
-
-
-//add support codec spdif out
-static int ali_valid_spdif_rate(struct ac97_codec *codec, int rate)
-{
- unsigned long id = 0L;
-
- id = (ali_ac97_get(codec, AC97_VENDOR_ID1) << 16);
- id |= ali_ac97_get(codec, AC97_VENDOR_ID2) & 0xffff;
- switch (id) {
- case 0x41445361: /* AD1886 */
- if (rate == 48000) {
- return 1;
- }
- break;
- case 0x414c4720: /* ALC650 */
- if (rate == 48000) {
- return 1;
- }
- break;
- default: /* all other codecs, until we know otherwiae */
- if (rate == 48000 || rate == 44100 || rate == 32000) {
- return 1;
- }
- break;
- }
- return (0);
-}
-
-/* ali_set_spdif_output
- *
- * Configure the S/PDIF output transmitter. When we turn on
- * S/PDIF, we turn off the analog output. This may not be
- * the right thing to do.
- *
- * Assumptions:
- * The DSP sample rate must already be set to a supported
- * S/PDIF rate (32kHz, 44.1kHz, or 48kHz) or we abort.
- */
-static void ali_set_spdif_output(struct ali_state *state, int slots,
- int rate)
-{
- int vol;
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if (!(state->card->ac97_features & 4)) {
- state->card->ac97_status &= ~SPDIF_ON;
- } else {
- if (slots == -1) { /* Turn off S/PDIF */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
-
- /* If the volume wasn't muted before we turned on S/PDIF, unmute it */
- if (!(state->card->ac97_status & VOL_MUTED)) {
- aud_reg = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- ali_ac97_set(codec, AC97_MASTER_VOL_STEREO,
- (aud_reg & ~VOL_MUTED));
- }
- state->card->ac97_status &= ~(VOL_MUTED | SPDIF_ON);
- return;
- }
-
- vol = ali_ac97_get(codec, AC97_MASTER_VOL_STEREO);
- state->card->ac97_status = vol & VOL_MUTED;
-
- /* Set S/PDIF transmitter sample rate */
- aud_reg = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
- switch (rate) {
- case 32000:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_32K;
- break;
- case 44100:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_44K;
- break;
- case 48000:
- aud_reg = (aud_reg & AC97_SC_SPSR_MASK) | AC97_SC_SPSR_48K;
- break;
- default:
- /* turn off S/PDIF */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
- state->card->ac97_status &= ~SPDIF_ON;
- return;
- }
-
- ali_ac97_set(codec, AC97_SPDIF_CONTROL, aud_reg);
-
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- aud_reg = (aud_reg & AC97_EA_SLOT_MASK) | slots | AC97_EA_SPDIF;
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
- aud_reg = ali_ac97_get(codec, AC97_POWER_CONTROL);
- aud_reg |= 0x0002;
- ali_ac97_set(codec, AC97_POWER_CONTROL, aud_reg);
- udelay(1);
-
- state->card->ac97_status |= SPDIF_ON;
-
- /* Check to make sure the configuration is valid */
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- if (!(aud_reg & 0x0400)) {
- /* turn off S/PDIF */
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, (aud_reg & ~AC97_EA_SPDIF));
- state->card->ac97_status &= ~SPDIF_ON;
- return;
- }
- if (codec_independent_spdif_locked > 0) {
- aud_reg = ali_ac97_get(codec, 0x6a);
- ali_ac97_set(codec, 0x6a, (aud_reg & 0xefff));
- }
- /* Mute the analog output */
- /* Should this only mute the PCM volume??? */
- }
-}
-
-/* ali_set_dac_channels
- *
- * Configure the codec's multi-channel DACs
- *
- * The logic is backwards. Setting the bit to 1 turns off the DAC.
- *
- * What about the ICH? We currently configure it using the
- * SNDCTL_DSP_CHANNELS ioctl. If we're turnning on the DAC,
- * does that imply that we want the ICH set to support
- * these channels?
- *
- * TODO:
- * vailidate that the codec really supports these DACs
- * before turning them on.
- */
-static void ali_set_dac_channels(struct ali_state *state, int channel)
-{
- int aud_reg;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- aud_reg = ali_ac97_get(codec, AC97_EXTENDED_STATUS);
- aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
- state->card->ac97_status &= ~(SURR_ON | CENTER_LFE_ON);
-
- switch (channel) {
- case 2: /* always enabled */
- break;
- case 4:
- aud_reg &= ~AC97_EA_PRJ;
- state->card->ac97_status |= SURR_ON;
- break;
- case 6:
- aud_reg &= ~(AC97_EA_PRJ | AC97_EA_PRI | AC97_EA_PRK);
- state->card->ac97_status |= SURR_ON | CENTER_LFE_ON;
- break;
- default:
- break;
- }
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, aud_reg);
-
-}
-
-/* set playback sample rate */
-static unsigned int ali_set_dac_rate(struct ali_state *state,
- unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if (!(state->card->ac97_features & 0x0001)) {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
-
- rate = (rate * clocking) / 48000;
-
- if (strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000) / clocking;
- }
-
- new_rate = ac97_set_dac_rate(codec, rate);
- if (new_rate != rate) {
- dmabuf->rate = (new_rate * 48000) / clocking;
- }
- rate = new_rate;
- return dmabuf->rate;
-}
-
-/* set recording sample rate */
-static unsigned int ali_set_adc_rate(struct ali_state *state,
- unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- u32 new_rate;
- struct ac97_codec *codec = state->card->ac97_codec[0];
-
- if (!(state->card->ac97_features & 0x0001)) {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- /*
- * Adjust for misclocked crap
- */
-
- rate = (rate * clocking) / 48000;
- if (strict_clocking && rate < 8000) {
- rate = 8000;
- dmabuf->rate = (rate * 48000) / clocking;
- }
-
- new_rate = ac97_set_adc_rate(codec, rate);
-
- if (new_rate != rate) {
- dmabuf->rate = (new_rate * 48000) / clocking;
- rate = new_rate;
- }
- return dmabuf->rate;
-}
-
-/* set codec independent spdifout sample rate */
-static unsigned int ali_set_codecspdifout_rate(struct ali_state *state,
- unsigned int rate)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (!(state->card->ac97_features & 0x0001)) {
- dmabuf->rate = clocking;
- return clocking;
- }
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- dmabuf->rate = rate;
-
- return dmabuf->rate;
-}
-
-/* set controller independent spdif out function sample rate */
-static void ali_set_spdifout_rate(struct ali_state *state,
- unsigned int rate)
-{
- unsigned char ch_st_sel;
- unsigned short status_rate;
-
- switch (rate) {
- case 44100:
- status_rate = 0;
- break;
- case 32000:
- status_rate = 0x300;
- break;
- case 48000:
- default:
- status_rate = 0x200;
- break;
- }
-
- ch_st_sel = inb(state->card->iobase + ALI_SPDIFICS) & ALI_SPDIF_OUT_CH_STATUS; //select spdif_out
-
- ch_st_sel |= 0x80; //select right
- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
- outb(status_rate | 0x20, (state->card->iobase + ALI_SPDIFCSR + 2));
-
- ch_st_sel &= (~0x80); //select left
- outb(ch_st_sel, (state->card->iobase + ALI_SPDIFICS));
- outw(status_rate | 0x10, (state->card->iobase + ALI_SPDIFCSR + 2));
-}
-
-/* get current playback/recording dma buffer pointer (byte offset from LBA),
- called with spinlock held! */
-
-static inline unsigned ali_get_dma_addr(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned int civ, offset, port, port_picb;
- unsigned int data;
-
- if (!dmabuf->enable)
- return 0;
-
- if (rec == 1)
- port = state->card->iobase + dmabuf->read_channel->port;
- else if (rec == 2)
- port = state->card->iobase + dmabuf->codec_spdifout_channel->port;
- else if (rec == 3)
- port = state->card->iobase + dmabuf->controller_spdifout_channel->port;
- else
- port = state->card->iobase + dmabuf->write_channel->port;
-
- port_picb = port + OFF_PICB;
-
- do {
- civ = inb(port + OFF_CIV) & 31;
- offset = inw(port_picb);
- /* Must have a delay here! */
- if (offset == 0)
- udelay(1);
-
- /* Reread both registers and make sure that that total
- * offset from the first reading to the second is 0.
- * There is an issue with SiS hardware where it will count
- * picb down to 0, then update civ to the next value,
- * then set the new picb to fragsize bytes. We can catch
- * it between the civ update and the picb update, making
- * it look as though we are 1 fragsize ahead of where we
- * are. The next to we get the address though, it will
- * be back in thdelay is more than long enough
- * that we won't have to worry about the chip still being
- * out of sync with reality ;-)
- */
- } while (civ != (inb(port + OFF_CIV) & 31) || offset != inw(port_picb));
-
- data = ((civ + 1) * dmabuf->fragsize - (2 * offset)) % dmabuf->dmasize;
- if (inw(port_picb) == 0)
- data -= 2048;
-
- return data;
-}
-
-/* Stop recording (lock held) */
-static inline void __stop_adc(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- dmabuf->enable &= ~ADC_RUNNING;
-
- outl((1 << 18) | (1 << 16), card->iobase + ALI_DMACR);
- udelay(1);
-
- outb(0, card->iobase + PI_CR);
- while (inb(card->iobase + PI_CR) != 0);
-
- // now clear any latent interrupt bits (like the halt bit)
- outb(inb(card->iobase + PI_SR) | 0x001e, card->iobase + PI_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMIN, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_adc(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __stop_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_adc(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
-
- if (dmabuf->count < dmabuf->dmasize && dmabuf->ready
- && !dmabuf->enable && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- dmabuf->enable |= ADC_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + PI_CR);
- if (state->card->channel[0].used == 1)
- outl(1, state->card->iobase + ALI_DMACR); // DMA CONTROL REGISTRER
- udelay(100);
- if (state->card->channel[2].used == 1)
- outl((1 << 2), state->card->iobase + ALI_DMACR); //DMA CONTROL REGISTER
- udelay(100);
- }
-}
-
-static void start_adc(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
- __start_adc(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop playback (lock held) */
-static inline void __stop_dac(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- dmabuf->enable &= ~DAC_RUNNING;
- outl(0x00020000, card->iobase + 0x08);
- outb(0, card->iobase + PO_CR);
- while (inb(card->iobase + PO_CR) != 0)
- cpu_relax();
-
- outb(inb(card->iobase + PO_SR) | 0x001e, card->iobase + PO_SR);
-
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_PCMOUT, card->iobase + ALI_INTERRUPTSR);
-}
-
-static void stop_dac(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __stop_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_dac(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->enable |= DAC_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + PO_CR);
- outl((1 << 1), state->card->iobase + 0x08); //dma control register
- }
-}
-
-static void start_dac(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __start_dac(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/* stop codec and controller spdif out (lock held) */
-static inline void __stop_spdifout(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_card *card = state->card;
-
- if (codec_independent_spdif_locked > 0) {
- dmabuf->enable &= ~CODEC_SPDIFOUT_RUNNING;
- outl((1 << 19), card->iobase + 0x08);
- outb(0, card->iobase + CODECSPDIFOUT_CR);
-
- while (inb(card->iobase + CODECSPDIFOUT_CR) != 0)
- cpu_relax();
-
- outb(inb(card->iobase + CODECSPDIFOUT_SR) | 0x001e, card->iobase + CODECSPDIFOUT_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_CODECSPDIFOUT, card->iobase + ALI_INTERRUPTSR);
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->enable &= ~CONTROLLER_SPDIFOUT_RUNNING;
- outl((1 << 23), card->iobase + 0x08);
- outb(0, card->iobase + CONTROLLERSPDIFOUT_CR);
- while (inb(card->iobase + CONTROLLERSPDIFOUT_CR) != 0)
- cpu_relax();
- outb(inb(card->iobase + CONTROLLERSPDIFOUT_SR) | 0x001e, card->iobase + CONTROLLERSPDIFOUT_SR);
- outl(inl(card->iobase + ALI_INTERRUPTSR) & INT_SPDIFOUT, card->iobase + ALI_INTERRUPTSR);
- }
- }
-}
-
-static void stop_spdifout(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __stop_spdifout(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static inline void __start_spdifout(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- if (dmabuf->count > 0 && dmabuf->ready && !dmabuf->enable &&
- (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- if (codec_independent_spdif_locked > 0) {
- dmabuf->enable |= CODEC_SPDIFOUT_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + CODECSPDIFOUT_CR);
- outl((1 << 3), state->card->iobase + 0x08); //dma control register
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->enable |= CONTROLLER_SPDIFOUT_RUNNING;
- outb((1 << 4) | (1 << 2), state->card->iobase + CONTROLLERSPDIFOUT_CR);
- outl((1 << 7), state->card->iobase + 0x08); //dma control register
- }
- }
- }
-}
-
-static void start_spdifout(struct ali_state *state)
-{
- struct ali_card *card = state->card;
- unsigned long flags;
- spin_lock_irqsave(&card->lock, flags);
- __start_spdifout(state);
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/* allocate DMA buffer, playback , recording,spdif out buffer should be allocated separately */
-static int alloc_dmabuf(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- void *rawbuf = NULL;
- int order, size;
- struct page *page, *pend;
-
- /* If we don't have any oss frag params, then use our default ones */
- if (dmabuf->ossmaxfrags == 0)
- dmabuf->ossmaxfrags = 4;
- if (dmabuf->ossfragsize == 0)
- dmabuf->ossfragsize = (PAGE_SIZE << DMABUF_DEFAULTORDER) / dmabuf->ossmaxfrags;
- size = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
-
- if (dmabuf->rawbuf && (PAGE_SIZE << dmabuf->buforder) == size)
- return 0;
- /* alloc enough to satisfy the oss params */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
- if ((PAGE_SIZE << order) > size)
- continue;
- if ((rawbuf = pci_alloc_consistent(state->card->pci_dev,
- PAGE_SIZE << order,
- &dmabuf->dma_handle)))
- break;
- }
- if (!rawbuf)
- return -ENOMEM;
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->rawbuf = rawbuf;
- dmabuf->buforder = order;
-
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(rawbuf); page <= pend; page++)
- SetPageReserved(page);
- return 0;
-}
-
-/* free DMA buffer */
-static void dealloc_dmabuf(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct page *page, *pend;
-
- if (dmabuf->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
- for (page = virt_to_page(dmabuf->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(state->card->pci_dev,
- PAGE_SIZE << dmabuf->buforder,
- dmabuf->rawbuf, dmabuf->dma_handle);
- }
- dmabuf->rawbuf = NULL;
- dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct ali_state *state, unsigned rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- struct ali_channel *c = NULL;
- struct sg_item *sg;
- unsigned long flags;
- int ret;
- unsigned fragint;
- int i;
-
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
-
- dmabuf->total_bytes = 0;
- dmabuf->count = dmabuf->error = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
-
- /* allocate DMA buffer, let alloc_dmabuf determine if we are already
- * allocated well enough or if we should replace the current buffer
- * (assuming one is already allocated, if it isn't, then allocate it).
- */
- if ((ret = alloc_dmabuf(state)))
- return ret;
-
- /* FIXME: figure out all this OSS fragment stuff */
- /* I did, it now does what it should according to the OSS API. DL */
- /* We may not have realloced our dmabuf, but the fragment size to
- * fragment number ratio may have changed, so go ahead and reprogram
- * things
- */
-
- dmabuf->dmasize = PAGE_SIZE << dmabuf->buforder;
- dmabuf->numfrag = SG_LEN;
- dmabuf->fragsize = dmabuf->dmasize / dmabuf->numfrag;
- dmabuf->fragsamples = dmabuf->fragsize >> 1;
- dmabuf->userfragsize = dmabuf->ossfragsize;
- dmabuf->userfrags = dmabuf->dmasize / dmabuf->ossfragsize;
-
- memset(dmabuf->rawbuf, 0, dmabuf->dmasize);
-
- if (dmabuf->ossmaxfrags == 4) {
- fragint = 8;
- dmabuf->fragshift = 2;
- } else if (dmabuf->ossmaxfrags == 8) {
- fragint = 4;
- dmabuf->fragshift = 3;
- } else if (dmabuf->ossmaxfrags == 16) {
- fragint = 2;
- dmabuf->fragshift = 4;
- } else {
- fragint = 1;
- dmabuf->fragshift = 5;
- }
- /*
- * Now set up the ring
- */
-
- if (rec == 1)
- c = dmabuf->read_channel;
- else if (rec == 2)
- c = dmabuf->codec_spdifout_channel;
- else if (rec == 3)
- c = dmabuf->controller_spdifout_channel;
- else if (rec == 0)
- c = dmabuf->write_channel;
- if (c != NULL) {
- sg = &c->sg[0];
- /*
- * Load up 32 sg entries and take an interrupt at half
- * way (we might want more interrupts later..)
- */
- for (i = 0; i < dmabuf->numfrag; i++) {
- sg->busaddr =
- virt_to_bus(dmabuf->rawbuf +
- dmabuf->fragsize * i);
- // the card will always be doing 16bit stereo
- sg->control = dmabuf->fragsamples;
- sg->control |= CON_BUFPAD; //I modify
- // set us up to get IOC interrupts as often as needed to
- // satisfy numfrag requirements, no more
- if (((i + 1) % fragint) == 0) {
- sg->control |= CON_IOC;
- }
- sg++;
- }
- spin_lock_irqsave(&state->card->lock, flags);
- outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */
- outl(virt_to_bus(&c->sg[0]), state->card->iobase + c->port + OFF_BDBAR);
- outb(0, state->card->iobase + c->port + OFF_CIV);
- outb(0, state->card->iobase + c->port + OFF_LVI);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- /* set the ready flag for the dma buffer */
- dmabuf->ready = 1;
- return 0;
-}
-
-static void __ali_update_lvi(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int x, port;
- port = state->card->iobase;
- if (rec == 1)
- port += dmabuf->read_channel->port;
- else if (rec == 2)
- port += dmabuf->codec_spdifout_channel->port;
- else if (rec == 3)
- port += dmabuf->controller_spdifout_channel->port;
- else if (rec == 0)
- port += dmabuf->write_channel->port;
- /* if we are currently stopped, then our CIV is actually set to our
- * *last* sg segment and we are ready to wrap to the next. However,
- * if we set our LVI to the last sg segment, then it won't wrap to
- * the next sg segment, it won't even get a start. So, instead, when
- * we are stopped, we set both the LVI value and also we increment
- * the CIV value to the next sg segment to be played so that when
- * we call start_{dac,adc}, things will operate properly
- */
- if (!dmabuf->enable && dmabuf->ready) {
- if (rec && dmabuf->count < dmabuf->dmasize && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_adc(state);
- while (! (inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else if (!rec && dmabuf->count && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_dac(state);
- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else if (rec && dmabuf->count && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- if (codec_independent_spdif_locked > 0) {
- // outb((inb(port+OFF_CIV))&31, port+OFF_LVI);
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_spdifout(state);
- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- } else {
- if (controller_independent_spdif_locked > 0) {
- outb((inb(port + OFF_CIV) + 1) & 31, port + OFF_LVI);
- __start_spdifout(state);
- while (!(inb(port + OFF_CR) & ((1 << 4) | (1 << 2))))
- cpu_relax();
- }
- }
- }
- }
-
- /* swptr - 1 is the tail of our transfer */
- x = (dmabuf->dmasize + dmabuf->swptr - 1) % dmabuf->dmasize;
- x /= dmabuf->fragsize;
- outb(x, port + OFF_LVI);
-}
-
-static void ali_update_lvi(struct ali_state *state, int rec)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- if (!dmabuf->ready)
- return;
- spin_lock_irqsave(&state->card->lock, flags);
- __ali_update_lvi(state, rec);
- spin_unlock_irqrestore(&state->card->lock, flags);
-}
-
-/* update buffer manangement pointers, especially, dmabuf->count and dmabuf->hwptr */
-static void ali_update_ptr(struct ali_state *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned hwptr;
- int diff;
-
- /* error handling and process wake up for DAC */
- if (dmabuf->enable == ADC_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 1);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count += diff;
- if (dmabuf->count > dmabuf->dmasize) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a read */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if ((inb(state->card->iobase + PI_CIV) & 31) != (inb(state->card->iobase + PI_LVI) & 31)) {
- printk(KERN_WARNING "ali_audio: DMA overrun on read\n");
- dmabuf->error++;
- }
- }
- if (dmabuf->count > dmabuf->userfragsize)
- wake_up(&dmabuf->wait);
- }
- /* error handling and process wake up for DAC */
- if (dmabuf->enable == DAC_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 0);
- diff =
- (dmabuf->dmasize + hwptr -
- dmabuf->hwptr) % dmabuf->dmasize;
-#if defined(DEBUG_INTERRUPTS) || defined(DEBUG_MMAP)
- printk("DAC HWP %d,%d,%d\n", hwptr, dmabuf->hwptr, diff);
-#endif
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count -= diff;
- if (dmabuf->count < 0) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a write */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if ((inb(state->card->iobase + PO_CIV) & 31) != (inb(state->card->iobase + PO_LVI) & 31)) {
- printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
- printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
- inb(state->card->iobase + PO_CIV) & 31,
- inb(state->card->iobase + PO_LVI) & 31,
- dmabuf->hwptr,
- dmabuf->count);
- dmabuf->error++;
- }
- }
- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
- wake_up(&dmabuf->wait);
- }
-
- /* error handling and process wake up for CODEC SPDIF OUT */
- if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 2);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count -= diff;
- if (dmabuf->count < 0) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a write */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if ((inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31)) {
- printk(KERN_WARNING "ali_audio: DMA overrun on write\n");
- printk(KERN_DEBUG "ali_audio: CIV %d, LVI %d, hwptr %x, count %d\n",
- inb(state->card->iobase + CODECSPDIFOUT_CIV) & 31,
- inb(state->card->iobase + CODECSPDIFOUT_LVI) & 31,
- dmabuf->hwptr, dmabuf->count);
- dmabuf->error++;
- }
- }
- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
- wake_up(&dmabuf->wait);
- }
- /* error handling and process wake up for CONTROLLER SPDIF OUT */
- if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
- /* update hardware pointer */
- hwptr = ali_get_dma_addr(state, 3);
- diff = (dmabuf->dmasize + hwptr - dmabuf->hwptr) % dmabuf->dmasize;
- dmabuf->hwptr = hwptr;
- dmabuf->total_bytes += diff;
- dmabuf->count -= diff;
- if (dmabuf->count < 0) {
- /* buffer underrun or buffer overrun */
- /* this is normal for the end of a write */
- /* only give an error if we went past the */
- /* last valid sg entry */
- if ((inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31) != (inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31)) {
- printk(KERN_WARNING
- "ali_audio: DMA overrun on write\n");
- printk("ali_audio: CIV %d, LVI %d, hwptr %x, "
- "count %d\n",
- inb(state->card->iobase + CONTROLLERSPDIFOUT_CIV) & 31,
- inb(state->card->iobase + CONTROLLERSPDIFOUT_LVI) & 31,
- dmabuf->hwptr, dmabuf->count);
- dmabuf->error++;
- }
- }
- if (dmabuf->count < (dmabuf->dmasize - dmabuf->userfragsize))
- wake_up(&dmabuf->wait);
- }
-}
-
-static inline int ali_get_free_write_space(struct
- ali_state
- *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int free;
-
- if (dmabuf->count < 0) {
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- }
- free = dmabuf->dmasize - dmabuf->swptr;
- if ((dmabuf->count + free) > dmabuf->dmasize){
- free = dmabuf->dmasize - dmabuf->count;
- }
- return free;
-}
-
-static inline int ali_get_available_read_data(struct
- ali_state
- *state)
-{
- struct dmabuf *dmabuf = &state->dmabuf;
- int avail;
- ali_update_ptr(state);
- // catch overruns during record
- if (dmabuf->count > dmabuf->dmasize) {
- dmabuf->count = dmabuf->dmasize;
- dmabuf->swptr = dmabuf->hwptr;
- }
- avail = dmabuf->count;
- avail -= (dmabuf->hwptr % dmabuf->fragsize);
- if (avail < 0)
- return (0);
- return (avail);
-}
-
-static int drain_dac(struct ali_state *state, int signals_allowed)
-{
-
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned long tmo;
- int count;
- if (!dmabuf->ready)
- return 0;
- if (dmabuf->mapped) {
- stop_dac(state);
- return 0;
- }
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
-
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- count = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
- if (count <= 0)
- break;
- /*
- * This will make sure that our LVI is correct, that our
- * pointer is updated, and that the DAC is running. We
- * have to force the setting of dmabuf->trigger to avoid
- * any possible deadlocks.
- */
- if (!dmabuf->enable) {
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- ali_update_lvi(state, 0);
- }
- if (signal_pending(current) && signals_allowed) {
- break;
- }
-
- /* It seems that we have to set the current state to
- * TASK_INTERRUPTIBLE every time to make the process
- * really go to sleep. This also has to be *after* the
- * update_ptr() call because update_ptr is likely to
- * do a wake_up() which will unset this before we ever
- * try to sleep, resuling in a tight loop in this code
- * instead of actually sleeping and waiting for an
- * interrupt to wake us up!
- */
- set_current_state(TASK_INTERRUPTIBLE);
- /*
- * set the timeout to significantly longer than it *should*
- * take for the DAC to drain the DMA buffer
- */
- tmo = (count * HZ) / (dmabuf->rate);
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
- printk(KERN_ERR "ali_audio: drain_dac, dma timeout?\n");
- count = 0;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &wait);
- if (count > 0 && signal_pending(current) && signals_allowed)
- return -ERESTARTSYS;
- stop_dac(state);
- return 0;
-}
-
-
-static int drain_spdifout(struct ali_state *state, int signals_allowed)
-{
-
- DECLARE_WAITQUEUE(wait, current);
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned long tmo;
- int count;
- if (!dmabuf->ready)
- return 0;
- if (dmabuf->mapped) {
- stop_spdifout(state);
- return 0;
- }
- add_wait_queue(&dmabuf->wait, &wait);
- for (;;) {
-
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- count = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
- if (count <= 0)
- break;
- /*
- * This will make sure that our LVI is correct, that our
- * pointer is updated, and that the DAC is running. We
- * have to force the setting of dmabuf->trigger to avoid
- * any possible deadlocks.
- */
- if (!dmabuf->enable) {
- if (codec_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 2);
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 3);
- }
- }
- }
- if (signal_pending(current) && signals_allowed) {
- break;
- }
-
- /* It seems that we have to set the current state to
- * TASK_INTERRUPTIBLE every time to make the process
- * really go to sleep. This also has to be *after* the
- * update_ptr() call because update_ptr is likely to
- * do a wake_up() which will unset this before we ever
- * try to sleep, resuling in a tight loop in this code
- * instead of actually sleeping and waiting for an
- * interrupt to wake us up!
- */
- set_current_state(TASK_INTERRUPTIBLE);
- /*
- * set the timeout to significantly longer than it *should*
- * take for the DAC to drain the DMA buffer
- */
- tmo = (count * HZ) / (dmabuf->rate);
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
- printk(KERN_ERR "ali_audio: drain_spdifout, dma timeout?\n");
- count = 0;
- break;
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &wait);
- if (count > 0 && signal_pending(current) && signals_allowed)
- return -ERESTARTSYS;
- stop_spdifout(state);
- return 0;
-}
-
-static void ali_channel_interrupt(struct ali_card *card)
-{
- int i, count;
-
- for (i = 0; i < NR_HW_CH; i++) {
- struct ali_state *state = card->states[i];
- struct ali_channel *c = NULL;
- struct dmabuf *dmabuf;
- unsigned long port = card->iobase;
- u16 status;
- if (!state)
- continue;
- if (!state->dmabuf.ready)
- continue;
- dmabuf = &state->dmabuf;
- if (codec_independent_spdif_locked > 0) {
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
- c = dmabuf->codec_spdifout_channel;
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- c = dmabuf->controller_spdifout_channel;
- } else {
- if (dmabuf->enable & DAC_RUNNING) {
- c = dmabuf->write_channel;
- } else if (dmabuf->enable & ADC_RUNNING) {
- c = dmabuf->read_channel;
- } else
- continue;
- }
- }
- port += c->port;
-
- status = inw(port + OFF_SR);
-
- if (status & DMA_INT_COMPLETE) {
- /* only wake_up() waiters if this interrupt signals
- * us being beyond a userfragsize of data open or
- * available, and ali_update_ptr() does that for
- * us
- */
- ali_update_ptr(state);
- }
-
- if (status & DMA_INT_LVI) {
- ali_update_ptr(state);
- wake_up(&dmabuf->wait);
-
- if (dmabuf->enable & DAC_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & ADC_RUNNING)
- count = dmabuf->dmasize - dmabuf->count;
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else count = 0;
-
- if (count > 0) {
- if (dmabuf->enable & DAC_RUNNING)
- outl((1 << 1), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- outl((1 << 3), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- outl((1 << 7), state->card->iobase + ALI_DMACR);
- } else {
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- dmabuf->enable = 0;
- wake_up(&dmabuf->wait);
- }
-
- }
- if (!(status & DMA_INT_DCH)) {
- ali_update_ptr(state);
- wake_up(&dmabuf->wait);
- if (dmabuf->enable & DAC_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & ADC_RUNNING)
- count = dmabuf->dmasize - dmabuf->count;
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- count = dmabuf->count;
- else
- count = 0;
-
- if (count > 0) {
- if (dmabuf->enable & DAC_RUNNING)
- outl((1 << 1), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- outl((1 << 3), state->card->iobase + ALI_DMACR);
- else if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- outl((1 << 7), state->card->iobase + ALI_DMACR);
- } else {
- if (dmabuf->enable & DAC_RUNNING)
- __stop_dac(state);
- if (dmabuf->enable & ADC_RUNNING)
- __stop_adc(state);
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)
- __stop_spdifout(state);
- dmabuf->enable = 0;
- wake_up(&dmabuf->wait);
- }
- }
- outw(status & DMA_INT_MASK, port + OFF_SR);
- }
-}
-
-static irqreturn_t ali_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct ali_card *card = (struct ali_card *) dev_id;
- u32 status;
- u16 status2;
-
- spin_lock(&card->lock);
- status = inl(card->iobase + ALI_INTERRUPTSR);
- if (!(status & INT_MASK)) {
- spin_unlock(&card->lock);
- return IRQ_NONE; /* not for us */
- }
-
- if (codec_independent_spdif_locked > 0) {
- if (globel == 0) {
- globel += 1;
- status2 = inw(card->iobase + 0x76);
- outw(status2 | 0x000c, card->iobase + 0x76);
- } else {
- if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
- ali_channel_interrupt(card);
- }
- } else {
- if (status & (INT_PCMOUT | INT_PCMIN | INT_MICIN | INT_SPDIFOUT | INT_CODECSPDIFOUT))
- ali_channel_interrupt(card);
- }
-
- /* clear 'em */
- outl(status & INT_MASK, card->iobase + ALI_INTERRUPTSR);
- spin_unlock(&card->lock);
- return IRQ_HANDLED;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is
- waiting to be copied to the user's buffer. It is filled by the dma
- machine and drained by this loop. */
-
-static ssize_t ali_read(struct file *file, char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_card *card = state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt;
- DECLARE_WAITQUEUE(waita, current);
-#ifdef DEBUG2
- printk("ali_audio: ali_read called, count = %d\n", count);
-#endif
- if (dmabuf->mapped)
- return -ENXIO;
- if (dmabuf->enable & DAC_RUNNING)
- return -ENODEV;
- if (!dmabuf->read_channel) {
- dmabuf->ready = 0;
- dmabuf->read_channel = card->alloc_rec_pcm_channel(card);
- if (!dmabuf->read_channel) {
- return -EBUSY;
- }
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- add_wait_queue(&dmabuf->wait, &waita);
- while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- continue;
- }
- swptr = dmabuf->swptr;
- cnt = ali_get_available_read_data(state);
- // this is to make the copy_to_user simpler below
- if (cnt > (dmabuf->dmasize - swptr))
- cnt = dmabuf->dmasize - swptr;
- spin_unlock_irqrestore(&card->lock, flags);
- if (cnt > count)
- cnt = count;
- /* Lop off the last two bits to force the code to always
- * write in full samples. This keeps software that sets
- * O_NONBLOCK but doesn't check the return value of the
- * write call from getting things out of state where they
- * think a full 4 byte sample was written when really only
- * a portion was, resulting in odd sound and stereo
- * hysteresis.
- */
- cnt &= ~0x3;
- if (cnt <= 0) {
- unsigned long tmo;
- /*
- * Don't let us deadlock. The ADC won't start if
- * dmabuf->trigger isn't set. A call to SETTRIGGER
- * could have turned it off after we set it to on
- * previously.
- */
- dmabuf->trigger = PCM_ENABLE_INPUT;
- /*
- * This does three things. Updates LVI to be correct,
- * makes sure the ADC is running, and updates the
- * hwptr.
- */
- ali_update_lvi(state, 1);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto done;
- }
- /* Set the timeout to how long it would take to fill
- * two of our buffers. If we haven't been woke up
- * by then, then we know something is wrong.
- */
- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
-
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer overrun. And worse, there is
- NOTHING we can do to prevent it. */
- if (!schedule_timeout(tmo >= 2 ? tmo : 2)) {
- printk(KERN_ERR
- "ali_audio: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- dmabuf->dmasize, dmabuf->fragsize,
- dmabuf->count, dmabuf->hwptr,
- dmabuf->swptr);
- /* a buffer overrun, we delay the recovery until next time the
- while loop begin and we REALLY have space to record */
- }
- if (signal_pending(current)) {
- ret = ret ? ret : -ERESTARTSYS;
- goto done;
- }
- continue;
- }
-
- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto done;
- }
-
- swptr = (swptr + cnt) % dmabuf->dmasize;
- spin_lock_irqsave(&card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- continue;
- }
- dmabuf->swptr = swptr;
- dmabuf->count -= cnt;
- spin_unlock_irqrestore(&card->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
-done:
- ali_update_lvi(state, 1);
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
- return ret;
-}
-
-/* in this loop, dmabuf.count signifies the amount of data that is waiting to be dma to
- the soundcard. it is drained by the dma machine and filled by this loop. */
-static ssize_t ali_write(struct file *file,
- const char __user *buffer, size_t count, loff_t * ppos)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_card *card = state ? state->card : NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr = 0;
- int cnt, x;
- DECLARE_WAITQUEUE(waita, current);
-#ifdef DEBUG2
- printk("ali_audio: ali_write called, count = %d\n", count);
-#endif
- if (dmabuf->mapped)
- return -ENXIO;
- if (dmabuf->enable & ADC_RUNNING)
- return -ENODEV;
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->codec_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card);
- if (!dmabuf->codec_spdifout_channel)
- return -EBUSY;
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->controller_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card);
- if (!dmabuf->controller_spdifout_channel)
- return -EBUSY;
- }
- } else {
- if (!dmabuf->write_channel) {
- dmabuf->ready = 0;
- dmabuf->write_channel =
- card->alloc_pcm_channel(card);
- if (!dmabuf->write_channel)
- return -EBUSY;
- }
- }
- }
-
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
- return ret;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
- return ret;
- } else {
-
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- }
- }
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- add_wait_queue(&dmabuf->wait, &waita);
- while (count > 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&state->card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- continue;
- }
-
- swptr = dmabuf->swptr;
- cnt = ali_get_free_write_space(state);
- /* Bound the maximum size to how much we can copy to the
- * dma buffer before we hit the end. If we have more to
- * copy then it will get done in a second pass of this
- * loop starting from the beginning of the buffer.
- */
- if (cnt > (dmabuf->dmasize - swptr))
- cnt = dmabuf->dmasize - swptr;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG2
- printk(KERN_INFO
- "ali_audio: ali_write: %d bytes available space\n",
- cnt);
-#endif
- if (cnt > count)
- cnt = count;
- /* Lop off the last two bits to force the code to always
- * write in full samples. This keeps software that sets
- * O_NONBLOCK but doesn't check the return value of the
- * write call from getting things out of state where they
- * think a full 4 byte sample was written when really only
- * a portion was, resulting in odd sound and stereo
- * hysteresis.
- */
- cnt &= ~0x3;
- if (cnt <= 0) {
- unsigned long tmo;
- // There is data waiting to be played
- /*
- * Force the trigger setting since we would
- * deadlock with it set any other way
- */
- if (codec_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 2);
- } else {
- if (controller_independent_spdif_locked > 0) {
- dmabuf->trigger = SPDIF_ENABLE_OUTPUT;
- ali_update_lvi(state, 3);
- } else {
-
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- ali_update_lvi(state, 0);
- }
- }
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto ret;
- }
- /* Not strictly correct but works */
- tmo = (dmabuf->dmasize * HZ * 2) / (dmabuf->rate * 4);
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer underrun. And worse, there is
- NOTHING we can do to prevent it. */
-
- /* FIXME - do timeout handling here !! */
- schedule_timeout(tmo >= 2 ? tmo : 2);
-
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto ret;
- }
- continue;
- }
- if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto ret;
- }
-
- swptr = (swptr + cnt) % dmabuf->dmasize;
- spin_lock_irqsave(&state->card->lock, flags);
- if (PM_SUSPENDED(card)) {
- spin_unlock_irqrestore(&card->lock, flags);
- continue;
- }
-
- dmabuf->swptr = swptr;
- dmabuf->count += cnt;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- if (swptr % dmabuf->fragsize) {
- x = dmabuf->fragsize - (swptr % dmabuf->fragsize);
- memset(dmabuf->rawbuf + swptr, '\0', x);
- }
-ret:
- if (codec_independent_spdif_locked > 0) {
- ali_update_lvi(state, 2);
- } else {
- if (controller_independent_spdif_locked > 0) {
- ali_update_lvi(state, 3);
- } else {
- ali_update_lvi(state, 0);
- }
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int ali_poll(struct file *file, struct poll_table_struct
- *wait)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- unsigned int mask = 0;
- if (!dmabuf->ready)
- return 0;
- poll_wait(file, &dmabuf->wait, wait);
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- if (file->f_mode & FMODE_READ && dmabuf->enable & ADC_RUNNING) {
- if (dmabuf->count >= (signed) dmabuf->fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE && (dmabuf->enable & (DAC_RUNNING|CODEC_SPDIFOUT_RUNNING|CONTROLLER_SPDIFOUT_RUNNING))) {
- if ((signed) dmabuf->dmasize >= dmabuf->count + (signed) dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
- return mask;
-}
-
-static int ali_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct dmabuf *dmabuf = &state->dmabuf;
- int ret = -EINVAL;
- unsigned long size;
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if (!dmabuf->write_channel && (dmabuf->write_channel = state->card->alloc_pcm_channel(state->card)) == NULL) {
- ret = -EBUSY;
- goto out;
- }
- }
- if (vma->vm_flags & VM_READ) {
- if (!dmabuf->read_channel && (dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card)) == NULL) {
- ret = -EBUSY;
- goto out;
- }
- }
- if ((ret = prog_dmabuf(state, 0)) != 0)
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << dmabuf->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- dmabuf->mapped = 1;
- dmabuf->trigger = 0;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int ali_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_channel *c = NULL;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- unsigned int i_scr;
- int val = 0, ret;
- struct ac97_codec *codec = state->card->ac97_codec[0];
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
-#ifdef DEBUG
- printk("ali_audio: ali_ioctl, arg=0x%x, cmd=",
- arg ? *p : 0);
-#endif
- switch (cmd) {
- case OSS_GETVERSION:
-#ifdef DEBUG
- printk("OSS_GETVERSION\n");
-#endif
- return put_user(SOUND_VERSION, p);
- case SNDCTL_DSP_RESET:
-#ifdef DEBUG
- printk("SNDCTL_DSP_RESET\n");
-#endif
- spin_lock_irqsave(&state->card->lock, flags);
- if (dmabuf->enable == DAC_RUNNING) {
- c = dmabuf->write_channel;
- __stop_dac(state);
- }
- if (dmabuf->enable == ADC_RUNNING) {
- c = dmabuf->read_channel;
- __stop_adc(state);
- }
- if (dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
- c = dmabuf->codec_spdifout_channel;
- __stop_spdifout(state);
- }
- if (dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
- c = dmabuf->controller_spdifout_channel;
- __stop_spdifout(state);
- }
- if (c != NULL) {
- outb(2, state->card->iobase + c->port + OFF_CR); /* reset DMA machine */
- outl(virt_to_bus(&c->sg[0]),
- state->card->iobase + c->port + OFF_BDBAR);
- outb(0, state->card->iobase + c->port + OFF_CIV);
- outb(0, state->card->iobase + c->port + OFF_LVI);
- }
-
- spin_unlock_irqrestore(&state->card->lock, flags);
- synchronize_irq(state->card->pci_dev->irq);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- return 0;
- case SNDCTL_DSP_SYNC:
-#ifdef DEBUG
- printk("SNDCTL_DSP_SYNC\n");
-#endif
- if (codec_independent_spdif_locked > 0) {
- if (dmabuf->enable != CODEC_SPDIFOUT_RUNNING
- || file->f_flags & O_NONBLOCK)
- return 0;
- if ((val = drain_spdifout(state, 1)))
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (dmabuf->enable !=
- CONTROLLER_SPDIFOUT_RUNNING
- || file->f_flags & O_NONBLOCK)
- return 0;
- if ((val = drain_spdifout(state, 1)))
- return val;
- } else {
- if (dmabuf->enable != DAC_RUNNING
- || file->f_flags & O_NONBLOCK)
- return 0;
- if ((val = drain_dac(state, 1)))
- return val;
- }
- }
- dmabuf->total_bytes = 0;
- return 0;
- case SNDCTL_DSP_SPEED: /* set smaple rate */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SPEED\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_WRITE) {
- if ((state->card->ac97_status & SPDIF_ON)) { /* S/PDIF Enabled */
- /* RELTEK ALC650 only support 48000, need to check that */
- if (ali_valid_spdif_rate(codec, val)) {
- if (codec_independent_spdif_locked > 0) {
- ali_set_spdif_output(state, -1, 0);
- stop_spdifout(state);
- dmabuf->ready = 0;
- /* I add test codec independent spdif out */
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_codecspdifout_rate(state, val); // I modified
- spin_unlock_irqrestore(&state->card->lock, flags);
- /* Set S/PDIF transmitter rate. */
- i_scr = inl(state->card->iobase + ALI_SCR);
- if ((i_scr & 0x00300000) == 0x00100000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- } else {
- if ((i_scr&0x00300000) == 0x00200000)
- {
- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00300000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
- } else {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- }
- }
- }
-
- if (!(state->card->ac97_status & SPDIF_ON)) {
- val = dmabuf->rate;
- }
- } else {
- if (controller_independent_spdif_locked > 0)
- {
- stop_spdifout(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_spdifout_rate(state, controller_independent_spdif_locked);
- spin_unlock_irqrestore(&state->card->lock, flags);
- } else {
- /* Set DAC rate */
- ali_set_spdif_output(state, -1, 0);
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- /* Set S/PDIF transmitter rate. */
- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, val);
- if (!(state->card->ac97_status & SPDIF_ON))
- {
- val = dmabuf->rate;
- }
- }
- }
- } else { /* Not a valid rate for S/PDIF, ignore it */
- val = dmabuf->rate;
- }
- } else {
- stop_dac(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_dac_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(state);
- dmabuf->ready = 0;
- spin_lock_irqsave(&state->card->lock, flags);
- ali_set_adc_rate(state, val);
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- }
- return put_user(dmabuf->rate, p);
- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
-#ifdef DEBUG
- printk("SNDCTL_DSP_STEREO\n");
-#endif
- if (dmabuf->enable & DAC_RUNNING) {
- stop_dac(state);
- }
- if (dmabuf->enable & ADC_RUNNING) {
- stop_adc(state);
- }
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- return put_user(1, p);
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)))
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)))
- return val;
- } else {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)))
- return val;
- }
- }
- }
-
- if (file->f_mode & FMODE_READ) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)))
- return val;
- }
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETBLKSIZE %d\n", dmabuf->userfragsize);
-#endif
- return put_user(dmabuf->userfragsize, p);
- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format */
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETFMTS\n");
-#endif
- return put_user(AFMT_S16_LE, p);
- case SNDCTL_DSP_SETFMT: /* Select sample format */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETFMT\n");
-#endif
- return put_user(AFMT_S16_LE, p);
- case SNDCTL_DSP_CHANNELS: // add support 4,6 channel
-#ifdef DEBUG
- printk("SNDCTL_DSP_CHANNELS\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- if (val > 0) {
- if (dmabuf->enable & DAC_RUNNING) {
- stop_dac(state);
- }
- if (dmabuf->enable & CODEC_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (dmabuf->enable & ADC_RUNNING) {
- stop_adc(state);
- }
- } else {
- return put_user(state->card->channels, p);
- }
-
- i_scr = inl(state->card->iobase + ALI_SCR);
- /* Current # of channels enabled */
- if (i_scr & 0x00000100)
- ret = 4;
- else if (i_scr & 0x00000200)
- ret = 6;
- else
- ret = 2;
- switch (val) {
- case 2: /* 2 channels is always supported */
- if (codec_independent_spdif_locked > 0) {
- outl(((i_scr & 0xfffffcff) | 0x00100000), (state->card->iobase + ALI_SCR));
- } else
- outl((i_scr & 0xfffffcff), (state->card->iobase + ALI_SCR));
- /* Do we need to change mixer settings???? */
- break;
- case 4: /* Supported on some chipsets, better check first */
- if (codec_independent_spdif_locked > 0) {
- outl(((i_scr & 0xfffffcff) | 0x00000100 | 0x00200000), (state->card->iobase + ALI_SCR));
- } else
- outl(((i_scr & 0xfffffcff) | 0x00000100), (state->card->iobase + ALI_SCR));
- break;
- case 6: /* Supported on some chipsets, better check first */
- if (codec_independent_spdif_locked > 0) {
- outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000 | 0x00300000), (state->card->iobase + ALI_SCR));
- } else
- outl(((i_scr & 0xfffffcff) | 0x00000200 | 0x00008000), (state->card->iobase + ALI_SCR));
- break;
- default: /* nothing else is ever supported by the chipset */
- val = ret;
- break;
- }
- return put_user(val, p);
- case SNDCTL_DSP_POST: /* the user has sent all data and is notifying us */
- /* we update the swptr to the end of the last sg segment then return */
-#ifdef DEBUG
- printk("SNDCTL_DSP_POST\n");
-#endif
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready || (dmabuf->enable != CODEC_SPDIFOUT_RUNNING))
- return 0;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready || (dmabuf->enable != CONTROLLER_SPDIFOUT_RUNNING))
- return 0;
- } else {
- if (!dmabuf->ready || (dmabuf->enable != DAC_RUNNING))
- return 0;
- }
- }
- if ((dmabuf->swptr % dmabuf->fragsize) != 0) {
- val = dmabuf->fragsize - (dmabuf->swptr % dmabuf->fragsize);
- dmabuf->swptr += val;
- dmabuf->count += val;
- }
- return 0;
- case SNDCTL_DSP_SUBDIVIDE:
- if (dmabuf->subdivision)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
-#ifdef DEBUG
- printk("SNDCTL_DSP_SUBDIVIDE %d\n", val);
-#endif
- dmabuf->subdivision = val;
- dmabuf->ready = 0;
- return 0;
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- dmabuf->ossfragsize = 1 << (val & 0xffff);
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- if (!dmabuf->ossfragsize || !dmabuf->ossmaxfrags)
- return -EINVAL;
- /*
- * Bound the frag size into our allowed range of 256 - 4096
- */
- if (dmabuf->ossfragsize < 256)
- dmabuf->ossfragsize = 256;
- else if (dmabuf->ossfragsize > 4096)
- dmabuf->ossfragsize = 4096;
- /*
- * The numfrags could be something reasonable, or it could
- * be 0xffff meaning "Give me as much as possible". So,
- * we check the numfrags * fragsize doesn't exceed our
- * 64k buffer limit, nor is it less than our 8k minimum.
- * If it fails either one of these checks, then adjust the
- * number of fragments, not the size of them. It's OK if
- * our number of fragments doesn't equal 32 or anything
- * like our hardware based number now since we are using
- * a different frag count for the hardware. Before we get
- * into this though, bound the maxfrags to avoid overflow
- * issues. A reasonable bound would be 64k / 256 since our
- * maximum buffer size is 64k and our minimum frag size is
- * 256. On the other end, our minimum buffer size is 8k and
- * our maximum frag size is 4k, so the lower bound should
- * be 2.
- */
- if (dmabuf->ossmaxfrags > 256)
- dmabuf->ossmaxfrags = 256;
- else if (dmabuf->ossmaxfrags < 2)
- dmabuf->ossmaxfrags = 2;
- val = dmabuf->ossfragsize * dmabuf->ossmaxfrags;
- while (val < 8192) {
- val <<= 1;
- dmabuf->ossmaxfrags <<= 1;
- }
- while (val > 65536) {
- val >>= 1;
- dmabuf->ossmaxfrags >>= 1;
- }
- dmabuf->ready = 0;
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETFRAGMENT 0x%x, %d, %d\n", val,
- dmabuf->ossfragsize, dmabuf->ossmaxfrags);
-#endif
- return 0;
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
- return val;
- } else {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- }
- }
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- abinfo.fragsize = dmabuf->userfragsize;
- abinfo.fragstotal = dmabuf->userfrags;
- if (dmabuf->mapped)
- abinfo.bytes = dmabuf->dmasize;
- else
- abinfo.bytes = ali_get_free_write_space(state);
- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETOSPACE %d, %d, %d, %d\n",
- abinfo.bytes, abinfo.fragsize, abinfo.fragments,
- abinfo.fragstotal);
-#endif
- return copy_to_user(argp, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (codec_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 2)) != 0)
- return val;
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 3)) != 0)
- return val;
- } else {
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- }
- }
- spin_lock_irqsave(&state->card->lock, flags);
- val = ali_get_free_write_space(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.ptr = dmabuf->hwptr;
- cinfo.blocks = val / dmabuf->userfragsize;
- if (codec_independent_spdif_locked > 0) {
- if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __ali_update_lvi(state, 2);
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if (dmabuf->mapped && (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __ali_update_lvi(state, 3);
- }
- } else {
- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_OUTPUT)) {
- dmabuf->count += val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __ali_update_lvi(state, 0);
- }
- }
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETOPTR %d, %d, %d, %d\n", cinfo.bytes,
- cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
- return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT : 0;
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- abinfo.bytes = ali_get_available_read_data(state);
- abinfo.fragsize = dmabuf->userfragsize;
- abinfo.fragstotal = dmabuf->userfrags;
- abinfo.fragments = abinfo.bytes / dmabuf->userfragsize;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETISPACE %d, %d, %d, %d\n",
- abinfo.bytes, abinfo.fragsize, abinfo.fragments,
- abinfo.fragstotal);
-#endif
- return copy_to_user(argp, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- spin_lock_irqsave(&state->card->lock, flags);
- val = ali_get_available_read_data(state);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = val / dmabuf->userfragsize;
- cinfo.ptr = dmabuf->hwptr;
- if (dmabuf->mapped && (dmabuf->trigger & PCM_ENABLE_INPUT)) {
- dmabuf->count -= val;
- dmabuf->swptr = (dmabuf->swptr + val) % dmabuf->dmasize;
- __ali_update_lvi(state, 1);
- }
- spin_unlock_irqrestore(&state->card->lock, flags);
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_GETIPTR %d, %d, %d, %d\n", cinfo.bytes,
- cinfo.blocks, cinfo.ptr, dmabuf->count);
-#endif
- return copy_to_user(argp, &cinfo, sizeof(cinfo))? -EFAULT: 0;
- case SNDCTL_DSP_NONBLOCK:
-#ifdef DEBUG
- printk("SNDCTL_DSP_NONBLOCK\n");
-#endif
- file->f_flags |= O_NONBLOCK;
- return 0;
- case SNDCTL_DSP_GETCAPS:
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETCAPS\n");
-#endif
- return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER |
- DSP_CAP_MMAP | DSP_CAP_BIND, p);
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETTRIGGER 0x%x\n", dmabuf->trigger);
-#endif
- return put_user(dmabuf->trigger, p);
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
-#if defined(DEBUG) || defined(DEBUG_MMAP)
- printk("SNDCTL_DSP_SETTRIGGER 0x%x\n", val);
-#endif
- if (!(val & PCM_ENABLE_INPUT) && dmabuf->enable == ADC_RUNNING) {
- stop_adc(state);
- }
- if (!(val & PCM_ENABLE_OUTPUT) && dmabuf->enable == DAC_RUNNING) {
- stop_dac(state);
- }
- if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CODEC_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- if (!(val & SPDIF_ENABLE_OUTPUT) && dmabuf->enable == CONTROLLER_SPDIFOUT_RUNNING) {
- stop_spdifout(state);
- }
- dmabuf->trigger = val;
- if (val & PCM_ENABLE_OUTPUT && !(dmabuf->enable & DAC_RUNNING)) {
- if (!dmabuf->write_channel) {
- dmabuf->ready = 0;
- dmabuf->write_channel = state->card->alloc_pcm_channel(state->card);
- if (!dmabuf->write_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = ali_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- __ali_update_lvi(state, 0);
- spin_unlock_irqrestore(&state->card->lock,
- flags);
- } else
- start_dac(state);
- }
- if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CODEC_SPDIFOUT_RUNNING)) {
- if (!dmabuf->codec_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->codec_spdifout_channel = state->card->alloc_codec_spdifout_channel(state->card);
- if (!dmabuf->codec_spdifout_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 2)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = ali_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- __ali_update_lvi(state, 2);
- spin_unlock_irqrestore(&state->card->lock,
- flags);
- } else
- start_spdifout(state);
- }
- if (val & SPDIF_ENABLE_OUTPUT && !(dmabuf->enable & CONTROLLER_SPDIFOUT_RUNNING)) {
- if (!dmabuf->controller_spdifout_channel) {
- dmabuf->ready = 0;
- dmabuf->controller_spdifout_channel = state->card->alloc_controller_spdifout_channel(state->card);
- if (!dmabuf->controller_spdifout_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 3)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- dmabuf->count = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = ali_get_free_write_space(state);
- dmabuf->swptr = (dmabuf->swptr + dmabuf->count) % dmabuf->dmasize;
- __ali_update_lvi(state, 3);
- spin_unlock_irqrestore(&state->card->lock, flags);
- } else
- start_spdifout(state);
- }
- if (val & PCM_ENABLE_INPUT && !(dmabuf->enable & ADC_RUNNING)) {
- if (!dmabuf->read_channel) {
- dmabuf->ready = 0;
- dmabuf->read_channel = state->card->alloc_rec_pcm_channel(state->card);
- if (!dmabuf->read_channel)
- return -EBUSY;
- }
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- if (dmabuf->mapped) {
- spin_lock_irqsave(&state->card->lock,
- flags);
- ali_update_ptr(state);
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = 0;
- spin_unlock_irqrestore(&state->card->lock, flags);
- }
- ali_update_lvi(state, 1);
- start_adc(state);
- }
- return 0;
- case SNDCTL_DSP_SETDUPLEX:
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETDUPLEX\n");
-#endif
- return -EINVAL;
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&state->card->lock, flags);
- ali_update_ptr(state);
- val = dmabuf->count;
- spin_unlock_irqrestore(&state->card->lock, flags);
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETODELAY %d\n", dmabuf->count);
-#endif
- return put_user(val, p);
- case SOUND_PCM_READ_RATE:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_RATE %d\n", dmabuf->rate);
-#endif
- return put_user(dmabuf->rate, p);
- case SOUND_PCM_READ_CHANNELS:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_CHANNELS\n");
-#endif
- return put_user(2, p);
- case SOUND_PCM_READ_BITS:
-#ifdef DEBUG
- printk("SOUND_PCM_READ_BITS\n");
-#endif
- return put_user(AFMT_S16_LE, p);
- case SNDCTL_DSP_SETSPDIF: /* Set S/PDIF Control register */
-#ifdef DEBUG
- printk("SNDCTL_DSP_SETSPDIF\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- /* Check to make sure the codec supports S/PDIF transmitter */
- if ((state->card->ac97_features & 4)) {
- /* mask out the transmitter speed bits so the user can't set them */
- val &= ~0x3000;
- /* Add the current transmitter speed bits to the passed value */
- ret = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
- val |= (ret & 0x3000);
- ali_ac97_set(codec, AC97_SPDIF_CONTROL, val);
- if (ali_ac97_get(codec, AC97_SPDIF_CONTROL) != val) {
- printk(KERN_ERR "ali_audio: Unable to set S/PDIF configuration to 0x%04x.\n", val);
- return -EFAULT;
- }
- }
-#ifdef DEBUG
- else
- printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
-#endif
- return put_user(val, p);
- case SNDCTL_DSP_GETSPDIF: /* Get S/PDIF Control register */
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETSPDIF\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- /* Check to make sure the codec supports S/PDIF transmitter */
- if (!(state->card->ac97_features & 4)) {
-#ifdef DEBUG
- printk(KERN_WARNING "ali_audio: S/PDIF transmitter not avalible.\n");
-#endif
- val = 0;
- } else {
- val = ali_ac97_get(codec, AC97_SPDIF_CONTROL);
- }
-
- return put_user(val, p);
-//end add support spdif out
-//add support 4,6 channel
- case SNDCTL_DSP_GETCHANNELMASK:
-#ifdef DEBUG
- printk("SNDCTL_DSP_GETCHANNELMASK\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- /* Based on AC'97 DAC support, not ICH hardware */
- val = DSP_BIND_FRONT;
- if (state->card->ac97_features & 0x0004)
- val |= DSP_BIND_SPDIF;
- if (state->card->ac97_features & 0x0080)
- val |= DSP_BIND_SURR;
- if (state->card->ac97_features & 0x0140)
- val |= DSP_BIND_CENTER_LFE;
- return put_user(val, p);
- case SNDCTL_DSP_BIND_CHANNEL:
-#ifdef DEBUG
- printk("SNDCTL_DSP_BIND_CHANNEL\n");
-#endif
- if (get_user(val, p))
- return -EFAULT;
- if (val == DSP_BIND_QUERY) {
- val = DSP_BIND_FRONT; /* Always report this as being enabled */
- if (state->card->ac97_status & SPDIF_ON)
- val |= DSP_BIND_SPDIF;
- else {
- if (state->card->ac97_status & SURR_ON)
- val |= DSP_BIND_SURR;
- if (state->card->
- ac97_status & CENTER_LFE_ON)
- val |= DSP_BIND_CENTER_LFE;
- }
- } else { /* Not a query, set it */
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (dmabuf->enable == DAC_RUNNING) {
- stop_dac(state);
- }
- if (val & DSP_BIND_SPDIF) { /* Turn on SPDIF */
- /* Ok, this should probably define what slots
- * to use. For now, we'll only set it to the
- * defaults:
- *
- * non multichannel codec maps to slots 3&4
- * 2 channel codec maps to slots 7&8
- * 4 channel codec maps to slots 6&9
- * 6 channel codec maps to slots 10&11
- *
- * there should be some way for the app to
- * select the slot assignment.
- */
- i_scr = inl(state->card->iobase + ALI_SCR);
- if (codec_independent_spdif_locked > 0) {
-
- if ((i_scr & 0x00300000) == 0x00100000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00200000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00300000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
- }
- }
- }
- } else { /* codec spdif out (pcm out share ) */
- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, dmabuf->rate); //I do not modify
- }
-
- if (!(state->card->ac97_status & SPDIF_ON))
- val &= ~DSP_BIND_SPDIF;
- } else {
- int mask;
- int channels;
- /* Turn off S/PDIF if it was on */
- if (state->card->ac97_status & SPDIF_ON)
- ali_set_spdif_output(state, -1, 0);
- mask =
- val & (DSP_BIND_FRONT | DSP_BIND_SURR |
- DSP_BIND_CENTER_LFE);
- switch (mask) {
- case DSP_BIND_FRONT:
- channels = 2;
- break;
- case DSP_BIND_FRONT | DSP_BIND_SURR:
- channels = 4;
- break;
- case DSP_BIND_FRONT | DSP_BIND_SURR | DSP_BIND_CENTER_LFE:
- channels = 6;
- break;
- default:
- val = DSP_BIND_FRONT;
- channels = 2;
- break;
- }
- ali_set_dac_channels(state, channels);
- /* check that they really got turned on */
- if (!state->card->ac97_status & SURR_ON)
- val &= ~DSP_BIND_SURR;
- if (!state->card->
- ac97_status & CENTER_LFE_ON)
- val &= ~DSP_BIND_CENTER_LFE;
- }
- }
- return put_user(val, p);
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
- }
- return -EINVAL;
-}
-
-static int ali_open(struct inode *inode, struct file *file)
-{
- int i = 0;
- struct ali_card *card = devs;
- struct ali_state *state = NULL;
- struct dmabuf *dmabuf = NULL;
- unsigned int i_scr;
-
- /* find an available virtual channel (instance of /dev/dsp) */
-
- while (card != NULL) {
-
- /*
- * If we are initializing and then fail, card could go
- * away unuexpectedly while we are in the for() loop.
- * So, check for card on each iteration before we check
- * for card->initializing to avoid a possible oops.
- * This usually only matters for times when the driver is
- * autoloaded by kmod.
- */
- for (i = 0; i < 50 && card && card->initializing; i++) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 20);
- }
-
- for (i = 0; i < NR_HW_CH && card && !card->initializing; i++) {
- if (card->states[i] == NULL) {
- state = card->states[i] = (struct ali_state *) kmalloc(sizeof(struct ali_state), GFP_KERNEL);
- if (state == NULL)
- return -ENOMEM;
- memset(state, 0, sizeof(struct ali_state));
- dmabuf = &state->dmabuf;
- goto found_virt;
- }
- }
- card = card->next;
- }
-
- /* no more virtual channel avaiable */
- if (!state)
- return -ENODEV;
-found_virt:
- /* initialize the virtual channel */
-
- state->virt = i;
- state->card = card;
- state->magic = ALI5455_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- file->private_data = state;
- dmabuf->trigger = 0;
- /* allocate hardware channels */
- if (file->f_mode & FMODE_READ) {
- if ((dmabuf->read_channel =
- card->alloc_rec_pcm_channel(card)) == NULL) {
- kfree(card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- dmabuf->trigger |= PCM_ENABLE_INPUT;
- ali_set_adc_rate(state, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (codec_independent_spdif_locked > 0) {
- if ((dmabuf->codec_spdifout_channel = card->alloc_codec_spdifout_channel(card)) == NULL) {
- kfree(card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
- ali_set_codecspdifout_rate(state, codec_independent_spdif_locked); //It must add
- i_scr = inl(state->card->iobase + ALI_SCR);
- if ((i_scr & 0x00300000) == 0x00100000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00200000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_6_9, codec_independent_spdif_locked);
- } else {
- if ((i_scr & 0x00300000) == 0x00300000) {
- ali_set_spdif_output(state, AC97_EA_SPSA_10_11, codec_independent_spdif_locked);
- } else {
- ali_set_spdif_output(state, AC97_EA_SPSA_7_8, codec_independent_spdif_locked);
- }
- }
-
- }
- } else {
- if (controller_independent_spdif_locked > 0) {
- if ((dmabuf->controller_spdifout_channel = card->alloc_controller_spdifout_channel(card)) == NULL) {
- kfree(card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- dmabuf->trigger |= SPDIF_ENABLE_OUTPUT;
- ali_set_spdifout_rate(state, controller_independent_spdif_locked);
- } else {
- if ((dmabuf->write_channel = card->alloc_pcm_channel(card)) == NULL) {
- kfree(card->states[i]);
- card->states[i] = NULL;
- return -EBUSY;
- }
- /* Initialize to 8kHz? What if we don't support 8kHz? */
- /* Let's change this to check for S/PDIF stuff */
-
- dmabuf->trigger |= PCM_ENABLE_OUTPUT;
- if (codec_pcmout_share_spdif_locked) {
- ali_set_dac_rate(state, codec_pcmout_share_spdif_locked);
- ali_set_spdif_output(state, AC97_EA_SPSA_3_4, codec_pcmout_share_spdif_locked);
- } else {
- ali_set_dac_rate(state, 8000);
- }
- }
-
- }
- }
-
- /* set default sample format. According to OSS Programmer's Guide /dev/dsp
- should be default to unsigned 8-bits, mono, with sample rate 8kHz and
- /dev/dspW will accept 16-bits sample, but we don't support those so we
- set it immediately to stereo and 16bit, which is all we do support */
- dmabuf->fmt |= ALI5455_FMT_16BIT | ALI5455_FMT_STEREO;
- dmabuf->ossfragsize = 0;
- dmabuf->ossmaxfrags = 0;
- dmabuf->subdivision = 0;
- state->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
- outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
- return nonseekable_open(inode, file);
-}
-
-static int ali_release(struct inode *inode, struct file *file)
-{
- struct ali_state *state = (struct ali_state *) file->private_data;
- struct ali_card *card = state->card;
- struct dmabuf *dmabuf = &state->dmabuf;
- unsigned long flags;
- lock_kernel();
-
- /* stop DMA state machine and free DMA buffers/channels */
- if (dmabuf->trigger & PCM_ENABLE_OUTPUT)
- drain_dac(state, 0);
-
- if (dmabuf->trigger & SPDIF_ENABLE_OUTPUT)
- drain_spdifout(state, 0);
-
- if (dmabuf->trigger & PCM_ENABLE_INPUT)
- stop_adc(state);
-
- spin_lock_irqsave(&card->lock, flags);
- dealloc_dmabuf(state);
- if (file->f_mode & FMODE_WRITE) {
- if (codec_independent_spdif_locked > 0) {
- state->card->free_pcm_channel(state->card, dmabuf->codec_spdifout_channel->num);
- } else {
- if (controller_independent_spdif_locked > 0)
- state->card->free_pcm_channel(state->card,
- dmabuf->controller_spdifout_channel->num);
- else state->card->free_pcm_channel(state->card,
- dmabuf->write_channel->num);
- }
- }
- if (file->f_mode & FMODE_READ)
- state->card->free_pcm_channel(state->card, dmabuf->read_channel->num);
-
- state->card->states[state->virt] = NULL;
- kfree(state);
- spin_unlock_irqrestore(&card->lock, flags);
- unlock_kernel();
- return 0;
-}
-
-static /*const */ struct file_operations ali_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ali_read,
- .write = ali_write,
- .poll = ali_poll,
- .ioctl = ali_ioctl,
- .mmap = ali_mmap,
- .open = ali_open,
- .release = ali_release,
-};
-
-/* Read AC97 codec registers */
-static u16 ali_ac97_get(struct ac97_codec *dev, u8 reg)
-{
- struct ali_card *card = dev->private_data;
- int count1 = 100;
- char val;
- unsigned short int data = 0, count, addr1, addr2 = 0;
-
- spin_lock(&card->ac97_lock);
- while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
- udelay(1);
-
- addr1 = reg;
- reg |= 0x0080;
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x08)
- break;
- }
- if (count == 0x7f)
- {
- spin_unlock(&card->ac97_lock);
- return -1;
- }
- outw(reg, (card->iobase + ALI_CPR) + 2);
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x02) {
- data = inw(card->iobase + ALI_SPR);
- addr2 = inw((card->iobase + ALI_SPR) + 2);
- break;
- }
- }
- spin_unlock(&card->ac97_lock);
- if (count == 0x7f)
- return -1;
- if (addr2 != addr1)
- return -1;
- return ((u16) data);
-}
-
-/* write ac97 codec register */
-
-static void ali_ac97_set(struct ac97_codec *dev, u8 reg, u16 data)
-{
- struct ali_card *card = dev->private_data;
- int count1 = 100;
- char val;
- unsigned short int count;
-
- spin_lock(&card->ac97_lock);
- while (count1-- && (inl(card->iobase + ALI_CAS) & 0x80000000))
- udelay(1);
-
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x08)
- break;
- }
- if (count == 0x7f) {
- printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
- spin_unlock(&card->ac97_lock);
- return;
- }
- outw(data, (card->iobase + ALI_CPR));
- outb(reg, (card->iobase + ALI_CPR) + 2);
- for (count = 0; count < 0x7f; count++) {
- val = inb(card->iobase + ALI_CSPSR);
- if (val & 0x01)
- break;
- }
- spin_unlock(&card->ac97_lock);
- if (count == 0x7f)
- printk(KERN_WARNING "ali_ac97_set: AC97 codec register access timed out. \n");
- return;
-}
-
-/* OSS /dev/mixer file operation methods */
-
-static int ali_open_mixdev(struct inode *inode, struct file *file)
-{
- int i;
- int minor = iminor(inode);
- struct ali_card *card = devs;
- for (card = devs; card != NULL; card = card->next) {
- /*
- * If we are initializing and then fail, card could go
- * away unuexpectedly while we are in the for() loop.
- * So, check for card on each iteration before we check
- * for card->initializing to avoid a possible oops.
- * This usually only matters for times when the driver is
- * autoloaded by kmod.
- */
- for (i = 0; i < 50 && card && card->initializing; i++) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 20);
- }
- for (i = 0; i < NR_AC97 && card && !card->initializing; i++)
- if (card->ac97_codec[i] != NULL
- && card->ac97_codec[i]->dev_mixer == minor) {
- file->private_data = card->ac97_codec[i];
- return nonseekable_open(inode, file);
- }
- }
- return -ENODEV;
-}
-
-static int ali_ioctl_mixdev(struct inode *inode,
- struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static /*const */ struct file_operations ali_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = ali_ioctl_mixdev,
- .open = ali_open_mixdev,
-};
-
-/* AC97 codec initialisation. These small functions exist so we don't
- duplicate code between module init and apm resume */
-
-static inline int ali_ac97_exists(struct ali_card *card, int ac97_number)
-{
- unsigned int i = 1;
- u32 reg = inl(card->iobase + ALI_RTSR);
- if (ac97_number) {
- while (i < 100) {
-
- reg = inl(card->iobase + ALI_RTSR);
- if (reg & 0x40) {
- break;
- } else {
- outl(reg | 0x00000040,
- card->iobase + 0x34);
- udelay(1);
- }
- i++;
- }
-
- } else {
- while (i < 100) {
- reg = inl(card->iobase + ALI_RTSR);
- if (reg & 0x80) {
- break;
- } else {
- outl(reg | 0x00000080,
- card->iobase + 0x34);
- udelay(1);
- }
- i++;
- }
- }
-
- if (ac97_number)
- return reg & 0x40;
- else
- return reg & 0x80;
-}
-
-static inline int ali_ac97_enable_variable_rate(struct ac97_codec *codec)
-{
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, 9);
- ali_ac97_set(codec, AC97_EXTENDED_STATUS, ali_ac97_get(codec, AC97_EXTENDED_STATUS) | 0xE800);
- return (ali_ac97_get(codec, AC97_EXTENDED_STATUS) & 1);
-}
-
-
-static int ali_ac97_probe_and_powerup(struct ali_card *card, struct ac97_codec *codec)
-{
- /* Returns 0 on failure */
- int i;
- u16 addr;
- if (ac97_probe_codec(codec) == 0)
- return 0;
- /* ac97_probe_codec is success ,then begin to init codec */
- ali_ac97_set(codec, AC97_RESET, 0xffff);
- if (card->channel[0].used == 1) {
- ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
- ali_ac97_set(codec, AC97_LINEIN_VOL, 0x0808);
- ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
- }
-
- if (card->channel[2].used == 1) //if MICin then init codec
- {
- ali_ac97_set(codec, AC97_RECORD_SELECT, 0x0000);
- ali_ac97_set(codec, AC97_MIC_VOL, 0x8808);
- ali_ac97_set(codec, AC97_RECORD_GAIN, 0x0F0F);
- ali_ac97_set(codec, AC97_RECORD_GAIN_MIC, 0x0000);
- }
-
- ali_ac97_set(codec, AC97_MASTER_VOL_STEREO, 0x0000);
- ali_ac97_set(codec, AC97_HEADPHONE_VOL, 0x0000);
- ali_ac97_set(codec, AC97_PCMOUT_VOL, 0x0000);
- ali_ac97_set(codec, AC97_CD_VOL, 0x0808);
- ali_ac97_set(codec, AC97_VIDEO_VOL, 0x0808);
- ali_ac97_set(codec, AC97_AUX_VOL, 0x0808);
- ali_ac97_set(codec, AC97_PHONE_VOL, 0x8048);
- ali_ac97_set(codec, AC97_PCBEEP_VOL, 0x0000);
- ali_ac97_set(codec, AC97_GENERAL_PURPOSE, AC97_GP_MIX);
- ali_ac97_set(codec, AC97_MASTER_VOL_MONO, 0x0000);
- ali_ac97_set(codec, 0x38, 0x0000);
- addr = ali_ac97_get(codec, 0x2a);
- ali_ac97_set(codec, 0x2a, addr | 0x0001);
- addr = ali_ac97_get(codec, 0x2a);
- addr = ali_ac97_get(codec, 0x28);
- ali_ac97_set(codec, 0x2c, 0xbb80);
- addr = ali_ac97_get(codec, 0x2c);
- /* power it all up */
- ali_ac97_set(codec, AC97_POWER_CONTROL,
- ali_ac97_get(codec, AC97_POWER_CONTROL) & ~0x7f00);
- /* wait for analog ready */
- for (i = 10; i && ((ali_ac97_get(codec, AC97_POWER_CONTROL) & 0xf) != 0xf); i--) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 20);
- }
- /* FIXME !! */
- i++;
- return i;
-}
-
-
-/* I clone ali5455(2.4.7 ) not clone i810_audio(2.4.18) */
-
-static int ali_reset_5455(struct ali_card *card)
-{
- outl(0x80000003, card->iobase + ALI_SCR);
- outl(0x83838383, card->iobase + ALI_FIFOCR1);
- outl(0x83838383, card->iobase + ALI_FIFOCR2);
- if (controller_pcmout_share_spdif_locked > 0) {
- outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
- card->iobase + ALI_SPDIFICS);
- outl(0x0408000a, card->iobase + ALI_INTERFACECR);
- } else {
- if (codec_independent_spdif_locked > 0) {
- outl((inl(card->iobase + ALI_SCR) | 0x00100000), card->iobase + ALI_SCR); // now I select slot 7 & 8
- outl(0x00200000, card->iobase + ALI_INTERFACECR); //enable codec independent spdifout
- } else
- outl(0x04080002, card->iobase + ALI_INTERFACECR);
- }
-
- outl(0x00000000, card->iobase + ALI_INTERRUPTCR);
- outl(0x00000000, card->iobase + ALI_INTERRUPTSR);
- if (controller_independent_spdif_locked > 0)
- outl((inl(card->iobase + ALI_SPDIFICS) | 0x00000001),
- card->iobase + ALI_SPDIFICS);
- return 1;
-}
-
-
-static int ali_ac97_random_init_stuff(struct ali_card
- *card)
-{
- u32 reg = inl(card->iobase + ALI_SCR);
- int i = 0;
- reg = inl(card->iobase + ALI_SCR);
- if ((reg & 2) == 0) /* Cold required */
- reg |= 2;
- else
- reg |= 1; /* Warm */
- reg &= ~0x80000000; /* ACLink on */
- outl(reg, card->iobase + ALI_SCR);
-
- while (i < 10) {
- if ((inl(card->iobase + 0x18) & (1 << 1)) == 0)
- break;
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(HZ / 20);
- i++;
- }
- if (i == 10) {
- printk(KERN_ERR "ali_audio: AC'97 reset failed.\n");
- return 0;
- }
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(HZ / 2);
- return 1;
-}
-
-/* AC97 codec initialisation. */
-
-static int __devinit ali_ac97_init(struct ali_card *card)
-{
- int num_ac97 = 0;
- int total_channels = 0;
- struct ac97_codec *codec;
- u16 eid;
-
- if (!ali_ac97_random_init_stuff(card))
- return 0;
-
- /* Number of channels supported */
- /* What about the codec? Just because the ICH supports */
- /* multiple channels doesn't mean the codec does. */
- /* we'll have to modify this in the codec section below */
- /* to reflect what the codec has. */
- /* ICH and ICH0 only support 2 channels so don't bother */
- /* to check.... */
- inl(card->iobase + ALI_CPR);
- card->channels = 2;
-
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
-
- /* Assume codec isn't available until we go through the
- * gauntlet below */
- card->ac97_codec[num_ac97] = NULL;
- /* The ICH programmer's reference says you should */
- /* check the ready status before probing. So we chk */
- /* What do we do if it's not ready? Wait and try */
- /* again, or abort? */
- if (!ali_ac97_exists(card, num_ac97)) {
- if (num_ac97 == 0)
- printk(KERN_ERR "ali_audio: Primary codec not ready.\n");
- break;
- }
-
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
- /* initialize some basic codec information, other fields will be filled
- in ac97_probe_codec */
- codec->private_data = card;
- codec->id = num_ac97;
- codec->codec_read = ali_ac97_get;
- codec->codec_write = ali_ac97_set;
- if (!ali_ac97_probe_and_powerup(card, codec)) {
- printk(KERN_ERR "ali_audio: timed out waiting for codec %d analog ready",
- num_ac97);
- kfree(codec);
- break; /* it didn't work */
- }
-
- /* Store state information about S/PDIF transmitter */
- card->ac97_status = 0;
- /* Don't attempt to get eid until powerup is complete */
- eid = ali_ac97_get(codec, AC97_EXTENDED_ID);
- if (eid == 0xFFFF) {
- printk(KERN_ERR "ali_audio: no codec attached ?\n");
- kfree(codec);
- break;
- }
-
- card->ac97_features = eid;
- /* Now check the codec for useful features to make up for
- the dumbness of the ali5455 hardware engine */
- if (!(eid & 0x0001))
- printk(KERN_WARNING
- "ali_audio: only 48Khz playback available.\n");
- else {
- if (!ali_ac97_enable_variable_rate(codec)) {
- printk(KERN_WARNING
- "ali_audio: Codec refused to allow VRA, using 48Khz only.\n");
- card->ac97_features &= ~1;
- }
- }
-
- /* Determine how many channels the codec(s) support */
- /* - The primary codec always supports 2 */
- /* - If the codec supports AMAP, surround DACs will */
- /* automaticlly get assigned to slots. */
- /* * Check for surround DACs and increment if */
- /* found. */
- /* - Else check if the codec is revision 2.2 */
- /* * If surround DACs exist, assign them to slots */
- /* and increment channel count. */
-
- /* All of this only applies to ICH2 and above. ICH */
- /* and ICH0 only support 2 channels. ICH2 will only */
- /* support multiple codecs in a "split audio" config. */
- /* as described above. */
-
- /* TODO: Remove all the debugging messages! */
-
- if ((eid & 0xc000) == 0) /* primary codec */
- total_channels += 2;
- if ((codec->dev_mixer = register_sound_mixer(&ali_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "ali_audio: couldn't register mixer!\n");
- kfree(codec);
- break;
- }
- card->ac97_codec[num_ac97] = codec;
- }
- /* pick the minimum of channels supported by ICHx or codec(s) */
- card->channels = (card->channels > total_channels) ? total_channels : card->channels;
- return num_ac97;
-}
-
-static void __devinit ali_configure_clocking(void)
-{
- struct ali_card *card;
- struct ali_state *state;
- struct dmabuf *dmabuf;
- unsigned int i, offset, new_offset;
- unsigned long flags;
- card = devs;
-
- /* We could try to set the clocking for multiple cards, but can you even have
- * more than one ali in a machine? Besides, clocking is global, so unless
- * someone actually thinks more than one ali in a machine is possible and
- * decides to rewrite that little bit, setting the rate for more than one card
- * is a waste of time.
- */
- if (card != NULL) {
- state = card->states[0] = (struct ali_state *)
- kmalloc(sizeof(struct ali_state), GFP_KERNEL);
- if (state == NULL)
- return;
- memset(state, 0, sizeof(struct ali_state));
- dmabuf = &state->dmabuf;
- dmabuf->write_channel = card->alloc_pcm_channel(card);
- state->virt = 0;
- state->card = card;
- state->magic = ALI5455_STATE_MAGIC;
- init_waitqueue_head(&dmabuf->wait);
- mutex_init(&state->open_mutex);
- dmabuf->fmt = ALI5455_FMT_STEREO | ALI5455_FMT_16BIT;
- dmabuf->trigger = PCM_ENABLE_OUTPUT;
- ali_set_dac_rate(state, 48000);
- if (prog_dmabuf(state, 0) != 0)
- goto config_out_nodmabuf;
-
- if (dmabuf->dmasize < 16384)
- goto config_out;
-
- dmabuf->count = dmabuf->dmasize;
- outb(31, card->iobase + dmabuf->write_channel->port + OFF_LVI);
-
- local_irq_save(flags);
- start_dac(state);
- offset = ali_get_dma_addr(state, 0);
- mdelay(50);
- new_offset = ali_get_dma_addr(state, 0);
- stop_dac(state);
-
- outb(2, card->iobase + dmabuf->write_channel->port + OFF_CR);
- local_irq_restore(flags);
-
- i = new_offset - offset;
-
- if (i == 0)
- goto config_out;
- i = i / 4 * 20;
- if (i > 48500 || i < 47500) {
- clocking = clocking * clocking / i;
- }
-config_out:
- dealloc_dmabuf(state);
-config_out_nodmabuf:
- state->card->free_pcm_channel(state->card, state->dmabuf. write_channel->num);
- kfree(state);
- card->states[0] = NULL;
- }
-}
-
-/* install the driver, we do not allocate hardware channel nor DMA buffer now, they are defered
- until "ACCESS" time (in prog_dmabuf called by open/read/write/ioctl/mmap) */
-
-static int __devinit ali_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *pci_id)
-{
- struct ali_card *card;
- if (pci_enable_device(pci_dev))
- return -EIO;
- if (pci_set_dma_mask(pci_dev, ALI5455_DMA_MASK)) {
- printk(KERN_ERR "ali5455: architecture does not support"
- " 32bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- if ((card = kmalloc(sizeof(struct ali_card), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "ali_audio: out of memory\n");
- return -ENOMEM;
- }
- memset(card, 0, sizeof(*card));
- card->initializing = 1;
- card->iobase = pci_resource_start(pci_dev, 0);
- card->pci_dev = pci_dev;
- card->pci_id = pci_id->device;
- card->irq = pci_dev->irq;
- card->next = devs;
- card->magic = ALI5455_CARD_MAGIC;
-#ifdef CONFIG_PM
- card->pm_suspended = 0;
-#endif
- spin_lock_init(&card->lock);
- spin_lock_init(&card->ac97_lock);
- devs = card;
- pci_set_master(pci_dev);
- printk(KERN_INFO "ali: %s found at IO 0x%04lx, IRQ %d\n",
- card_names[pci_id->driver_data], card->iobase, card->irq);
- card->alloc_pcm_channel = ali_alloc_pcm_channel;
- card->alloc_rec_pcm_channel = ali_alloc_rec_pcm_channel;
- card->alloc_rec_mic_channel = ali_alloc_rec_mic_channel;
- card->alloc_codec_spdifout_channel = ali_alloc_codec_spdifout_channel;
- card->alloc_controller_spdifout_channel = ali_alloc_controller_spdifout_channel;
- card->free_pcm_channel = ali_free_pcm_channel;
- card->channel[0].offset = 0;
- card->channel[0].port = 0x40;
- card->channel[0].num = 0;
- card->channel[1].offset = 0;
- card->channel[1].port = 0x50;
- card->channel[1].num = 1;
- card->channel[2].offset = 0;
- card->channel[2].port = 0x60;
- card->channel[2].num = 2;
- card->channel[3].offset = 0;
- card->channel[3].port = 0x70;
- card->channel[3].num = 3;
- card->channel[4].offset = 0;
- card->channel[4].port = 0xb0;
- card->channel[4].num = 4;
- /* claim our iospace and irq */
- request_region(card->iobase, 256, card_names[pci_id->driver_data]);
- if (request_irq(card->irq, &ali_interrupt, IRQF_SHARED,
- card_names[pci_id->driver_data], card)) {
- printk(KERN_ERR "ali_audio: unable to allocate irq %d\n",
- card->irq);
- release_region(card->iobase, 256);
- kfree(card);
- return -ENODEV;
- }
-
- if (ali_reset_5455(card) <= 0) {
- unregister_sound_dsp(card->dev_audio);
- release_region(card->iobase, 256);
- free_irq(card->irq, card);
- kfree(card);
- return -ENODEV;
- }
-
- /* initialize AC97 codec and register /dev/mixer */
- if (ali_ac97_init(card) < 0) {
- release_region(card->iobase, 256);
- free_irq(card->irq, card);
- kfree(card);
- return -ENODEV;
- }
-
- pci_set_drvdata(pci_dev, card);
-
- if (clocking == 0) {
- clocking = 48000;
- ali_configure_clocking();
- }
-
- /* register /dev/dsp */
- if ((card->dev_audio = register_sound_dsp(&ali_audio_fops, -1)) < 0) {
- int i;
- printk(KERN_ERR"ali_audio: couldn't register DSP device!\n");
- release_region(card->iobase, 256);
- free_irq(card->irq, card);
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->dev_mixer);
- kfree(card->ac97_codec[i]);
- }
- kfree(card);
- return -ENODEV;
- }
- card->initializing = 0;
- return 0;
-}
-
-static void __devexit ali_remove(struct pci_dev *pci_dev)
-{
- int i;
- struct ali_card *card = pci_get_drvdata(pci_dev);
- /* free hardware resources */
- free_irq(card->irq, devs);
- release_region(card->iobase, 256);
- /* unregister audio devices */
- for (i = 0; i < NR_AC97; i++)
- if (card->ac97_codec[i] != NULL) {
- unregister_sound_mixer(card->ac97_codec[i]->
- dev_mixer);
- ac97_release_codec(card->ac97_codec[i]);
- card->ac97_codec[i] = NULL;
- }
- unregister_sound_dsp(card->dev_audio);
- kfree(card);
-}
-
-#ifdef CONFIG_PM
-static int ali_pm_suspend(struct pci_dev *dev, pm_message_t pm_state)
-{
- struct ali_card *card = pci_get_drvdata(dev);
- struct ali_state *state;
- unsigned long flags;
- struct dmabuf *dmabuf;
- int i, num_ac97;
-
- if (!card)
- return 0;
- spin_lock_irqsave(&card->lock, flags);
- card->pm_suspended = 1;
- for (i = 0; i < NR_HW_CH; i++) {
- state = card->states[i];
- if (!state)
- continue;
- /* this happens only if there are open files */
- dmabuf = &state->dmabuf;
- if (dmabuf->enable & DAC_RUNNING ||
- (dmabuf->count
- && (dmabuf->trigger & PCM_ENABLE_OUTPUT))) {
- state->pm_saved_dac_rate = dmabuf->rate;
- stop_dac(state);
- } else {
- state->pm_saved_dac_rate = 0;
- }
- if (dmabuf->enable & ADC_RUNNING) {
- state->pm_saved_adc_rate = dmabuf->rate;
- stop_adc(state);
- } else {
- state->pm_saved_adc_rate = 0;
- }
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr = 0;
- dmabuf->count = dmabuf->total_bytes = 0;
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
- /* save mixer settings */
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- struct ac97_codec *codec = card->ac97_codec[num_ac97];
- if (!codec)
- continue;
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if ((supported_mixer(codec, i)) && (codec->read_mixer)) {
- card->pm_saved_mixer_settings[i][num_ac97] = codec->read_mixer(codec, i);
- }
- }
- }
- pci_save_state(dev); /* XXX do we need this? */
- pci_disable_device(dev); /* disable busmastering */
- pci_set_power_state(dev, 3); /* Zzz. */
- return 0;
-}
-
-
-static int ali_pm_resume(struct pci_dev *dev)
-{
- int num_ac97, i = 0;
- struct ali_card *card = pci_get_drvdata(dev);
- pci_enable_device(dev);
- pci_restore_state(dev);
- /* observation of a toshiba portege 3440ct suggests that the
- hardware has to be more or less completely reinitialized from
- scratch after an apm suspend. Works For Me. -dan */
- ali_ac97_random_init_stuff(card);
- for (num_ac97 = 0; num_ac97 < NR_AC97; num_ac97++) {
- struct ac97_codec *codec = card->ac97_codec[num_ac97];
- /* check they haven't stolen the hardware while we were
- away */
- if (!codec || !ali_ac97_exists(card, num_ac97)) {
- if (num_ac97)
- continue;
- else
- BUG();
- }
- if (!ali_ac97_probe_and_powerup(card, codec))
- BUG();
- if ((card->ac97_features & 0x0001)) {
- /* at probe time we found we could do variable
- rates, but APM suspend has made it forget
- its magical powers */
- if (!ali_ac97_enable_variable_rate(codec))
- BUG();
- }
- /* we lost our mixer settings, so restore them */
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (supported_mixer(codec, i)) {
- int val = card->pm_saved_mixer_settings[i][num_ac97];
- codec->mixer_state[i] = val;
- codec->write_mixer(codec, i,
- (val & 0xff),
- ((val >> 8) & 0xff));
- }
- }
- }
-
- /* we need to restore the sample rate from whatever it was */
- for (i = 0; i < NR_HW_CH; i++) {
- struct ali_state *state = card->states[i];
- if (state) {
- if (state->pm_saved_adc_rate)
- ali_set_adc_rate(state, state->pm_saved_adc_rate);
- if (state->pm_saved_dac_rate)
- ali_set_dac_rate(state, state->pm_saved_dac_rate);
- }
- }
-
- card->pm_suspended = 0;
- /* any processes that were reading/writing during the suspend
- probably ended up here */
- for (i = 0; i < NR_HW_CH; i++) {
- struct ali_state *state = card->states[i];
- if (state)
- wake_up(&state->dmabuf.wait);
- }
- return 0;
-}
-#endif /* CONFIG_PM */
-
-MODULE_AUTHOR("");
-MODULE_DESCRIPTION("ALI 5455 audio support");
-MODULE_LICENSE("GPL");
-module_param(clocking, int, 0);
-/* FIXME: bool? */
-module_param(strict_clocking, uint, 0);
-module_param(codec_pcmout_share_spdif_locked, uint, 0);
-module_param(codec_independent_spdif_locked, uint, 0);
-module_param(controller_pcmout_share_spdif_locked, uint, 0);
-module_param(controller_independent_spdif_locked, uint, 0);
-#define ALI5455_MODULE_NAME "ali5455"
-static struct pci_driver ali_pci_driver = {
- .name = ALI5455_MODULE_NAME,
- .id_table = ali_pci_tbl,
- .probe = ali_probe,
- .remove = __devexit_p(ali_remove),
-#ifdef CONFIG_PM
- .suspend = ali_pm_suspend,
- .resume = ali_pm_resume,
-#endif /* CONFIG_PM */
-};
-
-static int __init ali_init_module(void)
-{
- printk(KERN_INFO "ALI 5455 + AC97 Audio, version "
- DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
-
- if (codec_independent_spdif_locked > 0) {
- if (codec_independent_spdif_locked == 32000
- || codec_independent_spdif_locked == 44100
- || codec_independent_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_independent_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- codec_independent_spdif_locked = 0;
- }
- }
- if (controller_independent_spdif_locked > 0) {
- if (controller_independent_spdif_locked == 32000
- || controller_independent_spdif_locked == 44100
- || controller_independent_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", controller_independent_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- controller_independent_spdif_locked = 0;
- }
- }
-
- if (codec_pcmout_share_spdif_locked > 0) {
- if (codec_pcmout_share_spdif_locked == 32000
- || codec_pcmout_share_spdif_locked == 44100
- || codec_pcmout_share_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling S/PDIF at sample rate %dHz.\n", codec_pcmout_share_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- codec_pcmout_share_spdif_locked = 0;
- }
- }
- if (controller_pcmout_share_spdif_locked > 0) {
- if (controller_pcmout_share_spdif_locked == 32000
- || controller_pcmout_share_spdif_locked == 44100
- || controller_pcmout_share_spdif_locked == 48000) {
- printk(KERN_INFO "ali_audio: Enabling controller S/PDIF at sample rate %dHz.\n", controller_pcmout_share_spdif_locked);
- } else {
- printk(KERN_INFO "ali_audio: S/PDIF can only be locked to 32000, 44100, or 48000Hz.\n");
- controller_pcmout_share_spdif_locked = 0;
- }
- }
- return pci_register_driver(&ali_pci_driver);
-}
-
-static void __exit ali_cleanup_module(void)
-{
- pci_unregister_driver(&ali_pci_driver);
-}
-
-module_init(ali_init_module);
-module_exit(ali_cleanup_module);
-/*
-Local Variables:
-c-basic-offset: 8
-End:
-*/
diff --git a/sound/oss/au1000.c b/sound/oss/au1000.c
deleted file mode 100644
index e3796231452a..000000000000
--- a/sound/oss/au1000.c
+++ /dev/null
@@ -1,2216 +0,0 @@
-/*
- * au1000.c -- Sound driver for Alchemy Au1000 MIPS Internet Edge
- * Processor.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- *
- *
- * Module command line parameters:
- *
- * Supported devices:
- * /dev/dsp standard OSS /dev/dsp device
- * /dev/mixer standard OSS /dev/mixer device
- *
- * Notes:
- *
- * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are
- * taken, slightly modified or not at all, from the ES1371 driver,
- * so refer to the credits in es1371.c for those. The rest of the
- * code (probe, open, read, write, the ISR, etc.) is new.
- *
- * Revision history
- * 06.27.2001 Initial version
- * 03.20.2002 Added mutex locks around read/write methods, to prevent
- * simultaneous access on SMP or preemptible kernels. Also
- * removed the counter/pointer fragment aligning at the end
- * of read/write methods [stevel].
- * 03.21.2002 Add support for coherent DMA on the audio read/write DMA
- * channels [stevel].
- *
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/init.h>
-#include <linux/page-flags.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/mach-au1x00/au1000.h>
-#include <asm/mach-au1x00/au1000_dma.h>
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#undef AU1000_DEBUG
-#undef AU1000_VERBOSE_DEBUG
-
-#define AU1000_MODULE_NAME "Au1000 audio"
-#define PFX AU1000_MODULE_NAME
-
-#ifdef AU1000_DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
-
-
-/* misc stuff */
-#define POLL_COUNT 0x5000
-#define AC97_EXT_DACS (AC97_EXTID_SDAC | AC97_EXTID_CDAC | AC97_EXTID_LDAC)
-
-/* Boot options */
-static int vra = 0; // 0 = no VRA, 1 = use VRA if codec supports it
-module_param(vra, bool, 0);
-MODULE_PARM_DESC(vra, "if 1 use VRA if codec supports it");
-
-
-/* --------------------------------------------------------------------- */
-
-struct au1000_state {
- /* soundcore stuff */
- int dev_audio;
-
-#ifdef AU1000_DEBUG
- /* debug /proc entry */
- struct proc_dir_entry *ps;
- struct proc_dir_entry *ac97_ps;
-#endif /* AU1000_DEBUG */
-
- struct ac97_codec codec;
- unsigned codec_base_caps;// AC'97 reg 00h, "Reset Register"
- unsigned codec_ext_caps; // AC'97 reg 28h, "Extended Audio ID"
- int no_vra; // do not use VRA
-
- spinlock_t lock;
- struct mutex open_mutex;
- struct mutex sem;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- unsigned int dmanr; // DMA Channel number
- unsigned sample_rate; // Hz
- unsigned src_factor; // SRC interp/decimation (no vra)
- unsigned sample_size; // 8 or 16
- int num_channels; // 1 = mono, 2 = stereo, 4, 6
- int dma_bytes_per_sample;// DMA bytes per audio sample frame
- int user_bytes_per_sample;// User bytes per audio sample frame
- int cnt_factor; // user-to-DMA bytes per audio
- // sample frame
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag; // # of DMA fragments in DMA buffer
- unsigned fragshift;
- void *nextIn; // ptr to next-in to DMA buffer
- void *nextOut;// ptr to next-out from DMA buffer
- int count; // current byte count in DMA buffer
- unsigned total_bytes; // total bytes written or read
- unsigned error; // over/underrun
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize; // user perception of fragment size
- unsigned dma_fragsize; // DMA (real) fragment size
- unsigned dmasize; // Total DMA buffer size
- // (mult. of DMA fragsize)
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned stopped:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac , dma_adc;
-} au1000_state;
-
-/* --------------------------------------------------------------------- */
-
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void au1000_delay(int msec)
-{
- unsigned long tmo;
- signed long tmo2;
-
- if (in_interrupt())
- return;
-
- tmo = jiffies + (msec * HZ) / 1000;
- for (;;) {
- tmo2 = tmo - jiffies;
- if (tmo2 <= 0)
- break;
- schedule_timeout(tmo2);
- }
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static u16 rdcodec(struct ac97_codec *codec, u8 addr)
-{
- struct au1000_state *s = (struct au1000_state *)codec->private_data;
- unsigned long flags;
- u32 cmd;
- u16 data;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++)
- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
- break;
- if (i == POLL_COUNT)
- err("rdcodec: codec cmd pending expired!");
-
- cmd = (u32) addr & AC97C_INDEX_MASK;
- cmd |= AC97C_READ; // read command
- au_writel(cmd, AC97C_CMD);
-
- /* now wait for the data */
- for (i = 0; i < POLL_COUNT; i++)
- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
- break;
- if (i == POLL_COUNT) {
- err("rdcodec: read poll expired!");
- return 0;
- }
-
- data = au_readl(AC97C_CMD) & 0xffff;
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- return data;
-}
-
-
-static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
- struct au1000_state *s = (struct au1000_state *)codec->private_data;
- unsigned long flags;
- u32 cmd;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++)
- if (!(au_readl(AC97C_STATUS) & AC97C_CP))
- break;
- if (i == POLL_COUNT)
- err("wrcodec: codec cmd pending expired!");
-
- cmd = (u32) addr & AC97C_INDEX_MASK;
- cmd &= ~AC97C_READ; // write command
- cmd |= ((u32) data << AC97C_WD_BIT); // OR in the data word
- au_writel(cmd, AC97C_CMD);
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void waitcodec(struct ac97_codec *codec)
-{
- u16 temp;
- int i;
-
- /* codec_wait is used to wait for a ready state after
- an AC97C_RESET. */
- au1000_delay(10);
-
- // first poll the CODEC_READY tag bit
- for (i = 0; i < POLL_COUNT; i++)
- if (au_readl(AC97C_STATUS) & AC97C_READY)
- break;
- if (i == POLL_COUNT) {
- err("waitcodec: CODEC_READY poll expired!");
- return;
- }
- // get AC'97 powerdown control/status register
- temp = rdcodec(codec, AC97_POWER_CONTROL);
-
- // If anything is powered down, power'em up
- if (temp & 0x7f00) {
- // Power on
- wrcodec(codec, AC97_POWER_CONTROL, 0);
- au1000_delay(100);
- // Reread
- temp = rdcodec(codec, AC97_POWER_CONTROL);
- }
-
- // Check if Codec REF,ANL,DAC,ADC ready
- if ((temp & 0x7f0f) != 0x000f)
- err("codec reg 26 status (0x%x) not ready!!", temp);
-}
-
-
-/* --------------------------------------------------------------------- */
-
-/* stop the ADC before calling */
-static void set_adc_rate(struct au1000_state *s, unsigned rate)
-{
- struct dmabuf *adc = &s->dma_adc;
- struct dmabuf *dac = &s->dma_dac;
- unsigned adc_rate, dac_rate;
- u16 ac97_extstat;
-
- if (s->no_vra) {
- // calc SRC factor
- adc->src_factor = ((96000 / rate) + 1) >> 1;
- adc->sample_rate = 48000 / adc->src_factor;
- return;
- }
-
- adc->src_factor = 1;
-
- ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
-
- rate = rate > 48000 ? 48000 : rate;
-
- // enable VRA
- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
- ac97_extstat | AC97_EXTSTAT_VRA);
- // now write the sample rate
- wrcodec(&s->codec, AC97_PCM_LR_ADC_RATE, (u16) rate);
- // read it back for actual supported rate
- adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("%s: set to %d Hz", __FUNCTION__, adc_rate);
-#endif
-
- // some codec's don't allow unequal DAC and ADC rates, in which case
- // writing one rate reg actually changes both.
- dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
- if (dac->num_channels > 2)
- wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, dac_rate);
- if (dac->num_channels > 4)
- wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, dac_rate);
-
- adc->sample_rate = adc_rate;
- dac->sample_rate = dac_rate;
-}
-
-/* stop the DAC before calling */
-static void set_dac_rate(struct au1000_state *s, unsigned rate)
-{
- struct dmabuf *dac = &s->dma_dac;
- struct dmabuf *adc = &s->dma_adc;
- unsigned adc_rate, dac_rate;
- u16 ac97_extstat;
-
- if (s->no_vra) {
- // calc SRC factor
- dac->src_factor = ((96000 / rate) + 1) >> 1;
- dac->sample_rate = 48000 / dac->src_factor;
- return;
- }
-
- dac->src_factor = 1;
-
- ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
-
- rate = rate > 48000 ? 48000 : rate;
-
- // enable VRA
- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
- ac97_extstat | AC97_EXTSTAT_VRA);
- // now write the sample rate
- wrcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE, (u16) rate);
- // I don't support different sample rates for multichannel,
- // so make these channels the same.
- if (dac->num_channels > 2)
- wrcodec(&s->codec, AC97_PCM_SURR_DAC_RATE, (u16) rate);
- if (dac->num_channels > 4)
- wrcodec(&s->codec, AC97_PCM_LFE_DAC_RATE, (u16) rate);
- // read it back for actual supported rate
- dac_rate = rdcodec(&s->codec, AC97_PCM_FRONT_DAC_RATE);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("%s: set to %d Hz", __FUNCTION__, dac_rate);
-#endif
-
- // some codec's don't allow unequal DAC and ADC rates, in which case
- // writing one rate reg actually changes both.
- adc_rate = rdcodec(&s->codec, AC97_PCM_LR_ADC_RATE);
-
- dac->sample_rate = dac_rate;
- adc->sample_rate = adc_rate;
-}
-
-static void stop_dac(struct au1000_state *s)
-{
- struct dmabuf *db = &s->dma_dac;
- unsigned long flags;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- disable_dma(db->dmanr);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void stop_adc(struct au1000_state *s)
-{
- struct dmabuf *db = &s->dma_adc;
- unsigned long flags;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- disable_dma(db->dmanr);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void set_xmit_slots(int num_channels)
-{
- u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_XMIT_SLOTS_MASK;
-
- switch (num_channels) {
- case 1: // mono
- case 2: // stereo, slots 3,4
- ac97_config |= (0x3 << AC97C_XMIT_SLOTS_BIT);
- break;
- case 4: // stereo with surround, slots 3,4,7,8
- ac97_config |= (0x33 << AC97C_XMIT_SLOTS_BIT);
- break;
- case 6: // stereo with surround and center/LFE, slots 3,4,6,7,8,9
- ac97_config |= (0x7b << AC97C_XMIT_SLOTS_BIT);
- break;
- }
-
- au_writel(ac97_config, AC97C_CONFIG);
-}
-
-static void set_recv_slots(int num_channels)
-{
- u32 ac97_config = au_readl(AC97C_CONFIG) & ~AC97C_RECV_SLOTS_MASK;
-
- /*
- * Always enable slots 3 and 4 (stereo). Slot 6 is
- * optional Mic ADC, which I don't support yet.
- */
- ac97_config |= (0x3 << AC97C_RECV_SLOTS_BIT);
-
- au_writel(ac97_config, AC97C_CONFIG);
-}
-
-static void start_dac(struct au1000_state *s)
-{
- struct dmabuf *db = &s->dma_dac;
- unsigned long flags;
- unsigned long buf1, buf2;
-
- if (!db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- au_readl(AC97C_STATUS); // read status to clear sticky bits
-
- // reset Buffer 1 and 2 pointers to nextOut and nextOut+dma_fragsize
- buf1 = virt_to_phys(db->nextOut);
- buf2 = buf1 + db->dma_fragsize;
- if (buf2 >= db->dmaaddr + db->dmasize)
- buf2 -= db->dmasize;
-
- set_xmit_slots(db->num_channels);
-
- init_dma(db->dmanr);
- if (get_dma_active_buffer(db->dmanr) == 0) {
- clear_dma_done0(db->dmanr); // clear DMA done bit
- set_dma_addr0(db->dmanr, buf1);
- set_dma_addr1(db->dmanr, buf2);
- } else {
- clear_dma_done1(db->dmanr); // clear DMA done bit
- set_dma_addr1(db->dmanr, buf1);
- set_dma_addr0(db->dmanr, buf2);
- }
- set_dma_count(db->dmanr, db->dma_fragsize>>1);
- enable_dma_buffers(db->dmanr);
-
- start_dma(db->dmanr);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dump_au1000_dma_channel(db->dmanr);
-#endif
-
- db->stopped = 0;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct au1000_state *s)
-{
- struct dmabuf *db = &s->dma_adc;
- unsigned long flags;
- unsigned long buf1, buf2;
-
- if (!db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- au_readl(AC97C_STATUS); // read status to clear sticky bits
-
- // reset Buffer 1 and 2 pointers to nextIn and nextIn+dma_fragsize
- buf1 = virt_to_phys(db->nextIn);
- buf2 = buf1 + db->dma_fragsize;
- if (buf2 >= db->dmaaddr + db->dmasize)
- buf2 -= db->dmasize;
-
- set_recv_slots(db->num_channels);
-
- init_dma(db->dmanr);
- if (get_dma_active_buffer(db->dmanr) == 0) {
- clear_dma_done0(db->dmanr); // clear DMA done bit
- set_dma_addr0(db->dmanr, buf1);
- set_dma_addr1(db->dmanr, buf2);
- } else {
- clear_dma_done1(db->dmanr); // clear DMA done bit
- set_dma_addr1(db->dmanr, buf1);
- set_dma_addr0(db->dmanr, buf2);
- }
- set_dma_count(db->dmanr, db->dma_fragsize>>1);
- enable_dma_buffers(db->dmanr);
-
- start_dma(db->dmanr);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dump_au1000_dma_channel(db->dmanr);
-#endif
-
- db->stopped = 0;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct au1000_state *s, struct dmabuf *db)
-{
- struct page *page, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf +
- (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- dma_free_noncoherent(NULL,
- PAGE_SIZE << db->buforder,
- db->rawbuf,
- db->dmaaddr);
- }
- db->rawbuf = db->nextIn = db->nextOut = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct au1000_state *s, struct dmabuf *db)
-{
- int order;
- unsigned user_bytes_per_sec;
- unsigned bufs;
- struct page *page, *pend;
- unsigned rate = db->sample_rate;
-
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER;
- order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = dma_alloc_noncoherent(NULL,
- PAGE_SIZE << order,
- &db->dmaaddr,
- 0)))
- break;
- if (!db->rawbuf)
- return -ENOMEM;
- db->buforder = order;
- /* now mark the pages as reserved;
- otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(db->rawbuf +
- (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
-
- db->cnt_factor = 1;
- if (db->sample_size == 8)
- db->cnt_factor *= 2;
- if (db->num_channels == 1)
- db->cnt_factor *= 2;
- db->cnt_factor *= db->src_factor;
-
- db->count = 0;
- db->nextIn = db->nextOut = db->rawbuf;
-
- db->user_bytes_per_sample = (db->sample_size>>3) * db->num_channels;
- db->dma_bytes_per_sample = 2 * ((db->num_channels == 1) ?
- 2 : db->num_channels);
-
- user_bytes_per_sec = rate * db->user_bytes_per_sample;
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < user_bytes_per_sec)
- db->fragshift = ld2(user_bytes_per_sec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(user_bytes_per_sec / 100 /
- (db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
-
- db->fragsize = 1 << db->fragshift;
- db->dma_fragsize = db->fragsize * db->cnt_factor;
- db->numfrag = bufs / db->dma_fragsize;
-
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->fragsize = 1 << db->fragshift;
- db->dma_fragsize = db->fragsize * db->cnt_factor;
- db->numfrag = bufs / db->dma_fragsize;
- }
-
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
-
- db->dmasize = db->dma_fragsize * db->numfrag;
- memset(db->rawbuf, 0, bufs);
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("rate=%d, samplesize=%d, channels=%d",
- rate, db->sample_size, db->num_channels);
- dbg("fragsize=%d, cnt_factor=%d, dma_fragsize=%d",
- db->fragsize, db->cnt_factor, db->dma_fragsize);
- dbg("numfrag=%d, dmasize=%d", db->numfrag, db->dmasize);
-#endif
-
- db->ready = 1;
- return 0;
-}
-
-static inline int prog_dmabuf_adc(struct au1000_state *s)
-{
- stop_adc(s);
- return prog_dmabuf(s, &s->dma_adc);
-
-}
-
-static inline int prog_dmabuf_dac(struct au1000_state *s)
-{
- stop_dac(s);
- return prog_dmabuf(s, &s->dma_dac);
-}
-
-
-/* hold spinlock for the following */
-static irqreturn_t dac_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct au1000_state *s = (struct au1000_state *) dev_id;
- struct dmabuf *dac = &s->dma_dac;
- unsigned long newptr;
- u32 ac97c_stat, buff_done;
-
- ac97c_stat = au_readl(AC97C_STATUS);
-#ifdef AU1000_VERBOSE_DEBUG
- if (ac97c_stat & (AC97C_XU | AC97C_XO | AC97C_TE))
- dbg("AC97C status = 0x%08x", ac97c_stat);
-#endif
-
- if ((buff_done = get_dma_buffer_done(dac->dmanr)) == 0) {
- /* fastpath out, to ease interrupt sharing */
- return IRQ_HANDLED;
- }
-
- spin_lock(&s->lock);
-
- if (buff_done != (DMA_D0 | DMA_D1)) {
- dac->nextOut += dac->dma_fragsize;
- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
- dac->nextOut -= dac->dmasize;
-
- /* update playback pointers */
- newptr = virt_to_phys(dac->nextOut) + dac->dma_fragsize;
- if (newptr >= dac->dmaaddr + dac->dmasize)
- newptr -= dac->dmasize;
-
- dac->count -= dac->dma_fragsize;
- dac->total_bytes += dac->dma_fragsize;
-
- if (dac->count <= 0) {
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("dac underrun");
-#endif
- spin_unlock(&s->lock);
- stop_dac(s);
- spin_lock(&s->lock);
- dac->count = 0;
- dac->nextIn = dac->nextOut;
- } else if (buff_done == DMA_D0) {
- clear_dma_done0(dac->dmanr); // clear DMA done bit
- set_dma_count0(dac->dmanr, dac->dma_fragsize>>1);
- set_dma_addr0(dac->dmanr, newptr);
- enable_dma_buffer0(dac->dmanr); // reenable
- } else {
- clear_dma_done1(dac->dmanr); // clear DMA done bit
- set_dma_count1(dac->dmanr, dac->dma_fragsize>>1);
- set_dma_addr1(dac->dmanr, newptr);
- enable_dma_buffer1(dac->dmanr); // reenable
- }
- } else {
- // both done bits set, we missed an interrupt
- spin_unlock(&s->lock);
- stop_dac(s);
- spin_lock(&s->lock);
-
- dac->nextOut += 2*dac->dma_fragsize;
- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
- dac->nextOut -= dac->dmasize;
-
- dac->count -= 2*dac->dma_fragsize;
- dac->total_bytes += 2*dac->dma_fragsize;
-
- if (dac->count > 0) {
- spin_unlock(&s->lock);
- start_dac(s);
- spin_lock(&s->lock);
- }
- }
-
- /* wake up anybody listening */
- if (waitqueue_active(&dac->wait))
- wake_up(&dac->wait);
-
- spin_unlock(&s->lock);
-
- return IRQ_HANDLED;
-}
-
-
-static irqreturn_t adc_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct au1000_state *s = (struct au1000_state *) dev_id;
- struct dmabuf *adc = &s->dma_adc;
- unsigned long newptr;
- u32 ac97c_stat, buff_done;
-
- ac97c_stat = au_readl(AC97C_STATUS);
-#ifdef AU1000_VERBOSE_DEBUG
- if (ac97c_stat & (AC97C_RU | AC97C_RO))
- dbg("AC97C status = 0x%08x", ac97c_stat);
-#endif
-
- if ((buff_done = get_dma_buffer_done(adc->dmanr)) == 0) {
- /* fastpath out, to ease interrupt sharing */
- return IRQ_HANDLED;
- }
-
- spin_lock(&s->lock);
-
- if (buff_done != (DMA_D0 | DMA_D1)) {
- if (adc->count + adc->dma_fragsize > adc->dmasize) {
- // Overrun. Stop ADC and log the error
- spin_unlock(&s->lock);
- stop_adc(s);
- adc->error++;
- err("adc overrun");
- return IRQ_NONE;
- }
-
- adc->nextIn += adc->dma_fragsize;
- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
- adc->nextIn -= adc->dmasize;
-
- /* update capture pointers */
- newptr = virt_to_phys(adc->nextIn) + adc->dma_fragsize;
- if (newptr >= adc->dmaaddr + adc->dmasize)
- newptr -= adc->dmasize;
-
- adc->count += adc->dma_fragsize;
- adc->total_bytes += adc->dma_fragsize;
-
- if (buff_done == DMA_D0) {
- clear_dma_done0(adc->dmanr); // clear DMA done bit
- set_dma_count0(adc->dmanr, adc->dma_fragsize>>1);
- set_dma_addr0(adc->dmanr, newptr);
- enable_dma_buffer0(adc->dmanr); // reenable
- } else {
- clear_dma_done1(adc->dmanr); // clear DMA done bit
- set_dma_count1(adc->dmanr, adc->dma_fragsize>>1);
- set_dma_addr1(adc->dmanr, newptr);
- enable_dma_buffer1(adc->dmanr); // reenable
- }
- } else {
- // both done bits set, we missed an interrupt
- spin_unlock(&s->lock);
- stop_adc(s);
- spin_lock(&s->lock);
-
- if (adc->count + 2*adc->dma_fragsize > adc->dmasize) {
- // Overrun. Log the error
- adc->error++;
- err("adc overrun");
- spin_unlock(&s->lock);
- return IRQ_NONE;
- }
-
- adc->nextIn += 2*adc->dma_fragsize;
- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
- adc->nextIn -= adc->dmasize;
-
- adc->count += 2*adc->dma_fragsize;
- adc->total_bytes += 2*adc->dma_fragsize;
-
- spin_unlock(&s->lock);
- start_adc(s);
- spin_lock(&s->lock);
- }
-
- /* wake up anybody listening */
- if (waitqueue_active(&adc->wait))
- wake_up(&adc->wait);
-
- spin_unlock(&s->lock);
-
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static loff_t au1000_llseek(struct file *file, loff_t offset, int origin)
-{
- return -ESPIPE;
-}
-
-
-static int au1000_open_mixdev(struct inode *inode, struct file *file)
-{
- file->private_data = &au1000_state;
- return nonseekable_open(inode, file);
-}
-
-static int au1000_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
- unsigned long arg)
-{
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static int au1000_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- struct ac97_codec *codec = &s->codec;
-
- return mixdev_ioctl(codec, cmd, arg);
-}
-
-static /*const */ struct file_operations au1000_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = au1000_llseek,
- .ioctl = au1000_ioctl_mixdev,
- .open = au1000_open_mixdev,
- .release = au1000_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct au1000_state *s, int nonblock)
-{
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
- return 0;
-
- for (;;) {
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock)
- return -EBUSY;
- tmo = 1000 * count / (s->no_vra ?
- 48000 : s->dma_dac.sample_rate);
- tmo /= s->dma_dac.dma_bytes_per_sample;
- au1000_delay(tmo);
- }
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline u8 S16_TO_U8(s16 ch)
-{
- return (u8) (ch >> 8) + 0x80;
-}
-static inline s16 U8_TO_S16(u8 ch)
-{
- return (s16) (ch - 0x80) << 8;
-}
-
-/*
- * Translates user samples to dma buffer suitable for AC'97 DAC data:
- * If mono, copy left channel to right channel in dma buffer.
- * If 8 bit samples, cvt to 16-bit before writing to dma buffer.
- * If interpolating (no VRA), duplicate every audio frame src_factor times.
- */
-static int translate_from_user(struct dmabuf *db,
- char* dmabuf,
- char* userbuf,
- int dmacount)
-{
- int sample, i;
- int interp_bytes_per_sample;
- int num_samples;
- int mono = (db->num_channels == 1);
- char usersample[12];
- s16 ch, dmasample[6];
-
- if (db->sample_size == 16 && !mono && db->src_factor == 1) {
- // no translation necessary, just copy
- if (copy_from_user(dmabuf, userbuf, dmacount))
- return -EFAULT;
- return dmacount;
- }
-
- interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
- num_samples = dmacount / interp_bytes_per_sample;
-
- for (sample = 0; sample < num_samples; sample++) {
- if (copy_from_user(usersample, userbuf,
- db->user_bytes_per_sample)) {
- dbg("%s: fault", __FUNCTION__);
- return -EFAULT;
- }
-
- for (i = 0; i < db->num_channels; i++) {
- if (db->sample_size == 8)
- ch = U8_TO_S16(usersample[i]);
- else
- ch = *((s16 *) (&usersample[i * 2]));
- dmasample[i] = ch;
- if (mono)
- dmasample[i + 1] = ch; // right channel
- }
-
- // duplicate every audio frame src_factor times
- for (i = 0; i < db->src_factor; i++)
- memcpy(dmabuf, dmasample, db->dma_bytes_per_sample);
-
- userbuf += db->user_bytes_per_sample;
- dmabuf += interp_bytes_per_sample;
- }
-
- return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Translates AC'97 ADC samples to user buffer:
- * If mono, send only left channel to user buffer.
- * If 8 bit samples, cvt from 16 to 8 bit before writing to user buffer.
- * If decimating (no VRA), skip over src_factor audio frames.
- */
-static int translate_to_user(struct dmabuf *db,
- char* userbuf,
- char* dmabuf,
- int dmacount)
-{
- int sample, i;
- int interp_bytes_per_sample;
- int num_samples;
- int mono = (db->num_channels == 1);
- char usersample[12];
-
- if (db->sample_size == 16 && !mono && db->src_factor == 1) {
- // no translation necessary, just copy
- if (copy_to_user(userbuf, dmabuf, dmacount))
- return -EFAULT;
- return dmacount;
- }
-
- interp_bytes_per_sample = db->dma_bytes_per_sample * db->src_factor;
- num_samples = dmacount / interp_bytes_per_sample;
-
- for (sample = 0; sample < num_samples; sample++) {
- for (i = 0; i < db->num_channels; i++) {
- if (db->sample_size == 8)
- usersample[i] =
- S16_TO_U8(*((s16 *) (&dmabuf[i * 2])));
- else
- *((s16 *) (&usersample[i * 2])) =
- *((s16 *) (&dmabuf[i * 2]));
- }
-
- if (copy_to_user(userbuf, usersample,
- db->user_bytes_per_sample)) {
- dbg("%s: fault", __FUNCTION__);
- return -EFAULT;
- }
-
- userbuf += db->user_bytes_per_sample;
- dmabuf += interp_bytes_per_sample;
- }
-
- return num_samples * interp_bytes_per_sample;
-}
-
-/*
- * Copy audio data to/from user buffer from/to dma buffer, taking care
- * that we wrap when reading/writing the dma buffer. Returns actual byte
- * count written to or read from the dma buffer.
- */
-static int copy_dmabuf_user(struct dmabuf *db, char* userbuf,
- int count, int to_user)
-{
- char *bufptr = to_user ? db->nextOut : db->nextIn;
- char *bufend = db->rawbuf + db->dmasize;
- int cnt, ret;
-
- if (bufptr + count > bufend) {
- int partial = (int) (bufend - bufptr);
- if (to_user) {
- if ((cnt = translate_to_user(db, userbuf,
- bufptr, partial)) < 0)
- return cnt;
- ret = cnt;
- if ((cnt = translate_to_user(db, userbuf + partial,
- db->rawbuf,
- count - partial)) < 0)
- return cnt;
- ret += cnt;
- } else {
- if ((cnt = translate_from_user(db, bufptr, userbuf,
- partial)) < 0)
- return cnt;
- ret = cnt;
- if ((cnt = translate_from_user(db, db->rawbuf,
- userbuf + partial,
- count - partial)) < 0)
- return cnt;
- ret += cnt;
- }
- } else {
- if (to_user)
- ret = translate_to_user(db, userbuf, bufptr, count);
- else
- ret = translate_from_user(db, bufptr, userbuf, count);
- }
-
- return ret;
-}
-
-
-static ssize_t au1000_read(struct file *file, char *buffer,
- size_t count, loff_t *ppos)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- struct dmabuf *db = &s->dma_adc;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- int cnt, usercnt, avail;
-
- if (db->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- count *= db->cnt_factor;
-
- mutex_lock(&s->sem);
- add_wait_queue(&db->wait, &wait);
-
- while (count > 0) {
- // wait for samples in ADC dma buffer
- do {
- if (db->stopped)
- start_adc(s);
- spin_lock_irqsave(&s->lock, flags);
- avail = db->count;
- if (avail <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (avail <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&s->sem);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out2;
- }
- mutex_lock(&s->sem);
- }
- } while (avail <= 0);
-
- // copy from nextOut to user
- if ((cnt = copy_dmabuf_user(db, buffer,
- count > avail ?
- avail : count, 1)) < 0) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
-
- spin_lock_irqsave(&s->lock, flags);
- db->count -= cnt;
- db->nextOut += cnt;
- if (db->nextOut >= db->rawbuf + db->dmasize)
- db->nextOut -= db->dmasize;
- spin_unlock_irqrestore(&s->lock, flags);
-
- count -= cnt;
- usercnt = cnt / db->cnt_factor;
- buffer += usercnt;
- ret += usercnt;
- } // while (count > 0)
-
-out:
- mutex_unlock(&s->sem);
-out2:
- remove_wait_queue(&db->wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t au1000_write(struct file *file, const char *buffer,
- size_t count, loff_t * ppos)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- struct dmabuf *db = &s->dma_dac;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret = 0;
- unsigned long flags;
- int cnt, usercnt, avail;
-
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("write: count=%d", count);
-#endif
-
- if (db->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-
- count *= db->cnt_factor;
-
- mutex_lock(&s->sem);
- add_wait_queue(&db->wait, &wait);
-
- while (count > 0) {
- // wait for space in playback buffer
- do {
- spin_lock_irqsave(&s->lock, flags);
- avail = (int) db->dmasize - db->count;
- if (avail <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (avail <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&s->sem);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out2;
- }
- mutex_lock(&s->sem);
- }
- } while (avail <= 0);
-
- // copy from user to nextIn
- if ((cnt = copy_dmabuf_user(db, (char *) buffer,
- count > avail ?
- avail : count, 0)) < 0) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
-
- spin_lock_irqsave(&s->lock, flags);
- db->count += cnt;
- db->nextIn += cnt;
- if (db->nextIn >= db->rawbuf + db->dmasize)
- db->nextIn -= db->dmasize;
- spin_unlock_irqrestore(&s->lock, flags);
- if (db->stopped)
- start_dac(s);
-
- count -= cnt;
- usercnt = cnt / db->cnt_factor;
- buffer += usercnt;
- ret += usercnt;
- } // while (count > 0)
-
-out:
- mutex_unlock(&s->sem);
-out2:
- remove_wait_queue(&db->wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int au1000_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready)
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready)
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
-
- spin_lock_irqsave(&s->lock, flags);
-
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.dma_fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >=
- (signed)s->dma_dac.dma_fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed) s->dma_dac.dmasize >=
- s->dma_dac.count + (signed)s->dma_dac.dma_fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int au1000_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- struct dmabuf *db;
- unsigned long size;
- int ret = 0;
-
- dbg("%s", __FUNCTION__);
-
- lock_kernel();
- mutex_lock(&s->sem);
- if (vma->vm_flags & VM_WRITE)
- db = &s->dma_dac;
- else if (vma->vm_flags & VM_READ)
- db = &s->dma_adc;
- else {
- ret = -EINVAL;
- goto out;
- }
- if (vma->vm_pgoff != 0) {
- ret = -EINVAL;
- goto out;
- }
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder)) {
- ret = -EINVAL;
- goto out;
- }
- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(db->rawbuf),
- size, vma->vm_page_prot)) {
- ret = -EAGAIN;
- goto out;
- }
- vma->vm_flags &= ~VM_IO;
- db->mapped = 1;
-out:
- mutex_unlock(&s->sem);
- unlock_kernel();
- return ret;
-}
-
-
-#ifdef AU1000_VERBOSE_DEBUG
-static struct ioctl_str_t {
- unsigned int cmd;
- const char *str;
-} ioctl_str[] = {
- {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
- {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
- {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
- {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
- {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
- {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
- {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
- {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
- {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
- {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
- {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
- {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
- {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
- {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
- {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
- {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
- {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
- {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
- {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
- {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
- {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
- {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
- {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
- {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
- {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
- {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
- {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
- {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
- {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
- {OSS_GETVERSION, "OSS_GETVERSION"},
- {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
- {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
- {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
- {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
-};
-#endif
-
-// Need to hold a spin-lock before calling this!
-static int dma_count_done(struct dmabuf *db)
-{
- if (db->stopped)
- return 0;
-
- return db->dma_fragsize - get_dma_residue(db->dmanr);
-}
-
-
-static int au1000_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, mapped, ret, diff;
-
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-#ifdef AU1000_VERBOSE_DEBUG
- for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
- if (ioctl_str[count].cmd == cmd)
- break;
- }
- if (count < sizeof(ioctl_str) / sizeof(ioctl_str[0]))
- dbg("ioctl %s, arg=0x%lx", ioctl_str[count].str, arg);
- else
- dbg("ioctl 0x%x unknown, arg=0x%lx", cmd, arg);
-#endif
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *) arg);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, file->f_flags & O_NONBLOCK);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
- DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq();
- s->dma_dac.count = s->dma_dac.total_bytes = 0;
- s->dma_dac.nextIn = s->dma_dac.nextOut =
- s->dma_dac.rawbuf;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq();
- s->dma_adc.count = s->dma_adc.total_bytes = 0;
- s->dma_adc.nextIn = s->dma_adc.nextOut =
- s->dma_adc.rawbuf;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- set_adc_rate(s, val);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- set_dac_rate(s, val);
- }
- if (s->open_mode & FMODE_READ)
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- if (s->open_mode & FMODE_WRITE)
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return put_user((file->f_mode & FMODE_READ) ?
- s->dma_adc.sample_rate :
- s->dma_dac.sample_rate,
- (int *)arg);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.num_channels = val ? 2 : 1;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.num_channels = val ? 2 : 1;
- if (s->codec_ext_caps & AC97_EXT_DACS) {
- // disable surround and center/lfe in AC'97
- u16 ext_stat = rdcodec(&s->codec,
- AC97_EXTENDED_STATUS);
- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
- ext_stat | (AC97_EXTSTAT_PRI |
- AC97_EXTSTAT_PRJ |
- AC97_EXTSTAT_PRK));
- }
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- if (val < 0 || val > 2)
- return -EINVAL;
- stop_adc(s);
- s->dma_adc.num_channels = val;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- switch (val) {
- case 1:
- case 2:
- break;
- case 3:
- case 5:
- return -EINVAL;
- case 4:
- if (!(s->codec_ext_caps &
- AC97_EXTID_SDAC))
- return -EINVAL;
- break;
- case 6:
- if ((s->codec_ext_caps &
- AC97_EXT_DACS) != AC97_EXT_DACS)
- return -EINVAL;
- break;
- default:
- return -EINVAL;
- }
-
- stop_dac(s);
- if (val <= 2 &&
- (s->codec_ext_caps & AC97_EXT_DACS)) {
- // disable surround and center/lfe
- // channels in AC'97
- u16 ext_stat =
- rdcodec(&s->codec,
- AC97_EXTENDED_STATUS);
- wrcodec(&s->codec,
- AC97_EXTENDED_STATUS,
- ext_stat | (AC97_EXTSTAT_PRI |
- AC97_EXTSTAT_PRJ |
- AC97_EXTSTAT_PRK));
- } else if (val >= 4) {
- // enable surround, center/lfe
- // channels in AC'97
- u16 ext_stat =
- rdcodec(&s->codec,
- AC97_EXTENDED_STATUS);
- ext_stat &= ~AC97_EXTSTAT_PRJ;
- if (val == 6)
- ext_stat &=
- ~(AC97_EXTSTAT_PRI |
- AC97_EXTSTAT_PRK);
- wrcodec(&s->codec,
- AC97_EXTENDED_STATUS,
- ext_stat);
- }
-
- s->dma_dac.num_channels = val;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- }
- return put_user(val, (int *) arg);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt */
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- if (val == AFMT_S16_LE)
- s->dma_adc.sample_size = 16;
- else {
- val = AFMT_U8;
- s->dma_adc.sample_size = 8;
- }
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- if (val == AFMT_S16_LE)
- s->dma_dac.sample_size = 16;
- else {
- val = AFMT_U8;
- s->dma_dac.sample_size = 8;
- }
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- } else {
- if (file->f_mode & FMODE_READ)
- val = (s->dma_adc.sample_size == 16) ?
- AFMT_S16_LE : AFMT_U8;
- else
- val = (s->dma_dac.sample_size == 16) ?
- AFMT_S16_LE : AFMT_U8;
- }
- return put_user(val, (int *) arg);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
- val |= PCM_ENABLE_OUTPUT;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *) arg);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT)
- start_adc(s);
- else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT)
- start_dac(s);
- else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- abinfo.fragsize = s->dma_dac.fragsize;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- count -= dma_count_done(&s->dma_dac);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- abinfo.bytes = (s->dma_dac.dmasize - count) /
- s->dma_dac.cnt_factor;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
-#ifdef AU1000_VERBOSE_DEBUG
- dbg("bytes=%d, fragments=%d", abinfo.bytes, abinfo.fragments);
-#endif
- return copy_to_user((void *) arg, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- abinfo.fragsize = s->dma_adc.fragsize;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_adc.count;
- count += dma_count_done(&s->dma_adc);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- abinfo.bytes = count / s->dma_adc.cnt_factor;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- return copy_to_user((void *) arg, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- count -= dma_count_done(&s->dma_dac);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- count /= s->dma_dac.cnt_factor;
- return put_user(count, (int *) arg);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cinfo.bytes = s->dma_adc.total_bytes;
- count = s->dma_adc.count;
- if (!s->dma_adc.stopped) {
- diff = dma_count_done(&s->dma_adc);
- count += diff;
- cinfo.bytes += diff;
- cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) + diff -
- s->dma_adc.dmaaddr;
- } else
- cinfo.ptr = virt_to_phys(s->dma_adc.nextIn) -
- s->dma_adc.dmaaddr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= (s->dma_adc.dma_fragsize-1);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_adc.fragshift;
- return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cinfo.bytes = s->dma_dac.total_bytes;
- count = s->dma_dac.count;
- if (!s->dma_dac.stopped) {
- diff = dma_count_done(&s->dma_dac);
- count -= diff;
- cinfo.bytes += diff;
- cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) + diff -
- s->dma_dac.dmaaddr;
- } else
- cinfo.ptr = virt_to_phys(s->dma_dac.nextOut) -
- s->dma_dac.dmaaddr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= (s->dma_dac.dma_fragsize-1);
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
- return copy_to_user((void *) arg, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE)
- return put_user(s->dma_dac.fragsize, (int *) arg);
- else
- return put_user(s->dma_adc.fragsize, (int *) arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, (int *) arg))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.subdivision = val;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.subdivision = val;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ?
- s->dma_adc.sample_rate :
- s->dma_dac.sample_rate,
- (int *)arg);
-
- case SOUND_PCM_READ_CHANNELS:
- if (file->f_mode & FMODE_READ)
- return put_user(s->dma_adc.num_channels, (int *)arg);
- else
- return put_user(s->dma_dac.num_channels, (int *)arg);
-
- case SOUND_PCM_READ_BITS:
- if (file->f_mode & FMODE_READ)
- return put_user(s->dma_adc.sample_size, (int *)arg);
- else
- return put_user(s->dma_dac.sample_size, (int *)arg);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
- }
-
- return mixdev_ioctl(&s->codec, cmd, arg);
-}
-
-
-static int au1000_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct au1000_state *s = &au1000_state;
- int ret;
-
-#ifdef AU1000_VERBOSE_DEBUG
- if (file->f_flags & O_NONBLOCK)
- dbg("%s: non-blocking", __FUNCTION__);
- else
- dbg("%s: blocking", __FUNCTION__);
-#endif
-
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
-
- stop_dac(s);
- stop_adc(s);
-
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
- s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
- s->dma_adc.num_channels = 1;
- s->dma_adc.sample_size = 8;
- set_adc_rate(s, 8000);
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->dma_adc.sample_size = 16;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
- s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
- s->dma_dac.num_channels = 1;
- s->dma_dac.sample_size = 8;
- set_dac_rate(s, 8000);
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->dma_dac.sample_size = 16;
- }
-
- if (file->f_mode & FMODE_READ) {
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
-
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- mutex_init(&s->sem);
- return nonseekable_open(inode, file);
-}
-
-static int au1000_release(struct inode *inode, struct file *file)
-{
- struct au1000_state *s = (struct au1000_state *)file->private_data;
-
- lock_kernel();
-
- if (file->f_mode & FMODE_WRITE) {
- unlock_kernel();
- drain_dac(s, file->f_flags & O_NONBLOCK);
- lock_kernel();
- }
-
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- dealloc_dmabuf(s, &s->dma_dac);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- }
- s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static /*const */ struct file_operations au1000_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = au1000_llseek,
- .read = au1000_read,
- .write = au1000_write,
- .poll = au1000_poll,
- .ioctl = au1000_ioctl,
- .mmap = au1000_mmap,
- .open = au1000_open,
- .release = au1000_release,
-};
-
-
-/* --------------------------------------------------------------------- */
-
-
-/* --------------------------------------------------------------------- */
-
-/*
- * for debugging purposes, we'll create a proc device that dumps the
- * CODEC chipstate
- */
-
-#ifdef AU1000_DEBUG
-static int proc_au1000_dump(char *buf, char **start, off_t fpos,
- int length, int *eof, void *data)
-{
- struct au1000_state *s = &au1000_state;
- int cnt, len = 0;
-
- /* print out header */
- len += sprintf(buf + len, "\n\t\tAU1000 Audio Debug\n\n");
-
- // print out digital controller state
- len += sprintf(buf + len, "AU1000 Audio Controller registers\n");
- len += sprintf(buf + len, "---------------------------------\n");
- len += sprintf (buf + len, "AC97C_CONFIG = %08x\n",
- au_readl(AC97C_CONFIG));
- len += sprintf (buf + len, "AC97C_STATUS = %08x\n",
- au_readl(AC97C_STATUS));
- len += sprintf (buf + len, "AC97C_CNTRL = %08x\n",
- au_readl(AC97C_CNTRL));
-
- /* print out CODEC state */
- len += sprintf(buf + len, "\nAC97 CODEC registers\n");
- len += sprintf(buf + len, "----------------------\n");
- for (cnt = 0; cnt <= 0x7e; cnt += 2)
- len += sprintf(buf + len, "reg %02x = %04x\n",
- cnt, rdcodec(&s->codec, cnt));
-
- if (fpos >= len) {
- *start = buf;
- *eof = 1;
- return 0;
- }
- *start = buf + fpos;
- if ((len -= fpos) > length)
- return length;
- *eof = 1;
- return len;
-
-}
-#endif /* AU1000_DEBUG */
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com");
-MODULE_DESCRIPTION("Au1000 Audio Driver");
-
-/* --------------------------------------------------------------------- */
-
-static int __devinit au1000_probe(void)
-{
- struct au1000_state *s = &au1000_state;
- int val;
-#ifdef AU1000_DEBUG
- char proc_str[80];
-#endif
-
- memset(s, 0, sizeof(struct au1000_state));
-
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
- s->codec.private_data = s;
- s->codec.id = 0;
- s->codec.codec_read = rdcodec;
- s->codec.codec_write = wrcodec;
- s->codec.codec_wait = waitcodec;
-
- if (!request_mem_region(CPHYSADDR(AC97C_CONFIG),
- 0x14, AU1000_MODULE_NAME)) {
- err("AC'97 ports in use");
- return -1;
- }
- // Allocate the DMA Channels
- if ((s->dma_dac.dmanr = request_au1000_dma(DMA_ID_AC97C_TX,
- "audio DAC",
- dac_dma_interrupt,
- IRQF_DISABLED, s)) < 0) {
- err("Can't get DAC DMA");
- goto err_dma1;
- }
- if ((s->dma_adc.dmanr = request_au1000_dma(DMA_ID_AC97C_RX,
- "audio ADC",
- adc_dma_interrupt,
- IRQF_DISABLED, s)) < 0) {
- err("Can't get ADC DMA");
- goto err_dma2;
- }
-
- info("DAC: DMA%d/IRQ%d, ADC: DMA%d/IRQ%d",
- s->dma_dac.dmanr, get_dma_done_irq(s->dma_dac.dmanr),
- s->dma_adc.dmanr, get_dma_done_irq(s->dma_adc.dmanr));
-
- // enable DMA coherency in read/write DMA channels
- set_dma_mode(s->dma_dac.dmanr,
- get_dma_mode(s->dma_dac.dmanr) & ~DMA_NC);
- set_dma_mode(s->dma_adc.dmanr,
- get_dma_mode(s->dma_adc.dmanr) & ~DMA_NC);
-
- /* register devices */
-
- if ((s->dev_audio = register_sound_dsp(&au1000_audio_fops, -1)) < 0)
- goto err_dev1;
- if ((s->codec.dev_mixer =
- register_sound_mixer(&au1000_mixer_fops, -1)) < 0)
- goto err_dev2;
-
-#ifdef AU1000_DEBUG
- /* intialize the debug proc device */
- s->ps = create_proc_read_entry(AU1000_MODULE_NAME, 0, NULL,
- proc_au1000_dump, NULL);
-#endif /* AU1000_DEBUG */
-
- // configure pins for AC'97
- au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
-
- // Assert reset for 10msec to the AC'97 controller, and enable clock
- au_writel(AC97C_RS | AC97C_CE, AC97C_CNTRL);
- au1000_delay(10);
- au_writel(AC97C_CE, AC97C_CNTRL);
- au1000_delay(10); // wait for clock to stabilize
-
- /* cold reset the AC'97 */
- au_writel(AC97C_RESET, AC97C_CONFIG);
- au1000_delay(10);
- au_writel(0, AC97C_CONFIG);
- /* need to delay around 500msec(bleech) to give
- some CODECs enough time to wakeup */
- au1000_delay(500);
-
- /* warm reset the AC'97 to start the bitclk */
- au_writel(AC97C_SG | AC97C_SYNC, AC97C_CONFIG);
- udelay(100);
- au_writel(0, AC97C_CONFIG);
-
- /* codec init */
- if (!ac97_probe_codec(&s->codec))
- goto err_dev3;
-
- s->codec_base_caps = rdcodec(&s->codec, AC97_RESET);
- s->codec_ext_caps = rdcodec(&s->codec, AC97_EXTENDED_ID);
- info("AC'97 Base/Extended ID = %04x/%04x",
- s->codec_base_caps, s->codec_ext_caps);
-
- /*
- * On the Pb1000, audio playback is on the AUX_OUT
- * channel (which defaults to LNLVL_OUT in AC'97
- * rev 2.2) so make sure this channel is listed
- * as supported (soundcard.h calls this channel
- * ALTPCM). ac97_codec.c does not handle detection
- * of this channel correctly.
- */
- s->codec.supported_mixers |= SOUND_MASK_ALTPCM;
- /*
- * Now set AUX_OUT's default volume.
- */
- val = 0x4343;
- mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_ALTPCM,
- (unsigned long) &val);
-
- if (!(s->codec_ext_caps & AC97_EXTID_VRA)) {
- // codec does not support VRA
- s->no_vra = 1;
- } else if (!vra) {
- // Boot option says disable VRA
- u16 ac97_extstat = rdcodec(&s->codec, AC97_EXTENDED_STATUS);
- wrcodec(&s->codec, AC97_EXTENDED_STATUS,
- ac97_extstat & ~AC97_EXTSTAT_VRA);
- s->no_vra = 1;
- }
- if (s->no_vra)
- info("no VRA, interpolating and decimating");
-
- /* set mic to be the recording source */
- val = SOUND_MASK_MIC;
- mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC,
- (unsigned long) &val);
-
-#ifdef AU1000_DEBUG
- sprintf(proc_str, "driver/%s/%d/ac97", AU1000_MODULE_NAME,
- s->codec.id);
- s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,
- ac97_read_proc, &s->codec);
-#endif
-
-#ifdef CONFIG_MIPS_XXS1500
- /* deassert eapd */
- wrcodec(&s->codec, AC97_POWER_CONTROL,
- rdcodec(&s->codec, AC97_POWER_CONTROL) & ~0x8000);
- /* mute a number of signals which seem to be causing problems
- * if not muted.
- */
- wrcodec(&s->codec, AC97_PCBEEP_VOL, 0x8000);
- wrcodec(&s->codec, AC97_PHONE_VOL, 0x8008);
- wrcodec(&s->codec, AC97_MIC_VOL, 0x8008);
- wrcodec(&s->codec, AC97_LINEIN_VOL, 0x8808);
- wrcodec(&s->codec, AC97_CD_VOL, 0x8808);
- wrcodec(&s->codec, AC97_VIDEO_VOL, 0x8808);
- wrcodec(&s->codec, AC97_AUX_VOL, 0x8808);
- wrcodec(&s->codec, AC97_PCMOUT_VOL, 0x0808);
- wrcodec(&s->codec, AC97_GENERAL_PURPOSE, 0x2000);
-#endif
-
- return 0;
-
- err_dev3:
- unregister_sound_mixer(s->codec.dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- free_au1000_dma(s->dma_adc.dmanr);
- err_dma2:
- free_au1000_dma(s->dma_dac.dmanr);
- err_dma1:
- release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
- return -1;
-}
-
-static void au1000_remove(void)
-{
- struct au1000_state *s = &au1000_state;
-
- if (!s)
- return;
-#ifdef AU1000_DEBUG
- if (s->ps)
- remove_proc_entry(AU1000_MODULE_NAME, NULL);
-#endif /* AU1000_DEBUG */
- synchronize_irq();
- free_au1000_dma(s->dma_adc.dmanr);
- free_au1000_dma(s->dma_dac.dmanr);
- release_mem_region(CPHYSADDR(AC97C_CONFIG), 0x14);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->codec.dev_mixer);
-}
-
-static int __init init_au1000(void)
-{
- info("stevel@mvista.com, built " __TIME__ " on " __DATE__);
- return au1000_probe();
-}
-
-static void __exit cleanup_au1000(void)
-{
- info("unloading");
- au1000_remove();
-}
-
-module_init(init_au1000);
-module_exit(cleanup_au1000);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-static int __init au1000_setup(char *options)
-{
- char *this_opt;
-
- if (!options || !*options)
- return 0;
-
- while ((this_opt = strsep(&options, ","))) {
- if (!*this_opt)
- continue;
- if (!strncmp(this_opt, "vra", 3)) {
- vra = 1;
- }
- }
-
- return 1;
-}
-
-__setup("au1000_audio=", au1000_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/audio.c b/sound/oss/audio.c
index 22dd63c36816..89bd27a5e865 100644
--- a/sound/oss/audio.c
+++ b/sound/oss/audio.c
@@ -1,5 +1,5 @@
/*
- * sound/audio.c
+ * sound/oss/audio.c
*
* Device file manager for /dev/audio
*/
diff --git a/sound/oss/audio_syms.c b/sound/oss/audio_syms.c
deleted file mode 100644
index 5da217fcbedd..000000000000
--- a/sound/oss/audio_syms.c
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Exported symbols for audio driver.
- */
-
-#include <linux/module.h>
-
-char audio_syms_symbol;
-
-#include "sound_config.h"
-#include "sound_calls.h"
-
-EXPORT_SYMBOL(DMAbuf_start_dma);
-EXPORT_SYMBOL(DMAbuf_open_dma);
-EXPORT_SYMBOL(DMAbuf_close_dma);
-EXPORT_SYMBOL(DMAbuf_inputintr);
-EXPORT_SYMBOL(DMAbuf_outputintr);
diff --git a/sound/oss/awe_hw.h b/sound/oss/awe_hw.h
deleted file mode 100644
index 7e403ad68152..000000000000
--- a/sound/oss/awe_hw.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * sound/awe_hw.h
- *
- * Access routines and definitions for the low level driver for the
- * Creative AWE32/SB32/AWE64 wave table synth.
- * version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-2000 Takashi Iwai
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef AWE_HW_H_DEF
-#define AWE_HW_H_DEF
-
-/*
- * Emu-8000 control registers
- * name(channel) reg, port
- */
-
-#define awe_cmd_idx(reg,ch) (((reg)<< 5) | (ch))
-
-#define Data0 0 /* 0x620: doubleword r/w */
-#define Data1 1 /* 0xA20: doubleword r/w */
-#define Data2 2 /* 0xA22: word r/w */
-#define Data3 3 /* 0xE20: word r/w */
-#define Pointer 4 /* 0xE22 register pointer r/w */
-
-#define AWE_CPF(ch) awe_cmd_idx(0,ch), Data0 /* DW: current pitch and fractional address */
-#define AWE_PTRX(ch) awe_cmd_idx(1,ch), Data0 /* DW: pitch target and reverb send */
-#define AWE_CVCF(ch) awe_cmd_idx(2,ch), Data0 /* DW: current volume and filter cutoff */
-#define AWE_VTFT(ch) awe_cmd_idx(3,ch), Data0 /* DW: volume and filter cutoff targets */
-#define AWE_0080(ch) awe_cmd_idx(4,ch), Data0 /* DW: ?? */
-#define AWE_00A0(ch) awe_cmd_idx(5,ch), Data0 /* DW: ?? */
-#define AWE_PSST(ch) awe_cmd_idx(6,ch), Data0 /* DW: pan send and loop start address */
-#define AWE_CSL(ch) awe_cmd_idx(7,ch), Data0 /* DW: chorus send and loop end address */
-#define AWE_CCCA(ch) awe_cmd_idx(0,ch), Data1 /* DW: Q, control bits, and current address */
-#define AWE_HWCF4 awe_cmd_idx(1,9), Data1 /* DW: config dw 4 */
-#define AWE_HWCF5 awe_cmd_idx(1,10), Data1 /* DW: config dw 5 */
-#define AWE_HWCF6 awe_cmd_idx(1,13), Data1 /* DW: config dw 6 */
-#define AWE_HWCF7 awe_cmd_idx(1,14), Data1 /* DW: config dw 7? (not documented) */
-#define AWE_SMALR awe_cmd_idx(1,20), Data1 /* DW: sound memory address for left read */
-#define AWE_SMARR awe_cmd_idx(1,21), Data1 /* DW: for right read */
-#define AWE_SMALW awe_cmd_idx(1,22), Data1 /* DW: sound memory address for left write */
-#define AWE_SMARW awe_cmd_idx(1,23), Data1 /* DW: for right write */
-#define AWE_SMLD awe_cmd_idx(1,26), Data1 /* W: sound memory left data */
-#define AWE_SMRD awe_cmd_idx(1,26), Data2 /* W: right data */
-#define AWE_WC awe_cmd_idx(1,27), Data2 /* W: sample counter */
-#define AWE_WC_Cmd awe_cmd_idx(1,27)
-#define AWE_WC_Port Data2
-#define AWE_HWCF1 awe_cmd_idx(1,29), Data1 /* W: config w 1 */
-#define AWE_HWCF2 awe_cmd_idx(1,30), Data1 /* W: config w 2 */
-#define AWE_HWCF3 awe_cmd_idx(1,31), Data1 /* W: config w 3 */
-#define AWE_INIT1(ch) awe_cmd_idx(2,ch), Data1 /* W: init array 1 */
-#define AWE_INIT2(ch) awe_cmd_idx(2,ch), Data2 /* W: init array 2 */
-#define AWE_INIT3(ch) awe_cmd_idx(3,ch), Data1 /* W: init array 3 */
-#define AWE_INIT4(ch) awe_cmd_idx(3,ch), Data2 /* W: init array 4 */
-#define AWE_ENVVOL(ch) awe_cmd_idx(4,ch), Data1 /* W: volume envelope delay */
-#define AWE_DCYSUSV(ch) awe_cmd_idx(5,ch), Data1 /* W: volume envelope sustain and decay */
-#define AWE_ENVVAL(ch) awe_cmd_idx(6,ch), Data1 /* W: modulation envelope delay */
-#define AWE_DCYSUS(ch) awe_cmd_idx(7,ch), Data1 /* W: modulation envelope sustain and decay */
-#define AWE_ATKHLDV(ch) awe_cmd_idx(4,ch), Data2 /* W: volume envelope attack and hold */
-#define AWE_LFO1VAL(ch) awe_cmd_idx(5,ch), Data2 /* W: LFO#1 Delay */
-#define AWE_ATKHLD(ch) awe_cmd_idx(6,ch), Data2 /* W: modulation envelope attack and hold */
-#define AWE_LFO2VAL(ch) awe_cmd_idx(7,ch), Data2 /* W: LFO#2 Delay */
-#define AWE_IP(ch) awe_cmd_idx(0,ch), Data3 /* W: initial pitch */
-#define AWE_IFATN(ch) awe_cmd_idx(1,ch), Data3 /* W: initial filter cutoff and attenuation */
-#define AWE_PEFE(ch) awe_cmd_idx(2,ch), Data3 /* W: pitch and filter envelope heights */
-#define AWE_FMMOD(ch) awe_cmd_idx(3,ch), Data3 /* W: vibrato and filter modulation freq */
-#define AWE_TREMFRQ(ch) awe_cmd_idx(4,ch), Data3 /* W: LFO#1 tremolo amount and freq */
-#define AWE_FM2FRQ2(ch) awe_cmd_idx(5,ch), Data3 /* W: LFO#2 vibrato amount and freq */
-
-/* used during detection (returns ROM version?; not documented in ADIP) */
-#define AWE_U1 0xE0, Data3 /* (R)(W) used in initialization */
-#define AWE_U2(ch) 0xC0+(ch), Data3 /* (W)(W) used in init envelope */
-
-
-#define AWE_MAX_VOICES 32
-#define AWE_NORMAL_VOICES 30 /*30&31 are reserved for DRAM refresh*/
-
-#define AWE_MAX_CHANNELS 32 /* max midi channels (must >= voices) */
-#define AWE_MAX_LAYERS AWE_MAX_VOICES /* maximum number of multiple layers */
-
-#define AWE_DRAM_OFFSET 0x200000
-#define AWE_MAX_DRAM_SIZE (28 * 1024) /* 28 MB is max onboard memory */
-
-#endif
diff --git a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c
deleted file mode 100644
index d1a0eb294d6f..000000000000
--- a/sound/oss/awe_wave.c
+++ /dev/null
@@ -1,6149 +0,0 @@
-/*
- * sound/awe_wave.c
- *
- * The low level driver for the AWE32/SB32/AWE64 wave table synth.
- * version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-2000 Takashi Iwai
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * Changelog:
- * Aug 18, 2003, Adam Belay <ambx1@neo.rr.com>
- * - detection code rewrite
- */
-
-#include <linux/awe_voice.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/pnp.h>
-
-#include "sound_config.h"
-
-#include "awe_wave.h"
-#include "awe_hw.h"
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-#include "tuning.h"
-#include <linux/ultrasound.h>
-#endif
-
-/*
- * debug message
- */
-
-#ifdef AWE_DEBUG_ON
-#define DEBUG(LVL,XXX) {if (ctrls[AWE_MD_DEBUG_MODE] > LVL) { XXX; }}
-#define ERRMSG(XXX) {if (ctrls[AWE_MD_DEBUG_MODE]) { XXX; }}
-#define FATALERR(XXX) XXX
-#else
-#define DEBUG(LVL,XXX) /**/
-#define ERRMSG(XXX) XXX
-#define FATALERR(XXX) XXX
-#endif
-
-/*
- * bank and voice record
- */
-
-typedef struct _sf_list sf_list;
-typedef struct _awe_voice_list awe_voice_list;
-typedef struct _awe_sample_list awe_sample_list;
-
-/* soundfont record */
-struct _sf_list {
- unsigned short sf_id; /* id number */
- unsigned short type; /* lock & shared flags */
- int num_info; /* current info table index */
- int num_sample; /* current sample table index */
- int mem_ptr; /* current word byte pointer */
- awe_voice_list *infos, *last_infos; /* instruments */
- awe_sample_list *samples, *last_samples; /* samples */
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- sf_list *shared; /* shared list */
- unsigned char name[AWE_PATCH_NAME_LEN]; /* sharing id */
-#endif
- sf_list *next, *prev;
-};
-
-/* instrument list */
-struct _awe_voice_list {
- awe_voice_info v; /* instrument information */
- sf_list *holder; /* parent sf_list of this record */
- unsigned char bank, instr; /* preset number information */
- char type, disabled; /* type=normal/mapped, disabled=boolean */
- awe_voice_list *next; /* linked list with same sf_id */
- awe_voice_list *next_instr; /* instrument list */
- awe_voice_list *next_bank; /* hash table list */
-};
-
-/* voice list type */
-#define V_ST_NORMAL 0
-#define V_ST_MAPPED 1
-
-/* sample list */
-struct _awe_sample_list {
- awe_sample_info v; /* sample information */
- sf_list *holder; /* parent sf_list of this record */
- awe_sample_list *next; /* linked list with same sf_id */
-};
-
-/* sample and information table */
-static int current_sf_id; /* current number of fonts */
-static int locked_sf_id; /* locked position */
-static sf_list *sfhead, *sftail; /* linked-lists */
-
-#define awe_free_mem_ptr() (sftail ? sftail->mem_ptr : 0)
-#define awe_free_info() (sftail ? sftail->num_info : 0)
-#define awe_free_sample() (sftail ? sftail->num_sample : 0)
-
-#define AWE_MAX_PRESETS 256
-#define AWE_DEFAULT_PRESET 0
-#define AWE_DEFAULT_BANK 0
-#define AWE_DEFAULT_DRUM 0
-#define AWE_DRUM_BANK 128
-
-#define MAX_LAYERS AWE_MAX_VOICES
-
-/* preset table index */
-static awe_voice_list *preset_table[AWE_MAX_PRESETS];
-
-/*
- * voice table
- */
-
-/* effects table */
-typedef struct FX_Rec { /* channel effects */
- unsigned char flags[AWE_FX_END];
- short val[AWE_FX_END];
-} FX_Rec;
-
-
-/* channel parameters */
-typedef struct _awe_chan_info {
- int channel; /* channel number */
- int bank; /* current tone bank */
- int instr; /* current program */
- int bender; /* midi pitchbend (-8192 - 8192) */
- int bender_range; /* midi bender range (x100) */
- int panning; /* panning (0-127) */
- int main_vol; /* channel volume (0-127) */
- int expression_vol; /* midi expression (0-127) */
- int chan_press; /* channel pressure */
- int sustained; /* sustain status in MIDI */
- FX_Rec fx; /* effects */
- FX_Rec fx_layer[MAX_LAYERS]; /* layer effects */
-} awe_chan_info;
-
-/* voice parameters */
-typedef struct _voice_info {
- int state;
-#define AWE_ST_OFF (1<<0) /* no sound */
-#define AWE_ST_ON (1<<1) /* playing */
-#define AWE_ST_STANDBY (1<<2) /* stand by for playing */
-#define AWE_ST_SUSTAINED (1<<3) /* sustained */
-#define AWE_ST_MARK (1<<4) /* marked for allocation */
-#define AWE_ST_DRAM (1<<5) /* DRAM read/write */
-#define AWE_ST_FM (1<<6) /* reserved for FM */
-#define AWE_ST_RELEASED (1<<7) /* released */
-
- int ch; /* midi channel */
- int key; /* internal key for search */
- int layer; /* layer number (for channel mode only) */
- int time; /* allocated time */
- awe_chan_info *cinfo; /* channel info */
-
- int note; /* midi key (0-127) */
- int velocity; /* midi velocity (0-127) */
- int sostenuto; /* sostenuto on/off */
- awe_voice_info *sample; /* assigned voice */
-
- /* EMU8000 parameters */
- int apitch; /* pitch parameter */
- int avol; /* volume parameter */
- int apan; /* panning parameter */
- int acutoff; /* cutoff parameter */
- short aaux; /* aux word */
-} voice_info;
-
-/* voice information */
-static voice_info voices[AWE_MAX_VOICES];
-
-#define IS_NO_SOUND(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_RELEASED|AWE_ST_STANDBY|AWE_ST_SUSTAINED))
-#define IS_NO_EFFECT(v) (voices[v].state != AWE_ST_ON)
-#define IS_PLAYING(v) (voices[v].state & (AWE_ST_ON|AWE_ST_SUSTAINED|AWE_ST_RELEASED))
-#define IS_EMPTY(v) (voices[v].state & (AWE_ST_OFF|AWE_ST_MARK|AWE_ST_DRAM|AWE_ST_FM))
-
-
-/* MIDI channel effects information (for hw control) */
-static awe_chan_info channels[AWE_MAX_CHANNELS];
-
-
-/*
- * global variables
- */
-
-#ifndef AWE_DEFAULT_BASE_ADDR
-#define AWE_DEFAULT_BASE_ADDR 0 /* autodetect */
-#endif
-
-#ifndef AWE_DEFAULT_MEM_SIZE
-#define AWE_DEFAULT_MEM_SIZE -1 /* autodetect */
-#endif
-
-static int io = AWE_DEFAULT_BASE_ADDR; /* Emu8000 base address */
-static int memsize = AWE_DEFAULT_MEM_SIZE; /* memory size in Kbytes */
-#ifdef CONFIG_PNP
-static int isapnp = -1;
-#else
-static int isapnp;
-#endif
-
-MODULE_AUTHOR("Takashi Iwai <iwai@ww.uni-erlangen.de>");
-MODULE_DESCRIPTION("SB AWE32/64 WaveTable driver");
-MODULE_LICENSE("GPL");
-
-module_param(io, int, 0);
-MODULE_PARM_DESC(io, "base i/o port of Emu8000");
-module_param(memsize, int, 0);
-MODULE_PARM_DESC(memsize, "onboard DRAM size in Kbytes");
-module_param(isapnp, bool, 0);
-MODULE_PARM_DESC(isapnp, "use ISAPnP detection");
-
-/* DRAM start offset */
-static int awe_mem_start = AWE_DRAM_OFFSET;
-
-/* maximum channels for playing */
-static int awe_max_voices = AWE_MAX_VOICES;
-
-static int patch_opened; /* sample already loaded? */
-
-static char atten_relative = FALSE;
-static short atten_offset;
-
-static int awe_present = FALSE; /* awe device present? */
-static int awe_busy = FALSE; /* awe device opened? */
-
-static int my_dev = -1;
-
-#define DEFAULT_DRUM_FLAGS ((1 << 9) | (1 << 25))
-#define IS_DRUM_CHANNEL(c) (drum_flags & (1 << (c)))
-#define DRUM_CHANNEL_ON(c) (drum_flags |= (1 << (c)))
-#define DRUM_CHANNEL_OFF(c) (drum_flags &= ~(1 << (c)))
-static unsigned int drum_flags = DEFAULT_DRUM_FLAGS; /* channel flags */
-
-static int playing_mode = AWE_PLAY_INDIRECT;
-#define SINGLE_LAYER_MODE() (playing_mode == AWE_PLAY_INDIRECT || playing_mode == AWE_PLAY_DIRECT)
-#define MULTI_LAYER_MODE() (playing_mode == AWE_PLAY_MULTI || playing_mode == AWE_PLAY_MULTI2)
-
-static int current_alloc_time; /* voice allocation index for channel mode */
-
-static struct synth_info awe_info = {
- "AWE32 Synth", /* name */
- 0, /* device */
- SYNTH_TYPE_SAMPLE, /* synth_type */
- SAMPLE_TYPE_AWE32, /* synth_subtype */
- 0, /* perc_mode (obsolete) */
- AWE_MAX_VOICES, /* nr_voices */
- 0, /* nr_drums (obsolete) */
- 400 /* instr_bank_size */
-};
-
-
-static struct voice_alloc_info *voice_alloc; /* set at initialization */
-
-
-/*
- * function prototypes
- */
-
-static int awe_request_region(void);
-static void awe_release_region(void);
-
-static void awe_reset_samples(void);
-/* emu8000 chip i/o access */
-static void setup_ports(int p1, int p2, int p3);
-static void awe_poke(unsigned short cmd, unsigned short port, unsigned short data);
-static void awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data);
-static unsigned short awe_peek(unsigned short cmd, unsigned short port);
-static unsigned int awe_peek_dw(unsigned short cmd, unsigned short port);
-static void awe_wait(unsigned short delay);
-
-/* initialize emu8000 chip */
-static void awe_initialize(void);
-
-/* set voice parameters */
-static void awe_init_ctrl_parms(int init_all);
-static void awe_init_voice_info(awe_voice_info *vp);
-static void awe_init_voice_parm(awe_voice_parm *pp);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int freq_to_note(int freq);
-static int calc_rate_offset(int Hz);
-/*static int calc_parm_delay(int msec);*/
-static int calc_parm_hold(int msec);
-static int calc_parm_attack(int msec);
-static int calc_parm_decay(int msec);
-static int calc_parm_search(int msec, short *table);
-#endif /* gus compat */
-
-/* turn on/off note */
-static void awe_note_on(int voice);
-static void awe_note_off(int voice);
-static void awe_terminate(int voice);
-static void awe_exclusive_off(int voice);
-static void awe_note_off_all(int do_sustain);
-
-/* calculate voice parameters */
-typedef void (*fx_affect_func)(int voice, int forced);
-static void awe_set_pitch(int voice, int forced);
-static void awe_set_voice_pitch(int voice, int forced);
-static void awe_set_volume(int voice, int forced);
-static void awe_set_voice_vol(int voice, int forced);
-static void awe_set_pan(int voice, int forced);
-static void awe_fx_fmmod(int voice, int forced);
-static void awe_fx_tremfrq(int voice, int forced);
-static void awe_fx_fm2frq2(int voice, int forced);
-static void awe_fx_filterQ(int voice, int forced);
-static void awe_calc_pitch(int voice);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_calc_pitch_from_freq(int voice, int freq);
-#endif
-static void awe_calc_volume(int voice);
-static void awe_update_volume(void);
-static void awe_change_master_volume(short val);
-static void awe_voice_init(int voice, int init_all);
-static void awe_channel_init(int ch, int init_all);
-static void awe_fx_init(int ch);
-static void awe_send_effect(int voice, int layer, int type, int val);
-static void awe_modwheel_change(int voice, int value);
-
-/* sequencer interface */
-static int awe_open(int dev, int mode);
-static void awe_close(int dev);
-static int awe_ioctl(int dev, unsigned int cmd, void __user * arg);
-static int awe_kill_note(int dev, int voice, int note, int velocity);
-static int awe_start_note(int dev, int v, int note_num, int volume);
-static int awe_set_instr(int dev, int voice, int instr_no);
-static int awe_set_instr_2(int dev, int voice, int instr_no);
-static void awe_reset(int dev);
-static void awe_hw_control(int dev, unsigned char *event);
-static int awe_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag);
-static void awe_aftertouch(int dev, int voice, int pressure);
-static void awe_controller(int dev, int voice, int ctrl_num, int value);
-static void awe_panning(int dev, int voice, int value);
-static void awe_volume_method(int dev, int mode);
-static void awe_bender(int dev, int voice, int value);
-static int awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc);
-static void awe_setup_voice(int dev, int voice, int chn);
-
-#define awe_key_pressure(dev,voice,key,press) awe_start_note(dev,voice,(key)+128,press)
-
-/* hardware controls */
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static void awe_hw_gus_control(int dev, int cmd, unsigned char *event);
-#endif
-static void awe_hw_awe_control(int dev, int cmd, unsigned char *event);
-static void awe_voice_change(int voice, fx_affect_func func);
-static void awe_sostenuto_on(int voice, int forced);
-static void awe_sustain_off(int voice, int forced);
-static void awe_terminate_and_init(int voice, int forced);
-
-/* voice search */
-static int awe_search_key(int bank, int preset, int note);
-static awe_voice_list *awe_search_instr(int bank, int preset, int note);
-static int awe_search_multi_voices(awe_voice_list *rec, int note, int velocity, awe_voice_info **vlist);
-static void awe_alloc_multi_voices(int ch, int note, int velocity, int key);
-static void awe_alloc_one_voice(int voice, int note, int velocity);
-static int awe_clear_voice(void);
-
-/* load / remove patches */
-static int awe_open_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_close_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_info(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_remove_info(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_data(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_replace_data(awe_patch_info *patch, const char __user *addr, int count);
-static int awe_load_map(awe_patch_info *patch, const char __user *addr, int count);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-static int awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag);
-#endif
-/*static int awe_probe_info(awe_patch_info *patch, const char __user *addr, int count);*/
-static int awe_probe_data(awe_patch_info *patch, const char __user *addr, int count);
-static sf_list *check_patch_opened(int type, char *name);
-static int awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *sp, int channels);
-static int awe_create_sf(int type, char *name);
-static void awe_free_sf(sf_list *sf);
-static void add_sf_info(sf_list *sf, awe_voice_list *rec);
-static void add_sf_sample(sf_list *sf, awe_sample_list *smp);
-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next);
-static void add_info_list(awe_voice_list *rec);
-static void awe_remove_samples(int sf_id);
-static void rebuild_preset_list(void);
-static short awe_set_sample(awe_voice_list *rec);
-static awe_sample_list *search_sample_index(sf_list *sf, int sample);
-
-static int is_identical_holder(sf_list *sf1, sf_list *sf2);
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-static int is_identical_name(unsigned char *name, sf_list *p);
-static int is_shared_sf(unsigned char *name);
-static int info_duplicated(sf_list *sf, awe_voice_list *rec);
-#endif /* allow sharing */
-
-/* lowlevel functions */
-static void awe_init_audio(void);
-static void awe_init_dma(void);
-static void awe_init_array(void);
-static void awe_send_array(unsigned short *data);
-static void awe_tweak_voice(int voice);
-static void awe_tweak(void);
-static void awe_init_fm(void);
-static int awe_open_dram_for_write(int offset, int channels);
-static void awe_open_dram_for_check(void);
-static void awe_close_dram(void);
-/*static void awe_write_dram(unsigned short c);*/
-static int awe_detect_base(int addr);
-static int awe_detect(void);
-static void awe_check_dram(void);
-static int awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count);
-static void awe_set_chorus_mode(int mode);
-static void awe_update_chorus_mode(void);
-static int awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count);
-static void awe_set_reverb_mode(int mode);
-static void awe_update_reverb_mode(void);
-static void awe_equalizer(int bass, int treble);
-static void awe_update_equalizer(void);
-
-#ifdef CONFIG_AWE32_MIXER
-static void attach_mixer(void);
-static void unload_mixer(void);
-#endif
-
-#ifdef CONFIG_AWE32_MIDIEMU
-static void attach_midiemu(void);
-static void unload_midiemu(void);
-#endif
-
-#define limitvalue(x, a, b) if ((x) < (a)) (x) = (a); else if ((x) > (b)) (x) = (b)
-
-/*
- * control parameters
- */
-
-
-#ifdef AWE_USE_NEW_VOLUME_CALC
-#define DEF_VOLUME_CALC TRUE
-#else
-#define DEF_VOLUME_CALC FALSE
-#endif /* new volume */
-
-#define DEF_ZERO_ATTEN 32 /* 12dB below */
-#define DEF_MOD_SENSE 18
-#define DEF_CHORUS_MODE 2
-#define DEF_REVERB_MODE 4
-#define DEF_BASS_LEVEL 5
-#define DEF_TREBLE_LEVEL 9
-
-static struct CtrlParmsDef {
- int value;
- int init_each_time;
- void (*update)(void);
-} ctrl_parms[AWE_MD_END] = {
- {0,0, NULL}, {0,0, NULL}, /* <-- not used */
- {AWE_VERSION_NUMBER, FALSE, NULL},
- {TRUE, FALSE, NULL}, /* exclusive */
- {TRUE, FALSE, NULL}, /* realpan */
- {AWE_DEFAULT_BANK, FALSE, NULL}, /* gusbank */
- {FALSE, TRUE, NULL}, /* keep effect */
- {DEF_ZERO_ATTEN, FALSE, awe_update_volume}, /* zero_atten */
- {FALSE, FALSE, NULL}, /* chn_prior */
- {DEF_MOD_SENSE, FALSE, NULL}, /* modwheel sense */
- {AWE_DEFAULT_PRESET, FALSE, NULL}, /* def_preset */
- {AWE_DEFAULT_BANK, FALSE, NULL}, /* def_bank */
- {AWE_DEFAULT_DRUM, FALSE, NULL}, /* def_drum */
- {FALSE, FALSE, NULL}, /* toggle_drum_bank */
- {DEF_VOLUME_CALC, FALSE, awe_update_volume}, /* new_volume_calc */
- {DEF_CHORUS_MODE, FALSE, awe_update_chorus_mode}, /* chorus mode */
- {DEF_REVERB_MODE, FALSE, awe_update_reverb_mode}, /* reverb mode */
- {DEF_BASS_LEVEL, FALSE, awe_update_equalizer}, /* bass level */
- {DEF_TREBLE_LEVEL, FALSE, awe_update_equalizer}, /* treble level */
- {0, FALSE, NULL}, /* debug mode */
- {FALSE, FALSE, NULL}, /* pan exchange */
-};
-
-static int ctrls[AWE_MD_END];
-
-
-/*
- * synth operation table
- */
-
-static struct synth_operations awe_operations =
-{
- .owner = THIS_MODULE,
- .id = "EMU8K",
- .info = &awe_info,
- .midi_dev = 0,
- .synth_type = SYNTH_TYPE_SAMPLE,
- .synth_subtype = SAMPLE_TYPE_AWE32,
- .open = awe_open,
- .close = awe_close,
- .ioctl = awe_ioctl,
- .kill_note = awe_kill_note,
- .start_note = awe_start_note,
- .set_instr = awe_set_instr_2,
- .reset = awe_reset,
- .hw_control = awe_hw_control,
- .load_patch = awe_load_patch,
- .aftertouch = awe_aftertouch,
- .controller = awe_controller,
- .panning = awe_panning,
- .volume_method = awe_volume_method,
- .bender = awe_bender,
- .alloc_voice = awe_alloc,
- .setup_voice = awe_setup_voice
-};
-
-static void free_tables(void)
-{
- if (sftail) {
- sf_list *p, *prev;
- for (p = sftail; p; p = prev) {
- prev = p->prev;
- awe_free_sf(p);
- }
- }
- sfhead = sftail = NULL;
-}
-
-/*
- * clear sample tables
- */
-
-static void
-awe_reset_samples(void)
-{
- /* free all bank tables */
- memset(preset_table, 0, sizeof(preset_table));
- free_tables();
-
- current_sf_id = 0;
- locked_sf_id = 0;
- patch_opened = 0;
-}
-
-
-/*
- * EMU register access
- */
-
-/* select a given AWE32 pointer */
-static int awe_ports[5];
-static int port_setuped = FALSE;
-static int awe_cur_cmd = -1;
-#define awe_set_cmd(cmd) \
-if (awe_cur_cmd != cmd) { outw(cmd, awe_ports[Pointer]); awe_cur_cmd = cmd; }
-
-/* write 16bit data */
-static void
-awe_poke(unsigned short cmd, unsigned short port, unsigned short data)
-{
- awe_set_cmd(cmd);
- outw(data, awe_ports[port]);
-}
-
-/* write 32bit data */
-static void
-awe_poke_dw(unsigned short cmd, unsigned short port, unsigned int data)
-{
- unsigned short addr = awe_ports[port];
- awe_set_cmd(cmd);
- outw(data, addr); /* write lower 16 bits */
- outw(data >> 16, addr + 2); /* write higher 16 bits */
-}
-
-/* read 16bit data */
-static unsigned short
-awe_peek(unsigned short cmd, unsigned short port)
-{
- unsigned short k;
- awe_set_cmd(cmd);
- k = inw(awe_ports[port]);
- return k;
-}
-
-/* read 32bit data */
-static unsigned int
-awe_peek_dw(unsigned short cmd, unsigned short port)
-{
- unsigned int k1, k2;
- unsigned short addr = awe_ports[port];
- awe_set_cmd(cmd);
- k1 = inw(addr);
- k2 = inw(addr + 2);
- k1 |= k2 << 16;
- return k1;
-}
-
-/* wait delay number of AWE32 44100Hz clocks */
-#ifdef WAIT_BY_LOOP /* wait by loop -- that's not good.. */
-static void
-awe_wait(unsigned short delay)
-{
- unsigned short clock, target;
- unsigned short port = awe_ports[AWE_WC_Port];
- int counter;
-
- /* sample counter */
- awe_set_cmd(AWE_WC_Cmd);
- clock = (unsigned short)inw(port);
- target = clock + delay;
- counter = 0;
- if (target < clock) {
- for (; (unsigned short)inw(port) > target; counter++)
- if (counter > 65536)
- break;
- }
- for (; (unsigned short)inw(port) < target; counter++)
- if (counter > 65536)
- break;
-}
-#else
-
-static void awe_wait(unsigned short delay)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout((HZ*(unsigned long)delay + 44099)/44100);
-}
-/*
-static void awe_wait(unsigned short delay)
-{
- udelay(((unsigned long)delay * 1000000L + 44099) / 44100);
-}
-*/
-#endif /* wait by loop */
-
-/* write a word data */
-#define awe_write_dram(c) awe_poke(AWE_SMLD, c)
-
-/*
- * AWE32 voice parameters
- */
-
-/* initialize voice_info record */
-static void
-awe_init_voice_info(awe_voice_info *vp)
-{
- vp->sample = 0;
- vp->rate_offset = 0;
-
- vp->start = 0;
- vp->end = 0;
- vp->loopstart = 0;
- vp->loopend = 0;
- vp->mode = 0;
- vp->root = 60;
- vp->tune = 0;
- vp->low = 0;
- vp->high = 127;
- vp->vellow = 0;
- vp->velhigh = 127;
-
- vp->fixkey = -1;
- vp->fixvel = -1;
- vp->fixpan = -1;
- vp->pan = -1;
-
- vp->exclusiveClass = 0;
- vp->amplitude = 127;
- vp->attenuation = 0;
- vp->scaleTuning = 100;
-
- awe_init_voice_parm(&vp->parm);
-}
-
-/* initialize voice_parm record:
- * Env1/2: delay=0, attack=0, hold=0, sustain=0, decay=0, release=0.
- * Vibrato and Tremolo effects are zero.
- * Cutoff is maximum.
- * Chorus and Reverb effects are zero.
- */
-static void
-awe_init_voice_parm(awe_voice_parm *pp)
-{
- pp->moddelay = 0x8000;
- pp->modatkhld = 0x7f7f;
- pp->moddcysus = 0x7f7f;
- pp->modrelease = 0x807f;
- pp->modkeyhold = 0;
- pp->modkeydecay = 0;
-
- pp->voldelay = 0x8000;
- pp->volatkhld = 0x7f7f;
- pp->voldcysus = 0x7f7f;
- pp->volrelease = 0x807f;
- pp->volkeyhold = 0;
- pp->volkeydecay = 0;
-
- pp->lfo1delay = 0x8000;
- pp->lfo2delay = 0x8000;
- pp->pefe = 0;
-
- pp->fmmod = 0;
- pp->tremfrq = 0;
- pp->fm2frq2 = 0;
-
- pp->cutoff = 0xff;
- pp->filterQ = 0;
-
- pp->chorus = 0;
- pp->reverb = 0;
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* convert frequency mHz to abstract cents (= midi key * 100) */
-static int
-freq_to_note(int mHz)
-{
- /* abscents = log(mHz/8176) / log(2) * 1200 */
- unsigned int max_val = (unsigned int)0xffffffff / 10000;
- int i, times;
- unsigned int base;
- unsigned int freq;
- int note, tune;
-
- if (mHz == 0)
- return 0;
- if (mHz < 0)
- return 12799; /* maximum */
-
- freq = mHz;
- note = 0;
- for (base = 8176 * 2; freq >= base; base *= 2) {
- note += 12;
- if (note >= 128) /* over maximum */
- return 12799;
- }
- base /= 2;
-
- /* to avoid overflow... */
- times = 10000;
- while (freq > max_val) {
- max_val *= 10;
- times /= 10;
- base /= 10;
- }
-
- freq = freq * times / base;
- for (i = 0; i < 12; i++) {
- if (freq < semitone_tuning[i+1])
- break;
- note++;
- }
-
- tune = 0;
- freq = freq * 10000 / semitone_tuning[i];
- for (i = 0; i < 100; i++) {
- if (freq < cent_tuning[i+1])
- break;
- tune++;
- }
-
- return note * 100 + tune;
-}
-
-
-/* convert Hz to AWE32 rate offset:
- * sample pitch offset for the specified sample rate
- * rate=44100 is no offset, each 4096 is 1 octave (twice).
- * eg, when rate is 22050, this offset becomes -4096.
- */
-static int
-calc_rate_offset(int Hz)
-{
- /* offset = log(Hz / 44100) / log(2) * 4096 */
- int freq, base, i;
-
- /* maybe smaller than max (44100Hz) */
- if (Hz <= 0 || Hz >= 44100) return 0;
-
- base = 0;
- for (freq = Hz * 2; freq < 44100; freq *= 2)
- base++;
- base *= 1200;
-
- freq = 44100 * 10000 / (freq/2);
- for (i = 0; i < 12; i++) {
- if (freq < semitone_tuning[i+1])
- break;
- base += 100;
- }
- freq = freq * 10000 / semitone_tuning[i];
- for (i = 0; i < 100; i++) {
- if (freq < cent_tuning[i+1])
- break;
- base++;
- }
- return -base * 4096 / 1200;
-}
-
-
-/*
- * convert envelope time parameter to AWE32 raw parameter
- */
-
-/* attack & decay/release time table (msec) */
-static short attack_time_tbl[128] = {
-32767, 32767, 5989, 4235, 2994, 2518, 2117, 1780, 1497, 1373, 1259, 1154, 1058, 970, 890, 816,
-707, 691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377,
-361, 345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188,
-180, 172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94,
-90, 86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47,
-45, 43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23,
-22, 21, 20, 19, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
-11, 11, 10, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 0,
-};
-
-static short decay_time_tbl[128] = {
-32767, 32767, 22614, 15990, 11307, 9508, 7995, 6723, 5653, 5184, 4754, 4359, 3997, 3665, 3361, 3082,
-2828, 2765, 2648, 2535, 2428, 2325, 2226, 2132, 2042, 1955, 1872, 1793, 1717, 1644, 1574, 1507,
-1443, 1382, 1324, 1267, 1214, 1162, 1113, 1066, 978, 936, 897, 859, 822, 787, 754, 722,
-691, 662, 634, 607, 581, 557, 533, 510, 489, 468, 448, 429, 411, 393, 377, 361,
-345, 331, 317, 303, 290, 278, 266, 255, 244, 234, 224, 214, 205, 196, 188, 180,
-172, 165, 158, 151, 145, 139, 133, 127, 122, 117, 112, 107, 102, 98, 94, 90,
-86, 82, 79, 75, 72, 69, 66, 63, 61, 58, 56, 53, 51, 49, 47, 45,
-43, 41, 39, 37, 36, 34, 33, 31, 30, 29, 28, 26, 25, 24, 23, 22,
-};
-
-#define calc_parm_delay(msec) (0x8000 - (msec) * 1000 / 725);
-
-/* delay time = 0x8000 - msec/92 */
-static int
-calc_parm_hold(int msec)
-{
- int val = (0x7f * 92 - msec) / 92;
- if (val < 1) val = 1;
- if (val > 127) val = 127;
- return val;
-}
-
-/* attack time: search from time table */
-static int
-calc_parm_attack(int msec)
-{
- return calc_parm_search(msec, attack_time_tbl);
-}
-
-/* decay/release time: search from time table */
-static int
-calc_parm_decay(int msec)
-{
- return calc_parm_search(msec, decay_time_tbl);
-}
-
-/* search an index for specified time from given time table */
-static int
-calc_parm_search(int msec, short *table)
-{
- int left = 1, right = 127, mid;
- while (left < right) {
- mid = (left + right) / 2;
- if (msec < (int)table[mid])
- left = mid + 1;
- else
- right = mid;
- }
- return left;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*
- * effects table
- */
-
-/* set an effect value */
-#define FX_FLAG_OFF 0
-#define FX_FLAG_SET 1
-#define FX_FLAG_ADD 2
-
-#define FX_SET(rec,type,value) \
- ((rec)->flags[type] = FX_FLAG_SET, (rec)->val[type] = (value))
-#define FX_ADD(rec,type,value) \
- ((rec)->flags[type] = FX_FLAG_ADD, (rec)->val[type] = (value))
-#define FX_UNSET(rec,type) \
- ((rec)->flags[type] = FX_FLAG_OFF, (rec)->val[type] = 0)
-
-/* check the effect value is set */
-#define FX_ON(rec,type) ((rec)->flags[type])
-
-#define PARM_BYTE 0
-#define PARM_WORD 1
-#define PARM_SIGN 2
-
-static struct PARM_DEFS {
- int type; /* byte or word */
- int low, high; /* value range */
- fx_affect_func realtime; /* realtime paramater change */
-} parm_defs[] = {
- {PARM_WORD, 0, 0x8000, NULL}, /* env1 delay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 attack */
- {PARM_BYTE, 0, 0x7e, NULL}, /* env1 hold */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 decay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env1 release */
- {PARM_BYTE, 0, 0x7f, NULL}, /* env1 sustain */
- {PARM_BYTE, 0, 0xff, NULL}, /* env1 pitch */
- {PARM_BYTE, 0, 0xff, NULL}, /* env1 cutoff */
-
- {PARM_WORD, 0, 0x8000, NULL}, /* env2 delay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 attack */
- {PARM_BYTE, 0, 0x7e, NULL}, /* env2 hold */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 decay */
- {PARM_BYTE, 1, 0x7f, NULL}, /* env2 release */
- {PARM_BYTE, 0, 0x7f, NULL}, /* env2 sustain */
-
- {PARM_WORD, 0, 0x8000, NULL}, /* lfo1 delay */
- {PARM_BYTE, 0, 0xff, awe_fx_tremfrq}, /* lfo1 freq */
- {PARM_SIGN, -128, 127, awe_fx_tremfrq}, /* lfo1 volume */
- {PARM_SIGN, -128, 127, awe_fx_fmmod}, /* lfo1 pitch */
- {PARM_BYTE, 0, 0xff, awe_fx_fmmod}, /* lfo1 cutoff */
-
- {PARM_WORD, 0, 0x8000, NULL}, /* lfo2 delay */
- {PARM_BYTE, 0, 0xff, awe_fx_fm2frq2}, /* lfo2 freq */
- {PARM_SIGN, -128, 127, awe_fx_fm2frq2}, /* lfo2 pitch */
-
- {PARM_WORD, 0, 0xffff, awe_set_voice_pitch}, /* initial pitch */
- {PARM_BYTE, 0, 0xff, NULL}, /* chorus */
- {PARM_BYTE, 0, 0xff, NULL}, /* reverb */
- {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial cutoff */
- {PARM_BYTE, 0, 15, awe_fx_filterQ}, /* initial resonance */
-
- {PARM_WORD, 0, 0xffff, NULL}, /* sample start */
- {PARM_WORD, 0, 0xffff, NULL}, /* loop start */
- {PARM_WORD, 0, 0xffff, NULL}, /* loop end */
- {PARM_WORD, 0, 0xffff, NULL}, /* coarse sample start */
- {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop start */
- {PARM_WORD, 0, 0xffff, NULL}, /* coarse loop end */
- {PARM_BYTE, 0, 0xff, awe_set_volume}, /* initial attenuation */
-};
-
-
-static unsigned char
-FX_BYTE(FX_Rec *rec, FX_Rec *lay, int type, unsigned char value)
-{
- int effect = 0;
- int on = 0;
- if (lay && (on = FX_ON(lay, type)) != 0)
- effect = lay->val[type];
- if (!on && (on = FX_ON(rec, type)) != 0)
- effect = rec->val[type];
- if (on == FX_FLAG_ADD) {
- if (parm_defs[type].type == PARM_SIGN) {
- if (value > 0x7f)
- effect += (int)value - 0x100;
- else
- effect += (int)value;
- } else {
- effect += (int)value;
- }
- }
- if (on) {
- if (effect < parm_defs[type].low)
- effect = parm_defs[type].low;
- else if (effect > parm_defs[type].high)
- effect = parm_defs[type].high;
- return (unsigned char)effect;
- }
- return value;
-}
-
-/* get word effect value */
-static unsigned short
-FX_WORD(FX_Rec *rec, FX_Rec *lay, int type, unsigned short value)
-{
- int effect = 0;
- int on = 0;
- if (lay && (on = FX_ON(lay, type)) != 0)
- effect = lay->val[type];
- if (!on && (on = FX_ON(rec, type)) != 0)
- effect = rec->val[type];
- if (on == FX_FLAG_ADD)
- effect += (int)value;
- if (on) {
- if (effect < parm_defs[type].low)
- effect = parm_defs[type].low;
- else if (effect > parm_defs[type].high)
- effect = parm_defs[type].high;
- return (unsigned short)effect;
- }
- return value;
-}
-
-/* get word (upper=type1/lower=type2) effect value */
-static unsigned short
-FX_COMB(FX_Rec *rec, FX_Rec *lay, int type1, int type2, unsigned short value)
-{
- unsigned short tmp;
- tmp = FX_BYTE(rec, lay, type1, (unsigned char)(value >> 8));
- tmp <<= 8;
- tmp |= FX_BYTE(rec, lay, type2, (unsigned char)(value & 0xff));
- return tmp;
-}
-
-/* address offset */
-static int
-FX_OFFSET(FX_Rec *rec, FX_Rec *lay, int lo, int hi, int mode)
-{
- int addr = 0;
- if (lay && FX_ON(lay, hi))
- addr = (short)lay->val[hi];
- else if (FX_ON(rec, hi))
- addr = (short)rec->val[hi];
- addr = addr << 15;
- if (lay && FX_ON(lay, lo))
- addr += (short)lay->val[lo];
- else if (FX_ON(rec, lo))
- addr += (short)rec->val[lo];
- if (!(mode & AWE_SAMPLE_8BITS))
- addr /= 2;
- return addr;
-}
-
-
-/*
- * turn on/off sample
- */
-
-/* table for volume target calculation */
-static unsigned short voltarget[16] = {
- 0xEAC0, 0XE0C8, 0XD740, 0XCE20, 0XC560, 0XBD08, 0XB500, 0XAD58,
- 0XA5F8, 0X9EF0, 0X9830, 0X91C0, 0X8B90, 0X85A8, 0X8000, 0X7A90
-};
-
-static void
-awe_note_on(int voice)
-{
- unsigned int temp;
- int addr;
- int vtarget, ftarget, ptarget, pitch;
- awe_voice_info *vp;
- awe_voice_parm_block *parm;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- /* A voice sample must assigned before calling */
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- parm = (awe_voice_parm_block*)&vp->parm;
-
- /* channel to be silent and idle */
- awe_poke(AWE_DCYSUSV(voice), 0x0080);
- awe_poke(AWE_VTFT(voice), 0x0000FFFF);
- awe_poke(AWE_CVCF(voice), 0x0000FFFF);
- awe_poke(AWE_PTRX(voice), 0);
- awe_poke(AWE_CPF(voice), 0);
-
- /* set pitch offset */
- awe_set_pitch(voice, TRUE);
-
- /* modulation & volume envelope */
- if (parm->modatk >= 0x80 && parm->moddelay >= 0x8000) {
- awe_poke(AWE_ENVVAL(voice), 0xBFFF);
- pitch = (parm->env1pit<<4) + voices[voice].apitch;
- if (pitch > 0xffff) pitch = 0xffff;
- /* calculate filter target */
- ftarget = parm->cutoff + parm->env1fc;
- limitvalue(ftarget, 0, 255);
- ftarget <<= 8;
- } else {
- awe_poke(AWE_ENVVAL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_ENV1_DELAY, parm->moddelay));
- ftarget = parm->cutoff;
- ftarget <<= 8;
- pitch = voices[voice].apitch;
- }
-
- /* calcualte pitch target */
- if (pitch != 0xffff) {
- ptarget = 1 << (pitch >> 12);
- if (pitch & 0x800) ptarget += (ptarget*0x102e)/0x2710;
- if (pitch & 0x400) ptarget += (ptarget*0x764)/0x2710;
- if (pitch & 0x200) ptarget += (ptarget*0x389)/0x2710;
- ptarget += (ptarget>>1);
- if (ptarget > 0xffff) ptarget = 0xffff;
-
- } else ptarget = 0xffff;
- if (parm->modatk >= 0x80)
- awe_poke(AWE_ATKHLD(voice),
- FX_BYTE(fx, fx_lay, AWE_FX_ENV1_HOLD, parm->modhld) << 8 | 0x7f);
- else
- awe_poke(AWE_ATKHLD(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV1_HOLD, AWE_FX_ENV1_ATTACK,
- vp->parm.modatkhld));
- awe_poke(AWE_DCYSUS(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV1_SUSTAIN, AWE_FX_ENV1_DECAY,
- vp->parm.moddcysus));
-
- if (parm->volatk >= 0x80 && parm->voldelay >= 0x8000) {
- awe_poke(AWE_ENVVOL(voice), 0xBFFF);
- vtarget = voltarget[voices[voice].avol%0x10]>>(voices[voice].avol>>4);
- } else {
- awe_poke(AWE_ENVVOL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_ENV2_DELAY, vp->parm.voldelay));
- vtarget = 0;
- }
- if (parm->volatk >= 0x80)
- awe_poke(AWE_ATKHLDV(voice),
- FX_BYTE(fx, fx_lay, AWE_FX_ENV2_HOLD, parm->volhld) << 8 | 0x7f);
- else
- awe_poke(AWE_ATKHLDV(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV2_HOLD, AWE_FX_ENV2_ATTACK,
- vp->parm.volatkhld));
- /* decay/sustain parameter for volume envelope must be set at last */
-
- /* cutoff and volume */
- awe_set_volume(voice, TRUE);
-
- /* modulation envelope heights */
- awe_poke(AWE_PEFE(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV1_PITCH, AWE_FX_ENV1_CUTOFF,
- vp->parm.pefe));
-
- /* lfo1/2 delay */
- awe_poke(AWE_LFO1VAL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_LFO1_DELAY, vp->parm.lfo1delay));
- awe_poke(AWE_LFO2VAL(voice),
- FX_WORD(fx, fx_lay, AWE_FX_LFO2_DELAY, vp->parm.lfo2delay));
-
- /* lfo1 pitch & cutoff shift */
- awe_fx_fmmod(voice, TRUE);
- /* lfo1 volume & freq */
- awe_fx_tremfrq(voice, TRUE);
- /* lfo2 pitch & freq */
- awe_fx_fm2frq2(voice, TRUE);
- /* pan & loop start */
- awe_set_pan(voice, TRUE);
-
- /* chorus & loop end (chorus 8bit, MSB) */
- addr = vp->loopend - 1;
- addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_END,
- AWE_FX_COARSE_LOOP_END, vp->mode);
- temp = FX_BYTE(fx, fx_lay, AWE_FX_CHORUS, vp->parm.chorus);
- temp = (temp <<24) | (unsigned int)addr;
- awe_poke_dw(AWE_CSL(voice), temp);
- DEBUG(4,printk("AWE32: [-- loopend=%x/%x]\n", vp->loopend, addr));
-
- /* Q & current address (Q 4bit value, MSB) */
- addr = vp->start - 1;
- addr += FX_OFFSET(fx, fx_lay, AWE_FX_SAMPLE_START,
- AWE_FX_COARSE_SAMPLE_START, vp->mode);
- temp = FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ);
- temp = (temp<<28) | (unsigned int)addr;
- awe_poke_dw(AWE_CCCA(voice), temp);
- DEBUG(4,printk("AWE32: [-- startaddr=%x/%x]\n", vp->start, addr));
-
- /* clear unknown registers */
- awe_poke_dw(AWE_00A0(voice), 0);
- awe_poke_dw(AWE_0080(voice), 0);
-
- /* reset volume */
- awe_poke_dw(AWE_VTFT(voice), (vtarget<<16)|ftarget);
- awe_poke_dw(AWE_CVCF(voice), (vtarget<<16)|ftarget);
-
- /* set reverb */
- temp = FX_BYTE(fx, fx_lay, AWE_FX_REVERB, vp->parm.reverb);
- temp = (temp << 8) | (ptarget << 16) | voices[voice].aaux;
- awe_poke_dw(AWE_PTRX(voice), temp);
- awe_poke_dw(AWE_CPF(voice), ptarget << 16);
- /* turn on envelope */
- awe_poke(AWE_DCYSUSV(voice),
- FX_COMB(fx, fx_lay, AWE_FX_ENV2_SUSTAIN, AWE_FX_ENV2_DECAY,
- vp->parm.voldcysus));
-
- voices[voice].state = AWE_ST_ON;
-
- /* clear voice position for the next note on this channel */
- if (SINGLE_LAYER_MODE()) {
- FX_UNSET(fx, AWE_FX_SAMPLE_START);
- FX_UNSET(fx, AWE_FX_COARSE_SAMPLE_START);
- }
-}
-
-
-/* turn off the voice */
-static void
-awe_note_off(int voice)
-{
- awe_voice_info *vp;
- unsigned short tmp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if ((vp = voices[voice].sample) == NULL) {
- voices[voice].state = AWE_ST_OFF;
- return;
- }
-
- tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV1_RELEASE,
- (unsigned char)vp->parm.modrelease);
- awe_poke(AWE_DCYSUS(voice), tmp);
- tmp = 0x8000 | FX_BYTE(fx, fx_lay, AWE_FX_ENV2_RELEASE,
- (unsigned char)vp->parm.volrelease);
- awe_poke(AWE_DCYSUSV(voice), tmp);
- voices[voice].state = AWE_ST_RELEASED;
-}
-
-/* force to terminate the voice (no releasing echo) */
-static void
-awe_terminate(int voice)
-{
- awe_poke(AWE_DCYSUSV(voice), 0x807F);
- awe_tweak_voice(voice);
- voices[voice].state = AWE_ST_OFF;
-}
-
-/* turn off other voices with the same exclusive class (for drums) */
-static void
-awe_exclusive_off(int voice)
-{
- int i, exclass;
-
- if (voices[voice].sample == NULL)
- return;
- if ((exclass = voices[voice].sample->exclusiveClass) == 0)
- return; /* not exclusive */
-
- /* turn off voices with the same class */
- for (i = 0; i < awe_max_voices; i++) {
- if (i != voice && IS_PLAYING(i) &&
- voices[i].sample && voices[i].ch == voices[voice].ch &&
- voices[i].sample->exclusiveClass == exclass) {
- DEBUG(4,printk("AWE32: [exoff(%d)]\n", i));
- awe_terminate(i);
- awe_voice_init(i, TRUE);
- }
- }
-}
-
-
-/*
- * change the parameters of an audible voice
- */
-
-/* change pitch */
-static void
-awe_set_pitch(int voice, int forced)
-{
- if (IS_NO_EFFECT(voice) && !forced) return;
- awe_poke(AWE_IP(voice), voices[voice].apitch);
- DEBUG(3,printk("AWE32: [-- pitch=%x]\n", voices[voice].apitch));
-}
-
-/* calculate & change pitch */
-static void
-awe_set_voice_pitch(int voice, int forced)
-{
- awe_calc_pitch(voice);
- awe_set_pitch(voice, forced);
-}
-
-/* change volume & cutoff */
-static void
-awe_set_volume(int voice, int forced)
-{
- awe_voice_info *vp;
- unsigned short tmp2;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (!IS_PLAYING(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- tmp2 = FX_BYTE(fx, fx_lay, AWE_FX_CUTOFF,
- (unsigned char)voices[voice].acutoff);
- tmp2 = (tmp2 << 8);
- tmp2 |= FX_BYTE(fx, fx_lay, AWE_FX_ATTEN,
- (unsigned char)voices[voice].avol);
- awe_poke(AWE_IFATN(voice), tmp2);
-}
-
-/* calculate & change volume */
-static void
-awe_set_voice_vol(int voice, int forced)
-{
- if (IS_EMPTY(voice))
- return;
- awe_calc_volume(voice);
- awe_set_volume(voice, forced);
-}
-
-
-/* change pan; this could make a click noise.. */
-static void
-awe_set_pan(int voice, int forced)
-{
- unsigned int temp;
- int addr;
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- /* pan & loop start (pan 8bit, MSB, 0:right, 0xff:left) */
- if (vp->fixpan > 0) /* 0-127 */
- temp = 255 - (int)vp->fixpan * 2;
- else {
- int pos = 0;
- if (vp->pan >= 0) /* 0-127 */
- pos = (int)vp->pan * 2 - 128;
- pos += voices[voice].cinfo->panning; /* -128 - 127 */
- temp = 127 - pos;
- }
- limitvalue(temp, 0, 255);
- if (ctrls[AWE_MD_PAN_EXCHANGE]) {
- temp = 255 - temp;
- }
- if (forced || temp != voices[voice].apan) {
- voices[voice].apan = temp;
- if (temp == 0)
- voices[voice].aaux = 0xff;
- else
- voices[voice].aaux = (-temp) & 0xff;
- addr = vp->loopstart - 1;
- addr += FX_OFFSET(fx, fx_lay, AWE_FX_LOOP_START,
- AWE_FX_COARSE_LOOP_START, vp->mode);
- temp = (temp<<24) | (unsigned int)addr;
- awe_poke_dw(AWE_PSST(voice), temp);
- DEBUG(4,printk("AWE32: [-- loopstart=%x/%x]\n", vp->loopstart, addr));
- }
-}
-
-/* effects change during playing */
-static void
-awe_fx_fmmod(int voice, int forced)
-{
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
- awe_poke(AWE_FMMOD(voice),
- FX_COMB(fx, fx_lay, AWE_FX_LFO1_PITCH, AWE_FX_LFO1_CUTOFF,
- vp->parm.fmmod));
-}
-
-/* set tremolo (lfo1) volume & frequency */
-static void
-awe_fx_tremfrq(int voice, int forced)
-{
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
- awe_poke(AWE_TREMFRQ(voice),
- FX_COMB(fx, fx_lay, AWE_FX_LFO1_VOLUME, AWE_FX_LFO1_FREQ,
- vp->parm.tremfrq));
-}
-
-/* set lfo2 pitch & frequency */
-static void
-awe_fx_fm2frq2(int voice, int forced)
-{
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
- awe_poke(AWE_FM2FRQ2(voice),
- FX_COMB(fx, fx_lay, AWE_FX_LFO2_PITCH, AWE_FX_LFO2_FREQ,
- vp->parm.fm2frq2));
-}
-
-
-/* Q & current address (Q 4bit value, MSB) */
-static void
-awe_fx_filterQ(int voice, int forced)
-{
- unsigned int addr;
- awe_voice_info *vp;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- if (IS_NO_EFFECT(voice) && !forced) return;
- if ((vp = voices[voice].sample) == NULL || vp->index == 0)
- return;
-
- addr = awe_peek_dw(AWE_CCCA(voice)) & 0xffffff;
- addr |= (FX_BYTE(fx, fx_lay, AWE_FX_FILTERQ, vp->parm.filterQ) << 28);
- awe_poke_dw(AWE_CCCA(voice), addr);
-}
-
-/*
- * calculate pitch offset
- *
- * 0xE000 is no pitch offset at 44100Hz sample.
- * Every 4096 is one octave.
- */
-
-static void
-awe_calc_pitch(int voice)
-{
- voice_info *vp = &voices[voice];
- awe_voice_info *ap;
- awe_chan_info *cp = voices[voice].cinfo;
- int offset;
-
- /* search voice information */
- if ((ap = vp->sample) == NULL)
- return;
- if (ap->index == 0) {
- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample((awe_voice_list*)ap) == 0)
- return;
- }
-
- /* calculate offset */
- if (ap->fixkey >= 0) {
- DEBUG(3,printk("AWE32: p-> fixkey(%d) tune(%d)\n", ap->fixkey, ap->tune));
- offset = (ap->fixkey - ap->root) * 4096 / 12;
- } else {
- DEBUG(3,printk("AWE32: p(%d)-> root(%d) tune(%d)\n", vp->note, ap->root, ap->tune));
- offset = (vp->note - ap->root) * 4096 / 12;
- DEBUG(4,printk("AWE32: p-> ofs=%d\n", offset));
- }
- offset = (offset * ap->scaleTuning) / 100;
- DEBUG(4,printk("AWE32: p-> scale* ofs=%d\n", offset));
- offset += ap->tune * 4096 / 1200;
- DEBUG(4,printk("AWE32: p-> tune+ ofs=%d\n", offset));
- if (cp->bender != 0) {
- DEBUG(3,printk("AWE32: p-> bend(%d) %d\n", voice, cp->bender));
- /* (819200: 1 semitone) ==> (4096: 12 semitones) */
- offset += cp->bender * cp->bender_range / 2400;
- }
-
- /* add initial pitch correction */
- if (FX_ON(&cp->fx_layer[vp->layer], AWE_FX_INIT_PITCH))
- offset += cp->fx_layer[vp->layer].val[AWE_FX_INIT_PITCH];
- else if (FX_ON(&cp->fx, AWE_FX_INIT_PITCH))
- offset += cp->fx.val[AWE_FX_INIT_PITCH];
-
- /* 0xe000: root pitch */
- vp->apitch = 0xe000 + ap->rate_offset + offset;
- DEBUG(4,printk("AWE32: p-> sum aofs=%x, rate_ofs=%d\n", vp->apitch, ap->rate_offset));
- if (vp->apitch > 0xffff)
- vp->apitch = 0xffff;
- if (vp->apitch < 0)
- vp->apitch = 0;
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-/* calculate MIDI key and semitone from the specified frequency */
-static void
-awe_calc_pitch_from_freq(int voice, int freq)
-{
- voice_info *vp = &voices[voice];
- awe_voice_info *ap;
- FX_Rec *fx = &voices[voice].cinfo->fx;
- FX_Rec *fx_lay = NULL;
- int offset;
- int note;
-
- if (voices[voice].layer < MAX_LAYERS)
- fx_lay = &voices[voice].cinfo->fx_layer[voices[voice].layer];
-
- /* search voice information */
- if ((ap = vp->sample) == NULL)
- return;
- if (ap->index == 0) {
- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample((awe_voice_list*)ap) == 0)
- return;
- }
- note = freq_to_note(freq);
- offset = (note - ap->root * 100 + ap->tune) * 4096 / 1200;
- offset = (offset * ap->scaleTuning) / 100;
- if (fx_lay && FX_ON(fx_lay, AWE_FX_INIT_PITCH))
- offset += fx_lay->val[AWE_FX_INIT_PITCH];
- else if (FX_ON(fx, AWE_FX_INIT_PITCH))
- offset += fx->val[AWE_FX_INIT_PITCH];
- vp->apitch = 0xe000 + ap->rate_offset + offset;
- if (vp->apitch > 0xffff)
- vp->apitch = 0xffff;
- if (vp->apitch < 0)
- vp->apitch = 0;
-}
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-
-/*
- * calculate volume attenuation
- *
- * Voice volume is controlled by volume attenuation parameter.
- * So volume becomes maximum when avol is 0 (no attenuation), and
- * minimum when 255 (-96dB or silence).
- */
-
-static int vol_table[128] = {
- 255,111,95,86,79,74,70,66,63,61,58,56,54,52,50,49,
- 47,46,45,43,42,41,40,39,38,37,36,35,34,34,33,32,
- 31,31,30,29,29,28,27,27,26,26,25,24,24,23,23,22,
- 22,21,21,21,20,20,19,19,18,18,18,17,17,16,16,16,
- 15,15,15,14,14,14,13,13,13,12,12,12,11,11,11,10,
- 10,10,10,9,9,9,8,8,8,8,7,7,7,7,6,6,
- 6,6,5,5,5,5,5,4,4,4,4,3,3,3,3,3,
- 2,2,2,2,2,1,1,1,1,1,0,0,0,0,0,0,
-};
-
-/* tables for volume->attenuation calculation */
-static unsigned char voltab1[128] = {
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x2b, 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22,
- 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a,
- 0x19, 0x19, 0x18, 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x14,
- 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10,
- 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0e, 0x0d,
- 0x0d, 0x0d, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09,
- 0x08, 0x08, 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06,
- 0x06, 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x04,
- 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03, 0x03, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char voltab2[128] = {
- 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x2a,
- 0x29, 0x28, 0x27, 0x26, 0x25, 0x24, 0x24, 0x23, 0x22, 0x21,
- 0x21, 0x20, 0x1f, 0x1e, 0x1e, 0x1d, 0x1c, 0x1c, 0x1b, 0x1a,
- 0x1a, 0x19, 0x19, 0x18, 0x18, 0x17, 0x16, 0x16, 0x15, 0x15,
- 0x14, 0x14, 0x13, 0x13, 0x13, 0x12, 0x12, 0x11, 0x11, 0x10,
- 0x10, 0x10, 0x0f, 0x0f, 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d,
- 0x0d, 0x0c, 0x0c, 0x0c, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0a,
- 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09, 0x09, 0x08, 0x08, 0x08,
- 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
- 0x06, 0x06, 0x06, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
- 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03, 0x03, 0x03, 0x03,
- 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static unsigned char expressiontab[128] = {
- 0x7f, 0x6c, 0x62, 0x5a, 0x54, 0x50, 0x4b, 0x48, 0x45, 0x42,
- 0x40, 0x3d, 0x3b, 0x39, 0x38, 0x36, 0x34, 0x33, 0x31, 0x30,
- 0x2f, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28, 0x27, 0x26, 0x25,
- 0x24, 0x24, 0x23, 0x22, 0x21, 0x21, 0x20, 0x1f, 0x1e, 0x1e,
- 0x1d, 0x1d, 0x1c, 0x1b, 0x1b, 0x1a, 0x1a, 0x19, 0x18, 0x18,
- 0x17, 0x17, 0x16, 0x16, 0x15, 0x15, 0x15, 0x14, 0x14, 0x13,
- 0x13, 0x12, 0x12, 0x11, 0x11, 0x11, 0x10, 0x10, 0x0f, 0x0f,
- 0x0f, 0x0e, 0x0e, 0x0e, 0x0d, 0x0d, 0x0d, 0x0c, 0x0c, 0x0c,
- 0x0b, 0x0b, 0x0b, 0x0a, 0x0a, 0x0a, 0x09, 0x09, 0x09, 0x09,
- 0x08, 0x08, 0x08, 0x07, 0x07, 0x07, 0x07, 0x06, 0x06, 0x06,
- 0x06, 0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x04, 0x03,
- 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static void
-awe_calc_volume(int voice)
-{
- voice_info *vp = &voices[voice];
- awe_voice_info *ap;
- awe_chan_info *cp = voices[voice].cinfo;
- int vol;
-
- /* search voice information */
- if ((ap = vp->sample) == NULL)
- return;
-
- ap = vp->sample;
- if (ap->index == 0) {
- DEBUG(3,printk("AWE32: set sample (%d)\n", ap->sample));
- if (awe_set_sample((awe_voice_list*)ap) == 0)
- return;
- }
-
- if (ctrls[AWE_MD_NEW_VOLUME_CALC]) {
- int main_vol = cp->main_vol * ap->amplitude / 127;
- limitvalue(vp->velocity, 0, 127);
- limitvalue(main_vol, 0, 127);
- limitvalue(cp->expression_vol, 0, 127);
-
- vol = voltab1[main_vol] + voltab2[vp->velocity];
- vol = (vol * 8) / 3;
- vol += ap->attenuation;
- if (cp->expression_vol < 127)
- vol += ((0x100 - vol) * expressiontab[cp->expression_vol])/128;
- vol += atten_offset;
- if (atten_relative)
- vol += ctrls[AWE_MD_ZERO_ATTEN];
- limitvalue(vol, 0, 255);
- vp->avol = vol;
-
- } else {
- /* 0 - 127 */
- vol = (vp->velocity * cp->main_vol * cp->expression_vol) / (127*127);
- vol = vol * ap->amplitude / 127;
-
- if (vol < 0) vol = 0;
- if (vol > 127) vol = 127;
-
- /* calc to attenuation */
- vol = vol_table[vol];
- vol += (int)ap->attenuation;
- vol += atten_offset;
- if (atten_relative)
- vol += ctrls[AWE_MD_ZERO_ATTEN];
- if (vol > 255) vol = 255;
-
- vp->avol = vol;
- }
- if (cp->bank != AWE_DRUM_BANK && ((awe_voice_parm_block*)(&ap->parm))->volatk < 0x7d) {
- int atten;
- if (vp->velocity < 70) atten = 70;
- else atten = vp->velocity;
- vp->acutoff = (atten * ap->parm.cutoff + 0xa0) >> 7;
- } else {
- vp->acutoff = ap->parm.cutoff;
- }
- DEBUG(3,printk("AWE32: [-- voice(%d) vol=%x]\n", voice, vol));
-}
-
-/* change master volume */
-static void
-awe_change_master_volume(short val)
-{
- limitvalue(val, 0, 127);
- atten_offset = vol_table[val];
- atten_relative = TRUE;
- awe_update_volume();
-}
-
-/* update volumes of all available channels */
-static void awe_update_volume(void)
-{
- int i;
- for (i = 0; i < awe_max_voices; i++)
- awe_set_voice_vol(i, TRUE);
-}
-
-/* set sostenuto on */
-static void awe_sostenuto_on(int voice, int forced)
-{
- if (IS_NO_EFFECT(voice) && !forced) return;
- voices[voice].sostenuto = 127;
-}
-
-
-/* drop sustain */
-static void awe_sustain_off(int voice, int forced)
-{
- if (voices[voice].state == AWE_ST_SUSTAINED) {
- awe_note_off(voice);
- awe_fx_init(voices[voice].ch);
- awe_voice_init(voice, FALSE);
- }
-}
-
-
-/* terminate and initialize voice */
-static void awe_terminate_and_init(int voice, int forced)
-{
- awe_terminate(voice);
- awe_fx_init(voices[voice].ch);
- awe_voice_init(voice, TRUE);
-}
-
-
-/*
- * synth operation routines
- */
-
-#define AWE_VOICE_KEY(v) (0x8000 | (v))
-#define AWE_CHAN_KEY(c,n) (((c) << 8) | ((n) + 1))
-#define KEY_CHAN_MATCH(key,c) (((key) >> 8) == (c))
-
-/* initialize the voice */
-static void
-awe_voice_init(int voice, int init_all)
-{
- voice_info *vp = &voices[voice];
-
- /* reset voice search key */
- if (playing_mode == AWE_PLAY_DIRECT)
- vp->key = AWE_VOICE_KEY(voice);
- else
- vp->key = 0;
-
- /* clear voice mapping */
- voice_alloc->map[voice] = 0;
-
- /* touch the timing flag */
- vp->time = current_alloc_time;
-
- /* initialize other parameters if necessary */
- if (init_all) {
- vp->note = -1;
- vp->velocity = 0;
- vp->sostenuto = 0;
-
- vp->sample = NULL;
- vp->cinfo = &channels[voice];
- vp->ch = voice;
- vp->state = AWE_ST_OFF;
-
- /* emu8000 parameters */
- vp->apitch = 0;
- vp->avol = 255;
- vp->apan = -1;
- }
-}
-
-/* clear effects */
-static void awe_fx_init(int ch)
-{
- if (SINGLE_LAYER_MODE() && !ctrls[AWE_MD_KEEP_EFFECT]) {
- memset(&channels[ch].fx, 0, sizeof(channels[ch].fx));
- memset(&channels[ch].fx_layer, 0, sizeof(&channels[ch].fx_layer));
- }
-}
-
-/* initialize channel info */
-static void awe_channel_init(int ch, int init_all)
-{
- awe_chan_info *cp = &channels[ch];
- cp->channel = ch;
- if (init_all) {
- cp->panning = 0; /* zero center */
- cp->bender_range = 200; /* sense * 100 */
- cp->main_vol = 127;
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch)) {
- cp->instr = ctrls[AWE_MD_DEF_DRUM];
- cp->bank = AWE_DRUM_BANK;
- } else {
- cp->instr = ctrls[AWE_MD_DEF_PRESET];
- cp->bank = ctrls[AWE_MD_DEF_BANK];
- }
- }
-
- cp->bender = 0; /* zero tune skew */
- cp->expression_vol = 127;
- cp->chan_press = 0;
- cp->sustained = 0;
-
- if (! ctrls[AWE_MD_KEEP_EFFECT]) {
- memset(&cp->fx, 0, sizeof(cp->fx));
- memset(&cp->fx_layer, 0, sizeof(cp->fx_layer));
- }
-}
-
-
-/* change the voice parameters; voice = channel */
-static void awe_voice_change(int voice, fx_affect_func func)
-{
- int i;
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- func(voice, FALSE);
- break;
- case AWE_PLAY_INDIRECT:
- for (i = 0; i < awe_max_voices; i++)
- if (voices[i].key == AWE_VOICE_KEY(voice))
- func(i, FALSE);
- break;
- default:
- for (i = 0; i < awe_max_voices; i++)
- if (KEY_CHAN_MATCH(voices[i].key, voice))
- func(i, FALSE);
- break;
- }
-}
-
-
-/*
- * device open / close
- */
-
-/* open device:
- * reset status of all voices, and clear sample position flag
- */
-static int
-awe_open(int dev, int mode)
-{
- if (awe_busy)
- return -EBUSY;
-
- awe_busy = TRUE;
-
- /* set default mode */
- awe_init_ctrl_parms(FALSE);
- atten_relative = TRUE;
- atten_offset = 0;
- drum_flags = DEFAULT_DRUM_FLAGS;
- playing_mode = AWE_PLAY_INDIRECT;
-
- /* reset voices & channels */
- awe_reset(dev);
-
- patch_opened = 0;
-
- return 0;
-}
-
-
-/* close device:
- * reset all voices again (terminate sounds)
- */
-static void
-awe_close(int dev)
-{
- awe_reset(dev);
- awe_busy = FALSE;
-}
-
-
-/* set miscellaneous mode parameters
- */
-static void
-awe_init_ctrl_parms(int init_all)
-{
- int i;
- for (i = 0; i < AWE_MD_END; i++) {
- if (init_all || ctrl_parms[i].init_each_time)
- ctrls[i] = ctrl_parms[i].value;
- }
-}
-
-
-/* sequencer I/O control:
- */
-static int
-awe_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- switch (cmd) {
- case SNDCTL_SYNTH_INFO:
- if (playing_mode == AWE_PLAY_DIRECT)
- awe_info.nr_voices = awe_max_voices;
- else
- awe_info.nr_voices = AWE_MAX_CHANNELS;
- if (copy_to_user(arg, &awe_info, sizeof(awe_info)))
- return -EFAULT;
- return 0;
- break;
-
- case SNDCTL_SEQ_RESETSAMPLES:
- awe_reset(dev);
- awe_reset_samples();
- return 0;
- break;
-
- case SNDCTL_SEQ_PERCMODE:
- /* what's this? */
- return 0;
- break;
-
- case SNDCTL_SYNTH_MEMAVL:
- return memsize - awe_free_mem_ptr() * 2;
- break;
-
- default:
- printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd);
- return -EINVAL;
- break;
- }
-}
-
-
-static int voice_in_range(int voice)
-{
- if (playing_mode == AWE_PLAY_DIRECT) {
- if (voice < 0 || voice >= awe_max_voices)
- return FALSE;
- } else {
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return FALSE;
- }
- return TRUE;
-}
-
-static void release_voice(int voice, int do_sustain)
-{
- if (IS_NO_SOUND(voice))
- return;
- if (do_sustain && (voices[voice].cinfo->sustained == 127 ||
- voices[voice].sostenuto == 127))
- voices[voice].state = AWE_ST_SUSTAINED;
- else {
- awe_note_off(voice);
- awe_fx_init(voices[voice].ch);
- awe_voice_init(voice, FALSE);
- }
-}
-
-/* release all notes */
-static void awe_note_off_all(int do_sustain)
-{
- int i;
- for (i = 0; i < awe_max_voices; i++)
- release_voice(i, do_sustain);
-}
-
-/* kill a voice:
- * not terminate, just release the voice.
- */
-static int
-awe_kill_note(int dev, int voice, int note, int velocity)
-{
- int i, v2, key;
-
- DEBUG(2,printk("AWE32: [off(%d) nt=%d vl=%d]\n", voice, note, velocity));
- if (! voice_in_range(voice))
- return -EINVAL;
-
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- case AWE_PLAY_INDIRECT:
- key = AWE_VOICE_KEY(voice);
- break;
-
- case AWE_PLAY_MULTI2:
- v2 = voice_alloc->map[voice] >> 8;
- voice_alloc->map[voice] = 0;
- voice = v2;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return -EINVAL;
- /* continue to below */
- default:
- key = AWE_CHAN_KEY(voice, note);
- break;
- }
-
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key)
- release_voice(i, TRUE);
- }
- return 0;
-}
-
-
-static void start_or_volume_change(int voice, int velocity)
-{
- voices[voice].velocity = velocity;
- awe_calc_volume(voice);
- if (voices[voice].state == AWE_ST_STANDBY)
- awe_note_on(voice);
- else if (voices[voice].state == AWE_ST_ON)
- awe_set_volume(voice, FALSE);
-}
-
-static void set_and_start_voice(int voice, int state)
-{
- /* calculate pitch & volume parameters */
- voices[voice].state = state;
- awe_calc_pitch(voice);
- awe_calc_volume(voice);
- if (state == AWE_ST_ON)
- awe_note_on(voice);
-}
-
-/* start a voice:
- * if note is 255, identical with aftertouch function.
- * Otherwise, start a voice with specified not and volume.
- */
-static int
-awe_start_note(int dev, int voice, int note, int velocity)
-{
- int i, key, state, volonly;
-
- DEBUG(2,printk("AWE32: [on(%d) nt=%d vl=%d]\n", voice, note, velocity));
- if (! voice_in_range(voice))
- return -EINVAL;
-
- if (velocity == 0)
- state = AWE_ST_STANDBY; /* stand by for playing */
- else
- state = AWE_ST_ON; /* really play */
- volonly = FALSE;
-
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- case AWE_PLAY_INDIRECT:
- key = AWE_VOICE_KEY(voice);
- if (note == 255)
- volonly = TRUE;
- break;
-
- case AWE_PLAY_MULTI2:
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return -EINVAL;
- /* continue to below */
- default:
- if (note >= 128) { /* key volume mode */
- note -= 128;
- volonly = TRUE;
- }
- key = AWE_CHAN_KEY(voice, note);
- break;
- }
-
- /* dynamic volume change */
- if (volonly) {
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key)
- start_or_volume_change(i, velocity);
- }
- return 0;
- }
-
- /* if the same note still playing, stop it */
- if (playing_mode != AWE_PLAY_DIRECT || ctrls[AWE_MD_EXCLUSIVE_SOUND]) {
- for (i = 0; i < awe_max_voices; i++)
- if (voices[i].key == key) {
- if (voices[i].state == AWE_ST_ON) {
- awe_note_off(i);
- awe_voice_init(i, FALSE);
- } else if (voices[i].state == AWE_ST_STANDBY)
- awe_voice_init(i, TRUE);
- }
- }
-
- /* allocate voices */
- if (playing_mode == AWE_PLAY_DIRECT)
- awe_alloc_one_voice(voice, note, velocity);
- else
- awe_alloc_multi_voices(voice, note, velocity, key);
-
- /* turn off other voices exlusively (for drums) */
- for (i = 0; i < awe_max_voices; i++)
- if (voices[i].key == key)
- awe_exclusive_off(i);
-
- /* set up pitch and volume parameters */
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key && voices[i].state == AWE_ST_OFF)
- set_and_start_voice(i, state);
- }
-
- return 0;
-}
-
-
-/* calculate hash key */
-static int
-awe_search_key(int bank, int preset, int note)
-{
- unsigned int key;
-
-#if 1 /* new hash table */
- if (bank == AWE_DRUM_BANK)
- key = preset + note + 128;
- else
- key = bank + preset;
-#else
- key = preset;
-#endif
- key %= AWE_MAX_PRESETS;
-
- return (int)key;
-}
-
-
-/* search instrument from hash table */
-static awe_voice_list *
-awe_search_instr(int bank, int preset, int note)
-{
- awe_voice_list *p;
- int key, key2;
-
- key = awe_search_key(bank, preset, note);
- for (p = preset_table[key]; p; p = p->next_bank) {
- if (p->instr == preset && p->bank == bank)
- return p;
- }
- key2 = awe_search_key(bank, preset, 0); /* search default */
- if (key == key2)
- return NULL;
- for (p = preset_table[key2]; p; p = p->next_bank) {
- if (p->instr == preset && p->bank == bank)
- return p;
- }
- return NULL;
-}
-
-
-/* assign the instrument to a voice */
-static int
-awe_set_instr_2(int dev, int voice, int instr_no)
-{
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return -EINVAL;
- }
- return awe_set_instr(dev, voice, instr_no);
-}
-
-/* assign the instrument to a channel; voice is the channel number */
-static int
-awe_set_instr(int dev, int voice, int instr_no)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return -EINVAL;
-
- if (instr_no < 0 || instr_no >= AWE_MAX_PRESETS)
- return -EINVAL;
-
- cinfo = &channels[voice];
- cinfo->instr = instr_no;
- DEBUG(2,printk("AWE32: [program(%d) %d]\n", voice, instr_no));
-
- return 0;
-}
-
-
-/* reset all voices; terminate sounds and initialize parameters */
-static void
-awe_reset(int dev)
-{
- int i;
- current_alloc_time = 0;
- /* don't turn off voice 31 and 32. they are used also for FM voices */
- for (i = 0; i < awe_max_voices; i++) {
- awe_terminate(i);
- awe_voice_init(i, TRUE);
- }
- for (i = 0; i < AWE_MAX_CHANNELS; i++)
- awe_channel_init(i, TRUE);
- for (i = 0; i < 16; i++) {
- awe_operations.chn_info[i].controllers[CTL_MAIN_VOLUME] = 127;
- awe_operations.chn_info[i].controllers[CTL_EXPRESSION] = 127;
- }
- awe_init_fm();
- awe_tweak();
-}
-
-
-/* hardware specific control:
- * GUS specific and AWE32 specific controls are available.
- */
-static void
-awe_hw_control(int dev, unsigned char *event)
-{
- int cmd = event[2];
- if (cmd & _AWE_MODE_FLAG)
- awe_hw_awe_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#ifdef AWE_HAS_GUS_COMPATIBILITY
- else
- awe_hw_gus_control(dev, cmd & _AWE_MODE_VALUE_MASK, event);
-#endif
-}
-
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* GUS compatible controls */
-static void
-awe_hw_gus_control(int dev, int cmd, unsigned char *event)
-{
- int voice, i, key;
- unsigned short p1;
- short p2;
- int plong;
-
- if (MULTI_LAYER_MODE())
- return;
- if (cmd == _GUS_NUMVOICES)
- return;
-
- voice = event[3];
- if (! voice_in_range(voice))
- return;
-
- p1 = *(unsigned short *) &event[4];
- p2 = *(short *) &event[6];
- plong = *(int*) &event[4];
-
- switch (cmd) {
- case _GUS_VOICESAMPLE:
- awe_set_instr(dev, voice, p1);
- return;
-
- case _GUS_VOICEBALA:
- /* 0 to 15 --> -128 to 127 */
- awe_panning(dev, voice, ((int)p1 << 4) - 128);
- return;
-
- case _GUS_VOICEVOL:
- case _GUS_VOICEVOL2:
- /* not supported yet */
- return;
-
- case _GUS_RAMPRANGE:
- case _GUS_RAMPRATE:
- case _GUS_RAMPMODE:
- case _GUS_RAMPON:
- case _GUS_RAMPOFF:
- /* volume ramping not supported */
- return;
-
- case _GUS_VOLUME_SCALE:
- return;
-
- case _GUS_VOICE_POS:
- FX_SET(&channels[voice].fx, AWE_FX_SAMPLE_START,
- (short)(plong & 0x7fff));
- FX_SET(&channels[voice].fx, AWE_FX_COARSE_SAMPLE_START,
- (plong >> 15) & 0xffff);
- return;
- }
-
- key = AWE_VOICE_KEY(voice);
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].key == key) {
- switch (cmd) {
- case _GUS_VOICEON:
- awe_note_on(i);
- break;
-
- case _GUS_VOICEOFF:
- awe_terminate(i);
- awe_fx_init(voices[i].ch);
- awe_voice_init(i, TRUE);
- break;
-
- case _GUS_VOICEFADE:
- awe_note_off(i);
- awe_fx_init(voices[i].ch);
- awe_voice_init(i, FALSE);
- break;
-
- case _GUS_VOICEFREQ:
- awe_calc_pitch_from_freq(i, plong);
- break;
- }
- }
- }
-}
-
-#endif /* gus_compat */
-
-
-/* AWE32 specific controls */
-static void
-awe_hw_awe_control(int dev, int cmd, unsigned char *event)
-{
- int voice;
- unsigned short p1;
- short p2;
- int i;
-
- voice = event[3];
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- p1 = *(unsigned short *) &event[4];
- p2 = *(short *) &event[6];
-
- switch (cmd) {
- case _AWE_DEBUG_MODE:
- ctrls[AWE_MD_DEBUG_MODE] = p1;
- printk(KERN_DEBUG "AWE32: debug mode = %d\n", ctrls[AWE_MD_DEBUG_MODE]);
- break;
- case _AWE_REVERB_MODE:
- ctrls[AWE_MD_REVERB_MODE] = p1;
- awe_update_reverb_mode();
- break;
-
- case _AWE_CHORUS_MODE:
- ctrls[AWE_MD_CHORUS_MODE] = p1;
- awe_update_chorus_mode();
- break;
-
- case _AWE_REMOVE_LAST_SAMPLES:
- DEBUG(0,printk("AWE32: remove last samples\n"));
- awe_reset(0);
- if (locked_sf_id > 0)
- awe_remove_samples(locked_sf_id);
- break;
-
- case _AWE_INITIALIZE_CHIP:
- awe_initialize();
- break;
-
- case _AWE_SEND_EFFECT:
- i = -1;
- if (p1 >= 0x100) {
- i = (p1 >> 8);
- if (i < 0 || i >= MAX_LAYERS)
- break;
- }
- awe_send_effect(voice, i, p1, p2);
- break;
-
- case _AWE_RESET_CHANNEL:
- awe_channel_init(voice, !p1);
- break;
-
- case _AWE_TERMINATE_ALL:
- awe_reset(0);
- break;
-
- case _AWE_TERMINATE_CHANNEL:
- awe_voice_change(voice, awe_terminate_and_init);
- break;
-
- case _AWE_RELEASE_ALL:
- awe_note_off_all(FALSE);
- break;
- case _AWE_NOTEOFF_ALL:
- awe_note_off_all(TRUE);
- break;
-
- case _AWE_INITIAL_VOLUME:
- DEBUG(0,printk("AWE32: init attenuation %d\n", p1));
- atten_relative = (char)p2;
- atten_offset = (short)p1;
- awe_update_volume();
- break;
-
- case _AWE_CHN_PRESSURE:
- channels[voice].chan_press = p1;
- awe_modwheel_change(voice, p1);
- break;
-
- case _AWE_CHANNEL_MODE:
- DEBUG(0,printk("AWE32: channel mode = %d\n", p1));
- playing_mode = p1;
- awe_reset(0);
- break;
-
- case _AWE_DRUM_CHANNELS:
- DEBUG(0,printk("AWE32: drum flags = %x\n", p1));
- drum_flags = *(unsigned int*)&event[4];
- break;
-
- case _AWE_MISC_MODE:
- DEBUG(0,printk("AWE32: ctrl parms = %d %d\n", p1, p2));
- if (p1 > AWE_MD_VERSION && p1 < AWE_MD_END) {
- ctrls[p1] = p2;
- if (ctrl_parms[p1].update)
- ctrl_parms[p1].update();
- }
- break;
-
- case _AWE_EQUALIZER:
- ctrls[AWE_MD_BASS_LEVEL] = p1;
- ctrls[AWE_MD_TREBLE_LEVEL] = p2;
- awe_update_equalizer();
- break;
-
- default:
- DEBUG(0,printk("AWE32: hw control cmd=%d voice=%d\n", cmd, voice));
- break;
- }
-}
-
-
-/* change effects */
-static void
-awe_send_effect(int voice, int layer, int type, int val)
-{
- awe_chan_info *cinfo;
- FX_Rec *fx;
- int mode;
-
- cinfo = &channels[voice];
- if (layer >= 0 && layer < MAX_LAYERS)
- fx = &cinfo->fx_layer[layer];
- else
- fx = &cinfo->fx;
-
- if (type & 0x40)
- mode = FX_FLAG_OFF;
- else if (type & 0x80)
- mode = FX_FLAG_ADD;
- else
- mode = FX_FLAG_SET;
- type &= 0x3f;
-
- if (type >= 0 && type < AWE_FX_END) {
- DEBUG(2,printk("AWE32: effects (%d) %d %d\n", voice, type, val));
- if (mode == FX_FLAG_SET)
- FX_SET(fx, type, val);
- else if (mode == FX_FLAG_ADD)
- FX_ADD(fx, type, val);
- else
- FX_UNSET(fx, type);
- if (mode != FX_FLAG_OFF && parm_defs[type].realtime) {
- DEBUG(2,printk("AWE32: fx_realtime (%d)\n", voice));
- awe_voice_change(voice, parm_defs[type].realtime);
- }
- }
-}
-
-
-/* change modulation wheel; voice is already mapped on multi2 mode */
-static void
-awe_modwheel_change(int voice, int value)
-{
- int i;
- awe_chan_info *cinfo;
-
- cinfo = &channels[voice];
- i = value * ctrls[AWE_MD_MOD_SENSE] / 1200;
- FX_ADD(&cinfo->fx, AWE_FX_LFO1_PITCH, i);
- awe_voice_change(voice, awe_fx_fmmod);
- FX_ADD(&cinfo->fx, AWE_FX_LFO2_PITCH, i);
- awe_voice_change(voice, awe_fx_fm2frq2);
-}
-
-
-/* voice pressure change */
-static void
-awe_aftertouch(int dev, int voice, int pressure)
-{
- int note;
-
- DEBUG(2,printk("AWE32: [after(%d) %d]\n", voice, pressure));
- if (! voice_in_range(voice))
- return;
-
- switch (playing_mode) {
- case AWE_PLAY_DIRECT:
- case AWE_PLAY_INDIRECT:
- awe_start_note(dev, voice, 255, pressure);
- break;
- case AWE_PLAY_MULTI2:
- note = (voice_alloc->map[voice] & 0xff) - 1;
- awe_key_pressure(dev, voice, note + 0x80, pressure);
- break;
- }
-}
-
-
-/* voice control change */
-static void
-awe_controller(int dev, int voice, int ctrl_num, int value)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- cinfo = &channels[voice];
-
- switch (ctrl_num) {
- case CTL_BANK_SELECT: /* MIDI control #0 */
- DEBUG(2,printk("AWE32: [bank(%d) %d]\n", voice, value));
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice) &&
- !ctrls[AWE_MD_TOGGLE_DRUM_BANK])
- break;
- if (value < 0 || value > 255)
- break;
- cinfo->bank = value;
- if (cinfo->bank == AWE_DRUM_BANK)
- DRUM_CHANNEL_ON(cinfo->channel);
- else
- DRUM_CHANNEL_OFF(cinfo->channel);
- awe_set_instr(dev, voice, cinfo->instr);
- break;
-
- case CTL_MODWHEEL: /* MIDI control #1 */
- DEBUG(2,printk("AWE32: [modwheel(%d) %d]\n", voice, value));
- awe_modwheel_change(voice, value);
- break;
-
- case CTRL_PITCH_BENDER: /* SEQ1 V2 contorl */
- DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, value));
- /* zero centered */
- cinfo->bender = value;
- awe_voice_change(voice, awe_set_voice_pitch);
- break;
-
- case CTRL_PITCH_BENDER_RANGE: /* SEQ1 V2 control */
- DEBUG(2,printk("AWE32: [range(%d) %d]\n", voice, value));
- /* value = sense x 100 */
- cinfo->bender_range = value;
- /* no audible pitch change yet.. */
- break;
-
- case CTL_EXPRESSION: /* MIDI control #11 */
- if (SINGLE_LAYER_MODE())
- value /= 128;
- case CTRL_EXPRESSION: /* SEQ1 V2 control */
- DEBUG(2,printk("AWE32: [expr(%d) %d]\n", voice, value));
- /* 0 - 127 */
- cinfo->expression_vol = value;
- awe_voice_change(voice, awe_set_voice_vol);
- break;
-
- case CTL_PAN: /* MIDI control #10 */
- DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, value));
- /* (0-127) -> signed 8bit */
- cinfo->panning = value * 2 - 128;
- if (ctrls[AWE_MD_REALTIME_PAN])
- awe_voice_change(voice, awe_set_pan);
- break;
-
- case CTL_MAIN_VOLUME: /* MIDI control #7 */
- if (SINGLE_LAYER_MODE())
- value = (value * 100) / 16383;
- case CTRL_MAIN_VOLUME: /* SEQ1 V2 control */
- DEBUG(2,printk("AWE32: [mainvol(%d) %d]\n", voice, value));
- /* 0 - 127 */
- cinfo->main_vol = value;
- awe_voice_change(voice, awe_set_voice_vol);
- break;
-
- case CTL_EXT_EFF_DEPTH: /* reverb effects: 0-127 */
- DEBUG(2,printk("AWE32: [reverb(%d) %d]\n", voice, value));
- FX_SET(&cinfo->fx, AWE_FX_REVERB, value * 2);
- break;
-
- case CTL_CHORUS_DEPTH: /* chorus effects: 0-127 */
- DEBUG(2,printk("AWE32: [chorus(%d) %d]\n", voice, value));
- FX_SET(&cinfo->fx, AWE_FX_CHORUS, value * 2);
- break;
-
- case 120: /* all sounds off */
- awe_note_off_all(FALSE);
- break;
- case 123: /* all notes off */
- awe_note_off_all(TRUE);
- break;
-
- case CTL_SUSTAIN: /* MIDI control #64 */
- cinfo->sustained = value;
- if (value != 127)
- awe_voice_change(voice, awe_sustain_off);
- break;
-
- case CTL_SOSTENUTO: /* MIDI control #66 */
- if (value == 127)
- awe_voice_change(voice, awe_sostenuto_on);
- else
- awe_voice_change(voice, awe_sustain_off);
- break;
-
- default:
- DEBUG(0,printk("AWE32: [control(%d) ctrl=%d val=%d]\n",
- voice, ctrl_num, value));
- break;
- }
-}
-
-
-/* voice pan change (value = -128 - 127) */
-static void
-awe_panning(int dev, int voice, int value)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- cinfo = &channels[voice];
- cinfo->panning = value;
- DEBUG(2,printk("AWE32: [pan(%d) %d]\n", voice, cinfo->panning));
- if (ctrls[AWE_MD_REALTIME_PAN])
- awe_voice_change(voice, awe_set_pan);
-}
-
-
-/* volume mode change */
-static void
-awe_volume_method(int dev, int mode)
-{
- /* not impremented */
- DEBUG(0,printk("AWE32: [volmethod mode=%d]\n", mode));
-}
-
-
-/* pitch wheel change: 0-16384 */
-static void
-awe_bender(int dev, int voice, int value)
-{
- awe_chan_info *cinfo;
-
- if (! voice_in_range(voice))
- return;
-
- if (playing_mode == AWE_PLAY_MULTI2) {
- voice = voice_alloc->map[voice] >> 8;
- if (voice < 0 || voice >= AWE_MAX_CHANNELS)
- return;
- }
-
- /* convert to zero centered value */
- cinfo = &channels[voice];
- cinfo->bender = value - 8192;
- DEBUG(2,printk("AWE32: [bend(%d) %d]\n", voice, cinfo->bender));
- awe_voice_change(voice, awe_set_voice_pitch);
-}
-
-
-/*
- * load a sound patch:
- * three types of patches are accepted: AWE, GUS, and SYSEX.
- */
-
-static int
-awe_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
- awe_patch_info patch;
- int rc = 0;
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
- if (format == GUS_PATCH) {
- return awe_load_guspatch(addr, offs, count, pmgr_flag);
- } else
-#endif
- if (format == SYSEX_PATCH) {
- /* no system exclusive message supported yet */
- return 0;
- } else if (format != AWE_PATCH) {
- printk(KERN_WARNING "AWE32 Error: Invalid patch format (key) 0x%x\n", format);
- return -EINVAL;
- }
-
- if (count < AWE_PATCH_INFO_SIZE) {
- printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
- return -EINVAL;
- }
- if (copy_from_user(((char*)&patch) + offs, addr + offs,
- AWE_PATCH_INFO_SIZE - offs))
- return -EFAULT;
-
- count -= AWE_PATCH_INFO_SIZE;
- if (count < patch.len) {
- printk(KERN_WARNING "AWE32: sample: Patch record too short (%d<%d)\n",
- count, patch.len);
- return -EINVAL;
- }
-
- switch (patch.type) {
- case AWE_LOAD_INFO:
- rc = awe_load_info(&patch, addr, count);
- break;
- case AWE_LOAD_DATA:
- rc = awe_load_data(&patch, addr, count);
- break;
- case AWE_OPEN_PATCH:
- rc = awe_open_patch(&patch, addr, count);
- break;
- case AWE_CLOSE_PATCH:
- rc = awe_close_patch(&patch, addr, count);
- break;
- case AWE_UNLOAD_PATCH:
- rc = awe_unload_patch(&patch, addr, count);
- break;
- case AWE_REPLACE_DATA:
- rc = awe_replace_data(&patch, addr, count);
- break;
- case AWE_MAP_PRESET:
- rc = awe_load_map(&patch, addr, count);
- break;
- /* case AWE_PROBE_INFO:
- rc = awe_probe_info(&patch, addr, count);
- break;*/
- case AWE_PROBE_DATA:
- rc = awe_probe_data(&patch, addr, count);
- break;
- case AWE_REMOVE_INFO:
- rc = awe_remove_info(&patch, addr, count);
- break;
- case AWE_LOAD_CHORUS_FX:
- rc = awe_load_chorus_fx(&patch, addr, count);
- break;
- case AWE_LOAD_REVERB_FX:
- rc = awe_load_reverb_fx(&patch, addr, count);
- break;
-
- default:
- printk(KERN_WARNING "AWE32 Error: unknown patch format type %d\n",
- patch.type);
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-
-/* create an sf list record */
-static int
-awe_create_sf(int type, char *name)
-{
- sf_list *rec;
-
- /* terminate sounds */
- awe_reset(0);
- rec = (sf_list *)kmalloc(sizeof(*rec), GFP_KERNEL);
- if (rec == NULL)
- return 1; /* no memory */
- rec->sf_id = current_sf_id + 1;
- rec->type = type;
- if (/*current_sf_id == 0 ||*/ (type & AWE_PAT_LOCKED) != 0)
- locked_sf_id = current_sf_id + 1;
- rec->num_info = awe_free_info();
- rec->num_sample = awe_free_sample();
- rec->mem_ptr = awe_free_mem_ptr();
- rec->infos = rec->last_infos = NULL;
- rec->samples = rec->last_samples = NULL;
-
- /* add to linked-list */
- rec->next = NULL;
- rec->prev = sftail;
- if (sftail)
- sftail->next = rec;
- else
- sfhead = rec;
- sftail = rec;
- current_sf_id++;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- rec->shared = NULL;
- if (name)
- memcpy(rec->name, name, AWE_PATCH_NAME_LEN);
- else
- strcpy(rec->name, "*TEMPORARY*");
- if (current_sf_id > 1 && name && (type & AWE_PAT_SHARED) != 0) {
- /* is the current font really a shared font? */
- if (is_shared_sf(rec->name)) {
- /* check if the shared font is already installed */
- sf_list *p;
- for (p = rec->prev; p; p = p->prev) {
- if (is_identical_name(rec->name, p)) {
- rec->shared = p;
- break;
- }
- }
- }
- }
-#endif /* allow sharing */
-
- return 0;
-}
-
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
-
-/* check if the given name is a valid shared name */
-#define ASC_TO_KEY(c) ((c) - 'A' + 1)
-static int is_shared_sf(unsigned char *name)
-{
- static unsigned char id_head[4] = {
- ASC_TO_KEY('A'), ASC_TO_KEY('W'), ASC_TO_KEY('E'),
- AWE_MAJOR_VERSION,
- };
- if (memcmp(name, id_head, 4) == 0)
- return TRUE;
- return FALSE;
-}
-
-/* check if the given name matches to the existing list */
-static int is_identical_name(unsigned char *name, sf_list *p)
-{
- char *id = p->name;
- if (is_shared_sf(id) && memcmp(id, name, AWE_PATCH_NAME_LEN) == 0)
- return TRUE;
- return FALSE;
-}
-
-/* check if the given voice info exists */
-static int info_duplicated(sf_list *sf, awe_voice_list *rec)
-{
- /* search for all sharing lists */
- for (; sf; sf = sf->shared) {
- awe_voice_list *p;
- for (p = sf->infos; p; p = p->next) {
- if (p->type == V_ST_NORMAL &&
- p->bank == rec->bank &&
- p->instr == rec->instr &&
- p->v.low == rec->v.low &&
- p->v.high == rec->v.high &&
- p->v.sample == rec->v.sample)
- return TRUE;
- }
- }
- return FALSE;
-}
-
-#endif /* AWE_ALLOW_SAMPLE_SHARING */
-
-
-/* free sf_list record */
-/* linked-list in this function is not cared */
-static void
-awe_free_sf(sf_list *sf)
-{
- if (sf->infos) {
- awe_voice_list *p, *next;
- for (p = sf->infos; p; p = next) {
- next = p->next;
- kfree(p);
- }
- }
- if (sf->samples) {
- awe_sample_list *p, *next;
- for (p = sf->samples; p; p = next) {
- next = p->next;
- kfree(p);
- }
- }
- kfree(sf);
-}
-
-
-/* open patch; create sf list and set opened flag */
-static int
-awe_open_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
- awe_open_parm parm;
- int shared;
-
- if (copy_from_user(&parm, addr + AWE_PATCH_INFO_SIZE, sizeof(parm)))
- return -EFAULT;
- shared = FALSE;
-
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (sftail && (parm.type & AWE_PAT_SHARED) != 0) {
- /* is the previous font the same font? */
- if (is_identical_name(parm.name, sftail)) {
- /* then append to the previous */
- shared = TRUE;
- awe_reset(0);
- if (parm.type & AWE_PAT_LOCKED)
- locked_sf_id = current_sf_id;
- }
- }
-#endif /* allow sharing */
- if (! shared) {
- if (awe_create_sf(parm.type, parm.name)) {
- printk(KERN_ERR "AWE32: can't open: failed to alloc new list\n");
- return -ENOMEM;
- }
- }
- patch_opened = TRUE;
- return current_sf_id;
-}
-
-/* check if the patch is already opened */
-static sf_list *
-check_patch_opened(int type, char *name)
-{
- if (! patch_opened) {
- if (awe_create_sf(type, name)) {
- printk(KERN_ERR "AWE32: failed to alloc new list\n");
- return NULL;
- }
- patch_opened = TRUE;
- return sftail;
- }
- return sftail;
-}
-
-/* close the patch; if no voice is loaded, remove the patch */
-static int
-awe_close_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (patch_opened && sftail) {
- /* if no voice is loaded, release the current patch */
- if (sftail->infos == NULL) {
- awe_reset(0);
- awe_remove_samples(current_sf_id - 1);
- }
- }
- patch_opened = 0;
- return 0;
-}
-
-
-/* remove the latest patch */
-static int
-awe_unload_patch(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (current_sf_id > 0 && current_sf_id > locked_sf_id) {
- awe_reset(0);
- awe_remove_samples(current_sf_id - 1);
- }
- return 0;
-}
-
-/* allocate voice info list records */
-static awe_voice_list *
-alloc_new_info(void)
-{
- awe_voice_list *newlist;
-
- newlist = kmalloc(sizeof(*newlist), GFP_KERNEL);
- if (newlist == NULL) {
- printk(KERN_ERR "AWE32: can't alloc info table\n");
- return NULL;
- }
- return newlist;
-}
-
-/* allocate sample info list records */
-static awe_sample_list *
-alloc_new_sample(void)
-{
- awe_sample_list *newlist;
-
- newlist = (awe_sample_list *)kmalloc(sizeof(*newlist), GFP_KERNEL);
- if (newlist == NULL) {
- printk(KERN_ERR "AWE32: can't alloc sample table\n");
- return NULL;
- }
- return newlist;
-}
-
-/* load voice map */
-static int
-awe_load_map(awe_patch_info *patch, const char __user *addr, int count)
-{
- awe_voice_map map;
- awe_voice_list *rec, *p;
- sf_list *sf;
-
- /* get the link info */
- if (count < sizeof(map)) {
- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
- return -EINVAL;
- }
- if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
- return -EFAULT;
-
- /* check if the identical mapping already exists */
- p = awe_search_instr(map.map_bank, map.map_instr, map.map_key);
- for (; p; p = p->next_instr) {
- if (p->type == V_ST_MAPPED &&
- p->v.start == map.src_instr &&
- p->v.end == map.src_bank &&
- p->v.fixkey == map.src_key)
- return 0; /* already present! */
- }
-
- if ((sf = check_patch_opened(AWE_PAT_TYPE_MAP, NULL)) == NULL)
- return -ENOMEM;
-
- if ((rec = alloc_new_info()) == NULL)
- return -ENOMEM;
-
- rec->bank = map.map_bank;
- rec->instr = map.map_instr;
- rec->type = V_ST_MAPPED;
- rec->disabled = FALSE;
- awe_init_voice_info(&rec->v);
- if (map.map_key >= 0) {
- rec->v.low = map.map_key;
- rec->v.high = map.map_key;
- }
- rec->v.start = map.src_instr;
- rec->v.end = map.src_bank;
- rec->v.fixkey = map.src_key;
- add_sf_info(sf, rec);
- add_info_list(rec);
-
- return 0;
-}
-
-#if 0
-/* probe preset in the current list -- nothing to be loaded */
-static int
-awe_probe_info(awe_patch_info *patch, const char __user *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- awe_voice_map map;
- awe_voice_list *p;
-
- if (! patch_opened)
- return -EINVAL;
-
- /* get the link info */
- if (count < sizeof(map)) {
- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
- return -EINVAL;
- }
- if (copy_from_user(&map, addr + AWE_PATCH_INFO_SIZE, sizeof(map)))
- return -EFAULT;
-
- /* check if the identical mapping already exists */
- if (sftail == NULL)
- return -EINVAL;
- p = awe_search_instr(map.src_bank, map.src_instr, map.src_key);
- for (; p; p = p->next_instr) {
- if (p->type == V_ST_NORMAL &&
- is_identical_holder(p->holder, sftail) &&
- p->v.low <= map.src_key &&
- p->v.high >= map.src_key)
- return 0; /* already present! */
- }
-#endif /* allow sharing */
- return -EINVAL;
-}
-#endif
-
-/* probe sample in the current list -- nothing to be loaded */
-static int
-awe_probe_data(awe_patch_info *patch, const char __user *addr, int count)
-{
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (! patch_opened)
- return -EINVAL;
-
- /* search the specified sample by optarg */
- if (search_sample_index(sftail, patch->optarg) != NULL)
- return 0;
-#endif /* allow sharing */
- return -EINVAL;
-}
-
-
-/* remove the present instrument layers */
-static int
-remove_info(sf_list *sf, int bank, int instr)
-{
- awe_voice_list *prev, *next, *p;
- int removed = 0;
-
- prev = NULL;
- for (p = sf->infos; p; p = next) {
- next = p->next;
- if (p->type == V_ST_NORMAL &&
- p->bank == bank && p->instr == instr) {
- /* remove this layer */
- if (prev)
- prev->next = next;
- else
- sf->infos = next;
- if (p == sf->last_infos)
- sf->last_infos = prev;
- sf->num_info--;
- removed++;
- kfree(p);
- } else
- prev = p;
- }
- if (removed)
- rebuild_preset_list();
- return removed;
-}
-
-/* load voice information data */
-static int
-awe_load_info(awe_patch_info *patch, const char __user *addr, int count)
-{
- int offset;
- awe_voice_rec_hdr hdr;
- int i;
- int total_size;
- sf_list *sf;
- awe_voice_list *rec;
-
- if (count < AWE_VOICE_REC_SIZE) {
- printk(KERN_WARNING "AWE32 Error: invalid patch info length\n");
- return -EINVAL;
- }
-
- offset = AWE_PATCH_INFO_SIZE;
- if (copy_from_user((char*)&hdr, addr + offset, AWE_VOICE_REC_SIZE))
- return -EFAULT;
- offset += AWE_VOICE_REC_SIZE;
-
- if (hdr.nvoices <= 0 || hdr.nvoices >= 100) {
- printk(KERN_WARNING "AWE32 Error: Invalid voice number %d\n", hdr.nvoices);
- return -EINVAL;
- }
- total_size = AWE_VOICE_REC_SIZE + AWE_VOICE_INFO_SIZE * hdr.nvoices;
- if (count < total_size) {
- printk(KERN_WARNING "AWE32 Error: patch length(%d) is smaller than nvoices(%d)\n",
- count, hdr.nvoices);
- return -EINVAL;
- }
-
- if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
- return -ENOMEM;
-
- switch (hdr.write_mode) {
- case AWE_WR_EXCLUSIVE:
- /* exclusive mode - if the instrument already exists,
- return error */
- for (rec = sf->infos; rec; rec = rec->next) {
- if (rec->type == V_ST_NORMAL &&
- rec->bank == hdr.bank &&
- rec->instr == hdr.instr)
- return -EINVAL;
- }
- break;
- case AWE_WR_REPLACE:
- /* replace mode - remove the instrument if it already exists */
- remove_info(sf, hdr.bank, hdr.instr);
- break;
- }
-
- /* append new layers */
- for (i = 0; i < hdr.nvoices; i++) {
- rec = alloc_new_info();
- if (rec == NULL)
- return -ENOMEM;
-
- rec->bank = hdr.bank;
- rec->instr = hdr.instr;
- rec->type = V_ST_NORMAL;
- rec->disabled = FALSE;
-
- /* copy awe_voice_info parameters */
- if (copy_from_user(&rec->v, addr + offset, AWE_VOICE_INFO_SIZE)) {
- kfree(rec);
- return -EFAULT;
- }
- offset += AWE_VOICE_INFO_SIZE;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- if (sf && sf->shared) {
- if (info_duplicated(sf, rec)) {
- kfree(rec);
- continue;
- }
- }
-#endif /* allow sharing */
- if (rec->v.mode & AWE_MODE_INIT_PARM)
- awe_init_voice_parm(&rec->v.parm);
- add_sf_info(sf, rec);
- awe_set_sample(rec);
- add_info_list(rec);
- }
-
- return 0;
-}
-
-
-/* remove instrument layers */
-static int
-awe_remove_info(awe_patch_info *patch, const char __user *addr, int count)
-{
- unsigned char bank, instr;
- sf_list *sf;
-
- if (! patch_opened || (sf = sftail) == NULL) {
- printk(KERN_WARNING "AWE32: remove_info: patch not opened\n");
- return -EINVAL;
- }
-
- bank = ((unsigned short)patch->optarg >> 8) & 0xff;
- instr = (unsigned short)patch->optarg & 0xff;
- if (! remove_info(sf, bank, instr))
- return -EINVAL;
- return 0;
-}
-
-
-/* load wave sample data */
-static int
-awe_load_data(awe_patch_info *patch, const char __user *addr, int count)
-{
- int offset, size;
- int rc;
- awe_sample_info tmprec;
- awe_sample_list *rec;
- sf_list *sf;
-
- if ((sf = check_patch_opened(AWE_PAT_TYPE_MISC, NULL)) == NULL)
- return -ENOMEM;
-
- size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
- offset = AWE_PATCH_INFO_SIZE;
- if (copy_from_user(&tmprec, addr + offset, AWE_SAMPLE_INFO_SIZE))
- return -EFAULT;
- offset += AWE_SAMPLE_INFO_SIZE;
- if (size != tmprec.size) {
- printk(KERN_WARNING "AWE32: load: sample size differed (%d != %d)\n",
- tmprec.size, size);
- return -EINVAL;
- }
-
- if (search_sample_index(sf, tmprec.sample) != NULL) {
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- /* if shared sample, skip this data */
- if (sf->type & AWE_PAT_SHARED)
- return 0;
-#endif /* allow sharing */
- DEBUG(1,printk("AWE32: sample data %d already present\n", tmprec.sample));
- return -EINVAL;
- }
-
- if ((rec = alloc_new_sample()) == NULL)
- return -ENOMEM;
-
- memcpy(&rec->v, &tmprec, sizeof(tmprec));
-
- if (rec->v.size > 0) {
- if ((rc = awe_write_wave_data(addr, offset, rec, -1)) < 0) {
- kfree(rec);
- return rc;
- }
- sf->mem_ptr += rc;
- }
-
- add_sf_sample(sf, rec);
- return 0;
-}
-
-
-/* replace wave sample data */
-static int
-awe_replace_data(awe_patch_info *patch, const char __user *addr, int count)
-{
- int offset;
- int size;
- int rc;
- int channels;
- awe_sample_info cursmp;
- int save_mem_ptr;
- sf_list *sf;
- awe_sample_list *rec;
-
- if (! patch_opened || (sf = sftail) == NULL) {
- printk(KERN_WARNING "AWE32: replace: patch not opened\n");
- return -EINVAL;
- }
-
- size = (count - AWE_SAMPLE_INFO_SIZE) / 2;
- offset = AWE_PATCH_INFO_SIZE;
- if (copy_from_user(&cursmp, addr + offset, AWE_SAMPLE_INFO_SIZE))
- return -EFAULT;
- offset += AWE_SAMPLE_INFO_SIZE;
- if (cursmp.size == 0 || size != cursmp.size) {
- printk(KERN_WARNING "AWE32: replace: invalid sample size (%d!=%d)\n",
- cursmp.size, size);
- return -EINVAL;
- }
- channels = patch->optarg;
- if (channels <= 0 || channels > AWE_NORMAL_VOICES) {
- printk(KERN_WARNING "AWE32: replace: invalid channels %d\n", channels);
- return -EINVAL;
- }
-
- for (rec = sf->samples; rec; rec = rec->next) {
- if (rec->v.sample == cursmp.sample)
- break;
- }
- if (rec == NULL) {
- printk(KERN_WARNING "AWE32: replace: cannot find existing sample data %d\n",
- cursmp.sample);
- return -EINVAL;
- }
-
- if (rec->v.size != cursmp.size) {
- printk(KERN_WARNING "AWE32: replace: exiting size differed (%d!=%d)\n",
- rec->v.size, cursmp.size);
- return -EINVAL;
- }
-
- save_mem_ptr = awe_free_mem_ptr();
- sftail->mem_ptr = rec->v.start - awe_mem_start;
- memcpy(&rec->v, &cursmp, sizeof(cursmp));
- rec->v.sf_id = current_sf_id;
- if ((rc = awe_write_wave_data(addr, offset, rec, channels)) < 0)
- return rc;
- sftail->mem_ptr = save_mem_ptr;
-
- return 0;
-}
-
-
-/*----------------------------------------------------------------*/
-
-static const char __user *readbuf_addr;
-static int readbuf_offs;
-static int readbuf_flags;
-
-/* initialize read buffer */
-static int
-readbuf_init(const char __user *addr, int offset, awe_sample_info *sp)
-{
- readbuf_addr = addr;
- readbuf_offs = offset;
- readbuf_flags = sp->mode_flags;
- return 0;
-}
-
-/* read directly from user buffer */
-static unsigned short
-readbuf_word(int pos)
-{
- unsigned short c;
- /* read from user buffer */
- if (readbuf_flags & AWE_SAMPLE_8BITS) {
- unsigned char cc;
- get_user(cc, (unsigned char __user *)(readbuf_addr + readbuf_offs + pos));
- c = (unsigned short)cc << 8; /* convert 8bit -> 16bit */
- } else {
- get_user(c, (unsigned short __user *)(readbuf_addr + readbuf_offs + pos * 2));
- }
- if (readbuf_flags & AWE_SAMPLE_UNSIGNED)
- c ^= 0x8000; /* unsigned -> signed */
- return c;
-}
-
-#define readbuf_word_cache readbuf_word
-#define readbuf_end() /**/
-
-/*----------------------------------------------------------------*/
-
-#define BLANK_LOOP_START 8
-#define BLANK_LOOP_END 40
-#define BLANK_LOOP_SIZE 48
-
-/* loading onto memory - return the actual written size */
-static int
-awe_write_wave_data(const char __user *addr, int offset, awe_sample_list *list, int channels)
-{
- int i, truesize, dram_offset;
- awe_sample_info *sp = &list->v;
- int rc;
-
- /* be sure loop points start < end */
- if (sp->loopstart > sp->loopend) {
- int tmp = sp->loopstart;
- sp->loopstart = sp->loopend;
- sp->loopend = tmp;
- }
-
- /* compute true data size to be loaded */
- truesize = sp->size;
- if (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))
- truesize += sp->loopend - sp->loopstart;
- if (sp->mode_flags & AWE_SAMPLE_NO_BLANK)
- truesize += BLANK_LOOP_SIZE;
- if (awe_free_mem_ptr() + truesize >= memsize/2) {
- DEBUG(-1,printk("AWE32 Error: Sample memory full\n"));
- return -ENOSPC;
- }
-
- /* recalculate address offset */
- sp->end -= sp->start;
- sp->loopstart -= sp->start;
- sp->loopend -= sp->start;
-
- dram_offset = awe_free_mem_ptr() + awe_mem_start;
- sp->start = dram_offset;
- sp->end += dram_offset;
- sp->loopstart += dram_offset;
- sp->loopend += dram_offset;
-
- /* set the total size (store onto obsolete checksum value) */
- if (sp->size == 0)
- sp->checksum = 0;
- else
- sp->checksum = truesize;
-
- if ((rc = awe_open_dram_for_write(dram_offset, channels)) != 0)
- return rc;
-
- if (readbuf_init(addr, offset, sp) < 0)
- return -ENOSPC;
-
- for (i = 0; i < sp->size; i++) {
- unsigned short c;
- c = readbuf_word(i);
- awe_write_dram(c);
- if (i == sp->loopend &&
- (sp->mode_flags & (AWE_SAMPLE_BIDIR_LOOP|AWE_SAMPLE_REVERSE_LOOP))) {
- int looplen = sp->loopend - sp->loopstart;
- /* copy reverse loop */
- int k;
- for (k = 1; k <= looplen; k++) {
- c = readbuf_word_cache(i - k);
- awe_write_dram(c);
- }
- if (sp->mode_flags & AWE_SAMPLE_BIDIR_LOOP) {
- sp->end += looplen;
- } else {
- sp->start += looplen;
- sp->end += looplen;
- }
- }
- }
- readbuf_end();
-
- /* if no blank loop is attached in the sample, add it */
- if (sp->mode_flags & AWE_SAMPLE_NO_BLANK) {
- for (i = 0; i < BLANK_LOOP_SIZE; i++)
- awe_write_dram(0);
- if (sp->mode_flags & AWE_SAMPLE_SINGLESHOT) {
- sp->loopstart = sp->end + BLANK_LOOP_START;
- sp->loopend = sp->end + BLANK_LOOP_END;
- }
- }
-
- awe_close_dram();
-
- /* initialize FM */
- awe_init_fm();
-
- return truesize;
-}
-
-
-/*----------------------------------------------------------------*/
-
-#ifdef AWE_HAS_GUS_COMPATIBILITY
-
-/* calculate GUS envelope time:
- * is this correct? i have no idea..
- */
-static int
-calc_gus_envelope_time(int rate, int start, int end)
-{
- int r, p, t;
- r = (3 - ((rate >> 6) & 3)) * 3;
- p = rate & 0x3f;
- t = end - start;
- if (t < 0) t = -t;
- if (13 > r)
- t = t << (13 - r);
- else
- t = t >> (r - 13);
- return (t * 10) / (p * 441);
-}
-
-#define calc_gus_sustain(val) (0x7f - vol_table[(val)/2])
-#define calc_gus_attenuation(val) vol_table[(val)/2]
-
-/* load GUS patch */
-static int
-awe_load_guspatch(const char __user *addr, int offs, int size, int pmgr_flag)
-{
- struct patch_info patch;
- awe_voice_info *rec;
- awe_sample_info *smp;
- awe_voice_list *vrec;
- awe_sample_list *smprec;
- int sizeof_patch;
- int note, rc;
- sf_list *sf;
-
- sizeof_patch = (int)((long)&patch.data[0] - (long)&patch); /* header size */
- if (size < sizeof_patch) {
- printk(KERN_WARNING "AWE32 Error: Patch header too short\n");
- return -EINVAL;
- }
- if (copy_from_user(((char*)&patch) + offs, addr + offs, sizeof_patch - offs))
- return -EFAULT;
- size -= sizeof_patch;
- if (size < patch.len) {
- printk(KERN_WARNING "AWE32 Error: Patch record too short (%d<%d)\n",
- size, patch.len);
- return -EINVAL;
- }
- if ((sf = check_patch_opened(AWE_PAT_TYPE_GUS, NULL)) == NULL)
- return -ENOMEM;
- if ((smprec = alloc_new_sample()) == NULL)
- return -ENOMEM;
- if ((vrec = alloc_new_info()) == NULL) {
- kfree(smprec);
- return -ENOMEM;
- }
-
- smp = &smprec->v;
- smp->sample = sf->num_sample;
- smp->start = 0;
- smp->end = patch.len;
- smp->loopstart = patch.loop_start;
- smp->loopend = patch.loop_end;
- smp->size = patch.len;
-
- /* set up mode flags */
- smp->mode_flags = 0;
- if (!(patch.mode & WAVE_16_BITS))
- smp->mode_flags |= AWE_SAMPLE_8BITS;
- if (patch.mode & WAVE_UNSIGNED)
- smp->mode_flags |= AWE_SAMPLE_UNSIGNED;
- smp->mode_flags |= AWE_SAMPLE_NO_BLANK;
- if (!(patch.mode & (WAVE_LOOPING|WAVE_BIDIR_LOOP|WAVE_LOOP_BACK)))
- smp->mode_flags |= AWE_SAMPLE_SINGLESHOT;
- if (patch.mode & WAVE_BIDIR_LOOP)
- smp->mode_flags |= AWE_SAMPLE_BIDIR_LOOP;
- if (patch.mode & WAVE_LOOP_BACK)
- smp->mode_flags |= AWE_SAMPLE_REVERSE_LOOP;
-
- DEBUG(0,printk("AWE32: [sample %d mode %x]\n", patch.instr_no, smp->mode_flags));
- if (patch.mode & WAVE_16_BITS) {
- /* convert to word offsets */
- smp->size /= 2;
- smp->end /= 2;
- smp->loopstart /= 2;
- smp->loopend /= 2;
- }
- smp->checksum_flag = 0;
- smp->checksum = 0;
-
- if ((rc = awe_write_wave_data(addr, sizeof_patch, smprec, -1)) < 0) {
- kfree(vrec);
- return rc;
- }
- sf->mem_ptr += rc;
- add_sf_sample(sf, smprec);
-
- /* set up voice info */
- rec = &vrec->v;
- awe_init_voice_info(rec);
- rec->sample = sf->num_info; /* the last sample */
- rec->rate_offset = calc_rate_offset(patch.base_freq);
- note = freq_to_note(patch.base_note);
- rec->root = note / 100;
- rec->tune = -(note % 100);
- rec->low = freq_to_note(patch.low_note) / 100;
- rec->high = freq_to_note(patch.high_note) / 100;
- DEBUG(1,printk("AWE32: [gus base offset=%d, note=%d, range=%d-%d(%d-%d)]\n",
- rec->rate_offset, note,
- rec->low, rec->high,
- patch.low_note, patch.high_note));
- /* panning position; -128 - 127 => 0-127 */
- rec->pan = (patch.panning + 128) / 2;
-
- /* detuning is ignored */
- /* 6points volume envelope */
- if (patch.mode & WAVE_ENVELOPES) {
- int attack, hold, decay, release;
- attack = calc_gus_envelope_time
- (patch.env_rate[0], 0, patch.env_offset[0]);
- hold = calc_gus_envelope_time
- (patch.env_rate[1], patch.env_offset[0],
- patch.env_offset[1]);
- decay = calc_gus_envelope_time
- (patch.env_rate[2], patch.env_offset[1],
- patch.env_offset[2]);
- release = calc_gus_envelope_time
- (patch.env_rate[3], patch.env_offset[1],
- patch.env_offset[4]);
- release += calc_gus_envelope_time
- (patch.env_rate[4], patch.env_offset[3],
- patch.env_offset[4]);
- release += calc_gus_envelope_time
- (patch.env_rate[5], patch.env_offset[4],
- patch.env_offset[5]);
- rec->parm.volatkhld = (calc_parm_hold(hold) << 8) |
- calc_parm_attack(attack);
- rec->parm.voldcysus = (calc_gus_sustain(patch.env_offset[2]) << 8) |
- calc_parm_decay(decay);
- rec->parm.volrelease = 0x8000 | calc_parm_decay(release);
- DEBUG(2,printk("AWE32: [gusenv atk=%d, hld=%d, dcy=%d, rel=%d]\n", attack, hold, decay, release));
- rec->attenuation = calc_gus_attenuation(patch.env_offset[0]);
- }
-
- /* tremolo effect */
- if (patch.mode & WAVE_TREMOLO) {
- int rate = (patch.tremolo_rate * 1000 / 38) / 42;
- rec->parm.tremfrq = ((patch.tremolo_depth / 2) << 8) | rate;
- DEBUG(2,printk("AWE32: [gusenv tremolo rate=%d, dep=%d, tremfrq=%x]\n",
- patch.tremolo_rate, patch.tremolo_depth,
- rec->parm.tremfrq));
- }
- /* vibrato effect */
- if (patch.mode & WAVE_VIBRATO) {
- int rate = (patch.vibrato_rate * 1000 / 38) / 42;
- rec->parm.fm2frq2 = ((patch.vibrato_depth / 6) << 8) | rate;
- DEBUG(2,printk("AWE32: [gusenv vibrato rate=%d, dep=%d, tremfrq=%x]\n",
- patch.tremolo_rate, patch.tremolo_depth,
- rec->parm.tremfrq));
- }
-
- /* scale_freq, scale_factor, volume, and fractions not implemented */
-
- /* append to the tail of the list */
- vrec->bank = ctrls[AWE_MD_GUS_BANK];
- vrec->instr = patch.instr_no;
- vrec->disabled = FALSE;
- vrec->type = V_ST_NORMAL;
-
- add_sf_info(sf, vrec);
- add_info_list(vrec);
-
- /* set the voice index */
- awe_set_sample(vrec);
-
- return 0;
-}
-
-#endif /* AWE_HAS_GUS_COMPATIBILITY */
-
-/*
- * sample and voice list handlers
- */
-
-/* append this to the current sf list */
-static void add_sf_info(sf_list *sf, awe_voice_list *rec)
-{
- if (sf == NULL)
- return;
- rec->holder = sf;
- rec->v.sf_id = sf->sf_id;
- if (sf->last_infos)
- sf->last_infos->next = rec;
- else
- sf->infos = rec;
- sf->last_infos = rec;
- rec->next = NULL;
- sf->num_info++;
-}
-
-/* prepend this sample to sf list */
-static void add_sf_sample(sf_list *sf, awe_sample_list *rec)
-{
- if (sf == NULL)
- return;
- rec->holder = sf;
- rec->v.sf_id = sf->sf_id;
- if (sf->last_samples)
- sf->last_samples->next = rec;
- else
- sf->samples = rec;
- sf->last_samples = rec;
- rec->next = NULL;
- sf->num_sample++;
-}
-
-/* purge the old records which don't belong with the same file id */
-static void purge_old_list(awe_voice_list *rec, awe_voice_list *next)
-{
- rec->next_instr = next;
- if (rec->bank == AWE_DRUM_BANK) {
- /* remove samples with the same note range */
- awe_voice_list *cur, *prev = rec;
- int low = rec->v.low;
- int high = rec->v.high;
- for (cur = next; cur; cur = cur->next_instr) {
- if (cur->v.low == low &&
- cur->v.high == high &&
- ! is_identical_holder(cur->holder, rec->holder))
- prev->next_instr = cur->next_instr;
- else
- prev = cur;
- }
- } else {
- if (! is_identical_holder(next->holder, rec->holder))
- /* remove all samples */
- rec->next_instr = NULL;
- }
-}
-
-/* prepend to top of the preset table */
-static void add_info_list(awe_voice_list *rec)
-{
- awe_voice_list *prev, *cur;
- int key;
-
- if (rec->disabled)
- return;
-
- key = awe_search_key(rec->bank, rec->instr, rec->v.low);
- prev = NULL;
- for (cur = preset_table[key]; cur; cur = cur->next_bank) {
- /* search the first record with the same bank number */
- if (cur->instr == rec->instr && cur->bank == rec->bank) {
- /* replace the list with the new record */
- rec->next_bank = cur->next_bank;
- if (prev)
- prev->next_bank = rec;
- else
- preset_table[key] = rec;
- purge_old_list(rec, cur);
- return;
- }
- prev = cur;
- }
-
- /* this is the first bank record.. just add this */
- rec->next_instr = NULL;
- rec->next_bank = preset_table[key];
- preset_table[key] = rec;
-}
-
-/* remove samples later than the specified sf_id */
-static void
-awe_remove_samples(int sf_id)
-{
- sf_list *p, *prev;
-
- if (sf_id <= 0) {
- awe_reset_samples();
- return;
- }
- /* already removed? */
- if (current_sf_id <= sf_id)
- return;
-
- for (p = sftail; p; p = prev) {
- if (p->sf_id <= sf_id)
- break;
- prev = p->prev;
- awe_free_sf(p);
- }
- sftail = p;
- if (sftail) {
- sf_id = sftail->sf_id;
- sftail->next = NULL;
- } else {
- sf_id = 0;
- sfhead = NULL;
- }
- current_sf_id = sf_id;
- if (locked_sf_id > sf_id)
- locked_sf_id = sf_id;
-
- rebuild_preset_list();
-}
-
-/* rebuild preset search list */
-static void rebuild_preset_list(void)
-{
- sf_list *p;
- awe_voice_list *rec;
-
- memset(preset_table, 0, sizeof(preset_table));
-
- for (p = sfhead; p; p = p->next) {
- for (rec = p->infos; rec; rec = rec->next)
- add_info_list(rec);
- }
-}
-
-/* compare the given sf_id pair */
-static int is_identical_holder(sf_list *sf1, sf_list *sf2)
-{
- if (sf1 == NULL || sf2 == NULL)
- return FALSE;
- if (sf1 == sf2)
- return TRUE;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- {
- /* compare with the sharing id */
- sf_list *p;
- int counter = 0;
- if (sf1->sf_id < sf2->sf_id) { /* make sure id1 > id2 */
- sf_list *tmp; tmp = sf1; sf1 = sf2; sf2 = tmp;
- }
- for (p = sf1->shared; p; p = p->shared) {
- if (counter++ > current_sf_id)
- break; /* strange sharing loop.. quit */
- if (p == sf2)
- return TRUE;
- }
- }
-#endif /* allow sharing */
- return FALSE;
-}
-
-/* search the sample index matching with the given sample id */
-static awe_sample_list *
-search_sample_index(sf_list *sf, int sample)
-{
- awe_sample_list *p;
-#ifdef AWE_ALLOW_SAMPLE_SHARING
- int counter = 0;
- while (sf) {
- for (p = sf->samples; p; p = p->next) {
- if (p->v.sample == sample)
- return p;
- }
- sf = sf->shared;
- if (counter++ > current_sf_id)
- break; /* strange sharing loop.. quit */
- }
-#else
- if (sf) {
- for (p = sf->samples; p; p = p->next) {
- if (p->v.sample == sample)
- return p;
- }
- }
-#endif
- return NULL;
-}
-
-/* search the specified sample */
-/* non-zero = found */
-static short
-awe_set_sample(awe_voice_list *rec)
-{
- awe_sample_list *smp;
- awe_voice_info *vp = &rec->v;
-
- vp->index = 0;
- if ((smp = search_sample_index(rec->holder, vp->sample)) == NULL)
- return 0;
-
- /* set the actual sample offsets */
- vp->start += smp->v.start;
- vp->end += smp->v.end;
- vp->loopstart += smp->v.loopstart;
- vp->loopend += smp->v.loopend;
- /* copy mode flags */
- vp->mode = smp->v.mode_flags;
- /* set flag */
- vp->index = 1;
-
- return 1;
-}
-
-
-/*
- * voice allocation
- */
-
-/* look for all voices associated with the specified note & velocity */
-static int
-awe_search_multi_voices(awe_voice_list *rec, int note, int velocity,
- awe_voice_info **vlist)
-{
- int nvoices;
-
- nvoices = 0;
- for (; rec; rec = rec->next_instr) {
- if (note >= rec->v.low &&
- note <= rec->v.high &&
- velocity >= rec->v.vellow &&
- velocity <= rec->v.velhigh) {
- if (rec->type == V_ST_MAPPED) {
- /* mapper */
- vlist[0] = &rec->v;
- return -1;
- }
- vlist[nvoices++] = &rec->v;
- if (nvoices >= AWE_MAX_VOICES)
- break;
- }
- }
- return nvoices;
-}
-
-/* store the voice list from the specified note and velocity.
- if the preset is mapped, seek for the destination preset, and rewrite
- the note number if necessary.
- */
-static int
-really_alloc_voices(int bank, int instr, int *note, int velocity, awe_voice_info **vlist)
-{
- int nvoices;
- awe_voice_list *vrec;
- int level = 0;
-
- for (;;) {
- vrec = awe_search_instr(bank, instr, *note);
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- if (nvoices == 0) {
- if (bank == AWE_DRUM_BANK)
- /* search default drumset */
- vrec = awe_search_instr(bank, ctrls[AWE_MD_DEF_DRUM], *note);
- else
- /* search default preset */
- vrec = awe_search_instr(ctrls[AWE_MD_DEF_BANK], instr, *note);
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- }
- if (nvoices == 0) {
- if (bank == AWE_DRUM_BANK && ctrls[AWE_MD_DEF_DRUM] != 0)
- /* search default drumset */
- vrec = awe_search_instr(bank, 0, *note);
- else if (bank != AWE_DRUM_BANK && ctrls[AWE_MD_DEF_BANK] != 0)
- /* search default preset */
- vrec = awe_search_instr(0, instr, *note);
- nvoices = awe_search_multi_voices(vrec, *note, velocity, vlist);
- }
- if (nvoices < 0) { /* mapping */
- int key = vlist[0]->fixkey;
- instr = vlist[0]->start;
- bank = vlist[0]->end;
- if (level++ > 5) {
- printk(KERN_ERR "AWE32: too deep mapping level\n");
- return 0;
- }
- if (key >= 0)
- *note = key;
- } else
- break;
- }
-
- return nvoices;
-}
-
-/* allocate voices corresponding note and velocity; supports multiple insts. */
-static void
-awe_alloc_multi_voices(int ch, int note, int velocity, int key)
-{
- int i, v, nvoices, bank;
- awe_voice_info *vlist[AWE_MAX_VOICES];
-
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(ch))
- bank = AWE_DRUM_BANK; /* always search drumset */
- else
- bank = channels[ch].bank;
-
- /* check the possible voices; note may be changeable if mapped */
- nvoices = really_alloc_voices(bank, channels[ch].instr,
- &note, velocity, vlist);
-
- /* set the voices */
- current_alloc_time++;
- for (i = 0; i < nvoices; i++) {
- v = awe_clear_voice();
- voices[v].key = key;
- voices[v].ch = ch;
- voices[v].note = note;
- voices[v].velocity = velocity;
- voices[v].time = current_alloc_time;
- voices[v].cinfo = &channels[ch];
- voices[v].sample = vlist[i];
- voices[v].state = AWE_ST_MARK;
- voices[v].layer = nvoices - i - 1; /* in reverse order */
- }
-
- /* clear the mark in allocated voices */
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].state == AWE_ST_MARK)
- voices[i].state = AWE_ST_OFF;
-
- }
-}
-
-
-/* search an empty voice.
- if no empty voice is found, at least terminate a voice
- */
-static int
-awe_clear_voice(void)
-{
- enum {
- OFF=0, RELEASED, SUSTAINED, PLAYING, END
- };
- struct voice_candidate_t {
- int best;
- int time;
- int vtarget;
- } candidate[END];
- int i, type, vtarget;
-
- vtarget = 0xffff;
- for (type = OFF; type < END; type++) {
- candidate[type].best = -1;
- candidate[type].time = current_alloc_time + 1;
- candidate[type].vtarget = vtarget;
- }
-
- for (i = 0; i < awe_max_voices; i++) {
- if (voices[i].state & AWE_ST_OFF)
- type = OFF;
- else if (voices[i].state & AWE_ST_RELEASED)
- type = RELEASED;
- else if (voices[i].state & AWE_ST_SUSTAINED)
- type = SUSTAINED;
- else if (voices[i].state & ~AWE_ST_MARK)
- type = PLAYING;
- else
- continue;
-#ifdef AWE_CHECK_VTARGET
- /* get current volume */
- vtarget = (awe_peek_dw(AWE_VTFT(i)) >> 16) & 0xffff;
-#endif
- if (candidate[type].best < 0 ||
- vtarget < candidate[type].vtarget ||
- (vtarget == candidate[type].vtarget &&
- voices[i].time < candidate[type].time)) {
- candidate[type].best = i;
- candidate[type].time = voices[i].time;
- candidate[type].vtarget = vtarget;
- }
- }
-
- for (type = OFF; type < END; type++) {
- if ((i = candidate[type].best) >= 0) {
- if (voices[i].state != AWE_ST_OFF)
- awe_terminate(i);
- awe_voice_init(i, TRUE);
- return i;
- }
- }
- return 0;
-}
-
-
-/* search sample for the specified note & velocity and set it on the voice;
- * note that voice is the voice index (not channel index)
- */
-static void
-awe_alloc_one_voice(int voice, int note, int velocity)
-{
- int ch, nvoices, bank;
- awe_voice_info *vlist[AWE_MAX_VOICES];
-
- ch = voices[voice].ch;
- if (MULTI_LAYER_MODE() && IS_DRUM_CHANNEL(voice))
- bank = AWE_DRUM_BANK; /* always search drumset */
- else
- bank = voices[voice].cinfo->bank;
-
- nvoices = really_alloc_voices(bank, voices[voice].cinfo->instr,
- &note, velocity, vlist);
- if (nvoices > 0) {
- voices[voice].time = ++current_alloc_time;
- voices[voice].sample = vlist[0]; /* use the first one */
- voices[voice].layer = 0;
- voices[voice].note = note;
- voices[voice].velocity = velocity;
- }
-}
-
-
-/*
- * sequencer2 functions
- */
-
-/* search an empty voice; used by sequencer2 */
-static int
-awe_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
- playing_mode = AWE_PLAY_MULTI2;
- awe_info.nr_voices = AWE_MAX_CHANNELS;
- return awe_clear_voice();
-}
-
-
-/* set up voice; used by sequencer2 */
-static void
-awe_setup_voice(int dev, int voice, int chn)
-{
- struct channel_info *info;
- if (synth_devs[dev] == NULL ||
- (info = &synth_devs[dev]->chn_info[chn]) == NULL)
- return;
-
- if (voice < 0 || voice >= awe_max_voices)
- return;
-
- DEBUG(2,printk("AWE32: [setup(%d) ch=%d]\n", voice, chn));
- channels[chn].expression_vol = info->controllers[CTL_EXPRESSION];
- channels[chn].main_vol = info->controllers[CTL_MAIN_VOLUME];
- channels[chn].panning =
- info->controllers[CTL_PAN] * 2 - 128; /* signed 8bit */
- channels[chn].bender = info->bender_value; /* zero center */
- channels[chn].bank = info->controllers[CTL_BANK_SELECT];
- channels[chn].sustained = info->controllers[CTL_SUSTAIN];
- if (info->controllers[CTL_EXT_EFF_DEPTH]) {
- FX_SET(&channels[chn].fx, AWE_FX_REVERB,
- info->controllers[CTL_EXT_EFF_DEPTH] * 2);
- }
- if (info->controllers[CTL_CHORUS_DEPTH]) {
- FX_SET(&channels[chn].fx, AWE_FX_CHORUS,
- info->controllers[CTL_CHORUS_DEPTH] * 2);
- }
- awe_set_instr(dev, chn, info->pgm_num);
-}
-
-
-#ifdef CONFIG_AWE32_MIXER
-/*
- * AWE32 mixer device control
- */
-
-static int awe_mixer_ioctl(int dev, unsigned int cmd, void __user *arg);
-
-static int my_mixerdev = -1;
-
-static struct mixer_operations awe_mixer_operations = {
- .owner = THIS_MODULE,
- .id = "AWE",
- .name = "AWE32 Equalizer",
- .ioctl = awe_mixer_ioctl,
-};
-
-static void __init attach_mixer(void)
-{
- if ((my_mixerdev = sound_alloc_mixerdev()) >= 0) {
- mixer_devs[my_mixerdev] = &awe_mixer_operations;
- }
-}
-
-static void unload_mixer(void)
-{
- if (my_mixerdev >= 0)
- sound_unload_mixerdev(my_mixerdev);
-}
-
-static int
-awe_mixer_ioctl(int dev, unsigned int cmd, void __user * arg)
-{
- int i, level, value;
-
- if (((cmd >> 8) & 0xff) != 'M')
- return -EINVAL;
-
- if (get_user(level, (int __user *)arg))
- return -EFAULT;
- level = ((level & 0xff) + (level >> 8)) / 2;
- DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level));
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
- switch (cmd & 0xff) {
- case SOUND_MIXER_BASS:
- value = level * 12 / 100;
- if (value >= 12)
- value = 11;
- ctrls[AWE_MD_BASS_LEVEL] = value;
- awe_update_equalizer();
- break;
- case SOUND_MIXER_TREBLE:
- value = level * 12 / 100;
- if (value >= 12)
- value = 11;
- ctrls[AWE_MD_TREBLE_LEVEL] = value;
- awe_update_equalizer();
- break;
- case SOUND_MIXER_VOLUME:
- level = level * 127 / 100;
- if (level >= 128) level = 127;
- atten_relative = FALSE;
- atten_offset = vol_table[level];
- awe_update_volume();
- break;
- }
- }
- switch (cmd & 0xff) {
- case SOUND_MIXER_BASS:
- level = ctrls[AWE_MD_BASS_LEVEL] * 100 / 24;
- level = (level << 8) | level;
- break;
- case SOUND_MIXER_TREBLE:
- level = ctrls[AWE_MD_TREBLE_LEVEL] * 100 / 24;
- level = (level << 8) | level;
- break;
- case SOUND_MIXER_VOLUME:
- value = atten_offset;
- if (atten_relative)
- value += ctrls[AWE_MD_ZERO_ATTEN];
- for (i = 127; i > 0; i--) {
- if (value <= vol_table[i])
- break;
- }
- level = i * 100 / 127;
- level = (level << 8) | level;
- break;
- case SOUND_MIXER_DEVMASK:
- level = SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_VOLUME;
- break;
- default:
- level = 0;
- break;
- }
- if (put_user(level, (int __user *)arg))
- return -EFAULT;
- return level;
-}
-#endif /* CONFIG_AWE32_MIXER */
-
-
-/*
- * initialization of Emu8000
- */
-
-/* intiailize audio channels */
-static void
-awe_init_audio(void)
-{
- int ch;
-
- /* turn off envelope engines */
- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
- awe_poke(AWE_DCYSUSV(ch), 0x80);
- }
-
- /* reset all other parameters to zero */
- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
- awe_poke(AWE_ENVVOL(ch), 0);
- awe_poke(AWE_ENVVAL(ch), 0);
- awe_poke(AWE_DCYSUS(ch), 0);
- awe_poke(AWE_ATKHLDV(ch), 0);
- awe_poke(AWE_LFO1VAL(ch), 0);
- awe_poke(AWE_ATKHLD(ch), 0);
- awe_poke(AWE_LFO2VAL(ch), 0);
- awe_poke(AWE_IP(ch), 0);
- awe_poke(AWE_IFATN(ch), 0);
- awe_poke(AWE_PEFE(ch), 0);
- awe_poke(AWE_FMMOD(ch), 0);
- awe_poke(AWE_TREMFRQ(ch), 0);
- awe_poke(AWE_FM2FRQ2(ch), 0);
- awe_poke_dw(AWE_PTRX(ch), 0);
- awe_poke_dw(AWE_VTFT(ch), 0);
- awe_poke_dw(AWE_PSST(ch), 0);
- awe_poke_dw(AWE_CSL(ch), 0);
- awe_poke_dw(AWE_CCCA(ch), 0);
- }
-
- for (ch = 0; ch < AWE_MAX_VOICES; ch++) {
- awe_poke_dw(AWE_CPF(ch), 0);
- awe_poke_dw(AWE_CVCF(ch), 0);
- }
-}
-
-
-/* initialize DMA address */
-static void
-awe_init_dma(void)
-{
- awe_poke_dw(AWE_SMALR, 0);
- awe_poke_dw(AWE_SMARR, 0);
- awe_poke_dw(AWE_SMALW, 0);
- awe_poke_dw(AWE_SMARW, 0);
-}
-
-
-/* initialization arrays; from ADIP */
-
-static unsigned short init1[128] = {
- 0x03ff, 0x0030, 0x07ff, 0x0130, 0x0bff, 0x0230, 0x0fff, 0x0330,
- 0x13ff, 0x0430, 0x17ff, 0x0530, 0x1bff, 0x0630, 0x1fff, 0x0730,
- 0x23ff, 0x0830, 0x27ff, 0x0930, 0x2bff, 0x0a30, 0x2fff, 0x0b30,
- 0x33ff, 0x0c30, 0x37ff, 0x0d30, 0x3bff, 0x0e30, 0x3fff, 0x0f30,
-
- 0x43ff, 0x0030, 0x47ff, 0x0130, 0x4bff, 0x0230, 0x4fff, 0x0330,
- 0x53ff, 0x0430, 0x57ff, 0x0530, 0x5bff, 0x0630, 0x5fff, 0x0730,
- 0x63ff, 0x0830, 0x67ff, 0x0930, 0x6bff, 0x0a30, 0x6fff, 0x0b30,
- 0x73ff, 0x0c30, 0x77ff, 0x0d30, 0x7bff, 0x0e30, 0x7fff, 0x0f30,
-
- 0x83ff, 0x0030, 0x87ff, 0x0130, 0x8bff, 0x0230, 0x8fff, 0x0330,
- 0x93ff, 0x0430, 0x97ff, 0x0530, 0x9bff, 0x0630, 0x9fff, 0x0730,
- 0xa3ff, 0x0830, 0xa7ff, 0x0930, 0xabff, 0x0a30, 0xafff, 0x0b30,
- 0xb3ff, 0x0c30, 0xb7ff, 0x0d30, 0xbbff, 0x0e30, 0xbfff, 0x0f30,
-
- 0xc3ff, 0x0030, 0xc7ff, 0x0130, 0xcbff, 0x0230, 0xcfff, 0x0330,
- 0xd3ff, 0x0430, 0xd7ff, 0x0530, 0xdbff, 0x0630, 0xdfff, 0x0730,
- 0xe3ff, 0x0830, 0xe7ff, 0x0930, 0xebff, 0x0a30, 0xefff, 0x0b30,
- 0xf3ff, 0x0c30, 0xf7ff, 0x0d30, 0xfbff, 0x0e30, 0xffff, 0x0f30,
-};
-
-static unsigned short init2[128] = {
- 0x03ff, 0x8030, 0x07ff, 0x8130, 0x0bff, 0x8230, 0x0fff, 0x8330,
- 0x13ff, 0x8430, 0x17ff, 0x8530, 0x1bff, 0x8630, 0x1fff, 0x8730,
- 0x23ff, 0x8830, 0x27ff, 0x8930, 0x2bff, 0x8a30, 0x2fff, 0x8b30,
- 0x33ff, 0x8c30, 0x37ff, 0x8d30, 0x3bff, 0x8e30, 0x3fff, 0x8f30,
-
- 0x43ff, 0x8030, 0x47ff, 0x8130, 0x4bff, 0x8230, 0x4fff, 0x8330,
- 0x53ff, 0x8430, 0x57ff, 0x8530, 0x5bff, 0x8630, 0x5fff, 0x8730,
- 0x63ff, 0x8830, 0x67ff, 0x8930, 0x6bff, 0x8a30, 0x6fff, 0x8b30,
- 0x73ff, 0x8c30, 0x77ff, 0x8d30, 0x7bff, 0x8e30, 0x7fff, 0x8f30,
-
- 0x83ff, 0x8030, 0x87ff, 0x8130, 0x8bff, 0x8230, 0x8fff, 0x8330,
- 0x93ff, 0x8430, 0x97ff, 0x8530, 0x9bff, 0x8630, 0x9fff, 0x8730,
- 0xa3ff, 0x8830, 0xa7ff, 0x8930, 0xabff, 0x8a30, 0xafff, 0x8b30,
- 0xb3ff, 0x8c30, 0xb7ff, 0x8d30, 0xbbff, 0x8e30, 0xbfff, 0x8f30,
-
- 0xc3ff, 0x8030, 0xc7ff, 0x8130, 0xcbff, 0x8230, 0xcfff, 0x8330,
- 0xd3ff, 0x8430, 0xd7ff, 0x8530, 0xdbff, 0x8630, 0xdfff, 0x8730,
- 0xe3ff, 0x8830, 0xe7ff, 0x8930, 0xebff, 0x8a30, 0xefff, 0x8b30,
- 0xf3ff, 0x8c30, 0xf7ff, 0x8d30, 0xfbff, 0x8e30, 0xffff, 0x8f30,
-};
-
-static unsigned short init3[128] = {
- 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
- 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x8F7C, 0x167E, 0xF254,
- 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x8BAA, 0x1B6D, 0xF234,
- 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x86E7, 0x229E, 0xF224,
-
- 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x87F6, 0x2C28, 0xF254,
- 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x8F02, 0x1341, 0xF264,
- 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x8FA9, 0x3EB5, 0xF294,
- 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0xC4C3, 0x3EBB, 0xC5C3,
-
- 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x8671, 0x14FD, 0x8287,
- 0x3EBC, 0xE610, 0x3EC8, 0x8C7B, 0x031A, 0x87E6, 0x3EC8, 0x86F7,
- 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x821F, 0x3ECA, 0x8386,
- 0x3EC1, 0x8C03, 0x3EC9, 0x831E, 0x3ECA, 0x8C4C, 0x3EBF, 0x8C55,
-
- 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x8EAD, 0x3EC8, 0xD308,
- 0x3EC2, 0x8F7E, 0x3ECB, 0x8219, 0x3ECB, 0xD26E, 0x3EC5, 0x831F,
- 0x3EC6, 0xC308, 0x3EC3, 0xB2FF, 0x3EC9, 0x8265, 0x3EC9, 0x8319,
- 0x1342, 0xD36E, 0x3EC7, 0xB3FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-static unsigned short init4[128] = {
- 0x0C10, 0x8470, 0x14FE, 0xB488, 0x167F, 0xA470, 0x18E7, 0x84B5,
- 0x1B6E, 0x842A, 0x1F1D, 0x852A, 0x0DA3, 0x0F7C, 0x167E, 0x7254,
- 0x0000, 0x842A, 0x0001, 0x852A, 0x18E6, 0x0BAA, 0x1B6D, 0x7234,
- 0x229F, 0x8429, 0x2746, 0x8529, 0x1F1C, 0x06E7, 0x229E, 0x7224,
-
- 0x0DA4, 0x8429, 0x2C29, 0x8529, 0x2745, 0x07F6, 0x2C28, 0x7254,
- 0x383B, 0x8428, 0x320F, 0x8528, 0x320E, 0x0F02, 0x1341, 0x7264,
- 0x3EB6, 0x8428, 0x3EB9, 0x8528, 0x383A, 0x0FA9, 0x3EB5, 0x7294,
- 0x3EB7, 0x8474, 0x3EBA, 0x8575, 0x3EB8, 0x44C3, 0x3EBB, 0x45C3,
-
- 0x0000, 0xA404, 0x0001, 0xA504, 0x141F, 0x0671, 0x14FD, 0x0287,
- 0x3EBC, 0xE610, 0x3EC8, 0x0C7B, 0x031A, 0x07E6, 0x3EC8, 0x86F7,
- 0x3EC0, 0x821E, 0x3EBE, 0xD208, 0x3EBD, 0x021F, 0x3ECA, 0x0386,
- 0x3EC1, 0x0C03, 0x3EC9, 0x031E, 0x3ECA, 0x8C4C, 0x3EBF, 0x0C55,
-
- 0x3EC9, 0xC208, 0x3EC4, 0xBC84, 0x3EC8, 0x0EAD, 0x3EC8, 0xD308,
- 0x3EC2, 0x8F7E, 0x3ECB, 0x0219, 0x3ECB, 0xD26E, 0x3EC5, 0x031F,
- 0x3EC6, 0xC308, 0x3EC3, 0x32FF, 0x3EC9, 0x0265, 0x3EC9, 0x8319,
- 0x1342, 0xD36E, 0x3EC7, 0x33FF, 0x0000, 0x8365, 0x1420, 0x9570,
-};
-
-
-/* send initialization arrays to start up */
-static void
-awe_init_array(void)
-{
- awe_send_array(init1);
- awe_wait(1024);
- awe_send_array(init2);
- awe_send_array(init3);
- awe_poke_dw(AWE_HWCF4, 0);
- awe_poke_dw(AWE_HWCF5, 0x83);
- awe_poke_dw(AWE_HWCF6, 0x8000);
- awe_send_array(init4);
-}
-
-/* send an initialization array */
-static void
-awe_send_array(unsigned short *data)
-{
- int i;
- unsigned short *p;
-
- p = data;
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT1(i), *p);
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT2(i), *p);
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT3(i), *p);
- for (i = 0; i < AWE_MAX_VOICES; i++, p++)
- awe_poke(AWE_INIT4(i), *p);
-}
-
-
-/*
- * set up awe32 channels to some known state.
- */
-
-/* set the envelope & LFO parameters to the default values; see ADIP */
-static void
-awe_tweak_voice(int i)
-{
- /* set all mod/vol envelope shape to minimum */
- awe_poke(AWE_ENVVOL(i), 0x8000);
- awe_poke(AWE_ENVVAL(i), 0x8000);
- awe_poke(AWE_DCYSUS(i), 0x7F7F);
- awe_poke(AWE_ATKHLDV(i), 0x7F7F);
- awe_poke(AWE_ATKHLD(i), 0x7F7F);
- awe_poke(AWE_PEFE(i), 0); /* mod envelope height to zero */
- awe_poke(AWE_LFO1VAL(i), 0x8000); /* no delay for LFO1 */
- awe_poke(AWE_LFO2VAL(i), 0x8000);
- awe_poke(AWE_IP(i), 0xE000); /* no pitch shift */
- awe_poke(AWE_IFATN(i), 0xFF00); /* volume to minimum */
- awe_poke(AWE_FMMOD(i), 0);
- awe_poke(AWE_TREMFRQ(i), 0);
- awe_poke(AWE_FM2FRQ2(i), 0);
-}
-
-static void
-awe_tweak(void)
-{
- int i;
- /* reset all channels */
- for (i = 0; i < awe_max_voices; i++)
- awe_tweak_voice(i);
-}
-
-
-/*
- * initializes the FM section of AWE32;
- * see Vince Vu's unofficial AWE32 programming guide
- */
-
-static void
-awe_init_fm(void)
-{
-#ifndef AWE_ALWAYS_INIT_FM
- /* if no extended memory is on board.. */
- if (memsize <= 0)
- return;
-#endif
- DEBUG(3,printk("AWE32: initializing FM\n"));
-
- /* Initialize the last two channels for DRAM refresh and producing
- the reverb and chorus effects for Yamaha OPL-3 synthesizer */
-
- /* 31: FM left channel, 0xffffe0-0xffffe8 */
- awe_poke(AWE_DCYSUSV(30), 0x80);
- awe_poke_dw(AWE_PSST(30), 0xFFFFFFE0); /* full left */
- awe_poke_dw(AWE_CSL(30), 0x00FFFFE8 |
- (DEF_FM_CHORUS_DEPTH << 24));
- awe_poke_dw(AWE_PTRX(30), (DEF_FM_REVERB_DEPTH << 8));
- awe_poke_dw(AWE_CPF(30), 0);
- awe_poke_dw(AWE_CCCA(30), 0x00FFFFE3);
-
- /* 32: FM right channel, 0xfffff0-0xfffff8 */
- awe_poke(AWE_DCYSUSV(31), 0x80);
- awe_poke_dw(AWE_PSST(31), 0x00FFFFF0); /* full right */
- awe_poke_dw(AWE_CSL(31), 0x00FFFFF8 |
- (DEF_FM_CHORUS_DEPTH << 24));
- awe_poke_dw(AWE_PTRX(31), (DEF_FM_REVERB_DEPTH << 8));
- awe_poke_dw(AWE_CPF(31), 0x8000);
- awe_poke_dw(AWE_CCCA(31), 0x00FFFFF3);
-
- /* skew volume & cutoff */
- awe_poke_dw(AWE_VTFT(30), 0x8000FFFF);
- awe_poke_dw(AWE_VTFT(31), 0x8000FFFF);
-
- voices[30].state = AWE_ST_FM;
- voices[31].state = AWE_ST_FM;
-
- /* change maximum channels to 30 */
- awe_max_voices = AWE_NORMAL_VOICES;
- if (playing_mode == AWE_PLAY_DIRECT)
- awe_info.nr_voices = awe_max_voices;
- else
- awe_info.nr_voices = AWE_MAX_CHANNELS;
- voice_alloc->max_voice = awe_max_voices;
-}
-
-/*
- * AWE32 DRAM access routines
- */
-
-/* open DRAM write accessing mode */
-static int
-awe_open_dram_for_write(int offset, int channels)
-{
- int vidx[AWE_NORMAL_VOICES];
- int i;
-
- if (channels < 0 || channels >= AWE_NORMAL_VOICES) {
- channels = AWE_NORMAL_VOICES;
- for (i = 0; i < AWE_NORMAL_VOICES; i++)
- vidx[i] = i;
- } else {
- for (i = 0; i < channels; i++) {
- vidx[i] = awe_clear_voice();
- voices[vidx[i]].state = AWE_ST_MARK;
- }
- }
-
- /* use all channels for DMA transfer */
- for (i = 0; i < channels; i++) {
- if (vidx[i] < 0) continue;
- awe_poke(AWE_DCYSUSV(vidx[i]), 0x80);
- awe_poke_dw(AWE_VTFT(vidx[i]), 0);
- awe_poke_dw(AWE_CVCF(vidx[i]), 0);
- awe_poke_dw(AWE_PTRX(vidx[i]), 0x40000000);
- awe_poke_dw(AWE_CPF(vidx[i]), 0x40000000);
- awe_poke_dw(AWE_PSST(vidx[i]), 0);
- awe_poke_dw(AWE_CSL(vidx[i]), 0);
- awe_poke_dw(AWE_CCCA(vidx[i]), 0x06000000);
- voices[vidx[i]].state = AWE_ST_DRAM;
- }
- /* point channels 31 & 32 to ROM samples for DRAM refresh */
- awe_poke_dw(AWE_VTFT(30), 0);
- awe_poke_dw(AWE_PSST(30), 0x1d8);
- awe_poke_dw(AWE_CSL(30), 0x1e0);
- awe_poke_dw(AWE_CCCA(30), 0x1d8);
- awe_poke_dw(AWE_VTFT(31), 0);
- awe_poke_dw(AWE_PSST(31), 0x1d8);
- awe_poke_dw(AWE_CSL(31), 0x1e0);
- awe_poke_dw(AWE_CCCA(31), 0x1d8);
- voices[30].state = AWE_ST_FM;
- voices[31].state = AWE_ST_FM;
-
- /* if full bit is on, not ready to write on */
- if (awe_peek_dw(AWE_SMALW) & 0x80000000) {
- for (i = 0; i < channels; i++) {
- awe_poke_dw(AWE_CCCA(vidx[i]), 0);
- voices[vidx[i]].state = AWE_ST_OFF;
- }
- printk("awe: not ready to write..\n");
- return -EPERM;
- }
-
- /* set address to write */
- awe_poke_dw(AWE_SMALW, offset);
-
- return 0;
-}
-
-/* open DRAM for RAM size detection */
-static void
-awe_open_dram_for_check(void)
-{
- int i;
- for (i = 0; i < AWE_NORMAL_VOICES; i++) {
- awe_poke(AWE_DCYSUSV(i), 0x80);
- awe_poke_dw(AWE_VTFT(i), 0);
- awe_poke_dw(AWE_CVCF(i), 0);
- awe_poke_dw(AWE_PTRX(i), 0x40000000);
- awe_poke_dw(AWE_CPF(i), 0x40000000);
- awe_poke_dw(AWE_PSST(i), 0);
- awe_poke_dw(AWE_CSL(i), 0);
- if (i & 1) /* DMA write */
- awe_poke_dw(AWE_CCCA(i), 0x06000000);
- else /* DMA read */
- awe_poke_dw(AWE_CCCA(i), 0x04000000);
- voices[i].state = AWE_ST_DRAM;
- }
-}
-
-
-/* close dram access */
-static void
-awe_close_dram(void)
-{
- int i;
- /* wait until FULL bit in SMAxW register be false */
- for (i = 0; i < 10000; i++) {
- if (!(awe_peek_dw(AWE_SMALW) & 0x80000000))
- break;
- awe_wait(10);
- }
-
- for (i = 0; i < AWE_NORMAL_VOICES; i++) {
- if (voices[i].state == AWE_ST_DRAM) {
- awe_poke_dw(AWE_CCCA(i), 0);
- awe_poke(AWE_DCYSUSV(i), 0x807F);
- voices[i].state = AWE_ST_OFF;
- }
- }
-}
-
-
-/*
- * check dram size on AWE board
- */
-
-/* any three numbers you like */
-#define UNIQUE_ID1 0x1234
-#define UNIQUE_ID2 0x4321
-#define UNIQUE_ID3 0xABCD
-
-static void __init
-awe_check_dram(void)
-{
- if (awe_present) /* already initialized */
- return;
-
- if (memsize >= 0) { /* given by config file or module option */
- memsize *= 1024; /* convert to Kbytes */
- return;
- }
-
- awe_open_dram_for_check();
-
- memsize = 0;
-
- /* set up unique two id numbers */
- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET);
- awe_poke(AWE_SMLD, UNIQUE_ID1);
- awe_poke(AWE_SMLD, UNIQUE_ID2);
-
- while (memsize < AWE_MAX_DRAM_SIZE) {
- awe_wait(5);
- /* read a data on the DRAM start address */
- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET);
- awe_peek(AWE_SMLD); /* discard stale data */
- if (awe_peek(AWE_SMLD) != UNIQUE_ID1)
- break;
- if (awe_peek(AWE_SMLD) != UNIQUE_ID2)
- break;
- memsize += 512; /* increment 512kbytes */
- /* Write a unique data on the test address;
- * if the address is out of range, the data is written on
- * 0x200000(=AWE_DRAM_OFFSET). Then the two id words are
- * broken by this data.
- */
- awe_poke_dw(AWE_SMALW, AWE_DRAM_OFFSET + memsize*512L);
- awe_poke(AWE_SMLD, UNIQUE_ID3);
- awe_wait(5);
- /* read a data on the just written DRAM address */
- awe_poke_dw(AWE_SMALR, AWE_DRAM_OFFSET + memsize*512L);
- awe_peek(AWE_SMLD); /* discard stale data */
- if (awe_peek(AWE_SMLD) != UNIQUE_ID3)
- break;
- }
- awe_close_dram();
-
- DEBUG(0,printk("AWE32: %d Kbytes memory detected\n", memsize));
-
- /* convert to Kbytes */
- memsize *= 1024;
-}
-
-
-/*----------------------------------------------------------------*/
-
-/*
- * chorus and reverb controls; from VV's guide
- */
-
-/* 5 parameters for each chorus mode; 3 x 16bit, 2 x 32bit */
-static char chorus_defined[AWE_CHORUS_NUMBERS];
-static awe_chorus_fx_rec chorus_parm[AWE_CHORUS_NUMBERS] = {
- {0xE600, 0x03F6, 0xBC2C ,0x00000000, 0x0000006D}, /* chorus 1 */
- {0xE608, 0x031A, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 2 */
- {0xE610, 0x031A, 0xBC84, 0x00000000, 0x00000083}, /* chorus 3 */
- {0xE620, 0x0269, 0xBC6E, 0x00000000, 0x0000017C}, /* chorus 4 */
- {0xE680, 0x04D3, 0xBCA6, 0x00000000, 0x0000005B}, /* feedback */
- {0xE6E0, 0x044E, 0xBC37, 0x00000000, 0x00000026}, /* flanger */
- {0xE600, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay */
- {0xE6C0, 0x0B06, 0xBC00, 0x0000E000, 0x00000083}, /* short delay + feedback */
-};
-
-static int
-awe_load_chorus_fx(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (patch->optarg < AWE_CHORUS_PREDEFINED || patch->optarg >= AWE_CHORUS_NUMBERS) {
- printk(KERN_WARNING "AWE32 Error: invalid chorus mode %d for uploading\n", patch->optarg);
- return -EINVAL;
- }
- if (count < sizeof(awe_chorus_fx_rec)) {
- printk(KERN_WARNING "AWE32 Error: too short chorus fx parameters\n");
- return -EINVAL;
- }
- if (copy_from_user(&chorus_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_chorus_fx_rec)))
- return -EFAULT;
- chorus_defined[patch->optarg] = TRUE;
- return 0;
-}
-
-static void
-awe_set_chorus_mode(int effect)
-{
- if (effect < 0 || effect >= AWE_CHORUS_NUMBERS ||
- (effect >= AWE_CHORUS_PREDEFINED && !chorus_defined[effect]))
- return;
- awe_poke(AWE_INIT3(9), chorus_parm[effect].feedback);
- awe_poke(AWE_INIT3(12), chorus_parm[effect].delay_offset);
- awe_poke(AWE_INIT4(3), chorus_parm[effect].lfo_depth);
- awe_poke_dw(AWE_HWCF4, chorus_parm[effect].delay);
- awe_poke_dw(AWE_HWCF5, chorus_parm[effect].lfo_freq);
- awe_poke_dw(AWE_HWCF6, 0x8000);
- awe_poke_dw(AWE_HWCF7, 0x0000);
-}
-
-static void
-awe_update_chorus_mode(void)
-{
- awe_set_chorus_mode(ctrls[AWE_MD_CHORUS_MODE]);
-}
-
-/*----------------------------------------------------------------*/
-
-/* reverb mode settings; write the following 28 data of 16 bit length
- * on the corresponding ports in the reverb_cmds array
- */
-static char reverb_defined[AWE_CHORUS_NUMBERS];
-static awe_reverb_fx_rec reverb_parm[AWE_REVERB_NUMBERS] = {
-{{ /* room 1 */
- 0xB488, 0xA450, 0x9550, 0x84B5, 0x383A, 0x3EB5, 0x72F4,
- 0x72A4, 0x7254, 0x7204, 0x7204, 0x7204, 0x4416, 0x4516,
- 0xA490, 0xA590, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* room 2 */
- 0xB488, 0xA458, 0x9558, 0x84B5, 0x383A, 0x3EB5, 0x7284,
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* room 3 */
- 0xB488, 0xA460, 0x9560, 0x84B5, 0x383A, 0x3EB5, 0x7284,
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4416, 0x4516,
- 0xA490, 0xA590, 0x842C, 0x852C, 0x842C, 0x852C, 0x842B,
- 0x852B, 0x842B, 0x852B, 0x842A, 0x852A, 0x842A, 0x852A,
-}},
-{{ /* hall 1 */
- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7284,
- 0x7254, 0x7224, 0x7224, 0x7254, 0x7284, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842B, 0x852B, 0x842B, 0x852B, 0x842A,
- 0x852A, 0x842A, 0x852A, 0x8429, 0x8529, 0x8429, 0x8529,
-}},
-{{ /* hall 2 */
- 0xB488, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7254,
- 0x7234, 0x7224, 0x7254, 0x7264, 0x7294, 0x44C3, 0x45C3,
- 0xA404, 0xA504, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* plate */
- 0xB4FF, 0xA470, 0x9570, 0x84B5, 0x383A, 0x3EB5, 0x7234,
- 0x7234, 0x7234, 0x7234, 0x7234, 0x7234, 0x4448, 0x4548,
- 0xA440, 0xA540, 0x842A, 0x852A, 0x842A, 0x852A, 0x8429,
- 0x8529, 0x8429, 0x8529, 0x8428, 0x8528, 0x8428, 0x8528,
-}},
-{{ /* delay */
- 0xB4FF, 0xA470, 0x9500, 0x84B5, 0x333A, 0x39B5, 0x7204,
- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-{{ /* panning delay */
- 0xB4FF, 0xA490, 0x9590, 0x8474, 0x333A, 0x39B5, 0x7204,
- 0x7204, 0x7204, 0x7204, 0x7204, 0x72F4, 0x4400, 0x4500,
- 0xA4FF, 0xA5FF, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420,
- 0x8520, 0x8420, 0x8520, 0x8420, 0x8520, 0x8420, 0x8520,
-}},
-};
-
-static struct ReverbCmdPair {
- unsigned short cmd, port;
-} reverb_cmds[28] = {
- {AWE_INIT1(0x03)}, {AWE_INIT1(0x05)}, {AWE_INIT4(0x1F)}, {AWE_INIT1(0x07)},
- {AWE_INIT2(0x14)}, {AWE_INIT2(0x16)}, {AWE_INIT1(0x0F)}, {AWE_INIT1(0x17)},
- {AWE_INIT1(0x1F)}, {AWE_INIT2(0x07)}, {AWE_INIT2(0x0F)}, {AWE_INIT2(0x17)},
- {AWE_INIT2(0x1D)}, {AWE_INIT2(0x1F)}, {AWE_INIT3(0x01)}, {AWE_INIT3(0x03)},
- {AWE_INIT1(0x09)}, {AWE_INIT1(0x0B)}, {AWE_INIT1(0x11)}, {AWE_INIT1(0x13)},
- {AWE_INIT1(0x19)}, {AWE_INIT1(0x1B)}, {AWE_INIT2(0x01)}, {AWE_INIT2(0x03)},
- {AWE_INIT2(0x09)}, {AWE_INIT2(0x0B)}, {AWE_INIT2(0x11)}, {AWE_INIT2(0x13)},
-};
-
-static int
-awe_load_reverb_fx(awe_patch_info *patch, const char __user *addr, int count)
-{
- if (patch->optarg < AWE_REVERB_PREDEFINED || patch->optarg >= AWE_REVERB_NUMBERS) {
- printk(KERN_WARNING "AWE32 Error: invalid reverb mode %d for uploading\n", patch->optarg);
- return -EINVAL;
- }
- if (count < sizeof(awe_reverb_fx_rec)) {
- printk(KERN_WARNING "AWE32 Error: too short reverb fx parameters\n");
- return -EINVAL;
- }
- if (copy_from_user(&reverb_parm[patch->optarg], addr + AWE_PATCH_INFO_SIZE,
- sizeof(awe_reverb_fx_rec)))
- return -EFAULT;
- reverb_defined[patch->optarg] = TRUE;
- return 0;
-}
-
-static void
-awe_set_reverb_mode(int effect)
-{
- int i;
- if (effect < 0 || effect >= AWE_REVERB_NUMBERS ||
- (effect >= AWE_REVERB_PREDEFINED && !reverb_defined[effect]))
- return;
- for (i = 0; i < 28; i++)
- awe_poke(reverb_cmds[i].cmd, reverb_cmds[i].port,
- reverb_parm[effect].parms[i]);
-}
-
-static void
-awe_update_reverb_mode(void)
-{
- awe_set_reverb_mode(ctrls[AWE_MD_REVERB_MODE]);
-}
-
-/*
- * treble/bass equalizer control
- */
-
-static unsigned short bass_parm[12][3] = {
- {0xD26A, 0xD36A, 0x0000}, /* -12 dB */
- {0xD25B, 0xD35B, 0x0000}, /* -8 */
- {0xD24C, 0xD34C, 0x0000}, /* -6 */
- {0xD23D, 0xD33D, 0x0000}, /* -4 */
- {0xD21F, 0xD31F, 0x0000}, /* -2 */
- {0xC208, 0xC308, 0x0001}, /* 0 (HW default) */
- {0xC219, 0xC319, 0x0001}, /* +2 */
- {0xC22A, 0xC32A, 0x0001}, /* +4 */
- {0xC24C, 0xC34C, 0x0001}, /* +6 */
- {0xC26E, 0xC36E, 0x0001}, /* +8 */
- {0xC248, 0xC348, 0x0002}, /* +10 */
- {0xC26A, 0xC36A, 0x0002}, /* +12 dB */
-};
-
-static unsigned short treble_parm[12][9] = {
- {0x821E, 0xC26A, 0x031E, 0xC36A, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001}, /* -12 dB */
- {0x821E, 0xC25B, 0x031E, 0xC35B, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xC24C, 0x031E, 0xC34C, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xC23D, 0x031E, 0xC33D, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xC21F, 0x031E, 0xC31F, 0x021E, 0xD208, 0x831E, 0xD308, 0x0001},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021E, 0xD208, 0x831E, 0xD308, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021D, 0xD219, 0x831D, 0xD319, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021C, 0xD22A, 0x831C, 0xD32A, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x021A, 0xD24C, 0x831A, 0xD34C, 0x0002},
- {0x821E, 0xD208, 0x031E, 0xD308, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +8 (HW default) */
- {0x821D, 0xD219, 0x031D, 0xD319, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002},
- {0x821C, 0xD22A, 0x031C, 0xD32A, 0x0219, 0xD26E, 0x8319, 0xD36E, 0x0002}, /* +12 dB */
-};
-
-
-/*
- * set Emu8000 digital equalizer; from 0 to 11 [-12dB - 12dB]
- */
-static void
-awe_equalizer(int bass, int treble)
-{
- unsigned short w;
-
- if (bass < 0 || bass > 11 || treble < 0 || treble > 11)
- return;
- awe_poke(AWE_INIT4(0x01), bass_parm[bass][0]);
- awe_poke(AWE_INIT4(0x11), bass_parm[bass][1]);
- awe_poke(AWE_INIT3(0x11), treble_parm[treble][0]);
- awe_poke(AWE_INIT3(0x13), treble_parm[treble][1]);
- awe_poke(AWE_INIT3(0x1B), treble_parm[treble][2]);
- awe_poke(AWE_INIT4(0x07), treble_parm[treble][3]);
- awe_poke(AWE_INIT4(0x0B), treble_parm[treble][4]);
- awe_poke(AWE_INIT4(0x0D), treble_parm[treble][5]);
- awe_poke(AWE_INIT4(0x17), treble_parm[treble][6]);
- awe_poke(AWE_INIT4(0x19), treble_parm[treble][7]);
- w = bass_parm[bass][2] + treble_parm[treble][8];
- awe_poke(AWE_INIT4(0x15), (unsigned short)(w + 0x0262));
- awe_poke(AWE_INIT4(0x1D), (unsigned short)(w + 0x8362));
-}
-
-static void awe_update_equalizer(void)
-{
- awe_equalizer(ctrls[AWE_MD_BASS_LEVEL], ctrls[AWE_MD_TREBLE_LEVEL]);
-}
-
-
-/*----------------------------------------------------------------*/
-
-#ifdef CONFIG_AWE32_MIDIEMU
-
-/*
- * Emu8000 MIDI Emulation
- */
-
-/*
- * midi queue record
- */
-
-/* queue type */
-enum { Q_NONE, Q_VARLEN, Q_READ, Q_SYSEX, };
-
-#define MAX_MIDIBUF 64
-
-/* midi status */
-typedef struct MidiStatus {
- int queue; /* queue type */
- int qlen; /* queue length */
- int read; /* chars read */
- int status; /* current status */
- int chan; /* current channel */
- unsigned char buf[MAX_MIDIBUF];
-} MidiStatus;
-
-/* MIDI mode type */
-enum { MODE_GM, MODE_GS, MODE_XG, };
-
-/* NRPN / CC -> Emu8000 parameter converter */
-typedef struct {
- int control;
- int awe_effect;
- unsigned short (*convert)(int val);
-} ConvTable;
-
-
-/*
- * prototypes
- */
-
-static int awe_midi_open(int dev, int mode, void (*input)(int,unsigned char), void (*output)(int));
-static void awe_midi_close(int dev);
-static int awe_midi_ioctl(int dev, unsigned cmd, void __user * arg);
-static int awe_midi_outputc(int dev, unsigned char midi_byte);
-
-static void init_midi_status(MidiStatus *st);
-static void clear_rpn(void);
-static void get_midi_char(MidiStatus *st, int c);
-/*static void queue_varlen(MidiStatus *st, int c);*/
-static void special_event(MidiStatus *st, int c);
-static void queue_read(MidiStatus *st, int c);
-static void midi_note_on(MidiStatus *st);
-static void midi_note_off(MidiStatus *st);
-static void midi_key_pressure(MidiStatus *st);
-static void midi_channel_pressure(MidiStatus *st);
-static void midi_pitch_wheel(MidiStatus *st);
-static void midi_program_change(MidiStatus *st);
-static void midi_control_change(MidiStatus *st);
-static void midi_select_bank(MidiStatus *st, int val);
-static void midi_nrpn_event(MidiStatus *st);
-static void midi_rpn_event(MidiStatus *st);
-static void midi_detune(int chan, int coarse, int fine);
-static void midi_system_exclusive(MidiStatus *st);
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val);
-static int xg_control_change(MidiStatus *st, int cmd, int val);
-
-#define numberof(ary) (sizeof(ary)/sizeof(ary[0]))
-
-
-/*
- * OSS Midi device record
- */
-
-static struct midi_operations awe_midi_operations =
-{
- .owner = THIS_MODULE,
- .info = {"AWE Midi Emu", 0, 0, SNDCARD_SB},
- .in_info = {0},
- .open = awe_midi_open, /*open*/
- .close = awe_midi_close, /*close*/
- .ioctl = awe_midi_ioctl, /*ioctl*/
- .outputc = awe_midi_outputc, /*outputc*/
-};
-
-static int my_mididev = -1;
-
-static void __init attach_midiemu(void)
-{
- if ((my_mididev = sound_alloc_mididev()) < 0)
- printk ("Sound: Too many midi devices detected\n");
- else
- midi_devs[my_mididev] = &awe_midi_operations;
-}
-
-static void unload_midiemu(void)
-{
- if (my_mididev >= 0)
- sound_unload_mididev(my_mididev);
-}
-
-
-/*
- * open/close midi device
- */
-
-static int midi_opened = FALSE;
-
-static int midi_mode;
-static int coarsetune, finetune;
-
-static int xg_mapping = TRUE;
-static int xg_bankmode;
-
-/* effect sensitivity */
-
-#define FX_CUTOFF 0
-#define FX_RESONANCE 1
-#define FX_ATTACK 2
-#define FX_RELEASE 3
-#define FX_VIBRATE 4
-#define FX_VIBDEPTH 5
-#define FX_VIBDELAY 6
-#define FX_NUMS 7
-
-#define DEF_FX_CUTOFF 170
-#define DEF_FX_RESONANCE 6
-#define DEF_FX_ATTACK 50
-#define DEF_FX_RELEASE 50
-#define DEF_FX_VIBRATE 30
-#define DEF_FX_VIBDEPTH 4
-#define DEF_FX_VIBDELAY 1500
-
-/* effect sense: */
-static int gs_sense[] =
-{
- DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
- DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-static int xg_sense[] =
-{
- DEF_FX_CUTOFF, DEF_FX_RESONANCE, DEF_FX_ATTACK, DEF_FX_RELEASE,
- DEF_FX_VIBRATE, DEF_FX_VIBDEPTH, DEF_FX_VIBDELAY
-};
-
-
-/* current status */
-static MidiStatus curst;
-
-
-static int
-awe_midi_open (int dev, int mode,
- void (*input)(int,unsigned char),
- void (*output)(int))
-{
- if (midi_opened)
- return -EBUSY;
-
- midi_opened = TRUE;
-
- midi_mode = MODE_GM;
-
- curst.queue = Q_NONE;
- curst.qlen = 0;
- curst.read = 0;
- curst.status = 0;
- curst.chan = 0;
- memset(curst.buf, 0, sizeof(curst.buf));
-
- init_midi_status(&curst);
-
- return 0;
-}
-
-static void
-awe_midi_close (int dev)
-{
- midi_opened = FALSE;
-}
-
-
-static int
-awe_midi_ioctl (int dev, unsigned cmd, void __user *arg)
-{
- return -EPERM;
-}
-
-static int
-awe_midi_outputc (int dev, unsigned char midi_byte)
-{
- if (! midi_opened)
- return 1;
-
- /* force to change playing mode */
- playing_mode = AWE_PLAY_MULTI;
-
- get_midi_char(&curst, midi_byte);
- return 1;
-}
-
-
-/*
- * initialize
- */
-
-static void init_midi_status(MidiStatus *st)
-{
- clear_rpn();
- coarsetune = 0;
- finetune = 0;
-}
-
-
-/*
- * RPN & NRPN
- */
-
-#define MAX_MIDI_CHANNELS 16
-
-/* RPN & NRPN */
-static unsigned char nrpn[MAX_MIDI_CHANNELS]; /* current event is NRPN? */
-static int msb_bit; /* current event is msb for RPN/NRPN */
-/* RPN & NRPN indeces */
-static unsigned char rpn_msb[MAX_MIDI_CHANNELS], rpn_lsb[MAX_MIDI_CHANNELS];
-/* RPN & NRPN values */
-static int rpn_val[MAX_MIDI_CHANNELS];
-
-static void clear_rpn(void)
-{
- int i;
- for (i = 0; i < MAX_MIDI_CHANNELS; i++) {
- nrpn[i] = 0;
- rpn_msb[i] = 127;
- rpn_lsb[i] = 127;
- rpn_val[i] = 0;
- }
- msb_bit = 0;
-}
-
-
-/*
- * process midi queue
- */
-
-/* status event types */
-typedef void (*StatusEvent)(MidiStatus *st);
-static struct StatusEventList {
- StatusEvent process;
- int qlen;
-} status_event[8] = {
- {midi_note_off, 2},
- {midi_note_on, 2},
- {midi_key_pressure, 2},
- {midi_control_change, 2},
- {midi_program_change, 1},
- {midi_channel_pressure, 1},
- {midi_pitch_wheel, 2},
- {NULL, 0},
-};
-
-
-/* read a char from fifo and process it */
-static void get_midi_char(MidiStatus *st, int c)
-{
- if (c == 0xfe) {
- /* ignore active sense */
- st->queue = Q_NONE;
- return;
- }
-
- switch (st->queue) {
- /* case Q_VARLEN: queue_varlen(st, c); break;*/
- case Q_READ:
- case Q_SYSEX:
- queue_read(st, c);
- break;
- case Q_NONE:
- st->read = 0;
- if ((c & 0xf0) == 0xf0) {
- special_event(st, c);
- } else if (c & 0x80) { /* status change */
- st->status = (c >> 4) & 0x07;
- st->chan = c & 0x0f;
- st->queue = Q_READ;
- st->qlen = status_event[st->status].qlen;
- if (st->qlen == 0)
- st->queue = Q_NONE;
- }
- break;
- }
-}
-
-/* 0xfx events */
-static void special_event(MidiStatus *st, int c)
-{
- switch (c) {
- case 0xf0: /* system exclusive */
- st->queue = Q_SYSEX;
- st->qlen = 0;
- break;
- case 0xf1: /* MTC quarter frame */
- case 0xf3: /* song select */
- st->queue = Q_READ;
- st->qlen = 1;
- break;
- case 0xf2: /* song position */
- st->queue = Q_READ;
- st->qlen = 2;
- break;
- }
-}
-
-#if 0
-/* read variable length value */
-static void queue_varlen(MidiStatus *st, int c)
-{
- st->qlen += (c & 0x7f);
- if (c & 0x80) {
- st->qlen <<= 7;
- return;
- }
- if (st->qlen <= 0) {
- st->qlen = 0;
- st->queue = Q_NONE;
- }
- st->queue = Q_READ;
- st->read = 0;
-}
-#endif
-
-
-/* read a char */
-static void queue_read(MidiStatus *st, int c)
-{
- if (st->read < MAX_MIDIBUF) {
- if (st->queue != Q_SYSEX)
- c &= 0x7f;
- st->buf[st->read] = (unsigned char)c;
- }
- st->read++;
- if (st->queue == Q_SYSEX && c == 0xf7) {
- midi_system_exclusive(st);
- st->queue = Q_NONE;
- } else if (st->queue == Q_READ && st->read >= st->qlen) {
- if (status_event[st->status].process)
- status_event[st->status].process(st);
- st->queue = Q_NONE;
- }
-}
-
-
-/*
- * status events
- */
-
-/* note on */
-static void midi_note_on(MidiStatus *st)
-{
- DEBUG(2,printk("midi: note_on (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
- if (st->buf[1] == 0)
- midi_note_off(st);
- else
- awe_start_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* note off */
-static void midi_note_off(MidiStatus *st)
-{
- DEBUG(2,printk("midi: note_off (%d) %d %d\n", st->chan, st->buf[0], st->buf[1]));
- awe_kill_note(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* key pressure change */
-static void midi_key_pressure(MidiStatus *st)
-{
- awe_key_pressure(0, st->chan, st->buf[0], st->buf[1]);
-}
-
-/* channel pressure change */
-static void midi_channel_pressure(MidiStatus *st)
-{
- channels[st->chan].chan_press = st->buf[0];
- awe_modwheel_change(st->chan, st->buf[0]);
-}
-
-/* pitch wheel change */
-static void midi_pitch_wheel(MidiStatus *st)
-{
- int val = (int)st->buf[1] * 128 + st->buf[0];
- awe_bender(0, st->chan, val);
-}
-
-/* program change */
-static void midi_program_change(MidiStatus *st)
-{
- int preset;
- preset = st->buf[0];
- if (midi_mode == MODE_GS && IS_DRUM_CHANNEL(st->chan) && preset == 127)
- preset = 0;
- else if (midi_mode == MODE_XG && xg_mapping && IS_DRUM_CHANNEL(st->chan))
- preset += 64;
-
- awe_set_instr(0, st->chan, preset);
-}
-
-#define send_effect(chan,type,val) awe_send_effect(chan,-1,type,val)
-#define add_effect(chan,type,val) awe_send_effect(chan,-1,(type)|0x80,val)
-#define unset_effect(chan,type) awe_send_effect(chan,-1,(type)|0x40,0)
-
-/* midi control change */
-static void midi_control_change(MidiStatus *st)
-{
- int cmd = st->buf[0];
- int val = st->buf[1];
-
- DEBUG(2,printk("midi: control (%d) %d %d\n", st->chan, cmd, val));
- if (midi_mode == MODE_XG) {
- if (xg_control_change(st, cmd, val))
- return;
- }
-
- /* controls #31 - #64 are LSB of #0 - #31 */
- msb_bit = 1;
- if (cmd >= 0x20 && cmd < 0x40) {
- msb_bit = 0;
- cmd -= 0x20;
- }
-
- switch (cmd) {
- case CTL_SOFT_PEDAL:
- if (val == 127)
- add_effect(st->chan, AWE_FX_CUTOFF, -160);
- else
- unset_effect(st->chan, AWE_FX_CUTOFF);
- break;
-
- case CTL_BANK_SELECT:
- midi_select_bank(st, val);
- break;
-
- /* set RPN/NRPN parameter */
- case CTL_REGIST_PARM_NUM_MSB:
- nrpn[st->chan]=0; rpn_msb[st->chan]=val;
- break;
- case CTL_REGIST_PARM_NUM_LSB:
- nrpn[st->chan]=0; rpn_lsb[st->chan]=val;
- break;
- case CTL_NONREG_PARM_NUM_MSB:
- nrpn[st->chan]=1; rpn_msb[st->chan]=val;
- break;
- case CTL_NONREG_PARM_NUM_LSB:
- nrpn[st->chan]=1; rpn_lsb[st->chan]=val;
- break;
-
- /* send RPN/NRPN entry */
- case CTL_DATA_ENTRY:
- if (msb_bit)
- rpn_val[st->chan] = val * 128;
- else
- rpn_val[st->chan] |= val;
- if (nrpn[st->chan])
- midi_nrpn_event(st);
- else
- midi_rpn_event(st);
- break;
-
- /* increase/decrease data entry */
- case CTL_DATA_INCREMENT:
- rpn_val[st->chan]++;
- midi_rpn_event(st);
- break;
- case CTL_DATA_DECREMENT:
- rpn_val[st->chan]--;
- midi_rpn_event(st);
- break;
-
- /* default */
- default:
- awe_controller(0, st->chan, cmd, val);
- break;
- }
-}
-
-/* tone bank change */
-static void midi_select_bank(MidiStatus *st, int val)
-{
- if (midi_mode == MODE_XG && msb_bit) {
- xg_bankmode = val;
- /* XG MSB value; not normal bank selection */
- switch (val) {
- case 127: /* remap to drum channel */
- awe_controller(0, st->chan, CTL_BANK_SELECT, 128);
- break;
- default: /* remap to normal channel */
- awe_controller(0, st->chan, CTL_BANK_SELECT, val);
- break;
- }
- return;
- } else if (midi_mode == MODE_GS && !msb_bit)
- /* ignore LSB bank in GS mode (used for mapping) */
- return;
-
- /* normal bank controls; accept both MSB and LSB */
- if (! IS_DRUM_CHANNEL(st->chan)) {
- if (midi_mode == MODE_XG) {
- if (xg_bankmode) return;
- if (val == 64 || val == 126)
- val = 0;
- } else if (midi_mode == MODE_GS && val == 127)
- val = 0;
- awe_controller(0, st->chan, CTL_BANK_SELECT, val);
- }
-}
-
-
-/*
- * RPN events
- */
-
-static void midi_rpn_event(MidiStatus *st)
-{
- int type;
- type = (rpn_msb[st->chan]<<8) | rpn_lsb[st->chan];
- switch (type) {
- case 0x0000: /* Pitch bend sensitivity */
- /* MSB only / 1 semitone per 128 */
- if (msb_bit) {
- channels[st->chan].bender_range =
- rpn_val[st->chan] * 100 / 128;
- }
- break;
-
- case 0x0001: /* fine tuning: */
- /* MSB/LSB, 8192=center, 100/8192 cent step */
- finetune = rpn_val[st->chan] - 8192;
- midi_detune(st->chan, coarsetune, finetune);
- break;
-
- case 0x0002: /* coarse tuning */
- /* MSB only / 8192=center, 1 semitone per 128 */
- if (msb_bit) {
- coarsetune = rpn_val[st->chan] - 8192;
- midi_detune(st->chan, coarsetune, finetune);
- }
- break;
-
- case 0x7F7F: /* "lock-in" RPN */
- break;
- }
-}
-
-
-/* tuning:
- * coarse = -8192 to 8192 (100 cent per 128)
- * fine = -8192 to 8192 (max=100cent)
- */
-static void midi_detune(int chan, int coarse, int fine)
-{
- /* 4096 = 1200 cents in AWE parameter */
- int val;
- val = coarse * 4096 / (12 * 128);
- val += fine / 24;
- if (val)
- send_effect(chan, AWE_FX_INIT_PITCH, val);
- else
- unset_effect(chan, AWE_FX_INIT_PITCH);
-}
-
-
-/*
- * system exclusive message
- * GM/GS/XG macros are accepted
- */
-
-static void midi_system_exclusive(MidiStatus *st)
-{
- /* GM on */
- static unsigned char gm_on_macro[] = {
- 0x7e,0x7f,0x09,0x01,
- };
- /* XG on */
- static unsigned char xg_on_macro[] = {
- 0x43,0x10,0x4c,0x00,0x00,0x7e,0x00,
- };
- /* GS prefix
- * drum channel: XX=0x1?(channel), YY=0x15, ZZ=on/off
- * reverb mode: XX=0x01, YY=0x30, ZZ=0-7
- * chorus mode: XX=0x01, YY=0x38, ZZ=0-7
- */
- static unsigned char gs_pfx_macro[] = {
- 0x41,0x10,0x42,0x12,0x40,/*XX,YY,ZZ*/
- };
-
-#if 0
- /* SC88 system mode set
- * single module mode: XX=1
- * double module mode: XX=0
- */
- static unsigned char gs_mode_macro[] = {
- 0x41,0x10,0x42,0x12,0x00,0x00,0x7F,/*ZZ*/
- };
- /* SC88 display macro: XX=01:bitmap, 00:text
- */
- static unsigned char gs_disp_macro[] = {
- 0x41,0x10,0x45,0x12,0x10,/*XX,00*/
- };
-#endif
-
- /* GM on */
- if (memcmp(st->buf, gm_on_macro, sizeof(gm_on_macro)) == 0) {
- if (midi_mode != MODE_GS && midi_mode != MODE_XG)
- midi_mode = MODE_GM;
- init_midi_status(st);
- }
-
- /* GS macros */
- else if (memcmp(st->buf, gs_pfx_macro, sizeof(gs_pfx_macro)) == 0) {
- if (midi_mode != MODE_GS && midi_mode != MODE_XG)
- midi_mode = MODE_GS;
-
- if (st->buf[5] == 0x00 && st->buf[6] == 0x7f && st->buf[7] == 0x00) {
- /* GS reset */
- init_midi_status(st);
- }
-
- else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x15) {
- /* drum pattern */
- int p = st->buf[5] & 0x0f;
- if (p == 0) p = 9;
- else if (p < 10) p--;
- if (st->buf[7] == 0)
- DRUM_CHANNEL_OFF(p);
- else
- DRUM_CHANNEL_ON(p);
-
- } else if ((st->buf[5] & 0xf0) == 0x10 && st->buf[6] == 0x21) {
- /* program */
- int p = st->buf[5] & 0x0f;
- if (p == 0) p = 9;
- else if (p < 10) p--;
- if (! IS_DRUM_CHANNEL(p))
- awe_set_instr(0, p, st->buf[7]);
-
- } else if (st->buf[5] == 0x01 && st->buf[6] == 0x30) {
- /* reverb mode */
- awe_set_reverb_mode(st->buf[7]);
-
- } else if (st->buf[5] == 0x01 && st->buf[6] == 0x38) {
- /* chorus mode */
- awe_set_chorus_mode(st->buf[7]);
-
- } else if (st->buf[5] == 0x00 && st->buf[6] == 0x04) {
- /* master volume */
- awe_change_master_volume(st->buf[7]);
-
- }
- }
-
- /* XG on */
- else if (memcmp(st->buf, xg_on_macro, sizeof(xg_on_macro)) == 0) {
- midi_mode = MODE_XG;
- xg_mapping = TRUE;
- xg_bankmode = 0;
- }
-}
-
-
-/*----------------------------------------------------------------*/
-
-/*
- * convert NRPN/control values
- */
-
-static int send_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
- int i, cval;
- for (i = 0; i < num_tables; i++) {
- if (table[i].control == type) {
- cval = table[i].convert(val);
- send_effect(st->chan, table[i].awe_effect, cval);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static int add_converted_effect(ConvTable *table, int num_tables, MidiStatus *st, int type, int val)
-{
- int i, cval;
- for (i = 0; i < num_tables; i++) {
- if (table[i].control == type) {
- cval = table[i].convert(val);
- add_effect(st->chan, table[i].awe_effect|0x80, cval);
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-/*
- * AWE32 NRPN effects
- */
-
-static unsigned short fx_delay(int val);
-static unsigned short fx_attack(int val);
-static unsigned short fx_hold(int val);
-static unsigned short fx_decay(int val);
-static unsigned short fx_the_value(int val);
-static unsigned short fx_twice_value(int val);
-static unsigned short fx_conv_pitch(int val);
-static unsigned short fx_conv_Q(int val);
-
-/* function for each NRPN */ /* [range] units */
-#define fx_env1_delay fx_delay /* [0,5900] 4msec */
-#define fx_env1_attack fx_attack /* [0,5940] 1msec */
-#define fx_env1_hold fx_hold /* [0,8191] 1msec */
-#define fx_env1_decay fx_decay /* [0,5940] 4msec */
-#define fx_env1_release fx_decay /* [0,5940] 4msec */
-#define fx_env1_sustain fx_the_value /* [0,127] 0.75dB */
-#define fx_env1_pitch fx_the_value /* [-127,127] 9.375cents */
-#define fx_env1_cutoff fx_the_value /* [-127,127] 56.25cents */
-
-#define fx_env2_delay fx_delay /* [0,5900] 4msec */
-#define fx_env2_attack fx_attack /* [0,5940] 1msec */
-#define fx_env2_hold fx_hold /* [0,8191] 1msec */
-#define fx_env2_decay fx_decay /* [0,5940] 4msec */
-#define fx_env2_release fx_decay /* [0,5940] 4msec */
-#define fx_env2_sustain fx_the_value /* [0,127] 0.75dB */
-
-#define fx_lfo1_delay fx_delay /* [0,5900] 4msec */
-#define fx_lfo1_freq fx_twice_value /* [0,127] 84mHz */
-#define fx_lfo1_volume fx_twice_value /* [0,127] 0.1875dB */
-#define fx_lfo1_pitch fx_the_value /* [-127,127] 9.375cents */
-#define fx_lfo1_cutoff fx_twice_value /* [-64,63] 56.25cents */
-
-#define fx_lfo2_delay fx_delay /* [0,5900] 4msec */
-#define fx_lfo2_freq fx_twice_value /* [0,127] 84mHz */
-#define fx_lfo2_pitch fx_the_value /* [-127,127] 9.375cents */
-
-#define fx_init_pitch fx_conv_pitch /* [-8192,8192] cents */
-#define fx_chorus fx_the_value /* [0,255] -- */
-#define fx_reverb fx_the_value /* [0,255] -- */
-#define fx_cutoff fx_twice_value /* [0,127] 62Hz */
-#define fx_filterQ fx_conv_Q /* [0,127] -- */
-
-static unsigned short fx_delay(int val)
-{
- return (unsigned short)calc_parm_delay(val);
-}
-
-static unsigned short fx_attack(int val)
-{
- return (unsigned short)calc_parm_attack(val);
-}
-
-static unsigned short fx_hold(int val)
-{
- return (unsigned short)calc_parm_hold(val);
-}
-
-static unsigned short fx_decay(int val)
-{
- return (unsigned short)calc_parm_decay(val);
-}
-
-static unsigned short fx_the_value(int val)
-{
- return (unsigned short)(val & 0xff);
-}
-
-static unsigned short fx_twice_value(int val)
-{
- return (unsigned short)((val * 2) & 0xff);
-}
-
-static unsigned short fx_conv_pitch(int val)
-{
- return (short)(val * 4096 / 1200);
-}
-
-static unsigned short fx_conv_Q(int val)
-{
- return (unsigned short)((val / 8) & 0xff);
-}
-
-
-static ConvTable awe_effects[] =
-{
- { 0, AWE_FX_LFO1_DELAY, fx_lfo1_delay},
- { 1, AWE_FX_LFO1_FREQ, fx_lfo1_freq},
- { 2, AWE_FX_LFO2_DELAY, fx_lfo2_delay},
- { 3, AWE_FX_LFO2_FREQ, fx_lfo2_freq},
-
- { 4, AWE_FX_ENV1_DELAY, fx_env1_delay},
- { 5, AWE_FX_ENV1_ATTACK,fx_env1_attack},
- { 6, AWE_FX_ENV1_HOLD, fx_env1_hold},
- { 7, AWE_FX_ENV1_DECAY, fx_env1_decay},
- { 8, AWE_FX_ENV1_SUSTAIN, fx_env1_sustain},
- { 9, AWE_FX_ENV1_RELEASE, fx_env1_release},
-
- {10, AWE_FX_ENV2_DELAY, fx_env2_delay},
- {11, AWE_FX_ENV2_ATTACK, fx_env2_attack},
- {12, AWE_FX_ENV2_HOLD, fx_env2_hold},
- {13, AWE_FX_ENV2_DECAY, fx_env2_decay},
- {14, AWE_FX_ENV2_SUSTAIN, fx_env2_sustain},
- {15, AWE_FX_ENV2_RELEASE, fx_env2_release},
-
- {16, AWE_FX_INIT_PITCH, fx_init_pitch},
- {17, AWE_FX_LFO1_PITCH, fx_lfo1_pitch},
- {18, AWE_FX_LFO2_PITCH, fx_lfo2_pitch},
- {19, AWE_FX_ENV1_PITCH, fx_env1_pitch},
- {20, AWE_FX_LFO1_VOLUME, fx_lfo1_volume},
- {21, AWE_FX_CUTOFF, fx_cutoff},
- {22, AWE_FX_FILTERQ, fx_filterQ},
- {23, AWE_FX_LFO1_CUTOFF, fx_lfo1_cutoff},
- {24, AWE_FX_ENV1_CUTOFF, fx_env1_cutoff},
- {25, AWE_FX_CHORUS, fx_chorus},
- {26, AWE_FX_REVERB, fx_reverb},
-};
-
-static int num_awe_effects = numberof(awe_effects);
-
-
-/*
- * GS(SC88) NRPN effects; still experimental
- */
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short gs_cutoff(int val)
-{
- return (val - 64) * gs_sense[FX_CUTOFF] / 50;
-}
-
-/* resonance: 0 to 15(max) */
-static unsigned short gs_filterQ(int val)
-{
- return (val - 64) * gs_sense[FX_RESONANCE] / 50;
-}
-
-/* attack: */
-static unsigned short gs_attack(int val)
-{
- return -(val - 64) * gs_sense[FX_ATTACK] / 50;
-}
-
-/* decay: */
-static unsigned short gs_decay(int val)
-{
- return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* release: */
-static unsigned short gs_release(int val)
-{
- return -(val - 64) * gs_sense[FX_RELEASE] / 50;
-}
-
-/* vibrato freq: 0.042Hz step, max=255 */
-static unsigned short gs_vib_rate(int val)
-{
- return (val - 64) * gs_sense[FX_VIBRATE] / 50;
-}
-
-/* vibrato depth: max=127, 1 octave */
-static unsigned short gs_vib_depth(int val)
-{
- return (val - 64) * gs_sense[FX_VIBDEPTH] / 50;
-}
-
-/* vibrato delay: -0.725msec step */
-static unsigned short gs_vib_delay(int val)
-{
- return -(val - 64) * gs_sense[FX_VIBDELAY] / 50;
-}
-
-static ConvTable gs_effects[] =
-{
- {32, AWE_FX_CUTOFF, gs_cutoff},
- {33, AWE_FX_FILTERQ, gs_filterQ},
- {99, AWE_FX_ENV2_ATTACK, gs_attack},
- {100, AWE_FX_ENV2_DECAY, gs_decay},
- {102, AWE_FX_ENV2_RELEASE, gs_release},
- {8, AWE_FX_LFO1_FREQ, gs_vib_rate},
- {9, AWE_FX_LFO1_VOLUME, gs_vib_depth},
- {10, AWE_FX_LFO1_DELAY, gs_vib_delay},
-};
-
-static int num_gs_effects = numberof(gs_effects);
-
-
-/*
- * NRPN events: accept as AWE32/SC88 specific controls
- */
-
-static void midi_nrpn_event(MidiStatus *st)
-{
- if (rpn_msb[st->chan] == 127 && rpn_lsb[st->chan] <= 26) {
- if (! msb_bit) /* both MSB/LSB necessary */
- send_converted_effect(awe_effects, num_awe_effects,
- st, rpn_lsb[st->chan],
- rpn_val[st->chan] - 8192);
- } else if (rpn_msb[st->chan] == 1) {
- if (msb_bit) /* only MSB is valid */
- add_converted_effect(gs_effects, num_gs_effects,
- st, rpn_lsb[st->chan],
- rpn_val[st->chan] / 128);
- }
-}
-
-
-/*
- * XG control effects; still experimental
- */
-
-/* cutoff: quarter semitone step, max=255 */
-static unsigned short xg_cutoff(int val)
-{
- return (val - 64) * xg_sense[FX_CUTOFF] / 64;
-}
-
-/* resonance: 0(open) to 15(most nasal) */
-static unsigned short xg_filterQ(int val)
-{
- return (val - 64) * xg_sense[FX_RESONANCE] / 64;
-}
-
-/* attack: */
-static unsigned short xg_attack(int val)
-{
- return -(val - 64) * xg_sense[FX_ATTACK] / 64;
-}
-
-/* release: */
-static unsigned short xg_release(int val)
-{
- return -(val - 64) * xg_sense[FX_RELEASE] / 64;
-}
-
-static ConvTable xg_effects[] =
-{
- {71, AWE_FX_CUTOFF, xg_cutoff},
- {74, AWE_FX_FILTERQ, xg_filterQ},
- {72, AWE_FX_ENV2_RELEASE, xg_release},
- {73, AWE_FX_ENV2_ATTACK, xg_attack},
-};
-
-static int num_xg_effects = numberof(xg_effects);
-
-static int xg_control_change(MidiStatus *st, int cmd, int val)
-{
- return add_converted_effect(xg_effects, num_xg_effects, st, cmd, val);
-}
-
-#endif /* CONFIG_AWE32_MIDIEMU */
-
-
-/*----------------------------------------------------------------*/
-
-
-/*
- * initialization of AWE driver
- */
-
-static void
-awe_initialize(void)
-{
- DEBUG(0,printk("AWE32: initializing..\n"));
-
- /* initialize hardware configuration */
- awe_poke(AWE_HWCF1, 0x0059);
- awe_poke(AWE_HWCF2, 0x0020);
-
- /* disable audio; this seems to reduce a clicking noise a bit.. */
- awe_poke(AWE_HWCF3, 0);
-
- /* initialize audio channels */
- awe_init_audio();
-
- /* initialize DMA */
- awe_init_dma();
-
- /* initialize init array */
- awe_init_array();
-
- /* check DRAM memory size */
- awe_check_dram();
-
- /* initialize the FM section of the AWE32 */
- awe_init_fm();
-
- /* set up voice envelopes */
- awe_tweak();
-
- /* enable audio */
- awe_poke(AWE_HWCF3, 0x0004);
-
- /* set default values */
- awe_init_ctrl_parms(TRUE);
-
- /* set equalizer */
- awe_update_equalizer();
-
- /* set reverb & chorus modes */
- awe_update_reverb_mode();
- awe_update_chorus_mode();
-}
-
-
-/*
- * Core Device Management Functions
- */
-
-/* store values to i/o port array */
-static void setup_ports(int port1, int port2, int port3)
-{
- awe_ports[0] = port1;
- if (port2 == 0)
- port2 = port1 + 0x400;
- awe_ports[1] = port2;
- awe_ports[2] = port2 + 2;
- if (port3 == 0)
- port3 = port1 + 0x800;
- awe_ports[3] = port3;
- awe_ports[4] = port3 + 2;
-
- port_setuped = TRUE;
-}
-
-/*
- * port request
- * 0x620-623, 0xA20-A23, 0xE20-E23
- */
-
-static int
-awe_request_region(void)
-{
- if (! port_setuped)
- return 0;
- if (! request_region(awe_ports[0], 4, "sound driver (AWE32)"))
- return 0;
- if (! request_region(awe_ports[1], 4, "sound driver (AWE32)"))
- goto err_out;
- if (! request_region(awe_ports[3], 4, "sound driver (AWE32)"))
- goto err_out1;
- return 1;
-err_out1:
- release_region(awe_ports[1], 4);
-err_out:
- release_region(awe_ports[0], 4);
- return 0;
-}
-
-static void
-awe_release_region(void)
-{
- if (! port_setuped) return;
- release_region(awe_ports[0], 4);
- release_region(awe_ports[1], 4);
- release_region(awe_ports[3], 4);
-}
-
-static int awe_attach_device(void)
-{
- if (awe_present) return 0; /* for OSS38.. called twice? */
-
- /* reserve I/O ports for awedrv */
- if (! awe_request_region()) {
- printk(KERN_ERR "AWE32: I/O area already used.\n");
- return 0;
- }
-
- /* set buffers to NULL */
- sfhead = sftail = NULL;
-
- my_dev = sound_alloc_synthdev();
- if (my_dev == -1) {
- printk(KERN_ERR "AWE32 Error: too many synthesizers\n");
- awe_release_region();
- return 0;
- }
-
- voice_alloc = &awe_operations.alloc;
- voice_alloc->max_voice = awe_max_voices;
- synth_devs[my_dev] = &awe_operations;
-
-#ifdef CONFIG_AWE32_MIXER
- attach_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
- attach_midiemu();
-#endif
-
- /* clear all samples */
- awe_reset_samples();
-
- /* initialize AWE32 hardware */
- awe_initialize();
-
- sprintf(awe_info.name, "AWE32-%s (RAM%dk)",
- AWEDRV_VERSION, memsize/1024);
- printk(KERN_INFO "<SoundBlaster EMU8000 (RAM%dk)>\n", memsize/1024);
-
- awe_present = TRUE;
-
- return 1;
-}
-
-static void awe_dettach_device(void)
-{
- if (awe_present) {
- awe_reset_samples();
- awe_release_region();
- free_tables();
-#ifdef CONFIG_AWE32_MIXER
- unload_mixer();
-#endif
-#ifdef CONFIG_AWE32_MIDIEMU
- unload_midiemu();
-#endif
- sound_unload_synthdev(my_dev);
- awe_present = FALSE;
- }
-}
-
-
-/*
- * Legacy device Probing
- */
-
-/* detect emu8000 chip on the specified address; from VV's guide */
-
-static int __init
-awe_detect_base(int addr)
-{
- setup_ports(addr, 0, 0);
- if ((awe_peek(AWE_U1) & 0x000F) != 0x000C)
- return 0;
- if ((awe_peek(AWE_HWCF1) & 0x007E) != 0x0058)
- return 0;
- if ((awe_peek(AWE_HWCF2) & 0x0003) != 0x0003)
- return 0;
- DEBUG(0,printk("AWE32 found at %x\n", addr));
- return 1;
-}
-
-static int __init awe_detect_legacy_devices(void)
-{
- int base;
- for (base = 0x620; base <= 0x680; base += 0x20)
- if (awe_detect_base(base)) {
- awe_attach_device();
- return 1;
- }
- DEBUG(0,printk("AWE32 Legacy detection failed\n"));
- return 0;
-}
-
-
-/*
- * PnP device Probing
- */
-
-static struct pnp_device_id awe_pnp_ids[] = {
- {.id = "CTL0021", .driver_data = 0}, /* AWE32 WaveTable */
- {.id = "CTL0022", .driver_data = 0}, /* AWE64 WaveTable */
- {.id = "CTL0023", .driver_data = 0}, /* AWE64 Gold WaveTable */
- { } /* terminator */
-};
-
-MODULE_DEVICE_TABLE(pnp, awe_pnp_ids);
-
-static int awe_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
-{
- int io1, io2, io3;
-
- if (awe_present) {
- printk(KERN_ERR "AWE32: This driver only supports one AWE32 device, skipping.\n");
- }
-
- if (!pnp_port_valid(dev,0) ||
- !pnp_port_valid(dev,1) ||
- !pnp_port_valid(dev,2)) {
- printk(KERN_ERR "AWE32: The PnP device does not have the required resources.\n");
- return -EINVAL;
- }
- io1 = pnp_port_start(dev,0);
- io2 = pnp_port_start(dev,1);
- io3 = pnp_port_start(dev,2);
- printk(KERN_INFO "AWE32: A PnP Wave Table was detected at IO's %#x,%#x,%#x.\n",
- io1, io2, io3);
- setup_ports(io1, io2, io3);
-
- awe_attach_device();
- return 0;
-}
-
-static void awe_pnp_remove(struct pnp_dev *dev)
-{
- awe_dettach_device();
-}
-
-static struct pnp_driver awe_pnp_driver = {
- .name = "AWE32",
- .id_table = awe_pnp_ids,
- .probe = awe_pnp_probe,
- .remove = awe_pnp_remove,
-};
-
-static int __init awe_detect_pnp_devices(void)
-{
- int ret;
-
- ret = pnp_register_driver(&awe_pnp_driver);
- if (ret<0)
- printk(KERN_ERR "AWE32: PnP support is unavailable.\n");
- return ret;
-}
-
-
-/*
- * device / lowlevel (module) interface
- */
-
-static int __init
-awe_detect(void)
-{
- printk(KERN_INFO "AWE32: Probing for WaveTable...\n");
- if (isapnp) {
- if (awe_detect_pnp_devices()>=0)
- return 1;
- } else
- printk(KERN_INFO "AWE32: Skipping PnP detection.\n");
-
- if (awe_detect_legacy_devices())
- return 1;
-
- return 0;
-}
-
-static int __init attach_awe(void)
-{
- return awe_detect() ? 0 : -ENODEV;
-}
-
-static void __exit unload_awe(void)
-{
- pnp_unregister_driver(&awe_pnp_driver);
- awe_dettach_device();
-}
-
-
-module_init(attach_awe);
-module_exit(unload_awe);
-
-#ifndef MODULE
-static int __init setup_awe(char *str)
-{
- /* io, memsize, isapnp */
- int ints[4];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- memsize = ints[2];
- isapnp = ints[3];
-
- return 1;
-}
-
-__setup("awe=", setup_awe);
-#endif
diff --git a/sound/oss/awe_wave.h b/sound/oss/awe_wave.h
deleted file mode 100644
index a3aa018118bd..000000000000
--- a/sound/oss/awe_wave.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * sound/awe_config.h
- *
- * Configuration of AWE32/SB32/AWE64 wave table synth driver.
- * version 0.4.4; Jan. 4, 2000
- *
- * Copyright (C) 1996-1998 Takashi Iwai
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * chorus & reverb effects send for FM chip: from 0 to 0xff
- * larger numbers often cause weird sounds.
- */
-
-#define DEF_FM_CHORUS_DEPTH 0x10
-#define DEF_FM_REVERB_DEPTH 0x10
-
-
-/*
- * other compile conditions
- */
-
-/* initialize FM passthrough even without extended RAM */
-#undef AWE_ALWAYS_INIT_FM
-
-/* debug on */
-#define AWE_DEBUG_ON
-
-/* GUS compatible mode */
-#define AWE_HAS_GUS_COMPATIBILITY
-
-/* add MIDI emulation by wavetable */
-#define CONFIG_AWE32_MIDIEMU
-
-/* add mixer control of emu8000 equalizer */
-#undef CONFIG_AWE32_MIXER
-
-/* use new volume calculation method as default */
-#define AWE_USE_NEW_VOLUME_CALC
-
-/* check current volume target for searching empty voices */
-#define AWE_CHECK_VTARGET
-
-/* allow sample sharing */
-#define AWE_ALLOW_SAMPLE_SHARING
-
-/*
- * AWE32 card configuration:
- * uncomment the following lines *ONLY* when auto detection doesn't
- * work properly on your machine.
- */
-
-/*#define AWE_DEFAULT_BASE_ADDR 0x620*/ /* base port address */
-/*#define AWE_DEFAULT_MEM_SIZE 512*/ /* kbytes */
-
-/*
- * AWE driver version number
- */
-#define AWE_MAJOR_VERSION 0
-#define AWE_MINOR_VERSION 4
-#define AWE_TINY_VERSION 4
-#define AWE_VERSION_NUMBER ((AWE_MAJOR_VERSION<<16)|(AWE_MINOR_VERSION<<8)|AWE_TINY_VERSION)
-#define AWEDRV_VERSION "0.4.4"
diff --git a/sound/oss/btaudio.c b/sound/oss/btaudio.c
index 324a81fd3a3b..6ad384114239 100644
--- a/sound/oss/btaudio.c
+++ b/sound/oss/btaudio.c
@@ -824,7 +824,7 @@ static char *irq_name[] = { "", "", "", "OFLOW", "", "", "", "", "", "", "",
"RISCI", "FBUS", "FTRGT", "FDSR", "PPERR",
"RIPERR", "PABORT", "OCERR", "SCERR" };
-static irqreturn_t btaudio_irq(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t btaudio_irq(int irq, void *dev_id)
{
int count = 0;
u32 stat,astat;
diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
deleted file mode 100644
index ea51aafaf401..000000000000
--- a/sound/oss/cmpci.c
+++ /dev/null
@@ -1,3381 +0,0 @@
-/*
- * cmpci.c -- C-Media PCI audio driver.
- *
- * Copyright (C) 1999 C-media support (support@cmedia.com.tw)
- *
- * Based on the PCI drivers by Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * For update, visit:
- * http://www.cmedia.com.tw
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Special thanks to David C. Niemi, Jan Pfeifer
- *
- *
- * Module command line parameters:
- * none so far
- *
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * The card has both an FM and a Wavetable synth, but I have to figure
- * out first how to drive them...
- *
- * Revision history
- * 06.05.98 0.1 Initial release
- * 10.05.98 0.2 Fixed many bugs, esp. ADC rate calculation
- * First stab at a simple midi interface (no bells&whistles)
- * 13.05.98 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
- * set_dac_rate in the FMODE_WRITE case in cm_open
- * Fix hwptr out of bounds (now mpg123 works)
- * 14.05.98 0.4 Don't allow excessive interrupt rates
- * 08.06.98 0.5 First release using Alan Cox' soundcore instead of miscdevice
- * 03.08.98 0.6 Do not include modversions.h
- * Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * 31.08.98 0.7 Fix realplayer problems - dac.count issues
- * 10.12.98 0.8 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.98 0.9 Fix a few f_file & FMODE_ bugs
- * 06.01.99 0.10 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.99 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.99 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 18.08.99 1.5 Only deallocate DMA buffer when unloading.
- * 02.09.99 1.6 Enable SPDIF LOOP
- * Change the mixer read back
- * 21.09.99 2.33 Use RCS version as driver version.
- * Add support for modem, S/PDIF loop and 4 channels.
- * (8738 only)
- * Fix bug cause x11amp cannot play.
- *
- * Fixes:
- * Arnaldo Carvalho de Melo <acme@conectiva.com.br>
- * 18/05/2001 - .bss nitpicks, fix a bug in set_dac_channels where it
- * was calling prog_dmabuf with s->lock held, call missing
- * unlock_kernel in cm_midi_release
- * 08/10/2001 - use set_current_state in some more places
- *
- * Carlos Eduardo Gorges <carlos@techlinux.com.br>
- * Fri May 25 2001
- * - SMP support ( spin[un]lock* revision )
- * - speaker mixer support
- * Mon Aug 13 2001
- * - optimizations and cleanups
- *
- * 03/01/2003 - open_mode fixes from Georg Acher <acher@in.tum.de>
- * Simon Braunschmidt <brasimon@web.de>
- * Sat Jan 31 2004
- * - provide support for opl3 FM by releasing IO range after initialization
- *
- * ChenLi Tien <cltien@cmedia.com.tw>
- * Mar 9 2004
- * - Fix S/PDIF out if spdif_loop enabled
- * - Load opl3 driver if enabled (fmio in proper range)
- * - Load mpu401 if enabled (mpuio in proper range)
- * Apr 5 2004
- * - Fix DUAL_DAC dma synchronization bug
- * - Check exist FM/MPU401 I/O before activate.
- * - Add AFTM_S16_BE format support, so MPlayer/Xine can play AC3/mutlichannel
- * on Mac
- * - Change to support kernel 2.6 so only small patch needed
- * - All parameters default to 0
- * - Add spdif_out to send PCM through S/PDIF out jack
- * - Add hw_copy to get 4-spaker output for general PCM/analog output
- *
- * Stefan Thater <stefan.thaeter@gmx.de>
- * Apr 5 2004
- * - Fix mute single channel for CD/Line-in/AUX-in
- */
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SOUND_CMPCI_MIDI
-#include "sound_config.h"
-#include "mpu401.h"
-#endif
-#ifdef CONFIG_SOUND_CMPCI_FM
-#include "opl3.h"
-#endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-#include <linux/gameport.h>
-#include <linux/mutex.h>
-
-#endif
-
-/* --------------------------------------------------------------------- */
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#undef DMABYTEIO
-#define DBG(x) {}
-/* --------------------------------------------------------------------- */
-
-#define CM_MAGIC ((PCI_VENDOR_ID_CMEDIA<<16)|PCI_DEVICE_ID_CMEDIA_CM8338A)
-
-/* CM8338 registers definition ****************/
-
-#define CODEC_CMI_FUNCTRL0 (0x00)
-#define CODEC_CMI_FUNCTRL1 (0x04)
-#define CODEC_CMI_CHFORMAT (0x08)
-#define CODEC_CMI_INT_HLDCLR (0x0C)
-#define CODEC_CMI_INT_STATUS (0x10)
-#define CODEC_CMI_LEGACY_CTRL (0x14)
-#define CODEC_CMI_MISC_CTRL (0x18)
-#define CODEC_CMI_TDMA_POS (0x1C)
-#define CODEC_CMI_MIXER (0x20)
-#define CODEC_SB16_DATA (0x22)
-#define CODEC_SB16_ADDR (0x23)
-#define CODEC_CMI_MIXER1 (0x24)
-#define CODEC_CMI_MIXER2 (0x25)
-#define CODEC_CMI_AUX_VOL (0x26)
-#define CODEC_CMI_MISC (0x27)
-#define CODEC_CMI_AC97 (0x28)
-
-#define CODEC_CMI_CH0_FRAME1 (0x80)
-#define CODEC_CMI_CH0_FRAME2 (0x84)
-#define CODEC_CMI_CH1_FRAME1 (0x88)
-#define CODEC_CMI_CH1_FRAME2 (0x8C)
-
-#define CODEC_CMI_SPDIF_CTRL (0x90)
-#define CODEC_CMI_MISC_CTRL2 (0x92)
-
-#define CODEC_CMI_EXT_REG (0xF0)
-
-/* Mixer registers for SB16 ******************/
-
-#define DSP_MIX_DATARESETIDX ((unsigned char)(0x00))
-
-#define DSP_MIX_MASTERVOLIDX_L ((unsigned char)(0x30))
-#define DSP_MIX_MASTERVOLIDX_R ((unsigned char)(0x31))
-#define DSP_MIX_VOICEVOLIDX_L ((unsigned char)(0x32))
-#define DSP_MIX_VOICEVOLIDX_R ((unsigned char)(0x33))
-#define DSP_MIX_FMVOLIDX_L ((unsigned char)(0x34))
-#define DSP_MIX_FMVOLIDX_R ((unsigned char)(0x35))
-#define DSP_MIX_CDVOLIDX_L ((unsigned char)(0x36))
-#define DSP_MIX_CDVOLIDX_R ((unsigned char)(0x37))
-#define DSP_MIX_LINEVOLIDX_L ((unsigned char)(0x38))
-#define DSP_MIX_LINEVOLIDX_R ((unsigned char)(0x39))
-
-#define DSP_MIX_MICVOLIDX ((unsigned char)(0x3A))
-#define DSP_MIX_SPKRVOLIDX ((unsigned char)(0x3B))
-
-#define DSP_MIX_OUTMIXIDX ((unsigned char)(0x3C))
-
-#define DSP_MIX_ADCMIXIDX_L ((unsigned char)(0x3D))
-#define DSP_MIX_ADCMIXIDX_R ((unsigned char)(0x3E))
-
-#define DSP_MIX_INGAINIDX_L ((unsigned char)(0x3F))
-#define DSP_MIX_INGAINIDX_R ((unsigned char)(0x40))
-#define DSP_MIX_OUTGAINIDX_L ((unsigned char)(0x41))
-#define DSP_MIX_OUTGAINIDX_R ((unsigned char)(0x42))
-
-#define DSP_MIX_AGCIDX ((unsigned char)(0x43))
-
-#define DSP_MIX_TREBLEIDX_L ((unsigned char)(0x44))
-#define DSP_MIX_TREBLEIDX_R ((unsigned char)(0x45))
-#define DSP_MIX_BASSIDX_L ((unsigned char)(0x46))
-#define DSP_MIX_BASSIDX_R ((unsigned char)(0x47))
-#define DSP_MIX_EXTENSION ((unsigned char)(0xf0))
-// pseudo register for AUX
-#define DSP_MIX_AUXVOL_L ((unsigned char)(0x50))
-#define DSP_MIX_AUXVOL_R ((unsigned char)(0x51))
-
-// I/O length
-#define CM_EXTENT_CODEC 0x100
-#define CM_EXTENT_MIDI 0x2
-#define CM_EXTENT_SYNTH 0x4
-#define CM_EXTENT_GAME 0x8
-
-// Function Control Register 0 (00h)
-#define CHADC0 0x01
-#define CHADC1 0x02
-#define PAUSE0 0x04
-#define PAUSE1 0x08
-
-// Function Control Register 0+2 (02h)
-#define CHEN0 0x01
-#define CHEN1 0x02
-#define RST_CH0 0x04
-#define RST_CH1 0x08
-
-// Function Control Register 1 (04h)
-#define JYSTK_EN 0x02
-#define UART_EN 0x04
-#define SPDO2DAC 0x40
-#define SPDFLOOP 0x80
-
-// Function Control Register 1+1 (05h)
-#define SPDF_0 0x01
-#define SPDF_1 0x02
-#define ASFC 0x1c
-#define DSFC 0xe0
-#define SPDIF2DAC (SPDF_1 << 8 | SPDO2DAC)
-
-// Channel Format Register (08h)
-#define CM_CFMT_STEREO 0x01
-#define CM_CFMT_16BIT 0x02
-#define CM_CFMT_MASK 0x03
-#define POLVALID 0x20
-#define INVSPDIFI 0x80
-
-// Channel Format Register+2 (0ah)
-#define SPD24SEL 0x20
-
-// Channel Format Register+3 (0bh)
-#define CHB3D 0x20
-#define CHB3D5C 0x80
-
-// Interrupt Hold/Clear Register+2 (0eh)
-#define CH0_INT_EN 0x01
-#define CH1_INT_EN 0x02
-
-// Interrupt Register (10h)
-#define CHINT0 0x01
-#define CHINT1 0x02
-#define CH0BUSY 0x04
-#define CH1BUSY 0x08
-
-// Legacy Control/Status Register+1 (15h)
-#define EXBASEN 0x10
-#define BASE2LIN 0x20
-#define CENTR2LIN 0x40
-#define CB2LIN (BASE2LIN | CENTR2LIN)
-#define CHB3D6C 0x80
-
-// Legacy Control/Status Register+2 (16h)
-#define DAC2SPDO 0x20
-#define SPDCOPYRHT 0x40
-#define ENSPDOUT 0x80
-
-// Legacy Control/Status Register+3 (17h)
-#define FMSEL 0x03
-#define VSBSEL 0x0c
-#define VMPU 0x60
-#define NXCHG 0x80
-
-// Miscellaneous Control Register (18h)
-#define REAR2LIN 0x20
-#define MUTECH1 0x40
-#define ENCENTER 0x80
-
-// Miscellaneous Control Register+1 (19h)
-#define SELSPDIFI2 0x01
-#define SPDF_AC97 0x80
-
-// Miscellaneous Control Register+2 (1ah)
-#define AC3_EN 0x04
-#define FM_EN 0x08
-#define SPD32SEL 0x20
-#define XCHGDAC 0x40
-#define ENDBDAC 0x80
-
-// Miscellaneous Control Register+3 (1bh)
-#define SPDIFI48K 0x01
-#define SPDO5V 0x02
-#define N4SPK3D 0x04
-#define RESET 0x40
-#define PWD 0x80
-#define SPDIF48K (SPDIFI48K << 24 | SPDF_AC97 << 8)
-
-// Mixer1 (24h)
-#define CDPLAY 0x01
-#define X3DEN 0x02
-#define REAR2FRONT 0x10
-#define SPK4 0x20
-#define WSMUTE 0x40
-#define FMMUTE 0x80
-
-// Miscellaneous Register (27h)
-#define SPDVALID 0x02
-#define CENTR2MIC 0x04
-
-// Miscellaneous Register2 (92h)
-#define SPD32KFMT 0x10
-
-#define CM_CFMT_DACSHIFT 2
-#define CM_CFMT_ADCSHIFT 0
-#define CM_FREQ_DACSHIFT 5
-#define CM_FREQ_ADCSHIFT 2
-#define RSTDAC RST_CH1
-#define RSTADC RST_CH0
-#define ENDAC CHEN1
-#define ENADC CHEN0
-#define PAUSEDAC PAUSE1
-#define PAUSEADC PAUSE0
-#define CODEC_CMI_ADC_FRAME1 CODEC_CMI_CH0_FRAME1
-#define CODEC_CMI_ADC_FRAME2 CODEC_CMI_CH0_FRAME2
-#define CODEC_CMI_DAC_FRAME1 CODEC_CMI_CH1_FRAME1
-#define CODEC_CMI_DAC_FRAME2 CODEC_CMI_CH1_FRAME2
-#define DACINT CHINT1
-#define ADCINT CHINT0
-#define DACBUSY CH1BUSY
-#define ADCBUSY CH0BUSY
-#define ENDACINT CH1_INT_EN
-#define ENADCINT CH0_INT_EN
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-#define SND_DEV_DSP16 5
-
-#define NR_DEVICE 3 /* maximum number of devices */
-
-#define set_dac1_rate set_adc_rate
-#define set_dac1_rate_unlocked set_adc_rate_unlocked
-#define stop_dac1 stop_adc
-#define stop_dac1_unlocked stop_adc_unlocked
-#define get_dmadac1 get_dmaadc
-
-static unsigned int devindex = 0;
-
-//*********************************************/
-
-struct cm_state {
- /* magic */
- unsigned int magic;
-
- /* list of cmedia devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- int dev_audio; /* soundcore stuff */
- int dev_mixer;
-
- unsigned int iosb, iobase, iosynth,
- iomidi, iogame, irq; /* hardware resources */
- unsigned short deviceid; /* pci_id */
-
- struct { /* mixer stuff */
- unsigned int modcnt;
- unsigned short vol[13];
- } mix;
-
- unsigned int rateadc, ratedac; /* wave stuff */
- unsigned char fmt, enable;
-
- spinlock_t lock;
- struct mutex open_mutex;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
-
- unsigned fragsize; /* redundant, but makes calculations easier */
- unsigned dmasize;
- unsigned fragsamples;
- unsigned dmasamples;
-
- unsigned mapped:1; /* OSS stuff */
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned enabled:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- int midi_devc;
- struct address_info mpu_data;
-#endif
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
- struct gameport *gameport;
-#endif
-
- int chip_version;
- int max_channels;
- int curr_channels;
- int capability; /* HW capability, various for chip versions */
-
- int status; /* HW or SW state */
-
- int spdif_counter; /* spdif frame counter */
-};
-
-/* flags used for capability */
-#define CAN_AC3_HW 0x00000001 /* 037 or later */
-#define CAN_AC3_SW 0x00000002 /* 033 or later */
-#define CAN_AC3 (CAN_AC3_HW | CAN_AC3_SW)
-#define CAN_DUAL_DAC 0x00000004 /* 033 or later */
-#define CAN_MULTI_CH_HW 0x00000008 /* 039 or later */
-#define CAN_MULTI_CH (CAN_MULTI_CH_HW | CAN_DUAL_DAC)
-#define CAN_LINE_AS_REAR 0x00000010 /* 033 or later */
-#define CAN_LINE_AS_BASS 0x00000020 /* 039 or later */
-#define CAN_MIC_AS_BASS 0x00000040 /* 039 or later */
-
-/* flags used for status */
-#define DO_AC3_HW 0x00000001
-#define DO_AC3_SW 0x00000002
-#define DO_AC3 (DO_AC3_HW | DO_AC3_SW)
-#define DO_DUAL_DAC 0x00000004
-#define DO_MULTI_CH_HW 0x00000008
-#define DO_MULTI_CH (DO_MULTI_CH_HW | DO_DUAL_DAC)
-#define DO_LINE_AS_REAR 0x00000010 /* 033 or later */
-#define DO_LINE_AS_BASS 0x00000020 /* 039 or later */
-#define DO_MIC_AS_BASS 0x00000040 /* 039 or later */
-#define DO_SPDIF_OUT 0x00000100
-#define DO_SPDIF_IN 0x00000200
-#define DO_SPDIF_LOOP 0x00000400
-#define DO_BIGENDIAN_W 0x00001000 /* used in PowerPC */
-#define DO_BIGENDIAN_R 0x00002000 /* used in PowerPC */
-
-static LIST_HEAD(devs);
-
-static int mpuio;
-static int fmio;
-static int joystick;
-static int spdif_inverse;
-static int spdif_loop;
-static int spdif_out;
-static int use_line_as_rear;
-static int use_line_as_bass;
-static int use_mic_as_bass;
-static int mic_boost;
-static int hw_copy;
-module_param(mpuio, int, 0);
-module_param(fmio, int, 0);
-module_param(joystick, bool, 0);
-module_param(spdif_inverse, bool, 0);
-module_param(spdif_loop, bool, 0);
-module_param(spdif_out, bool, 0);
-module_param(use_line_as_rear, bool, 0);
-module_param(use_line_as_bass, bool, 0);
-module_param(use_mic_as_bass, bool, 0);
-module_param(mic_boost, bool, 0);
-module_param(hw_copy, bool, 0);
-MODULE_PARM_DESC(mpuio, "(0x330, 0x320, 0x310, 0x300) Base of MPU-401, 0 to disable");
-MODULE_PARM_DESC(fmio, "(0x388, 0x3C8, 0x3E0) Base of OPL3, 0 to disable");
-MODULE_PARM_DESC(joystick, "(1/0) Enable joystick interface, still need joystick driver");
-MODULE_PARM_DESC(spdif_inverse, "(1/0) Invert S/PDIF-in signal");
-MODULE_PARM_DESC(spdif_loop, "(1/0) Route S/PDIF-in to S/PDIF-out directly");
-MODULE_PARM_DESC(spdif_out, "(1/0) Send PCM to S/PDIF-out (PCM volume will not function)");
-MODULE_PARM_DESC(use_line_as_rear, "(1/0) Use line-in jack as rear-out");
-MODULE_PARM_DESC(use_line_as_bass, "(1/0) Use line-in jack as bass/center");
-MODULE_PARM_DESC(use_mic_as_bass, "(1/0) Use mic-in jack as bass/center");
-MODULE_PARM_DESC(mic_boost, "(1/0) Enable microphone boost");
-MODULE_PARM_DESC(hw_copy, "Copy front channel to surround channel");
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned exp=16,l=5,r=0;
- static const unsigned num[]={0x2,0x4,0x10,0x100,0x10000};
-
- /* num: 2, 4, 16, 256, 65536 */
- /* exp: 1, 2, 4, 8, 16 */
-
- while(l--) {
- if( x >= num[l] ) {
- if(num[l]>2) x >>= exp;
- r+=exp;
- }
- exp>>=1;
- }
-
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void maskb(unsigned int addr, unsigned int mask, unsigned int value)
-{
- outb((inb(addr) & mask) | value, addr);
-}
-
-static void maskw(unsigned int addr, unsigned int mask, unsigned int value)
-{
- outw((inw(addr) & mask) | value, addr);
-}
-
-static void maskl(unsigned int addr, unsigned int mask, unsigned int value)
-{
- outl((inl(addr) & mask) | value, addr);
-}
-
-static void set_dmadac1(struct cm_state *s, unsigned int addr, unsigned int count)
-{
- if (addr)
- outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC0, 0);
-}
-
-static void set_dmaadc(struct cm_state *s, unsigned int addr, unsigned int count)
-{
- outl(addr, s->iobase + CODEC_CMI_ADC_FRAME1);
- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2);
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, CHADC0);
-}
-
-static void set_dmadac(struct cm_state *s, unsigned int addr, unsigned int count)
-{
- outl(addr, s->iobase + CODEC_CMI_DAC_FRAME1);
- outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2);
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, 0);
- if (s->status & DO_DUAL_DAC)
- set_dmadac1(s, 0, count);
-}
-
-static void set_countadc(struct cm_state *s, unsigned count)
-{
- outw(count - 1, s->iobase + CODEC_CMI_ADC_FRAME2 + 2);
-}
-
-static void set_countdac(struct cm_state *s, unsigned count)
-{
- outw(count - 1, s->iobase + CODEC_CMI_DAC_FRAME2 + 2);
- if (s->status & DO_DUAL_DAC)
- set_countadc(s, count);
-}
-
-static unsigned get_dmadac(struct cm_state *s)
-{
- unsigned int curr_addr;
-
- curr_addr = inw(s->iobase + CODEC_CMI_DAC_FRAME2) + 1;
- curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
- curr_addr = s->dma_dac.dmasize - curr_addr;
-
- return curr_addr;
-}
-
-static unsigned get_dmaadc(struct cm_state *s)
-{
- unsigned int curr_addr;
-
- curr_addr = inw(s->iobase + CODEC_CMI_ADC_FRAME2) + 1;
- curr_addr <<= sample_shift[(s->fmt >> CM_CFMT_ADCSHIFT) & CM_CFMT_MASK];
- curr_addr = s->dma_adc.dmasize - curr_addr;
-
- return curr_addr;
-}
-
-static void wrmixer(struct cm_state *s, unsigned char idx, unsigned char data)
-{
- unsigned char regval, pseudo;
-
- // pseudo register
- if (idx == DSP_MIX_AUXVOL_L) {
- data >>= 4;
- data &= 0x0f;
- regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0x0f;
- outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
- return;
- }
- if (idx == DSP_MIX_AUXVOL_R) {
- data &= 0xf0;
- regval = inb(s->iobase + CODEC_CMI_AUX_VOL) & ~0xf0;
- outb(regval | data, s->iobase + CODEC_CMI_AUX_VOL);
- return;
- }
- outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
- // pseudo bits
- if (idx == DSP_MIX_OUTMIXIDX) {
- pseudo = data & ~0x1f;
- pseudo >>= 1;
- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x30;
- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
- }
- if (idx == DSP_MIX_ADCMIXIDX_L) {
- pseudo = data & 0x80;
- pseudo >>= 1;
- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x40;
- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
- }
- if (idx == DSP_MIX_ADCMIXIDX_R) {
- pseudo = data & 0x80;
- regval = inb(s->iobase + CODEC_CMI_MIXER2) & ~0x80;
- outb(regval | pseudo, s->iobase + CODEC_CMI_MIXER2);
- }
- outb(data, s->iobase + CODEC_SB16_DATA);
- udelay(10);
-}
-
-static unsigned char rdmixer(struct cm_state *s, unsigned char idx)
-{
- unsigned char v, pseudo;
-
- // pseudo register
- if (idx == DSP_MIX_AUXVOL_L) {
- v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0x0f;
- v <<= 4;
- return v;
- }
- if (idx == DSP_MIX_AUXVOL_L) {
- v = inb(s->iobase + CODEC_CMI_AUX_VOL) & 0xf0;
- return v;
- }
- outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
- v = inb(s->iobase + CODEC_SB16_DATA);
- udelay(10);
- // pseudo bits
- if (idx == DSP_MIX_OUTMIXIDX) {
- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x30;
- pseudo <<= 1;
- v |= pseudo;
- }
- if (idx == DSP_MIX_ADCMIXIDX_L) {
- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x40;
- pseudo <<= 1;
- v |= pseudo;
- }
- if (idx == DSP_MIX_ADCMIXIDX_R) {
- pseudo = inb(s->iobase + CODEC_CMI_MIXER2) & 0x80;
- v |= pseudo;
- }
- return v;
-}
-
-static void set_fmt_unlocked(struct cm_state *s, unsigned char mask, unsigned char data)
-{
- if (mask && s->chip_version > 0) { /* 8338 cannot keep this */
- s->fmt = inb(s->iobase + CODEC_CMI_CHFORMAT);
- udelay(10);
- }
- s->fmt = (s->fmt & mask) | data;
- outb(s->fmt, s->iobase + CODEC_CMI_CHFORMAT);
- udelay(10);
-}
-
-static void set_fmt(struct cm_state *s, unsigned char mask, unsigned char data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_fmt_unlocked(s,mask,data);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void frobindir(struct cm_state *s, unsigned char idx, unsigned char mask, unsigned char data)
-{
- outb(idx, s->iobase + CODEC_SB16_ADDR);
- udelay(10);
- outb((inb(s->iobase + CODEC_SB16_DATA) & mask) | data, s->iobase + CODEC_SB16_DATA);
- udelay(10);
-}
-
-static struct {
- unsigned rate;
- unsigned lower;
- unsigned upper;
- unsigned char freq;
-} rate_lookup[] =
-{
- { 5512, (0 + 5512) / 2, (5512 + 8000) / 2, 0 },
- { 8000, (5512 + 8000) / 2, (8000 + 11025) / 2, 4 },
- { 11025, (8000 + 11025) / 2, (11025 + 16000) / 2, 1 },
- { 16000, (11025 + 16000) / 2, (16000 + 22050) / 2, 5 },
- { 22050, (16000 + 22050) / 2, (22050 + 32000) / 2, 2 },
- { 32000, (22050 + 32000) / 2, (32000 + 44100) / 2, 6 },
- { 44100, (32000 + 44100) / 2, (44100 + 48000) / 2, 3 },
- { 48000, (44100 + 48000) / 2, 48000, 7 }
-};
-
-static void set_spdif_copyright(struct cm_state *s, int spdif_copyright)
-{
- /* enable SPDIF-in Copyright */
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~SPDCOPYRHT, spdif_copyright ? SPDCOPYRHT : 0);
-}
-
-static void set_spdif_loop(struct cm_state *s, int spdif_loop)
-{
- /* enable SPDIF loop */
- if (spdif_loop) {
- s->status |= DO_SPDIF_LOOP;
- /* turn on spdif-in to spdif-out */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, SPDFLOOP);
- } else {
- s->status &= ~DO_SPDIF_LOOP;
- /* turn off spdif-in to spdif-out */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDFLOOP, 0);
- }
-}
-
-static void set_spdif_monitor(struct cm_state *s, int channel)
-{
- // SPDO2DAC
- maskw(s->iobase + CODEC_CMI_FUNCTRL1, ~SPDO2DAC, channel == 2 ? SPDO2DAC : 0);
- // CDPLAY
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, channel ? CDPLAY : 0);
-}
-
-static void set_spdifout_level(struct cm_state *s, int level5v)
-{
- /* SPDO5V */
- if (s->chip_version > 0)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~SPDO5V, level5v ? SPDO5V : 0);
-}
-
-static void set_spdifin_inverse(struct cm_state *s, int spdif_inverse)
-{
- if (s->chip_version == 0) /* 8338 has not this feature */
- return;
- if (spdif_inverse) {
- /* turn on spdif-in inverse */
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_CHFORMAT, ~0, INVSPDIFI);
- else
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 1);
- } else {
- /* turn off spdif-ininverse */
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_CHFORMAT, ~INVSPDIFI, 0);
- else
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~1, 0);
- }
-}
-
-static void set_spdifin_channel2(struct cm_state *s, int channel2)
-{
- /* SELSPDIFI2 */
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 1, ~SELSPDIFI2, channel2 ? SELSPDIFI2 : 0);
-}
-
-static void set_spdifin_valid(struct cm_state *s, int valid)
-{
- /* SPDVALID */
- maskb(s->iobase + CODEC_CMI_MISC, ~SPDVALID, valid ? SPDVALID : 0);
-}
-
-static void set_spdifout_unlocked(struct cm_state *s, unsigned rate)
-{
- if (rate != 48000 && rate != 44100)
- rate = 0;
- if (rate == 48000 || rate == 44100) {
- set_spdif_loop(s, 0);
- // SPDF_1
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
- // SPDIFI48K SPDF_AC97
- maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
- if (s->chip_version >= 55)
- // SPD32KFMT
- maskb(s->iobase + CODEC_CMI_MISC_CTRL2, ~SPD32KFMT, rate == 48000 ? SPD32KFMT : 0);
- if (s->chip_version > 0)
- // ENSPDOUT
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~0, ENSPDOUT);
- // monitor SPDIF out
- set_spdif_monitor(s, 2);
- s->status |= DO_SPDIF_OUT;
- } else {
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 2, ~ENSPDOUT, 0);
- // monitor none
- set_spdif_monitor(s, 0);
- s->status &= ~DO_SPDIF_OUT;
- }
-}
-
-static void set_spdifout(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_spdifout_unlocked(s,rate);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void set_spdifin_unlocked(struct cm_state *s, unsigned rate)
-{
- if (rate == 48000 || rate == 44100) {
- // SPDF_1
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~0, SPDF_1);
- // SPDIFI48K SPDF_AC97
- maskl(s->iobase + CODEC_CMI_MISC_CTRL, ~SPDIF48K, rate == 48000 ? SPDIF48K : 0);
- s->status |= DO_SPDIF_IN;
- } else {
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~SPDF_1, 0);
- s->status &= ~DO_SPDIF_IN;
- }
-}
-
-static void set_spdifin(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_spdifin_unlocked(s,rate);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* find parity for bit 4~30 */
-static unsigned parity(unsigned data)
-{
- unsigned parity = 0;
- int counter = 4;
-
- data >>= 4; // start from bit 4
- while (counter <= 30) {
- if (data & 1)
- parity++;
- data >>= 1;
- counter++;
- }
- return parity & 1;
-}
-
-static void set_ac3_unlocked(struct cm_state *s, unsigned rate)
-{
- if (!(s->capability & CAN_AC3))
- return;
- /* enable AC3 */
- if (rate && rate != 44100)
- rate = 48000;
- if (rate == 48000 || rate == 44100) {
- // mute DAC
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, WSMUTE);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~0, MUTECH1);
- // AC3EN for 039, 0x04
- if (s->chip_version >= 39) {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, AC3_EN);
- if (s->chip_version == 55)
- maskb(s->iobase + CODEC_CMI_SPDIF_CTRL, ~2, 0);
- // AC3EN for 037, 0x10
- } else if (s->chip_version == 37)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x10);
- if (s->capability & CAN_AC3_HW) {
- // SPD24SEL for 039, 0x20, but cannot be set
- if (s->chip_version == 39)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, SPD24SEL);
- // SPD24SEL for 037, 0x02
- else if (s->chip_version == 37)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~0, 0x02);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MIXER1, ~CDPLAY, 0);
-
- s->status |= DO_AC3_HW;
- } else {
- // SPD32SEL for 037 & 039
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, SPD32SEL);
- // set 176K sample rate to fix 033 HW bug
- if (s->chip_version == 33) {
- if (rate == 48000)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0, 0x08);
- else
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
- }
- s->status |= DO_AC3_SW;
- }
- } else {
- maskb(s->iobase + CODEC_CMI_MIXER1, ~WSMUTE, 0);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~MUTECH1, 0);
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 2, ~(SPD24SEL|0x12), 0);
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~(SPD32SEL|AC3_EN), 0);
- if (s->chip_version == 33)
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 1, ~0x08, 0);
- if (s->chip_version >= 39)
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, CDPLAY);
- s->status &= ~DO_AC3;
- }
- s->spdif_counter = 0;
-}
-
-static void set_line_as_rear(struct cm_state *s, int use_line_as_rear)
-{
- if (!(s->capability & CAN_LINE_AS_REAR))
- return;
- if (use_line_as_rear) {
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, SPK4);
- s->status |= DO_LINE_AS_REAR;
- } else {
- maskb(s->iobase + CODEC_CMI_MIXER1, ~SPK4, 0);
- s->status &= ~DO_LINE_AS_REAR;
- }
-}
-
-static void set_line_as_bass(struct cm_state *s, int use_line_as_bass)
-{
- if (!(s->capability & CAN_LINE_AS_BASS))
- return;
- if (use_line_as_bass) {
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~0, CB2LIN);
- s->status |= DO_LINE_AS_BASS;
- } else {
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CB2LIN, 0);
- s->status &= ~DO_LINE_AS_BASS;
- }
-}
-
-static void set_mic_as_bass(struct cm_state *s, int use_mic_as_bass)
-{
- if (!(s->capability & CAN_MIC_AS_BASS))
- return;
- if (use_mic_as_bass) {
- maskb(s->iobase + CODEC_CMI_MISC, ~0, 0x04);
- s->status |= DO_MIC_AS_BASS;
- } else {
- maskb(s->iobase + CODEC_CMI_MISC, ~0x04, 0);
- s->status &= ~DO_MIC_AS_BASS;
- }
-}
-
-static void set_hw_copy(struct cm_state *s, int hw_copy)
-{
- if (s->max_channels > 2 && hw_copy)
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~0, N4SPK3D);
- else
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 3, ~N4SPK3D, 0);
-}
-
-static void set_ac3(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- set_spdifout_unlocked(s, rate);
- set_ac3_unlocked(s, rate);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int trans_ac3(struct cm_state *s, void *dest, const char __user *source, int size)
-{
- int i = size / 2;
- unsigned long data;
- unsigned short data16;
- unsigned long *dst = (unsigned long *) dest;
- unsigned short __user *src = (unsigned short __user *)source;
- int err;
-
- do {
- if ((err = __get_user(data16, src++)))
- return err;
- data = (unsigned long)le16_to_cpu(data16);
- data <<= 12; // ok for 16-bit data
- if (s->spdif_counter == 2 || s->spdif_counter == 3)
- data |= 0x40000000; // indicate AC-3 raw data
- if (parity(data))
- data |= 0x80000000; // parity
- if (s->spdif_counter == 0)
- data |= 3; // preamble 'M'
- else if (s->spdif_counter & 1)
- data |= 5; // odd, 'W'
- else
- data |= 9; // even, 'M'
- *dst++ = cpu_to_le32(data);
- s->spdif_counter++;
- if (s->spdif_counter == 384)
- s->spdif_counter = 0;
- } while (--i);
-
- return 0;
-}
-
-static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate)
-{
- unsigned char freq = 4;
- int i;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
- rate = rate_lookup[i].rate;
- freq = rate_lookup[i].freq;
- break;
- }
- }
- s->rateadc = rate;
- freq <<= CM_FREQ_ADCSHIFT;
-
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
-}
-
-static void set_adc_rate(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned char freq = 4;
- int i;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
- rate = rate_lookup[i].rate;
- freq = rate_lookup[i].freq;
- break;
- }
- }
- s->rateadc = rate;
- freq <<= CM_FREQ_ADCSHIFT;
-
- spin_lock_irqsave(&s->lock, flags);
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~ASFC, freq);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void set_dac_rate(struct cm_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned char freq = 4;
- int i;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
- for (i = 0; i < sizeof(rate_lookup) / sizeof(rate_lookup[0]); i++) {
- if (rate > rate_lookup[i].lower && rate <= rate_lookup[i].upper) {
- rate = rate_lookup[i].rate;
- freq = rate_lookup[i].freq;
- break;
- }
- }
- s->ratedac = rate;
- freq <<= CM_FREQ_DACSHIFT;
-
- spin_lock_irqsave(&s->lock, flags);
- maskb(s->iobase + CODEC_CMI_FUNCTRL1 + 1, ~DSFC, freq);
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (s->curr_channels <= 2 && spdif_out)
- set_spdifout(s, rate);
- if (s->status & DO_DUAL_DAC)
- set_dac1_rate(s, rate);
-}
-
-/* --------------------------------------------------------------------- */
-static inline void reset_adc(struct cm_state *s)
-{
- /* reset bus master */
- outb(s->enable | RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- udelay(10);
- outb(s->enable & ~RSTADC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
-}
-
-static inline void reset_dac(struct cm_state *s)
-{
- /* reset bus master */
- outb(s->enable | RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- udelay(10);
- outb(s->enable & ~RSTDAC, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- if (s->status & DO_DUAL_DAC)
- reset_adc(s);
-}
-
-static inline void pause_adc(struct cm_state *s)
-{
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEADC);
-}
-
-static inline void pause_dac(struct cm_state *s)
-{
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~0, PAUSEDAC);
- if (s->status & DO_DUAL_DAC)
- pause_adc(s);
-}
-
-static inline void disable_adc(struct cm_state *s)
-{
- /* disable channel */
- s->enable &= ~ENADC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- reset_adc(s);
-}
-
-static inline void disable_dac(struct cm_state *s)
-{
- /* disable channel */
- s->enable &= ~ENDAC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- reset_dac(s);
- if (s->status & DO_DUAL_DAC)
- disable_adc(s);
-}
-
-static inline void enable_adc(struct cm_state *s)
-{
- if (!(s->enable & ENADC)) {
- /* enable channel */
- s->enable |= ENADC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- }
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEADC, 0);
-}
-
-static inline void enable_dac_unlocked(struct cm_state *s)
-{
- if (!(s->enable & ENDAC)) {
- /* enable channel */
- s->enable |= ENDAC;
- outb(s->enable, s->iobase + CODEC_CMI_FUNCTRL0 + 2);
- }
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~PAUSEDAC, 0);
-
- if (s->status & DO_DUAL_DAC)
- enable_adc(s);
-}
-
-static inline void stop_adc_unlocked(struct cm_state *s)
-{
- if (s->enable & ENADC) {
- /* disable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENADCINT, 0);
- disable_adc(s);
- }
-}
-
-static inline void stop_adc(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- stop_adc_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-
-}
-
-static inline void stop_dac_unlocked(struct cm_state *s)
-{
- if (s->enable & ENDAC) {
- /* disable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~ENDACINT, 0);
- disable_dac(s);
- }
- if (s->status & DO_DUAL_DAC)
- stop_dac1_unlocked(s);
-}
-
-static inline void stop_dac(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- stop_dac_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void start_adc_unlocked(struct cm_state *s)
-{
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- /* enable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
- enable_adc(s);
- }
-}
-
-static void start_adc(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- start_adc_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac1_unlocked(struct cm_state *s)
-{
- if ((s->dma_adc.mapped || s->dma_adc.count > 0) && s->dma_adc.ready) {
- /* enable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENADCINT);
- enable_dac_unlocked(s);
- }
-}
-
-static void start_dac_unlocked(struct cm_state *s)
-{
- if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
- /* enable interrupt */
- maskb(s->iobase + CODEC_CMI_INT_HLDCLR + 2, ~0, ENDACINT);
- enable_dac_unlocked(s);
- }
- if (s->status & DO_DUAL_DAC)
- start_dac1_unlocked(s);
-}
-
-static void start_dac(struct cm_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- start_dac_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static int prog_dmabuf(struct cm_state *s, unsigned rec);
-
-static int set_dac_channels(struct cm_state *s, int channels)
-{
- unsigned long flags;
- static unsigned int fmmute = 0;
-
- spin_lock_irqsave(&s->lock, flags);
-
- if ((channels > 2) && (channels <= s->max_channels)
- && (((s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK) == (CM_CFMT_STEREO | CM_CFMT_16BIT))) {
- set_spdifout_unlocked(s, 0);
- if (s->capability & CAN_MULTI_CH_HW) {
- // NXCHG
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0, NXCHG);
- // CHB3D or CHB3D5C
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), channels > 4 ? CHB3D5C : CHB3D);
- // CHB3D6C
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, channels == 6 ? CHB3D6C : 0);
- // ENCENTER
- maskb(s->iobase + CODEC_CMI_MISC_CTRL, ~ENCENTER, channels == 6 ? ENCENTER : 0);
- s->status |= DO_MULTI_CH_HW;
- } else if (s->capability & CAN_DUAL_DAC) {
- unsigned char fmtm = ~0, fmts = 0;
- ssize_t ret;
-
- // ENDBDAC, turn on double DAC mode
- // XCHGDAC, CH0 -> back, CH1->front
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, ENDBDAC|XCHGDAC);
- // mute FM
- fmmute = inb(s->iobase + CODEC_CMI_MIXER1) & FMMUTE;
- maskb(s->iobase + CODEC_CMI_MIXER1, ~0, FMMUTE);
- s->status |= DO_DUAL_DAC;
- // prepare secondary buffer
- spin_unlock_irqrestore(&s->lock, flags);
- ret = prog_dmabuf(s, 1);
- if (ret) return ret;
- spin_lock_irqsave(&s->lock, flags);
-
- // copy the hw state
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
- // the HW only support 16-bit stereo
- fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
- fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
- fmts |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- fmts |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
-
- set_fmt_unlocked(s, fmtm, fmts);
- set_adc_rate_unlocked(s, s->ratedac);
- }
- // disable 4 speaker mode (analog duplicate)
- set_hw_copy(s, 0);
- s->curr_channels = channels;
-
- // enable jack redirect
- set_line_as_rear(s, use_line_as_rear);
- if (channels > 4) {
- set_line_as_bass(s, use_line_as_bass);
- set_mic_as_bass(s, use_mic_as_bass);
- }
- } else {
- if (s->status & DO_MULTI_CH_HW) {
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~NXCHG, 0);
- maskb(s->iobase + CODEC_CMI_CHFORMAT + 3, ~(CHB3D5C|CHB3D), 0);
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 1, ~CHB3D6C, 0);
- } else if (s->status & DO_DUAL_DAC) {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~ENDBDAC, 0);
- maskb(s->iobase + CODEC_CMI_MIXER1, ~FMMUTE, fmmute);
- }
- // enable 4 speaker mode (analog duplicate)
- set_hw_copy(s, hw_copy);
- s->status &= ~DO_MULTI_CH;
- s->curr_channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
- // disable jack redirect
- set_line_as_rear(s, hw_copy ? use_line_as_rear : 0);
- set_line_as_bass(s, 0);
- set_mic_as_bass(s, 0);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return s->curr_channels;
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (16-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static void dealloc_dmabuf(struct cm_state *s, struct dmabuf *db)
-{
- struct page *pstart, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
- ClearPageReserved(pstart);
- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
- }
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-/* Ch1 is used for playback, Ch0 is used for recording */
-
-static int prog_dmabuf(struct cm_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- int order;
- unsigned bytepersec;
- unsigned bufs;
- struct page *pstart, *pend;
- unsigned char fmt;
- unsigned long flags;
-
- fmt = s->fmt;
- if (rec) {
- stop_adc(s);
- fmt >>= CM_CFMT_ADCSHIFT;
- } else {
- stop_dac(s);
- fmt >>= CM_CFMT_DACSHIFT;
- }
-
- fmt &= CM_CFMT_MASK;
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
- break;
- if (!db->rawbuf || !db->dmaaddr)
- return -ENOMEM;
- db->buforder = order;
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (pstart = virt_to_page(db->rawbuf); pstart <= pend; pstart++)
- SetPageReserved(pstart);
- }
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- /* to make fragsize >= 4096 */
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
- db->dmasamples = db->dmasize >> sample_shift[fmt];
- memset(db->rawbuf, (fmt & CM_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
- spin_lock_irqsave(&s->lock, flags);
- if (rec) {
- if (s->status & DO_DUAL_DAC)
- set_dmadac1(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
- else
- set_dmaadc(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
- /* program sample counts */
- set_countdac(s, db->fragsamples);
- } else {
- set_dmadac(s, db->dmaaddr, db->dmasize >> sample_shift[fmt]);
- /* program sample counts */
- set_countdac(s, db->fragsamples);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- db->enabled = 1;
- db->ready = 1;
- return 0;
-}
-
-static inline void clear_advance(struct cm_state *s)
-{
- unsigned char c = (s->fmt & (CM_CFMT_16BIT << CM_CFMT_DACSHIFT)) ? 0 : 0x80;
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned char *buf1 = s->dma_adc.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- if (s->status & DO_DUAL_DAC)
- memset(buf1 + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
- if (s->status & DO_DUAL_DAC)
- memset(buf1 + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void cm_update_ptr(struct cm_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- if (s->status & DO_DUAL_DAC) {
- /* the dac part will finish for this */
- } else {
- hwptr = get_dmaadc(s) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- if (!s->dma_adc.mapped) {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- pause_adc(s);
- s->dma_adc.error++;
- }
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = get_dmadac(s) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- }
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- wake_up(&s->dma_dac.wait);
- } else {
- s->dma_dac.count -= diff;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.count -= diff;
- if (s->dma_dac.count <= 0) {
- pause_dac(s);
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
- wake_up(&s->dma_dac.wait);
- }
- }
-}
-
-static irqreturn_t cm_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct cm_state *s = (struct cm_state *)dev_id;
- unsigned int intsrc, intstat;
- unsigned char mask = 0;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inl(s->iobase + CODEC_CMI_INT_STATUS);
- if (!(intsrc & 0x80000000))
- return IRQ_NONE;
- spin_lock(&s->lock);
- intstat = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- /* acknowledge interrupt */
- if (intsrc & ADCINT)
- mask |= ENADCINT;
- if (intsrc & DACINT)
- mask |= ENDACINT;
- outb(intstat & ~mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- outb(intstat | mask, s->iobase + CODEC_CMI_INT_HLDCLR + 2);
- cm_update_ptr(s);
- spin_unlock(&s->lock);
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- if (intsrc & 0x00010000) { // UART interrupt
- if (s->midi_devc && intchk_mpu401((void *)s->midi_devc))
- mpuintr(irq, (void *)s->midi_devc, regs);
- else
- inb(s->iomidi);// dummy read
- }
-#endif
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "cmpci: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != CM_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-#define MT_4 1
-#define MT_5MUTE 2
-#define MT_4MUTEMONO 3
-#define MT_6MUTE 4
-#define MT_5MUTEMONO 5
-
-static const struct {
- unsigned left;
- unsigned right;
- unsigned type;
- unsigned rec;
- unsigned play;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_CD] = { DSP_MIX_CDVOLIDX_L, DSP_MIX_CDVOLIDX_R, MT_5MUTE, 0x04, 0x06 },
- [SOUND_MIXER_LINE] = { DSP_MIX_LINEVOLIDX_L, DSP_MIX_LINEVOLIDX_R, MT_5MUTE, 0x10, 0x18 },
- [SOUND_MIXER_MIC] = { DSP_MIX_MICVOLIDX, DSP_MIX_MICVOLIDX, MT_5MUTEMONO, 0x01, 0x01 },
- [SOUND_MIXER_SYNTH] = { DSP_MIX_FMVOLIDX_L, DSP_MIX_FMVOLIDX_R, MT_5MUTE, 0x40, 0x00 },
- [SOUND_MIXER_VOLUME] = { DSP_MIX_MASTERVOLIDX_L, DSP_MIX_MASTERVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
- [SOUND_MIXER_PCM] = { DSP_MIX_VOICEVOLIDX_L, DSP_MIX_VOICEVOLIDX_R, MT_5MUTE, 0x00, 0x00 },
- [SOUND_MIXER_LINE1] = { DSP_MIX_AUXVOL_L, DSP_MIX_AUXVOL_R, MT_5MUTE, 0x80, 0x60 },
- [SOUND_MIXER_SPEAKER]= { DSP_MIX_SPKRVOLIDX, DSP_MIX_SPKRVOLIDX, MT_5MUTEMONO, 0x00, 0x01 }
-};
-
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
-{
- [SOUND_MIXER_CD] = 1,
- [SOUND_MIXER_LINE] = 2,
- [SOUND_MIXER_MIC] = 3,
- [SOUND_MIXER_SYNTH] = 4,
- [SOUND_MIXER_VOLUME] = 5,
- [SOUND_MIXER_PCM] = 6,
- [SOUND_MIXER_LINE1] = 7,
- [SOUND_MIXER_SPEAKER]= 8
-};
-
-static unsigned mixer_outmask(struct cm_state *s)
-{
- unsigned long flags;
- int i, j, k;
-
- spin_lock_irqsave(&s->lock, flags);
- j = rdmixer(s, DSP_MIX_OUTMIXIDX);
- spin_unlock_irqrestore(&s->lock, flags);
- for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (j & mixtable[i].play)
- k |= 1 << i;
- return k;
-}
-
-static unsigned mixer_recmask(struct cm_state *s)
-{
- unsigned long flags;
- int i, j, k;
-
- spin_lock_irqsave(&s->lock, flags);
- j = rdmixer(s, DSP_MIX_ADCMIXIDX_L);
- spin_unlock_irqrestore(&s->lock, flags);
- for (k = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (j & mixtable[i].rec)
- k |= 1 << i;
- return k;
-}
-
-static int mixer_ioctl(struct cm_state *s, unsigned int cmd, unsigned long arg)
-{
- unsigned long flags;
- int i, val, j;
- unsigned char l, r, rl, rr;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, "cmpci", sizeof(info.id));
- strlcpy(info.name, "C-Media PCI", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, "cmpci", sizeof(info.id));
- strlcpy(info.name, "C-Media cmpci", sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- val = mixer_recmask(s);
- return put_user(val, p);
-
- case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
- val = mixer_outmask(s);
- return put_user(val, p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].rec)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_OUTMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].play)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(0, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
- if (!volidx[i])
- return -EINVAL;
- return put_user(s->mix.vol[volidx[i]-1], p);
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- i = hweight32(val);
- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (!mixtable[i].rec) {
- val &= ~(1 << i);
- continue;
- }
- j |= mixtable[i].rec;
- }
- spin_lock_irqsave(&s->lock, flags);
- wrmixer(s, DSP_MIX_ADCMIXIDX_L, j);
- wrmixer(s, DSP_MIX_ADCMIXIDX_R, (j & 1) | (j>>1) | (j & 0x80));
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- case SOUND_MIXER_OUTSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (!mixtable[i].play) {
- val &= ~(1 << i);
- continue;
- }
- j |= mixtable[i].play;
- }
- spin_lock_irqsave(&s->lock, flags);
- wrmixer(s, DSP_MIX_OUTMIXIDX, j);
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- r = (val >> 8) & 0xff;
- if (l > 100)
- l = 100;
- if (r > 100)
- r = 100;
- spin_lock_irqsave(&s->lock, flags);
- switch (mixtable[i].type) {
- case MT_4:
- if (l >= 10)
- l -= 10;
- if (r >= 10)
- r -= 10;
- frobindir(s, mixtable[i].left, 0xf0, l / 6);
- frobindir(s, mixtable[i].right, 0xf0, l / 6);
- break;
-
- case MT_4MUTEMONO:
- rl = (l < 4 ? 0 : (l - 5) / 3) & 31;
- rr = (rl >> 2) & 7;
- wrmixer(s, mixtable[i].left, rl<<3);
- if (i == SOUND_MIXER_MIC)
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
- break;
-
- case MT_5MUTEMONO:
- rl = l < 4 ? 0 : (l - 5) / 3;
- wrmixer(s, mixtable[i].left, rl<<3);
- l = rdmixer(s, DSP_MIX_OUTMIXIDX) & ~mixtable[i].play;
- r = rl ? mixtable[i].play : 0;
- wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
- /* for recording */
- if (i == SOUND_MIXER_MIC) {
- if (s->chip_version >= 37) {
- rr = rl >> 1;
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, (rr&0x07)<<1);
- frobindir(s, DSP_MIX_EXTENSION, ~0x01, rr>>3);
- } else {
- rr = rl >> 2;
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0x0e, rr<<1);
- }
- }
- break;
-
- case MT_5MUTE:
- rl = l < 4 ? 0 : (l - 5) / 3;
- rr = r < 4 ? 0 : (r - 5) / 3;
- wrmixer(s, mixtable[i].left, rl<<3);
- wrmixer(s, mixtable[i].right, rr<<3);
- l = rdmixer(s, DSP_MIX_OUTMIXIDX);
- l &= ~mixtable[i].play;
- r = (rl|rr) ? mixtable[i].play : 0;
- wrmixer(s, DSP_MIX_OUTMIXIDX, l | r);
- break;
-
- case MT_6MUTE:
- if (l < 6)
- rl = 0x00;
- else
- rl = l * 2 / 3;
- if (r < 6)
- rr = 0x00;
- else
- rr = r * 2 / 3;
- wrmixer(s, mixtable[i].left, rl);
- wrmixer(s, mixtable[i].right, rr);
- break;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (!volidx[i])
- return -EINVAL;
- s->mix.vol[volidx[i]-1] = val;
- return put_user(s->mix.vol[volidx[i]-1], p);
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int cm_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- struct cm_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct cm_state, devs);
- if (s->dev_mixer == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int cm_release_mixdev(struct inode *inode, struct file *file)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int cm_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct cm_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations cm_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = cm_ioctl_mixdev,
- .open = cm_open_mixdev,
- .release = cm_release_mixdev,
-};
-
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct cm_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> CM_CFMT_DACSHIFT) & CM_CFMT_MASK];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "cmpci: dma timed out??\n");)
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t cm_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- add_wait_queue(&s->dma_adc.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_adc.enabled)
- start_adc(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "cmpci: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- spin_lock_irqsave(&s->lock, flags);
- stop_adc_unlocked(s);
- set_dmaadc(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
- /* program sample counts */
- set_countadc(s, s->dma_adc.fragsamples);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- continue;
- }
- if (s->status & DO_BIGENDIAN_R) {
- int i, err;
- unsigned char *src;
- char __user *dst = buffer;
- unsigned char data[2];
-
- src = (unsigned char *) (s->dma_adc.rawbuf + swptr);
- // copy left/right sample at one time
- for (i = 0; i < cnt / 2; i++) {
- data[0] = src[1];
- data[1] = src[0];
- if ((err = __put_user(data[0], dst++))) {
- ret = err;
- goto out;
- }
- if ((err = __put_user(data[1], dst++))) {
- ret = err;
- goto out;
- }
- src += 2;
- }
- } else if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_adc.enabled)
- start_adc_unlocked(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
-out:
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t cm_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- if (s->status & DO_DUAL_DAC) {
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- }
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- add_wait_queue(&s->dma_dac.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.swptr = s->dma_dac.swptr;
- s->dma_adc.count = s->dma_dac.count;
- s->dma_adc.endcleared = s->dma_dac.endcleared;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize-swptr;
- if (s->status & DO_AC3_SW) {
- if (s->dma_dac.count + 2 * cnt > s->dma_dac.dmasize)
- cnt = (s->dma_dac.dmasize - s->dma_dac.count) / 2;
- } else {
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
- }
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if ((s->status & DO_DUAL_DAC) && (cnt > count / 2))
- cnt = count / 2;
- if (cnt <= 0) {
- if (s->dma_dac.enabled)
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "cmpci: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- spin_lock_irqsave(&s->lock, flags);
- stop_dac_unlocked(s);
- set_dmadac(s, s->dma_dac.dmaaddr, s->dma_dac.dmasamples);
- /* program sample counts */
- set_countdac(s, s->dma_dac.fragsamples);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- if (s->status & DO_DUAL_DAC) {
- set_dmadac1(s, s->dma_adc.dmaaddr, s->dma_adc.dmasamples);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- continue;
- }
- if (s->status & DO_AC3_SW) {
- int err;
-
- // clip exceeded data, caught by 033 and 037
- if (swptr + 2 * cnt > s->dma_dac.dmasize)
- cnt = (s->dma_dac.dmasize - swptr) / 2;
- if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) {
- ret = err;
- goto out;
- }
- swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize;
- } else if ((s->status & DO_DUAL_DAC) && (s->status & DO_BIGENDIAN_W)) {
- int i, err;
- const char __user *src = buffer;
- unsigned char *dst0, *dst1;
- unsigned char data[8];
-
- dst0 = (unsigned char *) (s->dma_dac.rawbuf + swptr);
- dst1 = (unsigned char *) (s->dma_adc.rawbuf + swptr);
- // copy left/right sample at one time
- for (i = 0; i < cnt / 4; i++) {
- if ((err = __get_user(data[0], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[1], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[2], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[3], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[4], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[5], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[6], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[7], src++))) {
- ret = err;
- goto out;
- }
- dst0[0] = data[1];
- dst0[1] = data[0];
- dst0[2] = data[3];
- dst0[3] = data[2];
- dst1[0] = data[5];
- dst1[1] = data[4];
- dst1[2] = data[7];
- dst1[3] = data[6];
- dst0 += 4;
- dst1 += 4;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- } else if (s->status & DO_DUAL_DAC) {
- int i, err;
- unsigned long __user *src = (unsigned long __user *) buffer;
- unsigned long *dst0, *dst1;
-
- dst0 = (unsigned long *) (s->dma_dac.rawbuf + swptr);
- dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr);
- // copy left/right sample at one time
- for (i = 0; i < cnt / 4; i++) {
- if ((err = __get_user(*dst0++, src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(*dst1++, src++))) {
- ret = err;
- goto out;
- }
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- } else if (s->status & DO_BIGENDIAN_W) {
- int i, err;
- const char __user *src = buffer;
- unsigned char *dst;
- unsigned char data[2];
-
- dst = (unsigned char *) (s->dma_dac.rawbuf + swptr);
- // swap hi/lo bytes for each sample
- for (i = 0; i < cnt / 2; i++) {
- if ((err = __get_user(data[0], src++))) {
- ret = err;
- goto out;
- }
- if ((err = __get_user(data[1], src++))) {
- ret = err;
- goto out;
- }
- dst[0] = data[1];
- dst[1] = data[0];
- dst += 2;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- } else {
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- }
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- if (s->status & DO_AC3_SW)
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->status & DO_DUAL_DAC) {
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
- if (s->dma_dac.enabled)
- start_dac(s);
- }
-out:
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static unsigned int cm_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf(s, 0))
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf(s, 1))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int cm_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- goto out;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EINVAL;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-#define SNDCTL_SPDIF_COPYRIGHT _SIOW('S', 0, int) // set/reset S/PDIF copy protection
-#define SNDCTL_SPDIF_LOOP _SIOW('S', 1, int) // set/reset S/PDIF loop
-#define SNDCTL_SPDIF_MONITOR _SIOW('S', 2, int) // set S/PDIF monitor
-#define SNDCTL_SPDIF_LEVEL _SIOW('S', 3, int) // set/reset S/PDIF out level
-#define SNDCTL_SPDIF_INV _SIOW('S', 4, int) // set/reset S/PDIF in inverse
-#define SNDCTL_SPDIF_SEL2 _SIOW('S', 5, int) // set S/PDIF in #2
-#define SNDCTL_SPDIF_VALID _SIOW('S', 6, int) // set S/PDIF valid
-#define SNDCTL_SPDIFOUT _SIOW('S', 7, int) // set S/PDIF out
-#define SNDCTL_SPDIFIN _SIOW('S', 8, int) // set S/PDIF out
-
-static int cm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_BIND, p);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- spin_lock_irqsave(&s->lock, flags);
- stop_adc_unlocked(s);
- s->dma_adc.ready = 0;
- set_adc_rate_unlocked(s, val);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.ready = 0;
- set_dac_rate(s, val);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- }
- set_fmt(s, fmtm, fmtd);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_DACSHIFT);
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- }
- set_fmt(s, fmtm, fmtd);
- if ((s->capability & CAN_MULTI_CH)
- && (file->f_mode & FMODE_WRITE)) {
- val = set_dac_channels(s, val);
- return put_user(val, p);
- }
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT)
- : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_BE|AFMT_S16_LE|AFMT_U8|
- ((s->capability & CAN_AC3) ? AFMT_AC3 : 0), p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_BE || val == AFMT_S16_LE)
- fmtd |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_ADCSHIFT);
- if (val == AFMT_S16_BE)
- s->status |= DO_BIGENDIAN_R;
- else
- s->status &= ~DO_BIGENDIAN_R;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_BE || val == AFMT_S16_LE || val == AFMT_AC3)
- fmtd |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
- else
- fmtm &= ~(CM_CFMT_16BIT << CM_CFMT_DACSHIFT);
- if (val == AFMT_AC3) {
- fmtd |= CM_CFMT_STEREO << CM_CFMT_DACSHIFT;
- set_ac3(s, 48000);
- } else
- set_ac3(s, 0);
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_BE || val == AFMT_S16_LE)
- fmtd |= CM_CFMT_STEREO << CM_CFMT_ADCSHIFT;
- else
- fmtm &= ~(CM_CFMT_STEREO << CM_CFMT_ADCSHIFT);
- }
- if (val == AFMT_S16_BE)
- s->status |= DO_BIGENDIAN_W;
- else
- s->status &= ~DO_BIGENDIAN_W;
- }
- set_fmt(s, fmtm, fmtd);
- }
- if (s->status & DO_AC3) return put_user(AFMT_AC3, p);
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT)
- : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? val : AFMT_U8, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (s->status & DO_DUAL_DAC) {
- if (file->f_mode & FMODE_WRITE &&
- (s->enable & ENDAC) &&
- (s->enable & ENADC))
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
- }
- if (file->f_mode & FMODE_READ && s->enable & ENADC)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & ENDAC)
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- s->dma_adc.enabled = 1;
- start_adc(s);
- } else {
- s->dma_adc.enabled = 0;
- stop_adc(s);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (s->status & DO_DUAL_DAC) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- }
- s->dma_dac.enabled = 1;
- start_dac(s);
- } else {
- s->dma_dac.enabled = 0;
- stop_dac(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!(s->enable & ENDAC) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!(s->enable & ENADC) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cm_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- if (s->status & DO_DUAL_DAC) {
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(s, 0)))
- return val;
- if (s->status & DO_DUAL_DAC) {
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(2 * s->dma_dac.fragsize, p);
- }
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- if (s->status & DO_DUAL_DAC) {
- s->dma_adc.ossfragshift = s->dma_dac.ossfragshift;
- s->dma_adc.ossmaxfrags = s->dma_dac.ossmaxfrags;
- }
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.subdivision = val;
- if (s->status & DO_DUAL_DAC)
- s->dma_adc.subdivision = val;
- }
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_STEREO << CM_CFMT_ADCSHIFT) : (CM_CFMT_STEREO << CM_CFMT_DACSHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (CM_CFMT_16BIT << CM_CFMT_ADCSHIFT) : (CM_CFMT_16BIT << CM_CFMT_DACSHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_READ_FILTER:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_GETCHANNELMASK:
- return put_user(DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE|DSP_BIND_SPDIF, p);
-
- case SNDCTL_DSP_BIND_CHANNEL:
- if (get_user(val, p))
- return -EFAULT;
- if (val == DSP_BIND_QUERY) {
- val = DSP_BIND_FRONT;
- if (s->status & DO_SPDIF_OUT)
- val |= DSP_BIND_SPDIF;
- else {
- if (s->curr_channels == 4)
- val |= DSP_BIND_SURR;
- if (s->curr_channels > 4)
- val |= DSP_BIND_CENTER_LFE;
- }
- } else {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val & DSP_BIND_SPDIF) {
- set_spdifin(s, s->rateadc);
- if (!(s->status & DO_SPDIF_OUT))
- val &= ~DSP_BIND_SPDIF;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val & DSP_BIND_SPDIF) {
- set_spdifout(s, s->ratedac);
- set_dac_channels(s, s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1);
- if (!(s->status & DO_SPDIF_OUT))
- val &= ~DSP_BIND_SPDIF;
- } else {
- int channels;
- int mask;
-
- mask = val & (DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE);
- switch (mask) {
- case DSP_BIND_FRONT:
- channels = 2;
- break;
- case DSP_BIND_FRONT|DSP_BIND_SURR:
- channels = 4;
- break;
- case DSP_BIND_FRONT|DSP_BIND_SURR|DSP_BIND_CENTER_LFE:
- channels = 6;
- break;
- default:
- channels = s->fmt & (CM_CFMT_STEREO << CM_CFMT_DACSHIFT) ? 2 : 1;
- break;
- }
- set_dac_channels(s, channels);
- }
- }
- }
- return put_user(val, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- return -EINVAL;
- case SNDCTL_SPDIF_COPYRIGHT:
- if (get_user(val, p))
- return -EFAULT;
- set_spdif_copyright(s, val);
- return 0;
- case SNDCTL_SPDIF_LOOP:
- if (get_user(val, p))
- return -EFAULT;
- set_spdif_loop(s, val);
- return 0;
- case SNDCTL_SPDIF_MONITOR:
- if (get_user(val, p))
- return -EFAULT;
- set_spdif_monitor(s, val);
- return 0;
- case SNDCTL_SPDIF_LEVEL:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifout_level(s, val);
- return 0;
- case SNDCTL_SPDIF_INV:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin_inverse(s, val);
- return 0;
- case SNDCTL_SPDIF_SEL2:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin_channel2(s, val);
- return 0;
- case SNDCTL_SPDIF_VALID:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin_valid(s, val);
- return 0;
- case SNDCTL_SPDIFOUT:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifout(s, val ? s->ratedac : 0);
- return 0;
- case SNDCTL_SPDIFIN:
- if (get_user(val, p))
- return -EFAULT;
- set_spdifin(s, val ? s->rateadc : 0);
- return 0;
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int cm_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned char fmtm = ~0, fmts = 0;
- struct list_head *list;
- struct cm_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct cm_state, devs);
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- if (file->f_mode & FMODE_READ) {
- s->status &= ~DO_BIGENDIAN_R;
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_ADCSHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= CM_CFMT_16BIT << CM_CFMT_ADCSHIFT;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- set_adc_rate(s, 8000);
- // spdif-in is turnned off by default
- set_spdifin(s, 0);
- }
- if (file->f_mode & FMODE_WRITE) {
- s->status &= ~DO_BIGENDIAN_W;
- fmtm &= ~((CM_CFMT_STEREO | CM_CFMT_16BIT) << CM_CFMT_DACSHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= CM_CFMT_16BIT << CM_CFMT_DACSHIFT;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- s->dma_dac.enabled = 1;
- set_dac_rate(s, 8000);
- // clear previous multichannel, spdif, ac3 state
- set_spdifout(s, 0);
- set_ac3(s, 0);
- set_dac_channels(s, 1);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int cm_release(struct inode *inode, struct file *file)
-{
- struct cm_state *s = (struct cm_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
-
- dealloc_dmabuf(s, &s->dma_dac);
- if (s->status & DO_DUAL_DAC)
- dealloc_dmabuf(s, &s->dma_adc);
-
- if (s->status & DO_MULTI_CH)
- set_dac_channels(s, 1);
- if (s->status & DO_AC3)
- set_ac3(s, 0);
- if (s->status & DO_SPDIF_OUT)
- set_spdifout(s, 0);
- /* enable SPDIF loop */
- set_spdif_loop(s, spdif_loop);
- s->status &= ~DO_BIGENDIAN_W;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- s->status &= ~DO_BIGENDIAN_R;
- }
- s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations cm_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = cm_read,
- .write = cm_write,
- .poll = cm_poll,
- .ioctl = cm_ioctl,
- .mmap = cm_mmap,
- .open = cm_open,
- .release = cm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_CD, 0x4f4f },
- { SOUND_MIXER_WRITE_LINE, 0x4f4f },
- { SOUND_MIXER_WRITE_MIC, 0x4f4f },
- { SOUND_MIXER_WRITE_SYNTH, 0x4f4f },
- { SOUND_MIXER_WRITE_VOLUME, 0x4f4f },
- { SOUND_MIXER_WRITE_PCM, 0x4f4f }
-};
-
-/* check chip version and capability */
-static int query_chip(struct cm_state *s)
-{
- int ChipVersion = -1;
- unsigned char RegValue;
-
- // check reg 0Ch, bit 24-31
- RegValue = inb(s->iobase + CODEC_CMI_INT_HLDCLR + 3);
- if (RegValue == 0) {
- // check reg 08h, bit 24-28
- RegValue = inb(s->iobase + CODEC_CMI_CHFORMAT + 3);
- RegValue &= 0x1f;
- if (RegValue == 0) {
- ChipVersion = 33;
- s->max_channels = 4;
- s->capability |= CAN_AC3_SW;
- s->capability |= CAN_DUAL_DAC;
- } else {
- ChipVersion = 37;
- s->max_channels = 4;
- s->capability |= CAN_AC3_HW;
- s->capability |= CAN_DUAL_DAC;
- }
- } else {
- // check reg 0Ch, bit 26
- if (RegValue & (1 << (26-24))) {
- ChipVersion = 39;
- if (RegValue & (1 << (24-24)))
- s->max_channels = 6;
- else
- s->max_channels = 4;
- s->capability |= CAN_AC3_HW;
- s->capability |= CAN_DUAL_DAC;
- s->capability |= CAN_MULTI_CH_HW;
- s->capability |= CAN_LINE_AS_BASS;
- s->capability |= CAN_MIC_AS_BASS;
- } else {
- ChipVersion = 55; // 4 or 6 channels
- s->max_channels = 6;
- s->capability |= CAN_AC3_HW;
- s->capability |= CAN_DUAL_DAC;
- s->capability |= CAN_MULTI_CH_HW;
- s->capability |= CAN_LINE_AS_BASS;
- s->capability |= CAN_MIC_AS_BASS;
- }
- }
- s->capability |= CAN_LINE_AS_REAR;
- return ChipVersion;
-}
-
-#ifdef CONFIG_SOUND_CMPCI_JOYSTICK
-static int __devinit cm_create_gameport(struct cm_state *s, int io_port)
-{
- struct gameport *gp;
-
- if (!request_region(io_port, CM_EXTENT_GAME, "cmpci GAME")) {
- printk(KERN_ERR "cmpci: gameport io ports 0x%#x in use\n", io_port);
- return -EBUSY;
- }
-
- if (!(s->gameport = gp = gameport_allocate_port())) {
- printk(KERN_ERR "cmpci: can not allocate memory for gameport\n");
- release_region(io_port, CM_EXTENT_GAME);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "C-Media GP");
- gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
- gp->dev.parent = &s->dev->dev;
- gp->io = io_port;
-
- /* enable joystick */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x02);
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static void __devexit cm_free_gameport(struct cm_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
-
- gameport_unregister_port(s->gameport);
- s->gameport = NULL;
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
- release_region(gpio, CM_EXTENT_GAME);
- }
-}
-#else
-static inline int cm_create_gameport(struct cm_state *s, int io_port) { return -ENOSYS; }
-static inline void cm_free_gameport(struct cm_state *s) { }
-#endif
-
-#define echo_option(x)\
-if (x) strcat(options, "" #x " ")
-
-static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- struct cm_state *s;
- mm_segment_t fs;
- int i, val, ret;
- unsigned char reg_mask;
- int timeout;
- struct resource *ports;
- struct {
- unsigned short deviceid;
- char *devicename;
- } devicetable[] = {
- { PCI_DEVICE_ID_CMEDIA_CM8338A, "CM8338A" },
- { PCI_DEVICE_ID_CMEDIA_CM8338B, "CM8338B" },
- { PCI_DEVICE_ID_CMEDIA_CM8738, "CM8738" },
- { PCI_DEVICE_ID_CMEDIA_CM8738B, "CM8738B" },
- };
- char *devicename = "unknown";
- char options[256];
-
- if ((ret = pci_enable_device(pcidev)))
- return ret;
- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO))
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
- i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
- if (i) {
- printk(KERN_WARNING "cmpci: architecture does not support 32bit PCI busmaster DMA\n");
- return i;
- }
- s = kmalloc(sizeof(*s), GFP_KERNEL);
- if (!s) {
- printk(KERN_WARNING "cmpci: out of memory\n");
- return -ENOMEM;
- }
- /* search device name */
- for (i = 0; i < sizeof(devicetable) / sizeof(devicetable[0]); i++) {
- if (devicetable[i].deviceid == pcidev->device) {
- devicename = devicetable[i].devicename;
- break;
- }
- }
- memset(s, 0, sizeof(struct cm_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
- s->magic = CM_MAGIC;
- s->dev = pcidev;
- s->iobase = pci_resource_start(pcidev, 0);
- s->iosynth = fmio;
- s->iomidi = mpuio;
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- s->midi_devc = 0;
-#endif
- s->status = 0;
- if (s->iobase == 0)
- return -ENODEV;
- s->irq = pcidev->irq;
-
- if (!request_region(s->iobase, CM_EXTENT_CODEC, "cmpci")) {
- printk(KERN_ERR "cmpci: io ports %#x-%#x in use\n", s->iobase, s->iobase+CM_EXTENT_CODEC-1);
- ret = -EBUSY;
- goto err_region5;
- }
- /* dump parameters */
- strcpy(options, "cmpci: ");
- echo_option(joystick);
- echo_option(spdif_inverse);
- echo_option(spdif_loop);
- echo_option(spdif_out);
- echo_option(use_line_as_rear);
- echo_option(use_line_as_bass);
- echo_option(use_mic_as_bass);
- echo_option(mic_boost);
- echo_option(hw_copy);
- printk(KERN_INFO "%s\n", options);
-
- /* initialize codec registers */
- outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
- /* reset mixer */
- wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
- /* request irq */
- if ((ret = request_irq(s->irq, cm_interrupt, IRQF_SHARED, "cmpci", s))) {
- printk(KERN_ERR "cmpci: irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_INFO "cmpci: found %s adapter at io %#x irq %u\n",
- devicename, s->iobase, s->irq);
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&cm_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&cm_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- pci_set_master(pcidev); /* enable bus mastering */
- /* initialize the chips */
- fs = get_fs();
- set_fs(KERNEL_DS);
- /* set mixer output */
- frobindir(s, DSP_MIX_OUTMIXIDX, 0x1f, 0x1f);
- /* set mixer input */
- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD|SOUND_MASK_MIC;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- set_fs(fs);
- /* use channel 1 for playback, channel 0 for record */
- maskb(s->iobase + CODEC_CMI_FUNCTRL0, ~CHADC1, CHADC0);
- /* turn off VMIC3 - mic boost */
- if (mic_boost)
- maskb(s->iobase + CODEC_CMI_MIXER2, ~1, 0);
- else
- maskb(s->iobase + CODEC_CMI_MIXER2, ~0, 1);
- s->deviceid = pcidev->device;
-
- if (pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738
- || pcidev->device == PCI_DEVICE_ID_CMEDIA_CM8738B) {
-
- /* chip version and hw capability check */
- s->chip_version = query_chip(s);
- printk(KERN_INFO "cmpci: chip version = 0%d\n", s->chip_version);
-
- /* set SPDIF-in inverse before enable SPDIF loop */
- set_spdifin_inverse(s, spdif_inverse);
-
- /* use SPDIF in #1 */
- set_spdifin_channel2(s, 0);
- } else {
- s->chip_version = 0;
- /* 8338 will fall here */
- s->max_channels = 4;
- s->capability |= CAN_DUAL_DAC;
- s->capability |= CAN_LINE_AS_REAR;
- }
- /* enable SPDIF loop */
- set_spdif_loop(s, spdif_loop);
-
- // enable 4 speaker mode (analog duplicate)
- set_hw_copy(s, hw_copy);
-
- reg_mask = 0;
-#ifdef CONFIG_SOUND_CMPCI_FM
- /* disable FM */
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
- if (s->iosynth) {
- /* don't enable OPL3 if there is one */
- if (opl3_detect(s->iosynth, NULL)) {
- s->iosynth = 0;
- } else {
- /* set IO based at 0x388 */
- switch (s->iosynth) {
- case 0x388:
- reg_mask = 0;
- break;
- case 0x3C8:
- reg_mask = 0x01;
- break;
- case 0x3E0:
- reg_mask = 0x02;
- break;
- case 0x3E8:
- reg_mask = 0x03;
- break;
- default:
- s->iosynth = 0;
- break;
- }
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x03, reg_mask);
- /* enable FM */
- if (s->iosynth) {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~0, 8);
- if (opl3_detect(s->iosynth, NULL))
- ret = opl3_init(s->iosynth, NULL, THIS_MODULE);
- else {
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
- s->iosynth = 0;
- }
- }
- }
- }
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- switch (s->iomidi) {
- case 0x330:
- reg_mask = 0;
- break;
- case 0x320:
- reg_mask = 0x20;
- break;
- case 0x310:
- reg_mask = 0x40;
- break;
- case 0x300:
- reg_mask = 0x60;
- break;
- default:
- s->iomidi = 0;
- goto skip_mpu;
- }
- ports = request_region(s->iomidi, 2, "mpu401");
- if (!ports)
- goto skip_mpu;
- /* disable MPU-401 */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
- s->mpu_data.name = "cmpci mpu";
- s->mpu_data.io_base = s->iomidi;
- s->mpu_data.irq = -s->irq; // tell mpu401 to share irq
- if (probe_mpu401(&s->mpu_data, ports)) {
- release_region(s->iomidi, 2);
- s->iomidi = 0;
- goto skip_mpu;
- }
- maskb(s->iobase + CODEC_CMI_LEGACY_CTRL + 3, ~0x60, reg_mask);
- /* enable MPU-401 */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
- /* clear all previously received interrupt */
- for (timeout = 900000; timeout > 0; timeout--) {
- if ((inb(s->iomidi + 1) && 0x80) == 0)
- inb(s->iomidi);
- else
- break;
- }
- if (!probe_mpu401(&s->mpu_data, ports)) {
- release_region(s->iomidi, 2);
- s->iomidi = 0;
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0, 0x04);
- } else {
- attach_mpu401(&s->mpu_data, THIS_MODULE);
- s->midi_devc = s->mpu_data.slots[1];
- }
-skip_mpu:
-#endif
- /* disable joystick port */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x02, 0);
- if (joystick)
- cm_create_gameport(s, 0x200);
-
- /* store it in the driver field */
- pci_set_drvdata(pcidev, s);
- /* put it into driver list */
- list_add_tail(&s->devs, &devs);
- /* increment devindex */
- if (devindex < NR_DEVICE-1)
- devindex++;
- return 0;
-
-err_dev2:
- unregister_sound_dsp(s->dev_audio);
-err_dev1:
- printk(KERN_ERR "cmpci: cannot register misc device\n");
- free_irq(s->irq, s);
-err_irq:
- release_region(s->iobase, CM_EXTENT_CODEC);
-err_region5:
- kfree(s);
- return ret;
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("ChenLi Tien, cltien@cmedia.com.tw");
-MODULE_DESCRIPTION("CM8x38 Audio Driver");
-MODULE_LICENSE("GPL");
-
-static void __devexit cm_remove(struct pci_dev *dev)
-{
- struct cm_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
-
- cm_free_gameport(s);
-
-#ifdef CONFIG_SOUND_CMPCI_FM
- if (s->iosynth) {
- /* disable FM */
- maskb(s->iobase + CODEC_CMI_MISC_CTRL + 2, ~8, 0);
- }
-#endif
-#ifdef CONFIG_SOUND_CMPCI_MIDI
- if (s->iomidi) {
- unload_mpu401(&s->mpu_data);
- /* disable MPU-401 */
- maskb(s->iobase + CODEC_CMI_FUNCTRL1, ~0x04, 0);
- }
-#endif
- set_spdif_loop(s, 0);
- list_del(&s->devs);
- outb(0, s->iobase + CODEC_CMI_INT_HLDCLR + 2); /* disable ints */
- synchronize_irq(s->irq);
- outb(0, s->iobase + CODEC_CMI_FUNCTRL0 + 2); /* disable channels */
- free_irq(s->irq, s);
-
- /* reset mixer */
- wrmixer(s, DSP_MIX_DATARESETIDX, 0);
-
- release_region(s->iobase, CM_EXTENT_CODEC);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] __devinitdata = {
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { PCI_VENDOR_ID_CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver cm_driver = {
- .name = "cmpci",
- .id_table = id_table,
- .probe = cm_probe,
- .remove = __devexit_p(cm_remove)
-};
-
-static int __init init_cmpci(void)
-{
- printk(KERN_INFO "cmpci: version $Revision: 6.82 $ time " __TIME__ " " __DATE__ "\n");
- return pci_register_driver(&cm_driver);
-}
-
-static void __exit cleanup_cmpci(void)
-{
- printk(KERN_INFO "cmpci: unloading\n");
- pci_unregister_driver(&cm_driver);
-}
-
-module_init(init_cmpci);
-module_exit(cleanup_cmpci);
diff --git a/sound/oss/cs4281/Makefile b/sound/oss/cs4281/Makefile
deleted file mode 100644
index 6d527e8530d6..000000000000
--- a/sound/oss/cs4281/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-# Makefile for Cirrus Logic-Crystal CS4281
-#
-
-obj-$(CONFIG_SOUND_CS4281) += cs4281.o
-
-cs4281-objs += cs4281m.o
diff --git a/sound/oss/cs4281/cs4281_hwdefs.h b/sound/oss/cs4281/cs4281_hwdefs.h
deleted file mode 100644
index 701d595e33f5..000000000000
--- a/sound/oss/cs4281/cs4281_hwdefs.h
+++ /dev/null
@@ -1,1234 +0,0 @@
-//****************************************************************************
-//
-// HWDEFS.H - Definitions of the registers and data structures used by the
-// CS4281
-//
-// Copyright (c) 1999,2000,2001 Crystal Semiconductor Corp.
-//
-//****************************************************************************
-
-#ifndef _H_HWDEFS
-#define _H_HWDEFS
-
-//****************************************************************************
-//
-// The following define the offsets of the registers located in the PCI
-// configuration space of the CS4281 part.
-//
-//****************************************************************************
-#define PCICONFIG_DEVID_VENID 0x00000000L
-#define PCICONFIG_STATUS_COMMAND 0x00000004L
-#define PCICONFIG_CLASS_REVISION 0x00000008L
-#define PCICONFIG_LATENCY_TIMER 0x0000000CL
-#define PCICONFIG_BA0 0x00000010L
-#define PCICONFIG_BA1 0x00000014L
-#define PCICONFIG_SUBSYSID_SUBSYSVENID 0x0000002CL
-#define PCICONFIG_INTERRUPT 0x0000003CL
-
-//****************************************************************************
-//
-// The following define the offsets of the registers accessed via base address
-// register zero on the CS4281 part.
-//
-//****************************************************************************
-#define BA0_HISR 0x00000000L
-#define BA0_HICR 0x00000008L
-#define BA0_HIMR 0x0000000CL
-#define BA0_IIER 0x00000010L
-#define BA0_HDSR0 0x000000F0L
-#define BA0_HDSR1 0x000000F4L
-#define BA0_HDSR2 0x000000F8L
-#define BA0_HDSR3 0x000000FCL
-#define BA0_DCA0 0x00000110L
-#define BA0_DCC0 0x00000114L
-#define BA0_DBA0 0x00000118L
-#define BA0_DBC0 0x0000011CL
-#define BA0_DCA1 0x00000120L
-#define BA0_DCC1 0x00000124L
-#define BA0_DBA1 0x00000128L
-#define BA0_DBC1 0x0000012CL
-#define BA0_DCA2 0x00000130L
-#define BA0_DCC2 0x00000134L
-#define BA0_DBA2 0x00000138L
-#define BA0_DBC2 0x0000013CL
-#define BA0_DCA3 0x00000140L
-#define BA0_DCC3 0x00000144L
-#define BA0_DBA3 0x00000148L
-#define BA0_DBC3 0x0000014CL
-#define BA0_DMR0 0x00000150L
-#define BA0_DCR0 0x00000154L
-#define BA0_DMR1 0x00000158L
-#define BA0_DCR1 0x0000015CL
-#define BA0_DMR2 0x00000160L
-#define BA0_DCR2 0x00000164L
-#define BA0_DMR3 0x00000168L
-#define BA0_DCR3 0x0000016CL
-#define BA0_DLMR 0x00000170L
-#define BA0_DLSR 0x00000174L
-#define BA0_FCR0 0x00000180L
-#define BA0_FCR1 0x00000184L
-#define BA0_FCR2 0x00000188L
-#define BA0_FCR3 0x0000018CL
-#define BA0_FPDR0 0x00000190L
-#define BA0_FPDR1 0x00000194L
-#define BA0_FPDR2 0x00000198L
-#define BA0_FPDR3 0x0000019CL
-#define BA0_FCHS 0x0000020CL
-#define BA0_FSIC0 0x00000210L
-#define BA0_FSIC1 0x00000214L
-#define BA0_FSIC2 0x00000218L
-#define BA0_FSIC3 0x0000021CL
-#define BA0_PCICFG00 0x00000300L
-#define BA0_PCICFG04 0x00000304L
-#define BA0_PCICFG08 0x00000308L
-#define BA0_PCICFG0C 0x0000030CL
-#define BA0_PCICFG10 0x00000310L
-#define BA0_PCICFG14 0x00000314L
-#define BA0_PCICFG18 0x00000318L
-#define BA0_PCICFG1C 0x0000031CL
-#define BA0_PCICFG20 0x00000320L
-#define BA0_PCICFG24 0x00000324L
-#define BA0_PCICFG28 0x00000328L
-#define BA0_PCICFG2C 0x0000032CL
-#define BA0_PCICFG30 0x00000330L
-#define BA0_PCICFG34 0x00000334L
-#define BA0_PCICFG38 0x00000338L
-#define BA0_PCICFG3C 0x0000033CL
-#define BA0_PCICFG40 0x00000340L
-#define BA0_PMCS 0x00000344L
-#define BA0_CWPR 0x000003E0L
-#define BA0_EPPMC 0x000003E4L
-#define BA0_GPIOR 0x000003E8L
-#define BA0_SPMC 0x000003ECL
-#define BA0_CFLR 0x000003F0L
-#define BA0_IISR 0x000003F4L
-#define BA0_TMS 0x000003F8L
-#define BA0_SSVID 0x000003FCL
-#define BA0_CLKCR1 0x00000400L
-#define BA0_FRR 0x00000410L
-#define BA0_SLT12O 0x0000041CL
-#define BA0_SERMC 0x00000420L
-#define BA0_SERC1 0x00000428L
-#define BA0_SERC2 0x0000042CL
-#define BA0_SLT12M 0x0000045CL
-#define BA0_ACCTL 0x00000460L
-#define BA0_ACSTS 0x00000464L
-#define BA0_ACOSV 0x00000468L
-#define BA0_ACCAD 0x0000046CL
-#define BA0_ACCDA 0x00000470L
-#define BA0_ACISV 0x00000474L
-#define BA0_ACSAD 0x00000478L
-#define BA0_ACSDA 0x0000047CL
-#define BA0_JSPT 0x00000480L
-#define BA0_JSCTL 0x00000484L
-#define BA0_MIDCR 0x00000490L
-#define BA0_MIDCMD 0x00000494L
-#define BA0_MIDSR 0x00000494L
-#define BA0_MIDWP 0x00000498L
-#define BA0_MIDRP 0x0000049CL
-#define BA0_AODSD1 0x000004A8L
-#define BA0_AODSD2 0x000004ACL
-#define BA0_CFGI 0x000004B0L
-#define BA0_SLT12M2 0x000004DCL
-#define BA0_ACSTS2 0x000004E4L
-#define BA0_ACISV2 0x000004F4L
-#define BA0_ACSAD2 0x000004F8L
-#define BA0_ACSDA2 0x000004FCL
-#define BA0_IOTGP 0x00000500L
-#define BA0_IOTSB 0x00000504L
-#define BA0_IOTFM 0x00000508L
-#define BA0_IOTDMA 0x0000050CL
-#define BA0_IOTAC0 0x00000500L
-#define BA0_IOTAC1 0x00000504L
-#define BA0_IOTAC2 0x00000508L
-#define BA0_IOTAC3 0x0000050CL
-#define BA0_IOTPCP 0x0000052CL
-#define BA0_IOTCC 0x00000530L
-#define BA0_IOTCR 0x0000058CL
-#define BA0_PCPRR 0x00000600L
-#define BA0_PCPGR 0x00000604L
-#define BA0_PCPCR 0x00000608L
-#define BA0_PCPCIEN 0x00000608L
-#define BA0_SBMAR 0x00000700L
-#define BA0_SBMDR 0x00000704L
-#define BA0_SBRR 0x00000708L
-#define BA0_SBRDP 0x0000070CL
-#define BA0_SBWDP 0x00000710L
-#define BA0_SBWBS 0x00000710L
-#define BA0_SBRBS 0x00000714L
-#define BA0_FMSR 0x00000730L
-#define BA0_B0AP 0x00000730L
-#define BA0_FMDP 0x00000734L
-#define BA0_B1AP 0x00000738L
-#define BA0_B1DP 0x0000073CL
-#define BA0_SSPM 0x00000740L
-#define BA0_DACSR 0x00000744L
-#define BA0_ADCSR 0x00000748L
-#define BA0_SSCR 0x0000074CL
-#define BA0_FMLVC 0x00000754L
-#define BA0_FMRVC 0x00000758L
-#define BA0_SRCSA 0x0000075CL
-#define BA0_PPLVC 0x00000760L
-#define BA0_PPRVC 0x00000764L
-#define BA0_PASR 0x00000768L
-#define BA0_CASR 0x0000076CL
-
-//****************************************************************************
-//
-// The following define the offsets of the AC97 shadow registers, which appear
-// as a virtual extension to the base address register zero memory range.
-//
-//****************************************************************************
-#define AC97_REG_OFFSET_MASK 0x0000007EL
-#define AC97_CODEC_NUMBER_MASK 0x00003000L
-
-#define BA0_AC97_RESET 0x00001000L
-#define BA0_AC97_MASTER_VOLUME 0x00001002L
-#define BA0_AC97_HEADPHONE_VOLUME 0x00001004L
-#define BA0_AC97_MASTER_VOLUME_MONO 0x00001006L
-#define BA0_AC97_MASTER_TONE 0x00001008L
-#define BA0_AC97_PC_BEEP_VOLUME 0x0000100AL
-#define BA0_AC97_PHONE_VOLUME 0x0000100CL
-#define BA0_AC97_MIC_VOLUME 0x0000100EL
-#define BA0_AC97_LINE_IN_VOLUME 0x00001010L
-#define BA0_AC97_CD_VOLUME 0x00001012L
-#define BA0_AC97_VIDEO_VOLUME 0x00001014L
-#define BA0_AC97_AUX_VOLUME 0x00001016L
-#define BA0_AC97_PCM_OUT_VOLUME 0x00001018L
-#define BA0_AC97_RECORD_SELECT 0x0000101AL
-#define BA0_AC97_RECORD_GAIN 0x0000101CL
-#define BA0_AC97_RECORD_GAIN_MIC 0x0000101EL
-#define BA0_AC97_GENERAL_PURPOSE 0x00001020L
-#define BA0_AC97_3D_CONTROL 0x00001022L
-#define BA0_AC97_MODEM_RATE 0x00001024L
-#define BA0_AC97_POWERDOWN 0x00001026L
-#define BA0_AC97_EXT_AUDIO_ID 0x00001028L
-#define BA0_AC97_EXT_AUDIO_POWER 0x0000102AL
-#define BA0_AC97_PCM_FRONT_DAC_RATE 0x0000102CL
-#define BA0_AC97_PCM_SURR_DAC_RATE 0x0000102EL
-#define BA0_AC97_PCM_LFE_DAC_RATE 0x00001030L
-#define BA0_AC97_PCM_LR_ADC_RATE 0x00001032L
-#define BA0_AC97_MIC_ADC_RATE 0x00001034L
-#define BA0_AC97_6CH_VOL_C_LFE 0x00001036L
-#define BA0_AC97_6CH_VOL_SURROUND 0x00001038L
-#define BA0_AC97_RESERVED_3A 0x0000103AL
-#define BA0_AC97_EXT_MODEM_ID 0x0000103CL
-#define BA0_AC97_EXT_MODEM_POWER 0x0000103EL
-#define BA0_AC97_LINE1_CODEC_RATE 0x00001040L
-#define BA0_AC97_LINE2_CODEC_RATE 0x00001042L
-#define BA0_AC97_HANDSET_CODEC_RATE 0x00001044L
-#define BA0_AC97_LINE1_CODEC_LEVEL 0x00001046L
-#define BA0_AC97_LINE2_CODEC_LEVEL 0x00001048L
-#define BA0_AC97_HANDSET_CODEC_LEVEL 0x0000104AL
-#define BA0_AC97_GPIO_PIN_CONFIG 0x0000104CL
-#define BA0_AC97_GPIO_PIN_TYPE 0x0000104EL
-#define BA0_AC97_GPIO_PIN_STICKY 0x00001050L
-#define BA0_AC97_GPIO_PIN_WAKEUP 0x00001052L
-#define BA0_AC97_GPIO_PIN_STATUS 0x00001054L
-#define BA0_AC97_MISC_MODEM_AFE_STAT 0x00001056L
-#define BA0_AC97_RESERVED_58 0x00001058L
-#define BA0_AC97_CRYSTAL_REV_N_FAB_ID 0x0000105AL
-#define BA0_AC97_TEST_AND_MISC_CTRL 0x0000105CL
-#define BA0_AC97_AC_MODE 0x0000105EL
-#define BA0_AC97_MISC_CRYSTAL_CONTROL 0x00001060L
-#define BA0_AC97_LINE1_HYPRID_CTRL 0x00001062L
-#define BA0_AC97_VENDOR_RESERVED_64 0x00001064L
-#define BA0_AC97_VENDOR_RESERVED_66 0x00001066L
-#define BA0_AC97_SPDIF_CONTROL 0x00001068L
-#define BA0_AC97_VENDOR_RESERVED_6A 0x0000106AL
-#define BA0_AC97_VENDOR_RESERVED_6C 0x0000106CL
-#define BA0_AC97_VENDOR_RESERVED_6E 0x0000106EL
-#define BA0_AC97_VENDOR_RESERVED_70 0x00001070L
-#define BA0_AC97_VENDOR_RESERVED_72 0x00001072L
-#define BA0_AC97_VENDOR_RESERVED_74 0x00001074L
-#define BA0_AC97_CAL_ADDRESS 0x00001076L
-#define BA0_AC97_CAL_DATA 0x00001078L
-#define BA0_AC97_VENDOR_RESERVED_7A 0x0000107AL
-#define BA0_AC97_VENDOR_ID1 0x0000107CL
-#define BA0_AC97_VENDOR_ID2 0x0000107EL
-
-//****************************************************************************
-//
-// The following define the offsets of the registers and memories accessed via
-// base address register one on the CS4281 part.
-//
-//****************************************************************************
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI device ID/vendor ID
-// register.
-//
-//****************************************************************************
-#define PDV_VENID_MASK 0x0000FFFFL
-#define PDV_DEVID_MASK 0xFFFF0000L
-#define PDV_VENID_SHIFT 0L
-#define PDV_DEVID_SHIFT 16L
-#define VENID_CIRRUS_LOGIC 0x1013L
-#define DEVID_CS4281 0x6005L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI status and command
-// register.
-//
-//****************************************************************************
-#define PSC_IO_SPACE_ENABLE 0x00000001L
-#define PSC_MEMORY_SPACE_ENABLE 0x00000002L
-#define PSC_BUS_MASTER_ENABLE 0x00000004L
-#define PSC_SPECIAL_CYCLES 0x00000008L
-#define PSC_MWI_ENABLE 0x00000010L
-#define PSC_VGA_PALETTE_SNOOP 0x00000020L
-#define PSC_PARITY_RESPONSE 0x00000040L
-#define PSC_WAIT_CONTROL 0x00000080L
-#define PSC_SERR_ENABLE 0x00000100L
-#define PSC_FAST_B2B_ENABLE 0x00000200L
-#define PSC_UDF_MASK 0x007F0000L
-#define PSC_FAST_B2B_CAPABLE 0x00800000L
-#define PSC_PARITY_ERROR_DETECTED 0x01000000L
-#define PSC_DEVSEL_TIMING_MASK 0x06000000L
-#define PSC_TARGET_ABORT_SIGNALLED 0x08000000L
-#define PSC_RECEIVED_TARGET_ABORT 0x10000000L
-#define PSC_RECEIVED_MASTER_ABORT 0x20000000L
-#define PSC_SIGNALLED_SERR 0x40000000L
-#define PSC_DETECTED_PARITY_ERROR 0x80000000L
-#define PSC_UDF_SHIFT 16L
-#define PSC_DEVSEL_TIMING_SHIFT 25L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI class/revision ID
-// register.
-//
-//****************************************************************************
-#define PCR_REVID_MASK 0x000000FFL
-#define PCR_INTERFACE_MASK 0x0000FF00L
-#define PCR_SUBCLASS_MASK 0x00FF0000L
-#define PCR_CLASS_MASK 0xFF000000L
-#define PCR_REVID_SHIFT 0L
-#define PCR_INTERFACE_SHIFT 8L
-#define PCR_SUBCLASS_SHIFT 16L
-#define PCR_CLASS_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI latency timer register.
-//
-//****************************************************************************
-#define PLT_CACHE_LINE_SIZE_MASK 0x000000FFL
-#define PLT_LATENCY_TIMER_MASK 0x0000FF00L
-#define PLT_HEADER_TYPE_MASK 0x00FF0000L
-#define PLT_BIST_MASK 0xFF000000L
-#define PLT_CACHE_LINE_SIZE_SHIFT 0L
-#define PLT_LATENCY_TIMER_SHIFT 8L
-#define PLT_HEADER_TYPE_SHIFT 16L
-#define PLT_BIST_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI base address registers.
-//
-//****************************************************************************
-#define PBAR_MEMORY_SPACE_INDICATOR 0x00000001L
-#define PBAR_LOCATION_TYPE_MASK 0x00000006L
-#define PBAR_NOT_PREFETCHABLE 0x00000008L
-#define PBAR_ADDRESS_MASK 0xFFFFFFF0L
-#define PBAR_LOCATION_TYPE_SHIFT 1L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI subsystem ID/subsystem
-// vendor ID register.
-//
-//****************************************************************************
-#define PSS_SUBSYSTEM_VENDOR_ID_MASK 0x0000FFFFL
-#define PSS_SUBSYSTEM_ID_MASK 0xFFFF0000L
-#define PSS_SUBSYSTEM_VENDOR_ID_SHIFT 0L
-#define PSS_SUBSYSTEM_ID_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PCI interrupt register.
-//
-//****************************************************************************
-#define PI_LINE_MASK 0x000000FFL
-#define PI_PIN_MASK 0x0000FF00L
-#define PI_MIN_GRANT_MASK 0x00FF0000L
-#define PI_MAX_LATENCY_MASK 0xFF000000L
-#define PI_LINE_SHIFT 0L
-#define PI_PIN_SHIFT 8L
-#define PI_MIN_GRANT_SHIFT 16L
-#define PI_MAX_LATENCY_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the host interrupt status
-// register.
-//
-//****************************************************************************
-#define HISR_HVOLMASK 0x00000003L
-#define HISR_VDNI 0x00000001L
-#define HISR_VUPI 0x00000002L
-#define HISR_GP1I 0x00000004L
-#define HISR_GP3I 0x00000008L
-#define HISR_GPSI 0x00000010L
-#define HISR_GPPI 0x00000020L
-#define HISR_DMAI 0x00040000L
-#define HISR_FIFOI 0x00100000L
-#define HISR_HVOL 0x00200000L
-#define HISR_MIDI 0x00400000L
-#define HISR_SBINT 0x00800000L
-#define HISR_INTENA 0x80000000L
-#define HISR_DMA_MASK 0x00000F00L
-#define HISR_FIFO_MASK 0x0000F000L
-#define HISR_DMA_SHIFT 8L
-#define HISR_FIFO_SHIFT 12L
-#define HISR_FIFO0 0x00001000L
-#define HISR_FIFO1 0x00002000L
-#define HISR_FIFO2 0x00004000L
-#define HISR_FIFO3 0x00008000L
-#define HISR_DMA0 0x00000100L
-#define HISR_DMA1 0x00000200L
-#define HISR_DMA2 0x00000400L
-#define HISR_DMA3 0x00000800L
-#define HISR_RESERVED 0x40000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the host interrupt control
-// register.
-//
-//****************************************************************************
-#define HICR_IEV 0x00000001L
-#define HICR_CHGM 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the DMA Mode Register n
-// (DMRn)
-//
-//****************************************************************************
-#define DMRn_TR_MASK 0x0000000CL
-#define DMRn_TR_SHIFT 2L
-#define DMRn_AUTO 0x00000010L
-#define DMRn_TR_READ 0x00000008L
-#define DMRn_TR_WRITE 0x00000004L
-#define DMRn_TYPE_MASK 0x000000C0L
-#define DMRn_TYPE_SHIFT 6L
-#define DMRn_SIZE8 0x00010000L
-#define DMRn_MONO 0x00020000L
-#define DMRn_BEND 0x00040000L
-#define DMRn_USIGN 0x00080000L
-#define DMRn_SIZE20 0x00100000L
-#define DMRn_SWAPC 0x00400000L
-#define DMRn_CBC 0x01000000L
-#define DMRn_TBC 0x02000000L
-#define DMRn_POLL 0x10000000L
-#define DMRn_DMA 0x20000000L
-#define DMRn_FSEL_MASK 0xC0000000L
-#define DMRn_FSEL_SHIFT 30L
-#define DMRn_FSEL0 0x00000000L
-#define DMRn_FSEL1 0x40000000L
-#define DMRn_FSEL2 0x80000000L
-#define DMRn_FSEL3 0xC0000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the DMA Command Register n
-// (DCRn)
-//
-//****************************************************************************
-#define DCRn_HTCIE 0x00020000L
-#define DCRn_TCIE 0x00010000L
-#define DCRn_MSK 0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the FIFO Control
-// register n.(FCRn)
-//
-//****************************************************************************
-#define FCRn_OF_MASK 0x0000007FL
-#define FCRn_OF_SHIFT 0L
-#define FCRn_SZ_MASK 0x00007F00L
-#define FCRn_SZ_SHIFT 8L
-#define FCRn_LS_MASK 0x001F0000L
-#define FCRn_LS_SHIFT 16L
-#define FCRn_RS_MASK 0x1F000000L
-#define FCRn_RS_SHIFT 24L
-#define FCRn_FEN 0x80000000L
-#define FCRn_PSH 0x20000000L
-#define FCRn_DACZ 0x40000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port Power Management
-// control register.(SPMC)
-//
-//****************************************************************************
-#define SPMC_RSTN 0x00000001L
-#define SPMC_ASYN 0x00000002L
-#define SPMC_WUP1 0x00000004L
-#define SPMC_WUP2 0x00000008L
-#define SPMC_ASDI2E 0x00000100L
-#define SPMC_ESSPD 0x00000200L
-#define SPMC_GISPEN 0x00004000L
-#define SPMC_GIPPEN 0x00008000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Configuration Load register.
-// (CFLR)
-//
-//****************************************************************************
-#define CFLR_CLOCK_SOURCE_MASK 0x00000003L
-#define CFLR_CLOCK_SOURCE_AC97 0x00000001L
-
-#define CFLR_CB0_MASK 0x000000FFL
-#define CFLR_CB1_MASK 0x0000FF00L
-#define CFLR_CB2_MASK 0x00FF0000L
-#define CFLR_CB3_MASK 0xFF000000L
-#define CFLR_CB0_SHIFT 0L
-#define CFLR_CB1_SHIFT 8L
-#define CFLR_CB2_SHIFT 16L
-#define CFLR_CB3_SHIFT 24L
-
-#define IOTCR_DMA0 0x00000000L
-#define IOTCR_DMA1 0x00000400L
-#define IOTCR_DMA2 0x00000800L
-#define IOTCR_DMA3 0x00000C00L
-#define IOTCR_CCLS 0x00000100L
-#define IOTCR_PCPCI 0x00000200L
-#define IOTCR_DDMA 0x00000300L
-
-#define SBWBS_WBB 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the SRC Slot Assignment Register
-// (SRCSA)
-//
-//****************************************************************************
-#define SRCSA_PLSS_MASK 0x0000001FL
-#define SRCSA_PLSS_SHIFT 0L
-#define SRCSA_PRSS_MASK 0x00001F00L
-#define SRCSA_PRSS_SHIFT 8L
-#define SRCSA_CLSS_MASK 0x001F0000L
-#define SRCSA_CLSS_SHIFT 16L
-#define SRCSA_CRSS_MASK 0x1F000000L
-#define SRCSA_CRSS_SHIFT 24L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound System Power Management
-// register.(SSPM)
-//
-//****************************************************************************
-#define SSPM_FPDN 0x00000080L
-#define SSPM_MIXEN 0x00000040L
-#define SSPM_CSRCEN 0x00000020L
-#define SSPM_PSRCEN 0x00000010L
-#define SSPM_JSEN 0x00000008L
-#define SSPM_ACLEN 0x00000004L
-#define SSPM_FMEN 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound System Control
-// Register. (SSCR)
-//
-//****************************************************************************
-#define SSCR_SB 0x00000004L
-#define SSCR_HVC 0x00000008L
-#define SSCR_LPFIFO 0x00000040L
-#define SSCR_LPSRC 0x00000080L
-#define SSCR_XLPSRC 0x00000100L
-#define SSCR_MVMD 0x00010000L
-#define SSCR_MVAD 0x00020000L
-#define SSCR_MVLD 0x00040000L
-#define SSCR_MVCS 0x00080000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Clock Control Register 1.
-// (CLKCR1)
-//
-//****************************************************************************
-#define CLKCR1_DLLSS_MASK 0x0000000CL
-#define CLKCR1_DLLSS_SHIFT 2L
-#define CLKCR1_DLLP 0x00000010L
-#define CLKCR1_SWCE 0x00000020L
-#define CLKCR1_DLLOS 0x00000040L
-#define CLKCR1_CKRA 0x00010000L
-#define CLKCR1_CKRN 0x00020000L
-#define CLKCR1_DLLRDY 0x01000000L
-#define CLKCR1_CLKON 0x02000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the Sound Blaster Read Buffer
-// Status.(SBRBS)
-//
-//****************************************************************************
-#define SBRBS_RD_MASK 0x0000007FL
-#define SBRBS_RD_SHIFT 0L
-#define SBRBS_RBF 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port master control
-// register.(SERMC)
-//
-//****************************************************************************
-#define SERMC_MSPE 0x00000001L
-#define SERMC_PTC_MASK 0x0000000EL
-#define SERMC_PTC_SHIFT 1L
-#define SERMC_PTC_AC97 0x00000002L
-#define SERMC_PLB 0x00000010L
-#define SERMC_PXLB 0x00000020L
-#define SERMC_LOFV 0x00080000L
-#define SERMC_SLB 0x00100000L
-#define SERMC_SXLB 0x00200000L
-#define SERMC_ODSEN1 0x01000000L
-#define SERMC_ODSEN2 0x02000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the General Purpose I/O Register.
-// (GPIOR)
-//
-//****************************************************************************
-#define GPIOR_VDNS 0x00000001L
-#define GPIOR_VUPS 0x00000002L
-#define GPIOR_GP1S 0x00000004L
-#define GPIOR_GP3S 0x00000008L
-#define GPIOR_GPSS 0x00000010L
-#define GPIOR_GPPS 0x00000020L
-#define GPIOR_GP1D 0x00000400L
-#define GPIOR_GP3D 0x00000800L
-#define GPIOR_VDNLT 0x00010000L
-#define GPIOR_VDNPO 0x00020000L
-#define GPIOR_VDNST 0x00040000L
-#define GPIOR_VDNW 0x00080000L
-#define GPIOR_VUPLT 0x00100000L
-#define GPIOR_VUPPO 0x00200000L
-#define GPIOR_VUPST 0x00400000L
-#define GPIOR_VUPW 0x00800000L
-#define GPIOR_GP1OE 0x01000000L
-#define GPIOR_GP1PT 0x02000000L
-#define GPIOR_GP1ST 0x04000000L
-#define GPIOR_GP1W 0x08000000L
-#define GPIOR_GP3OE 0x10000000L
-#define GPIOR_GP3PT 0x20000000L
-#define GPIOR_GP3ST 0x40000000L
-#define GPIOR_GP3W 0x80000000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the clock control register 1.
-//
-//****************************************************************************
-#define CLKCR1_PLLSS_MASK 0x0000000CL
-#define CLKCR1_PLLSS_SERIAL 0x00000000L
-#define CLKCR1_PLLSS_CRYSTAL 0x00000004L
-#define CLKCR1_PLLSS_PCI 0x00000008L
-#define CLKCR1_PLLSS_RESERVED 0x0000000CL
-#define CLKCR1_PLLP 0x00000010L
-#define CLKCR1_SWCE 0x00000020L
-#define CLKCR1_PLLOS 0x00000040L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the feature reporting register.
-//
-//****************************************************************************
-#define FRR_FAB_MASK 0x00000003L
-#define FRR_MASK_MASK 0x0000001CL
-#define FRR_ID_MASK 0x00003000L
-#define FRR_FAB_SHIFT 0L
-#define FRR_MASK_SHIFT 2L
-#define FRR_ID_SHIFT 12L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port 1 configuration
-// register.
-//
-//****************************************************************************
-#define SERC1_VALUE 0x00000003L
-#define SERC1_SO1EN 0x00000001L
-#define SERC1_SO1F_MASK 0x0000000EL
-#define SERC1_SO1F_CS423X 0x00000000L
-#define SERC1_SO1F_AC97 0x00000002L
-#define SERC1_SO1F_DAC 0x00000004L
-#define SERC1_SO1F_SPDIF 0x00000006L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the serial port 2 configuration
-// register.
-//
-//****************************************************************************
-#define SERC2_VALUE 0x00000003L
-#define SERC2_SI1EN 0x00000001L
-#define SERC2_SI1F_MASK 0x0000000EL
-#define SERC2_SI1F_CS423X 0x00000000L
-#define SERC2_SI1F_AC97 0x00000002L
-#define SERC2_SI1F_ADC 0x00000004L
-#define SERC2_SI1F_SPDIF 0x00000006L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 control register.
-//
-//****************************************************************************
-#define ACCTL_ESYN 0x00000002L
-#define ACCTL_VFRM 0x00000004L
-#define ACCTL_DCV 0x00000008L
-#define ACCTL_CRW 0x00000010L
-#define ACCTL_TC 0x00000040L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status register.
-//
-//****************************************************************************
-#define ACSTS_CRDY 0x00000001L
-#define ACSTS_VSTS 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 output slot valid
-// register.
-//
-//****************************************************************************
-#define ACOSV_SLV3 0x00000001L
-#define ACOSV_SLV4 0x00000002L
-#define ACOSV_SLV5 0x00000004L
-#define ACOSV_SLV6 0x00000008L
-#define ACOSV_SLV7 0x00000010L
-#define ACOSV_SLV8 0x00000020L
-#define ACOSV_SLV9 0x00000040L
-#define ACOSV_SLV10 0x00000080L
-#define ACOSV_SLV11 0x00000100L
-#define ACOSV_SLV12 0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 command address
-// register.
-//
-//****************************************************************************
-#define ACCAD_CI_MASK 0x0000007FL
-#define ACCAD_CI_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 command data register.
-//
-//****************************************************************************
-#define ACCDA_CD_MASK 0x0000FFFFL
-#define ACCDA_CD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 input slot valid
-// register.
-//
-//****************************************************************************
-#define ACISV_ISV3 0x00000001L
-#define ACISV_ISV4 0x00000002L
-#define ACISV_ISV5 0x00000004L
-#define ACISV_ISV6 0x00000008L
-#define ACISV_ISV7 0x00000010L
-#define ACISV_ISV8 0x00000020L
-#define ACISV_ISV9 0x00000040L
-#define ACISV_ISV10 0x00000080L
-#define ACISV_ISV11 0x00000100L
-#define ACISV_ISV12 0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status address
-// register.
-//
-//****************************************************************************
-#define ACSAD_SI_MASK 0x0000007FL
-#define ACSAD_SI_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status data register.
-//
-//****************************************************************************
-#define ACSDA_SD_MASK 0x0000FFFFL
-#define ACSDA_SD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers (all 12).
-//
-//****************************************************************************
-#define IOTAC_SA_MASK 0x0000FFFFL
-#define IOTAC_MSK_MASK 0x000F0000L
-#define IOTAC_IODC_MASK 0x06000000L
-#define IOTAC_IODC_16_BIT 0x00000000L
-#define IOTAC_IODC_10_BIT 0x02000000L
-#define IOTAC_IODC_12_BIT 0x04000000L
-#define IOTAC_WSPI 0x08000000L
-#define IOTAC_RSPI 0x10000000L
-#define IOTAC_WSE 0x20000000L
-#define IOTAC_WE 0x40000000L
-#define IOTAC_RE 0x80000000L
-#define IOTAC_SA_SHIFT 0L
-#define IOTAC_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI master enable
-// register.
-//
-//****************************************************************************
-#define PCPCIEN_EN 0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the joystick poll/trigger
-// register.
-//
-//****************************************************************************
-#define JSPT_CAX 0x00000001L
-#define JSPT_CAY 0x00000002L
-#define JSPT_CBX 0x00000004L
-#define JSPT_CBY 0x00000008L
-#define JSPT_BA1 0x00000010L
-#define JSPT_BA2 0x00000020L
-#define JSPT_BB1 0x00000040L
-#define JSPT_BB2 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the joystick control register.
-// The TBF bit has been moved from MIDSR register to JSCTL register bit 8.
-//
-//****************************************************************************
-#define JSCTL_SP_MASK 0x00000003L
-#define JSCTL_SP_SLOW 0x00000000L
-#define JSCTL_SP_MEDIUM_SLOW 0x00000001L
-#define JSCTL_SP_MEDIUM_FAST 0x00000002L
-#define JSCTL_SP_FAST 0x00000003L
-#define JSCTL_ARE 0x00000004L
-#define JSCTL_TBF 0x00000100L
-
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI control register.
-//
-//****************************************************************************
-#define MIDCR_TXE 0x00000001L
-#define MIDCR_RXE 0x00000002L
-#define MIDCR_RIE 0x00000004L
-#define MIDCR_TIE 0x00000008L
-#define MIDCR_MLB 0x00000010L
-#define MIDCR_MRST 0x00000020L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI status register.
-//
-//****************************************************************************
-#define MIDSR_RBE 0x00000080L
-#define MIDSR_RDA 0x00008000L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI write port register.
-//
-//****************************************************************************
-#define MIDWP_MWD_MASK 0x000000FFL
-#define MIDWP_MWD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the MIDI read port register.
-//
-//****************************************************************************
-#define MIDRP_MRD_MASK 0x000000FFL
-#define MIDRP_MRD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the configuration interface
-// register.
-//
-//****************************************************************************
-#define CFGI_CLK 0x00000001L
-#define CFGI_DOUT 0x00000002L
-#define CFGI_DIN_EEN 0x00000004L
-#define CFGI_EELD 0x00000008L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the subsystem ID and vendor ID
-// register.
-//
-//****************************************************************************
-#define SSVID_VID_MASK 0x0000FFFFL
-#define SSVID_SID_MASK 0xFFFF0000L
-#define SSVID_VID_SHIFT 0L
-#define SSVID_SID_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the GPIO pin interface register.
-//
-//****************************************************************************
-#define GPIOR_VOLDN 0x00000001L
-#define GPIOR_VOLUP 0x00000002L
-#define GPIOR_SI2D 0x00000004L
-#define GPIOR_SI2OE 0x00000008L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status register 2.
-//
-//****************************************************************************
-#define ACSTS2_CRDY 0x00000001L
-#define ACSTS2_VSTS 0x00000002L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 input slot valid
-// register 2.
-//
-//****************************************************************************
-#define ACISV2_ISV3 0x00000001L
-#define ACISV2_ISV4 0x00000002L
-#define ACISV2_ISV5 0x00000004L
-#define ACISV2_ISV6 0x00000008L
-#define ACISV2_ISV7 0x00000010L
-#define ACISV2_ISV8 0x00000020L
-#define ACISV2_ISV9 0x00000040L
-#define ACISV2_ISV10 0x00000080L
-#define ACISV2_ISV11 0x00000100L
-#define ACISV2_ISV12 0x00000200L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status address
-// register 2.
-//
-//****************************************************************************
-#define ACSAD2_SI_MASK 0x0000007FL
-#define ACSAD2_SI_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 status data register 2.
-//
-//****************************************************************************
-#define ACSDA2_SD_MASK 0x0000FFFFL
-#define ACSDA2_SD_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap control register.
-//
-//****************************************************************************
-#define IOTCR_ITD 0x00000001L
-#define IOTCR_HRV 0x00000002L
-#define IOTCR_SRV 0x00000004L
-#define IOTCR_DTI 0x00000008L
-#define IOTCR_DFI 0x00000010L
-#define IOTCR_DDP 0x00000020L
-#define IOTCR_JTE 0x00000040L
-#define IOTCR_PPE 0x00000080L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for Hardware Master Volume.
-//
-//****************************************************************************
-#define IOTGP_SA_MASK 0x0000FFFFL
-#define IOTGP_MSK_MASK 0x000F0000L
-#define IOTGP_IODC_MASK 0x06000000L
-#define IOTGP_IODC_16_BIT 0x00000000L
-#define IOTGP_IODC_10_BIT 0x02000000L
-#define IOTGP_IODC_12_BIT 0x04000000L
-#define IOTGP_WSPI 0x08000000L
-#define IOTGP_RSPI 0x10000000L
-#define IOTGP_WSE 0x20000000L
-#define IOTGP_WE 0x40000000L
-#define IOTGP_RE 0x80000000L
-#define IOTGP_SA_SHIFT 0L
-#define IOTGP_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for Sound Blaster
-//
-//****************************************************************************
-#define IOTSB_SA_MASK 0x0000FFFFL
-#define IOTSB_MSK_MASK 0x000F0000L
-#define IOTSB_IODC_MASK 0x06000000L
-#define IOTSB_IODC_16_BIT 0x00000000L
-#define IOTSB_IODC_10_BIT 0x02000000L
-#define IOTSB_IODC_12_BIT 0x04000000L
-#define IOTSB_WSPI 0x08000000L
-#define IOTSB_RSPI 0x10000000L
-#define IOTSB_WSE 0x20000000L
-#define IOTSB_WE 0x40000000L
-#define IOTSB_RE 0x80000000L
-#define IOTSB_SA_SHIFT 0L
-#define IOTSB_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the I/O trap address and control
-// registers for FM.
-//
-//****************************************************************************
-#define IOTFM_SA_MASK 0x0000FFFFL
-#define IOTFM_MSK_MASK 0x000F0000L
-#define IOTFM_IODC_MASK 0x06000000L
-#define IOTFM_IODC_16_BIT 0x00000000L
-#define IOTFM_IODC_10_BIT 0x02000000L
-#define IOTFM_IODC_12_BIT 0x04000000L
-#define IOTFM_WSPI 0x08000000L
-#define IOTFM_RSPI 0x10000000L
-#define IOTFM_WSE 0x20000000L
-#define IOTFM_WE 0x40000000L
-#define IOTFM_RE 0x80000000L
-#define IOTFM_SA_SHIFT 0L
-#define IOTFM_MSK_SHIFT 16L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI request register.
-//
-//****************************************************************************
-#define PCPRR_RDC_MASK 0x00000007L
-#define PCPRR_REQ 0x00008000L
-#define PCPRR_RDC_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI grant register.
-//
-//****************************************************************************
-#define PCPGR_GDC_MASK 0x00000007L
-#define PCPGR_VL 0x00008000L
-#define PCPGR_GDC_SHIFT 0L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the PC/PCI Control Register.
-//
-//****************************************************************************
-#define PCPCR_EN 0x00000001L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the debug index register.
-//
-//****************************************************************************
-#define DREG_REGID_MASK 0x0000007FL
-#define DREG_DEBUG 0x00000080L
-#define DREG_RGBK_MASK 0x00000700L
-#define DREG_TRAP 0x00000800L
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_TRAPX 0x00001000L
-#endif
-#endif
-#define DREG_REGID_SHIFT 0L
-#define DREG_RGBK_SHIFT 8L
-#define DREG_RGBK_REGID_MASK 0x0000077FL
-#define DREG_REGID_R0 0x00000010L
-#define DREG_REGID_R1 0x00000011L
-#define DREG_REGID_R2 0x00000012L
-#define DREG_REGID_R3 0x00000013L
-#define DREG_REGID_R4 0x00000014L
-#define DREG_REGID_R5 0x00000015L
-#define DREG_REGID_R6 0x00000016L
-#define DREG_REGID_R7 0x00000017L
-#define DREG_REGID_R8 0x00000018L
-#define DREG_REGID_R9 0x00000019L
-#define DREG_REGID_RA 0x0000001AL
-#define DREG_REGID_RB 0x0000001BL
-#define DREG_REGID_RC 0x0000001CL
-#define DREG_REGID_RD 0x0000001DL
-#define DREG_REGID_RE 0x0000001EL
-#define DREG_REGID_RF 0x0000001FL
-#define DREG_REGID_RA_BUS_LOW 0x00000020L
-#define DREG_REGID_RA_BUS_HIGH 0x00000038L
-#define DREG_REGID_YBUS_LOW 0x00000050L
-#define DREG_REGID_YBUS_HIGH 0x00000058L
-#define DREG_REGID_TRAP_0 0x00000100L
-#define DREG_REGID_TRAP_1 0x00000101L
-#define DREG_REGID_TRAP_2 0x00000102L
-#define DREG_REGID_TRAP_3 0x00000103L
-#define DREG_REGID_TRAP_4 0x00000104L
-#define DREG_REGID_TRAP_5 0x00000105L
-#define DREG_REGID_TRAP_6 0x00000106L
-#define DREG_REGID_TRAP_7 0x00000107L
-#define DREG_REGID_INDIRECT_ADDRESS 0x0000010EL
-#define DREG_REGID_TOP_OF_STACK 0x0000010FL
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_8 0x00000110L
-#define DREG_REGID_TRAP_9 0x00000111L
-#define DREG_REGID_TRAP_10 0x00000112L
-#define DREG_REGID_TRAP_11 0x00000113L
-#define DREG_REGID_TRAP_12 0x00000114L
-#define DREG_REGID_TRAP_13 0x00000115L
-#define DREG_REGID_TRAP_14 0x00000116L
-#define DREG_REGID_TRAP_15 0x00000117L
-#define DREG_REGID_TRAP_16 0x00000118L
-#define DREG_REGID_TRAP_17 0x00000119L
-#define DREG_REGID_TRAP_18 0x0000011AL
-#define DREG_REGID_TRAP_19 0x0000011BL
-#define DREG_REGID_TRAP_20 0x0000011CL
-#define DREG_REGID_TRAP_21 0x0000011DL
-#define DREG_REGID_TRAP_22 0x0000011EL
-#define DREG_REGID_TRAP_23 0x0000011FL
-#endif
-#endif
-#define DREG_REGID_RSA0_LOW 0x00000200L
-#define DREG_REGID_RSA0_HIGH 0x00000201L
-#define DREG_REGID_RSA1_LOW 0x00000202L
-#define DREG_REGID_RSA1_HIGH 0x00000203L
-#define DREG_REGID_RSA2 0x00000204L
-#define DREG_REGID_RSA3 0x00000205L
-#define DREG_REGID_RSI0_LOW 0x00000206L
-#define DREG_REGID_RSI0_HIGH 0x00000207L
-#define DREG_REGID_RSI1 0x00000208L
-#define DREG_REGID_RSI2 0x00000209L
-#define DREG_REGID_SAGUSTATUS 0x0000020AL
-#define DREG_REGID_RSCONFIG01_LOW 0x0000020BL
-#define DREG_REGID_RSCONFIG01_HIGH 0x0000020CL
-#define DREG_REGID_RSCONFIG23_LOW 0x0000020DL
-#define DREG_REGID_RSCONFIG23_HIGH 0x0000020EL
-#define DREG_REGID_RSDMA01E 0x0000020FL
-#define DREG_REGID_RSDMA23E 0x00000210L
-#define DREG_REGID_RSD0_LOW 0x00000211L
-#define DREG_REGID_RSD0_HIGH 0x00000212L
-#define DREG_REGID_RSD1_LOW 0x00000213L
-#define DREG_REGID_RSD1_HIGH 0x00000214L
-#define DREG_REGID_RSD2_LOW 0x00000215L
-#define DREG_REGID_RSD2_HIGH 0x00000216L
-#define DREG_REGID_RSD3_LOW 0x00000217L
-#define DREG_REGID_RSD3_HIGH 0x00000218L
-#define DREG_REGID_SRAR_HIGH 0x0000021AL
-#define DREG_REGID_SRAR_LOW 0x0000021BL
-#define DREG_REGID_DMA_STATE 0x0000021CL
-#define DREG_REGID_CURRENT_DMA_STREAM 0x0000021DL
-#define DREG_REGID_NEXT_DMA_STREAM 0x0000021EL
-#define DREG_REGID_CPU_STATUS 0x00000300L
-#define DREG_REGID_MAC_MODE 0x00000301L
-#define DREG_REGID_STACK_AND_REPEAT 0x00000302L
-#define DREG_REGID_INDEX0 0x00000304L
-#define DREG_REGID_INDEX1 0x00000305L
-#define DREG_REGID_DMA_STATE_0_3 0x00000400L
-#define DREG_REGID_DMA_STATE_4_7 0x00000404L
-#define DREG_REGID_DMA_STATE_8_11 0x00000408L
-#define DREG_REGID_DMA_STATE_12_15 0x0000040CL
-#define DREG_REGID_DMA_STATE_16_19 0x00000410L
-#define DREG_REGID_DMA_STATE_20_23 0x00000414L
-#define DREG_REGID_DMA_STATE_24_27 0x00000418L
-#define DREG_REGID_DMA_STATE_28_31 0x0000041CL
-#define DREG_REGID_DMA_STATE_32_35 0x00000420L
-#define DREG_REGID_DMA_STATE_36_39 0x00000424L
-#define DREG_REGID_DMA_STATE_40_43 0x00000428L
-#define DREG_REGID_DMA_STATE_44_47 0x0000042CL
-#define DREG_REGID_DMA_STATE_48_51 0x00000430L
-#define DREG_REGID_DMA_STATE_52_55 0x00000434L
-#define DREG_REGID_DMA_STATE_56_59 0x00000438L
-#define DREG_REGID_DMA_STATE_60_63 0x0000043CL
-#define DREG_REGID_DMA_STATE_64_67 0x00000440L
-#define DREG_REGID_DMA_STATE_68_71 0x00000444L
-#define DREG_REGID_DMA_STATE_72_75 0x00000448L
-#define DREG_REGID_DMA_STATE_76_79 0x0000044CL
-#define DREG_REGID_DMA_STATE_80_83 0x00000450L
-#define DREG_REGID_DMA_STATE_84_87 0x00000454L
-#define DREG_REGID_DMA_STATE_88_91 0x00000458L
-#define DREG_REGID_DMA_STATE_92_95 0x0000045CL
-#define DREG_REGID_TRAP_SELECT 0x00000500L
-#define DREG_REGID_TRAP_WRITE_0 0x00000500L
-#define DREG_REGID_TRAP_WRITE_1 0x00000501L
-#define DREG_REGID_TRAP_WRITE_2 0x00000502L
-#define DREG_REGID_TRAP_WRITE_3 0x00000503L
-#define DREG_REGID_TRAP_WRITE_4 0x00000504L
-#define DREG_REGID_TRAP_WRITE_5 0x00000505L
-#define DREG_REGID_TRAP_WRITE_6 0x00000506L
-#define DREG_REGID_TRAP_WRITE_7 0x00000507L
-#if !defined(NO_CS4612)
-#if !defined(NO_CS4615)
-#define DREG_REGID_TRAP_WRITE_8 0x00000510L
-#define DREG_REGID_TRAP_WRITE_9 0x00000511L
-#define DREG_REGID_TRAP_WRITE_10 0x00000512L
-#define DREG_REGID_TRAP_WRITE_11 0x00000513L
-#define DREG_REGID_TRAP_WRITE_12 0x00000514L
-#define DREG_REGID_TRAP_WRITE_13 0x00000515L
-#define DREG_REGID_TRAP_WRITE_14 0x00000516L
-#define DREG_REGID_TRAP_WRITE_15 0x00000517L
-#define DREG_REGID_TRAP_WRITE_16 0x00000518L
-#define DREG_REGID_TRAP_WRITE_17 0x00000519L
-#define DREG_REGID_TRAP_WRITE_18 0x0000051AL
-#define DREG_REGID_TRAP_WRITE_19 0x0000051BL
-#define DREG_REGID_TRAP_WRITE_20 0x0000051CL
-#define DREG_REGID_TRAP_WRITE_21 0x0000051DL
-#define DREG_REGID_TRAP_WRITE_22 0x0000051EL
-#define DREG_REGID_TRAP_WRITE_23 0x0000051FL
-#endif
-#endif
-#define DREG_REGID_MAC0_ACC0_LOW 0x00000600L
-#define DREG_REGID_MAC0_ACC1_LOW 0x00000601L
-#define DREG_REGID_MAC0_ACC2_LOW 0x00000602L
-#define DREG_REGID_MAC0_ACC3_LOW 0x00000603L
-#define DREG_REGID_MAC1_ACC0_LOW 0x00000604L
-#define DREG_REGID_MAC1_ACC1_LOW 0x00000605L
-#define DREG_REGID_MAC1_ACC2_LOW 0x00000606L
-#define DREG_REGID_MAC1_ACC3_LOW 0x00000607L
-#define DREG_REGID_MAC0_ACC0_MID 0x00000608L
-#define DREG_REGID_MAC0_ACC1_MID 0x00000609L
-#define DREG_REGID_MAC0_ACC2_MID 0x0000060AL
-#define DREG_REGID_MAC0_ACC3_MID 0x0000060BL
-#define DREG_REGID_MAC1_ACC0_MID 0x0000060CL
-#define DREG_REGID_MAC1_ACC1_MID 0x0000060DL
-#define DREG_REGID_MAC1_ACC2_MID 0x0000060EL
-#define DREG_REGID_MAC1_ACC3_MID 0x0000060FL
-#define DREG_REGID_MAC0_ACC0_HIGH 0x00000610L
-#define DREG_REGID_MAC0_ACC1_HIGH 0x00000611L
-#define DREG_REGID_MAC0_ACC2_HIGH 0x00000612L
-#define DREG_REGID_MAC0_ACC3_HIGH 0x00000613L
-#define DREG_REGID_MAC1_ACC0_HIGH 0x00000614L
-#define DREG_REGID_MAC1_ACC1_HIGH 0x00000615L
-#define DREG_REGID_MAC1_ACC2_HIGH 0x00000616L
-#define DREG_REGID_MAC1_ACC3_HIGH 0x00000617L
-#define DREG_REGID_RSHOUT_LOW 0x00000620L
-#define DREG_REGID_RSHOUT_MID 0x00000628L
-#define DREG_REGID_RSHOUT_HIGH 0x00000630L
-
-//****************************************************************************
-//
-// The following defines are for the flags in the AC97 S/PDIF Control register.
-//
-//****************************************************************************
-#define SPDIF_CONTROL_SPDIF_EN 0x00008000L
-#define SPDIF_CONTROL_VAL 0x00004000L
-#define SPDIF_CONTROL_COPY 0x00000004L
-#define SPDIF_CONTROL_CC0 0x00000010L
-#define SPDIF_CONTROL_CC1 0x00000020L
-#define SPDIF_CONTROL_CC2 0x00000040L
-#define SPDIF_CONTROL_CC3 0x00000080L
-#define SPDIF_CONTROL_CC4 0x00000100L
-#define SPDIF_CONTROL_CC5 0x00000200L
-#define SPDIF_CONTROL_CC6 0x00000400L
-#define SPDIF_CONTROL_L 0x00000800L
-
-#endif // _H_HWDEFS
diff --git a/sound/oss/cs4281/cs4281_wrapper-24.c b/sound/oss/cs4281/cs4281_wrapper-24.c
deleted file mode 100644
index 4559f02c9969..000000000000
--- a/sound/oss/cs4281/cs4281_wrapper-24.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*******************************************************************************
-*
-* "cs4281_wrapper.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* 12/20/00 trw - new file.
-*
-*******************************************************************************/
-
-#include <linux/spinlock.h>
-
-static int cs4281_resume_null(struct pci_dev *pcidev) { return 0; }
-static int cs4281_suspend_null(struct pci_dev *pcidev, pm_message_t state) { return 0; }
-
-#define free_dmabuf(state, dmabuf) \
- pci_free_consistent(state->pcidev, \
- PAGE_SIZE << (dmabuf)->buforder, \
- (dmabuf)->rawbuf, (dmabuf)->dmaaddr);
-#define free_dmabuf2(state, dmabuf) \
- pci_free_consistent((state)->pcidev, \
- PAGE_SIZE << (state)->buforder_tmpbuff, \
- (state)->tmpbuff, (state)->dmaaddr_tmpbuff);
-#define cs4x_pgoff(vma) ((vma)->vm_pgoff)
-
diff --git a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
deleted file mode 100644
index 0400a416dc93..000000000000
--- a/sound/oss/cs4281/cs4281m.c
+++ /dev/null
@@ -1,4487 +0,0 @@
-/*******************************************************************************
-*
-* "cs4281.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- adapted from drivers by Thomas Sailer,
-* -- but don't bug him; Problems should go to:
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* Module command line parameters:
-* none
-*
-* Supported devices:
-* /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
-* /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
-* /dev/midi simple MIDI UART interface, no ioctl
-*
-* Modification History
-* 08/20/00 trw - silence and no stopping DAC until release
-* 08/23/00 trw - added CS_DBG statements, fix interrupt hang issue on DAC stop.
-* 09/18/00 trw - added 16bit only record with conversion
-* 09/24/00 trw - added Enhanced Full duplex (separate simultaneous
-* capture/playback rates)
-* 10/03/00 trw - fixed mmap (fixed GRECORD and the XMMS mmap test plugin
-* libOSSm.so)
-* 10/11/00 trw - modified for 2.4.0-test9 kernel enhancements (NR_MAP removal)
-* 11/03/00 trw - fixed interrupt loss/stutter, added debug.
-* 11/10/00 bkz - added __devinit to cs4281_hw_init()
-* 11/10/00 trw - fixed SMP and capture spinlock hang.
-* 12/04/00 trw - cleaned up CSDEBUG flags and added "defaultorder" moduleparm.
-* 12/05/00 trw - fixed polling (myth2), and added underrun swptr fix.
-* 12/08/00 trw - added PM support.
-* 12/14/00 trw - added wrapper code, builds under 2.4.0, 2.2.17-20, 2.2.17-8
-* (RH/Dell base), 2.2.18, 2.2.12. cleaned up code mods by ident.
-* 12/19/00 trw - added PM support for 2.2 base (apm_callback). other PM cleanup.
-* 12/21/00 trw - added fractional "defaultorder" inputs. if >100 then use
-* defaultorder-100 as power of 2 for the buffer size. example:
-* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
-*
-*******************************************************************************/
-
-/* uncomment the following line to disable building PM support into the driver */
-//#define NOT_CS4281_PM 1
-
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/wait.h>
-
-#include <asm/current.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-//#include "cs_dm.h"
-#include "cs4281_hwdefs.h"
-#include "cs4281pm.h"
-
-struct cs4281_state;
-
-static void stop_dac(struct cs4281_state *s);
-static void stop_adc(struct cs4281_state *s);
-static void start_dac(struct cs4281_state *s);
-static void start_adc(struct cs4281_state *s);
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-// ---------------------------------------------------------------------
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CRYSTAL_CS4281
-#define PCI_DEVICE_ID_CRYSTAL_CS4281 0x6005
-#endif
-
-#define CS4281_MAGIC ((PCI_DEVICE_ID_CRYSTAL_CS4281<<16) | PCI_VENDOR_ID_CIRRUS)
-#define CS4281_CFLR_DEFAULT 0x00000001 /* CFLR must be in AC97 link mode */
-
-// buffer order determines the size of the dma buffer for the driver.
-// under Linux, a smaller buffer allows more responsiveness from many of the
-// applications (e.g. games). A larger buffer allows some of the apps (esound)
-// to not underrun the dma buffer as easily. As default, use 32k (order=3)
-// rather than 64k as some of the games work more responsively.
-// log base 2( buff sz = 32k).
-static unsigned long defaultorder = 3;
-module_param(defaultorder, ulong, 0);
-
-//
-// Turn on/off debugging compilation by commenting out "#define CSDEBUG"
-//
-#define CSDEBUG 1
-#if CSDEBUG
-#define CSDEBUG_INTERFACE 1
-#else
-#undef CSDEBUG_INTERFACE
-#endif
-//
-// cs_debugmask areas
-//
-#define CS_INIT 0x00000001 // initialization and probe functions
-#define CS_ERROR 0x00000002 // tmp debugging bit placeholder
-#define CS_INTERRUPT 0x00000004 // interrupt handler (separate from all other)
-#define CS_FUNCTION 0x00000008 // enter/leave functions
-#define CS_WAVE_WRITE 0x00000010 // write information for wave
-#define CS_WAVE_READ 0x00000020 // read information for wave
-#define CS_MIDI_WRITE 0x00000040 // write information for midi
-#define CS_MIDI_READ 0x00000080 // read information for midi
-#define CS_MPU401_WRITE 0x00000100 // write information for mpu401
-#define CS_MPU401_READ 0x00000200 // read information for mpu401
-#define CS_OPEN 0x00000400 // all open functions in the driver
-#define CS_RELEASE 0x00000800 // all release functions in the driver
-#define CS_PARMS 0x00001000 // functional and operational parameters
-#define CS_IOCTL 0x00002000 // ioctl (non-mixer)
-#define CS_PM 0x00004000 // power management
-#define CS_TMP 0x10000000 // tmp debug mask bit
-
-#define CS_IOCTL_CMD_SUSPEND 0x1 // suspend
-#define CS_IOCTL_CMD_RESUME 0x2 // resume
-//
-// CSDEBUG is usual mode is set to 1, then use the
-// cs_debuglevel and cs_debugmask to turn on or off debugging.
-// Debug level of 1 has been defined to be kernel errors and info
-// that should be printed on any released driver.
-//
-#if CSDEBUG
-#define CS_DBGOUT(mask,level,x) if((cs_debuglevel >= (level)) && ((mask) & cs_debugmask) ) {x;}
-#else
-#define CS_DBGOUT(mask,level,x)
-#endif
-
-#if CSDEBUG
-static unsigned long cs_debuglevel = 1; // levels range from 1-9
-static unsigned long cs_debugmask = CS_INIT | CS_ERROR; // use CS_DBGOUT with various mask values
-module_param(cs_debuglevel, ulong, 0);
-module_param(cs_debugmask, ulong, 0);
-#endif
-#define CS_TRUE 1
-#define CS_FALSE 0
-
-// MIDI buffer sizes
-#define MIDIINBUF 500
-#define MIDIOUTBUF 500
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define CS4281_MAJOR_VERSION 1
-#define CS4281_MINOR_VERSION 13
-#ifdef __ia64__
-#define CS4281_ARCH 64 //architecture key
-#else
-#define CS4281_ARCH 32 //architecture key
-#endif
-
-#define CS_TYPE_ADC 0
-#define CS_TYPE_DAC 1
-
-
-static const char invalid_magic[] =
- KERN_CRIT "cs4281: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != CS4281_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-//LIST_HEAD(cs4281_devs);
-static struct list_head cs4281_devs = { &cs4281_devs, &cs4281_devs };
-
-struct cs4281_state;
-
-#include "cs4281_wrapper-24.c"
-
-struct cs4281_state {
- // magic
- unsigned int magic;
-
- // we keep the cards in a linked list
- struct cs4281_state *next;
-
- // pcidev is needed to turn off the DDMA controller at driver shutdown
- struct pci_dev *pcidev;
- struct list_head list;
-
- // soundcore stuff
- int dev_audio;
- int dev_mixer;
- int dev_midi;
-
- // hardware resources
- unsigned int pBA0phys, pBA1phys;
- char __iomem *pBA0;
- char __iomem *pBA1;
- unsigned int irq;
-
- // mixer registers
- struct {
- unsigned short vol[10];
- unsigned int recsrc;
- unsigned int modcnt;
- unsigned short micpreamp;
- } mix;
-
- // wave stuff
- struct properties {
- unsigned fmt;
- unsigned fmt_original; // original requested format
- unsigned channels;
- unsigned rate;
- unsigned char clkdiv;
- } prop_dac, prop_adc;
- unsigned conversion:1; // conversion from 16 to 8 bit in progress
- void *tmpbuff; // tmp buffer for sample conversions
- unsigned ena;
- spinlock_t lock;
- struct mutex open_sem;
- struct mutex open_sem_adc;
- struct mutex open_sem_dac;
- mode_t open_mode;
- wait_queue_head_t open_wait;
- wait_queue_head_t open_wait_adc;
- wait_queue_head_t open_wait_dac;
-
- dma_addr_t dmaaddr_tmpbuff;
- unsigned buforder_tmpbuff; // Log base 2 of 'rawbuf' size in bytes..
- struct dmabuf {
- void *rawbuf; // Physical address of
- dma_addr_t dmaaddr;
- unsigned buforder; // Log base 2 of 'rawbuf' size in bytes..
- unsigned numfrag; // # of 'fragments' in the buffer.
- unsigned fragshift; // Log base 2 of fragment size.
- unsigned hwptr, swptr;
- unsigned total_bytes; // # bytes process since open.
- unsigned blocks; // last returned blocks value GETOPTR
- unsigned wakeup; // interrupt occurred on block
- int count;
- unsigned underrun; // underrun flag
- unsigned error; // over/underrun
- wait_queue_head_t wait;
- // redundant, but makes calculations easier
- unsigned fragsize; // 2**fragshift..
- unsigned dmasize; // 2**buforder.
- unsigned fragsamples;
- // OSS stuff
- unsigned mapped:1; // Buffer mapped in cs4281_mmap()?
- unsigned ready:1; // prog_dmabuf_dac()/adc() successful?
- unsigned endcleared:1;
- unsigned type:1; // adc or dac buffer (CS_TYPE_XXX)
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-
- // midi stuff
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- struct timer_list timer;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
- struct cs4281_pm pm;
- struct cs4281_pipeline pl[CS4281_NUMBER_OF_PIPELINES];
-};
-
-#include "cs4281pm-24.c"
-
-#if CSDEBUG
-
-// DEBUG ROUTINES
-
-#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int)
-#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int)
-#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int)
-#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int)
-
-#define SOUND_MIXER_CS_APM _SIOWR('M',124, int)
-
-
-static void cs_printioctl(unsigned int x)
-{
- unsigned int i;
- unsigned char vidx;
- // Index of mixtable1[] member is Device ID
- // and must be <= SOUND_MIXER_NRDEVICES.
- // Value of array member is index into s->mix.vol[]
- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, // voice
- [SOUND_MIXER_LINE1] = 2, // AUX
- [SOUND_MIXER_CD] = 3, // CD
- [SOUND_MIXER_LINE] = 4, // Line
- [SOUND_MIXER_SYNTH] = 5, // FM
- [SOUND_MIXER_MIC] = 6, // Mic
- [SOUND_MIXER_SPEAKER] = 7, // Speaker
- [SOUND_MIXER_RECLEV] = 8, // Recording level
- [SOUND_MIXER_VOLUME] = 9 // Master Volume
- };
-
- switch (x) {
- case SOUND_MIXER_CS_GETDBGMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_GETDBGMASK:\n"));
- break;
- case SOUND_MIXER_CS_GETDBGLEVEL:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_GETDBGLEVEL:\n"));
- break;
- case SOUND_MIXER_CS_SETDBGMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_SETDBGMASK:\n"));
- break;
- case SOUND_MIXER_CS_SETDBGLEVEL:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_CS_SETDBGLEVEL:\n"));
- break;
- case OSS_GETVERSION:
- CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION:\n"));
- break;
- case SNDCTL_DSP_SYNC:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC:\n"));
- break;
- case SNDCTL_DSP_SETDUPLEX:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX:\n"));
- break;
- case SNDCTL_DSP_GETCAPS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS:\n"));
- break;
- case SNDCTL_DSP_RESET:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET:\n"));
- break;
- case SNDCTL_DSP_SPEED:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED:\n"));
- break;
- case SNDCTL_DSP_STEREO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO:\n"));
- break;
- case SNDCTL_DSP_CHANNELS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS:\n"));
- break;
- case SNDCTL_DSP_GETFMTS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS:\n"));
- break;
- case SNDCTL_DSP_SETFMT:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT:\n"));
- break;
- case SNDCTL_DSP_POST:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST:\n"));
- break;
- case SNDCTL_DSP_GETTRIGGER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER:\n"));
- break;
- case SNDCTL_DSP_SETTRIGGER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER:\n"));
- break;
- case SNDCTL_DSP_GETOSPACE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE:\n"));
- break;
- case SNDCTL_DSP_GETISPACE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE:\n"));
- break;
- case SNDCTL_DSP_NONBLOCK:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK:\n"));
- break;
- case SNDCTL_DSP_GETODELAY:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY:\n"));
- break;
- case SNDCTL_DSP_GETIPTR:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR:\n"));
- break;
- case SNDCTL_DSP_GETOPTR:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR:\n"));
- break;
- case SNDCTL_DSP_GETBLKSIZE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE:\n"));
- break;
- case SNDCTL_DSP_SETFRAGMENT:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SNDCTL_DSP_SETFRAGMENT:\n"));
- break;
- case SNDCTL_DSP_SUBDIVIDE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE:\n"));
- break;
- case SOUND_PCM_READ_RATE:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE:\n"));
- break;
- case SOUND_PCM_READ_CHANNELS:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_PCM_READ_CHANNELS:\n"));
- break;
- case SOUND_PCM_READ_BITS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS:\n"));
- break;
- case SOUND_PCM_WRITE_FILTER:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_PCM_WRITE_FILTER:\n"));
- break;
- case SNDCTL_DSP_SETSYNCRO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO:\n"));
- break;
- case SOUND_PCM_READ_FILTER:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER:\n"));
- break;
- case SOUND_MIXER_PRIVATE1:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1:\n"));
- break;
- case SOUND_MIXER_PRIVATE2:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2:\n"));
- break;
- case SOUND_MIXER_PRIVATE3:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3:\n"));
- break;
- case SOUND_MIXER_PRIVATE4:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4:\n"));
- break;
- case SOUND_MIXER_PRIVATE5:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5:\n"));
- break;
- case SOUND_MIXER_INFO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO:\n"));
- break;
- case SOUND_OLD_MIXER_INFO:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO:\n"));
- break;
-
- default:
- switch (_IOC_NR(x)) {
- case SOUND_MIXER_VOLUME:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_VOLUME:\n"));
- break;
- case SOUND_MIXER_SPEAKER:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_SPEAKER:\n"));
- break;
- case SOUND_MIXER_RECLEV:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_RECLEV:\n"));
- break;
- case SOUND_MIXER_MIC:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_MIC:\n"));
- break;
- case SOUND_MIXER_SYNTH:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_SYNTH:\n"));
- break;
- case SOUND_MIXER_RECSRC:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_RECSRC:\n"));
- break;
- case SOUND_MIXER_DEVMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_DEVMASK:\n"));
- break;
- case SOUND_MIXER_RECMASK:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_RECMASK:\n"));
- break;
- case SOUND_MIXER_STEREODEVS:
- CS_DBGOUT(CS_IOCTL, 4,
- printk("SOUND_MIXER_STEREODEVS:\n"));
- break;
- case SOUND_MIXER_CAPS:
- CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:\n"));
- break;
- default:
- i = _IOC_NR(x);
- if (i >= SOUND_MIXER_NRDEVICES
- || !(vidx = mixtable1[i])) {
- CS_DBGOUT(CS_IOCTL, 4, printk
- ("UNKNOWN IOCTL: 0x%.8x NR=%d\n",
- x, i));
- } else {
- CS_DBGOUT(CS_IOCTL, 4, printk
- ("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d\n",
- x, i));
- }
- break;
- }
- }
-}
-#endif
-static int prog_dmabuf_adc(struct cs4281_state *s);
-static void prog_codec(struct cs4281_state *s, unsigned type);
-
-// ---------------------------------------------------------------------
-//
-// Hardware Interfaces For the CS4281
-//
-
-
-//******************************************************************************
-// "delayus()-- Delay for the specified # of microseconds.
-//******************************************************************************
-static void delayus(struct cs4281_state *s, u32 delay)
-{
- u32 j;
- if ((delay > 9999) && (s->pm.flags & CS4281_PM_IDLE)) {
- j = (delay * HZ) / 1000000; /* calculate delay in jiffies */
- if (j < 1)
- j = 1; /* minimum one jiffy. */
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(j);
- } else
- udelay(delay);
- return;
-}
-
-
-//******************************************************************************
-// "cs4281_read_ac97" -- Reads a word from the specified location in the
-// CS4281's address space(based on the BA0 register).
-//
-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 register,
-// 0h for reads.
-// 3. Write ACCTL = Control Register = 460h for initiating the write
-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 17h
-// 5. if DCV not cleared, break and return error
-// 6. Read ACSTS = Status Register = 464h, check VSTS bit
-//****************************************************************************
-static int cs4281_read_ac97(struct cs4281_state *card, u32 offset,
- u32 * value)
-{
- u32 count, status;
-
- // Make sure that there is not data sitting
- // around from a previous uncompleted access.
- // ACSDA = Status Data Register = 47Ch
- status = readl(card->pBA0 + BA0_ACSDA);
-
- // Setup the AC97 control registers on the CS4281 to send the
- // appropriate command to the AC97 to perform the read.
- // ACCAD = Command Address Register = 46Ch
- // ACCDA = Command Data Register = 470h
- // ACCTL = Control Register = 460h
- // bit DCV - will clear when process completed
- // bit CRW - Read command
- // bit VFRM - valid frame enabled
- // bit ESYN - ASYNC generation enabled
-
- // Get the actual AC97 register from the offset
- writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
- writel(0, card->pBA0 + BA0_ACCDA);
- writel(ACCTL_DCV | ACCTL_CRW | ACCTL_VFRM | ACCTL_ESYN,
- card->pBA0 + BA0_ACCTL);
-
- // Wait for the read to occur.
- for (count = 0; count < 10; count++) {
- // First, we want to wait for a short time.
- udelay(25);
-
- // Now, check to see if the read has completed.
- // ACCTL = 460h, DCV should be reset by now and 460h = 17h
- if (!(readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV))
- break;
- }
-
- // Make sure the read completed.
- if (readl(card->pBA0 + BA0_ACCTL) & ACCTL_DCV)
- return 1;
-
- // Wait for the valid status bit to go active.
- for (count = 0; count < 10; count++) {
- // Read the AC97 status register.
- // ACSTS = Status Register = 464h
- status = readl(card->pBA0 + BA0_ACSTS);
-
- // See if we have valid status.
- // VSTS - Valid Status
- if (status & ACSTS_VSTS)
- break;
- // Wait for a short while.
- udelay(25);
- }
-
- // Make sure we got valid status.
- if (!(status & ACSTS_VSTS))
- return 1;
-
- // Read the data returned from the AC97 register.
- // ACSDA = Status Data Register = 474h
- *value = readl(card->pBA0 + BA0_ACSDA);
-
- // Success.
- return (0);
-}
-
-
-//****************************************************************************
-//
-// "cs4281_write_ac97()"-- writes a word to the specified location in the
-// CS461x's address space (based on the part's base address zero register).
-//
-// 1. Write ACCAD = Command Address Register = 46Ch for AC97 register address
-// 2. Write ACCDA = Command Data Register = 470h for data to write to AC97 reg.
-// 3. Write ACCTL = Control Register = 460h for initiating the write
-// 4. Read ACCTL = 460h, DCV should be reset by now and 460h = 07h
-// 5. if DCV not cleared, break and return error
-//
-//****************************************************************************
-static int cs4281_write_ac97(struct cs4281_state *card, u32 offset,
- u32 value)
-{
- u32 count, status=0;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs_4281_write_ac97()+ \n"));
-
- // Setup the AC97 control registers on the CS4281 to send the
- // appropriate command to the AC97 to perform the read.
- // ACCAD = Command Address Register = 46Ch
- // ACCDA = Command Data Register = 470h
- // ACCTL = Control Register = 460h
- // set DCV - will clear when process completed
- // reset CRW - Write command
- // set VFRM - valid frame enabled
- // set ESYN - ASYNC generation enabled
- // set RSTN - ARST# inactive, AC97 codec not reset
-
- // Get the actual AC97 register from the offset
-
- writel(offset - BA0_AC97_RESET, card->pBA0 + BA0_ACCAD);
- writel(value, card->pBA0 + BA0_ACCDA);
- writel(ACCTL_DCV | ACCTL_VFRM | ACCTL_ESYN,
- card->pBA0 + BA0_ACCTL);
-
- // Wait for the write to occur.
- for (count = 0; count < 100; count++) {
- // First, we want to wait for a short time.
- udelay(25);
- // Now, check to see if the write has completed.
- // ACCTL = 460h, DCV should be reset by now and 460h = 07h
- status = readl(card->pBA0 + BA0_ACCTL);
- if (!(status & ACCTL_DCV))
- break;
- }
-
- // Make sure the write completed.
- if (status & ACCTL_DCV) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs4281: cs_4281_write_ac97()- unable to write. ACCTL_DCV active\n"));
- return 1;
- }
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs_4281_write_ac97()- 0\n"));
- // Success.
- return 0;
-}
-
-
-//******************************************************************************
-// "Init4281()" -- Bring up the part.
-//******************************************************************************
-static __devinit int cs4281_hw_init(struct cs4281_state *card)
-{
- u32 ac97_slotid;
- u32 temp1, temp2;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs4281_hw_init()+ \n"));
-#ifndef NOT_CS4281_PM
- if(!card)
- return 1;
-#endif
- temp2 = readl(card->pBA0 + BA0_CFLR);
- CS_DBGOUT(CS_INIT | CS_ERROR | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_hw_init() CFLR 0x%x\n", temp2));
- if(temp2 != CS4281_CFLR_DEFAULT)
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
- "cs4281: cs4281_hw_init() CFLR invalid - resetting from 0x%x to 0x%x\n",
- temp2,CS4281_CFLR_DEFAULT));
- writel(CS4281_CFLR_DEFAULT, card->pBA0 + BA0_CFLR);
- temp2 = readl(card->pBA0 + BA0_CFLR);
- if(temp2 != CS4281_CFLR_DEFAULT)
- {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
- "cs4281: cs4281_hw_init() Invalid hardware - unable to configure CFLR\n"));
- return 1;
- }
- }
-
- //***************************************7
- // Set up the Sound System Configuration
- //***************************************
-
- // Set the 'Configuration Write Protect' register
- // to 4281h. Allows vendor-defined configuration
- // space between 0e4h and 0ffh to be written.
-
- writel(0x4281, card->pBA0 + BA0_CWPR); // (3e0h)
-
- // (0), Blast the clock control register to zero so that the
- // PLL starts out in a known state, and blast the master serial
- // port control register to zero so that the serial ports also
- // start out in a known state.
-
- writel(0, card->pBA0 + BA0_CLKCR1); // (400h)
- writel(0, card->pBA0 + BA0_SERMC); // (420h)
-
-
- // (1), Make ESYN go to zero to turn off
- // the Sync pulse on the AC97 link.
-
- writel(0, card->pBA0 + BA0_ACCTL);
- udelay(50);
-
-
- // (2) Drive the ARST# pin low for a minimum of 1uS (as defined in
- // the AC97 spec) and then drive it high. This is done for non
- // AC97 modes since there might be logic external to the CS461x
- // that uses the ARST# line for a reset.
-
- writel(0, card->pBA0 + BA0_SPMC); // (3ech)
- udelay(100);
- writel(SPMC_RSTN, card->pBA0 + BA0_SPMC);
- delayus(card,50000); // Wait 50 ms for ABITCLK to become stable.
-
- // (3) Turn on the Sound System Clocks.
- writel(CLKCR1_PLLP, card->pBA0 + BA0_CLKCR1); // (400h)
- delayus(card,50000); // Wait for the PLL to stabilize.
- // Turn on clocking of the core (CLKCR1(400h) = 0x00000030)
- writel(CLKCR1_PLLP | CLKCR1_SWCE, card->pBA0 + BA0_CLKCR1);
-
- // (4) Power on everything for now..
- writel(0x7E, card->pBA0 + BA0_SSPM); // (740h)
-
- // (5) Wait for clock stabilization.
- for (temp1 = 0; temp1 < 1000; temp1++) {
- udelay(1000);
- if (readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)
- break;
- }
- if (!(readl(card->pBA0 + BA0_CLKCR1) & CLKCR1_DLLRDY)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: DLLRDY failed!\n"));
- return -EIO;
- }
- // (6) Enable ASYNC generation.
- writel(ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
-
- // Now wait 'for a short while' to allow the AC97
- // part to start generating bit clock. (so we don't
- // Try to start the PLL without an input clock.)
- delayus(card,50000);
-
- // Set the serial port timing configuration, so that the
- // clock control circuit gets its clock from the right place.
- writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
-
- // (7) Wait for the codec ready signal from the AC97 codec.
-
- for (temp1 = 0; temp1 < 1000; temp1++) {
- // Delay a mil to let things settle out and
- // to prevent retrying the read too quickly.
- udelay(1000);
- if (readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY) // If ready, (464h)
- break; // exit the 'for' loop.
- }
- if (!(readl(card->pBA0 + BA0_ACSTS) & ACSTS_CRDY)) // If never came ready,
- {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
- "cs4281: ACSTS never came ready!\n"));
- return -EIO; // exit initialization.
- }
- // (8) Assert the 'valid frame' signal so we can
- // begin sending commands to the AC97 codec.
- writel(ACCTL_VFRM | ACCTL_ESYN, card->pBA0 + BA0_ACCTL); // (460h)
-
- // (9), Wait until CODEC calibration is finished.
- // Print an error message if it doesn't.
- for (temp1 = 0; temp1 < 1000; temp1++) {
- delayus(card,10000);
- // Read the AC97 Powerdown Control/Status Register.
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp2);
- if ((temp2 & 0x0000000F) == 0x0000000F)
- break;
- }
- if ((temp2 & 0x0000000F) != 0x0000000F) {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_ERR
- "cs4281: Codec failed to calibrate. Status = %.8x.\n",
- temp2));
- return -EIO;
- }
- // (10), Set the serial port timing configuration, so that the
- // clock control circuit gets its clock from the right place.
- writel(SERMC_PTC_AC97, card->pBA0 + BA0_SERMC); // (420h)=2.
-
-
- // (11) Wait until we've sampled input slots 3 & 4 as valid, meaning
- // that the codec is pumping ADC data across the AC link.
- for (temp1 = 0; temp1 < 1000; temp1++) {
- // Delay a mil to let things settle out and
- // to prevent retrying the read too quickly.
- delayus(card,1000); //(test)
-
- // Read the input slot valid register; See
- // if input slots 3 and 4 are valid yet.
- if (
- (readl(card->pBA0 + BA0_ACISV) &
- (ACISV_ISV3 | ACISV_ISV4)) ==
- (ACISV_ISV3 | ACISV_ISV4)) break; // Exit the 'for' if slots are valid.
- }
- // If we never got valid data, exit initialization.
- if ((readl(card->pBA0 + BA0_ACISV) & (ACISV_ISV3 | ACISV_ISV4))
- != (ACISV_ISV3 | ACISV_ISV4)) {
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_ERR
- "cs4281: Never got valid data!\n"));
- return -EIO; // If no valid data, exit initialization.
- }
- // (12), Start digital data transfer of audio data to the codec.
- writel(ACOSV_SLV3 | ACOSV_SLV4, card->pBA0 + BA0_ACOSV); // (468h)
-
-
- //**************************************
- // Unmute the Master and Alternate
- // (headphone) volumes. Set to max.
- //**************************************
- cs4281_write_ac97(card, BA0_AC97_HEADPHONE_VOLUME, 0);
- cs4281_write_ac97(card, BA0_AC97_MASTER_VOLUME, 0);
-
- //******************************************
- // Power on the DAC(AddDACUser()from main())
- //******************************************
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfdff);
-
- // Wait until we sample a DAC ready state.
- for (temp2 = 0; temp2 < 32; temp2++) {
- // Let's wait a mil to let things settle.
- delayus(card,1000);
- // Read the current state of the power control reg.
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- // If the DAC ready state bit is set, stop waiting.
- if (temp1 & 0x2)
- break;
- }
-
- //******************************************
- // Power on the ADC(AddADCUser()from main())
- //******************************************
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- cs4281_write_ac97(card, BA0_AC97_POWERDOWN, temp1 &= 0xfeff);
-
- // Wait until we sample ADC ready state.
- for (temp2 = 0; temp2 < 32; temp2++) {
- // Let's wait a mil to let things settle.
- delayus(card,1000);
- // Read the current state of the power control reg.
- cs4281_read_ac97(card, BA0_AC97_POWERDOWN, &temp1);
- // If the ADC ready state bit is set, stop waiting.
- if (temp1 & 0x1)
- break;
- }
- // Set up 4281 Register contents that
- // don't change for boot duration.
-
- // For playback, we map AC97 slot 3 and 4(Left
- // & Right PCM playback) to DMA Channel 0.
- // Set the fifo to be 15 bytes at offset zero.
-
- ac97_slotid = 0x01000f00; // FCR0.RS[4:0]=1(=>slot4, right PCM playback).
- // FCR0.LS[4:0]=0(=>slot3, left PCM playback).
- // FCR0.SZ[6-0]=15; FCR0.OF[6-0]=0.
- writel(ac97_slotid, card->pBA0 + BA0_FCR0); // (180h)
- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR0); // Turn on FIFO Enable.
-
- // For capture, we map AC97 slot 10 and 11(Left
- // and Right PCM Record) to DMA Channel 1.
- // Set the fifo to be 15 bytes at offset sixteen.
- ac97_slotid = 0x0B0A0f10; // FCR1.RS[4:0]=11(=>slot11, right PCM record).
- // FCR1.LS[4:0]=10(=>slot10, left PCM record).
- // FCR1.SZ[6-0]=15; FCR1.OF[6-0]=16.
- writel(ac97_slotid | FCRn_PSH, card->pBA0 + BA0_FCR1); // (184h)
- writel(ac97_slotid | FCRn_FEN, card->pBA0 + BA0_FCR1); // Turn on FIFO Enable.
-
- // Map the Playback SRC to the same AC97 slots(3 & 4--
- // --Playback left & right)as DMA channel 0.
- // Map the record SRC to the same AC97 slots(10 & 11--
- // -- Record left & right) as DMA channel 1.
-
- ac97_slotid = 0x0b0a0100; // SCRSA.PRSS[4:0]=1(=>slot4, right PCM playback).
- // SCRSA.PLSS[4:0]=0(=>slot3, left PCM playback).
- // SCRSA.CRSS[4:0]=11(=>slot11, right PCM record)
- // SCRSA.CLSS[4:0]=10(=>slot10, left PCM record).
- writel(ac97_slotid, card->pBA0 + BA0_SRCSA); // (75ch)
-
- // Set 'Half Terminal Count Interrupt Enable' and 'Terminal
- // Count Interrupt Enable' in DMA Control Registers 0 & 1.
- // Set 'MSK' flag to 1 to keep the DMA engines paused.
- temp1 = (DCRn_HTCIE | DCRn_TCIE | DCRn_MSK); // (00030001h)
- writel(temp1, card->pBA0 + BA0_DCR0); // (154h
- writel(temp1, card->pBA0 + BA0_DCR1); // (15ch)
-
- // Set 'Auto-Initialize Control' to 'enabled'; For playback,
- // set 'Transfer Type Control'(TR[1:0]) to 'read transfer',
- // for record, set Transfer Type Control to 'write transfer'.
- // All other bits set to zero; Some will be changed @ transfer start.
- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_READ); // (20000018h)
- writel(temp1, card->pBA0 + BA0_DMR0); // (150h)
- temp1 = (DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE); // (20000014h)
- writel(temp1, card->pBA0 + BA0_DMR1); // (158h)
-
- // Enable DMA interrupts generally, and
- // DMA0 & DMA1 interrupts specifically.
- temp1 = readl(card->pBA0 + BA0_HIMR) & 0xfffbfcff;
- writel(temp1, card->pBA0 + BA0_HIMR);
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs4281_hw_init()- 0\n"));
- return 0;
-}
-
-#ifndef NOT_CS4281_PM
-static void printpm(struct cs4281_state *s)
-{
- CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
- CS_DBGOUT(CS_PM, 9, printk("flags:0x%x u32CLKCR1_SAVE: 0%x u32SSPMValue: 0x%x\n",
- (unsigned)s->pm.flags,s->pm.u32CLKCR1_SAVE,s->pm.u32SSPMValue));
- CS_DBGOUT(CS_PM, 9, printk("u32PPLVCvalue: 0x%x u32PPRVCvalue: 0x%x\n",
- s->pm.u32PPLVCvalue,s->pm.u32PPRVCvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32FMLVCvalue: 0x%x u32FMRVCvalue: 0x%x\n",
- s->pm.u32FMLVCvalue,s->pm.u32FMRVCvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32GPIORvalue: 0x%x u32JSCTLvalue: 0x%x\n",
- s->pm.u32GPIORvalue,s->pm.u32JSCTLvalue));
- CS_DBGOUT(CS_PM, 9, printk("u32SSCR: 0x%x u32SRCSA: 0x%x\n",
- s->pm.u32SSCR,s->pm.u32SRCSA));
- CS_DBGOUT(CS_PM, 9, printk("u32DacASR: 0x%x u32AdcASR: 0x%x\n",
- s->pm.u32DacASR,s->pm.u32AdcASR));
- CS_DBGOUT(CS_PM, 9, printk("u32DacSR: 0x%x u32AdcSR: 0x%x\n",
- s->pm.u32DacSR,s->pm.u32AdcSR));
- CS_DBGOUT(CS_PM, 9, printk("u32MIDCR_Save: 0x%x\n",
- s->pm.u32MIDCR_Save));
-
-}
-static void printpipe(struct cs4281_pipeline *pl)
-{
-
- CS_DBGOUT(CS_PM, 9, printk("pm struct:\n"));
- CS_DBGOUT(CS_PM, 9, printk("flags:0x%x number: 0%x\n",
- (unsigned)pl->flags,pl->number));
- CS_DBGOUT(CS_PM, 9, printk("u32DBAnValue: 0%x u32DBCnValue: 0x%x\n",
- pl->u32DBAnValue,pl->u32DBCnValue));
- CS_DBGOUT(CS_PM, 9, printk("u32DMRnValue: 0x%x u32DCRnValue: 0x%x\n",
- pl->u32DMRnValue,pl->u32DCRnValue));
- CS_DBGOUT(CS_PM, 9, printk("u32DBAnAddress: 0x%x u32DBCnAddress: 0x%x\n",
- pl->u32DBAnAddress,pl->u32DBCnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32DCAnAddress: 0x%x u32DCCnAddress: 0x%x\n",
- pl->u32DCCnAddress,pl->u32DCCnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32DMRnAddress: 0x%x u32DCRnAddress: 0x%x\n",
- pl->u32DMRnAddress,pl->u32DCRnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32HDSRnAddress: 0x%x u32DBAn_Save: 0x%x\n",
- pl->u32HDSRnAddress,pl->u32DBAn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32DBCn_Save: 0x%x u32DMRn_Save: 0x%x\n",
- pl->u32DBCn_Save,pl->u32DMRn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32DCRn_Save: 0x%x u32DCCn_Save: 0x%x\n",
- pl->u32DCRn_Save,pl->u32DCCn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32DCAn_Save: 0x%x\n",
- pl->u32DCAn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32FCRn_Save: 0x%x u32FSICn_Save: 0x%x\n",
- pl->u32FCRn_Save,pl->u32FSICn_Save));
- CS_DBGOUT(CS_PM, 9, printk("u32FCRnValue: 0x%x u32FSICnValue: 0x%x\n",
- pl->u32FCRnValue,pl->u32FSICnValue));
- CS_DBGOUT(CS_PM, 9, printk("u32FCRnAddress: 0x%x u32FSICnAddress: 0x%x\n",
- pl->u32FCRnAddress,pl->u32FSICnAddress));
- CS_DBGOUT(CS_PM, 9, printk("u32FPDRnValue: 0x%x u32FPDRnAddress: 0x%x\n",
- pl->u32FPDRnValue,pl->u32FPDRnAddress));
-}
-static void printpipelines(struct cs4281_state *s)
-{
- int i;
- for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
- {
- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
- {
- printpipe(&s->pl[i]);
- }
- }
-}
-/****************************************************************************
-*
-* Suspend - save the ac97 regs, mute the outputs and power down the part.
-*
-****************************************************************************/
-static void cs4281_ac97_suspend(struct cs4281_state *s)
-{
- int Count,i;
-
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()+\n"));
-/*
-* change the state, save the current hwptr, then stop the dac/adc
-*/
- s->pm.flags &= ~CS4281_PM_IDLE;
- s->pm.flags |= CS4281_PM_SUSPENDING;
- s->pm.u32hwptr_playback = readl(s->pBA0 + BA0_DCA0);
- s->pm.u32hwptr_capture = readl(s->pBA0 + BA0_DCA1);
- stop_dac(s);
- stop_adc(s);
-
- for(Count = 0x2, i=0; (Count <= CS4281_AC97_HIGHESTREGTORESTORE)
- && (i < CS4281_AC97_NUMBER_RESTORE_REGS);
- Count += 2, i++)
- {
- cs4281_read_ac97(s, BA0_AC97_RESET + Count, &s->pm.ac97[i]);
- }
-/*
-* Save the ac97 volume registers as well as the current powerdown state.
-* Now, mute the all the outputs (master, headphone, and mono), as well
-* as the PCM volume, in preparation for powering down the entire part.
-*/
- cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME, &s->pm.u32AC97_master_volume);
- cs4281_read_ac97(s, BA0_AC97_HEADPHONE_VOLUME, &s->pm.u32AC97_headphone_volume);
- cs4281_read_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, &s->pm.u32AC97_master_volume_mono);
- cs4281_read_ac97(s, BA0_AC97_PCM_OUT_VOLUME, &s->pm.u32AC97_pcm_out_volume);
-
- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, 0x8000);
- cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, 0x8000);
- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME_MONO, 0x8000);
- cs4281_write_ac97(s, BA0_AC97_PCM_OUT_VOLUME, 0x8000);
-
- cs4281_read_ac97(s, BA0_AC97_POWERDOWN, &s->pm.u32AC97_powerdown);
- cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE, &s->pm.u32AC97_general_purpose);
-
-/*
-* And power down everything on the AC97 codec.
-*/
- cs4281_write_ac97(s, BA0_AC97_POWERDOWN, 0xff00);
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_suspend()-\n"));
-}
-
-/****************************************************************************
-*
-* Resume - power up the part and restore its registers..
-*
-****************************************************************************/
-static void cs4281_ac97_resume(struct cs4281_state *s)
-{
- int Count,i;
-
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()+\n"));
-
-/* do not save the power state registers at this time
- //
- // If we saved away the power control registers, write them into the
- // shadows so those saved values get restored instead of the current
- // shadowed value.
- //
- if( bPowerStateSaved )
- {
- PokeShadow( 0x26, ulSaveReg0x26 );
- bPowerStateSaved = FALSE;
- }
-*/
-
-//
-// First, we restore the state of the general purpose register. This
-// contains the mic select (mic1 or mic2) and if we restore this after
-// we restore the mic volume/boost state and mic2 was selected at
-// suspend time, we will end up with a brief period of time where mic1
-// is selected with the volume/boost settings for mic2, causing
-// acoustic feedback. So we restore the general purpose register
-// first, thereby getting the correct mic selected before we restore
-// the mic volume/boost.
-//
- cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE, s->pm.u32AC97_general_purpose);
-
-//
-// Now, while the outputs are still muted, restore the state of power
-// on the AC97 part.
-//
- cs4281_write_ac97(s, BA0_AC97_POWERDOWN, s->pm.u32AC97_powerdown);
-
-/*
-* Restore just the first set of registers, from register number
-* 0x02 to the register number that ulHighestRegToRestore specifies.
-*/
- for( Count = 0x2, i=0;
- (Count <= CS4281_AC97_HIGHESTREGTORESTORE)
- && (i < CS4281_AC97_NUMBER_RESTORE_REGS);
- Count += 2, i++)
- {
- cs4281_write_ac97(s, BA0_AC97_RESET + Count, s->pm.ac97[i]);
- }
- CS_DBGOUT(CS_PM, 9, printk("cs4281: cs4281_ac97_resume()-\n"));
-}
-
-/* do not save the power state registers at this time
-****************************************************************************
-*
-* SavePowerState - Save the power registers away.
-*
-****************************************************************************
-void
-HWAC97codec::SavePowerState(void)
-{
- ENTRY(TM_OBJECTCALLS, "HWAC97codec::SavePowerState()\r\n");
-
- ulSaveReg0x26 = PeekShadow(0x26);
-
- //
- // Note that we have saved registers that need to be restored during a
- // resume instead of ulAC97Regs[].
- //
- bPowerStateSaved = TRUE;
-
-} // SavePowerState
-*/
-
-static void cs4281_SuspendFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- /*
- * We need to save the contents of the BASIC FIFO Registers.
- */
- pl->u32FCRn_Save = readl(s->pBA0 + pl->u32FCRnAddress);
- pl->u32FSICn_Save = readl(s->pBA0 + pl->u32FSICnAddress);
-}
-static void cs4281_ResumeFIFO(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- /*
- * We need to restore the contents of the BASIC FIFO Registers.
- */
- writel(pl->u32FCRn_Save,s->pBA0 + pl->u32FCRnAddress);
- writel(pl->u32FSICn_Save,s->pBA0 + pl->u32FSICnAddress);
-}
-static void cs4281_SuspendDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- //
- // We need to save the contents of the BASIC DMA Registers.
- //
- pl->u32DBAn_Save = readl(s->pBA0 + pl->u32DBAnAddress);
- pl->u32DBCn_Save = readl(s->pBA0 + pl->u32DBCnAddress);
- pl->u32DMRn_Save = readl(s->pBA0 + pl->u32DMRnAddress);
- pl->u32DCRn_Save = readl(s->pBA0 + pl->u32DCRnAddress);
- pl->u32DCCn_Save = readl(s->pBA0 + pl->u32DCCnAddress);
- pl->u32DCAn_Save = readl(s->pBA0 + pl->u32DCAnAddress);
-}
-static void cs4281_ResumeDMAengine(struct cs4281_state *s, struct cs4281_pipeline *pl)
-{
- //
- // We need to save the contents of the BASIC DMA Registers.
- //
- writel( pl->u32DBAn_Save, s->pBA0 + pl->u32DBAnAddress);
- writel( pl->u32DBCn_Save, s->pBA0 + pl->u32DBCnAddress);
- writel( pl->u32DMRn_Save, s->pBA0 + pl->u32DMRnAddress);
- writel( pl->u32DCRn_Save, s->pBA0 + pl->u32DCRnAddress);
- writel( pl->u32DCCn_Save, s->pBA0 + pl->u32DCCnAddress);
- writel( pl->u32DCAn_Save, s->pBA0 + pl->u32DCAnAddress);
-}
-
-static int cs4281_suspend(struct cs4281_state *s)
-{
- int i;
- u32 u32CLKCR1;
- struct cs4281_pm *pm = &s->pm;
- CS_DBGOUT(CS_PM | CS_FUNCTION, 9,
- printk("cs4281: cs4281_suspend()+ flags=%d\n",
- (unsigned)s->pm.flags));
-/*
-* check the current state, only suspend if IDLE
-*/
- if(!(s->pm.flags & CS4281_PM_IDLE))
- {
- CS_DBGOUT(CS_PM | CS_ERROR, 2,
- printk("cs4281: cs4281_suspend() unable to suspend, not IDLE\n"));
- return 1;
- }
- s->pm.flags &= ~CS4281_PM_IDLE;
- s->pm.flags |= CS4281_PM_SUSPENDING;
-
-//
-// Gershwin CLKRUN - Set CKRA
-//
- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
-
- pm->u32CLKCR1_SAVE = u32CLKCR1;
- if(!(u32CLKCR1 & 0x00010000 ) )
- writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
-
-//
-// First, turn on the clocks (yikes) to the devices, so that they will
-// respond when we try to save their state.
-//
- if(!(u32CLKCR1 & CLKCR1_SWCE))
- {
- writel(u32CLKCR1 | CLKCR1_SWCE , s->pBA0 + BA0_CLKCR1);
- }
-
- //
- // Save the power state
- //
- pm->u32SSPMValue = readl(s->pBA0 + BA0_SSPM);
-
- //
- // Disable interrupts.
- //
- writel(HICR_CHGM, s->pBA0 + BA0_HICR);
-
- //
- // Save the PCM Playback Left and Right Volume Control.
- //
- pm->u32PPLVCvalue = readl(s->pBA0 + BA0_PPLVC);
- pm->u32PPRVCvalue = readl(s->pBA0 + BA0_PPRVC);
-
- //
- // Save the FM Synthesis Left and Right Volume Control.
- //
- pm->u32FMLVCvalue = readl(s->pBA0 + BA0_FMLVC);
- pm->u32FMRVCvalue = readl(s->pBA0 + BA0_FMRVC);
-
- //
- // Save the GPIOR value.
- //
- pm->u32GPIORvalue = readl(s->pBA0 + BA0_GPIOR);
-
- //
- // Save the JSCTL value.
- //
- pm->u32JSCTLvalue = readl(s->pBA0 + BA0_GPIOR);
-
- //
- // Save Sound System Control Register
- //
- pm->u32SSCR = readl(s->pBA0 + BA0_SSCR);
-
- //
- // Save SRC Slot Assinment register
- //
- pm->u32SRCSA = readl(s->pBA0 + BA0_SRCSA);
-
- //
- // Save sample rate
- //
- pm->u32DacASR = readl(s->pBA0 + BA0_PASR);
- pm->u32AdcASR = readl(s->pBA0 + BA0_CASR);
- pm->u32DacSR = readl(s->pBA0 + BA0_DACSR);
- pm->u32AdcSR = readl(s->pBA0 + BA0_ADCSR);
-
- //
- // Loop through all of the PipeLines
- //
- for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
- {
- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
- {
- //
- // Ask the DMAengines and FIFOs to Suspend.
- //
- cs4281_SuspendDMAengine(s,&s->pl[i]);
- cs4281_SuspendFIFO(s,&s->pl[i]);
- }
- }
- //
- // We need to save the contents of the Midi Control Register.
- //
- pm->u32MIDCR_Save = readl(s->pBA0 + BA0_MIDCR);
-/*
-* save off the AC97 part information
-*/
- cs4281_ac97_suspend(s);
-
- //
- // Turn off the serial ports.
- //
- writel(0, s->pBA0 + BA0_SERMC);
-
- //
- // Power off FM, Joystick, AC link,
- //
- writel(0, s->pBA0 + BA0_SSPM);
-
- //
- // DLL off.
- //
- writel(0, s->pBA0 + BA0_CLKCR1);
-
- //
- // AC link off.
- //
- writel(0, s->pBA0 + BA0_SPMC);
-
- //
- // Put the chip into D3(hot) state.
- //
- // PokeBA0(BA0_PMCS, 0x00000003);
-
- //
- // Gershwin CLKRUN - Clear CKRA
- //
- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
- writel(u32CLKCR1 & 0xFFFEFFFF, s->pBA0 + BA0_CLKCR1);
-
-#ifdef CSDEBUG
- printpm(s);
- printpipelines(s);
-#endif
-
- s->pm.flags &= ~CS4281_PM_SUSPENDING;
- s->pm.flags |= CS4281_PM_SUSPENDED;
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 9,
- printk("cs4281: cs4281_suspend()- flags=%d\n",
- (unsigned)s->pm.flags));
- return 0;
-}
-
-static int cs4281_resume(struct cs4281_state *s)
-{
- int i;
- unsigned temp1;
- u32 u32CLKCR1;
- struct cs4281_pm *pm = &s->pm;
- CS_DBGOUT(CS_PM | CS_FUNCTION, 4,
- printk( "cs4281: cs4281_resume()+ flags=%d\n",
- (unsigned)s->pm.flags));
- if(!(s->pm.flags & CS4281_PM_SUSPENDED))
- {
- CS_DBGOUT(CS_PM | CS_ERROR, 2,
- printk("cs4281: cs4281_resume() unable to resume, not SUSPENDED\n"));
- return 1;
- }
- s->pm.flags &= ~CS4281_PM_SUSPENDED;
- s->pm.flags |= CS4281_PM_RESUMING;
-
-//
-// Gershwin CLKRUN - Set CKRA
-//
- u32CLKCR1 = readl(s->pBA0 + BA0_CLKCR1);
- writel(u32CLKCR1 | 0x00010000, s->pBA0 + BA0_CLKCR1);
-
- //
- // set the power state.
- //
- //old PokeBA0(BA0_PMCS, 0);
-
- //
- // Program the clock circuit and serial ports.
- //
- temp1 = cs4281_hw_init(s);
- if (temp1) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1,
- printk(KERN_ERR
- "cs4281: resume cs4281_hw_init() error.\n"));
- return -1;
- }
-
- //
- // restore the Power state
- //
- writel(pm->u32SSPMValue, s->pBA0 + BA0_SSPM);
-
- //
- // Set post SRC mix setting (FM or ALT48K)
- //
- writel(pm->u32SSPM_BITS, s->pBA0 + BA0_SSPM);
-
- //
- // Loop through all of the PipeLines
- //
- for(i = 0; i < CS4281_NUMBER_OF_PIPELINES; i++)
- {
- if(s->pl[i].flags & CS4281_PIPELINE_VALID)
- {
- //
- // Ask the DMAengines and FIFOs to Resume.
- //
- cs4281_ResumeDMAengine(s,&s->pl[i]);
- cs4281_ResumeFIFO(s,&s->pl[i]);
- }
- }
- //
- // We need to restore the contents of the Midi Control Register.
- //
- writel(pm->u32MIDCR_Save, s->pBA0 + BA0_MIDCR);
-
- cs4281_ac97_resume(s);
- //
- // Restore the PCM Playback Left and Right Volume Control.
- //
- writel(pm->u32PPLVCvalue, s->pBA0 + BA0_PPLVC);
- writel(pm->u32PPRVCvalue, s->pBA0 + BA0_PPRVC);
-
- //
- // Restore the FM Synthesis Left and Right Volume Control.
- //
- writel(pm->u32FMLVCvalue, s->pBA0 + BA0_FMLVC);
- writel(pm->u32FMRVCvalue, s->pBA0 + BA0_FMRVC);
-
- //
- // Restore the JSCTL value.
- //
- writel(pm->u32JSCTLvalue, s->pBA0 + BA0_JSCTL);
-
- //
- // Restore the GPIOR register value.
- //
- writel(pm->u32GPIORvalue, s->pBA0 + BA0_GPIOR);
-
- //
- // Restore Sound System Control Register
- //
- writel(pm->u32SSCR, s->pBA0 + BA0_SSCR);
-
- //
- // Restore SRC Slot Assignment register
- //
- writel(pm->u32SRCSA, s->pBA0 + BA0_SRCSA);
-
- //
- // Restore sample rate
- //
- writel(pm->u32DacASR, s->pBA0 + BA0_PASR);
- writel(pm->u32AdcASR, s->pBA0 + BA0_CASR);
- writel(pm->u32DacSR, s->pBA0 + BA0_DACSR);
- writel(pm->u32AdcSR, s->pBA0 + BA0_ADCSR);
-
- //
- // Restore CFL1/2 registers we saved to compensate for OEM bugs.
- //
- // PokeBA0(BA0_CFLR, ulConfig);
-
- //
- // Gershwin CLKRUN - Clear CKRA
- //
- writel(pm->u32CLKCR1_SAVE, s->pBA0 + BA0_CLKCR1);
-
- //
- // Enable interrupts on the part.
- //
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
-
-#ifdef CSDEBUG
- printpm(s);
- printpipelines(s);
-#endif
-/*
-* change the state, restore the current hwptrs, then stop the dac/adc
-*/
- s->pm.flags |= CS4281_PM_IDLE;
- s->pm.flags &= ~(CS4281_PM_SUSPENDING | CS4281_PM_SUSPENDED
- | CS4281_PM_RESUMING | CS4281_PM_RESUMED);
-
- writel(s->pm.u32hwptr_playback, s->pBA0 + BA0_DCA0);
- writel(s->pm.u32hwptr_capture, s->pBA0 + BA0_DCA1);
- start_dac(s);
- start_adc(s);
-
- CS_DBGOUT(CS_PM | CS_FUNCTION, 9, printk("cs4281: cs4281_resume()- flags=%d\n",
- (unsigned)s->pm.flags));
- return 0;
-}
-
-#endif
-
-//******************************************************************************
-// "cs4281_play_rate()" --
-//******************************************************************************
-static void cs4281_play_rate(struct cs4281_state *card, u32 playrate)
-{
- u32 DACSRvalue = 1;
-
- // Based on the sample rate, program the DACSR register.
- if (playrate == 8000)
- DACSRvalue = 5;
- if (playrate == 11025)
- DACSRvalue = 4;
- else if (playrate == 22050)
- DACSRvalue = 2;
- else if (playrate == 44100)
- DACSRvalue = 1;
- else if ((playrate <= 48000) && (playrate >= 6023))
- DACSRvalue = 24576000 / (playrate * 16);
- else if (playrate < 6023)
- // Not allowed by open.
- return;
- else if (playrate > 48000)
- // Not allowed by open.
- return;
- CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 2, printk(KERN_INFO
- "cs4281: cs4281_play_rate(): DACSRvalue=0x%.8x playrate=%d\n",
- DACSRvalue, playrate));
- // Write the 'sample rate select code'
- // to the 'DAC Sample Rate' register.
- writel(DACSRvalue, card->pBA0 + BA0_DACSR); // (744h)
-}
-
-//******************************************************************************
-// "cs4281_record_rate()" -- Initialize the record sample rate converter.
-//******************************************************************************
-static void cs4281_record_rate(struct cs4281_state *card, u32 outrate)
-{
- u32 ADCSRvalue = 1;
-
- //
- // Based on the sample rate, program the ADCSR register
- //
- if (outrate == 8000)
- ADCSRvalue = 5;
- if (outrate == 11025)
- ADCSRvalue = 4;
- else if (outrate == 22050)
- ADCSRvalue = 2;
- else if (outrate == 44100)
- ADCSRvalue = 1;
- else if ((outrate <= 48000) && (outrate >= 6023))
- ADCSRvalue = 24576000 / (outrate * 16);
- else if (outrate < 6023) {
- // Not allowed by open.
- return;
- } else if (outrate > 48000) {
- // Not allowed by open.
- return;
- }
- CS_DBGOUT(CS_WAVE_READ | CS_PARMS, 2, printk(KERN_INFO
- "cs4281: cs4281_record_rate(): ADCSRvalue=0x%.8x outrate=%d\n",
- ADCSRvalue, outrate));
- // Write the 'sample rate select code
- // to the 'ADC Sample Rate' register.
- writel(ADCSRvalue, card->pBA0 + BA0_ADCSR); // (748h)
-}
-
-
-
-static void stop_dac(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO "cs4281: stop_dac():\n"));
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_WRITE;
- temp1 = readl(s->pBA0 + BA0_DCR0) | DCRn_MSK;
- writel(temp1, s->pBA0 + BA0_DCR0);
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void start_dac(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_FUNCTION, 3, printk(KERN_INFO "cs4281: start_dac()+\n"));
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped ||
- (s->dma_dac.count > 0
- && s->dma_dac.ready))
-#ifndef NOT_CS4281_PM
- && (s->pm.flags & CS4281_PM_IDLE))
-#else
-)
-#endif
- {
- s->ena |= FMODE_WRITE;
- temp1 = readl(s->pBA0 + BA0_DCR0) & ~DCRn_MSK; // Clear DMA0 channel mask.
- writel(temp1, s->pBA0 + BA0_DCR0); // Start DMA'ing.
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
-
- writel(7, s->pBA0 + BA0_PPRVC);
- writel(7, s->pBA0 + BA0_PPLVC);
- CS_DBGOUT(CS_WAVE_WRITE | CS_PARMS, 8, printk(KERN_INFO
- "cs4281: start_dac(): writel 0x%x start dma\n", temp1));
-
- }
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 3,
- printk(KERN_INFO "cs4281: start_dac()-\n"));
-}
-
-
-static void stop_adc(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_FUNCTION, 3,
- printk(KERN_INFO "cs4281: stop_adc()+\n"));
-
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_READ;
-
- if (s->conversion == 1) {
- s->conversion = 0;
- s->prop_adc.fmt = s->prop_adc.fmt_original;
- }
- temp1 = readl(s->pBA0 + BA0_DCR1) | DCRn_MSK;
- writel(temp1, s->pBA0 + BA0_DCR1);
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 3,
- printk(KERN_INFO "cs4281: stop_adc()-\n"));
-}
-
-
-static void start_adc(struct cs4281_state *s)
-{
- unsigned long flags;
- unsigned temp1;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: start_adc()+\n"));
-
- if (!(s->ena & FMODE_READ) &&
- (s->dma_adc.mapped || s->dma_adc.count <=
- (signed) (s->dma_adc.dmasize - 2 * s->dma_adc.fragsize))
- && s->dma_adc.ready
-#ifndef NOT_CS4281_PM
- && (s->pm.flags & CS4281_PM_IDLE))
-#else
-)
-#endif
- {
- if (s->prop_adc.fmt & AFMT_S8 || s->prop_adc.fmt & AFMT_U8) {
- //
- // now only use 16 bit capture, due to truncation issue
- // in the chip, noticable distortion occurs.
- // allocate buffer and then convert from 16 bit to
- // 8 bit for the user buffer.
- //
- s->prop_adc.fmt_original = s->prop_adc.fmt;
- if (s->prop_adc.fmt & AFMT_S8) {
- s->prop_adc.fmt &= ~AFMT_S8;
- s->prop_adc.fmt |= AFMT_S16_LE;
- }
- if (s->prop_adc.fmt & AFMT_U8) {
- s->prop_adc.fmt &= ~AFMT_U8;
- s->prop_adc.fmt |= AFMT_U16_LE;
- }
- //
- // prog_dmabuf_adc performs a stop_adc() but that is
- // ok since we really haven't started the DMA yet.
- //
- prog_codec(s, CS_TYPE_ADC);
-
- if (prog_dmabuf_adc(s) != 0) {
- CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
- "cs4281: start_adc(): error in prog_dmabuf_adc\n"));
- }
- s->conversion = 1;
- }
- spin_lock_irqsave(&s->lock, flags);
- s->ena |= FMODE_READ;
- temp1 = readl(s->pBA0 + BA0_DCR1) & ~DCRn_MSK; // Clear DMA1 channel mask bit.
- writel(temp1, s->pBA0 + BA0_DCR1); // Start recording
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts.
- spin_unlock_irqrestore(&s->lock, flags);
-
- CS_DBGOUT(CS_PARMS, 6, printk(KERN_INFO
- "cs4281: start_adc(): writel 0x%x \n", temp1));
- }
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: start_adc()-\n"));
-
-}
-
-
-// ---------------------------------------------------------------------
-
-#define DMABUF_MINORDER 1 // ==> min buffer size = 8K.
-
-
-static void dealloc_dmabuf(struct cs4281_state *s, struct dmabuf *db)
-{
- struct page *map, *mapend;
-
- if (db->rawbuf) {
- // Undo prog_dmabuf()'s marking the pages as reserved
- mapend =
- virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) -
- 1);
- for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
- ClearPageReserved(map);
- free_dmabuf(s, db);
- }
- if (s->tmpbuff && (db->type == CS_TYPE_ADC)) {
- // Undo prog_dmabuf()'s marking the pages as reserved
- mapend =
- virt_to_page(s->tmpbuff +
- (PAGE_SIZE << s->buforder_tmpbuff) - 1);
- for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
- ClearPageReserved(map);
- free_dmabuf2(s, db);
- }
- s->tmpbuff = NULL;
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct cs4281_state *s, struct dmabuf *db)
-{
- int order;
- unsigned bytespersec, temp1;
- unsigned bufs, sample_shift = 0;
- struct page *map, *mapend;
- unsigned long df;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_dmabuf()+\n"));
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error =
- db->endcleared = db->blocks = db->wakeup = db->underrun = 0;
-/*
-* check for order within limits, but do not overwrite value, check
-* later for a fractional defaultorder (i.e. 100+).
-*/
- if((defaultorder > 0) && (defaultorder < 12))
- df = defaultorder;
- else
- df = 1;
-
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = df; order >= DMABUF_MINORDER; order--)
- if ( (db->rawbuf = (void *) pci_alloc_consistent(
- s->pcidev, PAGE_SIZE << order, &db-> dmaaddr)))
- break;
- if (!db->rawbuf) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: prog_dmabuf(): unable to allocate rawbuf\n"));
- return -ENOMEM;
- }
- db->buforder = order;
- // Now mark the pages as reserved; otherwise the
- // remap_pfn_range() in cs4281_mmap doesn't work.
- // 1. get index to last page in mem_map array for rawbuf.
- mapend = virt_to_page(db->rawbuf +
- (PAGE_SIZE << db->buforder) - 1);
-
- // 2. mark each physical page in range as 'reserved'.
- for (map = virt_to_page(db->rawbuf); map <= mapend; map++)
- SetPageReserved(map);
- }
- if (!s->tmpbuff && (db->type == CS_TYPE_ADC)) {
- for (order = df; order >= DMABUF_MINORDER;
- order--)
- if ( (s->tmpbuff = (void *) pci_alloc_consistent(
- s->pcidev, PAGE_SIZE << order,
- &s->dmaaddr_tmpbuff)))
- break;
- if (!s->tmpbuff) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: prog_dmabuf(): unable to allocate tmpbuff\n"));
- return -ENOMEM;
- }
- s->buforder_tmpbuff = order;
- // Now mark the pages as reserved; otherwise the
- // remap_pfn_range() in cs4281_mmap doesn't work.
- // 1. get index to last page in mem_map array for rawbuf.
- mapend = virt_to_page(s->tmpbuff +
- (PAGE_SIZE << s->buforder_tmpbuff) - 1);
-
- // 2. mark each physical page in range as 'reserved'.
- for (map = virt_to_page(s->tmpbuff); map <= mapend; map++)
- SetPageReserved(map);
- }
- if (db->type == CS_TYPE_DAC) {
- if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- sample_shift++;
- if (s->prop_dac.channels > 1)
- sample_shift++;
- bytespersec = s->prop_dac.rate << sample_shift;
- } else // CS_TYPE_ADC
- {
- if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- sample_shift++;
- if (s->prop_adc.channels > 1)
- sample_shift++;
- bytespersec = s->prop_adc.rate << sample_shift;
- }
- bufs = PAGE_SIZE << db->buforder;
-
-/*
-* added fractional "defaultorder" inputs. if >100 then use
-* defaultorder-100 as power of 2 for the buffer size. example:
-* 106 = 2^(106-100) = 2^6 = 64 bytes for the buffer size.
-*/
- if(defaultorder >= 100)
- {
- bufs = 1 << (defaultorder-100);
- }
-
-#define INTERRUPT_RATE_MS 100 // Interrupt rate in milliseconds.
- db->numfrag = 2;
-/*
-* Nominal frag size(bytes/interrupt)
-*/
- temp1 = bytespersec / (1000 / INTERRUPT_RATE_MS);
- db->fragshift = 8; // Min 256 bytes.
- while (1 << db->fragshift < temp1) // Calc power of 2 frag size.
- db->fragshift += 1;
- db->fragsize = 1 << db->fragshift;
- db->dmasize = db->fragsize * 2;
- db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
-
-// If the calculated size is larger than the allocated
-// buffer, divide the allocated buffer into 2 fragments.
- if (db->dmasize > bufs) {
-
- db->numfrag = 2; // Two fragments.
- db->fragsize = bufs >> 1; // Each 1/2 the alloc'ed buffer.
- db->fragsamples = db->fragsize >> sample_shift; // # samples/fragment.
- db->dmasize = bufs; // Use all the alloc'ed buffer.
-
- db->fragshift = 0; // Calculate 'fragshift'.
- temp1 = db->fragsize; // update_ptr() uses it
- while ((temp1 >>= 1) > 1) // to calc 'total-bytes'
- db->fragshift += 1; // returned in DSP_GETI/OPTR.
- }
- CS_DBGOUT(CS_PARMS, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf(): numfrag=%d fragsize=%d fragsamples=%d fragshift=%d bufs=%d fmt=0x%x ch=%d\n",
- db->numfrag, db->fragsize, db->fragsamples,
- db->fragshift, bufs,
- (db->type == CS_TYPE_DAC) ? s->prop_dac.fmt :
- s->prop_adc.fmt,
- (db->type == CS_TYPE_DAC) ? s->prop_dac.channels :
- s->prop_adc.channels));
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_dmabuf()-\n"));
- return 0;
-}
-
-
-static int prog_dmabuf_adc(struct cs4281_state *s)
-{
- unsigned long va;
- unsigned count;
- int c;
- stop_adc(s);
- s->dma_adc.type = CS_TYPE_ADC;
- if ((c = prog_dmabuf(s, &s->dma_adc)))
- return c;
-
- if (s->dma_adc.rawbuf) {
- memset(s->dma_adc.rawbuf,
- (s->prop_adc.
- fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- s->dma_adc.dmasize);
- }
- if (s->tmpbuff) {
- memset(s->tmpbuff,
- (s->prop_adc.
- fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- PAGE_SIZE << s->buforder_tmpbuff);
- }
-
- va = virt_to_bus(s->dma_adc.rawbuf);
-
- count = s->dma_adc.dmasize;
-
- if (s->prop_adc.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
- count /= 2; // 16-bit.
-
- if (s->prop_adc.channels > 1)
- count /= 2; // Assume stereo.
-
- CS_DBGOUT(CS_WAVE_READ, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf_adc(): count=%d va=0x%.8x\n",
- count, (unsigned) va));
-
- writel(va, s->pBA0 + BA0_DBA1); // Set buffer start address.
- writel(count - 1, s->pBA0 + BA0_DBC1); // Set count.
- s->dma_adc.ready = 1;
- return 0;
-}
-
-
-static int prog_dmabuf_dac(struct cs4281_state *s)
-{
- unsigned long va;
- unsigned count;
- int c;
- stop_dac(s);
- s->dma_dac.type = CS_TYPE_DAC;
- if ((c = prog_dmabuf(s, &s->dma_dac)))
- return c;
- memset(s->dma_dac.rawbuf,
- (s->prop_dac.fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- s->dma_dac.dmasize);
-
- va = virt_to_bus(s->dma_dac.rawbuf);
-
- count = s->dma_dac.dmasize;
- if (s->prop_dac.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE))
- count /= 2; // 16-bit.
-
- if (s->prop_dac.channels > 1)
- count /= 2; // Assume stereo.
-
- writel(va, s->pBA0 + BA0_DBA0); // Set buffer start address.
- writel(count - 1, s->pBA0 + BA0_DBC0); // Set count.
-
- CS_DBGOUT(CS_WAVE_WRITE, 3, printk(KERN_INFO
- "cs4281: prog_dmabuf_dac(): count=%d va=0x%.8x\n",
- count, (unsigned) va));
-
- s->dma_dac.ready = 1;
- return 0;
-}
-
-
-static void clear_advance(void *buf, unsigned bsize, unsigned bptr,
- unsigned len, unsigned char c)
-{
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(((char *) buf) + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
- "cs4281: clear_advance(): memset %d at %p for %d size \n",
- (unsigned)c, ((char *) buf) + bptr, len));
- memset(((char *) buf) + bptr, c, len);
-}
-
-
-
-// call with spinlock held!
-static void cs4281_update_ptr(struct cs4281_state *s, int intflag)
-{
- int diff;
- unsigned hwptr, va;
-
- // update ADC pointer
- if (s->ena & FMODE_READ) {
- hwptr = readl(s->pBA0 + BA0_DCA1); // Read capture DMA address.
- va = virt_to_bus(s->dma_adc.rawbuf);
- hwptr -= (unsigned) va;
- diff =
- (s->dma_adc.dmasize + hwptr -
- s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count > s->dma_adc.dmasize)
- s->dma_adc.count = s->dma_adc.dmasize;
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >=
- (signed) s->dma_adc.fragsize) wake_up(&s->
- dma_adc.
- wait);
- } else {
- if (s->dma_adc.count > 0)
- wake_up(&s->dma_adc.wait);
- }
- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
- s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count));
- }
- // update DAC pointer
- //
- // check for end of buffer, means that we are going to wait for another interrupt
- // to allow silence to fill the fifos on the part, to keep pops down to a minimum.
- //
- if (s->ena & FMODE_WRITE) {
- hwptr = readl(s->pBA0 + BA0_DCA0); // Read play DMA address.
- va = virt_to_bus(s->dma_dac.rawbuf);
- hwptr -= (unsigned) va;
- diff = (s->dma_dac.dmasize + hwptr -
- s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= s->dma_dac.fragsize) {
- s->dma_dac.wakeup = 1;
- wake_up(&s->dma_dac.wait);
- if (s->dma_dac.count > s->dma_dac.dmasize)
- s->dma_dac.count &=
- s->dma_dac.dmasize - 1;
- }
- } else {
- s->dma_dac.count -= diff;
- if (s->dma_dac.count <= 0) {
- //
- // fill with silence, and do not shut down the DAC.
- // Continue to play silence until the _release.
- //
- CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): memset %d at %p for %d size \n",
- (unsigned)(s->prop_dac.fmt &
- (AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0,
- s->dma_dac.rawbuf, s->dma_dac.dmasize));
- memset(s->dma_dac.rawbuf,
- (s->prop_dac.
- fmt & (AFMT_U8 | AFMT_U16_LE)) ?
- 0x80 : 0, s->dma_dac.dmasize);
- if (s->dma_dac.count < 0) {
- s->dma_dac.underrun = 1;
- s->dma_dac.count = 0;
- CS_DBGOUT(CS_ERROR, 9, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): underrun\n"));
- }
- } else if (s->dma_dac.count <=
- (signed) s->dma_dac.fragsize
- && !s->dma_dac.endcleared) {
- clear_advance(s->dma_dac.rawbuf,
- s->dma_dac.dmasize,
- s->dma_dac.swptr,
- s->dma_dac.fragsize,
- (s->prop_dac.
- fmt & (AFMT_U8 |
- AFMT_U16_LE)) ? 0x80
- : 0);
- s->dma_dac.endcleared = 1;
- }
- if ( (s->dma_dac.count <= (signed) s->dma_dac.dmasize/2) ||
- intflag)
- {
- wake_up(&s->dma_dac.wait);
- }
- }
- CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
- "cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
- s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count));
- }
-}
-
-
-// ---------------------------------------------------------------------
-
-static void prog_codec(struct cs4281_state *s, unsigned type)
-{
- unsigned long flags;
- unsigned temp1, format;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_codec()+ \n"));
-
- spin_lock_irqsave(&s->lock, flags);
- if (type == CS_TYPE_ADC) {
- temp1 = readl(s->pBA0 + BA0_DCR1);
- writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR1); // Stop capture DMA, if active.
-
- // program sampling rates
- // Note, for CS4281, capture & play rates can be set independently.
- cs4281_record_rate(s, s->prop_adc.rate);
-
- // program ADC parameters
- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_WRITE;
- if (s->prop_adc.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
- if (s->prop_adc.fmt & (AFMT_S16_BE | AFMT_U16_BE)) // Big-endian?
- format |= DMRn_BEND;
- if (s->prop_adc.fmt & (AFMT_U16_LE | AFMT_U16_BE))
- format |= DMRn_USIGN; // Unsigned.
- } else
- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
- if (s->prop_adc.channels < 2)
- format |= DMRn_MONO;
-
- writel(format, s->pBA0 + BA0_DMR1);
-
- CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
- "cs4281: prog_codec(): adc %s %s %s rate=%d DMR0 format=0x%.8x\n",
- (format & DMRn_SIZE8) ? "8" : "16",
- (format & DMRn_USIGN) ? "Unsigned" : "Signed",
- (format & DMRn_MONO) ? "Mono" : "Stereo",
- s->prop_adc.rate, format));
-
- s->ena &= ~FMODE_READ; // not capturing data yet
- }
-
-
- if (type == CS_TYPE_DAC) {
- temp1 = readl(s->pBA0 + BA0_DCR0);
- writel(temp1 | DCRn_MSK, s->pBA0 + BA0_DCR0); // Stop play DMA, if active.
-
- // program sampling rates
- // Note, for CS4281, capture & play rates can be set independently.
- cs4281_play_rate(s, s->prop_dac.rate);
-
- // program DAC parameters
- format = DMRn_DMA | DMRn_AUTO | DMRn_TR_READ;
- if (s->prop_dac.
- fmt & (AFMT_S16_LE | AFMT_U16_LE | AFMT_S16_BE | AFMT_U16_BE)) { // 16-bit
- if (s->prop_dac.fmt & (AFMT_S16_BE | AFMT_U16_BE))
- format |= DMRn_BEND; // Big Endian.
- if (s->prop_dac.fmt & (AFMT_U16_LE | AFMT_U16_BE))
- format |= DMRn_USIGN; // Unsigned.
- } else
- format |= DMRn_SIZE8 | DMRn_USIGN; // 8-bit, unsigned
-
- if (s->prop_dac.channels < 2)
- format |= DMRn_MONO;
-
- writel(format, s->pBA0 + BA0_DMR0);
-
-
- CS_DBGOUT(CS_PARMS, 2, printk(KERN_INFO
- "cs4281: prog_codec(): dac %s %s %s rate=%d DMR0 format=0x%.8x\n",
- (format & DMRn_SIZE8) ? "8" : "16",
- (format & DMRn_USIGN) ? "Unsigned" : "Signed",
- (format & DMRn_MONO) ? "Mono" : "Stereo",
- s->prop_dac.rate, format));
-
- s->ena &= ~FMODE_WRITE; // not capturing data yet
-
- }
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: prog_codec()- \n"));
-}
-
-
-static int mixer_ioctl(struct cs4281_state *s, unsigned int cmd,
- unsigned long arg)
-{
- // Index to mixer_src[] is value of AC97 Input Mux Select Reg.
- // Value of array member is recording source Device ID Mask.
- static const unsigned int mixer_src[8] = {
- SOUND_MASK_MIC, SOUND_MASK_CD, 0, SOUND_MASK_LINE1,
- SOUND_MASK_LINE, SOUND_MASK_VOLUME, 0, 0
- };
- void __user *argp = (void __user *)arg;
-
- // Index of mixtable1[] member is Device ID
- // and must be <= SOUND_MIXER_NRDEVICES.
- // Value of array member is index into s->mix.vol[]
- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, // voice
- [SOUND_MIXER_LINE1] = 2, // AUX
- [SOUND_MIXER_CD] = 3, // CD
- [SOUND_MIXER_LINE] = 4, // Line
- [SOUND_MIXER_SYNTH] = 5, // FM
- [SOUND_MIXER_MIC] = 6, // Mic
- [SOUND_MIXER_SPEAKER] = 7, // Speaker
- [SOUND_MIXER_RECLEV] = 8, // Recording level
- [SOUND_MIXER_VOLUME] = 9 // Master Volume
- };
-
-
- static const unsigned mixreg[] = {
- BA0_AC97_PCM_OUT_VOLUME,
- BA0_AC97_AUX_VOLUME,
- BA0_AC97_CD_VOLUME,
- BA0_AC97_LINE_IN_VOLUME
- };
- unsigned char l, r, rl, rr, vidx;
- unsigned char attentbl[11] =
- { 63, 42, 26, 17, 14, 11, 8, 6, 4, 2, 0 };
- unsigned temp1;
- int i, val;
-
- VALIDATE_STATE(s);
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
- "cs4281: mixer_ioctl(): s=%p cmd=0x%.8x\n", s, cmd));
-#if CSDEBUG
- cs_printioctl(cmd);
-#endif
-#if CSDEBUG_INTERFACE
-
- if ((cmd == SOUND_MIXER_CS_GETDBGMASK) ||
- (cmd == SOUND_MIXER_CS_SETDBGMASK) ||
- (cmd == SOUND_MIXER_CS_GETDBGLEVEL) ||
- (cmd == SOUND_MIXER_CS_SETDBGLEVEL) ||
- (cmd == SOUND_MIXER_CS_APM))
- {
- switch (cmd) {
-
- case SOUND_MIXER_CS_GETDBGMASK:
- return put_user(cs_debugmask,
- (unsigned long __user *) argp);
-
- case SOUND_MIXER_CS_GETDBGLEVEL:
- return put_user(cs_debuglevel,
- (unsigned long __user *) argp);
-
- case SOUND_MIXER_CS_SETDBGMASK:
- if (get_user(val, (unsigned long __user *) argp))
- return -EFAULT;
- cs_debugmask = val;
- return 0;
-
- case SOUND_MIXER_CS_SETDBGLEVEL:
- if (get_user(val, (unsigned long __user *) argp))
- return -EFAULT;
- cs_debuglevel = val;
- return 0;
-#ifndef NOT_CS4281_PM
- case SOUND_MIXER_CS_APM:
- if (get_user(val, (unsigned long __user *) argp))
- return -EFAULT;
- if(val == CS_IOCTL_CMD_SUSPEND)
- cs4281_suspend(s);
- else if(val == CS_IOCTL_CMD_RESUME)
- cs4281_resume(s);
- else
- {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs4281: mixer_ioctl(): invalid APM cmd (%d)\n",
- val));
- }
- return 0;
-#endif
- default:
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO
- "cs4281: mixer_ioctl(): ERROR unknown debug cmd\n"));
- return 0;
- }
- }
-#endif
-
- if (cmd == SOUND_MIXER_PRIVATE1) {
- // enable/disable/query mixer preamp
- if (get_user(val, (int __user *) argp))
- return -EFAULT;
- if (val != -1) {
- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
- temp1 = val ? (temp1 | 0x40) : (temp1 & 0xffbf);
- cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
- }
- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
- val = (temp1 & 0x40) ? 1 : 0;
- return put_user(val, (int __user *) argp);
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- // enable/disable/query spatializer
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- if (val != -1) {
- temp1 = (val & 0x3f) >> 2;
- cs4281_write_ac97(s, BA0_AC97_3D_CONTROL, temp1);
- cs4281_read_ac97(s, BA0_AC97_GENERAL_PURPOSE,
- &temp1);
- cs4281_write_ac97(s, BA0_AC97_GENERAL_PURPOSE,
- temp1 | 0x2000);
- }
- cs4281_read_ac97(s, BA0_AC97_3D_CONTROL, &temp1);
- return put_user((temp1 << 2) | 3, (int __user *)argp);
- }
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strlcpy(info.id, "CS4281", sizeof(info.id));
- strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strlcpy(info.id, "CS4281", sizeof(info.id));
- strlcpy(info.name, "Crystal CS4281", sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int __user *) argp);
-
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- // If ioctl has only the SIOC_READ bit(bit 31)
- // on, process the only-read commands.
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
- cs4281_read_ac97(s, BA0_AC97_RECORD_SELECT, &temp1);
- return put_user(mixer_src[temp1&7], (int __user *)argp);
-
- case SOUND_MIXER_DEVMASK: // Arg contains a bit for each supported device
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
- SOUND_MASK_CD | SOUND_MASK_LINE |
- SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME |
- SOUND_MASK_RECLEV |
- SOUND_MASK_SPEAKER, (int __user *)argp);
-
- case SOUND_MIXER_RECMASK: // Arg contains a bit for each supported recording source
- return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC |
- SOUND_MASK_CD | SOUND_MASK_VOLUME |
- SOUND_MASK_LINE1, (int __user *) argp);
-
- case SOUND_MIXER_STEREODEVS: // Mixer channels supporting stereo
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH |
- SOUND_MASK_CD | SOUND_MASK_LINE |
- SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME |
- SOUND_MASK_RECLEV, (int __user *)argp);
-
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, (int __user *)argp);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES
- || !(vidx = mixtable1[i]))
- return -EINVAL;
- return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
- }
- }
- // If ioctl doesn't have both the SIOC_READ and
- // the SIOC_WRITE bit set, return invalid.
- if (_SIOC_DIR(cmd) != (_SIOC_READ | _SIOC_WRITE))
- return -EINVAL;
-
- // Increment the count of volume writes.
- s->mix.modcnt++;
-
- // Isolate the command; it must be a write.
- switch (_IOC_NR(cmd)) {
-
- case SOUND_MIXER_RECSRC: // Arg contains a bit for each recording source
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- i = hweight32(val); // i = # bits on in val.
- if (i != 1) // One & only 1 bit must be on.
- return 0;
- for (i = 0; i < sizeof(mixer_src) / sizeof(int); i++) {
- if (val == mixer_src[i]) {
- temp1 = (i << 8) | i;
- cs4281_write_ac97(s,
- BA0_AC97_RECORD_SELECT,
- temp1);
- return 0;
- }
- }
- return 0;
-
- case SOUND_MIXER_VOLUME:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100; // Max soundcard.h vol is 100.
- if (l < 6) {
- rl = 63;
- l = 0;
- } else
- rl = attentbl[(10 * l) / 100]; // Convert 0-100 vol to 63-0 atten.
-
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100; // Max right volume is 100, too
- if (r < 6) {
- rr = 63;
- r = 0;
- } else
- rr = attentbl[(10 * r) / 100]; // Convert volume to attenuation.
-
- if ((rl > 60) && (rr > 60)) // If both l & r are 'low',
- temp1 = 0x8000; // turn on the mute bit.
- else
- temp1 = 0;
-
- temp1 |= (rl << 8) | rr;
-
- cs4281_write_ac97(s, BA0_AC97_MASTER_VOLUME, temp1);
- cs4281_write_ac97(s, BA0_AC97_HEADPHONE_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[8] = ((unsigned int) r << 8) | l;
-#else
- s->mix.vol[8] = val;
-#endif
- return put_user(s->mix.vol[8], (int __user *)argp);
-
- case SOUND_MIXER_SPEAKER:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (l < 3) {
- rl = 0;
- l = 0;
- } else {
- rl = (l * 2 - 5) / 13; // Convert 0-100 range to 0-15.
- l = (rl * 13 + 5) / 2;
- }
-
- if (rl < 3) {
- temp1 = 0x8000;
- rl = 0;
- } else
- temp1 = 0;
- rl = 15 - rl; // Convert volume to attenuation.
- temp1 |= rl << 1;
- cs4281_write_ac97(s, BA0_AC97_PC_BEEP_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[6] = l << 8;
-#else
- s->mix.vol[6] = val;
-#endif
- return put_user(s->mix.vol[6], (int __user *)argp);
-
- case SOUND_MIXER_RECLEV:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- rl = (l * 2 - 5) / 13; // Convert 0-100 scale to 0-15.
- rr = (r * 2 - 5) / 13;
- if (rl < 3 && rr < 3)
- temp1 = 0x8000;
- else
- temp1 = 0;
-
- temp1 = temp1 | (rl << 8) | rr;
- cs4281_write_ac97(s, BA0_AC97_RECORD_GAIN, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[7] = ((unsigned int) r << 8) | l;
-#else
- s->mix.vol[7] = val;
-#endif
- return put_user(s->mix.vol[7], (int __user *)argp);
-
- case SOUND_MIXER_MIC:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (l < 1) {
- l = 0;
- rl = 0;
- } else {
- rl = ((unsigned) l * 5 - 4) / 16; // Convert 0-100 range to 0-31.
- l = (rl * 16 + 4) / 5;
- }
- cs4281_read_ac97(s, BA0_AC97_MIC_VOLUME, &temp1);
- temp1 &= 0x40; // Isolate 20db gain bit.
- if (rl < 3) {
- temp1 |= 0x8000;
- rl = 0;
- }
- rl = 31 - rl; // Convert volume to attenuation.
- temp1 |= rl;
- cs4281_write_ac97(s, BA0_AC97_MIC_VOLUME, temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[5] = val << 8;
-#else
- s->mix.vol[5] = val;
-#endif
- return put_user(s->mix.vol[5], (int __user *)argp);
-
-
- case SOUND_MIXER_SYNTH:
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- rl = (l * 2 - 11) / 3; // Convert 0-100 range to 0-63.
- rr = (r * 2 - 11) / 3;
- if (rl < 3) // If l is low, turn on
- temp1 = 0x0080; // the mute bit.
- else
- temp1 = 0;
-
- rl = 63 - rl; // Convert vol to attenuation.
- writel(temp1 | rl, s->pBA0 + BA0_FMLVC);
- if (rr < 3) // If rr is low, turn on
- temp1 = 0x0080; // the mute bit.
- else
- temp1 = 0;
- rr = 63 - rr; // Convert vol to attenuation.
- writel(temp1 | rr, s->pBA0 + BA0_FMRVC);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[4] = (r << 8) | l;
-#else
- s->mix.vol[4] = val;
-#endif
- return put_user(s->mix.vol[4], (int __user *)argp);
-
-
- default:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: mixer_ioctl(): default\n"));
-
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
- return -EINVAL;
- if (get_user(val, (int __user *)argp))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (l < 1) {
- l = 0;
- rl = 31;
- } else
- rl = (attentbl[(l * 10) / 100]) >> 1;
-
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- if (r < 1) {
- r = 0;
- rr = 31;
- } else
- rr = (attentbl[(r * 10) / 100]) >> 1;
- if ((rl > 30) && (rr > 30))
- temp1 = 0x8000;
- else
- temp1 = 0;
- temp1 = temp1 | (rl << 8) | rr;
- cs4281_write_ac97(s, mixreg[vidx - 1], temp1);
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[vidx - 1] = ((unsigned int) r << 8) | l;
-#else
- s->mix.vol[vidx - 1] = val;
-#endif
-#ifndef NOT_CS4281_PM
- CS_DBGOUT(CS_PM, 9, printk(KERN_INFO
- "write ac97 mixreg[%d]=0x%x mix.vol[]=0x%x\n",
- vidx-1,temp1,s->mix.vol[vidx-1]));
-#endif
- return put_user(s->mix.vol[vidx - 1], (int __user *)argp);
- }
-}
-
-
-// ---------------------------------------------------------------------
-
-static int cs4281_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct cs4281_state *s=NULL;
- struct list_head *entry;
-
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_open_mixdev()+\n"));
-
- list_for_each(entry, &cs4281_devs)
- {
- s = list_entry(entry, struct cs4281_state, list);
- if(s->dev_mixer == minor)
- break;
- }
- if (!s)
- {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2,
- printk(KERN_INFO "cs4281: cs4281_open_mixdev()- -ENODEV\n"));
- return -ENODEV;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
-
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_open_mixdev()- 0\n"));
-
- return nonseekable_open(inode, file);
-}
-
-
-static int cs4281_release_mixdev(struct inode *inode, struct file *file)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-
-static int cs4281_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct cs4281_state *) file->private_data, cmd,
- arg);
-}
-
-
-// ******************************************************************************************
-// Mixer file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = cs4281_ioctl_mixdev,
- .open = cs4281_open_mixdev,
- .release = cs4281_release_mixdev,
-};
-
-// ---------------------------------------------------------------------
-
-
-static int drain_adc(struct cs4281_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
- unsigned tmo;
-
- if (s->dma_adc.mapped)
- return 0;
- add_wait_queue(&s->dma_adc.wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_adc.count;
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: drain_adc() %d\n", count));
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0) {
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: drain_adc() count<0\n"));
- break;
- }
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_adc.wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo =
- 3 * HZ * (count +
- s->dma_adc.fragsize) / 2 / s->prop_adc.rate;
- if (s->prop_adc.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- tmo >>= 1;
- if (s->prop_adc.channels > 1)
- tmo >>= 1;
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "cs4281: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_adc.wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static int drain_dac(struct cs4281_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
- unsigned tmo;
-
- if (s->dma_dac.mapped)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo =
- 3 * HZ * (count +
- s->dma_dac.fragsize) / 2 / s->prop_dac.rate;
- if (s->prop_dac.fmt & (AFMT_S16_LE | AFMT_U16_LE))
- tmo >>= 1;
- if (s->prop_dac.channels > 1)
- tmo >>= 1;
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "cs4281: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-//****************************************************************************
-//
-// CopySamples copies 16-bit stereo samples from the source to the
-// destination, possibly converting down to either 8-bit or mono or both.
-// count specifies the number of output bytes to write.
-//
-// Arguments:
-//
-// dst - Pointer to a destination buffer.
-// src - Pointer to a source buffer
-// count - The number of bytes to copy into the destination buffer.
-// iChannels - Stereo - 2
-// Mono - 1
-// fmt - AFMT_xxx (soundcard.h formats)
-//
-// NOTES: only call this routine for conversion to 8bit from 16bit
-//
-//****************************************************************************
-static void CopySamples(char *dst, char *src, int count, int iChannels,
- unsigned fmt)
-{
-
- unsigned short *psSrc;
- long lAudioSample;
-
- CS_DBGOUT(CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: CopySamples()+ "));
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- " dst=%p src=%p count=%d iChannels=%d fmt=0x%x\n",
- dst, src, (unsigned) count, (unsigned) iChannels, (unsigned) fmt));
-
- // Gershwin does format conversion in hardware so normally
- // we don't do any host based coversion. The data formatter
- // truncates 16 bit data to 8 bit and that causes some hiss.
- // We have already forced the HW to do 16 bit sampling and
- // 2 channel so that we can use software to round instead
- // of truncate
-
- //
- // See if the data should be output as 8-bit unsigned stereo.
- // or if the data should be output at 8-bit unsigned mono.
- //
- if ( ((iChannels == 2) && (fmt & AFMT_U8)) ||
- ((iChannels == 1) && (fmt & AFMT_U8)) ) {
- //
- // Convert each 16-bit unsigned stereo sample to 8-bit unsigned
- // stereo using rounding.
- //
- psSrc = (unsigned short *) src;
- count = count / 2;
- while (count--) {
- lAudioSample = (long) psSrc[count] + (long) 0x80;
- if (lAudioSample > 0xffff) {
- lAudioSample = 0xffff;
- }
- dst[count] = (char) (lAudioSample >> 8);
- }
- }
- //
- // check for 8-bit signed stereo.
- //
- else if ((iChannels == 2) && (fmt & AFMT_S8)) {
- //
- // Convert each 16-bit stereo sample to 8-bit stereo using rounding.
- //
- psSrc = (short *) src;
- while (count--) {
- lAudioSample =
- (((long) psSrc[0] + (long) psSrc[1]) / 2);
- psSrc += 2;
- *dst++ = (char) ((short) lAudioSample >> 8);
- }
- }
- //
- // Otherwise, the data should be output as 8-bit signed mono.
- //
- else if ((iChannels == 1) && (fmt & AFMT_S8)) {
- //
- // Convert each 16-bit signed mono sample to 8-bit signed mono
- // using rounding.
- //
- psSrc = (short *) src;
- count = count / 2;
- while (count--) {
- lAudioSample =
- (((long) psSrc[0] + (long) psSrc[1]) / 2);
- if (lAudioSample > 0x7fff) {
- lAudioSample = 0x7fff;
- }
- psSrc += 2;
- *dst++ = (char) ((short) lAudioSample >> 8);
- }
- }
-}
-
-//
-// cs_copy_to_user()
-// replacement for the standard copy_to_user, to allow for a conversion from
-// 16 bit to 8 bit if the record conversion is active. the cs4281 has some
-// issues with 8 bit capture, so the driver always captures data in 16 bit
-// and then if the user requested 8 bit, converts from 16 to 8 bit.
-//
-static unsigned cs_copy_to_user(struct cs4281_state *s, void __user *dest,
- unsigned *hwsrc, unsigned cnt,
- unsigned *copied)
-{
- void *src = hwsrc; //default to the standard destination buffer addr
-
- CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
- "cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=%p\n",
- s->prop_adc.fmt, s->prop_adc.fmt_original,
- (unsigned) cnt, dest));
-
- if (cnt > s->dma_adc.dmasize) {
- cnt = s->dma_adc.dmasize;
- }
- if (!cnt) {
- *copied = 0;
- return 0;
- }
- if (s->conversion) {
- if (!s->tmpbuff) {
- *copied = cnt / 2;
- return 0;
- }
- CopySamples(s->tmpbuff, (void *) hwsrc, cnt,
- (unsigned) s->prop_adc.channels,
- s->prop_adc.fmt_original);
- src = s->tmpbuff;
- cnt = cnt / 2;
- }
-
- if (copy_to_user(dest, src, cnt)) {
- *copied = 0;
- return -EFAULT;
- }
- *copied = cnt;
- CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: cs_copy_to_user()- copied bytes is %d \n", cnt));
- return 0;
-}
-
-// ---------------------------------------------------------------------
-
-static ssize_t cs4281_read(struct file *file, char __user *buffer, size_t count,
- loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
- unsigned copied = 0;
-
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
- printk(KERN_INFO "cs4281: cs4281_read()+ %Zu \n", count));
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-//
-// "count" is the amount of bytes to read (from app), is decremented each loop
-// by the amount of bytes that have been returned to the user buffer.
-// "cnt" is the running total of each read from the buffer (changes each loop)
-// "buffer" points to the app's buffer
-// "ret" keeps a running total of the amount of bytes that have been copied
-// to the user buffer.
-// "copied" is the total bytes copied into the user buffer for each loop.
-//
- while (count > 0) {
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- "_read() count>0 count=%Zu .count=%d .swptr=%d .hwptr=%d \n",
- count, s->dma_adc.count,
- s->dma_adc.swptr, s->dma_adc.hwptr));
- spin_lock_irqsave(&s->lock, flags);
-
- // get the current copy point of the sw buffer
- swptr = s->dma_adc.swptr;
-
- // cnt is the amount of unread bytes from the end of the
- // hw buffer to the current sw pointer
- cnt = s->dma_adc.dmasize - swptr;
-
- // dma_adc.count is the current total bytes that have not been read.
- // if the amount of unread bytes from the current sw pointer to the
- // end of the buffer is greater than the current total bytes that
- // have not been read, then set the "cnt" (unread bytes) to the
- // amount of unread bytes.
-
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- spin_unlock_irqrestore(&s->lock, flags);
- //
- // if we are converting from 8/16 then we need to copy
- // twice the number of 16 bit bytes then 8 bit bytes.
- //
- if (s->conversion) {
- if (cnt > (count * 2))
- cnt = (count * 2);
- } else {
- if (cnt > count)
- cnt = count;
- }
- //
- // "cnt" NOW is the smaller of the amount that will be read,
- // and the amount that is requested in this read (or partial).
- // if there are no bytes in the buffer to read, then start the
- // ADC and wait for the interrupt handler to wake us up.
- //
- if (cnt <= 0) {
-
- // start up the dma engine and then continue back to the top of
- // the loop when wake up occurs.
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_adc.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- // there are bytes in the buffer to read.
- // copy from the hw buffer over to the user buffer.
- // user buffer is designated by "buffer"
- // virtual address to copy from is rawbuf+swptr
- // the "cnt" is the number of bytes to read.
-
- CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
- "_read() copy_to cnt=%d count=%Zu ", cnt, count));
- CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
- " .dmasize=%d .count=%d buffer=%p ret=%Zd\n",
- s->dma_adc.dmasize, s->dma_adc.count, buffer, ret));
-
- if (cs_copy_to_user
- (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied))
- return ret ? ret : -EFAULT;
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= copied;
- buffer += copied;
- ret += copied;
- start_adc(s);
- }
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
- printk(KERN_INFO "cs4281: cs4281_read()- %Zd\n", ret));
- return ret;
-}
-
-
-static ssize_t cs4281_write(struct file *file, const char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr, hwptr, busaddr;
- int cnt;
-
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
- printk(KERN_INFO "cs4281: cs4281_write()+ count=%Zu\n",
- count));
- VALIDATE_STATE(s);
-
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- if (s->dma_dac.underrun) {
- s->dma_dac.underrun = 0;
- hwptr = readl(s->pBA0 + BA0_DCA0);
- busaddr = virt_to_bus(s->dma_dac.rawbuf);
- hwptr -= (unsigned) busaddr;
- s->dma_dac.swptr = s->dma_dac.hwptr = hwptr;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize - swptr;
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- start_dac(s);
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->dma_dac.wait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt))
- return ret ? ret : -EFAULT;
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(s);
- }
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
- printk(KERN_INFO "cs4281: cs4281_write()- %Zd\n", ret));
- return ret;
-}
-
-
-static unsigned int cs4281_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO "cs4281: cs4281_poll()+\n"));
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO
- "cs4281: cs4281_poll() wait on FMODE_WRITE\n"));
- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO
- "cs4281: cs4281_poll() wait on FMODE_READ\n"));
- if(!s->dma_dac.ready && prog_dmabuf_adc(s))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >=
- (signed) s->dma_dac.fragsize) {
- if (s->dma_dac.wakeup)
- mask |= POLLOUT | POLLWRNORM;
- else
- mask = 0;
- s->dma_dac.wakeup = 0;
- }
- } else {
- if ((signed) (s->dma_dac.dmasize/2) >= s->dma_dac.count)
- mask |= POLLOUT | POLLWRNORM;
- }
- } else if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed) s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- } else {
- if (s->dma_adc.count > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE | CS_WAVE_READ, 4,
- printk(KERN_INFO "cs4281: cs4281_poll()- 0x%.8x\n",
- mask));
- return mask;
-}
-
-
-static int cs4281_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- struct dmabuf *db;
- int ret;
- unsigned long size;
-
- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_mmap()+\n"));
-
- VALIDATE_STATE(s);
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf_dac(s)) != 0)
- return ret;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf_adc(s)) != 0)
- return ret;
- db = &s->dma_adc;
- } else
- return -EINVAL;
-//
-// only support PLAYBACK for now
-//
- db = &s->dma_dac;
-
- if (cs4x_pgoff(vma) != 0)
- return -EINVAL;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- return -EINVAL;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
- db->mapped = 1;
-
- CS_DBGOUT(CS_FUNCTION | CS_PARMS | CS_OPEN, 4,
- printk(KERN_INFO "cs4281: cs4281_mmap()- 0 size=%d\n",
- (unsigned) size));
-
- return 0;
-}
-
-
-static int cs4281_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- int __user *p = (int __user *)arg;
-
- CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): file=%p cmd=0x%.8x\n", file, cmd));
-#if CSDEBUG
- cs_printioctl(cmd);
-#endif
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): SOUND_VERSION=0x%.8x\n",
- SOUND_VERSION));
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SYNC\n"));
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s,
- 0 /*file->f_flags & O_NONBLOCK */
- );
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
- DSP_CAP_TRIGGER | DSP_CAP_MMAP,
- p);
-
- case SNDCTL_DSP_RESET:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_RESET\n"));
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr =
- s->dma_dac.count = s->dma_dac.total_bytes =
- s->dma_dac.blocks = s->dma_dac.wakeup = 0;
- prog_codec(s, CS_TYPE_DAC);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr =
- s->dma_adc.count = s->dma_adc.total_bytes =
- s->dma_adc.blocks = s->dma_dac.wakeup = 0;
- prog_codec(s, CS_TYPE_ADC);
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SPEED val=%d\n", val));
- //
- // support independent capture and playback channels
- // assume that the file mode bit determines the
- // direction of the data flow.
- //
- if (file->f_mode & FMODE_READ) {
- if (val >= 0) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- // program sampling rates
- if (val > 48000)
- val = 48000;
- if (val < 6300)
- val = 6300;
- s->prop_adc.rate = val;
- prog_codec(s, CS_TYPE_ADC);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val >= 0) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- // program sampling rates
- if (val > 48000)
- val = 48000;
- if (val < 6300)
- val = 6300;
- s->prop_dac.rate = val;
- prog_codec(s, CS_TYPE_DAC);
- }
- }
-
- if (file->f_mode & FMODE_WRITE)
- val = s->prop_dac.rate;
- else if (file->f_mode & FMODE_READ)
- val = s->prop_adc.rate;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_STEREO val=%d\n", val));
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- s->prop_adc.channels = val ? 2 : 1;
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- s->prop_dac.channels = val ? 2 : 1;
- prog_codec(s, CS_TYPE_DAC);
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_CHANNELS val=%d\n",
- val));
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- s->prop_adc.channels = 2;
- else
- s->prop_adc.channels = 1;
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- s->prop_dac.channels = 2;
- else
- s->prop_dac.channels = 1;
- prog_codec(s, CS_TYPE_DAC);
- }
- }
-
- if (file->f_mode & FMODE_WRITE)
- val = s->prop_dac.channels;
- else if (file->f_mode & FMODE_READ)
- val = s->prop_adc.channels;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_GETFMTS: // Returns a mask
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_GETFMT val=0x%.8x\n",
- AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
- AFMT_U8));
- return put_user(AFMT_S16_LE | AFMT_U16_LE | AFMT_S8 |
- AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(val, p))
- return -EFAULT;
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SETFMT val=0x%.8x\n",
- val));
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val != AFMT_S16_LE
- && val != AFMT_U16_LE && val != AFMT_S8
- && val != AFMT_U8)
- val = AFMT_U8;
- s->prop_adc.fmt = val;
- s->prop_adc.fmt_original = s->prop_adc.fmt;
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val != AFMT_S16_LE
- && val != AFMT_U16_LE && val != AFMT_S8
- && val != AFMT_U8)
- val = AFMT_U8;
- s->prop_dac.fmt = val;
- s->prop_dac.fmt_original = s->prop_dac.fmt;
- prog_codec(s, CS_TYPE_DAC);
- }
- } else {
- if (file->f_mode & FMODE_WRITE)
- val = s->prop_dac.fmt_original;
- else if (file->f_mode & FMODE_READ)
- val = s->prop_adc.fmt_original;
- }
- CS_DBGOUT(CS_IOCTL | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_SETFMT return val=0x%.8x\n",
- val));
- return put_user(val, p);
-
- case SNDCTL_DSP_POST:
- CS_DBGOUT(CS_IOCTL, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): DSP_POST\n"));
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & s->ena & FMODE_READ)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & s->ena & FMODE_WRITE)
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready
- && (ret = prog_dmabuf_adc(s)))
- return ret;
- start_adc(s);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready
- && (ret = prog_dmabuf_dac(s)))
- return ret;
- start_dac(s);
- } else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)))
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- abinfo.fragsize = s->dma_dac.fragsize;
- if (s->dma_dac.mapped)
- abinfo.bytes = s->dma_dac.dmasize;
- else
- abinfo.bytes =
- s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- CS_DBGOUT(CS_FUNCTION | CS_PARMS, 4, printk(KERN_INFO
- "cs4281: cs4281_ioctl(): GETOSPACE .fragsize=%d .bytes=%d .fragstotal=%d .fragments=%d\n",
- abinfo.fragsize,abinfo.bytes,abinfo.fragstotal,
- abinfo.fragments));
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(p, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)))
- return val;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- if (s->conversion) {
- abinfo.fragsize = s->dma_adc.fragsize / 2;
- abinfo.bytes = s->dma_adc.count / 2;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments =
- abinfo.bytes >> (s->dma_adc.fragshift - 1);
- } else {
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments =
- abinfo.bytes >> s->dma_adc.fragshift;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(p, &abinfo,
- sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if(!s->dma_adc.ready && prog_dmabuf_adc(s))
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- cinfo.bytes = s->dma_adc.total_bytes;
- if (s->dma_adc.mapped) {
- cinfo.blocks =
- (cinfo.bytes >> s->dma_adc.fragshift) -
- s->dma_adc.blocks;
- s->dma_adc.blocks =
- cinfo.bytes >> s->dma_adc.fragshift;
- } else {
- if (s->conversion) {
- cinfo.blocks =
- s->dma_adc.count /
- 2 >> (s->dma_adc.fragshift - 1);
- } else
- cinfo.blocks =
- s->dma_adc.count >> s->dma_adc.
- fragshift;
- }
- if (s->conversion)
- cinfo.ptr = s->dma_adc.hwptr / 2;
- else
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize - 1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(p, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if(!s->dma_dac.ready && prog_dmabuf_dac(s))
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_update_ptr(s,CS_FALSE);
- cinfo.bytes = s->dma_dac.total_bytes;
- if (s->dma_dac.mapped) {
- cinfo.blocks =
- (cinfo.bytes >> s->dma_dac.fragshift) -
- s->dma_dac.blocks;
- s->dma_dac.blocks =
- cinfo.bytes >> s->dma_dac.fragshift;
- } else {
- cinfo.blocks =
- s->dma_dac.count >> s->dma_dac.fragshift;
- }
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize - 1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(p, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf_dac(s)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf_adc(s)))
- return val;
- if (s->conversion)
- return put_user(s->dma_adc.fragsize / 2, p);
- else
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- return 0; // Say OK, but do nothing.
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision)
- || (file->f_mode & FMODE_WRITE
- && s->dma_dac.subdivision)) return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- else if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- if (file->f_mode & FMODE_READ)
- return put_user(s->prop_adc.rate, p);
- else if (file->f_mode & FMODE_WRITE)
- return put_user(s->prop_dac.rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- if (file->f_mode & FMODE_READ)
- return put_user(s->prop_adc.channels, p);
- else if (file->f_mode & FMODE_WRITE)
- return put_user(s->prop_dac.channels, p);
-
- case SOUND_PCM_READ_BITS:
- if (file->f_mode & FMODE_READ)
- return
- put_user(
- (s->prop_adc.
- fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
- p);
- else if (file->f_mode & FMODE_WRITE)
- return
- put_user(
- (s->prop_dac.
- fmt & (AFMT_S8 | AFMT_U8)) ? 8 : 16,
- p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-
-static int cs4281_release(struct inode *inode, struct file *file)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
-
- CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO
- "cs4281: cs4281_release(): inode=%p file=%p f_mode=%d\n",
- inode, file, file->f_mode));
-
- VALIDATE_STATE(s);
-
- if (file->f_mode & FMODE_WRITE) {
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_sem_dac);
- stop_dac(s);
- dealloc_dmabuf(s, &s->dma_dac);
- s->open_mode &= ~FMODE_WRITE;
- mutex_unlock(&s->open_sem_dac);
- wake_up(&s->open_wait_dac);
- }
- if (file->f_mode & FMODE_READ) {
- drain_adc(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_sem_adc);
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- s->open_mode &= ~FMODE_READ;
- mutex_unlock(&s->open_sem_adc);
- wake_up(&s->open_wait_adc);
- }
- return 0;
-}
-
-static int cs4281_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct cs4281_state *s=NULL;
- struct list_head *entry;
-
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): inode=%p file=%p f_mode=0x%x\n",
- inode, file, file->f_mode));
-
- list_for_each(entry, &cs4281_devs)
- {
- s = list_entry(entry, struct cs4281_state, list);
-
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- if (entry == &cs4281_devs)
- return -ENODEV;
- if (!s) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
- return -ENODEV;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
-
- // wait for device to become free
- if (!(file->f_mode & (FMODE_WRITE | FMODE_READ))) {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): Error - must open READ and/or WRITE\n"));
- return -ENODEV;
- }
- if (file->f_mode & FMODE_WRITE) {
- mutex_lock(&s->open_sem_dac);
- while (s->open_mode & FMODE_WRITE) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_sem_dac);
- return -EBUSY;
- }
- mutex_unlock(&s->open_sem_dac);
- interruptible_sleep_on(&s->open_wait_dac);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_sem_dac);
- }
- }
- if (file->f_mode & FMODE_READ) {
- mutex_lock(&s->open_sem_adc);
- while (s->open_mode & FMODE_READ) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_sem_adc);
- return -EBUSY;
- }
- mutex_unlock(&s->open_sem_adc);
- interruptible_sleep_on(&s->open_wait_adc);
-
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_sem_adc);
- }
- }
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- if (file->f_mode & FMODE_READ) {
- s->prop_adc.fmt = AFMT_U8;
- s->prop_adc.fmt_original = s->prop_adc.fmt;
- s->prop_adc.channels = 1;
- s->prop_adc.rate = 8000;
- s->prop_adc.clkdiv = 96 | 0x80;
- s->conversion = 0;
- s->ena &= ~FMODE_READ;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
- s->dma_adc.subdivision = 0;
- mutex_unlock(&s->open_sem_adc);
-
- if (prog_dmabuf_adc(s)) {
- CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
- "cs4281: adc Program dmabufs failed.\n"));
- cs4281_release(inode, file);
- return -ENOMEM;
- }
- prog_codec(s, CS_TYPE_ADC);
- }
- if (file->f_mode & FMODE_WRITE) {
- s->prop_dac.fmt = AFMT_U8;
- s->prop_dac.fmt_original = s->prop_dac.fmt;
- s->prop_dac.channels = 1;
- s->prop_dac.rate = 8000;
- s->prop_dac.clkdiv = 96 | 0x80;
- s->conversion = 0;
- s->ena &= ~FMODE_WRITE;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
- s->dma_dac.subdivision = 0;
- mutex_unlock(&s->open_sem_dac);
-
- if (prog_dmabuf_dac(s)) {
- CS_DBGOUT(CS_OPEN | CS_ERROR, 2, printk(KERN_ERR
- "cs4281: dac Program dmabufs failed.\n"));
- cs4281_release(inode, file);
- return -ENOMEM;
- }
- prog_codec(s, CS_TYPE_DAC);
- }
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2,
- printk(KERN_INFO "cs4281: cs4281_open()- 0\n"));
- return nonseekable_open(inode, file);
-}
-
-
-// ******************************************************************************************
-// Wave (audio) file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = cs4281_read,
- .write = cs4281_write,
- .poll = cs4281_poll,
- .ioctl = cs4281_ioctl,
- .mmap = cs4281_mmap,
- .open = cs4281_open,
- .release = cs4281_release,
-};
-
-// ---------------------------------------------------------------------
-
-// hold spinlock for the following!
-static void cs4281_handle_midi(struct cs4281_state *s)
-{
- unsigned char ch;
- int wake;
- unsigned temp1;
-
- wake = 0;
- while (!(readl(s->pBA0 + BA0_MIDSR) & 0x80)) {
- ch = readl(s->pBA0 + BA0_MIDRP);
- if (s->midi.icnt < MIDIINBUF) {
- s->midi.ibuf[s->midi.iwr] = ch;
- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
- s->midi.icnt++;
- }
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.iwait);
- wake = 0;
- while (!(readl(s->pBA0 + BA0_MIDSR) & 0x40) && s->midi.ocnt > 0) {
- temp1 = (s->midi.obuf[s->midi.ord]) & 0x000000ff;
- writel(temp1, s->pBA0 + BA0_MIDWP);
- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
- s->midi.ocnt--;
- if (s->midi.ocnt < MIDIOUTBUF - 16)
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.owait);
-}
-
-
-
-static irqreturn_t cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct cs4281_state *s = (struct cs4281_state *) dev_id;
- unsigned int temp1;
-
- // fastpath out, to ease interrupt sharing
- temp1 = readl(s->pBA0 + BA0_HISR); // Get Int Status reg.
-
- CS_DBGOUT(CS_INTERRUPT, 6, printk(KERN_INFO
- "cs4281: cs4281_interrupt() BA0_HISR=0x%.8x\n", temp1));
-/*
-* If not DMA or MIDI interrupt, then just return.
-*/
- if (!(temp1 & (HISR_DMA0 | HISR_DMA1 | HISR_MIDI))) {
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR);
- CS_DBGOUT(CS_INTERRUPT, 9, printk(KERN_INFO
- "cs4281: cs4281_interrupt(): returning not cs4281 interrupt.\n"));
- return IRQ_NONE;
- }
-
- if (temp1 & HISR_DMA0) // If play interrupt,
- readl(s->pBA0 + BA0_HDSR0); // clear the source.
-
- if (temp1 & HISR_DMA1) // Same for play.
- readl(s->pBA0 + BA0_HDSR1);
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Local EOI
-
- spin_lock(&s->lock);
- cs4281_update_ptr(s,CS_TRUE);
- cs4281_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-// **************************************************************************
-
-static void cs4281_midi_timer(unsigned long data)
-{
- struct cs4281_state *s = (struct cs4281_state *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- cs4281_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->midi.timer.expires = jiffies + 1;
- add_timer(&s->midi.timer);
-}
-
-
-// ---------------------------------------------------------------------
-
-static ssize_t cs4281_midi_read(struct file *file, char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.ird;
- cnt = MIDIINBUF - ptr;
- if (s->midi.icnt < cnt)
- cnt = s->midi.icnt;
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->midi.iwait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt))
- return ret ? ret : -EFAULT;
- ptr = (ptr + cnt) % MIDIINBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.ird = ptr;
- s->midi.icnt -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
- return ret;
-}
-
-
-static ssize_t cs4281_midi_write(struct file *file, const char __user *buffer,
- size_t count, loff_t * ppos)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.owr;
- cnt = MIDIOUTBUF - ptr;
- if (s->midi.ocnt + cnt > MIDIOUTBUF)
- cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0)
- cs4281_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
- interruptible_sleep_on(&s->midi.owait);
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- continue;
- }
- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt))
- return ret ? ret : -EFAULT;
- ptr = (ptr + cnt) % MIDIOUTBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.owr = ptr;
- s->midi.ocnt += cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_lock_irqsave(&s->lock, flags);
- cs4281_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return ret;
-}
-
-
-static unsigned int cs4281_midi_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_flags & FMODE_WRITE)
- poll_wait(file, &s->midi.owait, wait);
- if (file->f_flags & FMODE_READ)
- poll_wait(file, &s->midi.iwait, wait);
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_flags & FMODE_READ) {
- if (s->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_flags & FMODE_WRITE) {
- if (s->midi.ocnt < MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-
-static int cs4281_midi_open(struct inode *inode, struct file *file)
-{
- unsigned long flags, temp1;
- unsigned int minor = iminor(inode);
- struct cs4281_state *s=NULL;
- struct list_head *entry;
- list_for_each(entry, &cs4281_devs)
- {
- s = list_entry(entry, struct cs4281_state, list);
-
- if (s->dev_midi == minor)
- break;
- }
-
- if (entry == &cs4281_devs)
- return -ENODEV;
- if (!s)
- {
- CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
- "cs4281: cs4281_open(): Error - unable to find audio state struct\n"));
- return -ENODEV;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- // wait for device to become free
- mutex_lock(&s->open_sem);
- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_sem);
- return -EBUSY;
- }
- mutex_unlock(&s->open_sem);
- interruptible_sleep_on(&s->open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_sem);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- writel(1, s->pBA0 + BA0_MIDCR); // Reset the interface.
- writel(0, s->pBA0 + BA0_MIDCR); // Return to normal mode.
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- writel(0x0000000f, s->pBA0 + BA0_MIDCR); // Enable transmit, record, ints.
- temp1 = readl(s->pBA0 + BA0_HIMR);
- writel(temp1 & 0xffbfffff, s->pBA0 + BA0_HIMR); // Enable midi int. recognition.
- writel(HICR_IEV | HICR_CHGM, s->pBA0 + BA0_HICR); // Enable interrupts
- init_timer(&s->midi.timer);
- s->midi.timer.expires = jiffies + 1;
- s->midi.timer.data = (unsigned long) s;
- s->midi.timer.function = cs4281_midi_timer;
- add_timer(&s->midi.timer);
- }
- if (file->f_mode & FMODE_READ) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |=
- (file->
- f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ |
- FMODE_MIDI_WRITE);
- mutex_unlock(&s->open_sem);
- return nonseekable_open(inode, file);
-}
-
-
-static int cs4281_midi_release(struct inode *inode, struct file *file)
-{
- struct cs4281_state *s =
- (struct cs4281_state *) file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- unsigned count, tmo;
-
- VALIDATE_STATE(s);
-
- if (file->f_mode & FMODE_WRITE) {
- add_wait_queue(&s->midi.owait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->midi.ocnt;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (file->f_flags & O_NONBLOCK) {
- remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG
- "cs4281: midi timed out??\n");
- }
- remove_wait_queue(&s->midi.owait, &wait);
- current->state = TASK_RUNNING;
- }
- mutex_lock(&s->open_sem);
- s->open_mode &=
- (~(file->f_mode << FMODE_MIDI_SHIFT)) & (FMODE_MIDI_READ |
- FMODE_MIDI_WRITE);
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- writel(0, s->pBA0 + BA0_MIDCR); // Disable Midi interrupts.
- del_timer(&s->midi.timer);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- mutex_unlock(&s->open_sem);
- wake_up(&s->open_wait);
- return 0;
-}
-
-// ******************************************************************************************
-// Midi file operations struct.
-// ******************************************************************************************
-static /*const */ struct file_operations cs4281_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = cs4281_midi_read,
- .write = cs4281_midi_write,
- .poll = cs4281_midi_poll,
- .open = cs4281_midi_open,
- .release = cs4281_midi_release,
-};
-
-
-// ---------------------------------------------------------------------
-
-// maximum number of devices
-#define NR_DEVICE 8 // Only eight devices supported currently.
-
-// ---------------------------------------------------------------------
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
-
- {
- SOUND_MIXER_WRITE_VOLUME, 0x4040}, {
- SOUND_MIXER_WRITE_PCM, 0x4040}, {
- SOUND_MIXER_WRITE_SYNTH, 0x4040}, {
- SOUND_MIXER_WRITE_CD, 0x4040}, {
- SOUND_MIXER_WRITE_LINE, 0x4040}, {
- SOUND_MIXER_WRITE_LINE1, 0x4040}, {
- SOUND_MIXER_WRITE_RECLEV, 0x0000}, {
- SOUND_MIXER_WRITE_SPEAKER, 0x4040}, {
- SOUND_MIXER_WRITE_MIC, 0x0000}
-};
-
-
-#ifndef NOT_CS4281_PM
-static void __devinit cs4281_BuildFIFO(
- struct cs4281_pipeline *p,
- struct cs4281_state *s)
-{
- switch(p->number)
- {
- case 0: /* playback */
- {
- p->u32FCRnAddress = BA0_FCR0;
- p->u32FSICnAddress = BA0_FSIC0;
- p->u32FPDRnAddress = BA0_FPDR0;
- break;
- }
- case 1: /* capture */
- {
- p->u32FCRnAddress = BA0_FCR1;
- p->u32FSICnAddress = BA0_FSIC1;
- p->u32FPDRnAddress = BA0_FPDR1;
- break;
- }
-
- case 2:
- {
- p->u32FCRnAddress = BA0_FCR2;
- p->u32FSICnAddress = BA0_FSIC2;
- p->u32FPDRnAddress = BA0_FPDR2;
- break;
- }
- case 3:
- {
- p->u32FCRnAddress = BA0_FCR3;
- p->u32FSICnAddress = BA0_FSIC3;
- p->u32FPDRnAddress = BA0_FPDR3;
- break;
- }
- default:
- break;
- }
- //
- // first read the hardware to initialize the member variables
- //
- p->u32FCRnValue = readl(s->pBA0 + p->u32FCRnAddress);
- p->u32FSICnValue = readl(s->pBA0 + p->u32FSICnAddress);
- p->u32FPDRnValue = readl(s->pBA0 + p->u32FPDRnAddress);
-
-}
-
-static void __devinit cs4281_BuildDMAengine(
- struct cs4281_pipeline *p,
- struct cs4281_state *s)
-{
-/*
-* initialize all the addresses of this pipeline dma info.
-*/
- switch(p->number)
- {
- case 0: /* playback */
- {
- p->u32DBAnAddress = BA0_DBA0;
- p->u32DCAnAddress = BA0_DCA0;
- p->u32DBCnAddress = BA0_DBC0;
- p->u32DCCnAddress = BA0_DCC0;
- p->u32DMRnAddress = BA0_DMR0;
- p->u32DCRnAddress = BA0_DCR0;
- p->u32HDSRnAddress = BA0_HDSR0;
- break;
- }
-
- case 1: /* capture */
- {
- p->u32DBAnAddress = BA0_DBA1;
- p->u32DCAnAddress = BA0_DCA1;
- p->u32DBCnAddress = BA0_DBC1;
- p->u32DCCnAddress = BA0_DCC1;
- p->u32DMRnAddress = BA0_DMR1;
- p->u32DCRnAddress = BA0_DCR1;
- p->u32HDSRnAddress = BA0_HDSR1;
- break;
- }
-
- case 2:
- {
- p->u32DBAnAddress = BA0_DBA2;
- p->u32DCAnAddress = BA0_DCA2;
- p->u32DBCnAddress = BA0_DBC2;
- p->u32DCCnAddress = BA0_DCC2;
- p->u32DMRnAddress = BA0_DMR2;
- p->u32DCRnAddress = BA0_DCR2;
- p->u32HDSRnAddress = BA0_HDSR2;
- break;
- }
-
- case 3:
- {
- p->u32DBAnAddress = BA0_DBA3;
- p->u32DCAnAddress = BA0_DCA3;
- p->u32DBCnAddress = BA0_DBC3;
- p->u32DCCnAddress = BA0_DCC3;
- p->u32DMRnAddress = BA0_DMR3;
- p->u32DCRnAddress = BA0_DCR3;
- p->u32HDSRnAddress = BA0_HDSR3;
- break;
- }
- default:
- break;
- }
-
-//
-// Initialize the dma values for this pipeline
-//
- p->u32DBAnValue = readl(s->pBA0 + p->u32DBAnAddress);
- p->u32DBCnValue = readl(s->pBA0 + p->u32DBCnAddress);
- p->u32DMRnValue = readl(s->pBA0 + p->u32DMRnAddress);
- p->u32DCRnValue = readl(s->pBA0 + p->u32DCRnAddress);
-
-}
-
-static void __devinit cs4281_InitPM(struct cs4281_state *s)
-{
- int i;
- struct cs4281_pipeline *p;
-
- for(i=0;i<CS4281_NUMBER_OF_PIPELINES;i++)
- {
- p = &s->pl[i];
- p->number = i;
- cs4281_BuildDMAengine(p,s);
- cs4281_BuildFIFO(p,s);
- /*
- * currently only 2 pipelines are used
- * so, only set the valid bit on the playback and capture.
- */
- if( (i == CS4281_PLAYBACK_PIPELINE_NUMBER) ||
- (i == CS4281_CAPTURE_PIPELINE_NUMBER))
- p->flags |= CS4281_PIPELINE_VALID;
- }
- s->pm.u32SSPM_BITS = 0x7e; /* rev c, use 0x7c for rev a or b */
-}
-#endif
-
-static int __devinit cs4281_probe(struct pci_dev *pcidev,
- const struct pci_device_id *pciid)
-{
- struct cs4281_state *s;
- dma_addr_t dma_mask;
- mm_segment_t fs;
- int i, val;
- unsigned int temp1, temp2;
-
- CS_DBGOUT(CS_FUNCTION | CS_INIT, 2,
- printk(KERN_INFO "cs4281: probe()+\n"));
-
- if (pci_enable_device(pcidev)) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: pci_enable_device() failed\n"));
- return -1;
- }
- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_MEM) ||
- !(pci_resource_flags(pcidev, 1) & IORESOURCE_MEM)) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe()- Memory region not assigned\n"));
- return -ENODEV;
- }
- if (pcidev->irq == 0) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() IRQ not assigned\n"));
- return -ENODEV;
- }
- dma_mask = 0xffffffff; /* this enables playback and recording */
- i = pci_set_dma_mask(pcidev, dma_mask);
- if (i) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() architecture does not support 32bit PCI busmaster DMA\n"));
- return i;
- }
- if (!(s = kmalloc(sizeof(struct cs4281_state), GFP_KERNEL))) {
- CS_DBGOUT(CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() no memory for state struct.\n"));
- return -1;
- }
- memset(s, 0, sizeof(struct cs4281_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->open_wait_adc);
- init_waitqueue_head(&s->open_wait_dac);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- mutex_init(&s->open_sem);
- mutex_init(&s->open_sem_adc);
- mutex_init(&s->open_sem_dac);
- spin_lock_init(&s->lock);
- s->pBA0phys = pci_resource_start(pcidev, 0);
- s->pBA1phys = pci_resource_start(pcidev, 1);
-
- /* Convert phys to linear. */
- s->pBA0 = ioremap_nocache(s->pBA0phys, 4096);
- if (!s->pBA0) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
- "cs4281: BA0 I/O mapping failed. Skipping part.\n"));
- goto err_free;
- }
- s->pBA1 = ioremap_nocache(s->pBA1phys, 65536);
- if (!s->pBA1) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
- "cs4281: BA1 I/O mapping failed. Skipping part.\n"));
- goto err_unmap;
- }
-
- temp1 = readl(s->pBA0 + BA0_PCICFG00);
- temp2 = readl(s->pBA0 + BA0_PCICFG04);
-
- CS_DBGOUT(CS_INIT, 2,
- printk(KERN_INFO
- "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=%p pBA1=%p \n",
- (unsigned) temp1, (unsigned) temp2, s->pBA0, s->pBA1));
- CS_DBGOUT(CS_INIT, 2,
- printk(KERN_INFO
- "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
- (unsigned) s->pBA0phys, (unsigned) s->pBA1phys));
-
-#ifndef NOT_CS4281_PM
- s->pm.flags = CS4281_PM_IDLE;
-#endif
- temp1 = cs4281_hw_init(s);
- if (temp1) {
- CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_ERR
- "cs4281: cs4281_hw_init() failed. Skipping part.\n"));
- goto err_irq;
- }
- s->magic = CS4281_MAGIC;
- s->pcidev = pcidev;
- s->irq = pcidev->irq;
- if (request_irq
- (s->irq, cs4281_interrupt, IRQF_SHARED, "Crystal CS4281", s)) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1,
- printk(KERN_ERR "cs4281: irq %u in use\n", s->irq));
- goto err_irq;
- }
- if ((s->dev_audio = register_sound_dsp(&cs4281_audio_fops, -1)) <
- 0) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() register_sound_dsp() failed.\n"));
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&cs4281_mixer_fops, -1)) <
- 0) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() register_sound_mixer() failed.\n"));
- goto err_dev2;
- }
- if ((s->dev_midi = register_sound_midi(&cs4281_midi_fops, -1)) < 0) {
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_ERR
- "cs4281: probe() register_sound_midi() failed.\n"));
- goto err_dev3;
- }
-#ifndef NOT_CS4281_PM
- cs4281_InitPM(s);
- s->pm.flags |= CS4281_PM_NOT_REGISTERED;
-#endif
-
- pci_set_master(pcidev); // enable bus mastering
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long) &val);
- for (i = 0; i < sizeof(initvol) / sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long) &val);
- }
- val = 1; // enable mic preamp
- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long) &val);
- set_fs(fs);
-
- pci_set_drvdata(pcidev, s);
- list_add(&s->list, &cs4281_devs);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: probe()- device allocated successfully\n"));
- return 0;
-
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- free_irq(s->irq, s);
- err_irq:
- iounmap(s->pBA1);
- err_unmap:
- iounmap(s->pBA0);
- err_free:
- kfree(s);
-
- CS_DBGOUT(CS_INIT | CS_ERROR, 1, printk(KERN_INFO
- "cs4281: probe()- no device allocated\n"));
- return -ENODEV;
-} // probe_cs4281
-
-
-// ---------------------------------------------------------------------
-
-static void __devexit cs4281_remove(struct pci_dev *pci_dev)
-{
- struct cs4281_state *s = pci_get_drvdata(pci_dev);
- // stop DMA controller
- synchronize_irq(s->irq);
- free_irq(s->irq, s);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_midi(s->dev_midi);
- iounmap(s->pBA1);
- iounmap(s->pBA0);
- pci_set_drvdata(pci_dev,NULL);
- list_del(&s->list);
- kfree(s);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: cs4281_remove()-: remove successful\n"));
-}
-
-static struct pci_device_id cs4281_pci_tbl[] = {
- {
- .vendor = PCI_VENDOR_ID_CIRRUS,
- .device = PCI_DEVICE_ID_CRYSTAL_CS4281,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, cs4281_pci_tbl);
-
-static struct pci_driver cs4281_pci_driver = {
- .name = "cs4281",
- .id_table = cs4281_pci_tbl,
- .probe = cs4281_probe,
- .remove = __devexit_p(cs4281_remove),
- .suspend = CS4281_SUSPEND_TBL,
- .resume = CS4281_RESUME_TBL,
-};
-
-static int __init cs4281_init_module(void)
-{
- int rtn = 0;
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO
- "cs4281: cs4281_init_module()+ \n"));
- printk(KERN_INFO "cs4281: version v%d.%02d.%d time " __TIME__ " "
- __DATE__ "\n", CS4281_MAJOR_VERSION, CS4281_MINOR_VERSION,
- CS4281_ARCH);
- rtn = pci_register_driver(&cs4281_pci_driver);
-
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cs4281_init_module()- (%d)\n",rtn));
- return rtn;
-}
-
-static void __exit cs4281_cleanup_module(void)
-{
- pci_unregister_driver(&cs4281_pci_driver);
- CS_DBGOUT(CS_INIT | CS_FUNCTION, 2,
- printk(KERN_INFO "cs4281: cleanup_cs4281() finished\n"));
-}
-// ---------------------------------------------------------------------
-
-MODULE_AUTHOR("gw boynton, audio@crystal.cirrus.com");
-MODULE_DESCRIPTION("Cirrus Logic CS4281 Driver");
-MODULE_LICENSE("GPL");
-
-// ---------------------------------------------------------------------
-
-module_init(cs4281_init_module);
-module_exit(cs4281_cleanup_module);
-
diff --git a/sound/oss/cs4281/cs4281pm-24.c b/sound/oss/cs4281/cs4281pm-24.c
deleted file mode 100644
index 90cbd7679534..000000000000
--- a/sound/oss/cs4281/cs4281pm-24.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*******************************************************************************
-*
-* "cs4281pm.c" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* 12/22/00 trw - new file.
-*
-*******************************************************************************/
-
-#ifndef NOT_CS4281_PM
-#include <linux/pm.h>
-
-static int cs4281_suspend(struct cs4281_state *s);
-static int cs4281_resume(struct cs4281_state *s);
-/*
-* for now (12/22/00) only enable the pm_register PM support.
-* allow these table entries to be null.
-#define CS4281_SUSPEND_TBL cs4281_suspend_tbl
-#define CS4281_RESUME_TBL cs4281_resume_tbl
-*/
-#define CS4281_SUSPEND_TBL cs4281_suspend_null
-#define CS4281_RESUME_TBL cs4281_resume_null
-
-#else /* CS4281_PM */
-#define CS4281_SUSPEND_TBL cs4281_suspend_null
-#define CS4281_RESUME_TBL cs4281_resume_null
-#endif /* CS4281_PM */
-
diff --git a/sound/oss/cs4281/cs4281pm.h b/sound/oss/cs4281/cs4281pm.h
deleted file mode 100644
index b44fdc9ce002..000000000000
--- a/sound/oss/cs4281/cs4281pm.h
+++ /dev/null
@@ -1,74 +0,0 @@
-#ifndef NOT_CS4281_PM
-/*******************************************************************************
-*
-* "cs4281pm.h" -- Cirrus Logic-Crystal CS4281 linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (audio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* 12/22/00 trw - new file.
-*
-*******************************************************************************/
-/* general pm definitions */
-#define CS4281_AC97_HIGHESTREGTORESTORE 0x26
-#define CS4281_AC97_NUMBER_RESTORE_REGS (CS4281_AC97_HIGHESTREGTORESTORE/2-1)
-
-/* pipeline definitions */
-#define CS4281_NUMBER_OF_PIPELINES 4
-#define CS4281_PIPELINE_VALID 0x0001
-#define CS4281_PLAYBACK_PIPELINE_NUMBER 0x0000
-#define CS4281_CAPTURE_PIPELINE_NUMBER 0x0001
-
-/* PM state defintions */
-#define CS4281_PM_NOT_REGISTERED 0x1000
-#define CS4281_PM_IDLE 0x0001
-#define CS4281_PM_SUSPENDING 0x0002
-#define CS4281_PM_SUSPENDED 0x0004
-#define CS4281_PM_RESUMING 0x0008
-#define CS4281_PM_RESUMED 0x0010
-
-struct cs4281_pm {
- unsigned long flags;
- u32 u32CLKCR1_SAVE,u32SSPMValue,u32PPLVCvalue,u32PPRVCvalue;
- u32 u32FMLVCvalue,u32FMRVCvalue,u32GPIORvalue,u32JSCTLvalue,u32SSCR;
- u32 u32SRCSA,u32DacASR,u32AdcASR,u32DacSR,u32AdcSR,u32MIDCR_Save;
- u32 u32SSPM_BITS;
- u32 ac97[CS4281_AC97_NUMBER_RESTORE_REGS];
- u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono;
- u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose;
- u32 u32hwptr_playback,u32hwptr_capture;
-};
-
-struct cs4281_pipeline {
- unsigned flags;
- unsigned number;
- u32 u32DBAnValue,u32DBCnValue,u32DMRnValue,u32DCRnValue;
- u32 u32DBAnAddress,u32DCAnAddress,u32DBCnAddress,u32DCCnAddress;
- u32 u32DMRnAddress,u32DCRnAddress,u32HDSRnAddress;
- u32 u32DBAn_Save,u32DBCn_Save,u32DMRn_Save,u32DCRn_Save;
- u32 u32DCCn_Save,u32DCAn_Save;
-/*
-* technically, these are fifo variables, but just map the
-* first fifo with the first pipeline and then use the fifo
-* variables inside of the pipeline struct.
-*/
- u32 u32FCRn_Save,u32FSICn_Save;
- u32 u32FCRnValue,u32FCRnAddress,u32FSICnValue,u32FSICnAddress;
- u32 u32FPDRnValue,u32FPDRnAddress;
-};
-#endif
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
index 5195bf933cb8..6e3c41f530e6 100644
--- a/sound/oss/cs46xx.c
+++ b/sound/oss/cs46xx.c
@@ -96,7 +96,7 @@
#include <asm/dma.h>
#include <asm/uaccess.h>
-#include "cs46xxpm-24.h"
+#include "cs46xxpm.h"
#include "cs46xx_wrapper-24.h"
#include "cs461x.h"
@@ -389,8 +389,10 @@ static int cs_hardware_init(struct cs_card *card);
static int cs46xx_powerup(struct cs_card *card, unsigned int type);
static int cs461x_powerdown(struct cs_card *card, unsigned int type, int suspendflag);
static void cs461x_clear_serial_FIFOs(struct cs_card *card, int type);
+#ifdef CONFIG_PM
static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
static int cs46xx_resume_tbl(struct pci_dev *pcidev);
+#endif
#if CSDEBUG
@@ -1611,7 +1613,7 @@ static void cs_handle_midi(struct cs_card *card)
wake_up(&card->midi.owait);
}
-static irqreturn_t cs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cs_interrupt(int irq, void *dev_id)
{
struct cs_card *card = (struct cs_card *)dev_id;
/* Single channel card */
@@ -2980,7 +2982,7 @@ static void clkrun_hack(struct cs_card *card, int change)
card->active+=change;
- acpi_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
+ acpi_dev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
if (acpi_dev == NULL)
return; /* Not a thinkpad thats for sure */
@@ -3006,6 +3008,7 @@ static void clkrun_hack(struct cs_card *card, int change)
change,card->active));
outw(control&~0x2000, port+0x10);
}
+ pci_dev_put(acpi_dev);
}
@@ -5389,8 +5392,10 @@ static struct pci_driver cs46xx_pci_driver = {
.id_table = cs46xx_pci_tbl,
.probe = cs46xx_probe,
.remove = __devexit_p(cs46xx_remove),
- .suspend = CS46XX_SUSPEND_TBL,
- .resume = CS46XX_RESUME_TBL,
+#ifdef CONFIG_PM
+ .suspend = cs46xx_suspend_tbl,
+ .resume = cs46xx_resume_tbl,
+#endif
};
static int __init cs46xx_init_module(void)
@@ -5420,7 +5425,7 @@ static void __exit cs46xx_cleanup_module(void)
module_init(cs46xx_init_module);
module_exit(cs46xx_cleanup_module);
-#if CS46XX_ACPI_SUPPORT
+#ifdef CONFIG_PM
static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
{
struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
diff --git a/sound/oss/cs46xxpm-24.h b/sound/oss/cs46xxpm-24.h
deleted file mode 100644
index ad82db84d013..000000000000
--- a/sound/oss/cs46xxpm-24.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*******************************************************************************
-*
-* "cs46xxpm-24.h" -- Cirrus Logic-Crystal CS46XX linux audio driver.
-*
-* Copyright (C) 2000,2001 Cirrus Logic Corp.
-* -- tom woller (twoller@crystal.cirrus.com) or
-* (pcaudio@crystal.cirrus.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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*
-* 12/22/00 trw - new file.
-*
-*******************************************************************************/
-#ifndef __CS46XXPM24_H
-#define __CS46XXPM24_H
-
-#include <linux/pm.h>
-#include "cs46xxpm.h"
-
-
-#define CS46XX_ACPI_SUPPORT 1
-#ifdef CS46XX_ACPI_SUPPORT
-/*
-* for now (12/22/00) only enable the pm_register PM support.
-* allow these table entries to be null.
-*/
-static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state);
-static int cs46xx_resume_tbl(struct pci_dev *pcidev);
-#define CS46XX_SUSPEND_TBL cs46xx_suspend_tbl
-#define CS46XX_RESUME_TBL cs46xx_resume_tbl
-#else
-#define CS46XX_SUSPEND_TBL cs46xx_null
-#define CS46XX_RESUME_TBL cs46xx_null
-#endif
-
-#endif
diff --git a/sound/oss/dev_table.c b/sound/oss/dev_table.c
index f65a90469d8a..08274c995d06 100644
--- a/sound/oss/dev_table.c
+++ b/sound/oss/dev_table.c
@@ -1,5 +1,5 @@
/*
- * sound/dev_table.c
+ * sound/oss/dev_table.c
*
* Device call tables.
*
@@ -13,9 +13,39 @@
#include <linux/init.h>
-#define _DEV_TABLE_C_
#include "sound_config.h"
+struct audio_operations *audio_devs[MAX_AUDIO_DEV];
+EXPORT_SYMBOL(audio_devs);
+
+int num_audiodevs;
+EXPORT_SYMBOL(num_audiodevs);
+
+struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
+EXPORT_SYMBOL(mixer_devs);
+
+int num_mixers;
+EXPORT_SYMBOL(num_mixers);
+
+struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
+EXPORT_SYMBOL(synth_devs);
+
+int num_synths;
+
+struct midi_operations *midi_devs[MAX_MIDI_DEV];
+EXPORT_SYMBOL(midi_devs);
+
+int num_midis;
+EXPORT_SYMBOL(num_midis);
+
+struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
+ &default_sound_timer, NULL
+};
+EXPORT_SYMBOL(sound_timer_devs);
+
+int num_sound_timers = 1;
+
+
static int sound_alloc_audiodev(void);
int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
@@ -75,6 +105,7 @@ int sound_install_audiodrv(int vers, char *name, struct audio_driver *driver,
audio_init_devices();
return num;
}
+EXPORT_SYMBOL(sound_install_audiodrv);
int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
int driver_size, void *devc)
@@ -113,6 +144,7 @@ int sound_install_mixer(int vers, char *name, struct mixer_operations *driver,
mixer_devs[n] = op;
return n;
}
+EXPORT_SYMBOL(sound_install_mixer);
void sound_unload_audiodev(int dev)
{
@@ -122,6 +154,7 @@ void sound_unload_audiodev(int dev)
unregister_sound_dsp((dev<<4)+3);
}
}
+EXPORT_SYMBOL(sound_unload_audiodev);
static int sound_alloc_audiodev(void)
{
@@ -144,6 +177,7 @@ int sound_alloc_mididev(void)
num_midis = i + 1;
return i;
}
+EXPORT_SYMBOL(sound_alloc_mididev);
int sound_alloc_synthdev(void)
{
@@ -158,6 +192,7 @@ int sound_alloc_synthdev(void)
}
return -1;
}
+EXPORT_SYMBOL(sound_alloc_synthdev);
int sound_alloc_mixerdev(void)
{
@@ -169,6 +204,7 @@ int sound_alloc_mixerdev(void)
num_mixers = i + 1;
return i;
}
+EXPORT_SYMBOL(sound_alloc_mixerdev);
int sound_alloc_timerdev(void)
{
@@ -183,6 +219,7 @@ int sound_alloc_timerdev(void)
}
return -1;
}
+EXPORT_SYMBOL(sound_alloc_timerdev);
void sound_unload_mixerdev(int dev)
{
@@ -192,6 +229,7 @@ void sound_unload_mixerdev(int dev)
num_mixers--;
}
}
+EXPORT_SYMBOL(sound_unload_mixerdev);
void sound_unload_mididev(int dev)
{
@@ -200,15 +238,19 @@ void sound_unload_mididev(int dev)
unregister_sound_midi((dev<<4)+2);
}
}
+EXPORT_SYMBOL(sound_unload_mididev);
void sound_unload_synthdev(int dev)
{
if (dev != -1)
synth_devs[dev] = NULL;
}
+EXPORT_SYMBOL(sound_unload_synthdev);
void sound_unload_timerdev(int dev)
{
if (dev != -1)
sound_timer_devs[dev] = NULL;
}
+EXPORT_SYMBOL(sound_unload_timerdev);
+
diff --git a/sound/oss/dev_table.h b/sound/oss/dev_table.h
index adf1d625b576..b7617bee6388 100644
--- a/sound/oss/dev_table.h
+++ b/sound/oss/dev_table.h
@@ -352,22 +352,8 @@ struct sound_timer_operations
void (*arm_timer)(int dev, long time);
};
-#ifdef _DEV_TABLE_C_
-struct audio_operations *audio_devs[MAX_AUDIO_DEV];
-int num_audiodevs;
-struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
-int num_mixers;
-struct synth_operations *synth_devs[MAX_SYNTH_DEV+MAX_MIDI_DEV];
-int num_synths;
-struct midi_operations *midi_devs[MAX_MIDI_DEV];
-int num_midis;
-
extern struct sound_timer_operations default_sound_timer;
-struct sound_timer_operations *sound_timer_devs[MAX_TIMER_DEV] = {
- &default_sound_timer, NULL
-};
-int num_sound_timers = 1;
-#else
+
extern struct audio_operations *audio_devs[MAX_AUDIO_DEV];
extern int num_audiodevs;
extern struct mixer_operations *mixer_devs[MAX_MIXER_DEV];
@@ -378,7 +364,6 @@ extern struct midi_operations *midi_devs[MAX_MIDI_DEV];
extern int num_midis;
extern struct sound_timer_operations * sound_timer_devs[MAX_TIMER_DEV];
extern int num_sound_timers;
-#endif /* _DEV_TABLE_C_ */
extern int sound_map_buffer (int dev, struct dma_buffparms *dmap, buffmem_desc *info);
void sound_timer_init (struct sound_lowlev_timer *t, char *name);
diff --git a/sound/oss/dm.h b/sound/oss/dm.h
deleted file mode 100644
index 14a90593c44f..000000000000
--- a/sound/oss/dm.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef _DRIVERS_SOUND_DM_H
-#define _DRIVERS_SOUND_DM_H
-
-/*
- * Definitions of the 'direct midi sound' interface used
- * by the newer commercial OSS package. We should export
- * this to userland somewhere in glibc later.
- */
-
-/*
- * Data structure composing an FM "note" or sound event.
- */
-
-struct dm_fm_voice
-{
- u8 op;
- u8 voice;
- u8 am;
- u8 vibrato;
- u8 do_sustain;
- u8 kbd_scale;
- u8 harmonic;
- u8 scale_level;
- u8 volume;
- u8 attack;
- u8 decay;
- u8 sustain;
- u8 release;
- u8 feedback;
- u8 connection;
- u8 left;
- u8 right;
- u8 waveform;
-};
-
-/*
- * This describes an FM note by its voice, octave, frequency number (10bit)
- * and key on/off.
- */
-
-struct dm_fm_note
-{
- u8 voice;
- u8 octave;
- u32 fnum;
- u8 key_on;
-};
-
-/*
- * FM parameters that apply globally to all voices, and thus are not "notes"
- */
-
-struct dm_fm_params
-{
- u8 am_depth;
- u8 vib_depth;
- u8 kbd_split;
- u8 rhythm;
-
- /* This block is the percussion instrument data */
- u8 bass;
- u8 snare;
- u8 tomtom;
- u8 cymbal;
- u8 hihat;
-};
-
-/*
- * FM mode ioctl settings
- */
-
-#define FM_IOCTL_RESET 0x20
-#define FM_IOCTL_PLAY_NOTE 0x21
-#define FM_IOCTL_SET_VOICE 0x22
-#define FM_IOCTL_SET_PARAMS 0x23
-#define FM_IOCTL_SET_MODE 0x24
-#define FM_IOCTL_SET_OPL 0x25
-
-#endif
diff --git a/sound/oss/dmabuf.c b/sound/oss/dmabuf.c
index 15ce7119c5f4..b256c0401161 100644
--- a/sound/oss/dmabuf.c
+++ b/sound/oss/dmabuf.c
@@ -1,5 +1,5 @@
/*
- * sound/dmabuf.c
+ * sound/oss/dmabuf.c
*
* The DMA buffer manager for digitized voice applications
*/
@@ -926,6 +926,7 @@ int DMAbuf_start_dma(int dev, unsigned long physaddr, int count, int dma_mode)
sound_start_dma(dmap, physaddr, count, dma_mode);
return count;
}
+EXPORT_SYMBOL(DMAbuf_start_dma);
static int local_start_dma(struct audio_operations *adev, unsigned long physaddr, int count, int dma_mode)
{
@@ -1055,6 +1056,8 @@ void DMAbuf_outputintr(int dev, int notify_only)
do_outputintr(dev, notify_only);
spin_unlock_irqrestore(&dmap->lock,flags);
}
+EXPORT_SYMBOL(DMAbuf_outputintr);
+
/* called with dmap->lock held in irq context */
static void do_inputintr(int dev)
{
@@ -1154,36 +1157,7 @@ void DMAbuf_inputintr(int dev)
do_inputintr(dev);
spin_unlock_irqrestore(&dmap->lock,flags);
}
-
-int DMAbuf_open_dma(int dev)
-{
- /*
- * NOTE! This routine opens only the primary DMA channel (output).
- */
- struct audio_operations *adev = audio_devs[dev];
- int err;
-
- if ((err = open_dmap(adev, OPEN_READWRITE, adev->dmap_out)) < 0)
- return -EBUSY;
- dma_init_buffers(adev->dmap_out);
- adev->dmap_out->flags |= DMA_ALLOC_DONE;
- adev->dmap_out->fragment_size = adev->dmap_out->buffsize;
-
- if (adev->dmap_out->dma >= 0) {
- unsigned long flags;
-
- flags=claim_dma_lock();
- clear_dma_ff(adev->dmap_out->dma);
- disable_dma(adev->dmap_out->dma);
- release_dma_lock(flags);
- }
- return 0;
-}
-
-void DMAbuf_close_dma(int dev)
-{
- close_dmap(audio_devs[dev], audio_devs[dev]->dmap_out);
-}
+EXPORT_SYMBOL(DMAbuf_inputintr);
void DMAbuf_init(int dev, int dma1, int dma2)
{
@@ -1192,12 +1166,6 @@ void DMAbuf_init(int dev, int dma1, int dma2)
* NOTE! This routine could be called several times.
*/
- /* drag in audio_syms.o */
- {
- extern char audio_syms_symbol;
- audio_syms_symbol = 0;
- }
-
if (adev && adev->dmap_out == NULL) {
if (adev->d == NULL)
panic("OSS: audio_devs[%d]->d == NULL\n", dev);
diff --git a/sound/oss/dmasound/dmasound_atari.c b/sound/oss/dmasound/dmasound_atari.c
index dc31373069a5..285239d64b82 100644
--- a/sound/oss/dmasound/dmasound_atari.c
+++ b/sound/oss/dmasound/dmasound_atari.c
@@ -133,7 +133,7 @@ static int FalconSetFormat(int format);
static int FalconSetVolume(int volume);
static void AtaPlayNextFrame(int index);
static void AtaPlay(void);
-static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t AtaInterrupt(int irq, void *dummy);
/*** Mid level stuff *********************************************************/
@@ -1257,7 +1257,7 @@ static void AtaPlay(void)
}
-static irqreturn_t AtaInterrupt(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t AtaInterrupt(int irq, void *dummy)
{
#if 0
/* ++TeSche: if you should want to test this... */
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 9ae659f82430..37773b1deea5 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -281,9 +281,9 @@ static int PMacSetFormat(int format);
static int PMacSetVolume(int volume);
static void PMacPlay(void);
static void PMacRecord(void);
-static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs);
-static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs);
-static irqreturn_t pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs);
+static irqreturn_t pmac_awacs_tx_intr(int irq, void *devid);
+static irqreturn_t pmac_awacs_rx_intr(int irq, void *devid);
+static irqreturn_t pmac_awacs_intr(int irq, void *devid);
static void awacs_write(int val);
static int awacs_get_volume(int reg, int lshift);
static int awacs_volume_setter(int volume, int n, int mute, int lshift);
@@ -398,7 +398,7 @@ read_audio_gpio(int gpio_addr)
* Headphone interrupt via GPIO (Tumbler, Snapper, DACA)
*/
static irqreturn_t
-headphone_intr(int irq, void *devid, struct pt_regs *regs)
+headphone_intr(int irq, void *devid)
{
unsigned long flags;
@@ -465,7 +465,7 @@ tas_dmasound_init(void)
val = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, gpio_headphone_detect, 0);
pmac_call_feature(PMAC_FTR_WRITE_GPIO, NULL, gpio_headphone_detect, val | 0x80);
/* Trigger it */
- headphone_intr(0,NULL,NULL);
+ headphone_intr(0, NULL);
}
}
if (!gpio_headphone_irq) {
@@ -1037,7 +1037,7 @@ static void PMacRecord(void)
*/
static irqreturn_t
-pmac_awacs_tx_intr(int irq, void *devid, struct pt_regs *regs)
+pmac_awacs_tx_intr(int irq, void *devid)
{
int i = write_sq.front;
int stat;
@@ -1129,7 +1129,7 @@ printk("dmasound_pmac: tx-irq: xfer died - patching it up...\n") ;
static irqreturn_t
-pmac_awacs_rx_intr(int irq, void *devid, struct pt_regs *regs)
+pmac_awacs_rx_intr(int irq, void *devid)
{
int stat ;
/* For some reason on my PowerBook G3, I get one interrupt
@@ -1212,7 +1212,7 @@ printk("dmasound_pmac: rx-irq: DIED - attempting resurection\n");
static irqreturn_t
-pmac_awacs_intr(int irq, void *devid, struct pt_regs *regs)
+pmac_awacs_intr(int irq, void *devid)
{
int ctrl;
int status;
@@ -1499,7 +1499,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
write_audio_gpio(gpio_audio_reset, !gpio_audio_reset_pol);
msleep(150);
tas_leave_sleep(); /* Stub for now */
- headphone_intr(0,NULL,NULL);
+ headphone_intr(0, NULL);
break;
case AWACS_DACA:
msleep(10); /* Check this !!! */
diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c
index 68e1d8f6c359..90fc058e1159 100644
--- a/sound/oss/dmasound/dmasound_paula.c
+++ b/sound/oss/dmasound/dmasound_paula.c
@@ -82,7 +82,7 @@ static int AmiSetVolume(int volume);
static int AmiSetTreble(int treble);
static void AmiPlayNextFrame(int index);
static void AmiPlay(void);
-static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t AmiInterrupt(int irq, void *dummy);
#ifdef CONFIG_HEARTBEAT
@@ -556,7 +556,7 @@ static void AmiPlay(void)
}
-static irqreturn_t AmiInterrupt(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t AmiInterrupt(int irq, void *dummy)
{
int minframes = 1;
diff --git a/sound/oss/dmasound/dmasound_q40.c b/sound/oss/dmasound/dmasound_q40.c
index e2081f32b0c4..b3379dd7ca5e 100644
--- a/sound/oss/dmasound/dmasound_q40.c
+++ b/sound/oss/dmasound/dmasound_q40.c
@@ -48,8 +48,8 @@ static int Q40SetFormat(int format);
static int Q40SetVolume(int volume);
static void Q40PlayNextFrame(int index);
static void Q40Play(void);
-static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp);
-static irqreturn_t Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t Q40StereoInterrupt(int irq, void *dummy);
+static irqreturn_t Q40MonoInterrupt(int irq, void *dummy);
static void Q40Interrupt(void);
@@ -451,7 +451,7 @@ static void Q40Play(void)
spin_unlock_irqrestore(&dmasound.lock, flags);
}
-static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t Q40StereoInterrupt(int irq, void *dummy)
{
spin_lock(&dmasound.lock);
if (q40_sc>1){
@@ -463,7 +463,7 @@ static irqreturn_t Q40StereoInterrupt(int irq, void *dummy, struct pt_regs *fp)
spin_unlock(&dmasound.lock);
return IRQ_HANDLED;
}
-static irqreturn_t Q40MonoInterrupt(int irq, void *dummy, struct pt_regs *fp)
+static irqreturn_t Q40MonoInterrupt(int irq, void *dummy)
{
spin_lock(&dmasound.lock);
if (q40_sc>0){
diff --git a/sound/oss/emu10k1/irqmgr.c b/sound/oss/emu10k1/irqmgr.c
index d19b464ba01b..fb2ce638f01c 100644
--- a/sound/oss/emu10k1/irqmgr.c
+++ b/sound/oss/emu10k1/irqmgr.c
@@ -37,7 +37,7 @@
/* Interrupt handler */
-irqreturn_t emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t emu10k1_interrupt(int irq, void *dev_id)
{
struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
u32 irqstatus, irqstatus_tmp;
diff --git a/sound/oss/emu10k1/main.c b/sound/oss/emu10k1/main.c
index c4ce94d6e10c..6c59df7b0001 100644
--- a/sound/oss/emu10k1/main.c
+++ b/sound/oss/emu10k1/main.c
@@ -167,7 +167,7 @@ extern struct file_operations emu10k1_midi_fops;
static struct midi_operations emu10k1_midi_operations;
#endif
-extern irqreturn_t emu10k1_interrupt(int, void *, struct pt_regs *s);
+extern irqreturn_t emu10k1_interrupt(int, void *);
static int __devinit emu10k1_audio_init(struct emu10k1_card *card)
{
diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
deleted file mode 100644
index 13f483149737..000000000000
--- a/sound/oss/es1370.c
+++ /dev/null
@@ -1,2819 +0,0 @@
-/*****************************************************************************/
-
-/*
- * es1370.c -- Ensoniq ES1370/Asahi Kasei AK4531 audio driver.
- *
- * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Special thanks to David C. Niemi
- *
- *
- * Module command line parameters:
- * lineout if 1 the LINE jack is used as an output instead of an input.
- * LINE then contains the unmixed dsp output. This can be used
- * to make the card a four channel one: use dsp to output two
- * channels to LINE and dac to output the other two channels to
- * SPKR. Set the mixer to only output synth to SPKR.
- * micbias sets the +5V bias to the mic if using an electretmic.
- *
- *
- * Note: sync mode is not yet supported (i.e. running dsp and dac from the same
- * clock source)
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/dsp1 additional DAC, like /dev/dsp, but output only,
- * only 5512, 11025, 22050 and 44100 samples/s,
- * outputs to mixer "SYNTH" setting
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * NOTE: the card does not have any FM/Wavetable synthesizer, it is supposed
- * to be done in software. That is what /dev/dac is for. By now (Q2 1998)
- * there are several MIDI to PCM (WAV) packages, one of them is timidity.
- *
- * Revision history
- * 26.03.1998 0.1 Initial release
- * 31.03.1998 0.2 Fix bug in GETOSPACE
- * 04.04.1998 0.3 Make it work (again) under 2.0.33
- * Fix mixer write operation not returning the actual
- * settings
- * 05.04.1998 0.4 First attempt at using the new PCI stuff
- * 29.04.1998 0.5 Fix hang when ^C is pressed on amp
- * 07.05.1998 0.6 Don't double lock around stop_*() in *_release()
- * 10.05.1998 0.7 First stab at a simple midi interface (no bells&whistles)
- * 14.05.1998 0.8 Don't allow excessive interrupt rates
- * 08.06.1998 0.9 First release using Alan Cox' soundcore instead of
- * miscdevice
- * 05.07.1998 0.10 Fixed the driver to correctly maintin OSS style volume
- * settings (not sure if this should be standard)
- * Fixed many references: f_flags should be f_mode
- * -- Gerald Britton <gbritton@mit.edu>
- * 03.08.1998 0.11 Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * Fixed mixer table thanks to Hakan.Lennestal@lu.erisoft.se
- * On module startup, set DAC2 to 11kSPS instead of 5.5kSPS,
- * as it produces an annoying ssssh in the lower sampling rate
- * Do not include modversions.h
- * 22.08.1998 0.12 Mixer registers actually have 5 instead of 4 bits
- * pointed out by Itai Nahshon
- * 31.08.1998 0.13 Fix realplayer problems - dac.count issues
- * 08.10.1998 0.14 Joystick support fixed
- * -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
- * 10.12.1998 0.15 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.1998 0.16 Don't wake up app until there are fragsize bytes to read/write
- * 06.01.1999 0.17 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.1999 0.18 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.1999 0.19 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.1999 0.20 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * Note: joystick address handling might still be wrong on archs
- * other than i386
- * 10.05.1999 0.21 Added support for an electret mic for SB PCI64
- * to the Linux kernel sound driver. This mod also straighten
- * out the question marks around the mic impedance setting
- * (micz). From Kim.Berts@fisub.mail.abb.com
- * 11.05.1999 0.22 Implemented the IMIX call to mute recording monitor.
- * Guenter Geiger <geiger@epy.co.at>
- * 15.06.1999 0.23 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.1999 0.24 Add pci_set_master
- * 02.08.1999 0.25 Added workaround for the "phantom write" bug first
- * documented by Dave Sharpless from Anchor Games
- * 03.08.1999 0.26 adapt to Linus' new __setup/__initcall
- * added kernel command line option "es1370=joystick[,lineout[,micbias]]"
- * removed CONFIG_SOUND_ES1370_JOYPORT_BOOT kludge
- * 12.08.1999 0.27 module_init/__setup fixes
- * 19.08.1999 0.28 SOUND_MIXER_IMIX fixes, reported by Gianluca <gialluca@mail.tiscalinet.it>
- * 31.08.1999 0.29 add spin_lock_init
- * replaced current->state = x with set_current_state(x)
- * 03.09.1999 0.30 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 28.10.1999 0.31 More waitqueue races fixed
- * 08.01.2000 0.32 Prevent some ioctl's from returning bad count values on underrun/overrun;
- * Tim Janik's BSE (Bedevilled Sound Engine) found this
- * 07.02.2000 0.33 Use pci_alloc_consistent and pci_register_driver
- * 21.11.2000 0.34 Initialize dma buffers in poll, otherwise poll may return a bogus mask
- * 12.12.2000 0.35 More dma buffer initializations, patch from
- * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- * 07.01.2001 0.36 Timeout change in wrcodec as requested by Frank Klemm <pfk@fuchs.offl.uni-jena.de>
- * 31.01.2001 0.37 Register/Unregister gameport
- * Fix SETTRIGGER non OSS API conformity
- * 03.01.2003 0.38 open_mode fixes from Georg Acher <acher@in.tum.de>
- *
- * some important things missing in Ensoniq documentation:
- *
- * Experimental PCLKDIV results: play the same waveforms on both DAC1 and DAC2
- * and vary PCLKDIV to obtain zero beat.
- * 5512sps: 254
- * 44100sps: 30
- * seems to be fs = 1411200/(PCLKDIV+2)
- *
- * should find out when curr_sample_ct is cleared and
- * where exactly the CCB fetches data
- *
- * The card uses a 22.5792 MHz crystal.
- * The LINEIN jack may be converted to an AOUT jack by
- * setting pin 47 (XCTL0) of the ES1370 to high.
- * Pin 48 (XCTL1) of the ES1370 sets the +5V bias for an electretmic
- *
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/gameport.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#define DBG(x) {}
-/*#define DBG(x) {x}*/
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_ENSONIQ
-#define PCI_VENDOR_ID_ENSONIQ 0x1274
-#endif
-
-#ifndef PCI_DEVICE_ID_ENSONIQ_ES1370
-#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000
-#endif
-
-#define ES1370_MAGIC ((PCI_VENDOR_ID_ENSONIQ<<16)|PCI_DEVICE_ID_ENSONIQ_ES1370)
-
-#define ES1370_EXTENT 0x40
-#define JOY_EXTENT 8
-
-#define ES1370_REG_CONTROL 0x00
-#define ES1370_REG_STATUS 0x04
-#define ES1370_REG_UART_DATA 0x08
-#define ES1370_REG_UART_STATUS 0x09
-#define ES1370_REG_UART_CONTROL 0x09
-#define ES1370_REG_UART_TEST 0x0a
-#define ES1370_REG_MEMPAGE 0x0c
-#define ES1370_REG_CODEC 0x10
-#define ES1370_REG_SERIAL_CONTROL 0x20
-#define ES1370_REG_DAC1_SCOUNT 0x24
-#define ES1370_REG_DAC2_SCOUNT 0x28
-#define ES1370_REG_ADC_SCOUNT 0x2c
-
-#define ES1370_REG_DAC1_FRAMEADR 0xc30
-#define ES1370_REG_DAC1_FRAMECNT 0xc34
-#define ES1370_REG_DAC2_FRAMEADR 0xc38
-#define ES1370_REG_DAC2_FRAMECNT 0xc3c
-#define ES1370_REG_ADC_FRAMEADR 0xd30
-#define ES1370_REG_ADC_FRAMECNT 0xd34
-#define ES1370_REG_PHANTOM_FRAMEADR 0xd38
-#define ES1370_REG_PHANTOM_FRAMECNT 0xd3c
-
-#define ES1370_FMT_U8_MONO 0
-#define ES1370_FMT_U8_STEREO 1
-#define ES1370_FMT_S16_MONO 2
-#define ES1370_FMT_S16_STEREO 3
-#define ES1370_FMT_STEREO 1
-#define ES1370_FMT_S16 2
-#define ES1370_FMT_MASK 3
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-static const unsigned dac1_samplerate[] = { 5512, 11025, 22050, 44100 };
-
-#define DAC2_SRTODIV(x) (((1411200+(x)/2)/(x))-2)
-#define DAC2_DIVTOSR(x) (1411200/((x)+2))
-
-#define CTRL_ADC_STOP 0x80000000 /* 1 = ADC stopped */
-#define CTRL_XCTL1 0x40000000 /* electret mic bias */
-#define CTRL_OPEN 0x20000000 /* no function, can be read and written */
-#define CTRL_PCLKDIV 0x1fff0000 /* ADC/DAC2 clock divider */
-#define CTRL_SH_PCLKDIV 16
-#define CTRL_MSFMTSEL 0x00008000 /* MPEG serial data fmt: 0 = Sony, 1 = I2S */
-#define CTRL_M_SBB 0x00004000 /* DAC2 clock: 0 = PCLKDIV, 1 = MPEG */
-#define CTRL_WTSRSEL 0x00003000 /* DAC1 clock freq: 0=5512, 1=11025, 2=22050, 3=44100 */
-#define CTRL_SH_WTSRSEL 12
-#define CTRL_DAC_SYNC 0x00000800 /* 1 = DAC2 runs off DAC1 clock */
-#define CTRL_CCB_INTRM 0x00000400 /* 1 = CCB "voice" ints enabled */
-#define CTRL_M_CB 0x00000200 /* recording source: 0 = ADC, 1 = MPEG */
-#define CTRL_XCTL0 0x00000100 /* 0 = Line in, 1 = Line out */
-#define CTRL_BREQ 0x00000080 /* 1 = test mode (internal mem test) */
-#define CTRL_DAC1_EN 0x00000040 /* enable DAC1 */
-#define CTRL_DAC2_EN 0x00000020 /* enable DAC2 */
-#define CTRL_ADC_EN 0x00000010 /* enable ADC */
-#define CTRL_UART_EN 0x00000008 /* enable MIDI uart */
-#define CTRL_JYSTK_EN 0x00000004 /* enable Joystick port (presumably at address 0x200) */
-#define CTRL_CDC_EN 0x00000002 /* enable serial (CODEC) interface */
-#define CTRL_SERR_DIS 0x00000001 /* 1 = disable PCI SERR signal */
-
-#define STAT_INTR 0x80000000 /* wired or of all interrupt bits */
-#define STAT_CSTAT 0x00000400 /* 1 = codec busy or codec write in progress */
-#define STAT_CBUSY 0x00000200 /* 1 = codec busy */
-#define STAT_CWRIP 0x00000100 /* 1 = codec write in progress */
-#define STAT_VC 0x00000060 /* CCB int source, 0=DAC1, 1=DAC2, 2=ADC, 3=undef */
-#define STAT_SH_VC 5
-#define STAT_MCCB 0x00000010 /* CCB int pending */
-#define STAT_UART 0x00000008 /* UART int pending */
-#define STAT_DAC1 0x00000004 /* DAC1 int pending */
-#define STAT_DAC2 0x00000002 /* DAC2 int pending */
-#define STAT_ADC 0x00000001 /* ADC int pending */
-
-#define USTAT_RXINT 0x80 /* UART rx int pending */
-#define USTAT_TXINT 0x04 /* UART tx int pending */
-#define USTAT_TXRDY 0x02 /* UART tx ready */
-#define USTAT_RXRDY 0x01 /* UART rx ready */
-
-#define UCTRL_RXINTEN 0x80 /* 1 = enable RX ints */
-#define UCTRL_TXINTEN 0x60 /* TX int enable field mask */
-#define UCTRL_ENA_TXINT 0x20 /* enable TX int */
-#define UCTRL_CNTRL 0x03 /* control field */
-#define UCTRL_CNTRL_SWR 0x03 /* software reset command */
-
-#define SCTRL_P2ENDINC 0x00380000 /* */
-#define SCTRL_SH_P2ENDINC 19
-#define SCTRL_P2STINC 0x00070000 /* */
-#define SCTRL_SH_P2STINC 16
-#define SCTRL_R1LOOPSEL 0x00008000 /* 0 = loop mode */
-#define SCTRL_P2LOOPSEL 0x00004000 /* 0 = loop mode */
-#define SCTRL_P1LOOPSEL 0x00002000 /* 0 = loop mode */
-#define SCTRL_P2PAUSE 0x00001000 /* 1 = pause mode */
-#define SCTRL_P1PAUSE 0x00000800 /* 1 = pause mode */
-#define SCTRL_R1INTEN 0x00000400 /* enable interrupt */
-#define SCTRL_P2INTEN 0x00000200 /* enable interrupt */
-#define SCTRL_P1INTEN 0x00000100 /* enable interrupt */
-#define SCTRL_P1SCTRLD 0x00000080 /* reload sample count register for DAC1 */
-#define SCTRL_P2DACSEN 0x00000040 /* 1 = DAC2 play back last sample when disabled */
-#define SCTRL_R1SEB 0x00000020 /* 1 = 16bit */
-#define SCTRL_R1SMB 0x00000010 /* 1 = stereo */
-#define SCTRL_R1FMT 0x00000030 /* format mask */
-#define SCTRL_SH_R1FMT 4
-#define SCTRL_P2SEB 0x00000008 /* 1 = 16bit */
-#define SCTRL_P2SMB 0x00000004 /* 1 = stereo */
-#define SCTRL_P2FMT 0x0000000c /* format mask */
-#define SCTRL_SH_P2FMT 2
-#define SCTRL_P1SEB 0x00000002 /* 1 = 16bit */
-#define SCTRL_P1SMB 0x00000001 /* 1 = stereo */
-#define SCTRL_P1FMT 0x00000003 /* format mask */
-#define SCTRL_SH_P1FMT 0
-
-/* misc stuff */
-
-#define FMODE_DAC 4 /* slight misuse of mode_t */
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF 256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-/* --------------------------------------------------------------------- */
-
-struct es1370_state {
- /* magic */
- unsigned int magic;
-
- /* list of es1370 devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
- int dev_mixer;
- int dev_dac;
- int dev_midi;
-
- /* hardware resources */
- unsigned long io; /* long for SPARC */
- unsigned int irq;
-
- /* mixer registers; there is no HW readback */
- struct {
- unsigned short vol[10];
- unsigned int recsrc;
- unsigned int modcnt;
- unsigned short micpreamp;
- unsigned int imix;
- } mix;
-
- /* wave stuff */
- unsigned ctrl;
- unsigned sctrl;
-
- spinlock_t lock;
- struct mutex open_mutex;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned enabled:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac1, dma_dac2, dma_adc;
-
- /* The following buffer is used to point the phantom write channel to. */
- unsigned char *bugbuf_cpu;
- dma_addr_t bugbuf_dma;
-
- /* midi stuff */
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
-#ifdef SUPPORT_JOYSTICK
- struct gameport *gameport;
-#endif
-
- struct mutex mutex;
-};
-
-/* --------------------------------------------------------------------- */
-
-static LIST_HEAD(devs);
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void wrcodec(struct es1370_state *s, unsigned char idx, unsigned char data)
-{
- unsigned long tmo = jiffies + HZ/10, j;
-
- do {
- j = jiffies;
- if (!(inl(s->io+ES1370_REG_STATUS) & STAT_CSTAT)) {
- outw((((unsigned short)idx)<<8)|data, s->io+ES1370_REG_CODEC);
- return;
- }
- schedule();
- } while ((signed)(tmo-j) > 0);
- printk(KERN_ERR "es1370: write to codec register timeout\n");
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct es1370_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_ADC_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac1(struct es1370_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_DAC1_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac2(struct es1370_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl &= ~CTRL_DAC2_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac1(struct es1370_state *s)
-{
- unsigned long flags;
- unsigned fragremain, fshift;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ctrl & CTRL_DAC1_EN) && (s->dma_dac1.mapped || s->dma_dac1.count > 0)
- && s->dma_dac1.ready) {
- s->ctrl |= CTRL_DAC1_EN;
- s->sctrl = (s->sctrl & ~(SCTRL_P1LOOPSEL | SCTRL_P1PAUSE | SCTRL_P1SCTRLD)) | SCTRL_P1INTEN;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- fragremain = ((- s->dma_dac1.hwptr) & (s->dma_dac1.fragsize-1));
- fshift = sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
- if (fragremain < 2*fshift)
- fragremain = s->dma_dac1.fragsize;
- outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl((s->dma_dac1.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC1_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac2(struct es1370_state *s)
-{
- unsigned long flags;
- unsigned fragremain, fshift;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ctrl & CTRL_DAC2_EN) && (s->dma_dac2.mapped || s->dma_dac2.count > 0)
- && s->dma_dac2.ready) {
- s->ctrl |= CTRL_DAC2_EN;
- s->sctrl = (s->sctrl & ~(SCTRL_P2LOOPSEL | SCTRL_P2PAUSE | SCTRL_P2DACSEN |
- SCTRL_P2ENDINC | SCTRL_P2STINC)) | SCTRL_P2INTEN |
- (((s->sctrl & SCTRL_P2FMT) ? 2 : 1) << SCTRL_SH_P2ENDINC) |
- (0 << SCTRL_SH_P2STINC);
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- fragremain = ((- s->dma_dac2.hwptr) & (s->dma_dac2.fragsize-1));
- fshift = sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
- if (fragremain < 2*fshift)
- fragremain = s->dma_dac2.fragsize;
- outl((fragremain >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl((s->dma_dac2.fragsize >> fshift) - 1, s->io+ES1370_REG_DAC2_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct es1370_state *s)
-{
- unsigned long flags;
- unsigned fragremain, fshift;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ctrl & CTRL_ADC_EN) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- s->ctrl |= CTRL_ADC_EN;
- s->sctrl = (s->sctrl & ~SCTRL_R1LOOPSEL) | SCTRL_R1INTEN;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- fragremain = ((- s->dma_adc.hwptr) & (s->dma_adc.fragsize-1));
- fshift = sample_shift[(s->sctrl & SCTRL_R1FMT) >> SCTRL_SH_R1FMT];
- if (fragremain < 2*fshift)
- fragremain = s->dma_adc.fragsize;
- outl((fragremain >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl((s->dma_adc.fragsize >> fshift) - 1, s->io+ES1370_REG_ADC_SCOUNT);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct es1370_state *s, struct dmabuf *db)
-{
- struct page *page, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
- }
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct es1370_state *s, struct dmabuf *db, unsigned rate, unsigned fmt, unsigned reg)
-{
- int order;
- unsigned bytepersec;
- unsigned bufs;
- struct page *page, *pend;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
- break;
- if (!db->rawbuf)
- return -ENOMEM;
- db->buforder = order;
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
- fmt &= ES1370_FMT_MASK;
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
- memset(db->rawbuf, (fmt & ES1370_FMT_S16) ? 0 : 0x80, db->dmasize);
- outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
- outl(db->dmaaddr, s->io+(reg & 0xff));
- outl((db->dmasize >> 2)-1, s->io+((reg + 4) & 0xff));
- db->enabled = 1;
- db->ready = 1;
- return 0;
-}
-
-static inline int prog_dmabuf_adc(struct es1370_state *s)
-{
- stop_adc(s);
- return prog_dmabuf(s, &s->dma_adc, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
- (s->sctrl >> SCTRL_SH_R1FMT) & ES1370_FMT_MASK, ES1370_REG_ADC_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac2(struct es1370_state *s)
-{
- stop_dac2(s);
- return prog_dmabuf(s, &s->dma_dac2, DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV),
- (s->sctrl >> SCTRL_SH_P2FMT) & ES1370_FMT_MASK, ES1370_REG_DAC2_FRAMEADR);
-}
-
-static inline int prog_dmabuf_dac1(struct es1370_state *s)
-{
- stop_dac1(s);
- return prog_dmabuf(s, &s->dma_dac1, dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL],
- (s->sctrl >> SCTRL_SH_P1FMT) & ES1370_FMT_MASK, ES1370_REG_DAC1_FRAMEADR);
-}
-
-static inline unsigned get_hwptr(struct es1370_state *s, struct dmabuf *db, unsigned reg)
-{
- unsigned hwptr, diff;
-
- outl((reg >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
- hwptr = (inl(s->io+(reg & 0xff)) >> 14) & 0x3fffc;
- diff = (db->dmasize + hwptr - db->hwptr) % db->dmasize;
- db->hwptr = hwptr;
- return diff;
-}
-
-static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
-{
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(((char *)buf) + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- memset(((char *)buf) + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void es1370_update_ptr(struct es1370_state *s)
-{
- int diff;
-
- /* update ADC pointer */
- if (s->ctrl & CTRL_ADC_EN) {
- diff = get_hwptr(s, &s->dma_adc, ES1370_REG_ADC_FRAMECNT);
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- if (!s->dma_adc.mapped) {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- s->ctrl &= ~CTRL_ADC_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC1 pointer */
- if (s->ctrl & CTRL_DAC1_EN) {
- diff = get_hwptr(s, &s->dma_dac1, ES1370_REG_DAC1_FRAMECNT);
- s->dma_dac1.total_bytes += diff;
- if (s->dma_dac1.mapped) {
- s->dma_dac1.count += diff;
- if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
- wake_up(&s->dma_dac1.wait);
- } else {
- s->dma_dac1.count -= diff;
- if (s->dma_dac1.count <= 0) {
- s->ctrl &= ~CTRL_DAC1_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- s->dma_dac1.error++;
- } else if (s->dma_dac1.count <= (signed)s->dma_dac1.fragsize && !s->dma_dac1.endcleared) {
- clear_advance(s->dma_dac1.rawbuf, s->dma_dac1.dmasize, s->dma_dac1.swptr,
- s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80);
- s->dma_dac1.endcleared = 1;
- }
- if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize)
- wake_up(&s->dma_dac1.wait);
- }
- }
- /* update DAC2 pointer */
- if (s->ctrl & CTRL_DAC2_EN) {
- diff = get_hwptr(s, &s->dma_dac2, ES1370_REG_DAC2_FRAMECNT);
- s->dma_dac2.total_bytes += diff;
- if (s->dma_dac2.mapped) {
- s->dma_dac2.count += diff;
- if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize)
- wake_up(&s->dma_dac2.wait);
- } else {
- s->dma_dac2.count -= diff;
- if (s->dma_dac2.count <= 0) {
- s->ctrl &= ~CTRL_DAC2_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- s->dma_dac2.error++;
- } else if (s->dma_dac2.count <= (signed)s->dma_dac2.fragsize && !s->dma_dac2.endcleared) {
- clear_advance(s->dma_dac2.rawbuf, s->dma_dac2.dmasize, s->dma_dac2.swptr,
- s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80);
- s->dma_dac2.endcleared = 1;
- }
- if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize)
- wake_up(&s->dma_dac2.wait);
- }
- }
-}
-
-/* hold spinlock for the following! */
-static void es1370_handle_midi(struct es1370_state *s)
-{
- unsigned char ch;
- int wake;
-
- if (!(s->ctrl & CTRL_UART_EN))
- return;
- wake = 0;
- while (inb(s->io+ES1370_REG_UART_STATUS) & USTAT_RXRDY) {
- ch = inb(s->io+ES1370_REG_UART_DATA);
- if (s->midi.icnt < MIDIINBUF) {
- s->midi.ibuf[s->midi.iwr] = ch;
- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
- s->midi.icnt++;
- }
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.iwait);
- wake = 0;
- while ((inb(s->io+ES1370_REG_UART_STATUS) & USTAT_TXRDY) && s->midi.ocnt > 0) {
- outb(s->midi.obuf[s->midi.ord], s->io+ES1370_REG_UART_DATA);
- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
- s->midi.ocnt--;
- if (s->midi.ocnt < MIDIOUTBUF-16)
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.owait);
- outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1370_REG_UART_CONTROL);
-}
-
-static irqreturn_t es1370_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct es1370_state *s = (struct es1370_state *)dev_id;
- unsigned int intsrc, sctl;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inl(s->io+ES1370_REG_STATUS);
- if (!(intsrc & 0x80000000))
- return IRQ_NONE;
- spin_lock(&s->lock);
- /* clear audio interrupts first */
- sctl = s->sctrl;
- if (intsrc & STAT_ADC)
- sctl &= ~SCTRL_R1INTEN;
- if (intsrc & STAT_DAC1)
- sctl &= ~SCTRL_P1INTEN;
- if (intsrc & STAT_DAC2)
- sctl &= ~SCTRL_P2INTEN;
- outl(sctl, s->io+ES1370_REG_SERIAL_CONTROL);
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- es1370_update_ptr(s);
- es1370_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "es1370: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != ES1370_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-static const struct {
- unsigned volidx:4;
- unsigned left:4;
- unsigned right:4;
- unsigned stereo:1;
- unsigned recmask:13;
- unsigned avail:1;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_VOLUME] = { 0, 0x0, 0x1, 1, 0x0000, 1 }, /* master */
- [SOUND_MIXER_PCM] = { 1, 0x2, 0x3, 1, 0x0400, 1 }, /* voice */
- [SOUND_MIXER_SYNTH] = { 2, 0x4, 0x5, 1, 0x0060, 1 }, /* FM */
- [SOUND_MIXER_CD] = { 3, 0x6, 0x7, 1, 0x0006, 1 }, /* CD */
- [SOUND_MIXER_LINE] = { 4, 0x8, 0x9, 1, 0x0018, 1 }, /* Line */
- [SOUND_MIXER_LINE1] = { 5, 0xa, 0xb, 1, 0x1800, 1 }, /* AUX */
- [SOUND_MIXER_LINE2] = { 6, 0xc, 0x0, 0, 0x0100, 1 }, /* Mono1 */
- [SOUND_MIXER_LINE3] = { 7, 0xd, 0x0, 0, 0x0200, 1 }, /* Mono2 */
- [SOUND_MIXER_MIC] = { 8, 0xe, 0x0, 0, 0x0001, 1 }, /* Mic */
- [SOUND_MIXER_OGAIN] = { 9, 0xf, 0x0, 0, 0x0000, 1 } /* mono out */
-};
-
-static void set_recsrc(struct es1370_state *s, unsigned int val)
-{
- unsigned int i, j;
-
- for (j = i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (!mixtable[i].recmask) {
- val &= ~(1 << i);
- continue;
- }
- j |= mixtable[i].recmask;
- }
- s->mix.recsrc = val;
- wrcodec(s, 0x12, j & 0xd5);
- wrcodec(s, 0x13, j & 0xaa);
- wrcodec(s, 0x14, (j >> 8) & 0x17);
- wrcodec(s, 0x15, (j >> 8) & 0x0f);
- i = (j & 0x37f) | ((j << 1) & 0x3000) | 0xc60;
- if (!s->mix.imix) {
- i &= 0xff60; /* mute record and line monitor */
- }
- wrcodec(s, 0x10, i);
- wrcodec(s, 0x11, i >> 8);
-}
-
-static int mixer_ioctl(struct es1370_state *s, unsigned int cmd, unsigned long arg)
-{
- unsigned long flags;
- int i, val;
- unsigned char l, r, rl, rr;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_PRIVATE1) {
- /* enable/disable/query mixer preamp */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- s->mix.micpreamp = !!val;
- wrcodec(s, 0x19, s->mix.micpreamp);
- }
- return put_user(s->mix.micpreamp, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- /* enable/disable/query use of linein as second lineout */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->ctrl |= CTRL_XCTL0;
- else
- s->ctrl &= ~CTRL_XCTL0;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->ctrl & CTRL_XCTL0) ? 1 : 0, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE3) {
- /* enable/disable/query microphone impedance setting */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->ctrl |= CTRL_XCTL1;
- else
- s->ctrl &= ~CTRL_XCTL1;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->ctrl & CTRL_XCTL1) ? 1 : 0, p);
- }
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strncpy(info.id, "ES1370", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strncpy(info.id, "ES1370", sizeof(info.id));
- strncpy(info.name, "Ensoniq ES1370", sizeof(info.name));
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(s->mix.recsrc, p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- val = SOUND_MASK_IMIX;
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].avail)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].recmask)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].stereo)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(0, p);
-
- case SOUND_MIXER_IMIX:
- return put_user(s->mix.imix, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
- return -EINVAL;
- return put_user(s->mix.vol[mixtable[i].volidx], p);
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
-
- case SOUND_MIXER_IMIX:
- if (get_user(s->mix.imix, p))
- return -EFAULT;
- set_recsrc(s, s->mix.recsrc);
- return 0;
-
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- set_recsrc(s, val);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].avail)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- if (mixtable[i].stereo) {
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- if (l < 7) {
- rl = 0x80;
- l = 0;
- } else {
- rl = 31 - ((l - 7) / 3);
- l = (31 - rl) * 3 + 7;
- }
- if (r < 7) {
- rr = 0x80;
- r = 0;
- } else {
- rr = 31 - ((r - 7) / 3);
- r = (31 - rr) * 3 + 7;
- }
- wrcodec(s, mixtable[i].right, rr);
- } else {
- if (mixtable[i].left == 15) {
- if (l < 2) {
- rr = rl = 0x80;
- r = l = 0;
- } else {
- rl = 7 - ((l - 2) / 14);
- r = l = (7 - rl) * 14 + 2;
- }
- } else {
- if (l < 7) {
- rl = 0x80;
- r = l = 0;
- } else {
- rl = 31 - ((l - 7) / 3);
- r = l = (31 - rl) * 3 + 7;
- }
- }
- }
- wrcodec(s, mixtable[i].left, rl);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[mixtable[i].volidx] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[mixtable[i].volidx] = val;
-#endif
- return put_user(s->mix.vol[mixtable[i].volidx], p);
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int es1370_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_state, devs);
- if (s->dev_mixer == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int es1370_release_mixdev(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int es1370_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct es1370_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations es1370_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = es1370_ioctl_mixdev,
- .open = es1370_open_mixdev,
- .release = es1370_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac1(struct es1370_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac1.mapped || !s->dma_dac1.ready)
- return 0;
- add_wait_queue(&s->dma_dac1.wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac1.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac1.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac1.fragsize) / 2
- / dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL];
- tmo >>= sample_shift[(s->sctrl & SCTRL_P1FMT) >> SCTRL_SH_P1FMT];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
- }
- remove_wait_queue(&s->dma_dac1.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static int drain_dac2(struct es1370_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac2.mapped || !s->dma_dac2.ready)
- return 0;
- add_wait_queue(&s->dma_dac2.wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac2.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac2.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac2.fragsize) / 2
- / DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV);
- tmo >>= sample_shift[(s->sctrl & SCTRL_P2FMT) >> SCTRL_SH_P2FMT];
- if (!schedule_timeout(tmo + 1))
- DBG(printk(KERN_DEBUG "es1370: dma timed out??\n");)
- }
- remove_wait_queue(&s->dma_dac2.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret = 0;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- mutex_lock(&s->mutex);
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- goto out;
-
- add_wait_queue(&s->dma_adc.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_adc.enabled)
- start_adc(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&s->mutex);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- mutex_lock(&s->mutex);
- if (s->dma_adc.mapped)
- {
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_adc.enabled)
- start_adc(s);
- }
-out:
- mutex_unlock(&s->mutex);
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t es1370_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret = 0;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac2.mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- mutex_lock(&s->mutex);
- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
- goto out;
- ret = 0;
- add_wait_queue(&s->dma_dac2.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac2.count < 0) {
- s->dma_dac2.count = 0;
- s->dma_dac2.swptr = s->dma_dac2.hwptr;
- }
- swptr = s->dma_dac2.swptr;
- cnt = s->dma_dac2.dmasize-swptr;
- if (s->dma_dac2.count + cnt > s->dma_dac2.dmasize)
- cnt = s->dma_dac2.dmasize - s->dma_dac2.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_dac2.enabled)
- start_dac2(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- goto out;
- }
- mutex_unlock(&s->mutex);
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto out;
- }
- mutex_lock(&s->mutex);
- if (s->dma_dac2.mapped)
- {
- ret = -ENXIO;
- goto out;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac2.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- goto out;
- }
- swptr = (swptr + cnt) % s->dma_dac2.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac2.swptr = swptr;
- s->dma_dac2.count += cnt;
- s->dma_dac2.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac2.enabled)
- start_dac2(s);
- }
-out:
- mutex_unlock(&s->mutex);
- remove_wait_queue(&s->dma_dac2.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1370_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac2.ready && prog_dmabuf_dac2(s))
- return 0;
- poll_wait(file, &s->dma_dac2.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf_adc(s))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac2.mapped) {
- if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int es1370_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- struct dmabuf *db;
- int ret = 0;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- mutex_lock(&s->mutex);
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf_dac2(s)) != 0) {
- goto out;
- }
- db = &s->dma_dac2;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf_adc(s)) != 0) {
- goto out;
- }
- db = &s->dma_adc;
- } else {
- ret = -EINVAL;
- goto out;
- }
- if (vma->vm_pgoff != 0) {
- ret = -EINVAL;
- goto out;
- }
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder)) {
- ret = -EINVAL;
- goto out;
- }
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
- ret = -EAGAIN;
- goto out;
- }
- db->mapped = 1;
-out:
- mutex_unlock(&s->mutex);
- unlock_kernel();
- return ret;
-}
-
-static int es1370_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, mapped, ret;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac2.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- synchronize_irq(s->irq);
- s->dma_dac2.swptr = s->dma_dac2.hwptr = s->dma_dac2.count = s->dma_dac2.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (s->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
- return -EINVAL;
- if (val < 4000)
- val = 4000;
- if (val > 50000)
- val = 50000;
- stop_adc(s);
- stop_dac2(s);
- s->dma_adc.ready = s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(val) << CTRL_SH_PCLKDIV);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->sctrl |= SCTRL_R1SMB;
- else
- s->sctrl &= ~SCTRL_R1SMB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->sctrl |= SCTRL_P2SMB;
- else
- s->sctrl &= ~SCTRL_P2SMB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val >= 2)
- s->sctrl |= SCTRL_R1SMB;
- else
- s->sctrl &= ~SCTRL_R1SMB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val >= 2)
- s->sctrl |= SCTRL_P2SMB;
- else
- s->sctrl &= ~SCTRL_P2SMB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- }
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val == AFMT_S16_LE)
- s->sctrl |= SCTRL_R1SEB;
- else
- s->sctrl &= ~SCTRL_R1SEB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- s->dma_dac2.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val == AFMT_S16_LE)
- s->sctrl |= SCTRL_P2SEB;
- else
- s->sctrl &= ~SCTRL_P2SEB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- }
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ?
- AFMT_S16_LE : AFMT_U8, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN)
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- s->dma_adc.enabled = 1;
- start_adc(s);
- } else {
- s->dma_adc.enabled = 0;
- stop_adc(s);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
- return ret;
- s->dma_dac2.enabled = 1;
- start_dac2(s);
- } else {
- s->dma_dac2.enabled = 0;
- stop_dac2(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- abinfo.fragsize = s->dma_dac2.fragsize;
- count = s->dma_dac2.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac2.dmasize - count;
- abinfo.fragstotal = s->dma_dac2.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac2.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- count = s->dma_adc.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- count = s->dma_dac2.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- return put_user(count, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- count = s->dma_adc.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac2.ready && (val = prog_dmabuf_dac2(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- cinfo.bytes = s->dma_dac2.total_bytes;
- count = s->dma_dac2.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac2.fragshift;
- cinfo.ptr = s->dma_dac2.hwptr;
- if (s->dma_dac2.mapped)
- s->dma_dac2.count &= s->dma_dac2.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf_dac2(s)))
- return val;
- return put_user(s->dma_dac2.fragsize, p);
- }
- if ((val = prog_dmabuf_adc(s)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac2.ossfragshift = val & 0xffff;
- s->dma_dac2.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac2.ossfragshift < 4)
- s->dma_dac2.ossfragshift = 4;
- if (s->dma_dac2.ossfragshift > 15)
- s->dma_dac2.ossfragshift = 15;
- if (s->dma_dac2.ossmaxfrags < 4)
- s->dma_dac2.ossmaxfrags = 4;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac2.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user(DAC2_DIVTOSR((s->ctrl & CTRL_PCLKDIV) >> CTRL_SH_PCLKDIV), p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SMB : SCTRL_P2SMB)) ?
- 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->sctrl & ((file->f_mode & FMODE_READ) ? SCTRL_R1SEB : SCTRL_P2SEB)) ?
- 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int es1370_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_state, devs);
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_READ|FMODE_WRITE)))
- s->ctrl = (s->ctrl & ~CTRL_PCLKDIV) | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV);
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- s->sctrl &= ~SCTRL_R1FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_R1FMT;
- else
- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_R1FMT;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac2.ossfragshift = s->dma_dac2.ossmaxfrags = s->dma_dac2.subdivision = 0;
- s->dma_dac2.enabled = 1;
- s->sctrl &= ~SCTRL_P2FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P2FMT;
- else
- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P2FMT;
- }
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- mutex_init(&s->mutex);
- return nonseekable_open(inode, file);
-}
-
-static int es1370_release(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac2(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac2(s);
- synchronize_irq(s->irq);
- dealloc_dmabuf(s, &s->dma_dac2);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- }
- s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1370_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = es1370_read,
- .write = es1370_write,
- .poll = es1370_poll,
- .ioctl = es1370_ioctl,
- .mmap = es1370_mmap,
- .open = es1370_open,
- .release = es1370_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_write_dac(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret = 0;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac1.mapped)
- return -ENXIO;
- if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- add_wait_queue(&s->dma_dac1.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac1.count < 0) {
- s->dma_dac1.count = 0;
- s->dma_dac1.swptr = s->dma_dac1.hwptr;
- }
- swptr = s->dma_dac1.swptr;
- cnt = s->dma_dac1.dmasize-swptr;
- if (s->dma_dac1.count + cnt > s->dma_dac1.dmasize)
- cnt = s->dma_dac1.dmasize - s->dma_dac1.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_dac1.enabled)
- start_dac1(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac1.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_dac1.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac1.swptr = swptr;
- s->dma_dac1.count += cnt;
- s->dma_dac1.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac1.enabled)
- start_dac1(s);
- }
- remove_wait_queue(&s->dma_dac1.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1370_poll_dac(struct file *file, struct poll_table_struct *wait)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (!s->dma_dac1.ready && prog_dmabuf_dac1(s))
- return 0;
- poll_wait(file, &s->dma_dac1.wait, wait);
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- if (s->dma_dac1.mapped) {
- if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int es1370_mmap_dac(struct file *file, struct vm_area_struct *vma)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- int ret;
- unsigned long size;
-
- VALIDATE_STATE(s);
- if (!(vma->vm_flags & VM_WRITE))
- return -EINVAL;
- lock_kernel();
- if ((ret = prog_dmabuf_dac1(s)) != 0)
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << s->dma_dac1.buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(s->dma_dac1.rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- s->dma_dac1.mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int es1370_ioctl_dac(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- unsigned ctrl;
- int val, ret;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- return drain_dac1(s, 0/*file->f_flags & O_NONBLOCK*/);
-
- case SNDCTL_DSP_SETDUPLEX:
- return -EINVAL;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- stop_dac1(s);
- synchronize_irq(s->irq);
- s->dma_dac1.swptr = s->dma_dac1.hwptr = s->dma_dac1.count = s->dma_dac1.total_bytes = 0;
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- for (ctrl = 0; ctrl <= 2; ctrl++)
- if (val < (dac1_samplerate[ctrl] + dac1_samplerate[ctrl+1]) / 2)
- break;
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (ctrl << CTRL_SH_WTSRSEL);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val)
- s->sctrl |= SCTRL_P1SMB;
- else
- s->sctrl &= ~SCTRL_P1SMB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- if (s->dma_dac1.mapped)
- return -EINVAL;
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val >= 2)
- s->sctrl |= SCTRL_P1SMB;
- else
- s->sctrl &= ~SCTRL_P1SMB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- stop_dac1(s);
- s->dma_dac1.ready = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (val == AFMT_S16_LE)
- s->sctrl |= SCTRL_P1SEB;
- else
- s->sctrl &= ~SCTRL_P1SEB;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- return put_user((s->sctrl & SCTRL_P1SEB) ? AFMT_S16_LE : AFMT_U8, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- return put_user((s->ctrl & CTRL_DAC1_EN) ? PCM_ENABLE_OUTPUT : 0, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac1.ready && (ret = prog_dmabuf_dac1(s)))
- return ret;
- s->dma_dac1.enabled = 1;
- start_dac1(s);
- } else {
- s->dma_dac1.enabled = 0;
- stop_dac1(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- abinfo.fragsize = s->dma_dac1.fragsize;
- count = s->dma_dac1.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac1.dmasize - count;
- abinfo.fragstotal = s->dma_dac1.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac1.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user((void __user *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- count = s->dma_dac1.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- return put_user(count, p);
-
- case SNDCTL_DSP_GETOPTR:
- if (!s->dma_dac1.ready && (val = prog_dmabuf_dac1(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- es1370_update_ptr(s);
- cinfo.bytes = s->dma_dac1.total_bytes;
- count = s->dma_dac1.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac1.fragshift;
- cinfo.ptr = s->dma_dac1.hwptr;
- if (s->dma_dac1.mapped)
- s->dma_dac1.count &= s->dma_dac1.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user((void __user *)arg, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if ((val = prog_dmabuf_dac1(s)))
- return val;
- return put_user(s->dma_dac1.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- s->dma_dac1.ossfragshift = val & 0xffff;
- s->dma_dac1.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac1.ossfragshift < 4)
- s->dma_dac1.ossfragshift = 4;
- if (s->dma_dac1.ossfragshift > 15)
- s->dma_dac1.ossfragshift = 15;
- if (s->dma_dac1.ossmaxfrags < 4)
- s->dma_dac1.ossmaxfrags = 4;
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if (s->dma_dac1.subdivision)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- s->dma_dac1.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user(dac1_samplerate[(s->ctrl & CTRL_WTSRSEL) >> CTRL_SH_WTSRSEL], p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->sctrl & SCTRL_P1SMB) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->sctrl & SCTRL_P1SEB) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int es1370_open_dac(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_state, devs);
- if (!((s->dev_dac ^ minor) & ~0xf))
- break;
- }
- VALIDATE_STATE(s);
- /* we allow opening with O_RDWR, most programs do it although they will only write */
-#if 0
- if (file->f_mode & FMODE_READ)
- return -EPERM;
-#endif
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & FMODE_DAC) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- s->dma_dac1.ossfragshift = s->dma_dac1.ossmaxfrags = s->dma_dac1.subdivision = 0;
- s->dma_dac1.enabled = 1;
- spin_lock_irqsave(&s->lock, flags);
- s->ctrl = (s->ctrl & ~CTRL_WTSRSEL) | (1 << CTRL_SH_WTSRSEL);
- s->sctrl &= ~SCTRL_P1FMT;
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->sctrl |= ES1370_FMT_S16_MONO << SCTRL_SH_P1FMT;
- else
- s->sctrl |= ES1370_FMT_U8_MONO << SCTRL_SH_P1FMT;
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= FMODE_DAC;
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int es1370_release_dac(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- drain_dac1(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- stop_dac1(s);
- dealloc_dmabuf(s, &s->dma_dac1);
- s->open_mode &= ~FMODE_DAC;
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1370_dac_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .write = es1370_write_dac,
- .poll = es1370_poll_dac,
- .ioctl = es1370_ioctl_dac,
- .mmap = es1370_mmap_dac,
- .open = es1370_open_dac,
- .release = es1370_release_dac,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t es1370_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.iwait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.ird;
- cnt = MIDIINBUF - ptr;
- if (s->midi.icnt < cnt)
- cnt = s->midi.icnt;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIINBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.ird = ptr;
- s->midi.icnt -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.iwait, &wait);
- return ret;
-}
-
-static ssize_t es1370_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.owait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.owr;
- cnt = MIDIOUTBUF - ptr;
- if (s->midi.ocnt + cnt > MIDIOUTBUF)
- cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0) {
- __set_current_state(TASK_INTERRUPTIBLE);
- es1370_handle_midi(s);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIOUTBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.owr = ptr;
- s->midi.ocnt += cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_lock_irqsave(&s->lock, flags);
- es1370_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.owait, &wait);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int es1370_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &s->midi.owait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &s->midi.iwait, wait);
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ) {
- if (s->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->midi.ocnt < MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int es1370_midi_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct es1370_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct es1370_state, devs);
- if (s->dev_midi == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- outb(UCTRL_CNTRL_SWR, s->io+ES1370_REG_UART_CONTROL);
- outb(0, s->io+ES1370_REG_UART_CONTROL);
- outb(0, s->io+ES1370_REG_UART_TEST);
- }
- if (file->f_mode & FMODE_READ) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- }
- s->ctrl |= CTRL_UART_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- es1370_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int es1370_midi_release(struct inode *inode, struct file *file)
-{
- struct es1370_state *s = (struct es1370_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- unsigned count, tmo;
-
- VALIDATE_STATE(s);
-
- lock_kernel();
- if (file->f_mode & FMODE_WRITE) {
- add_wait_queue(&s->midi.owait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->midi.ocnt;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (file->f_flags & O_NONBLOCK)
- break;
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- DBG(printk(KERN_DEBUG "es1370: midi timed out??\n");)
- }
- remove_wait_queue(&s->midi.owait, &wait);
- set_current_state(TASK_RUNNING);
- }
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- s->ctrl &= ~CTRL_UART_EN;
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations es1370_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = es1370_midi_read,
- .write = es1370_midi_write,
- .poll = es1370_midi_poll,
- .open = es1370_midi_open,
- .release = es1370_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int lineout[NR_DEVICE];
-static int micbias[NR_DEVICE];
-
-static unsigned int devindex;
-
-module_param_array(lineout, bool, NULL, 0);
-MODULE_PARM_DESC(lineout, "if 1 the LINE input is converted to LINE out");
-module_param_array(micbias, bool, NULL, 0);
-MODULE_PARM_DESC(micbias, "sets the +5V bias for an electret microphone");
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("ES1370 AudioPCI Driver");
-MODULE_LICENSE("GPL");
-
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
- { SOUND_MIXER_WRITE_LINE3, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 },
- { SOUND_MIXER_WRITE_OGAIN, 0x4040 }
-};
-
-#ifdef SUPPORT_JOYSTICK
-
-static int __devinit es1370_register_gameport(struct es1370_state *s)
-{
- struct gameport *gp;
-
- if (!request_region(0x200, JOY_EXTENT, "es1370")) {
- printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
- return -EBUSY;
- }
-
- s->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
- release_region(0x200, JOY_EXTENT);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "ESS1370");
- gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
- gp->dev.parent = &s->dev->dev;
- gp->io = 0x200;
-
- s->ctrl |= CTRL_JYSTK_EN;
- outl(s->ctrl, s->io + ES1370_REG_CONTROL);
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void es1370_unregister_gameport(struct es1370_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, JOY_EXTENT);
-
- }
-}
-
-#else
-static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; }
-static inline void es1370_unregister_gameport(struct es1370_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- struct es1370_state *s;
- mm_segment_t fs;
- int i, val, ret;
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
-
- if ( !(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
- !pci_resource_start(pcidev, 0)
- )
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
- i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
- if (i) {
- printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
- return i;
- }
- if (!(s = kmalloc(sizeof(struct es1370_state), GFP_KERNEL))) {
- printk(KERN_WARNING "es1370: out of memory\n");
- return -ENOMEM;
- }
- memset(s, 0, sizeof(struct es1370_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac1.wait);
- init_waitqueue_head(&s->dma_dac2.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
- s->magic = ES1370_MAGIC;
- s->dev = pcidev;
- s->io = pci_resource_start(pcidev, 0);
- s->irq = pcidev->irq;
- if (!request_region(s->io, ES1370_EXTENT, "es1370")) {
- printk(KERN_ERR "es1370: io ports %#lx-%#lx in use\n", s->io, s->io+ES1370_EXTENT-1);
- ret = -EBUSY;
- goto err_region;
- }
- if ((ret=request_irq(s->irq, es1370_interrupt, IRQF_SHARED, "es1370",s))) {
- printk(KERN_ERR "es1370: irq %u in use\n", s->irq);
- goto err_irq;
- }
-
- /* initialize codec registers */
- /* note: setting CTRL_SERR_DIS is reported to break
- * mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
- s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
- if (lineout[devindex])
- s->ctrl |= CTRL_XCTL0;
- if (micbias[devindex])
- s->ctrl |= CTRL_XCTL1;
- s->sctrl = 0;
- printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n",
- s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in",
- (s->ctrl & CTRL_XCTL1) ? "1" : "0");
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&es1370_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- if ((s->dev_dac = register_sound_dsp(&es1370_dac_fops, -1)) < 0) {
- ret = s->dev_dac;
- goto err_dev3;
- }
- if ((s->dev_midi = register_sound_midi(&es1370_midi_fops, -1)) < 0) {
- ret = s->dev_midi;
- goto err_dev4;
- }
- /* initialize the chips */
- outl(s->ctrl, s->io+ES1370_REG_CONTROL);
- outl(s->sctrl, s->io+ES1370_REG_SERIAL_CONTROL);
- /* point phantom write channel to "bugbuf" */
- s->bugbuf_cpu = pci_alloc_consistent(pcidev,16,&s->bugbuf_dma);
- if (!s->bugbuf_cpu) {
- ret = -ENOMEM;
- goto err_dev5;
- }
- outl((ES1370_REG_PHANTOM_FRAMEADR >> 8) & 15, s->io+ES1370_REG_MEMPAGE);
- outl(s->bugbuf_dma, s->io+(ES1370_REG_PHANTOM_FRAMEADR & 0xff));
- outl(0, s->io+(ES1370_REG_PHANTOM_FRAMECNT & 0xff));
- pci_set_master(pcidev); /* enable bus mastering */
- wrcodec(s, 0x16, 3); /* no RST, PD */
- wrcodec(s, 0x17, 0); /* CODEC ADC and CODEC DAC use {LR,B}CLK2 and run off the LRCLK2 PLL; program DAC_SYNC=0!! */
- wrcodec(s, 0x18, 0); /* recording source is mixer */
- wrcodec(s, 0x19, s->mix.micpreamp = 1); /* turn on MIC preamp */
- s->mix.imix = 1;
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH|SOUND_MASK_CD;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- set_fs(fs);
-
- es1370_register_gameport(s);
-
- /* store it in the driver field */
- pci_set_drvdata(pcidev, s);
- /* put it into driver list */
- list_add_tail(&s->devs, &devs);
- /* increment devindex */
- if (devindex < NR_DEVICE-1)
- devindex++;
- return 0;
-
- err_dev5:
- unregister_sound_midi(s->dev_midi);
- err_dev4:
- unregister_sound_dsp(s->dev_dac);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "es1370: cannot register misc device\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->io, ES1370_EXTENT);
- err_region:
- kfree(s);
- return ret;
-}
-
-static void __devexit es1370_remove(struct pci_dev *dev)
-{
- struct es1370_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- list_del(&s->devs);
- outl(CTRL_SERR_DIS | (1 << CTRL_SH_WTSRSEL), s->io+ES1370_REG_CONTROL); /* switch everything off */
- outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
- synchronize_irq(s->irq);
- free_irq(s->irq, s);
- es1370_unregister_gameport(s);
- release_region(s->io, ES1370_EXTENT);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_dsp(s->dev_dac);
- unregister_sound_midi(s->dev_midi);
- pci_free_consistent(dev, 16, s->bugbuf_cpu, s->bugbuf_dma);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver es1370_driver = {
- .name = "es1370",
- .id_table = id_table,
- .probe = es1370_probe,
- .remove = __devexit_p(es1370_remove),
-};
-
-static int __init init_es1370(void)
-{
- printk(KERN_INFO "es1370: version v0.38 time " __TIME__ " " __DATE__ "\n");
- return pci_register_driver(&es1370_driver);
-}
-
-static void __exit cleanup_es1370(void)
-{
- printk(KERN_INFO "es1370: unloading\n");
- pci_unregister_driver(&es1370_driver);
-}
-
-module_init(init_es1370);
-module_exit(cleanup_es1370);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: es1370=lineout[,micbias]] */
-
-static int __init es1370_setup(char *str)
-{
- static unsigned __initdata nr_dev = 0;
-
- if (nr_dev >= NR_DEVICE)
- return 0;
-
- (void)
- ((get_option(&str,&lineout [nr_dev]) == 2)
- && get_option(&str,&micbias [nr_dev])
- );
-
- nr_dev++;
- return 1;
-}
-
-__setup("es1370=", es1370_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
index a2ffe723dad5..ddf6b0a0bca5 100644
--- a/sound/oss/es1371.c
+++ b/sound/oss/es1371.c
@@ -1100,9 +1100,9 @@ static void es1371_handle_midi(struct es1371_state *s)
outb((s->midi.ocnt > 0) ? UCTRL_RXINTEN | UCTRL_ENA_TXINT : UCTRL_RXINTEN, s->io+ES1371_REG_UART_CONTROL);
}
-static irqreturn_t es1371_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t es1371_interrupt(int irq, void *dev_id)
{
- struct es1371_state *s = (struct es1371_state *)dev_id;
+ struct es1371_state *s = dev_id;
unsigned int intsrc, sctl;
/* fastpath out, to ease interrupt sharing */
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
deleted file mode 100644
index 82f40a0a5c9c..000000000000
--- a/sound/oss/esssolo1.c
+++ /dev/null
@@ -1,2516 +0,0 @@
-/****************************************************************************/
-
-/*
- * esssolo1.c -- ESS Technology Solo1 (ES1946) audio driver.
- *
- * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Module command line parameters:
- * none so far
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * Revision history
- * 10.11.1998 0.1 Initial release (without any hardware)
- * 22.03.1999 0.2 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 07.04.1999 0.3 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * 15.06.1999 0.4 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.1999 0.5 Add pci_set_master
- * 12.08.1999 0.6 Fix MIDI UART crashing the driver
- * Changed mixer semantics from OSS documented
- * behaviour to OSS "code behaviour".
- * Recording might actually work now.
- * The real DDMA controller address register is at PCI config
- * 0x60, while the register at 0x18 is used as a placeholder
- * register for BIOS address allocation. This register
- * is supposed to be copied into 0x60, according
- * to the Solo1 datasheet. When I do that, I can access
- * the DDMA registers except the mask bit, which
- * is stuck at 1. When I copy the contents of 0x18 +0x10
- * to the DDMA base register, everything seems to work.
- * The fun part is that the Windows Solo1 driver doesn't
- * seem to do these tricks.
- * Bugs remaining: plops and clicks when starting/stopping playback
- * 31.08.1999 0.7 add spin_lock_init
- * replaced current->state = x with set_current_state(x)
- * 03.09.1999 0.8 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 07.10.1999 0.9 Fix initialization; complain if sequencer writes time out
- * Revised resource grabbing for the FM synthesizer
- * 28.10.1999 0.10 More waitqueue races fixed
- * 09.12.1999 0.11 Work around stupid Alpha port issue (virt_to_bus(kmalloc(GFP_DMA)) > 16M)
- * Disabling recording on Alpha
- * 12.01.2000 0.12 Prevent some ioctl's from returning bad count values on underrun/overrun;
- * Tim Janik's BSE (Bedevilled Sound Engine) found this
- * Integrated (aka redid 8-)) APM support patch by Zach Brown
- * 07.02.2000 0.13 Use pci_alloc_consistent and pci_register_driver
- * 19.02.2000 0.14 Use pci_dma_supported to determine if recording should be disabled
- * 13.03.2000 0.15 Reintroduce initialization of a couple of PCI config space registers
- * 21.11.2000 0.16 Initialize dma buffers in poll, otherwise poll may return a bogus mask
- * 12.12.2000 0.17 More dma buffer initializations, patch from
- * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- * 31.01.2001 0.18 Register/Unregister gameport, original patch from
- * Nathaniel Daw <daw@cs.cmu.edu>
- * Fix SETTRIGGER non OSS API conformity
- * 10.03.2001 provide abs function, prevent picking up a bogus kernel macro
- * for abs. Bug report by Andrew Morton <andrewm@uow.edu.au>
- * 15.05.2001 pci_enable_device moved, return values in probe cleaned
- * up. Marcus Meissner <mm@caldera.de>
- * 22.05.2001 0.19 more cleanups, changed PM to PCI 2.4 style, got rid
- * of global list of devices, using pci device data.
- * Marcus Meissner <mm@caldera.de>
- * 03.01.2003 0.20 open_mode fixes from Georg Acher <acher@in.tum.de>
- */
-
-/*****************************************************************************/
-
-#include <linux/interrupt.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/gameport.h>
-#include <linux/wait.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "dm.h"
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_ESS
-#define PCI_VENDOR_ID_ESS 0x125d
-#endif
-#ifndef PCI_DEVICE_ID_ESS_SOLO1
-#define PCI_DEVICE_ID_ESS_SOLO1 0x1969
-#endif
-
-#define SOLO1_MAGIC ((PCI_VENDOR_ID_ESS<<16)|PCI_DEVICE_ID_ESS_SOLO1)
-
-#define DDMABASE_OFFSET 0 /* chip bug workaround kludge */
-#define DDMABASE_EXTENT 16
-
-#define IOBASE_EXTENT 16
-#define SBBASE_EXTENT 16
-#define VCBASE_EXTENT (DDMABASE_EXTENT+DDMABASE_OFFSET)
-#define MPUBASE_EXTENT 4
-#define GPBASE_EXTENT 4
-#define GAMEPORT_EXTENT 4
-
-#define FMSYNTH_EXTENT 4
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF 256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 3
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define FMODE_DMFM 0x10
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-static struct pci_driver solo1_driver;
-
-/* --------------------------------------------------------------------- */
-
-struct solo1_state {
- /* magic */
- unsigned int magic;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
- int dev_mixer;
- int dev_midi;
- int dev_dmfm;
-
- /* hardware resources */
- unsigned long iobase, sbbase, vcbase, ddmabase, mpubase; /* long for SPARC */
- unsigned int irq;
-
- /* mixer registers */
- struct {
- unsigned short vol[10];
- unsigned int recsrc;
- unsigned int modcnt;
- unsigned short micpreamp;
- } mix;
-
- /* wave stuff */
- unsigned fmt;
- unsigned channels;
- unsigned rate;
- unsigned char clkdiv;
- unsigned ena;
-
- spinlock_t lock;
- struct mutex open_mutex;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned enabled:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-
- /* midi stuff */
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- struct timer_list timer;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
-#if SUPPORT_JOYSTICK
- struct gameport *gameport;
-#endif
-};
-
-/* --------------------------------------------------------------------- */
-
-static inline void write_seq(struct solo1_state *s, unsigned char data)
-{
- int i;
- unsigned long flags;
-
- /* the local_irq_save stunt is to send the data within the command window */
- for (i = 0; i < 0xffff; i++) {
- local_irq_save(flags);
- if (!(inb(s->sbbase+0xc) & 0x80)) {
- outb(data, s->sbbase+0xc);
- local_irq_restore(flags);
- return;
- }
- local_irq_restore(flags);
- }
- printk(KERN_ERR "esssolo1: write_seq timeout\n");
- outb(data, s->sbbase+0xc);
-}
-
-static inline int read_seq(struct solo1_state *s, unsigned char *data)
-{
- int i;
-
- if (!data)
- return 0;
- for (i = 0; i < 0xffff; i++)
- if (inb(s->sbbase+0xe) & 0x80) {
- *data = inb(s->sbbase+0xa);
- return 1;
- }
- printk(KERN_ERR "esssolo1: read_seq timeout\n");
- return 0;
-}
-
-static inline int reset_ctrl(struct solo1_state *s)
-{
- int i;
-
- outb(3, s->sbbase+6); /* clear sequencer and FIFO */
- udelay(10);
- outb(0, s->sbbase+6);
- for (i = 0; i < 0xffff; i++)
- if (inb(s->sbbase+0xe) & 0x80)
- if (inb(s->sbbase+0xa) == 0xaa) {
- write_seq(s, 0xc6); /* enter enhanced mode */
- return 1;
- }
- return 0;
-}
-
-static void write_ctrl(struct solo1_state *s, unsigned char reg, unsigned char data)
-{
- write_seq(s, reg);
- write_seq(s, data);
-}
-
-#if 0 /* unused */
-static unsigned char read_ctrl(struct solo1_state *s, unsigned char reg)
-{
- unsigned char r;
-
- write_seq(s, 0xc0);
- write_seq(s, reg);
- read_seq(s, &r);
- return r;
-}
-#endif /* unused */
-
-static void write_mixer(struct solo1_state *s, unsigned char reg, unsigned char data)
-{
- outb(reg, s->sbbase+4);
- outb(data, s->sbbase+5);
-}
-
-static unsigned char read_mixer(struct solo1_state *s, unsigned char reg)
-{
- outb(reg, s->sbbase+4);
- return inb(s->sbbase+5);
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_dac(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_WRITE;
- write_mixer(s, 0x78, 0x10);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ena & FMODE_WRITE) && (s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
- s->ena |= FMODE_WRITE;
- write_mixer(s, 0x78, 0x12);
- udelay(10);
- write_mixer(s, 0x78, 0x13);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_adc(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->ena &= ~FMODE_READ;
- write_ctrl(s, 0xb8, 0xe);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct solo1_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->ena & FMODE_READ) && (s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- s->ena |= FMODE_READ;
- write_ctrl(s, 0xb8, 0xf);
-#if 0
- printk(KERN_DEBUG "solo1: DMAbuffer: 0x%08lx\n", (long)s->dma_adc.rawbuf);
- printk(KERN_DEBUG "solo1: DMA: mask: 0x%02x cnt: 0x%04x addr: 0x%08x stat: 0x%02x\n",
- inb(s->ddmabase+0xf), inw(s->ddmabase+4), inl(s->ddmabase), inb(s->ddmabase+8));
-#endif
- outb(0, s->ddmabase+0xd); /* master reset */
- outb(1, s->ddmabase+0xf); /* mask */
- outb(0x54/*0x14*/, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
- outl(virt_to_bus(s->dma_adc.rawbuf), s->ddmabase);
- outw(s->dma_adc.dmasize-1, s->ddmabase+4);
- outb(0, s->ddmabase+0xf);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-#if 0
- printk(KERN_DEBUG "solo1: start DMA: reg B8: 0x%02x SBstat: 0x%02x\n"
- KERN_DEBUG "solo1: DMA: stat: 0x%02x cnt: 0x%04x mask: 0x%02x\n",
- read_ctrl(s, 0xb8), inb(s->sbbase+0xc),
- inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->ddmabase+0xf));
- printk(KERN_DEBUG "solo1: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
- KERN_DEBUG "solo1: B1: 0x%02x B2: 0x%02x B4: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n",
- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb4), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8),
- read_ctrl(s, 0xb9));
-#endif
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct solo1_state *s, struct dmabuf *db)
-{
- struct page *page, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
- }
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct solo1_state *s, struct dmabuf *db)
-{
- int order;
- unsigned bytespersec;
- unsigned bufs, sample_shift = 0;
- struct page *page, *pend;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
- break;
- if (!db->rawbuf)
- return -ENOMEM;
- db->buforder = order;
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- sample_shift++;
- if (s->channels > 1)
- sample_shift++;
- bytespersec = s->rate << sample_shift;
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytespersec)
- db->fragshift = ld2(bytespersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytespersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift;
- db->dmasize = db->numfrag << db->fragshift;
- db->enabled = 1;
- return 0;
-}
-
-static inline int prog_dmabuf_adc(struct solo1_state *s)
-{
- unsigned long va;
- int c;
-
- stop_adc(s);
- /* check if PCI implementation supports 24bit busmaster DMA */
- if (s->dev->dma_mask > 0xffffff)
- return -EIO;
- if ((c = prog_dmabuf(s, &s->dma_adc)))
- return c;
- va = s->dma_adc.dmaaddr;
- if ((va & ~((1<<24)-1)))
- panic("solo1: buffer above 16M boundary");
- outb(0, s->ddmabase+0xd); /* clear */
- outb(1, s->ddmabase+0xf); /* mask */
- /*outb(0, s->ddmabase+8);*/ /* enable (enable is active low!) */
- outb(0x54, s->ddmabase+0xb); /* DMA_MODE_READ | DMA_MODE_AUTOINIT */
- outl(va, s->ddmabase);
- outw(s->dma_adc.dmasize-1, s->ddmabase+4);
- c = - s->dma_adc.fragsamples;
- write_ctrl(s, 0xa4, c);
- write_ctrl(s, 0xa5, c >> 8);
- outb(0, s->ddmabase+0xf);
- s->dma_adc.ready = 1;
- return 0;
-}
-
-static int prog_dmabuf_dac(struct solo1_state *s)
-{
- unsigned long va;
- int c;
-
- stop_dac(s);
- if ((c = prog_dmabuf(s, &s->dma_dac)))
- return c;
- memset(s->dma_dac.rawbuf, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80, s->dma_dac.dmasize); /* almost correct for U16 */
- va = s->dma_dac.dmaaddr;
- if ((va ^ (va + s->dma_dac.dmasize - 1)) & ~((1<<20)-1))
- panic("solo1: buffer crosses 1M boundary");
- outl(va, s->iobase);
- /* warning: s->dma_dac.dmasize & 0xffff must not be zero! i.e. this limits us to a 32k buffer */
- outw(s->dma_dac.dmasize, s->iobase+4);
- c = - s->dma_dac.fragsamples;
- write_mixer(s, 0x74, c);
- write_mixer(s, 0x76, c >> 8);
- outb(0xa, s->iobase+6);
- s->dma_dac.ready = 1;
- return 0;
-}
-
-static inline void clear_advance(void *buf, unsigned bsize, unsigned bptr, unsigned len, unsigned char c)
-{
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(((char *)buf) + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- memset(((char *)buf) + bptr, c, len);
-}
-
-/* call with spinlock held! */
-
-static void solo1_update_ptr(struct solo1_state *s)
-{
- int diff;
- unsigned hwptr;
-
- /* update ADC pointer */
- if (s->ena & FMODE_READ) {
- hwptr = (s->dma_adc.dmasize - 1 - inw(s->ddmabase+4)) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
-#if 0
- printk(KERN_DEBUG "solo1: rd: hwptr %u swptr %u dmasize %u count %u\n",
- s->dma_adc.hwptr, s->dma_adc.swptr, s->dma_adc.dmasize, s->dma_adc.count);
-#endif
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- } else {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- s->ena &= ~FMODE_READ;
- write_ctrl(s, 0xb8, 0xe);
- s->dma_adc.error++;
- }
- if (s->dma_adc.count > 0)
- wake_up(&s->dma_adc.wait);
- }
- }
- /* update DAC pointer */
- if (s->ena & FMODE_WRITE) {
- hwptr = (s->dma_dac.dmasize - inw(s->iobase+4)) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
-#if 0
- printk(KERN_DEBUG "solo1: wr: hwptr %u swptr %u dmasize %u count %u\n",
- s->dma_dac.hwptr, s->dma_dac.swptr, s->dma_dac.dmasize, s->dma_dac.count);
-#endif
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- wake_up(&s->dma_dac.wait);
- } else {
- s->dma_dac.count -= diff;
- if (s->dma_dac.count <= 0) {
- s->ena &= ~FMODE_WRITE;
- write_mixer(s, 0x78, 0x12);
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s->dma_dac.rawbuf, s->dma_dac.dmasize, s->dma_dac.swptr,
- s->dma_dac.fragsize, (s->fmt & (AFMT_U8 | AFMT_U16_LE)) ? 0 : 0x80);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
- wake_up(&s->dma_dac.wait);
- }
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static void prog_codec(struct solo1_state *s)
-{
- unsigned long flags;
- int fdiv, filter;
- unsigned char c;
-
- reset_ctrl(s);
- write_seq(s, 0xd3);
- /* program sampling rates */
- filter = s->rate * 9 / 20; /* Set filter roll-off to 90% of rate/2 */
- fdiv = 256 - 7160000 / (filter * 82);
- spin_lock_irqsave(&s->lock, flags);
- write_ctrl(s, 0xa1, s->clkdiv);
- write_ctrl(s, 0xa2, fdiv);
- write_mixer(s, 0x70, s->clkdiv);
- write_mixer(s, 0x72, fdiv);
- /* program ADC parameters */
- write_ctrl(s, 0xb8, 0xe);
- write_ctrl(s, 0xb9, /*0x1*/0);
- write_ctrl(s, 0xa8, (s->channels > 1) ? 0x11 : 0x12);
- c = 0xd0;
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- c |= 0x04;
- if (s->fmt & (AFMT_S16_LE | AFMT_S8))
- c |= 0x20;
- if (s->channels > 1)
- c ^= 0x48;
- write_ctrl(s, 0xb7, (c & 0x70) | 1);
- write_ctrl(s, 0xb7, c);
- write_ctrl(s, 0xb1, 0x50);
- write_ctrl(s, 0xb2, 0x50);
- /* program DAC parameters */
- c = 0x40;
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- c |= 1;
- if (s->fmt & (AFMT_S16_LE | AFMT_S8))
- c |= 4;
- if (s->channels > 1)
- c |= 2;
- write_mixer(s, 0x7a, c);
- write_mixer(s, 0x78, 0x10);
- s->ena = 0;
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "solo1: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != SOLO1_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-static int mixer_ioctl(struct solo1_state *s, unsigned int cmd, unsigned long arg)
-{
- static const unsigned int mixer_src[8] = {
- SOUND_MASK_MIC, SOUND_MASK_MIC, SOUND_MASK_CD, SOUND_MASK_VOLUME,
- SOUND_MASK_MIC, 0, SOUND_MASK_LINE, 0
- };
- static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_PCM] = 1, /* voice */
- [SOUND_MIXER_SYNTH] = 2, /* FM */
- [SOUND_MIXER_CD] = 3, /* CD */
- [SOUND_MIXER_LINE] = 4, /* Line */
- [SOUND_MIXER_LINE1] = 5, /* AUX */
- [SOUND_MIXER_MIC] = 6, /* Mic */
- [SOUND_MIXER_LINE2] = 7, /* Mono in */
- [SOUND_MIXER_SPEAKER] = 8, /* Speaker */
- [SOUND_MIXER_RECLEV] = 9, /* Recording level */
- [SOUND_MIXER_VOLUME] = 10 /* Master Volume */
- };
- static const unsigned char mixreg[] = {
- 0x7c, /* voice */
- 0x36, /* FM */
- 0x38, /* CD */
- 0x3e, /* Line */
- 0x3a, /* AUX */
- 0x1a, /* Mic */
- 0x6d /* Mono in */
- };
- unsigned char l, r, rl, rr, vidx;
- int i, val;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
-
- if (cmd == SOUND_MIXER_PRIVATE1) {
- /* enable/disable/query mixer preamp */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- val = val ? 0xff : 0xf7;
- write_mixer(s, 0x7d, (read_mixer(s, 0x7d) | 0x08) & val);
- }
- val = (read_mixer(s, 0x7d) & 0x08) ? 1 : 0;
- return put_user(val, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- /* enable/disable/query spatializer */
- if (get_user(val, p))
- return -EFAULT;
- if (val != -1) {
- val &= 0x3f;
- write_mixer(s, 0x52, val);
- write_mixer(s, 0x50, val ? 0x08 : 0);
- }
- return put_user(read_mixer(s, 0x52), p);
- }
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- strncpy(info.id, "Solo1", sizeof(info.id));
- strncpy(info.name, "ESS Solo1", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- strncpy(info.id, "Solo1", sizeof(info.id));
- strncpy(info.name, "ESS Solo1", sizeof(info.name));
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(mixer_src[read_mixer(s, 0x1c) & 7], p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV |
- SOUND_MASK_SPEAKER, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- return put_user(SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD | SOUND_MASK_VOLUME, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- return put_user(SOUND_MASK_PCM | SOUND_MASK_SYNTH | SOUND_MASK_CD |
- SOUND_MASK_LINE | SOUND_MASK_LINE1 | SOUND_MASK_MIC |
- SOUND_MASK_VOLUME | SOUND_MASK_LINE2 | SOUND_MASK_RECLEV, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
- return -EINVAL;
- return put_user(s->mix.vol[vidx-1], p);
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-#if 0
- {
- static const unsigned char regs[] = {
- 0x1c, 0x1a, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x60, 0x62, 0x6d, 0x7c
- };
- int i;
-
- for (i = 0; i < sizeof(regs); i++)
- printk(KERN_DEBUG "solo1: mixer reg 0x%02x: 0x%02x\n",
- regs[i], read_mixer(s, regs[i]));
- printk(KERN_DEBUG "solo1: ctrl reg 0x%02x: 0x%02x\n",
- 0xb4, read_ctrl(s, 0xb4));
- }
-#endif
- if (get_user(val, p))
- return -EFAULT;
- i = hweight32(val);
- if (i == 0)
- return 0;
- else if (i > 1)
- val &= ~mixer_src[read_mixer(s, 0x1c) & 7];
- for (i = 0; i < 8; i++) {
- if (mixer_src[i] & val)
- break;
- }
- if (i > 7)
- return 0;
- write_mixer(s, 0x1c, i);
- return 0;
-
- case SOUND_MIXER_VOLUME:
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- r = (val >> 8) & 0xff;
- if (r > 100)
- r = 100;
- if (l < 6) {
- rl = 0x40;
- l = 0;
- } else {
- rl = (l * 2 - 11) / 3;
- l = (rl * 3 + 11) / 2;
- }
- if (r < 6) {
- rr = 0x40;
- r = 0;
- } else {
- rr = (r * 2 - 11) / 3;
- r = (rr * 3 + 11) / 2;
- }
- write_mixer(s, 0x60, rl);
- write_mixer(s, 0x62, rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[9] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[9] = val;
-#endif
- return put_user(s->mix.vol[9], p);
-
- case SOUND_MIXER_SPEAKER:
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- if (l > 100)
- l = 100;
- else if (l < 2)
- l = 2;
- rl = (l - 2) / 14;
- l = rl * 14 + 2;
- write_mixer(s, 0x3c, rl);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[7] = l * 0x101;
-#else
- s->mix.vol[7] = val;
-#endif
- return put_user(s->mix.vol[7], p);
-
- case SOUND_MIXER_RECLEV:
- if (get_user(val, p))
- return -EFAULT;
- l = (val << 1) & 0x1fe;
- if (l > 200)
- l = 200;
- else if (l < 5)
- l = 5;
- r = (val >> 7) & 0x1fe;
- if (r > 200)
- r = 200;
- else if (r < 5)
- r = 5;
- rl = (l - 5) / 13;
- rr = (r - 5) / 13;
- r = (rl * 13 + 5) / 2;
- l = (rr * 13 + 5) / 2;
- write_ctrl(s, 0xb4, (rl << 4) | rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[8] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[8] = val;
-#endif
- return put_user(s->mix.vol[8], p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i]))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = (val << 1) & 0x1fe;
- if (l > 200)
- l = 200;
- else if (l < 5)
- l = 5;
- r = (val >> 7) & 0x1fe;
- if (r > 200)
- r = 200;
- else if (r < 5)
- r = 5;
- rl = (l - 5) / 13;
- rr = (r - 5) / 13;
- r = (rl * 13 + 5) / 2;
- l = (rr * 13 + 5) / 2;
- write_mixer(s, mixreg[vidx-1], (rl << 4) | rr);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- s->mix.vol[vidx-1] = ((unsigned int)r << 8) | l;
-#else
- s->mix.vol[vidx-1] = val;
-#endif
- return put_user(s->mix.vol[vidx-1], p);
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int solo1_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
- drvr = pci_dev_driver (pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (s->dev_mixer == minor)
- break;
- }
- if (!s)
- return -ENODEV;
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int solo1_release_mixdev(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int solo1_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct solo1_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations solo1_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = solo1_ioctl_mixdev,
- .open = solo1_open_mixdev,
- .release = solo1_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct solo1_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count;
- unsigned tmo;
-
- if (s->dma_dac.mapped)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->rate;
- if (s->fmt & (AFMT_S16_LE | AFMT_U16_LE))
- tmo >>= 1;
- if (s->channels > 1)
- tmo >>= 1;
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "solo1: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t solo1_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
- add_wait_queue(&s->dma_adc.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x cnt: %u\n",
- read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc), cnt);
-#endif
- if (cnt <= 0) {
- if (s->dma_adc.enabled)
- start_adc(s);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
- KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
- KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
- KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
- inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
-#endif
- if (inb(s->ddmabase+15) & 1)
- printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: regs: A1: 0x%02x A2: 0x%02x A4: 0x%02x A5: 0x%02x A8: 0x%02x\n"
- KERN_DEBUG "solo1_read: regs: B1: 0x%02x B2: 0x%02x B7: 0x%02x B8: 0x%02x B9: 0x%02x\n"
- KERN_DEBUG "solo1_read: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x mask: 0x%02x\n"
- KERN_DEBUG "solo1_read: SBstat: 0x%02x cnt: %u\n",
- read_ctrl(s, 0xa1), read_ctrl(s, 0xa2), read_ctrl(s, 0xa4), read_ctrl(s, 0xa5), read_ctrl(s, 0xa8),
- read_ctrl(s, 0xb1), read_ctrl(s, 0xb2), read_ctrl(s, 0xb7), read_ctrl(s, 0xb8), read_ctrl(s, 0xb9),
- inl(s->ddmabase), inw(s->ddmabase+4), inb(s->ddmabase+8), inb(s->ddmabase+15), inb(s->sbbase+0xc), cnt);
-#endif
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_adc.enabled)
- start_adc(s);
-#ifdef DEBUGREC
- printk(KERN_DEBUG "solo1_read: reg B8: 0x%02x DMAstat: 0x%02x DMAcnt: 0x%04x SBstat: 0x%02x\n",
- read_ctrl(s, 0xb8), inb(s->ddmabase+8), inw(s->ddmabase+4), inb(s->sbbase+0xc));
-#endif
- }
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t solo1_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-#if 0
- printk(KERN_DEBUG "solo1_write: reg 70: 0x%02x 71: 0x%02x 72: 0x%02x 74: 0x%02x 76: 0x%02x 78: 0x%02x 7A: 0x%02x\n"
- KERN_DEBUG "solo1_write: DMA: addr: 0x%08x cnt: 0x%04x stat: 0x%02x SBstat: 0x%02x\n",
- read_mixer(s, 0x70), read_mixer(s, 0x71), read_mixer(s, 0x72), read_mixer(s, 0x74), read_mixer(s, 0x76),
- read_mixer(s, 0x78), read_mixer(s, 0x7a), inl(s->iobase), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
- printk(KERN_DEBUG "solo1_write: reg 78: 0x%02x reg 7A: 0x%02x DMAcnt: 0x%04x DMAstat: 0x%02x SBstat: 0x%02x\n",
- read_mixer(s, 0x78), read_mixer(s, 0x7a), inw(s->iobase+4), inb(s->iobase+6), inb(s->sbbase+0xc));
-#endif
- ret = 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize-swptr;
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_dac.enabled)
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac.enabled)
- start_dac(s);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int solo1_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf_dac(s))
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf_adc(s))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.mapped) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- } else {
- if (s->dma_adc.count > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-
-static int solo1_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf_dac(s)) != 0)
- goto out;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf_adc(s)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int solo1_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret, count;
- int div1, div2;
- unsigned rate1, rate2;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- prog_codec(s);
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program sampling rates */
- if (val > 48000)
- val = 48000;
- if (val < 6300)
- val = 6300;
- div1 = (768000 + val / 2) / val;
- rate1 = (768000 + div1 / 2) / div1;
- div1 = -div1;
- div2 = (793800 + val / 2) / val;
- rate2 = (793800 + div2 / 2) / div2;
- div2 = (-div2) & 0x7f;
- if (abs(val - rate2) < abs(val - rate1)) {
- rate1 = rate2;
- div1 = div2;
- }
- s->rate = rate1;
- s->clkdiv = div1;
- prog_codec(s);
- }
- return put_user(s->rate, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program channels */
- s->channels = val ? 2 : 1;
- prog_codec(s);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program channels */
- s->channels = (val >= 2) ? 2 : 1;
- prog_codec(s);
- }
- return put_user(s->channels, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U16_LE|AFMT_S8|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- stop_adc(s);
- stop_dac(s);
- s->dma_adc.ready = s->dma_dac.ready = 0;
- /* program format */
- if (val != AFMT_S16_LE && val != AFMT_U16_LE &&
- val != AFMT_S8 && val != AFMT_U8)
- val = AFMT_U8;
- s->fmt = val;
- prog_codec(s);
- }
- return put_user(s->fmt, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & s->ena & FMODE_READ)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & s->ena & FMODE_WRITE)
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- s->dma_dac.enabled = 1;
- start_adc(s);
- if (inb(s->ddmabase+15) & 1)
- printk(KERN_ERR "solo1: cannot start recording, DDMA mask bit stuck at 1\n");
- } else {
- s->dma_dac.enabled = 0;
- stop_adc(s);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf_dac(s)))
- return ret;
- s->dma_dac.enabled = 1;
- start_dac(s);
- } else {
- s->dma_dac.enabled = 0;
- stop_dac(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac.dmasize - count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- return put_user(count, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf_adc(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf_dac(s)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- solo1_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
-#if 0
- printk(KERN_DEBUG "esssolo1: GETOPTR: bytes %u blocks %u ptr %u, buforder %u numfrag %u fragshift %u\n"
- KERN_DEBUG "esssolo1: swptr %u count %u fragsize %u dmasize %u fragsamples %u\n",
- cinfo.bytes, cinfo.blocks, cinfo.ptr, s->dma_dac.buforder, s->dma_dac.numfrag, s->dma_dac.fragshift,
- s->dma_dac.swptr, s->dma_dac.count, s->dma_dac.fragsize, s->dma_dac.dmasize, s->dma_dac.fragsamples);
-#endif
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf_dac(s)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf_adc(s)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user(s->rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user(s->channels, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & (AFMT_S8|AFMT_U8)) ? 8 : 16, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int solo1_release(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- outb(0, s->iobase+6); /* disable DMA */
- dealloc_dmabuf(s, &s->dma_dac);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- outb(1, s->ddmabase+0xf); /* mask DMA channel */
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- dealloc_dmabuf(s, &s->dma_adc);
- }
- s->open_mode &= ~(FMODE_READ | FMODE_WRITE);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static int solo1_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver(pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- if (!s)
- return -ENODEV;
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & (FMODE_READ | FMODE_WRITE)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- s->fmt = AFMT_U8;
- s->channels = 1;
- s->rate = 8000;
- s->clkdiv = 96 | 0x80;
- s->ena = 0;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- s->dma_dac.enabled = 1;
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- prog_codec(s);
- return nonseekable_open(inode, file);
-}
-
-static /*const*/ struct file_operations solo1_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = solo1_read,
- .write = solo1_write,
- .poll = solo1_poll,
- .ioctl = solo1_ioctl,
- .mmap = solo1_mmap,
- .open = solo1_open,
- .release = solo1_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* hold spinlock for the following! */
-static void solo1_handle_midi(struct solo1_state *s)
-{
- unsigned char ch;
- int wake;
-
- if (!(s->mpubase))
- return;
- wake = 0;
- while (!(inb(s->mpubase+1) & 0x80)) {
- ch = inb(s->mpubase);
- if (s->midi.icnt < MIDIINBUF) {
- s->midi.ibuf[s->midi.iwr] = ch;
- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
- s->midi.icnt++;
- }
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.iwait);
- wake = 0;
- while (!(inb(s->mpubase+1) & 0x40) && s->midi.ocnt > 0) {
- outb(s->midi.obuf[s->midi.ord], s->mpubase);
- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
- s->midi.ocnt--;
- if (s->midi.ocnt < MIDIOUTBUF-16)
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.owait);
-}
-
-static irqreturn_t solo1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct solo1_state *s = (struct solo1_state *)dev_id;
- unsigned int intsrc;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inb(s->iobase+7); /* get interrupt source(s) */
- if (!intsrc)
- return IRQ_NONE;
- (void)inb(s->sbbase+0xe); /* clear interrupt */
- spin_lock(&s->lock);
- /* clear audio interrupts first */
- if (intsrc & 0x20)
- write_mixer(s, 0x7a, read_mixer(s, 0x7a) & 0x7f);
- solo1_update_ptr(s);
- solo1_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-static void solo1_midi_timer(unsigned long data)
-{
- struct solo1_state *s = (struct solo1_state *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- solo1_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->midi.timer.expires = jiffies+1;
- add_timer(&s->midi.timer);
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t solo1_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.iwait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.ird;
- cnt = MIDIINBUF - ptr;
- if (s->midi.icnt < cnt)
- cnt = s->midi.icnt;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIINBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.ird = ptr;
- s->midi.icnt -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.iwait, &wait);
- return ret;
-}
-
-static ssize_t solo1_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.owait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.owr;
- cnt = MIDIOUTBUF - ptr;
- if (s->midi.ocnt + cnt > MIDIOUTBUF)
- cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0) {
- __set_current_state(TASK_INTERRUPTIBLE);
- solo1_handle_midi(s);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIOUTBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.owr = ptr;
- s->midi.ocnt += cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_lock_irqsave(&s->lock, flags);
- solo1_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.owait, &wait);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int solo1_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_flags & FMODE_WRITE)
- poll_wait(file, &s->midi.owait, wait);
- if (file->f_flags & FMODE_READ)
- poll_wait(file, &s->midi.iwait, wait);
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_flags & FMODE_READ) {
- if (s->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_flags & FMODE_WRITE) {
- if (s->midi.ocnt < MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int solo1_midi_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver(pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (s->dev_midi == minor)
- break;
- }
- if (!s)
- return -ENODEV;
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- outb(0xff, s->mpubase+1); /* reset command */
- outb(0x3f, s->mpubase+1); /* uart command */
- if (!(inb(s->mpubase+1) & 0x80))
- inb(s->mpubase);
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- outb(0xb0, s->iobase + 7); /* enable A1, A2, MPU irq's */
- init_timer(&s->midi.timer);
- s->midi.timer.expires = jiffies+1;
- s->midi.timer.data = (unsigned long)s;
- s->midi.timer.function = solo1_midi_timer;
- add_timer(&s->midi.timer);
- }
- if (file->f_mode & FMODE_READ) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int solo1_midi_release(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- unsigned count, tmo;
-
- VALIDATE_STATE(s);
-
- lock_kernel();
- if (file->f_mode & FMODE_WRITE) {
- add_wait_queue(&s->midi.owait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->midi.ocnt;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (file->f_flags & O_NONBLOCK)
- break;
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "solo1: midi timed out??\n");
- }
- remove_wait_queue(&s->midi.owait, &wait);
- set_current_state(TASK_RUNNING);
- }
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- outb(0x30, s->iobase + 7); /* enable A1, A2 irq's */
- del_timer(&s->midi.timer);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations solo1_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = solo1_midi_read,
- .write = solo1_midi_write,
- .poll = solo1_midi_poll,
- .open = solo1_midi_open,
- .release = solo1_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int solo1_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- static const unsigned char op_offset[18] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
- };
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- struct dm_fm_voice v;
- struct dm_fm_note n;
- struct dm_fm_params p;
- unsigned int io;
- unsigned int regb;
-
- switch (cmd) {
- case FM_IOCTL_RESET:
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->sbbase);
- outb(0, s->sbbase+1);
- outb(regb, s->sbbase+2);
- outb(0, s->sbbase+3);
- }
- return 0;
-
- case FM_IOCTL_PLAY_NOTE:
- if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
- return -EFAULT;
- if (n.voice >= 18)
- return -EINVAL;
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->sbbase+2;
- } else {
- regb = n.voice;
- io = s->sbbase;
- }
- outb(0xa0 + regb, io);
- outb(n.fnum & 0xff, io+1);
- outb(0xb0 + regb, io);
- outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
- return 0;
-
- case FM_IOCTL_SET_VOICE:
- if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
- return -EFAULT;
- if (v.voice >= 18)
- return -EINVAL;
- regb = op_offset[v.voice];
- io = s->sbbase + ((v.op & 1) << 1);
- outb(0x20 + regb, io);
- outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) |
- ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
- outb(0x40 + regb, io);
- outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
- outb(0x60 + regb, io);
- outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
- outb(0x80 + regb, io);
- outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
- outb(0xe0 + regb, io);
- outb(v.waveform & 0x7, io+1);
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->sbbase+2;
- } else {
- regb = n.voice;
- io = s->sbbase;
- }
- outb(0xc0 + regb, io);
- outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
- (v.connection & 1), io+1);
- return 0;
-
- case FM_IOCTL_SET_PARAMS:
- if (copy_from_user(&p, (void __user *)arg, sizeof(p)))
- return -EFAULT;
- outb(0x08, s->sbbase);
- outb((p.kbd_split & 1) << 6, s->sbbase+1);
- outb(0xbd, s->sbbase);
- outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
- ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->sbbase+1);
- return 0;
-
- case FM_IOCTL_SET_OPL:
- outb(4, s->sbbase+2);
- outb(arg, s->sbbase+3);
- return 0;
-
- case FM_IOCTL_SET_MODE:
- outb(5, s->sbbase+2);
- outb(arg & 1, s->sbbase+3);
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-static int solo1_dmfm_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct solo1_state *s = NULL;
- struct pci_dev *pci_dev = NULL;
-
- while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver(pci_dev);
- if (drvr != &solo1_driver)
- continue;
- s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- continue;
- if (s->dev_dmfm == minor)
- break;
- }
- if (!s)
- return -ENODEV;
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & FMODE_DMFM) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- if (!request_region(s->sbbase, FMSYNTH_EXTENT, "ESS Solo1")) {
- mutex_unlock(&s->open_mutex);
- printk(KERN_ERR "solo1: FM synth io ports in use, opl3 loaded?\n");
- return -EBUSY;
- }
- /* init the stuff */
- outb(1, s->sbbase);
- outb(0x20, s->sbbase+1); /* enable waveforms */
- outb(4, s->sbbase+2);
- outb(0, s->sbbase+3); /* no 4op enabled */
- outb(5, s->sbbase+2);
- outb(1, s->sbbase+3); /* enable OPL3 */
- s->open_mode |= FMODE_DMFM;
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int solo1_dmfm_release(struct inode *inode, struct file *file)
-{
- struct solo1_state *s = (struct solo1_state *)file->private_data;
- unsigned int regb;
-
- VALIDATE_STATE(s);
- lock_kernel();
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~FMODE_DMFM;
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->sbbase);
- outb(0, s->sbbase+1);
- outb(regb, s->sbbase+2);
- outb(0, s->sbbase+3);
- }
- release_region(s->sbbase, FMSYNTH_EXTENT);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations solo1_dmfm_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = solo1_dmfm_ioctl,
- .open = solo1_dmfm_open,
- .release = solo1_dmfm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
- { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
- { SOUND_MIXER_WRITE_SPEAKER, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 }
-};
-
-static int setup_solo1(struct solo1_state *s)
-{
- struct pci_dev *pcidev = s->dev;
- mm_segment_t fs;
- int i, val;
-
- /* initialize DDMA base address */
- printk(KERN_DEBUG "solo1: ddma base address: 0x%lx\n", s->ddmabase);
- pci_write_config_word(pcidev, 0x60, (s->ddmabase & (~0xf)) | 1);
- /* set DMA policy to DDMA, IRQ emulation off (CLKRUN disabled for now) */
- pci_write_config_dword(pcidev, 0x50, 0);
- /* disable legacy audio address decode */
- pci_write_config_word(pcidev, 0x40, 0x907f);
-
- /* initialize the chips */
- if (!reset_ctrl(s)) {
- printk(KERN_ERR "esssolo1: cannot reset controller\n");
- return -1;
- }
- outb(0xb0, s->iobase+7); /* enable A1, A2, MPU irq's */
-
- /* initialize mixer regs */
- write_mixer(s, 0x7f, 0); /* disable music digital recording */
- write_mixer(s, 0x7d, 0x0c); /* enable mic preamp, MONO_OUT is 2nd DAC right channel */
- write_mixer(s, 0x64, 0x45); /* volume control */
- write_mixer(s, 0x48, 0x10); /* enable music DAC/ES6xx interface */
- write_mixer(s, 0x50, 0); /* disable spatializer */
- write_mixer(s, 0x52, 0);
- write_mixer(s, 0x14, 0); /* DAC1 minimum volume */
- write_mixer(s, 0x71, 0x20); /* enable new 0xA1 reg format */
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- outb(1, s->ddmabase+0xf); /* mask channel */
- /*outb(0, s->ddmabase+0x8);*/ /* enable controller (enable is low active!!) */
-
- pci_set_master(pcidev); /* enable bus mastering */
-
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- val = 1; /* enable mic preamp */
- mixer_ioctl(s, SOUND_MIXER_PRIVATE1, (unsigned long)&val);
- set_fs(fs);
- return 0;
-}
-
-static int
-solo1_suspend(struct pci_dev *pci_dev, pm_message_t state) {
- struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- return 1;
- outb(0, s->iobase+6);
- /* DMA master clear */
- outb(0, s->ddmabase+0xd);
- /* reset sequencer and FIFO */
- outb(3, s->sbbase+6);
- /* turn off DDMA controller address space */
- pci_write_config_word(s->dev, 0x60, 0);
- return 0;
-}
-
-static int
-solo1_resume(struct pci_dev *pci_dev) {
- struct solo1_state *s = (struct solo1_state*)pci_get_drvdata(pci_dev);
- if (!s)
- return 1;
- setup_solo1(s);
- return 0;
-}
-
-#ifdef SUPPORT_JOYSTICK
-static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
-{
- struct gameport *gp;
-
- if (!request_region(io_port, GAMEPORT_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: gameport io ports are in use\n");
- return -EBUSY;
- }
-
- s->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR "solo1: can not allocate memory for gameport\n");
- release_region(io_port, GAMEPORT_EXTENT);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "ESS Solo1 Gameport");
- gameport_set_phys(gp, "isa%04x/gameport0", io_port);
- gp->dev.parent = &s->dev->dev;
- gp->io = io_port;
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void solo1_unregister_gameport(struct solo1_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, GAMEPORT_EXTENT);
- }
-}
-#else
-static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
-static inline void solo1_unregister_gameport(struct solo1_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- struct solo1_state *s;
- int gpio;
- int ret;
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
- if (!(pci_resource_flags(pcidev, 0) & IORESOURCE_IO) ||
- !(pci_resource_flags(pcidev, 1) & IORESOURCE_IO) ||
- !(pci_resource_flags(pcidev, 2) & IORESOURCE_IO) ||
- !(pci_resource_flags(pcidev, 3) & IORESOURCE_IO))
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
-
- /* Recording requires 24-bit DMA, so attempt to set dma mask
- * to 24 bits first, then 32 bits (playback only) if that fails.
- */
- if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK) &&
- pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
- printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
- return -ENODEV;
- }
-
- if (!(s = kmalloc(sizeof(struct solo1_state), GFP_KERNEL))) {
- printk(KERN_WARNING "solo1: out of memory\n");
- return -ENOMEM;
- }
- memset(s, 0, sizeof(struct solo1_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
- s->magic = SOLO1_MAGIC;
- s->dev = pcidev;
- s->iobase = pci_resource_start(pcidev, 0);
- s->sbbase = pci_resource_start(pcidev, 1);
- s->vcbase = pci_resource_start(pcidev, 2);
- s->ddmabase = s->vcbase + DDMABASE_OFFSET;
- s->mpubase = pci_resource_start(pcidev, 3);
- gpio = pci_resource_start(pcidev, 4);
- s->irq = pcidev->irq;
- ret = -EBUSY;
- if (!request_region(s->iobase, IOBASE_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region1;
- }
- if (!request_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region2;
- }
- if (!request_region(s->ddmabase, DDMABASE_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region3;
- }
- if (!request_region(s->mpubase, MPUBASE_EXTENT, "ESS Solo1")) {
- printk(KERN_ERR "solo1: io ports in use\n");
- goto err_region4;
- }
- if ((ret=request_irq(s->irq,solo1_interrupt,IRQF_SHARED,"ESS Solo1",s))) {
- printk(KERN_ERR "solo1: irq %u in use\n", s->irq);
- goto err_irq;
- }
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&solo1_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&solo1_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- if ((s->dev_midi = register_sound_midi(&solo1_midi_fops, -1)) < 0) {
- ret = s->dev_midi;
- goto err_dev3;
- }
- if ((s->dev_dmfm = register_sound_special(&solo1_dmfm_fops, 15 /* ?? */)) < 0) {
- ret = s->dev_dmfm;
- goto err_dev4;
- }
- if (setup_solo1(s)) {
- ret = -EIO;
- goto err;
- }
- /* register gameport */
- solo1_register_gameport(s, gpio);
- /* store it in the driver field */
- pci_set_drvdata(pcidev, s);
- return 0;
-
- err:
- unregister_sound_special(s->dev_dmfm);
- err_dev4:
- unregister_sound_midi(s->dev_midi);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "solo1: initialisation error\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->mpubase, MPUBASE_EXTENT);
- err_region4:
- release_region(s->ddmabase, DDMABASE_EXTENT);
- err_region3:
- release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- err_region2:
- release_region(s->iobase, IOBASE_EXTENT);
- err_region1:
- kfree(s);
- return ret;
-}
-
-static void __devexit solo1_remove(struct pci_dev *dev)
-{
- struct solo1_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- /* stop DMA controller */
- outb(0, s->iobase+6);
- outb(0, s->ddmabase+0xd); /* DMA master clear */
- outb(3, s->sbbase+6); /* reset sequencer and FIFO */
- synchronize_irq(s->irq);
- pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
- free_irq(s->irq, s);
- solo1_unregister_gameport(s);
- release_region(s->iobase, IOBASE_EXTENT);
- release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
- release_region(s->ddmabase, DDMABASE_EXTENT);
- release_region(s->mpubase, MPUBASE_EXTENT);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_midi(s->dev_midi);
- unregister_sound_special(s->dev_dmfm);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_SOLO1, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver solo1_driver = {
- .name = "ESS Solo1",
- .id_table = id_table,
- .probe = solo1_probe,
- .remove = __devexit_p(solo1_remove),
- .suspend = solo1_suspend,
- .resume = solo1_resume,
-};
-
-
-static int __init init_solo1(void)
-{
- printk(KERN_INFO "solo1: version v0.20 time " __TIME__ " " __DATE__ "\n");
- return pci_register_driver(&solo1_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("ESS Solo1 Driver");
-MODULE_LICENSE("GPL");
-
-
-static void __exit cleanup_solo1(void)
-{
- printk(KERN_INFO "solo1: unloading\n");
- pci_unregister_driver(&solo1_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-module_init(init_solo1);
-module_exit(cleanup_solo1);
-
diff --git a/sound/oss/forte.c b/sound/oss/forte.c
deleted file mode 100644
index ea1c0207aef2..000000000000
--- a/sound/oss/forte.c
+++ /dev/null
@@ -1,2139 +0,0 @@
-/*
- * forte.c - ForteMedia FM801 OSS Driver
- *
- * Written by Martin K. Petersen <mkp@mkp.net>
- * Copyright (C) 2002 Hewlett-Packard Company
- * Portions Copyright (C) 2003 Martin K. Petersen
- *
- * Latest version: http://mkp.net/forte/
- *
- * Based upon the ALSA FM801 driver by Jaroslav Kysela and OSS drivers
- * by Thomas Sailer, Alan Cox, Zach Brown, and Jeff Garzik. Thanks
- * guys!
- *
- * 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/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/pci.h>
-
-#include <linux/delay.h>
-#include <linux/poll.h>
-
-#include <linux/sound.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-
-#include <linux/proc_fs.h>
-#include <linux/mutex.h>
-
-#include <asm/uaccess.h>
-#include <asm/io.h>
-
-#define DRIVER_NAME "forte"
-#define DRIVER_VERSION "$Id: forte.c,v 1.63 2003/03/01 05:32:42 mkp Exp $"
-#define PFX DRIVER_NAME ": "
-
-#undef M_DEBUG
-
-#ifdef M_DEBUG
-#define DPRINTK(args...) printk(KERN_WARNING args)
-#else
-#define DPRINTK(args...)
-#endif
-
-/* Card capabilities */
-#define FORTE_CAPS (DSP_CAP_MMAP | DSP_CAP_TRIGGER)
-
-/* Supported audio formats */
-#define FORTE_FMTS (AFMT_U8 | AFMT_S16_LE)
-
-/* Buffers */
-#define FORTE_MIN_FRAG_SIZE 256
-#define FORTE_MAX_FRAG_SIZE PAGE_SIZE
-#define FORTE_DEF_FRAG_SIZE 256
-#define FORTE_MIN_FRAGMENTS 2
-#define FORTE_MAX_FRAGMENTS 256
-#define FORTE_DEF_FRAGMENTS 2
-#define FORTE_MIN_BUF_MSECS 500
-#define FORTE_MAX_BUF_MSECS 1000
-
-/* PCI BARs */
-#define FORTE_PCM_VOL 0x00 /* PCM Output Volume */
-#define FORTE_FM_VOL 0x02 /* FM Output Volume */
-#define FORTE_I2S_VOL 0x04 /* I2S Volume */
-#define FORTE_REC_SRC 0x06 /* Record Source */
-#define FORTE_PLY_CTRL 0x08 /* Playback Control */
-#define FORTE_PLY_COUNT 0x0a /* Playback Count */
-#define FORTE_PLY_BUF1 0x0c /* Playback Buffer I */
-#define FORTE_PLY_BUF2 0x10 /* Playback Buffer II */
-#define FORTE_CAP_CTRL 0x14 /* Capture Control */
-#define FORTE_CAP_COUNT 0x16 /* Capture Count */
-#define FORTE_CAP_BUF1 0x18 /* Capture Buffer I */
-#define FORTE_CAP_BUF2 0x1c /* Capture Buffer II */
-#define FORTE_CODEC_CTRL 0x22 /* Codec Control */
-#define FORTE_I2S_MODE 0x24 /* I2S Mode Control */
-#define FORTE_VOLUME 0x26 /* Volume Up/Down/Mute Status */
-#define FORTE_I2C_CTRL 0x29 /* I2C Control */
-#define FORTE_AC97_CMD 0x2a /* AC'97 Command */
-#define FORTE_AC97_DATA 0x2c /* AC'97 Data */
-#define FORTE_MPU401_DATA 0x30 /* MPU401 Data */
-#define FORTE_MPU401_CMD 0x31 /* MPU401 Command */
-#define FORTE_GPIO_CTRL 0x52 /* General Purpose I/O Control */
-#define FORTE_GEN_CTRL 0x54 /* General Control */
-#define FORTE_IRQ_MASK 0x56 /* Interrupt Mask */
-#define FORTE_IRQ_STATUS 0x5a /* Interrupt Status */
-#define FORTE_OPL3_BANK0 0x68 /* OPL3 Status Read / Bank 0 Write */
-#define FORTE_OPL3_DATA0 0x69 /* OPL3 Data 0 Write */
-#define FORTE_OPL3_BANK1 0x6a /* OPL3 Bank 1 Write */
-#define FORTE_OPL3_DATA1 0x6b /* OPL3 Bank 1 Write */
-#define FORTE_POWERDOWN 0x70 /* Blocks Power Down Control */
-
-#define FORTE_CAP_OFFSET FORTE_CAP_CTRL - FORTE_PLY_CTRL
-
-#define FORTE_AC97_ADDR_SHIFT 10
-
-/* Playback and record control register bits */
-#define FORTE_BUF1_LAST (1<<1)
-#define FORTE_BUF2_LAST (1<<2)
-#define FORTE_START (1<<5)
-#define FORTE_PAUSE (1<<6)
-#define FORTE_IMMED_STOP (1<<7)
-#define FORTE_RATE_SHIFT 8
-#define FORTE_RATE_MASK (15 << FORTE_RATE_SHIFT)
-#define FORTE_CHANNELS_4 (1<<12) /* Playback only */
-#define FORTE_CHANNELS_6 (2<<12) /* Playback only */
-#define FORTE_CHANNELS_6MS (3<<12) /* Playback only */
-#define FORTE_CHANNELS_MASK (3<<12)
-#define FORTE_16BIT (1<<14)
-#define FORTE_STEREO (1<<15)
-
-/* IRQ status bits */
-#define FORTE_IRQ_PLAYBACK (1<<8)
-#define FORTE_IRQ_CAPTURE (1<<9)
-#define FORTE_IRQ_VOLUME (1<<14)
-#define FORTE_IRQ_MPU (1<<15)
-
-/* CODEC control */
-#define FORTE_CC_CODEC_RESET (1<<5)
-#define FORTE_CC_AC97_RESET (1<<6)
-
-/* AC97 cmd */
-#define FORTE_AC97_WRITE (0<<7)
-#define FORTE_AC97_READ (1<<7)
-#define FORTE_AC97_DP_INVALID (0<<8)
-#define FORTE_AC97_DP_VALID (1<<8)
-#define FORTE_AC97_PORT_RDY (0<<9)
-#define FORTE_AC97_PORT_BSY (1<<9)
-
-
-struct forte_channel {
- const char *name;
-
- unsigned short ctrl; /* Ctrl BAR contents */
- unsigned long iobase; /* Ctrl BAR address */
-
- wait_queue_head_t wait;
-
- void *buf; /* Buffer */
- dma_addr_t buf_handle; /* Buffer handle */
-
- unsigned int record;
- unsigned int format;
- unsigned int rate;
- unsigned int stereo;
-
- unsigned int frag_sz; /* Current fragment size */
- unsigned int frag_num; /* Current # of fragments */
- unsigned int frag_msecs; /* Milliseconds per frag */
- unsigned int buf_sz; /* Current buffer size */
-
- unsigned int hwptr; /* Tail */
- unsigned int swptr; /* Head */
- unsigned int filled_frags; /* Fragments currently full */
- unsigned int next_buf; /* Index of next buffer */
-
- unsigned int active; /* Channel currently in use */
- unsigned int mapped; /* mmap */
-
- unsigned int buf_pages; /* Real size of buffer */
- unsigned int nr_irqs; /* Number of interrupts */
- unsigned int bytes; /* Total bytes */
- unsigned int residue; /* Partial fragment */
-};
-
-
-struct forte_chip {
- struct pci_dev *pci_dev;
- unsigned long iobase;
- int irq;
-
- struct mutex open_mutex; /* Device access */
- spinlock_t lock; /* State */
-
- spinlock_t ac97_lock;
- struct ac97_codec *ac97;
-
- int multichannel;
- int dsp; /* OSS handle */
- int trigger; /* mmap I/O trigger */
-
- struct forte_channel play;
- struct forte_channel rec;
-};
-
-
-static int channels[] = { 2, 4, 6, };
-static int rates[] = { 5500, 8000, 9600, 11025, 16000, 19200,
- 22050, 32000, 38400, 44100, 48000, };
-
-static struct forte_chip *forte;
-static int found;
-
-
-/* AC97 Codec -------------------------------------------------------------- */
-
-
-/**
- * forte_ac97_wait:
- * @chip: fm801 instance whose AC97 codec to wait on
- *
- * FIXME:
- * Stop busy-waiting
- */
-
-static inline int
-forte_ac97_wait (struct forte_chip *chip)
-{
- int i = 10000;
-
- while ( (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_PORT_BSY)
- && i-- )
- cpu_relax();
-
- return i == 0;
-}
-
-
-/**
- * forte_ac97_read:
- * @codec: AC97 codec to read from
- * @reg: register to read
- */
-
-static u16
-forte_ac97_read (struct ac97_codec *codec, u8 reg)
-{
- u16 ret = 0;
- struct forte_chip *chip = codec->private_data;
-
- spin_lock (&chip->ac97_lock);
-
- /* Knock, knock */
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_read: Serial bus busy\n");
- goto out;
- }
-
- /* Send read command */
- outw (reg | (1<<7), chip->iobase + FORTE_AC97_CMD);
-
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_read: Bus busy reading reg 0x%x\n",
- reg);
- goto out;
- }
-
- /* Sanity checking */
- if (inw (chip->iobase + FORTE_AC97_CMD) & FORTE_AC97_DP_INVALID) {
- printk (KERN_ERR PFX "ac97_read: Invalid data port");
- goto out;
- }
-
- /* Fetch result */
- ret = inw (chip->iobase + FORTE_AC97_DATA);
-
- out:
- spin_unlock (&chip->ac97_lock);
- return ret;
-}
-
-
-/**
- * forte_ac97_write:
- * @codec: AC97 codec to send command to
- * @reg: register to write
- * @val: value to write
- */
-
-static void
-forte_ac97_write (struct ac97_codec *codec, u8 reg, u16 val)
-{
- struct forte_chip *chip = codec->private_data;
-
- spin_lock (&chip->ac97_lock);
-
- /* Knock, knock */
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_write: Serial bus busy\n");
- goto out;
- }
-
- outw (val, chip->iobase + FORTE_AC97_DATA);
- outb (reg | FORTE_AC97_WRITE, chip->iobase + FORTE_AC97_CMD);
-
- /* Wait for completion */
- if (forte_ac97_wait (chip)) {
- printk (KERN_ERR PFX "ac97_write: Bus busy after write\n");
- goto out;
- }
-
- out:
- spin_unlock (&chip->ac97_lock);
-}
-
-
-/* Mixer ------------------------------------------------------------------- */
-
-
-/**
- * forte_mixer_open:
- * @inode:
- * @file:
- */
-
-static int
-forte_mixer_open (struct inode *inode, struct file *file)
-{
- struct forte_chip *chip = forte;
- file->private_data = chip->ac97;
- return 0;
-}
-
-
-/**
- * forte_mixer_release:
- * @inode:
- * @file:
- */
-
-static int
-forte_mixer_release (struct inode *inode, struct file *file)
-{
- /* We will welease Wodewick */
- return 0;
-}
-
-
-/**
- * forte_mixer_ioctl:
- * @inode:
- * @file:
- */
-
-static int
-forte_mixer_ioctl (struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *) file->private_data;
-
- return codec->mixer_ioctl (codec, cmd, arg);
-}
-
-
-static struct file_operations forte_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = forte_mixer_ioctl,
- .open = forte_mixer_open,
- .release = forte_mixer_release,
-};
-
-
-/* Channel ----------------------------------------------------------------- */
-
-/**
- * forte_channel_reset:
- * @channel: Channel to reset
- *
- * Locking: Must be called with lock held.
- */
-
-static void
-forte_channel_reset (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase)
- return;
-
- DPRINTK ("%s: channel = %s\n", __FUNCTION__, channel->name);
-
- channel->ctrl &= ~FORTE_START;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-
- /* We always play at least two fragments, hence these defaults */
- channel->hwptr = channel->frag_sz;
- channel->next_buf = 1;
- channel->swptr = 0;
- channel->filled_frags = 0;
- channel->active = 0;
- channel->bytes = 0;
- channel->nr_irqs = 0;
- channel->mapped = 0;
- channel->residue = 0;
-}
-
-
-/**
- * forte_channel_start:
- * @channel: Channel to start (record/playback)
- *
- * Locking: Must be called with lock held.
- */
-
-static void inline
-forte_channel_start (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase || channel->active)
- return;
-
- channel->ctrl &= ~(FORTE_PAUSE | FORTE_BUF1_LAST | FORTE_BUF2_LAST
- | FORTE_IMMED_STOP);
- channel->ctrl |= FORTE_START;
- channel->active = 1;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/**
- * forte_channel_stop:
- * @channel: Channel to stop
- *
- * Locking: Must be called with lock held.
- */
-
-static void inline
-forte_channel_stop (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase)
- return;
-
- channel->ctrl &= ~(FORTE_START | FORTE_PAUSE);
- channel->ctrl |= FORTE_IMMED_STOP;
-
- channel->active = 0;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/**
- * forte_channel_pause:
- * @channel: Channel to pause
- *
- * Locking: Must be called with lock held.
- */
-
-static void inline
-forte_channel_pause (struct forte_channel *channel)
-{
- if (!channel || !channel->iobase)
- return;
-
- channel->ctrl |= FORTE_PAUSE;
-
- channel->active = 0;
- outw (channel->ctrl, channel->iobase + FORTE_PLY_CTRL);
-}
-
-
-/**
- * forte_channel_rate:
- * @channel: Channel whose rate to set. Playback and record are
- * independent.
- * @rate: Channel rate in Hz
- *
- * Locking: Must be called with lock held.
- */
-
-static int
-forte_channel_rate (struct forte_channel *channel, unsigned int rate)
-{
- int new_rate;
-
- if (!channel || !channel->iobase)
- return -EINVAL;
-
- /* The FM801 only supports a handful of fixed frequencies.
- * We find the value closest to what userland requested.
- */
- if (rate <= 6250) { rate = 5500; new_rate = 0; }
- else if (rate <= 8800) { rate = 8000; new_rate = 1; }
- else if (rate <= 10312) { rate = 9600; new_rate = 2; }
- else if (rate <= 13512) { rate = 11025; new_rate = 3; }
- else if (rate <= 17600) { rate = 16000; new_rate = 4; }
- else if (rate <= 20625) { rate = 19200; new_rate = 5; }
- else if (rate <= 27025) { rate = 22050; new_rate = 6; }
- else if (rate <= 35200) { rate = 32000; new_rate = 7; }
- else if (rate <= 41250) { rate = 38400; new_rate = 8; }
- else if (rate <= 46050) { rate = 44100; new_rate = 9; }
- else { rate = 48000; new_rate = 10; }
-
- channel->ctrl &= ~FORTE_RATE_MASK;
- channel->ctrl |= new_rate << FORTE_RATE_SHIFT;
- channel->rate = rate;
-
- DPRINTK ("%s: %s rate = %d\n", __FUNCTION__, channel->name, rate);
-
- return rate;
-}
-
-
-/**
- * forte_channel_format:
- * @channel: Channel whose audio format to set
- * @format: OSS format ID
- *
- * Locking: Must be called with lock held.
- */
-
-static int
-forte_channel_format (struct forte_channel *channel, int format)
-{
- if (!channel || !channel->iobase)
- return -EINVAL;
-
- switch (format) {
-
- case AFMT_QUERY:
- break;
-
- case AFMT_U8:
- channel->ctrl &= ~FORTE_16BIT;
- channel->format = AFMT_U8;
- break;
-
- case AFMT_S16_LE:
- default:
- channel->ctrl |= FORTE_16BIT;
- channel->format = AFMT_S16_LE;
- break;
- }
-
- DPRINTK ("%s: %s want %d format, got %d\n", __FUNCTION__, channel->name,
- format, channel->format);
-
- return channel->format;
-}
-
-
-/**
- * forte_channel_stereo:
- * @channel: Channel to toggle
- * @stereo: 0 for Mono, 1 for Stereo
- *
- * Locking: Must be called with lock held.
- */
-
-static int
-forte_channel_stereo (struct forte_channel *channel, unsigned int stereo)
-{
- int ret;
-
- if (!channel || !channel->iobase)
- return -EINVAL;
-
- DPRINTK ("%s: %s stereo = %d\n", __FUNCTION__, channel->name, stereo);
-
- switch (stereo) {
-
- case 0:
- channel->ctrl &= ~(FORTE_STEREO | FORTE_CHANNELS_MASK);
- channel-> stereo = stereo;
- ret = stereo;
- break;
-
- case 1:
- channel->ctrl &= ~FORTE_CHANNELS_MASK;
- channel->ctrl |= FORTE_STEREO;
- channel-> stereo = stereo;
- ret = stereo;
- break;
-
- default:
- DPRINTK ("Unsupported channel format");
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-
-/**
- * forte_channel_buffer:
- * @channel: Channel whose buffer to set up
- *
- * Locking: Must be called with lock held.
- */
-
-static void
-forte_channel_buffer (struct forte_channel *channel, int sz, int num)
-{
- unsigned int msecs, shift;
-
- /* Go away, I'm busy */
- if (channel->filled_frags || channel->bytes)
- return;
-
- /* Fragment size must be a power of 2 */
- shift = 0; sz++;
- while (sz >>= 1)
- shift++;
- channel->frag_sz = 1 << shift;
-
- /* Round fragment size to something reasonable */
- if (channel->frag_sz < FORTE_MIN_FRAG_SIZE)
- channel->frag_sz = FORTE_MIN_FRAG_SIZE;
-
- if (channel->frag_sz > FORTE_MAX_FRAG_SIZE)
- channel->frag_sz = FORTE_MAX_FRAG_SIZE;
-
- /* Find fragment length in milliseconds */
- msecs = channel->frag_sz /
- (channel->format == AFMT_S16_LE ? 2 : 1) /
- (channel->stereo ? 2 : 1) /
- (channel->rate / 1000);
-
- channel->frag_msecs = msecs;
-
- /* Pick a suitable number of fragments */
- if (msecs * num < FORTE_MIN_BUF_MSECS)
- num = FORTE_MIN_BUF_MSECS / msecs;
-
- if (msecs * num > FORTE_MAX_BUF_MSECS)
- num = FORTE_MAX_BUF_MSECS / msecs;
-
- /* Fragment number must be a power of 2 */
- shift = 0;
- while (num >>= 1)
- shift++;
- channel->frag_num = 1 << (shift + 1);
-
- /* Round fragment number to something reasonable */
- if (channel->frag_num < FORTE_MIN_FRAGMENTS)
- channel->frag_num = FORTE_MIN_FRAGMENTS;
-
- if (channel->frag_num > FORTE_MAX_FRAGMENTS)
- channel->frag_num = FORTE_MAX_FRAGMENTS;
-
- channel->buf_sz = channel->frag_sz * channel->frag_num;
-
- DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d\n",
- __FUNCTION__, channel->name, channel->frag_sz,
- channel->frag_num, channel->buf_sz);
-}
-
-
-/**
- * forte_channel_prep:
- * @channel: Channel whose buffer to prepare
- *
- * Locking: Lock held.
- */
-
-static void
-forte_channel_prep (struct forte_channel *channel)
-{
- struct page *page;
- int i;
-
- if (channel->buf)
- return;
-
- forte_channel_buffer (channel, channel->frag_sz, channel->frag_num);
- channel->buf_pages = channel->buf_sz >> PAGE_SHIFT;
-
- if (channel->buf_sz % PAGE_SIZE)
- channel->buf_pages++;
-
- DPRINTK ("%s: %s frag_sz = %d, frag_num = %d, buf_sz = %d, pg = %d\n",
- __FUNCTION__, channel->name, channel->frag_sz,
- channel->frag_num, channel->buf_sz, channel->buf_pages);
-
- /* DMA buffer */
- channel->buf = pci_alloc_consistent (forte->pci_dev,
- channel->buf_pages * PAGE_SIZE,
- &channel->buf_handle);
-
- if (!channel->buf || !channel->buf_handle)
- BUG();
-
- page = virt_to_page (channel->buf);
-
- /* FIXME: can this go away ? */
- for (i = 0 ; i < channel->buf_pages ; i++)
- SetPageReserved(page++);
-
- /* Prep buffer registers */
- outw (channel->frag_sz - 1, channel->iobase + FORTE_PLY_COUNT);
- outl (channel->buf_handle, channel->iobase + FORTE_PLY_BUF1);
- outl (channel->buf_handle + channel->frag_sz,
- channel->iobase + FORTE_PLY_BUF2);
-
- /* Reset hwptr */
- channel->hwptr = channel->frag_sz;
- channel->next_buf = 1;
-
- DPRINTK ("%s: %s buffer @ %p (%p)\n", __FUNCTION__, channel->name,
- channel->buf, channel->buf_handle);
-}
-
-
-/**
- * forte_channel_drain:
- * @chip:
- * @channel:
- *
- * Locking: Don't hold the lock.
- */
-
-static inline int
-forte_channel_drain (struct forte_channel *channel)
-{
- DECLARE_WAITQUEUE (wait, current);
- unsigned long flags;
-
- DPRINTK ("%s\n", __FUNCTION__);
-
- if (channel->mapped) {
- spin_lock_irqsave (&forte->lock, flags);
- forte_channel_stop (channel);
- spin_unlock_irqrestore (&forte->lock, flags);
- return 0;
- }
-
- spin_lock_irqsave (&forte->lock, flags);
- add_wait_queue (&channel->wait, &wait);
-
- for (;;) {
- if (channel->active == 0 || channel->filled_frags == 1)
- break;
-
- spin_unlock_irqrestore (&forte->lock, flags);
-
- __set_current_state (TASK_INTERRUPTIBLE);
- schedule();
-
- spin_lock_irqsave (&forte->lock, flags);
- }
-
- forte_channel_stop (channel);
- forte_channel_reset (channel);
- set_current_state (TASK_RUNNING);
- remove_wait_queue (&channel->wait, &wait);
- spin_unlock_irqrestore (&forte->lock, flags);
-
- return 0;
-}
-
-
-/**
- * forte_channel_init:
- * @chip: Forte chip instance the channel hangs off
- * @channel: Channel to initialize
- *
- * Description:
- * Initializes a channel, sets defaults, and allocates
- * buffers.
- *
- * Locking: No lock held.
- */
-
-static int
-forte_channel_init (struct forte_chip *chip, struct forte_channel *channel)
-{
- DPRINTK ("%s: chip iobase @ %p\n", __FUNCTION__, (void *)chip->iobase);
-
- spin_lock_irq (&chip->lock);
- memset (channel, 0x0, sizeof (*channel));
-
- if (channel == &chip->play) {
- channel->name = "PCM_OUT";
- channel->iobase = chip->iobase;
- DPRINTK ("%s: PCM-OUT iobase @ %p\n", __FUNCTION__,
- (void *) channel->iobase);
- }
- else if (channel == &chip->rec) {
- channel->name = "PCM_IN";
- channel->iobase = chip->iobase + FORTE_CAP_OFFSET;
- channel->record = 1;
- DPRINTK ("%s: PCM-IN iobase @ %p\n", __FUNCTION__,
- (void *) channel->iobase);
- }
- else
- BUG();
-
- init_waitqueue_head (&channel->wait);
-
- /* Defaults: 48kHz, 16-bit, stereo */
- channel->ctrl = inw (channel->iobase + FORTE_PLY_CTRL);
- forte_channel_reset (channel);
- forte_channel_stereo (channel, 1);
- forte_channel_format (channel, AFMT_S16_LE);
- forte_channel_rate (channel, 48000);
- channel->frag_sz = FORTE_DEF_FRAG_SIZE;
- channel->frag_num = FORTE_DEF_FRAGMENTS;
-
- chip->trigger = 0;
- spin_unlock_irq (&chip->lock);
-
- return 0;
-}
-
-
-/**
- * forte_channel_free:
- * @chip: Chip this channel hangs off
- * @channel: Channel to nuke
- *
- * Description:
- * Resets channel and frees buffers.
- *
- * Locking: Hold your horses.
- */
-
-static void
-forte_channel_free (struct forte_chip *chip, struct forte_channel *channel)
-{
- DPRINTK ("%s: %s\n", __FUNCTION__, channel->name);
-
- if (!channel->buf_handle)
- return;
-
- pci_free_consistent (chip->pci_dev, channel->buf_pages * PAGE_SIZE,
- channel->buf, channel->buf_handle);
-
- memset (channel, 0x0, sizeof (*channel));
-}
-
-
-/* DSP --------------------------------------------------------------------- */
-
-
-/**
- * forte_dsp_ioctl:
- */
-
-static int
-forte_dsp_ioctl (struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- int ival=0, ret, rval=0, rd, wr, count;
- struct forte_chip *chip;
- struct audio_buf_info abi;
- struct count_info cinfo;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- chip = file->private_data;
-
- if (file->f_mode & FMODE_WRITE)
- wr = 1;
- else
- wr = 0;
-
- if (file->f_mode & FMODE_READ)
- rd = 1;
- else
- rd = 0;
-
- switch (cmd) {
-
- case OSS_GETVERSION:
- return put_user (SOUND_VERSION, p);
-
- case SNDCTL_DSP_GETCAPS:
- DPRINTK ("%s: GETCAPS\n", __FUNCTION__);
-
- ival = FORTE_CAPS; /* DUPLEX */
- return put_user (ival, p);
-
- case SNDCTL_DSP_GETFMTS:
- DPRINTK ("%s: GETFMTS\n", __FUNCTION__);
-
- ival = FORTE_FMTS; /* U8, 16LE */
- return put_user (ival, p);
-
- case SNDCTL_DSP_SETFMT: /* U8, 16LE */
- DPRINTK ("%s: SETFMT\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_format (&chip->rec, ival);
- }
-
- if (wr) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_format (&chip->play, ival);
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (rval, p);
-
- case SNDCTL_DSP_STEREO: /* 0 - mono, 1 - stereo */
- DPRINTK ("%s: STEREO\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_stereo (&chip->rec, ival);
- }
-
- if (wr) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_stereo (&chip->play, ival);
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (rval, p);
-
- case SNDCTL_DSP_CHANNELS: /* 1 - mono, 2 - stereo */
- DPRINTK ("%s: CHANNELS\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_stereo (&chip->rec, ival-1) + 1;
- }
-
- if (wr) {
- forte_channel_stop (&chip->play);
- rval = forte_channel_stereo (&chip->play, ival-1) + 1;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (rval, p);
-
- case SNDCTL_DSP_SPEED:
- DPRINTK ("%s: SPEED\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_stop (&chip->rec);
- rval = forte_channel_rate (&chip->rec, ival);
- }
-
- if (wr) {
- forte_channel_stop (&chip->play);
- rval = forte_channel_rate (&chip->play, ival);
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user(rval, p);
-
- case SNDCTL_DSP_GETBLKSIZE:
- DPRINTK ("%s: GETBLKSIZE\n", __FUNCTION__);
-
- spin_lock_irq (&chip->lock);
-
- if (rd)
- ival = chip->rec.frag_sz;
-
- if (wr)
- ival = chip->play.frag_sz;
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (ival, p);
-
- case SNDCTL_DSP_RESET:
- DPRINTK ("%s: RESET\n", __FUNCTION__);
-
- spin_lock_irq (&chip->lock);
-
- if (rd)
- forte_channel_reset (&chip->rec);
-
- if (wr)
- forte_channel_reset (&chip->play);
-
- spin_unlock_irq (&chip->lock);
-
- return 0;
-
- case SNDCTL_DSP_SYNC:
- DPRINTK ("%s: SYNC\n", __FUNCTION__);
-
- if (wr)
- ret = forte_channel_drain (&chip->play);
-
- return 0;
-
- case SNDCTL_DSP_POST:
- DPRINTK ("%s: POST\n", __FUNCTION__);
-
- if (wr) {
- spin_lock_irq (&chip->lock);
-
- if (chip->play.filled_frags)
- forte_channel_start (&chip->play);
-
- spin_unlock_irq (&chip->lock);
- }
-
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- DPRINTK ("%s: SETFRAGMENT\n", __FUNCTION__);
-
- if (get_user (ival, p))
- return -EFAULT;
-
- spin_lock_irq (&chip->lock);
-
- if (rd) {
- forte_channel_buffer (&chip->rec, ival & 0xffff,
- (ival >> 16) & 0xffff);
- ival = (chip->rec.frag_num << 16) + chip->rec.frag_sz;
- }
-
- if (wr) {
- forte_channel_buffer (&chip->play, ival & 0xffff,
- (ival >> 16) & 0xffff);
- ival = (chip->play.frag_num << 16) +chip->play.frag_sz;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (ival, p);
-
- case SNDCTL_DSP_GETISPACE:
- DPRINTK ("%s: GETISPACE\n", __FUNCTION__);
-
- if (!rd)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- abi.fragstotal = chip->rec.frag_num;
- abi.fragsize = chip->rec.frag_sz;
-
- if (chip->rec.mapped) {
- abi.fragments = chip->rec.frag_num - 2;
- abi.bytes = abi.fragments * abi.fragsize;
- }
- else {
- abi.fragments = chip->rec.filled_frags;
- abi.bytes = abi.fragments * abi.fragsize;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETIPTR:
- DPRINTK ("%s: GETIPTR\n", __FUNCTION__);
-
- if (!rd)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- if (chip->rec.active)
- cinfo.ptr = chip->rec.hwptr;
- else
- cinfo.ptr = 0;
-
- cinfo.bytes = chip->rec.bytes;
- cinfo.blocks = chip->rec.nr_irqs;
- chip->rec.nr_irqs = 0;
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!wr)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- abi.fragstotal = chip->play.frag_num;
- abi.fragsize = chip->play.frag_sz;
-
- if (chip->play.mapped) {
- abi.fragments = chip->play.frag_num - 2;
- abi.bytes = chip->play.buf_sz;
- }
- else {
- abi.fragments = chip->play.frag_num -
- chip->play.filled_frags;
-
- if (chip->play.residue)
- abi.fragments--;
-
- abi.bytes = abi.fragments * abi.fragsize +
- chip->play.residue;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &abi, sizeof (abi)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!wr)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- if (chip->play.active)
- cinfo.ptr = chip->play.hwptr;
- else
- cinfo.ptr = 0;
-
- cinfo.bytes = chip->play.bytes;
- cinfo.blocks = chip->play.nr_irqs;
- chip->play.nr_irqs = 0;
-
- spin_unlock_irq (&chip->lock);
-
- return copy_to_user (argp, &cinfo, sizeof (cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!wr)
- return -EINVAL;
-
- spin_lock_irq (&chip->lock);
-
- if (!chip->play.active) {
- ival = 0;
- }
- else if (chip->play.mapped) {
- count = inw (chip->play.iobase + FORTE_PLY_COUNT) + 1;
- ival = chip->play.frag_sz - count;
- }
- else {
- ival = chip->play.filled_frags * chip->play.frag_sz;
-
- if (chip->play.residue)
- ival += chip->play.frag_sz - chip->play.residue;
- }
-
- spin_unlock_irq (&chip->lock);
-
- return put_user (ival, p);
-
- case SNDCTL_DSP_SETDUPLEX:
- DPRINTK ("%s: SETDUPLEX\n", __FUNCTION__);
-
- return -EINVAL;
-
- case SNDCTL_DSP_GETTRIGGER:
- DPRINTK ("%s: GETTRIGGER\n", __FUNCTION__);
-
- return put_user (chip->trigger, p);
-
- case SNDCTL_DSP_SETTRIGGER:
-
- if (get_user (ival, p))
- return -EFAULT;
-
- DPRINTK ("%s: SETTRIGGER %d\n", __FUNCTION__, ival);
-
- if (wr) {
- spin_lock_irq (&chip->lock);
-
- if (ival & PCM_ENABLE_OUTPUT)
- forte_channel_start (&chip->play);
- else {
- chip->trigger = 1;
- forte_channel_prep (&chip->play);
- forte_channel_stop (&chip->play);
- }
-
- spin_unlock_irq (&chip->lock);
- }
- else if (rd) {
- spin_lock_irq (&chip->lock);
-
- if (ival & PCM_ENABLE_INPUT)
- forte_channel_start (&chip->rec);
- else {
- chip->trigger = 1;
- forte_channel_prep (&chip->rec);
- forte_channel_stop (&chip->rec);
- }
-
- spin_unlock_irq (&chip->lock);
- }
-
- return 0;
-
- case SOUND_PCM_READ_RATE:
- DPRINTK ("%s: PCM_READ_RATE\n", __FUNCTION__);
- return put_user (chip->play.rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- DPRINTK ("%s: PCM_READ_CHANNELS\n", __FUNCTION__);
- return put_user (chip->play.stereo, p);
-
- case SOUND_PCM_READ_BITS:
- DPRINTK ("%s: PCM_READ_BITS\n", __FUNCTION__);
- return put_user (chip->play.format, p);
-
- case SNDCTL_DSP_NONBLOCK:
- DPRINTK ("%s: DSP_NONBLOCK\n", __FUNCTION__);
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- default:
- DPRINTK ("Unsupported ioctl: %x (%p)\n", cmd, argp);
- break;
- }
-
- return -EINVAL;
-}
-
-
-/**
- * forte_dsp_open:
- */
-
-static int
-forte_dsp_open (struct inode *inode, struct file *file)
-{
- struct forte_chip *chip = forte; /* FIXME: HACK FROM HELL! */
-
- if (file->f_flags & O_NONBLOCK) {
- if (!mutex_trylock(&chip->open_mutex)) {
- DPRINTK ("%s: returning -EAGAIN\n", __FUNCTION__);
- return -EAGAIN;
- }
- }
- else {
- if (mutex_lock_interruptible(&chip->open_mutex)) {
- DPRINTK ("%s: returning -ERESTARTSYS\n", __FUNCTION__);
- return -ERESTARTSYS;
- }
- }
-
- file->private_data = forte;
-
- DPRINTK ("%s: dsp opened by %d\n", __FUNCTION__, current->pid);
-
- if (file->f_mode & FMODE_WRITE)
- forte_channel_init (forte, &forte->play);
-
- if (file->f_mode & FMODE_READ)
- forte_channel_init (forte, &forte->rec);
-
- return nonseekable_open(inode, file);
-}
-
-
-/**
- * forte_dsp_release:
- */
-
-static int
-forte_dsp_release (struct inode *inode, struct file *file)
-{
- struct forte_chip *chip = file->private_data;
- int ret = 0;
-
- DPRINTK ("%s: chip @ %p\n", __FUNCTION__, chip);
-
- if (file->f_mode & FMODE_WRITE) {
- forte_channel_drain (&chip->play);
-
- spin_lock_irq (&chip->lock);
-
- forte_channel_free (chip, &chip->play);
-
- spin_unlock_irq (&chip->lock);
- }
-
- if (file->f_mode & FMODE_READ) {
- while (chip->rec.filled_frags > 0)
- interruptible_sleep_on (&chip->rec.wait);
-
- spin_lock_irq (&chip->lock);
-
- forte_channel_stop (&chip->rec);
- forte_channel_free (chip, &chip->rec);
-
- spin_unlock_irq (&chip->lock);
- }
-
- mutex_unlock(&chip->open_mutex);
-
- return ret;
-}
-
-
-/**
- * forte_dsp_poll:
- *
- */
-
-static unsigned int
-forte_dsp_poll (struct file *file, struct poll_table_struct *wait)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned int mask = 0;
-
- chip = file->private_data;
-
- if (file->f_mode & FMODE_WRITE) {
- channel = &chip->play;
-
- if (channel->active)
- poll_wait (file, &channel->wait, wait);
-
- spin_lock_irq (&chip->lock);
-
- if (channel->frag_num - channel->filled_frags > 0)
- mask |= POLLOUT | POLLWRNORM;
-
- spin_unlock_irq (&chip->lock);
- }
-
- if (file->f_mode & FMODE_READ) {
- channel = &chip->rec;
-
- if (channel->active)
- poll_wait (file, &channel->wait, wait);
-
- spin_lock_irq (&chip->lock);
-
- if (channel->filled_frags > 0)
- mask |= POLLIN | POLLRDNORM;
-
- spin_unlock_irq (&chip->lock);
- }
-
- return mask;
-}
-
-
-/**
- * forte_dsp_mmap:
- */
-
-static int
-forte_dsp_mmap (struct file *file, struct vm_area_struct *vma)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned long size;
- int ret;
-
- chip = file->private_data;
-
- DPRINTK ("%s: start %lXh, size %ld, pgoff %ld\n", __FUNCTION__,
- vma->vm_start, vma->vm_end - vma->vm_start, vma->vm_pgoff);
-
- spin_lock_irq (&chip->lock);
-
- if (vma->vm_flags & VM_WRITE && chip->play.active) {
- ret = -EBUSY;
- goto out;
- }
-
- if (vma->vm_flags & VM_READ && chip->rec.active) {
- ret = -EBUSY;
- goto out;
- }
-
- if (file->f_mode & FMODE_WRITE)
- channel = &chip->play;
- else if (file->f_mode & FMODE_READ)
- channel = &chip->rec;
- else {
- ret = -EINVAL;
- goto out;
- }
-
- forte_channel_prep (channel);
- channel->mapped = 1;
-
- if (vma->vm_pgoff != 0) {
- ret = -EINVAL;
- goto out;
- }
-
- size = vma->vm_end - vma->vm_start;
-
- if (size > channel->buf_pages * PAGE_SIZE) {
- DPRINTK ("%s: size (%ld) > buf_sz (%d) \n", __FUNCTION__,
- size, channel->buf_sz);
- ret = -EINVAL;
- goto out;
- }
-
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(channel->buf) >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
- DPRINTK ("%s: remap el a no worko\n", __FUNCTION__);
- ret = -EAGAIN;
- goto out;
- }
-
- ret = 0;
-
- out:
- spin_unlock_irq (&chip->lock);
- return ret;
-}
-
-
-/**
- * forte_dsp_write:
- */
-
-static ssize_t
-forte_dsp_write (struct file *file, const char __user *buffer, size_t bytes,
- loff_t *ppos)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned int i = bytes, sz = 0;
- unsigned long flags;
-
- if (!access_ok (VERIFY_READ, buffer, bytes))
- return -EFAULT;
-
- chip = (struct forte_chip *) file->private_data;
-
- if (!chip)
- BUG();
-
- channel = &chip->play;
-
- if (!channel)
- BUG();
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Set up buffers with the right fragment size */
- forte_channel_prep (channel);
-
- while (i) {
- /* All fragment buffers in use -> wait */
- if (channel->frag_num - channel->filled_frags == 0) {
- DECLARE_WAITQUEUE (wait, current);
-
- /* For trigger or non-blocking operation, get out */
- if (chip->trigger || file->f_flags & O_NONBLOCK) {
- spin_unlock_irqrestore (&chip->lock, flags);
- return -EAGAIN;
- }
-
- /* Otherwise wait for buffers */
- add_wait_queue (&channel->wait, &wait);
-
- for (;;) {
- spin_unlock_irqrestore (&chip->lock, flags);
-
- set_current_state (TASK_INTERRUPTIBLE);
- schedule();
-
- spin_lock_irqsave (&chip->lock, flags);
-
- if (channel->frag_num - channel->filled_frags)
- break;
- }
-
- remove_wait_queue (&channel->wait, &wait);
- set_current_state (TASK_RUNNING);
-
- if (signal_pending (current)) {
- spin_unlock_irqrestore (&chip->lock, flags);
- return -ERESTARTSYS;
- }
- }
-
- if (channel->residue)
- sz = channel->residue;
- else if (i > channel->frag_sz)
- sz = channel->frag_sz;
- else
- sz = i;
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- if (copy_from_user ((void *) channel->buf + channel->swptr, buffer, sz))
- return -EFAULT;
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Advance software pointer */
- buffer += sz;
- channel->swptr += sz;
- channel->swptr %= channel->buf_sz;
- i -= sz;
-
- /* Only bump filled_frags if a full fragment has been written */
- if (channel->swptr % channel->frag_sz == 0) {
- channel->filled_frags++;
- channel->residue = 0;
- }
- else
- channel->residue = channel->frag_sz - sz;
-
- /* If playback isn't active, start it */
- if (channel->active == 0 && chip->trigger == 0)
- forte_channel_start (channel);
- }
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- return bytes - i;
-}
-
-
-/**
- * forte_dsp_read:
- */
-
-static ssize_t
-forte_dsp_read (struct file *file, char __user *buffer, size_t bytes,
- loff_t *ppos)
-{
- struct forte_chip *chip;
- struct forte_channel *channel;
- unsigned int i = bytes, sz;
- unsigned long flags;
-
- if (!access_ok (VERIFY_WRITE, buffer, bytes))
- return -EFAULT;
-
- chip = (struct forte_chip *) file->private_data;
-
- if (!chip)
- BUG();
-
- channel = &chip->rec;
-
- if (!channel)
- BUG();
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Set up buffers with the right fragment size */
- forte_channel_prep (channel);
-
- /* Start recording */
- if (!chip->trigger)
- forte_channel_start (channel);
-
- while (i) {
- /* No fragment buffers in use -> wait */
- if (channel->filled_frags == 0) {
- DECLARE_WAITQUEUE (wait, current);
-
- /* For trigger mode operation, get out */
- if (chip->trigger) {
- spin_unlock_irqrestore (&chip->lock, flags);
- return -EAGAIN;
- }
-
- add_wait_queue (&channel->wait, &wait);
-
- for (;;) {
- if (channel->active == 0)
- break;
-
- if (channel->filled_frags)
- break;
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- set_current_state (TASK_INTERRUPTIBLE);
- schedule();
-
- spin_lock_irqsave (&chip->lock, flags);
- }
-
- set_current_state (TASK_RUNNING);
- remove_wait_queue (&channel->wait, &wait);
- }
-
- if (i > channel->frag_sz)
- sz = channel->frag_sz;
- else
- sz = i;
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- if (copy_to_user (buffer, (void *)channel->buf+channel->swptr, sz)) {
- DPRINTK ("%s: copy_to_user failed\n", __FUNCTION__);
- return -EFAULT;
- }
-
- spin_lock_irqsave (&chip->lock, flags);
-
- /* Advance software pointer */
- buffer += sz;
- if (channel->filled_frags > 0)
- channel->filled_frags--;
- channel->swptr += channel->frag_sz;
- channel->swptr %= channel->buf_sz;
- i -= sz;
- }
-
- spin_unlock_irqrestore (&chip->lock, flags);
-
- return bytes - i;
-}
-
-
-static struct file_operations forte_dsp_fops = {
- .owner = THIS_MODULE,
- .llseek = &no_llseek,
- .read = &forte_dsp_read,
- .write = &forte_dsp_write,
- .poll = &forte_dsp_poll,
- .ioctl = &forte_dsp_ioctl,
- .open = &forte_dsp_open,
- .release = &forte_dsp_release,
- .mmap = &forte_dsp_mmap,
-};
-
-
-/* Common ------------------------------------------------------------------ */
-
-
-/**
- * forte_interrupt:
- */
-
-static irqreturn_t
-forte_interrupt (int irq, void *dev_id, struct pt_regs *regs)
-{
- struct forte_chip *chip = dev_id;
- struct forte_channel *channel = NULL;
- u16 status, count;
-
- status = inw (chip->iobase + FORTE_IRQ_STATUS);
-
- /* If this is not for us, get outta here ASAP */
- if ((status & (FORTE_IRQ_PLAYBACK | FORTE_IRQ_CAPTURE)) == 0)
- return IRQ_NONE;
-
- if (status & FORTE_IRQ_PLAYBACK) {
- channel = &chip->play;
-
- spin_lock (&chip->lock);
-
- if (channel->frag_sz == 0)
- goto pack;
-
- /* Declare a fragment done */
- if (channel->filled_frags > 0)
- channel->filled_frags--;
- channel->bytes += channel->frag_sz;
- channel->nr_irqs++;
-
- /* Flip-flop between buffer I and II */
- channel->next_buf ^= 1;
-
- /* Advance hardware pointer by fragment size and wrap around */
- channel->hwptr += channel->frag_sz;
- channel->hwptr %= channel->buf_sz;
-
- /* Buffer I or buffer II BAR */
- outl (channel->buf_handle + channel->hwptr,
- channel->next_buf == 0 ?
- channel->iobase + FORTE_PLY_BUF1 :
- channel->iobase + FORTE_PLY_BUF2);
-
- /* If the currently playing fragment is last, schedule pause */
- if (channel->filled_frags == 1)
- forte_channel_pause (channel);
-
- pack:
- /* Acknowledge interrupt */
- outw (FORTE_IRQ_PLAYBACK, chip->iobase + FORTE_IRQ_STATUS);
-
- if (waitqueue_active (&channel->wait))
- wake_up_all (&channel->wait);
-
- spin_unlock (&chip->lock);
- }
-
- if (status & FORTE_IRQ_CAPTURE) {
- channel = &chip->rec;
- spin_lock (&chip->lock);
-
- /* One fragment filled */
- channel->filled_frags++;
-
- /* Get # of completed bytes */
- count = inw (channel->iobase + FORTE_PLY_COUNT) + 1;
-
- if (count == 0) {
- DPRINTK ("%s: last, filled_frags = %d\n", __FUNCTION__,
- channel->filled_frags);
- channel->filled_frags = 0;
- goto rack;
- }
-
- /* Buffer I or buffer II BAR */
- outl (channel->buf_handle + channel->hwptr,
- channel->next_buf == 0 ?
- channel->iobase + FORTE_PLY_BUF1 :
- channel->iobase + FORTE_PLY_BUF2);
-
- /* Flip-flop between buffer I and II */
- channel->next_buf ^= 1;
-
- /* Advance hardware pointer by fragment size and wrap around */
- channel->hwptr += channel->frag_sz;
- channel->hwptr %= channel->buf_sz;
-
- /* Out of buffers */
- if (channel->filled_frags == channel->frag_num - 1)
- forte_channel_stop (channel);
- rack:
- /* Acknowledge interrupt */
- outw (FORTE_IRQ_CAPTURE, chip->iobase + FORTE_IRQ_STATUS);
-
- spin_unlock (&chip->lock);
-
- if (waitqueue_active (&channel->wait))
- wake_up_all (&channel->wait);
- }
-
- return IRQ_HANDLED;
-}
-
-
-/**
- * forte_proc_read:
- */
-
-static int
-forte_proc_read (char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int i = 0, p_rate, p_chan, r_rate;
- unsigned short p_reg, r_reg;
-
- i += sprintf (page, "ForteMedia FM801 OSS Lite driver\n%s\n \n",
- DRIVER_VERSION);
-
- if (!forte->iobase)
- return i;
-
- p_rate = p_chan = -1;
- p_reg = inw (forte->iobase + FORTE_PLY_CTRL);
- p_rate = (p_reg >> 8) & 15;
- p_chan = (p_reg >> 12) & 3;
-
- if (p_rate >= 0 || p_rate <= 10)
- p_rate = rates[p_rate];
-
- if (p_chan >= 0 || p_chan <= 2)
- p_chan = channels[p_chan];
-
- r_rate = -1;
- r_reg = inw (forte->iobase + FORTE_CAP_CTRL);
- r_rate = (r_reg >> 8) & 15;
-
- if (r_rate >= 0 || r_rate <= 10)
- r_rate = rates[r_rate];
-
- i += sprintf (page + i,
- " Playback Capture\n"
- "FIFO empty : %-3s %-3s\n"
- "Buf1 Last : %-3s %-3s\n"
- "Buf2 Last : %-3s %-3s\n"
- "Started : %-3s %-3s\n"
- "Paused : %-3s %-3s\n"
- "Immed Stop : %-3s %-3s\n"
- "Rate : %-5d %-5d\n"
- "Channels : %-5d -\n"
- "16-bit : %-3s %-3s\n"
- "Stereo : %-3s %-3s\n"
- " \n"
- "Buffer Sz : %-6d %-6d\n"
- "Frag Sz : %-6d %-6d\n"
- "Frag Num : %-6d %-6d\n"
- "Frag msecs : %-6d %-6d\n"
- "Used Frags : %-6d %-6d\n"
- "Mapped : %-3s %-3s\n",
- p_reg & 1<<0 ? "yes" : "no",
- r_reg & 1<<0 ? "yes" : "no",
- p_reg & 1<<1 ? "yes" : "no",
- r_reg & 1<<1 ? "yes" : "no",
- p_reg & 1<<2 ? "yes" : "no",
- r_reg & 1<<2 ? "yes" : "no",
- p_reg & 1<<5 ? "yes" : "no",
- r_reg & 1<<5 ? "yes" : "no",
- p_reg & 1<<6 ? "yes" : "no",
- r_reg & 1<<6 ? "yes" : "no",
- p_reg & 1<<7 ? "yes" : "no",
- r_reg & 1<<7 ? "yes" : "no",
- p_rate, r_rate,
- p_chan,
- p_reg & 1<<14 ? "yes" : "no",
- r_reg & 1<<14 ? "yes" : "no",
- p_reg & 1<<15 ? "yes" : "no",
- r_reg & 1<<15 ? "yes" : "no",
- forte->play.buf_sz, forte->rec.buf_sz,
- forte->play.frag_sz, forte->rec.frag_sz,
- forte->play.frag_num, forte->rec.frag_num,
- forte->play.frag_msecs, forte->rec.frag_msecs,
- forte->play.filled_frags, forte->rec.filled_frags,
- forte->play.mapped ? "yes" : "no",
- forte->rec.mapped ? "yes" : "no"
- );
-
- return i;
-}
-
-
-/**
- * forte_proc_init:
- *
- * Creates driver info entries in /proc
- */
-
-static int __init
-forte_proc_init (void)
-{
- if (!proc_mkdir ("driver/forte", NULL))
- return -EIO;
-
- if (!create_proc_read_entry ("driver/forte/chip", 0, NULL, forte_proc_read, forte)) {
- remove_proc_entry ("driver/forte", NULL);
- return -EIO;
- }
-
- if (!create_proc_read_entry("driver/forte/ac97", 0, NULL, ac97_read_proc, forte->ac97)) {
- remove_proc_entry ("driver/forte/chip", NULL);
- remove_proc_entry ("driver/forte", NULL);
- return -EIO;
- }
-
- return 0;
-}
-
-
-/**
- * forte_proc_remove:
- *
- * Removes driver info entries in /proc
- */
-
-static void
-forte_proc_remove (void)
-{
- remove_proc_entry ("driver/forte/ac97", NULL);
- remove_proc_entry ("driver/forte/chip", NULL);
- remove_proc_entry ("driver/forte", NULL);
-}
-
-
-/**
- * forte_chip_init:
- * @chip: Chip instance to initialize
- *
- * Description:
- * Resets chip, configures codec and registers the driver with
- * the sound subsystem.
- *
- * Press and hold Start for 8 secs, then switch on Run
- * and hold for 4 seconds. Let go of Start. Numbers
- * assume a properly oiled TWG.
- */
-
-static int __devinit
-forte_chip_init (struct forte_chip *chip)
-{
- u8 revision;
- u16 cmdw;
- struct ac97_codec *codec;
-
- pci_read_config_byte (chip->pci_dev, PCI_REVISION_ID, &revision);
-
- if (revision >= 0xB1) {
- chip->multichannel = 1;
- printk (KERN_INFO PFX "Multi-channel device detected.\n");
- }
-
- /* Reset chip */
- outw (FORTE_CC_CODEC_RESET | FORTE_CC_AC97_RESET,
- chip->iobase + FORTE_CODEC_CTRL);
- udelay(100);
- outw (0, chip->iobase + FORTE_CODEC_CTRL);
-
- /* Request read from AC97 */
- outw (FORTE_AC97_READ | (0 << FORTE_AC97_ADDR_SHIFT),
- chip->iobase + FORTE_AC97_CMD);
- mdelay(750);
-
- if ((inw (chip->iobase + FORTE_AC97_CMD) & (3<<8)) != (1<<8)) {
- printk (KERN_INFO PFX "AC97 codec not responding");
- return -EIO;
- }
-
- /* Init volume */
- outw (0x0808, chip->iobase + FORTE_PCM_VOL);
- outw (0x9f1f, chip->iobase + FORTE_FM_VOL);
- outw (0x8808, chip->iobase + FORTE_I2S_VOL);
-
- /* I2S control - I2S mode */
- outw (0x0003, chip->iobase + FORTE_I2S_MODE);
-
- /* Interrupt setup - unmask PLAYBACK & CAPTURE */
- cmdw = inw (chip->iobase + FORTE_IRQ_MASK);
- cmdw &= ~0x0003;
- outw (cmdw, chip->iobase + FORTE_IRQ_MASK);
-
- /* Interrupt clear */
- outw (FORTE_IRQ_PLAYBACK|FORTE_IRQ_CAPTURE,
- chip->iobase + FORTE_IRQ_STATUS);
-
- /* Set up the AC97 codec */
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
- codec->private_data = chip;
- codec->codec_read = forte_ac97_read;
- codec->codec_write = forte_ac97_write;
- codec->id = 0;
-
- if (ac97_probe_codec (codec) == 0) {
- printk (KERN_ERR PFX "codec probe failed\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- /* Register mixer */
- if ((codec->dev_mixer =
- register_sound_mixer (&forte_mixer_fops, -1)) < 0) {
- printk (KERN_ERR PFX "couldn't register mixer!\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- chip->ac97 = codec;
-
- /* Register DSP */
- if ((chip->dsp = register_sound_dsp (&forte_dsp_fops, -1) ) < 0) {
- printk (KERN_ERR PFX "couldn't register dsp!\n");
- return -1;
- }
-
- /* Register with /proc */
- if (forte_proc_init()) {
- printk (KERN_ERR PFX "couldn't add entries to /proc!\n");
- return -1;
- }
-
- return 0;
-}
-
-
-/**
- * forte_probe:
- * @pci_dev: PCI struct for probed device
- * @pci_id:
- *
- * Description:
- * Allocates chip instance, I/O region, and IRQ
- */
-static int __init
-forte_probe (struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- struct forte_chip *chip;
- int ret = 0;
-
- /* FIXME: Support more than one chip */
- if (found++)
- return -EIO;
-
- /* Ignition */
- if (pci_enable_device (pci_dev))
- return -EIO;
-
- pci_set_master (pci_dev);
-
- /* Allocate chip instance and configure */
- forte = (struct forte_chip *)
- kmalloc (sizeof (struct forte_chip), GFP_KERNEL);
- chip = forte;
-
- if (chip == NULL) {
- printk (KERN_WARNING PFX "Out of memory");
- return -ENOMEM;
- }
-
- memset (chip, 0, sizeof (struct forte_chip));
- chip->pci_dev = pci_dev;
-
- mutex_init(&chip->open_mutex);
- spin_lock_init (&chip->lock);
- spin_lock_init (&chip->ac97_lock);
-
- if (! request_region (pci_resource_start (pci_dev, 0),
- pci_resource_len (pci_dev, 0), DRIVER_NAME)) {
- printk (KERN_WARNING PFX "Unable to reserve I/O space");
- ret = -ENOMEM;
- goto error;
- }
-
- chip->iobase = pci_resource_start (pci_dev, 0);
- chip->irq = pci_dev->irq;
-
- if (request_irq (chip->irq, forte_interrupt, IRQF_SHARED, DRIVER_NAME,
- chip)) {
- printk (KERN_WARNING PFX "Unable to reserve IRQ");
- ret = -EIO;
- goto error;
- }
-
- pci_set_drvdata (pci_dev, chip);
-
- printk (KERN_INFO PFX "FM801 chip found at 0x%04lX-0x%16llX IRQ %u\n",
- chip->iobase, (unsigned long long)pci_resource_end (pci_dev, 0),
- chip->irq);
-
- /* Power it up */
- if ((ret = forte_chip_init (chip)) == 0)
- return 0;
-
- error:
- if (chip->irq)
- free_irq (chip->irq, chip);
-
- if (chip->iobase)
- release_region (pci_resource_start (pci_dev, 0),
- pci_resource_len (pci_dev, 0));
-
- kfree (chip);
-
- return ret;
-}
-
-
-/**
- * forte_remove:
- * @pci_dev: PCI device to unclaim
- *
- */
-
-static void
-forte_remove (struct pci_dev *pci_dev)
-{
- struct forte_chip *chip = pci_get_drvdata (pci_dev);
-
- if (chip == NULL)
- return;
-
- /* Turn volume down to avoid popping */
- outw (0x1f1f, chip->iobase + FORTE_PCM_VOL);
- outw (0x1f1f, chip->iobase + FORTE_FM_VOL);
- outw (0x1f1f, chip->iobase + FORTE_I2S_VOL);
-
- forte_proc_remove();
- free_irq (chip->irq, chip);
- release_region (chip->iobase, pci_resource_len (pci_dev, 0));
-
- unregister_sound_dsp (chip->dsp);
- unregister_sound_mixer (chip->ac97->dev_mixer);
- ac97_release_codec(chip->ac97);
- kfree (chip);
-
- printk (KERN_INFO PFX "driver released\n");
-}
-
-
-static struct pci_device_id forte_pci_ids[] = {
- { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, },
- { 0, }
-};
-
-
-static struct pci_driver forte_pci_driver = {
- .name = DRIVER_NAME,
- .id_table = forte_pci_ids,
- .probe = forte_probe,
- .remove = forte_remove,
-
-};
-
-
-/**
- * forte_init_module:
- *
- */
-
-static int __init
-forte_init_module (void)
-{
- printk (KERN_INFO PFX DRIVER_VERSION "\n");
-
- return pci_register_driver (&forte_pci_driver);
-}
-
-
-/**
- * forte_cleanup_module:
- *
- */
-
-static void __exit
-forte_cleanup_module (void)
-{
- pci_unregister_driver (&forte_pci_driver);
-}
-
-
-module_init(forte_init_module);
-module_exit(forte_cleanup_module);
-
-MODULE_AUTHOR("Martin K. Petersen <mkp@mkp.net>");
-MODULE_DESCRIPTION("ForteMedia FM801 OSS Driver");
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE (pci, forte_pci_ids);
diff --git a/sound/oss/gus.h b/sound/oss/gus.h
deleted file mode 100644
index 3d5271baf042..000000000000
--- a/sound/oss/gus.h
+++ /dev/null
@@ -1,24 +0,0 @@
-
-#include "ad1848.h"
-
-/* From gus_card.c */
-int gus_set_midi_irq(int num);
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs * dummy);
-
-/* From gus_wave.c */
-int gus_wave_detect(int baseaddr);
-void gus_wave_init(struct address_info *hw_config);
-void gus_wave_unload (struct address_info *hw_config);
-void gus_voice_irq(void);
-void gus_write8(int reg, unsigned int data);
-void guswave_dma_irq(void);
-void gus_delay(void);
-int gus_default_mixer_ioctl (int dev, unsigned int cmd, void __user *arg);
-void gus_timer_command (unsigned int addr, unsigned int val);
-
-/* From gus_midi.c */
-void gus_midi_init(struct address_info *hw_config);
-void gus_midi_interrupt(int dummy);
-
-/* From ics2101.c */
-int ics2101_mixer_init(void);
diff --git a/sound/oss/gus_card.c b/sound/oss/gus_card.c
deleted file mode 100644
index dbb29771e2bb..000000000000
--- a/sound/oss/gus_card.c
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- * sound/gus_card.c
- *
- * Detection routine for the Gravis Ultrasound.
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- *
- * Frank van de Pol : Fixed GUS MAX interrupt handling, enabled simultanious
- * usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
- * Christoph Hellwig: Adapted to module_init/module_exit, simple cleanups.
- *
- * Status:
- * Tested...
- */
-
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_hw.h"
-
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy);
-
-int gus_base = 0, gus_irq = 0, gus_dma = 0;
-int gus_no_wave_dma = 0;
-extern int gus_wave_volume;
-extern int gus_pcm_volume;
-extern int have_gus_max;
-int gus_pnp_flag = 0;
-#ifdef CONFIG_SOUND_GUS16
-static int db16; /* Has a Gus16 AD1848 on it */
-#endif
-
-static void __init attach_gus(struct address_info *hw_config)
-{
- gus_wave_init(hw_config);
-
- if (sound_alloc_dma(hw_config->dma, "GUS"))
- printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma);
- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
- if (sound_alloc_dma(hw_config->dma2, "GUS(2)"))
- printk(KERN_ERR "gus_card.c: Can't allocate DMA channel %d\n", hw_config->dma2);
- gus_midi_init(hw_config);
- if(request_irq(hw_config->irq, gusintr, 0, "Gravis Ultrasound", hw_config)<0)
- printk(KERN_ERR "gus_card.c: Unable to allocate IRQ %d\n", hw_config->irq);
-
- return;
-}
-
-static int __init probe_gus(struct address_info *hw_config)
-{
- int irq;
- int io_addr;
-
- if (hw_config->card_subtype == 1)
- gus_pnp_flag = 1;
-
- irq = hw_config->irq;
-
- if (hw_config->card_subtype == 0) /* GUS/MAX/ACE */
- if (irq != 3 && irq != 5 && irq != 7 && irq != 9 &&
- irq != 11 && irq != 12 && irq != 15)
- {
- printk(KERN_ERR "GUS: Unsupported IRQ %d\n", irq);
- return 0;
- }
- if (gus_wave_detect(hw_config->io_base))
- return 1;
-
-#ifndef EXCLUDE_GUS_IODETECT
-
- /*
- * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6)
- */
-
- for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) {
- if (io_addr == hw_config->io_base) /* Already tested */
- continue;
- if (gus_wave_detect(io_addr)) {
- hw_config->io_base = io_addr;
- return 1;
- }
- }
-#endif
-
- printk("NO GUS card found !\n");
- return 0;
-}
-
-static void __exit unload_gus(struct address_info *hw_config)
-{
- DDB(printk("unload_gus(%x)\n", hw_config->io_base));
-
- gus_wave_unload(hw_config);
-
- release_region(hw_config->io_base, 16);
- release_region(hw_config->io_base + 0x100, 12); /* 0x10c-> is MAX */
- free_irq(hw_config->irq, hw_config);
-
- sound_free_dma(hw_config->dma);
-
- if (hw_config->dma2 != -1 && hw_config->dma2 != hw_config->dma)
- sound_free_dma(hw_config->dma2);
-}
-
-irqreturn_t gusintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
- unsigned char src;
- extern int gus_timer_enabled;
- int handled = 0;
-
-#ifdef CONFIG_SOUND_GUSMAX
- if (have_gus_max) {
- struct address_info *hw_config = dev_id;
- adintr(irq, (void *)hw_config->slots[1], NULL);
- }
-#endif
-#ifdef CONFIG_SOUND_GUS16
- if (db16) {
- struct address_info *hw_config = dev_id;
- adintr(irq, (void *)hw_config->slots[3], NULL);
- }
-#endif
-
- while (1)
- {
- if (!(src = inb(u_IrqStatus)))
- break;
- handled = 1;
- if (src & DMA_TC_IRQ)
- {
- guswave_dma_irq();
- }
- if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ))
- {
- gus_midi_interrupt(0);
- }
- if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ))
- {
- if (gus_timer_enabled)
- sound_timer_interrupt();
- gus_write8(0x45, 0); /* Ack IRQ */
- gus_timer_command(4, 0x80); /* Reset IRQ flags */
- }
- if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ))
- gus_voice_irq();
- }
- return IRQ_RETVAL(handled);
-}
-
-/*
- * Some extra code for the 16 bit sampling option
- */
-
-#ifdef CONFIG_SOUND_GUS16
-
-static int __init init_gus_db16(struct address_info *hw_config)
-{
- struct resource *ports;
-
- ports = request_region(hw_config->io_base, 4, "ad1848");
- if (!ports)
- return 0;
-
- if (!ad1848_detect(ports, NULL, hw_config->osp)) {
- release_region(hw_config->io_base, 4);
- return 0;
- }
-
- gus_pcm_volume = 100;
- gus_wave_volume = 90;
-
- hw_config->slots[3] = ad1848_init("GUS 16 bit sampling", ports,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma, 0,
- hw_config->osp,
- THIS_MODULE);
- return 1;
-}
-
-static void __exit unload_gus_db16(struct address_info *hw_config)
-{
-
- ad1848_unload(hw_config->io_base,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma, 0);
- sound_unload_audiodev(hw_config->slots[3]);
-}
-#endif
-
-#ifdef CONFIG_SOUND_GUS16
-static int gus16;
-#endif
-#ifdef CONFIG_SOUND_GUSMAX
-static int no_wave_dma; /* Set if no dma is to be used for the
- wave table (GF1 chip) */
-#endif
-
-
-/*
- * Note DMA2 of -1 has the right meaning in the GUS driver as well
- * as here.
- */
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1; /* Set this for modules that need it */
-static int __initdata type = 0; /* 1 for PnP */
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma16, int, 0);
-module_param(type, int, 0);
-#ifdef CONFIG_SOUND_GUSMAX
-module_param(no_wave_dma, int, 0);
-#endif
-#ifdef CONFIG_SOUND_GUS16
-module_param(db16, int, 0);
-module_param(gus16, int, 0);
-#endif
-MODULE_LICENSE("GPL");
-
-static int __init init_gus(void)
-{
- printk(KERN_INFO "Gravis Ultrasound audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma16;
- cfg.card_subtype = type;
-#ifdef CONFIG_SOUND_GUSMAX
- gus_no_wave_dma = no_wave_dma;
-#endif
-
- if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
- printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n");
- return -EINVAL;
- }
-
-#ifdef CONFIG_SOUND_GUS16
- if (gus16 && init_gus_db16(&cfg))
- db16 = 1;
-#endif
- if (!probe_gus(&cfg))
- return -ENODEV;
- attach_gus(&cfg);
-
- return 0;
-}
-
-static void __exit cleanup_gus(void)
-{
-#ifdef CONFIG_SOUND_GUS16
- if (db16)
- unload_gus_db16(&cfg);
-#endif
- unload_gus(&cfg);
-}
-
-module_init(init_gus);
-module_exit(cleanup_gus);
-
-#ifndef MODULE
-static int __init setup_gus(char *str)
-{
- /* io, irq, dma, dma2 */
- int ints[5];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma16 = ints[4];
-
- return 1;
-}
-
-__setup("gus=", setup_gus);
-#endif
diff --git a/sound/oss/gus_hw.h b/sound/oss/gus_hw.h
deleted file mode 100644
index f97a0b8670e3..000000000000
--- a/sound/oss/gus_hw.h
+++ /dev/null
@@ -1,50 +0,0 @@
-
-/*
- * I/O addresses
- */
-
-#define u_Base (gus_base + 0x000)
-#define u_Mixer u_Base
-#define u_Status (gus_base + 0x006)
-#define u_TimerControl (gus_base + 0x008)
-#define u_TimerData (gus_base + 0x009)
-#define u_IRQDMAControl (gus_base + 0x00b)
-#define u_MidiControl (gus_base + 0x100)
-#define MIDI_RESET 0x03
-#define MIDI_ENABLE_XMIT 0x20
-#define MIDI_ENABLE_RCV 0x80
-#define u_MidiStatus u_MidiControl
-#define MIDI_RCV_FULL 0x01
-#define MIDI_XMIT_EMPTY 0x02
-#define MIDI_FRAME_ERR 0x10
-#define MIDI_OVERRUN 0x20
-#define MIDI_IRQ_PEND 0x80
-#define u_MidiData (gus_base + 0x101)
-#define u_Voice (gus_base + 0x102)
-#define u_Command (gus_base + 0x103)
-#define u_DataLo (gus_base + 0x104)
-#define u_DataHi (gus_base + 0x105)
-#define u_MixData (gus_base + 0x106) /* Rev. 3.7+ mixing */
-#define u_MixSelect (gus_base + 0x506) /* registers. */
-#define u_IrqStatus u_Status
-# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */
-# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */
-# define GF1_TIMER1_IRQ 0x04 /* general purpose timer */
-# define GF1_TIMER2_IRQ 0x08 /* general purpose timer */
-# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */
-# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */
-# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */
-
-#define ICS2101 1
-# define ICS_MIXDEVS 6
-# define DEV_MIC 0
-# define DEV_LINE 1
-# define DEV_CD 2
-# define DEV_GF1 3
-# define DEV_UNUSED 4
-# define DEV_VOL 5
-
-# define CHN_LEFT 0
-# define CHN_RIGHT 1
-#define CS4231 2
-#define u_DRAMIO (gus_base + 0x107)
diff --git a/sound/oss/gus_linearvol.h b/sound/oss/gus_linearvol.h
deleted file mode 100644
index 7ad0c30d4fd9..000000000000
--- a/sound/oss/gus_linearvol.h
+++ /dev/null
@@ -1,18 +0,0 @@
-static unsigned short gus_linearvol[128] = {
- 0x0000, 0x08ff, 0x09ff, 0x0a80, 0x0aff, 0x0b40, 0x0b80, 0x0bc0,
- 0x0bff, 0x0c20, 0x0c40, 0x0c60, 0x0c80, 0x0ca0, 0x0cc0, 0x0ce0,
- 0x0cff, 0x0d10, 0x0d20, 0x0d30, 0x0d40, 0x0d50, 0x0d60, 0x0d70,
- 0x0d80, 0x0d90, 0x0da0, 0x0db0, 0x0dc0, 0x0dd0, 0x0de0, 0x0df0,
- 0x0dff, 0x0e08, 0x0e10, 0x0e18, 0x0e20, 0x0e28, 0x0e30, 0x0e38,
- 0x0e40, 0x0e48, 0x0e50, 0x0e58, 0x0e60, 0x0e68, 0x0e70, 0x0e78,
- 0x0e80, 0x0e88, 0x0e90, 0x0e98, 0x0ea0, 0x0ea8, 0x0eb0, 0x0eb8,
- 0x0ec0, 0x0ec8, 0x0ed0, 0x0ed8, 0x0ee0, 0x0ee8, 0x0ef0, 0x0ef8,
- 0x0eff, 0x0f04, 0x0f08, 0x0f0c, 0x0f10, 0x0f14, 0x0f18, 0x0f1c,
- 0x0f20, 0x0f24, 0x0f28, 0x0f2c, 0x0f30, 0x0f34, 0x0f38, 0x0f3c,
- 0x0f40, 0x0f44, 0x0f48, 0x0f4c, 0x0f50, 0x0f54, 0x0f58, 0x0f5c,
- 0x0f60, 0x0f64, 0x0f68, 0x0f6c, 0x0f70, 0x0f74, 0x0f78, 0x0f7c,
- 0x0f80, 0x0f84, 0x0f88, 0x0f8c, 0x0f90, 0x0f94, 0x0f98, 0x0f9c,
- 0x0fa0, 0x0fa4, 0x0fa8, 0x0fac, 0x0fb0, 0x0fb4, 0x0fb8, 0x0fbc,
- 0x0fc0, 0x0fc4, 0x0fc8, 0x0fcc, 0x0fd0, 0x0fd4, 0x0fd8, 0x0fdc,
- 0x0fe0, 0x0fe4, 0x0fe8, 0x0fec, 0x0ff0, 0x0ff4, 0x0ff8, 0x0ffc
-};
diff --git a/sound/oss/gus_midi.c b/sound/oss/gus_midi.c
deleted file mode 100644
index b48f57c24e48..000000000000
--- a/sound/oss/gus_midi.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * sound/gus2_midi.c
- *
- * The low level driver for the GUS Midi Interface.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added __init to gus_midi_init()
- */
-
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_hw.h"
-
-static int midi_busy, input_opened;
-static int my_dev;
-static int output_used;
-static volatile unsigned char gus_midi_control;
-static void (*midi_input_intr) (int dev, unsigned char data);
-
-static unsigned char tmp_queue[256];
-extern int gus_pnp_flag;
-static volatile int qlen;
-static volatile unsigned char qhead, qtail;
-extern int gus_base, gus_irq, gus_dma;
-extern int *gus_osp;
-extern spinlock_t gus_lock;
-
-static int GUS_MIDI_STATUS(void)
-{
- return inb(u_MidiStatus);
-}
-
-static int gus_midi_open(int dev, int mode, void (*input) (int dev, unsigned char data), void (*output) (int dev))
-{
- if (midi_busy)
- {
-/* printk("GUS: Midi busy\n");*/
- return -EBUSY;
- }
- outb((MIDI_RESET), u_MidiControl);
- gus_delay();
-
- gus_midi_control = 0;
- input_opened = 0;
-
- if (mode == OPEN_READ || mode == OPEN_READWRITE)
- if (!gus_pnp_flag)
- {
- gus_midi_control |= MIDI_ENABLE_RCV;
- input_opened = 1;
- }
- outb((gus_midi_control), u_MidiControl); /* Enable */
-
- midi_busy = 1;
- qlen = qhead = qtail = output_used = 0;
- midi_input_intr = input;
-
- return 0;
-}
-
-static int dump_to_midi(unsigned char midi_byte)
-{
- unsigned long flags;
- int ok = 0;
-
- output_used = 1;
-
- spin_lock_irqsave(&gus_lock, flags);
-
- if (GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY)
- {
- ok = 1;
- outb((midi_byte), u_MidiData);
- }
- else
- {
- /*
- * Enable Midi xmit interrupts (again)
- */
- gus_midi_control |= MIDI_ENABLE_XMIT;
- outb((gus_midi_control), u_MidiControl);
- }
-
- spin_unlock_irqrestore(&gus_lock,flags);
- return ok;
-}
-
-static void gus_midi_close(int dev)
-{
- /*
- * Reset FIFO pointers, disable intrs
- */
-
- outb((MIDI_RESET), u_MidiControl);
- midi_busy = 0;
-}
-
-static int gus_midi_out(int dev, unsigned char midi_byte)
-{
- unsigned long flags;
-
- /*
- * Drain the local queue first
- */
- spin_lock_irqsave(&gus_lock, flags);
-
- while (qlen && dump_to_midi(tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
- spin_unlock_irqrestore(&gus_lock,flags);
-
- /*
- * Output the byte if the local queue is empty.
- */
-
- if (!qlen)
- if (dump_to_midi(midi_byte))
- return 1; /*
- * OK
- */
-
- /*
- * Put to the local queue
- */
-
- if (qlen >= 256)
- return 0; /*
- * Local queue full
- */
- spin_lock_irqsave(&gus_lock, flags);
-
- tmp_queue[qtail] = midi_byte;
- qlen++;
- qtail++;
-
- spin_unlock_irqrestore(&gus_lock,flags);
- return 1;
-}
-
-static int gus_midi_start_read(int dev)
-{
- return 0;
-}
-
-static int gus_midi_end_read(int dev)
-{
- return 0;
-}
-
-static void gus_midi_kick(int dev)
-{
-}
-
-static int gus_midi_buffer_status(int dev)
-{
- unsigned long flags;
-
- if (!output_used)
- return 0;
-
- spin_lock_irqsave(&gus_lock, flags);
-
- if (qlen && dump_to_midi(tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
- spin_unlock_irqrestore(&gus_lock,flags);
- return (qlen > 0) || !(GUS_MIDI_STATUS() & MIDI_XMIT_EMPTY);
-}
-
-#define MIDI_SYNTH_NAME "Gravis Ultrasound Midi"
-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-static struct midi_operations gus_midi_operations =
-{
- .owner = THIS_MODULE,
- .info = {"Gravis UltraSound Midi", 0, 0, SNDCARD_GUS},
- .converter = &std_midi_synth,
- .in_info = {0},
- .open = gus_midi_open,
- .close = gus_midi_close,
- .outputc = gus_midi_out,
- .start_read = gus_midi_start_read,
- .end_read = gus_midi_end_read,
- .kick = gus_midi_kick,
- .buffer_status = gus_midi_buffer_status,
-};
-
-void __init gus_midi_init(struct address_info *hw_config)
-{
- int dev = sound_alloc_mididev();
-
- if (dev == -1)
- {
- printk(KERN_INFO "gus_midi: Too many midi devices detected\n");
- return;
- }
- outb((MIDI_RESET), u_MidiControl);
-
- std_midi_synth.midi_dev = my_dev = dev;
- hw_config->slots[2] = dev;
- midi_devs[dev] = &gus_midi_operations;
- sequencer_init();
- return;
-}
-
-void gus_midi_interrupt(int dummy)
-{
- volatile unsigned char stat, data;
- int timeout = 10;
-
- spin_lock(&gus_lock);
-
- while (timeout-- > 0 && (stat = GUS_MIDI_STATUS()) & (MIDI_RCV_FULL | MIDI_XMIT_EMPTY))
- {
- if (stat & MIDI_RCV_FULL)
- {
- data = inb(u_MidiData);
- if (input_opened)
- midi_input_intr(my_dev, data);
- }
- if (stat & MIDI_XMIT_EMPTY)
- {
- while (qlen && dump_to_midi(tmp_queue[qhead]))
- {
- qlen--;
- qhead++;
- }
- if (!qlen)
- {
- /*
- * Disable Midi output interrupts, since no data in the buffer
- */
- gus_midi_control &= ~MIDI_ENABLE_XMIT;
- outb((gus_midi_control), u_MidiControl);
- outb((gus_midi_control), u_MidiControl);
- }
- }
- }
- spin_unlock(&gus_lock);
-}
diff --git a/sound/oss/gus_vol.c b/sound/oss/gus_vol.c
deleted file mode 100644
index 6ae6924e1647..000000000000
--- a/sound/oss/gus_vol.c
+++ /dev/null
@@ -1,153 +0,0 @@
-
-/*
- * gus_vol.c - Compute volume for GUS.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-#include "sound_config.h"
-
-#include "gus.h"
-#include "gus_linearvol.h"
-
-#define GUS_VOLUME gus_wave_volume
-
-
-extern int gus_wave_volume;
-
-/*
- * Calculate gus volume from note velocity, main volume, expression, and
- * intrinsic patch volume given in patch library. Expression is multiplied
- * in, so it emphasizes differences in note velocity, while main volume is
- * added in -- I don't know whether this is right, but it seems reasonable to
- * me. (In the previous stage, main volume controller messages were changed
- * to expression controller messages, if they were found to be used for
- * dynamic volume adjustments, so here, main volume can be assumed to be
- * constant throughout a song.)
- *
- * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so
- * we can give a big boost to very weak voices like nylon guitar and the
- * basses. The normal value is 64. Strings are assigned lower values.
- */
-
-unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev)
-{
- int i, m, n, x;
-
-
- /*
- * A voice volume of 64 is considered neutral, so adjust the main volume if
- * something other than this neutral value was assigned in the patch
- * library.
- */
- x = 256 + 6 * (voicev - 64);
-
- /*
- * Boost expression by voice volume above neutral.
- */
-
- if (voicev > 65)
- xpn += voicev - 64;
- xpn += (voicev - 64) / 2;
-
- /*
- * Combine multiplicative and level components.
- */
- x = vel * xpn * 6 + (voicev / 4) * x;
-
-#ifdef GUS_VOLUME
- /*
- * Further adjustment by installation-specific master volume control
- * (default 60).
- */
- x = (x * GUS_VOLUME * GUS_VOLUME) / 10000;
-#endif
-
-#ifdef GUS_USE_CHN_MAIN_VOLUME
- /*
- * Experimental support for the channel main volume
- */
-
- mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */
- x = (x * mainv * mainv) / 16384;
-#endif
-
- if (x < 2)
- return (0);
- else if (x >= 65535)
- return ((15 << 8) | 255);
-
- /*
- * Convert to GUS's logarithmic form with 4 bit exponent i and 8 bit
- * mantissa m.
- */
-
- n = x;
- i = 7;
- if (n < 128)
- {
- while (i > 0 && n < (1 << i))
- i--;
- }
- else
- {
- while (n > 255)
- {
- n >>= 1;
- i++;
- }
- }
- /*
- * Mantissa is part of linear volume not expressed in exponent. (This is
- * not quite like real logs -- I wonder if it's right.)
- */
- m = x - (1 << i);
-
- /*
- * Adjust mantissa to 8 bits.
- */
- if (m > 0)
- {
- if (i > 8)
- m >>= i - 8;
- else if (i < 8)
- m <<= 8 - i;
- }
- return ((i << 8) + m);
-}
-
-/*
- * Volume-values are interpreted as linear values. Volume is based on the
- * value supplied with SEQ_START_NOTE(), channel main volume (if compiled in)
- * and the volume set by the mixer-device (default 60%).
- */
-
-unsigned short gus_linear_vol(int vol, int mainvol)
-{
- int mixer_mainvol;
-
- if (vol <= 0)
- vol = 0;
- else if (vol >= 127)
- vol = 127;
-
-#ifdef GUS_VOLUME
- mixer_mainvol = GUS_VOLUME;
-#else
- mixer_mainvol = 100;
-#endif
-
-#ifdef GUS_USE_CHN_MAIN_VOLUME
- if (mainvol <= 0)
- mainvol = 0;
- else if (mainvol >= 127)
- mainvol = 127;
-#else
- mainvol = 127;
-#endif
- return gus_linearvol[(((vol * mainvol) / 127) * mixer_mainvol) / 100];
-}
diff --git a/sound/oss/gus_wave.c b/sound/oss/gus_wave.c
deleted file mode 100644
index 942d5186580d..000000000000
--- a/sound/oss/gus_wave.c
+++ /dev/null
@@ -1,3464 +0,0 @@
-/*
- * sound/gus_wave.c
- *
- * Driver for the Gravis UltraSound wave table synth.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
- * Frank van de Pol : Fixed GUS MAX interrupt handling. Enabled simultanious
- * usage of CS4231A codec, GUS wave and MIDI for GUS MAX.
- * Bartlomiej Zolnierkiewicz : added some __init/__exit
- */
-
-#include <linux/init.h>
-#include <linux/config.h>
-#include <linux/spinlock.h>
-
-#define GUSPNP_AUTODETECT
-
-#include "sound_config.h"
-#include <linux/ultrasound.h>
-
-#include "gus.h"
-#include "gus_hw.h"
-
-#define GUS_BANK_SIZE (((iw_mode) ? 256*1024*1024 : 256*1024))
-
-#define MAX_SAMPLE 150
-#define MAX_PATCH 256
-
-#define NOT_SAMPLE 0xffff
-
-struct voice_info
-{
- unsigned long orig_freq;
- unsigned long current_freq;
- unsigned long mode;
- int fixed_pitch;
- int bender;
- int bender_range;
- int panning;
- int midi_volume;
- unsigned int initial_volume;
- unsigned int current_volume;
- int loop_irq_mode, loop_irq_parm;
-#define LMODE_FINISH 1
-#define LMODE_PCM 2
-#define LMODE_PCM_STOP 3
- int volume_irq_mode, volume_irq_parm;
-#define VMODE_HALT 1
-#define VMODE_ENVELOPE 2
-#define VMODE_START_NOTE 3
-
- int env_phase;
- unsigned char env_rate[6];
- unsigned char env_offset[6];
-
- /*
- * Volume computation parameters for gus_adagio_vol()
- */
- int main_vol, expression_vol, patch_vol;
-
- /* Variables for "Ultraclick" removal */
- int dev_pending, note_pending, volume_pending,
- sample_pending;
- char kill_pending;
- long offset_pending;
-
-};
-
-static struct voice_alloc_info *voice_alloc;
-static struct address_info *gus_hw_config;
-extern int gus_base;
-extern int gus_irq, gus_dma;
-extern int gus_pnp_flag;
-extern int gus_no_wave_dma;
-static int gus_dma2 = -1;
-static int dual_dma_mode;
-static long gus_mem_size;
-static long free_mem_ptr;
-static int gus_busy;
-static int gus_no_dma;
-static int nr_voices;
-static int gus_devnum;
-static int volume_base, volume_scale, volume_method;
-static int gus_recmask = SOUND_MASK_MIC;
-static int recording_active;
-static int only_read_access;
-static int only_8_bits;
-
-static int iw_mode = 0;
-int gus_wave_volume = 60;
-int gus_pcm_volume = 80;
-int have_gus_max = 0;
-static int gus_line_vol = 100, gus_mic_vol;
-static unsigned char mix_image = 0x00;
-
-int gus_timer_enabled = 0;
-
-/*
- * Current version of this driver doesn't allow synth and PCM functions
- * at the same time. The active_device specifies the active driver
- */
-
-static int active_device;
-
-#define GUS_DEV_WAVE 1 /* Wave table synth */
-#define GUS_DEV_PCM_DONE 2 /* PCM device, transfer done */
-#define GUS_DEV_PCM_CONTINUE 3 /* PCM device, transfer done ch. 1/2 */
-
-static int gus_audio_speed;
-static int gus_audio_channels;
-static int gus_audio_bits;
-static int gus_audio_bsize;
-static char bounce_buf[8 * 1024]; /* Must match value set to max_fragment */
-
-static DECLARE_WAIT_QUEUE_HEAD(dram_sleeper);
-
-/*
- * Variables and buffers for PCM output
- */
-
-#define MAX_PCM_BUFFERS (128*MAX_REALTIME_FACTOR) /* Don't change */
-
-static int pcm_bsize, pcm_nblk, pcm_banksize;
-static int pcm_datasize[MAX_PCM_BUFFERS];
-static volatile int pcm_head, pcm_tail, pcm_qlen;
-static volatile int pcm_active;
-static volatile int dma_active;
-static int pcm_opened;
-static int pcm_current_dev;
-static int pcm_current_block;
-static unsigned long pcm_current_buf;
-static int pcm_current_count;
-static int pcm_current_intrflag;
-DEFINE_SPINLOCK(gus_lock);
-
-extern int *gus_osp;
-
-static struct voice_info voices[32];
-
-static int freq_div_table[] =
-{
- 44100, /* 14 */
- 41160, /* 15 */
- 38587, /* 16 */
- 36317, /* 17 */
- 34300, /* 18 */
- 32494, /* 19 */
- 30870, /* 20 */
- 29400, /* 21 */
- 28063, /* 22 */
- 26843, /* 23 */
- 25725, /* 24 */
- 24696, /* 25 */
- 23746, /* 26 */
- 22866, /* 27 */
- 22050, /* 28 */
- 21289, /* 29 */
- 20580, /* 30 */
- 19916, /* 31 */
- 19293 /* 32 */
-};
-
-static struct patch_info *samples;
-static long sample_ptrs[MAX_SAMPLE + 1];
-static int sample_map[32];
-static int free_sample;
-static int mixer_type;
-
-
-static int patch_table[MAX_PATCH];
-static int patch_map[32];
-
-static struct synth_info gus_info = {
- "Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS,
- 0, 16, 0, MAX_PATCH
-};
-
-static void gus_poke(long addr, unsigned char data);
-static void compute_and_set_volume(int voice, int volume, int ramp_time);
-extern unsigned short gus_adagio_vol(int vel, int mainv, int xpn, int voicev);
-extern unsigned short gus_linear_vol(int vol, int mainvol);
-static void compute_volume(int voice, int volume);
-static void do_volume_irq(int voice);
-static void set_input_volumes(void);
-static void gus_tmr_install(int io_base);
-
-#define INSTANT_RAMP -1 /* Instant change. No ramping */
-#define FAST_RAMP 0 /* Fastest possible ramp */
-
-static void reset_sample_memory(void)
-{
- int i;
-
- for (i = 0; i <= MAX_SAMPLE; i++)
- sample_ptrs[i] = -1;
- for (i = 0; i < 32; i++)
- sample_map[i] = -1;
- for (i = 0; i < 32; i++)
- patch_map[i] = -1;
-
- gus_poke(0, 0); /* Put a silent sample to the beginning */
- gus_poke(1, 0);
- free_mem_ptr = 2;
-
- free_sample = 0;
-
- for (i = 0; i < MAX_PATCH; i++)
- patch_table[i] = NOT_SAMPLE;
-}
-
-void gus_delay(void)
-{
- int i;
-
- for (i = 0; i < 7; i++)
- inb(u_DRAMIO);
-}
-
-static void gus_poke(long addr, unsigned char data)
-{ /* Writes a byte to the DRAM */
- outb((0x43), u_Command);
- outb((addr & 0xff), u_DataLo);
- outb(((addr >> 8) & 0xff), u_DataHi);
-
- outb((0x44), u_Command);
- outb(((addr >> 16) & 0xff), u_DataHi);
- outb((data), u_DRAMIO);
-}
-
-static unsigned char gus_peek(long addr)
-{ /* Reads a byte from the DRAM */
- unsigned char tmp;
-
- outb((0x43), u_Command);
- outb((addr & 0xff), u_DataLo);
- outb(((addr >> 8) & 0xff), u_DataHi);
-
- outb((0x44), u_Command);
- outb(((addr >> 16) & 0xff), u_DataHi);
- tmp = inb(u_DRAMIO);
-
- return tmp;
-}
-
-void gus_write8(int reg, unsigned int data)
-{ /* Writes to an indirect register (8 bit) */
- outb((reg), u_Command);
- outb(((unsigned char) (data & 0xff)), u_DataHi);
-}
-
-static unsigned char gus_read8(int reg)
-{
- /* Reads from an indirect register (8 bit). Offset 0x80. */
- unsigned char val;
-
- outb((reg | 0x80), u_Command);
- val = inb(u_DataHi);
-
- return val;
-}
-
-static unsigned char gus_look8(int reg)
-{
- /* Reads from an indirect register (8 bit). No additional offset. */
- unsigned char val;
-
- outb((reg), u_Command);
- val = inb(u_DataHi);
-
- return val;
-}
-
-static void gus_write16(int reg, unsigned int data)
-{
- /* Writes to an indirect register (16 bit) */
- outb((reg), u_Command);
-
- outb(((unsigned char) (data & 0xff)), u_DataLo);
- outb(((unsigned char) ((data >> 8) & 0xff)), u_DataHi);
-}
-
-static unsigned short gus_read16(int reg)
-{
- /* Reads from an indirect register (16 bit). Offset 0x80. */
- unsigned char hi, lo;
-
- outb((reg | 0x80), u_Command);
-
- lo = inb(u_DataLo);
- hi = inb(u_DataHi);
-
- return ((hi << 8) & 0xff00) | lo;
-}
-
-static unsigned short gus_look16(int reg)
-{
- /* Reads from an indirect register (16 bit). No additional offset. */
- unsigned char hi, lo;
-
- outb((reg), u_Command);
-
- lo = inb(u_DataLo);
- hi = inb(u_DataHi);
-
- return ((hi << 8) & 0xff00) | lo;
-}
-
-static void gus_write_addr(int reg, unsigned long address, int frac, int is16bit)
-{
- /* Writes an 24 bit memory address */
- unsigned long hold_address;
-
- if (is16bit)
- {
- if (iw_mode)
- {
- /* Interwave spesific address translations */
- address >>= 1;
- }
- else
- {
- /*
- * Special processing required for 16 bit patches
- */
-
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
- }
- gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
- gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
- + (frac << 5));
- /* Could writing twice fix problems with GUS_VOICE_POS()? Let's try. */
- gus_delay();
- gus_write16(reg, (unsigned short) ((address >> 7) & 0xffff));
- gus_write16(reg + 1, (unsigned short) ((address << 9) & 0xffff)
- + (frac << 5));
-}
-
-static void gus_select_voice(int voice)
-{
- if (voice < 0 || voice > 31)
- return;
- outb((voice), u_Voice);
-}
-
-static void gus_select_max_voices(int nvoices)
-{
- if (iw_mode)
- nvoices = 32;
- if (nvoices < 14)
- nvoices = 14;
- if (nvoices > 32)
- nvoices = 32;
-
- voice_alloc->max_voice = nr_voices = nvoices;
- gus_write8(0x0e, (nvoices - 1) | 0xc0);
-}
-
-static void gus_voice_on(unsigned int mode)
-{
- gus_write8(0x00, (unsigned char) (mode & 0xfc));
- gus_delay();
- gus_write8(0x00, (unsigned char) (mode & 0xfc));
-}
-
-static void gus_voice_off(void)
-{
- gus_write8(0x00, gus_read8(0x00) | 0x03);
-}
-
-static void gus_voice_mode(unsigned int m)
-{
- unsigned char mode = (unsigned char) (m & 0xff);
-
- gus_write8(0x00, (gus_read8(0x00) & 0x03) |
- (mode & 0xfc)); /* Don't touch last two bits */
- gus_delay();
- gus_write8(0x00, (gus_read8(0x00) & 0x03) | (mode & 0xfc));
-}
-
-static void gus_voice_freq(unsigned long freq)
-{
- unsigned long divisor = freq_div_table[nr_voices - 14];
- unsigned short fc;
-
- /* Interwave plays at 44100 Hz with any number of voices */
- if (iw_mode)
- fc = (unsigned short) (((freq << 9) + (44100 >> 1)) / 44100);
- else
- fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor);
- fc = fc << 1;
-
- gus_write16(0x01, fc);
-}
-
-static void gus_voice_volume(unsigned int vol)
-{
- gus_write8(0x0d, 0x03); /* Stop ramp before setting volume */
- gus_write16(0x09, (unsigned short) (vol << 4));
-}
-
-static void gus_voice_balance(unsigned int balance)
-{
- gus_write8(0x0c, (unsigned char) (balance & 0xff));
-}
-
-static void gus_ramp_range(unsigned int low, unsigned int high)
-{
- gus_write8(0x07, (unsigned char) ((low >> 4) & 0xff));
- gus_write8(0x08, (unsigned char) ((high >> 4) & 0xff));
-}
-
-static void gus_ramp_rate(unsigned int scale, unsigned int rate)
-{
- gus_write8(0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f)));
-}
-
-static void gus_rampon(unsigned int m)
-{
- unsigned char mode = (unsigned char) (m & 0xff);
-
- gus_write8(0x0d, mode & 0xfc);
- gus_delay();
- gus_write8(0x0d, mode & 0xfc);
-}
-
-static void gus_ramp_mode(unsigned int m)
-{
- unsigned char mode = (unsigned char) (m & 0xff);
-
- gus_write8(0x0d, (gus_read8(0x0d) & 0x03) |
- (mode & 0xfc)); /* Leave the last 2 bits alone */
- gus_delay();
- gus_write8(0x0d, (gus_read8(0x0d) & 0x03) | (mode & 0xfc));
-}
-
-static void gus_rampoff(void)
-{
- gus_write8(0x0d, 0x03);
-}
-
-static void gus_set_voice_pos(int voice, long position)
-{
- int sample_no;
-
- if ((sample_no = sample_map[voice]) != -1) {
- if (position < samples[sample_no].len) {
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- voices[voice].offset_pending = position;
- else
- gus_write_addr(0x0a, sample_ptrs[sample_no] + position, 0,
- samples[sample_no].mode & WAVE_16_BITS);
- }
- }
-}
-
-static void gus_voice_init(int voice)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_volume(0);
- gus_voice_off();
- gus_write_addr(0x0a, 0, 0, 0); /* Set current position to 0 */
- gus_write8(0x00, 0x03); /* Voice off */
- gus_write8(0x0d, 0x03); /* Ramping off */
- voice_alloc->map[voice] = 0;
- voice_alloc->alloc_times[voice] = 0;
- spin_unlock_irqrestore(&gus_lock,flags);
-
-}
-
-static void gus_voice_init2(int voice)
-{
- voices[voice].panning = 0;
- voices[voice].mode = 0;
- voices[voice].orig_freq = 20000;
- voices[voice].current_freq = 20000;
- voices[voice].bender = 0;
- voices[voice].bender_range = 200;
- voices[voice].initial_volume = 0;
- voices[voice].current_volume = 0;
- voices[voice].loop_irq_mode = 0;
- voices[voice].loop_irq_parm = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].volume_irq_parm = 0;
- voices[voice].env_phase = 0;
- voices[voice].main_vol = 127;
- voices[voice].patch_vol = 127;
- voices[voice].expression_vol = 127;
- voices[voice].sample_pending = -1;
- voices[voice].fixed_pitch = 0;
-}
-
-static void step_envelope(int voice)
-{
- unsigned vol, prev_vol, phase;
- unsigned char rate;
- unsigned long flags;
-
- if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2)
- {
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_rampoff();
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- /*
- * Sustain phase begins. Continue envelope after receiving note off.
- */
- }
- if (voices[voice].env_phase >= 5)
- {
- /* Envelope finished. Shoot the voice down */
- gus_voice_init(voice);
- return;
- }
- prev_vol = voices[voice].current_volume;
- phase = ++voices[voice].env_phase;
- compute_volume(voice, voices[voice].midi_volume);
- vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255;
- rate = voices[voice].env_rate[phase];
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
-
- gus_voice_volume(prev_vol);
-
-
- gus_write8(0x06, rate); /* Ramping rate */
-
- voices[voice].volume_irq_mode = VMODE_ENVELOPE;
-
- if (((vol - prev_vol) / 64) == 0) /* No significant volume change */
- {
- spin_unlock_irqrestore(&gus_lock,flags);
- step_envelope(voice); /* Continue the envelope on the next step */
- return;
- }
- if (vol > prev_vol)
- {
- if (vol >= (4096 - 64))
- vol = 4096 - 65;
- gus_ramp_range(0, vol);
- gus_rampon(0x20); /* Increasing volume, with IRQ */
- }
- else
- {
- if (vol <= 64)
- vol = 65;
- gus_ramp_range(vol, 4030);
- gus_rampon(0x60); /* Decreasing volume, with IRQ */
- }
- voices[voice].current_volume = vol;
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void init_envelope(int voice)
-{
- voices[voice].env_phase = -1;
- voices[voice].current_volume = 64;
-
- step_envelope(voice);
-}
-
-static void start_release(int voice)
-{
- if (gus_read8(0x00) & 0x03)
- return; /* Voice already stopped */
-
- voices[voice].env_phase = 2; /* Will be incremented by step_envelope */
-
- voices[voice].current_volume = voices[voice].initial_volume =
- gus_read16(0x09) >> 4; /* Get current volume */
-
- voices[voice].mode &= ~WAVE_SUSTAIN_ON;
- gus_rampoff();
- step_envelope(voice);
-}
-
-static void gus_voice_fade(int voice)
-{
- int instr_no = sample_map[voice], is16bits;
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
-
- if (instr_no < 0 || instr_no > MAX_SAMPLE)
- {
- gus_write8(0x00, 0x03); /* Hard stop */
- voice_alloc->map[voice] = 0;
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* 8 or 16 bits */
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- start_release(voice);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- /*
- * Ramp the volume down but not too quickly.
- */
- if ((int) (gus_read16(0x09) >> 4) < 100) /* Get current volume */
- {
- gus_voice_off();
- gus_rampoff();
- gus_voice_init(voice);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- gus_ramp_range(65, 4030);
- gus_ramp_rate(2, 4);
- gus_rampon(0x40 | 0x20); /* Down, once, with IRQ */
- voices[voice].volume_irq_mode = VMODE_HALT;
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void gus_reset(void)
-{
- int i;
-
- gus_select_max_voices(24);
- volume_base = 3071;
- volume_scale = 4;
- volume_method = VOL_METHOD_ADAGIO;
-
- for (i = 0; i < 32; i++)
- {
- gus_voice_init(i); /* Turn voice off */
- gus_voice_init2(i);
- }
-}
-
-static void gus_initialize(void)
-{
- unsigned long flags;
- unsigned char dma_image, irq_image, tmp;
-
- static unsigned char gus_irq_map[16] = {
- 0, 0, 0, 3, 0, 2, 0, 4, 0, 1, 0, 5, 6, 0, 0, 7
- };
-
- static unsigned char gus_dma_map[8] = {
- 0, 1, 0, 2, 0, 3, 4, 5
- };
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_write8(0x4c, 0); /* Reset GF1 */
- gus_delay();
- gus_delay();
-
- gus_write8(0x4c, 1); /* Release Reset */
- gus_delay();
- gus_delay();
-
- /*
- * Clear all interrupts
- */
-
- gus_write8(0x41, 0); /* DMA control */
- gus_write8(0x45, 0); /* Timer control */
- gus_write8(0x49, 0); /* Sample control */
-
- gus_select_max_voices(24);
-
- inb(u_Status); /* Touch the status register */
-
- gus_look8(0x41); /* Clear any pending DMA IRQs */
- gus_look8(0x49); /* Clear any pending sample IRQs */
- gus_read8(0x0f); /* Clear pending IRQs */
-
- gus_reset(); /* Resets all voices */
-
- gus_look8(0x41); /* Clear any pending DMA IRQs */
- gus_look8(0x49); /* Clear any pending sample IRQs */
- gus_read8(0x0f); /* Clear pending IRQs */
-
- gus_write8(0x4c, 7); /* Master reset | DAC enable | IRQ enable */
-
- /*
- * Set up for Digital ASIC
- */
-
- outb((0x05), gus_base + 0x0f);
-
- mix_image |= 0x02; /* Disable line out (for a moment) */
- outb((mix_image), u_Mixer);
-
- outb((0x00), u_IRQDMAControl);
-
- outb((0x00), gus_base + 0x0f);
-
- /*
- * Now set up the DMA and IRQ interface
- *
- * The GUS supports two IRQs and two DMAs.
- *
- * Just one DMA channel is used. This prevents simultaneous ADC and DAC.
- * Adding this support requires significant changes to the dmabuf.c, dsp.c
- * and audio.c also.
- */
-
- irq_image = 0;
- tmp = gus_irq_map[gus_irq];
- if (!gus_pnp_flag && !tmp)
- printk(KERN_WARNING "Warning! GUS IRQ not selected\n");
- irq_image |= tmp;
- irq_image |= 0x40; /* Combine IRQ1 (GF1) and IRQ2 (Midi) */
-
- dual_dma_mode = 1;
- if (gus_dma2 == gus_dma || gus_dma2 == -1)
- {
- dual_dma_mode = 0;
- dma_image = 0x40; /* Combine DMA1 (DRAM) and IRQ2 (ADC) */
-
- tmp = gus_dma_map[gus_dma];
- if (!tmp)
- printk(KERN_WARNING "Warning! GUS DMA not selected\n");
-
- dma_image |= tmp;
- }
- else
- {
- /* Setup dual DMA channel mode for GUS MAX */
-
- dma_image = gus_dma_map[gus_dma];
- if (!dma_image)
- printk(KERN_WARNING "Warning! GUS DMA not selected\n");
-
- tmp = gus_dma_map[gus_dma2] << 3;
- if (!tmp)
- {
- printk(KERN_WARNING "Warning! Invalid GUS MAX DMA\n");
- tmp = 0x40; /* Combine DMA channels */
- dual_dma_mode = 0;
- }
- dma_image |= tmp;
- }
-
- /*
- * For some reason the IRQ and DMA addresses must be written twice
- */
-
- /*
- * Doing it first time
- */
-
- outb((mix_image), u_Mixer); /* Select DMA control */
- outb((dma_image | 0x80), u_IRQDMAControl); /* Set DMA address */
-
- outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */
- outb((irq_image), u_IRQDMAControl); /* Set IRQ address */
-
- /*
- * Doing it second time
- */
-
- outb((mix_image), u_Mixer); /* Select DMA control */
- outb((dma_image), u_IRQDMAControl); /* Set DMA address */
-
- outb((mix_image | 0x40), u_Mixer); /* Select IRQ control */
- outb((irq_image), u_IRQDMAControl); /* Set IRQ address */
-
- gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
-
- mix_image &= ~0x02; /* Enable line out */
- mix_image |= 0x08; /* Enable IRQ */
- outb((mix_image), u_Mixer); /*
- * Turn mixer channels on
- * Note! Mic in is left off.
- */
-
- gus_select_voice(0); /* This disables writes to IRQ/DMA reg */
-
- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
-
- inb(u_Status); /* Touch the status register */
-
- gus_look8(0x41); /* Clear any pending DMA IRQs */
- gus_look8(0x49); /* Clear any pending sample IRQs */
-
- gus_read8(0x0f); /* Clear pending IRQs */
-
- if (iw_mode)
- gus_write8(0x19, gus_read8(0x19) | 0x01);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-
-static void __init pnp_mem_init(void)
-{
-#include "iwmem.h"
-#define CHUNK_SIZE (256*1024)
-#define BANK_SIZE (4*1024*1024)
-#define CHUNKS_PER_BANK (BANK_SIZE/CHUNK_SIZE)
-
- int bank, chunk, addr, total = 0;
- int bank_sizes[4];
- int i, j, bits = -1, testbits = -1, nbanks = 0;
-
- /*
- * This routine determines what kind of RAM is installed in each of the four
- * SIMM banks and configures the DRAM address decode logic accordingly.
- */
-
- /*
- * Place the chip into enhanced mode
- */
- gus_write8(0x19, gus_read8(0x19) | 0x01);
- gus_write8(0x53, gus_look8(0x53) & ~0x02); /* Select DRAM I/O access */
-
- /*
- * Set memory configuration to 4 DRAM banks of 4M in each (16M total).
- */
-
- gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | 0x000c);
-
- /*
- * Perform the DRAM size detection for each bank individually.
- */
- for (bank = 0; bank < 4; bank++)
- {
- int size = 0;
-
- addr = bank * BANK_SIZE;
-
- /* Clean check points of each chunk */
- for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
- {
- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
- }
-
- /* Write a value to each chunk point and verify the result */
- for (chunk = 0; chunk < CHUNKS_PER_BANK; chunk++)
- {
- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x55);
- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0xAA);
-
- if (gus_peek(addr + chunk * CHUNK_SIZE + 0L) == 0x55 &&
- gus_peek(addr + chunk * CHUNK_SIZE + 1L) == 0xAA)
- {
- /* OK. There is RAM. Now check for possible shadows */
- int ok = 1, chunk2;
-
- for (chunk2 = 0; ok && chunk2 < chunk; chunk2++)
- if (gus_peek(addr + chunk2 * CHUNK_SIZE + 0L) ||
- gus_peek(addr + chunk2 * CHUNK_SIZE + 1L))
- ok = 0; /* Addressing wraps */
-
- if (ok)
- size = (chunk + 1) * CHUNK_SIZE;
- }
- gus_poke(addr + chunk * CHUNK_SIZE + 0L, 0x00);
- gus_poke(addr + chunk * CHUNK_SIZE + 1L, 0x00);
- }
- bank_sizes[bank] = size;
- if (size)
- nbanks = bank + 1;
- DDB(printk("Interwave: Bank %d, size=%dk\n", bank, size / 1024));
- }
-
- if (nbanks == 0) /* No RAM - Give up */
- {
- printk(KERN_ERR "Sound: An Interwave audio chip detected but no DRAM\n");
- printk(KERN_ERR "Sound: Unable to work with this card.\n");
- gus_write8(0x19, gus_read8(0x19) & ~0x01);
- gus_mem_size = 0;
- return;
- }
-
- /*
- * Now we know how much DRAM there is in each bank. The next step is
- * to find a DRAM size encoding (0 to 12) which is best for the combination
- * we have.
- *
- * First try if any of the possible alternatives matches exactly the amount
- * of memory we have.
- */
-
- for (i = 0; bits == -1 && i < 13; i++)
- {
- bits = i;
-
- for (j = 0; bits != -1 && j < 4; j++)
- if (mem_decode[i][j] != bank_sizes[j])
- bits = -1; /* No hit */
- }
-
- /*
- * If necessary, try to find a combination where other than the last
- * bank matches our configuration and the last bank is left oversized.
- * In this way we don't leave holes in the middle of memory.
- */
-
- if (bits == -1) /* No luck yet */
- {
- for (i = 0; bits == -1 && i < 13; i++)
- {
- bits = i;
-
- for (j = 0; bits != -1 && j < nbanks - 1; j++)
- if (mem_decode[i][j] != bank_sizes[j])
- bits = -1; /* No hit */
- if (mem_decode[i][nbanks - 1] < bank_sizes[nbanks - 1])
- bits = -1; /* The last bank is too small */
- }
- }
- /*
- * The last resort is to search for a combination where the banks are
- * smaller than the actual SIMMs. This leaves some memory in the banks
- * unused but doesn't leave holes in the DRAM address space.
- */
- if (bits == -1) /* No luck yet */
- {
- for (i = 0; i < 13; i++)
- {
- testbits = i;
- for (j = 0; testbits != -1 && j < nbanks - 1; j++)
- if (mem_decode[i][j] > bank_sizes[j]) {
- testbits = -1;
- }
- if(testbits > bits) bits = testbits;
- }
- if (bits != -1)
- {
- printk(KERN_INFO "Interwave: Can't use all installed RAM.\n");
- printk(KERN_INFO "Interwave: Try reordering SIMMS.\n");
- }
- printk(KERN_INFO "Interwave: Can't find working DRAM encoding.\n");
- printk(KERN_INFO "Interwave: Defaulting to 256k. Try reordering SIMMS.\n");
- bits = 0;
- }
- DDB(printk("Interwave: Selecting DRAM addressing mode %d\n", bits));
-
- for (bank = 0; bank < 4; bank++)
- {
- DDB(printk(" Bank %d, mem=%dk (limit %dk)\n", bank, bank_sizes[bank] / 1024, mem_decode[bits][bank] / 1024));
-
- if (bank_sizes[bank] > mem_decode[bits][bank])
- total += mem_decode[bits][bank];
- else
- total += bank_sizes[bank];
- }
-
- DDB(printk("Total %dk of DRAM (enhanced mode)\n", total / 1024));
-
- /*
- * Set the memory addressing mode.
- */
- gus_write16(0x52, (gus_look16(0x52) & 0xfff0) | bits);
-
-/* Leave the chip into enhanced mode. Disable LFO */
- gus_mem_size = total;
- iw_mode = 1;
- gus_write8(0x19, (gus_read8(0x19) | 0x01) & ~0x02);
-}
-
-int __init gus_wave_detect(int baseaddr)
-{
- unsigned long i, max_mem = 1024L;
- unsigned long loc;
- unsigned char val;
-
- if (!request_region(baseaddr, 16, "GUS"))
- return 0;
- if (!request_region(baseaddr + 0x100, 12, "GUS")) { /* 0x10c-> is MAX */
- release_region(baseaddr, 16);
- return 0;
- }
-
- gus_base = baseaddr;
-
- gus_write8(0x4c, 0); /* Reset GF1 */
- gus_delay();
- gus_delay();
-
- gus_write8(0x4c, 1); /* Release Reset */
- gus_delay();
- gus_delay();
-
-#ifdef GUSPNP_AUTODETECT
- val = gus_look8(0x5b); /* Version number register */
- gus_write8(0x5b, ~val); /* Invert all bits */
-
- if ((gus_look8(0x5b) & 0xf0) == (val & 0xf0)) /* No change */
- {
- if ((gus_look8(0x5b) & 0x0f) == ((~val) & 0x0f)) /* Change */
- {
- DDB(printk("Interwave chip version %d detected\n", (val & 0xf0) >> 4));
- gus_pnp_flag = 1;
- }
- else
- {
- DDB(printk("Not an Interwave chip (%x)\n", gus_look8(0x5b)));
- gus_pnp_flag = 0;
- }
- }
- gus_write8(0x5b, val); /* Restore all bits */
-#endif
-
- if (gus_pnp_flag)
- pnp_mem_init();
- if (iw_mode)
- return 1;
-
- /* See if there is first block there.... */
- gus_poke(0L, 0xaa);
- if (gus_peek(0L) != 0xaa) {
- release_region(baseaddr + 0x100, 12);
- release_region(baseaddr, 16);
- return 0;
- }
-
- /* Now zero it out so that I can check for mirroring .. */
- gus_poke(0L, 0x00);
- for (i = 1L; i < max_mem; i++)
- {
- int n, failed;
-
- /* check for mirroring ... */
- if (gus_peek(0L) != 0)
- break;
- loc = i << 10;
-
- for (n = loc - 1, failed = 0; n <= loc; n++)
- {
- gus_poke(loc, 0xaa);
- if (gus_peek(loc) != 0xaa)
- failed = 1;
- gus_poke(loc, 0x55);
- if (gus_peek(loc) != 0x55)
- failed = 1;
- }
- if (failed)
- break;
- }
- gus_mem_size = i << 10;
- return 1;
-}
-
-static int guswave_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
-
- switch (cmd)
- {
- case SNDCTL_SYNTH_INFO:
- gus_info.nr_voices = nr_voices;
- if (copy_to_user(arg, &gus_info, sizeof(gus_info)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_SEQ_RESETSAMPLES:
- reset_sample_memory();
- return 0;
-
- case SNDCTL_SEQ_PERCMODE:
- return 0;
-
- case SNDCTL_SYNTH_MEMAVL:
- return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
-
- default:
- return -EINVAL;
- }
-}
-
-static int guswave_set_instr(int dev, int voice, int instr_no)
-{
- int sample_no;
-
- if (instr_no < 0 || instr_no > MAX_PATCH)
- instr_no = 0; /* Default to acoustic piano */
-
- if (voice < 0 || voice > 31)
- return -EINVAL;
-
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].sample_pending = instr_no;
- return 0;
- }
- sample_no = patch_table[instr_no];
- patch_map[voice] = -1;
-
- if (sample_no == NOT_SAMPLE)
- {
-/* printk("GUS: Undefined patch %d for voice %d\n", instr_no, voice);*/
- return -EINVAL; /* Patch not defined */
- }
- if (sample_ptrs[sample_no] == -1) /* Sample not loaded */
- {
-/* printk("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice);*/
- return -EINVAL;
- }
- sample_map[voice] = sample_no;
- patch_map[voice] = instr_no;
- return 0;
-}
-
-static int guswave_kill_note(int dev, int voice, int note, int velocity)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- /* voice_alloc->map[voice] = 0xffff; */
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].kill_pending = 1;
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- else
- {
- spin_unlock_irqrestore(&gus_lock,flags);
- gus_voice_fade(voice);
- }
-
- return 0;
-}
-
-static void guswave_aftertouch(int dev, int voice, int pressure)
-{
-}
-
-static void guswave_panning(int dev, int voice, int value)
-{
- if (voice >= 0 || voice < 32)
- voices[voice].panning = value;
-}
-
-static void guswave_volume_method(int dev, int mode)
-{
- if (mode == VOL_METHOD_LINEAR || mode == VOL_METHOD_ADAGIO)
- volume_method = mode;
-}
-
-static void compute_volume(int voice, int volume)
-{
- if (volume < 128)
- voices[voice].midi_volume = volume;
-
- switch (volume_method)
- {
- case VOL_METHOD_ADAGIO:
- voices[voice].initial_volume =
- gus_adagio_vol(voices[voice].midi_volume, voices[voice].main_vol,
- voices[voice].expression_vol,
- voices[voice].patch_vol);
- break;
-
- case VOL_METHOD_LINEAR: /* Totally ignores patch-volume and expression */
- voices[voice].initial_volume = gus_linear_vol(volume, voices[voice].main_vol);
- break;
-
- default:
- voices[voice].initial_volume = volume_base +
- (voices[voice].midi_volume * volume_scale);
- }
-
- if (voices[voice].initial_volume > 4030)
- voices[voice].initial_volume = 4030;
-}
-
-static void compute_and_set_volume(int voice, int volume, int ramp_time)
-{
- int curr, target, rate;
- unsigned long flags;
-
- compute_volume(voice, volume);
- voices[voice].current_volume = voices[voice].initial_volume;
-
- spin_lock_irqsave(&gus_lock,flags);
- /*
- * CAUTION! Interrupts disabled. Enable them before returning
- */
-
- gus_select_voice(voice);
-
- curr = gus_read16(0x09) >> 4;
- target = voices[voice].initial_volume;
-
- if (ramp_time == INSTANT_RAMP)
- {
- gus_rampoff();
- gus_voice_volume(target);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- if (ramp_time == FAST_RAMP)
- rate = 63;
- else
- rate = 16;
- gus_ramp_rate(0, rate);
-
- if ((target - curr) / 64 == 0) /* Close enough to target. */
- {
- gus_rampoff();
- gus_voice_volume(target);
- spin_unlock_irqrestore(&gus_lock,flags);
- return;
- }
- if (target > curr)
- {
- if (target > (4095 - 65))
- target = 4095 - 65;
- gus_ramp_range(curr, target);
- gus_rampon(0x00); /* Ramp up, once, no IRQ */
- }
- else
- {
- if (target < 65)
- target = 65;
-
- gus_ramp_range(target, curr);
- gus_rampon(0x40); /* Ramp down, once, no irq */
- }
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void dynamic_volume_change(int voice)
-{
- unsigned char status;
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- status = gus_read8(0x00); /* Get voice status */
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (status & 0x03)
- return; /* Voice was not running */
-
- if (!(voices[voice].mode & WAVE_ENVELOPES))
- {
- compute_and_set_volume(voice, voices[voice].midi_volume, 1);
- return;
- }
-
- /*
- * Voice is running and has envelopes.
- */
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- status = gus_read8(0x0d); /* Ramping status */
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (status & 0x03) /* Sustain phase? */
- {
- compute_and_set_volume(voice, voices[voice].midi_volume, 1);
- return;
- }
- if (voices[voice].env_phase < 0)
- return;
-
- compute_volume(voice, voices[voice].midi_volume);
-
-}
-
-static void guswave_controller(int dev, int voice, int ctrl_num, int value)
-{
- unsigned long flags;
- unsigned long freq;
-
- if (voice < 0 || voice > 31)
- return;
-
- switch (ctrl_num)
- {
- case CTRL_PITCH_BENDER:
- voices[voice].bender = value;
-
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- {
- freq = compute_finetune(voices[voice].orig_freq, value, voices[voice].bender_range, 0);
- voices[voice].current_freq = freq;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_freq(freq);
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- break;
-
- case CTRL_PITCH_BENDER_RANGE:
- voices[voice].bender_range = value;
- break;
- case CTL_EXPRESSION:
- value /= 128;
- case CTRL_EXPRESSION:
- if (volume_method == VOL_METHOD_ADAGIO)
- {
- voices[voice].expression_vol = value;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change(voice);
- }
- break;
-
- case CTL_PAN:
- voices[voice].panning = (value * 2) - 128;
- break;
-
- case CTL_MAIN_VOLUME:
- value = (value * 100) / 16383;
-
- case CTRL_MAIN_VOLUME:
- voices[voice].main_vol = value;
- if (voices[voice].volume_irq_mode != VMODE_START_NOTE)
- dynamic_volume_change(voice);
- break;
-
- default:
- break;
- }
-}
-
-static int guswave_start_note2(int dev, int voice, int note_num, int volume)
-{
- int sample, best_sample, best_delta, delta_freq;
- int is16bits, samplep, patch, pan;
- unsigned long note_freq, base_note, freq, flags;
- unsigned char mode = 0;
-
- if (voice < 0 || voice > 31)
- {
-/* printk("GUS: Invalid voice\n");*/
- return -EINVAL;
- }
- if (note_num == 255)
- {
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- voices[voice].midi_volume = volume;
- dynamic_volume_change(voice);
- return 0;
- }
- compute_and_set_volume(voice, volume, 1);
- return 0;
- }
- if ((patch = patch_map[voice]) == -1)
- return -EINVAL;
- if ((samplep = patch_table[patch]) == NOT_SAMPLE)
- {
- return -EINVAL;
- }
- note_freq = note_to_freq(note_num);
-
- /*
- * Find a sample within a patch so that the note_freq is between low_note
- * and high_note.
- */
- sample = -1;
-
- best_sample = samplep;
- best_delta = 1000000;
- while (samplep != 0 && samplep != NOT_SAMPLE && sample == -1)
- {
- delta_freq = note_freq - samples[samplep].base_note;
- if (delta_freq < 0)
- delta_freq = -delta_freq;
- if (delta_freq < best_delta)
- {
- best_sample = samplep;
- best_delta = delta_freq;
- }
- if (samples[samplep].low_note <= note_freq &&
- note_freq <= samples[samplep].high_note)
- {
- sample = samplep;
- }
- else
- samplep = samples[samplep].key; /* Link to next sample */
- }
- if (sample == -1)
- sample = best_sample;
-
- if (sample == -1)
- {
-/* printk("GUS: Patch %d not defined for note %d\n", patch, note_num);*/
- return 0; /* Should play default patch ??? */
- }
- is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0;
- voices[voice].mode = samples[sample].mode;
- voices[voice].patch_vol = samples[sample].volume;
-
- if (iw_mode)
- gus_write8(0x15, 0x00); /* RAM, Reset voice deactivate bit of SMSI */
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- int i;
-
- for (i = 0; i < 6; i++)
- {
- voices[voice].env_rate[i] = samples[sample].env_rate[i];
- voices[voice].env_offset[i] = samples[sample].env_offset[i];
- }
- }
- sample_map[voice] = sample;
-
- if (voices[voice].fixed_pitch) /* Fixed pitch */
- {
- freq = samples[sample].base_freq;
- }
- else
- {
- base_note = samples[sample].base_note / 100;
- note_freq /= 100;
-
- freq = samples[sample].base_freq * note_freq / base_note;
- }
-
- voices[voice].orig_freq = freq;
-
- /*
- * Since the pitch bender may have been set before playing the note, we
- * have to calculate the bending now.
- */
-
- freq = compute_finetune(voices[voice].orig_freq, voices[voice].bender,
- voices[voice].bender_range, 0);
- voices[voice].current_freq = freq;
-
- pan = (samples[sample].panning + voices[voice].panning) / 32;
- pan += 7;
- if (pan < 0)
- pan = 0;
- if (pan > 15)
- pan = 15;
-
- if (samples[sample].mode & WAVE_16_BITS)
- {
- mode |= 0x04; /* 16 bits */
- if ((sample_ptrs[sample] / GUS_BANK_SIZE) !=
- ((sample_ptrs[sample] + samples[sample].len) / GUS_BANK_SIZE))
- printk(KERN_ERR "GUS: Sample address error\n");
- }
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_off();
- gus_rampoff();
-
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (voices[voice].mode & WAVE_ENVELOPES)
- {
- compute_volume(voice, volume);
- init_envelope(voice);
- }
- else
- {
- compute_and_set_volume(voice, volume, 0);
- }
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
-
- if (samples[sample].mode & WAVE_LOOP_BACK)
- gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].len -
- voices[voice].offset_pending, 0, is16bits); /* start=end */
- else
- gus_write_addr(0x0a, sample_ptrs[sample] + voices[voice].offset_pending, 0, is16bits); /* Sample start=begin */
-
- if (samples[sample].mode & WAVE_LOOPING)
- {
- mode |= 0x08;
-
- if (samples[sample].mode & WAVE_BIDIR_LOOP)
- mode |= 0x10;
-
- if (samples[sample].mode & WAVE_LOOP_BACK)
- {
- gus_write_addr(0x0a, sample_ptrs[sample] + samples[sample].loop_end -
- voices[voice].offset_pending,
- (samples[sample].fractions >> 4) & 0x0f, is16bits);
- mode |= 0x40;
- }
- gus_write_addr(0x02, sample_ptrs[sample] + samples[sample].loop_start,
- samples[sample].fractions & 0x0f, is16bits); /* Loop start location */
- gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].loop_end,
- (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */
- }
- else
- {
- mode |= 0x20; /* Loop IRQ at the end */
- voices[voice].loop_irq_mode = LMODE_FINISH; /* Ramp down at the end */
- voices[voice].loop_irq_parm = 1;
- gus_write_addr(0x02, sample_ptrs[sample], 0, is16bits); /* Loop start location */
- gus_write_addr(0x04, sample_ptrs[sample] + samples[sample].len - 1,
- (samples[sample].fractions >> 4) & 0x0f, is16bits); /* Loop end location */
- }
- gus_voice_freq(freq);
- gus_voice_balance(pan);
- gus_voice_on(mode);
- spin_unlock_irqrestore(&gus_lock,flags);
-
- return 0;
-}
-
-/*
- * New guswave_start_note by Andrew J. Robinson attempts to minimize clicking
- * when the note playing on the voice is changed. It uses volume
- * ramping.
- */
-
-static int guswave_start_note(int dev, int voice, int note_num, int volume)
-{
- unsigned long flags;
- int mode;
- int ret_val = 0;
-
- spin_lock_irqsave(&gus_lock,flags);
- if (note_num == 255)
- {
- if (voices[voice].volume_irq_mode == VMODE_START_NOTE)
- {
- voices[voice].volume_pending = volume;
- }
- else
- {
- ret_val = guswave_start_note2(dev, voice, note_num, volume);
- }
- }
- else
- {
- gus_select_voice(voice);
- mode = gus_read8(0x00);
- if (mode & 0x20)
- gus_write8(0x00, mode & 0xdf); /* No interrupt! */
-
- voices[voice].offset_pending = 0;
- voices[voice].kill_pending = 0;
- voices[voice].volume_irq_mode = 0;
- voices[voice].loop_irq_mode = 0;
-
- if (voices[voice].sample_pending >= 0)
- {
- spin_unlock_irqrestore(&gus_lock,flags); /* Run temporarily with interrupts enabled */
- guswave_set_instr(voices[voice].dev_pending, voice, voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice); /* Reselect the voice (just to be sure) */
- }
- if ((mode & 0x01) || (int) ((gus_read16(0x09) >> 4) < (unsigned) 2065))
- {
- ret_val = guswave_start_note2(dev, voice, note_num, volume);
- }
- else
- {
- voices[voice].dev_pending = dev;
- voices[voice].note_pending = note_num;
- voices[voice].volume_pending = volume;
- voices[voice].volume_irq_mode = VMODE_START_NOTE;
-
- gus_rampoff();
- gus_ramp_range(2000, 4065);
- gus_ramp_rate(0, 63); /* Fastest possible rate */
- gus_rampon(0x20 | 0x40); /* Ramp down, once, irq */
- }
- }
- spin_unlock_irqrestore(&gus_lock,flags);
- return ret_val;
-}
-
-static void guswave_reset(int dev)
-{
- int i;
-
- for (i = 0; i < 32; i++)
- {
- gus_voice_init(i);
- gus_voice_init2(i);
- }
-}
-
-static int guswave_open(int dev, int mode)
-{
- int err;
-
- if (gus_busy)
- return -EBUSY;
-
- voice_alloc->timestamp = 0;
-
- if (gus_no_wave_dma) {
- gus_no_dma = 1;
- } else {
- if ((err = DMAbuf_open_dma(gus_devnum)) < 0)
- {
- /* printk( "GUS: Loading samples without DMA\n"); */
- gus_no_dma = 1; /* Upload samples using PIO */
- }
- else
- gus_no_dma = 0;
- }
-
- init_waitqueue_head(&dram_sleeper);
- gus_busy = 1;
- active_device = GUS_DEV_WAVE;
-
- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
- gus_initialize();
- gus_reset();
- gusintr(gus_irq, (void *)gus_hw_config, NULL); /* Serve pending interrupts */
-
- return 0;
-}
-
-static void guswave_close(int dev)
-{
- gus_busy = 0;
- active_device = 0;
- gus_reset();
-
- if (!gus_no_dma)
- DMAbuf_close_dma(gus_devnum);
-}
-
-static int guswave_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
- struct patch_info patch;
- int instr;
- long sizeof_patch;
-
- unsigned long blk_sz, blk_end, left, src_offs, target;
-
- sizeof_patch = (long) &patch.data[0] - (long) &patch; /* Header size */
-
- if (format != GUS_PATCH)
- {
-/* printk("GUS Error: Invalid patch format (key) 0x%x\n", format);*/
- return -EINVAL;
- }
- if (count < sizeof_patch)
- {
-/* printk("GUS Error: Patch header too short\n");*/
- return -EINVAL;
- }
- count -= sizeof_patch;
-
- if (free_sample >= MAX_SAMPLE)
- {
-/* printk("GUS: Sample table full\n");*/
- return -ENOSPC;
- }
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
-
- if (copy_from_user(&((char *) &patch)[offs], &(addr)[offs],
- sizeof_patch - offs))
- return -EFAULT;
-
- if (patch.mode & WAVE_ROM)
- return -EINVAL;
- if (gus_mem_size == 0)
- return -ENOSPC;
-
- instr = patch.instr_no;
-
- if (instr < 0 || instr > MAX_PATCH)
- {
-/* printk(KERN_ERR "GUS: Invalid patch number %d\n", instr);*/
- return -EINVAL;
- }
- if (count < patch.len)
- {
-/* printk(KERN_ERR "GUS Warning: Patch record too short (%d<%d)\n", count, (int) patch.len);*/
- patch.len = count;
- }
- if (patch.len <= 0 || patch.len > gus_mem_size)
- {
-/* printk(KERN_ERR "GUS: Invalid sample length %d\n", (int) patch.len);*/
- return -EINVAL;
- }
- if (patch.mode & WAVE_LOOPING)
- {
- if (patch.loop_start < 0 || patch.loop_start >= patch.len)
- {
-/* printk(KERN_ERR "GUS: Invalid loop start\n");*/
- return -EINVAL;
- }
- if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len)
- {
-/* printk(KERN_ERR "GUS: Invalid loop end\n");*/
- return -EINVAL;
- }
- }
- free_mem_ptr = (free_mem_ptr + 31) & ~31; /* 32 byte alignment */
-
- if (patch.mode & WAVE_16_BITS)
- {
- /*
- * 16 bit samples must fit one 256k bank.
- */
- if (patch.len >= GUS_BANK_SIZE)
- {
-/* printk("GUS: Sample (16 bit) too long %d\n", (int) patch.len);*/
- return -ENOSPC;
- }
- if ((free_mem_ptr / GUS_BANK_SIZE) !=
- ((free_mem_ptr + patch.len) / GUS_BANK_SIZE))
- {
- unsigned long tmp_mem =
- /* Align to 256K */
- ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE;
-
- if ((tmp_mem + patch.len) > gus_mem_size)
- return -ENOSPC;
-
- free_mem_ptr = tmp_mem; /* This leaves unusable memory */
- }
- }
- if ((free_mem_ptr + patch.len) > gus_mem_size)
- return -ENOSPC;
-
- sample_ptrs[free_sample] = free_mem_ptr;
-
- /*
- * Tremolo is not possible with envelopes
- */
-
- if (patch.mode & WAVE_ENVELOPES)
- patch.mode &= ~WAVE_TREMOLO;
-
- if (!(patch.mode & WAVE_FRACTIONS))
- {
- patch.fractions = 0;
- }
- memcpy((char *) &samples[free_sample], &patch, sizeof_patch);
-
- /*
- * Link this_one sample to the list of samples for patch 'instr'.
- */
-
- samples[free_sample].key = patch_table[instr];
- patch_table[instr] = free_sample;
-
- /*
- * Use DMA to transfer the wave data to the DRAM
- */
-
- left = patch.len;
- src_offs = 0;
- target = free_mem_ptr;
-
- while (left) /* Not completely transferred yet */
- {
- blk_sz = audio_devs[gus_devnum]->dmap_out->bytes_in_use;
- if (blk_sz > left)
- blk_sz = left;
-
- /*
- * DMA cannot cross bank (256k) boundaries. Check for that.
- */
-
- blk_end = target + blk_sz;
-
- if ((target / GUS_BANK_SIZE) != (blk_end / GUS_BANK_SIZE))
- {
- /* Split the block */
- blk_end &= ~(GUS_BANK_SIZE - 1);
- blk_sz = blk_end - target;
- }
- if (gus_no_dma)
- {
- /*
- * For some reason the DMA is not possible. We have to use PIO.
- */
- long i;
- unsigned char data;
-
- for (i = 0; i < blk_sz; i++)
- {
- get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[sizeof_patch + i]));
- if (patch.mode & WAVE_UNSIGNED)
- if (!(patch.mode & WAVE_16_BITS) || (i & 0x01))
- data ^= 0x80; /* Convert to signed */
- gus_poke(target + i, data);
- }
- }
- else
- {
- unsigned long address, hold_address;
- unsigned char dma_command;
- unsigned long flags;
-
- if (audio_devs[gus_devnum]->dmap_out->raw_buf == NULL)
- {
- printk(KERN_ERR "GUS: DMA buffer == NULL\n");
- return -ENOSPC;
- }
- /*
- * OK, move now. First in and then out.
- */
-
- if (copy_from_user(audio_devs[gus_devnum]->dmap_out->raw_buf,
- &(addr)[sizeof_patch + src_offs],
- blk_sz))
- return -EFAULT;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma(gus_devnum, audio_devs[gus_devnum]->dmap_out->raw_buf_phys,
- blk_sz, DMA_MODE_WRITE);
-
- /*
- * Set the DRAM address for the wave data
- */
-
- if (iw_mode)
- {
- /* Different address translation in enhanced mode */
-
- unsigned char hi;
-
- if (gus_dma > 4)
- address = target >> 1; /* Convert to 16 bit word address */
- else
- address = target;
-
- hi = (unsigned char) ((address >> 16) & 0xf0);
- hi += (unsigned char) (address & 0x0f);
-
- gus_write16(0x42, (address >> 4) & 0xffff); /* DMA address (low) */
- gus_write8(0x50, hi);
- }
- else
- {
- address = target;
- if (audio_devs[gus_devnum]->dmap_out->dma > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
- gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
- }
-
- /*
- * Start the DMA transfer
- */
-
- dma_command = 0x21; /* IRQ enable, DMA start */
- if (patch.mode & WAVE_UNSIGNED)
- dma_command |= 0x80; /* Invert MSB */
- if (patch.mode & WAVE_16_BITS)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- if (audio_devs[gus_devnum]->dmap_out->dma > 3)
- dma_command |= 0x04; /* 16 bit DMA _channel_ */
-
- /*
- * Sleep here until the DRAM DMA done interrupt is served
- */
- active_device = GUS_DEV_WAVE;
- gus_write8(0x41, dma_command); /* Lets go luteet (=bugs) */
-
- spin_unlock_irqrestore(&gus_lock,flags); /* opens a race */
- if (!interruptible_sleep_on_timeout(&dram_sleeper, HZ))
- printk("GUS: DMA Transfer timed out\n");
- }
-
- /*
- * Now the next part
- */
-
- left -= blk_sz;
- src_offs += blk_sz;
- target += blk_sz;
-
- gus_write8(0x41, 0); /* Stop DMA */
- }
-
- free_mem_ptr += patch.len;
- free_sample++;
- return 0;
-}
-
-static void guswave_hw_control(int dev, unsigned char *event_rec)
-{
- int voice, cmd;
- unsigned short p1, p2;
- unsigned int plong;
- unsigned long flags;
-
- cmd = event_rec[2];
- voice = event_rec[3];
- p1 = *(unsigned short *) &event_rec[4];
- p2 = *(unsigned short *) &event_rec[6];
- plong = *(unsigned int *) &event_rec[4];
-
- if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) &&
- (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS))
- do_volume_irq(voice);
-
- switch (cmd)
- {
- case _GUS_NUMVOICES:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_select_max_voices(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICESAMPLE:
- guswave_set_instr(dev, voice, p1);
- break;
-
- case _GUS_VOICEON:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_on(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEOFF:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_off();
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEFADE:
- gus_voice_fade(voice);
- break;
-
- case _GUS_VOICEMODE:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_voice_mode(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEBALA:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_balance(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEFREQ:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_freq(plong);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEVOL:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_volume(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOICEVOL2: /* Just update the software voice level */
- voices[voice].initial_volume = voices[voice].current_volume = p1;
- break;
-
- case _GUS_RAMPRANGE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_ramp_range(p1, p2);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPRATE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NJET-NJET */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_ramp_rate(p1, p2);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPMODE:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NO-NO */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_ramp_mode(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPON:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* EI-EI */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- p1 &= ~0x20; /* Don't allow interrupts */
- gus_rampon(p1);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_RAMPOFF:
- if (voices[voice].mode & WAVE_ENVELOPES)
- break; /* NEJ-NEJ */
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_rampoff();
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- case _GUS_VOLUME_SCALE:
- volume_base = p1;
- volume_scale = p2;
- break;
-
- case _GUS_VOICE_POS:
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_set_voice_pos(voice, plong);
- spin_unlock_irqrestore(&gus_lock,flags);
- break;
-
- default:
- break;
- }
-}
-
-static int gus_audio_set_speed(int speed)
-{
- if (speed <= 0)
- speed = gus_audio_speed;
-
- if (speed < 4000)
- speed = 4000;
-
- if (speed > 44100)
- speed = 44100;
-
- gus_audio_speed = speed;
-
- if (only_read_access)
- {
- /* Compute nearest valid recording speed and return it */
-
- /* speed = (9878400 / (gus_audio_speed + 2)) / 16; */
- speed = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
- speed = (9878400 / (speed * 16)) - 2;
- }
- return speed;
-}
-
-static int gus_audio_set_channels(int channels)
-{
- if (!channels)
- return gus_audio_channels;
- if (channels > 2)
- channels = 2;
- if (channels < 1)
- channels = 1;
- gus_audio_channels = channels;
- return channels;
-}
-
-static int gus_audio_set_bits(int bits)
-{
- if (!bits)
- return gus_audio_bits;
-
- if (bits != 8 && bits != 16)
- bits = 8;
-
- if (only_8_bits)
- bits = 8;
-
- gus_audio_bits = bits;
- return bits;
-}
-
-static int gus_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int val;
-
- switch (cmd)
- {
- case SOUND_PCM_WRITE_RATE:
- if (get_user(val, (int __user*)arg))
- return -EFAULT;
- val = gus_audio_set_speed(val);
- break;
-
- case SOUND_PCM_READ_RATE:
- val = gus_audio_speed;
- break;
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- val = gus_audio_set_channels(val + 1) - 1;
- break;
-
- case SOUND_PCM_WRITE_CHANNELS:
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- val = gus_audio_set_channels(val);
- break;
-
- case SOUND_PCM_READ_CHANNELS:
- val = gus_audio_channels;
- break;
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- val = gus_audio_set_bits(val);
- break;
-
- case SOUND_PCM_READ_BITS:
- val = gus_audio_bits;
- break;
-
- case SOUND_PCM_WRITE_FILTER: /* NOT POSSIBLE */
- case SOUND_PCM_READ_FILTER:
- val = -EINVAL;
- break;
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *)arg);
-}
-
-static void gus_audio_reset(int dev)
-{
- if (recording_active)
- {
- gus_write8(0x49, 0x00); /* Halt recording */
- set_input_volumes();
- }
-}
-
-static int saved_iw_mode; /* A hack hack hack */
-
-static int gus_audio_open(int dev, int mode)
-{
- if (gus_busy)
- return -EBUSY;
-
- if (gus_pnp_flag && mode & OPEN_READ)
- {
-/* printk(KERN_ERR "GUS: Audio device #%d is playback only.\n", dev);*/
- return -EIO;
- }
- gus_initialize();
-
- gus_busy = 1;
- active_device = 0;
-
- saved_iw_mode = iw_mode;
- if (iw_mode)
- {
- /* There are some problems with audio in enhanced mode so disable it */
- gus_write8(0x19, gus_read8(0x19) & ~0x01); /* Disable enhanced mode */
- iw_mode = 0;
- }
-
- gus_reset();
- reset_sample_memory();
- gus_select_max_voices(14);
-
- pcm_active = 0;
- dma_active = 0;
- pcm_opened = 1;
- if (mode & OPEN_READ)
- {
- recording_active = 1;
- set_input_volumes();
- }
- only_read_access = !(mode & OPEN_WRITE);
- only_8_bits = mode & OPEN_READ;
- if (only_8_bits)
- audio_devs[dev]->format_mask = AFMT_U8;
- else
- audio_devs[dev]->format_mask = AFMT_U8 | AFMT_S16_LE;
-
- return 0;
-}
-
-static void gus_audio_close(int dev)
-{
- iw_mode = saved_iw_mode;
- gus_reset();
- gus_busy = 0;
- pcm_opened = 0;
- active_device = 0;
-
- if (recording_active)
- {
- gus_write8(0x49, 0x00); /* Halt recording */
- set_input_volumes();
- }
- recording_active = 0;
-}
-
-static void gus_audio_update_volume(void)
-{
- unsigned long flags;
- int voice;
-
- if (pcm_active && pcm_opened)
- for (voice = 0; voice < gus_audio_channels; voice++)
- {
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_rampoff();
- gus_voice_volume(1530 + (25 * gus_pcm_volume));
- gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
- spin_unlock_irqrestore(&gus_lock,flags);
- }
-}
-
-static void play_next_pcm_block(void)
-{
- unsigned long flags;
- int speed = gus_audio_speed;
- int this_one, is16bits, chn;
- unsigned long dram_loc;
- unsigned char mode[2], ramp_mode[2];
-
- if (!pcm_qlen)
- return;
-
- this_one = pcm_head;
-
- for (chn = 0; chn < gus_audio_channels; chn++)
- {
- mode[chn] = 0x00;
- ramp_mode[chn] = 0x03; /* Ramping and rollover off */
-
- if (chn == 0)
- {
- mode[chn] |= 0x20; /* Loop IRQ */
- voices[chn].loop_irq_mode = LMODE_PCM;
- }
- if (gus_audio_bits != 8)
- {
- is16bits = 1;
- mode[chn] |= 0x04; /* 16 bit data */
- }
- else
- is16bits = 0;
-
- dram_loc = this_one * pcm_bsize;
- dram_loc += chn * pcm_banksize;
-
- if (this_one == (pcm_nblk - 1)) /* Last fragment of the DRAM buffer */
- {
- mode[chn] |= 0x08; /* Enable loop */
- ramp_mode[chn] = 0x03; /* Disable rollover bit */
- }
- else
- {
- if (chn == 0)
- ramp_mode[chn] = 0x04; /* Enable rollover bit */
- }
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(chn);
- gus_voice_freq(speed);
-
- if (gus_audio_channels == 1)
- gus_voice_balance(7); /* mono */
- else if (chn == 0)
- gus_voice_balance(0); /* left */
- else
- gus_voice_balance(15); /* right */
-
- if (!pcm_active) /* Playback not already active */
- {
- /*
- * The playback was not started yet (or there has been a pause).
- * Start the voice (again) and ask for a rollover irq at the end of
- * this_one block. If this_one one is last of the buffers, use just
- * the normal loop with irq.
- */
-
- gus_voice_off();
- gus_rampoff();
- gus_voice_volume(1530 + (25 * gus_pcm_volume));
- gus_ramp_range(65, 1530 + (25 * gus_pcm_volume));
-
- gus_write_addr(0x0a, chn * pcm_banksize, 0, is16bits); /* Starting position */
- gus_write_addr(0x02, chn * pcm_banksize, 0, is16bits); /* Loop start */
-
- if (chn != 0)
- gus_write_addr(0x04, pcm_banksize + (pcm_bsize * pcm_nblk) - 1,
- 0, is16bits); /* Loop end location */
- }
- if (chn == 0)
- gus_write_addr(0x04, dram_loc + pcm_bsize - 1,
- 0, is16bits); /* Loop end location */
- else
- mode[chn] |= 0x08; /* Enable looping */
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- for (chn = 0; chn < gus_audio_channels; chn++)
- {
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(chn);
- gus_write8(0x0d, ramp_mode[chn]);
- if (iw_mode)
- gus_write8(0x15, 0x00); /* Reset voice deactivate bit of SMSI */
- gus_voice_on(mode[chn]);
- spin_unlock_irqrestore(&gus_lock,flags);
- }
- pcm_active = 1;
-}
-
-static void gus_transfer_output_block(int dev, unsigned long buf,
- int total_count, int intrflag, int chn)
-{
- /*
- * This routine transfers one block of audio data to the DRAM. In mono mode
- * it's called just once. When in stereo mode, this_one routine is called
- * once for both channels.
- *
- * The left/mono channel data is transferred to the beginning of dram and the
- * right data to the area pointed by gus_page_size.
- */
-
- int this_one, count;
- unsigned long flags;
- unsigned char dma_command;
- unsigned long address, hold_address;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- count = total_count / gus_audio_channels;
-
- if (chn == 0)
- {
- if (pcm_qlen >= pcm_nblk)
- printk(KERN_WARNING "GUS Warning: PCM buffers out of sync\n");
-
- this_one = pcm_current_block = pcm_tail;
- pcm_qlen++;
- pcm_tail = (pcm_tail + 1) % pcm_nblk;
- pcm_datasize[this_one] = count;
- }
- else
- this_one = pcm_current_block;
-
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- DMAbuf_start_dma(dev, buf + (chn * count), count, DMA_MODE_WRITE);
-
- address = this_one * pcm_bsize;
- address += chn * pcm_banksize;
-
- if (audio_devs[dev]->dmap_out->dma > 3)
- {
- hold_address = address;
- address = address >> 1;
- address &= 0x0001ffffL;
- address |= (hold_address & 0x000c0000L);
- }
- gus_write16(0x42, (address >> 4) & 0xffff); /* DRAM DMA address */
-
- dma_command = 0x21; /* IRQ enable, DMA start */
-
- if (gus_audio_bits != 8)
- dma_command |= 0x40; /* 16 bit _DATA_ */
- else
- dma_command |= 0x80; /* Invert MSB */
-
- if (audio_devs[dev]->dmap_out->dma > 3)
- dma_command |= 0x04; /* 16 bit DMA channel */
-
- gus_write8(0x41, dma_command); /* Kick start */
-
- if (chn == (gus_audio_channels - 1)) /* Last channel */
- {
- /*
- * Last (right or mono) channel data
- */
- dma_active = 1; /* DMA started. There is a unacknowledged buffer */
- active_device = GUS_DEV_PCM_DONE;
- if (!pcm_active && (pcm_qlen > 1 || count < pcm_bsize))
- {
- play_next_pcm_block();
- }
- }
- else
- {
- /*
- * Left channel data. The right channel
- * is transferred after DMA interrupt
- */
- active_device = GUS_DEV_PCM_CONTINUE;
- }
-
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static void gus_uninterleave8(char *buf, int l)
-{
-/* This routine uninterleaves 8 bit stereo output (LRLRLR->LLLRRR) */
- int i, p = 0, halfsize = l / 2;
- char *buf2 = buf + halfsize, *src = bounce_buf;
-
- memcpy(bounce_buf, buf, l);
-
- for (i = 0; i < halfsize; i++)
- {
- buf[i] = src[p++]; /* Left channel */
- buf2[i] = src[p++]; /* Right channel */
- }
-}
-
-static void gus_uninterleave16(short *buf, int l)
-{
-/* This routine uninterleaves 16 bit stereo output (LRLRLR->LLLRRR) */
- int i, p = 0, halfsize = l / 2;
- short *buf2 = buf + halfsize, *src = (short *) bounce_buf;
-
- memcpy(bounce_buf, (char *) buf, l * 2);
-
- for (i = 0; i < halfsize; i++)
- {
- buf[i] = src[p++]; /* Left channel */
- buf2[i] = src[p++]; /* Right channel */
- }
-}
-
-static void gus_audio_output_block(int dev, unsigned long buf, int total_count,
- int intrflag)
-{
- struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
- dmap->flags |= DMA_NODMA | DMA_NOTIMEOUT;
-
- pcm_current_buf = buf;
- pcm_current_count = total_count;
- pcm_current_intrflag = intrflag;
- pcm_current_dev = dev;
- if (gus_audio_channels == 2)
- {
- char *b = dmap->raw_buf + (buf - dmap->raw_buf_phys);
-
- if (gus_audio_bits == 8)
- gus_uninterleave8(b, total_count);
- else
- gus_uninterleave16((short *) b, total_count / 2);
- }
- gus_transfer_output_block(dev, buf, total_count, intrflag, 0);
-}
-
-static void gus_audio_start_input(int dev, unsigned long buf, int count,
- int intrflag)
-{
- unsigned long flags;
- unsigned char mode;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- DMAbuf_start_dma(dev, buf, count, DMA_MODE_READ);
- mode = 0xa0; /* DMA IRQ enabled, invert MSB */
-
- if (audio_devs[dev]->dmap_in->dma > 3)
- mode |= 0x04; /* 16 bit DMA channel */
- if (gus_audio_channels > 1)
- mode |= 0x02; /* Stereo */
- mode |= 0x01; /* DMA enable */
-
- gus_write8(0x49, mode);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int gus_audio_prepare_for_input(int dev, int bsize, int bcount)
-{
- unsigned int rate;
-
- gus_audio_bsize = bsize;
- audio_devs[dev]->dmap_in->flags |= DMA_NODMA;
- rate = (((9878400 + gus_audio_speed / 2) / (gus_audio_speed + 2)) + 8) / 16;
-
- gus_write8(0x48, rate & 0xff); /* Set sampling rate */
-
- if (gus_audio_bits != 8)
- {
-/* printk("GUS Error: 16 bit recording not supported\n");*/
- return -EINVAL;
- }
- return 0;
-}
-
-static int gus_audio_prepare_for_output(int dev, int bsize, int bcount)
-{
- int i;
-
- long mem_ptr, mem_size;
-
- audio_devs[dev]->dmap_out->flags |= DMA_NODMA | DMA_NOTIMEOUT;
- mem_ptr = 0;
- mem_size = gus_mem_size / gus_audio_channels;
-
- if (mem_size > (256 * 1024))
- mem_size = 256 * 1024;
-
- pcm_bsize = bsize / gus_audio_channels;
- pcm_head = pcm_tail = pcm_qlen = 0;
-
- pcm_nblk = 2; /* MAX_PCM_BUFFERS; */
- if ((pcm_bsize * pcm_nblk) > mem_size)
- pcm_nblk = mem_size / pcm_bsize;
-
- for (i = 0; i < pcm_nblk; i++)
- pcm_datasize[i] = 0;
-
- pcm_banksize = pcm_nblk * pcm_bsize;
-
- if (gus_audio_bits != 8 && pcm_banksize == (256 * 1024))
- pcm_nblk--;
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- return 0;
-}
-
-static int gus_local_qlen(int dev)
-{
- return pcm_qlen;
-}
-
-
-static struct audio_driver gus_audio_driver =
-{
- .owner = THIS_MODULE,
- .open = gus_audio_open,
- .close = gus_audio_close,
- .output_block = gus_audio_output_block,
- .start_input = gus_audio_start_input,
- .ioctl = gus_audio_ioctl,
- .prepare_for_input = gus_audio_prepare_for_input,
- .prepare_for_output = gus_audio_prepare_for_output,
- .halt_io = gus_audio_reset,
- .local_qlen = gus_local_qlen,
-};
-
-static void guswave_setup_voice(int dev, int voice, int chn)
-{
- struct channel_info *info = &synth_devs[dev]->chn_info[chn];
-
- guswave_set_instr(dev, voice, info->pgm_num);
- voices[voice].expression_vol = info->controllers[CTL_EXPRESSION]; /* Just MSB */
- voices[voice].main_vol = (info->controllers[CTL_MAIN_VOLUME] * 100) / (unsigned) 128;
- voices[voice].panning = (info->controllers[CTL_PAN] * 2) - 128;
- voices[voice].bender = 0;
- voices[voice].bender_range = info->bender_range;
-
- if (chn == 9)
- voices[voice].fixed_pitch = 1;
-}
-
-static void guswave_bender(int dev, int voice, int value)
-{
- int freq;
- unsigned long flags;
-
- voices[voice].bender = value - 8192;
- freq = compute_finetune(voices[voice].orig_freq, value - 8192, voices[voice].bender_range, 0);
- voices[voice].current_freq = freq;
-
- spin_lock_irqsave(&gus_lock,flags);
- gus_select_voice(voice);
- gus_voice_freq(freq);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int guswave_alloc(int dev, int chn, int note, struct voice_alloc_info *alloc)
-{
- int i, p, best = -1, best_time = 0x7fffffff;
-
- p = alloc->ptr;
- /*
- * First look for a completely stopped voice
- */
-
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0)
- {
- alloc->ptr = p;
- return p;
- }
- if (alloc->alloc_times[p] < best_time)
- {
- best = p;
- best_time = alloc->alloc_times[p];
- }
- p = (p + 1) % alloc->max_voice;
- }
-
- /*
- * Then look for a releasing voice
- */
-
- for (i = 0; i < alloc->max_voice; i++)
- {
- if (alloc->map[p] == 0xffff)
- {
- alloc->ptr = p;
- return p;
- }
- p = (p + 1) % alloc->max_voice;
- }
- if (best >= 0)
- p = best;
-
- alloc->ptr = p;
- return p;
-}
-
-static struct synth_operations guswave_operations =
-{
- .owner = THIS_MODULE,
- .id = "GUS",
- .info = &gus_info,
- .midi_dev = 0,
- .synth_type = SYNTH_TYPE_SAMPLE,
- .synth_subtype = SAMPLE_TYPE_GUS,
- .open = guswave_open,
- .close = guswave_close,
- .ioctl = guswave_ioctl,
- .kill_note = guswave_kill_note,
- .start_note = guswave_start_note,
- .set_instr = guswave_set_instr,
- .reset = guswave_reset,
- .hw_control = guswave_hw_control,
- .load_patch = guswave_load_patch,
- .aftertouch = guswave_aftertouch,
- .controller = guswave_controller,
- .panning = guswave_panning,
- .volume_method = guswave_volume_method,
- .bender = guswave_bender,
- .alloc_voice = guswave_alloc,
- .setup_voice = guswave_setup_voice
-};
-
-static void set_input_volumes(void)
-{
- unsigned long flags;
- unsigned char mask = 0xff & ~0x06; /* Just line out enabled */
-
- if (have_gus_max) /* Don't disturb GUS MAX */
- return;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- /*
- * Enable channels having vol > 10%
- * Note! bit 0x01 means the line in DISABLED while 0x04 means
- * the mic in ENABLED.
- */
- if (gus_line_vol > 10)
- mask &= ~0x01;
- if (gus_mic_vol > 10)
- mask |= 0x04;
-
- if (recording_active)
- {
- /*
- * Disable channel, if not selected for recording
- */
- if (!(gus_recmask & SOUND_MASK_LINE))
- mask |= 0x01;
- if (!(gus_recmask & SOUND_MASK_MIC))
- mask &= ~0x04;
- }
- mix_image &= ~0x07;
- mix_image |= mask & 0x07;
- outb((mix_image), u_Mixer);
-
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
- SOUND_MASK_SYNTH|SOUND_MASK_PCM)
-
-int gus_default_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int vol, val;
-
- if (((cmd >> 8) & 0xff) != 'M')
- return -EINVAL;
-
- if (!access_ok(VERIFY_WRITE, arg, sizeof(int)))
- return -EFAULT;
-
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- {
- if (__get_user(val, (int __user *) arg))
- return -EFAULT;
-
- switch (cmd & 0xff)
- {
- case SOUND_MIXER_RECSRC:
- gus_recmask = val & MIX_DEVS;
- if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
- gus_recmask = SOUND_MASK_MIC;
- /* Note! Input volumes are updated during next open for recording */
- val = gus_recmask;
- break;
-
- case SOUND_MIXER_MIC:
- vol = val & 0xff;
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- gus_mic_vol = vol;
- set_input_volumes();
- val = vol | (vol << 8);
- break;
-
- case SOUND_MIXER_LINE:
- vol = val & 0xff;
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- gus_line_vol = vol;
- set_input_volumes();
- val = vol | (vol << 8);
- break;
-
- case SOUND_MIXER_PCM:
- gus_pcm_volume = val & 0xff;
- if (gus_pcm_volume < 0)
- gus_pcm_volume = 0;
- if (gus_pcm_volume > 100)
- gus_pcm_volume = 100;
- gus_audio_update_volume();
- val = gus_pcm_volume | (gus_pcm_volume << 8);
- break;
-
- case SOUND_MIXER_SYNTH:
- gus_wave_volume = val & 0xff;
- if (gus_wave_volume < 0)
- gus_wave_volume = 0;
- if (gus_wave_volume > 100)
- gus_wave_volume = 100;
- if (active_device == GUS_DEV_WAVE)
- {
- int voice;
- for (voice = 0; voice < nr_voices; voice++)
- dynamic_volume_change(voice); /* Apply the new vol */
- }
- val = gus_wave_volume | (gus_wave_volume << 8);
- break;
-
- default:
- return -EINVAL;
- }
- }
- else
- {
- switch (cmd & 0xff)
- {
- /*
- * Return parameters
- */
- case SOUND_MIXER_RECSRC:
- val = gus_recmask;
- break;
-
- case SOUND_MIXER_DEVMASK:
- val = MIX_DEVS;
- break;
-
- case SOUND_MIXER_STEREODEVS:
- val = 0;
- break;
-
- case SOUND_MIXER_RECMASK:
- val = SOUND_MASK_MIC | SOUND_MASK_LINE;
- break;
-
- case SOUND_MIXER_CAPS:
- val = 0;
- break;
-
- case SOUND_MIXER_MIC:
- val = gus_mic_vol | (gus_mic_vol << 8);
- break;
-
- case SOUND_MIXER_LINE:
- val = gus_line_vol | (gus_line_vol << 8);
- break;
-
- case SOUND_MIXER_PCM:
- val = gus_pcm_volume | (gus_pcm_volume << 8);
- break;
-
- case SOUND_MIXER_SYNTH:
- val = gus_wave_volume | (gus_wave_volume << 8);
- break;
-
- default:
- return -EINVAL;
- }
- }
- return __put_user(val, (int __user *)arg);
-}
-
-static struct mixer_operations gus_mixer_operations =
-{
- .owner = THIS_MODULE,
- .id = "GUS",
- .name = "Gravis Ultrasound",
- .ioctl = gus_default_mixer_ioctl
-};
-
-static int __init gus_default_mixer_init(void)
-{
- int n;
-
- if ((n = sound_alloc_mixerdev()) != -1)
- {
- /*
- * Don't install if there is another
- * mixer
- */
- mixer_devs[n] = &gus_mixer_operations;
- }
- if (have_gus_max)
- {
- /*
- * Enable all mixer channels on the GF1 side. Otherwise recording will
- * not be possible using GUS MAX.
- */
- mix_image &= ~0x07;
- mix_image |= 0x04; /* All channels enabled */
- outb((mix_image), u_Mixer);
- }
- return n;
-}
-
-void __init gus_wave_init(struct address_info *hw_config)
-{
- unsigned long flags;
- unsigned char val;
- char *model_num = "2.4";
- char tmp[64];
- int gus_type = 0x24; /* 2.4 */
-
- int irq = hw_config->irq, dma = hw_config->dma, dma2 = hw_config->dma2;
- int sdev;
-
- hw_config->slots[0] = -1; /* No wave */
- hw_config->slots[1] = -1; /* No ad1848 */
- hw_config->slots[4] = -1; /* No audio */
- hw_config->slots[5] = -1; /* No mixer */
-
- if (!gus_pnp_flag)
- {
- if (irq < 0 || irq > 15)
- {
- printk(KERN_ERR "ERROR! Invalid IRQ#%d. GUS Disabled", irq);
- return;
- }
- }
-
- if (dma < 0 || dma > 7 || dma == 4)
- {
- printk(KERN_ERR "ERROR! Invalid DMA#%d. GUS Disabled", dma);
- return;
- }
- gus_irq = irq;
- gus_dma = dma;
- gus_dma2 = dma2;
- gus_hw_config = hw_config;
-
- if (gus_dma2 == -1)
- gus_dma2 = dma;
-
- /*
- * Try to identify the GUS model.
- *
- * Versions < 3.6 don't have the digital ASIC. Try to probe it first.
- */
-
- spin_lock_irqsave(&gus_lock,flags);
- outb((0x20), gus_base + 0x0f);
- val = inb(gus_base + 0x0f);
- spin_unlock_irqrestore(&gus_lock,flags);
-
- if (gus_pnp_flag || (val != 0xff && (val & 0x06))) /* Should be 0x02?? */
- {
- int ad_flags = 0;
-
- if (gus_pnp_flag)
- ad_flags = 0x12345678; /* Interwave "magic" */
- /*
- * It has the digital ASIC so the card is at least v3.4.
- * Next try to detect the true model.
- */
-
- if (gus_pnp_flag) /* Hack hack hack */
- val = 10;
- else
- val = inb(u_MixSelect);
-
- /*
- * Value 255 means pre-3.7 which don't have mixer.
- * Values 5 thru 9 mean v3.7 which has a ICS2101 mixer.
- * 10 and above is GUS MAX which has the CS4231 codec/mixer.
- *
- */
-
- if (val == 255 || val < 5)
- {
- model_num = "3.4";
- gus_type = 0x34;
- }
- else if (val < 10)
- {
- model_num = "3.7";
- gus_type = 0x37;
- mixer_type = ICS2101;
- request_region(u_MixSelect, 1, "GUS mixer");
- }
- else
- {
- struct resource *ports;
- ports = request_region(gus_base + 0x10c, 4, "ad1848");
- model_num = "MAX";
- gus_type = 0x40;
- mixer_type = CS4231;
-#ifdef CONFIG_SOUND_GUSMAX
- {
- unsigned char max_config = 0x40; /* Codec enable */
-
- if (gus_dma2 == -1)
- gus_dma2 = gus_dma;
-
- if (gus_dma > 3)
- max_config |= 0x10; /* 16 bit capture DMA */
-
- if (gus_dma2 > 3)
- max_config |= 0x20; /* 16 bit playback DMA */
-
- max_config |= (gus_base >> 4) & 0x0f; /* Extract the X from 2X0 */
-
- outb((max_config), gus_base + 0x106); /* UltraMax control */
- }
-
- if (!ports)
- goto no_cs4231;
-
- if (ad1848_detect(ports, &ad_flags, hw_config->osp))
- {
- char *name = "GUS MAX";
- int old_num_mixers = num_mixers;
-
- if (gus_pnp_flag)
- name = "GUS PnP";
-
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- have_gus_max = 1;
- if (hw_config->name)
- name = hw_config->name;
-
- hw_config->slots[1] = ad1848_init(name, ports,
- -irq, gus_dma2, /* Playback DMA */
- gus_dma, /* Capture DMA */
- 1, /* Share DMA channels with GF1 */
- hw_config->osp,
- THIS_MODULE);
-
- if (num_mixers > old_num_mixers)
- {
- /* GUS has it's own mixer map */
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_SYNTH);
- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_CD);
- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
- }
- }
- else {
- release_region(gus_base + 0x10c, 4);
- no_cs4231:
- printk(KERN_WARNING "GUS: No CS4231 ??");
- }
-#else
- printk(KERN_ERR "GUS MAX found, but not compiled in\n");
-#endif
- }
- }
- else
- {
- /*
- * ASIC not detected so the card must be 2.2 or 2.4.
- * There could still be the 16-bit/mixer daughter card.
- */
- }
-
- if (hw_config->name)
- snprintf(tmp, sizeof(tmp), "%s (%dk)", hw_config->name,
- (int) gus_mem_size / 1024);
- else if (gus_pnp_flag)
- snprintf(tmp, sizeof(tmp), "Gravis UltraSound PnP (%dk)",
- (int) gus_mem_size / 1024);
- else
- snprintf(tmp, sizeof(tmp), "Gravis UltraSound %s (%dk)", model_num,
- (int) gus_mem_size / 1024);
-
-
- samples = (struct patch_info *)vmalloc((MAX_SAMPLE + 1) * sizeof(*samples));
- if (samples == NULL)
- {
- printk(KERN_WARNING "gus_init: Cant allocate memory for instrument tables\n");
- return;
- }
- conf_printf(tmp, hw_config);
- strlcpy(gus_info.name, tmp, sizeof(gus_info.name));
-
- if ((sdev = sound_alloc_synthdev()) == -1)
- printk(KERN_WARNING "gus_init: Too many synthesizers\n");
- else
- {
- voice_alloc = &guswave_operations.alloc;
- if (iw_mode)
- guswave_operations.id = "IWAVE";
- hw_config->slots[0] = sdev;
- synth_devs[sdev] = &guswave_operations;
- sequencer_init();
- gus_tmr_install(gus_base + 8);
- }
-
- reset_sample_memory();
-
- gus_initialize();
-
- if ((gus_mem_size > 0) && !gus_no_wave_dma)
- {
- hw_config->slots[4] = -1;
- if ((gus_devnum = sound_install_audiodrv(AUDIO_DRIVER_VERSION,
- "Ultrasound",
- &gus_audio_driver,
- sizeof(struct audio_driver),
- NEEDS_RESTART |
- ((!iw_mode && dma2 != dma && dma2 != -1) ?
- DMA_DUPLEX : 0),
- AFMT_U8 | AFMT_S16_LE,
- NULL, dma, dma2)) < 0)
- {
- return;
- }
-
- hw_config->slots[4] = gus_devnum;
- audio_devs[gus_devnum]->min_fragment = 9; /* 512k */
- audio_devs[gus_devnum]->max_fragment = 11; /* 8k (must match size of bounce_buf */
- audio_devs[gus_devnum]->mixer_dev = -1; /* Next mixer# */
- audio_devs[gus_devnum]->flags |= DMA_HARDSTOP;
- }
-
- /*
- * Mixer dependent initialization.
- */
-
- switch (mixer_type)
- {
- case ICS2101:
- gus_mic_vol = gus_line_vol = gus_pcm_volume = 100;
- gus_wave_volume = 90;
- request_region(u_MixSelect, 1, "GUS mixer");
- hw_config->slots[5] = ics2101_mixer_init();
- audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */
- return;
-
- case CS4231:
- /* Initialized elsewhere (ad1848.c) */
- default:
- hw_config->slots[5] = gus_default_mixer_init();
- audio_devs[gus_devnum]->mixer_dev = hw_config->slots[5]; /* Next mixer# */
- return;
- }
-}
-
-void __exit gus_wave_unload(struct address_info *hw_config)
-{
-#ifdef CONFIG_SOUND_GUSMAX
- if (have_gus_max)
- {
- ad1848_unload(gus_base + 0x10c,
- -gus_irq,
- gus_dma2, /* Playback DMA */
- gus_dma, /* Capture DMA */
- 1); /* Share DMA channels with GF1 */
- }
-#endif
-
- if (mixer_type == ICS2101)
- {
- release_region(u_MixSelect, 1);
- }
- if (hw_config->slots[0] != -1)
- sound_unload_synthdev(hw_config->slots[0]);
- if (hw_config->slots[1] != -1)
- sound_unload_audiodev(hw_config->slots[1]);
- if (hw_config->slots[2] != -1)
- sound_unload_mididev(hw_config->slots[2]);
- if (hw_config->slots[4] != -1)
- sound_unload_audiodev(hw_config->slots[4]);
- if (hw_config->slots[5] != -1)
- sound_unload_mixerdev(hw_config->slots[5]);
-
- vfree(samples);
- samples=NULL;
-}
-/* called in interrupt context */
-static void do_loop_irq(int voice)
-{
- unsigned char tmp;
- int mode, parm;
-
- spin_lock(&gus_lock);
- gus_select_voice(voice);
-
- tmp = gus_read8(0x00);
- tmp &= ~0x20; /*
- * Disable wave IRQ for this_one voice
- */
- gus_write8(0x00, tmp);
-
- if (tmp & 0x03) /* Voice stopped */
- voice_alloc->map[voice] = 0;
-
- mode = voices[voice].loop_irq_mode;
- voices[voice].loop_irq_mode = 0;
- parm = voices[voice].loop_irq_parm;
-
- switch (mode)
- {
- case LMODE_FINISH: /*
- * Final loop finished, shoot volume down
- */
-
- if ((int) (gus_read16(0x09) >> 4) < 100) /*
- * Get current volume
- */
- {
- gus_voice_off();
- gus_rampoff();
- gus_voice_init(voice);
- break;
- }
- gus_ramp_range(65, 4065);
- gus_ramp_rate(0, 63); /*
- * Fastest possible rate
- */
- gus_rampon(0x20 | 0x40); /*
- * Ramp down, once, irq
- */
- voices[voice].volume_irq_mode = VMODE_HALT;
- break;
-
- case LMODE_PCM_STOP:
- pcm_active = 0; /* Signal to the play_next_pcm_block routine */
- case LMODE_PCM:
- {
- pcm_qlen--;
- pcm_head = (pcm_head + 1) % pcm_nblk;
- if (pcm_qlen && pcm_active)
- {
- play_next_pcm_block();
- }
- else
- {
- /* Underrun. Just stop the voice */
- gus_select_voice(0); /* Left channel */
- gus_voice_off();
- gus_rampoff();
- gus_select_voice(1); /* Right channel */
- gus_voice_off();
- gus_rampoff();
- pcm_active = 0;
- }
-
- /*
- * If the queue was full before this interrupt, the DMA transfer was
- * suspended. Let it continue now.
- */
-
- if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
- DMAbuf_outputintr(gus_devnum, 0);
- }
- break;
-
- default:
- break;
- }
- spin_unlock(&gus_lock);
-}
-
-static void do_volume_irq(int voice)
-{
- unsigned char tmp;
- int mode, parm;
- unsigned long flags;
-
- spin_lock_irqsave(&gus_lock,flags);
-
- gus_select_voice(voice);
- tmp = gus_read8(0x0d);
- tmp &= ~0x20; /*
- * Disable volume ramp IRQ
- */
- gus_write8(0x0d, tmp);
-
- mode = voices[voice].volume_irq_mode;
- voices[voice].volume_irq_mode = 0;
- parm = voices[voice].volume_irq_parm;
-
- switch (mode)
- {
- case VMODE_HALT: /* Decay phase finished */
- if (iw_mode)
- gus_write8(0x15, 0x02); /* Set voice deactivate bit of SMSI */
- spin_unlock_irqrestore(&gus_lock,flags);
- gus_voice_init(voice);
- break;
-
- case VMODE_ENVELOPE:
- gus_rampoff();
- spin_unlock_irqrestore(&gus_lock,flags);
- step_envelope(voice);
- break;
-
- case VMODE_START_NOTE:
- spin_unlock_irqrestore(&gus_lock,flags);
- guswave_start_note2(voices[voice].dev_pending, voice,
- voices[voice].note_pending, voices[voice].volume_pending);
- if (voices[voice].kill_pending)
- guswave_kill_note(voices[voice].dev_pending, voice,
- voices[voice].note_pending, 0);
-
- if (voices[voice].sample_pending >= 0)
- {
- guswave_set_instr(voices[voice].dev_pending, voice,
- voices[voice].sample_pending);
- voices[voice].sample_pending = -1;
- }
- break;
-
- default:
- spin_unlock_irqrestore(&gus_lock,flags);
- }
-}
-/* called in irq context */
-void gus_voice_irq(void)
-{
- unsigned long wave_ignore = 0, volume_ignore = 0;
- unsigned long voice_bit;
-
- unsigned char src, voice;
-
- while (1)
- {
- src = gus_read8(0x0f); /*
- * Get source info
- */
- voice = src & 0x1f;
- src &= 0xc0;
-
- if (src == (0x80 | 0x40))
- return; /*
- * No interrupt
- */
-
- voice_bit = 1 << voice;
-
- if (!(src & 0x80)) /*
- * Wave IRQ pending
- */
- if (!(wave_ignore & voice_bit) && (int) voice < nr_voices) /*
- * Not done
- * yet
- */
- {
- wave_ignore |= voice_bit;
- do_loop_irq(voice);
- }
- if (!(src & 0x40)) /*
- * Volume IRQ pending
- */
- if (!(volume_ignore & voice_bit) && (int) voice < nr_voices) /*
- * Not done
- * yet
- */
- {
- volume_ignore |= voice_bit;
- do_volume_irq(voice);
- }
- }
-}
-
-void guswave_dma_irq(void)
-{
- unsigned char status;
-
- status = gus_look8(0x41); /* Get DMA IRQ Status */
- if (status & 0x40) /* DMA interrupt pending */
- switch (active_device)
- {
- case GUS_DEV_WAVE:
- wake_up(&dram_sleeper);
- break;
-
- case GUS_DEV_PCM_CONTINUE: /* Left channel data transferred */
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- gus_transfer_output_block(pcm_current_dev, pcm_current_buf,
- pcm_current_count,
- pcm_current_intrflag, 1);
- break;
-
- case GUS_DEV_PCM_DONE: /* Right or mono channel data transferred */
- gus_write8(0x41, 0); /* Disable GF1 DMA */
- if (pcm_qlen < pcm_nblk)
- {
- dma_active = 0;
- if (gus_busy)
- {
- if (audio_devs[gus_devnum]->dmap_out->qlen > 0)
- DMAbuf_outputintr(gus_devnum, 0);
- }
- }
- break;
-
- default:
- break;
- }
- status = gus_look8(0x49); /*
- * Get Sampling IRQ Status
- */
- if (status & 0x40) /*
- * Sampling Irq pending
- */
- {
- DMAbuf_inputintr(gus_devnum);
- }
-}
-
-/*
- * Timer stuff
- */
-
-static volatile int select_addr, data_addr;
-static volatile int curr_timer;
-
-void gus_timer_command(unsigned int addr, unsigned int val)
-{
- int i;
-
- outb(((unsigned char) (addr & 0xff)), select_addr);
-
- for (i = 0; i < 2; i++)
- inb(select_addr);
-
- outb(((unsigned char) (val & 0xff)), data_addr);
-
- for (i = 0; i < 2; i++)
- inb(select_addr);
-}
-
-static void arm_timer(int timer, unsigned int interval)
-{
- curr_timer = timer;
-
- if (timer == 1)
- {
- gus_write8(0x46, 256 - interval); /* Set counter for timer 1 */
- gus_write8(0x45, 0x04); /* Enable timer 1 IRQ */
- gus_timer_command(0x04, 0x01); /* Start timer 1 */
- }
- else
- {
- gus_write8(0x47, 256 - interval); /* Set counter for timer 2 */
- gus_write8(0x45, 0x08); /* Enable timer 2 IRQ */
- gus_timer_command(0x04, 0x02); /* Start timer 2 */
- }
-
- gus_timer_enabled = 1;
-}
-
-static unsigned int gus_tmr_start(int dev, unsigned int usecs_per_tick)
-{
- int timer_no, resolution;
- int divisor;
-
- if (usecs_per_tick > (256 * 80))
- {
- timer_no = 2;
- resolution = 320; /* usec */
- }
- else
- {
- timer_no = 1;
- resolution = 80; /* usec */
- }
- divisor = (usecs_per_tick + (resolution / 2)) / resolution;
- arm_timer(timer_no, divisor);
-
- return divisor * resolution;
-}
-
-static void gus_tmr_disable(int dev)
-{
- gus_write8(0x45, 0); /* Disable both timers */
- gus_timer_enabled = 0;
-}
-
-static void gus_tmr_restart(int dev)
-{
- if (curr_timer == 1)
- gus_write8(0x45, 0x04); /* Start timer 1 again */
- else
- gus_write8(0x45, 0x08); /* Start timer 2 again */
- gus_timer_enabled = 1;
-}
-
-static struct sound_lowlev_timer gus_tmr =
-{
- 0,
- 1,
- gus_tmr_start,
- gus_tmr_disable,
- gus_tmr_restart
-};
-
-static void gus_tmr_install(int io_base)
-{
- struct sound_lowlev_timer *tmr;
-
- select_addr = io_base;
- data_addr = io_base + 1;
-
- tmr = &gus_tmr;
-
-#ifdef THIS_GETS_FIXED
- sound_timer_init(&gus_tmr, "GUS");
-#endif
-}
diff --git a/sound/oss/hal2.c b/sound/oss/hal2.c
index 80ab402dae9a..784bdd707055 100644
--- a/sound/oss/hal2.c
+++ b/sound/oss/hal2.c
@@ -370,9 +370,9 @@ static void hal2_adc_interrupt(struct hal2_codec *adc)
wake_up(&adc->dma_wait);
}
-static irqreturn_t hal2_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t hal2_interrupt(int irq, void *dev_id)
{
- struct hal2_card *hal2 = (struct hal2_card*)dev_id;
+ struct hal2_card *hal2 = dev_id;
irqreturn_t ret = IRQ_NONE;
/* decide what caused this interrupt */
diff --git a/sound/oss/harmony.c b/sound/oss/harmony.c
deleted file mode 100644
index 591683c55f27..000000000000
--- a/sound/oss/harmony.c
+++ /dev/null
@@ -1,1330 +0,0 @@
-/*
- drivers/sound/harmony.c
-
- This is a sound driver for ASP's and Lasi's Harmony sound chip
- and is unlikely to be used for anything other than on a HP PA-RISC.
-
- Harmony is found in HP 712s, 715/new and many other GSC based machines.
- On older 715 machines you'll find the technically identical chip
- called 'Vivace'. Both Harmony and Vicace are supported by this driver.
-
- Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@onefishtwo.ca>
- Copyright 2000-2003 (c) Helge Deller <deller@gmx.de>
- Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr>
- Copyright 2001 (c) Jean-Christophe Vaugeois <vaugeoij@esiee.fr>
- Copyright 2004 (c) Stuart Brady <sdbrady@ntlworld.com>
-
-
-TODO:
- - fix SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls to
- return the real values
- - add private ioctl for selecting line- or microphone input
- (only one of them is available at the same time)
- - add module parameters
- - implement mmap functionality
- - implement gain meter ?
- - ...
-*/
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/pci.h>
-
-#include <asm/parisc-device.h>
-#include <asm/io.h>
-
-#include "sound_config.h"
-
-
-#define PFX "harmony: "
-#define HARMONY_VERSION "V0.9a"
-
-#undef DEBUG
-#ifdef DEBUG
-# define DPRINTK printk
-#else
-# define DPRINTK(x,...)
-#endif
-
-
-#define MAX_BUFS 10 /* maximum number of rotating buffers */
-#define HARMONY_BUF_SIZE 4096 /* needs to be a multiple of PAGE_SIZE (4096)! */
-
-#define CNTL_C 0x80000000
-#define CNTL_ST 0x00000020
-#define CNTL_44100 0x00000015 /* HARMONY_SR_44KHZ */
-#define CNTL_8000 0x00000008 /* HARMONY_SR_8KHZ */
-
-#define GAINCTL_HE 0x08000000
-#define GAINCTL_LE 0x04000000
-#define GAINCTL_SE 0x02000000
-
-#define DSTATUS_PN 0x00000200
-#define DSTATUS_RN 0x00000002
-
-#define DSTATUS_IE 0x80000000
-
-#define HARMONY_DF_16BIT_LINEAR 0
-#define HARMONY_DF_8BIT_ULAW 1
-#define HARMONY_DF_8BIT_ALAW 2
-
-#define HARMONY_SS_MONO 0
-#define HARMONY_SS_STEREO 1
-
-#define HARMONY_SR_8KHZ 0x08
-#define HARMONY_SR_16KHZ 0x09
-#define HARMONY_SR_27KHZ 0x0A
-#define HARMONY_SR_32KHZ 0x0B
-#define HARMONY_SR_48KHZ 0x0E
-#define HARMONY_SR_9KHZ 0x0F
-#define HARMONY_SR_5KHZ 0x10
-#define HARMONY_SR_11KHZ 0x11
-#define HARMONY_SR_18KHZ 0x12
-#define HARMONY_SR_22KHZ 0x13
-#define HARMONY_SR_37KHZ 0x14
-#define HARMONY_SR_44KHZ 0x15
-#define HARMONY_SR_33KHZ 0x16
-#define HARMONY_SR_6KHZ 0x17
-
-/*
- * Some magics numbers used to auto-detect file formats
- */
-
-#define HARMONY_MAGIC_8B_ULAW 1
-#define HARMONY_MAGIC_8B_ALAW 27
-#define HARMONY_MAGIC_16B_LINEAR 3
-#define HARMONY_MAGIC_MONO 1
-#define HARMONY_MAGIC_STEREO 2
-
-/*
- * Channels Positions in mixer register
- */
-
-#define GAIN_HE_SHIFT 27
-#define GAIN_HE_MASK ( 1 << GAIN_HE_SHIFT)
-#define GAIN_LE_SHIFT 26
-#define GAIN_LE_MASK ( 1 << GAIN_LE_SHIFT)
-#define GAIN_SE_SHIFT 25
-#define GAIN_SE_MASK ( 1 << GAIN_SE_SHIFT)
-#define GAIN_IS_SHIFT 24
-#define GAIN_IS_MASK ( 1 << GAIN_IS_SHIFT)
-#define GAIN_MA_SHIFT 20
-#define GAIN_MA_MASK ( 0x0f << GAIN_MA_SHIFT)
-#define GAIN_LI_SHIFT 16
-#define GAIN_LI_MASK ( 0x0f << GAIN_LI_SHIFT)
-#define GAIN_RI_SHIFT 12
-#define GAIN_RI_MASK ( 0x0f << GAIN_RI_SHIFT)
-#define GAIN_LO_SHIFT 6
-#define GAIN_LO_MASK ( 0x3f << GAIN_LO_SHIFT)
-#define GAIN_RO_SHIFT 0
-#define GAIN_RO_MASK ( 0x3f << GAIN_RO_SHIFT)
-
-
-#define MAX_OUTPUT_LEVEL (GAIN_RO_MASK >> GAIN_RO_SHIFT)
-#define MAX_INPUT_LEVEL (GAIN_RI_MASK >> GAIN_RI_SHIFT)
-#define MAX_MONITOR_LEVEL (GAIN_MA_MASK >> GAIN_MA_SHIFT)
-
-#define MIXER_INTERNAL SOUND_MIXER_LINE1
-#define MIXER_LINEOUT SOUND_MIXER_LINE2
-#define MIXER_HEADPHONES SOUND_MIXER_LINE3
-
-#define MASK_INTERNAL SOUND_MASK_LINE1
-#define MASK_LINEOUT SOUND_MASK_LINE2
-#define MASK_HEADPHONES SOUND_MASK_LINE3
-
-/*
- * Channels Mask in mixer register
- */
-
-#define GAIN_TOTAL_SILENCE 0x00F00FFF
-#define GAIN_DEFAULT 0x0FF00000
-
-
-struct harmony_hpa {
- u8 unused000;
- u8 id;
- u8 teleshare_id;
- u8 unused003;
- u32 reset;
- u32 cntl;
- u32 gainctl;
- u32 pnxtadd;
- u32 pcuradd;
- u32 rnxtadd;
- u32 rcuradd;
- u32 dstatus;
- u32 ov;
- u32 pio;
- u32 unused02c;
- u32 unused030[3];
- u32 diag;
-};
-
-struct harmony_dev {
- struct harmony_hpa *hpa;
- struct parisc_device *dev;
- u32 current_gain;
- u32 dac_rate; /* 8000 ... 48000 (Hz) */
- u8 data_format; /* HARMONY_DF_xx_BIT_xxx */
- u8 sample_rate; /* HARMONY_SR_xx_KHZ */
- u8 stereo_select; /* HARMONY_SS_MONO or HARMONY_SS_STEREO */
- int format_initialized :1;
- int suspended_playing :1;
- int suspended_recording :1;
-
- int blocked_playing :1;
- int blocked_recording :1;
- int audio_open :1;
- int mixer_open :1;
-
- wait_queue_head_t wq_play, wq_record;
- int first_filled_play; /* first buffer containing data (next to play) */
- int nb_filled_play;
- int play_offset;
- int first_filled_record;
- int nb_filled_record;
-
- int dsp_unit, mixer_unit;
-};
-
-
-static struct harmony_dev harmony;
-
-
-/*
- * Dynamic sound buffer allocation and DMA memory
- */
-
-struct harmony_buffer {
- unsigned char *addr;
- dma_addr_t dma_handle;
- int dma_coherent; /* Zero if dma_alloc_coherent() fails */
- unsigned int len;
-};
-
-/*
- * Harmony memory buffers
- */
-
-static struct harmony_buffer played_buf, recorded_buf, silent, graveyard;
-
-
-#define CHECK_WBACK_INV_OFFSET(b,offset,len) \
- do { if (!b.dma_coherent) \
- dma_cache_wback_inv((unsigned long)b.addr+offset,len); \
- } while (0)
-
-
-static int __init harmony_alloc_buffer(struct harmony_buffer *b,
- unsigned int buffer_count)
-{
- b->len = buffer_count * HARMONY_BUF_SIZE;
- b->addr = dma_alloc_coherent(&harmony.dev->dev,
- b->len, &b->dma_handle, GFP_KERNEL|GFP_DMA);
- if (b->addr && b->dma_handle) {
- b->dma_coherent = 1;
- DPRINTK(KERN_INFO PFX "coherent memory: 0x%lx, played_buf: 0x%lx\n",
- (unsigned long)b->dma_handle, (unsigned long)b->addr);
- } else {
- b->dma_coherent = 0;
- /* kmalloc()ed memory will HPMC on ccio machines ! */
- b->addr = kmalloc(b->len, GFP_KERNEL);
- if (!b->addr) {
- printk(KERN_ERR PFX "couldn't allocate memory\n");
- return -EBUSY;
- }
- b->dma_handle = __pa(b->addr);
- }
- return 0;
-}
-
-static void __exit harmony_free_buffer(struct harmony_buffer *b)
-{
- if (!b->addr)
- return;
-
- if (b->dma_coherent)
- dma_free_coherent(&harmony.dev->dev,
- b->len, b->addr, b->dma_handle);
- else
- kfree(b->addr);
-
- memset(b, 0, sizeof(*b));
-}
-
-
-
-/*
- * Low-Level sound-chip programming
- */
-
-static void __inline__ harmony_wait_CNTL(void)
-{
- /* Wait until we're out of control mode */
- while (gsc_readl(&harmony.hpa->cntl) & CNTL_C)
- /* wait */ ;
-}
-
-
-static void harmony_update_control(void)
-{
- u32 default_cntl;
-
- /* Set CNTL */
- default_cntl = (CNTL_C | /* The C bit */
- (harmony.data_format << 6) | /* Set the data format */
- (harmony.stereo_select << 5) | /* Stereo select */
- (harmony.sample_rate)); /* Set sample rate */
- harmony.format_initialized = 1;
-
- /* initialize CNTL */
- gsc_writel(default_cntl, &harmony.hpa->cntl);
-}
-
-static void harmony_set_control(u8 data_format, u8 sample_rate, u8 stereo_select)
-{
- harmony.sample_rate = sample_rate;
- harmony.data_format = data_format;
- harmony.stereo_select = stereo_select;
- harmony_update_control();
-}
-
-static void harmony_set_rate(u8 data_rate)
-{
- harmony.sample_rate = data_rate;
- harmony_update_control();
-}
-
-static int harmony_detect_rate(int *freq)
-{
- int newrate;
- switch (*freq) {
- case 8000: newrate = HARMONY_SR_8KHZ; break;
- case 16000: newrate = HARMONY_SR_16KHZ; break;
- case 27428: newrate = HARMONY_SR_27KHZ; break;
- case 32000: newrate = HARMONY_SR_32KHZ; break;
- case 48000: newrate = HARMONY_SR_48KHZ; break;
- case 9600: newrate = HARMONY_SR_9KHZ; break;
- case 5512: newrate = HARMONY_SR_5KHZ; break;
- case 11025: newrate = HARMONY_SR_11KHZ; break;
- case 18900: newrate = HARMONY_SR_18KHZ; break;
- case 22050: newrate = HARMONY_SR_22KHZ; break;
- case 37800: newrate = HARMONY_SR_37KHZ; break;
- case 44100: newrate = HARMONY_SR_44KHZ; break;
- case 33075: newrate = HARMONY_SR_33KHZ; break;
- case 6615: newrate = HARMONY_SR_6KHZ; break;
- default: newrate = HARMONY_SR_8KHZ;
- *freq = 8000; break;
- }
- return newrate;
-}
-
-static void harmony_set_format(u8 data_format)
-{
- harmony.data_format = data_format;
- harmony_update_control();
-}
-
-static void harmony_set_stereo(u8 stereo_select)
-{
- harmony.stereo_select = stereo_select;
- harmony_update_control();
-}
-
-static void harmony_disable_interrupts(void)
-{
- harmony_wait_CNTL();
- gsc_writel(0, &harmony.hpa->dstatus);
-}
-
-static void harmony_enable_interrupts(void)
-{
- harmony_wait_CNTL();
- gsc_writel(DSTATUS_IE, &harmony.hpa->dstatus);
-}
-
-/*
- * harmony_silence()
- *
- * This subroutine fills in a buffer starting at location start and
- * silences for length bytes. This references the current
- * configuration of the audio format.
- *
- */
-
-static void harmony_silence(struct harmony_buffer *buffer, int start, int length)
-{
- u8 silence_char;
-
- /* Despite what you hear, silence is different in
- different audio formats. */
- switch (harmony.data_format) {
- case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break;
- case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break;
- case HARMONY_DF_16BIT_LINEAR: /* fall through */
- default: silence_char = 0;
- }
-
- memset(buffer->addr+start, silence_char, length);
-}
-
-
-static int harmony_audio_open(struct inode *inode, struct file *file)
-{
- if (harmony.audio_open)
- return -EBUSY;
-
- harmony.audio_open = 1;
- harmony.suspended_playing = harmony.suspended_recording = 1;
- harmony.blocked_playing = harmony.blocked_recording = 0;
- harmony.first_filled_play = harmony.first_filled_record = 0;
- harmony.nb_filled_play = harmony.nb_filled_record = 0;
- harmony.play_offset = 0;
- init_waitqueue_head(&harmony.wq_play);
- init_waitqueue_head(&harmony.wq_record);
-
- /* Start off in a balanced mode. */
- harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
- harmony_update_control();
- harmony.format_initialized = 0;
-
- /* Clear out all the buffers and flush to cache */
- harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
- CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
- return 0;
-}
-
-/*
- * Release (close) the audio device.
- */
-
-static int harmony_audio_release(struct inode *inode, struct file *file)
-{
- if (!harmony.audio_open)
- return -EBUSY;
-
- harmony.audio_open = 0;
-
- return 0;
-}
-
-/*
- * Read recorded data off the audio device.
- */
-
-static ssize_t harmony_audio_read(struct file *file,
- char *buffer,
- size_t size_count,
- loff_t *ppos)
-{
- int total_count = (int) size_count;
- int count = 0;
- int buf_to_read;
-
- while (count<total_count) {
- /* Wait until we're out of control mode */
- harmony_wait_CNTL();
-
- /* Figure out which buffer to fill in */
- if (harmony.nb_filled_record <= 2) {
- harmony.blocked_recording = 1;
- if (harmony.suspended_recording) {
- harmony.suspended_recording = 0;
- harmony_enable_interrupts();
- }
-
- interruptible_sleep_on(&harmony.wq_record);
- harmony.blocked_recording = 0;
- }
-
- if (harmony.nb_filled_record < 2)
- return -EBUSY;
-
- buf_to_read = harmony.first_filled_record;
-
- /* Copy the page to an aligned buffer */
- if (copy_to_user(buffer+count, recorded_buf.addr +
- (HARMONY_BUF_SIZE*buf_to_read),
- HARMONY_BUF_SIZE)) {
- count = -EFAULT;
- break;
- }
-
- harmony.nb_filled_record--;
- harmony.first_filled_record++;
- harmony.first_filled_record %= MAX_BUFS;
-
- count += HARMONY_BUF_SIZE;
- }
- return count;
-}
-
-
-
-
-/*
- * Here is the place where we try to recognize file format.
- * Sun/NeXT .au files begin with the string .snd
- * At offset 12 is specified the encoding.
- * At offset 16 is specified speed rate
- * At Offset 20 is specified the numbers of voices
- */
-
-#define four_bytes_to_u32(start) (file_header[start] << 24)|\
- (file_header[start+1] << 16)|\
- (file_header[start+2] << 8)|\
- (file_header[start+3]);
-
-#define test_rate(tested,real_value,harmony_value) if ((tested)<=(real_value))\
-
-
-static int harmony_format_auto_detect(const char *buffer, int block_size)
-{
- u8 file_header[24];
- u32 start_string;
- int ret = 0;
-
- if (block_size>24) {
- if (copy_from_user(file_header, buffer, sizeof(file_header)))
- ret = -EFAULT;
-
- start_string = four_bytes_to_u32(0);
-
- if ((file_header[4]==0) && (start_string==0x2E736E64)) {
- u32 format;
- u32 nb_voices;
- u32 speed;
-
- format = four_bytes_to_u32(12);
- nb_voices = four_bytes_to_u32(20);
- speed = four_bytes_to_u32(16);
-
- switch (format) {
- case HARMONY_MAGIC_8B_ULAW:
- harmony.data_format = HARMONY_DF_8BIT_ULAW;
- break;
- case HARMONY_MAGIC_8B_ALAW:
- harmony.data_format = HARMONY_DF_8BIT_ALAW;
- break;
- case HARMONY_MAGIC_16B_LINEAR:
- harmony.data_format = HARMONY_DF_16BIT_LINEAR;
- break;
- default:
- harmony_set_control(HARMONY_DF_16BIT_LINEAR,
- HARMONY_SR_44KHZ, HARMONY_SS_STEREO);
- goto out;
- }
- switch (nb_voices) {
- case HARMONY_MAGIC_MONO:
- harmony.stereo_select = HARMONY_SS_MONO;
- break;
- case HARMONY_MAGIC_STEREO:
- harmony.stereo_select = HARMONY_SS_STEREO;
- break;
- default:
- harmony.stereo_select = HARMONY_SS_MONO;
- break;
- }
- harmony_set_rate(harmony_detect_rate(&speed));
- harmony.dac_rate = speed;
- goto out;
- }
- }
- harmony_set_control(HARMONY_DF_8BIT_ULAW, HARMONY_SR_8KHZ, HARMONY_SS_MONO);
-out:
- return ret;
-}
-#undef four_bytes_to_u32
-
-
-static ssize_t harmony_audio_write(struct file *file,
- const char *buffer,
- size_t size_count,
- loff_t *ppos)
-{
- int total_count = (int) size_count;
- int count = 0;
- int frame_size;
- int buf_to_fill;
- int fresh_buffer;
-
- if (!harmony.format_initialized) {
- if (harmony_format_auto_detect(buffer, total_count))
- return -EFAULT;
- }
-
- while (count<total_count) {
- /* Wait until we're out of control mode */
- harmony_wait_CNTL();
-
- /* Figure out which buffer to fill in */
- if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset) {
- harmony.blocked_playing = 1;
- interruptible_sleep_on(&harmony.wq_play);
- harmony.blocked_playing = 0;
- }
- if (harmony.nb_filled_play+2 >= MAX_BUFS && !harmony.play_offset)
- return -EBUSY;
-
-
- buf_to_fill = (harmony.first_filled_play+harmony.nb_filled_play);
- if (harmony.play_offset) {
- buf_to_fill--;
- buf_to_fill += MAX_BUFS;
- }
- buf_to_fill %= MAX_BUFS;
-
- fresh_buffer = (harmony.play_offset == 0);
-
- /* Figure out the size of the frame */
- if ((total_count-count) >= HARMONY_BUF_SIZE - harmony.play_offset) {
- frame_size = HARMONY_BUF_SIZE - harmony.play_offset;
- } else {
- frame_size = total_count - count;
- /* Clear out the buffer, since there we'll only be
- overlaying part of the old buffer with the new one */
- harmony_silence(&played_buf,
- HARMONY_BUF_SIZE*buf_to_fill+frame_size+harmony.play_offset,
- HARMONY_BUF_SIZE-frame_size-harmony.play_offset);
- }
-
- /* Copy the page to an aligned buffer */
- if (copy_from_user(played_buf.addr +(HARMONY_BUF_SIZE*buf_to_fill) + harmony.play_offset,
- buffer+count, frame_size))
- return -EFAULT;
- CHECK_WBACK_INV_OFFSET(played_buf, (HARMONY_BUF_SIZE*buf_to_fill + harmony.play_offset),
- frame_size);
-
- if (fresh_buffer)
- harmony.nb_filled_play++;
-
- count += frame_size;
- harmony.play_offset += frame_size;
- harmony.play_offset %= HARMONY_BUF_SIZE;
- if (harmony.suspended_playing && (harmony.nb_filled_play>=4))
- harmony_enable_interrupts();
- }
-
- return count;
-}
-
-static unsigned int harmony_audio_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- unsigned int mask = 0;
-
- if (file->f_mode & FMODE_READ) {
- if (!harmony.suspended_recording)
- poll_wait(file, &harmony.wq_record, wait);
- if (harmony.nb_filled_record)
- mask |= POLLIN | POLLRDNORM;
- }
-
- if (file->f_mode & FMODE_WRITE) {
- if (!harmony.suspended_playing)
- poll_wait(file, &harmony.wq_play, wait);
- if (harmony.nb_filled_play)
- mask |= POLLOUT | POLLWRNORM;
- }
-
- return mask;
-}
-
-static int harmony_audio_ioctl(struct inode *inode,
- struct file *file,
- unsigned int cmd,
- unsigned long arg)
-{
- int ival, new_format;
- int frag_size, frag_buf;
- struct audio_buf_info info;
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *) arg);
-
- case SNDCTL_DSP_GETCAPS:
- ival = DSP_CAP_DUPLEX;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETFMTS:
- ival = (AFMT_S16_BE | AFMT_MU_LAW | AFMT_A_LAW );
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SETFMT:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- if (ival != AFMT_QUERY) {
- switch (ival) {
- case AFMT_MU_LAW: new_format = HARMONY_DF_8BIT_ULAW; break;
- case AFMT_A_LAW: new_format = HARMONY_DF_8BIT_ALAW; break;
- case AFMT_S16_BE: new_format = HARMONY_DF_16BIT_LINEAR; break;
- default: {
- DPRINTK(KERN_WARNING PFX
- "unsupported sound format 0x%04x requested.\n",
- ival);
- ival = AFMT_S16_BE;
- return put_user(ival, (int *) arg);
- }
- }
- harmony_set_format(new_format);
- return 0;
- } else {
- switch (harmony.data_format) {
- case HARMONY_DF_8BIT_ULAW: ival = AFMT_MU_LAW; break;
- case HARMONY_DF_8BIT_ALAW: ival = AFMT_A_LAW; break;
- case HARMONY_DF_16BIT_LINEAR: ival = AFMT_U16_BE; break;
- default: ival = 0;
- }
- return put_user(ival, (int *) arg);
- }
-
- case SOUND_PCM_READ_RATE:
- ival = harmony.dac_rate;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_SPEED:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- harmony_set_rate(harmony_detect_rate(&ival));
- harmony.dac_rate = ival;
- return put_user(ival, (int*) arg);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- if (ival != 0 && ival != 1)
- return -EINVAL;
- harmony_set_stereo(ival);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(ival, (int *) arg))
- return -EFAULT;
- if (ival != 1 && ival != 2) {
- ival = harmony.stereo_select == HARMONY_SS_MONO ? 1 : 2;
- return put_user(ival, (int *) arg);
- }
- harmony_set_stereo(ival-1);
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- ival = HARMONY_BUF_SIZE;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_RESET:
- if (!harmony.suspended_recording) {
- /* TODO: stop_recording() */
- }
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(ival, (int *)arg))
- return -EFAULT;
- frag_size = ival & 0xffff;
- frag_buf = (ival>>16) & 0xffff;
- /* TODO: We use hardcoded fragment sizes and numbers for now */
- frag_size = 12; /* 4096 == 2^12 */
- frag_buf = MAX_BUFS;
- ival = (frag_buf << 16) + frag_size;
- return put_user(ival, (int *) arg);
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- info.fragstotal = MAX_BUFS;
- info.fragments = MAX_BUFS - harmony.nb_filled_play;
- info.fragsize = HARMONY_BUF_SIZE;
- info.bytes = info.fragments * info.fragsize;
- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- info.fragstotal = MAX_BUFS;
- info.fragments = /*MAX_BUFS-*/ harmony.nb_filled_record;
- info.fragsize = HARMONY_BUF_SIZE;
- info.bytes = info.fragments * info.fragsize;
- return copy_to_user((void *)arg, &info, sizeof(info)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_SYNC:
- return 0;
- }
-
- return -EINVAL;
-}
-
-
-/*
- * harmony_interrupt()
- *
- * harmony interruption service routine
- *
- */
-
-static irqreturn_t harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
-{
- u32 dstatus;
- struct harmony_hpa *hpa;
-
- /* Setup the hpa */
- hpa = ((struct harmony_dev *)dev)->hpa;
- harmony_wait_CNTL();
-
- /* Read dstatus and pcuradd (the current address) */
- dstatus = gsc_readl(&hpa->dstatus);
-
- /* Turn off interrupts */
- harmony_disable_interrupts();
-
- /* Check if this is a request to get the next play buffer */
- if (dstatus & DSTATUS_PN) {
- if (!harmony.nb_filled_play) {
- harmony.suspended_playing = 1;
- gsc_writel((unsigned long)silent.dma_handle, &hpa->pnxtadd);
-
- if (!harmony.suspended_recording)
- harmony_enable_interrupts();
- } else {
- harmony.suspended_playing = 0;
- gsc_writel((unsigned long)played_buf.dma_handle +
- (HARMONY_BUF_SIZE*harmony.first_filled_play),
- &hpa->pnxtadd);
- harmony.first_filled_play++;
- harmony.first_filled_play %= MAX_BUFS;
- harmony.nb_filled_play--;
-
- harmony_enable_interrupts();
- }
-
- if (harmony.blocked_playing)
- wake_up_interruptible(&harmony.wq_play);
- }
-
- /* Check if we're being asked to fill in a recording buffer */
- if (dstatus & DSTATUS_RN) {
- if((harmony.nb_filled_record+2>=MAX_BUFS) || harmony.suspended_recording)
- {
- harmony.nb_filled_record = 0;
- harmony.first_filled_record = 0;
- harmony.suspended_recording = 1;
- gsc_writel((unsigned long)graveyard.dma_handle, &hpa->rnxtadd);
- if (!harmony.suspended_playing)
- harmony_enable_interrupts();
- } else {
- int buf_to_fill;
- buf_to_fill = (harmony.first_filled_record+harmony.nb_filled_record) % MAX_BUFS;
- CHECK_WBACK_INV_OFFSET(recorded_buf, HARMONY_BUF_SIZE*buf_to_fill, HARMONY_BUF_SIZE);
- gsc_writel((unsigned long)recorded_buf.dma_handle +
- HARMONY_BUF_SIZE*buf_to_fill,
- &hpa->rnxtadd);
- harmony.nb_filled_record++;
- harmony_enable_interrupts();
- }
-
- if (harmony.blocked_recording && harmony.nb_filled_record>3)
- wake_up_interruptible(&harmony.wq_record);
- }
- return IRQ_HANDLED;
-}
-
-/*
- * Sound playing functions
- */
-
-static struct file_operations harmony_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = harmony_audio_read,
- .write = harmony_audio_write,
- .poll = harmony_audio_poll,
- .ioctl = harmony_audio_ioctl,
- .open = harmony_audio_open,
- .release = harmony_audio_release,
-};
-
-static int harmony_audio_init(void)
-{
- /* Request that IRQ */
- if (request_irq(harmony.dev->irq, harmony_interrupt, 0 ,"harmony", &harmony)) {
- printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony.dev->irq);
- return -EFAULT;
- }
-
- harmony.dsp_unit = register_sound_dsp(&harmony_audio_fops, -1);
- if (harmony.dsp_unit < 0) {
- printk(KERN_ERR PFX "Error registering dsp\n");
- free_irq(harmony.dev->irq, &harmony);
- return -EFAULT;
- }
-
- /* Clear the buffers so you don't end up with crap in the buffers. */
- harmony_silence(&played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
- /* Make sure this makes it to cache */
- CHECK_WBACK_INV_OFFSET(played_buf, 0, HARMONY_BUF_SIZE*MAX_BUFS);
-
- /* Clear out the silent buffer and flush to cache */
- harmony_silence(&silent, 0, HARMONY_BUF_SIZE);
- CHECK_WBACK_INV_OFFSET(silent, 0, HARMONY_BUF_SIZE);
-
- harmony.audio_open = 0;
-
- return 0;
-}
-
-
-/*
- * mixer functions
- */
-
-static void harmony_mixer_set_gain(void)
-{
- harmony_wait_CNTL();
- gsc_writel(harmony.current_gain, &harmony.hpa->gainctl);
-}
-
-/*
- * Read gain of selected channel.
- * The OSS rate is from 0 (silent) to 100 -> need some conversions
- *
- * The harmony gain are attenuation for output and monitor gain.
- * is amplifaction for input gain
- */
-#define to_harmony_level(level,max) ((level)*max/100)
-#define to_oss_level(level,max) ((level)*100/max)
-
-static int harmony_mixer_get_level(int channel)
-{
- int left_level;
- int right_level;
-
- switch (channel) {
- case SOUND_MIXER_VOLUME:
- left_level = (harmony.current_gain & GAIN_LO_MASK) >> GAIN_LO_SHIFT;
- right_level = (harmony.current_gain & GAIN_RO_MASK) >> GAIN_RO_SHIFT;
- left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
- right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
- return (right_level << 8)+left_level;
-
- case SOUND_MIXER_IGAIN:
- left_level = (harmony.current_gain & GAIN_LI_MASK) >> GAIN_LI_SHIFT;
- right_level= (harmony.current_gain & GAIN_RI_MASK) >> GAIN_RI_SHIFT;
- left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
- right_level= to_oss_level(right_level, MAX_INPUT_LEVEL);
- return (right_level << 8)+left_level;
-
- case SOUND_MIXER_MONITOR:
- left_level = (harmony.current_gain & GAIN_MA_MASK) >> GAIN_MA_SHIFT;
- left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
- return (left_level << 8)+left_level;
- }
- return -EINVAL;
-}
-
-
-
-/*
- * Some conversions for the same reasons.
- * We give back the new real value(s) due to
- * the rescale.
- */
-
-static int harmony_mixer_set_level(int channel, int value)
-{
- int left_level;
- int right_level;
- int new_left_level;
- int new_right_level;
-
- right_level = (value & 0x0000ff00) >> 8;
- left_level = value & 0x000000ff;
- if (right_level > 100) right_level = 100;
- if (left_level > 100) left_level = 100;
-
- switch (channel) {
- case SOUND_MIXER_VOLUME:
- right_level = to_harmony_level(100-right_level, MAX_OUTPUT_LEVEL);
- left_level = to_harmony_level(100-left_level, MAX_OUTPUT_LEVEL);
- new_right_level = to_oss_level(MAX_OUTPUT_LEVEL - right_level, MAX_OUTPUT_LEVEL);
- new_left_level = to_oss_level(MAX_OUTPUT_LEVEL - left_level, MAX_OUTPUT_LEVEL);
- harmony.current_gain = (harmony.current_gain & ~(GAIN_LO_MASK | GAIN_RO_MASK))
- | (left_level << GAIN_LO_SHIFT) | (right_level << GAIN_RO_SHIFT);
- harmony_mixer_set_gain();
- return (new_right_level << 8) + new_left_level;
-
- case SOUND_MIXER_IGAIN:
- right_level = to_harmony_level(right_level, MAX_INPUT_LEVEL);
- left_level = to_harmony_level(left_level, MAX_INPUT_LEVEL);
- new_right_level = to_oss_level(right_level, MAX_INPUT_LEVEL);
- new_left_level = to_oss_level(left_level, MAX_INPUT_LEVEL);
- harmony.current_gain = (harmony.current_gain & ~(GAIN_LI_MASK | GAIN_RI_MASK))
- | (left_level << GAIN_LI_SHIFT) | (right_level << GAIN_RI_SHIFT);
- harmony_mixer_set_gain();
- return (new_right_level << 8) + new_left_level;
-
- case SOUND_MIXER_MONITOR:
- left_level = to_harmony_level(100-left_level, MAX_MONITOR_LEVEL);
- new_left_level = to_oss_level(MAX_MONITOR_LEVEL-left_level, MAX_MONITOR_LEVEL);
- harmony.current_gain = (harmony.current_gain & ~GAIN_MA_MASK) | (left_level << GAIN_MA_SHIFT);
- harmony_mixer_set_gain();
- return (new_left_level << 8) + new_left_level;
- }
-
- return -EINVAL;
-}
-
-#undef to_harmony_level
-#undef to_oss_level
-
-/*
- * Return the selected input device (mic or line)
- */
-
-static int harmony_mixer_get_recmask(void)
-{
- int current_input_line;
-
- current_input_line = (harmony.current_gain & GAIN_IS_MASK)
- >> GAIN_IS_SHIFT;
- if (current_input_line)
- return SOUND_MASK_MIC;
-
- return SOUND_MASK_LINE;
-}
-
-/*
- * Set the input (only one at time, arbitrary priority to line in)
- */
-
-static int harmony_mixer_set_recmask(int recmask)
-{
- int new_input_line;
- int new_input_mask;
- int current_input_line;
-
- current_input_line = (harmony.current_gain & GAIN_IS_MASK)
- >> GAIN_IS_SHIFT;
- if ((current_input_line && ((recmask & SOUND_MASK_LINE) || !(recmask & SOUND_MASK_MIC))) ||
- (!current_input_line && ((recmask & SOUND_MASK_LINE) && !(recmask & SOUND_MASK_MIC)))) {
- new_input_line = 0;
- new_input_mask = SOUND_MASK_LINE;
- } else {
- new_input_line = 1;
- new_input_mask = SOUND_MASK_MIC;
- }
- harmony.current_gain = ((harmony.current_gain & ~GAIN_IS_MASK) |
- (new_input_line << GAIN_IS_SHIFT ));
- harmony_mixer_set_gain();
- return new_input_mask;
-}
-
-
-/*
- * give the active outlines
- */
-
-static int harmony_mixer_get_outmask(void)
-{
- int outmask = 0;
-
- if (harmony.current_gain & GAIN_SE_MASK) outmask |= MASK_INTERNAL;
- if (harmony.current_gain & GAIN_LE_MASK) outmask |= MASK_LINEOUT;
- if (harmony.current_gain & GAIN_HE_MASK) outmask |= MASK_HEADPHONES;
-
- return outmask;
-}
-
-
-static int harmony_mixer_set_outmask(int outmask)
-{
- if (outmask & MASK_INTERNAL)
- harmony.current_gain |= GAIN_SE_MASK;
- else
- harmony.current_gain &= ~GAIN_SE_MASK;
-
- if (outmask & MASK_LINEOUT)
- harmony.current_gain |= GAIN_LE_MASK;
- else
- harmony.current_gain &= ~GAIN_LE_MASK;
-
- if (outmask & MASK_HEADPHONES)
- harmony.current_gain |= GAIN_HE_MASK;
- else
- harmony.current_gain &= ~GAIN_HE_MASK;
-
- harmony_mixer_set_gain();
-
- return (outmask & (MASK_INTERNAL | MASK_LINEOUT | MASK_HEADPHONES));
-}
-
-/*
- * This code is inspired from sb_mixer.c
- */
-
-static int harmony_mixer_ioctl(struct inode * inode, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- int val;
- int ret;
-
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strncpy(info.id, "harmony", sizeof(info.id)-1);
- strncpy(info.name, "Harmony audio", sizeof(info.name)-1);
- info.modify_counter = 1; /* ? */
- if (copy_to_user((void *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
-
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, (int *)arg);
-
- /* read */
- val = 0;
- if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- if (get_user(val, (int *)arg))
- return -EFAULT;
-
- switch (cmd) {
- case MIXER_READ(SOUND_MIXER_CAPS):
- ret = SOUND_CAP_EXCL_INPUT;
- break;
- case MIXER_READ(SOUND_MIXER_STEREODEVS):
- ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN;
- break;
-
- case MIXER_READ(SOUND_MIXER_RECMASK):
- ret = SOUND_MASK_MIC | SOUND_MASK_LINE;
- break;
- case MIXER_READ(SOUND_MIXER_DEVMASK):
- ret = SOUND_MASK_VOLUME | SOUND_MASK_IGAIN |
- SOUND_MASK_MONITOR;
- break;
- case MIXER_READ(SOUND_MIXER_OUTMASK):
- ret = MASK_INTERNAL | MASK_LINEOUT |
- MASK_HEADPHONES;
- break;
-
- case MIXER_WRITE(SOUND_MIXER_RECSRC):
- ret = harmony_mixer_set_recmask(val);
- break;
- case MIXER_READ(SOUND_MIXER_RECSRC):
- ret = harmony_mixer_get_recmask();
- break;
-
- case MIXER_WRITE(SOUND_MIXER_OUTSRC):
- ret = harmony_mixer_set_outmask(val);
- break;
- case MIXER_READ(SOUND_MIXER_OUTSRC):
- ret = harmony_mixer_get_outmask();
- break;
-
- case MIXER_WRITE(SOUND_MIXER_VOLUME):
- case MIXER_WRITE(SOUND_MIXER_IGAIN):
- case MIXER_WRITE(SOUND_MIXER_MONITOR):
- ret = harmony_mixer_set_level(cmd & 0xff, val);
- break;
-
- case MIXER_READ(SOUND_MIXER_VOLUME):
- case MIXER_READ(SOUND_MIXER_IGAIN):
- case MIXER_READ(SOUND_MIXER_MONITOR):
- ret = harmony_mixer_get_level(cmd & 0xff);
- break;
-
- default:
- return -EINVAL;
- }
-
- if (put_user(ret, (int *)arg))
- return -EFAULT;
- return 0;
-}
-
-
-static int harmony_mixer_open(struct inode *inode, struct file *file)
-{
- if (harmony.mixer_open)
- return -EBUSY;
- harmony.mixer_open = 1;
- return 0;
-}
-
-static int harmony_mixer_release(struct inode *inode, struct file *file)
-{
- if (!harmony.mixer_open)
- return -EBUSY;
- harmony.mixer_open = 0;
- return 0;
-}
-
-static struct file_operations harmony_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .open = harmony_mixer_open,
- .release = harmony_mixer_release,
- .ioctl = harmony_mixer_ioctl,
-};
-
-
-/*
- * Mute all the output and reset Harmony.
- */
-
-static void __init harmony_mixer_reset(void)
-{
- harmony.current_gain = GAIN_TOTAL_SILENCE;
- harmony_mixer_set_gain();
- harmony_wait_CNTL();
- gsc_writel(1, &harmony.hpa->reset);
- mdelay(50); /* wait 50 ms */
- gsc_writel(0, &harmony.hpa->reset);
- harmony.current_gain = GAIN_DEFAULT;
- harmony_mixer_set_gain();
-}
-
-static int __init harmony_mixer_init(void)
-{
- /* Register the device file operations */
- harmony.mixer_unit = register_sound_mixer(&harmony_mixer_fops, -1);
- if (harmony.mixer_unit < 0) {
- printk(KERN_WARNING PFX "Error Registering Mixer Driver\n");
- return -EFAULT;
- }
-
- harmony_mixer_reset();
- harmony.mixer_open = 0;
-
- return 0;
-}
-
-
-
-/*
- * This is the callback that's called by the inventory hardware code
- * if it finds a match to the registered driver.
- */
-static int __devinit
-harmony_driver_probe(struct parisc_device *dev)
-{
- u8 id;
- u8 rev;
- u32 cntl;
- int ret;
-
- if (harmony.hpa) {
- /* We only support one Harmony at this time */
- printk(KERN_ERR PFX "driver already registered\n");
- return -EBUSY;
- }
-
- if (!dev->irq) {
- printk(KERN_ERR PFX "no irq found\n");
- return -ENODEV;
- }
-
- /* Set the HPA of harmony */
- harmony.hpa = (struct harmony_hpa *)dev->hpa.start;
- harmony.dev = dev;
-
- /* Grab the ID and revision from the device */
- id = gsc_readb(&harmony.hpa->id);
- if ((id | 1) != 0x15) {
- printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", id);
- return -EBUSY;
- }
- cntl = gsc_readl(&harmony.hpa->cntl);
- rev = (cntl>>20) & 0xff;
-
- printk(KERN_INFO "Lasi Harmony Audio driver " HARMONY_VERSION ", "
- "h/w id %i, rev. %i at 0x%lx, IRQ %i\n",
- id, rev, dev->hpa.start, harmony.dev->irq);
-
- /* Make sure the control bit isn't set, although I don't think it
- ever is. */
- if (cntl & CNTL_C) {
- printk(KERN_WARNING PFX "CNTL busy\n");
- harmony.hpa = 0;
- return -EBUSY;
- }
-
- /* Initialize the memory buffers */
- if (harmony_alloc_buffer(&played_buf, MAX_BUFS) ||
- harmony_alloc_buffer(&recorded_buf, MAX_BUFS) ||
- harmony_alloc_buffer(&graveyard, 1) ||
- harmony_alloc_buffer(&silent, 1)) {
- ret = -EBUSY;
- goto out_err;
- }
-
- /* Initialize /dev/mixer and /dev/audio */
- if ((ret=harmony_mixer_init()))
- goto out_err;
- if ((ret=harmony_audio_init()))
- goto out_err;
-
- return 0;
-
-out_err:
- harmony.hpa = 0;
- harmony_free_buffer(&played_buf);
- harmony_free_buffer(&recorded_buf);
- harmony_free_buffer(&graveyard);
- harmony_free_buffer(&silent);
- return ret;
-}
-
-
-static struct parisc_device_id harmony_tbl[] = {
- /* { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, Bushmaster/Flounder */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */
- { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(parisc, harmony_tbl);
-
-static struct parisc_driver harmony_driver = {
- .name = "Lasi Harmony",
- .id_table = harmony_tbl,
- .probe = harmony_driver_probe,
-};
-
-static int __init init_harmony(void)
-{
- return register_parisc_driver(&harmony_driver);
-}
-
-static void __exit cleanup_harmony(void)
-{
- free_irq(harmony.dev->irq, &harmony);
- unregister_sound_mixer(harmony.mixer_unit);
- unregister_sound_dsp(harmony.dsp_unit);
- harmony_free_buffer(&played_buf);
- harmony_free_buffer(&recorded_buf);
- harmony_free_buffer(&graveyard);
- harmony_free_buffer(&silent);
- unregister_parisc_driver(&harmony_driver);
-}
-
-
-MODULE_AUTHOR("Alex DeVries <alex@onefishtwo.ca>");
-MODULE_DESCRIPTION("Harmony sound driver");
-MODULE_LICENSE("GPL");
-
-module_init(init_harmony);
-module_exit(cleanup_harmony);
-
diff --git a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
index ddcddc2347f7..240cc7939b69 100644
--- a/sound/oss/i810_audio.c
+++ b/sound/oss/i810_audio.c
@@ -1523,9 +1523,9 @@ static void i810_channel_interrupt(struct i810_card *card)
#endif
}
-static irqreturn_t i810_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t i810_interrupt(int irq, void *dev_id)
{
- struct i810_card *card = (struct i810_card *)dev_id;
+ struct i810_card *card = dev_id;
u32 status;
spin_lock(&card->lock);
diff --git a/sound/oss/ics2101.c b/sound/oss/ics2101.c
deleted file mode 100644
index d5f3be8550f3..000000000000
--- a/sound/oss/ics2101.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * sound/ics2101.c
- *
- * Driver for the ICS2101 mixer of GUS v3.7.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- *
- * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
- * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
- */
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include <linux/ultrasound.h>
-
-#include "gus.h"
-#include "gus_hw.h"
-
-#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
- SOUND_MASK_SYNTH| \
- SOUND_MASK_CD | SOUND_MASK_VOLUME)
-
-extern int *gus_osp;
-extern int gus_base;
-extern spinlock_t gus_lock;
-static int volumes[ICS_MIXDEVS];
-static int left_fix[ICS_MIXDEVS] =
-{1, 1, 1, 2, 1, 2};
-static int right_fix[ICS_MIXDEVS] =
-{2, 2, 2, 1, 2, 1};
-
-static int scale_vol(int vol)
-{
- /*
- * Experimental volume scaling by Risto Kankkunen.
- * This should give smoother volume response than just
- * a plain multiplication.
- */
-
- int e;
-
- if (vol < 0)
- vol = 0;
- if (vol > 100)
- vol = 100;
- vol = (31 * vol + 50) / 100;
- e = 0;
- if (vol)
- {
- while (vol < 16)
- {
- vol <<= 1;
- e--;
- }
- vol -= 16;
- e += 7;
- }
- return ((e << 4) + vol);
-}
-
-static void write_mix(int dev, int chn, int vol)
-{
- int *selector;
- unsigned long flags;
- int ctrl_addr = dev << 3;
- int attn_addr = dev << 3;
-
- vol = scale_vol(vol);
-
- if (chn == CHN_LEFT)
- {
- selector = left_fix;
- ctrl_addr |= 0x00;
- attn_addr |= 0x02;
- }
- else
- {
- selector = right_fix;
- ctrl_addr |= 0x01;
- attn_addr |= 0x03;
- }
-
- spin_lock_irqsave(&gus_lock, flags);
- outb((ctrl_addr), u_MixSelect);
- outb((selector[dev]), u_MixData);
- outb((attn_addr), u_MixSelect);
- outb(((unsigned char) vol), u_MixData);
- spin_unlock_irqrestore(&gus_lock,flags);
-}
-
-static int set_volumes(int dev, int vol)
-{
- int left = vol & 0x00ff;
- int right = (vol >> 8) & 0x00ff;
-
- if (left < 0)
- left = 0;
- if (left > 100)
- left = 100;
- if (right < 0)
- right = 0;
- if (right > 100)
- right = 100;
-
- write_mix(dev, CHN_LEFT, left);
- write_mix(dev, CHN_RIGHT, right);
-
- vol = left + (right << 8);
- volumes[dev] = vol;
- return vol;
-}
-
-static int ics2101_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
-{
- int val;
-
- if (((cmd >> 8) & 0xff) == 'M') {
- if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
-
- if (get_user(val, (int __user *)arg))
- return -EFAULT;
- switch (cmd & 0xff) {
- case SOUND_MIXER_RECSRC:
- return gus_default_mixer_ioctl(dev, cmd, arg);
-
- case SOUND_MIXER_MIC:
- val = set_volumes(DEV_MIC, val);
- break;
-
- case SOUND_MIXER_CD:
- val = set_volumes(DEV_CD, val);
- break;
-
- case SOUND_MIXER_LINE:
- val = set_volumes(DEV_LINE, val);
- break;
-
- case SOUND_MIXER_SYNTH:
- val = set_volumes(DEV_GF1, val);
- break;
-
- case SOUND_MIXER_VOLUME:
- val = set_volumes(DEV_VOL, val);
- break;
-
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *)arg);
- } else {
- switch (cmd & 0xff) {
- /*
- * Return parameters
- */
- case SOUND_MIXER_RECSRC:
- return gus_default_mixer_ioctl(dev, cmd, arg);
-
- case SOUND_MIXER_DEVMASK:
- val = MIX_DEVS;
- break;
-
- case SOUND_MIXER_STEREODEVS:
- val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC;
- break;
-
- case SOUND_MIXER_RECMASK:
- val = SOUND_MASK_MIC | SOUND_MASK_LINE;
- break;
-
- case SOUND_MIXER_CAPS:
- val = 0;
- break;
-
- case SOUND_MIXER_MIC:
- val = volumes[DEV_MIC];
- break;
-
- case SOUND_MIXER_LINE:
- val = volumes[DEV_LINE];
- break;
-
- case SOUND_MIXER_CD:
- val = volumes[DEV_CD];
- break;
-
- case SOUND_MIXER_VOLUME:
- val = volumes[DEV_VOL];
- break;
-
- case SOUND_MIXER_SYNTH:
- val = volumes[DEV_GF1];
- break;
-
- default:
- return -EINVAL;
- }
- return put_user(val, (int __user *)arg);
- }
- }
- return -EINVAL;
-}
-
-static struct mixer_operations ics2101_mixer_operations =
-{
- .owner = THIS_MODULE,
- .id = "ICS2101",
- .name = "ICS2101 Multimedia Mixer",
- .ioctl = ics2101_mixer_ioctl
-};
-
-int __init ics2101_mixer_init(void)
-{
- int i;
- int n;
-
- if ((n = sound_alloc_mixerdev()) != -1)
- {
- mixer_devs[n] = &ics2101_mixer_operations;
-
- /*
- * Some GUS v3.7 cards had some channels flipped. Disable
- * the flipping feature if the model id is other than 5.
- */
-
- if (inb(u_MixSelect) != 5)
- {
- for (i = 0; i < ICS_MIXDEVS; i++)
- left_fix[i] = 1;
- for (i = 0; i < ICS_MIXDEVS; i++)
- right_fix[i] = 2;
- }
- set_volumes(DEV_GF1, 0x5a5a);
- set_volumes(DEV_CD, 0x5a5a);
- set_volumes(DEV_MIC, 0x0000);
- set_volumes(DEV_LINE, 0x5a5a);
- set_volumes(DEV_VOL, 0x5a5a);
- set_volumes(DEV_UNUSED, 0x0000);
- }
- return n;
-}
diff --git a/sound/oss/ite8172.c b/sound/oss/ite8172.c
deleted file mode 100644
index 68aab3605d74..000000000000
--- a/sound/oss/ite8172.c
+++ /dev/null
@@ -1,2261 +0,0 @@
-/*
- * ite8172.c -- ITE IT8172G Sound Driver.
- *
- * Copyright 2001 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- * stevel@mvista.com or source@mvista.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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
- * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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.
- *
- *
- * Module command line parameters:
- *
- * Supported devices:
- * /dev/dsp standard OSS /dev/dsp device
- * /dev/mixer standard OSS /dev/mixer device
- *
- * Notes:
- *
- * 1. Much of the OSS buffer allocation, ioctl's, and mmap'ing are
- * taken, slightly modified or not at all, from the ES1371 driver,
- * so refer to the credits in es1371.c for those. The rest of the
- * code (probe, open, read, write, the ISR, etc.) is new.
- * 2. The following support is untested:
- * * Memory mapping the audio buffers, and the ioctl controls that go
- * with it.
- * * S/PDIF output.
- * * I2S support.
- * 3. The following is not supported:
- * * legacy audio mode.
- * 4. Support for volume button interrupts is implemented but doesn't
- * work yet.
- *
- * Revision history
- * 02.08.2001 Initial release
- * 06.22.2001 Added I2S support
- * 07.30.2003 Removed initialisation to zero for static variables
- * (spdif[NR_DEVICE], i2s_fmt[NR_DEVICE], and devindex)
- */
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/bitops.h>
-#include <linux/proc_fs.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/ac97_codec.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-#include <asm/it8172/it8172.h>
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-#define IT8172_DEBUG
-#undef IT8172_VERBOSE_DEBUG
-#define DBG(x) {}
-
-#define IT8172_MODULE_NAME "IT8172 audio"
-#define PFX IT8172_MODULE_NAME
-
-#ifdef IT8172_DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
-
-
-#define IT8172_MODULE_NAME "IT8172 audio"
-#define PFX IT8172_MODULE_NAME
-
-#ifdef IT8172_DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG PFX ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-#define err(format, arg...) printk(KERN_ERR PFX ": " format "\n" , ## arg)
-#define info(format, arg...) printk(KERN_INFO PFX ": " format "\n" , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING PFX ": " format "\n" , ## arg)
-
-
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-
-/*
- * Audio Controller register bit definitions follow. See
- * include/asm/it8172/it8172.h for register offsets.
- */
-
-/* PCM Out Volume Reg */
-#define PCMOV_PCMOM (1<<15) /* PCM Out Mute default 1: mute */
-#define PCMOV_PCMRCG_BIT 8 /* PCM Right channel Gain */
-#define PCMOV_PCMRCG_MASK (0x1f<<PCMOV_PCMRCG_BIT)
-#define PCMOV_PCMLCG_BIT 0 /* PCM Left channel gain */
-#define PCMOV_PCMLCG_MASK 0x1f
-
-/* FM Out Volume Reg */
-#define FMOV_FMOM (1<<15) /* FM Out Mute default 1: mute */
-#define FMOV_FMRCG_BIT 8 /* FM Right channel Gain */
-#define FMOV_FMRCG_MASK (0x1f<<FMOV_FMRCG_BIT)
-#define FMOV_FMLCG_BIT 0 /* FM Left channel gain */
-#define FMOV_FMLCG_MASK 0x1f
-
-/* I2S Out Volume Reg */
-#define I2SV_I2SOM (1<<15) /* I2S Out Mute default 1: mute */
-#define I2SV_I2SRCG_BIT 8 /* I2S Right channel Gain */
-#define I2SV_I2SRCG_MASK (0x1f<<I2SV_I2SRCG_BIT)
-#define I2SV_I2SLCG_BIT 0 /* I2S Left channel gain */
-#define I2SV_I2SLCG_MASK 0x1f
-
-/* Digital Recording Source Select Reg */
-#define DRSS_BIT 0
-#define DRSS_MASK 0x07
-#define DRSS_AC97_PRIM 0
-#define DRSS_FM 1
-#define DRSS_I2S 2
-#define DRSS_PCM 3
-#define DRSS_AC97_SEC 4
-
-/* Playback/Capture Channel Control Registers */
-#define CC_SM (1<<15) /* Stereo, Mone 0: mono 1: stereo */
-#define CC_DF (1<<14) /* Data Format 0: 8 bit 1: 16 bit */
-#define CC_FMT_BIT 14
-#define CC_FMT_MASK (0x03<<CC_FMT_BIT)
-#define CC_CF_BIT 12 /* Channel format (Playback only) */
-#define CC_CF_MASK (0x03<<CC_CF_BIT)
-#define CC_CF_2 0
-#define CC_CF_4 (1<<CC_CF_BIT)
-#define CC_CF_6 (2<<CC_CF_BIT)
-#define CC_SR_BIT 8 /* sample Rate */
-#define CC_SR_MASK (0x0f<<CC_SR_BIT)
-#define CC_SR_5500 0
-#define CC_SR_8000 (1<<CC_SR_BIT)
-#define CC_SR_9600 (2<<CC_SR_BIT)
-#define CC_SR_11025 (3<<CC_SR_BIT)
-#define CC_SR_16000 (4<<CC_SR_BIT)
-#define CC_SR_19200 (5<<CC_SR_BIT)
-#define CC_SR_22050 (6<<CC_SR_BIT)
-#define CC_SR_32000 (7<<CC_SR_BIT)
-#define CC_SR_38400 (8<<CC_SR_BIT)
-#define CC_SR_44100 (9<<CC_SR_BIT)
-#define CC_SR_48000 (10<<CC_SR_BIT)
-#define CC_CSP (1<<7) /* Channel stop
- * 0: End of Current buffer
- * 1: Immediately stop when rec stop */
-#define CC_CP (1<<6) /* Channel pause 0: normal, 1: pause */
-#define CC_CA (1<<5) /* Channel Action 0: Stop , 1: start */
-#define CC_CB2L (1<<2) /* Cur. buf. 2 xfr is last 0: No, 1: Yes */
-#define CC_CB1L (1<<1) /* Cur. buf. 1 xfr is last 0: No, 1: Yes */
-#define CC_DE 1 /* DFC/DFIFO Data Empty 1: empty, 0: not empty
- * (Playback only)
- */
-
-/* Codec Control Reg */
-#define CODECC_GME (1<<9) /* AC97 GPIO Mode enable */
-#define CODECC_ATM (1<<8) /* AC97 ATE test mode 0: test 1: normal */
-#define CODECC_WR (1<<6) /* AC97 Warn reset 1: warm reset , 0: Normal */
-#define CODECC_CR (1<<5) /* AC97 Cold reset 1: Cold reset , 0: Normal */
-
-
-/* I2S Control Reg */
-#define I2SMC_SR_BIT 6 /* I2S Sampling rate
- * 00: 48KHz, 01: 44.1 KHz, 10: 32 32 KHz */
-#define I2SMC_SR_MASK (0x03<<I2SMC_SR_BIT)
-#define I2SMC_SR_48000 0
-#define I2SMC_SR_44100 (1<<I2SMC_SR_BIT)
-#define I2SMC_SR_32000 (2<<I2SMC_SR_BIT)
-#define I2SMC_SRSS (1<<5) /* Sample Rate Source Select 1:S/W, 0: H/W */
-#define I2SMC_I2SF_BIT 0 /* I2S Format */
-#define I2SMC_I2SF_MASK 0x03
-#define I2SMC_I2SF_DAC 0
-#define I2SMC_I2SF_ADC 2
-#define I2SMC_I2SF_I2S 3
-
-
-/* Volume up, Down, Mute */
-#define VS_VMP (1<<2) /* Volume mute 1: pushed, 0: not */
-#define VS_VDP (1<<1) /* Volume Down 1: pushed, 0: not */
-#define VS_VUP 1 /* Volime Up 1: pushed, 0: not */
-
-/* SRC, Mixer test control/DFC status reg */
-#define SRCS_DPUSC (1<<5) /* DFC Playback underrun Status/clear */
-#define SRCS_DCOSC (1<<4) /* DFC Capture Overrun Status/clear */
-#define SRCS_SIS (1<<3) /* SRC input select 1: Mixer, 0: Codec I/F */
-#define SRCS_CDIS_BIT 0 /* Codec Data Input Select */
-#define SRCS_CDIS_MASK 0x07
-#define SRCS_CDIS_MIXER 0
-#define SRCS_CDIS_PCM 1
-#define SRCS_CDIS_I2S 2
-#define SRCS_CDIS_FM 3
-#define SRCS_CDIS_DFC 4
-
-
-/* Codec Index Reg command Port */
-#define CIRCP_CID_BIT 10
-#define CIRCP_CID_MASK (0x03<<CIRCP_CID_BIT)
-#define CIRCP_CPS (1<<9) /* Command Port Status 0: ready, 1: busy */
-#define CIRCP_DPVF (1<<8) /* Data Port Valid Flag 0: invalis, 1: valid */
-#define CIRCP_RWC (1<<7) /* Read/write command */
-#define CIRCP_CIA_BIT 0
-#define CIRCP_CIA_MASK 0x007F /* Codec Index Address */
-
-/* Test Mode Control/Test group Select Control */
-
-/* General Control Reg */
-#define GC_VDC_BIT 6 /* Volume Division Control */
-#define GC_VDC_MASK (0x03<<GC_VDC_BIT)
-#define GC_VDC_NONE 0
-#define GC_VDC_DIV2 (1<<GC_VDC_BIT)
-#define GC_VDC_DIV4 (2<<GC_VDC_BIT)
-#define GC_SOE (1<<2) /* S/PDIF Output enable */
-#define GC_SWR 1 /* Software warn reset */
-
-/* Interrupt mask Control Reg */
-#define IMC_VCIM (1<<6) /* Volume CNTL interrupt mask */
-#define IMC_CCIM (1<<1) /* Capture Chan. iterrupt mask */
-#define IMC_PCIM 1 /* Playback Chan. interrupt mask */
-
-/* Interrupt status/clear reg */
-#define ISC_VCI (1<<6) /* Volume CNTL interrupt 1: clears */
-#define ISC_CCI (1<<1) /* Capture Chan. interrupt 1: clears */
-#define ISC_PCI 1 /* Playback Chan. interrupt 1: clears */
-
-/* misc stuff */
-#define POLL_COUNT 0x5000
-
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Define DIGITAL1 as the I2S channel, since it is not listed in
- * soundcard.h.
- */
-#define SOUND_MIXER_I2S SOUND_MIXER_DIGITAL1
-#define SOUND_MASK_I2S SOUND_MASK_DIGITAL1
-#define SOUND_MIXER_READ_I2S MIXER_READ(SOUND_MIXER_I2S)
-#define SOUND_MIXER_WRITE_I2S MIXER_WRITE(SOUND_MIXER_I2S)
-
-/* --------------------------------------------------------------------- */
-
-struct it8172_state {
- /* list of it8172 devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
-
- /* hardware resources */
- unsigned long io;
- unsigned int irq;
-
- /* PCI ID's */
- u16 vendor;
- u16 device;
- u8 rev; /* the chip revision */
-
- /* options */
- int spdif_volume; /* S/PDIF output is enabled if != -1 */
- int i2s_volume; /* current I2S out volume, in OSS format */
- int i2s_recording;/* 1 = recording from I2S, 0 = not */
-
-#ifdef IT8172_DEBUG
- /* debug /proc entry */
- struct proc_dir_entry *ps;
- struct proc_dir_entry *ac97_ps;
-#endif /* IT8172_DEBUG */
-
- struct ac97_codec codec;
-
- unsigned short pcc, capcc;
- unsigned dacrate, adcrate;
-
- spinlock_t lock;
- struct mutex open_mutex;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- void* nextIn;
- void* nextOut;
- int count;
- int curBufPtr;
- unsigned total_bytes;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned stopped:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-};
-
-/* --------------------------------------------------------------------- */
-
-static LIST_HEAD(devs);
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-static void it8172_delay(int msec)
-{
- unsigned long tmo;
- signed long tmo2;
-
- if (in_interrupt())
- return;
-
- tmo = jiffies + (msec*HZ)/1000;
- for (;;) {
- tmo2 = tmo - jiffies;
- if (tmo2 <= 0)
- break;
- schedule_timeout(tmo2);
- }
-}
-
-
-static unsigned short
-get_compat_rate(unsigned* rate)
-{
- unsigned rate_out = *rate;
- unsigned short sr;
-
- if (rate_out >= 46050) {
- sr = CC_SR_48000; rate_out = 48000;
- } else if (rate_out >= 41250) {
- sr = CC_SR_44100; rate_out = 44100;
- } else if (rate_out >= 35200) {
- sr = CC_SR_38400; rate_out = 38400;
- } else if (rate_out >= 27025) {
- sr = CC_SR_32000; rate_out = 32000;
- } else if (rate_out >= 20625) {
- sr = CC_SR_22050; rate_out = 22050;
- } else if (rate_out >= 17600) {
- sr = CC_SR_19200; rate_out = 19200;
- } else if (rate_out >= 13513) {
- sr = CC_SR_16000; rate_out = 16000;
- } else if (rate_out >= 10313) {
- sr = CC_SR_11025; rate_out = 11025;
- } else if (rate_out >= 8800) {
- sr = CC_SR_9600; rate_out = 9600;
- } else if (rate_out >= 6750) {
- sr = CC_SR_8000; rate_out = 8000;
- } else {
- sr = CC_SR_5500; rate_out = 5500;
- }
-
- *rate = rate_out;
- return sr;
-}
-
-static void set_adc_rate(struct it8172_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned short sr;
-
- sr = get_compat_rate(&rate);
-
- spin_lock_irqsave(&s->lock, flags);
- s->capcc &= ~CC_SR_MASK;
- s->capcc |= sr;
- outw(s->capcc, s->io+IT_AC_CAPCC);
- spin_unlock_irqrestore(&s->lock, flags);
-
- s->adcrate = rate;
-}
-
-
-static void set_dac_rate(struct it8172_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned short sr;
-
- sr = get_compat_rate(&rate);
-
- spin_lock_irqsave(&s->lock, flags);
- s->pcc &= ~CC_SR_MASK;
- s->pcc |= sr;
- outw(s->pcc, s->io+IT_AC_PCC);
- spin_unlock_irqrestore(&s->lock, flags);
-
- s->dacrate = rate;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static u16 rdcodec(struct ac97_codec *codec, u8 addr)
-{
- struct it8172_state *s = (struct it8172_state *)codec->private_data;
- unsigned long flags;
- unsigned short circp, data;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++)
- if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS))
- break;
- if (i == POLL_COUNT)
- err("rdcodec: codec ready poll expired!");
-
- circp = addr & CIRCP_CIA_MASK;
- circp |= (codec->id << CIRCP_CID_BIT);
- circp |= CIRCP_RWC; // read command
- outw(circp, s->io+IT_AC_CIRCP);
-
- /* now wait for the data */
- for (i = 0; i < POLL_COUNT; i++)
- if (inw(s->io+IT_AC_CIRCP) & CIRCP_DPVF)
- break;
- if (i == POLL_COUNT)
- err("rdcodec: read poll expired!");
-
- data = inw(s->io+IT_AC_CIRDP);
- spin_unlock_irqrestore(&s->lock, flags);
-
- return data;
-}
-
-
-static void wrcodec(struct ac97_codec *codec, u8 addr, u16 data)
-{
- struct it8172_state *s = (struct it8172_state *)codec->private_data;
- unsigned long flags;
- unsigned short circp;
- int i;
-
- spin_lock_irqsave(&s->lock, flags);
-
- for (i = 0; i < POLL_COUNT; i++)
- if (!(inw(s->io+IT_AC_CIRCP) & CIRCP_CPS))
- break;
- if (i == POLL_COUNT)
- err("wrcodec: codec ready poll expired!");
-
- circp = addr & CIRCP_CIA_MASK;
- circp |= (codec->id << CIRCP_CID_BIT);
- circp &= ~CIRCP_RWC; // write command
-
- outw(data, s->io+IT_AC_CIRDP); // send data first
- outw(circp, s->io+IT_AC_CIRCP);
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-
-static void waitcodec(struct ac97_codec *codec)
-{
- unsigned short temp;
-
- /* codec_wait is used to wait for a ready state after
- an AC97_RESET. */
- it8172_delay(10);
-
- temp = rdcodec(codec, 0x26);
-
- // If power down, power up
- if (temp & 0x3f00) {
- // Power on
- wrcodec(codec, 0x26, 0);
- it8172_delay(100);
- // Reread
- temp = rdcodec(codec, 0x26);
- }
-
- // Check if Codec REF,ANL,DAC,ADC ready***/
- if ((temp & 0x3f0f) != 0x000f) {
- err("codec reg 26 status (0x%x) not ready!!", temp);
- return;
- }
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct it8172_state *s)
-{
- struct dmabuf* db = &s->dma_adc;
- unsigned long flags;
- unsigned char imc;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- s->capcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L);
- s->capcc |= CC_CSP;
- outw(s->capcc, s->io+IT_AC_CAPCC);
-
- // disable capture interrupt
- imc = inb(s->io+IT_AC_IMC);
- outb(imc | IMC_CCIM, s->io+IT_AC_IMC);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac(struct it8172_state *s)
-{
- struct dmabuf* db = &s->dma_dac;
- unsigned long flags;
- unsigned char imc;
-
- if (db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- s->pcc &= ~(CC_CA | CC_CP | CC_CB2L | CC_CB1L);
- s->pcc |= CC_CSP;
- outw(s->pcc, s->io+IT_AC_PCC);
-
- // disable playback interrupt
- imc = inb(s->io+IT_AC_IMC);
- outb(imc | IMC_PCIM, s->io+IT_AC_IMC);
-
- db->stopped = 1;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac(struct it8172_state *s)
-{
- struct dmabuf* db = &s->dma_dac;
- unsigned long flags;
- unsigned char imc;
- unsigned long buf1, buf2;
-
- if (!db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- // reset Buffer 1 and 2 pointers to nextOut and nextOut+fragsize
- buf1 = virt_to_bus(db->nextOut);
- buf2 = buf1 + db->fragsize;
- if (buf2 >= db->dmaaddr + db->dmasize)
- buf2 -= db->dmasize;
-
- outl(buf1, s->io+IT_AC_PCB1STA);
- outl(buf2, s->io+IT_AC_PCB2STA);
- db->curBufPtr = IT_AC_PCB1STA;
-
- // enable playback interrupt
- imc = inb(s->io+IT_AC_IMC);
- outb(imc & ~IMC_PCIM, s->io+IT_AC_IMC);
-
- s->pcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L);
- s->pcc |= CC_CA;
- outw(s->pcc, s->io+IT_AC_PCC);
-
- db->stopped = 0;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct it8172_state *s)
-{
- struct dmabuf* db = &s->dma_adc;
- unsigned long flags;
- unsigned char imc;
- unsigned long buf1, buf2;
-
- if (!db->stopped)
- return;
-
- spin_lock_irqsave(&s->lock, flags);
-
- // reset Buffer 1 and 2 pointers to nextIn and nextIn+fragsize
- buf1 = virt_to_bus(db->nextIn);
- buf2 = buf1 + db->fragsize;
- if (buf2 >= db->dmaaddr + db->dmasize)
- buf2 -= db->dmasize;
-
- outl(buf1, s->io+IT_AC_CAPB1STA);
- outl(buf2, s->io+IT_AC_CAPB2STA);
- db->curBufPtr = IT_AC_CAPB1STA;
-
- // enable capture interrupt
- imc = inb(s->io+IT_AC_IMC);
- outb(imc & ~IMC_CCIM, s->io+IT_AC_IMC);
-
- s->capcc &= ~(CC_CSP | CC_CP | CC_CB2L | CC_CB1L);
- s->capcc |= CC_CA;
- outw(s->capcc, s->io+IT_AC_CAPCC);
-
- db->stopped = 0;
-
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static inline void dealloc_dmabuf(struct it8172_state *s, struct dmabuf *db)
-{
- struct page *page, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf +
- (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder,
- db->rawbuf, db->dmaaddr);
- }
- db->rawbuf = db->nextIn = db->nextOut = NULL;
- db->mapped = db->ready = 0;
-}
-
-static int prog_dmabuf(struct it8172_state *s, struct dmabuf *db,
- unsigned rate, unsigned fmt, unsigned reg)
-{
- int order;
- unsigned bytepersec;
- unsigned bufs;
- struct page *page, *pend;
-
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER;
- order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf =
- pci_alloc_consistent(s->dev,
- PAGE_SIZE << order,
- &db->dmaaddr)))
- break;
- if (!db->rawbuf)
- return -ENOMEM;
- db->buforder = order;
- /* now mark the pages as reserved;
- otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(db->rawbuf +
- (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
-
- db->count = 0;
- db->nextIn = db->nextOut = db->rawbuf;
-
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytepersec/100/(db->subdivision ?
- db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
- memset(db->rawbuf, (fmt & (CC_DF>>CC_FMT_BIT)) ? 0 : 0x80, bufs);
-
-#ifdef IT8172_VERBOSE_DEBUG
- dbg("rate=%d, fragsize=%d, numfrag=%d, dmasize=%d",
- rate, db->fragsize, db->numfrag, db->dmasize);
-#endif
-
- // set data length register
- outw(db->fragsize, s->io+reg+2);
- db->ready = 1;
-
- return 0;
-}
-
-static inline int prog_dmabuf_adc(struct it8172_state *s)
-{
- stop_adc(s);
- return prog_dmabuf(s, &s->dma_adc, s->adcrate,
- (s->capcc & CC_FMT_MASK) >> CC_FMT_BIT,
- IT_AC_CAPCC);
-}
-
-static inline int prog_dmabuf_dac(struct it8172_state *s)
-{
- stop_dac(s);
- return prog_dmabuf(s, &s->dma_dac, s->dacrate,
- (s->pcc & CC_FMT_MASK) >> CC_FMT_BIT,
- IT_AC_PCC);
-}
-
-
-/* hold spinlock for the following! */
-
-static irqreturn_t it8172_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct it8172_state *s = (struct it8172_state *)dev_id;
- struct dmabuf* dac = &s->dma_dac;
- struct dmabuf* adc = &s->dma_adc;
- unsigned char isc, vs;
- unsigned short vol, mute;
- unsigned long newptr;
-
- spin_lock(&s->lock);
-
- isc = inb(s->io+IT_AC_ISC);
-
- /* fastpath out, to ease interrupt sharing */
- if (!(isc & (ISC_VCI | ISC_CCI | ISC_PCI))) {
- spin_unlock(&s->lock);
- return IRQ_NONE;
- }
-
- /* clear audio interrupts first */
- outb(isc | ISC_VCI | ISC_CCI | ISC_PCI, s->io+IT_AC_ISC);
-
- /* handle volume button events (ignore if S/PDIF enabled) */
- if ((isc & ISC_VCI) && s->spdif_volume == -1) {
- vs = inb(s->io+IT_AC_VS);
- outb(0, s->io+IT_AC_VS);
- vol = inw(s->io+IT_AC_PCMOV);
- mute = vol & PCMOV_PCMOM;
- vol &= PCMOV_PCMLCG_MASK;
- if ((vs & VS_VUP) && vol > 0)
- vol--;
- if ((vs & VS_VDP) && vol < 0x1f)
- vol++;
- vol |= (vol << PCMOV_PCMRCG_BIT);
- if (vs & VS_VMP)
- vol |= (mute ^ PCMOV_PCMOM);
- outw(vol, s->io+IT_AC_PCMOV);
- }
-
- /* update capture pointers */
- if (isc & ISC_CCI) {
- if (adc->count > adc->dmasize - adc->fragsize) {
- // Overrun. Stop ADC and log the error
- stop_adc(s);
- adc->error++;
- dbg("adc overrun");
- } else {
- newptr = virt_to_bus(adc->nextIn) + 2*adc->fragsize;
- if (newptr >= adc->dmaaddr + adc->dmasize)
- newptr -= adc->dmasize;
-
- outl(newptr, s->io+adc->curBufPtr);
- adc->curBufPtr = (adc->curBufPtr == IT_AC_CAPB1STA) ?
- IT_AC_CAPB2STA : IT_AC_CAPB1STA;
-
- adc->nextIn += adc->fragsize;
- if (adc->nextIn >= adc->rawbuf + adc->dmasize)
- adc->nextIn -= adc->dmasize;
-
- adc->count += adc->fragsize;
- adc->total_bytes += adc->fragsize;
-
- /* wake up anybody listening */
- if (waitqueue_active(&adc->wait))
- wake_up_interruptible(&adc->wait);
- }
- }
-
- /* update playback pointers */
- if (isc & ISC_PCI) {
- newptr = virt_to_bus(dac->nextOut) + 2*dac->fragsize;
- if (newptr >= dac->dmaaddr + dac->dmasize)
- newptr -= dac->dmasize;
-
- outl(newptr, s->io+dac->curBufPtr);
- dac->curBufPtr = (dac->curBufPtr == IT_AC_PCB1STA) ?
- IT_AC_PCB2STA : IT_AC_PCB1STA;
-
- dac->nextOut += dac->fragsize;
- if (dac->nextOut >= dac->rawbuf + dac->dmasize)
- dac->nextOut -= dac->dmasize;
-
- dac->count -= dac->fragsize;
- dac->total_bytes += dac->fragsize;
-
- /* wake up anybody listening */
- if (waitqueue_active(&dac->wait))
- wake_up_interruptible(&dac->wait);
-
- if (dac->count <= 0)
- stop_dac(s);
- }
-
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-/* --------------------------------------------------------------------- */
-
-static int it8172_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- struct it8172_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct it8172_state, devs);
- if (s->codec.dev_mixer == minor)
- break;
- }
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int it8172_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-
-static u16
-cvt_ossvol(unsigned int gain)
-{
- u16 ret;
-
- if (gain == 0)
- return 0;
-
- if (gain > 100)
- gain = 100;
-
- ret = (100 - gain + 32) / 4;
- ret = ret > 31 ? 31 : ret;
- return ret;
-}
-
-
-static int mixdev_ioctl(struct ac97_codec *codec, unsigned int cmd,
- unsigned long arg)
-{
- struct it8172_state *s = (struct it8172_state *)codec->private_data;
- unsigned int left, right;
- unsigned long flags;
- int val;
- u16 vol;
-
- /*
- * When we are in S/PDIF mode, we want to disable any analog output so
- * we filter the master/PCM channel volume ioctls.
- *
- * Also filter I2S channel, which AC'97 knows nothing about.
- */
-
- switch (cmd) {
- case SOUND_MIXER_WRITE_VOLUME:
- // if not in S/PDIF mode, pass to AC'97
- if (s->spdif_volume == -1)
- break;
- return 0;
- case SOUND_MIXER_WRITE_PCM:
- // if not in S/PDIF mode, pass to AC'97
- if (s->spdif_volume == -1)
- break;
- if (get_user(val, (int *)arg))
- return -EFAULT;
- right = ((val >> 8) & 0xff);
- left = (val & 0xff);
- if (right > 100)
- right = 100;
- if (left > 100)
- left = 100;
- s->spdif_volume = (right << 8) | left;
- vol = cvt_ossvol(left);
- vol |= (cvt_ossvol(right) << PCMOV_PCMRCG_BIT);
- if (vol == 0)
- vol = PCMOV_PCMOM; // mute
- spin_lock_irqsave(&s->lock, flags);
- outw(vol, s->io+IT_AC_PCMOV);
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(s->spdif_volume, (int *)arg);
- case SOUND_MIXER_READ_PCM:
- // if not in S/PDIF mode, pass to AC'97
- if (s->spdif_volume == -1)
- break;
- return put_user(s->spdif_volume, (int *)arg);
- case SOUND_MIXER_WRITE_I2S:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- right = ((val >> 8) & 0xff);
- left = (val & 0xff);
- if (right > 100)
- right = 100;
- if (left > 100)
- left = 100;
- s->i2s_volume = (right << 8) | left;
- vol = cvt_ossvol(left);
- vol |= (cvt_ossvol(right) << I2SV_I2SRCG_BIT);
- if (vol == 0)
- vol = I2SV_I2SOM; // mute
- outw(vol, s->io+IT_AC_I2SV);
- return put_user(s->i2s_volume, (int *)arg);
- case SOUND_MIXER_READ_I2S:
- return put_user(s->i2s_volume, (int *)arg);
- case SOUND_MIXER_WRITE_RECSRC:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val & SOUND_MASK_I2S) {
- s->i2s_recording = 1;
- outb(DRSS_I2S, s->io+IT_AC_DRSS);
- return 0;
- } else {
- s->i2s_recording = 0;
- outb(DRSS_AC97_PRIM, s->io+IT_AC_DRSS);
- // now let AC'97 select record source
- break;
- }
- case SOUND_MIXER_READ_RECSRC:
- if (s->i2s_recording)
- return put_user(SOUND_MASK_I2S, (int *)arg);
- else
- // let AC'97 report recording source
- break;
- }
-
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static int it8172_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct it8172_state *s = (struct it8172_state *)file->private_data;
- struct ac97_codec *codec = &s->codec;
-
- return mixdev_ioctl(codec, cmd, arg);
-}
-
-static /*const*/ struct file_operations it8172_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = it8172_ioctl_mixdev,
- .open = it8172_open_mixdev,
- .release = it8172_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct it8172_state *s, int nonblock)
-{
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready || s->dma_dac.stopped)
- return 0;
-
- for (;;) {
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- //if (nonblock)
- //return -EBUSY;
- tmo = 1000 * count / s->dacrate;
- tmo >>= sample_shift[(s->pcc & CC_FMT_MASK) >> CC_FMT_BIT];
- it8172_delay(tmo);
- }
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-
-/*
- * Copy audio data to/from user buffer from/to dma buffer, taking care
- * that we wrap when reading/writing the dma buffer. Returns actual byte
- * count written to or read from the dma buffer.
- */
-static int copy_dmabuf_user(struct dmabuf *db, char* userbuf,
- int count, int to_user)
-{
- char* bufptr = to_user ? db->nextOut : db->nextIn;
- char* bufend = db->rawbuf + db->dmasize;
-
- if (bufptr + count > bufend) {
- int partial = (int)(bufend - bufptr);
- if (to_user) {
- if (copy_to_user(userbuf, bufptr, partial))
- return -EFAULT;
- if (copy_to_user(userbuf + partial, db->rawbuf,
- count - partial))
- return -EFAULT;
- } else {
- if (copy_from_user(bufptr, userbuf, partial))
- return -EFAULT;
- if (copy_from_user(db->rawbuf,
- userbuf + partial,
- count - partial))
- return -EFAULT;
- }
- } else {
- if (to_user) {
- if (copy_to_user(userbuf, bufptr, count))
- return -EFAULT;
- } else {
- if (copy_from_user(bufptr, userbuf, count))
- return -EFAULT;
- }
- }
-
- return count;
-}
-
-
-static ssize_t it8172_read(struct file *file, char *buffer,
- size_t count, loff_t *ppos)
-{
- struct it8172_state *s = (struct it8172_state *)file->private_data;
- struct dmabuf *db = &s->dma_adc;
- ssize_t ret;
- unsigned long flags;
- int cnt, remainder, avail;
-
- if (db->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- while (count > 0) {
- // wait for samples in capture buffer
- do {
- spin_lock_irqsave(&s->lock, flags);
- if (db->stopped)
- start_adc(s);
- avail = db->count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (avail <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- return ret;
- }
- interruptible_sleep_on(&db->wait);
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- return ret;
- }
- }
- } while (avail <= 0);
-
- // copy from nextOut to user
- if ((cnt = copy_dmabuf_user(db, buffer, count > avail ?
- avail : count, 1)) < 0) {
- if (!ret)
- ret = -EFAULT;
- return ret;
- }
-
- spin_lock_irqsave(&s->lock, flags);
- db->count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
-
- db->nextOut += cnt;
- if (db->nextOut >= db->rawbuf + db->dmasize)
- db->nextOut -= db->dmasize;
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- } // while (count > 0)
-
- /*
- * See if the dma buffer count after this read call is
- * aligned on a fragsize boundary. If not, read from
- * buffer until we reach a boundary, and let's hope this
- * is just the last remainder of an audio record. If not
- * it means the user is not reading in fragsize chunks, in
- * which case it's his/her fault that there are audio gaps
- * in their record.
- */
- spin_lock_irqsave(&s->lock, flags);
- remainder = db->count % db->fragsize;
- if (remainder) {
- db->nextOut += remainder;
- if (db->nextOut >= db->rawbuf + db->dmasize)
- db->nextOut -= db->dmasize;
- db->count -= remainder;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-
- return ret;
-}
-
-static ssize_t it8172_write(struct file *file, const char *buffer,
- size_t count, loff_t *ppos)
-{
- struct it8172_state *s = (struct it8172_state *)file->private_data;
- struct dmabuf *db = &s->dma_dac;
- ssize_t ret;
- unsigned long flags;
- int cnt, remainder, avail;
-
- if (db->mapped)
- return -ENXIO;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- while (count > 0) {
- // wait for space in playback buffer
- do {
- spin_lock_irqsave(&s->lock, flags);
- avail = db->dmasize - db->count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (avail <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- return ret;
- }
- interruptible_sleep_on(&db->wait);
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- return ret;
- }
- }
- } while (avail <= 0);
-
- // copy to nextIn
- if ((cnt = copy_dmabuf_user(db, (char*)buffer,
- count > avail ?
- avail : count, 0)) < 0) {
- if (!ret)
- ret = -EFAULT;
- return ret;
- }
-
- spin_lock_irqsave(&s->lock, flags);
- db->count += cnt;
- if (db->stopped)
- start_dac(s);
- spin_unlock_irqrestore(&s->lock, flags);
-
- db->nextIn += cnt;
- if (db->nextIn >= db->rawbuf + db->dmasize)
- db->nextIn -= db->dmasize;
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- } // while (count > 0)
-
- /*
- * See if the dma buffer count after this write call is
- * aligned on a fragsize boundary. If not, fill buffer
- * with silence to the next boundary, and let's hope this
- * is just the last remainder of an audio playback. If not
- * it means the user is not sending us fragsize chunks, in
- * which case it's his/her fault that there are audio gaps
- * in their playback.
- */
- spin_lock_irqsave(&s->lock, flags);
- remainder = db->count % db->fragsize;
- if (remainder) {
- int fill_cnt = db->fragsize - remainder;
- memset(db->nextIn, 0, fill_cnt);
- db->nextIn += fill_cnt;
- if (db->nextIn >= db->rawbuf + db->dmasize)
- db->nextIn -= db->dmasize;
- db->count += fill_cnt;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int it8172_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct it8172_state *s = (struct it8172_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready)
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready)
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
-
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >=
- s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int it8172_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct it8172_state *s = (struct it8172_state *)file->private_data;
- struct dmabuf *db;
- unsigned long size;
-
- lock_kernel();
- if (vma->vm_flags & VM_WRITE)
- db = &s->dma_dac;
- else if (vma->vm_flags & VM_READ)
- db = &s->dma_adc;
- else {
- unlock_kernel();
- return -EINVAL;
- }
- if (vma->vm_pgoff != 0) {
- unlock_kernel();
- return -EINVAL;
- }
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder)) {
- unlock_kernel();
- return -EINVAL;
- }
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot)) {
- unlock_kernel();
- return -EAGAIN;
- }
- db->mapped = 1;
- unlock_kernel();
- return 0;
-}
-
-
-#ifdef IT8172_VERBOSE_DEBUG
-static struct ioctl_str_t {
- unsigned int cmd;
- const char* str;
-} ioctl_str[] = {
- {SNDCTL_DSP_RESET, "SNDCTL_DSP_RESET"},
- {SNDCTL_DSP_SYNC, "SNDCTL_DSP_SYNC"},
- {SNDCTL_DSP_SPEED, "SNDCTL_DSP_SPEED"},
- {SNDCTL_DSP_STEREO, "SNDCTL_DSP_STEREO"},
- {SNDCTL_DSP_GETBLKSIZE, "SNDCTL_DSP_GETBLKSIZE"},
- {SNDCTL_DSP_SAMPLESIZE, "SNDCTL_DSP_SAMPLESIZE"},
- {SNDCTL_DSP_CHANNELS, "SNDCTL_DSP_CHANNELS"},
- {SOUND_PCM_WRITE_CHANNELS, "SOUND_PCM_WRITE_CHANNELS"},
- {SOUND_PCM_WRITE_FILTER, "SOUND_PCM_WRITE_FILTER"},
- {SNDCTL_DSP_POST, "SNDCTL_DSP_POST"},
- {SNDCTL_DSP_SUBDIVIDE, "SNDCTL_DSP_SUBDIVIDE"},
- {SNDCTL_DSP_SETFRAGMENT, "SNDCTL_DSP_SETFRAGMENT"},
- {SNDCTL_DSP_GETFMTS, "SNDCTL_DSP_GETFMTS"},
- {SNDCTL_DSP_SETFMT, "SNDCTL_DSP_SETFMT"},
- {SNDCTL_DSP_GETOSPACE, "SNDCTL_DSP_GETOSPACE"},
- {SNDCTL_DSP_GETISPACE, "SNDCTL_DSP_GETISPACE"},
- {SNDCTL_DSP_NONBLOCK, "SNDCTL_DSP_NONBLOCK"},
- {SNDCTL_DSP_GETCAPS, "SNDCTL_DSP_GETCAPS"},
- {SNDCTL_DSP_GETTRIGGER, "SNDCTL_DSP_GETTRIGGER"},
- {SNDCTL_DSP_SETTRIGGER, "SNDCTL_DSP_SETTRIGGER"},
- {SNDCTL_DSP_GETIPTR, "SNDCTL_DSP_GETIPTR"},
- {SNDCTL_DSP_GETOPTR, "SNDCTL_DSP_GETOPTR"},
- {SNDCTL_DSP_MAPINBUF, "SNDCTL_DSP_MAPINBUF"},
- {SNDCTL_DSP_MAPOUTBUF, "SNDCTL_DSP_MAPOUTBUF"},
- {SNDCTL_DSP_SETSYNCRO, "SNDCTL_DSP_SETSYNCRO"},
- {SNDCTL_DSP_SETDUPLEX, "SNDCTL_DSP_SETDUPLEX"},
- {SNDCTL_DSP_GETODELAY, "SNDCTL_DSP_GETODELAY"},
- {SNDCTL_DSP_GETCHANNELMASK, "SNDCTL_DSP_GETCHANNELMASK"},
- {SNDCTL_DSP_BIND_CHANNEL, "SNDCTL_DSP_BIND_CHANNEL"},
- {OSS_GETVERSION, "OSS_GETVERSION"},
- {SOUND_PCM_READ_RATE, "SOUND_PCM_READ_RATE"},
- {SOUND_PCM_READ_CHANNELS, "SOUND_PCM_READ_CHANNELS"},
- {SOUND_PCM_READ_BITS, "SOUND_PCM_READ_BITS"},
- {SOUND_PCM_READ_FILTER, "SOUND_PCM_READ_FILTER"}
-};
-#endif
-
-static int it8172_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct it8172_state *s = (struct it8172_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, mapped, ret, diff;
-
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
-#ifdef IT8172_VERBOSE_DEBUG
- for (count=0; count<sizeof(ioctl_str)/sizeof(ioctl_str[0]); count++) {
- if (ioctl_str[count].cmd == cmd)
- break;
- }
- if (count < sizeof(ioctl_str)/sizeof(ioctl_str[0]))
- dbg("ioctl %s, arg=0x%08x",
- ioctl_str[count].str, (unsigned int)arg);
- else
- dbg("ioctl unknown, 0x%x", cmd);
-#endif
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, (int *)arg);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, file->f_flags & O_NONBLOCK);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME |
- DSP_CAP_TRIGGER | DSP_CAP_MMAP, (int *)arg);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.count = s->dma_dac.total_bytes = 0;
- s->dma_dac.nextIn = s->dma_dac.nextOut =
- s->dma_dac.rawbuf;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->irq);
- s->dma_adc.count = s->dma_adc.total_bytes = 0;
- s->dma_adc.nextIn = s->dma_adc.nextOut =
- s->dma_adc.rawbuf;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- set_adc_rate(s, val);
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- set_dac_rate(s, val);
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- }
- return put_user((file->f_mode & FMODE_READ) ?
- s->adcrate : s->dacrate, (int *)arg);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- if (val)
- s->capcc |= CC_SM;
- else
- s->capcc &= ~CC_SM;
- outw(s->capcc, s->io+IT_AC_CAPCC);
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- if (val)
- s->pcc |= CC_SM;
- else
- s->pcc &= ~CC_SM;
- outw(s->pcc, s->io+IT_AC_PCC);
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val != 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- if (val >= 2) {
- val = 2;
- s->capcc |= CC_SM;
- }
- else
- s->capcc &= ~CC_SM;
- outw(s->capcc, s->io+IT_AC_CAPCC);
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- switch (val) {
- case 1:
- s->pcc &= ~CC_SM;
- break;
- case 2:
- s->pcc |= CC_SM;
- break;
- default:
- // FIX! support multichannel???
- val = 2;
- s->pcc |= CC_SM;
- break;
- }
- outw(s->pcc, s->io+IT_AC_PCC);
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- }
- return put_user(val, (int *)arg);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U8, (int *)arg);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- if (val == AFMT_S16_LE)
- s->capcc |= CC_DF;
- else {
- val = AFMT_U8;
- s->capcc &= ~CC_DF;
- }
- outw(s->capcc, s->io+IT_AC_CAPCC);
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- if (val == AFMT_S16_LE)
- s->pcc |= CC_DF;
- else {
- val = AFMT_U8;
- s->pcc &= ~CC_DF;
- }
- outw(s->pcc, s->io+IT_AC_PCC);
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- } else {
- if (file->f_mode & FMODE_READ)
- val = (s->capcc & CC_DF) ?
- AFMT_S16_LE : AFMT_U8;
- else
- val = (s->pcc & CC_DF) ?
- AFMT_S16_LE : AFMT_U8;
- }
- return put_user(val, (int *)arg);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ && !s->dma_adc.stopped)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && !s->dma_dac.stopped)
- val |= PCM_ENABLE_OUTPUT;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, (int *)arg);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT)
- start_adc(s);
- else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT)
- start_dac(s);
- else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- abinfo.fragsize = s->dma_dac.fragsize;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- if (!s->dma_dac.stopped)
- count -= (s->dma_dac.fragsize -
- inw(s->io+IT_AC_PCDL));
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac.dmasize - count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ?
- -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- abinfo.fragsize = s->dma_adc.fragsize;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_adc.count;
- if (!s->dma_adc.stopped)
- count += (s->dma_adc.fragsize -
- inw(s->io+IT_AC_CAPCDL));
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- abinfo.bytes = count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ?
- -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- if (!s->dma_dac.stopped)
- count -= (s->dma_dac.fragsize -
- inw(s->io+IT_AC_PCDL));
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- return put_user(count, (int *)arg);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cinfo.bytes = s->dma_adc.total_bytes;
- count = s->dma_adc.count;
- if (!s->dma_adc.stopped) {
- diff = s->dma_adc.fragsize - inw(s->io+IT_AC_CAPCDL);
- count += diff;
- cinfo.bytes += diff;
- cinfo.ptr = inl(s->io+s->dma_adc.curBufPtr) -
- s->dma_adc.dmaaddr;
- } else
- cinfo.ptr = virt_to_bus(s->dma_adc.nextIn) -
- s->dma_adc.dmaaddr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_adc.fragshift;
- if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&s->lock, flags);
- cinfo.bytes = s->dma_dac.total_bytes;
- count = s->dma_dac.count;
- if (!s->dma_dac.stopped) {
- diff = s->dma_dac.fragsize - inw(s->io+IT_AC_CAPCDL);
- count -= diff;
- cinfo.bytes += diff;
- cinfo.ptr = inl(s->io+s->dma_dac.curBufPtr) -
- s->dma_dac.dmaaddr;
- } else
- cinfo.ptr = virt_to_bus(s->dma_dac.nextOut) -
- s->dma_dac.dmaaddr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
- if (copy_to_user((void *)arg, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE)
- return put_user(s->dma_dac.fragsize, (int *)arg);
- else
- return put_user(s->dma_adc.fragsize, (int *)arg);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, (int *)arg))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.subdivision = val;
- if ((ret = prog_dmabuf_adc(s)))
- return ret;
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.subdivision = val;
- if ((ret = prog_dmabuf_dac(s)))
- return ret;
- }
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ?
- s->adcrate : s->dacrate, (int *)arg);
-
- case SOUND_PCM_READ_CHANNELS:
- if (file->f_mode & FMODE_READ)
- return put_user((s->capcc & CC_SM) ? 2 : 1,
- (int *)arg);
- else
- return put_user((s->pcc & CC_SM) ? 2 : 1,
- (int *)arg);
-
- case SOUND_PCM_READ_BITS:
- if (file->f_mode & FMODE_READ)
- return put_user((s->capcc & CC_DF) ? 16 : 8,
- (int *)arg);
- else
- return put_user((s->pcc & CC_DF) ? 16 : 8,
- (int *)arg);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
- }
-
- return mixdev_ioctl(&s->codec, cmd, arg);
-}
-
-
-static int it8172_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct it8172_state *s;
- int ret;
-
-#ifdef IT8172_VERBOSE_DEBUG
- if (file->f_flags & O_NONBLOCK)
- dbg("%s: non-blocking", __FUNCTION__);
- else
- dbg("%s: blocking", __FUNCTION__);
-#endif
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct it8172_state, devs);
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
-
- spin_lock_irqsave(&s->lock, flags);
-
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags =
- s->dma_adc.subdivision = s->dma_adc.total_bytes = 0;
- s->capcc &= ~(CC_SM | CC_DF);
- set_adc_rate(s, 8000);
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->capcc |= CC_DF;
- outw(s->capcc, s->io+IT_AC_CAPCC);
- if ((ret = prog_dmabuf_adc(s))) {
- spin_unlock_irqrestore(&s->lock, flags);
- return ret;
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags =
- s->dma_dac.subdivision = s->dma_dac.total_bytes = 0;
- s->pcc &= ~(CC_SM | CC_DF);
- set_dac_rate(s, 8000);
- if ((minor & 0xf) == SND_DEV_DSP16)
- s->pcc |= CC_DF;
- outw(s->pcc, s->io+IT_AC_PCC);
- if ((ret = prog_dmabuf_dac(s))) {
- spin_unlock_irqrestore(&s->lock, flags);
- return ret;
- }
- }
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- s->open_mode |= (file->f_mode & (FMODE_READ | FMODE_WRITE));
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int it8172_release(struct inode *inode, struct file *file)
-{
- struct it8172_state *s = (struct it8172_state *)file->private_data;
-
-#ifdef IT8172_VERBOSE_DEBUG
- dbg("%s", __FUNCTION__);
-#endif
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- dealloc_dmabuf(s, &s->dma_dac);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- }
- s->open_mode &= ((~file->f_mode) & (FMODE_READ|FMODE_WRITE));
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations it8172_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = it8172_read,
- .write = it8172_write,
- .poll = it8172_poll,
- .ioctl = it8172_ioctl,
- .mmap = it8172_mmap,
- .open = it8172_open,
- .release = it8172_release,
-};
-
-
-/* --------------------------------------------------------------------- */
-
-
-/* --------------------------------------------------------------------- */
-
-/*
- * for debugging purposes, we'll create a proc device that dumps the
- * CODEC chipstate
- */
-
-#ifdef IT8172_DEBUG
-static int proc_it8172_dump (char *buf, char **start, off_t fpos,
- int length, int *eof, void *data)
-{
- struct it8172_state *s;
- int cnt, len = 0;
-
- if (list_empty(&devs))
- return 0;
- s = list_entry(devs.next, struct it8172_state, devs);
-
- /* print out header */
- len += sprintf(buf + len, "\n\t\tIT8172 Audio Debug\n\n");
-
- // print out digital controller state
- len += sprintf (buf + len, "IT8172 Audio Controller registers\n");
- len += sprintf (buf + len, "---------------------------------\n");
- cnt=0;
- while (cnt < 0x72) {
- if (cnt == IT_AC_PCB1STA || cnt == IT_AC_PCB2STA ||
- cnt == IT_AC_CAPB1STA || cnt == IT_AC_CAPB2STA ||
- cnt == IT_AC_PFDP) {
- len+= sprintf (buf + len, "reg %02x = %08x\n",
- cnt, inl(s->io+cnt));
- cnt += 4;
- } else {
- len+= sprintf (buf + len, "reg %02x = %04x\n",
- cnt, inw(s->io+cnt));
- cnt += 2;
- }
- }
-
- /* print out CODEC state */
- len += sprintf (buf + len, "\nAC97 CODEC registers\n");
- len += sprintf (buf + len, "----------------------\n");
- for (cnt=0; cnt <= 0x7e; cnt = cnt +2)
- len+= sprintf (buf + len, "reg %02x = %04x\n",
- cnt, rdcodec(&s->codec, cnt));
-
- if (fpos >=len){
- *start = buf;
- *eof =1;
- return 0;
- }
- *start = buf + fpos;
- if ((len -= fpos) > length)
- return length;
- *eof =1;
- return len;
-
-}
-#endif /* IT8172_DEBUG */
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int spdif[NR_DEVICE];
-static int i2s_fmt[NR_DEVICE];
-
-static unsigned int devindex;
-
-module_param_array(spdif, int, NULL, 0);
-MODULE_PARM_DESC(spdif, "if 1 the S/PDIF digital output is enabled");
-module_param_array(i2s_fmt, int, NULL, 0);
-MODULE_PARM_DESC(i2s_fmt, "the format of I2S");
-
-MODULE_AUTHOR("Monta Vista Software, stevel@mvista.com");
-MODULE_DESCRIPTION("IT8172 Audio Driver");
-
-/* --------------------------------------------------------------------- */
-
-static int __devinit it8172_probe(struct pci_dev *pcidev,
- const struct pci_device_id *pciid)
-{
- struct it8172_state *s;
- int i, val;
- unsigned short pcisr, vol;
- unsigned char legacy, imc;
- char proc_str[80];
-
- if (pcidev->irq == 0)
- return -1;
-
- if (!(s = kmalloc(sizeof(struct it8172_state), GFP_KERNEL))) {
- err("alloc of device struct failed");
- return -1;
- }
-
- memset(s, 0, sizeof(struct it8172_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
- s->dev = pcidev;
- s->io = pci_resource_start(pcidev, 0);
- s->irq = pcidev->irq;
- s->vendor = pcidev->vendor;
- s->device = pcidev->device;
- pci_read_config_byte(pcidev, PCI_REVISION_ID, &s->rev);
- s->codec.private_data = s;
- s->codec.id = 0;
- s->codec.codec_read = rdcodec;
- s->codec.codec_write = wrcodec;
- s->codec.codec_wait = waitcodec;
-
- if (!request_region(s->io, pci_resource_len(pcidev,0),
- IT8172_MODULE_NAME)) {
- err("io ports %#lx->%#lx in use",
- s->io, s->io + pci_resource_len(pcidev,0)-1);
- goto err_region;
- }
- if (request_irq(s->irq, it8172_interrupt, IRQF_DISABLED,
- IT8172_MODULE_NAME, s)) {
- err("irq %u in use", s->irq);
- goto err_irq;
- }
-
- info("IO at %#lx, IRQ %d", s->io, s->irq);
-
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&it8172_audio_fops, -1)) < 0)
- goto err_dev1;
- if ((s->codec.dev_mixer =
- register_sound_mixer(&it8172_mixer_fops, -1)) < 0)
- goto err_dev2;
-
-#ifdef IT8172_DEBUG
- /* initialize the debug proc device */
- s->ps = create_proc_read_entry(IT8172_MODULE_NAME, 0, NULL,
- proc_it8172_dump, NULL);
-#endif /* IT8172_DEBUG */
-
- /*
- * Reset the Audio device using the IT8172 PCI Reset register. This
- * creates an audible double click on a speaker connected to Line-out.
- */
- IT_IO_READ16(IT_PM_PCISR, pcisr);
- pcisr |= IT_PM_PCISR_ACSR;
- IT_IO_WRITE16(IT_PM_PCISR, pcisr);
- /* wait up to 100msec for reset to complete */
- for (i=0; pcisr & IT_PM_PCISR_ACSR; i++) {
- it8172_delay(10);
- if (i == 10)
- break;
- IT_IO_READ16(IT_PM_PCISR, pcisr);
- }
- if (i == 10) {
- err("chip reset timeout!");
- goto err_dev3;
- }
-
- /* enable pci io and bus mastering */
- if (pci_enable_device(pcidev))
- goto err_dev3;
- pci_set_master(pcidev);
-
- /* get out of legacy mode */
- pci_read_config_byte (pcidev, 0x40, &legacy);
- pci_write_config_byte (pcidev, 0x40, legacy & ~1);
-
- s->spdif_volume = -1;
- /* check to see if s/pdif mode is being requested */
- if (spdif[devindex]) {
- info("enabling S/PDIF output");
- s->spdif_volume = 0;
- outb(GC_SOE, s->io+IT_AC_GC);
- } else {
- info("disabling S/PDIF output");
- outb(0, s->io+IT_AC_GC);
- }
-
- /* check to see if I2S format requested */
- if (i2s_fmt[devindex]) {
- info("setting I2S format to 0x%02x", i2s_fmt[devindex]);
- outb(i2s_fmt[devindex], s->io+IT_AC_I2SMC);
- } else {
- outb(I2SMC_I2SF_I2S, s->io+IT_AC_I2SMC);
- }
-
- /* cold reset the AC97 */
- outw(CODECC_CR, s->io+IT_AC_CODECC);
- udelay(1000);
- outw(0, s->io+IT_AC_CODECC);
- /* need to delay around 500msec(bleech) to give
- some CODECs enough time to wakeup */
- it8172_delay(500);
-
- /* AC97 warm reset to start the bitclk */
- outw(CODECC_WR, s->io+IT_AC_CODECC);
- udelay(1000);
- outw(0, s->io+IT_AC_CODECC);
-
- /* codec init */
- if (!ac97_probe_codec(&s->codec))
- goto err_dev3;
-
- /* add I2S as allowable recording source */
- s->codec.record_sources |= SOUND_MASK_I2S;
-
- /* Enable Volume button interrupts */
- imc = inb(s->io+IT_AC_IMC);
- outb(imc & ~IMC_VCIM, s->io+IT_AC_IMC);
-
- /* Un-mute PCM and FM out on the controller */
- vol = inw(s->io+IT_AC_PCMOV);
- outw(vol & ~PCMOV_PCMOM, s->io+IT_AC_PCMOV);
- vol = inw(s->io+IT_AC_FMOV);
- outw(vol & ~FMOV_FMOM, s->io+IT_AC_FMOV);
-
- /* set channel defaults to 8-bit, mono, 8 Khz */
- s->pcc = 0;
- s->capcc = 0;
- set_dac_rate(s, 8000);
- set_adc_rate(s, 8000);
-
- /* set mic to be the recording source */
- val = SOUND_MASK_MIC;
- mixdev_ioctl(&s->codec, SOUND_MIXER_WRITE_RECSRC,
- (unsigned long)&val);
-
- /* mute AC'97 master and PCM when in S/PDIF mode */
- if (s->spdif_volume != -1) {
- val = 0x0000;
- s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_VOLUME,
- (unsigned long)&val);
- s->codec.mixer_ioctl(&s->codec, SOUND_MIXER_WRITE_PCM,
- (unsigned long)&val);
- }
-
-#ifdef IT8172_DEBUG
- sprintf(proc_str, "driver/%s/%d/ac97", IT8172_MODULE_NAME,
- s->codec.id);
- s->ac97_ps = create_proc_read_entry (proc_str, 0, NULL,
- ac97_read_proc, &s->codec);
-#endif
-
- /* store it in the driver field */
- pci_set_drvdata(pcidev, s);
- pcidev->dma_mask = 0xffffffff;
- /* put it into driver list */
- list_add_tail(&s->devs, &devs);
- /* increment devindex */
- if (devindex < NR_DEVICE-1)
- devindex++;
- return 0;
-
- err_dev3:
- unregister_sound_mixer(s->codec.dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- err("cannot register misc device");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->io, pci_resource_len(pcidev,0));
- err_region:
- kfree(s);
- return -1;
-}
-
-static void __devexit it8172_remove(struct pci_dev *dev)
-{
- struct it8172_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- list_del(&s->devs);
-#ifdef IT8172_DEBUG
- if (s->ps)
- remove_proc_entry(IT8172_MODULE_NAME, NULL);
-#endif /* IT8172_DEBUG */
- synchronize_irq(s->irq);
- free_irq(s->irq, s);
- release_region(s->io, pci_resource_len(dev,0));
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->codec.dev_mixer);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_IT8172G_AUDIO, PCI_ANY_ID,
- PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver it8172_driver = {
- .name = IT8172_MODULE_NAME,
- .id_table = id_table,
- .probe = it8172_probe,
- .remove = __devexit_p(it8172_remove)
-};
-
-static int __init init_it8172(void)
-{
- info("version v0.5 time " __TIME__ " " __DATE__);
- return pci_register_driver(&it8172_driver);
-}
-
-static void __exit cleanup_it8172(void)
-{
- info("unloading");
- pci_unregister_driver(&it8172_driver);
-}
-
-module_init(init_it8172);
-module_exit(cleanup_it8172);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: it8172=[spdif],[i2s:<I2S format>] */
-
-static int __init it8172_setup(char *options)
-{
- char* this_opt;
- static unsigned __initdata nr_dev = 0;
-
- if (nr_dev >= NR_DEVICE)
- return 0;
-
- if (!options || !*options)
- return 0;
-
- while (this_opt = strsep(&options, ",")) {
- if (!*this_opt)
- continue;
- if (!strncmp(this_opt, "spdif", 5)) {
- spdif[nr_dev] = 1;
- } else if (!strncmp(this_opt, "i2s:", 4)) {
- if (!strncmp(this_opt+4, "dac", 3))
- i2s_fmt[nr_dev] = I2SMC_I2SF_DAC;
- else if (!strncmp(this_opt+4, "adc", 3))
- i2s_fmt[nr_dev] = I2SMC_I2SF_ADC;
- else if (!strncmp(this_opt+4, "i2s", 3))
- i2s_fmt[nr_dev] = I2SMC_I2SF_I2S;
- }
- }
-
- nr_dev++;
- return 1;
-}
-
-__setup("it8172=", it8172_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/iwmem.h b/sound/oss/iwmem.h
deleted file mode 100644
index 84745fbcabcb..000000000000
--- a/sound/oss/iwmem.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * sound/iwmem.h
- *
- * DRAM size encoding table for AMD Interwave chip.
- */
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * Bartlomiej Zolnierkiewicz : added __initdata to mem_decode
- */
-
-
-#define K 1024
-#define M (1024*K)
-static int mem_decode[][4] __initdata =
-{
-/* Bank0 Bank1 Bank2 Bank3 Encoding bits */
- {256*K, 0, 0, 0}, /* 0 */
- {256*K, 256*K, 0, 0}, /* 1 */
- {256*K, 256*K, 256*K, 256*K}, /* 2 */
- {256*K, 1*M, 0, 0}, /* 3 */
- {256*K, 1*M, 1*M, 1*M}, /* 4 */
- {256*K, 256*K, 1*M, 0}, /* 5 */
- {256*K, 256*K, 1*M, 1*M}, /* 6 */
- {1*M, 0, 0, 0}, /* 7 */
- {1*M, 1*M, 0, 0}, /* 8 */
- {1*M, 1*M, 1*M, 1*M}, /* 9 */
- {4*M, 0, 0, 0}, /* 10 */
- {4*M, 4*M, 0, 0}, /* 11 */
- {4*M, 4*M, 4*M, 4*M} /* 12 */
-};
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
deleted file mode 100644
index aa3c50db66c4..000000000000
--- a/sound/oss/mad16.c
+++ /dev/null
@@ -1,1113 +0,0 @@
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * mad16.c
- *
- * Initialization code for OPTi MAD16 compatible audio chips. Including
- *
- * OPTi 82C928 MAD16 (replaced by C929)
- * OAK OTI-601D Mozart
- * OAK OTI-605 Mozart (later version with MPU401 Midi)
- * OPTi 82C929 MAD16 Pro
- * OPTi 82C930
- * OPTi 82C924
- *
- * These audio interface chips don't produce sound themselves. They just
- * connect some other components (OPL-[234] and a WSS compatible codec)
- * to the PC bus and perform I/O, DMA and IRQ address decoding. There is
- * also a UART for the MPU-401 mode (not 82C928/Mozart).
- * The Mozart chip appears to be compatible with the 82C928, although later
- * issues of the card, using the OTI-605 chip, have an MPU-401 compatible Midi
- * port. This port is configured differently to that of the OPTi audio chips.
- *
- * Changes
- *
- * Alan Cox Clean up, added module selections.
- *
- * A. Wik Added support for Opti924 PnP.
- * Improved debugging support. 16-May-1998
- * Fixed bug. 16-Jun-1998
- *
- * Torsten Duwe Made Opti924 PnP support non-destructive
- * 23-Dec-1998
- *
- * Paul Grayson Added support for Midi on later Mozart cards.
- * 25-Nov-1999
- * Christoph Hellwig Adapted to module_init/module_exit.
- * Arnaldo C. de Melo got rid of attach_uart401 21-Sep-2000
- *
- * Pavel Rabel Clean up Nov-2000
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/gameport.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "sb.h"
-#include "mpu401.h"
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-static int mad16_conf;
-static int mad16_cdsel;
-static DEFINE_SPINLOCK(lock);
-
-#define C928 1
-#define MOZART 2
-#define C929 3
-#define C930 4
-#define C924 5
-
-/*
- * Registers
- *
- * The MAD16 occupies I/O ports 0xf8d to 0xf93 (fixed locations).
- * All ports are inactive by default. They can be activated by
- * writing 0xE2 or 0xE3 to the password register. The password is valid
- * only until the next I/O read or write.
- *
- * 82C930 uses 0xE4 as the password and indirect addressing to access
- * the config registers.
- */
-
-#define MC0_PORT 0xf8c /* Dummy port */
-#define MC1_PORT 0xf8d /* SB address, CD-ROM interface type, joystick */
-#define MC2_PORT 0xf8e /* CD-ROM address, IRQ, DMA, plus OPL4 bit */
-#define MC3_PORT 0xf8f
-#define PASSWD_REG 0xf8f
-#define MC4_PORT 0xf90
-#define MC5_PORT 0xf91
-#define MC6_PORT 0xf92
-#define MC7_PORT 0xf93
-#define MC8_PORT 0xf94
-#define MC9_PORT 0xf95
-#define MC10_PORT 0xf96
-#define MC11_PORT 0xf97
-#define MC12_PORT 0xf98
-
-static int board_type = C928;
-
-static int *mad16_osp;
-static int c931_detected; /* minor differences from C930 */
-static char c924pnp; /* " " " C924 */
-static int debug; /* debugging output */
-
-#ifdef DDB
-#undef DDB
-#endif
-#define DDB(x) do {if (debug) x;} while (0)
-
-static unsigned char mad_read(int port)
-{
- unsigned long flags;
- unsigned char tmp;
-
- spin_lock_irqsave(&lock,flags);
-
- switch (board_type) /* Output password */
- {
- case C928:
- case MOZART:
- outb((0xE2), PASSWD_REG);
- break;
-
- case C929:
- outb((0xE3), PASSWD_REG);
- break;
-
- case C930:
- /* outb(( 0xE4), PASSWD_REG); */
- break;
-
- case C924:
- /* the c924 has its ports relocated by -128 if
- PnP is enabled -aw */
- if (!c924pnp)
- outb((0xE5), PASSWD_REG); else
- outb((0xE5), PASSWD_REG - 0x80);
- break;
- }
-
- if (board_type == C930)
- {
- outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
- tmp = inb(0xe0f); /* Read from data reg */
- }
- else
- if (!c924pnp)
- tmp = inb(port); else
- tmp = inb(port-0x80);
- spin_unlock_irqrestore(&lock,flags);
-
- return tmp;
-}
-
-static void mad_write(int port, int value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
-
- switch (board_type) /* Output password */
- {
- case C928:
- case MOZART:
- outb((0xE2), PASSWD_REG);
- break;
-
- case C929:
- outb((0xE3), PASSWD_REG);
- break;
-
- case C930:
- /* outb(( 0xE4), PASSWD_REG); */
- break;
-
- case C924:
- if (!c924pnp)
- outb((0xE5), PASSWD_REG); else
- outb((0xE5), PASSWD_REG - 0x80);
- break;
- }
-
- if (board_type == C930)
- {
- outb((port - MC0_PORT), 0xe0e); /* Write to index reg */
- outb(((unsigned char) (value & 0xff)), 0xe0f);
- }
- else
- if (!c924pnp)
- outb(((unsigned char) (value & 0xff)), port); else
- outb(((unsigned char) (value & 0xff)), port-0x80);
- spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init detect_c930(void)
-{
- unsigned char tmp = mad_read(MC1_PORT);
-
- if ((tmp & 0x06) != 0x06)
- {
- DDB(printk("Wrong C930 signature (%x)\n", tmp));
- /* return 0; */
- }
- mad_write(MC1_PORT, 0);
-
- if (mad_read(MC1_PORT) != 0x06)
- {
- DDB(printk("Wrong C930 signature2 (%x)\n", tmp));
- /* return 0; */
- }
- mad_write(MC1_PORT, tmp); /* Restore bits */
-
- mad_write(MC7_PORT, 0);
- if ((tmp = mad_read(MC7_PORT)) != 0)
- {
- DDB(printk("MC7 not writable (%x)\n", tmp));
- return 0;
- }
- mad_write(MC7_PORT, 0xcb);
- if ((tmp = mad_read(MC7_PORT)) != 0xcb)
- {
- DDB(printk("MC7 not writable2 (%x)\n", tmp));
- return 0;
- }
-
- tmp = mad_read(MC0_PORT+18);
- if (tmp == 0xff || tmp == 0x00)
- return 1;
- /* We probably have a C931 */
- DDB(printk("Detected C931 config=0x%02x\n", tmp));
- c931_detected = 1;
-
- /*
- * We cannot configure the chip if it is in PnP mode.
- * If we have a CSN assigned (bit 8 in MC13) we first try
- * a software reset, then a software power off, finally
- * Clearing PnP mode. The last option is not
- * Bit 8 in MC13
- */
- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
- return 1;
-
- /* Software reset */
- mad_write(MC9_PORT, 0x02);
- mad_write(MC9_PORT, 0x00);
-
- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
- return 1;
-
- /* Power off, and on again */
- mad_write(MC9_PORT, 0xc2);
- mad_write(MC9_PORT, 0xc0);
-
- if ((mad_read(MC0_PORT+13) & 0x80) == 0)
- return 1;
-
-#if 0
- /* Force off PnP mode. This is not recommended because
- * the PnP bios will not recognize the chip on the next
- * warm boot and may assignd different resources to other
- * PnP/PCI cards.
- */
- mad_write(MC0_PORT+17, 0x04);
-#endif
- return 1;
-}
-
-static int __init detect_mad16(void)
-{
- unsigned char tmp, tmp2, bit;
- int i, port;
-
- /*
- * Check that reading a register doesn't return bus float (0xff)
- * when the card is accessed using password. This may fail in case
- * the card is in low power mode. Normally at least the power saving
- * mode bit should be 0.
- */
-
- if ((tmp = mad_read(MC1_PORT)) == 0xff)
- {
- DDB(printk("MC1_PORT returned 0xff\n"));
- return 0;
- }
- for (i = 0xf8d; i <= 0xf98; i++)
- if (!c924pnp)
- DDB(printk("Port %0x (init value) = %0x\n", i, mad_read(i)));
- else
- DDB(printk("Port %0x (init value) = %0x\n", i-0x80, mad_read(i)));
-
- if (board_type == C930)
- return detect_c930();
-
- /*
- * Now check that the gate is closed on first I/O after writing
- * the password. (This is how a MAD16 compatible card works).
- */
-
- if ((tmp2 = inb(MC1_PORT)) == tmp) /* It didn't close */
- {
- DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
- return 0;
- }
-
- bit = (c924pnp) ? 0x20 : 0x80;
- port = (c924pnp) ? MC2_PORT : MC1_PORT;
-
- tmp = mad_read(port);
- mad_write(port, tmp ^ bit); /* Toggle a bit */
- if ((tmp2 = mad_read(port)) != (tmp ^ bit)) /* Compare the bit */
- {
- mad_write(port, tmp); /* Restore */
- DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
- return 0;
- }
- mad_write(port, tmp); /* Restore */
- return 1; /* Bingo */
-}
-
-static int __init wss_init(struct address_info *hw_config)
-{
- /*
- * Check if the IO port returns valid signature. The original MS Sound
- * system returns 0x04 while some cards (AudioTrix Pro for example)
- * return 0x00.
- */
-
- if ((inb(hw_config->io_base + 3) & 0x3f) != 0x04 &&
- (inb(hw_config->io_base + 3) & 0x3f) != 0x00)
- {
- DDB(printk("No MSS signature detected on port 0x%x (0x%x)\n", hw_config->io_base, inb(hw_config->io_base + 3)));
- return 0;
- }
- /*
- * Check that DMA0 is not in use with a 8 bit board.
- */
- if (hw_config->dma == 0 && inb(hw_config->io_base + 3) & 0x80)
- {
- printk("MSS: Can't use DMA0 with a 8 bit card/slot\n");
- return 0;
- }
- if (hw_config->irq > 9 && inb(hw_config->io_base + 3) & 0x80)
- printk(KERN_ERR "MSS: Can't use IRQ%d with a 8 bit card/slot\n", hw_config->irq);
- return 1;
-}
-
-static void __init init_c930(struct address_info *hw_config, int base)
-{
- unsigned char cfg = 0;
-
- cfg |= (0x0f & mad16_conf);
-
- if(c931_detected)
- {
- /* Bit 0 has reversd meaning. Bits 1 and 2 sese
- reversed on write.
- Support only IDE cdrom. IDE port programmed
- somewhere else. */
- cfg = (cfg & 0x09) ^ 0x07;
- }
- cfg |= base << 4;
- mad_write(MC1_PORT, cfg);
-
- /* MC2 is CD configuration. Don't touch it. */
-
- mad_write(MC3_PORT, 0); /* Disable SB mode IRQ and DMA */
-
- /* bit 2 of MC4 reverses it's meaning between the C930
- and the C931. */
- cfg = c931_detected ? 0x04 : 0x00;
-
- if(mad16_cdsel & 0x20)
- mad_write(MC4_PORT, 0x62|cfg); /* opl4 */
- else
- mad_write(MC4_PORT, 0x52|cfg); /* opl3 */
-
- mad_write(MC5_PORT, 0x3C); /* Init it into mode2 */
- mad_write(MC6_PORT, 0x02); /* Enable WSS, Disable MPU and SB */
- mad_write(MC7_PORT, 0xCB);
- mad_write(MC10_PORT, 0x11);
-}
-
-static int __init chip_detect(void)
-{
- int i;
-
- /*
- * Then try to detect with the old password
- */
- board_type = C924;
-
- DDB(printk("Detect using password = 0xE5\n"));
-
- if (detect_mad16()) {
- return 1;
- }
-
- board_type = C928;
-
- DDB(printk("Detect using password = 0xE2\n"));
-
- if (detect_mad16())
- {
- unsigned char model;
-
- if (((model = mad_read(MC3_PORT)) & 0x03) == 0x03) {
- DDB(printk("mad16.c: Mozart detected\n"));
- board_type = MOZART;
- } else {
- DDB(printk("mad16.c: 82C928 detected???\n"));
- board_type = C928;
- }
- return 1;
- }
-
- board_type = C929;
-
- DDB(printk("Detect using password = 0xE3\n"));
-
- if (detect_mad16())
- {
- DDB(printk("mad16.c: 82C929 detected\n"));
- return 1;
- }
-
- if (inb(PASSWD_REG) != 0xff)
- return 0;
-
- /*
- * First relocate MC# registers to 0xe0e/0xe0f, disable password
- */
-
- outb((0xE4), PASSWD_REG);
- outb((0x80), PASSWD_REG);
-
- board_type = C930;
-
- DDB(printk("Detect using password = 0xE4\n"));
-
- for (i = 0xf8d; i <= 0xf93; i++)
- DDB(printk("port %03x = %02x\n", i, mad_read(i)));
-
- if(detect_mad16()) {
- DDB(printk("mad16.c: 82C930 detected\n"));
- return 1;
- }
-
- /* The C931 has the password reg at F8D */
- outb((0xE4), 0xF8D);
- outb((0x80), 0xF8D);
- DDB(printk("Detect using password = 0xE4 for C931\n"));
-
- if (detect_mad16()) {
- return 1;
- }
-
- board_type = C924;
- c924pnp++;
- DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
- if (detect_mad16()) {
- DDB(printk("mad16.c: 82C924 PnP detected\n"));
- return 1;
- }
-
- c924pnp=0;
-
- return 0;
-}
-
-static int __init probe_mad16(struct address_info *hw_config)
-{
- int i;
- unsigned char tmp;
- unsigned char cs4231_mode = 0;
-
- int ad_flags = 0;
-
- signed char bits;
-
- static char dma_bits[4] = {
- 1, 2, 0, 3
- };
-
- int config_port = hw_config->io_base + 0, version_port = hw_config->io_base + 3;
- int dma = hw_config->dma, dma2 = hw_config->dma2;
- unsigned char dma2_bit = 0;
- int base;
- struct resource *ports;
-
- mad16_osp = hw_config->osp;
-
- switch (hw_config->io_base) {
- case 0x530:
- base = 0;
- break;
- case 0xe80:
- base = 1;
- break;
- case 0xf40:
- base = 2;
- break;
- case 0x604:
- base = 3;
- break;
- default:
- printk(KERN_ERR "MAD16/Mozart: Bad WSS base address 0x%x\n", hw_config->io_base);
- return 0;
- }
-
- if (dma != 0 && dma != 1 && dma != 3) {
- printk(KERN_ERR "MSS: Bad DMA %d\n", dma);
- return 0;
- }
-
- /*
- * Check that all ports return 0xff (bus float) when no password
- * is written to the password register.
- */
-
- DDB(printk("--- Detecting MAD16 / Mozart ---\n"));
- if (!chip_detect())
- return 0;
-
- switch (hw_config->irq) {
- case 7:
- bits = 8;
- break;
- case 9:
- bits = 0x10;
- break;
- case 10:
- bits = 0x18;
- break;
- case 12:
- bits = 0x20;
- break;
- case 5: /* Also IRQ5 is possible on C930 */
- if (board_type == C930 || c924pnp) {
- bits = 0x28;
- break;
- }
- default:
- printk(KERN_ERR "MAD16/Mozart: Bad IRQ %d\n", hw_config->irq);
- return 0;
- }
-
- ports = request_region(hw_config->io_base + 4, 4, "ad1848");
- if (!ports) {
- printk(KERN_ERR "MSS: I/O port conflict\n");
- return 0;
- }
- if (!request_region(hw_config->io_base, 4, "mad16 WSS config")) {
- release_region(hw_config->io_base + 4, 4);
- printk(KERN_ERR "MSS: I/O port conflict\n");
- return 0;
- }
-
- if (board_type == C930) {
- init_c930(hw_config, base);
- goto got_it;
- }
-
- for (i = 0xf8d; i <= 0xf93; i++) {
- if (!c924pnp)
- DDB(printk("port %03x = %02x\n", i, mad_read(i)));
- else
- DDB(printk("port %03x = %02x\n", i-0x80, mad_read(i)));
- }
-
-/*
- * Set the WSS address
- */
-
- tmp = (mad_read(MC1_PORT) & 0x0f) | 0x80; /* Enable WSS, Disable SB */
- tmp |= base << 4; /* WSS port select bits */
-
- /*
- * Set optional CD-ROM and joystick settings.
- */
-
- tmp &= ~0x0f;
- tmp |= (mad16_conf & 0x0f); /* CD-ROM and joystick bits */
- mad_write(MC1_PORT, tmp);
-
- tmp = mad16_cdsel;
- mad_write(MC2_PORT, tmp);
- mad_write(MC3_PORT, 0xf0); /* Disable SB */
-
- if (board_type == C924) /* Specific C924 init values */
- {
- mad_write(MC4_PORT, 0xA0);
- mad_write(MC5_PORT, 0x05);
- mad_write(MC6_PORT, 0x03);
- }
- if (!ad1848_detect(ports, &ad_flags, mad16_osp))
- goto fail;
-
- if (ad_flags & (AD_F_CS4231 | AD_F_CS4248))
- cs4231_mode = 0x02; /* CS4248/CS4231 sync delay switch */
-
- if (board_type == C929)
- {
- mad_write(MC4_PORT, 0xa2);
- mad_write(MC5_PORT, 0xA5 | cs4231_mode);
- mad_write(MC6_PORT, 0x03); /* Disable MPU401 */
- }
- else
- {
- mad_write(MC4_PORT, 0x02);
- mad_write(MC5_PORT, 0x30 | cs4231_mode);
- }
-
- for (i = 0xf8d; i <= 0xf93; i++) {
- if (!c924pnp)
- DDB(printk("port %03x after init = %02x\n", i, mad_read(i)));
- else
- DDB(printk("port %03x after init = %02x\n", i-0x80, mad_read(i)));
- }
-
-got_it:
- ad_flags = 0;
- if (!ad1848_detect(ports, &ad_flags, mad16_osp))
- goto fail;
-
- if (!wss_init(hw_config))
- goto fail;
-
- /*
- * Set the IRQ and DMA addresses.
- */
-
- outb((bits | 0x40), config_port);
- if ((inb(version_port) & 0x40) == 0)
- printk(KERN_ERR "[IRQ Conflict?]\n");
-
- /*
- * Handle the capture DMA channel
- */
-
- if (ad_flags & AD_F_CS4231 && dma2 != -1 && dma2 != dma)
- {
- if (!((dma == 0 && dma2 == 1) ||
- (dma == 1 && dma2 == 0) ||
- (dma == 3 && dma2 == 0)))
- { /* Unsupported combination. Try to swap channels */
- int tmp = dma;
-
- dma = dma2;
- dma2 = tmp;
- }
- if ((dma == 0 && dma2 == 1) || (dma == 1 && dma2 == 0) ||
- (dma == 3 && dma2 == 0))
- {
- dma2_bit = 0x04; /* Enable capture DMA */
- }
- else
- {
- printk("MAD16: Invalid capture DMA\n");
- dma2 = dma;
- }
- }
- else dma2 = dma;
-
- outb((bits | dma_bits[dma] | dma2_bit), config_port); /* Write IRQ+DMA setup */
-
- hw_config->slots[0] = ad1848_init("mad16 WSS", ports,
- hw_config->irq,
- dma,
- dma2, 0,
- hw_config->osp,
- THIS_MODULE);
- return 1;
-
-fail:
- release_region(hw_config->io_base + 4, 4);
- release_region(hw_config->io_base, 4);
- return 0;
-}
-
-static int __init probe_mad16_mpu(struct address_info *hw_config)
-{
- unsigned char tmp;
-
- if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
- {
-
-#ifdef CONFIG_MAD16_OLDCARD
-
- tmp = mad_read(MC3_PORT);
-
- /*
- * MAD16 SB base is defined by the WSS base. It cannot be changed
- * alone.
- * Ignore configured I/O base. Use the active setting.
- */
-
- if (mad_read(MC1_PORT) & 0x20)
- hw_config->io_base = 0x240;
- else
- hw_config->io_base = 0x220;
-
- switch (hw_config->irq)
- {
- case 5:
- tmp = (tmp & 0x3f) | 0x80;
- break;
- case 7:
- tmp = (tmp & 0x3f);
- break;
- case 11:
- tmp = (tmp & 0x3f) | 0x40;
- break;
- default:
- printk(KERN_ERR "mad16/Mozart: Invalid MIDI IRQ\n");
- return 0;
- }
-
- mad_write(MC3_PORT, tmp | 0x04);
- hw_config->driver_use_1 = SB_MIDI_ONLY;
- if (!request_region(hw_config->io_base, 16, "soundblaster"))
- return 0;
- if (!sb_dsp_detect(hw_config, 0, 0, NULL)) {
- release_region(hw_config->io_base, 16);
- return 0;
- }
-
- if (mad_read(MC1_PORT) & 0x20)
- hw_config->io_base = 0x240;
- else
- hw_config->io_base = 0x220;
-
- hw_config->name = "Mad16/Mozart";
- sb_dsp_init(hw_config, THIS_MODULE);
- return 1;
-#else
- /* assuming all later Mozart cards are identified as
- * either 82C928 or Mozart. If so, following code attempts
- * to set MPU register. TODO - add probing
- */
-
- tmp = mad_read(MC8_PORT);
-
- switch (hw_config->irq)
- {
- case 5:
- tmp |= 0x08;
- break;
- case 7:
- tmp |= 0x10;
- break;
- case 9:
- tmp |= 0x18;
- break;
- case 10:
- tmp |= 0x20;
- break;
- case 11:
- tmp |= 0x28;
- break;
- default:
- printk(KERN_ERR "mad16/MOZART: invalid mpu_irq\n");
- return 0;
- }
-
- switch (hw_config->io_base)
- {
- case 0x300:
- tmp |= 0x01;
- break;
- case 0x310:
- tmp |= 0x03;
- break;
- case 0x320:
- tmp |= 0x05;
- break;
- case 0x330:
- tmp |= 0x07;
- break;
- default:
- printk(KERN_ERR "mad16/MOZART: invalid mpu_io\n");
- return 0;
- }
-
- mad_write(MC8_PORT, tmp); /* write MPU port parameters */
- goto probe_401;
-#endif
- }
- tmp = mad_read(MC6_PORT) & 0x83;
- tmp |= 0x80; /* MPU-401 enable */
-
- /* Set the MPU base bits */
-
- switch (hw_config->io_base)
- {
- case 0x300:
- tmp |= 0x60;
- break;
- case 0x310:
- tmp |= 0x40;
- break;
- case 0x320:
- tmp |= 0x20;
- break;
- case 0x330:
- tmp |= 0x00;
- break;
- default:
- printk(KERN_ERR "MAD16: Invalid MIDI port 0x%x\n", hw_config->io_base);
- return 0;
- }
-
- /* Set the MPU IRQ bits */
-
- switch (hw_config->irq)
- {
- case 5:
- tmp |= 0x10;
- break;
- case 7:
- tmp |= 0x18;
- break;
- case 9:
- tmp |= 0x00;
- break;
- case 10:
- tmp |= 0x08;
- break;
- default:
- printk(KERN_ERR "MAD16: Invalid MIDI IRQ %d\n", hw_config->irq);
- break;
- }
-
- mad_write(MC6_PORT, tmp); /* Write MPU401 config */
-
-#ifndef CONFIG_MAD16_OLDCARD
-probe_401:
-#endif
- hw_config->driver_use_1 = SB_MIDI_ONLY;
- hw_config->name = "Mad16/Mozart";
- return probe_uart401(hw_config, THIS_MODULE);
-}
-
-static void __exit unload_mad16(struct address_info *hw_config)
-{
- ad1848_unload(hw_config->io_base + 4,
- hw_config->irq,
- hw_config->dma,
- hw_config->dma2, 0);
- release_region(hw_config->io_base, 4);
- sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static void __exit unload_mad16_mpu(struct address_info *hw_config)
-{
-#ifdef CONFIG_MAD16_OLDCARD
- if (board_type < C929) /* Early chip. No MPU support. Just SB MIDI */
- {
- sb_dsp_unload(hw_config, 0);
- return;
- }
-#endif
-
- unload_uart401(hw_config);
-}
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int found_mpu;
-
-static int __initdata mpu_io = 0;
-static int __initdata mpu_irq = 0;
-static int __initdata io = -1;
-static int __initdata dma = -1;
-static int __initdata dma16 = -1; /* Set this for modules that need it */
-static int __initdata irq = -1;
-static int __initdata cdtype = 0;
-static int __initdata cdirq = 0;
-static int __initdata cdport = 0x340;
-static int __initdata cddma = -1;
-static int __initdata opl4 = 0;
-static int __initdata joystick = 0;
-
-module_param(mpu_io, int, 0);
-module_param(mpu_irq, int, 0);
-module_param(io, int, 0);
-module_param(dma, int, 0);
-module_param(dma16, int, 0);
-module_param(irq, int, 0);
-module_param(cdtype, int, 0);
-module_param(cdirq, int, 0);
-module_param(cdport, int, 0);
-module_param(cddma, int, 0);
-module_param(opl4, int, 0);
-module_param(joystick, bool, 0);
-module_param(debug, bool, 0644);
-
-static int __initdata dma_map[2][8] =
-{
- {0x03, -1, -1, -1, -1, 0x00, 0x01, 0x02},
- {0x03, -1, 0x01, 0x00, -1, -1, -1, -1}
-};
-
-static int __initdata irq_map[16] =
-{
- 0x00, -1, -1, 0x0A,
- -1, 0x04, -1, 0x08,
- -1, 0x10, 0x14, 0x18,
- -1, -1, -1, -1
-};
-
-#ifdef SUPPORT_JOYSTICK
-
-static struct gameport *gameport;
-
-static int __devinit mad16_register_gameport(int io_port)
-{
- if (!request_region(io_port, 1, "mad16 gameport")) {
- printk(KERN_ERR "mad16: gameport address 0x%#x already in use\n", io_port);
- return -EBUSY;
- }
-
- gameport = gameport_allocate_port();
- if (!gameport) {
- printk(KERN_ERR "mad16: can not allocate memory for gameport\n");
- release_region(io_port, 1);
- return -ENOMEM;
- }
-
- gameport_set_name(gameport, "MAD16 Gameport");
- gameport_set_phys(gameport, "isa%04x/gameport0", io_port);
- gameport->io = io_port;
-
- gameport_register_port(gameport);
-
- return 0;
-}
-
-static inline void mad16_unregister_gameport(void)
-{
- if (gameport) {
- /* the gameport was initialized so we must free it up */
- gameport_unregister_port(gameport);
- gameport = NULL;
- release_region(0x201, 1);
- }
-}
-#else
-static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
-static inline void mad16_unregister_gameport(void) { }
-#endif
-
-static int __devinit init_mad16(void)
-{
- int dmatype = 0;
-
- printk(KERN_INFO "MAD16 audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
-
- printk(KERN_INFO "CDROM ");
- switch (cdtype)
- {
- case 0x00:
- printk("Disabled");
- cdirq = 0;
- break;
- case 0x02:
- printk("Sony CDU31A");
- dmatype = 1;
- if(cddma == -1) cddma = 3;
- break;
- case 0x04:
- printk("Mitsumi");
- dmatype = 0;
- if(cddma == -1) cddma = 5;
- break;
- case 0x06:
- printk("Panasonic Lasermate");
- dmatype = 1;
- if(cddma == -1) cddma = 3;
- break;
- case 0x08:
- printk("Secondary IDE");
- dmatype = 0;
- if(cddma == -1) cddma = 5;
- break;
- case 0x0A:
- printk("Primary IDE");
- dmatype = 0;
- if(cddma == -1) cddma = 5;
- break;
- default:
- printk("\n");
- printk(KERN_ERR "Invalid CDROM type\n");
- return -EINVAL;
- }
-
- /*
- * Build the config words
- */
-
- mad16_conf = (joystick ^ 1) | cdtype;
- mad16_cdsel = 0;
- if (opl4)
- mad16_cdsel |= 0x20;
-
- if(cdtype){
- if (cddma > 7 || cddma < 0 || dma_map[dmatype][cddma] == -1)
- {
- printk("\n");
- printk(KERN_ERR "Invalid CDROM DMA\n");
- return -EINVAL;
- }
- if (cddma)
- printk(", DMA %d", cddma);
- else
- printk(", no DMA");
-
- if (!cdirq)
- printk(", no IRQ");
- else if (cdirq < 0 || cdirq > 15 || irq_map[cdirq] == -1)
- {
- printk(", invalid IRQ (disabling)");
- cdirq = 0;
- }
- else printk(", IRQ %d", cdirq);
-
- mad16_cdsel |= dma_map[dmatype][cddma];
-
- if (cdtype < 0x08)
- {
- switch (cdport)
- {
- case 0x340:
- mad16_cdsel |= 0x00;
- break;
- case 0x330:
- mad16_cdsel |= 0x40;
- break;
- case 0x360:
- mad16_cdsel |= 0x80;
- break;
- case 0x320:
- mad16_cdsel |= 0xC0;
- break;
- default:
- printk(KERN_ERR "Unknown CDROM I/O base %d\n", cdport);
- return -EINVAL;
- }
- }
- mad16_cdsel |= irq_map[cdirq];
- }
-
- printk(".\n");
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma16;
-
- if (cfg.io_base == -1 || cfg.dma == -1 || cfg.irq == -1) {
- printk(KERN_ERR "I/O, DMA and irq are mandatory\n");
- return -EINVAL;
- }
-
- if (!request_region(MC0_PORT, 12, "mad16"))
- return -EBUSY;
-
- if (!probe_mad16(&cfg)) {
- release_region(MC0_PORT, 12);
- return -ENODEV;
- }
-
- cfg_mpu.io_base = mpu_io;
- cfg_mpu.irq = mpu_irq;
-
- found_mpu = probe_mad16_mpu(&cfg_mpu);
-
- if (joystick)
- mad16_register_gameport(0x201);
-
- return 0;
-}
-
-static void __exit cleanup_mad16(void)
-{
- if (found_mpu)
- unload_mad16_mpu(&cfg_mpu);
- mad16_unregister_gameport();
- unload_mad16(&cfg);
- release_region(MC0_PORT, 12);
-}
-
-module_init(init_mad16);
-module_exit(cleanup_mad16);
-
-#ifndef MODULE
-static int __init setup_mad16(char *str)
-{
- /* io, irq */
- int ints[8];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma16 = ints[4];
- mpu_io = ints[5];
- mpu_irq = ints[6];
- joystick = ints[7];
-
- return 1;
-}
-
-__setup("mad16=", setup_mad16);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
deleted file mode 100644
index 1d98d100d739..000000000000
--- a/sound/oss/maestro.c
+++ /dev/null
@@ -1,3686 +0,0 @@
-/*****************************************************************************
- *
- * ESS Maestro/Maestro-2/Maestro-2E driver for Linux 2.[23].x
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * (c) Copyright 1999 Alan Cox <alan.cox@linux.org>
- *
- * Based heavily on SonicVibes.c:
- * Copyright (C) 1998-1999 Thomas Sailer (sailer@ife.ee.ethz.ch)
- *
- * Heavily modified by Zach Brown <zab@zabbo.net> based on lunch
- * with ESS engineers. Many thanks to Howard Kim for providing
- * contacts and hardware. Honorable mention goes to Eric
- * Brombaugh for all sorts of things. Best regards to the
- * proprietors of Hack Central for fine lodging.
- *
- * Supported devices:
- * /dev/dsp0-3 standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- *
- * Hardware Description
- *
- * A working Maestro setup contains the Maestro chip wired to a
- * codec or 2. In the Maestro we have the APUs, the ASSP, and the
- * Wavecache. The APUs can be though of as virtual audio routing
- * channels. They can take data from a number of sources and perform
- * basic encodings of the data. The wavecache is a storehouse for
- * PCM data. Typically it deals with PCI and interracts with the
- * APUs. The ASSP is a wacky DSP like device that ESS is loth
- * to release docs on. Thankfully it isn't required on the Maestro
- * until you start doing insane things like FM emulation and surround
- * encoding. The codecs are almost always AC-97 compliant codecs,
- * but it appears that early Maestros may have had PT101 (an ESS
- * part?) wired to them. The only real difference in the Maestro
- * families is external goop like docking capability, memory for
- * the ASSP, and initialization differences.
- *
- * Driver Operation
- *
- * We only drive the APU/Wavecache as typical DACs and drive the
- * mixers in the codecs. There are 64 APUs. We assign 6 to each
- * /dev/dsp? device. 2 channels for output, and 4 channels for
- * input.
- *
- * Each APU can do a number of things, but we only really use
- * 3 basic functions. For playback we use them to convert PCM
- * data fetched over PCI by the wavecahche into analog data that
- * is handed to the codec. One APU for mono, and a pair for stereo.
- * When in stereo, the combination of smarts in the APU and Wavecache
- * decide which wavecache gets the left or right channel.
- *
- * For record we still use the old overly mono system. For each in
- * coming channel the data comes in from the codec, through a 'input'
- * APU, through another rate converter APU, and then into memory via
- * the wavecache and PCI. If its stereo, we mash it back into LRLR in
- * software. The pass between the 2 APUs is supposedly what requires us
- * to have a 512 byte buffer sitting around in wavecache/memory.
- *
- * The wavecache makes our life even more fun. First off, it can
- * only address the first 28 bits of PCI address space, making it
- * useless on quite a few architectures. Secondly, its insane.
- * It claims to fetch from 4 regions of PCI space, each 4 meg in length.
- * But that doesn't really work. You can only use 1 region. So all our
- * allocations have to be in 4meg of each other. Booo. Hiss.
- * So we have a module parameter, dsps_order, that is the order of
- * the number of dsps to provide. All their buffer space is allocated
- * on open time. The sonicvibes OSS routines we inherited really want
- * power of 2 buffers, so we have all those next to each other, then
- * 512 byte regions for the recording wavecaches. This ends up
- * wasting quite a bit of memory. The only fixes I can see would be
- * getting a kernel allocator that could work in zones, or figuring out
- * just how to coerce the WP into doing what we want.
- *
- * The indirection of the various registers means we have to spinlock
- * nearly all register accesses. We have the main register indirection
- * like the wave cache, maestro registers, etc. Then we have beasts
- * like the APU interface that is indirect registers gotten at through
- * the main maestro indirection. Ouch. We spinlock around the actual
- * ports on a per card basis. This means spinlock activity at each IO
- * operation, but the only IO operation clusters are in non critical
- * paths and it makes the code far easier to follow. Interrupts are
- * blocked while holding the locks because the int handler has to
- * get at some of them :(. The mixer interface doesn't, however.
- * We also have an OSS state lock that is thrown around in a few
- * places.
- *
- * This driver has brute force APM suspend support. We catch suspend
- * notifications and stop all work being done on the chip. Any people
- * that try between this shutdown and the real suspend operation will
- * be put to sleep. When we resume we restore our software state on
- * the chip and wake up the people that were using it. The code thats
- * being used now is quite dirty and assumes we're on a uni-processor
- * machine. Much of it will need to be cleaned up for SMP ACPI or
- * similar.
- *
- * We also pay attention to PCI power management now. The driver
- * will power down units of the chip that it knows aren't needed.
- * The WaveProcessor and company are only powered on when people
- * have /dev/dsp*s open. On removal the driver will
- * power down the maestro entirely. There could still be
- * trouble with BIOSen that magically change power states
- * themselves, but we'll see.
- *
- * History
- * v0.15 - May 21 2001 - Marcus Meissner <mm@caldera.de>
- * Ported to Linux 2.4 PCI API. Some clean ups, global devs list
- * removed (now using pci device driver data).
- * PM needs to be polished still. Bumped version.
- * (still kind of v0.14) May 13 2001 - Ben Pfaff <pfaffben@msu.edu>
- * Add support for 978 docking and basic hardware volume control
- * (still kind of v0.14) Nov 23 - Alan Cox <alan@redhat.com>
- * Add clocking= for people with seriously warped hardware
- * (still v0.14) Nov 10 2000 - Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * add __init to maestro_ac97_init() and maestro_install()
- * (still based on v0.14) Mar 29 2000 - Zach Brown <zab@redhat.com>
- * move to 2.3 power management interface, which
- * required hacking some suspend/resume/check paths
- * make static compilation work
- * v0.14 - Jan 28 2000 - Zach Brown <zab@redhat.com>
- * add PCI power management through ACPI regs.
- * we now shut down on machine reboot/halt
- * leave scary PCI config items alone (isa stuff, mostly)
- * enable 1921s, it seems only mine was broke.
- * fix swapped left/right pcm dac. har har.
- * up bob freq, increase buffers, fix pointers at underflow
- * silly compilation problems
- * v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
- * fix nec Versas? man would that be cool.
- * v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
- * brown bag volume max fix..
- * v0.11 - Nov 11 1999 - Zach Brown <zab@redhat.com>
- * use proper stereo apu decoding, mmap/write should work.
- * make volume sliders more useful, tweak rate calculation.
- * fix lame 8bit format reporting bug. duh. apm apu saving buglet also
- * fix maestro 1 clock freq "bug", remove pt101 support
- * v0.10 - Oct 28 1999 - Zach Brown <zab@redhat.com>
- * aha, so, sometimes the WP writes a status word to offset 0
- * from one of the PCMBARs. rearrange allocation accordingly..
- * cheers again to Eric for being a good hacker in investigating this.
- * Jeroen Hoogervorst submits 7500 fix out of nowhere. yay. :)
- * v0.09 - Oct 23 1999 - Zach Brown <zab@redhat.com>
- * added APM support.
- * re-order something such that some 2Es now work. Magic!
- * new codec reset routine. made some codecs come to life.
- * fix clear_advance, sync some control with ESS.
- * now write to all base regs to be paranoid.
- * v0.08 - Oct 20 1999 - Zach Brown <zab@redhat.com>
- * Fix initial buflen bug. I am so smart. also smp compiling..
- * I owe Eric yet another beer: fixed recmask, igain,
- * muting, and adc sync consistency. Go Team.
- * v0.07 - Oct 4 1999 - Zach Brown <zab@redhat.com>
- * tweak adc/dac, formating, and stuff to allow full duplex
- * allocate dsps memory at open() so we can fit in the wavecache window
- * fix wavecache braindamage. again. no more scribbling?
- * fix ess 1921 codec bug on some laptops.
- * fix dumb pci scanning bug
- * started 2.3 cleanup, redid spinlocks, little cleanups
- * v0.06 - Sep 20 1999 - Zach Brown <zab@redhat.com>
- * fix wavecache thinkos. limit to 1 /dev/dsp.
- * eric is wearing his thinking toque this week.
- * spotted apu mode bugs and gain ramping problem
- * don't touch weird mixer regs, make recmask optional
- * fixed igain inversion, defaults for mixers, clean up rec_start
- * make mono recording work.
- * report subsystem stuff, please send reports.
- * littles: parallel out, amp now
- * v0.05 - Sep 17 1999 - Zach Brown <zab@redhat.com>
- * merged and fixed up Eric's initial recording code
- * munged format handling to catch misuse, needs rewrite.
- * revert ring bus init, fixup shared int, add pci busmaster setting
- * fix mixer oss interface, fix mic mute and recmask
- * mask off unsupported mixers, reset with all 1s, modularize defaults
- * make sure bob is running while we need it
- * got rid of device limit, initial minimal apm hooks
- * pull out dead code/includes, only allow multimedia/audio maestros
- * v0.04 - Sep 01 1999 - Zach Brown <zab@redhat.com>
- * copied memory leak fix from sonicvibes driver
- * different ac97 reset, play with 2.0 ac97, simplify ring bus setup
- * bob freq code, region sanity, jitter sync fix; all from Eric
- *
- * TODO
- * fix bob frequency
- * endianness
- * do smart things with ac97 2.0 bits.
- * dual codecs
- * leave 54->61 open
- *
- * it also would be fun to have a mode that would not use pci dma at all
- * but would copy into the wavecache on board memory and use that
- * on architectures that don't like the maestro's pci dma ickiness.
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/reboot.h>
-#include <linux/bitops.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-
-#include <asm/current.h>
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "maestro.h"
-
-static struct pci_driver maestro_pci_driver;
-
-/* --------------------------------------------------------------------- */
-
-#define M_DEBUG 1
-
-#ifdef M_DEBUG
-static int debug;
-#define M_printk(args...) {if (debug) printk(args);}
-#else
-#define M_printk(x)
-#endif
-
-/* we try to setup 2^(dsps_order) /dev/dsp devices */
-static int dsps_order;
-/* whether or not we mess around with power management */
-static int use_pm=2; /* set to 1 for force */
-/* clocking for broken hardware - a few laptops seem to use a 50Khz clock
- ie insmod with clocking=50000 or so */
-
-static int clocking=48000;
-
-MODULE_AUTHOR("Zach Brown <zab@zabbo.net>, Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("ESS Maestro Driver");
-MODULE_LICENSE("GPL");
-
-#ifdef M_DEBUG
-module_param(debug, bool, 0644);
-#endif
-module_param(dsps_order, int, 0);
-module_param(use_pm, int, 0);
-module_param(clocking, int, 0);
-
-/* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.15"
-
-#ifndef PCI_VENDOR_ESS
-#define PCI_VENDOR_ESS 0x125D
-#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */
-#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */
-
-#define PCI_VENDOR_ESS_OLD 0x1285 /* Platform Tech,
- the people the maestro
- was bought from */
-#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 /* maestro 1 */
-#endif /* PCI_VENDOR_ESS */
-
-#define ESS_CHAN_HARD 0x100
-
-/* NEC Versas ? */
-#define NEC_VERSA_SUBID1 0x80581033
-#define NEC_VERSA_SUBID2 0x803c1033
-
-
-/* changed so that I could actually find all the
- references and fix them up. it's a little more readable now. */
-#define ESS_FMT_STEREO 0x01
-#define ESS_FMT_16BIT 0x02
-#define ESS_FMT_MASK 0x03
-#define ESS_DAC_SHIFT 0
-#define ESS_ADC_SHIFT 4
-
-#define ESS_STATE_MAGIC 0x125D1968
-#define ESS_CARD_MAGIC 0x19283746
-
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
-
-#define MAX_DSP_ORDER 2
-#define MAX_DSPS (1<<MAX_DSP_ORDER)
-#define NR_DSPS (1<<dsps_order)
-#define NR_IDRS 32
-
-#define NR_APUS 64
-#define NR_APU_REGS 16
-
-/* acpi states */
-enum {
- ACPI_D0=0,
- ACPI_D1,
- ACPI_D2,
- ACPI_D3
-};
-
-/* bits in the acpi masks */
-#define ACPI_12MHZ ( 1 << 15)
-#define ACPI_24MHZ ( 1 << 14)
-#define ACPI_978 ( 1 << 13)
-#define ACPI_SPDIF ( 1 << 12)
-#define ACPI_GLUE ( 1 << 11)
-#define ACPI__10 ( 1 << 10) /* reserved */
-#define ACPI_PCIINT ( 1 << 9)
-#define ACPI_HV ( 1 << 8) /* hardware volume */
-#define ACPI_GPIO ( 1 << 7)
-#define ACPI_ASSP ( 1 << 6)
-#define ACPI_SB ( 1 << 5) /* sb emul */
-#define ACPI_FM ( 1 << 4) /* fm emul */
-#define ACPI_RB ( 1 << 3) /* ringbus / aclink */
-#define ACPI_MIDI ( 1 << 2)
-#define ACPI_GP ( 1 << 1) /* game port */
-#define ACPI_WP ( 1 << 0) /* wave processor */
-
-#define ACPI_ALL (0xffff)
-#define ACPI_SLEEP (~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \
- ACPI_MIDI|ACPI_GP|ACPI_WP))
-#define ACPI_NONE (ACPI__10)
-
-/* these masks indicate which units we care about at
- which states */
-static u16 acpi_state_mask[] = {
- [ACPI_D0] = ACPI_ALL,
- [ACPI_D1] = ACPI_SLEEP,
- [ACPI_D2] = ACPI_SLEEP,
- [ACPI_D3] = ACPI_NONE
-};
-
-static char version[] __devinitdata =
-KERN_INFO "maestro: version " DRIVER_VERSION " time " __TIME__ " " __DATE__ "\n";
-
-
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-enum card_types_t {
- TYPE_MAESTRO,
- TYPE_MAESTRO2,
- TYPE_MAESTRO2E
-};
-
-static const char *card_names[]={
- [TYPE_MAESTRO] = "ESS Maestro",
- [TYPE_MAESTRO2] = "ESS Maestro 2",
- [TYPE_MAESTRO2E] = "ESS Maestro 2E"
-};
-
-static int clock_freq[]={
- [TYPE_MAESTRO] = (49152000L / 1024L),
- [TYPE_MAESTRO2] = (50000000L / 1024L),
- [TYPE_MAESTRO2E] = (50000000L / 1024L)
-};
-
-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-
-static struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
-
-/* --------------------------------------------------------------------- */
-
-struct ess_state {
- unsigned int magic;
- /* FIXME: we probably want submixers in here, but only one record pair */
- u8 apu[6]; /* l/r output, l/r intput converters, l/r input apus */
- u8 apu_mode[6]; /* Running mode for this APU */
- u8 apu_pan[6]; /* Panning setup for this APU */
- u32 apu_base[6]; /* base address for this apu */
- struct ess_card *card; /* Card info */
- /* wave stuff */
- unsigned int rateadc, ratedac;
- unsigned char fmt, enable;
-
- int index;
-
- /* this locks around the oss state in the driver */
- spinlock_t lock;
- /* only let 1 be opening at a time */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
- mode_t open_mode;
-
- /* soundcore stuff */
- int dev_audio;
-
- struct dmabuf {
- void *rawbuf;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- /* XXX zab - swptr only in here so that it can be referenced by
- clear_advance, as far as I can tell :( */
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1; /* our oss buffers are ready to go */
- unsigned endcleared:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- u16 base; /* Offset for ptr */
- } dma_dac, dma_adc;
-
- /* pointer to each dsp?s piece of the apu->src buffer page */
- void *mixbuf;
-
-};
-
-struct ess_card {
- unsigned int magic;
-
- /* We keep maestro cards in a linked list */
- struct ess_card *next;
-
- int dev_mixer;
-
- int card_type;
-
- /* as most of this is static,
- perhaps it should be a pointer to a global struct */
- struct mixer_goo {
- int modcnt;
- int supported_mixers;
- int stereo_mixers;
- int record_sources;
- /* the caller must guarantee arg sanity before calling these */
-/* int (*read_mixer)(struct ess_card *card, int index);*/
- void (*write_mixer)(struct ess_card *card,int mixer, unsigned int left,unsigned int right);
- int (*recmask_io)(struct ess_card *card,int rw,int mask);
- unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
- } mix;
-
- int power_regs;
-
- int in_suspend;
- wait_queue_head_t suspend_queue;
-
- struct ess_state channels[MAX_DSPS];
- u16 maestro_map[NR_IDRS]; /* Register map */
- /* we have to store this junk so that we can come back from a
- suspend */
- u16 apu_map[NR_APUS][NR_APU_REGS]; /* contents of apu regs */
-
- /* this locks around the physical registers on the card */
- spinlock_t lock;
-
- /* memory for this card.. wavecache limited :(*/
- void *dmapages;
- int dmaorder;
-
- /* hardware resources */
- struct pci_dev *pcidev;
- u32 iobase;
- u32 irq;
-
- int bob_freq;
- char dsps_open;
-
- int dock_mute_vol;
-};
-
-static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val );
-
-static unsigned
-ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static void check_suspend(struct ess_card *card);
-
-/* --------------------------------------------------------------------- */
-
-
-/*
- * ESS Maestro AC97 codec programming interface.
- */
-
-static void maestro_ac97_set(struct ess_card *card, u8 cmd, u16 val)
-{
- int io = card->iobase;
- int i;
- /*
- * Wait for the codec bus to be free
- */
-
- check_suspend(card);
-
- for(i=0;i<10000;i++)
- {
- if(!(inb(io+ESS_AC97_INDEX)&1))
- break;
- }
- /*
- * Write the bus
- */
- outw(val, io+ESS_AC97_DATA);
- mdelay(1);
- outb(cmd, io+ESS_AC97_INDEX);
- mdelay(1);
-}
-
-static u16 maestro_ac97_get(struct ess_card *card, u8 cmd)
-{
- int io = card->iobase;
- int sanity=10000;
- u16 data;
- int i;
-
- check_suspend(card);
- /*
- * Wait for the codec bus to be free
- */
-
- for(i=0;i<10000;i++)
- {
- if(!(inb(io+ESS_AC97_INDEX)&1))
- break;
- }
-
- outb(cmd|0x80, io+ESS_AC97_INDEX);
- mdelay(1);
-
- while(inb(io+ESS_AC97_INDEX)&1)
- {
- sanity--;
- if(!sanity)
- {
- printk(KERN_ERR "maestro: ac97 codec timeout reading 0x%x.\n",cmd);
- return 0;
- }
- }
- data=inw(io+ESS_AC97_DATA);
- mdelay(1);
- return data;
-}
-
-/* OSS interface to the ac97s.. */
-
-#define AC97_STEREO_MASK (SOUND_MASK_VOLUME|\
- SOUND_MASK_PCM|SOUND_MASK_LINE|SOUND_MASK_CD|\
- SOUND_MASK_VIDEO|SOUND_MASK_LINE1|SOUND_MASK_IGAIN)
-
-#define AC97_SUPPORTED_MASK (AC97_STEREO_MASK | \
- SOUND_MASK_BASS|SOUND_MASK_TREBLE|SOUND_MASK_MIC|\
- SOUND_MASK_SPEAKER)
-
-#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
- SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
- SOUND_MASK_PHONEIN)
-
-#define supported_mixer(CARD,FOO) ( CARD->mix.supported_mixers & (1<<FOO) )
-
-/* this table has default mixer values for all OSS mixers.
- be sure to fill it in if you add oss mixers
- to anyone's supported mixer defines */
-
-static unsigned int mixer_defaults[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_VOLUME] = 0x3232,
- [SOUND_MIXER_BASS] = 0x3232,
- [SOUND_MIXER_TREBLE] = 0x3232,
- [SOUND_MIXER_SPEAKER] = 0x3232,
- [SOUND_MIXER_MIC] = 0x8000, /* annoying */
- [SOUND_MIXER_LINE] = 0x3232,
- [SOUND_MIXER_CD] = 0x3232,
- [SOUND_MIXER_VIDEO] = 0x3232,
- [SOUND_MIXER_LINE1] = 0x3232,
- [SOUND_MIXER_PCM] = 0x3232,
- [SOUND_MIXER_IGAIN] = 0x3232
-};
-
-static struct ac97_mixer_hw {
- unsigned char offset;
- int scale;
-} ac97_hw[SOUND_MIXER_NRDEVICES]= {
- [SOUND_MIXER_VOLUME] = {0x02,63},
- [SOUND_MIXER_BASS] = {0x08,15},
- [SOUND_MIXER_TREBLE] = {0x08,15},
- [SOUND_MIXER_SPEAKER] = {0x0a,15},
- [SOUND_MIXER_MIC] = {0x0e,31},
- [SOUND_MIXER_LINE] = {0x10,31},
- [SOUND_MIXER_CD] = {0x12,31},
- [SOUND_MIXER_VIDEO] = {0x14,31},
- [SOUND_MIXER_LINE1] = {0x16,31},
- [SOUND_MIXER_PCM] = {0x18,31},
- [SOUND_MIXER_IGAIN] = {0x1c,15}
-};
-
-#if 0 /* *shrug* removed simply because we never used it.
- feel free to implement again if needed */
-
-/* reads the given OSS mixer from the ac97
- the caller must have insured that the ac97 knows
- about that given mixer, and should be holding a
- spinlock for the card */
-static int ac97_read_mixer(struct ess_card *card, int mixer)
-{
- u16 val;
- int ret=0;
- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
- val = maestro_ac97_get(card, mh->offset);
-
- if(AC97_STEREO_MASK & (1<<mixer)) {
- /* nice stereo mixers .. */
- int left,right;
-
- left = (val >> 8) & 0x7f;
- right = val & 0x7f;
-
- if (mixer == SOUND_MIXER_IGAIN) {
- right = (right * 100) / mh->scale;
- left = (left * 100) / mh->scale;
- } else {
- right = 100 - ((right * 100) / mh->scale);
- left = 100 - ((left * 100) / mh->scale);
- }
-
- ret = left | (right << 8);
- } else if (mixer == SOUND_MIXER_SPEAKER) {
- ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
- } else if (mixer == SOUND_MIXER_MIC) {
- ret = 100 - (((val & 0x1f) * 100) / mh->scale);
- /* the low bit is optional in the tone sliders and masking
- it lets is avoid the 0xf 'bypass'.. */
- } else if (mixer == SOUND_MIXER_BASS) {
- ret = 100 - ((((val >> 8) & 0xe) * 100) / mh->scale);
- } else if (mixer == SOUND_MIXER_TREBLE) {
- ret = 100 - (((val & 0xe) * 100) / mh->scale);
- }
-
- M_printk("read mixer %d (0x%x) %x -> %x\n",mixer,mh->offset,val,ret);
-
- return ret;
-}
-#endif
-
-/* write the OSS encoded volume to the given OSS encoded mixer,
- again caller's job to make sure all is well in arg land,
- call with spinlock held */
-
-/* linear scale -> log */
-static unsigned char lin2log[101] =
-{
-0, 0 , 15 , 23 , 30 , 34 , 38 , 42 , 45 , 47 ,
-50 , 52 , 53 , 55 , 57 , 58 , 60 , 61 , 62 ,
-63 , 65 , 66 , 67 , 68 , 69 , 69 , 70 , 71 ,
-72 , 73 , 73 , 74 , 75 , 75 , 76 , 77 , 77 ,
-78 , 78 , 79 , 80 , 80 , 81 , 81 , 82 , 82 ,
-83 , 83 , 84 , 84 , 84 , 85 , 85 , 86 , 86 ,
-87 , 87 , 87 , 88 , 88 , 88 , 89 , 89 , 89 ,
-90 , 90 , 90 , 91 , 91 , 91 , 92 , 92 , 92 ,
-93 , 93 , 93 , 94 , 94 , 94 , 94 , 95 , 95 ,
-95 , 95 , 96 , 96 , 96 , 96 , 97 , 97 , 97 ,
-97 , 98 , 98 , 98 , 98 , 99 , 99 , 99 , 99 , 99
-};
-
-static void ac97_write_mixer(struct ess_card *card,int mixer, unsigned int left, unsigned int right)
-{
- u16 val=0;
- struct ac97_mixer_hw *mh = &ac97_hw[mixer];
-
- M_printk("wrote mixer %d (0x%x) %d,%d",mixer,mh->offset,left,right);
-
- if(AC97_STEREO_MASK & (1<<mixer)) {
- /* stereo mixers, mute them if we can */
-
- if (mixer == SOUND_MIXER_IGAIN) {
- /* igain's slider is reversed.. */
- right = (right * mh->scale) / 100;
- left = (left * mh->scale) / 100;
- if ((left == 0) && (right == 0))
- val |= 0x8000;
- } else if (mixer == SOUND_MIXER_PCM || mixer == SOUND_MIXER_CD) {
- /* log conversion seems bad for them */
- if ((left == 0) && (right == 0))
- val = 0x8000;
- right = ((100 - right) * mh->scale) / 100;
- left = ((100 - left) * mh->scale) / 100;
- } else {
- /* log conversion for the stereo controls */
- if((left == 0) && (right == 0))
- val = 0x8000;
- right = ((100 - lin2log[right]) * mh->scale) / 100;
- left = ((100 - lin2log[left]) * mh->scale) / 100;
- }
-
- val |= (left << 8) | right;
-
- } else if (mixer == SOUND_MIXER_SPEAKER) {
- val = (((100 - left) * mh->scale) / 100) << 1;
- } else if (mixer == SOUND_MIXER_MIC) {
- val = maestro_ac97_get(card, mh->offset) & ~0x801f;
- val |= (((100 - left) * mh->scale) / 100);
- /* the low bit is optional in the tone sliders and masking
- it lets is avoid the 0xf 'bypass'.. */
- } else if (mixer == SOUND_MIXER_BASS) {
- val = maestro_ac97_get(card , mh->offset) & ~0x0f00;
- val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (mixer == SOUND_MIXER_TREBLE) {
- val = maestro_ac97_get(card , mh->offset) & ~0x000f;
- val |= (((100 - left) * mh->scale) / 100) & 0x000e;
- }
-
- maestro_ac97_set(card , mh->offset, val);
-
- M_printk(" -> %x\n",val);
-}
-
-/* the following tables allow us to go from
- OSS <-> ac97 quickly. */
-
-enum ac97_recsettings {
- AC97_REC_MIC=0,
- AC97_REC_CD,
- AC97_REC_VIDEO,
- AC97_REC_AUX,
- AC97_REC_LINE,
- AC97_REC_STEREO, /* combination of all enabled outputs.. */
- AC97_REC_MONO, /*.. or the mono equivalent */
- AC97_REC_PHONE
-};
-
-static unsigned int ac97_oss_mask[] = {
- [AC97_REC_MIC] = SOUND_MASK_MIC,
- [AC97_REC_CD] = SOUND_MASK_CD,
- [AC97_REC_VIDEO] = SOUND_MASK_VIDEO,
- [AC97_REC_AUX] = SOUND_MASK_LINE1,
- [AC97_REC_LINE] = SOUND_MASK_LINE,
- [AC97_REC_PHONE] = SOUND_MASK_PHONEIN
-};
-
-/* indexed by bit position */
-static unsigned int ac97_oss_rm[] = {
- [SOUND_MIXER_MIC] = AC97_REC_MIC,
- [SOUND_MIXER_CD] = AC97_REC_CD,
- [SOUND_MIXER_VIDEO] = AC97_REC_VIDEO,
- [SOUND_MIXER_LINE1] = AC97_REC_AUX,
- [SOUND_MIXER_LINE] = AC97_REC_LINE,
- [SOUND_MIXER_PHONEIN] = AC97_REC_PHONE
-};
-
-/* read or write the recmask
- the ac97 can really have left and right recording
- inputs independently set, but OSS doesn't seem to
- want us to express that to the user.
- the caller guarantees that we have a supported bit set,
- and they must be holding the card's spinlock */
-static int
-ac97_recmask_io(struct ess_card *card, int read, int mask)
-{
- unsigned int val = ac97_oss_mask[ maestro_ac97_get(card, 0x1a) & 0x7 ];
-
- if (read) return val;
-
- /* oss can have many inputs, maestro can't. try
- to pick the 'new' one */
-
- if (mask != val) mask &= ~val;
-
- val = ffs(mask) - 1;
- val = ac97_oss_rm[val];
- val |= val << 8; /* set both channels */
-
- M_printk("maestro: setting ac97 recmask to 0x%x\n",val);
-
- maestro_ac97_set(card,0x1a,val);
-
- return 0;
-};
-
-/*
- * The Maestro can be wired to a standard AC97 compliant codec
- * (see www.intel.com for the pdf's on this), or to a PT101 codec
- * which appears to be the ES1918 (data sheet on the esstech.com.tw site)
- *
- * The PT101 setup is untested.
- */
-
-static u16 __init maestro_ac97_init(struct ess_card *card)
-{
- u16 vend1, vend2, caps;
-
- card->mix.supported_mixers = AC97_SUPPORTED_MASK;
- card->mix.stereo_mixers = AC97_STEREO_MASK;
- card->mix.record_sources = AC97_RECORD_MASK;
-/* card->mix.read_mixer = ac97_read_mixer;*/
- card->mix.write_mixer = ac97_write_mixer;
- card->mix.recmask_io = ac97_recmask_io;
-
- vend1 = maestro_ac97_get(card, 0x7c);
- vend2 = maestro_ac97_get(card, 0x7e);
-
- caps = maestro_ac97_get(card, 0x00);
-
- printk(KERN_INFO "maestro: AC97 Codec detected: v: 0x%2x%2x caps: 0x%x pwr: 0x%x\n",
- vend1,vend2,caps,maestro_ac97_get(card,0x26) & 0xf);
-
- if (! (caps & 0x4) ) {
- /* no bass/treble nobs */
- card->mix.supported_mixers &= ~(SOUND_MASK_BASS|SOUND_MASK_TREBLE);
- }
-
- /* XXX endianness, dork head. */
- /* vendor specifc bits.. */
- switch ((long)(vend1 << 16) | vend2) {
- case 0x545200ff: /* TriTech */
- /* no idea what this does */
- maestro_ac97_set(card,0x2a,0x0001);
- maestro_ac97_set(card,0x2c,0x0000);
- maestro_ac97_set(card,0x2c,0xffff);
- break;
-#if 0 /* i thought the problems I was seeing were with
- the 1921, but apparently they were with the pci board
- it was on, so this code is commented out.
- lets see if this holds true. */
- case 0x83847609: /* ESS 1921 */
- /* writing to 0xe (mic) or 0x1a (recmask) seems
- to hang this codec */
- card->mix.supported_mixers &= ~(SOUND_MASK_MIC);
- card->mix.record_sources = 0;
- card->mix.recmask_io = NULL;
-#if 0 /* don't ask. I have yet to see what these actually do. */
- maestro_ac97_set(card,0x76,0xABBA); /* o/~ Take a chance on me o/~ */
- udelay(20);
- maestro_ac97_set(card,0x78,0x3002);
- udelay(20);
- maestro_ac97_set(card,0x78,0x3802);
- udelay(20);
-#endif
- break;
-#endif
- default: break;
- }
-
- maestro_ac97_set(card, 0x1E, 0x0404);
- /* null misc stuff */
- maestro_ac97_set(card, 0x20, 0x0000);
-
- return 0;
-}
-
-#if 0 /* there has been 1 person on the planet with a pt101 that we
- know of. If they care, they can put this back in :) */
-static u16 maestro_pt101_init(struct ess_card *card,int iobase)
-{
- printk(KERN_INFO "maestro: PT101 Codec detected, initializing but _not_ installing mixer device.\n");
- /* who knows.. */
- maestro_ac97_set(iobase, 0x2A, 0x0001);
- maestro_ac97_set(iobase, 0x2C, 0x0000);
- maestro_ac97_set(iobase, 0x2C, 0xFFFF);
- maestro_ac97_set(iobase, 0x10, 0x9F1F);
- maestro_ac97_set(iobase, 0x12, 0x0808);
- maestro_ac97_set(iobase, 0x14, 0x9F1F);
- maestro_ac97_set(iobase, 0x16, 0x9F1F);
- maestro_ac97_set(iobase, 0x18, 0x0404);
- maestro_ac97_set(iobase, 0x1A, 0x0000);
- maestro_ac97_set(iobase, 0x1C, 0x0000);
- maestro_ac97_set(iobase, 0x02, 0x0404);
- maestro_ac97_set(iobase, 0x04, 0x0808);
- maestro_ac97_set(iobase, 0x0C, 0x801F);
- maestro_ac97_set(iobase, 0x0E, 0x801F);
- return 0;
-}
-#endif
-
-/* this is very magic, and very slow.. */
-static void
-maestro_ac97_reset(int ioaddr, struct pci_dev *pcidev)
-{
- u16 save_68;
- u16 w;
- u32 vend;
-
- outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
- outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
- outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
-
- /* reset the first codec */
- outw(0x0000, ioaddr+0x36);
- save_68 = inw(ioaddr+0x68);
- pci_read_config_word(pcidev, 0x58, &w); /* something magical with gpio and bus arb. */
- pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &vend);
- if( w & 0x1)
- save_68 |= 0x10;
- outw(0xfffe, ioaddr + 0x64); /* tickly gpio 0.. */
- outw(0x0001, ioaddr + 0x68);
- outw(0x0000, ioaddr + 0x60);
- udelay(20);
- outw(0x0001, ioaddr + 0x60);
- mdelay(20);
-
- outw(save_68 | 0x1, ioaddr + 0x68); /* now restore .. */
- outw( (inw(ioaddr + 0x38) & 0xfffc)|0x1, ioaddr + 0x38);
- outw( (inw(ioaddr + 0x3a) & 0xfffc)|0x1, ioaddr + 0x3a);
- outw( (inw(ioaddr + 0x3c) & 0xfffc)|0x1, ioaddr + 0x3c);
-
- /* now the second codec */
- outw(0x0000, ioaddr+0x36);
- outw(0xfff7, ioaddr + 0x64);
- save_68 = inw(ioaddr+0x68);
- outw(0x0009, ioaddr + 0x68);
- outw(0x0001, ioaddr + 0x60);
- udelay(20);
- outw(0x0009, ioaddr + 0x60);
- mdelay(500); /* .. ouch.. */
- outw( inw(ioaddr + 0x38) & 0xfffc, ioaddr + 0x38);
- outw( inw(ioaddr + 0x3a) & 0xfffc, ioaddr + 0x3a);
- outw( inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c);
-
-#if 0 /* the loop here needs to be much better if we want it.. */
- M_printk("trying software reset\n");
- /* try and do a software reset */
- outb(0x80|0x7c, ioaddr + 0x30);
- for (w=0; ; w++) {
- if ((inw(ioaddr+ 0x30) & 1) == 0) {
- if(inb(ioaddr + 0x32) !=0) break;
-
- outb(0x80|0x7d, ioaddr + 0x30);
- if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
- outb(0x80|0x7f, ioaddr + 0x30);
- if (((inw(ioaddr+ 0x30) & 1) == 0) && (inb(ioaddr + 0x32) !=0)) break;
- }
-
- if( w > 10000) {
- outb( inb(ioaddr + 0x37) | 0x08, ioaddr + 0x37); /* do a software reset */
- mdelay(500); /* oh my.. */
- outb( inb(ioaddr + 0x37) & ~0x08, ioaddr + 0x37);
- udelay(1);
- outw( 0x80, ioaddr+0x30);
- for(w = 0 ; w < 10000; w++) {
- if((inw(ioaddr + 0x30) & 1) ==0) break;
- }
- }
- }
-#endif
- if ( vend == NEC_VERSA_SUBID1 || vend == NEC_VERSA_SUBID2) {
- /* turn on external amp? */
- outw(0xf9ff, ioaddr + 0x64);
- outw(inw(ioaddr+0x68) | 0x600, ioaddr + 0x68);
- outw(0x0209, ioaddr + 0x60);
- }
-
- /* Turn on the 978 docking chip.
- First frob the "master output enable" bit,
- then set most of the playback volume control registers to max. */
- outb(inb(ioaddr+0xc0)|(1<<5), ioaddr+0xc0);
- outb(0xff, ioaddr+0xc3);
- outb(0xff, ioaddr+0xc4);
- outb(0xff, ioaddr+0xc6);
- outb(0xff, ioaddr+0xc8);
- outb(0x3f, ioaddr+0xcf);
- outb(0x3f, ioaddr+0xd0);
-}
-/*
- * Indirect register access. Not all registers are readable so we
- * need to keep register state ourselves
- */
-
-#define WRITEABLE_MAP 0xEFFFFF
-#define READABLE_MAP 0x64003F
-
-/*
- * The Maestro engineers were a little indirection happy. These indirected
- * registers themselves include indirect registers at another layer
- */
-
-static void __maestro_write(struct ess_card *card, u16 reg, u16 data)
-{
- long ioaddr = card->iobase;
-
- outw(reg, ioaddr+0x02);
- outw(data, ioaddr+0x00);
- if( reg >= NR_IDRS) printk("maestro: IDR %d out of bounds!\n",reg);
- else card->maestro_map[reg]=data;
-
-}
-
-static void maestro_write(struct ess_state *s, u16 reg, u16 data)
-{
- unsigned long flags;
-
- check_suspend(s->card);
- spin_lock_irqsave(&s->card->lock,flags);
-
- __maestro_write(s->card,reg,data);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 __maestro_read(struct ess_card *card, u16 reg)
-{
- long ioaddr = card->iobase;
-
- outw(reg, ioaddr+0x02);
- return card->maestro_map[reg]=inw(ioaddr+0x00);
-}
-
-static u16 maestro_read(struct ess_state *s, u16 reg)
-{
- if(READABLE_MAP & (1<<reg))
- {
- unsigned long flags;
- check_suspend(s->card);
- spin_lock_irqsave(&s->card->lock,flags);
-
- __maestro_read(s->card,reg);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
- }
- return s->card->maestro_map[reg];
-}
-
-/*
- * These routines handle accessing the second level indirections to the
- * wave ram.
- */
-
-/*
- * The register names are the ones ESS uses (see 104T31.ZIP)
- */
-
-#define IDR0_DATA_PORT 0x00
-#define IDR1_CRAM_POINTER 0x01
-#define IDR2_CRAM_DATA 0x02
-#define IDR3_WAVE_DATA 0x03
-#define IDR4_WAVE_PTR_LOW 0x04
-#define IDR5_WAVE_PTR_HI 0x05
-#define IDR6_TIMER_CTRL 0x06
-#define IDR7_WAVE_ROMRAM 0x07
-
-static void apu_index_set(struct ess_card *card, u16 index)
-{
- int i;
- __maestro_write(card, IDR1_CRAM_POINTER, index);
- for(i=0;i<1000;i++)
- if(__maestro_read(card, IDR1_CRAM_POINTER)==index)
- return;
- printk(KERN_WARNING "maestro: APU register select failed.\n");
-}
-
-static void apu_data_set(struct ess_card *card, u16 data)
-{
- int i;
- for(i=0;i<1000;i++)
- {
- if(__maestro_read(card, IDR0_DATA_PORT)==data)
- return;
- __maestro_write(card, IDR0_DATA_PORT, data);
- }
-}
-
-/*
- * This is the public interface for APU manipulation. It handles the
- * interlock to avoid two APU writes in parallel etc. Don't diddle
- * directly with the stuff above.
- */
-
-static void apu_set_register(struct ess_state *s, u16 channel, u8 reg, u16 data)
-{
- unsigned long flags;
-
- check_suspend(s->card);
-
- if(channel&ESS_CHAN_HARD)
- channel&=~ESS_CHAN_HARD;
- else
- {
- if(channel>5)
- printk("BAD CHANNEL %d.\n",channel);
- else
- channel = s->apu[channel];
- /* store based on real hardware apu/reg */
- s->card->apu_map[channel][reg]=data;
- }
- reg|=(channel<<4);
-
- /* hooray for double indirection!! */
- spin_lock_irqsave(&s->card->lock,flags);
-
- apu_index_set(s->card, reg);
- apu_data_set(s->card, data);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 apu_get_register(struct ess_state *s, u16 channel, u8 reg)
-{
- unsigned long flags;
- u16 v;
-
- check_suspend(s->card);
-
- if(channel&ESS_CHAN_HARD)
- channel&=~ESS_CHAN_HARD;
- else
- channel = s->apu[channel];
-
- reg|=(channel<<4);
-
- spin_lock_irqsave(&s->card->lock,flags);
-
- apu_index_set(s->card, reg);
- v=__maestro_read(s->card, IDR0_DATA_PORT);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
- return v;
-}
-
-
-/*
- * The wavecache buffers between the APUs and
- * pci bus mastering
- */
-
-static void wave_set_register(struct ess_state *s, u16 reg, u16 value)
-{
- long ioaddr = s->card->iobase;
- unsigned long flags;
- check_suspend(s->card);
-
- spin_lock_irqsave(&s->card->lock,flags);
-
- outw(reg, ioaddr+0x10);
- outw(value, ioaddr+0x12);
-
- spin_unlock_irqrestore(&s->card->lock,flags);
-}
-
-static u16 wave_get_register(struct ess_state *s, u16 reg)
-{
- long ioaddr = s->card->iobase;
- unsigned long flags;
- u16 value;
- check_suspend(s->card);
-
- spin_lock_irqsave(&s->card->lock,flags);
- outw(reg, ioaddr+0x10);
- value=inw(ioaddr+0x12);
- spin_unlock_irqrestore(&s->card->lock,flags);
-
- return value;
-}
-
-static void sound_reset(int ioaddr)
-{
- outw(0x2000, 0x18+ioaddr);
- udelay(1);
- outw(0x0000, 0x18+ioaddr);
- udelay(1);
-}
-
-/* sets the play formats of these apus, should be passed the already shifted format */
-static void set_apu_fmt(struct ess_state *s, int apu, int mode)
-{
- int apu_fmt = 0x10;
-
- if(!(mode&ESS_FMT_16BIT)) apu_fmt+=0x20;
- if((mode&ESS_FMT_STEREO)) apu_fmt+=0x10;
- s->apu_mode[apu] = apu_fmt;
- s->apu_mode[apu+1] = apu_fmt;
-}
-
-/* this only fixes the output apu mode to be later set by start_dac and
- company. output apu modes are set in ess_rec_setup */
-static void set_fmt(struct ess_state *s, unsigned char mask, unsigned char data)
-{
- s->fmt = (s->fmt & mask) | data;
- set_apu_fmt(s, 0, (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK);
-}
-
-/* this is off by a little bit.. */
-static u32 compute_rate(struct ess_state *s, u32 freq)
-{
- u32 clock = clock_freq[s->card->card_type];
-
- freq = (freq * clocking)/48000;
-
- if (freq == 48000)
- return 0x10000;
-
- return ((freq / clock) <<16 )+
- (((freq % clock) << 16) / clock);
-}
-
-static void set_dac_rate(struct ess_state *s, unsigned int rate)
-{
- u32 freq;
- int fmt = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
-
- s->ratedac = rate;
-
- if(! (fmt & ESS_FMT_16BIT) && !(fmt & ESS_FMT_STEREO))
- rate >>= 1;
-
-/* M_printk("computing dac rate %d with mode %d\n",rate,s->fmt);*/
-
- freq = compute_rate(s, rate);
-
- /* Load the frequency, turn on 6dB */
- apu_set_register(s, 0, 2,(apu_get_register(s, 0, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 0, 3, freq>>8);
- apu_set_register(s, 1, 2,(apu_get_register(s, 1, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 1, 3, freq>>8);
-}
-
-static void set_adc_rate(struct ess_state *s, unsigned rate)
-{
- u32 freq;
-
- /* Sample Rate conversion APUs don't like 0x10000 for their rate */
- if (rate > 47999)
- rate = 47999;
- if (rate < 4000)
- rate = 4000;
-
- s->rateadc = rate;
-
- freq = compute_rate(s, rate);
-
- /* Load the frequency, turn on 6dB */
- apu_set_register(s, 2, 2,(apu_get_register(s, 2, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 2, 3, freq>>8);
- apu_set_register(s, 3, 2,(apu_get_register(s, 3, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 3, 3, freq>>8);
-
- /* fix mixer rate at 48khz. and its _must_ be 0x10000. */
- freq = 0x10000;
-
- apu_set_register(s, 4, 2,(apu_get_register(s, 4, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 4, 3, freq>>8);
- apu_set_register(s, 5, 2,(apu_get_register(s, 5, 2)&0x00FF)|
- ( ((freq&0xFF)<<8)|0x10 ));
- apu_set_register(s, 5, 3, freq>>8);
-}
-
-/* Stop our host of recording apus */
-static inline void stop_adc(struct ess_state *s)
-{
- /* XXX lets hope we don't have to lock around this */
- if (! (s->enable & ADC_RUNNING)) return;
-
- s->enable &= ~ADC_RUNNING;
- apu_set_register(s, 2, 0, apu_get_register(s, 2, 0)&0xFF0F);
- apu_set_register(s, 3, 0, apu_get_register(s, 3, 0)&0xFF0F);
- apu_set_register(s, 4, 0, apu_get_register(s, 2, 0)&0xFF0F);
- apu_set_register(s, 5, 0, apu_get_register(s, 3, 0)&0xFF0F);
-}
-
-/* stop output apus */
-static void stop_dac(struct ess_state *s)
-{
- /* XXX have to lock around this? */
- if (! (s->enable & DAC_RUNNING)) return;
-
- s->enable &= ~DAC_RUNNING;
- apu_set_register(s, 0, 0, apu_get_register(s, 0, 0)&0xFF0F);
- apu_set_register(s, 1, 0, apu_get_register(s, 1, 0)&0xFF0F);
-}
-
-static void start_dac(struct ess_state *s)
-{
- /* XXX locks? */
- if ( (s->dma_dac.mapped || s->dma_dac.count > 0) &&
- s->dma_dac.ready &&
- (! (s->enable & DAC_RUNNING)) ) {
-
- s->enable |= DAC_RUNNING;
-
- apu_set_register(s, 0, 0,
- (apu_get_register(s, 0, 0)&0xFF0F)|s->apu_mode[0]);
-
- if((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_STEREO)
- apu_set_register(s, 1, 0,
- (apu_get_register(s, 1, 0)&0xFF0F)|s->apu_mode[1]);
- }
-}
-
-static void start_adc(struct ess_state *s)
-{
- /* XXX locks? */
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready && (! (s->enable & ADC_RUNNING)) ) {
-
- s->enable |= ADC_RUNNING;
- apu_set_register(s, 2, 0,
- (apu_get_register(s, 2, 0)&0xFF0F)|s->apu_mode[2]);
- apu_set_register(s, 4, 0,
- (apu_get_register(s, 4, 0)&0xFF0F)|s->apu_mode[4]);
-
- if( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
- apu_set_register(s, 3, 0,
- (apu_get_register(s, 3, 0)&0xFF0F)|s->apu_mode[3]);
- apu_set_register(s, 5, 0,
- (apu_get_register(s, 5, 0)&0xFF0F)|s->apu_mode[5]);
- }
-
- }
-}
-
-
-/*
- * Native play back driver
- */
-
-/* the mode passed should be already shifted and masked */
-static void
-ess_play_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
-{
- u32 pa;
- u32 tmpval;
- int high_apu = 0;
- int channel;
-
- M_printk("mode=%d rate=%d buf=%p len=%d.\n",
- mode, rate, buffer, size);
-
- /* all maestro sizes are in 16bit words */
- size >>=1;
-
- if(mode&ESS_FMT_STEREO) {
- high_apu++;
- /* only 16/stereo gets size divided */
- if(mode&ESS_FMT_16BIT)
- size>>=1;
- }
-
- for(channel=0; channel <= high_apu; channel++)
- {
- pa = virt_to_bus(buffer);
-
- /* set the wavecache control reg */
- tmpval = (pa - 0x10) & 0xFFF8;
- if(!(mode & ESS_FMT_16BIT)) tmpval |= 4;
- if(mode & ESS_FMT_STEREO) tmpval |= 2;
- ess->apu_base[channel]=tmpval;
- wave_set_register(ess, ess->apu[channel]<<3, tmpval);
-
- pa -= virt_to_bus(ess->card->dmapages);
- pa>>=1; /* words */
-
- /* base offset of dma calcs when reading the pointer
- on the left one */
- if(!channel) ess->dma_dac.base = pa&0xFFFF;
-
- pa|=0x00400000; /* System RAM */
-
- /* XXX the 16bit here might not be needed.. */
- if((mode & ESS_FMT_STEREO) && (mode & ESS_FMT_16BIT)) {
- if(channel)
- pa|=0x00800000; /* Stereo */
- pa>>=1;
- }
-
-/* XXX think about endianess when writing these registers */
- M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
- /* start of sample */
- apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
- apu_set_register(ess, channel, 5, pa&0xFFFF);
- /* sample end */
- apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
- /* setting loop len == sample len */
- apu_set_register(ess, channel, 7, size);
-
- /* clear effects/env.. */
- apu_set_register(ess, channel, 8, 0x0000);
- /* set amp now to 0xd0 (?), low byte is 'amplitude dest'? */
- apu_set_register(ess, channel, 9, 0xD000);
-
- /* clear routing stuff */
- apu_set_register(ess, channel, 11, 0x0000);
- /* dma on, no envelopes, filter to all 1s) */
- apu_set_register(ess, channel, 0, 0x400F);
-
- if(mode&ESS_FMT_16BIT)
- ess->apu_mode[channel]=0x10;
- else
- ess->apu_mode[channel]=0x30;
-
- if(mode&ESS_FMT_STEREO) {
- /* set panning: left or right */
- apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10));
- ess->apu_mode[channel] += 0x10;
- } else
- apu_set_register(ess, channel, 10, 0x8F08);
- }
-
- /* clear WP interrupts */
- outw(1, ess->card->iobase+0x04);
- /* enable WP ints */
- outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
-
- /* go team! */
- set_dac_rate(ess,rate);
- start_dac(ess);
-}
-
-/*
- * Native record driver
- */
-
-/* again, passed mode is alrady shifted/masked */
-static void
-ess_rec_setup(struct ess_state *ess, int mode, u32 rate, void *buffer, int size)
-{
- int apu_step = 2;
- int channel;
-
- M_printk("maestro: ess_rec_setup: mode=%d rate=%d buf=0x%p len=%d.\n",
- mode, rate, buffer, size);
-
- /* all maestro sizes are in 16bit words */
- size >>=1;
-
- /* we're given the full size of the buffer, but
- in stereo each channel will only use its half */
- if(mode&ESS_FMT_STEREO) {
- size >>=1;
- apu_step = 1;
- }
-
- /* APU assignments: 2 = mono/left SRC
- 3 = right SRC
- 4 = mono/left Input Mixer
- 5 = right Input Mixer */
- for(channel=2;channel<6;channel+=apu_step)
- {
- int i;
- int bsize, route;
- u32 pa;
- u32 tmpval;
-
- /* data seems to flow from the codec, through an apu into
- the 'mixbuf' bit of page, then through the SRC apu
- and out to the real 'buffer'. ok. sure. */
-
- if(channel & 0x04) {
- /* ok, we're an input mixer going from adc
- through the mixbuf to the other apus */
-
- if(!(channel & 0x01)) {
- pa = virt_to_bus(ess->mixbuf);
- } else {
- pa = virt_to_bus(ess->mixbuf + (PAGE_SIZE >> 4));
- }
-
- /* we source from a 'magic' apu */
- bsize = PAGE_SIZE >> 5; /* half of this channels alloc, in words */
- route = 0x14 + (channel - 4); /* parallel in crap, see maestro reg 0xC [8-11] */
- ess->apu_mode[channel] = 0x90; /* Input Mixer */
-
- } else {
- /* we're a rate converter taking
- input from the input apus and outputing it to
- system memory */
- if(!(channel & 0x01)) {
- pa = virt_to_bus(buffer);
- } else {
- /* right channel records its split half.
- *2 accommodates for rampant shifting earlier */
- pa = virt_to_bus(buffer + size*2);
- }
-
- ess->apu_mode[channel] = 0xB0; /* Sample Rate Converter */
-
- bsize = size;
- /* get input from inputing apu */
- route = channel + 2;
- }
-
- M_printk("maestro: ess_rec_setup: getting pa 0x%x from %d\n",pa,channel);
-
- /* set the wavecache control reg */
- tmpval = (pa - 0x10) & 0xFFF8;
- ess->apu_base[channel]=tmpval;
- wave_set_register(ess, ess->apu[channel]<<3, tmpval);
-
- pa -= virt_to_bus(ess->card->dmapages);
- pa>>=1; /* words */
-
- /* base offset of dma calcs when reading the pointer
- on this left one */
- if(channel==2) ess->dma_adc.base = pa&0xFFFF;
-
- pa|=0x00400000; /* bit 22 -> System RAM */
-
- M_printk("maestro: ess_rec_setup: APU[%d] pa = 0x%x size = 0x%x route = 0x%x\n",
- ess->apu[channel], pa, bsize, route);
-
- /* Begin loading the APU */
- for(i=0;i<15;i++) /* clear all PBRs */
- apu_set_register(ess, channel, i, 0x0000);
-
- apu_set_register(ess, channel, 0, 0x400F);
-
- /* need to enable subgroups.. and we should probably
- have different groups for different /dev/dsps.. */
- apu_set_register(ess, channel, 2, 0x8);
-
- /* Load the buffer into the wave engine */
- apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
- /* XXX reg is little endian.. */
- apu_set_register(ess, channel, 5, pa&0xFFFF);
- apu_set_register(ess, channel, 6, (pa+bsize)&0xFFFF);
- apu_set_register(ess, channel, 7, bsize);
-
- /* clear effects/env.. */
- apu_set_register(ess, channel, 8, 0x00F0);
-
- /* amplitude now? sure. why not. */
- apu_set_register(ess, channel, 9, 0x0000);
-
- /* set filter tune, radius, polar pan */
- apu_set_register(ess, channel, 10, 0x8F08);
-
- /* route input */
- apu_set_register(ess, channel, 11, route);
- }
-
- /* clear WP interrupts */
- outw(1, ess->card->iobase+0x04);
- /* enable WP ints */
- outw(inw(ess->card->iobase+0x18)|4, ess->card->iobase+0x18);
-
- /* let 'er rip */
- set_adc_rate(ess,rate);
- start_adc(ess);
-}
-/* --------------------------------------------------------------------- */
-
-static void set_dmaa(struct ess_state *s, unsigned int addr, unsigned int count)
-{
- M_printk("set_dmaa??\n");
-}
-
-static void set_dmac(struct ess_state *s, unsigned int addr, unsigned int count)
-{
- M_printk("set_dmac??\n");
-}
-
-/* Playback pointer */
-static inline unsigned get_dmaa(struct ess_state *s)
-{
- int offset;
-
- offset = apu_get_register(s,0,5);
-
-/* M_printk("dmaa: offset: %d, base: %d\n",offset,s->dma_dac.base); */
-
- offset-=s->dma_dac.base;
-
- return (offset&0xFFFE)<<1; /* hardware is in words */
-}
-
-/* Record pointer */
-static inline unsigned get_dmac(struct ess_state *s)
-{
- int offset;
-
- offset = apu_get_register(s,2,5);
-
-/* M_printk("dmac: offset: %d, base: %d\n",offset,s->dma_adc.base); */
-
- /* The offset is an address not a position relative to base */
- offset-=s->dma_adc.base;
-
- return (offset&0xFFFE)<<1; /* hardware is in words */
-}
-
-/*
- * Meet Bob, the timer...
- */
-
-static irqreturn_t ess_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-static void stop_bob(struct ess_state *s)
-{
- /* Mask IDR 11,17 */
- maestro_write(s, 0x11, maestro_read(s, 0x11)&~1);
- maestro_write(s, 0x17, maestro_read(s, 0x17)&~1);
-}
-
-/* eventually we could be clever and limit bob ints
- to the frequency at which our smallest duration
- chunks may expire */
-#define ESS_SYSCLK 50000000
-static void start_bob(struct ess_state *s)
-{
- int prescale;
- int divide;
-
- /* XXX make freq selector much smarter, see calc_bob_rate */
- int freq = 200;
-
- /* compute ideal interrupt frequency for buffer size & play rate */
- /* first, find best prescaler value to match freq */
- for(prescale=5;prescale<12;prescale++)
- if(freq > (ESS_SYSCLK>>(prescale+9)))
- break;
-
- /* next, back off prescaler whilst getting divider into optimum range */
- divide=1;
- while((prescale > 5) && (divide<32))
- {
- prescale--;
- divide <<=1;
- }
- divide>>=1;
-
- /* now fine-tune the divider for best match */
- for(;divide<31;divide++)
- if(freq >= ((ESS_SYSCLK>>(prescale+9))/(divide+1)))
- break;
-
- /* divide = 0 is illegal, but don't let prescale = 4! */
- if(divide == 0)
- {
- divide++;
- if(prescale>5)
- prescale--;
- }
-
- maestro_write(s, 6, 0x9000 | (prescale<<5) | divide); /* set reg */
-
- /* Now set IDR 11/17 */
- maestro_write(s, 0x11, maestro_read(s, 0x11)|1);
- maestro_write(s, 0x17, maestro_read(s, 0x17)|1);
-}
-/* --------------------------------------------------------------------- */
-
-/* this quickly calculates the frequency needed for bob
- and sets it if its different than what bob is
- currently running at. its called often so
- needs to be fairly quick. */
-#define BOB_MIN 50
-#define BOB_MAX 400
-static void calc_bob_rate(struct ess_state *s) {
-#if 0 /* this thing tries to set the frequency of bob such that
- there are 2 interrupts / buffer walked by the dac/adc. That
- is probably very wrong for people who actually care about
- mid buffer positioning. it should be calculated as bytes/interrupt
- and that needs to be decided :) so for now just use the static 150
- in start_bob.*/
-
- unsigned int dac_rate=2,adc_rate=1,newrate;
- static int israte=-1;
-
- if (s->dma_dac.fragsize == 0) dac_rate = BOB_MIN;
- else {
- dac_rate = (2 * s->ratedac * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
- (s->dma_dac.fragsize) ;
- }
-
- if (s->dma_adc.fragsize == 0) adc_rate = BOB_MIN;
- else {
- adc_rate = (2 * s->rateadc * sample_size[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK]) /
- (s->dma_adc.fragsize) ;
- }
-
- if(dac_rate > adc_rate) newrate = adc_rate;
- else newrate=dac_rate;
-
- if(newrate > BOB_MAX) newrate = BOB_MAX;
- else {
- if(newrate < BOB_MIN)
- newrate = BOB_MIN;
- }
-
- if( israte != newrate) {
- printk("dac: %d adc: %d rate: %d\n",dac_rate,adc_rate,israte);
- israte=newrate;
- }
-#endif
-
-}
-
-static int
-prog_dmabuf(struct ess_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- unsigned bytepersec;
- unsigned bufs;
- unsigned char fmt;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- fmt = s->fmt;
- if (rec) {
- stop_adc(s);
- fmt >>= ESS_ADC_SHIFT;
- } else {
- stop_dac(s);
- fmt >>= ESS_DAC_SHIFT;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- fmt &= ESS_FMT_MASK;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
- /* this algorithm is a little nuts.. where did /1000 come from? */
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
-
- M_printk("maestro: setup oss: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
-
- memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
-
- spin_lock_irqsave(&s->lock, flags);
- if (rec)
- ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
- else
- ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
-
- spin_unlock_irqrestore(&s->lock, flags);
- db->ready = 1;
-
- return 0;
-}
-
-static __inline__ void
-clear_advance(struct ess_state *s)
-{
- unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
-
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- /* account for wrapping? */
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void
-ess_update_ptr(struct ess_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- /* oh boy should this all be re-written. everything in the current code paths think
- that the various counters/pointers are expressed in bytes to the user but we have
- two apus doing stereo stuff so we fix it up here.. it propagates to all the various
- counters from here. */
- if ( s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
- hwptr = (get_dmac(s)*2) % s->dma_adc.dmasize;
- } else {
- hwptr = get_dmac(s) % s->dma_adc.dmasize;
- }
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- if (!s->dma_adc.mapped) {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- /* FILL ME
- wrindir(s, SV_CIENABLE, s->enable); */
- stop_adc(s);
- /* brute force everyone back in sync, sigh */
- s->dma_adc.count = 0;
- s->dma_adc.swptr = 0;
- s->dma_adc.hwptr = 0;
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = get_dmaa(s) % s->dma_dac.dmasize;
- /* the apu only reports the length it has seen, not the
- length of the memory that has been used (the WP
- knows that) */
- if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
- hwptr<<=1;
-
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-/* M_printk("updating dac: hwptr: %d diff: %d\n",hwptr,diff);*/
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
- wake_up(&s->dma_dac.wait);
- }
- } else {
- s->dma_dac.count -= diff;
-/* M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
- if (s->dma_dac.count <= 0) {
- M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count,
- hwptr, s->dma_dac.swptr);
- /* FILL ME
- wrindir(s, SV_CIENABLE, s->enable); */
- /* XXX how on earth can calling this with the lock held work.. */
- stop_dac(s);
- /* brute force everyone back in sync, sigh */
- s->dma_dac.count = 0;
- s->dma_dac.swptr = hwptr;
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
- wake_up(&s->dma_dac.wait);
-/* printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr,
- hwptr);*/
- }
- }
- }
-}
-
-static irqreturn_t
-ess_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct ess_state *s;
- struct ess_card *c = (struct ess_card *)dev_id;
- int i;
- u32 event;
-
- if ( ! (event = inb(c->iobase+0x1A)) )
- return IRQ_NONE;
-
- outw(inw(c->iobase+4)&1, c->iobase+4);
-
-/* M_printk("maestro int: %x\n",event);*/
- if(event&(1<<6))
- {
- int x;
- enum {UP_EVT, DOWN_EVT, MUTE_EVT} vol_evt;
- int volume;
-
- /* Figure out which volume control button was pushed,
- based on differences from the default register
- values. */
- x = inb(c->iobase+0x1c);
- if (x&1) vol_evt = MUTE_EVT;
- else if (((x>>1)&7) > 4) vol_evt = UP_EVT;
- else vol_evt = DOWN_EVT;
-
- /* Reset the volume control registers. */
- outb(0x88, c->iobase+0x1c);
- outb(0x88, c->iobase+0x1d);
- outb(0x88, c->iobase+0x1e);
- outb(0x88, c->iobase+0x1f);
-
- /* Deal with the button press in a hammer-handed
- manner by adjusting the master mixer volume. */
- volume = c->mix.mixer_state[0] & 0xff;
- if (vol_evt == UP_EVT) {
- volume += 5;
- if (volume > 100)
- volume = 100;
- }
- else if (vol_evt == DOWN_EVT) {
- volume -= 5;
- if (volume < 0)
- volume = 0;
- } else {
- /* vol_evt == MUTE_EVT */
- if (volume == 0)
- volume = c->dock_mute_vol;
- else {
- c->dock_mute_vol = volume;
- volume = 0;
- }
- }
- set_mixer (c, 0, (volume << 8) | volume);
- }
-
- /* Ack all the interrupts. */
- outb(0xFF, c->iobase+0x1A);
-
- /*
- * Update the pointers for all APU's we are running.
- */
- for(i=0;i<NR_DSPS;i++)
- {
- s=&c->channels[i];
- if(s->dev_audio == -1)
- break;
- spin_lock(&s->lock);
- ess_update_ptr(s);
- spin_unlock(&s->lock);
- }
- return IRQ_HANDLED;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "maestro: invalid magic value in %s\n";
-
-#define VALIDATE_MAGIC(FOO,MAG) \
-({ \
- if (!(FOO) || (FOO)->magic != MAG) { \
- printk(invalid_magic,__FUNCTION__); \
- return -ENXIO; \
- } \
-})
-
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,ESS_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,ESS_CARD_MAGIC)
-
-static void set_mixer(struct ess_card *card,unsigned int mixer, unsigned int val )
-{
- unsigned int left,right;
- /* cleanse input a little */
- right = ((val >> 8) & 0xff) ;
- left = (val & 0xff) ;
-
- if(right > 100) right = 100;
- if(left > 100) left = 100;
-
- card->mix.mixer_state[mixer]=(right << 8) | left;
- card->mix.write_mixer(card,mixer,left,right);
-}
-
-static void
-mixer_push_state(struct ess_card *card)
-{
- int i;
- for(i = 0 ; i < SOUND_MIXER_NRDEVICES ; i++) {
- if( ! supported_mixer(card,i)) continue;
-
- set_mixer(card,i,card->mix.mixer_state[i]);
- }
-}
-
-static int mixer_ioctl(struct ess_card *card, unsigned int cmd, unsigned long arg)
-{
- int i, val=0;
- unsigned long flags;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_CARD(card);
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
- strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
- info.modify_counter = card->mix.modcnt;
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, card_names[card->card_type], sizeof(info.id));
- strlcpy(info.name, card_names[card->card_type], sizeof(info.name));
- if (copy_to_user(argp, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
-
- if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
-
- if (_IOC_DIR(cmd) == _IOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* give them the current record source */
-
- if(!card->mix.recmask_io) {
- val = 0;
- } else {
- spin_lock_irqsave(&card->lock, flags);
- val = card->mix.recmask_io(card,1,0);
- spin_unlock_irqrestore(&card->lock, flags);
- }
- break;
-
- case SOUND_MIXER_DEVMASK: /* give them the supported mixers */
- val = card->mix.supported_mixers;
- break;
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- val = card->mix.record_sources;
- break;
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- val = card->mix.stereo_mixers;
- break;
-
- case SOUND_MIXER_CAPS:
- val = SOUND_CAP_EXCL_INPUT;
- break;
-
- default: /* read a specific mixer */
- i = _IOC_NR(cmd);
-
- if ( ! supported_mixer(card,i))
- return -EINVAL;
-
- /* do we ever want to touch the hardware? */
-/* spin_lock_irqsave(&card->lock, flags);
- val = card->mix.read_mixer(card,i);
- spin_unlock_irqrestore(&card->lock, flags);*/
-
- val = card->mix.mixer_state[i];
-/* M_printk("returned 0x%x for mixer %d\n",val,i);*/
-
- break;
- }
- return put_user(val, p);
- }
-
- if (_IOC_DIR(cmd) != (_IOC_WRITE|_IOC_READ))
- return -EINVAL;
-
- card->mix.modcnt++;
-
- if (get_user(val, p))
- return -EFAULT;
-
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
-
- if (!card->mix.recmask_io) return -EINVAL;
- if(!val) return 0;
- if(! (val &= card->mix.record_sources)) return -EINVAL;
-
- spin_lock_irqsave(&card->lock, flags);
- card->mix.recmask_io(card,0,val);
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
-
- if ( ! supported_mixer(card,i))
- return -EINVAL;
-
- spin_lock_irqsave(&card->lock, flags);
- set_mixer(card,i,val);
- spin_unlock_irqrestore(&card->lock, flags);
-
- return 0;
- }
-}
-
-/* --------------------------------------------------------------------- */
-static int ess_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct ess_card *card = NULL;
- struct pci_dev *pdev = NULL;
- struct pci_driver *drvr;
-
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- drvr = pci_dev_driver (pdev);
- if (drvr == &maestro_pci_driver) {
- card = (struct ess_card*)pci_get_drvdata (pdev);
- if (!card)
- continue;
- if (card->dev_mixer == minor)
- break;
- }
- }
- if (!card)
- return -ENODEV;
- file->private_data = card;
- return nonseekable_open(inode, file);
-}
-
-static int ess_release_mixdev(struct inode *inode, struct file *file)
-{
- struct ess_card *card = (struct ess_card *)file->private_data;
-
- VALIDATE_CARD(card);
-
- return 0;
-}
-
-static int ess_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct ess_card *card = (struct ess_card *)file->private_data;
-
- VALIDATE_CARD(card);
-
- return mixer_ioctl(card, cmd, arg);
-}
-
-static /*const*/ struct file_operations ess_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = ess_ioctl_mixdev,
- .open = ess_open_mixdev,
- .release = ess_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct ess_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait,current);
- unsigned long flags;
- int count;
- signed long tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- current->state = TASK_INTERRUPTIBLE;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- /* XXX uhm.. questionable locking*/
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- return -EBUSY;
- }
- tmo = (count * HZ) / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
- or something. who cares. - zach */
- if (!schedule_timeout(tmo ? tmo : 1) && tmo)
- M_printk(KERN_DEBUG "maestro: dma timed out?? %ld\n",jiffies);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- current->state = TASK_RUNNING;
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-/* Zach sez: "god this is gross.." */
-static int
-comb_stereo(unsigned char *real_buffer,unsigned char *tmp_buffer, int offset,
- int count, int bufsize)
-{
- /* No such thing as stereo recording, so we
- use dual input mixers. which means we have to
- combine mono to stereo buffer. yuck.
-
- but we don't have to be able to work a byte at a time..*/
-
- unsigned char *so,*left,*right;
- int i;
-
- so = tmp_buffer;
- left = real_buffer + offset;
- right = real_buffer + bufsize/2 + offset;
-
-/* M_printk("comb_stereo writing %d to %p from %p and %p, offset: %d size: %d\n",count/2, tmp_buffer,left,right,offset,bufsize);*/
-
- for(i=count/4; i ; i--) {
- (*(so+2)) = *(right++);
- (*(so+3)) = *(right++);
- (*so) = *(left++);
- (*(so+1)) = *(left++);
- so+=4;
- }
-
- return 0;
-}
-
-/* in this loop, dma_adc.count signifies the amount of data thats waiting
- to be copied to the user's buffer. it is filled by the interrupt
- handler and drained by this loop. */
-static ssize_t
-ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
- unsigned char *combbuf = NULL;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- if(!(combbuf = kmalloc(count,GFP_KERNEL)))
- return -ENOMEM;
- ret = 0;
-
- calc_bob_rate(s);
-
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- /* remember, all these things are expressed in bytes to be
- sent to the user.. hence the evil / 2 down below */
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (cnt > count)
- cnt = count;
-
- if ( cnt > 0 ) cnt &= ~3;
-
- if (cnt <= 0) {
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- {
- ret = ret ? ret : -EAGAIN;
- goto rec_return_free;
- }
- if (!interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ)) {
- if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- /* program enhanced mode registers */
- /* FILL ME */
-/* wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1); */
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current))
- {
- ret = ret ? ret : -ERESTARTSYS;
- goto rec_return_free;
- }
- continue;
- }
-
- if(s->fmt & (ESS_FMT_STEREO << ESS_ADC_SHIFT)) {
- /* swptr/2 so that we know the real offset in each apu's buffer */
- comb_stereo(s->dma_adc.rawbuf,combbuf,swptr/2,cnt,s->dma_adc.dmasize);
- if (copy_to_user(buffer, combbuf, cnt)) {
- ret = ret ? ret : -EFAULT;
- goto rec_return_free;
- }
- } else {
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- ret = ret ? ret : -EFAULT;
- goto rec_return_free;
- }
- }
-
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_adc(s);
- }
-
-rec_return_free:
- kfree(combbuf);
- return ret;
-}
-
-static ssize_t
-ess_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- calc_bob_rate(s);
-
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
-
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
-
- cnt = s->dma_dac.dmasize-swptr;
-
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if(!ret) ret = -EAGAIN;
- goto return_free;
- }
- if (!interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ)) {
- if(! s->card->in_suspend) printk(KERN_DEBUG "maestro: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- stop_dac(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- /* program enhanced mode registers */
-/* wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1); */
- /* FILL ME */
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- goto return_free;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
- goto return_free;
- }
-/* printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/
-
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
-
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(s);
- }
-return_free:
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int ess_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
-
-/* In 0.14 prog_dmabuf always returns success anyway ... */
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf(s, 0))
- return 0;
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf(s, 1))
- return 0;
- }
-
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &s->dma_dac.wait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &s->dma_adc.wait, wait);
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int ess_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- goto out;
- db = &s->dma_dac;
- } else
-#if 0
- /* if we can have the wp/wc do the combining
- we can turn this back on. */
- if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
-#endif
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int ess_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
-/* printk("maestro: ess_ioctl: cmd %d\n", cmd);*/
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, file->f_flags & O_NONBLOCK);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- /* XXX fix */
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->card->pcidev->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->card->pcidev->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- set_adc_rate(s, val);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- set_dac_rate(s, val);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_U8|AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- /* fixed at 16bit for now */
- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
-#if 0
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
-#endif
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
- AFMT_S16_LE :
- AFMT_U8,
- p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
- val |= PCM_ENABLE_INPUT;
- if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING))
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- start_adc(s);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- start_dac(s);
- } else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- spin_lock_irqsave(&s->lock, flags);
- ess_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- M_printk("maestro: SETFRAGMENT: %0x\n",val);
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return -EINVAL;
-}
-
-static void
-set_base_registers(struct ess_state *s,void *vaddr)
-{
- unsigned long packed_phys = virt_to_bus(vaddr)>>12;
- wave_set_register(s, 0x01FC , packed_phys);
- wave_set_register(s, 0x01FD , packed_phys);
- wave_set_register(s, 0x01FE , packed_phys);
- wave_set_register(s, 0x01FF , packed_phys);
-}
-
-/*
- * this guy makes sure we're in the right power
- * state for what we want to be doing
- */
-static void maestro_power(struct ess_card *card, int tostate)
-{
- u16 active_mask = acpi_state_mask[tostate];
- u8 state;
-
- if(!use_pm) return;
-
- pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state);
- state&=3;
-
- /* make sure we're in the right state */
- if(state != tostate) {
- M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n",
- card->pcidev->bus->number,
- PCI_SLOT(card->pcidev->devfn),
- PCI_FUNC(card->pcidev->devfn),
- state,tostate);
- pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate);
- }
-
- /* and make sure the units we care about are on
- XXX we might want to do this before state flipping? */
- pci_write_config_word(card->pcidev, 0x54, ~ active_mask);
- pci_write_config_word(card->pcidev, 0x56, ~ active_mask);
-}
-
-/* we allocate a large power of two for all our memory.
- this is cut up into (not to scale :):
- |silly fifo word | 512byte mixbuf per adc | dac/adc * channels |
-*/
-static int
-allocate_buffers(struct ess_state *s)
-{
- void *rawbuf=NULL;
- int order,i;
- struct page *page, *pend;
-
- /* alloc as big a chunk as we can */
- for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
- if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
- break;
-
- if (!rawbuf)
- return 1;
-
- M_printk("maestro: allocated %ld (%d) bytes at %p\n",PAGE_SIZE<<order,order, rawbuf);
-
- if ((virt_to_bus(rawbuf) + (PAGE_SIZE << order) - 1) & ~((1<<28)-1)) {
- printk(KERN_ERR "maestro: DMA buffer beyond 256MB! busaddr 0x%lx size %ld\n",
- virt_to_bus(rawbuf), PAGE_SIZE << order);
- kfree(rawbuf);
- return 1;
- }
-
- s->card->dmapages = rawbuf;
- s->card->dmaorder = order;
-
- for(i=0;i<NR_DSPS;i++) {
- struct ess_state *ess = &s->card->channels[i];
-
- if(ess->dev_audio == -1)
- continue;
-
- ess->dma_dac.ready = s->dma_dac.mapped = 0;
- ess->dma_adc.ready = s->dma_adc.mapped = 0;
- ess->dma_adc.buforder = ess->dma_dac.buforder = order - 1 - dsps_order - 1;
-
- /* offset dac and adc buffers starting half way through and then at each [da][ad]c's
- order's intervals.. */
- ess->dma_dac.rawbuf = rawbuf + (PAGE_SIZE<<(order-1)) + (i * ( PAGE_SIZE << (ess->dma_dac.buforder + 1 )));
- ess->dma_adc.rawbuf = ess->dma_dac.rawbuf + ( PAGE_SIZE << ess->dma_dac.buforder);
- /* offset mixbuf by a mixbuf so that the lame status fifo can
- happily scribble away.. */
- ess->mixbuf = rawbuf + (512 * (i+1));
-
- M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf,
- ess->dma_adc.rawbuf, ess->mixbuf);
-
- }
-
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(rawbuf); page <= pend; page++)
- SetPageReserved(page);
-
- return 0;
-}
-static void
-free_buffers(struct ess_state *s)
-{
- struct page *page, *pend;
-
- s->dma_dac.rawbuf = s->dma_adc.rawbuf = NULL;
- s->dma_dac.mapped = s->dma_adc.mapped = 0;
- s->dma_dac.ready = s->dma_adc.ready = 0;
-
- M_printk("maestro: freeing %p\n",s->card->dmapages);
- /* undo marking the pages as reserved */
-
- pend = virt_to_page(s->card->dmapages + (PAGE_SIZE << s->card->dmaorder) - 1);
- for (page = virt_to_page(s->card->dmapages); page <= pend; page++)
- ClearPageReserved(page);
-
- free_pages((unsigned long)s->card->dmapages,s->card->dmaorder);
- s->card->dmapages = NULL;
-}
-
-static int
-ess_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct ess_state *s = NULL;
- unsigned char fmtm = ~0, fmts = 0;
- struct pci_dev *pdev = NULL;
- /*
- * Scan the cards and find the channel. We only
- * do this at open time so it is ok
- */
-
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- struct ess_card *c;
- struct pci_driver *drvr;
-
- drvr = pci_dev_driver (pdev);
- if (drvr == &maestro_pci_driver) {
- int i;
- struct ess_state *sp;
-
- c = (struct ess_card*)pci_get_drvdata (pdev);
- if (!c)
- continue;
- for(i=0;i<NR_DSPS;i++)
- {
- sp=&c->channels[i];
- if(sp->dev_audio < 0)
- continue;
- if((sp->dev_audio ^ minor) & ~0xf)
- continue;
- s=sp;
- }
- }
- }
- if (!s)
- return -ENODEV;
-
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EWOULDBLOCK;
- }
- mutex_unlock(&s->open_mutex);
- interruptible_sleep_on(&s->open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
-
- /* under semaphore.. */
- if ((s->card->dmapages==NULL) && allocate_buffers(s)) {
- mutex_unlock(&s->open_mutex);
- return -ENOMEM;
- }
-
- /* we're covered by the open_mutex */
- if( ! s->card->dsps_open ) {
- maestro_power(s->card,ACPI_D0);
- start_bob(s);
- }
- s->card->dsps_open++;
- M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
-
- /* ok, lets write WC base regs now that we've
- powered up the chip */
- M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages),
- ((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12);
- set_base_registers(s,s->card->dmapages);
-
- if (file->f_mode & FMODE_READ) {
-/*
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT; */
-
- fmtm &= ~((ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT);
- fmts = (ESS_FMT_STEREO|ESS_FMT_16BIT) << ESS_ADC_SHIFT;
-
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- set_adc_rate(s, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- set_dac_rate(s, 8000);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int
-ess_release(struct inode *inode, struct file *file)
-{
- struct ess_state *s = (struct ess_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- }
-
- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
- /* we're covered by the open_mutex */
- M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
- if( --s->card->dsps_open <= 0) {
- s->card->dsps_open = 0;
- stop_bob(s);
- free_buffers(s);
- maestro_power(s->card,ACPI_D2);
- }
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
- unlock_kernel();
- return 0;
-}
-
-static struct file_operations ess_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ess_read,
- .write = ess_write,
- .poll = ess_poll,
- .ioctl = ess_ioctl,
- .mmap = ess_mmap,
- .open = ess_open,
- .release = ess_release,
-};
-
-static int
-maestro_config(struct ess_card *card)
-{
- struct pci_dev *pcidev = card->pcidev;
- struct ess_state *ess = &card->channels[0];
- int apu,iobase = card->iobase;
- u16 w;
- u32 n;
-
- /* We used to muck around with pci config space that
- * we had no business messing with. We don't know enough
- * about the machine to know which DMA mode is appropriate,
- * etc. We were guessing wrong on some machines and making
- * them unhappy. We now trust in the BIOS to do things right,
- * which almost certainly means a new host of problems will
- * arise with broken BIOS implementations. screw 'em.
- * We're already intolerant of machines that don't assign
- * IRQs.
- */
-
- /* do config work at full power */
- maestro_power(card,ACPI_D0);
-
- pci_read_config_word(pcidev, 0x50, &w);
-
- w&=~(1<<5); /* Don't swap left/right (undoc)*/
-
- pci_write_config_word(pcidev, 0x50, w);
-
- pci_read_config_word(pcidev, 0x52, &w);
- w&=~(1<<15); /* Turn off internal clock multiplier */
- /* XXX how do we know which to use? */
- w&=~(1<<14); /* External clock */
-
- w|= (1<<7); /* Hardware volume control on */
- w|= (1<<6); /* Debounce off: easier to push the HWV buttons. */
- w&=~(1<<5); /* GPIO 4:5 */
- w|= (1<<4); /* Disconnect from the CHI. Enabling this made a dell 7500 work. */
- w&=~(1<<2); /* MIDI fix off (undoc) */
- w&=~(1<<1); /* reserved, always write 0 */
- pci_write_config_word(pcidev, 0x52, w);
-
- /*
- * Legacy mode
- */
-
- pci_read_config_word(pcidev, 0x40, &w);
- w|=(1<<15); /* legacy decode off */
- w&=~(1<<14); /* Disable SIRQ */
- w&=~(0x1f); /* disable mpu irq/io, game port, fm, SB */
-
- pci_write_config_word(pcidev, 0x40, w);
-
- /* Set up 978 docking control chip. */
- pci_read_config_word(pcidev, 0x58, &w);
- w|=1<<2; /* Enable 978. */
- w|=1<<3; /* Turn on 978 hardware volume control. */
- w&=~(1<<11); /* Turn on 978 mixer volume control. */
- pci_write_config_word(pcidev, 0x58, w);
-
- sound_reset(iobase);
-
- /*
- * Ring Bus Setup
- */
-
- /* setup usual 0x34 stuff.. 0x36 may be chip specific */
- outw(0xC090, iobase+0x34); /* direct sound, stereo */
- udelay(20);
- outw(0x3000, iobase+0x36); /* direct sound, stereo */
- udelay(20);
-
-
- /*
- * Reset the CODEC
- */
-
- maestro_ac97_reset(iobase,pcidev);
-
- /*
- * Ring Bus Setup
- */
-
- n=inl(iobase+0x34);
- n&=~0xF000;
- n|=12<<12; /* Direct Sound, Stereo */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x0F00; /* Modem off */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x00F0;
- n|=9<<4; /* DAC, Stereo */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x000F; /* ASSP off */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n|=(1<<29); /* Enable ring bus */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n|=(1<<28); /* Enable serial bus */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x00F00000; /* MIC off */
- outl(n, iobase+0x34);
-
- n=inl(iobase+0x34);
- n&=~0x000F0000; /* I2S off */
- outl(n, iobase+0x34);
-
-
- w=inw(iobase+0x18);
- w&=~(1<<7); /* ClkRun off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<6); /* Hardware volume control interrupt off... for now. */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<4); /* ASSP irq off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<3); /* ISDN irq off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w|=(1<<2); /* Direct Sound IRQ on */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w&=~(1<<1); /* MPU401 IRQ off */
- outw(w, iobase+0x18);
-
- w=inw(iobase+0x18);
- w|=(1<<0); /* SB IRQ on */
- outw(w, iobase+0x18);
-
- /* Set hardware volume control registers to midpoints.
- We can tell which button was pushed based on how they change. */
- outb(0x88, iobase+0x1c);
- outb(0x88, iobase+0x1d);
- outb(0x88, iobase+0x1e);
- outb(0x88, iobase+0x1f);
-
- /* it appears some maestros (dell 7500) only work if these are set,
- regardless of whether we use the assp or not. */
-
- outb(0, iobase+0xA4);
- outb(3, iobase+0xA2);
- outb(0, iobase+0xA6);
-
- for(apu=0;apu<16;apu++)
- {
- /* Write 0 into the buffer area 0x1E0->1EF */
- outw(0x01E0+apu, 0x10+iobase);
- outw(0x0000, 0x12+iobase);
-
- /*
- * The 1.10 test program seem to write 0 into the buffer area
- * 0x1D0-0x1DF too.
- */
- outw(0x01D0+apu, 0x10+iobase);
- outw(0x0000, 0x12+iobase);
- }
-
-#if 1
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- (wave_get_register(ess, IDR7_WAVE_ROMRAM)&0xFF00));
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- wave_get_register(ess, IDR7_WAVE_ROMRAM)|0x100);
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- wave_get_register(ess, IDR7_WAVE_ROMRAM)&~0x200);
- wave_set_register(ess, IDR7_WAVE_ROMRAM,
- wave_get_register(ess, IDR7_WAVE_ROMRAM)|~0x400);
-#else
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- (maestro_read(ess, IDR7_WAVE_ROMRAM)&0xFF00));
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- maestro_read(ess, IDR7_WAVE_ROMRAM)|0x100);
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- maestro_read(ess, IDR7_WAVE_ROMRAM)&~0x200);
- maestro_write(ess, IDR7_WAVE_ROMRAM,
- maestro_read(ess, IDR7_WAVE_ROMRAM)|0x400);
-#endif
-
- maestro_write(ess, IDR2_CRAM_DATA, 0x0000);
- maestro_write(ess, 0x08, 0xB004);
- /* Now back to the DirectSound stuff */
- maestro_write(ess, 0x09, 0x001B);
- maestro_write(ess, 0x0A, 0x8000);
- maestro_write(ess, 0x0B, 0x3F37);
- maestro_write(ess, 0x0C, 0x0098);
-
- /* parallel out ?? */
- maestro_write(ess, 0x0C,
- (maestro_read(ess, 0x0C)&~0xF000)|0x8000);
- /* parallel in, has something to do with recording :) */
- maestro_write(ess, 0x0C,
- (maestro_read(ess, 0x0C)&~0x0F00)|0x0500);
-
- maestro_write(ess, 0x0D, 0x7632);
-
- /* Wave cache control on - test off, sg off,
- enable, enable extra chans 1Mb */
-
- outw(inw(0x14+iobase)|(1<<8),0x14+iobase);
- outw(inw(0x14+iobase)&0xFE03,0x14+iobase);
- outw((inw(0x14+iobase)&0xFFFC), 0x14+iobase);
- outw(inw(0x14+iobase)|(1<<7),0x14+iobase);
-
- outw(0xA1A0, 0x14+iobase); /* 0300 ? */
-
- /* Now clear the APU control ram */
- for(apu=0;apu<NR_APUS;apu++)
- {
- for(w=0;w<NR_APU_REGS;w++)
- apu_set_register(ess, apu|ESS_CHAN_HARD, w, 0);
-
- }
-
- return 0;
-
-}
-
-/* this guy tries to find the pci power management
- * register bank. this should really be in core
- * code somewhere. 1 on success. */
-static int
-parse_power(struct ess_card *card, struct pci_dev *pcidev)
-{
- u32 n;
- u16 w;
- u8 next;
- int max = 64; /* an a 8bit guy pointing to 32bit guys
- can only express so much. */
-
- card->power_regs = 0;
-
- /* check to see if we have a capabilities list in
- the config register */
- pci_read_config_word(pcidev, PCI_STATUS, &w);
- if(!(w & PCI_STATUS_CAP_LIST)) return 0;
-
- /* walk the list, starting at the head. */
- pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next);
-
- while(next && max--) {
- pci_read_config_dword(pcidev, next & ~3, &n);
- if((n & 0xff) == PCI_CAP_ID_PM) {
- card->power_regs = next;
- break;
- }
- next = ((n>>8) & 0xff);
- }
-
- return card->power_regs ? 1 : 0;
-}
-
-static int __init
-maestro_probe(struct pci_dev *pcidev,const struct pci_device_id *pdid)
-{
- int card_type = pdid->driver_data;
- u32 n;
- int iobase;
- int i, ret;
- struct ess_card *card;
- struct ess_state *ess;
- int num = 0;
-
-/* when built into the kernel, we only print version if device is found */
-#ifndef MODULE
- static int printed_version;
- if (!printed_version++)
- printk(version);
-#endif
-
- /* don't pick up weird modem maestros */
- if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
- return -ENODEV;
-
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
-
- iobase = pci_resource_start(pcidev,0);
- if (!iobase || !(pci_resource_flags(pcidev, 0 ) & IORESOURCE_IO))
- return -ENODEV;
-
- if(pcidev->irq == 0)
- return -ENODEV;
-
- /* stake our claim on the iospace */
- if( request_region(iobase, 256, card_names[card_type]) == NULL )
- {
- printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
- return -EBUSY;
- }
-
- /* just to be sure */
- pci_set_master(pcidev);
-
- card = kmalloc(sizeof(struct ess_card), GFP_KERNEL);
- if(card == NULL)
- {
- printk(KERN_WARNING "maestro: out of memory\n");
- release_region(iobase, 256);
- return -ENOMEM;
- }
-
- memset(card, 0, sizeof(*card));
- card->pcidev = pcidev;
-
- card->iobase = iobase;
- card->card_type = card_type;
- card->irq = pcidev->irq;
- card->magic = ESS_CARD_MAGIC;
- spin_lock_init(&card->lock);
- init_waitqueue_head(&card->suspend_queue);
-
- card->dock_mute_vol = 50;
-
- /* init our groups of 6 apus */
- for(i=0;i<NR_DSPS;i++)
- {
- struct ess_state *s=&card->channels[i];
-
- s->index = i;
-
- s->card = card;
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- spin_lock_init(&s->lock);
- mutex_init(&s->open_mutex);
- s->magic = ESS_STATE_MAGIC;
-
- s->apu[0] = 6*i;
- s->apu[1] = (6*i)+1;
- s->apu[2] = (6*i)+2;
- s->apu[3] = (6*i)+3;
- s->apu[4] = (6*i)+4;
- s->apu[5] = (6*i)+5;
-
- if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
- printk("maestro: BOTCH!\n");
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&ess_audio_fops, -1)) < 0)
- break;
- }
-
- num = i;
-
- /* clear the rest if we ran out of slots to register */
- for(;i<NR_DSPS;i++)
- {
- struct ess_state *s=&card->channels[i];
- s->dev_audio = -1;
- }
-
- ess = &card->channels[0];
-
- /*
- * Ok card ready. Begin setup proper
- */
-
- printk(KERN_INFO "maestro: Configuring %s found at IO 0x%04X IRQ %d\n",
- card_names[card_type],iobase,card->irq);
- pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
- printk(KERN_INFO "maestro: subvendor id: 0x%08x\n",n);
-
- /* turn off power management unless:
- * - the user explicitly asks for it
- * or
- * - we're not a 2e, lesser chipps seem to have problems.
- * - we're not on our _very_ small whitelist. some implemenetations
- * really don't like the pm code, others require it.
- * feel free to expand this as required.
- */
-#define SUBSYSTEM_VENDOR(x) (x&0xffff)
- if( (use_pm != 1) &&
- ((card_type != TYPE_MAESTRO2E) || (SUBSYSTEM_VENDOR(n) != 0x1028)))
- use_pm = 0;
-
- if(!use_pm)
- printk(KERN_INFO "maestro: not attempting power management.\n");
- else {
- if(!parse_power(card,pcidev))
- printk(KERN_INFO "maestro: no PCI power management interface found.\n");
- else {
- pci_read_config_dword(pcidev, card->power_regs, &n);
- printk(KERN_INFO "maestro: PCI power management capability: 0x%x\n",n>>16);
- }
- }
-
- maestro_config(card);
-
- if(maestro_ac97_get(card, 0x00)==0x0080) {
- printk(KERN_ERR "maestro: my goodness! you seem to have a pt101 codec, which is quite rare.\n"
- "\tyou should tell someone about this.\n");
- } else {
- maestro_ac97_init(card);
- }
-
- if ((card->dev_mixer = register_sound_mixer(&ess_mixer_fops, -1)) < 0) {
- printk("maestro: couldn't register mixer!\n");
- } else {
- memcpy(card->mix.mixer_state,mixer_defaults,sizeof(card->mix.mixer_state));
- mixer_push_state(card);
- }
-
- if((ret=request_irq(card->irq, ess_interrupt, IRQF_SHARED, card_names[card_type], card)))
- {
- printk(KERN_ERR "maestro: unable to allocate irq %d,\n", card->irq);
- unregister_sound_mixer(card->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
- struct ess_state *s = &card->channels[i];
- if(s->dev_audio != -1)
- unregister_sound_dsp(s->dev_audio);
- }
- release_region(card->iobase, 256);
- unregister_reboot_notifier(&maestro_nb);
- kfree(card);
- return ret;
- }
-
- /* Turn on hardware volume control interrupt.
- This has to come after we grab the IRQ above,
- or a crash will result on installation if a button has been pressed,
- because in that case we'll get an immediate interrupt. */
- n = inw(iobase+0x18);
- n|=(1<<6);
- outw(n, iobase+0x18);
-
- pci_set_drvdata(pcidev,card);
- /* now go to sleep 'till something interesting happens */
- maestro_power(card,ACPI_D2);
-
- printk(KERN_INFO "maestro: %d channels configured.\n", num);
- return 0;
-}
-
-static void maestro_remove(struct pci_dev *pcidev) {
- struct ess_card *card = pci_get_drvdata(pcidev);
- int i;
- u32 n;
-
- /* XXX maybe should force stop bob, but should be all
- stopped by _release by now */
-
- /* Turn off hardware volume control interrupt.
- This has to come before we leave the IRQ below,
- or a crash results if a button is pressed ! */
- n = inw(card->iobase+0x18);
- n&=~(1<<6);
- outw(n, card->iobase+0x18);
-
- free_irq(card->irq, card);
- unregister_sound_mixer(card->dev_mixer);
- for(i=0;i<NR_DSPS;i++)
- {
- struct ess_state *ess = &card->channels[i];
- if(ess->dev_audio != -1)
- unregister_sound_dsp(ess->dev_audio);
- }
- /* Goodbye, Mr. Bond. */
- maestro_power(card,ACPI_D3);
- release_region(card->iobase, 256);
- kfree(card);
- pci_set_drvdata(pcidev,NULL);
-}
-
-static struct pci_device_id maestro_pci_tbl[] = {
- {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1968, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2},
- {PCI_VENDOR_ESS, PCI_DEVICE_ID_ESS_ESS1978, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO2E},
- {PCI_VENDOR_ESS_OLD, PCI_DEVICE_ID_ESS_ESS0100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, TYPE_MAESTRO},
- {0,}
-};
-MODULE_DEVICE_TABLE(pci, maestro_pci_tbl);
-
-static struct pci_driver maestro_pci_driver = {
- .name = "maestro",
- .id_table = maestro_pci_tbl,
- .probe = maestro_probe,
- .remove = maestro_remove,
-};
-
-static int __init init_maestro(void)
-{
- int rc;
-
- rc = pci_register_driver(&maestro_pci_driver);
- if (rc < 0)
- return rc;
-
- if (register_reboot_notifier(&maestro_nb))
- printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
-#ifdef MODULE
- printk(version);
-#endif
- if (dsps_order < 0) {
- dsps_order = 1;
- printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
- }
- else if (dsps_order > MAX_DSP_ORDER) {
- dsps_order = MAX_DSP_ORDER;
- printk(KERN_WARNING "maestro: clipping dsps_order to %d\n",dsps_order);
- }
- return 0;
-}
-
-static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
-{
- /* this notifier is called when the kernel is really shut down. */
- M_printk("maestro: shutting down\n");
- /* this will remove all card instances too */
- pci_unregister_driver(&maestro_pci_driver);
- /* XXX dunno about power management */
- return NOTIFY_OK;
-}
-
-/* --------------------------------------------------------------------- */
-
-
-static void cleanup_maestro(void) {
- M_printk("maestro: unloading\n");
- pci_unregister_driver(&maestro_pci_driver);
- unregister_reboot_notifier(&maestro_nb);
-}
-
-/* --------------------------------------------------------------------- */
-
-void
-check_suspend(struct ess_card *card)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- if(!card->in_suspend) return;
-
- card->in_suspend++;
- add_wait_queue(&(card->suspend_queue), &wait);
- current->state = TASK_UNINTERRUPTIBLE;
- schedule();
- remove_wait_queue(&(card->suspend_queue), &wait);
- current->state = TASK_RUNNING;
-}
-
-module_init(init_maestro);
-module_exit(cleanup_maestro);
diff --git a/sound/oss/maestro.h b/sound/oss/maestro.h
deleted file mode 100644
index 023ec7f968f9..000000000000
--- a/sound/oss/maestro.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Registers for the ESS PCI cards
- */
-
-/*
- * Memory access
- */
-
-#define ESS_MEM_DATA 0x00
-#define ESS_MEM_INDEX 0x02
-
-/*
- * AC-97 Codec port. Delay 1uS after each write. This is used to
- * talk AC-97 (see intel.com). Write data then register.
- */
-
-#define ESS_AC97_INDEX 0x30 /* byte wide */
-#define ESS_AC97_DATA 0x32
-
-/*
- * Reading is a bit different. You write register|0x80 to ubdex
- * delay 1uS poll the low bit of index, when it clears read the
- * data value.
- */
-
-/*
- * Control port. Not yet fully understood
- * The value 0xC090 gets loaded to it then 0x0000 and 0x2800
- * to the data port. Then after 4uS the value 0x300 is written
- */
-
-#define RING_BUS_CTRL_L 0x34
-#define RING_BUS_CTRL_H 0x36
-
-/*
- * This is also used during setup. The value 0x17 is written to it
- */
-
-#define ESS_SETUP_18 0x18
-
-/*
- * And this one gets 0x000b
- */
-
-#define ESS_SETUP_A2 0xA2
-
-/*
- * And this 0x0000
- */
-
-#define ESS_SETUP_A4 0xA4
-#define ESS_SETUP_A6 0xA6
-
-/*
- * Stuff to do with Harpo - the wave stuff
- */
-
-#define ESS_WAVETABLE_SIZE 0x14
-#define ESS_WAVETABLE_2M 0xA180
-
diff --git a/sound/oss/maestro3.c b/sound/oss/maestro3.c
deleted file mode 100644
index 5548e3cff7ce..000000000000
--- a/sound/oss/maestro3.c
+++ /dev/null
@@ -1,2969 +0,0 @@
-/*****************************************************************************
- *
- * ESS Maestro3/Allegro driver for Linux 2.4.x
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * (c) Copyright 2000 Zach Brown <zab@zabbo.net>
- *
- * I need to thank many people for helping make this driver happen.
- * As always, Eric Brombaugh was a hacking machine and killed many bugs
- * that I was too dumb to notice. Howard Kim at ESS provided reference boards
- * and as much docs as he could. Todd and Mick at Dell tested snapshots on
- * an army of laptops. msw and deviant at Red Hat also humoured me by hanging
- * their laptops every few hours in the name of science.
- *
- * Shouts go out to Mike "DJ XPCom" Ang.
- *
- * History
- * v1.23 - Jun 5 2002 - Michael Olson <olson@cs.odu.edu>
- * added a module option to allow selection of GPIO pin number
- * for external amp
- * v1.22 - Feb 28 2001 - Zach Brown <zab@zabbo.net>
- * allocate mem at insmod/setup, rather than open
- * limit pci dma addresses to 28bit, thanks guys.
- * v1.21 - Feb 04 2001 - Zach Brown <zab@zabbo.net>
- * fix up really dumb notifier -> suspend oops
- * v1.20 - Jan 30 2001 - Zach Brown <zab@zabbo.net>
- * get rid of pm callback and use pci_dev suspend/resume instead
- * m3_probe cleanups, including pm oops think-o
- * v1.10 - Jan 6 2001 - Zach Brown <zab@zabbo.net>
- * revert to lame remap_page_range mmap() just to make it work
- * record mmap fixed.
- * fix up incredibly broken open/release resource management
- * duh. fix record format setting.
- * add SMP locking and cleanup formatting here and there
- * v1.00 - Dec 16 2000 - Zach Brown <zab@zabbo.net>
- * port to sexy 2.4 interfaces
- * properly align instance allocations so recording works
- * clean up function namespace a little :/
- * update PCI IDs based on mail from ESS
- * arbitrarily bump version number to show its 2.4 now,
- * 2.2 will stay 0., oss_audio port gets 2.
- * v0.03 - Nov 05 2000 - Zach Brown <zab@zabbo.net>
- * disable recording but allow dsp to be opened read
- * pull out most silly compat defines
- * v0.02 - Nov 04 2000 - Zach Brown <zab@zabbo.net>
- * changed clocking setup for m3, slowdown fixed.
- * codec reset is hopefully reliable now
- * rudimentary apm/power management makes suspend/resume work
- * v0.01 - Oct 31 2000 - Zach Brown <zab@zabbo.net>
- * first release
- * v0.00 - Sep 09 2000 - Zach Brown <zab@zabbo.net>
- * first pass derivation from maestro.c
- *
- * TODO
- * in/out allocated contiguously so fullduplex mmap will work?
- * no beep on init (mute)
- * resetup msrc data memory if freq changes?
- *
- * --
- *
- * Allow me to ramble a bit about the m3 architecture. The core of the
- * chip is the 'assp', the custom ESS dsp that runs the show. It has
- * a small amount of code and data ram. ESS drops binary dsp code images
- * on our heads, but we don't get to see specs on the dsp.
- *
- * The constant piece of code on the dsp is the 'kernel'. It also has a
- * chunk of the dsp memory that is statically set aside for its control
- * info. This is the KDATA defines in maestro3.h. Part of its core
- * data is a list of code addresses that point to the pieces of DSP code
- * that it should walk through in its loop. These other pieces of code
- * do the real work. The kernel presumably jumps into each of them in turn.
- * These code images tend to have their own data area, and one can have
- * multiple data areas representing different states for each of the 'client
- * instance' code portions. There is generally a list in the kernel data
- * that points to the data instances for a given piece of code.
- *
- * We've only been given the binary image for the 'minisrc', mini sample
- * rate converter. This is rather annoying because it limits the work
- * we can do on the dsp, but it also greatly simplifies the job of managing
- * dsp data memory for the code and data for our playing streams :). We
- * statically allocate the minisrc code into a region we 'know' to be free
- * based on the map of the binary kernel image we're loading. We also
- * statically allocate the data areas for the maximum number of pcm streams
- * we can be dealing with. This max is set by the length of the static list
- * in the kernel data that records the number of minisrc data regions we
- * can have. Thats right, all software dsp mixing with static code list
- * limits. Rock.
- *
- * How sound goes in and out is still a relative mystery. It appears
- * that the dsp has the ability to get input and output through various
- * 'connections'. To do IO from or to a connection, you put the address
- * of the minisrc client area in the static kernel data lists for that
- * input or output. so for pcm -> dsp -> mixer, we put the minisrc data
- * instance in the DMA list and also in the list for the mixer. I guess
- * it Just Knows which is in/out, and we give some dma control info that
- * helps. There are all sorts of cool inputs/outputs that it seems we can't
- * use without dsp code images that know how to use them.
- *
- * So at init time we preload all the memory allocation stuff and set some
- * system wide parameters. When we really get a sound to play we build
- * up its minisrc header (stream parameters, buffer addresses, input/output
- * settings). Then we throw its header on the various lists. We also
- * tickle some KDATA settings that ask the assp to raise clock interrupts
- * and do some amount of software mixing before handing data to the ac97.
- *
- * Sorry for the vague details. Feel free to ask Eric or myself if you
- * happen to be trying to use this driver elsewhere. Please accept my
- * apologies for the quality of the OSS support code, its passed through
- * too many hands now and desperately wants to be rethought.
- */
-
-/*****************************************************************************/
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ctype.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/reboot.h>
-#include <linux/spinlock.h>
-#include <linux/ac97_codec.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#include "maestro3.h"
-
-#define M_DEBUG 1
-
-#define DRIVER_VERSION "1.23"
-#define M3_MODULE_NAME "maestro3"
-#define PFX M3_MODULE_NAME ": "
-
-#define M3_STATE_MAGIC 0x734d724d
-#define M3_CARD_MAGIC 0x646e6f50
-
-#define ESS_FMT_STEREO 0x01
-#define ESS_FMT_16BIT 0x02
-#define ESS_FMT_MASK 0x03
-#define ESS_DAC_SHIFT 0
-#define ESS_ADC_SHIFT 4
-
-#define DAC_RUNNING 1
-#define ADC_RUNNING 2
-
-#define SND_DEV_DSP16 5
-
-#ifdef M_DEBUG
-static int debug;
-#define DPMOD 1 /* per module load */
-#define DPSTR 2 /* per 'stream' */
-#define DPSYS 3 /* per syscall */
-#define DPCRAP 4 /* stuff the user shouldn't see unless they're really debuggin */
-#define DPINT 5 /* per interrupt, LOTS */
-#define DPRINTK(DP, args...) {if (debug >= (DP)) printk(KERN_DEBUG PFX args);}
-#else
-#define DPRINTK(x)
-#endif
-
-struct m3_list {
- int curlen;
- u16 mem_addr;
- int max;
-};
-
-static int external_amp = 1;
-static int gpio_pin = -1;
-
-struct m3_state {
- unsigned int magic;
- struct m3_card *card;
- unsigned char fmt, enable;
-
- int index;
-
- /* this locks around the oss state in the driver */
- /* no, this lock is removed - only use card->lock */
- /* otherwise: against what are you protecting on SMP
- when irqhandler uses s->lock
- and m3_assp_read uses card->lock ?
- */
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
- mode_t open_mode;
-
- int dev_audio;
-
- struct assp_instance {
- u16 code, data;
- } dac_inst, adc_inst;
-
- /* should be in dmabuf */
- unsigned int rateadc, ratedac;
-
- struct dmabuf {
- void *rawbuf;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- /* new in m3 */
- int mixer_index, dma_index, msrc_index, adc1_index;
- int in_lists;
- /* 2.4.. */
- dma_addr_t handle;
-
- } dma_dac, dma_adc;
-};
-
-struct m3_card {
- unsigned int magic;
-
- struct m3_card *next;
-
- struct ac97_codec *ac97;
- spinlock_t ac97_lock;
-
- int card_type;
-
-#define NR_DSPS 1
-#define MAX_DSPS NR_DSPS
- struct m3_state channels[MAX_DSPS];
-
- /* this locks around the physical registers on the card */
- spinlock_t lock;
-
- /* hardware resources */
- struct pci_dev *pcidev;
- u32 iobase;
- u32 irq;
-
- int dacs_active;
-
- int timer_users;
-
- struct m3_list msrc_list,
- mixer_list,
- adc1_list,
- dma_list;
-
- /* for storing reset state..*/
- u8 reset_state;
-
- u16 *suspend_mem;
- int in_suspend;
- wait_queue_head_t suspend_queue;
-};
-
-/*
- * an arbitrary volume we set the internal
- * volume settings to so that the ac97 volume
- * range is a little less insane. 0x7fff is
- * max.
- */
-#define ARB_VOLUME ( 0x6800 )
-
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-enum {
- ESS_ALLEGRO,
- ESS_MAESTRO3,
- /*
- * a maestro3 with 'hardware strapping', only
- * found inside ESS?
- */
- ESS_MAESTRO3HW,
-};
-
-static char *card_names[] = {
- [ESS_ALLEGRO] = "Allegro",
- [ESS_MAESTRO3] = "Maestro3(i)",
- [ESS_MAESTRO3HW] = "Maestro3(i)hw"
-};
-
-#ifndef PCI_VENDOR_ESS
-#define PCI_VENDOR_ESS 0x125D
-#endif
-
-#define M3_DEVICE(DEV, TYPE) \
-{ \
-.vendor = PCI_VENDOR_ESS, \
-.device = DEV, \
-.subvendor = PCI_ANY_ID, \
-.subdevice = PCI_ANY_ID, \
-.class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, \
-.class_mask = 0xffff << 8, \
-.driver_data = TYPE, \
-}
-
-static struct pci_device_id m3_id_table[] = {
- M3_DEVICE(0x1988, ESS_ALLEGRO),
- M3_DEVICE(0x1998, ESS_MAESTRO3),
- M3_DEVICE(0x199a, ESS_MAESTRO3HW),
- {0,}
-};
-
-MODULE_DEVICE_TABLE (pci, m3_id_table);
-
-/*
- * reports seem to indicate that the m3 is limited
- * to 28bit bus addresses. aaaargggh...
- */
-#define M3_PCI_DMA_MASK 0x0fffffff
-
-static unsigned
-ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-static struct m3_card *devs;
-
-/*
- * I'm not very good at laying out functions in a file :)
- */
-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf);
-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state);
-static void check_suspend(struct m3_card *card);
-
-static struct notifier_block m3_reboot_nb = {
- .notifier_call = m3_notifier,
-};
-
-static void m3_outw(struct m3_card *card,
- u16 value, unsigned long reg)
-{
- check_suspend(card);
- outw(value, card->iobase + reg);
-}
-
-static u16 m3_inw(struct m3_card *card, unsigned long reg)
-{
- check_suspend(card);
- return inw(card->iobase + reg);
-}
-static void m3_outb(struct m3_card *card,
- u8 value, unsigned long reg)
-{
- check_suspend(card);
- outb(value, card->iobase + reg);
-}
-static u8 m3_inb(struct m3_card *card, unsigned long reg)
-{
- check_suspend(card);
- return inb(card->iobase + reg);
-}
-
-/*
- * access 16bit words to the code or data regions of the dsp's memory.
- * index addresses 16bit words.
- */
-static u16 __m3_assp_read(struct m3_card *card, u16 region, u16 index)
-{
- m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
- m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
- return m3_inw(card, DSP_PORT_MEMORY_DATA);
-}
-static u16 m3_assp_read(struct m3_card *card, u16 region, u16 index)
-{
- unsigned long flags;
- u16 ret;
-
- spin_lock_irqsave(&(card->lock), flags);
- ret = __m3_assp_read(card, region, index);
- spin_unlock_irqrestore(&(card->lock), flags);
-
- return ret;
-}
-
-static void __m3_assp_write(struct m3_card *card,
- u16 region, u16 index, u16 data)
-{
- m3_outw(card, region & MEMTYPE_MASK, DSP_PORT_MEMORY_TYPE);
- m3_outw(card, index, DSP_PORT_MEMORY_INDEX);
- m3_outw(card, data, DSP_PORT_MEMORY_DATA);
-}
-static void m3_assp_write(struct m3_card *card,
- u16 region, u16 index, u16 data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&(card->lock), flags);
- __m3_assp_write(card, region, index, data);
- spin_unlock_irqrestore(&(card->lock), flags);
-}
-
-static void m3_assp_halt(struct m3_card *card)
-{
- card->reset_state = m3_inb(card, DSP_PORT_CONTROL_REG_B) & ~REGB_STOP_CLOCK;
- mdelay(10);
- m3_outb(card, card->reset_state & ~REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
-}
-
-static void m3_assp_continue(struct m3_card *card)
-{
- m3_outb(card, card->reset_state | REGB_ENABLE_RESET, DSP_PORT_CONTROL_REG_B);
-}
-
-/*
- * This makes me sad. the maestro3 has lists
- * internally that must be packed.. 0 terminates,
- * apparently, or maybe all unused entries have
- * to be 0, the lists have static lengths set
- * by the binary code images.
- */
-
-static int m3_add_list(struct m3_card *card,
- struct m3_list *list, u16 val)
-{
- DPRINTK(DPSTR, "adding val 0x%x to list 0x%p at pos %d\n",
- val, list, list->curlen);
-
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + list->curlen,
- val);
-
- return list->curlen++;
-
-}
-
-static void m3_remove_list(struct m3_card *card,
- struct m3_list *list, int index)
-{
- u16 val;
- int lastindex = list->curlen - 1;
-
- DPRINTK(DPSTR, "removing ind %d from list 0x%p\n",
- index, list);
-
- if(index != lastindex) {
- val = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + lastindex);
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + index,
- val);
- }
-
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- list->mem_addr + lastindex,
- 0);
-
- list->curlen--;
-}
-
-static void set_fmt(struct m3_state *s, unsigned char mask, unsigned char data)
-{
- int tmp;
-
- s->fmt = (s->fmt & mask) | data;
-
- tmp = (s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK;
-
- /* write to 'mono' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 1,
- (tmp & ESS_FMT_STEREO) ? 0 : 1);
- /* write to '8bit' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 2,
- (tmp & ESS_FMT_16BIT) ? 0 : 1);
-
- tmp = (s->fmt >> ESS_ADC_SHIFT) & ESS_FMT_MASK;
-
- /* write to 'mono' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 1,
- (tmp & ESS_FMT_STEREO) ? 0 : 1);
- /* write to '8bit' word */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 2,
- (tmp & ESS_FMT_16BIT) ? 0 : 1);
-}
-
-static void set_dac_rate(struct m3_state *s, unsigned int rate)
-{
- u32 freq;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
-
- s->ratedac = rate;
-
- freq = ((rate << 15) + 24000 ) / 48000;
- if(freq)
- freq--;
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_FREQUENCY,
- freq);
-}
-
-static void set_adc_rate(struct m3_state *s, unsigned int rate)
-{
- u32 freq;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 8000)
- rate = 8000;
-
- s->rateadc = rate;
-
- freq = ((rate << 15) + 24000 ) / 48000;
- if(freq)
- freq--;
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_FREQUENCY,
- freq);
-}
-
-static void inc_timer_users(struct m3_card *card)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- card->timer_users++;
- DPRINTK(DPSYS, "inc timer users now %d\n",
- card->timer_users);
- if(card->timer_users != 1)
- goto out;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_RELOAD,
- 240 ) ;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_CURRENT,
- 240 ) ;
-
- m3_outw(card,
- m3_inw(card, HOST_INT_CTRL) | CLKRUN_GEN_ENABLE,
- HOST_INT_CTRL);
-out:
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-static void dec_timer_users(struct m3_card *card)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&card->lock, flags);
-
- card->timer_users--;
- DPRINTK(DPSYS, "dec timer users now %d\n",
- card->timer_users);
- if(card->timer_users > 0 )
- goto out;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_RELOAD,
- 0 ) ;
-
- __m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TIMER_COUNT_CURRENT,
- 0 ) ;
-
- m3_outw(card, m3_inw(card, HOST_INT_CTRL) & ~CLKRUN_GEN_ENABLE,
- HOST_INT_CTRL);
-out:
- spin_unlock_irqrestore(&card->lock, flags);
-}
-
-/*
- * {start,stop}_{adc,dac} should be called
- * while holding the 'state' lock and they
- * will try to grab the 'card' lock..
- */
-static void stop_adc(struct m3_state *s)
-{
- if (! (s->enable & ADC_RUNNING))
- return;
-
- s->enable &= ~ADC_RUNNING;
- dec_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_INSTANCE_READY, 0);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_ADC1_REQUEST, 0);
-}
-
-static void stop_dac(struct m3_state *s)
-{
- if (! (s->enable & DAC_RUNNING))
- return;
-
- DPRINTK(DPSYS, "stop_dac()\n");
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_INSTANCE_READY, 0);
-
- s->enable &= ~DAC_RUNNING;
- s->card->dacs_active--;
- dec_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_MIXER_TASK_NUMBER,
- s->card->dacs_active ) ;
-}
-
-static void start_dac(struct m3_state *s)
-{
- if( (!s->dma_dac.mapped && s->dma_dac.count < 1) ||
- !s->dma_dac.ready ||
- (s->enable & DAC_RUNNING))
- return;
-
- DPRINTK(DPSYS, "start_dac()\n");
-
- s->enable |= DAC_RUNNING;
- s->card->dacs_active++;
- inc_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_INSTANCE_READY, 1);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_MIXER_TASK_NUMBER,
- s->card->dacs_active ) ;
-}
-
-static void start_adc(struct m3_state *s)
-{
- if ((! s->dma_adc.mapped &&
- s->dma_adc.count >= (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- || !s->dma_adc.ready
- || (s->enable & ADC_RUNNING) )
- return;
-
- DPRINTK(DPSYS, "start_adc()\n");
-
- s->enable |= ADC_RUNNING;
- inc_timer_users(s->card);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- KDATA_ADC1_REQUEST, 1);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_INSTANCE_READY, 1);
-}
-
-static struct play_vals {
- u16 addr, val;
-} pv[] = {
- {CDATA_LEFT_VOLUME, ARB_VOLUME},
- {CDATA_RIGHT_VOLUME, ARB_VOLUME},
- {SRC3_DIRECTION_OFFSET, 0} ,
- /* +1, +2 are stereo/16 bit */
- {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
- {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
- {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
- {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
- {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
- {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
- {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
- {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
- {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
- {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
- {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
- {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
- {SRC3_DIRECTION_OFFSET + 16, 8}, /* numin */
- {SRC3_DIRECTION_OFFSET + 17, 50*2}, /* numout */
- {SRC3_DIRECTION_OFFSET + 18, MINISRC_BIQUAD_STAGE - 1}, /* numstage */
- {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
- {SRC3_DIRECTION_OFFSET + 21, 0} /* booster */
-};
-
-
-/* the mode passed should be already shifted and masked */
-static void m3_play_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
-{
- int dsp_in_size = MINISRC_IN_BUFFER_SIZE - (0x20 * 2);
- int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x20 * 2);
- int dsp_in_buffer = s->dac_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
- int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
- struct dmabuf *db = &s->dma_dac;
- int i;
-
- DPRINTK(DPSTR, "mode=%d rate=%d buf=%p len=%d.\n",
- mode, rate, buffer, size);
-
-#define LO(x) ((x) & 0xffff)
-#define HI(x) LO((x) >> 16)
-
- /* host dma buffer pointers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_ADDRL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_ADDRH,
- HI(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
- LO(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
- HI(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_CURRENTL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_HOST_SRC_CURRENTH,
- HI(virt_to_bus(buffer)));
-#undef LO
-#undef HI
-
- /* dsp buffers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_BEGIN,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_END_PLUS_1,
- dsp_in_buffer + (dsp_in_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_HEAD,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_IN_BUF_TAIL,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_BEGIN,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_END_PLUS_1,
- dsp_out_buffer + (dsp_out_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_HEAD,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_OUT_BUF_TAIL,
- dsp_out_buffer);
-
- /*
- * some per client initializers
- */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 12,
- s->dac_inst.data + 40 + 8);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 19,
- s->dac_inst.code + MINISRC_COEF_LOC);
-
- /* enable or disable low pass filter? */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + SRC3_DIRECTION_OFFSET + 22,
- s->ratedac > 45000 ? 0xff : 0 );
-
- /* tell it which way dma is going? */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + CDATA_DMA_CONTROL,
- DMACONTROL_AUTOREPEAT + DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
-
- /*
- * set an armload of static initializers
- */
- for(i = 0 ; i < (sizeof(pv) / sizeof(pv[0])) ; i++)
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->dac_inst.data + pv[i].addr, pv[i].val);
-
- /*
- * put us in the lists if we're not already there
- */
-
- if(db->in_lists == 0) {
-
- db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
- s->dac_inst.data >> DP_SHIFT_COUNT);
-
- db->dma_index = m3_add_list(s->card, &s->card->dma_list,
- s->dac_inst.data >> DP_SHIFT_COUNT);
-
- db->mixer_index = m3_add_list(s->card, &s->card->mixer_list,
- s->dac_inst.data >> DP_SHIFT_COUNT);
-
- db->in_lists = 1;
- }
-
- set_dac_rate(s,rate);
- start_dac(s);
-}
-
-/*
- * Native record driver
- */
-static struct rec_vals {
- u16 addr, val;
-} rv[] = {
- {CDATA_LEFT_VOLUME, ARB_VOLUME},
- {CDATA_RIGHT_VOLUME, ARB_VOLUME},
- {SRC3_DIRECTION_OFFSET, 1} ,
- /* +1, +2 are stereo/16 bit */
- {SRC3_DIRECTION_OFFSET + 3, 0x0000}, /* fraction? */
- {SRC3_DIRECTION_OFFSET + 4, 0}, /* first l */
- {SRC3_DIRECTION_OFFSET + 5, 0}, /* first r */
- {SRC3_DIRECTION_OFFSET + 6, 0}, /* second l */
- {SRC3_DIRECTION_OFFSET + 7, 0}, /* second r */
- {SRC3_DIRECTION_OFFSET + 8, 0}, /* delta l */
- {SRC3_DIRECTION_OFFSET + 9, 0}, /* delta r */
- {SRC3_DIRECTION_OFFSET + 10, 0x8000}, /* round */
- {SRC3_DIRECTION_OFFSET + 11, 0xFF00}, /* higher bute mark */
- {SRC3_DIRECTION_OFFSET + 13, 0}, /* temp0 */
- {SRC3_DIRECTION_OFFSET + 14, 0}, /* c fraction */
- {SRC3_DIRECTION_OFFSET + 15, 0}, /* counter */
- {SRC3_DIRECTION_OFFSET + 16, 50},/* numin */
- {SRC3_DIRECTION_OFFSET + 17, 8}, /* numout */
- {SRC3_DIRECTION_OFFSET + 18, 0}, /* numstage */
- {SRC3_DIRECTION_OFFSET + 19, 0}, /* coef */
- {SRC3_DIRECTION_OFFSET + 20, 0}, /* filtertap */
- {SRC3_DIRECTION_OFFSET + 21, 0}, /* booster */
- {SRC3_DIRECTION_OFFSET + 22, 0xff} /* skip lpf */
-};
-
-/* again, passed mode is alrady shifted/masked */
-static void m3_rec_setup(struct m3_state *s, int mode, u32 rate, void *buffer, int size)
-{
- int dsp_in_size = MINISRC_IN_BUFFER_SIZE + (0x10 * 2);
- int dsp_out_size = MINISRC_OUT_BUFFER_SIZE - (0x10 * 2);
- int dsp_in_buffer = s->adc_inst.data + (MINISRC_TMP_BUFFER_SIZE / 2);
- int dsp_out_buffer = dsp_in_buffer + (dsp_in_size / 2) + 1;
- struct dmabuf *db = &s->dma_adc;
- int i;
-
- DPRINTK(DPSTR, "rec_setup mode=%d rate=%d buf=%p len=%d.\n",
- mode, rate, buffer, size);
-
-#define LO(x) ((x) & 0xffff)
-#define HI(x) LO((x) >> 16)
-
- /* host dma buffer pointers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_ADDRL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_ADDRH,
- HI(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1L,
- LO(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_END_PLUS_1H,
- HI(virt_to_bus(buffer) + size));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_CURRENTL,
- LO(virt_to_bus(buffer)));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_HOST_SRC_CURRENTH,
- HI(virt_to_bus(buffer)));
-#undef LO
-#undef HI
-
- /* dsp buffers */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_BEGIN,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_END_PLUS_1,
- dsp_in_buffer + (dsp_in_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_HEAD,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_IN_BUF_TAIL,
- dsp_in_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_BEGIN,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_END_PLUS_1,
- dsp_out_buffer + (dsp_out_size / 2));
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_HEAD,
- dsp_out_buffer);
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_OUT_BUF_TAIL,
- dsp_out_buffer);
-
- /*
- * some per client initializers
- */
-
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + SRC3_DIRECTION_OFFSET + 12,
- s->adc_inst.data + 40 + 8);
-
- /* tell it which way dma is going? */
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + CDATA_DMA_CONTROL,
- DMACONTROL_DIRECTION + DMACONTROL_AUTOREPEAT +
- DMAC_PAGE3_SELECTOR + DMAC_BLOCKF_SELECTOR);
-
- /*
- * set an armload of static initializers
- */
- for(i = 0 ; i < (sizeof(rv) / sizeof(rv[0])) ; i++)
- m3_assp_write(s->card, MEMTYPE_INTERNAL_DATA,
- s->adc_inst.data + rv[i].addr, rv[i].val);
-
- /*
- * put us in the lists if we're not already there
- */
-
- if(db->in_lists == 0) {
-
- db->adc1_index = m3_add_list(s->card, &s->card->adc1_list,
- s->adc_inst.data >> DP_SHIFT_COUNT);
-
- db->dma_index = m3_add_list(s->card, &s->card->dma_list,
- s->adc_inst.data >> DP_SHIFT_COUNT);
-
- db->msrc_index = m3_add_list(s->card, &s->card->msrc_list,
- s->adc_inst.data >> DP_SHIFT_COUNT);
-
- db->in_lists = 1;
- }
-
- set_adc_rate(s,rate);
- start_adc(s);
-}
-/* --------------------------------------------------------------------- */
-
-static void set_dmaa(struct m3_state *s, unsigned int addr, unsigned int count)
-{
- DPRINTK(DPINT,"set_dmaa??\n");
-}
-
-static void set_dmac(struct m3_state *s, unsigned int addr, unsigned int count)
-{
- DPRINTK(DPINT,"set_dmac??\n");
-}
-
-static u32 get_dma_pos(struct m3_card *card,
- int instance_addr)
-{
- u16 hi = 0, lo = 0;
- int retry = 10;
-
- /*
- * try and get a valid answer
- */
- while(retry--) {
- hi = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- instance_addr + CDATA_HOST_SRC_CURRENTH);
-
- lo = m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- instance_addr + CDATA_HOST_SRC_CURRENTL);
-
- if(hi == m3_assp_read(card, MEMTYPE_INTERNAL_DATA,
- instance_addr + CDATA_HOST_SRC_CURRENTH))
- break;
- }
- return lo | (hi<<16);
-}
-
-static u32 get_dmaa(struct m3_state *s)
-{
- u32 offset;
-
- offset = get_dma_pos(s->card, s->dac_inst.data) -
- virt_to_bus(s->dma_dac.rawbuf);
-
- DPRINTK(DPINT,"get_dmaa: 0x%08x\n",offset);
-
- return offset;
-}
-
-static u32 get_dmac(struct m3_state *s)
-{
- u32 offset;
-
- offset = get_dma_pos(s->card, s->adc_inst.data) -
- virt_to_bus(s->dma_adc.rawbuf);
-
- DPRINTK(DPINT,"get_dmac: 0x%08x\n",offset);
-
- return offset;
-
-}
-
-static int
-prog_dmabuf(struct m3_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- unsigned bytepersec;
- unsigned bufs;
- unsigned char fmt;
- unsigned long flags;
-
- spin_lock_irqsave(&s->card->lock, flags);
-
- fmt = s->fmt;
- if (rec) {
- stop_adc(s);
- fmt >>= ESS_ADC_SHIFT;
- } else {
- stop_dac(s);
- fmt >>= ESS_DAC_SHIFT;
- }
- fmt &= ESS_FMT_MASK;
-
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
-
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
-
- DPRINTK(DPSTR,"prog_dmabuf: numfrag: %d fragsize: %d dmasize: %d\n",db->numfrag,db->fragsize,db->dmasize);
-
- memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
-
- if (rec)
- m3_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
- else
- m3_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
-
- db->ready = 1;
-
- spin_unlock_irqrestore(&s->card->lock, flags);
-
- return 0;
-}
-
-static void clear_advance(struct m3_state *s)
-{
- unsigned char c = ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_16BIT) ? 0 : 0x80;
-
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- /* account for wrapping? */
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void m3_update_ptr(struct m3_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- hwptr = get_dmac(s) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- if (!s->dma_adc.mapped) {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- stop_adc(s);
- /* brute force everyone back in sync, sigh */
- s->dma_adc.count = 0;
- s->dma_adc.swptr = 0;
- s->dma_adc.hwptr = 0;
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = get_dmaa(s) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
-
- DPRINTK(DPINT,"updating dac: hwptr: %6d diff: %6d count: %6d\n",
- hwptr,diff,s->dma_dac.count);
-
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
-
- if (s->dma_dac.mapped) {
-
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) {
- wake_up(&s->dma_dac.wait);
- }
- } else {
-
- s->dma_dac.count -= diff;
-
- if (s->dma_dac.count <= 0) {
- DPRINTK(DPCRAP,"underflow! diff: %d (0x%x) count: %d (0x%x) hw: %d (0x%x) sw: %d (0x%x)\n",
- diff, diff,
- s->dma_dac.count,
- s->dma_dac.count,
- hwptr, hwptr,
- s->dma_dac.swptr,
- s->dma_dac.swptr);
- stop_dac(s);
- /* brute force everyone back in sync, sigh */
- s->dma_dac.count = 0;
- s->dma_dac.swptr = hwptr;
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
- wake_up(&s->dma_dac.wait);
- DPRINTK(DPINT,"waking up DAC count: %d sw: %d hw: %d\n",
- s->dma_dac.count, s->dma_dac.swptr, hwptr);
- }
- }
- }
-}
-
-static irqreturn_t m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct m3_card *c = (struct m3_card *)dev_id;
- struct m3_state *s = &c->channels[0];
- u8 status;
-
- status = inb(c->iobase+0x1A);
-
- if(status == 0xff)
- return IRQ_NONE;
-
- /* presumably acking the ints? */
- outw(status, c->iobase+0x1A);
-
- if(c->in_suspend)
- return IRQ_HANDLED;
-
- /*
- * ack an assp int if its running
- * and has an int pending
- */
- if( status & ASSP_INT_PENDING) {
- u8 ctl = inb(c->iobase + ASSP_CONTROL_B);
- if( !(ctl & STOP_ASSP_CLOCK)) {
- ctl = inb(c->iobase + ASSP_HOST_INT_STATUS );
- if(ctl & DSP2HOST_REQ_TIMER) {
- outb( DSP2HOST_REQ_TIMER, c->iobase + ASSP_HOST_INT_STATUS);
- /* update adc/dac info if it was a timer int */
- spin_lock(&c->lock);
- m3_update_ptr(s);
- spin_unlock(&c->lock);
- }
- }
- }
-
- /* XXX is this needed? */
- if(status & 0x40)
- outb(0x40, c->iobase+0x1A);
- return IRQ_HANDLED;
-}
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT PFX "invalid magic value in %s\n";
-
-#define VALIDATE_MAGIC(FOO,MAG) \
-({ \
- if (!(FOO) || (FOO)->magic != MAG) { \
- printk(invalid_magic,__FUNCTION__); \
- return -ENXIO; \
- } \
-})
-
-#define VALIDATE_STATE(a) VALIDATE_MAGIC(a,M3_STATE_MAGIC)
-#define VALIDATE_CARD(a) VALIDATE_MAGIC(a,M3_CARD_MAGIC)
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct m3_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait,current);
- unsigned long flags;
- int count;
- signed long tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- spin_lock_irqsave(&s->card->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->card->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = (count * HZ) / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK];
- /* XXX this is just broken. someone is waking us up alot, or schedule_timeout is broken.
- or something. who cares. - zach */
- if (!schedule_timeout(tmo ? tmo : 1) && tmo)
- DPRINTK(DPCRAP,"dma timed out?? %ld\n",jiffies);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-static ssize_t m3_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-
- spin_lock_irqsave(&s->card->lock, flags);
-
- while (count > 0) {
- int timed_out;
-
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- start_adc(s);
- if (file->f_flags & O_NONBLOCK)
- {
- ret = ret ? ret : -EAGAIN;
- goto out;
- }
-
- spin_unlock_irqrestore(&s->card->lock, flags);
- timed_out = interruptible_sleep_on_timeout(&s->dma_adc.wait, HZ) == 0;
- spin_lock_irqsave(&s->card->lock, flags);
-
- if(timed_out) {
- printk("read: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- }
- if (signal_pending(current))
- {
- ret = ret ? ret : -ERESTARTSYS;
- goto out;
- }
- continue;
- }
-
- spin_unlock_irqrestore(&s->card->lock, flags);
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- ret = ret ? ret : -EFAULT;
- return ret;
- }
- spin_lock_irqsave(&s->card->lock, flags);
-
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_adc(s);
- }
-
-out:
- spin_unlock_irqrestore(&s->card->lock, flags);
- return ret;
-}
-
-static ssize_t m3_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-
- spin_lock_irqsave(&s->card->lock, flags);
-
- while (count > 0) {
- int timed_out;
-
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
-
- cnt = s->dma_dac.dmasize-swptr;
-
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
-
-
- if (cnt > count)
- cnt = count;
-
- if (cnt <= 0) {
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if(!ret) ret = -EAGAIN;
- goto out;
- }
- spin_unlock_irqrestore(&s->card->lock, flags);
- timed_out = interruptible_sleep_on_timeout(&s->dma_dac.wait, HZ) == 0;
- spin_lock_irqsave(&s->card->lock, flags);
- if(timed_out) {
- DPRINTK(DPCRAP,"write: chip lockup? dmasz %u fragsz %u count %u hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- stop_dac(s);
- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- }
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- goto out;
- }
- continue;
- }
- spin_unlock_irqrestore(&s->card->lock, flags);
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
- return ret;
- }
- spin_lock_irqsave(&s->card->lock, flags);
-
- DPRINTK(DPSYS,"wrote %6d bytes at sw: %6d cnt: %6d while hw: %6d\n",
- cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);
-
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
-
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- start_dac(s);
- }
-out:
- spin_unlock_irqrestore(&s->card->lock, flags);
- return ret;
-}
-
-static unsigned int m3_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &s->dma_dac.wait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &s->dma_adc.wait, wait);
-
- spin_lock_irqsave(&s->card->lock, flags);
- m3_update_ptr(s);
-
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
-
- spin_unlock_irqrestore(&s->card->lock, flags);
- return mask;
-}
-
-static int m3_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- unsigned long max_size, size, start, offset;
- struct dmabuf *db;
- int ret = -EINVAL;
-
- VALIDATE_STATE(s);
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- return ret;
- db = &s->dma_dac;
- } else
- if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- return ret;
- db = &s->dma_adc;
- } else
- return -EINVAL;
-
- max_size = db->dmasize;
-
- start = vma->vm_start;
- offset = (vma->vm_pgoff << PAGE_SHIFT);
- size = vma->vm_end - vma->vm_start;
-
- if(size > max_size)
- goto out;
- if(offset > max_size - size)
- goto out;
-
- /*
- * this will be ->nopage() once I can
- * ask Jeff what the hell I'm doing wrong.
- */
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
-
- db->mapped = 1;
- ret = 0;
-
-out:
- return ret;
-}
-
-/*
- * this function is a disaster..
- */
-#define get_user_ret(x, ptr, ret) ({ if(get_user(x, ptr)) return ret; })
-static int m3_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- struct m3_card *card=s->card;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
-
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
-
- DPRINTK(DPSYS,"m3_ioctl: cmd %d\n", cmd);
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, file->f_flags & O_NONBLOCK);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- /* XXX fix */
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- spin_lock_irqsave(&card->lock, flags);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->card->pcidev->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->card->pcidev->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- case SNDCTL_DSP_SPEED:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- set_adc_rate(s, val);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- set_dac_rate(s, val);
- }
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= ESS_FMT_STEREO << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_STEREO << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_U8|AFMT_S16_LE, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_ADC_SHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
- else
- fmtm &= ~(ESS_FMT_16BIT << ESS_DAC_SHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ?
- (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ?
- AFMT_S16_LE :
- AFMT_U8,
- p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if ((file->f_mode & FMODE_READ) && (s->enable & ADC_RUNNING))
- val |= PCM_ENABLE_INPUT;
- if ((file->f_mode & FMODE_WRITE) && (s->enable & DAC_RUNNING))
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- get_user_ret(val, p, -EFAULT);
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- start_adc(s);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- start_dac(s);
- } else
- stop_dac(s);
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!(s->enable & DAC_RUNNING) && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- abinfo.bytes = s->dma_dac.dmasize - s->dma_dac.count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&card->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!(s->enable & ADC_RUNNING) && (val = prog_dmabuf(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- abinfo.bytes = s->dma_adc.count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&card->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- val = s->dma_dac.count;
- spin_unlock_irqrestore(&card->lock, flags);
- return put_user(val, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- cinfo.blocks = s->dma_adc.count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&card->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- spin_lock_irqsave(&card->lock, flags);
- m3_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- cinfo.blocks = s->dma_dac.count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&card->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- get_user_ret(val, p, -EFAULT);
- spin_lock_irqsave(&card->lock, flags);
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- }
- spin_unlock_irqrestore(&card->lock, flags);
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- get_user_ret(val, p, -EFAULT);
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_STEREO << ESS_ADC_SHIFT)
- : (ESS_FMT_STEREO << ESS_DAC_SHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (ESS_FMT_16BIT << ESS_ADC_SHIFT)
- : (ESS_FMT_16BIT << ESS_DAC_SHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return -EINVAL;
-}
-
-static int
-allocate_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
-{
- int order;
-
- DPRINTK(DPSTR,"allocating for dmabuf %p\n", db);
-
- /*
- * alloc as big a chunk as we can, start with
- * 64k 'cause we're insane. based on order cause
- * the amazingly complicated prog_dmabuf wants it.
- *
- * pci_alloc_sonsistent guarantees that it won't cross a natural
- * boundary; the m3 hardware can't have dma cross a 64k bus
- * address boundary.
- */
- for (order = 16-PAGE_SHIFT; order >= 1; order--) {
- db->rawbuf = pci_alloc_consistent(pci_dev, PAGE_SIZE << order,
- &(db->handle));
- if(db->rawbuf)
- break;
- }
-
- if (!db->rawbuf)
- return 1;
-
- DPRINTK(DPSTR,"allocated %ld (%d) bytes at %p\n",
- PAGE_SIZE<<order, order, db->rawbuf);
-
- {
- struct page *page, *pend;
-
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << order) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
-
-
- db->buforder = order;
- db->ready = 0;
- db->mapped = 0;
-
- return 0;
-}
-
-static void
-nuke_lists(struct m3_card *card, struct dmabuf *db)
-{
- m3_remove_list(card, &(card->dma_list), db->dma_index);
- m3_remove_list(card, &(card->msrc_list), db->msrc_index);
- db->in_lists = 0;
-}
-
-static void
-free_dmabuf(struct pci_dev *pci_dev, struct dmabuf *db)
-{
- if(db->rawbuf == NULL)
- return;
-
- DPRINTK(DPSTR,"freeing %p from dmabuf %p\n",db->rawbuf, db);
-
- {
- struct page *page, *pend;
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- }
-
-
- pci_free_consistent(pci_dev, PAGE_SIZE << db->buforder,
- db->rawbuf, db->handle);
-
- db->rawbuf = NULL;
- db->buforder = 0;
- db->mapped = 0;
- db->ready = 0;
-}
-
-static int m3_open(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct m3_card *c;
- struct m3_state *s = NULL;
- int i;
- unsigned char fmtm = ~0, fmts = 0;
- unsigned long flags;
-
- /*
- * Scan the cards and find the channel. We only
- * do this at open time so it is ok
- */
- for(c = devs ; c != NULL ; c = c->next) {
-
- for(i=0;i<NR_DSPS;i++) {
-
- if(c->channels[i].dev_audio < 0)
- continue;
- if((c->channels[i].dev_audio ^ minor) & ~0xf)
- continue;
-
- s = &c->channels[i];
- break;
- }
- }
-
- if (!s)
- return -ENODEV;
-
- VALIDATE_STATE(s);
-
- file->private_data = s;
-
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EWOULDBLOCK;
- }
- mutex_unlock(&s->open_mutex);
- interruptible_sleep_on(&s->open_wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
-
- spin_lock_irqsave(&c->lock, flags);
-
- if (file->f_mode & FMODE_READ) {
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_ADC_SHIFT;
-
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- set_adc_rate(s, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_DAC_SHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= ESS_FMT_16BIT << ESS_DAC_SHIFT;
-
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- set_dac_rate(s, 8000);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
-
- mutex_unlock(&s->open_mutex);
- spin_unlock_irqrestore(&c->lock, flags);
- return nonseekable_open(inode, file);
-}
-
-static int m3_release(struct inode *inode, struct file *file)
-{
- struct m3_state *s = (struct m3_state *)file->private_data;
- struct m3_card *card=s->card;
- unsigned long flags;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
-
- mutex_lock(&s->open_mutex);
- spin_lock_irqsave(&card->lock, flags);
-
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- if(s->dma_dac.in_lists) {
- m3_remove_list(s->card, &(s->card->mixer_list), s->dma_dac.mixer_index);
- nuke_lists(s->card, &(s->dma_dac));
- }
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- if(s->dma_adc.in_lists) {
- m3_remove_list(s->card, &(s->card->adc1_list), s->dma_adc.adc1_index);
- nuke_lists(s->card, &(s->dma_adc));
- }
- }
-
- s->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
- spin_unlock_irqrestore(&card->lock, flags);
- mutex_unlock(&s->open_mutex);
- wake_up(&s->open_wait);
-
- return 0;
-}
-
-/*
- * Wait for the ac97 serial bus to be free.
- * return nonzero if the bus is still busy.
- */
-static int m3_ac97_wait(struct m3_card *card)
-{
- int i = 10000;
-
- while( (m3_inb(card, 0x30) & 1) && i--) ;
-
- return i == 0;
-}
-
-static u16 m3_ac97_read(struct ac97_codec *codec, u8 reg)
-{
- u16 ret = 0;
- struct m3_card *card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- if(m3_ac97_wait(card)) {
- printk(KERN_ERR PFX "serial bus busy reading reg 0x%x\n",reg);
- goto out;
- }
-
- m3_outb(card, 0x80 | (reg & 0x7f), 0x30);
-
- if(m3_ac97_wait(card)) {
- printk(KERN_ERR PFX "serial bus busy finishing read reg 0x%x\n",reg);
- goto out;
- }
-
- ret = m3_inw(card, 0x32);
- DPRINTK(DPCRAP,"reading 0x%04x from 0x%02x\n",ret, reg);
-
-out:
- spin_unlock(&card->ac97_lock);
- return ret;
-}
-
-static void m3_ac97_write(struct ac97_codec *codec, u8 reg, u16 val)
-{
- struct m3_card *card = codec->private_data;
-
- spin_lock(&card->ac97_lock);
-
- if(m3_ac97_wait(card)) {
- printk(KERN_ERR PFX "serial bus busy writing 0x%x to 0x%x\n",val, reg);
- goto out;
- }
- DPRINTK(DPCRAP,"writing 0x%04x to 0x%02x\n", val, reg);
-
- m3_outw(card, val, 0x32);
- m3_outb(card, reg & 0x7f, 0x30);
-out:
- spin_unlock(&card->ac97_lock);
-}
-/* OSS /dev/mixer file operation methods */
-static int m3_open_mixdev(struct inode *inode, struct file *file)
-{
- unsigned int minor = iminor(inode);
- struct m3_card *card = devs;
-
- for (card = devs; card != NULL; card = card->next) {
- if((card->ac97 != NULL) && (card->ac97->dev_mixer == minor))
- break;
- }
-
- if (!card) {
- return -ENODEV;
- }
-
- file->private_data = card->ac97;
-
- return nonseekable_open(inode, file);
-}
-
-static int m3_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int m3_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static struct file_operations m3_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = m3_ioctl_mixdev,
- .open = m3_open_mixdev,
- .release = m3_release_mixdev,
-};
-
-static void remote_codec_config(int io, int isremote)
-{
- isremote = isremote ? 1 : 0;
-
- outw( (inw(io + RING_BUS_CTRL_B) & ~SECOND_CODEC_ID_MASK) | isremote,
- io + RING_BUS_CTRL_B);
- outw( (inw(io + SDO_OUT_DEST_CTRL) & ~COMMAND_ADDR_OUT) | isremote,
- io + SDO_OUT_DEST_CTRL);
- outw( (inw(io + SDO_IN_DEST_CTRL) & ~STATUS_ADDR_IN) | isremote,
- io + SDO_IN_DEST_CTRL);
-}
-
-/*
- * hack, returns non zero on err
- */
-static int try_read_vendor(struct m3_card *card)
-{
- u16 ret;
-
- if(m3_ac97_wait(card))
- return 1;
-
- m3_outb(card, 0x80 | (AC97_VENDOR_ID1 & 0x7f), 0x30);
-
- if(m3_ac97_wait(card))
- return 1;
-
- ret = m3_inw(card, 0x32);
-
- return (ret == 0) || (ret == 0xffff);
-}
-
-static void m3_codec_reset(struct m3_card *card, int busywait)
-{
- u16 dir;
- int delay1 = 0, delay2 = 0, i;
- int io = card->iobase;
-
- switch (card->card_type) {
- /*
- * the onboard codec on the allegro seems
- * to want to wait a very long time before
- * coming back to life
- */
- case ESS_ALLEGRO:
- delay1 = 50;
- delay2 = 800;
- break;
- case ESS_MAESTRO3:
- case ESS_MAESTRO3HW:
- delay1 = 20;
- delay2 = 500;
- break;
- }
-
- for(i = 0; i < 5; i ++) {
- dir = inw(io + GPIO_DIRECTION);
- dir |= 0x10; /* assuming pci bus master? */
-
- remote_codec_config(io, 0);
-
- outw(IO_SRAM_ENABLE, io + RING_BUS_CTRL_A);
- udelay(20);
-
- outw(dir & ~GPO_PRIMARY_AC97 , io + GPIO_DIRECTION);
- outw(~GPO_PRIMARY_AC97 , io + GPIO_MASK);
- outw(0, io + GPIO_DATA);
- outw(dir | GPO_PRIMARY_AC97, io + GPIO_DIRECTION);
-
- if(busywait) {
- mdelay(delay1);
- } else {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((delay1 * HZ) / 1000);
- }
-
- outw(GPO_PRIMARY_AC97, io + GPIO_DATA);
- udelay(5);
- /* ok, bring back the ac-link */
- outw(IO_SRAM_ENABLE | SERIAL_AC_LINK_ENABLE, io + RING_BUS_CTRL_A);
- outw(~0, io + GPIO_MASK);
-
- if(busywait) {
- mdelay(delay2);
- } else {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((delay2 * HZ) / 1000);
- }
- if(! try_read_vendor(card))
- break;
-
- delay1 += 10;
- delay2 += 100;
-
- DPRINTK(DPMOD, "retrying codec reset with delays of %d and %d ms\n",
- delay1, delay2);
- }
-
-#if 0
- /* more gung-ho reset that doesn't
- * seem to work anywhere :)
- */
- tmp = inw(io + RING_BUS_CTRL_A);
- outw(RAC_SDFS_ENABLE|LAC_SDFS_ENABLE, io + RING_BUS_CTRL_A);
- mdelay(20);
- outw(tmp, io + RING_BUS_CTRL_A);
- mdelay(50);
-#endif
-}
-
-static int __devinit m3_codec_install(struct m3_card *card)
-{
- struct ac97_codec *codec;
-
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- codec->private_data = card;
- codec->codec_read = m3_ac97_read;
- codec->codec_write = m3_ac97_write;
- /* someday we should support secondary codecs.. */
- codec->id = 0;
-
- if (ac97_probe_codec(codec) == 0) {
- printk(KERN_ERR PFX "codec probe failed\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- if ((codec->dev_mixer = register_sound_mixer(&m3_mixer_fops, -1)) < 0) {
- printk(KERN_ERR PFX "couldn't register mixer!\n");
- ac97_release_codec(codec);
- return -1;
- }
-
- card->ac97 = codec;
-
- return 0;
-}
-
-
-#define MINISRC_LPF_LEN 10
-static u16 minisrc_lpf[MINISRC_LPF_LEN] = {
- 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C,
- 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F
-};
-static void m3_assp_init(struct m3_card *card)
-{
- int i;
-
- /* zero kernel data */
- for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_BASE_ADDR + i, 0);
-
- /* zero mixer data? */
- for(i = 0 ; i < (REV_B_DATA_MEMORY_UNIT_LENGTH * NUM_UNITS_KERNEL_DATA) / 2; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_BASE_ADDR2 + i, 0);
-
- /* init dma pointer */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_CURRENT_DMA,
- KDATA_DMA_XFER0);
-
- /* write kernel into code memory.. */
- for(i = 0 ; i < sizeof(assp_kernel_image) / 2; i++) {
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- REV_B_CODE_MEMORY_BEGIN + i,
- assp_kernel_image[i]);
- }
-
- /*
- * We only have this one client and we know that 0x400
- * is free in our kernel's mem map, so lets just
- * drop it there. It seems that the minisrc doesn't
- * need vectors, so we won't bother with them..
- */
- for(i = 0 ; i < sizeof(assp_minisrc_image) / 2; i++) {
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- 0x400 + i,
- assp_minisrc_image[i]);
- }
-
- /*
- * write the coefficients for the low pass filter?
- */
- for(i = 0; i < MINISRC_LPF_LEN ; i++) {
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- 0x400 + MINISRC_COEF_LOC + i,
- minisrc_lpf[i]);
- }
-
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE,
- 0x400 + MINISRC_COEF_LOC + MINISRC_LPF_LEN,
- 0x8000);
-
- /*
- * the minisrc is the only thing on
- * our task list..
- */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_TASK0,
- 0x400);
-
- /*
- * init the mixer number..
- */
-
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_MIXER_TASK_NUMBER,0);
-
- /*
- * EXTREME KERNEL MASTER VOLUME
- */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_DAC_LEFT_VOLUME, ARB_VOLUME);
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_DAC_RIGHT_VOLUME, ARB_VOLUME);
-
- card->mixer_list.mem_addr = KDATA_MIXER_XFER0;
- card->mixer_list.max = MAX_VIRTUAL_MIXER_CHANNELS;
- card->adc1_list.mem_addr = KDATA_ADC1_XFER0;
- card->adc1_list.max = MAX_VIRTUAL_ADC1_CHANNELS;
- card->dma_list.mem_addr = KDATA_DMA_XFER0;
- card->dma_list.max = MAX_VIRTUAL_DMA_CHANNELS;
- card->msrc_list.mem_addr = KDATA_INSTANCE0_MINISRC;
- card->msrc_list.max = MAX_INSTANCE_MINISRC;
-}
-
-static int setup_msrc(struct m3_card *card,
- struct assp_instance *inst, int index)
-{
- int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 +
- MINISRC_IN_BUFFER_SIZE / 2 +
- 1 + MINISRC_OUT_BUFFER_SIZE / 2 + 1 );
- int address, i;
-
- /*
- * the revb memory map has 0x1100 through 0x1c00
- * free.
- */
-
- /*
- * align instance address to 256 bytes so that it's
- * shifted list address is aligned.
- * list address = (mem address >> 1) >> 7;
- */
- data_bytes = (data_bytes + 255) & ~255;
- address = 0x1100 + ((data_bytes/2) * index);
-
- if((address + (data_bytes/2)) >= 0x1c00) {
- printk(KERN_ERR PFX "no memory for %d bytes at ind %d (addr 0x%x)\n",
- data_bytes, index, address);
- return -1;
- }
-
- for(i = 0; i < data_bytes/2 ; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- address + i, 0);
-
- inst->code = 0x400;
- inst->data = address;
-
- return 0;
-}
-
-static int m3_assp_client_init(struct m3_state *s)
-{
- setup_msrc(s->card, &(s->dac_inst), s->index * 2);
- setup_msrc(s->card, &(s->adc_inst), (s->index * 2) + 1);
-
- return 0;
-}
-
-static void m3_amp_enable(struct m3_card *card, int enable)
-{
- /*
- * this works for the reference board, have to find
- * out about others
- *
- * this needs more magic for 4 speaker, but..
- */
- int io = card->iobase;
- u16 gpo, polarity_port, polarity;
-
- if(!external_amp)
- return;
-
- if (gpio_pin >= 0 && gpio_pin <= 15) {
- polarity_port = 0x1000 + (0x100 * gpio_pin);
- } else {
- switch (card->card_type) {
- case ESS_ALLEGRO:
- polarity_port = 0x1800;
- break;
- default:
- polarity_port = 0x1100;
- /* Panasonic toughbook CF72 has to be different... */
- if(card->pcidev->subsystem_vendor == 0x10F7 && card->pcidev->subsystem_device == 0x833D)
- polarity_port = 0x1D00;
- break;
- }
- }
-
- gpo = (polarity_port >> 8) & 0x0F;
- polarity = polarity_port >> 12;
- if ( enable )
- polarity = !polarity;
- polarity = polarity << gpo;
- gpo = 1 << gpo;
-
- outw(~gpo , io + GPIO_MASK);
-
- outw( inw(io + GPIO_DIRECTION) | gpo ,
- io + GPIO_DIRECTION);
-
- outw( (GPO_SECONDARY_AC97 | GPO_PRIMARY_AC97 | polarity) ,
- io + GPIO_DATA);
-
- outw(0xffff , io + GPIO_MASK);
-}
-
-static int
-maestro_config(struct m3_card *card)
-{
- struct pci_dev *pcidev = card->pcidev;
- u32 n;
- u8 t; /* makes as much sense as 'n', no? */
-
- pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
- n &= REDUCED_DEBOUNCE;
- n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
- pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
-
- outb(RESET_ASSP, card->iobase + ASSP_CONTROL_B);
- pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
- n &= ~INT_CLK_SELECT;
- if(card->card_type >= ESS_MAESTRO3) {
- n &= ~INT_CLK_MULT_ENABLE;
- n |= INT_CLK_SRC_NOT_PCI;
- }
- n &= ~( CLK_MULT_MODE_SELECT | CLK_MULT_MODE_SELECT_2 );
- pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
-
- if(card->card_type <= ESS_ALLEGRO) {
- pci_read_config_dword(pcidev, PCI_USER_CONFIG, &n);
- n |= IN_CLK_12MHZ_SELECT;
- pci_write_config_dword(pcidev, PCI_USER_CONFIG, n);
- }
-
- t = inb(card->iobase + ASSP_CONTROL_A);
- t &= ~( DSP_CLK_36MHZ_SELECT | ASSP_CLK_49MHZ_SELECT);
- t |= ASSP_CLK_49MHZ_SELECT;
- t |= ASSP_0_WS_ENABLE;
- outb(t, card->iobase + ASSP_CONTROL_A);
-
- outb(RUN_ASSP, card->iobase + ASSP_CONTROL_B);
-
- return 0;
-}
-
-static void m3_enable_ints(struct m3_card *card)
-{
- unsigned long io = card->iobase;
-
- outw(ASSP_INT_ENABLE, io + HOST_INT_CTRL);
- outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
- io + ASSP_CONTROL_C);
-}
-
-static struct file_operations m3_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = m3_read,
- .write = m3_write,
- .poll = m3_poll,
- .ioctl = m3_ioctl,
- .mmap = m3_mmap,
- .open = m3_open,
- .release = m3_release,
-};
-
-#ifdef CONFIG_PM
-static int alloc_dsp_suspendmem(struct m3_card *card)
-{
- int len = sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
-
- if( (card->suspend_mem = vmalloc(len)) == NULL)
- return 1;
-
- return 0;
-}
-
-#else
-#define alloc_dsp_suspendmem(args...) 0
-#endif
-
-/*
- * great day! this function is ugly as hell.
- */
-static int __devinit m3_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
-{
- u32 n;
- int i;
- struct m3_card *card = NULL;
- int ret = 0;
- int card_type = pci_id->driver_data;
-
- DPRINTK(DPMOD, "in maestro_install\n");
-
- if (pci_enable_device(pci_dev))
- return -EIO;
-
- if (pci_set_dma_mask(pci_dev, M3_PCI_DMA_MASK)) {
- printk(KERN_ERR PFX "architecture does not support limiting to 28bit PCI bus addresses\n");
- return -ENODEV;
- }
-
- pci_set_master(pci_dev);
-
- if( (card = kmalloc(sizeof(struct m3_card), GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING PFX "out of memory\n");
- return -ENOMEM;
- }
- memset(card, 0, sizeof(struct m3_card));
- card->pcidev = pci_dev;
- init_waitqueue_head(&card->suspend_queue);
-
- if ( ! request_region(pci_resource_start(pci_dev, 0),
- pci_resource_len (pci_dev, 0), M3_MODULE_NAME)) {
-
- printk(KERN_WARNING PFX "unable to reserve I/O space.\n");
- ret = -EBUSY;
- goto out;
- }
-
- card->iobase = pci_resource_start(pci_dev, 0);
-
- if(alloc_dsp_suspendmem(card)) {
- printk(KERN_WARNING PFX "couldn't alloc %d bytes for saving dsp state on suspend\n",
- REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH);
- ret = -ENOMEM;
- goto out;
- }
-
- card->card_type = card_type;
- card->irq = pci_dev->irq;
- card->next = devs;
- card->magic = M3_CARD_MAGIC;
- spin_lock_init(&card->lock);
- spin_lock_init(&card->ac97_lock);
- devs = card;
- for(i = 0; i<NR_DSPS; i++) {
- struct m3_state *s = &(card->channels[i]);
- s->dev_audio = -1;
- }
-
- printk(KERN_INFO PFX "Configuring ESS %s found at IO 0x%04X IRQ %d\n",
- card_names[card->card_type], card->iobase, card->irq);
-
- pci_read_config_dword(pci_dev, PCI_SUBSYSTEM_VENDOR_ID, &n);
- printk(KERN_INFO PFX " subvendor id: 0x%08x\n",n);
-
- maestro_config(card);
- m3_assp_halt(card);
-
- m3_codec_reset(card, 0);
-
- if(m3_codec_install(card)) {
- ret = -EIO;
- goto out;
- }
-
- m3_assp_init(card);
- m3_amp_enable(card, 1);
-
- for(i=0;i<NR_DSPS;i++) {
- struct m3_state *s=&card->channels[i];
-
- s->index = i;
-
- s->card = card;
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- mutex_init(&(s->open_mutex));
- s->magic = M3_STATE_MAGIC;
-
- m3_assp_client_init(s);
-
- if(s->dma_adc.ready || s->dma_dac.ready || s->dma_adc.rawbuf)
- printk(KERN_WARNING PFX "initing a dsp device that is already in use?\n");
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&m3_audio_fops, -1)) < 0) {
- break;
- }
-
- if( allocate_dmabuf(card->pcidev, &(s->dma_adc)) ||
- allocate_dmabuf(card->pcidev, &(s->dma_dac))) {
- ret = -ENOMEM;
- goto out;
- }
- }
-
- if(request_irq(card->irq, m3_interrupt, IRQF_SHARED, card_names[card->card_type], card)) {
-
- printk(KERN_ERR PFX "unable to allocate irq %d,\n", card->irq);
-
- ret = -EIO;
- goto out;
- }
-
- pci_set_drvdata(pci_dev, card);
-
- m3_enable_ints(card);
- m3_assp_continue(card);
-
-out:
- if(ret) {
- if(card->iobase)
- release_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0));
- vfree(card->suspend_mem);
- if(card->ac97) {
- unregister_sound_mixer(card->ac97->dev_mixer);
- kfree(card->ac97);
- }
- for(i=0;i<NR_DSPS;i++)
- {
- struct m3_state *s = &card->channels[i];
- if(s->dev_audio != -1)
- unregister_sound_dsp(s->dev_audio);
- }
- kfree(card);
- }
-
- return ret;
-}
-
-static void m3_remove(struct pci_dev *pci_dev)
-{
- struct m3_card *card;
-
- unregister_reboot_notifier(&m3_reboot_nb);
-
- while ((card = devs)) {
- int i;
- devs = devs->next;
-
- free_irq(card->irq, card);
- unregister_sound_mixer(card->ac97->dev_mixer);
- kfree(card->ac97);
-
- for(i=0;i<NR_DSPS;i++)
- {
- struct m3_state *s = &card->channels[i];
- if(s->dev_audio < 0)
- continue;
-
- unregister_sound_dsp(s->dev_audio);
- free_dmabuf(card->pcidev, &s->dma_adc);
- free_dmabuf(card->pcidev, &s->dma_dac);
- }
-
- release_region(card->iobase, 256);
- vfree(card->suspend_mem);
- kfree(card);
- }
- devs = NULL;
-}
-
-/*
- * some bioses like the sound chip to be powered down
- * at shutdown. We're just calling _suspend to
- * achieve that..
- */
-static int m3_notifier(struct notifier_block *nb, unsigned long event, void *buf)
-{
- struct m3_card *card;
-
- DPRINTK(DPMOD, "notifier suspending all cards\n");
-
- for(card = devs; card != NULL; card = card->next) {
- if(!card->in_suspend)
- m3_suspend(card->pcidev, PMSG_SUSPEND); /* XXX legal? */
- }
- return 0;
-}
-
-static int m3_suspend(struct pci_dev *pci_dev, pm_message_t state)
-{
- unsigned long flags;
- int i;
- struct m3_card *card = pci_get_drvdata(pci_dev);
-
- /* must be a better way.. */
- spin_lock_irqsave(&card->lock, flags);
-
- DPRINTK(DPMOD, "pm in dev %p\n",card);
-
- for(i=0;i<NR_DSPS;i++) {
- struct m3_state *s = &card->channels[i];
-
- if(s->dev_audio == -1)
- continue;
-
- DPRINTK(DPMOD, "stop_adc/dac() device %d\n",i);
- stop_dac(s);
- stop_adc(s);
- }
-
- mdelay(10); /* give the assp a chance to idle.. */
-
- m3_assp_halt(card);
-
- if(card->suspend_mem) {
- int index = 0;
-
- DPRINTK(DPMOD, "saving code\n");
- for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
- card->suspend_mem[index++] =
- m3_assp_read(card, MEMTYPE_INTERNAL_CODE, i);
- DPRINTK(DPMOD, "saving data\n");
- for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
- card->suspend_mem[index++] =
- m3_assp_read(card, MEMTYPE_INTERNAL_DATA, i);
- }
-
- DPRINTK(DPMOD, "powering down apci regs\n");
- m3_outw(card, 0xffff, 0x54);
- m3_outw(card, 0xffff, 0x56);
-
- card->in_suspend = 1;
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- return 0;
-}
-
-static int m3_resume(struct pci_dev *pci_dev)
-{
- unsigned long flags;
- int index;
- int i;
- struct m3_card *card = pci_get_drvdata(pci_dev);
-
- spin_lock_irqsave(&card->lock, flags);
- card->in_suspend = 0;
-
- DPRINTK(DPMOD, "resuming\n");
-
- /* first lets just bring everything back. .*/
-
- DPRINTK(DPMOD, "bringing power back on card 0x%p\n",card);
- m3_outw(card, 0, 0x54);
- m3_outw(card, 0, 0x56);
-
- DPRINTK(DPMOD, "restoring pci configs and reseting codec\n");
- maestro_config(card);
- m3_assp_halt(card);
- m3_codec_reset(card, 1);
-
- DPRINTK(DPMOD, "restoring dsp code card\n");
- index = 0;
- for(i = REV_B_CODE_MEMORY_BEGIN ; i <= REV_B_CODE_MEMORY_END; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_CODE, i,
- card->suspend_mem[index++]);
- for(i = REV_B_DATA_MEMORY_BEGIN ; i <= REV_B_DATA_MEMORY_END; i++)
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA, i,
- card->suspend_mem[index++]);
-
- /* tell the dma engine to restart itself */
- m3_assp_write(card, MEMTYPE_INTERNAL_DATA,
- KDATA_DMA_ACTIVE, 0);
-
- DPRINTK(DPMOD, "resuming dsp\n");
- m3_assp_continue(card);
-
- DPRINTK(DPMOD, "enabling ints\n");
- m3_enable_ints(card);
-
- /* bring back the old school flavor */
- for(i = 0; i < SOUND_MIXER_NRDEVICES ; i++) {
- int state = card->ac97->mixer_state[i];
- if (!supported_mixer(card->ac97, i))
- continue;
-
- card->ac97->write_mixer(card->ac97, i,
- state & 0xff, (state >> 8) & 0xff);
- }
-
- m3_amp_enable(card, 1);
-
- /*
- * now we flip on the music
- */
- for(i=0;i<NR_DSPS;i++) {
- struct m3_state *s = &card->channels[i];
- if(s->dev_audio == -1)
- continue;
- /*
- * db->ready makes it so these guys can be
- * called unconditionally..
- */
- DPRINTK(DPMOD, "turning on dacs ind %d\n",i);
- start_dac(s);
- start_adc(s);
- }
-
- spin_unlock_irqrestore(&card->lock, flags);
-
- /*
- * all right, we think things are ready,
- * wake up people who were using the device
- * when we suspended
- */
- wake_up(&card->suspend_queue);
-
- return 0;
-}
-
-MODULE_AUTHOR("Zach Brown <zab@zabbo.net>");
-MODULE_DESCRIPTION("ESS Maestro3/Allegro Driver");
-MODULE_LICENSE("GPL");
-
-#ifdef M_DEBUG
-module_param(debug, int, 0);
-#endif
-module_param(external_amp, int, 0);
-module_param(gpio_pin, int, 0);
-
-static struct pci_driver m3_pci_driver = {
- .name = "ess_m3_audio",
- .id_table = m3_id_table,
- .probe = m3_probe,
- .remove = m3_remove,
- .suspend = m3_suspend,
- .resume = m3_resume,
-};
-
-static int __init m3_init_module(void)
-{
- printk(KERN_INFO PFX "version " DRIVER_VERSION " built at " __TIME__ " " __DATE__ "\n");
-
- if (register_reboot_notifier(&m3_reboot_nb)) {
- printk(KERN_WARNING PFX "reboot notifier registration failed\n");
- return -ENODEV; /* ? */
- }
-
- if (pci_register_driver(&m3_pci_driver)) {
- unregister_reboot_notifier(&m3_reboot_nb);
- return -ENODEV;
- }
- return 0;
-}
-
-static void __exit m3_cleanup_module(void)
-{
- pci_unregister_driver(&m3_pci_driver);
-}
-
-module_init(m3_init_module);
-module_exit(m3_cleanup_module);
-
-void check_suspend(struct m3_card *card)
-{
- DECLARE_WAITQUEUE(wait, current);
-
- if(!card->in_suspend)
- return;
-
- card->in_suspend++;
- add_wait_queue(&card->suspend_queue, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule();
- remove_wait_queue(&card->suspend_queue, &wait);
- set_current_state(TASK_RUNNING);
-}
diff --git a/sound/oss/maestro3.h b/sound/oss/maestro3.h
deleted file mode 100644
index dde29862c572..000000000000
--- a/sound/oss/maestro3.h
+++ /dev/null
@@ -1,821 +0,0 @@
-/*
- * ESS Technology allegro audio driver.
- *
- * Copyright (C) 1992-2000 Don Kim (don.kim@esstech.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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Hacked for the maestro3 driver by zab
- */
-
-// Allegro PCI configuration registers
-#define PCI_LEGACY_AUDIO_CTRL 0x40
-#define SOUND_BLASTER_ENABLE 0x00000001
-#define FM_SYNTHESIS_ENABLE 0x00000002
-#define GAME_PORT_ENABLE 0x00000004
-#define MPU401_IO_ENABLE 0x00000008
-#define MPU401_IRQ_ENABLE 0x00000010
-#define ALIAS_10BIT_IO 0x00000020
-#define SB_DMA_MASK 0x000000C0
-#define SB_DMA_0 0x00000040
-#define SB_DMA_1 0x00000040
-#define SB_DMA_R 0x00000080
-#define SB_DMA_3 0x000000C0
-#define SB_IRQ_MASK 0x00000700
-#define SB_IRQ_5 0x00000000
-#define SB_IRQ_7 0x00000100
-#define SB_IRQ_9 0x00000200
-#define SB_IRQ_10 0x00000300
-#define MIDI_IRQ_MASK 0x00003800
-#define SERIAL_IRQ_ENABLE 0x00004000
-#define DISABLE_LEGACY 0x00008000
-
-#define PCI_ALLEGRO_CONFIG 0x50
-#define SB_ADDR_240 0x00000004
-#define MPU_ADDR_MASK 0x00000018
-#define MPU_ADDR_330 0x00000000
-#define MPU_ADDR_300 0x00000008
-#define MPU_ADDR_320 0x00000010
-#define MPU_ADDR_340 0x00000018
-#define USE_PCI_TIMING 0x00000040
-#define POSTED_WRITE_ENABLE 0x00000080
-#define DMA_POLICY_MASK 0x00000700
-#define DMA_DDMA 0x00000000
-#define DMA_TDMA 0x00000100
-#define DMA_PCPCI 0x00000200
-#define DMA_WBDMA16 0x00000400
-#define DMA_WBDMA4 0x00000500
-#define DMA_WBDMA2 0x00000600
-#define DMA_WBDMA1 0x00000700
-#define DMA_SAFE_GUARD 0x00000800
-#define HI_PERF_GP_ENABLE 0x00001000
-#define PIC_SNOOP_MODE_0 0x00002000
-#define PIC_SNOOP_MODE_1 0x00004000
-#define SOUNDBLASTER_IRQ_MASK 0x00008000
-#define RING_IN_ENABLE 0x00010000
-#define SPDIF_TEST_MODE 0x00020000
-#define CLK_MULT_MODE_SELECT_2 0x00040000
-#define EEPROM_WRITE_ENABLE 0x00080000
-#define CODEC_DIR_IN 0x00100000
-#define HV_BUTTON_FROM_GD 0x00200000
-#define REDUCED_DEBOUNCE 0x00400000
-#define HV_CTRL_ENABLE 0x00800000
-#define SPDIF_ENABLE 0x01000000
-#define CLK_DIV_SELECT 0x06000000
-#define CLK_DIV_BY_48 0x00000000
-#define CLK_DIV_BY_49 0x02000000
-#define CLK_DIV_BY_50 0x04000000
-#define CLK_DIV_RESERVED 0x06000000
-#define PM_CTRL_ENABLE 0x08000000
-#define CLK_MULT_MODE_SELECT 0x30000000
-#define CLK_MULT_MODE_SHIFT 28
-#define CLK_MULT_MODE_0 0x00000000
-#define CLK_MULT_MODE_1 0x10000000
-#define CLK_MULT_MODE_2 0x20000000
-#define CLK_MULT_MODE_3 0x30000000
-#define INT_CLK_SELECT 0x40000000
-#define INT_CLK_MULT_RESET 0x80000000
-
-// M3
-#define INT_CLK_SRC_NOT_PCI 0x00100000
-#define INT_CLK_MULT_ENABLE 0x80000000
-
-#define PCI_ACPI_CONTROL 0x54
-#define PCI_ACPI_D0 0x00000000
-#define PCI_ACPI_D1 0xB4F70000
-#define PCI_ACPI_D2 0xB4F7B4F7
-
-#define PCI_USER_CONFIG 0x58
-#define EXT_PCI_MASTER_ENABLE 0x00000001
-#define SPDIF_OUT_SELECT 0x00000002
-#define TEST_PIN_DIR_CTRL 0x00000004
-#define AC97_CODEC_TEST 0x00000020
-#define TRI_STATE_BUFFER 0x00000080
-#define IN_CLK_12MHZ_SELECT 0x00000100
-#define MULTI_FUNC_DISABLE 0x00000200
-#define EXT_MASTER_PAIR_SEL 0x00000400
-#define PCI_MASTER_SUPPORT 0x00000800
-#define STOP_CLOCK_ENABLE 0x00001000
-#define EAPD_DRIVE_ENABLE 0x00002000
-#define REQ_TRI_STATE_ENABLE 0x00004000
-#define REQ_LOW_ENABLE 0x00008000
-#define MIDI_1_ENABLE 0x00010000
-#define MIDI_2_ENABLE 0x00020000
-#define SB_AUDIO_SYNC 0x00040000
-#define HV_CTRL_TEST 0x00100000
-#define SOUNDBLASTER_TEST 0x00400000
-
-#define PCI_USER_CONFIG_C 0x5C
-
-#define PCI_DDMA_CTRL 0x60
-#define DDMA_ENABLE 0x00000001
-
-
-// Allegro registers
-#define HOST_INT_CTRL 0x18
-#define SB_INT_ENABLE 0x0001
-#define MPU401_INT_ENABLE 0x0002
-#define ASSP_INT_ENABLE 0x0010
-#define RING_INT_ENABLE 0x0020
-#define HV_INT_ENABLE 0x0040
-#define CLKRUN_GEN_ENABLE 0x0100
-#define HV_CTRL_TO_PME 0x0400
-#define SOFTWARE_RESET_ENABLE 0x8000
-
-/*
- * should be using the above defines, probably.
- */
-#define REGB_ENABLE_RESET 0x01
-#define REGB_STOP_CLOCK 0x10
-
-#define HOST_INT_STATUS 0x1A
-#define SB_INT_PENDING 0x01
-#define MPU401_INT_PENDING 0x02
-#define ASSP_INT_PENDING 0x10
-#define RING_INT_PENDING 0x20
-#define HV_INT_PENDING 0x40
-
-#define HARDWARE_VOL_CTRL 0x1B
-#define SHADOW_MIX_REG_VOICE 0x1C
-#define HW_VOL_COUNTER_VOICE 0x1D
-#define SHADOW_MIX_REG_MASTER 0x1E
-#define HW_VOL_COUNTER_MASTER 0x1F
-
-#define CODEC_COMMAND 0x30
-#define CODEC_READ_B 0x80
-
-#define CODEC_STATUS 0x30
-#define CODEC_BUSY_B 0x01
-
-#define CODEC_DATA 0x32
-
-#define RING_BUS_CTRL_A 0x36
-#define RAC_PME_ENABLE 0x0100
-#define RAC_SDFS_ENABLE 0x0200
-#define LAC_PME_ENABLE 0x0400
-#define LAC_SDFS_ENABLE 0x0800
-#define SERIAL_AC_LINK_ENABLE 0x1000
-#define IO_SRAM_ENABLE 0x2000
-#define IIS_INPUT_ENABLE 0x8000
-
-#define RING_BUS_CTRL_B 0x38
-#define SECOND_CODEC_ID_MASK 0x0003
-#define SPDIF_FUNC_ENABLE 0x0010
-#define SECOND_AC_ENABLE 0x0020
-#define SB_MODULE_INTF_ENABLE 0x0040
-#define SSPE_ENABLE 0x0040
-#define M3I_DOCK_ENABLE 0x0080
-
-#define SDO_OUT_DEST_CTRL 0x3A
-#define COMMAND_ADDR_OUT 0x0003
-#define PCM_LR_OUT_LOCAL 0x0000
-#define PCM_LR_OUT_REMOTE 0x0004
-#define PCM_LR_OUT_MUTE 0x0008
-#define PCM_LR_OUT_BOTH 0x000C
-#define LINE1_DAC_OUT_LOCAL 0x0000
-#define LINE1_DAC_OUT_REMOTE 0x0010
-#define LINE1_DAC_OUT_MUTE 0x0020
-#define LINE1_DAC_OUT_BOTH 0x0030
-#define PCM_CLS_OUT_LOCAL 0x0000
-#define PCM_CLS_OUT_REMOTE 0x0040
-#define PCM_CLS_OUT_MUTE 0x0080
-#define PCM_CLS_OUT_BOTH 0x00C0
-#define PCM_RLF_OUT_LOCAL 0x0000
-#define PCM_RLF_OUT_REMOTE 0x0100
-#define PCM_RLF_OUT_MUTE 0x0200
-#define PCM_RLF_OUT_BOTH 0x0300
-#define LINE2_DAC_OUT_LOCAL 0x0000
-#define LINE2_DAC_OUT_REMOTE 0x0400
-#define LINE2_DAC_OUT_MUTE 0x0800
-#define LINE2_DAC_OUT_BOTH 0x0C00
-#define HANDSET_OUT_LOCAL 0x0000
-#define HANDSET_OUT_REMOTE 0x1000
-#define HANDSET_OUT_MUTE 0x2000
-#define HANDSET_OUT_BOTH 0x3000
-#define IO_CTRL_OUT_LOCAL 0x0000
-#define IO_CTRL_OUT_REMOTE 0x4000
-#define IO_CTRL_OUT_MUTE 0x8000
-#define IO_CTRL_OUT_BOTH 0xC000
-
-#define SDO_IN_DEST_CTRL 0x3C
-#define STATUS_ADDR_IN 0x0003
-#define PCM_LR_IN_LOCAL 0x0000
-#define PCM_LR_IN_REMOTE 0x0004
-#define PCM_LR_RESERVED 0x0008
-#define PCM_LR_IN_BOTH 0x000C
-#define LINE1_ADC_IN_LOCAL 0x0000
-#define LINE1_ADC_IN_REMOTE 0x0010
-#define LINE1_ADC_IN_MUTE 0x0020
-#define MIC_ADC_IN_LOCAL 0x0000
-#define MIC_ADC_IN_REMOTE 0x0040
-#define MIC_ADC_IN_MUTE 0x0080
-#define LINE2_DAC_IN_LOCAL 0x0000
-#define LINE2_DAC_IN_REMOTE 0x0400
-#define LINE2_DAC_IN_MUTE 0x0800
-#define HANDSET_IN_LOCAL 0x0000
-#define HANDSET_IN_REMOTE 0x1000
-#define HANDSET_IN_MUTE 0x2000
-#define IO_STATUS_IN_LOCAL 0x0000
-#define IO_STATUS_IN_REMOTE 0x4000
-
-#define SPDIF_IN_CTRL 0x3E
-#define SPDIF_IN_ENABLE 0x0001
-
-#define GPIO_DATA 0x60
-#define GPIO_DATA_MASK 0x0FFF
-#define GPIO_HV_STATUS 0x3000
-#define GPIO_PME_STATUS 0x4000
-
-#define GPIO_MASK 0x64
-#define GPIO_DIRECTION 0x68
-#define GPO_PRIMARY_AC97 0x0001
-#define GPI_LINEOUT_SENSE 0x0004
-#define GPO_SECONDARY_AC97 0x0008
-#define GPI_VOL_DOWN 0x0010
-#define GPI_VOL_UP 0x0020
-#define GPI_IIS_CLK 0x0040
-#define GPI_IIS_LRCLK 0x0080
-#define GPI_IIS_DATA 0x0100
-#define GPI_DOCKING_STATUS 0x0100
-#define GPI_HEADPHONE_SENSE 0x0200
-#define GPO_EXT_AMP_SHUTDOWN 0x1000
-
-// M3
-#define GPO_M3_EXT_AMP_SHUTDN 0x0002
-
-#define ASSP_INDEX_PORT 0x80
-#define ASSP_MEMORY_PORT 0x82
-#define ASSP_DATA_PORT 0x84
-
-#define MPU401_DATA_PORT 0x98
-#define MPU401_STATUS_PORT 0x99
-
-#define CLK_MULT_DATA_PORT 0x9C
-
-#define ASSP_CONTROL_A 0xA2
-#define ASSP_0_WS_ENABLE 0x01
-#define ASSP_CTRL_A_RESERVED1 0x02
-#define ASSP_CTRL_A_RESERVED2 0x04
-#define ASSP_CLK_49MHZ_SELECT 0x08
-#define FAST_PLU_ENABLE 0x10
-#define ASSP_CTRL_A_RESERVED3 0x20
-#define DSP_CLK_36MHZ_SELECT 0x40
-
-#define ASSP_CONTROL_B 0xA4
-#define RESET_ASSP 0x00
-#define RUN_ASSP 0x01
-#define ENABLE_ASSP_CLOCK 0x00
-#define STOP_ASSP_CLOCK 0x10
-#define RESET_TOGGLE 0x40
-
-#define ASSP_CONTROL_C 0xA6
-#define ASSP_HOST_INT_ENABLE 0x01
-#define FM_ADDR_REMAP_DISABLE 0x02
-#define HOST_WRITE_PORT_ENABLE 0x08
-
-#define ASSP_HOST_INT_STATUS 0xAC
-#define DSP2HOST_REQ_PIORECORD 0x01
-#define DSP2HOST_REQ_I2SRATE 0x02
-#define DSP2HOST_REQ_TIMER 0x04
-
-// AC97 registers
-// XXX fix this crap up
-/*#define AC97_RESET 0x00*/
-
-#define AC97_VOL_MUTE_B 0x8000
-#define AC97_VOL_M 0x1F
-#define AC97_LEFT_VOL_S 8
-
-#define AC97_MASTER_VOL 0x02
-#define AC97_LINE_LEVEL_VOL 0x04
-#define AC97_MASTER_MONO_VOL 0x06
-#define AC97_PC_BEEP_VOL 0x0A
-#define AC97_PC_BEEP_VOL_M 0x0F
-#define AC97_SROUND_MASTER_VOL 0x38
-#define AC97_PC_BEEP_VOL_S 1
-
-/*#define AC97_PHONE_VOL 0x0C
-#define AC97_MIC_VOL 0x0E*/
-#define AC97_MIC_20DB_ENABLE 0x40
-
-/*#define AC97_LINEIN_VOL 0x10
-#define AC97_CD_VOL 0x12
-#define AC97_VIDEO_VOL 0x14
-#define AC97_AUX_VOL 0x16*/
-#define AC97_PCM_OUT_VOL 0x18
-/*#define AC97_RECORD_SELECT 0x1A*/
-#define AC97_RECORD_MIC 0x00
-#define AC97_RECORD_CD 0x01
-#define AC97_RECORD_VIDEO 0x02
-#define AC97_RECORD_AUX 0x03
-#define AC97_RECORD_MONO_MUX 0x02
-#define AC97_RECORD_DIGITAL 0x03
-#define AC97_RECORD_LINE 0x04
-#define AC97_RECORD_STEREO 0x05
-#define AC97_RECORD_MONO 0x06
-#define AC97_RECORD_PHONE 0x07
-
-/*#define AC97_RECORD_GAIN 0x1C*/
-#define AC97_RECORD_VOL_M 0x0F
-
-/*#define AC97_GENERAL_PURPOSE 0x20*/
-#define AC97_POWER_DOWN_CTRL 0x26
-#define AC97_ADC_READY 0x0001
-#define AC97_DAC_READY 0x0002
-#define AC97_ANALOG_READY 0x0004
-#define AC97_VREF_ON 0x0008
-#define AC97_PR0 0x0100
-#define AC97_PR1 0x0200
-#define AC97_PR2 0x0400
-#define AC97_PR3 0x0800
-#define AC97_PR4 0x1000
-
-#define AC97_RESERVED1 0x28
-
-#define AC97_VENDOR_TEST 0x5A
-
-#define AC97_CLOCK_DELAY 0x5C
-#define AC97_LINEOUT_MUX_SEL 0x0001
-#define AC97_MONO_MUX_SEL 0x0002
-#define AC97_CLOCK_DELAY_SEL 0x1F
-#define AC97_DAC_CDS_SHIFT 6
-#define AC97_ADC_CDS_SHIFT 11
-
-#define AC97_MULTI_CHANNEL_SEL 0x74
-
-/*#define AC97_VENDOR_ID1 0x7C
-#define AC97_VENDOR_ID2 0x7E*/
-
-/*
- * ASSP control regs
- */
-#define DSP_PORT_TIMER_COUNT 0x06
-
-#define DSP_PORT_MEMORY_INDEX 0x80
-
-#define DSP_PORT_MEMORY_TYPE 0x82
-#define MEMTYPE_INTERNAL_CODE 0x0002
-#define MEMTYPE_INTERNAL_DATA 0x0003
-#define MEMTYPE_MASK 0x0003
-
-#define DSP_PORT_MEMORY_DATA 0x84
-
-#define DSP_PORT_CONTROL_REG_A 0xA2
-#define DSP_PORT_CONTROL_REG_B 0xA4
-#define DSP_PORT_CONTROL_REG_C 0xA6
-
-#define REV_A_CODE_MEMORY_BEGIN 0x0000
-#define REV_A_CODE_MEMORY_END 0x0FFF
-#define REV_A_CODE_MEMORY_UNIT_LENGTH 0x0040
-#define REV_A_CODE_MEMORY_LENGTH (REV_A_CODE_MEMORY_END - REV_A_CODE_MEMORY_BEGIN + 1)
-
-#define REV_B_CODE_MEMORY_BEGIN 0x0000
-#define REV_B_CODE_MEMORY_END 0x0BFF
-#define REV_B_CODE_MEMORY_UNIT_LENGTH 0x0040
-#define REV_B_CODE_MEMORY_LENGTH (REV_B_CODE_MEMORY_END - REV_B_CODE_MEMORY_BEGIN + 1)
-
-#define REV_A_DATA_MEMORY_BEGIN 0x1000
-#define REV_A_DATA_MEMORY_END 0x2FFF
-#define REV_A_DATA_MEMORY_UNIT_LENGTH 0x0080
-#define REV_A_DATA_MEMORY_LENGTH (REV_A_DATA_MEMORY_END - REV_A_DATA_MEMORY_BEGIN + 1)
-
-#define REV_B_DATA_MEMORY_BEGIN 0x1000
-#define REV_B_DATA_MEMORY_END 0x2BFF
-#define REV_B_DATA_MEMORY_UNIT_LENGTH 0x0080
-#define REV_B_DATA_MEMORY_LENGTH (REV_B_DATA_MEMORY_END - REV_B_DATA_MEMORY_BEGIN + 1)
-
-
-#define NUM_UNITS_KERNEL_CODE 16
-#define NUM_UNITS_KERNEL_DATA 2
-
-#define NUM_UNITS_KERNEL_CODE_WITH_HSP 16
-#define NUM_UNITS_KERNEL_DATA_WITH_HSP 5
-
-/*
- * Kernel data layout
- */
-
-#define DP_SHIFT_COUNT 7
-
-#define KDATA_BASE_ADDR 0x1000
-#define KDATA_BASE_ADDR2 0x1080
-
-#define KDATA_TASK0 (KDATA_BASE_ADDR + 0x0000)
-#define KDATA_TASK1 (KDATA_BASE_ADDR + 0x0001)
-#define KDATA_TASK2 (KDATA_BASE_ADDR + 0x0002)
-#define KDATA_TASK3 (KDATA_BASE_ADDR + 0x0003)
-#define KDATA_TASK4 (KDATA_BASE_ADDR + 0x0004)
-#define KDATA_TASK5 (KDATA_BASE_ADDR + 0x0005)
-#define KDATA_TASK6 (KDATA_BASE_ADDR + 0x0006)
-#define KDATA_TASK7 (KDATA_BASE_ADDR + 0x0007)
-#define KDATA_TASK_ENDMARK (KDATA_BASE_ADDR + 0x0008)
-
-#define KDATA_CURRENT_TASK (KDATA_BASE_ADDR + 0x0009)
-#define KDATA_TASK_SWITCH (KDATA_BASE_ADDR + 0x000A)
-
-#define KDATA_INSTANCE0_POS3D (KDATA_BASE_ADDR + 0x000B)
-#define KDATA_INSTANCE1_POS3D (KDATA_BASE_ADDR + 0x000C)
-#define KDATA_INSTANCE2_POS3D (KDATA_BASE_ADDR + 0x000D)
-#define KDATA_INSTANCE3_POS3D (KDATA_BASE_ADDR + 0x000E)
-#define KDATA_INSTANCE4_POS3D (KDATA_BASE_ADDR + 0x000F)
-#define KDATA_INSTANCE5_POS3D (KDATA_BASE_ADDR + 0x0010)
-#define KDATA_INSTANCE6_POS3D (KDATA_BASE_ADDR + 0x0011)
-#define KDATA_INSTANCE7_POS3D (KDATA_BASE_ADDR + 0x0012)
-#define KDATA_INSTANCE8_POS3D (KDATA_BASE_ADDR + 0x0013)
-#define KDATA_INSTANCE_POS3D_ENDMARK (KDATA_BASE_ADDR + 0x0014)
-
-#define KDATA_INSTANCE0_SPKVIRT (KDATA_BASE_ADDR + 0x0015)
-#define KDATA_INSTANCE_SPKVIRT_ENDMARK (KDATA_BASE_ADDR + 0x0016)
-
-#define KDATA_INSTANCE0_SPDIF (KDATA_BASE_ADDR + 0x0017)
-#define KDATA_INSTANCE_SPDIF_ENDMARK (KDATA_BASE_ADDR + 0x0018)
-
-#define KDATA_INSTANCE0_MODEM (KDATA_BASE_ADDR + 0x0019)
-#define KDATA_INSTANCE_MODEM_ENDMARK (KDATA_BASE_ADDR + 0x001A)
-
-#define KDATA_INSTANCE0_SRC (KDATA_BASE_ADDR + 0x001B)
-#define KDATA_INSTANCE1_SRC (KDATA_BASE_ADDR + 0x001C)
-#define KDATA_INSTANCE_SRC_ENDMARK (KDATA_BASE_ADDR + 0x001D)
-
-#define KDATA_INSTANCE0_MINISRC (KDATA_BASE_ADDR + 0x001E)
-#define KDATA_INSTANCE1_MINISRC (KDATA_BASE_ADDR + 0x001F)
-#define KDATA_INSTANCE2_MINISRC (KDATA_BASE_ADDR + 0x0020)
-#define KDATA_INSTANCE3_MINISRC (KDATA_BASE_ADDR + 0x0021)
-#define KDATA_INSTANCE_MINISRC_ENDMARK (KDATA_BASE_ADDR + 0x0022)
-
-#define KDATA_INSTANCE0_CPYTHRU (KDATA_BASE_ADDR + 0x0023)
-#define KDATA_INSTANCE1_CPYTHRU (KDATA_BASE_ADDR + 0x0024)
-#define KDATA_INSTANCE_CPYTHRU_ENDMARK (KDATA_BASE_ADDR + 0x0025)
-
-#define KDATA_CURRENT_DMA (KDATA_BASE_ADDR + 0x0026)
-#define KDATA_DMA_SWITCH (KDATA_BASE_ADDR + 0x0027)
-#define KDATA_DMA_ACTIVE (KDATA_BASE_ADDR + 0x0028)
-
-#define KDATA_DMA_XFER0 (KDATA_BASE_ADDR + 0x0029)
-#define KDATA_DMA_XFER1 (KDATA_BASE_ADDR + 0x002A)
-#define KDATA_DMA_XFER2 (KDATA_BASE_ADDR + 0x002B)
-#define KDATA_DMA_XFER3 (KDATA_BASE_ADDR + 0x002C)
-#define KDATA_DMA_XFER4 (KDATA_BASE_ADDR + 0x002D)
-#define KDATA_DMA_XFER5 (KDATA_BASE_ADDR + 0x002E)
-#define KDATA_DMA_XFER6 (KDATA_BASE_ADDR + 0x002F)
-#define KDATA_DMA_XFER7 (KDATA_BASE_ADDR + 0x0030)
-#define KDATA_DMA_XFER8 (KDATA_BASE_ADDR + 0x0031)
-#define KDATA_DMA_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0032)
-
-#define KDATA_I2S_SAMPLE_COUNT (KDATA_BASE_ADDR + 0x0033)
-#define KDATA_I2S_INT_METER (KDATA_BASE_ADDR + 0x0034)
-#define KDATA_I2S_ACTIVE (KDATA_BASE_ADDR + 0x0035)
-
-#define KDATA_TIMER_COUNT_RELOAD (KDATA_BASE_ADDR + 0x0036)
-#define KDATA_TIMER_COUNT_CURRENT (KDATA_BASE_ADDR + 0x0037)
-
-#define KDATA_HALT_SYNCH_CLIENT (KDATA_BASE_ADDR + 0x0038)
-#define KDATA_HALT_SYNCH_DMA (KDATA_BASE_ADDR + 0x0039)
-#define KDATA_HALT_ACKNOWLEDGE (KDATA_BASE_ADDR + 0x003A)
-
-#define KDATA_ADC1_XFER0 (KDATA_BASE_ADDR + 0x003B)
-#define KDATA_ADC1_XFER_ENDMARK (KDATA_BASE_ADDR + 0x003C)
-#define KDATA_ADC1_LEFT_VOLUME (KDATA_BASE_ADDR + 0x003D)
-#define KDATA_ADC1_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x003E)
-#define KDATA_ADC1_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x003F)
-#define KDATA_ADC1_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0040)
-
-#define KDATA_ADC2_XFER0 (KDATA_BASE_ADDR + 0x0041)
-#define KDATA_ADC2_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0042)
-#define KDATA_ADC2_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0043)
-#define KDATA_ADC2_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x0044)
-#define KDATA_ADC2_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x0045)
-#define KDATA_ADC2_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x0046)
-
-#define KDATA_CD_XFER0 (KDATA_BASE_ADDR + 0x0047)
-#define KDATA_CD_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0048)
-#define KDATA_CD_LEFT_VOLUME (KDATA_BASE_ADDR + 0x0049)
-#define KDATA_CD_RIGHT_VOLUME (KDATA_BASE_ADDR + 0x004A)
-#define KDATA_CD_LEFT_SUR_VOL (KDATA_BASE_ADDR + 0x004B)
-#define KDATA_CD_RIGHT_SUR_VOL (KDATA_BASE_ADDR + 0x004C)
-
-#define KDATA_MIC_XFER0 (KDATA_BASE_ADDR + 0x004D)
-#define KDATA_MIC_XFER_ENDMARK (KDATA_BASE_ADDR + 0x004E)
-#define KDATA_MIC_VOLUME (KDATA_BASE_ADDR + 0x004F)
-#define KDATA_MIC_SUR_VOL (KDATA_BASE_ADDR + 0x0050)
-
-#define KDATA_I2S_XFER0 (KDATA_BASE_ADDR + 0x0051)
-#define KDATA_I2S_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0052)
-
-#define KDATA_CHI_XFER0 (KDATA_BASE_ADDR + 0x0053)
-#define KDATA_CHI_XFER_ENDMARK (KDATA_BASE_ADDR + 0x0054)
-
-#define KDATA_SPDIF_XFER (KDATA_BASE_ADDR + 0x0055)
-#define KDATA_SPDIF_CURRENT_FRAME (KDATA_BASE_ADDR + 0x0056)
-#define KDATA_SPDIF_FRAME0 (KDATA_BASE_ADDR + 0x0057)
-#define KDATA_SPDIF_FRAME1 (KDATA_BASE_ADDR + 0x0058)
-#define KDATA_SPDIF_FRAME2 (KDATA_BASE_ADDR + 0x0059)
-
-#define KDATA_SPDIF_REQUEST (KDATA_BASE_ADDR + 0x005A)
-#define KDATA_SPDIF_TEMP (KDATA_BASE_ADDR + 0x005B)
-
-#define KDATA_SPDIFIN_XFER0 (KDATA_BASE_ADDR + 0x005C)
-#define KDATA_SPDIFIN_XFER_ENDMARK (KDATA_BASE_ADDR + 0x005D)
-#define KDATA_SPDIFIN_INT_METER (KDATA_BASE_ADDR + 0x005E)
-
-#define KDATA_DSP_RESET_COUNT (KDATA_BASE_ADDR + 0x005F)
-#define KDATA_DEBUG_OUTPUT (KDATA_BASE_ADDR + 0x0060)
-
-#define KDATA_KERNEL_ISR_LIST (KDATA_BASE_ADDR + 0x0061)
-
-#define KDATA_KERNEL_ISR_CBSR1 (KDATA_BASE_ADDR + 0x0062)
-#define KDATA_KERNEL_ISR_CBER1 (KDATA_BASE_ADDR + 0x0063)
-#define KDATA_KERNEL_ISR_CBCR (KDATA_BASE_ADDR + 0x0064)
-#define KDATA_KERNEL_ISR_AR0 (KDATA_BASE_ADDR + 0x0065)
-#define KDATA_KERNEL_ISR_AR1 (KDATA_BASE_ADDR + 0x0066)
-#define KDATA_KERNEL_ISR_AR2 (KDATA_BASE_ADDR + 0x0067)
-#define KDATA_KERNEL_ISR_AR3 (KDATA_BASE_ADDR + 0x0068)
-#define KDATA_KERNEL_ISR_AR4 (KDATA_BASE_ADDR + 0x0069)
-#define KDATA_KERNEL_ISR_AR5 (KDATA_BASE_ADDR + 0x006A)
-#define KDATA_KERNEL_ISR_BRCR (KDATA_BASE_ADDR + 0x006B)
-#define KDATA_KERNEL_ISR_PASR (KDATA_BASE_ADDR + 0x006C)
-#define KDATA_KERNEL_ISR_PAER (KDATA_BASE_ADDR + 0x006D)
-
-#define KDATA_CLIENT_SCRATCH0 (KDATA_BASE_ADDR + 0x006E)
-#define KDATA_CLIENT_SCRATCH1 (KDATA_BASE_ADDR + 0x006F)
-#define KDATA_KERNEL_SCRATCH (KDATA_BASE_ADDR + 0x0070)
-#define KDATA_KERNEL_ISR_SCRATCH (KDATA_BASE_ADDR + 0x0071)
-
-#define KDATA_OUEUE_LEFT (KDATA_BASE_ADDR + 0x0072)
-#define KDATA_QUEUE_RIGHT (KDATA_BASE_ADDR + 0x0073)
-
-#define KDATA_ADC1_REQUEST (KDATA_BASE_ADDR + 0x0074)
-#define KDATA_ADC2_REQUEST (KDATA_BASE_ADDR + 0x0075)
-#define KDATA_CD_REQUEST (KDATA_BASE_ADDR + 0x0076)
-#define KDATA_MIC_REQUEST (KDATA_BASE_ADDR + 0x0077)
-
-#define KDATA_ADC1_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0078)
-#define KDATA_ADC2_MIXER_REQUEST (KDATA_BASE_ADDR + 0x0079)
-#define KDATA_CD_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007A)
-#define KDATA_MIC_MIXER_REQUEST (KDATA_BASE_ADDR + 0x007B)
-#define KDATA_MIC_SYNC_COUNTER (KDATA_BASE_ADDR + 0x007C)
-
-/*
- * second 'segment' (?) reserved for mixer
- * buffers..
- */
-
-#define KDATA_MIXER_WORD0 (KDATA_BASE_ADDR2 + 0x0000)
-#define KDATA_MIXER_WORD1 (KDATA_BASE_ADDR2 + 0x0001)
-#define KDATA_MIXER_WORD2 (KDATA_BASE_ADDR2 + 0x0002)
-#define KDATA_MIXER_WORD3 (KDATA_BASE_ADDR2 + 0x0003)
-#define KDATA_MIXER_WORD4 (KDATA_BASE_ADDR2 + 0x0004)
-#define KDATA_MIXER_WORD5 (KDATA_BASE_ADDR2 + 0x0005)
-#define KDATA_MIXER_WORD6 (KDATA_BASE_ADDR2 + 0x0006)
-#define KDATA_MIXER_WORD7 (KDATA_BASE_ADDR2 + 0x0007)
-#define KDATA_MIXER_WORD8 (KDATA_BASE_ADDR2 + 0x0008)
-#define KDATA_MIXER_WORD9 (KDATA_BASE_ADDR2 + 0x0009)
-#define KDATA_MIXER_WORDA (KDATA_BASE_ADDR2 + 0x000A)
-#define KDATA_MIXER_WORDB (KDATA_BASE_ADDR2 + 0x000B)
-#define KDATA_MIXER_WORDC (KDATA_BASE_ADDR2 + 0x000C)
-#define KDATA_MIXER_WORDD (KDATA_BASE_ADDR2 + 0x000D)
-#define KDATA_MIXER_WORDE (KDATA_BASE_ADDR2 + 0x000E)
-#define KDATA_MIXER_WORDF (KDATA_BASE_ADDR2 + 0x000F)
-
-#define KDATA_MIXER_XFER0 (KDATA_BASE_ADDR2 + 0x0010)
-#define KDATA_MIXER_XFER1 (KDATA_BASE_ADDR2 + 0x0011)
-#define KDATA_MIXER_XFER2 (KDATA_BASE_ADDR2 + 0x0012)
-#define KDATA_MIXER_XFER3 (KDATA_BASE_ADDR2 + 0x0013)
-#define KDATA_MIXER_XFER4 (KDATA_BASE_ADDR2 + 0x0014)
-#define KDATA_MIXER_XFER5 (KDATA_BASE_ADDR2 + 0x0015)
-#define KDATA_MIXER_XFER6 (KDATA_BASE_ADDR2 + 0x0016)
-#define KDATA_MIXER_XFER7 (KDATA_BASE_ADDR2 + 0x0017)
-#define KDATA_MIXER_XFER8 (KDATA_BASE_ADDR2 + 0x0018)
-#define KDATA_MIXER_XFER9 (KDATA_BASE_ADDR2 + 0x0019)
-#define KDATA_MIXER_XFER_ENDMARK (KDATA_BASE_ADDR2 + 0x001A)
-
-#define KDATA_MIXER_TASK_NUMBER (KDATA_BASE_ADDR2 + 0x001B)
-#define KDATA_CURRENT_MIXER (KDATA_BASE_ADDR2 + 0x001C)
-#define KDATA_MIXER_ACTIVE (KDATA_BASE_ADDR2 + 0x001D)
-#define KDATA_MIXER_BANK_STATUS (KDATA_BASE_ADDR2 + 0x001E)
-#define KDATA_DAC_LEFT_VOLUME (KDATA_BASE_ADDR2 + 0x001F)
-#define KDATA_DAC_RIGHT_VOLUME (KDATA_BASE_ADDR2 + 0x0020)
-
-#define MAX_INSTANCE_MINISRC (KDATA_INSTANCE_MINISRC_ENDMARK - KDATA_INSTANCE0_MINISRC)
-#define MAX_VIRTUAL_DMA_CHANNELS (KDATA_DMA_XFER_ENDMARK - KDATA_DMA_XFER0)
-#define MAX_VIRTUAL_MIXER_CHANNELS (KDATA_MIXER_XFER_ENDMARK - KDATA_MIXER_XFER0)
-#define MAX_VIRTUAL_ADC1_CHANNELS (KDATA_ADC1_XFER_ENDMARK - KDATA_ADC1_XFER0)
-
-/*
- * client data area offsets
- */
-#define CDATA_INSTANCE_READY 0x00
-
-#define CDATA_HOST_SRC_ADDRL 0x01
-#define CDATA_HOST_SRC_ADDRH 0x02
-#define CDATA_HOST_SRC_END_PLUS_1L 0x03
-#define CDATA_HOST_SRC_END_PLUS_1H 0x04
-#define CDATA_HOST_SRC_CURRENTL 0x05
-#define CDATA_HOST_SRC_CURRENTH 0x06
-
-#define CDATA_IN_BUF_CONNECT 0x07
-#define CDATA_OUT_BUF_CONNECT 0x08
-
-#define CDATA_IN_BUF_BEGIN 0x09
-#define CDATA_IN_BUF_END_PLUS_1 0x0A
-#define CDATA_IN_BUF_HEAD 0x0B
-#define CDATA_IN_BUF_TAIL 0x0C
-#define CDATA_OUT_BUF_BEGIN 0x0D
-#define CDATA_OUT_BUF_END_PLUS_1 0x0E
-#define CDATA_OUT_BUF_HEAD 0x0F
-#define CDATA_OUT_BUF_TAIL 0x10
-
-#define CDATA_DMA_CONTROL 0x11
-#define CDATA_RESERVED 0x12
-
-#define CDATA_FREQUENCY 0x13
-#define CDATA_LEFT_VOLUME 0x14
-#define CDATA_RIGHT_VOLUME 0x15
-#define CDATA_LEFT_SUR_VOL 0x16
-#define CDATA_RIGHT_SUR_VOL 0x17
-
-#define CDATA_HEADER_LEN 0x18
-
-#define SRC3_DIRECTION_OFFSET CDATA_HEADER_LEN
-#define SRC3_MODE_OFFSET (CDATA_HEADER_LEN + 1)
-#define SRC3_WORD_LENGTH_OFFSET (CDATA_HEADER_LEN + 2)
-#define SRC3_PARAMETER_OFFSET (CDATA_HEADER_LEN + 3)
-#define SRC3_COEFF_ADDR_OFFSET (CDATA_HEADER_LEN + 8)
-#define SRC3_FILTAP_ADDR_OFFSET (CDATA_HEADER_LEN + 10)
-#define SRC3_TEMP_INBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 16)
-#define SRC3_TEMP_OUTBUF_ADDR_OFFSET (CDATA_HEADER_LEN + 17)
-
-#define MINISRC_IN_BUFFER_SIZE ( 0x50 * 2 )
-#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
-#define MINISRC_OUT_BUFFER_SIZE ( 0x50 * 2 * 2)
-#define MINISRC_TMP_BUFFER_SIZE ( 112 + ( MINISRC_BIQUAD_STAGE * 3 + 4 ) * 2 * 2 )
-#define MINISRC_BIQUAD_STAGE 2
-#define MINISRC_COEF_LOC 0X175
-
-#define DMACONTROL_BLOCK_MASK 0x000F
-#define DMAC_BLOCK0_SELECTOR 0x0000
-#define DMAC_BLOCK1_SELECTOR 0x0001
-#define DMAC_BLOCK2_SELECTOR 0x0002
-#define DMAC_BLOCK3_SELECTOR 0x0003
-#define DMAC_BLOCK4_SELECTOR 0x0004
-#define DMAC_BLOCK5_SELECTOR 0x0005
-#define DMAC_BLOCK6_SELECTOR 0x0006
-#define DMAC_BLOCK7_SELECTOR 0x0007
-#define DMAC_BLOCK8_SELECTOR 0x0008
-#define DMAC_BLOCK9_SELECTOR 0x0009
-#define DMAC_BLOCKA_SELECTOR 0x000A
-#define DMAC_BLOCKB_SELECTOR 0x000B
-#define DMAC_BLOCKC_SELECTOR 0x000C
-#define DMAC_BLOCKD_SELECTOR 0x000D
-#define DMAC_BLOCKE_SELECTOR 0x000E
-#define DMAC_BLOCKF_SELECTOR 0x000F
-#define DMACONTROL_PAGE_MASK 0x00F0
-#define DMAC_PAGE0_SELECTOR 0x0030
-#define DMAC_PAGE1_SELECTOR 0x0020
-#define DMAC_PAGE2_SELECTOR 0x0010
-#define DMAC_PAGE3_SELECTOR 0x0000
-#define DMACONTROL_AUTOREPEAT 0x1000
-#define DMACONTROL_STOPPED 0x2000
-#define DMACONTROL_DIRECTION 0x0100
-
-
-/*
- * DSP Code images
- */
-
-static u16 assp_kernel_image[] = {
- 0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4,
- 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
- 0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4,
- 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x0063, 0x7980, 0x006B, 0x7980, 0x03B4, 0x7980, 0x03B4,
- 0xBF80, 0x2C7C, 0x8806, 0x8804, 0xBE40, 0xBC20, 0xAE09, 0x1000, 0xAE0A, 0x0001, 0x6938, 0xEB08,
- 0x0053, 0x695A, 0xEB08, 0x00D6, 0x0009, 0x8B88, 0x6980, 0xE388, 0x0036, 0xBE30, 0xBC20, 0x6909,
- 0xB801, 0x9009, 0xBE41, 0xBE41, 0x6928, 0xEB88, 0x0078, 0xBE41, 0xBE40, 0x7980, 0x0038, 0xBE41,
- 0xBE41, 0x903A, 0x6938, 0xE308, 0x0056, 0x903A, 0xBE41, 0xBE40, 0xEF00, 0x903A, 0x6939, 0xE308,
- 0x005E, 0x903A, 0xEF00, 0x690B, 0x660C, 0xEF8C, 0x690A, 0x660C, 0x620B, 0x6609, 0xEF00, 0x6910,
- 0x660F, 0xEF04, 0xE388, 0x0075, 0x690E, 0x660F, 0x6210, 0x660D, 0xEF00, 0x690E, 0x660D, 0xEF00,
- 0xAE70, 0x0001, 0xBC20, 0xAE27, 0x0001, 0x6939, 0xEB08, 0x005D, 0x6926, 0xB801, 0x9026, 0x0026,
- 0x8B88, 0x6980, 0xE388, 0x00CB, 0x9028, 0x0D28, 0x4211, 0xE100, 0x007A, 0x4711, 0xE100, 0x00A0,
- 0x7A80, 0x0063, 0xB811, 0x660A, 0x6209, 0xE304, 0x007A, 0x0C0B, 0x4005, 0x100A, 0xBA01, 0x9012,
- 0x0C12, 0x4002, 0x7980, 0x00AF, 0x7A80, 0x006B, 0xBE02, 0x620E, 0x660D, 0xBA10, 0xE344, 0x007A,
- 0x0C10, 0x4005, 0x100E, 0xBA01, 0x9012, 0x0C12, 0x4002, 0x1003, 0xBA02, 0x9012, 0x0C12, 0x4000,
- 0x1003, 0xE388, 0x00BA, 0x1004, 0x7980, 0x00BC, 0x1004, 0xBA01, 0x9012, 0x0C12, 0x4001, 0x0C05,
- 0x4003, 0x0C06, 0x4004, 0x1011, 0xBFB0, 0x01FF, 0x9012, 0x0C12, 0x4006, 0xBC20, 0xEF00, 0xAE26,
- 0x1028, 0x6970, 0xBFD0, 0x0001, 0x9070, 0xE388, 0x007A, 0xAE28, 0x0000, 0xEF00, 0xAE70, 0x0300,
- 0x0C70, 0xB00C, 0xAE5A, 0x0000, 0xEF00, 0x7A80, 0x038A, 0x697F, 0xB801, 0x907F, 0x0056, 0x8B88,
- 0x0CA0, 0xB008, 0xAF71, 0xB000, 0x4E71, 0xE200, 0x00F3, 0xAE56, 0x1057, 0x0056, 0x0CA0, 0xB008,
- 0x8056, 0x7980, 0x03A1, 0x0810, 0xBFA0, 0x1059, 0xE304, 0x03A1, 0x8056, 0x7980, 0x03A1, 0x7A80,
- 0x038A, 0xBF01, 0xBE43, 0xBE59, 0x907C, 0x6937, 0xE388, 0x010D, 0xBA01, 0xE308, 0x010C, 0xAE71,
- 0x0004, 0x0C71, 0x5000, 0x6936, 0x9037, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80, 0xBF0A,
- 0x0560, 0xF500, 0xBF0A, 0x0520, 0xB900, 0xBB17, 0x90A0, 0x6917, 0xE388, 0x0148, 0x0D17, 0xE100,
- 0x0127, 0xBF0C, 0x0578, 0xBF0D, 0x057C, 0x7980, 0x012B, 0xBF0C, 0x0538, 0xBF0D, 0x053C, 0x6900,
- 0xE308, 0x0135, 0x8B8C, 0xBE59, 0xBB07, 0x90A0, 0xBC20, 0x7980, 0x0157, 0x030C, 0x8B8B, 0xB903,
- 0x8809, 0xBEC6, 0x013E, 0x69AC, 0x90AB, 0x69AD, 0x90AB, 0x0813, 0x660A, 0xE344, 0x0144, 0x0309,
- 0x830C, 0xBC20, 0x7980, 0x0157, 0x6955, 0xE388, 0x0157, 0x7C38, 0xBF0B, 0x0578, 0xF500, 0xBF0B,
- 0x0538, 0xB907, 0x8809, 0xBEC6, 0x0156, 0x10AB, 0x90AA, 0x6974, 0xE388, 0x0163, 0xAE72, 0x0540,
- 0xF500, 0xAE72, 0x0500, 0xAE61, 0x103B, 0x7A80, 0x02F6, 0x6978, 0xE388, 0x0182, 0x8B8C, 0xBF0C,
- 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA20, 0x8812, 0x733D, 0x7A80, 0x0380, 0x733E, 0x7A80, 0x0380,
- 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA2C, 0x8812, 0x733F, 0x7A80, 0x0380, 0x7340,
- 0x7A80, 0x0380, 0x6975, 0xE388, 0x018E, 0xAE72, 0x0548, 0xF500, 0xAE72, 0x0508, 0xAE61, 0x1041,
- 0x7A80, 0x02F6, 0x6979, 0xE388, 0x01AD, 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA18,
- 0x8812, 0x7343, 0x7A80, 0x0380, 0x7344, 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40,
- 0x0814, 0xBA24, 0x8812, 0x7345, 0x7A80, 0x0380, 0x7346, 0x7A80, 0x0380, 0x6976, 0xE388, 0x01B9,
- 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x1047, 0x7A80, 0x02F6, 0x697A, 0xE388, 0x01D8,
- 0x8B8C, 0xBF0C, 0x0560, 0xE500, 0x7C40, 0x0814, 0xBA08, 0x8812, 0x7349, 0x7A80, 0x0380, 0x734A,
- 0x7A80, 0x0380, 0x8B8C, 0xBF0C, 0x056C, 0xE500, 0x7C40, 0x0814, 0xBA14, 0x8812, 0x734B, 0x7A80,
- 0x0380, 0x734C, 0x7A80, 0x0380, 0xBC21, 0xAE1C, 0x1090, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40,
- 0x0812, 0xB804, 0x8813, 0x8B8D, 0xBF0D, 0x056C, 0xE500, 0x7C40, 0x0815, 0xB804, 0x8811, 0x7A80,
- 0x034A, 0x8B8A, 0xBF0A, 0x0560, 0xE500, 0x7C40, 0x731F, 0xB903, 0x8809, 0xBEC6, 0x01F9, 0x548A,
- 0xBE03, 0x98A0, 0x7320, 0xB903, 0x8809, 0xBEC6, 0x0201, 0x548A, 0xBE03, 0x98A0, 0x1F20, 0x2F1F,
- 0x9826, 0xBC20, 0x6935, 0xE388, 0x03A1, 0x6933, 0xB801, 0x9033, 0xBFA0, 0x02EE, 0xE308, 0x03A1,
- 0x9033, 0xBF00, 0x6951, 0xE388, 0x021F, 0x7334, 0xBE80, 0x5760, 0xBE03, 0x9F7E, 0xBE59, 0x9034,
- 0x697E, 0x0D51, 0x9013, 0xBC20, 0x695C, 0xE388, 0x03A1, 0x735E, 0xBE80, 0x5760, 0xBE03, 0x9F7E,
- 0xBE59, 0x905E, 0x697E, 0x0D5C, 0x9013, 0x7980, 0x03A1, 0x7A80, 0x038A, 0xBF01, 0xBE43, 0x6977,
- 0xE388, 0x024E, 0xAE61, 0x104D, 0x0061, 0x8B88, 0x6980, 0xE388, 0x024E, 0x9071, 0x0D71, 0x000B,
- 0xAFA0, 0x8010, 0xAFA0, 0x8010, 0x0810, 0x660A, 0xE308, 0x0249, 0x0009, 0x0810, 0x660C, 0xE388,
- 0x024E, 0x800B, 0xBC20, 0x697B, 0xE388, 0x03A1, 0xBF0A, 0x109E, 0x8B8A, 0xAF80, 0x8014, 0x4C80,
- 0xE100, 0x0266, 0x697C, 0xBF90, 0x0560, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0564, 0x9073, 0x0473,
- 0x7980, 0x0270, 0x697C, 0xBF90, 0x0520, 0x9072, 0x0372, 0x697C, 0xBF90, 0x0524, 0x9073, 0x0473,
- 0x697C, 0xB801, 0x907C, 0xBF0A, 0x10FD, 0x8B8A, 0xAF80, 0x8010, 0x734F, 0x548A, 0xBE03, 0x9880,
- 0xBC21, 0x7326, 0x548B, 0xBE03, 0x618B, 0x988C, 0xBE03, 0x6180, 0x9880, 0x7980, 0x03A1, 0x7A80,
- 0x038A, 0x0D28, 0x4711, 0xE100, 0x02BE, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388, 0x02B6,
- 0xBFA0, 0x0800, 0xE388, 0x02B2, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02A3, 0x6909,
- 0x900B, 0x7980, 0x02A5, 0xAF0B, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100, 0x02ED,
- 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x6909, 0x900B, 0x7980, 0x02B8, 0xAF0B, 0x4005,
- 0xAF05, 0x4003, 0xAF06, 0x4004, 0x7980, 0x02ED, 0xAF12, 0x4006, 0x6912, 0xBFB0, 0x0C00, 0xE388,
- 0x02E7, 0xBFA0, 0x0800, 0xE388, 0x02E3, 0x6912, 0xBFB0, 0x0C00, 0xBFA0, 0x0400, 0xE388, 0x02D4,
- 0x690D, 0x9010, 0x7980, 0x02D6, 0xAF10, 0x4005, 0x6901, 0x9005, 0x6902, 0x9006, 0x4311, 0xE100,
- 0x02ED, 0x6911, 0xBFC0, 0x2000, 0x9011, 0x7980, 0x02ED, 0x690D, 0x9010, 0x7980, 0x02E9, 0xAF10,
- 0x4005, 0xAF05, 0x4003, 0xAF06, 0x4004, 0xBC20, 0x6970, 0x9071, 0x7A80, 0x0078, 0x6971, 0x9070,
- 0x7980, 0x03A1, 0xBC20, 0x0361, 0x8B8B, 0x6980, 0xEF88, 0x0272, 0x0372, 0x7804, 0x9071, 0x0D71,
- 0x8B8A, 0x000B, 0xB903, 0x8809, 0xBEC6, 0x0309, 0x69A8, 0x90AB, 0x69A8, 0x90AA, 0x0810, 0x660A,
- 0xE344, 0x030F, 0x0009, 0x0810, 0x660C, 0xE388, 0x0314, 0x800B, 0xBC20, 0x6961, 0xB801, 0x9061,
- 0x7980, 0x02F7, 0x7A80, 0x038A, 0x5D35, 0x0001, 0x6934, 0xB801, 0x9034, 0xBF0A, 0x109E, 0x8B8A,
- 0xAF80, 0x8014, 0x4880, 0xAE72, 0x0550, 0xF500, 0xAE72, 0x0510, 0xAE61, 0x1051, 0x7A80, 0x02F6,
- 0x7980, 0x03A1, 0x7A80, 0x038A, 0x5D35, 0x0002, 0x695E, 0xB801, 0x905E, 0xBF0A, 0x109E, 0x8B8A,
- 0xAF80, 0x8014, 0x4780, 0xAE72, 0x0558, 0xF500, 0xAE72, 0x0518, 0xAE61, 0x105C, 0x7A80, 0x02F6,
- 0x7980, 0x03A1, 0x001C, 0x8B88, 0x6980, 0xEF88, 0x901D, 0x0D1D, 0x100F, 0x6610, 0xE38C, 0x0358,
- 0x690E, 0x6610, 0x620F, 0x660D, 0xBA0F, 0xE301, 0x037A, 0x0410, 0x8B8A, 0xB903, 0x8809, 0xBEC6,
- 0x036C, 0x6A8C, 0x61AA, 0x98AB, 0x6A8C, 0x61AB, 0x98AD, 0x6A8C, 0x61AD, 0x98A9, 0x6A8C, 0x61A9,
- 0x98AA, 0x7C04, 0x8B8B, 0x7C04, 0x8B8D, 0x7C04, 0x8B89, 0x7C04, 0x0814, 0x660E, 0xE308, 0x0379,
- 0x040D, 0x8410, 0xBC21, 0x691C, 0xB801, 0x901C, 0x7980, 0x034A, 0xB903, 0x8809, 0x8B8A, 0xBEC6,
- 0x0388, 0x54AC, 0xBE03, 0x618C, 0x98AA, 0xEF00, 0xBC20, 0xBE46, 0x0809, 0x906B, 0x080A, 0x906C,
- 0x080B, 0x906D, 0x081A, 0x9062, 0x081B, 0x9063, 0x081E, 0x9064, 0xBE59, 0x881E, 0x8065, 0x8166,
- 0x8267, 0x8368, 0x8469, 0x856A, 0xEF00, 0xBC20, 0x696B, 0x8809, 0x696C, 0x880A, 0x696D, 0x880B,
- 0x6962, 0x881A, 0x6963, 0x881B, 0x6964, 0x881E, 0x0065, 0x0166, 0x0267, 0x0368, 0x0469, 0x056A,
- 0xBE3A,
-};
-
-/*
- * Mini sample rate converter code image
- * that is to be loaded at 0x400 on the DSP.
- */
-static u16 assp_minisrc_image[] = {
-
- 0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412,
- 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41,
- 0x7A80, 0x002A, 0xBE40, 0x3029, 0xEFCC, 0xBE41, 0x7A80, 0x0028, 0xBE40, 0x3028, 0xEFCC, 0x6907,
- 0xE308, 0x042A, 0x6909, 0x902C, 0x7980, 0x042C, 0x690D, 0x902C, 0x1009, 0x881A, 0x100A, 0xBA01,
- 0x881B, 0x100D, 0x881C, 0x100E, 0xBA01, 0x881D, 0xBF80, 0x00ED, 0x881E, 0x050C, 0x0124, 0xB904,
- 0x9027, 0x6918, 0xE308, 0x04B3, 0x902D, 0x6913, 0xBFA0, 0x7598, 0xF704, 0xAE2D, 0x00FF, 0x8B8D,
- 0x6919, 0xE308, 0x0463, 0x691A, 0xE308, 0x0456, 0xB907, 0x8809, 0xBEC6, 0x0453, 0x10A9, 0x90AD,
- 0x7980, 0x047C, 0xB903, 0x8809, 0xBEC6, 0x0460, 0x1889, 0x6C22, 0x90AD, 0x10A9, 0x6E23, 0x6C22,
- 0x90AD, 0x7980, 0x047C, 0x101A, 0xE308, 0x046F, 0xB903, 0x8809, 0xBEC6, 0x046C, 0x10A9, 0x90A0,
- 0x90AD, 0x7980, 0x047C, 0xB901, 0x8809, 0xBEC6, 0x047B, 0x1889, 0x6C22, 0x90A0, 0x90AD, 0x10A9,
- 0x6E23, 0x6C22, 0x90A0, 0x90AD, 0x692D, 0xE308, 0x049C, 0x0124, 0xB703, 0xB902, 0x8818, 0x8B89,
- 0x022C, 0x108A, 0x7C04, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99A0,
- 0x108A, 0x90A0, 0x692B, 0x881F, 0x7E80, 0x055B, 0x692A, 0x8809, 0x8B89, 0x99AF, 0x7B99, 0x0484,
- 0x0124, 0x060F, 0x101B, 0x2013, 0x901B, 0xBFA0, 0x7FFF, 0xE344, 0x04AC, 0x901B, 0x8B89, 0x7A80,
- 0x051A, 0x6927, 0xBA01, 0x9027, 0x7A80, 0x0523, 0x6927, 0xE308, 0x049E, 0x7980, 0x050F, 0x0624,
- 0x1026, 0x2013, 0x9026, 0xBFA0, 0x7FFF, 0xE304, 0x04C0, 0x8B8D, 0x7A80, 0x051A, 0x7980, 0x04B4,
- 0x9026, 0x1013, 0x3026, 0x901B, 0x8B8D, 0x7A80, 0x051A, 0x7A80, 0x0523, 0x1027, 0xBA01, 0x9027,
- 0xE308, 0x04B4, 0x0124, 0x060F, 0x8B89, 0x691A, 0xE308, 0x04EA, 0x6919, 0xE388, 0x04E0, 0xB903,
- 0x8809, 0xBEC6, 0x04DD, 0x1FA0, 0x2FAE, 0x98A9, 0x7980, 0x050F, 0xB901, 0x8818, 0xB907, 0x8809,
- 0xBEC6, 0x04E7, 0x10EE, 0x90A9, 0x7980, 0x050F, 0x6919, 0xE308, 0x04FE, 0xB903, 0x8809, 0xBE46,
- 0xBEC6, 0x04FA, 0x17A0, 0xBE1E, 0x1FAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0xBE47,
- 0x7980, 0x050F, 0xB901, 0x8809, 0xBEC6, 0x050E, 0x16A0, 0x26A0, 0xBFB7, 0xFF00, 0xBE1E, 0x1EA0,
- 0x2EAE, 0xBFBF, 0xFF00, 0xBE13, 0xBFDF, 0x8080, 0x99A9, 0x850C, 0x860F, 0x6907, 0xE388, 0x0516,
- 0x0D07, 0x8510, 0xBE59, 0x881E, 0xBE4A, 0xEF00, 0x101E, 0x901C, 0x101F, 0x901D, 0x10A0, 0x901E,
- 0x10A0, 0x901F, 0xEF00, 0x101E, 0x301C, 0x9020, 0x731B, 0x5420, 0xBE03, 0x9825, 0x1025, 0x201C,
- 0x9025, 0x7325, 0x5414, 0xBE03, 0x8B8E, 0x9880, 0x692F, 0xE388, 0x0539, 0xBE59, 0xBB07, 0x6180,
- 0x9880, 0x8BA0, 0x101F, 0x301D, 0x9021, 0x731B, 0x5421, 0xBE03, 0x982E, 0x102E, 0x201D, 0x902E,
- 0x732E, 0x5415, 0xBE03, 0x9880, 0x692F, 0xE388, 0x054F, 0xBE59, 0xBB07, 0x6180, 0x9880, 0x8BA0,
- 0x6918, 0xEF08, 0x7325, 0x5416, 0xBE03, 0x98A0, 0x732E, 0x5417, 0xBE03, 0x98A0, 0xEF00, 0x8BA0,
- 0xBEC6, 0x056B, 0xBE59, 0xBB04, 0xAA90, 0xBE04, 0xBE1E, 0x99E0, 0x8BE0, 0x69A0, 0x90D0, 0x69A0,
- 0x90D0, 0x081F, 0xB805, 0x881F, 0x8B90, 0x69A0, 0x90D0, 0x69A0, 0x9090, 0x8BD0, 0x8BD8, 0xBE1F,
- 0xEF00, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
- 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
-};
-
diff --git a/sound/oss/maui.c b/sound/oss/maui.c
deleted file mode 100644
index 05cf194eda6b..000000000000
--- a/sound/oss/maui.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- * sound/maui.c
- *
- * The low level driver for Turtle Beach Maui and Tropez.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * Alan Cox General clean up, use kernel IRQ
- * system
- * Christoph Hellwig Adapted to module_init/module_exit
- * Bartlomiej Zolnierkiewicz
- * Added __init to download_code()
- *
- * Status:
- * Andrew J. Kroll Tested 06/01/1999 with:
- * * OSWF.MOT File Version: 1.15
- * * OSWF.MOT File Dated: 09/12/94
- * * Older versions will cause problems.
- */
-
-#include <linux/interrupt.h>
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#define USE_SEQ_MACROS
-#define USE_SIMPLE_MACROS
-
-#include "sound_config.h"
-#include "sound_firmware.h"
-
-#include "mpu401.h"
-
-static int maui_base = 0x330;
-
-static volatile int irq_ok;
-static int *maui_osp;
-
-#define HOST_DATA_PORT (maui_base + 2)
-#define HOST_STAT_PORT (maui_base + 3)
-#define HOST_CTRL_PORT (maui_base + 3)
-
-#define STAT_TX_INTR 0x40
-#define STAT_TX_AVAIL 0x20
-#define STAT_TX_IENA 0x10
-#define STAT_RX_INTR 0x04
-#define STAT_RX_AVAIL 0x02
-#define STAT_RX_IENA 0x01
-
-static int (*orig_load_patch)(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag) = NULL;
-
-#include "maui_boot.h"
-
-static int maui_wait(int mask)
-{
- int i;
-
- /*
- * Perform a short initial wait without sleeping
- */
-
- for (i = 0; i < 100; i++)
- if (inb(HOST_STAT_PORT) & mask)
- return 1;
-
- /*
- * Wait up to 15 seconds with sleeping
- */
-
- for (i = 0; i < 150; i++) {
- if (inb(HOST_STAT_PORT) & mask)
- return 1;
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ / 10);
- if (signal_pending(current))
- return 0;
- }
- return 0;
-}
-
-static int maui_read(void)
-{
- if (maui_wait(STAT_RX_AVAIL))
- return inb(HOST_DATA_PORT);
- return -1;
-}
-
-static int maui_write(unsigned char data)
-{
- if (maui_wait(STAT_TX_AVAIL)) {
- outb((data), HOST_DATA_PORT);
- return 1;
- }
- printk(KERN_WARNING "Maui: Write timeout\n");
- return 0;
-}
-
-static irqreturn_t mauiintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
- irq_ok = 1;
- return IRQ_HANDLED;
-}
-
-static int __init download_code(void)
-{
- int i, lines = 0;
- int eol_seen = 0, done = 0;
- int skip = 1;
-
- printk(KERN_INFO "Code download (%d bytes): ", maui_osLen);
-
- for (i = 0; i < maui_osLen; i++) {
- if (maui_os[i] != '\r') {
- if (!skip || (maui_os[i] == 'S' && (i == 0 || maui_os[i - 1] == '\n'))) {
- skip = 0;
-
- if (maui_os[i] == '\n')
- eol_seen = skip = 1;
- else if (maui_os[i] == 'S') {
- if (maui_os[i + 1] == '8')
- done = 1;
- if (!maui_write(0xF1))
- goto failure;
- if (!maui_write('S'))
- goto failure;
- } else {
- if (!maui_write(maui_os[i]))
- goto failure;
- }
-
- if (eol_seen) {
- int c = 0;
- int n;
-
- eol_seen = 0;
-
- for (n = 0; n < 2; n++) {
- if (maui_wait(STAT_RX_AVAIL)) {
- c = inb(HOST_DATA_PORT);
- break;
- }
- }
- if (c != 0x80) {
- printk("Download not acknowledged\n");
- return 0;
- }
- else if (!(lines++ % 10))
- printk(".");
-
- if (done) {
- printk("\n");
- printk(KERN_INFO "Download complete\n");
- return 1;
- }
- }
- }
- }
- }
-
-failure:
- printk("\n");
- printk(KERN_ERR "Download failed!!!\n");
- return 0;
-}
-
-static int __init maui_init(int irq)
-{
- unsigned char bits;
-
- switch (irq) {
- case 9:
- bits = 0x00;
- break;
- case 5:
- bits = 0x08;
- break;
- case 12:
- bits = 0x10;
- break;
- case 15:
- bits = 0x18;
- break;
-
- default:
- printk(KERN_ERR "Maui: Invalid IRQ %d\n", irq);
- return 0;
- }
- outb((0x00), HOST_CTRL_PORT); /* Reset */
- outb((bits), HOST_DATA_PORT); /* Set the IRQ bits */
- outb((bits | 0x80), HOST_DATA_PORT); /* Set the IRQ bits again? */
- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
- outb((0xD0), HOST_CTRL_PORT); /* Cause interrupt */
-
-#ifdef CONFIG_SMP
- {
- int i;
- for (i = 0; i < 1000000 && !irq_ok; i++)
- ;
- if (!irq_ok)
- return 0;
- }
-#endif
- outb((0x80), HOST_CTRL_PORT); /* Leave reset */
-
- printk(KERN_INFO "Turtle Beach Maui initialization\n");
-
- if (!download_code())
- return 0;
-
- outb((0xE0), HOST_CTRL_PORT); /* Normal operation */
-
- /* Select mpu401 mode */
-
- maui_write(0xf0);
- maui_write(1);
- if (maui_read() != 0x80) {
- maui_write(0xf0);
- maui_write(1);
- if (maui_read() != 0x80)
- printk(KERN_ERR "Maui didn't acknowledge set HW mode command\n");
- }
- printk(KERN_INFO "Maui initialized OK\n");
- return 1;
-}
-
-static int maui_short_wait(int mask) {
- int i;
-
- for (i = 0; i < 1000; i++) {
- if (inb(HOST_STAT_PORT) & mask) {
- return 1;
- }
- }
- return 0;
-}
-
-static int maui_load_patch(int dev, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
-
- struct sysex_info header;
- unsigned long left, src_offs;
- int hdr_size = (unsigned long) &header.data[0] - (unsigned long) &header;
- int i;
-
- if (format == SYSEX_PATCH) /* Handled by midi_synth.c */
- return orig_load_patch(dev, format, addr, offs, count, pmgr_flag);
-
- if (format != MAUI_PATCH)
- {
- printk(KERN_WARNING "Maui: Unknown patch format\n");
- }
- if (count < hdr_size) {
-/* printk("Maui error: Patch header too short\n");*/
- return -EINVAL;
- }
- count -= hdr_size;
-
- /*
- * Copy the header from user space but ignore the first bytes which have
- * been transferred already.
- */
-
- if(copy_from_user(&((char *) &header)[offs], &(addr)[offs], hdr_size - offs))
- return -EFAULT;
-
- if (count < header.len) {
- printk(KERN_ERR "Maui warning: Host command record too short (%d<%d)\n", count, (int) header.len);
- header.len = count;
- }
- left = header.len;
- src_offs = 0;
-
- for (i = 0; i < left; i++) {
- unsigned char data;
-
- if(get_user(*(unsigned char *) &data, (unsigned char __user *) &((addr)[hdr_size + i])))
- return -EFAULT;
- if (i == 0 && !(data & 0x80))
- return -EINVAL;
-
- if (maui_write(data) == -1)
- return -EIO;
- }
-
- if ((i = maui_read()) != 0x80) {
- if (i != -1)
- printk("Maui: Error status %02x\n", i);
- return -EIO;
- }
- return 0;
-}
-
-static int __init probe_maui(struct address_info *hw_config)
-{
- struct resource *ports;
- int this_dev;
- int i;
- int tmp1, tmp2, ret;
-
- ports = request_region(hw_config->io_base, 2, "mpu401");
- if (!ports)
- return 0;
-
- if (!request_region(hw_config->io_base + 2, 6, "Maui"))
- goto out;
-
- maui_base = hw_config->io_base;
- maui_osp = hw_config->osp;
-
- if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0)
- goto out2;
-
- /*
- * Initialize the processor if necessary
- */
-
- if (maui_osLen > 0) {
- if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) ||
- !maui_write(0x9F) || /* Report firmware version */
- !maui_short_wait(STAT_RX_AVAIL) ||
- maui_read() == -1 || maui_read() == -1)
- if (!maui_init(hw_config->irq))
- goto out3;
- }
- if (!maui_write(0xCF)) /* Report hardware version */ {
- printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
- goto out3;
- }
- if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) {
- printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n");
- goto out3;
- }
- if (tmp1 == 0xff || tmp2 == 0xff)
- goto out3;
- printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2);
-
- if (!maui_write(0x9F)) /* Report firmware version */
- goto out3;
- if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1)
- goto out3;
-
- printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2);
-
- if (!maui_write(0x85)) /* Report free DRAM */
- goto out3;
- tmp1 = 0;
- for (i = 0; i < 4; i++) {
- tmp1 |= maui_read() << (7 * i);
- }
- printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024);
-
- for (i = 0; i < 1000; i++)
- if (probe_mpu401(hw_config, ports))
- break;
-
- ret = probe_mpu401(hw_config, ports);
- if (!ret)
- goto out3;
-
- conf_printf("Maui", hw_config);
-
- hw_config->irq *= -1;
- hw_config->name = "Maui";
- attach_mpu401(hw_config, THIS_MODULE);
-
- if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ {
- struct synth_operations *synth;
-
- this_dev = hw_config->slots[1];
-
- /*
- * Intercept patch loading calls so that they can be handled
- * by the Maui driver.
- */
-
- synth = midi_devs[this_dev]->converter;
- if (synth != NULL) {
- synth->id = "MAUI";
- orig_load_patch = synth->load_patch;
- synth->load_patch = &maui_load_patch;
- } else
- printk(KERN_ERR "Maui: Can't install patch loader\n");
- }
- return 1;
-
-out3:
- free_irq(hw_config->irq, NULL);
-out2:
- release_region(hw_config->io_base + 2, 6);
-out:
- release_region(hw_config->io_base, 2);
- return 0;
-}
-
-static void __exit unload_maui(struct address_info *hw_config)
-{
- int irq = hw_config->irq;
- release_region(hw_config->io_base + 2, 6);
- unload_mpu401(hw_config);
-
- if (irq < 0)
- irq = -irq;
- if (irq > 0)
- free_irq(irq, NULL);
-}
-
-static int fw_load;
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-
-/*
- * Install a Maui card. Needs mpu401 loaded already.
- */
-
-static int __init init_maui(void)
-{
- printk(KERN_INFO "Turtle beach Maui and Tropez driver, Copyright (C) by Hannu Savolainen 1993-1996\n");
-
- cfg.io_base = io;
- cfg.irq = irq;
-
- if (cfg.io_base == -1 || cfg.irq == -1) {
- printk(KERN_INFO "maui: irq and io must be set.\n");
- return -EINVAL;
- }
-
- if (maui_os == NULL) {
- fw_load = 1;
- maui_osLen = mod_firmware_load("/etc/sound/oswf.mot", (char **) &maui_os);
- }
- if (probe_maui(&cfg) == 0)
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit cleanup_maui(void)
-{
- if (fw_load && maui_os)
- vfree(maui_os);
- unload_maui(&cfg);
-}
-
-module_init(init_maui);
-module_exit(cleanup_maui);
-
-#ifndef MODULE
-static int __init setup_maui(char *str)
-{
- /* io, irq */
- int ints[3];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
-
- return 1;
-}
-
-__setup("maui=", setup_maui);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/midi_syms.c b/sound/oss/midi_syms.c
deleted file mode 100644
index 5b146ddf5725..000000000000
--- a/sound/oss/midi_syms.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Exported symbols for midi driver.
- */
-
-#include <linux/module.h>
-
-char midi_syms_symbol;
-
-#include "sound_config.h"
-#define _MIDI_SYNTH_C_
-#include "midi_synth.h"
-
-EXPORT_SYMBOL(do_midi_msg);
-EXPORT_SYMBOL(midi_synth_open);
-EXPORT_SYMBOL(midi_synth_close);
-EXPORT_SYMBOL(midi_synth_ioctl);
-EXPORT_SYMBOL(midi_synth_kill_note);
-EXPORT_SYMBOL(midi_synth_start_note);
-EXPORT_SYMBOL(midi_synth_set_instr);
-EXPORT_SYMBOL(midi_synth_reset);
-EXPORT_SYMBOL(midi_synth_hw_control);
-EXPORT_SYMBOL(midi_synth_aftertouch);
-EXPORT_SYMBOL(midi_synth_controller);
-EXPORT_SYMBOL(midi_synth_panning);
-EXPORT_SYMBOL(midi_synth_setup_voice);
-EXPORT_SYMBOL(midi_synth_send_sysex);
-EXPORT_SYMBOL(midi_synth_bender);
-EXPORT_SYMBOL(midi_synth_load_patch);
-EXPORT_SYMBOL(MIDIbuf_avail);
diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c
index 972edc62afd1..9e450988ed36 100644
--- a/sound/oss/midi_synth.c
+++ b/sound/oss/midi_synth.c
@@ -1,5 +1,5 @@
/*
- * sound/midi_synth.c
+ * sound/oss/midi_synth.c
*
* High level midi sequencer manager for dumb MIDI interfaces.
*/
@@ -84,6 +84,7 @@ do_midi_msg(int synthno, unsigned char *msg, int mlen)
;
}
}
+EXPORT_SYMBOL(do_midi_msg);
static void
midi_outc(int midi_dev, int data)
@@ -276,6 +277,7 @@ int midi_synth_ioctl(int dev, unsigned int cmd, void __user *arg)
return -EINVAL;
}
}
+EXPORT_SYMBOL(midi_synth_ioctl);
int
midi_synth_kill_note(int dev, int channel, int note, int velocity)
@@ -342,6 +344,7 @@ midi_synth_kill_note(int dev, int channel, int note, int velocity)
return 0;
}
+EXPORT_SYMBOL(midi_synth_kill_note);
int
midi_synth_set_instr(int dev, int channel, int instr_no)
@@ -364,6 +367,7 @@ midi_synth_set_instr(int dev, int channel, int instr_no)
return 0;
}
+EXPORT_SYMBOL(midi_synth_set_instr);
int
midi_synth_start_note(int dev, int channel, int note, int velocity)
@@ -405,6 +409,7 @@ midi_synth_start_note(int dev, int channel, int note, int velocity)
}
return 0;
}
+EXPORT_SYMBOL(midi_synth_start_note);
void
midi_synth_reset(int dev)
@@ -412,6 +417,7 @@ midi_synth_reset(int dev)
leave_sysex(dev);
}
+EXPORT_SYMBOL(midi_synth_reset);
int
midi_synth_open(int dev, int mode)
@@ -444,6 +450,7 @@ midi_synth_open(int dev, int mode)
return 1;
}
+EXPORT_SYMBOL(midi_synth_open);
void
midi_synth_close(int dev)
@@ -459,11 +466,13 @@ midi_synth_close(int dev)
midi_devs[orig_dev]->close(orig_dev);
}
+EXPORT_SYMBOL(midi_synth_close);
void
midi_synth_hw_control(int dev, unsigned char *event)
{
}
+EXPORT_SYMBOL(midi_synth_hw_control);
int
midi_synth_load_patch(int dev, int format, const char __user *addr,
@@ -542,11 +551,13 @@ midi_synth_load_patch(int dev, int format, const char __user *addr,
midi_outc(orig_dev, 0xf7);
return 0;
}
-
+EXPORT_SYMBOL(midi_synth_load_patch);
+
void midi_synth_panning(int dev, int channel, int pressure)
{
}
-
+EXPORT_SYMBOL(midi_synth_panning);
+
void midi_synth_aftertouch(int dev, int channel, int pressure)
{
int orig_dev = synth_devs[dev]->midi_dev;
@@ -576,6 +587,7 @@ void midi_synth_aftertouch(int dev, int channel, int pressure)
midi_outc(orig_dev, pressure);
}
+EXPORT_SYMBOL(midi_synth_aftertouch);
void
midi_synth_controller(int dev, int channel, int ctrl_num, int value)
@@ -604,6 +616,7 @@ midi_synth_controller(int dev, int channel, int ctrl_num, int value)
midi_outc(orig_dev, ctrl_num);
midi_outc(orig_dev, value & 0x7f);
}
+EXPORT_SYMBOL(midi_synth_controller);
void
midi_synth_bender(int dev, int channel, int value)
@@ -635,11 +648,13 @@ midi_synth_bender(int dev, int channel, int value)
midi_outc(orig_dev, value & 0x7f);
midi_outc(orig_dev, (value >> 7) & 0x7f);
}
+EXPORT_SYMBOL(midi_synth_bender);
void
midi_synth_setup_voice(int dev, int voice, int channel)
{
}
+EXPORT_SYMBOL(midi_synth_setup_voice);
int
midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
@@ -695,3 +710,5 @@ midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
return 0;
}
+EXPORT_SYMBOL(midi_synth_send_sysex);
+
diff --git a/sound/oss/midibuf.c b/sound/oss/midibuf.c
index 6982556ded56..a40be0cf1d97 100644
--- a/sound/oss/midibuf.c
+++ b/sound/oss/midibuf.c
@@ -1,5 +1,5 @@
/*
- * sound/midibuf.c
+ * sound/oss/midibuf.c
*
* Device file manager for /dev/midi#
*/
@@ -414,18 +414,11 @@ unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait)
}
-void MIDIbuf_init(void)
-{
- /* drag in midi_syms.o */
- {
- extern char midi_syms_symbol;
- midi_syms_symbol = 0;
- }
-}
-
int MIDIbuf_avail(int dev)
{
if (midi_in_buf[dev])
return DATA_AVAIL (midi_in_buf[dev]);
return 0;
}
+EXPORT_SYMBOL(MIDIbuf_avail);
+
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index 0aac54c68f01..e96220541971 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -1,5 +1,5 @@
/*
- * sound/mpu401.c
+ * sound/oss/mpu401.c
*
* The low level driver for Roland MPU-401 compatible Midi cards.
*/
@@ -432,19 +432,10 @@ static void mpu401_input_loop(struct mpu_config *devc)
devc->m_busy = 0;
}
-int intchk_mpu401(void *dev_id)
+static irqreturn_t mpuintr(int irq, void *dev_id)
{
struct mpu_config *devc;
- int dev = (int) dev_id;
-
- devc = &dev_conf[dev];
- return input_avail(devc);
-}
-
-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
- struct mpu_config *devc;
- int dev = (int) dev_id;
+ int dev = (int)(unsigned long) dev_id;
int handled = 0;
devc = &dev_conf[dev];
@@ -1761,8 +1752,6 @@ static int mpu_timer_init(int midi_dev)
EXPORT_SYMBOL(probe_mpu401);
EXPORT_SYMBOL(attach_mpu401);
EXPORT_SYMBOL(unload_mpu401);
-EXPORT_SYMBOL(intchk_mpu401);
-EXPORT_SYMBOL(mpuintr);
static struct address_info cfg;
diff --git a/sound/oss/mpu401.h b/sound/oss/mpu401.h
index bdc5bde641e6..0ad1e9ee74f7 100644
--- a/sound/oss/mpu401.h
+++ b/sound/oss/mpu401.h
@@ -3,12 +3,9 @@
int probe_uart401 (struct address_info *hw_config, struct module *owner);
void unload_uart401 (struct address_info *hw_config);
-irqreturn_t uart401intr (int irq, void *dev_id, struct pt_regs * dummy);
+irqreturn_t uart401intr (int irq, void *dev_id);
/* From mpu401.c */
int probe_mpu401(struct address_info *hw_config, struct resource *ports);
int attach_mpu401(struct address_info * hw_config, struct module *owner);
void unload_mpu401(struct address_info *hw_info);
-
-int intchk_mpu401(void *dev_id);
-irqreturn_t mpuintr(int irq, void *dev_id, struct pt_regs * dummy);
diff --git a/sound/oss/msnd_pinnacle.c b/sound/oss/msnd_pinnacle.c
index 6d7763dae895..d5146790f5e3 100644
--- a/sound/oss/msnd_pinnacle.c
+++ b/sound/oss/msnd_pinnacle.c
@@ -1087,7 +1087,7 @@ static __inline__ void eval_dsp_msg(register WORD wMessage)
}
}
-static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t intr(int irq, void *dev_id)
{
/* Send ack to DSP */
msnd_inb(dev.io + HP_RXL);
diff --git a/sound/oss/nec_vrc5477.c b/sound/oss/nec_vrc5477.c
index 6f7f2f0423e4..da9728e17727 100644
--- a/sound/oss/nec_vrc5477.c
+++ b/sound/oss/nec_vrc5477.c
@@ -848,7 +848,7 @@ static inline void vrc5477_ac97_dac_interrupt(struct vrc5477_ac97_state *s)
wake_up_interruptible(&dac->wait);
}
-static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t vrc5477_ac97_interrupt(int irq, void *dev_id)
{
struct vrc5477_ac97_state *s = (struct vrc5477_ac97_state *)dev_id;
u32 irqStatus;
diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h
index 21e07b5081f2..1dade9033995 100644
--- a/sound/oss/nm256.h
+++ b/sound/oss/nm256.h
@@ -115,7 +115,7 @@ struct nm256_info
int has_irq;
/* The card interrupt service routine. */
- irqreturn_t (*introutine) (int, void *, struct pt_regs *);
+ irq_handler_t introutine;
/* Current audio config, cached. */
struct sinfo {
diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
index 7760dddf2b32..44cd15505001 100644
--- a/sound/oss/nm256_audio.c
+++ b/sound/oss/nm256_audio.c
@@ -45,8 +45,8 @@ static struct audio_driver nm256_audio_driver;
static int nm256_grabInterrupt (struct nm256_info *card);
static int nm256_releaseInterrupt (struct nm256_info *card);
-static irqreturn_t nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy);
-static irqreturn_t nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy);
+static irqreturn_t nm256_interrupt (int irq, void *dev_id);
+static irqreturn_t nm256_interrupt_zx (int irq, void *dev_id);
/* These belong in linux/pci.h. */
#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
@@ -526,7 +526,7 @@ nm256_initHw (struct nm256_info *card)
*/
static irqreturn_t
-nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
+nm256_interrupt (int irq, void *dev_id)
{
struct nm256_info *card = (struct nm256_info *)dev_id;
u16 status;
@@ -629,7 +629,7 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
*/
static irqreturn_t
-nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy)
+nm256_interrupt_zx (int irq, void *dev_id)
{
struct nm256_info *card = (struct nm256_info *)dev_id;
u32 status;
diff --git a/sound/oss/opl3.c b/sound/oss/opl3.c
index a31734b7842f..4799bc77f987 100644
--- a/sound/oss/opl3.c
+++ b/sound/oss/opl3.c
@@ -1,5 +1,5 @@
/*
- * sound/opl3.c
+ * sound/oss/opl3.c
*
* A low level driver for Yamaha YM3812 and OPL-3 -chips
*
diff --git a/sound/oss/opl3sa.c b/sound/oss/opl3sa.c
deleted file mode 100644
index fe4907c6e8fc..000000000000
--- a/sound/oss/opl3sa.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * sound/opl3sa.c
- *
- * Low level driver for Yamaha YMF701B aka OPL3-SA chip
- *
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * Alan Cox Modularisation
- * Christoph Hellwig Adapted to module_init/module_exit
- * Arnaldo C. de Melo got rid of attach_uart401
- *
- * FIXME:
- * Check for install of mpu etc is wrong, should check result of the mss stuff
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/spinlock.h>
-
-#undef SB_OK
-
-#include "sound_config.h"
-
-#include "ad1848.h"
-#include "mpu401.h"
-
-#ifdef SB_OK
-#include "sb.h"
-static int sb_initialized;
-#endif
-
-static DEFINE_SPINLOCK(lock);
-
-static unsigned char opl3sa_read(int addr)
-{
- unsigned long flags;
- unsigned char tmp;
-
- spin_lock_irqsave(&lock,flags);
- outb((0x1d), 0xf86); /* password */
- outb(((unsigned char) addr), 0xf86); /* address */
- tmp = inb(0xf87); /* data */
- spin_unlock_irqrestore(&lock,flags);
-
- return tmp;
-}
-
-static void opl3sa_write(int addr, int data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
- outb((0x1d), 0xf86); /* password */
- outb(((unsigned char) addr), 0xf86); /* address */
- outb(((unsigned char) data), 0xf87); /* data */
- spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init opl3sa_detect(void)
-{
- int tmp;
-
- if (((tmp = opl3sa_read(0x01)) & 0xc4) != 0x04)
- {
- DDB(printk("OPL3-SA detect error 1 (%x)\n", opl3sa_read(0x01)));
- /* return 0; */
- }
-
- /*
- * Check that the password feature has any effect
- */
-
- if (inb(0xf87) == tmp)
- {
- DDB(printk("OPL3-SA detect failed 2 (%x/%x)\n", tmp, inb(0xf87)));
- return 0;
- }
- tmp = (opl3sa_read(0x04) & 0xe0) >> 5;
-
- if (tmp != 0 && tmp != 1)
- {
- DDB(printk("OPL3-SA detect failed 3 (%d)\n", tmp));
- return 0;
- }
- DDB(printk("OPL3-SA mode %x detected\n", tmp));
-
- opl3sa_write(0x01, 0x00); /* Disable MSS */
- opl3sa_write(0x02, 0x00); /* Disable SB */
- opl3sa_write(0x03, 0x00); /* Disable MPU */
-
- return 1;
-}
-
-/*
- * Probe and attach routines for the Windows Sound System mode of
- * OPL3-SA
- */
-
-static int __init probe_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
-{
- unsigned char tmp = 0x24; /* WSS enable */
-
- /*
- * Check if the IO port returns valid signature. The original MS Sound
- * system returns 0x04 while some cards (OPL3-SA for example)
- * return 0x00.
- */
-
- if (!opl3sa_detect())
- {
- printk(KERN_ERR "OSS: OPL3-SA chip not found\n");
- return 0;
- }
-
- switch (hw_config->io_base)
- {
- case 0x530:
- tmp |= 0x00;
- break;
- case 0xe80:
- tmp |= 0x08;
- break;
- case 0xf40:
- tmp |= 0x10;
- break;
- case 0x604:
- tmp |= 0x18;
- break;
- default:
- printk(KERN_ERR "OSS: Unsupported OPL3-SA/WSS base %x\n", hw_config->io_base);
- return 0;
- }
-
- opl3sa_write(0x01, tmp); /* WSS setup register */
-
- return probe_ms_sound(hw_config, ports);
-}
-
-static void __init attach_opl3sa_wss(struct address_info *hw_config, struct resource *ports)
-{
- int nm = num_mixers;
-
- /* FIXME */
- attach_ms_sound(hw_config, ports, THIS_MODULE);
- if (num_mixers > nm) /* A mixer was installed */
- {
- AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_CD);
- AD1848_REROUTE(SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH);
- AD1848_REROUTE(SOUND_MIXER_LINE3, SOUND_MIXER_LINE);
- }
-}
-
-
-static int __init probe_opl3sa_mpu(struct address_info *hw_config)
-{
- unsigned char conf;
- static signed char irq_bits[] = {
- -1, -1, -1, -1, -1, 1, -1, 2, -1, 3, 4
- };
-
- if (hw_config->irq > 10)
- {
- printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
- return 0;
- }
- if (irq_bits[hw_config->irq] == -1)
- {
- printk(KERN_ERR "OPL3-SA: Bad MPU IRQ %d\n", hw_config->irq);
- return 0;
- }
- switch (hw_config->io_base)
- {
- case 0x330:
- conf = 0x00;
- break;
- case 0x332:
- conf = 0x20;
- break;
- case 0x334:
- conf = 0x40;
- break;
- case 0x300:
- conf = 0x60;
- break;
- default:
- return 0; /* Invalid port */
- }
-
- conf |= 0x83; /* MPU & OPL3 (synth) & game port enable */
- conf |= irq_bits[hw_config->irq] << 2;
-
- opl3sa_write(0x03, conf);
-
- hw_config->name = "OPL3-SA (MPU401)";
-
- return probe_uart401(hw_config, THIS_MODULE);
-}
-
-static void __exit unload_opl3sa_wss(struct address_info *hw_config)
-{
- int dma2 = hw_config->dma2;
-
- if (dma2 == -1)
- dma2 = hw_config->dma;
-
- release_region(0xf86, 2);
- release_region(hw_config->io_base, 4);
-
- ad1848_unload(hw_config->io_base + 4,
- hw_config->irq,
- hw_config->dma,
- dma2,
- 0);
- sound_unload_audiodev(hw_config->slots[0]);
-}
-
-static inline void __exit unload_opl3sa_mpu(struct address_info *hw_config)
-{
- unload_uart401(hw_config);
-}
-
-#ifdef SB_OK
-static inline void __exit unload_opl3sa_sb(struct address_info *hw_config)
-{
- sb_dsp_unload(hw_config);
-}
-#endif
-
-static int found_mpu;
-
-static struct address_info cfg;
-static struct address_info cfg_mpu;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma2 = -1;
-static int __initdata mpu_io = -1;
-static int __initdata mpu_irq = -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma2, int, 0);
-module_param(mpu_io, int, 0);
-module_param(mpu_irq, int, 0);
-
-static int __init init_opl3sa(void)
-{
- struct resource *ports;
- if (io == -1 || irq == -1 || dma == -1) {
- printk(KERN_ERR "opl3sa: dma, irq and io must be set.\n");
- return -EINVAL;
- }
-
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma2;
-
- cfg_mpu.io_base = mpu_io;
- cfg_mpu.irq = mpu_irq;
-
- ports = request_region(io + 4, 4, "ad1848");
- if (!ports)
- return -EBUSY;
-
- if (!request_region(0xf86, 2, "OPL3-SA"))/* Control port is busy */ {
- release_region(io + 4, 4);
- return 0;
- }
-
- if (!request_region(io, 4, "WSS config")) {
- release_region(0x86, 2);
- release_region(io + 4, 4);
- return 0;
- }
-
- if (probe_opl3sa_wss(&cfg, ports) == 0) {
- release_region(0xf86, 2);
- release_region(io, 4);
- release_region(io + 4, 4);
- return -ENODEV;
- }
-
- found_mpu=probe_opl3sa_mpu(&cfg_mpu);
-
- attach_opl3sa_wss(&cfg, ports);
- return 0;
-}
-
-static void __exit cleanup_opl3sa(void)
-{
- if(found_mpu)
- unload_opl3sa_mpu(&cfg_mpu);
- unload_opl3sa_wss(&cfg);
-}
-
-module_init(init_opl3sa);
-module_exit(cleanup_opl3sa);
-
-#ifndef MODULE
-static int __init setup_opl3sa(char *str)
-{
- /* io, irq, dma, dma2, mpu_io, mpu_irq */
- int ints[7];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
-
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- mpu_io = ints[5];
- mpu_irq = ints[6];
-
- return 1;
-}
-
-__setup("opl3sa=", setup_opl3sa);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
index aec05a2bfc87..e20051f1be4d 100644
--- a/sound/oss/opl3sa2.c
+++ b/sound/oss/opl3sa2.c
@@ -1,5 +1,5 @@
/*
- * sound/opl3sa2.c
+ * sound/oss/opl3sa2.c
*
* A low level driver for Yamaha OPL3-SA2 and SA3 cards.
* NOTE: All traces of the name OPL3-SAx have now (December 2000) been
diff --git a/sound/oss/pas2_card.c b/sound/oss/pas2_card.c
index 97666007b274..25f3a22c52ee 100644
--- a/sound/oss/pas2_card.c
+++ b/sound/oss/pas2_card.c
@@ -1,5 +1,5 @@
/*
- * sound/pas2_card.c
+ * sound/oss/pas2_card.c
*
* Detection routine for the Pro Audio Spectrum cards.
*/
@@ -88,7 +88,7 @@ void pas_write(unsigned char data, int ioaddr)
/******************* Begin of the Interrupt Handler ********************/
-static irqreturn_t pasintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t pasintr(int irq, void *dev_id)
{
int status;
diff --git a/sound/oss/pas2_midi.c b/sound/oss/pas2_midi.c
index 79d6a5827b6d..1122d10a20c3 100644
--- a/sound/oss/pas2_midi.c
+++ b/sound/oss/pas2_midi.c
@@ -1,5 +1,5 @@
/*
- * sound/pas2_midi.c
+ * sound/oss/pas2_midi.c
*
* The low level driver for the PAS Midi Interface.
*/
diff --git a/sound/oss/pas2_mixer.c b/sound/oss/pas2_mixer.c
index 4aade5304587..a0bcb85c3904 100644
--- a/sound/oss/pas2_mixer.c
+++ b/sound/oss/pas2_mixer.c
@@ -1,6 +1,6 @@
/*
- * sound/pas2_mixer.c
+ * sound/oss/pas2_mixer.c
*
* Mixer routines for the Pro Audio Spectrum cards.
*/
diff --git a/sound/oss/pss.c b/sound/oss/pss.c
index 37ee234b587c..ece428b2ba9f 100644
--- a/sound/oss/pss.c
+++ b/sound/oss/pss.c
@@ -1,5 +1,5 @@
/*
- * sound/pss.c
+ * sound/oss/pss.c
*
* The low level driver for the Personal Sound System (ECHO ESC614).
*
diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c
deleted file mode 100644
index f17d25b6f836..000000000000
--- a/sound/oss/rme96xx.c
+++ /dev/null
@@ -1,1857 +0,0 @@
-/* (C) 2000 Guenter Geiger <geiger@debian.org>
- with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
- based on es1370.c
-
-
-
- * 10 Jan 2001: 0.1 initial version
- * 19 Jan 2001: 0.2 fixed bug in select()
- * 27 Apr 2001: 0.3 more than one card usable
- * 11 May 2001: 0.4 fixed for SMP, included into kernel source tree
- * 17 May 2001: 0.5 draining code didn't work on new cards
- * 18 May 2001: 0.6 remove synchronize_irq() call
- * 17 Jul 2001: 0.7 updated xrmectrl to make it work for newer cards
- * 2 feb 2002: 0.8 fixed pci device handling, see below for patches from Heiko (Thanks!)
- Marcus Meissner <Marcus.Meissner@caldera.de>
-
- Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
- HP20020108 fixed handling of "large" read()
- HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
- HP20020118 made mixer ioctl and handling of devices>1 more safe
- HP20020201 fixed handling of "large" read() properly
- added REV 1.5 S/P-DIF receiver support
- SNDCTL_DSP_SPEED now returns the actual speed
- * 10 Aug 2002: added synchronize_irq() again
-
-TODO:
- - test more than one card --- done
- - check for pci IOREGION (see es1370) in rme96xx_probe ??
- - error detection
- - mmap interface
- - mixer mmap interface
- - mixer ioctl
- - get rid of noise upon first open (why ??)
- - allow multiple open (at least for read)
- - allow multiple open for non overlapping regions
- - recheck the multiple devices part (offsets of different devices, etc)
- - do decent draining in _release --- done
- - SMP support
- - what about using fragstotal>2 for small fragsize? (HP20020118)
- - add support for AFMT_S32_LE
-*/
-
-#ifndef RMEVERSION
-#define RMEVERSION "0.8"
-#endif
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/sound.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/smp_lock.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/wait.h>
-#include <linux/mutex.h>
-
-#include <asm/dma.h>
-#include <asm/page.h>
-
-#include "rme96xx.h"
-
-#define NR_DEVICE 2
-
-static int devices = 1;
-module_param(devices, int, 0);
-MODULE_PARM_DESC(devices, "number of dsp devices allocated by the driver");
-
-
-MODULE_AUTHOR("Guenter Geiger, geiger@debian.org");
-MODULE_DESCRIPTION("RME9652/36 \"Hammerfall\" Driver");
-MODULE_LICENSE("GPL");
-
-
-#ifdef DEBUG
-#define DBG(x) printk("RME_DEBUG:");x
-#define COMM(x) printk("RME_COMM: " x "\n");
-#else
-#define DBG(x) while (0) {}
-#define COMM(x)
-#endif
-
-/*--------------------------------------------------------------------------
- Preporcessor Macros and Definitions
- --------------------------------------------------------------------------*/
-
-#define RME96xx_MAGIC 0x6473
-
-/* Registers-Space in offsets from base address with 16MByte size */
-
-#define RME96xx_IO_EXTENT 16l*1024l*1024l
-#define RME96xx_CHANNELS_PER_CARD 26
-
-/* Write - Register */
-
-/* 0,4,8,12,16,20,24,28 ... hardware init (erasing fifo-pointer intern) */
-#define RME96xx_num_of_init_regs 8
-
-#define RME96xx_init_buffer (0/4)
-#define RME96xx_play_buffer (32/4) /* pointer to 26x64kBit RAM from mainboard */
-#define RME96xx_rec_buffer (36/4) /* pointer to 26x64kBit RAM from mainboard */
-#define RME96xx_control_register (64/4) /* exact meaning see below */
-#define RME96xx_irq_clear (96/4) /* irq acknowledge */
-#define RME96xx_time_code (100/4) /* if used with alesis adat */
-#define RME96xx_thru_base (128/4) /* 132...228 Thru for 26 channels */
-#define RME96xx_thru_channels RME96xx_CHANNELS_PER_CARD
-
-/* Read Register */
-
-#define RME96xx_status_register 0 /* meaning see below */
-
-
-
-/* Status Register: */
-/* ------------------------------------------------------------------------ */
-#define RME96xx_IRQ 0x0000001 /* IRQ is High if not reset by RMExx_irq_clear */
-#define RME96xx_lock_2 0x0000002 /* ADAT 3-PLL: 1=locked, 0=unlocked */
-#define RME96xx_lock_1 0x0000004 /* ADAT 2-PLL: 1=locked, 0=unlocked */
-#define RME96xx_lock_0 0x0000008 /* ADAT 1-PLL: 1=locked, 0=unlocked */
-
-#define RME96xx_fs48 0x0000010 /* sample rate 0 ...44.1/88.2, 1 ... 48/96 Khz */
-#define RME96xx_wsel_rd 0x0000020 /* if Word-Clock is used and valid then 1 */
-#define RME96xx_buf_pos1 0x0000040 /* Bit 6..15 : Position of buffer-pointer in 64Bytes-blocks */
-#define RME96xx_buf_pos2 0x0000080 /* resolution +/- 1 64Byte/block (since 64Bytes bursts) */
-
-#define RME96xx_buf_pos3 0x0000100 /* 10 bits = 1024 values */
-#define RME96xx_buf_pos4 0x0000200 /* if we mask off the first 6 bits, we can take the status */
-#define RME96xx_buf_pos5 0x0000400 /* register as sample counter in the hardware buffer */
-#define RME96xx_buf_pos6 0x0000800
-
-#define RME96xx_buf_pos7 0x0001000
-#define RME96xx_buf_pos8 0x0002000
-#define RME96xx_buf_pos9 0x0004000
-#define RME96xx_buf_pos10 0x0008000
-
-#define RME96xx_sync_2 0x0010000 /* if ADAT-IN3 synced to system clock */
-#define RME96xx_sync_1 0x0020000 /* if ADAT-IN2 synced to system clock */
-#define RME96xx_sync_0 0x0040000 /* if ADAT-IN1 synced to system clock */
-#define RME96xx_DS_rd 0x0080000 /* 1=Double Speed, 0=Normal Speed */
-
-#define RME96xx_tc_busy 0x0100000 /* 1=time-code copy in progress (960ms) */
-#define RME96xx_tc_out 0x0200000 /* time-code out bit */
-#define RME96xx_F_0 0x0400000 /* 000=64kHz, 100=88.2kHz, 011=96kHz */
-#define RME96xx_F_1 0x0800000 /* 111=32kHz, 110=44.1kHz, 101=48kHz, */
-
-#define RME96xx_F_2 0x1000000 /* 001=Rev 1.5+ external Crystal Chip */
-#define RME96xx_ERF 0x2000000 /* Error-Flag of SDPIF Receiver (1=No Lock)*/
-#define RME96xx_buffer_id 0x4000000 /* toggles by each interrupt on rec/play */
-#define RME96xx_tc_valid 0x8000000 /* 1 = a signal is detected on time-code input */
-#define RME96xx_SPDIF_READ 0x10000000 /* byte available from Rev 1.5+ SPDIF interface */
-
-/* Status Register Fields */
-
-#define RME96xx_lock (RME96xx_lock_0|RME96xx_lock_1|RME96xx_lock_2)
-#define RME96xx_sync (RME96xx_sync_0|RME96xx_sync_1|RME96xx_sync_2)
-#define RME96xx_F (RME96xx_F_0|RME96xx_F_1|RME96xx_F_2)
-#define rme96xx_decode_spdif_rate(x) ((x)>>22)
-
-/* Bit 6..15 : h/w buffer pointer */
-#define RME96xx_buf_pos 0x000FFC0
-/* Bits 31,30,29 are bits 5,4,3 of h/w pointer position on later
- Rev G EEPROMS and Rev 1.5 cards or later.
-*/
-#define RME96xx_REV15_buf_pos(x) ((((x)&0xE0000000)>>26)|((x)&RME96xx_buf_pos))
-
-
-/* Control-Register: */
-/*--------------------------------------------------------------------------------*/
-
-#define RME96xx_start_bit 0x0001 /* start record/play */
-#define RME96xx_latency0 0x0002 /* Buffer size / latency */
-#define RME96xx_latency1 0x0004 /* buffersize = 512Bytes * 2^n */
-#define RME96xx_latency2 0x0008 /* 0=64samples ... 7=8192samples */
-
-#define RME96xx_Master 0x0010 /* Clock Mode 1=Master, 0=Slave/Auto */
-#define RME96xx_IE 0x0020 /* Interupt Enable */
-#define RME96xx_freq 0x0040 /* samplerate 0=44.1/88.2, 1=48/96 kHz*/
-#define RME96xx_freq1 0x0080 /* samplerate 0=32 kHz, 1=other rates ??? (from ALSA, but may be wrong) */
-#define RME96xx_DS 0x0100 /* double speed 0=44.1/48, 1=88.2/96 Khz */
-#define RME96xx_PRO 0x0200 /* SPDIF-OUT 0=consumer, 1=professional */
-#define RME96xx_EMP 0x0400 /* SPDIF-OUT emphasis 0=off, 1=on */
-#define RME96xx_Dolby 0x0800 /* SPDIF-OUT non-audio bit 1=set, 0=unset */
-
-#define RME96xx_opt_out 0x1000 /* use 1st optical OUT as SPDIF: 1=yes, 0=no */
-#define RME96xx_wsel 0x2000 /* use Wordclock as sync (overwrites master) */
-#define RME96xx_inp_0 0x4000 /* SPDIF-IN 00=optical (ADAT1), */
-#define RME96xx_inp_1 0x8000 /* 01=coaxial (Cinch), 10=internal CDROM */
-
-#define RME96xx_SyncRef0 0x10000 /* preferred sync-source in autosync */
-#define RME96xx_SyncRef1 0x20000 /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
-
-#define RME96xx_SPDIF_RESET (1<<18) /* Rev 1.5+: h/w SPDIF receiver */
-#define RME96xx_SPDIF_SELECT (1<<19)
-#define RME96xx_SPDIF_CLOCK (1<<20)
-#define RME96xx_SPDIF_WRITE (1<<21)
-#define RME96xx_ADAT1_INTERNAL (1<<22) /* Rev 1.5+: if set, internal CD connector carries ADAT */
-
-
-#define RME96xx_ctrl_init (RME96xx_latency0 |\
- RME96xx_Master |\
- RME96xx_inp_1)
-
-
-
-/* Control register fields and shortcuts */
-
-#define RME96xx_latency (RME96xx_latency0|RME96xx_latency1|RME96xx_latency2)
-#define RME96xx_inp (RME96xx_inp_0|RME96xx_inp_1)
-#define RME96xx_SyncRef (RME96xx_SyncRef0|RME96xx_SyncRef1)
-#define RME96xx_mixer_allowed (RME96xx_Master|RME96xx_PRO|RME96xx_EMP|RME96xx_Dolby|RME96xx_opt_out|RME96xx_wsel|RME96xx_inp|RME96xx_SyncRef|RME96xx_ADAT1_INTERNAL)
-
-/* latency = 512Bytes * 2^n, where n is made from Bit3 ... Bit1 (??? HP20020201) */
-
-#define RME96xx_SET_LATENCY(x) (((x)&0x7)<<1)
-#define RME96xx_GET_LATENCY(x) (((x)>>1)&0x7)
-#define RME96xx_SET_inp(x) (((x)&0x3)<<14)
-#define RME96xx_GET_inp(x) (((x)>>14)&0x3)
-#define RME96xx_SET_SyncRef(x) (((x)&0x3)<<17)
-#define RME96xx_GET_SyncRef(x) (((x)>>17)&0x3)
-
-
-/* buffer sizes */
-#define RME96xx_BYTES_PER_SAMPLE 4 /* sizeof(u32) */
-#define RME_16K 16*1024
-
-#define RME96xx_DMA_MAX_SAMPLES (RME_16K)
-#define RME96xx_DMA_MAX_SIZE (RME_16K * RME96xx_BYTES_PER_SAMPLE)
-#define RME96xx_DMA_MAX_SIZE_ALL (RME96xx_DMA_MAX_SIZE * RME96xx_CHANNELS_PER_CARD)
-
-#define RME96xx_NUM_OF_FRAGMENTS 2
-#define RME96xx_FRAGMENT_MAX_SIZE (RME96xx_DMA_MAX_SIZE/2)
-#define RME96xx_FRAGMENT_MAX_SAMPLES (RME96xx_DMA_MAX_SAMPLES/2)
-#define RME96xx_MAX_LATENCY 7 /* 16k samples */
-
-
-#define RME96xx_MAX_DEVS 4 /* we provide some OSS stereodevs */
-#define RME96xx_MASK_DEVS 0x3 /* RME96xx_MAX_DEVS-1 */
-
-#define RME_MESS "rme96xx:"
-/*------------------------------------------------------------------------
- Types, struct and function declarations
- ------------------------------------------------------------------------*/
-
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT RME_MESS" invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != RME96xx_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-
-static struct file_operations rme96xx_audio_fops;
-static struct file_operations rme96xx_mixer_fops;
-static int numcards;
-
-typedef int32_t raw_sample_t;
-
-typedef struct _rme96xx_info {
-
- /* hardware settings */
- int magic;
- struct pci_dev * pcidev; /* pci_dev structure */
- unsigned long __iomem *iobase;
- unsigned int irq;
-
- /* list of rme96xx devices */
- struct list_head devs;
-
- spinlock_t lock;
-
- u32 *recbuf; /* memory for rec buffer */
- u32 *playbuf; /* memory for play buffer */
-
- u32 control_register;
-
- u32 thru_bits; /* thru 1=on, 0=off channel 1=Bit1... channel 26= Bit26 */
-
- int hw_rev; /* h/w rev * 10 (i.e. 1.5 has hw_rev = 15) */
- char *card_name; /* hammerfall or hammerfall light names */
-
- int open_count; /* unused ??? HP20020201 */
-
- int rate;
- int latency;
- unsigned int fragsize;
- int started;
-
- int hwptr; /* can be negativ because of pci burst offset */
- unsigned int hwbufid; /* set by interrupt, buffer which is written/read now */
-
- struct dmabuf {
-
- unsigned int format;
- int formatshift;
- int inchannels; /* number of channels for device */
- int outchannels; /* number of channels for device */
- int mono; /* if true, we play mono on 2 channels */
- int inoffset; /* which channel is considered the first one */
- int outoffset;
-
- /* state */
- int opened; /* open() made */
- int started; /* first write/read */
- int mmapped; /* mmap */
- int open_mode;
-
- struct _rme96xx_info *s;
-
- /* pointer to read/write position in buffer */
- unsigned readptr;
- unsigned writeptr;
-
- unsigned error; /* over/underruns cleared on sync again */
-
- /* waiting and locking */
- wait_queue_head_t wait;
- struct mutex open_mutex;
- wait_queue_head_t open_wait;
-
- } dma[RME96xx_MAX_DEVS];
-
- int dspnum[RME96xx_MAX_DEVS]; /* register with sound subsystem */
- int mixer; /* register with sound subsystem */
-} rme96xx_info;
-
-
-/* fiddling with the card (first level hardware control) */
-
-static inline void rme96xx_set_ctrl(rme96xx_info* s,int mask)
-{
-
- s->control_register|=mask;
- writel(s->control_register,s->iobase + RME96xx_control_register);
-
-}
-
-static inline void rme96xx_unset_ctrl(rme96xx_info* s,int mask)
-{
-
- s->control_register&=(~mask);
- writel(s->control_register,s->iobase + RME96xx_control_register);
-
-}
-
-static inline int rme96xx_get_sample_rate_status(rme96xx_info* s)
-{
- int val;
- u32 status;
- status = readl(s->iobase + RME96xx_status_register);
- val = (status & RME96xx_fs48) ? 48000 : 44100;
- if (status & RME96xx_DS_rd)
- val *= 2;
- return val;
-}
-
-static inline int rme96xx_get_sample_rate_ctrl(rme96xx_info* s)
-{
- int val;
- val = (s->control_register & RME96xx_freq) ? 48000 : 44100;
- if (s->control_register & RME96xx_DS)
- val *= 2;
- return val;
-}
-
-
-/* code from ALSA card-rme9652.c for rev 1.5 SPDIF receiver HP 20020201 */
-
-static void rme96xx_spdif_set_bit (rme96xx_info* s, int mask, int onoff)
-{
- if (onoff)
- s->control_register |= mask;
- else
- s->control_register &= ~mask;
-
- writel(s->control_register,s->iobase + RME96xx_control_register);
-}
-
-static void rme96xx_spdif_write_byte (rme96xx_info* s, const int val)
-{
- long mask;
- long i;
-
- for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
- if (val & mask)
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 1);
- else
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_WRITE, 0);
-
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
- }
-}
-
-static int rme96xx_spdif_read_byte (rme96xx_info* s)
-{
- long mask;
- long val;
- long i;
-
- val = 0;
-
- for (i = 0, mask = 0x80; i < 8; i++, mask >>= 1) {
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 1);
- if (readl(s->iobase + RME96xx_status_register) & RME96xx_SPDIF_READ)
- val |= mask;
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_CLOCK, 0);
- }
-
- return val;
-}
-
-static void rme96xx_write_spdif_codec (rme96xx_info* s, const int address, const int data)
-{
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
- rme96xx_spdif_write_byte (s, 0x20);
- rme96xx_spdif_write_byte (s, address);
- rme96xx_spdif_write_byte (s, data);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
-}
-
-
-static int rme96xx_spdif_read_codec (rme96xx_info* s, const int address)
-{
- int ret;
-
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
- rme96xx_spdif_write_byte (s, 0x20);
- rme96xx_spdif_write_byte (s, address);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 1);
-
- rme96xx_spdif_write_byte (s, 0x21);
- ret = rme96xx_spdif_read_byte (s);
- rme96xx_spdif_set_bit (s, RME96xx_SPDIF_SELECT, 0);
-
- return ret;
-}
-
-static void rme96xx_initialize_spdif_receiver (rme96xx_info* s)
-{
- /* XXX what unsets this ? */
- /* no idea ??? HP 20020201 */
-
- s->control_register |= RME96xx_SPDIF_RESET;
-
- rme96xx_write_spdif_codec (s, 4, 0x40);
- rme96xx_write_spdif_codec (s, 17, 0x13);
- rme96xx_write_spdif_codec (s, 6, 0x02);
-}
-
-static inline int rme96xx_spdif_sample_rate (rme96xx_info *s, int *spdifrate)
-{
- unsigned int rate_bits;
-
- *spdifrate = 0x1;
- if (readl(s->iobase + RME96xx_status_register) & RME96xx_ERF) {
- return -1; /* error condition */
- }
-
- if (s->hw_rev == 15) {
-
- int x, y, ret;
-
- x = rme96xx_spdif_read_codec (s, 30);
-
- if (x != 0)
- y = 48000 * 64 / x;
- else
- y = 0;
-
- if (y > 30400 && y < 33600) {ret = 32000; *spdifrate = 0x7;}
- else if (y > 41900 && y < 46000) {ret = 44100; *spdifrate = 0x6;}
- else if (y > 46000 && y < 50400) {ret = 48000; *spdifrate = 0x5;}
- else if (y > 60800 && y < 67200) {ret = 64000; *spdifrate = 0x0;}
- else if (y > 83700 && y < 92000) {ret = 88200; *spdifrate = 0x4;}
- else if (y > 92000 && y < 100000) {ret = 96000; *spdifrate = 0x3;}
- else {ret = 0; *spdifrate = 0x1;}
- return ret;
- }
-
- rate_bits = readl(s->iobase + RME96xx_status_register) & RME96xx_F;
-
- switch (*spdifrate = rme96xx_decode_spdif_rate(rate_bits)) {
- case 0x7:
- return 32000;
- break;
-
- case 0x6:
- return 44100;
- break;
-
- case 0x5:
- return 48000;
- break;
-
- case 0x4:
- return 88200;
- break;
-
- case 0x3:
- return 96000;
- break;
-
- case 0x0:
- return 64000;
- break;
-
- default:
- /* was an ALSA warning ...
- snd_printk("%s: unknown S/PDIF input rate (bits = 0x%x)\n",
- s->card_name, rate_bits);
- */
- return 0;
- break;
- }
-}
-
-/* end of code from ALSA card-rme9652.c */
-
-
-
-/* the hwbuf in the status register seems to have some jitter, to get rid of
- it, we first only let the numbers grow, to be on the secure side we
- subtract a certain amount RME96xx_BURSTBYTES from the resulting number */
-
-/* the function returns the hardware pointer in bytes */
-#define RME96xx_BURSTBYTES -64 /* bytes by which hwptr could be off */
-
-static inline int rme96xx_gethwptr(rme96xx_info* s,int exact)
-{
- unsigned long flags;
- if (exact) {
- unsigned int hwp;
-/* the hwptr seems to be rather unreliable :(, so we don't use it */
- spin_lock_irqsave(&s->lock,flags);
-
- hwp = readl(s->iobase + RME96xx_status_register) & 0xffc0;
- s->hwptr = (hwp < s->hwptr) ? s->hwptr : hwp;
-// s->hwptr = hwp;
-
- spin_unlock_irqrestore(&s->lock,flags);
- return (s->hwptr+RME96xx_BURSTBYTES) & ((s->fragsize<<1)-1);
- }
- return (s->hwbufid ? s->fragsize : 0);
-}
-
-static inline void rme96xx_setlatency(rme96xx_info* s,int l)
-{
- s->latency = l;
- s->fragsize = 1<<(8+l);
- rme96xx_unset_ctrl(s,RME96xx_latency);
- rme96xx_set_ctrl(s,RME96xx_SET_LATENCY(l));
-}
-
-
-static void rme96xx_clearbufs(struct dmabuf* dma)
-{
- int i,j;
- unsigned long flags;
-
- /* clear dmabufs */
- for(i=0;i<devices;i++) {
- for (j=0;j<dma->outchannels + dma->mono;j++)
- memset(&dma->s->playbuf[(dma->outoffset + j)*RME96xx_DMA_MAX_SAMPLES],
- 0, RME96xx_DMA_MAX_SIZE);
- }
- spin_lock_irqsave(&dma->s->lock,flags);
- dma->writeptr = 0;
- dma->readptr = 0;
- spin_unlock_irqrestore(&dma->s->lock,flags);
-}
-
-static int rme96xx_startcard(rme96xx_info *s,int stop)
-{
- int i;
- unsigned long flags;
-
- COMM ("startcard");
- if(s->control_register & RME96xx_IE){
- /* disable interrupt first */
-
- rme96xx_unset_ctrl( s,RME96xx_start_bit );
- udelay(10);
- rme96xx_unset_ctrl( s,RME96xx_IE);
- spin_lock_irqsave(&s->lock,flags); /* timing is critical */
- s->started = 0;
- spin_unlock_irqrestore(&s->lock,flags);
- if (stop) {
- COMM("Sound card stopped");
- return 1;
- }
- }
- COMM ("interrupt disabled");
- /* first initialize all pointers on card */
- for(i=0;i<RME96xx_num_of_init_regs;i++){
- writel(0,s->iobase + i);
- udelay(10); /* ?? */
- }
- COMM ("regs cleaned");
-
- spin_lock_irqsave(&s->lock,flags); /* timing is critical */
- udelay(10);
- s->started = 1;
- s->hwptr = 0;
- spin_unlock_irqrestore(&s->lock,flags);
-
- rme96xx_set_ctrl( s, RME96xx_IE | RME96xx_start_bit);
-
-
- COMM("Sound card started");
-
- return 1;
-}
-
-
-static inline int rme96xx_getospace(struct dmabuf * dma, unsigned int hwp)
-{
- int cnt;
- int swptr;
- unsigned long flags;
-
- spin_lock_irqsave(&dma->s->lock,flags);
- swptr = dma->writeptr;
- cnt = (hwp - swptr);
-
- if (cnt < 0) {
- cnt = ((dma->s->fragsize<<1) - swptr);
- }
- spin_unlock_irqrestore(&dma->s->lock,flags);
- return cnt;
-}
-
-static inline int rme96xx_getispace(struct dmabuf * dma, unsigned int hwp)
-{
- int cnt;
- int swptr;
- unsigned long flags;
-
- spin_lock_irqsave(&dma->s->lock,flags);
- swptr = dma->readptr;
- cnt = (hwp - swptr);
-
- if (cnt < 0) {
- cnt = ((dma->s->fragsize<<1) - swptr);
- }
- spin_unlock_irqrestore(&dma->s->lock,flags);
- return cnt;
-}
-
-
-static inline int rme96xx_copyfromuser(struct dmabuf* dma,const char __user * buffer,int count,int hop)
-{
- int swptr = dma->writeptr;
- switch (dma->format) {
- case AFMT_S32_BLOCKED:
- {
- char __user * buf = (char __user *)buffer;
- int cnt = count/dma->outchannels;
- int i;
- for (i=0;i < dma->outchannels;i++) {
- char* hwbuf =(char*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=swptr;
-
- if (copy_from_user(hwbuf,buf, cnt))
- return -1;
- buf+=hop;
- }
- swptr+=cnt;
- break;
- }
- case AFMT_S16_LE:
- {
- int i,j;
- int cnt = count/dma->outchannels;
- for (i=0;i < dma->outchannels + dma->mono;i++) {
- short __user * sbuf = (short __user *)buffer + i*(!dma->mono);
- short* hwbuf =(short*) &dma->s->playbuf[(dma->outoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=(swptr>>1);
- for (j=0;j<(cnt>>1);j++) {
- hwbuf++; /* skip the low 16 bits */
- __get_user(*hwbuf++,sbuf++);
- sbuf+=(dma->outchannels-1);
- }
- }
- swptr += (cnt<<1);
- break;
- }
- default:
- printk(RME_MESS" unsupported format\n");
- return -1;
- } /* switch */
-
- swptr&=((dma->s->fragsize<<1) -1);
- dma->writeptr = swptr;
-
- return 0;
-}
-
-/* The count argument is the number of bytes */
-static inline int rme96xx_copytouser(struct dmabuf* dma,const char __user* buffer,int count,int hop)
-{
- int swptr = dma->readptr;
- switch (dma->format) {
- case AFMT_S32_BLOCKED:
- {
- char __user * buf = (char __user *)buffer;
- int cnt = count/dma->inchannels;
- int i;
-
- for (i=0;i < dma->inchannels;i++) {
- char* hwbuf =(char*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=swptr;
-
- if (copy_to_user(buf,hwbuf,cnt))
- return -1;
- buf+=hop;
- }
- swptr+=cnt;
- break;
- }
- case AFMT_S16_LE:
- {
- int i,j;
- int cnt = count/dma->inchannels;
- for (i=0;i < dma->inchannels;i++) {
- short __user * sbuf = (short __user *)buffer + i;
- short* hwbuf =(short*) &dma->s->recbuf[(dma->inoffset + i)*RME96xx_DMA_MAX_SAMPLES];
- hwbuf+=(swptr>>1);
- for (j=0;j<(cnt>>1);j++) {
- hwbuf++;
- __put_user(*hwbuf++,sbuf++);
- sbuf+=(dma->inchannels-1);
- }
- }
- swptr += (cnt<<1);
- break;
- }
- default:
- printk(RME_MESS" unsupported format\n");
- return -1;
- } /* switch */
-
- swptr&=((dma->s->fragsize<<1) -1);
- dma->readptr = swptr;
- return 0;
-}
-
-
-static irqreturn_t rme96xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- int i;
- rme96xx_info *s = (rme96xx_info *)dev_id;
- struct dmabuf *db;
- u32 status;
- unsigned long flags;
-
- status = readl(s->iobase + RME96xx_status_register);
- if (!(status & RME96xx_IRQ)) {
- return IRQ_NONE;
- }
-
- spin_lock_irqsave(&s->lock,flags);
- writel(0,s->iobase + RME96xx_irq_clear);
-
- s->hwbufid = (status & RME96xx_buffer_id)>>26;
- if ((status & 0xffc0) <= 256) s->hwptr = 0;
- for(i=0;i<devices;i++)
- {
- db = &(s->dma[i]);
- if(db->started > 0)
- wake_up(&(db->wait));
- }
- spin_unlock_irqrestore(&s->lock,flags);
- return IRQ_HANDLED;
-}
-
-
-
-/*----------------------------------------------------------------------------
- PCI detection and module initialization stuff
- ----------------------------------------------------------------------------*/
-
-static void* busmaster_malloc(int size) {
- int pg; /* 2 s exponent of memory size */
- char *buf;
-
- DBG(printk("kernel malloc pages ..\n"));
-
- for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-
- buf = (char *) __get_free_pages(GFP_KERNEL | GFP_DMA, pg);
-
- if (buf) {
- struct page* page, *last_page;
-
- page = virt_to_page(buf);
- last_page = page + (1 << pg);
- DBG(printk("setting reserved bit\n"));
- while (page < last_page) {
- SetPageReserved(page);
- page++;
- }
- return buf;
- }
- DBG(printk("allocated %ld",(long)buf));
- return NULL;
-}
-
-static void busmaster_free(void* ptr,int size) {
- int pg;
- struct page* page, *last_page;
-
- if (ptr == NULL)
- return;
-
- for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++);
-
- page = virt_to_page(ptr);
- last_page = page + (1 << pg);
- while (page < last_page) {
- ClearPageReserved(page);
- page++;
- }
- DBG(printk("freeing pages\n"));
- free_pages((unsigned long) ptr, pg);
- DBG(printk("done\n"));
-}
-
-/* initialize those parts of the info structure which are not pci detectable resources */
-
-static int rme96xx_dmabuf_init(rme96xx_info * s,struct dmabuf* dma,int ioffset,int ooffset) {
-
- mutex_init(&dma->open_mutex);
- init_waitqueue_head(&dma->open_wait);
- init_waitqueue_head(&dma->wait);
- dma->s = s;
- dma->error = 0;
-
- dma->format = AFMT_S32_BLOCKED;
- dma->formatshift = 0;
- dma->inchannels = dma->outchannels = 1;
- dma->inoffset = ioffset;
- dma->outoffset = ooffset;
-
- dma->opened=0;
- dma->started=0;
- dma->mmapped=0;
- dma->open_mode=0;
- dma->mono=0;
-
- rme96xx_clearbufs(dma);
- return 0;
-}
-
-
-static int rme96xx_init(rme96xx_info* s)
-{
- int i;
- int status;
- unsigned short rev;
-
- DBG(printk("%s\n", __FUNCTION__));
- numcards++;
-
- s->magic = RME96xx_MAGIC;
-
- spin_lock_init(&s->lock);
-
- COMM ("setup busmaster memory")
- s->recbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
- s->playbuf = busmaster_malloc(RME96xx_DMA_MAX_SIZE_ALL);
-
- if (!s->recbuf || !s->playbuf) {
- printk(KERN_ERR RME_MESS" Unable to allocate busmaster memory\n");
- return -ENODEV;
- }
-
- COMM ("setting rec and playbuffers")
-
- writel((u32) virt_to_bus(s->recbuf),s->iobase + RME96xx_rec_buffer);
- writel((u32) virt_to_bus(s->playbuf),s->iobase + RME96xx_play_buffer);
-
- COMM ("initializing control register")
- rme96xx_unset_ctrl(s,0xffffffff);
- rme96xx_set_ctrl(s,RME96xx_ctrl_init);
-
-
- COMM ("setup devices")
- for (i=0;i < devices;i++) {
- struct dmabuf * dma = &s->dma[i];
- rme96xx_dmabuf_init(s,dma,2*i,2*i);
- }
-
- /* code from ALSA card-rme9652.c HP 20020201 */
- /* Determine the h/w rev level of the card. This seems like
- a particularly kludgy way to encode it, but its what RME
- chose to do, so we follow them ...
- */
-
- status = readl(s->iobase + RME96xx_status_register);
- if (rme96xx_decode_spdif_rate(status&RME96xx_F) == 1) {
- s->hw_rev = 15;
- } else {
- s->hw_rev = 11;
- }
-
- /* Differentiate between the standard Hammerfall, and the
- "Light", which does not have the expansion board. This
- method comes from information received from Mathhias
- Clausen at RME. Display the EEPROM and h/w revID where
- relevant.
- */
-
- pci_read_config_word(s->pcidev, PCI_CLASS_REVISION, &rev);
- switch (rev & 0xff) {
- case 8: /* original eprom */
- if (s->hw_rev == 15) {
- s->card_name = "RME Digi9636 (Rev 1.5)";
- } else {
- s->card_name = "RME Digi9636";
- }
- break;
- case 9: /* W36_G EPROM */
- s->card_name = "RME Digi9636 (Rev G)";
- break;
- case 4: /* W52_G EPROM */
- s->card_name = "RME Digi9652 (Rev G)";
- break;
- default:
- case 3: /* original eprom */
- if (s->hw_rev == 15) {
- s->card_name = "RME Digi9652 (Rev 1.5)";
- } else {
- s->card_name = "RME Digi9652";
- }
- break;
- }
-
- printk(KERN_INFO RME_MESS" detected %s (hw_rev %d)\n",s->card_name,s->hw_rev);
-
- if (s->hw_rev == 15)
- rme96xx_initialize_spdif_receiver (s);
-
- s->started = 0;
- rme96xx_setlatency(s,7);
-
- printk(KERN_INFO RME_MESS" card %d initialized\n",numcards);
- return 0;
-}
-
-
-/* open uses this to figure out which device was opened .. this seems to be
- unnecessary complex */
-
-static LIST_HEAD(devs);
-
-static int __devinit rme96xx_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- int i;
- rme96xx_info *s;
-
- DBG(printk("%s\n", __FUNCTION__));
-
- if (pcidev->irq == 0)
- return -1;
- if (!pci_dma_supported(pcidev, 0xffffffff)) {
- printk(KERN_WARNING RME_MESS" architecture does not support 32bit PCI busmaster DMA\n");
- return -1;
- }
- if (!(s = kmalloc(sizeof(rme96xx_info), GFP_KERNEL))) {
- printk(KERN_WARNING RME_MESS" out of memory\n");
- return -1;
- }
- memset(s, 0, sizeof(rme96xx_info));
-
- s->pcidev = pcidev;
- s->iobase = ioremap(pci_resource_start(pcidev, 0),RME96xx_IO_EXTENT);
- s->irq = pcidev->irq;
-
- DBG(printk("remapped iobase: %lx irq %d\n",(long)s->iobase,s->irq));
-
- if (pci_enable_device(pcidev))
- goto err_irq;
- if (request_irq(s->irq, rme96xx_interrupt, IRQF_SHARED, "rme96xx", s)) {
- printk(KERN_ERR RME_MESS" irq %u in use\n", s->irq);
- goto err_irq;
- }
-
- /* initialize the card */
-
- i = 0;
- if (rme96xx_init(s) < 0) {
- printk(KERN_ERR RME_MESS" initialization failed\n");
- goto err_devices;
- }
- for (i=0;i<devices;i++) {
- if ((s->dspnum[i] = register_sound_dsp(&rme96xx_audio_fops, -1)) < 0)
- goto err_devices;
- }
-
- if ((s->mixer = register_sound_mixer(&rme96xx_mixer_fops, -1)) < 0)
- goto err_devices;
-
- pci_set_drvdata(pcidev, s);
- pcidev->dma_mask = 0xffffffff; /* ????? */
- /* put it into driver list */
- list_add_tail(&s->devs, &devs);
-
- DBG(printk("initialization successful\n"));
- return 0;
-
- /* error handler */
- err_devices:
- while (i--)
- unregister_sound_dsp(s->dspnum[i]);
- free_irq(s->irq,s);
- err_irq:
- kfree(s);
- return -1;
-}
-
-
-static void __devexit rme96xx_remove(struct pci_dev *dev)
-{
- int i;
- rme96xx_info *s = pci_get_drvdata(dev);
-
- if (!s) {
- printk(KERN_ERR"device structure not valid\n");
- return ;
- }
-
- if (s->started) rme96xx_startcard(s,0);
-
- i = devices;
- while (i) {
- i--;
- unregister_sound_dsp(s->dspnum[i]);
- }
-
- unregister_sound_mixer(s->mixer);
- synchronize_irq(s->irq);
- free_irq(s->irq,s);
- busmaster_free(s->recbuf,RME96xx_DMA_MAX_SIZE_ALL);
- busmaster_free(s->playbuf,RME96xx_DMA_MAX_SIZE_ALL);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-
-#ifndef PCI_VENDOR_ID_RME
-#define PCI_VENDOR_ID_RME 0x10ee
-#endif
-#ifndef PCI_DEVICE_ID_RME9652
-#define PCI_DEVICE_ID_RME9652 0x3fc4
-#endif
-#ifndef PCI_ANY_ID
-#define PCI_ANY_ID 0
-#endif
-
-static struct pci_device_id id_table[] = {
- {
- .vendor = PCI_VENDOR_ID_RME,
- .device = PCI_DEVICE_ID_RME9652,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver rme96xx_driver = {
- .name = "rme96xx",
- .id_table = id_table,
- .probe = rme96xx_probe,
- .remove = __devexit_p(rme96xx_remove),
-};
-
-static int __init init_rme96xx(void)
-{
- printk(KERN_INFO RME_MESS" version "RMEVERSION" time " __TIME__ " " __DATE__ "\n");
- devices = ((devices-1) & RME96xx_MASK_DEVS) + 1;
- printk(KERN_INFO RME_MESS" reserving %d dsp device(s)\n",devices);
- numcards = 0;
- return pci_register_driver(&rme96xx_driver);
-}
-
-static void __exit cleanup_rme96xx(void)
-{
- printk(KERN_INFO RME_MESS" unloading\n");
- pci_unregister_driver(&rme96xx_driver);
-}
-
-module_init(init_rme96xx);
-module_exit(cleanup_rme96xx);
-
-
-
-
-
-/*--------------------------------------------------------------------------
- Implementation of file operations
----------------------------------------------------------------------------*/
-
-#define RME96xx_FMT (AFMT_S16_LE|AFMT_U8|AFMT_S32_BLOCKED)
-/* AFTM_U8 is not (yet?) supported ... HP20020201 */
-
-static int rme96xx_ioctl(struct inode *in, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct dmabuf * dma = (struct dmabuf *)file->private_data;
- rme96xx_info *s = dma->s;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val = 0;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
-
- DBG(printk("ioctl %ud\n",cmd));
-
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
-#if 0
- if (file->f_mode & FMODE_WRITE)
- return drain_dac2(s, 0/*file->f_flags & O_NONBLOCK*/);
-#endif
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
-// rme96xx_clearbufs(dma);
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
-/* generally it's not a problem if we change the speed
- if (dma->open_mode & (~file->f_mode) & (FMODE_READ|FMODE_WRITE))
- return -EINVAL;
-*/
- spin_lock_irqsave(&s->lock, flags);
-
- switch (val) {
- case 44100:
- case 88200:
- rme96xx_unset_ctrl(s,RME96xx_freq);
- break;
- case 48000:
- case 96000:
- rme96xx_set_ctrl(s,RME96xx_freq);
- break;
- /* just report current rate as default
- e.g. use 0 to "select" current digital input rate
- default:
- rme96xx_unset_ctrl(s,RME96xx_freq);
- val = 44100;
- */
- }
- if (val > 50000)
- rme96xx_set_ctrl(s,RME96xx_DS);
- else
- rme96xx_unset_ctrl(s,RME96xx_DS);
- /* set val to actual value HP 20020201 */
- /* NOTE: if not "Sync Master", reported rate might be not yet "updated" ... but I don't want to insert a long udelay() here */
- if ((s->control_register & RME96xx_Master) && !(s->control_register & RME96xx_wsel))
- val = rme96xx_get_sample_rate_ctrl(s);
- else
- val = rme96xx_get_sample_rate_status(s);
- s->rate = val;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- DBG(printk("speed set to %d\n",val));
- return put_user(val, p);
-
- case SNDCTL_DSP_STEREO: /* this plays a mono file on two channels */
- if (get_user(val, p))
- return -EFAULT;
-
- if (!val) {
- DBG(printk("setting to mono\n"));
- dma->mono=1;
- dma->inchannels = 1;
- dma->outchannels = 1;
- }
- else {
- DBG(printk("setting to stereo\n"));
- dma->mono = 0;
- dma->inchannels = 2;
- dma->outchannels = 2;
- }
- return 0;
- case SNDCTL_DSP_CHANNELS:
- /* remember to check for resonable offset/channel pairs here */
- if (get_user(val, p))
- return -EFAULT;
-
- if (file->f_mode & FMODE_WRITE) {
- if (val > 0 && (dma->outoffset + val) <= RME96xx_CHANNELS_PER_CARD)
- dma->outchannels = val;
- else
- dma->outchannels = val = 2;
- DBG(printk("setting to outchannels %d\n",val));
- }
- if (file->f_mode & FMODE_READ) {
- if (val > 0 && (dma->inoffset + val) <= RME96xx_CHANNELS_PER_CARD)
- dma->inchannels = val;
- else
- dma->inchannels = val = 2;
- DBG(printk("setting to inchannels %d\n",val));
- }
-
- dma->mono=0;
-
- return put_user(val, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(RME96xx_FMT, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- DBG(printk("setting to format %x\n",val));
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- if (val & RME96xx_FMT)
- dma->format = val;
- switch (dma->format) {
- case AFMT_S16_LE:
- dma->formatshift=1;
- break;
- case AFMT_S32_BLOCKED:
- dma->formatshift=0;
- break;
- }
- }
- return put_user(dma->format, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
-#if 0
- if (file->f_mode & FMODE_READ && s->ctrl & CTRL_ADC_EN)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->ctrl & CTRL_DAC2_EN)
- val |= PCM_ENABLE_OUTPUT;
-#endif
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
-#if 0
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf_adc(s)))
- return ret;
- start_adc(s);
- } else
- stop_adc(s);
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac2.ready && (ret = prog_dmabuf_dac2(s)))
- return ret;
- start_dac2(s);
- } else
- stop_dac2(s);
- }
-#endif
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- val = rme96xx_gethwptr(dma->s,0);
-
-
- count = rme96xx_getospace(dma,val);
- if (!s->started) count = s->fragsize*2;
- abinfo.fragsize =(s->fragsize*dma->outchannels)>>dma->formatshift;
- abinfo.bytes = (count*dma->outchannels)>>dma->formatshift;
- abinfo.fragstotal = 2;
- abinfo.fragments = (count > s->fragsize);
-
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
-
- val = rme96xx_gethwptr(dma->s,0);
-
- count = rme96xx_getispace(dma,val);
-
- abinfo.fragsize = (s->fragsize*dma->inchannels)>>dma->formatshift;
- abinfo.bytes = (count*dma->inchannels)>>dma->formatshift;
- abinfo.fragstotal = 2;
- abinfo.fragments = count > s->fragsize;
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY: /* What should this exactly do ? ,
- ATM it is just abinfo.bytes */
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
-
- val = rme96xx_gethwptr(dma->s,0);
- count = val - dma->readptr;
- if (count < 0)
- count += s->fragsize<<1;
-
- return put_user(count, p);
-
-
-/* check out how to use mmaped mode (can only be blocked !!!) */
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- val = rme96xx_gethwptr(dma->s,0);
- spin_lock_irqsave(&s->lock,flags);
- cinfo.bytes = s->fragsize<<1;
- count = val - dma->readptr;
- if (count < 0)
- count += s->fragsize<<1;
-
- cinfo.blocks = (count > s->fragsize);
- cinfo.ptr = val;
- if (dma->mmapped)
- dma->readptr &= s->fragsize<<1;
- spin_unlock_irqrestore(&s->lock,flags);
-
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- val = rme96xx_gethwptr(dma->s,0);
- spin_lock_irqsave(&s->lock,flags);
- cinfo.bytes = s->fragsize<<1;
- count = val - dma->writeptr;
- if (count < 0)
- count += s->fragsize<<1;
-
- cinfo.blocks = (count > s->fragsize);
- cinfo.ptr = val;
- if (dma->mmapped)
- dma->writeptr &= s->fragsize<<1;
- spin_unlock_irqrestore(&s->lock,flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
- case SNDCTL_DSP_GETBLKSIZE:
- return put_user(s->fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- val&=0xffff;
- val -= 7;
- if (val < 0) val = 0;
- if (val > 7) val = 7;
- rme96xx_setlatency(s,val);
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
-#if 0
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac2.subdivision))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac2.subdivision = val;
-#endif
- return 0;
-
- case SOUND_PCM_READ_RATE:
- /* HP20020201 */
- s->rate = rme96xx_get_sample_rate_status(s);
- return put_user(s->rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user(dma->outchannels, p);
-
- case SOUND_PCM_READ_BITS:
- switch (dma->format) {
- case AFMT_S32_BLOCKED:
- val = 32;
- break;
- case AFMT_S16_LE:
- val = 16;
- break;
- }
- return put_user(val, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
-
-
- return -ENODEV;
-}
-
-
-
-static int rme96xx_open(struct inode *in, struct file *f)
-{
- int minor = iminor(in);
- struct list_head *list;
- int devnum;
- rme96xx_info *s;
- struct dmabuf* dma;
- DECLARE_WAITQUEUE(wait, current);
-
- DBG(printk("device num %d open\n",devnum));
-
- nonseekable_open(in, f);
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, rme96xx_info, devs);
- for (devnum=0; devnum<devices; devnum++)
- if (!((s->dspnum[devnum] ^ minor) & ~0xf))
- break;
- if (devnum<devices)
- break;
- }
- VALIDATE_STATE(s);
-
- dma = &s->dma[devnum];
- f->private_data = dma;
- /* wait for device to become free */
- mutex_lock(&dma->open_mutex);
- while (dma->open_mode & f->f_mode) {
- if (f->f_flags & O_NONBLOCK) {
- mutex_unlock(&dma->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&dma->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&dma->open_mutex);
- schedule();
- remove_wait_queue(&dma->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&dma->open_mutex);
- }
-
- COMM ("hardware open")
-
- if (!dma->opened) rme96xx_dmabuf_init(dma->s,dma,dma->inoffset,dma->outoffset);
-
- dma->open_mode |= (f->f_mode & (FMODE_READ | FMODE_WRITE));
- dma->opened = 1;
- mutex_unlock(&dma->open_mutex);
-
- DBG(printk("device num %d open finished\n",devnum));
- return 0;
-}
-
-static int rme96xx_release(struct inode *in, struct file *file)
-{
- struct dmabuf * dma = (struct dmabuf*) file->private_data;
- /* int hwp; ... was unused HP20020201 */
- DBG(printk("%s\n", __FUNCTION__));
-
- COMM ("draining")
- if (dma->open_mode & FMODE_WRITE) {
-#if 0 /* Why doesn't this work with some cards ?? */
- hwp = rme96xx_gethwptr(dma->s,0);
- while (rme96xx_getospace(dma,hwp)) {
- interruptible_sleep_on(&(dma->wait));
- hwp = rme96xx_gethwptr(dma->s,0);
- }
-#endif
- rme96xx_clearbufs(dma);
- }
-
- dma->open_mode &= (~file->f_mode) & (FMODE_READ|FMODE_WRITE);
-
- if (!(dma->open_mode & (FMODE_READ|FMODE_WRITE))) {
- dma->opened = 0;
- if (dma->s->started) rme96xx_startcard(dma->s,1);
- }
-
- wake_up(&dma->open_wait);
- mutex_unlock(&dma->open_mutex);
-
- return 0;
-}
-
-
-static ssize_t rme96xx_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- ssize_t ret = 0;
- int cnt; /* number of bytes from "buffer" that will/can be used */
- int hop = count/dma->outchannels;
- int hwp;
- int exact = (file->f_flags & O_NONBLOCK);
-
-
- if(dma == NULL || (dma->s) == NULL)
- return -ENXIO;
-
- if (dma->mmapped || !dma->opened)
- return -ENXIO;
-
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
-
- if (! (dma->open_mode & FMODE_WRITE))
- return -ENXIO;
-
- if (!dma->s->started) rme96xx_startcard(dma->s,exact);
- hwp = rme96xx_gethwptr(dma->s,0);
-
- if(!(dma->started)){
- COMM ("first write")
-
- dma->readptr = hwp;
- dma->writeptr = hwp;
- dma->started = 1;
- }
-
- while (count > 0) {
- cnt = rme96xx_getospace(dma,hwp);
- cnt>>=dma->formatshift;
- cnt*=dma->outchannels;
- if (cnt > count)
- cnt = count;
-
- if (cnt != 0) {
- if (rme96xx_copyfromuser(dma,buffer,cnt,hop))
- return ret ? ret : -EFAULT;
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (count == 0) return ret;
- }
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
-
- if ((hwp - dma->writeptr) <= 0) {
- interruptible_sleep_on(&(dma->wait));
-
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- }
-
- hwp = rme96xx_gethwptr(dma->s,exact);
-
- }; /* count > 0 */
-
- return ret;
-}
-
-static ssize_t rme96xx_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- ssize_t ret = 0;
- int cnt; /* number of bytes from "buffer" that will/can be used */
- int hop = count/dma->inchannels;
- int hwp;
- int exact = (file->f_flags & O_NONBLOCK);
-
-
- if(dma == NULL || (dma->s) == NULL)
- return -ENXIO;
-
- if (dma->mmapped || !dma->opened)
- return -ENXIO;
-
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
-
- if (! (dma->open_mode & FMODE_READ))
- return -ENXIO;
-
- if (!dma->s->started) rme96xx_startcard(dma->s,exact);
- hwp = rme96xx_gethwptr(dma->s,0);
-
- if(!(dma->started)){
- COMM ("first read")
-
- dma->writeptr = hwp;
- dma->readptr = hwp;
- dma->started = 1;
- }
-
- while (count > 0) {
- cnt = rme96xx_getispace(dma,hwp);
- cnt>>=dma->formatshift;
- cnt*=dma->inchannels;
-
- if (cnt > count)
- cnt = count;
-
- if (cnt != 0) {
-
- if (rme96xx_copytouser(dma,buffer,cnt,hop))
- return ret ? ret : -EFAULT;
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (count == 0) return ret;
- }
- if (file->f_flags & O_NONBLOCK)
- return ret ? ret : -EAGAIN;
-
- if ((hwp - dma->readptr) <= 0) {
- interruptible_sleep_on(&(dma->wait));
-
- if (signal_pending(current))
- return ret ? ret : -ERESTARTSYS;
- }
- hwp = rme96xx_gethwptr(dma->s,exact);
-
- }; /* count > 0 */
-
- return ret;
-}
-
-static int rm96xx_mmap(struct file *file, struct vm_area_struct *vma) {
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- rme96xx_info* s = dma->s;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
-
- if (vma->vm_pgoff != 0) {
- unlock_kernel();
- return -EINVAL;
- }
- size = vma->vm_end - vma->vm_start;
- if (size > RME96xx_DMA_MAX_SIZE) {
- unlock_kernel();
- return -EINVAL;
- }
-
-
- if (vma->vm_flags & VM_WRITE) {
- if (!s->started) rme96xx_startcard(s,1);
-
- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->outoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
- unlock_kernel();
- return -EAGAIN;
- }
- }
- else if (vma->vm_flags & VM_READ) {
- if (!s->started) rme96xx_startcard(s,1);
- if (remap_pfn_range(vma, vma->vm_start, virt_to_phys(s->playbuf + dma->inoffset*RME96xx_DMA_MAX_SIZE) >> PAGE_SHIFT, size, vma->vm_page_prot)) {
- unlock_kernel();
- return -EAGAIN;
- }
- } else {
- unlock_kernel();
- return -EINVAL;
- }
-
-
-/* this is the mapping */
- vma->vm_flags &= ~VM_IO;
- dma->mmapped = 1;
- unlock_kernel();
- return 0;
-}
-
-static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct dmabuf *dma = (struct dmabuf *)file->private_data;
- rme96xx_info* s = dma->s;
- unsigned int mask = 0;
- unsigned int hwp,cnt;
-
- DBG(printk("rme96xx poll_wait ...\n"));
- VALIDATE_STATE(s);
-
- if (!s->started) {
- mask |= POLLOUT | POLLWRNORM;
- }
- poll_wait(file, &dma->wait, wait);
-
- hwp = rme96xx_gethwptr(dma->s,0);
-
- DBG(printk("rme96xx poll: ..cnt %d > %d\n",cnt,s->fragsize));
-
- cnt = rme96xx_getispace(dma,hwp);
-
- if (file->f_mode & FMODE_READ)
- if (cnt > 0)
- mask |= POLLIN | POLLRDNORM;
-
-
-
- cnt = rme96xx_getospace(dma,hwp);
-
- if (file->f_mode & FMODE_WRITE)
- if (cnt > 0)
- mask |= POLLOUT | POLLWRNORM;
-
-
-// printk("rme96xx poll_wait ...%d > %d\n",rme96xx_getospace(dma,hwp),rme96xx_getispace(dma,hwp));
-
- return mask;
-}
-
-
-static struct file_operations rme96xx_audio_fops = {
- .owner = THIS_MODULE,
- .read = rme96xx_read,
- .write = rme96xx_write,
- .poll = rme96xx_poll,
- .ioctl = rme96xx_ioctl,
- .mmap = rm96xx_mmap,
- .open = rme96xx_open,
- .release = rme96xx_release
-};
-
-static int rme96xx_mixer_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- rme96xx_info *s;
-
- COMM ("mixer open");
-
- nonseekable_open(inode, file);
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, rme96xx_info, devs);
- if (s->mixer== minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
-
- COMM ("mixer opened")
- return 0;
-}
-
-static int rme96xx_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- rme96xx_info *s = (rme96xx_info *)file->private_data;
- u32 status;
- int spdifrate;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- status = readl(s->iobase + RME96xx_status_register);
- /* hack to convert rev 1.5 SPDIF rate to "crystalrate" format HP 20020201 */
- rme96xx_spdif_sample_rate(s,&spdifrate);
- status = (status & ~RME96xx_F) | ((spdifrate<<22) & RME96xx_F);
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_PRIVATE1) {
- rme_mixer mixer;
- if (copy_from_user(&mixer,argp,sizeof(mixer)))
- return -EFAULT;
-
- mixer.devnr &= RME96xx_MASK_DEVS;
- if (mixer.devnr >= devices)
- mixer.devnr = devices-1;
- if (file->f_mode & FMODE_WRITE && !s->dma[mixer.devnr].opened) {
- /* modify only if device not open */
- if (mixer.o_offset < 0)
- mixer.o_offset = 0;
- if (mixer.o_offset >= RME96xx_CHANNELS_PER_CARD)
- mixer.o_offset = RME96xx_CHANNELS_PER_CARD-1;
- if (mixer.i_offset < 0)
- mixer.i_offset = 0;
- if (mixer.i_offset >= RME96xx_CHANNELS_PER_CARD)
- mixer.i_offset = RME96xx_CHANNELS_PER_CARD-1;
- s->dma[mixer.devnr].outoffset = mixer.o_offset;
- s->dma[mixer.devnr].inoffset = mixer.i_offset;
- }
-
- mixer.o_offset = s->dma[mixer.devnr].outoffset;
- mixer.i_offset = s->dma[mixer.devnr].inoffset;
-
- return copy_to_user(argp, &mixer, sizeof(mixer)) ? -EFAULT : 0;
- }
- if (cmd == SOUND_MIXER_PRIVATE2) {
- return put_user(status, p);
- }
- if (cmd == SOUND_MIXER_PRIVATE3) {
- u32 control;
- if (copy_from_user(&control,argp,sizeof(control)))
- return -EFAULT;
- if (file->f_mode & FMODE_WRITE) {
- s->control_register &= ~RME96xx_mixer_allowed;
- s->control_register |= control & RME96xx_mixer_allowed;
- writel(control,s->iobase + RME96xx_control_register);
- }
-
- return put_user(s->control_register, p);
- }
- return -1;
-}
-
-
-
-static int rme96xx_mixer_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static /*const*/ struct file_operations rme96xx_mixer_fops = {
- .owner = THIS_MODULE,
- .ioctl = rme96xx_mixer_ioctl,
- .open = rme96xx_mixer_open,
- .release = rme96xx_mixer_release,
-};
diff --git a/sound/oss/rme96xx.h b/sound/oss/rme96xx.h
deleted file mode 100644
index 7a3c188ea0a8..000000000000
--- a/sound/oss/rme96xx.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* (C) 2000 Guenter Geiger <geiger@debian.org>
- with copy/pastes from the driver of Winfried Ritsch <ritsch@iem.kug.ac.at>
-
-Modifications - Heiko Purnhagen <purnhage@tnt.uni-hannover.de>
- HP20020116 towards REV 1.5 support, based on ALSA's card-rme9652.c
- HP20020201 completed?
-
-A text/graphic control panel (rmectrl/xrmectrl) is available from
- http://gige.xdv.org/pages/soft/pages/rme
-*/
-
-
-#ifndef AFMT_S32_BLOCKED
-#define AFMT_S32_BLOCKED 0x0000400
-#endif
-
-/* AFMT_S16_BLOCKED not yet supported */
-#ifndef AFMT_S16_BLOCKED
-#define AFMT_S16_BLOCKED 0x0000800
-#endif
-
-
-typedef struct rme_status {
- unsigned int irq:1;
- unsigned int lockmask:3; /* ADAT input PLLs locked */
- /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
- unsigned int sr48:1; /* sample rate: 0=44.1/88.2 1=48/96 kHz */
- unsigned int wclock:1; /* 1=wordclock used */
- unsigned int bufpoint:10;
- unsigned int syncmask:3; /* ADAT input in sync with system clock */
- /* 100=ADAT1, 010=ADAT2, 001=ADAT3 */
- unsigned int doublespeed:1; /* sample rate: 0=44.1/48 1=88.2/96 kHz */
- unsigned int tc_busy:1;
- unsigned int tc_out:1;
- unsigned int crystalrate:3; /* spdif input sample rate: */
- /* 000=64kHz, 100=88.2kHz, 011=96kHz */
- /* 111=32kHz, 110=44.1kHz, 101=48kHz */
- unsigned int spdif_error:1; /* 1=no spdif lock */
- unsigned int bufid:1;
- unsigned int tc_valid:1; /* 1=timecode input detected */
- unsigned int spdif_read:1;
-} rme_status_t;
-
-
-/* only fields marked W: can be modified by writing to SOUND_MIXER_PRIVATE3 */
-typedef struct rme_control {
- unsigned int start:1;
- unsigned int latency:3; /* buffer size / latency [samples]: */
- /* 0=64 ... 7=8192 */
- unsigned int master:1; /* W: clock mode: 1=master 0=slave/auto */
- unsigned int ie:1;
- unsigned int sr48:1; /* samplerate 0=44.1/88.2, 1=48/96 kHz */
- unsigned int spare:1;
- unsigned int doublespeed:1; /* double speed 0=44.1/48, 1=88.2/96 Khz */
- unsigned int pro:1; /* W: SPDIF-OUT 0=consumer, 1=professional */
- unsigned int emphasis:1; /* W: SPDIF-OUT emphasis 0=off, 1=on */
- unsigned int dolby:1; /* W: SPDIF-OUT non-audio bit 1=set, 0=unset */
- unsigned int opt_out:1; /* W: use 1st optical OUT as SPDIF: 1=yes, 0=no */
- unsigned int wordclock:1; /* W: use Wordclock as sync (overwrites master) */
- unsigned int spdif_in:2; /* W: SPDIF-IN: */
- /* 00=optical (ADAT1), 01=coaxial (Cinch), 10=internal CDROM */
- unsigned int sync_ref:2; /* W: preferred sync-source in autosync */
- /* 00=ADAT1, 01=ADAT2, 10=ADAT3, 11=SPDIF */
- unsigned int spdif_reset:1;
- unsigned int spdif_select:1;
- unsigned int spdif_clock:1;
- unsigned int spdif_write:1;
- unsigned int adat1_cd:1; /* W: Rev 1.5+: if set, internal CD connector carries ADAT */
-} rme_ctrl_t;
-
-
-typedef struct _rme_mixer {
- int i_offset;
- int o_offset;
- int devnr;
- int spare[8];
-} rme_mixer;
-
diff --git a/sound/oss/sb_audio.c b/sound/oss/sb_audio.c
index 75e54f6f638a..733b014ec7d1 100644
--- a/sound/oss/sb_audio.c
+++ b/sound/oss/sb_audio.c
@@ -1,5 +1,5 @@
/*
- * sound/sb_audio.c
+ * sound/oss/sb_audio.c
*
* Audio routines for Sound Blaster compatible cards.
*
diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c
index 35bab6e2f998..440537c72604 100644
--- a/sound/oss/sb_common.c
+++ b/sound/oss/sb_common.c
@@ -1,5 +1,5 @@
/*
- * sound/sb_common.c
+ * sound/oss/sb_common.c
*
* Common routines for Sound Blaster compatible cards.
*
@@ -132,7 +132,7 @@ static void sb_intr (sb_devc *devc)
if (src & 4) /* MPU401 interrupt */
if(devc->midi_irq_cookie)
- uart401intr(devc->irq, devc->midi_irq_cookie, NULL);
+ uart401intr(devc->irq, devc->midi_irq_cookie);
if (!(src & 3))
return; /* Not a DSP interrupt */
@@ -200,7 +200,7 @@ static void pci_intr(sb_devc *devc)
sb_intr(devc);
}
-static irqreturn_t sbintr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t sbintr(int irq, void *dev_id)
{
sb_devc *devc = dev_id;
diff --git a/sound/oss/sb_midi.c b/sound/oss/sb_midi.c
index ed3bd0640ffd..2e3bc045caba 100644
--- a/sound/oss/sb_midi.c
+++ b/sound/oss/sb_midi.c
@@ -1,5 +1,5 @@
/*
- * sound/sb_dsp.c
+ * sound/oss/sb_midi.c
*
* The low level driver for the Sound Blaster DS chips.
*
diff --git a/sound/oss/sb_mixer.c b/sound/oss/sb_mixer.c
index ccb21d48d42c..238e2cf44b08 100644
--- a/sound/oss/sb_mixer.c
+++ b/sound/oss/sb_mixer.c
@@ -1,5 +1,5 @@
/*
- * sound/sb_mixer.c
+ * sound/oss/sb_mixer.c
*
* The low level mixer driver for the Sound Blaster compatible cards.
*/
diff --git a/sound/oss/sb_mixer.h b/sound/oss/sb_mixer.h
index ab74426157ba..4b9425f085e3 100644
--- a/sound/oss/sb_mixer.h
+++ b/sound/oss/sb_mixer.h
@@ -1,5 +1,5 @@
/*
- * sound/sb_mixer.h
+ * sound/oss/sb_mixer.h
*
* Definitions for the SB Pro and SB16 mixers
*/
diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c
index 6815c30e0bc1..5c215f787ca9 100644
--- a/sound/oss/sequencer.c
+++ b/sound/oss/sequencer.c
@@ -1,5 +1,5 @@
/*
- * sound/sequencer.c
+ * sound/oss/sequencer.c
*
* The sequencer personality manager.
*/
@@ -16,7 +16,6 @@
*/
#include <linux/kmod.h>
#include <linux/spinlock.h>
-#define SEQUENCER_C
#include "sound_config.h"
#include "midi_ctrl.h"
@@ -157,6 +156,7 @@ void seq_copy_to_input(unsigned char *event_rec, int len)
wake_up(&midi_sleeper);
spin_unlock_irqrestore(&lock,flags);
}
+EXPORT_SYMBOL(seq_copy_to_input);
static void sequencer_midi_input(int dev, unsigned char data)
{
@@ -206,6 +206,7 @@ void seq_input_event(unsigned char *event_rec, int len)
}
seq_copy_to_input(event_rec, len);
}
+EXPORT_SYMBOL(seq_input_event);
int sequencer_write(int dev, struct file *file, const char __user *buf, int count)
{
@@ -1554,6 +1555,7 @@ void sequencer_timer(unsigned long dummy)
{
seq_startplay();
}
+EXPORT_SYMBOL(sequencer_timer);
int note_to_freq(int note_num)
{
@@ -1587,6 +1589,7 @@ int note_to_freq(int note_num)
return note_freq;
}
+EXPORT_SYMBOL(note_to_freq);
unsigned long compute_finetune(unsigned long base_freq, int bend, int range,
int vibrato_cents)
@@ -1640,19 +1643,12 @@ unsigned long compute_finetune(unsigned long base_freq, int bend, int range,
else
return (base_freq * amount) / 10000; /* Bend up */
}
-
+EXPORT_SYMBOL(compute_finetune);
void sequencer_init(void)
{
- /* drag in sequencer_syms.o */
- {
- extern char sequencer_syms_symbol;
- sequencer_syms_symbol = 0;
- }
-
if (sequencer_ok)
return;
- MIDIbuf_init();
queue = (unsigned char *)vmalloc(SEQ_MAX_QUEUE * EV_SZ);
if (queue == NULL)
{
@@ -1668,6 +1664,7 @@ void sequencer_init(void)
}
sequencer_ok = 1;
}
+EXPORT_SYMBOL(sequencer_init);
void sequencer_unload(void)
{
diff --git a/sound/oss/sequencer_syms.c b/sound/oss/sequencer_syms.c
deleted file mode 100644
index 5d008798c310..000000000000
--- a/sound/oss/sequencer_syms.c
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Exported symbols for sequencer driver.
- */
-
-#include <linux/module.h>
-
-char sequencer_syms_symbol;
-
-#include "sound_config.h"
-#include "sound_calls.h"
-
-EXPORT_SYMBOL(note_to_freq);
-EXPORT_SYMBOL(compute_finetune);
-EXPORT_SYMBOL(seq_copy_to_input);
-EXPORT_SYMBOL(seq_input_event);
-EXPORT_SYMBOL(sequencer_init);
-EXPORT_SYMBOL(sequencer_timer);
-
-EXPORT_SYMBOL(sound_timer_init);
-EXPORT_SYMBOL(sound_timer_interrupt);
-EXPORT_SYMBOL(sound_timer_syncinterval);
-
-/* Tuning */
-
-#define _SEQUENCER_C_
-#include "tuning.h"
-
-EXPORT_SYMBOL(cent_tuning);
-EXPORT_SYMBOL(semitone_tuning);
diff --git a/sound/oss/sgalaxy.c b/sound/oss/sgalaxy.c
deleted file mode 100644
index 3f32d4674371..000000000000
--- a/sound/oss/sgalaxy.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * sound/sgalaxy.c
- *
- * Low level driver for Aztech Sound Galaxy cards.
- * Copyright 1998 Artur Skawina <skawina@geocities.com>
- *
- * Supported cards:
- * Aztech Sound Galaxy Waverider Pro 32 - 3D
- * Aztech Sound Galaxy Washington 16
- *
- * Based on cs4232.c by Hannu Savolainen and Alan Cox.
- *
- *
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added __init to sb_rst() and sb_cmd()
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include "sound_config.h"
-#include "ad1848.h"
-
-static void sleep( unsigned howlong )
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(howlong);
-}
-
-#define DPORT 0x80
-
-/* Sound Blaster regs */
-
-#define SBDSP_RESET 0x6
-#define SBDSP_READ 0xA
-#define SBDSP_COMMAND 0xC
-#define SBDSP_STATUS SBDSP_COMMAND
-#define SBDSP_DATA_AVAIL 0xE
-
-static int __init sb_rst(int base)
-{
- int i;
-
- outb( 1, base+SBDSP_RESET ); /* reset the DSP */
- outb( 0, base+SBDSP_RESET );
-
- for ( i=0; i<500; i++ ) /* delay */
- inb(DPORT);
-
- for ( i=0; i<100000; i++ )
- {
- if ( inb( base+SBDSP_DATA_AVAIL )&0x80 )
- break;
- }
-
- if ( inb( base+SBDSP_READ )!=0xAA )
- return 0;
-
- return 1;
-}
-
-static int __init sb_cmd( int base, unsigned char val )
-{
- int i;
-
- for ( i=100000; i; i-- )
- {
- if ( (inb( base+SBDSP_STATUS )&0x80)==0 )
- {
- outb( val, base+SBDSP_COMMAND );
- break;
- }
- }
- return i; /* i>0 == success */
-}
-
-
-#define ai_sgbase driver_use_1
-
-static int __init probe_sgalaxy( struct address_info *ai )
-{
- struct resource *ports;
- int n;
-
- if (!request_region(ai->io_base, 4, "WSS config")) {
- printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
- return 0;
- }
-
- ports = request_region(ai->io_base + 4, 4, "ad1848");
- if (!ports) {
- printk(KERN_ERR "sgalaxy: WSS IO port 0x%03x not available\n", ai->io_base);
- release_region(ai->io_base, 4);
- return 0;
- }
-
- if (!request_region( ai->ai_sgbase, 0x10, "SoundGalaxy SB")) {
- printk(KERN_ERR "sgalaxy: SB IO port 0x%03x not available\n", ai->ai_sgbase);
- release_region(ai->io_base + 4, 4);
- release_region(ai->io_base, 4);
- return 0;
- }
-
- if (ad1848_detect(ports, NULL, ai->osp))
- goto out; /* The card is already active, check irq etc... */
-
- /* switch to MSS/WSS mode */
-
- sb_rst( ai->ai_sgbase );
-
- sb_cmd( ai->ai_sgbase, 9 );
- sb_cmd( ai->ai_sgbase, 0 );
-
- sleep( HZ/10 );
-
-out:
- if (!probe_ms_sound(ai, ports)) {
- release_region(ai->io_base + 4, 4);
- release_region(ai->io_base, 4);
- release_region(ai->ai_sgbase, 0x10);
- return 0;
- }
-
- attach_ms_sound(ai, ports, THIS_MODULE);
- n=ai->slots[0];
-
- if (n!=-1 && audio_devs[n]->mixer_dev != -1 ) {
- AD1848_REROUTE( SOUND_MIXER_LINE1, SOUND_MIXER_LINE ); /* Line-in */
- AD1848_REROUTE( SOUND_MIXER_LINE2, SOUND_MIXER_SYNTH ); /* FM+Wavetable*/
- AD1848_REROUTE( SOUND_MIXER_LINE3, SOUND_MIXER_CD ); /* CD */
- }
- return 1;
-}
-
-static void __exit unload_sgalaxy( struct address_info *ai )
-{
- unload_ms_sound( ai );
- release_region( ai->ai_sgbase, 0x10 );
-}
-
-static struct address_info cfg;
-
-static int __initdata io = -1;
-static int __initdata irq = -1;
-static int __initdata dma = -1;
-static int __initdata dma2 = -1;
-static int __initdata sgbase = -1;
-
-module_param(io, int, 0);
-module_param(irq, int, 0);
-module_param(dma, int, 0);
-module_param(dma2, int, 0);
-module_param(sgbase, int, 0);
-
-static int __init init_sgalaxy(void)
-{
- cfg.io_base = io;
- cfg.irq = irq;
- cfg.dma = dma;
- cfg.dma2 = dma2;
- cfg.ai_sgbase = sgbase;
-
- if (cfg.io_base == -1 || cfg.irq == -1 || cfg.dma == -1 || cfg.ai_sgbase == -1 ) {
- printk(KERN_ERR "sgalaxy: io, irq, dma and sgbase must be set.\n");
- return -EINVAL;
- }
-
- if ( probe_sgalaxy(&cfg) == 0 )
- return -ENODEV;
-
- return 0;
-}
-
-static void __exit cleanup_sgalaxy(void)
-{
- unload_sgalaxy(&cfg);
-}
-
-module_init(init_sgalaxy);
-module_exit(cleanup_sgalaxy);
-
-#ifndef MODULE
-static int __init setup_sgalaxy(char *str)
-{
- /* io, irq, dma, dma2, sgbase */
- int ints[6];
-
- str = get_options(str, ARRAY_SIZE(ints), ints);
- io = ints[1];
- irq = ints[2];
- dma = ints[3];
- dma2 = ints[4];
- sgbase = ints[5];
-
- return 1;
-}
-
-__setup("sgalaxy=", setup_sgalaxy);
-#endif
-MODULE_LICENSE("GPL");
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c
index 7b168d85f4ab..3b3b4da8cfd3 100644
--- a/sound/oss/sh_dac_audio.c
+++ b/sound/oss/sh_dac_audio.c
@@ -1,3 +1,14 @@
+/*
+ * sound/oss/sh_dac_audio.c
+ *
+ * SH DAC based sound :(
+ *
+ * Copyright (C) 2004,2005 Andriy Skulysh
+ *
+ * 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/module.h>
#include <linux/init.h>
#include <linux/sched.h>
@@ -6,18 +17,17 @@
#include <linux/fs.h>
#include <linux/sound.h>
#include <linux/soundcard.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/delay.h>
-#include <linux/interrupt.h>
-
+#include <asm/clock.h>
#include <asm/cpu/dac.h>
-
-#ifdef MACH_HP600
+#include <asm/cpu/timer.h>
+#include <asm/machvec.h>
#include <asm/hp6xx/hp6xx.h>
-#include <asm/hd64461/hd64461.h>
-#endif
+#include <asm/hd64461.h>
#define MODNAME "sh_dac_audio"
@@ -26,11 +36,6 @@
#define TMU1_TCR_INIT 0x0020 /* Clock/4, rising edge; interrupt on */
#define TMU1_TSTR_INIT 0x02 /* Bit to turn on TMU1 */
-#define TMU_TSTR 0xfffffe92
-#define TMU1_TCOR 0xfffffea0
-#define TMU1_TCNT 0xfffffea4
-#define TMU1_TCR 0xfffffea8
-
#define BUFFER_SIZE 48000
static int rate;
@@ -71,34 +76,37 @@ static void dac_audio_sync(void)
static void dac_audio_start(void)
{
-#ifdef MACH_HP600
- u16 v;
- v = inw(HD64461_GPADR);
- v &= ~HD64461_GPADR_SPEAKER;
- outw(v, HD64461_GPADR);
-#endif
+ if (mach_is_hp6xx()) {
+ u16 v = inw(HD64461_GPADR);
+ v &= ~HD64461_GPADR_SPEAKER;
+ outw(v, HD64461_GPADR);
+ }
+
sh_dac_enable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
ctrl_outw(TMU1_TCR_INIT, TMU1_TCR);
}
static void dac_audio_stop(void)
{
-#ifdef MACH_HP600
- u16 v;
-#endif
dac_audio_stop_timer();
-#ifdef MACH_HP600
- v = inw(HD64461_GPADR);
- v |= HD64461_GPADR_SPEAKER;
- outw(v, HD64461_GPADR);
-#endif
+
+ if (mach_is_hp6xx()) {
+ u16 v = inw(HD64461_GPADR);
+ v |= HD64461_GPADR_SPEAKER;
+ outw(v, HD64461_GPADR);
+ }
+
+ sh_dac_output(0, CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
sh_dac_disable(CONFIG_SOUND_SH_DAC_AUDIO_CHANNEL);
}
static void dac_audio_set_rate(void)
{
unsigned long interval;
+ struct clk *clk;
- interval = (current_cpu_data.module_clock / 4) / rate;
+ clk = clk_get("module_clk");
+ interval = (clk_get_rate(clk) / 4) / rate;
+ clk_put(clk);
ctrl_outl(interval, TMU1_TCOR);
ctrl_outl(interval, TMU1_TCNT);
}
@@ -255,7 +263,7 @@ struct file_operations dac_audio_fops = {
.release = dac_audio_release,
};
-static irqreturn_t timer1_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t timer1_interrupt(int irq, void *dev)
{
unsigned long timer_status;
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
deleted file mode 100644
index 8ea532d40198..000000000000
--- a/sound/oss/sonicvibes.c
+++ /dev/null
@@ -1,2792 +0,0 @@
-/*****************************************************************************/
-
-/*
- * sonicvibes.c -- S3 Sonic Vibes audio driver.
- *
- * Copyright (C) 1998-2001, 2003 Thomas Sailer (t.sailer@alumni.ethz.ch)
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Special thanks to David C. Niemi
- *
- *
- * Module command line parameters:
- * none so far
- *
- *
- * Supported devices:
- * /dev/dsp standard /dev/dsp device, (mostly) OSS compatible
- * /dev/mixer standard /dev/mixer device, (mostly) OSS compatible
- * /dev/midi simple MIDI UART interface, no ioctl
- *
- * The card has both an FM and a Wavetable synth, but I have to figure
- * out first how to drive them...
- *
- * Revision history
- * 06.05.1998 0.1 Initial release
- * 10.05.1998 0.2 Fixed many bugs, esp. ADC rate calculation
- * First stab at a simple midi interface (no bells&whistles)
- * 13.05.1998 0.3 Fix stupid cut&paste error: set_adc_rate was called instead of
- * set_dac_rate in the FMODE_WRITE case in sv_open
- * Fix hwptr out of bounds (now mpg123 works)
- * 14.05.1998 0.4 Don't allow excessive interrupt rates
- * 08.06.1998 0.5 First release using Alan Cox' soundcore instead of miscdevice
- * 03.08.1998 0.6 Do not include modversions.h
- * Now mixer behaviour can basically be selected between
- * "OSS documented" and "OSS actual" behaviour
- * 31.08.1998 0.7 Fix realplayer problems - dac.count issues
- * 10.12.1998 0.8 Fix drain_dac trying to wait on not yet initialized DMA
- * 16.12.1998 0.9 Fix a few f_file & FMODE_ bugs
- * 06.01.1999 0.10 remove the silly SA_INTERRUPT flag.
- * hopefully killed the egcs section type conflict
- * 12.03.1999 0.11 cinfo.blocks should be reset after GETxPTR ioctl.
- * reported by Johan Maes <joma@telindus.be>
- * 22.03.1999 0.12 return EAGAIN instead of EBUSY when O_NONBLOCK
- * read/write cannot be executed
- * 05.04.1999 0.13 added code to sv_read and sv_write which should detect
- * lockups of the sound chip and revive it. This is basically
- * an ugly hack, but at least applications using this driver
- * won't hang forever. I don't know why these lockups happen,
- * it might well be the motherboard chipset (an early 486 PCI
- * board with ALI chipset), since every busmastering 100MB
- * ethernet card I've tried (Realtek 8139 and Macronix tulip clone)
- * exhibit similar behaviour (they work for a couple of packets
- * and then lock up and can be revived by ifconfig down/up).
- * 07.04.1999 0.14 implemented the following ioctl's: SOUND_PCM_READ_RATE,
- * SOUND_PCM_READ_CHANNELS, SOUND_PCM_READ_BITS;
- * Alpha fixes reported by Peter Jones <pjones@redhat.com>
- * Note: dmaio hack might still be wrong on archs other than i386
- * 15.06.1999 0.15 Fix bad allocation bug.
- * Thanks to Deti Fliegl <fliegl@in.tum.de>
- * 28.06.1999 0.16 Add pci_set_master
- * 03.08.1999 0.17 adapt to Linus' new __setup/__initcall
- * added kernel command line options "sonicvibes=reverb" and "sonicvibesdmaio=dmaioaddr"
- * 12.08.1999 0.18 module_init/__setup fixes
- * 24.08.1999 0.19 get rid of the dmaio kludge, replace with allocate_resource
- * 31.08.1999 0.20 add spin_lock_init
- * use new resource allocation to allocate DDMA IO space
- * replaced current->state = x with set_current_state(x)
- * 03.09.1999 0.21 change read semantics for MIDI to match
- * OSS more closely; remove possible wakeup race
- * 28.10.1999 0.22 More waitqueue races fixed
- * 01.12.1999 0.23 New argument to allocate_resource
- * 07.12.1999 0.24 More allocate_resource semantics change
- * 08.01.2000 0.25 Prevent some ioctl's from returning bad count values on underrun/overrun;
- * Tim Janik's BSE (Bedevilled Sound Engine) found this
- * use Martin Mares' pci_assign_resource
- * 07.02.2000 0.26 Use pci_alloc_consistent and pci_register_driver
- * 21.11.2000 0.27 Initialize dma buffers in poll, otherwise poll may return a bogus mask
- * 12.12.2000 0.28 More dma buffer initializations, patch from
- * Tjeerd Mulder <tjeerd.mulder@fujitsu-siemens.com>
- * 31.01.2001 0.29 Register/Unregister gameport
- * Fix SETTRIGGER non OSS API conformity
- * 18.05.2001 0.30 PCI probing and error values cleaned up by Marcus
- * Meissner <mm@caldera.de>
- * 03.01.2003 0.31 open_mode fixes from Georg Acher <acher@in.tum.de>
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/interrupt.h>
-#include <linux/wait.h>
-#include <linux/mm.h>
-#include <linux/delay.h>
-#include <linux/sound.h>
-#include <linux/slab.h>
-#include <linux/soundcard.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/spinlock.h>
-#include <linux/smp_lock.h>
-#include <linux/gameport.h>
-#include <linux/dma-mapping.h>
-#include <linux/mutex.h>
-
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#include "dm.h"
-
-#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
-#define SUPPORT_JOYSTICK 1
-#endif
-
-/* --------------------------------------------------------------------- */
-
-#undef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-/* --------------------------------------------------------------------- */
-
-#ifndef PCI_VENDOR_ID_S3
-#define PCI_VENDOR_ID_S3 0x5333
-#endif
-#ifndef PCI_DEVICE_ID_S3_SONICVIBES
-#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00
-#endif
-
-#define SV_MAGIC ((PCI_VENDOR_ID_S3<<16)|PCI_DEVICE_ID_S3_SONICVIBES)
-
-#define SV_EXTENT_SB 0x10
-#define SV_EXTENT_ENH 0x10
-#define SV_EXTENT_SYNTH 0x4
-#define SV_EXTENT_MIDI 0x4
-#define SV_EXTENT_GAME 0x8
-#define SV_EXTENT_DMA 0x10
-
-/*
- * we are not a bridge and thus use a resource for DDMA that is used for bridges but
- * left empty for normal devices
- */
-#define RESOURCE_SB 0
-#define RESOURCE_ENH 1
-#define RESOURCE_SYNTH 2
-#define RESOURCE_MIDI 3
-#define RESOURCE_GAME 4
-#define RESOURCE_DDMA 7
-
-#define SV_MIDI_DATA 0
-#define SV_MIDI_COMMAND 1
-#define SV_MIDI_STATUS 1
-
-#define SV_DMA_ADDR0 0
-#define SV_DMA_ADDR1 1
-#define SV_DMA_ADDR2 2
-#define SV_DMA_ADDR3 3
-#define SV_DMA_COUNT0 4
-#define SV_DMA_COUNT1 5
-#define SV_DMA_COUNT2 6
-#define SV_DMA_MODE 0xb
-#define SV_DMA_RESET 0xd
-#define SV_DMA_MASK 0xf
-
-/*
- * DONT reset the DMA controllers unless you understand
- * the reset semantics. Assuming reset semantics as in
- * the 8237 does not work.
- */
-
-#define DMA_MODE_AUTOINIT 0x10
-#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */
-#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */
-
-#define SV_CODEC_CONTROL 0
-#define SV_CODEC_INTMASK 1
-#define SV_CODEC_STATUS 2
-#define SV_CODEC_IADDR 4
-#define SV_CODEC_IDATA 5
-
-#define SV_CCTRL_RESET 0x80
-#define SV_CCTRL_INTADRIVE 0x20
-#define SV_CCTRL_WAVETABLE 0x08
-#define SV_CCTRL_REVERB 0x04
-#define SV_CCTRL_ENHANCED 0x01
-
-#define SV_CINTMASK_DMAA 0x01
-#define SV_CINTMASK_DMAC 0x04
-#define SV_CINTMASK_SPECIAL 0x08
-#define SV_CINTMASK_UPDOWN 0x40
-#define SV_CINTMASK_MIDI 0x80
-
-#define SV_CSTAT_DMAA 0x01
-#define SV_CSTAT_DMAC 0x04
-#define SV_CSTAT_SPECIAL 0x08
-#define SV_CSTAT_UPDOWN 0x40
-#define SV_CSTAT_MIDI 0x80
-
-#define SV_CIADDR_TRD 0x80
-#define SV_CIADDR_MCE 0x40
-
-/* codec indirect registers */
-#define SV_CIMIX_ADCINL 0x00
-#define SV_CIMIX_ADCINR 0x01
-#define SV_CIMIX_AUX1INL 0x02
-#define SV_CIMIX_AUX1INR 0x03
-#define SV_CIMIX_CDINL 0x04
-#define SV_CIMIX_CDINR 0x05
-#define SV_CIMIX_LINEINL 0x06
-#define SV_CIMIX_LINEINR 0x07
-#define SV_CIMIX_MICIN 0x08
-#define SV_CIMIX_SYNTHINL 0x0A
-#define SV_CIMIX_SYNTHINR 0x0B
-#define SV_CIMIX_AUX2INL 0x0C
-#define SV_CIMIX_AUX2INR 0x0D
-#define SV_CIMIX_ANALOGINL 0x0E
-#define SV_CIMIX_ANALOGINR 0x0F
-#define SV_CIMIX_PCMINL 0x10
-#define SV_CIMIX_PCMINR 0x11
-
-#define SV_CIGAMECONTROL 0x09
-#define SV_CIDATAFMT 0x12
-#define SV_CIENABLE 0x13
-#define SV_CIUPDOWN 0x14
-#define SV_CIREVISION 0x15
-#define SV_CIADCOUTPUT 0x16
-#define SV_CIDMAABASECOUNT1 0x18
-#define SV_CIDMAABASECOUNT0 0x19
-#define SV_CIDMACBASECOUNT1 0x1c
-#define SV_CIDMACBASECOUNT0 0x1d
-#define SV_CIPCMSR0 0x1e
-#define SV_CIPCMSR1 0x1f
-#define SV_CISYNTHSR0 0x20
-#define SV_CISYNTHSR1 0x21
-#define SV_CIADCCLKSOURCE 0x22
-#define SV_CIADCALTSR 0x23
-#define SV_CIADCPLLM 0x24
-#define SV_CIADCPLLN 0x25
-#define SV_CISYNTHPLLM 0x26
-#define SV_CISYNTHPLLN 0x27
-#define SV_CIUARTCONTROL 0x2a
-#define SV_CIDRIVECONTROL 0x2b
-#define SV_CISRSSPACE 0x2c
-#define SV_CISRSCENTER 0x2d
-#define SV_CIWAVETABLESRC 0x2e
-#define SV_CIANALOGPWRDOWN 0x30
-#define SV_CIDIGITALPWRDOWN 0x31
-
-
-#define SV_CIMIX_ADCSRC_CD 0x20
-#define SV_CIMIX_ADCSRC_DAC 0x40
-#define SV_CIMIX_ADCSRC_AUX2 0x60
-#define SV_CIMIX_ADCSRC_LINE 0x80
-#define SV_CIMIX_ADCSRC_AUX1 0xa0
-#define SV_CIMIX_ADCSRC_MIC 0xc0
-#define SV_CIMIX_ADCSRC_MIXOUT 0xe0
-#define SV_CIMIX_ADCSRC_MASK 0xe0
-
-#define SV_CFMT_STEREO 0x01
-#define SV_CFMT_16BIT 0x02
-#define SV_CFMT_MASK 0x03
-#define SV_CFMT_ASHIFT 0
-#define SV_CFMT_CSHIFT 4
-
-static const unsigned sample_size[] = { 1, 2, 2, 4 };
-static const unsigned sample_shift[] = { 0, 1, 1, 2 };
-
-#define SV_CENABLE_PPE 0x4
-#define SV_CENABLE_RE 0x2
-#define SV_CENABLE_PE 0x1
-
-
-/* MIDI buffer sizes */
-
-#define MIDIINBUF 256
-#define MIDIOUTBUF 256
-
-#define FMODE_MIDI_SHIFT 2
-#define FMODE_MIDI_READ (FMODE_READ << FMODE_MIDI_SHIFT)
-#define FMODE_MIDI_WRITE (FMODE_WRITE << FMODE_MIDI_SHIFT)
-
-#define FMODE_DMFM 0x10
-
-/* --------------------------------------------------------------------- */
-
-struct sv_state {
- /* magic */
- unsigned int magic;
-
- /* list of sonicvibes devices */
- struct list_head devs;
-
- /* the corresponding pci_dev structure */
- struct pci_dev *dev;
-
- /* soundcore stuff */
- int dev_audio;
- int dev_mixer;
- int dev_midi;
- int dev_dmfm;
-
- /* hardware resources */
- unsigned long iosb, ioenh, iosynth, iomidi; /* long for SPARC */
- unsigned int iodmaa, iodmac, irq;
-
- /* mixer stuff */
- struct {
- unsigned int modcnt;
-#ifndef OSS_DOCUMENTED_MIXER_SEMANTICS
- unsigned short vol[13];
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- } mix;
-
- /* wave stuff */
- unsigned int rateadc, ratedac;
- unsigned char fmt, enable;
-
- spinlock_t lock;
- struct mutex open_mutex;
- mode_t open_mode;
- wait_queue_head_t open_wait;
-
- struct dmabuf {
- void *rawbuf;
- dma_addr_t dmaaddr;
- unsigned buforder;
- unsigned numfrag;
- unsigned fragshift;
- unsigned hwptr, swptr;
- unsigned total_bytes;
- int count;
- unsigned error; /* over/underrun */
- wait_queue_head_t wait;
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize;
- unsigned fragsamples;
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned endcleared:1;
- unsigned enabled:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
- } dma_dac, dma_adc;
-
- /* midi stuff */
- struct {
- unsigned ird, iwr, icnt;
- unsigned ord, owr, ocnt;
- wait_queue_head_t iwait;
- wait_queue_head_t owait;
- struct timer_list timer;
- unsigned char ibuf[MIDIINBUF];
- unsigned char obuf[MIDIOUTBUF];
- } midi;
-
-#if SUPPORT_JOYSTICK
- struct gameport *gameport;
-#endif
-};
-
-/* --------------------------------------------------------------------- */
-
-static LIST_HEAD(devs);
-static unsigned long wavetable_mem;
-
-/* --------------------------------------------------------------------- */
-
-static inline unsigned ld2(unsigned int x)
-{
- unsigned r = 0;
-
- if (x >= 0x10000) {
- x >>= 16;
- r += 16;
- }
- if (x >= 0x100) {
- x >>= 8;
- r += 8;
- }
- if (x >= 0x10) {
- x >>= 4;
- r += 4;
- }
- if (x >= 4) {
- x >>= 2;
- r += 2;
- }
- if (x >= 2)
- r++;
- return r;
-}
-
-/* --------------------------------------------------------------------- */
-
-/*
- * Why use byte IO? Nobody knows, but S3 does it also in their Windows driver.
- */
-
-#undef DMABYTEIO
-
-static void set_dmaa(struct sv_state *s, unsigned int addr, unsigned int count)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmaa, u;
-
- count--;
- for (u = 4; u > 0; u--, addr >>= 8, io++)
- outb(addr & 0xff, io);
- for (u = 3; u > 0; u--, count >>= 8, io++)
- outb(count & 0xff, io);
-#else /* DMABYTEIO */
- count--;
- outl(addr, s->iodmaa + SV_DMA_ADDR0);
- outl(count, s->iodmaa + SV_DMA_COUNT0);
-#endif /* DMABYTEIO */
- outb(0x18, s->iodmaa + SV_DMA_MODE);
-}
-
-static void set_dmac(struct sv_state *s, unsigned int addr, unsigned int count)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmac, u;
-
- count >>= 1;
- count--;
- for (u = 4; u > 0; u--, addr >>= 8, io++)
- outb(addr & 0xff, io);
- for (u = 3; u > 0; u--, count >>= 8, io++)
- outb(count & 0xff, io);
-#else /* DMABYTEIO */
- count >>= 1;
- count--;
- outl(addr, s->iodmac + SV_DMA_ADDR0);
- outl(count, s->iodmac + SV_DMA_COUNT0);
-#endif /* DMABYTEIO */
- outb(0x14, s->iodmac + SV_DMA_MODE);
-}
-
-static inline unsigned get_dmaa(struct sv_state *s)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmaa+6, v = 0, u;
-
- for (u = 3; u > 0; u--, io--) {
- v <<= 8;
- v |= inb(io);
- }
- return v + 1;
-#else /* DMABYTEIO */
- return (inl(s->iodmaa + SV_DMA_COUNT0) & 0xffffff) + 1;
-#endif /* DMABYTEIO */
-}
-
-static inline unsigned get_dmac(struct sv_state *s)
-{
-#ifdef DMABYTEIO
- unsigned io = s->iodmac+6, v = 0, u;
-
- for (u = 3; u > 0; u--, io--) {
- v <<= 8;
- v |= inb(io);
- }
- return (v + 1) << 1;
-#else /* DMABYTEIO */
- return ((inl(s->iodmac + SV_DMA_COUNT0) & 0xffffff) + 1) << 1;
-#endif /* DMABYTEIO */
-}
-
-static void wrindir(struct sv_state *s, unsigned char idx, unsigned char data)
-{
- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb(data, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
-}
-
-static unsigned char rdindir(struct sv_state *s, unsigned char idx)
-{
- unsigned char v;
-
- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- v = inb(s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- return v;
-}
-
-static void set_fmt(struct sv_state *s, unsigned char mask, unsigned char data)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- outb(SV_CIDATAFMT | SV_CIADDR_MCE, s->ioenh + SV_CODEC_IADDR);
- if (mask) {
- s->fmt = inb(s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- }
- s->fmt = (s->fmt & mask) | data;
- outb(s->fmt, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- outb(0, s->ioenh + SV_CODEC_IADDR);
- spin_unlock_irqrestore(&s->lock, flags);
- udelay(10);
-}
-
-static void frobindir(struct sv_state *s, unsigned char idx, unsigned char mask, unsigned char data)
-{
- outb(idx & 0x3f, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb((inb(s->ioenh + SV_CODEC_IDATA) & mask) ^ data, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
-}
-
-#define REFFREQUENCY 24576000
-#define ADCMULT 512
-#define FULLRATE 48000
-
-static unsigned setpll(struct sv_state *s, unsigned char reg, unsigned rate)
-{
- unsigned long flags;
- unsigned char r, m=0, n=0;
- unsigned xm, xn, xr, xd, metric = ~0U;
- /* the warnings about m and n used uninitialized are bogus and may safely be ignored */
-
- if (rate < 625000/ADCMULT)
- rate = 625000/ADCMULT;
- if (rate > 150000000/ADCMULT)
- rate = 150000000/ADCMULT;
- /* slight violation of specs, needed for continuous sampling rates */
- for (r = 0; rate < 75000000/ADCMULT; r += 0x20, rate <<= 1);
- for (xn = 3; xn < 35; xn++)
- for (xm = 3; xm < 130; xm++) {
- xr = REFFREQUENCY/ADCMULT * xm / xn;
- xd = abs((signed)(xr - rate));
- if (xd < metric) {
- metric = xd;
- m = xm - 2;
- n = xn - 2;
- }
- }
- reg &= 0x3f;
- spin_lock_irqsave(&s->lock, flags);
- outb(reg, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb(m, s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- outb(reg+1, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- outb(r | n, s->ioenh + SV_CODEC_IDATA);
- spin_unlock_irqrestore(&s->lock, flags);
- udelay(10);
- return (REFFREQUENCY/ADCMULT * (m + 2) / (n + 2)) >> ((r >> 5) & 7);
-}
-
-#if 0
-
-static unsigned getpll(struct sv_state *s, unsigned char reg)
-{
- unsigned long flags;
- unsigned char m, n;
-
- reg &= 0x3f;
- spin_lock_irqsave(&s->lock, flags);
- outb(reg, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- m = inb(s->ioenh + SV_CODEC_IDATA);
- udelay(10);
- outb(reg+1, s->ioenh + SV_CODEC_IADDR);
- udelay(10);
- n = inb(s->ioenh + SV_CODEC_IDATA);
- spin_unlock_irqrestore(&s->lock, flags);
- udelay(10);
- return (REFFREQUENCY/ADCMULT * (m + 2) / ((n & 0x1f) + 2)) >> ((n >> 5) & 7);
-}
-
-#endif
-
-static void set_dac_rate(struct sv_state *s, unsigned rate)
-{
- unsigned div;
- unsigned long flags;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
- div = (rate * 65536 + FULLRATE/2) / FULLRATE;
- if (div > 65535)
- div = 65535;
- spin_lock_irqsave(&s->lock, flags);
- wrindir(s, SV_CIPCMSR1, div >> 8);
- wrindir(s, SV_CIPCMSR0, div);
- spin_unlock_irqrestore(&s->lock, flags);
- s->ratedac = (div * FULLRATE + 32768) / 65536;
-}
-
-static void set_adc_rate(struct sv_state *s, unsigned rate)
-{
- unsigned long flags;
- unsigned rate1, rate2, div;
-
- if (rate > 48000)
- rate = 48000;
- if (rate < 4000)
- rate = 4000;
- rate1 = setpll(s, SV_CIADCPLLM, rate);
- div = (48000 + rate/2) / rate;
- if (div > 8)
- div = 8;
- rate2 = (48000 + div/2) / div;
- spin_lock_irqsave(&s->lock, flags);
- wrindir(s, SV_CIADCALTSR, (div-1) << 4);
- if (abs((signed)(rate-rate2)) <= abs((signed)(rate-rate1))) {
- wrindir(s, SV_CIADCCLKSOURCE, 0x10);
- s->rateadc = rate2;
- } else {
- wrindir(s, SV_CIADCCLKSOURCE, 0x00);
- s->rateadc = rate1;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-static inline void stop_adc(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->enable &= ~SV_CENABLE_RE;
- wrindir(s, SV_CIENABLE, s->enable);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static inline void stop_dac(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- s->enable &= ~(SV_CENABLE_PPE | SV_CENABLE_PE);
- wrindir(s, SV_CIENABLE, s->enable);
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_dac(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if ((s->dma_dac.mapped || s->dma_dac.count > 0) && s->dma_dac.ready) {
- s->enable = (s->enable & ~SV_CENABLE_PPE) | SV_CENABLE_PE;
- wrindir(s, SV_CIENABLE, s->enable);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-static void start_adc(struct sv_state *s)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- if ((s->dma_adc.mapped || s->dma_adc.count < (signed)(s->dma_adc.dmasize - 2*s->dma_adc.fragsize))
- && s->dma_adc.ready) {
- s->enable |= SV_CENABLE_RE;
- wrindir(s, SV_CIENABLE, s->enable);
- }
- spin_unlock_irqrestore(&s->lock, flags);
-}
-
-/* --------------------------------------------------------------------- */
-
-#define DMABUF_DEFAULTORDER (17-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-static void dealloc_dmabuf(struct sv_state *s, struct dmabuf *db)
-{
- struct page *page, *pend;
-
- if (db->rawbuf) {
- /* undo marking the pages as reserved */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- ClearPageReserved(page);
- pci_free_consistent(s->dev, PAGE_SIZE << db->buforder, db->rawbuf, db->dmaaddr);
- }
- db->rawbuf = NULL;
- db->mapped = db->ready = 0;
-}
-
-
-/* DMAA is used for playback, DMAC is used for recording */
-
-static int prog_dmabuf(struct sv_state *s, unsigned rec)
-{
- struct dmabuf *db = rec ? &s->dma_adc : &s->dma_dac;
- unsigned rate = rec ? s->rateadc : s->ratedac;
- int order;
- unsigned bytepersec;
- unsigned bufs;
- struct page *page, *pend;
- unsigned char fmt;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- fmt = s->fmt;
- if (rec) {
- s->enable &= ~SV_CENABLE_RE;
- fmt >>= SV_CFMT_CSHIFT;
- } else {
- s->enable &= ~SV_CENABLE_PE;
- fmt >>= SV_CFMT_ASHIFT;
- }
- wrindir(s, SV_CIENABLE, s->enable);
- spin_unlock_irqrestore(&s->lock, flags);
- fmt &= SV_CFMT_MASK;
- db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
- if (!db->rawbuf) {
- db->ready = db->mapped = 0;
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--)
- if ((db->rawbuf = pci_alloc_consistent(s->dev, PAGE_SIZE << order, &db->dmaaddr)))
- break;
- if (!db->rawbuf)
- return -ENOMEM;
- db->buforder = order;
- if ((virt_to_bus(db->rawbuf) ^ (virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1)) & ~0xffff)
- printk(KERN_DEBUG "sv: DMA buffer crosses 64k boundary: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
- if ((virt_to_bus(db->rawbuf) + (PAGE_SIZE << db->buforder) - 1) & ~0xffffff)
- printk(KERN_DEBUG "sv: DMA buffer beyond 16MB: busaddr 0x%lx size %ld\n",
- virt_to_bus(db->rawbuf), PAGE_SIZE << db->buforder);
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- pend = virt_to_page(db->rawbuf + (PAGE_SIZE << db->buforder) - 1);
- for (page = virt_to_page(db->rawbuf); page <= pend; page++)
- SetPageReserved(page);
- }
- bytepersec = rate << sample_shift[fmt];
- bufs = PAGE_SIZE << db->buforder;
- if (db->ossfragshift) {
- if ((1000 << db->ossfragshift) < bytepersec)
- db->fragshift = ld2(bytepersec/1000);
- else
- db->fragshift = db->ossfragshift;
- } else {
- db->fragshift = ld2(bytepersec/100/(db->subdivision ? db->subdivision : 1));
- if (db->fragshift < 3)
- db->fragshift = 3;
- }
- db->numfrag = bufs >> db->fragshift;
- while (db->numfrag < 4 && db->fragshift > 3) {
- db->fragshift--;
- db->numfrag = bufs >> db->fragshift;
- }
- db->fragsize = 1 << db->fragshift;
- if (db->ossmaxfrags >= 4 && db->ossmaxfrags < db->numfrag)
- db->numfrag = db->ossmaxfrags;
- db->fragsamples = db->fragsize >> sample_shift[fmt];
- db->dmasize = db->numfrag << db->fragshift;
- memset(db->rawbuf, (fmt & SV_CFMT_16BIT) ? 0 : 0x80, db->dmasize);
- spin_lock_irqsave(&s->lock, flags);
- if (rec) {
- set_dmac(s, db->dmaaddr, db->numfrag << db->fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMACBASECOUNT1, (db->fragsamples-1) >> 8);
- wrindir(s, SV_CIDMACBASECOUNT0, db->fragsamples-1);
- } else {
- set_dmaa(s, db->dmaaddr, db->numfrag << db->fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMAABASECOUNT1, (db->fragsamples-1) >> 8);
- wrindir(s, SV_CIDMAABASECOUNT0, db->fragsamples-1);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- db->enabled = 1;
- db->ready = 1;
- return 0;
-}
-
-static inline void clear_advance(struct sv_state *s)
-{
- unsigned char c = (s->fmt & (SV_CFMT_16BIT << SV_CFMT_ASHIFT)) ? 0 : 0x80;
- unsigned char *buf = s->dma_dac.rawbuf;
- unsigned bsize = s->dma_dac.dmasize;
- unsigned bptr = s->dma_dac.swptr;
- unsigned len = s->dma_dac.fragsize;
-
- if (bptr + len > bsize) {
- unsigned x = bsize - bptr;
- memset(buf + bptr, c, x);
- bptr = 0;
- len -= x;
- }
- memset(buf + bptr, c, len);
-}
-
-/* call with spinlock held! */
-static void sv_update_ptr(struct sv_state *s)
-{
- unsigned hwptr;
- int diff;
-
- /* update ADC pointer */
- if (s->dma_adc.ready) {
- hwptr = (s->dma_adc.dmasize - get_dmac(s)) % s->dma_adc.dmasize;
- diff = (s->dma_adc.dmasize + hwptr - s->dma_adc.hwptr) % s->dma_adc.dmasize;
- s->dma_adc.hwptr = hwptr;
- s->dma_adc.total_bytes += diff;
- s->dma_adc.count += diff;
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- wake_up(&s->dma_adc.wait);
- if (!s->dma_adc.mapped) {
- if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
- s->enable &= ~SV_CENABLE_RE;
- wrindir(s, SV_CIENABLE, s->enable);
- s->dma_adc.error++;
- }
- }
- }
- /* update DAC pointer */
- if (s->dma_dac.ready) {
- hwptr = (s->dma_dac.dmasize - get_dmaa(s)) % s->dma_dac.dmasize;
- diff = (s->dma_dac.dmasize + hwptr - s->dma_dac.hwptr) % s->dma_dac.dmasize;
- s->dma_dac.hwptr = hwptr;
- s->dma_dac.total_bytes += diff;
- if (s->dma_dac.mapped) {
- s->dma_dac.count += diff;
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- wake_up(&s->dma_dac.wait);
- } else {
- s->dma_dac.count -= diff;
- if (s->dma_dac.count <= 0) {
- s->enable &= ~SV_CENABLE_PE;
- wrindir(s, SV_CIENABLE, s->enable);
- s->dma_dac.error++;
- } else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
- clear_advance(s);
- s->dma_dac.endcleared = 1;
- }
- if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
- wake_up(&s->dma_dac.wait);
- }
- }
-}
-
-/* hold spinlock for the following! */
-static void sv_handle_midi(struct sv_state *s)
-{
- unsigned char ch;
- int wake;
-
- wake = 0;
- while (!(inb(s->iomidi+1) & 0x80)) {
- ch = inb(s->iomidi);
- if (s->midi.icnt < MIDIINBUF) {
- s->midi.ibuf[s->midi.iwr] = ch;
- s->midi.iwr = (s->midi.iwr + 1) % MIDIINBUF;
- s->midi.icnt++;
- }
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.iwait);
- wake = 0;
- while (!(inb(s->iomidi+1) & 0x40) && s->midi.ocnt > 0) {
- outb(s->midi.obuf[s->midi.ord], s->iomidi);
- s->midi.ord = (s->midi.ord + 1) % MIDIOUTBUF;
- s->midi.ocnt--;
- if (s->midi.ocnt < MIDIOUTBUF-16)
- wake = 1;
- }
- if (wake)
- wake_up(&s->midi.owait);
-}
-
-static irqreturn_t sv_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct sv_state *s = (struct sv_state *)dev_id;
- unsigned int intsrc;
-
- /* fastpath out, to ease interrupt sharing */
- intsrc = inb(s->ioenh + SV_CODEC_STATUS);
- if (!(intsrc & (SV_CSTAT_DMAA | SV_CSTAT_DMAC | SV_CSTAT_MIDI)))
- return IRQ_NONE;
- spin_lock(&s->lock);
- sv_update_ptr(s);
- sv_handle_midi(s);
- spin_unlock(&s->lock);
- return IRQ_HANDLED;
-}
-
-static void sv_midi_timer(unsigned long data)
-{
- struct sv_state *s = (struct sv_state *)data;
- unsigned long flags;
-
- spin_lock_irqsave(&s->lock, flags);
- sv_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- s->midi.timer.expires = jiffies+1;
- add_timer(&s->midi.timer);
-}
-
-/* --------------------------------------------------------------------- */
-
-static const char invalid_magic[] = KERN_CRIT "sv: invalid magic value\n";
-
-#define VALIDATE_STATE(s) \
-({ \
- if (!(s) || (s)->magic != SV_MAGIC) { \
- printk(invalid_magic); \
- return -ENXIO; \
- } \
-})
-
-/* --------------------------------------------------------------------- */
-
-#define MT_4 1
-#define MT_5MUTE 2
-#define MT_4MUTEMONO 3
-#define MT_6MUTE 4
-
-static const struct {
- unsigned left:5;
- unsigned right:5;
- unsigned type:3;
- unsigned rec:3;
-} mixtable[SOUND_MIXER_NRDEVICES] = {
- [SOUND_MIXER_RECLEV] = { SV_CIMIX_ADCINL, SV_CIMIX_ADCINR, MT_4, 0 },
- [SOUND_MIXER_LINE1] = { SV_CIMIX_AUX1INL, SV_CIMIX_AUX1INR, MT_5MUTE, 5 },
- [SOUND_MIXER_CD] = { SV_CIMIX_CDINL, SV_CIMIX_CDINR, MT_5MUTE, 1 },
- [SOUND_MIXER_LINE] = { SV_CIMIX_LINEINL, SV_CIMIX_LINEINR, MT_5MUTE, 4 },
- [SOUND_MIXER_MIC] = { SV_CIMIX_MICIN, SV_CIMIX_ADCINL, MT_4MUTEMONO, 6 },
- [SOUND_MIXER_SYNTH] = { SV_CIMIX_SYNTHINL, SV_CIMIX_SYNTHINR, MT_5MUTE, 2 },
- [SOUND_MIXER_LINE2] = { SV_CIMIX_AUX2INL, SV_CIMIX_AUX2INR, MT_5MUTE, 3 },
- [SOUND_MIXER_VOLUME] = { SV_CIMIX_ANALOGINL, SV_CIMIX_ANALOGINR, MT_5MUTE, 7 },
- [SOUND_MIXER_PCM] = { SV_CIMIX_PCMINL, SV_CIMIX_PCMINR, MT_6MUTE, 0 }
-};
-
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-
-static int return_mixval(struct sv_state *s, unsigned i, int *arg)
-{
- unsigned long flags;
- unsigned char l, r, rl, rr;
-
- spin_lock_irqsave(&s->lock, flags);
- l = rdindir(s, mixtable[i].left);
- r = rdindir(s, mixtable[i].right);
- spin_unlock_irqrestore(&s->lock, flags);
- switch (mixtable[i].type) {
- case MT_4:
- r &= 0xf;
- l &= 0xf;
- rl = 10 + 6 * (l & 15);
- rr = 10 + 6 * (r & 15);
- break;
-
- case MT_4MUTEMONO:
- rl = 55 - 3 * (l & 15);
- if (r & 0x10)
- rl += 45;
- rr = rl;
- r = l;
- break;
-
- case MT_5MUTE:
- default:
- rl = 100 - 3 * (l & 31);
- rr = 100 - 3 * (r & 31);
- break;
-
- case MT_6MUTE:
- rl = 100 - 3 * (l & 63) / 2;
- rr = 100 - 3 * (r & 63) / 2;
- break;
- }
- if (l & 0x80)
- rl = 0;
- if (r & 0x80)
- rr = 0;
- return put_user((rr << 8) | rl, arg);
-}
-
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
-{
- [SOUND_MIXER_RECLEV] = 1,
- [SOUND_MIXER_LINE1] = 2,
- [SOUND_MIXER_CD] = 3,
- [SOUND_MIXER_LINE] = 4,
- [SOUND_MIXER_MIC] = 5,
- [SOUND_MIXER_SYNTH] = 6,
- [SOUND_MIXER_LINE2] = 7,
- [SOUND_MIXER_VOLUME] = 8,
- [SOUND_MIXER_PCM] = 9
-};
-
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
-
-static unsigned mixer_recmask(struct sv_state *s)
-{
- unsigned long flags;
- int i, j;
-
- spin_lock_irqsave(&s->lock, flags);
- j = rdindir(s, SV_CIMIX_ADCINL) >> 5;
- spin_unlock_irqrestore(&s->lock, flags);
- j &= 7;
- for (i = 0; i < SOUND_MIXER_NRDEVICES && mixtable[i].rec != j; i++);
- return 1 << i;
-}
-
-static int mixer_ioctl(struct sv_state *s, unsigned int cmd, unsigned long arg)
-{
- unsigned long flags;
- int i, val;
- unsigned char l, r, rl, rr;
- int __user *p = (int __user *)arg;
-
- VALIDATE_STATE(s);
- if (cmd == SOUND_MIXER_INFO) {
- mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, "SonicVibes", sizeof(info.id));
- strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
- info.modify_counter = s->mix.modcnt;
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == SOUND_OLD_MIXER_INFO) {
- _old_mixer_info info;
- memset(&info, 0, sizeof(info));
- strlcpy(info.id, "SonicVibes", sizeof(info.id));
- strlcpy(info.name, "S3 SonicVibes", sizeof(info.name));
- if (copy_to_user((void __user *)arg, &info, sizeof(info)))
- return -EFAULT;
- return 0;
- }
- if (cmd == OSS_GETVERSION)
- return put_user(SOUND_VERSION, p);
- if (cmd == SOUND_MIXER_PRIVATE1) { /* SRS settings */
- if (get_user(val, p))
- return -EFAULT;
- spin_lock_irqsave(&s->lock, flags);
- if (val & 1) {
- if (val & 2) {
- l = 4 - ((val >> 2) & 7);
- if (l & ~3)
- l = 4;
- r = 4 - ((val >> 5) & 7);
- if (r & ~3)
- r = 4;
- wrindir(s, SV_CISRSSPACE, l);
- wrindir(s, SV_CISRSCENTER, r);
- } else
- wrindir(s, SV_CISRSSPACE, 0x80);
- }
- l = rdindir(s, SV_CISRSSPACE);
- r = rdindir(s, SV_CISRSCENTER);
- spin_unlock_irqrestore(&s->lock, flags);
- if (l & 0x80)
- return put_user(0, p);
- return put_user(((4 - (l & 7)) << 2) | ((4 - (r & 7)) << 5) | 2, p);
- }
- if (_IOC_TYPE(cmd) != 'M' || _SIOC_SIZE(cmd) != sizeof(int))
- return -EINVAL;
- if (_SIOC_DIR(cmd) == _SIOC_READ) {
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- return put_user(mixer_recmask(s), p);
-
- case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].rec)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
- for (val = i = 0; i < SOUND_MIXER_NRDEVICES; i++)
- if (mixtable[i].type && mixtable[i].type != MT_4MUTEMONO)
- val |= 1 << i;
- return put_user(val, p);
-
- case SOUND_MIXER_CAPS:
- return put_user(SOUND_CAP_EXCL_INPUT, p);
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- return return_mixval(s, i, p);
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- if (!volidx[i])
- return -EINVAL;
- return put_user(s->mix.vol[volidx[i]-1], p);
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- }
- }
- if (_SIOC_DIR(cmd) != (_SIOC_READ|_SIOC_WRITE))
- return -EINVAL;
- s->mix.modcnt++;
- switch (_IOC_NR(cmd)) {
- case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
- if (get_user(val, p))
- return -EFAULT;
- i = hweight32(val);
- if (i == 0)
- return 0; /*val = mixer_recmask(s);*/
- else if (i > 1)
- val &= ~mixer_recmask(s);
- for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) {
- if (!(val & (1 << i)))
- continue;
- if (mixtable[i].rec)
- break;
- }
- if (i == SOUND_MIXER_NRDEVICES)
- return 0;
- spin_lock_irqsave(&s->lock, flags);
- frobindir(s, SV_CIMIX_ADCINL, 0x1f, mixtable[i].rec << 5);
- frobindir(s, SV_CIMIX_ADCINR, 0x1f, mixtable[i].rec << 5);
- spin_unlock_irqrestore(&s->lock, flags);
- return 0;
-
- default:
- i = _IOC_NR(cmd);
- if (i >= SOUND_MIXER_NRDEVICES || !mixtable[i].type)
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- l = val & 0xff;
- r = (val >> 8) & 0xff;
- if (mixtable[i].type == MT_4MUTEMONO)
- l = (r + l) / 2;
- if (l > 100)
- l = 100;
- if (r > 100)
- r = 100;
- spin_lock_irqsave(&s->lock, flags);
- switch (mixtable[i].type) {
- case MT_4:
- if (l >= 10)
- l -= 10;
- if (r >= 10)
- r -= 10;
- frobindir(s, mixtable[i].left, 0xf0, l / 6);
- frobindir(s, mixtable[i].right, 0xf0, l / 6);
- break;
-
- case MT_4MUTEMONO:
- rr = 0;
- if (l < 10)
- rl = 0x80;
- else {
- if (l >= 55) {
- rr = 0x10;
- l -= 45;
- }
- rl = (55 - l) / 3;
- }
- wrindir(s, mixtable[i].left, rl);
- frobindir(s, mixtable[i].right, ~0x10, rr);
- break;
-
- case MT_5MUTE:
- if (l < 7)
- rl = 0x80;
- else
- rl = (100 - l) / 3;
- if (r < 7)
- rr = 0x80;
- else
- rr = (100 - r) / 3;
- wrindir(s, mixtable[i].left, rl);
- wrindir(s, mixtable[i].right, rr);
- break;
-
- case MT_6MUTE:
- if (l < 6)
- rl = 0x80;
- else
- rl = (100 - l) * 2 / 3;
- if (r < 6)
- rr = 0x80;
- else
- rr = (100 - r) * 2 / 3;
- wrindir(s, mixtable[i].left, rl);
- wrindir(s, mixtable[i].right, rr);
- break;
- }
- spin_unlock_irqrestore(&s->lock, flags);
-#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
- return return_mixval(s, i, p);
-#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- if (!volidx[i])
- return -EINVAL;
- s->mix.vol[volidx[i]-1] = val;
- return put_user(s->mix.vol[volidx[i]-1], p);
-#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
- }
-}
-
-/* --------------------------------------------------------------------- */
-
-static int sv_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_state, devs);
- if (s->dev_mixer == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- return nonseekable_open(inode, file);
-}
-
-static int sv_release_mixdev(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
-
- VALIDATE_STATE(s);
- return 0;
-}
-
-static int sv_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- return mixer_ioctl((struct sv_state *)file->private_data, cmd, arg);
-}
-
-static /*const*/ struct file_operations sv_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = sv_ioctl_mixdev,
- .open = sv_open_mixdev,
- .release = sv_release_mixdev,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int drain_dac(struct sv_state *s, int nonblock)
-{
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- int count, tmo;
-
- if (s->dma_dac.mapped || !s->dma_dac.ready)
- return 0;
- add_wait_queue(&s->dma_dac.wait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (nonblock) {
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return -EBUSY;
- }
- tmo = 3 * HZ * (count + s->dma_dac.fragsize) / 2 / s->ratedac;
- tmo >>= sample_shift[(s->fmt >> SV_CFMT_ASHIFT) & SV_CFMT_MASK];
- if (!schedule_timeout(tmo + 1))
- printk(KERN_DEBUG "sv: dma timed out??\n");
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- return 0;
-}
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t sv_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_adc.mapped)
- return -ENXIO;
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- ret = 0;
-#if 0
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- spin_unlock_irqrestore(&s->lock, flags);
-#endif
- add_wait_queue(&s->dma_adc.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- swptr = s->dma_adc.swptr;
- cnt = s->dma_adc.dmasize-swptr;
- if (s->dma_adc.count < cnt)
- cnt = s->dma_adc.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_adc.enabled)
- start_adc(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "sv: read: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_adc.dmasize, s->dma_adc.fragsize, s->dma_adc.count,
- s->dma_adc.hwptr, s->dma_adc.swptr);
- stop_adc(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmac(s, virt_to_bus(s->dma_adc.rawbuf), s->dma_adc.numfrag << s->dma_adc.fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMACBASECOUNT1, (s->dma_adc.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMACBASECOUNT0, s->dma_adc.fragsamples-1);
- s->dma_adc.count = s->dma_adc.hwptr = s->dma_adc.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->dma_adc.rawbuf + swptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_adc.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_adc.swptr = swptr;
- s->dma_adc.count -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_adc.enabled)
- start_adc(s);
- }
- remove_wait_queue(&s->dma_adc.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-static ssize_t sv_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned swptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (s->dma_dac.mapped)
- return -ENXIO;
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- ret = 0;
-#if 0
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- spin_unlock_irqrestore(&s->lock, flags);
-#endif
- add_wait_queue(&s->dma_dac.wait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- if (s->dma_dac.count < 0) {
- s->dma_dac.count = 0;
- s->dma_dac.swptr = s->dma_dac.hwptr;
- }
- swptr = s->dma_dac.swptr;
- cnt = s->dma_dac.dmasize-swptr;
- if (s->dma_dac.count + cnt > s->dma_dac.dmasize)
- cnt = s->dma_dac.dmasize - s->dma_dac.count;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (s->dma_dac.enabled)
- start_dac(s);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- if (!schedule_timeout(HZ)) {
- printk(KERN_DEBUG "sv: write: chip lockup? dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- s->dma_dac.dmasize, s->dma_dac.fragsize, s->dma_dac.count,
- s->dma_dac.hwptr, s->dma_dac.swptr);
- stop_dac(s);
- spin_lock_irqsave(&s->lock, flags);
- set_dmaa(s, virt_to_bus(s->dma_dac.rawbuf), s->dma_dac.numfrag << s->dma_dac.fragshift);
- /* program enhanced mode registers */
- wrindir(s, SV_CIDMAABASECOUNT1, (s->dma_dac.fragsamples-1) >> 8);
- wrindir(s, SV_CIDMAABASECOUNT0, s->dma_dac.fragsamples-1);
- s->dma_dac.count = s->dma_dac.hwptr = s->dma_dac.swptr = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- }
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->dma_dac.rawbuf + swptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- swptr = (swptr + cnt) % s->dma_dac.dmasize;
- spin_lock_irqsave(&s->lock, flags);
- s->dma_dac.swptr = swptr;
- s->dma_dac.count += cnt;
- s->dma_dac.endcleared = 0;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- if (s->dma_dac.enabled)
- start_dac(s);
- }
- remove_wait_queue(&s->dma_dac.wait, &wait);
- set_current_state(TASK_RUNNING);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int sv_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE) {
- if (!s->dma_dac.ready && prog_dmabuf(s, 1))
- return 0;
- poll_wait(file, &s->dma_dac.wait, wait);
- }
- if (file->f_mode & FMODE_READ) {
- if (!s->dma_adc.ready && prog_dmabuf(s, 0))
- return 0;
- poll_wait(file, &s->dma_adc.wait, wait);
- }
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- if (file->f_mode & FMODE_READ) {
- if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->dma_dac.mapped) {
- if (s->dma_dac.count >= (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int sv_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- struct dmabuf *db;
- int ret = -EINVAL;
- unsigned long size;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(s, 1)) != 0)
- goto out;
- db = &s->dma_dac;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(s, 0)) != 0)
- goto out;
- db = &s->dma_adc;
- } else
- goto out;
- ret = -EINVAL;
- if (vma->vm_pgoff != 0)
- goto out;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << db->buforder))
- goto out;
- ret = -EAGAIN;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(db->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- goto out;
- db->mapped = 1;
- ret = 0;
-out:
- unlock_kernel();
- return ret;
-}
-
-static int sv_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int count;
- int val, mapped, ret;
- unsigned char fmtm, fmtd;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- VALIDATE_STATE(s);
- mapped = ((file->f_mode & FMODE_WRITE) && s->dma_dac.mapped) ||
- ((file->f_mode & FMODE_READ) && s->dma_adc.mapped);
- switch (cmd) {
- case OSS_GETVERSION:
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_SYNC:
- if (file->f_mode & FMODE_WRITE)
- return drain_dac(s, 0/*file->f_flags & O_NONBLOCK*/);
- return 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP, p);
-
- case SNDCTL_DSP_RESET:
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- synchronize_irq(s->irq);
- s->dma_dac.swptr = s->dma_dac.hwptr = s->dma_dac.count = s->dma_dac.total_bytes = 0;
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- synchronize_irq(s->irq);
- s->dma_adc.swptr = s->dma_adc.hwptr = s->dma_adc.count = s->dma_adc.total_bytes = 0;
- }
- return 0;
-
- case SNDCTL_DSP_SPEED:
- if (get_user(val, p))
- return -EFAULT;
- if (val >= 0) {
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- set_adc_rate(s, val);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- set_dac_rate(s, val);
- }
- }
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SNDCTL_DSP_STEREO:
- if (get_user(val, p))
- return -EFAULT;
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- return 0;
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- if (val != 0) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val >= 2)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_CSHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_CSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val >= 2)
- fmtd |= SV_CFMT_STEREO << SV_CFMT_ASHIFT;
- else
- fmtm &= ~(SV_CFMT_STEREO << SV_CFMT_ASHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT)
- : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p);
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask */
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Selects ONE fmt*/
- if (get_user(val, p))
- return -EFAULT;
- if (val != AFMT_QUERY) {
- fmtd = 0;
- fmtm = ~0;
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- s->dma_adc.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
- else
- fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_CSHIFT);
- }
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- s->dma_dac.ready = 0;
- if (val == AFMT_S16_LE)
- fmtd |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
- else
- fmtm &= ~(SV_CFMT_16BIT << SV_CFMT_ASHIFT);
- }
- set_fmt(s, fmtm, fmtd);
- }
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT)
- : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? AFMT_S16_LE : AFMT_U8, p);
-
- case SNDCTL_DSP_POST:
- return 0;
-
- case SNDCTL_DSP_GETTRIGGER:
- val = 0;
- if (file->f_mode & FMODE_READ && s->enable & SV_CENABLE_RE)
- val |= PCM_ENABLE_INPUT;
- if (file->f_mode & FMODE_WRITE && s->enable & SV_CENABLE_PE)
- val |= PCM_ENABLE_OUTPUT;
- return put_user(val, p);
-
- case SNDCTL_DSP_SETTRIGGER:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- if (val & PCM_ENABLE_INPUT) {
- if (!s->dma_adc.ready && (ret = prog_dmabuf(s, 1)))
- return ret;
- s->dma_adc.enabled = 1;
- start_adc(s);
- } else {
- s->dma_adc.enabled = 0;
- stop_adc(s);
- }
- }
- if (file->f_mode & FMODE_WRITE) {
- if (val & PCM_ENABLE_OUTPUT) {
- if (!s->dma_dac.ready && (ret = prog_dmabuf(s, 0)))
- return ret;
- s->dma_dac.enabled = 1;
- start_dac(s);
- } else {
- s->dma_dac.enabled = 0;
- stop_dac(s);
- }
- }
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- abinfo.fragsize = s->dma_dac.fragsize;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = s->dma_dac.dmasize - count;
- abinfo.fragstotal = s->dma_dac.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_dac.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- abinfo.fragsize = s->dma_adc.fragsize;
- count = s->dma_adc.count;
- if (count < 0)
- count = 0;
- abinfo.bytes = count;
- abinfo.fragstotal = s->dma_adc.numfrag;
- abinfo.fragments = abinfo.bytes >> s->dma_adc.fragshift;
- spin_unlock_irqrestore(&s->lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETODELAY:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- count = s->dma_dac.count;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count < 0)
- count = 0;
- return put_user(count, p);
-
- case SNDCTL_DSP_GETIPTR:
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- if (!s->dma_adc.ready && (val = prog_dmabuf(s, 1)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- cinfo.bytes = s->dma_adc.total_bytes;
- count = s->dma_adc.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_adc.fragshift;
- cinfo.ptr = s->dma_adc.hwptr;
- if (s->dma_adc.mapped)
- s->dma_adc.count &= s->dma_adc.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETOPTR:
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- if (!s->dma_dac.ready && (val = prog_dmabuf(s, 0)) != 0)
- return val;
- spin_lock_irqsave(&s->lock, flags);
- sv_update_ptr(s);
- cinfo.bytes = s->dma_dac.total_bytes;
- count = s->dma_dac.count;
- if (count < 0)
- count = 0;
- cinfo.blocks = count >> s->dma_dac.fragshift;
- cinfo.ptr = s->dma_dac.hwptr;
- if (s->dma_dac.mapped)
- s->dma_dac.count &= s->dma_dac.fragsize-1;
- spin_unlock_irqrestore(&s->lock, flags);
- if (copy_to_user(argp, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(s, 0)))
- return val;
- return put_user(s->dma_dac.fragsize, p);
- }
- if ((val = prog_dmabuf(s, 1)))
- return val;
- return put_user(s->dma_adc.fragsize, p);
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- if (file->f_mode & FMODE_READ) {
- s->dma_adc.ossfragshift = val & 0xffff;
- s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_adc.ossfragshift < 4)
- s->dma_adc.ossfragshift = 4;
- if (s->dma_adc.ossfragshift > 15)
- s->dma_adc.ossfragshift = 15;
- if (s->dma_adc.ossmaxfrags < 4)
- s->dma_adc.ossmaxfrags = 4;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->dma_dac.ossfragshift = val & 0xffff;
- s->dma_dac.ossmaxfrags = (val >> 16) & 0xffff;
- if (s->dma_dac.ossfragshift < 4)
- s->dma_dac.ossfragshift = 4;
- if (s->dma_dac.ossfragshift > 15)
- s->dma_dac.ossfragshift = 15;
- if (s->dma_dac.ossmaxfrags < 4)
- s->dma_dac.ossmaxfrags = 4;
- }
- return 0;
-
- case SNDCTL_DSP_SUBDIVIDE:
- if ((file->f_mode & FMODE_READ && s->dma_adc.subdivision) ||
- (file->f_mode & FMODE_WRITE && s->dma_dac.subdivision))
- return -EINVAL;
- if (get_user(val, p))
- return -EFAULT;
- if (val != 1 && val != 2 && val != 4)
- return -EINVAL;
- if (file->f_mode & FMODE_READ)
- s->dma_adc.subdivision = val;
- if (file->f_mode & FMODE_WRITE)
- s->dma_dac.subdivision = val;
- return 0;
-
- case SOUND_PCM_READ_RATE:
- return put_user((file->f_mode & FMODE_READ) ? s->rateadc : s->ratedac, p);
-
- case SOUND_PCM_READ_CHANNELS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_STEREO << SV_CFMT_CSHIFT)
- : (SV_CFMT_STEREO << SV_CFMT_ASHIFT))) ? 2 : 1, p);
-
- case SOUND_PCM_READ_BITS:
- return put_user((s->fmt & ((file->f_mode & FMODE_READ) ? (SV_CFMT_16BIT << SV_CFMT_CSHIFT)
- : (SV_CFMT_16BIT << SV_CFMT_ASHIFT))) ? 16 : 8, p);
-
- case SOUND_PCM_WRITE_FILTER:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_READ_FILTER:
- return -EINVAL;
-
- }
- return mixer_ioctl(s, cmd, arg);
-}
-
-static int sv_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned char fmtm = ~0, fmts = 0;
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_state, devs);
- if (!((s->dev_audio ^ minor) & ~0xf))
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & file->f_mode) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- if (file->f_mode & FMODE_READ) {
- fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_CSHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= SV_CFMT_16BIT << SV_CFMT_CSHIFT;
- s->dma_adc.ossfragshift = s->dma_adc.ossmaxfrags = s->dma_adc.subdivision = 0;
- s->dma_adc.enabled = 1;
- set_adc_rate(s, 8000);
- }
- if (file->f_mode & FMODE_WRITE) {
- fmtm &= ~((SV_CFMT_STEREO | SV_CFMT_16BIT) << SV_CFMT_ASHIFT);
- if ((minor & 0xf) == SND_DEV_DSP16)
- fmts |= SV_CFMT_16BIT << SV_CFMT_ASHIFT;
- s->dma_dac.ossfragshift = s->dma_dac.ossmaxfrags = s->dma_dac.subdivision = 0;
- s->dma_dac.enabled = 1;
- set_dac_rate(s, 8000);
- }
- set_fmt(s, fmtm, fmts);
- s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int sv_release(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
-
- VALIDATE_STATE(s);
- lock_kernel();
- if (file->f_mode & FMODE_WRITE)
- drain_dac(s, file->f_flags & O_NONBLOCK);
- mutex_lock(&s->open_mutex);
- if (file->f_mode & FMODE_WRITE) {
- stop_dac(s);
- dealloc_dmabuf(s, &s->dma_dac);
- }
- if (file->f_mode & FMODE_READ) {
- stop_adc(s);
- dealloc_dmabuf(s, &s->dma_adc);
- }
- s->open_mode &= ~(file->f_mode & (FMODE_READ|FMODE_WRITE));
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations sv_audio_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = sv_read,
- .write = sv_write,
- .poll = sv_poll,
- .ioctl = sv_ioctl,
- .mmap = sv_mmap,
- .open = sv_open,
- .release = sv_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static ssize_t sv_midi_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_WRITE, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.iwait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.ird;
- cnt = MIDIINBUF - ptr;
- if (s->midi.icnt < cnt)
- cnt = s->midi.icnt;
- if (cnt <= 0)
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_to_user(buffer, s->midi.ibuf + ptr, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIINBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.ird = ptr;
- s->midi.icnt -= cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- break;
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.iwait, &wait);
- return ret;
-}
-
-static ssize_t sv_midi_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- ssize_t ret;
- unsigned long flags;
- unsigned ptr;
- int cnt;
-
- VALIDATE_STATE(s);
- if (!access_ok(VERIFY_READ, buffer, count))
- return -EFAULT;
- if (count == 0)
- return 0;
- ret = 0;
- add_wait_queue(&s->midi.owait, &wait);
- while (count > 0) {
- spin_lock_irqsave(&s->lock, flags);
- ptr = s->midi.owr;
- cnt = MIDIOUTBUF - ptr;
- if (s->midi.ocnt + cnt > MIDIOUTBUF)
- cnt = MIDIOUTBUF - s->midi.ocnt;
- if (cnt <= 0) {
- __set_current_state(TASK_INTERRUPTIBLE);
- sv_handle_midi(s);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- if (file->f_flags & O_NONBLOCK) {
- if (!ret)
- ret = -EAGAIN;
- break;
- }
- schedule();
- if (signal_pending(current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(s->midi.obuf + ptr, buffer, cnt)) {
- if (!ret)
- ret = -EFAULT;
- break;
- }
- ptr = (ptr + cnt) % MIDIOUTBUF;
- spin_lock_irqsave(&s->lock, flags);
- s->midi.owr = ptr;
- s->midi.ocnt += cnt;
- spin_unlock_irqrestore(&s->lock, flags);
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- spin_lock_irqsave(&s->lock, flags);
- sv_handle_midi(s);
- spin_unlock_irqrestore(&s->lock, flags);
- }
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&s->midi.owait, &wait);
- return ret;
-}
-
-/* No kernel lock - we have our own spinlock */
-static unsigned int sv_midi_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- unsigned long flags;
- unsigned int mask = 0;
-
- VALIDATE_STATE(s);
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &s->midi.owait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &s->midi.iwait, wait);
- spin_lock_irqsave(&s->lock, flags);
- if (file->f_mode & FMODE_READ) {
- if (s->midi.icnt > 0)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- if (s->midi.ocnt < MIDIOUTBUF)
- mask |= POLLOUT | POLLWRNORM;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- return mask;
-}
-
-static int sv_midi_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_state, devs);
- if (s->dev_midi == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- //outb(inb(s->ioenh + SV_CODEC_CONTROL) | SV_CCTRL_WAVETABLE, s->ioenh + SV_CODEC_CONTROL);
- outb(inb(s->ioenh + SV_CODEC_INTMASK) | SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
- wrindir(s, SV_CIUARTCONTROL, 5); /* output MIDI data to external and internal synth */
- wrindir(s, SV_CIWAVETABLESRC, 1); /* Wavetable in PC RAM */
- outb(0xff, s->iomidi+1); /* reset command */
- outb(0x3f, s->iomidi+1); /* uart command */
- if (!(inb(s->iomidi+1) & 0x80))
- inb(s->iomidi);
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- init_timer(&s->midi.timer);
- s->midi.timer.expires = jiffies+1;
- s->midi.timer.data = (unsigned long)s;
- s->midi.timer.function = sv_midi_timer;
- add_timer(&s->midi.timer);
- }
- if (file->f_mode & FMODE_READ) {
- s->midi.ird = s->midi.iwr = s->midi.icnt = 0;
- }
- if (file->f_mode & FMODE_WRITE) {
- s->midi.ord = s->midi.owr = s->midi.ocnt = 0;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- s->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int sv_midi_release(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- DECLARE_WAITQUEUE(wait, current);
- unsigned long flags;
- unsigned count, tmo;
-
- VALIDATE_STATE(s);
-
- lock_kernel();
- if (file->f_mode & FMODE_WRITE) {
- add_wait_queue(&s->midi.owait, &wait);
- for (;;) {
- __set_current_state(TASK_INTERRUPTIBLE);
- spin_lock_irqsave(&s->lock, flags);
- count = s->midi.ocnt;
- spin_unlock_irqrestore(&s->lock, flags);
- if (count <= 0)
- break;
- if (signal_pending(current))
- break;
- if (file->f_flags & O_NONBLOCK) {
- remove_wait_queue(&s->midi.owait, &wait);
- set_current_state(TASK_RUNNING);
- unlock_kernel();
- return -EBUSY;
- }
- tmo = (count * HZ) / 3100;
- if (!schedule_timeout(tmo ? : 1) && tmo)
- printk(KERN_DEBUG "sv: midi timed out??\n");
- }
- remove_wait_queue(&s->midi.owait, &wait);
- set_current_state(TASK_RUNNING);
- }
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ|FMODE_MIDI_WRITE));
- spin_lock_irqsave(&s->lock, flags);
- if (!(s->open_mode & (FMODE_MIDI_READ | FMODE_MIDI_WRITE))) {
- outb(inb(s->ioenh + SV_CODEC_INTMASK) & ~SV_CINTMASK_MIDI, s->ioenh + SV_CODEC_INTMASK);
- del_timer(&s->midi.timer);
- }
- spin_unlock_irqrestore(&s->lock, flags);
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations sv_midi_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = sv_midi_read,
- .write = sv_midi_write,
- .poll = sv_midi_poll,
- .open = sv_midi_open,
- .release = sv_midi_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int sv_dmfm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- static const unsigned char op_offset[18] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
- 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15
- };
- struct sv_state *s = (struct sv_state *)file->private_data;
- struct dm_fm_voice v;
- struct dm_fm_note n;
- struct dm_fm_params p;
- unsigned int io;
- unsigned int regb;
-
- switch (cmd) {
- case FM_IOCTL_RESET:
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->iosynth);
- outb(0, s->iosynth+1);
- outb(regb, s->iosynth+2);
- outb(0, s->iosynth+3);
- }
- return 0;
-
- case FM_IOCTL_PLAY_NOTE:
- if (copy_from_user(&n, (void __user *)arg, sizeof(n)))
- return -EFAULT;
- if (n.voice >= 18)
- return -EINVAL;
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->iosynth+2;
- } else {
- regb = n.voice;
- io = s->iosynth;
- }
- outb(0xa0 + regb, io);
- outb(n.fnum & 0xff, io+1);
- outb(0xb0 + regb, io);
- outb(((n.fnum >> 8) & 3) | ((n.octave & 7) << 2) | ((n.key_on & 1) << 5), io+1);
- return 0;
-
- case FM_IOCTL_SET_VOICE:
- if (copy_from_user(&v, (void __user *)arg, sizeof(v)))
- return -EFAULT;
- if (v.voice >= 18)
- return -EINVAL;
- regb = op_offset[v.voice];
- io = s->iosynth + ((v.op & 1) << 1);
- outb(0x20 + regb, io);
- outb(((v.am & 1) << 7) | ((v.vibrato & 1) << 6) | ((v.do_sustain & 1) << 5) |
- ((v.kbd_scale & 1) << 4) | (v.harmonic & 0xf), io+1);
- outb(0x40 + regb, io);
- outb(((v.scale_level & 0x3) << 6) | (v.volume & 0x3f), io+1);
- outb(0x60 + regb, io);
- outb(((v.attack & 0xf) << 4) | (v.decay & 0xf), io+1);
- outb(0x80 + regb, io);
- outb(((v.sustain & 0xf) << 4) | (v.release & 0xf), io+1);
- outb(0xe0 + regb, io);
- outb(v.waveform & 0x7, io+1);
- if (n.voice >= 9) {
- regb = n.voice - 9;
- io = s->iosynth+2;
- } else {
- regb = n.voice;
- io = s->iosynth;
- }
- outb(0xc0 + regb, io);
- outb(((v.right & 1) << 5) | ((v.left & 1) << 4) | ((v.feedback & 7) << 1) |
- (v.connection & 1), io+1);
- return 0;
-
- case FM_IOCTL_SET_PARAMS:
- if (copy_from_user(&p, (void *__user )arg, sizeof(p)))
- return -EFAULT;
- outb(0x08, s->iosynth);
- outb((p.kbd_split & 1) << 6, s->iosynth+1);
- outb(0xbd, s->iosynth);
- outb(((p.am_depth & 1) << 7) | ((p.vib_depth & 1) << 6) | ((p.rhythm & 1) << 5) | ((p.bass & 1) << 4) |
- ((p.snare & 1) << 3) | ((p.tomtom & 1) << 2) | ((p.cymbal & 1) << 1) | (p.hihat & 1), s->iosynth+1);
- return 0;
-
- case FM_IOCTL_SET_OPL:
- outb(4, s->iosynth+2);
- outb(arg, s->iosynth+3);
- return 0;
-
- case FM_IOCTL_SET_MODE:
- outb(5, s->iosynth+2);
- outb(arg & 1, s->iosynth+3);
- return 0;
-
- default:
- return -EINVAL;
- }
-}
-
-static int sv_dmfm_open(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- DECLARE_WAITQUEUE(wait, current);
- struct list_head *list;
- struct sv_state *s;
-
- for (list = devs.next; ; list = list->next) {
- if (list == &devs)
- return -ENODEV;
- s = list_entry(list, struct sv_state, devs);
- if (s->dev_dmfm == minor)
- break;
- }
- VALIDATE_STATE(s);
- file->private_data = s;
- /* wait for device to become free */
- mutex_lock(&s->open_mutex);
- while (s->open_mode & FMODE_DMFM) {
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&s->open_mutex);
- return -EBUSY;
- }
- add_wait_queue(&s->open_wait, &wait);
- __set_current_state(TASK_INTERRUPTIBLE);
- mutex_unlock(&s->open_mutex);
- schedule();
- remove_wait_queue(&s->open_wait, &wait);
- set_current_state(TASK_RUNNING);
- if (signal_pending(current))
- return -ERESTARTSYS;
- mutex_lock(&s->open_mutex);
- }
- /* init the stuff */
- outb(1, s->iosynth);
- outb(0x20, s->iosynth+1); /* enable waveforms */
- outb(4, s->iosynth+2);
- outb(0, s->iosynth+3); /* no 4op enabled */
- outb(5, s->iosynth+2);
- outb(1, s->iosynth+3); /* enable OPL3 */
- s->open_mode |= FMODE_DMFM;
- mutex_unlock(&s->open_mutex);
- return nonseekable_open(inode, file);
-}
-
-static int sv_dmfm_release(struct inode *inode, struct file *file)
-{
- struct sv_state *s = (struct sv_state *)file->private_data;
- unsigned int regb;
-
- VALIDATE_STATE(s);
- lock_kernel();
- mutex_lock(&s->open_mutex);
- s->open_mode &= ~FMODE_DMFM;
- for (regb = 0xb0; regb < 0xb9; regb++) {
- outb(regb, s->iosynth);
- outb(0, s->iosynth+1);
- outb(regb, s->iosynth+2);
- outb(0, s->iosynth+3);
- }
- wake_up(&s->open_wait);
- mutex_unlock(&s->open_mutex);
- unlock_kernel();
- return 0;
-}
-
-static /*const*/ struct file_operations sv_dmfm_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = sv_dmfm_ioctl,
- .open = sv_dmfm_open,
- .release = sv_dmfm_release,
-};
-
-/* --------------------------------------------------------------------- */
-
-/* maximum number of devices; only used for command line params */
-#define NR_DEVICE 5
-
-static int reverb[NR_DEVICE];
-
-#if 0
-static int wavetable[NR_DEVICE];
-#endif
-
-static unsigned int devindex;
-
-module_param_array(reverb, bool, NULL, 0);
-MODULE_PARM_DESC(reverb, "if 1 enables the reverb circuitry. NOTE: your card must have the reverb RAM");
-#if 0
-MODULE_PARM(wavetable, "1-" __MODULE_STRING(NR_DEVICE) "i");
-MODULE_PARM_DESC(wavetable, "if 1 the wavetable synth is enabled");
-#endif
-
-MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
-MODULE_DESCRIPTION("S3 SonicVibes Driver");
-MODULE_LICENSE("GPL");
-
-
-/* --------------------------------------------------------------------- */
-
-static struct initvol {
- int mixch;
- int vol;
-} initvol[] __devinitdata = {
- { SOUND_MIXER_WRITE_RECLEV, 0x4040 },
- { SOUND_MIXER_WRITE_LINE1, 0x4040 },
- { SOUND_MIXER_WRITE_CD, 0x4040 },
- { SOUND_MIXER_WRITE_LINE, 0x4040 },
- { SOUND_MIXER_WRITE_MIC, 0x4040 },
- { SOUND_MIXER_WRITE_SYNTH, 0x4040 },
- { SOUND_MIXER_WRITE_LINE2, 0x4040 },
- { SOUND_MIXER_WRITE_VOLUME, 0x4040 },
- { SOUND_MIXER_WRITE_PCM, 0x4040 }
-};
-
-#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
- (pci_resource_flags((dev), (num)) & IORESOURCE_IO))
-
-#ifdef SUPPORT_JOYSTICK
-static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
-{
- struct gameport *gp;
-
- if (!request_region(io_port, SV_EXTENT_GAME, "S3 SonicVibes Gameport")) {
- printk(KERN_ERR "sv: gameport io ports are in use\n");
- return -EBUSY;
- }
-
- s->gameport = gp = gameport_allocate_port();
- if (!gp) {
- printk(KERN_ERR "sv: can not allocate memory for gameport\n");
- release_region(io_port, SV_EXTENT_GAME);
- return -ENOMEM;
- }
-
- gameport_set_name(gp, "S3 SonicVibes Gameport");
- gameport_set_phys(gp, "isa%04x/gameport0", io_port);
- gp->dev.parent = &s->dev->dev;
- gp->io = io_port;
-
- gameport_register_port(gp);
-
- return 0;
-}
-
-static inline void sv_unregister_gameport(struct sv_state *s)
-{
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, SV_EXTENT_GAME);
- }
-}
-#else
-static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; }
-static inline void sv_unregister_gameport(struct sv_state *s) { }
-#endif /* SUPPORT_JOYSTICK */
-
-static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
-{
- static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
- struct sv_state *s;
- mm_segment_t fs;
- int i, val, ret;
- int gpio;
- char *ddmaname;
- unsigned ddmanamelen;
-
- if ((ret=pci_enable_device(pcidev)))
- return ret;
-
- if (!RSRCISIOREGION(pcidev, RESOURCE_SB) ||
- !RSRCISIOREGION(pcidev, RESOURCE_ENH) ||
- !RSRCISIOREGION(pcidev, RESOURCE_SYNTH) ||
- !RSRCISIOREGION(pcidev, RESOURCE_MIDI) ||
- !RSRCISIOREGION(pcidev, RESOURCE_GAME))
- return -ENODEV;
- if (pcidev->irq == 0)
- return -ENODEV;
- if (pci_set_dma_mask(pcidev, DMA_24BIT_MASK)) {
- printk(KERN_WARNING "sonicvibes: architecture does not support 24bit PCI busmaster DMA\n");
- return -ENODEV;
- }
- /* try to allocate a DDMA resource if not already available */
- if (!RSRCISIOREGION(pcidev, RESOURCE_DDMA)) {
- pcidev->resource[RESOURCE_DDMA].start = 0;
- pcidev->resource[RESOURCE_DDMA].end = 2*SV_EXTENT_DMA-1;
- pcidev->resource[RESOURCE_DDMA].flags = PCI_BASE_ADDRESS_SPACE_IO | IORESOURCE_IO;
- ddmanamelen = strlen(sv_ddma_name)+1;
- if (!(ddmaname = kmalloc(ddmanamelen, GFP_KERNEL)))
- return -1;
- memcpy(ddmaname, sv_ddma_name, ddmanamelen);
- pcidev->resource[RESOURCE_DDMA].name = ddmaname;
- if (pci_assign_resource(pcidev, RESOURCE_DDMA)) {
- pcidev->resource[RESOURCE_DDMA].name = NULL;
- kfree(ddmaname);
- printk(KERN_ERR "sv: cannot allocate DDMA controller io ports\n");
- return -EBUSY;
- }
- }
- if (!(s = kmalloc(sizeof(struct sv_state), GFP_KERNEL))) {
- printk(KERN_WARNING "sv: out of memory\n");
- return -ENOMEM;
- }
- memset(s, 0, sizeof(struct sv_state));
- init_waitqueue_head(&s->dma_adc.wait);
- init_waitqueue_head(&s->dma_dac.wait);
- init_waitqueue_head(&s->open_wait);
- init_waitqueue_head(&s->midi.iwait);
- init_waitqueue_head(&s->midi.owait);
- mutex_init(&s->open_mutex);
- spin_lock_init(&s->lock);
- s->magic = SV_MAGIC;
- s->dev = pcidev;
- s->iosb = pci_resource_start(pcidev, RESOURCE_SB);
- s->ioenh = pci_resource_start(pcidev, RESOURCE_ENH);
- s->iosynth = pci_resource_start(pcidev, RESOURCE_SYNTH);
- s->iomidi = pci_resource_start(pcidev, RESOURCE_MIDI);
- s->iodmaa = pci_resource_start(pcidev, RESOURCE_DDMA);
- s->iodmac = pci_resource_start(pcidev, RESOURCE_DDMA) + SV_EXTENT_DMA;
- gpio = pci_resource_start(pcidev, RESOURCE_GAME);
- pci_write_config_dword(pcidev, 0x40, s->iodmaa | 9); /* enable and use extended mode */
- pci_write_config_dword(pcidev, 0x48, s->iodmac | 9); /* enable */
- printk(KERN_DEBUG "sv: io ports: %#lx %#lx %#lx %#lx %#x %#x %#x\n",
- s->iosb, s->ioenh, s->iosynth, s->iomidi, gpio, s->iodmaa, s->iodmac);
- s->irq = pcidev->irq;
-
- /* hack */
- pci_write_config_dword(pcidev, 0x60, wavetable_mem >> 12); /* wavetable base address */
-
- ret = -EBUSY;
- if (!request_region(s->ioenh, SV_EXTENT_ENH, "S3 SonicVibes PCM")) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->ioenh, s->ioenh+SV_EXTENT_ENH-1);
- goto err_region5;
- }
- if (!request_region(s->iodmaa, SV_EXTENT_DMA, "S3 SonicVibes DMAA")) {
- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmaa, s->iodmaa+SV_EXTENT_DMA-1);
- goto err_region4;
- }
- if (!request_region(s->iodmac, SV_EXTENT_DMA, "S3 SonicVibes DMAC")) {
- printk(KERN_ERR "sv: io ports %#x-%#x in use\n", s->iodmac, s->iodmac+SV_EXTENT_DMA-1);
- goto err_region3;
- }
- if (!request_region(s->iomidi, SV_EXTENT_MIDI, "S3 SonicVibes Midi")) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iomidi, s->iomidi+SV_EXTENT_MIDI-1);
- goto err_region2;
- }
- if (!request_region(s->iosynth, SV_EXTENT_SYNTH, "S3 SonicVibes Synth")) {
- printk(KERN_ERR "sv: io ports %#lx-%#lx in use\n", s->iosynth, s->iosynth+SV_EXTENT_SYNTH-1);
- goto err_region1;
- }
-
- /* initialize codec registers */
- outb(0x80, s->ioenh + SV_CODEC_CONTROL); /* assert reset */
- udelay(50);
- outb(0x00, s->ioenh + SV_CODEC_CONTROL); /* deassert reset */
- udelay(50);
- outb(SV_CCTRL_INTADRIVE | SV_CCTRL_ENHANCED /*| SV_CCTRL_WAVETABLE */
- | (reverb[devindex] ? SV_CCTRL_REVERB : 0), s->ioenh + SV_CODEC_CONTROL);
- inb(s->ioenh + SV_CODEC_STATUS); /* clear ints */
- wrindir(s, SV_CIDRIVECONTROL, 0); /* drive current 16mA */
- wrindir(s, SV_CIENABLE, s->enable = 0); /* disable DMAA and DMAC */
- outb(~(SV_CINTMASK_DMAA | SV_CINTMASK_DMAC), s->ioenh + SV_CODEC_INTMASK);
- /* outb(0xff, s->iodmaa + SV_DMA_RESET); */
- /* outb(0xff, s->iodmac + SV_DMA_RESET); */
- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
- wrindir(s, SV_CIADCCLKSOURCE, 0); /* use pll as ADC clock source */
- wrindir(s, SV_CIANALOGPWRDOWN, 0); /* power up the analog parts of the device */
- wrindir(s, SV_CIDIGITALPWRDOWN, 0); /* power up the digital parts of the device */
- setpll(s, SV_CIADCPLLM, 8000);
- wrindir(s, SV_CISRSSPACE, 0x80); /* SRS off */
- wrindir(s, SV_CIPCMSR0, (8000 * 65536 / FULLRATE) & 0xff);
- wrindir(s, SV_CIPCMSR1, ((8000 * 65536 / FULLRATE) >> 8) & 0xff);
- wrindir(s, SV_CIADCOUTPUT, 0);
- /* request irq */
- if ((ret=request_irq(s->irq,sv_interrupt,IRQF_SHARED,"S3 SonicVibes",s))) {
- printk(KERN_ERR "sv: irq %u in use\n", s->irq);
- goto err_irq;
- }
- printk(KERN_INFO "sv: found adapter at io %#lx irq %u dmaa %#06x dmac %#06x revision %u\n",
- s->ioenh, s->irq, s->iodmaa, s->iodmac, rdindir(s, SV_CIREVISION));
- /* register devices */
- if ((s->dev_audio = register_sound_dsp(&sv_audio_fops, -1)) < 0) {
- ret = s->dev_audio;
- goto err_dev1;
- }
- if ((s->dev_mixer = register_sound_mixer(&sv_mixer_fops, -1)) < 0) {
- ret = s->dev_mixer;
- goto err_dev2;
- }
- if ((s->dev_midi = register_sound_midi(&sv_midi_fops, -1)) < 0) {
- ret = s->dev_midi;
- goto err_dev3;
- }
- if ((s->dev_dmfm = register_sound_special(&sv_dmfm_fops, 15 /* ?? */)) < 0) {
- ret = s->dev_dmfm;
- goto err_dev4;
- }
- pci_set_master(pcidev); /* enable bus mastering */
- /* initialize the chips */
- fs = get_fs();
- set_fs(KERNEL_DS);
- val = SOUND_MASK_LINE|SOUND_MASK_SYNTH;
- mixer_ioctl(s, SOUND_MIXER_WRITE_RECSRC, (unsigned long)&val);
- for (i = 0; i < sizeof(initvol)/sizeof(initvol[0]); i++) {
- val = initvol[i].vol;
- mixer_ioctl(s, initvol[i].mixch, (unsigned long)&val);
- }
- set_fs(fs);
- /* register gameport */
- sv_register_gameport(s, gpio);
- /* store it in the driver field */
- pci_set_drvdata(pcidev, s);
- /* put it into driver list */
- list_add_tail(&s->devs, &devs);
- /* increment devindex */
- if (devindex < NR_DEVICE-1)
- devindex++;
- return 0;
-
- err_dev4:
- unregister_sound_midi(s->dev_midi);
- err_dev3:
- unregister_sound_mixer(s->dev_mixer);
- err_dev2:
- unregister_sound_dsp(s->dev_audio);
- err_dev1:
- printk(KERN_ERR "sv: cannot register misc device\n");
- free_irq(s->irq, s);
- err_irq:
- release_region(s->iosynth, SV_EXTENT_SYNTH);
- err_region1:
- release_region(s->iomidi, SV_EXTENT_MIDI);
- err_region2:
- release_region(s->iodmac, SV_EXTENT_DMA);
- err_region3:
- release_region(s->iodmaa, SV_EXTENT_DMA);
- err_region4:
- release_region(s->ioenh, SV_EXTENT_ENH);
- err_region5:
- kfree(s);
- return ret;
-}
-
-static void __devexit sv_remove(struct pci_dev *dev)
-{
- struct sv_state *s = pci_get_drvdata(dev);
-
- if (!s)
- return;
- list_del(&s->devs);
- outb(~0, s->ioenh + SV_CODEC_INTMASK); /* disable ints */
- synchronize_irq(s->irq);
- inb(s->ioenh + SV_CODEC_STATUS); /* ack interrupts */
- wrindir(s, SV_CIENABLE, 0); /* disable DMAA and DMAC */
- /*outb(0, s->iodmaa + SV_DMA_RESET);*/
- /*outb(0, s->iodmac + SV_DMA_RESET);*/
- free_irq(s->irq, s);
- sv_unregister_gameport(s);
- release_region(s->iodmac, SV_EXTENT_DMA);
- release_region(s->iodmaa, SV_EXTENT_DMA);
- release_region(s->ioenh, SV_EXTENT_ENH);
- release_region(s->iomidi, SV_EXTENT_MIDI);
- release_region(s->iosynth, SV_EXTENT_SYNTH);
- unregister_sound_dsp(s->dev_audio);
- unregister_sound_mixer(s->dev_mixer);
- unregister_sound_midi(s->dev_midi);
- unregister_sound_special(s->dev_dmfm);
- kfree(s);
- pci_set_drvdata(dev, NULL);
-}
-
-static struct pci_device_id id_table[] = {
- { PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_SONICVIBES, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, id_table);
-
-static struct pci_driver sv_driver = {
- .name = "sonicvibes",
- .id_table = id_table,
- .probe = sv_probe,
- .remove = __devexit_p(sv_remove),
-};
-
-static int __init init_sonicvibes(void)
-{
- printk(KERN_INFO "sv: version v0.31 time " __TIME__ " " __DATE__ "\n");
-#if 0
- if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
- printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
-#endif
- return pci_register_driver(&sv_driver);
-}
-
-static void __exit cleanup_sonicvibes(void)
-{
- printk(KERN_INFO "sv: unloading\n");
- pci_unregister_driver(&sv_driver);
- if (wavetable_mem)
- free_pages(wavetable_mem, 20-PAGE_SHIFT);
-}
-
-module_init(init_sonicvibes);
-module_exit(cleanup_sonicvibes);
-
-/* --------------------------------------------------------------------- */
-
-#ifndef MODULE
-
-/* format is: sonicvibes=[reverb] sonicvibesdmaio=dmaioaddr */
-
-static int __init sonicvibes_setup(char *str)
-{
- static unsigned __initdata nr_dev = 0;
-
- if (nr_dev >= NR_DEVICE)
- return 0;
-#if 0
- if (get_option(&str, &reverb[nr_dev]) == 2)
- (void)get_option(&str, &wavetable[nr_dev]);
-#else
- (void)get_option(&str, &reverb[nr_dev]);
-#endif
-
- nr_dev++;
- return 1;
-}
-
-__setup("sonicvibes=", sonicvibes_setup);
-
-#endif /* MODULE */
diff --git a/sound/oss/sound_calls.h b/sound/oss/sound_calls.h
index 1ae07509664f..87d8ad4a0340 100644
--- a/sound/oss/sound_calls.h
+++ b/sound/oss/sound_calls.h
@@ -13,8 +13,6 @@ int DMAbuf_move_wrpointer(int dev, int l);
void DMAbuf_init(int dev, int dma1, int dma2);
void DMAbuf_deinit(int dev);
int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode);
-int DMAbuf_open_dma (int dev);
-void DMAbuf_close_dma (int dev);
void DMAbuf_inputintr(int dev);
void DMAbuf_outputintr(int dev, int underflow_flag);
struct dma_buffparms;
@@ -73,7 +71,6 @@ unsigned int MIDIbuf_poll(int dev, struct file *file, poll_table * wait);
int MIDIbuf_avail(int dev);
void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count);
-void MIDIbuf_init(void);
/* From soundcard.c */
diff --git a/sound/oss/sound_syms.c b/sound/oss/sound_syms.c
deleted file mode 100644
index cb7c33fe5b05..000000000000
--- a/sound/oss/sound_syms.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * The sound core exports the following symbols to the rest of
- * modulespace.
- *
- * (C) Copyright 1997 Alan Cox, Licensed under the GNU GPL
- *
- * Thu May 27 1999 Andrew J. Kroll <ag784@freenet..buffalo..edu>
- * left out exported symbol... fixed
- */
-
-#include <linux/module.h>
-#include "sound_config.h"
-#include "sound_calls.h"
-
-char sound_syms_symbol;
-
-EXPORT_SYMBOL(mixer_devs);
-EXPORT_SYMBOL(audio_devs);
-EXPORT_SYMBOL(num_mixers);
-EXPORT_SYMBOL(num_audiodevs);
-
-EXPORT_SYMBOL(midi_devs);
-EXPORT_SYMBOL(num_midis);
-EXPORT_SYMBOL(synth_devs);
-
-EXPORT_SYMBOL(sound_timer_devs);
-
-EXPORT_SYMBOL(sound_install_audiodrv);
-EXPORT_SYMBOL(sound_install_mixer);
-EXPORT_SYMBOL(sound_alloc_dma);
-EXPORT_SYMBOL(sound_free_dma);
-EXPORT_SYMBOL(sound_open_dma);
-EXPORT_SYMBOL(sound_close_dma);
-EXPORT_SYMBOL(sound_alloc_mididev);
-EXPORT_SYMBOL(sound_alloc_mixerdev);
-EXPORT_SYMBOL(sound_alloc_timerdev);
-EXPORT_SYMBOL(sound_alloc_synthdev);
-EXPORT_SYMBOL(sound_unload_audiodev);
-EXPORT_SYMBOL(sound_unload_mididev);
-EXPORT_SYMBOL(sound_unload_mixerdev);
-EXPORT_SYMBOL(sound_unload_timerdev);
-EXPORT_SYMBOL(sound_unload_synthdev);
-
-EXPORT_SYMBOL(load_mixer_volumes);
-
-EXPORT_SYMBOL(conf_printf);
-EXPORT_SYMBOL(conf_printf2);
-
-MODULE_DESCRIPTION("OSS Sound subsystem");
-MODULE_AUTHOR("Hannu Savolainen, et al.");
diff --git a/sound/oss/sound_timer.c b/sound/oss/sound_timer.c
index bc2777dd2ef9..f0f0c19fbff7 100644
--- a/sound/oss/sound_timer.c
+++ b/sound/oss/sound_timer.c
@@ -1,5 +1,5 @@
/*
- * sound/sound_timer.c
+ * sound/oss/sound_timer.c
*/
/*
* Copyright (C) by Hannu Savolainen 1993-1997
@@ -76,6 +76,7 @@ void sound_timer_syncinterval(unsigned int new_usecs)
tmr_ctr = 0;
usecs_per_tmr = new_usecs;
}
+EXPORT_SYMBOL(sound_timer_syncinterval);
static void tmr_reset(void)
{
@@ -300,6 +301,7 @@ void sound_timer_interrupt(void)
}
spin_unlock_irqrestore(&lock,flags);
}
+EXPORT_SYMBOL(sound_timer_interrupt);
void sound_timer_init(struct sound_lowlev_timer *t, char *name)
{
@@ -321,3 +323,5 @@ void sound_timer_init(struct sound_lowlev_timer *t, char *name)
strcpy(sound_timer.info.name, name);
sound_timer_devs[n] = &sound_timer;
}
+EXPORT_SYMBOL(sound_timer_init);
+
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c
index 0860d6789715..2344d09c7114 100644
--- a/sound/oss/soundcard.c
+++ b/sound/oss/soundcard.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/sound/soundcard.c
+ * linux/sound/oss/soundcard.c
*
* Sound card driver for Linux
*
@@ -107,6 +107,7 @@ int *load_mixer_volumes(char *name, int *levels, int present)
mixer_vols[n].levels[i] = levels[i];
return mixer_vols[n].levels;
}
+EXPORT_SYMBOL(load_mixer_volumes);
static int set_mixer_levels(void __user * arg)
{
@@ -541,12 +542,6 @@ static int __init oss_init(void)
int err;
int i, j;
- /* drag in sound_syms.o */
- {
- extern char sound_syms_symbol;
- sound_syms_symbol = 0;
- }
-
#ifdef CONFIG_PCI
if(dmabug)
isa_dma_bridge_buggy = dmabug;
@@ -614,6 +609,8 @@ static void __exit oss_cleanup(void)
module_init(oss_init);
module_exit(oss_cleanup);
MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("OSS Sound subsystem");
+MODULE_AUTHOR("Hannu Savolainen, et al.");
int sound_alloc_dma(int chn, char *deviceID)
@@ -627,6 +624,7 @@ int sound_alloc_dma(int chn, char *deviceID)
return 0;
}
+EXPORT_SYMBOL(sound_alloc_dma);
int sound_open_dma(int chn, char *deviceID)
{
@@ -642,6 +640,7 @@ int sound_open_dma(int chn, char *deviceID)
dma_alloc_map[chn] = DMA_MAP_BUSY;
return 0;
}
+EXPORT_SYMBOL(sound_open_dma);
void sound_free_dma(int chn)
{
@@ -652,6 +651,7 @@ void sound_free_dma(int chn)
free_dma(chn);
dma_alloc_map[chn] = DMA_MAP_UNAVAIL;
}
+EXPORT_SYMBOL(sound_free_dma);
void sound_close_dma(int chn)
{
@@ -661,6 +661,7 @@ void sound_close_dma(int chn)
}
dma_alloc_map[chn] = DMA_MAP_FREE;
}
+EXPORT_SYMBOL(sound_close_dma);
static void do_sequencer_timer(unsigned long dummy)
{
@@ -714,6 +715,7 @@ void conf_printf(char *name, struct address_info *hw_config)
printk("\n");
#endif
}
+EXPORT_SYMBOL(conf_printf);
void conf_printf2(char *name, int base, int irq, int dma, int dma2)
{
@@ -734,3 +736,5 @@ void conf_printf2(char *name, int base, int irq, int dma, int dma2)
printk("\n");
#endif
}
+EXPORT_SYMBOL(conf_printf2);
+
diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c
index 9ed5211c3168..51f2fa615413 100644
--- a/sound/oss/sscape.c
+++ b/sound/oss/sscape.c
@@ -1,5 +1,5 @@
/*
- * sound/sscape.c
+ * sound/oss/sscape.c
*
* Low level driver for Ensoniq SoundScape
*
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c
index eb5ea32fd1b0..471c274c5000 100644
--- a/sound/oss/swarm_cs4297a.c
+++ b/sound/oss/swarm_cs4297a.c
@@ -725,7 +725,7 @@ static int serdma_reg_access(struct cs4297a_state *s, u64 data)
serdma_t *d = &s->dma_dac;
u64 *data_p;
unsigned swptr;
- int flags;
+ unsigned long flags;
serdma_descr_t *descr;
if (s->reg_request) {
@@ -2505,7 +2505,7 @@ static /*const */ struct file_operations cs4297a_audio_fops = {
.release = cs4297a_release,
};
-static void cs4297a_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void cs4297a_interrupt(int irq, void *dev_id)
{
struct cs4297a_state *s = (struct cs4297a_state *) dev_id;
u32 status;
diff --git a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c
index c9d04518b172..107534477a2f 100644
--- a/sound/oss/sys_timer.c
+++ b/sound/oss/sys_timer.c
@@ -1,5 +1,5 @@
/*
- * sound/sys_timer.c
+ * sound/oss/sys_timer.c
*
* The default timer for the Level 2 sequencer interface
* Uses the (1/HZ sec) timer of kernel.
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index 2813e4c8e365..7a363a178afd 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -488,10 +488,6 @@ static void ali_set_spdif_out_rate(struct trident_card *card, unsigned int rate)
static void ali_enable_special_channel(struct trident_state *stat);
static struct trident_channel *ali_alloc_rec_pcm_channel(struct trident_card *card);
static struct trident_channel *ali_alloc_pcm_channel(struct trident_card *card);
-static void ali_restore_regs(struct trident_card *card);
-static void ali_save_regs(struct trident_card *card);
-static int trident_suspend(struct pci_dev *dev, pm_message_t unused);
-static int trident_resume(struct pci_dev *dev);
static void ali_free_pcm_channel(struct trident_card *card, unsigned int channel);
static int ali_setup_multi_channels(struct trident_card *card, int chan_nums);
static unsigned int ali_get_spdif_in_rate(struct trident_card *card);
@@ -507,13 +503,6 @@ static int ali_allocate_other_states_resources(struct trident_state *state,
int chan_nums);
static void ali_free_other_states_resources(struct trident_state *state);
-/* save registers for ALi Power Management */
-static struct ali_saved_registers {
- unsigned long global_regs[ALI_GLOBAL_REGS];
- unsigned long channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];
- unsigned mixer_regs[ALI_MIXER_REGS];
-} ali_registers;
-
#define seek_offset(dma_ptr, buffer, cnt, offset, copy_count) do { \
(dma_ptr) += (offset); \
(buffer) += (offset); \
@@ -1822,7 +1811,7 @@ cyber_address_interrupt(struct trident_card *card)
}
static irqreturn_t
-trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+trident_interrupt(int irq, void *dev_id)
{
struct trident_card *card = (struct trident_card *) dev_id;
u32 event;
@@ -1873,7 +1862,7 @@ trident_read(struct file *file, char __user *buffer, size_t count, loff_t * ppos
unsigned swptr;
int cnt;
- pr_debug("trident: trident_read called, count = %d\n", count);
+ pr_debug("trident: trident_read called, count = %zd\n", count);
VALIDATE_STATE(state);
@@ -1989,7 +1978,7 @@ trident_write(struct file *file, const char __user *buffer, size_t count, loff_t
unsigned int copy_count;
int lret; /* for lock_set_fmt */
- pr_debug("trident: trident_write called, count = %d\n", count);
+ pr_debug("trident: trident_write called, count = %zd\n", count);
VALIDATE_STATE(state);
@@ -3280,8 +3269,8 @@ ali_setup_spdif_out(struct trident_card *card, int flag)
char temp;
struct pci_dev *pci_dev = NULL;
- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
+ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ pci_dev);
if (pci_dev == NULL)
return;
pci_read_config_byte(pci_dev, 0x61, &temp);
@@ -3295,6 +3284,8 @@ ali_setup_spdif_out(struct trident_card *card, int flag)
temp |= 0x10;
pci_write_config_byte(pci_dev, 0x7e, temp);
+ pci_dev_put(pci_dev);
+
ch = inb(TRID_REG(card, ALI_SCTRL));
outb(ch | ALI_SPDIF_OUT_ENABLE, TRID_REG(card, ALI_SCTRL));
ch = inb(TRID_REG(card, ALI_SPDIF_CTRL));
@@ -3501,16 +3492,19 @@ ali_close_multi_channels(void)
char temp = 0;
struct pci_dev *pci_dev = NULL;
- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
+ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ pci_dev);
if (pci_dev == NULL)
return -1;
+
pci_read_config_byte(pci_dev, 0x59, &temp);
temp &= ~0x80;
pci_write_config_byte(pci_dev, 0x59, temp);
- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
- pci_dev);
+ pci_dev_put(pci_dev);
+
+ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+ NULL);
if (pci_dev == NULL)
return -1;
@@ -3518,6 +3512,8 @@ ali_close_multi_channels(void)
temp &= ~0x20;
pci_write_config_byte(pci_dev, 0xB8, temp);
+ pci_dev_put(pci_dev);
+
return 0;
}
@@ -3528,21 +3524,26 @@ ali_setup_multi_channels(struct trident_card *card, int chan_nums)
char temp = 0;
struct pci_dev *pci_dev = NULL;
- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
+ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ pci_dev);
if (pci_dev == NULL)
return -1;
pci_read_config_byte(pci_dev, 0x59, &temp);
temp |= 0x80;
pci_write_config_byte(pci_dev, 0x59, temp);
- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
- pci_dev);
+ pci_dev_put(pci_dev);
+
+ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101,
+ NULL);
if (pci_dev == NULL)
return -1;
pci_read_config_byte(pci_dev, (int) 0xB8, &temp);
temp |= 0x20;
pci_write_config_byte(pci_dev, (int) 0xB8, (u8) temp);
+
+ pci_dev_put(pci_dev);
+
if (chan_nums == 6) {
dwValue = inl(TRID_REG(card, ALI_SCTRL)) | 0x000f0000;
outl(dwValue, TRID_REG(card, ALI_SCTRL));
@@ -3653,6 +3654,14 @@ ali_allocate_other_states_resources(struct trident_state *state, int chan_nums)
return 0;
}
+#ifdef CONFIG_PM
+/* save registers for ALi Power Management */
+static struct ali_saved_registers {
+ unsigned long global_regs[ALI_GLOBAL_REGS];
+ unsigned long channel_regs[ALI_CHANNELS][ALI_CHANNEL_REGS];
+ unsigned mixer_regs[ALI_MIXER_REGS];
+} ali_registers;
+
static void
ali_save_regs(struct trident_card *card)
{
@@ -3746,6 +3755,7 @@ trident_resume(struct pci_dev *dev)
}
return 0;
}
+#endif
static struct trident_channel *
ali_alloc_pcm_channel(struct trident_card *card)
@@ -4105,8 +4115,8 @@ ali_reset_5451(struct trident_card *card)
unsigned int dwVal;
unsigned short wCount, wReg;
- pci_dev = pci_find_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
- pci_dev);
+ pci_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533,
+ pci_dev);
if (pci_dev == NULL)
return -1;
@@ -4116,6 +4126,7 @@ ali_reset_5451(struct trident_card *card)
pci_read_config_dword(pci_dev, 0x7c, &dwVal);
pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff);
udelay(5000);
+ pci_dev_put(pci_dev);
pci_dev = card->pci_dev;
if (pci_dev == NULL)
@@ -4395,7 +4406,7 @@ trident_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
init_timer(&card->timer);
card->iobase = iobase;
- card->pci_dev = pci_dev;
+ card->pci_dev = pci_dev_get(pci_dev);
card->pci_id = pci_id->device;
card->revision = revision;
card->irq = pci_dev->irq;
@@ -4549,6 +4560,7 @@ out_unregister_sound_dsp:
out_free_irq:
free_irq(card->irq, card);
out_proc_fs:
+ pci_dev_put(card->pci_dev);
if (res) {
remove_proc_entry("ALi5451", NULL);
res = NULL;
@@ -4599,9 +4611,9 @@ trident_remove(struct pci_dev *pci_dev)
}
unregister_sound_dsp(card->dev_audio);
- kfree(card);
-
pci_set_drvdata(pci_dev, NULL);
+ pci_dev_put(card->pci_dev);
+ kfree(card);
}
MODULE_AUTHOR("Alan Cox, Aaron Holtzman, Ollie Lho, Ching Ling Lee, Muli Ben-Yehuda");
@@ -4616,8 +4628,10 @@ static struct pci_driver trident_pci_driver = {
.id_table = trident_pci_tbl,
.probe = trident_probe,
.remove = __devexit_p(trident_remove),
+#ifdef CONFIG_PM
.suspend = trident_suspend,
.resume = trident_resume
+#endif
};
static int __init
diff --git a/sound/oss/trix.c b/sound/oss/trix.c
index d1f1f154dcce..e04169e8e3f8 100644
--- a/sound/oss/trix.c
+++ b/sound/oss/trix.c
@@ -1,5 +1,5 @@
/*
- * sound/trix.c
+ * sound/oss/trix.c
*
* Low level driver for the MediaTrix AudioTrix Pro
* (MT-0002-PC Control Chip)
diff --git a/sound/oss/tuning.h b/sound/oss/tuning.h
index 858e1fe6c618..a73e3dd39f9a 100644
--- a/sound/oss/tuning.h
+++ b/sound/oss/tuning.h
@@ -1,13 +1,11 @@
-#ifdef SEQUENCER_C
-
-unsigned short semitone_tuning[24] =
+static unsigned short semitone_tuning[24] =
{
/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983,
/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784,
/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755
};
-unsigned short cent_tuning[100] =
+static unsigned short cent_tuning[100] =
{
/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041,
/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087,
@@ -23,7 +21,3 @@ unsigned short cent_tuning[100] =
/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564,
/* 96 */ 10570, 10576, 10582, 10589
};
-#else
-extern unsigned short semitone_tuning[24];
-extern unsigned short cent_tuning[100];
-#endif
diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c
index a3d75baf6df8..a446b826d5fc 100644
--- a/sound/oss/uart401.c
+++ b/sound/oss/uart401.c
@@ -1,5 +1,5 @@
/*
- * sound/uart401.c
+ * sound/oss/uart401.c
*
* MPU-401 UART driver (formerly uart401_midi.c)
*
@@ -96,7 +96,7 @@ static void uart401_input_loop(uart401_devc * devc)
printk(KERN_WARNING "Too much work in interrupt on uart401 (0x%X). UART jabbering ??\n", devc->base);
}
-irqreturn_t uart401intr(int irq, void *dev_id, struct pt_regs *dummy)
+irqreturn_t uart401intr(int irq, void *dev_id)
{
uart401_devc *devc = dev_id;
diff --git a/sound/oss/uart6850.c b/sound/oss/uart6850.c
index 74ae75f9e2dc..f3f914aa92ee 100644
--- a/sound/oss/uart6850.c
+++ b/sound/oss/uart6850.c
@@ -1,5 +1,5 @@
/*
- * sound/uart6850.c
+ * sound/oss/uart6850.c
*
*
* Copyright (C) by Hannu Savolainen 1993-1997
@@ -104,7 +104,7 @@ static void uart6850_input_loop(void)
}
}
-static irqreturn_t m6850intr(int irq, void *dev_id, struct pt_regs *dummy)
+static irqreturn_t m6850intr(int irq, void *dev_id)
{
if (input_avail())
uart6850_input_loop();
diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c
index a7ef04fab075..d952b2264da1 100644
--- a/sound/oss/v_midi.c
+++ b/sound/oss/v_midi.c
@@ -1,5 +1,5 @@
/*
- * sound/v_midi.c
+ * sound/oss/v_midi.c
*
* The low level driver for the Sound Blaster DS chips.
*
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
index 08d8c94d01b2..17837d4b5ed3 100644
--- a/sound/oss/via82cxxx_audio.c
+++ b/sound/oss/via82cxxx_audio.c
@@ -1547,7 +1547,7 @@ static int via_mixer_open (struct inode *inode, struct file *file)
DPRINTK ("ENTER\n");
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+ while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
drvr = pci_dev_driver (pdev);
if (drvr == &via_driver) {
assert (pci_get_drvdata (pdev) != NULL);
@@ -1562,6 +1562,7 @@ static int via_mixer_open (struct inode *inode, struct file *file)
return -ENODEV;
match:
+ pci_dev_put(pdev);
file->private_data = card->ac97;
DPRINTK ("EXIT, returning 0\n");
@@ -1911,7 +1912,7 @@ static void via_intr_channel (struct via_info *card, struct via_channel *chan)
}
-static irqreturn_t via_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t via_interrupt(int irq, void *dev_id)
{
struct via_info *card = dev_id;
u32 status32;
@@ -1926,7 +1927,7 @@ static irqreturn_t via_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
#ifdef CONFIG_MIDI_VIA82CXXX
if (card->midi_devc)
- uart401intr(irq, card->midi_devc, regs);
+ uart401intr(irq, card->midi_devc);
#endif
return IRQ_HANDLED;
}
@@ -1949,7 +1950,7 @@ static irqreturn_t via_interrupt(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static irqreturn_t via_new_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t via_new_interrupt(int irq, void *dev_id)
{
struct via_info *card = dev_id;
u32 status32;
@@ -3245,7 +3246,7 @@ static int via_dsp_open (struct inode *inode, struct file *file)
}
card = NULL;
- while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
+ while ((pdev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
drvr = pci_dev_driver (pdev);
if (drvr == &via_driver) {
assert (pci_get_drvdata (pdev) != NULL);
@@ -3264,6 +3265,7 @@ static int via_dsp_open (struct inode *inode, struct file *file)
return -ENODEV;
match:
+ pci_dev_put(pdev);
if (nonblock) {
if (!mutex_trylock(&card->open_mutex)) {
DPRINTK ("EXIT, returning -EAGAIN\n");
diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c
index 8932d89408ef..bb4a0969f461 100644
--- a/sound/oss/vidc.c
+++ b/sound/oss/vidc.c
@@ -372,7 +372,7 @@ static void vidc_audio_trigger(int dev, int enable_bits)
adev->flags |= DMA_ACTIVE;
dma_interrupt = vidc_audio_dma_interrupt;
- vidc_sound_dma_irq(0, NULL, NULL);
+ vidc_sound_dma_irq(0, NULL);
iomd_writeb(DMA_CR_E | 0x10, IOMD_SD0CR);
local_irq_restore(flags);
diff --git a/sound/oss/vidc.h b/sound/oss/vidc.h
index d5b8064dc565..0d1424751ecd 100644
--- a/sound/oss/vidc.h
+++ b/sound/oss/vidc.h
@@ -33,7 +33,7 @@ extern unsigned long vidc_fill_2x16_s(unsigned long ibuf, unsigned long iend,
* DMA Interrupt handler
*/
-extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref, struct pt_regs *regs);
+extern irqreturn_t vidc_sound_dma_irq(int irqnr, void *ref);
/*
* Filler routine pointer
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c
index 5f140c7586b3..6dfb9f4b03ec 100644
--- a/sound/oss/vwsnd.c
+++ b/sound/oss/vwsnd.c
@@ -2233,12 +2233,12 @@ static void vwsnd_audio_write_intr(vwsnd_dev_t *devc, unsigned int status)
pcm_output(devc, underflown, 0);
}
-static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t vwsnd_audio_intr(int irq, void *dev_id)
{
- vwsnd_dev_t *devc = (vwsnd_dev_t *) dev_id;
+ vwsnd_dev_t *devc = dev_id;
unsigned int status;
- DBGEV("(irq=%d, dev_id=0x%p, regs=0x%p)\n", irq, dev_id, regs);
+ DBGEV("(irq=%d, dev_id=0x%p)\n", irq, dev_id);
status = li_get_clear_intr_status(&devc->lith);
vwsnd_audio_read_intr(devc, status);
diff --git a/sound/oss/waveartist.c b/sound/oss/waveartist.c
index 22d26624b34a..c5bf363d32c2 100644
--- a/sound/oss/waveartist.c
+++ b/sound/oss/waveartist.c
@@ -1,5 +1,5 @@
/*
- * linux/drivers/sound/waveartist.c
+ * linux/sound/oss/waveartist.c
*
* The low level driver for the RWA010 Rockwell Wave Artist
* codec chip used in the Rebel.com NetWinder.
@@ -833,7 +833,7 @@ static struct audio_driver waveartist_audio_driver = {
static irqreturn_t
-waveartist_intr(int irq, void *dev_id, struct pt_regs *regs)
+waveartist_intr(int irq, void *dev_id)
{
wavnc_info *devc = (wavnc_info *)dev_id;
int irqstatus, status;
diff --git a/sound/oss/waveartist.h b/sound/oss/waveartist.h
index 2033fb87b247..dac4ca910d95 100644
--- a/sound/oss/waveartist.h
+++ b/sound/oss/waveartist.h
@@ -1,5 +1,5 @@
/*
- * linux/drivers/sound/waveartist.h
+ * linux/sound/oss/waveartist.h
*
* def file for Rockwell RWA010 chip set, as installed in Rebel.com NetWinder
*/
diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c
deleted file mode 100644
index 1dec3958cc7b..000000000000
--- a/sound/oss/wavfront.c
+++ /dev/null
@@ -1,3554 +0,0 @@
-/* -*- linux-c -*-
- *
- * sound/wavfront.c
- *
- * A Linux driver for Turtle Beach WaveFront Series (Maui, Tropez, Tropez Plus)
- *
- * This driver supports the onboard wavetable synthesizer (an ICS2115),
- * including patch, sample and program loading and unloading, conversion
- * of GUS patches during loading, and full user-level access to all
- * WaveFront commands. It tries to provide semi-intelligent patch and
- * sample management as well.
- *
- * It also provides support for the ICS emulation of an MPU-401. Full
- * support for the ICS emulation's "virtual MIDI mode" is provided in
- * wf_midi.c.
- *
- * Support is also provided for the Tropez Plus' onboard FX processor,
- * a Yamaha YSS225. Currently, code exists to configure the YSS225,
- * and there is an interface allowing tweaking of any of its memory
- * addresses. However, I have been unable to decipher the logical
- * positioning of the configuration info for various effects, so for
- * now, you just get the YSS225 in the same state as Turtle Beach's
- * "SETUPSND.EXE" utility leaves it.
- *
- * The boards' DAC/ADC (a Crystal CS4232) is supported by cs4232.[co],
- * This chip also controls the configuration of the card: the wavefront
- * synth is logical unit 4.
- *
- *
- * Supported devices:
- *
- * /dev/dsp - using cs4232+ad1848 modules, OSS compatible
- * /dev/midiNN and /dev/midiNN+1 - using wf_midi code, OSS compatible
- * /dev/synth00 - raw synth interface
- *
- **********************************************************************
- *
- * Copyright (C) by Paul Barton-Davis 1998
- *
- * Some portions of this file are taken from work that is
- * copyright (C) by Hannu Savolainen 1993-1996
- *
- * Although the relevant code here is all new, the handling of
- * sample/alias/multi- samples is entirely based on a driver by Matt
- * Martin and Rutger Nijlunsing which demonstrated how to get things
- * to work correctly. The GUS patch loading code has been almost
- * unaltered by me, except to fit formatting and function names in the
- * rest of the file. Many thanks to them.
- *
- * Appreciation and thanks to Hannu Savolainen for his early work on the Maui
- * driver, and answering a few questions while this one was developed.
- *
- * Absolutely NO thanks to Turtle Beach/Voyetra and Yamaha for their
- * complete lack of help in developing this driver, and in particular
- * for their utter silence in response to questions about undocumented
- * aspects of configuring a WaveFront soundcard, particularly the
- * effects processor.
- *
- * $Id: wavfront.c,v 0.7 1998/09/09 15:47:36 pbd Exp $
- *
- * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- *
- * Changes:
- * 11-10-2000 Bartlomiej Zolnierkiewicz <bkz@linux-ide.org>
- * Added some __init and __initdata to entries in yss225.c
- */
-
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/ptrace.h>
-#include <linux/fcntl.h>
-#include <linux/syscalls.h>
-#include <linux/ioport.h>
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include <linux/config.h>
-
-#include <linux/delay.h>
-
-#include "sound_config.h"
-
-#include <linux/wavefront.h>
-
-#define _MIDI_SYNTH_C_
-#define MIDI_SYNTH_NAME "WaveFront MIDI"
-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-/* Compile-time control of the extent to which OSS is supported.
-
- I consider /dev/sequencer to be an anachronism, but given its
- widespread usage by various Linux MIDI software, it seems worth
- offering support to it if it's not too painful. Instead of using
- /dev/sequencer, I recommend:
-
- for synth programming and patch loading: /dev/synthNN
- for kernel-synchronized MIDI sequencing: the ALSA sequencer
- for direct MIDI control: /dev/midiNN
-
- I have never tried static compilation into the kernel. The #if's
- for this are really just notes to myself about what the code is
- for.
-*/
-
-#define OSS_SUPPORT_SEQ 0x1 /* use of /dev/sequencer */
-#define OSS_SUPPORT_STATIC_INSTALL 0x2 /* static compilation into kernel */
-
-#define OSS_SUPPORT_LEVEL 0x1 /* just /dev/sequencer for now */
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-static int (*midi_load_patch) (int devno, int format, const char __user *addr,
- int offs, int count, int pmgr_flag) = NULL;
-#endif /* OSS_SUPPORT_SEQ */
-
-/* if WF_DEBUG not defined, no run-time debugging messages will
- be available via the debug flag setting. Given the current
- beta state of the driver, this will remain set until a future
- version.
-*/
-
-#define WF_DEBUG 1
-
-#ifdef WF_DEBUG
-
-/* Thank goodness for gcc's preprocessor ... */
-
-#define DPRINT(cond, format, args...) \
- if ((dev.debug & (cond)) == (cond)) { \
- printk (KERN_DEBUG LOGNAME format, ## args); \
- }
-#else
-#define DPRINT(cond, format, args...)
-#endif
-
-#define LOGNAME "WaveFront: "
-
-/* bitmasks for WaveFront status port value */
-
-#define STAT_RINTR_ENABLED 0x01
-#define STAT_CAN_READ 0x02
-#define STAT_INTR_READ 0x04
-#define STAT_WINTR_ENABLED 0x10
-#define STAT_CAN_WRITE 0x20
-#define STAT_INTR_WRITE 0x40
-
-/*** Module-accessible parameters ***************************************/
-
-static int wf_raw; /* we normally check for "raw state" to firmware
- loading. if set, then during driver loading, the
- state of the board is ignored, and we reset the
- board and load the firmware anyway.
- */
-
-static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in
- whatever state it is when the driver is loaded.
- The default is to download the microprogram and
- associated coefficients to set it up for "default"
- operation, whatever that means.
- */
-
-static int debug_default; /* you can set this to control debugging
- during driver loading. it takes any combination
- of the WF_DEBUG_* flags defined in
- wavefront.h
- */
-
-/* XXX this needs to be made firmware and hardware version dependent */
-
-static char *ospath = "/etc/sound/wavefront.os"; /* where to find a processed
- version of the WaveFront OS
- */
-
-static int wait_polls = 2000; /* This is a number of tries we poll the
- status register before resorting to sleeping.
- WaveFront being an ISA card each poll takes
- about 1.2us. So before going to
- sleep we wait up to 2.4ms in a loop.
- */
-
-static int sleep_length = HZ/100; /* This says how long we're going to
- sleep between polls.
- 10ms sounds reasonable for fast response.
- */
-
-static int sleep_tries = 50; /* Wait for status 0.5 seconds total. */
-
-static int reset_time = 2; /* hundreths of a second we wait after a HW reset for
- the expected interrupt.
- */
-
-static int ramcheck_time = 20; /* time in seconds to wait while ROM code
- checks on-board RAM.
- */
-
-static int osrun_time = 10; /* time in seconds we wait for the OS to
- start running.
- */
-
-module_param(wf_raw, int, 0);
-module_param(fx_raw, int, 0);
-module_param(debug_default, int, 0);
-module_param(wait_polls, int, 0);
-module_param(sleep_length, int, 0);
-module_param(sleep_tries, int, 0);
-module_param(ospath, charp, 0);
-module_param(reset_time, int, 0);
-module_param(ramcheck_time, int, 0);
-module_param(osrun_time, int, 0);
-
-/***************************************************************************/
-
-/* Note: because this module doesn't export any symbols, this really isn't
- a global variable, even if it looks like one. I was quite confused by
- this when I started writing this as a (newer) module -- pbd.
-*/
-
-struct wf_config {
- int devno; /* device number from kernel */
- int irq; /* "you were one, one of the few ..." */
- int base; /* low i/o port address */
-
-#define mpu_data_port base
-#define mpu_command_port base + 1 /* write semantics */
-#define mpu_status_port base + 1 /* read semantics */
-#define data_port base + 2
-#define status_port base + 3 /* read semantics */
-#define control_port base + 3 /* write semantics */
-#define block_port base + 4 /* 16 bit, writeonly */
-#define last_block_port base + 6 /* 16 bit, writeonly */
-
- /* FX ports. These are mapped through the ICS2115 to the YS225.
- The ICS2115 takes care of flipping the relevant pins on the
- YS225 so that access to each of these ports does the right
- thing. Note: these are NOT documented by Turtle Beach.
- */
-
-#define fx_status base + 8
-#define fx_op base + 8
-#define fx_lcr base + 9
-#define fx_dsp_addr base + 0xa
-#define fx_dsp_page base + 0xb
-#define fx_dsp_lsb base + 0xc
-#define fx_dsp_msb base + 0xd
-#define fx_mod_addr base + 0xe
-#define fx_mod_data base + 0xf
-
- volatile int irq_ok; /* set by interrupt handler */
- volatile int irq_cnt; /* ditto */
- int opened; /* flag, holds open(2) mode */
- char debug; /* debugging flags */
- int freemem; /* installed RAM, in bytes */
-
- int synth_dev; /* devno for "raw" synth */
- int mididev; /* devno for internal MIDI */
- int ext_mididev; /* devno for external MIDI */
- int fx_mididev; /* devno for FX MIDI interface */
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- int oss_dev; /* devno for OSS sequencer synth */
-#endif /* OSS_SUPPORT_SEQ */
-
- char fw_version[2]; /* major = [0], minor = [1] */
- char hw_version[2]; /* major = [0], minor = [1] */
- char israw; /* needs Motorola microcode */
- char has_fx; /* has FX processor (Tropez+) */
- char prog_status[WF_MAX_PROGRAM]; /* WF_SLOT_* */
- char patch_status[WF_MAX_PATCH]; /* WF_SLOT_* */
- char sample_status[WF_MAX_SAMPLE]; /* WF_ST_* | WF_SLOT_* */
- int samples_used; /* how many */
- char interrupts_on; /* h/w MPU interrupts enabled ? */
- char rom_samples_rdonly; /* can we write on ROM samples */
- wait_queue_head_t interrupt_sleeper;
-} dev;
-
-static DEFINE_SPINLOCK(lock);
-static int detect_wffx(void);
-static int wffx_ioctl (wavefront_fx_info *);
-static int wffx_init (void);
-
-static int wavefront_delete_sample (int sampnum);
-static int wavefront_find_free_sample (void);
-
-/* From wf_midi.c */
-
-extern int virtual_midi_enable (void);
-extern int virtual_midi_disable (void);
-extern int detect_wf_mpu (int, int);
-extern int install_wf_mpu (void);
-extern int uninstall_wf_mpu (void);
-
-typedef struct {
- int cmd;
- char *action;
- unsigned int read_cnt;
- unsigned int write_cnt;
- int need_ack;
-} wavefront_command;
-
-static struct {
- int errno;
- const char *errstr;
-} wavefront_errors[] = {
- { 0x01, "Bad sample number" },
- { 0x02, "Out of sample memory" },
- { 0x03, "Bad patch number" },
- { 0x04, "Error in number of voices" },
- { 0x06, "Sample load already in progress" },
- { 0x0B, "No sample load request pending" },
- { 0x0E, "Bad MIDI channel number" },
- { 0x10, "Download Record Error" },
- { 0x80, "Success" },
- { 0 }
-};
-
-#define NEEDS_ACK 1
-
-static wavefront_command wavefront_commands[] = {
- { WFC_SET_SYNTHVOL, "set synthesizer volume", 0, 1, NEEDS_ACK },
- { WFC_GET_SYNTHVOL, "get synthesizer volume", 1, 0, 0},
- { WFC_SET_NVOICES, "set number of voices", 0, 1, NEEDS_ACK },
- { WFC_GET_NVOICES, "get number of voices", 1, 0, 0 },
- { WFC_SET_TUNING, "set synthesizer tuning", 0, 2, NEEDS_ACK },
- { WFC_GET_TUNING, "get synthesizer tuning", 2, 0, 0 },
- { WFC_DISABLE_CHANNEL, "disable synth channel", 0, 1, NEEDS_ACK },
- { WFC_ENABLE_CHANNEL, "enable synth channel", 0, 1, NEEDS_ACK },
- { WFC_GET_CHANNEL_STATUS, "get synth channel status", 3, 0, 0 },
- { WFC_MISYNTH_OFF, "disable midi-in to synth", 0, 0, NEEDS_ACK },
- { WFC_MISYNTH_ON, "enable midi-in to synth", 0, 0, NEEDS_ACK },
- { WFC_VMIDI_ON, "enable virtual midi mode", 0, 0, NEEDS_ACK },
- { WFC_VMIDI_OFF, "disable virtual midi mode", 0, 0, NEEDS_ACK },
- { WFC_MIDI_STATUS, "report midi status", 1, 0, 0 },
- { WFC_FIRMWARE_VERSION, "report firmware version", 2, 0, 0 },
- { WFC_HARDWARE_VERSION, "report hardware version", 2, 0, 0 },
- { WFC_GET_NSAMPLES, "report number of samples", 2, 0, 0 },
- { WFC_INSTOUT_LEVELS, "report instantaneous output levels", 7, 0, 0 },
- { WFC_PEAKOUT_LEVELS, "report peak output levels", 7, 0, 0 },
- { WFC_DOWNLOAD_SAMPLE, "download sample",
- 0, WF_SAMPLE_BYTES, NEEDS_ACK },
- { WFC_DOWNLOAD_BLOCK, "download block", 0, 0, NEEDS_ACK},
- { WFC_DOWNLOAD_SAMPLE_HEADER, "download sample header",
- 0, WF_SAMPLE_HDR_BYTES, NEEDS_ACK },
- { WFC_UPLOAD_SAMPLE_HEADER, "upload sample header", 13, 2, 0 },
-
- /* This command requires a variable number of bytes to be written.
- There is a hack in wavefront_cmd() to support this. The actual
- count is passed in as the read buffer ptr, cast appropriately.
- Ugh.
- */
-
- { WFC_DOWNLOAD_MULTISAMPLE, "download multisample", 0, 0, NEEDS_ACK },
-
- /* This one is a hack as well. We just read the first byte of the
- response, don't fetch an ACK, and leave the rest to the
- calling function. Ugly, ugly, ugly.
- */
-
- { WFC_UPLOAD_MULTISAMPLE, "upload multisample", 2, 1, 0 },
- { WFC_DOWNLOAD_SAMPLE_ALIAS, "download sample alias",
- 0, WF_ALIAS_BYTES, NEEDS_ACK },
- { WFC_UPLOAD_SAMPLE_ALIAS, "upload sample alias", WF_ALIAS_BYTES, 2, 0},
- { WFC_DELETE_SAMPLE, "delete sample", 0, 2, NEEDS_ACK },
- { WFC_IDENTIFY_SAMPLE_TYPE, "identify sample type", 5, 2, 0 },
- { WFC_UPLOAD_SAMPLE_PARAMS, "upload sample parameters" },
- { WFC_REPORT_FREE_MEMORY, "report free memory", 4, 0, 0 },
- { WFC_DOWNLOAD_PATCH, "download patch", 0, 134, NEEDS_ACK },
- { WFC_UPLOAD_PATCH, "upload patch", 132, 2, 0 },
- { WFC_DOWNLOAD_PROGRAM, "download program", 0, 33, NEEDS_ACK },
- { WFC_UPLOAD_PROGRAM, "upload program", 32, 1, 0 },
- { WFC_DOWNLOAD_EDRUM_PROGRAM, "download enhanced drum program", 0, 9,
- NEEDS_ACK},
- { WFC_UPLOAD_EDRUM_PROGRAM, "upload enhanced drum program", 8, 1, 0},
- { WFC_SET_EDRUM_CHANNEL, "set enhanced drum program channel",
- 0, 1, NEEDS_ACK },
- { WFC_DISABLE_DRUM_PROGRAM, "disable drum program", 0, 1, NEEDS_ACK },
- { WFC_REPORT_CHANNEL_PROGRAMS, "report channel program numbers",
- 32, 0, 0 },
- { WFC_NOOP, "the no-op command", 0, 0, NEEDS_ACK },
- { 0x00 }
-};
-
-static const char *
-wavefront_errorstr (int errnum)
-
-{
- int i;
-
- for (i = 0; wavefront_errors[i].errstr; i++) {
- if (wavefront_errors[i].errno == errnum) {
- return wavefront_errors[i].errstr;
- }
- }
-
- return "Unknown WaveFront error";
-}
-
-static wavefront_command *
-wavefront_get_command (int cmd)
-
-{
- int i;
-
- for (i = 0; wavefront_commands[i].cmd != 0; i++) {
- if (cmd == wavefront_commands[i].cmd) {
- return &wavefront_commands[i];
- }
- }
-
- return (wavefront_command *) 0;
-}
-
-static inline int
-wavefront_status (void)
-
-{
- return inb (dev.status_port);
-}
-
-static int
-wavefront_wait (int mask)
-
-{
- int i;
-
- for (i = 0; i < wait_polls; i++)
- if (wavefront_status() & mask)
- return 1;
-
- for (i = 0; i < sleep_tries; i++) {
-
- if (wavefront_status() & mask) {
- set_current_state(TASK_RUNNING);
- return 1;
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(sleep_length);
- if (signal_pending(current))
- break;
- }
-
- set_current_state(TASK_RUNNING);
- return 0;
-}
-
-static int
-wavefront_read (void)
-
-{
- if (wavefront_wait (STAT_CAN_READ))
- return inb (dev.data_port);
-
- DPRINT (WF_DEBUG_DATA, "read timeout.\n");
-
- return -1;
-}
-
-static int
-wavefront_write (unsigned char data)
-
-{
- if (wavefront_wait (STAT_CAN_WRITE)) {
- outb (data, dev.data_port);
- return 0;
- }
-
- DPRINT (WF_DEBUG_DATA, "write timeout.\n");
-
- return -1;
-}
-
-static int
-wavefront_cmd (int cmd, unsigned char *rbuf, unsigned char *wbuf)
-
-{
- int ack;
- int i;
- int c;
- wavefront_command *wfcmd;
-
- if ((wfcmd = wavefront_get_command (cmd)) == (wavefront_command *) 0) {
- printk (KERN_WARNING LOGNAME "command 0x%x not supported.\n",
- cmd);
- return 1;
- }
-
- /* Hack to handle the one variable-size write command. See
- wavefront_send_multisample() for the other half of this
- gross and ugly strategy.
- */
-
- if (cmd == WFC_DOWNLOAD_MULTISAMPLE) {
- wfcmd->write_cnt = (unsigned int) rbuf;
- rbuf = NULL;
- }
-
- DPRINT (WF_DEBUG_CMD, "0x%x [%s] (%d,%d,%d)\n",
- cmd, wfcmd->action, wfcmd->read_cnt,
- wfcmd->write_cnt, wfcmd->need_ack);
-
- if (wavefront_write (cmd)) {
- DPRINT ((WF_DEBUG_IO|WF_DEBUG_CMD), "cannot request "
- "0x%x [%s].\n",
- cmd, wfcmd->action);
- return 1;
- }
-
- if (wfcmd->write_cnt > 0) {
- DPRINT (WF_DEBUG_DATA, "writing %d bytes "
- "for 0x%x\n",
- wfcmd->write_cnt, cmd);
-
- for (i = 0; i < wfcmd->write_cnt; i++) {
- if (wavefront_write (wbuf[i])) {
- DPRINT (WF_DEBUG_IO, "bad write for byte "
- "%d of 0x%x [%s].\n",
- i, cmd, wfcmd->action);
- return 1;
- }
-
- DPRINT (WF_DEBUG_DATA, "write[%d] = 0x%x\n",
- i, wbuf[i]);
- }
- }
-
- if (wfcmd->read_cnt > 0) {
- DPRINT (WF_DEBUG_DATA, "reading %d ints "
- "for 0x%x\n",
- wfcmd->read_cnt, cmd);
-
- for (i = 0; i < wfcmd->read_cnt; i++) {
-
- if ((c = wavefront_read()) == -1) {
- DPRINT (WF_DEBUG_IO, "bad read for byte "
- "%d of 0x%x [%s].\n",
- i, cmd, wfcmd->action);
- return 1;
- }
-
- /* Now handle errors. Lots of special cases here */
-
- if (c == 0xff) {
- if ((c = wavefront_read ()) == -1) {
- DPRINT (WF_DEBUG_IO, "bad read for "
- "error byte at "
- "read byte %d "
- "of 0x%x [%s].\n",
- i, cmd,
- wfcmd->action);
- return 1;
- }
-
- /* Can you believe this madness ? */
-
- if (c == 1 &&
- wfcmd->cmd == WFC_IDENTIFY_SAMPLE_TYPE) {
- rbuf[0] = WF_ST_EMPTY;
- return (0);
-
- } else if (c == 3 &&
- wfcmd->cmd == WFC_UPLOAD_PATCH) {
-
- return 3;
-
- } else if (c == 1 &&
- wfcmd->cmd == WFC_UPLOAD_PROGRAM) {
-
- return 1;
-
- } else {
-
- DPRINT (WF_DEBUG_IO, "error %d (%s) "
- "during "
- "read for byte "
- "%d of 0x%x "
- "[%s].\n",
- c,
- wavefront_errorstr (c),
- i, cmd,
- wfcmd->action);
- return 1;
-
- }
-
- } else {
- rbuf[i] = c;
- }
-
- DPRINT (WF_DEBUG_DATA, "read[%d] = 0x%x\n",i, rbuf[i]);
- }
- }
-
- if ((wfcmd->read_cnt == 0 && wfcmd->write_cnt == 0) || wfcmd->need_ack) {
-
- DPRINT (WF_DEBUG_CMD, "reading ACK for 0x%x\n", cmd);
-
- /* Some commands need an ACK, but return zero instead
- of the standard value.
- */
-
- if ((ack = wavefront_read()) == 0) {
- ack = WF_ACK;
- }
-
- if (ack != WF_ACK) {
- if (ack == -1) {
- DPRINT (WF_DEBUG_IO, "cannot read ack for "
- "0x%x [%s].\n",
- cmd, wfcmd->action);
- return 1;
-
- } else {
- int err = -1; /* something unknown */
-
- if (ack == 0xff) { /* explicit error */
-
- if ((err = wavefront_read ()) == -1) {
- DPRINT (WF_DEBUG_DATA,
- "cannot read err "
- "for 0x%x [%s].\n",
- cmd, wfcmd->action);
- }
- }
-
- DPRINT (WF_DEBUG_IO, "0x%x [%s] "
- "failed (0x%x, 0x%x, %s)\n",
- cmd, wfcmd->action, ack, err,
- wavefront_errorstr (err));
-
- return -err;
- }
- }
-
- DPRINT (WF_DEBUG_DATA, "ack received "
- "for 0x%x [%s]\n",
- cmd, wfcmd->action);
- } else {
-
- DPRINT (WF_DEBUG_CMD, "0x%x [%s] does not need "
- "ACK (%d,%d,%d)\n",
- cmd, wfcmd->action, wfcmd->read_cnt,
- wfcmd->write_cnt, wfcmd->need_ack);
- }
-
- return 0;
-
-}
-
-/***********************************************************************
-WaveFront: data munging
-
-Things here are weird. All data written to the board cannot
-have its most significant bit set. Any data item with values
-potentially > 0x7F (127) must be split across multiple bytes.
-
-Sometimes, we need to munge numeric values that are represented on
-the x86 side as 8-32 bit values. Sometimes, we need to munge data
-that is represented on the x86 side as an array of bytes. The most
-efficient approach to handling both cases seems to be to use 2
-different functions for munging and 2 for de-munging. This avoids
-weird casting and worrying about bit-level offsets.
-
-**********************************************************************/
-
-static
-unsigned char *
-munge_int32 (unsigned int src,
- unsigned char *dst,
- unsigned int dst_size)
-{
- int i;
-
- for (i = 0;i < dst_size; i++) {
- *dst = src & 0x7F; /* Mask high bit of LSB */
- src = src >> 7; /* Rotate Right 7 bits */
- /* Note: we leave the upper bits in place */
-
- dst++;
- };
- return dst;
-};
-
-static int
-demunge_int32 (unsigned char* src, int src_size)
-
-{
- int i;
- int outval = 0;
-
- for (i = src_size - 1; i >= 0; i--) {
- outval=(outval<<7)+src[i];
- }
-
- return outval;
-};
-
-static
-unsigned char *
-munge_buf (unsigned char *src, unsigned char *dst, unsigned int dst_size)
-
-{
- int i;
- unsigned int last = dst_size / 2;
-
- for (i = 0; i < last; i++) {
- *dst++ = src[i] & 0x7f;
- *dst++ = src[i] >> 7;
- }
- return dst;
-}
-
-static
-unsigned char *
-demunge_buf (unsigned char *src, unsigned char *dst, unsigned int src_bytes)
-
-{
- int i;
- unsigned char *end = src + src_bytes;
-
- end = src + src_bytes;
-
- /* NOTE: src and dst *CAN* point to the same address */
-
- for (i = 0; src != end; i++) {
- dst[i] = *src++;
- dst[i] |= (*src++)<<7;
- }
-
- return dst;
-}
-
-/***********************************************************************
-WaveFront: sample, patch and program management.
-***********************************************************************/
-
-static int
-wavefront_delete_sample (int sample_num)
-
-{
- unsigned char wbuf[2];
- int x;
-
- wbuf[0] = sample_num & 0x7f;
- wbuf[1] = sample_num >> 7;
-
- if ((x = wavefront_cmd (WFC_DELETE_SAMPLE, NULL, wbuf)) == 0) {
- dev.sample_status[sample_num] = WF_ST_EMPTY;
- }
-
- return x;
-}
-
-static int
-wavefront_get_sample_status (int assume_rom)
-
-{
- int i;
- unsigned char rbuf[32], wbuf[32];
- unsigned int sc_real, sc_alias, sc_multi;
-
- /* check sample status */
-
- if (wavefront_cmd (WFC_GET_NSAMPLES, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME "cannot request sample count.\n");
- return -1;
- }
-
- sc_real = sc_alias = sc_multi = dev.samples_used = 0;
-
- for (i = 0; i < WF_MAX_SAMPLE; i++) {
-
- wbuf[0] = i & 0x7f;
- wbuf[1] = i >> 7;
-
- if (wavefront_cmd (WFC_IDENTIFY_SAMPLE_TYPE, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "cannot identify sample "
- "type of slot %d\n", i);
- dev.sample_status[i] = WF_ST_EMPTY;
- continue;
- }
-
- dev.sample_status[i] = (WF_SLOT_FILLED|rbuf[0]);
-
- if (assume_rom) {
- dev.sample_status[i] |= WF_SLOT_ROM;
- }
-
- switch (rbuf[0] & WF_ST_MASK) {
- case WF_ST_SAMPLE:
- sc_real++;
- break;
- case WF_ST_MULTISAMPLE:
- sc_multi++;
- break;
- case WF_ST_ALIAS:
- sc_alias++;
- break;
- case WF_ST_EMPTY:
- break;
-
- default:
- printk (KERN_WARNING LOGNAME "unknown sample type for "
- "slot %d (0x%x)\n",
- i, rbuf[0]);
- }
-
- if (rbuf[0] != WF_ST_EMPTY) {
- dev.samples_used++;
- }
- }
-
- printk (KERN_INFO LOGNAME
- "%d samples used (%d real, %d aliases, %d multi), "
- "%d empty\n", dev.samples_used, sc_real, sc_alias, sc_multi,
- WF_MAX_SAMPLE - dev.samples_used);
-
-
- return (0);
-
-}
-
-static int
-wavefront_get_patch_status (void)
-
-{
- unsigned char patchbuf[WF_PATCH_BYTES];
- unsigned char patchnum[2];
- wavefront_patch *p;
- int i, x, cnt, cnt2;
-
- for (i = 0; i < WF_MAX_PATCH; i++) {
- patchnum[0] = i & 0x7f;
- patchnum[1] = i >> 7;
-
- if ((x = wavefront_cmd (WFC_UPLOAD_PATCH, patchbuf,
- patchnum)) == 0) {
-
- dev.patch_status[i] |= WF_SLOT_FILLED;
- p = (wavefront_patch *) patchbuf;
- dev.sample_status
- [p->sample_number|(p->sample_msb<<7)] |=
- WF_SLOT_USED;
-
- } else if (x == 3) { /* Bad patch number */
- dev.patch_status[i] = 0;
- } else {
- printk (KERN_ERR LOGNAME "upload patch "
- "error 0x%x\n", x);
- dev.patch_status[i] = 0;
- return 1;
- }
- }
-
- /* program status has already filled in slot_used bits */
-
- for (i = 0, cnt = 0, cnt2 = 0; i < WF_MAX_PATCH; i++) {
- if (dev.patch_status[i] & WF_SLOT_FILLED) {
- cnt++;
- }
- if (dev.patch_status[i] & WF_SLOT_USED) {
- cnt2++;
- }
-
- }
- printk (KERN_INFO LOGNAME
- "%d patch slots filled, %d in use\n", cnt, cnt2);
-
- return (0);
-}
-
-static int
-wavefront_get_program_status (void)
-
-{
- unsigned char progbuf[WF_PROGRAM_BYTES];
- wavefront_program prog;
- unsigned char prognum;
- int i, x, l, cnt;
-
- for (i = 0; i < WF_MAX_PROGRAM; i++) {
- prognum = i;
-
- if ((x = wavefront_cmd (WFC_UPLOAD_PROGRAM, progbuf,
- &prognum)) == 0) {
-
- dev.prog_status[i] |= WF_SLOT_USED;
-
- demunge_buf (progbuf, (unsigned char *) &prog,
- WF_PROGRAM_BYTES);
-
- for (l = 0; l < WF_NUM_LAYERS; l++) {
- if (prog.layer[l].mute) {
- dev.patch_status
- [prog.layer[l].patch_number] |=
- WF_SLOT_USED;
- }
- }
- } else if (x == 1) { /* Bad program number */
- dev.prog_status[i] = 0;
- } else {
- printk (KERN_ERR LOGNAME "upload program "
- "error 0x%x\n", x);
- dev.prog_status[i] = 0;
- }
- }
-
- for (i = 0, cnt = 0; i < WF_MAX_PROGRAM; i++) {
- if (dev.prog_status[i]) {
- cnt++;
- }
- }
-
- printk (KERN_INFO LOGNAME "%d programs slots in use\n", cnt);
-
- return (0);
-}
-
-static int
-wavefront_send_patch (wavefront_patch_info *header)
-
-{
- unsigned char buf[WF_PATCH_BYTES+2];
- unsigned char *bptr;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading patch %d\n",
- header->number);
-
- dev.patch_status[header->number] |= WF_SLOT_FILLED;
-
- bptr = buf;
- bptr = munge_int32 (header->number, buf, 2);
- munge_buf ((unsigned char *)&header->hdr.p, bptr, WF_PATCH_BYTES);
-
- if (wavefront_cmd (WFC_DOWNLOAD_PATCH, NULL, buf)) {
- printk (KERN_ERR LOGNAME "download patch failed\n");
- return -(EIO);
- }
-
- return (0);
-}
-
-static int
-wavefront_send_program (wavefront_patch_info *header)
-
-{
- unsigned char buf[WF_PROGRAM_BYTES+1];
- int i;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading program %d\n",
- header->number);
-
- dev.prog_status[header->number] = WF_SLOT_USED;
-
- /* XXX need to zero existing SLOT_USED bit for program_status[i]
- where `i' is the program that's being (potentially) overwritten.
- */
-
- for (i = 0; i < WF_NUM_LAYERS; i++) {
- if (header->hdr.pr.layer[i].mute) {
- dev.patch_status[header->hdr.pr.layer[i].patch_number] |=
- WF_SLOT_USED;
-
- /* XXX need to mark SLOT_USED for sample used by
- patch_number, but this means we have to load it. Ick.
- */
- }
- }
-
- buf[0] = header->number;
- munge_buf ((unsigned char *)&header->hdr.pr, &buf[1], WF_PROGRAM_BYTES);
-
- if (wavefront_cmd (WFC_DOWNLOAD_PROGRAM, NULL, buf)) {
- printk (KERN_WARNING LOGNAME "download patch failed\n");
- return -(EIO);
- }
-
- return (0);
-}
-
-static int
-wavefront_freemem (void)
-
-{
- char rbuf[8];
-
- if (wavefront_cmd (WFC_REPORT_FREE_MEMORY, rbuf, NULL)) {
- printk (KERN_WARNING LOGNAME "can't get memory stats.\n");
- return -1;
- } else {
- return demunge_int32 (rbuf, 4);
- }
-}
-
-static int
-wavefront_send_sample (wavefront_patch_info *header,
- UINT16 __user *dataptr,
- int data_is_unsigned)
-
-{
- /* samples are downloaded via a 16-bit wide i/o port
- (you could think of it as 2 adjacent 8-bit wide ports
- but its less efficient that way). therefore, all
- the blocksizes and so forth listed in the documentation,
- and used conventionally to refer to sample sizes,
- which are given in 8-bit units (bytes), need to be
- divided by 2.
- */
-
- UINT16 sample_short;
- UINT32 length;
- UINT16 __user *data_end = NULL;
- unsigned int i;
- const int max_blksize = 4096/2;
- unsigned int written;
- unsigned int blocksize;
- int dma_ack;
- int blocknum;
- unsigned char sample_hdr[WF_SAMPLE_HDR_BYTES];
- unsigned char *shptr;
- int skip = 0;
- int initial_skip = 0;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "sample %sdownload for slot %d, "
- "type %d, %d bytes from %p\n",
- header->size ? "" : "header ",
- header->number, header->subkey,
- header->size,
- header->dataptr);
-
- if (header->number == WAVEFRONT_FIND_FREE_SAMPLE_SLOT) {
- int x;
-
- if ((x = wavefront_find_free_sample ()) < 0) {
- return -ENOMEM;
- }
- printk (KERN_DEBUG LOGNAME "unspecified sample => %d\n", x);
- header->number = x;
- }
-
- if (header->size) {
-
- /* XXX it's a debatable point whether or not RDONLY semantics
- on the ROM samples should cover just the sample data or
- the sample header. For now, it only covers the sample data,
- so anyone is free at all times to rewrite sample headers.
-
- My reason for this is that we have the sample headers
- available in the WFB file for General MIDI, and so these
- can always be reset if needed. The sample data, however,
- cannot be recovered without a complete reset and firmware
- reload of the ICS2115, which is a very expensive operation.
-
- So, doing things this way allows us to honor the notion of
- "RESETSAMPLES" reasonably cheaply. Note however, that this
- is done purely at user level: there is no WFB parser in
- this driver, and so a complete reset (back to General MIDI,
- or theoretically some other configuration) is the
- responsibility of the user level library.
-
- To try to do this in the kernel would be a little
- crazy: we'd need 158K of kernel space just to hold
- a copy of the patch/program/sample header data.
- */
-
- if (dev.rom_samples_rdonly) {
- if (dev.sample_status[header->number] & WF_SLOT_ROM) {
- printk (KERN_ERR LOGNAME "sample slot %d "
- "write protected\n",
- header->number);
- return -EACCES;
- }
- }
-
- wavefront_delete_sample (header->number);
- }
-
- if (header->size) {
- dev.freemem = wavefront_freemem ();
-
- if (dev.freemem < header->size) {
- printk (KERN_ERR LOGNAME
- "insufficient memory to "
- "load %d byte sample.\n",
- header->size);
- return -ENOMEM;
- }
-
- }
-
- skip = WF_GET_CHANNEL(&header->hdr.s);
-
- if (skip > 0 && header->hdr.s.SampleResolution != LINEAR_16BIT) {
- printk (KERN_ERR LOGNAME "channel selection only "
- "possible on 16-bit samples");
- return -(EINVAL);
- }
-
- switch (skip) {
- case 0:
- initial_skip = 0;
- skip = 1;
- break;
- case 1:
- initial_skip = 0;
- skip = 2;
- break;
- case 2:
- initial_skip = 1;
- skip = 2;
- break;
- case 3:
- initial_skip = 2;
- skip = 3;
- break;
- case 4:
- initial_skip = 3;
- skip = 4;
- break;
- case 5:
- initial_skip = 4;
- skip = 5;
- break;
- case 6:
- initial_skip = 5;
- skip = 6;
- break;
- }
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "channel selection: %d => "
- "initial skip = %d, skip = %d\n",
- WF_GET_CHANNEL (&header->hdr.s),
- initial_skip, skip);
-
- /* Be safe, and zero the "Unused" bits ... */
-
- WF_SET_CHANNEL(&header->hdr.s, 0);
-
- /* adjust size for 16 bit samples by dividing by two. We always
- send 16 bits per write, even for 8 bit samples, so the length
- is always half the size of the sample data in bytes.
- */
-
- length = header->size / 2;
-
- /* the data we're sent has not been munged, and in fact, the
- header we have to send isn't just a munged copy either.
- so, build the sample header right here.
- */
-
- shptr = &sample_hdr[0];
-
- shptr = munge_int32 (header->number, shptr, 2);
-
- if (header->size) {
- shptr = munge_int32 (length, shptr, 4);
- }
-
- /* Yes, a 4 byte result doesn't contain all of the offset bits,
- but the offset only uses 24 bits.
- */
-
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleStartOffset),
- shptr, 4);
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopStartOffset),
- shptr, 4);
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.loopEndOffset),
- shptr, 4);
- shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset),
- shptr, 4);
-
- /* This one is truly weird. What kind of weirdo decided that in
- a system dominated by 16 and 32 bit integers, they would use
- a just 12 bits ?
- */
-
- shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3);
-
- /* Why is this nybblified, when the MSB is *always* zero ?
- Anyway, we can't take address of bitfield, so make a
- good-faith guess at where it starts.
- */
-
- shptr = munge_int32 (*(&header->hdr.s.FrequencyBias+1),
- shptr, 2);
-
- if (wavefront_cmd (header->size ?
- WFC_DOWNLOAD_SAMPLE : WFC_DOWNLOAD_SAMPLE_HEADER,
- NULL, sample_hdr)) {
- printk (KERN_WARNING LOGNAME "sample %sdownload refused.\n",
- header->size ? "" : "header ");
- return -(EIO);
- }
-
- if (header->size == 0) {
- goto sent; /* Sorry. Just had to have one somewhere */
- }
-
- data_end = dataptr + length;
-
- /* Do any initial skip over an unused channel's data */
-
- dataptr += initial_skip;
-
- for (written = 0, blocknum = 0;
- written < length; written += max_blksize, blocknum++) {
-
- if ((length - written) > max_blksize) {
- blocksize = max_blksize;
- } else {
- /* round to nearest 16-byte value */
- blocksize = ((length-written+7)&~0x7);
- }
-
- if (wavefront_cmd (WFC_DOWNLOAD_BLOCK, NULL, NULL)) {
- printk (KERN_WARNING LOGNAME "download block "
- "request refused.\n");
- return -(EIO);
- }
-
- for (i = 0; i < blocksize; i++) {
-
- if (dataptr < data_end) {
-
- __get_user (sample_short, dataptr);
- dataptr += skip;
-
- if (data_is_unsigned) { /* GUS ? */
-
- if (WF_SAMPLE_IS_8BIT(&header->hdr.s)) {
-
- /* 8 bit sample
- resolution, sign
- extend both bytes.
- */
-
- ((unsigned char*)
- &sample_short)[0] += 0x7f;
- ((unsigned char*)
- &sample_short)[1] += 0x7f;
-
- } else {
-
- /* 16 bit sample
- resolution, sign
- extend the MSB.
- */
-
- sample_short += 0x7fff;
- }
- }
-
- } else {
-
- /* In padding section of final block:
-
- Don't fetch unsupplied data from
- user space, just continue with
- whatever the final value was.
- */
- }
-
- if (i < blocksize - 1) {
- outw (sample_short, dev.block_port);
- } else {
- outw (sample_short, dev.last_block_port);
- }
- }
-
- /* Get "DMA page acknowledge", even though its really
- nothing to do with DMA at all.
- */
-
- if ((dma_ack = wavefront_read ()) != WF_DMA_ACK) {
- if (dma_ack == -1) {
- printk (KERN_ERR LOGNAME "upload sample "
- "DMA ack timeout\n");
- return -(EIO);
- } else {
- printk (KERN_ERR LOGNAME "upload sample "
- "DMA ack error 0x%x\n",
- dma_ack);
- return -(EIO);
- }
- }
- }
-
- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_SAMPLE);
-
- /* Note, label is here because sending the sample header shouldn't
- alter the sample_status info at all.
- */
-
- sent:
- return (0);
-}
-
-static int
-wavefront_send_alias (wavefront_patch_info *header)
-
-{
- unsigned char alias_hdr[WF_ALIAS_BYTES];
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "download alias, %d is "
- "alias for %d\n",
- header->number,
- header->hdr.a.OriginalSample);
-
- munge_int32 (header->number, &alias_hdr[0], 2);
- munge_int32 (header->hdr.a.OriginalSample, &alias_hdr[2], 2);
- munge_int32 (*((unsigned int *)&header->hdr.a.sampleStartOffset),
- &alias_hdr[4], 4);
- munge_int32 (*((unsigned int *)&header->hdr.a.loopStartOffset),
- &alias_hdr[8], 4);
- munge_int32 (*((unsigned int *)&header->hdr.a.loopEndOffset),
- &alias_hdr[12], 4);
- munge_int32 (*((unsigned int *)&header->hdr.a.sampleEndOffset),
- &alias_hdr[16], 4);
- munge_int32 (header->hdr.a.FrequencyBias, &alias_hdr[20], 3);
- munge_int32 (*(&header->hdr.a.FrequencyBias+1), &alias_hdr[23], 2);
-
- if (wavefront_cmd (WFC_DOWNLOAD_SAMPLE_ALIAS, NULL, alias_hdr)) {
- printk (KERN_ERR LOGNAME "download alias failed.\n");
- return -(EIO);
- }
-
- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_ALIAS);
-
- return (0);
-}
-
-static int
-wavefront_send_multisample (wavefront_patch_info *header)
-{
- int i;
- int num_samples;
- unsigned char msample_hdr[WF_MSAMPLE_BYTES];
-
- munge_int32 (header->number, &msample_hdr[0], 2);
-
- /* You'll recall at this point that the "number of samples" value
- in a wavefront_multisample struct is actually the log2 of the
- real number of samples.
- */
-
- num_samples = (1<<(header->hdr.ms.NumberOfSamples&7));
- msample_hdr[2] = (unsigned char) header->hdr.ms.NumberOfSamples;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "multi %d with %d=%d samples\n",
- header->number,
- header->hdr.ms.NumberOfSamples,
- num_samples);
-
- for (i = 0; i < num_samples; i++) {
- DPRINT(WF_DEBUG_LOAD_PATCH|WF_DEBUG_DATA, "sample[%d] = %d\n",
- i, header->hdr.ms.SampleNumber[i]);
- munge_int32 (header->hdr.ms.SampleNumber[i],
- &msample_hdr[3+(i*2)], 2);
- }
-
- /* Need a hack here to pass in the number of bytes
- to be written to the synth. This is ugly, and perhaps
- one day, I'll fix it.
- */
-
- if (wavefront_cmd (WFC_DOWNLOAD_MULTISAMPLE,
- (unsigned char *) ((num_samples*2)+3),
- msample_hdr)) {
- printk (KERN_ERR LOGNAME "download of multisample failed.\n");
- return -(EIO);
- }
-
- dev.sample_status[header->number] = (WF_SLOT_FILLED|WF_ST_MULTISAMPLE);
-
- return (0);
-}
-
-static int
-wavefront_fetch_multisample (wavefront_patch_info *header)
-{
- int i;
- unsigned char log_ns[1];
- unsigned char number[2];
- int num_samples;
-
- munge_int32 (header->number, number, 2);
-
- if (wavefront_cmd (WFC_UPLOAD_MULTISAMPLE, log_ns, number)) {
- printk (KERN_ERR LOGNAME "upload multisample failed.\n");
- return -(EIO);
- }
-
- DPRINT (WF_DEBUG_DATA, "msample %d has %d samples\n",
- header->number, log_ns[0]);
-
- header->hdr.ms.NumberOfSamples = log_ns[0];
-
- /* get the number of samples ... */
-
- num_samples = (1 << log_ns[0]);
-
- for (i = 0; i < num_samples; i++) {
- s8 d[2];
-
- if ((d[0] = wavefront_read ()) == -1) {
- printk (KERN_ERR LOGNAME "upload multisample failed "
- "during sample loop.\n");
- return -(EIO);
- }
-
- if ((d[1] = wavefront_read ()) == -1) {
- printk (KERN_ERR LOGNAME "upload multisample failed "
- "during sample loop.\n");
- return -(EIO);
- }
-
- header->hdr.ms.SampleNumber[i] =
- demunge_int32 ((unsigned char *) d, 2);
-
- DPRINT (WF_DEBUG_DATA, "msample sample[%d] = %d\n",
- i, header->hdr.ms.SampleNumber[i]);
- }
-
- return (0);
-}
-
-
-static int
-wavefront_send_drum (wavefront_patch_info *header)
-
-{
- unsigned char drumbuf[WF_DRUM_BYTES];
- wavefront_drum *drum = &header->hdr.d;
- int i;
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "downloading edrum for MIDI "
- "note %d, patch = %d\n",
- header->number, drum->PatchNumber);
-
- drumbuf[0] = header->number & 0x7f;
-
- for (i = 0; i < 4; i++) {
- munge_int32 (((unsigned char *)drum)[i], &drumbuf[1+(i*2)], 2);
- }
-
- if (wavefront_cmd (WFC_DOWNLOAD_EDRUM_PROGRAM, NULL, drumbuf)) {
- printk (KERN_ERR LOGNAME "download drum failed.\n");
- return -(EIO);
- }
-
- return (0);
-}
-
-static int
-wavefront_find_free_sample (void)
-
-{
- int i;
-
- for (i = 0; i < WF_MAX_SAMPLE; i++) {
- if (!(dev.sample_status[i] & WF_SLOT_FILLED)) {
- return i;
- }
- }
- printk (KERN_WARNING LOGNAME "no free sample slots!\n");
- return -1;
-}
-
-static int
-wavefront_find_free_patch (void)
-
-{
- int i;
-
- for (i = 0; i < WF_MAX_PATCH; i++) {
- if (!(dev.patch_status[i] & WF_SLOT_FILLED)) {
- return i;
- }
- }
- printk (KERN_WARNING LOGNAME "no free patch slots!\n");
- return -1;
-}
-
-static int
-log2_2048(int n)
-
-{
- int tbl[]={0, 0, 2048, 3246, 4096, 4755, 5294, 5749, 6143,
- 6492, 6803, 7084, 7342, 7578, 7797, 8001, 8192,
- 8371, 8540, 8699, 8851, 8995, 9132, 9264, 9390,
- 9510, 9626, 9738, 9845, 9949, 10049, 10146};
- int i;
-
- /* Returns 2048*log2(n) */
-
- /* FIXME: this is like doing integer math
- on quantum particles (RuN) */
-
- i=0;
- while(n>=32*256) {
- n>>=8;
- i+=2048*8;
- }
- while(n>=32) {
- n>>=1;
- i+=2048;
- }
- i+=tbl[n];
- return(i);
-}
-
-static int
-wavefront_load_gus_patch (int devno, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
- struct patch_info guspatch;
- wavefront_patch_info *samp, *pat, *prog;
- wavefront_patch *patp;
- wavefront_sample *sampp;
- wavefront_program *progp;
-
- int i,base_note;
- long sizeof_patch;
- int rc = -ENOMEM;
-
- samp = kmalloc(3 * sizeof(wavefront_patch_info), GFP_KERNEL);
- if (!samp)
- goto free_fail;
- pat = samp + 1;
- prog = pat + 1;
-
- /* Copy in the header of the GUS patch */
-
- sizeof_patch = (long) &guspatch.data[0] - (long) &guspatch;
- if (copy_from_user(&((char *) &guspatch)[offs],
- &(addr)[offs], sizeof_patch - offs)) {
- rc = -EFAULT;
- goto free_fail;
- }
-
- if ((i = wavefront_find_free_patch ()) == -1) {
- rc = -EBUSY;
- goto free_fail;
- }
- pat->number = i;
- pat->subkey = WF_ST_PATCH;
- patp = &pat->hdr.p;
-
- if ((i = wavefront_find_free_sample ()) == -1) {
- rc = -EBUSY;
- goto free_fail;
- }
- samp->number = i;
- samp->subkey = WF_ST_SAMPLE;
- samp->size = guspatch.len;
- sampp = &samp->hdr.s;
-
- prog->number = guspatch.instr_no;
- progp = &prog->hdr.pr;
-
- /* Setup the patch structure */
-
- patp->amplitude_bias=guspatch.volume;
- patp->portamento=0;
- patp->sample_number= samp->number & 0xff;
- patp->sample_msb= samp->number >> 8;
- patp->pitch_bend= /*12*/ 0;
- patp->mono=1;
- patp->retrigger=1;
- patp->nohold=(guspatch.mode & WAVE_SUSTAIN_ON) ? 0:1;
- patp->frequency_bias=0;
- patp->restart=0;
- patp->reuse=0;
- patp->reset_lfo=1;
- patp->fm_src2=0;
- patp->fm_src1=WF_MOD_MOD_WHEEL;
- patp->am_src=WF_MOD_PRESSURE;
- patp->am_amount=127;
- patp->fc1_mod_amount=0;
- patp->fc2_mod_amount=0;
- patp->fm_amount1=0;
- patp->fm_amount2=0;
- patp->envelope1.attack_level=127;
- patp->envelope1.decay1_level=127;
- patp->envelope1.decay2_level=127;
- patp->envelope1.sustain_level=127;
- patp->envelope1.release_level=0;
- patp->envelope2.attack_velocity=127;
- patp->envelope2.attack_level=127;
- patp->envelope2.decay1_level=127;
- patp->envelope2.decay2_level=127;
- patp->envelope2.sustain_level=127;
- patp->envelope2.release_level=0;
- patp->envelope2.attack_velocity=127;
- patp->randomizer=0;
-
- /* Program for this patch */
-
- progp->layer[0].patch_number= pat->number; /* XXX is this right ? */
- progp->layer[0].mute=1;
- progp->layer[0].pan_or_mod=1;
- progp->layer[0].pan=7;
- progp->layer[0].mix_level=127 /* guspatch.volume */;
- progp->layer[0].split_type=0;
- progp->layer[0].split_point=0;
- progp->layer[0].play_below=0;
-
- for (i = 1; i < 4; i++) {
- progp->layer[i].mute=0;
- }
-
- /* Sample data */
-
- sampp->SampleResolution=((~guspatch.mode & WAVE_16_BITS)<<1);
-
- for (base_note=0;
- note_to_freq (base_note) < guspatch.base_note;
- base_note++);
-
- if ((guspatch.base_note-note_to_freq(base_note))
- >(note_to_freq(base_note)-guspatch.base_note))
- base_note++;
-
- printk(KERN_DEBUG "ref freq=%d,base note=%d\n",
- guspatch.base_freq,
- base_note);
-
- sampp->FrequencyBias = (29550 - log2_2048(guspatch.base_freq)
- + base_note*171);
- printk(KERN_DEBUG "Freq Bias is %d\n", sampp->FrequencyBias);
- sampp->Loop=(guspatch.mode & WAVE_LOOPING) ? 1:0;
- sampp->sampleStartOffset.Fraction=0;
- sampp->sampleStartOffset.Integer=0;
- sampp->loopStartOffset.Fraction=0;
- sampp->loopStartOffset.Integer=guspatch.loop_start
- >>((guspatch.mode&WAVE_16_BITS) ? 1:0);
- sampp->loopEndOffset.Fraction=0;
- sampp->loopEndOffset.Integer=guspatch.loop_end
- >>((guspatch.mode&WAVE_16_BITS) ? 1:0);
- sampp->sampleEndOffset.Fraction=0;
- sampp->sampleEndOffset.Integer=guspatch.len >> (guspatch.mode&1);
- sampp->Bidirectional=(guspatch.mode&WAVE_BIDIR_LOOP) ? 1:0;
- sampp->Reverse=(guspatch.mode&WAVE_LOOP_BACK) ? 1:0;
-
- /* Now ship it down */
-
- wavefront_send_sample (samp,
- (unsigned short __user *) &(addr)[sizeof_patch],
- (guspatch.mode & WAVE_UNSIGNED) ? 1:0);
- wavefront_send_patch (pat);
- wavefront_send_program (prog);
-
- /* Now pan as best we can ... use the slave/internal MIDI device
- number if it exists (since it talks to the WaveFront), or the
- master otherwise.
- */
-
- if (dev.mididev > 0) {
- midi_synth_controller (dev.mididev, guspatch.instr_no, 10,
- ((guspatch.panning << 4) > 127) ?
- 127 : (guspatch.panning << 4));
- }
- rc = 0;
-
-free_fail:
- kfree(samp);
- return rc;
-}
-
-static int
-wavefront_load_patch (const char __user *addr)
-
-
-{
- wavefront_patch_info header;
-
- if (copy_from_user (&header, addr, sizeof(wavefront_patch_info) -
- sizeof(wavefront_any))) {
- printk (KERN_WARNING LOGNAME "bad address for load patch.\n");
- return -EFAULT;
- }
-
- DPRINT (WF_DEBUG_LOAD_PATCH, "download "
- "Sample type: %d "
- "Sample number: %d "
- "Sample size: %d\n",
- header.subkey,
- header.number,
- header.size);
-
- switch (header.subkey) {
- case WF_ST_SAMPLE: /* sample or sample_header, based on patch->size */
-
- if (copy_from_user((unsigned char *) &header.hdr.s,
- (unsigned char __user *) header.hdrptr,
- sizeof (wavefront_sample)))
- return -EFAULT;
-
- return wavefront_send_sample (&header, header.dataptr, 0);
-
- case WF_ST_MULTISAMPLE:
-
- if (copy_from_user(&header.hdr.s, header.hdrptr,
- sizeof(wavefront_multisample)))
- return -EFAULT;
-
- return wavefront_send_multisample (&header);
-
-
- case WF_ST_ALIAS:
-
- if (copy_from_user(&header.hdr.a, header.hdrptr,
- sizeof (wavefront_alias)))
- return -EFAULT;
-
- return wavefront_send_alias (&header);
-
- case WF_ST_DRUM:
- if (copy_from_user(&header.hdr.d, header.hdrptr,
- sizeof (wavefront_drum)))
- return -EFAULT;
-
- return wavefront_send_drum (&header);
-
- case WF_ST_PATCH:
- if (copy_from_user(&header.hdr.p, header.hdrptr,
- sizeof (wavefront_patch)))
- return -EFAULT;
-
- return wavefront_send_patch (&header);
-
- case WF_ST_PROGRAM:
- if (copy_from_user(&header.hdr.pr, header.hdrptr,
- sizeof (wavefront_program)))
- return -EFAULT;
-
- return wavefront_send_program (&header);
-
- default:
- printk (KERN_ERR LOGNAME "unknown patch type %d.\n",
- header.subkey);
- return -(EINVAL);
- }
-
- return 0;
-}
-
-/***********************************************************************
-WaveFront: /dev/sequencer{,2} and other hardware-dependent interfaces
-***********************************************************************/
-
-static void
-process_sample_hdr (UCHAR8 *buf)
-
-{
- wavefront_sample s;
- UCHAR8 *ptr;
-
- ptr = buf;
-
- /* The board doesn't send us an exact copy of a "wavefront_sample"
- in response to an Upload Sample Header command. Instead, we
- have to convert the data format back into our data structure,
- just as in the Download Sample command, where we have to do
- something very similar in the reverse direction.
- */
-
- *((UINT32 *) &s.sampleStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.loopStartOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.loopEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.sampleEndOffset) = demunge_int32 (ptr, 4); ptr += 4;
- *((UINT32 *) &s.FrequencyBias) = demunge_int32 (ptr, 3); ptr += 3;
-
- s.SampleResolution = *ptr & 0x3;
- s.Loop = *ptr & 0x8;
- s.Bidirectional = *ptr & 0x10;
- s.Reverse = *ptr & 0x40;
-
- /* Now copy it back to where it came from */
-
- memcpy (buf, (unsigned char *) &s, sizeof (wavefront_sample));
-}
-
-static int
-wavefront_synth_control (int cmd, wavefront_control *wc)
-
-{
- unsigned char patchnumbuf[2];
- int i;
-
- DPRINT (WF_DEBUG_CMD, "synth control with "
- "cmd 0x%x\n", wc->cmd);
-
- /* Pre-handling of or for various commands */
-
- switch (wc->cmd) {
- case WFC_DISABLE_INTERRUPTS:
- printk (KERN_INFO LOGNAME "interrupts disabled.\n");
- outb (0x80|0x20, dev.control_port);
- dev.interrupts_on = 0;
- return 0;
-
- case WFC_ENABLE_INTERRUPTS:
- printk (KERN_INFO LOGNAME "interrupts enabled.\n");
- outb (0x80|0x40|0x20, dev.control_port);
- dev.interrupts_on = 1;
- return 0;
-
- case WFC_INTERRUPT_STATUS:
- wc->rbuf[0] = dev.interrupts_on;
- return 0;
-
- case WFC_ROMSAMPLES_RDONLY:
- dev.rom_samples_rdonly = wc->wbuf[0];
- wc->status = 0;
- return 0;
-
- case WFC_IDENTIFY_SLOT_TYPE:
- i = wc->wbuf[0] | (wc->wbuf[1] << 7);
- if (i <0 || i >= WF_MAX_SAMPLE) {
- printk (KERN_WARNING LOGNAME "invalid slot ID %d\n",
- i);
- wc->status = EINVAL;
- return 0;
- }
- wc->rbuf[0] = dev.sample_status[i];
- wc->status = 0;
- return 0;
-
- case WFC_DEBUG_DRIVER:
- dev.debug = wc->wbuf[0];
- printk (KERN_INFO LOGNAME "debug = 0x%x\n", dev.debug);
- return 0;
-
- case WFC_FX_IOCTL:
- wffx_ioctl ((wavefront_fx_info *) &wc->wbuf[0]);
- return 0;
-
- case WFC_UPLOAD_PATCH:
- munge_int32 (*((UINT32 *) wc->wbuf), patchnumbuf, 2);
- memcpy (wc->wbuf, patchnumbuf, 2);
- break;
-
- case WFC_UPLOAD_MULTISAMPLE:
- /* multisamples have to be handled differently, and
- cannot be dealt with properly by wavefront_cmd() alone.
- */
- wc->status = wavefront_fetch_multisample
- ((wavefront_patch_info *) wc->rbuf);
- return 0;
-
- case WFC_UPLOAD_SAMPLE_ALIAS:
- printk (KERN_INFO LOGNAME "support for sample alias upload "
- "being considered.\n");
- wc->status = EINVAL;
- return -EINVAL;
- }
-
- wc->status = wavefront_cmd (wc->cmd, wc->rbuf, wc->wbuf);
-
- /* Post-handling of certain commands.
-
- In particular, if the command was an upload, demunge the data
- so that the user-level doesn't have to think about it.
- */
-
- if (wc->status == 0) {
- switch (wc->cmd) {
- /* intercept any freemem requests so that we know
- we are always current with the user-level view
- of things.
- */
-
- case WFC_REPORT_FREE_MEMORY:
- dev.freemem = demunge_int32 (wc->rbuf, 4);
- break;
-
- case WFC_UPLOAD_PATCH:
- demunge_buf (wc->rbuf, wc->rbuf, WF_PATCH_BYTES);
- break;
-
- case WFC_UPLOAD_PROGRAM:
- demunge_buf (wc->rbuf, wc->rbuf, WF_PROGRAM_BYTES);
- break;
-
- case WFC_UPLOAD_EDRUM_PROGRAM:
- demunge_buf (wc->rbuf, wc->rbuf, WF_DRUM_BYTES - 1);
- break;
-
- case WFC_UPLOAD_SAMPLE_HEADER:
- process_sample_hdr (wc->rbuf);
- break;
-
- case WFC_UPLOAD_SAMPLE_ALIAS:
- printk (KERN_INFO LOGNAME "support for "
- "sample aliases still "
- "being considered.\n");
- break;
-
- case WFC_VMIDI_OFF:
- if (virtual_midi_disable () < 0) {
- return -(EIO);
- }
- break;
-
- case WFC_VMIDI_ON:
- if (virtual_midi_enable () < 0) {
- return -(EIO);
- }
- break;
- }
- }
-
- return 0;
-}
-
-
-/***********************************************************************/
-/* WaveFront: Linux file system interface (for access via raw synth) */
-/***********************************************************************/
-
-static int
-wavefront_open (struct inode *inode, struct file *file)
-{
- /* XXX fix me */
- dev.opened = file->f_flags;
- return 0;
-}
-
-static int
-wavefront_release(struct inode *inode, struct file *file)
-{
- lock_kernel();
- dev.opened = 0;
- dev.debug = 0;
- unlock_kernel();
- return 0;
-}
-
-static int
-wavefront_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- wavefront_control wc;
- int err;
-
- switch (cmd) {
-
- case WFCTL_WFCMD:
- if (copy_from_user(&wc, (void __user *) arg, sizeof (wc)))
- return -EFAULT;
-
- if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
- if (copy_to_user ((void __user *) arg, &wc, sizeof (wc)))
- return -EFAULT;
- }
-
- return err;
-
- case WFCTL_LOAD_SPP:
- return wavefront_load_patch ((const char __user *) arg);
-
- default:
- printk (KERN_WARNING LOGNAME "invalid ioctl %#x\n", cmd);
- return -(EINVAL);
-
- }
- return 0;
-}
-
-static /*const*/ struct file_operations wavefront_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = wavefront_ioctl,
- .open = wavefront_open,
- .release = wavefront_release,
-};
-
-
-/***********************************************************************/
-/* WaveFront: OSS installation and support interface */
-/***********************************************************************/
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
-
-static struct synth_info wavefront_info =
-{"Turtle Beach WaveFront", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_WAVEFRONT,
- 0, 32, 0, 0, SYNTH_CAP_INPUT};
-
-static int
-wavefront_oss_open (int devno, int mode)
-
-{
- dev.opened = mode;
- return 0;
-}
-
-static void
-wavefront_oss_close (int devno)
-
-{
- dev.opened = 0;
- dev.debug = 0;
- return;
-}
-
-static int
-wavefront_oss_ioctl (int devno, unsigned int cmd, void __user * arg)
-
-{
- wavefront_control wc;
- int err;
-
- switch (cmd) {
- case SNDCTL_SYNTH_INFO:
- if(copy_to_user(arg, &wavefront_info, sizeof (wavefront_info)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_SEQ_RESETSAMPLES:
-// printk (KERN_WARNING LOGNAME "driver cannot reset samples.\n");
- return 0; /* don't force an error */
-
- case SNDCTL_SEQ_PERCMODE:
- return 0; /* don't force an error */
-
- case SNDCTL_SYNTH_MEMAVL:
- if ((dev.freemem = wavefront_freemem ()) < 0) {
- printk (KERN_ERR LOGNAME "cannot get memory size\n");
- return -EIO;
- } else {
- return dev.freemem;
- }
- break;
-
- case SNDCTL_SYNTH_CONTROL:
- if(copy_from_user (&wc, arg, sizeof (wc)))
- err = -EFAULT;
- else if ((err = wavefront_synth_control (cmd, &wc)) == 0) {
- if(copy_to_user (arg, &wc, sizeof (wc)))
- err = -EFAULT;
- }
-
- return err;
-
- default:
- return -(EINVAL);
- }
-}
-
-static int
-wavefront_oss_load_patch (int devno, int format, const char __user *addr,
- int offs, int count, int pmgr_flag)
-{
-
- if (format == SYSEX_PATCH) { /* Handled by midi_synth.c */
- if (midi_load_patch == NULL) {
- printk (KERN_ERR LOGNAME
- "SYSEX not loadable: "
- "no midi patch loader!\n");
- return -(EINVAL);
- }
-
- return midi_load_patch (devno, format, addr,
- offs, count, pmgr_flag);
-
- } else if (format == GUS_PATCH) {
- return wavefront_load_gus_patch (devno, format,
- addr, offs, count, pmgr_flag);
-
- } else if (format != WAVEFRONT_PATCH) {
- printk (KERN_ERR LOGNAME "unknown patch format %d\n", format);
- return -(EINVAL);
- }
-
- if (count < sizeof (wavefront_patch_info)) {
- printk (KERN_ERR LOGNAME "sample header too short\n");
- return -(EINVAL);
- }
-
- /* "addr" points to a user-space wavefront_patch_info */
-
- return wavefront_load_patch (addr);
-}
-
-static struct synth_operations wavefront_operations =
-{
- .owner = THIS_MODULE,
- .id = "WaveFront",
- .info = &wavefront_info,
- .midi_dev = 0,
- .synth_type = SYNTH_TYPE_SAMPLE,
- .synth_subtype = SAMPLE_TYPE_WAVEFRONT,
- .open = wavefront_oss_open,
- .close = wavefront_oss_close,
- .ioctl = wavefront_oss_ioctl,
- .kill_note = midi_synth_kill_note,
- .start_note = midi_synth_start_note,
- .set_instr = midi_synth_set_instr,
- .reset = midi_synth_reset,
- .load_patch = midi_synth_load_patch,
- .aftertouch = midi_synth_aftertouch,
- .controller = midi_synth_controller,
- .panning = midi_synth_panning,
- .bender = midi_synth_bender,
- .setup_voice = midi_synth_setup_voice
-};
-#endif /* OSS_SUPPORT_SEQ */
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_STATIC_INSTALL
-
-static void __init attach_wavefront (struct address_info *hw_config)
-{
- (void) install_wavefront ();
-}
-
-static int __init probe_wavefront (struct address_info *hw_config)
-{
- return !detect_wavefront (hw_config->irq, hw_config->io_base);
-}
-
-static void __exit unload_wavefront (struct address_info *hw_config)
-{
- (void) uninstall_wavefront ();
-}
-
-#endif /* OSS_SUPPORT_STATIC_INSTALL */
-
-/***********************************************************************/
-/* WaveFront: Linux modular sound kernel installation interface */
-/***********************************************************************/
-
-static irqreturn_t
-wavefrontintr(int irq, void *dev_id, struct pt_regs *dummy)
-{
- struct wf_config *hw = dev_id;
-
- /*
- Some comments on interrupts. I attempted a version of this
- driver that used interrupts throughout the code instead of
- doing busy and/or sleep-waiting. Alas, it appears that once
- the Motorola firmware is downloaded, the card *never*
- generates an RX interrupt. These are successfully generated
- during firmware loading, and after that wavefront_status()
- reports that an interrupt is pending on the card from time
- to time, but it never seems to be delivered to this
- driver. Note also that wavefront_status() continues to
- report that RX interrupts are enabled, suggesting that I
- didn't goof up and disable them by mistake.
-
- Thus, I stepped back to a prior version of
- wavefront_wait(), the only place where this really
- matters. Its sad, but I've looked through the code to check
- on things, and I really feel certain that the Motorola
- firmware prevents RX-ready interrupts.
- */
-
- if ((wavefront_status() & (STAT_INTR_READ|STAT_INTR_WRITE)) == 0) {
- return IRQ_NONE;
- }
-
- hw->irq_ok = 1;
- hw->irq_cnt++;
- wake_up_interruptible (&hw->interrupt_sleeper);
- return IRQ_HANDLED;
-}
-
-/* STATUS REGISTER
-
-0 Host Rx Interrupt Enable (1=Enabled)
-1 Host Rx Register Full (1=Full)
-2 Host Rx Interrupt Pending (1=Interrupt)
-3 Unused
-4 Host Tx Interrupt (1=Enabled)
-5 Host Tx Register empty (1=Empty)
-6 Host Tx Interrupt Pending (1=Interrupt)
-7 Unused
-*/
-
-static int
-wavefront_interrupt_bits (int irq)
-
-{
- int bits;
-
- switch (irq) {
- case 9:
- bits = 0x00;
- break;
- case 5:
- bits = 0x08;
- break;
- case 12:
- bits = 0x10;
- break;
- case 15:
- bits = 0x18;
- break;
-
- default:
- printk (KERN_WARNING LOGNAME "invalid IRQ %d\n", irq);
- bits = -1;
- }
-
- return bits;
-}
-
-static void
-wavefront_should_cause_interrupt (int val, int port, int timeout)
-
-{
- unsigned long flags;
-
- /* this will not help on SMP - but at least it compiles */
- spin_lock_irqsave(&lock, flags);
- dev.irq_ok = 0;
- outb (val,port);
- interruptible_sleep_on_timeout (&dev.interrupt_sleeper, timeout);
- spin_unlock_irqrestore(&lock,flags);
-}
-
-static int __init wavefront_hw_reset (void)
-{
- int bits;
- int hwv[2];
- unsigned long irq_mask;
- short reported_irq;
-
- /* IRQ already checked in init_module() */
-
- bits = wavefront_interrupt_bits (dev.irq);
-
- printk (KERN_DEBUG LOGNAME "autodetecting WaveFront IRQ\n");
-
- irq_mask = probe_irq_on ();
-
- outb (0x0, dev.control_port);
- outb (0x80 | 0x40 | bits, dev.data_port);
- wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
- dev.control_port,
- (reset_time*HZ)/100);
-
- reported_irq = probe_irq_off (irq_mask);
-
- if (reported_irq != dev.irq) {
- if (reported_irq == 0) {
- printk (KERN_ERR LOGNAME
- "No unassigned interrupts detected "
- "after h/w reset\n");
- } else if (reported_irq < 0) {
- printk (KERN_ERR LOGNAME
- "Multiple unassigned interrupts detected "
- "after h/w reset\n");
- } else {
- printk (KERN_ERR LOGNAME "autodetected IRQ %d not the "
- "value provided (%d)\n", reported_irq,
- dev.irq);
- }
- dev.irq = -1;
- return 1;
- } else {
- printk (KERN_INFO LOGNAME "autodetected IRQ at %d\n",
- reported_irq);
- }
-
- if (request_irq (dev.irq, wavefrontintr,
- IRQF_DISABLED|IRQF_SHARED,
- "wavefront synth", &dev) < 0) {
- printk (KERN_WARNING LOGNAME "IRQ %d not available!\n",
- dev.irq);
- return 1;
- }
-
- /* try reset of port */
-
- outb (0x0, dev.control_port);
-
- /* At this point, the board is in reset, and the H/W initialization
- register is accessed at the same address as the data port.
-
- Bit 7 - Enable IRQ Driver
- 0 - Tri-state the Wave-Board drivers for the PC Bus IRQs
- 1 - Enable IRQ selected by bits 5:3 to be driven onto the PC Bus.
-
- Bit 6 - MIDI Interface Select
-
- 0 - Use the MIDI Input from the 26-pin WaveBlaster
- compatible header as the serial MIDI source
- 1 - Use the MIDI Input from the 9-pin D connector as the
- serial MIDI source.
-
- Bits 5:3 - IRQ Selection
- 0 0 0 - IRQ 2/9
- 0 0 1 - IRQ 5
- 0 1 0 - IRQ 12
- 0 1 1 - IRQ 15
- 1 0 0 - Reserved
- 1 0 1 - Reserved
- 1 1 0 - Reserved
- 1 1 1 - Reserved
-
- Bits 2:1 - Reserved
- Bit 0 - Disable Boot ROM
- 0 - memory accesses to 03FC30-03FFFFH utilize the internal Boot ROM
- 1 - memory accesses to 03FC30-03FFFFH are directed to external
- storage.
-
- */
-
- /* configure hardware: IRQ, enable interrupts,
- plus external 9-pin MIDI interface selected
- */
-
- outb (0x80 | 0x40 | bits, dev.data_port);
-
- /* CONTROL REGISTER
-
- 0 Host Rx Interrupt Enable (1=Enabled) 0x1
- 1 Unused 0x2
- 2 Unused 0x4
- 3 Unused 0x8
- 4 Host Tx Interrupt Enable 0x10
- 5 Mute (0=Mute; 1=Play) 0x20
- 6 Master Interrupt Enable (1=Enabled) 0x40
- 7 Master Reset (0=Reset; 1=Run) 0x80
-
- Take us out of reset, mute output, master + TX + RX interrupts on.
-
- We'll get an interrupt presumably to tell us that the TX
- register is clear.
- */
-
- wavefront_should_cause_interrupt(0x80|0x40|0x10|0x1,
- dev.control_port,
- (reset_time*HZ)/100);
-
- /* Note: data port is now the data port, not the h/w initialization
- port.
- */
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "intr not received after h/w un-reset.\n");
- goto gone_bad;
- }
-
- dev.interrupts_on = 1;
-
- /* Note: data port is now the data port, not the h/w initialization
- port.
-
- At this point, only "HW VERSION" or "DOWNLOAD OS" commands
- will work. So, issue one of them, and wait for TX
- interrupt. This can take a *long* time after a cold boot,
- while the ISC ROM does its RAM test. The SDK says up to 4
- seconds - with 12MB of RAM on a Tropez+, it takes a lot
- longer than that (~16secs). Note that the card understands
- the difference between a warm and a cold boot, so
- subsequent ISC2115 reboots (say, caused by module
- reloading) will get through this much faster.
-
- XXX Interesting question: why is no RX interrupt received first ?
- */
-
- wavefront_should_cause_interrupt(WFC_HARDWARE_VERSION,
- dev.data_port, ramcheck_time*HZ);
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "post-RAM-check interrupt not received.\n");
- goto gone_bad;
- }
-
- if (!wavefront_wait (STAT_CAN_READ)) {
- printk (KERN_WARNING LOGNAME
- "no response to HW version cmd.\n");
- goto gone_bad;
- }
-
- if ((hwv[0] = wavefront_read ()) == -1) {
- printk (KERN_WARNING LOGNAME
- "board not responding correctly.\n");
- goto gone_bad;
- }
-
- if (hwv[0] == 0xFF) { /* NAK */
-
- /* Board's RAM test failed. Try to read error code,
- and tell us about it either way.
- */
-
- if ((hwv[0] = wavefront_read ()) == -1) {
- printk (KERN_WARNING LOGNAME "on-board RAM test failed "
- "(bad error code).\n");
- } else {
- printk (KERN_WARNING LOGNAME "on-board RAM test failed "
- "(error code: 0x%x).\n",
- hwv[0]);
- }
- goto gone_bad;
- }
-
- /* We're OK, just get the next byte of the HW version response */
-
- if ((hwv[1] = wavefront_read ()) == -1) {
- printk (KERN_WARNING LOGNAME "incorrect h/w response.\n");
- goto gone_bad;
- }
-
- printk (KERN_INFO LOGNAME "hardware version %d.%d\n",
- hwv[0], hwv[1]);
-
- return 0;
-
-
- gone_bad:
- if (dev.irq >= 0) {
- free_irq (dev.irq, &dev);
- dev.irq = -1;
- }
- return (1);
-}
-
-static int __init detect_wavefront (int irq, int io_base)
-{
- unsigned char rbuf[4], wbuf[4];
-
- /* TB docs say the device takes up 8 ports, but we know that
- if there is an FX device present (i.e. a Tropez+) it really
- consumes 16.
- */
-
- if (!request_region (io_base, 16, "wavfront")) {
- printk (KERN_ERR LOGNAME "IO address range 0x%x - 0x%x "
- "already in use - ignored\n", dev.base,
- dev.base+15);
- return -1;
- }
-
- dev.irq = irq;
- dev.base = io_base;
- dev.israw = 0;
- dev.debug = debug_default;
- dev.interrupts_on = 0;
- dev.irq_cnt = 0;
- dev.rom_samples_rdonly = 1; /* XXX default lock on ROM sample slots */
-
- if (wavefront_cmd (WFC_FIRMWARE_VERSION, rbuf, wbuf) == 0) {
-
- dev.fw_version[0] = rbuf[0];
- dev.fw_version[1] = rbuf[1];
- printk (KERN_INFO LOGNAME
- "firmware %d.%d already loaded.\n",
- rbuf[0], rbuf[1]);
-
- /* check that a command actually works */
-
- if (wavefront_cmd (WFC_HARDWARE_VERSION,
- rbuf, wbuf) == 0) {
- dev.hw_version[0] = rbuf[0];
- dev.hw_version[1] = rbuf[1];
- } else {
- printk (KERN_WARNING LOGNAME "not raw, but no "
- "hardware version!\n");
- release_region (io_base, 16);
- return 0;
- }
-
- if (!wf_raw) {
- /* will re-acquire region in install_wavefront() */
- release_region (io_base, 16);
- return 1;
- } else {
- printk (KERN_INFO LOGNAME
- "reloading firmware anyway.\n");
- dev.israw = 1;
- }
-
- } else {
-
- dev.israw = 1;
- printk (KERN_INFO LOGNAME
- "no response to firmware probe, assume raw.\n");
-
- }
-
- init_waitqueue_head (&dev.interrupt_sleeper);
-
- if (wavefront_hw_reset ()) {
- printk (KERN_WARNING LOGNAME "hardware reset failed\n");
- release_region (io_base, 16);
- return 0;
- }
-
- /* Check for FX device, present only on Tropez+ */
-
- dev.has_fx = (detect_wffx () == 0);
-
- /* will re-acquire region in install_wavefront() */
- release_region (io_base, 16);
- return 1;
-}
-
-#include "os.h"
-#include <linux/fs.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <asm/uaccess.h>
-
-
-static int
-wavefront_download_firmware (char *path)
-
-{
- unsigned char section[WF_SECTION_MAX];
- char section_length; /* yes, just a char; max value is WF_SECTION_MAX */
- int section_cnt_downloaded = 0;
- int fd;
- int c;
- int i;
- mm_segment_t fs;
-
- /* This tries to be a bit cleverer than the stuff Alan Cox did for
- the generic sound firmware, in that it actually knows
- something about the structure of the Motorola firmware. In
- particular, it uses a version that has been stripped of the
- 20K of useless header information, and had section lengths
- added, making it possible to load the entire OS without any
- [kv]malloc() activity, since the longest entity we ever read is
- 42 bytes (well, WF_SECTION_MAX) long.
- */
-
- fs = get_fs();
- set_fs (get_ds());
-
- if ((fd = sys_open (path, 0, 0)) < 0) {
- printk (KERN_WARNING LOGNAME "Unable to load \"%s\".\n",
- path);
- return 1;
- }
-
- while (1) {
- int x;
-
- if ((x = sys_read (fd, &section_length, sizeof (section_length))) !=
- sizeof (section_length)) {
- printk (KERN_ERR LOGNAME "firmware read error.\n");
- goto failure;
- }
-
- if (section_length == 0) {
- break;
- }
-
- if (sys_read (fd, section, section_length) != section_length) {
- printk (KERN_ERR LOGNAME "firmware section "
- "read error.\n");
- goto failure;
- }
-
- /* Send command */
-
- if (wavefront_write (WFC_DOWNLOAD_OS)) {
- goto failure;
- }
-
- for (i = 0; i < section_length; i++) {
- if (wavefront_write (section[i])) {
- goto failure;
- }
- }
-
- /* get ACK */
-
- if (wavefront_wait (STAT_CAN_READ)) {
-
- if ((c = inb (dev.data_port)) != WF_ACK) {
-
- printk (KERN_ERR LOGNAME "download "
- "of section #%d not "
- "acknowledged, ack = 0x%x\n",
- section_cnt_downloaded + 1, c);
- goto failure;
-
- }
-
- } else {
- printk (KERN_ERR LOGNAME "time out for firmware ACK.\n");
- goto failure;
- }
-
- }
-
- sys_close (fd);
- set_fs (fs);
- return 0;
-
- failure:
- sys_close (fd);
- set_fs (fs);
- printk (KERN_ERR "\nWaveFront: firmware download failed!!!\n");
- return 1;
-}
-
-static int __init wavefront_config_midi (void)
-{
- unsigned char rbuf[4], wbuf[4];
-
- if (detect_wf_mpu (dev.irq, dev.base) < 0) {
- printk (KERN_WARNING LOGNAME
- "could not find working MIDI device\n");
- return -1;
- }
-
- if ((dev.mididev = install_wf_mpu ()) < 0) {
- printk (KERN_WARNING LOGNAME
- "MIDI interfaces not configured\n");
- return -1;
- }
-
- /* Route external MIDI to WaveFront synth (by default) */
-
- if (wavefront_cmd (WFC_MISYNTH_ON, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "cannot enable MIDI-IN to synth routing.\n");
- /* XXX error ? */
- }
-
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- /* Get the regular MIDI patch loading function, so we can
- use it if we ever get handed a SYSEX patch. This is
- unlikely, because its so damn slow, but we may as well
- leave this functionality from maui.c behind, since it
- could be useful for sequencer applications that can
- only use MIDI to do patch loading.
- */
-
- if (midi_devs[dev.mididev]->converter != NULL) {
- midi_load_patch = midi_devs[dev.mididev]->converter->load_patch;
- midi_devs[dev.mididev]->converter->load_patch =
- &wavefront_oss_load_patch;
- }
-
-#endif /* OSS_SUPPORT_SEQ */
-
- /* Turn on Virtual MIDI, but first *always* turn it off,
- since otherwise consectutive reloads of the driver will
- never cause the hardware to generate the initial "internal" or
- "external" source bytes in the MIDI data stream. This
- is pretty important, since the internal hardware generally will
- be used to generate none or very little MIDI output, and
- thus the only source of MIDI data is actually external. Without
- the switch bytes, the driver will think it all comes from
- the internal interface. Duh.
- */
-
- if (wavefront_cmd (WFC_VMIDI_OFF, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "virtual MIDI mode not disabled\n");
- return 0; /* We're OK, but missing the external MIDI dev */
- }
-
- if ((dev.ext_mididev = virtual_midi_enable ()) < 0) {
- printk (KERN_WARNING LOGNAME "no virtual MIDI access.\n");
- } else {
- if (wavefront_cmd (WFC_VMIDI_ON, rbuf, wbuf)) {
- printk (KERN_WARNING LOGNAME
- "cannot enable virtual MIDI mode.\n");
- virtual_midi_disable ();
- }
- }
-
- return 0;
-}
-
-static int __init wavefront_do_reset (int atboot)
-{
- char voices[1];
-
- if (!atboot && wavefront_hw_reset ()) {
- printk (KERN_WARNING LOGNAME "hw reset failed.\n");
- goto gone_bad;
- }
-
- if (dev.israw) {
- if (wavefront_download_firmware (ospath)) {
- goto gone_bad;
- }
-
- dev.israw = 0;
-
- /* Wait for the OS to get running. The protocol for
- this is non-obvious, and was determined by
- using port-IO tracing in DOSemu and some
- experimentation here.
-
- Rather than using timed waits, use interrupts creatively.
- */
-
- wavefront_should_cause_interrupt (WFC_NOOP,
- dev.data_port,
- (osrun_time*HZ));
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "no post-OS interrupt.\n");
- goto gone_bad;
- }
-
- /* Now, do it again ! */
-
- wavefront_should_cause_interrupt (WFC_NOOP,
- dev.data_port, (10*HZ));
-
- if (!dev.irq_ok) {
- printk (KERN_WARNING LOGNAME
- "no post-OS interrupt(2).\n");
- goto gone_bad;
- }
-
- /* OK, no (RX/TX) interrupts any more, but leave mute
- in effect.
- */
-
- outb (0x80|0x40, dev.control_port);
-
- /* No need for the IRQ anymore */
-
- free_irq (dev.irq, &dev);
-
- }
-
- if (dev.has_fx && fx_raw) {
- wffx_init ();
- }
-
- /* SETUPSND.EXE asks for sample memory config here, but since i
- have no idea how to interpret the result, we'll forget
- about it.
- */
-
- if ((dev.freemem = wavefront_freemem ()) < 0) {
- goto gone_bad;
- }
-
- printk (KERN_INFO LOGNAME "available DRAM %dk\n", dev.freemem / 1024);
-
- if (wavefront_write (0xf0) ||
- wavefront_write (1) ||
- (wavefront_read () < 0)) {
- dev.debug = 0;
- printk (KERN_WARNING LOGNAME "MPU emulation mode not set.\n");
- goto gone_bad;
- }
-
- voices[0] = 32;
-
- if (wavefront_cmd (WFC_SET_NVOICES, NULL, voices)) {
- printk (KERN_WARNING LOGNAME
- "cannot set number of voices to 32.\n");
- goto gone_bad;
- }
-
-
- return 0;
-
- gone_bad:
- /* reset that sucker so that it doesn't bother us. */
-
- outb (0x0, dev.control_port);
- dev.interrupts_on = 0;
- if (dev.irq >= 0) {
- free_irq (dev.irq, &dev);
- }
- return 1;
-}
-
-static int __init wavefront_init (int atboot)
-{
- int samples_are_from_rom;
-
- if (dev.israw) {
- samples_are_from_rom = 1;
- } else {
- /* XXX is this always true ? */
- samples_are_from_rom = 0;
- }
-
- if (dev.israw || fx_raw) {
- if (wavefront_do_reset (atboot)) {
- return -1;
- }
- }
-
- wavefront_get_sample_status (samples_are_from_rom);
- wavefront_get_program_status ();
- wavefront_get_patch_status ();
-
- /* Start normal operation: unreset, master interrupt enabled, no mute
- */
-
- outb (0x80|0x40|0x20, dev.control_port);
-
- return (0);
-}
-
-static int __init install_wavefront (void)
-{
- if (!request_region (dev.base+2, 6, "wavefront synth"))
- return -1;
-
- if (dev.has_fx) {
- if (!request_region (dev.base+8, 8, "wavefront fx")) {
- release_region (dev.base+2, 6);
- return -1;
- }
- }
-
- if ((dev.synth_dev = register_sound_synth (&wavefront_fops, -1)) < 0) {
- printk (KERN_ERR LOGNAME "cannot register raw synth\n");
- goto err_out;
- }
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- if ((dev.oss_dev = sound_alloc_synthdev()) == -1) {
- printk (KERN_ERR LOGNAME "Too many sequencers\n");
- /* FIXME: leak: should unregister sound synth */
- goto err_out;
- } else {
- synth_devs[dev.oss_dev] = &wavefront_operations;
- }
-#endif /* OSS_SUPPORT_SEQ */
-
- if (wavefront_init (1) < 0) {
- printk (KERN_WARNING LOGNAME "initialization failed.\n");
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- sound_unload_synthdev (dev.oss_dev);
-#endif /* OSS_SUPPORT_SEQ */
-
- goto err_out;
- }
-
- if (wavefront_config_midi ()) {
- printk (KERN_WARNING LOGNAME "could not initialize MIDI.\n");
- }
-
- return dev.oss_dev;
-
-err_out:
- release_region (dev.base+2, 6);
- if (dev.has_fx)
- release_region (dev.base+8, 8);
- return -1;
-}
-
-static void __exit uninstall_wavefront (void)
-{
- /* the first two i/o addresses are freed by the wf_mpu code */
- release_region (dev.base+2, 6);
-
- if (dev.has_fx) {
- release_region (dev.base+8, 8);
- }
-
- unregister_sound_synth (dev.synth_dev);
-
-#if OSS_SUPPORT_LEVEL & OSS_SUPPORT_SEQ
- sound_unload_synthdev (dev.oss_dev);
-#endif /* OSS_SUPPORT_SEQ */
- uninstall_wf_mpu ();
-}
-
-/***********************************************************************/
-/* WaveFront FX control */
-/***********************************************************************/
-
-#include "yss225.h"
-
-/* Control bits for the Load Control Register
- */
-
-#define FX_LSB_TRANSFER 0x01 /* transfer after DSP LSB byte written */
-#define FX_MSB_TRANSFER 0x02 /* transfer after DSP MSB byte written */
-#define FX_AUTO_INCR 0x04 /* auto-increment DSP address after transfer */
-
-static int
-wffx_idle (void)
-
-{
- int i;
- unsigned int x = 0x80;
-
- for (i = 0; i < 1000; i++) {
- x = inb (dev.fx_status);
- if ((x & 0x80) == 0) {
- break;
- }
- }
-
- if (x & 0x80) {
- printk (KERN_ERR LOGNAME "FX device never idle.\n");
- return 0;
- }
-
- return (1);
-}
-
-int __init detect_wffx (void)
-{
- /* This is a crude check, but its the best one I have for now.
- Certainly on the Maui and the Tropez, wffx_idle() will
- report "never idle", which suggests that this test should
- work OK.
- */
-
- if (inb (dev.fx_status) & 0x80) {
- printk (KERN_INFO LOGNAME "Hmm, probably a Maui or Tropez.\n");
- return -1;
- }
-
- return 0;
-}
-
-static void
-wffx_mute (int onoff)
-
-{
- if (!wffx_idle()) {
- return;
- }
-
- outb (onoff ? 0x02 : 0x00, dev.fx_op);
-}
-
-static int
-wffx_memset (int page,
- int addr, int cnt, unsigned short *data)
-{
- if (page < 0 || page > 7) {
- printk (KERN_ERR LOGNAME "FX memset: "
- "page must be >= 0 and <= 7\n");
- return -(EINVAL);
- }
-
- if (addr < 0 || addr > 0x7f) {
- printk (KERN_ERR LOGNAME "FX memset: "
- "addr must be >= 0 and <= 7f\n");
- return -(EINVAL);
- }
-
- if (cnt == 1) {
-
- outb (FX_LSB_TRANSFER, dev.fx_lcr);
- outb (page, dev.fx_dsp_page);
- outb (addr, dev.fx_dsp_addr);
- outb ((data[0] >> 8), dev.fx_dsp_msb);
- outb ((data[0] & 0xff), dev.fx_dsp_lsb);
-
- printk (KERN_INFO LOGNAME "FX: addr %d:%x set to 0x%x\n",
- page, addr, data[0]);
-
- } else {
- int i;
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (page, dev.fx_dsp_page);
- outb (addr, dev.fx_dsp_addr);
-
- for (i = 0; i < cnt; i++) {
- outb ((data[i] >> 8), dev.fx_dsp_msb);
- outb ((data[i] & 0xff), dev.fx_dsp_lsb);
- if (!wffx_idle ()) {
- break;
- }
- }
-
- if (i != cnt) {
- printk (KERN_WARNING LOGNAME
- "FX memset "
- "(0x%x, 0x%x, %p, %d) incomplete\n",
- page, addr, data, cnt);
- return -(EIO);
- }
- }
-
- return 0;
-}
-
-static int
-wffx_ioctl (wavefront_fx_info *r)
-
-{
- unsigned short page_data[256];
- unsigned short *pd;
-
- switch (r->request) {
- case WFFX_MUTE:
- wffx_mute (r->data[0]);
- return 0;
-
- case WFFX_MEMSET:
-
- if (r->data[2] <= 0) {
- printk (KERN_ERR LOGNAME "cannot write "
- "<= 0 bytes to FX\n");
- return -(EINVAL);
- } else if (r->data[2] == 1) {
- pd = (unsigned short *) &r->data[3];
- } else {
- if (r->data[2] > sizeof (page_data)) {
- printk (KERN_ERR LOGNAME "cannot write "
- "> 255 bytes to FX\n");
- return -(EINVAL);
- }
- if (copy_from_user(page_data,
- (unsigned char __user *)r->data[3],
- r->data[2]))
- return -EFAULT;
- pd = page_data;
- }
-
- return wffx_memset (r->data[0], /* page */
- r->data[1], /* addr */
- r->data[2], /* cnt */
- pd);
-
- default:
- printk (KERN_WARNING LOGNAME
- "FX: ioctl %d not yet supported\n",
- r->request);
- return -(EINVAL);
- }
-}
-
-/* YSS225 initialization.
-
- This code was developed using DOSEMU. The Turtle Beach SETUPSND
- utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
- of the port I/O done, using the Yamaha faxback document as a guide
- to add more logic to the code. Its really pretty weird.
-
- There was an alternative approach of just dumping the whole I/O
- sequence as a series of port/value pairs and a simple loop
- that output it. However, I hope that eventually I'll get more
- control over what this code does, and so I tried to stick with
- a somewhat "algorithmic" approach.
-*/
-
-static int __init wffx_init (void)
-{
- int i;
- int j;
-
- /* Set all bits for all channels on the MOD unit to zero */
- /* XXX But why do this twice ? */
-
- for (j = 0; j < 2; j++) {
- for (i = 0x10; i <= 0xff; i++) {
-
- if (!wffx_idle ()) {
- return (-1);
- }
-
- outb (i, dev.fx_mod_addr);
- outb (0x0, dev.fx_mod_data);
- }
- }
-
- if (!wffx_idle()) return (-1);
- outb (0x02, dev.fx_op); /* mute on */
-
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x44, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x42, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x43, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x7c, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x7e, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x46, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x49, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x47, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x4a, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
-
- /* either because of stupidity by TB's programmers, or because it
- actually does something, rezero the MOD page.
- */
- for (i = 0x10; i <= 0xff; i++) {
-
- if (!wffx_idle ()) {
- return (-1);
- }
-
- outb (i, dev.fx_mod_addr);
- outb (0x0, dev.fx_mod_data);
- }
- /* load page zero */
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x00, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_zero); i += 2) {
- outb (page_zero[i], dev.fx_dsp_msb);
- outb (page_zero[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Now load page one */
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x01, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_one); i += 2) {
- outb (page_one[i], dev.fx_dsp_msb);
- outb (page_one[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x02, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_two); i++) {
- outb (page_two[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x03, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_three); i++) {
- outb (page_three[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x04, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_four); i++) {
- outb (page_four[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Load memory area (page six) */
-
- outb (FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x06, dev.fx_dsp_page);
-
- for (i = 0; i < sizeof (page_six); i += 3) {
- outb (page_six[i], dev.fx_dsp_addr);
- outb (page_six[i+1], dev.fx_dsp_msb);
- outb (page_six[i+2], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x07, dev.fx_dsp_page);
- outb (0x00, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_seven); i += 2) {
- outb (page_seven[i], dev.fx_dsp_msb);
- outb (page_seven[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Now setup the MOD area. We do this algorithmically in order to
- save a little data space. It could be done in the same fashion
- as the "pages".
- */
-
- for (i = 0x00; i <= 0x0f; i++) {
- outb (0x01, dev.fx_mod_addr);
- outb (i, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0x02, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0xb0; i <= 0xbf; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0xf0; i <= 0xff; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x10; i <= 0x1d; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0xff, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x1e, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x1f; i <= 0x2d; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0xff, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x2e, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x2f; i <= 0x3e; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x3f, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x40; i <= 0x4d; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x4e, dev.fx_mod_addr);
- outb (0x0e, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0x4f, dev.fx_mod_addr);
- outb (0x0e, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
-
- for (i = 0x50; i <= 0x6b; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x6c, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- outb (0x6d, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- outb (0x6e, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- outb (0x6f, dev.fx_mod_addr);
- outb (0x40, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0x70; i <= 0x7f; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0xc0, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x80; i <= 0xaf; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0xc0; i <= 0xdd; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0xde, dev.fx_mod_addr);
- outb (0x10, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0xdf, dev.fx_mod_addr);
- outb (0x10, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
-
- for (i = 0xe0; i <= 0xef; i++) {
- outb (i, dev.fx_mod_addr);
- outb (0x00, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x00; i <= 0x0f; i++) {
- outb (0x01, dev.fx_mod_addr);
- outb (i, dev.fx_mod_data);
- outb (0x02, dev.fx_mod_addr);
- outb (0x01, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- outb (0x02, dev.fx_op); /* mute on */
-
- /* Now set the coefficients and so forth for the programs above */
-
- for (i = 0; i < sizeof (coefficients); i += 4) {
- outb (coefficients[i], dev.fx_dsp_page);
- outb (coefficients[i+1], dev.fx_dsp_addr);
- outb (coefficients[i+2], dev.fx_dsp_msb);
- outb (coefficients[i+3], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- /* Some settings (?) that are too small to bundle into loops */
-
- if (!wffx_idle()) return (-1);
- outb (0x1e, dev.fx_mod_addr);
- outb (0x14, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0xde, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- outb (0xdf, dev.fx_mod_addr);
- outb (0x20, dev.fx_mod_data);
-
- /* some more coefficients */
-
- if (!wffx_idle()) return (-1);
- outb (0x06, dev.fx_dsp_page);
- outb (0x78, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x40, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x03, dev.fx_dsp_addr);
- outb (0x0f, dev.fx_dsp_msb);
- outb (0xff, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x0b, dev.fx_dsp_addr);
- outb (0x0f, dev.fx_dsp_msb);
- outb (0xff, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x02, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x0a, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x46, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- outb (0x07, dev.fx_dsp_page);
- outb (0x49, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
-
- /* Now, for some strange reason, lets reload every page
- and all the coefficients over again. I have *NO* idea
- why this is done. I do know that no sound is produced
- is this phase is omitted.
- */
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x00, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_zero_v2); i += 2) {
- outb (page_zero_v2[i], dev.fx_dsp_msb);
- outb (page_zero_v2[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x01, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_one_v2); i += 2) {
- outb (page_one_v2[i], dev.fx_dsp_msb);
- outb (page_one_v2[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- if (!wffx_idle()) return (-1);
- if (!wffx_idle()) return (-1);
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x02, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_two_v2); i++) {
- outb (page_two_v2[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x03, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_three_v2); i++) {
- outb (page_three_v2[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x04, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_four_v2); i++) {
- outb (page_four_v2[i], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x06, dev.fx_dsp_page);
-
- /* Page six v.2 is algorithmic */
-
- for (i = 0x10; i <= 0x3e; i += 2) {
- outb (i, dev.fx_dsp_addr);
- outb (0x00, dev.fx_dsp_msb);
- outb (0x00, dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- outb (FX_AUTO_INCR|FX_LSB_TRANSFER, dev.fx_lcr);
- outb (0x07, dev.fx_dsp_page);
- outb (0x10, dev.fx_dsp_addr);
-
- for (i = 0; i < sizeof (page_seven_v2); i += 2) {
- outb (page_seven_v2[i], dev.fx_dsp_msb);
- outb (page_seven_v2[i+1], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0x00; i < sizeof(mod_v2); i += 2) {
- outb (mod_v2[i], dev.fx_mod_addr);
- outb (mod_v2[i+1], dev.fx_mod_data);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0; i < sizeof (coefficients2); i += 4) {
- outb (coefficients2[i], dev.fx_dsp_page);
- outb (coefficients2[i+1], dev.fx_dsp_addr);
- outb (coefficients2[i+2], dev.fx_dsp_msb);
- outb (coefficients2[i+3], dev.fx_dsp_lsb);
- if (!wffx_idle()) return (-1);
- }
-
- for (i = 0; i < sizeof (coefficients3); i += 2) {
- int x;
-
- outb (0x07, dev.fx_dsp_page);
- x = (i % 4) ? 0x4e : 0x4c;
- outb (x, dev.fx_dsp_addr);
- outb (coefficients3[i], dev.fx_dsp_msb);
- outb (coefficients3[i+1], dev.fx_dsp_lsb);
- }
-
- outb (0x00, dev.fx_op); /* mute off */
- if (!wffx_idle()) return (-1);
-
- return (0);
-}
-
-static int io = -1;
-static int irq = -1;
-
-MODULE_AUTHOR ("Paul Barton-Davis <pbd@op.net>");
-MODULE_DESCRIPTION ("Turtle Beach WaveFront Linux Driver");
-MODULE_LICENSE("GPL");
-module_param (io, int, 0);
-module_param (irq, int, 0);
-
-static int __init init_wavfront (void)
-{
- printk ("Turtle Beach WaveFront Driver\n"
- "Copyright (C) by Hannu Solvainen, "
- "Paul Barton-Davis 1993-1998.\n");
-
- /* XXX t'would be lovely to ask the CS4232 for these values, eh ? */
-
- if (io == -1 || irq == -1) {
- printk (KERN_INFO LOGNAME "irq and io options must be set.\n");
- return -EINVAL;
- }
-
- if (wavefront_interrupt_bits (irq) < 0) {
- printk (KERN_INFO LOGNAME
- "IRQ must be 9, 5, 12 or 15 (not %d)\n", irq);
- return -ENODEV;
- }
-
- if (detect_wavefront (irq, io) < 0) {
- return -ENODEV;
- }
-
- if (install_wavefront () < 0) {
- return -EIO;
- }
-
- return 0;
-}
-
-static void __exit cleanup_wavfront (void)
-{
- uninstall_wavefront ();
-}
-
-module_init(init_wavfront);
-module_exit(cleanup_wavfront);
diff --git a/sound/oss/wf_midi.c b/sound/oss/wf_midi.c
deleted file mode 100644
index 3f3a390014ca..000000000000
--- a/sound/oss/wf_midi.c
+++ /dev/null
@@ -1,880 +0,0 @@
-/*
- * sound/wf_midi.c
- *
- * The low level driver for the WaveFront ICS2115 MIDI interface(s)
- * Note that there is also an MPU-401 emulation (actually, a UART-401
- * emulation) on the CS4232 on the Tropez Plus. This code has nothing
- * to do with that interface at all.
- *
- * The interface is essentially just a UART-401, but is has the
- * interesting property of supporting what Turtle Beach called
- * "Virtual MIDI" mode. In this mode, there are effectively *two*
- * MIDI buses accessible via the interface, one that is routed
- * solely to/from the external WaveFront synthesizer and the other
- * corresponding to the pin/socket connector used to link external
- * MIDI devices to the board.
- *
- * This driver fully supports this mode, allowing two distinct
- * midi devices (/dev/midiNN and /dev/midiNN+1) to be used
- * completely independently, giving 32 channels of MIDI routing,
- * 16 to the WaveFront synth and 16 to the external MIDI bus.
- *
- * Switching between the two is accomplished externally by the driver
- * using the two otherwise unused MIDI bytes. See the code for more details.
- *
- * NOTE: VIRTUAL MIDI MODE IS ON BY DEFAULT (see wavefront.c)
- *
- * The main reason to turn off Virtual MIDI mode is when you want to
- * tightly couple the WaveFront synth with an external MIDI
- * device. You won't be able to distinguish the source of any MIDI
- * data except via SysEx ID, but thats probably OK, since for the most
- * part, the WaveFront won't be sending any MIDI data at all.
- *
- * The main reason to turn on Virtual MIDI Mode is to provide two
- * completely independent 16-channel MIDI buses, one to the
- * WaveFront and one to any external MIDI devices. Given the 32
- * voice nature of the WaveFront, its pretty easy to find a use
- * for all 16 channels driving just that synth.
- *
- */
-
-/*
- * Copyright (C) by Paul Barton-Davis 1998
- * Some portions of this file are derived from work that is:
- *
- * CopyriGht (C) by Hannu Savolainen 1993-1996
- *
- * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include "sound_config.h"
-
-#include <linux/wavefront.h>
-
-#ifdef MODULE
-
-struct wf_mpu_config {
- int base;
-#define DATAPORT(d) (d)->base
-#define COMDPORT(d) (d)->base+1
-#define STATPORT(d) (d)->base+1
-
- int irq;
- int opened;
- int devno;
- int synthno;
- int mode;
-#define MODE_MIDI 1
-#define MODE_SYNTH 2
-
- void (*inputintr) (int dev, unsigned char data);
- char isvirtual; /* do virtual I/O stuff */
-};
-
-static struct wf_mpu_config devs[2];
-static struct wf_mpu_config *phys_dev = &devs[0];
-static struct wf_mpu_config *virt_dev = &devs[1];
-
-static void start_uart_mode (void);
-static DEFINE_SPINLOCK(lock);
-
-#define OUTPUT_READY 0x40
-#define INPUT_AVAIL 0x80
-#define MPU_ACK 0xFE
-#define UART_MODE_ON 0x3F
-
-static inline int wf_mpu_status (void)
-{
- return inb (STATPORT (phys_dev));
-}
-
-static inline int input_avail (void)
-{
- return !(wf_mpu_status() & INPUT_AVAIL);
-}
-
-static inline int output_ready (void)
-{
- return !(wf_mpu_status() & OUTPUT_READY);
-}
-
-static inline int read_data (void)
-{
- return inb (DATAPORT (phys_dev));
-}
-
-static inline void write_data (unsigned char byte)
-{
- outb (byte, DATAPORT (phys_dev));
-}
-
-/*
- * States for the input scanner (should be in dev_table.h)
- */
-
-#define MST_SYSMSG 100 /* System message (sysx etc). */
-#define MST_MTC 102 /* Midi Time Code (MTC) qframe msg */
-#define MST_SONGSEL 103 /* Song select */
-#define MST_SONGPOS 104 /* Song position pointer */
-#define MST_TIMED 105 /* Leading timing byte rcvd */
-
-/* buffer space check for input scanner */
-
-#define BUFTEST(mi) if (mi->m_ptr >= MI_MAX || mi->m_ptr < 0) \
-{printk(KERN_ERR "WF-MPU: Invalid buffer pointer %d/%d, s=%d\n", \
- mi->m_ptr, mi->m_left, mi->m_state);mi->m_ptr--;}
-
-static unsigned char len_tab[] = /* # of data bytes following a status
- */
-{
- 2, /* 8x */
- 2, /* 9x */
- 2, /* Ax */
- 2, /* Bx */
- 1, /* Cx */
- 1, /* Dx */
- 2, /* Ex */
- 0 /* Fx */
-};
-
-static int
-wf_mpu_input_scanner (int devno, int synthdev, unsigned char midic)
-
-{
- struct midi_input_info *mi = &midi_devs[devno]->in_info;
-
- switch (mi->m_state) {
- case MST_INIT:
- switch (midic) {
- case 0xf8:
- /* Timer overflow */
- break;
-
- case 0xfc:
- break;
-
- case 0xfd:
- /* XXX do something useful with this. If there is
- an external MIDI timer (e.g. a hardware sequencer,
- a useful timer can be derived ...
-
- For now, no timer support.
- */
- break;
-
- case 0xfe:
- return MPU_ACK;
- break;
-
- case 0xf0:
- case 0xf1:
- case 0xf2:
- case 0xf3:
- case 0xf4:
- case 0xf5:
- case 0xf6:
- case 0xf7:
- break;
-
- case 0xf9:
- break;
-
- case 0xff:
- mi->m_state = MST_SYSMSG;
- break;
-
- default:
- if (midic <= 0xef) {
- mi->m_state = MST_TIMED;
- }
- else
- printk (KERN_ERR "<MPU: Unknown event %02x> ",
- midic);
- }
- break;
-
- case MST_TIMED:
- {
- int msg = ((int) (midic & 0xf0) >> 4);
-
- mi->m_state = MST_DATA;
-
- if (msg < 8) { /* Data byte */
-
- msg = ((int) (mi->m_prev_status & 0xf0) >> 4);
- msg -= 8;
- mi->m_left = len_tab[msg] - 1;
-
- mi->m_ptr = 2;
- mi->m_buf[0] = mi->m_prev_status;
- mi->m_buf[1] = midic;
-
- if (mi->m_left <= 0) {
- mi->m_state = MST_INIT;
- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
- mi->m_ptr = 0;
- }
- } else if (msg == 0xf) { /* MPU MARK */
-
- mi->m_state = MST_INIT;
-
- switch (midic) {
- case 0xf8:
- break;
-
- case 0xf9:
- break;
-
- case 0xfc:
- break;
-
- default:
- break;
- }
- } else {
- mi->m_prev_status = midic;
- msg -= 8;
- mi->m_left = len_tab[msg];
-
- mi->m_ptr = 1;
- mi->m_buf[0] = midic;
-
- if (mi->m_left <= 0) {
- mi->m_state = MST_INIT;
- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
- mi->m_ptr = 0;
- }
- }
- }
- break;
-
- case MST_SYSMSG:
- switch (midic) {
- case 0xf0:
- mi->m_state = MST_SYSEX;
- break;
-
- case 0xf1:
- mi->m_state = MST_MTC;
- break;
-
- case 0xf2:
- mi->m_state = MST_SONGPOS;
- mi->m_ptr = 0;
- break;
-
- case 0xf3:
- mi->m_state = MST_SONGSEL;
- break;
-
- case 0xf6:
- mi->m_state = MST_INIT;
-
- /*
- * Real time messages
- */
- case 0xf8:
- /* midi clock */
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xfA:
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xFB:
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xFC:
- mi->m_state = MST_INIT;
- /* XXX need ext MIDI timer support */
- break;
-
- case 0xFE:
- /* active sensing */
- mi->m_state = MST_INIT;
- break;
-
- case 0xff:
- mi->m_state = MST_INIT;
- break;
-
- default:
- printk (KERN_ERR "unknown MIDI sysmsg %0x\n", midic);
- mi->m_state = MST_INIT;
- }
- break;
-
- case MST_MTC:
- mi->m_state = MST_INIT;
- break;
-
- case MST_SYSEX:
- if (midic == 0xf7) {
- mi->m_state = MST_INIT;
- } else {
- /* XXX fix me */
- }
- break;
-
- case MST_SONGPOS:
- BUFTEST (mi);
- mi->m_buf[mi->m_ptr++] = midic;
- if (mi->m_ptr == 2) {
- mi->m_state = MST_INIT;
- mi->m_ptr = 0;
- /* XXX need ext MIDI timer support */
- }
- break;
-
- case MST_DATA:
- BUFTEST (mi);
- mi->m_buf[mi->m_ptr++] = midic;
- if ((--mi->m_left) <= 0) {
- mi->m_state = MST_INIT;
- do_midi_msg (synthdev, mi->m_buf, mi->m_ptr);
- mi->m_ptr = 0;
- }
- break;
-
- default:
- printk (KERN_ERR "Bad state %d ", mi->m_state);
- mi->m_state = MST_INIT;
- }
-
- return 1;
-}
-
-static irqreturn_t
-wf_mpuintr(int irq, void *dev_id, struct pt_regs *dummy)
-
-{
- struct wf_mpu_config *physical_dev = dev_id;
- static struct wf_mpu_config *input_dev;
- struct midi_input_info *mi = &midi_devs[physical_dev->devno]->in_info;
- int n;
-
- if (!input_avail()) { /* not for us */
- return IRQ_NONE;
- }
-
- if (mi->m_busy)
- return IRQ_HANDLED;
- spin_lock(&lock);
- mi->m_busy = 1;
-
- if (!input_dev) {
- input_dev = physical_dev;
- }
-
- n = 50; /* XXX why ? */
-
- do {
- unsigned char c = read_data ();
-
- if (phys_dev->isvirtual) {
-
- if (c == WF_EXTERNAL_SWITCH) {
- input_dev = virt_dev;
- continue;
- } else if (c == WF_INTERNAL_SWITCH) {
- input_dev = phys_dev;
- continue;
- } /* else just leave it as it is */
-
- } else {
- input_dev = phys_dev;
- }
-
- if (input_dev->mode == MODE_SYNTH) {
-
- wf_mpu_input_scanner (input_dev->devno,
- input_dev->synthno, c);
-
- } else if (input_dev->opened & OPEN_READ) {
-
- if (input_dev->inputintr) {
- input_dev->inputintr (input_dev->devno, c);
- }
- }
-
- } while (input_avail() && n-- > 0);
-
- mi->m_busy = 0;
- spin_unlock(&lock);
- return IRQ_HANDLED;
-}
-
-static int
-wf_mpu_open (int dev, int mode,
- void (*input) (int dev, unsigned char data),
- void (*output) (int dev)
- )
-{
- struct wf_mpu_config *devc;
-
- if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
- return -(ENXIO);
-
- if (phys_dev->devno == dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return -(EINVAL);
- }
-
- if (devc->opened) {
- return -(EBUSY);
- }
-
- devc->mode = MODE_MIDI;
- devc->opened = mode;
- devc->synthno = 0;
-
- devc->inputintr = input;
- return 0;
-}
-
-static void
-wf_mpu_close (int dev)
-{
- struct wf_mpu_config *devc;
-
- if (dev < 0 || dev >= num_midis || midi_devs[dev]==NULL)
- return;
-
- if (phys_dev->devno == dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return;
- }
-
- devc->mode = 0;
- devc->inputintr = NULL;
- devc->opened = 0;
-}
-
-static int
-wf_mpu_out (int dev, unsigned char midi_byte)
-{
- int timeout;
- unsigned long flags;
- static int lastoutdev = -1;
- unsigned char switchch;
-
- if (phys_dev->isvirtual && lastoutdev != dev) {
-
- if (dev == phys_dev->devno) {
- switchch = WF_INTERNAL_SWITCH;
- } else if (dev == virt_dev->devno) {
- switchch = WF_EXTERNAL_SWITCH;
- } else {
- printk (KERN_ERR "WF-MPU: bad device number %d", dev);
- return (0);
- }
-
- /* XXX fix me */
-
- for (timeout = 30000; timeout > 0 && !output_ready ();
- timeout--);
-
- spin_lock_irqsave(&lock,flags);
-
- if (!output_ready ()) {
- printk (KERN_WARNING "WF-MPU: Send switch "
- "byte timeout\n");
- spin_unlock_irqrestore(&lock,flags);
- return 0;
- }
-
- write_data (switchch);
- spin_unlock_irqrestore(&lock,flags);
- }
-
- lastoutdev = dev;
-
- /*
- * Sometimes it takes about 30000 loops before the output becomes ready
- * (After reset). Normally it takes just about 10 loops.
- */
-
- /* XXX fix me */
-
- for (timeout = 30000; timeout > 0 && !output_ready (); timeout--);
-
- spin_lock_irqsave(&lock,flags);
- if (!output_ready ()) {
- spin_unlock_irqrestore(&lock,flags);
- printk (KERN_WARNING "WF-MPU: Send data timeout\n");
- return 0;
- }
-
- write_data (midi_byte);
- spin_unlock_irqrestore(&lock,flags);
-
- return 1;
-}
-
-static inline int wf_mpu_start_read (int dev) {
- return 0;
-}
-
-static inline int wf_mpu_end_read (int dev) {
- return 0;
-}
-
-static int wf_mpu_ioctl (int dev, unsigned cmd, void __user *arg)
-{
- printk (KERN_WARNING
- "WF-MPU: Intelligent mode not supported by hardware.\n");
- return -(EINVAL);
-}
-
-static int wf_mpu_buffer_status (int dev)
-{
- return 0;
-}
-
-static struct synth_operations wf_mpu_synth_operations[2];
-static struct midi_operations wf_mpu_midi_operations[2];
-
-static struct midi_operations wf_mpu_midi_proto =
-{
- .owner = THIS_MODULE,
- .info = {"WF-MPU MIDI", 0, MIDI_CAP_MPU401, SNDCARD_MPU401},
- .in_info = {0}, /* in_info */
- .open = wf_mpu_open,
- .close = wf_mpu_close,
- .ioctl = wf_mpu_ioctl,
- .outputc = wf_mpu_out,
- .start_read = wf_mpu_start_read,
- .end_read = wf_mpu_end_read,
- .buffer_status = wf_mpu_buffer_status,
-};
-
-static struct synth_info wf_mpu_synth_info_proto =
-{"WaveFront MPU-401 interface", 0,
- SYNTH_TYPE_MIDI, MIDI_TYPE_MPU401, 0, 128, 0, 128, SYNTH_CAP_INPUT};
-
-static struct synth_info wf_mpu_synth_info[2];
-
-static int
-wf_mpu_synth_ioctl (int dev, unsigned int cmd, void __user *arg)
-{
- int midi_dev;
- int index;
-
- midi_dev = synth_devs[dev]->midi_dev;
-
- if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL)
- return -(ENXIO);
-
- if (midi_dev == phys_dev->devno) {
- index = 0;
- } else if (phys_dev->isvirtual && midi_dev == virt_dev->devno) {
- index = 1;
- } else {
- return -(EINVAL);
- }
-
- switch (cmd) {
-
- case SNDCTL_SYNTH_INFO:
- if (copy_to_user(arg,
- &wf_mpu_synth_info[index],
- sizeof (struct synth_info)))
- return -EFAULT;
- return 0;
-
- case SNDCTL_SYNTH_MEMAVL:
- return 0x7fffffff;
-
- default:
- return -EINVAL;
- }
-}
-
-static int
-wf_mpu_synth_open (int dev, int mode)
-{
- int midi_dev;
- struct wf_mpu_config *devc;
-
- midi_dev = synth_devs[dev]->midi_dev;
-
- if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev]==NULL) {
- return -(ENXIO);
- }
-
- if (phys_dev->devno == midi_dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return -(EINVAL);
- }
-
- if (devc->opened) {
- return -(EBUSY);
- }
-
- devc->mode = MODE_SYNTH;
- devc->synthno = dev;
- devc->opened = mode;
- devc->inputintr = NULL;
- return 0;
-}
-
-static void
-wf_mpu_synth_close (int dev)
-{
- int midi_dev;
- struct wf_mpu_config *devc;
-
- midi_dev = synth_devs[dev]->midi_dev;
-
- if (phys_dev->devno == midi_dev) {
- devc = phys_dev;
- } else if (phys_dev->isvirtual && virt_dev->devno == midi_dev) {
- devc = virt_dev;
- } else {
- printk (KERN_ERR "WF-MPU: unknown device number %d\n", dev);
- return;
- }
-
- devc->inputintr = NULL;
- devc->opened = 0;
- devc->mode = 0;
-}
-
-#define _MIDI_SYNTH_C_
-#define MIDI_SYNTH_NAME "WaveFront (MIDI)"
-#define MIDI_SYNTH_CAPS SYNTH_CAP_INPUT
-#include "midi_synth.h"
-
-static struct synth_operations wf_mpu_synth_proto =
-{
- .owner = THIS_MODULE,
- .id = "WaveFront (ICS2115)",
- .info = NULL, /* info field, filled in during configuration */
- .midi_dev = 0, /* MIDI dev XXX should this be -1 ? */
- .synth_type = SYNTH_TYPE_MIDI,
- .synth_subtype = SAMPLE_TYPE_WAVEFRONT,
- .open = wf_mpu_synth_open,
- .close = wf_mpu_synth_close,
- .ioctl = wf_mpu_synth_ioctl,
- .kill_note = midi_synth_kill_note,
- .start_note = midi_synth_start_note,
- .set_instr = midi_synth_set_instr,
- .reset = midi_synth_reset,
- .hw_control = midi_synth_hw_control,
- .load_patch = midi_synth_load_patch,
- .aftertouch = midi_synth_aftertouch,
- .controller = midi_synth_controller,
- .panning = midi_synth_panning,
- .bender = midi_synth_bender,
- .setup_voice = midi_synth_setup_voice,
- .send_sysex = midi_synth_send_sysex
-};
-
-static int
-config_wf_mpu (struct wf_mpu_config *dev)
-
-{
- int is_external;
- char *name;
- int index;
-
- if (dev == phys_dev) {
- name = "WaveFront internal MIDI";
- is_external = 0;
- index = 0;
- memcpy ((char *) &wf_mpu_synth_operations[index],
- (char *) &wf_mpu_synth_proto,
- sizeof (struct synth_operations));
- } else {
- name = "WaveFront external MIDI";
- is_external = 1;
- index = 1;
- /* no synth operations for an external MIDI interface */
- }
-
- memcpy ((char *) &wf_mpu_synth_info[dev->devno],
- (char *) &wf_mpu_synth_info_proto,
- sizeof (struct synth_info));
-
- strcpy (wf_mpu_synth_info[index].name, name);
-
- wf_mpu_synth_operations[index].midi_dev = dev->devno;
- wf_mpu_synth_operations[index].info = &wf_mpu_synth_info[index];
-
- memcpy ((char *) &wf_mpu_midi_operations[index],
- (char *) &wf_mpu_midi_proto,
- sizeof (struct midi_operations));
-
- if (is_external) {
- wf_mpu_midi_operations[index].converter = NULL;
- } else {
- wf_mpu_midi_operations[index].converter =
- &wf_mpu_synth_operations[index];
- }
-
- strcpy (wf_mpu_midi_operations[index].info.name, name);
-
- midi_devs[dev->devno] = &wf_mpu_midi_operations[index];
- midi_devs[dev->devno]->in_info.m_busy = 0;
- midi_devs[dev->devno]->in_info.m_state = MST_INIT;
- midi_devs[dev->devno]->in_info.m_ptr = 0;
- midi_devs[dev->devno]->in_info.m_left = 0;
- midi_devs[dev->devno]->in_info.m_prev_status = 0;
-
- devs[index].opened = 0;
- devs[index].mode = 0;
-
- return (0);
-}
-
-int virtual_midi_enable (void)
-
-{
- if ((virt_dev->devno < 0) &&
- (virt_dev->devno = sound_alloc_mididev()) == -1) {
- printk (KERN_ERR
- "WF-MPU: too many midi devices detected\n");
- return -1;
- }
-
- config_wf_mpu (virt_dev);
-
- phys_dev->isvirtual = 1;
- return virt_dev->devno;
-}
-
-int
-virtual_midi_disable (void)
-
-{
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
-
- wf_mpu_close (virt_dev->devno);
- /* no synth on virt_dev, so no need to call wf_mpu_synth_close() */
- phys_dev->isvirtual = 0;
-
- spin_unlock_irqrestore(&lock,flags);
-
- return 0;
-}
-
-int __init detect_wf_mpu (int irq, int io_base)
-{
- if (!request_region(io_base, 2, "wavefront midi")) {
- printk (KERN_WARNING "WF-MPU: I/O port %x already in use.\n",
- io_base);
- return -1;
- }
-
- phys_dev->base = io_base;
- phys_dev->irq = irq;
- phys_dev->devno = -1;
- virt_dev->devno = -1;
-
- return 0;
-}
-
-int __init install_wf_mpu (void)
-{
- if ((phys_dev->devno = sound_alloc_mididev()) < 0){
-
- printk (KERN_ERR "WF-MPU: Too many MIDI devices detected.\n");
- release_region(phys_dev->base, 2);
- return -1;
- }
-
- phys_dev->isvirtual = 0;
-
- if (config_wf_mpu (phys_dev)) {
-
- printk (KERN_WARNING
- "WF-MPU: configuration for MIDI device %d failed\n",
- phys_dev->devno);
- sound_unload_mididev (phys_dev->devno);
-
- }
-
- /* OK, now we're configured to handle an interrupt ... */
-
- if (request_irq (phys_dev->irq, wf_mpuintr, IRQF_DISABLED|IRQF_SHARED,
- "wavefront midi", phys_dev) < 0) {
-
- printk (KERN_ERR "WF-MPU: Failed to allocate IRQ%d\n",
- phys_dev->irq);
- return -1;
-
- }
-
- /* This being a WaveFront (ICS-2115) emulated MPU-401, we have
- to switch it into UART (dumb) mode, because otherwise, it
- won't do anything at all.
- */
-
- start_uart_mode ();
-
- return phys_dev->devno;
-}
-
-void
-uninstall_wf_mpu (void)
-
-{
- release_region (phys_dev->base, 2);
- free_irq (phys_dev->irq, phys_dev);
- sound_unload_mididev (phys_dev->devno);
-
- if (virt_dev->devno >= 0) {
- sound_unload_mididev (virt_dev->devno);
- }
-}
-
-static void
-start_uart_mode (void)
-
-{
- int ok, i;
- unsigned long flags;
-
- spin_lock_irqsave(&lock,flags);
-
- /* XXX fix me */
-
- for (i = 0; i < 30000 && !output_ready (); i++);
-
- outb (UART_MODE_ON, COMDPORT(phys_dev));
-
- for (ok = 0, i = 50000; i > 0 && !ok; i--) {
- if (input_avail ()) {
- if (read_data () == MPU_ACK) {
- ok = 1;
- }
- }
- }
-
- spin_unlock_irqrestore(&lock,flags);
-}
-#endif
diff --git a/sound/oss/ymfpci.c b/sound/oss/ymfpci.c
deleted file mode 100644
index 6e22472df952..000000000000
--- a/sound/oss/ymfpci.c
+++ /dev/null
@@ -1,2692 +0,0 @@
-/*
- * Copyright 1999 Jaroslav Kysela <perex@suse.cz>
- * Copyright 2000 Alan Cox <alan@redhat.com>
- * Copyright 2001 Kai Germaschewski <kai@tp1.ruhr-uni-bochum.de>
- * Copyright 2002 Pete Zaitcev <zaitcev@yahoo.com>
- *
- * Yamaha YMF7xx driver.
- *
- * This code is a result of high-speed collision
- * between ymfpci.c of ALSA and cs46xx.c of Linux.
- * -- Pete Zaitcev <zaitcev@yahoo.com>; 2000/09/18
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * TODO:
- * - Use P44Slot for 44.1 playback (beware of idle buzzing in P44Slot).
- * - 96KHz playback for DVD - use pitch of 2.0.
- * - Retain DMA buffer on close, do not wait the end of frame.
- * - Resolve XXX tagged questions.
- * - Cannot play 5133Hz.
- * - 2001/01/07 Consider if we can remove voice_lock, like so:
- * : Allocate/deallocate voices in open/close under semafore.
- * : We access voices in interrupt, that only for pcms that open.
- * voice_lock around playback_prepare closes interrupts for insane duration.
- * - Revisit the way voice_alloc is done - too confusing, overcomplicated.
- * Should support various channel types, however.
- * - Remove prog_dmabuf from read/write, leave it in open.
- * - 2001/01/07 Replace the OPL3 part of CONFIG_SOUND_YMFPCI_LEGACY code with
- * native synthesizer through a playback slot.
- * - 2001/11/29 ac97_save_state
- * Talk to Kai to remove ac97_save_state before it's too late!
- * - Second AC97
- * - Restore S/PDIF - Toshibas have it.
- *
- * Kai used pci_alloc_consistent for DMA buffer, which sounds a little
- * unconventional. However, given how small our fragments can be,
- * a little uncached access is perhaps better than endless flushing.
- * On i386 and other I/O-coherent architectures pci_alloc_consistent
- * is entirely harmless.
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/soundcard.h>
-#include <linux/ac97_codec.h>
-#include <linux/sound.h>
-
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/uaccess.h>
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-# include "sound_config.h"
-# include "mpu401.h"
-#endif
-#include "ymfpci.h"
-
-/*
- * I do not believe in debug levels as I never can guess what
- * part of the code is going to be problematic in the future.
- * Don't forget to run your klogd with -c 8.
- *
- * Example (do not remove):
- * #define YMFDBG(fmt, arg...) do{ printk(KERN_DEBUG fmt, ##arg); }while(0)
- */
-#define YMFDBGW(fmt, arg...) /* */ /* write counts */
-#define YMFDBGI(fmt, arg...) /* */ /* interrupts */
-#define YMFDBGX(fmt, arg...) /* */ /* ioctl */
-
-static int ymf_playback_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
-static void ymf_capture_trigger(ymfpci_t *unit, struct ymf_pcm *ypcm, int cmd);
-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice);
-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank);
-static int ymf_playback_prepare(struct ymf_state *state);
-static int ymf_capture_prepare(struct ymf_state *state);
-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit);
-
-static void ymfpci_aclink_reset(struct pci_dev * pci);
-static void ymfpci_disable_dsp(ymfpci_t *unit);
-static void ymfpci_download_image(ymfpci_t *codec);
-static void ymf_memload(ymfpci_t *unit);
-
-static DEFINE_SPINLOCK(ymf_devs_lock);
-static LIST_HEAD(ymf_devs);
-
-/*
- * constants
- */
-
-static struct pci_device_id ymf_id_tbl[] = {
-#define DEV(dev, data) \
- { PCI_VENDOR_ID_YAMAHA, dev, PCI_ANY_ID, PCI_ANY_ID, 0, 0, \
- (unsigned long)data }
- DEV (PCI_DEVICE_ID_YAMAHA_724, "YMF724"),
- DEV (PCI_DEVICE_ID_YAMAHA_724F, "YMF724F"),
- DEV (PCI_DEVICE_ID_YAMAHA_740, "YMF740"),
- DEV (PCI_DEVICE_ID_YAMAHA_740C, "YMF740C"),
- DEV (PCI_DEVICE_ID_YAMAHA_744, "YMF744"),
- DEV (PCI_DEVICE_ID_YAMAHA_754, "YMF754"),
-#undef DEV
- { }
-};
-MODULE_DEVICE_TABLE(pci, ymf_id_tbl);
-
-/*
- * common I/O routines
- */
-
-static inline void ymfpci_writeb(ymfpci_t *codec, u32 offset, u8 val)
-{
- writeb(val, codec->reg_area_virt + offset);
-}
-
-static inline u16 ymfpci_readw(ymfpci_t *codec, u32 offset)
-{
- return readw(codec->reg_area_virt + offset);
-}
-
-static inline void ymfpci_writew(ymfpci_t *codec, u32 offset, u16 val)
-{
- writew(val, codec->reg_area_virt + offset);
-}
-
-static inline u32 ymfpci_readl(ymfpci_t *codec, u32 offset)
-{
- return readl(codec->reg_area_virt + offset);
-}
-
-static inline void ymfpci_writel(ymfpci_t *codec, u32 offset, u32 val)
-{
- writel(val, codec->reg_area_virt + offset);
-}
-
-static int ymfpci_codec_ready(ymfpci_t *codec, int secondary, int sched)
-{
- signed long end_time;
- u32 reg = secondary ? YDSXGR_SECSTATUSADR : YDSXGR_PRISTATUSADR;
-
- end_time = jiffies + 3 * (HZ / 4);
- do {
- if ((ymfpci_readw(codec, reg) & 0x8000) == 0)
- return 0;
- if (sched) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
- } while (end_time - (signed long)jiffies >= 0);
- printk(KERN_ERR "ymfpci_codec_ready: codec %i is not ready [0x%x]\n",
- secondary, ymfpci_readw(codec, reg));
- return -EBUSY;
-}
-
-static void ymfpci_codec_write(struct ac97_codec *dev, u8 reg, u16 val)
-{
- ymfpci_t *codec = dev->private_data;
- u32 cmd;
-
- spin_lock(&codec->ac97_lock);
- /* XXX Do make use of dev->id */
- ymfpci_codec_ready(codec, 0, 0);
- cmd = ((YDSXG_AC97WRITECMD | reg) << 16) | val;
- ymfpci_writel(codec, YDSXGR_AC97CMDDATA, cmd);
- spin_unlock(&codec->ac97_lock);
-}
-
-static u16 _ymfpci_codec_read(ymfpci_t *unit, u8 reg)
-{
- int i;
-
- if (ymfpci_codec_ready(unit, 0, 0))
- return ~0;
- ymfpci_writew(unit, YDSXGR_AC97CMDADR, YDSXG_AC97READCMD | reg);
- if (ymfpci_codec_ready(unit, 0, 0))
- return ~0;
- if (unit->pci->device == PCI_DEVICE_ID_YAMAHA_744 && unit->rev < 2) {
- for (i = 0; i < 600; i++)
- ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
- }
- return ymfpci_readw(unit, YDSXGR_PRISTATUSDATA);
-}
-
-static u16 ymfpci_codec_read(struct ac97_codec *dev, u8 reg)
-{
- ymfpci_t *unit = dev->private_data;
- u16 ret;
-
- spin_lock(&unit->ac97_lock);
- ret = _ymfpci_codec_read(unit, reg);
- spin_unlock(&unit->ac97_lock);
-
- return ret;
-}
-
-/*
- * Misc routines
- */
-
-/*
- * Calculate the actual sampling rate relatetively to the base clock (48kHz).
- */
-static u32 ymfpci_calc_delta(u32 rate)
-{
- switch (rate) {
- case 8000: return 0x02aaab00;
- case 11025: return 0x03accd00;
- case 16000: return 0x05555500;
- case 22050: return 0x07599a00;
- case 32000: return 0x0aaaab00;
- case 44100: return 0x0eb33300;
- default: return ((rate << 16) / 48000) << 12;
- }
-}
-
-static u32 def_rate[8] = {
- 100, 2000, 8000, 11025, 16000, 22050, 32000, 48000
-};
-
-static u32 ymfpci_calc_lpfK(u32 rate)
-{
- u32 i;
- static u32 val[8] = {
- 0x00570000, 0x06AA0000, 0x18B20000, 0x20930000,
- 0x2B9A0000, 0x35A10000, 0x3EAA0000, 0x40000000
- };
-
- if (rate == 44100)
- return 0x40000000; /* FIXME: What's the right value? */
- for (i = 0; i < 8; i++)
- if (rate <= def_rate[i])
- return val[i];
- return val[0];
-}
-
-static u32 ymfpci_calc_lpfQ(u32 rate)
-{
- u32 i;
- static u32 val[8] = {
- 0x35280000, 0x34A70000, 0x32020000, 0x31770000,
- 0x31390000, 0x31C90000, 0x33D00000, 0x40000000
- };
-
- if (rate == 44100)
- return 0x370A0000;
- for (i = 0; i < 8; i++)
- if (rate <= def_rate[i])
- return val[i];
- return val[0];
-}
-
-static u32 ymf_calc_lend(u32 rate)
-{
- return (rate * YMF_SAMPF) / 48000;
-}
-
-/*
- * We ever allow only a few formats, but let's be generic, for smaller surprise.
- */
-static int ymf_pcm_format_width(int format)
-{
- static int mask16 = AFMT_S16_LE|AFMT_S16_BE|AFMT_U16_LE|AFMT_U16_BE;
-
- if ((format & (format-1)) != 0) {
- printk(KERN_ERR "ymfpci: format 0x%x is not a power of 2\n", format);
- return 8;
- }
-
- if (format == AFMT_IMA_ADPCM) return 4;
- if ((format & mask16) != 0) return 16;
- return 8;
-}
-
-static void ymf_pcm_update_shift(struct ymf_pcm_format *f)
-{
- f->shift = 0;
- if (f->voices == 2)
- f->shift++;
- if (ymf_pcm_format_width(f->format) == 16)
- f->shift++;
-}
-
-/* Are you sure 32K is not too much? See if mpg123 skips on loaded systems. */
-#define DMABUF_DEFAULTORDER (15-PAGE_SHIFT)
-#define DMABUF_MINORDER 1
-
-/*
- * Allocate DMA buffer
- */
-static int alloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
-{
- void *rawbuf = NULL;
- dma_addr_t dma_addr;
- int order;
- struct page *map, *mapend;
-
- /* alloc as big a chunk as we can */
- for (order = DMABUF_DEFAULTORDER; order >= DMABUF_MINORDER; order--) {
- rawbuf = pci_alloc_consistent(unit->pci, PAGE_SIZE << order, &dma_addr);
- if (rawbuf)
- break;
- }
- if (!rawbuf)
- return -ENOMEM;
-
-#if 0
- printk(KERN_DEBUG "ymfpci: allocated %ld (order = %d) bytes at %p\n",
- PAGE_SIZE << order, order, rawbuf);
-#endif
-
- dmabuf->ready = dmabuf->mapped = 0;
- dmabuf->rawbuf = rawbuf;
- dmabuf->dma_addr = dma_addr;
- dmabuf->buforder = order;
-
- /* now mark the pages as reserved; otherwise remap_pfn_range doesn't do what we want */
- mapend = virt_to_page(rawbuf + (PAGE_SIZE << order) - 1);
- for (map = virt_to_page(rawbuf); map <= mapend; map++)
- set_bit(PG_reserved, &map->flags);
-
- return 0;
-}
-
-/*
- * Free DMA buffer
- */
-static void dealloc_dmabuf(ymfpci_t *unit, struct ymf_dmabuf *dmabuf)
-{
- struct page *map, *mapend;
-
- if (dmabuf->rawbuf) {
- /* undo marking the pages as reserved */
- mapend = virt_to_page(dmabuf->rawbuf + (PAGE_SIZE << dmabuf->buforder) - 1);
- for (map = virt_to_page(dmabuf->rawbuf); map <= mapend; map++)
- clear_bit(PG_reserved, &map->flags);
-
- pci_free_consistent(unit->pci, PAGE_SIZE << dmabuf->buforder,
- dmabuf->rawbuf, dmabuf->dma_addr);
- }
- dmabuf->rawbuf = NULL;
- dmabuf->mapped = dmabuf->ready = 0;
-}
-
-static int prog_dmabuf(struct ymf_state *state, int rec)
-{
- struct ymf_dmabuf *dmabuf;
- int w_16;
- unsigned bufsize;
- unsigned long flags;
- int redzone, redfrags;
- int ret;
-
- w_16 = ymf_pcm_format_width(state->format.format) == 16;
- dmabuf = rec ? &state->rpcm.dmabuf : &state->wpcm.dmabuf;
-
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->hwptr = dmabuf->swptr = 0;
- dmabuf->total_bytes = 0;
- dmabuf->count = 0;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-
- /* allocate DMA buffer if not allocated yet */
- if (!dmabuf->rawbuf)
- if ((ret = alloc_dmabuf(state->unit, dmabuf)))
- return ret;
-
- /*
- * Create fake fragment sizes and numbers for OSS ioctls.
- * Import what Doom might have set with SNDCTL_DSP_SETFRAGMENT.
- */
- bufsize = PAGE_SIZE << dmabuf->buforder;
- /* By default we give 4 big buffers. */
- dmabuf->fragshift = (dmabuf->buforder + PAGE_SHIFT - 2);
- if (dmabuf->ossfragshift > 3 &&
- dmabuf->ossfragshift < dmabuf->fragshift) {
- /* If OSS set smaller fragments, give more smaller buffers. */
- dmabuf->fragshift = dmabuf->ossfragshift;
- }
- dmabuf->fragsize = 1 << dmabuf->fragshift;
-
- dmabuf->numfrag = bufsize >> dmabuf->fragshift;
- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
-
- if (dmabuf->ossmaxfrags >= 2) {
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= state->format.shift;
- redzone *= 3;
- redfrags = (redzone + dmabuf->fragsize-1) >> dmabuf->fragshift;
-
- if (dmabuf->ossmaxfrags + redfrags < dmabuf->numfrag) {
- dmabuf->numfrag = dmabuf->ossmaxfrags + redfrags;
- dmabuf->dmasize = dmabuf->numfrag << dmabuf->fragshift;
- }
- }
-
- memset(dmabuf->rawbuf, w_16 ? 0 : 0x80, dmabuf->dmasize);
-
- /*
- * Now set up the ring
- */
-
- /* XXX ret = rec? cap_pre(): pbk_pre(); */
- spin_lock_irqsave(&state->unit->voice_lock, flags);
- if (rec) {
- if ((ret = ymf_capture_prepare(state)) != 0) {
- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
- return ret;
- }
- } else {
- if ((ret = ymf_playback_prepare(state)) != 0) {
- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
- return ret;
- }
- }
- spin_unlock_irqrestore(&state->unit->voice_lock, flags);
-
- /* set the ready flag for the dma buffer (this comment is not stupid) */
- dmabuf->ready = 1;
-
-#if 0
- printk(KERN_DEBUG "prog_dmabuf: rate %d format 0x%x,"
- " numfrag %d fragsize %d dmasize %d\n",
- state->format.rate, state->format.format, dmabuf->numfrag,
- dmabuf->fragsize, dmabuf->dmasize);
-#endif
-
- return 0;
-}
-
-static void ymf_start_dac(struct ymf_state *state)
-{
- ymf_playback_trigger(state->unit, &state->wpcm, 1);
-}
-
-// static void ymf_start_adc(struct ymf_state *state)
-// {
-// ymf_capture_trigger(state->unit, &state->rpcm, 1);
-// }
-
-/*
- * Wait until output is drained.
- * This does not kill the hardware for the sake of ioctls.
- */
-static void ymf_wait_dac(struct ymf_state *state)
-{
- struct ymf_unit *unit = state->unit;
- struct ymf_pcm *ypcm = &state->wpcm;
- DECLARE_WAITQUEUE(waita, current);
- unsigned long flags;
-
- add_wait_queue(&ypcm->dmabuf.wait, &waita);
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (ypcm->dmabuf.count != 0 && !ypcm->running) {
- ymf_playback_trigger(unit, ypcm, 1);
- }
-
-#if 0
- if (file->f_flags & O_NONBLOCK) {
- /*
- * XXX Our mistake is to attach DMA buffer to state
- * rather than to some per-device structure.
- * Cannot skip waiting, can only make it shorter.
- */
- }
-#endif
-
- set_current_state(TASK_UNINTERRUPTIBLE);
- while (ypcm->running) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- schedule();
- spin_lock_irqsave(&unit->reg_lock, flags);
- set_current_state(TASK_UNINTERRUPTIBLE);
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&ypcm->dmabuf.wait, &waita);
-
- /*
- * This function may take up to 4 seconds to reach this point
- * (32K circular buffer, 8000 Hz). User notices.
- */
-}
-
-/* Can just stop, without wait. Or can we? */
-static void ymf_stop_adc(struct ymf_state *state)
-{
- struct ymf_unit *unit = state->unit;
- unsigned long flags;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- ymf_capture_trigger(unit, &state->rpcm, 0);
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-/*
- * Hardware start management
- */
-
-static void ymfpci_hw_start(ymfpci_t *unit)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->start_count++ == 0) {
- ymfpci_writel(unit, YDSXGR_MODE,
- ymfpci_readl(unit, YDSXGR_MODE) | 3);
- unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-static void ymfpci_hw_stop(ymfpci_t *unit)
-{
- unsigned long flags;
- long timeout = 1000;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (--unit->start_count == 0) {
- ymfpci_writel(unit, YDSXGR_MODE,
- ymfpci_readl(unit, YDSXGR_MODE) & ~3);
- while (timeout-- > 0) {
- if ((ymfpci_readl(unit, YDSXGR_STATUS) & 2) == 0)
- break;
- }
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-}
-
-/*
- * Playback voice management
- */
-
-static int voice_alloc(ymfpci_t *codec, ymfpci_voice_type_t type, int pair, ymfpci_voice_t *rvoice[])
-{
- ymfpci_voice_t *voice, *voice2;
- int idx;
-
- for (idx = 0; idx < YDSXG_PLAYBACK_VOICES; idx += pair ? 2 : 1) {
- voice = &codec->voices[idx];
- voice2 = pair ? &codec->voices[idx+1] : NULL;
- if (voice->use || (voice2 && voice2->use))
- continue;
- voice->use = 1;
- if (voice2)
- voice2->use = 1;
- switch (type) {
- case YMFPCI_PCM:
- voice->pcm = 1;
- if (voice2)
- voice2->pcm = 1;
- break;
- case YMFPCI_SYNTH:
- voice->synth = 1;
- break;
- case YMFPCI_MIDI:
- voice->midi = 1;
- break;
- }
- ymfpci_hw_start(codec);
- rvoice[0] = voice;
- if (voice2) {
- ymfpci_hw_start(codec);
- rvoice[1] = voice2;
- }
- return 0;
- }
- return -EBUSY; /* Your audio channel is open by someone else. */
-}
-
-static void ymfpci_voice_free(ymfpci_t *unit, ymfpci_voice_t *pvoice)
-{
- ymfpci_hw_stop(unit);
- pvoice->use = pvoice->pcm = pvoice->synth = pvoice->midi = 0;
- pvoice->ypcm = NULL;
-}
-
-/*
- */
-
-static void ymf_pcm_interrupt(ymfpci_t *codec, ymfpci_voice_t *voice)
-{
- struct ymf_pcm *ypcm;
- int redzone;
- int pos, delta, swptr;
- int played, distance;
- struct ymf_state *state;
- struct ymf_dmabuf *dmabuf;
- char silence;
-
- if ((ypcm = voice->ypcm) == NULL) {
- return;
- }
- if ((state = ypcm->state) == NULL) {
- ypcm->running = 0; // lock it
- return;
- }
- dmabuf = &ypcm->dmabuf;
- spin_lock(&codec->reg_lock);
- if (ypcm->running) {
- YMFDBGI("ymfpci: %d, intr bank %d count %d start 0x%x:%x\n",
- voice->number, codec->active_bank, dmabuf->count,
- le32_to_cpu(voice->bank[0].start),
- le32_to_cpu(voice->bank[1].start));
- silence = (ymf_pcm_format_width(state->format.format) == 16) ?
- 0 : 0x80;
- /* We need actual left-hand-side redzone size here. */
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= (state->format.shift + 1);
- swptr = dmabuf->swptr;
-
- pos = le32_to_cpu(voice->bank[codec->active_bank].start);
- pos <<= state->format.shift;
- if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
- printk(KERN_ERR "ymfpci%d: runaway voice %d: hwptr %d=>%d dmasize %d\n",
- codec->dev_audio, voice->number,
- dmabuf->hwptr, pos, dmabuf->dmasize);
- pos = 0;
- }
- if (pos < dmabuf->hwptr) {
- delta = dmabuf->dmasize - dmabuf->hwptr;
- memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
- delta += pos;
- memset(dmabuf->rawbuf, silence, pos);
- } else {
- delta = pos - dmabuf->hwptr;
- memset(dmabuf->rawbuf + dmabuf->hwptr, silence, delta);
- }
- dmabuf->hwptr = pos;
-
- if (dmabuf->count == 0) {
- printk(KERN_ERR "ymfpci%d: %d: strain: hwptr %d\n",
- codec->dev_audio, voice->number, dmabuf->hwptr);
- ymf_playback_trigger(codec, ypcm, 0);
- }
-
- if (swptr <= pos) {
- distance = pos - swptr;
- } else {
- distance = dmabuf->dmasize - (swptr - pos);
- }
- if (distance < redzone) {
- /*
- * hwptr inside redzone => DMA ran out of samples.
- */
- if (delta < dmabuf->count) {
- /*
- * Lost interrupt or other screwage.
- */
- printk(KERN_ERR "ymfpci%d: %d: lost: delta %d"
- " hwptr %d swptr %d distance %d count %d\n",
- codec->dev_audio, voice->number, delta,
- dmabuf->hwptr, swptr, distance, dmabuf->count);
- } else {
- /*
- * Normal end of DMA.
- */
- YMFDBGI("ymfpci%d: %d: done: delta %d"
- " hwptr %d swptr %d distance %d count %d\n",
- codec->dev_audio, voice->number, delta,
- dmabuf->hwptr, swptr, distance, dmabuf->count);
- }
- played = dmabuf->count;
- if (ypcm->running) {
- ymf_playback_trigger(codec, ypcm, 0);
- }
- } else {
- /*
- * hwptr is chipping away towards a remote swptr.
- * Calculate other distance and apply it to count.
- */
- if (swptr >= pos) {
- distance = swptr - pos;
- } else {
- distance = dmabuf->dmasize - (pos - swptr);
- }
- if (distance < dmabuf->count) {
- played = dmabuf->count - distance;
- } else {
- played = 0;
- }
- }
-
- dmabuf->total_bytes += played;
- dmabuf->count -= played;
- if (dmabuf->count < dmabuf->dmasize / 2) {
- wake_up(&dmabuf->wait);
- }
- }
- spin_unlock(&codec->reg_lock);
-}
-
-static void ymf_cap_interrupt(ymfpci_t *unit, struct ymf_capture *cap)
-{
- struct ymf_pcm *ypcm;
- int redzone;
- struct ymf_state *state;
- struct ymf_dmabuf *dmabuf;
- int pos, delta;
- int cnt;
-
- if ((ypcm = cap->ypcm) == NULL) {
- return;
- }
- if ((state = ypcm->state) == NULL) {
- ypcm->running = 0; // lock it
- return;
- }
- dmabuf = &ypcm->dmabuf;
- spin_lock(&unit->reg_lock);
- if (ypcm->running) {
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= (state->format.shift + 1);
-
- pos = le32_to_cpu(cap->bank[unit->active_bank].start);
- // pos <<= state->format.shift;
- if (pos < 0 || pos >= dmabuf->dmasize) { /* ucode bug */
- printk(KERN_ERR "ymfpci%d: runaway capture %d: hwptr %d=>%d dmasize %d\n",
- unit->dev_audio, ypcm->capture_bank_number,
- dmabuf->hwptr, pos, dmabuf->dmasize);
- pos = 0;
- }
- if (pos < dmabuf->hwptr) {
- delta = dmabuf->dmasize - dmabuf->hwptr;
- delta += pos;
- } else {
- delta = pos - dmabuf->hwptr;
- }
- dmabuf->hwptr = pos;
-
- cnt = dmabuf->count;
- cnt += delta;
- if (cnt + redzone > dmabuf->dmasize) {
- /* Overflow - bump swptr */
- dmabuf->count = dmabuf->dmasize - redzone;
- dmabuf->swptr = dmabuf->hwptr + redzone;
- if (dmabuf->swptr >= dmabuf->dmasize) {
- dmabuf->swptr -= dmabuf->dmasize;
- }
- } else {
- dmabuf->count = cnt;
- }
-
- dmabuf->total_bytes += delta;
- if (dmabuf->count) { /* && is_sleeping XXX */
- wake_up(&dmabuf->wait);
- }
- }
- spin_unlock(&unit->reg_lock);
-}
-
-static int ymf_playback_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
-{
-
- if (ypcm->voices[0] == NULL) {
- return -EINVAL;
- }
- if (cmd != 0) {
- codec->ctrl_playback[ypcm->voices[0]->number + 1] =
- cpu_to_le32(ypcm->voices[0]->bank_ba);
- if (ypcm->voices[1] != NULL)
- codec->ctrl_playback[ypcm->voices[1]->number + 1] =
- cpu_to_le32(ypcm->voices[1]->bank_ba);
- ypcm->running = 1;
- } else {
- codec->ctrl_playback[ypcm->voices[0]->number + 1] = 0;
- if (ypcm->voices[1] != NULL)
- codec->ctrl_playback[ypcm->voices[1]->number + 1] = 0;
- ypcm->running = 0;
- }
- return 0;
-}
-
-static void ymf_capture_trigger(ymfpci_t *codec, struct ymf_pcm *ypcm, int cmd)
-{
- u32 tmp;
-
- if (cmd != 0) {
- tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) | (1 << ypcm->capture_bank_number);
- ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
- ypcm->running = 1;
- } else {
- tmp = ymfpci_readl(codec, YDSXGR_MAPOFREC) & ~(1 << ypcm->capture_bank_number);
- ymfpci_writel(codec, YDSXGR_MAPOFREC, tmp);
- ypcm->running = 0;
- }
-}
-
-static int ymfpci_pcm_voice_alloc(struct ymf_pcm *ypcm, int voices)
-{
- struct ymf_unit *unit;
- int err;
-
- unit = ypcm->state->unit;
- if (ypcm->voices[1] != NULL && voices < 2) {
- ymfpci_voice_free(unit, ypcm->voices[1]);
- ypcm->voices[1] = NULL;
- }
- if (voices == 1 && ypcm->voices[0] != NULL)
- return 0; /* already allocated */
- if (voices == 2 && ypcm->voices[0] != NULL && ypcm->voices[1] != NULL)
- return 0; /* already allocated */
- if (voices > 1) {
- if (ypcm->voices[0] != NULL && ypcm->voices[1] == NULL) {
- ymfpci_voice_free(unit, ypcm->voices[0]);
- ypcm->voices[0] = NULL;
- }
- if ((err = voice_alloc(unit, YMFPCI_PCM, 1, ypcm->voices)) < 0)
- return err;
- ypcm->voices[0]->ypcm = ypcm;
- ypcm->voices[1]->ypcm = ypcm;
- } else {
- if ((err = voice_alloc(unit, YMFPCI_PCM, 0, ypcm->voices)) < 0)
- return err;
- ypcm->voices[0]->ypcm = ypcm;
- }
- return 0;
-}
-
-static void ymf_pcm_init_voice(ymfpci_voice_t *voice, int stereo,
- int rate, int w_16, unsigned long addr, unsigned int end, int spdif)
-{
- u32 format;
- u32 delta = ymfpci_calc_delta(rate);
- u32 lpfQ = ymfpci_calc_lpfQ(rate);
- u32 lpfK = ymfpci_calc_lpfK(rate);
- ymfpci_playback_bank_t *bank;
- int nbank;
-
- /*
- * The gain is a floating point number. According to the manual,
- * bit 31 indicates a sign bit, bit 30 indicates an integer part,
- * and bits [29:15] indicate a decimal fraction part. Thus,
- * for a gain of 1.0 the constant of 0x40000000 is loaded.
- */
- unsigned default_gain = cpu_to_le32(0x40000000);
-
- format = (stereo ? 0x00010000 : 0) | (w_16 ? 0 : 0x80000000);
- if (stereo)
- end >>= 1;
- if (w_16)
- end >>= 1;
- for (nbank = 0; nbank < 2; nbank++) {
- bank = &voice->bank[nbank];
- bank->format = cpu_to_le32(format);
- bank->loop_default = 0; /* 0-loops forever, otherwise count */
- bank->base = cpu_to_le32(addr);
- bank->loop_start = 0;
- bank->loop_end = cpu_to_le32(end);
- bank->loop_frac = 0;
- bank->eg_gain_end = default_gain;
- bank->lpfQ = cpu_to_le32(lpfQ);
- bank->status = 0;
- bank->num_of_frames = 0;
- bank->loop_count = 0;
- bank->start = 0;
- bank->start_frac = 0;
- bank->delta =
- bank->delta_end = cpu_to_le32(delta);
- bank->lpfK =
- bank->lpfK_end = cpu_to_le32(lpfK);
- bank->eg_gain = default_gain;
- bank->lpfD1 =
- bank->lpfD2 = 0;
-
- bank->left_gain =
- bank->right_gain =
- bank->left_gain_end =
- bank->right_gain_end =
- bank->eff1_gain =
- bank->eff2_gain =
- bank->eff3_gain =
- bank->eff1_gain_end =
- bank->eff2_gain_end =
- bank->eff3_gain_end = 0;
-
- if (!stereo) {
- if (!spdif) {
- bank->left_gain =
- bank->right_gain =
- bank->left_gain_end =
- bank->right_gain_end = default_gain;
- } else {
- bank->eff2_gain =
- bank->eff2_gain_end =
- bank->eff3_gain =
- bank->eff3_gain_end = default_gain;
- }
- } else {
- if (!spdif) {
- if ((voice->number & 1) == 0) {
- bank->left_gain =
- bank->left_gain_end = default_gain;
- } else {
- bank->format |= cpu_to_le32(1);
- bank->right_gain =
- bank->right_gain_end = default_gain;
- }
- } else {
- if ((voice->number & 1) == 0) {
- bank->eff2_gain =
- bank->eff2_gain_end = default_gain;
- } else {
- bank->format |= cpu_to_le32(1);
- bank->eff3_gain =
- bank->eff3_gain_end = default_gain;
- }
- }
- }
- }
-}
-
-/*
- * XXX Capture channel allocation is entirely fake at the moment.
- * We use only one channel and mark it busy as required.
- */
-static int ymf_capture_alloc(struct ymf_unit *unit, int *pbank)
-{
- struct ymf_capture *cap;
- int cbank;
-
- cbank = 1; /* Only ADC slot is used for now. */
- cap = &unit->capture[cbank];
- if (cap->use)
- return -EBUSY;
- cap->use = 1;
- *pbank = cbank;
- return 0;
-}
-
-static int ymf_playback_prepare(struct ymf_state *state)
-{
- struct ymf_pcm *ypcm = &state->wpcm;
- int err, nvoice;
-
- if ((err = ymfpci_pcm_voice_alloc(ypcm, state->format.voices)) < 0) {
- /* Somebody started 32 mpg123's in parallel? */
- printk(KERN_INFO "ymfpci%d: cannot allocate voice\n",
- state->unit->dev_audio);
- return err;
- }
-
- for (nvoice = 0; nvoice < state->format.voices; nvoice++) {
- ymf_pcm_init_voice(ypcm->voices[nvoice],
- state->format.voices == 2, state->format.rate,
- ymf_pcm_format_width(state->format.format) == 16,
- ypcm->dmabuf.dma_addr, ypcm->dmabuf.dmasize,
- ypcm->spdif);
- }
- return 0;
-}
-
-static int ymf_capture_prepare(struct ymf_state *state)
-{
- ymfpci_t *unit = state->unit;
- struct ymf_pcm *ypcm = &state->rpcm;
- ymfpci_capture_bank_t * bank;
- /* XXX This is confusing, gotta rename one of them banks... */
- int nbank; /* flip-flop bank */
- int cbank; /* input [super-]bank */
- struct ymf_capture *cap;
- u32 rate, format;
-
- if (ypcm->capture_bank_number == -1) {
- if (ymf_capture_alloc(unit, &cbank) != 0)
- return -EBUSY;
-
- ypcm->capture_bank_number = cbank;
-
- cap = &unit->capture[cbank];
- cap->bank = unit->bank_capture[cbank][0];
- cap->ypcm = ypcm;
- ymfpci_hw_start(unit);
- }
-
- // ypcm->frag_size = snd_pcm_lib_transfer_fragment(substream);
- // frag_size is replaced with nonfragged byte-aligned rolling buffer
- rate = ((48000 * 4096) / state->format.rate) - 1;
- format = 0;
- if (state->format.voices == 2)
- format |= 2;
- if (ymf_pcm_format_width(state->format.format) == 8)
- format |= 1;
- switch (ypcm->capture_bank_number) {
- case 0:
- ymfpci_writel(unit, YDSXGR_RECFORMAT, format);
- ymfpci_writel(unit, YDSXGR_RECSLOTSR, rate);
- break;
- case 1:
- ymfpci_writel(unit, YDSXGR_ADCFORMAT, format);
- ymfpci_writel(unit, YDSXGR_ADCSLOTSR, rate);
- break;
- }
- for (nbank = 0; nbank < 2; nbank++) {
- bank = unit->bank_capture[ypcm->capture_bank_number][nbank];
- bank->base = cpu_to_le32(ypcm->dmabuf.dma_addr);
- // bank->loop_end = ypcm->dmabuf.dmasize >> state->format.shift;
- bank->loop_end = cpu_to_le32(ypcm->dmabuf.dmasize);
- bank->start = 0;
- bank->num_of_loops = 0;
- }
-#if 0 /* s/pdif */
- if (state->digital.dig_valid)
- /*state->digital.type == SND_PCM_DIG_AES_IEC958*/
- ymfpci_writew(codec, YDSXGR_SPDIFOUTSTATUS,
- state->digital.dig_status[0] | (state->digital.dig_status[1] << 8));
-#endif
- return 0;
-}
-
-static irqreturn_t ymf_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- ymfpci_t *codec = dev_id;
- u32 status, nvoice, mode;
- struct ymf_voice *voice;
- struct ymf_capture *cap;
-
- status = ymfpci_readl(codec, YDSXGR_STATUS);
- if (status & 0x80000000) {
- codec->active_bank = ymfpci_readl(codec, YDSXGR_CTRLSELECT) & 1;
- spin_lock(&codec->voice_lock);
- for (nvoice = 0; nvoice < YDSXG_PLAYBACK_VOICES; nvoice++) {
- voice = &codec->voices[nvoice];
- if (voice->use)
- ymf_pcm_interrupt(codec, voice);
- }
- for (nvoice = 0; nvoice < YDSXG_CAPTURE_VOICES; nvoice++) {
- cap = &codec->capture[nvoice];
- if (cap->use)
- ymf_cap_interrupt(codec, cap);
- }
- spin_unlock(&codec->voice_lock);
- spin_lock(&codec->reg_lock);
- ymfpci_writel(codec, YDSXGR_STATUS, 0x80000000);
- mode = ymfpci_readl(codec, YDSXGR_MODE) | 2;
- ymfpci_writel(codec, YDSXGR_MODE, mode);
- spin_unlock(&codec->reg_lock);
- }
-
- status = ymfpci_readl(codec, YDSXGR_INTFLAG);
- if (status & 1) {
- /* timer handler */
- ymfpci_writel(codec, YDSXGR_INTFLAG, ~0);
- }
- return IRQ_HANDLED;
-}
-
-static void ymf_pcm_free_substream(struct ymf_pcm *ypcm)
-{
- unsigned long flags;
- struct ymf_unit *unit;
-
- unit = ypcm->state->unit;
-
- if (ypcm->type == PLAYBACK_VOICE) {
- spin_lock_irqsave(&unit->voice_lock, flags);
- if (ypcm->voices[1])
- ymfpci_voice_free(unit, ypcm->voices[1]);
- if (ypcm->voices[0])
- ymfpci_voice_free(unit, ypcm->voices[0]);
- spin_unlock_irqrestore(&unit->voice_lock, flags);
- } else {
- if (ypcm->capture_bank_number != -1) {
- unit->capture[ypcm->capture_bank_number].use = 0;
- ypcm->capture_bank_number = -1;
- ymfpci_hw_stop(unit);
- }
- }
-}
-
-static struct ymf_state *ymf_state_alloc(ymfpci_t *unit)
-{
- struct ymf_pcm *ypcm;
- struct ymf_state *state;
-
- if ((state = kmalloc(sizeof(struct ymf_state), GFP_KERNEL)) == NULL) {
- goto out0;
- }
- memset(state, 0, sizeof(struct ymf_state));
-
- ypcm = &state->wpcm;
- ypcm->state = state;
- ypcm->type = PLAYBACK_VOICE;
- ypcm->capture_bank_number = -1;
- init_waitqueue_head(&ypcm->dmabuf.wait);
-
- ypcm = &state->rpcm;
- ypcm->state = state;
- ypcm->type = CAPTURE_AC97;
- ypcm->capture_bank_number = -1;
- init_waitqueue_head(&ypcm->dmabuf.wait);
-
- state->unit = unit;
-
- state->format.format = AFMT_U8;
- state->format.rate = 8000;
- state->format.voices = 1;
- ymf_pcm_update_shift(&state->format);
-
- return state;
-
-out0:
- return NULL;
-}
-
-/* AES/IEC958 channel status bits */
-#define SND_PCM_AES0_PROFESSIONAL (1<<0) /* 0 = consumer, 1 = professional */
-#define SND_PCM_AES0_NONAUDIO (1<<1) /* 0 = audio, 1 = non-audio */
-#define SND_PCM_AES0_PRO_EMPHASIS (7<<2) /* mask - emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_NOTID (0<<2) /* emphasis not indicated */
-#define SND_PCM_AES0_PRO_EMPHASIS_NONE (1<<2) /* none emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_5015 (3<<2) /* 50/15us emphasis */
-#define SND_PCM_AES0_PRO_EMPHASIS_CCITT (7<<2) /* CCITT J.17 emphasis */
-#define SND_PCM_AES0_PRO_FREQ_UNLOCKED (1<<5) /* source sample frequency: 0 = locked, 1 = unlocked */
-#define SND_PCM_AES0_PRO_FS (3<<6) /* mask - sample frequency */
-#define SND_PCM_AES0_PRO_FS_NOTID (0<<6) /* fs not indicated */
-#define SND_PCM_AES0_PRO_FS_44100 (1<<6) /* 44.1kHz */
-#define SND_PCM_AES0_PRO_FS_48000 (2<<6) /* 48kHz */
-#define SND_PCM_AES0_PRO_FS_32000 (3<<6) /* 32kHz */
-#define SND_PCM_AES0_CON_NOT_COPYRIGHT (1<<2) /* 0 = copyright, 1 = not copyright */
-#define SND_PCM_AES0_CON_EMPHASIS (7<<3) /* mask - emphasis */
-#define SND_PCM_AES0_CON_EMPHASIS_NONE (0<<3) /* none emphasis */
-#define SND_PCM_AES0_CON_EMPHASIS_5015 (1<<3) /* 50/15us emphasis */
-#define SND_PCM_AES0_CON_MODE (3<<6) /* mask - mode */
-#define SND_PCM_AES1_PRO_MODE (15<<0) /* mask - channel mode */
-#define SND_PCM_AES1_PRO_MODE_NOTID (0<<0) /* not indicated */
-#define SND_PCM_AES1_PRO_MODE_STEREOPHONIC (2<<0) /* stereophonic - ch A is left */
-#define SND_PCM_AES1_PRO_MODE_SINGLE (4<<0) /* single channel */
-#define SND_PCM_AES1_PRO_MODE_TWO (8<<0) /* two channels */
-#define SND_PCM_AES1_PRO_MODE_PRIMARY (12<<0) /* primary/secondary */
-#define SND_PCM_AES1_PRO_MODE_BYTE3 (15<<0) /* vector to byte 3 */
-#define SND_PCM_AES1_PRO_USERBITS (15<<4) /* mask - user bits */
-#define SND_PCM_AES1_PRO_USERBITS_NOTID (0<<4) /* not indicated */
-#define SND_PCM_AES1_PRO_USERBITS_192 (8<<4) /* 192-bit structure */
-#define SND_PCM_AES1_PRO_USERBITS_UDEF (12<<4) /* user defined application */
-#define SND_PCM_AES1_CON_CATEGORY 0x7f
-#define SND_PCM_AES1_CON_GENERAL 0x00
-#define SND_PCM_AES1_CON_EXPERIMENTAL 0x40
-#define SND_PCM_AES1_CON_SOLIDMEM_MASK 0x0f
-#define SND_PCM_AES1_CON_SOLIDMEM_ID 0x08
-#define SND_PCM_AES1_CON_BROADCAST1_MASK 0x07
-#define SND_PCM_AES1_CON_BROADCAST1_ID 0x04
-#define SND_PCM_AES1_CON_DIGDIGCONV_MASK 0x07
-#define SND_PCM_AES1_CON_DIGDIGCONV_ID 0x02
-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_MASK 0x1f
-#define SND_PCM_AES1_CON_ADC_COPYRIGHT_ID 0x06
-#define SND_PCM_AES1_CON_ADC_MASK 0x1f
-#define SND_PCM_AES1_CON_ADC_ID 0x16
-#define SND_PCM_AES1_CON_BROADCAST2_MASK 0x0f
-#define SND_PCM_AES1_CON_BROADCAST2_ID 0x0e
-#define SND_PCM_AES1_CON_LASEROPT_MASK 0x07
-#define SND_PCM_AES1_CON_LASEROPT_ID 0x01
-#define SND_PCM_AES1_CON_MUSICAL_MASK 0x07
-#define SND_PCM_AES1_CON_MUSICAL_ID 0x05
-#define SND_PCM_AES1_CON_MAGNETIC_MASK 0x07
-#define SND_PCM_AES1_CON_MAGNETIC_ID 0x03
-#define SND_PCM_AES1_CON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x00)
-#define SND_PCM_AES1_CON_NON_IEC908_CD (SND_PCM_AES1_CON_LASEROPT_ID|0x08)
-#define SND_PCM_AES1_CON_PCM_CODER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x00)
-#define SND_PCM_AES1_CON_SAMPLER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x20)
-#define SND_PCM_AES1_CON_MIXER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x10)
-#define SND_PCM_AES1_CON_RATE_CONVERTER (SND_PCM_AES1_CON_DIGDIGCONV_ID|0x18)
-#define SND_PCM_AES1_CON_SYNTHESIZER (SND_PCM_AES1_CON_MUSICAL_ID|0x00)
-#define SND_PCM_AES1_CON_MICROPHONE (SND_PCM_AES1_CON_MUSICAL_ID|0x08)
-#define SND_PCM_AES1_CON_DAT (SND_PCM_AES1_CON_MAGNETIC_ID|0x00)
-#define SND_PCM_AES1_CON_VCR (SND_PCM_AES1_CON_MAGNETIC_ID|0x08)
-#define SND_PCM_AES1_CON_ORIGINAL (1<<7) /* this bits depends on the category code */
-#define SND_PCM_AES2_PRO_SBITS (7<<0) /* mask - sample bits */
-#define SND_PCM_AES2_PRO_SBITS_20 (2<<0) /* 20-bit - coordination */
-#define SND_PCM_AES2_PRO_SBITS_24 (4<<0) /* 24-bit - main audio */
-#define SND_PCM_AES2_PRO_SBITS_UDEF (6<<0) /* user defined application */
-#define SND_PCM_AES2_PRO_WORDLEN (7<<3) /* mask - source word length */
-#define SND_PCM_AES2_PRO_WORDLEN_NOTID (0<<3) /* not indicated */
-#define SND_PCM_AES2_PRO_WORDLEN_22_18 (2<<3) /* 22-bit or 18-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_23_19 (4<<3) /* 23-bit or 19-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_24_20 (5<<3) /* 24-bit or 20-bit */
-#define SND_PCM_AES2_PRO_WORDLEN_20_16 (6<<3) /* 20-bit or 16-bit */
-#define SND_PCM_AES2_CON_SOURCE (15<<0) /* mask - source number */
-#define SND_PCM_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */
-#define SND_PCM_AES2_CON_CHANNEL (15<<4) /* mask - channel number */
-#define SND_PCM_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */
-#define SND_PCM_AES3_CON_FS (15<<0) /* mask - sample frequency */
-#define SND_PCM_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */
-#define SND_PCM_AES3_CON_FS_48000 (2<<0) /* 48kHz */
-#define SND_PCM_AES3_CON_FS_32000 (3<<0) /* 32kHz */
-#define SND_PCM_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */
-#define SND_PCM_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */
-#define SND_PCM_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */
-#define SND_PCM_AES3_CON_CLOCK_VARIABLE (2<<4) /* variable pitch */
-
-/*
- * User interface
- */
-
-/*
- * in this loop, dmabuf.count signifies the amount of data that is
- * waiting to be copied to the user's buffer. it is filled by the dma
- * machine and drained by this loop.
- */
-static ssize_t
-ymf_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->rpcm.dmabuf;
- struct ymf_unit *unit = state->unit;
- DECLARE_WAITQUEUE(waita, current);
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt; /* This many to go in this revolution */
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 1)))
- return ret;
- ret = 0;
-
- add_wait_queue(&dmabuf->wait, &waita);
- set_current_state(TASK_INTERRUPTIBLE);
- while (count > 0) {
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
- swptr = dmabuf->swptr;
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count < cnt)
- cnt = dmabuf->count;
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- unsigned long tmo;
- /* buffer is empty, start the dma machine and wait for data to be
- recorded */
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (!state->rpcm.running) {
- ymf_capture_trigger(state->unit, &state->rpcm, 1);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- /* This isnt strictly right for the 810 but it'll do */
- tmo = (dmabuf->dmasize * HZ) / (state->format.rate * 2);
- tmo >>= state->format.shift;
- /* There are two situations when sleep_on_timeout returns, one is when
- the interrupt is serviced correctly and the process is waked up by
- ISR ON TIME. Another is when timeout is expired, which means that
- either interrupt is NOT serviced correctly (pending interrupt) or it
- is TOO LATE for the process to be scheduled to run (scheduler latency)
- which results in a (potential) buffer overrun. And worse, there is
- NOTHING we can do to prevent it. */
- tmo = schedule_timeout(tmo);
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tmo == 0 && dmabuf->count == 0) {
- printk(KERN_ERR "ymfpci%d: recording schedule timeout, "
- "dmasz %u fragsz %u count %i hwptr %u swptr %u\n",
- state->unit->dev_audio,
- dmabuf->dmasize, dmabuf->fragsize, dmabuf->count,
- dmabuf->hwptr, dmabuf->swptr);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
-
- if (copy_to_user(buffer, dmabuf->rawbuf + swptr, cnt)) {
- if (!ret) ret = -EFAULT;
- break;
- }
-
- swptr = (swptr + cnt) % dmabuf->dmasize;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- continue;
- }
-
- dmabuf->swptr = swptr;
- dmabuf->count -= cnt;
- // spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- // spin_lock_irqsave(&unit->reg_lock, flags);
- if (!state->rpcm.running) {
- ymf_capture_trigger(unit, &state->rpcm, 1);
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- }
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- return ret;
-}
-
-static ssize_t
-ymf_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
- struct ymf_unit *unit = state->unit;
- DECLARE_WAITQUEUE(waita, current);
- ssize_t ret;
- unsigned long flags;
- unsigned int swptr;
- int cnt; /* This many to go in this revolution */
- int redzone;
- int delay;
-
- YMFDBGW("ymf_write: count %d\n", count);
-
- if (dmabuf->mapped)
- return -ENXIO;
- if (!dmabuf->ready && (ret = prog_dmabuf(state, 0)))
- return ret;
- ret = 0;
-
- /*
- * Alan's cs46xx works without a red zone - marvel of ingenuity.
- * We are not so brilliant... Red zone does two things:
- * 1. allows for safe start after a pause as we have no way
- * to know what the actual, relentlessly advancing, hwptr is.
- * 2. makes computations in ymf_pcm_interrupt simpler.
- */
- redzone = ymf_calc_lend(state->format.rate) << state->format.shift;
- redzone *= 3; /* 2 redzone + 1 possible uncertainty reserve. */
-
- add_wait_queue(&dmabuf->wait, &waita);
- set_current_state(TASK_INTERRUPTIBLE);
- while (count > 0) {
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- continue;
- }
- if (dmabuf->count < 0) {
- printk(KERN_ERR
- "ymf_write: count %d, was legal in cs46xx\n",
- dmabuf->count);
- dmabuf->count = 0;
- }
- if (dmabuf->count == 0) {
- swptr = dmabuf->hwptr;
- if (state->wpcm.running) {
- /*
- * Add uncertainty reserve.
- */
- cnt = ymf_calc_lend(state->format.rate);
- cnt <<= state->format.shift;
- if ((swptr += cnt) >= dmabuf->dmasize) {
- swptr -= dmabuf->dmasize;
- }
- }
- dmabuf->swptr = swptr;
- } else {
- /*
- * XXX This is not right if dmabuf->count is small -
- * about 2*x frame size or less. We cannot count on
- * on appending and not causing an artefact.
- * Should use a variation of the count==0 case above.
- */
- swptr = dmabuf->swptr;
- }
- cnt = dmabuf->dmasize - swptr;
- if (dmabuf->count + cnt > dmabuf->dmasize - redzone)
- cnt = (dmabuf->dmasize - redzone) - dmabuf->count;
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- if (cnt > count)
- cnt = count;
- if (cnt <= 0) {
- YMFDBGW("ymf_write: full, count %d swptr %d\n",
- dmabuf->count, dmabuf->swptr);
- /*
- * buffer is full, start the dma machine and
- * wait for data to be played
- */
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (!state->wpcm.running) {
- ymf_playback_trigger(unit, &state->wpcm, 1);
- }
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- if (file->f_flags & O_NONBLOCK) {
- if (!ret) ret = -EAGAIN;
- break;
- }
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- if (signal_pending(current)) {
- if (!ret) ret = -ERESTARTSYS;
- break;
- }
- continue;
- }
- if (copy_from_user(dmabuf->rawbuf + swptr, buffer, cnt)) {
- if (!ret) ret = -EFAULT;
- break;
- }
-
- if ((swptr += cnt) >= dmabuf->dmasize) {
- swptr -= dmabuf->dmasize;
- }
-
- spin_lock_irqsave(&unit->reg_lock, flags);
- if (unit->suspended) {
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- continue;
- }
- dmabuf->swptr = swptr;
- dmabuf->count += cnt;
-
- /*
- * Start here is a bad idea - may cause startup click
- * in /bin/play when dmabuf is not full yet.
- * However, some broken applications do not make
- * any use of SNDCTL_DSP_SYNC (Doom is the worst).
- * One frame is about 5.3ms, Doom write size is 46ms.
- */
- delay = state->format.rate / 20; /* 50ms */
- delay <<= state->format.shift;
- if (dmabuf->count >= delay && !state->wpcm.running) {
- ymf_playback_trigger(unit, &state->wpcm, 1);
- }
-
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- count -= cnt;
- buffer += cnt;
- ret += cnt;
- }
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&dmabuf->wait, &waita);
-
- YMFDBGW("ymf_write: ret %d dmabuf.count %d\n", ret, dmabuf->count);
- return ret;
-}
-
-static unsigned int ymf_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf;
- int redzone;
- unsigned long flags;
- unsigned int mask = 0;
-
- if (file->f_mode & FMODE_WRITE)
- poll_wait(file, &state->wpcm.dmabuf.wait, wait);
- if (file->f_mode & FMODE_READ)
- poll_wait(file, &state->rpcm.dmabuf.wait, wait);
-
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (file->f_mode & FMODE_READ) {
- dmabuf = &state->rpcm.dmabuf;
- if (dmabuf->count >= (signed)dmabuf->fragsize)
- mask |= POLLIN | POLLRDNORM;
- }
- if (file->f_mode & FMODE_WRITE) {
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= state->format.shift;
- redzone *= 3;
-
- dmabuf = &state->wpcm.dmabuf;
- if (dmabuf->mapped) {
- if (dmabuf->count >= (signed)dmabuf->fragsize)
- mask |= POLLOUT | POLLWRNORM;
- } else {
- /*
- * Don't select unless a full fragment is available.
- * Otherwise artsd does GETOSPACE, sees 0, and loops.
- */
- if (dmabuf->count + redzone + dmabuf->fragsize
- <= dmabuf->dmasize)
- mask |= POLLOUT | POLLWRNORM;
- }
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
-
- return mask;
-}
-
-static int ymf_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf = &state->wpcm.dmabuf;
- int ret;
- unsigned long size;
-
- if (vma->vm_flags & VM_WRITE) {
- if ((ret = prog_dmabuf(state, 0)) != 0)
- return ret;
- } else if (vma->vm_flags & VM_READ) {
- if ((ret = prog_dmabuf(state, 1)) != 0)
- return ret;
- } else
- return -EINVAL;
-
- if (vma->vm_pgoff != 0)
- return -EINVAL;
- size = vma->vm_end - vma->vm_start;
- if (size > (PAGE_SIZE << dmabuf->buforder))
- return -EINVAL;
- if (remap_pfn_range(vma, vma->vm_start,
- virt_to_phys(dmabuf->rawbuf) >> PAGE_SHIFT,
- size, vma->vm_page_prot))
- return -EAGAIN;
- dmabuf->mapped = 1;
-
-/* P3 */ printk(KERN_INFO "ymfpci: using memory mapped sound, untested!\n");
- return 0;
-}
-
-static int ymf_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- struct ymf_dmabuf *dmabuf;
- unsigned long flags;
- audio_buf_info abinfo;
- count_info cinfo;
- int redzone;
- int val;
- void __user *argp = (void __user *)arg;
- int __user *p = argp;
-
- switch (cmd) {
- case OSS_GETVERSION:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETVER) arg 0x%lx\n", cmd, arg);
- return put_user(SOUND_VERSION, p);
-
- case SNDCTL_DSP_RESET:
- YMFDBGX("ymf_ioctl: cmd 0x%x(RESET)\n", cmd);
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = dmabuf->total_bytes = 0;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- dmabuf->swptr = dmabuf->hwptr;
- dmabuf->count = dmabuf->total_bytes = 0;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- return 0;
-
- case SNDCTL_DSP_SYNC:
- YMFDBGX("ymf_ioctl: cmd 0x%x(SYNC)\n", cmd);
- if (file->f_mode & FMODE_WRITE) {
- dmabuf = &state->wpcm.dmabuf;
- if (file->f_flags & O_NONBLOCK) {
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (dmabuf->count != 0 && !state->wpcm.running) {
- ymf_start_dac(state);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- } else {
- ymf_wait_dac(state);
- }
- }
- /* XXX What does this do for reading? dmabuf->count=0; ? */
- return 0;
-
- case SNDCTL_DSP_SPEED: /* set smaple rate */
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(SPEED) sp %d\n", cmd, val);
- if (val >= 8000 && val <= 48000) {
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.rate = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.rate = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- return put_user(state->format.rate, p);
-
- /*
- * OSS manual does not mention SNDCTL_DSP_STEREO at all.
- * All channels are mono and if you want stereo, you
- * play into two channels with SNDCTL_DSP_CHANNELS.
- * However, mpg123 calls it. I wonder, why Michael Hipp used it.
- */
- case SNDCTL_DSP_STEREO: /* set stereo or mono channel */
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(STEREO) st %d\n", cmd, val);
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.voices = val ? 2 : 1;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.voices = val ? 2 : 1;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- return 0;
-
- case SNDCTL_DSP_GETBLKSIZE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETBLK)\n", cmd);
- if (file->f_mode & FMODE_WRITE) {
- if ((val = prog_dmabuf(state, 0)))
- return val;
- val = state->wpcm.dmabuf.fragsize;
- YMFDBGX("ymf_ioctl: GETBLK w %d\n", val);
- return put_user(val, p);
- }
- if (file->f_mode & FMODE_READ) {
- if ((val = prog_dmabuf(state, 1)))
- return val;
- val = state->rpcm.dmabuf.fragsize;
- YMFDBGX("ymf_ioctl: GETBLK r %d\n", val);
- return put_user(val, p);
- }
- return -EINVAL;
-
- case SNDCTL_DSP_GETFMTS: /* Returns a mask of supported sample format*/
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETFMTS)\n", cmd);
- return put_user(AFMT_S16_LE|AFMT_U8, p);
-
- case SNDCTL_DSP_SETFMT: /* Select sample format */
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(SETFMT) fmt %d\n", cmd, val);
- if (val == AFMT_S16_LE || val == AFMT_U8) {
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.format = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf->ready = 0;
- state->format.format = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- return put_user(state->format.format, p);
-
- case SNDCTL_DSP_CHANNELS:
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(CHAN) ch %d\n", cmd, val);
- if (val != 0) {
- if (file->f_mode & FMODE_WRITE) {
- ymf_wait_dac(state);
- if (val == 1 || val == 2) {
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf = &state->wpcm.dmabuf;
- dmabuf->ready = 0;
- state->format.voices = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- if (file->f_mode & FMODE_READ) {
- ymf_stop_adc(state);
- if (val == 1 || val == 2) {
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- dmabuf = &state->rpcm.dmabuf;
- dmabuf->ready = 0;
- state->format.voices = val;
- ymf_pcm_update_shift(&state->format);
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- }
- }
- }
- return put_user(state->format.voices, p);
-
- case SNDCTL_DSP_POST:
- YMFDBGX("ymf_ioctl: cmd 0x%x(POST)\n", cmd);
- /*
- * Quoting OSS PG:
- * The ioctl SNDCTL_DSP_POST is a lightweight version of
- * SNDCTL_DSP_SYNC. It just tells to the driver that there
- * is likely to be a pause in the output. This makes it
- * possible for the device to handle the pause more
- * intelligently. This ioctl doesn't block the application.
- *
- * The paragraph above is a clumsy way to say "flush ioctl".
- * This ioctl is used by mpg123.
- */
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- if (state->wpcm.dmabuf.count != 0 && !state->wpcm.running) {
- ymf_start_dac(state);
- }
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return 0;
-
- case SNDCTL_DSP_SETFRAGMENT:
- if (get_user(val, p))
- return -EFAULT;
- YMFDBGX("ymf_ioctl: cmd 0x%x(SETFRAG) fr 0x%04x:%04x(%d:%d)\n",
- cmd,
- (val >> 16) & 0xFFFF, val & 0xFFFF,
- (val >> 16) & 0xFFFF, val & 0xFFFF);
- dmabuf = &state->wpcm.dmabuf;
- dmabuf->ossfragshift = val & 0xffff;
- dmabuf->ossmaxfrags = (val >> 16) & 0xffff;
- if (dmabuf->ossfragshift < 4)
- dmabuf->ossfragshift = 4;
- if (dmabuf->ossfragshift > 15)
- dmabuf->ossfragshift = 15;
- return 0;
-
- case SNDCTL_DSP_GETOSPACE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETOSPACE)\n", cmd);
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- dmabuf = &state->wpcm.dmabuf;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 0)) != 0)
- return val;
- redzone = ymf_calc_lend(state->format.rate);
- redzone <<= state->format.shift;
- redzone *= 3;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->dmasize - dmabuf->count - redzone;
- abinfo.fragstotal = dmabuf->numfrag;
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETISPACE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETISPACE)\n", cmd);
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- dmabuf = &state->rpcm.dmabuf;
- if (!dmabuf->ready && (val = prog_dmabuf(state, 1)) != 0)
- return val;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- abinfo.fragsize = dmabuf->fragsize;
- abinfo.bytes = dmabuf->count;
- abinfo.fragstotal = dmabuf->numfrag;
- abinfo.fragments = abinfo.bytes >> dmabuf->fragshift;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- return copy_to_user(argp, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_NONBLOCK:
- YMFDBGX("ymf_ioctl: cmd 0x%x(NONBLOCK)\n", cmd);
- file->f_flags |= O_NONBLOCK;
- return 0;
-
- case SNDCTL_DSP_GETCAPS:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETCAPS)\n", cmd);
- /* return put_user(DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP,
- p); */
- return put_user(0, p);
-
- case SNDCTL_DSP_GETIPTR:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETIPTR)\n", cmd);
- if (!(file->f_mode & FMODE_READ))
- return -EINVAL;
- dmabuf = &state->rpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
- cinfo.ptr = dmabuf->hwptr;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- YMFDBGX("ymf_ioctl: GETIPTR ptr %d bytes %d\n",
- cinfo.ptr, cinfo.bytes);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_GETOPTR:
- YMFDBGX("ymf_ioctl: cmd 0x%x(GETOPTR)\n", cmd);
- if (!(file->f_mode & FMODE_WRITE))
- return -EINVAL;
- dmabuf = &state->wpcm.dmabuf;
- spin_lock_irqsave(&state->unit->reg_lock, flags);
- cinfo.bytes = dmabuf->total_bytes;
- cinfo.blocks = dmabuf->count >> dmabuf->fragshift;
- cinfo.ptr = dmabuf->hwptr;
- spin_unlock_irqrestore(&state->unit->reg_lock, flags);
- YMFDBGX("ymf_ioctl: GETOPTR ptr %d bytes %d\n",
- cinfo.ptr, cinfo.bytes);
- return copy_to_user(argp, &cinfo, sizeof(cinfo)) ? -EFAULT : 0;
-
- case SNDCTL_DSP_SETDUPLEX:
- YMFDBGX("ymf_ioctl: cmd 0x%x(SETDUPLEX)\n", cmd);
- return 0; /* Always duplex */
-
- case SOUND_PCM_READ_RATE:
- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_RATE)\n", cmd);
- return put_user(state->format.rate, p);
-
- case SOUND_PCM_READ_CHANNELS:
- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_CH)\n", cmd);
- return put_user(state->format.voices, p);
-
- case SOUND_PCM_READ_BITS:
- YMFDBGX("ymf_ioctl: cmd 0x%x(READ_BITS)\n", cmd);
- return put_user(AFMT_S16_LE, p);
-
- case SNDCTL_DSP_MAPINBUF:
- case SNDCTL_DSP_MAPOUTBUF:
- case SNDCTL_DSP_SETSYNCRO:
- case SOUND_PCM_WRITE_FILTER:
- case SOUND_PCM_READ_FILTER:
- YMFDBGX("ymf_ioctl: cmd 0x%x unsupported\n", cmd);
- return -ENOTTY;
-
- default:
- /*
- * Some programs mix up audio devices and ioctls
- * or perhaps they expect "universal" ioctls,
- * for instance we get SNDCTL_TMR_CONTINUE here.
- * (mpg123 -g 100 ends here too - to be fixed.)
- */
- YMFDBGX("ymf_ioctl: cmd 0x%x unknown\n", cmd);
- break;
- }
- return -ENOTTY;
-}
-
-/*
- * open(2)
- * We use upper part of the minor to distinguish between soundcards.
- * Channels are opened with a clone open.
- */
-static int ymf_open(struct inode *inode, struct file *file)
-{
- struct list_head *list;
- ymfpci_t *unit = NULL;
- int minor;
- struct ymf_state *state;
- int err;
-
- minor = iminor(inode);
- if ((minor & 0x0F) == 3) { /* /dev/dspN */
- ;
- } else {
- return -ENXIO;
- }
-
- unit = NULL; /* gcc warns */
- spin_lock(&ymf_devs_lock);
- list_for_each(list, &ymf_devs) {
- unit = list_entry(list, ymfpci_t, ymf_devs);
- if (((unit->dev_audio ^ minor) & ~0x0F) == 0)
- break;
- }
- spin_unlock(&ymf_devs_lock);
- if (unit == NULL)
- return -ENODEV;
-
- mutex_lock(&unit->open_mutex);
-
- if ((state = ymf_state_alloc(unit)) == NULL) {
- mutex_unlock(&unit->open_mutex);
- return -ENOMEM;
- }
- list_add_tail(&state->chain, &unit->states);
-
- file->private_data = state;
-
- /*
- * ymf_read and ymf_write that we borrowed from cs46xx
- * allocate buffers with prog_dmabuf(). We call prog_dmabuf
- * here so that in case of DMA memory exhaustion open
- * fails rather than write.
- *
- * XXX prog_dmabuf allocates voice. Should allocate explicitly, above.
- */
- if (file->f_mode & FMODE_WRITE) {
- if (!state->wpcm.dmabuf.ready) {
- if ((err = prog_dmabuf(state, 0)) != 0) {
- goto out_nodma;
- }
- }
- }
- if (file->f_mode & FMODE_READ) {
- if (!state->rpcm.dmabuf.ready) {
- if ((err = prog_dmabuf(state, 1)) != 0) {
- goto out_nodma;
- }
- }
- }
-
-#if 0 /* test if interrupts work */
- ymfpci_writew(unit, YDSXGR_TIMERCOUNT, 0xfffe); /* ~ 680ms */
- ymfpci_writeb(unit, YDSXGR_TIMERCTRL,
- (YDSXGR_TIMERCTRL_TEN|YDSXGR_TIMERCTRL_TIEN));
-#endif
- mutex_unlock(&unit->open_mutex);
-
- return nonseekable_open(inode, file);
-
-out_nodma:
- /*
- * XXX Broken custom: "goto out_xxx" in other place is
- * a nestable exception, but here it is not nestable due to semaphore.
- * XXX Doubtful technique of self-describing objects....
- */
- dealloc_dmabuf(unit, &state->wpcm.dmabuf);
- dealloc_dmabuf(unit, &state->rpcm.dmabuf);
- ymf_pcm_free_substream(&state->wpcm);
- ymf_pcm_free_substream(&state->rpcm);
-
- list_del(&state->chain);
- kfree(state);
-
- mutex_unlock(&unit->open_mutex);
- return err;
-}
-
-static int ymf_release(struct inode *inode, struct file *file)
-{
- struct ymf_state *state = (struct ymf_state *)file->private_data;
- ymfpci_t *unit = state->unit;
-
-#if 0 /* test if interrupts work */
- ymfpci_writeb(unit, YDSXGR_TIMERCTRL, 0);
-#endif
-
- mutex_lock(&unit->open_mutex);
-
- /*
- * XXX Solve the case of O_NONBLOCK close - don't deallocate here.
- * Deallocate when unloading the driver and we can wait.
- */
- ymf_wait_dac(state);
- ymf_stop_adc(state); /* fortunately, it's immediate */
- dealloc_dmabuf(unit, &state->wpcm.dmabuf);
- dealloc_dmabuf(unit, &state->rpcm.dmabuf);
- ymf_pcm_free_substream(&state->wpcm);
- ymf_pcm_free_substream(&state->rpcm);
-
- list_del(&state->chain);
- file->private_data = NULL; /* Can you tell I programmed Solaris */
- kfree(state);
-
- mutex_unlock(&unit->open_mutex);
-
- return 0;
-}
-
-/*
- * Mixer operations are based on cs46xx.
- */
-static int ymf_open_mixdev(struct inode *inode, struct file *file)
-{
- int minor = iminor(inode);
- struct list_head *list;
- ymfpci_t *unit;
- int i;
-
- spin_lock(&ymf_devs_lock);
- list_for_each(list, &ymf_devs) {
- unit = list_entry(list, ymfpci_t, ymf_devs);
- for (i = 0; i < NR_AC97; i++) {
- if (unit->ac97_codec[i] != NULL &&
- unit->ac97_codec[i]->dev_mixer == minor) {
- spin_unlock(&ymf_devs_lock);
- goto match;
- }
- }
- }
- spin_unlock(&ymf_devs_lock);
- return -ENODEV;
-
- match:
- file->private_data = unit->ac97_codec[i];
-
- return nonseekable_open(inode, file);
-}
-
-static int ymf_ioctl_mixdev(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct ac97_codec *codec = (struct ac97_codec *)file->private_data;
-
- return codec->mixer_ioctl(codec, cmd, arg);
-}
-
-static int ymf_release_mixdev(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static /*const*/ struct file_operations ymf_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = ymf_read,
- .write = ymf_write,
- .poll = ymf_poll,
- .ioctl = ymf_ioctl,
- .mmap = ymf_mmap,
- .open = ymf_open,
- .release = ymf_release,
-};
-
-static /*const*/ struct file_operations ymf_mixer_fops = {
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .ioctl = ymf_ioctl_mixdev,
- .open = ymf_open_mixdev,
- .release = ymf_release_mixdev,
-};
-
-/*
- */
-
-static int ymf_suspend(struct pci_dev *pcidev, pm_message_t unused)
-{
- struct ymf_unit *unit = pci_get_drvdata(pcidev);
- unsigned long flags;
- struct ymf_dmabuf *dmabuf;
- struct list_head *p;
- struct ymf_state *state;
- struct ac97_codec *codec;
- int i;
-
- spin_lock_irqsave(&unit->reg_lock, flags);
-
- unit->suspended = 1;
-
- for (i = 0; i < NR_AC97; i++) {
- if ((codec = unit->ac97_codec[i]) != NULL)
- ac97_save_state(codec);
- }
-
- list_for_each(p, &unit->states) {
- state = list_entry(p, struct ymf_state, chain);
-
- dmabuf = &state->wpcm.dmabuf;
- dmabuf->hwptr = dmabuf->swptr = 0;
- dmabuf->total_bytes = 0;
- dmabuf->count = 0;
-
- dmabuf = &state->rpcm.dmabuf;
- dmabuf->hwptr = dmabuf->swptr = 0;
- dmabuf->total_bytes = 0;
- dmabuf->count = 0;
- }
-
- ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0);
- ymfpci_disable_dsp(unit);
-
- spin_unlock_irqrestore(&unit->reg_lock, flags);
-
- return 0;
-}
-
-static int ymf_resume(struct pci_dev *pcidev)
-{
- struct ymf_unit *unit = pci_get_drvdata(pcidev);
- unsigned long flags;
- struct list_head *p;
- struct ymf_state *state;
- struct ac97_codec *codec;
- int i;
-
- ymfpci_aclink_reset(unit->pci);
- ymfpci_codec_ready(unit, 0, 1); /* prints diag if not ready. */
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- /* XXX At this time the legacy registers are probably deprogrammed. */
-#endif
-
- ymfpci_download_image(unit);
-
- ymf_memload(unit);
-
- spin_lock_irqsave(&unit->reg_lock, flags);
-
- if (unit->start_count) {
- ymfpci_writel(unit, YDSXGR_MODE, 3);
- unit->active_bank = ymfpci_readl(unit, YDSXGR_CTRLSELECT) & 1;
- }
-
- for (i = 0; i < NR_AC97; i++) {
- if ((codec = unit->ac97_codec[i]) != NULL)
- ac97_restore_state(codec);
- }
-
- unit->suspended = 0;
- list_for_each(p, &unit->states) {
- state = list_entry(p, struct ymf_state, chain);
- wake_up(&state->wpcm.dmabuf.wait);
- wake_up(&state->rpcm.dmabuf.wait);
- }
-
- spin_unlock_irqrestore(&unit->reg_lock, flags);
- return 0;
-}
-
-/*
- * initialization routines
- */
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-
-static int ymfpci_setup_legacy(ymfpci_t *unit, struct pci_dev *pcidev)
-{
- int v;
- int mpuio = -1, oplio = -1;
-
- switch (unit->iomidi) {
- case 0x330:
- mpuio = 0;
- break;
- case 0x300:
- mpuio = 1;
- break;
- case 0x332:
- mpuio = 2;
- break;
- case 0x334:
- mpuio = 3;
- break;
- default: ;
- }
-
- switch (unit->iosynth) {
- case 0x388:
- oplio = 0;
- break;
- case 0x398:
- oplio = 1;
- break;
- case 0x3a0:
- oplio = 2;
- break;
- case 0x3a8:
- oplio = 3;
- break;
- default: ;
- }
-
- if (mpuio >= 0 || oplio >= 0) {
- /* 0x0020: 1 - 10 bits of I/O address decoded, 0 - 16 bits. */
- v = 0x001e;
- pci_write_config_word(pcidev, PCIR_LEGCTRL, v);
-
- switch (pcidev->device) {
- case PCI_DEVICE_ID_YAMAHA_724:
- case PCI_DEVICE_ID_YAMAHA_740:
- case PCI_DEVICE_ID_YAMAHA_724F:
- case PCI_DEVICE_ID_YAMAHA_740C:
- v = 0x8800;
- if (mpuio >= 0) { v |= mpuio<<4; }
- if (oplio >= 0) { v |= oplio; }
- pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
- break;
-
- case PCI_DEVICE_ID_YAMAHA_744:
- case PCI_DEVICE_ID_YAMAHA_754:
- v = 0x8800;
- pci_write_config_word(pcidev, PCIR_ELEGCTRL, v);
- if (oplio >= 0) {
- pci_write_config_word(pcidev, PCIR_OPLADR, unit->iosynth);
- }
- if (mpuio >= 0) {
- pci_write_config_word(pcidev, PCIR_MPUADR, unit->iomidi);
- }
- break;
-
- default:
- printk(KERN_ERR "ymfpci: Unknown device ID: 0x%x\n",
- pcidev->device);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
-static void ymfpci_aclink_reset(struct pci_dev * pci)
-{
- u8 cmd;
-
- /*
- * In the 744, 754 only 0x01 exists, 0x02 is undefined.
- * It does not seem to hurt to trip both regardless of revision.
- */
- pci_read_config_byte(pci, PCIR_DSXGCTRL, &cmd);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd | 0x03);
- pci_write_config_byte(pci, PCIR_DSXGCTRL, cmd & 0xfc);
-
- pci_write_config_word(pci, PCIR_DSXPWRCTRL1, 0);
- pci_write_config_word(pci, PCIR_DSXPWRCTRL2, 0);
-}
-
-static void ymfpci_enable_dsp(ymfpci_t *codec)
-{
- ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000001);
-}
-
-static void ymfpci_disable_dsp(ymfpci_t *codec)
-{
- u32 val;
- int timeout = 1000;
-
- val = ymfpci_readl(codec, YDSXGR_CONFIG);
- if (val)
- ymfpci_writel(codec, YDSXGR_CONFIG, 0x00000000);
- while (timeout-- > 0) {
- val = ymfpci_readl(codec, YDSXGR_STATUS);
- if ((val & 0x00000002) == 0)
- break;
- }
-}
-
-#include "ymfpci_image.h"
-
-static void ymfpci_download_image(ymfpci_t *codec)
-{
- int i, ver_1e;
- u16 ctrl;
-
- ymfpci_writel(codec, YDSXGR_NATIVEDACOUTVOL, 0x00000000);
- ymfpci_disable_dsp(codec);
- ymfpci_writel(codec, YDSXGR_MODE, 0x00010000);
- ymfpci_writel(codec, YDSXGR_MODE, 0x00000000);
- ymfpci_writel(codec, YDSXGR_MAPOFREC, 0x00000000);
- ymfpci_writel(codec, YDSXGR_MAPOFEFFECT, 0x00000000);
- ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0x00000000);
- ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0x00000000);
- ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0x00000000);
- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
-
- /* setup DSP instruction code */
- for (i = 0; i < YDSXG_DSPLENGTH / 4; i++)
- ymfpci_writel(codec, YDSXGR_DSPINSTRAM + (i << 2), DspInst[i]);
-
- switch (codec->pci->device) {
- case PCI_DEVICE_ID_YAMAHA_724F:
- case PCI_DEVICE_ID_YAMAHA_740C:
- case PCI_DEVICE_ID_YAMAHA_744:
- case PCI_DEVICE_ID_YAMAHA_754:
- ver_1e = 1;
- break;
- default:
- ver_1e = 0;
- }
-
- if (ver_1e) {
- /* setup control instruction code */
- for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
- ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst1E[i]);
- } else {
- for (i = 0; i < YDSXG_CTRLLENGTH / 4; i++)
- ymfpci_writel(codec, YDSXGR_CTRLINSTRAM + (i << 2), CntrlInst[i]);
- }
-
- ymfpci_enable_dsp(codec);
-
- /* 0.02s sounds not too bad, we may do schedule_timeout() later. */
- mdelay(20); /* seems we need some delay after downloading image.. */
-}
-
-static int ymfpci_memalloc(ymfpci_t *codec)
-{
- unsigned int playback_ctrl_size;
- unsigned int bank_size_playback;
- unsigned int bank_size_capture;
- unsigned int bank_size_effect;
- unsigned int size;
- unsigned int off;
- char *ptr;
- dma_addr_t pba;
- int voice, bank;
-
- playback_ctrl_size = 4 + 4 * YDSXG_PLAYBACK_VOICES;
- bank_size_playback = ymfpci_readl(codec, YDSXGR_PLAYCTRLSIZE) << 2;
- bank_size_capture = ymfpci_readl(codec, YDSXGR_RECCTRLSIZE) << 2;
- bank_size_effect = ymfpci_readl(codec, YDSXGR_EFFCTRLSIZE) << 2;
- codec->work_size = YDSXG_DEFAULT_WORK_SIZE;
-
- size = ((playback_ctrl_size + 0x00ff) & ~0x00ff) +
- ((bank_size_playback * 2 * YDSXG_PLAYBACK_VOICES + 0xff) & ~0xff) +
- ((bank_size_capture * 2 * YDSXG_CAPTURE_VOICES + 0xff) & ~0xff) +
- ((bank_size_effect * 2 * YDSXG_EFFECT_VOICES + 0xff) & ~0xff) +
- codec->work_size;
-
- ptr = pci_alloc_consistent(codec->pci, size + 0xff, &pba);
- if (ptr == NULL)
- return -ENOMEM;
- codec->dma_area_va = ptr;
- codec->dma_area_ba = pba;
- codec->dma_area_size = size + 0xff;
-
- off = (unsigned long)ptr & 0xff;
- if (off) {
- ptr += 0x100 - off;
- pba += 0x100 - off;
- }
-
- /*
- * Hardware requires only ptr[playback_ctrl_size] zeroed,
- * but in our judgement it is a wrong kind of savings, so clear it all.
- */
- memset(ptr, 0, size);
-
- codec->ctrl_playback = (u32 *)ptr;
- codec->ctrl_playback_ba = pba;
- codec->ctrl_playback[0] = cpu_to_le32(YDSXG_PLAYBACK_VOICES);
- ptr += (playback_ctrl_size + 0x00ff) & ~0x00ff;
- pba += (playback_ctrl_size + 0x00ff) & ~0x00ff;
-
- off = 0;
- for (voice = 0; voice < YDSXG_PLAYBACK_VOICES; voice++) {
- codec->voices[voice].number = voice;
- codec->voices[voice].bank =
- (ymfpci_playback_bank_t *) (ptr + off);
- codec->voices[voice].bank_ba = pba + off;
- off += 2 * bank_size_playback; /* 2 banks */
- }
- off = (off + 0xff) & ~0xff;
- ptr += off;
- pba += off;
-
- off = 0;
- codec->bank_base_capture = pba;
- for (voice = 0; voice < YDSXG_CAPTURE_VOICES; voice++)
- for (bank = 0; bank < 2; bank++) {
- codec->bank_capture[voice][bank] =
- (ymfpci_capture_bank_t *) (ptr + off);
- off += bank_size_capture;
- }
- off = (off + 0xff) & ~0xff;
- ptr += off;
- pba += off;
-
- off = 0;
- codec->bank_base_effect = pba;
- for (voice = 0; voice < YDSXG_EFFECT_VOICES; voice++)
- for (bank = 0; bank < 2; bank++) {
- codec->bank_effect[voice][bank] =
- (ymfpci_effect_bank_t *) (ptr + off);
- off += bank_size_effect;
- }
- off = (off + 0xff) & ~0xff;
- ptr += off;
- pba += off;
-
- codec->work_base = pba;
-
- return 0;
-}
-
-static void ymfpci_memfree(ymfpci_t *codec)
-{
- ymfpci_writel(codec, YDSXGR_PLAYCTRLBASE, 0);
- ymfpci_writel(codec, YDSXGR_RECCTRLBASE, 0);
- ymfpci_writel(codec, YDSXGR_EFFCTRLBASE, 0);
- ymfpci_writel(codec, YDSXGR_WORKBASE, 0);
- ymfpci_writel(codec, YDSXGR_WORKSIZE, 0);
- pci_free_consistent(codec->pci,
- codec->dma_area_size, codec->dma_area_va, codec->dma_area_ba);
-}
-
-static void ymf_memload(ymfpci_t *unit)
-{
-
- ymfpci_writel(unit, YDSXGR_PLAYCTRLBASE, unit->ctrl_playback_ba);
- ymfpci_writel(unit, YDSXGR_RECCTRLBASE, unit->bank_base_capture);
- ymfpci_writel(unit, YDSXGR_EFFCTRLBASE, unit->bank_base_effect);
- ymfpci_writel(unit, YDSXGR_WORKBASE, unit->work_base);
- ymfpci_writel(unit, YDSXGR_WORKSIZE, unit->work_size >> 2);
-
- /* S/PDIF output initialization */
- ymfpci_writew(unit, YDSXGR_SPDIFOUTCTRL, 0);
- ymfpci_writew(unit, YDSXGR_SPDIFOUTSTATUS,
- SND_PCM_AES0_CON_EMPHASIS_NONE |
- (SND_PCM_AES1_CON_ORIGINAL << 8) |
- (SND_PCM_AES1_CON_PCM_CODER << 8));
-
- /* S/PDIF input initialization */
- ymfpci_writew(unit, YDSXGR_SPDIFINCTRL, 0);
-
- /* move this volume setup to mixer */
- ymfpci_writel(unit, YDSXGR_NATIVEDACOUTVOL, 0x3fff3fff);
- ymfpci_writel(unit, YDSXGR_BUF441OUTVOL, 0);
- ymfpci_writel(unit, YDSXGR_NATIVEADCINVOL, 0x3fff3fff);
- ymfpci_writel(unit, YDSXGR_NATIVEDACINVOL, 0x3fff3fff);
-}
-
-static int ymf_ac97_init(ymfpci_t *unit, int num_ac97)
-{
- struct ac97_codec *codec;
- u16 eid;
-
- if ((codec = ac97_alloc_codec()) == NULL)
- return -ENOMEM;
-
- /* initialize some basic codec information, other fields will be filled
- in ac97_probe_codec */
- codec->private_data = unit;
- codec->id = num_ac97;
-
- codec->codec_read = ymfpci_codec_read;
- codec->codec_write = ymfpci_codec_write;
-
- if (ac97_probe_codec(codec) == 0) {
- printk(KERN_ERR "ymfpci: ac97_probe_codec failed\n");
- goto out_kfree;
- }
-
- eid = ymfpci_codec_read(codec, AC97_EXTENDED_ID);
- if (eid==0xFFFF) {
- printk(KERN_WARNING "ymfpci: no codec attached ?\n");
- goto out_kfree;
- }
-
- unit->ac97_features = eid;
-
- if ((codec->dev_mixer = register_sound_mixer(&ymf_mixer_fops, -1)) < 0) {
- printk(KERN_ERR "ymfpci: couldn't register mixer!\n");
- goto out_kfree;
- }
-
- unit->ac97_codec[num_ac97] = codec;
-
- return 0;
- out_kfree:
- ac97_release_codec(codec);
- return -ENODEV;
-}
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
-# ifdef MODULE
-static int mpu_io;
-static int synth_io;
-module_param(mpu_io, int, 0);
-module_param(synth_io, int, 0);
-# else
-static int mpu_io = 0x330;
-static int synth_io = 0x388;
-# endif
-static int assigned;
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
-static int __devinit ymf_probe_one(struct pci_dev *pcidev, const struct pci_device_id *ent)
-{
- u16 ctrl;
- unsigned long base;
- ymfpci_t *codec;
-
- int err;
-
- if ((err = pci_enable_device(pcidev)) != 0) {
- printk(KERN_ERR "ymfpci: pci_enable_device failed\n");
- return err;
- }
- base = pci_resource_start(pcidev, 0);
-
- if ((codec = kmalloc(sizeof(ymfpci_t), GFP_KERNEL)) == NULL) {
- printk(KERN_ERR "ymfpci: no core\n");
- return -ENOMEM;
- }
- memset(codec, 0, sizeof(*codec));
-
- spin_lock_init(&codec->reg_lock);
- spin_lock_init(&codec->voice_lock);
- spin_lock_init(&codec->ac97_lock);
- mutex_init(&codec->open_mutex);
- INIT_LIST_HEAD(&codec->states);
- codec->pci = pcidev;
-
- pci_read_config_byte(pcidev, PCI_REVISION_ID, &codec->rev);
-
- if (request_mem_region(base, 0x8000, "ymfpci") == NULL) {
- printk(KERN_ERR "ymfpci: unable to request mem region\n");
- goto out_free;
- }
-
- if ((codec->reg_area_virt = ioremap(base, 0x8000)) == NULL) {
- printk(KERN_ERR "ymfpci: unable to map registers\n");
- goto out_release_region;
- }
-
- pci_set_master(pcidev);
-
- printk(KERN_INFO "ymfpci: %s at 0x%lx IRQ %d\n",
- (char *)ent->driver_data, base, pcidev->irq);
-
- ymfpci_aclink_reset(pcidev);
- if (ymfpci_codec_ready(codec, 0, 1) < 0)
- goto out_unmap;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- if (assigned == 0) {
- codec->iomidi = mpu_io;
- codec->iosynth = synth_io;
- if (ymfpci_setup_legacy(codec, pcidev) < 0)
- goto out_unmap;
- assigned = 1;
- }
-#endif
-
- ymfpci_download_image(codec);
-
- if (ymfpci_memalloc(codec) < 0)
- goto out_disable_dsp;
- ymf_memload(codec);
-
- if (request_irq(pcidev->irq, ymf_interrupt, IRQF_SHARED, "ymfpci", codec) != 0) {
- printk(KERN_ERR "ymfpci: unable to request IRQ %d\n",
- pcidev->irq);
- goto out_memfree;
- }
-
- /* register /dev/dsp */
- if ((codec->dev_audio = register_sound_dsp(&ymf_fops, -1)) < 0) {
- printk(KERN_ERR "ymfpci: unable to register dsp\n");
- goto out_free_irq;
- }
-
- /*
- * Poke just the primary for the moment.
- */
- if ((err = ymf_ac97_init(codec, 0)) != 0)
- goto out_unregister_sound_dsp;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- codec->opl3_data.name = "ymfpci";
- codec->mpu_data.name = "ymfpci";
-
- codec->opl3_data.io_base = codec->iosynth;
- codec->opl3_data.irq = -1;
-
- codec->mpu_data.io_base = codec->iomidi;
- codec->mpu_data.irq = -1; /* May be different from our PCI IRQ. */
-
- if (codec->iomidi) {
- if (!probe_uart401(&codec->mpu_data, THIS_MODULE)) {
- codec->iomidi = 0; /* XXX kludge */
- }
- }
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-
- /* put it into driver list */
- spin_lock(&ymf_devs_lock);
- list_add_tail(&codec->ymf_devs, &ymf_devs);
- spin_unlock(&ymf_devs_lock);
- pci_set_drvdata(pcidev, codec);
-
- return 0;
-
- out_unregister_sound_dsp:
- unregister_sound_dsp(codec->dev_audio);
- out_free_irq:
- free_irq(pcidev->irq, codec);
- out_memfree:
- ymfpci_memfree(codec);
- out_disable_dsp:
- ymfpci_disable_dsp(codec);
- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
- ymfpci_writel(codec, YDSXGR_STATUS, ~0);
- out_unmap:
- iounmap(codec->reg_area_virt);
- out_release_region:
- release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
- out_free:
- if (codec->ac97_codec[0])
- ac97_release_codec(codec->ac97_codec[0]);
- return -ENODEV;
-}
-
-static void __devexit ymf_remove_one(struct pci_dev *pcidev)
-{
- __u16 ctrl;
- ymfpci_t *codec = pci_get_drvdata(pcidev);
-
- /* remove from list of devices */
- spin_lock(&ymf_devs_lock);
- list_del(&codec->ymf_devs);
- spin_unlock(&ymf_devs_lock);
-
- unregister_sound_mixer(codec->ac97_codec[0]->dev_mixer);
- ac97_release_codec(codec->ac97_codec[0]);
- unregister_sound_dsp(codec->dev_audio);
- free_irq(pcidev->irq, codec);
- ymfpci_memfree(codec);
- ymfpci_writel(codec, YDSXGR_STATUS, ~0);
- ymfpci_disable_dsp(codec);
- ctrl = ymfpci_readw(codec, YDSXGR_GLOBALCTRL);
- ymfpci_writew(codec, YDSXGR_GLOBALCTRL, ctrl & ~0x0007);
- iounmap(codec->reg_area_virt);
- release_mem_region(pci_resource_start(pcidev, 0), 0x8000);
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- if (codec->iomidi) {
- unload_uart401(&codec->mpu_data);
- }
-#endif /* CONFIG_SOUND_YMFPCI_LEGACY */
-}
-
-MODULE_AUTHOR("Jaroslav Kysela");
-MODULE_DESCRIPTION("Yamaha YMF7xx PCI Audio");
-MODULE_LICENSE("GPL");
-
-static struct pci_driver ymfpci_driver = {
- .name = "ymfpci",
- .id_table = ymf_id_tbl,
- .probe = ymf_probe_one,
- .remove = __devexit_p(ymf_remove_one),
- .suspend = ymf_suspend,
- .resume = ymf_resume
-};
-
-static int __init ymf_init_module(void)
-{
- return pci_register_driver(&ymfpci_driver);
-}
-
-static void __exit ymf_cleanup_module (void)
-{
- pci_unregister_driver(&ymfpci_driver);
-}
-
-module_init(ymf_init_module);
-module_exit(ymf_cleanup_module);
diff --git a/sound/oss/ymfpci.h b/sound/oss/ymfpci.h
deleted file mode 100644
index ac1785f2b7e7..000000000000
--- a/sound/oss/ymfpci.h
+++ /dev/null
@@ -1,361 +0,0 @@
-#ifndef __YMFPCI_H
-#define __YMFPCI_H
-
-/*
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
- * Definitions for Yahama YMF724/740/744/754 chips
- *
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- */
-#include <linux/config.h>
-#include <linux/mutex.h>
-
-/*
- * Direct registers
- */
-
-/* #define YMFREG(codec, reg) (codec->port + YDSXGR_##reg) */
-
-#define YDSXGR_INTFLAG 0x0004
-#define YDSXGR_ACTIVITY 0x0006
-#define YDSXGR_GLOBALCTRL 0x0008
-#define YDSXGR_ZVCTRL 0x000A
-#define YDSXGR_TIMERCTRL 0x0010
-#define YDSXGR_TIMERCTRL_TEN 0x0001
-#define YDSXGR_TIMERCTRL_TIEN 0x0002
-#define YDSXGR_TIMERCOUNT 0x0012
-#define YDSXGR_SPDIFOUTCTRL 0x0018
-#define YDSXGR_SPDIFOUTSTATUS 0x001C
-#define YDSXGR_EEPROMCTRL 0x0020
-#define YDSXGR_SPDIFINCTRL 0x0034
-#define YDSXGR_SPDIFINSTATUS 0x0038
-#define YDSXGR_DSPPROGRAMDL 0x0048
-#define YDSXGR_DLCNTRL 0x004C
-#define YDSXGR_GPIOININTFLAG 0x0050
-#define YDSXGR_GPIOININTENABLE 0x0052
-#define YDSXGR_GPIOINSTATUS 0x0054
-#define YDSXGR_GPIOOUTCTRL 0x0056
-#define YDSXGR_GPIOFUNCENABLE 0x0058
-#define YDSXGR_GPIOTYPECONFIG 0x005A
-#define YDSXGR_AC97CMDDATA 0x0060
-#define YDSXGR_AC97CMDADR 0x0062
-#define YDSXGR_PRISTATUSDATA 0x0064
-#define YDSXGR_PRISTATUSADR 0x0066
-#define YDSXGR_SECSTATUSDATA 0x0068
-#define YDSXGR_SECSTATUSADR 0x006A
-#define YDSXGR_SECCONFIG 0x0070
-#define YDSXGR_LEGACYOUTVOL 0x0080
-#define YDSXGR_LEGACYOUTVOLL 0x0080
-#define YDSXGR_LEGACYOUTVOLR 0x0082
-#define YDSXGR_NATIVEDACOUTVOL 0x0084
-#define YDSXGR_NATIVEDACOUTVOLL 0x0084
-#define YDSXGR_NATIVEDACOUTVOLR 0x0086
-#define YDSXGR_SPDIFOUTVOL 0x0088
-#define YDSXGR_SPDIFOUTVOLL 0x0088
-#define YDSXGR_SPDIFOUTVOLR 0x008A
-#define YDSXGR_AC3OUTVOL 0x008C
-#define YDSXGR_AC3OUTVOLL 0x008C
-#define YDSXGR_AC3OUTVOLR 0x008E
-#define YDSXGR_PRIADCOUTVOL 0x0090
-#define YDSXGR_PRIADCOUTVOLL 0x0090
-#define YDSXGR_PRIADCOUTVOLR 0x0092
-#define YDSXGR_LEGACYLOOPVOL 0x0094
-#define YDSXGR_LEGACYLOOPVOLL 0x0094
-#define YDSXGR_LEGACYLOOPVOLR 0x0096
-#define YDSXGR_NATIVEDACLOOPVOL 0x0098
-#define YDSXGR_NATIVEDACLOOPVOLL 0x0098
-#define YDSXGR_NATIVEDACLOOPVOLR 0x009A
-#define YDSXGR_SPDIFLOOPVOL 0x009C
-#define YDSXGR_SPDIFLOOPVOLL 0x009E
-#define YDSXGR_SPDIFLOOPVOLR 0x009E
-#define YDSXGR_AC3LOOPVOL 0x00A0
-#define YDSXGR_AC3LOOPVOLL 0x00A0
-#define YDSXGR_AC3LOOPVOLR 0x00A2
-#define YDSXGR_PRIADCLOOPVOL 0x00A4
-#define YDSXGR_PRIADCLOOPVOLL 0x00A4
-#define YDSXGR_PRIADCLOOPVOLR 0x00A6
-#define YDSXGR_NATIVEADCINVOL 0x00A8
-#define YDSXGR_NATIVEADCINVOLL 0x00A8
-#define YDSXGR_NATIVEADCINVOLR 0x00AA
-#define YDSXGR_NATIVEDACINVOL 0x00AC
-#define YDSXGR_NATIVEDACINVOLL 0x00AC
-#define YDSXGR_NATIVEDACINVOLR 0x00AE
-#define YDSXGR_BUF441OUTVOL 0x00B0
-#define YDSXGR_BUF441OUTVOLL 0x00B0
-#define YDSXGR_BUF441OUTVOLR 0x00B2
-#define YDSXGR_BUF441LOOPVOL 0x00B4
-#define YDSXGR_BUF441LOOPVOLL 0x00B4
-#define YDSXGR_BUF441LOOPVOLR 0x00B6
-#define YDSXGR_SPDIFOUTVOL2 0x00B8
-#define YDSXGR_SPDIFOUTVOL2L 0x00B8
-#define YDSXGR_SPDIFOUTVOL2R 0x00BA
-#define YDSXGR_SPDIFLOOPVOL2 0x00BC
-#define YDSXGR_SPDIFLOOPVOL2L 0x00BC
-#define YDSXGR_SPDIFLOOPVOL2R 0x00BE
-#define YDSXGR_ADCSLOTSR 0x00C0
-#define YDSXGR_RECSLOTSR 0x00C4
-#define YDSXGR_ADCFORMAT 0x00C8
-#define YDSXGR_RECFORMAT 0x00CC
-#define YDSXGR_P44SLOTSR 0x00D0
-#define YDSXGR_STATUS 0x0100
-#define YDSXGR_CTRLSELECT 0x0104
-#define YDSXGR_MODE 0x0108
-#define YDSXGR_SAMPLECOUNT 0x010C
-#define YDSXGR_NUMOFSAMPLES 0x0110
-#define YDSXGR_CONFIG 0x0114
-#define YDSXGR_PLAYCTRLSIZE 0x0140
-#define YDSXGR_RECCTRLSIZE 0x0144
-#define YDSXGR_EFFCTRLSIZE 0x0148
-#define YDSXGR_WORKSIZE 0x014C
-#define YDSXGR_MAPOFREC 0x0150
-#define YDSXGR_MAPOFEFFECT 0x0154
-#define YDSXGR_PLAYCTRLBASE 0x0158
-#define YDSXGR_RECCTRLBASE 0x015C
-#define YDSXGR_EFFCTRLBASE 0x0160
-#define YDSXGR_WORKBASE 0x0164
-#define YDSXGR_DSPINSTRAM 0x1000
-#define YDSXGR_CTRLINSTRAM 0x4000
-
-#define YDSXG_AC97READCMD 0x8000
-#define YDSXG_AC97WRITECMD 0x0000
-
-#define PCIR_LEGCTRL 0x40
-#define PCIR_ELEGCTRL 0x42
-#define PCIR_DSXGCTRL 0x48
-#define PCIR_DSXPWRCTRL1 0x4a
-#define PCIR_DSXPWRCTRL2 0x4e
-#define PCIR_OPLADR 0x60
-#define PCIR_SBADR 0x62
-#define PCIR_MPUADR 0x64
-
-#define YDSXG_DSPLENGTH 0x0080
-#define YDSXG_CTRLLENGTH 0x3000
-
-#define YDSXG_DEFAULT_WORK_SIZE 0x0400
-
-#define YDSXG_PLAYBACK_VOICES 64
-#define YDSXG_CAPTURE_VOICES 2
-#define YDSXG_EFFECT_VOICES 5
-
-/* maxinum number of AC97 codecs connected, AC97 2.0 defined 4 */
-#define NR_AC97 2
-
-#define YMF_SAMPF 256 /* Samples per frame @48000 */
-
-/*
- * The slot/voice control bank (2 of these per voice)
- */
-
-typedef struct stru_ymfpci_playback_bank {
- u32 format;
- u32 loop_default;
- u32 base; /* 32-bit address */
- u32 loop_start; /* 32-bit offset */
- u32 loop_end; /* 32-bit offset */
- u32 loop_frac; /* 8-bit fraction - loop_start */
- u32 delta_end; /* pitch delta end */
- u32 lpfK_end;
- u32 eg_gain_end;
- u32 left_gain_end;
- u32 right_gain_end;
- u32 eff1_gain_end;
- u32 eff2_gain_end;
- u32 eff3_gain_end;
- u32 lpfQ;
- u32 status; /* P3: Always 0 for some reason. */
- u32 num_of_frames;
- u32 loop_count;
- u32 start; /* P3: J. reads this to know where chip is. */
- u32 start_frac;
- u32 delta;
- u32 lpfK;
- u32 eg_gain;
- u32 left_gain;
- u32 right_gain;
- u32 eff1_gain;
- u32 eff2_gain;
- u32 eff3_gain;
- u32 lpfD1;
- u32 lpfD2;
-} ymfpci_playback_bank_t;
-
-typedef struct stru_ymfpci_capture_bank {
- u32 base; /* 32-bit address (aligned at 4) */
- u32 loop_end; /* size in BYTES (aligned at 4) */
- u32 start; /* 32-bit offset */
- u32 num_of_loops; /* counter */
-} ymfpci_capture_bank_t;
-
-typedef struct stru_ymfpci_effect_bank {
- u32 base; /* 32-bit address */
- u32 loop_end; /* 32-bit offset */
- u32 start; /* 32-bit offset */
- u32 temp;
-} ymfpci_effect_bank_t;
-
-typedef struct ymf_voice ymfpci_voice_t;
-/*
- * Throughout the code Yaroslav names YMF unit pointer "codec"
- * even though it does not correspond to any codec. Must be historic.
- * We replace it with "unit" over time.
- * AC97 parts use "codec" to denote a codec, naturally.
- */
-typedef struct ymf_unit ymfpci_t;
-
-typedef enum {
- YMFPCI_PCM,
- YMFPCI_SYNTH,
- YMFPCI_MIDI
-} ymfpci_voice_type_t;
-
-struct ymf_voice {
- // ymfpci_t *codec;
- int number;
- char use, pcm, synth, midi; // bool
- ymfpci_playback_bank_t *bank;
- struct ymf_pcm *ypcm;
- dma_addr_t bank_ba;
-};
-
-struct ymf_capture {
- // struct ymf_unit *unit;
- int use;
- ymfpci_capture_bank_t *bank;
- struct ymf_pcm *ypcm;
-};
-
-struct ymf_unit {
- u8 rev; /* PCI revision */
- void __iomem *reg_area_virt;
- void *dma_area_va;
- dma_addr_t dma_area_ba;
- unsigned int dma_area_size;
-
- dma_addr_t bank_base_capture;
- dma_addr_t bank_base_effect;
- dma_addr_t work_base;
- unsigned int work_size;
-
- u32 *ctrl_playback;
- dma_addr_t ctrl_playback_ba;
- ymfpci_playback_bank_t *bank_playback[YDSXG_PLAYBACK_VOICES][2];
- ymfpci_capture_bank_t *bank_capture[YDSXG_CAPTURE_VOICES][2];
- ymfpci_effect_bank_t *bank_effect[YDSXG_EFFECT_VOICES][2];
-
- int start_count;
- int suspended;
-
- u32 active_bank;
- struct ymf_voice voices[YDSXG_PLAYBACK_VOICES];
- struct ymf_capture capture[YDSXG_CAPTURE_VOICES];
-
- struct ac97_codec *ac97_codec[NR_AC97];
- u16 ac97_features;
-
- struct pci_dev *pci;
-
-#ifdef CONFIG_SOUND_YMFPCI_LEGACY
- /* legacy hardware resources */
- unsigned int iosynth, iomidi;
- struct address_info opl3_data, mpu_data;
-#endif
-
- spinlock_t reg_lock;
- spinlock_t voice_lock;
- spinlock_t ac97_lock;
-
- /* soundcore stuff */
- int dev_audio;
- struct mutex open_mutex;
-
- struct list_head ymf_devs;
- struct list_head states; /* List of states for this unit */
-};
-
-struct ymf_dmabuf {
- dma_addr_t dma_addr;
- void *rawbuf;
- unsigned buforder;
-
- /* OSS buffer management stuff */
- unsigned numfrag;
- unsigned fragshift;
-
- /* our buffer acts like a circular ring */
- unsigned hwptr; /* where dma last started */
- unsigned swptr; /* where driver last clear/filled */
- int count; /* fill count */
- unsigned total_bytes; /* total bytes dmaed by hardware */
-
- wait_queue_head_t wait; /* put process on wait queue when no more space in buffer */
-
- /* redundant, but makes calculations easier */
- unsigned fragsize;
- unsigned dmasize; /* Total rawbuf[] size */
-
- /* OSS stuff */
- unsigned mapped:1;
- unsigned ready:1;
- unsigned ossfragshift;
- int ossmaxfrags;
- unsigned subdivision;
-};
-
-struct ymf_pcm_format {
- int format; /* OSS format */
- int rate; /* rate in Hz */
- int voices; /* number of voices */
- int shift; /* redundant, computed from the above */
-};
-
-typedef enum {
- PLAYBACK_VOICE,
- CAPTURE_REC,
- CAPTURE_AC97,
- EFFECT_DRY_LEFT,
- EFFECT_DRY_RIGHT,
- EFFECT_EFF1,
- EFFECT_EFF2,
- EFFECT_EFF3
-} ymfpci_pcm_type_t;
-
-/* This is variant record, but we hate unions. Little waste on pointers []. */
-struct ymf_pcm {
- ymfpci_pcm_type_t type;
- struct ymf_state *state;
-
- ymfpci_voice_t *voices[2];
- int capture_bank_number;
-
- struct ymf_dmabuf dmabuf;
- int running;
- int spdif;
-};
-
-/*
- * "Software" or virtual channel, an instance of opened /dev/dsp.
- * It may have two physical channels (pcms) for duplex operations.
- */
-
-struct ymf_state {
- struct list_head chain;
- struct ymf_unit *unit; /* backpointer */
- struct ymf_pcm rpcm, wpcm;
- struct ymf_pcm_format format;
-};
-
-#endif /* __YMFPCI_H */
diff --git a/sound/oss/ymfpci_image.h b/sound/oss/ymfpci_image.h
deleted file mode 100644
index 112f2fff6c8e..000000000000
--- a/sound/oss/ymfpci_image.h
+++ /dev/null
@@ -1,1565 +0,0 @@
-#ifndef _HWMCODE_
-#define _HWMCODE_
-
-static u32 DspInst[YDSXG_DSPLENGTH / 4] = {
- 0x00000081, 0x000001a4, 0x0000000a, 0x0000002f,
- 0x00080253, 0x01800317, 0x0000407b, 0x0000843f,
- 0x0001483c, 0x0001943c, 0x0005d83c, 0x00001c3c,
- 0x0000c07b, 0x00050c3f, 0x0121503c, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-
-static u32 CntrlInst[YDSXG_CTRLLENGTH / 4] = {
- 0x000007, 0x240007, 0x0C0007, 0x1C0007,
- 0x060007, 0x700002, 0x000020, 0x030040,
- 0x007104, 0x004286, 0x030040, 0x000F0D,
- 0x000810, 0x20043A, 0x000282, 0x00020D,
- 0x000810, 0x20043A, 0x001282, 0x200E82,
- 0x001A82, 0x032D0D, 0x000810, 0x10043A,
- 0x02D38D, 0x000810, 0x18043A, 0x00010D,
- 0x020015, 0x0000FD, 0x000020, 0x038860,
- 0x039060, 0x038060, 0x038040, 0x038040,
- 0x038040, 0x018040, 0x000A7D, 0x038040,
- 0x038040, 0x018040, 0x200402, 0x000882,
- 0x08001A, 0x000904, 0x015986, 0x000007,
- 0x260007, 0x000007, 0x000007, 0x018A06,
- 0x000007, 0x030C8D, 0x000810, 0x18043A,
- 0x260007, 0x00087D, 0x018042, 0x00160A,
- 0x04A206, 0x000007, 0x00218D, 0x000810,
- 0x08043A, 0x21C206, 0x000007, 0x0007FD,
- 0x018042, 0x08000A, 0x000904, 0x029386,
- 0x000195, 0x090D04, 0x000007, 0x000820,
- 0x0000F5, 0x000B7D, 0x01F060, 0x0000FD,
- 0x032206, 0x018040, 0x000A7D, 0x038042,
- 0x13804A, 0x18000A, 0x001820, 0x059060,
- 0x058860, 0x018040, 0x0000FD, 0x018042,
- 0x70000A, 0x000115, 0x071144, 0x032386,
- 0x030000, 0x007020, 0x034A06, 0x018040,
- 0x00348D, 0x000810, 0x08043A, 0x21EA06,
- 0x000007, 0x02D38D, 0x000810, 0x18043A,
- 0x018206, 0x000007, 0x240007, 0x000F8D,
- 0x000810, 0x00163A, 0x002402, 0x005C02,
- 0x0028FD, 0x000020, 0x018040, 0x08000D,
- 0x000815, 0x510984, 0x000007, 0x00004D,
- 0x000E5D, 0x000E02, 0x00418D, 0x000810,
- 0x08043A, 0x2C8A06, 0x000007, 0x00008D,
- 0x000924, 0x000F02, 0x00458D, 0x000810,
- 0x08043A, 0x2C8A06, 0x000007, 0x00387D,
- 0x018042, 0x08000A, 0x001015, 0x010984,
- 0x018386, 0x000007, 0x01AA06, 0x000007,
- 0x0008FD, 0x018042, 0x18000A, 0x001904,
- 0x218086, 0x280007, 0x001810, 0x28043A,
- 0x280C02, 0x00000D, 0x000810, 0x28143A,
- 0x08808D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00020D, 0x189904, 0x000007,
- 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x055A86, 0x000007,
- 0x000100, 0x000A20, 0x00047D, 0x018040,
- 0x018042, 0x20000A, 0x003015, 0x012144,
- 0x034986, 0x000007, 0x002104, 0x034986,
- 0x000007, 0x000F8D, 0x000810, 0x280C3A,
- 0x023944, 0x06C986, 0x000007, 0x001810,
- 0x28043A, 0x08810D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x002810, 0x78003A,
- 0x00688D, 0x000810, 0x08043A, 0x288A06,
- 0x000007, 0x00400D, 0x001015, 0x189904,
- 0x292904, 0x393904, 0x000007, 0x060206,
- 0x000007, 0x0004F5, 0x00007D, 0x000020,
- 0x00008D, 0x010860, 0x018040, 0x00047D,
- 0x038042, 0x21804A, 0x18000A, 0x021944,
- 0x215886, 0x000007, 0x004075, 0x71F104,
- 0x000007, 0x010042, 0x28000A, 0x002904,
- 0x212086, 0x000007, 0x003C0D, 0x30A904,
- 0x000007, 0x00077D, 0x018042, 0x08000A,
- 0x000904, 0x07DA86, 0x00057D, 0x002820,
- 0x03B060, 0x07F206, 0x018040, 0x003020,
- 0x03A860, 0x018040, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x07FA86, 0x000007,
- 0x00057D, 0x018042, 0x28040A, 0x000E8D,
- 0x000810, 0x280C3A, 0x00000D, 0x000810,
- 0x28143A, 0x09000D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x003DFD, 0x000020,
- 0x018040, 0x00107D, 0x008D8D, 0x000810,
- 0x08043A, 0x288A06, 0x000007, 0x000815,
- 0x08001A, 0x010984, 0x095186, 0x00137D,
- 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
- 0x038A60, 0x018040, 0x007FBD, 0x383DC4,
- 0x000007, 0x001A7D, 0x001375, 0x018042,
- 0x09004A, 0x10000A, 0x0B8D04, 0x139504,
- 0x000007, 0x000820, 0x019060, 0x001104,
- 0x212086, 0x010040, 0x0017FD, 0x018042,
- 0x08000A, 0x000904, 0x212286, 0x000007,
- 0x00197D, 0x038042, 0x09804A, 0x10000A,
- 0x000924, 0x001664, 0x0011FD, 0x038042,
- 0x2B804A, 0x19804A, 0x00008D, 0x218944,
- 0x000007, 0x002244, 0x0AE186, 0x000007,
- 0x001A64, 0x002A24, 0x00197D, 0x080102,
- 0x100122, 0x000820, 0x039060, 0x018040,
- 0x003DFD, 0x00008D, 0x000820, 0x018040,
- 0x001375, 0x001A7D, 0x010042, 0x09804A,
- 0x10000A, 0x00021D, 0x0189E4, 0x2992E4,
- 0x309144, 0x000007, 0x00060D, 0x000A15,
- 0x000C1D, 0x001025, 0x00A9E4, 0x012BE4,
- 0x000464, 0x01B3E4, 0x0232E4, 0x000464,
- 0x000464, 0x000464, 0x000464, 0x00040D,
- 0x08B1C4, 0x000007, 0x000820, 0x000BF5,
- 0x030040, 0x00197D, 0x038042, 0x09804A,
- 0x000A24, 0x08000A, 0x080E64, 0x000007,
- 0x100122, 0x000820, 0x031060, 0x010040,
- 0x0064AC, 0x00027D, 0x000020, 0x018040,
- 0x00107D, 0x018042, 0x0011FD, 0x3B804A,
- 0x09804A, 0x20000A, 0x000095, 0x1A1144,
- 0x00A144, 0x0D2086, 0x00040D, 0x00B984,
- 0x0D2186, 0x0018FD, 0x018042, 0x0010FD,
- 0x09804A, 0x28000A, 0x000095, 0x010924,
- 0x002A64, 0x0D1186, 0x000007, 0x002904,
- 0x0D2286, 0x000007, 0x0D2A06, 0x080002,
- 0x00008D, 0x00387D, 0x000820, 0x018040,
- 0x00127D, 0x018042, 0x10000A, 0x003904,
- 0x0DD186, 0x00080D, 0x7FFFB5, 0x00B984,
- 0x0DA186, 0x000025, 0x0E7A06, 0x00002D,
- 0x000015, 0x00082D, 0x02C78D, 0x000820,
- 0x0EC206, 0x00000D, 0x7F8035, 0x00B984,
- 0x0E7186, 0x400025, 0x00008D, 0x110944,
- 0x000007, 0x00018D, 0x109504, 0x000007,
- 0x009164, 0x000424, 0x000424, 0x000424,
- 0x100102, 0x280002, 0x02C68D, 0x000820,
- 0x0EC206, 0x00018D, 0x00042D, 0x00008D,
- 0x109504, 0x000007, 0x00020D, 0x109184,
- 0x000007, 0x02C70D, 0x000820, 0x00008D,
- 0x0038FD, 0x018040, 0x003BFD, 0x001020,
- 0x03A860, 0x000815, 0x313184, 0x212184,
- 0x000007, 0x03B060, 0x03A060, 0x018040,
- 0x0022FD, 0x000095, 0x010924, 0x000424,
- 0x000424, 0x001264, 0x100102, 0x000820,
- 0x039060, 0x018040, 0x001924, 0x00FB8D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x000424,
- 0x000424, 0x00117D, 0x018042, 0x08000A,
- 0x000A24, 0x280502, 0x280C02, 0x09800D,
- 0x000820, 0x0002FD, 0x018040, 0x200007,
- 0x0022FD, 0x018042, 0x08000A, 0x000095,
- 0x280DC4, 0x011924, 0x00197D, 0x018042,
- 0x0011FD, 0x09804A, 0x10000A, 0x0000B5,
- 0x113144, 0x0A8D04, 0x000007, 0x080A44,
- 0x129504, 0x000007, 0x0023FD, 0x001020,
- 0x038040, 0x101244, 0x000007, 0x000820,
- 0x039060, 0x018040, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x10FA86, 0x000007,
- 0x003BFD, 0x000100, 0x000A10, 0x0B807A,
- 0x13804A, 0x090984, 0x000007, 0x000095,
- 0x013D04, 0x118086, 0x10000A, 0x100002,
- 0x090984, 0x000007, 0x038042, 0x11804A,
- 0x090D04, 0x000007, 0x10000A, 0x090D84,
- 0x000007, 0x00257D, 0x000820, 0x018040,
- 0x00010D, 0x000810, 0x28143A, 0x00127D,
- 0x018042, 0x20000A, 0x00197D, 0x018042,
- 0x00117D, 0x31804A, 0x10000A, 0x003124,
- 0x01280D, 0x00397D, 0x000820, 0x058040,
- 0x038042, 0x09844A, 0x000606, 0x08040A,
- 0x300102, 0x003124, 0x000424, 0x000424,
- 0x001224, 0x280502, 0x001A4C, 0x130186,
- 0x700002, 0x00002D, 0x030000, 0x00387D,
- 0x018042, 0x10000A, 0x132A06, 0x002124,
- 0x0000AD, 0x100002, 0x00010D, 0x000924,
- 0x006B24, 0x01368D, 0x00397D, 0x000820,
- 0x058040, 0x038042, 0x09844A, 0x000606,
- 0x08040A, 0x003264, 0x00008D, 0x000A24,
- 0x001020, 0x00227D, 0x018040, 0x013C0D,
- 0x000810, 0x08043A, 0x29D206, 0x000007,
- 0x002820, 0x00207D, 0x018040, 0x00117D,
- 0x038042, 0x13804A, 0x33800A, 0x00387D,
- 0x018042, 0x08000A, 0x000904, 0x163A86,
- 0x000007, 0x00008D, 0x030964, 0x01478D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x380102,
- 0x000424, 0x000424, 0x001224, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x14A286,
- 0x000007, 0x280502, 0x001A4C, 0x163986,
- 0x000007, 0x032164, 0x00632C, 0x003DFD,
- 0x018042, 0x08000A, 0x000095, 0x090904,
- 0x000007, 0x000820, 0x001A4C, 0x156186,
- 0x018040, 0x030000, 0x157A06, 0x002124,
- 0x00010D, 0x000924, 0x006B24, 0x015B8D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x003A64,
- 0x000095, 0x001224, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x15DA86, 0x000007,
- 0x01628D, 0x000810, 0x08043A, 0x29D206,
- 0x000007, 0x14D206, 0x000007, 0x007020,
- 0x08010A, 0x10012A, 0x0020FD, 0x038860,
- 0x039060, 0x018040, 0x00227D, 0x018042,
- 0x003DFD, 0x08000A, 0x31844A, 0x000904,
- 0x16D886, 0x18008B, 0x00008D, 0x189904,
- 0x00312C, 0x17AA06, 0x000007, 0x00324C,
- 0x173386, 0x000007, 0x001904, 0x173086,
- 0x000007, 0x000095, 0x199144, 0x00222C,
- 0x003124, 0x00636C, 0x000E3D, 0x001375,
- 0x000BFD, 0x010042, 0x09804A, 0x10000A,
- 0x038AEC, 0x0393EC, 0x00224C, 0x17A986,
- 0x000007, 0x00008D, 0x189904, 0x00226C,
- 0x00322C, 0x30050A, 0x301DAB, 0x002083,
- 0x0018FD, 0x018042, 0x08000A, 0x018924,
- 0x300502, 0x001083, 0x001875, 0x010042,
- 0x10000A, 0x00008D, 0x010924, 0x001375,
- 0x330542, 0x330CCB, 0x332CCB, 0x3334CB,
- 0x333CCB, 0x3344CB, 0x334CCB, 0x3354CB,
- 0x305C8B, 0x006083, 0x0002F5, 0x010042,
- 0x08000A, 0x000904, 0x187A86, 0x000007,
- 0x001E2D, 0x0005FD, 0x018042, 0x08000A,
- 0x028924, 0x280502, 0x00060D, 0x000810,
- 0x280C3A, 0x00008D, 0x000810, 0x28143A,
- 0x0A808D, 0x000820, 0x0002F5, 0x010040,
- 0x220007, 0x001275, 0x030042, 0x21004A,
- 0x00008D, 0x1A0944, 0x000007, 0x01980D,
- 0x000810, 0x08043A, 0x2B2206, 0x000007,
- 0x0001F5, 0x030042, 0x0D004A, 0x10000A,
- 0x089144, 0x000007, 0x000820, 0x010040,
- 0x0025F5, 0x0A3144, 0x000007, 0x000820,
- 0x032860, 0x030040, 0x00217D, 0x038042,
- 0x0B804A, 0x10000A, 0x000820, 0x031060,
- 0x030040, 0x00008D, 0x000124, 0x00012C,
- 0x000E64, 0x001A64, 0x00636C, 0x08010A,
- 0x10012A, 0x000820, 0x031060, 0x030040,
- 0x0020FD, 0x018042, 0x08000A, 0x00227D,
- 0x018042, 0x10000A, 0x000820, 0x031060,
- 0x030040, 0x00197D, 0x018042, 0x08000A,
- 0x0022FD, 0x038042, 0x10000A, 0x000820,
- 0x031060, 0x030040, 0x090D04, 0x000007,
- 0x000820, 0x030040, 0x038042, 0x0B804A,
- 0x10000A, 0x000820, 0x031060, 0x030040,
- 0x038042, 0x13804A, 0x19804A, 0x110D04,
- 0x198D04, 0x000007, 0x08000A, 0x001020,
- 0x031860, 0x030860, 0x030040, 0x00008D,
- 0x0B0944, 0x000007, 0x000820, 0x010040,
- 0x0005F5, 0x030042, 0x08000A, 0x000820,
- 0x010040, 0x0000F5, 0x010042, 0x08000A,
- 0x000904, 0x1C6086, 0x001E75, 0x030042,
- 0x01044A, 0x000C0A, 0x1C7206, 0x000007,
- 0x000402, 0x000C02, 0x00177D, 0x001AF5,
- 0x018042, 0x03144A, 0x031C4A, 0x03244A,
- 0x032C4A, 0x03344A, 0x033C4A, 0x03444A,
- 0x004C0A, 0x00043D, 0x0013F5, 0x001AFD,
- 0x030042, 0x0B004A, 0x1B804A, 0x13804A,
- 0x20000A, 0x089144, 0x19A144, 0x0389E4,
- 0x0399EC, 0x005502, 0x005D0A, 0x030042,
- 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
- 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
- 0x006502, 0x006D0A, 0x030042, 0x0B004A,
- 0x19004A, 0x2B804A, 0x13804A, 0x21804A,
- 0x30000A, 0x089144, 0x19A144, 0x2AB144,
- 0x0389E4, 0x0399EC, 0x007502, 0x007D0A,
- 0x03A9E4, 0x000702, 0x00107D, 0x000415,
- 0x018042, 0x08000A, 0x0109E4, 0x000F02,
- 0x002AF5, 0x0019FD, 0x010042, 0x09804A,
- 0x10000A, 0x000934, 0x001674, 0x0029F5,
- 0x010042, 0x10000A, 0x00917C, 0x002075,
- 0x010042, 0x08000A, 0x000904, 0x1ED286,
- 0x0026F5, 0x0027F5, 0x030042, 0x09004A,
- 0x10000A, 0x000A3C, 0x00167C, 0x001A75,
- 0x000BFD, 0x010042, 0x51804A, 0x48000A,
- 0x160007, 0x001075, 0x010042, 0x282C0A,
- 0x281D12, 0x282512, 0x001F32, 0x1E0007,
- 0x0E0007, 0x001975, 0x010042, 0x002DF5,
- 0x0D004A, 0x10000A, 0x009144, 0x1FB286,
- 0x010042, 0x28340A, 0x000E5D, 0x00008D,
- 0x000375, 0x000820, 0x010040, 0x05D2F4,
- 0x54D104, 0x00735C, 0x205386, 0x000007,
- 0x0C0007, 0x080007, 0x0A0007, 0x02040D,
- 0x000810, 0x08043A, 0x332206, 0x000007,
- 0x205A06, 0x000007, 0x080007, 0x002275,
- 0x010042, 0x20000A, 0x002104, 0x212086,
- 0x001E2D, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x209286, 0x000007, 0x002010,
- 0x30043A, 0x00057D, 0x0180C3, 0x08000A,
- 0x028924, 0x280502, 0x280C02, 0x0A810D,
- 0x000820, 0x0002F5, 0x010040, 0x220007,
- 0x0004FD, 0x018042, 0x70000A, 0x030000,
- 0x007020, 0x06FA06, 0x018040, 0x02180D,
- 0x000810, 0x08043A, 0x2B2206, 0x000007,
- 0x0002FD, 0x018042, 0x08000A, 0x000904,
- 0x218A86, 0x000007, 0x01F206, 0x000007,
- 0x000875, 0x0009FD, 0x00010D, 0x220A06,
- 0x000295, 0x000B75, 0x00097D, 0x00000D,
- 0x000515, 0x010042, 0x18000A, 0x001904,
- 0x287886, 0x0006F5, 0x001020, 0x010040,
- 0x0004F5, 0x000820, 0x010040, 0x000775,
- 0x010042, 0x09804A, 0x10000A, 0x001124,
- 0x000904, 0x22BA86, 0x000815, 0x080102,
- 0x101204, 0x22DA06, 0x000575, 0x081204,
- 0x000007, 0x100102, 0x000575, 0x000425,
- 0x021124, 0x100102, 0x000820, 0x031060,
- 0x010040, 0x001924, 0x287886, 0x00008D,
- 0x000464, 0x009D04, 0x278886, 0x180102,
- 0x000575, 0x010042, 0x28040A, 0x00018D,
- 0x000924, 0x280D02, 0x00000D, 0x000924,
- 0x281502, 0x10000D, 0x000820, 0x0002F5,
- 0x010040, 0x200007, 0x001175, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x23C286,
- 0x000007, 0x000100, 0x080B20, 0x130B60,
- 0x1B0B60, 0x030A60, 0x010040, 0x050042,
- 0x3D004A, 0x35004A, 0x2D004A, 0x20000A,
- 0x0006F5, 0x010042, 0x28140A, 0x0004F5,
- 0x010042, 0x08000A, 0x000315, 0x010D04,
- 0x24CA86, 0x004015, 0x000095, 0x010D04,
- 0x24B886, 0x100022, 0x10002A, 0x24E206,
- 0x000007, 0x333104, 0x2AA904, 0x000007,
- 0x032124, 0x280502, 0x001124, 0x000424,
- 0x000424, 0x003224, 0x00292C, 0x00636C,
- 0x25F386, 0x000007, 0x02B164, 0x000464,
- 0x000464, 0x00008D, 0x000A64, 0x280D02,
- 0x10008D, 0x000820, 0x0002F5, 0x010040,
- 0x220007, 0x00008D, 0x38B904, 0x000007,
- 0x03296C, 0x30010A, 0x0002F5, 0x010042,
- 0x08000A, 0x000904, 0x25BA86, 0x000007,
- 0x02312C, 0x28050A, 0x00008D, 0x01096C,
- 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x001124, 0x000424,
- 0x000424, 0x003224, 0x300102, 0x032944,
- 0x267A86, 0x000007, 0x300002, 0x0004F5,
- 0x010042, 0x08000A, 0x000315, 0x010D04,
- 0x26C086, 0x003124, 0x000464, 0x300102,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x26CA86, 0x000007, 0x003124, 0x300502,
- 0x003924, 0x300583, 0x000883, 0x0005F5,
- 0x010042, 0x28040A, 0x00008D, 0x008124,
- 0x280D02, 0x00008D, 0x008124, 0x281502,
- 0x10018D, 0x000820, 0x0002F5, 0x010040,
- 0x220007, 0x001025, 0x000575, 0x030042,
- 0x09004A, 0x10000A, 0x0A0904, 0x121104,
- 0x000007, 0x001020, 0x050860, 0x050040,
- 0x0006FD, 0x018042, 0x09004A, 0x10000A,
- 0x0000A5, 0x0A0904, 0x121104, 0x000007,
- 0x000820, 0x019060, 0x010040, 0x0002F5,
- 0x010042, 0x08000A, 0x000904, 0x284286,
- 0x000007, 0x230A06, 0x000007, 0x000606,
- 0x000007, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x289286, 0x000007, 0x000100,
- 0x080B20, 0x138B60, 0x1B8B60, 0x238B60,
- 0x2B8B60, 0x338B60, 0x3B8B60, 0x438B60,
- 0x4B8B60, 0x538B60, 0x5B8B60, 0x638B60,
- 0x6B8B60, 0x738B60, 0x7B8B60, 0x038F60,
- 0x0B8F60, 0x138F60, 0x1B8F60, 0x238F60,
- 0x2B8F60, 0x338F60, 0x3B8F60, 0x438F60,
- 0x4B8F60, 0x538F60, 0x5B8F60, 0x638F60,
- 0x6B8F60, 0x738F60, 0x7B8F60, 0x038A60,
- 0x000606, 0x018040, 0x00008D, 0x000A64,
- 0x280D02, 0x000A24, 0x00027D, 0x018042,
- 0x10000A, 0x001224, 0x0003FD, 0x018042,
- 0x08000A, 0x000904, 0x2A8286, 0x000007,
- 0x00018D, 0x000A24, 0x000464, 0x000464,
- 0x080102, 0x000924, 0x000424, 0x000424,
- 0x100102, 0x02000D, 0x009144, 0x2AD986,
- 0x000007, 0x0001FD, 0x018042, 0x08000A,
- 0x000A44, 0x2ABB86, 0x018042, 0x0A000D,
- 0x000820, 0x0002FD, 0x018040, 0x200007,
- 0x00027D, 0x001020, 0x000606, 0x018040,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x2B2A86, 0x000007, 0x00037D, 0x018042,
- 0x08000A, 0x000904, 0x2B5A86, 0x000007,
- 0x000075, 0x002E7D, 0x010042, 0x0B804A,
- 0x000020, 0x000904, 0x000686, 0x010040,
- 0x31844A, 0x30048B, 0x000883, 0x00008D,
- 0x000810, 0x28143A, 0x00008D, 0x000810,
- 0x280C3A, 0x000675, 0x010042, 0x08000A,
- 0x003815, 0x010924, 0x280502, 0x0B000D,
- 0x000820, 0x0002F5, 0x010040, 0x000606,
- 0x220007, 0x000464, 0x000464, 0x000606,
- 0x000007, 0x000134, 0x007F8D, 0x00093C,
- 0x281D12, 0x282512, 0x001F32, 0x0E0007,
- 0x00010D, 0x00037D, 0x000820, 0x018040,
- 0x05D2F4, 0x000007, 0x080007, 0x00037D,
- 0x018042, 0x08000A, 0x000904, 0x2D0286,
- 0x000007, 0x000606, 0x000007, 0x000007,
- 0x000012, 0x100007, 0x320007, 0x600007,
- 0x100080, 0x48001A, 0x004904, 0x2D6186,
- 0x000007, 0x001210, 0x58003A, 0x000145,
- 0x5C5D04, 0x000007, 0x000080, 0x48001A,
- 0x004904, 0x2DB186, 0x000007, 0x001210,
- 0x50003A, 0x005904, 0x2E0886, 0x000045,
- 0x0000C5, 0x7FFFF5, 0x7FFF7D, 0x07D524,
- 0x004224, 0x500102, 0x200502, 0x000082,
- 0x40001A, 0x004104, 0x2E3986, 0x000007,
- 0x003865, 0x40001A, 0x004020, 0x00104D,
- 0x04C184, 0x301B86, 0x000040, 0x040007,
- 0x000165, 0x000145, 0x004020, 0x000040,
- 0x000765, 0x080080, 0x40001A, 0x004104,
- 0x2EC986, 0x000007, 0x001210, 0x40003A,
- 0x004104, 0x2F2286, 0x00004D, 0x0000CD,
- 0x004810, 0x20043A, 0x000882, 0x40001A,
- 0x004104, 0x2F3186, 0x000007, 0x004820,
- 0x005904, 0x300886, 0x000040, 0x0007E5,
- 0x200480, 0x2816A0, 0x3216E0, 0x3A16E0,
- 0x4216E0, 0x021260, 0x000040, 0x000032,
- 0x400075, 0x00007D, 0x07D574, 0x200512,
- 0x000082, 0x40001A, 0x004104, 0x2FE186,
- 0x000007, 0x037206, 0x640007, 0x060007,
- 0x0000E5, 0x000020, 0x000040, 0x000A65,
- 0x000020, 0x020040, 0x020040, 0x000040,
- 0x000165, 0x000042, 0x70000A, 0x007104,
- 0x30A286, 0x000007, 0x018206, 0x640007,
- 0x050000, 0x007020, 0x000040, 0x037206,
- 0x640007, 0x000007, 0x00306D, 0x028860,
- 0x029060, 0x08000A, 0x028860, 0x008040,
- 0x100012, 0x00100D, 0x009184, 0x314186,
- 0x000E0D, 0x009184, 0x325186, 0x000007,
- 0x300007, 0x001020, 0x003B6D, 0x008040,
- 0x000080, 0x08001A, 0x000904, 0x316186,
- 0x000007, 0x001220, 0x000DED, 0x008040,
- 0x008042, 0x10000A, 0x40000D, 0x109544,
- 0x000007, 0x001020, 0x000DED, 0x008040,
- 0x008042, 0x20040A, 0x000082, 0x08001A,
- 0x000904, 0x31F186, 0x000007, 0x003B6D,
- 0x008042, 0x08000A, 0x000E15, 0x010984,
- 0x329B86, 0x600007, 0x08001A, 0x000C15,
- 0x010984, 0x328386, 0x000020, 0x1A0007,
- 0x0002ED, 0x008040, 0x620007, 0x00306D,
- 0x028042, 0x0A804A, 0x000820, 0x0A804A,
- 0x000606, 0x10804A, 0x000007, 0x282512,
- 0x001F32, 0x05D2F4, 0x54D104, 0x00735C,
- 0x000786, 0x000007, 0x0C0007, 0x0A0007,
- 0x1C0007, 0x003465, 0x020040, 0x004820,
- 0x025060, 0x40000A, 0x024060, 0x000040,
- 0x454944, 0x000007, 0x004020, 0x003AE5,
- 0x000040, 0x0028E5, 0x000042, 0x48000A,
- 0x004904, 0x386886, 0x002C65, 0x000042,
- 0x40000A, 0x0000D5, 0x454104, 0x000007,
- 0x000655, 0x054504, 0x34F286, 0x0001D5,
- 0x054504, 0x34F086, 0x002B65, 0x000042,
- 0x003AE5, 0x50004A, 0x40000A, 0x45C3D4,
- 0x000007, 0x454504, 0x000007, 0x0000CD,
- 0x444944, 0x000007, 0x454504, 0x000007,
- 0x00014D, 0x554944, 0x000007, 0x045144,
- 0x34E986, 0x002C65, 0x000042, 0x48000A,
- 0x4CD104, 0x000007, 0x04C144, 0x34F386,
- 0x000007, 0x160007, 0x002CE5, 0x040042,
- 0x40000A, 0x004020, 0x000040, 0x002965,
- 0x000042, 0x40000A, 0x004104, 0x356086,
- 0x000007, 0x002402, 0x36A206, 0x005C02,
- 0x0025E5, 0x000042, 0x40000A, 0x004274,
- 0x002AE5, 0x000042, 0x40000A, 0x004274,
- 0x500112, 0x0029E5, 0x000042, 0x40000A,
- 0x004234, 0x454104, 0x000007, 0x004020,
- 0x000040, 0x003EE5, 0x000020, 0x000040,
- 0x002DE5, 0x400152, 0x50000A, 0x045144,
- 0x364A86, 0x0000C5, 0x003EE5, 0x004020,
- 0x000040, 0x002BE5, 0x000042, 0x40000A,
- 0x404254, 0x000007, 0x002AE5, 0x004020,
- 0x000040, 0x500132, 0x040134, 0x005674,
- 0x0029E5, 0x020042, 0x42000A, 0x000042,
- 0x50000A, 0x05417C, 0x0028E5, 0x000042,
- 0x48000A, 0x0000C5, 0x4CC144, 0x371086,
- 0x0026E5, 0x0027E5, 0x020042, 0x40004A,
- 0x50000A, 0x00423C, 0x00567C, 0x0028E5,
- 0x004820, 0x000040, 0x281D12, 0x282512,
- 0x001F72, 0x002965, 0x000042, 0x40000A,
- 0x004104, 0x37AA86, 0x0E0007, 0x160007,
- 0x1E0007, 0x003EE5, 0x000042, 0x40000A,
- 0x004104, 0x37E886, 0x002D65, 0x000042,
- 0x28340A, 0x003465, 0x020042, 0x42004A,
- 0x004020, 0x4A004A, 0x50004A, 0x05D2F4,
- 0x54D104, 0x00735C, 0x385186, 0x000007,
- 0x000606, 0x080007, 0x0C0007, 0x080007,
- 0x0A0007, 0x0001E5, 0x020045, 0x004020,
- 0x000060, 0x000365, 0x000040, 0x002E65,
- 0x001A20, 0x0A1A60, 0x000040, 0x003465,
- 0x020042, 0x42004A, 0x004020, 0x4A004A,
- 0x000606, 0x50004A, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000
-};
-
-// --------------------------------------------
-// DS-1E Controller InstructionRAM Code
-// 1999/06/21
-// Buf441 slot is Enabled.
-// --------------------------------------------
-// 04/09 creat
-// 04/12 stop nise fix
-// 06/21 WorkingOff timming
-static u32 CntrlInst1E[YDSXG_CTRLLENGTH / 4] = {
- 0x000007, 0x240007, 0x0C0007, 0x1C0007,
- 0x060007, 0x700002, 0x000020, 0x030040,
- 0x007104, 0x004286, 0x030040, 0x000F0D,
- 0x000810, 0x20043A, 0x000282, 0x00020D,
- 0x000810, 0x20043A, 0x001282, 0x200E82,
- 0x00800D, 0x000810, 0x20043A, 0x001A82,
- 0x03460D, 0x000810, 0x10043A, 0x02EC0D,
- 0x000810, 0x18043A, 0x00010D, 0x020015,
- 0x0000FD, 0x000020, 0x038860, 0x039060,
- 0x038060, 0x038040, 0x038040, 0x038040,
- 0x018040, 0x000A7D, 0x038040, 0x038040,
- 0x018040, 0x200402, 0x000882, 0x08001A,
- 0x000904, 0x017186, 0x000007, 0x260007,
- 0x400007, 0x000007, 0x03258D, 0x000810,
- 0x18043A, 0x260007, 0x284402, 0x00087D,
- 0x018042, 0x00160A, 0x05A206, 0x000007,
- 0x440007, 0x00230D, 0x000810, 0x08043A,
- 0x22FA06, 0x000007, 0x0007FD, 0x018042,
- 0x08000A, 0x000904, 0x02AB86, 0x000195,
- 0x090D04, 0x000007, 0x000820, 0x0000F5,
- 0x000B7D, 0x01F060, 0x0000FD, 0x033A06,
- 0x018040, 0x000A7D, 0x038042, 0x13804A,
- 0x18000A, 0x001820, 0x059060, 0x058860,
- 0x018040, 0x0000FD, 0x018042, 0x70000A,
- 0x000115, 0x071144, 0x033B86, 0x030000,
- 0x007020, 0x036206, 0x018040, 0x00360D,
- 0x000810, 0x08043A, 0x232206, 0x000007,
- 0x02EC0D, 0x000810, 0x18043A, 0x019A06,
- 0x000007, 0x240007, 0x000F8D, 0x000810,
- 0x00163A, 0x002402, 0x005C02, 0x0028FD,
- 0x000020, 0x018040, 0x08000D, 0x000815,
- 0x510984, 0x000007, 0x00004D, 0x000E5D,
- 0x000E02, 0x00430D, 0x000810, 0x08043A,
- 0x2E1206, 0x000007, 0x00008D, 0x000924,
- 0x000F02, 0x00470D, 0x000810, 0x08043A,
- 0x2E1206, 0x000007, 0x480480, 0x001210,
- 0x28043A, 0x00778D, 0x000810, 0x280C3A,
- 0x00068D, 0x000810, 0x28143A, 0x284402,
- 0x03258D, 0x000810, 0x18043A, 0x07FF8D,
- 0x000820, 0x0002FD, 0x018040, 0x260007,
- 0x200007, 0x0002FD, 0x018042, 0x08000A,
- 0x000904, 0x051286, 0x000007, 0x240007,
- 0x02EC0D, 0x000810, 0x18043A, 0x00387D,
- 0x018042, 0x08000A, 0x001015, 0x010984,
- 0x019B86, 0x000007, 0x01B206, 0x000007,
- 0x0008FD, 0x018042, 0x18000A, 0x001904,
- 0x22B886, 0x280007, 0x001810, 0x28043A,
- 0x280C02, 0x00000D, 0x000810, 0x28143A,
- 0x08808D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00020D, 0x189904, 0x000007,
- 0x00402D, 0x0000BD, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x065A86, 0x000007,
- 0x000100, 0x000A20, 0x00047D, 0x018040,
- 0x018042, 0x20000A, 0x003015, 0x012144,
- 0x036186, 0x000007, 0x002104, 0x036186,
- 0x000007, 0x000F8D, 0x000810, 0x280C3A,
- 0x023944, 0x07C986, 0x000007, 0x001810,
- 0x28043A, 0x08810D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x002810, 0x78003A,
- 0x00788D, 0x000810, 0x08043A, 0x2A1206,
- 0x000007, 0x00400D, 0x001015, 0x189904,
- 0x292904, 0x393904, 0x000007, 0x070206,
- 0x000007, 0x0004F5, 0x00007D, 0x000020,
- 0x00008D, 0x010860, 0x018040, 0x00047D,
- 0x038042, 0x21804A, 0x18000A, 0x021944,
- 0x229086, 0x000007, 0x004075, 0x71F104,
- 0x000007, 0x010042, 0x28000A, 0x002904,
- 0x225886, 0x000007, 0x003C0D, 0x30A904,
- 0x000007, 0x00077D, 0x018042, 0x08000A,
- 0x000904, 0x08DA86, 0x00057D, 0x002820,
- 0x03B060, 0x08F206, 0x018040, 0x003020,
- 0x03A860, 0x018040, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x08FA86, 0x000007,
- 0x00057D, 0x018042, 0x28040A, 0x000E8D,
- 0x000810, 0x280C3A, 0x00000D, 0x000810,
- 0x28143A, 0x09000D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x003DFD, 0x000020,
- 0x018040, 0x00107D, 0x009D8D, 0x000810,
- 0x08043A, 0x2A1206, 0x000007, 0x000815,
- 0x08001A, 0x010984, 0x0A5186, 0x00137D,
- 0x200500, 0x280F20, 0x338F60, 0x3B8F60,
- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
- 0x038A60, 0x018040, 0x00107D, 0x018042,
- 0x08000A, 0x000215, 0x010984, 0x3A8186,
- 0x000007, 0x007FBD, 0x383DC4, 0x000007,
- 0x001A7D, 0x001375, 0x018042, 0x09004A,
- 0x10000A, 0x0B8D04, 0x139504, 0x000007,
- 0x000820, 0x019060, 0x001104, 0x225886,
- 0x010040, 0x0017FD, 0x018042, 0x08000A,
- 0x000904, 0x225A86, 0x000007, 0x00197D,
- 0x038042, 0x09804A, 0x10000A, 0x000924,
- 0x001664, 0x0011FD, 0x038042, 0x2B804A,
- 0x19804A, 0x00008D, 0x218944, 0x000007,
- 0x002244, 0x0C1986, 0x000007, 0x001A64,
- 0x002A24, 0x00197D, 0x080102, 0x100122,
- 0x000820, 0x039060, 0x018040, 0x003DFD,
- 0x00008D, 0x000820, 0x018040, 0x001375,
- 0x001A7D, 0x010042, 0x09804A, 0x10000A,
- 0x00021D, 0x0189E4, 0x2992E4, 0x309144,
- 0x000007, 0x00060D, 0x000A15, 0x000C1D,
- 0x001025, 0x00A9E4, 0x012BE4, 0x000464,
- 0x01B3E4, 0x0232E4, 0x000464, 0x000464,
- 0x000464, 0x000464, 0x00040D, 0x08B1C4,
- 0x000007, 0x000820, 0x000BF5, 0x030040,
- 0x00197D, 0x038042, 0x09804A, 0x000A24,
- 0x08000A, 0x080E64, 0x000007, 0x100122,
- 0x000820, 0x031060, 0x010040, 0x0064AC,
- 0x00027D, 0x000020, 0x018040, 0x00107D,
- 0x018042, 0x0011FD, 0x3B804A, 0x09804A,
- 0x20000A, 0x000095, 0x1A1144, 0x00A144,
- 0x0E5886, 0x00040D, 0x00B984, 0x0E5986,
- 0x0018FD, 0x018042, 0x0010FD, 0x09804A,
- 0x28000A, 0x000095, 0x010924, 0x002A64,
- 0x0E4986, 0x000007, 0x002904, 0x0E5A86,
- 0x000007, 0x0E6206, 0x080002, 0x00008D,
- 0x00387D, 0x000820, 0x018040, 0x00127D,
- 0x018042, 0x10000A, 0x003904, 0x0F0986,
- 0x00080D, 0x7FFFB5, 0x00B984, 0x0ED986,
- 0x000025, 0x0FB206, 0x00002D, 0x000015,
- 0x00082D, 0x02E00D, 0x000820, 0x0FFA06,
- 0x00000D, 0x7F8035, 0x00B984, 0x0FA986,
- 0x400025, 0x00008D, 0x110944, 0x000007,
- 0x00018D, 0x109504, 0x000007, 0x009164,
- 0x000424, 0x000424, 0x000424, 0x100102,
- 0x280002, 0x02DF0D, 0x000820, 0x0FFA06,
- 0x00018D, 0x00042D, 0x00008D, 0x109504,
- 0x000007, 0x00020D, 0x109184, 0x000007,
- 0x02DF8D, 0x000820, 0x00008D, 0x0038FD,
- 0x018040, 0x003BFD, 0x001020, 0x03A860,
- 0x000815, 0x313184, 0x212184, 0x000007,
- 0x03B060, 0x03A060, 0x018040, 0x0022FD,
- 0x000095, 0x010924, 0x000424, 0x000424,
- 0x001264, 0x100102, 0x000820, 0x039060,
- 0x018040, 0x001924, 0x010F0D, 0x00397D,
- 0x000820, 0x058040, 0x038042, 0x09844A,
- 0x000606, 0x08040A, 0x000424, 0x000424,
- 0x00117D, 0x018042, 0x08000A, 0x000A24,
- 0x280502, 0x280C02, 0x09800D, 0x000820,
- 0x0002FD, 0x018040, 0x200007, 0x0022FD,
- 0x018042, 0x08000A, 0x000095, 0x280DC4,
- 0x011924, 0x00197D, 0x018042, 0x0011FD,
- 0x09804A, 0x10000A, 0x0000B5, 0x113144,
- 0x0A8D04, 0x000007, 0x080A44, 0x129504,
- 0x000007, 0x0023FD, 0x001020, 0x038040,
- 0x101244, 0x000007, 0x000820, 0x039060,
- 0x018040, 0x0002FD, 0x018042, 0x08000A,
- 0x000904, 0x123286, 0x000007, 0x003BFD,
- 0x000100, 0x000A10, 0x0B807A, 0x13804A,
- 0x090984, 0x000007, 0x000095, 0x013D04,
- 0x12B886, 0x10000A, 0x100002, 0x090984,
- 0x000007, 0x038042, 0x11804A, 0x090D04,
- 0x000007, 0x10000A, 0x090D84, 0x000007,
- 0x00257D, 0x000820, 0x018040, 0x00010D,
- 0x000810, 0x28143A, 0x00127D, 0x018042,
- 0x20000A, 0x00197D, 0x018042, 0x00117D,
- 0x31804A, 0x10000A, 0x003124, 0x013B8D,
- 0x00397D, 0x000820, 0x058040, 0x038042,
- 0x09844A, 0x000606, 0x08040A, 0x300102,
- 0x003124, 0x000424, 0x000424, 0x001224,
- 0x280502, 0x001A4C, 0x143986, 0x700002,
- 0x00002D, 0x030000, 0x00387D, 0x018042,
- 0x10000A, 0x146206, 0x002124, 0x0000AD,
- 0x100002, 0x00010D, 0x000924, 0x006B24,
- 0x014A0D, 0x00397D, 0x000820, 0x058040,
- 0x038042, 0x09844A, 0x000606, 0x08040A,
- 0x003264, 0x00008D, 0x000A24, 0x001020,
- 0x00227D, 0x018040, 0x014F8D, 0x000810,
- 0x08043A, 0x2B5A06, 0x000007, 0x002820,
- 0x00207D, 0x018040, 0x00117D, 0x038042,
- 0x13804A, 0x33800A, 0x00387D, 0x018042,
- 0x08000A, 0x000904, 0x177286, 0x000007,
- 0x00008D, 0x030964, 0x015B0D, 0x00397D,
- 0x000820, 0x058040, 0x038042, 0x09844A,
- 0x000606, 0x08040A, 0x380102, 0x000424,
- 0x000424, 0x001224, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x15DA86, 0x000007,
- 0x280502, 0x001A4C, 0x177186, 0x000007,
- 0x032164, 0x00632C, 0x003DFD, 0x018042,
- 0x08000A, 0x000095, 0x090904, 0x000007,
- 0x000820, 0x001A4C, 0x169986, 0x018040,
- 0x030000, 0x16B206, 0x002124, 0x00010D,
- 0x000924, 0x006B24, 0x016F0D, 0x00397D,
- 0x000820, 0x058040, 0x038042, 0x09844A,
- 0x000606, 0x08040A, 0x003A64, 0x000095,
- 0x001224, 0x0002FD, 0x018042, 0x08000A,
- 0x000904, 0x171286, 0x000007, 0x01760D,
- 0x000810, 0x08043A, 0x2B5A06, 0x000007,
- 0x160A06, 0x000007, 0x007020, 0x08010A,
- 0x10012A, 0x0020FD, 0x038860, 0x039060,
- 0x018040, 0x00227D, 0x018042, 0x003DFD,
- 0x08000A, 0x31844A, 0x000904, 0x181086,
- 0x18008B, 0x00008D, 0x189904, 0x00312C,
- 0x18E206, 0x000007, 0x00324C, 0x186B86,
- 0x000007, 0x001904, 0x186886, 0x000007,
- 0x000095, 0x199144, 0x00222C, 0x003124,
- 0x00636C, 0x000E3D, 0x001375, 0x000BFD,
- 0x010042, 0x09804A, 0x10000A, 0x038AEC,
- 0x0393EC, 0x00224C, 0x18E186, 0x000007,
- 0x00008D, 0x189904, 0x00226C, 0x00322C,
- 0x30050A, 0x301DAB, 0x002083, 0x0018FD,
- 0x018042, 0x08000A, 0x018924, 0x300502,
- 0x001083, 0x001875, 0x010042, 0x10000A,
- 0x00008D, 0x010924, 0x001375, 0x330542,
- 0x330CCB, 0x332CCB, 0x3334CB, 0x333CCB,
- 0x3344CB, 0x334CCB, 0x3354CB, 0x305C8B,
- 0x006083, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x19B286, 0x000007, 0x001E2D,
- 0x0005FD, 0x018042, 0x08000A, 0x028924,
- 0x280502, 0x00060D, 0x000810, 0x280C3A,
- 0x00008D, 0x000810, 0x28143A, 0x0A808D,
- 0x000820, 0x0002F5, 0x010040, 0x220007,
- 0x001275, 0x030042, 0x21004A, 0x00008D,
- 0x1A0944, 0x000007, 0x01AB8D, 0x000810,
- 0x08043A, 0x2CAA06, 0x000007, 0x0001F5,
- 0x030042, 0x0D004A, 0x10000A, 0x089144,
- 0x000007, 0x000820, 0x010040, 0x0025F5,
- 0x0A3144, 0x000007, 0x000820, 0x032860,
- 0x030040, 0x00217D, 0x038042, 0x0B804A,
- 0x10000A, 0x000820, 0x031060, 0x030040,
- 0x00008D, 0x000124, 0x00012C, 0x000E64,
- 0x001A64, 0x00636C, 0x08010A, 0x10012A,
- 0x000820, 0x031060, 0x030040, 0x0020FD,
- 0x018042, 0x08000A, 0x00227D, 0x018042,
- 0x10000A, 0x000820, 0x031060, 0x030040,
- 0x00197D, 0x018042, 0x08000A, 0x0022FD,
- 0x038042, 0x10000A, 0x000820, 0x031060,
- 0x030040, 0x090D04, 0x000007, 0x000820,
- 0x030040, 0x038042, 0x0B804A, 0x10000A,
- 0x000820, 0x031060, 0x030040, 0x038042,
- 0x13804A, 0x19804A, 0x110D04, 0x198D04,
- 0x000007, 0x08000A, 0x001020, 0x031860,
- 0x030860, 0x030040, 0x00008D, 0x0B0944,
- 0x000007, 0x000820, 0x010040, 0x0005F5,
- 0x030042, 0x08000A, 0x000820, 0x010040,
- 0x0000F5, 0x010042, 0x08000A, 0x000904,
- 0x1D9886, 0x001E75, 0x030042, 0x01044A,
- 0x000C0A, 0x1DAA06, 0x000007, 0x000402,
- 0x000C02, 0x00177D, 0x001AF5, 0x018042,
- 0x03144A, 0x031C4A, 0x03244A, 0x032C4A,
- 0x03344A, 0x033C4A, 0x03444A, 0x004C0A,
- 0x00043D, 0x0013F5, 0x001AFD, 0x030042,
- 0x0B004A, 0x1B804A, 0x13804A, 0x20000A,
- 0x089144, 0x19A144, 0x0389E4, 0x0399EC,
- 0x005502, 0x005D0A, 0x030042, 0x0B004A,
- 0x1B804A, 0x13804A, 0x20000A, 0x089144,
- 0x19A144, 0x0389E4, 0x0399EC, 0x006502,
- 0x006D0A, 0x030042, 0x0B004A, 0x19004A,
- 0x2B804A, 0x13804A, 0x21804A, 0x30000A,
- 0x089144, 0x19A144, 0x2AB144, 0x0389E4,
- 0x0399EC, 0x007502, 0x007D0A, 0x03A9E4,
- 0x000702, 0x00107D, 0x000415, 0x018042,
- 0x08000A, 0x0109E4, 0x000F02, 0x002AF5,
- 0x0019FD, 0x010042, 0x09804A, 0x10000A,
- 0x000934, 0x001674, 0x0029F5, 0x010042,
- 0x10000A, 0x00917C, 0x002075, 0x010042,
- 0x08000A, 0x000904, 0x200A86, 0x0026F5,
- 0x0027F5, 0x030042, 0x09004A, 0x10000A,
- 0x000A3C, 0x00167C, 0x001A75, 0x000BFD,
- 0x010042, 0x51804A, 0x48000A, 0x160007,
- 0x001075, 0x010042, 0x282C0A, 0x281D12,
- 0x282512, 0x001F32, 0x1E0007, 0x0E0007,
- 0x001975, 0x010042, 0x002DF5, 0x0D004A,
- 0x10000A, 0x009144, 0x20EA86, 0x010042,
- 0x28340A, 0x000E5D, 0x00008D, 0x000375,
- 0x000820, 0x010040, 0x05D2F4, 0x54D104,
- 0x00735C, 0x218B86, 0x000007, 0x0C0007,
- 0x080007, 0x0A0007, 0x02178D, 0x000810,
- 0x08043A, 0x34B206, 0x000007, 0x219206,
- 0x000007, 0x080007, 0x002275, 0x010042,
- 0x20000A, 0x002104, 0x225886, 0x001E2D,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x21CA86, 0x000007, 0x002010, 0x30043A,
- 0x00057D, 0x0180C3, 0x08000A, 0x028924,
- 0x280502, 0x280C02, 0x0A810D, 0x000820,
- 0x0002F5, 0x010040, 0x220007, 0x0004FD,
- 0x018042, 0x70000A, 0x030000, 0x007020,
- 0x07FA06, 0x018040, 0x022B8D, 0x000810,
- 0x08043A, 0x2CAA06, 0x000007, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x22C286,
- 0x000007, 0x020206, 0x000007, 0x000875,
- 0x0009FD, 0x00010D, 0x234206, 0x000295,
- 0x000B75, 0x00097D, 0x00000D, 0x000515,
- 0x010042, 0x18000A, 0x001904, 0x2A0086,
- 0x0006F5, 0x001020, 0x010040, 0x0004F5,
- 0x000820, 0x010040, 0x000775, 0x010042,
- 0x09804A, 0x10000A, 0x001124, 0x000904,
- 0x23F286, 0x000815, 0x080102, 0x101204,
- 0x241206, 0x000575, 0x081204, 0x000007,
- 0x100102, 0x000575, 0x000425, 0x021124,
- 0x100102, 0x000820, 0x031060, 0x010040,
- 0x001924, 0x2A0086, 0x00008D, 0x000464,
- 0x009D04, 0x291086, 0x180102, 0x000575,
- 0x010042, 0x28040A, 0x00018D, 0x000924,
- 0x280D02, 0x00000D, 0x000924, 0x281502,
- 0x10000D, 0x000820, 0x0002F5, 0x010040,
- 0x200007, 0x001175, 0x0002FD, 0x018042,
- 0x08000A, 0x000904, 0x24FA86, 0x000007,
- 0x000100, 0x080B20, 0x130B60, 0x1B0B60,
- 0x030A60, 0x010040, 0x050042, 0x3D004A,
- 0x35004A, 0x2D004A, 0x20000A, 0x0006F5,
- 0x010042, 0x28140A, 0x0004F5, 0x010042,
- 0x08000A, 0x000315, 0x010D04, 0x260286,
- 0x004015, 0x000095, 0x010D04, 0x25F086,
- 0x100022, 0x10002A, 0x261A06, 0x000007,
- 0x333104, 0x2AA904, 0x000007, 0x032124,
- 0x280502, 0x284402, 0x001124, 0x400102,
- 0x000424, 0x000424, 0x003224, 0x00292C,
- 0x00636C, 0x277386, 0x000007, 0x02B164,
- 0x000464, 0x000464, 0x00008D, 0x000A64,
- 0x280D02, 0x10008D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x00008D, 0x38B904,
- 0x000007, 0x03296C, 0x30010A, 0x0002F5,
- 0x010042, 0x08000A, 0x000904, 0x270286,
- 0x000007, 0x00212C, 0x28050A, 0x00316C,
- 0x00046C, 0x00046C, 0x28450A, 0x001124,
- 0x006B64, 0x100102, 0x00008D, 0x01096C,
- 0x280D0A, 0x10010D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x004124, 0x000424,
- 0x000424, 0x003224, 0x300102, 0x032944,
- 0x27FA86, 0x000007, 0x300002, 0x0004F5,
- 0x010042, 0x08000A, 0x000315, 0x010D04,
- 0x284086, 0x003124, 0x000464, 0x300102,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x284A86, 0x000007, 0x284402, 0x003124,
- 0x300502, 0x003924, 0x300583, 0x000883,
- 0x0005F5, 0x010042, 0x28040A, 0x00008D,
- 0x008124, 0x280D02, 0x00008D, 0x008124,
- 0x281502, 0x10018D, 0x000820, 0x0002F5,
- 0x010040, 0x220007, 0x001025, 0x000575,
- 0x030042, 0x09004A, 0x10000A, 0x0A0904,
- 0x121104, 0x000007, 0x001020, 0x050860,
- 0x050040, 0x0006FD, 0x018042, 0x09004A,
- 0x10000A, 0x0000A5, 0x0A0904, 0x121104,
- 0x000007, 0x000820, 0x019060, 0x010040,
- 0x0002F5, 0x010042, 0x08000A, 0x000904,
- 0x29CA86, 0x000007, 0x244206, 0x000007,
- 0x000606, 0x000007, 0x0002F5, 0x010042,
- 0x08000A, 0x000904, 0x2A1A86, 0x000007,
- 0x000100, 0x080B20, 0x138B60, 0x1B8B60,
- 0x238B60, 0x2B8B60, 0x338B60, 0x3B8B60,
- 0x438B60, 0x4B8B60, 0x538B60, 0x5B8B60,
- 0x638B60, 0x6B8B60, 0x738B60, 0x7B8B60,
- 0x038F60, 0x0B8F60, 0x138F60, 0x1B8F60,
- 0x238F60, 0x2B8F60, 0x338F60, 0x3B8F60,
- 0x438F60, 0x4B8F60, 0x538F60, 0x5B8F60,
- 0x638F60, 0x6B8F60, 0x738F60, 0x7B8F60,
- 0x038A60, 0x000606, 0x018040, 0x00008D,
- 0x000A64, 0x280D02, 0x000A24, 0x00027D,
- 0x018042, 0x10000A, 0x001224, 0x0003FD,
- 0x018042, 0x08000A, 0x000904, 0x2C0A86,
- 0x000007, 0x00018D, 0x000A24, 0x000464,
- 0x000464, 0x080102, 0x000924, 0x000424,
- 0x000424, 0x100102, 0x02000D, 0x009144,
- 0x2C6186, 0x000007, 0x0001FD, 0x018042,
- 0x08000A, 0x000A44, 0x2C4386, 0x018042,
- 0x0A000D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00027D, 0x001020, 0x000606,
- 0x018040, 0x0002F5, 0x010042, 0x08000A,
- 0x000904, 0x2CB286, 0x000007, 0x00037D,
- 0x018042, 0x08000A, 0x000904, 0x2CE286,
- 0x000007, 0x000075, 0x002E7D, 0x010042,
- 0x0B804A, 0x000020, 0x000904, 0x000686,
- 0x010040, 0x31844A, 0x30048B, 0x000883,
- 0x00008D, 0x000810, 0x28143A, 0x00008D,
- 0x000810, 0x280C3A, 0x000675, 0x010042,
- 0x08000A, 0x003815, 0x010924, 0x280502,
- 0x0B000D, 0x000820, 0x0002F5, 0x010040,
- 0x000606, 0x220007, 0x000464, 0x000464,
- 0x000606, 0x000007, 0x000134, 0x007F8D,
- 0x00093C, 0x281D12, 0x282512, 0x001F32,
- 0x0E0007, 0x00010D, 0x00037D, 0x000820,
- 0x018040, 0x05D2F4, 0x000007, 0x080007,
- 0x00037D, 0x018042, 0x08000A, 0x000904,
- 0x2E8A86, 0x000007, 0x000606, 0x000007,
- 0x000007, 0x000012, 0x100007, 0x320007,
- 0x600007, 0x460007, 0x100080, 0x48001A,
- 0x004904, 0x2EF186, 0x000007, 0x001210,
- 0x58003A, 0x000145, 0x5C5D04, 0x000007,
- 0x000080, 0x48001A, 0x004904, 0x2F4186,
- 0x000007, 0x001210, 0x50003A, 0x005904,
- 0x2F9886, 0x000045, 0x0000C5, 0x7FFFF5,
- 0x7FFF7D, 0x07D524, 0x004224, 0x500102,
- 0x200502, 0x000082, 0x40001A, 0x004104,
- 0x2FC986, 0x000007, 0x003865, 0x40001A,
- 0x004020, 0x00104D, 0x04C184, 0x31AB86,
- 0x000040, 0x040007, 0x000165, 0x000145,
- 0x004020, 0x000040, 0x000765, 0x080080,
- 0x40001A, 0x004104, 0x305986, 0x000007,
- 0x001210, 0x40003A, 0x004104, 0x30B286,
- 0x00004D, 0x0000CD, 0x004810, 0x20043A,
- 0x000882, 0x40001A, 0x004104, 0x30C186,
- 0x000007, 0x004820, 0x005904, 0x319886,
- 0x000040, 0x0007E5, 0x200480, 0x2816A0,
- 0x3216E0, 0x3A16E0, 0x4216E0, 0x021260,
- 0x000040, 0x000032, 0x400075, 0x00007D,
- 0x07D574, 0x200512, 0x000082, 0x40001A,
- 0x004104, 0x317186, 0x000007, 0x038A06,
- 0x640007, 0x0000E5, 0x000020, 0x000040,
- 0x000A65, 0x000020, 0x020040, 0x020040,
- 0x000040, 0x000165, 0x000042, 0x70000A,
- 0x007104, 0x323286, 0x000007, 0x060007,
- 0x019A06, 0x640007, 0x050000, 0x007020,
- 0x000040, 0x038A06, 0x640007, 0x000007,
- 0x00306D, 0x028860, 0x029060, 0x08000A,
- 0x028860, 0x008040, 0x100012, 0x00100D,
- 0x009184, 0x32D186, 0x000E0D, 0x009184,
- 0x33E186, 0x000007, 0x300007, 0x001020,
- 0x003B6D, 0x008040, 0x000080, 0x08001A,
- 0x000904, 0x32F186, 0x000007, 0x001220,
- 0x000DED, 0x008040, 0x008042, 0x10000A,
- 0x40000D, 0x109544, 0x000007, 0x001020,
- 0x000DED, 0x008040, 0x008042, 0x20040A,
- 0x000082, 0x08001A, 0x000904, 0x338186,
- 0x000007, 0x003B6D, 0x008042, 0x08000A,
- 0x000E15, 0x010984, 0x342B86, 0x600007,
- 0x08001A, 0x000C15, 0x010984, 0x341386,
- 0x000020, 0x1A0007, 0x0002ED, 0x008040,
- 0x620007, 0x00306D, 0x028042, 0x0A804A,
- 0x000820, 0x0A804A, 0x000606, 0x10804A,
- 0x000007, 0x282512, 0x001F32, 0x05D2F4,
- 0x54D104, 0x00735C, 0x000786, 0x000007,
- 0x0C0007, 0x0A0007, 0x1C0007, 0x003465,
- 0x020040, 0x004820, 0x025060, 0x40000A,
- 0x024060, 0x000040, 0x454944, 0x000007,
- 0x004020, 0x003AE5, 0x000040, 0x0028E5,
- 0x000042, 0x48000A, 0x004904, 0x39F886,
- 0x002C65, 0x000042, 0x40000A, 0x0000D5,
- 0x454104, 0x000007, 0x000655, 0x054504,
- 0x368286, 0x0001D5, 0x054504, 0x368086,
- 0x002B65, 0x000042, 0x003AE5, 0x50004A,
- 0x40000A, 0x45C3D4, 0x000007, 0x454504,
- 0x000007, 0x0000CD, 0x444944, 0x000007,
- 0x454504, 0x000007, 0x00014D, 0x554944,
- 0x000007, 0x045144, 0x367986, 0x002C65,
- 0x000042, 0x48000A, 0x4CD104, 0x000007,
- 0x04C144, 0x368386, 0x000007, 0x160007,
- 0x002CE5, 0x040042, 0x40000A, 0x004020,
- 0x000040, 0x002965, 0x000042, 0x40000A,
- 0x004104, 0x36F086, 0x000007, 0x002402,
- 0x383206, 0x005C02, 0x0025E5, 0x000042,
- 0x40000A, 0x004274, 0x002AE5, 0x000042,
- 0x40000A, 0x004274, 0x500112, 0x0029E5,
- 0x000042, 0x40000A, 0x004234, 0x454104,
- 0x000007, 0x004020, 0x000040, 0x003EE5,
- 0x000020, 0x000040, 0x002DE5, 0x400152,
- 0x50000A, 0x045144, 0x37DA86, 0x0000C5,
- 0x003EE5, 0x004020, 0x000040, 0x002BE5,
- 0x000042, 0x40000A, 0x404254, 0x000007,
- 0x002AE5, 0x004020, 0x000040, 0x500132,
- 0x040134, 0x005674, 0x0029E5, 0x020042,
- 0x42000A, 0x000042, 0x50000A, 0x05417C,
- 0x0028E5, 0x000042, 0x48000A, 0x0000C5,
- 0x4CC144, 0x38A086, 0x0026E5, 0x0027E5,
- 0x020042, 0x40004A, 0x50000A, 0x00423C,
- 0x00567C, 0x0028E5, 0x004820, 0x000040,
- 0x281D12, 0x282512, 0x001F72, 0x002965,
- 0x000042, 0x40000A, 0x004104, 0x393A86,
- 0x0E0007, 0x160007, 0x1E0007, 0x003EE5,
- 0x000042, 0x40000A, 0x004104, 0x397886,
- 0x002D65, 0x000042, 0x28340A, 0x003465,
- 0x020042, 0x42004A, 0x004020, 0x4A004A,
- 0x50004A, 0x05D2F4, 0x54D104, 0x00735C,
- 0x39E186, 0x000007, 0x000606, 0x080007,
- 0x0C0007, 0x080007, 0x0A0007, 0x0001E5,
- 0x020045, 0x004020, 0x000060, 0x000365,
- 0x000040, 0x002E65, 0x001A20, 0x0A1A60,
- 0x000040, 0x003465, 0x020042, 0x42004A,
- 0x004020, 0x4A004A, 0x000606, 0x50004A,
- 0x0017FD, 0x018042, 0x08000A, 0x000904,
- 0x225A86, 0x000007, 0x00107D, 0x018042,
- 0x0011FD, 0x33804A, 0x19804A, 0x20000A,
- 0x000095, 0x2A1144, 0x01A144, 0x3B9086,
- 0x00040D, 0x00B184, 0x3B9186, 0x0018FD,
- 0x018042, 0x0010FD, 0x09804A, 0x38000A,
- 0x000095, 0x010924, 0x003A64, 0x3B8186,
- 0x000007, 0x003904, 0x3B9286, 0x000007,
- 0x3B9A06, 0x00000D, 0x00008D, 0x000820,
- 0x00387D, 0x018040, 0x700002, 0x00117D,
- 0x018042, 0x00197D, 0x29804A, 0x30000A,
- 0x380002, 0x003124, 0x000424, 0x000424,
- 0x002A24, 0x280502, 0x00068D, 0x000810,
- 0x28143A, 0x00750D, 0x00B124, 0x002264,
- 0x3D0386, 0x284402, 0x000810, 0x280C3A,
- 0x0B800D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00758D, 0x00B124, 0x100102,
- 0x012144, 0x3E4986, 0x001810, 0x10003A,
- 0x00387D, 0x018042, 0x08000A, 0x000904,
- 0x3E4886, 0x030000, 0x3E4A06, 0x0000BD,
- 0x00008D, 0x023164, 0x000A64, 0x280D02,
- 0x0B808D, 0x000820, 0x0002FD, 0x018040,
- 0x200007, 0x00387D, 0x018042, 0x08000A,
- 0x000904, 0x3E3286, 0x030000, 0x0002FD,
- 0x018042, 0x08000A, 0x000904, 0x3D8286,
- 0x000007, 0x002810, 0x28043A, 0x00750D,
- 0x030924, 0x002264, 0x280D02, 0x02316C,
- 0x28450A, 0x0B810D, 0x000820, 0x0002FD,
- 0x018040, 0x200007, 0x00008D, 0x000A24,
- 0x3E4A06, 0x100102, 0x001810, 0x10003A,
- 0x0000BD, 0x003810, 0x30043A, 0x00187D,
- 0x018042, 0x0018FD, 0x09804A, 0x20000A,
- 0x0000AD, 0x028924, 0x07212C, 0x001010,
- 0x300583, 0x300D8B, 0x3014BB, 0x301C83,
- 0x002083, 0x00137D, 0x038042, 0x33844A,
- 0x33ACCB, 0x33B4CB, 0x33BCCB, 0x33C4CB,
- 0x33CCCB, 0x33D4CB, 0x305C8B, 0x006083,
- 0x001E0D, 0x0005FD, 0x018042, 0x20000A,
- 0x020924, 0x00068D, 0x00A96C, 0x00009D,
- 0x0002FD, 0x018042, 0x08000A, 0x000904,
- 0x3F6A86, 0x000007, 0x280502, 0x280D0A,
- 0x284402, 0x001810, 0x28143A, 0x0C008D,
- 0x000820, 0x0002FD, 0x018040, 0x220007,
- 0x003904, 0x225886, 0x001E0D, 0x00057D,
- 0x018042, 0x20000A, 0x020924, 0x0000A5,
- 0x0002FD, 0x018042, 0x08000A, 0x000904,
- 0x402A86, 0x000007, 0x280502, 0x280C02,
- 0x002010, 0x28143A, 0x0C010D, 0x000820,
- 0x0002FD, 0x018040, 0x225A06, 0x220007,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000,
- 0x000000, 0x000000, 0x000000, 0x000000
-};
-
-#endif //_HWMCODE_
diff --git a/sound/oss/yss225.c b/sound/oss/yss225.c
deleted file mode 100644
index e700400576d8..000000000000
--- a/sound/oss/yss225.c
+++ /dev/null
@@ -1,319 +0,0 @@
-#include <linux/init.h>
-
-unsigned char page_zero[] __initdata = {
-0x01, 0x7c, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00,
-0x11, 0x00, 0x20, 0x00, 0x32, 0x00, 0x40, 0x00, 0x13, 0x00, 0x00,
-0x00, 0x14, 0x02, 0x76, 0x00, 0x60, 0x00, 0x80, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x19,
-0x01, 0x1a, 0x01, 0x20, 0x01, 0x40, 0x01, 0x17, 0x00, 0x00, 0x01,
-0x80, 0x01, 0x20, 0x00, 0x10, 0x01, 0xa0, 0x03, 0xd1, 0x00, 0x00,
-0x01, 0xf2, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0xf4, 0x02,
-0xe0, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x17,
-0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x71, 0x02, 0x00, 0x00, 0x60, 0x00, 0x00,
-0x00, 0x92, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb3, 0x02,
-0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0x40,
-0x00, 0x80, 0x00, 0xf5, 0x00, 0x20, 0x00, 0x70, 0x00, 0xa0, 0x02,
-0x11, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
-0x02, 0x00, 0x00, 0x20, 0x00, 0x10, 0x00, 0x17, 0x00, 0x1b, 0x00,
-0x1d, 0x02, 0xdf
-};
-
-unsigned char page_one[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x19, 0x00,
-0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xd8, 0x00, 0x00,
-0x02, 0x20, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x01,
-0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x40, 0x02, 0x60,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x80, 0x00,
-0x00, 0x02, 0xfb, 0x02, 0xa0, 0x00, 0x00, 0x00, 0x1b, 0x02, 0xd7,
-0x00, 0x00, 0x02, 0xf7, 0x03, 0x20, 0x03, 0x00, 0x00, 0x00, 0x00,
-0x1c, 0x03, 0x3c, 0x00, 0x00, 0x03, 0x3f, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x03, 0x5d, 0x00,
-0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0x7d, 0x00, 0x00, 0x03, 0xc0,
-0x00, 0x00, 0x03, 0x9e, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03,
-0xbe, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
-0xdb, 0x00, 0x00, 0x02, 0xdb, 0x00, 0x00, 0x02, 0xe0, 0x00, 0x00,
-0x02, 0xfb, 0x00, 0x00, 0x02, 0xc0, 0x02, 0x40, 0x02, 0xfb, 0x02,
-0x60, 0x00, 0x1b
-};
-
-unsigned char page_two[] __initdata = {
-0xc4, 0x00, 0x44, 0x07, 0x44, 0x00, 0x40, 0x25, 0x01, 0x06, 0xc4,
-0x07, 0x40, 0x25, 0x01, 0x00, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x07,
-0x05, 0x05, 0x05, 0x04, 0x07, 0x05, 0x04, 0x07, 0x05, 0x44, 0x46,
-0x44, 0x46, 0x46, 0x07, 0x05, 0x44, 0x46, 0x05, 0x46, 0x05, 0x46,
-0x05, 0x46, 0x05, 0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07,
-0x44, 0x46, 0x05, 0x07, 0x44, 0x46, 0x05, 0x07, 0x44, 0x05, 0x05,
-0x05, 0x44, 0x05, 0x05, 0x05, 0x46, 0x05, 0x46, 0x05, 0x46, 0x05,
-0x46, 0x05, 0x46, 0x07, 0x46, 0x07, 0x44
-};
-
-unsigned char page_three[] __initdata = {
-0x07, 0x40, 0x00, 0x00, 0x00, 0x47, 0x00, 0x40, 0x00, 0x40, 0x06,
-0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
-0xc0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x00,
-0x60, 0x00, 0x70, 0x00, 0x40, 0x00, 0x40, 0x00, 0x42, 0x00, 0x40,
-0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
-0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x00, 0x42, 0x00, 0x40, 0x00, 0x42, 0x00, 0x02, 0x00, 0x02, 0x00,
-0x02, 0x00, 0x42, 0x00, 0xc0, 0x00, 0x40
-};
-
-unsigned char page_four[] __initdata = {
-0x63, 0x03, 0x26, 0x02, 0x2c, 0x00, 0x24, 0x00, 0x2e, 0x02, 0x02,
-0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
-0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, 0x00,
-0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60,
-0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00, 0x60, 0x00, 0x20, 0x00,
-0x20, 0x00, 0x22, 0x02, 0x22, 0x02, 0x20, 0x00, 0x60, 0x00, 0x22,
-0x02, 0x62, 0x02, 0x20, 0x01, 0x21, 0x01
-};
-
-unsigned char page_six[] __initdata = {
-0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00,
-0x00, 0x08, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x0e,
-0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x00, 0x00, 0x14, 0x00, 0x00,
-0x16, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x1c, 0x00,
-0x00, 0x1e, 0x00, 0x00, 0x20, 0x00, 0x00, 0x22, 0x00, 0x00, 0x24,
-0x00, 0x00, 0x26, 0x00, 0x00, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x00,
-0x2c, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x30, 0x00, 0x00, 0x32, 0x00,
-0x00, 0x34, 0x00, 0x00, 0x36, 0x00, 0x00, 0x38, 0x00, 0x00, 0x3a,
-0x00, 0x00, 0x3c, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x40, 0x00, 0x00,
-0x42, 0x03, 0x00, 0x44, 0x01, 0x00, 0x46, 0x0a, 0x21, 0x48, 0x0d,
-0x23, 0x4a, 0x23, 0x1b, 0x4c, 0x37, 0x8f, 0x4e, 0x45, 0x77, 0x50,
-0x52, 0xe2, 0x52, 0x1c, 0x92, 0x54, 0x1c, 0x52, 0x56, 0x07, 0x00,
-0x58, 0x2f, 0xc6, 0x5a, 0x0b, 0x00, 0x5c, 0x30, 0x06, 0x5e, 0x17,
-0x00, 0x60, 0x3d, 0xda, 0x62, 0x29, 0x00, 0x64, 0x3e, 0x41, 0x66,
-0x39, 0x00, 0x68, 0x4c, 0x48, 0x6a, 0x49, 0x00, 0x6c, 0x4c, 0x6c,
-0x6e, 0x11, 0xd2, 0x70, 0x16, 0x0c, 0x72, 0x00, 0x00, 0x74, 0x00,
-0x80, 0x76, 0x0f, 0x00, 0x78, 0x00, 0x80, 0x7a, 0x13, 0x00, 0x7c,
-0x80, 0x00, 0x7e, 0x80, 0x80
-};
-
-unsigned char page_seven[] __initdata = {
-0x0f, 0xff, 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
-0x08, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0f,
-0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0x0f, 0xff,
-0x0f, 0xff, 0x0f, 0xff, 0x02, 0xe9, 0x06, 0x8c, 0x06, 0x8c, 0x0f,
-0xff, 0x1a, 0x75, 0x0d, 0x8b, 0x04, 0xe9, 0x0b, 0x16, 0x1a, 0x38,
-0x0d, 0xc8, 0x04, 0x6f, 0x0b, 0x91, 0x0f, 0xff, 0x06, 0x40, 0x06,
-0x40, 0x02, 0x8f, 0x0f, 0xff, 0x06, 0x62, 0x06, 0x62, 0x02, 0x7b,
-0x0f, 0xff, 0x06, 0x97, 0x06, 0x97, 0x02, 0x52, 0x0f, 0xff, 0x06,
-0xf6, 0x06, 0xf6, 0x02, 0x19, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55,
-0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x05, 0x55, 0x14,
-0xda, 0x0d, 0x93, 0x04, 0xda, 0x05, 0x93, 0x14, 0xda, 0x0d, 0x93,
-0x04, 0xda, 0x05, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x02, 0x00
-};
-
-unsigned char page_zero_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_one_v2[] __initdata = {
-0x01, 0xc0, 0x01, 0xfa, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_two_v2[] __initdata = {
-0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-unsigned char page_three_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-unsigned char page_four_v2[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00
-};
-
-unsigned char page_seven_v2[] __initdata = {
-0x0f, 0xff, 0x0f, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-unsigned char mod_v2[] __initdata = {
-0x01, 0x00, 0x02, 0x00, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x02,
-0x00, 0x01, 0x03, 0x02, 0x00, 0x01, 0x04, 0x02, 0x00, 0x01, 0x05,
-0x02, 0x00, 0x01, 0x06, 0x02, 0x00, 0x01, 0x07, 0x02, 0x00, 0xb0,
-0x20, 0xb1, 0x20, 0xb2, 0x20, 0xb3, 0x20, 0xb4, 0x20, 0xb5, 0x20,
-0xb6, 0x20, 0xb7, 0x20, 0xf0, 0x20, 0xf1, 0x20, 0xf2, 0x20, 0xf3,
-0x20, 0xf4, 0x20, 0xf5, 0x20, 0xf6, 0x20, 0xf7, 0x20, 0x10, 0xff,
-0x11, 0xff, 0x12, 0xff, 0x13, 0xff, 0x14, 0xff, 0x15, 0xff, 0x16,
-0xff, 0x17, 0xff, 0x20, 0xff, 0x21, 0xff, 0x22, 0xff, 0x23, 0xff,
-0x24, 0xff, 0x25, 0xff, 0x26, 0xff, 0x27, 0xff, 0x30, 0x00, 0x31,
-0x00, 0x32, 0x00, 0x33, 0x00, 0x34, 0x00, 0x35, 0x00, 0x36, 0x00,
-0x37, 0x00, 0x40, 0x00, 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x44,
-0x00, 0x45, 0x00, 0x46, 0x00, 0x47, 0x00, 0x50, 0x00, 0x51, 0x00,
-0x52, 0x00, 0x53, 0x00, 0x54, 0x00, 0x55, 0x00, 0x56, 0x00, 0x57,
-0x00, 0x60, 0x00, 0x61, 0x00, 0x62, 0x00, 0x63, 0x00, 0x64, 0x00,
-0x65, 0x00, 0x66, 0x00, 0x67, 0x00, 0x70, 0xc0, 0x71, 0xc0, 0x72,
-0xc0, 0x73, 0xc0, 0x74, 0xc0, 0x75, 0xc0, 0x76, 0xc0, 0x77, 0xc0,
-0x80, 0x00, 0x81, 0x00, 0x82, 0x00, 0x83, 0x00, 0x84, 0x00, 0x85,
-0x00, 0x86, 0x00, 0x87, 0x00, 0x90, 0x00, 0x91, 0x00, 0x92, 0x00,
-0x93, 0x00, 0x94, 0x00, 0x95, 0x00, 0x96, 0x00, 0x97, 0x00, 0xa0,
-0x00, 0xa1, 0x00, 0xa2, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0xa5, 0x00,
-0xa6, 0x00, 0xa7, 0x00, 0xc0, 0x00, 0xc1, 0x00, 0xc2, 0x00, 0xc3,
-0x00, 0xc4, 0x00, 0xc5, 0x00, 0xc6, 0x00, 0xc7, 0x00, 0xd0, 0x00,
-0xd1, 0x00, 0xd2, 0x00, 0xd3, 0x00, 0xd4, 0x00, 0xd5, 0x00, 0xd6,
-0x00, 0xd7, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe2, 0x00, 0xe3, 0x00,
-0xe4, 0x00, 0xe5, 0x00, 0xe6, 0x00, 0xe7, 0x00, 0x01, 0x00, 0x02,
-0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03,
-0x02, 0x01, 0x01, 0x04, 0x02, 0x01, 0x01, 0x05, 0x02, 0x01, 0x01,
-0x06, 0x02, 0x01, 0x01, 0x07, 0x02, 0x01
-};
-unsigned char coefficients[] __initdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x00, 0x4b, 0x03,
-0x11, 0x00, 0x4d, 0x01, 0x32, 0x07, 0x46, 0x00, 0x00, 0x07, 0x49,
-0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x01,
-0x40, 0x02, 0x40, 0x01, 0x41, 0x02, 0x60, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00, 0x07, 0x4a, 0x00,
-0x00, 0x00, 0x47, 0x01, 0x00, 0x00, 0x4a, 0x01, 0x20, 0x07, 0x47,
-0x00, 0x00, 0x07, 0x4a, 0x00, 0x00, 0x07, 0x7c, 0x00, 0x00, 0x07,
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x07, 0x7c, 0x00, 0x00,
-0x07, 0x7e, 0x00, 0x00, 0x07, 0x44, 0x00, 0x00, 0x00, 0x44, 0x01,
-0x00, 0x07, 0x44, 0x00, 0x00, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43,
-0x00, 0x00, 0x00, 0x42, 0x01, 0x1a, 0x00, 0x43, 0x01, 0x20, 0x07,
-0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00,
-0x07, 0x41, 0x00, 0x00, 0x01, 0x40, 0x02, 0x40, 0x01, 0x41, 0x02,
-0x60, 0x07, 0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x44,
-0x0f, 0xff, 0x07, 0x42, 0x00, 0x00, 0x07, 0x43, 0x00, 0x00, 0x07,
-0x40, 0x00, 0x00, 0x07, 0x41, 0x00, 0x00, 0x07, 0x51, 0x06, 0x40,
-0x07, 0x50, 0x06, 0x40, 0x07, 0x4f, 0x03, 0x81, 0x07, 0x53, 0x1a,
-0x76, 0x07, 0x54, 0x0d, 0x8b, 0x07, 0x55, 0x04, 0xe9, 0x07, 0x56,
-0x0b, 0x17, 0x07, 0x57, 0x1a, 0x38, 0x07, 0x58, 0x0d, 0xc9, 0x07,
-0x59, 0x04, 0x6f, 0x07, 0x5a, 0x0b, 0x91, 0x07, 0x73, 0x14, 0xda,
-0x07, 0x74, 0x0d, 0x93, 0x07, 0x75, 0x04, 0xd9, 0x07, 0x76, 0x05,
-0x93, 0x07, 0x77, 0x14, 0xda, 0x07, 0x78, 0x0d, 0x93, 0x07, 0x79,
-0x04, 0xd9, 0x07, 0x7a, 0x05, 0x93, 0x07, 0x5e, 0x03, 0x68, 0x07,
-0x5c, 0x04, 0x31, 0x07, 0x5d, 0x04, 0x31, 0x07, 0x62, 0x03, 0x52,
-0x07, 0x60, 0x04, 0x76, 0x07, 0x61, 0x04, 0x76, 0x07, 0x66, 0x03,
-0x2e, 0x07, 0x64, 0x04, 0xda, 0x07, 0x65, 0x04, 0xda, 0x07, 0x6a,
-0x02, 0xf6, 0x07, 0x68, 0x05, 0x62, 0x07, 0x69, 0x05, 0x62, 0x06,
-0x46, 0x0a, 0x22, 0x06, 0x48, 0x0d, 0x24, 0x06, 0x6e, 0x11, 0xd3,
-0x06, 0x70, 0x15, 0xcb, 0x06, 0x52, 0x20, 0x93, 0x06, 0x54, 0x20,
-0x54, 0x06, 0x4a, 0x27, 0x1d, 0x06, 0x58, 0x2f, 0xc8, 0x06, 0x5c,
-0x30, 0x07, 0x06, 0x4c, 0x37, 0x90, 0x06, 0x60, 0x3d, 0xdb, 0x06,
-0x64, 0x3e, 0x42, 0x06, 0x4e, 0x45, 0x78, 0x06, 0x68, 0x4c, 0x48,
-0x06, 0x6c, 0x4c, 0x6c, 0x06, 0x50, 0x52, 0xe2, 0x06, 0x42, 0x02,
-0xba
-};
-unsigned char coefficients2[] __initdata = {
-0x07, 0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x45, 0x0f,
-0xff, 0x07, 0x48, 0x0f, 0xff, 0x07, 0x7b, 0x04, 0xcc, 0x07, 0x7d,
-0x04, 0xcc, 0x07, 0x7c, 0x00, 0x00, 0x07, 0x7e, 0x00, 0x00, 0x07,
-0x46, 0x00, 0x00, 0x07, 0x49, 0x00, 0x00, 0x07, 0x47, 0x00, 0x00,
-0x07, 0x4a, 0x00, 0x00, 0x07, 0x4c, 0x00, 0x00, 0x07, 0x4e, 0x00, 0x00
-};
-unsigned char coefficients3[] __initdata = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x28, 0x00, 0x51, 0x00,
-0x51, 0x00, 0x7a, 0x00, 0x7a, 0x00, 0xa3, 0x00, 0xa3, 0x00, 0xcc,
-0x00, 0xcc, 0x00, 0xf5, 0x00, 0xf5, 0x01, 0x1e, 0x01, 0x1e, 0x01,
-0x47, 0x01, 0x47, 0x01, 0x70, 0x01, 0x70, 0x01, 0x99, 0x01, 0x99,
-0x01, 0xc2, 0x01, 0xc2, 0x01, 0xeb, 0x01, 0xeb, 0x02, 0x14, 0x02,
-0x14, 0x02, 0x3d, 0x02, 0x3d, 0x02, 0x66, 0x02, 0x66, 0x02, 0x8f,
-0x02, 0x8f, 0x02, 0xb8, 0x02, 0xb8, 0x02, 0xe1, 0x02, 0xe1, 0x03,
-0x0a, 0x03, 0x0a, 0x03, 0x33, 0x03, 0x33, 0x03, 0x5c, 0x03, 0x5c,
-0x03, 0x85, 0x03, 0x85, 0x03, 0xae, 0x03, 0xae, 0x03, 0xd7, 0x03,
-0xd7, 0x04, 0x00, 0x04, 0x00, 0x04, 0x28, 0x04, 0x28, 0x04, 0x51,
-0x04, 0x51, 0x04, 0x7a, 0x04, 0x7a, 0x04, 0xa3, 0x04, 0xa3, 0x04,
-0xcc, 0x04, 0xcc, 0x04, 0xf5, 0x04, 0xf5, 0x05, 0x1e, 0x05, 0x1e,
-0x05, 0x47, 0x05, 0x47, 0x05, 0x70, 0x05, 0x70, 0x05, 0x99, 0x05,
-0x99, 0x05, 0xc2, 0x05, 0xc2, 0x05, 0xeb, 0x05, 0xeb, 0x06, 0x14,
-0x06, 0x14, 0x06, 0x3d, 0x06, 0x3d, 0x06, 0x66, 0x06, 0x66, 0x06,
-0x8f, 0x06, 0x8f, 0x06, 0xb8, 0x06, 0xb8, 0x06, 0xe1, 0x06, 0xe1,
-0x07, 0x0a, 0x07, 0x0a, 0x07, 0x33, 0x07, 0x33, 0x07, 0x5c, 0x07,
-0x5c, 0x07, 0x85, 0x07, 0x85, 0x07, 0xae, 0x07, 0xae, 0x07, 0xd7,
-0x07, 0xd7, 0x08, 0x00, 0x08, 0x00, 0x08, 0x28, 0x08, 0x28, 0x08,
-0x51, 0x08, 0x51, 0x08, 0x7a, 0x08, 0x7a, 0x08, 0xa3, 0x08, 0xa3,
-0x08, 0xcc, 0x08, 0xcc, 0x08, 0xf5, 0x08, 0xf5, 0x09, 0x1e, 0x09,
-0x1e, 0x09, 0x47, 0x09, 0x47, 0x09, 0x70, 0x09, 0x70, 0x09, 0x99,
-0x09, 0x99, 0x09, 0xc2, 0x09, 0xc2, 0x09, 0xeb, 0x09, 0xeb, 0x0a,
-0x14, 0x0a, 0x14, 0x0a, 0x3d, 0x0a, 0x3d, 0x0a, 0x66, 0x0a, 0x66,
-0x0a, 0x8f, 0x0a, 0x8f, 0x0a, 0xb8, 0x0a, 0xb8, 0x0a, 0xe1, 0x0a,
-0xe1, 0x0b, 0x0a, 0x0b, 0x0a, 0x0b, 0x33, 0x0b, 0x33, 0x0b, 0x5c,
-0x0b, 0x5c, 0x0b, 0x85, 0x0b, 0x85, 0x0b, 0xae, 0x0b, 0xae, 0x0b,
-0xd7, 0x0b, 0xd7, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x28, 0x0c, 0x28,
-0x0c, 0x51, 0x0c, 0x51, 0x0c, 0x7a, 0x0c, 0x7a, 0x0c, 0xa3, 0x0c,
-0xa3, 0x0c, 0xcc, 0x0c, 0xcc, 0x0c, 0xf5, 0x0c, 0xf5, 0x0d, 0x1e,
-0x0d, 0x1e, 0x0d, 0x47, 0x0d, 0x47, 0x0d, 0x70, 0x0d, 0x70, 0x0d,
-0x99, 0x0d, 0x99, 0x0d, 0xc2, 0x0d, 0xc2, 0x0d, 0xeb, 0x0d, 0xeb,
-0x0e, 0x14, 0x0e, 0x14, 0x0e, 0x3d, 0x0e, 0x3d, 0x0e, 0x66, 0x0e,
-0x66, 0x0e, 0x8f, 0x0e, 0x8f, 0x0e, 0xb8, 0x0e, 0xb8, 0x0e, 0xe1,
-0x0e, 0xe1, 0x0f, 0x0a, 0x0f, 0x0a, 0x0f, 0x33, 0x0f, 0x33, 0x0f,
-0x5c, 0x0f, 0x5c, 0x0f, 0x85, 0x0f, 0x85, 0x0f, 0xae, 0x0f, 0xae,
-0x0f, 0xd7, 0x0f, 0xd7, 0x0f, 0xff, 0x0f, 0xff
-};
-
diff --git a/sound/oss/yss225.h b/sound/oss/yss225.h
deleted file mode 100644
index 56d8b6b5e432..000000000000
--- a/sound/oss/yss225.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __yss255_h__
-#define __yss255_h__
-
-extern unsigned char page_zero[256];
-extern unsigned char page_one[256];
-extern unsigned char page_two[128];
-extern unsigned char page_three[128];
-extern unsigned char page_four[128];
-extern unsigned char page_six[192];
-extern unsigned char page_seven[256];
-extern unsigned char page_zero_v2[96];
-extern unsigned char page_one_v2[96];
-extern unsigned char page_two_v2[48];
-extern unsigned char page_three_v2[48];
-extern unsigned char page_four_v2[48];
-extern unsigned char page_seven_v2[96];
-extern unsigned char mod_v2[304];
-extern unsigned char coefficients[364];
-extern unsigned char coefficients2[56];
-extern unsigned char coefficients3[404];
-
-
-#endif /* __ys225_h__ */
-
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index ce73f3eae78c..cf603337b321 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -193,7 +193,7 @@ harmony_set_control(struct snd_harmony *h)
}
static irqreturn_t
-snd_harmony_interrupt(int irq, void *dev, struct pt_regs *regs)
+snd_harmony_interrupt(int irq, void *dev)
{
u32 dstatus;
struct snd_harmony *h = dev;
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index dc28b111a06d..15be6ba87c82 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -530,7 +530,7 @@ AC97_ENUM("ALC Headphone Mux", wm9711_enum[1]),
AC97_SINGLE("ALC Headphone Volume", AC97_VIDEO, 7, 7, 1),
AC97_SINGLE("Out3 Switch", AC97_AUX, 15, 1, 1),
-AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 1),
+AC97_SINGLE("Out3 ZC Switch", AC97_AUX, 7, 1, 0),
AC97_ENUM("Out3 Mux", wm9711_enum[2]),
AC97_ENUM("Out3 LR Mux", wm9711_enum[3]),
AC97_SINGLE("Out3 Volume", AC97_AUX, 0, 31, 1),
@@ -575,13 +575,14 @@ AC97_SINGLE("Playback Attenuate (-6dB) Switch", AC97_MASTER_TONE, 6, 1, 0),
AC97_SINGLE("ADC Switch", AC97_REC_GAIN, 15, 1, 1),
AC97_ENUM("Capture Volume Steps", wm9711_enum[6]),
-AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 15, 1),
+AC97_DOUBLE("Capture Volume", AC97_REC_GAIN, 8, 0, 63, 1),
AC97_SINGLE("Capture ZC Switch", AC97_REC_GAIN, 7, 1, 0),
AC97_SINGLE("Mic 1 to Phone Switch", AC97_MIC, 14, 1, 1),
AC97_SINGLE("Mic 2 to Phone Switch", AC97_MIC, 13, 1, 1),
AC97_ENUM("Mic Select Source", wm9711_enum[7]),
-AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 32, 1),
+AC97_SINGLE("Mic 1 Volume", AC97_MIC, 8, 31, 1),
+AC97_SINGLE("Mic 2 Volume", AC97_MIC, 0, 31, 1),
AC97_SINGLE("Mic 20dB Boost Switch", AC97_MIC, 7, 1, 0),
AC97_SINGLE("Master ZC Switch", AC97_MASTER, 7, 1, 0),
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c
index 0786d0edaca5..cbf8331c3d33 100644
--- a/sound/pci/ad1889.c
+++ b/sound/pci/ad1889.c
@@ -596,9 +596,7 @@ static struct snd_pcm_ops snd_ad1889_capture_ops = {
};
static irqreturn_t
-snd_ad1889_interrupt(int irq,
- void *dev_id,
- struct pt_regs *regs)
+snd_ad1889_interrupt(int irq, void *dev_id)
{
unsigned long st;
struct snd_ad1889 *chip = dev_id;
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
index 74668398eac5..13a8cefa7749 100644
--- a/sound/pci/ali5451/ali5451.c
+++ b/sound/pci/ali5451/ali5451.c
@@ -1047,9 +1047,7 @@ static void snd_ali_interrupt(struct snd_ali * codec)
}
-static irqreturn_t snd_ali_card_interrupt(int irq,
- void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_ali_card_interrupt(int irq, void *dev_id)
{
struct snd_ali *codec = dev_id;
diff --git a/sound/pci/als300.c b/sound/pci/als300.c
index 96cfb8ae5055..9b16c299f0a9 100644
--- a/sound/pci/als300.c
+++ b/sound/pci/als300.c
@@ -204,8 +204,7 @@ static int snd_als300_dev_free(struct snd_device *device)
return snd_als300_free(chip);
}
-static irqreturn_t snd_als300_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_als300_interrupt(int irq, void *dev_id)
{
u8 status;
struct snd_als300 *chip = dev_id;
@@ -236,8 +235,7 @@ static irqreturn_t snd_als300_interrupt(int irq, void *dev_id,
return IRQ_HANDLED;
}
-static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id)
{
u8 general, mpu, dram;
struct snd_als300 *chip = dev_id;
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c
index 9e596f750cbd..15fc3929b5f7 100644
--- a/sound/pci/als4000.c
+++ b/sound/pci/als4000.c
@@ -385,7 +385,7 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream *
* SB IRQ status.
* And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS??
* */
-static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id)
{
struct snd_sb *chip = dev_id;
unsigned gcr_status;
@@ -399,7 +399,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *
if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */
snd_pcm_period_elapsed(chip->capture_substream);
if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
/* release the gcr */
outb(gcr_status, chip->alt_port + 0xe);
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 347e25ff073d..3e8fc5a0006a 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -1300,7 +1300,7 @@ static int __devinit snd_atiixp_pcm_new(struct atiixp *chip)
/*
* interrupt handler
*/
-static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
{
struct atiixp *chip = dev_id;
unsigned int status;
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index a89d67c4598b..c5dda1bf3d46 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -1017,7 +1017,7 @@ static int __devinit snd_atiixp_pcm_new(struct atiixp_modem *chip)
/*
* interrupt handler
*/
-static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id)
{
struct atiixp_modem *chip = dev_id;
unsigned int status;
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index ef189d7f09d3..6ed5ad59f5b5 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -128,6 +128,7 @@ static int snd_vortex_dev_free(struct snd_device *device)
// Take down PCI interface.
synchronize_irq(vortex->irq);
free_irq(vortex->irq, vortex);
+ iounmap(vortex->mmio);
pci_release_regions(vortex->pci_dev);
pci_disable_device(vortex->pci_dev);
kfree(vortex);
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index b1cfc3c79d07..5ccf0b1ec670 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -236,8 +236,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode);
static int vortex_core_init(vortex_t * card);
static int vortex_core_shutdown(vortex_t * card);
static void vortex_enable_int(vortex_t * card);
-static irqreturn_t vortex_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t vortex_interrupt(int irq, void *dev_id);
static int vortex_alsafmt_aspfmt(int alsafmt);
/* Connection stuff. */
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 5299cce583d3..4a336eaae9d2 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -2385,7 +2385,7 @@ static void vortex_disable_int(vortex_t * card)
hwread(card->mmio, VORTEX_CTRL) & ~CTRL_IRQ_ENABLE);
}
-static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t vortex_interrupt(int irq, void *dev_id)
{
vortex_t *vortex = dev_id;
int i, handled;
@@ -2462,7 +2462,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
if (source & IRQ_MIDI) {
snd_mpu401_uart_interrupt(vortex->irq,
- vortex->rmidi->private_data, regs);
+ vortex->rmidi->private_data);
handled = 1;
}
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index bac8e9cfd921..692f203d65d8 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1191,7 +1191,7 @@ snd_azf3328_capture_pointer(struct snd_pcm_substream *substream)
}
static irqreturn_t
-snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+snd_azf3328_interrupt(int irq, void *dev_id)
{
struct snd_azf3328 *chip = dev_id;
u8 status, which;
@@ -1256,7 +1256,7 @@ snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* MPU401 has less critical IRQ requirements
* than timer and playback/recording, right? */
if (status & IRQ_MPU401) {
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
/* hmm, do we have to ack the IRQ here somehow?
* If so, then I don't know how... */
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index 97a280a246cb..d33a37086df9 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -269,7 +269,7 @@ static void snd_bt87x_pci_error(struct snd_bt87x *chip, unsigned int status)
}
}
-static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id)
{
struct snd_bt87x *chip = dev_id;
unsigned int status, irq_status;
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c
index 12bbbb6afd2d..6fa4a302f7de 100644
--- a/sound/pci/ca0106/ca0106_main.c
+++ b/sound/pci/ca0106/ca0106_main.c
@@ -1058,8 +1058,7 @@ static int snd_ca0106_dev_free(struct snd_device *device)
return snd_ca0106_free(chip);
}
-static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id)
{
unsigned int status;
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c
index 876b64464b6f..1f7e71083069 100644
--- a/sound/pci/cmipci.c
+++ b/sound/pci/cmipci.c
@@ -1294,7 +1294,7 @@ static int snd_cmipci_capture_spdif_hw_free(struct snd_pcm_substream *subs)
/*
* interrupt handler
*/
-static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id)
{
struct cmipci *cm = dev_id;
unsigned int status, mask = 0;
@@ -1315,7 +1315,7 @@ static irqreturn_t snd_cmipci_interrupt(int irq, void *dev_id, struct pt_regs *r
spin_unlock(&cm->reg_lock);
if (cm->rmidi && (status & CM_UARTINT))
- snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, cm->rmidi->private_data);
if (cm->pcm) {
if ((status & CM_CHINT0) && cm->channel[0].running)
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index 1990430a21c1..d54924e60bb1 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -493,7 +493,7 @@ struct cs4281 {
};
-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id);
static struct pci_device_id snd_cs4281_ids[] = {
{ 0x1013, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* CS4281 */
@@ -1814,7 +1814,7 @@ static int __devinit snd_cs4281_midi(struct cs4281 * chip, int device,
* Interrupt handler
*/
-static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id)
{
struct cs4281 *chip = dev_id;
unsigned int status, dma, val;
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
index 4851847180d2..16d4ebf2a33f 100644
--- a/sound/pci/cs46xx/cs46xx_lib.c
+++ b/sound/pci/cs46xx/cs46xx_lib.c
@@ -1149,7 +1149,7 @@ static int snd_cs46xx_capture_prepare(struct snd_pcm_substream *substream)
return 0;
}
-static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_cs46xx_interrupt(int irq, void *dev_id)
{
struct snd_cs46xx *chip = dev_id;
u32 status1;
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c
index 64c7826e8b8c..2441238f2004 100644
--- a/sound/pci/cs5535audio/cs5535audio.c
+++ b/sound/pci/cs5535audio/cs5535audio.c
@@ -203,8 +203,7 @@ static void process_bm1_irq(struct cs5535audio *cs5535au)
}
}
-static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id)
{
u16 acc_irq_stat;
u8 bm_stat;
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index c3dafa29054f..e5e88fe54de0 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -1818,8 +1818,7 @@ static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = {
IRQ Handler
******************************************************************************/
-static irqreturn_t snd_echo_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
{
struct echoaudio *chip = dev_id;
struct snd_pcm_substream *substream;
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
index 7ec5b63d0dce..97e42e115147 100644
--- a/sound/pci/echoaudio/layla24_dsp.c
+++ b/sound/pci/echoaudio/layla24_dsp.c
@@ -302,11 +302,11 @@ static int switch_asic(struct echoaudio *chip, const struct firmware *asic)
/* Check to see if this is already loaded */
if (asic != chip->asic_code) {
- monitors = kmalloc(MONITOR_ARRAY_SIZE, GFP_KERNEL);
+ monitors = kmemdup(chip->comm_page->monitors,
+ MONITOR_ARRAY_SIZE, GFP_KERNEL);
if (! monitors)
return -ENOMEM;
- memcpy(monitors, chip->comm_page->monitors, MONITOR_ARRAY_SIZE);
memset(chip->comm_page->monitors, ECHOGAIN_MUTED,
MONITOR_ARRAY_SIZE);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index be65d4db8e27..8058059c56e9 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1461,8 +1461,8 @@ void snd_emu10k1_resume_regs(struct snd_emu10k1 *emu)
/* resore for spdif */
if (emu->audigy)
- outl(emu->port + A_IOCFG, emu->saved_a_iocfg);
- outl(emu->port + HCFG, emu->saved_hcfg);
+ outl(emu->saved_a_iocfg, emu->port + A_IOCFG);
+ outl(emu->saved_hcfg, emu->port + HCFG);
val = emu->saved_ptr;
for (reg = saved_regs; *reg != 0xff; reg++)
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index da1610a571b8..c46905a11175 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -780,8 +780,7 @@ static int snd_emu10k1x_dev_free(struct snd_device *device)
return snd_emu10k1x_free(chip);
}
-static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id)
{
unsigned int status;
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c
index 1076af4c3669..4f18f7e8bcfb 100644
--- a/sound/pci/emu10k1/irq.c
+++ b/sound/pci/emu10k1/irq.c
@@ -30,7 +30,7 @@
#include <sound/core.h>
#include <sound/emu10k1.h>
-irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
{
struct snd_emu10k1 *emu = dev_id;
unsigned int status, status2, orig_status, orig_status2;
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c
index a8a601fc781f..8cb4fb2412db 100644
--- a/sound/pci/ens1370.c
+++ b/sound/pci/ens1370.c
@@ -444,7 +444,7 @@ struct ensoniq {
#endif
};
-static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id);
static struct pci_device_id snd_audiopci_ids[] = {
#ifdef CHIP1370
@@ -2404,7 +2404,7 @@ static int __devinit snd_ensoniq_midi(struct ensoniq * ensoniq, int device,
* Interrupt handler
*/
-static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id)
{
struct ensoniq *ensoniq = dev_id;
unsigned int status, sctrl;
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 3ce5a4e7e31f..2da988f78ba7 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -241,7 +241,7 @@ struct es1938 {
#endif
};
-static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id);
static struct pci_device_id snd_es1938_ids[] = {
{ 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Solo-1 */
@@ -1642,7 +1642,7 @@ static int __devinit snd_es1938_create(struct snd_card *card,
/* --------------------------------------------------------------------
* Interrupt handler
* -------------------------------------------------------------------- */
-static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id)
{
struct es1938 *chip = dev_id;
unsigned char status, audiostatus;
@@ -1714,7 +1714,7 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id, struct pt_regs *r
// snd_es1938_mixer_bits(chip, ESSSB_IREG_MPU401CONTROL, 0x40, 0); /* ack? */
if (chip->rmidi) {
handled = 1;
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
}
}
return IRQ_RETVAL(handled);
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index f3c40385c87d..b9d723c7e1db 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -590,7 +590,7 @@ struct es1968 {
#endif
};
-static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id);
static struct pci_device_id snd_es1968_ids[] = {
/* Maestro 1 */
@@ -1962,7 +1962,7 @@ static void es1968_update_hw_volume(unsigned long private_data)
/*
* interrupt handler
*/
-static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
{
struct es1968 *chip = dev_id;
u32 event;
@@ -1979,7 +1979,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *r
outb(0xFF, chip->io_port + 0x1A);
if ((event & ESM_MPU401_IRQ) && chip->rmidi) {
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
}
if (event & ESM_SOUND_IRQ) {
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index bdfda1997d5b..3ec7d7ee04dd 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -520,7 +520,7 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub
return bytes_to_frames(substream->runtime, ptr);
}
-static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id)
{
struct fm801 *chip = dev_id;
unsigned short status;
@@ -561,7 +561,7 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id, struct pt_regs *re
snd_pcm_period_elapsed(chip->capture_substream);
}
if (chip->rmidi && (status & FM801_IRQ_MPU))
- snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
if (status & FM801_IRQ_VOLUME)
;/* TODO */
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index e9d4cb4d07e1..feeed12920b4 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -811,7 +811,7 @@ static void azx_init_chip(struct azx *chip)
/*
* interrupt handler
*/
-static irqreturn_t azx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t azx_interrupt(int irq, void *dev_id)
{
struct azx *chip = dev_id;
struct azx_dev *azx_dev;
@@ -1682,6 +1682,7 @@ static struct pci_device_id azx_ids[] = {
{ 0x10b9, 0x5461, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ULI }, /* ULI M5461 */
{ 0x10de, 0x026c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 026c */
{ 0x10de, 0x0371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 0371 */
+ { 0x10de, 0x03f0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_NVIDIA }, /* NVIDIA 03f0 */
{ 0, }
};
MODULE_DEVICE_TABLE(pci, azx_ids);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index d08d2e399c8f..84a3eb8aacc2 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -5076,6 +5076,10 @@ static struct hda_board_config alc883_cfg_tbl[] = {
{ .modelname = "acer", .config = ALC883_ACER },
{ .pci_subvendor = 0x1025, .pci_subdevice = 0/*0x0102*/,
.config = ALC883_ACER },
+ { .pci_subvendor = 0x1025, .pci_subdevice = 0x0102,
+ .config = ALC883_ACER },
+ { .pci_subvendor = 0x1025, .pci_subdevice = 0x009f,
+ .config = ALC883_ACER },
{ .modelname = "auto", .config = ALC883_AUTO },
{}
};
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
index 76ec3d75fa9e..cc87dff1eb56 100644
--- a/sound/pci/hda/patch_si3054.c
+++ b/sound/pci/hda/patch_si3054.c
@@ -297,8 +297,13 @@ static int patch_si3054(struct hda_codec *codec)
struct hda_codec_preset snd_hda_preset_si3054[] = {
{ .id = 0x163c3055, .name = "Si3054", .patch = patch_si3054 },
{ .id = 0x163c3155, .name = "Si3054", .patch = patch_si3054 },
+ { .id = 0x11c11040, .name = "Si3054", .patch = patch_si3054 },
{ .id = 0x11c13026, .name = "Si3054", .patch = patch_si3054 },
+ { .id = 0x11c13055, .name = "Si3054", .patch = patch_si3054 },
+ { .id = 0x11c13155, .name = "Si3054", .patch = patch_si3054 },
+ { .id = 0x10573055, .name = "Si3054", .patch = patch_si3054 },
{ .id = 0x10573057, .name = "Si3054", .patch = patch_si3054 },
+ { .id = 0x10573155, .name = "Si3054", .patch = patch_si3054 },
{}
};
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index dc69392eafa3..8a576b78bee5 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -420,7 +420,7 @@ static void snd_ice1712_set_input_clock_source(struct snd_ice1712 *ice, int spdi
* Interrupt handler
*/
-static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id)
{
struct snd_ice1712 *ice = dev_id;
unsigned char status;
@@ -433,7 +433,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs *
handled = 1;
if (status & ICE1712_IRQ_MPU1) {
if (ice->rmidi[0])
- snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data);
outb(ICE1712_IRQ_MPU1, ICEREG(ice, IRQSTAT));
status &= ~ICE1712_IRQ_MPU1;
}
@@ -441,7 +441,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id, struct pt_regs *
outb(ICE1712_IRQ_TIMER, ICEREG(ice, IRQSTAT));
if (status & ICE1712_IRQ_MPU2) {
if (ice->rmidi[1])
- snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, ice->rmidi[1]->private_data);
outb(ICE1712_IRQ_MPU2, ICEREG(ice, IRQSTAT));
status &= ~ICE1712_IRQ_MPU2;
}
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 71d6aedc0749..e9cbfdf37059 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -218,7 +218,7 @@ static unsigned int snd_vt1724_get_gpio_data(struct snd_ice1712 *ice)
* Interrupt handler
*/
-static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
{
struct snd_ice1712 *ice = dev_id;
unsigned char status;
@@ -236,7 +236,7 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id, struct pt_regs *r
*/
if ((status & VT1724_IRQ_MPU_RX)||(status & VT1724_IRQ_MPU_TX)) {
if (ice->rmidi[0])
- snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, ice->rmidi[0]->private_data);
outb(status & (VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX), ICEREG1724(ice, IRQSTAT));
status &= ~(VT1724_IRQ_MPU_RX|VT1724_IRQ_MPU_TX);
}
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index 72dbaedcbdf5..f4319b8d4644 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -801,7 +801,7 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich
status & (ICH_FIFOE | ICH_BCIS | ICH_LVBCI));
}
-static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id)
{
struct intel8x0 *chip = dev_id;
struct ichdev *ichdev;
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c
index 268e2f7241ea..6703f5cb5569 100644
--- a/sound/pci/intel8x0m.c
+++ b/sound/pci/intel8x0m.c
@@ -511,7 +511,7 @@ static inline void snd_intel8x0_update(struct intel8x0m *chip, struct ichdev *ic
iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
}
-static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_intel8x0_interrupt(int irq, void *dev_id)
{
struct intel8x0m *chip = dev_id;
struct ichdev *ichdev;
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index cfea51f44784..fa8cd8cecc21 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -1119,14 +1119,11 @@ static void snd_korg1212_OnDSPDownloadComplete(struct snd_korg1212 *korg1212)
snd_korg1212_setCardState(korg1212, K1212_STATE_DSP_COMPLETE);
}
-static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id)
{
u32 doorbellValue;
struct snd_korg1212 *korg1212 = dev_id;
- if(irq != korg1212->irq)
- return IRQ_NONE;
-
doorbellValue = readl(korg1212->inDoorbellPtr);
if (!doorbellValue)
@@ -1140,7 +1137,6 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs
korg1212->inIRQ++;
-
switch (doorbellValue) {
case K1212_DB_DSPDownloadDone:
K1212_DEBUG_PRINTK("K1212_DEBUG: IRQ DNLD count - %ld, %x, [%s].\n",
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 45214b3b81be..05605f474a72 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -1685,8 +1685,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
spin_unlock_irqrestore(&chip->ac97_lock, flags);
}
-static irqreturn_t
-snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
{
struct snd_m3 *chip = dev_id;
u8 status;
diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c
index 406ac3a9d42a..d54457317b14 100644
--- a/sound/pci/mixart/mixart_core.c
+++ b/sound/pci/mixart/mixart_core.c
@@ -408,7 +408,7 @@ void snd_mixart_msg_tasklet(unsigned long arg)
}
-irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t snd_mixart_interrupt(int irq, void *dev_id)
{
struct mixart_mgr *mgr = dev_id;
int err;
diff --git a/sound/pci/mixart/mixart_core.h b/sound/pci/mixart/mixart_core.h
index 1fe2bcfcc57c..c919b734756f 100644
--- a/sound/pci/mixart/mixart_core.h
+++ b/sound/pci/mixart/mixart_core.h
@@ -563,7 +563,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int
int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, struct mixart_msg *request, u32 notif_event);
int snd_mixart_send_msg_nonblock(struct mixart_mgr *mgr, struct mixart_msg *request);
-irqreturn_t snd_mixart_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t snd_mixart_interrupt(int irq, void *dev_id);
void snd_mixart_msg_tasklet(unsigned long arg);
void snd_mixart_reset_board(struct mixart_mgr *mgr);
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c
index 101eee0aa018..b1bbdb9e3b7b 100644
--- a/sound/pci/nm256/nm256.c
+++ b/sound/pci/nm256/nm256.c
@@ -236,7 +236,7 @@ struct nm256 {
int irq;
int irq_acks;
- irqreturn_t (*interrupt)(int, void *, struct pt_regs *);
+ irq_handler_t interrupt;
int badintrcount; /* counter to check bogus interrupts */
struct mutex irq_mutex;
@@ -1004,7 +1004,7 @@ snd_nm256_intr_check(struct nm256 *chip)
*/
static irqreturn_t
-snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
+snd_nm256_interrupt(int irq, void *dev_id)
{
struct nm256 *chip = dev_id;
u16 status;
@@ -1069,7 +1069,7 @@ snd_nm256_interrupt(int irq, void *dev_id, struct pt_regs *dummy)
*/
static irqreturn_t
-snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy)
+snd_nm256_interrupt_zx(int irq, void *dev_id)
{
struct nm256 *chip = dev_id;
u32 status;
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index c40f59062684..0ff8dc36fde3 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -1131,7 +1131,7 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
}
-irqreturn_t pcxhr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
{
struct pcxhr_mgr *mgr = dev_id;
unsigned int reg;
diff --git a/sound/pci/pcxhr/pcxhr_core.h b/sound/pci/pcxhr/pcxhr_core.h
index e7415d6d1826..d9a4ab609875 100644
--- a/sound/pci/pcxhr/pcxhr_core.h
+++ b/sound/pci/pcxhr/pcxhr_core.h
@@ -194,7 +194,7 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
/* interrupt handling */
-irqreturn_t pcxhr_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+irqreturn_t pcxhr_interrupt(int irq, void *dev_id);
void pcxhr_msg_tasklet(unsigned long arg);
#endif /* __SOUND_PCXHR_CORE_H */
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c
index fe210c853442..ec4899147e1d 100644
--- a/sound/pci/riptide/riptide.c
+++ b/sound/pci/riptide/riptide.c
@@ -1736,7 +1736,7 @@ snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm)
}
static irqreturn_t
-snd_riptide_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+snd_riptide_interrupt(int irq, void *dev_id)
{
struct snd_riptide *chip = dev_id;
struct cmdif *cif = chip->cif;
@@ -1751,8 +1751,7 @@ snd_riptide_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (chip->rmidi && IS_MPUIRQ(cif->hwport)) {
chip->handled_irqs++;
snd_mpu401_uart_interrupt(irq,
- chip->rmidi->private_data,
- regs);
+ chip->rmidi->private_data);
}
SET_AIACK(cif->hwport);
}
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 2a71499242fa..dc8d1302e22d 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -818,8 +818,7 @@ static void snd_rme32_pcm_stop(struct rme32 * rme32, int to_pause)
writel(0, rme32->iobase + RME32_IO_RESET_POS);
}
-static irqreturn_t
-snd_rme32_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_rme32_interrupt(int irq, void *dev_id)
{
struct rme32 *rme32 = (struct rme32 *) dev_id;
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index f8de7c997017..106110a89a4c 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1117,8 +1117,7 @@ snd_rme96_capture_stop(struct rme96 *rme96)
static irqreturn_t
snd_rme96_interrupt(int irq,
- void *dev_id,
- struct pt_regs *regs)
+ void *dev_id)
{
struct rme96 *rme96 = (struct rme96 *)dev_id;
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index d3e07de433b0..694aa057ed49 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -3603,7 +3603,7 @@ static void hdsp_midi_tasklet(unsigned long arg)
snd_hdsp_midi_input_read (&hdsp->midi[1]);
}
-static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_hdsp_interrupt(int irq, void *dev_id)
{
struct hdsp *hdsp = (struct hdsp *) dev_id;
unsigned int status;
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 7d03ae066d53..7055d893855d 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -2556,8 +2556,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm)
interupt
------------------------------------------------------------*/
-static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
{
struct hdspm *hdspm = (struct hdspm *) dev_id;
unsigned int status;
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index fc15f61ad5d1..cf0427b4bfde 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -1882,7 +1882,7 @@ static void snd_rme9652_set_defaults(struct snd_rme9652 *rme9652)
rme9652_set_rate(rme9652, 48000);
}
-static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_rme9652_interrupt(int irq, void *dev_id)
{
struct snd_rme9652 *rme9652 = (struct snd_rme9652 *) dev_id;
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index e5d4def1aa6f..f9b8afabda9c 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -580,7 +580,7 @@ static int snd_sonicvibes_trigger(struct sonicvibes * sonic, int what, int cmd)
return result;
}
-static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id)
{
struct sonicvibes *sonic = dev_id;
unsigned char status;
@@ -601,7 +601,7 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_reg
}
if (sonic->rmidi) {
if (status & SV_MIDI_IRQ)
- snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, sonic->rmidi->private_data);
}
if (status & SV_UD_IRQ) {
unsigned char udreg;
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index ebbe12d78d8c..0d478871808d 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -52,8 +52,7 @@ static int snd_trident_pcm_mixer_build(struct snd_trident *trident,
static int snd_trident_pcm_mixer_free(struct snd_trident *trident,
struct snd_trident_voice * voice,
struct snd_pcm_substream *substream);
-static irqreturn_t snd_trident_interrupt(int irq, void *dev_id,
- struct pt_regs *regs);
+static irqreturn_t snd_trident_interrupt(int irq, void *dev_id);
static int snd_trident_sis_reset(struct snd_trident *trident);
static void snd_trident_clear_voices(struct snd_trident * trident,
@@ -3737,7 +3736,7 @@ static int snd_trident_free(struct snd_trident *trident)
---------------------------------------------------------------------------*/
-static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_trident_interrupt(int irq, void *dev_id)
{
struct snd_trident *trident = dev_id;
unsigned int audio_int, chn_int, stimer, channel, mask, tmp;
@@ -3825,7 +3824,7 @@ static irqreturn_t snd_trident_interrupt(int irq, void *dev_id, struct pt_regs *
}
if (audio_int & MPU401_IRQ) {
if (trident->rmidi) {
- snd_mpu401_uart_interrupt(irq, trident->rmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, trident->rmidi->private_data);
} else {
inb(TRID_REG(trident, T4D_MPUR0));
}
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index 6db3d4cc4d8d..e6990e0bbf23 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -613,7 +613,7 @@ static void snd_via82xx_channel_reset(struct via82xx *chip, struct viadev *viade
* Interrupt handler
* Used for 686 and 8233A
*/
-static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_via686_interrupt(int irq, void *dev_id)
{
struct via82xx *chip = dev_id;
unsigned int status;
@@ -623,7 +623,7 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *r
if (! (status & chip->intr_mask)) {
if (chip->rmidi)
/* check mpu401 interrupt */
- return snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs);
+ return snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data);
return IRQ_NONE;
}
@@ -659,7 +659,7 @@ static irqreturn_t snd_via686_interrupt(int irq, void *dev_id, struct pt_regs *r
/*
* Interrupt handler
*/
-static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_via8233_interrupt(int irq, void *dev_id)
{
struct via82xx *chip = dev_id;
unsigned int status;
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c
index 016f9dac253f..5ab1cf3d434b 100644
--- a/sound/pci/via82xx_modem.c
+++ b/sound/pci/via82xx_modem.c
@@ -475,7 +475,7 @@ static void snd_via82xx_channel_reset(struct via82xx_modem *chip, struct viadev
* Interrupt handler
*/
-static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_via82xx_interrupt(int irq, void *dev_id)
{
struct via82xx_modem *chip = dev_id;
unsigned int status;
diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c
index 24f6fc52f898..ebc6da89edf3 100644
--- a/sound/pci/ymfpci/ymfpci_main.c
+++ b/sound/pci/ymfpci/ymfpci_main.c
@@ -753,7 +753,7 @@ static void snd_ymfpci_irq_wait(struct snd_ymfpci *chip)
}
}
-static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id)
{
struct snd_ymfpci *chip = dev_id;
u32 status, nvoice, mode;
@@ -799,7 +799,7 @@ static irqreturn_t snd_ymfpci_interrupt(int irq, void *dev_id, struct pt_regs *r
snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status);
if (chip->rawmidi)
- snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data, regs);
+ snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data);
return IRQ_HANDLED;
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h
index 9a14a4f64bd3..206e2f5a113f 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.h
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h
@@ -138,7 +138,7 @@ int snd_pdacf_suspend(struct snd_pdacf *chip, pm_message_t state);
int snd_pdacf_resume(struct snd_pdacf *chip);
#endif
int snd_pdacf_pcm_new(struct snd_pdacf *chip);
-irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs);
+irqreturn_t pdacf_interrupt(int irq, void *dev);
void pdacf_tasklet(unsigned long private_data);
void pdacf_reinit(struct snd_pdacf *chip, int resume);
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
index 7c5f21e45cb4..5bd69206ba65 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
@@ -22,11 +22,12 @@
#include <sound/core.h>
#include "pdaudiocf.h"
#include <sound/initval.h>
+#include <asm/irq_regs.h>
/*
*
*/
-irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs)
+irqreturn_t pdacf_interrupt(int irq, void *dev)
{
struct snd_pdacf *chip = dev;
unsigned short stat;
@@ -45,7 +46,7 @@ irqreturn_t pdacf_interrupt(int irq, void *dev, struct pt_regs *regs)
if (!(stat & PDAUDIOCF_IRQAKM))
stat |= PDAUDIOCF_IRQAKM; /* check rate */
}
- if (regs != NULL)
+ if (get_irq_regs() != NULL)
snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
return IRQ_HANDLED;
}
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 641430631505..c64af55865d4 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -713,7 +713,7 @@ void snd_pmac_beep_dma_stop(struct snd_pmac *chip)
* interrupt handlers
*/
static irqreturn_t
-snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs)
+snd_pmac_tx_intr(int irq, void *devid)
{
struct snd_pmac *chip = devid;
snd_pmac_pcm_update(chip, &chip->playback);
@@ -722,7 +722,7 @@ snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs)
static irqreturn_t
-snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs)
+snd_pmac_rx_intr(int irq, void *devid)
{
struct snd_pmac *chip = devid;
snd_pmac_pcm_update(chip, &chip->capture);
@@ -731,7 +731,7 @@ snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs)
static irqreturn_t
-snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs)
+snd_pmac_ctrl_intr(int irq, void *devid)
{
struct snd_pmac *chip = devid;
int ctrl = in_le32(&chip->awacs->control);
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index cdff53e4a17e..2fbe1d183fce 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1017,7 +1017,7 @@ static void tumbler_update_automute(struct snd_pmac *chip, int do_notify)
/* interrupt - headphone plug changed */
-static irqreturn_t headphone_intr(int irq, void *devid, struct pt_regs *regs)
+static irqreturn_t headphone_intr(int irq, void *devid)
{
struct snd_pmac *chip = devid;
if (chip->update_automute && chip->initialized) {
diff --git a/sound/sound_core.c b/sound/sound_core.c
index 62d4d0c81261..5322c50c9617 100644
--- a/sound/sound_core.c
+++ b/sound/sound_core.c
@@ -366,25 +366,6 @@ int register_sound_dsp(const struct file_operations *fops, int dev)
EXPORT_SYMBOL(register_sound_dsp);
/**
- * register_sound_synth - register a synth device
- * @fops: File operations for the driver
- * @dev: Unit number to allocate
- *
- * Allocate a synth device. Unit is the number of the synth device requested.
- * Pass -1 to request the next free synth unit. On success the allocated
- * number is returned, on failure a negative error code is returned.
- */
-
-
-int register_sound_synth(const struct file_operations *fops, int dev)
-{
- return sound_insert_unit(&chains[9], fops, dev, 9, 137,
- "synth", S_IRUSR | S_IWUSR, NULL);
-}
-
-EXPORT_SYMBOL(register_sound_synth);
-
-/**
* unregister_sound_special - unregister a special sound device
* @unit: unit number to allocate
*
@@ -449,21 +430,6 @@ void unregister_sound_dsp(int unit)
EXPORT_SYMBOL(unregister_sound_dsp);
-/**
- * unregister_sound_synth - unregister a synth device
- * @unit: unit number to allocate
- *
- * Release a sound device that was allocated with register_sound_synth().
- * The unit passed is the return value from the register function.
- */
-
-void unregister_sound_synth(int unit)
-{
- return sound_remove_unit(&chains[9], unit);
-}
-
-EXPORT_SYMBOL(unregister_sound_synth);
-
/*
* Now our file operations
*/
@@ -551,10 +517,6 @@ int soundcore_open(struct inode *inode, struct file *file)
return -ENODEV;
}
-extern int mod_firmware_load(const char *, char **);
-EXPORT_SYMBOL(mod_firmware_load);
-
-
MODULE_DESCRIPTION("Core sound module");
MODULE_AUTHOR("Alan Cox");
MODULE_LICENSE("GPL");
diff --git a/sound/sound_firmware.c b/sound/sound_firmware.c
index 6ddadfac35ad..3a181d4c0dc6 100644
--- a/sound/sound_firmware.c
+++ b/sound/sound_firmware.c
@@ -4,6 +4,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
+#include "oss/sound_firmware.h"
static int do_mod_firmware_load(const char *fn, char **fp)
{
@@ -59,8 +60,7 @@ static int do_mod_firmware_load(const char *fn, char **fp)
* value zero on a failure.
*
* Caution: This API is not recommended. Firmware should be loaded via
- * an ioctl call and a setup application. This function may disappear
- * in future.
+ * request_firmware.
*/
int mod_firmware_load(const char *fn, char **fp)
@@ -73,4 +73,6 @@ int mod_firmware_load(const char *fn, char **fp)
set_fs(fs);
return r;
}
+EXPORT_SYMBOL(mod_firmware_load);
+MODULE_LICENSE("GPL");
diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
index be0bd503f013..c899786f30f5 100644
--- a/sound/sparc/amd7930.c
+++ b/sound/sparc/amd7930.c
@@ -491,7 +491,7 @@ static void __amd7930_update_map(struct snd_amd7930 *amd)
__amd7930_write_map(amd);
}
-static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_amd7930_interrupt(int irq, void *dev_id)
{
struct snd_amd7930 *amd = dev_id;
unsigned int elapsed;
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 9a06c3bd6944..edeb3d3c4c7e 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1753,7 +1753,7 @@ out_err:
#ifdef SBUS_SUPPORT
-static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id)
{
unsigned long flags;
unsigned char status;
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c
index 8016541ec16d..4ceb09d215d8 100644
--- a/sound/sparc/dbri.c
+++ b/sound/sparc/dbri.c
@@ -1903,8 +1903,7 @@ static void dbri_process_interrupt_buffer(struct snd_dbri * dbri)
}
}
-static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id,
- struct pt_regs *regs)
+static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id)
{
struct snd_dbri *dbri = dev_id;
static int errcnt = 0;
@@ -2412,8 +2411,6 @@ static struct snd_kcontrol_new dbri_controls[] __devinitdata = {
CS4215_SINGLE("Mic boost", 4, 4, 1, 1)
};
-#define NUM_CS4215_CONTROLS (sizeof(dbri_controls)/sizeof(struct snd_kcontrol_new))
-
static int __init snd_dbri_mixer(struct snd_dbri * dbri)
{
struct snd_card *card;
@@ -2424,7 +2421,7 @@ static int __init snd_dbri_mixer(struct snd_dbri * dbri)
card = dbri->card;
strcpy(card->mixername, card->shortname);
- for (idx = 0; idx < NUM_CS4215_CONTROLS; idx++) {
+ for (idx = 0; idx < ARRAY_SIZE(dbri_controls); idx++) {
if ((err = snd_ctl_add(card,
snd_ctl_new1(&dbri_controls[idx], dbri))) < 0)
return err;
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
index 49248fa7aef4..c82b01c7ad3a 100644
--- a/sound/usb/usbaudio.c
+++ b/sound/usb/usbaudio.c
@@ -653,7 +653,7 @@ static struct snd_urb_ops audio_urb_ops_high_speed[2] = {
/*
* complete callback from data urb
*/
-static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
+static void snd_complete_urb(struct urb *urb)
{
struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
struct snd_usb_substream *subs = ctx->subs;
@@ -676,7 +676,7 @@ static void snd_complete_urb(struct urb *urb, struct pt_regs *regs)
/*
* complete callback from sync urb
*/
-static void snd_complete_sync_urb(struct urb *urb, struct pt_regs *regs)
+static void snd_complete_sync_urb(struct urb *urb)
{
struct snd_urb_ctx *ctx = (struct snd_urb_ctx *)urb->context;
struct snd_usb_substream *subs = ctx->subs;
@@ -2046,10 +2046,9 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
void *buf = NULL;
if (size > 0) {
- buf = kmalloc(size, GFP_KERNEL);
+ buf = kmemdup(data, size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memcpy(buf, data, size);
}
err = usb_control_msg(dev, pipe, request, requesttype,
value, index, buf, size, timeout);
@@ -2846,12 +2845,11 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
int stream, err;
int *rate_table = NULL;
- fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+ fp = kmemdup(quirk->data, sizeof(*fp), GFP_KERNEL);
if (! fp) {
- snd_printk(KERN_ERR "cannot malloc\n");
+ snd_printk(KERN_ERR "cannot memdup\n");
return -ENOMEM;
}
- memcpy(fp, quirk->data, sizeof(*fp));
if (fp->nr_rates > 0) {
rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL);
if (!rate_table) {
@@ -3029,10 +3027,9 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip,
altsd->bNumEndpoints != 1)
return -ENXIO;
- fp = kmalloc(sizeof(*fp), GFP_KERNEL);
+ fp = kmemdup(&ua1000_format, sizeof(*fp), GFP_KERNEL);
if (!fp)
return -ENOMEM;
- memcpy(fp, &ua1000_format, sizeof(*fp));
fp->channels = alts->extra[4];
fp->iface = altsd->bInterfaceNumber;
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
index 5105b6b05748..b7c5e59b2299 100644
--- a/sound/usb/usbmidi.c
+++ b/sound/usb/usbmidi.c
@@ -181,9 +181,9 @@ static int snd_usbmidi_urb_error(int status)
case -ENODEV:
return -ENODEV;
/* errors that might occur during unplugging */
- case -EPROTO: /* EHCI */
- case -ETIMEDOUT: /* OHCI */
- case -EILSEQ: /* UHCI */
+ case -EPROTO:
+ case -ETIME:
+ case -EILSEQ:
return -EIO;
default:
snd_printk(KERN_ERR "urb status %d\n", status);
@@ -223,7 +223,7 @@ static void dump_urb(const char *type, const u8 *data, int length)
/*
* Processes the data read from the device.
*/
-static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
+static void snd_usbmidi_in_urb_complete(struct urb* urb)
{
struct snd_usb_midi_in_endpoint* ep = urb->context;
@@ -247,7 +247,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs)
snd_usbmidi_submit_urb(urb, GFP_ATOMIC);
}
-static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs)
+static void snd_usbmidi_out_urb_complete(struct urb* urb)
{
struct snd_usb_midi_out_endpoint* ep = urb->context;
@@ -323,10 +323,9 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep,
const void *data, int len)
{
int err;
- void *buf = kmalloc(len, GFP_KERNEL);
+ void *buf = kmemdup(data, len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memcpy(buf, data, len);
dump_urb("sending", buf, len);
err = usb_bulk_msg(ep->umidi->chip->dev, ep->urb->pipe, buf, len,
NULL, 250);
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c
index e516d6adbb22..1024c178f5c0 100644
--- a/sound/usb/usbmixer.c
+++ b/sound/usb/usbmixer.c
@@ -1710,7 +1710,7 @@ static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer,
}
}
-static void snd_usb_mixer_status_complete(struct urb *urb, struct pt_regs *regs)
+static void snd_usb_mixer_status_complete(struct urb *urb)
{
struct usb_mixer_interface *mixer = urb->context;
@@ -1772,8 +1772,7 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer)
return 0;
}
-static void snd_usb_soundblaster_remote_complete(struct urb *urb,
- struct pt_regs *regs)
+static void snd_usb_soundblaster_remote_complete(struct urb *urb)
{
struct usb_mixer_interface *mixer = urb->context;
const struct rc_config *rc = mixer->rc_cfg;
diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c
index cfec38d7839b..e011fcacce92 100644
--- a/sound/usb/usx2y/usbusx2y.c
+++ b/sound/usb/usx2y/usbusx2y.c
@@ -172,7 +172,7 @@ static void snd_usX2Y_card_private_free(struct snd_card *card);
/*
* pipe 4 is used for switching the lamps, setting samplerate, volumes ....
*/
-static void i_usX2Y_Out04Int(struct urb *urb, struct pt_regs *regs)
+static void i_usX2Y_Out04Int(struct urb *urb)
{
#ifdef CONFIG_SND_DEBUG
if (urb->status) {
@@ -184,7 +184,7 @@ static void i_usX2Y_Out04Int(struct urb *urb, struct pt_regs *regs)
#endif
}
-static void i_usX2Y_In04Int(struct urb *urb, struct pt_regs *regs)
+static void i_usX2Y_In04Int(struct urb *urb)
{
int err = 0;
struct usX2Ydev *usX2Y = urb->context;
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index f6bd0dee563c..367f8a32a665 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -306,7 +306,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y,
usX2Y_clients_stop(usX2Y);
}
-static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs)
+static void i_usX2Y_urb_complete(struct urb *urb)
{
struct snd_usX2Y_substream *subs = urb->context;
struct usX2Ydev *usX2Y = subs->usX2Y;
@@ -322,7 +322,7 @@ static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs)
usX2Y_error_urb_status(usX2Y, subs, urb);
return;
}
- if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
+ if (likely(urb->start_frame == usX2Y->wait_iso_frame))
subs->completed_urb = urb;
else {
usX2Y_error_sequence(usX2Y, subs, urb);
@@ -335,13 +335,9 @@ static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs)
atomic_read(&capsubs->state) >= state_PREPARED &&
(playbacksubs->completed_urb ||
atomic_read(&playbacksubs->state) < state_PREPARED)) {
- if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame)) {
- if (nr_of_packs() <= urb->start_frame &&
- urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
- usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
- else
- usX2Y->wait_iso_frame += nr_of_packs();
- } else {
+ if (!usX2Y_usbframe_complete(capsubs, playbacksubs, urb->start_frame))
+ usX2Y->wait_iso_frame += nr_of_packs();
+ else {
snd_printdd("\n");
usX2Y_clients_stop(usX2Y);
}
@@ -350,7 +346,7 @@ static void i_usX2Y_urb_complete(struct urb *urb, struct pt_regs *regs)
}
static void usX2Y_urbs_set_complete(struct usX2Ydev * usX2Y,
- void (*complete)(struct urb *, struct pt_regs *))
+ void (*complete)(struct urb *))
{
int s, u;
for (s = 0; s < 4; s++) {
@@ -370,7 +366,7 @@ static void usX2Y_subs_startup_finish(struct usX2Ydev * usX2Y)
usX2Y->prepare_subs = NULL;
}
-static void i_usX2Y_subs_startup(struct urb *urb, struct pt_regs *regs)
+static void i_usX2Y_subs_startup(struct urb *urb)
{
struct snd_usX2Y_substream *subs = urb->context;
struct usX2Ydev *usX2Y = subs->usX2Y;
@@ -382,7 +378,7 @@ static void i_usX2Y_subs_startup(struct urb *urb, struct pt_regs *regs)
wake_up(&usX2Y->prepare_wait_queue);
}
- i_usX2Y_urb_complete(urb, regs);
+ i_usX2Y_urb_complete(urb);
}
static void usX2Y_subs_prepare(struct snd_usX2Y_substream *subs)
@@ -495,7 +491,6 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs)
if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
goto start;
}
- usX2Y->wait_iso_frame = -1;
start:
usX2Y_subs_startup(subs);
@@ -516,10 +511,9 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs)
snd_printk (KERN_ERR "cannot submit datapipe for urb %d, err = %d\n", i, err);
err = -EPIPE;
goto cleanup;
- } else {
- if (0 > usX2Y->wait_iso_frame)
+ } else
+ if (i == 0)
usX2Y->wait_iso_frame = urb->start_frame;
- }
urb->transfer_flags = 0;
} else {
atomic_set(&subs->state, state_STARTING1);
@@ -663,7 +657,7 @@ static struct s_c2 SetRate48000[] =
};
#define NOOF_SETRATE_URBS ARRAY_SIZE(SetRate48000)
-static void i_usX2Y_04Int(struct urb *urb, struct pt_regs *regs)
+static void i_usX2Y_04Int(struct urb *urb)
{
struct usX2Ydev *usX2Y = urb->context;
diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c
index 88b72b52590f..8f3e35e24e72 100644
--- a/sound/usb/usx2y/usx2yhwdeppcm.c
+++ b/sound/usb/usx2y/usx2yhwdeppcm.c
@@ -226,7 +226,7 @@ static inline int usX2Y_usbpcm_usbframe_complete(struct snd_usX2Y_substream *cap
}
-static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs)
+static void i_usX2Y_usbpcm_urb_complete(struct urb *urb)
{
struct snd_usX2Y_substream *subs = urb->context;
struct usX2Ydev *usX2Y = subs->usX2Y;
@@ -243,7 +243,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs)
usX2Y_error_urb_status(usX2Y, subs, urb);
return;
}
- if (likely((0xFFFF & urb->start_frame) == usX2Y->wait_iso_frame))
+ if (likely(urb->start_frame == usX2Y->wait_iso_frame))
subs->completed_urb = urb;
else {
usX2Y_error_sequence(usX2Y, subs, urb);
@@ -256,13 +256,9 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb, struct pt_regs *regs)
if (capsubs->completed_urb && atomic_read(&capsubs->state) >= state_PREPARED &&
(NULL == capsubs2 || capsubs2->completed_urb) &&
(playbacksubs->completed_urb || atomic_read(&playbacksubs->state) < state_PREPARED)) {
- if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame)) {
- if (nr_of_packs() <= urb->start_frame &&
- urb->start_frame <= (2 * nr_of_packs() - 1)) // uhci and ohci
- usX2Y->wait_iso_frame = urb->start_frame - nr_of_packs();
- else
- usX2Y->wait_iso_frame += nr_of_packs();
- } else {
+ if (!usX2Y_usbpcm_usbframe_complete(capsubs, capsubs2, playbacksubs, urb->start_frame))
+ usX2Y->wait_iso_frame += nr_of_packs();
+ else {
snd_printdd("\n");
usX2Y_clients_stop(usX2Y);
}
@@ -294,7 +290,7 @@ static void usX2Y_usbpcm_subs_startup_finish(struct usX2Ydev * usX2Y)
usX2Y->prepare_subs = NULL;
}
-static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
+static void i_usX2Y_usbpcm_subs_startup(struct urb *urb)
{
struct snd_usX2Y_substream *subs = urb->context;
struct usX2Ydev *usX2Y = subs->usX2Y;
@@ -311,7 +307,7 @@ static void i_usX2Y_usbpcm_subs_startup(struct urb *urb, struct pt_regs *regs)
wake_up(&usX2Y->prepare_wait_queue);
}
- i_usX2Y_usbpcm_urb_complete(urb, regs);
+ i_usX2Y_usbpcm_urb_complete(urb);
}
/*
@@ -433,7 +429,6 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
if (subs != NULL && atomic_read(&subs->state) >= state_PREPARED)
goto start;
}
- usX2Y->wait_iso_frame = -1;
start:
usX2Y_usbpcm_subs_startup(subs);
@@ -459,7 +454,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs)
goto cleanup;
} else {
snd_printdd("%i\n", urb->start_frame);
- if (0 > usX2Y->wait_iso_frame)
+ if (u == 0)
usX2Y->wait_iso_frame = urb->start_frame;
}
urb->transfer_flags = 0;
@@ -632,7 +627,7 @@ static int usX2Y_pcms_lock_check(struct snd_card *card)
for (s = 0; s < 2; ++s) {
struct snd_pcm_substream *substream;
substream = pcm->streams[s].substream;
- if (SUBSTREAM_BUSY(substream))
+ if (substream && SUBSTREAM_BUSY(substream))
err = -EBUSY;
}
}